diff --git a/[refs] b/[refs] index 2e05f0ee5516..fa75c2c1e04e 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 5f19f14fed7786652b9617c633db101d26a42251 +refs/heads/master: 1d767cae4dbd4116fc3b2cc3251a20760f98339f diff --git a/trunk/CREDITS b/trunk/CREDITS index 370b4c7da39b..d8fe12a9421f 100644 --- a/trunk/CREDITS +++ b/trunk/CREDITS @@ -3814,8 +3814,8 @@ D: INFO-SHEET, former maintainer D: Author of the longest-living linux bug N: Jonathan Woithe -E: jwoithe@physics.adelaide.edu.au -W: http://www.physics.adelaide.edu.au/~jwoithe +E: jwoithe@just42.net +W: http:/www.just42.net/jwoithe D: ALS-007 sound card extensions to Sound Blaster driver S: 20 Jordan St S: Valley View, SA 5093 diff --git a/trunk/Documentation/ABI/removed/ip_queue b/trunk/Documentation/ABI/removed/ip_queue new file mode 100644 index 000000000000..3243613bc2d2 --- /dev/null +++ b/trunk/Documentation/ABI/removed/ip_queue @@ -0,0 +1,9 @@ +What: ip_queue +Date: finally removed in kernel v3.5.0 +Contact: Pablo Neira Ayuso +Description: + ip_queue has been replaced by nfnetlink_queue which provides + more advanced queueing mechanism to user-space. The ip_queue + module was already announced to become obsolete years ago. + +Users: diff --git a/trunk/Documentation/ABI/testing/dev-kmsg b/trunk/Documentation/ABI/testing/dev-kmsg new file mode 100644 index 000000000000..281ecc5f9709 --- /dev/null +++ b/trunk/Documentation/ABI/testing/dev-kmsg @@ -0,0 +1,90 @@ +What: /dev/kmsg +Date: Mai 2012 +KernelVersion: 3.5 +Contact: Kay Sievers +Description: The /dev/kmsg character device node provides userspace access + to the kernel's printk buffer. + + Injecting messages: + Every write() to the opened device node places a log entry in + the kernel's printk buffer. + + The logged line can be prefixed with a syslog prefix, which + carries the syslog priority and facility. The single decimal + prefix number is composed of the 3 lowest bits being the syslog + priority and the higher bits the syslog facility number. + + If no prefix is given, the priority number is the default kernel + log priority and the facility number is set to LOG_USER (1). It + is not possible to inject messages from userspace with the + facility number LOG_KERN (0), to make sure that the origin of + the messages can always be reliably determined. + + Accessing the buffer: + Every read() from the opened device node receives one record + of the kernel's printk buffer. + + The first read() directly following an open() always returns + first message in the buffer; there is no kernel-internal + persistent state; many readers can concurrently open the device + and read from it, without affecting other readers. + + Every read() will receive the next available record. If no more + records are available read() will block, or if O_NONBLOCK is + used -EAGAIN returned. + + Messages in the record ring buffer get overwritten as whole, + there are never partial messages received by read(). + + In case messages get overwritten in the circular buffer while + the device is kept open, the next read() will return -EPIPE, + and the seek position be updated to the next available record. + Subsequent reads() will return available records again. + + Unlike the classic syslog() interface, the 64 bit record + sequence numbers allow to calculate the amount of lost + messages, in case the buffer gets overwritten. And they allow + to reconnect to the buffer and reconstruct the read position + if needed, without limiting the interface to a single reader. + + The device supports seek with the following parameters: + SEEK_SET, 0 + seek to the first entry in the buffer + SEEK_END, 0 + seek after the last entry in the buffer + SEEK_DATA, 0 + seek after the last record available at the time + the last SYSLOG_ACTION_CLEAR was issued. + + The output format consists of a prefix carrying the syslog + prefix including priority and facility, the 64 bit message + sequence number and the monotonic timestamp in microseconds. + The values are separated by a ','. Future extensions might + add more comma separated values before the terminating ';'. + Unknown values should be gracefully ignored. + + The human readable text string starts directly after the ';' + and is terminated by a '\n'. Untrusted values derived from + hardware or other facilities are printed, therefore + all non-printable characters in the log message are escaped + by "\x00" C-style hex encoding. + + A line starting with ' ', is a continuation line, adding + key/value pairs to the log message, which provide the machine + readable context of the message, for reliable processing in + userspace. + + Example: + 7,160,424069;pci_root PNP0A03:00: host bridge window [io 0x0000-0x0cf7] (ignored) + SUBSYSTEM=acpi + DEVICE=+acpi:PNP0A03:00 + 6,339,5140900;NET: Registered protocol family 10 + 30,340,5690716;udevd[80]: starting version 181 + + The DEVICE= key uniquely identifies devices the following way: + b12:8 - block dev_t + c127:3 - char dev_t + n8 - netdev ifindex + +sound:card0 - subsystem:devname + +Users: dmesg(1), userspace kernel log consumers diff --git a/trunk/drivers/staging/iio/Documentation/sysfs-bus-iio b/trunk/Documentation/ABI/testing/sysfs-bus-iio similarity index 96% rename from trunk/drivers/staging/iio/Documentation/sysfs-bus-iio rename to trunk/Documentation/ABI/testing/sysfs-bus-iio index 46a995d6d261..5bc8a476c15e 100644 --- a/trunk/drivers/staging/iio/Documentation/sysfs-bus-iio +++ b/trunk/Documentation/ABI/testing/sysfs-bus-iio @@ -108,7 +108,7 @@ Description: physically equivalent inputs when non differential readings are separately available. In differential only parts, then all that is required is a consistent labeling. Units after application - of scale and offset are nanofarads.. + of scale and offset are nanofarads. What: /sys/bus/iio/devices/iio:deviceX/in_temp_raw What: /sys/bus/iio/devices/iio:deviceX/in_tempX_raw @@ -119,7 +119,7 @@ KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: Raw (unscaled no bias removal etc) temperature measurement. - It an axis is specified it generally means that the temperature + 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 are milli degrees Celsuis. @@ -232,7 +232,7 @@ Description: If known for a device, scale to be applied to Y[_name]_raw post addition of [Y][_name]_offset in order to obtain the measured value in units as specified in - [Y][_name]_raw documentation.. If shared across all in + [Y][_name]_raw documentation. If shared across all in channels then Y and are not present and the value is called [Y][_name]_scale. The peak modifier means this value is applied to Y[_name]_peak_raw values. @@ -243,6 +243,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_accel_z_calibbias What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_x_calibbias What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_calibbias What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_calibbias +What: /sys/bus/iio/devices/iio:deviceX/in_illuminance0_calibbias +What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_calibbias KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: @@ -258,6 +260,8 @@ What /sys/bus/iio/devices/iio:deviceX/in_accel_z_calibscale What /sys/bus/iio/devices/iio:deviceX/in_anglvel_x_calibscale What /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_calibscale What /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_calibscale +what /sys/bus/iio/devices/iio:deviceX/in_illuminance0_calibscale +what /sys/bus/iio/devices/iio:deviceX/in_proximity0_calibscale KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: @@ -276,6 +280,13 @@ Description: If a discrete set of scale values are available, they are listed in this attribute. +What /sys/bus/iio/devices/iio:deviceX/out_voltageY_hardwaregain +KernelVersion: 2.6.35 +Contact: linux-iio@vger.kernel.org +Description: + Hardware applied gain factor. If shared across all channels, + _hardwaregain is used. + What: /sys/.../in_accel_filter_low_pass_3db_frequency What: /sys/.../in_magn_filter_low_pass_3db_frequency What: /sys/.../in_anglvel_filter_low_pass_3db_frequency @@ -453,10 +464,14 @@ What: /sys/.../events/in_magn_z_raw_thresh_rising_value What: /sys/.../events/in_magn_z_raw_thresh_falling_value What: /sys/.../events/in_voltageY_supply_raw_thresh_rising_value What: /sys/.../events/in_voltageY_supply_raw_thresh_falling_value +What: /sys/.../events/in_voltageY_raw_thresh_rising_value What: /sys/.../events/in_voltageY_raw_thresh_falling_value -What: /sys/.../events/in_voltageY_raw_thresh_falling_value -What: /sys/.../events/in_tempY_raw_thresh_falling_value +What: /sys/.../events/in_tempY_raw_thresh_rising_value What: /sys/.../events/in_tempY_raw_thresh_falling_value +What: /sys/.../events/in_illuminance0_thresh_falling_value +what: /sys/.../events/in_illuminance0_thresh_rising_value +what: /sys/.../events/in_proximity0_thresh_falling_value +what: /sys/.../events/in_proximity0_thresh_rising_value KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: @@ -490,9 +505,9 @@ What: /sys/.../events/in_magn_z_raw_roc_rising_value What: /sys/.../events/in_magn_z_raw_roc_falling_value What: /sys/.../events/in_voltageY_supply_raw_roc_rising_value What: /sys/.../events/in_voltageY_supply_raw_roc_falling_value +What: /sys/.../events/in_voltageY_raw_roc_rising_value What: /sys/.../events/in_voltageY_raw_roc_falling_value -What: /sys/.../events/in_voltageY_raw_roc_falling_value -What: /sys/.../events/in_tempY_raw_roc_falling_value +What: /sys/.../events/in_tempY_raw_roc_rising_value What: /sys/.../events/in_tempY_raw_roc_falling_value KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org @@ -556,6 +571,8 @@ What: /sys/.../events/in_tempY_thresh_falling_period What: /sys/.../events/in_tempY_roc_rising_period What: /sys/.../events/in_tempY_roc_falling_period What: /sys/.../events/in_accel_x&y&z_mag_falling_period +What: /sys/.../events/in_intensity0_thresh_period +What: /sys/.../events/in_proximity0_thresh_period KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: @@ -718,24 +735,3 @@ Contact: linux-iio@vger.kernel.org Description: This attribute is used to read the amount of quadrature error present in the device at a given time. - -What: /sys/.../iio:deviceX/ac_excitation_en -KernelVersion: 3.1.0 -Contact: linux-iio@vger.kernel.org -Description: - This attribute, if available, is used to enable the AC - excitation mode found on some converters. In ac excitation mode, - the polarity of the excitation voltage is reversed on - alternate cycles, to eliminate DC errors. - -What: /sys/.../iio:deviceX/bridge_switch_en -KernelVersion: 3.1.0 -Contact: linux-iio@vger.kernel.org -Description: - This attribute, if available, is used to close or open the - bridge power down switch found on some converters. - In bridge applications, such as strain gauges and load cells, - the bridge itself consumes the majority of the current in the - system. To minimize the current consumption of the system, - the bridge can be disconnected (when it is not being used - using the bridge_switch_en attribute. diff --git a/trunk/Documentation/ABI/testing/sysfs-bus-usb b/trunk/Documentation/ABI/testing/sysfs-bus-usb index 7c22a532fdfb..6df4e6f57560 100644 --- a/trunk/Documentation/ABI/testing/sysfs-bus-usb +++ b/trunk/Documentation/ABI/testing/sysfs-bus-usb @@ -135,6 +135,17 @@ Description: for the device and attempt to bind to it. For example: # echo "8086 10f5" > /sys/bus/usb/drivers/foo/new_id + Reading from this file will list all dynamically added + device IDs in the same format, with one entry per + line. For example: + # cat /sys/bus/usb/drivers/foo/new_id + 8086 10f5 + dead beef 06 + f00d cafe + + The list will be truncated at PAGE_SIZE bytes due to + sysfs restrictions. + What: /sys/bus/usb-serial/drivers/.../new_id Date: October 2011 Contact: linux-usb@vger.kernel.org @@ -157,6 +168,10 @@ Description: match the driver to the device. For example: # echo "046d c315" > /sys/bus/usb/drivers/foo/remove_id + Reading from this file will list the dynamically added + device IDs, exactly like reading from the entry + "/sys/bus/usb/drivers/.../new_id" + What: /sys/bus/usb/device/.../avoid_reset_quirk Date: December 2009 Contact: Oliver Neukum @@ -189,7 +204,7 @@ Contact: Matthew Garrett Description: Some information about whether a given USB device is physically fixed to the platform can be inferred from a - combination of hub decriptor bits and platform-specific data + combination of hub descriptor bits and platform-specific data such as ACPI. This file will read either "removable" or "fixed" if the information is available, and "unknown" - otherwise. \ No newline at end of file + otherwise. diff --git a/trunk/Documentation/ABI/testing/sysfs-class-extcon b/trunk/Documentation/ABI/testing/sysfs-class-extcon new file mode 100644 index 000000000000..20ab361bd8c6 --- /dev/null +++ b/trunk/Documentation/ABI/testing/sysfs-class-extcon @@ -0,0 +1,97 @@ +What: /sys/class/extcon/.../ +Date: February 2012 +Contact: MyungJoo Ham +Description: + Provide a place in sysfs for the extcon objects. + This allows accessing extcon specific variables. + The name of extcon object denoted as ... is the name given + with extcon_dev_register. + + One extcon device denotes a single external connector + port. An external connector may have multiple cables + attached simultaneously. Many of docks, cradles, and + accessory cables have such capability. For example, + the 30-pin port of Nuri board (/arch/arm/mach-exynos) + may have both HDMI and Charger attached, or analog audio, + video, and USB cables attached simulteneously. + + If there are cables mutually exclusive with each other, + such binary relations may be expressed with extcon_dev's + mutually_exclusive array. + +What: /sys/class/extcon/.../name +Date: February 2012 +Contact: MyungJoo Ham +Description: + The /sys/class/extcon/.../name shows the name of the extcon + object. If the extcon object has an optional callback + "show_name" defined, the callback will provide the name with + this sysfs node. + +What: /sys/class/extcon/.../state +Date: February 2012 +Contact: MyungJoo Ham +Description: + The /sys/class/extcon/.../state shows and stores the cable + attach/detach information of the corresponding extcon object. + If the extcon object has an optional callback "show_state" + defined, the showing function is overriden with the optional + callback. + + If the default callback for showing function is used, the + format is like this: + # cat state + USB_OTG=1 + HDMI=0 + TA=1 + EAR_JACK=0 + # + In this example, the extcon device have USB_OTG and TA + cables attached and HDMI and EAR_JACK cables detached. + + In order to update the state of an extcon device, enter a hex + state number starting with 0x. + echo 0xHEX > state + + This updates the whole state of the extcon dev. + Inputs of all the methods are required to meet the + mutually_exclusive contidions if they exist. + + It is recommended to use this "global" state interface if + you need to enter the value atomically. The later state + interface associated with each cable cannot update + multiple cable states of an extcon device simultaneously. + +What: /sys/class/extcon/.../cable.x/name +Date: February 2012 +Contact: MyungJoo Ham +Description: + The /sys/class/extcon/.../cable.x/name shows the name of cable + "x" (integer between 0 and 31) of an extcon device. + +What: /sys/class/extcon/.../cable.x/state +Date: February 2012 +Contact: MyungJoo Ham +Description: + The /sys/class/extcon/.../cable.x/name shows and stores the + state of cable "x" (integer between 0 and 31) of an extcon + device. The state value is either 0 (detached) or 1 + (attached). + +What: /sys/class/extcon/.../mutually_exclusive/... +Date: December 2011 +Contact: MyungJoo Ham +Description: + Shows the relations of mutually exclusiveness. For example, + if the mutually_exclusive array of extcon_dev is + {0x3, 0x5, 0xC, 0x0}, the, the output is: + # ls mutually_exclusive/ + 0x3 + 0x5 + 0xc + # + + Note that mutually_exclusive is a sub-directory of the extcon + device and the file names under the mutually_exclusive + directory show the mutually-exclusive sets, not the contents + of the files. diff --git a/trunk/Documentation/ABI/testing/sysfs-class-net-mesh b/trunk/Documentation/ABI/testing/sysfs-class-net-mesh index b218e0f8bdb3..c81fe89c4c46 100644 --- a/trunk/Documentation/ABI/testing/sysfs-class-net-mesh +++ b/trunk/Documentation/ABI/testing/sysfs-class-net-mesh @@ -14,6 +14,15 @@ Description: mesh will be sent using multiple interfaces at the same time (if available). +What: /sys/class/net//mesh/bridge_loop_avoidance +Date: November 2011 +Contact: Simon Wunderlich +Description: + Indicates whether the bridge loop avoidance feature + is enabled. This feature detects and avoids loops + between the mesh and devices bridged with the soft + interface . + What: /sys/class/net//mesh/fragmentation Date: October 2010 Contact: Andreas Langer diff --git a/trunk/Documentation/ABI/testing/sysfs-devices-system-cpu b/trunk/Documentation/ABI/testing/sysfs-devices-system-cpu index e7be75b96e4b..5dab36448b44 100644 --- a/trunk/Documentation/ABI/testing/sysfs-devices-system-cpu +++ b/trunk/Documentation/ABI/testing/sysfs-devices-system-cpu @@ -9,31 +9,6 @@ Description: /sys/devices/system/cpu/cpu#/ -What: /sys/devices/system/cpu/sched_mc_power_savings - /sys/devices/system/cpu/sched_smt_power_savings -Date: June 2006 -Contact: Linux kernel mailing list -Description: Discover and adjust the kernel's multi-core scheduler support. - - Possible values are: - - 0 - No power saving load balance (default value) - 1 - Fill one thread/core/package first for long running threads - 2 - Also bias task wakeups to semi-idle cpu package for power - savings - - sched_mc_power_savings is dependent upon SCHED_MC, which is - itself architecture dependent. - - sched_smt_power_savings is dependent upon SCHED_SMT, which - is itself architecture dependent. - - The two files are independent of each other. It is possible - that one file may be present without the other. - - Introduced by git commit 5c45bf27. - - What: /sys/devices/system/cpu/kernel_max /sys/devices/system/cpu/offline /sys/devices/system/cpu/online diff --git a/trunk/Documentation/ABI/testing/sysfs-driver-wacom b/trunk/Documentation/ABI/testing/sysfs-driver-wacom index 0130d6683c14..56c54558c8a4 100644 --- a/trunk/Documentation/ABI/testing/sysfs-driver-wacom +++ b/trunk/Documentation/ABI/testing/sysfs-driver-wacom @@ -9,6 +9,14 @@ Description: or 0 otherwise. Writing to this file one of these values switches reporting speed. +What: /sys/class/leds/0005\:056A\:00BD.0001\:selector\:*/ +Date: May 2012 +Kernel Version: 3.5 +Contact: linux-bluetooth@vger.kernel.org +Description: + LED selector for Intuos4 WL. There are 4 leds, but only one LED + can be lit at a time. Max brightness is 127. + What: /sys/bus/usb/devices/-:./wacom_led/led Date: August 2011 Contact: linux-input@vger.kernel.org diff --git a/trunk/Documentation/DocBook/80211.tmpl b/trunk/Documentation/DocBook/80211.tmpl index c5ac6929c41c..f3e214f9e256 100644 --- a/trunk/Documentation/DocBook/80211.tmpl +++ b/trunk/Documentation/DocBook/80211.tmpl @@ -516,7 +516,7 @@ !Finclude/net/mac80211.h ieee80211_start_tx_ba_cb_irqsafe !Finclude/net/mac80211.h ieee80211_stop_tx_ba_session !Finclude/net/mac80211.h ieee80211_stop_tx_ba_cb_irqsafe -!Finclude/net/mac80211.h rate_control_changed +!Finclude/net/mac80211.h ieee80211_rate_control_changed !Finclude/net/mac80211.h ieee80211_tx_rate_control !Finclude/net/mac80211.h rate_control_send_low diff --git a/trunk/Documentation/DocBook/kernel-hacking.tmpl b/trunk/Documentation/DocBook/kernel-hacking.tmpl index 07a9c48de5a2..eee71426ecb8 100644 --- a/trunk/Documentation/DocBook/kernel-hacking.tmpl +++ b/trunk/Documentation/DocBook/kernel-hacking.tmpl @@ -1289,7 +1289,7 @@ static struct block_device_operations opt_fops = { * Sparc assembly will do this to ya. */ C_LABEL(cputypvar): - .asciz "compatability" + .asciz "compatibility" /* Tested on SS-5, SS-10. Probably someone at Sun applied a spell-checker. */ .align 4 diff --git a/trunk/Documentation/DocBook/libata.tmpl b/trunk/Documentation/DocBook/libata.tmpl index 31df1aa00710..deb71baed328 100644 --- a/trunk/Documentation/DocBook/libata.tmpl +++ b/trunk/Documentation/DocBook/libata.tmpl @@ -918,7 +918,7 @@ and other resources, etc. HSM violation This error is indicated when STATUS value doesn't match HSM - requirement during issuing or excution any ATA/ATAPI command. + requirement during issuing or execution any ATA/ATAPI command. diff --git a/trunk/Documentation/DocBook/media/v4l/controls.xml b/trunk/Documentation/DocBook/media/v4l/controls.xml index b84f25e9cc87..dd03cf4a6539 100644 --- a/trunk/Documentation/DocBook/media/v4l/controls.xml +++ b/trunk/Documentation/DocBook/media/v4l/controls.xml @@ -2023,7 +2023,7 @@ Possible values are: integer Cyclic intra macroblock refresh. This is the number of continuous macroblocks -refreshed every frame. Each frame a succesive set of macroblocks is refreshed until the cycle completes and starts from the +refreshed every frame. Each frame a successive set of macroblocks is refreshed until the cycle completes and starts from the top of the frame. Applicable to H264, H263 and MPEG4 encoder. @@ -2183,7 +2183,7 @@ Applicable to the MPEG4 and H264 encoders. integer The Video Buffer Verifier size in kilobytes, it is used as a limitation of frame skip. -The VBV is defined in the standard as a mean to verify that the produced stream will be succesfully decoded. +The VBV is defined in the standard as a mean to verify that the produced stream will be successfully decoded. The standard describes it as "Part of a hypothetical decoder that is conceptually connected to the output of the encoder. Its purpose is to provide a constraint on the variability of the data rate that an encoder or editing process may produce.". @@ -2196,7 +2196,7 @@ Applicable to the MPEG1, MPEG2, MPEG4 encoders. integer The Coded Picture Buffer size in kilobytes, it is used as a limitation of frame skip. -The CPB is defined in the H264 standard as a mean to verify that the produced stream will be succesfully decoded. +The CPB is defined in the H264 standard as a mean to verify that the produced stream will be successfully decoded. Applicable to the H264 encoder. diff --git a/trunk/Documentation/HOWTO b/trunk/Documentation/HOWTO index f7ade3b3b40d..59c080f084ef 100644 --- a/trunk/Documentation/HOWTO +++ b/trunk/Documentation/HOWTO @@ -218,16 +218,16 @@ The development process Linux kernel development process currently consists of a few different main kernel "branches" and lots of different subsystem-specific kernel branches. These different branches are: - - main 2.6.x kernel tree - - 2.6.x.y -stable kernel tree - - 2.6.x -git kernel patches + - main 3.x kernel tree + - 3.x.y -stable kernel tree + - 3.x -git kernel patches - subsystem specific kernel trees and patches - - the 2.6.x -next kernel tree for integration tests + - the 3.x -next kernel tree for integration tests -2.6.x kernel tree +3.x kernel tree ----------------- -2.6.x kernels are maintained by Linus Torvalds, and can be found on -kernel.org in the pub/linux/kernel/v2.6/ directory. Its development +3.x kernels are maintained by Linus Torvalds, and can be found on +kernel.org in the pub/linux/kernel/v3.x/ directory. Its development process is as follows: - As soon as a new kernel is released a two weeks window is open, during this period of time maintainers can submit big diffs to @@ -262,20 +262,20 @@ mailing list about kernel releases: released according to perceived bug status, not according to a preconceived timeline." -2.6.x.y -stable kernel tree +3.x.y -stable kernel tree --------------------------- -Kernels with 4-part versions are -stable kernels. They contain +Kernels with 3-part versions are -stable kernels. They contain relatively small and critical fixes for security problems or significant -regressions discovered in a given 2.6.x kernel. +regressions discovered in a given 3.x kernel. This is the recommended branch for users who want the most recent stable kernel and are not interested in helping test development/experimental versions. -If no 2.6.x.y kernel is available, then the highest numbered 2.6.x +If no 3.x.y kernel is available, then the highest numbered 3.x kernel is the current stable kernel. -2.6.x.y are maintained by the "stable" team , and +3.x.y are maintained by the "stable" team , and are released as needs dictate. The normal release period is approximately two weeks, but it can be longer if there are no pressing problems. A security-related problem, instead, can cause a release to happen almost @@ -285,7 +285,7 @@ The file Documentation/stable_kernel_rules.txt in the kernel tree documents what kinds of changes are acceptable for the -stable tree, and how the release process works. -2.6.x -git patches +3.x -git patches ------------------ These are daily snapshots of Linus' kernel tree which are managed in a git repository (hence the name.) These patches are usually released @@ -317,13 +317,13 @@ revisions to it, and maintainers can mark patches as under review, accepted, or rejected. Most of these patchwork sites are listed at http://patchwork.kernel.org/. -2.6.x -next kernel tree for integration tests +3.x -next kernel tree for integration tests --------------------------------------------- -Before updates from subsystem trees are merged into the mainline 2.6.x +Before updates from subsystem trees are merged into the mainline 3.x tree, they need to be integration-tested. For this purpose, a special testing repository exists into which virtually all subsystem trees are pulled on an almost daily basis: - http://git.kernel.org/?p=linux/kernel/git/sfr/linux-next.git + http://git.kernel.org/?p=linux/kernel/git/next/linux-next.git http://linux.f-seidel.de/linux-next/pmwiki/ This way, the -next kernel gives a summary outlook onto what will be diff --git a/trunk/Documentation/Makefile b/trunk/Documentation/Makefile index 30b656ece7aa..31d302bc5863 100644 --- a/trunk/Documentation/Makefile +++ b/trunk/Documentation/Makefile @@ -1,3 +1,3 @@ obj-m := DocBook/ accounting/ auxdisplay/ connector/ \ filesystems/ filesystems/configfs/ ia64/ laptops/ networking/ \ - pcmcia/ spi/ timers/ watchdog/src/ + pcmcia/ spi/ timers/ watchdog/src/ misc-devices/mei/ diff --git a/trunk/Documentation/RCU/torture.txt b/trunk/Documentation/RCU/torture.txt index 375d3fb71437..4ddf3913fd8c 100644 --- a/trunk/Documentation/RCU/torture.txt +++ b/trunk/Documentation/RCU/torture.txt @@ -47,6 +47,16 @@ irqreader Says to invoke RCU readers from irq level. This is currently permit this. (Or, more accurately, variants of RCU that do -not- permit this know to ignore this variable.) +n_barrier_cbs If this is nonzero, RCU barrier testing will be conducted, + in which case n_barrier_cbs specifies the number of + RCU callbacks (and corresponding kthreads) to use for + this testing. The value cannot be negative. If you + specify this to be non-zero when torture_type indicates a + synchronous RCU implementation (one for which a member of + the synchronize_rcu() rather than the call_rcu() family is + used -- see the documentation for torture_type below), an + error will be reported and no testing will be carried out. + nfakewriters This is the number of RCU fake writer threads to run. Fake writer threads repeatedly use the synchronous "wait for current readers" function of the interface selected by @@ -188,7 +198,7 @@ OUTPUT The statistics output is as follows: rcu-torture:--- Start of test: nreaders=16 nfakewriters=4 stat_interval=30 verbose=0 test_no_idle_hz=1 shuffle_interval=3 stutter=5 irqreader=1 fqs_duration=0 fqs_holdoff=0 fqs_stutter=3 test_boost=1/0 test_boost_interval=7 test_boost_duration=4 - rcu-torture: rtc: (null) ver: 155441 tfle: 0 rta: 155441 rtaf: 8884 rtf: 155440 rtmbe: 0 rtbke: 0 rtbre: 0 rtbf: 0 rtb: 0 nt: 3055767 + rcu-torture: rtc: (null) ver: 155441 tfle: 0 rta: 155441 rtaf: 8884 rtf: 155440 rtmbe: 0 rtbe: 0 rtbke: 0 rtbre: 0 rtbf: 0 rtb: 0 nt: 3055767 rcu-torture: Reader Pipe: 727860534 34213 0 0 0 0 0 0 0 0 0 rcu-torture: Reader Batch: 727877838 17003 0 0 0 0 0 0 0 0 0 rcu-torture: Free-Block Circulation: 155440 155440 155440 155440 155440 155440 155440 155440 155440 155440 0 @@ -230,6 +240,9 @@ o "rtmbe": A non-zero value indicates that rcutorture believes that rcu_assign_pointer() and rcu_dereference() are not working correctly. This value should be zero. +o "rtbe": A non-zero value indicates that one of the rcu_barrier() + family of functions is not working correctly. + o "rtbke": rcutorture was unable to create the real-time kthreads used to force RCU priority inversion. This value should be zero. diff --git a/trunk/Documentation/arm/00-INDEX b/trunk/Documentation/arm/00-INDEX index 91c24a1e8a9e..36420e116c90 100644 --- a/trunk/Documentation/arm/00-INDEX +++ b/trunk/Documentation/arm/00-INDEX @@ -4,8 +4,6 @@ Booting - requirements for booting Interrupts - ARM Interrupt subsystem documentation -IXP2000 - - Release Notes for Linux on Intel's IXP2000 Network Processor msm - MSM specific documentation Netwinder diff --git a/trunk/Documentation/arm/IXP2000 b/trunk/Documentation/arm/IXP2000 deleted file mode 100644 index 68d21d92a30b..000000000000 --- a/trunk/Documentation/arm/IXP2000 +++ /dev/null @@ -1,69 +0,0 @@ - -------------------------------------------------------------------------- -Release Notes for Linux on Intel's IXP2000 Network Processor - -Maintained by Deepak Saxena -------------------------------------------------------------------------- - -1. Overview - -Intel's IXP2000 family of NPUs (IXP2400, IXP2800, IXP2850) is designed -for high-performance network applications such high-availability -telecom systems. In addition to an XScale core, it contains up to 8 -"MicroEngines" that run special code, several high-end networking -interfaces (UTOPIA, SPI, etc), a PCI host bridge, one serial port, -flash interface, and some other odds and ends. For more information, see: - -http://developer.intel.com - -2. Linux Support - -Linux currently supports the following features on the IXP2000 NPUs: - -- On-chip serial -- PCI -- Flash (MTD/JFFS2) -- I2C through GPIO -- Timers (watchdog, OS) - -That is about all we can support under Linux ATM b/c the core networking -components of the chip are accessed via Intel's closed source SDK. -Please contact Intel directly on issues with using those. There is -also a mailing list run by some folks at Princeton University that might -be of help: https://lists.cs.princeton.edu/mailman/listinfo/ixp2xxx - -WHATEVER YOU DO, DO NOT POST EMAIL TO THE LINUX-ARM OR LINUX-ARM-KERNEL -MAILING LISTS REGARDING THE INTEL SDK. - -3. Supported Platforms - -- Intel IXDP2400 Reference Platform -- Intel IXDP2800 Reference Platform -- Intel IXDP2401 Reference Platform -- Intel IXDP2801 Reference Platform -- RadiSys ENP-2611 - -4. Usage Notes - -- The IXP2000 platforms usually have rather complex PCI bus topologies - with large memory space requirements. In addition, b/c of the way the - Intel SDK is designed, devices are enumerated in a very specific - way. B/c of this this, we use "pci=firmware" option in the kernel - command line so that we do not re-enumerate the bus. - -- IXDP2x01 systems have variable clock tick rates that we cannot determine - via HW registers. The "ixdp2x01_clk=XXX" cmd line options allow you - to pass the clock rate to the board port. - -5. Thanks - -The IXP2000 work has been funded by Intel Corp. and MontaVista Software, Inc. - -The following people have contributed patches/comments/etc: - -Naeem F. Afzal -Lennert Buytenhek -Jeffrey Daly - -------------------------------------------------------------------------- -Last Update: 8/09/2004 diff --git a/trunk/Documentation/arm/SPEAr/overview.txt b/trunk/Documentation/arm/SPEAr/overview.txt index 253a35c6f782..28a9af953b9d 100644 --- a/trunk/Documentation/arm/SPEAr/overview.txt +++ b/trunk/Documentation/arm/SPEAr/overview.txt @@ -17,14 +17,14 @@ Introduction SPEAr (Platform) - SPEAr3XX (3XX SOC series, based on ARM9) - SPEAr300 (SOC) - - SPEAr300_EVB (Evaluation Board) + - SPEAr300 Evaluation Board - SPEAr310 (SOC) - - SPEAr310_EVB (Evaluation Board) + - SPEAr310 Evaluation Board - SPEAr320 (SOC) - - SPEAr320_EVB (Evaluation Board) + - SPEAr320 Evaluation Board - SPEAr6XX (6XX SOC series, based on ARM9) - SPEAr600 (SOC) - - SPEAr600_EVB (Evaluation Board) + - SPEAr600 Evaluation Board - SPEAr13XX (13XX SOC series, based on ARM CORTEXA9) - SPEAr1300 (SOC) @@ -51,10 +51,11 @@ Introduction Common file for machines of spear3xx family is mach-spear3xx/spear3xx.c and for spear6xx is mach-spear6xx/spear6xx.c. mach-spear* also contain soc/machine specific files, like spear300.c, spear310.c, spear320.c and spear600.c. - mach-spear* also contains board specific files for each machine type. + mach-spear* doesn't contains board specific files as they fully support + Flattened Device Tree. Document Author --------------- - Viresh Kumar, (c) 2010 ST Microelectronics + Viresh Kumar , (c) 2010-2012 ST Microelectronics diff --git a/trunk/Documentation/blackfin/bfin-gpio-notes.txt b/trunk/Documentation/blackfin/bfin-gpio-notes.txt index d36b01f778b9..d245f39c3d01 100644 --- a/trunk/Documentation/blackfin/bfin-gpio-notes.txt +++ b/trunk/Documentation/blackfin/bfin-gpio-notes.txt @@ -53,7 +53,7 @@ 3. But there are some exceptions - Kernel permit the identical GPIO be requested both as GPIO and GPIO - interrut. + interrupt. Some drivers, like gpio-keys, need this behavior. Kernel only print out warning messages like, bfin-gpio: GPIO 24 is already reserved by gpio-keys: BTN0, and you are diff --git a/trunk/Documentation/cgroups/resource_counter.txt b/trunk/Documentation/cgroups/resource_counter.txt index 95b24d766eab..f3c4ec3626a2 100644 --- a/trunk/Documentation/cgroups/resource_counter.txt +++ b/trunk/Documentation/cgroups/resource_counter.txt @@ -77,11 +77,11 @@ to work with it. where the charging failed. d. int res_counter_charge_locked - (struct res_counter *rc, unsigned long val) + (struct res_counter *rc, unsigned long val, bool force) The same as res_counter_charge(), but it must not acquire/release the res_counter->lock internally (it must be called with res_counter->lock - held). + held). The force parameter indicates whether we can bypass the limit. e. void res_counter_uncharge[_locked] (struct res_counter *rc, unsigned long val) diff --git a/trunk/Documentation/devices.txt b/trunk/Documentation/devices.txt index 00383186d8fb..5941f5136c6b 100644 --- a/trunk/Documentation/devices.txt +++ b/trunk/Documentation/devices.txt @@ -98,7 +98,8 @@ Your cooperation is appreciated. 8 = /dev/random Nondeterministic random number gen. 9 = /dev/urandom Faster, less secure random number gen. 10 = /dev/aio Asynchronous I/O notification interface - 11 = /dev/kmsg Writes to this come out as printk's + 11 = /dev/kmsg Writes to this come out as printk's, reads + export the buffered printk records. 12 = /dev/oldmem Used by crashdump kernels to access the memory of the kernel that crashed. diff --git a/trunk/Documentation/devicetree/bindings/arm/arch_timer.txt b/trunk/Documentation/devicetree/bindings/arm/arch_timer.txt new file mode 100644 index 000000000000..52478c83d0cc --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/arm/arch_timer.txt @@ -0,0 +1,27 @@ +* ARM architected timer + +ARM Cortex-A7 and Cortex-A15 have a per-core architected timer, which +provides per-cpu timers. + +The timer is attached to a GIC to deliver its per-processor interrupts. + +** Timer node properties: + +- compatible : Should at least contain "arm,armv7-timer". + +- interrupts : Interrupt list for secure, non-secure, virtual and + hypervisor timers, in that order. + +- clock-frequency : The frequency of the main counter, in Hz. Optional. + +Example: + + timer { + compatible = "arm,cortex-a15-timer", + "arm,armv7-timer"; + interrupts = <1 13 0xf08>, + <1 14 0xf08>, + <1 11 0xf08>, + <1 10 0xf08>; + clock-frequency = <100000000>; + }; diff --git a/trunk/Documentation/devicetree/bindings/arm/atmel-adc.txt b/trunk/Documentation/devicetree/bindings/arm/atmel-adc.txt new file mode 100644 index 000000000000..c63097d6afeb --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/arm/atmel-adc.txt @@ -0,0 +1,65 @@ +* AT91's Analog to Digital Converter (ADC) + +Required properties: + - compatible: Should be "atmel,at91sam9260-adc" + - reg: Should contain ADC registers location and length + - interrupts: Should contain the IRQ line for the ADC + - atmel,adc-channel-base: Offset of the first channel data register + - atmel,adc-channels-used: Bitmask of the channels muxed and enable for this + device + - atmel,adc-drdy-mask: Mask of the DRDY interruption in the ADC + - atmel,adc-num-channels: Number of channels available in the ADC + - atmel,adc-startup-time: Startup Time of the ADC in microseconds as + defined in the datasheet + - atmel,adc-status-register: Offset of the Interrupt Status Register + - atmel,adc-trigger-register: Offset of the Trigger Register + - atmel,adc-vref: Reference voltage in millivolts for the conversions + +Optional properties: + - atmel,adc-use-external: Boolean to enable of external triggers + +Optional trigger Nodes: + - Required properties: + * trigger-name: Name of the trigger exposed to the user + * trigger-value: Value to put in the Trigger register + to activate this trigger + - Optional properties: + * trigger-external: Is the trigger an external trigger? + +Examples: +adc0: adc@fffb0000 { + compatible = "atmel,at91sam9260-adc"; + reg = <0xfffb0000 0x100>; + interrupts = <20 4>; + atmel,adc-channel-base = <0x30>; + atmel,adc-channels-used = <0xff>; + atmel,adc-drdy-mask = <0x10000>; + atmel,adc-num-channels = <8>; + atmel,adc-startup-time = <40>; + atmel,adc-status-register = <0x1c>; + atmel,adc-trigger-register = <0x08>; + atmel,adc-use-external; + atmel,adc-vref = <3300>; + + trigger@0 { + trigger-name = "external-rising"; + trigger-value = <0x1>; + trigger-external; + }; + trigger@1 { + trigger-name = "external-falling"; + trigger-value = <0x2>; + trigger-external; + }; + + trigger@2 { + trigger-name = "external-any"; + trigger-value = <0x3>; + trigger-external; + }; + + trigger@3 { + trigger-name = "continuous"; + trigger-value = <0x6>; + }; +}; diff --git a/trunk/Documentation/devicetree/bindings/arm/lpc32xx-mic.txt b/trunk/Documentation/devicetree/bindings/arm/lpc32xx-mic.txt new file mode 100644 index 000000000000..539adca19e8f --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/arm/lpc32xx-mic.txt @@ -0,0 +1,38 @@ +* NXP LPC32xx Main Interrupt Controller + (MIC, including SIC1 and SIC2 secondary controllers) + +Required properties: +- compatible: Should be "nxp,lpc3220-mic" +- interrupt-controller: Identifies the node as an interrupt controller. +- interrupt-parent: Empty for the interrupt controller itself +- #interrupt-cells: The number of cells to define the interrupts. Should be 2. + The first cell is the IRQ number + The second cell is used to specify mode: + 1 = low-to-high edge triggered + 2 = high-to-low edge triggered + 4 = active high level-sensitive + 8 = active low level-sensitive + Default for internal sources should be set to 4 (active high). +- reg: Should contain MIC registers location and length + +Examples: + /* + * MIC + */ + mic: interrupt-controller@40008000 { + compatible = "nxp,lpc3220-mic"; + interrupt-controller; + interrupt-parent; + #interrupt-cells = <2>; + reg = <0x40008000 0xC000>; + }; + + /* + * ADC + */ + adc@40048000 { + compatible = "nxp,lpc3220-adc"; + reg = <0x40048000 0x1000>; + interrupt-parent = <&mic>; + interrupts = <39 4>; + }; diff --git a/trunk/Documentation/devicetree/bindings/arm/lpc32xx.txt b/trunk/Documentation/devicetree/bindings/arm/lpc32xx.txt new file mode 100644 index 000000000000..56ec8ddc4a3b --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/arm/lpc32xx.txt @@ -0,0 +1,8 @@ +NXP LPC32xx Platforms Device Tree Bindings +------------------------------------------ + +Boards with the NXP LPC32xx SoC shall have the following properties: + +Required root node property: + +compatible: must be "nxp,lpc3220", "nxp,lpc3230", "nxp,lpc3240" or "nxp,lpc3250" diff --git a/trunk/Documentation/devicetree/bindings/arm/mrvl.txt b/trunk/Documentation/devicetree/bindings/arm/mrvl.txt deleted file mode 100644 index d8de933e9d81..000000000000 --- a/trunk/Documentation/devicetree/bindings/arm/mrvl.txt +++ /dev/null @@ -1,6 +0,0 @@ -Marvell Platforms Device Tree Bindings ----------------------------------------------------- - -PXA168 Aspenite Board -Required root node properties: - - compatible = "mrvl,pxa168-aspenite", "mrvl,pxa168"; diff --git a/trunk/Documentation/devicetree/bindings/arm/mrvl/intc.txt b/trunk/Documentation/devicetree/bindings/arm/mrvl/intc.txt new file mode 100644 index 000000000000..80b9a94d9a23 --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/arm/mrvl/intc.txt @@ -0,0 +1,40 @@ +* Marvell MMP Interrupt controller + +Required properties: +- compatible : Should be "mrvl,mmp-intc", "mrvl,mmp2-intc" or + "mrvl,mmp2-mux-intc" +- reg : Address and length of the register set of the interrupt controller. + If the interrupt controller is intc, address and length means the range + of the whold interrupt controller. If the interrupt controller is mux-intc, + address and length means one register. Since address of mux-intc is in the + range of intc. mux-intc is secondary interrupt controller. +- reg-names : Name of the register set of the interrupt controller. It's + only required in mux-intc interrupt controller. +- interrupts : Should be the port interrupt shared by mux interrupts. It's + only required in mux-intc interrupt controller. +- interrupt-controller : Identifies the node as an interrupt controller. +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. +- mrvl,intc-nr-irqs : Specifies the number of interrupts in the interrupt + controller. +- mrvl,clr-mfp-irq : Specifies the interrupt that needs to clear MFP edge + detection first. + +Example: + intc: interrupt-controller@d4282000 { + compatible = "mrvl,mmp2-intc"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0xd4282000 0x1000>; + mrvl,intc-nr-irqs = <64>; + }; + + intcmux4@d4282150 { + compatible = "mrvl,mmp2-mux-intc"; + interrupts = <4>; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x150 0x4>, <0x168 0x4>; + reg-names = "mux status", "mux mask"; + mrvl,intc-nr-irqs = <2>; + }; diff --git a/trunk/Documentation/devicetree/bindings/arm/mrvl/mrvl.txt b/trunk/Documentation/devicetree/bindings/arm/mrvl/mrvl.txt new file mode 100644 index 000000000000..117d741a2e4f --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/arm/mrvl/mrvl.txt @@ -0,0 +1,14 @@ +Marvell Platforms Device Tree Bindings +---------------------------------------------------- + +PXA168 Aspenite Board +Required root node properties: + - compatible = "mrvl,pxa168-aspenite", "mrvl,pxa168"; + +PXA910 DKB Board +Required root node properties: + - compatible = "mrvl,pxa910-dkb"; + +MMP2 Brownstone Board +Required root node properties: + - compatible = "mrvl,mmp2-brownstone"; diff --git a/trunk/Documentation/devicetree/bindings/arm/mrvl/timer.txt b/trunk/Documentation/devicetree/bindings/arm/mrvl/timer.txt new file mode 100644 index 000000000000..9a6e251462e7 --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/arm/mrvl/timer.txt @@ -0,0 +1,13 @@ +* Marvell MMP Timer controller + +Required properties: +- compatible : Should be "mrvl,mmp-timer". +- reg : Address and length of the register set of timer controller. +- interrupts : Should be the interrupt number. + +Example: + timer0: timer@d4014000 { + compatible = "mrvl,mmp-timer"; + reg = <0xd4014000 0x100>; + interrupts = <13>; + }; diff --git a/trunk/Documentation/devicetree/bindings/arm/spear.txt b/trunk/Documentation/devicetree/bindings/arm/spear.txt index f8e54f092328..aa5f355cc947 100644 --- a/trunk/Documentation/devicetree/bindings/arm/spear.txt +++ b/trunk/Documentation/devicetree/bindings/arm/spear.txt @@ -6,3 +6,21 @@ Boards with the ST SPEAr600 SoC shall have the following properties: Required root node property: compatible = "st,spear600"; + +Boards with the ST SPEAr300 SoC shall have the following properties: + +Required root node property: + +compatible = "st,spear300"; + +Boards with the ST SPEAr310 SoC shall have the following properties: + +Required root node property: + +compatible = "st,spear310"; + +Boards with the ST SPEAr320 SoC shall have the following properties: + +Required root node property: + +compatible = "st,spear320"; diff --git a/trunk/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-mc.txt b/trunk/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-mc.txt new file mode 100644 index 000000000000..c25a0a55151d --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-mc.txt @@ -0,0 +1,16 @@ +NVIDIA Tegra20 MC(Memory Controller) + +Required properties: +- compatible : "nvidia,tegra20-mc" +- reg : Should contain 2 register ranges(address and length); see the + example below. Note that the MC registers are interleaved with the + GART registers, and hence must be represented as multiple ranges. +- interrupts : Should contain MC General interrupt. + +Example: + mc { + compatible = "nvidia,tegra20-mc"; + reg = <0x7000f000 0x024 + 0x7000f03c 0x3c4>; + interrupts = <0 77 0x04>; + }; diff --git a/trunk/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra30-mc.txt b/trunk/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra30-mc.txt new file mode 100644 index 000000000000..e47e73f612f4 --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra30-mc.txt @@ -0,0 +1,18 @@ +NVIDIA Tegra30 MC(Memory Controller) + +Required properties: +- compatible : "nvidia,tegra30-mc" +- reg : Should contain 4 register ranges(address and length); see the + example below. Note that the MC registers are interleaved with the + SMMU registers, and hence must be represented as multiple ranges. +- interrupts : Should contain MC General interrupt. + +Example: + mc { + compatible = "nvidia,tegra30-mc"; + reg = <0x7000f000 0x010 + 0x7000f03c 0x1b4 + 0x7000f200 0x028 + 0x7000f284 0x17c>; + interrupts = <0 77 0x04>; + }; diff --git a/trunk/Documentation/devicetree/bindings/gpio/gpio-nmk.txt b/trunk/Documentation/devicetree/bindings/gpio/gpio-nmk.txt new file mode 100644 index 000000000000..ee87467ad8d6 --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/gpio/gpio-nmk.txt @@ -0,0 +1,31 @@ +Nomadik GPIO controller + +Required properties: +- compatible : Should be "st,nomadik-gpio". +- reg : Physical base address and length of the controller's registers. +- interrupts : The interrupt outputs from the controller. +- #gpio-cells : Should be two: + The first cell is the pin number. + The second cell is used to specify optional parameters: + - bits[3:0] trigger type and level flags: + 1 = low-to-high edge triggered. + 2 = high-to-low edge triggered. + 4 = active high level-sensitive. + 8 = active low level-sensitive. +- gpio-controller : Marks the device node as a GPIO controller. +- interrupt-controller : Marks the device node as an interrupt controller. +- gpio-bank : Specifies which bank a controller owns. +- st,supports-sleepmode : Specifies whether controller can sleep or not + +Example: + + gpio1: gpio@8012e080 { + compatible = "st,nomadik-gpio"; + reg = <0x8012e080 0x80>; + interrupts = <0 120 0x4>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + supports-sleepmode; + gpio-bank = <1>; + }; diff --git a/trunk/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt b/trunk/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt index 1e34cfe5ebea..05428f39d9ac 100644 --- a/trunk/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt +++ b/trunk/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt @@ -3,19 +3,25 @@ Required properties: - compatible : Should be "mrvl,pxa-gpio" or "mrvl,mmp-gpio" - reg : Address and length of the register set for the device -- interrupts : Should be the port interrupt shared by all gpio pins, if -- interrupt-name : Should be the name of irq resource. - one number. +- interrupts : Should be the port interrupt shared by all gpio pins. + There're three gpio interrupts in arch-pxa, and they're gpio0, + gpio1 and gpio_mux. There're only one gpio interrupt in arch-mmp, + gpio_mux. +- interrupt-name : Should be the name of irq resource. Each interrupt + binds its interrupt-name. +- interrupt-controller : Identifies the node as an interrupt controller. +- #interrupt-cells: Specifies the number of cells needed to encode an + interrupt source. - gpio-controller : Marks the device node as a gpio controller. - #gpio-cells : Should be one. It is the pin number. Example: gpio: gpio@d4019000 { - compatible = "mrvl,mmp-gpio", "mrvl,pxa-gpio"; + compatible = "mrvl,mmp-gpio"; reg = <0xd4019000 0x1000>; - interrupts = <49>, <17>, <18>; - interrupt-name = "gpio_mux", "gpio0", "gpio1"; + interrupts = <49>; + interrupt-name = "gpio_mux"; gpio-controller; #gpio-cells = <1>; interrupt-controller; diff --git a/trunk/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt b/trunk/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt index 071eb3caae91..b891ee218354 100644 --- a/trunk/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt +++ b/trunk/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt @@ -3,34 +3,31 @@ Required properties : - reg : Offset and length of the register set for the device - - compatible : should be "mrvl,mmp-twsi" where CHIP is the name of a + - compatible : should be "mrvl,mmp-twsi" where mmp is the name of a compatible processor, e.g. pxa168, pxa910, mmp2, mmp3. For the pxa2xx/pxa3xx, an additional node "mrvl,pxa-i2c" is required as shown in the example below. Recommended properties : - - interrupts : where a is the interrupt number and b is a - field that represents an encoding of the sense and level - information for the interrupt. This should be encoded based on - the information in section 2) depending on the type of interrupt - controller you have. + - interrupts : the interrupt number - interrupt-parent : the phandle for the interrupt controller that - services interrupts for this device. + services interrupts for this device. If the parent is the default + interrupt controller in device tree, it could be ignored. - mrvl,i2c-polling : Disable interrupt of i2c controller. Polling status register of i2c controller instead. - mrvl,i2c-fast-mode : Enable fast mode of i2c controller. Examples: twsi1: i2c@d4011000 { - compatible = "mrvl,mmp-twsi", "mrvl,pxa-i2c"; + compatible = "mrvl,mmp-twsi"; reg = <0xd4011000 0x1000>; interrupts = <7>; mrvl,i2c-fast-mode; }; twsi2: i2c@d4025000 { - compatible = "mrvl,mmp-twsi", "mrvl,pxa-i2c"; + compatible = "mrvl,mmp-twsi"; reg = <0xd4025000 0x1000>; interrupts = <58>; }; diff --git a/trunk/Documentation/devicetree/bindings/i2c/pnx.txt b/trunk/Documentation/devicetree/bindings/i2c/pnx.txt new file mode 100644 index 000000000000..fe98ada33ee4 --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/i2c/pnx.txt @@ -0,0 +1,36 @@ +* NXP PNX I2C Controller + +Required properties: + + - reg: Offset and length of the register set for the device + - compatible: should be "nxp,pnx-i2c" + - interrupts: configure one interrupt line + - #address-cells: always 1 (for i2c addresses) + - #size-cells: always 0 + - interrupt-parent: the phandle for the interrupt controller that + services interrupts for this device. + +Optional properties: + + - clock-frequency: desired I2C bus clock frequency in Hz, Default: 100000 Hz + +Examples: + + i2c1: i2c@400a0000 { + compatible = "nxp,pnx-i2c"; + reg = <0x400a0000 0x100>; + interrupt-parent = <&mic>; + interrupts = <51 0>; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c2: i2c@400a8000 { + compatible = "nxp,pnx-i2c"; + reg = <0x400a8000 0x100>; + interrupt-parent = <&mic>; + interrupts = <50 0>; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <100000>; + }; diff --git a/trunk/Documentation/devicetree/bindings/misc/bmp085.txt b/trunk/Documentation/devicetree/bindings/misc/bmp085.txt new file mode 100644 index 000000000000..91dfda2e4e11 --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/misc/bmp085.txt @@ -0,0 +1,20 @@ +BMP085/BMP18x digital pressure sensors + +Required properties: +- compatible: bosch,bmp085 + +Optional properties: +- chip-id: configurable chip id for non-default chip revisions +- temp-measurement-period: temperature measurement period (milliseconds) +- default-oversampling: default oversampling value to be used at startup, + value range is 0-3 with rising sensitivity. + +Example: + +pressure@77 { + compatible = "bosch,bmp085"; + reg = <0x77>; + chip-id = <10>; + temp-measurement-period = <100>; + default-oversampling = <2>; +}; diff --git a/trunk/Documentation/devicetree/bindings/mtd/orion-nand.txt b/trunk/Documentation/devicetree/bindings/mtd/orion-nand.txt new file mode 100644 index 000000000000..b2356b7d2fa4 --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/mtd/orion-nand.txt @@ -0,0 +1,50 @@ +NAND support for Marvell Orion SoC platforms + +Required properties: +- compatible : "mrvl,orion-nand". +- reg : Base physical address of the NAND and length of memory mapped + region + +Optional properties: +- cle : Address line number connected to CLE. Default is 0 +- ale : Address line number connected to ALE. Default is 1 +- bank-width : Width in bytes of the device. Default is 1 +- chip-delay : Chip dependent delay for transferring data from array to read + registers in usecs + +The device tree may optionally contain sub-nodes describing partitions of the +address space. See partition.txt for more detail. + +Example: + +nand@f4000000 { + #address-cells = <1>; + #size-cells = <1>; + cle = <0>; + ale = <1>; + bank-width = <1>; + chip-delay = <25>; + compatible = "mrvl,orion-nand"; + reg = <0xf4000000 0x400>; + + partition@0 { + label = "u-boot"; + reg = <0x0000000 0x100000>; + read-only; + }; + + partition@100000 { + label = "uImage"; + reg = <0x0100000 0x200000>; + }; + + partition@300000 { + label = "dtb"; + reg = <0x0300000 0x100000>; + }; + + partition@400000 { + label = "root"; + reg = <0x0400000 0x7d00000>; + }; +}; diff --git a/trunk/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt b/trunk/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt index 1ad80d5865a9..f31b686d4556 100644 --- a/trunk/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt +++ b/trunk/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt @@ -1,4 +1,4 @@ -Flexcan CAN contoller on Freescale's ARM and PowerPC system-on-a-chip (SOC). +Flexcan CAN controller on Freescale's ARM and PowerPC system-on-a-chip (SOC). Required properties: diff --git a/trunk/Documentation/devicetree/bindings/net/lpc-eth.txt b/trunk/Documentation/devicetree/bindings/net/lpc-eth.txt new file mode 100644 index 000000000000..585021acd178 --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/net/lpc-eth.txt @@ -0,0 +1,24 @@ +* NXP LPC32xx SoC Ethernet Controller + +Required properties: +- compatible: Should be "nxp,lpc-eth" +- reg: Address and length of the register set for the device +- interrupts: Should contain ethernet controller interrupt + +Optional properties: +- phy-mode: String, operation mode of the PHY interface. + Supported values are: "mii", "rmii" (default) +- use-iram: Use LPC32xx internal SRAM (IRAM) for DMA buffering +- local-mac-address : 6 bytes, mac address + +Example: + + mac: ethernet@31060000 { + compatible = "nxp,lpc-eth"; + reg = <0x31060000 0x1000>; + interrupt-parent = <&mic>; + interrupts = <29 0>; + + phy-mode = "rmii"; + use-iram; + }; diff --git a/trunk/Documentation/devicetree/bindings/net/mdio-mux-gpio.txt b/trunk/Documentation/devicetree/bindings/net/mdio-mux-gpio.txt new file mode 100644 index 000000000000..79384113c2b0 --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/net/mdio-mux-gpio.txt @@ -0,0 +1,127 @@ +Properties for an MDIO bus multiplexer/switch controlled by GPIO pins. + +This is a special case of a MDIO bus multiplexer. One or more GPIO +lines are used to control which child bus is connected. + +Required properties in addition to the generic multiplexer properties: + +- compatible : mdio-mux-gpio. +- gpios : GPIO specifiers for each GPIO line. One or more must be specified. + + +Example : + + /* The parent MDIO bus. */ + smi1: mdio@1180000001900 { + compatible = "cavium,octeon-3860-mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0x00001900 0x0 0x40>; + }; + + /* + An NXP sn74cbtlv3253 dual 1-of-4 switch controlled by a + pair of GPIO lines. Child busses 2 and 3 populated with 4 + PHYs each. + */ + mdio-mux { + compatible = "mdio-mux-gpio"; + gpios = <&gpio1 3 0>, <&gpio1 4 0>; + mdio-parent-bus = <&smi1>; + #address-cells = <1>; + #size-cells = <0>; + + mdio@2 { + reg = <2>; + #address-cells = <1>; + #size-cells = <0>; + + phy11: ethernet-phy@1 { + reg = <1>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <10 8>; /* Pin 10, active low */ + }; + phy12: ethernet-phy@2 { + reg = <2>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <10 8>; /* Pin 10, active low */ + }; + phy13: ethernet-phy@3 { + reg = <3>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <10 8>; /* Pin 10, active low */ + }; + phy14: ethernet-phy@4 { + reg = <4>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <10 8>; /* Pin 10, active low */ + }; + }; + + mdio@3 { + reg = <3>; + #address-cells = <1>; + #size-cells = <0>; + + phy21: ethernet-phy@1 { + reg = <1>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <12 8>; /* Pin 12, active low */ + }; + phy22: ethernet-phy@2 { + reg = <2>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <12 8>; /* Pin 12, active low */ + }; + phy23: ethernet-phy@3 { + reg = <3>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <12 8>; /* Pin 12, active low */ + }; + phy24: ethernet-phy@4 { + reg = <4>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <12 8>; /* Pin 12, active low */ + }; + }; + }; diff --git a/trunk/Documentation/devicetree/bindings/net/mdio-mux.txt b/trunk/Documentation/devicetree/bindings/net/mdio-mux.txt new file mode 100644 index 000000000000..f65606f8d632 --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/net/mdio-mux.txt @@ -0,0 +1,136 @@ +Common MDIO bus multiplexer/switch properties. + +An MDIO bus multiplexer/switch will have several child busses that are +numbered uniquely in a device dependent manner. The nodes for an MDIO +bus multiplexer/switch will have one child node for each child bus. + +Required properties: +- mdio-parent-bus : phandle to the parent MDIO bus. +- #address-cells = <1>; +- #size-cells = <0>; + +Optional properties: +- Other properties specific to the multiplexer/switch hardware. + +Required properties for child nodes: +- #address-cells = <1>; +- #size-cells = <0>; +- reg : The sub-bus number. + + +Example : + + /* The parent MDIO bus. */ + smi1: mdio@1180000001900 { + compatible = "cavium,octeon-3860-mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0x00001900 0x0 0x40>; + }; + + /* + An NXP sn74cbtlv3253 dual 1-of-4 switch controlled by a + pair of GPIO lines. Child busses 2 and 3 populated with 4 + PHYs each. + */ + mdio-mux { + compatible = "mdio-mux-gpio"; + gpios = <&gpio1 3 0>, <&gpio1 4 0>; + mdio-parent-bus = <&smi1>; + #address-cells = <1>; + #size-cells = <0>; + + mdio@2 { + reg = <2>; + #address-cells = <1>; + #size-cells = <0>; + + phy11: ethernet-phy@1 { + reg = <1>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <10 8>; /* Pin 10, active low */ + }; + phy12: ethernet-phy@2 { + reg = <2>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <10 8>; /* Pin 10, active low */ + }; + phy13: ethernet-phy@3 { + reg = <3>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <10 8>; /* Pin 10, active low */ + }; + phy14: ethernet-phy@4 { + reg = <4>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <10 8>; /* Pin 10, active low */ + }; + }; + + mdio@3 { + reg = <3>; + #address-cells = <1>; + #size-cells = <0>; + + phy21: ethernet-phy@1 { + reg = <1>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <12 8>; /* Pin 12, active low */ + }; + phy22: ethernet-phy@2 { + reg = <2>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <12 8>; /* Pin 12, active low */ + }; + phy23: ethernet-phy@3 { + reg = <3>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <12 8>; /* Pin 12, active low */ + }; + phy24: ethernet-phy@4 { + reg = <4>; + compatible = "marvell,88e1149r"; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <12 8>; /* Pin 12, active low */ + }; + }; + }; diff --git a/trunk/Documentation/devicetree/bindings/pinctrl/fsl,imx-pinctrl.txt b/trunk/Documentation/devicetree/bindings/pinctrl/fsl,imx-pinctrl.txt new file mode 100644 index 000000000000..ab19e6bc7d3b --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/pinctrl/fsl,imx-pinctrl.txt @@ -0,0 +1,95 @@ +* Freescale IOMUX Controller (IOMUXC) for i.MX + +The IOMUX Controller (IOMUXC), together with the IOMUX, enables the IC +to share one PAD to several functional blocks. The sharing is done by +multiplexing the PAD input/output signals. For each PAD there are up to +8 muxing options (called ALT modes). Since different modules require +different PAD settings (like pull up, keeper, etc) the IOMUXC controls +also the PAD settings parameters. + +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". + +Freescale IMX pin configuration node is a node of a group of pins which can be +used for a specific device or function. This node represents both mux and config +of the pins in that group. The 'mux' selects the function mode(also named mux +mode) this pin can work on and the 'config' configures various pad settings +such as pull-up, open drain, drive strength, etc. + +Required properties for iomux controller: +- compatible: "fsl,-iomuxc" + Please refer to each fsl,-pinctrl.txt binding doc for supported SoCs. + +Required properties for pin configuration node: +- fsl,pins: two integers array, represents a group of pins mux and config + setting. The format is fsl,pins = , PIN_FUNC_ID is a + pin working on a specific function, CONFIG is the pad setting value like + pull-up on this pin. Please refer to fsl,-pinctrl.txt for the valid + pins and functions of each SoC. + +Bits used for CONFIG: +NO_PAD_CTL(1 << 31): indicate this pin does not need config. + +SION(1 << 30): Software Input On Field. +Force the selected mux mode input path no matter of MUX_MODE functionality. +By default the input path is determined by functionality of the selected +mux mode (regular). + +Other bits are used for PAD setting. +Please refer to each fsl,-pinctrl,txt binding doc for SoC specific part +of bits definitions. + +NOTE: +Some requirements for using fsl,imx-pinctrl binding: +1. We have pin function node defined under iomux controller node to represent + what pinmux functions this SoC supports. +2. The pin configuration node intends to work on a specific function should + to be defined under that specific function node. + The function node's name should represent well about what function + this group of pins in this pin configuration node are working on. +3. The driver can use the function node's name and pin configuration node's + name describe the pin function and group hierarchy. + For example, Linux IMX pinctrl driver takes the function node's name + as the function name and pin configuration node's name as group name to + create the map table. +4. Each pin configuration node should have a phandle, devices can set pins + configurations by referring to the phandle of that pin configuration node. + +Examples: +usdhc@0219c000 { /* uSDHC4 */ + fsl,card-wired; + vmmc-supply = <®_3p3v>; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc4_1>; +}; + +iomuxc@020e0000 { + compatible = "fsl,imx6q-iomuxc"; + reg = <0x020e0000 0x4000>; + + /* shared pinctrl settings */ + usdhc4 { + pinctrl_usdhc4_1: usdhc4grp-1 { + fsl,pins = <1386 0x17059 /* MX6Q_PAD_SD4_CMD__USDHC4_CMD */ + 1392 0x10059 /* MX6Q_PAD_SD4_CLK__USDHC4_CLK */ + 1462 0x17059 /* MX6Q_PAD_SD4_DAT0__USDHC4_DAT0 */ + 1470 0x17059 /* MX6Q_PAD_SD4_DAT1__USDHC4_DAT1 */ + 1478 0x17059 /* MX6Q_PAD_SD4_DAT2__USDHC4_DAT2 */ + 1486 0x17059 /* MX6Q_PAD_SD4_DAT3__USDHC4_DAT3 */ + 1493 0x17059 /* MX6Q_PAD_SD4_DAT4__USDHC4_DAT4 */ + 1501 0x17059 /* MX6Q_PAD_SD4_DAT5__USDHC4_DAT5 */ + 1509 0x17059 /* MX6Q_PAD_SD4_DAT6__USDHC4_DAT6 */ + 1517 0x17059>; /* MX6Q_PAD_SD4_DAT7__USDHC4_DAT7 */ + }; + }; + .... +}; +Refer to the IOMUXC controller chapter in imx6q datasheet, +0x17059 means enable hysteresis, 47KOhm Pull Up, 50Mhz speed, +80Ohm driver strength and Fast Slew Rate. +User should refer to each SoC spec to set the correct value. + +TODO: when dtc macro support is available, we can change above raw data +to dt macro which can get better readability in dts file. diff --git a/trunk/Documentation/devicetree/bindings/pinctrl/fsl,imx51-pinctrl.txt b/trunk/Documentation/devicetree/bindings/pinctrl/fsl,imx51-pinctrl.txt new file mode 100644 index 000000000000..b96fa4c31745 --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/pinctrl/fsl,imx51-pinctrl.txt @@ -0,0 +1,787 @@ +* Freescale IMX51 IOMUX Controller + +Please refer to fsl,imx-pinctrl.txt in this directory for common binding part +and usage. + +Required properties: +- compatible: "fsl,imx51-iomuxc" +- fsl,pins: two integers array, represents a group of pins mux and config + setting. The format is fsl,pins = , PIN_FUNC_ID is a + pin working on a specific function, CONFIG is the pad setting value like + pull-up for this pin. Please refer to imx51 datasheet for the valid pad + config settings. + +CONFIG bits definition: +PAD_CTL_HVE (1 << 13) +PAD_CTL_HYS (1 << 8) +PAD_CTL_PKE (1 << 7) +PAD_CTL_PUE (1 << 6) +PAD_CTL_PUS_100K_DOWN (0 << 4) +PAD_CTL_PUS_47K_UP (1 << 4) +PAD_CTL_PUS_100K_UP (2 << 4) +PAD_CTL_PUS_22K_UP (3 << 4) +PAD_CTL_ODE (1 << 3) +PAD_CTL_DSE_LOW (0 << 1) +PAD_CTL_DSE_MED (1 << 1) +PAD_CTL_DSE_HIGH (2 << 1) +PAD_CTL_DSE_MAX (3 << 1) +PAD_CTL_SRE_FAST (1 << 0) +PAD_CTL_SRE_SLOW (0 << 0) + +See below for available PIN_FUNC_ID for imx51: +MX51_PAD_EIM_D16__AUD4_RXFS 0 +MX51_PAD_EIM_D16__AUD5_TXD 1 +MX51_PAD_EIM_D16__EIM_D16 2 +MX51_PAD_EIM_D16__GPIO2_0 3 +MX51_PAD_EIM_D16__I2C1_SDA 4 +MX51_PAD_EIM_D16__UART2_CTS 5 +MX51_PAD_EIM_D16__USBH2_DATA0 6 +MX51_PAD_EIM_D17__AUD5_RXD 7 +MX51_PAD_EIM_D17__EIM_D17 8 +MX51_PAD_EIM_D17__GPIO2_1 9 +MX51_PAD_EIM_D17__UART2_RXD 10 +MX51_PAD_EIM_D17__UART3_CTS 11 +MX51_PAD_EIM_D17__USBH2_DATA1 12 +MX51_PAD_EIM_D18__AUD5_TXC 13 +MX51_PAD_EIM_D18__EIM_D18 14 +MX51_PAD_EIM_D18__GPIO2_2 15 +MX51_PAD_EIM_D18__UART2_TXD 16 +MX51_PAD_EIM_D18__UART3_RTS 17 +MX51_PAD_EIM_D18__USBH2_DATA2 18 +MX51_PAD_EIM_D19__AUD4_RXC 19 +MX51_PAD_EIM_D19__AUD5_TXFS 20 +MX51_PAD_EIM_D19__EIM_D19 21 +MX51_PAD_EIM_D19__GPIO2_3 22 +MX51_PAD_EIM_D19__I2C1_SCL 23 +MX51_PAD_EIM_D19__UART2_RTS 24 +MX51_PAD_EIM_D19__USBH2_DATA3 25 +MX51_PAD_EIM_D20__AUD4_TXD 26 +MX51_PAD_EIM_D20__EIM_D20 27 +MX51_PAD_EIM_D20__GPIO2_4 28 +MX51_PAD_EIM_D20__SRTC_ALARM_DEB 29 +MX51_PAD_EIM_D20__USBH2_DATA4 30 +MX51_PAD_EIM_D21__AUD4_RXD 31 +MX51_PAD_EIM_D21__EIM_D21 32 +MX51_PAD_EIM_D21__GPIO2_5 33 +MX51_PAD_EIM_D21__SRTC_ALARM_DEB 34 +MX51_PAD_EIM_D21__USBH2_DATA5 35 +MX51_PAD_EIM_D22__AUD4_TXC 36 +MX51_PAD_EIM_D22__EIM_D22 37 +MX51_PAD_EIM_D22__GPIO2_6 38 +MX51_PAD_EIM_D22__USBH2_DATA6 39 +MX51_PAD_EIM_D23__AUD4_TXFS 40 +MX51_PAD_EIM_D23__EIM_D23 41 +MX51_PAD_EIM_D23__GPIO2_7 42 +MX51_PAD_EIM_D23__SPDIF_OUT1 43 +MX51_PAD_EIM_D23__USBH2_DATA7 44 +MX51_PAD_EIM_D24__AUD6_RXFS 45 +MX51_PAD_EIM_D24__EIM_D24 46 +MX51_PAD_EIM_D24__GPIO2_8 47 +MX51_PAD_EIM_D24__I2C2_SDA 48 +MX51_PAD_EIM_D24__UART3_CTS 49 +MX51_PAD_EIM_D24__USBOTG_DATA0 50 +MX51_PAD_EIM_D25__EIM_D25 51 +MX51_PAD_EIM_D25__KEY_COL6 52 +MX51_PAD_EIM_D25__UART2_CTS 53 +MX51_PAD_EIM_D25__UART3_RXD 54 +MX51_PAD_EIM_D25__USBOTG_DATA1 55 +MX51_PAD_EIM_D26__EIM_D26 56 +MX51_PAD_EIM_D26__KEY_COL7 57 +MX51_PAD_EIM_D26__UART2_RTS 58 +MX51_PAD_EIM_D26__UART3_TXD 59 +MX51_PAD_EIM_D26__USBOTG_DATA2 60 +MX51_PAD_EIM_D27__AUD6_RXC 61 +MX51_PAD_EIM_D27__EIM_D27 62 +MX51_PAD_EIM_D27__GPIO2_9 63 +MX51_PAD_EIM_D27__I2C2_SCL 64 +MX51_PAD_EIM_D27__UART3_RTS 65 +MX51_PAD_EIM_D27__USBOTG_DATA3 66 +MX51_PAD_EIM_D28__AUD6_TXD 67 +MX51_PAD_EIM_D28__EIM_D28 68 +MX51_PAD_EIM_D28__KEY_ROW4 69 +MX51_PAD_EIM_D28__USBOTG_DATA4 70 +MX51_PAD_EIM_D29__AUD6_RXD 71 +MX51_PAD_EIM_D29__EIM_D29 72 +MX51_PAD_EIM_D29__KEY_ROW5 73 +MX51_PAD_EIM_D29__USBOTG_DATA5 74 +MX51_PAD_EIM_D30__AUD6_TXC 75 +MX51_PAD_EIM_D30__EIM_D30 76 +MX51_PAD_EIM_D30__KEY_ROW6 77 +MX51_PAD_EIM_D30__USBOTG_DATA6 78 +MX51_PAD_EIM_D31__AUD6_TXFS 79 +MX51_PAD_EIM_D31__EIM_D31 80 +MX51_PAD_EIM_D31__KEY_ROW7 81 +MX51_PAD_EIM_D31__USBOTG_DATA7 82 +MX51_PAD_EIM_A16__EIM_A16 83 +MX51_PAD_EIM_A16__GPIO2_10 84 +MX51_PAD_EIM_A16__OSC_FREQ_SEL0 85 +MX51_PAD_EIM_A17__EIM_A17 86 +MX51_PAD_EIM_A17__GPIO2_11 87 +MX51_PAD_EIM_A17__OSC_FREQ_SEL1 88 +MX51_PAD_EIM_A18__BOOT_LPB0 89 +MX51_PAD_EIM_A18__EIM_A18 90 +MX51_PAD_EIM_A18__GPIO2_12 91 +MX51_PAD_EIM_A19__BOOT_LPB1 92 +MX51_PAD_EIM_A19__EIM_A19 93 +MX51_PAD_EIM_A19__GPIO2_13 94 +MX51_PAD_EIM_A20__BOOT_UART_SRC0 95 +MX51_PAD_EIM_A20__EIM_A20 96 +MX51_PAD_EIM_A20__GPIO2_14 97 +MX51_PAD_EIM_A21__BOOT_UART_SRC1 98 +MX51_PAD_EIM_A21__EIM_A21 99 +MX51_PAD_EIM_A21__GPIO2_15 100 +MX51_PAD_EIM_A22__EIM_A22 101 +MX51_PAD_EIM_A22__GPIO2_16 102 +MX51_PAD_EIM_A23__BOOT_HPN_EN 103 +MX51_PAD_EIM_A23__EIM_A23 104 +MX51_PAD_EIM_A23__GPIO2_17 105 +MX51_PAD_EIM_A24__EIM_A24 106 +MX51_PAD_EIM_A24__GPIO2_18 107 +MX51_PAD_EIM_A24__USBH2_CLK 108 +MX51_PAD_EIM_A25__DISP1_PIN4 109 +MX51_PAD_EIM_A25__EIM_A25 110 +MX51_PAD_EIM_A25__GPIO2_19 111 +MX51_PAD_EIM_A25__USBH2_DIR 112 +MX51_PAD_EIM_A26__CSI1_DATA_EN 113 +MX51_PAD_EIM_A26__DISP2_EXT_CLK 114 +MX51_PAD_EIM_A26__EIM_A26 115 +MX51_PAD_EIM_A26__GPIO2_20 116 +MX51_PAD_EIM_A26__USBH2_STP 117 +MX51_PAD_EIM_A27__CSI2_DATA_EN 118 +MX51_PAD_EIM_A27__DISP1_PIN1 119 +MX51_PAD_EIM_A27__EIM_A27 120 +MX51_PAD_EIM_A27__GPIO2_21 121 +MX51_PAD_EIM_A27__USBH2_NXT 122 +MX51_PAD_EIM_EB0__EIM_EB0 123 +MX51_PAD_EIM_EB1__EIM_EB1 124 +MX51_PAD_EIM_EB2__AUD5_RXFS 125 +MX51_PAD_EIM_EB2__CSI1_D2 126 +MX51_PAD_EIM_EB2__EIM_EB2 127 +MX51_PAD_EIM_EB2__FEC_MDIO 128 +MX51_PAD_EIM_EB2__GPIO2_22 129 +MX51_PAD_EIM_EB2__GPT_CMPOUT1 130 +MX51_PAD_EIM_EB3__AUD5_RXC 131 +MX51_PAD_EIM_EB3__CSI1_D3 132 +MX51_PAD_EIM_EB3__EIM_EB3 133 +MX51_PAD_EIM_EB3__FEC_RDATA1 134 +MX51_PAD_EIM_EB3__GPIO2_23 135 +MX51_PAD_EIM_EB3__GPT_CMPOUT2 136 +MX51_PAD_EIM_OE__EIM_OE 137 +MX51_PAD_EIM_OE__GPIO2_24 138 +MX51_PAD_EIM_CS0__EIM_CS0 139 +MX51_PAD_EIM_CS0__GPIO2_25 140 +MX51_PAD_EIM_CS1__EIM_CS1 141 +MX51_PAD_EIM_CS1__GPIO2_26 142 +MX51_PAD_EIM_CS2__AUD5_TXD 143 +MX51_PAD_EIM_CS2__CSI1_D4 144 +MX51_PAD_EIM_CS2__EIM_CS2 145 +MX51_PAD_EIM_CS2__FEC_RDATA2 146 +MX51_PAD_EIM_CS2__GPIO2_27 147 +MX51_PAD_EIM_CS2__USBOTG_STP 148 +MX51_PAD_EIM_CS3__AUD5_RXD 149 +MX51_PAD_EIM_CS3__CSI1_D5 150 +MX51_PAD_EIM_CS3__EIM_CS3 151 +MX51_PAD_EIM_CS3__FEC_RDATA3 152 +MX51_PAD_EIM_CS3__GPIO2_28 153 +MX51_PAD_EIM_CS3__USBOTG_NXT 154 +MX51_PAD_EIM_CS4__AUD5_TXC 155 +MX51_PAD_EIM_CS4__CSI1_D6 156 +MX51_PAD_EIM_CS4__EIM_CS4 157 +MX51_PAD_EIM_CS4__FEC_RX_ER 158 +MX51_PAD_EIM_CS4__GPIO2_29 159 +MX51_PAD_EIM_CS4__USBOTG_CLK 160 +MX51_PAD_EIM_CS5__AUD5_TXFS 161 +MX51_PAD_EIM_CS5__CSI1_D7 162 +MX51_PAD_EIM_CS5__DISP1_EXT_CLK 163 +MX51_PAD_EIM_CS5__EIM_CS5 164 +MX51_PAD_EIM_CS5__FEC_CRS 165 +MX51_PAD_EIM_CS5__GPIO2_30 166 +MX51_PAD_EIM_CS5__USBOTG_DIR 167 +MX51_PAD_EIM_DTACK__EIM_DTACK 168 +MX51_PAD_EIM_DTACK__GPIO2_31 169 +MX51_PAD_EIM_LBA__EIM_LBA 170 +MX51_PAD_EIM_LBA__GPIO3_1 171 +MX51_PAD_EIM_CRE__EIM_CRE 172 +MX51_PAD_EIM_CRE__GPIO3_2 173 +MX51_PAD_DRAM_CS1__DRAM_CS1 174 +MX51_PAD_NANDF_WE_B__GPIO3_3 175 +MX51_PAD_NANDF_WE_B__NANDF_WE_B 176 +MX51_PAD_NANDF_WE_B__PATA_DIOW 177 +MX51_PAD_NANDF_WE_B__SD3_DATA0 178 +MX51_PAD_NANDF_RE_B__GPIO3_4 179 +MX51_PAD_NANDF_RE_B__NANDF_RE_B 180 +MX51_PAD_NANDF_RE_B__PATA_DIOR 181 +MX51_PAD_NANDF_RE_B__SD3_DATA1 182 +MX51_PAD_NANDF_ALE__GPIO3_5 183 +MX51_PAD_NANDF_ALE__NANDF_ALE 184 +MX51_PAD_NANDF_ALE__PATA_BUFFER_EN 185 +MX51_PAD_NANDF_CLE__GPIO3_6 186 +MX51_PAD_NANDF_CLE__NANDF_CLE 187 +MX51_PAD_NANDF_CLE__PATA_RESET_B 188 +MX51_PAD_NANDF_WP_B__GPIO3_7 189 +MX51_PAD_NANDF_WP_B__NANDF_WP_B 190 +MX51_PAD_NANDF_WP_B__PATA_DMACK 191 +MX51_PAD_NANDF_WP_B__SD3_DATA2 192 +MX51_PAD_NANDF_RB0__ECSPI2_SS1 193 +MX51_PAD_NANDF_RB0__GPIO3_8 194 +MX51_PAD_NANDF_RB0__NANDF_RB0 195 +MX51_PAD_NANDF_RB0__PATA_DMARQ 196 +MX51_PAD_NANDF_RB0__SD3_DATA3 197 +MX51_PAD_NANDF_RB1__CSPI_MOSI 198 +MX51_PAD_NANDF_RB1__ECSPI2_RDY 199 +MX51_PAD_NANDF_RB1__GPIO3_9 200 +MX51_PAD_NANDF_RB1__NANDF_RB1 201 +MX51_PAD_NANDF_RB1__PATA_IORDY 202 +MX51_PAD_NANDF_RB1__SD4_CMD 203 +MX51_PAD_NANDF_RB2__DISP2_WAIT 204 +MX51_PAD_NANDF_RB2__ECSPI2_SCLK 205 +MX51_PAD_NANDF_RB2__FEC_COL 206 +MX51_PAD_NANDF_RB2__GPIO3_10 207 +MX51_PAD_NANDF_RB2__NANDF_RB2 208 +MX51_PAD_NANDF_RB2__USBH3_H3_DP 209 +MX51_PAD_NANDF_RB2__USBH3_NXT 210 +MX51_PAD_NANDF_RB3__DISP1_WAIT 211 +MX51_PAD_NANDF_RB3__ECSPI2_MISO 212 +MX51_PAD_NANDF_RB3__FEC_RX_CLK 213 +MX51_PAD_NANDF_RB3__GPIO3_11 214 +MX51_PAD_NANDF_RB3__NANDF_RB3 215 +MX51_PAD_NANDF_RB3__USBH3_CLK 216 +MX51_PAD_NANDF_RB3__USBH3_H3_DM 217 +MX51_PAD_GPIO_NAND__GPIO_NAND 218 +MX51_PAD_GPIO_NAND__PATA_INTRQ 219 +MX51_PAD_NANDF_CS0__GPIO3_16 220 +MX51_PAD_NANDF_CS0__NANDF_CS0 221 +MX51_PAD_NANDF_CS1__GPIO3_17 222 +MX51_PAD_NANDF_CS1__NANDF_CS1 223 +MX51_PAD_NANDF_CS2__CSPI_SCLK 224 +MX51_PAD_NANDF_CS2__FEC_TX_ER 225 +MX51_PAD_NANDF_CS2__GPIO3_18 226 +MX51_PAD_NANDF_CS2__NANDF_CS2 227 +MX51_PAD_NANDF_CS2__PATA_CS_0 228 +MX51_PAD_NANDF_CS2__SD4_CLK 229 +MX51_PAD_NANDF_CS2__USBH3_H1_DP 230 +MX51_PAD_NANDF_CS3__FEC_MDC 231 +MX51_PAD_NANDF_CS3__GPIO3_19 232 +MX51_PAD_NANDF_CS3__NANDF_CS3 233 +MX51_PAD_NANDF_CS3__PATA_CS_1 234 +MX51_PAD_NANDF_CS3__SD4_DAT0 235 +MX51_PAD_NANDF_CS3__USBH3_H1_DM 236 +MX51_PAD_NANDF_CS4__FEC_TDATA1 237 +MX51_PAD_NANDF_CS4__GPIO3_20 238 +MX51_PAD_NANDF_CS4__NANDF_CS4 239 +MX51_PAD_NANDF_CS4__PATA_DA_0 240 +MX51_PAD_NANDF_CS4__SD4_DAT1 241 +MX51_PAD_NANDF_CS4__USBH3_STP 242 +MX51_PAD_NANDF_CS5__FEC_TDATA2 243 +MX51_PAD_NANDF_CS5__GPIO3_21 244 +MX51_PAD_NANDF_CS5__NANDF_CS5 245 +MX51_PAD_NANDF_CS5__PATA_DA_1 246 +MX51_PAD_NANDF_CS5__SD4_DAT2 247 +MX51_PAD_NANDF_CS5__USBH3_DIR 248 +MX51_PAD_NANDF_CS6__CSPI_SS3 249 +MX51_PAD_NANDF_CS6__FEC_TDATA3 250 +MX51_PAD_NANDF_CS6__GPIO3_22 251 +MX51_PAD_NANDF_CS6__NANDF_CS6 252 +MX51_PAD_NANDF_CS6__PATA_DA_2 253 +MX51_PAD_NANDF_CS6__SD4_DAT3 254 +MX51_PAD_NANDF_CS7__FEC_TX_EN 255 +MX51_PAD_NANDF_CS7__GPIO3_23 256 +MX51_PAD_NANDF_CS7__NANDF_CS7 257 +MX51_PAD_NANDF_CS7__SD3_CLK 258 +MX51_PAD_NANDF_RDY_INT__ECSPI2_SS0 259 +MX51_PAD_NANDF_RDY_INT__FEC_TX_CLK 260 +MX51_PAD_NANDF_RDY_INT__GPIO3_24 261 +MX51_PAD_NANDF_RDY_INT__NANDF_RDY_INT 262 +MX51_PAD_NANDF_RDY_INT__SD3_CMD 263 +MX51_PAD_NANDF_D15__ECSPI2_MOSI 264 +MX51_PAD_NANDF_D15__GPIO3_25 265 +MX51_PAD_NANDF_D15__NANDF_D15 266 +MX51_PAD_NANDF_D15__PATA_DATA15 267 +MX51_PAD_NANDF_D15__SD3_DAT7 268 +MX51_PAD_NANDF_D14__ECSPI2_SS3 269 +MX51_PAD_NANDF_D14__GPIO3_26 270 +MX51_PAD_NANDF_D14__NANDF_D14 271 +MX51_PAD_NANDF_D14__PATA_DATA14 272 +MX51_PAD_NANDF_D14__SD3_DAT6 273 +MX51_PAD_NANDF_D13__ECSPI2_SS2 274 +MX51_PAD_NANDF_D13__GPIO3_27 275 +MX51_PAD_NANDF_D13__NANDF_D13 276 +MX51_PAD_NANDF_D13__PATA_DATA13 277 +MX51_PAD_NANDF_D13__SD3_DAT5 278 +MX51_PAD_NANDF_D12__ECSPI2_SS1 279 +MX51_PAD_NANDF_D12__GPIO3_28 280 +MX51_PAD_NANDF_D12__NANDF_D12 281 +MX51_PAD_NANDF_D12__PATA_DATA12 282 +MX51_PAD_NANDF_D12__SD3_DAT4 283 +MX51_PAD_NANDF_D11__FEC_RX_DV 284 +MX51_PAD_NANDF_D11__GPIO3_29 285 +MX51_PAD_NANDF_D11__NANDF_D11 286 +MX51_PAD_NANDF_D11__PATA_DATA11 287 +MX51_PAD_NANDF_D11__SD3_DATA3 288 +MX51_PAD_NANDF_D10__GPIO3_30 289 +MX51_PAD_NANDF_D10__NANDF_D10 290 +MX51_PAD_NANDF_D10__PATA_DATA10 291 +MX51_PAD_NANDF_D10__SD3_DATA2 292 +MX51_PAD_NANDF_D9__FEC_RDATA0 293 +MX51_PAD_NANDF_D9__GPIO3_31 294 +MX51_PAD_NANDF_D9__NANDF_D9 295 +MX51_PAD_NANDF_D9__PATA_DATA9 296 +MX51_PAD_NANDF_D9__SD3_DATA1 297 +MX51_PAD_NANDF_D8__FEC_TDATA0 298 +MX51_PAD_NANDF_D8__GPIO4_0 299 +MX51_PAD_NANDF_D8__NANDF_D8 300 +MX51_PAD_NANDF_D8__PATA_DATA8 301 +MX51_PAD_NANDF_D8__SD3_DATA0 302 +MX51_PAD_NANDF_D7__GPIO4_1 303 +MX51_PAD_NANDF_D7__NANDF_D7 304 +MX51_PAD_NANDF_D7__PATA_DATA7 305 +MX51_PAD_NANDF_D7__USBH3_DATA0 306 +MX51_PAD_NANDF_D6__GPIO4_2 307 +MX51_PAD_NANDF_D6__NANDF_D6 308 +MX51_PAD_NANDF_D6__PATA_DATA6 309 +MX51_PAD_NANDF_D6__SD4_LCTL 310 +MX51_PAD_NANDF_D6__USBH3_DATA1 311 +MX51_PAD_NANDF_D5__GPIO4_3 312 +MX51_PAD_NANDF_D5__NANDF_D5 313 +MX51_PAD_NANDF_D5__PATA_DATA5 314 +MX51_PAD_NANDF_D5__SD4_WP 315 +MX51_PAD_NANDF_D5__USBH3_DATA2 316 +MX51_PAD_NANDF_D4__GPIO4_4 317 +MX51_PAD_NANDF_D4__NANDF_D4 318 +MX51_PAD_NANDF_D4__PATA_DATA4 319 +MX51_PAD_NANDF_D4__SD4_CD 320 +MX51_PAD_NANDF_D4__USBH3_DATA3 321 +MX51_PAD_NANDF_D3__GPIO4_5 322 +MX51_PAD_NANDF_D3__NANDF_D3 323 +MX51_PAD_NANDF_D3__PATA_DATA3 324 +MX51_PAD_NANDF_D3__SD4_DAT4 325 +MX51_PAD_NANDF_D3__USBH3_DATA4 326 +MX51_PAD_NANDF_D2__GPIO4_6 327 +MX51_PAD_NANDF_D2__NANDF_D2 328 +MX51_PAD_NANDF_D2__PATA_DATA2 329 +MX51_PAD_NANDF_D2__SD4_DAT5 330 +MX51_PAD_NANDF_D2__USBH3_DATA5 331 +MX51_PAD_NANDF_D1__GPIO4_7 332 +MX51_PAD_NANDF_D1__NANDF_D1 333 +MX51_PAD_NANDF_D1__PATA_DATA1 334 +MX51_PAD_NANDF_D1__SD4_DAT6 335 +MX51_PAD_NANDF_D1__USBH3_DATA6 336 +MX51_PAD_NANDF_D0__GPIO4_8 337 +MX51_PAD_NANDF_D0__NANDF_D0 338 +MX51_PAD_NANDF_D0__PATA_DATA0 339 +MX51_PAD_NANDF_D0__SD4_DAT7 340 +MX51_PAD_NANDF_D0__USBH3_DATA7 341 +MX51_PAD_CSI1_D8__CSI1_D8 342 +MX51_PAD_CSI1_D8__GPIO3_12 343 +MX51_PAD_CSI1_D9__CSI1_D9 344 +MX51_PAD_CSI1_D9__GPIO3_13 345 +MX51_PAD_CSI1_D10__CSI1_D10 346 +MX51_PAD_CSI1_D11__CSI1_D11 347 +MX51_PAD_CSI1_D12__CSI1_D12 348 +MX51_PAD_CSI1_D13__CSI1_D13 349 +MX51_PAD_CSI1_D14__CSI1_D14 350 +MX51_PAD_CSI1_D15__CSI1_D15 351 +MX51_PAD_CSI1_D16__CSI1_D16 352 +MX51_PAD_CSI1_D17__CSI1_D17 353 +MX51_PAD_CSI1_D18__CSI1_D18 354 +MX51_PAD_CSI1_D19__CSI1_D19 355 +MX51_PAD_CSI1_VSYNC__CSI1_VSYNC 356 +MX51_PAD_CSI1_VSYNC__GPIO3_14 357 +MX51_PAD_CSI1_HSYNC__CSI1_HSYNC 358 +MX51_PAD_CSI1_HSYNC__GPIO3_15 359 +MX51_PAD_CSI1_PIXCLK__CSI1_PIXCLK 360 +MX51_PAD_CSI1_MCLK__CSI1_MCLK 361 +MX51_PAD_CSI2_D12__CSI2_D12 362 +MX51_PAD_CSI2_D12__GPIO4_9 363 +MX51_PAD_CSI2_D13__CSI2_D13 364 +MX51_PAD_CSI2_D13__GPIO4_10 365 +MX51_PAD_CSI2_D14__CSI2_D14 366 +MX51_PAD_CSI2_D15__CSI2_D15 367 +MX51_PAD_CSI2_D16__CSI2_D16 368 +MX51_PAD_CSI2_D17__CSI2_D17 369 +MX51_PAD_CSI2_D18__CSI2_D18 370 +MX51_PAD_CSI2_D18__GPIO4_11 371 +MX51_PAD_CSI2_D19__CSI2_D19 372 +MX51_PAD_CSI2_D19__GPIO4_12 373 +MX51_PAD_CSI2_VSYNC__CSI2_VSYNC 374 +MX51_PAD_CSI2_VSYNC__GPIO4_13 375 +MX51_PAD_CSI2_HSYNC__CSI2_HSYNC 376 +MX51_PAD_CSI2_HSYNC__GPIO4_14 377 +MX51_PAD_CSI2_PIXCLK__CSI2_PIXCLK 378 +MX51_PAD_CSI2_PIXCLK__GPIO4_15 379 +MX51_PAD_I2C1_CLK__GPIO4_16 380 +MX51_PAD_I2C1_CLK__I2C1_CLK 381 +MX51_PAD_I2C1_DAT__GPIO4_17 382 +MX51_PAD_I2C1_DAT__I2C1_DAT 383 +MX51_PAD_AUD3_BB_TXD__AUD3_TXD 384 +MX51_PAD_AUD3_BB_TXD__GPIO4_18 385 +MX51_PAD_AUD3_BB_RXD__AUD3_RXD 386 +MX51_PAD_AUD3_BB_RXD__GPIO4_19 387 +MX51_PAD_AUD3_BB_RXD__UART3_RXD 388 +MX51_PAD_AUD3_BB_CK__AUD3_TXC 389 +MX51_PAD_AUD3_BB_CK__GPIO4_20 390 +MX51_PAD_AUD3_BB_FS__AUD3_TXFS 391 +MX51_PAD_AUD3_BB_FS__GPIO4_21 392 +MX51_PAD_AUD3_BB_FS__UART3_TXD 393 +MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI 394 +MX51_PAD_CSPI1_MOSI__GPIO4_22 395 +MX51_PAD_CSPI1_MOSI__I2C1_SDA 396 +MX51_PAD_CSPI1_MISO__AUD4_RXD 397 +MX51_PAD_CSPI1_MISO__ECSPI1_MISO 398 +MX51_PAD_CSPI1_MISO__GPIO4_23 399 +MX51_PAD_CSPI1_SS0__AUD4_TXC 400 +MX51_PAD_CSPI1_SS0__ECSPI1_SS0 401 +MX51_PAD_CSPI1_SS0__GPIO4_24 402 +MX51_PAD_CSPI1_SS1__AUD4_TXD 403 +MX51_PAD_CSPI1_SS1__ECSPI1_SS1 404 +MX51_PAD_CSPI1_SS1__GPIO4_25 405 +MX51_PAD_CSPI1_RDY__AUD4_TXFS 406 +MX51_PAD_CSPI1_RDY__ECSPI1_RDY 407 +MX51_PAD_CSPI1_RDY__GPIO4_26 408 +MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK 409 +MX51_PAD_CSPI1_SCLK__GPIO4_27 410 +MX51_PAD_CSPI1_SCLK__I2C1_SCL 411 +MX51_PAD_UART1_RXD__GPIO4_28 412 +MX51_PAD_UART1_RXD__UART1_RXD 413 +MX51_PAD_UART1_TXD__GPIO4_29 414 +MX51_PAD_UART1_TXD__PWM2_PWMO 415 +MX51_PAD_UART1_TXD__UART1_TXD 416 +MX51_PAD_UART1_RTS__GPIO4_30 417 +MX51_PAD_UART1_RTS__UART1_RTS 418 +MX51_PAD_UART1_CTS__GPIO4_31 419 +MX51_PAD_UART1_CTS__UART1_CTS 420 +MX51_PAD_UART2_RXD__FIRI_TXD 421 +MX51_PAD_UART2_RXD__GPIO1_20 422 +MX51_PAD_UART2_RXD__UART2_RXD 423 +MX51_PAD_UART2_TXD__FIRI_RXD 424 +MX51_PAD_UART2_TXD__GPIO1_21 425 +MX51_PAD_UART2_TXD__UART2_TXD 426 +MX51_PAD_UART3_RXD__CSI1_D0 427 +MX51_PAD_UART3_RXD__GPIO1_22 428 +MX51_PAD_UART3_RXD__UART1_DTR 429 +MX51_PAD_UART3_RXD__UART3_RXD 430 +MX51_PAD_UART3_TXD__CSI1_D1 431 +MX51_PAD_UART3_TXD__GPIO1_23 432 +MX51_PAD_UART3_TXD__UART1_DSR 433 +MX51_PAD_UART3_TXD__UART3_TXD 434 +MX51_PAD_OWIRE_LINE__GPIO1_24 435 +MX51_PAD_OWIRE_LINE__OWIRE_LINE 436 +MX51_PAD_OWIRE_LINE__SPDIF_OUT 437 +MX51_PAD_KEY_ROW0__KEY_ROW0 438 +MX51_PAD_KEY_ROW1__KEY_ROW1 439 +MX51_PAD_KEY_ROW2__KEY_ROW2 440 +MX51_PAD_KEY_ROW3__KEY_ROW3 441 +MX51_PAD_KEY_COL0__KEY_COL0 442 +MX51_PAD_KEY_COL0__PLL1_BYP 443 +MX51_PAD_KEY_COL1__KEY_COL1 444 +MX51_PAD_KEY_COL1__PLL2_BYP 445 +MX51_PAD_KEY_COL2__KEY_COL2 446 +MX51_PAD_KEY_COL2__PLL3_BYP 447 +MX51_PAD_KEY_COL3__KEY_COL3 448 +MX51_PAD_KEY_COL4__I2C2_SCL 449 +MX51_PAD_KEY_COL4__KEY_COL4 450 +MX51_PAD_KEY_COL4__SPDIF_OUT1 451 +MX51_PAD_KEY_COL4__UART1_RI 452 +MX51_PAD_KEY_COL4__UART3_RTS 453 +MX51_PAD_KEY_COL5__I2C2_SDA 454 +MX51_PAD_KEY_COL5__KEY_COL5 455 +MX51_PAD_KEY_COL5__UART1_DCD 456 +MX51_PAD_KEY_COL5__UART3_CTS 457 +MX51_PAD_USBH1_CLK__CSPI_SCLK 458 +MX51_PAD_USBH1_CLK__GPIO1_25 459 +MX51_PAD_USBH1_CLK__I2C2_SCL 460 +MX51_PAD_USBH1_CLK__USBH1_CLK 461 +MX51_PAD_USBH1_DIR__CSPI_MOSI 462 +MX51_PAD_USBH1_DIR__GPIO1_26 463 +MX51_PAD_USBH1_DIR__I2C2_SDA 464 +MX51_PAD_USBH1_DIR__USBH1_DIR 465 +MX51_PAD_USBH1_STP__CSPI_RDY 466 +MX51_PAD_USBH1_STP__GPIO1_27 467 +MX51_PAD_USBH1_STP__UART3_RXD 468 +MX51_PAD_USBH1_STP__USBH1_STP 469 +MX51_PAD_USBH1_NXT__CSPI_MISO 470 +MX51_PAD_USBH1_NXT__GPIO1_28 471 +MX51_PAD_USBH1_NXT__UART3_TXD 472 +MX51_PAD_USBH1_NXT__USBH1_NXT 473 +MX51_PAD_USBH1_DATA0__GPIO1_11 474 +MX51_PAD_USBH1_DATA0__UART2_CTS 475 +MX51_PAD_USBH1_DATA0__USBH1_DATA0 476 +MX51_PAD_USBH1_DATA1__GPIO1_12 477 +MX51_PAD_USBH1_DATA1__UART2_RXD 478 +MX51_PAD_USBH1_DATA1__USBH1_DATA1 479 +MX51_PAD_USBH1_DATA2__GPIO1_13 480 +MX51_PAD_USBH1_DATA2__UART2_TXD 481 +MX51_PAD_USBH1_DATA2__USBH1_DATA2 482 +MX51_PAD_USBH1_DATA3__GPIO1_14 483 +MX51_PAD_USBH1_DATA3__UART2_RTS 484 +MX51_PAD_USBH1_DATA3__USBH1_DATA3 485 +MX51_PAD_USBH1_DATA4__CSPI_SS0 486 +MX51_PAD_USBH1_DATA4__GPIO1_15 487 +MX51_PAD_USBH1_DATA4__USBH1_DATA4 488 +MX51_PAD_USBH1_DATA5__CSPI_SS1 489 +MX51_PAD_USBH1_DATA5__GPIO1_16 490 +MX51_PAD_USBH1_DATA5__USBH1_DATA5 491 +MX51_PAD_USBH1_DATA6__CSPI_SS3 492 +MX51_PAD_USBH1_DATA6__GPIO1_17 493 +MX51_PAD_USBH1_DATA6__USBH1_DATA6 494 +MX51_PAD_USBH1_DATA7__ECSPI1_SS3 495 +MX51_PAD_USBH1_DATA7__ECSPI2_SS3 496 +MX51_PAD_USBH1_DATA7__GPIO1_18 497 +MX51_PAD_USBH1_DATA7__USBH1_DATA7 498 +MX51_PAD_DI1_PIN11__DI1_PIN11 499 +MX51_PAD_DI1_PIN11__ECSPI1_SS2 500 +MX51_PAD_DI1_PIN11__GPIO3_0 501 +MX51_PAD_DI1_PIN12__DI1_PIN12 502 +MX51_PAD_DI1_PIN12__GPIO3_1 503 +MX51_PAD_DI1_PIN13__DI1_PIN13 504 +MX51_PAD_DI1_PIN13__GPIO3_2 505 +MX51_PAD_DI1_D0_CS__DI1_D0_CS 506 +MX51_PAD_DI1_D0_CS__GPIO3_3 507 +MX51_PAD_DI1_D1_CS__DI1_D1_CS 508 +MX51_PAD_DI1_D1_CS__DISP1_PIN14 509 +MX51_PAD_DI1_D1_CS__DISP1_PIN5 510 +MX51_PAD_DI1_D1_CS__GPIO3_4 511 +MX51_PAD_DISPB2_SER_DIN__DISP1_PIN1 512 +MX51_PAD_DISPB2_SER_DIN__DISPB2_SER_DIN 513 +MX51_PAD_DISPB2_SER_DIN__GPIO3_5 514 +MX51_PAD_DISPB2_SER_DIO__DISP1_PIN6 515 +MX51_PAD_DISPB2_SER_DIO__DISPB2_SER_DIO 516 +MX51_PAD_DISPB2_SER_DIO__GPIO3_6 517 +MX51_PAD_DISPB2_SER_CLK__DISP1_PIN17 518 +MX51_PAD_DISPB2_SER_CLK__DISP1_PIN7 519 +MX51_PAD_DISPB2_SER_CLK__DISPB2_SER_CLK 520 +MX51_PAD_DISPB2_SER_CLK__GPIO3_7 521 +MX51_PAD_DISPB2_SER_RS__DISP1_EXT_CLK 522 +MX51_PAD_DISPB2_SER_RS__DISP1_PIN16 523 +MX51_PAD_DISPB2_SER_RS__DISP1_PIN8 524 +MX51_PAD_DISPB2_SER_RS__DISPB2_SER_RS 525 +MX51_PAD_DISPB2_SER_RS__DISPB2_SER_RS 526 +MX51_PAD_DISPB2_SER_RS__GPIO3_8 527 +MX51_PAD_DISP1_DAT0__DISP1_DAT0 528 +MX51_PAD_DISP1_DAT1__DISP1_DAT1 529 +MX51_PAD_DISP1_DAT2__DISP1_DAT2 530 +MX51_PAD_DISP1_DAT3__DISP1_DAT3 531 +MX51_PAD_DISP1_DAT4__DISP1_DAT4 532 +MX51_PAD_DISP1_DAT5__DISP1_DAT5 533 +MX51_PAD_DISP1_DAT6__BOOT_USB_SRC 534 +MX51_PAD_DISP1_DAT6__DISP1_DAT6 535 +MX51_PAD_DISP1_DAT7__BOOT_EEPROM_CFG 536 +MX51_PAD_DISP1_DAT7__DISP1_DAT7 537 +MX51_PAD_DISP1_DAT8__BOOT_SRC0 538 +MX51_PAD_DISP1_DAT8__DISP1_DAT8 539 +MX51_PAD_DISP1_DAT9__BOOT_SRC1 540 +MX51_PAD_DISP1_DAT9__DISP1_DAT9 541 +MX51_PAD_DISP1_DAT10__BOOT_SPARE_SIZE 542 +MX51_PAD_DISP1_DAT10__DISP1_DAT10 543 +MX51_PAD_DISP1_DAT11__BOOT_LPB_FREQ2 544 +MX51_PAD_DISP1_DAT11__DISP1_DAT11 545 +MX51_PAD_DISP1_DAT12__BOOT_MLC_SEL 546 +MX51_PAD_DISP1_DAT12__DISP1_DAT12 547 +MX51_PAD_DISP1_DAT13__BOOT_MEM_CTL0 548 +MX51_PAD_DISP1_DAT13__DISP1_DAT13 549 +MX51_PAD_DISP1_DAT14__BOOT_MEM_CTL1 550 +MX51_PAD_DISP1_DAT14__DISP1_DAT14 551 +MX51_PAD_DISP1_DAT15__BOOT_BUS_WIDTH 552 +MX51_PAD_DISP1_DAT15__DISP1_DAT15 553 +MX51_PAD_DISP1_DAT16__BOOT_PAGE_SIZE0 554 +MX51_PAD_DISP1_DAT16__DISP1_DAT16 555 +MX51_PAD_DISP1_DAT17__BOOT_PAGE_SIZE1 556 +MX51_PAD_DISP1_DAT17__DISP1_DAT17 557 +MX51_PAD_DISP1_DAT18__BOOT_WEIM_MUXED0 558 +MX51_PAD_DISP1_DAT18__DISP1_DAT18 559 +MX51_PAD_DISP1_DAT18__DISP2_PIN11 560 +MX51_PAD_DISP1_DAT18__DISP2_PIN5 561 +MX51_PAD_DISP1_DAT19__BOOT_WEIM_MUXED1 562 +MX51_PAD_DISP1_DAT19__DISP1_DAT19 563 +MX51_PAD_DISP1_DAT19__DISP2_PIN12 564 +MX51_PAD_DISP1_DAT19__DISP2_PIN6 565 +MX51_PAD_DISP1_DAT20__BOOT_MEM_TYPE0 566 +MX51_PAD_DISP1_DAT20__DISP1_DAT20 567 +MX51_PAD_DISP1_DAT20__DISP2_PIN13 568 +MX51_PAD_DISP1_DAT20__DISP2_PIN7 569 +MX51_PAD_DISP1_DAT21__BOOT_MEM_TYPE1 570 +MX51_PAD_DISP1_DAT21__DISP1_DAT21 571 +MX51_PAD_DISP1_DAT21__DISP2_PIN14 572 +MX51_PAD_DISP1_DAT21__DISP2_PIN8 573 +MX51_PAD_DISP1_DAT22__BOOT_LPB_FREQ0 574 +MX51_PAD_DISP1_DAT22__DISP1_DAT22 575 +MX51_PAD_DISP1_DAT22__DISP2_D0_CS 576 +MX51_PAD_DISP1_DAT22__DISP2_DAT16 577 +MX51_PAD_DISP1_DAT23__BOOT_LPB_FREQ1 578 +MX51_PAD_DISP1_DAT23__DISP1_DAT23 579 +MX51_PAD_DISP1_DAT23__DISP2_D1_CS 580 +MX51_PAD_DISP1_DAT23__DISP2_DAT17 581 +MX51_PAD_DISP1_DAT23__DISP2_SER_CS 582 +MX51_PAD_DI1_PIN3__DI1_PIN3 583 +MX51_PAD_DI1_PIN2__DI1_PIN2 584 +MX51_PAD_DI_GP2__DISP1_SER_CLK 585 +MX51_PAD_DI_GP2__DISP2_WAIT 586 +MX51_PAD_DI_GP3__CSI1_DATA_EN 587 +MX51_PAD_DI_GP3__DISP1_SER_DIO 588 +MX51_PAD_DI_GP3__FEC_TX_ER 589 +MX51_PAD_DI2_PIN4__CSI2_DATA_EN 590 +MX51_PAD_DI2_PIN4__DI2_PIN4 591 +MX51_PAD_DI2_PIN4__FEC_CRS 592 +MX51_PAD_DI2_PIN2__DI2_PIN2 593 +MX51_PAD_DI2_PIN2__FEC_MDC 594 +MX51_PAD_DI2_PIN3__DI2_PIN3 595 +MX51_PAD_DI2_PIN3__FEC_MDIO 596 +MX51_PAD_DI2_DISP_CLK__DI2_DISP_CLK 597 +MX51_PAD_DI2_DISP_CLK__FEC_RDATA1 598 +MX51_PAD_DI_GP4__DI2_PIN15 599 +MX51_PAD_DI_GP4__DISP1_SER_DIN 600 +MX51_PAD_DI_GP4__DISP2_PIN1 601 +MX51_PAD_DI_GP4__FEC_RDATA2 602 +MX51_PAD_DISP2_DAT0__DISP2_DAT0 603 +MX51_PAD_DISP2_DAT0__FEC_RDATA3 604 +MX51_PAD_DISP2_DAT0__KEY_COL6 605 +MX51_PAD_DISP2_DAT0__UART3_RXD 606 +MX51_PAD_DISP2_DAT0__USBH3_CLK 607 +MX51_PAD_DISP2_DAT1__DISP2_DAT1 608 +MX51_PAD_DISP2_DAT1__FEC_RX_ER 609 +MX51_PAD_DISP2_DAT1__KEY_COL7 610 +MX51_PAD_DISP2_DAT1__UART3_TXD 611 +MX51_PAD_DISP2_DAT1__USBH3_DIR 612 +MX51_PAD_DISP2_DAT2__DISP2_DAT2 613 +MX51_PAD_DISP2_DAT3__DISP2_DAT3 614 +MX51_PAD_DISP2_DAT4__DISP2_DAT4 615 +MX51_PAD_DISP2_DAT5__DISP2_DAT5 616 +MX51_PAD_DISP2_DAT6__DISP2_DAT6 617 +MX51_PAD_DISP2_DAT6__FEC_TDATA1 618 +MX51_PAD_DISP2_DAT6__GPIO1_19 619 +MX51_PAD_DISP2_DAT6__KEY_ROW4 620 +MX51_PAD_DISP2_DAT6__USBH3_STP 621 +MX51_PAD_DISP2_DAT7__DISP2_DAT7 622 +MX51_PAD_DISP2_DAT7__FEC_TDATA2 623 +MX51_PAD_DISP2_DAT7__GPIO1_29 624 +MX51_PAD_DISP2_DAT7__KEY_ROW5 625 +MX51_PAD_DISP2_DAT7__USBH3_NXT 626 +MX51_PAD_DISP2_DAT8__DISP2_DAT8 627 +MX51_PAD_DISP2_DAT8__FEC_TDATA3 628 +MX51_PAD_DISP2_DAT8__GPIO1_30 629 +MX51_PAD_DISP2_DAT8__KEY_ROW6 630 +MX51_PAD_DISP2_DAT8__USBH3_DATA0 631 +MX51_PAD_DISP2_DAT9__AUD6_RXC 632 +MX51_PAD_DISP2_DAT9__DISP2_DAT9 633 +MX51_PAD_DISP2_DAT9__FEC_TX_EN 634 +MX51_PAD_DISP2_DAT9__GPIO1_31 635 +MX51_PAD_DISP2_DAT9__USBH3_DATA1 636 +MX51_PAD_DISP2_DAT10__DISP2_DAT10 637 +MX51_PAD_DISP2_DAT10__DISP2_SER_CS 638 +MX51_PAD_DISP2_DAT10__FEC_COL 639 +MX51_PAD_DISP2_DAT10__KEY_ROW7 640 +MX51_PAD_DISP2_DAT10__USBH3_DATA2 641 +MX51_PAD_DISP2_DAT11__AUD6_TXD 642 +MX51_PAD_DISP2_DAT11__DISP2_DAT11 643 +MX51_PAD_DISP2_DAT11__FEC_RX_CLK 644 +MX51_PAD_DISP2_DAT11__GPIO1_10 645 +MX51_PAD_DISP2_DAT11__USBH3_DATA3 646 +MX51_PAD_DISP2_DAT12__AUD6_RXD 647 +MX51_PAD_DISP2_DAT12__DISP2_DAT12 648 +MX51_PAD_DISP2_DAT12__FEC_RX_DV 649 +MX51_PAD_DISP2_DAT12__USBH3_DATA4 650 +MX51_PAD_DISP2_DAT13__AUD6_TXC 651 +MX51_PAD_DISP2_DAT13__DISP2_DAT13 652 +MX51_PAD_DISP2_DAT13__FEC_TX_CLK 653 +MX51_PAD_DISP2_DAT13__USBH3_DATA5 654 +MX51_PAD_DISP2_DAT14__AUD6_TXFS 655 +MX51_PAD_DISP2_DAT14__DISP2_DAT14 656 +MX51_PAD_DISP2_DAT14__FEC_RDATA0 657 +MX51_PAD_DISP2_DAT14__USBH3_DATA6 658 +MX51_PAD_DISP2_DAT15__AUD6_RXFS 659 +MX51_PAD_DISP2_DAT15__DISP1_SER_CS 660 +MX51_PAD_DISP2_DAT15__DISP2_DAT15 661 +MX51_PAD_DISP2_DAT15__FEC_TDATA0 662 +MX51_PAD_DISP2_DAT15__USBH3_DATA7 663 +MX51_PAD_SD1_CMD__AUD5_RXFS 664 +MX51_PAD_SD1_CMD__CSPI_MOSI 665 +MX51_PAD_SD1_CMD__SD1_CMD 666 +MX51_PAD_SD1_CLK__AUD5_RXC 667 +MX51_PAD_SD1_CLK__CSPI_SCLK 668 +MX51_PAD_SD1_CLK__SD1_CLK 669 +MX51_PAD_SD1_DATA0__AUD5_TXD 670 +MX51_PAD_SD1_DATA0__CSPI_MISO 671 +MX51_PAD_SD1_DATA0__SD1_DATA0 672 +MX51_PAD_EIM_DA0__EIM_DA0 673 +MX51_PAD_EIM_DA1__EIM_DA1 674 +MX51_PAD_EIM_DA2__EIM_DA2 675 +MX51_PAD_EIM_DA3__EIM_DA3 676 +MX51_PAD_SD1_DATA1__AUD5_RXD 677 +MX51_PAD_SD1_DATA1__SD1_DATA1 678 +MX51_PAD_EIM_DA4__EIM_DA4 679 +MX51_PAD_EIM_DA5__EIM_DA5 680 +MX51_PAD_EIM_DA6__EIM_DA6 681 +MX51_PAD_EIM_DA7__EIM_DA7 682 +MX51_PAD_SD1_DATA2__AUD5_TXC 683 +MX51_PAD_SD1_DATA2__SD1_DATA2 684 +MX51_PAD_EIM_DA10__EIM_DA10 685 +MX51_PAD_EIM_DA11__EIM_DA11 686 +MX51_PAD_EIM_DA8__EIM_DA8 687 +MX51_PAD_EIM_DA9__EIM_DA9 688 +MX51_PAD_SD1_DATA3__AUD5_TXFS 689 +MX51_PAD_SD1_DATA3__CSPI_SS1 690 +MX51_PAD_SD1_DATA3__SD1_DATA3 691 +MX51_PAD_GPIO1_0__CSPI_SS2 692 +MX51_PAD_GPIO1_0__GPIO1_0 693 +MX51_PAD_GPIO1_0__SD1_CD 694 +MX51_PAD_GPIO1_1__CSPI_MISO 695 +MX51_PAD_GPIO1_1__GPIO1_1 696 +MX51_PAD_GPIO1_1__SD1_WP 697 +MX51_PAD_EIM_DA12__EIM_DA12 698 +MX51_PAD_EIM_DA13__EIM_DA13 699 +MX51_PAD_EIM_DA14__EIM_DA14 700 +MX51_PAD_EIM_DA15__EIM_DA15 701 +MX51_PAD_SD2_CMD__CSPI_MOSI 702 +MX51_PAD_SD2_CMD__I2C1_SCL 703 +MX51_PAD_SD2_CMD__SD2_CMD 704 +MX51_PAD_SD2_CLK__CSPI_SCLK 705 +MX51_PAD_SD2_CLK__I2C1_SDA 706 +MX51_PAD_SD2_CLK__SD2_CLK 707 +MX51_PAD_SD2_DATA0__CSPI_MISO 708 +MX51_PAD_SD2_DATA0__SD1_DAT4 709 +MX51_PAD_SD2_DATA0__SD2_DATA0 710 +MX51_PAD_SD2_DATA1__SD1_DAT5 711 +MX51_PAD_SD2_DATA1__SD2_DATA1 712 +MX51_PAD_SD2_DATA1__USBH3_H2_DP 713 +MX51_PAD_SD2_DATA2__SD1_DAT6 714 +MX51_PAD_SD2_DATA2__SD2_DATA2 715 +MX51_PAD_SD2_DATA2__USBH3_H2_DM 716 +MX51_PAD_SD2_DATA3__CSPI_SS2 717 +MX51_PAD_SD2_DATA3__SD1_DAT7 718 +MX51_PAD_SD2_DATA3__SD2_DATA3 719 +MX51_PAD_GPIO1_2__CCM_OUT_2 720 +MX51_PAD_GPIO1_2__GPIO1_2 721 +MX51_PAD_GPIO1_2__I2C2_SCL 722 +MX51_PAD_GPIO1_2__PLL1_BYP 723 +MX51_PAD_GPIO1_2__PWM1_PWMO 724 +MX51_PAD_GPIO1_3__GPIO1_3 725 +MX51_PAD_GPIO1_3__I2C2_SDA 726 +MX51_PAD_GPIO1_3__PLL2_BYP 727 +MX51_PAD_GPIO1_3__PWM2_PWMO 728 +MX51_PAD_PMIC_INT_REQ__PMIC_INT_REQ 729 +MX51_PAD_PMIC_INT_REQ__PMIC_PMU_IRQ_B 730 +MX51_PAD_GPIO1_4__DISP2_EXT_CLK 731 +MX51_PAD_GPIO1_4__EIM_RDY 732 +MX51_PAD_GPIO1_4__GPIO1_4 733 +MX51_PAD_GPIO1_4__WDOG1_WDOG_B 734 +MX51_PAD_GPIO1_5__CSI2_MCLK 735 +MX51_PAD_GPIO1_5__DISP2_PIN16 736 +MX51_PAD_GPIO1_5__GPIO1_5 737 +MX51_PAD_GPIO1_5__WDOG2_WDOG_B 738 +MX51_PAD_GPIO1_6__DISP2_PIN17 739 +MX51_PAD_GPIO1_6__GPIO1_6 740 +MX51_PAD_GPIO1_6__REF_EN_B 741 +MX51_PAD_GPIO1_7__CCM_OUT_0 742 +MX51_PAD_GPIO1_7__GPIO1_7 743 +MX51_PAD_GPIO1_7__SD2_WP 744 +MX51_PAD_GPIO1_7__SPDIF_OUT1 745 +MX51_PAD_GPIO1_8__CSI2_DATA_EN 746 +MX51_PAD_GPIO1_8__GPIO1_8 747 +MX51_PAD_GPIO1_8__SD2_CD 748 +MX51_PAD_GPIO1_8__USBH3_PWR 749 +MX51_PAD_GPIO1_9__CCM_OUT_1 750 +MX51_PAD_GPIO1_9__DISP2_D1_CS 751 +MX51_PAD_GPIO1_9__DISP2_SER_CS 752 +MX51_PAD_GPIO1_9__GPIO1_9 753 +MX51_PAD_GPIO1_9__SD2_LCTL 754 +MX51_PAD_GPIO1_9__USBH3_OC 755 diff --git a/trunk/Documentation/devicetree/bindings/pinctrl/fsl,imx53-pinctrl.txt b/trunk/Documentation/devicetree/bindings/pinctrl/fsl,imx53-pinctrl.txt new file mode 100644 index 000000000000..ca85ca432ef0 --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/pinctrl/fsl,imx53-pinctrl.txt @@ -0,0 +1,1202 @@ +* Freescale IMX53 IOMUX Controller + +Please refer to fsl,imx-pinctrl.txt in this directory for common binding part +and usage. + +Required properties: +- compatible: "fsl,imx53-iomuxc" +- fsl,pins: two integers array, represents a group of pins mux and config + setting. The format is fsl,pins = , PIN_FUNC_ID is a + pin working on a specific function, CONFIG is the pad setting value like + pull-up for this pin. Please refer to imx53 datasheet for the valid pad + config settings. + +CONFIG bits definition: +PAD_CTL_HVE (1 << 13) +PAD_CTL_HYS (1 << 8) +PAD_CTL_PKE (1 << 7) +PAD_CTL_PUE (1 << 6) +PAD_CTL_PUS_100K_DOWN (0 << 4) +PAD_CTL_PUS_47K_UP (1 << 4) +PAD_CTL_PUS_100K_UP (2 << 4) +PAD_CTL_PUS_22K_UP (3 << 4) +PAD_CTL_ODE (1 << 3) +PAD_CTL_DSE_LOW (0 << 1) +PAD_CTL_DSE_MED (1 << 1) +PAD_CTL_DSE_HIGH (2 << 1) +PAD_CTL_DSE_MAX (3 << 1) +PAD_CTL_SRE_FAST (1 << 0) +PAD_CTL_SRE_SLOW (0 << 0) + +See below for available PIN_FUNC_ID for imx53: +MX53_PAD_GPIO_19__KPP_COL_5 0 +MX53_PAD_GPIO_19__GPIO4_5 1 +MX53_PAD_GPIO_19__CCM_CLKO 2 +MX53_PAD_GPIO_19__SPDIF_OUT1 3 +MX53_PAD_GPIO_19__RTC_CE_RTC_EXT_TRIG2 4 +MX53_PAD_GPIO_19__ECSPI1_RDY 5 +MX53_PAD_GPIO_19__FEC_TDATA_3 6 +MX53_PAD_GPIO_19__SRC_INT_BOOT 7 +MX53_PAD_KEY_COL0__KPP_COL_0 8 +MX53_PAD_KEY_COL0__GPIO4_6 9 +MX53_PAD_KEY_COL0__AUDMUX_AUD5_TXC 10 +MX53_PAD_KEY_COL0__UART4_TXD_MUX 11 +MX53_PAD_KEY_COL0__ECSPI1_SCLK 12 +MX53_PAD_KEY_COL0__FEC_RDATA_3 13 +MX53_PAD_KEY_COL0__SRC_ANY_PU_RST 14 +MX53_PAD_KEY_ROW0__KPP_ROW_0 15 +MX53_PAD_KEY_ROW0__GPIO4_7 16 +MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD 17 +MX53_PAD_KEY_ROW0__UART4_RXD_MUX 18 +MX53_PAD_KEY_ROW0__ECSPI1_MOSI 19 +MX53_PAD_KEY_ROW0__FEC_TX_ER 20 +MX53_PAD_KEY_COL1__KPP_COL_1 21 +MX53_PAD_KEY_COL1__GPIO4_8 22 +MX53_PAD_KEY_COL1__AUDMUX_AUD5_TXFS 23 +MX53_PAD_KEY_COL1__UART5_TXD_MUX 24 +MX53_PAD_KEY_COL1__ECSPI1_MISO 25 +MX53_PAD_KEY_COL1__FEC_RX_CLK 26 +MX53_PAD_KEY_COL1__USBPHY1_TXREADY 27 +MX53_PAD_KEY_ROW1__KPP_ROW_1 28 +MX53_PAD_KEY_ROW1__GPIO4_9 29 +MX53_PAD_KEY_ROW1__AUDMUX_AUD5_RXD 30 +MX53_PAD_KEY_ROW1__UART5_RXD_MUX 31 +MX53_PAD_KEY_ROW1__ECSPI1_SS0 32 +MX53_PAD_KEY_ROW1__FEC_COL 33 +MX53_PAD_KEY_ROW1__USBPHY1_RXVALID 34 +MX53_PAD_KEY_COL2__KPP_COL_2 35 +MX53_PAD_KEY_COL2__GPIO4_10 36 +MX53_PAD_KEY_COL2__CAN1_TXCAN 37 +MX53_PAD_KEY_COL2__FEC_MDIO 38 +MX53_PAD_KEY_COL2__ECSPI1_SS1 39 +MX53_PAD_KEY_COL2__FEC_RDATA_2 40 +MX53_PAD_KEY_COL2__USBPHY1_RXACTIVE 41 +MX53_PAD_KEY_ROW2__KPP_ROW_2 42 +MX53_PAD_KEY_ROW2__GPIO4_11 43 +MX53_PAD_KEY_ROW2__CAN1_RXCAN 44 +MX53_PAD_KEY_ROW2__FEC_MDC 45 +MX53_PAD_KEY_ROW2__ECSPI1_SS2 46 +MX53_PAD_KEY_ROW2__FEC_TDATA_2 47 +MX53_PAD_KEY_ROW2__USBPHY1_RXERROR 48 +MX53_PAD_KEY_COL3__KPP_COL_3 49 +MX53_PAD_KEY_COL3__GPIO4_12 50 +MX53_PAD_KEY_COL3__USBOH3_H2_DP 51 +MX53_PAD_KEY_COL3__SPDIF_IN1 52 +MX53_PAD_KEY_COL3__I2C2_SCL 53 +MX53_PAD_KEY_COL3__ECSPI1_SS3 54 +MX53_PAD_KEY_COL3__FEC_CRS 55 +MX53_PAD_KEY_COL3__USBPHY1_SIECLOCK 56 +MX53_PAD_KEY_ROW3__KPP_ROW_3 57 +MX53_PAD_KEY_ROW3__GPIO4_13 58 +MX53_PAD_KEY_ROW3__USBOH3_H2_DM 59 +MX53_PAD_KEY_ROW3__CCM_ASRC_EXT_CLK 60 +MX53_PAD_KEY_ROW3__I2C2_SDA 61 +MX53_PAD_KEY_ROW3__OSC32K_32K_OUT 62 +MX53_PAD_KEY_ROW3__CCM_PLL4_BYP 63 +MX53_PAD_KEY_ROW3__USBPHY1_LINESTATE_0 64 +MX53_PAD_KEY_COL4__KPP_COL_4 65 +MX53_PAD_KEY_COL4__GPIO4_14 66 +MX53_PAD_KEY_COL4__CAN2_TXCAN 67 +MX53_PAD_KEY_COL4__IPU_SISG_4 68 +MX53_PAD_KEY_COL4__UART5_RTS 69 +MX53_PAD_KEY_COL4__USBOH3_USBOTG_OC 70 +MX53_PAD_KEY_COL4__USBPHY1_LINESTATE_1 71 +MX53_PAD_KEY_ROW4__KPP_ROW_4 72 +MX53_PAD_KEY_ROW4__GPIO4_15 73 +MX53_PAD_KEY_ROW4__CAN2_RXCAN 74 +MX53_PAD_KEY_ROW4__IPU_SISG_5 75 +MX53_PAD_KEY_ROW4__UART5_CTS 76 +MX53_PAD_KEY_ROW4__USBOH3_USBOTG_PWR 77 +MX53_PAD_KEY_ROW4__USBPHY1_VBUSVALID 78 +MX53_PAD_DI0_DISP_CLK__IPU_DI0_DISP_CLK 79 +MX53_PAD_DI0_DISP_CLK__GPIO4_16 80 +MX53_PAD_DI0_DISP_CLK__USBOH3_USBH2_DIR 81 +MX53_PAD_DI0_DISP_CLK__SDMA_DEBUG_CORE_STATE_0 82 +MX53_PAD_DI0_DISP_CLK__EMI_EMI_DEBUG_0 83 +MX53_PAD_DI0_DISP_CLK__USBPHY1_AVALID 84 +MX53_PAD_DI0_PIN15__IPU_DI0_PIN15 85 +MX53_PAD_DI0_PIN15__GPIO4_17 86 +MX53_PAD_DI0_PIN15__AUDMUX_AUD6_TXC 87 +MX53_PAD_DI0_PIN15__SDMA_DEBUG_CORE_STATE_1 88 +MX53_PAD_DI0_PIN15__EMI_EMI_DEBUG_1 89 +MX53_PAD_DI0_PIN15__USBPHY1_BVALID 90 +MX53_PAD_DI0_PIN2__IPU_DI0_PIN2 91 +MX53_PAD_DI0_PIN2__GPIO4_18 92 +MX53_PAD_DI0_PIN2__AUDMUX_AUD6_TXD 93 +MX53_PAD_DI0_PIN2__SDMA_DEBUG_CORE_STATE_2 94 +MX53_PAD_DI0_PIN2__EMI_EMI_DEBUG_2 95 +MX53_PAD_DI0_PIN2__USBPHY1_ENDSESSION 96 +MX53_PAD_DI0_PIN3__IPU_DI0_PIN3 97 +MX53_PAD_DI0_PIN3__GPIO4_19 98 +MX53_PAD_DI0_PIN3__AUDMUX_AUD6_TXFS 99 +MX53_PAD_DI0_PIN3__SDMA_DEBUG_CORE_STATE_3 100 +MX53_PAD_DI0_PIN3__EMI_EMI_DEBUG_3 101 +MX53_PAD_DI0_PIN3__USBPHY1_IDDIG 102 +MX53_PAD_DI0_PIN4__IPU_DI0_PIN4 103 +MX53_PAD_DI0_PIN4__GPIO4_20 104 +MX53_PAD_DI0_PIN4__AUDMUX_AUD6_RXD 105 +MX53_PAD_DI0_PIN4__ESDHC1_WP 106 +MX53_PAD_DI0_PIN4__SDMA_DEBUG_YIELD 107 +MX53_PAD_DI0_PIN4__EMI_EMI_DEBUG_4 108 +MX53_PAD_DI0_PIN4__USBPHY1_HOSTDISCONNECT 109 +MX53_PAD_DISP0_DAT0__IPU_DISP0_DAT_0 110 +MX53_PAD_DISP0_DAT0__GPIO4_21 111 +MX53_PAD_DISP0_DAT0__CSPI_SCLK 112 +MX53_PAD_DISP0_DAT0__USBOH3_USBH2_DATA_0 113 +MX53_PAD_DISP0_DAT0__SDMA_DEBUG_CORE_RUN 114 +MX53_PAD_DISP0_DAT0__EMI_EMI_DEBUG_5 115 +MX53_PAD_DISP0_DAT0__USBPHY2_TXREADY 116 +MX53_PAD_DISP0_DAT1__IPU_DISP0_DAT_1 117 +MX53_PAD_DISP0_DAT1__GPIO4_22 118 +MX53_PAD_DISP0_DAT1__CSPI_MOSI 119 +MX53_PAD_DISP0_DAT1__USBOH3_USBH2_DATA_1 120 +MX53_PAD_DISP0_DAT1__SDMA_DEBUG_EVENT_CHANNEL_SEL 121 +MX53_PAD_DISP0_DAT1__EMI_EMI_DEBUG_6 122 +MX53_PAD_DISP0_DAT1__USBPHY2_RXVALID 123 +MX53_PAD_DISP0_DAT2__IPU_DISP0_DAT_2 124 +MX53_PAD_DISP0_DAT2__GPIO4_23 125 +MX53_PAD_DISP0_DAT2__CSPI_MISO 126 +MX53_PAD_DISP0_DAT2__USBOH3_USBH2_DATA_2 127 +MX53_PAD_DISP0_DAT2__SDMA_DEBUG_MODE 128 +MX53_PAD_DISP0_DAT2__EMI_EMI_DEBUG_7 129 +MX53_PAD_DISP0_DAT2__USBPHY2_RXACTIVE 130 +MX53_PAD_DISP0_DAT3__IPU_DISP0_DAT_3 131 +MX53_PAD_DISP0_DAT3__GPIO4_24 132 +MX53_PAD_DISP0_DAT3__CSPI_SS0 133 +MX53_PAD_DISP0_DAT3__USBOH3_USBH2_DATA_3 134 +MX53_PAD_DISP0_DAT3__SDMA_DEBUG_BUS_ERROR 135 +MX53_PAD_DISP0_DAT3__EMI_EMI_DEBUG_8 136 +MX53_PAD_DISP0_DAT3__USBPHY2_RXERROR 137 +MX53_PAD_DISP0_DAT4__IPU_DISP0_DAT_4 138 +MX53_PAD_DISP0_DAT4__GPIO4_25 139 +MX53_PAD_DISP0_DAT4__CSPI_SS1 140 +MX53_PAD_DISP0_DAT4__USBOH3_USBH2_DATA_4 141 +MX53_PAD_DISP0_DAT4__SDMA_DEBUG_BUS_RWB 142 +MX53_PAD_DISP0_DAT4__EMI_EMI_DEBUG_9 143 +MX53_PAD_DISP0_DAT4__USBPHY2_SIECLOCK 144 +MX53_PAD_DISP0_DAT5__IPU_DISP0_DAT_5 145 +MX53_PAD_DISP0_DAT5__GPIO4_26 146 +MX53_PAD_DISP0_DAT5__CSPI_SS2 147 +MX53_PAD_DISP0_DAT5__USBOH3_USBH2_DATA_5 148 +MX53_PAD_DISP0_DAT5__SDMA_DEBUG_MATCHED_DMBUS 149 +MX53_PAD_DISP0_DAT5__EMI_EMI_DEBUG_10 150 +MX53_PAD_DISP0_DAT5__USBPHY2_LINESTATE_0 151 +MX53_PAD_DISP0_DAT6__IPU_DISP0_DAT_6 152 +MX53_PAD_DISP0_DAT6__GPIO4_27 153 +MX53_PAD_DISP0_DAT6__CSPI_SS3 154 +MX53_PAD_DISP0_DAT6__USBOH3_USBH2_DATA_6 155 +MX53_PAD_DISP0_DAT6__SDMA_DEBUG_RTBUFFER_WRITE 156 +MX53_PAD_DISP0_DAT6__EMI_EMI_DEBUG_11 157 +MX53_PAD_DISP0_DAT6__USBPHY2_LINESTATE_1 158 +MX53_PAD_DISP0_DAT7__IPU_DISP0_DAT_7 159 +MX53_PAD_DISP0_DAT7__GPIO4_28 160 +MX53_PAD_DISP0_DAT7__CSPI_RDY 161 +MX53_PAD_DISP0_DAT7__USBOH3_USBH2_DATA_7 162 +MX53_PAD_DISP0_DAT7__SDMA_DEBUG_EVENT_CHANNEL_0 163 +MX53_PAD_DISP0_DAT7__EMI_EMI_DEBUG_12 164 +MX53_PAD_DISP0_DAT7__USBPHY2_VBUSVALID 165 +MX53_PAD_DISP0_DAT8__IPU_DISP0_DAT_8 166 +MX53_PAD_DISP0_DAT8__GPIO4_29 167 +MX53_PAD_DISP0_DAT8__PWM1_PWMO 168 +MX53_PAD_DISP0_DAT8__WDOG1_WDOG_B 169 +MX53_PAD_DISP0_DAT8__SDMA_DEBUG_EVENT_CHANNEL_1 170 +MX53_PAD_DISP0_DAT8__EMI_EMI_DEBUG_13 171 +MX53_PAD_DISP0_DAT8__USBPHY2_AVALID 172 +MX53_PAD_DISP0_DAT9__IPU_DISP0_DAT_9 173 +MX53_PAD_DISP0_DAT9__GPIO4_30 174 +MX53_PAD_DISP0_DAT9__PWM2_PWMO 175 +MX53_PAD_DISP0_DAT9__WDOG2_WDOG_B 176 +MX53_PAD_DISP0_DAT9__SDMA_DEBUG_EVENT_CHANNEL_2 177 +MX53_PAD_DISP0_DAT9__EMI_EMI_DEBUG_14 178 +MX53_PAD_DISP0_DAT9__USBPHY2_VSTATUS_0 179 +MX53_PAD_DISP0_DAT10__IPU_DISP0_DAT_10 180 +MX53_PAD_DISP0_DAT10__GPIO4_31 181 +MX53_PAD_DISP0_DAT10__USBOH3_USBH2_STP 182 +MX53_PAD_DISP0_DAT10__SDMA_DEBUG_EVENT_CHANNEL_3 183 +MX53_PAD_DISP0_DAT10__EMI_EMI_DEBUG_15 184 +MX53_PAD_DISP0_DAT10__USBPHY2_VSTATUS_1 185 +MX53_PAD_DISP0_DAT11__IPU_DISP0_DAT_11 186 +MX53_PAD_DISP0_DAT11__GPIO5_5 187 +MX53_PAD_DISP0_DAT11__USBOH3_USBH2_NXT 188 +MX53_PAD_DISP0_DAT11__SDMA_DEBUG_EVENT_CHANNEL_4 189 +MX53_PAD_DISP0_DAT11__EMI_EMI_DEBUG_16 190 +MX53_PAD_DISP0_DAT11__USBPHY2_VSTATUS_2 191 +MX53_PAD_DISP0_DAT12__IPU_DISP0_DAT_12 192 +MX53_PAD_DISP0_DAT12__GPIO5_6 193 +MX53_PAD_DISP0_DAT12__USBOH3_USBH2_CLK 194 +MX53_PAD_DISP0_DAT12__SDMA_DEBUG_EVENT_CHANNEL_5 195 +MX53_PAD_DISP0_DAT12__EMI_EMI_DEBUG_17 196 +MX53_PAD_DISP0_DAT12__USBPHY2_VSTATUS_3 197 +MX53_PAD_DISP0_DAT13__IPU_DISP0_DAT_13 198 +MX53_PAD_DISP0_DAT13__GPIO5_7 199 +MX53_PAD_DISP0_DAT13__AUDMUX_AUD5_RXFS 200 +MX53_PAD_DISP0_DAT13__SDMA_DEBUG_EVT_CHN_LINES_0 201 +MX53_PAD_DISP0_DAT13__EMI_EMI_DEBUG_18 202 +MX53_PAD_DISP0_DAT13__USBPHY2_VSTATUS_4 203 +MX53_PAD_DISP0_DAT14__IPU_DISP0_DAT_14 204 +MX53_PAD_DISP0_DAT14__GPIO5_8 205 +MX53_PAD_DISP0_DAT14__AUDMUX_AUD5_RXC 206 +MX53_PAD_DISP0_DAT14__SDMA_DEBUG_EVT_CHN_LINES_1 207 +MX53_PAD_DISP0_DAT14__EMI_EMI_DEBUG_19 208 +MX53_PAD_DISP0_DAT14__USBPHY2_VSTATUS_5 209 +MX53_PAD_DISP0_DAT15__IPU_DISP0_DAT_15 210 +MX53_PAD_DISP0_DAT15__GPIO5_9 211 +MX53_PAD_DISP0_DAT15__ECSPI1_SS1 212 +MX53_PAD_DISP0_DAT15__ECSPI2_SS1 213 +MX53_PAD_DISP0_DAT15__SDMA_DEBUG_EVT_CHN_LINES_2 214 +MX53_PAD_DISP0_DAT15__EMI_EMI_DEBUG_20 215 +MX53_PAD_DISP0_DAT15__USBPHY2_VSTATUS_6 216 +MX53_PAD_DISP0_DAT16__IPU_DISP0_DAT_16 217 +MX53_PAD_DISP0_DAT16__GPIO5_10 218 +MX53_PAD_DISP0_DAT16__ECSPI2_MOSI 219 +MX53_PAD_DISP0_DAT16__AUDMUX_AUD5_TXC 220 +MX53_PAD_DISP0_DAT16__SDMA_EXT_EVENT_0 221 +MX53_PAD_DISP0_DAT16__SDMA_DEBUG_EVT_CHN_LINES_3 222 +MX53_PAD_DISP0_DAT16__EMI_EMI_DEBUG_21 223 +MX53_PAD_DISP0_DAT16__USBPHY2_VSTATUS_7 224 +MX53_PAD_DISP0_DAT17__IPU_DISP0_DAT_17 225 +MX53_PAD_DISP0_DAT17__GPIO5_11 226 +MX53_PAD_DISP0_DAT17__ECSPI2_MISO 227 +MX53_PAD_DISP0_DAT17__AUDMUX_AUD5_TXD 228 +MX53_PAD_DISP0_DAT17__SDMA_EXT_EVENT_1 229 +MX53_PAD_DISP0_DAT17__SDMA_DEBUG_EVT_CHN_LINES_4 230 +MX53_PAD_DISP0_DAT17__EMI_EMI_DEBUG_22 231 +MX53_PAD_DISP0_DAT18__IPU_DISP0_DAT_18 232 +MX53_PAD_DISP0_DAT18__GPIO5_12 233 +MX53_PAD_DISP0_DAT18__ECSPI2_SS0 234 +MX53_PAD_DISP0_DAT18__AUDMUX_AUD5_TXFS 235 +MX53_PAD_DISP0_DAT18__AUDMUX_AUD4_RXFS 236 +MX53_PAD_DISP0_DAT18__SDMA_DEBUG_EVT_CHN_LINES_5 237 +MX53_PAD_DISP0_DAT18__EMI_EMI_DEBUG_23 238 +MX53_PAD_DISP0_DAT18__EMI_WEIM_CS_2 239 +MX53_PAD_DISP0_DAT19__IPU_DISP0_DAT_19 240 +MX53_PAD_DISP0_DAT19__GPIO5_13 241 +MX53_PAD_DISP0_DAT19__ECSPI2_SCLK 242 +MX53_PAD_DISP0_DAT19__AUDMUX_AUD5_RXD 243 +MX53_PAD_DISP0_DAT19__AUDMUX_AUD4_RXC 244 +MX53_PAD_DISP0_DAT19__SDMA_DEBUG_EVT_CHN_LINES_6 245 +MX53_PAD_DISP0_DAT19__EMI_EMI_DEBUG_24 246 +MX53_PAD_DISP0_DAT19__EMI_WEIM_CS_3 247 +MX53_PAD_DISP0_DAT20__IPU_DISP0_DAT_20 248 +MX53_PAD_DISP0_DAT20__GPIO5_14 249 +MX53_PAD_DISP0_DAT20__ECSPI1_SCLK 250 +MX53_PAD_DISP0_DAT20__AUDMUX_AUD4_TXC 251 +MX53_PAD_DISP0_DAT20__SDMA_DEBUG_EVT_CHN_LINES_7 252 +MX53_PAD_DISP0_DAT20__EMI_EMI_DEBUG_25 253 +MX53_PAD_DISP0_DAT20__SATA_PHY_TDI 254 +MX53_PAD_DISP0_DAT21__IPU_DISP0_DAT_21 255 +MX53_PAD_DISP0_DAT21__GPIO5_15 256 +MX53_PAD_DISP0_DAT21__ECSPI1_MOSI 257 +MX53_PAD_DISP0_DAT21__AUDMUX_AUD4_TXD 258 +MX53_PAD_DISP0_DAT21__SDMA_DEBUG_BUS_DEVICE_0 259 +MX53_PAD_DISP0_DAT21__EMI_EMI_DEBUG_26 260 +MX53_PAD_DISP0_DAT21__SATA_PHY_TDO 261 +MX53_PAD_DISP0_DAT22__IPU_DISP0_DAT_22 262 +MX53_PAD_DISP0_DAT22__GPIO5_16 263 +MX53_PAD_DISP0_DAT22__ECSPI1_MISO 264 +MX53_PAD_DISP0_DAT22__AUDMUX_AUD4_TXFS 265 +MX53_PAD_DISP0_DAT22__SDMA_DEBUG_BUS_DEVICE_1 266 +MX53_PAD_DISP0_DAT22__EMI_EMI_DEBUG_27 267 +MX53_PAD_DISP0_DAT22__SATA_PHY_TCK 268 +MX53_PAD_DISP0_DAT23__IPU_DISP0_DAT_23 269 +MX53_PAD_DISP0_DAT23__GPIO5_17 270 +MX53_PAD_DISP0_DAT23__ECSPI1_SS0 271 +MX53_PAD_DISP0_DAT23__AUDMUX_AUD4_RXD 272 +MX53_PAD_DISP0_DAT23__SDMA_DEBUG_BUS_DEVICE_2 273 +MX53_PAD_DISP0_DAT23__EMI_EMI_DEBUG_28 274 +MX53_PAD_DISP0_DAT23__SATA_PHY_TMS 275 +MX53_PAD_CSI0_PIXCLK__IPU_CSI0_PIXCLK 276 +MX53_PAD_CSI0_PIXCLK__GPIO5_18 277 +MX53_PAD_CSI0_PIXCLK__SDMA_DEBUG_PC_0 278 +MX53_PAD_CSI0_PIXCLK__EMI_EMI_DEBUG_29 279 +MX53_PAD_CSI0_MCLK__IPU_CSI0_HSYNC 280 +MX53_PAD_CSI0_MCLK__GPIO5_19 281 +MX53_PAD_CSI0_MCLK__CCM_CSI0_MCLK 282 +MX53_PAD_CSI0_MCLK__SDMA_DEBUG_PC_1 283 +MX53_PAD_CSI0_MCLK__EMI_EMI_DEBUG_30 284 +MX53_PAD_CSI0_MCLK__TPIU_TRCTL 285 +MX53_PAD_CSI0_DATA_EN__IPU_CSI0_DATA_EN 286 +MX53_PAD_CSI0_DATA_EN__GPIO5_20 287 +MX53_PAD_CSI0_DATA_EN__SDMA_DEBUG_PC_2 288 +MX53_PAD_CSI0_DATA_EN__EMI_EMI_DEBUG_31 289 +MX53_PAD_CSI0_DATA_EN__TPIU_TRCLK 290 +MX53_PAD_CSI0_VSYNC__IPU_CSI0_VSYNC 291 +MX53_PAD_CSI0_VSYNC__GPIO5_21 292 +MX53_PAD_CSI0_VSYNC__SDMA_DEBUG_PC_3 293 +MX53_PAD_CSI0_VSYNC__EMI_EMI_DEBUG_32 294 +MX53_PAD_CSI0_VSYNC__TPIU_TRACE_0 295 +MX53_PAD_CSI0_DAT4__IPU_CSI0_D_4 296 +MX53_PAD_CSI0_DAT4__GPIO5_22 297 +MX53_PAD_CSI0_DAT4__KPP_COL_5 298 +MX53_PAD_CSI0_DAT4__ECSPI1_SCLK 299 +MX53_PAD_CSI0_DAT4__USBOH3_USBH3_STP 300 +MX53_PAD_CSI0_DAT4__AUDMUX_AUD3_TXC 301 +MX53_PAD_CSI0_DAT4__EMI_EMI_DEBUG_33 302 +MX53_PAD_CSI0_DAT4__TPIU_TRACE_1 303 +MX53_PAD_CSI0_DAT5__IPU_CSI0_D_5 304 +MX53_PAD_CSI0_DAT5__GPIO5_23 305 +MX53_PAD_CSI0_DAT5__KPP_ROW_5 306 +MX53_PAD_CSI0_DAT5__ECSPI1_MOSI 307 +MX53_PAD_CSI0_DAT5__USBOH3_USBH3_NXT 308 +MX53_PAD_CSI0_DAT5__AUDMUX_AUD3_TXD 309 +MX53_PAD_CSI0_DAT5__EMI_EMI_DEBUG_34 310 +MX53_PAD_CSI0_DAT5__TPIU_TRACE_2 311 +MX53_PAD_CSI0_DAT6__IPU_CSI0_D_6 312 +MX53_PAD_CSI0_DAT6__GPIO5_24 313 +MX53_PAD_CSI0_DAT6__KPP_COL_6 314 +MX53_PAD_CSI0_DAT6__ECSPI1_MISO 315 +MX53_PAD_CSI0_DAT6__USBOH3_USBH3_CLK 316 +MX53_PAD_CSI0_DAT6__AUDMUX_AUD3_TXFS 317 +MX53_PAD_CSI0_DAT6__EMI_EMI_DEBUG_35 318 +MX53_PAD_CSI0_DAT6__TPIU_TRACE_3 319 +MX53_PAD_CSI0_DAT7__IPU_CSI0_D_7 320 +MX53_PAD_CSI0_DAT7__GPIO5_25 321 +MX53_PAD_CSI0_DAT7__KPP_ROW_6 322 +MX53_PAD_CSI0_DAT7__ECSPI1_SS0 323 +MX53_PAD_CSI0_DAT7__USBOH3_USBH3_DIR 324 +MX53_PAD_CSI0_DAT7__AUDMUX_AUD3_RXD 325 +MX53_PAD_CSI0_DAT7__EMI_EMI_DEBUG_36 326 +MX53_PAD_CSI0_DAT7__TPIU_TRACE_4 327 +MX53_PAD_CSI0_DAT8__IPU_CSI0_D_8 328 +MX53_PAD_CSI0_DAT8__GPIO5_26 329 +MX53_PAD_CSI0_DAT8__KPP_COL_7 330 +MX53_PAD_CSI0_DAT8__ECSPI2_SCLK 331 +MX53_PAD_CSI0_DAT8__USBOH3_USBH3_OC 332 +MX53_PAD_CSI0_DAT8__I2C1_SDA 333 +MX53_PAD_CSI0_DAT8__EMI_EMI_DEBUG_37 334 +MX53_PAD_CSI0_DAT8__TPIU_TRACE_5 335 +MX53_PAD_CSI0_DAT9__IPU_CSI0_D_9 336 +MX53_PAD_CSI0_DAT9__GPIO5_27 337 +MX53_PAD_CSI0_DAT9__KPP_ROW_7 338 +MX53_PAD_CSI0_DAT9__ECSPI2_MOSI 339 +MX53_PAD_CSI0_DAT9__USBOH3_USBH3_PWR 340 +MX53_PAD_CSI0_DAT9__I2C1_SCL 341 +MX53_PAD_CSI0_DAT9__EMI_EMI_DEBUG_38 342 +MX53_PAD_CSI0_DAT9__TPIU_TRACE_6 343 +MX53_PAD_CSI0_DAT10__IPU_CSI0_D_10 344 +MX53_PAD_CSI0_DAT10__GPIO5_28 345 +MX53_PAD_CSI0_DAT10__UART1_TXD_MUX 346 +MX53_PAD_CSI0_DAT10__ECSPI2_MISO 347 +MX53_PAD_CSI0_DAT10__AUDMUX_AUD3_RXC 348 +MX53_PAD_CSI0_DAT10__SDMA_DEBUG_PC_4 349 +MX53_PAD_CSI0_DAT10__EMI_EMI_DEBUG_39 350 +MX53_PAD_CSI0_DAT10__TPIU_TRACE_7 351 +MX53_PAD_CSI0_DAT11__IPU_CSI0_D_11 352 +MX53_PAD_CSI0_DAT11__GPIO5_29 353 +MX53_PAD_CSI0_DAT11__UART1_RXD_MUX 354 +MX53_PAD_CSI0_DAT11__ECSPI2_SS0 355 +MX53_PAD_CSI0_DAT11__AUDMUX_AUD3_RXFS 356 +MX53_PAD_CSI0_DAT11__SDMA_DEBUG_PC_5 357 +MX53_PAD_CSI0_DAT11__EMI_EMI_DEBUG_40 358 +MX53_PAD_CSI0_DAT11__TPIU_TRACE_8 359 +MX53_PAD_CSI0_DAT12__IPU_CSI0_D_12 360 +MX53_PAD_CSI0_DAT12__GPIO5_30 361 +MX53_PAD_CSI0_DAT12__UART4_TXD_MUX 362 +MX53_PAD_CSI0_DAT12__USBOH3_USBH3_DATA_0 363 +MX53_PAD_CSI0_DAT12__SDMA_DEBUG_PC_6 364 +MX53_PAD_CSI0_DAT12__EMI_EMI_DEBUG_41 365 +MX53_PAD_CSI0_DAT12__TPIU_TRACE_9 366 +MX53_PAD_CSI0_DAT13__IPU_CSI0_D_13 367 +MX53_PAD_CSI0_DAT13__GPIO5_31 368 +MX53_PAD_CSI0_DAT13__UART4_RXD_MUX 369 +MX53_PAD_CSI0_DAT13__USBOH3_USBH3_DATA_1 370 +MX53_PAD_CSI0_DAT13__SDMA_DEBUG_PC_7 371 +MX53_PAD_CSI0_DAT13__EMI_EMI_DEBUG_42 372 +MX53_PAD_CSI0_DAT13__TPIU_TRACE_10 373 +MX53_PAD_CSI0_DAT14__IPU_CSI0_D_14 374 +MX53_PAD_CSI0_DAT14__GPIO6_0 375 +MX53_PAD_CSI0_DAT14__UART5_TXD_MUX 376 +MX53_PAD_CSI0_DAT14__USBOH3_USBH3_DATA_2 377 +MX53_PAD_CSI0_DAT14__SDMA_DEBUG_PC_8 378 +MX53_PAD_CSI0_DAT14__EMI_EMI_DEBUG_43 379 +MX53_PAD_CSI0_DAT14__TPIU_TRACE_11 380 +MX53_PAD_CSI0_DAT15__IPU_CSI0_D_15 381 +MX53_PAD_CSI0_DAT15__GPIO6_1 382 +MX53_PAD_CSI0_DAT15__UART5_RXD_MUX 383 +MX53_PAD_CSI0_DAT15__USBOH3_USBH3_DATA_3 384 +MX53_PAD_CSI0_DAT15__SDMA_DEBUG_PC_9 385 +MX53_PAD_CSI0_DAT15__EMI_EMI_DEBUG_44 386 +MX53_PAD_CSI0_DAT15__TPIU_TRACE_12 387 +MX53_PAD_CSI0_DAT16__IPU_CSI0_D_16 388 +MX53_PAD_CSI0_DAT16__GPIO6_2 389 +MX53_PAD_CSI0_DAT16__UART4_RTS 390 +MX53_PAD_CSI0_DAT16__USBOH3_USBH3_DATA_4 391 +MX53_PAD_CSI0_DAT16__SDMA_DEBUG_PC_10 392 +MX53_PAD_CSI0_DAT16__EMI_EMI_DEBUG_45 393 +MX53_PAD_CSI0_DAT16__TPIU_TRACE_13 394 +MX53_PAD_CSI0_DAT17__IPU_CSI0_D_17 395 +MX53_PAD_CSI0_DAT17__GPIO6_3 396 +MX53_PAD_CSI0_DAT17__UART4_CTS 397 +MX53_PAD_CSI0_DAT17__USBOH3_USBH3_DATA_5 398 +MX53_PAD_CSI0_DAT17__SDMA_DEBUG_PC_11 399 +MX53_PAD_CSI0_DAT17__EMI_EMI_DEBUG_46 400 +MX53_PAD_CSI0_DAT17__TPIU_TRACE_14 401 +MX53_PAD_CSI0_DAT18__IPU_CSI0_D_18 402 +MX53_PAD_CSI0_DAT18__GPIO6_4 403 +MX53_PAD_CSI0_DAT18__UART5_RTS 404 +MX53_PAD_CSI0_DAT18__USBOH3_USBH3_DATA_6 405 +MX53_PAD_CSI0_DAT18__SDMA_DEBUG_PC_12 406 +MX53_PAD_CSI0_DAT18__EMI_EMI_DEBUG_47 407 +MX53_PAD_CSI0_DAT18__TPIU_TRACE_15 408 +MX53_PAD_CSI0_DAT19__IPU_CSI0_D_19 409 +MX53_PAD_CSI0_DAT19__GPIO6_5 410 +MX53_PAD_CSI0_DAT19__UART5_CTS 411 +MX53_PAD_CSI0_DAT19__USBOH3_USBH3_DATA_7 412 +MX53_PAD_CSI0_DAT19__SDMA_DEBUG_PC_13 413 +MX53_PAD_CSI0_DAT19__EMI_EMI_DEBUG_48 414 +MX53_PAD_CSI0_DAT19__USBPHY2_BISTOK 415 +MX53_PAD_EIM_A25__EMI_WEIM_A_25 416 +MX53_PAD_EIM_A25__GPIO5_2 417 +MX53_PAD_EIM_A25__ECSPI2_RDY 418 +MX53_PAD_EIM_A25__IPU_DI1_PIN12 419 +MX53_PAD_EIM_A25__CSPI_SS1 420 +MX53_PAD_EIM_A25__IPU_DI0_D1_CS 421 +MX53_PAD_EIM_A25__USBPHY1_BISTOK 422 +MX53_PAD_EIM_EB2__EMI_WEIM_EB_2 423 +MX53_PAD_EIM_EB2__GPIO2_30 424 +MX53_PAD_EIM_EB2__CCM_DI1_EXT_CLK 425 +MX53_PAD_EIM_EB2__IPU_SER_DISP1_CS 426 +MX53_PAD_EIM_EB2__ECSPI1_SS0 427 +MX53_PAD_EIM_EB2__I2C2_SCL 428 +MX53_PAD_EIM_D16__EMI_WEIM_D_16 429 +MX53_PAD_EIM_D16__GPIO3_16 430 +MX53_PAD_EIM_D16__IPU_DI0_PIN5 431 +MX53_PAD_EIM_D16__IPU_DISPB1_SER_CLK 432 +MX53_PAD_EIM_D16__ECSPI1_SCLK 433 +MX53_PAD_EIM_D16__I2C2_SDA 434 +MX53_PAD_EIM_D17__EMI_WEIM_D_17 435 +MX53_PAD_EIM_D17__GPIO3_17 436 +MX53_PAD_EIM_D17__IPU_DI0_PIN6 437 +MX53_PAD_EIM_D17__IPU_DISPB1_SER_DIN 438 +MX53_PAD_EIM_D17__ECSPI1_MISO 439 +MX53_PAD_EIM_D17__I2C3_SCL 440 +MX53_PAD_EIM_D18__EMI_WEIM_D_18 441 +MX53_PAD_EIM_D18__GPIO3_18 442 +MX53_PAD_EIM_D18__IPU_DI0_PIN7 443 +MX53_PAD_EIM_D18__IPU_DISPB1_SER_DIO 444 +MX53_PAD_EIM_D18__ECSPI1_MOSI 445 +MX53_PAD_EIM_D18__I2C3_SDA 446 +MX53_PAD_EIM_D18__IPU_DI1_D0_CS 447 +MX53_PAD_EIM_D19__EMI_WEIM_D_19 448 +MX53_PAD_EIM_D19__GPIO3_19 449 +MX53_PAD_EIM_D19__IPU_DI0_PIN8 450 +MX53_PAD_EIM_D19__IPU_DISPB1_SER_RS 451 +MX53_PAD_EIM_D19__ECSPI1_SS1 452 +MX53_PAD_EIM_D19__EPIT1_EPITO 453 +MX53_PAD_EIM_D19__UART1_CTS 454 +MX53_PAD_EIM_D19__USBOH3_USBH2_OC 455 +MX53_PAD_EIM_D20__EMI_WEIM_D_20 456 +MX53_PAD_EIM_D20__GPIO3_20 457 +MX53_PAD_EIM_D20__IPU_DI0_PIN16 458 +MX53_PAD_EIM_D20__IPU_SER_DISP0_CS 459 +MX53_PAD_EIM_D20__CSPI_SS0 460 +MX53_PAD_EIM_D20__EPIT2_EPITO 461 +MX53_PAD_EIM_D20__UART1_RTS 462 +MX53_PAD_EIM_D20__USBOH3_USBH2_PWR 463 +MX53_PAD_EIM_D21__EMI_WEIM_D_21 464 +MX53_PAD_EIM_D21__GPIO3_21 465 +MX53_PAD_EIM_D21__IPU_DI0_PIN17 466 +MX53_PAD_EIM_D21__IPU_DISPB0_SER_CLK 467 +MX53_PAD_EIM_D21__CSPI_SCLK 468 +MX53_PAD_EIM_D21__I2C1_SCL 469 +MX53_PAD_EIM_D21__USBOH3_USBOTG_OC 470 +MX53_PAD_EIM_D22__EMI_WEIM_D_22 471 +MX53_PAD_EIM_D22__GPIO3_22 472 +MX53_PAD_EIM_D22__IPU_DI0_PIN1 473 +MX53_PAD_EIM_D22__IPU_DISPB0_SER_DIN 474 +MX53_PAD_EIM_D22__CSPI_MISO 475 +MX53_PAD_EIM_D22__USBOH3_USBOTG_PWR 476 +MX53_PAD_EIM_D23__EMI_WEIM_D_23 477 +MX53_PAD_EIM_D23__GPIO3_23 478 +MX53_PAD_EIM_D23__UART3_CTS 479 +MX53_PAD_EIM_D23__UART1_DCD 480 +MX53_PAD_EIM_D23__IPU_DI0_D0_CS 481 +MX53_PAD_EIM_D23__IPU_DI1_PIN2 482 +MX53_PAD_EIM_D23__IPU_CSI1_DATA_EN 483 +MX53_PAD_EIM_D23__IPU_DI1_PIN14 484 +MX53_PAD_EIM_EB3__EMI_WEIM_EB_3 485 +MX53_PAD_EIM_EB3__GPIO2_31 486 +MX53_PAD_EIM_EB3__UART3_RTS 487 +MX53_PAD_EIM_EB3__UART1_RI 488 +MX53_PAD_EIM_EB3__IPU_DI1_PIN3 489 +MX53_PAD_EIM_EB3__IPU_CSI1_HSYNC 490 +MX53_PAD_EIM_EB3__IPU_DI1_PIN16 491 +MX53_PAD_EIM_D24__EMI_WEIM_D_24 492 +MX53_PAD_EIM_D24__GPIO3_24 493 +MX53_PAD_EIM_D24__UART3_TXD_MUX 494 +MX53_PAD_EIM_D24__ECSPI1_SS2 495 +MX53_PAD_EIM_D24__CSPI_SS2 496 +MX53_PAD_EIM_D24__AUDMUX_AUD5_RXFS 497 +MX53_PAD_EIM_D24__ECSPI2_SS2 498 +MX53_PAD_EIM_D24__UART1_DTR 499 +MX53_PAD_EIM_D25__EMI_WEIM_D_25 500 +MX53_PAD_EIM_D25__GPIO3_25 501 +MX53_PAD_EIM_D25__UART3_RXD_MUX 502 +MX53_PAD_EIM_D25__ECSPI1_SS3 503 +MX53_PAD_EIM_D25__CSPI_SS3 504 +MX53_PAD_EIM_D25__AUDMUX_AUD5_RXC 505 +MX53_PAD_EIM_D25__ECSPI2_SS3 506 +MX53_PAD_EIM_D25__UART1_DSR 507 +MX53_PAD_EIM_D26__EMI_WEIM_D_26 508 +MX53_PAD_EIM_D26__GPIO3_26 509 +MX53_PAD_EIM_D26__UART2_TXD_MUX 510 +MX53_PAD_EIM_D26__FIRI_RXD 511 +MX53_PAD_EIM_D26__IPU_CSI0_D_1 512 +MX53_PAD_EIM_D26__IPU_DI1_PIN11 513 +MX53_PAD_EIM_D26__IPU_SISG_2 514 +MX53_PAD_EIM_D26__IPU_DISP1_DAT_22 515 +MX53_PAD_EIM_D27__EMI_WEIM_D_27 516 +MX53_PAD_EIM_D27__GPIO3_27 517 +MX53_PAD_EIM_D27__UART2_RXD_MUX 518 +MX53_PAD_EIM_D27__FIRI_TXD 519 +MX53_PAD_EIM_D27__IPU_CSI0_D_0 520 +MX53_PAD_EIM_D27__IPU_DI1_PIN13 521 +MX53_PAD_EIM_D27__IPU_SISG_3 522 +MX53_PAD_EIM_D27__IPU_DISP1_DAT_23 523 +MX53_PAD_EIM_D28__EMI_WEIM_D_28 524 +MX53_PAD_EIM_D28__GPIO3_28 525 +MX53_PAD_EIM_D28__UART2_CTS 526 +MX53_PAD_EIM_D28__IPU_DISPB0_SER_DIO 527 +MX53_PAD_EIM_D28__CSPI_MOSI 528 +MX53_PAD_EIM_D28__I2C1_SDA 529 +MX53_PAD_EIM_D28__IPU_EXT_TRIG 530 +MX53_PAD_EIM_D28__IPU_DI0_PIN13 531 +MX53_PAD_EIM_D29__EMI_WEIM_D_29 532 +MX53_PAD_EIM_D29__GPIO3_29 533 +MX53_PAD_EIM_D29__UART2_RTS 534 +MX53_PAD_EIM_D29__IPU_DISPB0_SER_RS 535 +MX53_PAD_EIM_D29__CSPI_SS0 536 +MX53_PAD_EIM_D29__IPU_DI1_PIN15 537 +MX53_PAD_EIM_D29__IPU_CSI1_VSYNC 538 +MX53_PAD_EIM_D29__IPU_DI0_PIN14 539 +MX53_PAD_EIM_D30__EMI_WEIM_D_30 540 +MX53_PAD_EIM_D30__GPIO3_30 541 +MX53_PAD_EIM_D30__UART3_CTS 542 +MX53_PAD_EIM_D30__IPU_CSI0_D_3 543 +MX53_PAD_EIM_D30__IPU_DI0_PIN11 544 +MX53_PAD_EIM_D30__IPU_DISP1_DAT_21 545 +MX53_PAD_EIM_D30__USBOH3_USBH1_OC 546 +MX53_PAD_EIM_D30__USBOH3_USBH2_OC 547 +MX53_PAD_EIM_D31__EMI_WEIM_D_31 548 +MX53_PAD_EIM_D31__GPIO3_31 549 +MX53_PAD_EIM_D31__UART3_RTS 550 +MX53_PAD_EIM_D31__IPU_CSI0_D_2 551 +MX53_PAD_EIM_D31__IPU_DI0_PIN12 552 +MX53_PAD_EIM_D31__IPU_DISP1_DAT_20 553 +MX53_PAD_EIM_D31__USBOH3_USBH1_PWR 554 +MX53_PAD_EIM_D31__USBOH3_USBH2_PWR 555 +MX53_PAD_EIM_A24__EMI_WEIM_A_24 556 +MX53_PAD_EIM_A24__GPIO5_4 557 +MX53_PAD_EIM_A24__IPU_DISP1_DAT_19 558 +MX53_PAD_EIM_A24__IPU_CSI1_D_19 559 +MX53_PAD_EIM_A24__IPU_SISG_2 560 +MX53_PAD_EIM_A24__USBPHY2_BVALID 561 +MX53_PAD_EIM_A23__EMI_WEIM_A_23 562 +MX53_PAD_EIM_A23__GPIO6_6 563 +MX53_PAD_EIM_A23__IPU_DISP1_DAT_18 564 +MX53_PAD_EIM_A23__IPU_CSI1_D_18 565 +MX53_PAD_EIM_A23__IPU_SISG_3 566 +MX53_PAD_EIM_A23__USBPHY2_ENDSESSION 567 +MX53_PAD_EIM_A22__EMI_WEIM_A_22 568 +MX53_PAD_EIM_A22__GPIO2_16 569 +MX53_PAD_EIM_A22__IPU_DISP1_DAT_17 570 +MX53_PAD_EIM_A22__IPU_CSI1_D_17 571 +MX53_PAD_EIM_A22__SRC_BT_CFG1_7 572 +MX53_PAD_EIM_A21__EMI_WEIM_A_21 573 +MX53_PAD_EIM_A21__GPIO2_17 574 +MX53_PAD_EIM_A21__IPU_DISP1_DAT_16 575 +MX53_PAD_EIM_A21__IPU_CSI1_D_16 576 +MX53_PAD_EIM_A21__SRC_BT_CFG1_6 577 +MX53_PAD_EIM_A20__EMI_WEIM_A_20 578 +MX53_PAD_EIM_A20__GPIO2_18 579 +MX53_PAD_EIM_A20__IPU_DISP1_DAT_15 580 +MX53_PAD_EIM_A20__IPU_CSI1_D_15 581 +MX53_PAD_EIM_A20__SRC_BT_CFG1_5 582 +MX53_PAD_EIM_A19__EMI_WEIM_A_19 583 +MX53_PAD_EIM_A19__GPIO2_19 584 +MX53_PAD_EIM_A19__IPU_DISP1_DAT_14 585 +MX53_PAD_EIM_A19__IPU_CSI1_D_14 586 +MX53_PAD_EIM_A19__SRC_BT_CFG1_4 587 +MX53_PAD_EIM_A18__EMI_WEIM_A_18 588 +MX53_PAD_EIM_A18__GPIO2_20 589 +MX53_PAD_EIM_A18__IPU_DISP1_DAT_13 590 +MX53_PAD_EIM_A18__IPU_CSI1_D_13 591 +MX53_PAD_EIM_A18__SRC_BT_CFG1_3 592 +MX53_PAD_EIM_A17__EMI_WEIM_A_17 593 +MX53_PAD_EIM_A17__GPIO2_21 594 +MX53_PAD_EIM_A17__IPU_DISP1_DAT_12 595 +MX53_PAD_EIM_A17__IPU_CSI1_D_12 596 +MX53_PAD_EIM_A17__SRC_BT_CFG1_2 597 +MX53_PAD_EIM_A16__EMI_WEIM_A_16 598 +MX53_PAD_EIM_A16__GPIO2_22 599 +MX53_PAD_EIM_A16__IPU_DI1_DISP_CLK 600 +MX53_PAD_EIM_A16__IPU_CSI1_PIXCLK 601 +MX53_PAD_EIM_A16__SRC_BT_CFG1_1 602 +MX53_PAD_EIM_CS0__EMI_WEIM_CS_0 603 +MX53_PAD_EIM_CS0__GPIO2_23 604 +MX53_PAD_EIM_CS0__ECSPI2_SCLK 605 +MX53_PAD_EIM_CS0__IPU_DI1_PIN5 606 +MX53_PAD_EIM_CS1__EMI_WEIM_CS_1 607 +MX53_PAD_EIM_CS1__GPIO2_24 608 +MX53_PAD_EIM_CS1__ECSPI2_MOSI 609 +MX53_PAD_EIM_CS1__IPU_DI1_PIN6 610 +MX53_PAD_EIM_OE__EMI_WEIM_OE 611 +MX53_PAD_EIM_OE__GPIO2_25 612 +MX53_PAD_EIM_OE__ECSPI2_MISO 613 +MX53_PAD_EIM_OE__IPU_DI1_PIN7 614 +MX53_PAD_EIM_OE__USBPHY2_IDDIG 615 +MX53_PAD_EIM_RW__EMI_WEIM_RW 616 +MX53_PAD_EIM_RW__GPIO2_26 617 +MX53_PAD_EIM_RW__ECSPI2_SS0 618 +MX53_PAD_EIM_RW__IPU_DI1_PIN8 619 +MX53_PAD_EIM_RW__USBPHY2_HOSTDISCONNECT 620 +MX53_PAD_EIM_LBA__EMI_WEIM_LBA 621 +MX53_PAD_EIM_LBA__GPIO2_27 622 +MX53_PAD_EIM_LBA__ECSPI2_SS1 623 +MX53_PAD_EIM_LBA__IPU_DI1_PIN17 624 +MX53_PAD_EIM_LBA__SRC_BT_CFG1_0 625 +MX53_PAD_EIM_EB0__EMI_WEIM_EB_0 626 +MX53_PAD_EIM_EB0__GPIO2_28 627 +MX53_PAD_EIM_EB0__IPU_DISP1_DAT_11 628 +MX53_PAD_EIM_EB0__IPU_CSI1_D_11 629 +MX53_PAD_EIM_EB0__GPC_PMIC_RDY 630 +MX53_PAD_EIM_EB0__SRC_BT_CFG2_7 631 +MX53_PAD_EIM_EB1__EMI_WEIM_EB_1 632 +MX53_PAD_EIM_EB1__GPIO2_29 633 +MX53_PAD_EIM_EB1__IPU_DISP1_DAT_10 634 +MX53_PAD_EIM_EB1__IPU_CSI1_D_10 635 +MX53_PAD_EIM_EB1__SRC_BT_CFG2_6 636 +MX53_PAD_EIM_DA0__EMI_NAND_WEIM_DA_0 637 +MX53_PAD_EIM_DA0__GPIO3_0 638 +MX53_PAD_EIM_DA0__IPU_DISP1_DAT_9 639 +MX53_PAD_EIM_DA0__IPU_CSI1_D_9 640 +MX53_PAD_EIM_DA0__SRC_BT_CFG2_5 641 +MX53_PAD_EIM_DA1__EMI_NAND_WEIM_DA_1 642 +MX53_PAD_EIM_DA1__GPIO3_1 643 +MX53_PAD_EIM_DA1__IPU_DISP1_DAT_8 644 +MX53_PAD_EIM_DA1__IPU_CSI1_D_8 645 +MX53_PAD_EIM_DA1__SRC_BT_CFG2_4 646 +MX53_PAD_EIM_DA2__EMI_NAND_WEIM_DA_2 647 +MX53_PAD_EIM_DA2__GPIO3_2 648 +MX53_PAD_EIM_DA2__IPU_DISP1_DAT_7 649 +MX53_PAD_EIM_DA2__IPU_CSI1_D_7 650 +MX53_PAD_EIM_DA2__SRC_BT_CFG2_3 651 +MX53_PAD_EIM_DA3__EMI_NAND_WEIM_DA_3 652 +MX53_PAD_EIM_DA3__GPIO3_3 653 +MX53_PAD_EIM_DA3__IPU_DISP1_DAT_6 654 +MX53_PAD_EIM_DA3__IPU_CSI1_D_6 655 +MX53_PAD_EIM_DA3__SRC_BT_CFG2_2 656 +MX53_PAD_EIM_DA4__EMI_NAND_WEIM_DA_4 657 +MX53_PAD_EIM_DA4__GPIO3_4 658 +MX53_PAD_EIM_DA4__IPU_DISP1_DAT_5 659 +MX53_PAD_EIM_DA4__IPU_CSI1_D_5 660 +MX53_PAD_EIM_DA4__SRC_BT_CFG3_7 661 +MX53_PAD_EIM_DA5__EMI_NAND_WEIM_DA_5 662 +MX53_PAD_EIM_DA5__GPIO3_5 663 +MX53_PAD_EIM_DA5__IPU_DISP1_DAT_4 664 +MX53_PAD_EIM_DA5__IPU_CSI1_D_4 665 +MX53_PAD_EIM_DA5__SRC_BT_CFG3_6 666 +MX53_PAD_EIM_DA6__EMI_NAND_WEIM_DA_6 667 +MX53_PAD_EIM_DA6__GPIO3_6 668 +MX53_PAD_EIM_DA6__IPU_DISP1_DAT_3 669 +MX53_PAD_EIM_DA6__IPU_CSI1_D_3 670 +MX53_PAD_EIM_DA6__SRC_BT_CFG3_5 671 +MX53_PAD_EIM_DA7__EMI_NAND_WEIM_DA_7 672 +MX53_PAD_EIM_DA7__GPIO3_7 673 +MX53_PAD_EIM_DA7__IPU_DISP1_DAT_2 674 +MX53_PAD_EIM_DA7__IPU_CSI1_D_2 675 +MX53_PAD_EIM_DA7__SRC_BT_CFG3_4 676 +MX53_PAD_EIM_DA8__EMI_NAND_WEIM_DA_8 677 +MX53_PAD_EIM_DA8__GPIO3_8 678 +MX53_PAD_EIM_DA8__IPU_DISP1_DAT_1 679 +MX53_PAD_EIM_DA8__IPU_CSI1_D_1 680 +MX53_PAD_EIM_DA8__SRC_BT_CFG3_3 681 +MX53_PAD_EIM_DA9__EMI_NAND_WEIM_DA_9 682 +MX53_PAD_EIM_DA9__GPIO3_9 683 +MX53_PAD_EIM_DA9__IPU_DISP1_DAT_0 684 +MX53_PAD_EIM_DA9__IPU_CSI1_D_0 685 +MX53_PAD_EIM_DA9__SRC_BT_CFG3_2 686 +MX53_PAD_EIM_DA10__EMI_NAND_WEIM_DA_10 687 +MX53_PAD_EIM_DA10__GPIO3_10 688 +MX53_PAD_EIM_DA10__IPU_DI1_PIN15 689 +MX53_PAD_EIM_DA10__IPU_CSI1_DATA_EN 690 +MX53_PAD_EIM_DA10__SRC_BT_CFG3_1 691 +MX53_PAD_EIM_DA11__EMI_NAND_WEIM_DA_11 692 +MX53_PAD_EIM_DA11__GPIO3_11 693 +MX53_PAD_EIM_DA11__IPU_DI1_PIN2 694 +MX53_PAD_EIM_DA11__IPU_CSI1_HSYNC 695 +MX53_PAD_EIM_DA12__EMI_NAND_WEIM_DA_12 696 +MX53_PAD_EIM_DA12__GPIO3_12 697 +MX53_PAD_EIM_DA12__IPU_DI1_PIN3 698 +MX53_PAD_EIM_DA12__IPU_CSI1_VSYNC 699 +MX53_PAD_EIM_DA13__EMI_NAND_WEIM_DA_13 700 +MX53_PAD_EIM_DA13__GPIO3_13 701 +MX53_PAD_EIM_DA13__IPU_DI1_D0_CS 702 +MX53_PAD_EIM_DA13__CCM_DI1_EXT_CLK 703 +MX53_PAD_EIM_DA14__EMI_NAND_WEIM_DA_14 704 +MX53_PAD_EIM_DA14__GPIO3_14 705 +MX53_PAD_EIM_DA14__IPU_DI1_D1_CS 706 +MX53_PAD_EIM_DA14__CCM_DI0_EXT_CLK 707 +MX53_PAD_EIM_DA15__EMI_NAND_WEIM_DA_15 708 +MX53_PAD_EIM_DA15__GPIO3_15 709 +MX53_PAD_EIM_DA15__IPU_DI1_PIN1 710 +MX53_PAD_EIM_DA15__IPU_DI1_PIN4 711 +MX53_PAD_NANDF_WE_B__EMI_NANDF_WE_B 712 +MX53_PAD_NANDF_WE_B__GPIO6_12 713 +MX53_PAD_NANDF_RE_B__EMI_NANDF_RE_B 714 +MX53_PAD_NANDF_RE_B__GPIO6_13 715 +MX53_PAD_EIM_WAIT__EMI_WEIM_WAIT 716 +MX53_PAD_EIM_WAIT__GPIO5_0 717 +MX53_PAD_EIM_WAIT__EMI_WEIM_DTACK_B 718 +MX53_PAD_LVDS1_TX3_P__GPIO6_22 719 +MX53_PAD_LVDS1_TX3_P__LDB_LVDS1_TX3 720 +MX53_PAD_LVDS1_TX2_P__GPIO6_24 721 +MX53_PAD_LVDS1_TX2_P__LDB_LVDS1_TX2 722 +MX53_PAD_LVDS1_CLK_P__GPIO6_26 723 +MX53_PAD_LVDS1_CLK_P__LDB_LVDS1_CLK 724 +MX53_PAD_LVDS1_TX1_P__GPIO6_28 725 +MX53_PAD_LVDS1_TX1_P__LDB_LVDS1_TX1 726 +MX53_PAD_LVDS1_TX0_P__GPIO6_30 727 +MX53_PAD_LVDS1_TX0_P__LDB_LVDS1_TX0 728 +MX53_PAD_LVDS0_TX3_P__GPIO7_22 729 +MX53_PAD_LVDS0_TX3_P__LDB_LVDS0_TX3 730 +MX53_PAD_LVDS0_CLK_P__GPIO7_24 731 +MX53_PAD_LVDS0_CLK_P__LDB_LVDS0_CLK 732 +MX53_PAD_LVDS0_TX2_P__GPIO7_26 733 +MX53_PAD_LVDS0_TX2_P__LDB_LVDS0_TX2 734 +MX53_PAD_LVDS0_TX1_P__GPIO7_28 735 +MX53_PAD_LVDS0_TX1_P__LDB_LVDS0_TX1 736 +MX53_PAD_LVDS0_TX0_P__GPIO7_30 737 +MX53_PAD_LVDS0_TX0_P__LDB_LVDS0_TX0 738 +MX53_PAD_GPIO_10__GPIO4_0 739 +MX53_PAD_GPIO_10__OSC32k_32K_OUT 740 +MX53_PAD_GPIO_11__GPIO4_1 741 +MX53_PAD_GPIO_12__GPIO4_2 742 +MX53_PAD_GPIO_13__GPIO4_3 743 +MX53_PAD_GPIO_14__GPIO4_4 744 +MX53_PAD_NANDF_CLE__EMI_NANDF_CLE 745 +MX53_PAD_NANDF_CLE__GPIO6_7 746 +MX53_PAD_NANDF_CLE__USBPHY1_VSTATUS_0 747 +MX53_PAD_NANDF_ALE__EMI_NANDF_ALE 748 +MX53_PAD_NANDF_ALE__GPIO6_8 749 +MX53_PAD_NANDF_ALE__USBPHY1_VSTATUS_1 750 +MX53_PAD_NANDF_WP_B__EMI_NANDF_WP_B 751 +MX53_PAD_NANDF_WP_B__GPIO6_9 752 +MX53_PAD_NANDF_WP_B__USBPHY1_VSTATUS_2 753 +MX53_PAD_NANDF_RB0__EMI_NANDF_RB_0 754 +MX53_PAD_NANDF_RB0__GPIO6_10 755 +MX53_PAD_NANDF_RB0__USBPHY1_VSTATUS_3 756 +MX53_PAD_NANDF_CS0__EMI_NANDF_CS_0 757 +MX53_PAD_NANDF_CS0__GPIO6_11 758 +MX53_PAD_NANDF_CS0__USBPHY1_VSTATUS_4 759 +MX53_PAD_NANDF_CS1__EMI_NANDF_CS_1 760 +MX53_PAD_NANDF_CS1__GPIO6_14 761 +MX53_PAD_NANDF_CS1__MLB_MLBCLK 762 +MX53_PAD_NANDF_CS1__USBPHY1_VSTATUS_5 763 +MX53_PAD_NANDF_CS2__EMI_NANDF_CS_2 764 +MX53_PAD_NANDF_CS2__GPIO6_15 765 +MX53_PAD_NANDF_CS2__IPU_SISG_0 766 +MX53_PAD_NANDF_CS2__ESAI1_TX0 767 +MX53_PAD_NANDF_CS2__EMI_WEIM_CRE 768 +MX53_PAD_NANDF_CS2__CCM_CSI0_MCLK 769 +MX53_PAD_NANDF_CS2__MLB_MLBSIG 770 +MX53_PAD_NANDF_CS2__USBPHY1_VSTATUS_6 771 +MX53_PAD_NANDF_CS3__EMI_NANDF_CS_3 772 +MX53_PAD_NANDF_CS3__GPIO6_16 773 +MX53_PAD_NANDF_CS3__IPU_SISG_1 774 +MX53_PAD_NANDF_CS3__ESAI1_TX1 775 +MX53_PAD_NANDF_CS3__EMI_WEIM_A_26 776 +MX53_PAD_NANDF_CS3__MLB_MLBDAT 777 +MX53_PAD_NANDF_CS3__USBPHY1_VSTATUS_7 778 +MX53_PAD_FEC_MDIO__FEC_MDIO 779 +MX53_PAD_FEC_MDIO__GPIO1_22 780 +MX53_PAD_FEC_MDIO__ESAI1_SCKR 781 +MX53_PAD_FEC_MDIO__FEC_COL 782 +MX53_PAD_FEC_MDIO__RTC_CE_RTC_PS2 783 +MX53_PAD_FEC_MDIO__SDMA_DEBUG_BUS_DEVICE_3 784 +MX53_PAD_FEC_MDIO__EMI_EMI_DEBUG_49 785 +MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 786 +MX53_PAD_FEC_REF_CLK__GPIO1_23 787 +MX53_PAD_FEC_REF_CLK__ESAI1_FSR 788 +MX53_PAD_FEC_REF_CLK__SDMA_DEBUG_BUS_DEVICE_4 789 +MX53_PAD_FEC_REF_CLK__EMI_EMI_DEBUG_50 790 +MX53_PAD_FEC_RX_ER__FEC_RX_ER 791 +MX53_PAD_FEC_RX_ER__GPIO1_24 792 +MX53_PAD_FEC_RX_ER__ESAI1_HCKR 793 +MX53_PAD_FEC_RX_ER__FEC_RX_CLK 794 +MX53_PAD_FEC_RX_ER__RTC_CE_RTC_PS3 795 +MX53_PAD_FEC_CRS_DV__FEC_RX_DV 796 +MX53_PAD_FEC_CRS_DV__GPIO1_25 797 +MX53_PAD_FEC_CRS_DV__ESAI1_SCKT 798 +MX53_PAD_FEC_RXD1__FEC_RDATA_1 799 +MX53_PAD_FEC_RXD1__GPIO1_26 800 +MX53_PAD_FEC_RXD1__ESAI1_FST 801 +MX53_PAD_FEC_RXD1__MLB_MLBSIG 802 +MX53_PAD_FEC_RXD1__RTC_CE_RTC_PS1 803 +MX53_PAD_FEC_RXD0__FEC_RDATA_0 804 +MX53_PAD_FEC_RXD0__GPIO1_27 805 +MX53_PAD_FEC_RXD0__ESAI1_HCKT 806 +MX53_PAD_FEC_RXD0__OSC32k_32K_OUT 807 +MX53_PAD_FEC_TX_EN__FEC_TX_EN 808 +MX53_PAD_FEC_TX_EN__GPIO1_28 809 +MX53_PAD_FEC_TX_EN__ESAI1_TX3_RX2 810 +MX53_PAD_FEC_TXD1__FEC_TDATA_1 811 +MX53_PAD_FEC_TXD1__GPIO1_29 812 +MX53_PAD_FEC_TXD1__ESAI1_TX2_RX3 813 +MX53_PAD_FEC_TXD1__MLB_MLBCLK 814 +MX53_PAD_FEC_TXD1__RTC_CE_RTC_PRSC_CLK 815 +MX53_PAD_FEC_TXD0__FEC_TDATA_0 816 +MX53_PAD_FEC_TXD0__GPIO1_30 817 +MX53_PAD_FEC_TXD0__ESAI1_TX4_RX1 818 +MX53_PAD_FEC_TXD0__USBPHY2_DATAOUT_0 819 +MX53_PAD_FEC_MDC__FEC_MDC 820 +MX53_PAD_FEC_MDC__GPIO1_31 821 +MX53_PAD_FEC_MDC__ESAI1_TX5_RX0 822 +MX53_PAD_FEC_MDC__MLB_MLBDAT 823 +MX53_PAD_FEC_MDC__RTC_CE_RTC_ALARM1_TRIG 824 +MX53_PAD_FEC_MDC__USBPHY2_DATAOUT_1 825 +MX53_PAD_PATA_DIOW__PATA_DIOW 826 +MX53_PAD_PATA_DIOW__GPIO6_17 827 +MX53_PAD_PATA_DIOW__UART1_TXD_MUX 828 +MX53_PAD_PATA_DIOW__USBPHY2_DATAOUT_2 829 +MX53_PAD_PATA_DMACK__PATA_DMACK 830 +MX53_PAD_PATA_DMACK__GPIO6_18 831 +MX53_PAD_PATA_DMACK__UART1_RXD_MUX 832 +MX53_PAD_PATA_DMACK__USBPHY2_DATAOUT_3 833 +MX53_PAD_PATA_DMARQ__PATA_DMARQ 834 +MX53_PAD_PATA_DMARQ__GPIO7_0 835 +MX53_PAD_PATA_DMARQ__UART2_TXD_MUX 836 +MX53_PAD_PATA_DMARQ__CCM_CCM_OUT_0 837 +MX53_PAD_PATA_DMARQ__USBPHY2_DATAOUT_4 838 +MX53_PAD_PATA_BUFFER_EN__PATA_BUFFER_EN 839 +MX53_PAD_PATA_BUFFER_EN__GPIO7_1 840 +MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX 841 +MX53_PAD_PATA_BUFFER_EN__CCM_CCM_OUT_1 842 +MX53_PAD_PATA_BUFFER_EN__USBPHY2_DATAOUT_5 843 +MX53_PAD_PATA_INTRQ__PATA_INTRQ 844 +MX53_PAD_PATA_INTRQ__GPIO7_2 845 +MX53_PAD_PATA_INTRQ__UART2_CTS 846 +MX53_PAD_PATA_INTRQ__CAN1_TXCAN 847 +MX53_PAD_PATA_INTRQ__CCM_CCM_OUT_2 848 +MX53_PAD_PATA_INTRQ__USBPHY2_DATAOUT_6 849 +MX53_PAD_PATA_DIOR__PATA_DIOR 850 +MX53_PAD_PATA_DIOR__GPIO7_3 851 +MX53_PAD_PATA_DIOR__UART2_RTS 852 +MX53_PAD_PATA_DIOR__CAN1_RXCAN 853 +MX53_PAD_PATA_DIOR__USBPHY2_DATAOUT_7 854 +MX53_PAD_PATA_RESET_B__PATA_PATA_RESET_B 855 +MX53_PAD_PATA_RESET_B__GPIO7_4 856 +MX53_PAD_PATA_RESET_B__ESDHC3_CMD 857 +MX53_PAD_PATA_RESET_B__UART1_CTS 858 +MX53_PAD_PATA_RESET_B__CAN2_TXCAN 859 +MX53_PAD_PATA_RESET_B__USBPHY1_DATAOUT_0 860 +MX53_PAD_PATA_IORDY__PATA_IORDY 861 +MX53_PAD_PATA_IORDY__GPIO7_5 862 +MX53_PAD_PATA_IORDY__ESDHC3_CLK 863 +MX53_PAD_PATA_IORDY__UART1_RTS 864 +MX53_PAD_PATA_IORDY__CAN2_RXCAN 865 +MX53_PAD_PATA_IORDY__USBPHY1_DATAOUT_1 866 +MX53_PAD_PATA_DA_0__PATA_DA_0 867 +MX53_PAD_PATA_DA_0__GPIO7_6 868 +MX53_PAD_PATA_DA_0__ESDHC3_RST 869 +MX53_PAD_PATA_DA_0__OWIRE_LINE 870 +MX53_PAD_PATA_DA_0__USBPHY1_DATAOUT_2 871 +MX53_PAD_PATA_DA_1__PATA_DA_1 872 +MX53_PAD_PATA_DA_1__GPIO7_7 873 +MX53_PAD_PATA_DA_1__ESDHC4_CMD 874 +MX53_PAD_PATA_DA_1__UART3_CTS 875 +MX53_PAD_PATA_DA_1__USBPHY1_DATAOUT_3 876 +MX53_PAD_PATA_DA_2__PATA_DA_2 877 +MX53_PAD_PATA_DA_2__GPIO7_8 878 +MX53_PAD_PATA_DA_2__ESDHC4_CLK 879 +MX53_PAD_PATA_DA_2__UART3_RTS 880 +MX53_PAD_PATA_DA_2__USBPHY1_DATAOUT_4 881 +MX53_PAD_PATA_CS_0__PATA_CS_0 882 +MX53_PAD_PATA_CS_0__GPIO7_9 883 +MX53_PAD_PATA_CS_0__UART3_TXD_MUX 884 +MX53_PAD_PATA_CS_0__USBPHY1_DATAOUT_5 885 +MX53_PAD_PATA_CS_1__PATA_CS_1 886 +MX53_PAD_PATA_CS_1__GPIO7_10 887 +MX53_PAD_PATA_CS_1__UART3_RXD_MUX 888 +MX53_PAD_PATA_CS_1__USBPHY1_DATAOUT_6 889 +MX53_PAD_PATA_DATA0__PATA_DATA_0 890 +MX53_PAD_PATA_DATA0__GPIO2_0 891 +MX53_PAD_PATA_DATA0__EMI_NANDF_D_0 892 +MX53_PAD_PATA_DATA0__ESDHC3_DAT4 893 +MX53_PAD_PATA_DATA0__GPU3d_GPU_DEBUG_OUT_0 894 +MX53_PAD_PATA_DATA0__IPU_DIAG_BUS_0 895 +MX53_PAD_PATA_DATA0__USBPHY1_DATAOUT_7 896 +MX53_PAD_PATA_DATA1__PATA_DATA_1 897 +MX53_PAD_PATA_DATA1__GPIO2_1 898 +MX53_PAD_PATA_DATA1__EMI_NANDF_D_1 899 +MX53_PAD_PATA_DATA1__ESDHC3_DAT5 900 +MX53_PAD_PATA_DATA1__GPU3d_GPU_DEBUG_OUT_1 901 +MX53_PAD_PATA_DATA1__IPU_DIAG_BUS_1 902 +MX53_PAD_PATA_DATA2__PATA_DATA_2 903 +MX53_PAD_PATA_DATA2__GPIO2_2 904 +MX53_PAD_PATA_DATA2__EMI_NANDF_D_2 905 +MX53_PAD_PATA_DATA2__ESDHC3_DAT6 906 +MX53_PAD_PATA_DATA2__GPU3d_GPU_DEBUG_OUT_2 907 +MX53_PAD_PATA_DATA2__IPU_DIAG_BUS_2 908 +MX53_PAD_PATA_DATA3__PATA_DATA_3 909 +MX53_PAD_PATA_DATA3__GPIO2_3 910 +MX53_PAD_PATA_DATA3__EMI_NANDF_D_3 911 +MX53_PAD_PATA_DATA3__ESDHC3_DAT7 912 +MX53_PAD_PATA_DATA3__GPU3d_GPU_DEBUG_OUT_3 913 +MX53_PAD_PATA_DATA3__IPU_DIAG_BUS_3 914 +MX53_PAD_PATA_DATA4__PATA_DATA_4 915 +MX53_PAD_PATA_DATA4__GPIO2_4 916 +MX53_PAD_PATA_DATA4__EMI_NANDF_D_4 917 +MX53_PAD_PATA_DATA4__ESDHC4_DAT4 918 +MX53_PAD_PATA_DATA4__GPU3d_GPU_DEBUG_OUT_4 919 +MX53_PAD_PATA_DATA4__IPU_DIAG_BUS_4 920 +MX53_PAD_PATA_DATA5__PATA_DATA_5 921 +MX53_PAD_PATA_DATA5__GPIO2_5 922 +MX53_PAD_PATA_DATA5__EMI_NANDF_D_5 923 +MX53_PAD_PATA_DATA5__ESDHC4_DAT5 924 +MX53_PAD_PATA_DATA5__GPU3d_GPU_DEBUG_OUT_5 925 +MX53_PAD_PATA_DATA5__IPU_DIAG_BUS_5 926 +MX53_PAD_PATA_DATA6__PATA_DATA_6 927 +MX53_PAD_PATA_DATA6__GPIO2_6 928 +MX53_PAD_PATA_DATA6__EMI_NANDF_D_6 929 +MX53_PAD_PATA_DATA6__ESDHC4_DAT6 930 +MX53_PAD_PATA_DATA6__GPU3d_GPU_DEBUG_OUT_6 931 +MX53_PAD_PATA_DATA6__IPU_DIAG_BUS_6 932 +MX53_PAD_PATA_DATA7__PATA_DATA_7 933 +MX53_PAD_PATA_DATA7__GPIO2_7 934 +MX53_PAD_PATA_DATA7__EMI_NANDF_D_7 935 +MX53_PAD_PATA_DATA7__ESDHC4_DAT7 936 +MX53_PAD_PATA_DATA7__GPU3d_GPU_DEBUG_OUT_7 937 +MX53_PAD_PATA_DATA7__IPU_DIAG_BUS_7 938 +MX53_PAD_PATA_DATA8__PATA_DATA_8 939 +MX53_PAD_PATA_DATA8__GPIO2_8 940 +MX53_PAD_PATA_DATA8__ESDHC1_DAT4 941 +MX53_PAD_PATA_DATA8__EMI_NANDF_D_8 942 +MX53_PAD_PATA_DATA8__ESDHC3_DAT0 943 +MX53_PAD_PATA_DATA8__GPU3d_GPU_DEBUG_OUT_8 944 +MX53_PAD_PATA_DATA8__IPU_DIAG_BUS_8 945 +MX53_PAD_PATA_DATA9__PATA_DATA_9 946 +MX53_PAD_PATA_DATA9__GPIO2_9 947 +MX53_PAD_PATA_DATA9__ESDHC1_DAT5 948 +MX53_PAD_PATA_DATA9__EMI_NANDF_D_9 949 +MX53_PAD_PATA_DATA9__ESDHC3_DAT1 950 +MX53_PAD_PATA_DATA9__GPU3d_GPU_DEBUG_OUT_9 951 +MX53_PAD_PATA_DATA9__IPU_DIAG_BUS_9 952 +MX53_PAD_PATA_DATA10__PATA_DATA_10 953 +MX53_PAD_PATA_DATA10__GPIO2_10 954 +MX53_PAD_PATA_DATA10__ESDHC1_DAT6 955 +MX53_PAD_PATA_DATA10__EMI_NANDF_D_10 956 +MX53_PAD_PATA_DATA10__ESDHC3_DAT2 957 +MX53_PAD_PATA_DATA10__GPU3d_GPU_DEBUG_OUT_10 958 +MX53_PAD_PATA_DATA10__IPU_DIAG_BUS_10 959 +MX53_PAD_PATA_DATA11__PATA_DATA_11 960 +MX53_PAD_PATA_DATA11__GPIO2_11 961 +MX53_PAD_PATA_DATA11__ESDHC1_DAT7 962 +MX53_PAD_PATA_DATA11__EMI_NANDF_D_11 963 +MX53_PAD_PATA_DATA11__ESDHC3_DAT3 964 +MX53_PAD_PATA_DATA11__GPU3d_GPU_DEBUG_OUT_11 965 +MX53_PAD_PATA_DATA11__IPU_DIAG_BUS_11 966 +MX53_PAD_PATA_DATA12__PATA_DATA_12 967 +MX53_PAD_PATA_DATA12__GPIO2_12 968 +MX53_PAD_PATA_DATA12__ESDHC2_DAT4 969 +MX53_PAD_PATA_DATA12__EMI_NANDF_D_12 970 +MX53_PAD_PATA_DATA12__ESDHC4_DAT0 971 +MX53_PAD_PATA_DATA12__GPU3d_GPU_DEBUG_OUT_12 972 +MX53_PAD_PATA_DATA12__IPU_DIAG_BUS_12 973 +MX53_PAD_PATA_DATA13__PATA_DATA_13 974 +MX53_PAD_PATA_DATA13__GPIO2_13 975 +MX53_PAD_PATA_DATA13__ESDHC2_DAT5 976 +MX53_PAD_PATA_DATA13__EMI_NANDF_D_13 977 +MX53_PAD_PATA_DATA13__ESDHC4_DAT1 978 +MX53_PAD_PATA_DATA13__GPU3d_GPU_DEBUG_OUT_13 979 +MX53_PAD_PATA_DATA13__IPU_DIAG_BUS_13 980 +MX53_PAD_PATA_DATA14__PATA_DATA_14 981 +MX53_PAD_PATA_DATA14__GPIO2_14 982 +MX53_PAD_PATA_DATA14__ESDHC2_DAT6 983 +MX53_PAD_PATA_DATA14__EMI_NANDF_D_14 984 +MX53_PAD_PATA_DATA14__ESDHC4_DAT2 985 +MX53_PAD_PATA_DATA14__GPU3d_GPU_DEBUG_OUT_14 986 +MX53_PAD_PATA_DATA14__IPU_DIAG_BUS_14 987 +MX53_PAD_PATA_DATA15__PATA_DATA_15 988 +MX53_PAD_PATA_DATA15__GPIO2_15 989 +MX53_PAD_PATA_DATA15__ESDHC2_DAT7 990 +MX53_PAD_PATA_DATA15__EMI_NANDF_D_15 991 +MX53_PAD_PATA_DATA15__ESDHC4_DAT3 992 +MX53_PAD_PATA_DATA15__GPU3d_GPU_DEBUG_OUT_15 993 +MX53_PAD_PATA_DATA15__IPU_DIAG_BUS_15 994 +MX53_PAD_SD1_DATA0__ESDHC1_DAT0 995 +MX53_PAD_SD1_DATA0__GPIO1_16 996 +MX53_PAD_SD1_DATA0__GPT_CAPIN1 997 +MX53_PAD_SD1_DATA0__CSPI_MISO 998 +MX53_PAD_SD1_DATA0__CCM_PLL3_BYP 999 +MX53_PAD_SD1_DATA1__ESDHC1_DAT1 1000 +MX53_PAD_SD1_DATA1__GPIO1_17 1001 +MX53_PAD_SD1_DATA1__GPT_CAPIN2 1002 +MX53_PAD_SD1_DATA1__CSPI_SS0 1003 +MX53_PAD_SD1_DATA1__CCM_PLL4_BYP 1004 +MX53_PAD_SD1_CMD__ESDHC1_CMD 1005 +MX53_PAD_SD1_CMD__GPIO1_18 1006 +MX53_PAD_SD1_CMD__GPT_CMPOUT1 1007 +MX53_PAD_SD1_CMD__CSPI_MOSI 1008 +MX53_PAD_SD1_CMD__CCM_PLL1_BYP 1009 +MX53_PAD_SD1_DATA2__ESDHC1_DAT2 1010 +MX53_PAD_SD1_DATA2__GPIO1_19 1011 +MX53_PAD_SD1_DATA2__GPT_CMPOUT2 1012 +MX53_PAD_SD1_DATA2__PWM2_PWMO 1013 +MX53_PAD_SD1_DATA2__WDOG1_WDOG_B 1014 +MX53_PAD_SD1_DATA2__CSPI_SS1 1015 +MX53_PAD_SD1_DATA2__WDOG1_WDOG_RST_B_DEB 1016 +MX53_PAD_SD1_DATA2__CCM_PLL2_BYP 1017 +MX53_PAD_SD1_CLK__ESDHC1_CLK 1018 +MX53_PAD_SD1_CLK__GPIO1_20 1019 +MX53_PAD_SD1_CLK__OSC32k_32K_OUT 1020 +MX53_PAD_SD1_CLK__GPT_CLKIN 1021 +MX53_PAD_SD1_CLK__CSPI_SCLK 1022 +MX53_PAD_SD1_CLK__SATA_PHY_DTB_0 1023 +MX53_PAD_SD1_DATA3__ESDHC1_DAT3 1024 +MX53_PAD_SD1_DATA3__GPIO1_21 1025 +MX53_PAD_SD1_DATA3__GPT_CMPOUT3 1026 +MX53_PAD_SD1_DATA3__PWM1_PWMO 1027 +MX53_PAD_SD1_DATA3__WDOG2_WDOG_B 1028 +MX53_PAD_SD1_DATA3__CSPI_SS2 1029 +MX53_PAD_SD1_DATA3__WDOG2_WDOG_RST_B_DEB 1030 +MX53_PAD_SD1_DATA3__SATA_PHY_DTB_1 1031 +MX53_PAD_SD2_CLK__ESDHC2_CLK 1032 +MX53_PAD_SD2_CLK__GPIO1_10 1033 +MX53_PAD_SD2_CLK__KPP_COL_5 1034 +MX53_PAD_SD2_CLK__AUDMUX_AUD4_RXFS 1035 +MX53_PAD_SD2_CLK__CSPI_SCLK 1036 +MX53_PAD_SD2_CLK__SCC_RANDOM_V 1037 +MX53_PAD_SD2_CMD__ESDHC2_CMD 1038 +MX53_PAD_SD2_CMD__GPIO1_11 1039 +MX53_PAD_SD2_CMD__KPP_ROW_5 1040 +MX53_PAD_SD2_CMD__AUDMUX_AUD4_RXC 1041 +MX53_PAD_SD2_CMD__CSPI_MOSI 1042 +MX53_PAD_SD2_CMD__SCC_RANDOM 1043 +MX53_PAD_SD2_DATA3__ESDHC2_DAT3 1044 +MX53_PAD_SD2_DATA3__GPIO1_12 1045 +MX53_PAD_SD2_DATA3__KPP_COL_6 1046 +MX53_PAD_SD2_DATA3__AUDMUX_AUD4_TXC 1047 +MX53_PAD_SD2_DATA3__CSPI_SS2 1048 +MX53_PAD_SD2_DATA3__SJC_DONE 1049 +MX53_PAD_SD2_DATA2__ESDHC2_DAT2 1050 +MX53_PAD_SD2_DATA2__GPIO1_13 1051 +MX53_PAD_SD2_DATA2__KPP_ROW_6 1052 +MX53_PAD_SD2_DATA2__AUDMUX_AUD4_TXD 1053 +MX53_PAD_SD2_DATA2__CSPI_SS1 1054 +MX53_PAD_SD2_DATA2__SJC_FAIL 1055 +MX53_PAD_SD2_DATA1__ESDHC2_DAT1 1056 +MX53_PAD_SD2_DATA1__GPIO1_14 1057 +MX53_PAD_SD2_DATA1__KPP_COL_7 1058 +MX53_PAD_SD2_DATA1__AUDMUX_AUD4_TXFS 1059 +MX53_PAD_SD2_DATA1__CSPI_SS0 1060 +MX53_PAD_SD2_DATA1__RTIC_SEC_VIO 1061 +MX53_PAD_SD2_DATA0__ESDHC2_DAT0 1062 +MX53_PAD_SD2_DATA0__GPIO1_15 1063 +MX53_PAD_SD2_DATA0__KPP_ROW_7 1064 +MX53_PAD_SD2_DATA0__AUDMUX_AUD4_RXD 1065 +MX53_PAD_SD2_DATA0__CSPI_MISO 1066 +MX53_PAD_SD2_DATA0__RTIC_DONE_INT 1067 +MX53_PAD_GPIO_0__CCM_CLKO 1068 +MX53_PAD_GPIO_0__GPIO1_0 1069 +MX53_PAD_GPIO_0__KPP_COL_5 1070 +MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK 1071 +MX53_PAD_GPIO_0__EPIT1_EPITO 1072 +MX53_PAD_GPIO_0__SRTC_ALARM_DEB 1073 +MX53_PAD_GPIO_0__USBOH3_USBH1_PWR 1074 +MX53_PAD_GPIO_0__CSU_TD 1075 +MX53_PAD_GPIO_1__ESAI1_SCKR 1076 +MX53_PAD_GPIO_1__GPIO1_1 1077 +MX53_PAD_GPIO_1__KPP_ROW_5 1078 +MX53_PAD_GPIO_1__CCM_SSI_EXT2_CLK 1079 +MX53_PAD_GPIO_1__PWM2_PWMO 1080 +MX53_PAD_GPIO_1__WDOG2_WDOG_B 1081 +MX53_PAD_GPIO_1__ESDHC1_CD 1082 +MX53_PAD_GPIO_1__SRC_TESTER_ACK 1083 +MX53_PAD_GPIO_9__ESAI1_FSR 1084 +MX53_PAD_GPIO_9__GPIO1_9 1085 +MX53_PAD_GPIO_9__KPP_COL_6 1086 +MX53_PAD_GPIO_9__CCM_REF_EN_B 1087 +MX53_PAD_GPIO_9__PWM1_PWMO 1088 +MX53_PAD_GPIO_9__WDOG1_WDOG_B 1089 +MX53_PAD_GPIO_9__ESDHC1_WP 1090 +MX53_PAD_GPIO_9__SCC_FAIL_STATE 1091 +MX53_PAD_GPIO_3__ESAI1_HCKR 1092 +MX53_PAD_GPIO_3__GPIO1_3 1093 +MX53_PAD_GPIO_3__I2C3_SCL 1094 +MX53_PAD_GPIO_3__DPLLIP1_TOG_EN 1095 +MX53_PAD_GPIO_3__CCM_CLKO2 1096 +MX53_PAD_GPIO_3__OBSERVE_MUX_OBSRV_INT_OUT0 1097 +MX53_PAD_GPIO_3__USBOH3_USBH1_OC 1098 +MX53_PAD_GPIO_3__MLB_MLBCLK 1099 +MX53_PAD_GPIO_6__ESAI1_SCKT 1100 +MX53_PAD_GPIO_6__GPIO1_6 1101 +MX53_PAD_GPIO_6__I2C3_SDA 1102 +MX53_PAD_GPIO_6__CCM_CCM_OUT_0 1103 +MX53_PAD_GPIO_6__CSU_CSU_INT_DEB 1104 +MX53_PAD_GPIO_6__OBSERVE_MUX_OBSRV_INT_OUT1 1105 +MX53_PAD_GPIO_6__ESDHC2_LCTL 1106 +MX53_PAD_GPIO_6__MLB_MLBSIG 1107 +MX53_PAD_GPIO_2__ESAI1_FST 1108 +MX53_PAD_GPIO_2__GPIO1_2 1109 +MX53_PAD_GPIO_2__KPP_ROW_6 1110 +MX53_PAD_GPIO_2__CCM_CCM_OUT_1 1111 +MX53_PAD_GPIO_2__CSU_CSU_ALARM_AUT_0 1112 +MX53_PAD_GPIO_2__OBSERVE_MUX_OBSRV_INT_OUT2 1113 +MX53_PAD_GPIO_2__ESDHC2_WP 1114 +MX53_PAD_GPIO_2__MLB_MLBDAT 1115 +MX53_PAD_GPIO_4__ESAI1_HCKT 1116 +MX53_PAD_GPIO_4__GPIO1_4 1117 +MX53_PAD_GPIO_4__KPP_COL_7 1118 +MX53_PAD_GPIO_4__CCM_CCM_OUT_2 1119 +MX53_PAD_GPIO_4__CSU_CSU_ALARM_AUT_1 1120 +MX53_PAD_GPIO_4__OBSERVE_MUX_OBSRV_INT_OUT3 1121 +MX53_PAD_GPIO_4__ESDHC2_CD 1122 +MX53_PAD_GPIO_4__SCC_SEC_STATE 1123 +MX53_PAD_GPIO_5__ESAI1_TX2_RX3 1124 +MX53_PAD_GPIO_5__GPIO1_5 1125 +MX53_PAD_GPIO_5__KPP_ROW_7 1126 +MX53_PAD_GPIO_5__CCM_CLKO 1127 +MX53_PAD_GPIO_5__CSU_CSU_ALARM_AUT_2 1128 +MX53_PAD_GPIO_5__OBSERVE_MUX_OBSRV_INT_OUT4 1129 +MX53_PAD_GPIO_5__I2C3_SCL 1130 +MX53_PAD_GPIO_5__CCM_PLL1_BYP 1131 +MX53_PAD_GPIO_7__ESAI1_TX4_RX1 1132 +MX53_PAD_GPIO_7__GPIO1_7 1133 +MX53_PAD_GPIO_7__EPIT1_EPITO 1134 +MX53_PAD_GPIO_7__CAN1_TXCAN 1135 +MX53_PAD_GPIO_7__UART2_TXD_MUX 1136 +MX53_PAD_GPIO_7__FIRI_RXD 1137 +MX53_PAD_GPIO_7__SPDIF_PLOCK 1138 +MX53_PAD_GPIO_7__CCM_PLL2_BYP 1139 +MX53_PAD_GPIO_8__ESAI1_TX5_RX0 1140 +MX53_PAD_GPIO_8__GPIO1_8 1141 +MX53_PAD_GPIO_8__EPIT2_EPITO 1142 +MX53_PAD_GPIO_8__CAN1_RXCAN 1143 +MX53_PAD_GPIO_8__UART2_RXD_MUX 1144 +MX53_PAD_GPIO_8__FIRI_TXD 1145 +MX53_PAD_GPIO_8__SPDIF_SRCLK 1146 +MX53_PAD_GPIO_8__CCM_PLL3_BYP 1147 +MX53_PAD_GPIO_16__ESAI1_TX3_RX2 1148 +MX53_PAD_GPIO_16__GPIO7_11 1149 +MX53_PAD_GPIO_16__TZIC_PWRFAIL_INT 1150 +MX53_PAD_GPIO_16__RTC_CE_RTC_EXT_TRIG1 1151 +MX53_PAD_GPIO_16__SPDIF_IN1 1152 +MX53_PAD_GPIO_16__I2C3_SDA 1153 +MX53_PAD_GPIO_16__SJC_DE_B 1154 +MX53_PAD_GPIO_17__ESAI1_TX0 1155 +MX53_PAD_GPIO_17__GPIO7_12 1156 +MX53_PAD_GPIO_17__SDMA_EXT_EVENT_0 1157 +MX53_PAD_GPIO_17__GPC_PMIC_RDY 1158 +MX53_PAD_GPIO_17__RTC_CE_RTC_FSV_TRIG 1159 +MX53_PAD_GPIO_17__SPDIF_OUT1 1160 +MX53_PAD_GPIO_17__IPU_SNOOP2 1161 +MX53_PAD_GPIO_17__SJC_JTAG_ACT 1162 +MX53_PAD_GPIO_18__ESAI1_TX1 1163 +MX53_PAD_GPIO_18__GPIO7_13 1164 +MX53_PAD_GPIO_18__SDMA_EXT_EVENT_1 1165 +MX53_PAD_GPIO_18__OWIRE_LINE 1166 +MX53_PAD_GPIO_18__RTC_CE_RTC_ALARM2_TRIG 1167 +MX53_PAD_GPIO_18__CCM_ASRC_EXT_CLK 1168 +MX53_PAD_GPIO_18__ESDHC1_LCTL 1169 +MX53_PAD_GPIO_18__SRC_SYSTEM_RST 1170 diff --git a/trunk/Documentation/devicetree/bindings/pinctrl/fsl,imx6q-pinctrl.txt b/trunk/Documentation/devicetree/bindings/pinctrl/fsl,imx6q-pinctrl.txt new file mode 100644 index 000000000000..82b43f915857 --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/pinctrl/fsl,imx6q-pinctrl.txt @@ -0,0 +1,1628 @@ +* Freescale IMX6Q IOMUX Controller + +Please refer to fsl,imx-pinctrl.txt in this directory for common binding part +and usage. + +Required properties: +- compatible: "fsl,imx6q-iomuxc" +- fsl,pins: two integers array, represents a group of pins mux and config + setting. The format is fsl,pins = , PIN_FUNC_ID is a + pin working on a specific function, CONFIG is the pad setting value like + pull-up for this pin. Please refer to imx6q datasheet for the valid pad + config settings. + +CONFIG bits definition: +PAD_CTL_HYS (1 << 16) +PAD_CTL_PUS_100K_DOWN (0 << 14) +PAD_CTL_PUS_47K_UP (1 << 14) +PAD_CTL_PUS_100K_UP (2 << 14) +PAD_CTL_PUS_22K_UP (3 << 14) +PAD_CTL_PUE (1 << 13) +PAD_CTL_PKE (1 << 12) +PAD_CTL_ODE (1 << 11) +PAD_CTL_SPEED_LOW (1 << 6) +PAD_CTL_SPEED_MED (2 << 6) +PAD_CTL_SPEED_HIGH (3 << 6) +PAD_CTL_DSE_DISABLE (0 << 3) +PAD_CTL_DSE_240ohm (1 << 3) +PAD_CTL_DSE_120ohm (2 << 3) +PAD_CTL_DSE_80ohm (3 << 3) +PAD_CTL_DSE_60ohm (4 << 3) +PAD_CTL_DSE_48ohm (5 << 3) +PAD_CTL_DSE_40ohm (6 << 3) +PAD_CTL_DSE_34ohm (7 << 3) +PAD_CTL_SRE_FAST (1 << 0) +PAD_CTL_SRE_SLOW (0 << 0) + +See below for available PIN_FUNC_ID for imx6q: +MX6Q_PAD_SD2_DAT1__USDHC2_DAT1 0 +MX6Q_PAD_SD2_DAT1__ECSPI5_SS0 1 +MX6Q_PAD_SD2_DAT1__WEIM_WEIM_CS_2 2 +MX6Q_PAD_SD2_DAT1__AUDMUX_AUD4_TXFS 3 +MX6Q_PAD_SD2_DAT1__KPP_COL_7 4 +MX6Q_PAD_SD2_DAT1__GPIO_1_14 5 +MX6Q_PAD_SD2_DAT1__CCM_WAIT 6 +MX6Q_PAD_SD2_DAT1__ANATOP_TESTO_0 7 +MX6Q_PAD_SD2_DAT2__USDHC2_DAT2 8 +MX6Q_PAD_SD2_DAT2__ECSPI5_SS1 9 +MX6Q_PAD_SD2_DAT2__WEIM_WEIM_CS_3 10 +MX6Q_PAD_SD2_DAT2__AUDMUX_AUD4_TXD 11 +MX6Q_PAD_SD2_DAT2__KPP_ROW_6 12 +MX6Q_PAD_SD2_DAT2__GPIO_1_13 13 +MX6Q_PAD_SD2_DAT2__CCM_STOP 14 +MX6Q_PAD_SD2_DAT2__ANATOP_TESTO_1 15 +MX6Q_PAD_SD2_DAT0__USDHC2_DAT0 16 +MX6Q_PAD_SD2_DAT0__ECSPI5_MISO 17 +MX6Q_PAD_SD2_DAT0__AUDMUX_AUD4_RXD 18 +MX6Q_PAD_SD2_DAT0__KPP_ROW_7 19 +MX6Q_PAD_SD2_DAT0__GPIO_1_15 20 +MX6Q_PAD_SD2_DAT0__DCIC2_DCIC_OUT 21 +MX6Q_PAD_SD2_DAT0__TESTO_2 22 +MX6Q_PAD_RGMII_TXC__USBOH3_H2_DATA 23 +MX6Q_PAD_RGMII_TXC__ENET_RGMII_TXC 24 +MX6Q_PAD_RGMII_TXC__SPDIF_SPDIF_EXTCLK 25 +MX6Q_PAD_RGMII_TXC__GPIO_6_19 26 +MX6Q_PAD_RGMII_TXC__MIPI_CORE_DPHY_IN_0 27 +MX6Q_PAD_RGMII_TXC__ANATOP_24M_OUT 28 +MX6Q_PAD_RGMII_TD0__MIPI_HSI_CRL_TX_RDY 29 +MX6Q_PAD_RGMII_TD0__ENET_RGMII_TD0 30 +MX6Q_PAD_RGMII_TD0__GPIO_6_20 31 +MX6Q_PAD_RGMII_TD0__MIPI_CORE_DPHY_IN_1 32 +MX6Q_PAD_RGMII_TD1__MIPI_HSI_CRL_RX_FLG 33 +MX6Q_PAD_RGMII_TD1__ENET_RGMII_TD1 34 +MX6Q_PAD_RGMII_TD1__GPIO_6_21 35 +MX6Q_PAD_RGMII_TD1__MIPI_CORE_DPHY_IN_2 36 +MX6Q_PAD_RGMII_TD1__CCM_PLL3_BYP 37 +MX6Q_PAD_RGMII_TD2__MIPI_HSI_CRL_RX_DTA 38 +MX6Q_PAD_RGMII_TD2__ENET_RGMII_TD2 39 +MX6Q_PAD_RGMII_TD2__GPIO_6_22 40 +MX6Q_PAD_RGMII_TD2__MIPI_CORE_DPHY_IN_3 41 +MX6Q_PAD_RGMII_TD2__CCM_PLL2_BYP 42 +MX6Q_PAD_RGMII_TD3__MIPI_HSI_CRL_RX_WAK 43 +MX6Q_PAD_RGMII_TD3__ENET_RGMII_TD3 44 +MX6Q_PAD_RGMII_TD3__GPIO_6_23 45 +MX6Q_PAD_RGMII_TD3__MIPI_CORE_DPHY_IN_4 46 +MX6Q_PAD_RGMII_RX_CTL__USBOH3_H3_DATA 47 +MX6Q_PAD_RGMII_RX_CTL__RGMII_RX_CTL 48 +MX6Q_PAD_RGMII_RX_CTL__GPIO_6_24 49 +MX6Q_PAD_RGMII_RX_CTL__MIPI_DPHY_IN_5 50 +MX6Q_PAD_RGMII_RD0__MIPI_HSI_CRL_RX_RDY 51 +MX6Q_PAD_RGMII_RD0__ENET_RGMII_RD0 52 +MX6Q_PAD_RGMII_RD0__GPIO_6_25 53 +MX6Q_PAD_RGMII_RD0__MIPI_CORE_DPHY_IN_6 54 +MX6Q_PAD_RGMII_TX_CTL__USBOH3_H2_STROBE 55 +MX6Q_PAD_RGMII_TX_CTL__RGMII_TX_CTL 56 +MX6Q_PAD_RGMII_TX_CTL__GPIO_6_26 57 +MX6Q_PAD_RGMII_TX_CTL__CORE_DPHY_IN_7 58 +MX6Q_PAD_RGMII_TX_CTL__ANATOP_REF_OUT 59 +MX6Q_PAD_RGMII_RD1__MIPI_HSI_CTRL_TX_FL 60 +MX6Q_PAD_RGMII_RD1__ENET_RGMII_RD1 61 +MX6Q_PAD_RGMII_RD1__GPIO_6_27 62 +MX6Q_PAD_RGMII_RD1__CORE_DPHY_TEST_IN_8 63 +MX6Q_PAD_RGMII_RD1__SJC_FAIL 64 +MX6Q_PAD_RGMII_RD2__MIPI_HSI_CRL_TX_DTA 65 +MX6Q_PAD_RGMII_RD2__ENET_RGMII_RD2 66 +MX6Q_PAD_RGMII_RD2__GPIO_6_28 67 +MX6Q_PAD_RGMII_RD2__MIPI_CORE_DPHY_IN_9 68 +MX6Q_PAD_RGMII_RD3__MIPI_HSI_CRL_TX_WAK 69 +MX6Q_PAD_RGMII_RD3__ENET_RGMII_RD3 70 +MX6Q_PAD_RGMII_RD3__GPIO_6_29 71 +MX6Q_PAD_RGMII_RD3__MIPI_CORE_DPHY_IN10 72 +MX6Q_PAD_RGMII_RXC__USBOH3_H3_STROBE 73 +MX6Q_PAD_RGMII_RXC__ENET_RGMII_RXC 74 +MX6Q_PAD_RGMII_RXC__GPIO_6_30 75 +MX6Q_PAD_RGMII_RXC__MIPI_CORE_DPHY_IN11 76 +MX6Q_PAD_EIM_A25__WEIM_WEIM_A_25 77 +MX6Q_PAD_EIM_A25__ECSPI4_SS1 78 +MX6Q_PAD_EIM_A25__ECSPI2_RDY 79 +MX6Q_PAD_EIM_A25__IPU1_DI1_PIN12 80 +MX6Q_PAD_EIM_A25__IPU1_DI0_D1_CS 81 +MX6Q_PAD_EIM_A25__GPIO_5_2 82 +MX6Q_PAD_EIM_A25__HDMI_TX_CEC_LINE 83 +MX6Q_PAD_EIM_A25__PL301_PER1_HBURST_0 84 +MX6Q_PAD_EIM_EB2__WEIM_WEIM_EB_2 85 +MX6Q_PAD_EIM_EB2__ECSPI1_SS0 86 +MX6Q_PAD_EIM_EB2__CCM_DI1_EXT_CLK 87 +MX6Q_PAD_EIM_EB2__IPU2_CSI1_D_19 88 +MX6Q_PAD_EIM_EB2__HDMI_TX_DDC_SCL 89 +MX6Q_PAD_EIM_EB2__GPIO_2_30 90 +MX6Q_PAD_EIM_EB2__I2C2_SCL 91 +MX6Q_PAD_EIM_EB2__SRC_BT_CFG_30 92 +MX6Q_PAD_EIM_D16__WEIM_WEIM_D_16 93 +MX6Q_PAD_EIM_D16__ECSPI1_SCLK 94 +MX6Q_PAD_EIM_D16__IPU1_DI0_PIN5 95 +MX6Q_PAD_EIM_D16__IPU2_CSI1_D_18 96 +MX6Q_PAD_EIM_D16__HDMI_TX_DDC_SDA 97 +MX6Q_PAD_EIM_D16__GPIO_3_16 98 +MX6Q_PAD_EIM_D16__I2C2_SDA 99 +MX6Q_PAD_EIM_D17__WEIM_WEIM_D_17 100 +MX6Q_PAD_EIM_D17__ECSPI1_MISO 101 +MX6Q_PAD_EIM_D17__IPU1_DI0_PIN6 102 +MX6Q_PAD_EIM_D17__IPU2_CSI1_PIXCLK 103 +MX6Q_PAD_EIM_D17__DCIC1_DCIC_OUT 104 +MX6Q_PAD_EIM_D17__GPIO_3_17 105 +MX6Q_PAD_EIM_D17__I2C3_SCL 106 +MX6Q_PAD_EIM_D17__PL301_PER1_HBURST_1 107 +MX6Q_PAD_EIM_D18__WEIM_WEIM_D_18 108 +MX6Q_PAD_EIM_D18__ECSPI1_MOSI 109 +MX6Q_PAD_EIM_D18__IPU1_DI0_PIN7 110 +MX6Q_PAD_EIM_D18__IPU2_CSI1_D_17 111 +MX6Q_PAD_EIM_D18__IPU1_DI1_D0_CS 112 +MX6Q_PAD_EIM_D18__GPIO_3_18 113 +MX6Q_PAD_EIM_D18__I2C3_SDA 114 +MX6Q_PAD_EIM_D18__PL301_PER1_HBURST_2 115 +MX6Q_PAD_EIM_D19__WEIM_WEIM_D_19 116 +MX6Q_PAD_EIM_D19__ECSPI1_SS1 117 +MX6Q_PAD_EIM_D19__IPU1_DI0_PIN8 118 +MX6Q_PAD_EIM_D19__IPU2_CSI1_D_16 119 +MX6Q_PAD_EIM_D19__UART1_CTS 120 +MX6Q_PAD_EIM_D19__GPIO_3_19 121 +MX6Q_PAD_EIM_D19__EPIT1_EPITO 122 +MX6Q_PAD_EIM_D19__PL301_PER1_HRESP 123 +MX6Q_PAD_EIM_D20__WEIM_WEIM_D_20 124 +MX6Q_PAD_EIM_D20__ECSPI4_SS0 125 +MX6Q_PAD_EIM_D20__IPU1_DI0_PIN16 126 +MX6Q_PAD_EIM_D20__IPU2_CSI1_D_15 127 +MX6Q_PAD_EIM_D20__UART1_RTS 128 +MX6Q_PAD_EIM_D20__GPIO_3_20 129 +MX6Q_PAD_EIM_D20__EPIT2_EPITO 130 +MX6Q_PAD_EIM_D21__WEIM_WEIM_D_21 131 +MX6Q_PAD_EIM_D21__ECSPI4_SCLK 132 +MX6Q_PAD_EIM_D21__IPU1_DI0_PIN17 133 +MX6Q_PAD_EIM_D21__IPU2_CSI1_D_11 134 +MX6Q_PAD_EIM_D21__USBOH3_USBOTG_OC 135 +MX6Q_PAD_EIM_D21__GPIO_3_21 136 +MX6Q_PAD_EIM_D21__I2C1_SCL 137 +MX6Q_PAD_EIM_D21__SPDIF_IN1 138 +MX6Q_PAD_EIM_D22__WEIM_WEIM_D_22 139 +MX6Q_PAD_EIM_D22__ECSPI4_MISO 140 +MX6Q_PAD_EIM_D22__IPU1_DI0_PIN1 141 +MX6Q_PAD_EIM_D22__IPU2_CSI1_D_10 142 +MX6Q_PAD_EIM_D22__USBOH3_USBOTG_PWR 143 +MX6Q_PAD_EIM_D22__GPIO_3_22 144 +MX6Q_PAD_EIM_D22__SPDIF_OUT1 145 +MX6Q_PAD_EIM_D22__PL301_PER1_HWRITE 146 +MX6Q_PAD_EIM_D23__WEIM_WEIM_D_23 147 +MX6Q_PAD_EIM_D23__IPU1_DI0_D0_CS 148 +MX6Q_PAD_EIM_D23__UART3_CTS 149 +MX6Q_PAD_EIM_D23__UART1_DCD 150 +MX6Q_PAD_EIM_D23__IPU2_CSI1_DATA_EN 151 +MX6Q_PAD_EIM_D23__GPIO_3_23 152 +MX6Q_PAD_EIM_D23__IPU1_DI1_PIN2 153 +MX6Q_PAD_EIM_D23__IPU1_DI1_PIN14 154 +MX6Q_PAD_EIM_EB3__WEIM_WEIM_EB_3 155 +MX6Q_PAD_EIM_EB3__ECSPI4_RDY 156 +MX6Q_PAD_EIM_EB3__UART3_RTS 157 +MX6Q_PAD_EIM_EB3__UART1_RI 158 +MX6Q_PAD_EIM_EB3__IPU2_CSI1_HSYNC 159 +MX6Q_PAD_EIM_EB3__GPIO_2_31 160 +MX6Q_PAD_EIM_EB3__IPU1_DI1_PIN3 161 +MX6Q_PAD_EIM_EB3__SRC_BT_CFG_31 162 +MX6Q_PAD_EIM_D24__WEIM_WEIM_D_24 163 +MX6Q_PAD_EIM_D24__ECSPI4_SS2 164 +MX6Q_PAD_EIM_D24__UART3_TXD 165 +MX6Q_PAD_EIM_D24__ECSPI1_SS2 166 +MX6Q_PAD_EIM_D24__ECSPI2_SS2 167 +MX6Q_PAD_EIM_D24__GPIO_3_24 168 +MX6Q_PAD_EIM_D24__AUDMUX_AUD5_RXFS 169 +MX6Q_PAD_EIM_D24__UART1_DTR 170 +MX6Q_PAD_EIM_D25__WEIM_WEIM_D_25 171 +MX6Q_PAD_EIM_D25__ECSPI4_SS3 172 +MX6Q_PAD_EIM_D25__UART3_RXD 173 +MX6Q_PAD_EIM_D25__ECSPI1_SS3 174 +MX6Q_PAD_EIM_D25__ECSPI2_SS3 175 +MX6Q_PAD_EIM_D25__GPIO_3_25 176 +MX6Q_PAD_EIM_D25__AUDMUX_AUD5_RXC 177 +MX6Q_PAD_EIM_D25__UART1_DSR 178 +MX6Q_PAD_EIM_D26__WEIM_WEIM_D_26 179 +MX6Q_PAD_EIM_D26__IPU1_DI1_PIN11 180 +MX6Q_PAD_EIM_D26__IPU1_CSI0_D_1 181 +MX6Q_PAD_EIM_D26__IPU2_CSI1_D_14 182 +MX6Q_PAD_EIM_D26__UART2_TXD 183 +MX6Q_PAD_EIM_D26__GPIO_3_26 184 +MX6Q_PAD_EIM_D26__IPU1_SISG_2 185 +MX6Q_PAD_EIM_D26__IPU1_DISP1_DAT_22 186 +MX6Q_PAD_EIM_D27__WEIM_WEIM_D_27 187 +MX6Q_PAD_EIM_D27__IPU1_DI1_PIN13 188 +MX6Q_PAD_EIM_D27__IPU1_CSI0_D_0 189 +MX6Q_PAD_EIM_D27__IPU2_CSI1_D_13 190 +MX6Q_PAD_EIM_D27__UART2_RXD 191 +MX6Q_PAD_EIM_D27__GPIO_3_27 192 +MX6Q_PAD_EIM_D27__IPU1_SISG_3 193 +MX6Q_PAD_EIM_D27__IPU1_DISP1_DAT_23 194 +MX6Q_PAD_EIM_D28__WEIM_WEIM_D_28 195 +MX6Q_PAD_EIM_D28__I2C1_SDA 196 +MX6Q_PAD_EIM_D28__ECSPI4_MOSI 197 +MX6Q_PAD_EIM_D28__IPU2_CSI1_D_12 198 +MX6Q_PAD_EIM_D28__UART2_CTS 199 +MX6Q_PAD_EIM_D28__GPIO_3_28 200 +MX6Q_PAD_EIM_D28__IPU1_EXT_TRIG 201 +MX6Q_PAD_EIM_D28__IPU1_DI0_PIN13 202 +MX6Q_PAD_EIM_D29__WEIM_WEIM_D_29 203 +MX6Q_PAD_EIM_D29__IPU1_DI1_PIN15 204 +MX6Q_PAD_EIM_D29__ECSPI4_SS0 205 +MX6Q_PAD_EIM_D29__UART2_RTS 206 +MX6Q_PAD_EIM_D29__GPIO_3_29 207 +MX6Q_PAD_EIM_D29__IPU2_CSI1_VSYNC 208 +MX6Q_PAD_EIM_D29__IPU1_DI0_PIN14 209 +MX6Q_PAD_EIM_D30__WEIM_WEIM_D_30 210 +MX6Q_PAD_EIM_D30__IPU1_DISP1_DAT_21 211 +MX6Q_PAD_EIM_D30__IPU1_DI0_PIN11 212 +MX6Q_PAD_EIM_D30__IPU1_CSI0_D_3 213 +MX6Q_PAD_EIM_D30__UART3_CTS 214 +MX6Q_PAD_EIM_D30__GPIO_3_30 215 +MX6Q_PAD_EIM_D30__USBOH3_USBH1_OC 216 +MX6Q_PAD_EIM_D30__PL301_PER1_HPROT_0 217 +MX6Q_PAD_EIM_D31__WEIM_WEIM_D_31 218 +MX6Q_PAD_EIM_D31__IPU1_DISP1_DAT_20 219 +MX6Q_PAD_EIM_D31__IPU1_DI0_PIN12 220 +MX6Q_PAD_EIM_D31__IPU1_CSI0_D_2 221 +MX6Q_PAD_EIM_D31__UART3_RTS 222 +MX6Q_PAD_EIM_D31__GPIO_3_31 223 +MX6Q_PAD_EIM_D31__USBOH3_USBH1_PWR 224 +MX6Q_PAD_EIM_D31__PL301_PER1_HPROT_1 225 +MX6Q_PAD_EIM_A24__WEIM_WEIM_A_24 226 +MX6Q_PAD_EIM_A24__IPU1_DISP1_DAT_19 227 +MX6Q_PAD_EIM_A24__IPU2_CSI1_D_19 228 +MX6Q_PAD_EIM_A24__IPU2_SISG_2 229 +MX6Q_PAD_EIM_A24__IPU1_SISG_2 230 +MX6Q_PAD_EIM_A24__GPIO_5_4 231 +MX6Q_PAD_EIM_A24__PL301_PER1_HPROT_2 232 +MX6Q_PAD_EIM_A24__SRC_BT_CFG_24 233 +MX6Q_PAD_EIM_A23__WEIM_WEIM_A_23 234 +MX6Q_PAD_EIM_A23__IPU1_DISP1_DAT_18 235 +MX6Q_PAD_EIM_A23__IPU2_CSI1_D_18 236 +MX6Q_PAD_EIM_A23__IPU2_SISG_3 237 +MX6Q_PAD_EIM_A23__IPU1_SISG_3 238 +MX6Q_PAD_EIM_A23__GPIO_6_6 239 +MX6Q_PAD_EIM_A23__PL301_PER1_HPROT_3 240 +MX6Q_PAD_EIM_A23__SRC_BT_CFG_23 241 +MX6Q_PAD_EIM_A22__WEIM_WEIM_A_22 242 +MX6Q_PAD_EIM_A22__IPU1_DISP1_DAT_17 243 +MX6Q_PAD_EIM_A22__IPU2_CSI1_D_17 244 +MX6Q_PAD_EIM_A22__GPIO_2_16 245 +MX6Q_PAD_EIM_A22__TPSMP_HDATA_0 246 +MX6Q_PAD_EIM_A22__SRC_BT_CFG_22 247 +MX6Q_PAD_EIM_A21__WEIM_WEIM_A_21 248 +MX6Q_PAD_EIM_A21__IPU1_DISP1_DAT_16 249 +MX6Q_PAD_EIM_A21__IPU2_CSI1_D_16 250 +MX6Q_PAD_EIM_A21__RESERVED_RESERVED 251 +MX6Q_PAD_EIM_A21__MIPI_CORE_DPHY_OUT_18 252 +MX6Q_PAD_EIM_A21__GPIO_2_17 253 +MX6Q_PAD_EIM_A21__TPSMP_HDATA_1 254 +MX6Q_PAD_EIM_A21__SRC_BT_CFG_21 255 +MX6Q_PAD_EIM_A20__WEIM_WEIM_A_20 256 +MX6Q_PAD_EIM_A20__IPU1_DISP1_DAT_15 257 +MX6Q_PAD_EIM_A20__IPU2_CSI1_D_15 258 +MX6Q_PAD_EIM_A20__RESERVED_RESERVED 259 +MX6Q_PAD_EIM_A20__MIPI_CORE_DPHY_OUT_19 260 +MX6Q_PAD_EIM_A20__GPIO_2_18 261 +MX6Q_PAD_EIM_A20__TPSMP_HDATA_2 262 +MX6Q_PAD_EIM_A20__SRC_BT_CFG_20 263 +MX6Q_PAD_EIM_A19__WEIM_WEIM_A_19 264 +MX6Q_PAD_EIM_A19__IPU1_DISP1_DAT_14 265 +MX6Q_PAD_EIM_A19__IPU2_CSI1_D_14 266 +MX6Q_PAD_EIM_A19__RESERVED_RESERVED 267 +MX6Q_PAD_EIM_A19__MIPI_CORE_DPHY_OUT_20 268 +MX6Q_PAD_EIM_A19__GPIO_2_19 269 +MX6Q_PAD_EIM_A19__TPSMP_HDATA_3 270 +MX6Q_PAD_EIM_A19__SRC_BT_CFG_19 271 +MX6Q_PAD_EIM_A18__WEIM_WEIM_A_18 272 +MX6Q_PAD_EIM_A18__IPU1_DISP1_DAT_13 273 +MX6Q_PAD_EIM_A18__IPU2_CSI1_D_13 274 +MX6Q_PAD_EIM_A18__RESERVED_RESERVED 275 +MX6Q_PAD_EIM_A18__MIPI_CORE_DPHY_OUT_21 276 +MX6Q_PAD_EIM_A18__GPIO_2_20 277 +MX6Q_PAD_EIM_A18__TPSMP_HDATA_4 278 +MX6Q_PAD_EIM_A18__SRC_BT_CFG_18 279 +MX6Q_PAD_EIM_A17__WEIM_WEIM_A_17 280 +MX6Q_PAD_EIM_A17__IPU1_DISP1_DAT_12 281 +MX6Q_PAD_EIM_A17__IPU2_CSI1_D_12 282 +MX6Q_PAD_EIM_A17__RESERVED_RESERVED 283 +MX6Q_PAD_EIM_A17__MIPI_CORE_DPHY_OUT_22 284 +MX6Q_PAD_EIM_A17__GPIO_2_21 285 +MX6Q_PAD_EIM_A17__TPSMP_HDATA_5 286 +MX6Q_PAD_EIM_A17__SRC_BT_CFG_17 287 +MX6Q_PAD_EIM_A16__WEIM_WEIM_A_16 288 +MX6Q_PAD_EIM_A16__IPU1_DI1_DISP_CLK 289 +MX6Q_PAD_EIM_A16__IPU2_CSI1_PIXCLK 290 +MX6Q_PAD_EIM_A16__MIPI_CORE_DPHY_OUT_23 291 +MX6Q_PAD_EIM_A16__GPIO_2_22 292 +MX6Q_PAD_EIM_A16__TPSMP_HDATA_6 293 +MX6Q_PAD_EIM_A16__SRC_BT_CFG_16 294 +MX6Q_PAD_EIM_CS0__WEIM_WEIM_CS_0 295 +MX6Q_PAD_EIM_CS0__IPU1_DI1_PIN5 296 +MX6Q_PAD_EIM_CS0__ECSPI2_SCLK 297 +MX6Q_PAD_EIM_CS0__MIPI_CORE_DPHY_OUT_24 298 +MX6Q_PAD_EIM_CS0__GPIO_2_23 299 +MX6Q_PAD_EIM_CS0__TPSMP_HDATA_7 300 +MX6Q_PAD_EIM_CS1__WEIM_WEIM_CS_1 301 +MX6Q_PAD_EIM_CS1__IPU1_DI1_PIN6 302 +MX6Q_PAD_EIM_CS1__ECSPI2_MOSI 303 +MX6Q_PAD_EIM_CS1__MIPI_CORE_DPHY_OUT_25 304 +MX6Q_PAD_EIM_CS1__GPIO_2_24 305 +MX6Q_PAD_EIM_CS1__TPSMP_HDATA_8 306 +MX6Q_PAD_EIM_OE__WEIM_WEIM_OE 307 +MX6Q_PAD_EIM_OE__IPU1_DI1_PIN7 308 +MX6Q_PAD_EIM_OE__ECSPI2_MISO 309 +MX6Q_PAD_EIM_OE__MIPI_CORE_DPHY_OUT_26 310 +MX6Q_PAD_EIM_OE__GPIO_2_25 311 +MX6Q_PAD_EIM_OE__TPSMP_HDATA_9 312 +MX6Q_PAD_EIM_RW__WEIM_WEIM_RW 313 +MX6Q_PAD_EIM_RW__IPU1_DI1_PIN8 314 +MX6Q_PAD_EIM_RW__ECSPI2_SS0 315 +MX6Q_PAD_EIM_RW__MIPI_CORE_DPHY_OUT_27 316 +MX6Q_PAD_EIM_RW__GPIO_2_26 317 +MX6Q_PAD_EIM_RW__TPSMP_HDATA_10 318 +MX6Q_PAD_EIM_RW__SRC_BT_CFG_29 319 +MX6Q_PAD_EIM_LBA__WEIM_WEIM_LBA 320 +MX6Q_PAD_EIM_LBA__IPU1_DI1_PIN17 321 +MX6Q_PAD_EIM_LBA__ECSPI2_SS1 322 +MX6Q_PAD_EIM_LBA__GPIO_2_27 323 +MX6Q_PAD_EIM_LBA__TPSMP_HDATA_11 324 +MX6Q_PAD_EIM_LBA__SRC_BT_CFG_26 325 +MX6Q_PAD_EIM_EB0__WEIM_WEIM_EB_0 326 +MX6Q_PAD_EIM_EB0__IPU1_DISP1_DAT_11 327 +MX6Q_PAD_EIM_EB0__IPU2_CSI1_D_11 328 +MX6Q_PAD_EIM_EB0__MIPI_CORE_DPHY_OUT_0 329 +MX6Q_PAD_EIM_EB0__CCM_PMIC_RDY 330 +MX6Q_PAD_EIM_EB0__GPIO_2_28 331 +MX6Q_PAD_EIM_EB0__TPSMP_HDATA_12 332 +MX6Q_PAD_EIM_EB0__SRC_BT_CFG_27 333 +MX6Q_PAD_EIM_EB1__WEIM_WEIM_EB_1 334 +MX6Q_PAD_EIM_EB1__IPU1_DISP1_DAT_10 335 +MX6Q_PAD_EIM_EB1__IPU2_CSI1_D_10 336 +MX6Q_PAD_EIM_EB1__MIPI_CORE_DPHY__OUT_1 337 +MX6Q_PAD_EIM_EB1__GPIO_2_29 338 +MX6Q_PAD_EIM_EB1__TPSMP_HDATA_13 339 +MX6Q_PAD_EIM_EB1__SRC_BT_CFG_28 340 +MX6Q_PAD_EIM_DA0__WEIM_WEIM_DA_A_0 341 +MX6Q_PAD_EIM_DA0__IPU1_DISP1_DAT_9 342 +MX6Q_PAD_EIM_DA0__IPU2_CSI1_D_9 343 +MX6Q_PAD_EIM_DA0__MIPI_CORE_DPHY__OUT_2 344 +MX6Q_PAD_EIM_DA0__GPIO_3_0 345 +MX6Q_PAD_EIM_DA0__TPSMP_HDATA_14 346 +MX6Q_PAD_EIM_DA0__SRC_BT_CFG_0 347 +MX6Q_PAD_EIM_DA1__WEIM_WEIM_DA_A_1 348 +MX6Q_PAD_EIM_DA1__IPU1_DISP1_DAT_8 349 +MX6Q_PAD_EIM_DA1__IPU2_CSI1_D_8 350 +MX6Q_PAD_EIM_DA1__MIPI_CORE_DPHY_OUT_3 351 +MX6Q_PAD_EIM_DA1__USBPHY1_TX_LS_MODE 352 +MX6Q_PAD_EIM_DA1__GPIO_3_1 353 +MX6Q_PAD_EIM_DA1__TPSMP_HDATA_15 354 +MX6Q_PAD_EIM_DA1__SRC_BT_CFG_1 355 +MX6Q_PAD_EIM_DA2__WEIM_WEIM_DA_A_2 356 +MX6Q_PAD_EIM_DA2__IPU1_DISP1_DAT_7 357 +MX6Q_PAD_EIM_DA2__IPU2_CSI1_D_7 358 +MX6Q_PAD_EIM_DA2__MIPI_CORE_DPHY_OUT_4 359 +MX6Q_PAD_EIM_DA2__USBPHY1_TX_HS_MODE 360 +MX6Q_PAD_EIM_DA2__GPIO_3_2 361 +MX6Q_PAD_EIM_DA2__TPSMP_HDATA_16 362 +MX6Q_PAD_EIM_DA2__SRC_BT_CFG_2 363 +MX6Q_PAD_EIM_DA3__WEIM_WEIM_DA_A_3 364 +MX6Q_PAD_EIM_DA3__IPU1_DISP1_DAT_6 365 +MX6Q_PAD_EIM_DA3__IPU2_CSI1_D_6 366 +MX6Q_PAD_EIM_DA3__MIPI_CORE_DPHY_OUT_5 367 +MX6Q_PAD_EIM_DA3__USBPHY1_TX_HIZ 368 +MX6Q_PAD_EIM_DA3__GPIO_3_3 369 +MX6Q_PAD_EIM_DA3__TPSMP_HDATA_17 370 +MX6Q_PAD_EIM_DA3__SRC_BT_CFG_3 371 +MX6Q_PAD_EIM_DA4__WEIM_WEIM_DA_A_4 372 +MX6Q_PAD_EIM_DA4__IPU1_DISP1_DAT_5 373 +MX6Q_PAD_EIM_DA4__IPU2_CSI1_D_5 374 +MX6Q_PAD_EIM_DA4__MIPI_CORE_DPHY_OUT_6 375 +MX6Q_PAD_EIM_DA4__ANATOP_USBPHY1_TX_EN 376 +MX6Q_PAD_EIM_DA4__GPIO_3_4 377 +MX6Q_PAD_EIM_DA4__TPSMP_HDATA_18 378 +MX6Q_PAD_EIM_DA4__SRC_BT_CFG_4 379 +MX6Q_PAD_EIM_DA5__WEIM_WEIM_DA_A_5 380 +MX6Q_PAD_EIM_DA5__IPU1_DISP1_DAT_4 381 +MX6Q_PAD_EIM_DA5__IPU2_CSI1_D_4 382 +MX6Q_PAD_EIM_DA5__MIPI_CORE_DPHY_OUT_7 383 +MX6Q_PAD_EIM_DA5__ANATOP_USBPHY1_TX_DP 384 +MX6Q_PAD_EIM_DA5__GPIO_3_5 385 +MX6Q_PAD_EIM_DA5__TPSMP_HDATA_19 386 +MX6Q_PAD_EIM_DA5__SRC_BT_CFG_5 387 +MX6Q_PAD_EIM_DA6__WEIM_WEIM_DA_A_6 388 +MX6Q_PAD_EIM_DA6__IPU1_DISP1_DAT_3 389 +MX6Q_PAD_EIM_DA6__IPU2_CSI1_D_3 390 +MX6Q_PAD_EIM_DA6__MIPI_CORE_DPHY_OUT_8 391 +MX6Q_PAD_EIM_DA6__ANATOP_USBPHY1_TX_DN 392 +MX6Q_PAD_EIM_DA6__GPIO_3_6 393 +MX6Q_PAD_EIM_DA6__TPSMP_HDATA_20 394 +MX6Q_PAD_EIM_DA6__SRC_BT_CFG_6 395 +MX6Q_PAD_EIM_DA7__WEIM_WEIM_DA_A_7 396 +MX6Q_PAD_EIM_DA7__IPU1_DISP1_DAT_2 397 +MX6Q_PAD_EIM_DA7__IPU2_CSI1_D_2 398 +MX6Q_PAD_EIM_DA7__MIPI_CORE_DPHY_OUT_9 399 +MX6Q_PAD_EIM_DA7__GPIO_3_7 400 +MX6Q_PAD_EIM_DA7__TPSMP_HDATA_21 401 +MX6Q_PAD_EIM_DA7__SRC_BT_CFG_7 402 +MX6Q_PAD_EIM_DA8__WEIM_WEIM_DA_A_8 403 +MX6Q_PAD_EIM_DA8__IPU1_DISP1_DAT_1 404 +MX6Q_PAD_EIM_DA8__IPU2_CSI1_D_1 405 +MX6Q_PAD_EIM_DA8__MIPI_CORE_DPHY_OUT_10 406 +MX6Q_PAD_EIM_DA8__GPIO_3_8 407 +MX6Q_PAD_EIM_DA8__TPSMP_HDATA_22 408 +MX6Q_PAD_EIM_DA8__SRC_BT_CFG_8 409 +MX6Q_PAD_EIM_DA9__WEIM_WEIM_DA_A_9 410 +MX6Q_PAD_EIM_DA9__IPU1_DISP1_DAT_0 411 +MX6Q_PAD_EIM_DA9__IPU2_CSI1_D_0 412 +MX6Q_PAD_EIM_DA9__MIPI_CORE_DPHY_OUT_11 413 +MX6Q_PAD_EIM_DA9__GPIO_3_9 414 +MX6Q_PAD_EIM_DA9__TPSMP_HDATA_23 415 +MX6Q_PAD_EIM_DA9__SRC_BT_CFG_9 416 +MX6Q_PAD_EIM_DA10__WEIM_WEIM_DA_A_10 417 +MX6Q_PAD_EIM_DA10__IPU1_DI1_PIN15 418 +MX6Q_PAD_EIM_DA10__IPU2_CSI1_DATA_EN 419 +MX6Q_PAD_EIM_DA10__MIPI_CORE_DPHY_OUT12 420 +MX6Q_PAD_EIM_DA10__GPIO_3_10 421 +MX6Q_PAD_EIM_DA10__TPSMP_HDATA_24 422 +MX6Q_PAD_EIM_DA10__SRC_BT_CFG_10 423 +MX6Q_PAD_EIM_DA11__WEIM_WEIM_DA_A_11 424 +MX6Q_PAD_EIM_DA11__IPU1_DI1_PIN2 425 +MX6Q_PAD_EIM_DA11__IPU2_CSI1_HSYNC 426 +MX6Q_PAD_EIM_DA11__MIPI_CORE_DPHY_OUT13 427 +MX6Q_PAD_EIM_DA11__SDMA_DBG_EVT_CHN_6 428 +MX6Q_PAD_EIM_DA11__GPIO_3_11 429 +MX6Q_PAD_EIM_DA11__TPSMP_HDATA_25 430 +MX6Q_PAD_EIM_DA11__SRC_BT_CFG_11 431 +MX6Q_PAD_EIM_DA12__WEIM_WEIM_DA_A_12 432 +MX6Q_PAD_EIM_DA12__IPU1_DI1_PIN3 433 +MX6Q_PAD_EIM_DA12__IPU2_CSI1_VSYNC 434 +MX6Q_PAD_EIM_DA12__MIPI_CORE_DPHY_OUT14 435 +MX6Q_PAD_EIM_DA12__SDMA_DEBUG_EVT_CHN_3 436 +MX6Q_PAD_EIM_DA12__GPIO_3_12 437 +MX6Q_PAD_EIM_DA12__TPSMP_HDATA_26 438 +MX6Q_PAD_EIM_DA12__SRC_BT_CFG_12 439 +MX6Q_PAD_EIM_DA13__WEIM_WEIM_DA_A_13 440 +MX6Q_PAD_EIM_DA13__IPU1_DI1_D0_CS 441 +MX6Q_PAD_EIM_DA13__CCM_DI1_EXT_CLK 442 +MX6Q_PAD_EIM_DA13__MIPI_CORE_DPHY_OUT15 443 +MX6Q_PAD_EIM_DA13__SDMA_DEBUG_EVT_CHN_4 444 +MX6Q_PAD_EIM_DA13__GPIO_3_13 445 +MX6Q_PAD_EIM_DA13__TPSMP_HDATA_27 446 +MX6Q_PAD_EIM_DA13__SRC_BT_CFG_13 447 +MX6Q_PAD_EIM_DA14__WEIM_WEIM_DA_A_14 448 +MX6Q_PAD_EIM_DA14__IPU1_DI1_D1_CS 449 +MX6Q_PAD_EIM_DA14__CCM_DI0_EXT_CLK 450 +MX6Q_PAD_EIM_DA14__MIPI_CORE_DPHY_OUT16 451 +MX6Q_PAD_EIM_DA14__SDMA_DEBUG_EVT_CHN_5 452 +MX6Q_PAD_EIM_DA14__GPIO_3_14 453 +MX6Q_PAD_EIM_DA14__TPSMP_HDATA_28 454 +MX6Q_PAD_EIM_DA14__SRC_BT_CFG_14 455 +MX6Q_PAD_EIM_DA15__WEIM_WEIM_DA_A_15 456 +MX6Q_PAD_EIM_DA15__IPU1_DI1_PIN1 457 +MX6Q_PAD_EIM_DA15__IPU1_DI1_PIN4 458 +MX6Q_PAD_EIM_DA15__MIPI_CORE_DPHY_OUT17 459 +MX6Q_PAD_EIM_DA15__GPIO_3_15 460 +MX6Q_PAD_EIM_DA15__TPSMP_HDATA_29 461 +MX6Q_PAD_EIM_DA15__SRC_BT_CFG_15 462 +MX6Q_PAD_EIM_WAIT__WEIM_WEIM_WAIT 463 +MX6Q_PAD_EIM_WAIT__WEIM_WEIM_DTACK_B 464 +MX6Q_PAD_EIM_WAIT__GPIO_5_0 465 +MX6Q_PAD_EIM_WAIT__TPSMP_HDATA_30 466 +MX6Q_PAD_EIM_WAIT__SRC_BT_CFG_25 467 +MX6Q_PAD_EIM_BCLK__WEIM_WEIM_BCLK 468 +MX6Q_PAD_EIM_BCLK__IPU1_DI1_PIN16 469 +MX6Q_PAD_EIM_BCLK__GPIO_6_31 470 +MX6Q_PAD_EIM_BCLK__TPSMP_HDATA_31 471 +MX6Q_PAD_DI0_DISP_CLK__IPU1_DI0_DSP_CLK 472 +MX6Q_PAD_DI0_DISP_CLK__IPU2_DI0_DSP_CLK 473 +MX6Q_PAD_DI0_DISP_CLK__MIPI_CR_DPY_OT28 474 +MX6Q_PAD_DI0_DISP_CLK__SDMA_DBG_CR_STA0 475 +MX6Q_PAD_DI0_DISP_CLK__GPIO_4_16 476 +MX6Q_PAD_DI0_DISP_CLK__MMDC_DEBUG_0 477 +MX6Q_PAD_DI0_PIN15__IPU1_DI0_PIN15 478 +MX6Q_PAD_DI0_PIN15__IPU2_DI0_PIN15 479 +MX6Q_PAD_DI0_PIN15__AUDMUX_AUD6_TXC 480 +MX6Q_PAD_DI0_PIN15__MIPI_CR_DPHY_OUT_29 481 +MX6Q_PAD_DI0_PIN15__SDMA_DBG_CORE_STA_1 482 +MX6Q_PAD_DI0_PIN15__GPIO_4_17 483 +MX6Q_PAD_DI0_PIN15__MMDC_MMDC_DEBUG_1 484 +MX6Q_PAD_DI0_PIN2__IPU1_DI0_PIN2 485 +MX6Q_PAD_DI0_PIN2__IPU2_DI0_PIN2 486 +MX6Q_PAD_DI0_PIN2__AUDMUX_AUD6_TXD 487 +MX6Q_PAD_DI0_PIN2__MIPI_CR_DPHY_OUT_30 488 +MX6Q_PAD_DI0_PIN2__SDMA_DBG_CORE_STA_2 489 +MX6Q_PAD_DI0_PIN2__GPIO_4_18 490 +MX6Q_PAD_DI0_PIN2__MMDC_DEBUG_2 491 +MX6Q_PAD_DI0_PIN2__PL301_PER1_HADDR_9 492 +MX6Q_PAD_DI0_PIN3__IPU1_DI0_PIN3 493 +MX6Q_PAD_DI0_PIN3__IPU2_DI0_PIN3 494 +MX6Q_PAD_DI0_PIN3__AUDMUX_AUD6_TXFS 495 +MX6Q_PAD_DI0_PIN3__MIPI_CORE_DPHY_OUT31 496 +MX6Q_PAD_DI0_PIN3__SDMA_DBG_CORE_STA_3 497 +MX6Q_PAD_DI0_PIN3__GPIO_4_19 498 +MX6Q_PAD_DI0_PIN3__MMDC_MMDC_DEBUG_3 499 +MX6Q_PAD_DI0_PIN3__PL301_PER1_HADDR_10 500 +MX6Q_PAD_DI0_PIN4__IPU1_DI0_PIN4 501 +MX6Q_PAD_DI0_PIN4__IPU2_DI0_PIN4 502 +MX6Q_PAD_DI0_PIN4__AUDMUX_AUD6_RXD 503 +MX6Q_PAD_DI0_PIN4__USDHC1_WP 504 +MX6Q_PAD_DI0_PIN4__SDMA_DEBUG_YIELD 505 +MX6Q_PAD_DI0_PIN4__GPIO_4_20 506 +MX6Q_PAD_DI0_PIN4__MMDC_MMDC_DEBUG_4 507 +MX6Q_PAD_DI0_PIN4__PL301_PER1_HADDR_11 508 +MX6Q_PAD_DISP0_DAT0__IPU1_DISP0_DAT_0 509 +MX6Q_PAD_DISP0_DAT0__IPU2_DISP0_DAT_0 510 +MX6Q_PAD_DISP0_DAT0__ECSPI3_SCLK 511 +MX6Q_PAD_DISP0_DAT0__USDHC1_USDHC_DBG_0 512 +MX6Q_PAD_DISP0_DAT0__SDMA_DBG_CORE_RUN 513 +MX6Q_PAD_DISP0_DAT0__GPIO_4_21 514 +MX6Q_PAD_DISP0_DAT0__MMDC_MMDC_DEBUG_5 515 +MX6Q_PAD_DISP0_DAT1__IPU1_DISP0_DAT_1 516 +MX6Q_PAD_DISP0_DAT1__IPU2_DISP0_DAT_1 517 +MX6Q_PAD_DISP0_DAT1__ECSPI3_MOSI 518 +MX6Q_PAD_DISP0_DAT1__USDHC1_USDHC_DBG_1 519 +MX6Q_PAD_DISP0_DAT1__SDMA_DBG_EVT_CHNSL 520 +MX6Q_PAD_DISP0_DAT1__GPIO_4_22 521 +MX6Q_PAD_DISP0_DAT1__MMDC_DEBUG_6 522 +MX6Q_PAD_DISP0_DAT1__PL301_PER1_HADR_12 523 +MX6Q_PAD_DISP0_DAT2__IPU1_DISP0_DAT_2 524 +MX6Q_PAD_DISP0_DAT2__IPU2_DISP0_DAT_2 525 +MX6Q_PAD_DISP0_DAT2__ECSPI3_MISO 526 +MX6Q_PAD_DISP0_DAT2__USDHC1_USDHC_DBG_2 527 +MX6Q_PAD_DISP0_DAT2__SDMA_DEBUG_MODE 528 +MX6Q_PAD_DISP0_DAT2__GPIO_4_23 529 +MX6Q_PAD_DISP0_DAT2__MMDC_DEBUG_7 530 +MX6Q_PAD_DISP0_DAT2__PL301_PER1_HADR_13 531 +MX6Q_PAD_DISP0_DAT3__IPU1_DISP0_DAT_3 532 +MX6Q_PAD_DISP0_DAT3__IPU2_DISP0_DAT_3 533 +MX6Q_PAD_DISP0_DAT3__ECSPI3_SS0 534 +MX6Q_PAD_DISP0_DAT3__USDHC1_USDHC_DBG_3 535 +MX6Q_PAD_DISP0_DAT3__SDMA_DBG_BUS_ERROR 536 +MX6Q_PAD_DISP0_DAT3__GPIO_4_24 537 +MX6Q_PAD_DISP0_DAT3__MMDC_MMDC_DBG_8 538 +MX6Q_PAD_DISP0_DAT3__PL301_PER1_HADR_14 539 +MX6Q_PAD_DISP0_DAT4__IPU1_DISP0_DAT_4 540 +MX6Q_PAD_DISP0_DAT4__IPU2_DISP0_DAT_4 541 +MX6Q_PAD_DISP0_DAT4__ECSPI3_SS1 542 +MX6Q_PAD_DISP0_DAT4__USDHC1_USDHC_DBG_4 543 +MX6Q_PAD_DISP0_DAT4__SDMA_DEBUG_BUS_RWB 544 +MX6Q_PAD_DISP0_DAT4__GPIO_4_25 545 +MX6Q_PAD_DISP0_DAT4__MMDC_MMDC_DEBUG_9 546 +MX6Q_PAD_DISP0_DAT4__PL301_PER1_HADR_15 547 +MX6Q_PAD_DISP0_DAT5__IPU1_DISP0_DAT_5 548 +MX6Q_PAD_DISP0_DAT5__IPU2_DISP0_DAT_5 549 +MX6Q_PAD_DISP0_DAT5__ECSPI3_SS2 550 +MX6Q_PAD_DISP0_DAT5__AUDMUX_AUD6_RXFS 551 +MX6Q_PAD_DISP0_DAT5__SDMA_DBG_MCH_DMBUS 552 +MX6Q_PAD_DISP0_DAT5__GPIO_4_26 553 +MX6Q_PAD_DISP0_DAT5__MMDC_DEBUG_10 554 +MX6Q_PAD_DISP0_DAT5__PL301_PER1_HADR_16 555 +MX6Q_PAD_DISP0_DAT6__IPU1_DISP0_DAT_6 556 +MX6Q_PAD_DISP0_DAT6__IPU2_DISP0_DAT_6 557 +MX6Q_PAD_DISP0_DAT6__ECSPI3_SS3 558 +MX6Q_PAD_DISP0_DAT6__AUDMUX_AUD6_RXC 559 +MX6Q_PAD_DISP0_DAT6__SDMA_DBG_RTBUF_WRT 560 +MX6Q_PAD_DISP0_DAT6__GPIO_4_27 561 +MX6Q_PAD_DISP0_DAT6__MMDC_DEBUG_11 562 +MX6Q_PAD_DISP0_DAT6__PL301_PER1_HADR_17 563 +MX6Q_PAD_DISP0_DAT7__IPU1_DISP0_DAT_7 564 +MX6Q_PAD_DISP0_DAT7__IPU2_DISP0_DAT_7 565 +MX6Q_PAD_DISP0_DAT7__ECSPI3_RDY 566 +MX6Q_PAD_DISP0_DAT7__USDHC1_USDHC_DBG_5 567 +MX6Q_PAD_DISP0_DAT7__SDMA_DBG_EVT_CHN_0 568 +MX6Q_PAD_DISP0_DAT7__GPIO_4_28 569 +MX6Q_PAD_DISP0_DAT7__MMDC_DEBUG_12 570 +MX6Q_PAD_DISP0_DAT7__PL301_PER1_HADR_18 571 +MX6Q_PAD_DISP0_DAT8__IPU1_DISP0_DAT_8 572 +MX6Q_PAD_DISP0_DAT8__IPU2_DISP0_DAT_8 573 +MX6Q_PAD_DISP0_DAT8__PWM1_PWMO 574 +MX6Q_PAD_DISP0_DAT8__WDOG1_WDOG_B 575 +MX6Q_PAD_DISP0_DAT8__SDMA_DBG_EVT_CHN_1 576 +MX6Q_PAD_DISP0_DAT8__GPIO_4_29 577 +MX6Q_PAD_DISP0_DAT8__MMDC_DEBUG_13 578 +MX6Q_PAD_DISP0_DAT8__PL301_PER1_HADR_19 579 +MX6Q_PAD_DISP0_DAT9__IPU1_DISP0_DAT_9 580 +MX6Q_PAD_DISP0_DAT9__IPU2_DISP0_DAT_9 581 +MX6Q_PAD_DISP0_DAT9__PWM2_PWMO 582 +MX6Q_PAD_DISP0_DAT9__WDOG2_WDOG_B 583 +MX6Q_PAD_DISP0_DAT9__SDMA_DBG_EVT_CHN_2 584 +MX6Q_PAD_DISP0_DAT9__GPIO_4_30 585 +MX6Q_PAD_DISP0_DAT9__MMDC_DEBUG_14 586 +MX6Q_PAD_DISP0_DAT9__PL301_PER1_HADR_20 587 +MX6Q_PAD_DISP0_DAT10__IPU1_DISP0_DAT_10 588 +MX6Q_PAD_DISP0_DAT10__IPU2_DISP0_DAT_10 589 +MX6Q_PAD_DISP0_DAT10__USDHC1_DBG_6 590 +MX6Q_PAD_DISP0_DAT10__SDMA_DBG_EVT_CHN3 591 +MX6Q_PAD_DISP0_DAT10__GPIO_4_31 592 +MX6Q_PAD_DISP0_DAT10__MMDC_DEBUG_15 593 +MX6Q_PAD_DISP0_DAT10__PL301_PER1_HADR21 594 +MX6Q_PAD_DISP0_DAT11__IPU1_DISP0_DAT_11 595 +MX6Q_PAD_DISP0_DAT11__IPU2_DISP0_DAT_11 596 +MX6Q_PAD_DISP0_DAT11__USDHC1_USDHC_DBG7 597 +MX6Q_PAD_DISP0_DAT11__SDMA_DBG_EVT_CHN4 598 +MX6Q_PAD_DISP0_DAT11__GPIO_5_5 599 +MX6Q_PAD_DISP0_DAT11__MMDC_DEBUG_16 600 +MX6Q_PAD_DISP0_DAT11__PL301_PER1_HADR22 601 +MX6Q_PAD_DISP0_DAT12__IPU1_DISP0_DAT_12 602 +MX6Q_PAD_DISP0_DAT12__IPU2_DISP0_DAT_12 603 +MX6Q_PAD_DISP0_DAT12__RESERVED_RESERVED 604 +MX6Q_PAD_DISP0_DAT12__SDMA_DBG_EVT_CHN5 605 +MX6Q_PAD_DISP0_DAT12__GPIO_5_6 606 +MX6Q_PAD_DISP0_DAT12__MMDC_DEBUG_17 607 +MX6Q_PAD_DISP0_DAT12__PL301_PER1_HADR23 608 +MX6Q_PAD_DISP0_DAT13__IPU1_DISP0_DAT_13 609 +MX6Q_PAD_DISP0_DAT13__IPU2_DISP0_DAT_13 610 +MX6Q_PAD_DISP0_DAT13__AUDMUX_AUD5_RXFS 611 +MX6Q_PAD_DISP0_DAT13__SDMA_DBG_EVT_CHN0 612 +MX6Q_PAD_DISP0_DAT13__GPIO_5_7 613 +MX6Q_PAD_DISP0_DAT13__MMDC_DEBUG_18 614 +MX6Q_PAD_DISP0_DAT13__PL301_PER1_HADR24 615 +MX6Q_PAD_DISP0_DAT14__IPU1_DISP0_DAT_14 616 +MX6Q_PAD_DISP0_DAT14__IPU2_DISP0_DAT_14 617 +MX6Q_PAD_DISP0_DAT14__AUDMUX_AUD5_RXC 618 +MX6Q_PAD_DISP0_DAT14__SDMA_DBG_EVT_CHN1 619 +MX6Q_PAD_DISP0_DAT14__GPIO_5_8 620 +MX6Q_PAD_DISP0_DAT14__MMDC_DEBUG_19 621 +MX6Q_PAD_DISP0_DAT15__IPU1_DISP0_DAT_15 622 +MX6Q_PAD_DISP0_DAT15__IPU2_DISP0_DAT_15 623 +MX6Q_PAD_DISP0_DAT15__ECSPI1_SS1 624 +MX6Q_PAD_DISP0_DAT15__ECSPI2_SS1 625 +MX6Q_PAD_DISP0_DAT15__SDMA_DBG_EVT_CHN2 626 +MX6Q_PAD_DISP0_DAT15__GPIO_5_9 627 +MX6Q_PAD_DISP0_DAT15__MMDC_DEBUG_20 628 +MX6Q_PAD_DISP0_DAT15__PL301_PER1_HADR25 629 +MX6Q_PAD_DISP0_DAT16__IPU1_DISP0_DAT_16 630 +MX6Q_PAD_DISP0_DAT16__IPU2_DISP0_DAT_16 631 +MX6Q_PAD_DISP0_DAT16__ECSPI2_MOSI 632 +MX6Q_PAD_DISP0_DAT16__AUDMUX_AUD5_TXC 633 +MX6Q_PAD_DISP0_DAT16__SDMA_EXT_EVENT_0 634 +MX6Q_PAD_DISP0_DAT16__GPIO_5_10 635 +MX6Q_PAD_DISP0_DAT16__MMDC_DEBUG_21 636 +MX6Q_PAD_DISP0_DAT16__PL301_PER1_HADR26 637 +MX6Q_PAD_DISP0_DAT17__IPU1_DISP0_DAT_17 638 +MX6Q_PAD_DISP0_DAT17__IPU2_DISP0_DAT_17 639 +MX6Q_PAD_DISP0_DAT17__ECSPI2_MISO 640 +MX6Q_PAD_DISP0_DAT17__AUDMUX_AUD5_TXD 641 +MX6Q_PAD_DISP0_DAT17__SDMA_EXT_EVENT_1 642 +MX6Q_PAD_DISP0_DAT17__GPIO_5_11 643 +MX6Q_PAD_DISP0_DAT17__MMDC_DEBUG_22 644 +MX6Q_PAD_DISP0_DAT17__PL301_PER1_HADR27 645 +MX6Q_PAD_DISP0_DAT18__IPU1_DISP0_DAT_18 646 +MX6Q_PAD_DISP0_DAT18__IPU2_DISP0_DAT_18 647 +MX6Q_PAD_DISP0_DAT18__ECSPI2_SS0 648 +MX6Q_PAD_DISP0_DAT18__AUDMUX_AUD5_TXFS 649 +MX6Q_PAD_DISP0_DAT18__AUDMUX_AUD4_RXFS 650 +MX6Q_PAD_DISP0_DAT18__GPIO_5_12 651 +MX6Q_PAD_DISP0_DAT18__MMDC_DEBUG_23 652 +MX6Q_PAD_DISP0_DAT18__WEIM_WEIM_CS_2 653 +MX6Q_PAD_DISP0_DAT19__IPU1_DISP0_DAT_19 654 +MX6Q_PAD_DISP0_DAT19__IPU2_DISP0_DAT_19 655 +MX6Q_PAD_DISP0_DAT19__ECSPI2_SCLK 656 +MX6Q_PAD_DISP0_DAT19__AUDMUX_AUD5_RXD 657 +MX6Q_PAD_DISP0_DAT19__AUDMUX_AUD4_RXC 658 +MX6Q_PAD_DISP0_DAT19__GPIO_5_13 659 +MX6Q_PAD_DISP0_DAT19__MMDC_DEBUG_24 660 +MX6Q_PAD_DISP0_DAT19__WEIM_WEIM_CS_3 661 +MX6Q_PAD_DISP0_DAT20__IPU1_DISP0_DAT_20 662 +MX6Q_PAD_DISP0_DAT20__IPU2_DISP0_DAT_20 663 +MX6Q_PAD_DISP0_DAT20__ECSPI1_SCLK 664 +MX6Q_PAD_DISP0_DAT20__AUDMUX_AUD4_TXC 665 +MX6Q_PAD_DISP0_DAT20__SDMA_DBG_EVT_CHN7 666 +MX6Q_PAD_DISP0_DAT20__GPIO_5_14 667 +MX6Q_PAD_DISP0_DAT20__MMDC_DEBUG_25 668 +MX6Q_PAD_DISP0_DAT20__PL301_PER1_HADR28 669 +MX6Q_PAD_DISP0_DAT21__IPU1_DISP0_DAT_21 670 +MX6Q_PAD_DISP0_DAT21__IPU2_DISP0_DAT_21 671 +MX6Q_PAD_DISP0_DAT21__ECSPI1_MOSI 672 +MX6Q_PAD_DISP0_DAT21__AUDMUX_AUD4_TXD 673 +MX6Q_PAD_DISP0_DAT21__SDMA_DBG_BUS_DEV0 674 +MX6Q_PAD_DISP0_DAT21__GPIO_5_15 675 +MX6Q_PAD_DISP0_DAT21__MMDC_DEBUG_26 676 +MX6Q_PAD_DISP0_DAT21__PL301_PER1_HADR29 677 +MX6Q_PAD_DISP0_DAT22__IPU1_DISP0_DAT_22 678 +MX6Q_PAD_DISP0_DAT22__IPU2_DISP0_DAT_22 679 +MX6Q_PAD_DISP0_DAT22__ECSPI1_MISO 680 +MX6Q_PAD_DISP0_DAT22__AUDMUX_AUD4_TXFS 681 +MX6Q_PAD_DISP0_DAT22__SDMA_DBG_BUS_DEV1 682 +MX6Q_PAD_DISP0_DAT22__GPIO_5_16 683 +MX6Q_PAD_DISP0_DAT22__MMDC_DEBUG_27 684 +MX6Q_PAD_DISP0_DAT22__PL301_PER1_HADR30 685 +MX6Q_PAD_DISP0_DAT23__IPU1_DISP0_DAT_23 686 +MX6Q_PAD_DISP0_DAT23__IPU2_DISP0_DAT_23 687 +MX6Q_PAD_DISP0_DAT23__ECSPI1_SS0 688 +MX6Q_PAD_DISP0_DAT23__AUDMUX_AUD4_RXD 689 +MX6Q_PAD_DISP0_DAT23__SDMA_DBG_BUS_DEV2 690 +MX6Q_PAD_DISP0_DAT23__GPIO_5_17 691 +MX6Q_PAD_DISP0_DAT23__MMDC_DEBUG_28 692 +MX6Q_PAD_DISP0_DAT23__PL301_PER1_HADR31 693 +MX6Q_PAD_ENET_MDIO__RESERVED_RESERVED 694 +MX6Q_PAD_ENET_MDIO__ENET_MDIO 695 +MX6Q_PAD_ENET_MDIO__ESAI1_SCKR 696 +MX6Q_PAD_ENET_MDIO__SDMA_DEBUG_BUS_DEV3 697 +MX6Q_PAD_ENET_MDIO__ENET_1588_EVT1_OUT 698 +MX6Q_PAD_ENET_MDIO__GPIO_1_22 699 +MX6Q_PAD_ENET_MDIO__SPDIF_PLOCK 700 +MX6Q_PAD_ENET_REF_CLK__RESERVED_RSRVED 701 +MX6Q_PAD_ENET_REF_CLK__ENET_TX_CLK 702 +MX6Q_PAD_ENET_REF_CLK__ESAI1_FSR 703 +MX6Q_PAD_ENET_REF_CLK__SDMA_DBGBUS_DEV4 704 +MX6Q_PAD_ENET_REF_CLK__GPIO_1_23 705 +MX6Q_PAD_ENET_REF_CLK__SPDIF_SRCLK 706 +MX6Q_PAD_ENET_REF_CLK__USBPHY1_RX_SQH 707 +MX6Q_PAD_ENET_RX_ER__ENET_RX_ER 708 +MX6Q_PAD_ENET_RX_ER__ESAI1_HCKR 709 +MX6Q_PAD_ENET_RX_ER__SPDIF_IN1 710 +MX6Q_PAD_ENET_RX_ER__ENET_1588_EVT2_OUT 711 +MX6Q_PAD_ENET_RX_ER__GPIO_1_24 712 +MX6Q_PAD_ENET_RX_ER__PHY_TDI 713 +MX6Q_PAD_ENET_RX_ER__USBPHY1_RX_HS_RXD 714 +MX6Q_PAD_ENET_CRS_DV__RESERVED_RSRVED 715 +MX6Q_PAD_ENET_CRS_DV__ENET_RX_EN 716 +MX6Q_PAD_ENET_CRS_DV__ESAI1_SCKT 717 +MX6Q_PAD_ENET_CRS_DV__SPDIF_EXTCLK 718 +MX6Q_PAD_ENET_CRS_DV__GPIO_1_25 719 +MX6Q_PAD_ENET_CRS_DV__PHY_TDO 720 +MX6Q_PAD_ENET_CRS_DV__USBPHY1_RX_FS_RXD 721 +MX6Q_PAD_ENET_RXD1__MLB_MLBSIG 722 +MX6Q_PAD_ENET_RXD1__ENET_RDATA_1 723 +MX6Q_PAD_ENET_RXD1__ESAI1_FST 724 +MX6Q_PAD_ENET_RXD1__ENET_1588_EVT3_OUT 725 +MX6Q_PAD_ENET_RXD1__GPIO_1_26 726 +MX6Q_PAD_ENET_RXD1__PHY_TCK 727 +MX6Q_PAD_ENET_RXD1__USBPHY1_RX_DISCON 728 +MX6Q_PAD_ENET_RXD0__OSC32K_32K_OUT 729 +MX6Q_PAD_ENET_RXD0__ENET_RDATA_0 730 +MX6Q_PAD_ENET_RXD0__ESAI1_HCKT 731 +MX6Q_PAD_ENET_RXD0__SPDIF_OUT1 732 +MX6Q_PAD_ENET_RXD0__GPIO_1_27 733 +MX6Q_PAD_ENET_RXD0__PHY_TMS 734 +MX6Q_PAD_ENET_RXD0__USBPHY1_PLL_CK20DIV 735 +MX6Q_PAD_ENET_TX_EN__RESERVED_RSRVED 736 +MX6Q_PAD_ENET_TX_EN__ENET_TX_EN 737 +MX6Q_PAD_ENET_TX_EN__ESAI1_TX3_RX2 738 +MX6Q_PAD_ENET_TX_EN__GPIO_1_28 739 +MX6Q_PAD_ENET_TX_EN__SATA_PHY_TDI 740 +MX6Q_PAD_ENET_TX_EN__USBPHY2_RX_SQH 741 +MX6Q_PAD_ENET_TXD1__MLB_MLBCLK 742 +MX6Q_PAD_ENET_TXD1__ENET_TDATA_1 743 +MX6Q_PAD_ENET_TXD1__ESAI1_TX2_RX3 744 +MX6Q_PAD_ENET_TXD1__ENET_1588_EVENT0_IN 745 +MX6Q_PAD_ENET_TXD1__GPIO_1_29 746 +MX6Q_PAD_ENET_TXD1__SATA_PHY_TDO 747 +MX6Q_PAD_ENET_TXD1__USBPHY2_RX_HS_RXD 748 +MX6Q_PAD_ENET_TXD0__RESERVED_RSRVED 749 +MX6Q_PAD_ENET_TXD0__ENET_TDATA_0 750 +MX6Q_PAD_ENET_TXD0__ESAI1_TX4_RX1 751 +MX6Q_PAD_ENET_TXD0__GPIO_1_30 752 +MX6Q_PAD_ENET_TXD0__SATA_PHY_TCK 753 +MX6Q_PAD_ENET_TXD0__USBPHY2_RX_FS_RXD 754 +MX6Q_PAD_ENET_MDC__MLB_MLBDAT 755 +MX6Q_PAD_ENET_MDC__ENET_MDC 756 +MX6Q_PAD_ENET_MDC__ESAI1_TX5_RX0 757 +MX6Q_PAD_ENET_MDC__ENET_1588_EVENT1_IN 758 +MX6Q_PAD_ENET_MDC__GPIO_1_31 759 +MX6Q_PAD_ENET_MDC__SATA_PHY_TMS 760 +MX6Q_PAD_ENET_MDC__USBPHY2_RX_DISCON 761 +MX6Q_PAD_DRAM_D40__MMDC_DRAM_D_40 762 +MX6Q_PAD_DRAM_D41__MMDC_DRAM_D_41 763 +MX6Q_PAD_DRAM_D42__MMDC_DRAM_D_42 764 +MX6Q_PAD_DRAM_D43__MMDC_DRAM_D_43 765 +MX6Q_PAD_DRAM_D44__MMDC_DRAM_D_44 766 +MX6Q_PAD_DRAM_D45__MMDC_DRAM_D_45 767 +MX6Q_PAD_DRAM_D46__MMDC_DRAM_D_46 768 +MX6Q_PAD_DRAM_D47__MMDC_DRAM_D_47 769 +MX6Q_PAD_DRAM_SDQS5__MMDC_DRAM_SDQS_5 770 +MX6Q_PAD_DRAM_DQM5__MMDC_DRAM_DQM_5 771 +MX6Q_PAD_DRAM_D32__MMDC_DRAM_D_32 772 +MX6Q_PAD_DRAM_D33__MMDC_DRAM_D_33 773 +MX6Q_PAD_DRAM_D34__MMDC_DRAM_D_34 774 +MX6Q_PAD_DRAM_D35__MMDC_DRAM_D_35 775 +MX6Q_PAD_DRAM_D36__MMDC_DRAM_D_36 776 +MX6Q_PAD_DRAM_D37__MMDC_DRAM_D_37 777 +MX6Q_PAD_DRAM_D38__MMDC_DRAM_D_38 778 +MX6Q_PAD_DRAM_D39__MMDC_DRAM_D_39 779 +MX6Q_PAD_DRAM_DQM4__MMDC_DRAM_DQM_4 780 +MX6Q_PAD_DRAM_SDQS4__MMDC_DRAM_SDQS_4 781 +MX6Q_PAD_DRAM_D24__MMDC_DRAM_D_24 782 +MX6Q_PAD_DRAM_D25__MMDC_DRAM_D_25 783 +MX6Q_PAD_DRAM_D26__MMDC_DRAM_D_26 784 +MX6Q_PAD_DRAM_D27__MMDC_DRAM_D_27 785 +MX6Q_PAD_DRAM_D28__MMDC_DRAM_D_28 786 +MX6Q_PAD_DRAM_D29__MMDC_DRAM_D_29 787 +MX6Q_PAD_DRAM_SDQS3__MMDC_DRAM_SDQS_3 788 +MX6Q_PAD_DRAM_D30__MMDC_DRAM_D_30 789 +MX6Q_PAD_DRAM_D31__MMDC_DRAM_D_31 790 +MX6Q_PAD_DRAM_DQM3__MMDC_DRAM_DQM_3 791 +MX6Q_PAD_DRAM_D16__MMDC_DRAM_D_16 792 +MX6Q_PAD_DRAM_D17__MMDC_DRAM_D_17 793 +MX6Q_PAD_DRAM_D18__MMDC_DRAM_D_18 794 +MX6Q_PAD_DRAM_D19__MMDC_DRAM_D_19 795 +MX6Q_PAD_DRAM_D20__MMDC_DRAM_D_20 796 +MX6Q_PAD_DRAM_D21__MMDC_DRAM_D_21 797 +MX6Q_PAD_DRAM_D22__MMDC_DRAM_D_22 798 +MX6Q_PAD_DRAM_SDQS2__MMDC_DRAM_SDQS_2 799 +MX6Q_PAD_DRAM_D23__MMDC_DRAM_D_23 800 +MX6Q_PAD_DRAM_DQM2__MMDC_DRAM_DQM_2 801 +MX6Q_PAD_DRAM_A0__MMDC_DRAM_A_0 802 +MX6Q_PAD_DRAM_A1__MMDC_DRAM_A_1 803 +MX6Q_PAD_DRAM_A2__MMDC_DRAM_A_2 804 +MX6Q_PAD_DRAM_A3__MMDC_DRAM_A_3 805 +MX6Q_PAD_DRAM_A4__MMDC_DRAM_A_4 806 +MX6Q_PAD_DRAM_A5__MMDC_DRAM_A_5 807 +MX6Q_PAD_DRAM_A6__MMDC_DRAM_A_6 808 +MX6Q_PAD_DRAM_A7__MMDC_DRAM_A_7 809 +MX6Q_PAD_DRAM_A8__MMDC_DRAM_A_8 810 +MX6Q_PAD_DRAM_A9__MMDC_DRAM_A_9 811 +MX6Q_PAD_DRAM_A10__MMDC_DRAM_A_10 812 +MX6Q_PAD_DRAM_A11__MMDC_DRAM_A_11 813 +MX6Q_PAD_DRAM_A12__MMDC_DRAM_A_12 814 +MX6Q_PAD_DRAM_A13__MMDC_DRAM_A_13 815 +MX6Q_PAD_DRAM_A14__MMDC_DRAM_A_14 816 +MX6Q_PAD_DRAM_A15__MMDC_DRAM_A_15 817 +MX6Q_PAD_DRAM_CAS__MMDC_DRAM_CAS 818 +MX6Q_PAD_DRAM_CS0__MMDC_DRAM_CS_0 819 +MX6Q_PAD_DRAM_CS1__MMDC_DRAM_CS_1 820 +MX6Q_PAD_DRAM_RAS__MMDC_DRAM_RAS 821 +MX6Q_PAD_DRAM_RESET__MMDC_DRAM_RESET 822 +MX6Q_PAD_DRAM_SDBA0__MMDC_DRAM_SDBA_0 823 +MX6Q_PAD_DRAM_SDBA1__MMDC_DRAM_SDBA_1 824 +MX6Q_PAD_DRAM_SDCLK_0__MMDC_DRAM_SDCLK0 825 +MX6Q_PAD_DRAM_SDBA2__MMDC_DRAM_SDBA_2 826 +MX6Q_PAD_DRAM_SDCKE0__MMDC_DRAM_SDCKE_0 827 +MX6Q_PAD_DRAM_SDCLK_1__MMDC_DRAM_SDCLK1 828 +MX6Q_PAD_DRAM_SDCKE1__MMDC_DRAM_SDCKE_1 829 +MX6Q_PAD_DRAM_SDODT0__MMDC_DRAM_ODT_0 830 +MX6Q_PAD_DRAM_SDODT1__MMDC_DRAM_ODT_1 831 +MX6Q_PAD_DRAM_SDWE__MMDC_DRAM_SDWE 832 +MX6Q_PAD_DRAM_D0__MMDC_DRAM_D_0 833 +MX6Q_PAD_DRAM_D1__MMDC_DRAM_D_1 834 +MX6Q_PAD_DRAM_D2__MMDC_DRAM_D_2 835 +MX6Q_PAD_DRAM_D3__MMDC_DRAM_D_3 836 +MX6Q_PAD_DRAM_D4__MMDC_DRAM_D_4 837 +MX6Q_PAD_DRAM_D5__MMDC_DRAM_D_5 838 +MX6Q_PAD_DRAM_SDQS0__MMDC_DRAM_SDQS_0 839 +MX6Q_PAD_DRAM_D6__MMDC_DRAM_D_6 840 +MX6Q_PAD_DRAM_D7__MMDC_DRAM_D_7 841 +MX6Q_PAD_DRAM_DQM0__MMDC_DRAM_DQM_0 842 +MX6Q_PAD_DRAM_D8__MMDC_DRAM_D_8 843 +MX6Q_PAD_DRAM_D9__MMDC_DRAM_D_9 844 +MX6Q_PAD_DRAM_D10__MMDC_DRAM_D_10 845 +MX6Q_PAD_DRAM_D11__MMDC_DRAM_D_11 846 +MX6Q_PAD_DRAM_D12__MMDC_DRAM_D_12 847 +MX6Q_PAD_DRAM_D13__MMDC_DRAM_D_13 848 +MX6Q_PAD_DRAM_D14__MMDC_DRAM_D_14 849 +MX6Q_PAD_DRAM_SDQS1__MMDC_DRAM_SDQS_1 850 +MX6Q_PAD_DRAM_D15__MMDC_DRAM_D_15 851 +MX6Q_PAD_DRAM_DQM1__MMDC_DRAM_DQM_1 852 +MX6Q_PAD_DRAM_D48__MMDC_DRAM_D_48 853 +MX6Q_PAD_DRAM_D49__MMDC_DRAM_D_49 854 +MX6Q_PAD_DRAM_D50__MMDC_DRAM_D_50 855 +MX6Q_PAD_DRAM_D51__MMDC_DRAM_D_51 856 +MX6Q_PAD_DRAM_D52__MMDC_DRAM_D_52 857 +MX6Q_PAD_DRAM_D53__MMDC_DRAM_D_53 858 +MX6Q_PAD_DRAM_D54__MMDC_DRAM_D_54 859 +MX6Q_PAD_DRAM_D55__MMDC_DRAM_D_55 860 +MX6Q_PAD_DRAM_SDQS6__MMDC_DRAM_SDQS_6 861 +MX6Q_PAD_DRAM_DQM6__MMDC_DRAM_DQM_6 862 +MX6Q_PAD_DRAM_D56__MMDC_DRAM_D_56 863 +MX6Q_PAD_DRAM_SDQS7__MMDC_DRAM_SDQS_7 864 +MX6Q_PAD_DRAM_D57__MMDC_DRAM_D_57 865 +MX6Q_PAD_DRAM_D58__MMDC_DRAM_D_58 866 +MX6Q_PAD_DRAM_D59__MMDC_DRAM_D_59 867 +MX6Q_PAD_DRAM_D60__MMDC_DRAM_D_60 868 +MX6Q_PAD_DRAM_DQM7__MMDC_DRAM_DQM_7 869 +MX6Q_PAD_DRAM_D61__MMDC_DRAM_D_61 870 +MX6Q_PAD_DRAM_D62__MMDC_DRAM_D_62 871 +MX6Q_PAD_DRAM_D63__MMDC_DRAM_D_63 872 +MX6Q_PAD_KEY_COL0__ECSPI1_SCLK 873 +MX6Q_PAD_KEY_COL0__ENET_RDATA_3 874 +MX6Q_PAD_KEY_COL0__AUDMUX_AUD5_TXC 875 +MX6Q_PAD_KEY_COL0__KPP_COL_0 876 +MX6Q_PAD_KEY_COL0__UART4_TXD 877 +MX6Q_PAD_KEY_COL0__GPIO_4_6 878 +MX6Q_PAD_KEY_COL0__DCIC1_DCIC_OUT 879 +MX6Q_PAD_KEY_COL0__SRC_ANY_PU_RST 880 +MX6Q_PAD_KEY_ROW0__ECSPI1_MOSI 881 +MX6Q_PAD_KEY_ROW0__ENET_TDATA_3 882 +MX6Q_PAD_KEY_ROW0__AUDMUX_AUD5_TXD 883 +MX6Q_PAD_KEY_ROW0__KPP_ROW_0 884 +MX6Q_PAD_KEY_ROW0__UART4_RXD 885 +MX6Q_PAD_KEY_ROW0__GPIO_4_7 886 +MX6Q_PAD_KEY_ROW0__DCIC2_DCIC_OUT 887 +MX6Q_PAD_KEY_ROW0__PL301_PER1_HADR_0 888 +MX6Q_PAD_KEY_COL1__ECSPI1_MISO 889 +MX6Q_PAD_KEY_COL1__ENET_MDIO 890 +MX6Q_PAD_KEY_COL1__AUDMUX_AUD5_TXFS 891 +MX6Q_PAD_KEY_COL1__KPP_COL_1 892 +MX6Q_PAD_KEY_COL1__UART5_TXD 893 +MX6Q_PAD_KEY_COL1__GPIO_4_8 894 +MX6Q_PAD_KEY_COL1__USDHC1_VSELECT 895 +MX6Q_PAD_KEY_COL1__PL301MX_PER1_HADR_1 896 +MX6Q_PAD_KEY_ROW1__ECSPI1_SS0 897 +MX6Q_PAD_KEY_ROW1__ENET_COL 898 +MX6Q_PAD_KEY_ROW1__AUDMUX_AUD5_RXD 899 +MX6Q_PAD_KEY_ROW1__KPP_ROW_1 900 +MX6Q_PAD_KEY_ROW1__UART5_RXD 901 +MX6Q_PAD_KEY_ROW1__GPIO_4_9 902 +MX6Q_PAD_KEY_ROW1__USDHC2_VSELECT 903 +MX6Q_PAD_KEY_ROW1__PL301_PER1_HADDR_2 904 +MX6Q_PAD_KEY_COL2__ECSPI1_SS1 905 +MX6Q_PAD_KEY_COL2__ENET_RDATA_2 906 +MX6Q_PAD_KEY_COL2__CAN1_TXCAN 907 +MX6Q_PAD_KEY_COL2__KPP_COL_2 908 +MX6Q_PAD_KEY_COL2__ENET_MDC 909 +MX6Q_PAD_KEY_COL2__GPIO_4_10 910 +MX6Q_PAD_KEY_COL2__USBOH3_H1_PWRCTL_WKP 911 +MX6Q_PAD_KEY_COL2__PL301_PER1_HADDR_3 912 +MX6Q_PAD_KEY_ROW2__ECSPI1_SS2 913 +MX6Q_PAD_KEY_ROW2__ENET_TDATA_2 914 +MX6Q_PAD_KEY_ROW2__CAN1_RXCAN 915 +MX6Q_PAD_KEY_ROW2__KPP_ROW_2 916 +MX6Q_PAD_KEY_ROW2__USDHC2_VSELECT 917 +MX6Q_PAD_KEY_ROW2__GPIO_4_11 918 +MX6Q_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 919 +MX6Q_PAD_KEY_ROW2__PL301_PER1_HADR_4 920 +MX6Q_PAD_KEY_COL3__ECSPI1_SS3 921 +MX6Q_PAD_KEY_COL3__ENET_CRS 922 +MX6Q_PAD_KEY_COL3__HDMI_TX_DDC_SCL 923 +MX6Q_PAD_KEY_COL3__KPP_COL_3 924 +MX6Q_PAD_KEY_COL3__I2C2_SCL 925 +MX6Q_PAD_KEY_COL3__GPIO_4_12 926 +MX6Q_PAD_KEY_COL3__SPDIF_IN1 927 +MX6Q_PAD_KEY_COL3__PL301_PER1_HADR_5 928 +MX6Q_PAD_KEY_ROW3__OSC32K_32K_OUT 929 +MX6Q_PAD_KEY_ROW3__ASRC_ASRC_EXT_CLK 930 +MX6Q_PAD_KEY_ROW3__HDMI_TX_DDC_SDA 931 +MX6Q_PAD_KEY_ROW3__KPP_ROW_3 932 +MX6Q_PAD_KEY_ROW3__I2C2_SDA 933 +MX6Q_PAD_KEY_ROW3__GPIO_4_13 934 +MX6Q_PAD_KEY_ROW3__USDHC1_VSELECT 935 +MX6Q_PAD_KEY_ROW3__PL301_PER1_HADR_6 936 +MX6Q_PAD_KEY_COL4__CAN2_TXCAN 937 +MX6Q_PAD_KEY_COL4__IPU1_SISG_4 938 +MX6Q_PAD_KEY_COL4__USBOH3_USBOTG_OC 939 +MX6Q_PAD_KEY_COL4__KPP_COL_4 940 +MX6Q_PAD_KEY_COL4__UART5_RTS 941 +MX6Q_PAD_KEY_COL4__GPIO_4_14 942 +MX6Q_PAD_KEY_COL4__MMDC_DEBUG_49 943 +MX6Q_PAD_KEY_COL4__PL301_PER1_HADDR_7 944 +MX6Q_PAD_KEY_ROW4__CAN2_RXCAN 945 +MX6Q_PAD_KEY_ROW4__IPU1_SISG_5 946 +MX6Q_PAD_KEY_ROW4__USBOH3_USBOTG_PWR 947 +MX6Q_PAD_KEY_ROW4__KPP_ROW_4 948 +MX6Q_PAD_KEY_ROW4__UART5_CTS 949 +MX6Q_PAD_KEY_ROW4__GPIO_4_15 950 +MX6Q_PAD_KEY_ROW4__MMDC_DEBUG_50 951 +MX6Q_PAD_KEY_ROW4__PL301_PER1_HADR_8 952 +MX6Q_PAD_GPIO_0__CCM_CLKO 953 +MX6Q_PAD_GPIO_0__KPP_COL_5 954 +MX6Q_PAD_GPIO_0__ASRC_ASRC_EXT_CLK 955 +MX6Q_PAD_GPIO_0__EPIT1_EPITO 956 +MX6Q_PAD_GPIO_0__GPIO_1_0 957 +MX6Q_PAD_GPIO_0__USBOH3_USBH1_PWR 958 +MX6Q_PAD_GPIO_0__SNVS_HP_WRAP_SNVS_VIO5 959 +MX6Q_PAD_GPIO_1__ESAI1_SCKR 960 +MX6Q_PAD_GPIO_1__WDOG2_WDOG_B 961 +MX6Q_PAD_GPIO_1__KPP_ROW_5 962 +MX6Q_PAD_GPIO_1__PWM2_PWMO 963 +MX6Q_PAD_GPIO_1__GPIO_1_1 964 +MX6Q_PAD_GPIO_1__USDHC1_CD 965 +MX6Q_PAD_GPIO_1__SRC_TESTER_ACK 966 +MX6Q_PAD_GPIO_9__ESAI1_FSR 967 +MX6Q_PAD_GPIO_9__WDOG1_WDOG_B 968 +MX6Q_PAD_GPIO_9__KPP_COL_6 969 +MX6Q_PAD_GPIO_9__CCM_REF_EN_B 970 +MX6Q_PAD_GPIO_9__PWM1_PWMO 971 +MX6Q_PAD_GPIO_9__GPIO_1_9 972 +MX6Q_PAD_GPIO_9__USDHC1_WP 973 +MX6Q_PAD_GPIO_9__SRC_EARLY_RST 974 +MX6Q_PAD_GPIO_3__ESAI1_HCKR 975 +MX6Q_PAD_GPIO_3__OBSERVE_MUX_INT_OUT0 976 +MX6Q_PAD_GPIO_3__I2C3_SCL 977 +MX6Q_PAD_GPIO_3__ANATOP_24M_OUT 978 +MX6Q_PAD_GPIO_3__CCM_CLKO2 979 +MX6Q_PAD_GPIO_3__GPIO_1_3 980 +MX6Q_PAD_GPIO_3__USBOH3_USBH1_OC 981 +MX6Q_PAD_GPIO_3__MLB_MLBCLK 982 +MX6Q_PAD_GPIO_6__ESAI1_SCKT 983 +MX6Q_PAD_GPIO_6__OBSERVE_MUX_INT_OUT1 984 +MX6Q_PAD_GPIO_6__I2C3_SDA 985 +MX6Q_PAD_GPIO_6__CCM_CCM_OUT_0 986 +MX6Q_PAD_GPIO_6__CSU_CSU_INT_DEB 987 +MX6Q_PAD_GPIO_6__GPIO_1_6 988 +MX6Q_PAD_GPIO_6__USDHC2_LCTL 989 +MX6Q_PAD_GPIO_6__MLB_MLBSIG 990 +MX6Q_PAD_GPIO_2__ESAI1_FST 991 +MX6Q_PAD_GPIO_2__OBSERVE_MUX_INT_OUT2 992 +MX6Q_PAD_GPIO_2__KPP_ROW_6 993 +MX6Q_PAD_GPIO_2__CCM_CCM_OUT_1 994 +MX6Q_PAD_GPIO_2__CSU_CSU_ALARM_AUT_0 995 +MX6Q_PAD_GPIO_2__GPIO_1_2 996 +MX6Q_PAD_GPIO_2__USDHC2_WP 997 +MX6Q_PAD_GPIO_2__MLB_MLBDAT 998 +MX6Q_PAD_GPIO_4__ESAI1_HCKT 999 +MX6Q_PAD_GPIO_4__OBSERVE_MUX_INT_OUT3 1000 +MX6Q_PAD_GPIO_4__KPP_COL_7 1001 +MX6Q_PAD_GPIO_4__CCM_CCM_OUT_2 1002 +MX6Q_PAD_GPIO_4__CSU_CSU_ALARM_AUT_1 1003 +MX6Q_PAD_GPIO_4__GPIO_1_4 1004 +MX6Q_PAD_GPIO_4__USDHC2_CD 1005 +MX6Q_PAD_GPIO_4__OCOTP_CRL_WRAR_FUSE_LA 1006 +MX6Q_PAD_GPIO_5__ESAI1_TX2_RX3 1007 +MX6Q_PAD_GPIO_5__OBSERVE_MUX_INT_OUT4 1008 +MX6Q_PAD_GPIO_5__KPP_ROW_7 1009 +MX6Q_PAD_GPIO_5__CCM_CLKO 1010 +MX6Q_PAD_GPIO_5__CSU_CSU_ALARM_AUT_2 1011 +MX6Q_PAD_GPIO_5__GPIO_1_5 1012 +MX6Q_PAD_GPIO_5__I2C3_SCL 1013 +MX6Q_PAD_GPIO_5__CHEETAH_EVENTI 1014 +MX6Q_PAD_GPIO_7__ESAI1_TX4_RX1 1015 +MX6Q_PAD_GPIO_7__ECSPI5_RDY 1016 +MX6Q_PAD_GPIO_7__EPIT1_EPITO 1017 +MX6Q_PAD_GPIO_7__CAN1_TXCAN 1018 +MX6Q_PAD_GPIO_7__UART2_TXD 1019 +MX6Q_PAD_GPIO_7__GPIO_1_7 1020 +MX6Q_PAD_GPIO_7__SPDIF_PLOCK 1021 +MX6Q_PAD_GPIO_7__USBOH3_OTGUSB_HST_MODE 1022 +MX6Q_PAD_GPIO_8__ESAI1_TX5_RX0 1023 +MX6Q_PAD_GPIO_8__ANATOP_ANATOP_32K_OUT 1024 +MX6Q_PAD_GPIO_8__EPIT2_EPITO 1025 +MX6Q_PAD_GPIO_8__CAN1_RXCAN 1026 +MX6Q_PAD_GPIO_8__UART2_RXD 1027 +MX6Q_PAD_GPIO_8__GPIO_1_8 1028 +MX6Q_PAD_GPIO_8__SPDIF_SRCLK 1029 +MX6Q_PAD_GPIO_8__USBOH3_OTG_PWRCTL_WAK 1030 +MX6Q_PAD_GPIO_16__ESAI1_TX3_RX2 1031 +MX6Q_PAD_GPIO_16__ENET_1588_EVENT2_IN 1032 +MX6Q_PAD_GPIO_16__ENET_ETHERNET_REF_OUT 1033 +MX6Q_PAD_GPIO_16__USDHC1_LCTL 1034 +MX6Q_PAD_GPIO_16__SPDIF_IN1 1035 +MX6Q_PAD_GPIO_16__GPIO_7_11 1036 +MX6Q_PAD_GPIO_16__I2C3_SDA 1037 +MX6Q_PAD_GPIO_16__SJC_DE_B 1038 +MX6Q_PAD_GPIO_17__ESAI1_TX0 1039 +MX6Q_PAD_GPIO_17__ENET_1588_EVENT3_IN 1040 +MX6Q_PAD_GPIO_17__CCM_PMIC_RDY 1041 +MX6Q_PAD_GPIO_17__SDMA_SDMA_EXT_EVENT_0 1042 +MX6Q_PAD_GPIO_17__SPDIF_OUT1 1043 +MX6Q_PAD_GPIO_17__GPIO_7_12 1044 +MX6Q_PAD_GPIO_17__SJC_JTAG_ACT 1045 +MX6Q_PAD_GPIO_18__ESAI1_TX1 1046 +MX6Q_PAD_GPIO_18__ENET_RX_CLK 1047 +MX6Q_PAD_GPIO_18__USDHC3_VSELECT 1048 +MX6Q_PAD_GPIO_18__SDMA_SDMA_EXT_EVENT_1 1049 +MX6Q_PAD_GPIO_18__ASRC_ASRC_EXT_CLK 1050 +MX6Q_PAD_GPIO_18__GPIO_7_13 1051 +MX6Q_PAD_GPIO_18__SNVS_HP_WRA_SNVS_VIO5 1052 +MX6Q_PAD_GPIO_18__SRC_SYSTEM_RST 1053 +MX6Q_PAD_GPIO_19__KPP_COL_5 1054 +MX6Q_PAD_GPIO_19__ENET_1588_EVENT0_OUT 1055 +MX6Q_PAD_GPIO_19__SPDIF_OUT1 1056 +MX6Q_PAD_GPIO_19__CCM_CLKO 1057 +MX6Q_PAD_GPIO_19__ECSPI1_RDY 1058 +MX6Q_PAD_GPIO_19__GPIO_4_5 1059 +MX6Q_PAD_GPIO_19__ENET_TX_ER 1060 +MX6Q_PAD_GPIO_19__SRC_INT_BOOT 1061 +MX6Q_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK 1062 +MX6Q_PAD_CSI0_PIXCLK__PCIE_CTRL_MUX_12 1063 +MX6Q_PAD_CSI0_PIXCLK__SDMA_DEBUG_PC_0 1064 +MX6Q_PAD_CSI0_PIXCLK__GPIO_5_18 1065 +MX6Q_PAD_CSI0_PIXCLK___MMDC_DEBUG_29 1066 +MX6Q_PAD_CSI0_PIXCLK__CHEETAH_EVENTO 1067 +MX6Q_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC 1068 +MX6Q_PAD_CSI0_MCLK__PCIE_CTRL_MUX_13 1069 +MX6Q_PAD_CSI0_MCLK__CCM_CLKO 1070 +MX6Q_PAD_CSI0_MCLK__SDMA_DEBUG_PC_1 1071 +MX6Q_PAD_CSI0_MCLK__GPIO_5_19 1072 +MX6Q_PAD_CSI0_MCLK__MMDC_MMDC_DEBUG_30 1073 +MX6Q_PAD_CSI0_MCLK__CHEETAH_TRCTL 1074 +MX6Q_PAD_CSI0_DATA_EN__IPU1_CSI0_DA_EN 1075 +MX6Q_PAD_CSI0_DATA_EN__WEIM_WEIM_D_0 1076 +MX6Q_PAD_CSI0_DATA_EN__PCIE_CTRL_MUX_14 1077 +MX6Q_PAD_CSI0_DATA_EN__SDMA_DEBUG_PC_2 1078 +MX6Q_PAD_CSI0_DATA_EN__GPIO_5_20 1079 +MX6Q_PAD_CSI0_DATA_EN__MMDC_DEBUG_31 1080 +MX6Q_PAD_CSI0_DATA_EN__CHEETAH_TRCLK 1081 +MX6Q_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC 1082 +MX6Q_PAD_CSI0_VSYNC__WEIM_WEIM_D_1 1083 +MX6Q_PAD_CSI0_VSYNC__PCIE_CTRL_MUX_15 1084 +MX6Q_PAD_CSI0_VSYNC__SDMA_DEBUG_PC_3 1085 +MX6Q_PAD_CSI0_VSYNC__GPIO_5_21 1086 +MX6Q_PAD_CSI0_VSYNC__MMDC_DEBUG_32 1087 +MX6Q_PAD_CSI0_VSYNC__CHEETAH_TRACE_0 1088 +MX6Q_PAD_CSI0_DAT4__IPU1_CSI0_D_4 1089 +MX6Q_PAD_CSI0_DAT4__WEIM_WEIM_D_2 1090 +MX6Q_PAD_CSI0_DAT4__ECSPI1_SCLK 1091 +MX6Q_PAD_CSI0_DAT4__KPP_COL_5 1092 +MX6Q_PAD_CSI0_DAT4__AUDMUX_AUD3_TXC 1093 +MX6Q_PAD_CSI0_DAT4__GPIO_5_22 1094 +MX6Q_PAD_CSI0_DAT4__MMDC_DEBUG_43 1095 +MX6Q_PAD_CSI0_DAT4__CHEETAH_TRACE_1 1096 +MX6Q_PAD_CSI0_DAT5__IPU1_CSI0_D_5 1097 +MX6Q_PAD_CSI0_DAT5__WEIM_WEIM_D_3 1098 +MX6Q_PAD_CSI0_DAT5__ECSPI1_MOSI 1099 +MX6Q_PAD_CSI0_DAT5__KPP_ROW_5 1100 +MX6Q_PAD_CSI0_DAT5__AUDMUX_AUD3_TXD 1101 +MX6Q_PAD_CSI0_DAT5__GPIO_5_23 1102 +MX6Q_PAD_CSI0_DAT5__MMDC_MMDC_DEBUG_44 1103 +MX6Q_PAD_CSI0_DAT5__CHEETAH_TRACE_2 1104 +MX6Q_PAD_CSI0_DAT6__IPU1_CSI0_D_6 1105 +MX6Q_PAD_CSI0_DAT6__WEIM_WEIM_D_4 1106 +MX6Q_PAD_CSI0_DAT6__ECSPI1_MISO 1107 +MX6Q_PAD_CSI0_DAT6__KPP_COL_6 1108 +MX6Q_PAD_CSI0_DAT6__AUDMUX_AUD3_TXFS 1109 +MX6Q_PAD_CSI0_DAT6__GPIO_5_24 1110 +MX6Q_PAD_CSI0_DAT6__MMDC_MMDC_DEBUG_45 1111 +MX6Q_PAD_CSI0_DAT6__CHEETAH_TRACE_3 1112 +MX6Q_PAD_CSI0_DAT7__IPU1_CSI0_D_7 1113 +MX6Q_PAD_CSI0_DAT7__WEIM_WEIM_D_5 1114 +MX6Q_PAD_CSI0_DAT7__ECSPI1_SS0 1115 +MX6Q_PAD_CSI0_DAT7__KPP_ROW_6 1116 +MX6Q_PAD_CSI0_DAT7__AUDMUX_AUD3_RXD 1117 +MX6Q_PAD_CSI0_DAT7__GPIO_5_25 1118 +MX6Q_PAD_CSI0_DAT7__MMDC_MMDC_DEBUG_46 1119 +MX6Q_PAD_CSI0_DAT7__CHEETAH_TRACE_4 1120 +MX6Q_PAD_CSI0_DAT8__IPU1_CSI0_D_8 1121 +MX6Q_PAD_CSI0_DAT8__WEIM_WEIM_D_6 1122 +MX6Q_PAD_CSI0_DAT8__ECSPI2_SCLK 1123 +MX6Q_PAD_CSI0_DAT8__KPP_COL_7 1124 +MX6Q_PAD_CSI0_DAT8__I2C1_SDA 1125 +MX6Q_PAD_CSI0_DAT8__GPIO_5_26 1126 +MX6Q_PAD_CSI0_DAT8__MMDC_MMDC_DEBUG_47 1127 +MX6Q_PAD_CSI0_DAT8__CHEETAH_TRACE_5 1128 +MX6Q_PAD_CSI0_DAT9__IPU1_CSI0_D_9 1129 +MX6Q_PAD_CSI0_DAT9__WEIM_WEIM_D_7 1130 +MX6Q_PAD_CSI0_DAT9__ECSPI2_MOSI 1131 +MX6Q_PAD_CSI0_DAT9__KPP_ROW_7 1132 +MX6Q_PAD_CSI0_DAT9__I2C1_SCL 1133 +MX6Q_PAD_CSI0_DAT9__GPIO_5_27 1134 +MX6Q_PAD_CSI0_DAT9__MMDC_MMDC_DEBUG_48 1135 +MX6Q_PAD_CSI0_DAT9__CHEETAH_TRACE_6 1136 +MX6Q_PAD_CSI0_DAT10__IPU1_CSI0_D_10 1137 +MX6Q_PAD_CSI0_DAT10__AUDMUX_AUD3_RXC 1138 +MX6Q_PAD_CSI0_DAT10__ECSPI2_MISO 1139 +MX6Q_PAD_CSI0_DAT10__UART1_TXD 1140 +MX6Q_PAD_CSI0_DAT10__SDMA_DEBUG_PC_4 1141 +MX6Q_PAD_CSI0_DAT10__GPIO_5_28 1142 +MX6Q_PAD_CSI0_DAT10__MMDC_MMDC_DEBUG_33 1143 +MX6Q_PAD_CSI0_DAT10__CHEETAH_TRACE_7 1144 +MX6Q_PAD_CSI0_DAT11__IPU1_CSI0_D_11 1145 +MX6Q_PAD_CSI0_DAT11__AUDMUX_AUD3_RXFS 1146 +MX6Q_PAD_CSI0_DAT11__ECSPI2_SS0 1147 +MX6Q_PAD_CSI0_DAT11__UART1_RXD 1148 +MX6Q_PAD_CSI0_DAT11__SDMA_DEBUG_PC_5 1149 +MX6Q_PAD_CSI0_DAT11__GPIO_5_29 1150 +MX6Q_PAD_CSI0_DAT11__MMDC_MMDC_DEBUG_34 1151 +MX6Q_PAD_CSI0_DAT11__CHEETAH_TRACE_8 1152 +MX6Q_PAD_CSI0_DAT12__IPU1_CSI0_D_12 1153 +MX6Q_PAD_CSI0_DAT12__WEIM_WEIM_D_8 1154 +MX6Q_PAD_CSI0_DAT12__PCIE_CTRL_MUX_16 1155 +MX6Q_PAD_CSI0_DAT12__UART4_TXD 1156 +MX6Q_PAD_CSI0_DAT12__SDMA_DEBUG_PC_6 1157 +MX6Q_PAD_CSI0_DAT12__GPIO_5_30 1158 +MX6Q_PAD_CSI0_DAT12__MMDC_MMDC_DEBUG_35 1159 +MX6Q_PAD_CSI0_DAT12__CHEETAH_TRACE_9 1160 +MX6Q_PAD_CSI0_DAT13__IPU1_CSI0_D_13 1161 +MX6Q_PAD_CSI0_DAT13__WEIM_WEIM_D_9 1162 +MX6Q_PAD_CSI0_DAT13__PCIE_CTRL_MUX_17 1163 +MX6Q_PAD_CSI0_DAT13__UART4_RXD 1164 +MX6Q_PAD_CSI0_DAT13__SDMA_DEBUG_PC_7 1165 +MX6Q_PAD_CSI0_DAT13__GPIO_5_31 1166 +MX6Q_PAD_CSI0_DAT13__MMDC_MMDC_DEBUG_36 1167 +MX6Q_PAD_CSI0_DAT13__CHEETAH_TRACE_10 1168 +MX6Q_PAD_CSI0_DAT14__IPU1_CSI0_D_14 1169 +MX6Q_PAD_CSI0_DAT14__WEIM_WEIM_D_10 1170 +MX6Q_PAD_CSI0_DAT14__PCIE_CTRL_MUX_18 1171 +MX6Q_PAD_CSI0_DAT14__UART5_TXD 1172 +MX6Q_PAD_CSI0_DAT14__SDMA_DEBUG_PC_8 1173 +MX6Q_PAD_CSI0_DAT14__GPIO_6_0 1174 +MX6Q_PAD_CSI0_DAT14__MMDC_MMDC_DEBUG_37 1175 +MX6Q_PAD_CSI0_DAT14__CHEETAH_TRACE_11 1176 +MX6Q_PAD_CSI0_DAT15__IPU1_CSI0_D_15 1177 +MX6Q_PAD_CSI0_DAT15__WEIM_WEIM_D_11 1178 +MX6Q_PAD_CSI0_DAT15__PCIE_CTRL_MUX_19 1179 +MX6Q_PAD_CSI0_DAT15__UART5_RXD 1180 +MX6Q_PAD_CSI0_DAT15__SDMA_DEBUG_PC_9 1181 +MX6Q_PAD_CSI0_DAT15__GPIO_6_1 1182 +MX6Q_PAD_CSI0_DAT15__MMDC_MMDC_DEBUG_38 1183 +MX6Q_PAD_CSI0_DAT15__CHEETAH_TRACE_12 1184 +MX6Q_PAD_CSI0_DAT16__IPU1_CSI0_D_16 1185 +MX6Q_PAD_CSI0_DAT16__WEIM_WEIM_D_12 1186 +MX6Q_PAD_CSI0_DAT16__PCIE_CTRL_MUX_20 1187 +MX6Q_PAD_CSI0_DAT16__UART4_RTS 1188 +MX6Q_PAD_CSI0_DAT16__SDMA_DEBUG_PC_10 1189 +MX6Q_PAD_CSI0_DAT16__GPIO_6_2 1190 +MX6Q_PAD_CSI0_DAT16__MMDC_MMDC_DEBUG_39 1191 +MX6Q_PAD_CSI0_DAT16__CHEETAH_TRACE_13 1192 +MX6Q_PAD_CSI0_DAT17__IPU1_CSI0_D_17 1193 +MX6Q_PAD_CSI0_DAT17__WEIM_WEIM_D_13 1194 +MX6Q_PAD_CSI0_DAT17__PCIE_CTRL_MUX_21 1195 +MX6Q_PAD_CSI0_DAT17__UART4_CTS 1196 +MX6Q_PAD_CSI0_DAT17__SDMA_DEBUG_PC_11 1197 +MX6Q_PAD_CSI0_DAT17__GPIO_6_3 1198 +MX6Q_PAD_CSI0_DAT17__MMDC_MMDC_DEBUG_40 1199 +MX6Q_PAD_CSI0_DAT17__CHEETAH_TRACE_14 1200 +MX6Q_PAD_CSI0_DAT18__IPU1_CSI0_D_18 1201 +MX6Q_PAD_CSI0_DAT18__WEIM_WEIM_D_14 1202 +MX6Q_PAD_CSI0_DAT18__PCIE_CTRL_MUX_22 1203 +MX6Q_PAD_CSI0_DAT18__UART5_RTS 1204 +MX6Q_PAD_CSI0_DAT18__SDMA_DEBUG_PC_12 1205 +MX6Q_PAD_CSI0_DAT18__GPIO_6_4 1206 +MX6Q_PAD_CSI0_DAT18__MMDC_MMDC_DEBUG_41 1207 +MX6Q_PAD_CSI0_DAT18__CHEETAH_TRACE_15 1208 +MX6Q_PAD_CSI0_DAT19__IPU1_CSI0_D_19 1209 +MX6Q_PAD_CSI0_DAT19__WEIM_WEIM_D_15 1210 +MX6Q_PAD_CSI0_DAT19__PCIE_CTRL_MUX_23 1211 +MX6Q_PAD_CSI0_DAT19__UART5_CTS 1212 +MX6Q_PAD_CSI0_DAT19__SDMA_DEBUG_PC_13 1213 +MX6Q_PAD_CSI0_DAT19__GPIO_6_5 1214 +MX6Q_PAD_CSI0_DAT19__MMDC_MMDC_DEBUG_42 1215 +MX6Q_PAD_CSI0_DAT19__ANATOP_TESTO_9 1216 +MX6Q_PAD_JTAG_TMS__SJC_TMS 1217 +MX6Q_PAD_JTAG_MOD__SJC_MOD 1218 +MX6Q_PAD_JTAG_TRSTB__SJC_TRSTB 1219 +MX6Q_PAD_JTAG_TDI__SJC_TDI 1220 +MX6Q_PAD_JTAG_TCK__SJC_TCK 1221 +MX6Q_PAD_JTAG_TDO__SJC_TDO 1222 +MX6Q_PAD_LVDS1_TX3_P__LDB_LVDS1_TX3 1223 +MX6Q_PAD_LVDS1_TX2_P__LDB_LVDS1_TX2 1224 +MX6Q_PAD_LVDS1_CLK_P__LDB_LVDS1_CLK 1225 +MX6Q_PAD_LVDS1_TX1_P__LDB_LVDS1_TX1 1226 +MX6Q_PAD_LVDS1_TX0_P__LDB_LVDS1_TX0 1227 +MX6Q_PAD_LVDS0_TX3_P__LDB_LVDS0_TX3 1228 +MX6Q_PAD_LVDS0_CLK_P__LDB_LVDS0_CLK 1229 +MX6Q_PAD_LVDS0_TX2_P__LDB_LVDS0_TX2 1230 +MX6Q_PAD_LVDS0_TX1_P__LDB_LVDS0_TX1 1231 +MX6Q_PAD_LVDS0_TX0_P__LDB_LVDS0_TX0 1232 +MX6Q_PAD_TAMPER__SNVS_LP_WRAP_SNVS_TD1 1233 +MX6Q_PAD_PMIC_ON_REQ__SNVS_LPWRAP_WKALM 1234 +MX6Q_PAD_PMIC_STBY_REQ__CCM_PMIC_STBYRQ 1235 +MX6Q_PAD_POR_B__SRC_POR_B 1236 +MX6Q_PAD_BOOT_MODE1__SRC_BOOT_MODE_1 1237 +MX6Q_PAD_RESET_IN_B__SRC_RESET_B 1238 +MX6Q_PAD_BOOT_MODE0__SRC_BOOT_MODE_0 1239 +MX6Q_PAD_TEST_MODE__TCU_TEST_MODE 1240 +MX6Q_PAD_SD3_DAT7__USDHC3_DAT7 1241 +MX6Q_PAD_SD3_DAT7__UART1_TXD 1242 +MX6Q_PAD_SD3_DAT7__PCIE_CTRL_MUX_24 1243 +MX6Q_PAD_SD3_DAT7__USBOH3_UH3_DFD_OUT_0 1244 +MX6Q_PAD_SD3_DAT7__USBOH3_UH2_DFD_OUT_0 1245 +MX6Q_PAD_SD3_DAT7__GPIO_6_17 1246 +MX6Q_PAD_SD3_DAT7__MIPI_CORE_DPHY_IN_12 1247 +MX6Q_PAD_SD3_DAT7__USBPHY2_CLK20DIV 1248 +MX6Q_PAD_SD3_DAT6__USDHC3_DAT6 1249 +MX6Q_PAD_SD3_DAT6__UART1_RXD 1250 +MX6Q_PAD_SD3_DAT6__PCIE_CTRL_MUX_25 1251 +MX6Q_PAD_SD3_DAT6__USBOH3_UH3_DFD_OUT_1 1252 +MX6Q_PAD_SD3_DAT6__USBOH3_UH2_DFD_OUT_1 1253 +MX6Q_PAD_SD3_DAT6__GPIO_6_18 1254 +MX6Q_PAD_SD3_DAT6__MIPI_CORE_DPHY_IN_13 1255 +MX6Q_PAD_SD3_DAT6__ANATOP_TESTO_10 1256 +MX6Q_PAD_SD3_DAT5__USDHC3_DAT5 1257 +MX6Q_PAD_SD3_DAT5__UART2_TXD 1258 +MX6Q_PAD_SD3_DAT5__PCIE_CTRL_MUX_26 1259 +MX6Q_PAD_SD3_DAT5__USBOH3_UH3_DFD_OUT_2 1260 +MX6Q_PAD_SD3_DAT5__USBOH3_UH2_DFD_OUT_2 1261 +MX6Q_PAD_SD3_DAT5__GPIO_7_0 1262 +MX6Q_PAD_SD3_DAT5__MIPI_CORE_DPHY_IN_14 1263 +MX6Q_PAD_SD3_DAT5__ANATOP_TESTO_11 1264 +MX6Q_PAD_SD3_DAT4__USDHC3_DAT4 1265 +MX6Q_PAD_SD3_DAT4__UART2_RXD 1266 +MX6Q_PAD_SD3_DAT4__PCIE_CTRL_MUX_27 1267 +MX6Q_PAD_SD3_DAT4__USBOH3_UH3_DFD_OUT_3 1268 +MX6Q_PAD_SD3_DAT4__USBOH3_UH2_DFD_OUT_3 1269 +MX6Q_PAD_SD3_DAT4__GPIO_7_1 1270 +MX6Q_PAD_SD3_DAT4__MIPI_CORE_DPHY_IN_15 1271 +MX6Q_PAD_SD3_DAT4__ANATOP_TESTO_12 1272 +MX6Q_PAD_SD3_CMD__USDHC3_CMD 1273 +MX6Q_PAD_SD3_CMD__UART2_CTS 1274 +MX6Q_PAD_SD3_CMD__CAN1_TXCAN 1275 +MX6Q_PAD_SD3_CMD__USBOH3_UH3_DFD_OUT_4 1276 +MX6Q_PAD_SD3_CMD__USBOH3_UH2_DFD_OUT_4 1277 +MX6Q_PAD_SD3_CMD__GPIO_7_2 1278 +MX6Q_PAD_SD3_CMD__MIPI_CORE_DPHY_IN_16 1279 +MX6Q_PAD_SD3_CMD__ANATOP_TESTO_13 1280 +MX6Q_PAD_SD3_CLK__USDHC3_CLK 1281 +MX6Q_PAD_SD3_CLK__UART2_RTS 1282 +MX6Q_PAD_SD3_CLK__CAN1_RXCAN 1283 +MX6Q_PAD_SD3_CLK__USBOH3_UH3_DFD_OUT_5 1284 +MX6Q_PAD_SD3_CLK__USBOH3_UH2_DFD_OUT_5 1285 +MX6Q_PAD_SD3_CLK__GPIO_7_3 1286 +MX6Q_PAD_SD3_CLK__MIPI_CORE_DPHY_IN_17 1287 +MX6Q_PAD_SD3_CLK__ANATOP_TESTO_14 1288 +MX6Q_PAD_SD3_DAT0__USDHC3_DAT0 1289 +MX6Q_PAD_SD3_DAT0__UART1_CTS 1290 +MX6Q_PAD_SD3_DAT0__CAN2_TXCAN 1291 +MX6Q_PAD_SD3_DAT0__USBOH3_UH3_DFD_OUT_6 1292 +MX6Q_PAD_SD3_DAT0__USBOH3_UH2_DFD_OUT_6 1293 +MX6Q_PAD_SD3_DAT0__GPIO_7_4 1294 +MX6Q_PAD_SD3_DAT0__MIPI_CORE_DPHY_IN_18 1295 +MX6Q_PAD_SD3_DAT0__ANATOP_TESTO_15 1296 +MX6Q_PAD_SD3_DAT1__USDHC3_DAT1 1297 +MX6Q_PAD_SD3_DAT1__UART1_RTS 1298 +MX6Q_PAD_SD3_DAT1__CAN2_RXCAN 1299 +MX6Q_PAD_SD3_DAT1__USBOH3_UH3_DFD_OUT_7 1300 +MX6Q_PAD_SD3_DAT1__USBOH3_UH2_DFD_OUT_7 1301 +MX6Q_PAD_SD3_DAT1__GPIO_7_5 1302 +MX6Q_PAD_SD3_DAT1__MIPI_CORE_DPHY_IN_19 1303 +MX6Q_PAD_SD3_DAT1__ANATOP_TESTI_0 1304 +MX6Q_PAD_SD3_DAT2__USDHC3_DAT2 1305 +MX6Q_PAD_SD3_DAT2__PCIE_CTRL_MUX_28 1306 +MX6Q_PAD_SD3_DAT2__USBOH3_UH3_DFD_OUT_8 1307 +MX6Q_PAD_SD3_DAT2__USBOH3_UH2_DFD_OUT_8 1308 +MX6Q_PAD_SD3_DAT2__GPIO_7_6 1309 +MX6Q_PAD_SD3_DAT2__MIPI_CORE_DPHY_IN_20 1310 +MX6Q_PAD_SD3_DAT2__ANATOP_TESTI_1 1311 +MX6Q_PAD_SD3_DAT3__USDHC3_DAT3 1312 +MX6Q_PAD_SD3_DAT3__UART3_CTS 1313 +MX6Q_PAD_SD3_DAT3__PCIE_CTRL_MUX_29 1314 +MX6Q_PAD_SD3_DAT3__USBOH3_UH3_DFD_OUT_9 1315 +MX6Q_PAD_SD3_DAT3__USBOH3_UH2_DFD_OUT_9 1316 +MX6Q_PAD_SD3_DAT3__GPIO_7_7 1317 +MX6Q_PAD_SD3_DAT3__MIPI_CORE_DPHY_IN_21 1318 +MX6Q_PAD_SD3_DAT3__ANATOP_TESTI_2 1319 +MX6Q_PAD_SD3_RST__USDHC3_RST 1320 +MX6Q_PAD_SD3_RST__UART3_RTS 1321 +MX6Q_PAD_SD3_RST__PCIE_CTRL_MUX_30 1322 +MX6Q_PAD_SD3_RST__USBOH3_UH3_DFD_OUT_10 1323 +MX6Q_PAD_SD3_RST__USBOH3_UH2_DFD_OUT_10 1324 +MX6Q_PAD_SD3_RST__GPIO_7_8 1325 +MX6Q_PAD_SD3_RST__MIPI_CORE_DPHY_IN_22 1326 +MX6Q_PAD_SD3_RST__ANATOP_ANATOP_TESTI_3 1327 +MX6Q_PAD_NANDF_CLE__RAWNAND_CLE 1328 +MX6Q_PAD_NANDF_CLE__IPU2_SISG_4 1329 +MX6Q_PAD_NANDF_CLE__PCIE_CTRL_MUX_31 1330 +MX6Q_PAD_NANDF_CLE__USBOH3_UH3_DFD_OT11 1331 +MX6Q_PAD_NANDF_CLE__USBOH3_UH2_DFD_OT11 1332 +MX6Q_PAD_NANDF_CLE__GPIO_6_7 1333 +MX6Q_PAD_NANDF_CLE__MIPI_CORE_DPHY_IN23 1334 +MX6Q_PAD_NANDF_CLE__TPSMP_HTRANS_0 1335 +MX6Q_PAD_NANDF_ALE__RAWNAND_ALE 1336 +MX6Q_PAD_NANDF_ALE__USDHC4_RST 1337 +MX6Q_PAD_NANDF_ALE__PCIE_CTRL_MUX_0 1338 +MX6Q_PAD_NANDF_ALE__USBOH3_UH3_DFD_OT12 1339 +MX6Q_PAD_NANDF_ALE__USBOH3_UH2_DFD_OT12 1340 +MX6Q_PAD_NANDF_ALE__GPIO_6_8 1341 +MX6Q_PAD_NANDF_ALE__MIPI_CR_DPHY_IN_24 1342 +MX6Q_PAD_NANDF_ALE__TPSMP_HTRANS_1 1343 +MX6Q_PAD_NANDF_WP_B__RAWNAND_RESETN 1344 +MX6Q_PAD_NANDF_WP_B__IPU2_SISG_5 1345 +MX6Q_PAD_NANDF_WP_B__PCIE_CTRL__MUX_1 1346 +MX6Q_PAD_NANDF_WP_B__USBOH3_UH3_DFDOT13 1347 +MX6Q_PAD_NANDF_WP_B__USBOH3_UH2_DFDOT13 1348 +MX6Q_PAD_NANDF_WP_B__GPIO_6_9 1349 +MX6Q_PAD_NANDF_WP_B__MIPI_CR_DPHY_OUT32 1350 +MX6Q_PAD_NANDF_WP_B__PL301_PER1_HSIZE_0 1351 +MX6Q_PAD_NANDF_RB0__RAWNAND_READY0 1352 +MX6Q_PAD_NANDF_RB0__IPU2_DI0_PIN1 1353 +MX6Q_PAD_NANDF_RB0__PCIE_CTRL_MUX_2 1354 +MX6Q_PAD_NANDF_RB0__USBOH3_UH3_DFD_OT14 1355 +MX6Q_PAD_NANDF_RB0__USBOH3_UH2_DFD_OT14 1356 +MX6Q_PAD_NANDF_RB0__GPIO_6_10 1357 +MX6Q_PAD_NANDF_RB0__MIPI_CR_DPHY_OUT_33 1358 +MX6Q_PAD_NANDF_RB0__PL301_PER1_HSIZE_1 1359 +MX6Q_PAD_NANDF_CS0__RAWNAND_CE0N 1360 +MX6Q_PAD_NANDF_CS0__USBOH3_UH3_DFD_OT15 1361 +MX6Q_PAD_NANDF_CS0__USBOH3_UH2_DFD_OT15 1362 +MX6Q_PAD_NANDF_CS0__GPIO_6_11 1363 +MX6Q_PAD_NANDF_CS0__PL301_PER1_HSIZE_2 1364 +MX6Q_PAD_NANDF_CS1__RAWNAND_CE1N 1365 +MX6Q_PAD_NANDF_CS1__USDHC4_VSELECT 1366 +MX6Q_PAD_NANDF_CS1__USDHC3_VSELECT 1367 +MX6Q_PAD_NANDF_CS1__PCIE_CTRL_MUX_3 1368 +MX6Q_PAD_NANDF_CS1__GPIO_6_14 1369 +MX6Q_PAD_NANDF_CS1__PL301_PER1_HRDYOUT 1370 +MX6Q_PAD_NANDF_CS2__RAWNAND_CE2N 1371 +MX6Q_PAD_NANDF_CS2__IPU1_SISG_0 1372 +MX6Q_PAD_NANDF_CS2__ESAI1_TX0 1373 +MX6Q_PAD_NANDF_CS2__WEIM_WEIM_CRE 1374 +MX6Q_PAD_NANDF_CS2__CCM_CLKO2 1375 +MX6Q_PAD_NANDF_CS2__GPIO_6_15 1376 +MX6Q_PAD_NANDF_CS2__IPU2_SISG_0 1377 +MX6Q_PAD_NANDF_CS3__RAWNAND_CE3N 1378 +MX6Q_PAD_NANDF_CS3__IPU1_SISG_1 1379 +MX6Q_PAD_NANDF_CS3__ESAI1_TX1 1380 +MX6Q_PAD_NANDF_CS3__WEIM_WEIM_A_26 1381 +MX6Q_PAD_NANDF_CS3__PCIE_CTRL_MUX_4 1382 +MX6Q_PAD_NANDF_CS3__GPIO_6_16 1383 +MX6Q_PAD_NANDF_CS3__IPU2_SISG_1 1384 +MX6Q_PAD_NANDF_CS3__TPSMP_CLK 1385 +MX6Q_PAD_SD4_CMD__USDHC4_CMD 1386 +MX6Q_PAD_SD4_CMD__RAWNAND_RDN 1387 +MX6Q_PAD_SD4_CMD__UART3_TXD 1388 +MX6Q_PAD_SD4_CMD__PCIE_CTRL_MUX_5 1389 +MX6Q_PAD_SD4_CMD__GPIO_7_9 1390 +MX6Q_PAD_SD4_CMD__TPSMP_HDATA_DIR 1391 +MX6Q_PAD_SD4_CLK__USDHC4_CLK 1392 +MX6Q_PAD_SD4_CLK__RAWNAND_WRN 1393 +MX6Q_PAD_SD4_CLK__UART3_RXD 1394 +MX6Q_PAD_SD4_CLK__PCIE_CTRL_MUX_6 1395 +MX6Q_PAD_SD4_CLK__GPIO_7_10 1396 +MX6Q_PAD_NANDF_D0__RAWNAND_D0 1397 +MX6Q_PAD_NANDF_D0__USDHC1_DAT4 1398 +MX6Q_PAD_NANDF_D0__GPU3D_GPU_DBG_OUT_0 1399 +MX6Q_PAD_NANDF_D0__USBOH3_UH2_DFD_OUT16 1400 +MX6Q_PAD_NANDF_D0__USBOH3_UH3_DFD_OUT16 1401 +MX6Q_PAD_NANDF_D0__GPIO_2_0 1402 +MX6Q_PAD_NANDF_D0__IPU1_IPU_DIAG_BUS_0 1403 +MX6Q_PAD_NANDF_D0__IPU2_IPU_DIAG_BUS_0 1404 +MX6Q_PAD_NANDF_D1__RAWNAND_D1 1405 +MX6Q_PAD_NANDF_D1__USDHC1_DAT5 1406 +MX6Q_PAD_NANDF_D1__GPU3D_GPU_DEBUG_OUT1 1407 +MX6Q_PAD_NANDF_D1__USBOH3_UH2_DFD_OUT17 1408 +MX6Q_PAD_NANDF_D1__USBOH3_UH3_DFD_OUT17 1409 +MX6Q_PAD_NANDF_D1__GPIO_2_1 1410 +MX6Q_PAD_NANDF_D1__IPU1_IPU_DIAG_BUS_1 1411 +MX6Q_PAD_NANDF_D1__IPU2_IPU_DIAG_BUS_1 1412 +MX6Q_PAD_NANDF_D2__RAWNAND_D2 1413 +MX6Q_PAD_NANDF_D2__USDHC1_DAT6 1414 +MX6Q_PAD_NANDF_D2__GPU3D_GPU_DBG_OUT_2 1415 +MX6Q_PAD_NANDF_D2__USBOH3_UH2_DFD_OUT18 1416 +MX6Q_PAD_NANDF_D2__USBOH3_UH3_DFD_OUT18 1417 +MX6Q_PAD_NANDF_D2__GPIO_2_2 1418 +MX6Q_PAD_NANDF_D2__IPU1_IPU_DIAG_BUS_2 1419 +MX6Q_PAD_NANDF_D2__IPU2_IPU_DIAG_BUS_2 1420 +MX6Q_PAD_NANDF_D3__RAWNAND_D3 1421 +MX6Q_PAD_NANDF_D3__USDHC1_DAT7 1422 +MX6Q_PAD_NANDF_D3__GPU3D_GPU_DBG_OUT_3 1423 +MX6Q_PAD_NANDF_D3__USBOH3_UH2_DFD_OUT19 1424 +MX6Q_PAD_NANDF_D3__USBOH3_UH3_DFD_OUT19 1425 +MX6Q_PAD_NANDF_D3__GPIO_2_3 1426 +MX6Q_PAD_NANDF_D3__IPU1_IPU_DIAG_BUS_3 1427 +MX6Q_PAD_NANDF_D3__IPU2_IPU_DIAG_BUS_3 1428 +MX6Q_PAD_NANDF_D4__RAWNAND_D4 1429 +MX6Q_PAD_NANDF_D4__USDHC2_DAT4 1430 +MX6Q_PAD_NANDF_D4__GPU3D_GPU_DBG_OUT_4 1431 +MX6Q_PAD_NANDF_D4__USBOH3_UH2_DFD_OUT20 1432 +MX6Q_PAD_NANDF_D4__USBOH3_UH3_DFD_OUT20 1433 +MX6Q_PAD_NANDF_D4__GPIO_2_4 1434 +MX6Q_PAD_NANDF_D4__IPU1_IPU_DIAG_BUS_4 1435 +MX6Q_PAD_NANDF_D4__IPU2_IPU_DIAG_BUS_4 1436 +MX6Q_PAD_NANDF_D5__RAWNAND_D5 1437 +MX6Q_PAD_NANDF_D5__USDHC2_DAT5 1438 +MX6Q_PAD_NANDF_D5__GPU3D_GPU_DBG_OUT_5 1439 +MX6Q_PAD_NANDF_D5__USBOH3_UH2_DFD_OUT21 1440 +MX6Q_PAD_NANDF_D5__USBOH3_UH3_DFD_OUT21 1441 +MX6Q_PAD_NANDF_D5__GPIO_2_5 1442 +MX6Q_PAD_NANDF_D5__IPU1_IPU_DIAG_BUS_5 1443 +MX6Q_PAD_NANDF_D5__IPU2_IPU_DIAG_BUS_5 1444 +MX6Q_PAD_NANDF_D6__RAWNAND_D6 1445 +MX6Q_PAD_NANDF_D6__USDHC2_DAT6 1446 +MX6Q_PAD_NANDF_D6__GPU3D_GPU_DBG_OUT_6 1447 +MX6Q_PAD_NANDF_D6__USBOH3_UH2_DFD_OUT22 1448 +MX6Q_PAD_NANDF_D6__USBOH3_UH3_DFD_OUT22 1449 +MX6Q_PAD_NANDF_D6__GPIO_2_6 1450 +MX6Q_PAD_NANDF_D6__IPU1_IPU_DIAG_BUS_6 1451 +MX6Q_PAD_NANDF_D6__IPU2_IPU_DIAG_BUS_6 1452 +MX6Q_PAD_NANDF_D7__RAWNAND_D7 1453 +MX6Q_PAD_NANDF_D7__USDHC2_DAT7 1454 +MX6Q_PAD_NANDF_D7__GPU3D_GPU_DBG_OUT_7 1455 +MX6Q_PAD_NANDF_D7__USBOH3_UH2_DFD_OUT23 1456 +MX6Q_PAD_NANDF_D7__USBOH3_UH3_DFD_OUT23 1457 +MX6Q_PAD_NANDF_D7__GPIO_2_7 1458 +MX6Q_PAD_NANDF_D7__IPU1_IPU_DIAG_BUS_7 1459 +MX6Q_PAD_NANDF_D7__IPU2_IPU_DIAG_BUS_7 1460 +MX6Q_PAD_SD4_DAT0__RAWNAND_D8 1461 +MX6Q_PAD_SD4_DAT0__USDHC4_DAT0 1462 +MX6Q_PAD_SD4_DAT0__RAWNAND_DQS 1463 +MX6Q_PAD_SD4_DAT0__USBOH3_UH2_DFD_OUT24 1464 +MX6Q_PAD_SD4_DAT0__USBOH3_UH3_DFD_OUT24 1465 +MX6Q_PAD_SD4_DAT0__GPIO_2_8 1466 +MX6Q_PAD_SD4_DAT0__IPU1_IPU_DIAG_BUS_8 1467 +MX6Q_PAD_SD4_DAT0__IPU2_IPU_DIAG_BUS_8 1468 +MX6Q_PAD_SD4_DAT1__RAWNAND_D9 1469 +MX6Q_PAD_SD4_DAT1__USDHC4_DAT1 1470 +MX6Q_PAD_SD4_DAT1__PWM3_PWMO 1471 +MX6Q_PAD_SD4_DAT1__USBOH3_UH2_DFD_OUT25 1472 +MX6Q_PAD_SD4_DAT1__USBOH3_UH3_DFD_OUT25 1473 +MX6Q_PAD_SD4_DAT1__GPIO_2_9 1474 +MX6Q_PAD_SD4_DAT1__IPU1_IPU_DIAG_BUS_9 1475 +MX6Q_PAD_SD4_DAT1__IPU2_IPU_DIAG_BUS_9 1476 +MX6Q_PAD_SD4_DAT2__RAWNAND_D10 1477 +MX6Q_PAD_SD4_DAT2__USDHC4_DAT2 1478 +MX6Q_PAD_SD4_DAT2__PWM4_PWMO 1479 +MX6Q_PAD_SD4_DAT2__USBOH3_UH2_DFD_OUT26 1480 +MX6Q_PAD_SD4_DAT2__USBOH3_UH3_DFD_OUT26 1481 +MX6Q_PAD_SD4_DAT2__GPIO_2_10 1482 +MX6Q_PAD_SD4_DAT2__IPU1_IPU_DIAG_BUS_10 1483 +MX6Q_PAD_SD4_DAT2__IPU2_IPU_DIAG_BUS_10 1484 +MX6Q_PAD_SD4_DAT3__RAWNAND_D11 1485 +MX6Q_PAD_SD4_DAT3__USDHC4_DAT3 1486 +MX6Q_PAD_SD4_DAT3__USBOH3_UH2_DFD_OUT27 1487 +MX6Q_PAD_SD4_DAT3__USBOH3_UH3_DFD_OUT27 1488 +MX6Q_PAD_SD4_DAT3__GPIO_2_11 1489 +MX6Q_PAD_SD4_DAT3__IPU1_IPU_DIAG_BUS_11 1490 +MX6Q_PAD_SD4_DAT3__IPU2_IPU_DIAG_BUS_11 1491 +MX6Q_PAD_SD4_DAT4__RAWNAND_D12 1492 +MX6Q_PAD_SD4_DAT4__USDHC4_DAT4 1493 +MX6Q_PAD_SD4_DAT4__UART2_RXD 1494 +MX6Q_PAD_SD4_DAT4__USBOH3_UH2_DFD_OUT28 1495 +MX6Q_PAD_SD4_DAT4__USBOH3_UH3_DFD_OUT28 1496 +MX6Q_PAD_SD4_DAT4__GPIO_2_12 1497 +MX6Q_PAD_SD4_DAT4__IPU1_IPU_DIAG_BUS_12 1498 +MX6Q_PAD_SD4_DAT4__IPU2_IPU_DIAG_BUS_12 1499 +MX6Q_PAD_SD4_DAT5__RAWNAND_D13 1500 +MX6Q_PAD_SD4_DAT5__USDHC4_DAT5 1501 +MX6Q_PAD_SD4_DAT5__UART2_RTS 1502 +MX6Q_PAD_SD4_DAT5__USBOH3_UH2_DFD_OUT29 1503 +MX6Q_PAD_SD4_DAT5__USBOH3_UH3_DFD_OUT29 1504 +MX6Q_PAD_SD4_DAT5__GPIO_2_13 1505 +MX6Q_PAD_SD4_DAT5__IPU1_IPU_DIAG_BUS_13 1506 +MX6Q_PAD_SD4_DAT5__IPU2_IPU_DIAG_BUS_13 1507 +MX6Q_PAD_SD4_DAT6__RAWNAND_D14 1508 +MX6Q_PAD_SD4_DAT6__USDHC4_DAT6 1509 +MX6Q_PAD_SD4_DAT6__UART2_CTS 1510 +MX6Q_PAD_SD4_DAT6__USBOH3_UH2_DFD_OUT30 1511 +MX6Q_PAD_SD4_DAT6__USBOH3_UH3_DFD_OUT30 1512 +MX6Q_PAD_SD4_DAT6__GPIO_2_14 1513 +MX6Q_PAD_SD4_DAT6__IPU1_IPU_DIAG_BUS_14 1514 +MX6Q_PAD_SD4_DAT6__IPU2_IPU_DIAG_BUS_14 1515 +MX6Q_PAD_SD4_DAT7__RAWNAND_D15 1516 +MX6Q_PAD_SD4_DAT7__USDHC4_DAT7 1517 +MX6Q_PAD_SD4_DAT7__UART2_TXD 1518 +MX6Q_PAD_SD4_DAT7__USBOH3_UH2_DFD_OUT31 1519 +MX6Q_PAD_SD4_DAT7__USBOH3_UH3_DFD_OUT31 1520 +MX6Q_PAD_SD4_DAT7__GPIO_2_15 1521 +MX6Q_PAD_SD4_DAT7__IPU1_IPU_DIAG_BUS_15 1522 +MX6Q_PAD_SD4_DAT7__IPU2_IPU_DIAG_BUS_15 1523 +MX6Q_PAD_SD1_DAT1__USDHC1_DAT1 1524 +MX6Q_PAD_SD1_DAT1__ECSPI5_SS0 1525 +MX6Q_PAD_SD1_DAT1__PWM3_PWMO 1526 +MX6Q_PAD_SD1_DAT1__GPT_CAPIN2 1527 +MX6Q_PAD_SD1_DAT1__PCIE_CTRL_MUX_7 1528 +MX6Q_PAD_SD1_DAT1__GPIO_1_17 1529 +MX6Q_PAD_SD1_DAT1__HDMI_TX_OPHYDTB_0 1530 +MX6Q_PAD_SD1_DAT1__ANATOP_TESTO_8 1531 +MX6Q_PAD_SD1_DAT0__USDHC1_DAT0 1532 +MX6Q_PAD_SD1_DAT0__ECSPI5_MISO 1533 +MX6Q_PAD_SD1_DAT0__CAAM_WRAP_RNG_OSCOBS 1534 +MX6Q_PAD_SD1_DAT0__GPT_CAPIN1 1535 +MX6Q_PAD_SD1_DAT0__PCIE_CTRL_MUX_8 1536 +MX6Q_PAD_SD1_DAT0__GPIO_1_16 1537 +MX6Q_PAD_SD1_DAT0__HDMI_TX_OPHYDTB_1 1538 +MX6Q_PAD_SD1_DAT0__ANATOP_TESTO_7 1539 +MX6Q_PAD_SD1_DAT3__USDHC1_DAT3 1540 +MX6Q_PAD_SD1_DAT3__ECSPI5_SS2 1541 +MX6Q_PAD_SD1_DAT3__GPT_CMPOUT3 1542 +MX6Q_PAD_SD1_DAT3__PWM1_PWMO 1543 +MX6Q_PAD_SD1_DAT3__WDOG2_WDOG_B 1544 +MX6Q_PAD_SD1_DAT3__GPIO_1_21 1545 +MX6Q_PAD_SD1_DAT3__WDOG2_WDOG_RST_B_DEB 1546 +MX6Q_PAD_SD1_DAT3__ANATOP_TESTO_6 1547 +MX6Q_PAD_SD1_CMD__USDHC1_CMD 1548 +MX6Q_PAD_SD1_CMD__ECSPI5_MOSI 1549 +MX6Q_PAD_SD1_CMD__PWM4_PWMO 1550 +MX6Q_PAD_SD1_CMD__GPT_CMPOUT1 1551 +MX6Q_PAD_SD1_CMD__GPIO_1_18 1552 +MX6Q_PAD_SD1_CMD__ANATOP_TESTO_5 1553 +MX6Q_PAD_SD1_DAT2__USDHC1_DAT2 1554 +MX6Q_PAD_SD1_DAT2__ECSPI5_SS1 1555 +MX6Q_PAD_SD1_DAT2__GPT_CMPOUT2 1556 +MX6Q_PAD_SD1_DAT2__PWM2_PWMO 1557 +MX6Q_PAD_SD1_DAT2__WDOG1_WDOG_B 1558 +MX6Q_PAD_SD1_DAT2__GPIO_1_19 1559 +MX6Q_PAD_SD1_DAT2__WDOG1_WDOG_RST_B_DEB 1560 +MX6Q_PAD_SD1_DAT2__ANATOP_TESTO_4 1561 +MX6Q_PAD_SD1_CLK__USDHC1_CLK 1562 +MX6Q_PAD_SD1_CLK__ECSPI5_SCLK 1563 +MX6Q_PAD_SD1_CLK__OSC32K_32K_OUT 1564 +MX6Q_PAD_SD1_CLK__GPT_CLKIN 1565 +MX6Q_PAD_SD1_CLK__GPIO_1_20 1566 +MX6Q_PAD_SD1_CLK__PHY_DTB_0 1567 +MX6Q_PAD_SD1_CLK__SATA_PHY_DTB_0 1568 +MX6Q_PAD_SD2_CLK__USDHC2_CLK 1569 +MX6Q_PAD_SD2_CLK__ECSPI5_SCLK 1570 +MX6Q_PAD_SD2_CLK__KPP_COL_5 1571 +MX6Q_PAD_SD2_CLK__AUDMUX_AUD4_RXFS 1572 +MX6Q_PAD_SD2_CLK__PCIE_CTRL_MUX_9 1573 +MX6Q_PAD_SD2_CLK__GPIO_1_10 1574 +MX6Q_PAD_SD2_CLK__PHY_DTB_1 1575 +MX6Q_PAD_SD2_CLK__SATA_PHY_DTB_1 1576 +MX6Q_PAD_SD2_CMD__USDHC2_CMD 1577 +MX6Q_PAD_SD2_CMD__ECSPI5_MOSI 1578 +MX6Q_PAD_SD2_CMD__KPP_ROW_5 1579 +MX6Q_PAD_SD2_CMD__AUDMUX_AUD4_RXC 1580 +MX6Q_PAD_SD2_CMD__PCIE_CTRL_MUX_10 1581 +MX6Q_PAD_SD2_CMD__GPIO_1_11 1582 +MX6Q_PAD_SD2_DAT3__USDHC2_DAT3 1583 +MX6Q_PAD_SD2_DAT3__ECSPI5_SS3 1584 +MX6Q_PAD_SD2_DAT3__KPP_COL_6 1585 +MX6Q_PAD_SD2_DAT3__AUDMUX_AUD4_TXC 1586 +MX6Q_PAD_SD2_DAT3__PCIE_CTRL_MUX_11 1587 +MX6Q_PAD_SD2_DAT3__GPIO_1_12 1588 +MX6Q_PAD_SD2_DAT3__SJC_DONE 1589 +MX6Q_PAD_SD2_DAT3__ANATOP_TESTO_3 1590 diff --git a/trunk/Documentation/devicetree/bindings/pinctrl/fsl,mxs-pinctrl.txt b/trunk/Documentation/devicetree/bindings/pinctrl/fsl,mxs-pinctrl.txt new file mode 100644 index 000000000000..f7e8e8f4d9a3 --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/pinctrl/fsl,mxs-pinctrl.txt @@ -0,0 +1,918 @@ +* Freescale MXS Pin Controller + +The pins controlled by mxs pin controller are organized in banks, each bank +has 32 pins. Each pin has 4 multiplexing functions, and generally, the 4th +function is GPIO. The configuration on the pins includes drive strength, +voltage and pull-up. + +Required properties: +- compatible: "fsl,imx23-pinctrl" or "fsl,imx28-pinctrl" +- reg: Should contain the register physical address and length for the + pin controller. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices. + +The node of mxs pin controller acts as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for +a group of pins, and only affects those parameters that are explicitly listed. +In other words, a subnode that describes a drive strength parameter implies no +information about pull-up. For this reason, even seemingly boolean values are +actually tristates in this binding: unspecified, off, or on. Unspecified is +represented as an absent property, and off/on are represented as integer +values 0 and 1. + +Those subnodes under mxs pin controller node will fall into two categories. +One is to set up a group of pins for a function, both mux selection and pin +configurations, and it's called group node in the binding document. The other +one is to adjust the pin configuration for some particular pins that need a +different configuration than what is defined in group node. The binding +document calls this type of node config node. + +On mxs, there is no hardware pin group. The pin group in this binding only +means a group of pins put together for particular peripheral to work in +particular function, like SSP0 functioning as mmc0-8bit. That said, the +group node should include all the pins needed for one function rather than +having these pins defined in several group nodes. It also means each of +"pinctrl-*" phandle in client device node should only have one group node +pointed in there, while the phandle can have multiple config node referenced +there to adjust configurations for some pins in the group. + +Required subnode-properties: +- fsl,pinmux-ids: An integer array. Each integer in the array specify a pin + with given mux function, with bank, pin and mux packed as below. + + [15..12] : bank number + [11..4] : pin number + [3..0] : mux selection + + This integer with mux selection packed is used as an entity by both group + and config nodes to identify a pin. The mux selection in the integer takes + effects only on group node, and will get ignored by driver with config node, + since config node is only meant to set up pin configurations. + + Valid values for these integers are listed below. + +- reg: Should be the index of the group nodes for same function. This property + is required only for group nodes, and should not be present in any config + nodes. + +Optional subnode-properties: +- fsl,drive-strength: Integer. + 0: 4 mA + 1: 8 mA + 2: 12 mA + 3: 16 mA +- fsl,voltage: Integer. + 0: 1.8 V + 1: 3.3 V +- fsl,pull-up: Integer. + 0: Disable the internal pull-up + 1: Enable the internal pull-up + +Examples: + +pinctrl@80018000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx28-pinctrl"; + reg = <0x80018000 2000>; + + mmc0_8bit_pins_a: mmc0-8bit@0 { + reg = <0>; + fsl,pinmux-ids = < + 0x2000 0x2010 0x2020 0x2030 + 0x2040 0x2050 0x2060 0x2070 + 0x2080 0x2090 0x20a0>; + fsl,drive-strength = <1>; + fsl,voltage = <1>; + fsl,pull-up = <1>; + }; + + mmc_cd_cfg: mmc-cd-cfg { + fsl,pinmux-ids = <0x2090>; + fsl,pull-up = <0>; + }; + + mmc_sck_cfg: mmc-sck-cfg { + fsl,pinmux-ids = <0x20a0>; + fsl,drive-strength = <2>; + fsl,pull-up = <0>; + }; +}; + +In this example, group node mmc0-8bit defines a group of pins for mxs SSP0 +to function as a 8-bit mmc device, with 8mA, 3.3V and pull-up configurations +applied on all these pins. And config nodes mmc-cd-cfg and mmc-sck-cfg are +adjusting the configuration for pins card-detection and clock from what group +node mmc0-8bit defines. Only the configuration properties to be adjusted need +to be listed in the config nodes. + +Valid values for i.MX28 pinmux-id: + +pinmux id +------ -- +MX28_PAD_GPMI_D00__GPMI_D0 0x0000 +MX28_PAD_GPMI_D01__GPMI_D1 0x0010 +MX28_PAD_GPMI_D02__GPMI_D2 0x0020 +MX28_PAD_GPMI_D03__GPMI_D3 0x0030 +MX28_PAD_GPMI_D04__GPMI_D4 0x0040 +MX28_PAD_GPMI_D05__GPMI_D5 0x0050 +MX28_PAD_GPMI_D06__GPMI_D6 0x0060 +MX28_PAD_GPMI_D07__GPMI_D7 0x0070 +MX28_PAD_GPMI_CE0N__GPMI_CE0N 0x0100 +MX28_PAD_GPMI_CE1N__GPMI_CE1N 0x0110 +MX28_PAD_GPMI_CE2N__GPMI_CE2N 0x0120 +MX28_PAD_GPMI_CE3N__GPMI_CE3N 0x0130 +MX28_PAD_GPMI_RDY0__GPMI_READY0 0x0140 +MX28_PAD_GPMI_RDY1__GPMI_READY1 0x0150 +MX28_PAD_GPMI_RDY2__GPMI_READY2 0x0160 +MX28_PAD_GPMI_RDY3__GPMI_READY3 0x0170 +MX28_PAD_GPMI_RDN__GPMI_RDN 0x0180 +MX28_PAD_GPMI_WRN__GPMI_WRN 0x0190 +MX28_PAD_GPMI_ALE__GPMI_ALE 0x01a0 +MX28_PAD_GPMI_CLE__GPMI_CLE 0x01b0 +MX28_PAD_GPMI_RESETN__GPMI_RESETN 0x01c0 +MX28_PAD_LCD_D00__LCD_D0 0x1000 +MX28_PAD_LCD_D01__LCD_D1 0x1010 +MX28_PAD_LCD_D02__LCD_D2 0x1020 +MX28_PAD_LCD_D03__LCD_D3 0x1030 +MX28_PAD_LCD_D04__LCD_D4 0x1040 +MX28_PAD_LCD_D05__LCD_D5 0x1050 +MX28_PAD_LCD_D06__LCD_D6 0x1060 +MX28_PAD_LCD_D07__LCD_D7 0x1070 +MX28_PAD_LCD_D08__LCD_D8 0x1080 +MX28_PAD_LCD_D09__LCD_D9 0x1090 +MX28_PAD_LCD_D10__LCD_D10 0x10a0 +MX28_PAD_LCD_D11__LCD_D11 0x10b0 +MX28_PAD_LCD_D12__LCD_D12 0x10c0 +MX28_PAD_LCD_D13__LCD_D13 0x10d0 +MX28_PAD_LCD_D14__LCD_D14 0x10e0 +MX28_PAD_LCD_D15__LCD_D15 0x10f0 +MX28_PAD_LCD_D16__LCD_D16 0x1100 +MX28_PAD_LCD_D17__LCD_D17 0x1110 +MX28_PAD_LCD_D18__LCD_D18 0x1120 +MX28_PAD_LCD_D19__LCD_D19 0x1130 +MX28_PAD_LCD_D20__LCD_D20 0x1140 +MX28_PAD_LCD_D21__LCD_D21 0x1150 +MX28_PAD_LCD_D22__LCD_D22 0x1160 +MX28_PAD_LCD_D23__LCD_D23 0x1170 +MX28_PAD_LCD_RD_E__LCD_RD_E 0x1180 +MX28_PAD_LCD_WR_RWN__LCD_WR_RWN 0x1190 +MX28_PAD_LCD_RS__LCD_RS 0x11a0 +MX28_PAD_LCD_CS__LCD_CS 0x11b0 +MX28_PAD_LCD_VSYNC__LCD_VSYNC 0x11c0 +MX28_PAD_LCD_HSYNC__LCD_HSYNC 0x11d0 +MX28_PAD_LCD_DOTCLK__LCD_DOTCLK 0x11e0 +MX28_PAD_LCD_ENABLE__LCD_ENABLE 0x11f0 +MX28_PAD_SSP0_DATA0__SSP0_D0 0x2000 +MX28_PAD_SSP0_DATA1__SSP0_D1 0x2010 +MX28_PAD_SSP0_DATA2__SSP0_D2 0x2020 +MX28_PAD_SSP0_DATA3__SSP0_D3 0x2030 +MX28_PAD_SSP0_DATA4__SSP0_D4 0x2040 +MX28_PAD_SSP0_DATA5__SSP0_D5 0x2050 +MX28_PAD_SSP0_DATA6__SSP0_D6 0x2060 +MX28_PAD_SSP0_DATA7__SSP0_D7 0x2070 +MX28_PAD_SSP0_CMD__SSP0_CMD 0x2080 +MX28_PAD_SSP0_DETECT__SSP0_CARD_DETECT 0x2090 +MX28_PAD_SSP0_SCK__SSP0_SCK 0x20a0 +MX28_PAD_SSP1_SCK__SSP1_SCK 0x20c0 +MX28_PAD_SSP1_CMD__SSP1_CMD 0x20d0 +MX28_PAD_SSP1_DATA0__SSP1_D0 0x20e0 +MX28_PAD_SSP1_DATA3__SSP1_D3 0x20f0 +MX28_PAD_SSP2_SCK__SSP2_SCK 0x2100 +MX28_PAD_SSP2_MOSI__SSP2_CMD 0x2110 +MX28_PAD_SSP2_MISO__SSP2_D0 0x2120 +MX28_PAD_SSP2_SS0__SSP2_D3 0x2130 +MX28_PAD_SSP2_SS1__SSP2_D4 0x2140 +MX28_PAD_SSP2_SS2__SSP2_D5 0x2150 +MX28_PAD_SSP3_SCK__SSP3_SCK 0x2180 +MX28_PAD_SSP3_MOSI__SSP3_CMD 0x2190 +MX28_PAD_SSP3_MISO__SSP3_D0 0x21a0 +MX28_PAD_SSP3_SS0__SSP3_D3 0x21b0 +MX28_PAD_AUART0_RX__AUART0_RX 0x3000 +MX28_PAD_AUART0_TX__AUART0_TX 0x3010 +MX28_PAD_AUART0_CTS__AUART0_CTS 0x3020 +MX28_PAD_AUART0_RTS__AUART0_RTS 0x3030 +MX28_PAD_AUART1_RX__AUART1_RX 0x3040 +MX28_PAD_AUART1_TX__AUART1_TX 0x3050 +MX28_PAD_AUART1_CTS__AUART1_CTS 0x3060 +MX28_PAD_AUART1_RTS__AUART1_RTS 0x3070 +MX28_PAD_AUART2_RX__AUART2_RX 0x3080 +MX28_PAD_AUART2_TX__AUART2_TX 0x3090 +MX28_PAD_AUART2_CTS__AUART2_CTS 0x30a0 +MX28_PAD_AUART2_RTS__AUART2_RTS 0x30b0 +MX28_PAD_AUART3_RX__AUART3_RX 0x30c0 +MX28_PAD_AUART3_TX__AUART3_TX 0x30d0 +MX28_PAD_AUART3_CTS__AUART3_CTS 0x30e0 +MX28_PAD_AUART3_RTS__AUART3_RTS 0x30f0 +MX28_PAD_PWM0__PWM_0 0x3100 +MX28_PAD_PWM1__PWM_1 0x3110 +MX28_PAD_PWM2__PWM_2 0x3120 +MX28_PAD_SAIF0_MCLK__SAIF0_MCLK 0x3140 +MX28_PAD_SAIF0_LRCLK__SAIF0_LRCLK 0x3150 +MX28_PAD_SAIF0_BITCLK__SAIF0_BITCLK 0x3160 +MX28_PAD_SAIF0_SDATA0__SAIF0_SDATA0 0x3170 +MX28_PAD_I2C0_SCL__I2C0_SCL 0x3180 +MX28_PAD_I2C0_SDA__I2C0_SDA 0x3190 +MX28_PAD_SAIF1_SDATA0__SAIF1_SDATA0 0x31a0 +MX28_PAD_SPDIF__SPDIF_TX 0x31b0 +MX28_PAD_PWM3__PWM_3 0x31c0 +MX28_PAD_PWM4__PWM_4 0x31d0 +MX28_PAD_LCD_RESET__LCD_RESET 0x31e0 +MX28_PAD_ENET0_MDC__ENET0_MDC 0x4000 +MX28_PAD_ENET0_MDIO__ENET0_MDIO 0x4010 +MX28_PAD_ENET0_RX_EN__ENET0_RX_EN 0x4020 +MX28_PAD_ENET0_RXD0__ENET0_RXD0 0x4030 +MX28_PAD_ENET0_RXD1__ENET0_RXD1 0x4040 +MX28_PAD_ENET0_TX_CLK__ENET0_TX_CLK 0x4050 +MX28_PAD_ENET0_TX_EN__ENET0_TX_EN 0x4060 +MX28_PAD_ENET0_TXD0__ENET0_TXD0 0x4070 +MX28_PAD_ENET0_TXD1__ENET0_TXD1 0x4080 +MX28_PAD_ENET0_RXD2__ENET0_RXD2 0x4090 +MX28_PAD_ENET0_RXD3__ENET0_RXD3 0x40a0 +MX28_PAD_ENET0_TXD2__ENET0_TXD2 0x40b0 +MX28_PAD_ENET0_TXD3__ENET0_TXD3 0x40c0 +MX28_PAD_ENET0_RX_CLK__ENET0_RX_CLK 0x40d0 +MX28_PAD_ENET0_COL__ENET0_COL 0x40e0 +MX28_PAD_ENET0_CRS__ENET0_CRS 0x40f0 +MX28_PAD_ENET_CLK__CLKCTRL_ENET 0x4100 +MX28_PAD_JTAG_RTCK__JTAG_RTCK 0x4140 +MX28_PAD_EMI_D00__EMI_DATA0 0x5000 +MX28_PAD_EMI_D01__EMI_DATA1 0x5010 +MX28_PAD_EMI_D02__EMI_DATA2 0x5020 +MX28_PAD_EMI_D03__EMI_DATA3 0x5030 +MX28_PAD_EMI_D04__EMI_DATA4 0x5040 +MX28_PAD_EMI_D05__EMI_DATA5 0x5050 +MX28_PAD_EMI_D06__EMI_DATA6 0x5060 +MX28_PAD_EMI_D07__EMI_DATA7 0x5070 +MX28_PAD_EMI_D08__EMI_DATA8 0x5080 +MX28_PAD_EMI_D09__EMI_DATA9 0x5090 +MX28_PAD_EMI_D10__EMI_DATA10 0x50a0 +MX28_PAD_EMI_D11__EMI_DATA11 0x50b0 +MX28_PAD_EMI_D12__EMI_DATA12 0x50c0 +MX28_PAD_EMI_D13__EMI_DATA13 0x50d0 +MX28_PAD_EMI_D14__EMI_DATA14 0x50e0 +MX28_PAD_EMI_D15__EMI_DATA15 0x50f0 +MX28_PAD_EMI_ODT0__EMI_ODT0 0x5100 +MX28_PAD_EMI_DQM0__EMI_DQM0 0x5110 +MX28_PAD_EMI_ODT1__EMI_ODT1 0x5120 +MX28_PAD_EMI_DQM1__EMI_DQM1 0x5130 +MX28_PAD_EMI_DDR_OPEN_FB__EMI_DDR_OPEN_FEEDBACK 0x5140 +MX28_PAD_EMI_CLK__EMI_CLK 0x5150 +MX28_PAD_EMI_DQS0__EMI_DQS0 0x5160 +MX28_PAD_EMI_DQS1__EMI_DQS1 0x5170 +MX28_PAD_EMI_DDR_OPEN__EMI_DDR_OPEN 0x51a0 +MX28_PAD_EMI_A00__EMI_ADDR0 0x6000 +MX28_PAD_EMI_A01__EMI_ADDR1 0x6010 +MX28_PAD_EMI_A02__EMI_ADDR2 0x6020 +MX28_PAD_EMI_A03__EMI_ADDR3 0x6030 +MX28_PAD_EMI_A04__EMI_ADDR4 0x6040 +MX28_PAD_EMI_A05__EMI_ADDR5 0x6050 +MX28_PAD_EMI_A06__EMI_ADDR6 0x6060 +MX28_PAD_EMI_A07__EMI_ADDR7 0x6070 +MX28_PAD_EMI_A08__EMI_ADDR8 0x6080 +MX28_PAD_EMI_A09__EMI_ADDR9 0x6090 +MX28_PAD_EMI_A10__EMI_ADDR10 0x60a0 +MX28_PAD_EMI_A11__EMI_ADDR11 0x60b0 +MX28_PAD_EMI_A12__EMI_ADDR12 0x60c0 +MX28_PAD_EMI_A13__EMI_ADDR13 0x60d0 +MX28_PAD_EMI_A14__EMI_ADDR14 0x60e0 +MX28_PAD_EMI_BA0__EMI_BA0 0x6100 +MX28_PAD_EMI_BA1__EMI_BA1 0x6110 +MX28_PAD_EMI_BA2__EMI_BA2 0x6120 +MX28_PAD_EMI_CASN__EMI_CASN 0x6130 +MX28_PAD_EMI_RASN__EMI_RASN 0x6140 +MX28_PAD_EMI_WEN__EMI_WEN 0x6150 +MX28_PAD_EMI_CE0N__EMI_CE0N 0x6160 +MX28_PAD_EMI_CE1N__EMI_CE1N 0x6170 +MX28_PAD_EMI_CKE__EMI_CKE 0x6180 +MX28_PAD_GPMI_D00__SSP1_D0 0x0001 +MX28_PAD_GPMI_D01__SSP1_D1 0x0011 +MX28_PAD_GPMI_D02__SSP1_D2 0x0021 +MX28_PAD_GPMI_D03__SSP1_D3 0x0031 +MX28_PAD_GPMI_D04__SSP1_D4 0x0041 +MX28_PAD_GPMI_D05__SSP1_D5 0x0051 +MX28_PAD_GPMI_D06__SSP1_D6 0x0061 +MX28_PAD_GPMI_D07__SSP1_D7 0x0071 +MX28_PAD_GPMI_CE0N__SSP3_D0 0x0101 +MX28_PAD_GPMI_CE1N__SSP3_D3 0x0111 +MX28_PAD_GPMI_CE2N__CAN1_TX 0x0121 +MX28_PAD_GPMI_CE3N__CAN1_RX 0x0131 +MX28_PAD_GPMI_RDY0__SSP1_CARD_DETECT 0x0141 +MX28_PAD_GPMI_RDY1__SSP1_CMD 0x0151 +MX28_PAD_GPMI_RDY2__CAN0_TX 0x0161 +MX28_PAD_GPMI_RDY3__CAN0_RX 0x0171 +MX28_PAD_GPMI_RDN__SSP3_SCK 0x0181 +MX28_PAD_GPMI_WRN__SSP1_SCK 0x0191 +MX28_PAD_GPMI_ALE__SSP3_D1 0x01a1 +MX28_PAD_GPMI_CLE__SSP3_D2 0x01b1 +MX28_PAD_GPMI_RESETN__SSP3_CMD 0x01c1 +MX28_PAD_LCD_D03__ETM_DA8 0x1031 +MX28_PAD_LCD_D04__ETM_DA9 0x1041 +MX28_PAD_LCD_D08__ETM_DA3 0x1081 +MX28_PAD_LCD_D09__ETM_DA4 0x1091 +MX28_PAD_LCD_D20__ENET1_1588_EVENT2_OUT 0x1141 +MX28_PAD_LCD_D21__ENET1_1588_EVENT2_IN 0x1151 +MX28_PAD_LCD_D22__ENET1_1588_EVENT3_OUT 0x1161 +MX28_PAD_LCD_D23__ENET1_1588_EVENT3_IN 0x1171 +MX28_PAD_LCD_RD_E__LCD_VSYNC 0x1181 +MX28_PAD_LCD_WR_RWN__LCD_HSYNC 0x1191 +MX28_PAD_LCD_RS__LCD_DOTCLK 0x11a1 +MX28_PAD_LCD_CS__LCD_ENABLE 0x11b1 +MX28_PAD_LCD_VSYNC__SAIF1_SDATA0 0x11c1 +MX28_PAD_LCD_HSYNC__SAIF1_SDATA1 0x11d1 +MX28_PAD_LCD_DOTCLK__SAIF1_MCLK 0x11e1 +MX28_PAD_SSP0_DATA4__SSP2_D0 0x2041 +MX28_PAD_SSP0_DATA5__SSP2_D3 0x2051 +MX28_PAD_SSP0_DATA6__SSP2_CMD 0x2061 +MX28_PAD_SSP0_DATA7__SSP2_SCK 0x2071 +MX28_PAD_SSP1_SCK__SSP2_D1 0x20c1 +MX28_PAD_SSP1_CMD__SSP2_D2 0x20d1 +MX28_PAD_SSP1_DATA0__SSP2_D6 0x20e1 +MX28_PAD_SSP1_DATA3__SSP2_D7 0x20f1 +MX28_PAD_SSP2_SCK__AUART2_RX 0x2101 +MX28_PAD_SSP2_MOSI__AUART2_TX 0x2111 +MX28_PAD_SSP2_MISO__AUART3_RX 0x2121 +MX28_PAD_SSP2_SS0__AUART3_TX 0x2131 +MX28_PAD_SSP2_SS1__SSP2_D1 0x2141 +MX28_PAD_SSP2_SS2__SSP2_D2 0x2151 +MX28_PAD_SSP3_SCK__AUART4_TX 0x2181 +MX28_PAD_SSP3_MOSI__AUART4_RX 0x2191 +MX28_PAD_SSP3_MISO__AUART4_RTS 0x21a1 +MX28_PAD_SSP3_SS0__AUART4_CTS 0x21b1 +MX28_PAD_AUART0_RX__I2C0_SCL 0x3001 +MX28_PAD_AUART0_TX__I2C0_SDA 0x3011 +MX28_PAD_AUART0_CTS__AUART4_RX 0x3021 +MX28_PAD_AUART0_RTS__AUART4_TX 0x3031 +MX28_PAD_AUART1_RX__SSP2_CARD_DETECT 0x3041 +MX28_PAD_AUART1_TX__SSP3_CARD_DETECT 0x3051 +MX28_PAD_AUART1_CTS__USB0_OVERCURRENT 0x3061 +MX28_PAD_AUART1_RTS__USB0_ID 0x3071 +MX28_PAD_AUART2_RX__SSP3_D1 0x3081 +MX28_PAD_AUART2_TX__SSP3_D2 0x3091 +MX28_PAD_AUART2_CTS__I2C1_SCL 0x30a1 +MX28_PAD_AUART2_RTS__I2C1_SDA 0x30b1 +MX28_PAD_AUART3_RX__CAN0_TX 0x30c1 +MX28_PAD_AUART3_TX__CAN0_RX 0x30d1 +MX28_PAD_AUART3_CTS__CAN1_TX 0x30e1 +MX28_PAD_AUART3_RTS__CAN1_RX 0x30f1 +MX28_PAD_PWM0__I2C1_SCL 0x3101 +MX28_PAD_PWM1__I2C1_SDA 0x3111 +MX28_PAD_PWM2__USB0_ID 0x3121 +MX28_PAD_SAIF0_MCLK__PWM_3 0x3141 +MX28_PAD_SAIF0_LRCLK__PWM_4 0x3151 +MX28_PAD_SAIF0_BITCLK__PWM_5 0x3161 +MX28_PAD_SAIF0_SDATA0__PWM_6 0x3171 +MX28_PAD_I2C0_SCL__TIMROT_ROTARYA 0x3181 +MX28_PAD_I2C0_SDA__TIMROT_ROTARYB 0x3191 +MX28_PAD_SAIF1_SDATA0__PWM_7 0x31a1 +MX28_PAD_LCD_RESET__LCD_VSYNC 0x31e1 +MX28_PAD_ENET0_MDC__GPMI_CE4N 0x4001 +MX28_PAD_ENET0_MDIO__GPMI_CE5N 0x4011 +MX28_PAD_ENET0_RX_EN__GPMI_CE6N 0x4021 +MX28_PAD_ENET0_RXD0__GPMI_CE7N 0x4031 +MX28_PAD_ENET0_RXD1__GPMI_READY4 0x4041 +MX28_PAD_ENET0_TX_CLK__HSADC_TRIGGER 0x4051 +MX28_PAD_ENET0_TX_EN__GPMI_READY5 0x4061 +MX28_PAD_ENET0_TXD0__GPMI_READY6 0x4071 +MX28_PAD_ENET0_TXD1__GPMI_READY7 0x4081 +MX28_PAD_ENET0_RXD2__ENET1_RXD0 0x4091 +MX28_PAD_ENET0_RXD3__ENET1_RXD1 0x40a1 +MX28_PAD_ENET0_TXD2__ENET1_TXD0 0x40b1 +MX28_PAD_ENET0_TXD3__ENET1_TXD1 0x40c1 +MX28_PAD_ENET0_RX_CLK__ENET0_RX_ER 0x40d1 +MX28_PAD_ENET0_COL__ENET1_TX_EN 0x40e1 +MX28_PAD_ENET0_CRS__ENET1_RX_EN 0x40f1 +MX28_PAD_GPMI_CE2N__ENET0_RX_ER 0x0122 +MX28_PAD_GPMI_CE3N__SAIF1_MCLK 0x0132 +MX28_PAD_GPMI_RDY0__USB0_ID 0x0142 +MX28_PAD_GPMI_RDY2__ENET0_TX_ER 0x0162 +MX28_PAD_GPMI_RDY3__HSADC_TRIGGER 0x0172 +MX28_PAD_GPMI_ALE__SSP3_D4 0x01a2 +MX28_PAD_GPMI_CLE__SSP3_D5 0x01b2 +MX28_PAD_LCD_D00__ETM_DA0 0x1002 +MX28_PAD_LCD_D01__ETM_DA1 0x1012 +MX28_PAD_LCD_D02__ETM_DA2 0x1022 +MX28_PAD_LCD_D03__ETM_DA3 0x1032 +MX28_PAD_LCD_D04__ETM_DA4 0x1042 +MX28_PAD_LCD_D05__ETM_DA5 0x1052 +MX28_PAD_LCD_D06__ETM_DA6 0x1062 +MX28_PAD_LCD_D07__ETM_DA7 0x1072 +MX28_PAD_LCD_D08__ETM_DA8 0x1082 +MX28_PAD_LCD_D09__ETM_DA9 0x1092 +MX28_PAD_LCD_D10__ETM_DA10 0x10a2 +MX28_PAD_LCD_D11__ETM_DA11 0x10b2 +MX28_PAD_LCD_D12__ETM_DA12 0x10c2 +MX28_PAD_LCD_D13__ETM_DA13 0x10d2 +MX28_PAD_LCD_D14__ETM_DA14 0x10e2 +MX28_PAD_LCD_D15__ETM_DA15 0x10f2 +MX28_PAD_LCD_D16__ETM_DA7 0x1102 +MX28_PAD_LCD_D17__ETM_DA6 0x1112 +MX28_PAD_LCD_D18__ETM_DA5 0x1122 +MX28_PAD_LCD_D19__ETM_DA4 0x1132 +MX28_PAD_LCD_D20__ETM_DA3 0x1142 +MX28_PAD_LCD_D21__ETM_DA2 0x1152 +MX28_PAD_LCD_D22__ETM_DA1 0x1162 +MX28_PAD_LCD_D23__ETM_DA0 0x1172 +MX28_PAD_LCD_RD_E__ETM_TCTL 0x1182 +MX28_PAD_LCD_WR_RWN__ETM_TCLK 0x1192 +MX28_PAD_LCD_HSYNC__ETM_TCTL 0x11d2 +MX28_PAD_LCD_DOTCLK__ETM_TCLK 0x11e2 +MX28_PAD_SSP1_SCK__ENET0_1588_EVENT2_OUT 0x20c2 +MX28_PAD_SSP1_CMD__ENET0_1588_EVENT2_IN 0x20d2 +MX28_PAD_SSP1_DATA0__ENET0_1588_EVENT3_OUT 0x20e2 +MX28_PAD_SSP1_DATA3__ENET0_1588_EVENT3_IN 0x20f2 +MX28_PAD_SSP2_SCK__SAIF0_SDATA1 0x2102 +MX28_PAD_SSP2_MOSI__SAIF0_SDATA2 0x2112 +MX28_PAD_SSP2_MISO__SAIF1_SDATA1 0x2122 +MX28_PAD_SSP2_SS0__SAIF1_SDATA2 0x2132 +MX28_PAD_SSP2_SS1__USB1_OVERCURRENT 0x2142 +MX28_PAD_SSP2_SS2__USB0_OVERCURRENT 0x2152 +MX28_PAD_SSP3_SCK__ENET1_1588_EVENT0_OUT 0x2182 +MX28_PAD_SSP3_MOSI__ENET1_1588_EVENT0_IN 0x2192 +MX28_PAD_SSP3_MISO__ENET1_1588_EVENT1_OUT 0x21a2 +MX28_PAD_SSP3_SS0__ENET1_1588_EVENT1_IN 0x21b2 +MX28_PAD_AUART0_RX__DUART_CTS 0x3002 +MX28_PAD_AUART0_TX__DUART_RTS 0x3012 +MX28_PAD_AUART0_CTS__DUART_RX 0x3022 +MX28_PAD_AUART0_RTS__DUART_TX 0x3032 +MX28_PAD_AUART1_RX__PWM_0 0x3042 +MX28_PAD_AUART1_TX__PWM_1 0x3052 +MX28_PAD_AUART1_CTS__TIMROT_ROTARYA 0x3062 +MX28_PAD_AUART1_RTS__TIMROT_ROTARYB 0x3072 +MX28_PAD_AUART2_RX__SSP3_D4 0x3082 +MX28_PAD_AUART2_TX__SSP3_D5 0x3092 +MX28_PAD_AUART2_CTS__SAIF1_BITCLK 0x30a2 +MX28_PAD_AUART2_RTS__SAIF1_LRCLK 0x30b2 +MX28_PAD_AUART3_RX__ENET0_1588_EVENT0_OUT 0x30c2 +MX28_PAD_AUART3_TX__ENET0_1588_EVENT0_IN 0x30d2 +MX28_PAD_AUART3_CTS__ENET0_1588_EVENT1_OUT 0x30e2 +MX28_PAD_AUART3_RTS__ENET0_1588_EVENT1_IN 0x30f2 +MX28_PAD_PWM0__DUART_RX 0x3102 +MX28_PAD_PWM1__DUART_TX 0x3112 +MX28_PAD_PWM2__USB1_OVERCURRENT 0x3122 +MX28_PAD_SAIF0_MCLK__AUART4_CTS 0x3142 +MX28_PAD_SAIF0_LRCLK__AUART4_RTS 0x3152 +MX28_PAD_SAIF0_BITCLK__AUART4_RX 0x3162 +MX28_PAD_SAIF0_SDATA0__AUART4_TX 0x3172 +MX28_PAD_I2C0_SCL__DUART_RX 0x3182 +MX28_PAD_I2C0_SDA__DUART_TX 0x3192 +MX28_PAD_SAIF1_SDATA0__SAIF0_SDATA1 0x31a2 +MX28_PAD_SPDIF__ENET1_RX_ER 0x31b2 +MX28_PAD_ENET0_MDC__SAIF0_SDATA1 0x4002 +MX28_PAD_ENET0_MDIO__SAIF0_SDATA2 0x4012 +MX28_PAD_ENET0_RX_EN__SAIF1_SDATA1 0x4022 +MX28_PAD_ENET0_RXD0__SAIF1_SDATA2 0x4032 +MX28_PAD_ENET0_TX_CLK__ENET0_1588_EVENT2_OUT 0x4052 +MX28_PAD_ENET0_RXD2__ENET0_1588_EVENT0_OUT 0x4092 +MX28_PAD_ENET0_RXD3__ENET0_1588_EVENT0_IN 0x40a2 +MX28_PAD_ENET0_TXD2__ENET0_1588_EVENT1_OUT 0x40b2 +MX28_PAD_ENET0_TXD3__ENET0_1588_EVENT1_IN 0x40c2 +MX28_PAD_ENET0_RX_CLK__ENET0_1588_EVENT2_IN 0x40d2 +MX28_PAD_ENET0_COL__ENET0_1588_EVENT3_OUT 0x40e2 +MX28_PAD_ENET0_CRS__ENET0_1588_EVENT3_IN 0x40f2 +MX28_PAD_GPMI_D00__GPIO_0_0 0x0003 +MX28_PAD_GPMI_D01__GPIO_0_1 0x0013 +MX28_PAD_GPMI_D02__GPIO_0_2 0x0023 +MX28_PAD_GPMI_D03__GPIO_0_3 0x0033 +MX28_PAD_GPMI_D04__GPIO_0_4 0x0043 +MX28_PAD_GPMI_D05__GPIO_0_5 0x0053 +MX28_PAD_GPMI_D06__GPIO_0_6 0x0063 +MX28_PAD_GPMI_D07__GPIO_0_7 0x0073 +MX28_PAD_GPMI_CE0N__GPIO_0_16 0x0103 +MX28_PAD_GPMI_CE1N__GPIO_0_17 0x0113 +MX28_PAD_GPMI_CE2N__GPIO_0_18 0x0123 +MX28_PAD_GPMI_CE3N__GPIO_0_19 0x0133 +MX28_PAD_GPMI_RDY0__GPIO_0_20 0x0143 +MX28_PAD_GPMI_RDY1__GPIO_0_21 0x0153 +MX28_PAD_GPMI_RDY2__GPIO_0_22 0x0163 +MX28_PAD_GPMI_RDY3__GPIO_0_23 0x0173 +MX28_PAD_GPMI_RDN__GPIO_0_24 0x0183 +MX28_PAD_GPMI_WRN__GPIO_0_25 0x0193 +MX28_PAD_GPMI_ALE__GPIO_0_26 0x01a3 +MX28_PAD_GPMI_CLE__GPIO_0_27 0x01b3 +MX28_PAD_GPMI_RESETN__GPIO_0_28 0x01c3 +MX28_PAD_LCD_D00__GPIO_1_0 0x1003 +MX28_PAD_LCD_D01__GPIO_1_1 0x1013 +MX28_PAD_LCD_D02__GPIO_1_2 0x1023 +MX28_PAD_LCD_D03__GPIO_1_3 0x1033 +MX28_PAD_LCD_D04__GPIO_1_4 0x1043 +MX28_PAD_LCD_D05__GPIO_1_5 0x1053 +MX28_PAD_LCD_D06__GPIO_1_6 0x1063 +MX28_PAD_LCD_D07__GPIO_1_7 0x1073 +MX28_PAD_LCD_D08__GPIO_1_8 0x1083 +MX28_PAD_LCD_D09__GPIO_1_9 0x1093 +MX28_PAD_LCD_D10__GPIO_1_10 0x10a3 +MX28_PAD_LCD_D11__GPIO_1_11 0x10b3 +MX28_PAD_LCD_D12__GPIO_1_12 0x10c3 +MX28_PAD_LCD_D13__GPIO_1_13 0x10d3 +MX28_PAD_LCD_D14__GPIO_1_14 0x10e3 +MX28_PAD_LCD_D15__GPIO_1_15 0x10f3 +MX28_PAD_LCD_D16__GPIO_1_16 0x1103 +MX28_PAD_LCD_D17__GPIO_1_17 0x1113 +MX28_PAD_LCD_D18__GPIO_1_18 0x1123 +MX28_PAD_LCD_D19__GPIO_1_19 0x1133 +MX28_PAD_LCD_D20__GPIO_1_20 0x1143 +MX28_PAD_LCD_D21__GPIO_1_21 0x1153 +MX28_PAD_LCD_D22__GPIO_1_22 0x1163 +MX28_PAD_LCD_D23__GPIO_1_23 0x1173 +MX28_PAD_LCD_RD_E__GPIO_1_24 0x1183 +MX28_PAD_LCD_WR_RWN__GPIO_1_25 0x1193 +MX28_PAD_LCD_RS__GPIO_1_26 0x11a3 +MX28_PAD_LCD_CS__GPIO_1_27 0x11b3 +MX28_PAD_LCD_VSYNC__GPIO_1_28 0x11c3 +MX28_PAD_LCD_HSYNC__GPIO_1_29 0x11d3 +MX28_PAD_LCD_DOTCLK__GPIO_1_30 0x11e3 +MX28_PAD_LCD_ENABLE__GPIO_1_31 0x11f3 +MX28_PAD_SSP0_DATA0__GPIO_2_0 0x2003 +MX28_PAD_SSP0_DATA1__GPIO_2_1 0x2013 +MX28_PAD_SSP0_DATA2__GPIO_2_2 0x2023 +MX28_PAD_SSP0_DATA3__GPIO_2_3 0x2033 +MX28_PAD_SSP0_DATA4__GPIO_2_4 0x2043 +MX28_PAD_SSP0_DATA5__GPIO_2_5 0x2053 +MX28_PAD_SSP0_DATA6__GPIO_2_6 0x2063 +MX28_PAD_SSP0_DATA7__GPIO_2_7 0x2073 +MX28_PAD_SSP0_CMD__GPIO_2_8 0x2083 +MX28_PAD_SSP0_DETECT__GPIO_2_9 0x2093 +MX28_PAD_SSP0_SCK__GPIO_2_10 0x20a3 +MX28_PAD_SSP1_SCK__GPIO_2_12 0x20c3 +MX28_PAD_SSP1_CMD__GPIO_2_13 0x20d3 +MX28_PAD_SSP1_DATA0__GPIO_2_14 0x20e3 +MX28_PAD_SSP1_DATA3__GPIO_2_15 0x20f3 +MX28_PAD_SSP2_SCK__GPIO_2_16 0x2103 +MX28_PAD_SSP2_MOSI__GPIO_2_17 0x2113 +MX28_PAD_SSP2_MISO__GPIO_2_18 0x2123 +MX28_PAD_SSP2_SS0__GPIO_2_19 0x2133 +MX28_PAD_SSP2_SS1__GPIO_2_20 0x2143 +MX28_PAD_SSP2_SS2__GPIO_2_21 0x2153 +MX28_PAD_SSP3_SCK__GPIO_2_24 0x2183 +MX28_PAD_SSP3_MOSI__GPIO_2_25 0x2193 +MX28_PAD_SSP3_MISO__GPIO_2_26 0x21a3 +MX28_PAD_SSP3_SS0__GPIO_2_27 0x21b3 +MX28_PAD_AUART0_RX__GPIO_3_0 0x3003 +MX28_PAD_AUART0_TX__GPIO_3_1 0x3013 +MX28_PAD_AUART0_CTS__GPIO_3_2 0x3023 +MX28_PAD_AUART0_RTS__GPIO_3_3 0x3033 +MX28_PAD_AUART1_RX__GPIO_3_4 0x3043 +MX28_PAD_AUART1_TX__GPIO_3_5 0x3053 +MX28_PAD_AUART1_CTS__GPIO_3_6 0x3063 +MX28_PAD_AUART1_RTS__GPIO_3_7 0x3073 +MX28_PAD_AUART2_RX__GPIO_3_8 0x3083 +MX28_PAD_AUART2_TX__GPIO_3_9 0x3093 +MX28_PAD_AUART2_CTS__GPIO_3_10 0x30a3 +MX28_PAD_AUART2_RTS__GPIO_3_11 0x30b3 +MX28_PAD_AUART3_RX__GPIO_3_12 0x30c3 +MX28_PAD_AUART3_TX__GPIO_3_13 0x30d3 +MX28_PAD_AUART3_CTS__GPIO_3_14 0x30e3 +MX28_PAD_AUART3_RTS__GPIO_3_15 0x30f3 +MX28_PAD_PWM0__GPIO_3_16 0x3103 +MX28_PAD_PWM1__GPIO_3_17 0x3113 +MX28_PAD_PWM2__GPIO_3_18 0x3123 +MX28_PAD_SAIF0_MCLK__GPIO_3_20 0x3143 +MX28_PAD_SAIF0_LRCLK__GPIO_3_21 0x3153 +MX28_PAD_SAIF0_BITCLK__GPIO_3_22 0x3163 +MX28_PAD_SAIF0_SDATA0__GPIO_3_23 0x3173 +MX28_PAD_I2C0_SCL__GPIO_3_24 0x3183 +MX28_PAD_I2C0_SDA__GPIO_3_25 0x3193 +MX28_PAD_SAIF1_SDATA0__GPIO_3_26 0x31a3 +MX28_PAD_SPDIF__GPIO_3_27 0x31b3 +MX28_PAD_PWM3__GPIO_3_28 0x31c3 +MX28_PAD_PWM4__GPIO_3_29 0x31d3 +MX28_PAD_LCD_RESET__GPIO_3_30 0x31e3 +MX28_PAD_ENET0_MDC__GPIO_4_0 0x4003 +MX28_PAD_ENET0_MDIO__GPIO_4_1 0x4013 +MX28_PAD_ENET0_RX_EN__GPIO_4_2 0x4023 +MX28_PAD_ENET0_RXD0__GPIO_4_3 0x4033 +MX28_PAD_ENET0_RXD1__GPIO_4_4 0x4043 +MX28_PAD_ENET0_TX_CLK__GPIO_4_5 0x4053 +MX28_PAD_ENET0_TX_EN__GPIO_4_6 0x4063 +MX28_PAD_ENET0_TXD0__GPIO_4_7 0x4073 +MX28_PAD_ENET0_TXD1__GPIO_4_8 0x4083 +MX28_PAD_ENET0_RXD2__GPIO_4_9 0x4093 +MX28_PAD_ENET0_RXD3__GPIO_4_10 0x40a3 +MX28_PAD_ENET0_TXD2__GPIO_4_11 0x40b3 +MX28_PAD_ENET0_TXD3__GPIO_4_12 0x40c3 +MX28_PAD_ENET0_RX_CLK__GPIO_4_13 0x40d3 +MX28_PAD_ENET0_COL__GPIO_4_14 0x40e3 +MX28_PAD_ENET0_CRS__GPIO_4_15 0x40f3 +MX28_PAD_ENET_CLK__GPIO_4_16 0x4103 +MX28_PAD_JTAG_RTCK__GPIO_4_20 0x4143 + +Valid values for i.MX23 pinmux-id: + +pinmux id +------ -- +MX23_PAD_GPMI_D00__GPMI_D00 0x0000 +MX23_PAD_GPMI_D01__GPMI_D01 0x0010 +MX23_PAD_GPMI_D02__GPMI_D02 0x0020 +MX23_PAD_GPMI_D03__GPMI_D03 0x0030 +MX23_PAD_GPMI_D04__GPMI_D04 0x0040 +MX23_PAD_GPMI_D05__GPMI_D05 0x0050 +MX23_PAD_GPMI_D06__GPMI_D06 0x0060 +MX23_PAD_GPMI_D07__GPMI_D07 0x0070 +MX23_PAD_GPMI_D08__GPMI_D08 0x0080 +MX23_PAD_GPMI_D09__GPMI_D09 0x0090 +MX23_PAD_GPMI_D10__GPMI_D10 0x00a0 +MX23_PAD_GPMI_D11__GPMI_D11 0x00b0 +MX23_PAD_GPMI_D12__GPMI_D12 0x00c0 +MX23_PAD_GPMI_D13__GPMI_D13 0x00d0 +MX23_PAD_GPMI_D14__GPMI_D14 0x00e0 +MX23_PAD_GPMI_D15__GPMI_D15 0x00f0 +MX23_PAD_GPMI_CLE__GPMI_CLE 0x0100 +MX23_PAD_GPMI_ALE__GPMI_ALE 0x0110 +MX23_PAD_GPMI_CE2N__GPMI_CE2N 0x0120 +MX23_PAD_GPMI_RDY0__GPMI_RDY0 0x0130 +MX23_PAD_GPMI_RDY1__GPMI_RDY1 0x0140 +MX23_PAD_GPMI_RDY2__GPMI_RDY2 0x0150 +MX23_PAD_GPMI_RDY3__GPMI_RDY3 0x0160 +MX23_PAD_GPMI_WPN__GPMI_WPN 0x0170 +MX23_PAD_GPMI_WRN__GPMI_WRN 0x0180 +MX23_PAD_GPMI_RDN__GPMI_RDN 0x0190 +MX23_PAD_AUART1_CTS__AUART1_CTS 0x01a0 +MX23_PAD_AUART1_RTS__AUART1_RTS 0x01b0 +MX23_PAD_AUART1_RX__AUART1_RX 0x01c0 +MX23_PAD_AUART1_TX__AUART1_TX 0x01d0 +MX23_PAD_I2C_SCL__I2C_SCL 0x01e0 +MX23_PAD_I2C_SDA__I2C_SDA 0x01f0 +MX23_PAD_LCD_D00__LCD_D00 0x1000 +MX23_PAD_LCD_D01__LCD_D01 0x1010 +MX23_PAD_LCD_D02__LCD_D02 0x1020 +MX23_PAD_LCD_D03__LCD_D03 0x1030 +MX23_PAD_LCD_D04__LCD_D04 0x1040 +MX23_PAD_LCD_D05__LCD_D05 0x1050 +MX23_PAD_LCD_D06__LCD_D06 0x1060 +MX23_PAD_LCD_D07__LCD_D07 0x1070 +MX23_PAD_LCD_D08__LCD_D08 0x1080 +MX23_PAD_LCD_D09__LCD_D09 0x1090 +MX23_PAD_LCD_D10__LCD_D10 0x10a0 +MX23_PAD_LCD_D11__LCD_D11 0x10b0 +MX23_PAD_LCD_D12__LCD_D12 0x10c0 +MX23_PAD_LCD_D13__LCD_D13 0x10d0 +MX23_PAD_LCD_D14__LCD_D14 0x10e0 +MX23_PAD_LCD_D15__LCD_D15 0x10f0 +MX23_PAD_LCD_D16__LCD_D16 0x1100 +MX23_PAD_LCD_D17__LCD_D17 0x1110 +MX23_PAD_LCD_RESET__LCD_RESET 0x1120 +MX23_PAD_LCD_RS__LCD_RS 0x1130 +MX23_PAD_LCD_WR__LCD_WR 0x1140 +MX23_PAD_LCD_CS__LCD_CS 0x1150 +MX23_PAD_LCD_DOTCK__LCD_DOTCK 0x1160 +MX23_PAD_LCD_ENABLE__LCD_ENABLE 0x1170 +MX23_PAD_LCD_HSYNC__LCD_HSYNC 0x1180 +MX23_PAD_LCD_VSYNC__LCD_VSYNC 0x1190 +MX23_PAD_PWM0__PWM0 0x11a0 +MX23_PAD_PWM1__PWM1 0x11b0 +MX23_PAD_PWM2__PWM2 0x11c0 +MX23_PAD_PWM3__PWM3 0x11d0 +MX23_PAD_PWM4__PWM4 0x11e0 +MX23_PAD_SSP1_CMD__SSP1_CMD 0x2000 +MX23_PAD_SSP1_DETECT__SSP1_DETECT 0x2010 +MX23_PAD_SSP1_DATA0__SSP1_DATA0 0x2020 +MX23_PAD_SSP1_DATA1__SSP1_DATA1 0x2030 +MX23_PAD_SSP1_DATA2__SSP1_DATA2 0x2040 +MX23_PAD_SSP1_DATA3__SSP1_DATA3 0x2050 +MX23_PAD_SSP1_SCK__SSP1_SCK 0x2060 +MX23_PAD_ROTARYA__ROTARYA 0x2070 +MX23_PAD_ROTARYB__ROTARYB 0x2080 +MX23_PAD_EMI_A00__EMI_A00 0x2090 +MX23_PAD_EMI_A01__EMI_A01 0x20a0 +MX23_PAD_EMI_A02__EMI_A02 0x20b0 +MX23_PAD_EMI_A03__EMI_A03 0x20c0 +MX23_PAD_EMI_A04__EMI_A04 0x20d0 +MX23_PAD_EMI_A05__EMI_A05 0x20e0 +MX23_PAD_EMI_A06__EMI_A06 0x20f0 +MX23_PAD_EMI_A07__EMI_A07 0x2100 +MX23_PAD_EMI_A08__EMI_A08 0x2110 +MX23_PAD_EMI_A09__EMI_A09 0x2120 +MX23_PAD_EMI_A10__EMI_A10 0x2130 +MX23_PAD_EMI_A11__EMI_A11 0x2140 +MX23_PAD_EMI_A12__EMI_A12 0x2150 +MX23_PAD_EMI_BA0__EMI_BA0 0x2160 +MX23_PAD_EMI_BA1__EMI_BA1 0x2170 +MX23_PAD_EMI_CASN__EMI_CASN 0x2180 +MX23_PAD_EMI_CE0N__EMI_CE0N 0x2190 +MX23_PAD_EMI_CE1N__EMI_CE1N 0x21a0 +MX23_PAD_GPMI_CE1N__GPMI_CE1N 0x21b0 +MX23_PAD_GPMI_CE0N__GPMI_CE0N 0x21c0 +MX23_PAD_EMI_CKE__EMI_CKE 0x21d0 +MX23_PAD_EMI_RASN__EMI_RASN 0x21e0 +MX23_PAD_EMI_WEN__EMI_WEN 0x21f0 +MX23_PAD_EMI_D00__EMI_D00 0x3000 +MX23_PAD_EMI_D01__EMI_D01 0x3010 +MX23_PAD_EMI_D02__EMI_D02 0x3020 +MX23_PAD_EMI_D03__EMI_D03 0x3030 +MX23_PAD_EMI_D04__EMI_D04 0x3040 +MX23_PAD_EMI_D05__EMI_D05 0x3050 +MX23_PAD_EMI_D06__EMI_D06 0x3060 +MX23_PAD_EMI_D07__EMI_D07 0x3070 +MX23_PAD_EMI_D08__EMI_D08 0x3080 +MX23_PAD_EMI_D09__EMI_D09 0x3090 +MX23_PAD_EMI_D10__EMI_D10 0x30a0 +MX23_PAD_EMI_D11__EMI_D11 0x30b0 +MX23_PAD_EMI_D12__EMI_D12 0x30c0 +MX23_PAD_EMI_D13__EMI_D13 0x30d0 +MX23_PAD_EMI_D14__EMI_D14 0x30e0 +MX23_PAD_EMI_D15__EMI_D15 0x30f0 +MX23_PAD_EMI_DQM0__EMI_DQM0 0x3100 +MX23_PAD_EMI_DQM1__EMI_DQM1 0x3110 +MX23_PAD_EMI_DQS0__EMI_DQS0 0x3120 +MX23_PAD_EMI_DQS1__EMI_DQS1 0x3130 +MX23_PAD_EMI_CLK__EMI_CLK 0x3140 +MX23_PAD_EMI_CLKN__EMI_CLKN 0x3150 +MX23_PAD_GPMI_D00__LCD_D8 0x0001 +MX23_PAD_GPMI_D01__LCD_D9 0x0011 +MX23_PAD_GPMI_D02__LCD_D10 0x0021 +MX23_PAD_GPMI_D03__LCD_D11 0x0031 +MX23_PAD_GPMI_D04__LCD_D12 0x0041 +MX23_PAD_GPMI_D05__LCD_D13 0x0051 +MX23_PAD_GPMI_D06__LCD_D14 0x0061 +MX23_PAD_GPMI_D07__LCD_D15 0x0071 +MX23_PAD_GPMI_D08__LCD_D18 0x0081 +MX23_PAD_GPMI_D09__LCD_D19 0x0091 +MX23_PAD_GPMI_D10__LCD_D20 0x00a1 +MX23_PAD_GPMI_D11__LCD_D21 0x00b1 +MX23_PAD_GPMI_D12__LCD_D22 0x00c1 +MX23_PAD_GPMI_D13__LCD_D23 0x00d1 +MX23_PAD_GPMI_D14__AUART2_RX 0x00e1 +MX23_PAD_GPMI_D15__AUART2_TX 0x00f1 +MX23_PAD_GPMI_CLE__LCD_D16 0x0101 +MX23_PAD_GPMI_ALE__LCD_D17 0x0111 +MX23_PAD_GPMI_CE2N__ATA_A2 0x0121 +MX23_PAD_AUART1_RTS__IR_CLK 0x01b1 +MX23_PAD_AUART1_RX__IR_RX 0x01c1 +MX23_PAD_AUART1_TX__IR_TX 0x01d1 +MX23_PAD_I2C_SCL__GPMI_RDY2 0x01e1 +MX23_PAD_I2C_SDA__GPMI_CE2N 0x01f1 +MX23_PAD_LCD_D00__ETM_DA8 0x1001 +MX23_PAD_LCD_D01__ETM_DA9 0x1011 +MX23_PAD_LCD_D02__ETM_DA10 0x1021 +MX23_PAD_LCD_D03__ETM_DA11 0x1031 +MX23_PAD_LCD_D04__ETM_DA12 0x1041 +MX23_PAD_LCD_D05__ETM_DA13 0x1051 +MX23_PAD_LCD_D06__ETM_DA14 0x1061 +MX23_PAD_LCD_D07__ETM_DA15 0x1071 +MX23_PAD_LCD_D08__ETM_DA0 0x1081 +MX23_PAD_LCD_D09__ETM_DA1 0x1091 +MX23_PAD_LCD_D10__ETM_DA2 0x10a1 +MX23_PAD_LCD_D11__ETM_DA3 0x10b1 +MX23_PAD_LCD_D12__ETM_DA4 0x10c1 +MX23_PAD_LCD_D13__ETM_DA5 0x10d1 +MX23_PAD_LCD_D14__ETM_DA6 0x10e1 +MX23_PAD_LCD_D15__ETM_DA7 0x10f1 +MX23_PAD_LCD_RESET__ETM_TCTL 0x1121 +MX23_PAD_LCD_RS__ETM_TCLK 0x1131 +MX23_PAD_LCD_DOTCK__GPMI_RDY3 0x1161 +MX23_PAD_LCD_ENABLE__I2C_SCL 0x1171 +MX23_PAD_LCD_HSYNC__I2C_SDA 0x1181 +MX23_PAD_LCD_VSYNC__LCD_BUSY 0x1191 +MX23_PAD_PWM0__ROTARYA 0x11a1 +MX23_PAD_PWM1__ROTARYB 0x11b1 +MX23_PAD_PWM2__GPMI_RDY3 0x11c1 +MX23_PAD_PWM3__ETM_TCTL 0x11d1 +MX23_PAD_PWM4__ETM_TCLK 0x11e1 +MX23_PAD_SSP1_DETECT__GPMI_CE3N 0x2011 +MX23_PAD_SSP1_DATA1__I2C_SCL 0x2031 +MX23_PAD_SSP1_DATA2__I2C_SDA 0x2041 +MX23_PAD_ROTARYA__AUART2_RTS 0x2071 +MX23_PAD_ROTARYB__AUART2_CTS 0x2081 +MX23_PAD_GPMI_D00__SSP2_DATA0 0x0002 +MX23_PAD_GPMI_D01__SSP2_DATA1 0x0012 +MX23_PAD_GPMI_D02__SSP2_DATA2 0x0022 +MX23_PAD_GPMI_D03__SSP2_DATA3 0x0032 +MX23_PAD_GPMI_D04__SSP2_DATA4 0x0042 +MX23_PAD_GPMI_D05__SSP2_DATA5 0x0052 +MX23_PAD_GPMI_D06__SSP2_DATA6 0x0062 +MX23_PAD_GPMI_D07__SSP2_DATA7 0x0072 +MX23_PAD_GPMI_D08__SSP1_DATA4 0x0082 +MX23_PAD_GPMI_D09__SSP1_DATA5 0x0092 +MX23_PAD_GPMI_D10__SSP1_DATA6 0x00a2 +MX23_PAD_GPMI_D11__SSP1_DATA7 0x00b2 +MX23_PAD_GPMI_D15__GPMI_CE3N 0x00f2 +MX23_PAD_GPMI_RDY0__SSP2_DETECT 0x0132 +MX23_PAD_GPMI_RDY1__SSP2_CMD 0x0142 +MX23_PAD_GPMI_WRN__SSP2_SCK 0x0182 +MX23_PAD_AUART1_CTS__SSP1_DATA4 0x01a2 +MX23_PAD_AUART1_RTS__SSP1_DATA5 0x01b2 +MX23_PAD_AUART1_RX__SSP1_DATA6 0x01c2 +MX23_PAD_AUART1_TX__SSP1_DATA7 0x01d2 +MX23_PAD_I2C_SCL__AUART1_TX 0x01e2 +MX23_PAD_I2C_SDA__AUART1_RX 0x01f2 +MX23_PAD_LCD_D08__SAIF2_SDATA0 0x1082 +MX23_PAD_LCD_D09__SAIF1_SDATA0 0x1092 +MX23_PAD_LCD_D10__SAIF_MCLK_BITCLK 0x10a2 +MX23_PAD_LCD_D11__SAIF_LRCLK 0x10b2 +MX23_PAD_LCD_D12__SAIF2_SDATA1 0x10c2 +MX23_PAD_LCD_D13__SAIF2_SDATA2 0x10d2 +MX23_PAD_LCD_D14__SAIF1_SDATA2 0x10e2 +MX23_PAD_LCD_D15__SAIF1_SDATA1 0x10f2 +MX23_PAD_LCD_D16__SAIF_ALT_BITCLK 0x1102 +MX23_PAD_LCD_RESET__GPMI_CE3N 0x1122 +MX23_PAD_PWM0__DUART_RX 0x11a2 +MX23_PAD_PWM1__DUART_TX 0x11b2 +MX23_PAD_PWM3__AUART1_CTS 0x11d2 +MX23_PAD_PWM4__AUART1_RTS 0x11e2 +MX23_PAD_SSP1_CMD__JTAG_TDO 0x2002 +MX23_PAD_SSP1_DETECT__USB_OTG_ID 0x2012 +MX23_PAD_SSP1_DATA0__JTAG_TDI 0x2022 +MX23_PAD_SSP1_DATA1__JTAG_TCLK 0x2032 +MX23_PAD_SSP1_DATA2__JTAG_RTCK 0x2042 +MX23_PAD_SSP1_DATA3__JTAG_TMS 0x2052 +MX23_PAD_SSP1_SCK__JTAG_TRST 0x2062 +MX23_PAD_ROTARYA__SPDIF 0x2072 +MX23_PAD_ROTARYB__GPMI_CE3N 0x2082 +MX23_PAD_GPMI_D00__GPIO_0_0 0x0003 +MX23_PAD_GPMI_D01__GPIO_0_1 0x0013 +MX23_PAD_GPMI_D02__GPIO_0_2 0x0023 +MX23_PAD_GPMI_D03__GPIO_0_3 0x0033 +MX23_PAD_GPMI_D04__GPIO_0_4 0x0043 +MX23_PAD_GPMI_D05__GPIO_0_5 0x0053 +MX23_PAD_GPMI_D06__GPIO_0_6 0x0063 +MX23_PAD_GPMI_D07__GPIO_0_7 0x0073 +MX23_PAD_GPMI_D08__GPIO_0_8 0x0083 +MX23_PAD_GPMI_D09__GPIO_0_9 0x0093 +MX23_PAD_GPMI_D10__GPIO_0_10 0x00a3 +MX23_PAD_GPMI_D11__GPIO_0_11 0x00b3 +MX23_PAD_GPMI_D12__GPIO_0_12 0x00c3 +MX23_PAD_GPMI_D13__GPIO_0_13 0x00d3 +MX23_PAD_GPMI_D14__GPIO_0_14 0x00e3 +MX23_PAD_GPMI_D15__GPIO_0_15 0x00f3 +MX23_PAD_GPMI_CLE__GPIO_0_16 0x0103 +MX23_PAD_GPMI_ALE__GPIO_0_17 0x0113 +MX23_PAD_GPMI_CE2N__GPIO_0_18 0x0123 +MX23_PAD_GPMI_RDY0__GPIO_0_19 0x0133 +MX23_PAD_GPMI_RDY1__GPIO_0_20 0x0143 +MX23_PAD_GPMI_RDY2__GPIO_0_21 0x0153 +MX23_PAD_GPMI_RDY3__GPIO_0_22 0x0163 +MX23_PAD_GPMI_WPN__GPIO_0_23 0x0173 +MX23_PAD_GPMI_WRN__GPIO_0_24 0x0183 +MX23_PAD_GPMI_RDN__GPIO_0_25 0x0193 +MX23_PAD_AUART1_CTS__GPIO_0_26 0x01a3 +MX23_PAD_AUART1_RTS__GPIO_0_27 0x01b3 +MX23_PAD_AUART1_RX__GPIO_0_28 0x01c3 +MX23_PAD_AUART1_TX__GPIO_0_29 0x01d3 +MX23_PAD_I2C_SCL__GPIO_0_30 0x01e3 +MX23_PAD_I2C_SDA__GPIO_0_31 0x01f3 +MX23_PAD_LCD_D00__GPIO_1_0 0x1003 +MX23_PAD_LCD_D01__GPIO_1_1 0x1013 +MX23_PAD_LCD_D02__GPIO_1_2 0x1023 +MX23_PAD_LCD_D03__GPIO_1_3 0x1033 +MX23_PAD_LCD_D04__GPIO_1_4 0x1043 +MX23_PAD_LCD_D05__GPIO_1_5 0x1053 +MX23_PAD_LCD_D06__GPIO_1_6 0x1063 +MX23_PAD_LCD_D07__GPIO_1_7 0x1073 +MX23_PAD_LCD_D08__GPIO_1_8 0x1083 +MX23_PAD_LCD_D09__GPIO_1_9 0x1093 +MX23_PAD_LCD_D10__GPIO_1_10 0x10a3 +MX23_PAD_LCD_D11__GPIO_1_11 0x10b3 +MX23_PAD_LCD_D12__GPIO_1_12 0x10c3 +MX23_PAD_LCD_D13__GPIO_1_13 0x10d3 +MX23_PAD_LCD_D14__GPIO_1_14 0x10e3 +MX23_PAD_LCD_D15__GPIO_1_15 0x10f3 +MX23_PAD_LCD_D16__GPIO_1_16 0x1103 +MX23_PAD_LCD_D17__GPIO_1_17 0x1113 +MX23_PAD_LCD_RESET__GPIO_1_18 0x1123 +MX23_PAD_LCD_RS__GPIO_1_19 0x1133 +MX23_PAD_LCD_WR__GPIO_1_20 0x1143 +MX23_PAD_LCD_CS__GPIO_1_21 0x1153 +MX23_PAD_LCD_DOTCK__GPIO_1_22 0x1163 +MX23_PAD_LCD_ENABLE__GPIO_1_23 0x1173 +MX23_PAD_LCD_HSYNC__GPIO_1_24 0x1183 +MX23_PAD_LCD_VSYNC__GPIO_1_25 0x1193 +MX23_PAD_PWM0__GPIO_1_26 0x11a3 +MX23_PAD_PWM1__GPIO_1_27 0x11b3 +MX23_PAD_PWM2__GPIO_1_28 0x11c3 +MX23_PAD_PWM3__GPIO_1_29 0x11d3 +MX23_PAD_PWM4__GPIO_1_30 0x11e3 +MX23_PAD_SSP1_CMD__GPIO_2_0 0x2003 +MX23_PAD_SSP1_DETECT__GPIO_2_1 0x2013 +MX23_PAD_SSP1_DATA0__GPIO_2_2 0x2023 +MX23_PAD_SSP1_DATA1__GPIO_2_3 0x2033 +MX23_PAD_SSP1_DATA2__GPIO_2_4 0x2043 +MX23_PAD_SSP1_DATA3__GPIO_2_5 0x2053 +MX23_PAD_SSP1_SCK__GPIO_2_6 0x2063 +MX23_PAD_ROTARYA__GPIO_2_7 0x2073 +MX23_PAD_ROTARYB__GPIO_2_8 0x2083 +MX23_PAD_EMI_A00__GPIO_2_9 0x2093 +MX23_PAD_EMI_A01__GPIO_2_10 0x20a3 +MX23_PAD_EMI_A02__GPIO_2_11 0x20b3 +MX23_PAD_EMI_A03__GPIO_2_12 0x20c3 +MX23_PAD_EMI_A04__GPIO_2_13 0x20d3 +MX23_PAD_EMI_A05__GPIO_2_14 0x20e3 +MX23_PAD_EMI_A06__GPIO_2_15 0x20f3 +MX23_PAD_EMI_A07__GPIO_2_16 0x2103 +MX23_PAD_EMI_A08__GPIO_2_17 0x2113 +MX23_PAD_EMI_A09__GPIO_2_18 0x2123 +MX23_PAD_EMI_A10__GPIO_2_19 0x2133 +MX23_PAD_EMI_A11__GPIO_2_20 0x2143 +MX23_PAD_EMI_A12__GPIO_2_21 0x2153 +MX23_PAD_EMI_BA0__GPIO_2_22 0x2163 +MX23_PAD_EMI_BA1__GPIO_2_23 0x2173 +MX23_PAD_EMI_CASN__GPIO_2_24 0x2183 +MX23_PAD_EMI_CE0N__GPIO_2_25 0x2193 +MX23_PAD_EMI_CE1N__GPIO_2_26 0x21a3 +MX23_PAD_GPMI_CE1N__GPIO_2_27 0x21b3 +MX23_PAD_GPMI_CE0N__GPIO_2_28 0x21c3 +MX23_PAD_EMI_CKE__GPIO_2_29 0x21d3 +MX23_PAD_EMI_RASN__GPIO_2_30 0x21e3 +MX23_PAD_EMI_WEN__GPIO_2_31 0x21f3 diff --git a/trunk/Documentation/devicetree/bindings/pinctrl/nvidia,tegra20-pinmux.txt b/trunk/Documentation/devicetree/bindings/pinctrl/nvidia,tegra20-pinmux.txt new file mode 100644 index 000000000000..c8e578263ce2 --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/pinctrl/nvidia,tegra20-pinmux.txt @@ -0,0 +1,132 @@ +NVIDIA Tegra20 pinmux controller + +Required properties: +- compatible: "nvidia,tegra20-pinmux" +- reg: Should contain the register physical address and length for each of + the tri-state, mux, pull-up/down, and pad control register sets. + +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". + +Tegra'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, tristate, 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 or tristate parameter. For this +reason, even seemingly boolean values are actually tristates in this binding: +unspecified, off, or on. Unspecified is represented as an absent property, +and off/on are represented as integer values 0 and 1. + +Required subnode-properties: +- nvidia,pins : An array of strings. Each string contains the name of a pin or + group. Valid values for these names are listed below. + +Optional subnode-properties: +- nvidia,function: A string containing the name of the function to mux to the + pin or group. Valid values for function names are listed below. See the Tegra + TRM to determine which are valid for each pin or group. +- nvidia,pull: Integer, representing the pull-down/up to apply to the pin. + 0: none, 1: down, 2: up. +- nvidia,tristate: Integer. + 0: drive, 1: tristate. +- nvidia,high-speed-mode: Integer. Enable high speed mode the pins. + 0: no, 1: yes. +- nvidia,schmitt: Integer. Enables Schmitt Trigger on the input. + 0: no, 1: yes. +- nvidia,low-power-mode: Integer. Valid values 0-3. 0 is least power, 3 is + most power. Controls the drive power or current. See "Low Power Mode" + or "LPMD1" and "LPMD0" in the Tegra TRM. +- nvidia,pull-down-strength: Integer. Controls drive strength. 0 is weakest. + The range of valid values depends on the pingroup. See "CAL_DRVDN" in the + Tegra TRM. +- nvidia,pull-up-strength: Integer. Controls drive strength. 0 is weakest. + The range of valid values depends on the pingroup. See "CAL_DRVUP" in the + Tegra TRM. +- nvidia,slew-rate-rising: Integer. Controls rising signal slew rate. 0 is + fastest. The range of valid values depends on the pingroup. See + "DRVDN_SLWR" in the Tegra TRM. +- nvidia,slew-rate-falling: Integer. Controls falling signal slew rate. 0 is + fastest. The range of valid values depends on the pingroup. See + "DRVUP_SLWF" in the Tegra TRM. + +Note that many of these properties are only valid for certain specific pins +or groups. See the Tegra TRM and various pinmux spreadsheets for complete +details regarding which groups support which functionality. The Linux pinctrl +driver may also be a useful reference, since it consolidates, disambiguates, +and corrects data from all those sources. + +Valid values for pin and group names are: + + mux groups: + + These all support nvidia,function, nvidia,tristate, and many support + nvidia,pull. + + ata, atb, atc, atd, ate, cdev1, cdev2, crtp, csus, dap1, dap2, dap3, dap4, + ddc, dta, dtb, dtc, dtd, dte, dtf, gma, gmb, gmc, gmd, gme, gpu, gpu7, + gpv, hdint, i2cp, irrx, irtx, kbca, kbcb, kbcc, kbcd, kbce, kbcf, lcsn, + ld0, ld1, ld2, ld3, ld4, ld5, ld6, ld7, ld8, ld9, ld10, ld11, ld12, ld13, + ld14, ld15, ld16, ld17, ldc, ldi, lhp0, lhp1, lhp2, lhs, lm0, lm1, lpp, + lpw0, lpw1, lpw2, lsc0, lsc1, lsck, lsda, lsdi, lspi, lvp0, lvp1, lvs, + owc, pmc, pta, rm, sdb, sdc, sdd, sdio1, slxa, slxc, slxd, slxk, spdi, + spdo, spia, spib, spic, spid, spie, spif, spig, spih, uaa, uab, uac, uad, + uca, ucb, uda. + + tristate groups: + + These only support nvidia,pull. + + ck32, ddrc, pmca, pmcb, pmcc, pmcd, pmce, xm2c, xm2d, ls, lc, ld17_0, + ld19_18, ld21_20, ld23_22. + + drive groups: + + With some exceptions, these support nvidia,high-speed-mode, + nvidia,schmitt, nvidia,low-power-mode, nvidia,pull-down-strength, + nvidia,pull-up-strength, nvidia,slew_rate-rising, nvidia,slew_rate-falling. + + drive_ao1, drive_ao2, drive_at1, drive_at2, drive_cdev1, drive_cdev2, + drive_csus, drive_dap1, drive_dap2, drive_dap3, drive_dap4, drive_dbg, + drive_lcd1, drive_lcd2, drive_sdmmc2, drive_sdmmc3, drive_spi, drive_uaa, + drive_uab, drive_uart2, drive_uart3, drive_vi1, drive_vi2, drive_xm2a, + drive_xm2c, drive_xm2d, drive_xm2clk, drive_sdio1, drive_crt, drive_ddc, + drive_gma, drive_gmb, drive_gmc, drive_gmd, drive_gme, drive_owr, + drive_uda. + +Example: + + pinctrl@70000000 { + compatible = "nvidia,tegra20-pinmux"; + reg = < 0x70000014 0x10 /* Tri-state registers */ + 0x70000080 0x20 /* Mux registers */ + 0x700000a0 0x14 /* Pull-up/down registers */ + 0x70000868 0xa8 >; /* Pad control registers */ + }; + +Example board file extract: + + pinctrl@70000000 { + sdio4_default: sdio4_default { + atb { + nvidia,pins = "atb", "gma", "gme"; + nvidia,function = "sdio4"; + nvidia,pull = <0>; + nvidia,tristate = <0>; + }; + }; + }; + + sdhci@c8000600 { + pinctrl-names = "default"; + pinctrl-0 = <&sdio4_default>; + }; diff --git a/trunk/Documentation/devicetree/bindings/pinctrl/nvidia,tegra30-pinmux.txt b/trunk/Documentation/devicetree/bindings/pinctrl/nvidia,tegra30-pinmux.txt new file mode 100644 index 000000000000..c275b70349c1 --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/pinctrl/nvidia,tegra30-pinmux.txt @@ -0,0 +1,132 @@ +NVIDIA Tegra30 pinmux controller + +The Tegra30 pinctrl binding is very similar to the Tegra20 pinctrl binding, +as described in nvidia,tegra20-pinmux.txt. In fact, this document assumes +that binding as a baseline, and only documents the differences between the +two bindings. + +Required properties: +- compatible: "nvidia,tegra30-pinmux" +- reg: Should contain the register physical address and length for each of + the pad control and mux registers. + +Tegra30 adds the following optional properties for pin configuration subnodes: +- nvidia,enable-input: Integer. Enable the pin's input path. 0: no, 1: yes. +- nvidia,open-drain: Integer. Enable open drain mode. 0: no, 1: yes. +- nvidia,lock: Integer. Lock the pin configuration against further changes + until reset. 0: no, 1: yes. +- nvidia,io-reset: Integer. Reset the IO path. 0: no, 1: yes. + +As with Tegra20, see the Tegra TRM for complete details regarding which groups +support which functionality. + +Valid values for pin and group names are: + + per-pin mux groups: + + These all support nvidia,function, nvidia,tristate, nvidia,pull, + nvidia,enable-input, nvidia,lock. Some support nvidia,open-drain, + nvidia,io-reset. + + clk_32k_out_pa0, uart3_cts_n_pa1, dap2_fs_pa2, dap2_sclk_pa3, + dap2_din_pa4, dap2_dout_pa5, sdmmc3_clk_pa6, sdmmc3_cmd_pa7, gmi_a17_pb0, + gmi_a18_pb1, lcd_pwr0_pb2, lcd_pclk_pb3, sdmmc3_dat3_pb4, sdmmc3_dat2_pb5, + sdmmc3_dat1_pb6, sdmmc3_dat0_pb7, uart3_rts_n_pc0, lcd_pwr1_pc1, + uart2_txd_pc2, uart2_rxd_pc3, gen1_i2c_scl_pc4, gen1_i2c_sda_pc5, + lcd_pwr2_pc6, gmi_wp_n_pc7, sdmmc3_dat5_pd0, sdmmc3_dat4_pd1, lcd_dc1_pd2, + sdmmc3_dat6_pd3, sdmmc3_dat7_pd4, vi_d1_pd5, vi_vsync_pd6, vi_hsync_pd7, + lcd_d0_pe0, lcd_d1_pe1, lcd_d2_pe2, lcd_d3_pe3, lcd_d4_pe4, lcd_d5_pe5, + lcd_d6_pe6, lcd_d7_pe7, lcd_d8_pf0, lcd_d9_pf1, lcd_d10_pf2, lcd_d11_pf3, + lcd_d12_pf4, lcd_d13_pf5, lcd_d14_pf6, lcd_d15_pf7, gmi_ad0_pg0, + gmi_ad1_pg1, gmi_ad2_pg2, gmi_ad3_pg3, gmi_ad4_pg4, gmi_ad5_pg5, + gmi_ad6_pg6, gmi_ad7_pg7, gmi_ad8_ph0, gmi_ad9_ph1, gmi_ad10_ph2, + gmi_ad11_ph3, gmi_ad12_ph4, gmi_ad13_ph5, gmi_ad14_ph6, gmi_ad15_ph7, + gmi_wr_n_pi0, gmi_oe_n_pi1, gmi_dqs_pi2, gmi_cs6_n_pi3, gmi_rst_n_pi4, + gmi_iordy_pi5, gmi_cs7_n_pi6, gmi_wait_pi7, gmi_cs0_n_pj0, lcd_de_pj1, + gmi_cs1_n_pj2, lcd_hsync_pj3, lcd_vsync_pj4, uart2_cts_n_pj5, + uart2_rts_n_pj6, gmi_a16_pj7, gmi_adv_n_pk0, gmi_clk_pk1, gmi_cs4_n_pk2, + gmi_cs2_n_pk3, gmi_cs3_n_pk4, spdif_out_pk5, spdif_in_pk6, gmi_a19_pk7, + vi_d2_pl0, vi_d3_pl1, vi_d4_pl2, vi_d5_pl3, vi_d6_pl4, vi_d7_pl5, + vi_d8_pl6, vi_d9_pl7, lcd_d16_pm0, lcd_d17_pm1, lcd_d18_pm2, lcd_d19_pm3, + lcd_d20_pm4, lcd_d21_pm5, lcd_d22_pm6, lcd_d23_pm7, dap1_fs_pn0, + dap1_din_pn1, dap1_dout_pn2, dap1_sclk_pn3, lcd_cs0_n_pn4, lcd_sdout_pn5, + lcd_dc0_pn6, hdmi_int_pn7, ulpi_data7_po0, ulpi_data0_po1, ulpi_data1_po2, + ulpi_data2_po3, ulpi_data3_po4, ulpi_data4_po5, ulpi_data5_po6, + ulpi_data6_po7, dap3_fs_pp0, dap3_din_pp1, dap3_dout_pp2, dap3_sclk_pp3, + dap4_fs_pp4, dap4_din_pp5, dap4_dout_pp6, dap4_sclk_pp7, kb_col0_pq0, + kb_col1_pq1, kb_col2_pq2, kb_col3_pq3, kb_col4_pq4, kb_col5_pq5, + kb_col6_pq6, kb_col7_pq7, kb_row0_pr0, kb_row1_pr1, kb_row2_pr2, + kb_row3_pr3, kb_row4_pr4, kb_row5_pr5, kb_row6_pr6, kb_row7_pr7, + kb_row8_ps0, kb_row9_ps1, kb_row10_ps2, kb_row11_ps3, kb_row12_ps4, + kb_row13_ps5, kb_row14_ps6, kb_row15_ps7, vi_pclk_pt0, vi_mclk_pt1, + vi_d10_pt2, vi_d11_pt3, vi_d0_pt4, gen2_i2c_scl_pt5, gen2_i2c_sda_pt6, + sdmmc4_cmd_pt7, pu0, pu1, pu2, pu3, pu4, pu5, pu6, jtag_rtck_pu7, pv0, + pv1, pv2, pv3, ddc_scl_pv4, ddc_sda_pv5, crt_hsync_pv6, crt_vsync_pv7, + lcd_cs1_n_pw0, lcd_m1_pw1, spi2_cs1_n_pw2, spi2_cs2_n_pw3, clk1_out_pw4, + clk2_out_pw5, uart3_txd_pw6, uart3_rxd_pw7, spi2_mosi_px0, spi2_miso_px1, + spi2_sck_px2, spi2_cs0_n_px3, spi1_mosi_px4, spi1_sck_px5, spi1_cs0_n_px6, + spi1_miso_px7, ulpi_clk_py0, ulpi_dir_py1, ulpi_nxt_py2, ulpi_stp_py3, + sdmmc1_dat3_py4, sdmmc1_dat2_py5, sdmmc1_dat1_py6, sdmmc1_dat0_py7, + sdmmc1_clk_pz0, sdmmc1_cmd_pz1, lcd_sdin_pz2, lcd_wr_n_pz3, lcd_sck_pz4, + sys_clk_req_pz5, pwr_i2c_scl_pz6, pwr_i2c_sda_pz7, sdmmc4_dat0_paa0, + sdmmc4_dat1_paa1, sdmmc4_dat2_paa2, sdmmc4_dat3_paa3, sdmmc4_dat4_paa4, + sdmmc4_dat5_paa5, sdmmc4_dat6_paa6, sdmmc4_dat7_paa7, pbb0, + cam_i2c_scl_pbb1, cam_i2c_sda_pbb2, pbb3, pbb4, pbb5, pbb6, pbb7, + cam_mclk_pcc0, pcc1, pcc2, sdmmc4_rst_n_pcc3, sdmmc4_clk_pcc4, + clk2_req_pcc5, pex_l2_rst_n_pcc6, pex_l2_clkreq_n_pcc7, + pex_l0_prsnt_n_pdd0, pex_l0_rst_n_pdd1, pex_l0_clkreq_n_pdd2, + pex_wake_n_pdd3, pex_l1_prsnt_n_pdd4, pex_l1_rst_n_pdd5, + pex_l1_clkreq_n_pdd6, pex_l2_prsnt_n_pdd7, clk3_out_pee0, clk3_req_pee1, + clk1_req_pee2, hdmi_cec_pee3, clk_32k_in, core_pwr_req, cpu_pwr_req, owr, + pwr_int_n. + + drive groups: + + These all support nvidia,pull-down-strength, nvidia,pull-up-strength, + nvidia,slew_rate-rising, nvidia,slew_rate-falling. Most but not all + support nvidia,high-speed-mode, nvidia,schmitt, nvidia,low-power-mode. + + ao1, ao2, at1, at2, at3, at4, at5, cdev1, cdev2, cec, crt, csus, dap1, + dap2, dap3, dap4, dbg, ddc, dev3, gma, gmb, gmc, gmd, gme, gmf, gmg, + gmh, gpv, lcd1, lcd2, owr, sdio1, sdio2, sdio3, spi, uaa, uab, uart2, + uart3, uda, vi1. + +Example: + + pinctrl@70000000 { + compatible = "nvidia,tegra30-pinmux"; + reg = < 0x70000868 0xd0 /* Pad control registers */ + 0x70003000 0x3e0 >; /* Mux registers */ + }; + +Example board file extract: + + pinctrl@70000000 { + sdmmc4_default: pinmux { + sdmmc4_clk_pcc4 { + nvidia,pins = "sdmmc4_clk_pcc4", + "sdmmc4_rst_n_pcc3"; + nvidia,function = "sdmmc4"; + nvidia,pull = <0>; + nvidia,tristate = <0>; + }; + sdmmc4_dat0_paa0 { + nvidia,pins = "sdmmc4_dat0_paa0", + "sdmmc4_dat1_paa1", + "sdmmc4_dat2_paa2", + "sdmmc4_dat3_paa3", + "sdmmc4_dat4_paa4", + "sdmmc4_dat5_paa5", + "sdmmc4_dat6_paa6", + "sdmmc4_dat7_paa7"; + nvidia,function = "sdmmc4"; + nvidia,pull = <2>; + nvidia,tristate = <0>; + }; + }; + }; + + sdhci@78000400 { + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc4_default>; + }; diff --git a/trunk/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt b/trunk/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt new file mode 100644 index 000000000000..c95ea8278f87 --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt @@ -0,0 +1,128 @@ +== Introduction == + +Hardware modules that control pin multiplexing or configuration parameters +such as pull-up/down, tri-state, drive-strength etc are designated as pin +controllers. Each pin controller must be represented as a node in device tree, +just like any other hardware module. + +Hardware modules whose signals are affected by pin configuration are +designated client devices. Again, each client device must be represented as a +node in device tree, just like any other hardware module. + +For a client device to operate correctly, certain pin controllers must +set up certain specific pin configurations. Some client devices need a +single static pin configuration, e.g. set up during initialization. Others +need to reconfigure pins at run-time, for example to tri-state pins when the +device is inactive. Hence, each client device can define a set of named +states. The number and names of those states is defined by the client device's +own binding. + +The common pinctrl bindings defined in this file provide an infrastructure +for client device device tree nodes to map those state names to the pin +configuration used by those states. + +Note that pin controllers themselves may also be client devices of themselves. +For example, a pin controller may set up its own "active" state when the +driver loads. This would allow representing a board's static pin configuration +in a single place, rather than splitting it across multiple client device +nodes. The decision to do this or not somewhat rests with the author of +individual board device tree files, and any requirements imposed by the +bindings for the individual client devices in use by that board, i.e. whether +they require certain specific named states for dynamic pin configuration. + +== Pinctrl client devices == + +For each client device individually, every pin state is assigned an integer +ID. These numbers start at 0, and are contiguous. For each state ID, a unique +property exists to define the pin configuration. Each state may also be +assigned a name. When names are used, another property exists to map from +those names to the integer IDs. + +Each client device's own binding determines the set of states the must be +defined in its device tree node, and whether to define the set of state +IDs that must be provided, or whether to define the set of state names that +must be provided. + +Required properties: +pinctrl-0: List of phandles, each pointing at a pin configuration + node. These referenced pin configuration nodes must be child + nodes of the pin controller that they configure. Multiple + entries may exist in this list so that multiple pin + controllers may be configured, or so that a state may be built + from multiple nodes for a single pin controller, each + contributing part of the overall configuration. See the next + section of this document for details of the format of these + pin configuration nodes. + + In some cases, it may be useful to define a state, but for it + to be empty. This may be required when a common IP block is + used in an SoC either without a pin controller, or where the + pin controller does not affect the HW module in question. If + the binding for that IP block requires certain pin states to + exist, they must still be defined, but may be left empty. + +Optional properties: +pinctrl-1: List of phandles, each pointing at a pin configuration + node within a pin controller. +... +pinctrl-n: List of phandles, each pointing at a pin configuration + node within a pin controller. +pinctrl-names: The list of names to assign states. List entry 0 defines the + name for integer state ID 0, list entry 1 for state ID 1, and + so on. + +For example: + + /* For a client device requiring named states */ + device { + pinctrl-names = "active", "idle"; + pinctrl-0 = <&state_0_node_a>; + pinctrl-1 = <&state_1_node_a &state_1_node_b>; + }; + + /* For the same device if using state IDs */ + device { + pinctrl-0 = <&state_0_node_a>; + pinctrl-1 = <&state_1_node_a &state_1_node_b>; + }; + + /* + * For an IP block whose binding supports pin configuration, + * but in use on an SoC that doesn't have any pin control hardware + */ + device { + pinctrl-names = "active", "idle"; + pinctrl-0 = <>; + pinctrl-1 = <>; + }; + +== Pin controller devices == + +Pin controller devices should contain the pin configuration nodes that client +devices reference. + +For example: + + pincontroller { + ... /* Standard DT properties for the device itself elided */ + + state_0_node_a { + ... + }; + state_1_node_a { + ... + }; + state_1_node_b { + ... + }; + } + +The contents of each of those pin configuration child nodes is defined +entirely by the binding for the individual pin controller device. There +exists no common standard for this content. + +The pin configuration nodes need not be direct children of the pin controller +device; they may be grandchildren, for example. Whether this is legal, and +whether there is any interaction between the child and intermediate parent +nodes, is again defined entirely by the binding for the individual pin +controller device. diff --git a/trunk/Documentation/devicetree/bindings/pinctrl/pinctrl_spear.txt b/trunk/Documentation/devicetree/bindings/pinctrl/pinctrl_spear.txt new file mode 100644 index 000000000000..3664d37e6799 --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/pinctrl/pinctrl_spear.txt @@ -0,0 +1,108 @@ +ST Microelectronics, SPEAr pinmux controller + +Required properties: +- compatible : "st,spear300-pinmux" + : "st,spear310-pinmux" + : "st,spear320-pinmux" +- reg : Address range of the pinctrl registers +- st,pinmux-mode: Mandatory for SPEAr300 and SPEAr320 and invalid for others. + - Its values for SPEAr300: + - NAND_MODE : <0> + - NOR_MODE : <1> + - PHOTO_FRAME_MODE : <2> + - LEND_IP_PHONE_MODE : <3> + - HEND_IP_PHONE_MODE : <4> + - LEND_WIFI_PHONE_MODE : <5> + - HEND_WIFI_PHONE_MODE : <6> + - ATA_PABX_WI2S_MODE : <7> + - ATA_PABX_I2S_MODE : <8> + - CAML_LCDW_MODE : <9> + - CAMU_LCD_MODE : <10> + - CAMU_WLCD_MODE : <11> + - CAML_LCD_MODE : <12> + - Its values for SPEAr320: + - AUTO_NET_SMII_MODE : <0> + - AUTO_NET_MII_MODE : <1> + - AUTO_EXP_MODE : <2> + - SMALL_PRINTERS_MODE : <3> + - EXTENDED_MODE : <4> + +Please refer to pinctrl-bindings.txt in this directory for details of the common +pinctrl bindings used by client devices. + +SPEAr's pinmux nodes act as a container for an abitrary number of subnodes. Each +of these subnodes represents muxing for a pin, a group, or a list of pins or +groups. + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Required subnode-properties: +- st,pins : An array of strings. Each string contains the name of a pin or + group. +- st,function: A string containing the name of the function to mux to the pin or + group. See the SPEAr's TRM to determine which are valid for each pin or group. + + Valid values for group and function names can be found from looking at the + group and function arrays in driver files: + drivers/pinctrl/spear/pinctrl-spear3*0.c + +Valid values for group names are: +For All SPEAr3xx machines: + "firda_grp", "i2c0_grp", "ssp_cs_grp", "ssp0_grp", "mii0_grp", + "gpio0_pin0_grp", "gpio0_pin1_grp", "gpio0_pin2_grp", "gpio0_pin3_grp", + "gpio0_pin4_grp", "gpio0_pin5_grp", "uart0_ext_grp", "uart0_grp", + "timer_0_1_grp", timer_0_1_pins, "timer_2_3_grp" + +For SPEAr300 machines: + "fsmc_2chips_grp", "fsmc_4chips_grp", "clcd_lcdmode_grp", + "clcd_pfmode_grp", "tdm_grp", "i2c_clk_grp_grp", "caml_grp", "camu_grp", + "dac_grp", "i2s_grp", "sdhci_4bit_grp", "sdhci_8bit_grp", + "gpio1_0_to_3_grp", "gpio1_4_to_7_grp" + +For SPEAr310 machines: + "emi_cs_0_to_5_grp", "uart1_grp", "uart2_grp", "uart3_grp", "uart4_grp", + "uart5_grp", "fsmc_grp", "rs485_0_grp", "rs485_1_grp", "tdm_grp" + +For SPEAr320 machines: + "clcd_grp", "emi_grp", "fsmc_8bit_grp", "fsmc_16bit_grp", "spp_grp", + "sdhci_led_grp", "sdhci_cd_12_grp", "sdhci_cd_51_grp", "i2s_grp", + "uart1_grp", "uart1_modem_2_to_7_grp", "uart1_modem_31_to_36_grp", + "uart1_modem_34_to_45_grp", "uart1_modem_80_to_85_grp", "uart2_grp", + "uart3_8_9_grp", "uart3_15_16_grp", "uart3_41_42_grp", + "uart3_52_53_grp", "uart3_73_74_grp", "uart3_94_95_grp", + "uart3_98_99_grp", "uart4_6_7_grp", "uart4_13_14_grp", + "uart4_39_40_grp", "uart4_71_72_grp", "uart4_92_93_grp", + "uart4_100_101_grp", "uart5_4_5_grp", "uart5_37_38_grp", + "uart5_69_70_grp", "uart5_90_91_grp", "uart6_2_3_grp", + "uart6_88_89_grp", "rs485_grp", "touchscreen_grp", "can0_grp", + "can1_grp", "pwm0_1_pin_8_9_grp", "pwm0_1_pin_14_15_grp", + "pwm0_1_pin_30_31_grp", "pwm0_1_pin_37_38_grp", "pwm0_1_pin_42_43_grp", + "pwm0_1_pin_59_60_grp", "pwm0_1_pin_88_89_grp", "pwm2_pin_7_grp", + "pwm2_pin_13_grp", "pwm2_pin_29_grp", "pwm2_pin_34_grp", + "pwm2_pin_41_grp", "pwm2_pin_58_grp", "pwm2_pin_87_grp", + "pwm3_pin_6_grp", "pwm3_pin_12_grp", "pwm3_pin_28_grp", + "pwm3_pin_40_grp", "pwm3_pin_57_grp", "pwm3_pin_86_grp", + "ssp1_17_20_grp", "ssp1_36_39_grp", "ssp1_48_51_grp", "ssp1_65_68_grp", + "ssp1_94_97_grp", "ssp2_13_16_grp", "ssp2_32_35_grp", "ssp2_44_47_grp", + "ssp2_61_64_grp", "ssp2_90_93_grp", "mii2_grp", "smii0_1_grp", + "rmii0_1_grp", "i2c1_8_9_grp", "i2c1_98_99_grp", "i2c2_0_1_grp", + "i2c2_2_3_grp", "i2c2_19_20_grp", "i2c2_75_76_grp", "i2c2_96_97_grp" + +Valid values for function names are: +For All SPEAr3xx machines: + "firda", "i2c0", "ssp_cs", "ssp0", "mii0", "gpio0", "uart0_ext", + "uart0", "timer_0_1", "timer_2_3" + +For SPEAr300 machines: + "fsmc", "clcd", "tdm", "i2c1", "cam", "dac", "i2s", "sdhci", "gpio1" + +For SPEAr310 machines: + "emi", "uart1", "uart2", "uart3", "uart4", "uart5", "fsmc", "rs485_0", + "rs485_1", "tdm" + +For SPEAr320 machines: + "clcd", "emi", "fsmc", "spp", "sdhci", "i2s", "uart1", "uart1_modem", + "uart2", "uart3", "uart4", "uart5", "uart6", "rs485", "touchscreen", + "can0", "can1", "pwm0_1", "pwm2", "pwm3", "ssp1", "ssp2", "mii2", + "mii0_1", "i2c1", "i2c2" diff --git a/trunk/Documentation/devicetree/bindings/pinmux/pinmux_nvidia.txt b/trunk/Documentation/devicetree/bindings/pinmux/pinmux_nvidia.txt deleted file mode 100644 index 36f82dbdd14d..000000000000 --- a/trunk/Documentation/devicetree/bindings/pinmux/pinmux_nvidia.txt +++ /dev/null @@ -1,5 +0,0 @@ -NVIDIA Tegra 2 pinmux controller - -Required properties: -- compatible : "nvidia,tegra20-pinmux" - diff --git a/trunk/Documentation/devicetree/bindings/regulator/fixed-regulator.txt b/trunk/Documentation/devicetree/bindings/regulator/fixed-regulator.txt index 9cf57fd042d2..2f5b6b1ba15f 100644 --- a/trunk/Documentation/devicetree/bindings/regulator/fixed-regulator.txt +++ b/trunk/Documentation/devicetree/bindings/regulator/fixed-regulator.txt @@ -8,6 +8,8 @@ Optional properties: - startup-delay-us: startup time in microseconds - enable-active-high: Polarity of GPIO is Active high If this property is missing, the default assumed is Active low. +- gpio-open-drain: GPIO is open drain type. + If this property is missing then default assumption is false. Any property defined as part of the core regulator binding, defined in regulator.txt, can also be used. @@ -25,5 +27,6 @@ Example: gpio = <&gpio1 16 0>; startup-delay-us = <70000>; enable-active-high; - regulator-boot-on + regulator-boot-on; + gpio-open-drain; }; diff --git a/trunk/Documentation/devicetree/bindings/regulator/tps62360-regulator.txt b/trunk/Documentation/devicetree/bindings/regulator/tps62360-regulator.txt new file mode 100644 index 000000000000..c8ca6b8f6582 --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/regulator/tps62360-regulator.txt @@ -0,0 +1,44 @@ +TPS62360 Voltage regulators + +Required properties: +- compatible: Must be one of the following. + "ti,tps62360" + "ti,tps62361", + "ti,tps62362", + "ti,tps62363", +- reg: I2C slave address + +Optional properties: +- ti,enable-vout-discharge: Enable output discharge. This is boolean value. +- ti,enable-pull-down: Enable pull down. This is boolean value. +- ti,vsel0-gpio: GPIO for controlling VSEL0 line. + If this property is missing, then assume that there is no GPIO + for vsel0 control. +- ti,vsel1-gpio: Gpio for controlling VSEL1 line. + If this property is missing, then assume that there is no GPIO + for vsel1 control. +- ti,vsel0-state-high: Inital state of vsel0 input is high. + If this property is missing, then assume the state as low (0). +- ti,vsel1-state-high: Inital state of vsel1 input is high. + If this property is missing, then assume the state as low (0). + +Any property defined as part of the core regulator binding, defined in +regulator.txt, can also be used. + +Example: + + abc: tps62360 { + compatible = "ti,tps62361"; + reg = <0x60>; + regulator-name = "tps62361-vout"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on + ti,vsel0-gpio = <&gpio1 16 0>; + ti,vsel1-gpio = <&gpio1 17 0>; + ti,vsel0-state-high; + ti,vsel1-state-high; + ti,enable-pull-down; + ti,enable-force-pwm; + ti,enable-vout-discharge; + }; diff --git a/trunk/Documentation/devicetree/bindings/regulator/tps6586x.txt b/trunk/Documentation/devicetree/bindings/regulator/tps6586x.txt new file mode 100644 index 000000000000..0fcabaa3baa3 --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/regulator/tps6586x.txt @@ -0,0 +1,97 @@ +TPS6586x family of regulators + +Required properties: +- compatible: "ti,tps6586x" +- reg: I2C slave address +- interrupts: the interrupt outputs of the controller +- #gpio-cells: number of cells to describe a GPIO +- gpio-controller: mark the device as a GPIO controller +- regulators: list of regulators provided by this controller, must be named + after their hardware counterparts: sm[0-2], ldo[0-9] and ldo_rtc + +Each regulator is defined using the standard binding for regulators. + +Example: + + pmu: tps6586x@34 { + compatible = "ti,tps6586x"; + reg = <0x34>; + interrupts = <0 88 0x4>; + + #gpio-cells = <2>; + gpio-controller; + + regulators { + sm0_reg: sm0 { + regulator-min-microvolt = < 725000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + + sm1_reg: sm1 { + regulator-min-microvolt = < 725000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + + sm2_reg: sm2 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <4550000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo0_reg: ldo0 { + regulator-name = "PCIE CLK"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + ldo1_reg: ldo1 { + regulator-min-microvolt = < 725000>; + regulator-max-microvolt = <1500000>; + }; + + ldo2_reg: ldo2 { + regulator-min-microvolt = < 725000>; + regulator-max-microvolt = <1500000>; + }; + + ldo3_reg: ldo3 { + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <3300000>; + }; + + ldo4_reg: ldo4 { + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <2475000>; + }; + + ldo5_reg: ldo5 { + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <3300000>; + }; + + ldo6_reg: ldo6 { + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <3300000>; + }; + + ldo7_reg: ldo7 { + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <3300000>; + }; + + ldo8_reg: ldo8 { + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <3300000>; + }; + + ldo9_reg: ldo9 { + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <3300000>; + }; + }; + }; diff --git a/trunk/Documentation/devicetree/bindings/staging/iio/adc/lpc32xx-adc.txt b/trunk/Documentation/devicetree/bindings/staging/iio/adc/lpc32xx-adc.txt new file mode 100644 index 000000000000..b3629d3a9adf --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/staging/iio/adc/lpc32xx-adc.txt @@ -0,0 +1,16 @@ +* NXP LPC32xx SoC ADC controller + +Required properties: +- compatible: must be "nxp,lpc3220-adc" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: The ADC interrupt + +Example: + + adc@40048000 { + compatible = "nxp,lpc3220-adc"; + reg = <0x40048000 0x1000>; + interrupt-parent = <&mic>; + interrupts = <39 0>; + }; diff --git a/trunk/Documentation/devicetree/bindings/staging/iio/adc/spear-adc.txt b/trunk/Documentation/devicetree/bindings/staging/iio/adc/spear-adc.txt new file mode 100644 index 000000000000..02ea23a63f20 --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/staging/iio/adc/spear-adc.txt @@ -0,0 +1,26 @@ +* ST SPEAr ADC device driver + +Required properties: +- compatible: Should be "st,spear600-adc" +- reg: Address and length of the register set for the device +- interrupt-parent: Should be the phandle for the interrupt controller + that services interrupts for this device +- interrupts: Should contain the ADC interrupt +- sampling-frequency: Default sampling frequency + +Optional properties: +- vref-external: External voltage reference in milli-volts. If omitted + the internal voltage reference will be used. +- average-samples: Number of samples to generate an average value. If + omitted, single data conversion will be used. + +Examples: + + adc: adc@d8200000 { + compatible = "st,spear600-adc"; + reg = <0xd8200000 0x1000>; + interrupt-parent = <&vic1>; + interrupts = <6>; + sampling-frequency = <5000000>; + vref-external = <2500>; /* 2.5V VRef */ + }; diff --git a/trunk/Documentation/devicetree/bindings/usb/isp1301.txt b/trunk/Documentation/devicetree/bindings/usb/isp1301.txt new file mode 100644 index 000000000000..5405d99d9aaa --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/usb/isp1301.txt @@ -0,0 +1,25 @@ +* NXP ISP1301 USB transceiver + +Required properties: +- compatible: must be "nxp,isp1301" +- reg: I2C address of the ISP1301 device + +Optional properties of devices using ISP1301: +- transceiver: phandle of isp1301 - this helps the ISP1301 driver to find the + ISP1301 instance associated with the respective USB driver + +Example: + + isp1301: usb-transceiver@2c { + compatible = "nxp,isp1301"; + reg = <0x2c>; + }; + + usbd@31020000 { + compatible = "nxp,lpc3220-udc"; + reg = <0x31020000 0x300>; + interrupt-parent = <&mic>; + interrupts = <0x3d 0>, <0x3e 0>, <0x3c 0>, <0x3a 0>; + transceiver = <&isp1301>; + status = "okay"; + }; diff --git a/trunk/Documentation/devicetree/bindings/usb/lpc32xx-udc.txt b/trunk/Documentation/devicetree/bindings/usb/lpc32xx-udc.txt new file mode 100644 index 000000000000..29f12a533f66 --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/usb/lpc32xx-udc.txt @@ -0,0 +1,28 @@ +* NXP LPC32xx SoC USB Device Controller (UDC) + +Required properties: +- compatible: Must be "nxp,lpc3220-udc" +- reg: Physical base address of the controller and length of memory mapped + region. +- interrupts: The USB interrupts: + * USB Device Low Priority Interrupt + * USB Device High Priority Interrupt + * USB Device DMA Interrupt + * External USB Transceiver Interrupt (OTG ATX) +- transceiver: phandle of the associated ISP1301 device - this is necessary for + the UDC controller for connecting to the USB physical layer + +Example: + + isp1301: usb-transceiver@2c { + compatible = "nxp,isp1301"; + reg = <0x2c>; + }; + + usbd@31020000 { + compatible = "nxp,lpc3220-udc"; + reg = <0x31020000 0x300>; + interrupt-parent = <&mic>; + interrupts = <0x3d 0>, <0x3e 0>, <0x3c 0>, <0x3a 0>; + transceiver = <&isp1301>; + }; diff --git a/trunk/Documentation/devicetree/bindings/usb/ohci-nxp.txt b/trunk/Documentation/devicetree/bindings/usb/ohci-nxp.txt new file mode 100644 index 000000000000..71e28c1017ed --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/usb/ohci-nxp.txt @@ -0,0 +1,24 @@ +* OHCI controller, NXP ohci-nxp variant + +Required properties: +- compatible: must be "nxp,ohci-nxp" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: The OHCI interrupt +- transceiver: phandle of the associated ISP1301 device - this is necessary for + the UDC controller for connecting to the USB physical layer + +Example (LPC32xx): + + isp1301: usb-transceiver@2c { + compatible = "nxp,isp1301"; + reg = <0x2c>; + }; + + ohci@31020000 { + compatible = "nxp,ohci-nxp"; + reg = <0x31020000 0x300>; + interrupt-parent = <&mic>; + interrupts = <0x3b 0>; + transceiver = <&isp1301>; + }; diff --git a/trunk/Documentation/devicetree/bindings/usb/spear-usb.txt b/trunk/Documentation/devicetree/bindings/usb/spear-usb.txt new file mode 100644 index 000000000000..f8a464a25653 --- /dev/null +++ b/trunk/Documentation/devicetree/bindings/usb/spear-usb.txt @@ -0,0 +1,39 @@ +ST SPEAr SoC USB controllers: +----------------------------- + +EHCI: +----- + +Required properties: +- compatible: "st,spear600-ehci" +- interrupt-parent: Should be the phandle for the interrupt controller + that services interrupts for this device +- interrupts: Should contain the EHCI interrupt + +Example: + + ehci@e1800000 { + compatible = "st,spear600-ehci", "usb-ehci"; + reg = <0xe1800000 0x1000>; + interrupt-parent = <&vic1>; + interrupts = <27>; + }; + + +OHCI: +----- + +Required properties: +- compatible: "st,spear600-ohci" +- interrupt-parent: Should be the phandle for the interrupt controller + that services interrupts for this device +- interrupts: Should contain the OHCI interrupt + +Example: + + ohci@e1900000 { + compatible = "st,spear600-ohci", "usb-ohci"; + reg = <0xe1800000 0x1000>; + interrupt-parent = <&vic1>; + interrupts = <26>; + }; diff --git a/trunk/Documentation/devicetree/bindings/vendor-prefixes.txt b/trunk/Documentation/devicetree/bindings/vendor-prefixes.txt index 82ac057a24a9..107d8addf0e4 100644 --- a/trunk/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/trunk/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -8,6 +8,7 @@ amcc Applied Micro Circuits Corporation (APM, formally AMCC) apm Applied Micro Circuits Corporation (APM) arm ARM Ltd. atmel Atmel Corporation +bosch Bosch Sensortec GmbH cavium Cavium, Inc. chrp Common Hardware Reference Platform cortina Cortina Systems, Inc. diff --git a/trunk/Documentation/driver-model/devres.txt b/trunk/Documentation/driver-model/devres.txt index 2a596a4fc23e..950856bd2e39 100644 --- a/trunk/Documentation/driver-model/devres.txt +++ b/trunk/Documentation/driver-model/devres.txt @@ -276,3 +276,11 @@ REGULATOR devm_regulator_get() devm_regulator_put() devm_regulator_bulk_get() + +CLOCK + devm_clk_get() + devm_clk_put() + +PINCTRL + devm_pinctrl_get() + devm_pinctrl_put() diff --git a/trunk/Documentation/dvb/opera-firmware.txt b/trunk/Documentation/dvb/opera-firmware.txt index 93e784c2607b..fb6683188ef7 100644 --- a/trunk/Documentation/dvb/opera-firmware.txt +++ b/trunk/Documentation/dvb/opera-firmware.txt @@ -8,7 +8,7 @@ from the windriver disk into this directory. Then run -./get_dvb_firware opera1 +./get_dvb_firmware opera1 and after that you have 2 files: @@ -24,4 +24,4 @@ After that the driver can load the firmware in kernel config and have hotplug running). -Marco Gittler \ No newline at end of file +Marco Gittler diff --git a/trunk/Documentation/dynamic-debug-howto.txt b/trunk/Documentation/dynamic-debug-howto.txt index 74e6c7782678..6e1684981da2 100644 --- a/trunk/Documentation/dynamic-debug-howto.txt +++ b/trunk/Documentation/dynamic-debug-howto.txt @@ -2,17 +2,17 @@ Introduction ============ -This document describes how to use the dynamic debug (ddebug) feature. +This document describes how to use the dynamic debug (dyndbg) feature. -Dynamic debug is designed to allow you to dynamically enable/disable kernel -code to obtain additional kernel information. Currently, if -CONFIG_DYNAMIC_DEBUG is set, then all pr_debug()/dev_dbg() calls can be -dynamically enabled per-callsite. +Dynamic debug is designed to allow you to dynamically enable/disable +kernel code to obtain additional kernel information. Currently, if +CONFIG_DYNAMIC_DEBUG is set, then all pr_debug()/dev_dbg() calls can +be dynamically enabled per-callsite. Dynamic debug has even more useful features: - * Simple query language allows turning on and off debugging statements by - matching any combination of 0 or 1 of: + * Simple query language allows turning on and off debugging + statements by matching any combination of 0 or 1 of: - source filename - function name @@ -20,17 +20,19 @@ Dynamic debug has even more useful features: - module name - format string - * Provides a debugfs control file: /dynamic_debug/control which can be - read to display the complete list of known debug statements, to help guide you + * Provides a debugfs control file: /dynamic_debug/control + which can be read to display the complete list of known debug + statements, to help guide you Controlling dynamic debug Behaviour =================================== The behaviour of pr_debug()/dev_dbg()s are controlled via writing to a -control file in the 'debugfs' filesystem. Thus, you must first mount the debugfs -filesystem, in order to make use of this feature. Subsequently, we refer to the -control file as: /dynamic_debug/control. For example, if you want to -enable printing from source file 'svcsock.c', line 1603 you simply do: +control file in the 'debugfs' filesystem. Thus, you must first mount +the debugfs filesystem, in order to make use of this feature. +Subsequently, we refer to the control file as: +/dynamic_debug/control. For example, if you want to enable +printing from source file 'svcsock.c', line 1603 you simply do: nullarbor:~ # echo 'file svcsock.c line 1603 +p' > /dynamic_debug/control @@ -44,15 +46,15 @@ nullarbor:~ # echo 'file svcsock.c wtf 1 +p' > Viewing Dynamic Debug Behaviour =========================== -You can view the currently configured behaviour of all the debug statements -via: +You can view the currently configured behaviour of all the debug +statements via: nullarbor:~ # cat /dynamic_debug/control # filename:lineno [module]function flags format -/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:323 [svcxprt_rdma]svc_rdma_cleanup - "SVCRDMA Module Removed, deregister RPC RDMA transport\012" -/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:341 [svcxprt_rdma]svc_rdma_init - "\011max_inline : %d\012" -/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:340 [svcxprt_rdma]svc_rdma_init - "\011sq_depth : %d\012" -/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:338 [svcxprt_rdma]svc_rdma_init - "\011max_requests : %d\012" +/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:323 [svcxprt_rdma]svc_rdma_cleanup =_ "SVCRDMA Module Removed, deregister RPC RDMA transport\012" +/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:341 [svcxprt_rdma]svc_rdma_init =_ "\011max_inline : %d\012" +/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:340 [svcxprt_rdma]svc_rdma_init =_ "\011sq_depth : %d\012" +/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:338 [svcxprt_rdma]svc_rdma_init =_ "\011max_requests : %d\012" ... @@ -65,12 +67,12 @@ nullarbor:~ # grep -i rdma /dynamic_debug/control | wc -l nullarbor:~ # grep -i tcp /dynamic_debug/control | wc -l 42 -Note in particular that the third column shows the enabled behaviour -flags for each debug statement callsite (see below for definitions of the -flags). The default value, no extra behaviour enabled, is "-". So -you can view all the debug statement callsites with any non-default flags: +The third column shows the currently enabled flags for each debug +statement callsite (see below for definitions of the flags). The +default value, with no flags enabled, is "=_". So you can view all +the debug statement callsites with any non-default flags: -nullarbor:~ # awk '$3 != "-"' /dynamic_debug/control +nullarbor:~ # awk '$3 != "=_"' /dynamic_debug/control # filename:lineno [module]function flags format /usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svcsock.c:1603 [sunrpc]svc_send p "svc_process: st_sendto returned %d\012" @@ -103,15 +105,14 @@ specifications, followed by a flags change specification. command ::= match-spec* flags-spec -The match-spec's are used to choose a subset of the known dprintk() +The match-spec's are used to choose a subset of the known pr_debug() callsites to which to apply the flags-spec. Think of them as a query with implicit ANDs between each pair. Note that an empty list of -match-specs is possible, but is not very useful because it will not -match any debug statement callsites. +match-specs will select all debug statement callsites. -A match specification comprises a keyword, which controls the attribute -of the callsite to be compared, and a value to compare against. Possible -keywords are: +A match specification comprises a keyword, which controls the +attribute of the callsite to be compared, and a value to compare +against. Possible keywords are: match-spec ::= 'func' string | 'file' string | @@ -164,15 +165,15 @@ format characters (") or single quote characters ('). Examples: - format svcrdma: // many of the NFS/RDMA server dprintks - format readahead // some dprintks in the readahead cache + format svcrdma: // many of the NFS/RDMA server pr_debugs + format readahead // some pr_debugs in the readahead cache format nfsd:\040SETATTR // one way to match a format with whitespace format "nfsd: SETATTR" // a neater way to match a format with whitespace format 'nfsd: SETATTR' // yet another way to match a format with whitespace line The given line number or range of line numbers is compared - against the line number of each dprintk() callsite. A single + against the line number of each pr_debug() callsite. A single line number matches the callsite line number exactly. A range of line numbers matches any callsite between the first and last line number inclusive. An empty first number means @@ -188,51 +189,93 @@ The flags specification comprises a change operation followed by one or more flag characters. The change operation is one of the characters: -- - remove the given flags - -+ - add the given flags - -= - set the flags to the given flags + - remove the given flags + + add the given flags + = set the flags to the given flags The flags are: -f - Include the function name in the printed message -l - Include line number in the printed message -m - Include module name in the printed message -p - Causes a printk() message to be emitted to dmesg -t - Include thread ID in messages not generated from interrupt context + p enables the pr_debug() callsite. + f Include the function name in the printed message + l Include line number in the printed message + m Include module name in the printed message + t Include thread ID in messages not generated from interrupt context + _ No flags are set. (Or'd with others on input) + +For display, the flags are preceded by '=' +(mnemonic: what the flags are currently equal to). -Note the regexp ^[-+=][flmpt]+$ matches a flags specification. -Note also that there is no convenient syntax to remove all -the flags at once, you need to use "-flmpt". +Note the regexp ^[-+=][flmpt_]+$ matches a flags specification. +To clear all flags at once, use "=_" or "-flmpt". -Debug messages during boot process +Debug messages during Boot Process ================================== -To be able to activate debug messages during the boot process, -even before userspace and debugfs exists, use the boot parameter: -ddebug_query="QUERY" +To activate debug messages for core code and built-in modules during +the boot process, even before userspace and debugfs exists, use +dyndbg="QUERY", module.dyndbg="QUERY", or ddebug_query="QUERY" +(ddebug_query is obsoleted by dyndbg, and deprecated). QUERY follows +the syntax described above, but must not exceed 1023 characters. Your +bootloader may impose lower limits. + +These dyndbg params are processed just after the ddebug tables are +processed, as part of the arch_initcall. Thus you can enable debug +messages in all code run after this arch_initcall via this boot +parameter. -QUERY follows the syntax described above, but must not exceed 1023 -characters. The enablement of debug messages is done as an arch_initcall. -Thus you can enable debug messages in all code processed after this -arch_initcall via this boot parameter. On an x86 system for example ACPI enablement is a subsys_initcall and -ddebug_query="file ec.c +p" + dyndbg="file ec.c +p" will show early Embedded Controller transactions during ACPI setup if your machine (typically a laptop) has an Embedded Controller. PCI (or other devices) initialization also is a hot candidate for using this boot parameter for debugging purposes. +If foo module is not built-in, foo.dyndbg will still be processed at +boot time, without effect, but will be reprocessed when module is +loaded later. dyndbg_query= and bare dyndbg= are only processed at +boot. + + +Debug Messages at Module Initialization Time +============================================ + +When "modprobe foo" is called, modprobe scans /proc/cmdline for +foo.params, strips "foo.", and passes them to the kernel along with +params given in modprobe args or /etc/modprob.d/*.conf files, +in the following order: + +1. # parameters given via /etc/modprobe.d/*.conf + options foo dyndbg=+pt + options foo dyndbg # defaults to +p + +2. # foo.dyndbg as given in boot args, "foo." is stripped and passed + foo.dyndbg=" func bar +p; func buz +mp" + +3. # args to modprobe + modprobe foo dyndbg==pmf # override previous settings + +These dyndbg queries are applied in order, with last having final say. +This allows boot args to override or modify those from /etc/modprobe.d +(sensible, since 1 is system wide, 2 is kernel or boot specific), and +modprobe args to override both. + +In the foo.dyndbg="QUERY" form, the query must exclude "module foo". +"foo" is extracted from the param-name, and applied to each query in +"QUERY", and only 1 match-spec of each type is allowed. + +The dyndbg option is a "fake" module parameter, which means: + +- modules do not need to define it explicitly +- every module gets it tacitly, whether they use pr_debug or not +- it doesnt appear in /sys/module/$module/parameters/ + To see it, grep the control file, or inspect /proc/cmdline. + +For CONFIG_DYNAMIC_DEBUG kernels, any settings given at boot-time (or +enabled by -DDEBUG flag during compilation) can be disabled later via +the sysfs interface if the debug messages are no longer needed: + + echo "module module_name -p" > /dynamic_debug/control Examples ======== @@ -260,3 +303,18 @@ nullarbor:~ # echo -n 'func svc_process -p' > // enable messages for NFS calls READ, READLINK, READDIR and READDIR+. nullarbor:~ # echo -n 'format "nfsd: READ" +p' > /dynamic_debug/control + +// enable all messages +nullarbor:~ # echo -n '+p' > /dynamic_debug/control + +// add module, function to all enabled messages +nullarbor:~ # echo -n '+mf' > /dynamic_debug/control + +// boot-args example, with newlines and comments for readability +Kernel command line: ... + // see whats going on in dyndbg=value processing + dynamic_debug.verbose=1 + // enable pr_debugs in 2 builtins, #cmt is stripped + dyndbg="module params +p #cmt ; module sys +p" + // enable pr_debugs in 2 functions in a module loaded later + pc87360.dyndbg="func pc87360_init_device +p; func pc87360_find +p" diff --git a/trunk/Documentation/edac.txt b/trunk/Documentation/edac.txt index fdcc49fad8e1..03df2b020332 100644 --- a/trunk/Documentation/edac.txt +++ b/trunk/Documentation/edac.txt @@ -734,7 +734,7 @@ were done at i7core_edac driver. This chapter will cover those differences associated with a physical CPU socket. Each MC have 3 physical read channels, 3 physical write channels and - 3 logic channels. The driver currenty sees it as just 3 channels. + 3 logic channels. The driver currently sees it as just 3 channels. Each channel can have up to 3 DIMMs. The minimum known unity is DIMMs. There are no information about csrows. diff --git a/trunk/Documentation/extcon/porting-android-switch-class b/trunk/Documentation/extcon/porting-android-switch-class new file mode 100644 index 000000000000..eb0fa5f4fe88 --- /dev/null +++ b/trunk/Documentation/extcon/porting-android-switch-class @@ -0,0 +1,124 @@ + + Staging/Android Switch Class Porting Guide + (linux/drivers/staging/android/switch) + (c) Copyright 2012 Samsung Electronics + +AUTHORS +MyungJoo Ham + +/***************************************************************** + * CHAPTER 1. * + * PORTING SWITCH CLASS DEVICE DRIVERS * + *****************************************************************/ + +****** STEP 1. Basic Functionality + No extcon extended feature, but switch features only. + +- struct switch_dev (fed to switch_dev_register/unregister) + @name: no change + @dev: no change + @index: drop (not used in switch device driver side anyway) + @state: no change + If you have used @state with magic numbers, keep it + at this step. + @print_name: no change but type change (switch_dev->extcon_dev) + @print_state: no change but type change (switch_dev->extcon_dev) + +- switch_dev_register(sdev, dev) + => extcon_dev_register(edev, dev) + : no change but type change (sdev->edev) +- switch_dev_unregister(sdev) + => extcon_dev_unregister(edev) + : no change but type change (sdev->edev) +- switch_get_state(sdev) + => extcon_get_state(edev) + : no change but type change (sdev->edev) and (return: int->u32) +- switch_set_state(sdev, state) + => extcon_set_state(edev, state) + : no change but type change (sdev->edev) and (state: int->u32) + +With this changes, the ex-switch extcon class device works as it once +worked as switch class device. However, it will now have additional +interfaces (both ABI and in-kernel API) and different ABI locations. +However, if CONFIG_ANDROID is enabled without CONFIG_ANDROID_SWITCH, +/sys/class/switch/* will be symbolically linked to /sys/class/extcon/ +so that they are still compatible with legacy userspace processes. + +****** STEP 2. Multistate (no more magic numbers in state value) + Extcon's extended features for switch device drivers with + complex features usually required magic numbers in state + value of switch_dev. With extcon, such magic numbers that + support multiple cables ( + + 1. Define cable names at edev->supported_cable. + 2. (Recommended) remove print_state callback. + 3. Use extcon_get_cable_state_(edev, index) or + extcon_get_cable_state(edev, cable_name) instead of + extcon_get_state(edev) if you intend to get a state of a specific + cable. Same for set_state. This way, you can remove the usage of + magic numbers in state value. + 4. Use extcon_update_state() if you are updating specific bits of + the state value. + +Example: a switch device driver w/ magic numbers for two cables. + "0x00": no cables connected. + "0x01": cable 1 connected + "0x02": cable 2 connected + "0x03": cable 1 and 2 connected + 1. edev->supported_cable = {"1", "2", NULL}; + 2. edev->print_state = NULL; + 3. extcon_get_cable_state_(edev, 0) shows cable 1's state. + extcon_get_cable_state(edev, "1") shows cable 1's state. + extcon_set_cable_state_(edev, 1) sets cable 2's state. + extcon_set_cable_state(edev, "2") sets cable 2's state + 4. extcon_update_state(edev, 0x01, 0) sets the least bit's 0. + +****** STEP 3. Notify other device drivers + + You can notify others of the cable attach/detach events with +notifier chains. + + At the side of other device drivers (the extcon device itself +does not need to get notified of its own events), there are two +methods to register notifier_block for cable events: +(a) for a specific cable or (b) for every cable. + + (a) extcon_register_interest(obj, extcon_name, cable_name, nb) + Example: want to get news of "MAX8997_MUIC"'s "USB" cable + + obj = kzalloc(sizeof(struct extcon_specific_cable_nb), + GFP_KERNEL); + nb->notifier_call = the_callback_to_handle_usb; + + extcon_register_intereset(obj, "MAX8997_MUIC", "USB", nb); + + (b) extcon_register_notifier(edev, nb) + Call nb for any changes in edev. + + Please note that in order to properly behave with method (a), +the extcon device driver should support multistate feature (STEP 2). + +****** STEP 4. Inter-cable relation (mutually exclusive) + + You can provide inter-cable mutually exclusiveness information +for an extcon device. When cables A and B are declared to be mutually +exclusive, the two cables cannot be in ATTACHED state simulteneously. + + +/***************************************************************** + * CHAPTER 2. * + * PORTING USERSPACE w/ SWITCH CLASS DEVICE SUPPORT * + *****************************************************************/ + +****** ABI Location + + If "CONFIG_ANDROID" is enabled and "CONFIG_ANDROID_SWITCH" is +disabled, /sys/class/switch/* are created as symbolic links to +/sys/class/extcon/*. Because CONFIG_ANDROID_SWITCH creates +/sys/class/switch directory, we disable symboling linking if +CONFIG_ANDROID_SWITCH is enabled. + + The two files of switch class, name and state, are provided with +extcon, too. When the multistate support (STEP 2 of CHAPTER 1.) is +not enabled or print_state callback is supplied, the output of +state ABI is same with switch class. diff --git a/trunk/Documentation/feature-removal-schedule.txt b/trunk/Documentation/feature-removal-schedule.txt index e4b57756b9f5..1e69a81e99d4 100644 --- a/trunk/Documentation/feature-removal-schedule.txt +++ b/trunk/Documentation/feature-removal-schedule.txt @@ -2,7 +2,14 @@ The following is a list of files and features that are going to be removed in the kernel source tree. Every entry should contain what exactly is going away, why it is happening, and who is going to be doing the work. When the feature is removed from the kernel, it should also -be removed from this file. +be removed from this file. The suggested deprecation period is 3 releases. + +--------------------------- + +What: ddebug_query="query" boot cmdline param +When: v3.8 +Why: obsoleted by dyndbg="query" and module.dyndbg="query" +Who: Jim Cromie , Jason Baron --------------------------- @@ -549,3 +556,14 @@ Why: The V4L2_CID_VCENTER, V4L2_CID_HCENTER controls have been deprecated There are newer controls (V4L2_CID_PAN*, V4L2_CID_TILT*) that provide similar functionality. Who: Sylwester Nawrocki + +---------------------------- + +What: cgroup option updates via remount +When: March 2013 +Why: Remount currently allows changing bound subsystems and + release_agent. Rebinding is hardly useful as it only works + when the hierarchy is empty and release_agent itself should be + replaced with conventional fsnotify. + +---------------------------- diff --git a/trunk/Documentation/filesystems/gfs2-glocks.txt b/trunk/Documentation/filesystems/gfs2-glocks.txt index 0494f78d87e4..fcc79957be63 100644 --- a/trunk/Documentation/filesystems/gfs2-glocks.txt +++ b/trunk/Documentation/filesystems/gfs2-glocks.txt @@ -61,7 +61,9 @@ go_unlock | Called on the final local unlock of a lock go_dump | Called to print content of object for debugfs file, or on | error to dump glock to the log. go_type | The type of the glock, LM_TYPE_..... -go_min_hold_time | The minimum hold time +go_callback | Called if the DLM sends a callback to drop this lock +go_flags | GLOF_ASPACE is set, if the glock has an address space + | associated with it The minimum hold time for each lock is the time after a remote lock grant for which we ignore remote demote requests. This is in order to @@ -89,6 +91,7 @@ go_demote_ok | Sometimes | Yes go_lock | Yes | No go_unlock | Yes | No go_dump | Sometimes | Yes +go_callback | Sometimes (N/A) | Yes N.B. Operations must not drop either the bit lock or the spinlock if its held on entry. go_dump and do_demote_ok must never block. @@ -111,4 +114,118 @@ itself (locking order as above), and the other, known as the iopen glock is used in conjunction with the i_nlink field in the inode to determine the lifetime of the inode in question. Locking of inodes is on a per-inode basis. Locking of rgrps is on a per rgrp basis. +In general we prefer to lock local locks prior to cluster locks. + + Glock Statistics + ------------------ + +The stats are divided into two sets: those relating to the +super block and those relating to an individual glock. The +super block stats are done on a per cpu basis in order to +try and reduce the overhead of gathering them. They are also +further divided by glock type. All timings are in nanoseconds. + +In the case of both the super block and glock statistics, +the same information is gathered in each case. The super +block timing statistics are used to provide default values for +the glock timing statistics, so that newly created glocks +should have, as far as possible, a sensible starting point. +The per-glock counters are initialised to zero when the +glock is created. The per-glock statistics are lost when +the glock is ejected from memory. + +The statistics are divided into three pairs of mean and +variance, plus two counters. The mean/variance pairs are +smoothed exponential estimates and the algorithm used is +one which will be very familiar to those used to calculation +of round trip times in network code. See "TCP/IP Illustrated, +Volume 1", W. Richard Stevens, sect 21.3, "Round-Trip Time Measurement", +p. 299 and onwards. Also, Volume 2, Sect. 25.10, p. 838 and onwards. +Unlike the TCP/IP Illustrated case, the mean and variance are +not scaled, but are in units of integer nanoseconds. + +The three pairs of mean/variance measure the following +things: + + 1. DLM lock time (non-blocking requests) + 2. DLM lock time (blocking requests) + 3. Inter-request time (again to the DLM) + +A non-blocking request is one which will complete right +away, whatever the state of the DLM lock in question. That +currently means any requests when (a) the current state of +the lock is exclusive, i.e. a lock demotion (b) the requested +state is either null or unlocked (again, a demotion) or (c) the +"try lock" flag is set. A blocking request covers all the other +lock requests. + +There are two counters. The first is there primarily to show +how many lock requests have been made, and thus how much data +has gone into the mean/variance calculations. The other counter +is counting queuing of holders at the top layer of the glock +code. Hopefully that number will be a lot larger than the number +of dlm lock requests issued. + +So why gather these statistics? There are several reasons +we'd like to get a better idea of these timings: + +1. To be able to better set the glock "min hold time" +2. To spot performance issues more easily +3. To improve the algorithm for selecting resource groups for +allocation (to base it on lock wait time, rather than blindly +using a "try lock") + +Due to the smoothing action of the updates, a step change in +some input quantity being sampled will only fully be taken +into account after 8 samples (or 4 for the variance) and this +needs to be carefully considered when interpreting the +results. + +Knowing both the time it takes a lock request to complete and +the average time between lock requests for a glock means we +can compute the total percentage of the time for which the +node is able to use a glock vs. time that the rest of the +cluster has its share. That will be very useful when setting +the lock min hold time. + +Great care has been taken to ensure that we +measure exactly the quantities that we want, as accurately +as possible. There are always inaccuracies in any +measuring system, but I hope this is as accurate as we +can reasonably make it. + +Per sb stats can be found here: +/sys/kernel/debug/gfs2//sbstats +Per glock stats can be found here: +/sys/kernel/debug/gfs2//glstats + +Assuming that debugfs is mounted on /sys/kernel/debug and also +that is replaced with the name of the gfs2 filesystem +in question. + +The abbreviations used in the output as are follows: + +srtt - Smoothed round trip time for non-blocking dlm requests +srttvar - Variance estimate for srtt +srttb - Smoothed round trip time for (potentially) blocking dlm requests +srttvarb - Variance estimate for srttb +sirt - Smoothed inter-request time (for dlm requests) +sirtvar - Variance estimate for sirt +dlm - Number of dlm requests made (dcnt in glstats file) +queue - Number of glock requests queued (qcnt in glstats file) + +The sbstats file contains a set of these stats for each glock type (so 8 lines +for each type) and for each cpu (one column per cpu). The glstats file contains +a set of these stats for each glock in a similar format to the glocks file, but +using the format mean/variance for each of the timing stats. + +The gfs2_glock_lock_time tracepoint prints out the current values of the stats +for the glock in question, along with some addition information on each dlm +reply that is received: + +status - The status of the dlm request +flags - The dlm request flags +tdiff - The time taken by this specific request +(remaining fields as per above list) + diff --git a/trunk/Documentation/filesystems/gfs2.txt b/trunk/Documentation/filesystems/gfs2.txt index 4cda926628aa..cc4f2306609e 100644 --- a/trunk/Documentation/filesystems/gfs2.txt +++ b/trunk/Documentation/filesystems/gfs2.txt @@ -1,7 +1,7 @@ Global File System ------------------ -http://sources.redhat.com/cluster/wiki/ +https://fedorahosted.org/cluster/wiki/HomePage GFS is a cluster file system. It allows a cluster of computers to simultaneously use a block device that is shared between them (with FC, @@ -30,7 +30,8 @@ needed, simply: If you are using Fedora, you need to install the gfs2-utils package and, for lock_dlm, you will also need to install the cman package -and write a cluster.conf as per the documentation. +and write a cluster.conf as per the documentation. For F17 and above +cman has been replaced by the dlm package. GFS2 is not on-disk compatible with previous versions of GFS, but it is pretty close. @@ -39,8 +40,6 @@ The following man pages can be found at the URL above: fsck.gfs2 to repair a filesystem gfs2_grow to expand a filesystem online gfs2_jadd to add journals to a filesystem online - gfs2_tool to manipulate, examine and tune a filesystem - gfs2_quota to examine and change quota values in a filesystem + tunegfs2 to manipulate, examine and tune a filesystem gfs2_convert to convert a gfs filesystem to gfs2 in-place - mount.gfs2 to help mount(8) mount a filesystem mkfs.gfs2 to make a filesystem diff --git a/trunk/Documentation/filesystems/nfs/pnfs.txt b/trunk/Documentation/filesystems/nfs/pnfs.txt index c7919c6e3bea..52ae07f5f578 100644 --- a/trunk/Documentation/filesystems/nfs/pnfs.txt +++ b/trunk/Documentation/filesystems/nfs/pnfs.txt @@ -93,7 +93,7 @@ The API to the login script is as follows: (allways exists) (More protocols can be defined in the future. The client does not interpret this string it is - passed unchanged as recieved from the Server) + passed unchanged as received from the Server) -o osdname of the requested target OSD (Might be empty) (A string which denotes the OSD name, there is a diff --git a/trunk/Documentation/filesystems/proc.txt b/trunk/Documentation/filesystems/proc.txt index b7413cb46dcb..ef088e55ab2e 100644 --- a/trunk/Documentation/filesystems/proc.txt +++ b/trunk/Documentation/filesystems/proc.txt @@ -996,7 +996,6 @@ Table 1-9: Network info in /proc/net snmp SNMP data sockstat Socket statistics tcp TCP sockets - tr_rif Token ring RIF routing table udp UDP sockets unix UNIX domain sockets wireless Wireless interface data (Wavelan etc) diff --git a/trunk/Documentation/filesystems/qnx6.txt b/trunk/Documentation/filesystems/qnx6.txt index 050223ea03c7..e59f2f09f56e 100644 --- a/trunk/Documentation/filesystems/qnx6.txt +++ b/trunk/Documentation/filesystems/qnx6.txt @@ -17,7 +17,7 @@ concepts of blocks, inodes and directories. On QNX it is possible to create little endian and big endian qnx6 filesystems. This feature makes it possible to create and use a different endianness fs for the target (QNX is used on quite a range of embedded systems) plattform -running on a different endianess. +running on a different endianness. The Linux driver handles endianness transparently. (LE and BE) Blocks @@ -26,7 +26,7 @@ Blocks The space in the device or file is split up into blocks. These are a fixed size of 512, 1024, 2048 or 4096, which is decided when the filesystem is created. -Blockpointers are 32bit, so the maximum space that can be adressed is +Blockpointers are 32bit, so the maximum space that can be addressed is 2^32 * 4096 bytes or 16TB The superblocks @@ -47,16 +47,16 @@ inactive superblock. Each superblock holds a set of root inodes for the different filesystem parts. (Inode, Bitmap and Longfilenames) Each of these root nodes holds information like total size of the stored -data and the adressing levels in that specific tree. -If the level value is 0, up to 16 direct blocks can be adressed by each +data and the addressing levels in that specific tree. +If the level value is 0, up to 16 direct blocks can be addressed by each node. -Level 1 adds an additional indirect adressing level where each indirect -adressing block holds up to blocksize / 4 bytes pointers to data blocks. -Level 2 adds an additional indirect adressig block level (so, already up -to 16 * 256 * 256 = 1048576 blocks that can be adressed by such a tree)a +Level 1 adds an additional indirect addressing level where each indirect +addressing block holds up to blocksize / 4 bytes pointers to data blocks. +Level 2 adds an additional indirect addressing block level (so, already up +to 16 * 256 * 256 = 1048576 blocks that can be addressed by such a tree). Unused block pointers are always set to ~0 - regardless of root node, -indirect adressing blocks or inodes. +indirect addressing blocks or inodes. Data leaves are always on the lowest level. So no data is stored on upper tree levels. @@ -64,7 +64,7 @@ The first Superblock is located at 0x2000. (0x2000 is the bootblock size) The Audi MMI 3G first superblock directly starts at byte 0. Second superblock position can either be calculated from the superblock information (total number of filesystem blocks) or by taking the highest -device address, zeroing the last 3 bytes and then substracting 0x1000 from +device address, zeroing the last 3 bytes and then subtracting 0x1000 from that address. 0x1000 is the size reserved for each superblock - regardless of the @@ -83,8 +83,8 @@ size, number of blocks used, access time, change time and modification time. Object mode field is POSIX format. (which makes things easier) There are also pointers to the first 16 blocks, if the object data can be -adressed with 16 direct blocks. -For more than 16 blocks an indirect adressing in form of another tree is +addressed with 16 direct blocks. +For more than 16 blocks an indirect addressing in form of another tree is used. (scheme is the same as the one used for the superblock root nodes) The filesize is stored 64bit. Inode counting starts with 1. (whilst long @@ -118,13 +118,13 @@ no block pointers and the directory file record pointing to the target file inode. Character and block special devices do not exist in QNX as those files -are handled by the QNX kernel/drivers and created in /dev independant of the +are handled by the QNX kernel/drivers and created in /dev independent of the underlaying filesystem. Long filenames -------------- -Long filenames are stored in a seperate adressing tree. The staring point +Long filenames are stored in a separate addressing tree. The staring point is the longfilename root node in the active superblock. Each data block (tree leaves) holds one long filename. That filename is limited to 510 bytes. The first two starting bytes are used as length field diff --git a/trunk/Documentation/hwmon/it87 b/trunk/Documentation/hwmon/it87 index 23b7def21ba8..fba745571684 100644 --- a/trunk/Documentation/hwmon/it87 +++ b/trunk/Documentation/hwmon/it87 @@ -63,7 +63,7 @@ Module Parameters Hardware Interfaces ------------------- -All the chips suported by this driver are LPC Super-I/O chips, accessed +All the chips supported by this driver are LPC Super-I/O chips, accessed through the LPC bus (ISA-like I/O ports). The IT8712F additionally has an SMBus interface to the hardware monitoring functions. This driver no longer supports this interface though, as it is slower and less reliable diff --git a/trunk/Documentation/hwmon/wm831x b/trunk/Documentation/hwmon/wm831x index 24f47d8f6a42..11446757c8c8 100644 --- a/trunk/Documentation/hwmon/wm831x +++ b/trunk/Documentation/hwmon/wm831x @@ -22,7 +22,7 @@ reporting of all the input values but does not provide any alarms. Voltage Monitoring ------------------ -Voltages are sampled by a 12 bit ADC. Voltages in milivolts are 1.465 +Voltages are sampled by a 12 bit ADC. Voltages in millivolts are 1.465 times the ADC value. Temperature Monitoring diff --git a/trunk/Documentation/ioctl/ioctl-number.txt b/trunk/Documentation/ioctl/ioctl-number.txt index e34b531dc316..915f28c470e9 100644 --- a/trunk/Documentation/ioctl/ioctl-number.txt +++ b/trunk/Documentation/ioctl/ioctl-number.txt @@ -120,6 +120,7 @@ Code Seq#(hex) Include File Comments 'G' 00-0F linux/gigaset_dev.h conflict! 'H' 00-7F linux/hiddev.h conflict! 'H' 00-0F linux/hidraw.h conflict! +'H' 01 linux/mei.h conflict! 'H' 00-0F sound/asound.h conflict! 'H' 20-40 sound/asound_fm.h conflict! 'H' 80-8F sound/sfnt_info.h conflict! diff --git a/trunk/Documentation/kernel-parameters.txt b/trunk/Documentation/kernel-parameters.txt index c1601e5a8b71..62aba89b04a2 100644 --- a/trunk/Documentation/kernel-parameters.txt +++ b/trunk/Documentation/kernel-parameters.txt @@ -110,6 +110,7 @@ parameter is applicable: USB USB support is enabled. USBHID USB Human Interface Device support is enabled. V4L Video For Linux support is enabled. + VMMIO Driver for memory mapped virtio devices is enabled. VGA The VGA console has been enabled. VT Virtual terminal support is enabled. WDT Watchdog support is enabled. @@ -610,7 +611,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ddebug_query= [KNL,DYNAMIC_DEBUG] Enable debug messages at early boot time. See Documentation/dynamic-debug-howto.txt for - details. + details. Deprecated, see dyndbg. debug [KNL] Enable kernel debugging (events log level). @@ -730,6 +731,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. dscc4.setup= [NET] + dyndbg[="val"] [KNL,DYNAMIC_DEBUG] + module.dyndbg[="val"] + Enable debug messages at boot time. See + Documentation/dynamic-debug-howto.txt for details. + earlycon= [KNL] Output early console device and options. uart[8250],io,[,options] uart[8250],mmio,[,options] @@ -2161,6 +2167,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. on: Turn realloc on realloc same as realloc=on noari do not use PCIe ARI. + pcie_scan_all Scan all possible PCIe devices. Otherwise we + only look for one device below a PCIe downstream + port. pcie_aspm= [PCIE] Forcibly enable or disable PCIe Active State Power Management. @@ -2330,18 +2339,100 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ramdisk_size= [RAM] Sizes of RAM disks in kilobytes See Documentation/blockdev/ramdisk.txt. - rcupdate.blimit= [KNL,BOOT] + rcutree.blimit= [KNL,BOOT] Set maximum number of finished RCU callbacks to process in one batch. - rcupdate.qhimark= [KNL,BOOT] + rcutree.qhimark= [KNL,BOOT] Set threshold of queued RCU callbacks over which batch limiting is disabled. - rcupdate.qlowmark= [KNL,BOOT] + rcutree.qlowmark= [KNL,BOOT] Set threshold of queued RCU callbacks below which batch limiting is re-enabled. + rcutree.rcu_cpu_stall_suppress= [KNL,BOOT] + Suppress RCU CPU stall warning messages. + + rcutree.rcu_cpu_stall_timeout= [KNL,BOOT] + Set timeout for RCU CPU stall warning messages. + + rcutorture.fqs_duration= [KNL,BOOT] + Set duration of force_quiescent_state bursts. + + rcutorture.fqs_holdoff= [KNL,BOOT] + Set holdoff time within force_quiescent_state bursts. + + rcutorture.fqs_stutter= [KNL,BOOT] + Set wait time between force_quiescent_state bursts. + + rcutorture.irqreader= [KNL,BOOT] + Test RCU readers from irq handlers. + + rcutorture.n_barrier_cbs= [KNL,BOOT] + Set callbacks/threads for rcu_barrier() testing. + + rcutorture.nfakewriters= [KNL,BOOT] + Set number of concurrent RCU writers. These just + stress RCU, they don't participate in the actual + test, hence the "fake". + + rcutorture.nreaders= [KNL,BOOT] + Set number of RCU readers. + + rcutorture.onoff_holdoff= [KNL,BOOT] + Set time (s) after boot for CPU-hotplug testing. + + rcutorture.onoff_interval= [KNL,BOOT] + Set time (s) between CPU-hotplug operations, or + zero to disable CPU-hotplug testing. + + rcutorture.shuffle_interval= [KNL,BOOT] + Set task-shuffle interval (s). Shuffling tasks + allows some CPUs to go into dyntick-idle mode + during the rcutorture test. + + rcutorture.shutdown_secs= [KNL,BOOT] + Set time (s) after boot system shutdown. This + is useful for hands-off automated testing. + + rcutorture.stall_cpu= [KNL,BOOT] + Duration of CPU stall (s) to test RCU CPU stall + warnings, zero to disable. + + rcutorture.stall_cpu_holdoff= [KNL,BOOT] + Time to wait (s) after boot before inducing stall. + + rcutorture.stat_interval= [KNL,BOOT] + Time (s) between statistics printk()s. + + rcutorture.stutter= [KNL,BOOT] + Time (s) to stutter testing, for example, specifying + five seconds causes the test to run for five seconds, + wait for five seconds, and so on. This tests RCU's + ability to transition abruptly to and from idle. + + rcutorture.test_boost= [KNL,BOOT] + Test RCU priority boosting? 0=no, 1=maybe, 2=yes. + "Maybe" means test if the RCU implementation + under test support RCU priority boosting. + + rcutorture.test_boost_duration= [KNL,BOOT] + Duration (s) of each individual boost test. + + rcutorture.test_boost_interval= [KNL,BOOT] + Interval (s) between each boost test. + + rcutorture.test_no_idle_hz= [KNL,BOOT] + Test RCU's dyntick-idle handling. See also the + rcutorture.shuffle_interval parameter. + + rcutorture.torture_type= [KNL,BOOT] + Specify the RCU implementation to test. + + rcutorture.verbose= [KNL,BOOT] + Enable additional printk() statements. + rdinit= [KNL] Format: Run specified binary instead of /init from the ramdisk, @@ -2847,6 +2938,22 @@ bytes respectively. Such letter suffixes can also be entirely omitted. video= [FB] Frame buffer configuration See Documentation/fb/modedb.txt. + virtio_mmio.device= + [VMMIO] Memory mapped virtio (platform) device. + + @:[:] + where: + := size (can use standard suffixes + like K, M and G) + := physical base address + := interrupt number (as passed to + request_irq()) + := (optional) platform device id + example: + virtio_mmio.device=1K@0x100b0000:48:7 + + Can be used multiple times for multiple devices. + vga= [BOOT,X86-32] Select a particular video mode See Documentation/x86/boot.txt and Documentation/svga.txt. diff --git a/trunk/Documentation/memory-devices/ti-emif.txt b/trunk/Documentation/memory-devices/ti-emif.txt new file mode 100644 index 000000000000..f4ad9a7d0f4b --- /dev/null +++ b/trunk/Documentation/memory-devices/ti-emif.txt @@ -0,0 +1,57 @@ +TI EMIF SDRAM Controller Driver: + +Author +======== +Aneesh V + +Location +============ +driver/memory/emif.c + +Supported SoCs: +=================== +TI OMAP44xx +TI OMAP54xx + +Menuconfig option: +========================== +Device Drivers + Memory devices + Texas Instruments EMIF driver + +Description +=========== +This driver is for the EMIF module available in Texas Instruments +SoCs. EMIF is an SDRAM controller that, based on its revision, +supports one or more of DDR2, DDR3, and LPDDR2 SDRAM protocols. +This driver takes care of only LPDDR2 memories presently. The +functions of the driver includes re-configuring AC timing +parameters and other settings during frequency, voltage and +temperature changes + +Platform Data (see include/linux/platform_data/emif_plat.h): +===================================================================== +DDR device details and other board dependent and SoC dependent +information can be passed through platform data (struct emif_platform_data) +- DDR device details: 'struct ddr_device_info' +- Device AC timings: 'struct lpddr2_timings' and 'struct lpddr2_min_tck' +- Custom configurations: customizable policy options through + 'struct emif_custom_configs' +- IP revision +- PHY type + +Interface to the external world: +================================ +EMIF driver registers notifiers for voltage and frequency changes +affecting EMIF and takes appropriate actions when these are invoked. +- freq_pre_notify_handling() +- freq_post_notify_handling() +- volt_notify_handling() + +Debugfs +======== +The driver creates two debugfs entries per device. +- regcache_dump : dump of register values calculated and saved for all + frequencies used so far. +- mr4 : last polled value of MR4 register in the LPDDR2 device. MR4 + indicates the current temperature level of the device. diff --git a/trunk/Documentation/memory-hotplug.txt b/trunk/Documentation/memory-hotplug.txt index 8f485d72cf25..6d0c2519cf47 100644 --- a/trunk/Documentation/memory-hotplug.txt +++ b/trunk/Documentation/memory-hotplug.txt @@ -341,7 +341,7 @@ Need more implementation yet.... -------------------------------- 8. Memory hotplug event notifier -------------------------------- -Memory hotplug has event notifer. There are 6 types of notification. +Memory hotplug has event notifier. There are 6 types of notification. MEMORY_GOING_ONLINE Generated before new memory becomes available in order to be able to diff --git a/trunk/Documentation/misc-devices/mei/.gitignore b/trunk/Documentation/misc-devices/mei/.gitignore new file mode 100644 index 000000000000..f356b81ca1ec --- /dev/null +++ b/trunk/Documentation/misc-devices/mei/.gitignore @@ -0,0 +1 @@ +mei-amt-version diff --git a/trunk/Documentation/misc-devices/mei/Makefile b/trunk/Documentation/misc-devices/mei/Makefile new file mode 100644 index 000000000000..00e8c3e836ff --- /dev/null +++ b/trunk/Documentation/misc-devices/mei/Makefile @@ -0,0 +1,8 @@ +# kbuild trick to avoid linker error. Can be omitted if a module is built. +obj- := dummy.o + +# List of programs to build +hostprogs-y := mei-amt-version +HOSTCFLAGS_mei-amt-version.o += -I$(objtree)/usr/include +# Tell kbuild to always build the programs +always := $(hostprogs-y) diff --git a/trunk/Documentation/misc-devices/mei/TODO b/trunk/Documentation/misc-devices/mei/TODO new file mode 100644 index 000000000000..6b3625d3058c --- /dev/null +++ b/trunk/Documentation/misc-devices/mei/TODO @@ -0,0 +1,2 @@ +TODO: + - Cleanup and split the timer function diff --git a/trunk/drivers/staging/mei/mei-amt-version.c b/trunk/Documentation/misc-devices/mei/mei-amt-version.c similarity index 99% rename from trunk/drivers/staging/mei/mei-amt-version.c rename to trunk/Documentation/misc-devices/mei/mei-amt-version.c index ac2a507be253..01804f216312 100644 --- a/trunk/drivers/staging/mei/mei-amt-version.c +++ b/trunk/Documentation/misc-devices/mei/mei-amt-version.c @@ -74,7 +74,7 @@ #include #include #include -#include "mei.h" +#include /***************************************************************************** * Intel Management Engine Interface diff --git a/trunk/drivers/staging/mei/mei.txt b/trunk/Documentation/misc-devices/mei/mei.txt similarity index 100% rename from trunk/drivers/staging/mei/mei.txt rename to trunk/Documentation/misc-devices/mei/mei.txt diff --git a/trunk/Documentation/networking/00-INDEX b/trunk/Documentation/networking/00-INDEX index 9ad9ddeb384c..2cc3c7733a2f 100644 --- a/trunk/Documentation/networking/00-INDEX +++ b/trunk/Documentation/networking/00-INDEX @@ -1,7 +1,5 @@ 00-INDEX - this file -3c359.txt - - information on the 3Com TokenLink Velocity XL (3c5359) driver. 3c505.txt - information on the 3Com EtherLink Plus (3c505) driver. 3c509.txt @@ -142,8 +140,6 @@ netif-msg.txt - Design of the network interface message level setting (NETIF_MSG_*). nfc.txt - The Linux Near Field Communication (NFS) subsystem. -olympic.txt - - IBM PCI Pit/Pit-Phy/Olympic Token Ring driver info. openvswitch.txt - Open vSwitch developer documentation. operstates.txt @@ -184,8 +180,6 @@ skfp.txt - SysKonnect FDDI (SK-5xxx, Compaq Netelligent) driver info. smc9.txt - the driver for SMC's 9000 series of Ethernet cards -smctr.txt - - SMC TokenCard TokenRing Linux driver info. spider-net.txt - README for the Spidernet Driver (as found in PS3 / Cell BE). stmmac.txt @@ -200,8 +194,6 @@ tcp-thin.txt - kernel tuning options for low rate 'thin' TCP streams. tlan.txt - ThunderLAN (Compaq Netelligent 10/100, Olicom OC-2xxx) driver info. -tms380tr.txt - - SysKonnect Token Ring ISA/PCI adapter driver info. tproxy.txt - Transparent proxy support user guide. tuntap.txt diff --git a/trunk/Documentation/networking/3c359.txt b/trunk/Documentation/networking/3c359.txt deleted file mode 100644 index dadfe8147ab8..000000000000 --- a/trunk/Documentation/networking/3c359.txt +++ /dev/null @@ -1,58 +0,0 @@ - -3COM PCI TOKEN LINK VELOCITY XL TOKEN RING CARDS README - -Release 0.9.0 - Release - Jul 17th 2000 Mike Phillips - - 1.2.0 - Final - Feb 17th 2002 Mike Phillips - Updated for submission to the 2.4.x kernel. - -Thanks: - Terry Murphy from 3Com for tech docs and support, - Adam D. Ligas for testing the driver. - -Note: - This driver will NOT work with the 3C339 Token Ring cards, you need -to use the tms380 driver instead. - -Options: - -The driver accepts three options: ringspeed, pkt_buf_sz and message_level. - -These options can be specified differently for each card found. - -ringspeed: Has one of three settings 0 (default), 4 or 16. 0 will -make the card autosense the ringspeed and join at the appropriate speed, -this will be the default option for most people. 4 or 16 allow you to -explicitly force the card to operate at a certain speed. The card will fail -if you try to insert it at the wrong speed. (Although some hubs will allow -this so be *very* careful). The main purpose for explicitly setting the ring -speed is for when the card is first on the ring. In autosense mode, if the card -cannot detect any active monitors on the ring it will open at the same speed as -its last opening. This can be hazardous if this speed does not match the speed -you want the ring to operate at. - -pkt_buf_sz: This is this initial receive buffer allocation size. This will -default to 4096 if no value is entered. You may increase performance of the -driver by setting this to a value larger than the network packet size, although -the driver now re-sizes buffers based on MTU settings as well. - -message_level: Controls level of messages created by the driver. Defaults to 0: -which only displays start-up and critical messages. Presently any non-zero -value will display all soft messages as well. NB This does not turn -debugging messages on, that must be done by modified the source code. - -Variable MTU size: - -The driver can handle a MTU size up to either 4500 or 18000 depending upon -ring speed. The driver also changes the size of the receive buffers as part -of the mtu re-sizing, so if you set mtu = 18000, you will need to be able -to allocate 16 * (sk_buff with 18000 buffer size) call it 18500 bytes per ring -position = 296,000 bytes of memory space, plus of course anything -necessary for the tx sk_buff's. Remember this is per card, so if you are -building routers, gateway's etc, you could start to use a lot of memory -real fast. - -2/17/02 Mike Phillips - diff --git a/trunk/Documentation/networking/3c509.txt b/trunk/Documentation/networking/3c509.txt index dcc9eaf59395..fbf722e15ac3 100644 --- a/trunk/Documentation/networking/3c509.txt +++ b/trunk/Documentation/networking/3c509.txt @@ -25,7 +25,6 @@ models: 3c509B (later revision of the ISA card; supports full-duplex) 3c589 (PCMCIA) 3c589B (later revision of the 3c589; supports full-duplex) - 3c529 (MCA) 3c579 (EISA) Large portions of this documentation were heavily borrowed from the guide diff --git a/trunk/Documentation/networking/batman-adv.txt b/trunk/Documentation/networking/batman-adv.txt index 221ad0cdf11f..75a592365af9 100644 --- a/trunk/Documentation/networking/batman-adv.txt +++ b/trunk/Documentation/networking/batman-adv.txt @@ -1,5 +1,3 @@ -[state: 21-08-2011] - BATMAN-ADV ---------- @@ -67,18 +65,19 @@ To deactivate an interface you have to write "none" into its All mesh wide settings can be found in batman's own interface folder: -# ls /sys/class/net/bat0/mesh/ -# aggregated_ogms fragmentation gw_sel_class vis_mode -# ap_isolation gw_bandwidth hop_penalty -# bonding gw_mode orig_interval +# ls /sys/class/net/bat0/mesh/ +# aggregated_ogms gw_bandwidth log_level +# ap_isolation gw_mode orig_interval +# bonding gw_sel_class routing_algo +# bridge_loop_avoidance hop_penalty vis_mode +# fragmentation There is a special folder for debugging information: # ls /sys/kernel/debug/batman_adv/bat0/ -# gateways socket transtable_global vis_data -# originators softif_neigh transtable_local - +# bla_claim_table log socket transtable_local +# gateways originators transtable_global vis_data Some of the files contain all sort of status information regard- ing the mesh network. For example, you can view the table of @@ -202,12 +201,13 @@ abled during run time. Following log_levels are defined: 1 - Enable messages related to routing / flooding / broadcasting 2 - Enable messages related to route added / changed / deleted 4 - Enable messages related to translation table operations -7 - Enable all messages +8 - Enable messages related to bridge loop avoidance +15 - enable all messages The debug output can be changed at runtime using the file /sys/class/net/bat0/mesh/log_level. e.g. -# echo 2 > /sys/class/net/bat0/mesh/log_level +# echo 6 > /sys/class/net/bat0/mesh/log_level will enable debug messages for when routes change. diff --git a/trunk/Documentation/networking/can.txt b/trunk/Documentation/networking/can.txt index 56ca3b75376e..ac295399f0d4 100644 --- a/trunk/Documentation/networking/can.txt +++ b/trunk/Documentation/networking/can.txt @@ -649,7 +649,7 @@ solution for a couple of reasons: The CAN device must be configured via netlink interface. The supported netlink message types are defined and briefly described in "include/linux/can/netlink.h". CAN link support for the program "ip" - of the IPROUTE2 utility suite is avaiable and it can be used as shown + of the IPROUTE2 utility suite is available and it can be used as shown below: - Setting CAN device properties: diff --git a/trunk/Documentation/networking/fore200e.txt b/trunk/Documentation/networking/fore200e.txt index f648eb265188..d52af53efdc5 100644 --- a/trunk/Documentation/networking/fore200e.txt +++ b/trunk/Documentation/networking/fore200e.txt @@ -11,12 +11,10 @@ i386, alpha (untested), powerpc, sparc and sparc64 archs. The intent is to enable the use of different models of FORE adapters at the same time, by hosts that have several bus interfaces (such as PCI+SBUS, -PCI+MCA or PCI+EISA). +or PCI+EISA). Only PCI and SBUS devices are currently supported by the driver, but support -for other bus interfaces such as EISA should not be too hard to add (this may -be more tricky for the MCA bus, though, as FORE made some MCA-specific -modifications to the adapter's AALI interface). +for other bus interfaces such as EISA should not be too hard to add. Firmware Copyright Notice diff --git a/trunk/Documentation/networking/ieee802154.txt b/trunk/Documentation/networking/ieee802154.txt index 1dc1c24a7547..703cf4370c79 100644 --- a/trunk/Documentation/networking/ieee802154.txt +++ b/trunk/Documentation/networking/ieee802154.txt @@ -4,15 +4,22 @@ Introduction ============ +The IEEE 802.15.4 working group focuses on standartization of bottom +two layers: Medium Accsess Control (MAC) and Physical (PHY). And there +are mainly two options available for upper layers: + - ZigBee - proprietary protocol from ZigBee Alliance + - 6LowPAN - IPv6 networking over low rate personal area networks The Linux-ZigBee project goal is to provide complete implementation -of IEEE 802.15.4 / ZigBee / 6LoWPAN protocols. IEEE 802.15.4 is a stack +of IEEE 802.15.4 and 6LoWPAN protocols. IEEE 802.15.4 is a stack of protocols for organizing Low-Rate Wireless Personal Area Networks. -Currently only IEEE 802.15.4 layer is implemented. We have chosen -to use plain Berkeley socket API, the generic Linux networking stack -to transfer IEEE 802.15.4 messages and a special protocol over genetlink -for configuration/management +The stack is composed of three main parts: + - IEEE 802.15.4 layer; We have chosen to use plain Berkeley socket API, + the generic Linux networking stack to transfer IEEE 802.15.4 messages + and a special protocol over genetlink for configuration/management + - MAC - provides access to shared channel and reliable data delivery + - PHY - represents device drivers Socket API @@ -29,15 +36,6 @@ or git tree at git://linux-zigbee.git.sourceforge.net/gitroot/linux-zigbee). One can use SOCK_RAW for passing raw data towards device xmit function. YMMV. -MLME - MAC Level Management -============================ - -Most of IEEE 802.15.4 MLME interfaces are directly mapped on netlink commands. -See the include/net/nl802154.h header. Our userspace tools package -(see above) provides CLI configuration utility for radio interfaces and simple -coordinator for IEEE 802.15.4 networks as an example users of MLME protocol. - - Kernel side ============= @@ -51,6 +49,15 @@ Like with WiFi, there are several types of devices implementing IEEE 802.15.4. Those types of devices require different approach to be hooked into Linux kernel. +MLME - MAC Level Management +============================ + +Most of IEEE 802.15.4 MLME interfaces are directly mapped on netlink commands. +See the include/net/nl802154.h header. Our userspace tools package +(see above) provides CLI configuration utility for radio interfaces and simple +coordinator for IEEE 802.15.4 networks as an example users of MLME protocol. + + HardMAC ======= @@ -73,11 +80,47 @@ We provide an example of simple HardMAC driver at drivers/ieee802154/fakehard.c SoftMAC ======= -We are going to provide intermediate layer implementing IEEE 802.15.4 MAC -in software. This is currently WIP. +The MAC is the middle layer in the IEEE 802.15.4 Linux stack. This moment it +provides interface for drivers registration and management of slave interfaces. + +NOTE: Currently the only monitor device type is supported - it's IEEE 802.15.4 +stack interface for network sniffers (e.g. WireShark). + +This layer is going to be extended soon. See header include/net/mac802154.h and several drivers in drivers/ieee802154/. + +Device drivers API +================== + +The include/net/mac802154.h defines following functions: + - struct ieee802154_dev *ieee802154_alloc_device + (size_t priv_size, struct ieee802154_ops *ops): + allocation of IEEE 802.15.4 compatible device + + - void ieee802154_free_device(struct ieee802154_dev *dev): + freeing allocated device + + - int ieee802154_register_device(struct ieee802154_dev *dev): + register PHY in the system + + - void ieee802154_unregister_device(struct ieee802154_dev *dev): + freeing registered PHY + +Moreover IEEE 802.15.4 device operations structure should be filled. + +Fake drivers +============ + +In addition there are two drivers available which simulate real devices with +HardMAC (fakehard) and SoftMAC (fakelb - IEEE 802.15.4 loopback driver) +interfaces. This option provides possibility to test and debug stack without +usage of real hardware. + +See sources in drivers/ieee802154 folder for more details. + + 6LoWPAN Linux implementation ============================ diff --git a/trunk/Documentation/networking/ip-sysctl.txt b/trunk/Documentation/networking/ip-sysctl.txt index 1619a8c80873..6f896b94abdc 100644 --- a/trunk/Documentation/networking/ip-sysctl.txt +++ b/trunk/Documentation/networking/ip-sysctl.txt @@ -190,6 +190,20 @@ tcp_cookie_size - INTEGER tcp_dsack - BOOLEAN Allows TCP to send "duplicate" SACKs. +tcp_early_retrans - INTEGER + Enable Early Retransmit (ER), per RFC 5827. ER lowers the threshold + for triggering fast retransmit when the amount of outstanding data is + small and when no previously unsent data can be transmitted (such + that limited transmit could be used). + Possible values: + 0 disables ER + 1 enables ER + 2 enables ER but delays fast recovery and fast retransmit + by a fourth of RTT. This mitigates connection falsely + recovers when network has a small degree of reordering + (less than 3 packets). + Default: 2 + tcp_ecn - INTEGER Enable Explicit Congestion Notification (ECN) in TCP. ECN is only used when both ends of the TCP flow support it. It is useful to @@ -1287,13 +1301,22 @@ bridge-nf-call-ip6tables - BOOLEAN bridge-nf-filter-vlan-tagged - BOOLEAN 1 : pass bridged vlan-tagged ARP/IP/IPv6 traffic to {arp,ip,ip6}tables. 0 : disable this. - Default: 1 + Default: 0 bridge-nf-filter-pppoe-tagged - BOOLEAN 1 : pass bridged pppoe-tagged IP/IPv6 traffic to {ip,ip6}tables. 0 : disable this. - Default: 1 + Default: 0 +bridge-nf-pass-vlan-input-dev - BOOLEAN + 1: if bridge-nf-filter-vlan-tagged is enabled, try to find a vlan + interface on the bridge and set the netfilter input device to the vlan. + This allows use of e.g. "iptables -i br0.1" and makes the REDIRECT + target work with vlan-on-top-of-bridge interfaces. When no matching + vlan interface is found, or this switch is off, the input device is + set to the bridge interface. + 0: disable bridge netfilter vlan interface lookup. + Default: 0 proc/sys/net/sctp/* Variables: @@ -1484,11 +1507,8 @@ addr_scope_policy - INTEGER /proc/sys/net/core/* -dev_weight - INTEGER - The maximum number of packets that kernel can handle on a NAPI - interrupt, it's a Per-CPU variable. + Please see: Documentation/sysctl/net.txt for descriptions of these entries. - Default: 64 /proc/sys/net/unix/* max_dgram_qlen - INTEGER diff --git a/trunk/Documentation/networking/mac80211-auth-assoc-deauth.txt b/trunk/Documentation/networking/mac80211-auth-assoc-deauth.txt index e0a2aa585ca3..d7a15fe91bf7 100644 --- a/trunk/Documentation/networking/mac80211-auth-assoc-deauth.txt +++ b/trunk/Documentation/networking/mac80211-auth-assoc-deauth.txt @@ -23,7 +23,7 @@ BA session stop & deauth/disassoc frames end note end -mac80211->driver: config(channel, non-HT) +mac80211->driver: config(channel, channel type) mac80211->driver: bss_info_changed(set BSSID, basic rate bitmap) mac80211->driver: sta_state(AP, exists) @@ -51,7 +51,7 @@ note over mac80211,driver: cleanup like for authenticate end alt not previously authenticated (FT) -mac80211->driver: config(channel, non-HT) +mac80211->driver: config(channel, channel type) mac80211->driver: bss_info_changed(set BSSID, basic rate bitmap) mac80211->driver: sta_state(AP, exists) mac80211->driver: sta_state(AP, authenticated) @@ -67,10 +67,6 @@ end mac80211->driver: set up QoS parameters -alt is HT channel -mac80211->driver: config(channel, HT params) -end - mac80211->driver: bss_info_changed(QoS, HT, associated with AID) mac80211->userspace: associated @@ -95,5 +91,5 @@ mac80211->driver: sta_state(AP,exists) mac80211->driver: sta_state(AP,not-exists) mac80211->driver: turn off powersave mac80211->driver: bss_info_changed(clear BSSID, not associated, no QoS, ...) -mac80211->driver: config(non-HT channel type) +mac80211->driver: config(channel type to non-HT) mac80211->userspace: disconnected diff --git a/trunk/Documentation/networking/olympic.txt b/trunk/Documentation/networking/olympic.txt deleted file mode 100644 index b95b5bf96751..000000000000 --- a/trunk/Documentation/networking/olympic.txt +++ /dev/null @@ -1,79 +0,0 @@ - -IBM PCI Pit/Pit-Phy/Olympic CHIPSET BASED TOKEN RING CARDS README - -Release 0.2.0 - Release - June 8th 1999 Peter De Schrijver & Mike Phillips -Release 0.9.C - Release - April 18th 2001 Mike Phillips - -Thanks: -Erik De Cock, Adrian Bridgett and Frank Fiene for their -patience and testing. -Donald Champion for the cardbus support -Kyle Lucke for the dma api changes. -Jonathon Bitner for hardware support. -Everybody on linux-tr for their continued support. - -Options: - -The driver accepts four options: ringspeed, pkt_buf_sz, -message_level and network_monitor. - -These options can be specified differently for each card found. - -ringspeed: Has one of three settings 0 (default), 4 or 16. 0 will -make the card autosense the ringspeed and join at the appropriate speed, -this will be the default option for most people. 4 or 16 allow you to -explicitly force the card to operate at a certain speed. The card will fail -if you try to insert it at the wrong speed. (Although some hubs will allow -this so be *very* careful). The main purpose for explicitly setting the ring -speed is for when the card is first on the ring. In autosense mode, if the card -cannot detect any active monitors on the ring it will not open, so you must -re-init the card at the appropriate speed. Unfortunately at present the only -way of doing this is rmmod and insmod which is a bit tough if it is compiled -in the kernel. - -pkt_buf_sz: This is this initial receive buffer allocation size. This will -default to 4096 if no value is entered. You may increase performance of the -driver by setting this to a value larger than the network packet size, although -the driver now re-sizes buffers based on MTU settings as well. - -message_level: Controls level of messages created by the driver. Defaults to 0: -which only displays start-up and critical messages. Presently any non-zero -value will display all soft messages as well. NB This does not turn -debugging messages on, that must be done by modified the source code. - -network_monitor: Any non-zero value will provide a quasi network monitoring -mode. All unexpected MAC frames (beaconing etc.) will be received -by the driver and the source and destination addresses printed. -Also an entry will be added in /proc/net called olympic_tr%d, where tr%d -is the registered device name, i.e tr0, tr1, etc. This displays low -level information about the configuration of the ring and the adapter. -This feature has been designed for network administrators to assist in -the diagnosis of network / ring problems. (This used to OLYMPIC_NETWORK_MONITOR, -but has now changed to allow each adapter to be configured differently and -to alleviate the necessity to re-compile olympic to turn the option on). - -Multi-card: - -The driver will detect multiple cards and will work with shared interrupts, -each card is assigned the next token ring device, i.e. tr0 , tr1, tr2. The -driver should also happily reside in the system with other drivers. It has -been tested with ibmtr.c running, and I personally have had one Olicom PCI -card and two IBM olympic cards (all on the same interrupt), all running -together. - -Variable MTU size: - -The driver can handle a MTU size up to either 4500 or 18000 depending upon -ring speed. The driver also changes the size of the receive buffers as part -of the mtu re-sizing, so if you set mtu = 18000, you will need to be able -to allocate 16 * (sk_buff with 18000 buffer size) call it 18500 bytes per ring -position = 296,000 bytes of memory space, plus of course anything -necessary for the tx sk_buff's. Remember this is per card, so if you are -building routers, gateway's etc, you could start to use a lot of memory -real fast. - - -6/8/99 Peter De Schrijver and Mike Phillips - diff --git a/trunk/Documentation/networking/smctr.txt b/trunk/Documentation/networking/smctr.txt deleted file mode 100644 index 9af25b810c1f..000000000000 --- a/trunk/Documentation/networking/smctr.txt +++ /dev/null @@ -1,66 +0,0 @@ -Text File for the SMC TokenCard TokenRing Linux driver (smctr.c). - By Jay Schulist - -The Linux SMC Token Ring driver works with the SMC TokenCard Elite (8115T) -ISA and SMC TokenCard Elite/A (8115T/A) MCA adapters. - -Latest information on this driver can be obtained on the Linux-SNA WWW site. -Please point your browser to: http://www.linux-sna.org - -This driver is rather simple to use. Select Y to Token Ring adapter support -in the kernel configuration. A choice for SMC Token Ring adapters will -appear. This drives supports all SMC ISA/MCA adapters. Choose this -option. I personally recommend compiling the driver as a module (M), but if you -you would like to compile it statically answer Y instead. - -This driver supports multiple adapters without the need to load multiple copies -of the driver. You should be able to load up to 7 adapters without any kernel -modifications, if you are in need of more please contact the maintainer of this -driver. - -Load the driver either by lilo/loadlin or as a module. When a module using the -following command will suffice for most: - -# modprobe smctr -smctr.c: v1.00 12/6/99 by jschlst@samba.org -tr0: SMC TokenCard 8115T at Io 0x300, Irq 10, Rom 0xd8000, Ram 0xcc000. - -Now just setup the device via ifconfig and set and routes you may have. After -this you are ready to start sending some tokens. - -Errata: -1). For anyone wondering where to pick up the SMC adapters please browse - to http://www.smc.com - -2). If you are the first/only Token Ring Client on a Token Ring LAN, please - specify the ringspeed with the ringspeed=[4/16] module option. If no - ringspeed is specified the driver will attempt to autodetect the ring - speed and/or if the adapter is the first/only station on the ring take - the appropriate actions. - - NOTE: Default ring speed is 16MB UTP. - -3). PnP support for this adapter sucks. I recommend hard setting the - IO/MEM/IRQ by the jumpers on the adapter. If this is not possible - load the module with the following io=[ioaddr] mem=[mem_addr] - irq=[irq_num]. - - The following IRQ, IO, and MEM settings are supported. - - IO ports: - 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, 0x300, - 0x320, 0x340, 0x360, 0x380. - - IRQs: - 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15 - - Memory addresses: - 0xA0000, 0xA4000, 0xA8000, 0xAC000, 0xB0000, 0xB4000, - 0xB8000, 0xBC000, 0xC0000, 0xC4000, 0xC8000, 0xCC000, - 0xD0000, 0xD4000, 0xD8000, 0xDC000, 0xE0000, 0xE4000, - 0xE8000, 0xEC000, 0xF0000, 0xF4000, 0xF8000, 0xFC000 - -This driver is under the GNU General Public License. Its Firmware image is -included as an initialized C-array and is licensed by SMC to the Linux -users of this driver. However no warranty about its fitness is expressed or -implied by SMC. diff --git a/trunk/Documentation/networking/stmmac.txt b/trunk/Documentation/networking/stmmac.txt index d0aeeadd264b..ab1e8d7004c5 100644 --- a/trunk/Documentation/networking/stmmac.txt +++ b/trunk/Documentation/networking/stmmac.txt @@ -111,11 +111,12 @@ and detailed below as well: int phy_addr; int interface; struct stmmac_mdio_bus_data *mdio_bus_data; - int pbl; + struct stmmac_dma_cfg *dma_cfg; int clk_csr; int has_gmac; int enh_desc; int tx_coe; + int rx_coe; int bugged_jumbo; int pmt; int force_sf_dma_mode; @@ -136,10 +137,12 @@ Where: o pbl: the Programmable Burst Length is maximum number of beats to be transferred in one DMA transaction. GMAC also enables the 4xPBL by default. - o clk_csr: CSR Clock range selection. + o clk_csr: fixed CSR Clock range selection. o has_gmac: uses the GMAC core. o enh_desc: if sets the MAC will use the enhanced descriptor structure. o tx_coe: core is able to perform the tx csum in HW. + o rx_coe: the supports three check sum offloading engine types: + type_1, type_2 (full csum) and no RX coe. o bugged_jumbo: some HWs are not able to perform the csum in HW for over-sized frames due to limited buffer sizes. Setting this flag the csum will be done in SW on @@ -160,7 +163,7 @@ Where: o custom_cfg: this is a custom configuration that can be passed while initialising the resources. -The we have: +For MDIO bus The we have: struct stmmac_mdio_bus_data { int bus_id; @@ -177,10 +180,28 @@ Where: o irqs: list of IRQs, one per PHY. o probed_phy_irq: if irqs is NULL, use this for probed PHY. + +For DMA engine we have the following internal fields that should be +tuned according to the HW capabilities. + +struct stmmac_dma_cfg { + int pbl; + int fixed_burst; + int burst_len_supported; +}; + +Where: + o pbl: Programmable Burst Length + o fixed_burst: program the DMA to use the fixed burst mode + o burst_len: this is the value we put in the register + supported values are provided as macros in + linux/stmmac.h header file. + +--- + Below an example how the structures above are using on ST platforms. static struct plat_stmmacenet_data stxYYY_ethernet_platform_data = { - .pbl = 32, .has_gmac = 0, .enh_desc = 0, .fix_mac_speed = stxYYY_ethernet_fix_mac_speed, diff --git a/trunk/Documentation/networking/tms380tr.txt b/trunk/Documentation/networking/tms380tr.txt deleted file mode 100644 index 1f73e13058df..000000000000 --- a/trunk/Documentation/networking/tms380tr.txt +++ /dev/null @@ -1,147 +0,0 @@ -Text file for the Linux SysKonnect Token Ring ISA/PCI Adapter Driver. - Text file by: Jay Schulist - -The Linux SysKonnect Token Ring driver works with the SysKonnect TR4/16(+) ISA, -SysKonnect TR4/16(+) PCI, SysKonnect TR4/16 PCI, and older revisions of the -SK NET TR4/16 ISA card. - -Latest information on this driver can be obtained on the Linux-SNA WWW site. -Please point your browser to: -http://www.linux-sna.org - -Many thanks to Christoph Goos for his excellent work on this driver and -SysKonnect for donating the adapters to Linux-SNA for the testing and -maintenance of this device driver. - -Important information to be noted: -1. Adapters can be slow to open (~20 secs) and close (~5 secs), please be - patient. -2. This driver works very well when autoprobing for adapters. Why even - think about those nasty io/int/dma settings of modprobe when the driver - will do it all for you! - -This driver is rather simple to use. Select Y to Token Ring adapter support -in the kernel configuration. A choice for SysKonnect Token Ring adapters will -appear. This drives supports all SysKonnect ISA and PCI adapters. Choose this -option. I personally recommend compiling the driver as a module (M), but if you -you would like to compile it statically answer Y instead. - -This driver supports multiple adapters without the need to load multiple copies -of the driver. You should be able to load up to 7 adapters without any kernel -modifications, if you are in need of more please contact the maintainer of this -driver. - -Load the driver either by lilo/loadlin or as a module. When a module using the -following command will suffice for most: - -# modprobe sktr - -This will produce output similar to the following: (Output is user specific) - -sktr.c: v1.01 08/29/97 by Christoph Goos -tr0: SK NET TR 4/16 PCI found at 0x6100, using IRQ 17. -tr1: SK NET TR 4/16 PCI found at 0x6200, using IRQ 16. -tr2: SK NET TR 4/16 ISA found at 0xa20, using IRQ 10 and DMA 5. - -Now just setup the device via ifconfig and set and routes you may have. After -this you are ready to start sending some tokens. - -Errata: -For anyone wondering where to pick up the SysKonnect adapters please browse -to http://www.syskonnect.com - -This driver is under the GNU General Public License. Its Firmware image is -included as an initialized C-array and is licensed by SysKonnect to the Linux -users of this driver. However no warranty about its fitness is expressed or -implied by SysKonnect. - -Below find attached the setting for the SK NET TR 4/16 ISA adapters -------------------------------------------------------------------- - - *************************** - *** C O N T E N T S *** - *************************** - - 1) Location of DIP-Switch W1 - 2) Default settings - 3) DIP-Switch W1 description - - - ============================================================== - CHAPTER 1 LOCATION OF DIP-SWITCH - ============================================================== - -UÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ -þUÄÄÄÄÄÄ¿ UÄÄÄÄÄ¿ UÄÄÄ¿ þ -þAÄÄÄÄÄÄU W1 AÄÄÄÄÄU UÄÄÄÄ¿ þ þ þ -þUÄÄÄÄÄÄ¿ þ þ þ þ UÄÄÅ¿ -þAÄÄÄÄÄÄU UÄÄÄÄÄÄÄÄÄÄÄ¿ AÄÄÄÄU þ þ þ þþ -þUÄÄÄÄÄÄ¿ þ þ UÄÄÄ¿ AÄÄÄU AÄÄÅU -þAÄÄÄÄÄÄU þ TMS380C26 þ þ þ þ -þUÄÄÄÄÄÄ¿ þ þ AÄÄÄU AÄ¿ -þAÄÄÄÄÄÄU þ þ þ þ -þ AÄÄÄÄÄÄÄÄÄÄÄU þ þ -þ þ þ -þ AÄU -þ þ -þ þ -þ þ -þ þ -AÄÄÄÄÄÄÄÄÄÄÄÄAÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄAÄÄAÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄAÄÄÄÄÄÄÄÄÄU - AÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄU AÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄU - - ============================================================== - CHAPTER 2 DEFAULT SETTINGS - ============================================================== - - W1 1 2 3 4 5 6 7 8 - +------------------------------+ - | ON X | - | OFF X X X X X X X | - +------------------------------+ - - W1.1 = ON Adapter drives address lines SA17..19 - W1.2 - 1.5 = OFF BootROM disabled - W1.6 - 1.8 = OFF I/O address 0A20h - - ============================================================== - CHAPTER 3 DIP SWITCH W1 DESCRIPTION - ============================================================== - - UÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄ¿ ON - þ 1 þ 2 þ 3 þ 4 þ 5 þ 6 þ 7 þ 8 þ - AÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄU OFF - |AD | BootROM Addr. | I/O | - +-+-+-------+-------+-----+-----+ - | | | - | | +------ 6 7 8 - | | ON ON ON 1900h - | | ON ON OFF 0900h - | | ON OFF ON 1980h - | | ON OFF OFF 0980h - | | OFF ON ON 1b20h - | | OFF ON OFF 0b20h - | | OFF OFF ON 1a20h - | | OFF OFF OFF 0a20h (+) - | | - | | - | +-------- 2 3 4 5 - | OFF x x x disabled (+) - | ON ON ON ON C0000 - | ON ON ON OFF C4000 - | ON ON OFF ON C8000 - | ON ON OFF OFF CC000 - | ON OFF ON ON D0000 - | ON OFF ON OFF D4000 - | ON OFF OFF ON D8000 - | ON OFF OFF OFF DC000 - | - | - +----- 1 - OFF adapter does NOT drive SA<17..19> - ON adapter drives SA<17..19> (+) - - - (+) means default setting - - ******************************** diff --git a/trunk/Documentation/nfc/nfc-hci.txt b/trunk/Documentation/nfc/nfc-hci.txt new file mode 100644 index 000000000000..216b7254fcc3 --- /dev/null +++ b/trunk/Documentation/nfc/nfc-hci.txt @@ -0,0 +1,155 @@ +HCI backend for NFC Core + +Author: Eric Lapuyade, Samuel Ortiz +Contact: eric.lapuyade@intel.com, samuel.ortiz@intel.com + +General +------- + +The HCI layer implements much of the ETSI TS 102 622 V10.2.0 specification. It +enables easy writing of HCI-based NFC drivers. The HCI layer runs as an NFC Core +backend, implementing an abstract nfc device and translating NFC Core API +to HCI commands and events. + +HCI +--- + +HCI registers as an nfc device with NFC Core. Requests coming from userspace are +routed through netlink sockets to NFC Core and then to HCI. From this point, +they are translated in a sequence of HCI commands sent to the HCI layer in the +host controller (the chip). The sending context blocks while waiting for the +response to arrive. +HCI events can also be received from the host controller. They will be handled +and a translation will be forwarded to NFC Core as needed. +HCI uses 2 execution contexts: +- one if for executing commands : nfc_hci_msg_tx_work(). Only one command +can be executing at any given moment. +- one if for dispatching received events and responses : nfc_hci_msg_rx_work() + +HCI Session initialization: +--------------------------- + +The Session initialization is an HCI standard which must unfortunately +support proprietary gates. This is the reason why the driver will pass a list +of proprietary gates that must be part of the session. HCI will ensure all +those gates have pipes connected when the hci device is set up. + +HCI Gates and Pipes +------------------- + +A gate defines the 'port' where some service can be found. In order to access +a service, one must create a pipe to that gate and open it. In this +implementation, pipes are totally hidden. The public API only knows gates. +This is consistent with the driver need to send commands to proprietary gates +without knowing the pipe connected to it. + +Driver interface +---------------- + +A driver would normally register itself with HCI and provide the following +entry points: + +struct nfc_hci_ops { + int (*open)(struct nfc_hci_dev *hdev); + void (*close)(struct nfc_hci_dev *hdev); + int (*xmit)(struct nfc_hci_dev *hdev, struct sk_buff *skb); + int (*start_poll)(struct nfc_hci_dev *hdev, u32 protocols); + int (*target_from_gate)(struct nfc_hci_dev *hdev, u8 gate, + struct nfc_target *target); +}; + +open() and close() shall turn the hardware on and off. xmit() shall simply +write a frame to the chip. start_poll() is an optional entrypoint that shall +set the hardware in polling mode. This must be implemented only if the hardware +uses proprietary gates or a mechanism slightly different from the HCI standard. +target_from_gate() is another optional entrypoint to return the protocols +corresponding to a proprietary gate. + +On the rx path, the driver is responsible to push incoming HCP frames to HCI +using nfc_hci_recv_frame(). HCI will take care of re-aggregation and handling +This must be done from a context that can sleep. + +SHDLC +----- + +Most chips use shdlc to ensure integrity and delivery ordering of the HCP +frames between the host controller (the chip) and hosts (entities connected +to the chip, like the cpu). In order to simplify writing the driver, an shdlc +layer is available for use by the driver. +When used, the driver actually registers with shdlc, and shdlc will register +with HCI. HCI sees shdlc as the driver and thus send its HCP frames +through shdlc->xmit. +SHDLC adds a new execution context (nfc_shdlc_sm_work()) to run its state +machine and handle both its rx and tx path. + +Included Drivers +---------------- + +An HCI based driver for an NXP PN544, connected through I2C bus, and using +shdlc is included. + +Execution Contexts +------------------ + +The execution contexts are the following: +- IRQ handler (IRQH): +fast, cannot sleep. stores incoming frames into an shdlc rx queue + +- SHDLC State Machine worker (SMW) +handles shdlc rx & tx queues. Dispatches HCI cmd responses. + +- HCI Tx Cmd worker (MSGTXWQ) +Serialize execution of HCI commands. Complete execution in case of resp timeout. + +- HCI Rx worker (MSGRXWQ) +Dispatches incoming HCI commands or events. + +- Syscall context from a userspace call (SYSCALL) +Any entrypoint in HCI called from NFC Core + +Workflow executing an HCI command (using shdlc) +----------------------------------------------- + +Executing an HCI command can easily be performed synchronously using the +following API: + +int nfc_hci_send_cmd (struct nfc_hci_dev *hdev, u8 gate, u8 cmd, + const u8 *param, size_t param_len, struct sk_buff **skb) + +The API must be invoked from a context that can sleep. Most of the time, this +will be the syscall context. skb will return the result that was received in +the response. + +Internally, execution is asynchronous. So all this API does is to enqueue the +HCI command, setup a local wait queue on stack, and wait_event() for completion. +The wait is not interruptible because it is guaranteed that the command will +complete after some short timeout anyway. + +MSGTXWQ context will then be scheduled and invoke nfc_hci_msg_tx_work(). +This function will dequeue the next pending command and send its HCP fragments +to the lower layer which happens to be shdlc. It will then start a timer to be +able to complete the command with a timeout error if no response arrive. + +SMW context gets scheduled and invokes nfc_shdlc_sm_work(). This function +handles shdlc framing in and out. It uses the driver xmit to send frames and +receives incoming frames in an skb queue filled from the driver IRQ handler. +SHDLC I(nformation) frames payload are HCP fragments. They are agregated to +form complete HCI frames, which can be a response, command, or event. + +HCI Responses are dispatched immediately from this context to unblock +waiting command execution. Reponse processing involves invoking the completion +callback that was provided by nfc_hci_msg_tx_work() when it sent the command. +The completion callback will then wake the syscall context. + +Workflow receiving an HCI event or command +------------------------------------------ + +HCI commands or events are not dispatched from SMW context. Instead, they are +queued to HCI rx_queue and will be dispatched from HCI rx worker +context (MSGRXWQ). This is done this way to allow a cmd or event handler +to also execute other commands (for example, handling the +NFC_HCI_EVT_TARGET_DISCOVERED event from PN544 requires to issue an +ANY_GET_PARAMETER to the reader A gate to get information on the target +that was discovered). + +Typically, such an event will be propagated to NFC Core from MSGRXWQ context. diff --git a/trunk/Documentation/parisc/debugging b/trunk/Documentation/parisc/debugging index d728594058e5..7d75223fa18d 100644 --- a/trunk/Documentation/parisc/debugging +++ b/trunk/Documentation/parisc/debugging @@ -34,6 +34,6 @@ registers interruption handlers read to find out where the machine was interrupted - so if you get an interruption between the instruction that clears the Q bit and the RFI that sets it again you don't know where exactly it happened. If you're lucky the IAOQ will point to the -instrucion that cleared the Q bit, if you're not it points anywhere +instruction that cleared the Q bit, if you're not it points anywhere at all. Usually Q bit problems will show themselves in unexplainable system hangs or running off the end of physical memory. diff --git a/trunk/Documentation/pinctrl.txt b/trunk/Documentation/pinctrl.txt index d97bccf46147..e40f4b4e1977 100644 --- a/trunk/Documentation/pinctrl.txt +++ b/trunk/Documentation/pinctrl.txt @@ -152,11 +152,9 @@ static const struct foo_group foo_groups[] = { }; -static int foo_list_groups(struct pinctrl_dev *pctldev, unsigned selector) +static int foo_get_groups_count(struct pinctrl_dev *pctldev) { - if (selector >= ARRAY_SIZE(foo_groups)) - return -EINVAL; - return 0; + return ARRAY_SIZE(foo_groups); } static const char *foo_get_group_name(struct pinctrl_dev *pctldev, @@ -175,7 +173,7 @@ static int foo_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, } static struct pinctrl_ops foo_pctrl_ops = { - .list_groups = foo_list_groups, + .get_groups_count = foo_get_groups_count, .get_group_name = foo_get_group_name, .get_group_pins = foo_get_group_pins, }; @@ -186,13 +184,12 @@ static struct pinctrl_desc foo_desc = { .pctlops = &foo_pctrl_ops, }; -The pin control subsystem will call the .list_groups() function repeatedly -beginning on 0 until it returns non-zero to determine legal selectors, then -it will call the other functions to retrieve the name and pins of the group. -Maintaining the data structure of the groups is up to the driver, this is -just a simple example - in practice you may need more entries in your group -structure, for example specific register ranges associated with each group -and so on. +The pin control subsystem will call the .get_groups_count() function to +determine total number of legal selectors, then it will call the other functions +to retrieve the name and pins of the group. Maintaining the data structure of +the groups is up to the driver, this is just a simple example - in practice you +may need more entries in your group structure, for example specific register +ranges associated with each group and so on. Pin configuration @@ -606,11 +603,9 @@ static const struct foo_group foo_groups[] = { }; -static int foo_list_groups(struct pinctrl_dev *pctldev, unsigned selector) +static int foo_get_groups_count(struct pinctrl_dev *pctldev) { - if (selector >= ARRAY_SIZE(foo_groups)) - return -EINVAL; - return 0; + return ARRAY_SIZE(foo_groups); } static const char *foo_get_group_name(struct pinctrl_dev *pctldev, @@ -629,7 +624,7 @@ static int foo_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, } static struct pinctrl_ops foo_pctrl_ops = { - .list_groups = foo_list_groups, + .get_groups_count = foo_get_groups_count, .get_group_name = foo_get_group_name, .get_group_pins = foo_get_group_pins, }; @@ -640,7 +635,7 @@ struct foo_pmx_func { const unsigned num_groups; }; -static const char * const spi0_groups[] = { "spi0_1_grp" }; +static const char * const spi0_groups[] = { "spi0_0_grp", "spi0_1_grp" }; static const char * const i2c0_groups[] = { "i2c0_grp" }; static const char * const mmc0_groups[] = { "mmc0_1_grp", "mmc0_2_grp", "mmc0_3_grp" }; @@ -663,11 +658,9 @@ static const struct foo_pmx_func foo_functions[] = { }, }; -int foo_list_funcs(struct pinctrl_dev *pctldev, unsigned selector) +int foo_get_functions_count(struct pinctrl_dev *pctldev) { - if (selector >= ARRAY_SIZE(foo_functions)) - return -EINVAL; - return 0; + return ARRAY_SIZE(foo_functions); } const char *foo_get_fname(struct pinctrl_dev *pctldev, unsigned selector) @@ -703,7 +696,7 @@ void foo_disable(struct pinctrl_dev *pctldev, unsigned selector, } struct pinmux_ops foo_pmxops = { - .list_functions = foo_list_funcs, + .get_functions_count = foo_get_functions_count, .get_function_name = foo_get_fname, .get_function_groups = foo_get_groups, .enable = foo_enable, @@ -786,7 +779,7 @@ and spi on the second function mapping: #include -static const struct pinctrl_map __initdata mapping[] = { +static const struct pinctrl_map mapping[] __initconst = { { .dev_name = "foo-spi.0", .name = PINCTRL_STATE_DEFAULT, @@ -952,13 +945,13 @@ case), we define a mapping like this: The result of grabbing this mapping from the device with something like this (see next paragraph): - p = pinctrl_get(dev); + p = devm_pinctrl_get(dev); s = pinctrl_lookup_state(p, "8bit"); ret = pinctrl_select_state(p, s); or more simply: - p = pinctrl_get_select(dev, "8bit"); + p = devm_pinctrl_get_select(dev, "8bit"); Will be that you activate all the three bottom records in the mapping at once. Since they share the same name, pin controller device, function and @@ -992,7 +985,7 @@ foo_probe() /* Allocate a state holder named "foo" etc */ struct foo_state *foo = ...; - foo->p = pinctrl_get(&device); + foo->p = devm_pinctrl_get(&device); if (IS_ERR(foo->p)) { /* FIXME: clean up "foo" here */ return PTR_ERR(foo->p); @@ -1000,24 +993,17 @@ foo_probe() foo->s = pinctrl_lookup_state(foo->p, PINCTRL_STATE_DEFAULT); if (IS_ERR(foo->s)) { - pinctrl_put(foo->p); /* FIXME: clean up "foo" here */ return PTR_ERR(s); } ret = pinctrl_select_state(foo->s); if (ret < 0) { - pinctrl_put(foo->p); /* FIXME: clean up "foo" here */ return ret; } } -foo_remove() -{ - pinctrl_put(state->p); -} - This get/lookup/select/put sequence can just as well be handled by bus drivers if you don't want each and every driver to handle it and you know the arrangement on your bus. @@ -1029,6 +1015,11 @@ The semantics of the pinctrl APIs are: kernel memory to hold the pinmux state. All mapping table parsing or similar slow operations take place within this API. +- devm_pinctrl_get() is a variant of pinctrl_get() that causes pinctrl_put() + to be called automatically on the retrieved pointer when the associated + device is removed. It is recommended to use this function over plain + pinctrl_get(). + - pinctrl_lookup_state() is called in process context to obtain a handle to a specific state for a the client device. This operation may be slow too. @@ -1041,14 +1032,30 @@ The semantics of the pinctrl APIs are: - pinctrl_put() frees all information associated with a pinctrl handle. +- devm_pinctrl_put() is a variant of pinctrl_put() that may be used to + explicitly destroy a pinctrl object returned by devm_pinctrl_get(). + However, use of this function will be rare, due to the automatic cleanup + that will occur even without calling it. + + pinctrl_get() must be paired with a plain pinctrl_put(). + pinctrl_get() may not be paired with devm_pinctrl_put(). + devm_pinctrl_get() can optionally be paired with devm_pinctrl_put(). + devm_pinctrl_get() may not be paired with plain pinctrl_put(). + Usually the pin control core handled the get/put pair and call out to the device drivers bookkeeping operations, like checking available functions and the associated pins, whereas the enable/disable pass on to the pin controller driver which takes care of activating and/or deactivating the mux setting by quickly poking some registers. -The pins are allocated for your device when you issue the pinctrl_get() call, -after this you should be able to see this in the debugfs listing of all pins. +The pins are allocated for your device when you issue the devm_pinctrl_get() +call, after this you should be able to see this in the debugfs listing of all +pins. + +NOTE: the pinctrl system will return -EPROBE_DEFER if it cannot find the +requested pinctrl handles, for example if the pinctrl driver has not yet +registered. Thus make sure that the error path in your driver gracefully +cleans up and is ready to retry the probing later in the startup process. System pin control hogging @@ -1094,13 +1101,13 @@ it, disables and releases it, and muxes it in on the pins defined by group B: #include -foo_switch() -{ - struct pinctrl *p; - struct pinctrl_state *s1, *s2; +struct pinctrl *p; +struct pinctrl_state *s1, *s2; +foo_probe() +{ /* Setup */ - p = pinctrl_get(&device); + p = devm_pinctrl_get(&device); if (IS_ERR(p)) ... @@ -1111,7 +1118,10 @@ foo_switch() s2 = pinctrl_lookup_state(foo->p, "pos-B"); if (IS_ERR(s2)) ... +} +foo_switch() +{ /* Enable on position A */ ret = pinctrl_select_state(s1); if (ret < 0) @@ -1125,8 +1135,6 @@ foo_switch() ... ... - - pinctrl_put(p); } The above has to be done from process context. diff --git a/trunk/Documentation/power/regulator/regulator.txt b/trunk/Documentation/power/regulator/regulator.txt index e272d9909e39..13902778ae44 100644 --- a/trunk/Documentation/power/regulator/regulator.txt +++ b/trunk/Documentation/power/regulator/regulator.txt @@ -11,8 +11,7 @@ Registration Drivers can register a regulator by calling :- struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, - struct device *dev, struct regulator_init_data *init_data, - void *driver_data, struct device_node *of_node); + const struct regulator_config *config); This will register the regulators capabilities and operations to the regulator core. diff --git a/trunk/Documentation/prctl/seccomp_filter.txt b/trunk/Documentation/prctl/seccomp_filter.txt new file mode 100644 index 000000000000..597c3c581375 --- /dev/null +++ b/trunk/Documentation/prctl/seccomp_filter.txt @@ -0,0 +1,163 @@ + SECure COMPuting with filters + ============================= + +Introduction +------------ + +A large number of system calls are exposed to every userland process +with many of them going unused for the entire lifetime of the process. +As system calls change and mature, bugs are found and eradicated. A +certain subset of userland applications benefit by having a reduced set +of available system calls. The resulting set reduces the total kernel +surface exposed to the application. System call filtering is meant for +use with those applications. + +Seccomp filtering provides a means for a process to specify a filter for +incoming system calls. The filter is expressed as a Berkeley Packet +Filter (BPF) program, as with socket filters, except that the data +operated on is related to the system call being made: system call +number and the system call arguments. This allows for expressive +filtering of system calls using a filter program language with a long +history of being exposed to userland and a straightforward data set. + +Additionally, BPF makes it impossible for users of seccomp to fall prey +to time-of-check-time-of-use (TOCTOU) attacks that are common in system +call interposition frameworks. BPF programs may not dereference +pointers which constrains all filters to solely evaluating the system +call arguments directly. + +What it isn't +------------- + +System call filtering isn't a sandbox. It provides a clearly defined +mechanism for minimizing the exposed kernel surface. It is meant to be +a tool for sandbox developers to use. Beyond that, policy for logical +behavior and information flow should be managed with a combination of +other system hardening techniques and, potentially, an LSM of your +choosing. Expressive, dynamic filters provide further options down this +path (avoiding pathological sizes or selecting which of the multiplexed +system calls in socketcall() is allowed, for instance) which could be +construed, incorrectly, as a more complete sandboxing solution. + +Usage +----- + +An additional seccomp mode is added and is enabled using the same +prctl(2) call as the strict seccomp. If the architecture has +CONFIG_HAVE_ARCH_SECCOMP_FILTER, then filters may be added as below: + +PR_SET_SECCOMP: + Now takes an additional argument which specifies a new filter + using a BPF program. + The BPF program will be executed over struct seccomp_data + reflecting the system call number, arguments, and other + metadata. The BPF program must then return one of the + acceptable values to inform the kernel which action should be + taken. + + Usage: + prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, prog); + + The 'prog' argument is a pointer to a struct sock_fprog which + will contain the filter program. If the program is invalid, the + call will return -1 and set errno to EINVAL. + + If fork/clone and execve are allowed by @prog, any child + processes will be constrained to the same filters and system + call ABI as the parent. + + Prior to use, the task must call prctl(PR_SET_NO_NEW_PRIVS, 1) or + run with CAP_SYS_ADMIN privileges in its namespace. If these are not + true, -EACCES will be returned. This requirement ensures that filter + programs cannot be applied to child processes with greater privileges + than the task that installed them. + + Additionally, if prctl(2) is allowed by the attached filter, + additional filters may be layered on which will increase evaluation + time, but allow for further decreasing the attack surface during + execution of a process. + +The above call returns 0 on success and non-zero on error. + +Return values +------------- +A seccomp filter may return any of the following values. If multiple +filters exist, the return value for the evaluation of a given system +call will always use the highest precedent value. (For example, +SECCOMP_RET_KILL will always take precedence.) + +In precedence order, they are: + +SECCOMP_RET_KILL: + Results in the task exiting immediately without executing the + system call. The exit status of the task (status & 0x7f) will + be SIGSYS, not SIGKILL. + +SECCOMP_RET_TRAP: + Results in the kernel sending a SIGSYS signal to the triggering + task without executing the system call. The kernel will + rollback the register state to just before the system call + entry such that a signal handler in the task will be able to + inspect the ucontext_t->uc_mcontext registers and emulate + system call success or failure upon return from the signal + handler. + + The SECCOMP_RET_DATA portion of the return value will be passed + as si_errno. + + SIGSYS triggered by seccomp will have a si_code of SYS_SECCOMP. + +SECCOMP_RET_ERRNO: + Results in the lower 16-bits of the return value being passed + to userland as the errno without executing the system call. + +SECCOMP_RET_TRACE: + When returned, this value will cause the kernel to attempt to + notify a ptrace()-based tracer prior to executing the system + call. If there is no tracer present, -ENOSYS is returned to + userland and the system call is not executed. + + A tracer will be notified if it requests PTRACE_O_TRACESECCOMP + using ptrace(PTRACE_SETOPTIONS). The tracer will be notified + of a PTRACE_EVENT_SECCOMP and the SECCOMP_RET_DATA portion of + the BPF program return value will be available to the tracer + via PTRACE_GETEVENTMSG. + +SECCOMP_RET_ALLOW: + Results in the system call being executed. + +If multiple filters exist, the return value for the evaluation of a +given system call will always use the highest precedent value. + +Precedence is only determined using the SECCOMP_RET_ACTION mask. When +multiple filters return values of the same precedence, only the +SECCOMP_RET_DATA from the most recently installed filter will be +returned. + +Pitfalls +-------- + +The biggest pitfall to avoid during use is filtering on system call +number without checking the architecture value. Why? On any +architecture that supports multiple system call invocation conventions, +the system call numbers may vary based on the specific invocation. If +the numbers in the different calling conventions overlap, then checks in +the filters may be abused. Always check the arch value! + +Example +------- + +The samples/seccomp/ directory contains both an x86-specific example +and a more generic example of a higher level macro interface for BPF +program generation. + + + +Adding architecture support +----------------------- + +See arch/Kconfig for the authoritative requirements. In general, if an +architecture supports both ptrace_event and seccomp, it will be able to +support seccomp filter with minor fixup: SIGSYS support and seccomp return +value checking. Then it must just add CONFIG_HAVE_ARCH_SECCOMP_FILTER +to its arch-specific Kconfig. diff --git a/trunk/Documentation/ramoops.txt b/trunk/Documentation/ramoops.txt index 8fb1ba7fe7bf..4ba7db231cb2 100644 --- a/trunk/Documentation/ramoops.txt +++ b/trunk/Documentation/ramoops.txt @@ -3,7 +3,7 @@ Ramoops oops/panic logger Sergiu Iordache -Updated: 8 August 2011 +Updated: 17 November 2011 0. Introduction @@ -30,6 +30,11 @@ variable while setting 0 in that variable dumps only the panics. The module uses a counter to record multiple dumps but the counter gets reset on restart (i.e. new dumps after the restart will overwrite old ones). +Ramoops also supports software ECC protection of persistent memory regions. +This might be useful when a hardware reset was used to bring the machine back +to life (i.e. a watchdog triggered). In such cases, RAM may be somewhat +corrupt, but usually it is restorable. + 2. Setting the parameters Setting the ramoops parameters can be done in 2 different manners: @@ -38,7 +43,7 @@ Setting the ramoops parameters can be done in 2 different manners: 2. Use a platform device and set the platform data. The parameters can then be set through that platform data. An example of doing that is: -#include +#include [...] static struct ramoops_platform_data ramoops_data = { @@ -46,6 +51,7 @@ static struct ramoops_platform_data ramoops_data = { .mem_address = <...>, .record_size = <...>, .dump_oops = <...>, + .ecc = <...>, }; static struct platform_device ramoops_dev = { @@ -71,6 +77,6 @@ timestamp and a new line. The dump then continues with the actual data. 4. Reading the data -The dump data can be read from memory (through /dev/mem or other means). -Getting the module parameters, which are needed in order to parse the data, can -be done through /sys/module/ramoops/parameters/* . +The dump data can be read from the pstore filesystem. The format for these +files is "dmesg-ramoops-N", where N is the record number in memory. To delete +a stored record from RAM, simply unlink the respective pstore file. diff --git a/trunk/Documentation/scheduler/sched-design-CFS.txt b/trunk/Documentation/scheduler/sched-design-CFS.txt index 91ecff07cede..d529e02d928d 100644 --- a/trunk/Documentation/scheduler/sched-design-CFS.txt +++ b/trunk/Documentation/scheduler/sched-design-CFS.txt @@ -130,7 +130,7 @@ CFS implements three scheduling policies: idle timer scheduler in order to avoid to get into priority inversion problems which would deadlock the machine. -SCHED_FIFO/_RR are implemented in sched_rt.c and are as specified by +SCHED_FIFO/_RR are implemented in sched/rt.c and are as specified by POSIX. The command chrt from util-linux-ng 2.13.1.1 can set all of these except @@ -145,9 +145,9 @@ Classes," an extensible hierarchy of scheduler modules. These modules encapsulate scheduling policy details and are handled by the scheduler core without the core code assuming too much about them. -sched_fair.c implements the CFS scheduler described above. +sched/fair.c implements the CFS scheduler described above. -sched_rt.c implements SCHED_FIFO and SCHED_RR semantics, in a simpler way than +sched/rt.c implements SCHED_FIFO and SCHED_RR semantics, in a simpler way than the previous vanilla scheduler did. It uses 100 runqueues (for all 100 RT priority levels, instead of 140 in the previous scheduler) and it needs no expired array. diff --git a/trunk/Documentation/scheduler/sched-domains.txt b/trunk/Documentation/scheduler/sched-domains.txt index b7ee379b651b..443f0c76bab4 100644 --- a/trunk/Documentation/scheduler/sched-domains.txt +++ b/trunk/Documentation/scheduler/sched-domains.txt @@ -61,10 +61,6 @@ The implementor should read comments in include/linux/sched.h: struct sched_domain fields, SD_FLAG_*, SD_*_INIT to get an idea of the specifics and what to tune. -For SMT, the architecture must define CONFIG_SCHED_SMT and provide a -cpumask_t cpu_sibling_map[NR_CPUS], where cpu_sibling_map[i] is the mask of -all "i"'s siblings as well as "i" itself. - Architectures may retain the regular override the default SD_*_INIT flags while using the generic domain builder in kernel/sched.c if they wish to retain the traditional SMT->SMP->NUMA topology (or some subset of that). This diff --git a/trunk/Documentation/scsi/ChangeLog.megaraid_sas b/trunk/Documentation/scsi/ChangeLog.megaraid_sas index 83f8ea8b79eb..80441ab608e4 100644 --- a/trunk/Documentation/scsi/ChangeLog.megaraid_sas +++ b/trunk/Documentation/scsi/ChangeLog.megaraid_sas @@ -1,3 +1,11 @@ +Release Date : Mon. Mar 19, 2012 17:00:00 PST 2012 - + (emaild-id:megaraidlinux@lsi.com) + Adam Radford +Current Version : 00.00.06.15-rc1 +Old Version : 00.00.06.14-rc1 + 1. Optimize HostMSIxVectors setting. + 2. Add fpRead/WriteCapable, fpRead/WriteAcrossStripe checks. +------------------------------------------------------------------------------- Release Date : Fri. Jan 6, 2012 17:00:00 PST 2010 - (emaild-id:megaraidlinux@lsi.com) Adam Radford diff --git a/trunk/Documentation/security/Smack.txt b/trunk/Documentation/security/Smack.txt index d2f72ae66432..a416479b8a1c 100644 --- a/trunk/Documentation/security/Smack.txt +++ b/trunk/Documentation/security/Smack.txt @@ -15,7 +15,7 @@ at hand. Smack consists of three major components: - The kernel - - A start-up script and a few modified applications + - Basic utilities, which are helpful but not required - Configuration data The kernel component of Smack is implemented as a Linux @@ -23,37 +23,28 @@ Security Modules (LSM) module. It requires netlabel and works best with file systems that support extended attributes, although xattr support is not strictly required. It is safe to run a Smack kernel under a "vanilla" distribution. + Smack kernels use the CIPSO IP option. Some network configurations are intolerant of IP options and can impede access to systems that use them as Smack does. -The startup script etc-init.d-smack should be installed -in /etc/init.d/smack and should be invoked early in the -start-up process. On Fedora rc5.d/S02smack is recommended. -This script ensures that certain devices have the correct -Smack attributes and loads the Smack configuration if -any is defined. This script invokes two programs that -ensure configuration data is properly formatted. These -programs are /usr/sbin/smackload and /usr/sin/smackcipso. -The system will run just fine without these programs, -but it will be difficult to set access rules properly. - -A version of "ls" that provides a "-M" option to display -Smack labels on long listing is available. +The current git repositories for Smack user space are: -A hacked version of sshd that allows network logins by users -with specific Smack labels is available. This version does -not work for scp. You must set the /etc/ssh/sshd_config -line: - UsePrivilegeSeparation no + git@gitorious.org:meego-platform-security/smackutil.git + git@gitorious.org:meego-platform-security/libsmack.git -The format of /etc/smack/usr is: +These should make and install on most modern distributions. +There are three commands included in smackutil: - username smack +smackload - properly formats data for writing to /smack/load +smackcipso - properly formats data for writing to /smack/cipso +chsmack - display or set Smack extended attribute values In keeping with the intent of Smack, configuration data is minimal and not strictly required. The most important configuration step is mounting the smackfs pseudo filesystem. +If smackutil is installed the startup script will take care +of this, but it can be manually as well. Add this line to /etc/fstab: @@ -61,19 +52,148 @@ Add this line to /etc/fstab: and create the /smack directory for mounting. -Smack uses extended attributes (xattrs) to store file labels. -The command to set a Smack label on a file is: +Smack uses extended attributes (xattrs) to store labels on filesystem +objects. The attributes are stored in the extended attribute security +name space. A process must have CAP_MAC_ADMIN to change any of these +attributes. + +The extended attributes that Smack uses are: + +SMACK64 + Used to make access control decisions. In almost all cases + the label given to a new filesystem object will be the label + of the process that created it. +SMACK64EXEC + The Smack label of a process that execs a program file with + this attribute set will run with this attribute's value. +SMACK64MMAP + Don't allow the file to be mmapped by a process whose Smack + label does not allow all of the access permitted to a process + with the label contained in this attribute. This is a very + specific use case for shared libraries. +SMACK64TRANSMUTE + Can only have the value "TRUE". If this attribute is present + on a directory when an object is created in the directory and + the Smack rule (more below) that permitted the write access + to the directory includes the transmute ("t") mode the object + gets the label of the directory instead of the label of the + creating process. If the object being created is a directory + the SMACK64TRANSMUTE attribute is set as well. +SMACK64IPIN + This attribute is only available on file descriptors for sockets. + Use the Smack label in this attribute for access control + decisions on packets being delivered to this socket. +SMACK64IPOUT + This attribute is only available on file descriptors for sockets. + Use the Smack label in this attribute for access control + decisions on packets coming from this socket. + +There are multiple ways to set a Smack label on a file: # attr -S -s SMACK64 -V "value" path + # chsmack -a value path -NOTE: Smack labels are limited to 23 characters. The attr command - does not enforce this restriction and can be used to set - invalid Smack labels on files. - -If you don't do anything special all users will get the floor ("_") -label when they log in. If you do want to log in via the hacked ssh -at other labels use the attr command to set the smack value on the -home directory and its contents. +A process can see the smack label it is running with by +reading /proc/self/attr/current. A process with CAP_MAC_ADMIN +can set the process smack by writing there. + +Most Smack configuration is accomplished by writing to files +in the smackfs filesystem. This pseudo-filesystem is usually +mounted on /smack. + +access + This interface reports whether a subject with the specified + Smack label has a particular access to an object with a + specified Smack label. Write a fixed format access rule to + this file. The next read will indicate whether the access + would be permitted. The text will be either "1" indicating + access, or "0" indicating denial. +access2 + This interface reports whether a subject with the specified + Smack label has a particular access to an object with a + specified Smack label. Write a long format access rule to + this file. The next read will indicate whether the access + would be permitted. The text will be either "1" indicating + access, or "0" indicating denial. +ambient + This contains the Smack label applied to unlabeled network + packets. +cipso + This interface allows a specific CIPSO header to be assigned + to a Smack label. The format accepted on write is: + "%24s%4d%4d"["%4d"]... + The first string is a fixed Smack label. The first number is + the level to use. The second number is the number of categories. + The following numbers are the categories. + "level-3-cats-5-19 3 2 5 19" +cipso2 + This interface allows a specific CIPSO header to be assigned + to a Smack label. The format accepted on write is: + "%s%4d%4d"["%4d"]... + The first string is a long Smack label. The first number is + the level to use. The second number is the number of categories. + The following numbers are the categories. + "level-3-cats-5-19 3 2 5 19" +direct + This contains the CIPSO level used for Smack direct label + representation in network packets. +doi + This contains the CIPSO domain of interpretation used in + network packets. +load + This interface allows access control rules in addition to + the system defined rules to be specified. The format accepted + on write is: + "%24s%24s%5s" + where the first string is the subject label, the second the + object label, and the third the requested access. The access + string may contain only the characters "rwxat-", and specifies + which sort of access is allowed. The "-" is a placeholder for + permissions that are not allowed. The string "r-x--" would + specify read and execute access. Labels are limited to 23 + characters in length. +load2 + This interface allows access control rules in addition to + the system defined rules to be specified. The format accepted + on write is: + "%s %s %s" + where the first string is the subject label, the second the + object label, and the third the requested access. The access + string may contain only the characters "rwxat-", and specifies + which sort of access is allowed. The "-" is a placeholder for + permissions that are not allowed. The string "r-x--" would + specify read and execute access. +load-self + This interface allows process specific access rules to be + defined. These rules are only consulted if access would + otherwise be permitted, and are intended to provide additional + restrictions on the process. The format is the same as for + the load interface. +load-self2 + This interface allows process specific access rules to be + defined. These rules are only consulted if access would + otherwise be permitted, and are intended to provide additional + restrictions on the process. The format is the same as for + the load2 interface. +logging + This contains the Smack logging state. +mapped + This contains the CIPSO level used for Smack mapped label + representation in network packets. +netlabel + This interface allows specific internet addresses to be + treated as single label hosts. Packets are sent to single + label hosts without CIPSO headers, but only from processes + that have Smack write access to the host label. All packets + received from single label hosts are given the specified + label. The format accepted on write is: + "%d.%d.%d.%d label" or "%d.%d.%d.%d/%d label". +onlycap + This contains the label processes must have for CAP_MAC_ADMIN + and CAP_MAC_OVERRIDE to be effective. If this file is empty + these capabilities are effective at for processes with any + label. The value is set by writing the desired label to the + file or cleared by writing "-" to the file. You can add access rules in /etc/smack/accesses. They take the form: @@ -83,10 +203,6 @@ access is a combination of the letters rwxa which specify the kind of access permitted a subject with subjectlabel on an object with objectlabel. If there is no rule no access is allowed. -A process can see the smack label it is running with by -reading /proc/self/attr/current. A privileged process can -set the process smack by writing there. - Look for additional programs on http://schaufler-ca.com From the Smack Whitepaper: @@ -186,7 +302,7 @@ team. Smack labels are unstructured, case sensitive, and the only operation ever performed on them is comparison for equality. Smack labels cannot contain unprintable characters, the "/" (slash), the "\" (backslash), the "'" (quote) and '"' (double-quote) characters. -Smack labels cannot begin with a '-', which is reserved for special options. +Smack labels cannot begin with a '-'. This is reserved for special options. There are some predefined labels: @@ -194,7 +310,7 @@ There are some predefined labels: ^ Pronounced "hat", a single circumflex character. * Pronounced "star", a single asterisk character. ? Pronounced "huh", a single question mark character. - @ Pronounced "Internet", a single at sign character. + @ Pronounced "web", a single at sign character. Every task on a Smack system is assigned a label. System tasks, such as init(8) and systems daemons, are run with the floor ("_") label. User tasks @@ -246,13 +362,14 @@ The format of an access rule is: Where subject-label is the Smack label of the task, object-label is the Smack label of the thing being accessed, and access is a string specifying the sort -of access allowed. The Smack labels are limited to 23 characters. The access -specification is searched for letters that describe access modes: +of access allowed. The access specification is searched for letters that +describe access modes: a: indicates that append access should be granted. r: indicates that read access should be granted. w: indicates that write access should be granted. x: indicates that execute access should be granted. + t: indicates that the rule requests transmutation. Uppercase values for the specification letters are allowed as well. Access mode specifications can be in any order. Examples of acceptable rules @@ -273,7 +390,7 @@ Examples of unacceptable rules are: Spaces are not allowed in labels. Since a subject always has access to files with the same label specifying a rule for that case is pointless. Only -valid letters (rwxaRWXA) and the dash ('-') character are allowed in +valid letters (rwxatRWXAT) and the dash ('-') character are allowed in access specifications. The dash is a placeholder, so "a-r" is the same as "ar". A lone dash is used to specify that no access should be allowed. @@ -297,6 +414,13 @@ but not any of its attributes by the circumstance of having read access to the containing directory but not to the differently labeled file. This is an artifact of the file name being data in the directory, not a part of the file. +If a directory is marked as transmuting (SMACK64TRANSMUTE=TRUE) and the +access rule that allows a process to create an object in that directory +includes 't' access the label assigned to the new object will be that +of the directory, not the creating process. This makes it much easier +for two processes with different labels to share data without granting +access to all of their files. + IPC objects, message queues, semaphore sets, and memory segments exist in flat namespaces and access requests are only required to match the object in question. diff --git a/trunk/Documentation/security/Yama.txt b/trunk/Documentation/security/Yama.txt index a9511f179069..e369de2d48cd 100644 --- a/trunk/Documentation/security/Yama.txt +++ b/trunk/Documentation/security/Yama.txt @@ -34,7 +34,7 @@ parent to a child process (i.e. direct "gdb EXE" and "strace EXE" still work), or with CAP_SYS_PTRACE (i.e. "gdb --pid=PID", and "strace -p PID" still work as root). -For software that has defined application-specific relationships +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 @@ -46,6 +46,8 @@ restrictions, it can call prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, ...) so that any otherwise allowed process (even those in external pid namespaces) may attach. +These restrictions do not change how ptrace via PTRACE_TRACEME operates. + The sysctl settings are: 0 - classic ptrace permissions: a process can PTRACE_ATTACH to any other @@ -60,6 +62,12 @@ The sysctl settings are: inferior can call prctl(PR_SET_PTRACER, debugger, ...) to declare an allowed debugger PID to call PTRACE_ATTACH on the inferior. +2 - admin-only attach: only processes with CAP_SYS_PTRACE may use ptrace + with PTRACE_ATTACH. + +3 - no attach: no processes may use ptrace with PTRACE_ATTACH. Once set, + this sysctl cannot be changed to a lower value. + The original children-only logic was based on the restrictions in grsecurity. ============================================================== diff --git a/trunk/Documentation/security/keys.txt b/trunk/Documentation/security/keys.txt index d389acd31e19..aa0dbd74b71b 100644 --- a/trunk/Documentation/security/keys.txt +++ b/trunk/Documentation/security/keys.txt @@ -805,6 +805,23 @@ The keyctl syscall functions are: kernel and resumes executing userspace. + (*) Invalidate a key. + + long keyctl(KEYCTL_INVALIDATE, key_serial_t key); + + This function marks a key as being invalidated and then wakes up the + garbage collector. The garbage collector immediately removes invalidated + keys from all keyrings and deletes the key when its reference count + reaches zero. + + Keys that are marked invalidated become invisible to normal key operations + immediately, though they are still visible in /proc/keys until deleted + (they're marked with an 'i' flag). + + A process must have search permission on the key for this function to be + successful. + + =============== KERNEL SERVICES =============== diff --git a/trunk/Documentation/sound/alsa/compress_offload.txt b/trunk/Documentation/sound/alsa/compress_offload.txt index c83a835350f0..90e9b3a11abc 100644 --- a/trunk/Documentation/sound/alsa/compress_offload.txt +++ b/trunk/Documentation/sound/alsa/compress_offload.txt @@ -18,7 +18,7 @@ processing. Support for such hardware has not been very good in Linux, mostly because of a lack of a generic API available in the mainline kernel. -Rather than requiring a compability break with an API change of the +Rather than requiring a compatibility break with an API change of the ALSA PCM interface, a new 'Compressed Data' API is introduced to provide a control and data-streaming interface for audio DSPs. diff --git a/trunk/Documentation/sound/oss/ALS b/trunk/Documentation/sound/oss/ALS index d01ffbfd5808..bf10bed4574b 100644 --- a/trunk/Documentation/sound/oss/ALS +++ b/trunk/Documentation/sound/oss/ALS @@ -57,10 +57,10 @@ The resulting sound driver will provide the following capabilities: DSP/PCM/audio out (L&R), FM (L&R) and Mic in (mono). Jonathan Woithe -jwoithe@physics.adelaide.edu.au +jwoithe@just42.net 30 March 1998 Modified 2000-02-26 by Dave Forrest, drf5n@virginia.edu to add ALS100/ALS200 Modified 2000-04-10 by Paul Laufer, pelaufer@csupomona.edu to add ISAPnP info. -Modified 2000-11-19 by Jonathan Woithe, jwoithe@physics.adelaide.edu.au +Modified 2000-11-19 by Jonathan Woithe, jwoithe@just42.net - updated information for kernel 2.4.x. diff --git a/trunk/Documentation/sparc/README-2.5 b/trunk/Documentation/sparc/README-2.5 deleted file mode 100644 index 806fe490a56d..000000000000 --- a/trunk/Documentation/sparc/README-2.5 +++ /dev/null @@ -1,46 +0,0 @@ -BTFIXUP -------- - -To build new kernels you have to issue "make image". The ready kernel -in ELF format is placed in arch/sparc/boot/image. Explanation is below. - -BTFIXUP is a unique feature of Linux/sparc among other architectures, -developed by Jakub Jelinek (I think... Obviously David S. Miller took -part, too). It allows to boot the same kernel at different -sub-architectures, such as sun4c, sun4m, sun4d, where SunOS uses -different kernels. This feature is convinient for people who you move -disks between boxes and for distrution builders. - -To function, BTFIXUP must link the kernel "in the draft" first, -analyze the result, write a special stub code based on that, and -build the final kernel with the stub (btfix.o). - -Kai Germaschewski improved the build system of the kernel in the 2.5 series -significantly. Unfortunately, the traditional way of running the draft -linking from architecture specific Makefile before the actual linking -by generic Makefile is nearly impossible to support properly in the -new build system. Therefore, the way we integrate BTFIXUP with the -build system was changed in 2.5.40. Now, generic Makefile performs -the draft linking and stores the result in file vmlinux. Architecture -specific post-processing invokes BTFIXUP machinery and final linking -in the same way as other architectures do bootstraps. - -Implications of that change are as follows. - -1. Hackers must type "make image" now, instead of just "make", in the same - way as s390 people do now. It is analogous to "make bzImage" on i386. - This does NOT affect sparc64, you continue to use "make" to build sparc64 - kernels. - -2. vmlinux is not the final kernel, so RPM builders have to adjust - their spec files (if they delivered vmlinux for debugging). - System.map generated for vmlinux is still valid. - -3. Scripts that produce a.out images have to be changed. First, if they - invoke make, they have to use "make image". Second, they have to pick up - the new kernel in arch/sparc/boot/image instead of vmlinux. - -4. Since we are compliant with Kai's build system now, make -j is permitted. - --- Pete Zaitcev -zaitcev@yahoo.com diff --git a/trunk/Documentation/static-keys.txt b/trunk/Documentation/static-keys.txt index d93f3c00f245..9f5263d3152c 100644 --- a/trunk/Documentation/static-keys.txt +++ b/trunk/Documentation/static-keys.txt @@ -235,7 +235,7 @@ label case adds: 6 (mov) + 2 (test) + 2 (jne) = 10 - 5 (5 byte jump 0) = 5 addition bytes. If we then include the padding bytes, the jump label code saves, 16 total bytes -of instruction memory for this small fucntion. In this case the non-jump label +of instruction memory for this small function. In this case the non-jump label function is 80 bytes long. Thus, we have have saved 20% of the instruction footprint. We can in fact improve this even further, since the 5-byte no-op really can be a 2-byte no-op since we can reach the branch with a 2-byte jmp. diff --git a/trunk/Documentation/sysctl/net.txt b/trunk/Documentation/sysctl/net.txt index 3201a7097e4d..98335b7a5337 100644 --- a/trunk/Documentation/sysctl/net.txt +++ b/trunk/Documentation/sysctl/net.txt @@ -43,6 +43,13 @@ Values : 1 - enable the JIT 2 - enable the JIT and ask the compiler to emit traces on kernel log. +dev_weight +-------------- + +The maximum number of packets that kernel can handle on a NAPI interrupt, +it's a Per-CPU variable. +Default: 64 + rmem_default ------------ diff --git a/trunk/Documentation/usb/dwc3.txt b/trunk/Documentation/usb/dwc3.txt index 7b590edae145..1d02c01d1c7c 100644 --- a/trunk/Documentation/usb/dwc3.txt +++ b/trunk/Documentation/usb/dwc3.txt @@ -28,7 +28,7 @@ Please pick something while reading :) none - primary handler of the EP-interrupt - reads the event and tries to process it. Everything that requries + reads the event and tries to process it. Everything that requires sleeping is handed over to the Thread. The event is saved in an per-endpoint data-structure. We probably have to pay attention not to process events once we diff --git a/trunk/Documentation/usb/functionfs.txt b/trunk/Documentation/usb/functionfs.txt new file mode 100644 index 000000000000..eaaaea019fc7 --- /dev/null +++ b/trunk/Documentation/usb/functionfs.txt @@ -0,0 +1,67 @@ +*How FunctionFS works* + +From kernel point of view it is just a composite function with some +unique behaviour. It may be added to an USB configuration only after +the user space driver has registered by writing descriptors and +strings (the user space program has to provide the same information +that kernel level composite functions provide when they are added to +the configuration). + +This in particular means that the composite initialisation functions +may not be in init section (ie. may not use the __init tag). + +From user space point of view it is a file system which when +mounted provides an "ep0" file. User space driver need to +write descriptors and strings to that file. It does not need +to worry about endpoints, interfaces or strings numbers but +simply provide descriptors such as if the function was the +only one (endpoints and strings numbers starting from one and +interface numbers starting from zero). The FunctionFS changes +them as needed also handling situation when numbers differ in +different configurations. + +When descriptors and strings are written "ep#" files appear +(one for each declared endpoint) which handle communication on +a single endpoint. Again, FunctionFS takes care of the real +numbers and changing of the configuration (which means that +"ep1" file may be really mapped to (say) endpoint 3 (and when +configuration changes to (say) endpoint 2)). "ep0" is used +for receiving events and handling setup requests. + +When all files are closed the function disables itself. + +What I also want to mention is that the FunctionFS is designed in such +a way that it is possible to mount it several times so in the end +a gadget could use several FunctionFS functions. The idea is that +each FunctionFS instance is identified by the device name used +when mounting. + +One can imagine a gadget that has an Ethernet, MTP and HID interfaces +where the last two are implemented via FunctionFS. On user space +level it would look like this: + +$ insmod g_ffs.ko idVendor= iSerialNumber= functions=mtp,hid +$ mkdir /dev/ffs-mtp && mount -t functionfs mtp /dev/ffs-mtp +$ ( cd /dev/ffs-mtp && mtp-daemon ) & +$ mkdir /dev/ffs-hid && mount -t functionfs hid /dev/ffs-hid +$ ( cd /dev/ffs-hid && hid-daemon ) & + +On kernel level the gadget checks ffs_data->dev_name to identify +whether it's FunctionFS designed for MTP ("mtp") or HID ("hid"). + +If no "functions" module parameters is supplied, the driver accepts +just one function with any name. + +When "functions" module parameter is supplied, only functions +with listed names are accepted. In particular, if the "functions" +parameter's value is just a one-element list, then the behaviour +is similar to when there is no "functions" at all; however, +only a function with the specified name is accepted. + +The gadget is registered only after all the declared function +filesystems have been mounted and USB descriptors of all functions +have been written to their ep0's. + +Conversely, the gadget is unregistered after the first USB function +closes its endpoints. + diff --git a/trunk/Documentation/usb/wusb-cbaf b/trunk/Documentation/usb/wusb-cbaf index 426ddaaef96f..8b3d43efce90 100644 --- a/trunk/Documentation/usb/wusb-cbaf +++ b/trunk/Documentation/usb/wusb-cbaf @@ -36,7 +36,7 @@ COMMAND/ARGS are get-cdid DEVICE - Get the device ID associated to the HOST-CHDI we sent with + Get the device ID associated to the HOST-CHID we sent with 'set-chid'. We might not know about it. set-cc DEVICE diff --git a/trunk/Documentation/video4linux/README.cpia2 b/trunk/Documentation/video4linux/README.cpia2 index ce8213d28b67..38e742fd0df7 100644 --- a/trunk/Documentation/video4linux/README.cpia2 +++ b/trunk/Documentation/video4linux/README.cpia2 @@ -12,7 +12,7 @@ gqcam application to view this stream. The driver is implemented as two kernel modules. The cpia2 module contains the camera functions and the V4L interface. The cpia2_usb module contains usb specific functions. The main reason for this was the size of the -module was getting out of hand, so I separted them. It is not likely that +module was getting out of hand, so I separated them. It is not likely that there will be a parallel port version. FEATURES: diff --git a/trunk/Documentation/virtual/virtio-spec.txt b/trunk/Documentation/virtual/virtio-spec.txt index da094737e2f8..0d6ec85481cb 100644 --- a/trunk/Documentation/virtual/virtio-spec.txt +++ b/trunk/Documentation/virtual/virtio-spec.txt @@ -1,11 +1,11 @@ [Generated file: see http://ozlabs.org/~rusty/virtio-spec/] Virtio PCI Card Specification -v0.9.1 DRAFT +v0.9.5 DRAFT - -Rusty Russell IBM Corporation (Editor) +Rusty Russell IBM Corporation (Editor) -2011 August 1. +2012 May 7. Purpose and Description @@ -68,11 +68,11 @@ and consists of three parts: +-------------------+-----------------------------------+-----------+ -When the driver wants to send buffers to the device, it puts them -in one or more slots in the descriptor table, and writes the -descriptor indices into the available ring. It then notifies the -device. When the device has finished with the buffers, it writes -the descriptors into the used ring, and sends an interrupt. +When the driver wants to send a buffer to the device, it fills in +a slot in the descriptor table (or chains several together), and +writes the descriptor index into the available ring. It then +notifies the device. When the device has finished a buffer, it +writes the descriptor into the used ring, and sends an interrupt. Specification @@ -106,7 +106,13 @@ for informational purposes by the guest). +----------------------+--------------------+---------------+ | 6 | ioMemory | - | +----------------------+--------------------+---------------+ +| 7 | rpmsg | Appendix H | ++----------------------+--------------------+---------------+ +| 8 | SCSI host | Appendix I | ++----------------------+--------------------+---------------+ | 9 | 9P transport | - | ++----------------------+--------------------+---------------+ +| 10 | mac80211 wlan | - | +----------------------+--------------------+---------------+ @@ -127,7 +133,7 @@ Note that this is possible because while the virtio header is PCI the native endian of the guest (where such distinction is applicable). - Device Initialization Sequence + Device Initialization Sequence We start with an overview of device initialization, then expand on the details of the device and how each step is preformed. @@ -177,7 +183,10 @@ The virtio header looks as follows: If MSI-X is enabled for the device, two additional fields -immediately follow this header: +immediately follow this header:[footnote: +ie. once you enable MSI-X on the device, the other fields move. +If you turn it off again, they move back! +] +------------++----------------+--------+ @@ -191,20 +200,6 @@ immediately follow this header: +------------++----------------+--------+ -Finally, if feature bits (VIRTIO_F_FEATURES_HI) this is -immediately followed by two additional fields: - - -+------------++----------------------+---------------------- -| Bits || 32 | 32 -+------------++----------------------+---------------------- -| Read/Write || R | R+W -+------------++----------------------+---------------------- -| Purpose || Device | Guest -| || Features bits 32:63 | Features bits 32:63 -+------------++----------------------+---------------------- - - Immediately following these general headers, there may be device-specific headers: @@ -238,31 +233,25 @@ at least one bit should be set: may be a significant (or infinite) delay before setting this bit. - DRIVER_OK (3) Indicates that the driver is set up and ready to + DRIVER_OK (4) Indicates that the driver is set up and ready to drive the device. - FAILED (8) Indicates that something went wrong in the guest, + FAILED (128) Indicates that something went wrong in the guest, and it has given up on the device. This could be an internal error, or the driver didn't like the device for some reason, or even a fatal error during device operation. The device must be reset before attempting to re-initialize. - Feature Bits + Feature Bits -The least significant 31 bits of the first configuration field -indicates the features that the device supports (the high bit is -reserved, and will be used to indicate the presence of future -feature bits elsewhere). If more than 31 feature bits are -supported, the device indicates so by setting feature bit 31 (see -[cha:Reserved-Feature-Bits]). The bits are allocated as follows: +Thefirst configuration field indicates the features that the +device supports. The bits are allocated as follows: 0 to 23 Feature bits for the specific device type - 24 to 40 Feature bits reserved for extensions to the queue and + 24 to 32 Feature bits reserved for extensions to the queue and feature negotiation mechanisms - 41 to 63 Feature bits reserved for future extensions - For example, feature bit 0 for a network device (i.e. Subsystem Device ID 1) indicates that the device supports checksumming of packets. @@ -286,10 +275,6 @@ will not see that feature bit in the Device Features field and can go into backwards compatibility mode (or, for poor implementations, set the FAILED Device Status bit). -Access to feature bits 32 to 63 is enabled by Guest by setting -feature bit 31. If this bit is unset, Device must assume that all -feature bits > 31 are unset. - Configuration/Queue Vectors When MSI-X capability is present and enabled in the device @@ -324,7 +309,7 @@ success, the previously written value is returned, and on failure, NO_VECTOR is returned. If a mapping failure is detected, the driver can retry mapping with fewervectors, or disable MSI-X. - Virtqueue Configuration + Virtqueue Configuration As a device can have zero or more virtqueues for bulk data transport (for example, the network driver has two), the driver @@ -587,7 +572,7 @@ and Red Hat under the (3-clause) BSD license so that it can be freely used by all other projects, and is reproduced (with slight variation to remove Linux assumptions) in Appendix A. - Device Operation + Device Operation There are two parts to device operation: supplying new buffers to the device, and processing used buffers from the device. As an @@ -813,7 +798,7 @@ vring.used->ring[vq->last_seen_used%vsz]; } - Dealing With Configuration Changes + Dealing With Configuration Changes Some virtio PCI devices can change the device configuration state, as reflected in the virtio header in the PCI configuration @@ -1260,18 +1245,6 @@ Currently there are five device-independent feature bits defined: driver should ignore the used_event field; the device should ignore the avail_event field; the flags field is used - VIRTIO_F_BAD_FEATURE(30) This feature should never be - negotiated by the guest; doing so is an indication that the - guest is faulty[footnote: -An experimental virtio PCI driver contained in Linux version -2.6.25 had this problem, and this feature bit can be used to -detect it. -] - - VIRTIO_F_FEATURES_HIGH(31) This feature indicates that the - device supports feature bits 32:63. If unset, feature bits - 32:63 are unset. - Appendix C: Network Device The virtio network device is a virtual ethernet card, and is the @@ -1335,11 +1308,17 @@ were required. VIRTIO_NET_F_CTRL_VLAN (19) Control channel VLAN filtering. + VIRTIO_NET_F_GUEST_ANNOUNCE(21) Guest can send gratuitous + packets. + Device configuration layout Two configuration fields are currently defined. The mac address field always exists (though is only valid if VIRTIO_NET_F_MAC is set), and the status field - only exists if VIRTIO_NET_F_STATUS is set. Only one bit is - currently defined for the status field: VIRTIO_NET_S_LINK_UP. #define VIRTIO_NET_S_LINK_UP 1 + only exists if VIRTIO_NET_F_STATUS is set. Two read-only bits + are currently defined for the status field: + VIRTIO_NET_S_LINK_UP and VIRTIO_NET_S_ANNOUNCE. #define VIRTIO_NET_S_LINK_UP 1 + +#define VIRTIO_NET_S_ANNOUNCE 2 @@ -1377,12 +1356,19 @@ struct virtio_net_config { packets by negotating the VIRTIO_NET_F_CSUM feature. This “ checksum offload” is a common feature on modern network cards. - If that feature is negotiated, a driver can use TCP or UDP - segmentation offload by negotiating the VIRTIO_NET_F_HOST_TSO4 - (IPv4 TCP), VIRTIO_NET_F_HOST_TSO6 (IPv6 TCP) and - VIRTIO_NET_F_HOST_UFO (UDP fragmentation) features. It should - not send TCP packets requiring segmentation offload which have - the Explicit Congestion Notification bit set, unless the + If that feature is negotiated[footnote: +ie. VIRTIO_NET_F_HOST_TSO* and VIRTIO_NET_F_HOST_UFO are +dependent on VIRTIO_NET_F_CSUM; a dvice which offers the offload +features must offer the checksum feature, and a driver which +accepts the offload features must accept the checksum feature. +Similar logic applies to the VIRTIO_NET_F_GUEST_TSO4 features +depending on VIRTIO_NET_F_GUEST_CSUM. +], a driver can use TCP or UDP segmentation offload by + negotiating the VIRTIO_NET_F_HOST_TSO4 (IPv4 TCP), + VIRTIO_NET_F_HOST_TSO6 (IPv6 TCP) and VIRTIO_NET_F_HOST_UFO + (UDP fragmentation) features. It should not send TCP packets + requiring segmentation offload which have the Explicit + Congestion Notification bit set, unless the VIRTIO_NET_F_HOST_ECN feature is negotiated.[footnote: This is a common restriction in real, older network cards. ] @@ -1403,7 +1389,7 @@ segmentation, if both guests are amenable. Packets are transmitted by placing them in the transmitq, and buffers for incoming packets are placed in the receiveq. In each -case, the packet itself is preceded by a header: +case, the packet itself is preceeded by a header: struct virtio_net_hdr { @@ -1462,9 +1448,10 @@ It will have a 14 byte ethernet header and 20 byte IP header followed by the TCP header (with the TCP checksum field 16 bytes into that header). csum_start will be 14+20 = 34 (the TCP checksum includes the header), and csum_offset will be 16. The -value in the TCP checksum field will be the sum of the TCP pseudo -header, so that replacing it by the ones' complement checksum of -the TCP header and body will give the correct result. +value in the TCP checksum field should be initialized to the sum +of the TCP pseudo header, so that replacing it by the ones' +complement checksum of the TCP header and body will give the +correct result. ] If the driver negotiated @@ -1483,8 +1470,8 @@ Due to various bugs in implementations, this field is not useful as a guarantee of the transport header size. ] - gso_size is the size of the packet beyond that header (ie. - MSS). + gso_size is the maximum size of each packet beyond that header + (ie. MSS). If the driver negotiated the VIRTIO_NET_F_HOST_ECN feature, the VIRTIO_NET_HDR_GSO_ECN bit may be set in “gso_type” as well, @@ -1567,7 +1554,9 @@ Processing packet involves: If the VIRTIO_NET_F_GUEST_TSO4, TSO6 or UFO options were negotiated, then the “gso_type” may be something other than VIRTIO_NET_HDR_GSO_NONE, and the “gso_size” field indicates the - desired MSS (see [enu:If-the-driver]).Control Virtqueue + desired MSS (see [enu:If-the-driver]). + + Control Virtqueue The driver uses the control virtqueue (if VIRTIO_NET_F_VTRL_VQ is negotiated) to send commands to manipulate various features of @@ -1642,7 +1631,7 @@ struct virtio_net_ctrl_mac { The device can filter incoming packets by any number of destination MAC addresses.[footnote: -Since there are no guarantees, it can use a hash filter +Since there are no guarentees, it can use a hash filter orsilently switch to allmulti or promiscuous mode if it is given too many addresses. ] This table is set using the class VIRTIO_NET_CTRL_MAC and the @@ -1665,6 +1654,38 @@ can control a VLAN filter table in the device. Both the VIRTIO_NET_CTRL_VLAN_ADD and VIRTIO_NET_CTRL_VLAN_DEL command take a 16-bit VLAN id as the command-specific-data. + Gratuitous Packet Sending + +If the driver negotiates the VIRTIO_NET_F_GUEST_ANNOUNCE (depends +on VIRTIO_NET_F_CTRL_VQ), it can ask the guest to send gratuitous +packets; this is usually done after the guest has been physically +migrated, and needs to announce its presence on the new network +links. (As hypervisor does not have the knowledge of guest +network configuration (eg. tagged vlan) it is simplest to prod +the guest in this way). + +#define VIRTIO_NET_CTRL_ANNOUNCE 3 + + #define VIRTIO_NET_CTRL_ANNOUNCE_ACK 0 + +The Guest needs to check VIRTIO_NET_S_ANNOUNCE bit in status +field when it notices the changes of device configuration. The +command VIRTIO_NET_CTRL_ANNOUNCE_ACK is used to indicate that +driver has recevied the notification and device would clear the +VIRTIO_NET_S_ANNOUNCE bit in the status filed after it received +this command. + +Processing this notification involves: + + Sending the gratuitous packets or marking there are pending + gratuitous packets to be sent and letting deferred routine to + send them. + + Sending VIRTIO_NET_CTRL_ANNOUNCE_ACK command through control + vq. + + . + Appendix D: Block Device The virtio block device is a simple virtual block device (ie. @@ -1699,8 +1720,6 @@ device except where noted. VIRTIO_BLK_F_FLUSH (9) Cache flush command support. - - Device configuration layout The capacity of the device (expressed in 512-byte sectors) is always present. The availability of the others all depend on various feature bits @@ -1743,8 +1762,6 @@ device except where noted. If the VIRTIO_BLK_F_RO feature is set by the device, any write requests will fail. - - Device Operation The driver queues requests to the virtqueue, and they are used by @@ -1805,7 +1822,7 @@ the FLUSH and FLUSH_OUT types are equivalent, the device does not distinguish between them ]). If the device has VIRTIO_BLK_F_BARRIER feature the high bit (VIRTIO_BLK_T_BARRIER) indicates that this request acts as a -barrier and that all preceding requests must be complete before +barrier and that all preceeding requests must be complete before this one, and all following requests must not be started until this is complete. Note that a barrier does not flush caches in the underlying backend device in host, and thus does not serve as @@ -2118,7 +2135,7 @@ This is historical, and independent of the guest page size Otherwise, the guest may begin to re-use pages previously given to the balloon before the device has acknowledged their - withdrawal. [footnote: + withdrawl. [footnote: In this case, deflation advice is merely a courtesy ] @@ -2198,3 +2215,996 @@ as follows: VIRTIO_BALLOON_S_MEMTOT The total amount of memory available (in bytes). +Appendix H: Rpmsg: Remote Processor Messaging + +Virtio rpmsg devices represent remote processors on the system +which run in asymmetric multi-processing (AMP) configuration, and +which are usually used to offload cpu-intensive tasks from the +main application processor (a typical SoC methodology). + +Virtio is being used to communicate with those remote processors; +empty buffers are placed in one virtqueue for receiving messages, +and non-empty buffers, containing outbound messages, are enqueued +in a second virtqueue for transmission. + +Numerous communication channels can be multiplexed over those two +virtqueues, so different entities, running on the application and +remote processor, can directly communicate in a point-to-point +fashion. + + Configuration + + Subsystem Device ID 7 + + Virtqueues 0:receiveq. 1:transmitq. + + Feature bits + + VIRTIO_RPMSG_F_NS (0) Device sends (and capable of receiving) + name service messages announcing the creation (or + destruction) of a channel:/** + + * struct rpmsg_ns_msg - dynamic name service announcement +message + + * @name: name of remote service that is published + + * @addr: address of remote service that is published + + * @flags: indicates whether service is created or destroyed + + * + + * This message is sent across to publish a new service (or +announce + + * about its removal). When we receives these messages, an +appropriate + + * rpmsg channel (i.e device) is created/destroyed. + + */ + +struct rpmsg_ns_msgoon_config { + + char name[RPMSG_NAME_SIZE]; + + u32 addr; + + u32 flags; + +} __packed; + + + +/** + + * enum rpmsg_ns_flags - dynamic name service announcement flags + + * + + * @RPMSG_NS_CREATE: a new remote service was just created + + * @RPMSG_NS_DESTROY: a remote service was just destroyed + + */ + +enum rpmsg_ns_flags { + + RPMSG_NS_CREATE = 0, + + RPMSG_NS_DESTROY = 1, + +}; + + Device configuration layout + +At his point none currently defined. + + Device Initialization + + The initialization routine should identify the receive and + transmission virtqueues. + + The receive virtqueue should be filled with receive buffers. + + Device Operation + +Messages are transmitted by placing them in the transmitq, and +buffers for inbound messages are placed in the receiveq. In any +case, messages are always preceded by the following header: /** + + * struct rpmsg_hdr - common header for all rpmsg messages + + * @src: source address + + * @dst: destination address + + * @reserved: reserved for future use + + * @len: length of payload (in bytes) + + * @flags: message flags + + * @data: @len bytes of message payload data + + * + + * Every message sent(/received) on the rpmsg bus begins with +this header. + + */ + +struct rpmsg_hdr { + + u32 src; + + u32 dst; + + u32 reserved; + + u16 len; + + u16 flags; + + u8 data[0]; + +} __packed; + +Appendix I: SCSI Host Device + +The virtio SCSI host device groups together one or more virtual +logical units (such as disks), and allows communicating to them +using the SCSI protocol. An instance of the device represents a +SCSI host to which many targets and LUNs are attached. + +The virtio SCSI device services two kinds of requests: + + command requests for a logical unit; + + task management functions related to a logical unit, target or + command. + +The device is also able to send out notifications about added and +removed logical units. Together, these capabilities provide a +SCSI transport protocol that uses virtqueues as the transfer +medium. In the transport protocol, the virtio driver acts as the +initiator, while the virtio SCSI host provides one or more +targets that receive and process the requests. + + Configuration + + Subsystem Device ID 8 + + Virtqueues 0:controlq; 1:eventq; 2..n:request queues. + + Feature bits + + VIRTIO_SCSI_F_INOUT (0) A single request can include both + read-only and write-only data buffers. + + VIRTIO_SCSI_F_HOTPLUG (1) The host should enable + hot-plug/hot-unplug of new LUNs and targets on the SCSI bus. + + Device configuration layout All fields of this configuration + are always available. sense_size and cdb_size are writable by + the guest.struct virtio_scsi_config { + + u32 num_queues; + + u32 seg_max; + + u32 max_sectors; + + u32 cmd_per_lun; + + u32 event_info_size; + + u32 sense_size; + + u32 cdb_size; + + u16 max_channel; + + u16 max_target; + + u32 max_lun; + +}; + + num_queues is the total number of request virtqueues exposed by + the device. The driver is free to use only one request queue, + or it can use more to achieve better performance. + + seg_max is the maximum number of segments that can be in a + command. A bidirectional command can include seg_max input + segments and seg_max output segments. + + max_sectors is a hint to the guest about the maximum transfer + size it should use. + + cmd_per_lun is a hint to the guest about the maximum number of + linked commands it should send to one LUN. The actual value + to be used is the minimum of cmd_per_lun and the virtqueue + size. + + event_info_size is the maximum size that the device will fill + for buffers that the driver places in the eventq. The driver + should always put buffers at least of this size. It is + written by the device depending on the set of negotated + features. + + sense_size is the maximum size of the sense data that the + device will write. The default value is written by the device + and will always be 96, but the driver can modify it. It is + restored to the default when the device is reset. + + cdb_size is the maximum size of the CDB that the driver will + write. The default value is written by the device and will + always be 32, but the driver can likewise modify it. It is + restored to the default when the device is reset. + + max_channel, max_target and max_lun can be used by the driver + as hints to constrain scanning the logical units on the + host.h + + Device Initialization + +The initialization routine should first of all discover the +device's virtqueues. + +If the driver uses the eventq, it should then place at least a +buffer in the eventq. + +The driver can immediately issue requests (for example, INQUIRY +or REPORT LUNS) or task management functions (for example, I_T +RESET). + + Device Operation: request queues + +The driver queues requests to an arbitrary request queue, and +they are used by the device on that same queue. It is the +responsibility of the driver to ensure strict request ordering +for commands placed on different queues, because they will be +consumed with no order constraints. + +Requests have the following format: + +struct virtio_scsi_req_cmd { + + // Read-only + + u8 lun[8]; + + u64 id; + + u8 task_attr; + + u8 prio; + + u8 crn; + + char cdb[cdb_size]; + + char dataout[]; + + // Write-only part + + u32 sense_len; + + u32 residual; + + u16 status_qualifier; + + u8 status; + + u8 response; + + u8 sense[sense_size]; + + char datain[]; + +}; + + + +/* command-specific response values */ + +#define VIRTIO_SCSI_S_OK 0 + +#define VIRTIO_SCSI_S_OVERRUN 1 + +#define VIRTIO_SCSI_S_ABORTED 2 + +#define VIRTIO_SCSI_S_BAD_TARGET 3 + +#define VIRTIO_SCSI_S_RESET 4 + +#define VIRTIO_SCSI_S_BUSY 5 + +#define VIRTIO_SCSI_S_TRANSPORT_FAILURE 6 + +#define VIRTIO_SCSI_S_TARGET_FAILURE 7 + +#define VIRTIO_SCSI_S_NEXUS_FAILURE 8 + +#define VIRTIO_SCSI_S_FAILURE 9 + + + +/* task_attr */ + +#define VIRTIO_SCSI_S_SIMPLE 0 + +#define VIRTIO_SCSI_S_ORDERED 1 + +#define VIRTIO_SCSI_S_HEAD 2 + +#define VIRTIO_SCSI_S_ACA 3 + +The lun field addresses a target and logical unit in the +virtio-scsi device's SCSI domain. The only supported format for +the LUN field is: first byte set to 1, second byte set to target, +third and fourth byte representing a single level LUN structure, +followed by four zero bytes. With this representation, a +virtio-scsi device can serve up to 256 targets and 16384 LUNs per +target. + +The id field is the command identifier (“tag”). + +task_attr, prio and crn should be left to zero. task_attr defines +the task attribute as in the table above, but all task attributes +may be mapped to SIMPLE by the device; crn may also be provided +by clients, but is generally expected to be 0. The maximum CRN +value defined by the protocol is 255, since CRN is stored in an +8-bit integer. + +All of these fields are defined in SAM. They are always +read-only, as are the cdb and dataout field. The cdb_size is +taken from the configuration space. + +sense and subsequent fields are always write-only. The sense_len +field indicates the number of bytes actually written to the sense +buffer. The residual field indicates the residual size, +calculated as “data_length - number_of_transferred_bytes”, for +read or write operations. For bidirectional commands, the +number_of_transferred_bytes includes both read and written bytes. +A residual field that is less than the size of datain means that +the dataout field was processed entirely. A residual field that +exceeds the size of datain means that the dataout field was +processed partially and the datain field was not processed at +all. + +The status byte is written by the device to be the status code as +defined in SAM. + +The response byte is written by the device to be one of the +following: + + VIRTIO_SCSI_S_OK when the request was completed and the status + byte is filled with a SCSI status code (not necessarily + "GOOD"). + + VIRTIO_SCSI_S_OVERRUN if the content of the CDB requires + transferring more data than is available in the data buffers. + + VIRTIO_SCSI_S_ABORTED if the request was cancelled due to an + ABORT TASK or ABORT TASK SET task management function. + + VIRTIO_SCSI_S_BAD_TARGET if the request was never processed + because the target indicated by the lun field does not exist. + + VIRTIO_SCSI_S_RESET if the request was cancelled due to a bus + or device reset (including a task management function). + + VIRTIO_SCSI_S_TRANSPORT_FAILURE if the request failed due to a + problem in the connection between the host and the target + (severed link). + + VIRTIO_SCSI_S_TARGET_FAILURE if the target is suffering a + failure and the guest should not retry on other paths. + + VIRTIO_SCSI_S_NEXUS_FAILURE if the nexus is suffering a failure + but retrying on other paths might yield a different result. + + VIRTIO_SCSI_S_BUSY if the request failed but retrying on the + same path should work. + + VIRTIO_SCSI_S_FAILURE for other host or guest error. In + particular, if neither dataout nor datain is empty, and the + VIRTIO_SCSI_F_INOUT feature has not been negotiated, the + request will be immediately returned with a response equal to + VIRTIO_SCSI_S_FAILURE. + + Device Operation: controlq + +The controlq is used for other SCSI transport operations. +Requests have the following format: + +struct virtio_scsi_ctrl { + + u32 type; + + ... + + u8 response; + +}; + + + +/* response values valid for all commands */ + +#define VIRTIO_SCSI_S_OK 0 + +#define VIRTIO_SCSI_S_BAD_TARGET 3 + +#define VIRTIO_SCSI_S_BUSY 5 + +#define VIRTIO_SCSI_S_TRANSPORT_FAILURE 6 + +#define VIRTIO_SCSI_S_TARGET_FAILURE 7 + +#define VIRTIO_SCSI_S_NEXUS_FAILURE 8 + +#define VIRTIO_SCSI_S_FAILURE 9 + +#define VIRTIO_SCSI_S_INCORRECT_LUN 12 + +The type identifies the remaining fields. + +The following commands are defined: + + Task management function +#define VIRTIO_SCSI_T_TMF 0 + + + +#define VIRTIO_SCSI_T_TMF_ABORT_TASK 0 + +#define VIRTIO_SCSI_T_TMF_ABORT_TASK_SET 1 + +#define VIRTIO_SCSI_T_TMF_CLEAR_ACA 2 + +#define VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET 3 + +#define VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET 4 + +#define VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET 5 + +#define VIRTIO_SCSI_T_TMF_QUERY_TASK 6 + +#define VIRTIO_SCSI_T_TMF_QUERY_TASK_SET 7 + + + +struct virtio_scsi_ctrl_tmf + +{ + + // Read-only part + + u32 type; + + u32 subtype; + + u8 lun[8]; + + u64 id; + + // Write-only part + + u8 response; + +} + + + +/* command-specific response values */ + +#define VIRTIO_SCSI_S_FUNCTION_COMPLETE 0 + +#define VIRTIO_SCSI_S_FUNCTION_SUCCEEDED 10 + +#define VIRTIO_SCSI_S_FUNCTION_REJECTED 11 + + The type is VIRTIO_SCSI_T_TMF; the subtype field defines. All + fields except response are filled by the driver. The subtype + field must always be specified and identifies the requested + task management function. + + Other fields may be irrelevant for the requested TMF; if so, + they are ignored but they should still be present. The lun + field is in the same format specified for request queues; the + single level LUN is ignored when the task management function + addresses a whole I_T nexus. When relevant, the value of the id + field is matched against the id values passed on the requestq. + + The outcome of the task management function is written by the + device in the response field. The command-specific response + values map 1-to-1 with those defined in SAM. + + Asynchronous notification query +#define VIRTIO_SCSI_T_AN_QUERY 1 + + + +struct virtio_scsi_ctrl_an { + + // Read-only part + + u32 type; + + u8 lun[8]; + + u32 event_requested; + + // Write-only part + + u32 event_actual; + + u8 response; + +} + + + +#define VIRTIO_SCSI_EVT_ASYNC_OPERATIONAL_CHANGE 2 + +#define VIRTIO_SCSI_EVT_ASYNC_POWER_MGMT 4 + +#define VIRTIO_SCSI_EVT_ASYNC_EXTERNAL_REQUEST 8 + +#define VIRTIO_SCSI_EVT_ASYNC_MEDIA_CHANGE 16 + +#define VIRTIO_SCSI_EVT_ASYNC_MULTI_HOST 32 + +#define VIRTIO_SCSI_EVT_ASYNC_DEVICE_BUSY 64 + + By sending this command, the driver asks the device which + events the given LUN can report, as described in paragraphs 6.6 + and A.6 of the SCSI MMC specification. The driver writes the + events it is interested in into the event_requested; the device + responds by writing the events that it supports into + event_actual. + + The type is VIRTIO_SCSI_T_AN_QUERY. The lun and event_requested + fields are written by the driver. The event_actual and response + fields are written by the device. + + No command-specific values are defined for the response byte. + + Asynchronous notification subscription +#define VIRTIO_SCSI_T_AN_SUBSCRIBE 2 + + + +struct virtio_scsi_ctrl_an { + + // Read-only part + + u32 type; + + u8 lun[8]; + + u32 event_requested; + + // Write-only part + + u32 event_actual; + + u8 response; + +} + + By sending this command, the driver asks the specified LUN to + report events for its physical interface, again as described in + the SCSI MMC specification. The driver writes the events it is + interested in into the event_requested; the device responds by + writing the events that it supports into event_actual. + + Event types are the same as for the asynchronous notification + query message. + + The type is VIRTIO_SCSI_T_AN_SUBSCRIBE. The lun and + event_requested fields are written by the driver. The + event_actual and response fields are written by the device. + + No command-specific values are defined for the response byte. + + Device Operation: eventq + +The eventq is used by the device to report information on logical +units that are attached to it. The driver should always leave a +few buffers ready in the eventq. In general, the device will not +queue events to cope with an empty eventq, and will end up +dropping events if it finds no buffer ready. However, when +reporting events for many LUNs (e.g. when a whole target +disappears), the device can throttle events to avoid dropping +them. For this reason, placing 10-15 buffers on the event queue +should be enough. + +Buffers are placed in the eventq and filled by the device when +interesting events occur. The buffers should be strictly +write-only (device-filled) and the size of the buffers should be +at least the value given in the device's configuration +information. + +Buffers returned by the device on the eventq will be referred to +as "events" in the rest of this section. Events have the +following format: + +#define VIRTIO_SCSI_T_EVENTS_MISSED 0x80000000 + + + +struct virtio_scsi_event { + + // Write-only part + + u32 event; + + ... + +} + +If bit 31 is set in the event field, the device failed to report +an event due to missing buffers. In this case, the driver should +poll the logical units for unit attention conditions, and/or do +whatever form of bus scan is appropriate for the guest operating +system. + +Other data that the device writes to the buffer depends on the +contents of the event field. The following events are defined: + + No event +#define VIRTIO_SCSI_T_NO_EVENT 0 + + This event is fired in the following cases: + + When the device detects in the eventq a buffer that is shorter + than what is indicated in the configuration field, it might + use it immediately and put this dummy value in the event + field. A well-written driver will never observe this + situation. + + When events are dropped, the device may signal this event as + soon as the drivers makes a buffer available, in order to + request action from the driver. In this case, of course, this + event will be reported with the VIRTIO_SCSI_T_EVENTS_MISSED + flag. + + Transport reset +#define VIRTIO_SCSI_T_TRANSPORT_RESET 1 + + + +struct virtio_scsi_event_reset { + + // Write-only part + + u32 event; + + u8 lun[8]; + + u32 reason; + +} + + + +#define VIRTIO_SCSI_EVT_RESET_HARD 0 + +#define VIRTIO_SCSI_EVT_RESET_RESCAN 1 + +#define VIRTIO_SCSI_EVT_RESET_REMOVED 2 + + By sending this event, the device signals that a logical unit + on a target has been reset, including the case of a new device + appearing or disappearing on the bus.The device fills in all + fields. The event field is set to + VIRTIO_SCSI_T_TRANSPORT_RESET. The lun field addresses a + logical unit in the SCSI host. + + The reason value is one of the three #define values appearing + above: + + VIRTIO_SCSI_EVT_RESET_REMOVED (“LUN/target removed”) is used if + the target or logical unit is no longer able to receive + commands. + + VIRTIO_SCSI_EVT_RESET_HARD (“LUN hard reset”) is used if the + logical unit has been reset, but is still present. + + VIRTIO_SCSI_EVT_RESET_RESCAN (“rescan LUN/target”) is used if a + target or logical unit has just appeared on the device. + + The “removed” and “rescan” events, when sent for LUN 0, may + apply to the entire target. After receiving them the driver + should ask the initiator to rescan the target, in order to + detect the case when an entire target has appeared or + disappeared. These two events will never be reported unless the + VIRTIO_SCSI_F_HOTPLUG feature was negotiated between the host + and the guest. + + Events will also be reported via sense codes (this obviously + does not apply to newly appeared buses or targets, since the + application has never discovered them): + + “LUN/target removed” maps to sense key ILLEGAL REQUEST, asc + 0x25, ascq 0x00 (LOGICAL UNIT NOT SUPPORTED) + + “LUN hard reset” maps to sense key UNIT ATTENTION, asc 0x29 + (POWER ON, RESET OR BUS DEVICE RESET OCCURRED) + + “rescan LUN/target” maps to sense key UNIT ATTENTION, asc 0x3f, + ascq 0x0e (REPORTED LUNS DATA HAS CHANGED) + + The preferred way to detect transport reset is always to use + events, because sense codes are only seen by the driver when it + sends a SCSI command to the logical unit or target. However, in + case events are dropped, the initiator will still be able to + synchronize with the actual state of the controller if the + driver asks the initiator to rescan of the SCSI bus. During the + rescan, the initiator will be able to observe the above sense + codes, and it will process them as if it the driver had + received the equivalent event. + + Asynchronous notification +#define VIRTIO_SCSI_T_ASYNC_NOTIFY 2 + + + +struct virtio_scsi_event_an { + + // Write-only part + + u32 event; + + u8 lun[8]; + + u32 reason; + +} + + By sending this event, the device signals that an asynchronous + event was fired from a physical interface. + + All fields are written by the device. The event field is set to + VIRTIO_SCSI_T_ASYNC_NOTIFY. The lun field addresses a logical + unit in the SCSI host. The reason field is a subset of the + events that the driver has subscribed to via the "Asynchronous + notification subscription" command. + + When dropped events are reported, the driver should poll for + asynchronous events manually using SCSI commands. + +Appendix X: virtio-mmio + +Virtual environments without PCI support (a common situation in +embedded devices models) might use simple memory mapped device (“ +virtio-mmio”) instead of the PCI device. + +The memory mapped virtio device behaviour is based on the PCI +device specification. Therefore most of operations like device +initialization, queues configuration and buffer transfers are +nearly identical. Existing differences are described in the +following sections. + + Device Initialization + +Instead of using the PCI IO space for virtio header, the “ +virtio-mmio” device provides a set of memory mapped control +registers, all 32 bits wide, followed by device-specific +configuration space. The following list presents their layout: + + Offset from the device base address | Direction | Name + Description + + 0x000 | R | MagicValue + “virt” string. + + 0x004 | R | Version + Device version number. Currently must be 1. + + 0x008 | R | DeviceID + Virtio Subsystem Device ID (ie. 1 for network card). + + 0x00c | R | VendorID + Virtio Subsystem Vendor ID. + + 0x010 | R | HostFeatures + Flags representing features the device supports. + Reading from this register returns 32 consecutive flag bits, + first bit depending on the last value written to + HostFeaturesSel register. Access to this register returns bits HostFeaturesSel*32 + + to (HostFeaturesSel*32)+31 +, eg. feature bits 0 to 31 if + HostFeaturesSel is set to 0 and features bits 32 to 63 if + HostFeaturesSel is set to 1. Also see [sub:Feature-Bits] + + 0x014 | W | HostFeaturesSel + Device (Host) features word selection. + Writing to this register selects a set of 32 device feature bits + accessible by reading from HostFeatures register. Device driver + must write a value to the HostFeaturesSel register before + reading from the HostFeatures register. + + 0x020 | W | GuestFeatures + Flags representing device features understood and activated by + the driver. + Writing to this register sets 32 consecutive flag bits, first + bit depending on the last value written to GuestFeaturesSel + register. Access to this register sets bits GuestFeaturesSel*32 + + to (GuestFeaturesSel*32)+31 +, eg. feature bits 0 to 31 if + GuestFeaturesSel is set to 0 and features bits 32 to 63 if + GuestFeaturesSel is set to 1. Also see [sub:Feature-Bits] + + 0x024 | W | GuestFeaturesSel + Activated (Guest) features word selection. + Writing to this register selects a set of 32 activated feature + bits accessible by writing to the GuestFeatures register. + Device driver must write a value to the GuestFeaturesSel + register before writing to the GuestFeatures register. + + 0x028 | W | GuestPageSize + Guest page size. + Device driver must write the guest page size in bytes to the + register during initialization, before any queues are used. + This value must be a power of 2 and is used by the Host to + calculate Guest address of the first queue page (see QueuePFN). + + 0x030 | W | QueueSel + Virtual queue index (first queue is 0). + Writing to this register selects the virtual queue that the + following operations on QueueNum, QueueAlign and QueuePFN apply + to. + + 0x034 | R | QueueNumMax + Maximum virtual queue size. + Reading from the register returns the maximum size of the queue + the Host is ready to process or zero (0x0) if the queue is not + available. This applies to the queue selected by writing to + QueueSel and is allowed only when QueuePFN is set to zero + (0x0), so when the queue is not actively used. + + 0x038 | W | QueueNum + Virtual queue size. + Queue size is a number of elements in the queue, therefore size + of the descriptor table and both available and used rings. + Writing to this register notifies the Host what size of the + queue the Guest will use. This applies to the queue selected by + writing to QueueSel. + + 0x03c | W | QueueAlign + Used Ring alignment in the virtual queue. + Writing to this register notifies the Host about alignment + boundary of the Used Ring in bytes. This value must be a power + of 2 and applies to the queue selected by writing to QueueSel. + + 0x040 | RW | QueuePFN + Guest physical page number of the virtual queue. + Writing to this register notifies the host about location of the + virtual queue in the Guest's physical address space. This value + is the index number of a page starting with the queue + Descriptor Table. Value zero (0x0) means physical address zero + (0x00000000) and is illegal. When the Guest stops using the + queue it must write zero (0x0) to this register. + Reading from this register returns the currently used page + number of the queue, therefore a value other than zero (0x0) + means that the queue is in use. + Both read and write accesses apply to the queue selected by + writing to QueueSel. + + 0x050 | W | QueueNotify + Queue notifier. + Writing a queue index to this register notifies the Host that + there are new buffers to process in the queue. + + 0x60 | R | InterruptStatus +Interrupt status. +Reading from this register returns a bit mask of interrupts + asserted by the device. An interrupt is asserted if the + corresponding bit is set, ie. equals one (1). + + Bit 0 | Used Ring Update +This interrupt is asserted when the Host has updated the Used + Ring in at least one of the active virtual queues. + + Bit 1 | Configuration change +This interrupt is asserted when configuration of the device has + changed. + + 0x064 | W | InterruptACK + Interrupt acknowledge. + Writing to this register notifies the Host that the Guest + finished handling interrupts. Set bits in the value clear the + corresponding bits of the InterruptStatus register. + + 0x070 | RW | Status + Device status. + Reading from this register returns the current device status + flags. + Writing non-zero values to this register sets the status flags, + indicating the Guest progress. Writing zero (0x0) to this + register triggers a device reset. + Also see [sub:Device-Initialization-Sequence] + + 0x100+ | RW | Config + Device-specific configuration space starts at an offset 0x100 + and is accessed with byte alignment. Its meaning and size + depends on the device and the driver. + +Virtual queue size is a number of elements in the queue, +therefore size of the descriptor table and both available and +used rings. + +The endianness of the registers follows the native endianness of +the Guest. Writing to registers described as “R” and reading from +registers described as “W” is not permitted and can cause +undefined behavior. + +The device initialization is performed as described in [sub:Device-Initialization-Sequence] + with one exception: the Guest must notify the Host about its +page size, writing the size in bytes to GuestPageSize register +before the initialization is finished. + +The memory mapped virtio devices generate single interrupt only, +therefore no special configuration is required. + + Virtqueue Configuration + +The virtual queue configuration is performed in a similar way to +the one described in [sec:Virtqueue-Configuration] with a few +additional operations: + + Select the queue writing its index (first queue is 0) to the + QueueSel register. + + Check if the queue is not already in use: read QueuePFN + register, returned value should be zero (0x0). + + Read maximum queue size (number of elements) from the + QueueNumMax register. If the returned value is zero (0x0) the + queue is not available. + + Allocate and zero the queue pages in contiguous virtual memory, + aligning the Used Ring to an optimal boundary (usually page + size). Size of the allocated queue may be smaller than or equal + to the maximum size returned by the Host. + + Notify the Host about the queue size by writing the size to + QueueNum register. + + Notify the Host about the used alignment by writing its value + in bytes to QueueAlign register. + + Write the physical number of the first page of the queue to the + QueuePFN register. + +The queue and the device are ready to begin normal operations +now. + + Device Operation + +The memory mapped virtio device behaves in the same way as +described in [sec:Device-Operation], with the following +exceptions: + + The device is notified about new buffers available in a queue + by writing the queue index to register QueueNum instead of the + virtio header in PCI I/O space ([sub:Notifying-The-Device]). + + The memory mapped virtio device is using single, dedicated + interrupt signal, which is raised when at least one of the + interrupts described in the InterruptStatus register + description is asserted. After receiving an interrupt, the + driver must read the InterruptStatus register to check what + caused the interrupt (see the register description). After the + interrupt is handled, the driver must acknowledge it by writing + a bit mask corresponding to the serviced interrupt to the + InterruptACK register. + diff --git a/trunk/drivers/staging/vme/vme_api.txt b/trunk/Documentation/vme_api.txt similarity index 100% rename from trunk/drivers/staging/vme/vme_api.txt rename to trunk/Documentation/vme_api.txt diff --git a/trunk/Documentation/zh_CN/magic-number.txt b/trunk/Documentation/zh_CN/magic-number.txt index f606ba8598cf..4263022f5002 100644 --- a/trunk/Documentation/zh_CN/magic-number.txt +++ b/trunk/Documentation/zh_CN/magic-number.txt @@ -160,7 +160,7 @@ QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry drivers/scsi/arm/queue.c HTB_CMAGIC 0xFEFAFEF1 htb_class net/sched/sch_htb.c NMI_MAGIC 0x48414d4d455201 nmi_s arch/mips/include/asm/sn/nmi.h -请注意,在声音记忆管理中仍然有每一些被定义的驱动魔术值。查看include/sound/sndmagic.h来获取他们完整的列表信息。很多OSS声音驱动拥有自己从声卡PCI ID构建的魔术值-他们也没有被列在这里。 +请注意,在声音记忆管理中仍然有一些特殊的为每个驱动定义的魔术值。查看include/sound/sndmagic.h来获取他们完整的列表信息。很多OSS声音驱动拥有自己从声卡PCI ID构建的魔术值-他们也没有被列在这里。 IrDA子系统也使用了大量的自己的魔术值,查看include/net/irda/irda.h来获取他们完整的信息。 diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index 85018f365ac7..9c293bf340b1 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -640,13 +640,6 @@ S: Maintained F: drivers/amba/ F: include/linux/amba/bus.h -ARM/ADI ROADRUNNER MACHINE SUPPORT -M: Lennert Buytenhek -L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -S: Maintained -F: arch/arm/mach-ixp23xx/ -F: arch/arm/mach-ixp23xx/include/mach/ - ARM/ADS SPHERE MACHINE SUPPORT M: Lennert Buytenhek L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -746,7 +739,10 @@ M: Barry Song L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: arch/arm/mach-prima2/ -F: drivers/dma/sirf-dma* +F: drivers/dma/sirf-dma.c +F: drivers/i2c/busses/i2c-sirf.c +F: drivers/pinctrl/pinctrl-sirf.c +F: drivers/spi/spi-sirf.c ARM/EBSA110 MACHINE SUPPORT M: Russell King @@ -859,21 +855,11 @@ M: Dan Williams L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained -ARM/INTEL IXP2000 ARM ARCHITECTURE -M: Lennert Buytenhek -L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -S: Maintained - ARM/INTEL IXDP2850 MACHINE SUPPORT M: Lennert Buytenhek L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained -ARM/INTEL IXP23XX ARM ARCHITECTURE -M: Lennert Buytenhek -L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -S: Maintained - ARM/INTEL IXP4XX ARM ARCHITECTURE M: Imre Kaloz M: Krzysztof Halasa @@ -908,11 +894,12 @@ ARM/MAGICIAN MACHINE SUPPORT M: Philipp Zabel S: Maintained -ARM/Marvell Loki/Kirkwood/MV78xx0/Orion SOC support -M: Lennert Buytenhek -M: Nicolas Pitre +ARM/Marvell Dove/Kirkwood/MV78xx0/Orion SOC support +M: Jason Cooper +M: Andrew Lunn L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -S: Odd Fixes +S: Maintained +F: arch/arm/mach-dove/ F: arch/arm/mach-kirkwood/ F: arch/arm/mach-mv78xx0/ F: arch/arm/mach-orion5x/ @@ -1331,6 +1318,21 @@ M: Nicolas Ferre S: Supported F: drivers/tty/serial/atmel_serial.c +ATMEL DMA DRIVER +M: Nicolas Ferre +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +S: Supported +F: drivers/dma/at_hdmac.c +F: drivers/dma/at_hdmac_regs.h +F: arch/arm/mach-at91/include/mach/at_hdmac.h + +ATMEL ISI DRIVER +M: Josh Wu +L: linux-media@vger.kernel.org +S: Supported +F: drivers/media/video/atmel-isi.c +F: include/media/atmel-isi.h + ATMEL LCDFB DRIVER M: Nicolas Ferre L: linux-fbdev@vger.kernel.org @@ -1348,10 +1350,22 @@ M: Nicolas Ferre S: Supported F: drivers/spi/spi-atmel.* +ATMEL Timer Counter (TC) AND CLOCKSOURCE DRIVERS +M: Nicolas Ferre +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +S: Supported +F: drivers/misc/atmel_tclib.c +F: drivers/clocksource/tcb_clksrc.c + +ATMEL TSADCC DRIVER +M: Josh Wu +L: linux-input@vger.kernel.org +S: Supported +F: drivers/input/touchscreen/atmel_tsadcc.c + ATMEL USBA UDC DRIVER M: Nicolas Ferre L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -W: http://avr32linux.org/twiki/bin/view/Main/AtmelUsbDeviceDriver S: Supported F: drivers/usb/gadget/atmel_usba_udc.* @@ -1431,6 +1445,7 @@ F: include/linux/backlight.h BATMAN ADVANCED M: Marek Lindner M: Simon Wunderlich +M: Antonio Quartulli L: b.a.t.m.a.n@lists.open-mesh.org W: http://www.open-mesh.org/ S: Maintained @@ -1598,6 +1613,7 @@ F: include/linux/bcma/ BROCADE BFA FC SCSI DRIVER M: Jing Huang +M: Krishna C Gudipati L: linux-scsi@vger.kernel.org S: Supported F: drivers/scsi/bfa/ @@ -1731,6 +1747,7 @@ S: Supported F: include/linux/capability.h F: security/capability.c F: security/commoncap.c +F: kernel/capability.c CELL BROADBAND ENGINE ARCHITECTURE M: Arnd Bergmann @@ -1809,6 +1826,12 @@ L: linux-kernel@zh-kernel.org (moderated for non-subscribers) S: Maintained F: Documentation/zh_CN/ +CHIPIDEA USB HIGH SPEED DUAL ROLE CONTROLLER +M: Alexander Shishkin +L: linux-usb@vger.kernel.org +S: Maintained +F: drivers/usb/chipidea/ + CISCO VIC ETHERNET NIC DRIVER M: Christian Benvenuti M: Roopa Prabhu @@ -2889,7 +2912,7 @@ S: Maintained F: arch/frv/ FUJITSU LAPTOP EXTRAS -M: Jonathan Woithe +M: Jonathan Woithe L: platform-driver-x86@vger.kernel.org S: Maintained F: drivers/platform/x86/fujitsu-laptop.c @@ -3383,6 +3406,7 @@ IIO SUBSYSTEM AND DRIVERS M: Jonathan Cameron L: linux-iio@vger.kernel.org S: Maintained +F: drivers/iio/ F: drivers/staging/iio/ IKANOS/ADI EAGLE ADSL USB DRIVER @@ -3518,12 +3542,6 @@ M: Deepak Saxena S: Maintained F: drivers/char/hw_random/ixp4xx-rng.c -INTEL IXP2000 ETHERNET DRIVER -M: Lennert Buytenhek -L: netdev@vger.kernel.org -S: Maintained -F: drivers/net/ethernet/xscale/ixp2000/ - INTEL ETHERNET DRIVERS (e100/e1000/e1000e/igb/igbvf/ixgb/ixgbe/ixgbevf) M: Jeff Kirsher M: Jesse Brandeburg @@ -3608,6 +3626,14 @@ S: Supported W: http://wireless.kernel.org/en/users/Drivers/iwmc3200wifi F: drivers/net/wireless/iwmc3200wifi/ +INTEL MANAGEMENT ENGINE (mei) +M: Tomas Winkler +L: linux-kernel@vger.kernel.org +S: Supported +F: include/linux/mei.h +F: drivers/misc/mei/* +F: Documentation/mei/* + IOC3 ETHERNET DRIVER M: Ralf Baechle L: linux-mips@linux-mips.org @@ -3633,7 +3659,7 @@ S: Maintained F: drivers/net/ethernet/icplus/ipg.* IPATH DRIVER -M: Mike Marciniszyn +M: Mike Marciniszyn L: linux-rdma@vger.kernel.org S: Maintained F: drivers/infiniband/hw/ipath/ @@ -5133,19 +5159,13 @@ F: Documentation/powerpc/eeh-pci-error-recovery.txt PCI SUBSYSTEM M: Bjorn Helgaas L: linux-pci@vger.kernel.org -Q: http://patchwork.kernel.org/project/linux-pci/list/ -T: git git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci.git +Q: http://patchwork.ozlabs.org/project/linux-pci/list/ +T: git git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/linux.git S: Supported F: Documentation/PCI/ F: drivers/pci/ F: include/linux/pci* -PCI HOTPLUG -M: Bjorn Helgaas -L: linux-pci@vger.kernel.org -S: Supported -F: drivers/pci/hotplug - PCMCIA SUBSYSTEM P: Linux PCMCIA Team L: linux-pcmcia@lists.infradead.org @@ -5208,7 +5228,7 @@ S: Maintained F: include/linux/personality.h PHONET PROTOCOL -M: Remi Denis-Courmont +M: Remi Denis-Courmont S: Supported F: Documentation/networking/phonet.txt F: include/linux/phonet.h @@ -5235,6 +5255,14 @@ M: Linus Walleij S: Maintained F: drivers/pinctrl/ +PIN CONTROLLER - ST SPEAR +M: Viresh Kumar +L: spear-devel@list.st.com +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +W: http://www.st.com/spear +S: Maintained +F: driver/pinctrl/spear/ + PKTCDVD DRIVER M: Peter Osterlund S: Maintained @@ -5458,7 +5486,7 @@ L: rtc-linux@googlegroups.com S: Maintained QIB DRIVER -M: Mike Marciniszyn +M: Mike Marciniszyn L: linux-rdma@vger.kernel.org S: Supported F: drivers/infiniband/hw/qib/ @@ -5608,14 +5636,13 @@ F: net/rds/ READ-COPY UPDATE (RCU) M: Dipankar Sarma M: "Paul E. McKenney" -W: http://www.rdrop.com/users/paulmck/rclock/ +W: http://www.rdrop.com/users/paulmck/RCU/ S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git F: Documentation/RCU/ +X: Documentation/RCU/torture.txt F: include/linux/rcu* -F: include/linux/srcu* F: kernel/rcu* -F: kernel/srcu* X: kernel/rcutorture.c REAL TIME CLOCK (RTC) SUBSYSTEM @@ -5961,7 +5988,7 @@ SECURITY SUBSYSTEM M: James Morris L: linux-security-module@vger.kernel.org (suggested Cc:) T: git git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security.git -W: http://security.wiki.kernel.org/ +W: http://kernsec.org/ S: Supported F: security/ @@ -6132,6 +6159,15 @@ S: Maintained F: include/linux/sl?b*.h F: mm/sl?b.c +SLEEPABLE READ-COPY UPDATE (SRCU) +M: Lai Jiangshan +M: "Paul E. McKenney" +W: http://www.rdrop.com/users/paulmck/RCU/ +S: Supported +T: git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git +F: include/linux/srcu* +F: kernel/srcu* + SMC91x ETHERNET DRIVER M: Nicolas Pitre S: Odd Fixes @@ -6331,21 +6367,6 @@ F: arch/arm/mach-spear*/clock.c F: arch/arm/plat-spear/clock.c F: arch/arm/plat-spear/include/plat/clock.h -SPEAR PAD MULTIPLEXING SUPPORT -M: Viresh Kumar -L: spear-devel@list.st.com -L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -W: http://www.st.com/spear -S: Maintained -F: arch/arm/plat-spear/include/plat/padmux.h -F: arch/arm/plat-spear/padmux.c -F: arch/arm/mach-spear*/spear*xx.c -F: arch/arm/mach-spear*/include/mach/generic.h -F: arch/arm/mach-spear3xx/spear3*0.c -F: arch/arm/mach-spear3xx/spear3*0_evb.c -F: arch/arm/mach-spear6xx/spear600.c -F: arch/arm/mach-spear6xx/spear600_evb.c - SPI SUBSYSTEM M: Grant Likely L: spi-devel-general@lists.sourceforge.net @@ -6676,6 +6697,16 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Maintained F: sound/soc/codecs/twl4030* +TI WILINK WIRELESS DRIVERS +M: Luciano Coelho +L: linux-wireless@vger.kernel.org +W: http://wireless.kernel.org/en/users/Drivers/wl12xx +W: http://wireless.kernel.org/en/users/Drivers/wl1251 +T: git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git +S: Maintained +F: drivers/net/wireless/ti/ +F: include/linux/wl12xx.h + TIPC NETWORK LAYER M: Jon Maloy M: Allan Stephens @@ -6883,6 +6914,14 @@ F: Documentation/cdrom/ F: drivers/cdrom/cdrom.c F: include/linux/cdrom.h +UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER +M: Vinayak Holikatti +M: Santosh Y +L: linux-scsi@vger.kernel.org +S: Supported +F: Documentation/scsi/ufs.txt +F: drivers/scsi/ufs/ + UNSORTED BLOCK IMAGES (UBI) M: Artem Bityutskiy W: http://www.linux-mtd.infradead.org/ @@ -7029,6 +7068,14 @@ W: http://pegasus2.sourceforge.net/ S: Maintained F: drivers/net/usb/pegasus.* +USB PHY LAYER +M: Felipe Balbi +L: linux-usb@vger.kernel.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git +S: Maintained +F: drivers/usb/phy/ +F: drivers/usb/otg/ + USB PRINTER DRIVER (usblp) M: Pete Zaitcev L: linux-usb@vger.kernel.org @@ -7312,6 +7359,18 @@ S: Maintained F: drivers/vlynq/vlynq.c F: include/linux/vlynq.h +VME SUBSYSTEM +M: Martyn Welch +M: Manohar Vanga +M: Greg Kroah-Hartman +L: devel@driverdev.osuosl.org +S: Maintained +T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git +F: Documentation/vme_api.txt +F: drivers/staging/vme/ +F: drivers/vme/ +F: include/linux/vme* + VMWARE VMXNET3 ETHERNET DRIVER M: Shreyas Bhatewara M: "VMware, Inc." @@ -7432,23 +7491,6 @@ M: Miloslav Trmac S: Maintained F: drivers/input/misc/wistron_btns.c -WL1251 WIRELESS DRIVER -M: Luciano Coelho -L: linux-wireless@vger.kernel.org -W: http://wireless.kernel.org/en/users/Drivers/wl1251 -T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git -S: Maintained -F: drivers/net/wireless/wl1251/* - -WL1271 WIRELESS DRIVER -M: Luciano Coelho -L: linux-wireless@vger.kernel.org -W: http://wireless.kernel.org/en/users/Drivers/wl12xx -T: git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git -S: Maintained -F: drivers/net/wireless/wl12xx/ -F: include/linux/wl12xx.h - WL3501 WIRELESS PCMCIA CARD DRIVER M: Arnaldo Carvalho de Melo L: linux-wireless@vger.kernel.org diff --git a/trunk/Makefile b/trunk/Makefile index 48bd1f50dcc3..546515cd07f3 100644 --- a/trunk/Makefile +++ b/trunk/Makefile @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 4 SUBLEVEL = 0 -EXTRAVERSION = -rc7 +EXTRAVERSION = NAME = Saber-toothed Squirrel # *DOCUMENTATION* @@ -400,8 +400,10 @@ export MODVERDIR := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_ve # Files to ignore in find ... statements -RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS -o -name .pc -o -name .hg -o -name .git \) -prune -o -export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn --exclude CVS --exclude .pc --exclude .hg --exclude .git +RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS \ + -o -name .pc -o -name .hg -o -name .git \) -prune -o +export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn \ + --exclude CVS --exclude .pc --exclude .hg --exclude .git # =========================================================================== # Rules shared between *config targets and build targets @@ -442,7 +444,7 @@ asm-generic: no-dot-config-targets := clean mrproper distclean \ cscope gtags TAGS tags help %docs check% coccicheck \ - include/linux/version.h headers_% archheaders \ + include/linux/version.h headers_% archheaders archscripts \ kernelversion %src-pkg config-targets := 0 @@ -966,7 +968,7 @@ prepare3: include/config/kernel.release ifneq ($(KBUILD_SRC),) @$(kecho) ' Using $(srctree) as source for kernel' $(Q)if [ -f $(srctree)/.config -o -d $(srctree)/include/config ]; then \ - echo " $(srctree) is not clean, please run 'make mrproper'";\ + echo " $(srctree) is not clean, please run 'make mrproper'"; \ echo " in the '$(srctree)' directory.";\ /bin/false; \ fi; @@ -979,7 +981,7 @@ prepare1: prepare2 include/linux/version.h include/generated/utsrelease.h \ include/config/auto.conf $(cmd_crmodverdir) -archprepare: archheaders prepare1 scripts_basic +archprepare: archheaders archscripts prepare1 scripts_basic prepare0: archprepare FORCE $(Q)$(MAKE) $(build)=. @@ -1003,8 +1005,8 @@ define filechk_utsrelease.h endef define filechk_version.h - (echo \#define LINUX_VERSION_CODE $(shell \ - expr $(VERSION) \* 65536 + 0$(PATCHLEVEL) \* 256 + 0$(SUBLEVEL)); \ + (echo \#define LINUX_VERSION_CODE $(shell \ + expr $(VERSION) \* 65536 + 0$(PATCHLEVEL) \* 256 + 0$(SUBLEVEL)); \ echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))';) endef @@ -1049,8 +1051,11 @@ hdr-dst = $(if $(KBUILD_HEADERS), dst=include/asm-$(hdr-arch), dst=include/asm) PHONY += archheaders archheaders: +PHONY += archscripts +archscripts: + PHONY += __headers -__headers: include/linux/version.h scripts_basic asm-generic archheaders FORCE +__headers: include/linux/version.h scripts_basic asm-generic archheaders archscripts FORCE $(Q)$(MAKE) $(build)=scripts build_unifdef PHONY += headers_install_all @@ -1468,6 +1473,13 @@ kernelrelease: kernelversion: @echo $(KERNELVERSION) +# Clear a bunch of variables before executing the submake +tools/: FORCE + $(Q)$(MAKE) LDFLAGS= MAKEFLAGS= -C $(src)/tools/ + +tools/%: FORCE + $(Q)$(MAKE) LDFLAGS= MAKEFLAGS= -C $(src)/tools/ $* + # Single targets # --------------------------------------------------------------------------- # Single targets are compatible with: diff --git a/trunk/README b/trunk/README index 0d5a7ddbe3ee..9beaed0ed620 100644 --- a/trunk/README +++ b/trunk/README @@ -1,4 +1,4 @@ - Linux kernel release 3.x + Linux kernel release 3.x These are the release notes for Linux version 3. Read them carefully, as they tell you what this is all about, explain how to install the @@ -62,13 +62,13 @@ INSTALLING the kernel source: directory where you have permissions (eg. your home directory) and unpack it: - gzip -cd linux-3.X.tar.gz | tar xvf - + gzip -cd linux-3.X.tar.gz | tar xvf - or - bzip2 -dc linux-3.X.tar.bz2 | tar xvf - + bzip2 -dc linux-3.X.tar.bz2 | tar xvf - - Replace "XX" with the version number of the latest kernel. + Replace "X" with the version number of the latest kernel. Do NOT use the /usr/src/linux area! This area has a (usually incomplete) set of kernel headers that are used by the library header @@ -78,49 +78,43 @@ INSTALLING the kernel source: - You can also upgrade between 3.x releases by patching. Patches are distributed in the traditional gzip and the newer bzip2 format. To install by patching, get all the newer patch files, enter the - top level directory of the kernel source (linux-3.x) and execute: + top level directory of the kernel source (linux-3.X) and execute: - gzip -cd ../patch-3.x.gz | patch -p1 + gzip -cd ../patch-3.x.gz | patch -p1 or - bzip2 -dc ../patch-3.x.bz2 | patch -p1 - (repeat xx for all versions bigger than the version of your current - source tree, _in_order_) and you should be ok. You may want to remove - the backup files (xxx~ or xxx.orig), and make sure that there are no - failed patches (xxx# or xxx.rej). If there are, either you or me has - made a mistake. + bzip2 -dc ../patch-3.x.bz2 | patch -p1 + + Replace "x" for all versions bigger than the version "X" of your current + source tree, _in_order_, and you should be ok. You may want to remove + the backup files (some-file-name~ or some-file-name.orig), and make sure + that there are no failed patches (some-file-name# or some-file-name.rej). + If there are, either you or I have made a mistake. Unlike patches for the 3.x kernels, patches for the 3.x.y kernels (also known as the -stable kernels) are not incremental but instead apply - directly to the base 3.x kernel. Please read - Documentation/applying-patches.txt for more information. + directly to the base 3.x kernel. For example, if your base kernel is 3.0 + and you want to apply the 3.0.3 patch, you must not first apply the 3.0.1 + and 3.0.2 patches. Similarly, if you are running kernel version 3.0.2 and + want to jump to 3.0.3, you must first reverse the 3.0.2 patch (that is, + patch -R) _before_ applying the 3.0.3 patch. You can read more on this in + Documentation/applying-patches.txt Alternatively, the script patch-kernel can be used to automate this process. It determines the current kernel version and applies any patches found. - linux/scripts/patch-kernel linux + linux/scripts/patch-kernel linux The first argument in the command above is the location of the kernel source. Patches are applied from the current directory, but an alternative directory can be specified as the second argument. - - If you are upgrading between releases using the stable series patches - (for example, patch-3.x.y), note that these "dot-releases" are - not incremental and must be applied to the 3.x base tree. For - example, if your base kernel is 3.0 and you want to apply the - 3.0.3 patch, you do not and indeed must not first apply the - 3.0.1 and 3.0.2 patches. Similarly, if you are running kernel - version 3.0.2 and want to jump to 3.0.3, you must first - reverse the 3.0.2 patch (that is, patch -R) _before_ applying - the 3.0.3 patch. - You can read more on this in Documentation/applying-patches.txt - - Make sure you have no stale .o files and dependencies lying around: - cd linux - make mrproper + cd linux + make mrproper You should now have the sources correctly installed. @@ -137,21 +131,23 @@ SOFTWARE REQUIREMENTS BUILD directory for the kernel: - When compiling the kernel all output files will per default be + When compiling the kernel, all output files will per default be stored together with the kernel source code. Using the option "make O=output/dir" allow you to specify an alternate place for the output files (including .config). Example: - kernel source code: /usr/src/linux-3.N - build directory: /home/name/build/kernel - To configure and build the kernel use: - cd /usr/src/linux-3.N - make O=/home/name/build/kernel menuconfig - make O=/home/name/build/kernel - sudo make O=/home/name/build/kernel modules_install install + kernel source code: /usr/src/linux-3.X + build directory: /home/name/build/kernel + + To configure and build the kernel, use: - Please note: If the 'O=output/dir' option is used then it must be + cd /usr/src/linux-3.X + make O=/home/name/build/kernel menuconfig + make O=/home/name/build/kernel + sudo make O=/home/name/build/kernel modules_install install + + Please note: If the 'O=output/dir' option is used, then it must be used for all invocations of make. CONFIGURING the kernel: @@ -163,61 +159,78 @@ CONFIGURING the kernel: new version with minimal work, use "make oldconfig", which will only ask you for the answers to new questions. - - Alternate configuration commands are: - "make config" Plain text interface. - "make menuconfig" Text based color menus, radiolists & dialogs. - "make nconfig" Enhanced text based color menus. - "make xconfig" X windows (Qt) based configuration tool. - "make gconfig" X windows (Gtk) based configuration tool. - "make oldconfig" Default all questions based on the contents of - your existing ./.config file and asking about - new config symbols. - "make silentoldconfig" - Like above, but avoids cluttering the screen - with questions already answered. - Additionally updates the dependencies. - "make defconfig" Create a ./.config file by using the default - symbol values from either arch/$ARCH/defconfig - or arch/$ARCH/configs/${PLATFORM}_defconfig, - depending on the architecture. - "make ${PLATFORM}_defconfig" - Create a ./.config file by using the default - symbol values from - arch/$ARCH/configs/${PLATFORM}_defconfig. - Use "make help" to get a list of all available - platforms of your architecture. - "make allyesconfig" - Create a ./.config file by setting symbol - values to 'y' as much as possible. - "make allmodconfig" - Create a ./.config file by setting symbol - values to 'm' as much as possible. - "make allnoconfig" Create a ./.config file by setting symbol - values to 'n' as much as possible. - "make randconfig" Create a ./.config file by setting symbol - values to random values. + - Alternative configuration commands are: + + "make config" Plain text interface. + + "make menuconfig" Text based color menus, radiolists & dialogs. + + "make nconfig" Enhanced text based color menus. + + "make xconfig" X windows (Qt) based configuration tool. + + "make gconfig" X windows (Gtk) based configuration tool. + + "make oldconfig" Default all questions based on the contents of + your existing ./.config file and asking about + new config symbols. + + "make silentoldconfig" + Like above, but avoids cluttering the screen + with questions already answered. + Additionally updates the dependencies. + + "make defconfig" Create a ./.config file by using the default + symbol values from either arch/$ARCH/defconfig + or arch/$ARCH/configs/${PLATFORM}_defconfig, + depending on the architecture. + + "make ${PLATFORM}_defconfig" + Create a ./.config file by using the default + symbol values from + arch/$ARCH/configs/${PLATFORM}_defconfig. + Use "make help" to get a list of all available + platforms of your architecture. + + "make allyesconfig" + Create a ./.config file by setting symbol + values to 'y' as much as possible. + + "make allmodconfig" + Create a ./.config file by setting symbol + values to 'm' as much as possible. + + "make allnoconfig" Create a ./.config file by setting symbol + values to 'n' as much as possible. + + "make randconfig" Create a ./.config file by setting symbol + values to random values. You can find more information on using the Linux kernel config tools in Documentation/kbuild/kconfig.txt. - NOTES on "make config": - - having unnecessary drivers will make the kernel bigger, and can - under some circumstances lead to problems: probing for a - nonexistent controller card may confuse your other controllers - - compiling the kernel with "Processor type" set higher than 386 - will result in a kernel that does NOT work on a 386. The - kernel will detect this on bootup, and give up. - - A kernel with math-emulation compiled in will still use the - coprocessor if one is present: the math emulation will just - never get used in that case. The kernel will be slightly larger, - but will work on different machines regardless of whether they - have a math coprocessor or not. - - the "kernel hacking" configuration details usually result in a - bigger or slower kernel (or both), and can even make the kernel - less stable by configuring some routines to actively try to - break bad code to find kernel problems (kmalloc()). Thus you - should probably answer 'n' to the questions for - "development", "experimental", or "debugging" features. + - NOTES on "make config": + + - Having unnecessary drivers will make the kernel bigger, and can + under some circumstances lead to problems: probing for a + nonexistent controller card may confuse your other controllers + + - Compiling the kernel with "Processor type" set higher than 386 + will result in a kernel that does NOT work on a 386. The + kernel will detect this on bootup, and give up. + + - A kernel with math-emulation compiled in will still use the + coprocessor if one is present: the math emulation will just + never get used in that case. The kernel will be slightly larger, + but will work on different machines regardless of whether they + have a math coprocessor or not. + + - The "kernel hacking" configuration details usually result in a + bigger or slower kernel (or both), and can even make the kernel + less stable by configuring some routines to actively try to + break bad code to find kernel problems (kmalloc()). Thus you + should probably answer 'n' to the questions for "development", + "experimental", or "debugging" features. COMPILING the kernel: @@ -230,7 +243,7 @@ COMPILING the kernel: possible to do "make install" if you have lilo installed to suit the kernel makefiles, but you may want to check your particular lilo setup first. - To do the actual install you have to be root, but none of the normal + To do the actual install, you have to be root, but none of the normal build should require that. Don't take the name of root in vain. - If you configured any of the parts of the kernel as `modules', you @@ -238,13 +251,13 @@ COMPILING the kernel: - Verbose kernel compile/build output: - Normally the kernel build system runs in a fairly quiet mode (but not + Normally, the kernel build system runs in a fairly quiet mode (but not totally silent). However, sometimes you or other kernel developers need to see compile, link, or other commands exactly as they are executed. For this, use "verbose" build mode. This is done by inserting "V=1" in the "make" command. E.g.: - make V=1 all + make V=1 all To have the build system also tell the reason for the rebuild of each target, use "V=2". The default is "V=0". @@ -256,6 +269,7 @@ COMPILING the kernel: are installing a new kernel with the same version number as your working kernel, make a backup of your modules directory before you do a "make modules_install". + Alternatively, before compiling, use the kernel config option "LOCALVERSION" to append a unique suffix to the regular kernel version. LOCALVERSION can be set in the "General Setup" menu. @@ -267,7 +281,7 @@ COMPILING the kernel: - Booting a kernel directly from a floppy without the assistance of a bootloader such as LILO, is no longer supported. - If you boot Linux from the hard drive, chances are you use LILO which + If you boot Linux from the hard drive, chances are you use LILO, which uses the kernel image as specified in the file /etc/lilo.conf. The kernel image file is usually /vmlinuz, /boot/vmlinuz, /bzImage or /boot/bzImage. To use the new kernel, save a copy of the old image @@ -306,21 +320,21 @@ IF SOMETHING GOES WRONG: - If the bug results in a message like - unable to handle kernel paging request at address C0000010 - Oops: 0002 - EIP: 0010:XXXXXXXX - eax: xxxxxxxx ebx: xxxxxxxx ecx: xxxxxxxx edx: xxxxxxxx - esi: xxxxxxxx edi: xxxxxxxx ebp: xxxxxxxx - ds: xxxx es: xxxx fs: xxxx gs: xxxx - Pid: xx, process nr: xx - xx xx xx xx xx xx xx xx xx xx + unable to handle kernel paging request at address C0000010 + Oops: 0002 + EIP: 0010:XXXXXXXX + eax: xxxxxxxx ebx: xxxxxxxx ecx: xxxxxxxx edx: xxxxxxxx + esi: xxxxxxxx edi: xxxxxxxx ebp: xxxxxxxx + ds: xxxx es: xxxx fs: xxxx gs: xxxx + Pid: xx, process nr: xx + xx xx xx xx xx xx xx xx xx xx or similar kernel debugging information on your screen or in your system log, please duplicate it *exactly*. The dump may look incomprehensible to you, but it does contain information that may help debugging the problem. The text above the dump is also important: it tells something about why the kernel dumped code (in - the above example it's due to a bad kernel pointer). More information + the above example, it's due to a bad kernel pointer). More information on making sense of the dump is in Documentation/oops-tracing.txt - If you compiled the kernel with CONFIG_KALLSYMS you can send the dump @@ -328,7 +342,7 @@ IF SOMETHING GOES WRONG: sense of the dump (but compiling with CONFIG_KALLSYMS is usually preferred). This utility can be downloaded from ftp://ftp..kernel.org/pub/linux/utils/kernel/ksymoops/ . - Alternately you can do the dump lookup by hand: + Alternatively, you can do the dump lookup by hand: - In debugging dumps like the above, it helps enormously if you can look up what the EIP value means. The hex value as such doesn't help @@ -342,7 +356,7 @@ IF SOMETHING GOES WRONG: the file 'linux/vmlinux'. To extract the namelist and match it against the EIP from the kernel crash, do: - nm vmlinux | sort | less + nm vmlinux | sort | less This will give you a list of kernel addresses sorted in ascending order, from which it is simple to find the function that contains the @@ -361,7 +375,7 @@ IF SOMETHING GOES WRONG: kernel image or similar), telling me as much about your setup as possible will help. Please read the REPORTING-BUGS document for details. - - Alternately, you can use gdb on a running kernel. (read-only; i.e. you + - Alternatively, you can use gdb on a running kernel. (read-only; i.e. you cannot change values or set break points.) To do this, first compile the kernel with -g; edit arch/i386/Makefile appropriately, then do a "make clean". You'll also need to enable CONFIG_PROC_FS (via "make config"). diff --git a/trunk/arch/Kconfig b/trunk/arch/Kconfig index 684eb5af439d..1f9461b9cc89 100644 --- a/trunk/arch/Kconfig +++ b/trunk/arch/Kconfig @@ -145,6 +145,21 @@ config HAVE_DMA_ATTRS config USE_GENERIC_SMP_HELPERS bool +config GENERIC_SMP_IDLE_THREAD + bool + +# Select if arch init_task initializer is different to init/init_task.c +config ARCH_INIT_TASK + bool + +# Select if arch has its private alloc_task_struct() function +config ARCH_TASK_STRUCT_ALLOCATOR + bool + +# Select if arch has its private alloc_thread_info() function +config ARCH_THREAD_INFO_ALLOCATOR + bool + config HAVE_REGS_AND_STACK_ACCESS_API bool help @@ -216,4 +231,27 @@ config HAVE_CMPXCHG_DOUBLE config ARCH_WANT_OLD_COMPAT_IPC bool +config HAVE_ARCH_SECCOMP_FILTER + bool + help + An arch should select this symbol if it provides all of these things: + - syscall_get_arch() + - syscall_get_arguments() + - syscall_rollback() + - syscall_set_return_value() + - SIGSYS siginfo_t support + - secure_computing is called from a ptrace_event()-safe context + - secure_computing return value is checked and a return value of -1 + results in the system call being skipped immediately. + +config SECCOMP_FILTER + def_bool y + depends on HAVE_ARCH_SECCOMP_FILTER && SECCOMP && NET + help + Enable tasks to build secure computing environments defined + in terms of Berkeley Packet Filter programs which implement + task-defined system call filtering polices. + + See Documentation/prctl/seccomp_filter.txt for details. + source "kernel/gcov/Kconfig" diff --git a/trunk/arch/alpha/Kconfig b/trunk/arch/alpha/Kconfig index 22e58a99f38b..0893f023efb8 100644 --- a/trunk/arch/alpha/Kconfig +++ b/trunk/arch/alpha/Kconfig @@ -15,6 +15,7 @@ config ALPHA select GENERIC_IRQ_SHOW select ARCH_WANT_OPTIONAL_GPIOLIB select ARCH_HAVE_NMI_SAFE_CMPXCHG + select GENERIC_SMP_IDLE_THREAD help The Alpha is a 64-bit general-purpose processor designed and marketed by the Digital Equipment Corporation of blessed memory, diff --git a/trunk/arch/alpha/kernel/Makefile b/trunk/arch/alpha/kernel/Makefile index 7a6d908bb865..84ec46b38f7d 100644 --- a/trunk/arch/alpha/kernel/Makefile +++ b/trunk/arch/alpha/kernel/Makefile @@ -6,7 +6,7 @@ extra-y := head.o vmlinux.lds asflags-y := $(KBUILD_CFLAGS) ccflags-y := -Wno-sign-compare -obj-y := entry.o traps.o process.o init_task.o osf_sys.o irq.o \ +obj-y := entry.o traps.o process.o osf_sys.o irq.o \ irq_alpha.o signal.o setup.o ptrace.o time.o \ alpha_ksyms.o systbls.o err_common.o io.o diff --git a/trunk/arch/alpha/kernel/init_task.c b/trunk/arch/alpha/kernel/init_task.c deleted file mode 100644 index 6f80ca4f9766..000000000000 --- a/trunk/arch/alpha/kernel/init_task.c +++ /dev/null @@ -1,17 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - - -static struct signal_struct init_signals = INIT_SIGNALS(init_signals); -static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); -struct task_struct init_task = INIT_TASK(init_task); -EXPORT_SYMBOL(init_task); - -union thread_union init_thread_union __init_task_data = - { INIT_THREAD_INFO(init_task) }; diff --git a/trunk/arch/alpha/kernel/pci_iommu.c b/trunk/arch/alpha/kernel/pci_iommu.c index cd634795aa9c..3f844d26d2c7 100644 --- a/trunk/arch/alpha/kernel/pci_iommu.c +++ b/trunk/arch/alpha/kernel/pci_iommu.c @@ -236,7 +236,7 @@ static int pci_dac_dma_supported(struct pci_dev *dev, u64 mask) ok = 0; /* If both conditions above are met, we are fine. */ - DBGA("pci_dac_dma_supported %s from %p\n", + DBGA("pci_dac_dma_supported %s from %pf\n", ok ? "yes" : "no", __builtin_return_address(0)); return ok; @@ -268,7 +268,7 @@ pci_map_single_1(struct pci_dev *pdev, void *cpu_addr, size_t size, && paddr + size <= __direct_map_size) { ret = paddr + __direct_map_base; - DBGA2("pci_map_single: [%p,%zx] -> direct %llx from %p\n", + DBGA2("pci_map_single: [%p,%zx] -> direct %llx from %pf\n", cpu_addr, size, ret, __builtin_return_address(0)); return ret; @@ -279,7 +279,7 @@ pci_map_single_1(struct pci_dev *pdev, void *cpu_addr, size_t size, if (dac_allowed) { ret = paddr + alpha_mv.pci_dac_offset; - DBGA2("pci_map_single: [%p,%zx] -> DAC %llx from %p\n", + DBGA2("pci_map_single: [%p,%zx] -> DAC %llx from %pf\n", cpu_addr, size, ret, __builtin_return_address(0)); return ret; @@ -316,7 +316,7 @@ pci_map_single_1(struct pci_dev *pdev, void *cpu_addr, size_t size, ret = arena->dma_base + dma_ofs * PAGE_SIZE; ret += (unsigned long)cpu_addr & ~PAGE_MASK; - DBGA2("pci_map_single: [%p,%zx] np %ld -> sg %llx from %p\n", + DBGA2("pci_map_single: [%p,%zx] np %ld -> sg %llx from %pf\n", cpu_addr, size, npages, ret, __builtin_return_address(0)); return ret; @@ -385,14 +385,14 @@ static void alpha_pci_unmap_page(struct device *dev, dma_addr_t dma_addr, && dma_addr < __direct_map_base + __direct_map_size) { /* Nothing to do. */ - DBGA2("pci_unmap_single: direct [%llx,%zx] from %p\n", + DBGA2("pci_unmap_single: direct [%llx,%zx] from %pf\n", dma_addr, size, __builtin_return_address(0)); return; } if (dma_addr > 0xffffffff) { - DBGA2("pci64_unmap_single: DAC [%llx,%zx] from %p\n", + DBGA2("pci64_unmap_single: DAC [%llx,%zx] from %pf\n", dma_addr, size, __builtin_return_address(0)); return; } @@ -424,7 +424,7 @@ static void alpha_pci_unmap_page(struct device *dev, dma_addr_t dma_addr, spin_unlock_irqrestore(&arena->lock, flags); - DBGA2("pci_unmap_single: sg [%llx,%zx] np %ld from %p\n", + DBGA2("pci_unmap_single: sg [%llx,%zx] np %ld from %pf\n", dma_addr, size, npages, __builtin_return_address(0)); } @@ -447,7 +447,7 @@ static void *alpha_pci_alloc_coherent(struct device *dev, size_t size, cpu_addr = (void *)__get_free_pages(gfp, order); if (! cpu_addr) { printk(KERN_INFO "pci_alloc_consistent: " - "get_free_pages failed from %p\n", + "get_free_pages failed from %pf\n", __builtin_return_address(0)); /* ??? Really atomic allocation? Otherwise we could play with vmalloc and sg if we can't find contiguous memory. */ @@ -466,7 +466,7 @@ static void *alpha_pci_alloc_coherent(struct device *dev, size_t size, goto try_again; } - DBGA2("pci_alloc_consistent: %zx -> [%p,%llx] from %p\n", + DBGA2("pci_alloc_consistent: %zx -> [%p,%llx] from %pf\n", size, cpu_addr, *dma_addrp, __builtin_return_address(0)); return cpu_addr; @@ -486,7 +486,7 @@ static void alpha_pci_free_coherent(struct device *dev, size_t size, pci_unmap_single(pdev, dma_addr, size, PCI_DMA_BIDIRECTIONAL); free_pages((unsigned long)cpu_addr, get_order(size)); - DBGA2("pci_free_consistent: [%llx,%zx] from %p\n", + DBGA2("pci_free_consistent: [%llx,%zx] from %pf\n", dma_addr, size, __builtin_return_address(0)); } diff --git a/trunk/arch/alpha/kernel/perf_event.c b/trunk/arch/alpha/kernel/perf_event.c index 0dae252f7a33..d821b17047e0 100644 --- a/trunk/arch/alpha/kernel/perf_event.c +++ b/trunk/arch/alpha/kernel/perf_event.c @@ -824,7 +824,6 @@ static void alpha_perf_event_irq_handler(unsigned long la_ptr, idx = la_ptr; - perf_sample_data_init(&data, 0); for (j = 0; j < cpuc->n_events; j++) { if (cpuc->current_idx[j] == idx) break; @@ -848,7 +847,7 @@ static void alpha_perf_event_irq_handler(unsigned long la_ptr, hwc = &event->hw; alpha_perf_event_update(event, hwc, idx, alpha_pmu->pmc_max_period[idx]+1); - data.period = event->hw.last_period; + perf_sample_data_init(&data, 0, hwc->last_period); if (alpha_perf_event_set_period(event, hwc, idx)) { if (perf_event_overflow(event, &data, regs)) { diff --git a/trunk/arch/alpha/kernel/smp.c b/trunk/arch/alpha/kernel/smp.c index 50d438db1f6b..35ddc02bfa4a 100644 --- a/trunk/arch/alpha/kernel/smp.c +++ b/trunk/arch/alpha/kernel/smp.c @@ -357,24 +357,10 @@ secondary_cpu_start(int cpuid, struct task_struct *idle) * Bring one cpu online. */ static int __cpuinit -smp_boot_one_cpu(int cpuid) +smp_boot_one_cpu(int cpuid, struct task_struct *idle) { - struct task_struct *idle; unsigned long timeout; - /* Cook up an idler for this guy. Note that the address we - give to kernel_thread is irrelevant -- it's going to start - where HWRPB.CPU_restart says to start. But this gets all - the other task-y sort of data structures set up like we - wish. We can't use kernel_thread since we must avoid - rescheduling the child. */ - idle = fork_idle(cpuid); - if (IS_ERR(idle)) - panic("failed fork for CPU %d", cpuid); - - DBGS(("smp_boot_one_cpu: CPU %d state 0x%lx flags 0x%lx\n", - cpuid, idle->state, idle->flags)); - /* Signal the secondary to wait a moment. */ smp_secondary_alive = -1; @@ -487,9 +473,9 @@ smp_prepare_boot_cpu(void) } int __cpuinit -__cpu_up(unsigned int cpu) +__cpu_up(unsigned int cpu, struct task_struct *tidle) { - smp_boot_one_cpu(cpu); + smp_boot_one_cpu(cpu, tidle); return cpu_online(cpu) ? 0 : -ENOSYS; } diff --git a/trunk/arch/arm/Kconfig b/trunk/arch/arm/Kconfig index 36586dba6fa6..76edcfe8b56f 100644 --- a/trunk/arch/arm/Kconfig +++ b/trunk/arch/arm/Kconfig @@ -11,6 +11,7 @@ config ARM select HAVE_OPROFILE if (HAVE_PERF_EVENTS) select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL select HAVE_ARCH_KGDB + select HAVE_ARCH_TRACEHOOK select HAVE_KPROBES if !XIP_KERNEL select HAVE_KRETPROBES if (HAVE_KPROBES) select HAVE_FUNCTION_TRACER if (!XIP_KERNEL) @@ -30,10 +31,15 @@ config ARM select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7)) select HAVE_C_RECORDMCOUNT select HAVE_GENERIC_HARDIRQS + select HARDIRQS_SW_RESEND + select GENERIC_IRQ_PROBE select GENERIC_IRQ_SHOW + select GENERIC_IRQ_PROBE + select HARDIRQS_SW_RESEND select CPU_PM if (SUSPEND || CPU_IDLE) select GENERIC_PCI_IOMAP - select HAVE_BPF_JIT if NET + select HAVE_BPF_JIT + select GENERIC_SMP_IDLE_THREAD help The ARM series is a line of low-power-consumption RISC chip designs licensed by ARM Ltd and targeted at embedded applications and @@ -126,14 +132,6 @@ config TRACE_IRQFLAGS_SUPPORT bool default y -config HARDIRQS_SW_RESEND - bool - default y - -config GENERIC_IRQ_PROBE - bool - default y - config GENERIC_LOCKBREAK bool default y @@ -159,9 +157,6 @@ config ARCH_HAS_CPUFREQ and that the relevant menu configurations are displayed for it. -config ARCH_HAS_CPU_IDLE_WAIT - def_bool y - config GENERIC_HWEIGHT bool default y @@ -280,6 +275,7 @@ config ARCH_INTEGRATOR select NEED_MACH_IO_H select NEED_MACH_MEMORY_H select SPARSE_IRQ + select MULTI_IRQ_HANDLER help Support for ARM's Integrator platform. @@ -340,8 +336,8 @@ config ARCH_AT91 select IRQ_DOMAIN select NEED_MACH_IO_H if PCCARD help - This enables support for systems based on the Atmel AT91RM9200, - AT91SAM9 processors. + This enables support for systems based on Atmel + AT91RM9200 and AT91SAM9* processors. config ARCH_BCMRING bool "Broadcom BCMRING" @@ -373,12 +369,12 @@ config ARCH_HIGHBANK Support for the Calxeda Highbank SoC based boards. config ARCH_CLPS711X - bool "Cirrus Logic CLPS711x/EP721x-based" + bool "Cirrus Logic CLPS711x/EP721x/EP731x-based" select CPU_ARM720T select ARCH_USES_GETTIMEOFFSET select NEED_MACH_MEMORY_H help - Support for Cirrus Logic 711x/721x based boards. + Support for Cirrus Logic 711x/721x/731x based boards. config ARCH_CNS3XXX bool "Cavium Networks CNS3XXX family" @@ -407,6 +403,8 @@ config ARCH_PRIMA2 select CLKDEV_LOOKUP select GENERIC_IRQ_CHIP select MIGHT_HAVE_CACHE_L2X0 + select PINCTRL + select PINCTRL_SIRF select USE_OF select ZONE_DMA help @@ -469,6 +467,7 @@ config ARCH_MXS select CLKDEV_LOOKUP select CLKSRC_MMIO select HAVE_CLK_PREPARE + select PINCTRL help Support for Freescale MXS-based family of processors @@ -528,28 +527,6 @@ config ARCH_IOP33X help Support for Intel's IOP33X (XScale) family of processors. -config ARCH_IXP23XX - bool "IXP23XX-based" - depends on MMU - select CPU_XSC3 - select PCI - select ARCH_USES_GETTIMEOFFSET - select NEED_MACH_IO_H - select NEED_MACH_MEMORY_H - help - Support for Intel's IXP23xx (XScale) family of processors. - -config ARCH_IXP2000 - bool "IXP2400/2800-based" - depends on MMU - select CPU_XSCALE - select PCI - select ARCH_USES_GETTIMEOFFSET - select NEED_MACH_IO_H - select NEED_MACH_MEMORY_H - help - Support for Intel's IXP2400/2800 (XScale) family of processors. - config ARCH_IXP4XX bool "IXP4xx-based" depends on MMU @@ -597,6 +574,7 @@ config ARCH_LPC32XX select USB_ARCH_HAS_OHCI select CLKDEV_LOOKUP select GENERIC_CLOCKEVENTS + select USE_OF help Support for the NXP LPC32XX family of processors @@ -632,7 +610,7 @@ config ARCH_MMP select CLKDEV_LOOKUP select GENERIC_CLOCKEVENTS select GPIO_PXA - select TICK_ONESHOT + select IRQ_DOMAIN select PLAT_PXA select SPARSE_IRQ select GENERIC_ALLOCATOR @@ -716,7 +694,6 @@ config ARCH_PXA select ARCH_REQUIRE_GPIOLIB select GENERIC_CLOCKEVENTS select GPIO_PXA - select TICK_ONESHOT select PLAT_PXA select SPARSE_IRQ select AUTO_ZRELADDR @@ -783,7 +760,6 @@ config ARCH_SA1100 select CPU_FREQ select GENERIC_CLOCKEVENTS select CLKDEV_LOOKUP - select TICK_ONESHOT select ARCH_REQUIRE_GPIOLIB select HAVE_IDE select NEED_MACH_MEMORY_H @@ -946,6 +922,7 @@ config ARCH_NOMADIK select CPU_ARM926T select CLKDEV_LOOKUP select GENERIC_CLOCKEVENTS + select PINCTRL select MIGHT_HAVE_CACHE_L2X0 select ARCH_REQUIRE_GPIOLIB help @@ -1046,10 +1023,6 @@ source "arch/arm/mach-iop13xx/Kconfig" source "arch/arm/mach-ixp4xx/Kconfig" -source "arch/arm/mach-ixp2000/Kconfig" - -source "arch/arm/mach-ixp23xx/Kconfig" - source "arch/arm/mach-kirkwood/Kconfig" source "arch/arm/mach-ks8695/Kconfig" @@ -1552,10 +1525,15 @@ config HAVE_ARM_SCU help This option enables support for the ARM system coherency unit +config ARM_ARCH_TIMER + bool "Architected timer support" + depends on CPU_V7 + help + This option enables support for the ARM architected timer + config HAVE_ARM_TWD bool depends on SMP - select TICK_ONESHOT help This options enables support for the ARM timer and watchdog unit @@ -1936,10 +1914,10 @@ choice default ZBOOT_ROM_NONE help Include experimental SD/MMC loading code in the ROM-able zImage. - With this enabled it is possible to write the the ROM-able zImage + With this enabled it is possible to write the ROM-able zImage kernel image to an MMC or SD card and boot the kernel straight from the reset vector. At reset the processor Mask ROM will load - the first part of the the ROM-able zImage which in turn loads the + the first part of the ROM-able zImage which in turn loads the rest the kernel image to RAM. config ZBOOT_ROM_NONE @@ -2281,9 +2259,9 @@ menu "Power management options" source "kernel/power/Kconfig" config ARCH_SUSPEND_POSSIBLE - depends on !ARCH_S5PC100 + depends on !ARCH_S5PC100 && !ARCH_TEGRA depends on CPU_ARM920T || CPU_ARM926T || CPU_SA1100 || \ - CPU_V6 || CPU_V6K || CPU_V7 || CPU_XSC3 || CPU_XSCALE + CPU_V6 || CPU_V6K || CPU_V7 || CPU_XSC3 || CPU_XSCALE || CPU_MOHAWK def_bool y config ARM_CPU_SUSPEND diff --git a/trunk/arch/arm/Makefile b/trunk/arch/arm/Makefile index 047a20780fc1..157900da8782 100644 --- a/trunk/arch/arm/Makefile +++ b/trunk/arch/arm/Makefile @@ -70,8 +70,6 @@ arch-$(CONFIG_CPU_32v4) :=-D__LINUX_ARM_ARCH__=4 -march=armv4 arch-$(CONFIG_CPU_32v3) :=-D__LINUX_ARM_ARCH__=3 -march=armv3 # This selects how we optimise for the processor. -tune-$(CONFIG_CPU_ARM610) :=-mtune=arm610 -tune-$(CONFIG_CPU_ARM710) :=-mtune=arm710 tune-$(CONFIG_CPU_ARM7TDMI) :=-mtune=arm7tdmi tune-$(CONFIG_CPU_ARM720T) :=-mtune=arm7tdmi tune-$(CONFIG_CPU_ARM740T) :=-mtune=arm7tdmi @@ -119,7 +117,7 @@ KBUILD_AFLAGS +=$(CFLAGS_ABI) $(AFLAGS_THUMB2) $(arch-y) $(tune-y) -include asm/ CHECKFLAGS += -D__arm__ #Default value -head-y := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o +head-y := arch/arm/kernel/head$(MMUEXT).o textofs-y := 0x00008000 textofs-$(CONFIG_ARCH_CLPS711X) := 0x00028000 # We don't want the htc bootloader to corrupt kernel during resume @@ -149,8 +147,6 @@ machine-$(CONFIG_ARCH_INTEGRATOR) := integrator machine-$(CONFIG_ARCH_IOP13XX) := iop13xx machine-$(CONFIG_ARCH_IOP32X) := iop32x machine-$(CONFIG_ARCH_IOP33X) := iop33x -machine-$(CONFIG_ARCH_IXP2000) := ixp2000 -machine-$(CONFIG_ARCH_IXP23XX) := ixp23xx machine-$(CONFIG_ARCH_IXP4XX) := ixp4xx machine-$(CONFIG_ARCH_KIRKWOOD) := kirkwood machine-$(CONFIG_ARCH_KS8695) := ks8695 diff --git a/trunk/arch/arm/boot/compressed/head-xscale.S b/trunk/arch/arm/boot/compressed/head-xscale.S index aa5ee49c5c5a..6ab0599c02dd 100644 --- a/trunk/arch/arm/boot/compressed/head-xscale.S +++ b/trunk/arch/arm/boot/compressed/head-xscale.S @@ -32,10 +32,3 @@ __XScale_start: bic r0, r0, #0x1000 @ clear Icache mcr p15, 0, r0, c1, c0, 0 -#ifdef CONFIG_ARCH_IXP2000 - mov r1, #-1 - mov r0, #0xd6000000 - str r1, [r0, #0x14] - str r1, [r0, #0x18] -#endif - diff --git a/trunk/arch/arm/boot/compressed/head.S b/trunk/arch/arm/boot/compressed/head.S index dc7e8ce8e6be..b8c64b80bafc 100644 --- a/trunk/arch/arm/boot/compressed/head.S +++ b/trunk/arch/arm/boot/compressed/head.S @@ -567,6 +567,12 @@ __armv3_mpu_cache_on: mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 mov pc, lr +#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH +#define CB_BITS 0x08 +#else +#define CB_BITS 0x0c +#endif + __setup_mmu: sub r3, r4, #16384 @ Page directory size bic r3, r3, #0xff @ Align the pointer bic r3, r3, #0x3f00 @@ -578,17 +584,14 @@ __setup_mmu: sub r3, r4, #16384 @ Page directory size mov r9, r0, lsr #18 mov r9, r9, lsl #18 @ start of RAM add r10, r9, #0x10000000 @ a reasonable RAM size - mov r1, #0x12 - orr r1, r1, #3 << 10 + mov r1, #0x12 @ XN|U + section mapping + orr r1, r1, #3 << 10 @ AP=11 add r2, r3, #16384 1: cmp r1, r9 @ if virt > start of RAM -#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH - orrhs r1, r1, #0x08 @ set cacheable -#else - orrhs r1, r1, #0x0c @ set cacheable, bufferable -#endif - cmp r1, r10 @ if virt > end of RAM - bichs r1, r1, #0x0c @ clear cacheable, bufferable + cmphs r10, r1 @ && end of RAM > virt + bic r1, r1, #0x1c @ clear XN|U + C + B + orrlo r1, r1, #0x10 @ Set XN|U for non-RAM + orrhs r1, r1, r6 @ set RAM section settings str r1, [r0], #4 @ 1:1 mapping add r1, r1, #1048576 teq r0, r2 @@ -599,7 +602,7 @@ __setup_mmu: sub r3, r4, #16384 @ Page directory size * so there is no map overlap problem for up to 1 MB compressed kernel. * If the execution is in RAM then we would only be duplicating the above. */ - mov r1, #0x1e + orr r1, r6, #0x04 @ ensure B is set for this orr r1, r1, #3 << 10 mov r2, pc mov r2, r2, lsr #20 @@ -620,6 +623,7 @@ __arm926ejs_mmu_cache_on: __armv4_mmu_cache_on: mov r12, lr #ifdef CONFIG_MMU + mov r6, #CB_BITS | 0x12 @ U bl __setup_mmu mov r0, #0 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer @@ -641,6 +645,7 @@ __armv7_mmu_cache_on: #ifdef CONFIG_MMU mrc p15, 0, r11, c0, c1, 4 @ read ID_MMFR0 tst r11, #0xf @ VMSA + movne r6, #CB_BITS | 0x02 @ !XN blne __setup_mmu mov r0, #0 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer @@ -655,7 +660,7 @@ __armv7_mmu_cache_on: orr r0, r0, #1 << 25 @ big-endian page tables #endif orrne r0, r0, #1 @ MMU enabled - movne r1, #-1 + movne r1, #0xfffffffd @ domain 0 = client mcrne p15, 0, r3, c2, c0, 0 @ load page table pointer mcrne p15, 0, r1, c3, c0, 0 @ load domain access control #endif @@ -668,6 +673,7 @@ __armv7_mmu_cache_on: __fa526_cache_on: mov r12, lr + mov r6, #CB_BITS | 0x12 @ U bl __setup_mmu mov r0, #0 mcr p15, 0, r0, c7, c7, 0 @ Invalidate whole cache @@ -680,18 +686,6 @@ __fa526_cache_on: mcr p15, 0, r0, c8, c7, 0 @ flush UTLB mov pc, r12 -__arm6_mmu_cache_on: - mov r12, lr - bl __setup_mmu - mov r0, #0 - mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 - mcr p15, 0, r0, c5, c0, 0 @ invalidate whole TLB v3 - mov r0, #0x30 - bl __common_mmu_cache_on - mov r0, #0 - mcr p15, 0, r0, c5, c0, 0 @ invalidate whole TLB v3 - mov pc, r12 - __common_mmu_cache_on: #ifndef CONFIG_THUMB2_KERNEL #ifndef DEBUG @@ -756,16 +750,6 @@ call_cache_fn: adr r12, proc_types .align 2 .type proc_types,#object proc_types: - .word 0x41560600 @ ARM6/610 - .word 0xffffffe0 - W(b) __arm6_mmu_cache_off @ works, but slow - W(b) __arm6_mmu_cache_off - mov pc, lr - THUMB( nop ) -@ b __arm6_mmu_cache_on @ untested -@ b __arm6_mmu_cache_off -@ b __armv3_mmu_cache_flush - .word 0x00000000 @ old ARM ID .word 0x0000f000 mov pc, lr @@ -777,8 +761,10 @@ proc_types: .word 0x41007000 @ ARM7/710 .word 0xfff8fe00 - W(b) __arm7_mmu_cache_off - W(b) __arm7_mmu_cache_off + mov pc, lr + THUMB( nop ) + mov pc, lr + THUMB( nop ) mov pc, lr THUMB( nop ) @@ -977,21 +963,6 @@ __armv7_mmu_cache_off: mcr p15, 0, r0, c7, c5, 4 @ ISB mov pc, r12 -__arm6_mmu_cache_off: - mov r0, #0x00000030 @ ARM6 control reg. - b __armv3_mmu_cache_off - -__arm7_mmu_cache_off: - mov r0, #0x00000070 @ ARM7 control reg. - b __armv3_mmu_cache_off - -__armv3_mmu_cache_off: - mcr p15, 0, r0, c1, c0, 0 @ turn MMU and cache off - mov r0, #0 - mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 - mcr p15, 0, r0, c5, c0, 0 @ invalidate whole TLB v3 - mov pc, lr - /* * Clean and flush the cache to maintain consistency. * diff --git a/trunk/arch/arm/boot/dts/at91sam9260.dtsi b/trunk/arch/arm/boot/dts/at91sam9260.dtsi new file mode 100644 index 000000000000..f449efc9825f --- /dev/null +++ b/trunk/arch/arm/boot/dts/at91sam9260.dtsi @@ -0,0 +1,273 @@ +/* + * at91sam9260.dtsi - Device Tree Include file for AT91SAM9260 family SoC + * + * Copyright (C) 2011 Atmel, + * 2011 Nicolas Ferre , + * 2011 Jean-Christophe PLAGNIOL-VILLARD + * + * Licensed under GPLv2 or later. + */ + +/include/ "skeleton.dtsi" + +/ { + model = "Atmel AT91SAM9260 family SoC"; + compatible = "atmel,at91sam9260"; + interrupt-parent = <&aic>; + + aliases { + serial0 = &dbgu; + serial1 = &usart0; + serial2 = &usart1; + serial3 = &usart2; + serial4 = &usart3; + serial5 = &usart4; + serial6 = &usart5; + gpio0 = &pioA; + gpio1 = &pioB; + gpio2 = &pioC; + tcb0 = &tcb0; + tcb1 = &tcb1; + }; + cpus { + cpu@0 { + compatible = "arm,arm926ejs"; + }; + }; + + memory { + reg = <0x20000000 0x04000000>; + }; + + ahb { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + apb { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + aic: interrupt-controller@fffff000 { + #interrupt-cells = <2>; + compatible = "atmel,at91rm9200-aic"; + interrupt-controller; + reg = <0xfffff000 0x200>; + }; + + ramc0: ramc@ffffea00 { + compatible = "atmel,at91sam9260-sdramc"; + reg = <0xffffea00 0x200>; + }; + + pmc: pmc@fffffc00 { + compatible = "atmel,at91rm9200-pmc"; + reg = <0xfffffc00 0x100>; + }; + + rstc@fffffd00 { + compatible = "atmel,at91sam9260-rstc"; + reg = <0xfffffd00 0x10>; + }; + + shdwc@fffffd10 { + compatible = "atmel,at91sam9260-shdwc"; + reg = <0xfffffd10 0x10>; + }; + + pit: timer@fffffd30 { + compatible = "atmel,at91sam9260-pit"; + reg = <0xfffffd30 0xf>; + interrupts = <1 4>; + }; + + tcb0: timer@fffa0000 { + compatible = "atmel,at91rm9200-tcb"; + reg = <0xfffa0000 0x100>; + interrupts = <17 4 18 4 19 4>; + }; + + tcb1: timer@fffdc000 { + compatible = "atmel,at91rm9200-tcb"; + reg = <0xfffdc000 0x100>; + interrupts = <26 4 27 4 28 4>; + }; + + pioA: gpio@fffff400 { + compatible = "atmel,at91rm9200-gpio"; + reg = <0xfffff400 0x100>; + interrupts = <2 4>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + }; + + pioB: gpio@fffff600 { + compatible = "atmel,at91rm9200-gpio"; + reg = <0xfffff600 0x100>; + interrupts = <3 4>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + }; + + pioC: gpio@fffff800 { + compatible = "atmel,at91rm9200-gpio"; + reg = <0xfffff800 0x100>; + interrupts = <4 4>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + }; + + dbgu: serial@fffff200 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffff200 0x200>; + interrupts = <1 4>; + status = "disabled"; + }; + + usart0: serial@fffb0000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffb0000 0x200>; + interrupts = <6 4>; + atmel,use-dma-rx; + atmel,use-dma-tx; + status = "disabled"; + }; + + usart1: serial@fffb4000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffb4000 0x200>; + interrupts = <7 4>; + atmel,use-dma-rx; + atmel,use-dma-tx; + status = "disabled"; + }; + + usart2: serial@fffb8000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffb8000 0x200>; + interrupts = <8 4>; + atmel,use-dma-rx; + atmel,use-dma-tx; + status = "disabled"; + }; + + usart3: serial@fffd0000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffd0000 0x200>; + interrupts = <23 4>; + atmel,use-dma-rx; + atmel,use-dma-tx; + status = "disabled"; + }; + + usart4: serial@fffd4000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffd4000 0x200>; + interrupts = <24 4>; + atmel,use-dma-rx; + atmel,use-dma-tx; + status = "disabled"; + }; + + usart5: serial@fffd8000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffd8000 0x200>; + interrupts = <25 4>; + atmel,use-dma-rx; + atmel,use-dma-tx; + status = "disabled"; + }; + + macb0: ethernet@fffc4000 { + compatible = "cdns,at32ap7000-macb", "cdns,macb"; + reg = <0xfffc4000 0x100>; + interrupts = <21 4>; + status = "disabled"; + }; + + usb1: gadget@fffa4000 { + compatible = "atmel,at91rm9200-udc"; + reg = <0xfffa4000 0x4000>; + interrupts = <10 4>; + status = "disabled"; + }; + + adc0: adc@fffe0000 { + compatible = "atmel,at91sam9260-adc"; + reg = <0xfffe0000 0x100>; + interrupts = <5 4>; + atmel,adc-use-external-triggers; + atmel,adc-channels-used = <0xf>; + atmel,adc-vref = <3300>; + atmel,adc-num-channels = <4>; + atmel,adc-startup-time = <15>; + atmel,adc-channel-base = <0x30>; + atmel,adc-drdy-mask = <0x10000>; + atmel,adc-status-register = <0x1c>; + atmel,adc-trigger-register = <0x04>; + + trigger@0 { + trigger-name = "timer-counter-0"; + trigger-value = <0x1>; + }; + trigger@1 { + trigger-name = "timer-counter-1"; + trigger-value = <0x3>; + }; + + trigger@2 { + trigger-name = "timer-counter-2"; + trigger-value = <0x5>; + }; + + trigger@3 { + trigger-name = "external"; + trigger-value = <0x13>; + trigger-external; + }; + }; + }; + + nand0: nand@40000000 { + compatible = "atmel,at91rm9200-nand"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x40000000 0x10000000 + 0xffffe800 0x200 + >; + atmel,nand-addr-offset = <21>; + atmel,nand-cmd-offset = <22>; + gpios = <&pioC 13 0 + &pioC 14 0 + 0 + >; + status = "disabled"; + }; + + usb0: ohci@00500000 { + compatible = "atmel,at91rm9200-ohci", "usb-ohci"; + reg = <0x00500000 0x100000>; + interrupts = <20 4>; + status = "disabled"; + }; + }; + + i2c@0 { + compatible = "i2c-gpio"; + gpios = <&pioA 23 0 /* sda */ + &pioA 24 0 /* scl */ + >; + i2c-gpio,sda-open-drain; + i2c-gpio,scl-open-drain; + i2c-gpio,delay-us = <2>; /* ~100 kHz */ + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; +}; diff --git a/trunk/arch/arm/boot/dts/at91sam9263.dtsi b/trunk/arch/arm/boot/dts/at91sam9263.dtsi new file mode 100644 index 000000000000..0209913a65a2 --- /dev/null +++ b/trunk/arch/arm/boot/dts/at91sam9263.dtsi @@ -0,0 +1,220 @@ +/* + * at91sam9263.dtsi - Device Tree Include file for AT91SAM9263 family SoC + * + * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD + * + * Licensed under GPLv2 only. + */ + +/include/ "skeleton.dtsi" + +/ { + model = "Atmel AT91SAM9263 family SoC"; + compatible = "atmel,at91sam9263"; + interrupt-parent = <&aic>; + + aliases { + serial0 = &dbgu; + serial1 = &usart0; + serial2 = &usart1; + serial3 = &usart2; + gpio0 = &pioA; + gpio1 = &pioB; + gpio2 = &pioC; + gpio3 = &pioD; + gpio4 = &pioE; + tcb0 = &tcb0; + }; + cpus { + cpu@0 { + compatible = "arm,arm926ejs"; + }; + }; + + memory { + reg = <0x20000000 0x08000000>; + }; + + ahb { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + apb { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + aic: interrupt-controller@fffff000 { + #interrupt-cells = <2>; + compatible = "atmel,at91rm9200-aic"; + interrupt-controller; + reg = <0xfffff000 0x200>; + }; + + pmc: pmc@fffffc00 { + compatible = "atmel,at91rm9200-pmc"; + reg = <0xfffffc00 0x100>; + }; + + ramc: ramc@ffffe200 { + compatible = "atmel,at91sam9260-sdramc"; + reg = <0xffffe200 0x200 + 0xffffe800 0x200>; + }; + + pit: timer@fffffd30 { + compatible = "atmel,at91sam9260-pit"; + reg = <0xfffffd30 0xf>; + interrupts = <1 4>; + }; + + tcb0: timer@fff7c000 { + compatible = "atmel,at91rm9200-tcb"; + reg = <0xfff7c000 0x100>; + interrupts = <19 4>; + }; + + rstc@fffffd00 { + compatible = "atmel,at91sam9260-rstc"; + reg = <0xfffffd00 0x10>; + }; + + shdwc@fffffd10 { + compatible = "atmel,at91sam9260-shdwc"; + reg = <0xfffffd10 0x10>; + }; + + pioA: gpio@fffff200 { + compatible = "atmel,at91rm9200-gpio"; + reg = <0xfffff200 0x100>; + interrupts = <2 4>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + }; + + pioB: gpio@fffff400 { + compatible = "atmel,at91rm9200-gpio"; + reg = <0xfffff400 0x100>; + interrupts = <3 4>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + }; + + pioC: gpio@fffff600 { + compatible = "atmel,at91rm9200-gpio"; + reg = <0xfffff600 0x100>; + interrupts = <4 4>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + }; + + pioD: gpio@fffff800 { + compatible = "atmel,at91rm9200-gpio"; + reg = <0xfffff800 0x100>; + interrupts = <4 4>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + }; + + pioE: gpio@fffffa00 { + compatible = "atmel,at91rm9200-gpio"; + reg = <0xfffffa00 0x100>; + interrupts = <4 4>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + }; + + dbgu: serial@ffffee00 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xffffee00 0x200>; + interrupts = <1 4>; + status = "disabled"; + }; + + usart0: serial@fff8c000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfff8c000 0x200>; + interrupts = <7 4>; + atmel,use-dma-rx; + atmel,use-dma-tx; + status = "disabled"; + }; + + usart1: serial@fff90000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfff90000 0x200>; + interrupts = <8 4>; + atmel,use-dma-rx; + atmel,use-dma-tx; + status = "disabled"; + }; + + usart2: serial@fff94000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfff94000 0x200>; + interrupts = <9 4>; + atmel,use-dma-rx; + atmel,use-dma-tx; + status = "disabled"; + }; + + macb0: ethernet@fffbc000 { + compatible = "cdns,at32ap7000-macb", "cdns,macb"; + reg = <0xfffbc000 0x100>; + interrupts = <21 4>; + status = "disabled"; + }; + + usb1: gadget@fff78000 { + compatible = "atmel,at91rm9200-udc"; + reg = <0xfff78000 0x4000>; + interrupts = <24 4>; + status = "disabled"; + }; + }; + + nand0: nand@40000000 { + compatible = "atmel,at91rm9200-nand"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x40000000 0x10000000 + 0xffffe000 0x200 + >; + atmel,nand-addr-offset = <21>; + atmel,nand-cmd-offset = <22>; + gpios = <&pioA 22 0 + &pioD 15 0 + 0 + >; + status = "disabled"; + }; + + usb0: ohci@00a00000 { + compatible = "atmel,at91rm9200-ohci", "usb-ohci"; + reg = <0x00a00000 0x100000>; + interrupts = <29 4>; + status = "disabled"; + }; + }; + + i2c@0 { + compatible = "i2c-gpio"; + gpios = <&pioB 4 0 /* sda */ + &pioB 5 0 /* scl */ + >; + i2c-gpio,sda-open-drain; + i2c-gpio,scl-open-drain; + i2c-gpio,delay-us = <2>; /* ~100 kHz */ + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; +}; diff --git a/trunk/arch/arm/boot/dts/at91sam9263ek.dts b/trunk/arch/arm/boot/dts/at91sam9263ek.dts new file mode 100644 index 000000000000..f86ac4b609fc --- /dev/null +++ b/trunk/arch/arm/boot/dts/at91sam9263ek.dts @@ -0,0 +1,156 @@ +/* + * at91sam9263ek.dts - Device Tree file for Atmel at91sam9263 reference board + * + * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD + * + * Licensed under GPLv2 only + */ +/dts-v1/; +/include/ "at91sam9263.dtsi" + +/ { + model = "Atmel at91sam9263ek"; + compatible = "atmel,at91sam9263ek", "atmel,at91sam9263", "atmel,at91sam9"; + + chosen { + bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs"; + }; + + memory { + reg = <0x20000000 0x4000000>; + }; + + clocks { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + main_clock: clock@0 { + compatible = "atmel,osc", "fixed-clock"; + clock-frequency = <16367660>; + }; + }; + + ahb { + apb { + dbgu: serial@ffffee00 { + status = "okay"; + }; + + usart0: serial@fff8c000 { + status = "okay"; + }; + + macb0: ethernet@fffbc000 { + phy-mode = "rmii"; + status = "okay"; + }; + + usb1: gadget@fff78000 { + atmel,vbus-gpio = <&pioA 25 0>; + status = "okay"; + }; + }; + + nand0: nand@40000000 { + nand-bus-width = <8>; + nand-ecc-mode = "soft"; + nand-on-flash-bbt = <1>; + status = "okay"; + + at91bootstrap@0 { + label = "at91bootstrap"; + reg = <0x0 0x20000>; + }; + + barebox@20000 { + label = "barebox"; + reg = <0x20000 0x40000>; + }; + + bareboxenv@60000 { + label = "bareboxenv"; + reg = <0x60000 0x20000>; + }; + + bareboxenv2@80000 { + label = "bareboxenv2"; + reg = <0x80000 0x20000>; + }; + + oftree@80000 { + label = "oftree"; + reg = <0xa0000 0x20000>; + }; + + kernel@a0000 { + label = "kernel"; + reg = <0xc0000 0x400000>; + }; + + rootfs@4a0000 { + label = "rootfs"; + reg = <0x4c0000 0x7800000>; + }; + + data@7ca0000 { + label = "data"; + reg = <0x7cc0000 0x8340000>; + }; + }; + + usb0: ohci@00a00000 { + num-ports = <2>; + status = "okay"; + atmel,vbus-gpio = <&pioA 24 0 + &pioA 21 0 + >; + }; + }; + + leds { + compatible = "gpio-leds"; + + d3 { + label = "d3"; + gpios = <&pioB 7 0>; + linux,default-trigger = "heartbeat"; + }; + + d2 { + label = "d2"; + gpios = <&pioC 29 1>; + linux,default-trigger = "nand-disk"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + left_click { + label = "left_click"; + gpios = <&pioC 5 1>; + linux,code = <272>; + gpio-key,wakeup; + }; + + right_click { + label = "right_click"; + gpios = <&pioC 4 1>; + linux,code = <273>; + gpio-key,wakeup; + }; + }; + + i2c@0 { + status = "okay"; + + 24c512@50 { + compatible = "24c512"; + reg = <0x50>; + pagesize = <128>; + }; + }; +}; diff --git a/trunk/arch/arm/boot/dts/at91sam9g20.dtsi b/trunk/arch/arm/boot/dts/at91sam9g20.dtsi index 773ef484037a..2a1d1ca8bd86 100644 --- a/trunk/arch/arm/boot/dts/at91sam9g20.dtsi +++ b/trunk/arch/arm/boot/dts/at91sam9g20.dtsi @@ -1,238 +1,26 @@ /* * at91sam9g20.dtsi - Device Tree Include file for AT91SAM9G20 family SoC * - * Copyright (C) 2011 Atmel, - * 2011 Nicolas Ferre , - * 2011 Jean-Christophe PLAGNIOL-VILLARD + * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD * - * Licensed under GPLv2 or later. + * Licensed under GPLv2. */ -/include/ "skeleton.dtsi" +/include/ "at91sam9260.dtsi" / { model = "Atmel AT91SAM9G20 family SoC"; compatible = "atmel,at91sam9g20"; - interrupt-parent = <&aic>; - - aliases { - serial0 = &dbgu; - serial1 = &usart0; - serial2 = &usart1; - serial3 = &usart2; - serial4 = &usart3; - serial5 = &usart4; - serial6 = &usart5; - gpio0 = &pioA; - gpio1 = &pioB; - gpio2 = &pioC; - tcb0 = &tcb0; - tcb1 = &tcb1; - }; - cpus { - cpu@0 { - compatible = "arm,arm926ejs"; - }; - }; memory { reg = <0x20000000 0x08000000>; }; ahb { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <1>; - ranges; - apb { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <1>; - ranges; - - aic: interrupt-controller@fffff000 { - #interrupt-cells = <2>; - compatible = "atmel,at91rm9200-aic"; - interrupt-controller; - reg = <0xfffff000 0x200>; - }; - - ramc0: ramc@ffffea00 { - compatible = "atmel,at91sam9260-sdramc"; - reg = <0xffffea00 0x200>; - }; - - pmc: pmc@fffffc00 { - compatible = "atmel,at91rm9200-pmc"; - reg = <0xfffffc00 0x100>; - }; - - rstc@fffffd00 { - compatible = "atmel,at91sam9260-rstc"; - reg = <0xfffffd00 0x10>; - }; - - shdwc@fffffd10 { - compatible = "atmel,at91sam9260-shdwc"; - reg = <0xfffffd10 0x10>; - }; - - pit: timer@fffffd30 { - compatible = "atmel,at91sam9260-pit"; - reg = <0xfffffd30 0xf>; - interrupts = <1 4>; - }; - - tcb0: timer@fffa0000 { - compatible = "atmel,at91rm9200-tcb"; - reg = <0xfffa0000 0x100>; - interrupts = <17 4 18 4 19 4>; - }; - - tcb1: timer@fffdc000 { - compatible = "atmel,at91rm9200-tcb"; - reg = <0xfffdc000 0x100>; - interrupts = <26 4 27 4 28 4>; - }; - - pioA: gpio@fffff400 { - compatible = "atmel,at91rm9200-gpio"; - reg = <0xfffff400 0x100>; - interrupts = <2 4>; - #gpio-cells = <2>; - gpio-controller; - interrupt-controller; - }; - - pioB: gpio@fffff600 { - compatible = "atmel,at91rm9200-gpio"; - reg = <0xfffff600 0x100>; - interrupts = <3 4>; - #gpio-cells = <2>; - gpio-controller; - interrupt-controller; - }; - - pioC: gpio@fffff800 { - compatible = "atmel,at91rm9200-gpio"; - reg = <0xfffff800 0x100>; - interrupts = <4 4>; - #gpio-cells = <2>; - gpio-controller; - interrupt-controller; - }; - - dbgu: serial@fffff200 { - compatible = "atmel,at91sam9260-usart"; - reg = <0xfffff200 0x200>; - interrupts = <1 4>; - status = "disabled"; - }; - - usart0: serial@fffb0000 { - compatible = "atmel,at91sam9260-usart"; - reg = <0xfffb0000 0x200>; - interrupts = <6 4>; - atmel,use-dma-rx; - atmel,use-dma-tx; - status = "disabled"; - }; - - usart1: serial@fffb4000 { - compatible = "atmel,at91sam9260-usart"; - reg = <0xfffb4000 0x200>; - interrupts = <7 4>; - atmel,use-dma-rx; - atmel,use-dma-tx; - status = "disabled"; - }; - - usart2: serial@fffb8000 { - compatible = "atmel,at91sam9260-usart"; - reg = <0xfffb8000 0x200>; - interrupts = <8 4>; - atmel,use-dma-rx; - atmel,use-dma-tx; - status = "disabled"; - }; - - usart3: serial@fffd0000 { - compatible = "atmel,at91sam9260-usart"; - reg = <0xfffd0000 0x200>; - interrupts = <23 4>; - atmel,use-dma-rx; - atmel,use-dma-tx; - status = "disabled"; - }; - - usart4: serial@fffd4000 { - compatible = "atmel,at91sam9260-usart"; - reg = <0xfffd4000 0x200>; - interrupts = <24 4>; - atmel,use-dma-rx; - atmel,use-dma-tx; - status = "disabled"; - }; - - usart5: serial@fffd8000 { - compatible = "atmel,at91sam9260-usart"; - reg = <0xfffd8000 0x200>; - interrupts = <25 4>; - atmel,use-dma-rx; - atmel,use-dma-tx; - status = "disabled"; - }; - - macb0: ethernet@fffc4000 { - compatible = "cdns,at32ap7000-macb", "cdns,macb"; - reg = <0xfffc4000 0x100>; - interrupts = <21 4>; - status = "disabled"; - }; - - usb1: gadget@fffa4000 { - compatible = "atmel,at91rm9200-udc"; - reg = <0xfffa4000 0x4000>; - interrupts = <10 4>; - status = "disabled"; + adc0: adc@fffe0000 { + atmel,adc-startup-time = <40>; }; }; - - nand0: nand@40000000 { - compatible = "atmel,at91rm9200-nand"; - #address-cells = <1>; - #size-cells = <1>; - reg = <0x40000000 0x10000000 - 0xffffe800 0x200 - >; - atmel,nand-addr-offset = <21>; - atmel,nand-cmd-offset = <22>; - gpios = <&pioC 13 0 - &pioC 14 0 - 0 - >; - status = "disabled"; - }; - - usb0: ohci@00500000 { - compatible = "atmel,at91rm9200-ohci", "usb-ohci"; - reg = <0x00500000 0x100000>; - interrupts = <20 4>; - status = "disabled"; - }; - }; - - i2c@0 { - compatible = "i2c-gpio"; - gpios = <&pioA 23 0 /* sda */ - &pioA 24 0 /* scl */ - >; - i2c-gpio,sda-open-drain; - i2c-gpio,scl-open-drain; - i2c-gpio,delay-us = <2>; /* ~100 kHz */ - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; }; }; diff --git a/trunk/arch/arm/boot/dts/at91sam9g20ek.dts b/trunk/arch/arm/boot/dts/at91sam9g20ek.dts new file mode 100644 index 000000000000..e5324bf9d529 --- /dev/null +++ b/trunk/arch/arm/boot/dts/at91sam9g20ek.dts @@ -0,0 +1,29 @@ +/* + * at91sam9g20ek.dts - Device Tree file for Atmel at91sam9g20ek board + * + * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD + * + * Licensed under GPLv2. + */ +/dts-v1/; +/include/ "at91sam9g20ek_common.dtsi" + +/ { + model = "Atmel at91sam9g20ek"; + compatible = "atmel,at91sam9g20ek", "atmel,at91sam9g20", "atmel,at91sam9"; + + leds { + compatible = "gpio-leds"; + + ds1 { + label = "ds1"; + gpios = <&pioA 9 0>; + linux,default-trigger = "heartbeat"; + }; + + ds5 { + label = "ds5"; + gpios = <&pioA 6 1>; + }; + }; +}; diff --git a/trunk/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts b/trunk/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts new file mode 100644 index 000000000000..f1b2e148ac8c --- /dev/null +++ b/trunk/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts @@ -0,0 +1,29 @@ +/* + * at91sam9g20ek_2mmc.dts - Device Tree file for Atmel at91sam9g20ek 2 MMC board + * + * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD + * + * Licensed under GPLv2. + */ +/dts-v1/; +/include/ "at91sam9g20ek_common.dtsi" + +/ { + model = "Atmel at91sam9g20ek 2 mmc"; + compatible = "atmel,at91sam9g20ek_2mmc", "atmel,at91sam9g20", "atmel,at91sam9"; + + leds { + compatible = "gpio-leds"; + + ds1 { + label = "ds1"; + gpios = <&pioB 9 0>; + linux,default-trigger = "heartbeat"; + }; + + ds5 { + label = "ds5"; + gpios = <&pioB 8 1>; + }; + }; +}; diff --git a/trunk/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/trunk/arch/arm/boot/dts/at91sam9g20ek_common.dtsi new file mode 100644 index 000000000000..b06c0db273b1 --- /dev/null +++ b/trunk/arch/arm/boot/dts/at91sam9g20ek_common.dtsi @@ -0,0 +1,142 @@ +/* + * at91sam9g20ek_common.dtsi - Device Tree file for Atmel at91sam9g20ek board + * + * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD + * + * Licensed under GPLv2. + */ +/include/ "at91sam9g20.dtsi" + +/ { + + chosen { + bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs"; + }; + + memory { + reg = <0x20000000 0x4000000>; + }; + + clocks { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + main_clock: clock@0 { + compatible = "atmel,osc", "fixed-clock"; + clock-frequency = <18432000>; + }; + }; + + ahb { + apb { + dbgu: serial@fffff200 { + status = "okay"; + }; + + usart0: serial@fffb0000 { + status = "okay"; + }; + + usart1: serial@fffb4000 { + status = "okay"; + }; + + macb0: ethernet@fffc4000 { + phy-mode = "rmii"; + status = "okay"; + }; + + usb1: gadget@fffa4000 { + atmel,vbus-gpio = <&pioC 5 0>; + status = "okay"; + }; + }; + + nand0: nand@40000000 { + nand-bus-width = <8>; + nand-ecc-mode = "soft"; + nand-on-flash-bbt; + status = "okay"; + + at91bootstrap@0 { + label = "at91bootstrap"; + reg = <0x0 0x20000>; + }; + + barebox@20000 { + label = "barebox"; + reg = <0x20000 0x40000>; + }; + + bareboxenv@60000 { + label = "bareboxenv"; + reg = <0x60000 0x20000>; + }; + + bareboxenv2@80000 { + label = "bareboxenv2"; + reg = <0x80000 0x20000>; + }; + + oftree@80000 { + label = "oftree"; + reg = <0xa0000 0x20000>; + }; + + kernel@a0000 { + label = "kernel"; + reg = <0xc0000 0x400000>; + }; + + rootfs@4a0000 { + label = "rootfs"; + reg = <0x4c0000 0x7800000>; + }; + + data@7ca0000 { + label = "data"; + reg = <0x7cc0000 0x8340000>; + }; + }; + + usb0: ohci@00500000 { + num-ports = <2>; + status = "okay"; + }; + }; + + i2c@0 { + status = "okay"; + + 24c512@50 { + compatible = "24c512"; + reg = <0x50>; + }; + + wm8731@1b { + compatible = "wm8731"; + reg = <0x1b>; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + btn3 { + label = "Buttin 3"; + gpios = <&pioA 30 1>; + linux,code = <0x103>; + gpio-key,wakeup; + }; + + btn4 { + label = "Buttin 4"; + gpios = <&pioA 31 1>; + linux,code = <0x104>; + gpio-key,wakeup; + }; + }; +}; diff --git a/trunk/arch/arm/boot/dts/at91sam9g45.dtsi b/trunk/arch/arm/boot/dts/at91sam9g45.dtsi index c8042147eaa2..7dbccaf199f7 100644 --- a/trunk/arch/arm/boot/dts/at91sam9g45.dtsi +++ b/trunk/arch/arm/boot/dts/at91sam9g45.dtsi @@ -199,6 +199,43 @@ interrupts = <25 4>; status = "disabled"; }; + + adc0: adc@fffb0000 { + compatible = "atmel,at91sam9260-adc"; + reg = <0xfffb0000 0x100>; + interrupts = <20 4>; + atmel,adc-use-external-triggers; + atmel,adc-channels-used = <0xff>; + atmel,adc-vref = <3300>; + atmel,adc-num-channels = <8>; + atmel,adc-startup-time = <40>; + atmel,adc-channel-base = <0x30>; + atmel,adc-drdy-mask = <0x10000>; + atmel,adc-status-register = <0x1c>; + atmel,adc-trigger-register = <0x08>; + + trigger@0 { + trigger-name = "external-rising"; + trigger-value = <0x1>; + trigger-external; + }; + trigger@1 { + trigger-name = "external-falling"; + trigger-value = <0x2>; + trigger-external; + }; + + trigger@2 { + trigger-name = "external-any"; + trigger-value = <0x3>; + trigger-external; + }; + + trigger@3 { + trigger-name = "continuous"; + trigger-value = <0x6>; + }; + }; }; nand0: nand@40000000 { diff --git a/trunk/arch/arm/boot/dts/at91sam9n12.dtsi b/trunk/arch/arm/boot/dts/at91sam9n12.dtsi new file mode 100644 index 000000000000..cb84de791b5a --- /dev/null +++ b/trunk/arch/arm/boot/dts/at91sam9n12.dtsi @@ -0,0 +1,221 @@ +/* + * at91sam9n12.dtsi - Device Tree include file for AT91SAM9N12 SoC + * + * Copyright (C) 2012 Atmel, + * 2012 Hong Xu + * + * Licensed under GPLv2 or later. + */ + +/include/ "skeleton.dtsi" + +/ { + model = "Atmel AT91SAM9N12 SoC"; + compatible = "atmel,at91sam9n12"; + interrupt-parent = <&aic>; + + aliases { + serial0 = &dbgu; + serial1 = &usart0; + serial2 = &usart1; + serial3 = &usart2; + serial4 = &usart3; + gpio0 = &pioA; + gpio1 = &pioB; + gpio2 = &pioC; + gpio3 = &pioD; + tcb0 = &tcb0; + tcb1 = &tcb1; + }; + cpus { + cpu@0 { + compatible = "arm,arm926ejs"; + }; + }; + + memory { + reg = <0x20000000 0x10000000>; + }; + + ahb { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + apb { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + aic: interrupt-controller@fffff000 { + #interrupt-cells = <2>; + compatible = "atmel,at91rm9200-aic"; + interrupt-controller; + reg = <0xfffff000 0x200>; + }; + + ramc0: ramc@ffffe800 { + compatible = "atmel,at91sam9g45-ddramc"; + reg = <0xffffe800 0x200>; + }; + + pmc: pmc@fffffc00 { + compatible = "atmel,at91rm9200-pmc"; + reg = <0xfffffc00 0x100>; + }; + + rstc@fffffe00 { + compatible = "atmel,at91sam9g45-rstc"; + reg = <0xfffffe00 0x10>; + }; + + pit: timer@fffffe30 { + compatible = "atmel,at91sam9260-pit"; + reg = <0xfffffe30 0xf>; + interrupts = <1 4>; + }; + + shdwc@fffffe10 { + compatible = "atmel,at91sam9x5-shdwc"; + reg = <0xfffffe10 0x10>; + }; + + tcb0: timer@f8008000 { + compatible = "atmel,at91sam9x5-tcb"; + reg = <0xf8008000 0x100>; + interrupts = <17 4>; + }; + + tcb1: timer@f800c000 { + compatible = "atmel,at91sam9x5-tcb"; + reg = <0xf800c000 0x100>; + interrupts = <17 4>; + }; + + dma: dma-controller@ffffec00 { + compatible = "atmel,at91sam9g45-dma"; + reg = <0xffffec00 0x200>; + interrupts = <20 4>; + }; + + pioA: gpio@fffff400 { + compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio"; + reg = <0xfffff400 0x100>; + interrupts = <2 4>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + }; + + pioB: gpio@fffff600 { + compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio"; + reg = <0xfffff600 0x100>; + interrupts = <2 4>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + }; + + pioC: gpio@fffff800 { + compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio"; + reg = <0xfffff800 0x100>; + interrupts = <3 4>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + }; + + pioD: gpio@fffffa00 { + compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio"; + reg = <0xfffffa00 0x100>; + interrupts = <3 4>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + }; + + dbgu: serial@fffff200 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffff200 0x200>; + interrupts = <1 4>; + status = "disabled"; + }; + + usart0: serial@f801c000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xf801c000 0x4000>; + interrupts = <5 4>; + atmel,use-dma-rx; + atmel,use-dma-tx; + status = "disabled"; + }; + + usart1: serial@f8020000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xf8020000 0x4000>; + interrupts = <6 4>; + atmel,use-dma-rx; + atmel,use-dma-tx; + status = "disabled"; + }; + + usart2: serial@f8024000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xf8024000 0x4000>; + interrupts = <7 4>; + atmel,use-dma-rx; + atmel,use-dma-tx; + status = "disabled"; + }; + + usart3: serial@f8028000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xf8028000 0x4000>; + interrupts = <8 4>; + atmel,use-dma-rx; + atmel,use-dma-tx; + status = "disabled"; + }; + }; + + nand0: nand@40000000 { + compatible = "atmel,at91rm9200-nand"; + #address-cells = <1>; + #size-cells = <1>; + reg = < 0x40000000 0x10000000 + 0xffffe000 0x00000600 + 0xffffe600 0x00000200 + 0x00100000 0x00100000 + >; + atmel,nand-addr-offset = <21>; + atmel,nand-cmd-offset = <22>; + gpios = <&pioD 5 0 + &pioD 4 0 + 0 + >; + status = "disabled"; + }; + + usb0: ohci@00500000 { + compatible = "atmel,at91rm9200-ohci", "usb-ohci"; + reg = <0x00500000 0x00100000>; + interrupts = <22 4>; + status = "disabled"; + }; + }; + + i2c@0 { + compatible = "i2c-gpio"; + gpios = <&pioA 30 0 /* sda */ + &pioA 31 0 /* scl */ + >; + i2c-gpio,sda-open-drain; + i2c-gpio,scl-open-drain; + i2c-gpio,delay-us = <2>; /* ~100 kHz */ + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; +}; diff --git a/trunk/arch/arm/boot/dts/at91sam9n12ek.dts b/trunk/arch/arm/boot/dts/at91sam9n12ek.dts new file mode 100644 index 000000000000..f4e43e38f3a1 --- /dev/null +++ b/trunk/arch/arm/boot/dts/at91sam9n12ek.dts @@ -0,0 +1,84 @@ +/* + * at91sam9n12ek.dts - Device Tree file for AT91SAM9N12-EK board + * + * Copyright (C) 2012 Atmel, + * 2012 Hong Xu + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +/include/ "at91sam9n12.dtsi" + +/ { + model = "Atmel AT91SAM9N12-EK"; + compatible = "atmel,at91sam9n12ek", "atmel,at91sam9n12", "atmel,at91sam9"; + + chosen { + bootargs = "mem=128M console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=jffs2"; + }; + + memory { + reg = <0x20000000 0x10000000>; + }; + + clocks { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + main_clock: clock@0 { + compatible = "atmel,osc", "fixed-clock"; + clock-frequency = <16000000>; + }; + }; + + ahb { + apb { + dbgu: serial@fffff200 { + status = "okay"; + }; + }; + + nand0: nand@40000000 { + nand-bus-width = <8>; + nand-ecc-mode = "soft"; + nand-on-flash-bbt; + status = "okay"; + }; + }; + + leds { + compatible = "gpio-leds"; + + d8 { + label = "d8"; + gpios = <&pioB 4 1>; + linux,default-trigger = "mmc0"; + }; + + d9 { + label = "d6"; + gpios = <&pioB 5 1>; + linux,default-trigger = "nand-disk"; + }; + + d10 { + label = "d7"; + gpios = <&pioB 6 0>; + linux,default-trigger = "heartbeat"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + enter { + label = "Enter"; + gpios = <&pioB 4 1>; + linux,code = <28>; + gpio-key,wakeup; + }; + }; +}; diff --git a/trunk/arch/arm/boot/dts/at91sam9x5.dtsi b/trunk/arch/arm/boot/dts/at91sam9x5.dtsi index dd4ed748469a..6b3ef4339ae7 100644 --- a/trunk/arch/arm/boot/dts/at91sam9x5.dtsi +++ b/trunk/arch/arm/boot/dts/at91sam9x5.dtsi @@ -190,6 +190,44 @@ interrupts = <27 4>; status = "disabled"; }; + + adc0: adc@f804c000 { + compatible = "atmel,at91sam9260-adc"; + reg = <0xf804c000 0x100>; + interrupts = <19 4>; + atmel,adc-use-external; + atmel,adc-channels-used = <0xffff>; + atmel,adc-vref = <3300>; + atmel,adc-num-channels = <12>; + atmel,adc-startup-time = <40>; + atmel,adc-channel-base = <0x50>; + atmel,adc-drdy-mask = <0x1000000>; + atmel,adc-status-register = <0x30>; + atmel,adc-trigger-register = <0xc0>; + + trigger@0 { + trigger-name = "external-rising"; + trigger-value = <0x1>; + trigger-external; + }; + + trigger@1 { + trigger-name = "external-falling"; + trigger-value = <0x2>; + trigger-external; + }; + + trigger@2 { + trigger-name = "external-any"; + trigger-value = <0x3>; + trigger-external; + }; + + trigger@3 { + trigger-name = "continuous"; + trigger-value = <0x6>; + }; + }; }; nand0: nand@40000000 { diff --git a/trunk/arch/arm/boot/dts/db8500.dtsi b/trunk/arch/arm/boot/dts/db8500.dtsi index 14bc30705099..881bc3987844 100644 --- a/trunk/arch/arm/boot/dts/db8500.dtsi +++ b/trunk/arch/arm/boot/dts/db8500.dtsi @@ -55,83 +55,101 @@ gpio0: gpio@8012e000 { compatible = "stericsson,db8500-gpio", - "stmicroelectronics,nomadik-gpio"; + "st,nomadik-gpio"; reg = <0x8012e000 0x80>; interrupts = <0 119 0x4>; supports-sleepmode; gpio-controller; + #gpio-cells = <2>; + gpio-bank = <0>; }; gpio1: gpio@8012e080 { compatible = "stericsson,db8500-gpio", - "stmicroelectronics,nomadik-gpio"; + "st,nomadik-gpio"; reg = <0x8012e080 0x80>; interrupts = <0 120 0x4>; supports-sleepmode; gpio-controller; + #gpio-cells = <2>; + gpio-bank = <1>; }; gpio2: gpio@8000e000 { compatible = "stericsson,db8500-gpio", - "stmicroelectronics,nomadik-gpio"; + "st,nomadik-gpio"; reg = <0x8000e000 0x80>; interrupts = <0 121 0x4>; supports-sleepmode; gpio-controller; + #gpio-cells = <2>; + gpio-bank = <2>; }; gpio3: gpio@8000e080 { compatible = "stericsson,db8500-gpio", - "stmicroelectronics,nomadik-gpio"; + "st,nomadik-gpio"; reg = <0x8000e080 0x80>; interrupts = <0 122 0x4>; supports-sleepmode; gpio-controller; + #gpio-cells = <2>; + gpio-bank = <3>; }; gpio4: gpio@8000e100 { compatible = "stericsson,db8500-gpio", - "stmicroelectronics,nomadik-gpio"; + "st,nomadik-gpio"; reg = <0x8000e100 0x80>; interrupts = <0 123 0x4>; supports-sleepmode; gpio-controller; + #gpio-cells = <2>; + gpio-bank = <4>; }; gpio5: gpio@8000e180 { compatible = "stericsson,db8500-gpio", - "stmicroelectronics,nomadik-gpio"; + "st,nomadik-gpio"; reg = <0x8000e180 0x80>; interrupts = <0 124 0x4>; supports-sleepmode; gpio-controller; + #gpio-cells = <2>; + gpio-bank = <5>; }; gpio6: gpio@8011e000 { compatible = "stericsson,db8500-gpio", - "stmicroelectronics,nomadik-gpio"; + "st,nomadik-gpio"; reg = <0x8011e000 0x80>; interrupts = <0 125 0x4>; supports-sleepmode; gpio-controller; + #gpio-cells = <2>; + gpio-bank = <6>; }; gpio7: gpio@8011e080 { compatible = "stericsson,db8500-gpio", - "stmicroelectronics,nomadik-gpio"; + "st,nomadik-gpio"; reg = <0x8011e080 0x80>; interrupts = <0 126 0x4>; supports-sleepmode; gpio-controller; + #gpio-cells = <2>; + gpio-bank = <7>; }; gpio8: gpio@a03fe000 { compatible = "stericsson,db8500-gpio", - "stmicroelectronics,nomadik-gpio"; + "st,nomadik-gpio"; reg = <0xa03fe000 0x80>; interrupts = <0 127 0x4>; supports-sleepmode; gpio-controller; + #gpio-cells = <2>; + gpio-bank = <8>; }; usb@a03e0000 { @@ -153,7 +171,13 @@ reg = <0x80157000 0x1000>; interrupts = <46 47>; #address-cells = <1>; - #size-cells = <0>; + #size-cells = <1>; + ranges; + + prcmu-timer-4@80157450 { + compatible = "stericsson,db8500-prcmu-timer-4"; + reg = <0x80157450 0xC>; + }; ab8500@5 { compatible = "stericsson,ab8500"; @@ -163,7 +187,7 @@ }; i2c@80004000 { - compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c"; + compatible = "stericsson,db8500-i2c", "st,nomadik-i2c"; reg = <0x80004000 0x1000>; interrupts = <0 21 0x4>; #address-cells = <1>; @@ -171,7 +195,7 @@ }; i2c@80122000 { - compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c"; + compatible = "stericsson,db8500-i2c", "st,nomadik-i2c"; reg = <0x80122000 0x1000>; interrupts = <0 22 0x4>; #address-cells = <1>; @@ -179,7 +203,7 @@ }; i2c@80128000 { - compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c"; + compatible = "stericsson,db8500-i2c", "st,nomadik-i2c"; reg = <0x80128000 0x1000>; interrupts = <0 55 0x4>; #address-cells = <1>; @@ -187,7 +211,7 @@ }; i2c@80110000 { - compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c"; + compatible = "stericsson,db8500-i2c", "st,nomadik-i2c"; reg = <0x80110000 0x1000>; interrupts = <0 12 0x4>; #address-cells = <1>; @@ -195,7 +219,7 @@ }; i2c@8012a000 { - compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c"; + compatible = "stericsson,db8500-i2c", "st,nomadik-i2c"; reg = <0x8012a000 0x1000>; interrupts = <0 51 0x4>; #address-cells = <1>; @@ -270,5 +294,14 @@ interrupts = <0 100 0x4>; status = "disabled"; }; + + external-bus@50000000 { + compatible = "simple-bus"; + reg = <0x50000000 0x4000000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x50000000 0x4000000>; + status = "disabled"; + }; }; }; diff --git a/trunk/arch/arm/boot/dts/emev2-kzm9d.dts b/trunk/arch/arm/boot/dts/emev2-kzm9d.dts new file mode 100644 index 000000000000..297e3baba71c --- /dev/null +++ b/trunk/arch/arm/boot/dts/emev2-kzm9d.dts @@ -0,0 +1,26 @@ +/* + * Device Tree Source for the KZM9D board + * + * Copyright (C) 2012 Renesas Solutions Corp. + * + * 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/ "emev2.dtsi" + +/ { + model = "EMEV2 KZM9D Board"; + compatible = "renesas,kzm9d", "renesas,emev2"; + + memory { + device_type = "memory"; + reg = <0x40000000 0x8000000>; + }; + + chosen { + bootargs = "console=ttyS1,115200n81"; + }; +}; diff --git a/trunk/arch/arm/boot/dts/emev2.dtsi b/trunk/arch/arm/boot/dts/emev2.dtsi new file mode 100644 index 000000000000..eb504a6c0f4a --- /dev/null +++ b/trunk/arch/arm/boot/dts/emev2.dtsi @@ -0,0 +1,63 @@ +/* + * Device Tree Source for the EMEV2 SoC + * + * Copyright (C) 2012 Renesas Solutions Corp. + * + * 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/ "skeleton.dtsi" + +/ { + compatible = "renesas,emev2"; + interrupt-parent = <&gic>; + + cpus { + cpu@0 { + compatible = "arm,cortex-a9"; + }; + cpu@1 { + compatible = "arm,cortex-a9"; + }; + }; + + gic: interrupt-controller@e0020000 { + compatible = "arm,cortex-a9-gic"; + interrupt-controller; + #interrupt-cells = <3>; + reg = <0xe0028000 0x1000>, + <0xe0020000 0x0100>; + }; + + sti@e0180000 { + compatible = "renesas,em-sti"; + reg = <0xe0180000 0x54>; + interrupts = <0 125 0>; + }; + + uart@e1020000 { + compatible = "renesas,em-uart"; + reg = <0xe1020000 0x38>; + interrupts = <0 8 0>; + }; + + uart@e1030000 { + compatible = "renesas,em-uart"; + reg = <0xe1030000 0x38>; + interrupts = <0 9 0>; + }; + + uart@e1040000 { + compatible = "renesas,em-uart"; + reg = <0xe1040000 0x38>; + interrupts = <0 10 0>; + }; + + uart@e1050000 { + compatible = "renesas,em-uart"; + reg = <0xe1050000 0x38>; + interrupts = <0 11 0>; + }; +}; diff --git a/trunk/arch/arm/boot/dts/ethernut5.dts b/trunk/arch/arm/boot/dts/ethernut5.dts new file mode 100644 index 000000000000..1ea9d34460a4 --- /dev/null +++ b/trunk/arch/arm/boot/dts/ethernut5.dts @@ -0,0 +1,84 @@ +/* + * ethernut5.dts - Device Tree file for Ethernut 5 board + * + * Copyright (C) 2012 egnite GmbH + * + * Licensed under GPLv2. + */ +/dts-v1/; +/include/ "at91sam9260.dtsi" + +/ { + model = "Ethernut 5"; + compatible = "egnite,ethernut5", "atmel,at91sam9260", "atmel,at91sam9"; + + chosen { + bootargs = "console=ttyS0,115200 root=/dev/mtdblock0 rw rootfstype=jffs2"; + }; + + memory { + reg = <0x20000000 0x08000000>; + }; + + ahb { + apb { + dbgu: serial@fffff200 { + status = "okay"; + }; + + usart0: serial@fffb0000 { + status = "okay"; + }; + + usart1: serial@fffb4000 { + status = "okay"; + }; + + macb0: ethernet@fffc4000 { + phy-mode = "rmii"; + status = "okay"; + }; + + usb1: gadget@fffa4000 { + atmel,vbus-gpio = <&pioC 5 0>; + status = "okay"; + }; + }; + + nand0: nand@40000000 { + nand-bus-width = <8>; + nand-ecc-mode = "soft"; + nand-on-flash-bbt; + status = "okay"; + + gpios = <0 + &pioC 14 0 + 0 + >; + + root@0 { + label = "root"; + reg = <0x0 0x08000000>; + }; + + data@20000 { + label = "data"; + reg = <0x08000000 0x38000000>; + }; + }; + + usb0: ohci@00500000 { + num-ports = <2>; + status = "okay"; + }; + }; + + i2c@0 { + status = "okay"; + + pcf8563@50 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + }; + }; +}; diff --git a/trunk/arch/arm/boot/dts/kirkwood-dns320.dts b/trunk/arch/arm/boot/dts/kirkwood-dns320.dts new file mode 100644 index 000000000000..dc09a735b04a --- /dev/null +++ b/trunk/arch/arm/boot/dts/kirkwood-dns320.dts @@ -0,0 +1,64 @@ +/dts-v1/; + +/include/ "kirkwood.dtsi" + +/ { + model = "D-Link DNS-320 NAS (Rev A1)"; + compatible = "dlink,dns-320-a1", "dlink,dns-320", "dlink,dns-kirkwood", "mrvl,kirkwood-88f6281", "mrvl,kirkwood"; + + memory { + device_type = "memory"; + reg = <0x00000000 0x8000000>; + }; + + chosen { + bootargs = "console=ttyS0,115200n8 earlyprintk"; + }; + + ocp@f1000000 { + serial@12000 { + clock-frequency = <166666667>; + status = "okay"; + }; + + serial@12100 { + clock-frequency = <166666667>; + status = "okay"; + }; + + nand@3000000 { + status = "okay"; + + partition@0 { + label = "u-boot"; + reg = <0x0000000 0x100000>; + read-only; + }; + + partition@100000 { + label = "uImage"; + reg = <0x0100000 0x500000>; + }; + + partition@600000 { + label = "ramdisk"; + reg = <0x0600000 0x500000>; + }; + + partition@b00000 { + label = "image"; + reg = <0x0b00000 0x6600000>; + }; + + partition@7100000 { + label = "mini firmware"; + reg = <0x7100000 0xa00000>; + }; + + partition@7b00000 { + label = "config"; + reg = <0x7b00000 0x500000>; + }; + }; + }; +}; diff --git a/trunk/arch/arm/boot/dts/kirkwood-dns325.dts b/trunk/arch/arm/boot/dts/kirkwood-dns325.dts new file mode 100644 index 000000000000..c2a5562525d2 --- /dev/null +++ b/trunk/arch/arm/boot/dts/kirkwood-dns325.dts @@ -0,0 +1,59 @@ +/dts-v1/; + +/include/ "kirkwood.dtsi" + +/ { + model = "D-Link DNS-325 NAS (Rev A1)"; + compatible = "dlink,dns-325-a1", "dlink,dns-325", "dlink,dns-kirkwood", "mrvl,kirkwood-88f6281", "mrvl,kirkwood"; + + memory { + device_type = "memory"; + reg = <0x00000000 0x10000000>; + }; + + chosen { + bootargs = "console=ttyS0,115200n8 earlyprintk"; + }; + + ocp@f1000000 { + serial@12000 { + clock-frequency = <200000000>; + status = "okay"; + }; + + nand@3000000 { + status = "okay"; + + partition@0 { + label = "u-boot"; + reg = <0x0000000 0x100000>; + read-only; + }; + + partition@100000 { + label = "uImage"; + reg = <0x0100000 0x500000>; + }; + + partition@600000 { + label = "ramdisk"; + reg = <0x0600000 0x500000>; + }; + + partition@b00000 { + label = "image"; + reg = <0x0b00000 0x6600000>; + }; + + partition@7100000 { + label = "mini firmware"; + reg = <0x7100000 0xa00000>; + }; + + partition@7b00000 { + label = "config"; + reg = <0x7b00000 0x500000>; + }; + }; + }; +}; diff --git a/trunk/arch/arm/boot/dts/kirkwood-ib62x0.dts b/trunk/arch/arm/boot/dts/kirkwood-ib62x0.dts new file mode 100644 index 000000000000..ada0f0c23085 --- /dev/null +++ b/trunk/arch/arm/boot/dts/kirkwood-ib62x0.dts @@ -0,0 +1,44 @@ +/dts-v1/; + +/include/ "kirkwood.dtsi" + +/ { + model = "RaidSonic ICY BOX IB-NAS62x0 (Rev B)"; + compatible = "raidsonic,ib-nas6210-b", "raidsonic,ib-nas6220-b", "raidsonic,ib-nas6210", "raidsonic,ib-nas6220", "raidsonic,ib-nas62x0", "mrvl,kirkwood-88f6281", "mrvl,kirkwood"; + + memory { + device_type = "memory"; + reg = <0x00000000 0x10000000>; + }; + + chosen { + bootargs = "console=ttyS0,115200n8 earlyprintk"; + }; + + ocp@f1000000 { + serial@12000 { + clock-frequency = <200000000>; + status = "okay"; + }; + + nand@3000000 { + status = "okay"; + + partition@0 { + label = "u-boot"; + reg = <0x0000000 0x100000>; + }; + + partition@100000 { + label = "uImage"; + reg = <0x0100000 0x600000>; + }; + + partition@700000 { + label = "root"; + reg = <0x0700000 0xf900000>; + }; + + }; + }; +}; diff --git a/trunk/arch/arm/boot/dts/kirkwood-iconnect.dts b/trunk/arch/arm/boot/dts/kirkwood-iconnect.dts new file mode 100644 index 000000000000..1ba75d4adecc --- /dev/null +++ b/trunk/arch/arm/boot/dts/kirkwood-iconnect.dts @@ -0,0 +1,26 @@ +/dts-v1/; + +/include/ "kirkwood.dtsi" + +/ { + model = "Iomega Iconnect"; + compatible = "iom,iconnect-1.1", "iom,iconnect", "mrvl,kirkwood-88f6281", "mrvl,kirkwood"; + + memory { + device_type = "memory"; + reg = <0x00000000 0x10000000>; + }; + + chosen { + bootargs = "console=ttyS0,115200n8 earlyprintk mtdparts=orion_nand:0xc0000@0x0(uboot),0x20000@0xa0000(env),0x300000@0x100000(zImage),0x300000@0x540000(initrd),0x1f400000@0x980000(boot)"; + linux,initrd-start = <0x4500040>; + linux,initrd-end = <0x4800000>; + }; + + ocp@f1000000 { + serial@12000 { + clock-frequency = <200000000>; + status = "ok"; + }; + }; +}; diff --git a/trunk/arch/arm/boot/dts/kirkwood.dtsi b/trunk/arch/arm/boot/dts/kirkwood.dtsi index 3474ef890945..926528b81baa 100644 --- a/trunk/arch/arm/boot/dts/kirkwood.dtsi +++ b/trunk/arch/arm/boot/dts/kirkwood.dtsi @@ -5,7 +5,7 @@ ocp@f1000000 { compatible = "simple-bus"; - ranges = <0 0xf1000000 0x1000000>; + ranges = <0 0xf1000000 0x4000000>; #address-cells = <1>; #size-cells = <1>; @@ -32,5 +32,18 @@ reg = <0x10300 0x20>; interrupts = <53>; }; + + nand@3000000 { + #address-cells = <1>; + #size-cells = <1>; + cle = <0>; + ale = <1>; + bank-width = <1>; + compatible = "mrvl,orion-nand"; + reg = <0x3000000 0x400>; + chip-delay = <25>; + /* set partition map and/or chip-delay in board dts */ + status = "disabled"; + }; }; }; diff --git a/trunk/arch/arm/boot/dts/kizbox.dts b/trunk/arch/arm/boot/dts/kizbox.dts new file mode 100644 index 000000000000..e8814fe0e277 --- /dev/null +++ b/trunk/arch/arm/boot/dts/kizbox.dts @@ -0,0 +1,138 @@ +/* + * kizbox.dts - Device Tree file for Overkiz Kizbox board + * + * Copyright (C) 2012 Boris BREZILLON + * + * Licensed under GPLv2. + */ +/dts-v1/; +/include/ "at91sam9g20.dtsi" + +/ { + + model = "Overkiz kizbox"; + compatible = "overkiz,kizbox", "atmel,at91sam9g20", "atmel,at91sam9"; + + chosen { + bootargs = "panic=5 ubi.mtd=1 rootfstype=ubifs root=ubi0:root"; + }; + + memory { + reg = <0x20000000 0x2000000>; + }; + + clocks { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + main_clock: clock@0 { + compatible = "atmel,osc", "fixed-clock"; + clock-frequency = <18432000>; + }; + }; + + ahb { + apb { + dbgu: serial@fffff200 { + status = "okay"; + }; + + usart0: serial@fffb0000 { + status = "okay"; + }; + + usart1: serial@fffb4000 { + status = "okay"; + }; + + macb0: ethernet@fffc4000 { + phy-mode = "mii"; + status = "okay"; + }; + + }; + + nand0: nand@40000000 { + nand-bus-width = <8>; + nand-ecc-mode = "soft"; + status = "okay"; + + bootloaderkernel@0 { + label = "bootloader-kernel"; + reg = <0x0 0xc0000>; + }; + + ubi@c0000 { + label = "ubi"; + reg = <0xc0000 0x7f40000>; + }; + + }; + + usb0: ohci@00500000 { + num-ports = <1>; + status = "okay"; + }; + }; + + i2c@0 { + status = "okay"; + + pcf8563@51 { + /* nxp pcf8563 rtc */ + compatible = "nxp,pcf8563"; + reg = <0x51>; + }; + + }; + + leds { + compatible = "gpio-leds"; + + led1g { + label = "led1:green"; + gpios = <&pioB 0 1>; + linux,default-trigger = "none"; + }; + + led1r { + label = "led1:red"; + gpios = <&pioB 1 1>; + linux,default-trigger = "none"; + }; + + led2g { + label = "led2:green"; + gpios = <&pioB 2 1>; + linux,default-trigger = "none"; + default-state = "on"; + }; + + led2r { + label = "led2:red"; + gpios = <&pioB 3 1>; + linux,default-trigger = "none"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + reset { + label = "reset"; + gpios = <&pioB 30 1>; + linux,code = <0x100>; + gpio-key,wakeup; + }; + + mode { + label = "mode"; + gpios = <&pioB 31 1>; + linux,code = <0x101>; + gpio-key,wakeup; + }; + }; +}; \ No newline at end of file diff --git a/trunk/arch/arm/boot/dts/lpc32xx.dtsi b/trunk/arch/arm/boot/dts/lpc32xx.dtsi new file mode 100644 index 000000000000..2d696866f71c --- /dev/null +++ b/trunk/arch/arm/boot/dts/lpc32xx.dtsi @@ -0,0 +1,292 @@ +/* + * NXP LPC32xx SoC + * + * Copyright 2012 Roland Stigge + * + * 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/ "skeleton.dtsi" + +/ { + compatible = "nxp,lpc3220"; + interrupt-parent = <&mic>; + + cpus { + cpu@0 { + compatible = "arm,arm926ejs"; + }; + }; + + ahb { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges = <0x20000000 0x20000000 0x30000000>; + + /* + * Enable either SLC or MLC + */ + slc: flash@20020000 { + compatible = "nxp,lpc3220-slc"; + reg = <0x20020000 0x1000>; + status = "disable"; + }; + + mlc: flash@200B0000 { + compatible = "nxp,lpc3220-mlc"; + reg = <0x200B0000 0x1000>; + status = "disable"; + }; + + dma@31000000 { + compatible = "arm,pl080", "arm,primecell"; + reg = <0x31000000 0x1000>; + interrupts = <0x1c 0>; + }; + + /* + * Enable either ohci or usbd (gadget)! + */ + ohci@31020000 { + compatible = "nxp,ohci-nxp", "usb-ohci"; + reg = <0x31020000 0x300>; + interrupts = <0x3b 0>; + status = "disable"; + }; + + usbd@31020000 { + compatible = "nxp,lpc3220-udc"; + reg = <0x31020000 0x300>; + interrupts = <0x3d 0>, <0x3e 0>, <0x3c 0>, <0x3a 0>; + status = "disable"; + }; + + clcd@31040000 { + compatible = "arm,pl110", "arm,primecell"; + reg = <0x31040000 0x1000>; + interrupts = <0x0e 0>; + status = "disable"; + }; + + mac: ethernet@31060000 { + compatible = "nxp,lpc-eth"; + reg = <0x31060000 0x1000>; + interrupts = <0x1d 0>; + }; + + apb { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges = <0x20000000 0x20000000 0x30000000>; + + ssp0: ssp@20084000 { + compatible = "arm,pl022", "arm,primecell"; + reg = <0x20084000 0x1000>; + interrupts = <0x14 0>; + }; + + spi1: spi@20088000 { + compatible = "nxp,lpc3220-spi"; + reg = <0x20088000 0x1000>; + }; + + ssp1: ssp@2008c000 { + compatible = "arm,pl022", "arm,primecell"; + reg = <0x2008c000 0x1000>; + interrupts = <0x15 0>; + }; + + spi2: spi@20090000 { + compatible = "nxp,lpc3220-spi"; + reg = <0x20090000 0x1000>; + }; + + i2s0: i2s@20094000 { + compatible = "nxp,lpc3220-i2s"; + reg = <0x20094000 0x1000>; + }; + + sd@20098000 { + compatible = "arm,pl180", "arm,primecell"; + reg = <0x20098000 0x1000>; + interrupts = <0x0f 0>, <0x0d 0>; + }; + + i2s1: i2s@2009C000 { + compatible = "nxp,lpc3220-i2s"; + reg = <0x2009C000 0x1000>; + }; + + uart3: serial@40080000 { + compatible = "nxp,serial"; + reg = <0x40080000 0x1000>; + }; + + uart4: serial@40088000 { + compatible = "nxp,serial"; + reg = <0x40088000 0x1000>; + }; + + uart5: serial@40090000 { + compatible = "nxp,serial"; + reg = <0x40090000 0x1000>; + }; + + uart6: serial@40098000 { + compatible = "nxp,serial"; + reg = <0x40098000 0x1000>; + }; + + i2c1: i2c@400A0000 { + compatible = "nxp,pnx-i2c"; + reg = <0x400A0000 0x100>; + interrupts = <0x33 0>; + #address-cells = <1>; + #size-cells = <0>; + pnx,timeout = <0x64>; + }; + + i2c2: i2c@400A8000 { + compatible = "nxp,pnx-i2c"; + reg = <0x400A8000 0x100>; + interrupts = <0x32 0>; + #address-cells = <1>; + #size-cells = <0>; + pnx,timeout = <0x64>; + }; + + i2cusb: i2c@31020300 { + compatible = "nxp,pnx-i2c"; + reg = <0x31020300 0x100>; + interrupts = <0x3f 0>; + #address-cells = <1>; + #size-cells = <0>; + pnx,timeout = <0x64>; + }; + }; + + fab { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges = <0x20000000 0x20000000 0x30000000>; + + /* + * MIC Interrupt controller includes: + * MIC @40008000 + * SIC1 @4000C000 + * SIC2 @40010000 + */ + mic: interrupt-controller@40008000 { + compatible = "nxp,lpc3220-mic"; + interrupt-controller; + reg = <0x40008000 0xC000>; + #interrupt-cells = <2>; + }; + + uart1: serial@40014000 { + compatible = "nxp,serial"; + reg = <0x40014000 0x1000>; + }; + + uart2: serial@40018000 { + compatible = "nxp,serial"; + reg = <0x40018000 0x1000>; + }; + + uart7: serial@4001C000 { + compatible = "nxp,serial"; + reg = <0x4001C000 0x1000>; + }; + + rtc@40024000 { + compatible = "nxp,lpc3220-rtc"; + reg = <0x40024000 0x1000>; + interrupts = <0x34 0>; + }; + + gpio: gpio@40028000 { + compatible = "nxp,lpc3220-gpio"; + reg = <0x40028000 0x1000>; + /* create a private address space for enumeration */ + #address-cells = <1>; + #size-cells = <0>; + + gpio_p0: gpio-bank@0 { + gpio-controller; + #gpio-cells = <2>; + reg = <0>; + }; + + gpio_p1: gpio-bank@1 { + gpio-controller; + #gpio-cells = <2>; + reg = <1>; + }; + + gpio_p2: gpio-bank@2 { + gpio-controller; + #gpio-cells = <2>; + reg = <2>; + }; + + gpio_p3: gpio-bank@3 { + gpio-controller; + #gpio-cells = <2>; + reg = <3>; + }; + + gpi_p3: gpio-bank@4 { + gpio-controller; + #gpio-cells = <2>; + reg = <4>; + }; + + gpo_p3: gpio-bank@5 { + gpio-controller; + #gpio-cells = <2>; + reg = <5>; + }; + }; + + watchdog@4003C000 { + compatible = "nxp,pnx4008-wdt"; + reg = <0x4003C000 0x1000>; + }; + + /* + * TSC vs. ADC: Since those two share the same + * hardware, you need to choose from one of the + * following two and do 'status = "okay";' for one of + * them + */ + + adc@40048000 { + compatible = "nxp,lpc3220-adc"; + reg = <0x40048000 0x1000>; + interrupts = <0x27 0>; + status = "disable"; + }; + + tsc@40048000 { + compatible = "nxp,lpc3220-tsc"; + reg = <0x40048000 0x1000>; + interrupts = <0x27 0>; + status = "disable"; + }; + + key@40050000 { + compatible = "nxp,lpc3220-key"; + reg = <0x40050000 0x1000>; + }; + + }; + }; +}; diff --git a/trunk/arch/arm/boot/dts/mmp2-brownstone.dts b/trunk/arch/arm/boot/dts/mmp2-brownstone.dts new file mode 100644 index 000000000000..153a4b2d12b5 --- /dev/null +++ b/trunk/arch/arm/boot/dts/mmp2-brownstone.dts @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2012 Marvell Technology Group Ltd. + * Author: Haojian Zhuang + * + * 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 + * publishhed by the Free Software Foundation. + */ + +/dts-v1/; +/include/ "mmp2.dtsi" + +/ { + model = "Marvell MMP2 Aspenite Development Board"; + compatible = "mrvl,mmp2-brownstone", "mrvl,mmp2"; + + chosen { + bootargs = "console=ttyS2,38400 root=/dev/nfs nfsroot=192.168.1.100:/nfsroot/ ip=192.168.1.101:192.168.1.100::255.255.255.0::eth0:on"; + }; + + memory { + reg = <0x00000000 0x04000000>; + }; + + soc { + apb@d4000000 { + uart3: uart@d4018000 { + status = "okay"; + }; + twsi1: i2c@d4011000 { + status = "okay"; + }; + rtc: rtc@d4010000 { + status = "okay"; + }; + }; + }; +}; diff --git a/trunk/arch/arm/boot/dts/mmp2.dtsi b/trunk/arch/arm/boot/dts/mmp2.dtsi new file mode 100644 index 000000000000..80f74e256408 --- /dev/null +++ b/trunk/arch/arm/boot/dts/mmp2.dtsi @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2012 Marvell Technology Group Ltd. + * Author: Haojian Zhuang + * + * 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 + * publishhed by the Free Software Foundation. + */ + +/include/ "skeleton.dtsi" + +/ { + aliases { + serial0 = &uart1; + serial1 = &uart2; + serial2 = &uart3; + serial3 = &uart4; + i2c0 = &twsi1; + i2c1 = &twsi2; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + interrupt-parent = <&intc>; + ranges; + + axi@d4200000 { /* AXI */ + compatible = "mrvl,axi-bus", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xd4200000 0x00200000>; + ranges; + + intc: interrupt-controller@d4282000 { + compatible = "mrvl,mmp2-intc"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0xd4282000 0x1000>; + mrvl,intc-nr-irqs = <64>; + }; + + intcmux4@d4282150 { + compatible = "mrvl,mmp2-mux-intc"; + interrupts = <4>; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x150 0x4>, <0x168 0x4>; + reg-names = "mux status", "mux mask"; + mrvl,intc-nr-irqs = <2>; + }; + + intcmux5: interrupt-controller@d4282154 { + compatible = "mrvl,mmp2-mux-intc"; + interrupts = <5>; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x154 0x4>, <0x16c 0x4>; + reg-names = "mux status", "mux mask"; + mrvl,intc-nr-irqs = <2>; + mrvl,clr-mfp-irq = <1>; + }; + + intcmux9: interrupt-controller@d4282180 { + compatible = "mrvl,mmp2-mux-intc"; + interrupts = <9>; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x180 0x4>, <0x17c 0x4>; + reg-names = "mux status", "mux mask"; + mrvl,intc-nr-irqs = <3>; + }; + + intcmux17: interrupt-controller@d4282158 { + compatible = "mrvl,mmp2-mux-intc"; + interrupts = <17>; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x158 0x4>, <0x170 0x4>; + reg-names = "mux status", "mux mask"; + mrvl,intc-nr-irqs = <5>; + }; + + intcmux35: interrupt-controller@d428215c { + compatible = "mrvl,mmp2-mux-intc"; + interrupts = <35>; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x15c 0x4>, <0x174 0x4>; + reg-names = "mux status", "mux mask"; + mrvl,intc-nr-irqs = <15>; + }; + + intcmux51: interrupt-controller@d4282160 { + compatible = "mrvl,mmp2-mux-intc"; + interrupts = <51>; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x160 0x4>, <0x178 0x4>; + reg-names = "mux status", "mux mask"; + mrvl,intc-nr-irqs = <2>; + }; + + intcmux55: interrupt-controller@d4282188 { + compatible = "mrvl,mmp2-mux-intc"; + interrupts = <55>; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x188 0x4>, <0x184 0x4>; + reg-names = "mux status", "mux mask"; + mrvl,intc-nr-irqs = <2>; + }; + }; + + apb@d4000000 { /* APB */ + compatible = "mrvl,apb-bus", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xd4000000 0x00200000>; + ranges; + + timer0: timer@d4014000 { + compatible = "mrvl,mmp-timer"; + reg = <0xd4014000 0x100>; + interrupts = <13>; + }; + + uart1: uart@d4030000 { + compatible = "mrvl,mmp-uart"; + reg = <0xd4030000 0x1000>; + interrupts = <27>; + status = "disabled"; + }; + + uart2: uart@d4017000 { + compatible = "mrvl,mmp-uart"; + reg = <0xd4017000 0x1000>; + interrupts = <28>; + status = "disabled"; + }; + + uart3: uart@d4018000 { + compatible = "mrvl,mmp-uart"; + reg = <0xd4018000 0x1000>; + interrupts = <24>; + status = "disabled"; + }; + + uart4: uart@d4016000 { + compatible = "mrvl,mmp-uart"; + reg = <0xd4016000 0x1000>; + interrupts = <46>; + status = "disabled"; + }; + + gpio@d4019000 { + compatible = "mrvl,mmp-gpio"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xd4019000 0x1000>; + gpio-controller; + #gpio-cells = <2>; + interrupts = <49>; + interrupt-names = "gpio_mux"; + interrupt-controller; + #interrupt-cells = <1>; + ranges; + + gcb0: gpio@d4019000 { + reg = <0xd4019000 0x4>; + }; + + gcb1: gpio@d4019004 { + reg = <0xd4019004 0x4>; + }; + + gcb2: gpio@d4019008 { + reg = <0xd4019008 0x4>; + }; + + gcb3: gpio@d4019100 { + reg = <0xd4019100 0x4>; + }; + + gcb4: gpio@d4019104 { + reg = <0xd4019104 0x4>; + }; + + gcb5: gpio@d4019108 { + reg = <0xd4019108 0x4>; + }; + }; + + twsi1: i2c@d4011000 { + compatible = "mrvl,mmp-twsi"; + reg = <0xd4011000 0x1000>; + interrupts = <7>; + mrvl,i2c-fast-mode; + status = "disabled"; + }; + + twsi2: i2c@d4025000 { + compatible = "mrvl,mmp-twsi"; + reg = <0xd4025000 0x1000>; + interrupts = <58>; + status = "disabled"; + }; + + rtc: rtc@d4010000 { + compatible = "mrvl,mmp-rtc"; + reg = <0xd4010000 0x1000>; + interrupts = <1 0>; + interrupt-names = "rtc 1Hz", "rtc alarm"; + interrupt-parent = <&intcmux5>; + status = "disabled"; + }; + }; + }; +}; diff --git a/trunk/arch/arm/boot/dts/omap3-beagle.dts b/trunk/arch/arm/boot/dts/omap3-beagle.dts index 9f72cd4cf308..8c756be4d7ad 100644 --- a/trunk/arch/arm/boot/dts/omap3-beagle.dts +++ b/trunk/arch/arm/boot/dts/omap3-beagle.dts @@ -18,3 +18,52 @@ reg = <0x80000000 0x20000000>; /* 512 MB */ }; }; + +&i2c1 { + clock-frequency = <2600000>; + + twl: twl@48 { + reg = <0x48>; + interrupts = <7>; /* SYS_NIRQ cascaded to intc */ + interrupt-parent = <&intc>; + + vsim: regulator@10 { + compatible = "ti,twl4030-vsim"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3000000>; + }; + }; +}; + +/include/ "twl4030.dtsi" + +&i2c2 { + clock-frequency = <400000>; +}; + +&i2c3 { + clock-frequency = <100000>; + + /* + * Display monitor features are burnt in the EEPROM + * as EDID data. + */ + eeprom@50 { + compatible = "ti,eeprom"; + reg = <0x50>; + }; +}; + +&mmc1 { + vmmc-supply = <&vmmc1>; + vmmc_aux-supply = <&vsim>; + ti,bus-width = <8>; +}; + +&mmc2 { + status = "disable"; +}; + +&mmc3 { + status = "disable"; +}; diff --git a/trunk/arch/arm/boot/dts/omap3.dtsi b/trunk/arch/arm/boot/dts/omap3.dtsi index c6121357c1eb..99474fa5fac4 100644 --- a/trunk/arch/arm/boot/dts/omap3.dtsi +++ b/trunk/arch/arm/boot/dts/omap3.dtsi @@ -69,6 +69,60 @@ reg = <0x48200000 0x1000>; }; + gpio1: gpio@48310000 { + compatible = "ti,omap3-gpio"; + ti,hwmods = "gpio1"; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + gpio2: gpio@49050000 { + compatible = "ti,omap3-gpio"; + ti,hwmods = "gpio2"; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + gpio3: gpio@49052000 { + compatible = "ti,omap3-gpio"; + ti,hwmods = "gpio3"; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + gpio4: gpio@49054000 { + compatible = "ti,omap3-gpio"; + ti,hwmods = "gpio4"; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + gpio5: gpio@49056000 { + compatible = "ti,omap3-gpio"; + ti,hwmods = "gpio5"; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + gpio6: gpio@49058000 { + compatible = "ti,omap3-gpio"; + ti,hwmods = "gpio6"; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + uart1: serial@4806a000 { compatible = "ti,omap3-uart"; ti,hwmods = "uart1"; @@ -113,5 +167,53 @@ #size-cells = <0>; ti,hwmods = "i2c3"; }; + + mcspi1: spi@48098000 { + compatible = "ti,omap2-mcspi"; + #address-cells = <1>; + #size-cells = <0>; + ti,hwmods = "mcspi1"; + ti,spi-num-cs = <4>; + }; + + mcspi2: spi@4809a000 { + compatible = "ti,omap2-mcspi"; + #address-cells = <1>; + #size-cells = <0>; + ti,hwmods = "mcspi2"; + ti,spi-num-cs = <2>; + }; + + mcspi3: spi@480b8000 { + compatible = "ti,omap2-mcspi"; + #address-cells = <1>; + #size-cells = <0>; + ti,hwmods = "mcspi3"; + ti,spi-num-cs = <2>; + }; + + mcspi4: spi@480ba000 { + compatible = "ti,omap2-mcspi"; + #address-cells = <1>; + #size-cells = <0>; + ti,hwmods = "mcspi4"; + ti,spi-num-cs = <1>; + }; + + mmc1: mmc@4809c000 { + compatible = "ti,omap3-hsmmc"; + ti,hwmods = "mmc1"; + ti,dual-volt; + }; + + mmc2: mmc@480b4000 { + compatible = "ti,omap3-hsmmc"; + ti,hwmods = "mmc2"; + }; + + mmc3: mmc@480ad000 { + compatible = "ti,omap3-hsmmc"; + ti,hwmods = "mmc3"; + }; }; }; diff --git a/trunk/arch/arm/boot/dts/omap4-panda.dts b/trunk/arch/arm/boot/dts/omap4-panda.dts index 9755ad5917f8..e671361bc791 100644 --- a/trunk/arch/arm/boot/dts/omap4-panda.dts +++ b/trunk/arch/arm/boot/dts/omap4-panda.dts @@ -17,4 +17,75 @@ device_type = "memory"; reg = <0x80000000 0x40000000>; /* 1 GB */ }; + + leds { + compatible = "gpio-leds"; + heartbeat { + label = "pandaboard::status1"; + gpios = <&gpio1 7 0>; + linux,default-trigger = "heartbeat"; + }; + + mmc { + label = "pandaboard::status2"; + gpios = <&gpio1 8 0>; + linux,default-trigger = "mmc0"; + }; + }; +}; + +&i2c1 { + clock-frequency = <400000>; + + twl: twl@48 { + reg = <0x48>; + /* SPI = 0, IRQ# = 7, 4 = active high level-sensitive */ + interrupts = <0 7 4>; /* IRQ_SYS_1N cascaded to gic */ + interrupt-parent = <&gic>; + }; +}; + +/include/ "twl6030.dtsi" + +&i2c2 { + clock-frequency = <400000>; +}; + +&i2c3 { + clock-frequency = <100000>; + + /* + * Display monitor features are burnt in their EEPROM as EDID data. + * The EEPROM is connected as I2C slave device. + */ + eeprom@50 { + compatible = "ti,eeprom"; + reg = <0x50>; + }; +}; + +&i2c4 { + clock-frequency = <400000>; +}; + +&mmc1 { + vmmc-supply = <&vmmc>; + ti,bus-width = <8>; +}; + +&mmc2 { + status = "disable"; +}; + +&mmc3 { + status = "disable"; +}; + +&mmc4 { + status = "disable"; +}; + +&mmc5 { + ti,non-removable; + ti,bus-width = <4>; }; diff --git a/trunk/arch/arm/boot/dts/omap4-sdp.dts b/trunk/arch/arm/boot/dts/omap4-sdp.dts index 63c6b2b2bf42..e5eeb6f9c6e6 100644 --- a/trunk/arch/arm/boot/dts/omap4-sdp.dts +++ b/trunk/arch/arm/boot/dts/omap4-sdp.dts @@ -17,4 +17,144 @@ device_type = "memory"; reg = <0x80000000 0x40000000>; /* 1 GB */ }; + + vdd_eth: fixedregulator@0 { + compatible = "regulator-fixed"; + regulator-name = "VDD_ETH"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio2 16 0>; /* gpio line 48 */ + enable-active-high; + regulator-boot-on; + }; + + leds { + compatible = "gpio-leds"; + debug0 { + label = "omap4:green:debug0"; + gpios = <&gpio2 29 0>; /* 61 */ + }; + + debug1 { + label = "omap4:green:debug1"; + gpios = <&gpio1 30 0>; /* 30 */ + }; + + debug2 { + label = "omap4:green:debug2"; + gpios = <&gpio1 7 0>; /* 7 */ + }; + + debug3 { + label = "omap4:green:debug3"; + gpios = <&gpio1 8 0>; /* 8 */ + }; + + debug4 { + label = "omap4:green:debug4"; + gpios = <&gpio2 18 0>; /* 50 */ + }; + + user1 { + label = "omap4:blue:user"; + gpios = <&gpio6 9 0>; /* 169 */ + }; + + user2 { + label = "omap4:red:user"; + gpios = <&gpio6 10 0>; /* 170 */ + }; + + user3 { + label = "omap4:green:user"; + gpios = <&gpio5 11 0>; /* 139 */ + }; + }; +}; + +&i2c1 { + clock-frequency = <400000>; + + twl: twl@48 { + reg = <0x48>; + /* SPI = 0, IRQ# = 7, 4 = active high level-sensitive */ + interrupts = <0 7 4>; /* IRQ_SYS_1N cascaded to gic */ + interrupt-parent = <&gic>; + }; +}; + +/include/ "twl6030.dtsi" + +&i2c2 { + clock-frequency = <400000>; +}; + +&i2c3 { + clock-frequency = <400000>; + + /* + * Temperature Sensor + * http://www.ti.com/lit/ds/symlink/tmp105.pdf + */ + tmp105@48 { + compatible = "ti,tmp105"; + reg = <0x48>; + }; + + /* + * Ambient Light Sensor + * http://www.rohm.com/products/databook/sensor/pdf/bh1780gli-e.pdf + */ + bh1780@29 { + compatible = "rohm,bh1780"; + reg = <0x29>; + }; +}; + +&i2c4 { + clock-frequency = <400000>; + + /* + * 3-Axis Digital Compass + * http://www.sparkfun.com/datasheets/Sensors/Magneto/HMC5843.pdf + */ + hmc5843@1e { + compatible = "honeywell,hmc5843"; + reg = <0x1e>; + }; +}; + +&mcspi1 { + eth@0 { + compatible = "ks8851"; + spi-max-frequency = <24000000>; + reg = <0>; + interrupt-parent = <&gpio2>; + interrupts = <2>; /* gpio line 34 */ + vdd-supply = <&vdd_eth>; + }; +}; + +&mmc1 { + vmmc-supply = <&vmmc>; + ti,bus-width = <8>; +}; + +&mmc2 { + vmmc-supply = <&vaux1>; + ti,bus-width = <8>; + ti,non-removable; +}; + +&mmc3 { + status = "disable"; +}; + +&mmc4 { + status = "disable"; +}; + +&mmc5 { + ti,bus-width = <4>; + ti,non-removable; }; diff --git a/trunk/arch/arm/boot/dts/omap4.dtsi b/trunk/arch/arm/boot/dts/omap4.dtsi index 3d35559e77bc..359c4979c8aa 100644 --- a/trunk/arch/arm/boot/dts/omap4.dtsi +++ b/trunk/arch/arm/boot/dts/omap4.dtsi @@ -104,6 +104,60 @@ <0x48240100 0x0100>; }; + gpio1: gpio@4a310000 { + compatible = "ti,omap4-gpio"; + ti,hwmods = "gpio1"; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + gpio2: gpio@48055000 { + compatible = "ti,omap4-gpio"; + ti,hwmods = "gpio2"; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + gpio3: gpio@48057000 { + compatible = "ti,omap4-gpio"; + ti,hwmods = "gpio3"; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + gpio4: gpio@48059000 { + compatible = "ti,omap4-gpio"; + ti,hwmods = "gpio4"; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + gpio5: gpio@4805b000 { + compatible = "ti,omap4-gpio"; + ti,hwmods = "gpio5"; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + + gpio6: gpio@4805d000 { + compatible = "ti,omap4-gpio"; + ti,hwmods = "gpio6"; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + uart1: serial@4806a000 { compatible = "ti,omap4-uart"; ti,hwmods = "uart1"; @@ -155,5 +209,68 @@ #size-cells = <0>; ti,hwmods = "i2c4"; }; + + mcspi1: spi@48098000 { + compatible = "ti,omap4-mcspi"; + #address-cells = <1>; + #size-cells = <0>; + ti,hwmods = "mcspi1"; + ti,spi-num-cs = <4>; + }; + + mcspi2: spi@4809a000 { + compatible = "ti,omap4-mcspi"; + #address-cells = <1>; + #size-cells = <0>; + ti,hwmods = "mcspi2"; + ti,spi-num-cs = <2>; + }; + + mcspi3: spi@480b8000 { + compatible = "ti,omap4-mcspi"; + #address-cells = <1>; + #size-cells = <0>; + ti,hwmods = "mcspi3"; + ti,spi-num-cs = <2>; + }; + + mcspi4: spi@480ba000 { + compatible = "ti,omap4-mcspi"; + #address-cells = <1>; + #size-cells = <0>; + ti,hwmods = "mcspi4"; + ti,spi-num-cs = <1>; + }; + + mmc1: mmc@4809c000 { + compatible = "ti,omap4-hsmmc"; + ti,hwmods = "mmc1"; + ti,dual-volt; + ti,needs-special-reset; + }; + + mmc2: mmc@480b4000 { + compatible = "ti,omap4-hsmmc"; + ti,hwmods = "mmc2"; + ti,needs-special-reset; + }; + + mmc3: mmc@480ad000 { + compatible = "ti,omap4-hsmmc"; + ti,hwmods = "mmc3"; + ti,needs-special-reset; + }; + + mmc4: mmc@480d1000 { + compatible = "ti,omap4-hsmmc"; + ti,hwmods = "mmc4"; + ti,needs-special-reset; + }; + + mmc5: mmc@480d5000 { + compatible = "ti,omap4-hsmmc"; + ti,hwmods = "mmc5"; + ti,needs-special-reset; + }; }; }; diff --git a/trunk/arch/arm/boot/dts/phy3250.dts b/trunk/arch/arm/boot/dts/phy3250.dts new file mode 100644 index 000000000000..0167e86314c0 --- /dev/null +++ b/trunk/arch/arm/boot/dts/phy3250.dts @@ -0,0 +1,145 @@ +/* + * PHYTEC phyCORE-LPC3250 board + * + * Copyright 2012 Roland Stigge + * + * 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/ "lpc32xx.dtsi" + +/ { + model = "PHYTEC phyCORE-LPC3250 board based on NXP LPC3250"; + compatible = "phytec,phy3250", "nxp,lpc3250"; + #address-cells = <1>; + #size-cells = <1>; + + memory { + device_type = "memory"; + reg = <0 0x4000000>; + }; + + ahb { + mac: ethernet@31060000 { + phy-mode = "rmii"; + use-iram; + }; + + /* Here, choose exactly one from: ohci, usbd */ + ohci@31020000 { + transceiver = <&isp1301>; + status = "okay"; + }; + +/* + usbd@31020000 { + transceiver = <&isp1301>; + status = "okay"; + }; +*/ + + clcd@31040000 { + status = "okay"; + }; + + /* 64MB Flash via SLC NAND controller */ + slc: flash@20020000 { + status = "okay"; + #address-cells = <1>; + #size-cells = <1>; + + mtd0@00000000 { + label = "phy3250-boot"; + reg = <0x00000000 0x00064000>; + read-only; + }; + + mtd1@00064000 { + label = "phy3250-uboot"; + reg = <0x00064000 0x00190000>; + read-only; + }; + + mtd2@001f4000 { + label = "phy3250-ubt-prms"; + reg = <0x001f4000 0x00010000>; + }; + + mtd3@00204000 { + label = "phy3250-kernel"; + reg = <0x00204000 0x00400000>; + }; + + mtd4@00604000 { + label = "phy3250-rootfs"; + reg = <0x00604000 0x039fc000>; + }; + }; + + apb { + i2c1: i2c@400A0000 { + clock-frequency = <100000>; + + pcf8563: rtc@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + }; + + uda1380: uda1380@18 { + compatible = "nxp,uda1380"; + reg = <0x18>; + power-gpio = <&gpio 0x59 0>; + reset-gpio = <&gpio 0x51 0>; + dac-clk = "wspll"; + }; + }; + + i2c2: i2c@400A8000 { + clock-frequency = <100000>; + }; + + i2cusb: i2c@31020300 { + clock-frequency = <100000>; + + isp1301: usb-transceiver@2c { + compatible = "nxp,isp1301"; + reg = <0x2c>; + }; + }; + + ssp0: ssp@20084000 { + eeprom: at25@0 { + compatible = "atmel,at25"; + }; + }; + }; + + fab { + tsc@40048000 { + status = "okay"; + }; + }; + }; + + leds { + compatible = "gpio-leds"; + + led0 { + gpios = <&gpo_p3 1 1>; /* GPO_P3 1, GPIO 80, active low */ + linux,default-trigger = "heartbeat"; + default-state = "off"; + }; + + led1 { + gpios = <&gpo_p3 14 1>; /* GPO_P3 14, GPIO 93, active low */ + linux,default-trigger = "timer"; + default-state = "off"; + }; + }; +}; diff --git a/trunk/arch/arm/boot/dts/pxa168.dtsi b/trunk/arch/arm/boot/dts/pxa168.dtsi index d32d5128f225..31a718696080 100644 --- a/trunk/arch/arm/boot/dts/pxa168.dtsi +++ b/trunk/arch/arm/boot/dts/pxa168.dtsi @@ -18,13 +18,6 @@ i2c1 = &twsi2; }; - intc: intc-interrupt-controller@d4282000 { - compatible = "mrvl,mmp-intc", "mrvl,intc"; - interrupt-controller; - #interrupt-cells = <1>; - reg = <0xd4282000 0x1000>; - }; - soc { #address-cells = <1>; #size-cells = <1>; @@ -32,6 +25,23 @@ interrupt-parent = <&intc>; ranges; + axi@d4200000 { /* AXI */ + compatible = "mrvl,axi-bus", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xd4200000 0x00200000>; + ranges; + + intc: interrupt-controller@d4282000 { + compatible = "mrvl,mmp-intc"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0xd4282000 0x1000>; + mrvl,intc-nr-irqs = <64>; + }; + + }; + apb@d4000000 { /* APB */ compatible = "mrvl,apb-bus", "simple-bus"; #address-cells = <1>; @@ -39,40 +49,65 @@ reg = <0xd4000000 0x00200000>; ranges; + timer0: timer@d4014000 { + compatible = "mrvl,mmp-timer"; + reg = <0xd4014000 0x100>; + interrupts = <13>; + }; + uart1: uart@d4017000 { - compatible = "mrvl,mmp-uart", "mrvl,pxa-uart"; + compatible = "mrvl,mmp-uart"; reg = <0xd4017000 0x1000>; interrupts = <27>; status = "disabled"; }; uart2: uart@d4018000 { - compatible = "mrvl,mmp-uart", "mrvl,pxa-uart"; + compatible = "mrvl,mmp-uart"; reg = <0xd4018000 0x1000>; interrupts = <28>; status = "disabled"; }; uart3: uart@d4026000 { - compatible = "mrvl,mmp-uart", "mrvl,pxa-uart"; + compatible = "mrvl,mmp-uart"; reg = <0xd4026000 0x1000>; interrupts = <29>; status = "disabled"; }; - gpio: gpio@d4019000 { - compatible = "mrvl,mmp-gpio", "mrvl,pxa-gpio"; + gpio@d4019000 { + compatible = "mrvl,mmp-gpio"; + #address-cells = <1>; + #size-cells = <1>; reg = <0xd4019000 0x1000>; + gpio-controller; + #gpio-cells = <2>; interrupts = <49>; interrupt-names = "gpio_mux"; - gpio-controller; - #gpio-cells = <1>; interrupt-controller; #interrupt-cells = <1>; + ranges; + + gcb0: gpio@d4019000 { + reg = <0xd4019000 0x4>; + }; + + gcb1: gpio@d4019004 { + reg = <0xd4019004 0x4>; + }; + + gcb2: gpio@d4019008 { + reg = <0xd4019008 0x4>; + }; + + gcb3: gpio@d4019100 { + reg = <0xd4019100 0x4>; + }; }; twsi1: i2c@d4011000 { - compatible = "mrvl,mmp-twsi", "mrvl,pxa-i2c"; + compatible = "mrvl,mmp-twsi"; reg = <0xd4011000 0x1000>; interrupts = <7>; mrvl,i2c-fast-mode; @@ -80,7 +115,7 @@ }; twsi2: i2c@d4025000 { - compatible = "mrvl,mmp-twsi", "mrvl,pxa-i2c"; + compatible = "mrvl,mmp-twsi"; reg = <0xd4025000 0x1000>; interrupts = <58>; status = "disabled"; diff --git a/trunk/arch/arm/boot/dts/pxa910-dkb.dts b/trunk/arch/arm/boot/dts/pxa910-dkb.dts new file mode 100644 index 000000000000..e92be5a474e7 --- /dev/null +++ b/trunk/arch/arm/boot/dts/pxa910-dkb.dts @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2012 Marvell Technology Group Ltd. + * Author: Haojian Zhuang + * + * 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 + * publishhed by the Free Software Foundation. + */ + +/dts-v1/; +/include/ "pxa910.dtsi" + +/ { + model = "Marvell PXA910 DKB Development Board"; + compatible = "mrvl,pxa910-dkb", "mrvl,pxa910"; + + chosen { + bootargs = "console=ttyS0,115200 root=/dev/nfs nfsroot=192.168.1.100:/nfsroot/ ip=192.168.1.101:192.168.1.100::255.255.255.0::eth0:on"; + }; + + memory { + reg = <0x00000000 0x10000000>; + }; + + soc { + apb@d4000000 { + uart1: uart@d4017000 { + status = "okay"; + }; + twsi1: i2c@d4011000 { + status = "okay"; + }; + rtc: rtc@d4010000 { + status = "okay"; + }; + }; + }; +}; diff --git a/trunk/arch/arm/boot/dts/pxa910.dtsi b/trunk/arch/arm/boot/dts/pxa910.dtsi new file mode 100644 index 000000000000..aebf32de73b4 --- /dev/null +++ b/trunk/arch/arm/boot/dts/pxa910.dtsi @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2012 Marvell Technology Group Ltd. + * Author: Haojian Zhuang + * + * 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 + * publishhed by the Free Software Foundation. + */ + +/include/ "skeleton.dtsi" + +/ { + aliases { + serial0 = &uart1; + serial1 = &uart2; + serial2 = &uart3; + i2c0 = &twsi1; + i2c1 = &twsi2; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + interrupt-parent = <&intc>; + ranges; + + axi@d4200000 { /* AXI */ + compatible = "mrvl,axi-bus", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xd4200000 0x00200000>; + ranges; + + intc: interrupt-controller@d4282000 { + compatible = "mrvl,mmp-intc"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0xd4282000 0x1000>; + mrvl,intc-nr-irqs = <64>; + }; + + }; + + apb@d4000000 { /* APB */ + compatible = "mrvl,apb-bus", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xd4000000 0x00200000>; + ranges; + + timer0: timer@d4014000 { + compatible = "mrvl,mmp-timer"; + reg = <0xd4014000 0x100>; + interrupts = <13>; + }; + + timer1: timer@d4016000 { + compatible = "mrvl,mmp-timer"; + reg = <0xd4016000 0x100>; + interrupts = <29>; + status = "disabled"; + }; + + uart1: uart@d4017000 { + compatible = "mrvl,mmp-uart"; + reg = <0xd4017000 0x1000>; + interrupts = <27>; + status = "disabled"; + }; + + uart2: uart@d4018000 { + compatible = "mrvl,mmp-uart"; + reg = <0xd4018000 0x1000>; + interrupts = <28>; + status = "disabled"; + }; + + uart3: uart@d4036000 { + compatible = "mrvl,mmp-uart"; + reg = <0xd4036000 0x1000>; + interrupts = <59>; + status = "disabled"; + }; + + gpio@d4019000 { + compatible = "mrvl,mmp-gpio"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xd4019000 0x1000>; + gpio-controller; + #gpio-cells = <2>; + interrupts = <49>; + interrupt-names = "gpio_mux"; + interrupt-controller; + #interrupt-cells = <1>; + ranges; + + gcb0: gpio@d4019000 { + reg = <0xd4019000 0x4>; + }; + + gcb1: gpio@d4019004 { + reg = <0xd4019004 0x4>; + }; + + gcb2: gpio@d4019008 { + reg = <0xd4019008 0x4>; + }; + + gcb3: gpio@d4019100 { + reg = <0xd4019100 0x4>; + }; + }; + + twsi1: i2c@d4011000 { + compatible = "mrvl,mmp-twsi"; + reg = <0xd4011000 0x1000>; + interrupts = <7>; + mrvl,i2c-fast-mode; + status = "disabled"; + }; + + twsi2: i2c@d4037000 { + compatible = "mrvl,mmp-twsi"; + reg = <0xd4037000 0x1000>; + interrupts = <54>; + status = "disabled"; + }; + + rtc: rtc@d4010000 { + compatible = "mrvl,mmp-rtc"; + reg = <0xd4010000 0x1000>; + interrupts = <5 6>; + interrupt-names = "rtc 1Hz", "rtc alarm"; + status = "disabled"; + }; + }; + }; +}; diff --git a/trunk/arch/arm/boot/dts/r8a7740-armadillo800eva.dts b/trunk/arch/arm/boot/dts/r8a7740-armadillo800eva.dts new file mode 100644 index 000000000000..a7505a95a3b7 --- /dev/null +++ b/trunk/arch/arm/boot/dts/r8a7740-armadillo800eva.dts @@ -0,0 +1,22 @@ +/* + * Device Tree Source for the armadillo 800 eva board + * + * Copyright (C) 2012 Renesas Solutions Corp. + * + * 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/ "skeleton.dtsi" + +/ { + model = "armadillo 800 eva"; + compatible = "renesas,armadillo800eva"; + + memory { + device_type = "memory"; + reg = <0x40000000 0x20000000>; + }; +}; diff --git a/trunk/arch/arm/boot/dts/sh7372.dtsi b/trunk/arch/arm/boot/dts/sh7372.dtsi new file mode 100644 index 000000000000..677fc603f8b3 --- /dev/null +++ b/trunk/arch/arm/boot/dts/sh7372.dtsi @@ -0,0 +1,21 @@ +/* + * Device Tree Source for the sh7372 SoC + * + * Copyright (C) 2012 Renesas Solutions Corp. + * + * 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/ "skeleton.dtsi" + +/ { + compatible = "renesas,sh7372"; + + cpus { + cpu@0 { + compatible = "arm,cortex-a8"; + }; + }; +}; diff --git a/trunk/arch/arm/boot/dts/sh73a0-kzm9g.dts b/trunk/arch/arm/boot/dts/sh73a0-kzm9g.dts new file mode 100644 index 000000000000..bcb911951978 --- /dev/null +++ b/trunk/arch/arm/boot/dts/sh73a0-kzm9g.dts @@ -0,0 +1,22 @@ +/* + * Device Tree Source for the KZM-A9-GT board + * + * Copyright (C) 2012 Renesas Solutions Corp. + * + * 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/ "skeleton.dtsi" + +/ { + model = "KZM-A9-GT"; + compatible = "renesas,kzm9g", "renesas,sh73a0"; + + memory { + device_type = "memory"; + reg = <0x41000000 0x1e800000>; + }; +}; diff --git a/trunk/arch/arm/boot/dts/snowball.dts b/trunk/arch/arm/boot/dts/snowball.dts index 359c6d679156..d99dc04f0d91 100644 --- a/trunk/arch/arm/boot/dts/snowball.dts +++ b/trunk/arch/arm/boot/dts/snowball.dts @@ -30,35 +30,35 @@ wakeup = <1>; linux,code = <2>; label = "userpb"; - gpios = <&gpio1 0>; + gpios = <&gpio1 0 0>; }; button@2 { debounce_interval = <50>; wakeup = <1>; linux,code = <3>; - label = "userpb"; - gpios = <&gpio4 23>; + label = "extkb1"; + gpios = <&gpio4 23 0>; }; button@3 { debounce_interval = <50>; wakeup = <1>; linux,code = <4>; - label = "userpb"; - gpios = <&gpio4 23>; + label = "extkb2"; + gpios = <&gpio4 24 0>; }; button@4 { debounce_interval = <50>; wakeup = <1>; linux,code = <5>; - label = "userpb"; - gpios = <&gpio5 1>; + label = "extkb3"; + gpios = <&gpio5 1 0>; }; button@5 { debounce_interval = <50>; wakeup = <1>; linux,code = <6>; - label = "userpb"; - gpios = <&gpio5 2>; + label = "extkb4"; + gpios = <&gpio5 2 0>; }; }; @@ -73,17 +73,19 @@ soc-u9500 { external-bus@50000000 { - compatible = "simple-bus"; - reg = <0x50000000 0x10000000>; - #address-cells = <1>; - #size-cells = <1>; - ranges; - - ethernet@50000000 { - compatible = "smsc,9111"; - reg = <0x50000000 0x10000>; - interrupts = <12>; + status = "okay"; + + ethernet@0 { + compatible = "smsc,lan9115"; + reg = <0 0x10000>; + interrupts = <12 0x1>; interrupt-parent = <&gpio4>; + + reg-shift = <1>; + reg-io-width = <2>; + smsc,force-internal-phy; + smsc,irq-active-high; + smsc,irq-push-pull; }; }; diff --git a/trunk/arch/arm/boot/dts/spear300-evb.dts b/trunk/arch/arm/boot/dts/spear300-evb.dts new file mode 100644 index 000000000000..910e264b87c0 --- /dev/null +++ b/trunk/arch/arm/boot/dts/spear300-evb.dts @@ -0,0 +1,221 @@ +/* + * DTS file for SPEAr300 Evaluation Baord + * + * Copyright 2012 Viresh Kumar + * + * 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/ "spear300.dtsi" + +/ { + model = "ST SPEAr300 Evaluation Board"; + compatible = "st,spear300-evb", "st,spear300"; + #address-cells = <1>; + #size-cells = <1>; + + memory { + reg = <0 0x40000000>; + }; + + ahb { + pinmux@99000000 { + st,pinmux-mode = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&state_default>; + + state_default: pinmux { + i2c0 { + st,pins = "i2c0_grp"; + st,function = "i2c0"; + }; + ssp0 { + st,pins = "ssp0_grp"; + st,function = "ssp0"; + }; + mii0 { + st,pins = "mii0_grp"; + st,function = "mii0"; + }; + uart0 { + st,pins = "uart0_grp"; + st,function = "uart0"; + }; + clcd { + st,pins = "clcd_pfmode_grp"; + st,function = "clcd"; + }; + sdhci { + st,pins = "sdhci_4bit_grp"; + st,function = "sdhci"; + }; + gpio1 { + st,pins = "gpio1_4_to_7_grp", + "gpio1_0_to_3_grp"; + st,function = "gpio1"; + }; + }; + }; + + clcd@60000000 { + status = "okay"; + }; + + dma@fc400000 { + status = "okay"; + }; + + fsmc: flash@94000000 { + status = "okay"; + }; + + gmac: eth@e0800000 { + status = "okay"; + }; + + sdhci@70000000 { + int-gpio = <&gpio1 0 0>; + power-gpio = <&gpio1 2 1>; + status = "okay"; + }; + + smi: flash@fc000000 { + status = "okay"; + }; + + spi0: spi@d0100000 { + status = "okay"; + }; + + ehci@e1800000 { + status = "okay"; + }; + + ohci@e1900000 { + status = "okay"; + }; + + ohci@e2100000 { + status = "okay"; + }; + + apb { + gpio0: gpio@fc980000 { + status = "okay"; + }; + + gpio1: gpio@a9000000 { + status = "okay"; + }; + + i2c0: i2c@d0180000 { + status = "okay"; + }; + + kbd@a0000000 { + linux,keymap = < 0x00000001 + 0x00010002 + 0x00020003 + 0x00030004 + 0x00040005 + 0x00050006 + 0x00060007 + 0x00070008 + 0x00080009 + 0x0100000a + 0x0101000c + 0x0102000d + 0x0103000e + 0x0104000f + 0x01050010 + 0x01060011 + 0x01070012 + 0x01080013 + 0x02000014 + 0x02010015 + 0x02020016 + 0x02030017 + 0x02040018 + 0x02050019 + 0x0206001a + 0x0207001b + 0x0208001c + 0x0300001d + 0x0301001e + 0x0302001f + 0x03030020 + 0x03040021 + 0x03050022 + 0x03060023 + 0x03070024 + 0x03080025 + 0x04000026 + 0x04010027 + 0x04020028 + 0x04030029 + 0x0404002a + 0x0405002b + 0x0406002c + 0x0407002d + 0x0408002e + 0x0500002f + 0x05010030 + 0x05020031 + 0x05030032 + 0x05040033 + 0x05050034 + 0x05060035 + 0x05070036 + 0x05080037 + 0x06000038 + 0x06010039 + 0x0602003a + 0x0603003b + 0x0604003c + 0x0605003d + 0x0606003e + 0x0607003f + 0x06080040 + 0x07000041 + 0x07010042 + 0x07020043 + 0x07030044 + 0x07040045 + 0x07050046 + 0x07060047 + 0x07070048 + 0x07080049 + 0x0800004a + 0x0801004b + 0x0802004c + 0x0803004d + 0x0804004e + 0x0805004f + 0x08060050 + 0x08070051 + 0x08080052 >; + autorepeat; + st,mode = <0>; + status = "okay"; + }; + + rtc@fc900000 { + status = "okay"; + }; + + serial@d0000000 { + status = "okay"; + }; + + wdt@fc880000 { + status = "okay"; + }; + }; + }; +}; diff --git a/trunk/arch/arm/boot/dts/spear300.dtsi b/trunk/arch/arm/boot/dts/spear300.dtsi new file mode 100644 index 000000000000..01c5e358fdb2 --- /dev/null +++ b/trunk/arch/arm/boot/dts/spear300.dtsi @@ -0,0 +1,77 @@ +/* + * DTS file for SPEAr300 SoC + * + * Copyright 2012 Viresh Kumar + * + * 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/ "spear3xx.dtsi" + +/ { + ahb { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges = <0x60000000 0x60000000 0x50000000 + 0xd0000000 0xd0000000 0x30000000>; + + pinmux@99000000 { + compatible = "st,spear300-pinmux"; + reg = <0x99000000 0x1000>; + }; + + clcd@60000000 { + compatible = "arm,clcd-pl110", "arm,primecell"; + reg = <0x60000000 0x1000>; + interrupts = <30>; + status = "disabled"; + }; + + fsmc: flash@94000000 { + compatible = "st,spear600-fsmc-nand"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x94000000 0x1000 /* FSMC Register */ + 0x80000000 0x0010>; /* NAND Base */ + reg-names = "fsmc_regs", "nand_data"; + st,ale-off = <0x20000>; + st,cle-off = <0x10000>; + status = "disabled"; + }; + + sdhci@70000000 { + compatible = "st,sdhci-spear"; + reg = <0x70000000 0x100>; + interrupts = <1>; + status = "disabled"; + }; + + apb { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges = <0xa0000000 0xa0000000 0x10000000 + 0xd0000000 0xd0000000 0x30000000>; + + gpio1: gpio@a9000000 { + #gpio-cells = <2>; + compatible = "arm,pl061", "arm,primecell"; + gpio-controller; + reg = <0xa9000000 0x1000>; + status = "disabled"; + }; + + kbd@a0000000 { + compatible = "st,spear300-kbd"; + reg = <0xa0000000 0x1000>; + status = "disabled"; + }; + }; + }; +}; diff --git a/trunk/arch/arm/boot/dts/spear310-evb.dts b/trunk/arch/arm/boot/dts/spear310-evb.dts new file mode 100644 index 000000000000..6d95317100ad --- /dev/null +++ b/trunk/arch/arm/boot/dts/spear310-evb.dts @@ -0,0 +1,172 @@ +/* + * DTS file for SPEAr310 Evaluation Baord + * + * Copyright 2012 Viresh Kumar + * + * 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/ "spear310.dtsi" + +/ { + model = "ST SPEAr310 Evaluation Board"; + compatible = "st,spear310-evb", "st,spear310"; + #address-cells = <1>; + #size-cells = <1>; + + memory { + reg = <0 0x40000000>; + }; + + ahb { + pinmux@b4000000 { + pinctrl-names = "default"; + pinctrl-0 = <&state_default>; + + state_default: pinmux { + gpio0 { + st,pins = "gpio0_pin0_grp", + "gpio0_pin1_grp", + "gpio0_pin2_grp", + "gpio0_pin3_grp", + "gpio0_pin4_grp", + "gpio0_pin5_grp"; + st,function = "gpio0"; + }; + i2c0 { + st,pins = "i2c0_grp"; + st,function = "i2c0"; + }; + mii0 { + st,pins = "mii0_grp"; + st,function = "mii0"; + }; + ssp0 { + st,pins = "ssp0_grp"; + st,function = "ssp0"; + }; + uart0 { + st,pins = "uart0_grp"; + st,function = "uart0"; + }; + emi { + st,pins = "emi_cs_0_to_5_grp"; + st,function = "emi"; + }; + fsmc { + st,pins = "fsmc_grp"; + st,function = "fsmc"; + }; + uart1 { + st,pins = "uart1_grp"; + st,function = "uart1"; + }; + uart2 { + st,pins = "uart2_grp"; + st,function = "uart2"; + }; + uart3 { + st,pins = "uart3_grp"; + st,function = "uart3"; + }; + uart4 { + st,pins = "uart4_grp"; + st,function = "uart4"; + }; + uart5 { + st,pins = "uart5_grp"; + st,function = "uart5"; + }; + }; + }; + + dma@fc400000 { + status = "okay"; + }; + + fsmc: flash@44000000 { + status = "okay"; + }; + + gmac: eth@e0800000 { + status = "okay"; + }; + + smi: flash@fc000000 { + status = "okay"; + clock-rate=<50000000>; + + flash@f8000000 { + label = "m25p64"; + reg = <0xf8000000 0x800000>; + #address-cells = <1>; + #size-cells = <1>; + st,smi-fast-mode; + }; + }; + + spi0: spi@d0100000 { + status = "okay"; + }; + + ehci@e1800000 { + status = "okay"; + }; + + ohci@e1900000 { + status = "okay"; + }; + + ohci@e2100000 { + status = "okay"; + }; + + apb { + gpio0: gpio@fc980000 { + status = "okay"; + }; + + i2c0: i2c@d0180000 { + status = "okay"; + }; + + rtc@fc900000 { + status = "okay"; + }; + + serial@d0000000 { + status = "okay"; + }; + + serial@b2000000 { + status = "okay"; + }; + + serial@b2080000 { + status = "okay"; + }; + + serial@b2100000 { + status = "okay"; + }; + + serial@b2180000 { + status = "okay"; + }; + + serial@b2200000 { + status = "okay"; + }; + + wdt@fc880000 { + status = "okay"; + }; + }; + }; +}; diff --git a/trunk/arch/arm/boot/dts/spear310.dtsi b/trunk/arch/arm/boot/dts/spear310.dtsi new file mode 100644 index 000000000000..e47081c494d9 --- /dev/null +++ b/trunk/arch/arm/boot/dts/spear310.dtsi @@ -0,0 +1,80 @@ +/* + * DTS file for SPEAr310 SoC + * + * Copyright 2012 Viresh Kumar + * + * 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/ "spear3xx.dtsi" + +/ { + ahb { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges = <0x40000000 0x40000000 0x10000000 + 0xb0000000 0xb0000000 0x10000000 + 0xd0000000 0xd0000000 0x30000000>; + + pinmux@b4000000 { + compatible = "st,spear310-pinmux"; + reg = <0xb4000000 0x1000>; + }; + + fsmc: flash@44000000 { + compatible = "st,spear600-fsmc-nand"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x44000000 0x1000 /* FSMC Register */ + 0x40000000 0x0010>; /* NAND Base */ + reg-names = "fsmc_regs", "nand_data"; + st,ale-off = <0x10000>; + st,cle-off = <0x20000>; + status = "disabled"; + }; + + apb { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges = <0xb0000000 0xb0000000 0x10000000 + 0xd0000000 0xd0000000 0x30000000>; + + serial@b2000000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0xb2000000 0x1000>; + status = "disabled"; + }; + + serial@b2080000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0xb2080000 0x1000>; + status = "disabled"; + }; + + serial@b2100000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0xb2100000 0x1000>; + status = "disabled"; + }; + + serial@b2180000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0xb2180000 0x1000>; + status = "disabled"; + }; + + serial@b2200000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0xb2200000 0x1000>; + status = "disabled"; + }; + }; + }; +}; diff --git a/trunk/arch/arm/boot/dts/spear320-evb.dts b/trunk/arch/arm/boot/dts/spear320-evb.dts new file mode 100644 index 000000000000..0c6463b71a37 --- /dev/null +++ b/trunk/arch/arm/boot/dts/spear320-evb.dts @@ -0,0 +1,173 @@ +/* + * DTS file for SPEAr320 Evaluation Baord + * + * Copyright 2012 Viresh Kumar + * + * 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/ "spear320.dtsi" + +/ { + model = "ST SPEAr300 Evaluation Board"; + compatible = "st,spear300-evb", "st,spear300"; + #address-cells = <1>; + #size-cells = <1>; + + memory { + reg = <0 0x40000000>; + }; + + ahb { + pinmux@b3000000 { + st,pinmux-mode = <3>; + pinctrl-names = "default"; + pinctrl-0 = <&state_default>; + + state_default: pinmux { + i2c0 { + st,pins = "i2c0_grp"; + st,function = "i2c0"; + }; + mii0 { + st,pins = "mii0_grp"; + st,function = "mii0"; + }; + ssp0 { + st,pins = "ssp0_grp"; + st,function = "ssp0"; + }; + uart0 { + st,pins = "uart0_grp"; + st,function = "uart0"; + }; + sdhci { + st,pins = "sdhci_cd_51_grp"; + st,function = "sdhci"; + }; + i2s { + st,pins = "i2s_grp"; + st,function = "i2s"; + }; + uart1 { + st,pins = "uart1_grp"; + st,function = "uart1"; + }; + uart2 { + st,pins = "uart2_grp"; + st,function = "uart2"; + }; + can0 { + st,pins = "can0_grp"; + st,function = "can0"; + }; + can1 { + st,pins = "can1_grp"; + st,function = "can1"; + }; + mii2 { + st,pins = "mii2_grp"; + st,function = "mii2"; + }; + pwm0_1 { + st,pins = "pwm0_1_pin_14_15_grp"; + st,function = "pwm0_1"; + }; + pwm2 { + st,pins = "pwm2_pin_13_grp"; + st,function = "pwm2"; + }; + }; + }; + + clcd@90000000 { + status = "okay"; + }; + + dma@fc400000 { + status = "okay"; + }; + + fsmc: flash@4c000000 { + status = "okay"; + }; + + gmac: eth@e0800000 { + status = "okay"; + }; + + sdhci@70000000 { + power-gpio = <&gpio0 2 1>; + power_always_enb; + status = "okay"; + }; + + smi: flash@fc000000 { + status = "okay"; + }; + + spi0: spi@d0100000 { + status = "okay"; + }; + + spi1: spi@a5000000 { + status = "okay"; + }; + + spi2: spi@a6000000 { + status = "okay"; + }; + + ehci@e1800000 { + status = "okay"; + }; + + ohci@e1900000 { + status = "okay"; + }; + + ohci@e2100000 { + status = "okay"; + }; + + apb { + gpio0: gpio@fc980000 { + status = "okay"; + }; + + i2c0: i2c@d0180000 { + status = "okay"; + }; + + i2c1: i2c@a7000000 { + status = "okay"; + }; + + rtc@fc900000 { + status = "okay"; + }; + + serial@d0000000 { + status = "okay"; + }; + + serial@a3000000 { + status = "okay"; + }; + + serial@a4000000 { + status = "okay"; + }; + + wdt@fc880000 { + status = "okay"; + }; + }; + }; +}; diff --git a/trunk/arch/arm/boot/dts/spear320.dtsi b/trunk/arch/arm/boot/dts/spear320.dtsi new file mode 100644 index 000000000000..5372ca399b1f --- /dev/null +++ b/trunk/arch/arm/boot/dts/spear320.dtsi @@ -0,0 +1,95 @@ +/* + * DTS file for SPEAr320 SoC + * + * Copyright 2012 Viresh Kumar + * + * 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/ "spear3xx.dtsi" + +/ { + ahb { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges = <0x40000000 0x40000000 0x80000000 + 0xd0000000 0xd0000000 0x30000000>; + + pinmux@b3000000 { + compatible = "st,spear320-pinmux"; + reg = <0xb3000000 0x1000>; + }; + + clcd@90000000 { + compatible = "arm,clcd-pl110", "arm,primecell"; + reg = <0x90000000 0x1000>; + interrupts = <33>; + status = "disabled"; + }; + + fsmc: flash@4c000000 { + compatible = "st,spear600-fsmc-nand"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x4c000000 0x1000 /* FSMC Register */ + 0x50000000 0x0010>; /* NAND Base */ + reg-names = "fsmc_regs", "nand_data"; + st,ale-off = <0x20000>; + st,cle-off = <0x10000>; + status = "disabled"; + }; + + sdhci@70000000 { + compatible = "st,sdhci-spear"; + reg = <0x70000000 0x100>; + interrupts = <29>; + status = "disabled"; + }; + + spi1: spi@a5000000 { + compatible = "arm,pl022", "arm,primecell"; + reg = <0xa5000000 0x1000>; + status = "disabled"; + }; + + spi2: spi@a6000000 { + compatible = "arm,pl022", "arm,primecell"; + reg = <0xa6000000 0x1000>; + status = "disabled"; + }; + + apb { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges = <0xa0000000 0xa0000000 0x10000000 + 0xd0000000 0xd0000000 0x30000000>; + + i2c1: i2c@a7000000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,designware-i2c"; + reg = <0xa7000000 0x1000>; + status = "disabled"; + }; + + serial@a3000000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0xa3000000 0x1000>; + status = "disabled"; + }; + + serial@a4000000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0xa4000000 0x1000>; + status = "disabled"; + }; + }; + }; +}; diff --git a/trunk/arch/arm/boot/dts/spear3xx.dtsi b/trunk/arch/arm/boot/dts/spear3xx.dtsi new file mode 100644 index 000000000000..0ae7c8e86311 --- /dev/null +++ b/trunk/arch/arm/boot/dts/spear3xx.dtsi @@ -0,0 +1,144 @@ +/* + * DTS file for all SPEAr3xx SoCs + * + * Copyright 2012 Viresh Kumar + * + * 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/ "skeleton.dtsi" + +/ { + interrupt-parent = <&vic>; + + cpus { + cpu@0 { + compatible = "arm,arm926ejs"; + }; + }; + + memory { + device_type = "memory"; + reg = <0 0x40000000>; + }; + + ahb { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges = <0xd0000000 0xd0000000 0x30000000>; + + vic: interrupt-controller@f1100000 { + compatible = "arm,pl190-vic"; + interrupt-controller; + reg = <0xf1100000 0x1000>; + #interrupt-cells = <1>; + }; + + dma@fc400000 { + compatible = "arm,pl080", "arm,primecell"; + reg = <0xfc400000 0x1000>; + interrupt-parent = <&vic>; + interrupts = <8>; + status = "disabled"; + }; + + gmac: eth@e0800000 { + compatible = "st,spear600-gmac"; + reg = <0xe0800000 0x8000>; + interrupts = <23 22>; + interrupt-names = "macirq", "eth_wake_irq"; + status = "disabled"; + }; + + smi: flash@fc000000 { + compatible = "st,spear600-smi"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xfc000000 0x1000>; + interrupts = <9>; + status = "disabled"; + }; + + spi0: spi@d0100000 { + compatible = "arm,pl022", "arm,primecell"; + reg = <0xd0100000 0x1000>; + interrupts = <20>; + status = "disabled"; + }; + + ehci@e1800000 { + compatible = "st,spear600-ehci", "usb-ehci"; + reg = <0xe1800000 0x1000>; + interrupts = <26>; + status = "disabled"; + }; + + ohci@e1900000 { + compatible = "st,spear600-ohci", "usb-ohci"; + reg = <0xe1900000 0x1000>; + interrupts = <25>; + status = "disabled"; + }; + + ohci@e2100000 { + compatible = "st,spear600-ohci", "usb-ohci"; + reg = <0xe2100000 0x1000>; + interrupts = <27>; + status = "disabled"; + }; + + apb { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges = <0xd0000000 0xd0000000 0x30000000>; + + gpio0: gpio@fc980000 { + compatible = "arm,pl061", "arm,primecell"; + reg = <0xfc980000 0x1000>; + interrupts = <11>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + status = "disabled"; + }; + + i2c0: i2c@d0180000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,designware-i2c"; + reg = <0xd0180000 0x1000>; + interrupts = <21>; + status = "disabled"; + }; + + rtc@fc900000 { + compatible = "st,spear-rtc"; + reg = <0xfc900000 0x1000>; + interrupts = <10>; + status = "disabled"; + }; + + serial@d0000000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0xd0000000 0x1000>; + interrupts = <19>; + status = "disabled"; + }; + + wdt@fc880000 { + compatible = "arm,sp805", "arm,primecell"; + reg = <0xfc880000 0x1000>; + interrupts = <12>; + status = "disabled"; + }; + }; + }; +}; diff --git a/trunk/arch/arm/boot/dts/spear600-evb.dts b/trunk/arch/arm/boot/dts/spear600-evb.dts index 636292e18c90..790a7a8a5ccd 100644 --- a/trunk/arch/arm/boot/dts/spear600-evb.dts +++ b/trunk/arch/arm/boot/dts/spear600-evb.dts @@ -24,6 +24,10 @@ }; ahb { + dma@fc400000 { + status = "okay"; + }; + gmac: ethernet@e0800000 { phy-mode = "gmii"; status = "okay"; diff --git a/trunk/arch/arm/boot/dts/spear600.dtsi b/trunk/arch/arm/boot/dts/spear600.dtsi index ebe0885a2b98..d777e3a6f178 100644 --- a/trunk/arch/arm/boot/dts/spear600.dtsi +++ b/trunk/arch/arm/boot/dts/spear600.dtsi @@ -45,6 +45,14 @@ #interrupt-cells = <1>; }; + dma@fc400000 { + compatible = "arm,pl080", "arm,primecell"; + reg = <0xfc400000 0x1000>; + interrupt-parent = <&vic1>; + interrupts = <10>; + status = "disabled"; + }; + gmac: ethernet@e0800000 { compatible = "st,spear600-gmac"; reg = <0xe0800000 0x8000>; diff --git a/trunk/arch/arm/boot/dts/tegra-cardhu.dts b/trunk/arch/arm/boot/dts/tegra-cardhu.dts index ac3fb7558459..0a9f34a2c3aa 100644 --- a/trunk/arch/arm/boot/dts/tegra-cardhu.dts +++ b/trunk/arch/arm/boot/dts/tegra-cardhu.dts @@ -10,6 +10,50 @@ reg = < 0x80000000 0x40000000 >; }; + pinmux@70000000 { + pinctrl-names = "default"; + pinctrl-0 = <&state_default>; + + state_default: pinmux { + sdmmc1_clk_pz0 { + nvidia,pins = "sdmmc1_clk_pz0"; + nvidia,function = "sdmmc1"; + nvidia,pull = <0>; + nvidia,tristate = <0>; + }; + sdmmc1_cmd_pz1 { + nvidia,pins = "sdmmc1_cmd_pz1", + "sdmmc1_dat0_py7", + "sdmmc1_dat1_py6", + "sdmmc1_dat2_py5", + "sdmmc1_dat3_py4"; + nvidia,function = "sdmmc1"; + nvidia,pull = <2>; + nvidia,tristate = <0>; + }; + sdmmc4_clk_pcc4 { + nvidia,pins = "sdmmc4_clk_pcc4", + "sdmmc4_rst_n_pcc3"; + nvidia,function = "sdmmc4"; + nvidia,pull = <0>; + nvidia,tristate = <0>; + }; + sdmmc4_dat0_paa0 { + nvidia,pins = "sdmmc4_dat0_paa0", + "sdmmc4_dat1_paa1", + "sdmmc4_dat2_paa2", + "sdmmc4_dat3_paa3", + "sdmmc4_dat4_paa4", + "sdmmc4_dat5_paa5", + "sdmmc4_dat6_paa6", + "sdmmc4_dat7_paa7"; + nvidia,function = "sdmmc4"; + nvidia,pull = <2>; + nvidia,tristate = <0>; + }; + }; + }; + serial@70006000 { clock-frequency = < 408000000 >; }; diff --git a/trunk/arch/arm/boot/dts/tegra-harmony.dts b/trunk/arch/arm/boot/dts/tegra-harmony.dts index 6e8447dc0202..1a0b1f182944 100644 --- a/trunk/arch/arm/boot/dts/tegra-harmony.dts +++ b/trunk/arch/arm/boot/dts/tegra-harmony.dts @@ -10,6 +10,230 @@ reg = < 0x00000000 0x40000000 >; }; + pinmux@70000000 { + pinctrl-names = "default"; + pinctrl-0 = <&state_default>; + + state_default: pinmux { + ata { + nvidia,pins = "ata"; + nvidia,function = "ide"; + }; + atb { + nvidia,pins = "atb", "gma", "gme"; + nvidia,function = "sdio4"; + }; + atc { + nvidia,pins = "atc"; + nvidia,function = "nand"; + }; + atd { + nvidia,pins = "atd", "ate", "gmb", "gmd", "gpu", + "spia", "spib", "spic"; + nvidia,function = "gmi"; + }; + cdev1 { + nvidia,pins = "cdev1"; + nvidia,function = "plla_out"; + }; + cdev2 { + nvidia,pins = "cdev2"; + nvidia,function = "pllp_out4"; + }; + crtp { + nvidia,pins = "crtp"; + nvidia,function = "crt"; + }; + csus { + nvidia,pins = "csus"; + nvidia,function = "vi_sensor_clk"; + }; + dap1 { + nvidia,pins = "dap1"; + nvidia,function = "dap1"; + }; + dap2 { + nvidia,pins = "dap2"; + nvidia,function = "dap2"; + }; + dap3 { + nvidia,pins = "dap3"; + nvidia,function = "dap3"; + }; + dap4 { + nvidia,pins = "dap4"; + nvidia,function = "dap4"; + }; + ddc { + nvidia,pins = "ddc"; + nvidia,function = "i2c2"; + }; + dta { + nvidia,pins = "dta", "dtd"; + nvidia,function = "sdio2"; + }; + dtb { + nvidia,pins = "dtb", "dtc", "dte"; + nvidia,function = "rsvd1"; + }; + dtf { + nvidia,pins = "dtf"; + nvidia,function = "i2c3"; + }; + gmc { + nvidia,pins = "gmc"; + nvidia,function = "uartd"; + }; + gpu7 { + nvidia,pins = "gpu7"; + nvidia,function = "rtck"; + }; + gpv { + nvidia,pins = "gpv", "slxa", "slxk"; + nvidia,function = "pcie"; + }; + hdint { + nvidia,pins = "hdint", "pta"; + nvidia,function = "hdmi"; + }; + i2cp { + nvidia,pins = "i2cp"; + nvidia,function = "i2cp"; + }; + irrx { + nvidia,pins = "irrx", "irtx"; + nvidia,function = "uarta"; + }; + kbca { + nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd", + "kbce", "kbcf"; + nvidia,function = "kbc"; + }; + lcsn { + nvidia,pins = "lcsn", "ld0", "ld1", "ld2", + "ld3", "ld4", "ld5", "ld6", "ld7", + "ld8", "ld9", "ld10", "ld11", "ld12", + "ld13", "ld14", "ld15", "ld16", "ld17", + "ldc", "ldi", "lhp0", "lhp1", "lhp2", + "lhs", "lm0", "lm1", "lpp", "lpw0", + "lpw1", "lpw2", "lsc0", "lsc1", "lsck", + "lsda", "lsdi", "lspi", "lvp0", "lvp1", + "lvs"; + nvidia,function = "displaya"; + }; + owc { + nvidia,pins = "owc", "spdi", "spdo", "uac"; + nvidia,function = "rsvd2"; + }; + pmc { + nvidia,pins = "pmc"; + nvidia,function = "pwr_on"; + }; + rm { + nvidia,pins = "rm"; + nvidia,function = "i2c1"; + }; + sdb { + nvidia,pins = "sdb", "sdc", "sdd"; + nvidia,function = "pwm"; + }; + sdio1 { + nvidia,pins = "sdio1"; + nvidia,function = "sdio1"; + }; + slxc { + nvidia,pins = "slxc", "slxd"; + nvidia,function = "spdif"; + }; + spid { + nvidia,pins = "spid", "spie", "spif"; + nvidia,function = "spi1"; + }; + spig { + nvidia,pins = "spig", "spih"; + nvidia,function = "spi2_alt"; + }; + uaa { + nvidia,pins = "uaa", "uab", "uda"; + nvidia,function = "ulpi"; + }; + uad { + nvidia,pins = "uad"; + nvidia,function = "irda"; + }; + uca { + nvidia,pins = "uca", "ucb"; + nvidia,function = "uartc"; + }; + conf_ata { + nvidia,pins = "ata", "atb", "atc", "atd", "ate", + "cdev1", "dap1", "dtb", "gma", "gmb", + "gmc", "gmd", "gme", "gpu7", "gpv", + "i2cp", "pta", "rm", "slxa", "slxk", + "spia", "spib"; + nvidia,pull = <0>; + nvidia,tristate = <0>; + }; + conf_cdev2 { + nvidia,pins = "cdev2", "csus", "spid", "spif"; + nvidia,pull = <1>; + nvidia,tristate = <1>; + }; + conf_ck32 { + nvidia,pins = "ck32", "ddrc", "pmca", "pmcb", + "pmcc", "pmcd", "pmce", "xm2c", "xm2d"; + nvidia,pull = <0>; + }; + conf_crtp { + nvidia,pins = "crtp", "dap2", "dap3", "dap4", + "dtc", "dte", "dtf", "gpu", "sdio1", + "slxc", "slxd", "spdi", "spdo", "spig", + "uac", "uda"; + nvidia,pull = <0>; + nvidia,tristate = <1>; + }; + conf_ddc { + nvidia,pins = "ddc", "dta", "dtd", "kbca", + "kbcb", "kbcc", "kbcd", "kbce", "kbcf", + "sdc"; + nvidia,pull = <2>; + nvidia,tristate = <0>; + }; + conf_hdint { + nvidia,pins = "hdint", "lcsn", "ldc", "lm1", + "lpw1", "lsc1", "lsck", "lsda", "lsdi", + "lvp0", "owc", "sdb"; + nvidia,tristate = <1>; + }; + conf_irrx { + nvidia,pins = "irrx", "irtx", "sdd", "spic", + "spie", "spih", "uaa", "uab", "uad", + "uca", "ucb"; + nvidia,pull = <2>; + nvidia,tristate = <1>; + }; + conf_lc { + nvidia,pins = "lc", "ls"; + nvidia,pull = <2>; + }; + conf_ld0 { + nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4", + "ld5", "ld6", "ld7", "ld8", "ld9", + "ld10", "ld11", "ld12", "ld13", "ld14", + "ld15", "ld16", "ld17", "ldi", "lhp0", + "lhp1", "lhp2", "lhs", "lm0", "lpp", + "lpw0", "lpw2", "lsc0", "lspi", "lvp1", + "lvs", "pmc"; + nvidia,tristate = <0>; + }; + conf_ld17_0 { + nvidia,pins = "ld17_0", "ld19_18", "ld21_20", + "ld23_22"; + nvidia,pull = <1>; + }; + }; + }; + pmc@7000f400 { nvidia,invert-interrupt; }; diff --git a/trunk/arch/arm/boot/dts/tegra-paz00.dts b/trunk/arch/arm/boot/dts/tegra-paz00.dts index 6c02abb469d4..10943fb2561c 100644 --- a/trunk/arch/arm/boot/dts/tegra-paz00.dts +++ b/trunk/arch/arm/boot/dts/tegra-paz00.dts @@ -10,6 +10,226 @@ reg = <0x00000000 0x20000000>; }; + pinmux@70000000 { + pinctrl-names = "default"; + pinctrl-0 = <&state_default>; + + state_default: pinmux { + ata { + nvidia,pins = "ata", "atc", "atd", "ate", + "dap2", "gmb", "gmc", "gmd", "spia", + "spib", "spic", "spid", "spie"; + nvidia,function = "gmi"; + }; + atb { + nvidia,pins = "atb", "gma", "gme"; + nvidia,function = "sdio4"; + }; + cdev1 { + nvidia,pins = "cdev1"; + nvidia,function = "plla_out"; + }; + cdev2 { + nvidia,pins = "cdev2"; + nvidia,function = "pllp_out4"; + }; + crtp { + nvidia,pins = "crtp"; + nvidia,function = "crt"; + }; + csus { + nvidia,pins = "csus"; + nvidia,function = "pllc_out1"; + }; + dap1 { + nvidia,pins = "dap1"; + nvidia,function = "dap1"; + }; + dap3 { + nvidia,pins = "dap3"; + nvidia,function = "dap3"; + }; + dap4 { + nvidia,pins = "dap4"; + nvidia,function = "dap4"; + }; + ddc { + nvidia,pins = "ddc"; + nvidia,function = "i2c2"; + }; + dta { + nvidia,pins = "dta", "dtb", "dtc", "dtd", "dte"; + nvidia,function = "rsvd1"; + }; + dtf { + nvidia,pins = "dtf"; + nvidia,function = "i2c3"; + }; + gpu { + nvidia,pins = "gpu", "sdb", "sdd"; + nvidia,function = "pwm"; + }; + gpu7 { + nvidia,pins = "gpu7"; + nvidia,function = "rtck"; + }; + gpv { + nvidia,pins = "gpv", "slxa", "slxk"; + nvidia,function = "pcie"; + }; + hdint { + nvidia,pins = "hdint", "pta"; + nvidia,function = "hdmi"; + }; + i2cp { + nvidia,pins = "i2cp"; + nvidia,function = "i2cp"; + }; + irrx { + nvidia,pins = "irrx", "irtx"; + nvidia,function = "uarta"; + }; + kbca { + nvidia,pins = "kbca", "kbcc", "kbce", "kbcf"; + nvidia,function = "kbc"; + }; + kbcb { + nvidia,pins = "kbcb", "kbcd"; + nvidia,function = "sdio2"; + }; + lcsn { + nvidia,pins = "lcsn", "ld0", "ld1", "ld2", + "ld3", "ld4", "ld5", "ld6", "ld7", + "ld8", "ld9", "ld10", "ld11", "ld12", + "ld13", "ld14", "ld15", "ld16", "ld17", + "ldc", "ldi", "lhp0", "lhp1", "lhp2", + "lhs", "lm0", "lm1", "lpp", "lpw0", + "lpw1", "lpw2", "lsc0", "lsc1", "lsck", + "lsda", "lsdi", "lspi", "lvp0", "lvp1", + "lvs"; + nvidia,function = "displaya"; + }; + owc { + nvidia,pins = "owc"; + nvidia,function = "owr"; + }; + pmc { + nvidia,pins = "pmc"; + nvidia,function = "pwr_on"; + }; + rm { + nvidia,pins = "rm"; + nvidia,function = "i2c1"; + }; + sdc { + nvidia,pins = "sdc"; + nvidia,function = "twc"; + }; + sdio1 { + nvidia,pins = "sdio1"; + nvidia,function = "sdio1"; + }; + slxc { + nvidia,pins = "slxc", "slxd"; + nvidia,function = "spi4"; + }; + spdi { + nvidia,pins = "spdi", "spdo"; + nvidia,function = "rsvd2"; + }; + spif { + nvidia,pins = "spif", "uac"; + nvidia,function = "rsvd4"; + }; + spig { + nvidia,pins = "spig", "spih"; + nvidia,function = "spi2_alt"; + }; + uaa { + nvidia,pins = "uaa", "uab", "uda"; + nvidia,function = "ulpi"; + }; + uad { + nvidia,pins = "uad"; + nvidia,function = "spdif"; + }; + uca { + nvidia,pins = "uca", "ucb"; + nvidia,function = "uartc"; + }; + conf_ata { + nvidia,pins = "ata", "atb", "atc", "atd", "ate", + "cdev1", "dap1", "dap2", "dtf", "gma", + "gmb", "gmc", "gmd", "gme", "gpu", + "gpu7", "gpv", "i2cp", "pta", "rm", + "sdio1", "slxk", "spdo", "uac", "uda"; + nvidia,pull = <0>; + nvidia,tristate = <0>; + }; + conf_cdev2 { + nvidia,pins = "cdev2"; + nvidia,pull = <1>; + nvidia,tristate = <0>; + }; + conf_ck32 { + nvidia,pins = "ck32", "ddrc", "pmca", "pmcb", + "pmcc", "pmcd", "pmce", "xm2c", "xm2d"; + nvidia,pull = <0>; + }; + conf_crtp { + nvidia,pins = "crtp", "dap3", "dap4", "dtb", + "dtc", "dte", "slxa", "slxc", "slxd", + "spdi"; + nvidia,pull = <0>; + nvidia,tristate = <1>; + }; + conf_csus { + nvidia,pins = "csus", "spia", "spib", "spid", + "spif"; + nvidia,pull = <1>; + nvidia,tristate = <1>; + }; + conf_ddc { + nvidia,pins = "ddc", "irrx", "irtx", "kbca", + "kbcb", "kbcc", "kbcd", "kbce", "kbcf", + "spic", "spig", "uaa", "uab"; + nvidia,pull = <2>; + nvidia,tristate = <0>; + }; + conf_dta { + nvidia,pins = "dta", "dtd", "owc", "sdc", "sdd", + "spie", "spih", "uad", "uca", "ucb"; + nvidia,pull = <2>; + nvidia,tristate = <1>; + }; + conf_hdint { + nvidia,pins = "hdint", "ld0", "ld1", "ld2", + "ld3", "ld4", "ld5", "ld6", "ld7", + "ld8", "ld9", "ld10", "ld11", "ld12", + "ld13", "ld14", "ld15", "ld16", "ld17", + "ldc", "ldi", "lhs", "lsc0", "lspi", + "lvs", "pmc"; + nvidia,tristate = <0>; + }; + conf_lc { + nvidia,pins = "lc", "ls"; + nvidia,pull = <2>; + }; + conf_lcsn { + nvidia,pins = "lcsn", "lhp0", "lhp1", "lhp2", + "lm0", "lm1", "lpp", "lpw0", "lpw1", + "lpw2", "lsc1", "lsck", "lsda", "lsdi", + "lvp0", "lvp1", "sdb"; + nvidia,tristate = <1>; + }; + conf_ld17_0 { + nvidia,pins = "ld17_0", "ld19_18", "ld21_20", + "ld23_22"; + nvidia,pull = <1>; + }; + }; + }; + i2c@7000c000 { clock-frequency = <400000>; diff --git a/trunk/arch/arm/boot/dts/tegra-seaboard.dts b/trunk/arch/arm/boot/dts/tegra-seaboard.dts index dbf1c5a171c2..ec33116f5df9 100644 --- a/trunk/arch/arm/boot/dts/tegra-seaboard.dts +++ b/trunk/arch/arm/boot/dts/tegra-seaboard.dts @@ -11,6 +11,249 @@ reg = < 0x00000000 0x40000000 >; }; + pinmux@70000000 { + pinctrl-names = "default"; + pinctrl-0 = <&state_default>; + + state_default: pinmux { + ata { + nvidia,pins = "ata"; + nvidia,function = "ide"; + }; + atb { + nvidia,pins = "atb", "gma", "gme"; + nvidia,function = "sdio4"; + }; + atc { + nvidia,pins = "atc"; + nvidia,function = "nand"; + }; + atd { + nvidia,pins = "atd", "ate", "gmb", "spia", + "spib", "spic"; + nvidia,function = "gmi"; + }; + cdev1 { + nvidia,pins = "cdev1"; + nvidia,function = "plla_out"; + }; + cdev2 { + nvidia,pins = "cdev2"; + nvidia,function = "pllp_out4"; + }; + crtp { + nvidia,pins = "crtp", "lm1"; + nvidia,function = "crt"; + }; + csus { + nvidia,pins = "csus"; + nvidia,function = "vi_sensor_clk"; + }; + dap1 { + nvidia,pins = "dap1"; + nvidia,function = "dap1"; + }; + dap2 { + nvidia,pins = "dap2"; + nvidia,function = "dap2"; + }; + dap3 { + nvidia,pins = "dap3"; + nvidia,function = "dap3"; + }; + dap4 { + nvidia,pins = "dap4"; + nvidia,function = "dap4"; + }; + ddc { + nvidia,pins = "ddc", "owc", "spdi", "spdo", + "uac"; + nvidia,function = "rsvd2"; + }; + dta { + nvidia,pins = "dta", "dtb", "dtc", "dtd", "dte"; + nvidia,function = "vi"; + }; + dtf { + nvidia,pins = "dtf"; + nvidia,function = "i2c3"; + }; + gmc { + nvidia,pins = "gmc"; + nvidia,function = "uartd"; + }; + gmd { + nvidia,pins = "gmd"; + nvidia,function = "sflash"; + }; + gpu { + nvidia,pins = "gpu"; + nvidia,function = "pwm"; + }; + gpu7 { + nvidia,pins = "gpu7"; + nvidia,function = "rtck"; + }; + gpv { + nvidia,pins = "gpv", "slxa", "slxk"; + nvidia,function = "pcie"; + }; + hdint { + nvidia,pins = "hdint", "lpw0", "lpw2", "lsc1", + "lsck", "lsda", "pta"; + nvidia,function = "hdmi"; + }; + i2cp { + nvidia,pins = "i2cp"; + nvidia,function = "i2cp"; + }; + irrx { + nvidia,pins = "irrx", "irtx"; + nvidia,function = "uartb"; + }; + kbca { + nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd", + "kbce", "kbcf"; + nvidia,function = "kbc"; + }; + lcsn { + nvidia,pins = "lcsn", "ldc", "lm0", "lpw1", + "lsdi", "lvp0"; + nvidia,function = "rsvd4"; + }; + ld0 { + nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4", + "ld5", "ld6", "ld7", "ld8", "ld9", + "ld10", "ld11", "ld12", "ld13", "ld14", + "ld15", "ld16", "ld17", "ldi", "lhp0", + "lhp1", "lhp2", "lhs", "lpp", "lsc0", + "lspi", "lvp1", "lvs"; + nvidia,function = "displaya"; + }; + pmc { + nvidia,pins = "pmc"; + nvidia,function = "pwr_on"; + }; + rm { + nvidia,pins = "rm"; + nvidia,function = "i2c1"; + }; + sdb { + nvidia,pins = "sdb", "sdc", "sdd"; + nvidia,function = "sdio3"; + }; + sdio1 { + nvidia,pins = "sdio1"; + nvidia,function = "sdio1"; + }; + slxc { + nvidia,pins = "slxc", "slxd"; + nvidia,function = "spdif"; + }; + spid { + nvidia,pins = "spid", "spie", "spif"; + nvidia,function = "spi1"; + }; + spig { + nvidia,pins = "spig", "spih"; + nvidia,function = "spi2_alt"; + }; + uaa { + nvidia,pins = "uaa", "uab", "uda"; + nvidia,function = "ulpi"; + }; + uad { + nvidia,pins = "uad"; + nvidia,function = "irda"; + }; + uca { + nvidia,pins = "uca", "ucb"; + nvidia,function = "uartc"; + }; + conf_ata { + nvidia,pins = "ata", "atb", "atc", "atd", + "cdev1", "cdev2", "dap1", "dap2", + "dap4", "dtf", "gma", "gmc", "gmd", + "gme", "gpu", "gpu7", "i2cp", "irrx", + "irtx", "pta", "rm", "sdc", "sdd", + "slxd", "slxk", "spdi", "spdo", "uac", + "uad", "uca", "ucb", "uda"; + nvidia,pull = <0>; + nvidia,tristate = <0>; + }; + conf_ate { + nvidia,pins = "ate", "csus", "dap3", "ddc", + "gpv", "owc", "slxc", "spib", "spid", + "spie"; + nvidia,pull = <0>; + nvidia,tristate = <1>; + }; + conf_ck32 { + nvidia,pins = "ck32", "ddrc", "pmca", "pmcb", + "pmcc", "pmcd", "pmce", "xm2c", "xm2d"; + nvidia,pull = <0>; + }; + conf_crtp { + nvidia,pins = "crtp", "gmb", "slxa", "spia", + "spig", "spih"; + nvidia,pull = <2>; + nvidia,tristate = <1>; + }; + conf_dta { + nvidia,pins = "dta", "dtb", "dtc", "dtd"; + nvidia,pull = <1>; + nvidia,tristate = <0>; + }; + conf_dte { + nvidia,pins = "dte", "spif"; + nvidia,pull = <1>; + nvidia,tristate = <1>; + }; + conf_hdint { + nvidia,pins = "hdint", "lcsn", "ldc", "lm1", + "lpw1", "lsc1", "lsck", "lsda", "lsdi", + "lvp0"; + nvidia,tristate = <1>; + }; + conf_kbca { + nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd", + "kbce", "kbcf", "sdio1", "spic", "uaa", + "uab"; + nvidia,pull = <2>; + nvidia,tristate = <0>; + }; + conf_lc { + nvidia,pins = "lc", "ls"; + nvidia,pull = <2>; + }; + conf_ld0 { + nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4", + "ld5", "ld6", "ld7", "ld8", "ld9", + "ld10", "ld11", "ld12", "ld13", "ld14", + "ld15", "ld16", "ld17", "ldi", "lhp0", + "lhp1", "lhp2", "lhs", "lm0", "lpp", + "lpw0", "lpw2", "lsc0", "lspi", "lvp1", + "lvs", "pmc", "sdb"; + nvidia,tristate = <0>; + }; + conf_ld17_0 { + nvidia,pins = "ld17_0", "ld19_18", "ld21_20", + "ld23_22"; + nvidia,pull = <1>; + }; + drive_sdio1 { + nvidia,pins = "drive_sdio1"; + nvidia,high-speed-mode = <0>; + nvidia,schmitt = <0>; + nvidia,low-power-mode = <3>; + nvidia,pull-down-strength = <31>; + nvidia,pull-up-strength = <31>; + nvidia,slew-rate-rising = <3>; + nvidia,slew-rate-falling = <3>; + }; + }; + }; + i2c@7000c000 { clock-frequency = <400000>; diff --git a/trunk/arch/arm/boot/dts/tegra-trimslice.dts b/trunk/arch/arm/boot/dts/tegra-trimslice.dts index 252476867b54..98efd5b0d7f9 100644 --- a/trunk/arch/arm/boot/dts/tegra-trimslice.dts +++ b/trunk/arch/arm/boot/dts/tegra-trimslice.dts @@ -10,6 +10,236 @@ reg = < 0x00000000 0x40000000 >; }; + pinmux@70000000 { + pinctrl-names = "default"; + pinctrl-0 = <&state_default>; + + state_default: pinmux { + ata { + nvidia,pins = "ata"; + nvidia,function = "ide"; + }; + atb { + nvidia,pins = "atb", "gma"; + nvidia,function = "sdio4"; + }; + atc { + nvidia,pins = "atc", "gmb"; + nvidia,function = "nand"; + }; + atd { + nvidia,pins = "atd", "ate", "gme", "pta"; + nvidia,function = "gmi"; + }; + cdev1 { + nvidia,pins = "cdev1"; + nvidia,function = "plla_out"; + }; + cdev2 { + nvidia,pins = "cdev2"; + nvidia,function = "pllp_out4"; + }; + crtp { + nvidia,pins = "crtp"; + nvidia,function = "crt"; + }; + csus { + nvidia,pins = "csus"; + nvidia,function = "vi_sensor_clk"; + }; + dap1 { + nvidia,pins = "dap1"; + nvidia,function = "dap1"; + }; + dap2 { + nvidia,pins = "dap2"; + nvidia,function = "dap2"; + }; + dap3 { + nvidia,pins = "dap3"; + nvidia,function = "dap3"; + }; + dap4 { + nvidia,pins = "dap4"; + nvidia,function = "dap4"; + }; + ddc { + nvidia,pins = "ddc"; + nvidia,function = "i2c2"; + }; + dta { + nvidia,pins = "dta", "dtb", "dtc", "dtd", "dte"; + nvidia,function = "vi"; + }; + dtf { + nvidia,pins = "dtf"; + nvidia,function = "i2c3"; + }; + gmc { + nvidia,pins = "gmc", "gmd"; + nvidia,function = "sflash"; + }; + gpu { + nvidia,pins = "gpu"; + nvidia,function = "uarta"; + }; + gpu7 { + nvidia,pins = "gpu7"; + nvidia,function = "rtck"; + }; + gpv { + nvidia,pins = "gpv", "slxa", "slxk"; + nvidia,function = "pcie"; + }; + hdint { + nvidia,pins = "hdint"; + nvidia,function = "hdmi"; + }; + i2cp { + nvidia,pins = "i2cp"; + nvidia,function = "i2cp"; + }; + irrx { + nvidia,pins = "irrx", "irtx"; + nvidia,function = "uartb"; + }; + kbca { + nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd", + "kbce", "kbcf"; + nvidia,function = "kbc"; + }; + lcsn { + nvidia,pins = "lcsn", "ld0", "ld1", "ld2", + "ld3", "ld4", "ld5", "ld6", "ld7", + "ld8", "ld9", "ld10", "ld11", "ld12", + "ld13", "ld14", "ld15", "ld16", "ld17", + "ldc", "ldi", "lhp0", "lhp1", "lhp2", + "lhs", "lm0", "lm1", "lpp", "lpw0", + "lpw1", "lpw2", "lsc0", "lsc1", "lsck", + "lsda", "lsdi", "lspi", "lvp0", "lvp1", + "lvs"; + nvidia,function = "displaya"; + }; + owc { + nvidia,pins = "owc", "uac"; + nvidia,function = "rsvd2"; + }; + pmc { + nvidia,pins = "pmc"; + nvidia,function = "pwr_on"; + }; + rm { + nvidia,pins = "rm"; + nvidia,function = "i2c1"; + }; + sdb { + nvidia,pins = "sdb", "sdc", "sdd"; + nvidia,function = "pwm"; + }; + sdio1 { + nvidia,pins = "sdio1"; + nvidia,function = "sdio1"; + }; + slxc { + nvidia,pins = "slxc", "slxd"; + nvidia,function = "sdio3"; + }; + spdi { + nvidia,pins = "spdi", "spdo"; + nvidia,function = "spdif"; + }; + spia { + nvidia,pins = "spia", "spib", "spic"; + nvidia,function = "spi2"; + }; + spid { + nvidia,pins = "spid", "spie", "spif"; + nvidia,function = "spi1"; + }; + spig { + nvidia,pins = "spig", "spih"; + nvidia,function = "spi2_alt"; + }; + uaa { + nvidia,pins = "uaa", "uab", "uda"; + nvidia,function = "ulpi"; + }; + uad { + nvidia,pins = "uad"; + nvidia,function = "irda"; + }; + uca { + nvidia,pins = "uca", "ucb"; + nvidia,function = "uartc"; + }; + conf_ata { + nvidia,pins = "ata", "atc", "atd", "ate", + "crtp", "dap2", "dap3", "dap4", "dta", + "dtb", "dtc", "dtd", "dte", "gmb", + "gme", "i2cp", "pta", "slxc", "slxd", + "spdi", "spdo", "uda"; + nvidia,pull = <0>; + nvidia,tristate = <1>; + }; + conf_atb { + nvidia,pins = "atb", "cdev1", "dap1", "gma", + "gmc", "gmd", "gpu", "gpu7", "gpv", + "sdio1", "slxa", "slxk", "uac"; + nvidia,pull = <0>; + nvidia,tristate = <0>; + }; + conf_cdev2 { + nvidia,pins = "cdev2", "csus", "spia", "spib", + "spid", "spif"; + nvidia,pull = <1>; + nvidia,tristate = <1>; + }; + conf_ck32 { + nvidia,pins = "ck32", "ddrc", "pmca", "pmcb", + "pmcc", "pmcd", "pmce", "xm2c", "xm2d"; + nvidia,pull = <0>; + }; + conf_ddc { + nvidia,pins = "ddc", "dtf", "rm", "sdc", "sdd"; + nvidia,pull = <2>; + nvidia,tristate = <0>; + }; + conf_hdint { + nvidia,pins = "hdint", "lcsn", "ldc", "lm1", + "lpw1", "lsc1", "lsck", "lsda", "lsdi", + "lvp0", "pmc"; + nvidia,tristate = <1>; + }; + conf_irrx { + nvidia,pins = "irrx", "irtx", "kbca", "kbcb", + "kbcc", "kbcd", "kbce", "kbcf", "owc", + "spic", "spie", "spig", "spih", "uaa", + "uab", "uad", "uca", "ucb"; + nvidia,pull = <2>; + nvidia,tristate = <1>; + }; + conf_lc { + nvidia,pins = "lc", "ls"; + nvidia,pull = <2>; + }; + conf_ld0 { + nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4", + "ld5", "ld6", "ld7", "ld8", "ld9", + "ld10", "ld11", "ld12", "ld13", "ld14", + "ld15", "ld16", "ld17", "ldi", "lhp0", + "lhp1", "lhp2", "lhs", "lm0", "lpp", + "lpw0", "lpw2", "lsc0", "lspi", "lvp1", + "lvs", "sdb"; + nvidia,tristate = <0>; + }; + conf_ld17_0 { + nvidia,pins = "ld17_0", "ld19_18", "ld21_20", + "ld23_22"; + nvidia,pull = <1>; + }; + }; + }; + i2c@7000c000 { clock-frequency = <400000>; }; diff --git a/trunk/arch/arm/boot/dts/tegra-ventana.dts b/trunk/arch/arm/boot/dts/tegra-ventana.dts index 2dcff8728e90..71eb2e50a668 100644 --- a/trunk/arch/arm/boot/dts/tegra-ventana.dts +++ b/trunk/arch/arm/boot/dts/tegra-ventana.dts @@ -10,6 +10,236 @@ reg = < 0x00000000 0x40000000 >; }; + pinmux@70000000 { + pinctrl-names = "default"; + pinctrl-0 = <&state_default>; + + state_default: pinmux { + ata { + nvidia,pins = "ata"; + nvidia,function = "ide"; + }; + atb { + nvidia,pins = "atb", "gma", "gme"; + nvidia,function = "sdio4"; + }; + atc { + nvidia,pins = "atc"; + nvidia,function = "nand"; + }; + atd { + nvidia,pins = "atd", "ate", "gmb", "spia", + "spib", "spic"; + nvidia,function = "gmi"; + }; + cdev1 { + nvidia,pins = "cdev1"; + nvidia,function = "plla_out"; + }; + cdev2 { + nvidia,pins = "cdev2"; + nvidia,function = "pllp_out4"; + }; + crtp { + nvidia,pins = "crtp", "lm1"; + nvidia,function = "crt"; + }; + csus { + nvidia,pins = "csus"; + nvidia,function = "vi_sensor_clk"; + }; + dap1 { + nvidia,pins = "dap1"; + nvidia,function = "dap1"; + }; + dap2 { + nvidia,pins = "dap2"; + nvidia,function = "dap2"; + }; + dap3 { + nvidia,pins = "dap3"; + nvidia,function = "dap3"; + }; + dap4 { + nvidia,pins = "dap4"; + nvidia,function = "dap4"; + }; + ddc { + nvidia,pins = "ddc", "owc", "spdi", "spdo", + "uac"; + nvidia,function = "rsvd2"; + }; + dta { + nvidia,pins = "dta", "dtb", "dtc", "dtd", "dte"; + nvidia,function = "vi"; + }; + dtf { + nvidia,pins = "dtf"; + nvidia,function = "i2c3"; + }; + gmc { + nvidia,pins = "gmc"; + nvidia,function = "uartd"; + }; + gmd { + nvidia,pins = "gmd"; + nvidia,function = "sflash"; + }; + gpu { + nvidia,pins = "gpu"; + nvidia,function = "pwm"; + }; + gpu7 { + nvidia,pins = "gpu7"; + nvidia,function = "rtck"; + }; + gpv { + nvidia,pins = "gpv", "slxa", "slxk"; + nvidia,function = "pcie"; + }; + hdint { + nvidia,pins = "hdint", "pta"; + nvidia,function = "hdmi"; + }; + i2cp { + nvidia,pins = "i2cp"; + nvidia,function = "i2cp"; + }; + irrx { + nvidia,pins = "irrx", "irtx"; + nvidia,function = "uartb"; + }; + kbca { + nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd", + "kbce", "kbcf"; + nvidia,function = "kbc"; + }; + lcsn { + nvidia,pins = "lcsn", "ldc", "lm0", "lpw1", + "lsdi", "lvp0"; + nvidia,function = "rsvd4"; + }; + ld0 { + nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4", + "ld5", "ld6", "ld7", "ld8", "ld9", + "ld10", "ld11", "ld12", "ld13", "ld14", + "ld15", "ld16", "ld17", "ldi", "lhp0", + "lhp1", "lhp2", "lhs", "lpp", "lpw0", + "lpw2", "lsc0", "lsc1", "lsck", "lsda", + "lspi", "lvp1", "lvs"; + nvidia,function = "displaya"; + }; + pmc { + nvidia,pins = "pmc"; + nvidia,function = "pwr_on"; + }; + rm { + nvidia,pins = "rm"; + nvidia,function = "i2c1"; + }; + sdb { + nvidia,pins = "sdb", "sdc", "sdd", "slxc"; + nvidia,function = "sdio3"; + }; + sdio1 { + nvidia,pins = "sdio1"; + nvidia,function = "sdio1"; + }; + slxd { + nvidia,pins = "slxd"; + nvidia,function = "spdif"; + }; + spid { + nvidia,pins = "spid", "spie", "spif"; + nvidia,function = "spi1"; + }; + spig { + nvidia,pins = "spig", "spih"; + nvidia,function = "spi2_alt"; + }; + uaa { + nvidia,pins = "uaa", "uab", "uda"; + nvidia,function = "ulpi"; + }; + uad { + nvidia,pins = "uad"; + nvidia,function = "irda"; + }; + uca { + nvidia,pins = "uca", "ucb"; + nvidia,function = "uartc"; + }; + conf_ata { + nvidia,pins = "ata", "atb", "atc", "atd", + "cdev1", "cdev2", "dap1", "dap2", + "dap4", "ddc", "dtf", "gma", "gmc", + "gme", "gpu", "gpu7", "i2cp", "irrx", + "irtx", "pta", "rm", "sdc", "sdd", + "slxc", "slxd", "slxk", "spdi", "spdo", + "uac", "uad", "uca", "ucb", "uda"; + nvidia,pull = <0>; + nvidia,tristate = <0>; + }; + conf_ate { + nvidia,pins = "ate", "csus", "dap3", "gmd", + "gpv", "owc", "spia", "spib", "spic", + "spid", "spie", "spig"; + nvidia,pull = <0>; + nvidia,tristate = <1>; + }; + conf_ck32 { + nvidia,pins = "ck32", "ddrc", "pmca", "pmcb", + "pmcc", "pmcd", "pmce", "xm2c", "xm2d"; + nvidia,pull = <0>; + }; + conf_crtp { + nvidia,pins = "crtp", "gmb", "slxa", "spih"; + nvidia,pull = <2>; + nvidia,tristate = <1>; + }; + conf_dta { + nvidia,pins = "dta", "dtb", "dtc", "dtd"; + nvidia,pull = <1>; + nvidia,tristate = <0>; + }; + conf_dte { + nvidia,pins = "dte", "spif"; + nvidia,pull = <1>; + nvidia,tristate = <1>; + }; + conf_hdint { + nvidia,pins = "hdint", "lcsn", "ldc", "lm1", + "lpw1", "lsck", "lsda", "lsdi", "lvp0"; + nvidia,tristate = <1>; + }; + conf_kbca { + nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd", + "kbce", "kbcf", "sdio1", "uaa", "uab"; + nvidia,pull = <2>; + nvidia,tristate = <0>; + }; + conf_lc { + nvidia,pins = "lc", "ls"; + nvidia,pull = <2>; + }; + conf_ld0 { + nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4", + "ld5", "ld6", "ld7", "ld8", "ld9", + "ld10", "ld11", "ld12", "ld13", "ld14", + "ld15", "ld16", "ld17", "ldi", "lhp0", + "lhp1", "lhp2", "lhs", "lm0", "lpp", + "lpw0", "lpw2", "lsc0", "lsc1", "lspi", + "lvp1", "lvs", "pmc", "sdb"; + nvidia,tristate = <0>; + }; + conf_ld17_0 { + nvidia,pins = "ld17_0", "ld19_18", "ld21_20", + "ld23_22"; + nvidia,pull = <1>; + }; + }; + }; + i2c@7000c000 { clock-frequency = <400000>; diff --git a/trunk/arch/arm/boot/dts/tny_a9260.dts b/trunk/arch/arm/boot/dts/tny_a9260.dts new file mode 100644 index 000000000000..367a16dcd5ef --- /dev/null +++ b/trunk/arch/arm/boot/dts/tny_a9260.dts @@ -0,0 +1,15 @@ +/* + * tny_a9260.dts - Device Tree file for Caloa TNY A9260 board + * + * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD + * + * Licensed under GPLv2. + */ +/dts-v1/; +/include/ "at91sam9260.dtsi" +/include/ "tny_a9260_common.dtsi" + +/ { + model = "Calao TNY A9260"; + compatible = "calao,tny-a9260", "atmel,at91sam9260", "atmel,at91sam9"; +}; diff --git a/trunk/arch/arm/boot/dts/tny_a9260_common.dtsi b/trunk/arch/arm/boot/dts/tny_a9260_common.dtsi new file mode 100644 index 000000000000..0e6d3de2e09e --- /dev/null +++ b/trunk/arch/arm/boot/dts/tny_a9260_common.dtsi @@ -0,0 +1,83 @@ +/* + * tny_a9260_common.dtsi - Device Tree file for Caloa TNY A926x board + * + * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD + * + * Licensed under GPLv2. + */ + +/ { + chosen { + bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock6 rw rootfstype=ubifs"; + }; + + memory { + reg = <0x20000000 0x4000000>; + }; + + clocks { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + main_clock: clock@0 { + compatible = "atmel,osc", "fixed-clock"; + clock-frequency = <12000000>; + }; + }; + + ahb { + apb { + dbgu: serial@fffff200 { + status = "okay"; + }; + }; + + nand0: nand@40000000 { + nand-bus-width = <8>; + nand-ecc-mode = "soft"; + nand-on-flash-bbt; + status = "okay"; + + at91bootstrap@0 { + label = "at91bootstrap"; + reg = <0x0 0x20000>; + }; + + barebox@20000 { + label = "barebox"; + reg = <0x20000 0x40000>; + }; + + bareboxenv@60000 { + label = "bareboxenv"; + reg = <0x60000 0x20000>; + }; + + bareboxenv2@80000 { + label = "bareboxenv2"; + reg = <0x80000 0x20000>; + }; + + oftree@80000 { + label = "oftree"; + reg = <0xa0000 0x20000>; + }; + + kernel@a0000 { + label = "kernel"; + reg = <0xc0000 0x400000>; + }; + + rootfs@4a0000 { + label = "rootfs"; + reg = <0x4c0000 0x7800000>; + }; + + data@7ca0000 { + label = "data"; + reg = <0x7cc0000 0x8340000>; + }; + }; + }; +}; diff --git a/trunk/arch/arm/boot/dts/tny_a9263.dts b/trunk/arch/arm/boot/dts/tny_a9263.dts new file mode 100644 index 000000000000..dee9c571306b --- /dev/null +++ b/trunk/arch/arm/boot/dts/tny_a9263.dts @@ -0,0 +1,97 @@ +/* + * usb_a9263.dts - Device Tree file for Caloa USB A9293 board + * + * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD + * + * Licensed under GPLv2 only + */ +/dts-v1/; +/include/ "at91sam9263.dtsi" + +/ { + model = "Calao TNY A9263"; + compatible = "atmel,tny-a9263", "atmel,at91sam9263", "atmel,at91sam9"; + + chosen { + bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs"; + }; + + memory { + reg = <0x20000000 0x4000000>; + }; + + clocks { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + main_clock: clock@0 { + compatible = "atmel,osc", "fixed-clock"; + clock-frequency = <12000000>; + }; + }; + + ahb { + apb { + dbgu: serial@ffffee00 { + status = "okay"; + }; + + usb1: gadget@fff78000 { + atmel,vbus-gpio = <&pioB 11 0>; + status = "okay"; + }; + }; + + nand0: nand@40000000 { + nand-bus-width = <8>; + nand-ecc-mode = "soft"; + nand-on-flash-bbt; + status = "okay"; + + at91bootstrap@0 { + label = "at91bootstrap"; + reg = <0x0 0x20000>; + }; + + barebox@20000 { + label = "barebox"; + reg = <0x20000 0x40000>; + }; + + bareboxenv@60000 { + label = "bareboxenv"; + reg = <0x60000 0x20000>; + }; + + bareboxenv2@80000 { + label = "bareboxenv2"; + reg = <0x80000 0x20000>; + }; + + oftree@80000 { + label = "oftree"; + reg = <0xa0000 0x20000>; + }; + + kernel@a0000 { + label = "kernel"; + reg = <0xc0000 0x400000>; + }; + + rootfs@4a0000 { + label = "rootfs"; + reg = <0x4c0000 0x7800000>; + }; + + data@7ca0000 { + label = "data"; + reg = <0x7cc0000 0x8340000>; + }; + }; + }; + + i2c@0 { + status = "okay"; + }; +}; diff --git a/trunk/arch/arm/boot/dts/tny_a9g20.dts b/trunk/arch/arm/boot/dts/tny_a9g20.dts new file mode 100644 index 000000000000..e1ab64c72dba --- /dev/null +++ b/trunk/arch/arm/boot/dts/tny_a9g20.dts @@ -0,0 +1,15 @@ +/* + * tny_a9g20.dts - Device Tree file for Caloa TNY A9G20 board + * + * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD + * + * Licensed under GPLv2. + */ +/dts-v1/; +/include/ "at91sam9g20.dtsi" +/include/ "tny_a9260_common.dtsi" + +/ { + model = "Calao TNY A9G20"; + compatible = "calao,tny-a9g20", "atmel,at91sam9g20", "atmel,at91sam9"; +}; diff --git a/trunk/arch/arm/boot/dts/twl4030.dtsi b/trunk/arch/arm/boot/dts/twl4030.dtsi new file mode 100644 index 000000000000..22f4d1394ed3 --- /dev/null +++ b/trunk/arch/arm/boot/dts/twl4030.dtsi @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.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. + */ + +/* + * Integrated Power Management Chip + */ +&twl { + compatible = "ti,twl4030"; + interrupt-controller; + #interrupt-cells = <1>; + + rtc { + compatible = "ti,twl4030-rtc"; + interrupts = <11>; + }; + + vdac: regulator@0 { + compatible = "ti,twl4030-vdac"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + vpll2: regulator@1 { + compatible = "ti,twl4030-vpll2"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + vmmc1: regulator@2 { + compatible = "ti,twl4030-vmmc1"; + regulator-min-microvolt = <1850000>; + regulator-max-microvolt = <3150000>; + }; + + twl_gpio: gpio { + compatible = "ti,twl4030-gpio"; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; +}; diff --git a/trunk/arch/arm/boot/dts/twl6030.dtsi b/trunk/arch/arm/boot/dts/twl6030.dtsi new file mode 100644 index 000000000000..3b2f3510d7eb --- /dev/null +++ b/trunk/arch/arm/boot/dts/twl6030.dtsi @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.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. + */ + +/* + * Integrated Power Management Chip + * http://www.ti.com/lit/ds/symlink/twl6030.pdf + */ +&twl { + compatible = "ti,twl6030"; + interrupt-controller; + #interrupt-cells = <1>; + + rtc { + compatible = "ti,twl4030-rtc"; + interrupts = <11>; + }; + + vaux1: regulator@0 { + compatible = "ti,twl6030-vaux1"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + }; + + vaux2: regulator@1 { + compatible = "ti,twl6030-vaux2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <2800000>; + }; + + vaux3: regulator@2 { + compatible = "ti,twl6030-vaux3"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + }; + + vmmc: regulator@3 { + compatible = "ti,twl6030-vmmc"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3000000>; + }; + + vpp: regulator@4 { + compatible = "ti,twl6030-vpp"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2500000>; + }; + + vusim: regulator@5 { + compatible = "ti,twl6030-vusim"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <2900000>; + }; + + vdac: regulator@6 { + compatible = "ti,twl6030-vdac"; + }; + + vana: regulator@7 { + compatible = "ti,twl6030-vana"; + }; + + vcxio: regulator@8 { + compatible = "ti,twl6030-vcxio"; + }; + + vusb: regulator@9 { + compatible = "ti,twl6030-vusb"; + }; + + v1v8: regulator@10 { + compatible = "ti,twl6030-v1v8"; + }; + + v2v1: regulator@11 { + compatible = "ti,twl6030-v2v1"; + }; + + clk32kg: regulator@12 { + compatible = "ti,twl6030-clk32kg"; + }; +}; diff --git a/trunk/arch/arm/boot/dts/usb_a9260.dts b/trunk/arch/arm/boot/dts/usb_a9260.dts new file mode 100644 index 000000000000..296216058c11 --- /dev/null +++ b/trunk/arch/arm/boot/dts/usb_a9260.dts @@ -0,0 +1,23 @@ +/* + * usb_a9260.dts - Device Tree file for Caloa USB A9260 board + * + * Copyright (C) 2011-2012 Jean-Christophe PLAGNIOL-VILLARD + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +/include/ "at91sam9260.dtsi" +/include/ "usb_a9260_common.dtsi" + +/ { + model = "Calao USB A9260"; + compatible = "calao,usb-a9260", "atmel,at91sam9260", "atmel,at91sam9"; + + chosen { + bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs"; + }; + + memory { + reg = <0x20000000 0x4000000>; + }; +}; diff --git a/trunk/arch/arm/boot/dts/usb_a9260_common.dtsi b/trunk/arch/arm/boot/dts/usb_a9260_common.dtsi new file mode 100644 index 000000000000..e70d229baef5 --- /dev/null +++ b/trunk/arch/arm/boot/dts/usb_a9260_common.dtsi @@ -0,0 +1,117 @@ +/* + * usb_a926x.dts - Device Tree file for Caloa USB A926x board + * + * Copyright (C) 2011-2012 Jean-Christophe PLAGNIOL-VILLARD + * + * Licensed under GPLv2 or later. + */ + +/ { + clocks { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + main_clock: clock@0 { + compatible = "atmel,osc", "fixed-clock"; + clock-frequency = <12000000>; + }; + }; + + ahb { + apb { + dbgu: serial@fffff200 { + status = "okay"; + }; + + macb0: ethernet@fffc4000 { + phy-mode = "rmii"; + status = "okay"; + }; + + usb1: gadget@fffa4000 { + atmel,vbus-gpio = <&pioC 5 0>; + status = "okay"; + }; + }; + + nand0: nand@40000000 { + nand-bus-width = <8>; + nand-ecc-mode = "soft"; + nand-on-flash-bbt; + status = "okay"; + + at91bootstrap@0 { + label = "at91bootstrap"; + reg = <0x0 0x20000>; + }; + + barebox@20000 { + label = "barebox"; + reg = <0x20000 0x40000>; + }; + + bareboxenv@60000 { + label = "bareboxenv"; + reg = <0x60000 0x20000>; + }; + + bareboxenv2@80000 { + label = "bareboxenv2"; + reg = <0x80000 0x20000>; + }; + + oftree@80000 { + label = "oftree"; + reg = <0xa0000 0x20000>; + }; + + kernel@a0000 { + label = "kernel"; + reg = <0xc0000 0x400000>; + }; + + rootfs@4a0000 { + label = "rootfs"; + reg = <0x4c0000 0x7800000>; + }; + + data@7ca0000 { + label = "data"; + reg = <0x7cc0000 0x8340000>; + }; + }; + + usb0: ohci@00500000 { + num-ports = <2>; + status = "okay"; + }; + }; + + leds { + compatible = "gpio-leds"; + + user_led { + label = "user_led"; + gpios = <&pioB 21 1>; + linux,default-trigger = "heartbeat"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + user_pb { + label = "user_pb"; + gpios = <&pioB 10 1>; + linux,code = <28>; + gpio-key,wakeup; + }; + }; + + i2c@0 { + status = "okay"; + }; +}; diff --git a/trunk/arch/arm/boot/dts/usb_a9263.dts b/trunk/arch/arm/boot/dts/usb_a9263.dts new file mode 100644 index 000000000000..6fe05ccb6203 --- /dev/null +++ b/trunk/arch/arm/boot/dts/usb_a9263.dts @@ -0,0 +1,131 @@ +/* + * usb_a9263.dts - Device Tree file for Caloa USB A9293 board + * + * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD + * + * Licensed under GPLv2 only + */ +/dts-v1/; +/include/ "at91sam9263.dtsi" + +/ { + model = "Calao USB A9263"; + compatible = "atmel,usb-a9263", "atmel,at91sam9263", "atmel,at91sam9"; + + chosen { + bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs"; + }; + + memory { + reg = <0x20000000 0x4000000>; + }; + + clocks { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + main_clock: clock@0 { + compatible = "atmel,osc", "fixed-clock"; + clock-frequency = <12000000>; + }; + }; + + ahb { + apb { + dbgu: serial@ffffee00 { + status = "okay"; + }; + + macb0: ethernet@fffbc000 { + phy-mode = "rmii"; + status = "okay"; + }; + + usb1: gadget@fff78000 { + atmel,vbus-gpio = <&pioB 11 0>; + status = "okay"; + }; + + }; + + nand0: nand@40000000 { + nand-bus-width = <8>; + nand-ecc-mode = "soft"; + nand-on-flash-bbt; + status = "okay"; + + at91bootstrap@0 { + label = "at91bootstrap"; + reg = <0x0 0x20000>; + }; + + barebox@20000 { + label = "barebox"; + reg = <0x20000 0x40000>; + }; + + bareboxenv@60000 { + label = "bareboxenv"; + reg = <0x60000 0x20000>; + }; + + bareboxenv2@80000 { + label = "bareboxenv2"; + reg = <0x80000 0x20000>; + }; + + oftree@80000 { + label = "oftree"; + reg = <0xa0000 0x20000>; + }; + + kernel@a0000 { + label = "kernel"; + reg = <0xc0000 0x400000>; + }; + + rootfs@4a0000 { + label = "rootfs"; + reg = <0x4c0000 0x7800000>; + }; + + data@7ca0000 { + label = "data"; + reg = <0x7cc0000 0x8340000>; + }; + }; + + usb0: ohci@00a00000 { + num-ports = <2>; + status = "okay"; + }; + }; + + leds { + compatible = "gpio-leds"; + + user_led { + label = "user_led"; + gpios = <&pioB 21 0>; + linux,default-trigger = "heartbeat"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + user_pb { + label = "user_pb"; + gpios = <&pioB 10 1>; + linux,code = <28>; + gpio-key,wakeup; + }; + }; + + i2c@0 { + status = "okay"; + }; +}; diff --git a/trunk/arch/arm/boot/dts/usb_a9g20.dts b/trunk/arch/arm/boot/dts/usb_a9g20.dts index 7c2399c532e5..2dacb16ce4ae 100644 --- a/trunk/arch/arm/boot/dts/usb_a9g20.dts +++ b/trunk/arch/arm/boot/dts/usb_a9g20.dts @@ -7,6 +7,7 @@ */ /dts-v1/; /include/ "at91sam9g20.dtsi" +/include/ "usb_a9260_common.dtsi" / { model = "Calao USB A9G20"; @@ -20,108 +21,7 @@ reg = <0x20000000 0x4000000>; }; - clocks { - #address-cells = <1>; - #size-cells = <1>; - ranges; - - main_clock: clock@0 { - compatible = "atmel,osc", "fixed-clock"; - clock-frequency = <12000000>; - }; - }; - - ahb { - apb { - dbgu: serial@fffff200 { - status = "okay"; - }; - - macb0: ethernet@fffc4000 { - phy-mode = "rmii"; - status = "okay"; - }; - - usb1: gadget@fffa4000 { - atmel,vbus-gpio = <&pioC 5 0>; - status = "okay"; - }; - }; - - nand0: nand@40000000 { - nand-bus-width = <8>; - nand-ecc-mode = "soft"; - nand-on-flash-bbt; - status = "okay"; - - at91bootstrap@0 { - label = "at91bootstrap"; - reg = <0x0 0x20000>; - }; - - barebox@20000 { - label = "barebox"; - reg = <0x20000 0x40000>; - }; - - bareboxenv@60000 { - label = "bareboxenv"; - reg = <0x60000 0x20000>; - }; - - bareboxenv2@80000 { - label = "bareboxenv2"; - reg = <0x80000 0x20000>; - }; - - kernel@a0000 { - label = "kernel"; - reg = <0xa0000 0x400000>; - }; - - rootfs@4a0000 { - label = "rootfs"; - reg = <0x4a0000 0x7800000>; - }; - - data@7ca0000 { - label = "data"; - reg = <0x7ca0000 0x8360000>; - }; - }; - - usb0: ohci@00500000 { - num-ports = <2>; - status = "okay"; - }; - }; - - leds { - compatible = "gpio-leds"; - - user_led { - label = "user_led"; - gpios = <&pioB 21 1>; - linux,default-trigger = "heartbeat"; - }; - }; - - gpio_keys { - compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; - - user_pb { - label = "user_pb"; - gpios = <&pioB 10 1>; - linux,code = <28>; - gpio-key,wakeup; - }; - }; - i2c@0 { - status = "okay"; - rv3029c2@56 { compatible = "rv3029c2"; reg = <0x56>; diff --git a/trunk/arch/arm/common/Makefile b/trunk/arch/arm/common/Makefile index 215816f1775f..e8a4e58f1b82 100644 --- a/trunk/arch/arm/common/Makefile +++ b/trunk/arch/arm/common/Makefile @@ -11,7 +11,5 @@ obj-$(CONFIG_DMABOUNCE) += dmabounce.o obj-$(CONFIG_SHARP_LOCOMO) += locomo.o obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o obj-$(CONFIG_SHARP_SCOOP) += scoop.o -obj-$(CONFIG_ARCH_IXP2000) += uengine.o -obj-$(CONFIG_ARCH_IXP23XX) += uengine.o obj-$(CONFIG_PCI_HOST_ITE8152) += it8152.o obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp.o diff --git a/trunk/arch/arm/common/it8152.c b/trunk/arch/arm/common/it8152.c index dcb13494ca0d..c4110d1b1f2d 100644 --- a/trunk/arch/arm/common/it8152.c +++ b/trunk/arch/arm/common/it8152.c @@ -222,7 +222,7 @@ static int it8152_pci_write_config(struct pci_bus *bus, return PCIBIOS_SUCCESSFUL; } -static struct pci_ops it8152_ops = { +struct pci_ops it8152_ops = { .read = it8152_pci_read_config, .write = it8152_pci_write_config, }; @@ -346,9 +346,4 @@ void pcibios_set_master(struct pci_dev *dev) } -struct pci_bus * __init it8152_pci_scan_bus(int nr, struct pci_sys_data *sys) -{ - return pci_scan_root_bus(NULL, nr, &it8152_ops, sys, &sys->resources); -} - EXPORT_SYMBOL(dma_set_coherent_mask); diff --git a/trunk/arch/arm/common/uengine.c b/trunk/arch/arm/common/uengine.c deleted file mode 100644 index bef408f3d76c..000000000000 --- a/trunk/arch/arm/common/uengine.c +++ /dev/null @@ -1,507 +0,0 @@ -/* - * Generic library functions for the microengines found on the Intel - * IXP2000 series of network processors. - * - * Copyright (C) 2004, 2005 Lennert Buytenhek - * Dedicated to Marija Kulikova. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of the - * License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(CONFIG_ARCH_IXP2000) -#define IXP_UENGINE_CSR_VIRT_BASE IXP2000_UENGINE_CSR_VIRT_BASE -#define IXP_PRODUCT_ID IXP2000_PRODUCT_ID -#define IXP_MISC_CONTROL IXP2000_MISC_CONTROL -#define IXP_RESET1 IXP2000_RESET1 -#else -#if defined(CONFIG_ARCH_IXP23XX) -#define IXP_UENGINE_CSR_VIRT_BASE IXP23XX_UENGINE_CSR_VIRT_BASE -#define IXP_PRODUCT_ID IXP23XX_PRODUCT_ID -#define IXP_MISC_CONTROL IXP23XX_MISC_CONTROL -#define IXP_RESET1 IXP23XX_RESET1 -#else -#error unknown platform -#endif -#endif - -#define USTORE_ADDRESS 0x000 -#define USTORE_DATA_LOWER 0x004 -#define USTORE_DATA_UPPER 0x008 -#define CTX_ENABLES 0x018 -#define CC_ENABLE 0x01c -#define CSR_CTX_POINTER 0x020 -#define INDIRECT_CTX_STS 0x040 -#define ACTIVE_CTX_STS 0x044 -#define INDIRECT_CTX_SIG_EVENTS 0x048 -#define INDIRECT_CTX_WAKEUP_EVENTS 0x050 -#define NN_PUT 0x080 -#define NN_GET 0x084 -#define TIMESTAMP_LOW 0x0c0 -#define TIMESTAMP_HIGH 0x0c4 -#define T_INDEX_BYTE_INDEX 0x0f4 -#define LOCAL_CSR_STATUS 0x180 - -u32 ixp2000_uengine_mask; - -static void *ixp2000_uengine_csr_area(int uengine) -{ - return ((void *)IXP_UENGINE_CSR_VIRT_BASE) + (uengine << 10); -} - -/* - * LOCAL_CSR_STATUS=1 after a read or write to a microengine's CSR - * space means that the microengine we tried to access was also trying - * to access its own CSR space on the same clock cycle as we did. When - * this happens, we lose the arbitration process by default, and the - * read or write we tried to do was not actually performed, so we try - * again until it succeeds. - */ -u32 ixp2000_uengine_csr_read(int uengine, int offset) -{ - void *uebase; - u32 *local_csr_status; - u32 *reg; - u32 value; - - uebase = ixp2000_uengine_csr_area(uengine); - - local_csr_status = (u32 *)(uebase + LOCAL_CSR_STATUS); - reg = (u32 *)(uebase + offset); - do { - value = ixp2000_reg_read(reg); - } while (ixp2000_reg_read(local_csr_status) & 1); - - return value; -} -EXPORT_SYMBOL(ixp2000_uengine_csr_read); - -void ixp2000_uengine_csr_write(int uengine, int offset, u32 value) -{ - void *uebase; - u32 *local_csr_status; - u32 *reg; - - uebase = ixp2000_uengine_csr_area(uengine); - - local_csr_status = (u32 *)(uebase + LOCAL_CSR_STATUS); - reg = (u32 *)(uebase + offset); - do { - ixp2000_reg_write(reg, value); - } while (ixp2000_reg_read(local_csr_status) & 1); -} -EXPORT_SYMBOL(ixp2000_uengine_csr_write); - -void ixp2000_uengine_reset(u32 uengine_mask) -{ - u32 value; - - value = ixp2000_reg_read(IXP_RESET1) & ~ixp2000_uengine_mask; - - uengine_mask &= ixp2000_uengine_mask; - ixp2000_reg_wrb(IXP_RESET1, value | uengine_mask); - ixp2000_reg_wrb(IXP_RESET1, value); -} -EXPORT_SYMBOL(ixp2000_uengine_reset); - -void ixp2000_uengine_set_mode(int uengine, u32 mode) -{ - /* - * CTL_STR_PAR_EN: unconditionally enable parity checking on - * control store. - */ - mode |= 0x10000000; - ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mode); - - /* - * Enable updating of condition codes. - */ - ixp2000_uengine_csr_write(uengine, CC_ENABLE, 0x00002000); - - /* - * Initialise other per-microengine registers. - */ - ixp2000_uengine_csr_write(uengine, NN_PUT, 0x00); - ixp2000_uengine_csr_write(uengine, NN_GET, 0x00); - ixp2000_uengine_csr_write(uengine, T_INDEX_BYTE_INDEX, 0); -} -EXPORT_SYMBOL(ixp2000_uengine_set_mode); - -static int make_even_parity(u32 x) -{ - return hweight32(x) & 1; -} - -static void ustore_write(int uengine, u64 insn) -{ - /* - * Generate even parity for top and bottom 20 bits. - */ - insn |= (u64)make_even_parity((insn >> 20) & 0x000fffff) << 41; - insn |= (u64)make_even_parity(insn & 0x000fffff) << 40; - - /* - * Write to microstore. The second write auto-increments - * the USTORE_ADDRESS index register. - */ - ixp2000_uengine_csr_write(uengine, USTORE_DATA_LOWER, (u32)insn); - ixp2000_uengine_csr_write(uengine, USTORE_DATA_UPPER, (u32)(insn >> 32)); -} - -void ixp2000_uengine_load_microcode(int uengine, u8 *ucode, int insns) -{ - int i; - - /* - * Start writing to microstore at address 0. - */ - ixp2000_uengine_csr_write(uengine, USTORE_ADDRESS, 0x80000000); - for (i = 0; i < insns; i++) { - u64 insn; - - insn = (((u64)ucode[0]) << 32) | - (((u64)ucode[1]) << 24) | - (((u64)ucode[2]) << 16) | - (((u64)ucode[3]) << 8) | - ((u64)ucode[4]); - ucode += 5; - - ustore_write(uengine, insn); - } - - /* - * Pad with a few NOPs at the end (to avoid the microengine - * aborting as it prefetches beyond the last instruction), unless - * we run off the end of the instruction store first, at which - * point the address register will wrap back to zero. - */ - for (i = 0; i < 4; i++) { - u32 addr; - - addr = ixp2000_uengine_csr_read(uengine, USTORE_ADDRESS); - if (addr == 0x80000000) - break; - ustore_write(uengine, 0xf0000c0300ULL); - } - - /* - * End programming. - */ - ixp2000_uengine_csr_write(uengine, USTORE_ADDRESS, 0x00000000); -} -EXPORT_SYMBOL(ixp2000_uengine_load_microcode); - -void ixp2000_uengine_init_context(int uengine, int context, int pc) -{ - /* - * Select the right context for indirect access. - */ - ixp2000_uengine_csr_write(uengine, CSR_CTX_POINTER, context); - - /* - * Initialise signal masks to immediately go to Ready state. - */ - ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_SIG_EVENTS, 1); - ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_WAKEUP_EVENTS, 1); - - /* - * Set program counter. - */ - ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_STS, pc); -} -EXPORT_SYMBOL(ixp2000_uengine_init_context); - -void ixp2000_uengine_start_contexts(int uengine, u8 ctx_mask) -{ - u32 mask; - - /* - * Enable the specified context to go to Executing state. - */ - mask = ixp2000_uengine_csr_read(uengine, CTX_ENABLES); - mask |= ctx_mask << 8; - ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mask); -} -EXPORT_SYMBOL(ixp2000_uengine_start_contexts); - -void ixp2000_uengine_stop_contexts(int uengine, u8 ctx_mask) -{ - u32 mask; - - /* - * Disable the Ready->Executing transition. Note that this - * does not stop the context until it voluntarily yields. - */ - mask = ixp2000_uengine_csr_read(uengine, CTX_ENABLES); - mask &= ~(ctx_mask << 8); - ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mask); -} -EXPORT_SYMBOL(ixp2000_uengine_stop_contexts); - -static int check_ixp_type(struct ixp2000_uengine_code *c) -{ - u32 product_id; - u32 rev; - - product_id = ixp2000_reg_read(IXP_PRODUCT_ID); - if (((product_id >> 16) & 0x1f) != 0) - return 0; - - switch ((product_id >> 8) & 0xff) { -#ifdef CONFIG_ARCH_IXP2000 - case 0: /* IXP2800 */ - if (!(c->cpu_model_bitmask & 4)) - return 0; - break; - - case 1: /* IXP2850 */ - if (!(c->cpu_model_bitmask & 8)) - return 0; - break; - - case 2: /* IXP2400 */ - if (!(c->cpu_model_bitmask & 2)) - return 0; - break; -#endif - -#ifdef CONFIG_ARCH_IXP23XX - case 4: /* IXP23xx */ - if (!(c->cpu_model_bitmask & 0x3f0)) - return 0; - break; -#endif - - default: - return 0; - } - - rev = product_id & 0xff; - if (rev < c->cpu_min_revision || rev > c->cpu_max_revision) - return 0; - - return 1; -} - -static void generate_ucode(u8 *ucode, u32 *gpr_a, u32 *gpr_b) -{ - int offset; - int i; - - offset = 0; - - for (i = 0; i < 128; i++) { - u8 b3; - u8 b2; - u8 b1; - u8 b0; - - b3 = (gpr_a[i] >> 24) & 0xff; - b2 = (gpr_a[i] >> 16) & 0xff; - b1 = (gpr_a[i] >> 8) & 0xff; - b0 = gpr_a[i] & 0xff; - - /* immed[@ai, (b1 << 8) | b0] */ - /* 11110000 0000VVVV VVVV11VV VVVVVV00 1IIIIIII */ - ucode[offset++] = 0xf0; - ucode[offset++] = (b1 >> 4); - ucode[offset++] = (b1 << 4) | 0x0c | (b0 >> 6); - ucode[offset++] = (b0 << 2); - ucode[offset++] = 0x80 | i; - - /* immed_w1[@ai, (b3 << 8) | b2] */ - /* 11110100 0100VVVV VVVV11VV VVVVVV00 1IIIIIII */ - ucode[offset++] = 0xf4; - ucode[offset++] = 0x40 | (b3 >> 4); - ucode[offset++] = (b3 << 4) | 0x0c | (b2 >> 6); - ucode[offset++] = (b2 << 2); - ucode[offset++] = 0x80 | i; - } - - for (i = 0; i < 128; i++) { - u8 b3; - u8 b2; - u8 b1; - u8 b0; - - b3 = (gpr_b[i] >> 24) & 0xff; - b2 = (gpr_b[i] >> 16) & 0xff; - b1 = (gpr_b[i] >> 8) & 0xff; - b0 = gpr_b[i] & 0xff; - - /* immed[@bi, (b1 << 8) | b0] */ - /* 11110000 0000VVVV VVVV001I IIIIII11 VVVVVVVV */ - ucode[offset++] = 0xf0; - ucode[offset++] = (b1 >> 4); - ucode[offset++] = (b1 << 4) | 0x02 | (i >> 6); - ucode[offset++] = (i << 2) | 0x03; - ucode[offset++] = b0; - - /* immed_w1[@bi, (b3 << 8) | b2] */ - /* 11110100 0100VVVV VVVV001I IIIIII11 VVVVVVVV */ - ucode[offset++] = 0xf4; - ucode[offset++] = 0x40 | (b3 >> 4); - ucode[offset++] = (b3 << 4) | 0x02 | (i >> 6); - ucode[offset++] = (i << 2) | 0x03; - ucode[offset++] = b2; - } - - /* ctx_arb[kill] */ - ucode[offset++] = 0xe0; - ucode[offset++] = 0x00; - ucode[offset++] = 0x01; - ucode[offset++] = 0x00; - ucode[offset++] = 0x00; -} - -static int set_initial_registers(int uengine, struct ixp2000_uengine_code *c) -{ - int per_ctx_regs; - u32 *gpr_a; - u32 *gpr_b; - u8 *ucode; - int i; - - gpr_a = kzalloc(128 * sizeof(u32), GFP_KERNEL); - gpr_b = kzalloc(128 * sizeof(u32), GFP_KERNEL); - ucode = kmalloc(513 * 5, GFP_KERNEL); - if (gpr_a == NULL || gpr_b == NULL || ucode == NULL) { - kfree(ucode); - kfree(gpr_b); - kfree(gpr_a); - return 1; - } - - per_ctx_regs = 16; - if (c->uengine_parameters & IXP2000_UENGINE_4_CONTEXTS) - per_ctx_regs = 32; - - for (i = 0; i < 256; i++) { - struct ixp2000_reg_value *r = c->initial_reg_values + i; - u32 *bank; - int inc; - int j; - - if (r->reg == -1) - break; - - bank = (r->reg & 0x400) ? gpr_b : gpr_a; - inc = (r->reg & 0x80) ? 128 : per_ctx_regs; - - j = r->reg & 0x7f; - while (j < 128) { - bank[j] = r->value; - j += inc; - } - } - - generate_ucode(ucode, gpr_a, gpr_b); - ixp2000_uengine_load_microcode(uengine, ucode, 513); - ixp2000_uengine_init_context(uengine, 0, 0); - ixp2000_uengine_start_contexts(uengine, 0x01); - for (i = 0; i < 100; i++) { - u32 status; - - status = ixp2000_uengine_csr_read(uengine, ACTIVE_CTX_STS); - if (!(status & 0x80000000)) - break; - } - ixp2000_uengine_stop_contexts(uengine, 0x01); - - kfree(ucode); - kfree(gpr_b); - kfree(gpr_a); - - return !!(i == 100); -} - -int ixp2000_uengine_load(int uengine, struct ixp2000_uengine_code *c) -{ - int ctx; - - if (!check_ixp_type(c)) - return 1; - - if (!(ixp2000_uengine_mask & (1 << uengine))) - return 1; - - ixp2000_uengine_reset(1 << uengine); - ixp2000_uengine_set_mode(uengine, c->uengine_parameters); - if (set_initial_registers(uengine, c)) - return 1; - ixp2000_uengine_load_microcode(uengine, c->insns, c->num_insns); - - for (ctx = 0; ctx < 8; ctx++) - ixp2000_uengine_init_context(uengine, ctx, 0); - - return 0; -} -EXPORT_SYMBOL(ixp2000_uengine_load); - - -static int __init ixp2000_uengine_init(void) -{ - int uengine; - u32 value; - - /* - * Determine number of microengines present. - */ - switch ((ixp2000_reg_read(IXP_PRODUCT_ID) >> 8) & 0x1fff) { -#ifdef CONFIG_ARCH_IXP2000 - case 0: /* IXP2800 */ - case 1: /* IXP2850 */ - ixp2000_uengine_mask = 0x00ff00ff; - break; - - case 2: /* IXP2400 */ - ixp2000_uengine_mask = 0x000f000f; - break; -#endif - -#ifdef CONFIG_ARCH_IXP23XX - case 4: /* IXP23xx */ - ixp2000_uengine_mask = (*IXP23XX_EXP_CFG_FUSE >> 8) & 0xf; - break; -#endif - - default: - printk(KERN_INFO "Detected unknown IXP2000 model (%.8x)\n", - (unsigned int)ixp2000_reg_read(IXP_PRODUCT_ID)); - ixp2000_uengine_mask = 0x00000000; - break; - } - - /* - * Reset microengines. - */ - ixp2000_uengine_reset(ixp2000_uengine_mask); - - /* - * Synchronise timestamp counters across all microengines. - */ - value = ixp2000_reg_read(IXP_MISC_CONTROL); - ixp2000_reg_wrb(IXP_MISC_CONTROL, value & ~0x80); - for (uengine = 0; uengine < 32; uengine++) { - if (ixp2000_uengine_mask & (1 << uengine)) { - ixp2000_uengine_csr_write(uengine, TIMESTAMP_LOW, 0); - ixp2000_uengine_csr_write(uengine, TIMESTAMP_HIGH, 0); - } - } - ixp2000_reg_wrb(IXP_MISC_CONTROL, value | 0x80); - - return 0; -} - -subsys_initcall(ixp2000_uengine_init); diff --git a/trunk/arch/arm/common/via82c505.c b/trunk/arch/arm/common/via82c505.c index 1171a5010aea..6cb362e56d29 100644 --- a/trunk/arch/arm/common/via82c505.c +++ b/trunk/arch/arm/common/via82c505.c @@ -51,7 +51,7 @@ via82c505_write_config(struct pci_bus *bus, unsigned int devfn, int where, return PCIBIOS_SUCCESSFUL; } -static struct pci_ops via82c505_ops = { +struct pci_ops via82c505_ops = { .read = via82c505_read_config, .write = via82c505_write_config, }; @@ -81,12 +81,3 @@ int __init via82c505_setup(int nr, struct pci_sys_data *sys) { return (nr == 0); } - -struct pci_bus * __init via82c505_scan_bus(int nr, struct pci_sys_data *sysdata) -{ - if (nr == 0) - return pci_scan_root_bus(NULL, 0, &via82c505_ops, sysdata, - &sysdata->resources); - - return NULL; -} diff --git a/trunk/arch/arm/common/vic.c b/trunk/arch/arm/common/vic.c index 7e288f96cedf..e0d538803cc3 100644 --- a/trunk/arch/arm/common/vic.c +++ b/trunk/arch/arm/common/vic.c @@ -39,6 +39,7 @@ * struct vic_device - VIC PM device * @irq: The IRQ number for the base of the VIC. * @base: The register base for the VIC. + * @valid_sources: A bitmask of valid interrupts * @resume_sources: A bitmask of interrupts for resume. * @resume_irqs: The IRQs enabled for resume. * @int_select: Save for VIC_INT_SELECT. @@ -50,6 +51,7 @@ struct vic_device { void __iomem *base; int irq; + u32 valid_sources; u32 resume_sources; u32 resume_irqs; u32 int_select; @@ -164,10 +166,32 @@ static int __init vic_pm_init(void) late_initcall(vic_pm_init); #endif /* CONFIG_PM */ +static struct irq_chip vic_chip; + +static int vic_irqdomain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + struct vic_device *v = d->host_data; + + /* Skip invalid IRQs, only register handlers for the real ones */ + if (!(v->valid_sources & (1 << hwirq))) + return -ENOTSUPP; + irq_set_chip_and_handler(irq, &vic_chip, handle_level_irq); + irq_set_chip_data(irq, v->base); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + return 0; +} + +static struct irq_domain_ops vic_irqdomain_ops = { + .map = vic_irqdomain_map, + .xlate = irq_domain_xlate_onetwocell, +}; + /** * vic_register() - Register a VIC. * @base: The base address of the VIC. * @irq: The base IRQ for the VIC. + * @valid_sources: bitmask of valid interrupts * @resume_sources: bitmask of interrupts allowed for resume sources. * @node: The device tree node associated with the VIC. * @@ -178,7 +202,8 @@ late_initcall(vic_pm_init); * This also configures the IRQ domain for the VIC. */ static void __init vic_register(void __iomem *base, unsigned int irq, - u32 resume_sources, struct device_node *node) + u32 valid_sources, u32 resume_sources, + struct device_node *node) { struct vic_device *v; @@ -189,11 +214,12 @@ static void __init vic_register(void __iomem *base, unsigned int irq, v = &vic_devices[vic_id]; v->base = base; + v->valid_sources = valid_sources; v->resume_sources = resume_sources; v->irq = irq; vic_id++; - v->domain = irq_domain_add_legacy(node, 32, irq, 0, - &irq_domain_simple_ops, v); + v->domain = irq_domain_add_legacy(node, fls(valid_sources), irq, 0, + &vic_irqdomain_ops, v); } static void vic_ack_irq(struct irq_data *d) @@ -287,23 +313,6 @@ static void __init vic_clear_interrupts(void __iomem *base) } } -static void __init vic_set_irq_sources(void __iomem *base, - unsigned int irq_start, u32 vic_sources) -{ - unsigned int i; - - for (i = 0; i < 32; i++) { - if (vic_sources & (1 << i)) { - unsigned int irq = irq_start + i; - - irq_set_chip_and_handler(irq, &vic_chip, - handle_level_irq); - irq_set_chip_data(irq, base); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); - } - } -} - /* * The PL190 cell from ARM has been modified by ST to handle 64 interrupts. * The original cell has 32 interrupts, while the modified one has 64, @@ -338,8 +347,7 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start, writel(32, base + VIC_PL190_DEF_VECT_ADDR); } - vic_set_irq_sources(base, irq_start, vic_sources); - vic_register(base, irq_start, 0, node); + vic_register(base, irq_start, vic_sources, 0, node); } void __init __vic_init(void __iomem *base, unsigned int irq_start, @@ -379,9 +387,7 @@ void __init __vic_init(void __iomem *base, unsigned int irq_start, vic_init2(base); - vic_set_irq_sources(base, irq_start, vic_sources); - - vic_register(base, irq_start, resume_sources, node); + vic_register(base, irq_start, vic_sources, resume_sources, node); } /** diff --git a/trunk/arch/arm/configs/armadillo800eva_defconfig b/trunk/arch/arm/configs/armadillo800eva_defconfig new file mode 100644 index 000000000000..ddc9fe6a78ac --- /dev/null +++ b/trunk/arch/arm/configs/armadillo800eva_defconfig @@ -0,0 +1,142 @@ +CONFIG_EXPERIMENTAL=y +CONFIG_SYSVIPC=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=16 +# CONFIG_UTS_NS is not set +# CONFIG_IPC_NS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SLAB=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_ARCH_SHMOBILE=y +CONFIG_ARCH_R8A7740=y +CONFIG_MACH_ARMADILLO800EVA=y +# CONFIG_SH_TIMER_TMU is not set +# CONFIG_ARM_THUMB is not set +CONFIG_CPU_BPREDICT_DISABLE=y +# CONFIG_CACHE_L2X0 is not set +CONFIG_ARM_ERRATA_430973=y +CONFIG_ARM_ERRATA_458693=y +CONFIG_ARM_ERRATA_460075=y +CONFIG_ARM_ERRATA_720789=y +CONFIG_ARM_ERRATA_743622=y +CONFIG_ARM_ERRATA_751472=y +CONFIG_ARM_ERRATA_754322=y +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +CONFIG_FORCE_MAX_ZONEORDER=13 +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="console=tty0 console=ttySC1,115200 earlyprintk=sh-sci.1,115200 ignore_loglevel root=/dev/nfs ip=dhcp nfsroot=,rsize=4096,wsize=4096" +CONFIG_CMDLINE_FORCE=y +CONFIG_KEXEC=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_SUSPEND is not set +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=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_INET_DIAG is not set +# CONFIG_IPV6 is not set +# CONFIG_WIRELESS is not set +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_NETDEVICES=y +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CIRRUS is not set +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +CONFIG_SH_ETH=y +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_WLAN is not set +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_KEYBOARD_ATKBD is not set +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ST1232=y +# CONFIG_SERIO is not set +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_SH_SCI=y +CONFIG_SERIAL_SH_SCI_NR_UARTS=8 +CONFIG_SERIAL_SH_SCI_CONSOLE=y +# CONFIG_HW_RANDOM is not set +CONFIG_I2C=y +CONFIG_I2C_SH_MOBILE=y +# CONFIG_HWMON is not set +CONFIG_FB=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_SH_MOBILE_LCDC=y +CONFIG_LCD_CLASS_DEVICE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +# CONFIG_SND_SUPPORT_OLD_API is not set +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_ARM is not set +CONFIG_SND_SOC=y +CONFIG_SND_SOC_SH4_FSI=y +# CONFIG_HID_SUPPORT is not set +CONFIG_USB=y +# CONFIG_USB_DEVICE_CLASS is not set +CONFIG_USB_RENESAS_USBHS=y +CONFIG_USB_GADGET=y +CONFIG_USB_RENESAS_USBHS_UDC=y +CONFIG_USB_ETH=m +CONFIG_MMC=y +CONFIG_MMC_SDHI=y +CONFIG_MMC_SH_MMCIF=y +CONFIG_UIO=y +CONFIG_UIO_PDRV_GENIRQ=y +# CONFIG_DNOTIFY is not set +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +# CONFIG_MISC_FILESYSTEMS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_V4_1=y +CONFIG_ROOT_NFS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +# CONFIG_ARM_UNWIND is not set +CONFIG_CRYPTO=y +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_XZ_DEC=y diff --git a/trunk/arch/arm/configs/at91_dt_defconfig b/trunk/arch/arm/configs/at91_dt_defconfig new file mode 100644 index 000000000000..67bc571ed0c3 --- /dev/null +++ b/trunk/arch/arm/configs/at91_dt_defconfig @@ -0,0 +1,196 @@ +CONFIG_EXPERIMENTAL=y +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_SWAP is not set +CONFIG_SYSVIPC=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_KALLSYMS_ALL=y +CONFIG_EMBEDDED=y +CONFIG_SLAB=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_LBDAF is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_ARCH_AT91=y +CONFIG_SOC_AT91SAM9260=y +CONFIG_SOC_AT91SAM9263=y +CONFIG_SOC_AT91SAM9G45=y +CONFIG_SOC_AT91SAM9X5=y +CONFIG_MACH_AT91SAM_DT=y +CONFIG_AT91_PROGRAMMABLE_CLOCKS=y +CONFIG_AT91_TIMER_HZ=128 +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +CONFIG_LEDS=y +CONFIG_LEDS_CPU=y +CONFIG_UACCESS_WITH_MEMCPY=y +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_ARM_APPENDED_DTB=y +CONFIG_ARM_ATAG_DTB_COMPAT=y +CONFIG_CMDLINE="mem=128M console=ttyS0,115200 initrd=0x21100000,25165824 root=/dev/ram0 rw" +CONFIG_KEXEC=y +CONFIG_AUTO_ZRELADDR=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_PNP=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_DIAG is not set +CONFIG_IPV6=y +# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET6_XFRM_MODE_TUNNEL is not set +# CONFIG_INET6_XFRM_MODE_BEET is not set +CONFIG_IPV6_SIT_6RD=y +# CONFIG_WIRELESS is not set +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_STANDALONE is not set +# CONFIG_PREVENT_FIRMWARE_BUILD is not set +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_ATMEL=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_GLUEBI=y +CONFIG_PROC_DEVICETREE=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=4 +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_ATMEL_PWM=y +CONFIG_ATMEL_TCLIB=y +CONFIG_EEPROM_93CX6=m +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_LOWLEVEL is not set +CONFIG_NETDEVICES=y +CONFIG_MII=y +CONFIG_MACB=y +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +CONFIG_DAVICOM_PHY=y +CONFIG_MICREL_PHY=y +# CONFIG_WLAN is not set +CONFIG_INPUT_POLLDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=480 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=272 +CONFIG_INPUT_JOYDEV=y +CONFIG_INPUT_EVDEV=y +# CONFIG_KEYBOARD_ATKBD is not set +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_SERIO is not set +CONFIG_LEGACY_PTY_COUNT=4 +CONFIG_SERIAL_ATMEL=y +CONFIG_SERIAL_ATMEL_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_I2C=y +CONFIG_I2C_GPIO=y +CONFIG_SPI=y +CONFIG_SPI_ATMEL=y +# CONFIG_HWMON is not set +CONFIG_WATCHDOG=y +CONFIG_AT91SAM9X_WATCHDOG=y +CONFIG_SSB=m +CONFIG_FB=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_ATMEL=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_ATMEL_LCDC=y +# CONFIG_BACKLIGHT_GENERIC is not set +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_ACORN_8x8=y +CONFIG_FONT_MINI_4x6=y +CONFIG_LOGO=y +# CONFIG_HID_SUPPORT is not set +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICE_CLASS is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_ACM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_SERIAL=y +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_FTDI_SIO=y +CONFIG_USB_SERIAL_PL2303=y +CONFIG_USB_GADGET=y +CONFIG_USB_AT91=m +CONFIG_USB_ATMEL_USBA=m +CONFIG_USB_ETH=m +CONFIG_USB_GADGETFS=m +CONFIG_USB_CDC_COMPOSITE=m +CONFIG_USB_G_ACM_MS=m +CONFIG_USB_G_MULTI=m +CONFIG_USB_G_MULTI_CDC=y +CONFIG_MMC=y +CONFIG_MMC_ATMELMCI=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_GPIO=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_AT91RM9200=y +CONFIG_RTC_DRV_AT91SAM9=y +CONFIG_DMADEVICES=y +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_EXT2_FS=y +CONFIG_FANOTIFY=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_ROOT_NFS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_CODEPAGE_850=y +CONFIG_NLS_ISO8859_1=y +CONFIG_STRIP_ASM_SYMS=y +CONFIG_DEBUG_FS=y +# CONFIG_SCHED_DEBUG is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_FTRACE is not set +CONFIG_DEBUG_USER=y +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_AES=y +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_USER_API_HASH=m +CONFIG_CRYPTO_USER_API_SKCIPHER=m +# CONFIG_CRYPTO_HW is not set +CONFIG_CRC_CCITT=m +CONFIG_CRC_ITU_T=m +CONFIG_CRC7=m +CONFIG_AVERAGE=y diff --git a/trunk/arch/arm/configs/at91rm9200_defconfig b/trunk/arch/arm/configs/at91rm9200_defconfig index bbe4e1a1f5d8..d54e2acd3ab1 100644 --- a/trunk/arch/arm/configs/at91rm9200_defconfig +++ b/trunk/arch/arm/configs/at91rm9200_defconfig @@ -14,6 +14,7 @@ CONFIG_MODULE_SRCVERSION_ALL=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_IOSCHED_CFQ is not set CONFIG_ARCH_AT91=y +CONFIG_ARCH_AT91RM9200=y CONFIG_MACH_ONEARM=y CONFIG_ARCH_AT91RM9200DK=y CONFIG_MACH_AT91RM9200EK=y diff --git a/trunk/arch/arm/configs/bcmring_defconfig b/trunk/arch/arm/configs/bcmring_defconfig index 795374d48f81..9e6a8fe13164 100644 --- a/trunk/arch/arm/configs/bcmring_defconfig +++ b/trunk/arch/arm/configs/bcmring_defconfig @@ -11,7 +11,7 @@ CONFIG_KALLSYMS_EXTRA_PASS=y # CONFIG_TIMERFD is not set # CONFIG_EVENTFD is not set # CONFIG_AIO is not set -CONFIG_PERF_COUNTERS=y +CONFIG_PERF_EVENTS=y # CONFIG_VM_EVENT_COUNTERS is not set # CONFIG_SLUB_DEBUG is not set # CONFIG_COMPAT_BRK is not set diff --git a/trunk/arch/arm/configs/imx_v4_v5_defconfig b/trunk/arch/arm/configs/imx_v4_v5_defconfig index 6b31cb60daab..09a02963cf58 100644 --- a/trunk/arch/arm/configs/imx_v4_v5_defconfig +++ b/trunk/arch/arm/configs/imx_v4_v5_defconfig @@ -92,6 +92,7 @@ CONFIG_INPUT_EVDEV=y # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_MC13783=m # CONFIG_SERIO is not set # CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_8250=m @@ -107,7 +108,8 @@ CONFIG_SPI_SPIDEV=y CONFIG_W1=y CONFIG_W1_MASTER_MXC=y CONFIG_W1_SLAVE_THERM=y -# CONFIG_HWMON is not set +CONFIG_HWMON=m +CONFIG_SENSORS_MC13783_ADC=m CONFIG_WATCHDOG=y CONFIG_IMX2_WDT=y CONFIG_MFD_MC13XXX=y diff --git a/trunk/arch/arm/configs/ixp2000_defconfig b/trunk/arch/arm/configs/ixp2000_defconfig deleted file mode 100644 index 8405aded97a3..000000000000 --- a/trunk/arch/arm/configs/ixp2000_defconfig +++ /dev/null @@ -1,99 +0,0 @@ -CONFIG_EXPERIMENTAL=y -CONFIG_SYSVIPC=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -CONFIG_EXPERT=y -# CONFIG_HOTPLUG is not set -CONFIG_SLAB=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -CONFIG_ARCH_IXP2000=y -CONFIG_ARCH_ENP2611=y -CONFIG_ARCH_IXDP2400=y -CONFIG_ARCH_IXDP2800=y -CONFIG_ARCH_IXDP2401=y -CONFIG_ARCH_IXDP2801=y -# CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO is not set -# CONFIG_ARM_THUMB is not set -CONFIG_CPU_BIG_ENDIAN=y -CONFIG_ZBOOT_ROM_TEXT=0x0 -CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="console=ttyS0,57600 root=/dev/nfs ip=bootp mem=64M@0x0" -CONFIG_FPE_NWFPE=y -CONFIG_FPE_NWFPE_XP=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_SYN_COOKIES=y -CONFIG_IPV6=y -# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET6_XFRM_MODE_TUNNEL is not set -# CONFIG_INET6_XFRM_MODE_BEET is not set -# CONFIG_IPV6_SIT is not set -# CONFIG_PREVENT_FIRMWARE_BUILD is not set -CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y -CONFIG_MTD_REDBOOT_PARTS=y -CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y -CONFIG_MTD_REDBOOT_PARTS_READONLY=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_CFI_INTELEXT=y -CONFIG_MTD_COMPLEX_MAPPINGS=y -CONFIG_MTD_IXP2000=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_NBD=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_EEPROM_LEGACY=y -CONFIG_NETDEVICES=y -CONFIG_DUMMY=y -CONFIG_NET_ETHERNET=y -CONFIG_NET_PCI=y -CONFIG_CS89x0=y -CONFIG_E100=y -CONFIG_ENP2611_MSF_NET=y -CONFIG_WAN=y -CONFIG_HDLC=y -CONFIG_HDLC_RAW=y -CONFIG_HDLC_CISCO=y -CONFIG_HDLC_FR=y -CONFIG_HDLC_PPP=y -CONFIG_DLCI=y -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -# CONFIG_VT is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_NR_UARTS=3 -# CONFIG_HW_RANDOM is not set -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_IXP2000=y -CONFIG_WATCHDOG=y -CONFIG_IXP2000_WATCHDOG=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT2_FS_POSIX_ACL=y -CONFIG_EXT3_FS=y -CONFIG_EXT3_FS_POSIX_ACL=y -CONFIG_INOTIFY=y -CONFIG_TMPFS=y -CONFIG_JFFS2_FS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DEBUG_MUTEXES=y -CONFIG_DEBUG_USER=y -CONFIG_DEBUG_ERRORS=y -CONFIG_DEBUG_LL=y diff --git a/trunk/arch/arm/configs/ixp23xx_defconfig b/trunk/arch/arm/configs/ixp23xx_defconfig deleted file mode 100644 index 688717612e91..000000000000 --- a/trunk/arch/arm/configs/ixp23xx_defconfig +++ /dev/null @@ -1,105 +0,0 @@ -CONFIG_EXPERIMENTAL=y -CONFIG_SYSVIPC=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_BLK_DEV_INITRD=y -CONFIG_EXPERT=y -CONFIG_SLAB=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -CONFIG_ARCH_IXP23XX=y -CONFIG_MACH_ESPRESSO=y -CONFIG_MACH_IXDP2351=y -CONFIG_MACH_ROADRUNNER=y -# CONFIG_ARM_THUMB is not set -CONFIG_CPU_BIG_ENDIAN=y -CONFIG_ZBOOT_ROM_TEXT=0x0 -CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs ip=bootp" -CONFIG_FPE_NWFPE=y -CONFIG_FPE_NWFPE_XP=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_SYN_COOKIES=y -CONFIG_IPV6=y -# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET6_XFRM_MODE_TUNNEL is not set -# CONFIG_INET6_XFRM_MODE_BEET is not set -# CONFIG_IPV6_SIT is not set -# CONFIG_PREVENT_FIRMWARE_BUILD is not set -# CONFIG_FW_LOADER is not set -CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y -CONFIG_MTD_REDBOOT_PARTS=y -CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y -CONFIG_MTD_REDBOOT_PARTS_READONLY=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_CFI_INTELEXT=y -CONFIG_MTD_COMPLEX_MAPPINGS=y -CONFIG_MTD_PHYSMAP=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_NBD=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_EEPROM_LEGACY=y -CONFIG_IDE=y -CONFIG_BLK_DEV_SIIMAGE=y -CONFIG_SCSI=y -CONFIG_BLK_DEV_SD=y -CONFIG_NETDEVICES=y -CONFIG_DUMMY=y -CONFIG_NET_ETHERNET=y -CONFIG_NET_PCI=y -CONFIG_E100=y -CONFIG_E1000=y -CONFIG_WAN=y -CONFIG_HDLC=y -CONFIG_HDLC_RAW=y -CONFIG_HDLC_CISCO=y -CONFIG_HDLC_FR=y -CONFIG_HDLC_PPP=y -CONFIG_DLCI=y -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -# CONFIG_VT is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -# CONFIG_HW_RANDOM is not set -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_WATCHDOG=y -# CONFIG_USB_HID is not set -CONFIG_USB=y -CONFIG_USB_MON=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_UHCI_HCD=y -CONFIG_USB_STORAGE=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT2_FS_POSIX_ACL=y -CONFIG_EXT3_FS=y -CONFIG_EXT3_FS_POSIX_ACL=y -CONFIG_INOTIFY=y -CONFIG_MSDOS_FS=y -CONFIG_TMPFS=y -CONFIG_JFFS2_FS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DEBUG_MUTEXES=y -CONFIG_DEBUG_USER=y -CONFIG_DEBUG_ERRORS=y -CONFIG_DEBUG_LL=y diff --git a/trunk/arch/arm/configs/kzm9g_defconfig b/trunk/arch/arm/configs/kzm9g_defconfig new file mode 100644 index 000000000000..e3ebc20ed0a7 --- /dev/null +++ b/trunk/arch/arm/configs/kzm9g_defconfig @@ -0,0 +1,139 @@ +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +CONFIG_EXPERIMENTAL=y +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=16 +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_IPC_NS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +# CONFIG_NET_NS is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_EMBEDDED=y +CONFIG_SLAB=y +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_ARCH_SHMOBILE=y +CONFIG_KEYBOARD_GPIO_POLLED=y +CONFIG_ARCH_SH73A0=y +CONFIG_MACH_KZM9G=y +CONFIG_MEMORY_START=0x41000000 +CONFIG_MEMORY_SIZE=0x1f000000 +CONFIG_ARM_ERRATA_743622=y +CONFIG_ARM_ERRATA_754322=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_SMP=y +CONFIG_SCHED_MC=y +CONFIG_PREEMPT=y +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +CONFIG_HIGHMEM=y +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="console=tty0 console=ttySC4,115200 root=/dev/nfs ip=dhcp ignore_loglevel earlyprintk=sh-sci.4,115200" +CONFIG_KEXEC=y +CONFIG_VFP=y +CONFIG_NEON=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_PM_RUNTIME=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=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_INET_DIAG is not set +# CONFIG_IPV6 is not set +CONFIG_IRDA=y +CONFIG_SH_IRDA=y +# CONFIG_WIRELESS is not set +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_NETDEVICES=y +CONFIG_SMSC911X=y +# CONFIG_WLAN is not set +CONFIG_INPUT_SPARSEKMAP=y +# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ST1232=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_SH_SCI=y +CONFIG_SERIAL_SH_SCI_NR_UARTS=9 +CONFIG_SERIAL_SH_SCI_CONSOLE=y +# CONFIG_HW_RANDOM is not set +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_SH_MOBILE=y +CONFIG_GPIO_PCF857X=y +# CONFIG_HWMON is not set +CONFIG_FB=y +CONFIG_FB_SH_MOBILE_LCDC=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_LOGO=y +CONFIG_FB_SH_MOBILE_MERAM=y +CONFIG_SOUND=y +CONFIG_SND=y +# CONFIG_SND_SUPPORT_OLD_API is not set +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_ARM is not set +# CONFIG_SND_USB is not set +CONFIG_SND_SOC=y +CONFIG_SND_SOC_SH4_FSI=y +# CONFIG_HID_SUPPORT is not set +CONFIG_USB=y +CONFIG_USB_DEVICEFS=y +CONFIG_USB_R8A66597_HCD=y +CONFIG_USB_STORAGE=y +CONFIG_MMC=y +# CONFIG_MMC_BLOCK_BOUNCE is not set +CONFIG_MMC_SDHI=y +CONFIG_MMC_SH_MMCIF=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_RTC_CLASS=y +CONFIG_DMADEVICES=y +CONFIG_SH_DMAE=y +CONFIG_ASYNC_TX_DMA=y +CONFIG_STAGING=y +# CONFIG_DNOTIFY is not set +# CONFIG_INOTIFY_USER is not set +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +# CONFIG_MISC_FILESYSTEMS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_V4_1=y +CONFIG_ROOT_NFS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +# CONFIG_SCHED_DEBUG is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_FTRACE is not set +# CONFIG_ARM_UNWIND is not set +CONFIG_CRYPTO=y +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_DES=y +CONFIG_CRC16=y diff --git a/trunk/arch/arm/configs/lpc32xx_defconfig b/trunk/arch/arm/configs/lpc32xx_defconfig index fb2088171ca9..4fa60547494a 100644 --- a/trunk/arch/arm/configs/lpc32xx_defconfig +++ b/trunk/arch/arm/configs/lpc32xx_defconfig @@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_BUF_SHIFT=14 +CONFIG_LOG_BUF_SHIFT=16 CONFIG_SYSFS_DEPRECATED=y CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y @@ -10,6 +10,7 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_SYSCTL_SYSCALL=y CONFIG_EMBEDDED=y CONFIG_SLAB=y +CONFIG_JUMP_LABEL=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set @@ -21,6 +22,8 @@ CONFIG_PREEMPT=y CONFIG_AEABI=y CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_ARM_APPENDED_DTB=y +CONFIG_ARM_ATAG_DTB_COMPAT=y CONFIG_CMDLINE="console=ttyS0,115200n81 root=/dev/ram0" CONFIG_CPU_IDLE=y CONFIG_FPE_NWFPE=y @@ -40,7 +43,8 @@ CONFIG_IP_PNP_BOOTP=y # CONFIG_INET_XFRM_MODE_BEET is not set # CONFIG_INET_LRO is not set # CONFIG_INET_DIAG is not set -# CONFIG_IPV6 is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y # CONFIG_WIRELESS is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" # CONFIG_FW_LOADER is not set @@ -55,13 +59,24 @@ CONFIG_BLK_DEV_CRYPTOLOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=1 CONFIG_BLK_DEV_RAM_SIZE=16384 -CONFIG_MISC_DEVICES=y CONFIG_EEPROM_AT25=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_NETDEVICES=y CONFIG_MII=y -CONFIG_PHYLIB=y +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CIRRUS is not set +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +CONFIG_LPC_ENET=y +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set CONFIG_SMSC_PHY=y # CONFIG_WLAN is not set # CONFIG_INPUT_MOUSEDEV_PSAUX is not set @@ -97,16 +112,22 @@ CONFIG_SND_SEQUENCER=y CONFIG_SND_MIXER_OSS=y CONFIG_SND_PCM_OSS=y CONFIG_SND_SEQUENCER_OSS=y -CONFIG_SND_DYNAMIC_MINORS=y +# CONFIG_SND_SUPPORT_OLD_API is not set # CONFIG_SND_VERBOSE_PROCFS is not set +CONFIG_SND_DEBUG=y +CONFIG_SND_DEBUG_VERBOSE=y # CONFIG_SND_DRIVERS is not set # CONFIG_SND_ARM is not set # CONFIG_SND_SPI is not set CONFIG_SND_SOC=y # CONFIG_HID_SUPPORT is not set CONFIG_USB=y +CONFIG_USB_OHCI_HCD=y CONFIG_USB_STORAGE=y -CONFIG_USB_LIBUSUAL=y +CONFIG_USB_GADGET=y +CONFIG_USB_LPC32XX=y +CONFIG_USB_MASS_STORAGE=m +CONFIG_USB_G_SERIAL=m CONFIG_MMC=y # CONFIG_MMC_BLOCK_BOUNCE is not set CONFIG_MMC_ARMMMCI=y @@ -114,10 +135,21 @@ CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_GPIO=y CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_BACKLIGHT=y +CONFIG_LEDS_TRIGGER_GPIO=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y CONFIG_RTC_CLASS=y CONFIG_RTC_INTF_DEV_UIE_EMUL=y +CONFIG_RTC_DRV_DS1374=y +CONFIG_RTC_DRV_PCF8563=y CONFIG_RTC_DRV_LPC32XX=y +CONFIG_DMADEVICES=y +CONFIG_AMBA_PL08X=y +CONFIG_STAGING=y +CONFIG_IIO=y +CONFIG_LPC32XX_ADC=y CONFIG_EXT2_FS=y CONFIG_AUTOFS4_FS=y CONFIG_MSDOS_FS=y diff --git a/trunk/arch/arm/configs/nhk8815_defconfig b/trunk/arch/arm/configs/nhk8815_defconfig index 37207d1bf44b..bf123c5384d4 100644 --- a/trunk/arch/arm/configs/nhk8815_defconfig +++ b/trunk/arch/arm/configs/nhk8815_defconfig @@ -97,6 +97,7 @@ CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_GPIO=y CONFIG_DEBUG_GPIO=y +CONFIG_PINCTRL_NOMADIK=y # CONFIG_HWMON is not set # CONFIG_VGA_CONSOLE is not set CONFIG_RTC_CLASS=y diff --git a/trunk/arch/arm/configs/omap2plus_defconfig b/trunk/arch/arm/configs/omap2plus_defconfig index d5f00d7eb075..9854ff4279e0 100644 --- a/trunk/arch/arm/configs/omap2plus_defconfig +++ b/trunk/arch/arm/configs/omap2plus_defconfig @@ -98,6 +98,7 @@ CONFIG_LIBERTAS_USB=m CONFIG_LIBERTAS_SDIO=m CONFIG_LIBERTAS_DEBUG=y CONFIG_USB_USBNET=y +CONFIG_USB_NET_SMSC95XX=y CONFIG_USB_ALI_M5632=y CONFIG_USB_AN2720=y CONFIG_USB_EPSON2888=y @@ -175,6 +176,7 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_DEVICEFS=y CONFIG_USB_SUSPEND=y CONFIG_USB_MON=y +CONFIG_USB_EHCI_HCD=y CONFIG_USB_WDM=y CONFIG_USB_STORAGE=y CONFIG_USB_LIBUSUAL=y diff --git a/trunk/arch/arm/configs/rpc_defconfig b/trunk/arch/arm/configs/rpc_defconfig index af278f7a2246..00515ef9782d 100644 --- a/trunk/arch/arm/configs/rpc_defconfig +++ b/trunk/arch/arm/configs/rpc_defconfig @@ -8,8 +8,6 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set CONFIG_ARCH_RPC=y -CONFIG_CPU_ARM610=y -CONFIG_CPU_ARM710=y CONFIG_CPU_SA110=y CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 diff --git a/trunk/arch/arm/configs/spear3xx_defconfig b/trunk/arch/arm/configs/spear3xx_defconfig index fea7e1f026a3..7ed42912d69a 100644 --- a/trunk/arch/arm/configs/spear3xx_defconfig +++ b/trunk/arch/arm/configs/spear3xx_defconfig @@ -2,33 +2,67 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_BLK_DEV_INITRD=y -CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODVERSIONS=y +CONFIG_PARTITION_ADVANCED=y CONFIG_PLAT_SPEAR=y -CONFIG_BOARD_SPEAR300_EVB=y -CONFIG_BOARD_SPEAR310_EVB=y -CONFIG_BOARD_SPEAR320_EVB=y +CONFIG_MACH_SPEAR300=y +CONFIG_MACH_SPEAR310=y +CONFIG_MACH_SPEAR320=y CONFIG_BINFMT_MISC=y +CONFIG_NET=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_MTD=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_FSMC=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_NETDEVICES=y +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_CIRRUS is not set +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SMSC is not set +CONFIG_STMMAC_ETH=y +# CONFIG_WLAN is not set CONFIG_INPUT_FF_MEMLESS=y # CONFIG_INPUT_MOUSEDEV_PSAUX is not set -# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_KEYBOARD_ATKBD is not set +CONFIG_KEYBOARD_SPEAR=y # CONFIG_INPUT_MOUSE is not set +# CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_AMBA_PL011=y CONFIG_SERIAL_AMBA_PL011_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set # CONFIG_HW_RANDOM is not set CONFIG_RAW_DRIVER=y CONFIG_MAX_RAW_DEVS=8192 +CONFIG_I2C=y +CONFIG_I2C_DESIGNWARE_PLATFORM=y +CONFIG_SPI=y +CONFIG_SPI_PL022=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_PL061=y # CONFIG_HWMON is not set +CONFIG_WATCHDOG=y +CONFIG_ARM_SP805_WATCHDOG=y +CONFIG_FB=y +CONFIG_FB_ARMCLCD=y # CONFIG_HID_SUPPORT is not set -# CONFIG_USB_SUPPORT is not set +CONFIG_USB=y +# CONFIG_USB_DEVICE_CLASS is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_OHCI_HCD=y +CONFIG_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_SPEAR=y +CONFIG_RTC_CLASS=y +CONFIG_DMADEVICES=y +CONFIG_AMBA_PL08X=y +CONFIG_DMATEST=m CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_SECURITY=y @@ -39,8 +73,6 @@ CONFIG_MSDOS_FS=m CONFIG_VFAT_FS=m CONFIG_FAT_DEFAULT_IOCHARSET="ascii" CONFIG_TMPFS=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_NLS=y CONFIG_NLS_DEFAULT="utf8" CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=m @@ -48,6 +80,4 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_SPINLOCK=y -CONFIG_DEBUG_SPINLOCK_SLEEP=y CONFIG_DEBUG_INFO=y -# CONFIG_CRC32 is not set diff --git a/trunk/arch/arm/configs/spear6xx_defconfig b/trunk/arch/arm/configs/spear6xx_defconfig index cef2e836afd2..cf94bc73a0e0 100644 --- a/trunk/arch/arm/configs/spear6xx_defconfig +++ b/trunk/arch/arm/configs/spear6xx_defconfig @@ -2,29 +2,58 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_BLK_DEV_INITRD=y -CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODVERSIONS=y +CONFIG_PARTITION_ADVANCED=y CONFIG_PLAT_SPEAR=y CONFIG_ARCH_SPEAR6XX=y -CONFIG_BOARD_SPEAR600_EVB=y +CONFIG_BOARD_SPEAR600_DT=y CONFIG_BINFMT_MISC=y +CONFIG_NET=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_MTD=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_FSMC=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_NETDEVICES=y +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_CIRRUS is not set +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SMSC is not set +CONFIG_STMMAC_ETH=y +# CONFIG_WLAN is not set CONFIG_INPUT_FF_MEMLESS=y # CONFIG_INPUT_MOUSEDEV_PSAUX is not set +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_AMBA_PL011=y CONFIG_SERIAL_AMBA_PL011_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set CONFIG_RAW_DRIVER=y CONFIG_MAX_RAW_DEVS=8192 +CONFIG_I2C=y +CONFIG_I2C_DESIGNWARE_PLATFORM=y +CONFIG_SPI=y +CONFIG_SPI_PL022=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_PL061=y # CONFIG_HWMON is not set +CONFIG_WATCHDOG=y +CONFIG_ARM_SP805_WATCHDOG=y # CONFIG_HID_SUPPORT is not set -# CONFIG_USB_SUPPORT is not set +CONFIG_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_OHCI_HCD=y +CONFIG_RTC_CLASS=y +CONFIG_DMADEVICES=y +CONFIG_AMBA_PL08X=y +CONFIG_DMATEST=m CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_SECURITY=y @@ -35,8 +64,6 @@ CONFIG_MSDOS_FS=m CONFIG_VFAT_FS=m CONFIG_FAT_DEFAULT_IOCHARSET="ascii" CONFIG_TMPFS=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_NLS=y CONFIG_NLS_DEFAULT="utf8" CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=m @@ -44,6 +71,4 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_SPINLOCK=y -CONFIG_DEBUG_SPINLOCK_SLEEP=y CONFIG_DEBUG_INFO=y -# CONFIG_CRC32 is not set diff --git a/trunk/arch/arm/include/asm/arch_timer.h b/trunk/arch/arm/include/asm/arch_timer.h new file mode 100644 index 000000000000..ed2e95d46e29 --- /dev/null +++ b/trunk/arch/arm/include/asm/arch_timer.h @@ -0,0 +1,19 @@ +#ifndef __ASMARM_ARCH_TIMER_H +#define __ASMARM_ARCH_TIMER_H + +#ifdef CONFIG_ARM_ARCH_TIMER +int arch_timer_of_register(void); +int arch_timer_sched_clock_init(void); +#else +static inline int arch_timer_of_register(void) +{ + return -ENXIO; +} + +static inline int arch_timer_sched_clock_init(void) +{ + return -ENXIO; +} +#endif + +#endif diff --git a/trunk/arch/arm/include/asm/cacheflush.h b/trunk/arch/arm/include/asm/cacheflush.h index d5d8d5c72682..004c1bc95d2b 100644 --- a/trunk/arch/arm/include/asm/cacheflush.h +++ b/trunk/arch/arm/include/asm/cacheflush.h @@ -101,7 +101,7 @@ struct cpu_cache_fns { void (*flush_user_range)(unsigned long, unsigned long, unsigned int); void (*coherent_kern_range)(unsigned long, unsigned long); - void (*coherent_user_range)(unsigned long, unsigned long); + int (*coherent_user_range)(unsigned long, unsigned long); void (*flush_kern_dcache_area)(void *, size_t); void (*dma_map_area)(const void *, size_t, int); @@ -142,7 +142,7 @@ extern void __cpuc_flush_kern_all(void); extern void __cpuc_flush_user_all(void); extern void __cpuc_flush_user_range(unsigned long, unsigned long, unsigned int); extern void __cpuc_coherent_kern_range(unsigned long, unsigned long); -extern void __cpuc_coherent_user_range(unsigned long, unsigned long); +extern int __cpuc_coherent_user_range(unsigned long, unsigned long); extern void __cpuc_flush_dcache_area(void *, size_t); /* @@ -249,7 +249,7 @@ extern void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr * Harvard caches are synchronised for the user space address range. * This is used for the ARM private sys_cacheflush system call. */ -#define flush_cache_user_range(vma,start,end) \ +#define flush_cache_user_range(start,end) \ __cpuc_coherent_user_range((start) & PAGE_MASK, PAGE_ALIGN(end)) /* diff --git a/trunk/arch/arm/include/asm/cmpxchg.h b/trunk/arch/arm/include/asm/cmpxchg.h index d41d7cbf0ada..7eb18c1d8d6c 100644 --- a/trunk/arch/arm/include/asm/cmpxchg.h +++ b/trunk/arch/arm/include/asm/cmpxchg.h @@ -229,66 +229,19 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr, (unsigned long)(n), \ sizeof(*(ptr)))) -#ifndef CONFIG_CPU_V6 /* min ARCH >= ARMv6K */ - -/* - * Note : ARMv7-M (currently unsupported by Linux) does not support - * ldrexd/strexd. If ARMv7-M is ever supported by the Linux kernel, it should - * not be allowed to use __cmpxchg64. - */ -static inline unsigned long long __cmpxchg64(volatile void *ptr, - unsigned long long old, - unsigned long long new) -{ - register unsigned long long oldval asm("r0"); - register unsigned long long __old asm("r2") = old; - register unsigned long long __new asm("r4") = new; - unsigned long res; - - do { - asm volatile( - " @ __cmpxchg8\n" - " ldrexd %1, %H1, [%2]\n" - " mov %0, #0\n" - " teq %1, %3\n" - " teqeq %H1, %H3\n" - " strexdeq %0, %4, %H4, [%2]\n" - : "=&r" (res), "=&r" (oldval) - : "r" (ptr), "Ir" (__old), "r" (__new) - : "memory", "cc"); - } while (res); - - return oldval; -} - -static inline unsigned long long __cmpxchg64_mb(volatile void *ptr, - unsigned long long old, - unsigned long long new) -{ - unsigned long long ret; - - smp_mb(); - ret = __cmpxchg64(ptr, old, new); - smp_mb(); - - return ret; -} - -#define cmpxchg64(ptr,o,n) \ - ((__typeof__(*(ptr)))__cmpxchg64_mb((ptr), \ - (unsigned long long)(o), \ - (unsigned long long)(n))) - -#define cmpxchg64_local(ptr,o,n) \ - ((__typeof__(*(ptr)))__cmpxchg64((ptr), \ - (unsigned long long)(o), \ - (unsigned long long)(n))) - -#else /* min ARCH = ARMv6 */ - -#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n)) - -#endif +#define cmpxchg64(ptr, o, n) \ + ((__typeof__(*(ptr)))atomic64_cmpxchg(container_of((ptr), \ + atomic64_t, \ + counter), \ + (unsigned long)(o), \ + (unsigned long)(n))) + +#define cmpxchg64_local(ptr, o, n) \ + ((__typeof__(*(ptr)))local64_cmpxchg(container_of((ptr), \ + local64_t, \ + a), \ + (unsigned long)(o), \ + (unsigned long)(n))) #endif /* __LINUX_ARM_ARCH__ >= 6 */ diff --git a/trunk/arch/arm/include/asm/cpu.h b/trunk/arch/arm/include/asm/cpu.h index 793968173bef..d797223b39d5 100644 --- a/trunk/arch/arm/include/asm/cpu.h +++ b/trunk/arch/arm/include/asm/cpu.h @@ -16,7 +16,6 @@ struct cpuinfo_arm { struct cpu cpu; #ifdef CONFIG_SMP - struct task_struct *idle; unsigned int loops_per_jiffy; #endif }; diff --git a/trunk/arch/arm/include/asm/glue-df.h b/trunk/arch/arm/include/asm/glue-df.h index 354d571e8bcc..8cacbcda76da 100644 --- a/trunk/arch/arm/include/asm/glue-df.h +++ b/trunk/arch/arm/include/asm/glue-df.h @@ -31,14 +31,6 @@ #undef CPU_DABORT_HANDLER #undef MULTI_DABORT -#if defined(CONFIG_CPU_ARM610) -# ifdef CPU_DABORT_HANDLER -# define MULTI_DABORT 1 -# else -# define CPU_DABORT_HANDLER cpu_arm6_data_abort -# endif -#endif - #if defined(CONFIG_CPU_ARM710) # ifdef CPU_DABORT_HANDLER # define MULTI_DABORT 1 diff --git a/trunk/arch/arm/include/asm/glue-proc.h b/trunk/arch/arm/include/asm/glue-proc.h index e2be7f142668..ac1dd54724b6 100644 --- a/trunk/arch/arm/include/asm/glue-proc.h +++ b/trunk/arch/arm/include/asm/glue-proc.h @@ -23,15 +23,6 @@ * CPU_NAME - the prefix for CPU related functions */ -#ifdef CONFIG_CPU_ARM610 -# ifdef CPU_NAME -# undef MULTI_CPU -# define MULTI_CPU -# else -# define CPU_NAME cpu_arm6 -# endif -#endif - #ifdef CONFIG_CPU_ARM7TDMI # ifdef CPU_NAME # undef MULTI_CPU @@ -41,15 +32,6 @@ # endif #endif -#ifdef CONFIG_CPU_ARM710 -# ifdef CPU_NAME -# undef MULTI_CPU -# define MULTI_CPU -# else -# define CPU_NAME cpu_arm7 -# endif -#endif - #ifdef CONFIG_CPU_ARM720T # ifdef CPU_NAME # undef MULTI_CPU diff --git a/trunk/arch/arm/include/asm/hardware/clps7111.h b/trunk/arch/arm/include/asm/hardware/clps7111.h deleted file mode 100644 index 44477225aed6..000000000000 --- a/trunk/arch/arm/include/asm/hardware/clps7111.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - * arch/arm/include/asm/hardware/clps7111.h - * - * This file contains the hardware definitions of the CLPS7111 internal - * registers. - * - * Copyright (C) 2000 Deep Blue Solutions Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __ASM_HARDWARE_CLPS7111_H -#define __ASM_HARDWARE_CLPS7111_H - -#define CLPS7111_PHYS_BASE (0x80000000) - -#ifndef __ASSEMBLY__ -#define clps_readb(off) __raw_readb(CLPS7111_BASE + (off)) -#define clps_readw(off) __raw_readw(CLPS7111_BASE + (off)) -#define clps_readl(off) __raw_readl(CLPS7111_BASE + (off)) -#define clps_writeb(val,off) __raw_writeb(val, CLPS7111_BASE + (off)) -#define clps_writew(val,off) __raw_writew(val, CLPS7111_BASE + (off)) -#define clps_writel(val,off) __raw_writel(val, CLPS7111_BASE + (off)) -#endif - -#define PADR (0x0000) -#define PBDR (0x0001) -#define PDDR (0x0003) -#define PADDR (0x0040) -#define PBDDR (0x0041) -#define PDDDR (0x0043) -#define PEDR (0x0080) -#define PEDDR (0x00c0) -#define SYSCON1 (0x0100) -#define SYSFLG1 (0x0140) -#define MEMCFG1 (0x0180) -#define MEMCFG2 (0x01c0) -#define DRFPR (0x0200) -#define INTSR1 (0x0240) -#define INTMR1 (0x0280) -#define LCDCON (0x02c0) -#define TC1D (0x0300) -#define TC2D (0x0340) -#define RTCDR (0x0380) -#define RTCMR (0x03c0) -#define PMPCON (0x0400) -#define CODR (0x0440) -#define UARTDR1 (0x0480) -#define UBRLCR1 (0x04c0) -#define SYNCIO (0x0500) -#define PALLSW (0x0540) -#define PALMSW (0x0580) -#define STFCLR (0x05c0) -#define BLEOI (0x0600) -#define MCEOI (0x0640) -#define TEOI (0x0680) -#define TC1EOI (0x06c0) -#define TC2EOI (0x0700) -#define RTCEOI (0x0740) -#define UMSEOI (0x0780) -#define COEOI (0x07c0) -#define HALT (0x0800) -#define STDBY (0x0840) - -#define FBADDR (0x1000) -#define SYSCON2 (0x1100) -#define SYSFLG2 (0x1140) -#define INTSR2 (0x1240) -#define INTMR2 (0x1280) -#define UARTDR2 (0x1480) -#define UBRLCR2 (0x14c0) -#define SS2DR (0x1500) -#define SRXEOF (0x1600) -#define SS2POP (0x16c0) -#define KBDEOI (0x1700) - -/* common bits: SYSCON1 / SYSCON2 */ -#define SYSCON_UARTEN (1 << 8) - -#define SYSCON1_KBDSCAN(x) ((x) & 15) -#define SYSCON1_KBDSCANMASK (15) -#define SYSCON1_TC1M (1 << 4) -#define SYSCON1_TC1S (1 << 5) -#define SYSCON1_TC2M (1 << 6) -#define SYSCON1_TC2S (1 << 7) -#define SYSCON1_UART1EN SYSCON_UARTEN -#define SYSCON1_BZTOG (1 << 9) -#define SYSCON1_BZMOD (1 << 10) -#define SYSCON1_DBGEN (1 << 11) -#define SYSCON1_LCDEN (1 << 12) -#define SYSCON1_CDENTX (1 << 13) -#define SYSCON1_CDENRX (1 << 14) -#define SYSCON1_SIREN (1 << 15) -#define SYSCON1_ADCKSEL(x) (((x) & 3) << 16) -#define SYSCON1_ADCKSEL_MASK (3 << 16) -#define SYSCON1_EXCKEN (1 << 18) -#define SYSCON1_WAKEDIS (1 << 19) -#define SYSCON1_IRTXM (1 << 20) - -/* common bits: SYSFLG1 / SYSFLG2 */ -#define SYSFLG_UBUSY (1 << 11) -#define SYSFLG_URXFE (1 << 22) -#define SYSFLG_UTXFF (1 << 23) - -#define SYSFLG1_MCDR (1 << 0) -#define SYSFLG1_DCDET (1 << 1) -#define SYSFLG1_WUDR (1 << 2) -#define SYSFLG1_WUON (1 << 3) -#define SYSFLG1_CTS (1 << 8) -#define SYSFLG1_DSR (1 << 9) -#define SYSFLG1_DCD (1 << 10) -#define SYSFLG1_UBUSY SYSFLG_UBUSY -#define SYSFLG1_NBFLG (1 << 12) -#define SYSFLG1_RSTFLG (1 << 13) -#define SYSFLG1_PFFLG (1 << 14) -#define SYSFLG1_CLDFLG (1 << 15) -#define SYSFLG1_URXFE SYSFLG_URXFE -#define SYSFLG1_UTXFF SYSFLG_UTXFF -#define SYSFLG1_CRXFE (1 << 24) -#define SYSFLG1_CTXFF (1 << 25) -#define SYSFLG1_SSIBUSY (1 << 26) -#define SYSFLG1_ID (1 << 29) - -#define SYSFLG2_SSRXOF (1 << 0) -#define SYSFLG2_RESVAL (1 << 1) -#define SYSFLG2_RESFRM (1 << 2) -#define SYSFLG2_SS2RXFE (1 << 3) -#define SYSFLG2_SS2TXFF (1 << 4) -#define SYSFLG2_SS2TXUF (1 << 5) -#define SYSFLG2_CKMODE (1 << 6) -#define SYSFLG2_UBUSY SYSFLG_UBUSY -#define SYSFLG2_URXFE SYSFLG_URXFE -#define SYSFLG2_UTXFF SYSFLG_UTXFF - -#define LCDCON_GSEN (1 << 30) -#define LCDCON_GSMD (1 << 31) - -#define SYSCON2_SERSEL (1 << 0) -#define SYSCON2_KBD6 (1 << 1) -#define SYSCON2_DRAMZ (1 << 2) -#define SYSCON2_KBWEN (1 << 3) -#define SYSCON2_SS2TXEN (1 << 4) -#define SYSCON2_PCCARD1 (1 << 5) -#define SYSCON2_PCCARD2 (1 << 6) -#define SYSCON2_SS2RXEN (1 << 7) -#define SYSCON2_UART2EN SYSCON_UARTEN -#define SYSCON2_SS2MAEN (1 << 9) -#define SYSCON2_OSTB (1 << 12) -#define SYSCON2_CLKENSL (1 << 13) -#define SYSCON2_BUZFREQ (1 << 14) - -/* common bits: UARTDR1 / UARTDR2 */ -#define UARTDR_FRMERR (1 << 8) -#define UARTDR_PARERR (1 << 9) -#define UARTDR_OVERR (1 << 10) - -/* common bits: UBRLCR1 / UBRLCR2 */ -#define UBRLCR_BAUD_MASK ((1 << 12) - 1) -#define UBRLCR_BREAK (1 << 12) -#define UBRLCR_PRTEN (1 << 13) -#define UBRLCR_EVENPRT (1 << 14) -#define UBRLCR_XSTOP (1 << 15) -#define UBRLCR_FIFOEN (1 << 16) -#define UBRLCR_WRDLEN5 (0 << 17) -#define UBRLCR_WRDLEN6 (1 << 17) -#define UBRLCR_WRDLEN7 (2 << 17) -#define UBRLCR_WRDLEN8 (3 << 17) -#define UBRLCR_WRDLEN_MASK (3 << 17) - -#define SYNCIO_SMCKEN (1 << 13) -#define SYNCIO_TXFRMEN (1 << 14) - -#endif /* __ASM_HARDWARE_CLPS7111_H */ diff --git a/trunk/arch/arm/include/asm/hardware/cs89712.h b/trunk/arch/arm/include/asm/hardware/cs89712.h deleted file mode 100644 index f75626933e94..000000000000 --- a/trunk/arch/arm/include/asm/hardware/cs89712.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * arch/arm/include/asm/hardware/cs89712.h - * - * This file contains the hardware definitions of the CS89712 - * additional internal registers. - * - * Copyright (C) 2001 Thomas Gleixner autronix automation - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __ASM_HARDWARE_CS89712_H -#define __ASM_HARDWARE_CS89712_H - -/* -* CS89712 additional registers -*/ - -#define PCDR 0x0002 /* Port C Data register ---------------------------- */ -#define PCDDR 0x0042 /* Port C Data Direction register ------------------ */ -#define SDCONF 0x2300 /* SDRAM Configuration register ---------------------*/ -#define SDRFPR 0x2340 /* SDRAM Refresh period register --------------------*/ - -#define SDCONF_ACTIVE (1 << 10) -#define SDCONF_CLKCTL (1 << 9) -#define SDCONF_WIDTH_4 (0 << 7) -#define SDCONF_WIDTH_8 (1 << 7) -#define SDCONF_WIDTH_16 (2 << 7) -#define SDCONF_WIDTH_32 (3 << 7) -#define SDCONF_SIZE_16 (0 << 5) -#define SDCONF_SIZE_64 (1 << 5) -#define SDCONF_SIZE_128 (2 << 5) -#define SDCONF_SIZE_256 (3 << 5) -#define SDCONF_CASLAT_2 (2) -#define SDCONF_CASLAT_3 (3) - -#endif /* __ASM_HARDWARE_CS89712_H */ diff --git a/trunk/arch/arm/include/asm/hardware/ep7211.h b/trunk/arch/arm/include/asm/hardware/ep7211.h deleted file mode 100644 index 654d5f625c49..000000000000 --- a/trunk/arch/arm/include/asm/hardware/ep7211.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * arch/arm/include/asm/hardware/ep7211.h - * - * This file contains the hardware definitions of the EP7211 internal - * registers. - * - * Copyright (C) 2001 Blue Mug, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __ASM_HARDWARE_EP7211_H -#define __ASM_HARDWARE_EP7211_H - -#include - -/* - * define EP7211_BASE to be the base address of the region - * you want to access. - */ - -#define EP7211_PHYS_BASE (0x80000000) - -/* - * XXX miket@bluemug.com: need to introduce EP7211 registers (those not - * present in 7212) here. - */ - -#endif /* __ASM_HARDWARE_EP7211_H */ diff --git a/trunk/arch/arm/include/asm/hardware/ep7212.h b/trunk/arch/arm/include/asm/hardware/ep7212.h deleted file mode 100644 index 3b43bbeaf1db..000000000000 --- a/trunk/arch/arm/include/asm/hardware/ep7212.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * arch/arm/include/asm/hardware/ep7212.h - * - * This file contains the hardware definitions of the EP7212 internal - * registers. - * - * Copyright (C) 2000 Deep Blue Solutions Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __ASM_HARDWARE_EP7212_H -#define __ASM_HARDWARE_EP7212_H - -/* - * define EP7212_BASE to be the base address of the region - * you want to access. - */ - -#define EP7212_PHYS_BASE (0x80000000) - -#ifndef __ASSEMBLY__ -#define ep_readl(off) __raw_readl(EP7212_BASE + (off)) -#define ep_writel(val,off) __raw_writel(val, EP7212_BASE + (off)) -#endif - -/* - * These registers are specific to the EP7212 only - */ -#define DAIR 0x2000 -#define DAIR0 0x2040 -#define DAIDR1 0x2080 -#define DAIDR2 0x20c0 -#define DAISR 0x2100 -#define SYSCON3 0x2200 -#define INTSR3 0x2240 -#define INTMR3 0x2280 -#define LEDFLSH 0x22c0 - -#define DAIR_DAIEN (1 << 16) -#define DAIR_ECS (1 << 17) -#define DAIR_LCTM (1 << 19) -#define DAIR_LCRM (1 << 20) -#define DAIR_RCTM (1 << 21) -#define DAIR_RCRM (1 << 22) -#define DAIR_LBM (1 << 23) - -#define DAIDR2_FIFOEN (1 << 15) -#define DAIDR2_FIFOLEFT (0x0d << 16) -#define DAIDR2_FIFORIGHT (0x11 << 16) - -#define DAISR_RCTS (1 << 0) -#define DAISR_RCRS (1 << 1) -#define DAISR_LCTS (1 << 2) -#define DAISR_LCRS (1 << 3) -#define DAISR_RCTU (1 << 4) -#define DAISR_RCRO (1 << 5) -#define DAISR_LCTU (1 << 6) -#define DAISR_LCRO (1 << 7) -#define DAISR_RCNF (1 << 8) -#define DAISR_RCNE (1 << 9) -#define DAISR_LCNF (1 << 10) -#define DAISR_LCNE (1 << 11) -#define DAISR_FIFO (1 << 12) - -#define SYSCON3_ADCCON (1 << 0) -#define SYSCON3_DAISEL (1 << 3) -#define SYSCON3_ADCCKNSEN (1 << 4) -#define SYSCON3_FASTWAKE (1 << 8) -#define SYSCON3_DAIEN (1 << 9) - -#endif /* __ASM_HARDWARE_EP7212_H */ diff --git a/trunk/arch/arm/include/asm/hardware/it8152.h b/trunk/arch/arm/include/asm/hardware/it8152.h index 73f84fa4f366..d36a73d7c0e8 100644 --- a/trunk/arch/arm/include/asm/hardware/it8152.h +++ b/trunk/arch/arm/include/asm/hardware/it8152.h @@ -110,6 +110,6 @@ extern void it8152_irq_demux(unsigned int irq, struct irq_desc *desc); extern void it8152_init_irq(void); extern int it8152_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin); extern int it8152_pci_setup(int nr, struct pci_sys_data *sys); -extern struct pci_bus *it8152_pci_scan_bus(int nr, struct pci_sys_data *sys); +extern struct pci_ops it8152_ops; #endif /* __ASM_HARDWARE_IT8152_H */ diff --git a/trunk/arch/arm/include/asm/hardware/uengine.h b/trunk/arch/arm/include/asm/hardware/uengine.h deleted file mode 100644 index b442d65c6593..000000000000 --- a/trunk/arch/arm/include/asm/hardware/uengine.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Generic library functions for the microengines found on the Intel - * IXP2000 series of network processors. - * - * Copyright (C) 2004, 2005 Lennert Buytenhek - * Dedicated to Marija Kulikova. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of the - * License, or (at your option) any later version. - */ - -#ifndef __IXP2000_UENGINE_H -#define __IXP2000_UENGINE_H - -extern u32 ixp2000_uengine_mask; - -struct ixp2000_uengine_code -{ - u32 cpu_model_bitmask; - u8 cpu_min_revision; - u8 cpu_max_revision; - - u32 uengine_parameters; - - struct ixp2000_reg_value { - int reg; - u32 value; - } *initial_reg_values; - - int num_insns; - u8 *insns; -}; - -u32 ixp2000_uengine_csr_read(int uengine, int offset); -void ixp2000_uengine_csr_write(int uengine, int offset, u32 value); -void ixp2000_uengine_reset(u32 uengine_mask); -void ixp2000_uengine_set_mode(int uengine, u32 mode); -void ixp2000_uengine_load_microcode(int uengine, u8 *ucode, int insns); -void ixp2000_uengine_init_context(int uengine, int context, int pc); -void ixp2000_uengine_start_contexts(int uengine, u8 ctx_mask); -void ixp2000_uengine_stop_contexts(int uengine, u8 ctx_mask); -int ixp2000_uengine_load(int uengine, struct ixp2000_uengine_code *c); - -#define IXP2000_UENGINE_8_CONTEXTS 0x00000000 -#define IXP2000_UENGINE_4_CONTEXTS 0x80000000 -#define IXP2000_UENGINE_PRN_UPDATE_EVERY 0x40000000 -#define IXP2000_UENGINE_PRN_UPDATE_ON_ACCESS 0x00000000 -#define IXP2000_UENGINE_NN_FROM_SELF 0x00100000 -#define IXP2000_UENGINE_NN_FROM_PREVIOUS 0x00000000 -#define IXP2000_UENGINE_ASSERT_EMPTY_AT_3 0x000c0000 -#define IXP2000_UENGINE_ASSERT_EMPTY_AT_2 0x00080000 -#define IXP2000_UENGINE_ASSERT_EMPTY_AT_1 0x00040000 -#define IXP2000_UENGINE_ASSERT_EMPTY_AT_0 0x00000000 -#define IXP2000_UENGINE_LM_ADDR1_GLOBAL 0x00020000 -#define IXP2000_UENGINE_LM_ADDR1_PER_CONTEXT 0x00000000 -#define IXP2000_UENGINE_LM_ADDR0_GLOBAL 0x00010000 -#define IXP2000_UENGINE_LM_ADDR0_PER_CONTEXT 0x00000000 - - -#endif diff --git a/trunk/arch/arm/include/asm/mach/pci.h b/trunk/arch/arm/include/asm/mach/pci.h index d943b7d20f11..26c511fddf8f 100644 --- a/trunk/arch/arm/include/asm/mach/pci.h +++ b/trunk/arch/arm/include/asm/mach/pci.h @@ -12,13 +12,14 @@ #define __ASM_MACH_PCI_H struct pci_sys_data; +struct pci_ops; struct pci_bus; struct hw_pci { #ifdef CONFIG_PCI_DOMAINS int domain; #endif - struct list_head buses; + struct pci_ops *ops; int nr_controllers; int (*setup)(int nr, struct pci_sys_data *); struct pci_bus *(*scan)(int nr, struct pci_sys_data *); @@ -45,15 +46,9 @@ struct pci_sys_data { u8 (*swizzle)(struct pci_dev *, u8 *); /* IRQ mapping */ int (*map_irq)(const struct pci_dev *, u8, u8); - struct hw_pci *hw; void *private_data; /* platform controller private data */ }; -/* - * This is the standard PCI-PCI bridge swizzling algorithm. - */ -#define pci_std_swizzle pci_common_swizzle - /* * Call this with your hw_pci struct to initialise the PCI system. */ @@ -62,22 +57,22 @@ void pci_common_init(struct hw_pci *); /* * PCI controllers */ +extern struct pci_ops iop3xx_ops; extern int iop3xx_pci_setup(int nr, struct pci_sys_data *); -extern struct pci_bus *iop3xx_pci_scan_bus(int nr, struct pci_sys_data *); extern void iop3xx_pci_preinit(void); extern void iop3xx_pci_preinit_cond(void); +extern struct pci_ops dc21285_ops; extern int dc21285_setup(int nr, struct pci_sys_data *); -extern struct pci_bus *dc21285_scan_bus(int nr, struct pci_sys_data *); extern void dc21285_preinit(void); extern void dc21285_postinit(void); +extern struct pci_ops via82c505_ops; extern int via82c505_setup(int nr, struct pci_sys_data *); -extern struct pci_bus *via82c505_scan_bus(int nr, struct pci_sys_data *); extern void via82c505_init(void *sysdata); +extern struct pci_ops pci_v3_ops; extern int pci_v3_setup(int nr, struct pci_sys_data *); -extern struct pci_bus *pci_v3_scan_bus(int nr, struct pci_sys_data *); extern void pci_v3_preinit(void); extern void pci_v3_postinit(void); diff --git a/trunk/arch/arm/include/asm/mach/time.h b/trunk/arch/arm/include/asm/mach/time.h index f73c908b7fa0..6ca945f534ab 100644 --- a/trunk/arch/arm/include/asm/mach/time.h +++ b/trunk/arch/arm/include/asm/mach/time.h @@ -42,4 +42,9 @@ struct sys_timer { extern void timer_tick(void); +struct timespec; +typedef void (*clock_access_fn)(struct timespec *); +extern int register_persistent_clock(clock_access_fn read_boot, + clock_access_fn read_persistent); + #endif diff --git a/trunk/arch/arm/include/asm/mmu.h b/trunk/arch/arm/include/asm/mmu.h index b8e580a297e4..14965658a923 100644 --- a/trunk/arch/arm/include/asm/mmu.h +++ b/trunk/arch/arm/include/asm/mmu.h @@ -34,11 +34,4 @@ typedef struct { #endif -/* - * switch_mm() may do a full cache flush over the context switch, - * so enable interrupts over the context switch to avoid high - * latency. - */ -#define __ARCH_WANT_INTERRUPTS_ON_CTXSW - #endif diff --git a/trunk/arch/arm/include/asm/mmu_context.h b/trunk/arch/arm/include/asm/mmu_context.h index a0b3cac0547c..0306bc642c0d 100644 --- a/trunk/arch/arm/include/asm/mmu_context.h +++ b/trunk/arch/arm/include/asm/mmu_context.h @@ -43,45 +43,104 @@ void __check_kvm_seq(struct mm_struct *mm); #define ASID_FIRST_VERSION (1 << ASID_BITS) extern unsigned int cpu_last_asid; -#ifdef CONFIG_SMP -DECLARE_PER_CPU(struct mm_struct *, current_mm); -#endif void __init_new_context(struct task_struct *tsk, struct mm_struct *mm); void __new_context(struct mm_struct *mm); +void cpu_set_reserved_ttbr0(void); -static inline void check_context(struct mm_struct *mm) +static inline void switch_new_context(struct mm_struct *mm) { - /* - * This code is executed with interrupts enabled. Therefore, - * mm->context.id cannot be updated to the latest ASID version - * on a different CPU (and condition below not triggered) - * without first getting an IPI to reset the context. The - * alternative is to take a read_lock on mm->context.id_lock - * (after changing its type to rwlock_t). - */ - if (unlikely((mm->context.id ^ cpu_last_asid) >> ASID_BITS)) - __new_context(mm); + unsigned long flags; + + __new_context(mm); + + local_irq_save(flags); + cpu_switch_mm(mm->pgd, mm); + local_irq_restore(flags); +} +static inline void check_and_switch_context(struct mm_struct *mm, + struct task_struct *tsk) +{ if (unlikely(mm->context.kvm_seq != init_mm.context.kvm_seq)) __check_kvm_seq(mm); + + /* + * Required during context switch to avoid speculative page table + * walking with the wrong TTBR. + */ + cpu_set_reserved_ttbr0(); + + if (!((mm->context.id ^ cpu_last_asid) >> ASID_BITS)) + /* + * The ASID is from the current generation, just switch to the + * new pgd. This condition is only true for calls from + * context_switch() and interrupts are already disabled. + */ + cpu_switch_mm(mm->pgd, mm); + else if (irqs_disabled()) + /* + * Defer the new ASID allocation until after the context + * switch critical region since __new_context() cannot be + * called with interrupts disabled (it sends IPIs). + */ + set_ti_thread_flag(task_thread_info(tsk), TIF_SWITCH_MM); + else + /* + * That is a direct call to switch_mm() or activate_mm() with + * interrupts enabled and a new context. + */ + switch_new_context(mm); } #define init_new_context(tsk,mm) (__init_new_context(tsk,mm),0) -#else - -static inline void check_context(struct mm_struct *mm) +#define finish_arch_post_lock_switch \ + finish_arch_post_lock_switch +static inline void finish_arch_post_lock_switch(void) { + if (test_and_clear_thread_flag(TIF_SWITCH_MM)) + switch_new_context(current->mm); +} + +#else /* !CONFIG_CPU_HAS_ASID */ + #ifdef CONFIG_MMU + +static inline void check_and_switch_context(struct mm_struct *mm, + struct task_struct *tsk) +{ if (unlikely(mm->context.kvm_seq != init_mm.context.kvm_seq)) __check_kvm_seq(mm); -#endif + + if (irqs_disabled()) + /* + * cpu_switch_mm() needs to flush the VIVT caches. To avoid + * high interrupt latencies, defer the call and continue + * running with the old mm. Since we only support UP systems + * on non-ASID CPUs, the old mm will remain valid until the + * finish_arch_post_lock_switch() call. + */ + set_ti_thread_flag(task_thread_info(tsk), TIF_SWITCH_MM); + else + cpu_switch_mm(mm->pgd, mm); } +#define finish_arch_post_lock_switch \ + finish_arch_post_lock_switch +static inline void finish_arch_post_lock_switch(void) +{ + if (test_and_clear_thread_flag(TIF_SWITCH_MM)) { + struct mm_struct *mm = current->mm; + cpu_switch_mm(mm->pgd, mm); + } +} + +#endif /* CONFIG_MMU */ + #define init_new_context(tsk,mm) 0 -#endif +#endif /* CONFIG_CPU_HAS_ASID */ #define destroy_context(mm) do { } while(0) @@ -119,12 +178,7 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next, __flush_icache_all(); #endif if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next) { -#ifdef CONFIG_SMP - struct mm_struct **crt_mm = &per_cpu(current_mm, cpu); - *crt_mm = next; -#endif - check_context(next); - cpu_switch_mm(next->pgd, next); + check_and_switch_context(next, tsk); if (cache_is_vivt()) cpumask_clear_cpu(cpu, mm_cpumask(prev)); } diff --git a/trunk/arch/arm/include/asm/page.h b/trunk/arch/arm/include/asm/page.h index 5838361c48b3..ecf901902e44 100644 --- a/trunk/arch/arm/include/asm/page.h +++ b/trunk/arch/arm/include/asm/page.h @@ -34,7 +34,6 @@ * processor(s) we're building for. * * We have the following to choose from: - * v3 - ARMv3 * v4wt - ARMv4 with writethrough cache, without minicache * v4wb - ARMv4 with writeback cache, without minicache * v4_mc - ARMv4 with minicache @@ -44,14 +43,6 @@ #undef _USER #undef MULTI_USER -#ifdef CONFIG_CPU_COPY_V3 -# ifdef _USER -# define MULTI_USER 1 -# else -# define _USER v3 -# endif -#endif - #ifdef CONFIG_CPU_COPY_V4WT # ifdef _USER # define MULTI_USER 1 diff --git a/trunk/arch/arm/include/asm/pgtable-3level.h b/trunk/arch/arm/include/asm/pgtable-3level.h index 759af70f9a0a..b24903549d1c 100644 --- a/trunk/arch/arm/include/asm/pgtable-3level.h +++ b/trunk/arch/arm/include/asm/pgtable-3level.h @@ -69,8 +69,6 @@ */ #define L_PTE_PRESENT (_AT(pteval_t, 3) << 0) /* Valid */ #define L_PTE_FILE (_AT(pteval_t, 1) << 2) /* only when !PRESENT */ -#define L_PTE_BUFFERABLE (_AT(pteval_t, 1) << 2) /* AttrIndx[0] */ -#define L_PTE_CACHEABLE (_AT(pteval_t, 1) << 3) /* AttrIndx[1] */ #define L_PTE_USER (_AT(pteval_t, 1) << 6) /* AP[1] */ #define L_PTE_RDONLY (_AT(pteval_t, 1) << 7) /* AP[2] */ #define L_PTE_SHARED (_AT(pteval_t, 3) << 8) /* SH[1:0], inner shareable */ diff --git a/trunk/arch/arm/include/asm/processor.h b/trunk/arch/arm/include/asm/processor.h index 5ac8d3d3e025..d7038fa22343 100644 --- a/trunk/arch/arm/include/asm/processor.h +++ b/trunk/arch/arm/include/asm/processor.h @@ -88,8 +88,6 @@ unsigned long get_wchan(struct task_struct *p); #define cpu_relax() barrier() #endif -void cpu_idle_wait(void); - /* * Create a new kernel thread */ diff --git a/trunk/arch/arm/include/asm/ptrace.h b/trunk/arch/arm/include/asm/ptrace.h index 451808ba1211..355ece523f41 100644 --- a/trunk/arch/arm/include/asm/ptrace.h +++ b/trunk/arch/arm/include/asm/ptrace.h @@ -249,6 +249,11 @@ static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) return regs->ARM_sp; } +static inline unsigned long user_stack_pointer(struct pt_regs *regs) +{ + return regs->ARM_sp; +} + #endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */ diff --git a/trunk/arch/arm/include/asm/syscall.h b/trunk/arch/arm/include/asm/syscall.h new file mode 100644 index 000000000000..c334a23ddf75 --- /dev/null +++ b/trunk/arch/arm/include/asm/syscall.h @@ -0,0 +1,93 @@ +/* + * Access to user system call parameters and results + * + * See asm-generic/syscall.h for descriptions of what we must do here. + */ + +#ifndef _ASM_ARM_SYSCALL_H +#define _ASM_ARM_SYSCALL_H + +#include + +extern const unsigned long sys_call_table[]; + +static inline int syscall_get_nr(struct task_struct *task, + struct pt_regs *regs) +{ + return task_thread_info(task)->syscall; +} + +static inline void syscall_rollback(struct task_struct *task, + struct pt_regs *regs) +{ + regs->ARM_r0 = regs->ARM_ORIG_r0; +} + +static inline long syscall_get_error(struct task_struct *task, + struct pt_regs *regs) +{ + unsigned long error = regs->ARM_r0; + return IS_ERR_VALUE(error) ? error : 0; +} + +static inline long syscall_get_return_value(struct task_struct *task, + struct pt_regs *regs) +{ + return regs->ARM_r0; +} + +static inline void syscall_set_return_value(struct task_struct *task, + struct pt_regs *regs, + int error, long val) +{ + regs->ARM_r0 = (long) error ? error : val; +} + +#define SYSCALL_MAX_ARGS 7 + +static inline void syscall_get_arguments(struct task_struct *task, + struct pt_regs *regs, + unsigned int i, unsigned int n, + unsigned long *args) +{ + if (i + n > SYSCALL_MAX_ARGS) { + unsigned long *args_bad = args + SYSCALL_MAX_ARGS - i; + unsigned int n_bad = n + i - SYSCALL_MAX_ARGS; + pr_warning("%s called with max args %d, handling only %d\n", + __func__, i + n, SYSCALL_MAX_ARGS); + memset(args_bad, 0, n_bad * sizeof(args[0])); + n = SYSCALL_MAX_ARGS - i; + } + + if (i == 0) { + args[0] = regs->ARM_ORIG_r0; + args++; + i++; + n--; + } + + memcpy(args, ®s->ARM_r0 + i, n * sizeof(args[0])); +} + +static inline void syscall_set_arguments(struct task_struct *task, + struct pt_regs *regs, + unsigned int i, unsigned int n, + const unsigned long *args) +{ + if (i + n > SYSCALL_MAX_ARGS) { + pr_warning("%s called with max args %d, handling only %d\n", + __func__, i + n, SYSCALL_MAX_ARGS); + n = SYSCALL_MAX_ARGS - i; + } + + if (i == 0) { + regs->ARM_ORIG_r0 = args[0]; + args++; + i++; + n--; + } + + memcpy(®s->ARM_r0 + i, args, n * sizeof(args[0])); +} + +#endif /* _ASM_ARM_SYSCALL_H */ diff --git a/trunk/arch/arm/include/asm/thread_info.h b/trunk/arch/arm/include/asm/thread_info.h index 0f04d84582e1..68388eb4946b 100644 --- a/trunk/arch/arm/include/asm/thread_info.h +++ b/trunk/arch/arm/include/asm/thread_info.h @@ -153,6 +153,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ #define TIF_RESTORE_SIGMASK 20 #define TIF_SECCOMP 21 +#define TIF_SWITCH_MM 22 /* deferred switch_mm */ #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) diff --git a/trunk/arch/arm/include/asm/tlbflush.h b/trunk/arch/arm/include/asm/tlbflush.h index 85fe61e73202..6e924d3a77eb 100644 --- a/trunk/arch/arm/include/asm/tlbflush.h +++ b/trunk/arch/arm/include/asm/tlbflush.h @@ -65,21 +65,6 @@ #define MULTI_TLB 1 #endif -#define v3_tlb_flags (TLB_V3_FULL | TLB_V3_PAGE) - -#ifdef CONFIG_CPU_TLB_V3 -# define v3_possible_flags v3_tlb_flags -# define v3_always_flags v3_tlb_flags -# ifdef _TLB -# define MULTI_TLB 1 -# else -# define _TLB v3 -# endif -#else -# define v3_possible_flags 0 -# define v3_always_flags (-1UL) -#endif - #define v4_tlb_flags (TLB_V4_U_FULL | TLB_V4_U_PAGE) #ifdef CONFIG_CPU_TLB_V4WT @@ -298,8 +283,7 @@ extern struct cpu_tlb_fns cpu_tlb; * implemented the "%?" method, but this has been discontinued due to too * many people getting it wrong. */ -#define possible_tlb_flags (v3_possible_flags | \ - v4_possible_flags | \ +#define possible_tlb_flags (v4_possible_flags | \ v4wbi_possible_flags | \ fr_possible_flags | \ v4wb_possible_flags | \ @@ -307,8 +291,7 @@ extern struct cpu_tlb_fns cpu_tlb; v6wbi_possible_flags | \ v7wbi_possible_flags) -#define always_tlb_flags (v3_always_flags & \ - v4_always_flags & \ +#define always_tlb_flags (v4_always_flags & \ v4wbi_always_flags & \ fr_always_flags & \ v4wb_always_flags & \ diff --git a/trunk/arch/arm/kernel/Makefile b/trunk/arch/arm/kernel/Makefile index 7b787d642af4..7ad2d5cf7008 100644 --- a/trunk/arch/arm/kernel/Makefile +++ b/trunk/arch/arm/kernel/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_ARM_CPU_SUSPEND) += sleep.o suspend.o obj-$(CONFIG_SMP) += smp.o smp_tlb.o obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o +obj-$(CONFIG_ARM_ARCH_TIMER) += arch_timer.o obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o insn.o obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o insn.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o insn.o patch.o @@ -81,4 +82,4 @@ head-y := head$(MMUEXT).o obj-$(CONFIG_DEBUG_LL) += debug.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o -extra-y := $(head-y) init_task.o vmlinux.lds +extra-y := $(head-y) vmlinux.lds diff --git a/trunk/arch/arm/kernel/arch_timer.c b/trunk/arch/arm/kernel/arch_timer.c new file mode 100644 index 000000000000..dd58035621f7 --- /dev/null +++ b/trunk/arch/arm/kernel/arch_timer.c @@ -0,0 +1,350 @@ +/* + * linux/arch/arm/kernel/arch_timer.c + * + * Copyright (C) 2011 ARM Ltd. + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static unsigned long arch_timer_rate; +static int arch_timer_ppi; +static int arch_timer_ppi2; + +static struct clock_event_device __percpu **arch_timer_evt; + +/* + * Architected system timer support. + */ + +#define ARCH_TIMER_CTRL_ENABLE (1 << 0) +#define ARCH_TIMER_CTRL_IT_MASK (1 << 1) +#define ARCH_TIMER_CTRL_IT_STAT (1 << 2) + +#define ARCH_TIMER_REG_CTRL 0 +#define ARCH_TIMER_REG_FREQ 1 +#define ARCH_TIMER_REG_TVAL 2 + +static void arch_timer_reg_write(int reg, u32 val) +{ + switch (reg) { + case ARCH_TIMER_REG_CTRL: + asm volatile("mcr p15, 0, %0, c14, c2, 1" : : "r" (val)); + break; + case ARCH_TIMER_REG_TVAL: + asm volatile("mcr p15, 0, %0, c14, c2, 0" : : "r" (val)); + break; + } + + isb(); +} + +static u32 arch_timer_reg_read(int reg) +{ + u32 val; + + switch (reg) { + case ARCH_TIMER_REG_CTRL: + asm volatile("mrc p15, 0, %0, c14, c2, 1" : "=r" (val)); + break; + case ARCH_TIMER_REG_FREQ: + asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (val)); + break; + case ARCH_TIMER_REG_TVAL: + asm volatile("mrc p15, 0, %0, c14, c2, 0" : "=r" (val)); + break; + default: + BUG(); + } + + return val; +} + +static irqreturn_t arch_timer_handler(int irq, void *dev_id) +{ + struct clock_event_device *evt = *(struct clock_event_device **)dev_id; + unsigned long ctrl; + + ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL); + if (ctrl & ARCH_TIMER_CTRL_IT_STAT) { + ctrl |= ARCH_TIMER_CTRL_IT_MASK; + arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl); + evt->event_handler(evt); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static void arch_timer_disable(void) +{ + unsigned long ctrl; + + ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL); + ctrl &= ~ARCH_TIMER_CTRL_ENABLE; + arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl); +} + +static void arch_timer_set_mode(enum clock_event_mode mode, + struct clock_event_device *clk) +{ + switch (mode) { + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + arch_timer_disable(); + break; + default: + break; + } +} + +static int arch_timer_set_next_event(unsigned long evt, + struct clock_event_device *unused) +{ + unsigned long ctrl; + + ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL); + ctrl |= ARCH_TIMER_CTRL_ENABLE; + ctrl &= ~ARCH_TIMER_CTRL_IT_MASK; + + arch_timer_reg_write(ARCH_TIMER_REG_TVAL, evt); + arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl); + + return 0; +} + +static int __cpuinit arch_timer_setup(struct clock_event_device *clk) +{ + /* Be safe... */ + arch_timer_disable(); + + clk->features = CLOCK_EVT_FEAT_ONESHOT; + clk->name = "arch_sys_timer"; + clk->rating = 450; + clk->set_mode = arch_timer_set_mode; + clk->set_next_event = arch_timer_set_next_event; + clk->irq = arch_timer_ppi; + + clockevents_config_and_register(clk, arch_timer_rate, + 0xf, 0x7fffffff); + + *__this_cpu_ptr(arch_timer_evt) = clk; + + enable_percpu_irq(clk->irq, 0); + if (arch_timer_ppi2) + enable_percpu_irq(arch_timer_ppi2, 0); + + return 0; +} + +/* Is the optional system timer available? */ +static int local_timer_is_architected(void) +{ + return (cpu_architecture() >= CPU_ARCH_ARMv7) && + ((read_cpuid_ext(CPUID_EXT_PFR1) >> 16) & 0xf) == 1; +} + +static int arch_timer_available(void) +{ + unsigned long freq; + + if (!local_timer_is_architected()) + return -ENXIO; + + if (arch_timer_rate == 0) { + arch_timer_reg_write(ARCH_TIMER_REG_CTRL, 0); + freq = arch_timer_reg_read(ARCH_TIMER_REG_FREQ); + + /* Check the timer frequency. */ + if (freq == 0) { + pr_warn("Architected timer frequency not available\n"); + return -EINVAL; + } + + arch_timer_rate = freq; + } + + pr_info_once("Architected local timer running at %lu.%02luMHz.\n", + arch_timer_rate / 1000000, (arch_timer_rate / 10000) % 100); + return 0; +} + +static inline cycle_t arch_counter_get_cntpct(void) +{ + u32 cvall, cvalh; + + asm volatile("mrrc p15, 0, %0, %1, c14" : "=r" (cvall), "=r" (cvalh)); + + return ((cycle_t) cvalh << 32) | cvall; +} + +static inline cycle_t arch_counter_get_cntvct(void) +{ + u32 cvall, cvalh; + + asm volatile("mrrc p15, 1, %0, %1, c14" : "=r" (cvall), "=r" (cvalh)); + + return ((cycle_t) cvalh << 32) | cvall; +} + +static u32 notrace arch_counter_get_cntvct32(void) +{ + cycle_t cntvct = arch_counter_get_cntvct(); + + /* + * The sched_clock infrastructure only knows about counters + * with at most 32bits. Forget about the upper 24 bits for the + * time being... + */ + return (u32)(cntvct & (u32)~0); +} + +static cycle_t arch_counter_read(struct clocksource *cs) +{ + return arch_counter_get_cntpct(); +} + +static struct clocksource clocksource_counter = { + .name = "arch_sys_counter", + .rating = 400, + .read = arch_counter_read, + .mask = CLOCKSOURCE_MASK(56), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static void __cpuinit arch_timer_stop(struct clock_event_device *clk) +{ + pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n", + clk->irq, smp_processor_id()); + disable_percpu_irq(clk->irq); + if (arch_timer_ppi2) + disable_percpu_irq(arch_timer_ppi2); + arch_timer_set_mode(CLOCK_EVT_MODE_UNUSED, clk); +} + +static struct local_timer_ops arch_timer_ops __cpuinitdata = { + .setup = arch_timer_setup, + .stop = arch_timer_stop, +}; + +static struct clock_event_device arch_timer_global_evt; + +static int __init arch_timer_register(void) +{ + int err; + + err = arch_timer_available(); + if (err) + return err; + + arch_timer_evt = alloc_percpu(struct clock_event_device *); + if (!arch_timer_evt) + return -ENOMEM; + + clocksource_register_hz(&clocksource_counter, arch_timer_rate); + + err = request_percpu_irq(arch_timer_ppi, arch_timer_handler, + "arch_timer", arch_timer_evt); + if (err) { + pr_err("arch_timer: can't register interrupt %d (%d)\n", + arch_timer_ppi, err); + goto out_free; + } + + if (arch_timer_ppi2) { + err = request_percpu_irq(arch_timer_ppi2, arch_timer_handler, + "arch_timer", arch_timer_evt); + if (err) { + pr_err("arch_timer: can't register interrupt %d (%d)\n", + arch_timer_ppi2, err); + arch_timer_ppi2 = 0; + goto out_free_irq; + } + } + + err = local_timer_register(&arch_timer_ops); + if (err) { + /* + * We couldn't register as a local timer (could be + * because we're on a UP platform, or because some + * other local timer is already present...). Try as a + * global timer instead. + */ + arch_timer_global_evt.cpumask = cpumask_of(0); + err = arch_timer_setup(&arch_timer_global_evt); + } + + if (err) + goto out_free_irq; + + return 0; + +out_free_irq: + free_percpu_irq(arch_timer_ppi, arch_timer_evt); + if (arch_timer_ppi2) + free_percpu_irq(arch_timer_ppi2, arch_timer_evt); + +out_free: + free_percpu(arch_timer_evt); + + return err; +} + +static const struct of_device_id arch_timer_of_match[] __initconst = { + { .compatible = "arm,armv7-timer", }, + {}, +}; + +int __init arch_timer_of_register(void) +{ + struct device_node *np; + u32 freq; + + np = of_find_matching_node(NULL, arch_timer_of_match); + if (!np) { + pr_err("arch_timer: can't find DT node\n"); + return -ENODEV; + } + + /* Try to determine the frequency from the device tree or CNTFRQ */ + if (!of_property_read_u32(np, "clock-frequency", &freq)) + arch_timer_rate = freq; + + arch_timer_ppi = irq_of_parse_and_map(np, 0); + arch_timer_ppi2 = irq_of_parse_and_map(np, 1); + pr_info("arch_timer: found %s irqs %d %d\n", + np->name, arch_timer_ppi, arch_timer_ppi2); + + return arch_timer_register(); +} + +int __init arch_timer_sched_clock_init(void) +{ + int err; + + err = arch_timer_available(); + if (err) + return err; + + setup_sched_clock(arch_counter_get_cntvct32, 32, arch_timer_rate); + return 0; +} diff --git a/trunk/arch/arm/kernel/bios32.c b/trunk/arch/arm/kernel/bios32.c index ede5f7741c42..25552508c3fd 100644 --- a/trunk/arch/arm/kernel/bios32.c +++ b/trunk/arch/arm/kernel/bios32.c @@ -374,16 +374,29 @@ EXPORT_SYMBOL(pcibios_fixup_bus); #endif /* - * Swizzle the device pin each time we cross a bridge. - * This might update pin and returns the slot number. + * Swizzle the device pin each time we cross a bridge. If a platform does + * not provide a swizzle function, we perform the standard PCI swizzling. + * + * The default swizzling walks up the bus tree one level at a time, applying + * the standard swizzle function at each step, stopping when it finds the PCI + * root bus. This will return the slot number of the bridge device on the + * root bus and the interrupt pin on that device which should correspond + * with the downstream device interrupt. + * + * Platforms may override this, in which case the slot and pin returned + * depend entirely on the platform code. However, please note that the + * PCI standard swizzle is implemented on plug-in cards and Cardbus based + * PCI extenders, so it can not be ignored. */ static u8 __devinit pcibios_swizzle(struct pci_dev *dev, u8 *pin) { struct pci_sys_data *sys = dev->sysdata; - int slot = 0, oldpin = *pin; + int slot, oldpin = *pin; if (sys->swizzle) slot = sys->swizzle(dev, pin); + else + slot = pci_common_swizzle(dev, pin); if (debug_pci) printk("PCI: %s swizzling pin %d => pin %d slot %d\n", @@ -410,7 +423,7 @@ static int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) return irq; } -static void __init pcibios_init_hw(struct hw_pci *hw) +static void __init pcibios_init_hw(struct hw_pci *hw, struct list_head *head) { struct pci_sys_data *sys = NULL; int ret; @@ -424,7 +437,6 @@ static void __init pcibios_init_hw(struct hw_pci *hw) #ifdef CONFIG_PCI_DOMAINS sys->domain = hw->domain; #endif - sys->hw = hw; sys->busnr = busnr; sys->swizzle = hw->swizzle; sys->map_irq = hw->map_irq; @@ -440,14 +452,18 @@ static void __init pcibios_init_hw(struct hw_pci *hw) &iomem_resource, sys->mem_offset); } - sys->bus = hw->scan(nr, sys); + if (hw->scan) + sys->bus = hw->scan(nr, sys); + else + sys->bus = pci_scan_root_bus(NULL, sys->busnr, + hw->ops, sys, &sys->resources); if (!sys->bus) panic("PCI: unable to scan bus!"); busnr = sys->bus->subordinate + 1; - list_add(&sys->node, &hw->buses); + list_add(&sys->node, head); } else { kfree(sys); if (ret < 0) @@ -459,19 +475,18 @@ static void __init pcibios_init_hw(struct hw_pci *hw) void __init pci_common_init(struct hw_pci *hw) { struct pci_sys_data *sys; - - INIT_LIST_HEAD(&hw->buses); + LIST_HEAD(head); pci_add_flags(PCI_REASSIGN_ALL_RSRC); if (hw->preinit) hw->preinit(); - pcibios_init_hw(hw); + pcibios_init_hw(hw, &head); if (hw->postinit) hw->postinit(); pci_fixup_irqs(pcibios_swizzle, pcibios_map_irq); - list_for_each_entry(sys, &hw->buses, node) { + list_for_each_entry(sys, &head, node) { struct pci_bus *bus = sys->bus; if (!pci_has_flag(PCI_PROBE_ONLY)) { diff --git a/trunk/arch/arm/kernel/entry-armv.S b/trunk/arch/arm/kernel/entry-armv.S index 7fd3ad048da9..437f0c426517 100644 --- a/trunk/arch/arm/kernel/entry-armv.S +++ b/trunk/arch/arm/kernel/entry-armv.S @@ -556,10 +556,6 @@ call_fpe: #endif tst r0, #0x08000000 @ only CDP/CPRT/LDC/STC have bit 27 tstne r0, #0x04000000 @ bit 26 set on both ARM and Thumb-2 -#if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710) - and r8, r0, #0x0f000000 @ mask out op-code bits - teqne r8, #0x0f000000 @ SWI (ARM6/7 bug)? -#endif moveq pc, lr get_thread_info r10 @ get current thread and r8, r0, #0x00000f00 @ mask out CP number diff --git a/trunk/arch/arm/kernel/entry-common.S b/trunk/arch/arm/kernel/entry-common.S index 54ee265dd819..7bd2d3cb8957 100644 --- a/trunk/arch/arm/kernel/entry-common.S +++ b/trunk/arch/arm/kernel/entry-common.S @@ -335,20 +335,6 @@ ENDPROC(ftrace_stub) *----------------------------------------------------------------------------- */ - /* If we're optimising for StrongARM the resulting code won't - run on an ARM7 and we can save a couple of instructions. - --pb */ -#ifdef CONFIG_CPU_ARM710 -#define A710(code...) code -.Larm710bug: - ldmia sp, {r0 - lr}^ @ Get calling r0 - lr - mov r0, r0 - add sp, sp, #S_FRAME_SIZE - subs pc, lr, #4 -#else -#define A710(code...) -#endif - .align 5 ENTRY(vector_swi) sub sp, sp, #S_FRAME_SIZE @@ -379,9 +365,6 @@ ENTRY(vector_swi) ldreq r10, [lr, #-4] @ get SWI instruction #else ldr r10, [lr, #-4] @ get SWI instruction - A710( and ip, r10, #0x0f000000 @ check for SWI ) - A710( teq ip, #0x0f000000 ) - A710( bne .Larm710bug ) #endif #ifdef CONFIG_CPU_ENDIAN_BE8 rev r10, r10 @ little endian instruction @@ -392,26 +375,15 @@ ENTRY(vector_swi) /* * Pure EABI user space always put syscall number into scno (r7). */ - A710( ldr ip, [lr, #-4] @ get SWI instruction ) - A710( and ip, ip, #0x0f000000 @ check for SWI ) - A710( teq ip, #0x0f000000 ) - A710( bne .Larm710bug ) - #elif defined(CONFIG_ARM_THUMB) - /* Legacy ABI only, possibly thumb mode. */ tst r8, #PSR_T_BIT @ this is SPSR from save_user_regs addne scno, r7, #__NR_SYSCALL_BASE @ put OS number in ldreq scno, [lr, #-4] #else - /* Legacy ABI only. */ ldr scno, [lr, #-4] @ get SWI instruction - A710( and ip, scno, #0x0f000000 @ check for SWI ) - A710( teq ip, #0x0f000000 ) - A710( bne .Larm710bug ) - #endif #ifdef CONFIG_ALIGNMENT_TRAP diff --git a/trunk/arch/arm/kernel/head.S b/trunk/arch/arm/kernel/head.S index 3bf0c7f8b043..835898e7d704 100644 --- a/trunk/arch/arm/kernel/head.S +++ b/trunk/arch/arm/kernel/head.S @@ -277,10 +277,6 @@ __create_page_tables: mov r3, r3, lsl #PMD_ORDER add r0, r4, r3 - rsb r3, r3, #0x4000 @ PTRS_PER_PGD*sizeof(long) - cmp r3, #0x0800 @ limit to 512MB - movhi r3, #0x0800 - add r6, r0, r3 mov r3, r7, lsr #SECTION_SHIFT ldr r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags orr r3, r7, r3, lsl #SECTION_SHIFT @@ -289,13 +285,10 @@ __create_page_tables: #else orr r3, r3, #PMD_SECT_XN #endif -1: str r3, [r0], #4 + str r3, [r0], #4 #ifdef CONFIG_ARM_LPAE str r7, [r0], #4 #endif - add r3, r3, #1 << SECTION_SHIFT - cmp r0, r6 - blo 1b #else /* CONFIG_DEBUG_ICEDCC || CONFIG_DEBUG_SEMIHOSTING */ /* we don't need any serial debugging mappings */ diff --git a/trunk/arch/arm/kernel/init_task.c b/trunk/arch/arm/kernel/init_task.c deleted file mode 100644 index e7cbb50dc356..000000000000 --- a/trunk/arch/arm/kernel/init_task.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - * linux/arch/arm/kernel/init_task.c - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -static struct signal_struct init_signals = INIT_SIGNALS(init_signals); -static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); -/* - * Initial thread structure. - * - * We need to make sure that this is 8192-byte aligned due to the - * way process stacks are handled. This is done by making sure - * the linker maps this in the .text segment right after head.S, - * and making head.S ensure the proper alignment. - * - * The things we do for performance.. - */ -union thread_union init_thread_union __init_task_data = - { INIT_THREAD_INFO(init_task) }; - -/* - * Initial task structure. - * - * All other task structs will be allocated on slabs in fork.c - */ -struct task_struct init_task = INIT_TASK(init_task); - -EXPORT_SYMBOL(init_task); diff --git a/trunk/arch/arm/kernel/perf_event_v6.c b/trunk/arch/arm/kernel/perf_event_v6.c index b78af0cc6ef3..ab627a740fa3 100644 --- a/trunk/arch/arm/kernel/perf_event_v6.c +++ b/trunk/arch/arm/kernel/perf_event_v6.c @@ -489,8 +489,6 @@ armv6pmu_handle_irq(int irq_num, */ armv6_pmcr_write(pmcr); - perf_sample_data_init(&data, 0); - cpuc = &__get_cpu_var(cpu_hw_events); for (idx = 0; idx < cpu_pmu->num_events; ++idx) { struct perf_event *event = cpuc->events[idx]; @@ -509,7 +507,7 @@ armv6pmu_handle_irq(int irq_num, hwc = &event->hw; armpmu_event_update(event, hwc, idx); - data.period = event->hw.last_period; + perf_sample_data_init(&data, 0, hwc->last_period); if (!armpmu_event_set_period(event, hwc, idx)) continue; diff --git a/trunk/arch/arm/kernel/perf_event_v7.c b/trunk/arch/arm/kernel/perf_event_v7.c index 00755d82e2f2..d3c536068162 100644 --- a/trunk/arch/arm/kernel/perf_event_v7.c +++ b/trunk/arch/arm/kernel/perf_event_v7.c @@ -1077,8 +1077,6 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev) */ regs = get_irq_regs(); - perf_sample_data_init(&data, 0); - cpuc = &__get_cpu_var(cpu_hw_events); for (idx = 0; idx < cpu_pmu->num_events; ++idx) { struct perf_event *event = cpuc->events[idx]; @@ -1097,7 +1095,7 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev) hwc = &event->hw; armpmu_event_update(event, hwc, idx); - data.period = event->hw.last_period; + perf_sample_data_init(&data, 0, hwc->last_period); if (!armpmu_event_set_period(event, hwc, idx)) continue; diff --git a/trunk/arch/arm/kernel/perf_event_xscale.c b/trunk/arch/arm/kernel/perf_event_xscale.c index 71a21e6712f5..e34e7254e652 100644 --- a/trunk/arch/arm/kernel/perf_event_xscale.c +++ b/trunk/arch/arm/kernel/perf_event_xscale.c @@ -248,8 +248,6 @@ xscale1pmu_handle_irq(int irq_num, void *dev) regs = get_irq_regs(); - perf_sample_data_init(&data, 0); - cpuc = &__get_cpu_var(cpu_hw_events); for (idx = 0; idx < cpu_pmu->num_events; ++idx) { struct perf_event *event = cpuc->events[idx]; @@ -263,7 +261,7 @@ xscale1pmu_handle_irq(int irq_num, void *dev) hwc = &event->hw; armpmu_event_update(event, hwc, idx); - data.period = event->hw.last_period; + perf_sample_data_init(&data, 0, hwc->last_period); if (!armpmu_event_set_period(event, hwc, idx)) continue; @@ -588,8 +586,6 @@ xscale2pmu_handle_irq(int irq_num, void *dev) regs = get_irq_regs(); - perf_sample_data_init(&data, 0); - cpuc = &__get_cpu_var(cpu_hw_events); for (idx = 0; idx < cpu_pmu->num_events; ++idx) { struct perf_event *event = cpuc->events[idx]; @@ -603,7 +599,7 @@ xscale2pmu_handle_irq(int irq_num, void *dev) hwc = &event->hw; armpmu_event_update(event, hwc, idx); - data.period = event->hw.last_period; + perf_sample_data_init(&data, 0, hwc->last_period); if (!armpmu_event_set_period(event, hwc, idx)) continue; diff --git a/trunk/arch/arm/kernel/process.c b/trunk/arch/arm/kernel/process.c index 2b7b017a20cd..19c95ea65b2f 100644 --- a/trunk/arch/arm/kernel/process.c +++ b/trunk/arch/arm/kernel/process.c @@ -157,26 +157,6 @@ EXPORT_SYMBOL(pm_power_off); void (*arm_pm_restart)(char str, const char *cmd) = null_restart; EXPORT_SYMBOL_GPL(arm_pm_restart); -static void do_nothing(void *unused) -{ -} - -/* - * cpu_idle_wait - Used to ensure that all the CPUs discard old value of - * pm_idle and update to new pm_idle value. Required while changing pm_idle - * handler on SMP systems. - * - * Caller must have changed pm_idle to the new value before the call. Old - * pm_idle value will not be used by any CPU after the return of this function. - */ -void cpu_idle_wait(void) -{ - smp_mb(); - /* kick all the CPUs so that they exit out of pm_idle */ - smp_call_function(do_nothing, NULL, 1); -} -EXPORT_SYMBOL_GPL(cpu_idle_wait); - /* * This is our default idle handler. */ diff --git a/trunk/arch/arm/kernel/ptrace.c b/trunk/arch/arm/kernel/ptrace.c index 9650c143afc1..14e38261cd31 100644 --- a/trunk/arch/arm/kernel/ptrace.c +++ b/trunk/arch/arm/kernel/ptrace.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -918,8 +919,6 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno) if (!test_thread_flag(TIF_SYSCALL_TRACE)) return scno; - if (!(current->ptrace & PT_PTRACED)) - return scno; current_thread_info()->syscall = scno; @@ -930,19 +929,11 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno) ip = regs->ARM_ip; regs->ARM_ip = why; - /* the 0x80 provides a way for the tracing parent to distinguish - between a syscall stop and SIGTRAP delivery */ - ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) - ? 0x80 : 0)); - /* - * this isn't the same as continuing with a signal, but it will do - * for normal use. strace only continues with a signal if the - * stopping signal is not SIGTRAP. -brl - */ - if (current->exit_code) { - send_sig(current->exit_code, current, 1); - current->exit_code = 0; - } + if (why) + tracehook_report_syscall_exit(regs, 0); + else if (tracehook_report_syscall_entry(regs)) + current_thread_info()->syscall = -1; + regs->ARM_ip = ip; return current_thread_info()->syscall; diff --git a/trunk/arch/arm/kernel/signal.c b/trunk/arch/arm/kernel/signal.c index d68d1b694680..73d9a420850d 100644 --- a/trunk/arch/arm/kernel/signal.c +++ b/trunk/arch/arm/kernel/signal.c @@ -589,6 +589,8 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, */ block_sigmask(ka, sig); + tracehook_signal_handler(sig, info, ka, regs, 0); + return 0; } diff --git a/trunk/arch/arm/kernel/smp.c b/trunk/arch/arm/kernel/smp.c index 8f4644659777..b735521a4a54 100644 --- a/trunk/arch/arm/kernel/smp.c +++ b/trunk/arch/arm/kernel/smp.c @@ -60,31 +60,10 @@ enum ipi_msg_type { static DECLARE_COMPLETION(cpu_running); -int __cpuinit __cpu_up(unsigned int cpu) +int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle) { - struct cpuinfo_arm *ci = &per_cpu(cpu_data, cpu); - struct task_struct *idle = ci->idle; int ret; - /* - * Spawn a new process manually, if not already done. - * Grab a pointer to its task struct so we can mess with it - */ - if (!idle) { - idle = fork_idle(cpu); - if (IS_ERR(idle)) { - printk(KERN_ERR "CPU%u: fork() failed\n", cpu); - return PTR_ERR(idle); - } - ci->idle = idle; - } else { - /* - * Since this idle thread is being re-used, call - * init_idle() to reinitialize the thread structure. - */ - init_idle(idle, cpu); - } - /* * We need to tell the secondary core where to find * its stack and the page tables. @@ -318,9 +297,6 @@ void __init smp_cpus_done(unsigned int max_cpus) void __init smp_prepare_boot_cpu(void) { - unsigned int cpu = smp_processor_id(); - - per_cpu(cpu_data, cpu).idle = current; } void __init smp_prepare_cpus(unsigned int max_cpus) @@ -454,6 +430,9 @@ static struct local_timer_ops *lt_ops; #ifdef CONFIG_LOCAL_TIMERS int local_timer_register(struct local_timer_ops *ops) { + if (!is_smp() || !setup_max_cpus) + return -ENXIO; + if (lt_ops) return -EBUSY; diff --git a/trunk/arch/arm/kernel/smp_scu.c b/trunk/arch/arm/kernel/smp_scu.c index 8f5dd7963356..b9f015e843d8 100644 --- a/trunk/arch/arm/kernel/smp_scu.c +++ b/trunk/arch/arm/kernel/smp_scu.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -74,7 +75,7 @@ void scu_enable(void __iomem *scu_base) int scu_power_mode(void __iomem *scu_base, unsigned int mode) { unsigned int val; - int cpu = smp_processor_id(); + int cpu = cpu_logical_map(smp_processor_id()); if (mode > 3 || mode == 1 || cpu > 3) return -EINVAL; diff --git a/trunk/arch/arm/kernel/thumbee.c b/trunk/arch/arm/kernel/thumbee.c index aab899764053..7b8403b76666 100644 --- a/trunk/arch/arm/kernel/thumbee.c +++ b/trunk/arch/arm/kernel/thumbee.c @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -67,8 +68,7 @@ static int __init thumbee_init(void) if (cpu_arch < CPU_ARCH_ARMv7) return 0; - /* processor feature register 0 */ - asm("mrc p15, 0, %0, c0, c1, 0\n" : "=r" (pfr0)); + pfr0 = read_cpuid_ext(CPUID_EXT_PFR0); if ((pfr0 & 0x0000f000) != 0x00001000) return 0; diff --git a/trunk/arch/arm/kernel/time.c b/trunk/arch/arm/kernel/time.c index fe31b22f18fd..af2afb019672 100644 --- a/trunk/arch/arm/kernel/time.c +++ b/trunk/arch/arm/kernel/time.c @@ -110,6 +110,42 @@ void timer_tick(void) } #endif +static void dummy_clock_access(struct timespec *ts) +{ + ts->tv_sec = 0; + ts->tv_nsec = 0; +} + +static clock_access_fn __read_persistent_clock = dummy_clock_access; +static clock_access_fn __read_boot_clock = dummy_clock_access;; + +void read_persistent_clock(struct timespec *ts) +{ + __read_persistent_clock(ts); +} + +void read_boot_clock(struct timespec *ts) +{ + __read_boot_clock(ts); +} + +int __init register_persistent_clock(clock_access_fn read_boot, + clock_access_fn read_persistent) +{ + /* Only allow the clockaccess functions to be registered once */ + if (__read_persistent_clock == dummy_clock_access && + __read_boot_clock == dummy_clock_access) { + if (read_boot) + __read_boot_clock = read_boot; + if (read_persistent) + __read_persistent_clock = read_persistent; + + return 0; + } + + return -EINVAL; +} + #if defined(CONFIG_PM) && !defined(CONFIG_GENERIC_CLOCKEVENTS) static int timer_suspend(void) { diff --git a/trunk/arch/arm/kernel/traps.c b/trunk/arch/arm/kernel/traps.c index 778454750a6c..3647170e9a16 100644 --- a/trunk/arch/arm/kernel/traps.c +++ b/trunk/arch/arm/kernel/traps.c @@ -479,14 +479,14 @@ static int bad_syscall(int n, struct pt_regs *regs) return regs->ARM_r0; } -static inline void +static inline int do_cache_op(unsigned long start, unsigned long end, int flags) { struct mm_struct *mm = current->active_mm; struct vm_area_struct *vma; if (end < start || flags) - return; + return -EINVAL; down_read(&mm->mmap_sem); vma = find_vma(mm, start); @@ -496,9 +496,11 @@ do_cache_op(unsigned long start, unsigned long end, int flags) if (end > vma->vm_end) end = vma->vm_end; - flush_cache_user_range(vma, start, end); + up_read(&mm->mmap_sem); + return flush_cache_user_range(start, end); } up_read(&mm->mmap_sem); + return -EINVAL; } /* @@ -544,8 +546,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs) * the specified region). */ case NR(cacheflush): - do_cache_op(regs->ARM_r0, regs->ARM_r1, regs->ARM_r2); - return 0; + return do_cache_op(regs->ARM_r0, regs->ARM_r1, regs->ARM_r2); case NR(usr26): if (!(elf_hwcap & HWCAP_26BIT)) diff --git a/trunk/arch/arm/lib/Makefile b/trunk/arch/arm/lib/Makefile index 0ade0acc1ed9..992769ae2599 100644 --- a/trunk/arch/arm/lib/Makefile +++ b/trunk/arch/arm/lib/Makefile @@ -17,30 +17,13 @@ lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ call_with_stack.o mmu-y := clear_user.o copy_page.o getuser.o putuser.o - -# the code in uaccess.S is not preemption safe and -# probably faster on ARMv3 only -ifeq ($(CONFIG_PREEMPT),y) - mmu-y += copy_from_user.o copy_to_user.o -else -ifneq ($(CONFIG_CPU_32v3),y) - mmu-y += copy_from_user.o copy_to_user.o -else - mmu-y += uaccess.o -endif -endif +mmu-y += copy_from_user.o copy_to_user.o # using lib_ here won't override already available weak symbols obj-$(CONFIG_UACCESS_WITH_MEMCPY) += uaccess_with_memcpy.o -lib-$(CONFIG_MMU) += $(mmu-y) - -ifeq ($(CONFIG_CPU_32v3),y) - lib-y += io-readsw-armv3.o io-writesw-armv3.o -else - lib-y += io-readsw-armv4.o io-writesw-armv4.o -endif - +lib-$(CONFIG_MMU) += $(mmu-y) +lib-y += io-readsw-armv4.o io-writesw-armv4.o lib-$(CONFIG_ARCH_RPC) += ecard.o io-acorn.o floppydma.o lib-$(CONFIG_ARCH_SHARK) += io-shark.o diff --git a/trunk/arch/arm/lib/io-readsw-armv3.S b/trunk/arch/arm/lib/io-readsw-armv3.S deleted file mode 100644 index 88487c8c4f23..000000000000 --- a/trunk/arch/arm/lib/io-readsw-armv3.S +++ /dev/null @@ -1,106 +0,0 @@ -/* - * linux/arch/arm/lib/io-readsw-armv3.S - * - * Copyright (C) 1995-2000 Russell King - * - * 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 - -.Linsw_bad_alignment: - adr r0, .Linsw_bad_align_msg - mov r2, lr - b panic -.Linsw_bad_align_msg: - .asciz "insw: bad buffer alignment (0x%p, lr=0x%08lX)\n" - .align - -.Linsw_align: tst r1, #1 - bne .Linsw_bad_alignment - - ldr r3, [r0] - strb r3, [r1], #1 - mov r3, r3, lsr #8 - strb r3, [r1], #1 - - subs r2, r2, #1 - moveq pc, lr - -ENTRY(__raw_readsw) - teq r2, #0 @ do we have to check for the zero len? - moveq pc, lr - tst r1, #3 - bne .Linsw_align - -.Linsw_aligned: mov ip, #0xff - orr ip, ip, ip, lsl #8 - stmfd sp!, {r4, r5, r6, lr} - - subs r2, r2, #8 - bmi .Lno_insw_8 - -.Linsw_8_lp: ldr r3, [r0] - and r3, r3, ip - ldr r4, [r0] - orr r3, r3, r4, lsl #16 - - ldr r4, [r0] - and r4, r4, ip - ldr r5, [r0] - orr r4, r4, r5, lsl #16 - - ldr r5, [r0] - and r5, r5, ip - ldr r6, [r0] - orr r5, r5, r6, lsl #16 - - ldr r6, [r0] - and r6, r6, ip - ldr lr, [r0] - orr r6, r6, lr, lsl #16 - - stmia r1!, {r3 - r6} - - subs r2, r2, #8 - bpl .Linsw_8_lp - - tst r2, #7 - ldmeqfd sp!, {r4, r5, r6, pc} - -.Lno_insw_8: tst r2, #4 - beq .Lno_insw_4 - - ldr r3, [r0] - and r3, r3, ip - ldr r4, [r0] - orr r3, r3, r4, lsl #16 - - ldr r4, [r0] - and r4, r4, ip - ldr r5, [r0] - orr r4, r4, r5, lsl #16 - - stmia r1!, {r3, r4} - -.Lno_insw_4: tst r2, #2 - beq .Lno_insw_2 - - ldr r3, [r0] - and r3, r3, ip - ldr r4, [r0] - orr r3, r3, r4, lsl #16 - - str r3, [r1], #4 - -.Lno_insw_2: tst r2, #1 - ldrne r3, [r0] - strneb r3, [r1], #1 - movne r3, r3, lsr #8 - strneb r3, [r1] - - ldmfd sp!, {r4, r5, r6, pc} - - diff --git a/trunk/arch/arm/lib/io-writesw-armv3.S b/trunk/arch/arm/lib/io-writesw-armv3.S deleted file mode 100644 index 49b800419e32..000000000000 --- a/trunk/arch/arm/lib/io-writesw-armv3.S +++ /dev/null @@ -1,126 +0,0 @@ -/* - * linux/arch/arm/lib/io-writesw-armv3.S - * - * Copyright (C) 1995-2000 Russell King - * - * 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 - -.Loutsw_bad_alignment: - adr r0, .Loutsw_bad_align_msg - mov r2, lr - b panic -.Loutsw_bad_align_msg: - .asciz "outsw: bad buffer alignment (0x%p, lr=0x%08lX)\n" - .align - -.Loutsw_align: tst r1, #1 - bne .Loutsw_bad_alignment - - add r1, r1, #2 - - ldr r3, [r1, #-4] - mov r3, r3, lsr #16 - orr r3, r3, r3, lsl #16 - str r3, [r0] - subs r2, r2, #1 - moveq pc, lr - -ENTRY(__raw_writesw) - teq r2, #0 @ do we have to check for the zero len? - moveq pc, lr - tst r1, #3 - bne .Loutsw_align - - stmfd sp!, {r4, r5, r6, lr} - - subs r2, r2, #8 - bmi .Lno_outsw_8 - -.Loutsw_8_lp: ldmia r1!, {r3, r4, r5, r6} - - mov ip, r3, lsl #16 - orr ip, ip, ip, lsr #16 - str ip, [r0] - - mov ip, r3, lsr #16 - orr ip, ip, ip, lsl #16 - str ip, [r0] - - mov ip, r4, lsl #16 - orr ip, ip, ip, lsr #16 - str ip, [r0] - - mov ip, r4, lsr #16 - orr ip, ip, ip, lsl #16 - str ip, [r0] - - mov ip, r5, lsl #16 - orr ip, ip, ip, lsr #16 - str ip, [r0] - - mov ip, r5, lsr #16 - orr ip, ip, ip, lsl #16 - str ip, [r0] - - mov ip, r6, lsl #16 - orr ip, ip, ip, lsr #16 - str ip, [r0] - - mov ip, r6, lsr #16 - orr ip, ip, ip, lsl #16 - str ip, [r0] - - subs r2, r2, #8 - bpl .Loutsw_8_lp - - tst r2, #7 - ldmeqfd sp!, {r4, r5, r6, pc} - -.Lno_outsw_8: tst r2, #4 - beq .Lno_outsw_4 - - ldmia r1!, {r3, r4} - - mov ip, r3, lsl #16 - orr ip, ip, ip, lsr #16 - str ip, [r0] - - mov ip, r3, lsr #16 - orr ip, ip, ip, lsl #16 - str ip, [r0] - - mov ip, r4, lsl #16 - orr ip, ip, ip, lsr #16 - str ip, [r0] - - mov ip, r4, lsr #16 - orr ip, ip, ip, lsl #16 - str ip, [r0] - -.Lno_outsw_4: tst r2, #2 - beq .Lno_outsw_2 - - ldr r3, [r1], #4 - - mov ip, r3, lsl #16 - orr ip, ip, ip, lsr #16 - str ip, [r0] - - mov ip, r3, lsr #16 - orr ip, ip, ip, lsl #16 - str ip, [r0] - -.Lno_outsw_2: tst r2, #1 - - ldrne r3, [r1] - - movne ip, r3, lsl #16 - orrne ip, ip, ip, lsr #16 - strne ip, [r0] - - ldmfd sp!, {r4, r5, r6, pc} diff --git a/trunk/arch/arm/lib/uaccess.S b/trunk/arch/arm/lib/uaccess.S deleted file mode 100644 index 5c908b1cb8ed..000000000000 --- a/trunk/arch/arm/lib/uaccess.S +++ /dev/null @@ -1,564 +0,0 @@ -/* - * linux/arch/arm/lib/uaccess.S - * - * Copyright (C) 1995, 1996,1997,1998 Russell King - * - * 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. - * - * Routines to block copy data to/from user memory - * These are highly optimised both for the 4k page size - * and for various alignments. - */ -#include -#include -#include -#include - - .text - -#define PAGE_SHIFT 12 - -/* Prototype: int __copy_to_user(void *to, const char *from, size_t n) - * Purpose : copy a block to user memory from kernel memory - * Params : to - user memory - * : from - kernel memory - * : n - number of bytes to copy - * Returns : Number of bytes NOT copied. - */ - -.Lc2u_dest_not_aligned: - rsb ip, ip, #4 - cmp ip, #2 - ldrb r3, [r1], #1 -USER( TUSER( strb) r3, [r0], #1) @ May fault - ldrgeb r3, [r1], #1 -USER( TUSER( strgeb) r3, [r0], #1) @ May fault - ldrgtb r3, [r1], #1 -USER( TUSER( strgtb) r3, [r0], #1) @ May fault - sub r2, r2, ip - b .Lc2u_dest_aligned - -ENTRY(__copy_to_user) - stmfd sp!, {r2, r4 - r7, lr} - cmp r2, #4 - blt .Lc2u_not_enough - ands ip, r0, #3 - bne .Lc2u_dest_not_aligned -.Lc2u_dest_aligned: - - ands ip, r1, #3 - bne .Lc2u_src_not_aligned -/* - * Seeing as there has to be at least 8 bytes to copy, we can - * copy one word, and force a user-mode page fault... - */ - -.Lc2u_0fupi: subs r2, r2, #4 - addmi ip, r2, #4 - bmi .Lc2u_0nowords - ldr r3, [r1], #4 -USER( TUSER( str) r3, [r0], #4) @ May fault - mov ip, r0, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction - rsb ip, ip, #0 - movs ip, ip, lsr #32 - PAGE_SHIFT - beq .Lc2u_0fupi -/* - * ip = max no. of bytes to copy before needing another "strt" insn - */ - cmp r2, ip - movlt ip, r2 - sub r2, r2, ip - subs ip, ip, #32 - blt .Lc2u_0rem8lp - -.Lc2u_0cpy8lp: ldmia r1!, {r3 - r6} - stmia r0!, {r3 - r6} @ Shouldnt fault - ldmia r1!, {r3 - r6} - subs ip, ip, #32 - stmia r0!, {r3 - r6} @ Shouldnt fault - bpl .Lc2u_0cpy8lp - -.Lc2u_0rem8lp: cmn ip, #16 - ldmgeia r1!, {r3 - r6} - stmgeia r0!, {r3 - r6} @ Shouldnt fault - tst ip, #8 - ldmneia r1!, {r3 - r4} - stmneia r0!, {r3 - r4} @ Shouldnt fault - tst ip, #4 - ldrne r3, [r1], #4 - TUSER( strne) r3, [r0], #4 @ Shouldnt fault - ands ip, ip, #3 - beq .Lc2u_0fupi -.Lc2u_0nowords: teq ip, #0 - beq .Lc2u_finished -.Lc2u_nowords: cmp ip, #2 - ldrb r3, [r1], #1 -USER( TUSER( strb) r3, [r0], #1) @ May fault - ldrgeb r3, [r1], #1 -USER( TUSER( strgeb) r3, [r0], #1) @ May fault - ldrgtb r3, [r1], #1 -USER( TUSER( strgtb) r3, [r0], #1) @ May fault - b .Lc2u_finished - -.Lc2u_not_enough: - movs ip, r2 - bne .Lc2u_nowords -.Lc2u_finished: mov r0, #0 - ldmfd sp!, {r2, r4 - r7, pc} - -.Lc2u_src_not_aligned: - bic r1, r1, #3 - ldr r7, [r1], #4 - cmp ip, #2 - bgt .Lc2u_3fupi - beq .Lc2u_2fupi -.Lc2u_1fupi: subs r2, r2, #4 - addmi ip, r2, #4 - bmi .Lc2u_1nowords - mov r3, r7, pull #8 - ldr r7, [r1], #4 - orr r3, r3, r7, push #24 -USER( TUSER( str) r3, [r0], #4) @ May fault - mov ip, r0, lsl #32 - PAGE_SHIFT - rsb ip, ip, #0 - movs ip, ip, lsr #32 - PAGE_SHIFT - beq .Lc2u_1fupi - cmp r2, ip - movlt ip, r2 - sub r2, r2, ip - subs ip, ip, #16 - blt .Lc2u_1rem8lp - -.Lc2u_1cpy8lp: mov r3, r7, pull #8 - ldmia r1!, {r4 - r7} - subs ip, ip, #16 - orr r3, r3, r4, push #24 - mov r4, r4, pull #8 - orr r4, r4, r5, push #24 - mov r5, r5, pull #8 - orr r5, r5, r6, push #24 - mov r6, r6, pull #8 - orr r6, r6, r7, push #24 - stmia r0!, {r3 - r6} @ Shouldnt fault - bpl .Lc2u_1cpy8lp - -.Lc2u_1rem8lp: tst ip, #8 - movne r3, r7, pull #8 - ldmneia r1!, {r4, r7} - orrne r3, r3, r4, push #24 - movne r4, r4, pull #8 - orrne r4, r4, r7, push #24 - stmneia r0!, {r3 - r4} @ Shouldnt fault - tst ip, #4 - movne r3, r7, pull #8 - ldrne r7, [r1], #4 - orrne r3, r3, r7, push #24 - TUSER( strne) r3, [r0], #4 @ Shouldnt fault - ands ip, ip, #3 - beq .Lc2u_1fupi -.Lc2u_1nowords: mov r3, r7, get_byte_1 - teq ip, #0 - beq .Lc2u_finished - cmp ip, #2 -USER( TUSER( strb) r3, [r0], #1) @ May fault - movge r3, r7, get_byte_2 -USER( TUSER( strgeb) r3, [r0], #1) @ May fault - movgt r3, r7, get_byte_3 -USER( TUSER( strgtb) r3, [r0], #1) @ May fault - b .Lc2u_finished - -.Lc2u_2fupi: subs r2, r2, #4 - addmi ip, r2, #4 - bmi .Lc2u_2nowords - mov r3, r7, pull #16 - ldr r7, [r1], #4 - orr r3, r3, r7, push #16 -USER( TUSER( str) r3, [r0], #4) @ May fault - mov ip, r0, lsl #32 - PAGE_SHIFT - rsb ip, ip, #0 - movs ip, ip, lsr #32 - PAGE_SHIFT - beq .Lc2u_2fupi - cmp r2, ip - movlt ip, r2 - sub r2, r2, ip - subs ip, ip, #16 - blt .Lc2u_2rem8lp - -.Lc2u_2cpy8lp: mov r3, r7, pull #16 - ldmia r1!, {r4 - r7} - subs ip, ip, #16 - orr r3, r3, r4, push #16 - mov r4, r4, pull #16 - orr r4, r4, r5, push #16 - mov r5, r5, pull #16 - orr r5, r5, r6, push #16 - mov r6, r6, pull #16 - orr r6, r6, r7, push #16 - stmia r0!, {r3 - r6} @ Shouldnt fault - bpl .Lc2u_2cpy8lp - -.Lc2u_2rem8lp: tst ip, #8 - movne r3, r7, pull #16 - ldmneia r1!, {r4, r7} - orrne r3, r3, r4, push #16 - movne r4, r4, pull #16 - orrne r4, r4, r7, push #16 - stmneia r0!, {r3 - r4} @ Shouldnt fault - tst ip, #4 - movne r3, r7, pull #16 - ldrne r7, [r1], #4 - orrne r3, r3, r7, push #16 - TUSER( strne) r3, [r0], #4 @ Shouldnt fault - ands ip, ip, #3 - beq .Lc2u_2fupi -.Lc2u_2nowords: mov r3, r7, get_byte_2 - teq ip, #0 - beq .Lc2u_finished - cmp ip, #2 -USER( TUSER( strb) r3, [r0], #1) @ May fault - movge r3, r7, get_byte_3 -USER( TUSER( strgeb) r3, [r0], #1) @ May fault - ldrgtb r3, [r1], #0 -USER( TUSER( strgtb) r3, [r0], #1) @ May fault - b .Lc2u_finished - -.Lc2u_3fupi: subs r2, r2, #4 - addmi ip, r2, #4 - bmi .Lc2u_3nowords - mov r3, r7, pull #24 - ldr r7, [r1], #4 - orr r3, r3, r7, push #8 -USER( TUSER( str) r3, [r0], #4) @ May fault - mov ip, r0, lsl #32 - PAGE_SHIFT - rsb ip, ip, #0 - movs ip, ip, lsr #32 - PAGE_SHIFT - beq .Lc2u_3fupi - cmp r2, ip - movlt ip, r2 - sub r2, r2, ip - subs ip, ip, #16 - blt .Lc2u_3rem8lp - -.Lc2u_3cpy8lp: mov r3, r7, pull #24 - ldmia r1!, {r4 - r7} - subs ip, ip, #16 - orr r3, r3, r4, push #8 - mov r4, r4, pull #24 - orr r4, r4, r5, push #8 - mov r5, r5, pull #24 - orr r5, r5, r6, push #8 - mov r6, r6, pull #24 - orr r6, r6, r7, push #8 - stmia r0!, {r3 - r6} @ Shouldnt fault - bpl .Lc2u_3cpy8lp - -.Lc2u_3rem8lp: tst ip, #8 - movne r3, r7, pull #24 - ldmneia r1!, {r4, r7} - orrne r3, r3, r4, push #8 - movne r4, r4, pull #24 - orrne r4, r4, r7, push #8 - stmneia r0!, {r3 - r4} @ Shouldnt fault - tst ip, #4 - movne r3, r7, pull #24 - ldrne r7, [r1], #4 - orrne r3, r3, r7, push #8 - TUSER( strne) r3, [r0], #4 @ Shouldnt fault - ands ip, ip, #3 - beq .Lc2u_3fupi -.Lc2u_3nowords: mov r3, r7, get_byte_3 - teq ip, #0 - beq .Lc2u_finished - cmp ip, #2 -USER( TUSER( strb) r3, [r0], #1) @ May fault - ldrgeb r3, [r1], #1 -USER( TUSER( strgeb) r3, [r0], #1) @ May fault - ldrgtb r3, [r1], #0 -USER( TUSER( strgtb) r3, [r0], #1) @ May fault - b .Lc2u_finished -ENDPROC(__copy_to_user) - - .pushsection .fixup,"ax" - .align 0 -9001: ldmfd sp!, {r0, r4 - r7, pc} - .popsection - -/* Prototype: unsigned long __copy_from_user(void *to,const void *from,unsigned long n); - * Purpose : copy a block from user memory to kernel memory - * Params : to - kernel memory - * : from - user memory - * : n - number of bytes to copy - * Returns : Number of bytes NOT copied. - */ -.Lcfu_dest_not_aligned: - rsb ip, ip, #4 - cmp ip, #2 -USER( TUSER( ldrb) r3, [r1], #1) @ May fault - strb r3, [r0], #1 -USER( TUSER( ldrgeb) r3, [r1], #1) @ May fault - strgeb r3, [r0], #1 -USER( TUSER( ldrgtb) r3, [r1], #1) @ May fault - strgtb r3, [r0], #1 - sub r2, r2, ip - b .Lcfu_dest_aligned - -ENTRY(__copy_from_user) - stmfd sp!, {r0, r2, r4 - r7, lr} - cmp r2, #4 - blt .Lcfu_not_enough - ands ip, r0, #3 - bne .Lcfu_dest_not_aligned -.Lcfu_dest_aligned: - ands ip, r1, #3 - bne .Lcfu_src_not_aligned - -/* - * Seeing as there has to be at least 8 bytes to copy, we can - * copy one word, and force a user-mode page fault... - */ - -.Lcfu_0fupi: subs r2, r2, #4 - addmi ip, r2, #4 - bmi .Lcfu_0nowords -USER( TUSER( ldr) r3, [r1], #4) - str r3, [r0], #4 - mov ip, r1, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction - rsb ip, ip, #0 - movs ip, ip, lsr #32 - PAGE_SHIFT - beq .Lcfu_0fupi -/* - * ip = max no. of bytes to copy before needing another "strt" insn - */ - cmp r2, ip - movlt ip, r2 - sub r2, r2, ip - subs ip, ip, #32 - blt .Lcfu_0rem8lp - -.Lcfu_0cpy8lp: ldmia r1!, {r3 - r6} @ Shouldnt fault - stmia r0!, {r3 - r6} - ldmia r1!, {r3 - r6} @ Shouldnt fault - subs ip, ip, #32 - stmia r0!, {r3 - r6} - bpl .Lcfu_0cpy8lp - -.Lcfu_0rem8lp: cmn ip, #16 - ldmgeia r1!, {r3 - r6} @ Shouldnt fault - stmgeia r0!, {r3 - r6} - tst ip, #8 - ldmneia r1!, {r3 - r4} @ Shouldnt fault - stmneia r0!, {r3 - r4} - tst ip, #4 - TUSER( ldrne) r3, [r1], #4 @ Shouldnt fault - strne r3, [r0], #4 - ands ip, ip, #3 - beq .Lcfu_0fupi -.Lcfu_0nowords: teq ip, #0 - beq .Lcfu_finished -.Lcfu_nowords: cmp ip, #2 -USER( TUSER( ldrb) r3, [r1], #1) @ May fault - strb r3, [r0], #1 -USER( TUSER( ldrgeb) r3, [r1], #1) @ May fault - strgeb r3, [r0], #1 -USER( TUSER( ldrgtb) r3, [r1], #1) @ May fault - strgtb r3, [r0], #1 - b .Lcfu_finished - -.Lcfu_not_enough: - movs ip, r2 - bne .Lcfu_nowords -.Lcfu_finished: mov r0, #0 - add sp, sp, #8 - ldmfd sp!, {r4 - r7, pc} - -.Lcfu_src_not_aligned: - bic r1, r1, #3 -USER( TUSER( ldr) r7, [r1], #4) @ May fault - cmp ip, #2 - bgt .Lcfu_3fupi - beq .Lcfu_2fupi -.Lcfu_1fupi: subs r2, r2, #4 - addmi ip, r2, #4 - bmi .Lcfu_1nowords - mov r3, r7, pull #8 -USER( TUSER( ldr) r7, [r1], #4) @ May fault - orr r3, r3, r7, push #24 - str r3, [r0], #4 - mov ip, r1, lsl #32 - PAGE_SHIFT - rsb ip, ip, #0 - movs ip, ip, lsr #32 - PAGE_SHIFT - beq .Lcfu_1fupi - cmp r2, ip - movlt ip, r2 - sub r2, r2, ip - subs ip, ip, #16 - blt .Lcfu_1rem8lp - -.Lcfu_1cpy8lp: mov r3, r7, pull #8 - ldmia r1!, {r4 - r7} @ Shouldnt fault - subs ip, ip, #16 - orr r3, r3, r4, push #24 - mov r4, r4, pull #8 - orr r4, r4, r5, push #24 - mov r5, r5, pull #8 - orr r5, r5, r6, push #24 - mov r6, r6, pull #8 - orr r6, r6, r7, push #24 - stmia r0!, {r3 - r6} - bpl .Lcfu_1cpy8lp - -.Lcfu_1rem8lp: tst ip, #8 - movne r3, r7, pull #8 - ldmneia r1!, {r4, r7} @ Shouldnt fault - orrne r3, r3, r4, push #24 - movne r4, r4, pull #8 - orrne r4, r4, r7, push #24 - stmneia r0!, {r3 - r4} - tst ip, #4 - movne r3, r7, pull #8 -USER( TUSER( ldrne) r7, [r1], #4) @ May fault - orrne r3, r3, r7, push #24 - strne r3, [r0], #4 - ands ip, ip, #3 - beq .Lcfu_1fupi -.Lcfu_1nowords: mov r3, r7, get_byte_1 - teq ip, #0 - beq .Lcfu_finished - cmp ip, #2 - strb r3, [r0], #1 - movge r3, r7, get_byte_2 - strgeb r3, [r0], #1 - movgt r3, r7, get_byte_3 - strgtb r3, [r0], #1 - b .Lcfu_finished - -.Lcfu_2fupi: subs r2, r2, #4 - addmi ip, r2, #4 - bmi .Lcfu_2nowords - mov r3, r7, pull #16 -USER( TUSER( ldr) r7, [r1], #4) @ May fault - orr r3, r3, r7, push #16 - str r3, [r0], #4 - mov ip, r1, lsl #32 - PAGE_SHIFT - rsb ip, ip, #0 - movs ip, ip, lsr #32 - PAGE_SHIFT - beq .Lcfu_2fupi - cmp r2, ip - movlt ip, r2 - sub r2, r2, ip - subs ip, ip, #16 - blt .Lcfu_2rem8lp - - -.Lcfu_2cpy8lp: mov r3, r7, pull #16 - ldmia r1!, {r4 - r7} @ Shouldnt fault - subs ip, ip, #16 - orr r3, r3, r4, push #16 - mov r4, r4, pull #16 - orr r4, r4, r5, push #16 - mov r5, r5, pull #16 - orr r5, r5, r6, push #16 - mov r6, r6, pull #16 - orr r6, r6, r7, push #16 - stmia r0!, {r3 - r6} - bpl .Lcfu_2cpy8lp - -.Lcfu_2rem8lp: tst ip, #8 - movne r3, r7, pull #16 - ldmneia r1!, {r4, r7} @ Shouldnt fault - orrne r3, r3, r4, push #16 - movne r4, r4, pull #16 - orrne r4, r4, r7, push #16 - stmneia r0!, {r3 - r4} - tst ip, #4 - movne r3, r7, pull #16 -USER( TUSER( ldrne) r7, [r1], #4) @ May fault - orrne r3, r3, r7, push #16 - strne r3, [r0], #4 - ands ip, ip, #3 - beq .Lcfu_2fupi -.Lcfu_2nowords: mov r3, r7, get_byte_2 - teq ip, #0 - beq .Lcfu_finished - cmp ip, #2 - strb r3, [r0], #1 - movge r3, r7, get_byte_3 - strgeb r3, [r0], #1 -USER( TUSER( ldrgtb) r3, [r1], #0) @ May fault - strgtb r3, [r0], #1 - b .Lcfu_finished - -.Lcfu_3fupi: subs r2, r2, #4 - addmi ip, r2, #4 - bmi .Lcfu_3nowords - mov r3, r7, pull #24 -USER( TUSER( ldr) r7, [r1], #4) @ May fault - orr r3, r3, r7, push #8 - str r3, [r0], #4 - mov ip, r1, lsl #32 - PAGE_SHIFT - rsb ip, ip, #0 - movs ip, ip, lsr #32 - PAGE_SHIFT - beq .Lcfu_3fupi - cmp r2, ip - movlt ip, r2 - sub r2, r2, ip - subs ip, ip, #16 - blt .Lcfu_3rem8lp - -.Lcfu_3cpy8lp: mov r3, r7, pull #24 - ldmia r1!, {r4 - r7} @ Shouldnt fault - orr r3, r3, r4, push #8 - mov r4, r4, pull #24 - orr r4, r4, r5, push #8 - mov r5, r5, pull #24 - orr r5, r5, r6, push #8 - mov r6, r6, pull #24 - orr r6, r6, r7, push #8 - stmia r0!, {r3 - r6} - subs ip, ip, #16 - bpl .Lcfu_3cpy8lp - -.Lcfu_3rem8lp: tst ip, #8 - movne r3, r7, pull #24 - ldmneia r1!, {r4, r7} @ Shouldnt fault - orrne r3, r3, r4, push #8 - movne r4, r4, pull #24 - orrne r4, r4, r7, push #8 - stmneia r0!, {r3 - r4} - tst ip, #4 - movne r3, r7, pull #24 -USER( TUSER( ldrne) r7, [r1], #4) @ May fault - orrne r3, r3, r7, push #8 - strne r3, [r0], #4 - ands ip, ip, #3 - beq .Lcfu_3fupi -.Lcfu_3nowords: mov r3, r7, get_byte_3 - teq ip, #0 - beq .Lcfu_finished - cmp ip, #2 - strb r3, [r0], #1 -USER( TUSER( ldrgeb) r3, [r1], #1) @ May fault - strgeb r3, [r0], #1 -USER( TUSER( ldrgtb) r3, [r1], #1) @ May fault - strgtb r3, [r0], #1 - b .Lcfu_finished -ENDPROC(__copy_from_user) - - .pushsection .fixup,"ax" - .align 0 - /* - * We took an exception. r0 contains a pointer to - * the byte not copied. - */ -9001: ldr r2, [sp], #4 @ void *to - sub r2, r0, r2 @ bytes copied - ldr r1, [sp], #4 @ unsigned long count - subs r4, r1, r2 @ bytes left to copy - movne r1, r4 - blne __memzero - mov r0, r4 - ldmfd sp!, {r4 - r7, pc} - .popsection - diff --git a/trunk/arch/arm/mach-at91/Kconfig b/trunk/arch/arm/mach-at91/Kconfig index 45db05d8d94c..19505c0a3f01 100644 --- a/trunk/arch/arm/mach-at91/Kconfig +++ b/trunk/arch/arm/mach-at91/Kconfig @@ -9,15 +9,6 @@ config HAVE_AT91_DBGU0 config HAVE_AT91_DBGU1 bool -config HAVE_AT91_USART3 - bool - -config HAVE_AT91_USART4 - bool - -config HAVE_AT91_USART5 - bool - config AT91_SAM9_ALT_RESET bool default !ARCH_AT91X40 @@ -26,87 +17,129 @@ config AT91_SAM9G45_RESET bool default !ARCH_AT91X40 +config SOC_AT91SAM9 + bool + select GENERIC_CLOCKEVENTS + select CPU_ARM926T + menu "Atmel AT91 System-on-Chip" -choice - prompt "Atmel AT91 Processor" +comment "Atmel AT91 Processor" -config ARCH_AT91RM9200 +config SOC_AT91SAM9 + bool + select CPU_ARM926T + select AT91_SAM9_TIME + select AT91_SAM9_SMC + +config SOC_AT91RM9200 bool "AT91RM9200" select CPU_ARM920T select GENERIC_CLOCKEVENTS select HAVE_AT91_DBGU0 - select HAVE_AT91_USART3 -config ARCH_AT91SAM9260 - bool "AT91SAM9260 or AT91SAM9XE" - select CPU_ARM926T - select GENERIC_CLOCKEVENTS +config SOC_AT91SAM9260 + bool "AT91SAM9260, AT91SAM9XE or AT91SAM9G20" + select SOC_AT91SAM9 select HAVE_AT91_DBGU0 - select HAVE_AT91_USART3 - select HAVE_AT91_USART4 - select HAVE_AT91_USART5 select HAVE_NET_MACB + help + Select this if you are using one of Atmel's AT91SAM9260, AT91SAM9XE + or AT91SAM9G20 SoC. -config ARCH_AT91SAM9261 - bool "AT91SAM9261" - select CPU_ARM926T - select GENERIC_CLOCKEVENTS - select HAVE_FB_ATMEL - select HAVE_AT91_DBGU0 - -config ARCH_AT91SAM9G10 - bool "AT91SAM9G10" - select CPU_ARM926T - select GENERIC_CLOCKEVENTS +config SOC_AT91SAM9261 + bool "AT91SAM9261 or AT91SAM9G10" + select SOC_AT91SAM9 select HAVE_AT91_DBGU0 select HAVE_FB_ATMEL + help + Select this if you are using one of Atmel's AT91SAM9261 or AT91SAM9G10 SoC. -config ARCH_AT91SAM9263 +config SOC_AT91SAM9263 bool "AT91SAM9263" - select CPU_ARM926T - select GENERIC_CLOCKEVENTS + select SOC_AT91SAM9 + select HAVE_AT91_DBGU1 select HAVE_FB_ATMEL select HAVE_NET_MACB - select HAVE_AT91_DBGU1 -config ARCH_AT91SAM9RL +config SOC_AT91SAM9RL bool "AT91SAM9RL" - select CPU_ARM926T - select GENERIC_CLOCKEVENTS - select HAVE_AT91_USART3 - select HAVE_FB_ATMEL - select HAVE_AT91_DBGU0 - -config ARCH_AT91SAM9G20 - bool "AT91SAM9G20" - select CPU_ARM926T - select GENERIC_CLOCKEVENTS + select SOC_AT91SAM9 select HAVE_AT91_DBGU0 - select HAVE_AT91_USART3 - select HAVE_AT91_USART4 - select HAVE_AT91_USART5 - select HAVE_NET_MACB + select HAVE_FB_ATMEL -config ARCH_AT91SAM9G45 - bool "AT91SAM9G45" - select CPU_ARM926T - select GENERIC_CLOCKEVENTS - select HAVE_AT91_USART3 +config SOC_AT91SAM9G45 + bool "AT91SAM9G45 or AT91SAM9M10 families" + select SOC_AT91SAM9 + select HAVE_AT91_DBGU1 select HAVE_FB_ATMEL select HAVE_NET_MACB - select HAVE_AT91_DBGU1 + help + Select this if you are using one of Atmel's AT91SAM9G45 family SoC. + This support covers AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and AT91SAM9M11. -config ARCH_AT91SAM9X5 +config SOC_AT91SAM9X5 bool "AT91SAM9x5 family" - select CPU_ARM926T - select GENERIC_CLOCKEVENTS + select SOC_AT91SAM9 + select HAVE_AT91_DBGU0 select HAVE_FB_ATMEL select HAVE_NET_MACB + help + Select this if you are using one of Atmel's AT91SAM9x5 family SoC. + This means that your SAM9 name finishes with a '5' (except if it is + AT91SAM9G45!). + This support covers AT91SAM9G15, AT91SAM9G25, AT91SAM9X25, AT91SAM9G35 + and AT91SAM9X35. + +config SOC_AT91SAM9N12 + bool "AT91SAM9N12 family" + select SOC_AT91SAM9 select HAVE_AT91_DBGU0 + select HAVE_FB_ATMEL + help + Select this if you are using Atmel's AT91SAM9N12 SoC. + +choice + prompt "Atmel AT91 Processor Devices for non DT boards" + +config ARCH_AT91_NONE + bool "None" + +config ARCH_AT91RM9200 + bool "AT91RM9200" + select SOC_AT91RM9200 + +config ARCH_AT91SAM9260 + bool "AT91SAM9260 or AT91SAM9XE" + select SOC_AT91SAM9260 + +config ARCH_AT91SAM9261 + bool "AT91SAM9261" + select SOC_AT91SAM9261 + +config ARCH_AT91SAM9G10 + bool "AT91SAM9G10" + select SOC_AT91SAM9261 + +config ARCH_AT91SAM9263 + bool "AT91SAM9263" + select SOC_AT91SAM9263 + +config ARCH_AT91SAM9RL + bool "AT91SAM9RL" + select SOC_AT91SAM9RL + +config ARCH_AT91SAM9G20 + bool "AT91SAM9G20" + select SOC_AT91SAM9260 + +config ARCH_AT91SAM9G45 + bool "AT91SAM9G45" + select SOC_AT91SAM9G45 config ARCH_AT91X40 bool "AT91x40" + depends on !MMU select ARCH_USES_GETTIMEOFFSET endchoice @@ -364,6 +397,7 @@ config MACH_AT91SAM9G20EK_2MMC Select this if you are using an Atmel AT91SAM9G20-EK Evaluation Kit with 2 SD/MMC Slots. This is the case for AT91SAM9G20-EK rev. C and onwards. + config MACH_CPU9G20 bool "Eukrea CPU9G20 board" @@ -433,9 +467,10 @@ comment "AT91SAM9G45 Board Type" config MACH_AT91SAM9M10G45EK bool "Atmel AT91SAM9M10G45-EK Evaluation Kits" help - Select this if you are using Atmel's AT91SAM9G45-EKES Evaluation Kit. - "ES" at the end of the name means that this board is an - Engineering Sample. + Select this if you are using Atmel's AT91SAM9M10G45-EK Evaluation Kit. + Those boards can be populated with any SoC of AT91SAM9G45 or AT91SAM9M10 + families: AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and AT91SAM9M11. + endif @@ -515,41 +550,6 @@ config AT91_TIMER_HZ system clock (of at least several MHz), rounding is less of a problem so it can be safer to use a decimal values like 100. -choice - prompt "Select a UART for early kernel messages" - -config AT91_EARLY_DBGU0 - bool "DBGU on rm9200, 9260/9g20, 9261/9g10 and 9rl" - depends on HAVE_AT91_DBGU0 - -config AT91_EARLY_DBGU1 - bool "DBGU on 9263 and 9g45" - depends on HAVE_AT91_DBGU1 - -config AT91_EARLY_USART0 - bool "USART0" - -config AT91_EARLY_USART1 - bool "USART1" - -config AT91_EARLY_USART2 - bool "USART2" - depends on ! ARCH_AT91X40 - -config AT91_EARLY_USART3 - bool "USART3" - depends on HAVE_AT91_USART3 - -config AT91_EARLY_USART4 - bool "USART4" - depends on HAVE_AT91_USART4 - -config AT91_EARLY_USART5 - bool "USART5" - depends on HAVE_AT91_USART5 - -endchoice - endmenu endif diff --git a/trunk/arch/arm/mach-at91/Makefile b/trunk/arch/arm/mach-at91/Makefile index 8512e53bed93..3bb7a51efc9d 100644 --- a/trunk/arch/arm/mach-at91/Makefile +++ b/trunk/arch/arm/mach-at91/Makefile @@ -10,17 +10,26 @@ obj- := obj-$(CONFIG_AT91_PMC_UNIT) += clock.o obj-$(CONFIG_AT91_SAM9_ALT_RESET) += at91sam9_alt_reset.o obj-$(CONFIG_AT91_SAM9G45_RESET) += at91sam9g45_reset.o +obj-$(CONFIG_SOC_AT91SAM9) += at91sam926x_time.o sam9_smc.o # CPU-specific support -obj-$(CONFIG_ARCH_AT91RM9200) += at91rm9200.o at91rm9200_time.o at91rm9200_devices.o -obj-$(CONFIG_ARCH_AT91SAM9260) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o -obj-$(CONFIG_ARCH_AT91SAM9261) += at91sam9261.o at91sam926x_time.o at91sam9261_devices.o sam9_smc.o -obj-$(CONFIG_ARCH_AT91SAM9G10) += at91sam9261.o at91sam926x_time.o at91sam9261_devices.o sam9_smc.o -obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263.o at91sam926x_time.o at91sam9263_devices.o sam9_smc.o -obj-$(CONFIG_ARCH_AT91SAM9RL) += at91sam9rl.o at91sam926x_time.o at91sam9rl_devices.o sam9_smc.o -obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o -obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45.o at91sam926x_time.o at91sam9g45_devices.o sam9_smc.o -obj-$(CONFIG_ARCH_AT91SAM9X5) += at91sam9x5.o at91sam926x_time.o sam9_smc.o +obj-$(CONFIG_SOC_AT91RM9200) += at91rm9200.o at91rm9200_time.o +obj-$(CONFIG_SOC_AT91SAM9260) += at91sam9260.o +obj-$(CONFIG_SOC_AT91SAM9261) += at91sam9261.o +obj-$(CONFIG_SOC_AT91SAM9263) += at91sam9263.o +obj-$(CONFIG_SOC_AT91SAM9G45) += at91sam9g45.o +obj-$(CONFIG_SOC_AT91SAM9N12) += at91sam9n12.o +obj-$(CONFIG_SOC_AT91SAM9X5) += at91sam9x5.o +obj-$(CONFIG_SOC_AT91SAM9RL) += at91sam9rl.o + +obj-$(CONFIG_ARCH_AT91RM9200) += at91rm9200_devices.o +obj-$(CONFIG_ARCH_AT91SAM9260) += at91sam9260_devices.o +obj-$(CONFIG_ARCH_AT91SAM9261) += at91sam9261_devices.o +obj-$(CONFIG_ARCH_AT91SAM9G10) += at91sam9261_devices.o +obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263_devices.o +obj-$(CONFIG_ARCH_AT91SAM9RL) += at91sam9rl_devices.o +obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260_devices.o +obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45_devices.o obj-$(CONFIG_ARCH_AT91X40) += at91x40.o at91x40_time.o # AT91RM9200 board-specific support diff --git a/trunk/arch/arm/mach-at91/Makefile.boot b/trunk/arch/arm/mach-at91/Makefile.boot index 0da66ca4a4f8..9e84fe4f2aaa 100644 --- a/trunk/arch/arm/mach-at91/Makefile.boot +++ b/trunk/arch/arm/mach-at91/Makefile.boot @@ -14,9 +14,23 @@ initrd_phys-y := 0x20410000 endif # Keep dtb files sorted alphabetically for each SoC +# sam9260 +dtb-$(CONFIG_MACH_AT91SAM_DT) += ethernut5.dtb +dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9260.dtb +dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9260.dtb +# sam9263 +dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9263ek.dtb +dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9263.dtb +dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9263.dtb # sam9g20 +dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek.dtb +dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek_2mmc.dtb +dtb-$(CONFIG_MACH_AT91SAM_DT) += kizbox.dtb +dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9g20.dtb dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9g20.dtb # sam9g45 dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9m10g45ek.dtb +# sam9n12 +dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9n12ek.dtb # sam9x5 dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g25ek.dtb diff --git a/trunk/arch/arm/mach-at91/at91rm9200.c b/trunk/arch/arm/mach-at91/at91rm9200.c index 364c19357e60..26917687fc30 100644 --- a/trunk/arch/arm/mach-at91/at91rm9200.c +++ b/trunk/arch/arm/mach-at91/at91rm9200.c @@ -26,15 +26,6 @@ #include "clock.h" #include "sam9_smc.h" -static struct map_desc at91rm9200_io_desc[] __initdata = { - { - .virtual = AT91_VA_BASE_EMAC, - .pfn = __phys_to_pfn(AT91RM9200_BASE_EMAC), - .length = SZ_16K, - .type = MT_DEVICE, - }, -}; - /* -------------------------------------------------------------------- * Clocks * -------------------------------------------------------------------- */ @@ -258,18 +249,6 @@ static void __init at91rm9200_register_clocks(void) clk_register(&pck3); } -static struct clk_lookup console_clock_lookup; - -void __init at91rm9200_set_console_clock(int id) -{ - if (id >= ARRAY_SIZE(usart_clocks_lookups)) - return; - - console_clock_lookup.con_id = "usart"; - console_clock_lookup.clk = usart_clocks_lookups[id].clk; - clkdev_add(&console_clock_lookup); -} - /* -------------------------------------------------------------------- * GPIO * -------------------------------------------------------------------- */ @@ -315,7 +294,6 @@ static void __init at91rm9200_map_io(void) { /* Map peripherals */ at91_init_sram(0, AT91RM9200_SRAM_BASE, AT91RM9200_SRAM_SIZE); - iotable_init(at91rm9200_io_desc, ARRAY_SIZE(at91rm9200_io_desc)); } static void __init at91rm9200_ioremap_registers(void) diff --git a/trunk/arch/arm/mach-at91/at91rm9200_devices.c b/trunk/arch/arm/mach-at91/at91rm9200_devices.c index 05774e5b1cba..e6b7d0533dd7 100644 --- a/trunk/arch/arm/mach-at91/at91rm9200_devices.c +++ b/trunk/arch/arm/mach-at91/at91rm9200_devices.c @@ -140,8 +140,8 @@ static struct macb_platform_data eth_data; static struct resource eth_resources[] = { [0] = { - .start = AT91_VA_BASE_EMAC, - .end = AT91_VA_BASE_EMAC + SZ_16K - 1, + .start = AT91RM9200_BASE_EMAC, + .end = AT91RM9200_BASE_EMAC + SZ_16K - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -1152,14 +1152,6 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) at91_uarts[portnr] = pdev; } -void __init at91_set_serial_console(unsigned portnr) -{ - if (portnr < ATMEL_MAX_UART) { - atmel_default_console_device = at91_uarts[portnr]; - at91rm9200_set_console_clock(at91_uarts[portnr]->id); - } -} - void __init at91_add_device_serial(void) { int i; @@ -1168,13 +1160,9 @@ void __init at91_add_device_serial(void) if (at91_uarts[i]) platform_device_register(at91_uarts[i]); } - - if (!atmel_default_console_device) - printk(KERN_INFO "AT91: No default serial console defined.\n"); } #else void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {} -void __init at91_set_serial_console(unsigned portnr) {} void __init at91_add_device_serial(void) {} #endif diff --git a/trunk/arch/arm/mach-at91/at91sam9260.c b/trunk/arch/arm/mach-at91/at91sam9260.c index 46f774233298..2b1e438ed878 100644 --- a/trunk/arch/arm/mach-at91/at91sam9260.c +++ b/trunk/arch/arm/mach-at91/at91sam9260.c @@ -55,6 +55,13 @@ static struct clk adc_clk = { .pmc_mask = 1 << AT91SAM9260_ID_ADC, .type = CLK_TYPE_PERIPHERAL, }; + +static struct clk adc_op_clk = { + .name = "adc_op_clk", + .type = CLK_TYPE_PERIPHERAL, + .rate_hz = 5000000, +}; + static struct clk usart0_clk = { .name = "usart0_clk", .pmc_mask = 1 << AT91SAM9260_ID_US0, @@ -166,6 +173,7 @@ static struct clk *periph_clocks[] __initdata = { &pioB_clk, &pioC_clk, &adc_clk, + &adc_op_clk, &usart0_clk, &usart1_clk, &usart2_clk, @@ -268,18 +276,6 @@ static void __init at91sam9260_register_clocks(void) clk_register(&pck1); } -static struct clk_lookup console_clock_lookup; - -void __init at91sam9260_set_console_clock(int id) -{ - if (id >= ARRAY_SIZE(usart_clocks_lookups)) - return; - - console_clock_lookup.con_id = "usart"; - console_clock_lookup.clk = usart_clocks_lookups[id].clk; - clkdev_add(&console_clock_lookup); -} - /* -------------------------------------------------------------------- * GPIO * -------------------------------------------------------------------- */ diff --git a/trunk/arch/arm/mach-at91/at91sam9260_devices.c b/trunk/arch/arm/mach-at91/at91sam9260_devices.c index 5652dde4bbe2..0ded951f785a 100644 --- a/trunk/arch/arm/mach-at91/at91sam9260_devices.c +++ b/trunk/arch/arm/mach-at91/at91sam9260_devices.c @@ -17,12 +17,15 @@ #include #include +#include + #include #include #include #include #include #include +#include #include "generic.h" @@ -702,25 +705,8 @@ static struct platform_device at91sam9260_tcb1_device = { .num_resources = ARRAY_SIZE(tcb1_resources), }; -#if defined(CONFIG_OF) -static struct of_device_id tcb_ids[] = { - { .compatible = "atmel,at91rm9200-tcb" }, - { /*sentinel*/ } -}; -#endif - static void __init at91_add_device_tc(void) { -#if defined(CONFIG_OF) - struct device_node *np; - - np = of_find_matching_node(NULL, tcb_ids); - if (np) { - of_node_put(np); - return; - } -#endif - platform_device_register(&at91sam9260_tcb0_device); platform_device_register(&at91sam9260_tcb1_device); } @@ -1229,14 +1215,6 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) at91_uarts[portnr] = pdev; } -void __init at91_set_serial_console(unsigned portnr) -{ - if (portnr < ATMEL_MAX_UART) { - atmel_default_console_device = at91_uarts[portnr]; - at91sam9260_set_console_clock(at91_uarts[portnr]->id); - } -} - void __init at91_add_device_serial(void) { int i; @@ -1245,13 +1223,9 @@ void __init at91_add_device_serial(void) if (at91_uarts[i]) platform_device_register(at91_uarts[i]); } - - if (!atmel_default_console_device) - printk(KERN_INFO "AT91: No default serial console defined.\n"); } #else void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {} -void __init at91_set_serial_console(unsigned portnr) {} void __init at91_add_device_serial(void) {} #endif @@ -1369,6 +1343,93 @@ void __init at91_add_device_cf(struct at91_cf_data *data) void __init at91_add_device_cf(struct at91_cf_data * data) {} #endif +/* -------------------------------------------------------------------- + * ADCs + * -------------------------------------------------------------------- */ + +#if IS_ENABLED(CONFIG_AT91_ADC) +static struct at91_adc_data adc_data; + +static struct resource adc_resources[] = { + [0] = { + .start = AT91SAM9260_BASE_ADC, + .end = AT91SAM9260_BASE_ADC + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91SAM9260_ID_ADC, + .end = AT91SAM9260_ID_ADC, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device at91_adc_device = { + .name = "at91_adc", + .id = -1, + .dev = { + .platform_data = &adc_data, + }, + .resource = adc_resources, + .num_resources = ARRAY_SIZE(adc_resources), +}; + +static struct at91_adc_trigger at91_adc_triggers[] = { + [0] = { + .name = "timer-counter-0", + .value = AT91_ADC_TRGSEL_TC0 | AT91_ADC_TRGEN, + }, + [1] = { + .name = "timer-counter-1", + .value = AT91_ADC_TRGSEL_TC1 | AT91_ADC_TRGEN, + }, + [2] = { + .name = "timer-counter-2", + .value = AT91_ADC_TRGSEL_TC2 | AT91_ADC_TRGEN, + }, + [3] = { + .name = "external", + .value = AT91_ADC_TRGSEL_EXTERNAL | AT91_ADC_TRGEN, + .is_external = true, + }, +}; + +static struct at91_adc_reg_desc at91_adc_register_g20 = { + .channel_base = AT91_ADC_CHR(0), + .drdy_mask = AT91_ADC_DRDY, + .status_register = AT91_ADC_SR, + .trigger_register = AT91_ADC_MR, +}; + +void __init at91_add_device_adc(struct at91_adc_data *data) +{ + if (!data) + return; + + if (test_bit(0, &data->channels_used)) + at91_set_A_periph(AT91_PIN_PC0, 0); + if (test_bit(1, &data->channels_used)) + at91_set_A_periph(AT91_PIN_PC1, 0); + if (test_bit(2, &data->channels_used)) + at91_set_A_periph(AT91_PIN_PC2, 0); + if (test_bit(3, &data->channels_used)) + at91_set_A_periph(AT91_PIN_PC3, 0); + + if (data->use_external_triggers) + at91_set_A_periph(AT91_PIN_PA22, 0); + + data->num_channels = 4; + data->startup_time = 10; + data->registers = &at91_adc_register_g20; + data->trigger_number = 4; + data->trigger_list = at91_adc_triggers; + + adc_data = *data; + platform_device_register(&at91_adc_device); +} +#else +void __init at91_add_device_adc(struct at91_adc_data *data) {} +#endif + /* -------------------------------------------------------------------- */ /* * These devices are always present and don't need any board-specific @@ -1376,6 +1437,9 @@ void __init at91_add_device_cf(struct at91_cf_data * data) {} */ static int __init at91_add_standard_devices(void) { + if (of_have_populated_dt()) + return 0; + at91_add_device_rtt(); at91_add_device_watchdog(); at91_add_device_tc(); diff --git a/trunk/arch/arm/mach-at91/at91sam9261.c b/trunk/arch/arm/mach-at91/at91sam9261.c index 7de81e6222f1..c77d503d09d1 100644 --- a/trunk/arch/arm/mach-at91/at91sam9261.c +++ b/trunk/arch/arm/mach-at91/at91sam9261.c @@ -239,18 +239,6 @@ static void __init at91sam9261_register_clocks(void) clk_register(&hck1); } -static struct clk_lookup console_clock_lookup; - -void __init at91sam9261_set_console_clock(int id) -{ - if (id >= ARRAY_SIZE(usart_clocks_lookups)) - return; - - console_clock_lookup.con_id = "usart"; - console_clock_lookup.clk = usart_clocks_lookups[id].clk; - clkdev_add(&console_clock_lookup); -} - /* -------------------------------------------------------------------- * GPIO * -------------------------------------------------------------------- */ diff --git a/trunk/arch/arm/mach-at91/at91sam9261_devices.c b/trunk/arch/arm/mach-at91/at91sam9261_devices.c index 4db961a93085..9295e90b08ff 100644 --- a/trunk/arch/arm/mach-at91/at91sam9261_devices.c +++ b/trunk/arch/arm/mach-at91/at91sam9261_devices.c @@ -1051,14 +1051,6 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) at91_uarts[portnr] = pdev; } -void __init at91_set_serial_console(unsigned portnr) -{ - if (portnr < ATMEL_MAX_UART) { - atmel_default_console_device = at91_uarts[portnr]; - at91sam9261_set_console_clock(at91_uarts[portnr]->id); - } -} - void __init at91_add_device_serial(void) { int i; @@ -1067,13 +1059,9 @@ void __init at91_add_device_serial(void) if (at91_uarts[i]) platform_device_register(at91_uarts[i]); } - - if (!atmel_default_console_device) - printk(KERN_INFO "AT91: No default serial console defined.\n"); } #else void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {} -void __init at91_set_serial_console(unsigned portnr) {} void __init at91_add_device_serial(void) {} #endif diff --git a/trunk/arch/arm/mach-at91/at91sam9263.c b/trunk/arch/arm/mach-at91/at91sam9263.c index ef301be66575..ed91c7e9f7c2 100644 --- a/trunk/arch/arm/mach-at91/at91sam9263.c +++ b/trunk/arch/arm/mach-at91/at91sam9263.c @@ -199,6 +199,16 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_ID("pioC", &pioCDE_clk), CLKDEV_CON_ID("pioD", &pioCDE_clk), CLKDEV_CON_ID("pioE", &pioCDE_clk), + /* more usart lookup table for DT entries */ + CLKDEV_CON_DEV_ID("usart", "ffffee00.serial", &mck), + CLKDEV_CON_DEV_ID("usart", "fff8c000.serial", &usart0_clk), + CLKDEV_CON_DEV_ID("usart", "fff90000.serial", &usart1_clk), + CLKDEV_CON_DEV_ID("usart", "fff94000.serial", &usart2_clk), + /* more tc lookup table for DT entries */ + CLKDEV_CON_DEV_ID("t0_clk", "fff7c000.timer", &tcb_clk), + CLKDEV_CON_DEV_ID("hclk", "a00000.ohci", &ohci_clk), + CLKDEV_CON_DEV_ID("spi_clk", "fffa4000.spi", &spi0_clk), + CLKDEV_CON_DEV_ID("spi_clk", "fffa8000.spi", &spi1_clk), }; static struct clk_lookup usart_clocks_lookups[] = { @@ -255,18 +265,6 @@ static void __init at91sam9263_register_clocks(void) clk_register(&pck3); } -static struct clk_lookup console_clock_lookup; - -void __init at91sam9263_set_console_clock(int id) -{ - if (id >= ARRAY_SIZE(usart_clocks_lookups)) - return; - - console_clock_lookup.con_id = "usart"; - console_clock_lookup.clk = usart_clocks_lookups[id].clk; - clkdev_add(&console_clock_lookup); -} - /* -------------------------------------------------------------------- * GPIO * -------------------------------------------------------------------- */ diff --git a/trunk/arch/arm/mach-at91/at91sam9263_devices.c b/trunk/arch/arm/mach-at91/at91sam9263_devices.c index fe99206de880..175e0009eaa9 100644 --- a/trunk/arch/arm/mach-at91/at91sam9263_devices.c +++ b/trunk/arch/arm/mach-at91/at91sam9263_devices.c @@ -953,8 +953,25 @@ static struct platform_device at91sam9263_tcb_device = { .num_resources = ARRAY_SIZE(tcb_resources), }; +#if defined(CONFIG_OF) +static struct of_device_id tcb_ids[] = { + { .compatible = "atmel,at91rm9200-tcb" }, + { /*sentinel*/ } +}; +#endif + static void __init at91_add_device_tc(void) { +#if defined(CONFIG_OF) + struct device_node *np; + + np = of_find_matching_node(NULL, tcb_ids); + if (np) { + of_node_put(np); + return; + } +#endif + platform_device_register(&at91sam9263_tcb_device); } #else @@ -1461,14 +1478,6 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) at91_uarts[portnr] = pdev; } -void __init at91_set_serial_console(unsigned portnr) -{ - if (portnr < ATMEL_MAX_UART) { - atmel_default_console_device = at91_uarts[portnr]; - at91sam9263_set_console_clock(at91_uarts[portnr]->id); - } -} - void __init at91_add_device_serial(void) { int i; @@ -1477,13 +1486,9 @@ void __init at91_add_device_serial(void) if (at91_uarts[i]) platform_device_register(at91_uarts[i]); } - - if (!atmel_default_console_device) - printk(KERN_INFO "AT91: No default serial console defined.\n"); } #else void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {} -void __init at91_set_serial_console(unsigned portnr) {} void __init at91_add_device_serial(void) {} #endif @@ -1495,6 +1500,9 @@ void __init at91_add_device_serial(void) {} */ static int __init at91_add_standard_devices(void) { + if (of_have_populated_dt()) + return 0; + at91_add_device_rtt(); at91_add_device_watchdog(); at91_add_device_tc(); diff --git a/trunk/arch/arm/mach-at91/at91sam9g45.c b/trunk/arch/arm/mach-at91/at91sam9g45.c index d222f8333dab..4792682d52b9 100644 --- a/trunk/arch/arm/mach-at91/at91sam9g45.c +++ b/trunk/arch/arm/mach-at91/at91sam9g45.c @@ -176,6 +176,12 @@ static struct clk vdec_clk = { .type = CLK_TYPE_PERIPHERAL, }; +static struct clk adc_op_clk = { + .name = "adc_op_clk", + .type = CLK_TYPE_PERIPHERAL, + .rate_hz = 13200000, +}; + static struct clk *periph_clocks[] __initdata = { &pioA_clk, &pioB_clk, @@ -204,6 +210,7 @@ static struct clk *periph_clocks[] __initdata = { &isi_clk, &udphs_clk, &mmc1_clk, + &adc_op_clk, // irq0 }; @@ -242,6 +249,8 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_ID("pioC", &pioC_clk), CLKDEV_CON_ID("pioD", &pioDE_clk), CLKDEV_CON_ID("pioE", &pioDE_clk), + /* Fake adc clock */ + CLKDEV_CON_ID("adc_clk", &tsc_clk), }; static struct clk_lookup usart_clocks_lookups[] = { @@ -288,18 +297,6 @@ static void __init at91sam9g45_register_clocks(void) clk_register(&pck1); } -static struct clk_lookup console_clock_lookup; - -void __init at91sam9g45_set_console_clock(int id) -{ - if (id >= ARRAY_SIZE(usart_clocks_lookups)) - return; - - console_clock_lookup.con_id = "usart"; - console_clock_lookup.clk = usart_clocks_lookups[id].clk; - clkdev_add(&console_clock_lookup); -} - /* -------------------------------------------------------------------- * GPIO * -------------------------------------------------------------------- */ diff --git a/trunk/arch/arm/mach-at91/at91sam9g45_devices.c b/trunk/arch/arm/mach-at91/at91sam9g45_devices.c index 6b008aee1dff..f6747246d649 100644 --- a/trunk/arch/arm/mach-at91/at91sam9g45_devices.c +++ b/trunk/arch/arm/mach-at91/at91sam9g45_devices.c @@ -19,9 +19,12 @@ #include #include +#include + #include #include - - Microprocessor Communications Support Chips, T.J. Byers, ISBN - 0-444-01224-9, has a section on the i82586. It tells you just enough - to know that you really don't want to learn how to program the chip. - - The original device probe code was stolen from ps2esdi.c - - Known Problems: - Since most of the code was stolen from ni52.c, you'll run across the - same bugs in the 0.62 version of ni52.c, plus maybe a few because of - the 3c523 idiosynchacies. The 3c523 has 16K of RAM though, so there - shouldn't be the overrun problem that the 8K ni52 has. - - This driver is for a 16K adapter. It should work fine on the 64K - adapters, but it will only use one of the 4 banks of RAM. Modifying - this for the 64K version would require a lot of heinous bank - switching, which I'm sure not interested in doing. If you try to - implement a bank switching version, you'll basically have to remember - what bank is enabled and do a switch every time you access a memory - location that's not current. You'll also have to remap pointers on - the driver side, because it only knows about 16K of the memory. - Anyone desperate or masochistic enough to try? - - It seems to be stable now when multiple transmit buffers are used. I - can't see any performance difference, but then I'm working on a 386SX. - - Multicast doesn't work. It doesn't even pretend to work. Don't use - it. Don't compile your kernel with multicast support. I don't know - why. - - Features: - This driver is useable as a loadable module. If you try to specify an - IRQ or a IO address (via insmod 3c523.o irq=xx io=0xyyy), it will - search the MCA slots until it finds a 3c523 with the specified - parameters. - - This driver does support multiple ethernet cards when used as a module - (up to MAX_3C523_CARDS, the default being 4) - - This has been tested with both BNC and TP versions, internal and - external transceivers. Haven't tested with the 64K version (that I - know of). - - History: - Jan 1st, 1996 - first public release - Feb 4th, 1996 - update to 1.3.59, incorporated multicast diffs from ni52.c - Feb 15th, 1996 - added shared irq support - Apr 1999 - added support for multiple cards when used as a module - added option to disable multicast as is causes problems - Ganesh Sittampalam - Stuart Adamson - Nov 2001 - added support for ethtool (jgarzik) - - $Header: /fsys2/home/chrisb/linux-1.3.59-MCA/drivers/net/RCS/3c523.c,v 1.1 1996/02/05 01:53:46 chrisb Exp chrisb $ - */ - -#define DRV_NAME "3c523" -#define DRV_VERSION "17-Nov-2001" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "3c523.h" - -/*************************************************************************/ -#define DEBUG /* debug on */ -#define SYSBUSVAL 0 /* 1 = 8 Bit, 0 = 16 bit - 3c523 only does 16 bit */ -#undef ELMC_MULTICAST /* Disable multicast support as it is somewhat seriously broken at the moment */ - -#define make32(ptr16) (p->memtop + (short) (ptr16) ) -#define make24(ptr32) ((char *) (ptr32) - p->base) -#define make16(ptr32) ((unsigned short) ((unsigned long) (ptr32) - (unsigned long) p->memtop )) - -/*************************************************************************/ -/* - Tables to which we can map values in the configuration registers. - */ -static int irq_table[] __initdata = { - 12, 7, 3, 9 -}; - -static int csr_table[] __initdata = { - 0x300, 0x1300, 0x2300, 0x3300 -}; - -static int shm_table[] __initdata = { - 0x0c0000, 0x0c8000, 0x0d0000, 0x0d8000 -}; - -/******************* how to calculate the buffers ***************************** - - - * IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, the driver works - * --------------- in a different (more stable?) mode. Only in this mode it's - * possible to configure the driver with 'NO_NOPCOMMANDS' - -sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8; -sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT -sizeof(rfd) = 24; sizeof(rbd) = 12; -sizeof(tbd) = 8; sizeof(transmit_cmd) = 16; -sizeof(nop_cmd) = 8; - - * if you don't know the driver, better do not change this values: */ - -#define RECV_BUFF_SIZE 1524 /* slightly oversized */ -#define XMIT_BUFF_SIZE 1524 /* slightly oversized */ -#define NUM_XMIT_BUFFS 1 /* config for both, 8K and 16K shmem */ -#define NUM_RECV_BUFFS_8 4 /* config for 8K shared mem */ -#define NUM_RECV_BUFFS_16 9 /* config for 16K shared mem */ - -#if (NUM_XMIT_BUFFS == 1) -#define NO_NOPCOMMANDS /* only possible with NUM_XMIT_BUFFS=1 */ -#endif - -/**************************************************************************/ - -#define DELAY(x) { mdelay(32 * x); } - -/* a much shorter delay: */ -#define DELAY_16(); { udelay(16) ; } - -/* wait for command with timeout: */ -#define WAIT_4_SCB_CMD() { int i; \ - for(i=0;i<1024;i++) { \ - if(!p->scb->cmd) break; \ - DELAY_16(); \ - if(i == 1023) { \ - pr_warning("%s:%d: scb_cmd timed out .. resetting i82586\n",\ - dev->name,__LINE__); \ - elmc_id_reset586(); } } } - -static irqreturn_t elmc_interrupt(int irq, void *dev_id); -static int elmc_open(struct net_device *dev); -static int elmc_close(struct net_device *dev); -static netdev_tx_t elmc_send_packet(struct sk_buff *, struct net_device *); -static struct net_device_stats *elmc_get_stats(struct net_device *dev); -static void elmc_timeout(struct net_device *dev); -#ifdef ELMC_MULTICAST -static void set_multicast_list(struct net_device *dev); -#endif -static const struct ethtool_ops netdev_ethtool_ops; - -/* helper-functions */ -static int init586(struct net_device *dev); -static int check586(struct net_device *dev, unsigned long where, unsigned size); -static void alloc586(struct net_device *dev); -static void startrecv586(struct net_device *dev); -static void *alloc_rfa(struct net_device *dev, void *ptr); -static void elmc_rcv_int(struct net_device *dev); -static void elmc_xmt_int(struct net_device *dev); -static void elmc_rnr_int(struct net_device *dev); - -struct priv { - unsigned long base; - char *memtop; - unsigned long mapped_start; /* Start of ioremap */ - volatile struct rfd_struct *rfd_last, *rfd_top, *rfd_first; - volatile struct scp_struct *scp; /* volatile is important */ - volatile struct iscp_struct *iscp; /* volatile is important */ - volatile struct scb_struct *scb; /* volatile is important */ - volatile struct tbd_struct *xmit_buffs[NUM_XMIT_BUFFS]; -#if (NUM_XMIT_BUFFS == 1) - volatile struct transmit_cmd_struct *xmit_cmds[2]; - volatile struct nop_cmd_struct *nop_cmds[2]; -#else - volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS]; - volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS]; -#endif - volatile int nop_point, num_recv_buffs; - volatile char *xmit_cbuffs[NUM_XMIT_BUFFS]; - volatile int xmit_count, xmit_last; - volatile int slot; -}; - -#define elmc_attn586() {elmc_do_attn586(dev->base_addr,ELMC_CTRL_INTE);} -#define elmc_reset586() {elmc_do_reset586(dev->base_addr,ELMC_CTRL_INTE);} - -/* with interrupts disabled - this will clear the interrupt bit in the - 3c523 control register, and won't put it back. This effectively - disables interrupts on the card. */ -#define elmc_id_attn586() {elmc_do_attn586(dev->base_addr,0);} -#define elmc_id_reset586() {elmc_do_reset586(dev->base_addr,0);} - -/*************************************************************************/ -/* - Do a Channel Attention on the 3c523. This is extremely board dependent. - */ -static void elmc_do_attn586(int ioaddr, int ints) -{ - /* the 3c523 requires a minimum of 500 ns. The delays here might be - a little too large, and hence they may cut the performance of the - card slightly. If someone who knows a little more about Linux - timing would care to play with these, I'd appreciate it. */ - - /* this bit masking stuff is crap. I'd rather have separate - registers with strobe triggers for each of these functions. - Ya take what ya got. */ - - outb(ELMC_CTRL_RST | 0x3 | ELMC_CTRL_CA | ints, ioaddr + ELMC_CTRL); - DELAY_16(); /* > 500 ns */ - outb(ELMC_CTRL_RST | 0x3 | ints, ioaddr + ELMC_CTRL); -} - -/*************************************************************************/ -/* - Reset the 82586 on the 3c523. Also very board dependent. - */ -static void elmc_do_reset586(int ioaddr, int ints) -{ - /* toggle the RST bit low then high */ - outb(0x3 | ELMC_CTRL_LBK, ioaddr + ELMC_CTRL); - DELAY_16(); /* > 500 ns */ - outb(ELMC_CTRL_RST | ELMC_CTRL_LBK | 0x3, ioaddr + ELMC_CTRL); - - elmc_do_attn586(ioaddr, ints); -} - -/********************************************** - * close device - */ - -static int elmc_close(struct net_device *dev) -{ - netif_stop_queue(dev); - elmc_id_reset586(); /* the hard way to stop the receiver */ - free_irq(dev->irq, dev); - return 0; -} - -/********************************************** - * open device - */ - -static int elmc_open(struct net_device *dev) -{ - int ret; - - elmc_id_attn586(); /* disable interrupts */ - - ret = request_irq(dev->irq, elmc_interrupt, IRQF_SHARED, - dev->name, dev); - if (ret) { - pr_err("%s: couldn't get irq %d\n", dev->name, dev->irq); - elmc_id_reset586(); - return ret; - } - alloc586(dev); - init586(dev); - startrecv586(dev); - netif_start_queue(dev); - return 0; /* most done by init */ -} - -/********************************************** - * Check to see if there's an 82586 out there. - */ - -static int __init check586(struct net_device *dev, unsigned long where, unsigned size) -{ - struct priv *p = netdev_priv(dev); - char *iscp_addrs[2]; - int i = 0; - - p->base = (unsigned long) isa_bus_to_virt((unsigned long)where) + size - 0x01000000; - p->memtop = isa_bus_to_virt((unsigned long)where) + size; - p->scp = (struct scp_struct *)(p->base + SCP_DEFAULT_ADDRESS); - memset((char *) p->scp, 0, sizeof(struct scp_struct)); - p->scp->sysbus = SYSBUSVAL; /* 1 = 8Bit-Bus, 0 = 16 Bit */ - - iscp_addrs[0] = isa_bus_to_virt((unsigned long)where); - iscp_addrs[1] = (char *) p->scp - sizeof(struct iscp_struct); - - for (i = 0; i < 2; i++) { - p->iscp = (struct iscp_struct *) iscp_addrs[i]; - memset((char *) p->iscp, 0, sizeof(struct iscp_struct)); - - p->scp->iscp = make24(p->iscp); - p->iscp->busy = 1; - - elmc_id_reset586(); - - /* reset586 does an implicit CA */ - - /* apparently, you sometimes have to kick the 82586 twice... */ - elmc_id_attn586(); - DELAY(1); - - if (p->iscp->busy) { /* i82586 clears 'busy' after successful init */ - return 0; - } - } - return 1; -} - -/****************************************************************** - * set iscp at the right place, called by elmc_probe and open586. - */ - -static void alloc586(struct net_device *dev) -{ - struct priv *p = netdev_priv(dev); - - elmc_id_reset586(); - DELAY(2); - - p->scp = (struct scp_struct *) (p->base + SCP_DEFAULT_ADDRESS); - p->scb = (struct scb_struct *) isa_bus_to_virt(dev->mem_start); - p->iscp = (struct iscp_struct *) ((char *) p->scp - sizeof(struct iscp_struct)); - - memset((char *) p->iscp, 0, sizeof(struct iscp_struct)); - memset((char *) p->scp, 0, sizeof(struct scp_struct)); - - p->scp->iscp = make24(p->iscp); - p->scp->sysbus = SYSBUSVAL; - p->iscp->scb_offset = make16(p->scb); - - p->iscp->busy = 1; - elmc_id_reset586(); - elmc_id_attn586(); - - DELAY(2); - - if (p->iscp->busy) - pr_err("%s: Init-Problems (alloc).\n", dev->name); - - memset((char *) p->scb, 0, sizeof(struct scb_struct)); -} - -/*****************************************************************/ - -static int elmc_getinfo(char *buf, int slot, void *d) -{ - int len = 0; - struct net_device *dev = d; - - if (dev == NULL) - return len; - - len += sprintf(buf + len, "Revision: 0x%x\n", - inb(dev->base_addr + ELMC_REVISION) & 0xf); - len += sprintf(buf + len, "IRQ: %d\n", dev->irq); - len += sprintf(buf + len, "IO Address: %#lx-%#lx\n", dev->base_addr, - dev->base_addr + ELMC_IO_EXTENT); - len += sprintf(buf + len, "Memory: %#lx-%#lx\n", dev->mem_start, - dev->mem_end - 1); - len += sprintf(buf + len, "Transceiver: %s\n", dev->if_port ? - "External" : "Internal"); - len += sprintf(buf + len, "Device: %s\n", dev->name); - len += sprintf(buf + len, "Hardware Address: %pM\n", - dev->dev_addr); - - return len; -} /* elmc_getinfo() */ - -static const struct net_device_ops netdev_ops = { - .ndo_open = elmc_open, - .ndo_stop = elmc_close, - .ndo_get_stats = elmc_get_stats, - .ndo_start_xmit = elmc_send_packet, - .ndo_tx_timeout = elmc_timeout, -#ifdef ELMC_MULTICAST - .ndo_set_rx_mode = set_multicast_list, -#endif - .ndo_change_mtu = eth_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -/*****************************************************************/ - -static int __init do_elmc_probe(struct net_device *dev) -{ - static int slot; - int base_addr = dev->base_addr; - int irq = dev->irq; - u_char status = 0; - u_char revision = 0; - int i = 0; - unsigned int size = 0; - int retval; - struct priv *pr = netdev_priv(dev); - - if (MCA_bus == 0) { - return -ENODEV; - } - /* search through the slots for the 3c523. */ - slot = mca_find_adapter(ELMC_MCA_ID, 0); - while (slot != -1) { - status = mca_read_stored_pos(slot, 2); - - dev->irq=irq_table[(status & ELMC_STATUS_IRQ_SELECT) >> 6]; - dev->base_addr=csr_table[(status & ELMC_STATUS_CSR_SELECT) >> 1]; - - /* - If we're trying to match a specified irq or IO address, - we'll reject a match unless it's what we're looking for. - Also reject it if the card is already in use. - */ - - if ((irq && irq != dev->irq) || - (base_addr && base_addr != dev->base_addr)) { - slot = mca_find_adapter(ELMC_MCA_ID, slot + 1); - continue; - } - if (!request_region(dev->base_addr, ELMC_IO_EXTENT, DRV_NAME)) { - slot = mca_find_adapter(ELMC_MCA_ID, slot + 1); - continue; - } - - /* found what we're looking for... */ - break; - } - - /* we didn't find any 3c523 in the slots we checked for */ - if (slot == MCA_NOTFOUND) - return (base_addr || irq) ? -ENXIO : -ENODEV; - - mca_set_adapter_name(slot, "3Com 3c523 Etherlink/MC"); - mca_set_adapter_procfn(slot, (MCA_ProcFn) elmc_getinfo, dev); - - /* if we get this far, adapter has been found - carry on */ - pr_info("%s: 3c523 adapter found in slot %d\n", dev->name, slot + 1); - - /* Now we extract configuration info from the card. - The 3c523 provides information in two of the POS registers, but - the second one is only needed if we want to tell the card what IRQ - to use. I suspect that whoever sets the thing up initially would - prefer we don't screw with those things. - - Note that we read the status info when we found the card... - - See 3c523.h for more details. - */ - - /* revision is stored in the first 4 bits of the revision register */ - revision = inb(dev->base_addr + ELMC_REVISION) & 0xf; - - /* according to docs, we read the interrupt and write it back to - the IRQ select register, since the POST might not configure the IRQ - properly. */ - switch (dev->irq) { - case 3: - mca_write_pos(slot, 3, 0x04); - break; - case 7: - mca_write_pos(slot, 3, 0x02); - break; - case 9: - mca_write_pos(slot, 3, 0x08); - break; - case 12: - mca_write_pos(slot, 3, 0x01); - break; - } - - pr->slot = slot; - - pr_info("%s: 3Com 3c523 Rev 0x%x at %#lx\n", dev->name, (int) revision, - dev->base_addr); - - /* Determine if we're using the on-board transceiver (i.e. coax) or - an external one. The information is pretty much useless, but I - guess it's worth brownie points. */ - dev->if_port = (status & ELMC_STATUS_DISABLE_THIN); - - /* The 3c523 has a 24K chunk of memory. The first 16K is the - shared memory, while the last 8K is for the EtherStart BIOS ROM. - Which we don't care much about here. We'll just tell Linux that - we're using 16K. MCA won't permit address space conflicts caused - by not mapping the other 8K. */ - dev->mem_start = shm_table[(status & ELMC_STATUS_MEMORY_SELECT) >> 3]; - - /* We're using MCA, so it's a given that the information about memory - size is correct. The Crynwr drivers do something like this. */ - - elmc_id_reset586(); /* seems like a good idea before checking it... */ - - size = 0x4000; /* check for 16K mem */ - if (!check586(dev, dev->mem_start, size)) { - pr_err("%s: memprobe, Can't find memory at 0x%lx!\n", dev->name, - dev->mem_start); - retval = -ENODEV; - goto err_out; - } - dev->mem_end = dev->mem_start + size; /* set mem_end showed by 'ifconfig' */ - - pr->memtop = isa_bus_to_virt(dev->mem_start) + size; - pr->base = (unsigned long) isa_bus_to_virt(dev->mem_start) + size - 0x01000000; - alloc586(dev); - - elmc_id_reset586(); /* make sure it doesn't generate spurious ints */ - - /* set number of receive-buffs according to memsize */ - pr->num_recv_buffs = NUM_RECV_BUFFS_16; - - /* dump all the assorted information */ - pr_info("%s: IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->name, - dev->irq, dev->if_port ? "ex" : "in", - dev->mem_start, dev->mem_end - 1); - - /* The hardware address for the 3c523 is stored in the first six - bytes of the IO address. */ - for (i = 0; i < 6; i++) - dev->dev_addr[i] = inb(dev->base_addr + i); - - pr_info("%s: hardware address %pM\n", - dev->name, dev->dev_addr); - - dev->netdev_ops = &netdev_ops; - dev->watchdog_timeo = HZ; - dev->ethtool_ops = &netdev_ethtool_ops; - - /* note that we haven't actually requested the IRQ from the kernel. - That gets done in elmc_open(). I'm not sure that's such a good idea, - but it works, so I'll go with it. */ - -#ifndef ELMC_MULTICAST - dev->flags&=~IFF_MULTICAST; /* Multicast doesn't work */ -#endif - - retval = register_netdev(dev); - if (retval) - goto err_out; - - return 0; -err_out: - mca_set_adapter_procfn(slot, NULL, NULL); - release_region(dev->base_addr, ELMC_IO_EXTENT); - return retval; -} - -#ifdef MODULE -static void cleanup_card(struct net_device *dev) -{ - mca_set_adapter_procfn(((struct priv *)netdev_priv(dev))->slot, - NULL, NULL); - release_region(dev->base_addr, ELMC_IO_EXTENT); -} -#else -struct net_device * __init elmc_probe(int unit) -{ - struct net_device *dev = alloc_etherdev(sizeof(struct priv)); - int err; - - if (!dev) - return ERR_PTR(-ENOMEM); - - sprintf(dev->name, "eth%d", unit); - netdev_boot_setup_check(dev); - - err = do_elmc_probe(dev); - if (err) - goto out; - return dev; -out: - free_netdev(dev); - return ERR_PTR(err); -} -#endif - -/********************************************** - * init the chip (elmc-interrupt should be disabled?!) - * needs a correct 'allocated' memory - */ - -static int init586(struct net_device *dev) -{ - void *ptr; - unsigned long s; - int i, result = 0; - struct priv *p = netdev_priv(dev); - volatile struct configure_cmd_struct *cfg_cmd; - volatile struct iasetup_cmd_struct *ias_cmd; - volatile struct tdr_cmd_struct *tdr_cmd; - volatile struct mcsetup_cmd_struct *mc_cmd; - struct netdev_hw_addr *ha; - int num_addrs = netdev_mc_count(dev); - - ptr = (void *) ((char *) p->scb + sizeof(struct scb_struct)); - - cfg_cmd = (struct configure_cmd_struct *) ptr; /* configure-command */ - cfg_cmd->cmd_status = 0; - cfg_cmd->cmd_cmd = CMD_CONFIGURE | CMD_LAST; - cfg_cmd->cmd_link = 0xffff; - - cfg_cmd->byte_cnt = 0x0a; /* number of cfg bytes */ - cfg_cmd->fifo = 0x08; /* fifo-limit (8=tx:32/rx:64) */ - cfg_cmd->sav_bf = 0x40; /* hold or discard bad recv frames (bit 7) */ - cfg_cmd->adr_len = 0x2e; /* addr_len |!src_insert |pre-len |loopback */ - cfg_cmd->priority = 0x00; - cfg_cmd->ifs = 0x60; - cfg_cmd->time_low = 0x00; - cfg_cmd->time_high = 0xf2; - cfg_cmd->promisc = 0; - if (dev->flags & (IFF_ALLMULTI | IFF_PROMISC)) - cfg_cmd->promisc = 1; - cfg_cmd->carr_coll = 0x00; - - p->scb->cbl_offset = make16(cfg_cmd); - - p->scb->cmd = CUC_START; /* cmd.-unit start */ - elmc_id_attn586(); - - s = jiffies; /* warning: only active with interrupts on !! */ - while (!(cfg_cmd->cmd_status & STAT_COMPL)) { - if (time_after(jiffies, s + 30*HZ/100)) - break; - } - - if ((cfg_cmd->cmd_status & (STAT_OK | STAT_COMPL)) != (STAT_COMPL | STAT_OK)) { - pr_warning("%s (elmc): configure command failed: %x\n", dev->name, cfg_cmd->cmd_status); - return 1; - } - /* - * individual address setup - */ - ias_cmd = (struct iasetup_cmd_struct *) ptr; - - ias_cmd->cmd_status = 0; - ias_cmd->cmd_cmd = CMD_IASETUP | CMD_LAST; - ias_cmd->cmd_link = 0xffff; - - memcpy((char *) &ias_cmd->iaddr, (char *) dev->dev_addr, ETH_ALEN); - - p->scb->cbl_offset = make16(ias_cmd); - - p->scb->cmd = CUC_START; /* cmd.-unit start */ - elmc_id_attn586(); - - s = jiffies; - while (!(ias_cmd->cmd_status & STAT_COMPL)) { - if (time_after(jiffies, s + 30*HZ/100)) - break; - } - - if ((ias_cmd->cmd_status & (STAT_OK | STAT_COMPL)) != (STAT_OK | STAT_COMPL)) { - pr_warning("%s (elmc): individual address setup command failed: %04x\n", - dev->name, ias_cmd->cmd_status); - return 1; - } - /* - * TDR, wire check .. e.g. no resistor e.t.c - */ - tdr_cmd = (struct tdr_cmd_struct *) ptr; - - tdr_cmd->cmd_status = 0; - tdr_cmd->cmd_cmd = CMD_TDR | CMD_LAST; - tdr_cmd->cmd_link = 0xffff; - tdr_cmd->status = 0; - - p->scb->cbl_offset = make16(tdr_cmd); - - p->scb->cmd = CUC_START; /* cmd.-unit start */ - elmc_attn586(); - - s = jiffies; - while (!(tdr_cmd->cmd_status & STAT_COMPL)) { - if (time_after(jiffies, s + 30*HZ/100)) { - pr_warning("%s: %d Problems while running the TDR.\n", dev->name, __LINE__); - result = 1; - break; - } - } - - if (!result) { - DELAY(2); /* wait for result */ - result = tdr_cmd->status; - - p->scb->cmd = p->scb->status & STAT_MASK; - elmc_id_attn586(); /* ack the interrupts */ - - if (result & TDR_LNK_OK) { - /* empty */ - } else if (result & TDR_XCVR_PRB) { - pr_warning("%s: TDR: Transceiver problem!\n", dev->name); - } else if (result & TDR_ET_OPN) { - pr_warning("%s: TDR: No correct termination %d clocks away.\n", dev->name, result & TDR_TIMEMASK); - } else if (result & TDR_ET_SRT) { - if (result & TDR_TIMEMASK) /* time == 0 -> strange :-) */ - pr_warning("%s: TDR: Detected a short circuit %d clocks away.\n", dev->name, result & TDR_TIMEMASK); - } else { - pr_warning("%s: TDR: Unknown status %04x\n", dev->name, result); - } - } - /* - * ack interrupts - */ - p->scb->cmd = p->scb->status & STAT_MASK; - elmc_id_attn586(); - - /* - * alloc nop/xmit-cmds - */ -#if (NUM_XMIT_BUFFS == 1) - for (i = 0; i < 2; i++) { - p->nop_cmds[i] = (struct nop_cmd_struct *) ptr; - p->nop_cmds[i]->cmd_cmd = CMD_NOP; - p->nop_cmds[i]->cmd_status = 0; - p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i])); - ptr = (char *) ptr + sizeof(struct nop_cmd_struct); - } - p->xmit_cmds[0] = (struct transmit_cmd_struct *) ptr; /* transmit cmd/buff 0 */ - ptr = (char *) ptr + sizeof(struct transmit_cmd_struct); -#else - for (i = 0; i < NUM_XMIT_BUFFS; i++) { - p->nop_cmds[i] = (struct nop_cmd_struct *) ptr; - p->nop_cmds[i]->cmd_cmd = CMD_NOP; - p->nop_cmds[i]->cmd_status = 0; - p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i])); - ptr = (char *) ptr + sizeof(struct nop_cmd_struct); - p->xmit_cmds[i] = (struct transmit_cmd_struct *) ptr; /*transmit cmd/buff 0 */ - ptr = (char *) ptr + sizeof(struct transmit_cmd_struct); - } -#endif - - ptr = alloc_rfa(dev, (void *) ptr); /* init receive-frame-area */ - - /* - * Multicast setup - */ - - if (num_addrs) { - /* I don't understand this: do we really need memory after the init? */ - int len = ((char *) p->iscp - (char *) ptr - 8) / 6; - if (len <= 0) { - pr_err("%s: Ooooops, no memory for MC-Setup!\n", dev->name); - } else { - if (len < num_addrs) { - num_addrs = len; - pr_warning("%s: Sorry, can only apply %d MC-Address(es).\n", - dev->name, num_addrs); - } - mc_cmd = (struct mcsetup_cmd_struct *) ptr; - mc_cmd->cmd_status = 0; - mc_cmd->cmd_cmd = CMD_MCSETUP | CMD_LAST; - mc_cmd->cmd_link = 0xffff; - mc_cmd->mc_cnt = num_addrs * 6; - i = 0; - netdev_for_each_mc_addr(ha, dev) - memcpy((char *) mc_cmd->mc_list[i++], - ha->addr, 6); - p->scb->cbl_offset = make16(mc_cmd); - p->scb->cmd = CUC_START; - elmc_id_attn586(); - s = jiffies; - while (!(mc_cmd->cmd_status & STAT_COMPL)) { - if (time_after(jiffies, s + 30*HZ/100)) - break; - } - if (!(mc_cmd->cmd_status & STAT_COMPL)) { - pr_warning("%s: Can't apply multicast-address-list.\n", dev->name); - } - } - } - /* - * alloc xmit-buffs / init xmit_cmds - */ - for (i = 0; i < NUM_XMIT_BUFFS; i++) { - p->xmit_cbuffs[i] = (char *) ptr; /* char-buffs */ - ptr = (char *) ptr + XMIT_BUFF_SIZE; - p->xmit_buffs[i] = (struct tbd_struct *) ptr; /* TBD */ - ptr = (char *) ptr + sizeof(struct tbd_struct); - if ((void *) ptr > (void *) p->iscp) { - pr_err("%s: not enough shared-mem for your configuration!\n", dev->name); - return 1; - } - memset((char *) (p->xmit_cmds[i]), 0, sizeof(struct transmit_cmd_struct)); - memset((char *) (p->xmit_buffs[i]), 0, sizeof(struct tbd_struct)); - p->xmit_cmds[i]->cmd_status = STAT_COMPL; - p->xmit_cmds[i]->cmd_cmd = CMD_XMIT | CMD_INT; - p->xmit_cmds[i]->tbd_offset = make16((p->xmit_buffs[i])); - p->xmit_buffs[i]->next = 0xffff; - p->xmit_buffs[i]->buffer = make24((p->xmit_cbuffs[i])); - } - - p->xmit_count = 0; - p->xmit_last = 0; -#ifndef NO_NOPCOMMANDS - p->nop_point = 0; -#endif - - /* - * 'start transmitter' (nop-loop) - */ -#ifndef NO_NOPCOMMANDS - p->scb->cbl_offset = make16(p->nop_cmds[0]); - p->scb->cmd = CUC_START; - elmc_id_attn586(); - WAIT_4_SCB_CMD(); -#else - p->xmit_cmds[0]->cmd_link = 0xffff; - p->xmit_cmds[0]->cmd_cmd = CMD_XMIT | CMD_LAST | CMD_INT; -#endif - - return 0; -} - -/****************************************************** - * This is a helper routine for elmc_rnr_int() and init586(). - * It sets up the Receive Frame Area (RFA). - */ - -static void *alloc_rfa(struct net_device *dev, void *ptr) -{ - volatile struct rfd_struct *rfd = (struct rfd_struct *) ptr; - volatile struct rbd_struct *rbd; - int i; - struct priv *p = netdev_priv(dev); - - memset((char *) rfd, 0, sizeof(struct rfd_struct) * p->num_recv_buffs); - p->rfd_first = rfd; - - for (i = 0; i < p->num_recv_buffs; i++) { - rfd[i].next = make16(rfd + (i + 1) % p->num_recv_buffs); - } - rfd[p->num_recv_buffs - 1].last = RFD_SUSP; /* RU suspend */ - - ptr = (void *) (rfd + p->num_recv_buffs); - - rbd = (struct rbd_struct *) ptr; - ptr = (void *) (rbd + p->num_recv_buffs); - - /* clr descriptors */ - memset((char *) rbd, 0, sizeof(struct rbd_struct) * p->num_recv_buffs); - - for (i = 0; i < p->num_recv_buffs; i++) { - rbd[i].next = make16((rbd + (i + 1) % p->num_recv_buffs)); - rbd[i].size = RECV_BUFF_SIZE; - rbd[i].buffer = make24(ptr); - ptr = (char *) ptr + RECV_BUFF_SIZE; - } - - p->rfd_top = p->rfd_first; - p->rfd_last = p->rfd_first + p->num_recv_buffs - 1; - - p->scb->rfa_offset = make16(p->rfd_first); - p->rfd_first->rbd_offset = make16(rbd); - - return ptr; -} - - -/************************************************** - * Interrupt Handler ... - */ - -static irqreturn_t -elmc_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - unsigned short stat; - struct priv *p; - - if (!netif_running(dev)) { - /* The 3c523 has this habit of generating interrupts during the - reset. I'm not sure if the ni52 has this same problem, but it's - really annoying if we haven't finished initializing it. I was - hoping all the elmc_id_* commands would disable this, but I - might have missed a few. */ - - elmc_id_attn586(); /* ack inter. and disable any more */ - return IRQ_HANDLED; - } else if (!(ELMC_CTRL_INT & inb(dev->base_addr + ELMC_CTRL))) { - /* wasn't this device */ - return IRQ_NONE; - } - /* reading ELMC_CTRL also clears the INT bit. */ - - p = netdev_priv(dev); - - while ((stat = p->scb->status & STAT_MASK)) - { - p->scb->cmd = stat; - elmc_attn586(); /* ack inter. */ - - if (stat & STAT_CX) { - /* command with I-bit set complete */ - elmc_xmt_int(dev); - } - if (stat & STAT_FR) { - /* received a frame */ - elmc_rcv_int(dev); - } -#ifndef NO_NOPCOMMANDS - if (stat & STAT_CNA) { - /* CU went 'not ready' */ - if (netif_running(dev)) { - pr_warning("%s: oops! CU has left active state. stat: %04x/%04x.\n", - dev->name, (int) stat, (int) p->scb->status); - } - } -#endif - - if (stat & STAT_RNR) { - /* RU went 'not ready' */ - - if (p->scb->status & RU_SUSPEND) { - /* special case: RU_SUSPEND */ - - WAIT_4_SCB_CMD(); - p->scb->cmd = RUC_RESUME; - elmc_attn586(); - } else { - pr_warning("%s: Receiver-Unit went 'NOT READY': %04x/%04x.\n", - dev->name, (int) stat, (int) p->scb->status); - elmc_rnr_int(dev); - } - } - WAIT_4_SCB_CMD(); /* wait for ack. (elmc_xmt_int can be faster than ack!!) */ - if (p->scb->cmd) { /* timed out? */ - break; - } - } - return IRQ_HANDLED; -} - -/******************************************************* - * receive-interrupt - */ - -static void elmc_rcv_int(struct net_device *dev) -{ - int status; - unsigned short totlen; - struct sk_buff *skb; - struct rbd_struct *rbd; - struct priv *p = netdev_priv(dev); - - for (; (status = p->rfd_top->status) & STAT_COMPL;) { - rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset); - - if (status & STAT_OK) { /* frame received without error? */ - if ((totlen = rbd->status) & RBD_LAST) { /* the first and the last buffer? */ - totlen &= RBD_MASK; /* length of this frame */ - rbd->status = 0; - skb = netdev_alloc_skb(dev, totlen + 2); - if (skb != NULL) { - skb_reserve(skb, 2); /* 16 byte alignment */ - skb_put(skb,totlen); - skb_copy_to_linear_data(skb, (char *) p->base+(unsigned long) rbd->buffer,totlen); - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes += totlen; - } else { - dev->stats.rx_dropped++; - } - } else { - pr_warning("%s: received oversized frame.\n", dev->name); - dev->stats.rx_dropped++; - } - } else { /* frame !(ok), only with 'save-bad-frames' */ - pr_warning("%s: oops! rfd-error-status: %04x\n", dev->name, status); - dev->stats.rx_errors++; - } - p->rfd_top->status = 0; - p->rfd_top->last = RFD_SUSP; - p->rfd_last->last = 0; /* delete RU_SUSP */ - p->rfd_last = p->rfd_top; - p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next); /* step to next RFD */ - } -} - -/********************************************************** - * handle 'Receiver went not ready'. - */ - -static void elmc_rnr_int(struct net_device *dev) -{ - struct priv *p = netdev_priv(dev); - - dev->stats.rx_errors++; - - WAIT_4_SCB_CMD(); /* wait for the last cmd */ - p->scb->cmd = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */ - elmc_attn586(); - WAIT_4_SCB_CMD(); /* wait for accept cmd. */ - - alloc_rfa(dev, (char *) p->rfd_first); - startrecv586(dev); /* restart RU */ - - pr_warning("%s: Receive-Unit restarted. Status: %04x\n", dev->name, p->scb->status); - -} - -/********************************************************** - * handle xmit - interrupt - */ - -static void elmc_xmt_int(struct net_device *dev) -{ - int status; - struct priv *p = netdev_priv(dev); - - status = p->xmit_cmds[p->xmit_last]->cmd_status; - if (!(status & STAT_COMPL)) { - pr_warning("%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name); - } - if (status & STAT_OK) { - dev->stats.tx_packets++; - dev->stats.collisions += (status & TCMD_MAXCOLLMASK); - } else { - dev->stats.tx_errors++; - if (status & TCMD_LATECOLL) { - pr_warning("%s: late collision detected.\n", dev->name); - dev->stats.collisions++; - } else if (status & TCMD_NOCARRIER) { - dev->stats.tx_carrier_errors++; - pr_warning("%s: no carrier detected.\n", dev->name); - } else if (status & TCMD_LOSTCTS) { - pr_warning("%s: loss of CTS detected.\n", dev->name); - } else if (status & TCMD_UNDERRUN) { - dev->stats.tx_fifo_errors++; - pr_warning("%s: DMA underrun detected.\n", dev->name); - } else if (status & TCMD_MAXCOLL) { - pr_warning("%s: Max. collisions exceeded.\n", dev->name); - dev->stats.collisions += 16; - } - } - -#if (NUM_XMIT_BUFFS != 1) - if ((++p->xmit_last) == NUM_XMIT_BUFFS) { - p->xmit_last = 0; - } -#endif - - netif_wake_queue(dev); -} - -/*********************************************************** - * (re)start the receiver - */ - -static void startrecv586(struct net_device *dev) -{ - struct priv *p = netdev_priv(dev); - - p->scb->rfa_offset = make16(p->rfd_first); - p->scb->cmd = RUC_START; - elmc_attn586(); /* start cmd. */ - WAIT_4_SCB_CMD(); /* wait for accept cmd. (no timeout!!) */ -} - -/****************************************************** - * timeout - */ - -static void elmc_timeout(struct net_device *dev) -{ - struct priv *p = netdev_priv(dev); - /* COMMAND-UNIT active? */ - if (p->scb->status & CU_ACTIVE) { - pr_debug("%s: strange ... timeout with CU active?!?\n", dev->name); - pr_debug("%s: X0: %04x N0: %04x N1: %04x %d\n", dev->name, - (int)p->xmit_cmds[0]->cmd_status, - (int)p->nop_cmds[0]->cmd_status, - (int)p->nop_cmds[1]->cmd_status, (int)p->nop_point); - p->scb->cmd = CUC_ABORT; - elmc_attn586(); - WAIT_4_SCB_CMD(); - p->scb->cbl_offset = make16(p->nop_cmds[p->nop_point]); - p->scb->cmd = CUC_START; - elmc_attn586(); - WAIT_4_SCB_CMD(); - netif_wake_queue(dev); - } else { - pr_debug("%s: xmitter timed out, try to restart! stat: %04x\n", - dev->name, p->scb->status); - pr_debug("%s: command-stats: %04x %04x\n", dev->name, - p->xmit_cmds[0]->cmd_status, p->xmit_cmds[1]->cmd_status); - elmc_close(dev); - elmc_open(dev); - } -} - -/****************************************************** - * send frame - */ - -static netdev_tx_t elmc_send_packet(struct sk_buff *skb, struct net_device *dev) -{ - int len; - int i; -#ifndef NO_NOPCOMMANDS - int next_nop; -#endif - struct priv *p = netdev_priv(dev); - - netif_stop_queue(dev); - - len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; - - if (len != skb->len) - memset((char *) p->xmit_cbuffs[p->xmit_count], 0, ETH_ZLEN); - skb_copy_from_linear_data(skb, (char *) p->xmit_cbuffs[p->xmit_count], skb->len); - -#if (NUM_XMIT_BUFFS == 1) -#ifdef NO_NOPCOMMANDS - p->xmit_buffs[0]->size = TBD_LAST | len; - for (i = 0; i < 16; i++) { - p->scb->cbl_offset = make16(p->xmit_cmds[0]); - p->scb->cmd = CUC_START; - p->xmit_cmds[0]->cmd_status = 0; - elmc_attn586(); - if (!i) { - dev_kfree_skb(skb); - } - WAIT_4_SCB_CMD(); - if ((p->scb->status & CU_ACTIVE)) { /* test it, because CU sometimes doesn't start immediately */ - break; - } - if (p->xmit_cmds[0]->cmd_status) { - break; - } - if (i == 15) { - pr_warning("%s: Can't start transmit-command.\n", dev->name); - } - } -#else - next_nop = (p->nop_point + 1) & 0x1; - p->xmit_buffs[0]->size = TBD_LAST | len; - - p->xmit_cmds[0]->cmd_link = p->nop_cmds[next_nop]->cmd_link - = make16((p->nop_cmds[next_nop])); - p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0; - - p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0])); - p->nop_point = next_nop; - dev_kfree_skb(skb); -#endif -#else - p->xmit_buffs[p->xmit_count]->size = TBD_LAST | len; - if ((next_nop = p->xmit_count + 1) == NUM_XMIT_BUFFS) { - next_nop = 0; - } - p->xmit_cmds[p->xmit_count]->cmd_status = 0; - p->xmit_cmds[p->xmit_count]->cmd_link = p->nop_cmds[next_nop]->cmd_link - = make16((p->nop_cmds[next_nop])); - p->nop_cmds[next_nop]->cmd_status = 0; - p->nop_cmds[p->xmit_count]->cmd_link = make16((p->xmit_cmds[p->xmit_count])); - p->xmit_count = next_nop; - if (p->xmit_count != p->xmit_last) - netif_wake_queue(dev); - dev_kfree_skb(skb); -#endif - return NETDEV_TX_OK; -} - -/******************************************* - * Someone wanna have the statistics - */ - -static struct net_device_stats *elmc_get_stats(struct net_device *dev) -{ - struct priv *p = netdev_priv(dev); - unsigned short crc, aln, rsc, ovrn; - - crc = p->scb->crc_errs; /* get error-statistic from the ni82586 */ - p->scb->crc_errs -= crc; - aln = p->scb->aln_errs; - p->scb->aln_errs -= aln; - rsc = p->scb->rsc_errs; - p->scb->rsc_errs -= rsc; - ovrn = p->scb->ovrn_errs; - p->scb->ovrn_errs -= ovrn; - - dev->stats.rx_crc_errors += crc; - dev->stats.rx_fifo_errors += ovrn; - dev->stats.rx_frame_errors += aln; - dev->stats.rx_dropped += rsc; - - return &dev->stats; -} - -/******************************************************** - * Set MC list .. - */ - -#ifdef ELMC_MULTICAST -static void set_multicast_list(struct net_device *dev) -{ - if (!dev->start) { - /* without a running interface, promiscuous doesn't work */ - return; - } - dev->start = 0; - alloc586(dev); - init586(dev); - startrecv586(dev); - dev->start = 1; -} -#endif - -static void netdev_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - strcpy(info->driver, DRV_NAME); - strcpy(info->version, DRV_VERSION); - sprintf(info->bus_info, "MCA 0x%lx", dev->base_addr); -} - -static const struct ethtool_ops netdev_ethtool_ops = { - .get_drvinfo = netdev_get_drvinfo, -}; - -#ifdef MODULE - -/* Increase if needed ;) */ -#define MAX_3C523_CARDS 4 - -static struct net_device *dev_elmc[MAX_3C523_CARDS]; -static int irq[MAX_3C523_CARDS]; -static int io[MAX_3C523_CARDS]; -module_param_array(irq, int, NULL, 0); -module_param_array(io, int, NULL, 0); -MODULE_PARM_DESC(io, "EtherLink/MC I/O base address(es)"); -MODULE_PARM_DESC(irq, "EtherLink/MC IRQ number(s)"); -MODULE_LICENSE("GPL"); - -int __init init_module(void) -{ - int this_dev,found = 0; - - /* Loop until we either can't find any more cards, or we have MAX_3C523_CARDS */ - for(this_dev=0; this_devirq=irq[this_dev]; - dev->base_addr=io[this_dev]; - if (do_elmc_probe(dev) == 0) { - dev_elmc[this_dev] = dev; - found++; - continue; - } - free_netdev(dev); - if (io[this_dev]==0) - break; - pr_warning("3c523.c: No 3c523 card found at io=%#x\n",io[this_dev]); - } - - if(found==0) { - if (io[0]==0) - pr_notice("3c523.c: No 3c523 cards found\n"); - return -ENXIO; - } else return 0; -} - -void __exit cleanup_module(void) -{ - int this_dev; - for (this_dev=0; this_dev - * Heavily modified by Richard Procter - * - * Based on skeleton.c written 1993-94 by Donald Becker and ne2.c - * (for the MCA stuff) written by Wim Dumon. - * - * Thanks to 3Com for making this possible by providing me with the - * documentation. - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#define DRV_NAME "3c527" -#define DRV_VERSION "0.7-SMP" -#define DRV_RELDATE "2003/09/21" - -static const char *version = -DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Richard Procter \n"; - -/** - * DOC: Traps for the unwary - * - * The diagram (Figure 1-1) and the POS summary disagree with the - * "Interrupt Level" section in the manual. - * - * The manual contradicts itself when describing the minimum number - * buffers in the 'configure lists' command. - * My card accepts a buffer config of 4/4. - * - * Setting the SAV BP bit does not save bad packets, but - * only enables RX on-card stats collection. - * - * The documentation in places seems to miss things. In actual fact - * I've always eventually found everything is documented, it just - * requires careful study. - * - * DOC: Theory Of Operation - * - * The 3com 3c527 is a 32bit MCA bus mastering adapter with a large - * amount of on board intelligence that housekeeps a somewhat dumber - * Intel NIC. For performance we want to keep the transmit queue deep - * as the card can transmit packets while fetching others from main - * memory by bus master DMA. Transmission and reception are driven by - * circular buffer queues. - * - * The mailboxes can be used for controlling how the card traverses - * its buffer rings, but are used only for initial setup in this - * implementation. The exec mailbox allows a variety of commands to - * be executed. Each command must complete before the next is - * executed. Primarily we use the exec mailbox for controlling the - * multicast lists. We have to do a certain amount of interesting - * hoop jumping as the multicast list changes can occur in interrupt - * state when the card has an exec command pending. We defer such - * events until the command completion interrupt. - * - * A copy break scheme (taken from 3c59x.c) is employed whereby - * received frames exceeding a configurable length are passed - * directly to the higher networking layers without incuring a copy, - * in what amounts to a time/space trade-off. - * - * The card also keeps a large amount of statistical information - * on-board. In a perfect world, these could be used safely at no - * cost. However, lacking information to the contrary, processing - * them without races would involve so much extra complexity as to - * make it unworthwhile to do so. In the end, a hybrid SW/HW - * implementation was made necessary --- see mc32_update_stats(). - * - * DOC: Notes - * - * It should be possible to use two or more cards, but at this stage - * only by loading two copies of the same module. - * - * The on-board 82586 NIC has trouble receiving multiple - * back-to-back frames and so is likely to drop packets from fast - * senders. -**/ - -#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 "3c527.h" - -MODULE_LICENSE("GPL"); - -/* - * The name of the card. Is used for messages and in the requests for - * io regions, irqs and dma channels - */ -static const char* cardname = DRV_NAME; - -/* use 0 for production, 1 for verification, >2 for debug */ -#ifndef NET_DEBUG -#define NET_DEBUG 2 -#endif - -static unsigned int mc32_debug = NET_DEBUG; - -/* The number of low I/O ports used by the ethercard. */ -#define MC32_IO_EXTENT 8 - -/* As implemented, values must be a power-of-2 -- 4/8/16/32 */ -#define TX_RING_LEN 32 /* Typically the card supports 37 */ -#define RX_RING_LEN 8 /* " " " */ - -/* Copy break point, see above for details. - * Setting to > 1512 effectively disables this feature. */ -#define RX_COPYBREAK 200 /* Value from 3c59x.c */ - -/* Issue the 82586 workaround command - this is for "busy lans", but - * basically means for all lans now days - has a performance (latency) - * cost, but best set. */ -static const int WORKAROUND_82586=1; - -/* Pointers to buffers and their on-card records */ -struct mc32_ring_desc -{ - volatile struct skb_header *p; - struct sk_buff *skb; -}; - -/* Information that needs to be kept for each board. */ -struct mc32_local -{ - int slot; - - u32 base; - volatile struct mc32_mailbox *rx_box; - volatile struct mc32_mailbox *tx_box; - volatile struct mc32_mailbox *exec_box; - volatile struct mc32_stats *stats; /* Start of on-card statistics */ - u16 tx_chain; /* Transmit list start offset */ - u16 rx_chain; /* Receive list start offset */ - u16 tx_len; /* Transmit list count */ - u16 rx_len; /* Receive list count */ - - u16 xceiver_desired_state; /* HALTED or RUNNING */ - u16 cmd_nonblocking; /* Thread is uninterested in command result */ - u16 mc_reload_wait; /* A multicast load request is pending */ - u32 mc_list_valid; /* True when the mclist is set */ - - struct mc32_ring_desc tx_ring[TX_RING_LEN]; /* Host Transmit ring */ - struct mc32_ring_desc rx_ring[RX_RING_LEN]; /* Host Receive ring */ - - atomic_t tx_count; /* buffers left */ - atomic_t tx_ring_head; /* index to tx en-queue end */ - u16 tx_ring_tail; /* index to tx de-queue end */ - - u16 rx_ring_tail; /* index to rx de-queue end */ - - struct semaphore cmd_mutex; /* Serialises issuing of execute commands */ - struct completion execution_cmd; /* Card has completed an execute command */ - struct completion xceiver_cmd; /* Card has completed a tx or rx command */ -}; - -/* The station (ethernet) address prefix, used for a sanity check. */ -#define SA_ADDR0 0x02 -#define SA_ADDR1 0x60 -#define SA_ADDR2 0xAC - -struct mca_adapters_t { - unsigned int id; - char *name; -}; - -static const struct mca_adapters_t mc32_adapters[] = { - { 0x0041, "3COM EtherLink MC/32" }, - { 0x8EF5, "IBM High Performance Lan Adapter" }, - { 0x0000, NULL } -}; - - -/* Macros for ring index manipulations */ -static inline u16 next_rx(u16 rx) { return (rx+1)&(RX_RING_LEN-1); }; -static inline u16 prev_rx(u16 rx) { return (rx-1)&(RX_RING_LEN-1); }; - -static inline u16 next_tx(u16 tx) { return (tx+1)&(TX_RING_LEN-1); }; - - -/* Index to functions, as function prototypes. */ -static int mc32_probe1(struct net_device *dev, int ioaddr); -static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len); -static int mc32_open(struct net_device *dev); -static void mc32_timeout(struct net_device *dev); -static netdev_tx_t mc32_send_packet(struct sk_buff *skb, - struct net_device *dev); -static irqreturn_t mc32_interrupt(int irq, void *dev_id); -static int mc32_close(struct net_device *dev); -static struct net_device_stats *mc32_get_stats(struct net_device *dev); -static void mc32_set_multicast_list(struct net_device *dev); -static void mc32_reset_multicast_list(struct net_device *dev); -static const struct ethtool_ops netdev_ethtool_ops; - -static void cleanup_card(struct net_device *dev) -{ - struct mc32_local *lp = netdev_priv(dev); - unsigned slot = lp->slot; - mca_mark_as_unused(slot); - mca_set_adapter_name(slot, NULL); - free_irq(dev->irq, dev); - release_region(dev->base_addr, MC32_IO_EXTENT); -} - -/** - * mc32_probe - Search for supported boards - * @unit: interface number to use - * - * Because MCA bus is a real bus and we can scan for cards we could do a - * single scan for all boards here. Right now we use the passed in device - * structure and scan for only one board. This needs fixing for modules - * in particular. - */ - -struct net_device *__init mc32_probe(int unit) -{ - struct net_device *dev = alloc_etherdev(sizeof(struct mc32_local)); - static int current_mca_slot = -1; - int i; - int err; - - if (!dev) - return ERR_PTR(-ENOMEM); - - if (unit >= 0) - sprintf(dev->name, "eth%d", unit); - - /* Do not check any supplied i/o locations. - POS registers usually don't fail :) */ - - /* MCA cards have POS registers. - Autodetecting MCA cards is extremely simple. - Just search for the card. */ - - for(i = 0; (mc32_adapters[i].name != NULL); i++) { - current_mca_slot = - mca_find_unused_adapter(mc32_adapters[i].id, 0); - - if(current_mca_slot != MCA_NOTFOUND) { - if(!mc32_probe1(dev, current_mca_slot)) - { - mca_set_adapter_name(current_mca_slot, - mc32_adapters[i].name); - mca_mark_as_used(current_mca_slot); - err = register_netdev(dev); - if (err) { - cleanup_card(dev); - free_netdev(dev); - dev = ERR_PTR(err); - } - return dev; - } - - } - } - free_netdev(dev); - return ERR_PTR(-ENODEV); -} - -static const struct net_device_ops netdev_ops = { - .ndo_open = mc32_open, - .ndo_stop = mc32_close, - .ndo_start_xmit = mc32_send_packet, - .ndo_get_stats = mc32_get_stats, - .ndo_set_rx_mode = mc32_set_multicast_list, - .ndo_tx_timeout = mc32_timeout, - .ndo_change_mtu = eth_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -/** - * mc32_probe1 - Check a given slot for a board and test the card - * @dev: Device structure to fill in - * @slot: The MCA bus slot being used by this card - * - * Decode the slot data and configure the card structures. Having done this we - * can reset the card and configure it. The card does a full self test cycle - * in firmware so we have to wait for it to return and post us either a - * failure case or some addresses we use to find the board internals. - */ - -static int __init mc32_probe1(struct net_device *dev, int slot) -{ - static unsigned version_printed; - int i, err; - u8 POS; - u32 base; - struct mc32_local *lp = netdev_priv(dev); - static const u16 mca_io_bases[] = { - 0x7280,0x7290, - 0x7680,0x7690, - 0x7A80,0x7A90, - 0x7E80,0x7E90 - }; - static const u32 mca_mem_bases[] = { - 0x00C0000, - 0x00C4000, - 0x00C8000, - 0x00CC000, - 0x00D0000, - 0x00D4000, - 0x00D8000, - 0x00DC000 - }; - static const char * const failures[] = { - "Processor instruction", - "Processor data bus", - "Processor data bus", - "Processor data bus", - "Adapter bus", - "ROM checksum", - "Base RAM", - "Extended RAM", - "82586 internal loopback", - "82586 initialisation failure", - "Adapter list configuration error" - }; - - /* Time to play MCA games */ - - if (mc32_debug && version_printed++ == 0) - pr_debug("%s", version); - - pr_info("%s: %s found in slot %d: ", dev->name, cardname, slot); - - POS = mca_read_stored_pos(slot, 2); - - if(!(POS&1)) - { - pr_cont("disabled.\n"); - return -ENODEV; - } - - /* Fill in the 'dev' fields. */ - dev->base_addr = mca_io_bases[(POS>>1)&7]; - dev->mem_start = mca_mem_bases[(POS>>4)&7]; - - POS = mca_read_stored_pos(slot, 4); - if(!(POS&1)) - { - pr_cont("memory window disabled.\n"); - return -ENODEV; - } - - POS = mca_read_stored_pos(slot, 5); - - i=(POS>>4)&3; - if(i==3) - { - pr_cont("invalid memory window.\n"); - return -ENODEV; - } - - i*=16384; - i+=16384; - - dev->mem_end=dev->mem_start + i; - - dev->irq = ((POS>>2)&3)+9; - - if(!request_region(dev->base_addr, MC32_IO_EXTENT, cardname)) - { - pr_cont("io 0x%3lX, which is busy.\n", dev->base_addr); - return -EBUSY; - } - - pr_cont("io 0x%3lX irq %d mem 0x%lX (%dK)\n", - dev->base_addr, dev->irq, dev->mem_start, i/1024); - - - /* We ought to set the cache line size here.. */ - - - /* - * Go PROM browsing - */ - - /* Retrieve and print the ethernet address. */ - for (i = 0; i < 6; i++) - { - mca_write_pos(slot, 6, i+12); - mca_write_pos(slot, 7, 0); - - dev->dev_addr[i] = mca_read_pos(slot,3); - } - - pr_info("%s: Address %pM ", dev->name, dev->dev_addr); - - mca_write_pos(slot, 6, 0); - mca_write_pos(slot, 7, 0); - - POS = mca_read_stored_pos(slot, 4); - - if(POS&2) - pr_cont(": BNC port selected.\n"); - else - pr_cont(": AUI port selected.\n"); - - POS=inb(dev->base_addr+HOST_CTRL); - POS|=HOST_CTRL_ATTN|HOST_CTRL_RESET; - POS&=~HOST_CTRL_INTE; - outb(POS, dev->base_addr+HOST_CTRL); - /* Reset adapter */ - udelay(100); - /* Reset off */ - POS&=~(HOST_CTRL_ATTN|HOST_CTRL_RESET); - outb(POS, dev->base_addr+HOST_CTRL); - - udelay(300); - - /* - * Grab the IRQ - */ - - err = request_irq(dev->irq, mc32_interrupt, IRQF_SHARED, DRV_NAME, dev); - if (err) { - release_region(dev->base_addr, MC32_IO_EXTENT); - pr_err("%s: unable to get IRQ %d.\n", DRV_NAME, dev->irq); - goto err_exit_ports; - } - - memset(lp, 0, sizeof(struct mc32_local)); - lp->slot = slot; - - i=0; - - base = inb(dev->base_addr); - - while(base == 0xFF) - { - i++; - if(i == 1000) - { - pr_err("%s: failed to boot adapter.\n", dev->name); - err = -ENODEV; - goto err_exit_irq; - } - udelay(1000); - if(inb(dev->base_addr+2)&(1<<5)) - base = inb(dev->base_addr); - } - - if(base>0) - { - if(base < 0x0C) - pr_err("%s: %s%s.\n", dev->name, failures[base-1], - base<0x0A?" test failure":""); - else - pr_err("%s: unknown failure %d.\n", dev->name, base); - err = -ENODEV; - goto err_exit_irq; - } - - base=0; - for(i=0;i<4;i++) - { - int n=0; - - while(!(inb(dev->base_addr+2)&(1<<5))) - { - n++; - udelay(50); - if(n>100) - { - pr_err("%s: mailbox read fail (%d).\n", dev->name, i); - err = -ENODEV; - goto err_exit_irq; - } - } - - base|=(inb(dev->base_addr)<<(8*i)); - } - - lp->exec_box=isa_bus_to_virt(dev->mem_start+base); - - base=lp->exec_box->data[1]<<16|lp->exec_box->data[0]; - - lp->base = dev->mem_start+base; - - lp->rx_box=isa_bus_to_virt(lp->base + lp->exec_box->data[2]); - lp->tx_box=isa_bus_to_virt(lp->base + lp->exec_box->data[3]); - - lp->stats = isa_bus_to_virt(lp->base + lp->exec_box->data[5]); - - /* - * Descriptor chains (card relative) - */ - - lp->tx_chain = lp->exec_box->data[8]; /* Transmit list start offset */ - lp->rx_chain = lp->exec_box->data[10]; /* Receive list start offset */ - lp->tx_len = lp->exec_box->data[9]; /* Transmit list count */ - lp->rx_len = lp->exec_box->data[11]; /* Receive list count */ - - sema_init(&lp->cmd_mutex, 0); - init_completion(&lp->execution_cmd); - init_completion(&lp->xceiver_cmd); - - pr_info("%s: Firmware Rev %d. %d RX buffers, %d TX buffers. Base of 0x%08X.\n", - dev->name, lp->exec_box->data[12], lp->rx_len, lp->tx_len, lp->base); - - dev->netdev_ops = &netdev_ops; - dev->watchdog_timeo = HZ*5; /* Board does all the work */ - dev->ethtool_ops = &netdev_ethtool_ops; - - return 0; - -err_exit_irq: - free_irq(dev->irq, dev); -err_exit_ports: - release_region(dev->base_addr, MC32_IO_EXTENT); - return err; -} - - -/** - * mc32_ready_poll - wait until we can feed it a command - * @dev: The device to wait for - * - * Wait until the card becomes ready to accept a command via the - * command register. This tells us nothing about the completion - * status of any pending commands and takes very little time at all. - */ - -static inline void mc32_ready_poll(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); -} - - -/** - * mc32_command_nowait - send a command non blocking - * @dev: The 3c527 to issue the command to - * @cmd: The command word to write to the mailbox - * @data: A data block if the command expects one - * @len: Length of the data block - * - * Send a command from interrupt state. If there is a command - * currently being executed then we return an error of -1. It - * simply isn't viable to wait around as commands may be - * slow. This can theoretically be starved on SMP, but it's hard - * to see a realistic situation. We do not wait for the command - * to complete --- we rely on the interrupt handler to tidy up - * after us. - */ - -static int mc32_command_nowait(struct net_device *dev, u16 cmd, void *data, int len) -{ - struct mc32_local *lp = netdev_priv(dev); - int ioaddr = dev->base_addr; - int ret = -1; - - if (down_trylock(&lp->cmd_mutex) == 0) - { - lp->cmd_nonblocking=1; - lp->exec_box->mbox=0; - lp->exec_box->mbox=cmd; - memcpy((void *)lp->exec_box->data, data, len); - barrier(); /* the memcpy forgot the volatile so be sure */ - - /* Send the command */ - mc32_ready_poll(dev); - outb(1<<6, ioaddr+HOST_CMD); - - ret = 0; - - /* Interrupt handler will signal mutex on completion */ - } - - return ret; -} - - -/** - * mc32_command - send a command and sleep until completion - * @dev: The 3c527 card to issue the command to - * @cmd: The command word to write to the mailbox - * @data: A data block if the command expects one - * @len: Length of the data block - * - * Sends exec commands in a user context. This permits us to wait around - * for the replies and also to wait for the command buffer to complete - * from a previous command before we execute our command. After our - * command completes we will attempt any pending multicast reload - * we blocked off by hogging the exec buffer. - * - * You feed the card a command, you wait, it interrupts you get a - * reply. All well and good. The complication arises because you use - * commands for filter list changes which come in at bh level from things - * like IPV6 group stuff. - */ - -static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len) -{ - struct mc32_local *lp = netdev_priv(dev); - int ioaddr = dev->base_addr; - int ret = 0; - - down(&lp->cmd_mutex); - - /* - * My Turn - */ - - lp->cmd_nonblocking=0; - lp->exec_box->mbox=0; - lp->exec_box->mbox=cmd; - memcpy((void *)lp->exec_box->data, data, len); - barrier(); /* the memcpy forgot the volatile so be sure */ - - mc32_ready_poll(dev); - outb(1<<6, ioaddr+HOST_CMD); - - wait_for_completion(&lp->execution_cmd); - - if(lp->exec_box->mbox&(1<<13)) - ret = -1; - - up(&lp->cmd_mutex); - - /* - * A multicast set got blocked - try it now - */ - - if(lp->mc_reload_wait) - { - mc32_reset_multicast_list(dev); - } - - return ret; -} - - -/** - * mc32_start_transceiver - tell board to restart tx/rx - * @dev: The 3c527 card to issue the command to - * - * This may be called from the interrupt state, where it is used - * to restart the rx ring if the card runs out of rx buffers. - * - * We must first check if it's ok to (re)start the transceiver. See - * mc32_close for details. - */ - -static void mc32_start_transceiver(struct net_device *dev) { - - struct mc32_local *lp = netdev_priv(dev); - int ioaddr = dev->base_addr; - - /* Ignore RX overflow on device closure */ - if (lp->xceiver_desired_state==HALTED) - return; - - /* Give the card the offset to the post-EOL-bit RX descriptor */ - mc32_ready_poll(dev); - lp->rx_box->mbox=0; - lp->rx_box->data[0]=lp->rx_ring[prev_rx(lp->rx_ring_tail)].p->next; - outb(HOST_CMD_START_RX, ioaddr+HOST_CMD); - - mc32_ready_poll(dev); - lp->tx_box->mbox=0; - outb(HOST_CMD_RESTRT_TX, ioaddr+HOST_CMD); /* card ignores this on RX restart */ - - /* We are not interrupted on start completion */ -} - - -/** - * mc32_halt_transceiver - tell board to stop tx/rx - * @dev: The 3c527 card to issue the command to - * - * We issue the commands to halt the card's transceiver. In fact, - * after some experimenting we now simply tell the card to - * suspend. When issuing aborts occasionally odd things happened. - * - * We then sleep until the card has notified us that both rx and - * tx have been suspended. - */ - -static void mc32_halt_transceiver(struct net_device *dev) -{ - struct mc32_local *lp = netdev_priv(dev); - int ioaddr = dev->base_addr; - - mc32_ready_poll(dev); - lp->rx_box->mbox=0; - outb(HOST_CMD_SUSPND_RX, ioaddr+HOST_CMD); - wait_for_completion(&lp->xceiver_cmd); - - mc32_ready_poll(dev); - lp->tx_box->mbox=0; - outb(HOST_CMD_SUSPND_TX, ioaddr+HOST_CMD); - wait_for_completion(&lp->xceiver_cmd); -} - - -/** - * mc32_load_rx_ring - load the ring of receive buffers - * @dev: 3c527 to build the ring for - * - * This initialises the on-card and driver datastructures to - * the point where mc32_start_transceiver() can be called. - * - * The card sets up the receive ring for us. We are required to use the - * ring it provides, although the size of the ring is configurable. - * - * We allocate an sk_buff for each ring entry in turn and - * initialise its house-keeping info. At the same time, we read - * each 'next' pointer in our rx_ring array. This reduces slow - * shared-memory reads and makes it easy to access predecessor - * descriptors. - * - * We then set the end-of-list bit for the last entry so that the - * card will know when it has run out of buffers. - */ - -static int mc32_load_rx_ring(struct net_device *dev) -{ - struct mc32_local *lp = netdev_priv(dev); - int i; - u16 rx_base; - volatile struct skb_header *p; - - rx_base=lp->rx_chain; - - for(i=0; irx_ring[i].skb=alloc_skb(1532, GFP_KERNEL); - if (lp->rx_ring[i].skb==NULL) { - for (;i>=0;i--) - kfree_skb(lp->rx_ring[i].skb); - return -ENOBUFS; - } - skb_reserve(lp->rx_ring[i].skb, 18); - - p=isa_bus_to_virt(lp->base+rx_base); - - p->control=0; - p->data=isa_virt_to_bus(lp->rx_ring[i].skb->data); - p->status=0; - p->length=1532; - - lp->rx_ring[i].p=p; - rx_base=p->next; - } - - lp->rx_ring[i-1].p->control |= CONTROL_EOL; - - lp->rx_ring_tail=0; - - return 0; -} - - -/** - * mc32_flush_rx_ring - free the ring of receive buffers - * @lp: Local data of 3c527 to flush the rx ring of - * - * Free the buffer for each ring slot. This may be called - * before mc32_load_rx_ring(), eg. on error in mc32_open(). - * Requires rx skb pointers to point to a valid skb, or NULL. - */ - -static void mc32_flush_rx_ring(struct net_device *dev) -{ - struct mc32_local *lp = netdev_priv(dev); - int i; - - for(i=0; i < RX_RING_LEN; i++) - { - if (lp->rx_ring[i].skb) { - dev_kfree_skb(lp->rx_ring[i].skb); - lp->rx_ring[i].skb = NULL; - } - lp->rx_ring[i].p=NULL; - } -} - - -/** - * mc32_load_tx_ring - load transmit ring - * @dev: The 3c527 card to issue the command to - * - * This sets up the host transmit data-structures. - * - * First, we obtain from the card it's current position in the tx - * ring, so that we will know where to begin transmitting - * packets. - * - * Then, we read the 'next' pointers from the on-card tx ring into - * our tx_ring array to reduce slow shared-mem reads. Finally, we - * intitalise the tx house keeping variables. - * - */ - -static void mc32_load_tx_ring(struct net_device *dev) -{ - struct mc32_local *lp = netdev_priv(dev); - volatile struct skb_header *p; - int i; - u16 tx_base; - - tx_base=lp->tx_box->data[0]; - - for(i=0 ; ibase+tx_base); - lp->tx_ring[i].p=p; - lp->tx_ring[i].skb=NULL; - - tx_base=p->next; - } - - /* -1 so that tx_ring_head cannot "lap" tx_ring_tail */ - /* see mc32_tx_ring */ - - atomic_set(&lp->tx_count, TX_RING_LEN-1); - atomic_set(&lp->tx_ring_head, 0); - lp->tx_ring_tail=0; -} - - -/** - * mc32_flush_tx_ring - free transmit ring - * @lp: Local data of 3c527 to flush the tx ring of - * - * If the ring is non-empty, zip over the it, freeing any - * allocated skb_buffs. The tx ring house-keeping variables are - * then reset. Requires rx skb pointers to point to a valid skb, - * or NULL. - */ - -static void mc32_flush_tx_ring(struct net_device *dev) -{ - struct mc32_local *lp = netdev_priv(dev); - int i; - - for (i=0; i < TX_RING_LEN; i++) - { - if (lp->tx_ring[i].skb) - { - dev_kfree_skb(lp->tx_ring[i].skb); - lp->tx_ring[i].skb = NULL; - } - } - - atomic_set(&lp->tx_count, 0); - atomic_set(&lp->tx_ring_head, 0); - lp->tx_ring_tail=0; -} - - -/** - * mc32_open - handle 'up' of card - * @dev: device to open - * - * The user is trying to bring the card into ready state. This requires - * a brief dialogue with the card. Firstly we enable interrupts and then - * 'indications'. Without these enabled the card doesn't bother telling - * us what it has done. This had me puzzled for a week. - * - * We configure the number of card descriptors, then load the network - * address and multicast filters. Turn on the workaround mode. This - * works around a bug in the 82586 - it asks the firmware to do - * so. It has a performance (latency) hit but is needed on busy - * [read most] lans. We load the ring with buffers then we kick it - * all off. - */ - -static int mc32_open(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - struct mc32_local *lp = netdev_priv(dev); - u8 one=1; - u8 regs; - u16 descnumbuffs[2] = {TX_RING_LEN, RX_RING_LEN}; - - /* - * Interrupts enabled - */ - - regs=inb(ioaddr+HOST_CTRL); - regs|=HOST_CTRL_INTE; - outb(regs, ioaddr+HOST_CTRL); - - /* - * Allow ourselves to issue commands - */ - - up(&lp->cmd_mutex); - - - /* - * Send the indications on command - */ - - mc32_command(dev, 4, &one, 2); - - /* - * Poke it to make sure it's really dead. - */ - - mc32_halt_transceiver(dev); - mc32_flush_tx_ring(dev); - - /* - * Ask card to set up on-card descriptors to our spec - */ - - if(mc32_command(dev, 8, descnumbuffs, 4)) { - pr_info("%s: %s rejected our buffer configuration!\n", - dev->name, cardname); - mc32_close(dev); - return -ENOBUFS; - } - - /* Report new configuration */ - mc32_command(dev, 6, NULL, 0); - - lp->tx_chain = lp->exec_box->data[8]; /* Transmit list start offset */ - lp->rx_chain = lp->exec_box->data[10]; /* Receive list start offset */ - lp->tx_len = lp->exec_box->data[9]; /* Transmit list count */ - lp->rx_len = lp->exec_box->data[11]; /* Receive list count */ - - /* Set Network Address */ - mc32_command(dev, 1, dev->dev_addr, 6); - - /* Set the filters */ - mc32_set_multicast_list(dev); - - if (WORKAROUND_82586) { - u16 zero_word=0; - mc32_command(dev, 0x0D, &zero_word, 2); /* 82586 bug workaround on */ - } - - mc32_load_tx_ring(dev); - - if(mc32_load_rx_ring(dev)) - { - mc32_close(dev); - return -ENOBUFS; - } - - lp->xceiver_desired_state = RUNNING; - - /* And finally, set the ball rolling... */ - mc32_start_transceiver(dev); - - netif_start_queue(dev); - - return 0; -} - - -/** - * mc32_timeout - handle a timeout from the network layer - * @dev: 3c527 that timed out - * - * Handle a timeout on transmit from the 3c527. This normally means - * bad things as the hardware handles cable timeouts and mess for - * us. - * - */ - -static void mc32_timeout(struct net_device *dev) -{ - pr_warning("%s: transmit timed out?\n", dev->name); - /* Try to restart the adaptor. */ - netif_wake_queue(dev); -} - - -/** - * mc32_send_packet - queue a frame for transmit - * @skb: buffer to transmit - * @dev: 3c527 to send it out of - * - * Transmit a buffer. This normally means throwing the buffer onto - * the transmit queue as the queue is quite large. If the queue is - * full then we set tx_busy and return. Once the interrupt handler - * gets messages telling it to reclaim transmit queue entries, we will - * clear tx_busy and the kernel will start calling this again. - * - * We do not disable interrupts or acquire any locks; this can - * run concurrently with mc32_tx_ring(), and the function itself - * is serialised at a higher layer. However, similarly for the - * card itself, we must ensure that we update tx_ring_head only - * after we've established a valid packet on the tx ring (and - * before we let the card "see" it, to prevent it racing with the - * irq handler). - * - */ - -static netdev_tx_t mc32_send_packet(struct sk_buff *skb, - struct net_device *dev) -{ - struct mc32_local *lp = netdev_priv(dev); - u32 head = atomic_read(&lp->tx_ring_head); - - volatile struct skb_header *p, *np; - - netif_stop_queue(dev); - - if(atomic_read(&lp->tx_count)==0) { - return NETDEV_TX_BUSY; - } - - if (skb_padto(skb, ETH_ZLEN)) { - netif_wake_queue(dev); - return NETDEV_TX_OK; - } - - atomic_dec(&lp->tx_count); - - /* P is the last sending/sent buffer as a pointer */ - p=lp->tx_ring[head].p; - - head = next_tx(head); - - /* NP is the buffer we will be loading */ - np=lp->tx_ring[head].p; - - /* We will need this to flush the buffer out */ - lp->tx_ring[head].skb=skb; - - np->length = unlikely(skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; - np->data = isa_virt_to_bus(skb->data); - np->status = 0; - np->control = CONTROL_EOP | CONTROL_EOL; - wmb(); - - /* - * The new frame has been setup; we can now - * let the interrupt handler and card "see" it - */ - - atomic_set(&lp->tx_ring_head, head); - p->control &= ~CONTROL_EOL; - - netif_wake_queue(dev); - return NETDEV_TX_OK; -} - - -/** - * mc32_update_stats - pull off the on board statistics - * @dev: 3c527 to service - * - * - * Query and reset the on-card stats. There's the small possibility - * of a race here, which would result in an underestimation of - * actual errors. As such, we'd prefer to keep all our stats - * collection in software. As a rule, we do. However it can't be - * used for rx errors and collisions as, by default, the card discards - * bad rx packets. - * - * Setting the SAV BP in the rx filter command supposedly - * stops this behaviour. However, testing shows that it only seems to - * enable the collation of on-card rx statistics --- the driver - * never sees an RX descriptor with an error status set. - * - */ - -static void mc32_update_stats(struct net_device *dev) -{ - struct mc32_local *lp = netdev_priv(dev); - volatile struct mc32_stats *st = lp->stats; - - u32 rx_errors=0; - - rx_errors+=dev->stats.rx_crc_errors +=st->rx_crc_errors; - st->rx_crc_errors=0; - rx_errors+=dev->stats.rx_fifo_errors +=st->rx_overrun_errors; - st->rx_overrun_errors=0; - rx_errors+=dev->stats.rx_frame_errors +=st->rx_alignment_errors; - st->rx_alignment_errors=0; - rx_errors+=dev->stats.rx_length_errors+=st->rx_tooshort_errors; - st->rx_tooshort_errors=0; - rx_errors+=dev->stats.rx_missed_errors+=st->rx_outofresource_errors; - st->rx_outofresource_errors=0; - dev->stats.rx_errors=rx_errors; - - /* Number of packets which saw one collision */ - dev->stats.collisions+=st->dataC[10]; - st->dataC[10]=0; - - /* Number of packets which saw 2--15 collisions */ - dev->stats.collisions+=st->dataC[11]; - st->dataC[11]=0; -} - - -/** - * mc32_rx_ring - process the receive ring - * @dev: 3c527 that needs its receive ring processing - * - * - * We have received one or more indications from the card that a - * receive has completed. The buffer ring thus contains dirty - * entries. We walk the ring by iterating over the circular rx_ring - * array, starting at the next dirty buffer (which happens to be the - * one we finished up at last time around). - * - * For each completed packet, we will either copy it and pass it up - * the stack or, if the packet is near MTU sized, we allocate - * another buffer and flip the old one up the stack. - * - * We must succeed in keeping a buffer on the ring. If necessary we - * will toss a received packet rather than lose a ring entry. Once - * the first uncompleted descriptor is found, we move the - * End-Of-List bit to include the buffers just processed. - * - */ - -static void mc32_rx_ring(struct net_device *dev) -{ - struct mc32_local *lp = netdev_priv(dev); - volatile struct skb_header *p; - u16 rx_ring_tail; - u16 rx_old_tail; - int x=0; - - rx_old_tail = rx_ring_tail = lp->rx_ring_tail; - - do - { - p=lp->rx_ring[rx_ring_tail].p; - - if(!(p->status & (1<<7))) { /* Not COMPLETED */ - break; - } - if(p->status & (1<<6)) /* COMPLETED_OK */ - { - - u16 length=p->length; - struct sk_buff *skb; - struct sk_buff *newskb; - - /* Try to save time by avoiding a copy on big frames */ - - if ((length > RX_COPYBREAK) && - ((newskb = netdev_alloc_skb(dev, 1532)) != NULL)) - { - skb=lp->rx_ring[rx_ring_tail].skb; - skb_put(skb, length); - - skb_reserve(newskb,18); - lp->rx_ring[rx_ring_tail].skb=newskb; - p->data=isa_virt_to_bus(newskb->data); - } - else - { - skb = netdev_alloc_skb(dev, length + 2); - - if(skb==NULL) { - dev->stats.rx_dropped++; - goto dropped; - } - - skb_reserve(skb,2); - memcpy(skb_put(skb, length), - lp->rx_ring[rx_ring_tail].skb->data, length); - } - - skb->protocol=eth_type_trans(skb,dev); - dev->stats.rx_packets++; - dev->stats.rx_bytes += length; - netif_rx(skb); - } - - dropped: - p->length = 1532; - p->status = 0; - - rx_ring_tail=next_rx(rx_ring_tail); - } - while(x++<48); - - /* If there was actually a frame to be processed, place the EOL bit */ - /* at the descriptor prior to the one to be filled next */ - - if (rx_ring_tail != rx_old_tail) - { - lp->rx_ring[prev_rx(rx_ring_tail)].p->control |= CONTROL_EOL; - lp->rx_ring[prev_rx(rx_old_tail)].p->control &= ~CONTROL_EOL; - - lp->rx_ring_tail=rx_ring_tail; - } -} - - -/** - * mc32_tx_ring - process completed transmits - * @dev: 3c527 that needs its transmit ring processing - * - * - * This operates in a similar fashion to mc32_rx_ring. We iterate - * over the transmit ring. For each descriptor which has been - * processed by the card, we free its associated buffer and note - * any errors. This continues until the transmit ring is emptied - * or we reach a descriptor that hasn't yet been processed by the - * card. - * - */ - -static void mc32_tx_ring(struct net_device *dev) -{ - struct mc32_local *lp = netdev_priv(dev); - volatile struct skb_header *np; - - /* - * We rely on head==tail to mean 'queue empty'. - * This is why lp->tx_count=TX_RING_LEN-1: in order to prevent - * tx_ring_head wrapping to tail and confusing a 'queue empty' - * condition with 'queue full' - */ - - while (lp->tx_ring_tail != atomic_read(&lp->tx_ring_head)) - { - u16 t; - - t=next_tx(lp->tx_ring_tail); - np=lp->tx_ring[t].p; - - if(!(np->status & (1<<7))) - { - /* Not COMPLETED */ - break; - } - dev->stats.tx_packets++; - if(!(np->status & (1<<6))) /* Not COMPLETED_OK */ - { - dev->stats.tx_errors++; - - switch(np->status&0x0F) - { - case 1: - dev->stats.tx_aborted_errors++; - break; /* Max collisions */ - case 2: - dev->stats.tx_fifo_errors++; - break; - case 3: - dev->stats.tx_carrier_errors++; - break; - case 4: - dev->stats.tx_window_errors++; - break; /* CTS Lost */ - case 5: - dev->stats.tx_aborted_errors++; - break; /* Transmit timeout */ - } - } - /* Packets are sent in order - this is - basically a FIFO queue of buffers matching - the card ring */ - dev->stats.tx_bytes+=lp->tx_ring[t].skb->len; - dev_kfree_skb_irq(lp->tx_ring[t].skb); - lp->tx_ring[t].skb=NULL; - atomic_inc(&lp->tx_count); - netif_wake_queue(dev); - - lp->tx_ring_tail=t; - } - -} - - -/** - * mc32_interrupt - handle an interrupt from a 3c527 - * @irq: Interrupt number - * @dev_id: 3c527 that requires servicing - * @regs: Registers (unused) - * - * - * An interrupt is raised whenever the 3c527 writes to the command - * register. This register contains the message it wishes to send us - * packed into a single byte field. We keep reading status entries - * until we have processed all the control items, but simply count - * transmit and receive reports. When all reports are in we empty the - * transceiver rings as appropriate. This saves the overhead of - * multiple command requests. - * - * Because MCA is level-triggered, we shouldn't miss indications. - * Therefore, we needn't ask the card to suspend interrupts within - * this handler. The card receives an implicit acknowledgment of the - * current interrupt when we read the command register. - * - */ - -static irqreturn_t mc32_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct mc32_local *lp; - int ioaddr, status, boguscount = 0; - int rx_event = 0; - int tx_event = 0; - - ioaddr = dev->base_addr; - lp = netdev_priv(dev); - - /* See whats cooking */ - - while((inb(ioaddr+HOST_STATUS)&HOST_STATUS_CWR) && boguscount++<2000) - { - status=inb(ioaddr+HOST_CMD); - - pr_debug("Status TX%d RX%d EX%d OV%d BC%d\n", - (status&7), (status>>3)&7, (status>>6)&1, - (status>>7)&1, boguscount); - - switch(status&7) - { - case 0: - break; - case 6: /* TX fail */ - case 2: /* TX ok */ - tx_event = 1; - break; - case 3: /* Halt */ - case 4: /* Abort */ - complete(&lp->xceiver_cmd); - break; - default: - pr_notice("%s: strange tx ack %d\n", dev->name, status&7); - } - status>>=3; - switch(status&7) - { - case 0: - break; - case 2: /* RX */ - rx_event=1; - break; - case 3: /* Halt */ - case 4: /* Abort */ - complete(&lp->xceiver_cmd); - break; - case 6: - /* Out of RX buffers stat */ - /* Must restart rx */ - dev->stats.rx_dropped++; - mc32_rx_ring(dev); - mc32_start_transceiver(dev); - break; - default: - pr_notice("%s: strange rx ack %d\n", - dev->name, status&7); - } - status>>=3; - if(status&1) - { - /* - * No thread is waiting: we need to tidy - * up ourself. - */ - - if (lp->cmd_nonblocking) { - up(&lp->cmd_mutex); - if (lp->mc_reload_wait) - mc32_reset_multicast_list(dev); - } - else complete(&lp->execution_cmd); - } - if(status&2) - { - /* - * We get interrupted once per - * counter that is about to overflow. - */ - - mc32_update_stats(dev); - } - } - - - /* - * Process the transmit and receive rings - */ - - if(tx_event) - mc32_tx_ring(dev); - - if(rx_event) - mc32_rx_ring(dev); - - return IRQ_HANDLED; -} - - -/** - * mc32_close - user configuring the 3c527 down - * @dev: 3c527 card to shut down - * - * The 3c527 is a bus mastering device. We must be careful how we - * shut it down. It may also be running shared interrupt so we have - * to be sure to silence it properly - * - * We indicate that the card is closing to the rest of the - * driver. Otherwise, it is possible that the card may run out - * of receive buffers and restart the transceiver while we're - * trying to close it. - * - * We abort any receive and transmits going on and then wait until - * any pending exec commands have completed in other code threads. - * In theory we can't get here while that is true, in practice I am - * paranoid - * - * We turn off the interrupt enable for the board to be sure it can't - * intefere with other devices. - */ - -static int mc32_close(struct net_device *dev) -{ - struct mc32_local *lp = netdev_priv(dev); - int ioaddr = dev->base_addr; - - u8 regs; - u16 one=1; - - lp->xceiver_desired_state = HALTED; - netif_stop_queue(dev); - - /* - * Send the indications on command (handy debug check) - */ - - mc32_command(dev, 4, &one, 2); - - /* Shut down the transceiver */ - - mc32_halt_transceiver(dev); - - /* Ensure we issue no more commands beyond this point */ - - down(&lp->cmd_mutex); - - /* Ok the card is now stopping */ - - regs=inb(ioaddr+HOST_CTRL); - regs&=~HOST_CTRL_INTE; - outb(regs, ioaddr+HOST_CTRL); - - mc32_flush_rx_ring(dev); - mc32_flush_tx_ring(dev); - - mc32_update_stats(dev); - - return 0; -} - - -/** - * mc32_get_stats - hand back stats to network layer - * @dev: The 3c527 card to handle - * - * We've collected all the stats we can in software already. Now - * it's time to update those kept on-card and return the lot. - * - */ - -static struct net_device_stats *mc32_get_stats(struct net_device *dev) -{ - mc32_update_stats(dev); - return &dev->stats; -} - - -/** - * do_mc32_set_multicast_list - attempt to update multicasts - * @dev: 3c527 device to load the list on - * @retry: indicates this is not the first call. - * - * - * Actually set or clear the multicast filter for this adaptor. The - * locking issues are handled by this routine. We have to track - * state as it may take multiple calls to get the command sequence - * completed. We just keep trying to schedule the loads until we - * manage to process them all. - * - * num_addrs == -1 Promiscuous mode, receive all packets - * - * num_addrs == 0 Normal mode, clear multicast list - * - * num_addrs > 0 Multicast mode, receive normal and MC packets, - * and do best-effort filtering. - * - * See mc32_update_stats() regards setting the SAV BP bit. - * - */ - -static void do_mc32_set_multicast_list(struct net_device *dev, int retry) -{ - struct mc32_local *lp = netdev_priv(dev); - u16 filt = (1<<2); /* Save Bad Packets, for stats purposes */ - - if ((dev->flags&IFF_PROMISC) || - (dev->flags&IFF_ALLMULTI) || - netdev_mc_count(dev) > 10) - /* Enable promiscuous mode */ - filt |= 1; - else if (!netdev_mc_empty(dev)) - { - unsigned char block[62]; - unsigned char *bp; - struct netdev_hw_addr *ha; - - if(retry==0) - lp->mc_list_valid = 0; - if(!lp->mc_list_valid) - { - block[1]=0; - block[0]=netdev_mc_count(dev); - bp=block+2; - - netdev_for_each_mc_addr(ha, dev) { - memcpy(bp, ha->addr, 6); - bp+=6; - } - if(mc32_command_nowait(dev, 2, block, - 2+6*netdev_mc_count(dev))==-1) - { - lp->mc_reload_wait = 1; - return; - } - lp->mc_list_valid=1; - } - } - - if(mc32_command_nowait(dev, 0, &filt, 2)==-1) - { - lp->mc_reload_wait = 1; - } - else { - lp->mc_reload_wait = 0; - } -} - - -/** - * mc32_set_multicast_list - queue multicast list update - * @dev: The 3c527 to use - * - * Commence loading the multicast list. This is called when the kernel - * changes the lists. It will override any pending list we are trying to - * load. - */ - -static void mc32_set_multicast_list(struct net_device *dev) -{ - do_mc32_set_multicast_list(dev,0); -} - - -/** - * mc32_reset_multicast_list - reset multicast list - * @dev: The 3c527 to use - * - * Attempt the next step in loading the multicast lists. If this attempt - * fails to complete then it will be scheduled and this function called - * again later from elsewhere. - */ - -static void mc32_reset_multicast_list(struct net_device *dev) -{ - do_mc32_set_multicast_list(dev,1); -} - -static void netdev_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - strcpy(info->driver, DRV_NAME); - strcpy(info->version, DRV_VERSION); - sprintf(info->bus_info, "MCA 0x%lx", dev->base_addr); -} - -static u32 netdev_get_msglevel(struct net_device *dev) -{ - return mc32_debug; -} - -static void netdev_set_msglevel(struct net_device *dev, u32 level) -{ - mc32_debug = level; -} - -static const struct ethtool_ops netdev_ethtool_ops = { - .get_drvinfo = netdev_get_drvinfo, - .get_msglevel = netdev_get_msglevel, - .set_msglevel = netdev_set_msglevel, -}; - -#ifdef MODULE - -static struct net_device *this_device; - -/** - * init_module - entry point - * - * Probe and locate a 3c527 card. This really should probe and locate - * all the 3c527 cards in the machine not just one of them. Yes you can - * insmod multiple modules for now but it's a hack. - */ - -int __init init_module(void) -{ - this_device = mc32_probe(-1); - if (IS_ERR(this_device)) - return PTR_ERR(this_device); - return 0; -} - -/** - * cleanup_module - free resources for an unload - * - * Unloading time. We release the MCA bus resources and the interrupt - * at which point everything is ready to unload. The card must be stopped - * at this point or we would not have been called. When we unload we - * leave the card stopped but not totally shut down. When the card is - * initialized it must be rebooted or the rings reloaded before any - * transmit operations are allowed to start scribbling into memory. - */ - -void __exit cleanup_module(void) -{ - unregister_netdev(this_device); - cleanup_card(this_device); - free_netdev(this_device); -} - -#endif /* MODULE */ diff --git a/trunk/drivers/net/ethernet/i825xx/3c527.h b/trunk/drivers/net/ethernet/i825xx/3c527.h deleted file mode 100644 index d693b8d15cde..000000000000 --- a/trunk/drivers/net/ethernet/i825xx/3c527.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 3COM "EtherLink MC/32" Descriptions - */ - -/* - * Registers - */ - -#define HOST_CMD 0 -#define HOST_CMD_START_RX (1<<3) -#define HOST_CMD_SUSPND_RX (3<<3) -#define HOST_CMD_RESTRT_RX (5<<3) - -#define HOST_CMD_SUSPND_TX 3 -#define HOST_CMD_RESTRT_TX 5 - - -#define HOST_STATUS 2 -#define HOST_STATUS_CRR (1<<6) -#define HOST_STATUS_CWR (1<<5) - - -#define HOST_CTRL 6 -#define HOST_CTRL_ATTN (1<<7) -#define HOST_CTRL_RESET (1<<6) -#define HOST_CTRL_INTE (1<<2) - -#define HOST_RAMPAGE 8 - -#define HALTED 0 -#define RUNNING 1 - -struct mc32_mailbox -{ - u16 mbox; - u16 data[1]; -} __packed; - -struct skb_header -{ - u8 status; - u8 control; - u16 next; /* Do not change! */ - u16 length; - u32 data; -} __packed; - -struct mc32_stats -{ - /* RX Errors */ - u32 rx_crc_errors; - u32 rx_alignment_errors; - u32 rx_overrun_errors; - u32 rx_tooshort_errors; - u32 rx_toolong_errors; - u32 rx_outofresource_errors; - - u32 rx_discarded; /* via card pattern match filter */ - - /* TX Errors */ - u32 tx_max_collisions; - u32 tx_carrier_errors; - u32 tx_underrun_errors; - u32 tx_cts_errors; - u32 tx_timeout_errors; - - /* various cruft */ - u32 dataA[6]; - u16 dataB[5]; - u32 dataC[14]; -} __packed; - -#define STATUS_MASK 0x0F -#define COMPLETED (1<<7) -#define COMPLETED_OK (1<<6) -#define BUFFER_BUSY (1<<5) - -#define CONTROL_EOP (1<<7) /* End Of Packet */ -#define CONTROL_EOL (1<<6) /* End of List */ - -#define MCA_MC32_ID 0x0041 /* Our MCA ident */ diff --git a/trunk/drivers/net/ethernet/i825xx/Kconfig b/trunk/drivers/net/ethernet/i825xx/Kconfig index ca1ae985c6df..fed5080a6b62 100644 --- a/trunk/drivers/net/ethernet/i825xx/Kconfig +++ b/trunk/drivers/net/ethernet/i825xx/Kconfig @@ -43,28 +43,6 @@ config EL16 To compile this driver as a module, choose M here. The module will be called 3c507. -config ELMC - tristate "3c523 \"EtherLink/MC\" support" - depends on MCA_LEGACY - ---help--- - If you have a network (Ethernet) card of this type, say Y and read - the Ethernet-HOWTO, available from - . - - To compile this driver as a module, choose M here. The module - will be called 3c523. - -config ELMC_II - tristate "3c527 \"EtherLink/MC 32\" support (EXPERIMENTAL)" - depends on MCA && MCA_LEGACY - ---help--- - If you have a network (Ethernet) card of this type, say Y and read - the Ethernet-HOWTO, available from - . - - To compile this driver as a module, choose M here. The module - will be called 3c527. - config ARM_ETHER1 tristate "Acorn Ether1 support" depends on ARM && ARCH_ACORN diff --git a/trunk/drivers/net/ethernet/i825xx/Makefile b/trunk/drivers/net/ethernet/i825xx/Makefile index f68a3694968a..6adff85e8ecc 100644 --- a/trunk/drivers/net/ethernet/i825xx/Makefile +++ b/trunk/drivers/net/ethernet/i825xx/Makefile @@ -7,8 +7,6 @@ obj-$(CONFIG_EEXPRESS) += eexpress.o obj-$(CONFIG_EEXPRESS_PRO) += eepro.o obj-$(CONFIG_ELPLUS) += 3c505.o obj-$(CONFIG_EL16) += 3c507.o -obj-$(CONFIG_ELMC) += 3c523.o -obj-$(CONFIG_ELMC_II) += 3c527.o obj-$(CONFIG_LP486E) += lp486e.o obj-$(CONFIG_NI52) += ni52.o obj-$(CONFIG_SUN3_82586) += sun3_82586.o diff --git a/trunk/drivers/net/ethernet/i825xx/eexpress.c b/trunk/drivers/net/ethernet/i825xx/eexpress.c index cc2e66ad4436..7a6a2f04c5b1 100644 --- a/trunk/drivers/net/ethernet/i825xx/eexpress.c +++ b/trunk/drivers/net/ethernet/i825xx/eexpress.c @@ -9,7 +9,7 @@ * Many modifications, and currently maintained, by * Philip Blundell * Added the Compaq LTE Alan Cox - * Added MCA support Adam Fritzler + * Added MCA support Adam Fritzler (now deleted) * * Note - this driver is experimental still - it has problems on faster * machines. Someone needs to sit down and go through it line by line with @@ -111,7 +111,6 @@ #include #include #include -#include #include #include #include @@ -227,16 +226,6 @@ static unsigned short start_code[] = { /* maps irq number to EtherExpress magic value */ static char irqrmap[] = { 0,0,1,2,3,4,0,0,0,1,5,6,0,0,0,0 }; -#ifdef CONFIG_MCA_LEGACY -/* mapping of the first four bits of the second POS register */ -static unsigned short mca_iomap[] = { - 0x270, 0x260, 0x250, 0x240, 0x230, 0x220, 0x210, 0x200, - 0x370, 0x360, 0x350, 0x340, 0x330, 0x320, 0x310, 0x300 -}; -/* bits 5-7 of the second POS register */ -static char mca_irqmap[] = { 12, 9, 3, 4, 5, 10, 11, 15 }; -#endif - /* * Prototypes for Linux interface */ @@ -340,53 +329,6 @@ static int __init do_express_probe(struct net_device *dev) dev->if_port = 0xff; /* not set */ -#ifdef CONFIG_MCA_LEGACY - if (MCA_bus) { - int slot = 0; - - /* - * Only find one card at a time. Subsequent calls - * will find others, however, proper multicard MCA - * probing and setup can't be done with the - * old-style Space.c init routines. -- ASF - */ - while (slot != MCA_NOTFOUND) { - int pos0, pos1; - - slot = mca_find_unused_adapter(0x628B, slot); - if (slot == MCA_NOTFOUND) - break; - - pos0 = mca_read_stored_pos(slot, 2); - pos1 = mca_read_stored_pos(slot, 3); - ioaddr = mca_iomap[pos1&0xf]; - - dev->irq = mca_irqmap[(pos1>>4)&0x7]; - - /* - * XXX: Transceiver selection is done - * differently on the MCA version. - * How to get it to select something - * other than external/AUI is currently - * unknown. This code is just for looks. -- ASF - */ - if ((pos0 & 0x7) == 0x1) - dev->if_port = AUI; - else if ((pos0 & 0x7) == 0x5) { - if (pos1 & 0x80) - dev->if_port = BNC; - else - dev->if_port = TPE; - } - - mca_set_adapter_name(slot, "Intel EtherExpress 16 MCA"); - mca_set_adapter_procfn(slot, NULL, dev); - mca_mark_as_used(slot); - - break; - } - } -#endif if (ioaddr&0xfe00) { if (!request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress")) return -EBUSY; diff --git a/trunk/drivers/net/ethernet/intel/Kconfig b/trunk/drivers/net/ethernet/intel/Kconfig index 76213162fbe3..79b07ec6726f 100644 --- a/trunk/drivers/net/ethernet/intel/Kconfig +++ b/trunk/drivers/net/ethernet/intel/Kconfig @@ -7,7 +7,7 @@ config NET_VENDOR_INTEL default y depends on PCI || PCI_MSI || ISA || ISA_DMA_API || ARM || \ ARCH_ACORN || MCA || MCA_LEGACY || SNI_RM || SUN3 || \ - GSC || BVME6000 || MVME16x || ARCH_ENP2611 || \ + GSC || BVME6000 || MVME16x || \ (ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR) || \ EXPERIMENTAL ---help--- @@ -120,6 +120,17 @@ config IGB_DCA driver. DCA is a method for warming the CPU cache before data is used, with the intent of lessening the impact of cache misses. +config IGB_PTP + bool "PTP Hardware Clock (PHC)" + default y + depends on IGB && PTP_1588_CLOCK + ---help--- + Say Y here if you want to use PTP Hardware Clock (PHC) in the + driver. Only the basic clock operations have been implemented. + + Every timestamp and clock read operations must consult the + overflow counter to form a correct time value. + config IGBVF tristate "Intel(R) 82576 Virtual Function Ethernet support" depends on PCI @@ -182,6 +193,14 @@ config IXGBE To compile this driver as a module, choose M here. The module will be called ixgbe. +config IXGBE_HWMON + bool "Intel(R) 10GbE PCI Express adapters HWMON support" + default y + depends on IXGBE && HWMON && !(IXGBE=y && HWMON=m) + ---help--- + Say Y if you want to expose the thermal sensor data on some of + our cards, via a hwmon sysfs interface. + config IXGBE_DCA bool "Direct Cache Access (DCA) Support" default y @@ -201,6 +220,17 @@ config IXGBE_DCB If unsure, say N. +config IXGBE_PTP + bool "PTP Clock Support" + default n + depends on IXGBE && PTP_1588_CLOCK + ---help--- + Say Y here if you want support for 1588 Timestamping with a + PHC device, using the PTP 1588 Clock support. This is + required to enable timestamping support for the device. + + If unsure, say N. + config IXGBEVF tristate "Intel(R) 82599 Virtual Function Ethernet support" depends on PCI_MSI diff --git a/trunk/drivers/net/ethernet/intel/e100.c b/trunk/drivers/net/ethernet/intel/e100.c index e498effb85d9..ada720b42ff6 100644 --- a/trunk/drivers/net/ethernet/intel/e100.c +++ b/trunk/drivers/net/ethernet/intel/e100.c @@ -1759,6 +1759,7 @@ static void e100_xmit_prepare(struct nic *nic, struct cb *cb, skb->data, skb->len, PCI_DMA_TODEVICE)); /* check for mapping failure? */ cb->u.tcb.tbd.size = cpu_to_le16(skb->len); + skb_tx_timestamp(skb); } static netdev_tx_t e100_xmit_frame(struct sk_buff *skb, @@ -2733,6 +2734,7 @@ static const struct ethtool_ops e100_ethtool_ops = { .set_phys_id = e100_set_phys_id, .get_ethtool_stats = e100_get_ethtool_stats, .get_sset_count = e100_get_sset_count, + .get_ts_info = ethtool_op_get_ts_info, }; static int e100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) diff --git a/trunk/drivers/net/ethernet/intel/e1000/e1000_main.c b/trunk/drivers/net/ethernet/intel/e1000/e1000_main.c index 8d8908d2a9b1..95731c841044 100644 --- a/trunk/drivers/net/ethernet/intel/e1000/e1000_main.c +++ b/trunk/drivers/net/ethernet/intel/e1000/e1000_main.c @@ -831,9 +831,10 @@ static int e1000_set_features(struct net_device *netdev, if (changed & NETIF_F_HW_VLAN_RX) e1000_vlan_mode(netdev, features); - if (!(changed & NETIF_F_RXCSUM)) + if (!(changed & (NETIF_F_RXCSUM | NETIF_F_RXALL))) return 0; + netdev->features = features; adapter->rx_csum = !!(features & NETIF_F_RXCSUM); if (netif_running(netdev)) @@ -1078,6 +1079,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, netdev->features |= netdev->hw_features; netdev->hw_features |= NETIF_F_RXCSUM; + netdev->hw_features |= NETIF_F_RXALL; netdev->hw_features |= NETIF_F_RXFCS; if (pci_using_dac) { @@ -1845,6 +1847,22 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter) break; } + /* This is useful for sniffing bad packets. */ + if (adapter->netdev->features & NETIF_F_RXALL) { + /* UPE and MPE will be handled by normal PROMISC logic + * in e1000e_set_rx_mode */ + rctl |= (E1000_RCTL_SBP | /* Receive bad packets */ + E1000_RCTL_BAM | /* RX All Bcast Pkts */ + E1000_RCTL_PMCF); /* RX All MAC Ctrl Pkts */ + + rctl &= ~(E1000_RCTL_VFE | /* Disable VLAN filter */ + E1000_RCTL_DPF | /* Allow filtered pause */ + E1000_RCTL_CFIEN); /* Dis VLAN CFIEN Filter */ + /* Do not mess with E1000_CTRL_VME, it affects transmit as well, + * and that breaks VLANs. + */ + } + ew32(RCTL, rctl); } @@ -3247,6 +3265,8 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, nr_frags, mss); if (count) { + skb_tx_timestamp(skb); + e1000_tx_queue(adapter, tx_ring, tx_flags, count); /* Make sure there is space in the ring for the next send. */ e1000_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 2); @@ -4050,7 +4070,11 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter, /* errors is only valid for DD + EOP descriptors */ if (unlikely((status & E1000_RXD_STAT_EOP) && (rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK))) { - u8 last_byte = *(skb->data + length - 1); + u8 *mapped; + u8 last_byte; + + mapped = page_address(buffer_info->page); + last_byte = *(mapped + length - 1); if (TBI_ACCEPT(hw, status, rx_desc->errors, length, last_byte)) { spin_lock_irqsave(&adapter->stats_lock, @@ -4061,6 +4085,8 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter, irq_flags); length--; } else { + if (netdev->features & NETIF_F_RXALL) + goto process_skb; /* recycle both page and skb */ buffer_info->skb = skb; /* an error means any chain goes out the window @@ -4073,6 +4099,7 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter, } #define rxtop rx_ring->rx_skb_top +process_skb: if (!(status & E1000_RXD_STAT_EOP)) { /* this descriptor is only the beginning (or middle) */ if (!rxtop) { @@ -4280,12 +4307,15 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, flags); length--; } else { + if (netdev->features & NETIF_F_RXALL) + goto process_skb; /* recycle */ buffer_info->skb = skb; goto next_desc; } } +process_skb: total_rx_bytes += (length - 4); /* don't count FCS */ total_rx_packets++; @@ -4369,30 +4399,6 @@ e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter, break; } - /* Fix for errata 23, can't cross 64kB boundary */ - if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) { - struct sk_buff *oldskb = skb; - e_err(rx_err, "skb align check failed: %u bytes at " - "%p\n", bufsz, skb->data); - /* Try again, without freeing the previous */ - skb = netdev_alloc_skb_ip_align(netdev, bufsz); - /* Failed allocation, critical failure */ - if (!skb) { - dev_kfree_skb(oldskb); - adapter->alloc_rx_buff_failed++; - break; - } - - if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) { - /* give up */ - dev_kfree_skb(skb); - dev_kfree_skb(oldskb); - break; /* while (cleaned_count--) */ - } - - /* Use new allocation */ - dev_kfree_skb(oldskb); - } buffer_info->skb = skb; buffer_info->length = adapter->rx_buffer_len; check_page: diff --git a/trunk/drivers/net/ethernet/intel/e1000e/80003es2lan.c b/trunk/drivers/net/ethernet/intel/e1000e/80003es2lan.c index bac9dda31b6c..4dd18a1f45d2 100644 --- a/trunk/drivers/net/ethernet/intel/e1000e/80003es2lan.c +++ b/trunk/drivers/net/ethernet/intel/e1000e/80003es2lan.c @@ -228,9 +228,7 @@ static s32 e1000_init_mac_params_80003es2lan(struct e1000_hw *hw) /* FWSM register */ mac->has_fwsm = true; /* ARC supported; valid only if manageability features are enabled. */ - mac->arc_subsystem_valid = - (er32(FWSM) & E1000_FWSM_MODE_MASK) - ? true : false; + mac->arc_subsystem_valid = !!(er32(FWSM) & E1000_FWSM_MODE_MASK); /* Adaptive IFS not supported */ mac->adaptive_ifs = false; @@ -766,6 +764,7 @@ static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw) { u32 ctrl; s32 ret_val; + u16 kum_reg_data; /* * Prevent the PCI-E bus from sticking if there is no TLP connection @@ -791,6 +790,13 @@ static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw) ew32(CTRL, ctrl | E1000_CTRL_RST); e1000_release_phy_80003es2lan(hw); + /* Disable IBIST slave mode (far-end loopback) */ + e1000_read_kmrn_reg_80003es2lan(hw, E1000_KMRNCTRLSTA_INBAND_PARAM, + &kum_reg_data); + kum_reg_data |= E1000_KMRNCTRLSTA_IBIST_DISABLE; + e1000_write_kmrn_reg_80003es2lan(hw, E1000_KMRNCTRLSTA_INBAND_PARAM, + kum_reg_data); + ret_val = e1000e_get_auto_rd_done(hw); if (ret_val) /* We don't want to continue accessing MAC registers. */ @@ -938,6 +944,14 @@ static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw) else reg |= (1 << 28); ew32(TARC(1), reg); + + /* + * Disable IPv6 extension header parsing because some malformed + * IPv6 headers can hang the Rx. + */ + reg = er32(RFCTL); + reg |= (E1000_RFCTL_IPV6_EX_DIS | E1000_RFCTL_NEW_IPV6_EXT_DIS); + ew32(RFCTL, reg); } /** @@ -1433,6 +1447,7 @@ static const struct e1000_mac_operations es2_mac_ops = { /* setup_physical_interface dependent on media type */ .setup_led = e1000e_setup_led_generic, .config_collision_dist = e1000e_config_collision_dist_generic, + .rar_set = e1000e_rar_set_generic, }; static const struct e1000_phy_operations es2_phy_ops = { diff --git a/trunk/drivers/net/ethernet/intel/e1000e/82571.c b/trunk/drivers/net/ethernet/intel/e1000e/82571.c index b3fdc6977f2e..36db4df09aed 100644 --- a/trunk/drivers/net/ethernet/intel/e1000e/82571.c +++ b/trunk/drivers/net/ethernet/intel/e1000e/82571.c @@ -295,9 +295,8 @@ static s32 e1000_init_mac_params_82571(struct e1000_hw *hw) * ARC supported; valid only if manageability features are * enabled. */ - mac->arc_subsystem_valid = - (er32(FWSM) & E1000_FWSM_MODE_MASK) - ? true : false; + mac->arc_subsystem_valid = !!(er32(FWSM) & + E1000_FWSM_MODE_MASK); break; case e1000_82574: case e1000_82583: @@ -798,7 +797,7 @@ static s32 e1000_update_nvm_checksum_82571(struct e1000_hw *hw) /* Check for pending operations. */ for (i = 0; i < E1000_FLASH_UPDATES; i++) { usleep_range(1000, 2000); - if ((er32(EECD) & E1000_EECD_FLUPD) == 0) + if (!(er32(EECD) & E1000_EECD_FLUPD)) break; } @@ -822,7 +821,7 @@ static s32 e1000_update_nvm_checksum_82571(struct e1000_hw *hw) for (i = 0; i < E1000_FLASH_UPDATES; i++) { usleep_range(1000, 2000); - if ((er32(EECD) & E1000_EECD_FLUPD) == 0) + if (!(er32(EECD) & E1000_EECD_FLUPD)) break; } @@ -1000,7 +999,7 @@ static s32 e1000_set_d0_lplu_state_82571(struct e1000_hw *hw, bool active) **/ static s32 e1000_reset_hw_82571(struct e1000_hw *hw) { - u32 ctrl, ctrl_ext; + u32 ctrl, ctrl_ext, eecd; s32 ret_val; /* @@ -1073,6 +1072,16 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw) */ switch (hw->mac.type) { + case e1000_82571: + case e1000_82572: + /* + * REQ and GNT bits need to be cleared when using AUTO_RD + * to access the EEPROM. + */ + eecd = er32(EECD); + eecd &= ~(E1000_EECD_REQ | E1000_EECD_GNT); + ew32(EECD, eecd); + break; case e1000_82573: case e1000_82574: case e1000_82583: @@ -1280,6 +1289,16 @@ static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw) ew32(CTRL_EXT, reg); } + /* + * Disable IPv6 extension header parsing because some malformed + * IPv6 headers can hang the Rx. + */ + if (hw->mac.type <= e1000_82573) { + reg = er32(RFCTL); + reg |= (E1000_RFCTL_IPV6_EX_DIS | E1000_RFCTL_NEW_IPV6_EXT_DIS); + ew32(RFCTL, reg); + } + /* PCI-Ex Control Registers */ switch (hw->mac.type) { case e1000_82574: @@ -1763,7 +1782,8 @@ void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state) * incoming packets directed to this port are dropped. * Eventually the LAA will be in RAR[0] and RAR[14]. */ - e1000e_rar_set(hw, hw->mac.addr, hw->mac.rar_entry_count - 1); + hw->mac.ops.rar_set(hw, hw->mac.addr, + hw->mac.rar_entry_count - 1); } /** @@ -1927,6 +1947,7 @@ static const struct e1000_mac_operations e82571_mac_ops = { .setup_led = e1000e_setup_led_generic, .config_collision_dist = e1000e_config_collision_dist_generic, .read_mac_addr = e1000_read_mac_addr_82571, + .rar_set = e1000e_rar_set_generic, }; static const struct e1000_phy_operations e82_phy_ops_igp = { @@ -2061,9 +2082,11 @@ const struct e1000_info e1000_82574_info = { | FLAG_HAS_SMART_POWER_DOWN | FLAG_HAS_AMT | FLAG_HAS_CTRLEXT_ON_LOAD, - .flags2 = FLAG2_CHECK_PHY_HANG + .flags2 = FLAG2_CHECK_PHY_HANG | FLAG2_DISABLE_ASPM_L0S - | FLAG2_NO_DISABLE_RX, + | FLAG2_DISABLE_ASPM_L1 + | FLAG2_NO_DISABLE_RX + | FLAG2_DMA_BURST, .pba = 32, .max_hw_frame_size = DEFAULT_JUMBO, .get_variants = e1000_get_variants_82571, diff --git a/trunk/drivers/net/ethernet/intel/e1000e/defines.h b/trunk/drivers/net/ethernet/intel/e1000e/defines.h index 3a5025917163..351a4097b2ba 100644 --- a/trunk/drivers/net/ethernet/intel/e1000e/defines.h +++ b/trunk/drivers/net/ethernet/intel/e1000e/defines.h @@ -74,7 +74,9 @@ #define E1000_WUS_BC E1000_WUFC_BC /* Extended Device Control */ +#define E1000_CTRL_EXT_LPCD 0x00000004 /* LCD Power Cycle Done */ #define E1000_CTRL_EXT_SDP3_DATA 0x00000080 /* Value of SW Definable Pin 3 */ +#define E1000_CTRL_EXT_FORCE_SMBUS 0x00000800 /* Force SMBus mode */ #define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */ #define E1000_CTRL_EXT_SPD_BYPS 0x00008000 /* Speed Select Bypass */ #define E1000_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */ @@ -573,6 +575,7 @@ #define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */ /* Link Partner Ability Register (Base Page) */ +#define NWAY_LPAR_100TX_FD_CAPS 0x0100 /* LP 100TX Full Dplx Capable */ #define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */ #define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */ @@ -739,6 +742,7 @@ #define I82577_E_PHY_ID 0x01540050 #define I82578_E_PHY_ID 0x004DD040 #define I82579_E_PHY_ID 0x01540090 +#define I217_E_PHY_ID 0x015400A0 /* M88E1000 Specific Registers */ #define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */ @@ -850,4 +854,8 @@ /* SerDes Control */ #define E1000_GEN_POLL_TIMEOUT 640 +/* FW Semaphore */ +#define E1000_FWSM_WLOCK_MAC_MASK 0x0380 +#define E1000_FWSM_WLOCK_MAC_SHIFT 7 + #endif /* _E1000_DEFINES_H_ */ diff --git a/trunk/drivers/net/ethernet/intel/e1000e/e1000.h b/trunk/drivers/net/ethernet/intel/e1000e/e1000.h index b83897f76ee3..6e6fffb34581 100644 --- a/trunk/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/trunk/drivers/net/ethernet/intel/e1000e/e1000.h @@ -206,6 +206,7 @@ enum e1000_boards { board_ich10lan, board_pchlan, board_pch2lan, + board_pch_lpt, }; struct e1000_ps_page { @@ -528,6 +529,7 @@ extern const struct e1000_info e1000_ich9_info; extern const struct e1000_info e1000_ich10_info; extern const struct e1000_info e1000_pch_info; extern const struct e1000_info e1000_pch2_info; +extern const struct e1000_info e1000_pch_lpt_info; extern const struct e1000_info e1000_es2_info; extern s32 e1000_read_pba_string_generic(struct e1000_hw *hw, u8 *pba_num, @@ -576,7 +578,7 @@ extern void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count); extern void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw, u8 *mc_addr_list, u32 mc_addr_count); -extern void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index); +extern void e1000e_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index); extern s32 e1000e_set_fc_watermarks(struct e1000_hw *hw); extern void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop); extern s32 e1000e_get_hw_semaphore(struct e1000_hw *hw); @@ -673,11 +675,21 @@ static inline s32 e1e_rphy(struct e1000_hw *hw, u32 offset, u16 *data) return hw->phy.ops.read_reg(hw, offset, data); } +static inline s32 e1e_rphy_locked(struct e1000_hw *hw, u32 offset, u16 *data) +{ + return hw->phy.ops.read_reg_locked(hw, offset, data); +} + static inline s32 e1e_wphy(struct e1000_hw *hw, u32 offset, u16 data) { return hw->phy.ops.write_reg(hw, offset, data); } +static inline s32 e1e_wphy_locked(struct e1000_hw *hw, u32 offset, u16 data) +{ + return hw->phy.ops.write_reg_locked(hw, offset, data); +} + static inline s32 e1000_get_cable_length(struct e1000_hw *hw) { return hw->phy.ops.get_cable_length(hw); @@ -735,9 +747,46 @@ static inline u32 __er32(struct e1000_hw *hw, unsigned long reg) return readl(hw->hw_addr + reg); } +#define er32(reg) __er32(hw, E1000_##reg) + +/** + * __ew32_prepare - prepare to write to MAC CSR register on certain parts + * @hw: pointer to the HW structure + * + * When updating the MAC CSR registers, the Manageability Engine (ME) could + * be accessing the registers at the same time. Normally, this is handled in + * h/w by an arbiter but on some parts there is a bug that acknowledges Host + * accesses later than it should which could result in the register to have + * an incorrect value. Workaround this by checking the FWSM register which + * has bit 24 set while ME is accessing MAC CSR registers, wait if it is set + * and try again a number of times. + **/ +static inline s32 __ew32_prepare(struct e1000_hw *hw) +{ + s32 i = E1000_ICH_FWSM_PCIM2PCI_COUNT; + + while ((er32(FWSM) & E1000_ICH_FWSM_PCIM2PCI) && --i) + udelay(50); + + return i; +} + static inline void __ew32(struct e1000_hw *hw, unsigned long reg, u32 val) { + if (hw->adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA) + __ew32_prepare(hw); + writel(val, hw->hw_addr + reg); } +#define ew32(reg, val) __ew32(hw, E1000_##reg, (val)) + +#define e1e_flush() er32(STATUS) + +#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) \ + (__ew32((a), (reg + ((offset) << 2)), (value))) + +#define E1000_READ_REG_ARRAY(a, reg, offset) \ + (readl((a)->hw_addr + reg + ((offset) << 2))) + #endif /* _E1000_H_ */ diff --git a/trunk/drivers/net/ethernet/intel/e1000e/ethtool.c b/trunk/drivers/net/ethernet/intel/e1000e/ethtool.c index db35dd5d96de..d863075df7a4 100644 --- a/trunk/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/trunk/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -259,8 +259,7 @@ static int e1000_set_settings(struct net_device *netdev, * cannot be changed */ if (hw->phy.ops.check_reset_block(hw)) { - e_err("Cannot change link characteristics when SoL/IDER is " - "active.\n"); + e_err("Cannot change link characteristics when SoL/IDER is active.\n"); return -EINVAL; } @@ -403,15 +402,15 @@ static void e1000_get_regs(struct net_device *netdev, regs_buff[1] = er32(STATUS); regs_buff[2] = er32(RCTL); - regs_buff[3] = er32(RDLEN); - regs_buff[4] = er32(RDH); - regs_buff[5] = er32(RDT); + regs_buff[3] = er32(RDLEN(0)); + regs_buff[4] = er32(RDH(0)); + regs_buff[5] = er32(RDT(0)); regs_buff[6] = er32(RDTR); regs_buff[7] = er32(TCTL); - regs_buff[8] = er32(TDLEN); - regs_buff[9] = er32(TDH); - regs_buff[10] = er32(TDT); + regs_buff[8] = er32(TDLEN(0)); + regs_buff[9] = er32(TDH(0)); + regs_buff[10] = er32(TDT(0)); regs_buff[11] = er32(TIDV); regs_buff[12] = adapter->hw.phy.type; /* PHY type (IGP=1, M88=0) */ @@ -727,9 +726,8 @@ static bool reg_pattern_test(struct e1000_adapter *adapter, u64 *data, (test[pat] & write)); val = E1000_READ_REG_ARRAY(&adapter->hw, reg, offset); if (val != (test[pat] & write & mask)) { - e_err("pattern test reg %04X failed: got 0x%08X " - "expected 0x%08X\n", reg + offset, val, - (test[pat] & write & mask)); + e_err("pattern test reg %04X failed: got 0x%08X expected 0x%08X\n", + reg + offset, val, (test[pat] & write & mask)); *data = reg; return 1; } @@ -744,8 +742,8 @@ static bool reg_set_and_check(struct e1000_adapter *adapter, u64 *data, __ew32(&adapter->hw, reg, write & mask); val = __er32(&adapter->hw, reg); if ((write & mask) != (val & mask)) { - e_err("set/check reg %04X test failed: got 0x%08X " - "expected 0x%08X\n", reg, (val & mask), (write & mask)); + e_err("set/check reg %04X test failed: got 0x%08X expected 0x%08X\n", + reg, (val & mask), (write & mask)); *data = reg; return 1; } @@ -775,6 +773,7 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) u32 i; u32 toggle; u32 mask; + u32 wlock_mac = 0; /* * The status register is Read Only, so a write should fail. @@ -797,8 +796,8 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) ew32(STATUS, toggle); after = er32(STATUS) & toggle; if (value != after) { - e_err("failed STATUS register test got: 0x%08X expected: " - "0x%08X\n", after, value); + e_err("failed STATUS register test got: 0x%08X expected: 0x%08X\n", + after, value); *data = 1; return 1; } @@ -813,15 +812,15 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) } REG_PATTERN_TEST(E1000_RDTR, 0x0000FFFF, 0xFFFFFFFF); - REG_PATTERN_TEST(E1000_RDBAH, 0xFFFFFFFF, 0xFFFFFFFF); - REG_PATTERN_TEST(E1000_RDLEN, 0x000FFF80, 0x000FFFFF); - REG_PATTERN_TEST(E1000_RDH, 0x0000FFFF, 0x0000FFFF); - REG_PATTERN_TEST(E1000_RDT, 0x0000FFFF, 0x0000FFFF); + REG_PATTERN_TEST(E1000_RDBAH(0), 0xFFFFFFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_RDLEN(0), 0x000FFF80, 0x000FFFFF); + REG_PATTERN_TEST(E1000_RDH(0), 0x0000FFFF, 0x0000FFFF); + REG_PATTERN_TEST(E1000_RDT(0), 0x0000FFFF, 0x0000FFFF); REG_PATTERN_TEST(E1000_FCRTH, 0x0000FFF8, 0x0000FFF8); REG_PATTERN_TEST(E1000_FCTTV, 0x0000FFFF, 0x0000FFFF); REG_PATTERN_TEST(E1000_TIPG, 0x3FFFFFFF, 0x3FFFFFFF); - REG_PATTERN_TEST(E1000_TDBAH, 0xFFFFFFFF, 0xFFFFFFFF); - REG_PATTERN_TEST(E1000_TDLEN, 0x000FFF80, 0x000FFFFF); + REG_PATTERN_TEST(E1000_TDBAH(0), 0xFFFFFFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_TDLEN(0), 0x000FFF80, 0x000FFFFF); REG_SET_AND_CHECK(E1000_RCTL, 0xFFFFFFFF, 0x00000000); @@ -830,29 +829,41 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) REG_SET_AND_CHECK(E1000_TCTL, 0xFFFFFFFF, 0x00000000); REG_SET_AND_CHECK(E1000_RCTL, before, 0xFFFFFFFF); - REG_PATTERN_TEST(E1000_RDBAL, 0xFFFFFFF0, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_RDBAL(0), 0xFFFFFFF0, 0xFFFFFFFF); if (!(adapter->flags & FLAG_IS_ICH)) REG_PATTERN_TEST(E1000_TXCW, 0xC000FFFF, 0x0000FFFF); - REG_PATTERN_TEST(E1000_TDBAL, 0xFFFFFFF0, 0xFFFFFFFF); + REG_PATTERN_TEST(E1000_TDBAL(0), 0xFFFFFFF0, 0xFFFFFFFF); REG_PATTERN_TEST(E1000_TIDV, 0x0000FFFF, 0x0000FFFF); mask = 0x8003FFFF; switch (mac->type) { case e1000_ich10lan: case e1000_pchlan: case e1000_pch2lan: + case e1000_pch_lpt: mask |= (1 << 18); break; default: break; } - for (i = 0; i < mac->rar_entry_count; i++) + + if (mac->type == e1000_pch_lpt) + wlock_mac = (er32(FWSM) & E1000_FWSM_WLOCK_MAC_MASK) >> + E1000_FWSM_WLOCK_MAC_SHIFT; + + for (i = 0; i < mac->rar_entry_count; i++) { + /* Cannot test write-protected SHRAL[n] registers */ + if ((wlock_mac == 1) || (wlock_mac && (i > wlock_mac))) + continue; + REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1), - mask, 0xFFFFFFFF); + mask, 0xFFFFFFFF); + } for (i = 0; i < mac->mta_reg_count; i++) REG_PATTERN_TEST_ARRAY(E1000_MTA, i, 0xFFFFFFFF, 0xFFFFFFFF); *data = 0; + return 0; } @@ -1104,11 +1115,11 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter) tx_ring->next_to_use = 0; tx_ring->next_to_clean = 0; - ew32(TDBAL, ((u64) tx_ring->dma & 0x00000000FFFFFFFF)); - ew32(TDBAH, ((u64) tx_ring->dma >> 32)); - ew32(TDLEN, tx_ring->count * sizeof(struct e1000_tx_desc)); - ew32(TDH, 0); - ew32(TDT, 0); + ew32(TDBAL(0), ((u64) tx_ring->dma & 0x00000000FFFFFFFF)); + ew32(TDBAH(0), ((u64) tx_ring->dma >> 32)); + ew32(TDLEN(0), tx_ring->count * sizeof(struct e1000_tx_desc)); + ew32(TDH(0), 0); + ew32(TDT(0), 0); ew32(TCTL, E1000_TCTL_PSP | E1000_TCTL_EN | E1000_TCTL_MULR | E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT | E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT); @@ -1168,11 +1179,11 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter) rctl = er32(RCTL); if (!(adapter->flags2 & FLAG2_NO_DISABLE_RX)) ew32(RCTL, rctl & ~E1000_RCTL_EN); - ew32(RDBAL, ((u64) rx_ring->dma & 0xFFFFFFFF)); - ew32(RDBAH, ((u64) rx_ring->dma >> 32)); - ew32(RDLEN, rx_ring->size); - ew32(RDH, 0); - ew32(RDT, 0); + ew32(RDBAL(0), ((u64) rx_ring->dma & 0xFFFFFFFF)); + ew32(RDBAH(0), ((u64) rx_ring->dma >> 32)); + ew32(RDLEN(0), rx_ring->size); + ew32(RDH(0), 0); + ew32(RDT(0), 0); rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 | E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_LPE | E1000_RCTL_SBP | E1000_RCTL_SECRC | @@ -1534,7 +1545,7 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter) int ret_val = 0; unsigned long time; - ew32(RDT, rx_ring->count - 1); + ew32(RDT(0), rx_ring->count - 1); /* * Calculate the loop count based on the largest descriptor ring @@ -1561,7 +1572,7 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter) if (k == tx_ring->count) k = 0; } - ew32(TDT, k); + ew32(TDT(0), k); e1e_flush(); msleep(200); time = jiffies; /* set the start time for the receive */ @@ -1791,8 +1802,7 @@ static void e1000_get_wol(struct net_device *netdev, wol->supported &= ~WAKE_UCAST; if (adapter->wol & E1000_WUFC_EX) - e_err("Interface does not support directed (unicast) " - "frame wake-up packets\n"); + e_err("Interface does not support directed (unicast) frame wake-up packets\n"); } if (adapter->wol & E1000_WUFC_EX) diff --git a/trunk/drivers/net/ethernet/intel/e1000e/hw.h b/trunk/drivers/net/ethernet/intel/e1000e/hw.h index f82ecf536c8b..ed5b40985edb 100644 --- a/trunk/drivers/net/ethernet/intel/e1000e/hw.h +++ b/trunk/drivers/net/ethernet/intel/e1000e/hw.h @@ -36,16 +36,6 @@ struct e1000_adapter; #include "defines.h" -#define er32(reg) __er32(hw, E1000_##reg) -#define ew32(reg,val) __ew32(hw, E1000_##reg, (val)) -#define e1e_flush() er32(STATUS) - -#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) \ - (writel((value), ((a)->hw_addr + reg + ((offset) << 2)))) - -#define E1000_READ_REG_ARRAY(a, reg, offset) \ - (readl((a)->hw_addr + reg + ((offset) << 2))) - enum e1e_registers { E1000_CTRL = 0x00000, /* Device Control - RW */ E1000_STATUS = 0x00008, /* Device Status - RO */ @@ -61,6 +51,7 @@ enum e1e_registers { E1000_FEXTNVM = 0x00028, /* Future Extended NVM - RW */ E1000_FCT = 0x00030, /* Flow Control Type - RW */ E1000_VET = 0x00038, /* VLAN Ether Type - RW */ + E1000_FEXTNVM3 = 0x0003C, /* Future Extended NVM 3 - RW */ E1000_ICR = 0x000C0, /* Interrupt Cause Read - R/clr */ E1000_ITR = 0x000C4, /* Interrupt Throttling Rate - RW */ E1000_ICS = 0x000C8, /* Interrupt Cause Set - WO */ @@ -94,31 +85,40 @@ enum e1e_registers { E1000_FCRTL = 0x02160, /* Flow Control Receive Threshold Low - RW */ E1000_FCRTH = 0x02168, /* Flow Control Receive Threshold High - RW */ E1000_PSRCTL = 0x02170, /* Packet Split Receive Control - RW */ - E1000_RDBAL = 0x02800, /* Rx Descriptor Base Address Low - RW */ - E1000_RDBAH = 0x02804, /* Rx Descriptor Base Address High - RW */ - E1000_RDLEN = 0x02808, /* Rx Descriptor Length - RW */ - E1000_RDH = 0x02810, /* Rx Descriptor Head - RW */ - E1000_RDT = 0x02818, /* Rx Descriptor Tail - RW */ - E1000_RDTR = 0x02820, /* Rx Delay Timer - RW */ - E1000_RXDCTL_BASE = 0x02828, /* Rx Descriptor Control - RW */ -#define E1000_RXDCTL(_n) (E1000_RXDCTL_BASE + (_n << 8)) - E1000_RADV = 0x0282C, /* Rx Interrupt Absolute Delay Timer - RW */ - -/* Convenience macros +/* + * Convenience macros * * Note: "_n" is the queue number of the register to be written to. * * Example usage: - * E1000_RDBAL_REG(current_rx_queue) - * + * E1000_RDBAL(current_rx_queue) */ -#define E1000_RDBAL_REG(_n) (E1000_RDBAL + (_n << 8)) + E1000_RDBAL_BASE = 0x02800, /* Rx Descriptor Base Address Low - RW */ +#define E1000_RDBAL(_n) (E1000_RDBAL_BASE + (_n << 8)) + E1000_RDBAH_BASE = 0x02804, /* Rx Descriptor Base Address High - RW */ +#define E1000_RDBAH(_n) (E1000_RDBAH_BASE + (_n << 8)) + E1000_RDLEN_BASE = 0x02808, /* Rx Descriptor Length - RW */ +#define E1000_RDLEN(_n) (E1000_RDLEN_BASE + (_n << 8)) + E1000_RDH_BASE = 0x02810, /* Rx Descriptor Head - RW */ +#define E1000_RDH(_n) (E1000_RDH_BASE + (_n << 8)) + E1000_RDT_BASE = 0x02818, /* Rx Descriptor Tail - RW */ +#define E1000_RDT(_n) (E1000_RDT_BASE + (_n << 8)) + E1000_RDTR = 0x02820, /* Rx Delay Timer - RW */ + E1000_RXDCTL_BASE = 0x02828, /* Rx Descriptor Control - RW */ +#define E1000_RXDCTL(_n) (E1000_RXDCTL_BASE + (_n << 8)) + E1000_RADV = 0x0282C, /* Rx Interrupt Absolute Delay Timer - RW */ + E1000_KABGTXD = 0x03004, /* AFE Band Gap Transmit Ref Data */ - E1000_TDBAL = 0x03800, /* Tx Descriptor Base Address Low - RW */ - E1000_TDBAH = 0x03804, /* Tx Descriptor Base Address High - RW */ - E1000_TDLEN = 0x03808, /* Tx Descriptor Length - RW */ - E1000_TDH = 0x03810, /* Tx Descriptor Head - RW */ - E1000_TDT = 0x03818, /* Tx Descriptor Tail - RW */ + E1000_TDBAL_BASE = 0x03800, /* Tx Descriptor Base Address Low - RW */ +#define E1000_TDBAL(_n) (E1000_TDBAL_BASE + (_n << 8)) + E1000_TDBAH_BASE = 0x03804, /* Tx Descriptor Base Address High - RW */ +#define E1000_TDBAH(_n) (E1000_TDBAH_BASE + (_n << 8)) + E1000_TDLEN_BASE = 0x03808, /* Tx Descriptor Length - RW */ +#define E1000_TDLEN(_n) (E1000_TDLEN_BASE + (_n << 8)) + E1000_TDH_BASE = 0x03810, /* Tx Descriptor Head - RW */ +#define E1000_TDH(_n) (E1000_TDH_BASE + (_n << 8)) + E1000_TDT_BASE = 0x03818, /* Tx Descriptor Tail - RW */ +#define E1000_TDT(_n) (E1000_TDT_BASE + (_n << 8)) E1000_TIDV = 0x03820, /* Tx Interrupt Delay Value - RW */ E1000_TXDCTL_BASE = 0x03828, /* Tx Descriptor Control - RW */ #define E1000_TXDCTL(_n) (E1000_TXDCTL_BASE + (_n << 8)) @@ -200,6 +200,14 @@ enum e1e_registers { #define E1000_RA (E1000_RAL(0)) E1000_RAH_BASE = 0x05404, /* Receive Address High - RW */ #define E1000_RAH(_n) (E1000_RAH_BASE + ((_n) * 8)) + E1000_SHRAL_PCH_LPT_BASE = 0x05408, +#define E1000_SHRAL_PCH_LPT(_n) (E1000_SHRAL_PCH_LPT_BASE + ((_n) * 8)) + E1000_SHRAH_PCH_LTP_BASE = 0x0540C, +#define E1000_SHRAH_PCH_LPT(_n) (E1000_SHRAH_PCH_LTP_BASE + ((_n) * 8)) + E1000_SHRAL_BASE = 0x05438, /* Shared Receive Address Low - RW */ +#define E1000_SHRAL(_n) (E1000_SHRAL_BASE + ((_n) * 8)) + E1000_SHRAH_BASE = 0x0543C, /* Shared Receive Address High - RW */ +#define E1000_SHRAH(_n) (E1000_SHRAH_BASE + ((_n) * 8)) E1000_VFTA = 0x05600, /* VLAN Filter Table Array - RW Array */ E1000_WUC = 0x05800, /* Wakeup Control - RW */ E1000_WUFC = 0x05808, /* Wakeup Filter Control - RW */ @@ -402,6 +410,8 @@ enum e1e_registers { #define E1000_DEV_ID_PCH_D_HV_DC 0x10F0 #define E1000_DEV_ID_PCH2_LV_LM 0x1502 #define E1000_DEV_ID_PCH2_LV_V 0x1503 +#define E1000_DEV_ID_PCH_LPT_I217_LM 0x153A +#define E1000_DEV_ID_PCH_LPT_I217_V 0x153B #define E1000_REVISION_4 4 @@ -422,6 +432,7 @@ enum e1000_mac_type { e1000_ich10lan, e1000_pchlan, e1000_pch2lan, + e1000_pch_lpt, }; enum e1000_media_type { @@ -459,6 +470,7 @@ enum e1000_phy_type { e1000_phy_82578, e1000_phy_82577, e1000_phy_82579, + e1000_phy_i217, }; enum e1000_bus_width { @@ -782,6 +794,7 @@ struct e1000_mac_operations { s32 (*setup_led)(struct e1000_hw *); void (*write_vfta)(struct e1000_hw *, u32, u32); void (*config_collision_dist)(struct e1000_hw *); + void (*rar_set)(struct e1000_hw *, u8 *, u32); s32 (*read_mac_addr)(struct e1000_hw *); }; @@ -966,6 +979,7 @@ struct e1000_dev_spec_ich8lan { struct e1000_shadow_ram shadow_ram[E1000_ICH8_SHADOW_RAM_WORDS]; bool nvm_k1_enabled; bool eee_disable; + u16 eee_lp_ability; }; struct e1000_hw { diff --git a/trunk/drivers/net/ethernet/intel/e1000e/ich8lan.c b/trunk/drivers/net/ethernet/intel/e1000e/ich8lan.c index b461c24945e3..bbf70ba367da 100644 --- a/trunk/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/trunk/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -105,6 +105,9 @@ #define E1000_FEXTNVM_SW_CONFIG 1 #define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* Bit redefined for ICH8M :/ */ +#define E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK 0x0C000000 +#define E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC 0x08000000 + #define E1000_FEXTNVM4_BEACON_DURATION_MASK 0x7 #define E1000_FEXTNVM4_BEACON_DURATION_8USEC 0x7 #define E1000_FEXTNVM4_BEACON_DURATION_16USEC 0x3 @@ -112,6 +115,8 @@ #define PCIE_ICH8_SNOOP_ALL PCIE_NO_SNOOP_ALL #define E1000_ICH_RAR_ENTRIES 7 +#define E1000_PCH2_RAR_ENTRIES 5 /* RAR[0], SHRA[0-3] */ +#define E1000_PCH_LPT_RAR_ENTRIES 12 /* RAR[0], SHRA[0-10] */ #define PHY_PAGE_SHIFT 5 #define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \ @@ -127,14 +132,22 @@ #define SW_FLAG_TIMEOUT 1000 /* SW Semaphore flag timeout in milliseconds */ +/* SMBus Control Phy Register */ +#define CV_SMB_CTRL PHY_REG(769, 23) +#define CV_SMB_CTRL_FORCE_SMBUS 0x0001 + /* SMBus Address Phy Register */ #define HV_SMB_ADDR PHY_REG(768, 26) #define HV_SMB_ADDR_MASK 0x007F #define HV_SMB_ADDR_PEC_EN 0x0200 #define HV_SMB_ADDR_VALID 0x0080 +#define HV_SMB_ADDR_FREQ_MASK 0x1100 +#define HV_SMB_ADDR_FREQ_LOW_SHIFT 8 +#define HV_SMB_ADDR_FREQ_HIGH_SHIFT 12 /* PHY Power Management Control */ #define HV_PM_CTRL PHY_REG(770, 17) +#define HV_PM_CTRL_PLL_STOP_IN_K1_GIGA 0x100 /* PHY Low Power Idle Control */ #define I82579_LPI_CTRL PHY_REG(772, 20) @@ -147,11 +160,26 @@ #define I82579_LPI_UPDATE_TIMER 0x4805 /* in 40ns units + 40 ns base value */ #define I82579_MSE_THRESHOLD 0x084F /* Mean Square Error Threshold */ #define I82579_MSE_LINK_DOWN 0x2411 /* MSE count before dropping link */ +#define I217_EEE_ADVERTISEMENT 0x8001 /* IEEE MMD Register 7.60 */ +#define I217_EEE_LP_ABILITY 0x8002 /* IEEE MMD Register 7.61 */ +#define I217_EEE_100_SUPPORTED (1 << 1) /* 100BaseTx EEE supported */ + +/* Intel Rapid Start Technology Support */ +#define I217_PROXY_CTRL PHY_REG(BM_WUC_PAGE, 70) +#define I217_PROXY_CTRL_AUTO_DISABLE 0x0080 +#define I217_SxCTRL PHY_REG(BM_PORT_CTRL_PAGE, 28) +#define I217_SxCTRL_MASK 0x1000 +#define I217_CGFREG PHY_REG(772, 29) +#define I217_CGFREG_MASK 0x0002 +#define I217_MEMPWR PHY_REG(772, 26) +#define I217_MEMPWR_MASK 0x0010 /* Strapping Option Register - RO */ #define E1000_STRAP 0x0000C #define E1000_STRAP_SMBUS_ADDRESS_MASK 0x00FE0000 #define E1000_STRAP_SMBUS_ADDRESS_SHIFT 17 +#define E1000_STRAP_SMT_FREQ_MASK 0x00003000 +#define E1000_STRAP_SMT_FREQ_SHIFT 12 /* OEM Bits Phy Register */ #define HV_OEM_BITS PHY_REG(768, 25) @@ -255,6 +283,8 @@ static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link); static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw); static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw); static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw); +static void e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index); +static void e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index); static s32 e1000_k1_workaround_lv(struct e1000_hw *hw); static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate); @@ -283,18 +313,161 @@ static inline void __ew32flash(struct e1000_hw *hw, unsigned long reg, u32 val) #define ew16flash(reg, val) __ew16flash(hw, (reg), (val)) #define ew32flash(reg, val) __ew32flash(hw, (reg), (val)) -static void e1000_toggle_lanphypc_value_ich8lan(struct e1000_hw *hw) +/** + * e1000_phy_is_accessible_pchlan - Check if able to access PHY registers + * @hw: pointer to the HW structure + * + * Test access to the PHY registers by reading the PHY ID registers. If + * the PHY ID is already known (e.g. resume path) compare it with known ID, + * otherwise assume the read PHY ID is correct if it is valid. + * + * Assumes the sw/fw/hw semaphore is already acquired. + **/ +static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw) { - u32 ctrl; + u16 phy_reg; + u32 phy_id; - ctrl = er32(CTRL); - ctrl |= E1000_CTRL_LANPHYPC_OVERRIDE; - ctrl &= ~E1000_CTRL_LANPHYPC_VALUE; - ew32(CTRL, ctrl); - e1e_flush(); - udelay(10); - ctrl &= ~E1000_CTRL_LANPHYPC_OVERRIDE; - ew32(CTRL, ctrl); + e1e_rphy_locked(hw, PHY_ID1, &phy_reg); + phy_id = (u32)(phy_reg << 16); + e1e_rphy_locked(hw, PHY_ID2, &phy_reg); + phy_id |= (u32)(phy_reg & PHY_REVISION_MASK); + + if (hw->phy.id) { + if (hw->phy.id == phy_id) + return true; + } else { + if ((phy_id != 0) && (phy_id != PHY_REVISION_MASK)) + hw->phy.id = phy_id; + return true; + } + + return false; +} + +/** + * e1000_init_phy_workarounds_pchlan - PHY initialization workarounds + * @hw: pointer to the HW structure + * + * Workarounds/flow necessary for PHY initialization during driver load + * and resume paths. + **/ +static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw) +{ + u32 mac_reg, fwsm = er32(FWSM); + s32 ret_val; + u16 phy_reg; + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) { + e_dbg("Failed to initialize PHY flow\n"); + return ret_val; + } + + /* + * The MAC-PHY interconnect may be in SMBus mode. If the PHY is + * inaccessible and resetting the PHY is not blocked, toggle the + * LANPHYPC Value bit to force the interconnect to PCIe mode. + */ + switch (hw->mac.type) { + case e1000_pch_lpt: + if (e1000_phy_is_accessible_pchlan(hw)) + break; + + /* + * Before toggling LANPHYPC, see if PHY is accessible by + * forcing MAC to SMBus mode first. + */ + mac_reg = er32(CTRL_EXT); + mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS; + ew32(CTRL_EXT, mac_reg); + + /* fall-through */ + case e1000_pch2lan: + /* + * Gate automatic PHY configuration by hardware on + * non-managed 82579 + */ + if ((hw->mac.type == e1000_pch2lan) && + !(fwsm & E1000_ICH_FWSM_FW_VALID)) + e1000_gate_hw_phy_config_ich8lan(hw, true); + + if (e1000_phy_is_accessible_pchlan(hw)) { + if (hw->mac.type == e1000_pch_lpt) { + /* Unforce SMBus mode in PHY */ + e1e_rphy_locked(hw, CV_SMB_CTRL, &phy_reg); + phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS; + e1e_wphy_locked(hw, CV_SMB_CTRL, phy_reg); + + /* Unforce SMBus mode in MAC */ + mac_reg = er32(CTRL_EXT); + mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS; + ew32(CTRL_EXT, mac_reg); + } + break; + } + + /* fall-through */ + case e1000_pchlan: + if ((hw->mac.type == e1000_pchlan) && + (fwsm & E1000_ICH_FWSM_FW_VALID)) + break; + + if (hw->phy.ops.check_reset_block(hw)) { + e_dbg("Required LANPHYPC toggle blocked by ME\n"); + break; + } + + e_dbg("Toggling LANPHYPC\n"); + + /* Set Phy Config Counter to 50msec */ + mac_reg = er32(FEXTNVM3); + mac_reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK; + mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC; + ew32(FEXTNVM3, mac_reg); + + /* Toggle LANPHYPC Value bit */ + mac_reg = er32(CTRL); + mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE; + mac_reg &= ~E1000_CTRL_LANPHYPC_VALUE; + ew32(CTRL, mac_reg); + e1e_flush(); + udelay(10); + mac_reg &= ~E1000_CTRL_LANPHYPC_OVERRIDE; + ew32(CTRL, mac_reg); + e1e_flush(); + if (hw->mac.type < e1000_pch_lpt) { + msleep(50); + } else { + u16 count = 20; + do { + usleep_range(5000, 10000); + } while (!(er32(CTRL_EXT) & + E1000_CTRL_EXT_LPCD) && count--); + } + break; + default: + break; + } + + hw->phy.ops.release(hw); + + /* + * Reset the PHY before any access to it. Doing so, ensures + * that the PHY is in a known good state before we read/write + * PHY registers. The generic reset is sufficient here, + * because we haven't determined the PHY type yet. + */ + ret_val = e1000e_phy_hw_reset_generic(hw); + + /* Ungate automatic PHY configuration on non-managed 82579 */ + if ((hw->mac.type == e1000_pch2lan) && + !(fwsm & E1000_ICH_FWSM_FW_VALID)) { + usleep_range(10000, 20000); + e1000_gate_hw_phy_config_ich8lan(hw, false); + } + + return ret_val; } /** @@ -324,70 +497,41 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) phy->ops.power_down = e1000_power_down_phy_copper_ich8lan; phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; - if (!hw->phy.ops.check_reset_block(hw)) { - u32 fwsm = er32(FWSM); - - /* - * The MAC-PHY interconnect may still be in SMBus mode after - * Sx->S0. If resetting the PHY is not blocked, toggle the - * LANPHYPC Value bit to force the interconnect to PCIe mode. - */ - e1000_toggle_lanphypc_value_ich8lan(hw); - msleep(50); - - /* - * Gate automatic PHY configuration by hardware on - * non-managed 82579 - */ - if ((hw->mac.type == e1000_pch2lan) && - !(fwsm & E1000_ICH_FWSM_FW_VALID)) - e1000_gate_hw_phy_config_ich8lan(hw, true); - - /* - * Reset the PHY before any access to it. Doing so, ensures - * that the PHY is in a known good state before we read/write - * PHY registers. The generic reset is sufficient here, - * because we haven't determined the PHY type yet. - */ - ret_val = e1000e_phy_hw_reset_generic(hw); - if (ret_val) - return ret_val; + phy->id = e1000_phy_unknown; - /* Ungate automatic PHY configuration on non-managed 82579 */ - if ((hw->mac.type == e1000_pch2lan) && - !(fwsm & E1000_ICH_FWSM_FW_VALID)) { - usleep_range(10000, 20000); - e1000_gate_hw_phy_config_ich8lan(hw, false); - } - } + ret_val = e1000_init_phy_workarounds_pchlan(hw); + if (ret_val) + return ret_val; - phy->id = e1000_phy_unknown; - switch (hw->mac.type) { - default: - ret_val = e1000e_get_phy_id(hw); - if (ret_val) - return ret_val; - if ((phy->id != 0) && (phy->id != PHY_REVISION_MASK)) + if (phy->id == e1000_phy_unknown) + switch (hw->mac.type) { + default: + ret_val = e1000e_get_phy_id(hw); + if (ret_val) + return ret_val; + if ((phy->id != 0) && (phy->id != PHY_REVISION_MASK)) + break; + /* fall-through */ + case e1000_pch2lan: + case e1000_pch_lpt: + /* + * In case the PHY needs to be in mdio slow mode, + * set slow mode and try to get the PHY id again. + */ + ret_val = e1000_set_mdio_slow_mode_hv(hw); + if (ret_val) + return ret_val; + ret_val = e1000e_get_phy_id(hw); + if (ret_val) + return ret_val; break; - /* fall-through */ - case e1000_pch2lan: - /* - * In case the PHY needs to be in mdio slow mode, - * set slow mode and try to get the PHY id again. - */ - ret_val = e1000_set_mdio_slow_mode_hv(hw); - if (ret_val) - return ret_val; - ret_val = e1000e_get_phy_id(hw); - if (ret_val) - return ret_val; - break; - } + } phy->type = e1000e_get_phy_type_from_id(phy->id); switch (phy->type) { case e1000_phy_82577: case e1000_phy_82579: + case e1000_phy_i217: phy->ops.check_polarity = e1000_check_polarity_82577; phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_82577; @@ -572,7 +716,7 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw) /* Adaptive IFS supported */ mac->adaptive_ifs = true; - /* LED operations */ + /* LED and other operations */ switch (mac->type) { case e1000_ich8lan: case e1000_ich9lan: @@ -591,8 +735,12 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw) mac->ops.led_on = e1000_led_on_ich8lan; mac->ops.led_off = e1000_led_off_ich8lan; break; - case e1000_pchlan: case e1000_pch2lan: + mac->rar_entry_count = E1000_PCH2_RAR_ENTRIES; + mac->ops.rar_set = e1000_rar_set_pch2lan; + /* fall-through */ + case e1000_pch_lpt: + case e1000_pchlan: /* check management mode */ mac->ops.check_mng_mode = e1000_check_mng_mode_pchlan; /* ID LED init */ @@ -609,12 +757,20 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw) break; } + if (mac->type == e1000_pch_lpt) { + mac->rar_entry_count = E1000_PCH_LPT_RAR_ENTRIES; + mac->ops.rar_set = e1000_rar_set_pch_lpt; + } + /* Enable PCS Lock-loss workaround for ICH8 */ if (mac->type == e1000_ich8lan) e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, true); - /* Gate automatic PHY configuration by hardware on managed 82579 */ - if ((mac->type == e1000_pch2lan) && + /* + * Gate automatic PHY configuration by hardware on managed + * 82579 and i217 + */ + if ((mac->type == e1000_pch2lan || mac->type == e1000_pch_lpt) && (er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) e1000_gate_hw_phy_config_ich8lan(hw, true); @@ -630,22 +786,50 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw) **/ static s32 e1000_set_eee_pchlan(struct e1000_hw *hw) { + struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; s32 ret_val = 0; u16 phy_reg; - if (hw->phy.type != e1000_phy_82579) + if ((hw->phy.type != e1000_phy_82579) && + (hw->phy.type != e1000_phy_i217)) return 0; ret_val = e1e_rphy(hw, I82579_LPI_CTRL, &phy_reg); if (ret_val) return ret_val; - if (hw->dev_spec.ich8lan.eee_disable) + if (dev_spec->eee_disable) phy_reg &= ~I82579_LPI_CTRL_ENABLE_MASK; else phy_reg |= I82579_LPI_CTRL_ENABLE_MASK; - return e1e_wphy(hw, I82579_LPI_CTRL, phy_reg); + ret_val = e1e_wphy(hw, I82579_LPI_CTRL, phy_reg); + if (ret_val) + return ret_val; + + if ((hw->phy.type == e1000_phy_i217) && !dev_spec->eee_disable) { + /* Save off link partner's EEE ability */ + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + return ret_val; + ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR, + I217_EEE_LP_ABILITY); + if (ret_val) + goto release; + e1e_rphy_locked(hw, I82579_EMI_DATA, &dev_spec->eee_lp_ability); + + /* + * EEE is not supported in 100Half, so ignore partner's EEE + * in 100 ability if full-duplex is not advertised. + */ + e1e_rphy_locked(hw, PHY_LP_ABILITY, &phy_reg); + if (!(phy_reg & NWAY_LPAR_100TX_FD_CAPS)) + dev_spec->eee_lp_ability &= ~I217_EEE_100_SUPPORTED; +release: + hw->phy.ops.release(hw); + } + + return 0; } /** @@ -687,6 +871,9 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) return ret_val; } + /* Clear link partner's EEE ability */ + hw->dev_spec.ich8lan.eee_lp_ability = 0; + if (!link) return 0; /* No link detected */ @@ -782,6 +969,7 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter) break; case e1000_pchlan: case e1000_pch2lan: + case e1000_pch_lpt: rc = e1000_init_phy_params_pchlan(hw); break; default: @@ -966,6 +1154,145 @@ static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw) (fwsm & (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT)); } +/** + * e1000_rar_set_pch2lan - Set receive address register + * @hw: pointer to the HW structure + * @addr: pointer to the receive address + * @index: receive address array register + * + * Sets the receive address array register at index to the address passed + * in by addr. For 82579, RAR[0] is the base address register that is to + * contain the MAC address but RAR[1-6] are reserved for manageability (ME). + * Use SHRA[0-3] in place of those reserved for ME. + **/ +static void e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index) +{ + u32 rar_low, rar_high; + + /* + * HW expects these in little endian so we reverse the byte order + * from network order (big endian) to little endian + */ + rar_low = ((u32)addr[0] | + ((u32)addr[1] << 8) | + ((u32)addr[2] << 16) | ((u32)addr[3] << 24)); + + rar_high = ((u32)addr[4] | ((u32)addr[5] << 8)); + + /* If MAC address zero, no need to set the AV bit */ + if (rar_low || rar_high) + rar_high |= E1000_RAH_AV; + + if (index == 0) { + ew32(RAL(index), rar_low); + e1e_flush(); + ew32(RAH(index), rar_high); + e1e_flush(); + return; + } + + if (index < hw->mac.rar_entry_count) { + s32 ret_val; + + ret_val = e1000_acquire_swflag_ich8lan(hw); + if (ret_val) + goto out; + + ew32(SHRAL(index - 1), rar_low); + e1e_flush(); + ew32(SHRAH(index - 1), rar_high); + e1e_flush(); + + e1000_release_swflag_ich8lan(hw); + + /* verify the register updates */ + if ((er32(SHRAL(index - 1)) == rar_low) && + (er32(SHRAH(index - 1)) == rar_high)) + return; + + e_dbg("SHRA[%d] might be locked by ME - FWSM=0x%8.8x\n", + (index - 1), er32(FWSM)); + } + +out: + e_dbg("Failed to write receive address at index %d\n", index); +} + +/** + * e1000_rar_set_pch_lpt - Set receive address registers + * @hw: pointer to the HW structure + * @addr: pointer to the receive address + * @index: receive address array register + * + * Sets the receive address register array at index to the address passed + * in by addr. For LPT, RAR[0] is the base address register that is to + * contain the MAC address. SHRA[0-10] are the shared receive address + * registers that are shared between the Host and manageability engine (ME). + **/ +static void e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index) +{ + u32 rar_low, rar_high; + u32 wlock_mac; + + /* + * HW expects these in little endian so we reverse the byte order + * from network order (big endian) to little endian + */ + rar_low = ((u32)addr[0] | ((u32)addr[1] << 8) | + ((u32)addr[2] << 16) | ((u32)addr[3] << 24)); + + rar_high = ((u32)addr[4] | ((u32)addr[5] << 8)); + + /* If MAC address zero, no need to set the AV bit */ + if (rar_low || rar_high) + rar_high |= E1000_RAH_AV; + + if (index == 0) { + ew32(RAL(index), rar_low); + e1e_flush(); + ew32(RAH(index), rar_high); + e1e_flush(); + return; + } + + /* + * The manageability engine (ME) can lock certain SHRAR registers that + * it is using - those registers are unavailable for use. + */ + if (index < hw->mac.rar_entry_count) { + wlock_mac = er32(FWSM) & E1000_FWSM_WLOCK_MAC_MASK; + wlock_mac >>= E1000_FWSM_WLOCK_MAC_SHIFT; + + /* Check if all SHRAR registers are locked */ + if (wlock_mac == 1) + goto out; + + if ((wlock_mac == 0) || (index <= wlock_mac)) { + s32 ret_val; + + ret_val = e1000_acquire_swflag_ich8lan(hw); + + if (ret_val) + goto out; + + ew32(SHRAL_PCH_LPT(index - 1), rar_low); + e1e_flush(); + ew32(SHRAH_PCH_LPT(index - 1), rar_high); + e1e_flush(); + + e1000_release_swflag_ich8lan(hw); + + /* verify the register updates */ + if ((er32(SHRAL_PCH_LPT(index - 1)) == rar_low) && + (er32(SHRAH_PCH_LPT(index - 1)) == rar_high)) + return; + } + } + +out: + e_dbg("Failed to write receive address at index %d\n", index); +} + /** * e1000_check_reset_block_ich8lan - Check if PHY reset is blocked * @hw: pointer to the HW structure @@ -994,6 +1321,8 @@ static s32 e1000_write_smbus_addr(struct e1000_hw *hw) { u16 phy_data; u32 strap = er32(STRAP); + u32 freq = (strap & E1000_STRAP_SMT_FREQ_MASK) >> + E1000_STRAP_SMT_FREQ_SHIFT; s32 ret_val = 0; strap &= E1000_STRAP_SMBUS_ADDRESS_MASK; @@ -1006,6 +1335,19 @@ static s32 e1000_write_smbus_addr(struct e1000_hw *hw) phy_data |= (strap >> E1000_STRAP_SMBUS_ADDRESS_SHIFT); phy_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID; + if (hw->phy.type == e1000_phy_i217) { + /* Restore SMBus frequency */ + if (freq--) { + phy_data &= ~HV_SMB_ADDR_FREQ_MASK; + phy_data |= (freq & (1 << 0)) << + HV_SMB_ADDR_FREQ_LOW_SHIFT; + phy_data |= (freq & (1 << 1)) << + (HV_SMB_ADDR_FREQ_HIGH_SHIFT - 1); + } else { + e_dbg("Unsupported SMB frequency in PHY\n"); + } + } + return e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR, phy_data); } @@ -1043,6 +1385,7 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw) /* Fall-thru */ case e1000_pchlan: case e1000_pch2lan: + case e1000_pch_lpt: sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M; break; default: @@ -1062,10 +1405,9 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw) * extended configuration before SW configuration */ data = er32(EXTCNF_CTRL); - if (!(hw->mac.type == e1000_pch2lan)) { - if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE) - goto release; - } + if ((hw->mac.type < e1000_pch2lan) && + (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)) + goto release; cnf_size = er32(EXTCNF_SIZE); cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK; @@ -1076,9 +1418,9 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw) cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK; cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT; - if ((!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) && - (hw->mac.type == e1000_pchlan)) || - (hw->mac.type == e1000_pch2lan)) { + if (((hw->mac.type == e1000_pchlan) && + !(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)) || + (hw->mac.type > e1000_pchlan)) { /* * HW configures the SMBus address and LEDs when the * OEM and LCD Write Enable bits are set in the NVM. @@ -1121,8 +1463,7 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw) reg_addr &= PHY_REG_MASK; reg_addr |= phy_page; - ret_val = phy->ops.write_reg_locked(hw, (u32)reg_addr, - reg_data); + ret_val = e1e_wphy_locked(hw, (u32)reg_addr, reg_data); if (ret_val) goto release; } @@ -1159,8 +1500,8 @@ static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link) /* Disable K1 when link is 1Gbps, otherwise use the NVM setting */ if (link) { if (hw->phy.type == e1000_phy_82578) { - ret_val = hw->phy.ops.read_reg_locked(hw, BM_CS_STATUS, - &status_reg); + ret_val = e1e_rphy_locked(hw, BM_CS_STATUS, + &status_reg); if (ret_val) goto release; @@ -1175,8 +1516,7 @@ static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link) } if (hw->phy.type == e1000_phy_82577) { - ret_val = hw->phy.ops.read_reg_locked(hw, HV_M_STATUS, - &status_reg); + ret_val = e1e_rphy_locked(hw, HV_M_STATUS, &status_reg); if (ret_val) goto release; @@ -1191,15 +1531,13 @@ static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link) } /* Link stall fix for link up */ - ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19), - 0x0100); + ret_val = e1e_wphy_locked(hw, PHY_REG(770, 19), 0x0100); if (ret_val) goto release; } else { /* Link stall fix for link down */ - ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19), - 0x4100); + ret_val = e1e_wphy_locked(hw, PHY_REG(770, 19), 0x4100); if (ret_val) goto release; } @@ -1279,14 +1617,14 @@ static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state) u32 mac_reg; u16 oem_reg; - if ((hw->mac.type != e1000_pch2lan) && (hw->mac.type != e1000_pchlan)) + if (hw->mac.type < e1000_pchlan) return ret_val; ret_val = hw->phy.ops.acquire(hw); if (ret_val) return ret_val; - if (!(hw->mac.type == e1000_pch2lan)) { + if (hw->mac.type == e1000_pchlan) { mac_reg = er32(EXTCNF_CTRL); if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) goto release; @@ -1298,7 +1636,7 @@ static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state) mac_reg = er32(PHY_CTRL); - ret_val = hw->phy.ops.read_reg_locked(hw, HV_OEM_BITS, &oem_reg); + ret_val = e1e_rphy_locked(hw, HV_OEM_BITS, &oem_reg); if (ret_val) goto release; @@ -1325,7 +1663,7 @@ static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state) !hw->phy.ops.check_reset_block(hw)) oem_reg |= HV_OEM_BITS_RESTART_AN; - ret_val = hw->phy.ops.write_reg_locked(hw, HV_OEM_BITS, oem_reg); + ret_val = e1e_wphy_locked(hw, HV_OEM_BITS, oem_reg); release: hw->phy.ops.release(hw); @@ -1421,11 +1759,10 @@ static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw) ret_val = hw->phy.ops.acquire(hw); if (ret_val) return ret_val; - ret_val = hw->phy.ops.read_reg_locked(hw, BM_PORT_GEN_CFG, &phy_data); + ret_val = e1e_rphy_locked(hw, BM_PORT_GEN_CFG, &phy_data); if (ret_val) goto release; - ret_val = hw->phy.ops.write_reg_locked(hw, BM_PORT_GEN_CFG, - phy_data & 0x00FF); + ret_val = e1e_wphy_locked(hw, BM_PORT_GEN_CFG, phy_data & 0x00FF); release: hw->phy.ops.release(hw); @@ -1484,7 +1821,7 @@ s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable) u32 mac_reg; u16 i; - if (hw->mac.type != e1000_pch2lan) + if (hw->mac.type < e1000_pch2lan) return 0; /* disable Rx path while enabling/disabling workaround */ @@ -1657,20 +1994,18 @@ static s32 e1000_lv_phy_workarounds_ich8lan(struct e1000_hw *hw) ret_val = hw->phy.ops.acquire(hw); if (ret_val) return ret_val; - ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_ADDR, - I82579_MSE_THRESHOLD); + ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR, I82579_MSE_THRESHOLD); if (ret_val) goto release; /* set MSE higher to enable link to stay up when noise is high */ - ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_DATA, 0x0034); + ret_val = e1e_wphy_locked(hw, I82579_EMI_DATA, 0x0034); if (ret_val) goto release; - ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_ADDR, - I82579_MSE_LINK_DOWN); + ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR, I82579_MSE_LINK_DOWN); if (ret_val) goto release; /* drop link after 5 times MSE threshold was reached */ - ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_DATA, 0x0005); + ret_val = e1e_wphy_locked(hw, I82579_EMI_DATA, 0x0005); release: hw->phy.ops.release(hw); @@ -1708,8 +2043,18 @@ static s32 e1000_k1_workaround_lv(struct e1000_hw *hw) return ret_val; if (status_reg & HV_M_STATUS_SPEED_1000) { + u16 pm_phy_reg; + mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_8USEC; phy_reg &= ~I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT; + /* LV 1G Packet drop issue wa */ + ret_val = e1e_rphy(hw, HV_PM_CTRL, &pm_phy_reg); + if (ret_val) + return ret_val; + pm_phy_reg &= ~HV_PM_CTRL_PLL_STOP_IN_K1_GIGA; + ret_val = e1e_wphy(hw, HV_PM_CTRL, pm_phy_reg); + if (ret_val) + return ret_val; } else { mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_16USEC; phy_reg |= I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT; @@ -1733,7 +2078,7 @@ static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate) { u32 extcnf_ctrl; - if (hw->mac.type != e1000_pch2lan) + if (hw->mac.type < e1000_pch2lan) return; extcnf_ctrl = er32(EXTCNF_CTRL); @@ -1835,12 +2180,10 @@ static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw) ret_val = hw->phy.ops.acquire(hw); if (ret_val) return ret_val; - ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_ADDR, - I82579_LPI_UPDATE_TIMER); + ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR, + I82579_LPI_UPDATE_TIMER); if (!ret_val) - ret_val = hw->phy.ops.write_reg_locked(hw, - I82579_EMI_DATA, - 0x1387); + ret_val = e1e_wphy_locked(hw, I82579_EMI_DATA, 0x1387); hw->phy.ops.release(hw); } @@ -2213,7 +2556,7 @@ static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw) hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); /* Check if the flash descriptor is valid */ - if (hsfsts.hsf_status.fldesvalid == 0) { + if (!hsfsts.hsf_status.fldesvalid) { e_dbg("Flash descriptor invalid. SW Sequencing must be used.\n"); return -E1000_ERR_NVM; } @@ -2233,7 +2576,7 @@ static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw) * completed. */ - if (hsfsts.hsf_status.flcinprog == 0) { + if (!hsfsts.hsf_status.flcinprog) { /* * There is no cycle running at present, * so we can start a cycle. @@ -2251,7 +2594,7 @@ static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw) */ for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) { hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); - if (hsfsts.hsf_status.flcinprog == 0) { + if (!hsfsts.hsf_status.flcinprog) { ret_val = 0; break; } @@ -2293,12 +2636,12 @@ static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout) /* wait till FDONE bit is set to 1 */ do { hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); - if (hsfsts.hsf_status.flcdone == 1) + if (hsfsts.hsf_status.flcdone) break; udelay(1); } while (i++ < timeout); - if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0) + if (hsfsts.hsf_status.flcdone && !hsfsts.hsf_status.flcerr) return 0; return -E1000_ERR_NVM; @@ -2409,10 +2752,10 @@ static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, * ICH_FLASH_CYCLE_REPEAT_COUNT times. */ hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); - if (hsfsts.hsf_status.flcerr == 1) { + if (hsfsts.hsf_status.flcerr) { /* Repeat for some time before giving up. */ continue; - } else if (hsfsts.hsf_status.flcdone == 0) { + } else if (!hsfsts.hsf_status.flcdone) { e_dbg("Timeout error - flash cycle did not complete.\n"); break; } @@ -2642,7 +2985,7 @@ static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw) if (ret_val) return ret_val; - if ((data & 0x40) == 0) { + if (!(data & 0x40)) { data |= 0x40; ret_val = e1000_write_nvm(hw, 0x19, 1, &data); if (ret_val) @@ -2760,10 +3103,10 @@ static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, * try...ICH_FLASH_CYCLE_REPEAT_COUNT times. */ hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); - if (hsfsts.hsf_status.flcerr == 1) + if (hsfsts.hsf_status.flcerr) /* Repeat for some time before giving up. */ continue; - if (hsfsts.hsf_status.flcdone == 0) { + if (!hsfsts.hsf_status.flcdone) { e_dbg("Timeout error - flash cycle did not complete.\n"); break; } @@ -2915,10 +3258,10 @@ static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank) * a few more times else Done */ hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); - if (hsfsts.hsf_status.flcerr == 1) + if (hsfsts.hsf_status.flcerr) /* repeat for some time before giving up */ continue; - else if (hsfsts.hsf_status.flcdone == 0) + else if (!hsfsts.hsf_status.flcdone) return ret_val; } while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT); } @@ -3060,8 +3403,8 @@ static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw) static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) { struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; - u16 reg; - u32 ctrl, kab; + u16 kum_cfg; + u32 ctrl, reg; s32 ret_val; /* @@ -3095,12 +3438,12 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) } if (hw->mac.type == e1000_pchlan) { - /* Save the NVM K1 bit setting*/ - ret_val = e1000_read_nvm(hw, E1000_NVM_K1_CONFIG, 1, ®); + /* Save the NVM K1 bit setting */ + ret_val = e1000_read_nvm(hw, E1000_NVM_K1_CONFIG, 1, &kum_cfg); if (ret_val) return ret_val; - if (reg & E1000_NVM_K1_ENABLE) + if (kum_cfg & E1000_NVM_K1_ENABLE) dev_spec->nvm_k1_enabled = true; else dev_spec->nvm_k1_enabled = false; @@ -3130,6 +3473,14 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) /* cannot issue a flush here because it hangs the hardware */ msleep(20); + /* Set Phy Config Counter to 50msec */ + if (hw->mac.type == e1000_pch2lan) { + reg = er32(FEXTNVM3); + reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK; + reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC; + ew32(FEXTNVM3, reg); + } + if (!ret_val) clear_bit(__E1000_ACCESS_SHARED_RESOURCE, &hw->adapter->state); @@ -3154,9 +3505,9 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) ew32(IMC, 0xffffffff); er32(ICR); - kab = er32(KABGTXD); - kab |= E1000_KABGTXD_BGSQLBIAS; - ew32(KABGTXD, kab); + reg = er32(KABGTXD); + reg |= E1000_KABGTXD_BGSQLBIAS; + ew32(KABGTXD, reg); return 0; } @@ -3309,6 +3660,13 @@ static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw) */ reg = er32(RFCTL); reg |= (E1000_RFCTL_NFSW_DIS | E1000_RFCTL_NFSR_DIS); + + /* + * Disable IPv6 extension header parsing because some malformed + * IPv6 headers can hang the Rx. + */ + if (hw->mac.type == e1000_ich8lan) + reg |= (E1000_RFCTL_IPV6_EX_DIS | E1000_RFCTL_NEW_IPV6_EXT_DIS); ew32(RFCTL, reg); } @@ -3359,6 +3717,7 @@ static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw) ew32(FCTTV, hw->fc.pause_time); if ((hw->phy.type == e1000_phy_82578) || (hw->phy.type == e1000_phy_82579) || + (hw->phy.type == e1000_phy_i217) || (hw->phy.type == e1000_phy_82577)) { ew32(FCRTV_PCH, hw->fc.refresh_time); @@ -3422,6 +3781,7 @@ static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw) break; case e1000_phy_82577: case e1000_phy_82579: + case e1000_phy_i217: ret_val = e1000_copper_link_setup_82577(hw); if (ret_val) return ret_val; @@ -3668,14 +4028,88 @@ void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw) * the LPLU setting in the NVM or custom setting. For PCH and newer parts, * the OEM bits PHY register (LED, GbE disable and LPLU configurations) also * needs to be written. + * Parts that support (and are linked to a partner which support) EEE in + * 100Mbps should disable LPLU since 100Mbps w/ EEE requires less power + * than 10Mbps w/o EEE. **/ void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw) { + struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; u32 phy_ctrl; s32 ret_val; phy_ctrl = er32(PHY_CTRL); phy_ctrl |= E1000_PHY_CTRL_GBE_DISABLE; + if (hw->phy.type == e1000_phy_i217) { + u16 phy_reg; + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + + if (!dev_spec->eee_disable) { + u16 eee_advert; + + ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR, + I217_EEE_ADVERTISEMENT); + if (ret_val) + goto release; + e1e_rphy_locked(hw, I82579_EMI_DATA, &eee_advert); + + /* + * Disable LPLU if both link partners support 100BaseT + * EEE and 100Full is advertised on both ends of the + * link. + */ + if ((eee_advert & I217_EEE_100_SUPPORTED) && + (dev_spec->eee_lp_ability & + I217_EEE_100_SUPPORTED) && + (hw->phy.autoneg_advertised & ADVERTISE_100_FULL)) + phy_ctrl &= ~(E1000_PHY_CTRL_D0A_LPLU | + E1000_PHY_CTRL_NOND0A_LPLU); + } + + /* + * For i217 Intel Rapid Start Technology support, + * when the system is going into Sx and no manageability engine + * is present, the driver must configure proxy to reset only on + * power good. LPI (Low Power Idle) state must also reset only + * on power good, as well as the MTA (Multicast table array). + * The SMBus release must also be disabled on LCD reset. + */ + if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) { + + /* Enable proxy to reset only on power good. */ + e1e_rphy_locked(hw, I217_PROXY_CTRL, &phy_reg); + phy_reg |= I217_PROXY_CTRL_AUTO_DISABLE; + e1e_wphy_locked(hw, I217_PROXY_CTRL, phy_reg); + + /* + * Set bit enable LPI (EEE) to reset only on + * power good. + */ + e1e_rphy_locked(hw, I217_SxCTRL, &phy_reg); + phy_reg |= I217_SxCTRL_MASK; + e1e_wphy_locked(hw, I217_SxCTRL, phy_reg); + + /* Disable the SMB release on LCD reset. */ + e1e_rphy_locked(hw, I217_MEMPWR, &phy_reg); + phy_reg &= ~I217_MEMPWR; + e1e_wphy_locked(hw, I217_MEMPWR, phy_reg); + } + + /* + * Enable MTA to reset for Intel Rapid Start Technology + * Support + */ + e1e_rphy_locked(hw, I217_CGFREG, &phy_reg); + phy_reg |= I217_CGFREG_MASK; + e1e_wphy_locked(hw, I217_CGFREG, phy_reg); + +release: + hw->phy.ops.release(hw); + } +out: ew32(PHY_CTRL, phy_ctrl); if (hw->mac.type == e1000_ich8lan) @@ -3704,44 +4138,61 @@ void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw) * on which PHY resets are not blocked, if the PHY registers cannot be * accessed properly by the s/w toggle the LANPHYPC value to power cycle * the PHY. + * On i217, setup Intel Rapid Start Technology. **/ void e1000_resume_workarounds_pchlan(struct e1000_hw *hw) { - u16 phy_id1, phy_id2; s32 ret_val; - if ((hw->mac.type != e1000_pch2lan) || - hw->phy.ops.check_reset_block(hw)) + if (hw->mac.type < e1000_pch2lan) return; - ret_val = hw->phy.ops.acquire(hw); + ret_val = e1000_init_phy_workarounds_pchlan(hw); if (ret_val) { - e_dbg("Failed to acquire PHY semaphore in resume\n"); + e_dbg("Failed to init PHY flow ret_val=%d\n", ret_val); return; } - /* Test access to the PHY registers by reading the ID regs */ - ret_val = hw->phy.ops.read_reg_locked(hw, PHY_ID1, &phy_id1); - if (ret_val) - goto release; - ret_val = hw->phy.ops.read_reg_locked(hw, PHY_ID2, &phy_id2); - if (ret_val) - goto release; - - if (hw->phy.id == ((u32)(phy_id1 << 16) | - (u32)(phy_id2 & PHY_REVISION_MASK))) - goto release; + /* + * For i217 Intel Rapid Start Technology support when the system + * is transitioning from Sx and no manageability engine is present + * configure SMBus to restore on reset, disable proxy, and enable + * the reset on MTA (Multicast table array). + */ + if (hw->phy.type == e1000_phy_i217) { + u16 phy_reg; - e1000_toggle_lanphypc_value_ich8lan(hw); + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) { + e_dbg("Failed to setup iRST\n"); + return; + } - hw->phy.ops.release(hw); - msleep(50); - e1000_phy_hw_reset(hw); - msleep(50); - return; + if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) { + /* + * Restore clear on SMB if no manageability engine + * is present + */ + ret_val = e1e_rphy_locked(hw, I217_MEMPWR, &phy_reg); + if (ret_val) + goto release; + phy_reg |= I217_MEMPWR_MASK; + e1e_wphy_locked(hw, I217_MEMPWR, phy_reg); + /* Disable Proxy */ + e1e_wphy_locked(hw, I217_PROXY_CTRL, 0); + } + /* Enable reset on MTA */ + ret_val = e1e_rphy_locked(hw, I217_CGFREG, &phy_reg); + if (ret_val) + goto release; + phy_reg &= ~I217_CGFREG_MASK; + e1e_wphy_locked(hw, I217_CGFREG, phy_reg); release: - hw->phy.ops.release(hw); + if (ret_val) + e_dbg("Error %d in resume workarounds\n", ret_val); + hw->phy.ops.release(hw); + } } /** @@ -3921,7 +4372,7 @@ static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw) /* If EEPROM is not marked present, init the IGP 3 PHY manually */ if (hw->mac.type <= e1000_ich9lan) { - if (((er32(EECD) & E1000_EECD_PRES) == 0) && + if (!(er32(EECD) & E1000_EECD_PRES) && (hw->phy.type == e1000_phy_igp_3)) { e1000e_phy_init_script_igp3(hw); } @@ -3982,6 +4433,7 @@ static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw) /* Clear PHY statistics registers */ if ((hw->phy.type == e1000_phy_82578) || (hw->phy.type == e1000_phy_82579) || + (hw->phy.type == e1000_phy_i217) || (hw->phy.type == e1000_phy_82577)) { ret_val = hw->phy.ops.acquire(hw); if (ret_val) @@ -4026,6 +4478,7 @@ static const struct e1000_mac_operations ich8_mac_ops = { .setup_physical_interface= e1000_setup_copper_link_ich8lan, /* id_led_init dependent on mac type */ .config_collision_dist = e1000e_config_collision_dist_generic, + .rar_set = e1000e_rar_set_generic, }; static const struct e1000_phy_operations ich8_phy_ops = { @@ -4140,3 +4593,22 @@ const struct e1000_info e1000_pch2_info = { .phy_ops = &ich8_phy_ops, .nvm_ops = &ich8_nvm_ops, }; + +const struct e1000_info e1000_pch_lpt_info = { + .mac = e1000_pch_lpt, + .flags = FLAG_IS_ICH + | FLAG_HAS_WOL + | FLAG_HAS_CTRLEXT_ON_LOAD + | FLAG_HAS_AMT + | FLAG_HAS_FLASH + | FLAG_HAS_JUMBO_FRAMES + | FLAG_APME_IN_WUC, + .flags2 = FLAG2_HAS_PHY_STATS + | FLAG2_HAS_EEE, + .pba = 26, + .max_hw_frame_size = DEFAULT_JUMBO, + .get_variants = e1000_get_variants_ich8lan, + .mac_ops = &ich8_mac_ops, + .phy_ops = &ich8_phy_ops, + .nvm_ops = &ich8_nvm_ops, +}; diff --git a/trunk/drivers/net/ethernet/intel/e1000e/mac.c b/trunk/drivers/net/ethernet/intel/e1000e/mac.c index decad98c1059..026e8b3ab52e 100644 --- a/trunk/drivers/net/ethernet/intel/e1000e/mac.c +++ b/trunk/drivers/net/ethernet/intel/e1000e/mac.c @@ -143,12 +143,12 @@ void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count) /* Setup the receive address */ e_dbg("Programming MAC Address into RAR[0]\n"); - e1000e_rar_set(hw, hw->mac.addr, 0); + hw->mac.ops.rar_set(hw, hw->mac.addr, 0); /* Zero out the other (rar_entry_count - 1) receive addresses */ e_dbg("Clearing RAR[1-%u]\n", rar_count - 1); for (i = 1; i < rar_count; i++) - e1000e_rar_set(hw, mac_addr, i); + hw->mac.ops.rar_set(hw, mac_addr, i); } /** @@ -215,13 +215,13 @@ s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw) * same as the normal permanent MAC address stored by the HW into the * RAR. Do this by mapping this address into RAR0. */ - e1000e_rar_set(hw, alt_mac_addr, 0); + hw->mac.ops.rar_set(hw, alt_mac_addr, 0); return 0; } /** - * e1000e_rar_set - Set receive address register + * e1000e_rar_set_generic - Set receive address register * @hw: pointer to the HW structure * @addr: pointer to the receive address * @index: receive address array register @@ -229,7 +229,7 @@ s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw) * Sets the receive address array register at index to the address passed * in by addr. **/ -void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index) +void e1000e_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index) { u32 rar_low, rar_high; @@ -681,7 +681,7 @@ static s32 e1000_set_default_fc_generic(struct e1000_hw *hw) return ret_val; } - if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0) + if (!(nvm_data & NVM_WORD0F_PAUSE_MASK)) hw->fc.requested_mode = e1000_fc_none; else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == NVM_WORD0F_ASM_DIR) hw->fc.requested_mode = e1000_fc_tx_pause; diff --git a/trunk/drivers/net/ethernet/intel/e1000e/manage.c b/trunk/drivers/net/ethernet/intel/e1000e/manage.c index 473f8e711510..bacc950fc684 100644 --- a/trunk/drivers/net/ethernet/intel/e1000e/manage.c +++ b/trunk/drivers/net/ethernet/intel/e1000e/manage.c @@ -85,7 +85,7 @@ static s32 e1000_mng_enable_host_if(struct e1000_hw *hw) /* Check that the host interface is enabled. */ hicr = er32(HICR); - if ((hicr & E1000_HICR_EN) == 0) { + if (!(hicr & E1000_HICR_EN)) { e_dbg("E1000_HOST_EN bit disabled.\n"); return -E1000_ERR_HOST_INTERFACE_COMMAND; } diff --git a/trunk/drivers/net/ethernet/intel/e1000e/netdev.c b/trunk/drivers/net/ethernet/intel/e1000e/netdev.c index 9520a6ac1f30..a4b0435b00dc 100644 --- a/trunk/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/trunk/drivers/net/ethernet/intel/e1000e/netdev.c @@ -56,7 +56,7 @@ #define DRV_EXTRAVERSION "-k" -#define DRV_VERSION "1.9.5" DRV_EXTRAVERSION +#define DRV_VERSION "2.0.0" DRV_EXTRAVERSION char e1000e_driver_name[] = "e1000e"; const char e1000e_driver_version[] = DRV_VERSION; @@ -79,6 +79,7 @@ static const struct e1000_info *e1000_info_tbl[] = { [board_ich10lan] = &e1000_ich10_info, [board_pchlan] = &e1000_pch_info, [board_pch2lan] = &e1000_pch2_info, + [board_pch_lpt] = &e1000_pch_lpt_info, }; struct e1000_reg_info { @@ -110,14 +111,14 @@ static const struct e1000_reg_info e1000_reg_info_tbl[] = { /* Rx Registers */ {E1000_RCTL, "RCTL"}, - {E1000_RDLEN, "RDLEN"}, - {E1000_RDH, "RDH"}, - {E1000_RDT, "RDT"}, + {E1000_RDLEN(0), "RDLEN"}, + {E1000_RDH(0), "RDH"}, + {E1000_RDT(0), "RDT"}, {E1000_RDTR, "RDTR"}, {E1000_RXDCTL(0), "RXDCTL"}, {E1000_ERT, "ERT"}, - {E1000_RDBAL, "RDBAL"}, - {E1000_RDBAH, "RDBAH"}, + {E1000_RDBAL(0), "RDBAL"}, + {E1000_RDBAH(0), "RDBAH"}, {E1000_RDFH, "RDFH"}, {E1000_RDFT, "RDFT"}, {E1000_RDFHS, "RDFHS"}, @@ -126,11 +127,11 @@ static const struct e1000_reg_info e1000_reg_info_tbl[] = { /* Tx Registers */ {E1000_TCTL, "TCTL"}, - {E1000_TDBAL, "TDBAL"}, - {E1000_TDBAH, "TDBAH"}, - {E1000_TDLEN, "TDLEN"}, - {E1000_TDH, "TDH"}, - {E1000_TDT, "TDT"}, + {E1000_TDBAL(0), "TDBAL"}, + {E1000_TDBAH(0), "TDBAH"}, + {E1000_TDLEN(0), "TDLEN"}, + {E1000_TDH(0), "TDH"}, + {E1000_TDT(0), "TDT"}, {E1000_TIDV, "TIDV"}, {E1000_TXDCTL(0), "TXDCTL"}, {E1000_TADV, "TADV"}, @@ -538,43 +539,15 @@ static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err, adapter->hw_csum_good++; } -/** - * e1000e_update_tail_wa - helper function for e1000e_update_[rt]dt_wa() - * @hw: pointer to the HW structure - * @tail: address of tail descriptor register - * @i: value to write to tail descriptor register - * - * When updating the tail register, the ME could be accessing Host CSR - * registers at the same time. Normally, this is handled in h/w by an - * arbiter but on some parts there is a bug that acknowledges Host accesses - * later than it should which could result in the descriptor register to - * have an incorrect value. Workaround this by checking the FWSM register - * which has bit 24 set while ME is accessing Host CSR registers, wait - * if it is set and try again a number of times. - **/ -static inline s32 e1000e_update_tail_wa(struct e1000_hw *hw, void __iomem *tail, - unsigned int i) -{ - unsigned int j = 0; - - while ((j++ < E1000_ICH_FWSM_PCIM2PCI_COUNT) && - (er32(FWSM) & E1000_ICH_FWSM_PCIM2PCI)) - udelay(50); - - writel(i, tail); - - if ((j == E1000_ICH_FWSM_PCIM2PCI_COUNT) && (i != readl(tail))) - return E1000_ERR_SWFW_SYNC; - - return 0; -} - static void e1000e_update_rdt_wa(struct e1000_ring *rx_ring, unsigned int i) { struct e1000_adapter *adapter = rx_ring->adapter; struct e1000_hw *hw = &adapter->hw; + s32 ret_val = __ew32_prepare(hw); - if (e1000e_update_tail_wa(hw, rx_ring->tail, i)) { + writel(i, rx_ring->tail); + + 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"); @@ -586,8 +559,11 @@ static void e1000e_update_tdt_wa(struct e1000_ring *tx_ring, unsigned int i) { struct e1000_adapter *adapter = tx_ring->adapter; struct e1000_hw *hw = &adapter->hw; + s32 ret_val = __ew32_prepare(hw); + + writel(i, tx_ring->tail); - if (e1000e_update_tail_wa(hw, tx_ring->tail, 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"); @@ -1053,7 +1029,8 @@ static void e1000_print_hw_hang(struct work_struct *work) if (!adapter->tx_hang_recheck && (adapter->flags2 & FLAG2_DMA_BURST)) { - /* May be block on write-back, flush and detect again + /* + * May be block on write-back, flush and detect again * flush pending descriptor writebacks to memory */ ew32(TIDV, adapter->tx_int_delay | E1000_TIDV_FPD); @@ -1108,6 +1085,10 @@ static void e1000_print_hw_hang(struct work_struct *work) phy_1000t_status, phy_ext_status, pci_status); + + /* Suggest workaround for known h/w issue */ + if ((hw->mac.type == e1000_pchlan) && (er32(CTRL) & E1000_CTRL_TFCE)) + e_err("Try turning off Tx pause (flow control) via ethtool\n"); } /** @@ -1645,7 +1626,10 @@ static void e1000_clean_rx_ring(struct e1000_ring *rx_ring) adapter->flags2 &= ~FLAG2_IS_DISCARDING; writel(0, rx_ring->head); - writel(0, rx_ring->tail); + if (rx_ring->adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA) + e1000e_update_rdt_wa(rx_ring, 0); + else + writel(0, rx_ring->tail); } static void e1000e_downshift_workaround(struct work_struct *work) @@ -2318,7 +2302,10 @@ static void e1000_clean_tx_ring(struct e1000_ring *tx_ring) tx_ring->next_to_clean = 0; writel(0, tx_ring->head); - writel(0, tx_ring->tail); + if (tx_ring->adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA) + e1000e_update_tdt_wa(tx_ring, 0); + else + writel(0, tx_ring->tail); } /** @@ -2530,33 +2517,31 @@ static int __devinit e1000_alloc_queues(struct e1000_adapter *adapter) } /** - * e1000_clean - NAPI Rx polling callback + * e1000e_poll - NAPI Rx polling callback * @napi: struct associated with this polling callback - * @budget: amount of packets driver is allowed to process this poll + * @weight: number of packets driver is allowed to process this poll **/ -static int e1000_clean(struct napi_struct *napi, int budget) +static int e1000e_poll(struct napi_struct *napi, int weight) { - struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, napi); + struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, + napi); struct e1000_hw *hw = &adapter->hw; struct net_device *poll_dev = adapter->netdev; int tx_cleaned = 1, work_done = 0; adapter = netdev_priv(poll_dev); - if (adapter->msix_entries && - !(adapter->rx_ring->ims_val & adapter->tx_ring->ims_val)) - goto clean_rx; - - tx_cleaned = e1000_clean_tx_irq(adapter->tx_ring); + if (!adapter->msix_entries || + (adapter->rx_ring->ims_val & adapter->tx_ring->ims_val)) + tx_cleaned = e1000_clean_tx_irq(adapter->tx_ring); -clean_rx: - adapter->clean_rx(adapter->rx_ring, &work_done, budget); + adapter->clean_rx(adapter->rx_ring, &work_done, weight); if (!tx_cleaned) - work_done = budget; + work_done = weight; - /* If budget not fully consumed, exit the polling mode */ - if (work_done < budget) { + /* If weight not fully consumed, exit the polling mode */ + if (work_done < weight) { if (adapter->itr_setting & 3) e1000_set_itr(adapter); napi_complete(napi); @@ -2800,13 +2785,13 @@ static void e1000_configure_tx(struct e1000_adapter *adapter) /* Setup the HW Tx Head and Tail descriptor pointers */ tdba = tx_ring->dma; tdlen = tx_ring->count * sizeof(struct e1000_tx_desc); - ew32(TDBAL, (tdba & DMA_BIT_MASK(32))); - ew32(TDBAH, (tdba >> 32)); - ew32(TDLEN, tdlen); - ew32(TDH, 0); - ew32(TDT, 0); - tx_ring->head = adapter->hw.hw_addr + E1000_TDH; - tx_ring->tail = adapter->hw.hw_addr + E1000_TDT; + ew32(TDBAL(0), (tdba & DMA_BIT_MASK(32))); + ew32(TDBAH(0), (tdba >> 32)); + ew32(TDLEN(0), tdlen); + ew32(TDH(0), 0); + ew32(TDT(0), 0); + tx_ring->head = adapter->hw.hw_addr + E1000_TDH(0); + tx_ring->tail = adapter->hw.hw_addr + E1000_TDT(0); /* Set the Tx Interrupt Delay register */ ew32(TIDV, adapter->tx_int_delay); @@ -2879,8 +2864,8 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter) u32 rctl, rfctl; u32 pages = 0; - /* Workaround Si errata on 82579 - configure jumbo frame flow */ - if (hw->mac.type == e1000_pch2lan) { + /* Workaround Si errata on PCHx - configure jumbo frame flow */ + if (hw->mac.type >= e1000_pch2lan) { s32 ret_val; if (adapter->netdev->mtu > ETH_DATA_LEN) @@ -2955,6 +2940,7 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter) /* Enable Extended Status in all Receive Descriptors */ rfctl = er32(RFCTL); rfctl |= E1000_RFCTL_EXTEN; + ew32(RFCTL, rfctl); /* * 82571 and greater support packet-split where the protocol @@ -2980,13 +2966,6 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter) if (adapter->rx_ps_pages) { u32 psrctl = 0; - /* - * disable packet split support for IPv6 extension headers, - * because some malformed IPv6 headers can hang the Rx - */ - rfctl |= (E1000_RFCTL_IPV6_EX_DIS | - E1000_RFCTL_NEW_IPV6_EXT_DIS); - /* Enable Packet split descriptors */ rctl |= E1000_RCTL_DTYP_PS; @@ -3025,7 +3004,6 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter) */ } - ew32(RFCTL, rfctl); ew32(RCTL, rctl); /* just started the receive unit, no need to restart */ adapter->flags &= ~FLAG_RX_RESTART_NOW; @@ -3110,13 +3088,13 @@ static void e1000_configure_rx(struct e1000_adapter *adapter) * the Base and Length of the Rx Descriptor Ring */ rdba = rx_ring->dma; - ew32(RDBAL, (rdba & DMA_BIT_MASK(32))); - ew32(RDBAH, (rdba >> 32)); - ew32(RDLEN, rdlen); - ew32(RDH, 0); - ew32(RDT, 0); - rx_ring->head = adapter->hw.hw_addr + E1000_RDH; - rx_ring->tail = adapter->hw.hw_addr + E1000_RDT; + ew32(RDBAL(0), (rdba & DMA_BIT_MASK(32))); + ew32(RDBAH(0), (rdba >> 32)); + ew32(RDLEN(0), rdlen); + ew32(RDH(0), 0); + ew32(RDT(0), 0); + rx_ring->head = adapter->hw.hw_addr + E1000_RDH(0); + rx_ring->tail = adapter->hw.hw_addr + E1000_RDT(0); /* Enable Receive Checksum Offload for TCP and UDP */ rxcsum = er32(RXCSUM); @@ -3229,7 +3207,7 @@ static int e1000e_write_uc_addr_list(struct net_device *netdev) netdev_for_each_uc_addr(ha, netdev) { if (!rar_entries) break; - e1000e_rar_set(hw, ha->addr, rar_entries--); + hw->mac.ops.rar_set(hw, ha->addr, rar_entries--); count++; } } @@ -3510,6 +3488,7 @@ void e1000e_reset(struct e1000_adapter *adapter) fc->refresh_time = 0x1000; break; case e1000_pch2lan: + case e1000_pch_lpt: fc->high_water = 0x05C20; fc->low_water = 0x05048; fc->pause_time = 0x0650; @@ -4038,6 +4017,7 @@ static int e1000_close(struct net_device *netdev) static int e1000_set_mac(struct net_device *netdev, void *p) { struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; struct sockaddr *addr = p; if (!is_valid_ether_addr(addr->sa_data)) @@ -4046,7 +4026,7 @@ static int e1000_set_mac(struct net_device *netdev, void *p) memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); memcpy(adapter->hw.mac.addr, addr->sa_data, netdev->addr_len); - e1000e_rar_set(&adapter->hw, adapter->hw.mac.addr, 0); + hw->mac.ops.rar_set(&adapter->hw, adapter->hw.mac.addr, 0); if (adapter->flags & FLAG_RESET_OVERWRITES_LAA) { /* activate the work around */ @@ -4060,9 +4040,8 @@ static int e1000_set_mac(struct net_device *netdev, void *p) * are dropped. Eventually the LAA will be in RAR[0] and * RAR[14] */ - e1000e_rar_set(&adapter->hw, - adapter->hw.mac.addr, - adapter->hw.mac.rar_entry_count - 1); + hw->mac.ops.rar_set(&adapter->hw, adapter->hw.mac.addr, + adapter->hw.mac.rar_entry_count - 1); } return 0; @@ -4641,7 +4620,7 @@ static void e1000_watchdog_task(struct work_struct *work) * reset from the other port. Set the appropriate LAA in RAR[0] */ if (e1000e_get_laa_state_82571(hw)) - e1000e_rar_set(hw, adapter->hw.mac.addr, 0); + hw->mac.ops.rar_set(hw, adapter->hw.mac.addr, 0); if (adapter->flags2 & FLAG2_CHECK_PHY_HANG) e1000e_check_82574_phy_workaround(adapter); @@ -5151,6 +5130,8 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, /* if count is 0 then mapping error has occurred */ count = e1000_tx_map(tx_ring, skb, first, max_per_txd, nr_frags, mss); if (count) { + skb_tx_timestamp(skb); + netdev_sent_queue(netdev, skb->len); e1000_tx_queue(tx_ring, tx_flags, count); /* Make sure there is space in the ring for the next send. */ @@ -5285,22 +5266,14 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) return -EINVAL; } - /* Jumbo frame workaround on 82579 requires CRC be stripped */ - if ((adapter->hw.mac.type == e1000_pch2lan) && + /* Jumbo frame workaround on 82579 and newer requires CRC be stripped */ + if ((adapter->hw.mac.type >= e1000_pch2lan) && !(adapter->flags2 & FLAG2_CRC_STRIPPING) && (new_mtu > ETH_DATA_LEN)) { - e_err("Jumbo Frames not supported on 82579 when CRC stripping is disabled.\n"); + e_err("Jumbo Frames not supported on this device when CRC stripping is disabled.\n"); return -EINVAL; } - /* 82573 Errata 17 */ - if (((adapter->hw.mac.type == e1000_82573) || - (adapter->hw.mac.type == e1000_82574)) && - (max_frame > ETH_FRAME_LEN + ETH_FCS_LEN)) { - adapter->flags2 |= FLAG2_DISABLE_ASPM_L1; - e1000e_disable_aspm(adapter->pdev, PCIE_LINK_STATE_L1); - } - while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) usleep_range(1000, 2000); /* e1000e_down -> e1000e_reset dependent on max_frame_size & mtu */ @@ -5694,7 +5667,7 @@ static int __e1000_resume(struct pci_dev *pdev) return err; } - if (hw->mac.type == e1000_pch2lan) + if (hw->mac.type >= e1000_pch2lan) e1000_resume_workarounds_pchlan(&adapter->hw); e1000e_power_up_phy(adapter); @@ -6226,7 +6199,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, netdev->netdev_ops = &e1000e_netdev_ops; e1000e_set_ethtool_ops(netdev); netdev->watchdog_timeo = 5 * HZ; - netif_napi_add(netdev, &adapter->napi, e1000_clean, 64); + netif_napi_add(netdev, &adapter->napi, e1000e_poll, 64); strlcpy(netdev->name, pci_name(pdev), sizeof(netdev->name)); netdev->mem_start = mmio_start; @@ -6593,6 +6566,9 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH2_LV_LM), board_pch2lan }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH2_LV_V), board_pch2lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LPT_I217_LM), board_pch_lpt }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LPT_I217_V), board_pch_lpt }, + { 0, 0, 0, 0, 0, 0, 0 } /* terminate list */ }; MODULE_DEVICE_TABLE(pci, e1000_pci_tbl); diff --git a/trunk/drivers/net/ethernet/intel/e1000e/param.c b/trunk/drivers/net/ethernet/intel/e1000e/param.c index 16adeb9418a8..55cc1565bc2f 100644 --- a/trunk/drivers/net/ethernet/intel/e1000e/param.c +++ b/trunk/drivers/net/ethernet/intel/e1000e/param.c @@ -166,8 +166,8 @@ E1000_PARAM(WriteProtectNVM, "Write-protect NVM [WARNING: disabling this can lea * * Default Value: 1 (enabled) */ -E1000_PARAM(CrcStripping, "Enable CRC Stripping, disable if your BMC needs " \ - "the CRC"); +E1000_PARAM(CrcStripping, + "Enable CRC Stripping, disable if your BMC needs the CRC"); struct e1000_option { enum { enable_option, range_option, list_option } type; @@ -347,8 +347,8 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter) /* * Make sure a message is printed for non-special - * values. And in case of an invalid option, display - * warning, use default and got through itr/itr_setting + * values. And in case of an invalid option, display + * warning, use default and go through itr/itr_setting * adjustment logic below */ if ((adapter->itr > 4) && @@ -365,7 +365,7 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter) * Make sure a message is printed for non-special * default values */ - if (adapter->itr > 40) + if (adapter->itr > 4) e_info("%s set to default %d\n", opt.name, adapter->itr); } diff --git a/trunk/drivers/net/ethernet/intel/e1000e/phy.c b/trunk/drivers/net/ethernet/intel/e1000e/phy.c index 35b45578c604..0334d013bc3c 100644 --- a/trunk/drivers/net/ethernet/intel/e1000e/phy.c +++ b/trunk/drivers/net/ethernet/intel/e1000e/phy.c @@ -638,6 +638,45 @@ s32 e1000e_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data) return __e1000_write_kmrn_reg(hw, offset, data, true); } +/** + * e1000_set_master_slave_mode - Setup PHY for Master/slave mode + * @hw: pointer to the HW structure + * + * Sets up Master/slave mode + **/ +static s32 e1000_set_master_slave_mode(struct e1000_hw *hw) +{ + s32 ret_val; + u16 phy_data; + + /* Resolve Master/Slave mode */ + ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &phy_data); + if (ret_val) + return ret_val; + + /* load defaults for future use */ + hw->phy.original_ms_type = (phy_data & CR_1000T_MS_ENABLE) ? + ((phy_data & CR_1000T_MS_VALUE) ? + e1000_ms_force_master : e1000_ms_force_slave) : e1000_ms_auto; + + switch (hw->phy.ms_type) { + case e1000_ms_force_master: + phy_data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE); + break; + case e1000_ms_force_slave: + phy_data |= CR_1000T_MS_ENABLE; + phy_data &= ~(CR_1000T_MS_VALUE); + break; + case e1000_ms_auto: + phy_data &= ~CR_1000T_MS_ENABLE; + /* fall-through */ + default: + break; + } + + return e1e_wphy(hw, PHY_1000T_CTRL, phy_data); +} + /** * e1000_copper_link_setup_82577 - Setup 82577 PHY for copper link * @hw: pointer to the HW structure @@ -659,7 +698,11 @@ s32 e1000_copper_link_setup_82577(struct e1000_hw *hw) /* Enable downshift */ phy_data |= I82577_CFG_ENABLE_DOWNSHIFT; - return e1e_wphy(hw, I82577_CFG_REG, phy_data); + ret_val = e1e_wphy(hw, I82577_CFG_REG, phy_data); + if (ret_val) + return ret_val; + + return e1000_set_master_slave_mode(hw); } /** @@ -718,12 +761,28 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw) * 1 - Enabled */ phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL; - if (phy->disable_polarity_correction == 1) + if (phy->disable_polarity_correction) phy_data |= M88E1000_PSCR_POLARITY_REVERSAL; /* Enable downshift on BM (disabled by default) */ - if (phy->type == e1000_phy_bm) + if (phy->type == e1000_phy_bm) { + /* For 82574/82583, first disable then enable downshift */ + if (phy->id == BME1000_E_PHY_ID_R2) { + phy_data &= ~BME1000_PSCR_ENABLE_DOWNSHIFT; + ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, + phy_data); + if (ret_val) + return ret_val; + /* Commit the changes. */ + ret_val = e1000e_commit_phy(hw); + if (ret_val) { + e_dbg("Error committing the PHY changes\n"); + return ret_val; + } + } + phy_data |= BME1000_PSCR_ENABLE_DOWNSHIFT; + } ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data); if (ret_val) @@ -879,31 +938,7 @@ s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw) return ret_val; } - ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &data); - if (ret_val) - return ret_val; - - /* load defaults for future use */ - phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ? - ((data & CR_1000T_MS_VALUE) ? - e1000_ms_force_master : - e1000_ms_force_slave) : - e1000_ms_auto; - - switch (phy->ms_type) { - case e1000_ms_force_master: - data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE); - break; - case e1000_ms_force_slave: - data |= CR_1000T_MS_ENABLE; - data &= ~(CR_1000T_MS_VALUE); - break; - case e1000_ms_auto: - data &= ~CR_1000T_MS_ENABLE; - default: - break; - } - ret_val = e1e_wphy(hw, PHY_1000T_CTRL, data); + ret_val = e1000_set_master_slave_mode(hw); } return ret_val; @@ -1090,7 +1125,7 @@ static s32 e1000_copper_link_autoneg(struct e1000_hw *hw) * If autoneg_advertised is zero, we assume it was not defaulted * by the calling code so we set to advertise full capability. */ - if (phy->autoneg_advertised == 0) + if (!phy->autoneg_advertised) phy->autoneg_advertised = phy->autoneg_mask; e_dbg("Reconfiguring auto-neg advertisement params\n"); @@ -1596,7 +1631,7 @@ s32 e1000e_check_downshift(struct e1000_hw *hw) ret_val = e1e_rphy(hw, offset, &phy_data); if (!ret_val) - phy->speed_downgraded = (phy_data & mask); + phy->speed_downgraded = !!(phy_data & mask); return ret_val; } @@ -1925,8 +1960,8 @@ s32 e1000e_get_phy_info_m88(struct e1000_hw *hw) if (ret_val) return ret_val; - phy->polarity_correction = (phy_data & - M88E1000_PSCR_POLARITY_REVERSAL); + phy->polarity_correction = !!(phy_data & + M88E1000_PSCR_POLARITY_REVERSAL); ret_val = e1000_check_polarity_m88(hw); if (ret_val) @@ -1936,7 +1971,7 @@ s32 e1000e_get_phy_info_m88(struct e1000_hw *hw) if (ret_val) return ret_val; - phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX); + phy->is_mdix = !!(phy_data & M88E1000_PSSR_MDIX); if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) { ret_val = e1000_get_cable_length(hw); @@ -1999,7 +2034,7 @@ s32 e1000e_get_phy_info_igp(struct e1000_hw *hw) if (ret_val) return ret_val; - phy->is_mdix = (data & IGP01E1000_PSSR_MDIX); + phy->is_mdix = !!(data & IGP01E1000_PSSR_MDIX); if ((data & IGP01E1000_PSSR_SPEED_MASK) == IGP01E1000_PSSR_SPEED_1000MBPS) { @@ -2052,8 +2087,7 @@ s32 e1000_get_phy_info_ife(struct e1000_hw *hw) ret_val = e1e_rphy(hw, IFE_PHY_SPECIAL_CONTROL, &data); if (ret_val) return ret_val; - phy->polarity_correction = (data & IFE_PSC_AUTO_POLARITY_DISABLE) - ? false : true; + phy->polarity_correction = !(data & IFE_PSC_AUTO_POLARITY_DISABLE); if (phy->polarity_correction) { ret_val = e1000_check_polarity_ife(hw); @@ -2070,7 +2104,7 @@ s32 e1000_get_phy_info_ife(struct e1000_hw *hw) if (ret_val) return ret_val; - phy->is_mdix = (data & IFE_PMC_MDIX_STATUS) ? true : false; + phy->is_mdix = !!(data & IFE_PMC_MDIX_STATUS); /* The following parameters are undefined for 10/100 operation. */ phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; @@ -2320,6 +2354,9 @@ enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id) case I82579_E_PHY_ID: phy_type = e1000_phy_82579; break; + case I217_E_PHY_ID: + phy_type = e1000_phy_i217; + break; default: phy_type = e1000_phy_unknown; break; @@ -2979,7 +3016,7 @@ static s32 __e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data, if ((hw->phy.type == e1000_phy_82578) && (hw->phy.revision >= 1) && (hw->phy.addr == 2) && - ((MAX_PHY_REG_ADDRESS & reg) == 0) && (data & (1 << 11))) { + !(MAX_PHY_REG_ADDRESS & reg) && (data & (1 << 11))) { u16 data2 = 0x7EFF; ret_val = e1000_access_phy_debug_regs_hv(hw, (1 << 6) | 0x3, @@ -3265,7 +3302,7 @@ s32 e1000_get_phy_info_82577(struct e1000_hw *hw) if (ret_val) return ret_val; - phy->is_mdix = (data & I82577_PHY_STATUS2_MDIX) ? true : false; + phy->is_mdix = !!(data & I82577_PHY_STATUS2_MDIX); if ((data & I82577_PHY_STATUS2_SPEED_MASK) == I82577_PHY_STATUS2_SPEED_1000MBPS) { diff --git a/trunk/drivers/net/ethernet/intel/igb/Makefile b/trunk/drivers/net/ethernet/intel/igb/Makefile index 6565c463185c..97c197fd4a8e 100644 --- a/trunk/drivers/net/ethernet/intel/igb/Makefile +++ b/trunk/drivers/net/ethernet/intel/igb/Makefile @@ -33,5 +33,7 @@ obj-$(CONFIG_IGB) += igb.o igb-objs := igb_main.o igb_ethtool.o e1000_82575.o \ - e1000_mac.o e1000_nvm.o e1000_phy.o e1000_mbx.o + e1000_mac.o e1000_nvm.o e1000_phy.o e1000_mbx.o \ + e1000_i210.o +igb-$(CONFIG_IGB_PTP) += igb_ptp.o diff --git a/trunk/drivers/net/ethernet/intel/igb/e1000_82575.c b/trunk/drivers/net/ethernet/intel/igb/e1000_82575.c index 08bdc33715ee..e65083958421 100644 --- a/trunk/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/trunk/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -36,6 +36,7 @@ #include "e1000_mac.h" #include "e1000_82575.h" +#include "e1000_i210.h" static s32 igb_get_invariants_82575(struct e1000_hw *); static s32 igb_acquire_phy_82575(struct e1000_hw *); @@ -52,6 +53,8 @@ static s32 igb_write_phy_reg_82580(struct e1000_hw *, u32, u16); static s32 igb_reset_hw_82575(struct e1000_hw *); static s32 igb_reset_hw_82580(struct e1000_hw *); static s32 igb_set_d0_lplu_state_82575(struct e1000_hw *, bool); +static s32 igb_set_d0_lplu_state_82580(struct e1000_hw *, bool); +static s32 igb_set_d3_lplu_state_82580(struct e1000_hw *, bool); static s32 igb_setup_copper_link_82575(struct e1000_hw *); static s32 igb_setup_serdes_link_82575(struct e1000_hw *); static s32 igb_write_phy_reg_sgmii_82575(struct e1000_hw *, u32, u16); @@ -96,6 +99,8 @@ static bool igb_sgmii_uses_mdio_82575(struct e1000_hw *hw) break; case e1000_82580: case e1000_i350: + case e1000_i210: + case e1000_i211: reg = rd32(E1000_MDICNFG); ext_mdio = !!(reg & E1000_MDICNFG_EXT_MDIO); break; @@ -150,6 +155,17 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) case E1000_DEV_ID_I350_SGMII: mac->type = e1000_i350; break; + case E1000_DEV_ID_I210_COPPER: + case E1000_DEV_ID_I210_COPPER_OEM1: + case E1000_DEV_ID_I210_COPPER_IT: + case E1000_DEV_ID_I210_FIBER: + case E1000_DEV_ID_I210_SERDES: + case E1000_DEV_ID_I210_SGMII: + mac->type = e1000_i210; + break; + case E1000_DEV_ID_I211_COPPER: + mac->type = e1000_i211; + break; default: return -E1000_ERR_MAC_INIT; break; @@ -182,26 +198,44 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) /* Set mta register count */ mac->mta_reg_count = 128; /* Set rar entry count */ - mac->rar_entry_count = E1000_RAR_ENTRIES_82575; - if (mac->type == e1000_82576) + switch (mac->type) { + case e1000_82576: mac->rar_entry_count = E1000_RAR_ENTRIES_82576; - if (mac->type == e1000_82580) + break; + case e1000_82580: mac->rar_entry_count = E1000_RAR_ENTRIES_82580; - if (mac->type == e1000_i350) + break; + case e1000_i350: + case e1000_i210: + case e1000_i211: mac->rar_entry_count = E1000_RAR_ENTRIES_I350; + break; + default: + mac->rar_entry_count = E1000_RAR_ENTRIES_82575; + break; + } /* reset */ if (mac->type >= e1000_82580) mac->ops.reset_hw = igb_reset_hw_82580; else mac->ops.reset_hw = igb_reset_hw_82575; + + if (mac->type >= e1000_i210) { + mac->ops.acquire_swfw_sync = igb_acquire_swfw_sync_i210; + mac->ops.release_swfw_sync = igb_release_swfw_sync_i210; + } else { + mac->ops.acquire_swfw_sync = igb_acquire_swfw_sync_82575; + mac->ops.release_swfw_sync = igb_release_swfw_sync_82575; + } + /* Set if part includes ASF firmware */ mac->asf_firmware_present = true; /* Set if manageability features are enabled. */ mac->arc_subsystem_valid = (rd32(E1000_FWSM) & E1000_FWSM_MODE_MASK) ? true : false; - /* enable EEE on i350 parts */ - if (mac->type == e1000_i350) + /* enable EEE on i350 parts and later parts */ + if (mac->type >= e1000_i350) dev_spec->eee_disable = false; else dev_spec->eee_disable = true; @@ -213,26 +247,6 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) /* NVM initialization */ eecd = rd32(E1000_EECD); - - nvm->opcode_bits = 8; - nvm->delay_usec = 1; - switch (nvm->override) { - case e1000_nvm_override_spi_large: - nvm->page_size = 32; - nvm->address_bits = 16; - break; - case e1000_nvm_override_spi_small: - nvm->page_size = 8; - nvm->address_bits = 8; - break; - default: - nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8; - nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8; - break; - } - - nvm->type = e1000_nvm_eeprom_spi; - size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >> E1000_EECD_SIZE_EX_SHIFT); @@ -242,6 +256,33 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) */ size += NVM_WORD_SIZE_BASE_SHIFT; + nvm->word_size = 1 << size; + if (hw->mac.type < e1000_i210) { + nvm->opcode_bits = 8; + nvm->delay_usec = 1; + switch (nvm->override) { + case e1000_nvm_override_spi_large: + nvm->page_size = 32; + nvm->address_bits = 16; + break; + case e1000_nvm_override_spi_small: + nvm->page_size = 8; + nvm->address_bits = 8; + break; + default: + nvm->page_size = eecd + & E1000_EECD_ADDR_BITS ? 32 : 8; + nvm->address_bits = eecd + & E1000_EECD_ADDR_BITS ? 16 : 8; + break; + } + if (nvm->word_size == (1 << 15)) + nvm->page_size = 128; + + nvm->type = e1000_nvm_eeprom_spi; + } else + nvm->type = e1000_nvm_flash_hw; + /* * Check for invalid size */ @@ -249,32 +290,60 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) pr_notice("The NVM size is not valid, defaulting to 32K\n"); size = 15; } - nvm->word_size = 1 << size; - if (nvm->word_size == (1 << 15)) - nvm->page_size = 128; /* NVM Function Pointers */ - nvm->ops.acquire = igb_acquire_nvm_82575; - if (nvm->word_size < (1 << 15)) - nvm->ops.read = igb_read_nvm_eerd; - else - nvm->ops.read = igb_read_nvm_spi; - - nvm->ops.release = igb_release_nvm_82575; switch (hw->mac.type) { case e1000_82580: nvm->ops.validate = igb_validate_nvm_checksum_82580; nvm->ops.update = igb_update_nvm_checksum_82580; + nvm->ops.acquire = igb_acquire_nvm_82575; + nvm->ops.release = igb_release_nvm_82575; + if (nvm->word_size < (1 << 15)) + nvm->ops.read = igb_read_nvm_eerd; + else + nvm->ops.read = igb_read_nvm_spi; + nvm->ops.write = igb_write_nvm_spi; break; case e1000_i350: nvm->ops.validate = igb_validate_nvm_checksum_i350; nvm->ops.update = igb_update_nvm_checksum_i350; + nvm->ops.acquire = igb_acquire_nvm_82575; + nvm->ops.release = igb_release_nvm_82575; + if (nvm->word_size < (1 << 15)) + nvm->ops.read = igb_read_nvm_eerd; + else + nvm->ops.read = igb_read_nvm_spi; + nvm->ops.write = igb_write_nvm_spi; + break; + case e1000_i210: + nvm->ops.validate = igb_validate_nvm_checksum_i210; + nvm->ops.update = igb_update_nvm_checksum_i210; + nvm->ops.acquire = igb_acquire_nvm_i210; + nvm->ops.release = igb_release_nvm_i210; + nvm->ops.read = igb_read_nvm_srrd_i210; + nvm->ops.valid_led_default = igb_valid_led_default_i210; + break; + case e1000_i211: + nvm->ops.acquire = igb_acquire_nvm_i210; + nvm->ops.release = igb_release_nvm_i210; + nvm->ops.read = igb_read_nvm_i211; + nvm->ops.valid_led_default = igb_valid_led_default_i210; + nvm->ops.validate = NULL; + nvm->ops.update = NULL; + nvm->ops.write = NULL; break; default: nvm->ops.validate = igb_validate_nvm_checksum; nvm->ops.update = igb_update_nvm_checksum; + nvm->ops.acquire = igb_acquire_nvm_82575; + nvm->ops.release = igb_release_nvm_82575; + if (nvm->word_size < (1 << 15)) + nvm->ops.read = igb_read_nvm_eerd; + else + nvm->ops.read = igb_read_nvm_spi; + nvm->ops.write = igb_write_nvm_spi; + break; } - nvm->ops.write = igb_write_nvm_spi; /* if part supports SR-IOV then initialize mailbox parameters */ switch (mac->type) { @@ -312,9 +381,13 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) if (igb_sgmii_active_82575(hw) && !igb_sgmii_uses_mdio_82575(hw)) { phy->ops.read_reg = igb_read_phy_reg_sgmii_82575; phy->ops.write_reg = igb_write_phy_reg_sgmii_82575; - } else if (hw->mac.type >= e1000_82580) { + } else if ((hw->mac.type == e1000_82580) + || (hw->mac.type == e1000_i350)) { phy->ops.read_reg = igb_read_phy_reg_82580; phy->ops.write_reg = igb_write_phy_reg_82580; + } else if (hw->phy.type >= e1000_phy_i210) { + phy->ops.read_reg = igb_read_phy_reg_gs40g; + phy->ops.write_reg = igb_write_phy_reg_gs40g; } else { phy->ops.read_reg = igb_read_phy_reg_igp; phy->ops.write_reg = igb_write_phy_reg_igp; @@ -343,6 +416,14 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) else phy->ops.get_cable_length = igb_get_cable_length_m88; + if (phy->id == I210_I_PHY_ID) { + phy->ops.get_cable_length = + igb_get_cable_length_m88_gen2; + phy->ops.set_d0_lplu_state = + igb_set_d0_lplu_state_82580; + phy->ops.set_d3_lplu_state = + igb_set_d3_lplu_state_82580; + } phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88; break; case IGP03E1000_E_PHY_ID: @@ -359,6 +440,17 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_82580; phy->ops.get_cable_length = igb_get_cable_length_82580; phy->ops.get_phy_info = igb_get_phy_info_82580; + phy->ops.set_d0_lplu_state = igb_set_d0_lplu_state_82580; + phy->ops.set_d3_lplu_state = igb_set_d3_lplu_state_82580; + break; + case I210_I_PHY_ID: + phy->type = e1000_phy_i210; + phy->ops.get_phy_info = igb_get_phy_info_m88; + phy->ops.check_polarity = igb_check_polarity_m88; + phy->ops.get_cable_length = igb_get_cable_length_m88_gen2; + phy->ops.set_d0_lplu_state = igb_set_d0_lplu_state_82580; + phy->ops.set_d3_lplu_state = igb_set_d3_lplu_state_82580; + phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88; break; default: return -E1000_ERR_PHY; @@ -385,7 +477,7 @@ static s32 igb_acquire_phy_82575(struct e1000_hw *hw) else if (hw->bus.func == E1000_FUNC_3) mask = E1000_SWFW_PHY3_SM; - return igb_acquire_swfw_sync_82575(hw, mask); + return hw->mac.ops.acquire_swfw_sync(hw, mask); } /** @@ -406,7 +498,7 @@ static void igb_release_phy_82575(struct e1000_hw *hw) else if (hw->bus.func == E1000_FUNC_3) mask = E1000_SWFW_PHY3_SM; - igb_release_swfw_sync_82575(hw, mask); + hw->mac.ops.release_swfw_sync(hw, mask); } /** @@ -510,6 +602,8 @@ static s32 igb_get_phy_id_82575(struct e1000_hw *hw) break; case e1000_82580: case e1000_i350: + case e1000_i210: + case e1000_i211: mdic = rd32(E1000_MDICNFG); mdic &= E1000_MDICNFG_PHY_MASK; phy->addr = mdic >> E1000_MDICNFG_PHY_SHIFT; @@ -673,6 +767,96 @@ static s32 igb_set_d0_lplu_state_82575(struct e1000_hw *hw, bool active) return ret_val; } +/** + * igb_set_d0_lplu_state_82580 - Set Low Power Linkup D0 state + * @hw: pointer to the HW structure + * @active: true to enable LPLU, false to disable + * + * Sets the LPLU D0 state according to the active flag. When + * activating LPLU this function also disables smart speed + * and vice versa. LPLU will not be activated unless the + * device autonegotiation advertisement meets standards of + * either 10 or 10/100 or 10/100/1000 at all duplexes. + * This is a function pointer entry point only called by + * PHY setup routines. + **/ +static s32 igb_set_d0_lplu_state_82580(struct e1000_hw *hw, bool active) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val = 0; + u16 data; + + data = rd32(E1000_82580_PHY_POWER_MGMT); + + if (active) { + data |= E1000_82580_PM_D0_LPLU; + + /* When LPLU is enabled, we should disable SmartSpeed */ + data &= ~E1000_82580_PM_SPD; + } else { + data &= ~E1000_82580_PM_D0_LPLU; + + /* + * LPLU and SmartSpeed are mutually exclusive. LPLU is used + * during Dx states where the power conservation is most + * important. During driver activity we should enable + * SmartSpeed, so performance is maintained. + */ + if (phy->smart_speed == e1000_smart_speed_on) + data |= E1000_82580_PM_SPD; + else if (phy->smart_speed == e1000_smart_speed_off) + data &= ~E1000_82580_PM_SPD; } + + wr32(E1000_82580_PHY_POWER_MGMT, data); + return ret_val; +} + +/** + * igb_set_d3_lplu_state_82580 - Sets low power link up state for D3 + * @hw: pointer to the HW structure + * @active: boolean used to enable/disable lplu + * + * Success returns 0, Failure returns 1 + * + * The low power link up (lplu) state is set to the power management level D3 + * and SmartSpeed is disabled when active is true, else clear lplu for D3 + * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU + * is used during Dx states where the power conservation is most important. + * During driver activity, SmartSpeed should be enabled so performance is + * maintained. + **/ +s32 igb_set_d3_lplu_state_82580(struct e1000_hw *hw, bool active) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val = 0; + u16 data; + + data = rd32(E1000_82580_PHY_POWER_MGMT); + + if (!active) { + data &= ~E1000_82580_PM_D3_LPLU; + /* + * LPLU and SmartSpeed are mutually exclusive. LPLU is used + * during Dx states where the power conservation is most + * important. During driver activity we should enable + * SmartSpeed, so performance is maintained. + */ + if (phy->smart_speed == e1000_smart_speed_on) + data |= E1000_82580_PM_SPD; + else if (phy->smart_speed == e1000_smart_speed_off) + data &= ~E1000_82580_PM_SPD; + } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) || + (phy->autoneg_advertised == E1000_ALL_NOT_GIG) || + (phy->autoneg_advertised == E1000_ALL_10_SPEED)) { + data |= E1000_82580_PM_D3_LPLU; + /* When LPLU is enabled, we should disable SmartSpeed */ + data &= ~E1000_82580_PM_SPD; + } + + wr32(E1000_82580_PHY_POWER_MGMT, data); + return ret_val; +} + /** * igb_acquire_nvm_82575 - Request for access to EEPROM * @hw: pointer to the HW structure @@ -686,14 +870,14 @@ static s32 igb_acquire_nvm_82575(struct e1000_hw *hw) { s32 ret_val; - ret_val = igb_acquire_swfw_sync_82575(hw, E1000_SWFW_EEP_SM); + ret_val = hw->mac.ops.acquire_swfw_sync(hw, E1000_SWFW_EEP_SM); if (ret_val) goto out; ret_val = igb_acquire_nvm(hw); if (ret_val) - igb_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM); + hw->mac.ops.release_swfw_sync(hw, E1000_SWFW_EEP_SM); out: return ret_val; @@ -709,7 +893,7 @@ static s32 igb_acquire_nvm_82575(struct e1000_hw *hw) static void igb_release_nvm_82575(struct e1000_hw *hw) { igb_release_nvm(hw); - igb_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM); + hw->mac.ops.release_swfw_sync(hw, E1000_SWFW_EEP_SM); } /** @@ -1080,7 +1264,6 @@ static s32 igb_init_hw_82575(struct e1000_hw *hw) * is no link. */ igb_clear_hw_cntrs_82575(hw); - return ret_val; } @@ -1117,6 +1300,7 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw) } } switch (hw->phy.type) { + case e1000_phy_i210: case e1000_phy_m88: if (hw->phy.id == I347AT4_E_PHY_ID || hw->phy.id == M88E1112_E_PHY_ID) @@ -1757,7 +1941,7 @@ static s32 igb_reset_hw_82580(struct e1000_hw *hw) /* Determine whether or not a global dev reset is requested */ if (global_device_reset && - igb_acquire_swfw_sync_82575(hw, swmbsw_mask)) + hw->mac.ops.acquire_swfw_sync(hw, swmbsw_mask)) global_device_reset = false; if (global_device_reset && @@ -1803,7 +1987,7 @@ static s32 igb_reset_hw_82580(struct e1000_hw *hw) /* Release semaphore */ if (global_device_reset) - igb_release_swfw_sync_82575(hw, swmbsw_mask); + hw->mac.ops.release_swfw_sync(hw, swmbsw_mask); return ret_val; } diff --git a/trunk/drivers/net/ethernet/intel/igb/e1000_82575.h b/trunk/drivers/net/ethernet/intel/igb/e1000_82575.h index b927d79ab536..e85c453f5428 100644 --- a/trunk/drivers/net/ethernet/intel/igb/e1000_82575.h +++ b/trunk/drivers/net/ethernet/intel/igb/e1000_82575.h @@ -55,10 +55,11 @@ extern void igb_rx_fifo_flush_82575(struct e1000_hw *hw); #define E1000_SRRCTL_DROP_EN 0x80000000 #define E1000_SRRCTL_TIMESTAMP 0x40000000 + #define E1000_MRQC_ENABLE_RSS_4Q 0x00000002 #define E1000_MRQC_ENABLE_VMDQ 0x00000003 -#define E1000_MRQC_ENABLE_VMDQ_RSS_2Q 0x00000005 #define E1000_MRQC_RSS_FIELD_IPV4_UDP 0x00400000 +#define E1000_MRQC_ENABLE_VMDQ_RSS_2Q 0x00000005 #define E1000_MRQC_RSS_FIELD_IPV6_UDP 0x00800000 #define E1000_MRQC_RSS_FIELD_IPV6_UDP_EX 0x01000000 diff --git a/trunk/drivers/net/ethernet/intel/igb/e1000_defines.h b/trunk/drivers/net/ethernet/intel/igb/e1000_defines.h index 89eb1f85b9fa..ec7e4fe3e3ee 100644 --- a/trunk/drivers/net/ethernet/intel/igb/e1000_defines.h +++ b/trunk/drivers/net/ethernet/intel/igb/e1000_defines.h @@ -301,6 +301,8 @@ * transactions */ #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 */ @@ -458,6 +460,7 @@ #define E1000_ERR_INVALID_ARGUMENT 16 #define E1000_ERR_NO_SPACE 17 #define E1000_ERR_NVM_PBA_SECTION 18 +#define E1000_ERR_INVM_VALUE_NOT_FOUND 19 /* Loop limit on how long we wait for auto-negotiation to complete */ #define COPPER_LINK_UP_LIMIT 10 @@ -595,6 +598,25 @@ #define E1000_EECD_AUTO_RD 0x00000200 /* NVM Auto Read done */ #define E1000_EECD_SIZE_EX_MASK 0x00007800 /* NVM Size */ #define E1000_EECD_SIZE_EX_SHIFT 11 +#define E1000_EECD_FLUPD_I210 0x00800000 /* Update FLASH */ +#define E1000_EECD_FLUDONE_I210 0x04000000 /* Update FLASH done*/ +#define E1000_FLUDONE_ATTEMPTS 20000 +#define E1000_EERD_EEWR_MAX_COUNT 512 /* buffered EEPROM words rw */ +#define E1000_I210_FIFO_SEL_RX 0x00 +#define E1000_I210_FIFO_SEL_TX_QAV(_i) (0x02 + (_i)) +#define E1000_I210_FIFO_SEL_TX_LEGACY E1000_I210_FIFO_SEL_TX_QAV(0) +#define E1000_I210_FIFO_SEL_BMC2OS_TX 0x06 +#define E1000_I210_FIFO_SEL_BMC2OS_RX 0x01 +#define E1000_EECD_FLUPD_I210 0x00800000 /* Update FLASH */ +#define E1000_EECD_FLUDONE_I210 0x04000000 /* Update FLASH done*/ +#define E1000_FLUDONE_ATTEMPTS 20000 +#define E1000_EERD_EEWR_MAX_COUNT 512 /* buffered EEPROM words rw */ +#define E1000_I210_FIFO_SEL_RX 0x00 +#define E1000_I210_FIFO_SEL_TX_QAV(_i) (0x02 + (_i)) +#define E1000_I210_FIFO_SEL_TX_LEGACY E1000_I210_FIFO_SEL_TX_QAV(0) +#define E1000_I210_FIFO_SEL_BMC2OS_TX 0x06 +#define E1000_I210_FIFO_SEL_BMC2OS_RX 0x01 + /* Offset to data in NVM read/write registers */ #define E1000_NVM_RW_REG_DATA 16 @@ -613,6 +635,16 @@ #define NVM_CHECKSUM_REG 0x003F #define NVM_COMPATIBILITY_REG_3 0x0003 #define NVM_COMPATIBILITY_BIT_MASK 0x8000 +#define NVM_MAC_ADDR 0x0000 +#define NVM_SUB_DEV_ID 0x000B +#define NVM_SUB_VEN_ID 0x000C +#define NVM_DEV_ID 0x000D +#define NVM_VEN_ID 0x000E +#define NVM_INIT_CTRL_2 0x000F +#define NVM_INIT_CTRL_4 0x0013 +#define NVM_LED_1_CFG 0x001C +#define NVM_LED_0_2_CFG 0x001F + #define E1000_NVM_CFG_DONE_PORT_0 0x040000 /* MNG config cycle done */ #define E1000_NVM_CFG_DONE_PORT_1 0x080000 /* ...for second port */ @@ -639,6 +671,7 @@ #define NVM_PBA_OFFSET_0 8 #define NVM_PBA_OFFSET_1 9 +#define NVM_RESERVED_WORD 0xFFFF #define NVM_PBA_PTR_GUARD 0xFAFA #define NVM_WORD_SIZE_BASE_SHIFT 6 @@ -696,6 +729,7 @@ #define I82580_I_PHY_ID 0x015403A0 #define I350_I_PHY_ID 0x015403B0 #define M88_VENDOR 0x0141 +#define I210_I_PHY_ID 0x01410C00 /* M88E1000 Specific Registers */ #define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */ @@ -815,6 +849,7 @@ #define E1000_IPCNFG_EEE_100M_AN 0x00000004 /* EEE Enable 100M AN */ #define E1000_EEER_TX_LPI_EN 0x00010000 /* EEE Tx LPI Enable */ #define E1000_EEER_RX_LPI_EN 0x00020000 /* EEE Rx LPI Enable */ +#define E1000_EEER_FRC_AN 0x10000000 /* Enable EEE in loopback */ #define E1000_EEER_LPI_FC 0x00040000 /* EEE Enable on FC */ /* SerDes Control */ diff --git a/trunk/drivers/net/ethernet/intel/igb/e1000_hw.h b/trunk/drivers/net/ethernet/intel/igb/e1000_hw.h index f67cbd3fa307..c2a51dcda550 100644 --- a/trunk/drivers/net/ethernet/intel/igb/e1000_hw.h +++ b/trunk/drivers/net/ethernet/intel/igb/e1000_hw.h @@ -63,6 +63,13 @@ struct e1000_hw; #define E1000_DEV_ID_I350_FIBER 0x1522 #define E1000_DEV_ID_I350_SERDES 0x1523 #define E1000_DEV_ID_I350_SGMII 0x1524 +#define E1000_DEV_ID_I210_COPPER 0x1533 +#define E1000_DEV_ID_I210_COPPER_OEM1 0x1534 +#define E1000_DEV_ID_I210_COPPER_IT 0x1535 +#define E1000_DEV_ID_I210_FIBER 0x1536 +#define E1000_DEV_ID_I210_SERDES 0x1537 +#define E1000_DEV_ID_I210_SGMII 0x1538 +#define E1000_DEV_ID_I211_COPPER 0x1539 #define E1000_REVISION_2 2 #define E1000_REVISION_4 4 @@ -83,6 +90,8 @@ enum e1000_mac_type { e1000_82576, e1000_82580, e1000_i350, + e1000_i210, + e1000_i211, e1000_num_macs /* List is 1-based, so subtract 1 for true count. */ }; @@ -117,6 +126,7 @@ enum e1000_phy_type { e1000_phy_igp_3, e1000_phy_ife, e1000_phy_82580, + e1000_phy_i210, }; enum e1000_bus_type { @@ -313,6 +323,9 @@ struct e1000_mac_operations { 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); + void (*release_swfw_sync)(struct e1000_hw *, u16); + }; struct e1000_phy_operations { @@ -338,6 +351,7 @@ struct e1000_nvm_operations { 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 *); }; struct e1000_info { diff --git a/trunk/drivers/net/ethernet/intel/igb/e1000_i210.c b/trunk/drivers/net/ethernet/intel/igb/e1000_i210.c new file mode 100644 index 000000000000..77a5f939bc74 --- /dev/null +++ b/trunk/drivers/net/ethernet/intel/igb/e1000_i210.c @@ -0,0 +1,603 @@ +/******************************************************************************* + + Intel(R) Gigabit Ethernet Linux driver + Copyright(c) 2007-2012 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, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + 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 + */ + +#include +#include + +#include "e1000_hw.h" +#include "e1000_i210.h" + +static s32 igb_get_hw_semaphore_i210(struct e1000_hw *hw); +static void igb_put_hw_semaphore_i210(struct e1000_hw *hw); +static s32 igb_write_nvm_srwr(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data); +static s32 igb_pool_flash_update_done_i210(struct e1000_hw *hw); + +/** + * igb_acquire_nvm_i210 - Request for access to EEPROM + * @hw: pointer to the HW structure + * + * Acquire the necessary semaphores for exclusive access to the EEPROM. + * Set the EEPROM access request bit and wait for EEPROM access grant bit. + * Return successful if access grant bit set, else clear the request for + * EEPROM access and return -E1000_ERR_NVM (-1). + **/ +s32 igb_acquire_nvm_i210(struct e1000_hw *hw) +{ + return igb_acquire_swfw_sync_i210(hw, E1000_SWFW_EEP_SM); +} + +/** + * igb_release_nvm_i210 - Release exclusive access to EEPROM + * @hw: pointer to the HW structure + * + * Stop any current commands to the EEPROM and clear the EEPROM request bit, + * then release the semaphores acquired. + **/ +void igb_release_nvm_i210(struct e1000_hw *hw) +{ + igb_release_swfw_sync_i210(hw, E1000_SWFW_EEP_SM); +} + +/** + * igb_acquire_swfw_sync_i210 - Acquire SW/FW semaphore + * @hw: pointer to the HW structure + * @mask: specifies which semaphore to acquire + * + * Acquire the SW/FW semaphore to access the PHY or NVM. The mask + * will also specify which port we're acquiring the lock for. + **/ +s32 igb_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask) +{ + u32 swfw_sync; + u32 swmask = mask; + u32 fwmask = mask << 16; + s32 ret_val = E1000_SUCCESS; + s32 i = 0, timeout = 200; /* FIXME: find real value to use here */ + + while (i < timeout) { + if (igb_get_hw_semaphore_i210(hw)) { + ret_val = -E1000_ERR_SWFW_SYNC; + goto out; + } + + swfw_sync = rd32(E1000_SW_FW_SYNC); + if (!(swfw_sync & fwmask)) + break; + + /* + * Firmware currently using resource (fwmask) + */ + igb_put_hw_semaphore_i210(hw); + mdelay(5); + i++; + } + + if (i == timeout) { + hw_dbg("Driver can't access resource, SW_FW_SYNC timeout.\n"); + ret_val = -E1000_ERR_SWFW_SYNC; + goto out; + } + + swfw_sync |= swmask; + wr32(E1000_SW_FW_SYNC, swfw_sync); + + igb_put_hw_semaphore_i210(hw); +out: + return ret_val; +} + +/** + * igb_release_swfw_sync_i210 - Release SW/FW semaphore + * @hw: pointer to the HW structure + * @mask: specifies which semaphore to acquire + * + * Release the SW/FW semaphore used to access the PHY or NVM. The mask + * will also specify which port we're releasing the lock for. + **/ +void igb_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask) +{ + u32 swfw_sync; + + while (igb_get_hw_semaphore_i210(hw) != E1000_SUCCESS) + ; /* Empty */ + + swfw_sync = rd32(E1000_SW_FW_SYNC); + swfw_sync &= ~mask; + wr32(E1000_SW_FW_SYNC, swfw_sync); + + igb_put_hw_semaphore_i210(hw); +} + +/** + * igb_get_hw_semaphore_i210 - Acquire hardware semaphore + * @hw: pointer to the HW structure + * + * Acquire the HW semaphore to access the PHY or NVM + **/ +static s32 igb_get_hw_semaphore_i210(struct e1000_hw *hw) +{ + u32 swsm; + s32 ret_val = E1000_SUCCESS; + s32 timeout = hw->nvm.word_size + 1; + s32 i = 0; + + /* Get the FW semaphore. */ + for (i = 0; i < timeout; i++) { + swsm = rd32(E1000_SWSM); + wr32(E1000_SWSM, swsm | E1000_SWSM_SWESMBI); + + /* Semaphore acquired if bit latched */ + if (rd32(E1000_SWSM) & E1000_SWSM_SWESMBI) + break; + + udelay(50); + } + + if (i == timeout) { + /* Release semaphores */ + igb_put_hw_semaphore(hw); + hw_dbg("Driver can't access the NVM\n"); + ret_val = -E1000_ERR_NVM; + goto out; + } + +out: + return ret_val; +} + +/** + * igb_put_hw_semaphore_i210 - Release hardware semaphore + * @hw: pointer to the HW structure + * + * Release hardware semaphore used to access the PHY or NVM + **/ +static void igb_put_hw_semaphore_i210(struct e1000_hw *hw) +{ + u32 swsm; + + swsm = rd32(E1000_SWSM); + + swsm &= ~E1000_SWSM_SWESMBI; + + wr32(E1000_SWSM, swsm); +} + +/** + * igb_read_nvm_srrd_i210 - Reads Shadow Ram using EERD register + * @hw: pointer to the HW structure + * @offset: offset of word in the Shadow Ram to read + * @words: number of words to read + * @data: word read from the Shadow Ram + * + * Reads a 16 bit word from the Shadow Ram using the EERD register. + * Uses necessary synchronization semaphores. + **/ +s32 igb_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data) +{ + s32 status = E1000_SUCCESS; + u16 i, count; + + /* We cannot hold synchronization semaphores for too long, + * because of forceful takeover procedure. However it is more efficient + * to read in bursts than synchronizing access for each word. */ + for (i = 0; i < words; i += E1000_EERD_EEWR_MAX_COUNT) { + count = (words - i) / E1000_EERD_EEWR_MAX_COUNT > 0 ? + E1000_EERD_EEWR_MAX_COUNT : (words - i); + if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) { + status = igb_read_nvm_eerd(hw, offset, count, + data + i); + hw->nvm.ops.release(hw); + } else { + status = E1000_ERR_SWFW_SYNC; + } + + if (status != E1000_SUCCESS) + break; + } + + return status; +} + +/** + * igb_write_nvm_srwr_i210 - Write to Shadow RAM using EEWR + * @hw: pointer to the HW structure + * @offset: offset within the Shadow RAM to be written to + * @words: number of words to write + * @data: 16 bit word(s) to be written to the Shadow RAM + * + * Writes data to Shadow RAM at offset using EEWR register. + * + * If e1000_update_nvm_checksum is not called after this function , the + * data will not be committed to FLASH and also Shadow RAM will most likely + * contain an invalid checksum. + * + * If error code is returned, data and Shadow RAM may be inconsistent - buffer + * partially written. + **/ +s32 igb_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data) +{ + s32 status = E1000_SUCCESS; + u16 i, count; + + /* We cannot hold synchronization semaphores for too long, + * because of forceful takeover procedure. However it is more efficient + * to write in bursts than synchronizing access for each word. */ + for (i = 0; i < words; i += E1000_EERD_EEWR_MAX_COUNT) { + count = (words - i) / E1000_EERD_EEWR_MAX_COUNT > 0 ? + E1000_EERD_EEWR_MAX_COUNT : (words - i); + if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) { + status = igb_write_nvm_srwr(hw, offset, count, + data + i); + hw->nvm.ops.release(hw); + } else { + status = E1000_ERR_SWFW_SYNC; + } + + if (status != E1000_SUCCESS) + break; + } + + return status; +} + +/** + * igb_write_nvm_srwr - Write to Shadow Ram using EEWR + * @hw: pointer to the HW structure + * @offset: offset within the Shadow Ram to be written to + * @words: number of words to write + * @data: 16 bit word(s) to be written to the Shadow Ram + * + * Writes data to Shadow Ram at offset using EEWR register. + * + * If igb_update_nvm_checksum is not called after this function , the + * Shadow Ram will most likely contain an invalid checksum. + **/ +static s32 igb_write_nvm_srwr(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 i, k, eewr = 0; + u32 attempts = 100000; + s32 ret_val = E1000_SUCCESS; + + /* + * A check for invalid values: offset too large, too many words, + * too many words for the offset, and not enough words. + */ + if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || + (words == 0)) { + hw_dbg("nvm parameter(s) out of bounds\n"); + ret_val = -E1000_ERR_NVM; + goto out; + } + + for (i = 0; i < words; i++) { + eewr = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) | + (data[i] << E1000_NVM_RW_REG_DATA) | + E1000_NVM_RW_REG_START; + + wr32(E1000_SRWR, eewr); + + for (k = 0; k < attempts; k++) { + if (E1000_NVM_RW_REG_DONE & + rd32(E1000_SRWR)) { + ret_val = E1000_SUCCESS; + break; + } + udelay(5); + } + + if (ret_val != E1000_SUCCESS) { + hw_dbg("Shadow RAM write EEWR timed out\n"); + break; + } + } + +out: + return ret_val; +} + +/** + * igb_read_nvm_i211 - Read NVM wrapper function for I211 + * @hw: pointer to the HW structure + * @address: the word address (aka eeprom offset) to read + * @data: pointer to the data read + * + * Wrapper function to return data formerly found in the NVM. + **/ +s32 igb_read_nvm_i211(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data) +{ + s32 ret_val = E1000_SUCCESS; + + /* Only the MAC addr is required to be present in the iNVM */ + switch (offset) { + case NVM_MAC_ADDR: + ret_val = igb_read_invm_i211(hw, offset, &data[0]); + ret_val |= igb_read_invm_i211(hw, offset+1, &data[1]); + ret_val |= igb_read_invm_i211(hw, offset+2, &data[2]); + if (ret_val != E1000_SUCCESS) + hw_dbg("MAC Addr not found in iNVM\n"); + break; + case NVM_ID_LED_SETTINGS: + case NVM_INIT_CTRL_2: + case NVM_INIT_CTRL_4: + case NVM_LED_1_CFG: + case NVM_LED_0_2_CFG: + igb_read_invm_i211(hw, offset, data); + break; + case NVM_COMPAT: + *data = ID_LED_DEFAULT_I210; + break; + case NVM_SUB_DEV_ID: + *data = hw->subsystem_device_id; + break; + case NVM_SUB_VEN_ID: + *data = hw->subsystem_vendor_id; + break; + case NVM_DEV_ID: + *data = hw->device_id; + break; + case NVM_VEN_ID: + *data = hw->vendor_id; + break; + default: + hw_dbg("NVM word 0x%02x is not mapped.\n", offset); + *data = NVM_RESERVED_WORD; + break; + } + return ret_val; +} + +/** + * igb_read_invm_i211 - Reads OTP + * @hw: pointer to the HW structure + * @address: the word address (aka eeprom offset) to read + * @data: pointer to the data read + * + * Reads 16-bit words from the OTP. Return error when the word is not + * stored in OTP. + **/ +s32 igb_read_invm_i211(struct e1000_hw *hw, u16 address, u16 *data) +{ + s32 status = -E1000_ERR_INVM_VALUE_NOT_FOUND; + u32 invm_dword; + u16 i; + u8 record_type, word_address; + + for (i = 0; i < E1000_INVM_SIZE; i++) { + invm_dword = rd32(E1000_INVM_DATA_REG(i)); + /* Get record type */ + record_type = INVM_DWORD_TO_RECORD_TYPE(invm_dword); + if (record_type == E1000_INVM_UNINITIALIZED_STRUCTURE) + break; + if (record_type == E1000_INVM_CSR_AUTOLOAD_STRUCTURE) + i += E1000_INVM_CSR_AUTOLOAD_DATA_SIZE_IN_DWORDS; + if (record_type == E1000_INVM_RSA_KEY_SHA256_STRUCTURE) + i += E1000_INVM_RSA_KEY_SHA256_DATA_SIZE_IN_DWORDS; + if (record_type == E1000_INVM_WORD_AUTOLOAD_STRUCTURE) { + word_address = INVM_DWORD_TO_WORD_ADDRESS(invm_dword); + if (word_address == (u8)address) { + *data = INVM_DWORD_TO_WORD_DATA(invm_dword); + hw_dbg("Read INVM Word 0x%02x = %x", + address, *data); + status = E1000_SUCCESS; + break; + } + } + } + if (status != E1000_SUCCESS) + hw_dbg("Requested word 0x%02x not found in OTP\n", address); + return status; +} + +/** + * igb_validate_nvm_checksum_i210 - Validate EEPROM checksum + * @hw: pointer to the HW structure + * + * Calculates the EEPROM checksum by reading/adding each word of the EEPROM + * and then verifies that the sum of the EEPROM is equal to 0xBABA. + **/ +s32 igb_validate_nvm_checksum_i210(struct e1000_hw *hw) +{ + s32 status = E1000_SUCCESS; + s32 (*read_op_ptr)(struct e1000_hw *, u16, u16, u16 *); + + if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) { + + /* + * Replace the read function with semaphore grabbing with + * the one that skips this for a while. + * We have semaphore taken already here. + */ + read_op_ptr = hw->nvm.ops.read; + hw->nvm.ops.read = igb_read_nvm_eerd; + + status = igb_validate_nvm_checksum(hw); + + /* Revert original read operation. */ + hw->nvm.ops.read = read_op_ptr; + + hw->nvm.ops.release(hw); + } else { + status = E1000_ERR_SWFW_SYNC; + } + + return status; +} + + +/** + * igb_update_nvm_checksum_i210 - Update EEPROM checksum + * @hw: pointer to the HW structure + * + * Updates the EEPROM checksum by reading/adding each word of the EEPROM + * up to the checksum. Then calculates the EEPROM checksum and writes the + * value to the EEPROM. Next commit EEPROM data onto the Flash. + **/ +s32 igb_update_nvm_checksum_i210(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + u16 checksum = 0; + u16 i, nvm_data; + + /* + * Read the first word from the EEPROM. If this times out or fails, do + * not continue or we could be in for a very long wait while every + * EEPROM read fails + */ + ret_val = igb_read_nvm_eerd(hw, 0, 1, &nvm_data); + if (ret_val != E1000_SUCCESS) { + hw_dbg("EEPROM read failed\n"); + goto out; + } + + if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) { + /* + * Do not use hw->nvm.ops.write, hw->nvm.ops.read + * because we do not want to take the synchronization + * semaphores twice here. + */ + + for (i = 0; i < NVM_CHECKSUM_REG; i++) { + ret_val = igb_read_nvm_eerd(hw, i, 1, &nvm_data); + if (ret_val) { + hw->nvm.ops.release(hw); + hw_dbg("NVM Read Error while updating checksum.\n"); + goto out; + } + checksum += nvm_data; + } + checksum = (u16) NVM_SUM - checksum; + ret_val = igb_write_nvm_srwr(hw, NVM_CHECKSUM_REG, 1, + &checksum); + if (ret_val != E1000_SUCCESS) { + hw->nvm.ops.release(hw); + hw_dbg("NVM Write Error while updating checksum.\n"); + goto out; + } + + hw->nvm.ops.release(hw); + + ret_val = igb_update_flash_i210(hw); + } else { + ret_val = -E1000_ERR_SWFW_SYNC; + } +out: + return ret_val; +} + +/** + * igb_update_flash_i210 - Commit EEPROM to the flash + * @hw: pointer to the HW structure + * + **/ +s32 igb_update_flash_i210(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + u32 flup; + + ret_val = igb_pool_flash_update_done_i210(hw); + if (ret_val == -E1000_ERR_NVM) { + hw_dbg("Flash update time out\n"); + goto out; + } + + flup = rd32(E1000_EECD) | E1000_EECD_FLUPD_I210; + wr32(E1000_EECD, flup); + + ret_val = igb_pool_flash_update_done_i210(hw); + if (ret_val == E1000_SUCCESS) + hw_dbg("Flash update complete\n"); + else + hw_dbg("Flash update time out\n"); + +out: + return ret_val; +} + +/** + * igb_pool_flash_update_done_i210 - Pool FLUDONE status. + * @hw: pointer to the HW structure + * + **/ +s32 igb_pool_flash_update_done_i210(struct e1000_hw *hw) +{ + s32 ret_val = -E1000_ERR_NVM; + u32 i, reg; + + for (i = 0; i < E1000_FLUDONE_ATTEMPTS; i++) { + reg = rd32(E1000_EECD); + if (reg & E1000_EECD_FLUDONE_I210) { + ret_val = E1000_SUCCESS; + break; + } + udelay(5); + } + + return ret_val; +} + +/** + * igb_valid_led_default_i210 - Verify a valid default LED config + * @hw: pointer to the HW structure + * @data: pointer to the NVM (EEPROM) + * + * Read the EEPROM for the current default LED configuration. If the + * LED configuration is not valid, set to a valid LED configuration. + **/ +s32 igb_valid_led_default_i210(struct e1000_hw *hw, u16 *data) +{ + s32 ret_val; + + ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data); + if (ret_val) { + hw_dbg("NVM Read Error\n"); + goto out; + } + + if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) { + switch (hw->phy.media_type) { + case e1000_media_type_internal_serdes: + *data = ID_LED_DEFAULT_I210_SERDES; + break; + case e1000_media_type_copper: + default: + *data = ID_LED_DEFAULT_I210; + break; + } + } +out: + return ret_val; +} diff --git a/trunk/drivers/net/ethernet/intel/igb/e1000_i210.h b/trunk/drivers/net/ethernet/intel/igb/e1000_i210.h new file mode 100644 index 000000000000..5dc2bd3f50bc --- /dev/null +++ b/trunk/drivers/net/ethernet/intel/igb/e1000_i210.h @@ -0,0 +1,76 @@ +/******************************************************************************* + + Intel(R) Gigabit Ethernet Linux driver + Copyright(c) 2007-2012 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, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + 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_ + +extern s32 igb_update_flash_i210(struct e1000_hw *hw); +extern s32 igb_update_nvm_checksum_i210(struct e1000_hw *hw); +extern s32 igb_validate_nvm_checksum_i210(struct e1000_hw *hw); +extern s32 igb_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset, + u16 words, u16 *data); +extern s32 igb_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset, + u16 words, u16 *data); +extern s32 igb_read_invm_i211(struct e1000_hw *hw, u16 address, u16 *data); +extern s32 igb_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask); +extern void igb_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask); +extern s32 igb_acquire_nvm_i210(struct e1000_hw *hw); +extern void igb_release_nvm_i210(struct e1000_hw *hw); +extern s32 igb_valid_led_default_i210(struct e1000_hw *hw, u16 *data); +extern s32 igb_read_nvm_i211(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data); + +#define E1000_STM_OPCODE 0xDB00 +#define E1000_EEPROM_FLASH_SIZE_WORD 0x11 + +#define INVM_DWORD_TO_RECORD_TYPE(invm_dword) \ + (u8)((invm_dword) & 0x7) +#define INVM_DWORD_TO_WORD_ADDRESS(invm_dword) \ + (u8)(((invm_dword) & 0x0000FE00) >> 9) +#define INVM_DWORD_TO_WORD_DATA(invm_dword) \ + (u16)(((invm_dword) & 0xFFFF0000) >> 16) + +enum E1000_INVM_STRUCTURE_TYPE { + E1000_INVM_UNINITIALIZED_STRUCTURE = 0x00, + E1000_INVM_WORD_AUTOLOAD_STRUCTURE = 0x01, + E1000_INVM_CSR_AUTOLOAD_STRUCTURE = 0x02, + E1000_INVM_PHY_REGISTER_AUTOLOAD_STRUCTURE = 0x03, + E1000_INVM_RSA_KEY_SHA256_STRUCTURE = 0x04, + E1000_INVM_INVALIDATED_STRUCTURE = 0x0F, +}; + +#define E1000_INVM_RSA_KEY_SHA256_DATA_SIZE_IN_DWORDS 8 +#define E1000_INVM_CSR_AUTOLOAD_DATA_SIZE_IN_DWORDS 1 + +#define ID_LED_DEFAULT_I210 ((ID_LED_OFF1_ON2 << 8) | \ + (ID_LED_OFF1_OFF2 << 4) | \ + (ID_LED_DEF1_DEF2)) +#define ID_LED_DEFAULT_I210_SERDES ((ID_LED_DEF1_DEF2 << 8) | \ + (ID_LED_DEF1_DEF2 << 4) | \ + (ID_LED_DEF1_DEF2)) + +#endif diff --git a/trunk/drivers/net/ethernet/intel/igb/e1000_mac.c b/trunk/drivers/net/ethernet/intel/igb/e1000_mac.c index f57338afd71f..819c145ac762 100644 --- a/trunk/drivers/net/ethernet/intel/igb/e1000_mac.c +++ b/trunk/drivers/net/ethernet/intel/igb/e1000_mac.c @@ -658,6 +658,7 @@ s32 igb_setup_link(struct e1000_hw *hw) ret_val = igb_set_fc_watermarks(hw); out: + return ret_val; } diff --git a/trunk/drivers/net/ethernet/intel/igb/e1000_nvm.c b/trunk/drivers/net/ethernet/intel/igb/e1000_nvm.c index fa2c6ba62139..aa5fcdf3f357 100644 --- a/trunk/drivers/net/ethernet/intel/igb/e1000_nvm.c +++ b/trunk/drivers/net/ethernet/intel/igb/e1000_nvm.c @@ -710,4 +710,3 @@ s32 igb_update_nvm_checksum(struct e1000_hw *hw) out: return ret_val; } - diff --git a/trunk/drivers/net/ethernet/intel/igb/e1000_phy.c b/trunk/drivers/net/ethernet/intel/igb/e1000_phy.c index 789de5b83aad..7be98b6f1052 100644 --- a/trunk/drivers/net/ethernet/intel/igb/e1000_phy.c +++ b/trunk/drivers/net/ethernet/intel/igb/e1000_phy.c @@ -35,6 +35,7 @@ static s32 igb_phy_setup_autoneg(struct e1000_hw *hw); static void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl); static s32 igb_wait_autoneg(struct e1000_hw *hw); +static s32 igb_set_master_slave_mode(struct e1000_hw *hw); /* Cable length tables */ static const u16 e1000_m88_cable_length_table[] = @@ -570,6 +571,11 @@ s32 igb_copper_link_setup_m88(struct e1000_hw *hw) hw_dbg("Error committing the PHY changes\n"); goto out; } + if (phy->type == e1000_phy_i210) { + ret_val = igb_set_master_slave_mode(hw); + if (ret_val) + return ret_val; + } out: return ret_val; @@ -1213,12 +1219,22 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw) goto out; if (!link) { - if (hw->phy.type != e1000_phy_m88 || - hw->phy.id == I347AT4_E_PHY_ID || - hw->phy.id == M88E1112_E_PHY_ID) { + bool reset_dsp = true; + + switch (hw->phy.id) { + case I347AT4_E_PHY_ID: + case M88E1112_E_PHY_ID: + case I210_I_PHY_ID: + reset_dsp = false; + break; + default: + if (hw->phy.type != e1000_phy_m88) + reset_dsp = false; + break; + } + if (!reset_dsp) hw_dbg("Link taking longer than expected.\n"); - } else { - + else { /* * We didn't get link. * Reset the DSP and cross our fingers. @@ -1243,7 +1259,8 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw) if (hw->phy.type != e1000_phy_m88 || hw->phy.id == I347AT4_E_PHY_ID || - hw->phy.id == M88E1112_E_PHY_ID) + hw->phy.id == M88E1112_E_PHY_ID || + hw->phy.id == I210_I_PHY_ID) goto out; ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); @@ -1441,6 +1458,7 @@ s32 igb_check_downshift(struct e1000_hw *hw) u16 phy_data, offset, mask; switch (phy->type) { + case e1000_phy_i210: case e1000_phy_m88: case e1000_phy_gg82563: offset = M88E1000_PHY_SPEC_STATUS; @@ -1476,7 +1494,7 @@ s32 igb_check_downshift(struct e1000_hw *hw) * * Polarity is determined based on the PHY specific status register. **/ -static s32 igb_check_polarity_m88(struct e1000_hw *hw) +s32 igb_check_polarity_m88(struct e1000_hw *hw) { struct e1000_phy_info *phy = &hw->phy; s32 ret_val; @@ -1665,6 +1683,7 @@ s32 igb_get_cable_length_m88_gen2(struct e1000_hw *hw) u16 phy_data, phy_data2, index, default_page, is_cm; switch (hw->phy.id) { + case I210_I_PHY_ID: case I347AT4_E_PHY_ID: /* Remember the original page select and set it to 7 */ ret_val = phy->ops.read_reg(hw, I347AT4_PAGE_SELECT, @@ -2129,10 +2148,16 @@ s32 igb_phy_init_script_igp3(struct e1000_hw *hw) void igb_power_up_phy_copper(struct e1000_hw *hw) { u16 mii_reg = 0; + u16 power_reg = 0; /* The PHY will retain its settings across a power down/up cycle */ hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg); mii_reg &= ~MII_CR_POWER_DOWN; + if (hw->phy.type == e1000_phy_i210) { + hw->phy.ops.read_reg(hw, GS40G_COPPER_SPEC, &power_reg); + power_reg &= ~GS40G_CS_POWER_DOWN; + hw->phy.ops.write_reg(hw, GS40G_COPPER_SPEC, power_reg); + } hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg); } @@ -2146,10 +2171,18 @@ void igb_power_up_phy_copper(struct e1000_hw *hw) void igb_power_down_phy_copper(struct e1000_hw *hw) { u16 mii_reg = 0; + u16 power_reg = 0; /* The PHY will retain its settings across a power down/up cycle */ hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg); mii_reg |= MII_CR_POWER_DOWN; + + /* i210 Phy requires an additional bit for power up/down */ + if (hw->phy.type == e1000_phy_i210) { + hw->phy.ops.read_reg(hw, GS40G_COPPER_SPEC, &power_reg); + power_reg |= GS40G_CS_POWER_DOWN; + hw->phy.ops.write_reg(hw, GS40G_COPPER_SPEC, power_reg); + } hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg); msleep(1); } @@ -2345,3 +2378,103 @@ s32 igb_get_cable_length_82580(struct e1000_hw *hw) out: return ret_val; } + +/** + * igb_write_phy_reg_gs40g - Write GS40G PHY register + * @hw: pointer to the HW structure + * @offset: lower half is register offset to write to + * upper half is page to use. + * @data: data to write at register offset + * + * Acquires semaphore, if necessary, then writes the data to PHY register + * at the offset. Release any acquired semaphores before exiting. + **/ +s32 igb_write_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 data) +{ + s32 ret_val; + u16 page = offset >> GS40G_PAGE_SHIFT; + + offset = offset & GS40G_OFFSET_MASK; + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + return ret_val; + + ret_val = igb_write_phy_reg_mdic(hw, GS40G_PAGE_SELECT, page); + if (ret_val) + goto release; + ret_val = igb_write_phy_reg_mdic(hw, offset, data); + +release: + hw->phy.ops.release(hw); + return ret_val; +} + +/** + * igb_read_phy_reg_gs40g - Read GS40G PHY register + * @hw: pointer to the HW structure + * @offset: lower half is register offset to read to + * upper half is page to use. + * @data: data to read at register offset + * + * Acquires semaphore, if necessary, then reads the data in the PHY register + * at the offset. Release any acquired semaphores before exiting. + **/ +s32 igb_read_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 *data) +{ + s32 ret_val; + u16 page = offset >> GS40G_PAGE_SHIFT; + + offset = offset & GS40G_OFFSET_MASK; + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + return ret_val; + + ret_val = igb_write_phy_reg_mdic(hw, GS40G_PAGE_SELECT, page); + if (ret_val) + goto release; + ret_val = igb_read_phy_reg_mdic(hw, offset, data); + +release: + hw->phy.ops.release(hw); + return ret_val; +} + +/** + * igb_set_master_slave_mode - Setup PHY for Master/slave mode + * @hw: pointer to the HW structure + * + * Sets up Master/slave mode + **/ +static s32 igb_set_master_slave_mode(struct e1000_hw *hw) +{ + s32 ret_val; + u16 phy_data; + + /* Resolve Master/Slave mode */ + ret_val = hw->phy.ops.read_reg(hw, PHY_1000T_CTRL, &phy_data); + if (ret_val) + return ret_val; + + /* load defaults for future use */ + hw->phy.original_ms_type = (phy_data & CR_1000T_MS_ENABLE) ? + ((phy_data & CR_1000T_MS_VALUE) ? + e1000_ms_force_master : + e1000_ms_force_slave) : e1000_ms_auto; + + switch (hw->phy.ms_type) { + case e1000_ms_force_master: + phy_data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE); + break; + case e1000_ms_force_slave: + phy_data |= CR_1000T_MS_ENABLE; + phy_data &= ~(CR_1000T_MS_VALUE); + break; + case e1000_ms_auto: + phy_data &= ~CR_1000T_MS_ENABLE; + /* fall-through */ + default: + break; + } + + return hw->phy.ops.write_reg(hw, PHY_1000T_CTRL, phy_data); +} diff --git a/trunk/drivers/net/ethernet/intel/igb/e1000_phy.h b/trunk/drivers/net/ethernet/intel/igb/e1000_phy.h index 4c32ac66ff39..34e40619f16b 100644 --- a/trunk/drivers/net/ethernet/intel/igb/e1000_phy.h +++ b/trunk/drivers/net/ethernet/intel/igb/e1000_phy.h @@ -73,6 +73,9 @@ s32 igb_copper_link_setup_82580(struct e1000_hw *hw); s32 igb_get_phy_info_82580(struct e1000_hw *hw); s32 igb_phy_force_speed_duplex_82580(struct e1000_hw *hw); s32 igb_get_cable_length_82580(struct e1000_hw *hw); +s32 igb_read_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 *data); +s32 igb_write_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 data); +s32 igb_check_polarity_m88(struct e1000_hw *hw); /* IGP01E1000 Specific Registers */ #define IGP01E1000_PHY_PORT_CONFIG 0x10 /* Port Config */ @@ -114,6 +117,13 @@ s32 igb_get_cable_length_82580(struct e1000_hw *hw); /* I82580 PHY Diagnostics Status */ #define I82580_DSTATUS_CABLE_LENGTH 0x03FC #define I82580_DSTATUS_CABLE_LENGTH_SHIFT 2 + +/* 82580 PHY Power Management */ +#define E1000_82580_PHY_POWER_MGMT 0xE14 +#define E1000_82580_PM_SPD 0x0001 /* Smart Power Down */ +#define E1000_82580_PM_D0_LPLU 0x0002 /* For D0a states */ +#define E1000_82580_PM_D3_LPLU 0x0004 /* For all other states */ + /* Enable flexible speed on link-up */ #define IGP02E1000_PM_D0_LPLU 0x0002 /* For D0a states */ #define IGP02E1000_PM_D3_LPLU 0x0004 /* For all other states */ @@ -133,4 +143,16 @@ s32 igb_get_cable_length_82580(struct e1000_hw *hw); #define E1000_CABLE_LENGTH_UNDEFINED 0xFF +/* GS40G - I210 PHY defines */ +#define GS40G_PAGE_SELECT 0x16 +#define GS40G_PAGE_SHIFT 16 +#define GS40G_OFFSET_MASK 0xFFFF +#define GS40G_PAGE_2 0x20000 +#define GS40G_MAC_REG2 0x15 +#define GS40G_MAC_LB 0x4140 +#define GS40G_MAC_SPEED_1G 0X0006 +#define GS40G_COPPER_SPEC 0x0010 +#define GS40G_CS_POWER_DOWN 0x0002 +#define GS40G_LINE_LB 0x4000 + #endif diff --git a/trunk/drivers/net/ethernet/intel/igb/e1000_regs.h b/trunk/drivers/net/ethernet/intel/igb/e1000_regs.h index ccdf36d503fd..35d1e4f2c92c 100644 --- a/trunk/drivers/net/ethernet/intel/igb/e1000_regs.h +++ b/trunk/drivers/net/ethernet/intel/igb/e1000_regs.h @@ -352,4 +352,18 @@ #define E1000_O2BGPTC 0x08FE4 /* OS2BMC packets received by BMC */ #define E1000_O2BSPC 0x0415C /* OS2BMC packets transmitted by host */ +#define E1000_SRWR 0x12018 /* Shadow Ram Write Register - RW */ +#define E1000_I210_FLMNGCTL 0x12038 +#define E1000_I210_FLMNGDATA 0x1203C +#define E1000_I210_FLMNGCNT 0x12040 + +#define E1000_I210_FLSWCTL 0x12048 +#define E1000_I210_FLSWDATA 0x1204C +#define E1000_I210_FLSWCNT 0x12050 + +#define E1000_I210_FLA 0x1201C + +#define E1000_INVM_DATA_REG(_n) (0x12120 + 4*(_n)) +#define E1000_INVM_SIZE 64 /* Number of INVM Data Registers */ + #endif diff --git a/trunk/drivers/net/ethernet/intel/igb/igb.h b/trunk/drivers/net/ethernet/intel/igb/igb.h index 8e33bdd33eea..ae6d3f393a54 100644 --- a/trunk/drivers/net/ethernet/intel/igb/igb.h +++ b/trunk/drivers/net/ethernet/intel/igb/igb.h @@ -35,8 +35,8 @@ #include "e1000_82575.h" #include -#include #include +#include #include #include @@ -65,10 +65,13 @@ struct igb_adapter; #define MAX_Q_VECTORS 8 /* Transmit and receive queues */ -#define IGB_MAX_RX_QUEUES (adapter->vfs_allocated_count ? 2 : \ - (hw->mac.type > e1000_82575 ? 8 : 4)) +#define IGB_MAX_RX_QUEUES ((adapter->vfs_allocated_count ? 2 : \ + (hw->mac.type > e1000_82575 ? 8 : 4))) +#define IGB_MAX_RX_QUEUES_I210 4 +#define IGB_MAX_RX_QUEUES_I211 2 #define IGB_MAX_TX_QUEUES 16 - +#define IGB_MAX_TX_QUEUES_I210 4 +#define IGB_MAX_TX_QUEUES_I211 2 #define IGB_MAX_VF_MC_ENTRIES 30 #define IGB_MAX_VF_FUNCTIONS 8 #define IGB_MAX_VFTA_ENTRIES 128 @@ -328,9 +331,6 @@ struct igb_adapter { /* OS defined structs */ struct pci_dev *pdev; - struct cyclecounter cycles; - struct timecounter clock; - struct timecompare compare; struct hwtstamp_config hwtstamp_config; spinlock_t stats64_lock; @@ -364,6 +364,13 @@ struct igb_adapter { u32 wvbr; int node; u32 *shadow_vfta; + + struct ptp_clock *ptp_clock; + struct ptp_clock_info caps; + struct delayed_work overflow_work; + spinlock_t tmreg_lock; + struct cyclecounter cc; + struct timecounter tc; }; #define IGB_FLAG_HAS_MSI (1 << 0) @@ -378,7 +385,6 @@ struct igb_adapter { #define IGB_DMCTLX_DCFLUSH_DIS 0x80000000 /* Disable DMA Coal Flush */ #define IGB_82576_TSYNC_SHIFT 19 -#define IGB_82580_TSYNC_SHIFT 24 #define IGB_TS_HDR_LEN 16 enum e1000_state_t { __IGB_TESTING, @@ -414,7 +420,15 @@ extern void igb_update_stats(struct igb_adapter *, struct rtnl_link_stats64 *); extern bool igb_has_link(struct igb_adapter *adapter); extern void igb_set_ethtool_ops(struct net_device *); extern void igb_power_up_link(struct igb_adapter *); +#ifdef CONFIG_IGB_PTP +extern void igb_ptp_init(struct igb_adapter *adapter); +extern void igb_ptp_remove(struct igb_adapter *adapter); +extern void igb_systim_to_hwtstamp(struct igb_adapter *adapter, + struct skb_shared_hwtstamps *hwtstamps, + u64 systim); + +#endif static inline s32 igb_reset_phy(struct e1000_hw *hw) { if (hw->phy.ops.reset) diff --git a/trunk/drivers/net/ethernet/intel/igb/igb_ethtool.c b/trunk/drivers/net/ethernet/intel/igb/igb_ethtool.c index e10821a0f249..812d4f963bd1 100644 --- a/trunk/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/trunk/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -335,7 +335,7 @@ static void igb_set_msglevel(struct net_device *netdev, u32 data) static int igb_get_regs_len(struct net_device *netdev) { -#define IGB_REGS_LEN 551 +#define IGB_REGS_LEN 739 return IGB_REGS_LEN * sizeof(u32); } @@ -552,10 +552,49 @@ static void igb_get_regs(struct net_device *netdev, regs_buff[548] = rd32(E1000_TDFT); regs_buff[549] = rd32(E1000_TDFHS); regs_buff[550] = rd32(E1000_TDFPC); - regs_buff[551] = adapter->stats.o2bgptc; - regs_buff[552] = adapter->stats.b2ospc; - regs_buff[553] = adapter->stats.o2bspc; - regs_buff[554] = adapter->stats.b2ogprc; + + if (hw->mac.type > e1000_82580) { + regs_buff[551] = adapter->stats.o2bgptc; + regs_buff[552] = adapter->stats.b2ospc; + regs_buff[553] = adapter->stats.o2bspc; + regs_buff[554] = adapter->stats.b2ogprc; + } + + if (hw->mac.type != e1000_82576) + return; + for (i = 0; i < 12; i++) + regs_buff[555 + i] = rd32(E1000_SRRCTL(i + 4)); + for (i = 0; i < 4; i++) + regs_buff[567 + i] = rd32(E1000_PSRTYPE(i + 4)); + for (i = 0; i < 12; i++) + regs_buff[571 + i] = rd32(E1000_RDBAL(i + 4)); + for (i = 0; i < 12; i++) + regs_buff[583 + i] = rd32(E1000_RDBAH(i + 4)); + for (i = 0; i < 12; i++) + regs_buff[595 + i] = rd32(E1000_RDLEN(i + 4)); + for (i = 0; i < 12; i++) + regs_buff[607 + i] = rd32(E1000_RDH(i + 4)); + for (i = 0; i < 12; i++) + regs_buff[619 + i] = rd32(E1000_RDT(i + 4)); + for (i = 0; i < 12; i++) + regs_buff[631 + i] = rd32(E1000_RXDCTL(i + 4)); + + for (i = 0; i < 12; i++) + regs_buff[643 + i] = rd32(E1000_TDBAL(i + 4)); + for (i = 0; i < 12; i++) + regs_buff[655 + i] = rd32(E1000_TDBAH(i + 4)); + for (i = 0; i < 12; i++) + regs_buff[667 + i] = rd32(E1000_TDLEN(i + 4)); + for (i = 0; i < 12; i++) + regs_buff[679 + i] = rd32(E1000_TDH(i + 4)); + for (i = 0; i < 12; i++) + regs_buff[691 + i] = rd32(E1000_TDT(i + 4)); + for (i = 0; i < 12; i++) + regs_buff[703 + i] = rd32(E1000_TXDCTL(i + 4)); + for (i = 0; i < 12; i++) + regs_buff[715 + i] = rd32(E1000_TDWBAL(i + 4)); + for (i = 0; i < 12; i++) + regs_buff[727 + i] = rd32(E1000_TDWBAH(i + 4)); } static int igb_get_eeprom_len(struct net_device *netdev) @@ -624,6 +663,9 @@ static int igb_set_eeprom(struct net_device *netdev, if (eeprom->len == 0) return -EOPNOTSUPP; + if (hw->mac.type == e1000_i211) + return -EOPNOTSUPP; + if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16))) return -EFAULT; @@ -851,6 +893,36 @@ struct igb_reg_test { #define TABLE64_TEST_LO 5 #define TABLE64_TEST_HI 6 +/* i210 reg test */ +static struct igb_reg_test reg_test_i210[] = { + { E1000_FCAL, 0x100, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_FCAH, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, + { E1000_FCT, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, + { E1000_RDBAL(0), 0x100, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, + { E1000_RDBAH(0), 0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_RDLEN(0), 0x100, 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, + /* RDH is read-only for i210, only test RDT. */ + { E1000_RDT(0), 0x100, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, + { E1000_FCRTH, 0x100, 1, PATTERN_TEST, 0x0000FFF0, 0x0000FFF0 }, + { E1000_FCTTV, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, + { E1000_TIPG, 0x100, 1, PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF }, + { E1000_TDBAL(0), 0x100, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, + { E1000_TDBAH(0), 0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_TDLEN(0), 0x100, 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, + { E1000_TDT(0), 0x100, 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_TCTL, 0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, + { E1000_RA, 0, 16, TABLE64_TEST_LO, + 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_RA, 0, 16, TABLE64_TEST_HI, + 0x900FFFFF, 0xFFFFFFFF }, + { E1000_MTA, 0, 128, TABLE32_TEST, + 0xFFFFFFFF, 0xFFFFFFFF }, + { 0, 0, 0, 0, 0 } +}; + /* i350 reg test */ static struct igb_reg_test reg_test_i350[] = { { E1000_FCAL, 0x100, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, @@ -1073,6 +1145,11 @@ static int igb_reg_test(struct igb_adapter *adapter, u64 *data) test = reg_test_i350; toggle = 0x7FEFF3FF; break; + case e1000_i210: + case e1000_i211: + test = reg_test_i210; + toggle = 0x7FEFF3FF; + break; case e1000_82580: test = reg_test_82580; toggle = 0x7FEFF3FF; @@ -1154,23 +1231,13 @@ static int igb_reg_test(struct igb_adapter *adapter, u64 *data) static int igb_eeprom_test(struct igb_adapter *adapter, u64 *data) { - u16 temp; - u16 checksum = 0; - u16 i; - *data = 0; - /* Read and add up the contents of the EEPROM */ - for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) { - if ((adapter->hw.nvm.ops.read(&adapter->hw, i, 1, &temp)) < 0) { - *data = 1; - break; - } - checksum += temp; - } - /* If Checksum is not Correct return error else test passed */ - if ((checksum != (u16) NVM_SUM) && !(*data)) - *data = 2; + /* Validate eeprom on all parts but i211 */ + if (adapter->hw.mac.type != e1000_i211) { + if (adapter->hw.nvm.ops.validate(&adapter->hw) < 0) + *data = 2; + } return *data; } @@ -1236,6 +1303,8 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data) ics_mask = 0x77DCFED5; break; case e1000_i350: + case e1000_i210: + case e1000_i211: ics_mask = 0x77DCFED5; break; default: @@ -1402,23 +1471,35 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; u32 ctrl_reg = 0; + u16 phy_reg = 0; hw->mac.autoneg = false; - if (hw->phy.type == e1000_phy_m88) { + switch (hw->phy.type) { + case e1000_phy_m88: /* Auto-MDI/MDIX Off */ igb_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); /* reset to update Auto-MDI/MDIX */ igb_write_phy_reg(hw, PHY_CONTROL, 0x9140); /* autoneg off */ igb_write_phy_reg(hw, PHY_CONTROL, 0x8140); - } else if (hw->phy.type == e1000_phy_82580) { + break; + case e1000_phy_82580: /* enable MII loopback */ igb_write_phy_reg(hw, I82580_PHY_LBK_CTRL, 0x8041); + break; + case e1000_phy_i210: + /* set loopback speed in PHY */ + igb_read_phy_reg(hw, (GS40G_PAGE_SELECT & GS40G_PAGE_2), + &phy_reg); + phy_reg |= GS40G_MAC_SPEED_1G; + igb_write_phy_reg(hw, (GS40G_PAGE_SELECT & GS40G_PAGE_2), + phy_reg); + ctrl_reg = rd32(E1000_CTRL_EXT); + default: + break; } - ctrl_reg = rd32(E1000_CTRL); - /* force 1000, set loopback */ igb_write_phy_reg(hw, PHY_CONTROL, 0x4140); @@ -1431,7 +1512,7 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter) E1000_CTRL_FD | /* Force Duplex to FULL */ E1000_CTRL_SLU); /* Set link up enable bit */ - if (hw->phy.type == e1000_phy_m88) + if ((hw->phy.type == e1000_phy_m88) || (hw->phy.type == e1000_phy_i210)) ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */ wr32(E1000_CTRL, ctrl_reg); @@ -1439,7 +1520,7 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter) /* Disable the receiver on the PHY so when a cable is plugged in, the * PHY does not begin to autoneg when a cable is reconnected to the NIC. */ - if (hw->phy.type == e1000_phy_m88) + if ((hw->phy.type == e1000_phy_m88) || (hw->phy.type == e1000_phy_i210)) igb_phy_disable_receiver(adapter); udelay(500); @@ -1704,6 +1785,14 @@ static int igb_loopback_test(struct igb_adapter *adapter, u64 *data) *data = 0; goto out; } + if ((adapter->hw.mac.type == e1000_i210) + || (adapter->hw.mac.type == e1000_i210)) { + dev_err(&adapter->pdev->dev, + "Loopback test not supported " + "on this part at this time.\n"); + *data = 0; + goto out; + } *data = igb_setup_desc_rings(adapter); if (*data) goto out; diff --git a/trunk/drivers/net/ethernet/intel/igb/igb_main.c b/trunk/drivers/net/ethernet/intel/igb/igb_main.c index 8683ca4748c8..dd3bfe8cd36c 100644 --- a/trunk/drivers/net/ethernet/intel/igb/igb_main.c +++ b/trunk/drivers/net/ethernet/intel/igb/igb_main.c @@ -60,8 +60,8 @@ #include "igb.h" #define MAJ 3 -#define MIN 2 -#define BUILD 10 +#define MIN 4 +#define BUILD 7 #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \ __stringify(BUILD) "-k" char igb_driver_name[] = "igb"; @@ -75,6 +75,11 @@ static const struct e1000_info *igb_info_tbl[] = { }; static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = { + { PCI_VDEVICE(INTEL, E1000_DEV_ID_I211_COPPER), board_82575 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_COPPER), board_82575 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_FIBER), board_82575 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_SERDES), board_82575 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_SGMII), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_COPPER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_FIBER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_SERDES), board_82575 }, @@ -114,7 +119,6 @@ static void igb_free_all_rx_resources(struct igb_adapter *); static void igb_setup_mrqc(struct igb_adapter *); static int igb_probe(struct pci_dev *, const struct pci_device_id *); static void __devexit igb_remove(struct pci_dev *pdev); -static void igb_init_hw_timer(struct igb_adapter *adapter); static int igb_sw_init(struct igb_adapter *); static int igb_open(struct net_device *); static int igb_close(struct net_device *); @@ -565,33 +569,6 @@ static void igb_dump(struct igb_adapter *adapter) return; } - -/** - * igb_read_clock - read raw cycle counter (to be used by time counter) - */ -static cycle_t igb_read_clock(const struct cyclecounter *tc) -{ - struct igb_adapter *adapter = - container_of(tc, struct igb_adapter, cycles); - struct e1000_hw *hw = &adapter->hw; - u64 stamp = 0; - int shift = 0; - - /* - * The timestamp latches on lowest register read. For the 82580 - * the lowest register is SYSTIMR instead of SYSTIML. However we never - * adjusted TIMINCA so SYSTIMR will just read as all 0s so ignore it. - */ - if (hw->mac.type >= e1000_82580) { - stamp = rd32(E1000_SYSTIMR) >> 8; - shift = IGB_82580_TSYNC_SHIFT; - } - - stamp |= (u64)rd32(E1000_SYSTIML) << shift; - stamp |= (u64)rd32(E1000_SYSTIMH) << (shift + 32); - return stamp; -} - /** * igb_get_hw_dev - return device * used by hardware layer to print debugging information @@ -669,6 +646,8 @@ static void igb_cache_ring_register(struct igb_adapter *adapter) case e1000_82575: case e1000_82580: case e1000_i350: + case e1000_i210: + case e1000_i211: default: for (; i < adapter->num_rx_queues; i++) adapter->rx_ring[i]->reg_idx = rbase_offset + i; @@ -755,8 +734,11 @@ static int igb_alloc_queues(struct igb_adapter *adapter) if (adapter->hw.mac.type >= e1000_82576) set_bit(IGB_RING_FLAG_RX_SCTP_CSUM, &ring->flags); - /* On i350, loopback VLAN packets have the tag byte-swapped. */ - if (adapter->hw.mac.type == e1000_i350) + /* + * On i350, i210, and i211, loopback VLAN packets + * have the tag byte-swapped. + * */ + if (adapter->hw.mac.type >= e1000_i350) set_bit(IGB_RING_FLAG_RX_LB_VLAN_BSWAP, &ring->flags); adapter->rx_ring[i] = ring; @@ -850,6 +832,8 @@ static void igb_assign_vector(struct igb_q_vector *q_vector, int msix_vector) break; case e1000_82580: case e1000_i350: + case e1000_i210: + case e1000_i211: /* * On 82580 and newer adapters the scheme is similar to 82576 * however instead of ordering column-major we have things @@ -916,6 +900,8 @@ static void igb_configure_msix(struct igb_adapter *adapter) case e1000_82576: case e1000_82580: case e1000_i350: + case e1000_i210: + case e1000_i211: /* Turn on MSI-X capability first, or our settings * won't stick. And it will take days to debug. */ wr32(E1000_GPIE, E1000_GPIE_MSIX_MODE | @@ -1062,6 +1048,11 @@ static int igb_set_interrupt_capability(struct igb_adapter *adapter) if (!(adapter->flags & IGB_FLAG_QUEUE_PAIRS)) numvecs += adapter->num_tx_queues; + /* i210 and i211 can only have 4 MSIX vectors for rx/tx queues. */ + if ((adapter->hw.mac.type == e1000_i210) + || (adapter->hw.mac.type == e1000_i211)) + numvecs = 4; + /* store the number of vectors reserved for queues */ adapter->num_q_vectors = numvecs; @@ -1069,6 +1060,7 @@ static int igb_set_interrupt_capability(struct igb_adapter *adapter) numvecs++; adapter->msix_entries = kcalloc(numvecs, sizeof(struct msix_entry), GFP_KERNEL); + if (!adapter->msix_entries) goto msi_only; @@ -1662,6 +1654,8 @@ void igb_reset(struct igb_adapter *adapter) pba &= E1000_RXPBS_SIZE_MASK_82576; break; case e1000_82575: + case e1000_i210: + case e1000_i211: default: pba = E1000_PBA_34K; break; @@ -1746,6 +1740,13 @@ void igb_reset(struct igb_adapter *adapter) if (hw->mac.ops.init_hw(hw)) dev_err(&pdev->dev, "Hardware Error\n"); + /* + * Flow control settings reset on hardware reset, so guarantee flow + * control is off when forcing speed. + */ + if (!hw->mac.autoneg) + igb_force_mac_fc(hw); + igb_init_dmac(adapter, pba); if (!netif_running(adapter->netdev)) igb_power_down_link(adapter); @@ -1850,7 +1851,7 @@ static int __devinit igb_probe(struct pci_dev *pdev, */ if (pdev->is_virtfn) { WARN(1, KERN_ERR "%s (%hx:%hx) should not be a VF!\n", - pci_name(pdev), pdev->vendor, pdev->device); + pci_name(pdev), pdev->vendor, pdev->device); return -EINVAL; } @@ -2004,11 +2005,16 @@ static int __devinit igb_probe(struct pci_dev *pdev, * known good starting state */ hw->mac.ops.reset_hw(hw); - /* make sure the NVM is good */ - if (hw->nvm.ops.validate(hw) < 0) { - dev_err(&pdev->dev, "The NVM Checksum Is Not Valid\n"); - err = -EIO; - goto err_eeprom; + /* + * make sure the NVM is good , i211 parts have special NVM that + * doesn't contain a checksum + */ + if (hw->mac.type != e1000_i211) { + if (hw->nvm.ops.validate(hw) < 0) { + dev_err(&pdev->dev, "The NVM Checksum Is Not Valid\n"); + err = -EIO; + goto err_eeprom; + } } /* copy the MAC address out of the NVM */ @@ -2113,9 +2119,11 @@ static int __devinit igb_probe(struct pci_dev *pdev, } #endif +#ifdef CONFIG_IGB_PTP /* do hw tstamp init after resetting */ - igb_init_hw_timer(adapter); + igb_ptp_init(adapter); +#endif dev_info(&pdev->dev, "Intel(R) Gigabit Ethernet Network Connection\n"); /* print bus type/speed/width info */ dev_info(&pdev->dev, "%s: (PCIe:%s:%s) %pM\n", @@ -2140,6 +2148,8 @@ static int __devinit igb_probe(struct pci_dev *pdev, adapter->num_rx_queues, adapter->num_tx_queues); switch (hw->mac.type) { case e1000_i350: + case e1000_i210: + case e1000_i211: igb_set_eee_i350(hw); break; default: @@ -2187,7 +2197,10 @@ static void __devexit igb_remove(struct pci_dev *pdev) struct e1000_hw *hw = &adapter->hw; pm_runtime_get_noresume(&pdev->dev); +#ifdef CONFIG_IGB_PTP + igb_ptp_remove(adapter); +#endif /* * The watchdog timer may be rescheduled, so explicitly * disable watchdog from being rescheduled. @@ -2263,9 +2276,14 @@ static void __devinit igb_probe_vfs(struct igb_adapter * adapter) { #ifdef CONFIG_PCI_IOV struct pci_dev *pdev = adapter->pdev; + struct e1000_hw *hw = &adapter->hw; int old_vfs = igb_find_enabled_vfs(adapter); int i; + /* Virtualization features not supported on i210 family. */ + if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211)) + return; + if (old_vfs) { dev_info(&pdev->dev, "%d pre-allocated VFs found - override " "max_vfs setting of %d\n", old_vfs, max_vfs); @@ -2277,6 +2295,7 @@ static void __devinit igb_probe_vfs(struct igb_adapter * adapter) adapter->vf_data = kcalloc(adapter->vfs_allocated_count, sizeof(struct vf_data_storage), GFP_KERNEL); + /* if allocation failed then we do not support SR-IOV */ if (!adapter->vf_data) { adapter->vfs_allocated_count = 0; @@ -2306,112 +2325,6 @@ static void __devinit igb_probe_vfs(struct igb_adapter * adapter) #endif /* CONFIG_PCI_IOV */ } -/** - * igb_init_hw_timer - Initialize hardware timer used with IEEE 1588 timestamp - * @adapter: board private structure to initialize - * - * igb_init_hw_timer initializes the function pointer and values for the hw - * timer found in hardware. - **/ -static void igb_init_hw_timer(struct igb_adapter *adapter) -{ - struct e1000_hw *hw = &adapter->hw; - - switch (hw->mac.type) { - case e1000_i350: - case e1000_82580: - memset(&adapter->cycles, 0, sizeof(adapter->cycles)); - adapter->cycles.read = igb_read_clock; - adapter->cycles.mask = CLOCKSOURCE_MASK(64); - adapter->cycles.mult = 1; - /* - * The 82580 timesync updates the system timer every 8ns by 8ns - * and the value cannot be shifted. Instead we need to shift - * the registers to generate a 64bit timer value. As a result - * SYSTIMR/L/H, TXSTMPL/H, RXSTMPL/H all have to be shifted by - * 24 in order to generate a larger value for synchronization. - */ - adapter->cycles.shift = IGB_82580_TSYNC_SHIFT; - /* disable system timer temporarily by setting bit 31 */ - wr32(E1000_TSAUXC, 0x80000000); - wrfl(); - - /* Set registers so that rollover occurs soon to test this. */ - wr32(E1000_SYSTIMR, 0x00000000); - wr32(E1000_SYSTIML, 0x80000000); - wr32(E1000_SYSTIMH, 0x000000FF); - wrfl(); - - /* enable system timer by clearing bit 31 */ - wr32(E1000_TSAUXC, 0x0); - wrfl(); - - timecounter_init(&adapter->clock, - &adapter->cycles, - ktime_to_ns(ktime_get_real())); - /* - * Synchronize our NIC clock against system wall clock. NIC - * time stamp reading requires ~3us per sample, each sample - * was pretty stable even under load => only require 10 - * samples for each offset comparison. - */ - memset(&adapter->compare, 0, sizeof(adapter->compare)); - adapter->compare.source = &adapter->clock; - adapter->compare.target = ktime_get_real; - adapter->compare.num_samples = 10; - timecompare_update(&adapter->compare, 0); - break; - case e1000_82576: - /* - * Initialize hardware timer: we keep it running just in case - * that some program needs it later on. - */ - memset(&adapter->cycles, 0, sizeof(adapter->cycles)); - adapter->cycles.read = igb_read_clock; - adapter->cycles.mask = CLOCKSOURCE_MASK(64); - adapter->cycles.mult = 1; - /** - * Scale the NIC clock cycle by a large factor so that - * relatively small clock corrections can be added or - * subtracted at each clock tick. The drawbacks of a large - * factor are a) that the clock register overflows more quickly - * (not such a big deal) and b) that the increment per tick has - * to fit into 24 bits. As a result we need to use a shift of - * 19 so we can fit a value of 16 into the TIMINCA register. - */ - adapter->cycles.shift = IGB_82576_TSYNC_SHIFT; - wr32(E1000_TIMINCA, - (1 << E1000_TIMINCA_16NS_SHIFT) | - (16 << IGB_82576_TSYNC_SHIFT)); - - /* Set registers so that rollover occurs soon to test this. */ - wr32(E1000_SYSTIML, 0x00000000); - wr32(E1000_SYSTIMH, 0xFF800000); - wrfl(); - - timecounter_init(&adapter->clock, - &adapter->cycles, - ktime_to_ns(ktime_get_real())); - /* - * Synchronize our NIC clock against system wall clock. NIC - * time stamp reading requires ~3us per sample, each sample - * was pretty stable even under load => only require 10 - * samples for each offset comparison. - */ - memset(&adapter->compare, 0, sizeof(adapter->compare)); - adapter->compare.source = &adapter->clock; - adapter->compare.target = ktime_get_real; - adapter->compare.num_samples = 10; - timecompare_update(&adapter->compare, 0); - break; - case e1000_82575: - /* 82575 does not support timesync */ - default: - break; - } - -} - /** * igb_sw_init - Initialize general software structures (struct igb_adapter) * @adapter: board private structure to initialize @@ -2457,11 +2370,28 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter) } else adapter->vfs_allocated_count = max_vfs; break; + case e1000_i210: + case e1000_i211: + adapter->vfs_allocated_count = 0; + break; default: break; } #endif /* CONFIG_PCI_IOV */ - adapter->rss_queues = min_t(u32, IGB_MAX_RX_QUEUES, num_online_cpus()); + switch (hw->mac.type) { + case e1000_i210: + adapter->rss_queues = min_t(u32, IGB_MAX_RX_QUEUES_I210, + num_online_cpus()); + break; + case e1000_i211: + adapter->rss_queues = min_t(u32, IGB_MAX_RX_QUEUES_I211, + num_online_cpus()); + break; + default: + adapter->rss_queues = min_t(u32, IGB_MAX_RX_QUEUES, + num_online_cpus()); + break; + } /* i350 cannot do RSS and SR-IOV at the same time */ if (hw->mac.type == e1000_i350 && adapter->vfs_allocated_count) adapter->rss_queues = 1; @@ -2491,7 +2421,7 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter) /* Explicitly disable IRQ since the NIC can be in any state. */ igb_irq_disable(adapter); - if (hw->mac.type == e1000_i350) + if (hw->mac.type >= e1000_i350) adapter->flags &= ~IGB_FLAG_DMAC; set_bit(__IGB_DOWN, &adapter->state); @@ -2944,6 +2874,17 @@ static void igb_setup_mrqc(struct igb_adapter *adapter) /* Don't need to set TUOFL or IPOFL, they default to 1 */ wr32(E1000_RXCSUM, rxcsum); + /* + * Generate RSS hash based on TCP port numbers and/or + * IPv4/v6 src and dst addresses since UDP cannot be + * hashed reliably due to IP fragmentation + */ + + mrqc = E1000_MRQC_RSS_FIELD_IPV4 | + E1000_MRQC_RSS_FIELD_IPV4_TCP | + E1000_MRQC_RSS_FIELD_IPV6 | + E1000_MRQC_RSS_FIELD_IPV6_TCP | + E1000_MRQC_RSS_FIELD_IPV6_TCP_EX; /* If VMDq is enabled then we set the appropriate mode for that, else * we default to RSS so that an RSS hash is calculated per packet even @@ -2959,25 +2900,15 @@ static void igb_setup_mrqc(struct igb_adapter *adapter) wr32(E1000_VT_CTL, vtctl); } if (adapter->rss_queues > 1) - mrqc = E1000_MRQC_ENABLE_VMDQ_RSS_2Q; + mrqc |= E1000_MRQC_ENABLE_VMDQ_RSS_2Q; else - mrqc = E1000_MRQC_ENABLE_VMDQ; + mrqc |= E1000_MRQC_ENABLE_VMDQ; } else { - mrqc = E1000_MRQC_ENABLE_RSS_4Q; + if (hw->mac.type != e1000_i211) + mrqc |= E1000_MRQC_ENABLE_RSS_4Q; } igb_vmm_control(adapter); - /* - * Generate RSS hash based on TCP port numbers and/or - * IPv4/v6 src and dst addresses since UDP cannot be - * hashed reliably due to IP fragmentation - */ - mrqc |= E1000_MRQC_RSS_FIELD_IPV4 | - E1000_MRQC_RSS_FIELD_IPV4_TCP | - E1000_MRQC_RSS_FIELD_IPV6 | - E1000_MRQC_RSS_FIELD_IPV6_TCP | - E1000_MRQC_RSS_FIELD_IPV6_TCP_EX; - wr32(E1000_MRQC, mrqc); } @@ -3579,7 +3510,7 @@ static void igb_set_rx_mode(struct net_device *netdev) * we will have issues with VLAN tag stripping not being done for frames * that are only arriving because we are the default pool */ - if (hw->mac.type < e1000_82576) + if ((hw->mac.type < e1000_82576) || (hw->mac.type > e1000_i350)) return; vmolr |= rd32(E1000_VMOLR(vfn)) & @@ -3676,7 +3607,7 @@ static bool igb_thermal_sensor_event(struct e1000_hw *hw, u32 event) bool ret = false; u32 ctrl_ext, thstat; - /* check for thermal sensor event on i350, copper only */ + /* check for thermal sensor event on i350 copper only */ if (hw->mac.type == e1000_i350) { thstat = rd32(E1000_THSTAT); ctrl_ext = rd32(E1000_CTRL_EXT); @@ -5721,35 +5652,7 @@ static int igb_poll(struct napi_struct *napi, int budget) return 0; } -/** - * igb_systim_to_hwtstamp - convert system time value to hw timestamp - * @adapter: board private structure - * @shhwtstamps: timestamp structure to update - * @regval: unsigned 64bit system time value. - * - * We need to convert the system time value stored in the RX/TXSTMP registers - * into a hwtstamp which can be used by the upper level timestamping functions - */ -static void igb_systim_to_hwtstamp(struct igb_adapter *adapter, - struct skb_shared_hwtstamps *shhwtstamps, - u64 regval) -{ - u64 ns; - - /* - * The 82580 starts with 1ns at bit 0 in RX/TXSTMPL, shift this up to - * 24 to match clock shift we setup earlier. - */ - if (adapter->hw.mac.type >= e1000_82580) - regval <<= IGB_82580_TSYNC_SHIFT; - - ns = timecounter_cyc2time(&adapter->clock, regval); - timecompare_update(&adapter->compare, ns); - memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps)); - shhwtstamps->hwtstamp = ns_to_ktime(ns); - shhwtstamps->syststamp = timecompare_transform(&adapter->compare, ns); -} - +#ifdef CONFIG_IGB_PTP /** * igb_tx_hwtstamp - utility function which checks for TX time stamp * @q_vector: pointer to q_vector containing needed info @@ -5779,6 +5682,7 @@ static void igb_tx_hwtstamp(struct igb_q_vector *q_vector, skb_tstamp_tx(buffer_info->skb, &shhwtstamps); } +#endif /** * igb_clean_tx_irq - Reclaim resources after transmit completes * @q_vector: pointer to q_vector containing needed info @@ -5822,9 +5726,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector) total_bytes += tx_buffer->bytecount; total_packets += tx_buffer->gso_segs; +#ifdef CONFIG_IGB_PTP /* retrieve hardware timestamp */ igb_tx_hwtstamp(q_vector, tx_buffer); +#endif /* free the skb */ dev_kfree_skb_any(tx_buffer->skb); tx_buffer->skb = NULL; @@ -5996,6 +5902,7 @@ static inline void igb_rx_hash(struct igb_ring *ring, skb->rxhash = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss); } +#ifdef CONFIG_IGB_PTP static void igb_rx_hwtstamp(struct igb_q_vector *q_vector, union e1000_adv_rx_desc *rx_desc, struct sk_buff *skb) @@ -6035,6 +5942,7 @@ static void igb_rx_hwtstamp(struct igb_q_vector *q_vector, igb_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), regval); } +#endif static void igb_rx_vlan(struct igb_ring *ring, union e1000_adv_rx_desc *rx_desc, struct sk_buff *skb) @@ -6145,7 +6053,9 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, int budget) goto next_desc; } +#ifdef CONFIG_IGB_PTP igb_rx_hwtstamp(q_vector, rx_desc, skb); +#endif igb_rx_hash(rx_ring, rx_desc, skb); igb_rx_checksum(rx_ring, rx_desc, skb); igb_rx_vlan(rx_ring, rx_desc, skb); @@ -7162,6 +7072,8 @@ static void igb_vmm_control(struct igb_adapter *adapter) switch (hw->mac.type) { case e1000_82575: + case e1000_i210: + case e1000_i211: default: /* replication is not supported for 82575 */ return; @@ -7235,6 +7147,9 @@ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba) /* watchdog timer= +-1000 usec in 32usec intervals */ reg |= (1000 >> 5); + + /* Disable BMC-to-OS Watchdog Enable */ + reg &= ~E1000_DMACR_DC_BMC2OSW_EN; wr32(E1000_DMACR, reg); /* diff --git a/trunk/drivers/net/ethernet/intel/igb/igb_ptp.c b/trunk/drivers/net/ethernet/intel/igb/igb_ptp.c new file mode 100644 index 000000000000..d5ee7fa50723 --- /dev/null +++ b/trunk/drivers/net/ethernet/intel/igb/igb_ptp.c @@ -0,0 +1,385 @@ +/* + * PTP Hardware Clock (PHC) driver for the Intel 82576 and 82580 + * + * Copyright (C) 2011 Richard Cochran + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include +#include +#include + +#include "igb.h" + +#define INCVALUE_MASK 0x7fffffff +#define ISGN 0x80000000 + +/* + * The 82580 timesync updates the system timer every 8ns by 8ns, + * and this update value cannot be reprogrammed. + * + * Neither the 82576 nor the 82580 offer registers wide enough to hold + * nanoseconds time values for very long. For the 82580, SYSTIM always + * counts nanoseconds, but the upper 24 bits are not availible. The + * frequency is adjusted by changing the 32 bit fractional nanoseconds + * register, TIMINCA. + * + * For the 82576, the SYSTIM register time unit is affect by the + * choice of the 24 bit TININCA:IV (incvalue) field. Five bits of this + * field are needed to provide the nominal 16 nanosecond period, + * leaving 19 bits for fractional nanoseconds. + * + * We scale the NIC clock cycle by a large factor so that relatively + * small clock corrections can be added or subtracted at each clock + * tick. The drawbacks of a large factor are a) that the clock + * register overflows more quickly (not such a big deal) and b) that + * the increment per tick has to fit into 24 bits. As a result we + * need to use a shift of 19 so we can fit a value of 16 into the + * TIMINCA register. + * + * + * SYSTIMH SYSTIML + * +--------------+ +---+---+------+ + * 82576 | 32 | | 8 | 5 | 19 | + * +--------------+ +---+---+------+ + * \________ 45 bits _______/ fract + * + * +----------+---+ +--------------+ + * 82580 | 24 | 8 | | 32 | + * +----------+---+ +--------------+ + * reserved \______ 40 bits _____/ + * + * + * The 45 bit 82576 SYSTIM overflows every + * 2^45 * 10^-9 / 3600 = 9.77 hours. + * + * The 40 bit 82580 SYSTIM overflows every + * 2^40 * 10^-9 / 60 = 18.3 minutes. + */ + +#define IGB_OVERFLOW_PERIOD (HZ * 60 * 9) +#define INCPERIOD_82576 (1 << E1000_TIMINCA_16NS_SHIFT) +#define INCVALUE_82576_MASK ((1 << E1000_TIMINCA_16NS_SHIFT) - 1) +#define INCVALUE_82576 (16 << IGB_82576_TSYNC_SHIFT) +#define IGB_NBITS_82580 40 + +/* + * SYSTIM read access for the 82576 + */ + +static cycle_t igb_82576_systim_read(const struct cyclecounter *cc) +{ + u64 val; + u32 lo, hi; + struct igb_adapter *igb = container_of(cc, struct igb_adapter, cc); + struct e1000_hw *hw = &igb->hw; + + lo = rd32(E1000_SYSTIML); + hi = rd32(E1000_SYSTIMH); + + val = ((u64) hi) << 32; + val |= lo; + + return val; +} + +/* + * SYSTIM read access for the 82580 + */ + +static cycle_t igb_82580_systim_read(const struct cyclecounter *cc) +{ + u64 val; + u32 lo, hi, jk; + struct igb_adapter *igb = container_of(cc, struct igb_adapter, cc); + struct e1000_hw *hw = &igb->hw; + + /* + * The timestamp latches on lowest register read. For the 82580 + * the lowest register is SYSTIMR instead of SYSTIML. However we only + * need to provide nanosecond resolution, so we just ignore it. + */ + jk = rd32(E1000_SYSTIMR); + lo = rd32(E1000_SYSTIML); + hi = rd32(E1000_SYSTIMH); + + val = ((u64) hi) << 32; + val |= lo; + + return val; +} + +/* + * PTP clock operations + */ + +static int ptp_82576_adjfreq(struct ptp_clock_info *ptp, s32 ppb) +{ + u64 rate; + u32 incvalue; + int neg_adj = 0; + struct igb_adapter *igb = container_of(ptp, struct igb_adapter, caps); + struct e1000_hw *hw = &igb->hw; + + if (ppb < 0) { + neg_adj = 1; + ppb = -ppb; + } + rate = ppb; + rate <<= 14; + rate = div_u64(rate, 1953125); + + incvalue = 16 << IGB_82576_TSYNC_SHIFT; + + if (neg_adj) + incvalue -= rate; + else + incvalue += rate; + + wr32(E1000_TIMINCA, INCPERIOD_82576 | (incvalue & INCVALUE_82576_MASK)); + + return 0; +} + +static int ptp_82580_adjfreq(struct ptp_clock_info *ptp, s32 ppb) +{ + u64 rate; + u32 inca; + int neg_adj = 0; + struct igb_adapter *igb = container_of(ptp, struct igb_adapter, caps); + struct e1000_hw *hw = &igb->hw; + + if (ppb < 0) { + neg_adj = 1; + ppb = -ppb; + } + rate = ppb; + rate <<= 26; + rate = div_u64(rate, 1953125); + + inca = rate & INCVALUE_MASK; + if (neg_adj) + inca |= ISGN; + + wr32(E1000_TIMINCA, inca); + + return 0; +} + +static int igb_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + s64 now; + unsigned long flags; + struct igb_adapter *igb = container_of(ptp, struct igb_adapter, caps); + + spin_lock_irqsave(&igb->tmreg_lock, flags); + + now = timecounter_read(&igb->tc); + now += delta; + timecounter_init(&igb->tc, &igb->cc, now); + + spin_unlock_irqrestore(&igb->tmreg_lock, flags); + + return 0; +} + +static int igb_gettime(struct ptp_clock_info *ptp, struct timespec *ts) +{ + u64 ns; + u32 remainder; + unsigned long flags; + struct igb_adapter *igb = container_of(ptp, struct igb_adapter, caps); + + spin_lock_irqsave(&igb->tmreg_lock, flags); + + ns = timecounter_read(&igb->tc); + + spin_unlock_irqrestore(&igb->tmreg_lock, flags); + + ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder); + ts->tv_nsec = remainder; + + return 0; +} + +static int igb_settime(struct ptp_clock_info *ptp, const struct timespec *ts) +{ + u64 ns; + unsigned long flags; + struct igb_adapter *igb = container_of(ptp, struct igb_adapter, caps); + + ns = ts->tv_sec * 1000000000ULL; + ns += ts->tv_nsec; + + spin_lock_irqsave(&igb->tmreg_lock, flags); + + timecounter_init(&igb->tc, &igb->cc, ns); + + spin_unlock_irqrestore(&igb->tmreg_lock, flags); + + return 0; +} + +static int ptp_82576_enable(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + return -EOPNOTSUPP; +} + +static int ptp_82580_enable(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + return -EOPNOTSUPP; +} + +static void igb_overflow_check(struct work_struct *work) +{ + struct timespec ts; + struct igb_adapter *igb = + container_of(work, struct igb_adapter, overflow_work.work); + + igb_gettime(&igb->caps, &ts); + + pr_debug("igb overflow check at %ld.%09lu\n", ts.tv_sec, ts.tv_nsec); + + schedule_delayed_work(&igb->overflow_work, IGB_OVERFLOW_PERIOD); +} + +void igb_ptp_init(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + + switch (hw->mac.type) { + case e1000_i210: + case e1000_i211: + case e1000_i350: + case e1000_82580: + adapter->caps.owner = THIS_MODULE; + strcpy(adapter->caps.name, "igb-82580"); + adapter->caps.max_adj = 62499999; + adapter->caps.n_ext_ts = 0; + adapter->caps.pps = 0; + adapter->caps.adjfreq = ptp_82580_adjfreq; + adapter->caps.adjtime = igb_adjtime; + adapter->caps.gettime = igb_gettime; + adapter->caps.settime = igb_settime; + adapter->caps.enable = ptp_82580_enable; + adapter->cc.read = igb_82580_systim_read; + adapter->cc.mask = CLOCKSOURCE_MASK(IGB_NBITS_82580); + adapter->cc.mult = 1; + adapter->cc.shift = 0; + /* Enable the timer functions by clearing bit 31. */ + wr32(E1000_TSAUXC, 0x0); + break; + + case e1000_82576: + adapter->caps.owner = THIS_MODULE; + strcpy(adapter->caps.name, "igb-82576"); + adapter->caps.max_adj = 1000000000; + adapter->caps.n_ext_ts = 0; + adapter->caps.pps = 0; + adapter->caps.adjfreq = ptp_82576_adjfreq; + adapter->caps.adjtime = igb_adjtime; + adapter->caps.gettime = igb_gettime; + adapter->caps.settime = igb_settime; + adapter->caps.enable = ptp_82576_enable; + adapter->cc.read = igb_82576_systim_read; + adapter->cc.mask = CLOCKSOURCE_MASK(64); + adapter->cc.mult = 1; + adapter->cc.shift = IGB_82576_TSYNC_SHIFT; + /* Dial the nominal frequency. */ + wr32(E1000_TIMINCA, INCPERIOD_82576 | INCVALUE_82576); + break; + + default: + adapter->ptp_clock = NULL; + return; + } + + wrfl(); + + timecounter_init(&adapter->tc, &adapter->cc, + ktime_to_ns(ktime_get_real())); + + INIT_DELAYED_WORK(&adapter->overflow_work, igb_overflow_check); + + spin_lock_init(&adapter->tmreg_lock); + + schedule_delayed_work(&adapter->overflow_work, IGB_OVERFLOW_PERIOD); + + adapter->ptp_clock = ptp_clock_register(&adapter->caps); + if (IS_ERR(adapter->ptp_clock)) { + adapter->ptp_clock = NULL; + dev_err(&adapter->pdev->dev, "ptp_clock_register failed\n"); + } else + dev_info(&adapter->pdev->dev, "added PHC on %s\n", + adapter->netdev->name); +} + +void igb_ptp_remove(struct igb_adapter *adapter) +{ + cancel_delayed_work_sync(&adapter->overflow_work); + + if (adapter->ptp_clock) { + ptp_clock_unregister(adapter->ptp_clock); + dev_info(&adapter->pdev->dev, "removed PHC on %s\n", + adapter->netdev->name); + } +} + +/** + * igb_systim_to_hwtstamp - convert system time value to hw timestamp + * @adapter: board private structure + * @hwtstamps: timestamp structure to update + * @systim: unsigned 64bit system time value. + * + * We need to convert the system time value stored in the RX/TXSTMP registers + * into a hwtstamp which can be used by the upper level timestamping functions. + * + * The 'tmreg_lock' spinlock is used to protect the consistency of the + * system time value. This is needed because reading the 64 bit time + * value involves reading two (or three) 32 bit registers. The first + * read latches the value. Ditto for writing. + * + * In addition, here have extended the system time with an overflow + * counter in software. + **/ +void igb_systim_to_hwtstamp(struct igb_adapter *adapter, + struct skb_shared_hwtstamps *hwtstamps, + u64 systim) +{ + u64 ns; + unsigned long flags; + + switch (adapter->hw.mac.type) { + case e1000_i210: + case e1000_i211: + case e1000_i350: + case e1000_82580: + case e1000_82576: + break; + default: + return; + } + + spin_lock_irqsave(&adapter->tmreg_lock, flags); + + ns = timecounter_cyc2time(&adapter->tc, systim); + + spin_unlock_irqrestore(&adapter->tmreg_lock, flags); + + memset(hwtstamps, 0, sizeof(*hwtstamps)); + hwtstamps->hwtstamp = ns_to_ktime(ns); +} diff --git a/trunk/drivers/net/ethernet/intel/ixgbe/Makefile b/trunk/drivers/net/ethernet/intel/ixgbe/Makefile index 8be1d1b2132e..0bdf06bc5c49 100644 --- a/trunk/drivers/net/ethernet/intel/ixgbe/Makefile +++ b/trunk/drivers/net/ethernet/intel/ixgbe/Makefile @@ -34,9 +34,11 @@ obj-$(CONFIG_IXGBE) += ixgbe.o ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \ ixgbe_82599.o ixgbe_82598.o ixgbe_phy.o ixgbe_sriov.o \ - ixgbe_mbx.o ixgbe_x540.o ixgbe_lib.o + ixgbe_mbx.o ixgbe_x540.o ixgbe_sysfs.o ixgbe_lib.o ixgbe-$(CONFIG_IXGBE_DCB) += ixgbe_dcb.o ixgbe_dcb_82598.o \ ixgbe_dcb_82599.o ixgbe_dcb_nl.o +ixgbe-$(CONFIG_IXGBE_PTP) += ixgbe_ptp.o + ixgbe-$(CONFIG_FCOE:m=y) += ixgbe_fcoe.o diff --git a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe.h index 81b155589532..3ef3c5284e52 100644 --- a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -36,6 +36,12 @@ #include #include +#ifdef CONFIG_IXGBE_PTP +#include +#include +#include +#endif /* CONFIG_IXGBE_PTP */ + #include "ixgbe_type.h" #include "ixgbe_common.h" #include "ixgbe_dcb.h" @@ -96,6 +102,7 @@ #define IXGBE_TX_FLAGS_FCOE (u32)(1 << 5) #define IXGBE_TX_FLAGS_FSO (u32)(1 << 6) #define IXGBE_TX_FLAGS_TXSW (u32)(1 << 7) +#define IXGBE_TX_FLAGS_TSTAMP (u32)(1 << 8) #define IXGBE_TX_FLAGS_VLAN_MASK 0xffff0000 #define IXGBE_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000 #define IXGBE_TX_FLAGS_VLAN_PRIO_SHIFT 29 @@ -331,6 +338,26 @@ struct ixgbe_q_vector { /* for dynamic allocation of rings associated with this q_vector */ struct ixgbe_ring ring[0] ____cacheline_internodealigned_in_smp; }; +#ifdef CONFIG_IXGBE_HWMON + +#define IXGBE_HWMON_TYPE_LOC 0 +#define IXGBE_HWMON_TYPE_TEMP 1 +#define IXGBE_HWMON_TYPE_CAUTION 2 +#define IXGBE_HWMON_TYPE_MAX 3 + +struct hwmon_attr { + struct device_attribute dev_attr; + struct ixgbe_hw *hw; + struct ixgbe_thermal_diode_data *sensor; + char name[12]; +}; + +struct hwmon_buff { + struct device *device; + struct hwmon_attr *hwmon_list; + unsigned int n_hwmon; +}; +#endif /* CONFIG_IXGBE_HWMON */ /* * microsecond values for various ITR rates shifted by 2 to fit itr register @@ -438,6 +465,8 @@ struct ixgbe_adapter { #define IXGBE_FLAG2_FDIR_REQUIRES_REINIT (u32)(1 << 7) #define IXGBE_FLAG2_RSS_FIELD_IPV4_UDP (u32)(1 << 8) #define IXGBE_FLAG2_RSS_FIELD_IPV6_UDP (u32)(1 << 9) +#define IXGBE_FLAG2_OVERFLOW_CHECK_ENABLED (u32)(1 << 10) +#define IXGBE_FLAG2_PTP_PPS_ENABLED (u32)(1 << 11) /* Tx fast path data */ int num_tx_queues; @@ -525,6 +554,17 @@ struct ixgbe_adapter { u32 interrupt_event; u32 led_reg; +#ifdef CONFIG_IXGBE_PTP + struct ptp_clock *ptp_clock; + struct ptp_clock_info ptp_caps; + unsigned long last_overflow_check; + spinlock_t tmreg_lock; + struct cyclecounter cc; + struct timecounter tc; + u32 base_incval; + u32 cycle_speed; +#endif /* CONFIG_IXGBE_PTP */ + /* SR-IOV */ DECLARE_BITMAP(active_vfs, IXGBE_MAX_VF_FUNCTIONS); unsigned int num_vfs; @@ -535,6 +575,10 @@ struct ixgbe_adapter { u32 timer_event_accumulator; u32 vferr_refcount; + struct kobject *info_kobj; +#ifdef CONFIG_IXGBE_HWMON + struct hwmon_buff ixgbe_hwmon_buff; +#endif /* CONFIG_IXGBE_HWMON */ }; struct ixgbe_fdir_filter { @@ -597,6 +641,8 @@ extern void ixgbe_disable_rx_queue(struct ixgbe_adapter *adapter, struct ixgbe_ring *); extern void ixgbe_update_stats(struct ixgbe_adapter *adapter); extern int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter); +extern int ixgbe_wol_supported(struct ixgbe_adapter *adapter, u16 device_id, + u16 subdevice_id); extern void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter); extern netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *, struct ixgbe_adapter *, @@ -626,10 +672,15 @@ extern void ixgbe_atr_compute_perfect_hash_82599(union ixgbe_atr_input *input, union ixgbe_atr_input *mask); extern void ixgbe_set_rx_mode(struct net_device *netdev); #ifdef CONFIG_IXGBE_DCB +extern void ixgbe_set_rx_drop_en(struct ixgbe_adapter *adapter); extern int ixgbe_setup_tc(struct net_device *dev, u8 tc); #endif extern void ixgbe_tx_ctxtdesc(struct ixgbe_ring *, u32, u32, u32, u32); extern void ixgbe_do_reset(struct net_device *netdev); +#ifdef CONFIG_IXGBE_HWMON +extern void ixgbe_sysfs_exit(struct ixgbe_adapter *adapter); +extern int ixgbe_sysfs_init(struct ixgbe_adapter *adapter); +#endif /* CONFIG_IXGBE_HWMON */ #ifdef IXGBE_FCOE extern void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter); extern int ixgbe_fso(struct ixgbe_ring *tx_ring, @@ -660,4 +711,18 @@ static inline struct netdev_queue *txring_txq(const struct ixgbe_ring *ring) return netdev_get_tx_queue(ring->netdev, ring->queue_index); } +#ifdef CONFIG_IXGBE_PTP +extern void ixgbe_ptp_init(struct ixgbe_adapter *adapter); +extern void ixgbe_ptp_stop(struct ixgbe_adapter *adapter); +extern void ixgbe_ptp_overflow_check(struct ixgbe_adapter *adapter); +extern void ixgbe_ptp_tx_hwtstamp(struct ixgbe_q_vector *q_vector, + struct sk_buff *skb); +extern void ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector, + struct sk_buff *skb); +extern int ixgbe_ptp_hwtstamp_ioctl(struct ixgbe_adapter *adapter, + struct ifreq *ifr, int cmd); +extern void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter); +extern void ixgbe_ptp_check_pps_event(struct ixgbe_adapter *adapter, u32 eicr); +#endif /* CONFIG_IXGBE_PTP */ + #endif /* _IXGBE_H_ */ diff --git a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c index 85d2e2c4ce4a..42537336110c 100644 --- a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c +++ b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c @@ -91,29 +91,6 @@ static void ixgbe_set_pcie_completion_timeout(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_GCR, gcr); } -/** - * ixgbe_get_pcie_msix_count_82598 - Gets MSI-X vector count - * @hw: pointer to hardware structure - * - * Read PCIe configuration space, and get the MSI-X vector count from - * the capabilities table. - **/ -static u16 ixgbe_get_pcie_msix_count_82598(struct ixgbe_hw *hw) -{ - struct ixgbe_adapter *adapter = hw->back; - u16 msix_count; - pci_read_config_word(adapter->pdev, IXGBE_PCIE_MSIX_82598_CAPS, - &msix_count); - msix_count &= IXGBE_PCIE_MSIX_TBL_SZ_MASK; - - /* MSI-X count is zero-based in HW, so increment to give proper value */ - msix_count++; - - return msix_count; -} - -/** - */ static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; @@ -126,7 +103,7 @@ static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw) mac->num_rar_entries = IXGBE_82598_RAR_ENTRIES; mac->max_rx_queues = IXGBE_82598_MAX_RX_QUEUES; mac->max_tx_queues = IXGBE_82598_MAX_TX_QUEUES; - mac->max_msix_vectors = ixgbe_get_pcie_msix_count_82598(hw); + mac->max_msix_vectors = ixgbe_get_pcie_msix_count_generic(hw); return 0; } @@ -347,24 +324,33 @@ static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw) /** * ixgbe_fc_enable_82598 - Enable flow control * @hw: pointer to hardware structure - * @packetbuf_num: packet buffer number (0-7) * * Enable flow control according to the current settings. **/ -static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num) +static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw) { s32 ret_val = 0; u32 fctrl_reg; u32 rmcs_reg; u32 reg; + u32 fcrtl, fcrth; u32 link_speed = 0; + int i; bool link_up; -#ifdef CONFIG_DCB - if (hw->fc.requested_mode == ixgbe_fc_pfc) + /* + * 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"); + ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; goto out; + } -#endif /* CONFIG_DCB */ /* * 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 @@ -386,9 +372,7 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num) } /* Negotiate the fc mode to use */ - ret_val = ixgbe_fc_autoneg(hw); - if (ret_val == IXGBE_ERR_FLOW_CONTROL) - goto out; + ixgbe_fc_autoneg(hw); /* Disable any previous flow control settings */ fctrl_reg = IXGBE_READ_REG(hw, IXGBE_FCTRL); @@ -405,9 +389,6 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num) * 2: Tx flow control is enabled (we can send pause frames but * we do not support receiving pause frames). * 3: Both Rx and Tx flow control (symmetric) are enabled. -#ifdef CONFIG_DCB - * 4: Priority Flow Control is enabled. -#endif * other: Invalid. */ switch (hw->fc.current_mode) { @@ -440,11 +421,6 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num) fctrl_reg |= IXGBE_FCTRL_RFCE; rmcs_reg |= IXGBE_RMCS_TFCE_802_3X; break; -#ifdef CONFIG_DCB - case ixgbe_fc_pfc: - goto out; - break; -#endif /* CONFIG_DCB */ default: hw_dbg(hw, "Flow control param set incorrectly\n"); ret_val = IXGBE_ERR_CONFIG; @@ -457,29 +433,29 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num) IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl_reg); IXGBE_WRITE_REG(hw, IXGBE_RMCS, rmcs_reg); - /* Set up and enable Rx high/low water mark thresholds, enable XON. */ - if (hw->fc.current_mode & ixgbe_fc_tx_pause) { - reg = hw->fc.low_water << 6; - if (hw->fc.send_xon) - reg |= IXGBE_FCRTL_XONE; - - IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num), reg); + fcrtl = (hw->fc.low_water << 10) | IXGBE_FCRTL_XONE; - reg = hw->fc.high_water[packetbuf_num] << 6; - reg |= IXGBE_FCRTH_FCEN; + /* 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]) { + 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); + } else { + IXGBE_WRITE_REG(hw, IXGBE_FCRTL(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_FCRTH(i), 0); + } - IXGBE_WRITE_REG(hw, IXGBE_FCRTH(packetbuf_num), reg); } /* Configure pause time (2 TCs per register) */ - reg = IXGBE_READ_REG(hw, IXGBE_FCTTV(packetbuf_num / 2)); - if ((packetbuf_num & 1) == 0) - reg = (reg & 0xFFFF0000) | hw->fc.pause_time; - else - reg = (reg & 0x0000FFFF) | (hw->fc.pause_time << 16); - IXGBE_WRITE_REG(hw, IXGBE_FCTTV(packetbuf_num / 2), reg); + reg = hw->fc.pause_time * 0x00010001; + for (i = 0; i < (MAX_TRAFFIC_CLASS / 2); i++) + IXGBE_WRITE_REG(hw, IXGBE_FCTTV(i), reg); - IXGBE_WRITE_REG(hw, IXGBE_FCRTV, (hw->fc.pause_time >> 1)); + /* Configure flow control refresh threshold value */ + IXGBE_WRITE_REG(hw, IXGBE_FCRTV, hw->fc.pause_time / 2); out: return ret_val; @@ -1300,6 +1276,8 @@ static struct ixgbe_mac_operations mac_ops_82598 = { .set_fw_drv_ver = NULL, .acquire_swfw_sync = &ixgbe_acquire_swfw_sync, .release_swfw_sync = &ixgbe_release_swfw_sync, + .get_thermal_sensor_data = NULL, + .init_thermal_sensor_thresh = NULL, }; static struct ixgbe_eeprom_operations eeprom_ops_82598 = { diff --git a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c index 9c14685358eb..dee64d2703f0 100644 --- a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c +++ b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c @@ -2119,6 +2119,8 @@ static struct ixgbe_mac_operations mac_ops_82599 = { .set_vlan_anti_spoofing = &ixgbe_set_vlan_anti_spoofing, .acquire_swfw_sync = &ixgbe_acquire_swfw_sync, .release_swfw_sync = &ixgbe_release_swfw_sync, + .get_thermal_sensor_data = &ixgbe_get_thermal_sensor_data_generic, + .init_thermal_sensor_thresh = &ixgbe_init_thermal_sensor_thresh_generic, }; diff --git a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index 49aa41fe7b84..77ac41feb0fe 100644 --- a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -47,13 +47,6 @@ static void ixgbe_lower_eeprom_clk(struct ixgbe_hw *hw, u32 *eec); static void ixgbe_release_eeprom(struct ixgbe_hw *hw); static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr); -static s32 ixgbe_fc_autoneg_fiber(struct ixgbe_hw *hw); -static s32 ixgbe_fc_autoneg_backplane(struct ixgbe_hw *hw); -static s32 ixgbe_fc_autoneg_copper(struct ixgbe_hw *hw); -static s32 ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw); -static s32 ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg, - u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm); -static s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num); static s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg); static s32 ixgbe_read_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data); @@ -63,6 +56,172 @@ static s32 ixgbe_detect_eeprom_page_size_generic(struct ixgbe_hw *hw, u16 offset); static s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw); +/** + * ixgbe_device_supports_autoneg_fc - Check if phy supports autoneg flow + * control + * @hw: pointer to hardware structure + * + * There are several phys that do not support autoneg flow control. This + * function check the device id to see if the associated phy supports + * autoneg flow control. + **/ +static s32 ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw) +{ + + switch (hw->device_id) { + case IXGBE_DEV_ID_X540T: + return 0; + case IXGBE_DEV_ID_82599_T3_LOM: + return 0; + default: + return IXGBE_ERR_FC_NOT_SUPPORTED; + } +} + +/** + * ixgbe_setup_fc - Set up flow control + * @hw: pointer to hardware structure + * + * Called at init time to set up flow control. + **/ +static s32 ixgbe_setup_fc(struct ixgbe_hw *hw) +{ + s32 ret_val = 0; + u32 reg = 0, reg_bp = 0; + u16 reg_cu = 0; + + /* + * Validate the requested mode. Strict IEEE mode does not allow + * ixgbe_fc_rx_pause because it will cause us to fail at UNH. + */ + if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) { + hw_dbg(hw, "ixgbe_fc_rx_pause not valid in strict IEEE mode\n"); + ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; + goto out; + } + + /* + * 10gig parts do not have a word in the EEPROM to determine the + * default flow control setting, so we explicitly set it to full. + */ + if (hw->fc.requested_mode == ixgbe_fc_default) + hw->fc.requested_mode = ixgbe_fc_full; + + /* + * Set up the 1G and 10G flow control advertisement registers so the + * HW will be able to do fc autoneg once the cable is plugged in. If + * we link at 10G, the 1G advertisement is harmless and vice versa. + */ + switch (hw->phy.media_type) { + case ixgbe_media_type_fiber: + case ixgbe_media_type_backplane: + reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); + reg_bp = IXGBE_READ_REG(hw, IXGBE_AUTOC); + break; + case ixgbe_media_type_copper: + hw->phy.ops.read_reg(hw, MDIO_AN_ADVERTISE, + MDIO_MMD_AN, ®_cu); + break; + default: + break; + } + + /* + * The possible values of fc.requested_mode are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames, + * but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames but + * we do not support receiving pause frames). + * 3: Both Rx and Tx flow control (symmetric) are enabled. + * other: Invalid. + */ + switch (hw->fc.requested_mode) { + case ixgbe_fc_none: + /* Flow control completely disabled by software override. */ + reg &= ~(IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); + if (hw->phy.media_type == ixgbe_media_type_backplane) + reg_bp &= ~(IXGBE_AUTOC_SYM_PAUSE | + IXGBE_AUTOC_ASM_PAUSE); + else if (hw->phy.media_type == ixgbe_media_type_copper) + reg_cu &= ~(IXGBE_TAF_SYM_PAUSE | IXGBE_TAF_ASM_PAUSE); + break; + case ixgbe_fc_tx_pause: + /* + * Tx Flow control is enabled, and Rx Flow control is + * disabled by software override. + */ + reg |= IXGBE_PCS1GANA_ASM_PAUSE; + reg &= ~IXGBE_PCS1GANA_SYM_PAUSE; + if (hw->phy.media_type == ixgbe_media_type_backplane) { + reg_bp |= IXGBE_AUTOC_ASM_PAUSE; + reg_bp &= ~IXGBE_AUTOC_SYM_PAUSE; + } else if (hw->phy.media_type == ixgbe_media_type_copper) { + reg_cu |= IXGBE_TAF_ASM_PAUSE; + reg_cu &= ~IXGBE_TAF_SYM_PAUSE; + } + break; + case ixgbe_fc_rx_pause: + /* + * Rx Flow control is enabled and Tx Flow control is + * disabled by software override. Since there really + * isn't a way to advertise that we are capable of RX + * Pause ONLY, we will advertise that we support both + * symmetric and asymmetric Rx PAUSE, as such we fall + * through to the fc_full statement. Later, we will + * disable the adapter's ability to send PAUSE frames. + */ + case ixgbe_fc_full: + /* Flow control (both Rx and Tx) is enabled by SW override. */ + reg |= IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE; + if (hw->phy.media_type == ixgbe_media_type_backplane) + reg_bp |= IXGBE_AUTOC_SYM_PAUSE | + IXGBE_AUTOC_ASM_PAUSE; + else if (hw->phy.media_type == ixgbe_media_type_copper) + reg_cu |= IXGBE_TAF_SYM_PAUSE | IXGBE_TAF_ASM_PAUSE; + break; + default: + hw_dbg(hw, "Flow control param set incorrectly\n"); + ret_val = IXGBE_ERR_CONFIG; + goto out; + break; + } + + if (hw->mac.type != ixgbe_mac_X540) { + /* + * Enable auto-negotiation between the MAC & PHY; + * the MAC will advertise clause 37 flow control. + */ + IXGBE_WRITE_REG(hw, IXGBE_PCS1GANA, reg); + reg = IXGBE_READ_REG(hw, IXGBE_PCS1GLCTL); + + /* Disable AN timeout */ + if (hw->fc.strict_ieee) + reg &= ~IXGBE_PCS1GLCTL_AN_1G_TIMEOUT_EN; + + IXGBE_WRITE_REG(hw, IXGBE_PCS1GLCTL, reg); + hw_dbg(hw, "Set up FC; PCS1GLCTL = 0x%08X\n", reg); + } + + /* + * AUTOC restart handles negotiation of 1G and 10G on backplane + * and copper. There is no need to set the PCS1GCTL register. + * + */ + if (hw->phy.media_type == ixgbe_media_type_backplane) { + reg_bp |= IXGBE_AUTOC_AN_RESTART; + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, reg_bp); + } else if ((hw->phy.media_type == ixgbe_media_type_copper) && + (ixgbe_device_supports_autoneg_fc(hw) == 0)) { + hw->phy.ops.write_reg(hw, MDIO_AN_ADVERTISE, + MDIO_MMD_AN, reg_cu); + } + + hw_dbg(hw, "Set up FC; IXGBE_AUTOC = 0x%08X\n", reg); +out: + return ret_val; +} + /** * ixgbe_start_hw_generic - Prepare hardware for Tx/Rx * @hw: pointer to hardware structure @@ -95,7 +254,7 @@ s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw) IXGBE_WRITE_FLUSH(hw); /* Setup flow control */ - ixgbe_setup_fc(hw, 0); + ixgbe_setup_fc(hw); /* Clear adapter stopped flag */ hw->adapter_stopped = false; @@ -1923,30 +2082,36 @@ s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw) /** * ixgbe_fc_enable_generic - Enable flow control * @hw: pointer to hardware structure - * @packetbuf_num: packet buffer number (0-7) * * Enable flow control according to the current settings. **/ -s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw, s32 packetbuf_num) +s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw) { s32 ret_val = 0; u32 mflcn_reg, fccfg_reg; u32 reg; u32 fcrtl, fcrth; + int i; -#ifdef CONFIG_DCB - if (hw->fc.requested_mode == ixgbe_fc_pfc) + /* + * 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"); + ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; goto out; + } -#endif /* CONFIG_DCB */ /* Negotiate the fc mode to use */ - ret_val = ixgbe_fc_autoneg(hw); - if (ret_val == IXGBE_ERR_FLOW_CONTROL) - goto out; + ixgbe_fc_autoneg(hw); /* Disable any previous flow control settings */ mflcn_reg = IXGBE_READ_REG(hw, IXGBE_MFLCN); - mflcn_reg &= ~(IXGBE_MFLCN_RFCE | IXGBE_MFLCN_RPFCE); + mflcn_reg &= ~(IXGBE_MFLCN_RPFCE_MASK | IXGBE_MFLCN_RFCE); fccfg_reg = IXGBE_READ_REG(hw, IXGBE_FCCFG); fccfg_reg &= ~(IXGBE_FCCFG_TFCE_802_3X | IXGBE_FCCFG_TFCE_PRIORITY); @@ -1959,9 +2124,6 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw, s32 packetbuf_num) * 2: Tx flow control is enabled (we can send pause frames but * we do not support receiving pause frames). * 3: Both Rx and Tx flow control (symmetric) are enabled. -#ifdef CONFIG_DCB - * 4: Priority Flow Control is enabled. -#endif * other: Invalid. */ switch (hw->fc.current_mode) { @@ -1994,11 +2156,6 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw, s32 packetbuf_num) mflcn_reg |= IXGBE_MFLCN_RFCE; fccfg_reg |= IXGBE_FCCFG_TFCE_802_3X; break; -#ifdef CONFIG_DCB - case ixgbe_fc_pfc: - goto out; - break; -#endif /* CONFIG_DCB */ default: hw_dbg(hw, "Flow control param set incorrectly\n"); ret_val = IXGBE_ERR_CONFIG; @@ -2011,125 +2168,109 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw, s32 packetbuf_num) IXGBE_WRITE_REG(hw, IXGBE_MFLCN, mflcn_reg); IXGBE_WRITE_REG(hw, IXGBE_FCCFG, fccfg_reg); - fcrtl = hw->fc.low_water << 10; + fcrtl = (hw->fc.low_water << 10) | IXGBE_FCRTL_XONE; - if (hw->fc.current_mode & ixgbe_fc_tx_pause) { - fcrth = hw->fc.high_water[packetbuf_num] << 10; - fcrth |= IXGBE_FCRTH_FCEN; - if (hw->fc.send_xon) - fcrtl |= IXGBE_FCRTL_XONE; - } else { - /* - * If Tx flow control is disabled, set our high water mark - * to Rx FIFO size minus 32 in order prevent Tx switch - * loopback from stalling on DMA. - */ - fcrth = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(packetbuf_num)) - 32; - } + /* 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]) { + IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), fcrtl); + fcrth = (hw->fc.high_water[i] << 10) | IXGBE_FCRTH_FCEN; + } else { + IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), 0); + /* + * In order to prevent Tx hangs when the internal Tx + * switch is enabled we must set the high water mark + * to the maximum FCRTH value. This allows the Tx + * switch to function even under heavy Rx workloads. + */ + fcrth = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i)) - 32; + } - IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(packetbuf_num), fcrth); - IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(packetbuf_num), fcrtl); + IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(i), fcrth); + } /* Configure pause time (2 TCs per register) */ - reg = IXGBE_READ_REG(hw, IXGBE_FCTTV(packetbuf_num / 2)); - if ((packetbuf_num & 1) == 0) - reg = (reg & 0xFFFF0000) | hw->fc.pause_time; - else - reg = (reg & 0x0000FFFF) | (hw->fc.pause_time << 16); - IXGBE_WRITE_REG(hw, IXGBE_FCTTV(packetbuf_num / 2), reg); + reg = hw->fc.pause_time * 0x00010001; + for (i = 0; i < (MAX_TRAFFIC_CLASS / 2); i++) + IXGBE_WRITE_REG(hw, IXGBE_FCTTV(i), reg); - IXGBE_WRITE_REG(hw, IXGBE_FCRTV, (hw->fc.pause_time >> 1)); + IXGBE_WRITE_REG(hw, IXGBE_FCRTV, hw->fc.pause_time / 2); out: return ret_val; } /** - * ixgbe_fc_autoneg - Configure flow control + * ixgbe_negotiate_fc - Negotiate flow control * @hw: pointer to hardware structure + * @adv_reg: flow control advertised settings + * @lp_reg: link partner's flow control settings + * @adv_sym: symmetric pause bit in advertisement + * @adv_asm: asymmetric pause bit in advertisement + * @lp_sym: symmetric pause bit in link partner advertisement + * @lp_asm: asymmetric pause bit in link partner advertisement * - * Compares our advertised flow control capabilities to those advertised by - * our link partner, and determines the proper flow control mode to use. + * Find the intersection between advertised settings and link partner's + * advertised settings **/ -s32 ixgbe_fc_autoneg(struct ixgbe_hw *hw) +static s32 ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg, + u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm) { - s32 ret_val = IXGBE_ERR_FC_NOT_NEGOTIATED; - ixgbe_link_speed speed; - bool link_up; + if ((!(adv_reg)) || (!(lp_reg))) + return IXGBE_ERR_FC_NOT_NEGOTIATED; - if (hw->fc.disable_fc_autoneg) - goto out; + if ((adv_reg & adv_sym) && (lp_reg & lp_sym)) { + /* + * Now we need to check if the user selected Rx ONLY + * of pause frames. In this case, we had to advertise + * FULL flow control because we could not advertise RX + * ONLY. Hence, we must now check to see if we need to + * turn OFF the TRANSMISSION of PAUSE frames. + */ + if (hw->fc.requested_mode == ixgbe_fc_full) { + hw->fc.current_mode = ixgbe_fc_full; + hw_dbg(hw, "Flow Control = FULL.\n"); + } else { + hw->fc.current_mode = ixgbe_fc_rx_pause; + hw_dbg(hw, "Flow Control=RX PAUSE frames only\n"); + } + } else if (!(adv_reg & adv_sym) && (adv_reg & adv_asm) && + (lp_reg & lp_sym) && (lp_reg & lp_asm)) { + hw->fc.current_mode = ixgbe_fc_tx_pause; + hw_dbg(hw, "Flow Control = TX PAUSE frames only.\n"); + } else if ((adv_reg & adv_sym) && (adv_reg & adv_asm) && + !(lp_reg & lp_sym) && (lp_reg & lp_asm)) { + hw->fc.current_mode = ixgbe_fc_rx_pause; + hw_dbg(hw, "Flow Control = RX PAUSE frames only.\n"); + } else { + hw->fc.current_mode = ixgbe_fc_none; + hw_dbg(hw, "Flow Control = NONE.\n"); + } + return 0; +} + +/** + * ixgbe_fc_autoneg_fiber - Enable flow control on 1 gig fiber + * @hw: pointer to hardware structure + * + * Enable flow control according on 1 gig fiber. + **/ +static s32 ixgbe_fc_autoneg_fiber(struct ixgbe_hw *hw) +{ + u32 pcs_anadv_reg, pcs_lpab_reg, linkstat; + s32 ret_val = IXGBE_ERR_FC_NOT_NEGOTIATED; /* - * AN should have completed when the cable was plugged in. - * Look for reasons to bail out. Bail out if: - * - FC autoneg is disabled, or if - * - link is not up. - * - * Since we're being called from an LSC, link is already known to be up. - * So use link_up_wait_to_complete=false. + * On multispeed fiber at 1g, bail out if + * - link is up but AN did not complete, or if + * - link is up and AN completed but timed out */ - hw->mac.ops.check_link(hw, &speed, &link_up, false); - if (!link_up) { - ret_val = IXGBE_ERR_FLOW_CONTROL; + + linkstat = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA); + if ((!!(linkstat & IXGBE_PCS1GLSTA_AN_COMPLETE) == 0) || + (!!(linkstat & IXGBE_PCS1GLSTA_AN_TIMED_OUT) == 1)) goto out; - } - - switch (hw->phy.media_type) { - /* Autoneg flow control on fiber adapters */ - case ixgbe_media_type_fiber: - if (speed == IXGBE_LINK_SPEED_1GB_FULL) - ret_val = ixgbe_fc_autoneg_fiber(hw); - break; - - /* Autoneg flow control on backplane adapters */ - case ixgbe_media_type_backplane: - ret_val = ixgbe_fc_autoneg_backplane(hw); - break; - - /* Autoneg flow control on copper adapters */ - case ixgbe_media_type_copper: - if (ixgbe_device_supports_autoneg_fc(hw) == 0) - ret_val = ixgbe_fc_autoneg_copper(hw); - break; - - default: - break; - } - -out: - if (ret_val == 0) { - hw->fc.fc_was_autonegged = true; - } else { - hw->fc.fc_was_autonegged = false; - hw->fc.current_mode = hw->fc.requested_mode; - } - return ret_val; -} - -/** - * ixgbe_fc_autoneg_fiber - Enable flow control on 1 gig fiber - * @hw: pointer to hardware structure - * - * Enable flow control according on 1 gig fiber. - **/ -static s32 ixgbe_fc_autoneg_fiber(struct ixgbe_hw *hw) -{ - u32 pcs_anadv_reg, pcs_lpab_reg, linkstat; - s32 ret_val; - - /* - * On multispeed fiber at 1g, bail out if - * - link is up but AN did not complete, or if - * - link is up and AN completed but timed out - */ - - linkstat = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA); - if ((!!(linkstat & IXGBE_PCS1GLSTA_AN_COMPLETE) == 0) || - (!!(linkstat & IXGBE_PCS1GLSTA_AN_TIMED_OUT) == 1)) { - ret_val = IXGBE_ERR_FC_NOT_NEGOTIATED; - goto out; - } pcs_anadv_reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); pcs_lpab_reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP); @@ -2153,7 +2294,7 @@ static s32 ixgbe_fc_autoneg_fiber(struct ixgbe_hw *hw) static s32 ixgbe_fc_autoneg_backplane(struct ixgbe_hw *hw) { u32 links2, anlp1_reg, autoc_reg, links; - s32 ret_val; + s32 ret_val = IXGBE_ERR_FC_NOT_NEGOTIATED; /* * On backplane, bail out if @@ -2161,21 +2302,13 @@ static s32 ixgbe_fc_autoneg_backplane(struct ixgbe_hw *hw) * - we are 82599 and link partner is not AN enabled */ links = IXGBE_READ_REG(hw, IXGBE_LINKS); - if ((links & IXGBE_LINKS_KX_AN_COMP) == 0) { - hw->fc.fc_was_autonegged = false; - hw->fc.current_mode = hw->fc.requested_mode; - ret_val = IXGBE_ERR_FC_NOT_NEGOTIATED; + if ((links & IXGBE_LINKS_KX_AN_COMP) == 0) goto out; - } if (hw->mac.type == ixgbe_mac_82599EB) { links2 = IXGBE_READ_REG(hw, IXGBE_LINKS2); - if ((links2 & IXGBE_LINKS2_AN_SUPPORTED) == 0) { - hw->fc.fc_was_autonegged = false; - hw->fc.current_mode = hw->fc.requested_mode; - ret_val = IXGBE_ERR_FC_NOT_NEGOTIATED; + if ((links2 & IXGBE_LINKS2_AN_SUPPORTED) == 0) goto out; - } } /* * Read the 10g AN autoc and LP ability registers and resolve @@ -2217,241 +2350,63 @@ static s32 ixgbe_fc_autoneg_copper(struct ixgbe_hw *hw) } /** - * ixgbe_negotiate_fc - Negotiate flow control - * @hw: pointer to hardware structure - * @adv_reg: flow control advertised settings - * @lp_reg: link partner's flow control settings - * @adv_sym: symmetric pause bit in advertisement - * @adv_asm: asymmetric pause bit in advertisement - * @lp_sym: symmetric pause bit in link partner advertisement - * @lp_asm: asymmetric pause bit in link partner advertisement - * - * Find the intersection between advertised settings and link partner's - * advertised settings - **/ -static s32 ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg, - u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm) -{ - if ((!(adv_reg)) || (!(lp_reg))) - return IXGBE_ERR_FC_NOT_NEGOTIATED; - - if ((adv_reg & adv_sym) && (lp_reg & lp_sym)) { - /* - * Now we need to check if the user selected Rx ONLY - * of pause frames. In this case, we had to advertise - * FULL flow control because we could not advertise RX - * ONLY. Hence, we must now check to see if we need to - * turn OFF the TRANSMISSION of PAUSE frames. - */ - if (hw->fc.requested_mode == ixgbe_fc_full) { - hw->fc.current_mode = ixgbe_fc_full; - hw_dbg(hw, "Flow Control = FULL.\n"); - } else { - hw->fc.current_mode = ixgbe_fc_rx_pause; - hw_dbg(hw, "Flow Control=RX PAUSE frames only\n"); - } - } else if (!(adv_reg & adv_sym) && (adv_reg & adv_asm) && - (lp_reg & lp_sym) && (lp_reg & lp_asm)) { - hw->fc.current_mode = ixgbe_fc_tx_pause; - hw_dbg(hw, "Flow Control = TX PAUSE frames only.\n"); - } else if ((adv_reg & adv_sym) && (adv_reg & adv_asm) && - !(lp_reg & lp_sym) && (lp_reg & lp_asm)) { - hw->fc.current_mode = ixgbe_fc_rx_pause; - hw_dbg(hw, "Flow Control = RX PAUSE frames only.\n"); - } else { - hw->fc.current_mode = ixgbe_fc_none; - hw_dbg(hw, "Flow Control = NONE.\n"); - } - return 0; -} - -/** - * ixgbe_setup_fc - Set up flow control + * ixgbe_fc_autoneg - Configure flow control * @hw: pointer to hardware structure * - * Called at init time to set up flow control. + * Compares our advertised flow control capabilities to those advertised by + * our link partner, and determines the proper flow control mode to use. **/ -static s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num) +void ixgbe_fc_autoneg(struct ixgbe_hw *hw) { - s32 ret_val = 0; - u32 reg = 0, reg_bp = 0; - u16 reg_cu = 0; - -#ifdef CONFIG_DCB - if (hw->fc.requested_mode == ixgbe_fc_pfc) { - hw->fc.current_mode = hw->fc.requested_mode; - goto out; - } - -#endif /* CONFIG_DCB */ - /* Validate the packetbuf configuration */ - if (packetbuf_num < 0 || packetbuf_num > 7) { - hw_dbg(hw, "Invalid packet buffer number [%d], expected range " - "is 0-7\n", packetbuf_num); - ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; - goto out; - } + s32 ret_val = IXGBE_ERR_FC_NOT_NEGOTIATED; + ixgbe_link_speed speed; + bool link_up; /* - * Validate the water mark configuration. Zero water marks are invalid - * because it causes the controller to just blast out fc packets. + * AN should have completed when the cable was plugged in. + * Look for reasons to bail out. Bail out if: + * - FC autoneg is disabled, or if + * - link is not up. + * + * Since we're being called from an LSC, link is already known to be up. + * So use link_up_wait_to_complete=false. */ - if (!hw->fc.low_water || - !hw->fc.high_water[packetbuf_num] || - !hw->fc.pause_time) { - hw_dbg(hw, "Invalid water mark configuration\n"); - ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; + if (hw->fc.disable_fc_autoneg) goto out; - } - /* - * Validate the requested mode. Strict IEEE mode does not allow - * ixgbe_fc_rx_pause because it will cause us to fail at UNH. - */ - if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) { - hw_dbg(hw, "ixgbe_fc_rx_pause not valid in strict " - "IEEE mode\n"); - ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; + hw->mac.ops.check_link(hw, &speed, &link_up, false); + if (!link_up) goto out; - } - - /* - * 10gig parts do not have a word in the EEPROM to determine the - * default flow control setting, so we explicitly set it to full. - */ - if (hw->fc.requested_mode == ixgbe_fc_default) - hw->fc.requested_mode = ixgbe_fc_full; - - /* - * Set up the 1G and 10G flow control advertisement registers so the - * HW will be able to do fc autoneg once the cable is plugged in. If - * we link at 10G, the 1G advertisement is harmless and vice versa. - */ switch (hw->phy.media_type) { + /* Autoneg flow control on fiber adapters */ case ixgbe_media_type_fiber: + if (speed == IXGBE_LINK_SPEED_1GB_FULL) + ret_val = ixgbe_fc_autoneg_fiber(hw); + break; + + /* Autoneg flow control on backplane adapters */ case ixgbe_media_type_backplane: - reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); - reg_bp = IXGBE_READ_REG(hw, IXGBE_AUTOC); + ret_val = ixgbe_fc_autoneg_backplane(hw); break; + /* Autoneg flow control on copper adapters */ case ixgbe_media_type_copper: - hw->phy.ops.read_reg(hw, MDIO_AN_ADVERTISE, - MDIO_MMD_AN, ®_cu); + if (ixgbe_device_supports_autoneg_fc(hw) == 0) + ret_val = ixgbe_fc_autoneg_copper(hw); break; default: - ; - } - - /* - * The possible values of fc.requested_mode are: - * 0: Flow control is completely disabled - * 1: Rx flow control is enabled (we can receive pause frames, - * but not send pause frames). - * 2: Tx flow control is enabled (we can send pause frames but - * we do not support receiving pause frames). - * 3: Both Rx and Tx flow control (symmetric) are enabled. -#ifdef CONFIG_DCB - * 4: Priority Flow Control is enabled. -#endif - * other: Invalid. - */ - switch (hw->fc.requested_mode) { - case ixgbe_fc_none: - /* Flow control completely disabled by software override. */ - reg &= ~(IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); - if (hw->phy.media_type == ixgbe_media_type_backplane) - reg_bp &= ~(IXGBE_AUTOC_SYM_PAUSE | - IXGBE_AUTOC_ASM_PAUSE); - else if (hw->phy.media_type == ixgbe_media_type_copper) - reg_cu &= ~(IXGBE_TAF_SYM_PAUSE | IXGBE_TAF_ASM_PAUSE); break; - case ixgbe_fc_rx_pause: - /* - * Rx Flow control is enabled and Tx Flow control is - * disabled by software override. Since there really - * isn't a way to advertise that we are capable of RX - * Pause ONLY, we will advertise that we support both - * symmetric and asymmetric Rx PAUSE. Later, we will - * disable the adapter's ability to send PAUSE frames. - */ - reg |= (IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); - if (hw->phy.media_type == ixgbe_media_type_backplane) - reg_bp |= (IXGBE_AUTOC_SYM_PAUSE | - IXGBE_AUTOC_ASM_PAUSE); - else if (hw->phy.media_type == ixgbe_media_type_copper) - reg_cu |= (IXGBE_TAF_SYM_PAUSE | IXGBE_TAF_ASM_PAUSE); - break; - case ixgbe_fc_tx_pause: - /* - * Tx Flow control is enabled, and Rx Flow control is - * disabled by software override. - */ - reg |= (IXGBE_PCS1GANA_ASM_PAUSE); - reg &= ~(IXGBE_PCS1GANA_SYM_PAUSE); - if (hw->phy.media_type == ixgbe_media_type_backplane) { - reg_bp |= (IXGBE_AUTOC_ASM_PAUSE); - reg_bp &= ~(IXGBE_AUTOC_SYM_PAUSE); - } else if (hw->phy.media_type == ixgbe_media_type_copper) { - reg_cu |= (IXGBE_TAF_ASM_PAUSE); - reg_cu &= ~(IXGBE_TAF_SYM_PAUSE); - } - break; - case ixgbe_fc_full: - /* Flow control (both Rx and Tx) is enabled by SW override. */ - reg |= (IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); - if (hw->phy.media_type == ixgbe_media_type_backplane) - reg_bp |= (IXGBE_AUTOC_SYM_PAUSE | - IXGBE_AUTOC_ASM_PAUSE); - else if (hw->phy.media_type == ixgbe_media_type_copper) - reg_cu |= (IXGBE_TAF_SYM_PAUSE | IXGBE_TAF_ASM_PAUSE); - break; -#ifdef CONFIG_DCB - case ixgbe_fc_pfc: - goto out; - break; -#endif /* CONFIG_DCB */ - default: - hw_dbg(hw, "Flow control param set incorrectly\n"); - ret_val = IXGBE_ERR_CONFIG; - goto out; - break; - } - - if (hw->mac.type != ixgbe_mac_X540) { - /* - * Enable auto-negotiation between the MAC & PHY; - * the MAC will advertise clause 37 flow control. - */ - IXGBE_WRITE_REG(hw, IXGBE_PCS1GANA, reg); - reg = IXGBE_READ_REG(hw, IXGBE_PCS1GLCTL); - - /* Disable AN timeout */ - if (hw->fc.strict_ieee) - reg &= ~IXGBE_PCS1GLCTL_AN_1G_TIMEOUT_EN; - - IXGBE_WRITE_REG(hw, IXGBE_PCS1GLCTL, reg); - hw_dbg(hw, "Set up FC; PCS1GLCTL = 0x%08X\n", reg); - } - - /* - * AUTOC restart handles negotiation of 1G and 10G on backplane - * and copper. There is no need to set the PCS1GCTL register. - * - */ - if (hw->phy.media_type == ixgbe_media_type_backplane) { - reg_bp |= IXGBE_AUTOC_AN_RESTART; - IXGBE_WRITE_REG(hw, IXGBE_AUTOC, reg_bp); - } else if ((hw->phy.media_type == ixgbe_media_type_copper) && - (ixgbe_device_supports_autoneg_fc(hw) == 0)) { - hw->phy.ops.write_reg(hw, MDIO_AN_ADVERTISE, - MDIO_MMD_AN, reg_cu); } - hw_dbg(hw, "Set up FC; IXGBE_AUTOC = 0x%08X\n", reg); out: - return ret_val; + if (ret_val == 0) { + hw->fc.fc_was_autonegged = true; + } else { + hw->fc.fc_was_autonegged = false; + hw->fc.current_mode = hw->fc.requested_mode; + } } /** @@ -2606,7 +2561,7 @@ s32 ixgbe_disable_rx_buff_generic(struct ixgbe_hw *hw) break; else /* Use interrupt-safe sleep just in case */ - udelay(10); + udelay(1000); } /* For informational purposes only */ @@ -2783,17 +2738,36 @@ s32 ixgbe_get_san_mac_addr_generic(struct ixgbe_hw *hw, u8 *san_mac_addr) * Read PCIe configuration space, and get the MSI-X vector count from * the capabilities table. **/ -u32 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw) +u16 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw) { struct ixgbe_adapter *adapter = hw->back; - u16 msix_count; - pci_read_config_word(adapter->pdev, IXGBE_PCIE_MSIX_82599_CAPS, - &msix_count); + u16 msix_count = 1; + u16 max_msix_count; + u16 pcie_offset; + + switch (hw->mac.type) { + case ixgbe_mac_82598EB: + pcie_offset = IXGBE_PCIE_MSIX_82598_CAPS; + max_msix_count = IXGBE_MAX_MSIX_VECTORS_82598; + break; + case ixgbe_mac_82599EB: + case ixgbe_mac_X540: + pcie_offset = IXGBE_PCIE_MSIX_82599_CAPS; + max_msix_count = IXGBE_MAX_MSIX_VECTORS_82599; + break; + default: + return msix_count; + } + + pci_read_config_word(adapter->pdev, pcie_offset, &msix_count); msix_count &= IXGBE_PCIE_MSIX_TBL_SZ_MASK; - /* MSI-X count is zero-based in HW, so increment to give proper value */ + /* MSI-X count is zero-based in HW */ msix_count++; + if (msix_count > max_msix_count) + msix_count = max_msix_count; + return msix_count; } @@ -3202,28 +3176,6 @@ s32 ixgbe_get_wwn_prefix_generic(struct ixgbe_hw *hw, u16 *wwnn_prefix, return 0; } -/** - * ixgbe_device_supports_autoneg_fc - Check if phy supports autoneg flow - * control - * @hw: pointer to hardware structure - * - * There are several phys that do not support autoneg flow control. This - * function check the device id to see if the associated phy supports - * autoneg flow control. - **/ -static s32 ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw) -{ - - switch (hw->device_id) { - case IXGBE_DEV_ID_X540T: - return 0; - case IXGBE_DEV_ID_82599_T3_LOM: - return 0; - default: - return IXGBE_ERR_FC_NOT_SUPPORTED; - } -} - /** * ixgbe_set_mac_anti_spoofing - Enable/Disable MAC anti-spoofing * @hw: pointer to hardware structure @@ -3585,3 +3537,172 @@ void ixgbe_clear_tx_pending(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT, gcr_ext); IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0); } + +static const u8 ixgbe_emc_temp_data[4] = { + IXGBE_EMC_INTERNAL_DATA, + IXGBE_EMC_DIODE1_DATA, + IXGBE_EMC_DIODE2_DATA, + IXGBE_EMC_DIODE3_DATA +}; +static const u8 ixgbe_emc_therm_limit[4] = { + IXGBE_EMC_INTERNAL_THERM_LIMIT, + IXGBE_EMC_DIODE1_THERM_LIMIT, + IXGBE_EMC_DIODE2_THERM_LIMIT, + IXGBE_EMC_DIODE3_THERM_LIMIT +}; + +/** + * ixgbe_get_ets_data - Extracts the ETS bit data + * @hw: pointer to hardware structure + * @ets_cfg: extected ETS data + * @ets_offset: offset of ETS data + * + * Returns error code. + **/ +static s32 ixgbe_get_ets_data(struct ixgbe_hw *hw, u16 *ets_cfg, + u16 *ets_offset) +{ + s32 status = 0; + + status = hw->eeprom.ops.read(hw, IXGBE_ETS_CFG, ets_offset); + if (status) + goto out; + + if ((*ets_offset == 0x0000) || (*ets_offset == 0xFFFF)) { + status = IXGBE_NOT_IMPLEMENTED; + goto out; + } + + status = hw->eeprom.ops.read(hw, *ets_offset, ets_cfg); + if (status) + goto out; + + if ((*ets_cfg & IXGBE_ETS_TYPE_MASK) != IXGBE_ETS_TYPE_EMC_SHIFTED) { + status = IXGBE_NOT_IMPLEMENTED; + goto out; + } + +out: + return status; +} + +/** + * ixgbe_get_thermal_sensor_data - Gathers thermal sensor data + * @hw: pointer to hardware structure + * + * Returns the thermal sensor data structure + **/ +s32 ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw) +{ + s32 status = 0; + u16 ets_offset; + u16 ets_cfg; + u16 ets_sensor; + u8 num_sensors; + u8 i; + struct ixgbe_thermal_sensor_data *data = &hw->mac.thermal_sensor_data; + + /* Only support thermal sensors attached to physical port 0 */ + if ((IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)) { + status = IXGBE_NOT_IMPLEMENTED; + goto out; + } + + status = ixgbe_get_ets_data(hw, &ets_cfg, &ets_offset); + if (status) + goto out; + + num_sensors = (ets_cfg & IXGBE_ETS_NUM_SENSORS_MASK); + if (num_sensors > IXGBE_MAX_SENSORS) + num_sensors = IXGBE_MAX_SENSORS; + + for (i = 0; i < num_sensors; i++) { + u8 sensor_index; + u8 sensor_location; + + status = hw->eeprom.ops.read(hw, (ets_offset + 1 + i), + &ets_sensor); + if (status) + goto out; + + sensor_index = ((ets_sensor & IXGBE_ETS_DATA_INDEX_MASK) >> + IXGBE_ETS_DATA_INDEX_SHIFT); + sensor_location = ((ets_sensor & IXGBE_ETS_DATA_LOC_MASK) >> + IXGBE_ETS_DATA_LOC_SHIFT); + + if (sensor_location != 0) { + status = hw->phy.ops.read_i2c_byte(hw, + ixgbe_emc_temp_data[sensor_index], + IXGBE_I2C_THERMAL_SENSOR_ADDR, + &data->sensor[i].temp); + if (status) + goto out; + } + } +out: + return status; +} + +/** + * ixgbe_init_thermal_sensor_thresh_generic - Inits thermal sensor thresholds + * @hw: pointer to hardware structure + * + * Inits the thermal sensor thresholds according to the NVM map + * and save off the threshold and location values into mac.thermal_sensor_data + **/ +s32 ixgbe_init_thermal_sensor_thresh_generic(struct ixgbe_hw *hw) +{ + s32 status = 0; + u16 ets_offset; + u16 ets_cfg; + u16 ets_sensor; + u8 low_thresh_delta; + u8 num_sensors; + u8 therm_limit; + u8 i; + struct ixgbe_thermal_sensor_data *data = &hw->mac.thermal_sensor_data; + + memset(data, 0, sizeof(struct ixgbe_thermal_sensor_data)); + + /* Only support thermal sensors attached to physical port 0 */ + if ((IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)) { + status = IXGBE_NOT_IMPLEMENTED; + goto out; + } + + status = ixgbe_get_ets_data(hw, &ets_cfg, &ets_offset); + if (status) + goto out; + + low_thresh_delta = ((ets_cfg & IXGBE_ETS_LTHRES_DELTA_MASK) >> + IXGBE_ETS_LTHRES_DELTA_SHIFT); + num_sensors = (ets_cfg & IXGBE_ETS_NUM_SENSORS_MASK); + if (num_sensors > IXGBE_MAX_SENSORS) + num_sensors = IXGBE_MAX_SENSORS; + + for (i = 0; i < num_sensors; i++) { + u8 sensor_index; + u8 sensor_location; + + hw->eeprom.ops.read(hw, (ets_offset + 1 + i), &ets_sensor); + sensor_index = ((ets_sensor & IXGBE_ETS_DATA_INDEX_MASK) >> + IXGBE_ETS_DATA_INDEX_SHIFT); + sensor_location = ((ets_sensor & IXGBE_ETS_DATA_LOC_MASK) >> + IXGBE_ETS_DATA_LOC_SHIFT); + therm_limit = ets_sensor & IXGBE_ETS_DATA_HTHRESH_MASK; + + hw->phy.ops.write_i2c_byte(hw, + ixgbe_emc_therm_limit[sensor_index], + IXGBE_I2C_THERMAL_SENSOR_ADDR, therm_limit); + + if (sensor_location == 0) + continue; + + data->sensor[i].location = sensor_location; + data->sensor[i].caution_thresh = therm_limit; + data->sensor[i].max_op_thresh = therm_limit - low_thresh_delta; + } +out: + return status; +} + diff --git a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h index 204f06235b45..6222fdb3d3f1 100644 --- a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h +++ b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h @@ -31,7 +31,7 @@ #include "ixgbe_type.h" #include "ixgbe.h" -u32 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw); +u16 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw); s32 ixgbe_init_ops_generic(struct ixgbe_hw *hw); s32 ixgbe_init_hw_generic(struct ixgbe_hw *hw); s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw); @@ -77,8 +77,8 @@ s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw); s32 ixgbe_disable_rx_buff_generic(struct ixgbe_hw *hw); s32 ixgbe_enable_rx_buff_generic(struct ixgbe_hw *hw); s32 ixgbe_enable_rx_dma_generic(struct ixgbe_hw *hw, u32 regval); -s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw, s32 packetbuf_num); -s32 ixgbe_fc_autoneg(struct ixgbe_hw *hw); +s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw); +void ixgbe_fc_autoneg(struct ixgbe_hw *hw); s32 ixgbe_validate_mac_addr(u8 *mac_addr); s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask); @@ -107,6 +107,19 @@ void ixgbe_clear_tx_pending(struct ixgbe_hw *hw); void ixgbe_set_rxpba_generic(struct ixgbe_hw *hw, int num_pb, u32 headroom, int strategy); +#define IXGBE_I2C_THERMAL_SENSOR_ADDR 0xF8 +#define IXGBE_EMC_INTERNAL_DATA 0x00 +#define IXGBE_EMC_INTERNAL_THERM_LIMIT 0x20 +#define IXGBE_EMC_DIODE1_DATA 0x01 +#define IXGBE_EMC_DIODE1_THERM_LIMIT 0x19 +#define IXGBE_EMC_DIODE2_DATA 0x23 +#define IXGBE_EMC_DIODE2_THERM_LIMIT 0x1A +#define IXGBE_EMC_DIODE3_DATA 0x2A +#define IXGBE_EMC_DIODE3_THERM_LIMIT 0x30 + +s32 ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw); +s32 ixgbe_init_thermal_sensor_thresh_generic(struct ixgbe_hw *hw); + #define IXGBE_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg))) #ifndef writeq diff --git a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c index d3695edfcb8b..87592b458c9c 100644 --- a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c +++ b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c @@ -191,53 +191,46 @@ s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *hw, */ s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, u8 pfc_en) { - u32 reg; + u32 fcrtl, reg; u8 i; - if (pfc_en) { - /* Enable Transmit Priority Flow Control */ - reg = IXGBE_READ_REG(hw, IXGBE_RMCS); - reg &= ~IXGBE_RMCS_TFCE_802_3X; - /* correct the reporting of our flow control status */ - reg |= IXGBE_RMCS_TFCE_PRIORITY; - IXGBE_WRITE_REG(hw, IXGBE_RMCS, reg); - - /* Enable Receive Priority Flow Control */ - reg = IXGBE_READ_REG(hw, IXGBE_FCTRL); - reg &= ~IXGBE_FCTRL_RFCE; - reg |= IXGBE_FCTRL_RPFCE; - IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg); - - /* Configure pause time */ - for (i = 0; i < (MAX_TRAFFIC_CLASS >> 1); i++) - IXGBE_WRITE_REG(hw, IXGBE_FCTTV(i), 0x68006800); + /* Enable Transmit Priority Flow Control */ + reg = IXGBE_READ_REG(hw, IXGBE_RMCS); + reg &= ~IXGBE_RMCS_TFCE_802_3X; + reg |= IXGBE_RMCS_TFCE_PRIORITY; + IXGBE_WRITE_REG(hw, IXGBE_RMCS, reg); - /* Configure flow control refresh threshold value */ - IXGBE_WRITE_REG(hw, IXGBE_FCRTV, 0x3400); - } + /* Enable Receive Priority Flow Control */ + reg = IXGBE_READ_REG(hw, IXGBE_FCTRL); + reg &= ~(IXGBE_FCTRL_RPFCE | IXGBE_FCTRL_RFCE); - /* - * Configure flow control thresholds and enable priority flow control - * for each traffic class. - */ - for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { - int enabled = pfc_en & (1 << i); + if (pfc_en) + reg |= IXGBE_FCTRL_RPFCE; - reg = hw->fc.low_water << 10; + IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg); - if (enabled == pfc_enabled_tx || - enabled == pfc_enabled_full) - reg |= IXGBE_FCRTL_XONE; + 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))) { + IXGBE_WRITE_REG(hw, IXGBE_FCRTL(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_FCRTH(i), 0); + continue; + } + + 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); + } - IXGBE_WRITE_REG(hw, IXGBE_FCRTL(i), reg); + /* Configure pause time */ + reg = hw->fc.pause_time * 0x00010001; + for (i = 0; i < (MAX_TRAFFIC_CLASS / 2); i++) + IXGBE_WRITE_REG(hw, IXGBE_FCTTV(i), reg); - reg = hw->fc.high_water[i] << 10; - if (enabled == pfc_enabled_tx || - enabled == pfc_enabled_full) - reg |= IXGBE_FCRTH_FCEN; + /* Configure flow control refresh threshold value */ + IXGBE_WRITE_REG(hw, IXGBE_FCRTV, hw->fc.pause_time / 2); - IXGBE_WRITE_REG(hw, IXGBE_FCRTH(i), reg); - } return 0; } diff --git a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c index 888a419dc3d9..4eac80d01857 100644 --- a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c +++ b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c @@ -211,24 +211,42 @@ s32 ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *hw, */ s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en, u8 *prio_tc) { - u32 i, j, reg; + u32 i, j, fcrtl, reg; u8 max_tc = 0; - for (i = 0; i < MAX_USER_PRIORITY; i++) + /* Enable Transmit Priority Flow Control */ + IXGBE_WRITE_REG(hw, IXGBE_FCCFG, IXGBE_FCCFG_TFCE_PRIORITY); + + /* Enable Receive Priority Flow Control */ + reg = IXGBE_READ_REG(hw, IXGBE_MFLCN); + reg |= IXGBE_MFLCN_DPF; + + /* + * X540 supports per TC Rx priority flow control. So + * clear all TCs and only enable those that should be + * enabled. + */ + reg &= ~(IXGBE_MFLCN_RPFCE_MASK | IXGBE_MFLCN_RFCE); + + if (hw->mac.type == ixgbe_mac_X540) + reg |= pfc_en << IXGBE_MFLCN_RPFCE_SHIFT; + + if (pfc_en) + reg |= IXGBE_MFLCN_RPFCE; + + IXGBE_WRITE_REG(hw, IXGBE_MFLCN, reg); + + for (i = 0; i < MAX_USER_PRIORITY; i++) { if (prio_tc[i] > max_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_TRAFFIC_CLASS; i++) { + for (i = 0; i <= max_tc; i++) { int enabled = 0; - if (i > max_tc) { - reg = 0; - IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), reg); - IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(i), reg); - continue; - } - for (j = 0; j < MAX_USER_PRIORITY; j++) { if ((prio_tc[j] == i) && (pfc_en & (1 << j))) { enabled = 1; @@ -236,61 +254,29 @@ s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en, u8 *prio_tc) } } - reg = hw->fc.low_water << 10; - - if (enabled) - reg |= IXGBE_FCRTL_XONE; - IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), reg); + if (enabled) { + reg = (hw->fc.high_water[i] << 10) | IXGBE_FCRTH_FCEN; + IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), fcrtl); + } else { + reg = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i)) - 32; + IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), 0); + } - reg = hw->fc.high_water[i] << 10; - if (enabled) - reg |= IXGBE_FCRTH_FCEN; IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(i), reg); } - if (pfc_en) { - /* Configure pause time (2 TCs per register) */ - reg = hw->fc.pause_time | (hw->fc.pause_time << 16); - for (i = 0; i < (MAX_TRAFFIC_CLASS / 2); i++) - IXGBE_WRITE_REG(hw, IXGBE_FCTTV(i), reg); - - /* Configure flow control refresh threshold value */ - IXGBE_WRITE_REG(hw, IXGBE_FCRTV, hw->fc.pause_time / 2); - - - reg = IXGBE_FCCFG_TFCE_PRIORITY; - IXGBE_WRITE_REG(hw, IXGBE_FCCFG, reg); - /* - * Enable Receive PFC - * 82599 will always honor XOFF frames we receive when - * we are in PFC mode however X540 only honors enabled - * traffic classes. - */ - reg = IXGBE_READ_REG(hw, IXGBE_MFLCN); - reg &= ~IXGBE_MFLCN_RFCE; - reg |= IXGBE_MFLCN_RPFCE | IXGBE_MFLCN_DPF; - - if (hw->mac.type == ixgbe_mac_X540) { - reg &= ~IXGBE_MFLCN_RPFCE_MASK; - reg |= pfc_en << IXGBE_MFLCN_RPFCE_SHIFT; - } + for (; i < MAX_TRAFFIC_CLASS; i++) { + IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(i), 0); + } - IXGBE_WRITE_REG(hw, IXGBE_MFLCN, reg); - - } else { - /* X540 devices have a RX bit that should be cleared - * if PFC is disabled on all TCs but PFC features is - * enabled. - */ - if (hw->mac.type == ixgbe_mac_X540) { - reg = IXGBE_READ_REG(hw, IXGBE_MFLCN); - reg &= ~IXGBE_MFLCN_RPFCE_MASK; - IXGBE_WRITE_REG(hw, IXGBE_MFLCN, reg); - } + /* Configure pause time (2 TCs per register) */ + reg = hw->fc.pause_time * 0x00010001; + for (i = 0; i < (MAX_TRAFFIC_CLASS / 2); i++) + IXGBE_WRITE_REG(hw, IXGBE_FCTTV(i), reg); - for (i = 0; i < MAX_TRAFFIC_CLASS; i++) - hw->mac.ops.fc_enable(hw, i); - } + /* Configure flow control refresh threshold value */ + IXGBE_WRITE_REG(hw, IXGBE_FCRTV, hw->fc.pause_time / 2); return 0; } diff --git a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c index 32e5c02ff6d0..5164a21b13ca 100644 --- a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c +++ b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c @@ -338,6 +338,8 @@ static void ixgbe_dcbnl_devreset(struct net_device *dev) static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) { struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_dcb_config *dcb_cfg = &adapter->dcb_cfg; + struct ixgbe_hw *hw = &adapter->hw; int ret = DCB_NO_HW_CHG; int i; @@ -350,32 +352,6 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) if (!adapter->dcb_set_bitmap) return ret; - if (adapter->dcb_cfg.pfc_mode_enable) { - switch (adapter->hw.mac.type) { - case ixgbe_mac_82599EB: - case ixgbe_mac_X540: - if (adapter->hw.fc.current_mode != ixgbe_fc_pfc) - adapter->last_lfc_mode = - adapter->hw.fc.current_mode; - break; - default: - break; - } - adapter->hw.fc.requested_mode = ixgbe_fc_pfc; - } else { - switch (adapter->hw.mac.type) { - case ixgbe_mac_82598EB: - adapter->hw.fc.requested_mode = ixgbe_fc_none; - break; - case ixgbe_mac_82599EB: - case ixgbe_mac_X540: - adapter->hw.fc.requested_mode = adapter->last_lfc_mode; - break; - default: - break; - } - } - if (adapter->dcb_set_bitmap & (BIT_PG_TX|BIT_PG_RX)) { u16 refill[MAX_TRAFFIC_CLASS], max[MAX_TRAFFIC_CLASS]; u8 bwg_id[MAX_TRAFFIC_CLASS], prio_type[MAX_TRAFFIC_CLASS]; @@ -388,23 +364,19 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) max_frame = max(max_frame, IXGBE_FCOE_JUMBO_FRAME_SIZE); #endif - ixgbe_dcb_calculate_tc_credits(&adapter->hw, &adapter->dcb_cfg, - max_frame, DCB_TX_CONFIG); - ixgbe_dcb_calculate_tc_credits(&adapter->hw, &adapter->dcb_cfg, - max_frame, DCB_RX_CONFIG); + ixgbe_dcb_calculate_tc_credits(hw, dcb_cfg, max_frame, + DCB_TX_CONFIG); + ixgbe_dcb_calculate_tc_credits(hw, dcb_cfg, max_frame, + DCB_RX_CONFIG); - ixgbe_dcb_unpack_refill(&adapter->dcb_cfg, - DCB_TX_CONFIG, refill); - ixgbe_dcb_unpack_max(&adapter->dcb_cfg, max); - ixgbe_dcb_unpack_bwgid(&adapter->dcb_cfg, - DCB_TX_CONFIG, bwg_id); - ixgbe_dcb_unpack_prio(&adapter->dcb_cfg, - DCB_TX_CONFIG, prio_type); - ixgbe_dcb_unpack_map(&adapter->dcb_cfg, - DCB_TX_CONFIG, prio_tc); + ixgbe_dcb_unpack_refill(dcb_cfg, DCB_TX_CONFIG, refill); + ixgbe_dcb_unpack_max(dcb_cfg, max); + ixgbe_dcb_unpack_bwgid(dcb_cfg, DCB_TX_CONFIG, bwg_id); + ixgbe_dcb_unpack_prio(dcb_cfg, DCB_TX_CONFIG, prio_type); + ixgbe_dcb_unpack_map(dcb_cfg, DCB_TX_CONFIG, prio_tc); - ixgbe_dcb_hw_ets_config(&adapter->hw, refill, max, - bwg_id, prio_type, prio_tc); + ixgbe_dcb_hw_ets_config(hw, refill, max, bwg_id, + prio_type, prio_tc); for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) netdev_set_prio_tc_map(netdev, i, prio_tc[i]); @@ -413,19 +385,21 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) } if (adapter->dcb_set_bitmap & BIT_PFC) { - u8 pfc_en; - u8 prio_tc[MAX_USER_PRIORITY]; + if (dcb_cfg->pfc_mode_enable) { + u8 pfc_en; + u8 prio_tc[MAX_USER_PRIORITY]; + + ixgbe_dcb_unpack_map(dcb_cfg, DCB_TX_CONFIG, prio_tc); + ixgbe_dcb_unpack_pfc(dcb_cfg, &pfc_en); + ixgbe_dcb_hw_pfc_config(hw, pfc_en, prio_tc); + } else { + hw->mac.ops.fc_enable(hw); + } - ixgbe_dcb_unpack_map(&adapter->dcb_cfg, - DCB_TX_CONFIG, prio_tc); - ixgbe_dcb_unpack_pfc(&adapter->dcb_cfg, &pfc_en); - ixgbe_dcb_hw_pfc_config(&adapter->hw, pfc_en, prio_tc); - if (ret != DCB_HW_CHG_RST) - ret = DCB_HW_CHG; - } + ixgbe_set_rx_drop_en(adapter); - if (adapter->dcb_cfg.pfc_mode_enable) - adapter->hw.fc.current_mode = ixgbe_fc_pfc; + ret = DCB_HW_CHG; + } #ifdef IXGBE_FCOE /* Reprogam FCoE hardware offloads when the traffic class @@ -647,7 +621,9 @@ static int ixgbe_dcbnl_ieee_setpfc(struct net_device *dev, struct ieee_pfc *pfc) { struct ixgbe_adapter *adapter = netdev_priv(dev); + struct ixgbe_hw *hw = &adapter->hw; u8 *prio_tc; + int err; if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_IEEE)) return -EINVAL; @@ -661,7 +637,16 @@ static int ixgbe_dcbnl_ieee_setpfc(struct net_device *dev, prio_tc = adapter->ixgbe_ieee_ets->prio_tc; memcpy(adapter->ixgbe_ieee_pfc, pfc, sizeof(*adapter->ixgbe_ieee_pfc)); - return ixgbe_dcb_hw_pfc_config(&adapter->hw, pfc->pfc_en, prio_tc); + + /* Enable link flow control parameters if PFC is disabled */ + if (pfc->pfc_en) + err = ixgbe_dcb_hw_pfc_config(hw, pfc->pfc_en, prio_tc); + else + err = hw->mac.ops.fc_enable(hw); + + ixgbe_set_rx_drop_en(adapter); + + return err; } static int ixgbe_dcbnl_ieee_setapp(struct net_device *dev, diff --git a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index cfe7d269590c..3178f1ec3711 100644 --- a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -391,11 +391,6 @@ static void ixgbe_get_pauseparam(struct net_device *netdev, } else if (hw->fc.current_mode == ixgbe_fc_full) { pause->rx_pause = 1; pause->tx_pause = 1; -#ifdef CONFIG_DCB - } else if (hw->fc.current_mode == ixgbe_fc_pfc) { - pause->rx_pause = 0; - pause->tx_pause = 0; -#endif } } @@ -404,21 +399,14 @@ static int ixgbe_set_pauseparam(struct net_device *netdev, { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; - struct ixgbe_fc_info fc; + struct ixgbe_fc_info fc = hw->fc; -#ifdef CONFIG_DCB - if (adapter->dcb_cfg.pfc_mode_enable || - ((hw->mac.type == ixgbe_mac_82598EB) && - (adapter->flags & IXGBE_FLAG_DCB_ENABLED))) + /* 82598 does no support link flow control with DCB enabled */ + if ((hw->mac.type == ixgbe_mac_82598EB) && + (adapter->flags & IXGBE_FLAG_DCB_ENABLED)) return -EINVAL; -#endif - fc = hw->fc; - - if (pause->autoneg != AUTONEG_ENABLE) - fc.disable_fc_autoneg = true; - else - fc.disable_fc_autoneg = false; + fc.disable_fc_autoneg = (pause->autoneg != AUTONEG_ENABLE); if ((pause->rx_pause && pause->tx_pause) || pause->autoneg) fc.requested_mode = ixgbe_fc_full; @@ -426,14 +414,8 @@ static int ixgbe_set_pauseparam(struct net_device *netdev, fc.requested_mode = ixgbe_fc_rx_pause; else if (!pause->rx_pause && pause->tx_pause) fc.requested_mode = ixgbe_fc_tx_pause; - else if (!pause->rx_pause && !pause->tx_pause) - fc.requested_mode = ixgbe_fc_none; else - return -EINVAL; - -#ifdef CONFIG_DCB - adapter->last_lfc_mode = fc.requested_mode; -#endif + fc.requested_mode = ixgbe_fc_none; /* if the thing changed then we'll update and use new autoneg */ if (memcmp(&fc, &hw->fc, sizeof(struct ixgbe_fc_info))) { @@ -1971,53 +1953,12 @@ static int ixgbe_wol_exclusion(struct ixgbe_adapter *adapter, struct ethtool_wolinfo *wol) { struct ixgbe_hw *hw = &adapter->hw; - int retval = 1; - u16 wol_cap = adapter->eeprom_cap & IXGBE_DEVICE_CAPS_WOL_MASK; - - /* WOL not supported except for the following */ - switch(hw->device_id) { - case IXGBE_DEV_ID_82599_SFP: - /* Only these subdevices could supports WOL */ - switch (hw->subsystem_device_id) { - case IXGBE_SUBDEV_ID_82599_560FLR: - /* only support first port */ - if (hw->bus.func != 0) { - wol->supported = 0; - break; - } - case IXGBE_SUBDEV_ID_82599_SFP: - retval = 0; - break; - default: - wol->supported = 0; - break; - } - break; - case IXGBE_DEV_ID_82599_COMBO_BACKPLANE: - /* All except this subdevice support WOL */ - if (hw->subsystem_device_id == - IXGBE_SUBDEV_ID_82599_KX4_KR_MEZZ) { - wol->supported = 0; - break; - } - retval = 0; - break; - case IXGBE_DEV_ID_82599_KX4: - retval = 0; - break; - case IXGBE_DEV_ID_X540T: - /* check eeprom to see if enabled wol */ - if ((wol_cap == IXGBE_DEVICE_CAPS_WOL_PORT0_1) || - ((wol_cap == IXGBE_DEVICE_CAPS_WOL_PORT0) && - (hw->bus.func == 0))) { - retval = 0; - break; - } + int retval = 0; - /* All others not supported */ - wol->supported = 0; - break; - default: + /* WOL not supported for all devices */ + if (!ixgbe_wol_supported(adapter, hw->device_id, + hw->subsystem_device_id)) { + retval = 1; wol->supported = 0; } @@ -2755,6 +2696,46 @@ static int ixgbe_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) return ret; } +static int ixgbe_get_ts_info(struct net_device *dev, + struct ethtool_ts_info *info) +{ + struct ixgbe_adapter *adapter = netdev_priv(dev); + + switch (adapter->hw.mac.type) { +#ifdef CONFIG_IXGBE_PTP + case ixgbe_mac_X540: + case ixgbe_mac_82599EB: + info->so_timestamping = + SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + + if (adapter->ptp_clock) + info->phc_index = ptp_clock_index(adapter->ptp_clock); + else + info->phc_index = -1; + + info->tx_types = + (1 << HWTSTAMP_TX_OFF) | + (1 << HWTSTAMP_TX_ON); + + info->rx_filters = + (1 << HWTSTAMP_FILTER_NONE) | + (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | + (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | + (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | + (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) | + (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) | + (1 << HWTSTAMP_FILTER_SOME); + break; +#endif /* CONFIG_IXGBE_PTP */ + default: + return ethtool_op_get_ts_info(dev, info); + break; + } + return 0; +} + static const struct ethtool_ops ixgbe_ethtool_ops = { .get_settings = ixgbe_get_settings, .set_settings = ixgbe_set_settings, @@ -2783,6 +2764,7 @@ static const struct ethtool_ops ixgbe_ethtool_ops = { .set_coalesce = ixgbe_set_coalesce, .get_rxnfc = ixgbe_get_rxnfc, .set_rxnfc = ixgbe_set_rxnfc, + .get_ts_info = ixgbe_get_ts_info, }; void ixgbe_set_ethtool_ops(struct net_device *netdev) diff --git a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c index ed1b47dc0834..af1a5314b494 100644 --- a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c +++ b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c @@ -523,11 +523,17 @@ static void ixgbe_add_ring(struct ixgbe_ring *ring, /** * ixgbe_alloc_q_vector - Allocate memory for a single interrupt vector * @adapter: board private structure to initialize + * @v_count: q_vectors allocated on adapter, used for ring interleaving * @v_idx: index of vector in adapter struct + * @txr_count: total number of Tx rings to allocate + * @txr_idx: index of first Tx ring to allocate + * @rxr_count: total number of Rx rings to allocate + * @rxr_idx: index of first Rx ring to allocate * * We allocate one q_vector. If allocation fails we return -ENOMEM. **/ -static int ixgbe_alloc_q_vector(struct ixgbe_adapter *adapter, int v_idx, +static int ixgbe_alloc_q_vector(struct ixgbe_adapter *adapter, + int v_count, int v_idx, int txr_count, int txr_idx, int rxr_count, int rxr_idx) { @@ -598,7 +604,7 @@ static int ixgbe_alloc_q_vector(struct ixgbe_adapter *adapter, int v_idx, /* update count and index */ txr_count--; - txr_idx++; + txr_idx += v_count; /* push pointer to next ring */ ring++; @@ -641,7 +647,7 @@ static int ixgbe_alloc_q_vector(struct ixgbe_adapter *adapter, int v_idx, /* update count and index */ rxr_count--; - rxr_idx++; + rxr_idx += v_count; /* push pointer to next ring */ ring++; @@ -700,24 +706,23 @@ static int ixgbe_alloc_q_vectors(struct ixgbe_adapter *adapter) q_vectors = 1; if (q_vectors >= (rxr_remaining + txr_remaining)) { - for (; rxr_remaining; v_idx++, q_vectors--) { - int rqpv = DIV_ROUND_UP(rxr_remaining, q_vectors); - err = ixgbe_alloc_q_vector(adapter, v_idx, - 0, 0, rqpv, rxr_idx); + for (; rxr_remaining; v_idx++) { + err = ixgbe_alloc_q_vector(adapter, q_vectors, v_idx, + 0, 0, 1, rxr_idx); if (err) goto err_out; /* update counts and index */ - rxr_remaining -= rqpv; - rxr_idx += rqpv; + rxr_remaining--; + rxr_idx++; } } - for (; q_vectors; v_idx++, q_vectors--) { - int rqpv = DIV_ROUND_UP(rxr_remaining, q_vectors); - int tqpv = DIV_ROUND_UP(txr_remaining, q_vectors); - err = ixgbe_alloc_q_vector(adapter, v_idx, + 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 = ixgbe_alloc_q_vector(adapter, q_vectors, v_idx, tqpv, txr_idx, rqpv, rxr_idx); @@ -726,9 +731,9 @@ static int ixgbe_alloc_q_vectors(struct ixgbe_adapter *adapter) /* update counts and index */ rxr_remaining -= rqpv; - rxr_idx += rqpv; txr_remaining -= tqpv; - txr_idx += tqpv; + rxr_idx++; + txr_idx++; } return 0; diff --git a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 467948e9ecd9..bf20457ea23a 100644 --- a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -63,8 +63,8 @@ static char ixgbe_default_device_descr[] = "Intel(R) 10 Gigabit Network Connection"; #endif #define MAJ 3 -#define MIN 8 -#define BUILD 21 +#define MIN 9 +#define BUILD 15 #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \ __stringify(BUILD) "-k" const char ixgbe_driver_version[] = DRV_VERSION; @@ -133,7 +133,7 @@ static struct notifier_block dca_notifier = { 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"); + "Maximum number of virtual functions to allocate per physical function - default is zero and maximum value is 63"); #endif /* CONFIG_PCI_IOV */ static unsigned int allow_unsupported_sfp; @@ -610,35 +610,50 @@ void ixgbe_unmap_and_free_tx_resource(struct ixgbe_ring *ring, /* tx_buffer must be completely set up in the transmit path */ } -static void ixgbe_update_xoff_received(struct ixgbe_adapter *adapter) +static void ixgbe_update_xoff_rx_lfc(struct ixgbe_adapter *adapter) { struct ixgbe_hw *hw = &adapter->hw; struct ixgbe_hw_stats *hwstats = &adapter->stats; - u32 data = 0; - u32 xoff[8] = {0}; int i; + u32 data; - if ((hw->fc.current_mode == ixgbe_fc_full) || - (hw->fc.current_mode == ixgbe_fc_rx_pause)) { - switch (hw->mac.type) { - case ixgbe_mac_82598EB: - data = IXGBE_READ_REG(hw, IXGBE_LXOFFRXC); - break; - default: - data = IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT); - } - hwstats->lxoffrxc += data; + if ((hw->fc.current_mode != ixgbe_fc_full) && + (hw->fc.current_mode != ixgbe_fc_rx_pause)) + return; - /* refill credits (no tx hang) if we received xoff */ - if (!data) - return; + switch (hw->mac.type) { + case ixgbe_mac_82598EB: + data = IXGBE_READ_REG(hw, IXGBE_LXOFFRXC); + break; + default: + data = IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT); + } + hwstats->lxoffrxc += data; - for (i = 0; i < adapter->num_tx_queues; i++) - clear_bit(__IXGBE_HANG_CHECK_ARMED, - &adapter->tx_ring[i]->state); + /* refill credits (no tx hang) if we received xoff */ + if (!data) return; - } else if (!(adapter->dcb_cfg.pfc_mode_enable)) + + for (i = 0; i < adapter->num_tx_queues; i++) + clear_bit(__IXGBE_HANG_CHECK_ARMED, + &adapter->tx_ring[i]->state); +} + +static void ixgbe_update_xoff_received(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + struct ixgbe_hw_stats *hwstats = &adapter->stats; + u32 xoff[8] = {0}; + int i; + bool pfc_en = adapter->dcb_cfg.pfc_mode_enable; + + if (adapter->ixgbe_ieee_pfc) + pfc_en |= !!(adapter->ixgbe_ieee_pfc->pfc_en); + + if (!(adapter->flags & IXGBE_FLAG_DCB_ENABLED) || !pfc_en) { + ixgbe_update_xoff_rx_lfc(adapter); return; + } /* update stats for each tc, only valid with PFC enabled */ for (i = 0; i < MAX_TX_PACKET_BUFFERS; i++) { @@ -774,6 +789,13 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector, total_bytes += tx_buffer->bytecount; total_packets += tx_buffer->gso_segs; +#ifdef CONFIG_IXGBE_PTP + if (unlikely(tx_buffer->tx_flags & + IXGBE_TX_FLAGS_TSTAMP)) + ixgbe_ptp_tx_hwtstamp(q_vector, + tx_buffer->skb); + +#endif /* free the skb */ dev_kfree_skb_any(tx_buffer->skb); @@ -1144,7 +1166,7 @@ static bool ixgbe_alloc_mapped_page(struct ixgbe_ring *rx_ring, * there isn't much point in holding memory we can't use */ if (dma_mapping_error(rx_ring->dev, dma)) { - put_page(page); + __free_pages(page, ixgbe_rx_pg_order(rx_ring)); bi->page = NULL; rx_ring->rx_stats.alloc_rx_page_failed++; @@ -1374,6 +1396,11 @@ static void ixgbe_process_skb_fields(struct ixgbe_ring *rx_ring, ixgbe_rx_checksum(rx_ring, rx_desc, skb); +#ifdef CONFIG_IXGBE_PTP + if (ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_STAT_TS)) + ixgbe_ptp_rx_hwtstamp(rx_ring->q_vector, skb); +#endif + if (ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_VP)) { u16 vid = le16_to_cpu(rx_desc->wb.upper.vlan); __vlan_hwaccel_put_tag(skb, vid); @@ -2295,6 +2322,9 @@ static irqreturn_t ixgbe_msix_other(int irq, void *data) } ixgbe_check_fan_failure(adapter, eicr); +#ifdef CONFIG_IXGBE_PTP + ixgbe_ptp_check_pps_event(adapter, eicr); +#endif /* re-enable the original interrupt state, no lsc, no queues */ if (!test_bit(__IXGBE_DOWN, &adapter->state)) @@ -2487,6 +2517,9 @@ static irqreturn_t ixgbe_intr(int irq, void *data) } ixgbe_check_fan_failure(adapter, eicr); +#ifdef CONFIG_IXGBE_PTP + ixgbe_ptp_check_pps_event(adapter, eicr); +#endif /* would disable interrupts here but EIAM disabled it */ napi_schedule(&q_vector->napi); @@ -2756,6 +2789,61 @@ static void ixgbe_configure_tx(struct ixgbe_adapter *adapter) ixgbe_configure_tx_ring(adapter, adapter->tx_ring[i]); } +static void ixgbe_enable_rx_drop(struct ixgbe_adapter *adapter, + struct ixgbe_ring *ring) +{ + struct ixgbe_hw *hw = &adapter->hw; + u8 reg_idx = ring->reg_idx; + u32 srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(reg_idx)); + + srrctl |= IXGBE_SRRCTL_DROP_EN; + + IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(reg_idx), srrctl); +} + +static void ixgbe_disable_rx_drop(struct ixgbe_adapter *adapter, + struct ixgbe_ring *ring) +{ + struct ixgbe_hw *hw = &adapter->hw; + u8 reg_idx = ring->reg_idx; + u32 srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(reg_idx)); + + srrctl &= ~IXGBE_SRRCTL_DROP_EN; + + IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(reg_idx), srrctl); +} + +#ifdef CONFIG_IXGBE_DCB +void ixgbe_set_rx_drop_en(struct ixgbe_adapter *adapter) +#else +static void ixgbe_set_rx_drop_en(struct ixgbe_adapter *adapter) +#endif +{ + int i; + bool pfc_en = adapter->dcb_cfg.pfc_mode_enable; + + if (adapter->ixgbe_ieee_pfc) + pfc_en |= !!(adapter->ixgbe_ieee_pfc->pfc_en); + + /* + * We should set the drop enable bit if: + * SR-IOV is enabled + * or + * Number of Rx queues > 1 and flow control is disabled + * + * This allows us to avoid head of line blocking for security + * and performance reasons. + */ + if (adapter->num_vfs || (adapter->num_rx_queues > 1 && + !(adapter->hw.fc.current_mode & ixgbe_fc_tx_pause) && !pfc_en)) { + for (i = 0; i < adapter->num_rx_queues; i++) + ixgbe_enable_rx_drop(adapter, adapter->rx_ring[i]); + } else { + for (i = 0; i < adapter->num_rx_queues; i++) + ixgbe_disable_rx_drop(adapter, adapter->rx_ring[i]); + } +} + #define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter, @@ -2902,33 +2990,6 @@ static void ixgbe_configure_rscctl(struct ixgbe_adapter *adapter, IXGBE_WRITE_REG(hw, IXGBE_RSCCTL(reg_idx), rscctrl); } -/** - * ixgbe_set_uta - Set unicast filter table address - * @adapter: board private structure - * - * The unicast table address is a register array of 32-bit registers. - * The table is meant to be used in a way similar to how the MTA is used - * however due to certain limitations in the hardware it is necessary to - * set all the hash bits to 1 and use the VMOLR ROPE bit as a promiscuous - * enable bit to allow vlan tag stripping when promiscuous mode is enabled - **/ -static void ixgbe_set_uta(struct ixgbe_adapter *adapter) -{ - struct ixgbe_hw *hw = &adapter->hw; - int i; - - /* The UTA table only exists on 82599 hardware and newer */ - if (hw->mac.type < ixgbe_mac_82599EB) - return; - - /* we only need to do this if VMDq is enabled */ - if (!(adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)) - return; - - for (i = 0; i < 128; i++) - IXGBE_WRITE_REG(hw, IXGBE_UTA(i), ~0); -} - #define IXGBE_MAX_RX_DESC_POLL 10 static void ixgbe_rx_desc_queue_enable(struct ixgbe_adapter *adapter, struct ixgbe_ring *ring) @@ -3214,8 +3275,6 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) /* Program registers for the distribution of queues */ ixgbe_setup_mrqc(adapter); - ixgbe_set_uta(adapter); - /* set_rx_buffer_len must be called before ring initialization */ ixgbe_set_rx_buffer_len(adapter); @@ -3452,16 +3511,17 @@ void ixgbe_set_rx_mode(struct net_device *netdev) } ixgbe_vlan_filter_enable(adapter); hw->addr_ctrl.user_set_promisc = false; - /* - * Write addresses to available RAR registers, if there is not - * sufficient space to store all the addresses then enable - * unicast promiscuous mode - */ - count = ixgbe_write_uc_addr_list(netdev); - if (count < 0) { - fctrl |= IXGBE_FCTRL_UPE; - vmolr |= IXGBE_VMOLR_ROPE; - } + } + + /* + * Write addresses to available RAR registers, if there is not + * sufficient space to store all the addresses then enable + * unicast promiscuous mode + */ + count = ixgbe_write_uc_addr_list(netdev); + if (count < 0) { + fctrl |= IXGBE_FCTRL_UPE; + vmolr |= IXGBE_VMOLR_ROPE; } if (adapter->num_vfs) { @@ -4128,7 +4188,8 @@ static void ixgbe_clean_rx_ring(struct ixgbe_ring *rx_ring) DMA_FROM_DEVICE); rx_buffer->dma = 0; if (rx_buffer->page) - put_page(rx_buffer->page); + __free_pages(rx_buffer->page, + ixgbe_rx_pg_order(rx_ring)); rx_buffer->page = NULL; } @@ -4426,9 +4487,6 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) /* default flow control settings */ hw->fc.requested_mode = ixgbe_fc_full; hw->fc.current_mode = ixgbe_fc_full; /* init for ethtool output */ -#ifdef CONFIG_DCB - adapter->last_lfc_mode = hw->fc.current_mode; -#endif ixgbe_pbthresh_setup(adapter); hw->fc.pause_time = IXGBE_DEFAULT_FCPAUSE; hw->fc.send_xon = true; @@ -4993,9 +5051,6 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) { u64 rsc_count = 0; u64 rsc_flush = 0; - for (i = 0; i < 16; i++) - adapter->hw_rx_no_dma_resources += - IXGBE_READ_REG(hw, IXGBE_QPRDC(i)); for (i = 0; i < adapter->num_rx_queues; i++) { rsc_count += adapter->rx_ring[i]->rx_stats.rsc_count; rsc_flush += adapter->rx_ring[i]->rx_stats.rsc_flush; @@ -5098,6 +5153,9 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) hwstats->b2ospc += IXGBE_READ_REG(hw, IXGBE_B2OSPC); hwstats->b2ogprc += IXGBE_READ_REG(hw, IXGBE_B2OGPRC); case ixgbe_mac_82599EB: + for (i = 0; i < 16; i++) + adapter->hw_rx_no_dma_resources += + IXGBE_READ_REG(hw, IXGBE_QPRDC(i)); hwstats->gorc += IXGBE_READ_REG(hw, IXGBE_GORCL); IXGBE_READ_REG(hw, IXGBE_GORCH); /* to clear */ hwstats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL); @@ -5275,7 +5333,7 @@ static void ixgbe_watchdog_update_link(struct ixgbe_adapter *adapter) struct ixgbe_hw *hw = &adapter->hw; u32 link_speed = adapter->link_speed; bool link_up = adapter->link_up; - int i; + bool pfc_en = adapter->dcb_cfg.pfc_mode_enable; if (!(adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE)) return; @@ -5287,13 +5345,13 @@ static void ixgbe_watchdog_update_link(struct ixgbe_adapter *adapter) link_speed = IXGBE_LINK_SPEED_10GB_FULL; link_up = true; } - if (link_up) { - if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { - for (i = 0; i < MAX_TRAFFIC_CLASS; i++) - hw->mac.ops.fc_enable(hw, i); - } else { - hw->mac.ops.fc_enable(hw, 0); - } + + if (adapter->ixgbe_ieee_pfc) + pfc_en |= !!(adapter->ixgbe_ieee_pfc->pfc_en); + + if (link_up && !((adapter->flags & IXGBE_FLAG_DCB_ENABLED) && pfc_en)) { + hw->mac.ops.fc_enable(hw); + ixgbe_set_rx_drop_en(adapter); } if (link_up || @@ -5347,6 +5405,11 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter) flow_rx = false; break; } + +#ifdef CONFIG_IXGBE_PTP + ixgbe_ptp_start_cyclecounter(adapter); +#endif + e_info(drv, "NIC Link is Up %s, Flow Control: %s\n", (link_speed == IXGBE_LINK_SPEED_10GB_FULL ? "10 Gbps" : @@ -5384,6 +5447,10 @@ static void ixgbe_watchdog_link_is_down(struct ixgbe_adapter *adapter) if (ixgbe_is_sfp(hw) && hw->mac.type == ixgbe_mac_82598EB) adapter->flags2 |= IXGBE_FLAG2_SEARCH_FOR_SFP; +#ifdef CONFIG_IXGBE_PTP + ixgbe_ptp_start_cyclecounter(adapter); +#endif + e_info(drv, "NIC Link is Down\n"); netif_carrier_off(netdev); } @@ -5683,6 +5750,9 @@ static void ixgbe_service_task(struct work_struct *work) ixgbe_watchdog_subtask(adapter); ixgbe_fdir_reinit_subtask(adapter); ixgbe_check_hang_subtask(adapter); +#ifdef CONFIG_IXGBE_PTP + ixgbe_ptp_overflow_check(adapter); +#endif ixgbe_service_event_complete(adapter); } @@ -5833,6 +5903,11 @@ static __le32 ixgbe_tx_cmd_type(u32 tx_flags) if (tx_flags & IXGBE_TX_FLAGS_HW_VLAN) cmd_type |= cpu_to_le32(IXGBE_ADVTXD_DCMD_VLE); +#ifdef CONFIG_IXGBE_PTP + if (tx_flags & IXGBE_TX_FLAGS_TSTAMP) + cmd_type |= cpu_to_le32(IXGBE_ADVTXD_MAC_TSTAMP); +#endif + /* set segmentation enable bits for TSO/FSO */ #ifdef IXGBE_FCOE if (tx_flags & (IXGBE_TX_FLAGS_TSO | IXGBE_TX_FLAGS_FSO)) @@ -6223,6 +6298,15 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, tx_flags |= IXGBE_TX_FLAGS_SW_VLAN; } + skb_tx_timestamp(skb); + +#ifdef CONFIG_IXGBE_PTP + if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) { + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + tx_flags |= IXGBE_TX_FLAGS_TSTAMP; + } +#endif + #ifdef CONFIG_PCI_IOV /* * Use the l2switch_enable flag - would be false if the DMA @@ -6375,7 +6459,14 @@ static int ixgbe_ioctl(struct net_device *netdev, struct ifreq *req, int cmd) { struct ixgbe_adapter *adapter = netdev_priv(netdev); - return mdio_mii_ioctl(&adapter->hw.phy.mdio, if_mii(req), cmd); + switch (cmd) { +#ifdef CONFIG_IXGBE_PTP + case SIOCSHWTSTAMP: + return ixgbe_ptp_hwtstamp_ioctl(adapter, req, cmd); +#endif + default: + return mdio_mii_ioctl(&adapter->hw.phy.mdio, if_mii(req), cmd); + } } /** @@ -6567,15 +6658,17 @@ int ixgbe_setup_tc(struct net_device *dev, u8 tc) if (tc) { netdev_set_num_tc(dev, tc); - adapter->last_lfc_mode = adapter->hw.fc.current_mode; adapter->flags |= IXGBE_FLAG_DCB_ENABLED; adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE; - if (adapter->hw.mac.type == ixgbe_mac_82598EB) + if (adapter->hw.mac.type == ixgbe_mac_82598EB) { + adapter->last_lfc_mode = adapter->hw.fc.requested_mode; adapter->hw.fc.requested_mode = ixgbe_fc_none; + } } else { netdev_reset_tc(dev); - adapter->hw.fc.requested_mode = adapter->last_lfc_mode; + if (adapter->hw.mac.type == ixgbe_mac_82598EB) + adapter->hw.fc.requested_mode = adapter->last_lfc_mode; adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED; adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE; @@ -6624,7 +6717,7 @@ static netdev_features_t ixgbe_fix_features(struct net_device *netdev, /* Turn off LRO if not RSC capable */ if (!(adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE)) features &= ~NETIF_F_LRO; - + return features; } @@ -6683,6 +6776,74 @@ static int ixgbe_set_features(struct net_device *netdev, return 0; } +static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, + struct net_device *dev, + unsigned char *addr, + u16 flags) +{ + struct ixgbe_adapter *adapter = netdev_priv(dev); + int err = -EOPNOTSUPP; + + if (ndm->ndm_state & NUD_PERMANENT) { + pr_info("%s: FDB only supports static addresses\n", + ixgbe_driver_name); + return -EINVAL; + } + + if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) { + if (is_unicast_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; +} + +static int ixgbe_ndo_fdb_del(struct ndmsg *ndm, + struct net_device *dev, + unsigned char *addr) +{ + struct ixgbe_adapter *adapter = netdev_priv(dev); + int err = -EOPNOTSUPP; + + if (ndm->ndm_state & NUD_PERMANENT) { + pr_info("%s: FDB only supports static addresses\n", + ixgbe_driver_name); + return -EINVAL; + } + + if (adapter->flags & IXGBE_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 ixgbe_ndo_fdb_dump(struct sk_buff *skb, + struct netlink_callback *cb, + struct net_device *dev, + int idx) +{ + struct ixgbe_adapter *adapter = netdev_priv(dev); + + if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) + idx = ndo_dflt_fdb_dump(skb, cb, dev, idx); + + return idx; +} + static const struct net_device_ops ixgbe_netdev_ops = { .ndo_open = ixgbe_open, .ndo_stop = ixgbe_close, @@ -6719,6 +6880,9 @@ static const struct net_device_ops ixgbe_netdev_ops = { #endif /* IXGBE_FCOE */ .ndo_set_features = ixgbe_set_features, .ndo_fix_features = ixgbe_fix_features, + .ndo_fdb_add = ixgbe_ndo_fdb_add, + .ndo_fdb_del = ixgbe_ndo_fdb_del, + .ndo_fdb_dump = ixgbe_ndo_fdb_dump, }; static void __devinit ixgbe_probe_vf(struct ixgbe_adapter *adapter, @@ -6733,13 +6897,65 @@ static void __devinit ixgbe_probe_vf(struct ixgbe_adapter *adapter, /* The 82599 supports up to 64 VFs per physical function * but this implementation limits allocation to 63 so that * basic networking resources are still available to the - * physical function + * physical function. If the user requests greater thn + * 63 VFs then it is an error - reset to default of zero. */ - adapter->num_vfs = (max_vfs > 63) ? 63 : max_vfs; + adapter->num_vfs = (max_vfs > 63) ? 0 : max_vfs; ixgbe_enable_sriov(adapter, ii); #endif /* CONFIG_PCI_IOV */ } +/** + * ixgbe_wol_supported - Check whether device supports WoL + * @hw: hw specific details + * @device_id: the device ID + * @subdev_id: the subsystem device ID + * + * This function is used by probe and ethtool to determine + * which devices have WoL support + * + **/ +int ixgbe_wol_supported(struct ixgbe_adapter *adapter, u16 device_id, + u16 subdevice_id) +{ + struct ixgbe_hw *hw = &adapter->hw; + u16 wol_cap = adapter->eeprom_cap & IXGBE_DEVICE_CAPS_WOL_MASK; + int is_wol_supported = 0; + + switch (device_id) { + case IXGBE_DEV_ID_82599_SFP: + /* Only these subdevices could supports WOL */ + switch (subdevice_id) { + case IXGBE_SUBDEV_ID_82599_560FLR: + /* only support first port */ + if (hw->bus.func != 0) + break; + case IXGBE_SUBDEV_ID_82599_SFP: + is_wol_supported = 1; + break; + } + break; + case IXGBE_DEV_ID_82599_COMBO_BACKPLANE: + /* All except this subdevice support WOL */ + if (subdevice_id != IXGBE_SUBDEV_ID_82599_KX4_KR_MEZZ) + is_wol_supported = 1; + break; + case IXGBE_DEV_ID_82599_KX4: + is_wol_supported = 1; + break; + case IXGBE_DEV_ID_X540T: + /* check eeprom to see if enabled wol */ + if ((wol_cap == IXGBE_DEVICE_CAPS_WOL_PORT0_1) || + ((wol_cap == IXGBE_DEVICE_CAPS_WOL_PORT0) && + (hw->bus.func == 0))) { + is_wol_supported = 1; + } + break; + } + + return is_wol_supported; +} + /** * ixgbe_probe - Device Initialization Routine * @pdev: PCI device information struct @@ -6766,7 +6982,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, u16 device_caps; #endif u32 eec; - u16 wol_cap; /* Catch broken hardware that put the wrong VF device ID in * the PCIe SR-IOV capability. @@ -7030,42 +7245,18 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, netdev->features &= ~NETIF_F_RXHASH; } - /* WOL not supported for all but the following */ + /* WOL not supported for all devices */ adapter->wol = 0; - switch (pdev->device) { - case IXGBE_DEV_ID_82599_SFP: - /* Only these subdevice supports WOL */ - switch (pdev->subsystem_device) { - case IXGBE_SUBDEV_ID_82599_560FLR: - /* only support first port */ - if (hw->bus.func != 0) - break; - case IXGBE_SUBDEV_ID_82599_SFP: - adapter->wol = IXGBE_WUFC_MAG; - break; - } - break; - case IXGBE_DEV_ID_82599_COMBO_BACKPLANE: - /* All except this subdevice support WOL */ - if (pdev->subsystem_device != IXGBE_SUBDEV_ID_82599_KX4_KR_MEZZ) - adapter->wol = IXGBE_WUFC_MAG; - break; - case IXGBE_DEV_ID_82599_KX4: + hw->eeprom.ops.read(hw, 0x2c, &adapter->eeprom_cap); + if (ixgbe_wol_supported(adapter, pdev->device, pdev->subsystem_device)) adapter->wol = IXGBE_WUFC_MAG; - break; - case IXGBE_DEV_ID_X540T: - /* Check eeprom to see if it is enabled */ - hw->eeprom.ops.read(hw, 0x2c, &adapter->eeprom_cap); - wol_cap = adapter->eeprom_cap & IXGBE_DEVICE_CAPS_WOL_MASK; - if ((wol_cap == IXGBE_DEVICE_CAPS_WOL_PORT0_1) || - ((wol_cap == IXGBE_DEVICE_CAPS_WOL_PORT0) && - (hw->bus.func == 0))) - adapter->wol = IXGBE_WUFC_MAG; - break; - } device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol); +#ifdef CONFIG_IXGBE_PTP + ixgbe_ptp_init(adapter); +#endif /* CONFIG_IXGBE_PTP*/ + /* save off EEPROM version number */ hw->eeprom.ops.read(hw, 0x2e, &adapter->eeprom_verh); hw->eeprom.ops.read(hw, 0x2d, &adapter->eeprom_verl); @@ -7152,6 +7343,12 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, e_dev_info("%s\n", ixgbe_default_device_descr); cards_found++; + +#ifdef CONFIG_IXGBE_HWMON + if (ixgbe_sysfs_init(adapter)) + e_err(probe, "failed to allocate sysfs resources\n"); +#endif /* CONFIG_IXGBE_HWMON */ + return 0; err_register: @@ -7190,6 +7387,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) set_bit(__IXGBE_DOWN, &adapter->state); cancel_work_sync(&adapter->service_task); +#ifdef CONFIG_IXGBE_PTP + ixgbe_ptp_stop(adapter); +#endif + #ifdef CONFIG_IXGBE_DCA if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) { adapter->flags &= ~IXGBE_FLAG_DCA_ENABLED; @@ -7198,6 +7399,10 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) } #endif +#ifdef CONFIG_IXGBE_HWMON + ixgbe_sysfs_exit(adapter); +#endif /* CONFIG_IXGBE_HWMON */ + #ifdef IXGBE_FCOE if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) ixgbe_cleanup_fcoe(adapter); diff --git a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c index bf9f82f4b1ae..24117709d6a2 100644 --- a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c +++ b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c @@ -1582,13 +1582,21 @@ static s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data) **/ static void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl) { - *i2cctl |= IXGBE_I2C_CLK_OUT; - - IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl); - IXGBE_WRITE_FLUSH(hw); + u32 i = 0; + u32 timeout = IXGBE_I2C_CLOCK_STRETCHING_TIMEOUT; + u32 i2cctl_r = 0; - /* SCL rise time (1000ns) */ - udelay(IXGBE_I2C_T_RISE); + for (i = 0; i < timeout; i++) { + *i2cctl |= IXGBE_I2C_CLK_OUT; + IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl); + IXGBE_WRITE_FLUSH(hw); + /* SCL rise time (1000ns) */ + udelay(IXGBE_I2C_T_RISE); + + i2cctl_r = IXGBE_READ_REG(hw, IXGBE_I2CCTL); + if (i2cctl_r & IXGBE_I2C_CLK_IN) + break; + } } /** diff --git a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c new file mode 100644 index 000000000000..ddc6a4d19302 --- /dev/null +++ b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c @@ -0,0 +1,900 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2012 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, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + 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 "ixgbe.h" +#include + +/* + * The 82599 and the X540 do not have true 64bit nanosecond scale + * counter registers. Instead, SYSTIME is defined by a fixed point + * system which allows the user to define the scale counter increment + * value at every level change of the oscillator driving the SYSTIME + * value. For both devices the TIMINCA:IV field defines this + * increment. On the X540 device, 31 bits are provided. However on the + * 82599 only provides 24 bits. The time unit is determined by the + * clock frequency of the oscillator in combination with the TIMINCA + * register. When these devices link at 10Gb the oscillator has a + * period of 6.4ns. In order to convert the scale counter into + * nanoseconds the cyclecounter and timecounter structures are + * used. The SYSTIME registers need to be converted to ns values by use + * of only a right shift (division by power of 2). The following math + * determines the largest incvalue that will fit into the available + * bits in the TIMINCA register. + * + * PeriodWidth: Number of bits to store the clock period + * MaxWidth: The maximum width value of the TIMINCA register + * Period: The clock period for the oscillator + * round(): discard the fractional portion of the calculation + * + * Period * [ 2 ^ ( MaxWidth - PeriodWidth ) ] + * + * For the X540, MaxWidth is 31 bits, and the base period is 6.4 ns + * For the 82599, MaxWidth is 24 bits, and the base period is 6.4 ns + * + * The period also changes based on the link speed: + * At 10Gb link or no link, the period remains the same. + * At 1Gb link, the period is multiplied by 10. (64ns) + * At 100Mb link, the period is multiplied by 100. (640ns) + * + * The calculated value allows us to right shift the SYSTIME register + * value in order to quickly convert it into a nanosecond clock, + * while allowing for the maximum possible adjustment value. + * + * These diagrams are only for the 10Gb link period + * + * SYSTIMEH SYSTIMEL + * +--------------+ +--------------+ + * X540 | 32 | | 1 | 3 | 28 | + * *--------------+ +--------------+ + * \________ 36 bits ______/ fract + * + * +--------------+ +--------------+ + * 82599 | 32 | | 8 | 3 | 21 | + * *--------------+ +--------------+ + * \________ 43 bits ______/ fract + * + * The 36 bit X540 SYSTIME overflows every + * 2^36 * 10^-9 / 60 = 1.14 minutes or 69 seconds + * + * The 43 bit 82599 SYSTIME overflows every + * 2^43 * 10^-9 / 3600 = 2.4 hours + */ +#define IXGBE_INCVAL_10GB 0x66666666 +#define IXGBE_INCVAL_1GB 0x40000000 +#define IXGBE_INCVAL_100 0x50000000 + +#define IXGBE_INCVAL_SHIFT_10GB 28 +#define IXGBE_INCVAL_SHIFT_1GB 24 +#define IXGBE_INCVAL_SHIFT_100 21 + +#define IXGBE_INCVAL_SHIFT_82599 7 +#define IXGBE_INCPER_SHIFT_82599 24 +#define IXGBE_MAX_TIMEADJ_VALUE 0x7FFFFFFFFFFFFFFFULL + +#define IXGBE_OVERFLOW_PERIOD (HZ * 30) + +#ifndef NSECS_PER_SEC +#define NSECS_PER_SEC 1000000000ULL +#endif + +/** + * ixgbe_ptp_read - read raw cycle counter (to be used by time counter) + * @cc - the cyclecounter structure + * + * this function reads the cyclecounter registers and is called by the + * cyclecounter structure used to construct a ns counter from the + * arbitrary fixed point registers + */ +static cycle_t ixgbe_ptp_read(const struct cyclecounter *cc) +{ + struct ixgbe_adapter *adapter = + container_of(cc, struct ixgbe_adapter, cc); + struct ixgbe_hw *hw = &adapter->hw; + u64 stamp = 0; + + stamp |= (u64)IXGBE_READ_REG(hw, IXGBE_SYSTIML); + stamp |= (u64)IXGBE_READ_REG(hw, IXGBE_SYSTIMH) << 32; + + return stamp; +} + +/** + * ixgbe_ptp_adjfreq + * @ptp - the ptp clock structure + * @ppb - parts per billion adjustment from base + * + * adjust the frequency of the ptp cycle counter by the + * indicated ppb from the base frequency. + */ +static int ixgbe_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) +{ + struct ixgbe_adapter *adapter = + container_of(ptp, struct ixgbe_adapter, ptp_caps); + struct ixgbe_hw *hw = &adapter->hw; + u64 freq; + u32 diff, incval; + int neg_adj = 0; + + if (ppb < 0) { + neg_adj = 1; + ppb = -ppb; + } + + smp_mb(); + incval = ACCESS_ONCE(adapter->base_incval); + + freq = incval; + freq *= ppb; + diff = div_u64(freq, 1000000000ULL); + + incval = neg_adj ? (incval - diff) : (incval + diff); + + switch (hw->mac.type) { + case ixgbe_mac_X540: + IXGBE_WRITE_REG(hw, IXGBE_TIMINCA, incval); + break; + case ixgbe_mac_82599EB: + IXGBE_WRITE_REG(hw, IXGBE_TIMINCA, + (1 << IXGBE_INCPER_SHIFT_82599) | + incval); + break; + default: + break; + } + + return 0; +} + +/** + * ixgbe_ptp_adjtime + * @ptp - the ptp clock structure + * @delta - offset to adjust the cycle counter by + * + * adjust the timer by resetting the timecounter structure. + */ +static int ixgbe_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + struct ixgbe_adapter *adapter = + container_of(ptp, struct ixgbe_adapter, ptp_caps); + unsigned long flags; + u64 now; + + spin_lock_irqsave(&adapter->tmreg_lock, flags); + + now = timecounter_read(&adapter->tc); + now += delta; + + /* reset the timecounter */ + timecounter_init(&adapter->tc, + &adapter->cc, + now); + + spin_unlock_irqrestore(&adapter->tmreg_lock, flags); + return 0; +} + +/** + * ixgbe_ptp_gettime + * @ptp - the ptp clock structure + * @ts - timespec structure to hold the current time value + * + * read the timecounter and return the correct value on ns, + * after converting it into a struct timespec. + */ +static int ixgbe_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts) +{ + struct ixgbe_adapter *adapter = + container_of(ptp, struct ixgbe_adapter, ptp_caps); + u64 ns; + u32 remainder; + unsigned long flags; + + spin_lock_irqsave(&adapter->tmreg_lock, flags); + ns = timecounter_read(&adapter->tc); + spin_unlock_irqrestore(&adapter->tmreg_lock, flags); + + ts->tv_sec = div_u64_rem(ns, 1000000000ULL, &remainder); + ts->tv_nsec = remainder; + + return 0; +} + +/** + * ixgbe_ptp_settime + * @ptp - the ptp clock structure + * @ts - the timespec containing the new time for the cycle counter + * + * reset the timecounter to use a new base value instead of the kernel + * wall timer value. + */ +static int ixgbe_ptp_settime(struct ptp_clock_info *ptp, + const struct timespec *ts) +{ + struct ixgbe_adapter *adapter = + container_of(ptp, struct ixgbe_adapter, ptp_caps); + u64 ns; + unsigned long flags; + + ns = ts->tv_sec * 1000000000ULL; + ns += ts->tv_nsec; + + /* reset the timecounter */ + spin_lock_irqsave(&adapter->tmreg_lock, flags); + timecounter_init(&adapter->tc, &adapter->cc, ns); + spin_unlock_irqrestore(&adapter->tmreg_lock, flags); + + return 0; +} + +/** + * ixgbe_ptp_enable + * @ptp - the ptp clock structure + * @rq - the requested feature to change + * @on - whether to enable or disable the feature + * + * enable (or disable) ancillary features of the phc subsystem. + * our driver only supports the PPS feature on the X540 + */ +static int ixgbe_ptp_enable(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + struct ixgbe_adapter *adapter = + container_of(ptp, struct ixgbe_adapter, ptp_caps); + + /** + * When PPS is enabled, unmask the interrupt for the ClockOut + * feature, so that the interrupt handler can send the PPS + * event when the clock SDP triggers. Clear mask when PPS is + * disabled + */ + if (rq->type == PTP_CLK_REQ_PPS) { + switch (adapter->hw.mac.type) { + case ixgbe_mac_X540: + if (on) + adapter->flags2 |= IXGBE_FLAG2_PTP_PPS_ENABLED; + else + adapter->flags2 &= + ~IXGBE_FLAG2_PTP_PPS_ENABLED; + return 0; + default: + break; + } + } + + return -ENOTSUPP; +} + +/** + * ixgbe_ptp_check_pps_event + * @adapter - the private adapter structure + * @eicr - the interrupt cause register value + * + * This function is called by the interrupt routine when checking for + * interrupts. It will check and handle a pps event. + */ +void ixgbe_ptp_check_pps_event(struct ixgbe_adapter *adapter, u32 eicr) +{ + struct ixgbe_hw *hw = &adapter->hw; + struct ptp_clock_event event; + + event.type = PTP_CLOCK_PPS; + + /* Make sure ptp clock is valid, and PPS event enabled */ + if (!adapter->ptp_clock || + !(adapter->flags2 & IXGBE_FLAG2_PTP_PPS_ENABLED)) + return; + + switch (hw->mac.type) { + case ixgbe_mac_X540: + if (eicr & IXGBE_EICR_TIMESYNC) + ptp_clock_event(adapter->ptp_clock, &event); + break; + default: + break; + } +} + +/** + * ixgbe_ptp_enable_sdp + * @hw - the hardware private structure + * @shift - the clock shift for calculating nanoseconds + * + * this function enables the clock out feature on the sdp0 for the + * X540 device. It will create a 1second periodic output that can be + * used as the PPS (via an interrupt). + * + * It calculates when the systime will be on an exact second, and then + * aligns the start of the PPS signal to that value. The shift is + * necessary because it can change based on the link speed. + */ +static void ixgbe_ptp_enable_sdp(struct ixgbe_hw *hw, int shift) +{ + u32 esdp, tsauxc, clktiml, clktimh, trgttiml, trgttimh; + u64 clock_edge = 0; + u32 rem; + + switch (hw->mac.type) { + case ixgbe_mac_X540: + esdp = IXGBE_READ_REG(hw, IXGBE_ESDP); + + /* + * enable the SDP0 pin as output, and connected to the native + * function for Timesync (ClockOut) + */ + esdp |= (IXGBE_ESDP_SDP0_DIR | + IXGBE_ESDP_SDP0_NATIVE); + + /* + * enable the Clock Out feature on SDP0, and allow interrupts + * to occur when the pin changes + */ + tsauxc = (IXGBE_TSAUXC_EN_CLK | + IXGBE_TSAUXC_SYNCLK | + IXGBE_TSAUXC_SDP0_INT); + + /* clock period (or pulse length) */ + clktiml = (u32)(NSECS_PER_SEC << shift); + clktimh = (u32)((NSECS_PER_SEC << shift) >> 32); + + clock_edge |= (u64)IXGBE_READ_REG(hw, IXGBE_SYSTIML); + clock_edge |= (u64)IXGBE_READ_REG(hw, IXGBE_SYSTIMH) << 32; + + /* + * account for the fact that we can't do u64 division + * with remainder, by converting the clock values into + * nanoseconds first + */ + clock_edge >>= shift; + div_u64_rem(clock_edge, NSECS_PER_SEC, &rem); + clock_edge += (NSECS_PER_SEC - rem); + clock_edge <<= shift; + + /* specify the initial clock start time */ + trgttiml = (u32)clock_edge; + trgttimh = (u32)(clock_edge >> 32); + + IXGBE_WRITE_REG(hw, IXGBE_CLKTIML, clktiml); + IXGBE_WRITE_REG(hw, IXGBE_CLKTIMH, clktimh); + IXGBE_WRITE_REG(hw, IXGBE_TRGTTIML0, trgttiml); + IXGBE_WRITE_REG(hw, IXGBE_TRGTTIMH0, trgttimh); + + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); + IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, tsauxc); + + IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EICR_TIMESYNC); + break; + default: + break; + } +} + +/** + * ixgbe_ptp_disable_sdp + * @hw - the private hardware structure + * + * this function disables the auxiliary SDP clock out feature + */ +static void ixgbe_ptp_disable_sdp(struct ixgbe_hw *hw) +{ + IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EICR_TIMESYNC); + IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, 0); +} + +/** + * ixgbe_ptp_overflow_check - delayed work to detect SYSTIME overflow + * @work: structure containing information about this work task + * + * this work function is scheduled to continue reading the timecounter + * in order to prevent missing when the system time registers wrap + * around. This needs to be run approximately twice a minute when no + * PTP activity is occurring. + */ +void ixgbe_ptp_overflow_check(struct ixgbe_adapter *adapter) +{ + unsigned long elapsed_jiffies = adapter->last_overflow_check - jiffies; + struct timespec ts; + + if ((adapter->flags2 & IXGBE_FLAG2_OVERFLOW_CHECK_ENABLED) && + (elapsed_jiffies >= IXGBE_OVERFLOW_PERIOD)) { + ixgbe_ptp_gettime(&adapter->ptp_caps, &ts); + adapter->last_overflow_check = jiffies; + } +} + +/** + * ixgbe_ptp_tx_hwtstamp - utility function which checks for TX time stamp + * @q_vector: structure containing interrupt and ring information + * @skb: particular skb to send timestamp with + * + * if the timestamp is valid, we convert it into the timecounter ns + * value, then store that result into the shhwtstamps structure which + * is passed up the network stack + */ +void ixgbe_ptp_tx_hwtstamp(struct ixgbe_q_vector *q_vector, + struct sk_buff *skb) +{ + struct ixgbe_adapter *adapter; + struct ixgbe_hw *hw; + struct skb_shared_hwtstamps shhwtstamps; + u64 regval = 0, ns; + u32 tsynctxctl; + unsigned long flags; + + /* we cannot process timestamps on a ring without a q_vector */ + if (!q_vector || !q_vector->adapter) + return; + + adapter = q_vector->adapter; + hw = &adapter->hw; + + tsynctxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCTXCTL); + regval |= (u64)IXGBE_READ_REG(hw, IXGBE_TXSTMPL); + regval |= (u64)IXGBE_READ_REG(hw, IXGBE_TXSTMPH) << 32; + + /* + * if TX timestamp is not valid, exit after clearing the + * timestamp registers + */ + if (!(tsynctxctl & IXGBE_TSYNCTXCTL_VALID)) + return; + + spin_lock_irqsave(&adapter->tmreg_lock, flags); + ns = timecounter_cyc2time(&adapter->tc, regval); + spin_unlock_irqrestore(&adapter->tmreg_lock, flags); + + memset(&shhwtstamps, 0, sizeof(shhwtstamps)); + shhwtstamps.hwtstamp = ns_to_ktime(ns); + skb_tstamp_tx(skb, &shhwtstamps); +} + +/** + * ixgbe_ptp_rx_hwtstamp - utility function which checks for RX time stamp + * @q_vector: structure containing interrupt and ring information + * @skb: particular skb to send timestamp with + * + * if the timestamp is valid, we convert it into the timecounter ns + * value, then store that result into the shhwtstamps structure which + * is passed up the network stack + */ +void ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector, + struct sk_buff *skb) +{ + struct ixgbe_adapter *adapter; + struct ixgbe_hw *hw; + struct skb_shared_hwtstamps *shhwtstamps; + u64 regval = 0, ns; + u32 tsyncrxctl; + unsigned long flags; + + /* we cannot process timestamps on a ring without a q_vector */ + if (!q_vector || !q_vector->adapter) + return; + + adapter = q_vector->adapter; + hw = &adapter->hw; + + tsyncrxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCRXCTL); + regval |= (u64)IXGBE_READ_REG(hw, IXGBE_RXSTMPL); + regval |= (u64)IXGBE_READ_REG(hw, IXGBE_RXSTMPH) << 32; + + /* + * If this bit is set, then the RX registers contain the time stamp. No + * other packet will be time stamped until we read these registers, so + * read the registers to make them available again. Because only one + * packet can be time stamped at a time, we know that the register + * values must belong to this one here and therefore we don't need to + * compare any of the additional attributes stored for it. + * + * If nothing went wrong, then it should have a skb_shared_tx that we + * can turn into a skb_shared_hwtstamps. + */ + if (!(tsyncrxctl & IXGBE_TSYNCRXCTL_VALID)) + return; + + spin_lock_irqsave(&adapter->tmreg_lock, flags); + ns = timecounter_cyc2time(&adapter->tc, regval); + spin_unlock_irqrestore(&adapter->tmreg_lock, flags); + + shhwtstamps = skb_hwtstamps(skb); + shhwtstamps->hwtstamp = ns_to_ktime(ns); +} + +/** + * ixgbe_ptp_hwtstamp_ioctl - control hardware time stamping + * @adapter: pointer to adapter struct + * @ifreq: ioctl data + * @cmd: particular ioctl requested + * + * Outgoing time stamping can be enabled and disabled. Play nice and + * disable it when requested, although it shouldn't case any overhead + * when no packet needs it. At most one packet in the queue may be + * marked for time stamping, otherwise it would be impossible to tell + * for sure to which packet the hardware time stamp belongs. + * + * Incoming time stamping has to be configured via the hardware + * filters. Not all combinations are supported, in particular event + * type has to be specified. Matching the kind of event packet is + * not supported, with the exception of "all V2 events regardless of + * level 2 or 4". + */ +int ixgbe_ptp_hwtstamp_ioctl(struct ixgbe_adapter *adapter, + struct ifreq *ifr, int cmd) +{ + struct ixgbe_hw *hw = &adapter->hw; + struct hwtstamp_config config; + u32 tsync_tx_ctl = IXGBE_TSYNCTXCTL_ENABLED; + u32 tsync_rx_ctl = IXGBE_TSYNCRXCTL_ENABLED; + u32 tsync_rx_mtrl = 0; + bool is_l4 = false; + bool is_l2 = false; + u32 regval; + + if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) + return -EFAULT; + + /* reserved for future extensions */ + if (config.flags) + return -EINVAL; + + switch (config.tx_type) { + case HWTSTAMP_TX_OFF: + tsync_tx_ctl = 0; + case HWTSTAMP_TX_ON: + break; + default: + return -ERANGE; + } + + switch (config.rx_filter) { + case HWTSTAMP_FILTER_NONE: + tsync_rx_ctl = 0; + break; + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: + tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_L4_V1; + tsync_rx_mtrl = IXGBE_RXMTRL_V1_SYNC_MSG; + is_l4 = true; + break; + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: + tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_L4_V1; + tsync_rx_mtrl = IXGBE_RXMTRL_V1_DELAY_REQ_MSG; + is_l4 = true; + break; + case HWTSTAMP_FILTER_PTP_V2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: + tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_L2_L4_V2; + tsync_rx_mtrl = IXGBE_RXMTRL_V2_SYNC_MSG; + is_l2 = true; + is_l4 = true; + config.rx_filter = HWTSTAMP_FILTER_SOME; + break; + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: + tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_L2_L4_V2; + tsync_rx_mtrl = IXGBE_RXMTRL_V2_DELAY_REQ_MSG; + is_l2 = true; + is_l4 = true; + config.rx_filter = HWTSTAMP_FILTER_SOME; + break; + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_EVENT: + tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_EVENT_V2; + config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; + is_l2 = true; + is_l4 = true; + break; + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: + case HWTSTAMP_FILTER_ALL: + default: + /* + * register RXMTRL must be set, therefore it is not + * possible to time stamp both V1 Sync and Delay_Req messages + * and hardware does not support timestamping all packets + * => return error + */ + return -ERANGE; + } + + if (hw->mac.type == ixgbe_mac_82598EB) { + if (tsync_rx_ctl | tsync_tx_ctl) + return -ERANGE; + return 0; + } + + /* define ethertype filter for timestamped packets */ + if (is_l2) + IXGBE_WRITE_REG(hw, IXGBE_ETQF(3), + (IXGBE_ETQF_FILTER_EN | /* enable filter */ + IXGBE_ETQF_1588 | /* enable timestamping */ + ETH_P_1588)); /* 1588 eth protocol type */ + else + IXGBE_WRITE_REG(hw, IXGBE_ETQF(3), 0); + +#define PTP_PORT 319 + /* L4 Queue Filter[3]: filter by destination port and protocol */ + if (is_l4) { + u32 ftqf = (IXGBE_FTQF_PROTOCOL_UDP /* UDP */ + | IXGBE_FTQF_POOL_MASK_EN /* Pool not compared */ + | IXGBE_FTQF_QUEUE_ENABLE); + + ftqf |= ((IXGBE_FTQF_PROTOCOL_COMP_MASK /* protocol check */ + & IXGBE_FTQF_DEST_PORT_MASK /* dest check */ + & IXGBE_FTQF_SOURCE_PORT_MASK) /* source check */ + << IXGBE_FTQF_5TUPLE_MASK_SHIFT); + + IXGBE_WRITE_REG(hw, IXGBE_L34T_IMIR(3), + (3 << IXGBE_IMIR_RX_QUEUE_SHIFT_82599 | + IXGBE_IMIR_SIZE_BP_82599)); + + /* enable port check */ + IXGBE_WRITE_REG(hw, IXGBE_SDPQF(3), + (htons(PTP_PORT) | + htons(PTP_PORT) << 16)); + + IXGBE_WRITE_REG(hw, IXGBE_FTQF(3), ftqf); + + tsync_rx_mtrl |= PTP_PORT << 16; + } else { + IXGBE_WRITE_REG(hw, IXGBE_FTQF(3), 0); + } + + /* enable/disable TX */ + regval = IXGBE_READ_REG(hw, IXGBE_TSYNCTXCTL); + regval &= ~IXGBE_TSYNCTXCTL_ENABLED; + regval |= tsync_tx_ctl; + IXGBE_WRITE_REG(hw, IXGBE_TSYNCTXCTL, regval); + + /* enable/disable RX */ + regval = IXGBE_READ_REG(hw, IXGBE_TSYNCRXCTL); + regval &= ~(IXGBE_TSYNCRXCTL_ENABLED | IXGBE_TSYNCRXCTL_TYPE_MASK); + regval |= tsync_rx_ctl; + IXGBE_WRITE_REG(hw, IXGBE_TSYNCRXCTL, regval); + + /* define which PTP packets are time stamped */ + IXGBE_WRITE_REG(hw, IXGBE_RXMTRL, tsync_rx_mtrl); + + IXGBE_WRITE_FLUSH(hw); + + /* clear TX/RX time stamp registers, just to be sure */ + regval = IXGBE_READ_REG(hw, IXGBE_TXSTMPH); + regval = IXGBE_READ_REG(hw, IXGBE_RXSTMPH); + + return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? + -EFAULT : 0; +} + +/** + * ixgbe_ptp_start_cyclecounter - create the cycle counter from hw + * @adapter - pointer to the adapter structure + * + * this function initializes the timecounter and cyclecounter + * structures for use in generated a ns counter from the arbitrary + * fixed point cycles registers in the hardware. + * + * A change in link speed impacts the frequency of the DMA clock on + * the device, which is used to generate the cycle counter + * registers. Therefor this function is called whenever the link speed + * changes. + * + * This function also turns on the SDP pin for clock out feature (X540 + * only), because this is where the shift is first calculated. + */ +void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + u32 incval = 0; + u32 shift = 0; + u32 cycle_speed; + unsigned long flags; + + /** + * Determine what speed we need to set the cyclecounter + * for. It should be different for 100Mb, 1Gb, and 10Gb. Treat + * unknown speeds as 10Gb. (Hence why we can't just copy the + * link_speed. + */ + switch (adapter->link_speed) { + case IXGBE_LINK_SPEED_100_FULL: + case IXGBE_LINK_SPEED_1GB_FULL: + case IXGBE_LINK_SPEED_10GB_FULL: + cycle_speed = adapter->link_speed; + break; + default: + /* cycle speed should be 10Gb when there is no link */ + cycle_speed = IXGBE_LINK_SPEED_10GB_FULL; + break; + } + + /* Bail if the cycle speed didn't change */ + if (adapter->cycle_speed == cycle_speed) + return; + + /* disable the SDP clock out */ + ixgbe_ptp_disable_sdp(hw); + + /** + * Scale the NIC cycle counter by a large factor so that + * relatively small corrections to the frequency can be added + * or subtracted. The drawbacks of a large factor include + * (a) the clock register overflows more quickly, (b) the cycle + * counter structure must be able to convert the systime value + * to nanoseconds using only a multiplier and a right-shift, + * and (c) the value must fit within the timinca register space + * => math based on internal DMA clock rate and available bits + */ + switch (cycle_speed) { + case IXGBE_LINK_SPEED_100_FULL: + incval = IXGBE_INCVAL_100; + shift = IXGBE_INCVAL_SHIFT_100; + break; + case IXGBE_LINK_SPEED_1GB_FULL: + incval = IXGBE_INCVAL_1GB; + shift = IXGBE_INCVAL_SHIFT_1GB; + break; + case IXGBE_LINK_SPEED_10GB_FULL: + incval = IXGBE_INCVAL_10GB; + shift = IXGBE_INCVAL_SHIFT_10GB; + break; + } + + /** + * Modify the calculated values to fit within the correct + * number of bits specified by the hardware. The 82599 doesn't + * have the same space as the X540, so bitshift the calculated + * values to fit. + */ + switch (hw->mac.type) { + case ixgbe_mac_X540: + IXGBE_WRITE_REG(hw, IXGBE_TIMINCA, incval); + break; + case ixgbe_mac_82599EB: + incval >>= IXGBE_INCVAL_SHIFT_82599; + shift -= IXGBE_INCVAL_SHIFT_82599; + IXGBE_WRITE_REG(hw, IXGBE_TIMINCA, + (1 << IXGBE_INCPER_SHIFT_82599) | + incval); + break; + default: + /* other devices aren't supported */ + return; + } + + /* reset the system time registers */ + IXGBE_WRITE_REG(hw, IXGBE_SYSTIML, 0x00000000); + IXGBE_WRITE_REG(hw, IXGBE_SYSTIMH, 0x00000000); + IXGBE_WRITE_FLUSH(hw); + + /* now that the shift has been calculated and the systime + * registers reset, (re-)enable the Clock out feature*/ + ixgbe_ptp_enable_sdp(hw, shift); + + /* store the new cycle speed */ + adapter->cycle_speed = cycle_speed; + + ACCESS_ONCE(adapter->base_incval) = incval; + smp_mb(); + + /* grab the ptp lock */ + spin_lock_irqsave(&adapter->tmreg_lock, flags); + + memset(&adapter->cc, 0, sizeof(adapter->cc)); + adapter->cc.read = ixgbe_ptp_read; + adapter->cc.mask = CLOCKSOURCE_MASK(64); + adapter->cc.shift = shift; + adapter->cc.mult = 1; + + /* reset the ns time counter */ + timecounter_init(&adapter->tc, &adapter->cc, + ktime_to_ns(ktime_get_real())); + + spin_unlock_irqrestore(&adapter->tmreg_lock, flags); +} + +/** + * ixgbe_ptp_init + * @adapter - the ixgbe private adapter structure + * + * This function performs the required steps for enabling ptp + * support. If ptp support has already been loaded it simply calls the + * cyclecounter init routine and exits. + */ +void ixgbe_ptp_init(struct ixgbe_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + + switch (adapter->hw.mac.type) { + case ixgbe_mac_X540: + snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr); + adapter->ptp_caps.owner = THIS_MODULE; + adapter->ptp_caps.max_adj = 250000000; + adapter->ptp_caps.n_alarm = 0; + adapter->ptp_caps.n_ext_ts = 0; + adapter->ptp_caps.n_per_out = 0; + adapter->ptp_caps.pps = 1; + adapter->ptp_caps.adjfreq = ixgbe_ptp_adjfreq; + adapter->ptp_caps.adjtime = ixgbe_ptp_adjtime; + adapter->ptp_caps.gettime = ixgbe_ptp_gettime; + adapter->ptp_caps.settime = ixgbe_ptp_settime; + adapter->ptp_caps.enable = ixgbe_ptp_enable; + break; + case ixgbe_mac_82599EB: + snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr); + adapter->ptp_caps.owner = THIS_MODULE; + adapter->ptp_caps.max_adj = 250000000; + adapter->ptp_caps.n_alarm = 0; + adapter->ptp_caps.n_ext_ts = 0; + adapter->ptp_caps.n_per_out = 0; + adapter->ptp_caps.pps = 0; + adapter->ptp_caps.adjfreq = ixgbe_ptp_adjfreq; + adapter->ptp_caps.adjtime = ixgbe_ptp_adjtime; + adapter->ptp_caps.gettime = ixgbe_ptp_gettime; + adapter->ptp_caps.settime = ixgbe_ptp_settime; + adapter->ptp_caps.enable = ixgbe_ptp_enable; + break; + default: + adapter->ptp_clock = NULL; + return; + } + + spin_lock_init(&adapter->tmreg_lock); + + ixgbe_ptp_start_cyclecounter(adapter); + + /* (Re)start the overflow check */ + adapter->flags2 |= IXGBE_FLAG2_OVERFLOW_CHECK_ENABLED; + + adapter->ptp_clock = ptp_clock_register(&adapter->ptp_caps); + if (IS_ERR(adapter->ptp_clock)) { + adapter->ptp_clock = NULL; + e_dev_err("ptp_clock_register failed\n"); + } else + e_dev_info("registered PHC device on %s\n", netdev->name); + + return; +} + +/** + * ixgbe_ptp_stop - disable ptp device and stop the overflow check + * @adapter: pointer to adapter struct + * + * this function stops the ptp support, and cancels the delayed work. + */ +void ixgbe_ptp_stop(struct ixgbe_adapter *adapter) +{ + ixgbe_ptp_disable_sdp(&adapter->hw); + + /* stop the overflow check task */ + adapter->flags2 &= ~IXGBE_FLAG2_OVERFLOW_CHECK_ENABLED; + + if (adapter->ptp_clock) { + ptp_clock_unregister(adapter->ptp_clock); + adapter->ptp_clock = NULL; + e_dev_info("removed PHC on %s\n", + adapter->netdev->name); + } +} diff --git a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c index 88a58cb08569..2d971d18696e 100644 --- a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c +++ b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c @@ -544,13 +544,18 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf) retval = ixgbe_read_mbx(hw, msgbuf, mbx_size, vf); - if (retval) + if (retval) { pr_err("Error receiving message from VF\n"); + return retval; + } /* this is a message we already processed, do nothing */ if (msgbuf[0] & (IXGBE_VT_MSGTYPE_ACK | IXGBE_VT_MSGTYPE_NACK)) return retval; + /* flush the ack before we write any messages back */ + IXGBE_WRITE_FLUSH(hw); + /* * until the vf completes a virtual function reset it should not be * allowed to start any configuration. @@ -637,6 +642,12 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf) case IXGBE_VF_SET_MACVLAN: index = (msgbuf[0] & IXGBE_VT_MSGINFO_MASK) >> IXGBE_VT_MSGINFO_SHIFT; + if (adapter->vfinfo[vf].pf_set_mac && index > 0) { + e_warn(drv, "VF %d requested MACVLAN filter but is " + "administratively denied\n", vf); + retval = -1; + break; + } /* * If the VF is allowed to set MAC filters then turn off * anti-spoofing to avoid false positives. An index diff --git a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c new file mode 100644 index 000000000000..1d80b1cefa6a --- /dev/null +++ b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c @@ -0,0 +1,245 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2012 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, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + 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 "ixgbe.h" +#include "ixgbe_common.h" +#include "ixgbe_type.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_IXGBE_HWMON +/* hwmon callback functions */ +static ssize_t ixgbe_hwmon_show_location(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hwmon_attr *ixgbe_attr = container_of(attr, struct hwmon_attr, + dev_attr); + return sprintf(buf, "loc%u\n", + ixgbe_attr->sensor->location); +} + +static ssize_t ixgbe_hwmon_show_temp(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hwmon_attr *ixgbe_attr = container_of(attr, struct hwmon_attr, + dev_attr); + unsigned int value; + + /* reset the temp field */ + ixgbe_attr->hw->mac.ops.get_thermal_sensor_data(ixgbe_attr->hw); + + value = ixgbe_attr->sensor->temp; + + /* display millidegree */ + value *= 1000; + + return sprintf(buf, "%u\n", value); +} + +static ssize_t ixgbe_hwmon_show_cautionthresh(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hwmon_attr *ixgbe_attr = container_of(attr, struct hwmon_attr, + dev_attr); + unsigned int value = ixgbe_attr->sensor->caution_thresh; + + /* display millidegree */ + value *= 1000; + + return sprintf(buf, "%u\n", value); +} + +static ssize_t ixgbe_hwmon_show_maxopthresh(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hwmon_attr *ixgbe_attr = container_of(attr, struct hwmon_attr, + dev_attr); + unsigned int value = ixgbe_attr->sensor->max_op_thresh; + + /* display millidegree */ + value *= 1000; + + return sprintf(buf, "%u\n", value); +} + +/* + * ixgbe_add_hwmon_attr - Create hwmon attr table for a hwmon sysfs file. + * @ adapter: pointer to the adapter structure + * @ offset: offset in the eeprom sensor data table + * @ type: type of sensor data to display + * + * For each file we want in hwmon's sysfs interface we need a device_attribute + * This is included in our hwmon_attr struct that contains the references to + * the data structures we need to get the data to display. + */ +static int ixgbe_add_hwmon_attr(struct ixgbe_adapter *adapter, + unsigned int offset, int type) { + int rc; + unsigned int n_attr; + struct hwmon_attr *ixgbe_attr; + + n_attr = adapter->ixgbe_hwmon_buff.n_hwmon; + ixgbe_attr = &adapter->ixgbe_hwmon_buff.hwmon_list[n_attr]; + + switch (type) { + case IXGBE_HWMON_TYPE_LOC: + ixgbe_attr->dev_attr.show = ixgbe_hwmon_show_location; + snprintf(ixgbe_attr->name, sizeof(ixgbe_attr->name), + "temp%u_label", offset); + break; + case IXGBE_HWMON_TYPE_TEMP: + ixgbe_attr->dev_attr.show = ixgbe_hwmon_show_temp; + snprintf(ixgbe_attr->name, sizeof(ixgbe_attr->name), + "temp%u_input", offset); + break; + case IXGBE_HWMON_TYPE_CAUTION: + ixgbe_attr->dev_attr.show = ixgbe_hwmon_show_cautionthresh; + snprintf(ixgbe_attr->name, sizeof(ixgbe_attr->name), + "temp%u_max", offset); + break; + case IXGBE_HWMON_TYPE_MAX: + ixgbe_attr->dev_attr.show = ixgbe_hwmon_show_maxopthresh; + snprintf(ixgbe_attr->name, sizeof(ixgbe_attr->name), + "temp%u_crit", offset); + break; + default: + rc = -EPERM; + return rc; + } + + /* These always the same regardless of type */ + ixgbe_attr->sensor = + &adapter->hw.mac.thermal_sensor_data.sensor[offset]; + ixgbe_attr->hw = &adapter->hw; + ixgbe_attr->dev_attr.store = NULL; + ixgbe_attr->dev_attr.attr.mode = S_IRUGO; + ixgbe_attr->dev_attr.attr.name = ixgbe_attr->name; + + rc = device_create_file(&adapter->pdev->dev, + &ixgbe_attr->dev_attr); + + if (rc == 0) + ++adapter->ixgbe_hwmon_buff.n_hwmon; + + return rc; +} + +static void ixgbe_sysfs_del_adapter(struct ixgbe_adapter *adapter) +{ + int i; + + if (adapter == NULL) + return; + + for (i = 0; i < adapter->ixgbe_hwmon_buff.n_hwmon; i++) { + device_remove_file(&adapter->pdev->dev, + &adapter->ixgbe_hwmon_buff.hwmon_list[i].dev_attr); + } + + kfree(adapter->ixgbe_hwmon_buff.hwmon_list); + + if (adapter->ixgbe_hwmon_buff.device) + hwmon_device_unregister(adapter->ixgbe_hwmon_buff.device); +} + +/* called from ixgbe_main.c */ +void ixgbe_sysfs_exit(struct ixgbe_adapter *adapter) +{ + ixgbe_sysfs_del_adapter(adapter); +} + +/* called from ixgbe_main.c */ +int ixgbe_sysfs_init(struct ixgbe_adapter *adapter) +{ + struct hwmon_buff *ixgbe_hwmon = &adapter->ixgbe_hwmon_buff; + unsigned int i; + int n_attrs; + int rc = 0; + + /* If this method isn't defined we don't support thermals */ + if (adapter->hw.mac.ops.init_thermal_sensor_thresh == NULL) { + goto exit; + } + + /* Don't create thermal hwmon interface if no sensors present */ + if (adapter->hw.mac.ops.init_thermal_sensor_thresh(&adapter->hw)) + goto exit; + + /* + * Allocation space for max attributs + * max num sensors * values (loc, temp, max, caution) + */ + n_attrs = IXGBE_MAX_SENSORS * 4; + ixgbe_hwmon->hwmon_list = kcalloc(n_attrs, sizeof(struct hwmon_attr), + GFP_KERNEL); + if (!ixgbe_hwmon->hwmon_list) { + rc = -ENOMEM; + goto err; + } + + ixgbe_hwmon->device = hwmon_device_register(&adapter->pdev->dev); + if (IS_ERR(ixgbe_hwmon->device)) { + rc = PTR_ERR(ixgbe_hwmon->device); + goto err; + } + + for (i = 0; i < IXGBE_MAX_SENSORS; i++) { + /* + * Only create hwmon sysfs entries for sensors that have + * meaningful data for. + */ + if (adapter->hw.mac.thermal_sensor_data.sensor[i].location == 0) + continue; + + /* Bail if any hwmon attr struct fails to initialize */ + rc = ixgbe_add_hwmon_attr(adapter, i, IXGBE_HWMON_TYPE_CAUTION); + rc |= ixgbe_add_hwmon_attr(adapter, i, IXGBE_HWMON_TYPE_LOC); + rc |= ixgbe_add_hwmon_attr(adapter, i, IXGBE_HWMON_TYPE_TEMP); + rc |= ixgbe_add_hwmon_attr(adapter, i, IXGBE_HWMON_TYPE_MAX); + if (rc) + goto err; + } + + goto exit; + +err: + ixgbe_sysfs_del_adapter(adapter); +exit: + return rc; +} +#endif /* CONFIG_IXGBE_HWMON */ + diff --git a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index 8636e8344fc9..204848d2448c 100644 --- a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -110,6 +110,28 @@ #define IXGBE_I2C_CLK_OUT 0x00000002 #define IXGBE_I2C_DATA_IN 0x00000004 #define IXGBE_I2C_DATA_OUT 0x00000008 +#define IXGBE_I2C_CLOCK_STRETCHING_TIMEOUT 500 + +#define IXGBE_I2C_THERMAL_SENSOR_ADDR 0xF8 +#define IXGBE_EMC_INTERNAL_DATA 0x00 +#define IXGBE_EMC_INTERNAL_THERM_LIMIT 0x20 +#define IXGBE_EMC_DIODE1_DATA 0x01 +#define IXGBE_EMC_DIODE1_THERM_LIMIT 0x19 +#define IXGBE_EMC_DIODE2_DATA 0x23 +#define IXGBE_EMC_DIODE2_THERM_LIMIT 0x1A + +#define IXGBE_MAX_SENSORS 3 + +struct ixgbe_thermal_diode_data { + u8 location; + u8 temp; + u8 caution_thresh; + u8 max_op_thresh; +}; + +struct ixgbe_thermal_sensor_data { + struct ixgbe_thermal_diode_data sensor[IXGBE_MAX_SENSORS]; +}; /* Interrupt Registers */ #define IXGBE_EICR 0x00800 @@ -802,6 +824,8 @@ #define IXGBE_TRGTTIMH0 0x08C28 /* Target Time Register 0 High - RW */ #define IXGBE_TRGTTIML1 0x08C2C /* Target Time Register 1 Low - RW */ #define IXGBE_TRGTTIMH1 0x08C30 /* Target Time Register 1 High - RW */ +#define IXGBE_CLKTIML 0x08C34 /* Clock Out Time Register Low - RW */ +#define IXGBE_CLKTIMH 0x08C38 /* Clock Out Time Register High - RW */ #define IXGBE_FREQOUT0 0x08C34 /* Frequency Out 0 Control register - RW */ #define IXGBE_FREQOUT1 0x08C38 /* Frequency Out 1 Control register - RW */ #define IXGBE_AUXSTMPL0 0x08C3C /* Auxiliary Time Stamp 0 register Low - RO */ @@ -1287,6 +1311,7 @@ enum { #define IXGBE_EICR_LINKSEC 0x00200000 /* PN Threshold */ #define IXGBE_EICR_MNG 0x00400000 /* Manageability Event Interrupt */ #define IXGBE_EICR_TS 0x00800000 /* Thermal Sensor Event */ +#define IXGBE_EICR_TIMESYNC 0x01000000 /* Timesync Event */ #define IXGBE_EICR_GPI_SDP0 0x01000000 /* Gen Purpose Interrupt on SDP0 */ #define IXGBE_EICR_GPI_SDP1 0x02000000 /* Gen Purpose Interrupt on SDP1 */ #define IXGBE_EICR_GPI_SDP2 0x04000000 /* Gen Purpose Interrupt on SDP2 */ @@ -1304,6 +1329,7 @@ enum { #define IXGBE_EICS_MAILBOX IXGBE_EICR_MAILBOX /* VF to PF Mailbox Int */ #define IXGBE_EICS_LSC IXGBE_EICR_LSC /* Link Status Change */ #define IXGBE_EICS_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */ +#define IXGBE_EICS_TIMESYNC IXGBE_EICR_TIMESYNC /* Timesync Event */ #define IXGBE_EICS_GPI_SDP0 IXGBE_EICR_GPI_SDP0 /* SDP0 Gen Purpose Int */ #define IXGBE_EICS_GPI_SDP1 IXGBE_EICR_GPI_SDP1 /* SDP1 Gen Purpose Int */ #define IXGBE_EICS_GPI_SDP2 IXGBE_EICR_GPI_SDP2 /* SDP2 Gen Purpose Int */ @@ -1322,6 +1348,7 @@ enum { #define IXGBE_EIMS_LSC IXGBE_EICR_LSC /* Link Status Change */ #define IXGBE_EIMS_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */ #define IXGBE_EIMS_TS IXGBE_EICR_TS /* Thermel Sensor Event */ +#define IXGBE_EIMS_TIMESYNC IXGBE_EICR_TIMESYNC /* Timesync Event */ #define IXGBE_EIMS_GPI_SDP0 IXGBE_EICR_GPI_SDP0 /* SDP0 Gen Purpose Int */ #define IXGBE_EIMS_GPI_SDP1 IXGBE_EICR_GPI_SDP1 /* SDP1 Gen Purpose Int */ #define IXGBE_EIMS_GPI_SDP2 IXGBE_EICR_GPI_SDP2 /* SDP2 Gen Purpose Int */ @@ -1339,6 +1366,7 @@ enum { #define IXGBE_EIMC_MAILBOX IXGBE_EICR_MAILBOX /* VF to PF Mailbox Int */ #define IXGBE_EIMC_LSC IXGBE_EICR_LSC /* Link Status Change */ #define IXGBE_EIMC_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */ +#define IXGBE_EIMC_TIMESYNC IXGBE_EICR_TIMESYNC /* Timesync Event */ #define IXGBE_EIMC_GPI_SDP0 IXGBE_EICR_GPI_SDP0 /* SDP0 Gen Purpose Int */ #define IXGBE_EIMC_GPI_SDP1 IXGBE_EICR_GPI_SDP1 /* SDP1 Gen Purpose Int */ #define IXGBE_EIMC_GPI_SDP2 IXGBE_EICR_GPI_SDP2 /* SDP2 Gen Purpose Int */ @@ -1479,8 +1507,10 @@ enum { #define IXGBE_ESDP_SDP4 0x00000010 /* SDP4 Data Value */ #define IXGBE_ESDP_SDP5 0x00000020 /* SDP5 Data Value */ #define IXGBE_ESDP_SDP6 0x00000040 /* SDP6 Data Value */ +#define IXGBE_ESDP_SDP0_DIR 0x00000100 /* SDP0 IO direction */ #define IXGBE_ESDP_SDP4_DIR 0x00000004 /* SDP4 IO direction */ #define IXGBE_ESDP_SDP5_DIR 0x00002000 /* SDP5 IO direction */ +#define IXGBE_ESDP_SDP0_NATIVE 0x00010000 /* SDP0 Native Function */ /* LEDCTL Bit Masks */ #define IXGBE_LED_IVRT_BASE 0x00000040 @@ -1677,11 +1707,29 @@ enum { #define IXGBE_PBANUM0_PTR 0x15 #define IXGBE_PBANUM1_PTR 0x16 #define IXGBE_FREE_SPACE_PTR 0X3E + +/* External Thermal Sensor Config */ +#define IXGBE_ETS_CFG 0x26 +#define IXGBE_ETS_LTHRES_DELTA_MASK 0x07C0 +#define IXGBE_ETS_LTHRES_DELTA_SHIFT 6 +#define IXGBE_ETS_TYPE_MASK 0x0038 +#define IXGBE_ETS_TYPE_SHIFT 3 +#define IXGBE_ETS_TYPE_EMC 0x000 +#define IXGBE_ETS_TYPE_EMC_SHIFTED 0x000 +#define IXGBE_ETS_NUM_SENSORS_MASK 0x0007 +#define IXGBE_ETS_DATA_LOC_MASK 0x3C00 +#define IXGBE_ETS_DATA_LOC_SHIFT 10 +#define IXGBE_ETS_DATA_INDEX_MASK 0x0300 +#define IXGBE_ETS_DATA_INDEX_SHIFT 8 +#define IXGBE_ETS_DATA_HTHRESH_MASK 0x00FF + #define IXGBE_SAN_MAC_ADDR_PTR 0x28 #define IXGBE_DEVICE_CAPS 0x2C #define IXGBE_SERIAL_NUMBER_MAC_ADDR 0x11 #define IXGBE_PCIE_MSIX_82599_CAPS 0x72 +#define IXGBE_MAX_MSIX_VECTORS_82599 0x40 #define IXGBE_PCIE_MSIX_82598_CAPS 0x62 +#define IXGBE_MAX_MSIX_VECTORS_82598 0x13 /* MSI-X capability fields masks */ #define IXGBE_PCIE_MSIX_TBL_SZ_MASK 0x7FF @@ -1839,6 +1887,40 @@ enum { #define IXGBE_RXDCTL_RLPML_EN 0x00008000 #define IXGBE_RXDCTL_VME 0x40000000 /* VLAN mode enable */ +#define IXGBE_TSAUXC_EN_CLK 0x00000004 +#define IXGBE_TSAUXC_SYNCLK 0x00000008 +#define IXGBE_TSAUXC_SDP0_INT 0x00000040 + +#define IXGBE_TSYNCTXCTL_VALID 0x00000001 /* Tx timestamp valid */ +#define IXGBE_TSYNCTXCTL_ENABLED 0x00000010 /* Tx timestamping enabled */ + +#define IXGBE_TSYNCRXCTL_VALID 0x00000001 /* Rx timestamp valid */ +#define IXGBE_TSYNCRXCTL_TYPE_MASK 0x0000000E /* Rx type mask */ +#define IXGBE_TSYNCRXCTL_TYPE_L2_V2 0x00 +#define IXGBE_TSYNCRXCTL_TYPE_L4_V1 0x02 +#define IXGBE_TSYNCRXCTL_TYPE_L2_L4_V2 0x04 +#define IXGBE_TSYNCRXCTL_TYPE_EVENT_V2 0x0A +#define IXGBE_TSYNCRXCTL_ENABLED 0x00000010 /* Rx Timestamping enabled */ + +#define IXGBE_RXMTRL_V1_CTRLT_MASK 0x000000FF +#define IXGBE_RXMTRL_V1_SYNC_MSG 0x00 +#define IXGBE_RXMTRL_V1_DELAY_REQ_MSG 0x01 +#define IXGBE_RXMTRL_V1_FOLLOWUP_MSG 0x02 +#define IXGBE_RXMTRL_V1_DELAY_RESP_MSG 0x03 +#define IXGBE_RXMTRL_V1_MGMT_MSG 0x04 + +#define IXGBE_RXMTRL_V2_MSGID_MASK 0x0000FF00 +#define IXGBE_RXMTRL_V2_SYNC_MSG 0x0000 +#define IXGBE_RXMTRL_V2_DELAY_REQ_MSG 0x0100 +#define IXGBE_RXMTRL_V2_PDELAY_REQ_MSG 0x0200 +#define IXGBE_RXMTRL_V2_PDELAY_RESP_MSG 0x0300 +#define IXGBE_RXMTRL_V2_FOLLOWUP_MSG 0x0800 +#define IXGBE_RXMTRL_V2_DELAY_RESP_MSG 0x0900 +#define IXGBE_RXMTRL_V2_PDELAY_FOLLOWUP_MSG 0x0A00 +#define IXGBE_RXMTRL_V2_ANNOUNCE_MSG 0x0B00 +#define IXGBE_RXMTRL_V2_SIGNALING_MSG 0x0C00 +#define IXGBE_RXMTRL_V2_MGMT_MSG 0x0D00 + #define IXGBE_FCTRL_SBP 0x00000002 /* Store Bad Packet */ #define IXGBE_FCTRL_MPE 0x00000100 /* Multicast Promiscuous Ena*/ #define IXGBE_FCTRL_UPE 0x00000200 /* Unicast Promiscuous Ena */ @@ -1852,7 +1934,7 @@ enum { #define IXGBE_MFLCN_DPF 0x00000002 /* Discard Pause Frame */ #define IXGBE_MFLCN_RPFCE 0x00000004 /* Receive Priority FC Enable */ #define IXGBE_MFLCN_RFCE 0x00000008 /* Receive FC Enable */ -#define IXGBE_MFLCN_RPFCE_MASK 0x00000FF0 /* Receive FC Mask */ +#define IXGBE_MFLCN_RPFCE_MASK 0x00000FF4 /* Receive FC Mask */ #define IXGBE_MFLCN_RPFCE_SHIFT 4 @@ -1968,6 +2050,7 @@ enum { #define IXGBE_RXDADV_STAT_FCSTAT_NODDP 0x00000010 /* 01: Ctxt w/o DDP */ #define IXGBE_RXDADV_STAT_FCSTAT_FCPRSP 0x00000020 /* 10: Recv. FCP_RSP */ #define IXGBE_RXDADV_STAT_FCSTAT_DDP 0x00000030 /* 11: Ctxt w/ DDP */ +#define IXGBE_RXDADV_STAT_TS 0x00010000 /* IEEE 1588 Time Stamp */ /* PSRTYPE bit definitions */ #define IXGBE_PSRTYPE_TCPHDR 0x00000010 @@ -2245,6 +2328,7 @@ struct ixgbe_adv_tx_context_desc { /* Adv Transmit Descriptor Config Masks */ #define IXGBE_ADVTXD_DTALEN_MASK 0x0000FFFF /* Data buf length(bytes) */ #define IXGBE_ADVTXD_MAC_LINKSEC 0x00040000 /* Insert LinkSec */ +#define IXGBE_ADVTXD_MAC_TSTAMP 0x00080000 /* IEEE 1588 Time Stamp */ #define IXGBE_ADVTXD_IPSEC_SA_INDEX_MASK 0x000003FF /* IPSec SA index */ #define IXGBE_ADVTXD_IPSEC_ESP_LEN_MASK 0x000001FF /* IPSec ESP length */ #define IXGBE_ADVTXD_DTYP_MASK 0x00F00000 /* DTYP mask */ @@ -2533,9 +2617,6 @@ enum ixgbe_fc_mode { ixgbe_fc_rx_pause, ixgbe_fc_tx_pause, ixgbe_fc_full, -#ifdef CONFIG_DCB - ixgbe_fc_pfc, -#endif ixgbe_fc_default }; @@ -2768,10 +2849,12 @@ struct ixgbe_mac_operations { void (*set_vlan_anti_spoofing)(struct ixgbe_hw *, bool, int); /* Flow Control */ - s32 (*fc_enable)(struct ixgbe_hw *, s32); + s32 (*fc_enable)(struct ixgbe_hw *); /* Manageability interface */ s32 (*set_fw_drv_ver)(struct ixgbe_hw *, u8, u8, u8, u8); + s32 (*get_thermal_sensor_data)(struct ixgbe_hw *); + s32 (*init_thermal_sensor_thresh)(struct ixgbe_hw *hw); }; struct ixgbe_phy_operations { @@ -2813,6 +2896,7 @@ struct ixgbe_mac_info { u16 wwnn_prefix; /* prefix for World Wide Port Name (WWPN) */ u16 wwpn_prefix; + u16 max_msix_vectors; #define IXGBE_MAX_MTA 128 u32 mta_shadow[IXGBE_MAX_MTA]; s32 mc_filter_type; @@ -2823,12 +2907,12 @@ struct ixgbe_mac_info { u32 rx_pb_size; u32 max_tx_queues; u32 max_rx_queues; - u32 max_msix_vectors; u32 orig_autoc; u32 orig_autoc2; bool orig_link_settings_stored; bool autotry_restart; u8 flags; + struct ixgbe_thermal_sensor_data thermal_sensor_data; }; struct ixgbe_phy_info { @@ -2938,7 +3022,6 @@ struct ixgbe_info { #define IXGBE_ERR_OVERTEMP -26 #define IXGBE_ERR_FC_NOT_NEGOTIATED -27 #define IXGBE_ERR_FC_NOT_SUPPORTED -28 -#define IXGBE_ERR_FLOW_CONTROL -29 #define IXGBE_ERR_SFP_SETUP_NOT_COMPLETE -30 #define IXGBE_ERR_PBA_SECTION -31 #define IXGBE_ERR_INVALID_ARGUMENT -32 diff --git a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c index 97a991403bbd..f90ec078ece2 100644 --- a/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c +++ b/trunk/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c @@ -849,6 +849,8 @@ static struct ixgbe_mac_operations mac_ops_X540 = { .release_swfw_sync = &ixgbe_release_swfw_sync_X540, .disable_rx_buff = &ixgbe_disable_rx_buff_generic, .enable_rx_buff = &ixgbe_enable_rx_buff_generic, + .get_thermal_sensor_data = NULL, + .init_thermal_sensor_thresh = NULL, }; static struct ixgbe_eeprom_operations eeprom_ops_X540 = { diff --git a/trunk/drivers/net/ethernet/intel/ixgbevf/defines.h b/trunk/drivers/net/ethernet/intel/ixgbevf/defines.h index 947b5c830735..e09a6cc633bb 100644 --- a/trunk/drivers/net/ethernet/intel/ixgbevf/defines.h +++ b/trunk/drivers/net/ethernet/intel/ixgbevf/defines.h @@ -40,6 +40,7 @@ typedef u32 ixgbe_link_speed; #define IXGBE_LINK_SPEED_1GB_FULL 0x0020 #define IXGBE_LINK_SPEED_10GB_FULL 0x0080 +#define IXGBE_LINK_SPEED_100_FULL 0x0008 #define IXGBE_CTRL_RST 0x04000000 /* Reset (SW) */ #define IXGBE_RXDCTL_ENABLE 0x02000000 /* Enable specific Rx Queue */ @@ -48,6 +49,7 @@ typedef u32 ixgbe_link_speed; #define IXGBE_LINKS_SPEED_82599 0x30000000 #define IXGBE_LINKS_SPEED_10G_82599 0x30000000 #define IXGBE_LINKS_SPEED_1G_82599 0x20000000 +#define IXGBE_LINKS_SPEED_100_82599 0x10000000 /* Number of Transmit and Receive Descriptors must be a multiple of 8 */ #define IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE 8 diff --git a/trunk/drivers/net/ethernet/intel/ixgbevf/ethtool.c b/trunk/drivers/net/ethernet/intel/ixgbevf/ethtool.c index 2bfe0d1d7958..e8dddf572d38 100644 --- a/trunk/drivers/net/ethernet/intel/ixgbevf/ethtool.c +++ b/trunk/drivers/net/ethernet/intel/ixgbevf/ethtool.c @@ -107,10 +107,20 @@ static int ixgbevf_get_settings(struct net_device *netdev, hw->mac.ops.check_link(hw, &link_speed, &link_up, false); if (link_up) { - ethtool_cmd_speed_set( - ecmd, - (link_speed == IXGBE_LINK_SPEED_10GB_FULL) ? - SPEED_10000 : SPEED_1000); + __u32 speed = SPEED_10000; + switch (link_speed) { + case IXGBE_LINK_SPEED_10GB_FULL: + speed = SPEED_10000; + break; + case IXGBE_LINK_SPEED_1GB_FULL: + speed = SPEED_1000; + break; + case IXGBE_LINK_SPEED_100_FULL: + speed = SPEED_100; + break; + } + + ethtool_cmd_speed_set(ecmd, speed); ecmd->duplex = DUPLEX_FULL; } else { ethtool_cmd_speed_set(ecmd, -1); diff --git a/trunk/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h b/trunk/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h index dfed420a1bf6..0a1b99240d43 100644 --- a/trunk/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h +++ b/trunk/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h @@ -287,7 +287,7 @@ extern const struct ixgbe_mbx_operations ixgbevf_mbx_ops; extern const char ixgbevf_driver_name[]; extern const char ixgbevf_driver_version[]; -extern int ixgbevf_up(struct ixgbevf_adapter *adapter); +extern void ixgbevf_up(struct ixgbevf_adapter *adapter); extern void ixgbevf_down(struct ixgbevf_adapter *adapter); extern void ixgbevf_reinit_locked(struct ixgbevf_adapter *adapter); extern void ixgbevf_reset(struct ixgbevf_adapter *adapter); diff --git a/trunk/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/trunk/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 307611ae831d..f69ec4288b10 100644 --- a/trunk/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/trunk/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -57,7 +57,7 @@ const char ixgbevf_driver_name[] = "ixgbevf"; static const char ixgbevf_driver_string[] = "Intel(R) 10 Gigabit PCI Express Virtual Function Network Driver"; -#define DRV_VERSION "2.2.0-k" +#define DRV_VERSION "2.6.0-k" const char ixgbevf_driver_version[] = DRV_VERSION; static char ixgbevf_copyright[] = "Copyright (c) 2009 - 2012 Intel Corporation."; @@ -1608,13 +1608,14 @@ static void ixgbevf_init_last_counter_stats(struct ixgbevf_adapter *adapter) adapter->stats.base_vfmprc = adapter->stats.last_vfmprc; } -static int ixgbevf_up_complete(struct ixgbevf_adapter *adapter) +static void ixgbevf_up_complete(struct ixgbevf_adapter *adapter) { struct net_device *netdev = adapter->netdev; struct ixgbe_hw *hw = &adapter->hw; int i, j = 0; int num_rx_rings = adapter->num_rx_queues; u32 txdctl, rxdctl; + u32 msg[2]; for (i = 0; i < adapter->num_tx_queues; i++) { j = adapter->tx_ring[i].reg_idx; @@ -1653,6 +1654,10 @@ static int ixgbevf_up_complete(struct ixgbevf_adapter *adapter) hw->mac.ops.set_rar(hw, 0, hw->mac.perm_addr, 0); } + msg[0] = IXGBE_VF_SET_LPE; + msg[1] = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; + hw->mbx.ops.write_posted(hw, msg, 2); + clear_bit(__IXGBEVF_DOWN, &adapter->state); ixgbevf_napi_enable_all(adapter); @@ -1667,24 +1672,20 @@ static int ixgbevf_up_complete(struct ixgbevf_adapter *adapter) adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; adapter->link_check_timeout = jiffies; mod_timer(&adapter->watchdog_timer, jiffies); - return 0; } -int ixgbevf_up(struct ixgbevf_adapter *adapter) +void ixgbevf_up(struct ixgbevf_adapter *adapter) { - int err; struct ixgbe_hw *hw = &adapter->hw; ixgbevf_configure(adapter); - err = ixgbevf_up_complete(adapter); + ixgbevf_up_complete(adapter); /* clear any pending interrupts, may auto mask */ IXGBE_READ_REG(hw, IXGBE_VTEICR); ixgbevf_irq_enable(adapter, true, true); - - return err; } /** @@ -2673,9 +2674,7 @@ static int ixgbevf_open(struct net_device *netdev) */ ixgbevf_map_rings_to_vectors(adapter); - err = ixgbevf_up_complete(adapter); - if (err) - goto err_up; + ixgbevf_up_complete(adapter); /* clear any pending interrupts, may auto mask */ IXGBE_READ_REG(hw, IXGBE_VTEICR); @@ -2689,7 +2688,6 @@ static int ixgbevf_open(struct net_device *netdev) err_req_irq: ixgbevf_down(adapter); -err_up: ixgbevf_free_irq(adapter); err_setup_rx: ixgbevf_free_all_rx_resources(adapter); @@ -3196,9 +3194,11 @@ static int ixgbevf_change_mtu(struct net_device *netdev, int new_mtu) /* must set new MTU before calling down or up */ netdev->mtu = new_mtu; - msg[0] = IXGBE_VF_SET_LPE; - msg[1] = max_frame; - hw->mbx.ops.write_posted(hw, msg, 2); + if (!netif_running(netdev)) { + msg[0] = IXGBE_VF_SET_LPE; + msg[1] = max_frame; + hw->mbx.ops.write_posted(hw, msg, 2); + } if (netif_running(netdev)) ixgbevf_reinit_locked(adapter); diff --git a/trunk/drivers/net/ethernet/intel/ixgbevf/vf.c b/trunk/drivers/net/ethernet/intel/ixgbevf/vf.c index 74be7411242a..ec89b86f7ca4 100644 --- a/trunk/drivers/net/ethernet/intel/ixgbevf/vf.c +++ b/trunk/drivers/net/ethernet/intel/ixgbevf/vf.c @@ -404,11 +404,17 @@ static s32 ixgbevf_check_mac_link_vf(struct ixgbe_hw *hw, else *link_up = false; - if ((links_reg & IXGBE_LINKS_SPEED_82599) == - IXGBE_LINKS_SPEED_10G_82599) + switch (links_reg & IXGBE_LINKS_SPEED_82599) { + case IXGBE_LINKS_SPEED_10G_82599: *speed = IXGBE_LINK_SPEED_10GB_FULL; - else + break; + case IXGBE_LINKS_SPEED_1G_82599: *speed = IXGBE_LINK_SPEED_1GB_FULL; + break; + case IXGBE_LINKS_SPEED_100_82599: + *speed = IXGBE_LINK_SPEED_100_FULL; + break; + } return 0; } diff --git a/trunk/drivers/net/ethernet/marvell/mv643xx_eth.c b/trunk/drivers/net/ethernet/marvell/mv643xx_eth.c index 5e1ca0f05090..c8950da60e6b 100644 --- a/trunk/drivers/net/ethernet/marvell/mv643xx_eth.c +++ b/trunk/drivers/net/ethernet/marvell/mv643xx_eth.c @@ -1665,6 +1665,7 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops = { .get_strings = mv643xx_eth_get_strings, .get_ethtool_stats = mv643xx_eth_get_ethtool_stats, .get_sset_count = mv643xx_eth_get_sset_count, + .get_ts_info = ethtool_op_get_ts_info, }; diff --git a/trunk/drivers/net/ethernet/marvell/pxa168_eth.c b/trunk/drivers/net/ethernet/marvell/pxa168_eth.c index efec6b60b327..1db023b075a1 100644 --- a/trunk/drivers/net/ethernet/marvell/pxa168_eth.c +++ b/trunk/drivers/net/ethernet/marvell/pxa168_eth.c @@ -1456,6 +1456,7 @@ static const struct ethtool_ops pxa168_ethtool_ops = { .set_settings = pxa168_set_settings, .get_drvinfo = pxa168_get_drvinfo, .get_link = ethtool_op_get_link, + .get_ts_info = ethtool_op_get_ts_info, }; static const struct net_device_ops pxa168_eth_netdev_ops = { diff --git a/trunk/drivers/net/ethernet/marvell/sky2.c b/trunk/drivers/net/ethernet/marvell/sky2.c index 487a6c8bd4ec..cace36f2ab92 100644 --- a/trunk/drivers/net/ethernet/marvell/sky2.c +++ b/trunk/drivers/net/ethernet/marvell/sky2.c @@ -4825,14 +4825,14 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw) init_waitqueue_head(&hw->msi_wait); - sky2_write32(hw, B0_IMSK, Y2_IS_IRQ_SW); - err = request_irq(pdev->irq, sky2_test_intr, 0, DRV_NAME, hw); if (err) { dev_err(&pdev->dev, "cannot assign irq %d\n", pdev->irq); return err; } + sky2_write32(hw, B0_IMSK, Y2_IS_IRQ_SW); + sky2_write8(hw, B0_CTST, CS_ST_SW_IRQ); sky2_read8(hw, B0_CTST); diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/Kconfig b/trunk/drivers/net/ethernet/mellanox/mlx4/Kconfig index 1bb93531f1ba..5f027f95cc84 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/Kconfig +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/Kconfig @@ -11,6 +11,18 @@ config MLX4_EN This driver supports Mellanox Technologies ConnectX Ethernet devices. +config MLX4_EN_DCB + bool "Data Center Bridging (DCB) Support" + default y + depends on MLX4_EN && DCB + ---help--- + Say Y here if you want to use Data Center Bridging (DCB) in the + driver. + If set to N, will not be able to configure QoS and ratelimit attributes. + This flag is depended on the kernel's DCB support. + + If unsure, set to Y + config MLX4_CORE tristate depends on PCI diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/Makefile b/trunk/drivers/net/ethernet/mellanox/mlx4/Makefile index 4a40ab967eeb..293127d28b33 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/Makefile +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_MLX4_EN) += mlx4_en.o mlx4_en-y := en_main.o en_tx.o en_rx.o en_ethtool.o en_port.o en_cq.o \ en_resources.o en_netdev.o en_selftest.o +mlx4_en-$(CONFIG_MLX4_EN_DCB) += en_dcb_nl.o diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/alloc.c b/trunk/drivers/net/ethernet/mellanox/mlx4/alloc.c index 8be20e7ea3d1..06fef5b44f77 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/alloc.c +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/alloc.c @@ -124,9 +124,6 @@ void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt) spin_lock(&bitmap->lock); bitmap_clear(bitmap->table, obj, cnt); - bitmap->last = min(bitmap->last, obj); - bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top) - & bitmap->mask; bitmap->avail += cnt; spin_unlock(&bitmap->lock); } diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/cmd.c b/trunk/drivers/net/ethernet/mellanox/mlx4/cmd.c index 773c70ea3f62..1bcead1fa2f6 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -1254,7 +1254,6 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state; u32 reply; - u32 slave_status = 0; u8 is_going_down = 0; int i; @@ -1274,10 +1273,8 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, } /*check if we are in the middle of FLR process, if so return "retry" status to the slave*/ - if (MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd) { - slave_status = MLX4_DELAY_RESET_SLAVE; + if (MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd) goto inform_slave_state; - } /* write the version in the event field */ reply |= mlx4_comm_get_version(); @@ -1557,7 +1554,7 @@ int mlx4_multi_func_init(struct mlx4_dev *dev) return 0; err_resource: - mlx4_free_resource_tracker(dev); + mlx4_free_resource_tracker(dev, RES_TR_FREE_ALL); err_thread: flush_workqueue(priv->mfunc.master.comm_wq); destroy_workqueue(priv->mfunc.master.comm_wq); diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/en_cq.c b/trunk/drivers/net/ethernet/mellanox/mlx4/en_cq.c index 00b81272e314..908a460d8db6 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/en_cq.c +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/en_cq.c @@ -124,11 +124,7 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, cq->mcq.comp = cq->is_tx ? mlx4_en_tx_irq : mlx4_en_rx_irq; cq->mcq.event = mlx4_en_cq_event; - if (cq->is_tx) { - init_timer(&cq->timer); - cq->timer.function = mlx4_en_poll_tx_cq; - cq->timer.data = (unsigned long) cq; - } else { + if (!cq->is_tx) { netif_napi_add(cq->dev, &cq->napi, mlx4_en_poll_rx_cq, 64); napi_enable(&cq->napi); } @@ -151,16 +147,12 @@ void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) void mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) { - struct mlx4_en_dev *mdev = priv->mdev; - - if (cq->is_tx) - del_timer(&cq->timer); - else { + if (!cq->is_tx) { napi_disable(&cq->napi); netif_napi_del(&cq->napi); } - mlx4_cq_free(mdev->dev, &cq->mcq); + mlx4_cq_free(priv->mdev->dev, &cq->mcq); } /* Set rx cq moderation parameters */ diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c b/trunk/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c new file mode 100644 index 000000000000..5d36795877cb --- /dev/null +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2011 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * 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 + +#include "mlx4_en.h" + +static int mlx4_en_dcbnl_ieee_getets(struct net_device *dev, + struct ieee_ets *ets) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct ieee_ets *my_ets = &priv->ets; + + /* No IEEE PFC settings available */ + if (!my_ets) + return -EINVAL; + + ets->ets_cap = IEEE_8021QAZ_MAX_TCS; + ets->cbs = my_ets->cbs; + memcpy(ets->tc_tx_bw, my_ets->tc_tx_bw, sizeof(ets->tc_tx_bw)); + memcpy(ets->tc_tsa, my_ets->tc_tsa, sizeof(ets->tc_tsa)); + memcpy(ets->prio_tc, my_ets->prio_tc, sizeof(ets->prio_tc)); + + return 0; +} + +static int mlx4_en_ets_validate(struct mlx4_en_priv *priv, struct ieee_ets *ets) +{ + int i; + int total_ets_bw = 0; + int has_ets_tc = 0; + + for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { + if (ets->prio_tc[i] > MLX4_EN_NUM_UP) { + en_err(priv, "Bad priority in UP <=> TC mapping. TC: %d, UP: %d\n", + i, ets->prio_tc[i]); + return -EINVAL; + } + + switch (ets->tc_tsa[i]) { + case IEEE_8021QAZ_TSA_STRICT: + break; + case IEEE_8021QAZ_TSA_ETS: + has_ets_tc = 1; + total_ets_bw += ets->tc_tx_bw[i]; + break; + default: + en_err(priv, "TC[%d]: Not supported TSA: %d\n", + i, ets->tc_tsa[i]); + return -ENOTSUPP; + } + } + + if (has_ets_tc && total_ets_bw != MLX4_EN_BW_MAX) { + en_err(priv, "Bad ETS BW sum: %d. Should be exactly 100%%\n", + total_ets_bw); + return -EINVAL; + } + + return 0; +} + +static int mlx4_en_config_port_scheduler(struct mlx4_en_priv *priv, + struct ieee_ets *ets, u16 *ratelimit) +{ + struct mlx4_en_dev *mdev = priv->mdev; + int num_strict = 0; + int i; + __u8 tc_tx_bw[IEEE_8021QAZ_MAX_TCS] = { 0 }; + __u8 pg[IEEE_8021QAZ_MAX_TCS] = { 0 }; + + ets = ets ?: &priv->ets; + ratelimit = ratelimit ?: priv->maxrate; + + /* higher TC means higher priority => lower pg */ + for (i = IEEE_8021QAZ_MAX_TCS - 1; i >= 0; i--) { + switch (ets->tc_tsa[i]) { + case IEEE_8021QAZ_TSA_STRICT: + pg[i] = num_strict++; + tc_tx_bw[i] = MLX4_EN_BW_MAX; + break; + case IEEE_8021QAZ_TSA_ETS: + pg[i] = MLX4_EN_TC_ETS; + tc_tx_bw[i] = ets->tc_tx_bw[i] ?: MLX4_EN_BW_MIN; + break; + } + } + + return mlx4_SET_PORT_SCHEDULER(mdev->dev, priv->port, tc_tx_bw, pg, + ratelimit); +} + +static int +mlx4_en_dcbnl_ieee_setets(struct net_device *dev, struct ieee_ets *ets) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_dev *mdev = priv->mdev; + int err; + + err = mlx4_en_ets_validate(priv, ets); + if (err) + return err; + + err = mlx4_SET_PORT_PRIO2TC(mdev->dev, priv->port, ets->prio_tc); + if (err) + return err; + + err = mlx4_en_config_port_scheduler(priv, ets, NULL); + if (err) + return err; + + memcpy(&priv->ets, ets, sizeof(priv->ets)); + + return 0; +} + +static int mlx4_en_dcbnl_ieee_getpfc(struct net_device *dev, + struct ieee_pfc *pfc) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + + pfc->pfc_cap = IEEE_8021QAZ_MAX_TCS; + pfc->pfc_en = priv->prof->tx_ppp; + + return 0; +} + +static int mlx4_en_dcbnl_ieee_setpfc(struct net_device *dev, + struct ieee_pfc *pfc) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_dev *mdev = priv->mdev; + int err; + + en_dbg(DRV, priv, "cap: 0x%x en: 0x%x mbc: 0x%x delay: %d\n", + pfc->pfc_cap, + pfc->pfc_en, + pfc->mbc, + pfc->delay); + + priv->prof->rx_pause = priv->prof->tx_pause = !!pfc->pfc_en; + priv->prof->rx_ppp = priv->prof->tx_ppp = pfc->pfc_en; + + err = mlx4_SET_PORT_general(mdev->dev, priv->port, + priv->rx_skb_size + ETH_FCS_LEN, + priv->prof->tx_pause, + priv->prof->tx_ppp, + priv->prof->rx_pause, + priv->prof->rx_ppp); + if (err) + en_err(priv, "Failed setting pause params\n"); + + return err; +} + +static u8 mlx4_en_dcbnl_getdcbx(struct net_device *dev) +{ + return DCB_CAP_DCBX_VER_IEEE; +} + +static u8 mlx4_en_dcbnl_setdcbx(struct net_device *dev, u8 mode) +{ + if ((mode & DCB_CAP_DCBX_LLD_MANAGED) || + (mode & DCB_CAP_DCBX_VER_CEE) || + !(mode & DCB_CAP_DCBX_VER_IEEE) || + !(mode & DCB_CAP_DCBX_HOST)) + return 1; + + return 0; +} + +#define MLX4_RATELIMIT_UNITS_IN_KB 100000 /* rate-limit HW unit in Kbps */ +static int mlx4_en_dcbnl_ieee_getmaxrate(struct net_device *dev, + struct ieee_maxrate *maxrate) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + int i; + + if (!priv->maxrate) + return -EINVAL; + + for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) + maxrate->tc_maxrate[i] = + priv->maxrate[i] * MLX4_RATELIMIT_UNITS_IN_KB; + + return 0; +} + +static int mlx4_en_dcbnl_ieee_setmaxrate(struct net_device *dev, + struct ieee_maxrate *maxrate) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + u16 tmp[IEEE_8021QAZ_MAX_TCS]; + int i, err; + + for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { + /* Convert from Kbps into HW units, rounding result up. + * Setting to 0, means unlimited BW. + */ + tmp[i] = div_u64(maxrate->tc_maxrate[i] + + MLX4_RATELIMIT_UNITS_IN_KB - 1, + MLX4_RATELIMIT_UNITS_IN_KB); + } + + err = mlx4_en_config_port_scheduler(priv, NULL, tmp); + if (err) + return err; + + memcpy(priv->maxrate, tmp, sizeof(*priv->maxrate)); + + return 0; +} + +const struct dcbnl_rtnl_ops mlx4_en_dcbnl_ops = { + .ieee_getets = mlx4_en_dcbnl_ieee_getets, + .ieee_setets = mlx4_en_dcbnl_ieee_setets, + .ieee_getmaxrate = mlx4_en_dcbnl_ieee_getmaxrate, + .ieee_setmaxrate = mlx4_en_dcbnl_ieee_setmaxrate, + .ieee_getpfc = mlx4_en_dcbnl_ieee_getpfc, + .ieee_setpfc = mlx4_en_dcbnl_ieee_setpfc, + + .getdcbx = mlx4_en_dcbnl_getdcbx, + .setdcbx = mlx4_en_dcbnl_setdcbx, +}; diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/trunk/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index 70346fd7f9c4..72901ce2b088 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -83,7 +83,7 @@ static const char main_strings[][ETH_GSTRING_LEN] = { #define NUM_ALL_STATS (NUM_MAIN_STATS + NUM_PORT_STATS + NUM_PKT_STATS + NUM_PERF_STATS) static const char mlx4_en_test_names[][ETH_GSTRING_LEN]= { - "Interupt Test", + "Interrupt Test", "Link Test", "Speed Test", "Register Test", @@ -359,8 +359,8 @@ static int mlx4_en_get_coalesce(struct net_device *dev, { struct mlx4_en_priv *priv = netdev_priv(dev); - coal->tx_coalesce_usecs = 0; - coal->tx_max_coalesced_frames = 0; + coal->tx_coalesce_usecs = priv->tx_usecs; + coal->tx_max_coalesced_frames = priv->tx_frames; coal->rx_coalesce_usecs = priv->rx_usecs; coal->rx_max_coalesced_frames = priv->rx_frames; @@ -388,6 +388,21 @@ static int mlx4_en_set_coalesce(struct net_device *dev, MLX4_EN_RX_COAL_TIME : coal->rx_coalesce_usecs; + /* Setting TX coalescing parameters */ + if (coal->tx_coalesce_usecs != priv->tx_usecs || + coal->tx_max_coalesced_frames != priv->tx_frames) { + priv->tx_usecs = coal->tx_coalesce_usecs; + priv->tx_frames = coal->tx_max_coalesced_frames; + for (i = 0; i < priv->tx_ring_num; i++) { + priv->tx_cq[i].moder_cnt = priv->tx_frames; + priv->tx_cq[i].moder_time = priv->tx_usecs; + if (mlx4_en_set_cq_moder(priv, &priv->tx_cq[i])) { + en_warn(priv, "Failed changing moderation " + "for TX cq %d\n", i); + } + } + } + /* Set adaptive coalescing params */ priv->pkt_rate_low = coal->pkt_rate_low; priv->rx_usecs_low = coal->rx_coalesce_usecs_low; diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/en_main.c b/trunk/drivers/net/ethernet/mellanox/mlx4/en_main.c index 2097a7d3c5b8..988b2424e1c6 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/en_main.c +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/en_main.c @@ -101,6 +101,8 @@ static int mlx4_en_get_profile(struct mlx4_en_dev *mdev) int i; params->udp_rss = udp_rss; + params->num_tx_rings_p_up = min_t(int, num_online_cpus(), + MLX4_EN_MAX_TX_RING_P_UP); if (params->udp_rss && !(mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_UDP_RSS)) { mlx4_warn(mdev, "UDP RSS is not supported on this device.\n"); @@ -113,8 +115,8 @@ static int mlx4_en_get_profile(struct mlx4_en_dev *mdev) params->prof[i].tx_ppp = pfctx; params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE; params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE; - params->prof[i].tx_ring_num = MLX4_EN_NUM_TX_RINGS + - (!!pfcrx) * MLX4_EN_NUM_PPP_RINGS; + params->prof[i].tx_ring_num = params->num_tx_rings_p_up * + MLX4_EN_NUM_UP; params->prof[i].rss_rings = 0; } diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/trunk/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 31b455a49273..926d8aac941c 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -45,6 +45,27 @@ #include "mlx4_en.h" #include "en_port.h" +static int mlx4_en_setup_tc(struct net_device *dev, u8 up) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + int i; + unsigned int q, offset = 0; + + if (up && up != MLX4_EN_NUM_UP) + return -EINVAL; + + netdev_set_num_tc(dev, up); + + /* Partition Tx queues evenly amongst UP's */ + q = priv->tx_ring_num / up; + for (i = 0; i < up; i++) { + netdev_set_tc_queue(dev, i, q, offset); + offset += q; + } + + return 0; +} + static int mlx4_en_vlan_rx_add_vid(struct net_device *dev, unsigned short vid) { struct mlx4_en_priv *priv = netdev_priv(dev); @@ -421,6 +442,8 @@ static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv) */ priv->rx_frames = MLX4_EN_RX_COAL_TARGET; priv->rx_usecs = MLX4_EN_RX_COAL_TIME; + priv->tx_frames = MLX4_EN_TX_COAL_PKTS; + priv->tx_usecs = MLX4_EN_TX_COAL_TIME; en_dbg(INTR, priv, "Default coalesing params for mtu:%d - " "rx_frames:%d rx_usecs:%d\n", priv->dev->mtu, priv->rx_frames, priv->rx_usecs); @@ -437,8 +460,8 @@ static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv) for (i = 0; i < priv->tx_ring_num; i++) { cq = &priv->tx_cq[i]; - cq->moder_cnt = MLX4_EN_TX_COAL_PKTS; - cq->moder_time = MLX4_EN_TX_COAL_TIME; + cq->moder_cnt = priv->tx_frames; + cq->moder_time = priv->tx_usecs; } /* Reset auto-moderation params */ @@ -650,12 +673,18 @@ int mlx4_en_start_port(struct net_device *dev) /* Configure ring */ tx_ring = &priv->tx_ring[i]; - err = mlx4_en_activate_tx_ring(priv, tx_ring, cq->mcq.cqn); + err = mlx4_en_activate_tx_ring(priv, tx_ring, cq->mcq.cqn, + i / priv->mdev->profile.num_tx_rings_p_up); if (err) { en_err(priv, "Failed allocating Tx ring\n"); mlx4_en_deactivate_cq(priv, cq); goto tx_err; } + tx_ring->tx_queue = netdev_get_tx_queue(dev, i); + + /* Arm CQ for TX completions */ + mlx4_en_arm_cq(priv, cq); + /* Set initial ownership of all Tx TXBBs to SW (1) */ for (j = 0; j < tx_ring->buf_size; j += STAMP_STRIDE) *((u32 *) (tx_ring->buf + j)) = 0xffffffff; @@ -797,12 +826,15 @@ static void mlx4_en_restart(struct work_struct *work) watchdog_task); struct mlx4_en_dev *mdev = priv->mdev; struct net_device *dev = priv->dev; + int i; en_dbg(DRV, priv, "Watchdog task called for port %d\n", priv->port); mutex_lock(&mdev->state_lock); if (priv->port_up) { mlx4_en_stop_port(dev); + for (i = 0; i < priv->tx_ring_num; i++) + netdev_tx_reset_queue(priv->tx_ring[i].tx_queue); if (mlx4_en_start_port(dev)) en_err(priv, "Failed restarting port %d\n", priv->port); } @@ -966,6 +998,10 @@ void mlx4_en_destroy_netdev(struct net_device *dev) mutex_unlock(&mdev->state_lock); mlx4_en_free_resources(priv); + + kfree(priv->tx_ring); + kfree(priv->tx_cq); + free_netdev(dev); } @@ -1036,6 +1072,7 @@ static const struct net_device_ops mlx4_netdev_ops = { .ndo_poll_controller = mlx4_en_netpoll, #endif .ndo_set_features = mlx4_en_set_features, + .ndo_setup_tc = mlx4_en_setup_tc, }; int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, @@ -1070,6 +1107,18 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, priv->ctrl_flags = cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE | MLX4_WQE_CTRL_SOLICITED); priv->tx_ring_num = prof->tx_ring_num; + priv->tx_ring = kzalloc(sizeof(struct mlx4_en_tx_ring) * + priv->tx_ring_num, GFP_KERNEL); + if (!priv->tx_ring) { + err = -ENOMEM; + goto out; + } + priv->tx_cq = kzalloc(sizeof(struct mlx4_en_cq) * priv->tx_ring_num, + GFP_KERNEL); + if (!priv->tx_cq) { + err = -ENOMEM; + goto out; + } priv->rx_ring_num = prof->rx_ring_num; priv->mac_index = -1; priv->msg_enable = MLX4_EN_MSG_LEVEL; @@ -1079,6 +1128,10 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, INIT_WORK(&priv->watchdog_task, mlx4_en_restart); INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate); INIT_DELAYED_WORK(&priv->stats_task, mlx4_en_do_get_stats); +#ifdef CONFIG_MLX4_EN_DCB + if (!mlx4_is_slave(priv->mdev->dev)) + dev->dcbnl_ops = &mlx4_en_dcbnl_ops; +#endif /* Query for default mac and max mtu */ priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port]; diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/en_port.h b/trunk/drivers/net/ethernet/mellanox/mlx4/en_port.h index 6934fd7e66ed..745090b49d9e 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/en_port.h +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/en_port.h @@ -39,6 +39,8 @@ #define SET_PORT_PROMISC_SHIFT 31 #define SET_PORT_MC_PROMISC_SHIFT 30 +#define MLX4_EN_NUM_TC 8 + #define VLAN_FLTR_SIZE 128 struct mlx4_set_vlan_fltr_mbox { __be32 entry[VLAN_FLTR_SIZE]; diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/en_resources.c b/trunk/drivers/net/ethernet/mellanox/mlx4/en_resources.c index bcbc54c16947..10c24c784b70 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/en_resources.c +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/en_resources.c @@ -39,7 +39,7 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride, int is_tx, int rss, int qpn, int cqn, - struct mlx4_qp_context *context) + int user_prio, struct mlx4_qp_context *context) { struct mlx4_en_dev *mdev = priv->mdev; @@ -57,6 +57,10 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride, context->local_qpn = cpu_to_be32(qpn); context->pri_path.ackto = 1 & 0x07; context->pri_path.sched_queue = 0x83 | (priv->port - 1) << 6; + if (user_prio >= 0) { + context->pri_path.sched_queue |= user_prio << 3; + context->pri_path.feup = 1 << 6; + } context->pri_path.counter_index = 0xff; context->cqn_send = cpu_to_be32(cqn); context->cqn_recv = cpu_to_be32(cqn); diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/trunk/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 9adbd53da525..d49a7ac3187d 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -823,7 +823,7 @@ static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, int qpn, memset(context, 0, sizeof *context); mlx4_en_fill_qp_context(priv, ring->actual_size, ring->stride, 0, 0, - qpn, ring->cqn, context); + qpn, ring->cqn, -1, context); context->db_rec_addr = cpu_to_be64(ring->wqres.db.dma); /* Cancel FCS removal if FW allows */ @@ -890,7 +890,7 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) } rss_map->indir_qp.event = mlx4_en_sqp_event; mlx4_en_fill_qp_context(priv, 0, 0, 0, 1, priv->base_qpn, - priv->rx_ring[0].cqn, &context); + priv->rx_ring[0].cqn, -1, &context); if (!priv->prof->rss_rings || priv->prof->rss_rings > priv->rx_ring_num) rss_rings = priv->rx_ring_num; diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/trunk/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 17968244c399..019d856b1334 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -67,8 +67,6 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, inline_thold = min(inline_thold, MAX_INLINE); - spin_lock_init(&ring->comp_lock); - tmp = size * sizeof(struct mlx4_en_tx_info); ring->tx_info = vmalloc(tmp); if (!ring->tx_info) @@ -156,7 +154,7 @@ void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, - int cq) + int cq, int user_prio) { struct mlx4_en_dev *mdev = priv->mdev; int err; @@ -174,7 +172,7 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv, ring->doorbell_qpn = ring->qp.qpn << 8; mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 1, 0, ring->qpn, - ring->cqn, &ring->context); + ring->cqn, user_prio, &ring->context); if (ring->bf_enabled) ring->context.usr_page = cpu_to_be32(ring->bf.uar->index); @@ -317,6 +315,8 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq) int size = cq->size; u32 size_mask = ring->size_mask; struct mlx4_cqe *buf = cq->buf; + u32 packets = 0; + u32 bytes = 0; if (!priv->port_up) return; @@ -345,6 +345,8 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq) priv, ring, ring_index, !!((ring->cons + txbbs_skipped) & ring->size)); + packets++; + bytes += ring->tx_info[ring_index].nr_bytes; } while (ring_index != new_index); ++cons_index; @@ -361,13 +363,14 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq) mlx4_cq_set_ci(mcq); wmb(); ring->cons += txbbs_skipped; + netdev_tx_completed_queue(ring->tx_queue, packets, bytes); /* Wakeup Tx queue if this ring stopped it */ if (unlikely(ring->blocked)) { if ((u32) (ring->prod - ring->cons) <= ring->size - HEADROOM - MAX_DESC_TXBBS) { ring->blocked = 0; - netif_tx_wake_queue(netdev_get_tx_queue(dev, cq->ring)); + netif_tx_wake_queue(ring->tx_queue); priv->port_stats.wake_queue++; } } @@ -377,41 +380,12 @@ void mlx4_en_tx_irq(struct mlx4_cq *mcq) { struct mlx4_en_cq *cq = container_of(mcq, struct mlx4_en_cq, mcq); struct mlx4_en_priv *priv = netdev_priv(cq->dev); - struct mlx4_en_tx_ring *ring = &priv->tx_ring[cq->ring]; - if (!spin_trylock(&ring->comp_lock)) - return; mlx4_en_process_tx_cq(cq->dev, cq); - mod_timer(&cq->timer, jiffies + 1); - spin_unlock(&ring->comp_lock); + mlx4_en_arm_cq(priv, cq); } -void mlx4_en_poll_tx_cq(unsigned long data) -{ - struct mlx4_en_cq *cq = (struct mlx4_en_cq *) data; - struct mlx4_en_priv *priv = netdev_priv(cq->dev); - struct mlx4_en_tx_ring *ring = &priv->tx_ring[cq->ring]; - u32 inflight; - - INC_PERF_COUNTER(priv->pstats.tx_poll); - - if (!spin_trylock_irq(&ring->comp_lock)) { - mod_timer(&cq->timer, jiffies + MLX4_EN_TX_POLL_TIMEOUT); - return; - } - mlx4_en_process_tx_cq(cq->dev, cq); - inflight = (u32) (ring->prod - ring->cons - ring->last_nr_txbb); - - /* If there are still packets in flight and the timer has not already - * been scheduled by the Tx routine then schedule it here to guarantee - * completion processing of these packets */ - if (inflight && priv->port_up) - mod_timer(&cq->timer, jiffies + MLX4_EN_TX_POLL_TIMEOUT); - - spin_unlock_irq(&ring->comp_lock); -} - static struct mlx4_en_tx_desc *mlx4_en_bounce_to_desc(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, u32 index, @@ -440,25 +414,6 @@ static struct mlx4_en_tx_desc *mlx4_en_bounce_to_desc(struct mlx4_en_priv *priv, return ring->buf + index * TXBB_SIZE; } -static inline void mlx4_en_xmit_poll(struct mlx4_en_priv *priv, int tx_ind) -{ - struct mlx4_en_cq *cq = &priv->tx_cq[tx_ind]; - struct mlx4_en_tx_ring *ring = &priv->tx_ring[tx_ind]; - unsigned long flags; - - /* If we don't have a pending timer, set one up to catch our recent - post in case the interface becomes idle */ - if (!timer_pending(&cq->timer)) - mod_timer(&cq->timer, jiffies + MLX4_EN_TX_POLL_TIMEOUT); - - /* Poll the CQ every mlx4_en_TX_MODER_POLL packets */ - if ((++ring->poll_cnt & (MLX4_EN_TX_POLL_MODER - 1)) == 0) - if (spin_trylock_irqsave(&ring->comp_lock, flags)) { - mlx4_en_process_tx_cq(priv->dev, cq); - spin_unlock_irqrestore(&ring->comp_lock, flags); - } -} - static int is_inline(struct sk_buff *skb, void **pfrag) { void *ptr; @@ -571,17 +526,16 @@ static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, struct sk_buff *sk u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb) { struct mlx4_en_priv *priv = netdev_priv(dev); - u16 vlan_tag = 0; + u16 rings_p_up = priv->mdev->profile.num_tx_rings_p_up; + u8 up = 0; - /* If we support per priority flow control and the packet contains - * a vlan tag, send the packet to the TX ring assigned to that priority - */ - if (priv->prof->rx_ppp && vlan_tx_tag_present(skb)) { - vlan_tag = vlan_tx_tag_get(skb); - return MLX4_EN_NUM_TX_RINGS + (vlan_tag >> 13); - } + if (dev->num_tc) + return skb_tx_hash(dev, skb); - return skb_tx_hash(dev, skb); + if (vlan_tx_tag_present(skb)) + up = vlan_tx_tag_get(skb) >> VLAN_PRIO_SHIFT; + + return __skb_tx_hash(dev, skb, rings_p_up) + up * rings_p_up; } static void mlx4_bf_copy(void __iomem *dst, unsigned long *src, unsigned bytecnt) @@ -594,7 +548,6 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_en_tx_ring *ring; - struct mlx4_en_cq *cq; struct mlx4_en_tx_desc *tx_desc; struct mlx4_wqe_data_seg *data; struct skb_frag_struct *frag; @@ -638,13 +591,10 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(((int)(ring->prod - ring->cons)) > ring->size - HEADROOM - MAX_DESC_TXBBS)) { /* every full Tx ring stops queue */ - netif_tx_stop_queue(netdev_get_tx_queue(dev, tx_ind)); + netif_tx_stop_queue(ring->tx_queue); ring->blocked = 1; priv->port_stats.queue_stopped++; - /* Use interrupts to find out when queue opened */ - cq = &priv->tx_cq[tx_ind]; - mlx4_en_arm_cq(priv, cq); return NETDEV_TX_BUSY; } @@ -707,7 +657,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) priv->port_stats.tso_packets++; i = ((skb->len - lso_header_size) / skb_shinfo(skb)->gso_size) + !!((skb->len - lso_header_size) % skb_shinfo(skb)->gso_size); - ring->bytes += skb->len + (i - 1) * lso_header_size; + tx_info->nr_bytes = skb->len + (i - 1) * lso_header_size; ring->packets += i; } else { /* Normal (Non LSO) packet */ @@ -715,10 +665,12 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) ((ring->prod & ring->size) ? cpu_to_be32(MLX4_EN_BIT_DESC_OWN) : 0); data = &tx_desc->data; - ring->bytes += max(skb->len, (unsigned int) ETH_ZLEN); + tx_info->nr_bytes = max_t(unsigned int, skb->len, ETH_ZLEN); ring->packets++; } + ring->bytes += tx_info->nr_bytes; + netdev_tx_sent_queue(ring->tx_queue, tx_info->nr_bytes); AVG_PERF_COUNTER(priv->pstats.tx_pktsz_avg, skb->len); @@ -792,9 +744,6 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) iowrite32be(ring->doorbell_qpn, ring->bf.uar->map + MLX4_SEND_DOORBELL); } - /* Poll CQ here */ - mlx4_en_xmit_poll(priv, tx_ind); - return NETDEV_TX_OK; tx_drop: diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/fw.c b/trunk/drivers/net/ethernet/mellanox/mlx4/fw.c index 2a02ba522e60..68f5cd6cb3c7 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -118,6 +118,20 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u64 flags) mlx4_dbg(dev, " %s\n", fname[i]); } +static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags) +{ + static const char * const fname[] = { + [0] = "RSS support", + [1] = "RSS Toeplitz Hash Function support", + [2] = "RSS XOR Hash Function support" + }; + int i; + + for (i = 0; i < ARRAY_SIZE(fname); ++i) + if (fname[i] && (flags & (1LL << i))) + mlx4_dbg(dev, " %s\n", fname[i]); +} + int mlx4_MOD_STAT_CFG(struct mlx4_dev *dev, struct mlx4_mod_stat_cfg *cfg) { struct mlx4_cmd_mailbox *mailbox; @@ -346,6 +360,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) #define QUERY_DEV_CAP_MAX_REQ_QP_OFFSET 0x29 #define QUERY_DEV_CAP_MAX_RES_QP_OFFSET 0x2b #define QUERY_DEV_CAP_MAX_GSO_OFFSET 0x2d +#define QUERY_DEV_CAP_RSS_OFFSET 0x2e #define QUERY_DEV_CAP_MAX_RDMA_OFFSET 0x2f #define QUERY_DEV_CAP_RSZ_SRQ_OFFSET 0x33 #define QUERY_DEV_CAP_ACK_DELAY_OFFSET 0x35 @@ -390,6 +405,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) #define QUERY_DEV_CAP_RSVD_LKEY_OFFSET 0x98 #define QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET 0xa0 + dev_cap->flags2 = 0; mailbox = mlx4_alloc_cmd_mailbox(dev); if (IS_ERR(mailbox)) return PTR_ERR(mailbox); @@ -439,6 +455,17 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) else dev_cap->max_gso_sz = 1 << field; + MLX4_GET(field, outbox, QUERY_DEV_CAP_RSS_OFFSET); + if (field & 0x20) + dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RSS_XOR; + if (field & 0x10) + dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RSS_TOP; + field &= 0xf; + if (field) { + dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RSS; + dev_cap->max_rss_tbl_sz = 1 << field; + } else + dev_cap->max_rss_tbl_sz = 0; MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RDMA_OFFSET); dev_cap->max_rdma_global = 1 << (field & 0x3f); MLX4_GET(field, outbox, QUERY_DEV_CAP_ACK_DELAY_OFFSET); @@ -632,8 +659,10 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) dev_cap->max_rq_desc_sz, dev_cap->max_rq_sg); mlx4_dbg(dev, "Max GSO size: %d\n", dev_cap->max_gso_sz); mlx4_dbg(dev, "Max counters: %d\n", dev_cap->max_counters); + mlx4_dbg(dev, "Max RSS Table size: %d\n", dev_cap->max_rss_tbl_sz); dump_dev_cap_flags(dev, dev_cap->flags); + dump_dev_cap_flags2(dev, dev_cap->flags2); out: mlx4_free_cmd_mailbox(dev, mailbox); @@ -1164,9 +1193,8 @@ int mlx4_INIT_PORT_wrapper(struct mlx4_dev *dev, int slave, MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); if (err) return err; - priv->mfunc.master.slave_state[slave].init_port_mask |= - (1 << port); } + priv->mfunc.master.slave_state[slave].init_port_mask |= (1 << port); ++priv->mfunc.master.init_port_ref[port]; return 0; } diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/fw.h b/trunk/drivers/net/ethernet/mellanox/mlx4/fw.h index e1a5fa56bcbc..64c0399e4b78 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/fw.h +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/fw.h @@ -79,6 +79,7 @@ struct mlx4_dev_cap { u64 trans_code[MLX4_MAX_PORTS + 1]; u16 stat_rate_support; u64 flags; + u64 flags2; int reserved_uars; int uar_size; int min_page_sz; @@ -110,6 +111,7 @@ struct mlx4_dev_cap { u32 reserved_lkey; u64 max_icm_sz; int max_gso_sz; + int max_rss_tbl_sz; u8 supported_port_types[MLX4_MAX_PORTS + 1]; u8 suggested_type[MLX4_MAX_PORTS + 1]; u8 default_sense[MLX4_MAX_PORTS + 1]; diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/main.c b/trunk/drivers/net/ethernet/mellanox/mlx4/main.c index 8bb05b46db86..2e024a68fa81 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/main.c @@ -272,10 +272,12 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) dev->caps.max_msg_sz = dev_cap->max_msg_sz; dev->caps.page_size_cap = ~(u32) (dev_cap->min_page_sz - 1); dev->caps.flags = dev_cap->flags; + dev->caps.flags2 = dev_cap->flags2; dev->caps.bmme_flags = dev_cap->bmme_flags; dev->caps.reserved_lkey = dev_cap->reserved_lkey; dev->caps.stat_rate_support = dev_cap->stat_rate_support; dev->caps.max_gso_sz = dev_cap->max_gso_sz; + dev->caps.max_rss_tbl_sz = dev_cap->max_rss_tbl_sz; /* Sense port always allowed on supported devices for ConnectX1 and 2 */ if (dev->pdev->device != 0x1003) @@ -1306,7 +1308,7 @@ static void mlx4_cleanup_counters_table(struct mlx4_dev *dev) mlx4_bitmap_cleanup(&mlx4_priv(dev)->counters_bitmap); } -int mlx4_counter_alloc(struct mlx4_dev *dev, u32 *idx) +int __mlx4_counter_alloc(struct mlx4_dev *dev, u32 *idx) { struct mlx4_priv *priv = mlx4_priv(dev); @@ -1319,13 +1321,44 @@ int mlx4_counter_alloc(struct mlx4_dev *dev, u32 *idx) return 0; } + +int mlx4_counter_alloc(struct mlx4_dev *dev, u32 *idx) +{ + u64 out_param; + int err; + + if (mlx4_is_mfunc(dev)) { + err = mlx4_cmd_imm(dev, 0, &out_param, RES_COUNTER, + RES_OP_RESERVE, MLX4_CMD_ALLOC_RES, + MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); + if (!err) + *idx = get_param_l(&out_param); + + return err; + } + return __mlx4_counter_alloc(dev, idx); +} EXPORT_SYMBOL_GPL(mlx4_counter_alloc); -void mlx4_counter_free(struct mlx4_dev *dev, u32 idx) +void __mlx4_counter_free(struct mlx4_dev *dev, u32 idx) { mlx4_bitmap_free(&mlx4_priv(dev)->counters_bitmap, idx); return; } + +void mlx4_counter_free(struct mlx4_dev *dev, u32 idx) +{ + u64 in_param; + + if (mlx4_is_mfunc(dev)) { + set_param_l(&in_param, idx); + mlx4_cmd(dev, in_param, RES_COUNTER, RES_OP_RESERVE, + MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A, + MLX4_CMD_WRAPPED); + return; + } + __mlx4_counter_free(dev, idx); +} EXPORT_SYMBOL_GPL(mlx4_counter_free); static int mlx4_setup_hca(struct mlx4_dev *dev) @@ -1865,7 +1898,6 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) mlx4_err(dev, "Failed to enable sriov," "continuing without sriov enabled" " (err = %d).\n", err); - num_vfs = 0; err = 0; } else { mlx4_warn(dev, "Running in master mode\n"); @@ -2022,7 +2054,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) mlx4_cmd_cleanup(dev); err_sriov: - if (num_vfs && (dev->flags & MLX4_FLAG_SRIOV)) + if (dev->flags & MLX4_FLAG_SRIOV) pci_disable_sriov(pdev); err_rel_own: @@ -2070,6 +2102,10 @@ static void mlx4_remove_one(struct pci_dev *pdev) mlx4_CLOSE_PORT(dev, p); } + if (mlx4_is_master(dev)) + mlx4_free_resource_tracker(dev, + RES_TR_FREE_SLAVES_ONLY); + mlx4_cleanup_counters_table(dev); mlx4_cleanup_mcg_table(dev); mlx4_cleanup_qp_table(dev); @@ -2082,7 +2118,8 @@ static void mlx4_remove_one(struct pci_dev *pdev) mlx4_cleanup_pd_table(dev); if (mlx4_is_master(dev)) - mlx4_free_resource_tracker(dev); + mlx4_free_resource_tracker(dev, + RES_TR_FREE_STRUCTS_ONLY); iounmap(priv->kar); mlx4_uar_free(dev, &priv->driver_uar); @@ -2099,7 +2136,7 @@ static void mlx4_remove_one(struct pci_dev *pdev) if (dev->flags & MLX4_FLAG_MSI_X) pci_disable_msix(pdev); - if (num_vfs && (dev->flags & MLX4_FLAG_SRIOV)) { + if (dev->flags & MLX4_FLAG_SRIOV) { mlx4_warn(dev, "Disabling sriov\n"); pci_disable_sriov(pdev); } diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/mcg.c b/trunk/drivers/net/ethernet/mellanox/mlx4/mcg.c index 4799e824052f..f4a8f98e402a 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/mcg.c +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/mcg.c @@ -357,7 +357,6 @@ static int add_promisc_qp(struct mlx4_dev *dev, u8 port, u32 prot; int i; bool found; - int last_index; int err; struct mlx4_priv *priv = mlx4_priv(dev); @@ -419,7 +418,6 @@ static int add_promisc_qp(struct mlx4_dev *dev, u8 port, if (err) goto out_mailbox; } - last_index = entry->index; } /* add the new qpn to list of promisc qps */ diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/trunk/drivers/net/ethernet/mellanox/mlx4/mlx4.h index 2a0ff2cc7182..86b6e5a2fabf 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -53,6 +53,26 @@ #define DRV_VERSION "1.1" #define DRV_RELDATE "Dec, 2011" +#define MLX4_NUM_UP 8 +#define MLX4_NUM_TC 8 +#define MLX4_RATELIMIT_UNITS 3 /* 100 Mbps */ +#define MLX4_RATELIMIT_DEFAULT 0xffff + +struct mlx4_set_port_prio2tc_context { + u8 prio2tc[4]; +}; + +struct mlx4_port_scheduler_tc_cfg_be { + __be16 pg; + __be16 bw_precentage; + __be16 max_bw_units; /* 3-100Mbps, 4-1Gbps, other values - reserved */ + __be16 max_bw_value; +}; + +struct mlx4_set_port_scheduler_context { + struct mlx4_port_scheduler_tc_cfg_be tc[MLX4_NUM_TC]; +}; + enum { MLX4_HCR_BASE = 0x80680, MLX4_HCR_SIZE = 0x0001c, @@ -126,6 +146,11 @@ enum mlx4_alloc_mode { RES_OP_MAP_ICM, }; +enum mlx4_res_tracker_free_type { + RES_TR_FREE_ALL, + RES_TR_FREE_SLAVES_ONLY, + RES_TR_FREE_STRUCTS_ONLY, +}; /* *Virtual HCR structures. @@ -851,6 +876,10 @@ void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac); int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac); int __mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, int start_index, int npages, u64 *page_list); +int __mlx4_counter_alloc(struct mlx4_dev *dev, u32 *idx); +void __mlx4_counter_free(struct mlx4_dev *dev, u32 idx); +int __mlx4_xrcd_alloc(struct mlx4_dev *dev, u32 *xrcdn); +void __mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn); void mlx4_start_catas_poll(struct mlx4_dev *dev); void mlx4_stop_catas_poll(struct mlx4_dev *dev); @@ -1007,7 +1036,8 @@ int mlx4_get_slave_from_resource_id(struct mlx4_dev *dev, void mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave_id); int mlx4_init_resource_tracker(struct mlx4_dev *dev); -void mlx4_free_resource_tracker(struct mlx4_dev *dev); +void mlx4_free_resource_tracker(struct mlx4_dev *dev, + enum mlx4_res_tracker_free_type type); int mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vhcr, diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/trunk/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index d69fee41f24a..6ae350921b1a 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -40,6 +40,9 @@ #include #include #include +#ifdef CONFIG_MLX4_EN_DCB +#include +#endif #include #include @@ -108,9 +111,8 @@ enum { #define MLX4_EN_MIN_TX_SIZE (4096 / TXBB_SIZE) #define MLX4_EN_SMALL_PKT_SIZE 64 -#define MLX4_EN_NUM_TX_RINGS 8 -#define MLX4_EN_NUM_PPP_RINGS 8 -#define MAX_TX_RINGS (MLX4_EN_NUM_TX_RINGS + MLX4_EN_NUM_PPP_RINGS) +#define MLX4_EN_MAX_TX_RING_P_UP 32 +#define MLX4_EN_NUM_UP 8 #define MLX4_EN_DEF_TX_RING_SIZE 512 #define MLX4_EN_DEF_RX_RING_SIZE 1024 @@ -118,7 +120,7 @@ enum { #define MLX4_EN_RX_COAL_TARGET 44 #define MLX4_EN_RX_COAL_TIME 0x10 -#define MLX4_EN_TX_COAL_PKTS 5 +#define MLX4_EN_TX_COAL_PKTS 16 #define MLX4_EN_TX_COAL_TIME 0x80 #define MLX4_EN_RX_RATE_LOW 400000 @@ -196,6 +198,7 @@ enum cq_type { struct mlx4_en_tx_info { struct sk_buff *skb; u32 nr_txbb; + u32 nr_bytes; u8 linear; u8 data_offset; u8 inl; @@ -251,9 +254,9 @@ struct mlx4_en_tx_ring { unsigned long bytes; unsigned long packets; unsigned long tx_csum; - spinlock_t comp_lock; struct mlx4_bf bf; bool bf_enabled; + struct netdev_queue *tx_queue; }; struct mlx4_en_rx_desc { @@ -304,8 +307,6 @@ struct mlx4_en_cq { spinlock_t lock; struct net_device *dev; struct napi_struct napi; - /* Per-core Tx cq processing support */ - struct timer_list timer; int size; int buf_size; unsigned vector; @@ -336,6 +337,7 @@ struct mlx4_en_profile { u32 active_ports; u32 small_pkt_int; u8 no_reset; + u8 num_tx_rings_p_up; struct mlx4_en_port_profile prof[MLX4_MAX_PORTS + 1]; }; @@ -411,6 +413,15 @@ struct mlx4_en_frag_info { }; +#ifdef CONFIG_MLX4_EN_DCB +/* Minimal TC BW - setting to 0 will block traffic */ +#define MLX4_EN_BW_MIN 1 +#define MLX4_EN_BW_MAX 100 /* Utilize 100% of the line */ + +#define MLX4_EN_TC_ETS 7 + +#endif + struct mlx4_en_priv { struct mlx4_en_dev *mdev; struct mlx4_en_port_profile *prof; @@ -465,9 +476,9 @@ struct mlx4_en_priv { u16 num_frags; u16 log_rx_info; - struct mlx4_en_tx_ring tx_ring[MAX_TX_RINGS]; + struct mlx4_en_tx_ring *tx_ring; struct mlx4_en_rx_ring rx_ring[MAX_RX_RINGS]; - struct mlx4_en_cq tx_cq[MAX_TX_RINGS]; + struct mlx4_en_cq *tx_cq; struct mlx4_en_cq rx_cq[MAX_RX_RINGS]; struct work_struct mcast_task; struct work_struct mac_task; @@ -484,6 +495,11 @@ struct mlx4_en_priv { int vids[128]; bool wol; struct device *ddev; + +#ifdef CONFIG_MLX4_EN_DCB + struct ieee_ets ets; + u16 maxrate[IEEE_8021QAZ_MAX_TCS]; +#endif }; enum mlx4_en_wol { @@ -512,7 +528,6 @@ void mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); int mlx4_en_set_cq_moder(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); -void mlx4_en_poll_tx_cq(unsigned long data); void mlx4_en_tx_irq(struct mlx4_cq *mcq); u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb); netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev); @@ -522,7 +537,7 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ri void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring); int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, - int cq); + int cq, int user_prio); void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring); @@ -540,8 +555,8 @@ int mlx4_en_process_rx_cq(struct net_device *dev, int budget); int mlx4_en_poll_rx_cq(struct napi_struct *napi, int budget); void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride, - int is_tx, int rss, int qpn, int cqn, - struct mlx4_qp_context *context); + int is_tx, int rss, int qpn, int cqn, int user_prio, + struct mlx4_qp_context *context); void mlx4_en_sqp_event(struct mlx4_qp *qp, enum mlx4_event event); int mlx4_en_map_buffer(struct mlx4_buf *buf); void mlx4_en_unmap_buffer(struct mlx4_buf *buf); @@ -558,6 +573,10 @@ int mlx4_SET_VLAN_FLTR(struct mlx4_dev *dev, struct mlx4_en_priv *priv); int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset); int mlx4_en_QUERY_PORT(struct mlx4_en_dev *mdev, u8 port); +#ifdef CONFIG_MLX4_EN_DCB +extern const struct dcbnl_rtnl_ops mlx4_en_dcbnl_ops; +#endif + #define MLX4_EN_NUM_SELF_TEST 5 void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf); u64 mlx4_en_mac_to_u64(u8 *addr); diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/mr.c b/trunk/drivers/net/ethernet/mellanox/mlx4/mr.c index fe2ac8449c19..af55b7ce5341 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/mr.c +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/mr.c @@ -788,7 +788,6 @@ int mlx4_fmr_alloc(struct mlx4_dev *dev, u32 pd, u32 access, int max_pages, int max_maps, u8 page_shift, struct mlx4_fmr *fmr) { struct mlx4_priv *priv = mlx4_priv(dev); - u64 mtt_offset; int err = -ENOMEM; if (max_maps > dev->caps.max_fmr_maps) @@ -811,8 +810,6 @@ int mlx4_fmr_alloc(struct mlx4_dev *dev, u32 pd, u32 access, int max_pages, if (err) return err; - mtt_offset = fmr->mr.mtt.offset * dev->caps.mtt_entry_sz; - fmr->mtts = mlx4_table_find(&priv->mr_table.mtt_table, fmr->mr.mtt.offset, &fmr->dma_handle); @@ -895,6 +892,6 @@ EXPORT_SYMBOL_GPL(mlx4_fmr_free); int mlx4_SYNC_TPT(struct mlx4_dev *dev) { return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_SYNC_TPT, 1000, - MLX4_CMD_WRAPPED); + MLX4_CMD_NATIVE); } EXPORT_SYMBOL_GPL(mlx4_SYNC_TPT); diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/pd.c b/trunk/drivers/net/ethernet/mellanox/mlx4/pd.c index db4746d0dca7..1ac88637ad9d 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/pd.c +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/pd.c @@ -63,7 +63,7 @@ void mlx4_pd_free(struct mlx4_dev *dev, u32 pdn) } EXPORT_SYMBOL_GPL(mlx4_pd_free); -int mlx4_xrcd_alloc(struct mlx4_dev *dev, u32 *xrcdn) +int __mlx4_xrcd_alloc(struct mlx4_dev *dev, u32 *xrcdn) { struct mlx4_priv *priv = mlx4_priv(dev); @@ -73,12 +73,47 @@ int mlx4_xrcd_alloc(struct mlx4_dev *dev, u32 *xrcdn) return 0; } + +int mlx4_xrcd_alloc(struct mlx4_dev *dev, u32 *xrcdn) +{ + u64 out_param; + int err; + + if (mlx4_is_mfunc(dev)) { + err = mlx4_cmd_imm(dev, 0, &out_param, + RES_XRCD, RES_OP_RESERVE, + MLX4_CMD_ALLOC_RES, + MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); + if (err) + return err; + + *xrcdn = get_param_l(&out_param); + return 0; + } + return __mlx4_xrcd_alloc(dev, xrcdn); +} EXPORT_SYMBOL_GPL(mlx4_xrcd_alloc); -void mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn) +void __mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn) { mlx4_bitmap_free(&mlx4_priv(dev)->xrcd_bitmap, xrcdn); } + +void mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn) +{ + u64 in_param; + int err; + + if (mlx4_is_mfunc(dev)) { + set_param_l(&in_param, xrcdn); + err = mlx4_cmd(dev, in_param, RES_XRCD, + RES_OP_RESERVE, MLX4_CMD_FREE_RES, + MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); + if (err) + mlx4_warn(dev, "Failed to release xrcdn %d\n", xrcdn); + } else + __mlx4_xrcd_free(dev, xrcdn); +} EXPORT_SYMBOL_GPL(mlx4_xrcd_free); int mlx4_init_pd_table(struct mlx4_dev *dev) diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/port.c b/trunk/drivers/net/ethernet/mellanox/mlx4/port.c index 77535ff18f1b..1fe2c7a8b40c 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/port.c +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/port.c @@ -338,13 +338,12 @@ EXPORT_SYMBOL_GPL(__mlx4_unregister_mac); void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac) { u64 out_param; - int err; if (mlx4_is_mfunc(dev)) { set_param_l(&out_param, port); - err = mlx4_cmd_imm(dev, mac, &out_param, RES_MAC, - RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES, - MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); + (void) mlx4_cmd_imm(dev, mac, &out_param, RES_MAC, + RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES, + MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); return; } __mlx4_unregister_mac(dev, port, mac); @@ -834,6 +833,68 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, } EXPORT_SYMBOL(mlx4_SET_PORT_qpn_calc); +int mlx4_SET_PORT_PRIO2TC(struct mlx4_dev *dev, u8 port, u8 *prio2tc) +{ + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_set_port_prio2tc_context *context; + int err; + u32 in_mod; + int i; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + context = mailbox->buf; + memset(context, 0, sizeof *context); + + for (i = 0; i < MLX4_NUM_UP; i += 2) + context->prio2tc[i >> 1] = prio2tc[i] << 4 | prio2tc[i + 1]; + + in_mod = MLX4_SET_PORT_PRIO2TC << 8 | port; + err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, + MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} +EXPORT_SYMBOL(mlx4_SET_PORT_PRIO2TC); + +int mlx4_SET_PORT_SCHEDULER(struct mlx4_dev *dev, u8 port, u8 *tc_tx_bw, + u8 *pg, u16 *ratelimit) +{ + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_set_port_scheduler_context *context; + int err; + u32 in_mod; + int i; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + context = mailbox->buf; + memset(context, 0, sizeof *context); + + for (i = 0; i < MLX4_NUM_TC; i++) { + struct mlx4_port_scheduler_tc_cfg_be *tc = &context->tc[i]; + u16 r = ratelimit && ratelimit[i] ? ratelimit[i] : + MLX4_RATELIMIT_DEFAULT; + + tc->pg = htons(pg[i]); + tc->bw_precentage = htons(tc_tx_bw[i]); + + tc->max_bw_units = htons(MLX4_RATELIMIT_UNITS); + tc->max_bw_value = htons(r); + } + + in_mod = MLX4_SET_PORT_SCHEDULER << 8 | port; + err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, + MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} +EXPORT_SYMBOL(mlx4_SET_PORT_SCHEDULER); + int mlx4_SET_MCAST_FLTR_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vhcr, struct mlx4_cmd_mailbox *inbox, diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/trunk/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 8752e6e08169..b45d0e7f6ab0 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -89,17 +89,6 @@ enum res_qp_states { RES_QP_HW }; -static inline const char *qp_states_str(enum res_qp_states state) -{ - switch (state) { - case RES_QP_BUSY: return "RES_QP_BUSY"; - case RES_QP_RESERVED: return "RES_QP_RESERVED"; - case RES_QP_MAPPED: return "RES_QP_MAPPED"; - case RES_QP_HW: return "RES_QP_HW"; - default: return "Unknown"; - } -} - struct res_qp { struct res_common com; struct res_mtt *mtt; @@ -173,16 +162,6 @@ enum res_srq_states { RES_SRQ_HW, }; -static inline const char *srq_states_str(enum res_srq_states state) -{ - switch (state) { - case RES_SRQ_BUSY: return "RES_SRQ_BUSY"; - case RES_SRQ_ALLOCATED: return "RES_SRQ_ALLOCATED"; - case RES_SRQ_HW: return "RES_SRQ_HW"; - default: return "Unknown"; - } -} - struct res_srq { struct res_common com; struct res_mtt *mtt; @@ -195,20 +174,21 @@ enum res_counter_states { RES_COUNTER_ALLOCATED, }; -static inline const char *counter_states_str(enum res_counter_states state) -{ - switch (state) { - case RES_COUNTER_BUSY: return "RES_COUNTER_BUSY"; - case RES_COUNTER_ALLOCATED: return "RES_COUNTER_ALLOCATED"; - default: return "Unknown"; - } -} - struct res_counter { struct res_common com; int port; }; +enum res_xrcdn_states { + RES_XRCD_BUSY = RES_ANY_BUSY, + RES_XRCD_ALLOCATED, +}; + +struct res_xrcdn { + struct res_common com; + int port; +}; + /* For Debug uses */ static const char *ResourceType(enum mlx4_resource rt) { @@ -221,6 +201,7 @@ static const char *ResourceType(enum mlx4_resource rt) case RES_MAC: return "RES_MAC"; case RES_EQ: return "RES_EQ"; case RES_COUNTER: return "RES_COUNTER"; + case RES_XRCD: return "RES_XRCD"; default: return "Unknown resource type !!!"; }; } @@ -254,16 +235,23 @@ int mlx4_init_resource_tracker(struct mlx4_dev *dev) return 0 ; } -void mlx4_free_resource_tracker(struct mlx4_dev *dev) +void mlx4_free_resource_tracker(struct mlx4_dev *dev, + enum mlx4_res_tracker_free_type type) { struct mlx4_priv *priv = mlx4_priv(dev); int i; if (priv->mfunc.master.res_tracker.slave_list) { - for (i = 0 ; i < dev->num_slaves; i++) - mlx4_delete_all_resources_for_slave(dev, i); - - kfree(priv->mfunc.master.res_tracker.slave_list); + if (type != RES_TR_FREE_STRUCTS_ONLY) + for (i = 0 ; i < dev->num_slaves; i++) + if (type == RES_TR_FREE_ALL || + dev->caps.function != i) + mlx4_delete_all_resources_for_slave(dev, i); + + if (type != RES_TR_FREE_SLAVES_ONLY) { + kfree(priv->mfunc.master.res_tracker.slave_list); + priv->mfunc.master.res_tracker.slave_list = NULL; + } } } @@ -471,6 +459,20 @@ static struct res_common *alloc_counter_tr(int id) return &ret->com; } +static struct res_common *alloc_xrcdn_tr(int id) +{ + struct res_xrcdn *ret; + + ret = kzalloc(sizeof *ret, GFP_KERNEL); + if (!ret) + return NULL; + + ret->com.res_id = id; + ret->com.state = RES_XRCD_ALLOCATED; + + return &ret->com; +} + static struct res_common *alloc_tr(int id, enum mlx4_resource type, int slave, int extra) { @@ -501,7 +503,9 @@ static struct res_common *alloc_tr(int id, enum mlx4_resource type, int slave, case RES_COUNTER: ret = alloc_counter_tr(id); break; - + case RES_XRCD: + ret = alloc_xrcdn_tr(id); + break; default: return NULL; } @@ -624,6 +628,16 @@ static int remove_counter_ok(struct res_counter *res) return 0; } +static int remove_xrcdn_ok(struct res_xrcdn *res) +{ + if (res->com.state == RES_XRCD_BUSY) + return -EBUSY; + else if (res->com.state != RES_XRCD_ALLOCATED) + return -EPERM; + + return 0; +} + static int remove_cq_ok(struct res_cq *res) { if (res->com.state == RES_CQ_BUSY) @@ -663,6 +677,8 @@ static int remove_ok(struct res_common *res, enum mlx4_resource type, int extra) return remove_eq_ok((struct res_eq *)res); case RES_COUNTER: return remove_counter_ok((struct res_counter *)res); + case RES_XRCD: + return remove_xrcdn_ok((struct res_xrcdn *)res); default: return -EINVAL; } @@ -1269,6 +1285,50 @@ static int vlan_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, return 0; } +static int counter_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, + u64 in_param, u64 *out_param) +{ + u32 index; + int err; + + if (op != RES_OP_RESERVE) + return -EINVAL; + + err = __mlx4_counter_alloc(dev, &index); + if (err) + return err; + + err = add_res_range(dev, slave, index, 1, RES_COUNTER, 0); + if (err) + __mlx4_counter_free(dev, index); + else + set_param_l(out_param, index); + + return err; +} + +static int xrcdn_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, + u64 in_param, u64 *out_param) +{ + u32 xrcdn; + int err; + + if (op != RES_OP_RESERVE) + return -EINVAL; + + err = __mlx4_xrcd_alloc(dev, &xrcdn); + if (err) + return err; + + err = add_res_range(dev, slave, xrcdn, 1, RES_XRCD, 0); + if (err) + __mlx4_xrcd_free(dev, xrcdn); + else + set_param_l(out_param, xrcdn); + + return err; +} + int mlx4_ALLOC_RES_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vhcr, struct mlx4_cmd_mailbox *inbox, @@ -1314,6 +1374,16 @@ int mlx4_ALLOC_RES_wrapper(struct mlx4_dev *dev, int slave, vhcr->in_param, &vhcr->out_param); break; + case RES_COUNTER: + err = counter_alloc_res(dev, slave, vhcr->op_modifier, alop, + vhcr->in_param, &vhcr->out_param); + break; + + case RES_XRCD: + err = xrcdn_alloc_res(dev, slave, vhcr->op_modifier, alop, + vhcr->in_param, &vhcr->out_param); + break; + default: err = -EINVAL; break; @@ -1496,6 +1566,44 @@ static int vlan_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, return 0; } +static int counter_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, + u64 in_param, u64 *out_param) +{ + int index; + int err; + + if (op != RES_OP_RESERVE) + return -EINVAL; + + index = get_param_l(&in_param); + err = rem_res_range(dev, slave, index, 1, RES_COUNTER, 0); + if (err) + return err; + + __mlx4_counter_free(dev, index); + + return err; +} + +static int xrcdn_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, + u64 in_param, u64 *out_param) +{ + int xrcdn; + int err; + + if (op != RES_OP_RESERVE) + return -EINVAL; + + xrcdn = get_param_l(&in_param); + err = rem_res_range(dev, slave, xrcdn, 1, RES_XRCD, 0); + if (err) + return err; + + __mlx4_xrcd_free(dev, xrcdn); + + return err; +} + int mlx4_FREE_RES_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vhcr, struct mlx4_cmd_mailbox *inbox, @@ -1541,6 +1649,15 @@ int mlx4_FREE_RES_wrapper(struct mlx4_dev *dev, int slave, vhcr->in_param, &vhcr->out_param); break; + case RES_COUNTER: + err = counter_free_res(dev, slave, vhcr->op_modifier, alop, + vhcr->in_param, &vhcr->out_param); + break; + + case RES_XRCD: + err = xrcdn_free_res(dev, slave, vhcr->op_modifier, alop, + vhcr->in_param, &vhcr->out_param); + default: break; } @@ -2536,7 +2653,7 @@ int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_qp qp; /* dummy for calling attach/detach */ u8 *gid = inbox->buf; enum mlx4_protocol prot = (vhcr->in_modifier >> 28) & 0x7; - int err, err1; + int err; int qpn; struct res_qp *rqp; int attach = vhcr->op_modifier; @@ -2571,7 +2688,7 @@ int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave, ex_rem: /* ignore error return below, already in error */ - err1 = rem_mcg_res(dev, slave, rqp, gid, prot, type); + (void) rem_mcg_res(dev, slave, rqp, gid, prot, type); ex_put: put_res(dev, slave, qpn, RES_QP); @@ -2604,13 +2721,12 @@ static void detach_qp(struct mlx4_dev *dev, int slave, struct res_qp *rqp) { struct res_gid *rgid; struct res_gid *tmp; - int err; struct mlx4_qp qp; /* dummy for calling attach/detach */ list_for_each_entry_safe(rgid, tmp, &rqp->mcg_list, list) { qp.qpn = rqp->local_qpn; - err = mlx4_qp_detach_common(dev, &qp, rgid->gid, rgid->prot, - rgid->steer); + (void) mlx4_qp_detach_common(dev, &qp, rgid->gid, rgid->prot, + rgid->steer); list_del(&rgid->list); kfree(rgid); } @@ -3036,14 +3152,13 @@ static void rem_slave_eqs(struct mlx4_dev *dev, int slave) MLX4_CMD_HW2SW_EQ, MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); - mlx4_dbg(dev, "rem_slave_eqs: failed" - " to move slave %d eqs %d to" - " SW ownership\n", slave, eqn); + if (err) + mlx4_dbg(dev, "rem_slave_eqs: failed" + " to move slave %d eqs %d to" + " SW ownership\n", slave, eqn); mlx4_free_cmd_mailbox(dev, mailbox); - if (!err) { - atomic_dec(&eq->mtt->ref_count); - state = RES_EQ_RESERVED; - } + atomic_dec(&eq->mtt->ref_count); + state = RES_EQ_RESERVED; break; default: @@ -3056,6 +3171,64 @@ static void rem_slave_eqs(struct mlx4_dev *dev, int slave) spin_unlock_irq(mlx4_tlock(dev)); } +static void rem_slave_counters(struct mlx4_dev *dev, int slave) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; + struct list_head *counter_list = + &tracker->slave_list[slave].res_list[RES_COUNTER]; + struct res_counter *counter; + struct res_counter *tmp; + int err; + int index; + + err = move_all_busy(dev, slave, RES_COUNTER); + if (err) + mlx4_warn(dev, "rem_slave_counters: Could not move all counters to " + "busy for slave %d\n", slave); + + spin_lock_irq(mlx4_tlock(dev)); + list_for_each_entry_safe(counter, tmp, counter_list, com.list) { + if (counter->com.owner == slave) { + index = counter->com.res_id; + radix_tree_delete(&tracker->res_tree[RES_COUNTER], index); + list_del(&counter->com.list); + kfree(counter); + __mlx4_counter_free(dev, index); + } + } + spin_unlock_irq(mlx4_tlock(dev)); +} + +static void rem_slave_xrcdns(struct mlx4_dev *dev, int slave) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; + struct list_head *xrcdn_list = + &tracker->slave_list[slave].res_list[RES_XRCD]; + struct res_xrcdn *xrcd; + struct res_xrcdn *tmp; + int err; + int xrcdn; + + err = move_all_busy(dev, slave, RES_XRCD); + if (err) + mlx4_warn(dev, "rem_slave_xrcdns: Could not move all xrcdns to " + "busy for slave %d\n", slave); + + spin_lock_irq(mlx4_tlock(dev)); + list_for_each_entry_safe(xrcd, tmp, xrcdn_list, com.list) { + if (xrcd->com.owner == slave) { + xrcdn = xrcd->com.res_id; + radix_tree_delete(&tracker->res_tree[RES_XRCD], xrcdn); + list_del(&xrcd->com.list); + kfree(xrcd); + __mlx4_xrcd_free(dev, xrcdn); + } + } + spin_unlock_irq(mlx4_tlock(dev)); +} + void mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave) { struct mlx4_priv *priv = mlx4_priv(dev); @@ -3069,5 +3242,7 @@ void mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave) rem_slave_mrs(dev, slave); rem_slave_eqs(dev, slave); rem_slave_mtts(dev, slave); + rem_slave_counters(dev, slave); + rem_slave_xrcdns(dev, slave); mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex); } diff --git a/trunk/drivers/net/ethernet/micrel/ks8842.c b/trunk/drivers/net/ethernet/micrel/ks8842.c index f84dd2dc82b6..24fb049ac2f2 100644 --- a/trunk/drivers/net/ethernet/micrel/ks8842.c +++ b/trunk/drivers/net/ethernet/micrel/ks8842.c @@ -1262,7 +1262,7 @@ static struct platform_driver ks8842_platform_driver = { .owner = THIS_MODULE, }, .probe = ks8842_probe, - .remove = ks8842_remove, + .remove = __devexit_p(ks8842_remove), }; module_platform_driver(ks8842_platform_driver); diff --git a/trunk/drivers/net/ethernet/myricom/myri10ge/myri10ge.c b/trunk/drivers/net/ethernet/myricom/myri10ge/myri10ge.c index 27273ae1a6e6..90153fc983cb 100644 --- a/trunk/drivers/net/ethernet/myricom/myri10ge/myri10ge.c +++ b/trunk/drivers/net/ethernet/myricom/myri10ge/myri10ge.c @@ -4033,7 +4033,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->netdev_ops = &myri10ge_netdev_ops; netdev->mtu = myri10ge_initial_mtu; - netdev->base_addr = mgp->iomem_base; netdev->hw_features = mgp->features | NETIF_F_LRO | NETIF_F_RXCSUM; netdev->features = netdev->hw_features; @@ -4047,12 +4046,10 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->vlan_features &= ~NETIF_F_TSO; /* make sure we can get an irq, and that MSI can be - * setup (if available). Also ensure netdev->irq - * is set to correct value if MSI is enabled */ + * setup (if available). */ status = myri10ge_request_irq(mgp); if (status != 0) goto abort_with_firmware; - netdev->irq = pdev->irq; myri10ge_free_irq(mgp); /* Save configuration space to be restored if the @@ -4077,7 +4074,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) else dev_info(dev, "%s IRQ %d, tx bndry %d, fw %s, WC %s\n", mgp->msi_enabled ? "MSI" : "xPIC", - netdev->irq, mgp->tx_boundary, mgp->fw_name, + pdev->irq, mgp->tx_boundary, mgp->fw_name, (mgp->wc_enabled ? "Enabled" : "Disabled")); board_number++; diff --git a/trunk/drivers/net/ethernet/natsemi/Kconfig b/trunk/drivers/net/ethernet/natsemi/Kconfig index eb836f770f50..f157334579fd 100644 --- a/trunk/drivers/net/ethernet/natsemi/Kconfig +++ b/trunk/drivers/net/ethernet/natsemi/Kconfig @@ -6,9 +6,8 @@ config NET_VENDOR_NATSEMI bool "National Semi-conductor devices" default y depends on AMIGA_PCMCIA || ARM || EISA || EXPERIMENTAL || H8300 || \ - ISA || M32R || MAC || MACH_JAZZ || MACH_TX49XX || MCA || \ - MCA_LEGACY || MIPS || PCI || PCMCIA || SUPERH || \ - XTENSA_PLATFORM_XT2000 || ZORRO + ISA || M32R || MAC || MACH_JAZZ || MACH_TX49XX || MIPS || \ + PCI || PCMCIA || SUPERH || XTENSA_PLATFORM_XT2000 || ZORRO ---help--- If you have a network (Ethernet) card belonging to this class, say Y and read the Ethernet-HOWTO, available from @@ -21,21 +20,6 @@ config NET_VENDOR_NATSEMI if NET_VENDOR_NATSEMI -config IBMLANA - tristate "IBM LAN Adapter/A support" - depends on MCA - ---help--- - This is a Micro Channel Ethernet adapter. You need to set - CONFIG_MCA to use this driver. It is both available as an in-kernel - driver and as a module. - - To compile this driver as a module, choose M here. The only - currently supported card is the IBM LAN Adapter/A for Ethernet. It - will both support 16K and 32K memory windows, however a 32K window - gives a better security against packet losses. Usage of multiple - boards with this driver should be possible, but has not been tested - up to now due to lack of hardware. - config MACSONIC tristate "Macintosh SONIC based ethernet (onboard, NuBus, LC, CS)" depends on MAC diff --git a/trunk/drivers/net/ethernet/natsemi/Makefile b/trunk/drivers/net/ethernet/natsemi/Makefile index 9aa5dea52b3e..764c532a96d1 100644 --- a/trunk/drivers/net/ethernet/natsemi/Makefile +++ b/trunk/drivers/net/ethernet/natsemi/Makefile @@ -2,7 +2,6 @@ # Makefile for the National Semi-conductor Sonic devices. # -obj-$(CONFIG_IBMLANA) += ibmlana.o obj-$(CONFIG_MACSONIC) += macsonic.o obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o obj-$(CONFIG_NATSEMI) += natsemi.o diff --git a/trunk/drivers/net/ethernet/natsemi/natsemi.c b/trunk/drivers/net/ethernet/natsemi/natsemi.c index d38e48d4f430..5b61d12f8b91 100644 --- a/trunk/drivers/net/ethernet/natsemi/natsemi.c +++ b/trunk/drivers/net/ethernet/natsemi/natsemi.c @@ -547,6 +547,7 @@ struct netdev_private { struct sk_buff *tx_skbuff[TX_RING_SIZE]; dma_addr_t tx_dma[TX_RING_SIZE]; struct net_device *dev; + void __iomem *ioaddr; struct napi_struct napi; /* Media monitoring timer */ struct timer_list timer; @@ -699,7 +700,9 @@ static ssize_t natsemi_set_dspcfg_workaround(struct device *dev, static inline void __iomem *ns_ioaddr(struct net_device *dev) { - return (void __iomem *) dev->base_addr; + struct netdev_private *np = netdev_priv(dev); + + return np->ioaddr; } static inline void natsemi_irq_enable(struct net_device *dev) @@ -863,10 +866,9 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, /* Store MAC Address in perm_addr */ memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN); - dev->base_addr = (unsigned long __force) ioaddr; - dev->irq = irq; - np = netdev_priv(dev); + np->ioaddr = ioaddr; + netif_napi_add(dev, &np->napi, natsemi_poll, 64); np->dev = dev; @@ -914,9 +916,6 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, } option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; - if (dev->mem_start) - option = dev->mem_start; - /* The lower four bits are the media type. */ if (option) { if (option & 0x200) @@ -1532,20 +1531,21 @@ static int netdev_open(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); void __iomem * ioaddr = ns_ioaddr(dev); + const int irq = np->pci_dev->irq; int i; /* Reset the chip, just in case. */ natsemi_reset(dev); - i = request_irq(dev->irq, intr_handler, IRQF_SHARED, dev->name, dev); + i = request_irq(irq, intr_handler, IRQF_SHARED, dev->name, dev); if (i) return i; if (netif_msg_ifup(np)) printk(KERN_DEBUG "%s: netdev_open() irq %d.\n", - dev->name, dev->irq); + dev->name, irq); i = alloc_ring(dev); if (i < 0) { - free_irq(dev->irq, dev); + free_irq(irq, dev); return i; } napi_enable(&np->napi); @@ -1794,6 +1794,7 @@ static void netdev_timer(unsigned long data) struct netdev_private *np = netdev_priv(dev); void __iomem * ioaddr = ns_ioaddr(dev); int next_tick = NATSEMI_TIMER_FREQ; + const int irq = np->pci_dev->irq; if (netif_msg_timer(np)) { /* DO NOT read the IntrStatus register, @@ -1817,14 +1818,14 @@ static void netdev_timer(unsigned long data) if (netif_msg_drv(np)) printk(KERN_NOTICE "%s: possible phy reset: " "re-initializing\n", dev->name); - disable_irq(dev->irq); + disable_irq(irq); spin_lock_irq(&np->lock); natsemi_stop_rxtx(dev); dump_ring(dev); reinit_ring(dev); init_registers(dev); spin_unlock_irq(&np->lock); - enable_irq(dev->irq); + enable_irq(irq); } else { /* hurry back */ next_tick = HZ; @@ -1841,10 +1842,10 @@ static void netdev_timer(unsigned long data) spin_unlock_irq(&np->lock); } if (np->oom) { - disable_irq(dev->irq); + disable_irq(irq); np->oom = 0; refill_rx(dev); - enable_irq(dev->irq); + enable_irq(irq); if (!np->oom) { writel(RxOn, ioaddr + ChipCmd); } else { @@ -1885,8 +1886,9 @@ static void ns_tx_timeout(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); void __iomem * ioaddr = ns_ioaddr(dev); + const int irq = np->pci_dev->irq; - disable_irq(dev->irq); + disable_irq(irq); spin_lock_irq(&np->lock); if (!np->hands_off) { if (netif_msg_tx_err(np)) @@ -1905,7 +1907,7 @@ static void ns_tx_timeout(struct net_device *dev) dev->name); } spin_unlock_irq(&np->lock); - enable_irq(dev->irq); + enable_irq(irq); dev->trans_start = jiffies; /* prevent tx timeout */ dev->stats.tx_errors++; @@ -2470,9 +2472,12 @@ static struct net_device_stats *get_stats(struct net_device *dev) #ifdef CONFIG_NET_POLL_CONTROLLER static void natsemi_poll_controller(struct net_device *dev) { - disable_irq(dev->irq); - intr_handler(dev->irq, dev); - enable_irq(dev->irq); + struct netdev_private *np = netdev_priv(dev); + const int irq = np->pci_dev->irq; + + disable_irq(irq); + intr_handler(irq, dev); + enable_irq(irq); } #endif @@ -2523,8 +2528,9 @@ static int natsemi_change_mtu(struct net_device *dev, int new_mtu) if (netif_running(dev)) { struct netdev_private *np = netdev_priv(dev); void __iomem * ioaddr = ns_ioaddr(dev); + const int irq = np->pci_dev->irq; - disable_irq(dev->irq); + disable_irq(irq); spin_lock(&np->lock); /* stop engines */ natsemi_stop_rxtx(dev); @@ -2537,7 +2543,7 @@ static int natsemi_change_mtu(struct net_device *dev, int new_mtu) /* restart engines */ writel(RxOn | TxOn, ioaddr + ChipCmd); spin_unlock(&np->lock); - enable_irq(dev->irq); + enable_irq(irq); } return 0; } @@ -3135,6 +3141,7 @@ static int netdev_close(struct net_device *dev) { void __iomem * ioaddr = ns_ioaddr(dev); struct netdev_private *np = netdev_priv(dev); + const int irq = np->pci_dev->irq; if (netif_msg_ifdown(np)) printk(KERN_DEBUG @@ -3156,14 +3163,14 @@ static int netdev_close(struct net_device *dev) */ del_timer_sync(&np->timer); - disable_irq(dev->irq); + disable_irq(irq); spin_lock_irq(&np->lock); natsemi_irq_disable(dev); np->hands_off = 1; spin_unlock_irq(&np->lock); - enable_irq(dev->irq); + enable_irq(irq); - free_irq(dev->irq, dev); + free_irq(irq, dev); /* Interrupt disabled, interrupt handler released, * queue stopped, timer deleted, rtnl_lock held @@ -3256,9 +3263,11 @@ static int natsemi_suspend (struct pci_dev *pdev, pm_message_t state) rtnl_lock(); if (netif_running (dev)) { + const int irq = np->pci_dev->irq; + del_timer_sync(&np->timer); - disable_irq(dev->irq); + disable_irq(irq); spin_lock_irq(&np->lock); natsemi_irq_disable(dev); @@ -3267,7 +3276,7 @@ static int natsemi_suspend (struct pci_dev *pdev, pm_message_t state) netif_stop_queue(dev); spin_unlock_irq(&np->lock); - enable_irq(dev->irq); + enable_irq(irq); napi_disable(&np->napi); @@ -3307,6 +3316,8 @@ static int natsemi_resume (struct pci_dev *pdev) if (netif_device_present(dev)) goto out; if (netif_running(dev)) { + const int irq = np->pci_dev->irq; + BUG_ON(!np->hands_off); ret = pci_enable_device(pdev); if (ret < 0) { @@ -3320,13 +3331,13 @@ static int natsemi_resume (struct pci_dev *pdev) natsemi_reset(dev); init_ring(dev); - disable_irq(dev->irq); + disable_irq(irq); spin_lock_irq(&np->lock); np->hands_off = 0; init_registers(dev); netif_device_attach(dev); spin_unlock_irq(&np->lock); - enable_irq(dev->irq); + enable_irq(irq); mod_timer(&np->timer, round_jiffies(jiffies + 1*HZ)); } diff --git a/trunk/drivers/net/ethernet/neterion/s2io.c b/trunk/drivers/net/ethernet/neterion/s2io.c index 6338ef8606ae..bb367582c1e8 100644 --- a/trunk/drivers/net/ethernet/neterion/s2io.c +++ b/trunk/drivers/net/ethernet/neterion/s2io.c @@ -2846,6 +2846,7 @@ static int s2io_poll_inta(struct napi_struct *napi, int budget) static void s2io_netpoll(struct net_device *dev) { struct s2io_nic *nic = netdev_priv(dev); + const int irq = nic->pdev->irq; struct XENA_dev_config __iomem *bar0 = nic->bar0; u64 val64 = 0xFFFFFFFFFFFFFFFFULL; int i; @@ -2855,7 +2856,7 @@ static void s2io_netpoll(struct net_device *dev) if (pci_channel_offline(nic->pdev)) return; - disable_irq(dev->irq); + disable_irq(irq); writeq(val64, &bar0->rx_traffic_int); writeq(val64, &bar0->tx_traffic_int); @@ -2884,7 +2885,7 @@ static void s2io_netpoll(struct net_device *dev) break; } } - enable_irq(dev->irq); + enable_irq(irq); } #endif @@ -3897,9 +3898,7 @@ static void remove_msix_isr(struct s2io_nic *sp) static void remove_inta_isr(struct s2io_nic *sp) { - struct net_device *dev = sp->dev; - - free_irq(sp->pdev->irq, dev); + free_irq(sp->pdev->irq, sp->dev); } /* ********************************************************* * @@ -7046,7 +7045,7 @@ static int s2io_add_isr(struct s2io_nic *sp) } } if (sp->config.intr_type == INTA) { - err = request_irq((int)sp->pdev->irq, s2io_isr, IRQF_SHARED, + err = request_irq(sp->pdev->irq, s2io_isr, IRQF_SHARED, sp->name, dev); if (err) { DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n", @@ -7908,9 +7907,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) goto bar1_remap_failed; } - dev->irq = pdev->irq; - dev->base_addr = (unsigned long)sp->bar0; - /* Initializing the BAR1 address as the start of the FIFO pointer. */ for (j = 0; j < MAX_TX_FIFOS; j++) { mac_control->tx_FIFO_start[j] = sp->bar1 + (j * 0x00020000); diff --git a/trunk/drivers/net/ethernet/neterion/vxge/vxge-main.c b/trunk/drivers/net/ethernet/neterion/vxge/vxge-main.c index ef76725454d2..51387c31914b 100644 --- a/trunk/drivers/net/ethernet/neterion/vxge/vxge-main.c +++ b/trunk/drivers/net/ethernet/neterion/vxge/vxge-main.c @@ -1882,25 +1882,24 @@ static int vxge_poll_inta(struct napi_struct *napi, int budget) */ static void vxge_netpoll(struct net_device *dev) { - struct __vxge_hw_device *hldev; - struct vxgedev *vdev; - - vdev = netdev_priv(dev); - hldev = pci_get_drvdata(vdev->pdev); + struct vxgedev *vdev = netdev_priv(dev); + struct pci_dev *pdev = vdev->pdev; + struct __vxge_hw_device *hldev = pci_get_drvdata(pdev); + const int irq = pdev->irq; vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__); - if (pci_channel_offline(vdev->pdev)) + if (pci_channel_offline(pdev)) return; - disable_irq(dev->irq); + disable_irq(irq); vxge_hw_device_clear_tx_rx(hldev); vxge_hw_device_clear_tx_rx(hldev); VXGE_COMPLETE_ALL_RX(vdev); VXGE_COMPLETE_ALL_TX(vdev); - enable_irq(dev->irq); + enable_irq(irq); vxge_debug_entryexit(VXGE_TRACE, "%s:%d Exiting...", __func__, __LINE__); @@ -2860,12 +2859,12 @@ static int vxge_open(struct net_device *dev) vdev->config.rx_pause_enable); if (vdev->vp_reset_timer.function == NULL) - vxge_os_timer(vdev->vp_reset_timer, - vxge_poll_vp_reset, vdev, (HZ/2)); + vxge_os_timer(&vdev->vp_reset_timer, vxge_poll_vp_reset, vdev, + HZ / 2); /* There is no need to check for RxD leak and RxD lookup on Titan1A */ if (vdev->titan1 && vdev->vp_lockup_timer.function == NULL) - vxge_os_timer(vdev->vp_lockup_timer, vxge_poll_vp_lockup, vdev, + vxge_os_timer(&vdev->vp_lockup_timer, vxge_poll_vp_lockup, vdev, HZ / 2); set_bit(__VXGE_STATE_CARD_UP, &vdev->state); @@ -3424,9 +3423,6 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev, ndev->features |= ndev->hw_features | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; - /* Driver entry points */ - ndev->irq = vdev->pdev->irq; - ndev->base_addr = (unsigned long) hldev->bar0; ndev->netdev_ops = &vxge_netdev_ops; diff --git a/trunk/drivers/net/ethernet/neterion/vxge/vxge-main.h b/trunk/drivers/net/ethernet/neterion/vxge/vxge-main.h index f52a42d1dbb7..35f3e7552ec2 100644 --- a/trunk/drivers/net/ethernet/neterion/vxge/vxge-main.h +++ b/trunk/drivers/net/ethernet/neterion/vxge/vxge-main.h @@ -416,12 +416,15 @@ struct vxge_tx_priv { static int p = val; \ module_param(p, int, 0) -#define vxge_os_timer(timer, handle, arg, exp) do { \ - init_timer(&timer); \ - timer.function = handle; \ - timer.data = (unsigned long) arg; \ - mod_timer(&timer, (jiffies + exp)); \ - } while (0); +static inline +void vxge_os_timer(struct timer_list *timer, void (*func)(unsigned long data), + struct vxgedev *vdev, unsigned long timeout) +{ + init_timer(timer); + timer->function = func; + timer->data = (unsigned long)vdev; + mod_timer(timer, jiffies + timeout); +} void vxge_initialize_ethtool_ops(struct net_device *ndev); enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev); diff --git a/trunk/drivers/net/ethernet/nvidia/forcedeth.c b/trunk/drivers/net/ethernet/nvidia/forcedeth.c index aca13046e432..928913c4f3ff 100644 --- a/trunk/drivers/net/ethernet/nvidia/forcedeth.c +++ b/trunk/drivers/net/ethernet/nvidia/forcedeth.c @@ -2279,6 +2279,8 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev) netdev_sent_queue(np->dev, skb->len); + skb_tx_timestamp(skb); + np->put_tx.orig = put_tx; spin_unlock_irqrestore(&np->lock, flags); @@ -2426,6 +2428,8 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb, netdev_sent_queue(np->dev, skb->len); + skb_tx_timestamp(skb); + np->put_tx.ex = put_tx; spin_unlock_irqrestore(&np->lock, flags); @@ -3942,13 +3946,11 @@ static int nv_request_irq(struct net_device *dev, int intr_test) ret = pci_enable_msi(np->pci_dev); if (ret == 0) { np->msi_flags |= NV_MSI_ENABLED; - dev->irq = np->pci_dev->irq; if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0) { netdev_info(dev, "request_irq failed %d\n", ret); pci_disable_msi(np->pci_dev); np->msi_flags &= ~NV_MSI_ENABLED; - dev->irq = np->pci_dev->irq; goto out_err; } @@ -5649,9 +5651,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i np->base = ioremap(addr, np->register_size); if (!np->base) goto out_relreg; - dev->base_addr = (unsigned long)np->base; - - dev->irq = pci_dev->irq; np->rx_ring_size = RX_RING_DEFAULT; np->tx_ring_size = TX_RING_DEFAULT; diff --git a/trunk/drivers/net/ethernet/nxp/lpc_eth.c b/trunk/drivers/net/ethernet/nxp/lpc_eth.c index 6dfc26d85e47..8d2666fcffd7 100644 --- a/trunk/drivers/net/ethernet/nxp/lpc_eth.c +++ b/trunk/drivers/net/ethernet/nxp/lpc_eth.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -340,13 +341,17 @@ */ #define LPC_POWERDOWN_MACAHB (1 << 31) -/* Upon the upcoming introduction of device tree usage in LPC32xx, - * lpc_phy_interface_mode() and use_iram_for_net() will be extended with a - * device parameter for access to device tree information at runtime, instead - * of defining the values at compile time - */ -static inline phy_interface_t lpc_phy_interface_mode(void) +static phy_interface_t lpc_phy_interface_mode(struct device *dev) { + if (dev && dev->of_node) { + const char *mode = of_get_property(dev->of_node, + "phy-mode", NULL); + if (mode && !strcmp(mode, "mii")) + return PHY_INTERFACE_MODE_MII; + return PHY_INTERFACE_MODE_RMII; + } + + /* non-DT */ #ifdef CONFIG_ARCH_LPC32XX_MII_SUPPORT return PHY_INTERFACE_MODE_MII; #else @@ -354,12 +359,16 @@ static inline phy_interface_t lpc_phy_interface_mode(void) #endif } -static inline int use_iram_for_net(void) +static bool use_iram_for_net(struct device *dev) { + if (dev && dev->of_node) + return of_property_read_bool(dev->of_node, "use-iram"); + + /* non-DT */ #ifdef CONFIG_ARCH_LPC32XX_IRAM_FOR_NET - return 1; + return true; #else - return 0; + return false; #endif } @@ -664,7 +673,7 @@ static void __lpc_eth_init(struct netdata_local *pldat) LPC_ENET_CLRT(pldat->net_base)); writel(LPC_IPGR_LOAD_PART2(0x12), LPC_ENET_IPGR(pldat->net_base)); - if (lpc_phy_interface_mode() == PHY_INTERFACE_MODE_MII) + if (lpc_phy_interface_mode(&pldat->pdev->dev) == PHY_INTERFACE_MODE_MII) writel(LPC_COMMAND_PASSRUNTFRAME, LPC_ENET_COMMAND(pldat->net_base)); else { @@ -804,12 +813,13 @@ static int lpc_mii_probe(struct net_device *ndev) } /* Attach to the PHY */ - if (lpc_phy_interface_mode() == PHY_INTERFACE_MODE_MII) + if (lpc_phy_interface_mode(&pldat->pdev->dev) == PHY_INTERFACE_MODE_MII) netdev_info(ndev, "using MII interface\n"); else netdev_info(ndev, "using RMII interface\n"); phydev = phy_connect(ndev, dev_name(&phydev->dev), - &lpc_handle_link_change, 0, lpc_phy_interface_mode()); + &lpc_handle_link_change, 0, + lpc_phy_interface_mode(&pldat->pdev->dev)); if (IS_ERR(phydev)) { netdev_err(ndev, "Could not attach to PHY\n"); @@ -843,7 +853,7 @@ static int lpc_mii_init(struct netdata_local *pldat) } /* Setup MII mode */ - if (lpc_phy_interface_mode() == PHY_INTERFACE_MODE_MII) + if (lpc_phy_interface_mode(&pldat->pdev->dev) == PHY_INTERFACE_MODE_MII) writel(LPC_COMMAND_PASSRUNTFRAME, LPC_ENET_COMMAND(pldat->net_base)); else { @@ -990,10 +1000,10 @@ static int __lpc_handle_recv(struct net_device *ndev, int budget) ndev->stats.rx_errors++; } else { /* Packet is good */ - skb = dev_alloc_skb(len + 8); - if (!skb) + skb = dev_alloc_skb(len); + if (!skb) { ndev->stats.rx_dropped++; - else { + } else { prdbuf = skb_put(skb, len); /* Copy packet from buffer */ @@ -1315,18 +1325,26 @@ static const struct net_device_ops lpc_netdev_ops = { static int lpc_eth_drv_probe(struct platform_device *pdev) { struct resource *res; - struct resource *dma_res; struct net_device *ndev; struct netdata_local *pldat; struct phy_device *phydev; dma_addr_t dma_handle; int irq, ret; + u32 tmp; + + /* Setup network interface for RMII or MII mode */ + tmp = __raw_readl(LPC32XX_CLKPWR_MACCLK_CTRL); + tmp &= ~LPC32XX_CLKPWR_MACCTRL_PINS_MSK; + if (lpc_phy_interface_mode(&pdev->dev) == PHY_INTERFACE_MODE_MII) + tmp |= LPC32XX_CLKPWR_MACCTRL_USE_MII_PINS; + else + tmp |= LPC32XX_CLKPWR_MACCTRL_USE_RMII_PINS; + __raw_writel(tmp, LPC32XX_CLKPWR_MACCLK_CTRL); /* Get platform resources */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dma_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); irq = platform_get_irq(pdev, 0); - if ((!res) || (!dma_res) || (irq < 0) || (irq >= NR_IRQS)) { + if ((!res) || (irq < 0) || (irq >= NR_IRQS)) { dev_err(&pdev->dev, "error getting resources.\n"); ret = -ENXIO; goto err_exit; @@ -1389,17 +1407,19 @@ static int lpc_eth_drv_probe(struct platform_device *pdev) sizeof(struct txrx_desc_t) + sizeof(struct rx_status_t)); pldat->dma_buff_base_v = 0; - if (use_iram_for_net()) { - dma_handle = dma_res->start; + if (use_iram_for_net(&pldat->pdev->dev)) { + dma_handle = LPC32XX_IRAM_BASE; if (pldat->dma_buff_size <= lpc32xx_return_iram_size()) pldat->dma_buff_base_v = - io_p2v(dma_res->start); + io_p2v(LPC32XX_IRAM_BASE); else netdev_err(ndev, "IRAM not big enough for net buffers, using SDRAM instead.\n"); } if (pldat->dma_buff_base_v == 0) { + pldat->pdev->dev.coherent_dma_mask = 0xFFFFFFFF; + pldat->pdev->dev.dma_mask = &pldat->pdev->dev.coherent_dma_mask; pldat->dma_buff_size = PAGE_ALIGN(pldat->dma_buff_size); /* Allocate a chunk of memory for the DMA ethernet buffers @@ -1488,7 +1508,7 @@ static int lpc_eth_drv_probe(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); unregister_netdev(ndev); err_out_dma_unmap: - if (!use_iram_for_net() || + if (!use_iram_for_net(&pldat->pdev->dev) || pldat->dma_buff_size > lpc32xx_return_iram_size()) dma_free_coherent(&pldat->pdev->dev, pldat->dma_buff_size, pldat->dma_buff_base_v, @@ -1515,7 +1535,7 @@ static int lpc_eth_drv_remove(struct platform_device *pdev) unregister_netdev(ndev); platform_set_drvdata(pdev, NULL); - if (!use_iram_for_net() || + if (!use_iram_for_net(&pldat->pdev->dev) || pldat->dma_buff_size > lpc32xx_return_iram_size()) dma_free_coherent(&pldat->pdev->dev, pldat->dma_buff_size, pldat->dma_buff_base_v, @@ -1584,6 +1604,14 @@ static int lpc_eth_drv_resume(struct platform_device *pdev) } #endif +#ifdef CONFIG_OF +static const struct of_device_id lpc_eth_match[] = { + { .compatible = "nxp,lpc-eth" }, + { } +}; +MODULE_DEVICE_TABLE(of, lpc_eth_match); +#endif + static struct platform_driver lpc_eth_driver = { .probe = lpc_eth_drv_probe, .remove = __devexit_p(lpc_eth_drv_remove), @@ -1593,6 +1621,7 @@ static struct platform_driver lpc_eth_driver = { #endif .driver = { .name = MODNAME, + .of_match_table = of_match_ptr(lpc_eth_match), }, }; diff --git a/trunk/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h b/trunk/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h index ba781747d174..b07311eaa693 100644 --- a/trunk/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h +++ b/trunk/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h @@ -658,6 +658,7 @@ extern u32 pch_src_uuid_lo_read(struct pci_dev *pdev); extern u32 pch_src_uuid_hi_read(struct pci_dev *pdev); extern u64 pch_rx_snap_read(struct pci_dev *pdev); extern u64 pch_tx_snap_read(struct pci_dev *pdev); +extern int pch_set_station_address(u8 *addr, struct pci_dev *pdev); #endif /* pch_gbe_param.c */ diff --git a/trunk/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/trunk/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c index 1e38d502a062..3787c64ee71c 100644 --- a/trunk/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c +++ b/trunk/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c @@ -79,7 +79,6 @@ const char pch_driver_version[] = DRV_VERSION; #define PCH_GBE_PAUSE_PKT4_VALUE 0x01000888 #define PCH_GBE_PAUSE_PKT5_VALUE 0x0000FFFF -#define PCH_GBE_ETH_ALEN 6 /* This defines the bits that are set in the Interrupt Mask * Set/Read Register. Each bit is documented below: @@ -101,18 +100,19 @@ const char pch_driver_version[] = DRV_VERSION; #ifdef CONFIG_PCH_PTP /* Macros for ieee1588 */ -#define TICKS_NS_SHIFT 5 - /* 0x40 Time Synchronization Channel Control Register Bits */ #define MASTER_MODE (1<<0) -#define SLAVE_MODE (0<<0) +#define SLAVE_MODE (0) #define V2_MODE (1<<31) -#define CAP_MODE0 (0<<16) +#define CAP_MODE0 (0) #define CAP_MODE2 (1<<17) /* 0x44 Time Synchronization Channel Event Register Bits */ #define TX_SNAPSHOT_LOCKED (1<<0) #define RX_SNAPSHOT_LOCKED (1<<1) + +#define PTP_L4_MULTICAST_SA "01:00:5e:00:01:81" +#define PTP_L2_MULTICAST_SA "01:1b:19:00:00:00" #endif static unsigned int copybreak __read_mostly = PCH_GBE_COPYBREAK_DEFAULT; @@ -120,6 +120,7 @@ static unsigned int copybreak __read_mostly = PCH_GBE_COPYBREAK_DEFAULT; static int pch_gbe_mdio_read(struct net_device *netdev, int addr, int reg); static void pch_gbe_mdio_write(struct net_device *netdev, int addr, int reg, int data); +static void pch_gbe_set_multi(struct net_device *netdev); #ifdef CONFIG_PCH_PTP static struct sock_filter ptp_filter[] = { @@ -133,10 +134,8 @@ static int pch_ptp_match(struct sk_buff *skb, u16 uid_hi, u32 uid_lo, u16 seqid) u16 *hi, *id; u32 lo; - if ((sk_run_filter(skb, ptp_filter) != PTP_CLASS_V2_IPV4) && - (sk_run_filter(skb, ptp_filter) != PTP_CLASS_V1_IPV4)) { + if (sk_run_filter(skb, ptp_filter) == PTP_CLASS_NONE) return 0; - } offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN; @@ -153,8 +152,8 @@ static int pch_ptp_match(struct sk_buff *skb, u16 uid_hi, u32 uid_lo, u16 seqid) seqid == *id); } -static void pch_rx_timestamp( - struct pch_gbe_adapter *adapter, struct sk_buff *skb) +static void +pch_rx_timestamp(struct pch_gbe_adapter *adapter, struct sk_buff *skb) { struct skb_shared_hwtstamps *shhwtstamps; struct pci_dev *pdev; @@ -183,7 +182,6 @@ static void pch_rx_timestamp( goto out; ns = pch_rx_snap_read(pdev); - ns <<= TICKS_NS_SHIFT; shhwtstamps = skb_hwtstamps(skb); memset(shhwtstamps, 0, sizeof(*shhwtstamps)); @@ -192,8 +190,8 @@ static void pch_rx_timestamp( pch_ch_event_write(pdev, RX_SNAPSHOT_LOCKED); } -static void pch_tx_timestamp( - struct pch_gbe_adapter *adapter, struct sk_buff *skb) +static void +pch_tx_timestamp(struct pch_gbe_adapter *adapter, struct sk_buff *skb) { struct skb_shared_hwtstamps shhwtstamps; struct pci_dev *pdev; @@ -202,17 +200,16 @@ static void pch_tx_timestamp( u32 cnt, val; shtx = skb_shinfo(skb); - if (unlikely(shtx->tx_flags & SKBTX_HW_TSTAMP && adapter->hwts_tx_en)) - shtx->tx_flags |= SKBTX_IN_PROGRESS; - else + if (likely(!(shtx->tx_flags & SKBTX_HW_TSTAMP && adapter->hwts_tx_en))) return; + shtx->tx_flags |= SKBTX_IN_PROGRESS; + /* Get ieee1588's dev information */ pdev = adapter->ptp_pdev; /* * This really stinks, but we have to poll for the Tx time stamp. - * Usually, the time stamp is ready after 4 to 6 microseconds. */ for (cnt = 0; cnt < 100; cnt++) { val = pch_ch_event_read(pdev); @@ -226,7 +223,6 @@ static void pch_tx_timestamp( } ns = pch_tx_snap_read(pdev); - ns <<= TICKS_NS_SHIFT; memset(&shhwtstamps, 0, sizeof(shhwtstamps)); shhwtstamps.hwtstamp = ns_to_ktime(ns); @@ -240,6 +236,7 @@ static int hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) struct hwtstamp_config cfg; struct pch_gbe_adapter *adapter = netdev_priv(netdev); struct pci_dev *pdev; + u8 station[20]; if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) return -EFAULT; @@ -267,15 +264,23 @@ static int hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) break; case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: adapter->hwts_rx_en = 0; - pch_ch_control_write(pdev, (SLAVE_MODE | CAP_MODE0)); + pch_ch_control_write(pdev, SLAVE_MODE | CAP_MODE0); break; case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: adapter->hwts_rx_en = 1; - pch_ch_control_write(pdev, (MASTER_MODE | CAP_MODE0)); + pch_ch_control_write(pdev, MASTER_MODE | CAP_MODE0); + break; + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: + adapter->hwts_rx_en = 1; + pch_ch_control_write(pdev, V2_MODE | CAP_MODE2); + strcpy(station, PTP_L4_MULTICAST_SA); + pch_set_station_address(station, pdev); break; - case HWTSTAMP_FILTER_PTP_V2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: adapter->hwts_rx_en = 1; - pch_ch_control_write(pdev, (V2_MODE | CAP_MODE2)); + pch_ch_control_write(pdev, V2_MODE | CAP_MODE2); + strcpy(station, PTP_L2_MULTICAST_SA); + pch_set_station_address(station, pdev); break; default: return -ERANGE; @@ -399,18 +404,18 @@ static void pch_gbe_mac_reset_hw(struct pch_gbe_hw *hw) iowrite32(PCH_GBE_MODE_GMII_ETHER, &hw->reg->MODE); #endif pch_gbe_wait_clr_bit(&hw->reg->RESET, PCH_GBE_ALL_RST); - /* Setup the receive address */ + /* Setup the receive addresses */ pch_gbe_mac_mar_set(hw, hw->mac.addr, 0); return; } static void pch_gbe_mac_reset_rx(struct pch_gbe_hw *hw) { - /* Read the MAC address. and store to the private data */ + /* Read the MAC addresses. and store to the private data */ pch_gbe_mac_read_mac_addr(hw); iowrite32(PCH_GBE_RX_RST, &hw->reg->RESET); pch_gbe_wait_clr_bit_irq(&hw->reg->RESET, PCH_GBE_RX_RST); - /* Setup the MAC address */ + /* Setup the MAC addresses */ pch_gbe_mac_mar_set(hw, hw->mac.addr, 0); return; } @@ -460,7 +465,7 @@ static void pch_gbe_mac_mc_addr_list_update(struct pch_gbe_hw *hw, if (mc_addr_count) { pch_gbe_mac_mar_set(hw, mc_addr_list, i); mc_addr_count--; - mc_addr_list += PCH_GBE_ETH_ALEN; + mc_addr_list += ETH_ALEN; } else { /* Clear MAC address mask */ adrmask = ioread32(&hw->reg->ADDR_MASK); @@ -775,6 +780,8 @@ void pch_gbe_reinit_locked(struct pch_gbe_adapter *adapter) void pch_gbe_reset(struct pch_gbe_adapter *adapter) { pch_gbe_mac_reset_hw(&adapter->hw); + /* reprogram multicast address register after reset */ + pch_gbe_set_multi(adapter->netdev); /* Setup the receive address. */ pch_gbe_mac_init_rx_addrs(&adapter->hw, PCH_GBE_MAR_ENTRIES); if (pch_gbe_hal_init_hw(&adapter->hw)) @@ -1178,8 +1185,6 @@ static void pch_gbe_tx_queue(struct pch_gbe_adapter *adapter, if (skb->protocol == htons(ETH_P_IP)) { struct iphdr *iph = ip_hdr(skb); unsigned int offset; - iph->check = 0; - iph->check = ip_fast_csum((u8 *) iph, iph->ihl); offset = skb_transport_offset(skb); if (iph->protocol == IPPROTO_TCP) { skb->csum = 0; @@ -1338,6 +1343,8 @@ static void pch_gbe_stop_receive(struct pch_gbe_adapter *adapter) /* Stop Receive */ pch_gbe_mac_reset_rx(hw); } + /* reprogram multicast address register after reset */ + pch_gbe_set_multi(adapter->netdev); } static void pch_gbe_start_receive(struct pch_gbe_hw *hw) @@ -1922,7 +1929,6 @@ static int pch_gbe_request_irq(struct pch_gbe_adapter *adapter) } -static void pch_gbe_set_multi(struct net_device *netdev); /** * pch_gbe_up - Up GbE network device * @adapter: Board private structure diff --git a/trunk/drivers/net/ethernet/packetengines/hamachi.c b/trunk/drivers/net/ethernet/packetengines/hamachi.c index 0d29f5f4b8e4..c2367158350e 100644 --- a/trunk/drivers/net/ethernet/packetengines/hamachi.c +++ b/trunk/drivers/net/ethernet/packetengines/hamachi.c @@ -683,8 +683,6 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev, } hmp->base = ioaddr; - dev->base_addr = (unsigned long)ioaddr; - dev->irq = irq; pci_set_drvdata(pdev, dev); hmp->chip_id = chip_id; @@ -859,14 +857,11 @@ static int hamachi_open(struct net_device *dev) u32 rx_int_var, tx_int_var; u16 fifo_info; - i = request_irq(dev->irq, hamachi_interrupt, IRQF_SHARED, dev->name, dev); + i = request_irq(hmp->pci_dev->irq, hamachi_interrupt, IRQF_SHARED, + dev->name, dev); if (i) return i; - if (hamachi_debug > 1) - printk(KERN_DEBUG "%s: hamachi_open() irq %d.\n", - dev->name, dev->irq); - hamachi_init_ring(dev); #if ADDRLEN == 64 @@ -1705,7 +1700,7 @@ static int hamachi_close(struct net_device *dev) } #endif /* __i386__ debugging only */ - free_irq(dev->irq, dev); + free_irq(hmp->pci_dev->irq, dev); del_timer_sync(&hmp->timer); diff --git a/trunk/drivers/net/ethernet/packetengines/yellowfin.c b/trunk/drivers/net/ethernet/packetengines/yellowfin.c index 7757b80ef924..04e622fd468d 100644 --- a/trunk/drivers/net/ethernet/packetengines/yellowfin.c +++ b/trunk/drivers/net/ethernet/packetengines/yellowfin.c @@ -427,9 +427,6 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev, /* Reset the chip. */ iowrite32(0x80000000, ioaddr + DMACtrl); - dev->base_addr = (unsigned long)ioaddr; - dev->irq = irq; - pci_set_drvdata(pdev, dev); spin_lock_init(&np->lock); @@ -569,25 +566,20 @@ static void mdio_write(void __iomem *ioaddr, int phy_id, int location, int value static int yellowfin_open(struct net_device *dev) { struct yellowfin_private *yp = netdev_priv(dev); + const int irq = yp->pci_dev->irq; void __iomem *ioaddr = yp->base; - int i, ret; + int i, rc; /* Reset the chip. */ iowrite32(0x80000000, ioaddr + DMACtrl); - ret = request_irq(dev->irq, yellowfin_interrupt, IRQF_SHARED, dev->name, dev); - if (ret) - return ret; - - if (yellowfin_debug > 1) - netdev_printk(KERN_DEBUG, dev, "%s() irq %d\n", - __func__, dev->irq); + rc = request_irq(irq, yellowfin_interrupt, IRQF_SHARED, dev->name, dev); + if (rc) + return rc; - ret = yellowfin_init_ring(dev); - if (ret) { - free_irq(dev->irq, dev); - return ret; - } + rc = yellowfin_init_ring(dev); + if (rc < 0) + goto err_free_irq; iowrite32(yp->rx_ring_dma, ioaddr + RxPtr); iowrite32(yp->tx_ring_dma, ioaddr + TxPtr); @@ -647,8 +639,12 @@ static int yellowfin_open(struct net_device *dev) yp->timer.data = (unsigned long)dev; yp->timer.function = yellowfin_timer; /* timer handler */ add_timer(&yp->timer); +out: + return rc; - return 0; +err_free_irq: + free_irq(irq, dev); + goto out; } static void yellowfin_timer(unsigned long data) @@ -1251,7 +1247,7 @@ static int yellowfin_close(struct net_device *dev) } #endif /* __i386__ debugging only */ - free_irq(dev->irq, dev); + free_irq(yp->pci_dev->irq, dev); /* Free all the skbuffs in the Rx queue. */ for (i = 0; i < RX_RING_SIZE; i++) { diff --git a/trunk/drivers/net/ethernet/pasemi/pasemi_mac.c b/trunk/drivers/net/ethernet/pasemi/pasemi_mac.c index ddc95b0ac78d..e559dfa06d6a 100644 --- a/trunk/drivers/net/ethernet/pasemi/pasemi_mac.c +++ b/trunk/drivers/net/ethernet/pasemi/pasemi_mac.c @@ -623,7 +623,7 @@ static void pasemi_mac_free_rx_resources(struct pasemi_mac *mac) mac->rx = NULL; } -static void pasemi_mac_replenish_rx_ring(const struct net_device *dev, +static void pasemi_mac_replenish_rx_ring(struct net_device *dev, const int limit) { const struct pasemi_mac *mac = netdev_priv(dev); diff --git a/trunk/drivers/net/ethernet/qlogic/netxen/netxen_nic.h b/trunk/drivers/net/ethernet/qlogic/netxen/netxen_nic.h index b5de8a7b90f1..37ccbe54e62d 100644 --- a/trunk/drivers/net/ethernet/qlogic/netxen/netxen_nic.h +++ b/trunk/drivers/net/ethernet/qlogic/netxen/netxen_nic.h @@ -53,8 +53,8 @@ #define _NETXEN_NIC_LINUX_MAJOR 4 #define _NETXEN_NIC_LINUX_MINOR 0 -#define _NETXEN_NIC_LINUX_SUBVERSION 78 -#define NETXEN_NIC_LINUX_VERSIONID "4.0.78" +#define _NETXEN_NIC_LINUX_SUBVERSION 79 +#define NETXEN_NIC_LINUX_VERSIONID "4.0.79" #define NETXEN_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c)) #define _major(v) (((v) >> 24) & 0xff) @@ -419,6 +419,8 @@ struct rcv_desc { (((sts_data) >> 52) & 0x1) #define netxen_get_lro_sts_seq_number(sts_data) \ ((sts_data) & 0x0FFFFFFFF) +#define netxen_get_lro_sts_mss(sts_data1) \ + ((sts_data1 >> 32) & 0x0FFFF) struct status_desc { @@ -794,6 +796,7 @@ struct netxen_cmd_args { #define NX_CAP0_JUMBO_CONTIGUOUS NX_CAP_BIT(0, 7) #define NX_CAP0_LRO_CONTIGUOUS NX_CAP_BIT(0, 8) #define NX_CAP0_HW_LRO NX_CAP_BIT(0, 10) +#define NX_CAP0_HW_LRO_MSS NX_CAP_BIT(0, 21) /* * Context state @@ -1073,6 +1076,8 @@ typedef struct { #define NX_FW_CAPABILITY_FVLANTX (1 << 9) #define NX_FW_CAPABILITY_HW_LRO (1 << 10) #define NX_FW_CAPABILITY_GBE_LINK_CFG (1 << 11) +#define NX_FW_CAPABILITY_MORE_CAPS (1 << 31) +#define NX_FW_CAPABILITY_2_LRO_MAX_TCP_SEG (1 << 2) /* module types */ #define LINKEVENT_MODULE_NOT_PRESENT 1 @@ -1155,6 +1160,7 @@ typedef struct { #define NETXEN_NIC_BRIDGE_ENABLED 0X10 #define NETXEN_NIC_DIAG_ENABLED 0x20 #define NETXEN_FW_RESET_OWNER 0x40 +#define NETXEN_FW_MSS_CAP 0x80 #define NETXEN_IS_MSI_FAMILY(adapter) \ ((adapter)->flags & (NETXEN_NIC_MSI_ENABLED | NETXEN_NIC_MSIX_ENABLED)) @@ -1201,6 +1207,9 @@ typedef struct { #define NX_FORCE_FW_RESET 0xdeaddead +/* Fw dump levels */ +static const u32 FW_DUMP_LEVELS[] = { 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff }; + /* Flash read/write address */ #define NX_FW_DUMP_REG1 0x00130060 #define NX_FW_DUMP_REG2 0x001e0000 @@ -1814,6 +1823,13 @@ struct netxen_brdinfo { char short_name[NETXEN_MAX_SHORT_NAME]; }; +struct netxen_dimm_cfg { + u8 presence; + u8 mem_type; + u8 dimm_type; + u32 size; +}; + static const struct netxen_brdinfo netxen_boards[] = { {NETXEN_BRDTYPE_P2_SB31_10G_CX4, 1, "XGb CX4"}, {NETXEN_BRDTYPE_P2_SB31_10G_HMEZ, 1, "XGb HMEZ"}, diff --git a/trunk/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c b/trunk/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c index f3c0057a802b..7f556a84925d 100644 --- a/trunk/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c +++ b/trunk/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c @@ -229,7 +229,7 @@ netxen_setup_minidump(struct netxen_adapter *adapter) adapter->mdump.md_template; adapter->mdump.md_capture_buff = NULL; adapter->mdump.fw_supports_md = 1; - adapter->mdump.md_enabled = 1; + adapter->mdump.md_enabled = 0; return err; @@ -328,6 +328,9 @@ nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter) cap = (NX_CAP0_LEGACY_CONTEXT | NX_CAP0_LEGACY_MN); cap |= (NX_CAP0_JUMBO_CONTIGUOUS | NX_CAP0_LRO_CONTIGUOUS); + if (adapter->flags & NETXEN_FW_MSS_CAP) + cap |= NX_CAP0_HW_LRO_MSS; + prq->capabilities[0] = cpu_to_le32(cap); prq->host_int_crb_mode = cpu_to_le32(NX_HOST_INT_CRB_MODE_SHARED); diff --git a/trunk/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c b/trunk/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c index 8c39299331a2..39730403782f 100644 --- a/trunk/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c +++ b/trunk/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c @@ -834,7 +834,7 @@ netxen_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump) static int netxen_set_dump(struct net_device *netdev, struct ethtool_dump *val) { - int ret = 0; + int i; struct netxen_adapter *adapter = netdev_priv(netdev); struct netxen_minidump *mdump = &adapter->mdump; @@ -844,7 +844,7 @@ netxen_set_dump(struct net_device *netdev, struct ethtool_dump *val) mdump->md_enabled = 1; if (adapter->fw_mdump_rdy) { netdev_info(netdev, "Previous dump not cleared, not forcing dump\n"); - return ret; + return 0; } netdev_info(netdev, "Forcing a fw dump\n"); nx_dev_request_reset(adapter); @@ -867,19 +867,21 @@ netxen_set_dump(struct net_device *netdev, struct ethtool_dump *val) adapter->flags &= ~NETXEN_FW_RESET_OWNER; break; default: - if (val->flag <= NX_DUMP_MASK_MAX && - val->flag >= NX_DUMP_MASK_MIN) { - mdump->md_capture_mask = val->flag & 0xff; - netdev_info(netdev, "Driver mask changed to: 0x%x\n", + for (i = 0; i < ARRAY_SIZE(FW_DUMP_LEVELS); i++) { + if (val->flag == FW_DUMP_LEVELS[i]) { + mdump->md_capture_mask = val->flag; + netdev_info(netdev, + "Driver mask changed to: 0x%x\n", mdump->md_capture_mask); - break; + return 0; + } } netdev_info(netdev, "Invalid dump level: 0x%x\n", val->flag); return -EINVAL; } - return ret; + return 0; } static int diff --git a/trunk/drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h b/trunk/drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h index b1a897cd9a8d..28e076960bcb 100644 --- a/trunk/drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h +++ b/trunk/drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h @@ -776,6 +776,7 @@ enum { #define CRB_SW_INT_MASK_3 (NETXEN_NIC_REG(0x1e8)) #define CRB_FW_CAPABILITIES_1 (NETXEN_CAM_RAM(0x128)) +#define CRB_FW_CAPABILITIES_2 (NETXEN_CAM_RAM(0x12c)) #define CRB_MAC_BLOCK_START (NETXEN_CAM_RAM(0x1c0)) /* @@ -955,6 +956,31 @@ enum { #define NX_CRB_DEV_REF_COUNT (NETXEN_CAM_RAM(0x138)) #define NX_CRB_DEV_STATE (NETXEN_CAM_RAM(0x140)) +/* MiniDIMM related macros */ +#define NETXEN_DIMM_CAPABILITY (NETXEN_CAM_RAM(0x258)) +#define NETXEN_DIMM_PRESENT 0x1 +#define NETXEN_DIMM_MEMTYPE_DDR2_SDRAM 0x2 +#define NETXEN_DIMM_SIZE 0x4 +#define NETXEN_DIMM_MEMTYPE(VAL) ((VAL >> 3) & 0xf) +#define NETXEN_DIMM_NUMROWS(VAL) ((VAL >> 7) & 0xf) +#define NETXEN_DIMM_NUMCOLS(VAL) ((VAL >> 11) & 0xf) +#define NETXEN_DIMM_NUMRANKS(VAL) ((VAL >> 15) & 0x3) +#define NETXEN_DIMM_DATAWIDTH(VAL) ((VAL >> 18) & 0x3) +#define NETXEN_DIMM_NUMBANKS(VAL) ((VAL >> 21) & 0xf) +#define NETXEN_DIMM_TYPE(VAL) ((VAL >> 25) & 0x3f) +#define NETXEN_DIMM_VALID_FLAG 0x80000000 + +#define NETXEN_DIMM_MEM_DDR2_SDRAM 0x8 + +#define NETXEN_DIMM_STD_MEM_SIZE 512 + +#define NETXEN_DIMM_TYPE_RDIMM 0x1 +#define NETXEN_DIMM_TYPE_UDIMM 0x2 +#define NETXEN_DIMM_TYPE_SO_DIMM 0x4 +#define NETXEN_DIMM_TYPE_Micro_DIMM 0x8 +#define NETXEN_DIMM_TYPE_Mini_RDIMM 0x10 +#define NETXEN_DIMM_TYPE_Mini_UDIMM 0x20 + /* Device State */ #define NX_DEV_COLD 1 #define NX_DEV_INITALIZING 2 diff --git a/trunk/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c b/trunk/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c index 718b27440351..8694124ef77d 100644 --- a/trunk/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c +++ b/trunk/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c @@ -1131,7 +1131,6 @@ netxen_validate_firmware(struct netxen_adapter *adapter) _build(file_fw_ver)); return -EINVAL; } - val = nx_get_bios_version(adapter); netxen_rom_fast_read(adapter, NX_BIOS_VERSION_OFFSET, (int *)&bios); if ((__force u32)val != bios) { @@ -1261,8 +1260,7 @@ void netxen_request_firmware(struct netxen_adapter *adapter) void netxen_release_firmware(struct netxen_adapter *adapter) { - if (adapter->fw) - release_firmware(adapter->fw); + release_firmware(adapter->fw); adapter->fw = NULL; } @@ -1661,6 +1659,9 @@ netxen_process_lro(struct netxen_adapter *adapter, length = skb->len; + if (adapter->flags & NETXEN_FW_MSS_CAP) + skb_shinfo(skb)->gso_size = netxen_get_lro_sts_mss(sts_data1); + netif_receive_skb(skb); adapter->stats.lro_pkts++; diff --git a/trunk/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/trunk/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c index 65a718f9ccd3..342b3a79bd0f 100644 --- a/trunk/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c +++ b/trunk/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c @@ -1184,6 +1184,7 @@ netxen_nic_attach(struct netxen_adapter *adapter) int err, ring; struct nx_host_rds_ring *rds_ring; struct nx_host_tx_ring *tx_ring; + u32 capab2; if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) return 0; @@ -1192,6 +1193,13 @@ netxen_nic_attach(struct netxen_adapter *adapter) if (err) return err; + adapter->flags &= ~NETXEN_FW_MSS_CAP; + if (adapter->capabilities & NX_FW_CAPABILITY_MORE_CAPS) { + capab2 = NXRD32(adapter, CRB_FW_CAPABILITIES_2); + if (capab2 & NX_FW_CAPABILITY_2_LRO_MAX_TCP_SEG) + adapter->flags |= NETXEN_FW_MSS_CAP; + } + err = netxen_napi_add(adapter, netdev); if (err) return err; @@ -1810,7 +1818,6 @@ netxen_tso_check(struct net_device *netdev, flags = FLAGS_VLAN_TAGGED; } else if (vlan_tx_tag_present(skb)) { - flags = FLAGS_VLAN_OOB; vid = vlan_tx_tag_get(skb); netxen_set_tx_vlan_tci(first_desc, vid); @@ -2926,6 +2933,134 @@ static struct bin_attribute bin_attr_mem = { .write = netxen_sysfs_write_mem, }; +static ssize_t +netxen_sysfs_read_dimm(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t offset, size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct netxen_adapter *adapter = dev_get_drvdata(dev); + struct net_device *netdev = adapter->netdev; + struct netxen_dimm_cfg dimm; + u8 dw, rows, cols, banks, ranks; + u32 val; + + if (size != sizeof(struct netxen_dimm_cfg)) { + netdev_err(netdev, "Invalid size\n"); + return -1; + } + + memset(&dimm, 0, sizeof(struct netxen_dimm_cfg)); + val = NXRD32(adapter, NETXEN_DIMM_CAPABILITY); + + /* Checks if DIMM info is valid. */ + if (val & NETXEN_DIMM_VALID_FLAG) { + netdev_err(netdev, "Invalid DIMM flag\n"); + dimm.presence = 0xff; + goto out; + } + + rows = NETXEN_DIMM_NUMROWS(val); + cols = NETXEN_DIMM_NUMCOLS(val); + ranks = NETXEN_DIMM_NUMRANKS(val); + banks = NETXEN_DIMM_NUMBANKS(val); + dw = NETXEN_DIMM_DATAWIDTH(val); + + dimm.presence = (val & NETXEN_DIMM_PRESENT); + + /* Checks if DIMM info is present. */ + if (!dimm.presence) { + netdev_err(netdev, "DIMM not present\n"); + goto out; + } + + dimm.dimm_type = NETXEN_DIMM_TYPE(val); + + switch (dimm.dimm_type) { + case NETXEN_DIMM_TYPE_RDIMM: + case NETXEN_DIMM_TYPE_UDIMM: + case NETXEN_DIMM_TYPE_SO_DIMM: + case NETXEN_DIMM_TYPE_Micro_DIMM: + case NETXEN_DIMM_TYPE_Mini_RDIMM: + case NETXEN_DIMM_TYPE_Mini_UDIMM: + break; + default: + netdev_err(netdev, "Invalid DIMM type %x\n", dimm.dimm_type); + goto out; + } + + if (val & NETXEN_DIMM_MEMTYPE_DDR2_SDRAM) + dimm.mem_type = NETXEN_DIMM_MEM_DDR2_SDRAM; + else + dimm.mem_type = NETXEN_DIMM_MEMTYPE(val); + + if (val & NETXEN_DIMM_SIZE) { + dimm.size = NETXEN_DIMM_STD_MEM_SIZE; + goto out; + } + + if (!rows) { + netdev_err(netdev, "Invalid no of rows %x\n", rows); + goto out; + } + + if (!cols) { + netdev_err(netdev, "Invalid no of columns %x\n", cols); + goto out; + } + + if (!banks) { + netdev_err(netdev, "Invalid no of banks %x\n", banks); + goto out; + } + + ranks += 1; + + switch (dw) { + case 0x0: + dw = 32; + break; + case 0x1: + dw = 33; + break; + case 0x2: + dw = 36; + break; + case 0x3: + dw = 64; + break; + case 0x4: + dw = 72; + break; + case 0x5: + dw = 80; + break; + case 0x6: + dw = 128; + break; + case 0x7: + dw = 144; + break; + default: + netdev_err(netdev, "Invalid data-width %x\n", dw); + goto out; + } + + dimm.size = ((1 << rows) * (1 << cols) * dw * banks * ranks) / 8; + /* Size returned in MB. */ + dimm.size = (dimm.size) / 0x100000; +out: + memcpy(buf, &dimm, sizeof(struct netxen_dimm_cfg)); + return sizeof(struct netxen_dimm_cfg); + +} + +static struct bin_attribute bin_attr_dimm = { + .attr = { .name = "dimm", .mode = (S_IRUGO | S_IWUSR) }, + .size = 0, + .read = netxen_sysfs_read_dimm, +}; + static void netxen_create_sysfs_entries(struct netxen_adapter *adapter) @@ -2963,6 +3098,8 @@ netxen_create_diag_entries(struct netxen_adapter *adapter) dev_info(dev, "failed to create crb sysfs entry\n"); if (device_create_bin_file(dev, &bin_attr_mem)) dev_info(dev, "failed to create mem sysfs entry\n"); + if (device_create_bin_file(dev, &bin_attr_dimm)) + dev_info(dev, "failed to create dimm sysfs entry\n"); } @@ -2975,6 +3112,7 @@ netxen_remove_diag_entries(struct netxen_adapter *adapter) device_remove_file(dev, &dev_attr_diag_mode); device_remove_bin_file(dev, &bin_attr_crb); device_remove_bin_file(dev, &bin_attr_mem); + device_remove_bin_file(dev, &bin_attr_dimm); } #ifdef CONFIG_INET diff --git a/trunk/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/trunk/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index 385a4d5c7c25..8680a5dae4a2 100644 --- a/trunk/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/trunk/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h @@ -36,8 +36,8 @@ #define _QLCNIC_LINUX_MAJOR 5 #define _QLCNIC_LINUX_MINOR 0 -#define _QLCNIC_LINUX_SUBVERSION 27 -#define QLCNIC_LINUX_VERSIONID "5.0.27" +#define _QLCNIC_LINUX_SUBVERSION 28 +#define QLCNIC_LINUX_VERSIONID "5.0.28" #define QLCNIC_DRV_IDC_VER 0x01 #define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\ (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION)) @@ -607,6 +607,7 @@ struct qlcnic_recv_context { #define QLCNIC_CDRP_CMD_CONFIG_PORT 0x0000002E #define QLCNIC_CDRP_CMD_TEMP_SIZE 0x0000002f #define QLCNIC_CDRP_CMD_GET_TEMP_HDR 0x00000030 +#define QLCNIC_CDRP_CMD_GET_MAC_STATS 0x00000037 #define QLCNIC_RCODE_SUCCESS 0 #define QLCNIC_RCODE_NOT_SUPPORTED 9 @@ -1180,18 +1181,62 @@ struct qlcnic_esw_func_cfg { #define QLCNIC_STATS_ESWITCH 2 #define QLCNIC_QUERY_RX_COUNTER 0 #define QLCNIC_QUERY_TX_COUNTER 1 -#define QLCNIC_ESW_STATS_NOT_AVAIL 0xffffffffffffffffULL +#define QLCNIC_STATS_NOT_AVAIL 0xffffffffffffffffULL +#define QLCNIC_FILL_STATS(VAL1) \ + (((VAL1) == QLCNIC_STATS_NOT_AVAIL) ? 0 : VAL1) +#define QLCNIC_MAC_STATS 1 +#define QLCNIC_ESW_STATS 2 #define QLCNIC_ADD_ESW_STATS(VAL1, VAL2)\ do { \ - if (((VAL1) == QLCNIC_ESW_STATS_NOT_AVAIL) && \ - ((VAL2) != QLCNIC_ESW_STATS_NOT_AVAIL)) \ + if (((VAL1) == QLCNIC_STATS_NOT_AVAIL) && \ + ((VAL2) != QLCNIC_STATS_NOT_AVAIL)) \ (VAL1) = (VAL2); \ - else if (((VAL1) != QLCNIC_ESW_STATS_NOT_AVAIL) && \ - ((VAL2) != QLCNIC_ESW_STATS_NOT_AVAIL)) \ + else if (((VAL1) != QLCNIC_STATS_NOT_AVAIL) && \ + ((VAL2) != QLCNIC_STATS_NOT_AVAIL)) \ (VAL1) += (VAL2); \ } while (0) +struct qlcnic_mac_statistics{ + __le64 mac_tx_frames; + __le64 mac_tx_bytes; + __le64 mac_tx_mcast_pkts; + __le64 mac_tx_bcast_pkts; + __le64 mac_tx_pause_cnt; + __le64 mac_tx_ctrl_pkt; + __le64 mac_tx_lt_64b_pkts; + __le64 mac_tx_lt_127b_pkts; + __le64 mac_tx_lt_255b_pkts; + __le64 mac_tx_lt_511b_pkts; + __le64 mac_tx_lt_1023b_pkts; + __le64 mac_tx_lt_1518b_pkts; + __le64 mac_tx_gt_1518b_pkts; + __le64 rsvd1[3]; + + __le64 mac_rx_frames; + __le64 mac_rx_bytes; + __le64 mac_rx_mcast_pkts; + __le64 mac_rx_bcast_pkts; + __le64 mac_rx_pause_cnt; + __le64 mac_rx_ctrl_pkt; + __le64 mac_rx_lt_64b_pkts; + __le64 mac_rx_lt_127b_pkts; + __le64 mac_rx_lt_255b_pkts; + __le64 mac_rx_lt_511b_pkts; + __le64 mac_rx_lt_1023b_pkts; + __le64 mac_rx_lt_1518b_pkts; + __le64 mac_rx_gt_1518b_pkts; + __le64 rsvd2[3]; + + __le64 mac_rx_length_error; + __le64 mac_rx_length_small; + __le64 mac_rx_length_large; + __le64 mac_rx_jabber; + __le64 mac_rx_dropped; + __le64 mac_rx_crc_error; + __le64 mac_align_error; +} __packed; + struct __qlcnic_esw_statistics { __le16 context_id; __le16 version; @@ -1352,6 +1397,8 @@ enum op_codes { #define QLCNIC_ENABLE_FW_DUMP 0xaddfeed #define QLCNIC_DISABLE_FW_DUMP 0xbadfeed #define QLCNIC_FORCE_FW_RESET 0xdeaddead +#define QLCNIC_SET_QUIESCENT 0xadd00010 +#define QLCNIC_RESET_QUIESCENT 0xadd00020 struct qlcnic_dump_operations { enum op_codes opcode; @@ -1510,6 +1557,7 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *, const u8, const u8, int qlcnic_get_eswitch_stats(struct qlcnic_adapter *, const u8, u8, struct __qlcnic_esw_statistics *); int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, u8, u8, u8); +int qlcnic_get_mac_stats(struct qlcnic_adapter *, struct qlcnic_mac_statistics *); extern int qlcnic_config_tso; /* @@ -1559,6 +1607,7 @@ static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring) } extern const struct ethtool_ops qlcnic_ethtool_ops; +extern const struct ethtool_ops qlcnic_ethtool_failed_ops; struct qlcnic_nic_template { int (*config_bridged_mode) (struct qlcnic_adapter *, u32); diff --git a/trunk/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/trunk/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c index 569a837d2ac4..8db85244e8ad 100644 --- a/trunk/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c +++ b/trunk/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c @@ -905,6 +905,65 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func, return err; } +/* This routine will retrieve the MAC statistics from firmware */ +int qlcnic_get_mac_stats(struct qlcnic_adapter *adapter, + struct qlcnic_mac_statistics *mac_stats) +{ + struct qlcnic_mac_statistics *stats; + struct qlcnic_cmd_args cmd; + size_t stats_size = sizeof(struct qlcnic_mac_statistics); + dma_addr_t stats_dma_t; + void *stats_addr; + int err; + + stats_addr = dma_alloc_coherent(&adapter->pdev->dev, stats_size, + &stats_dma_t, GFP_KERNEL); + if (!stats_addr) { + dev_err(&adapter->pdev->dev, + "%s: Unable to allocate memory.\n", __func__); + return -ENOMEM; + } + memset(stats_addr, 0, stats_size); + memset(&cmd, 0, sizeof(cmd)); + cmd.req.cmd = QLCNIC_CDRP_CMD_GET_MAC_STATS; + cmd.req.arg1 = stats_size << 16; + cmd.req.arg2 = MSD(stats_dma_t); + cmd.req.arg3 = LSD(stats_dma_t); + + qlcnic_issue_cmd(adapter, &cmd); + err = cmd.rsp.cmd; + + if (!err) { + stats = stats_addr; + mac_stats->mac_tx_frames = le64_to_cpu(stats->mac_tx_frames); + mac_stats->mac_tx_bytes = le64_to_cpu(stats->mac_tx_bytes); + mac_stats->mac_tx_mcast_pkts = + le64_to_cpu(stats->mac_tx_mcast_pkts); + mac_stats->mac_tx_bcast_pkts = + le64_to_cpu(stats->mac_tx_bcast_pkts); + mac_stats->mac_rx_frames = le64_to_cpu(stats->mac_rx_frames); + mac_stats->mac_rx_bytes = le64_to_cpu(stats->mac_rx_bytes); + mac_stats->mac_rx_mcast_pkts = + le64_to_cpu(stats->mac_rx_mcast_pkts); + mac_stats->mac_rx_length_error = + le64_to_cpu(stats->mac_rx_length_error); + mac_stats->mac_rx_length_small = + le64_to_cpu(stats->mac_rx_length_small); + mac_stats->mac_rx_length_large = + le64_to_cpu(stats->mac_rx_length_large); + mac_stats->mac_rx_jabber = le64_to_cpu(stats->mac_rx_jabber); + mac_stats->mac_rx_dropped = le64_to_cpu(stats->mac_rx_dropped); + mac_stats->mac_rx_crc_error = le64_to_cpu(stats->mac_rx_crc_error); + } else { + dev_info(&adapter->pdev->dev, + "%s: Get mac stats failed =%d.\n", __func__, err); + } + + dma_free_coherent(&adapter->pdev->dev, stats_size, stats_addr, + stats_dma_t); + return err; +} + int qlcnic_get_eswitch_stats(struct qlcnic_adapter *adapter, const u8 eswitch, const u8 rx_tx, struct __qlcnic_esw_statistics *esw_stats) { @@ -920,13 +979,13 @@ int qlcnic_get_eswitch_stats(struct qlcnic_adapter *adapter, const u8 eswitch, return -EIO; memset(esw_stats, 0, sizeof(u64)); - esw_stats->unicast_frames = QLCNIC_ESW_STATS_NOT_AVAIL; - esw_stats->multicast_frames = QLCNIC_ESW_STATS_NOT_AVAIL; - esw_stats->broadcast_frames = QLCNIC_ESW_STATS_NOT_AVAIL; - esw_stats->dropped_frames = QLCNIC_ESW_STATS_NOT_AVAIL; - esw_stats->errors = QLCNIC_ESW_STATS_NOT_AVAIL; - esw_stats->local_frames = QLCNIC_ESW_STATS_NOT_AVAIL; - esw_stats->numbytes = QLCNIC_ESW_STATS_NOT_AVAIL; + esw_stats->unicast_frames = QLCNIC_STATS_NOT_AVAIL; + esw_stats->multicast_frames = QLCNIC_STATS_NOT_AVAIL; + esw_stats->broadcast_frames = QLCNIC_STATS_NOT_AVAIL; + esw_stats->dropped_frames = QLCNIC_STATS_NOT_AVAIL; + esw_stats->errors = QLCNIC_STATS_NOT_AVAIL; + esw_stats->local_frames = QLCNIC_STATS_NOT_AVAIL; + esw_stats->numbytes = QLCNIC_STATS_NOT_AVAIL; esw_stats->context_id = eswitch; for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) { diff --git a/trunk/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/trunk/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c index 89ddf7f7d7df..9e9e78a5c4d7 100644 --- a/trunk/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c +++ b/trunk/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c @@ -78,8 +78,46 @@ static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = { "tx numbytes", }; -#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats) +static const char qlcnic_mac_stats_strings [][ETH_GSTRING_LEN] = { + "mac_tx_frames", + "mac_tx_bytes", + "mac_tx_mcast_pkts", + "mac_tx_bcast_pkts", + "mac_tx_pause_cnt", + "mac_tx_ctrl_pkt", + "mac_tx_lt_64b_pkts", + "mac_tx_lt_127b_pkts", + "mac_tx_lt_255b_pkts", + "mac_tx_lt_511b_pkts", + "mac_tx_lt_1023b_pkts", + "mac_tx_lt_1518b_pkts", + "mac_tx_gt_1518b_pkts", + "mac_rx_frames", + "mac_rx_bytes", + "mac_rx_mcast_pkts", + "mac_rx_bcast_pkts", + "mac_rx_pause_cnt", + "mac_rx_ctrl_pkt", + "mac_rx_lt_64b_pkts", + "mac_rx_lt_127b_pkts", + "mac_rx_lt_255b_pkts", + "mac_rx_lt_511b_pkts", + "mac_rx_lt_1023b_pkts", + "mac_rx_lt_1518b_pkts", + "mac_rx_gt_1518b_pkts", + "mac_rx_length_error", + "mac_rx_length_small", + "mac_rx_length_large", + "mac_rx_jabber", + "mac_rx_dropped", + "mac_rx_crc_error", + "mac_align_error", +}; + +#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats) +#define QLCNIC_MAC_STATS_LEN ARRAY_SIZE(qlcnic_mac_stats_strings) #define QLCNIC_DEVICE_STATS_LEN ARRAY_SIZE(qlcnic_device_gstrings_stats) +#define QLCNIC_TOTAL_STATS_LEN QLCNIC_STATS_LEN + QLCNIC_MAC_STATS_LEN static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = { "Register_Test_on_offline", @@ -644,8 +682,8 @@ static int qlcnic_get_sset_count(struct net_device *dev, int sset) return QLCNIC_TEST_LEN; case ETH_SS_STATS: if (adapter->flags & QLCNIC_ESWITCH_ENABLED) - return QLCNIC_STATS_LEN + QLCNIC_DEVICE_STATS_LEN; - return QLCNIC_STATS_LEN; + return QLCNIC_TOTAL_STATS_LEN + QLCNIC_DEVICE_STATS_LEN; + return QLCNIC_TOTAL_STATS_LEN; default: return -EOPNOTSUPP; } @@ -851,7 +889,7 @@ static void qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data) { struct qlcnic_adapter *adapter = netdev_priv(dev); - int index, i; + int index, i, j; switch (stringset) { case ETH_SS_TEST: @@ -864,6 +902,11 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data) qlcnic_gstrings_stats[index].stat_string, ETH_GSTRING_LEN); } + for (j = 0; j < QLCNIC_MAC_STATS_LEN; index++, j++) { + memcpy(data + index * ETH_GSTRING_LEN, + qlcnic_mac_stats_strings[j], + ETH_GSTRING_LEN); + } if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) return; for (i = 0; i < QLCNIC_DEVICE_STATS_LEN; index++, i++) { @@ -874,22 +917,64 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data) } } -#define QLCNIC_FILL_ESWITCH_STATS(VAL1) \ - (((VAL1) == QLCNIC_ESW_STATS_NOT_AVAIL) ? 0 : VAL1) - static void -qlcnic_fill_device_stats(int *index, u64 *data, - struct __qlcnic_esw_statistics *stats) +qlcnic_fill_stats(int *index, u64 *data, void *stats, int type) { int ind = *index; - data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->unicast_frames); - data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->multicast_frames); - data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->broadcast_frames); - data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->dropped_frames); - data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->errors); - data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->local_frames); - data[ind++] = QLCNIC_FILL_ESWITCH_STATS(stats->numbytes); + if (type == QLCNIC_MAC_STATS) { + struct qlcnic_mac_statistics *mac_stats = + (struct qlcnic_mac_statistics *)stats; + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_frames); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_bytes); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_mcast_pkts); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_bcast_pkts); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_pause_cnt); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_ctrl_pkt); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_64b_pkts); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_127b_pkts); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_255b_pkts); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_511b_pkts); + data[ind++] = + QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1023b_pkts); + data[ind++] = + QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1518b_pkts); + data[ind++] = + QLCNIC_FILL_STATS(mac_stats->mac_tx_gt_1518b_pkts); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_frames); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_bytes); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_mcast_pkts); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_bcast_pkts); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_pause_cnt); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_ctrl_pkt); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_64b_pkts); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_127b_pkts); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_255b_pkts); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_511b_pkts); + data[ind++] = + QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1023b_pkts); + data[ind++] = + QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1518b_pkts); + data[ind++] = + QLCNIC_FILL_STATS(mac_stats->mac_rx_gt_1518b_pkts); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_error); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_small); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_large); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_jabber); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_dropped); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_crc_error); + data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_align_error); + } else if (type == QLCNIC_ESW_STATS) { + struct __qlcnic_esw_statistics *esw_stats = + (struct __qlcnic_esw_statistics *)stats; + data[ind++] = QLCNIC_FILL_STATS(esw_stats->unicast_frames); + data[ind++] = QLCNIC_FILL_STATS(esw_stats->multicast_frames); + data[ind++] = QLCNIC_FILL_STATS(esw_stats->broadcast_frames); + data[ind++] = QLCNIC_FILL_STATS(esw_stats->dropped_frames); + data[ind++] = QLCNIC_FILL_STATS(esw_stats->errors); + data[ind++] = QLCNIC_FILL_STATS(esw_stats->local_frames); + data[ind++] = QLCNIC_FILL_STATS(esw_stats->numbytes); + } *index = ind; } @@ -900,6 +985,7 @@ qlcnic_get_ethtool_stats(struct net_device *dev, { struct qlcnic_adapter *adapter = netdev_priv(dev); struct qlcnic_esw_statistics port_stats; + struct qlcnic_mac_statistics mac_stats; int index, ret; for (index = 0; index < QLCNIC_STATS_LEN; index++) { @@ -911,6 +997,11 @@ qlcnic_get_ethtool_stats(struct net_device *dev, sizeof(u64)) ? *(u64 *)p:(*(u32 *)p); } + /* Retrieve MAC statistics from firmware */ + memset(&mac_stats, 0, sizeof(struct qlcnic_mac_statistics)); + qlcnic_get_mac_stats(adapter, &mac_stats); + qlcnic_fill_stats(&index, data, &mac_stats, QLCNIC_MAC_STATS); + if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) return; @@ -920,14 +1011,14 @@ qlcnic_get_ethtool_stats(struct net_device *dev, if (ret) return; - qlcnic_fill_device_stats(&index, data, &port_stats.rx); + qlcnic_fill_stats(&index, data, &port_stats.rx, QLCNIC_ESW_STATS); ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func, QLCNIC_QUERY_TX_COUNTER, &port_stats.tx); if (ret) return; - qlcnic_fill_device_stats(&index, data, &port_stats.tx); + qlcnic_fill_stats(&index, data, &port_stats.tx, QLCNIC_ESW_STATS); } static int qlcnic_set_led(struct net_device *dev, @@ -1132,11 +1223,21 @@ qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump) struct qlcnic_adapter *adapter = netdev_priv(netdev); struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; + if (!fw_dump->tmpl_hdr) { + netdev_err(adapter->netdev, "FW Dump not supported\n"); + return -ENOTSUPP; + } + if (fw_dump->clr) dump->len = fw_dump->tmpl_hdr->size + fw_dump->size; else dump->len = 0; - dump->flag = fw_dump->tmpl_hdr->drv_cap_mask; + + if (!fw_dump->enable) + dump->flag = ETH_FW_DUMP_DISABLE; + else + dump->flag = fw_dump->tmpl_hdr->drv_cap_mask; + dump->version = adapter->fw_version; return 0; } @@ -1150,6 +1251,11 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump, struct qlcnic_adapter *adapter = netdev_priv(netdev); struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; + if (!fw_dump->tmpl_hdr) { + netdev_err(netdev, "FW Dump not supported\n"); + return -ENOTSUPP; + } + if (!fw_dump->clr) { netdev_info(netdev, "Dump not available\n"); return -EINVAL; @@ -1177,55 +1283,74 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump, static int qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val) { - int ret = 0; + int i; struct qlcnic_adapter *adapter = netdev_priv(netdev); struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; + u32 state; switch (val->flag) { case QLCNIC_FORCE_FW_DUMP_KEY: + if (!fw_dump->tmpl_hdr) { + netdev_err(netdev, "FW dump not supported\n"); + return -ENOTSUPP; + } if (!fw_dump->enable) { netdev_info(netdev, "FW dump not enabled\n"); - return ret; + return 0; } if (fw_dump->clr) { netdev_info(netdev, "Previous dump not cleared, not forcing dump\n"); - return ret; + return 0; } netdev_info(netdev, "Forcing a FW dump\n"); qlcnic_dev_request_reset(adapter); break; case QLCNIC_DISABLE_FW_DUMP: - if (fw_dump->enable) { + if (fw_dump->enable && fw_dump->tmpl_hdr) { netdev_info(netdev, "Disabling FW dump\n"); fw_dump->enable = 0; } - break; + return 0; case QLCNIC_ENABLE_FW_DUMP: - if (!fw_dump->enable && fw_dump->tmpl_hdr) { + if (!fw_dump->tmpl_hdr) { + netdev_err(netdev, "FW dump not supported\n"); + return -ENOTSUPP; + } + if (!fw_dump->enable) { netdev_info(netdev, "Enabling FW dump\n"); fw_dump->enable = 1; } - break; + return 0; case QLCNIC_FORCE_FW_RESET: netdev_info(netdev, "Forcing a FW reset\n"); qlcnic_dev_request_reset(adapter); adapter->flags &= ~QLCNIC_FW_RESET_OWNER; - break; + return 0; + case QLCNIC_SET_QUIESCENT: + case QLCNIC_RESET_QUIESCENT: + state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); + if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) + netdev_info(netdev, "Device in FAILED state\n"); + return 0; default: - if (val->flag > QLCNIC_DUMP_MASK_MAX || - val->flag < QLCNIC_DUMP_MASK_MIN) { - netdev_info(netdev, - "Invalid dump level: 0x%x\n", val->flag); - ret = -EINVAL; - goto out; + if (!fw_dump->tmpl_hdr) { + netdev_err(netdev, "FW dump not supported\n"); + return -ENOTSUPP; + } + for (i = 0; i < ARRAY_SIZE(FW_DUMP_LEVELS); i++) { + if (val->flag == FW_DUMP_LEVELS[i]) { + fw_dump->tmpl_hdr->drv_cap_mask = + val->flag; + netdev_info(netdev, "Driver mask changed to: 0x%x\n", + fw_dump->tmpl_hdr->drv_cap_mask); + return 0; + } } - fw_dump->tmpl_hdr->drv_cap_mask = val->flag & 0xff; - netdev_info(netdev, "Driver mask changed to: 0x%x\n", - fw_dump->tmpl_hdr->drv_cap_mask); + netdev_info(netdev, "Invalid dump level: 0x%x\n", val->flag); + return -EINVAL; } -out: - return ret; + return 0; } const struct ethtool_ops qlcnic_ethtool_ops = { @@ -1258,3 +1383,10 @@ const struct ethtool_ops qlcnic_ethtool_ops = { .get_dump_data = qlcnic_get_dump_data, .set_dump = qlcnic_set_dump, }; + +const struct ethtool_ops qlcnic_ethtool_failed_ops = { + .get_settings = qlcnic_get_settings, + .get_drvinfo = qlcnic_get_drvinfo, + .set_msglevel = qlcnic_set_msglevel, + .get_msglevel = qlcnic_get_msglevel, +}; diff --git a/trunk/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h b/trunk/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h index a52819303d1b..6ced3195aad3 100644 --- a/trunk/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h +++ b/trunk/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h @@ -704,6 +704,8 @@ enum { #define QLCNIC_DEV_FAILED 0x6 #define QLCNIC_DEV_QUISCENT 0x7 +#define QLCNIC_DEV_BADBAD 0xbad0bad0 + #define QLCNIC_DEV_NPAR_NON_OPER 0 /* NON Operational */ #define QLCNIC_DEV_NPAR_OPER 1 /* NPAR Operational */ #define QLCNIC_DEV_NPAR_OPER_TIMEO 30 /* Operational time out */ @@ -776,6 +778,10 @@ struct qlcnic_legacy_intr_set { #define FLASH_ROM_WINDOW 0x42110030 #define FLASH_ROM_DATA 0x42150000 + +static const u32 FW_DUMP_LEVELS[] = { + 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff }; + static const u32 MIU_TEST_READ_DATA[] = { 0x410000A8, 0x410000AC, 0x410000B8, 0x410000BC, }; diff --git a/trunk/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c b/trunk/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c index d32cf0ddf1b9..799fd40ed03a 100644 --- a/trunk/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c +++ b/trunk/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c @@ -1321,8 +1321,7 @@ void qlcnic_request_firmware(struct qlcnic_adapter *adapter) void qlcnic_release_firmware(struct qlcnic_adapter *adapter) { - if (adapter->fw) - release_firmware(adapter->fw); + release_firmware(adapter->fw); adapter->fw = NULL; } diff --git a/trunk/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/trunk/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 75c32e875fef..46e77a2c5121 100644 --- a/trunk/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/trunk/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -338,6 +338,10 @@ static const struct net_device_ops qlcnic_netdev_ops = { #endif }; +static const struct net_device_ops qlcnic_netdev_failed_ops = { + .ndo_open = qlcnic_open, +}; + static struct qlcnic_nic_template qlcnic_ops = { .config_bridged_mode = qlcnic_config_bridged_mode, .config_led = qlcnic_config_led, @@ -1623,8 +1627,9 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = adapter->nic_ops->start_firmware(adapter); if (err) { - dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n"); - goto err_out_decr_ref; + dev_err(&pdev->dev, "Loading fw failed. Please Reboot\n" + "\t\tIf reboot doesn't help, try flashing the card\n"); + goto err_out_maintenance_mode; } if (qlcnic_read_mac_addr(adapter)) @@ -1695,6 +1700,18 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, NULL); pci_disable_device(pdev); return err; + +err_out_maintenance_mode: + netdev->netdev_ops = &qlcnic_netdev_failed_ops; + SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_failed_ops); + err = register_netdev(netdev); + if (err) { + dev_err(&pdev->dev, "failed to register net device\n"); + goto err_out_decr_ref; + } + pci_set_drvdata(pdev, adapter); + qlcnic_create_diag_entries(adapter); + return 0; } static void __devexit qlcnic_remove(struct pci_dev *pdev) @@ -1831,8 +1848,14 @@ qlcnic_resume(struct pci_dev *pdev) static int qlcnic_open(struct net_device *netdev) { struct qlcnic_adapter *adapter = netdev_priv(netdev); + u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); int err; + if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) { + netdev_err(netdev, "Device in FAILED state\n"); + return -EIO; + } + netif_carrier_off(netdev); err = qlcnic_attach(adapter); @@ -1942,7 +1965,7 @@ qlcnic_send_filter(struct qlcnic_adapter *adapter, __le16 vlan_id = 0; u8 hindex; - if (!compare_ether_addr(phdr->h_source, adapter->mac_addr)) + if (ether_addr_equal(phdr->h_source, adapter->mac_addr)) return; if (adapter->fhash.fnum >= adapter->fhash.fmax) @@ -2212,8 +2235,7 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if (adapter->flags & QLCNIC_MACSPOOF) { phdr = (struct ethhdr *)skb->data; - if (compare_ether_addr(phdr->h_source, - adapter->mac_addr)) + if (!ether_addr_equal(phdr->h_source, adapter->mac_addr)) goto drop_packet; } @@ -3018,6 +3040,12 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *adapter) return; state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); + if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) { + netdev_err(adapter->netdev, + "Device is in FAILED state, Please Reboot\n"); + qlcnic_api_unlock(adapter); + return; + } if (state == QLCNIC_DEV_READY) { QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET); @@ -3061,6 +3089,9 @@ qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter) while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) msleep(10); + if (!adapter->fw_work.work.func) + return; + cancel_delayed_work_sync(&adapter->fw_work); } @@ -4280,6 +4311,7 @@ static void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter) { struct device *dev = &adapter->pdev->dev; + u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); if (device_create_bin_file(dev, &bin_attr_port_stats)) dev_info(dev, "failed to create port stats sysfs entry"); @@ -4288,14 +4320,19 @@ qlcnic_create_diag_entries(struct qlcnic_adapter *adapter) return; if (device_create_file(dev, &dev_attr_diag_mode)) dev_info(dev, "failed to create diag_mode sysfs entry\n"); - if (device_create_file(dev, &dev_attr_beacon)) - dev_info(dev, "failed to create beacon sysfs entry"); if (device_create_bin_file(dev, &bin_attr_crb)) dev_info(dev, "failed to create crb sysfs entry\n"); if (device_create_bin_file(dev, &bin_attr_mem)) dev_info(dev, "failed to create mem sysfs entry\n"); + + if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) + return; + if (device_create_bin_file(dev, &bin_attr_pci_config)) dev_info(dev, "failed to create pci config sysfs entry"); + if (device_create_file(dev, &dev_attr_beacon)) + dev_info(dev, "failed to create beacon sysfs entry"); + if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) return; if (device_create_bin_file(dev, &bin_attr_esw_config)) @@ -4314,16 +4351,19 @@ static void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter) { struct device *dev = &adapter->pdev->dev; + u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); device_remove_bin_file(dev, &bin_attr_port_stats); if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) return; device_remove_file(dev, &dev_attr_diag_mode); - device_remove_file(dev, &dev_attr_beacon); device_remove_bin_file(dev, &bin_attr_crb); device_remove_bin_file(dev, &bin_attr_mem); + if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) + return; device_remove_bin_file(dev, &bin_attr_pci_config); + device_remove_file(dev, &dev_attr_beacon); if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) return; device_remove_bin_file(dev, &bin_attr_esw_config); diff --git a/trunk/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/trunk/drivers/net/ethernet/qlogic/qlge/qlge_main.c index 49343ec21c82..09d8d33171df 100644 --- a/trunk/drivers/net/ethernet/qlogic/qlge/qlge_main.c +++ b/trunk/drivers/net/ethernet/qlogic/qlge/qlge_main.c @@ -3845,7 +3845,7 @@ static int ql_wol(struct ql_adapter *qdev) if (qdev->wol & (WAKE_ARP | WAKE_MAGICSECURE | WAKE_PHY | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST)) { netif_err(qdev, ifdown, qdev->ndev, - "Unsupported WOL paramter. qdev->wol = 0x%x.\n", + "Unsupported WOL parameter. qdev->wol = 0x%x.\n", qdev->wol); return -EINVAL; } diff --git a/trunk/drivers/net/ethernet/rdc/r6040.c b/trunk/drivers/net/ethernet/rdc/r6040.c index b96e1920e045..4de73643fec6 100644 --- a/trunk/drivers/net/ethernet/rdc/r6040.c +++ b/trunk/drivers/net/ethernet/rdc/r6040.c @@ -4,7 +4,7 @@ * Copyright (C) 2004 Sten Wang * Copyright (C) 2007 * Daniel Gimpelevich - * Florian Fainelli + * Copyright (C) 2007-2012 Florian Fainelli * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -74,9 +74,13 @@ #define MT_ICR 0x0C /* TX interrupt control */ #define MR_ICR 0x10 /* RX interrupt control */ #define MTPR 0x14 /* TX poll command register */ +#define TM2TX 0x0001 /* Trigger MAC to transmit */ #define MR_BSR 0x18 /* RX buffer size */ #define MR_DCR 0x1A /* RX descriptor control */ #define MLSR 0x1C /* Last status */ +#define TX_FIFO_UNDR 0x0200 /* TX FIFO under-run */ +#define TX_EXCEEDC 0x2000 /* Transmit exceed collision */ +#define TX_LATEC 0x4000 /* Transmit late collision */ #define MMDIO 0x20 /* MDIO control register */ #define MDIO_WRITE 0x4000 /* MDIO write */ #define MDIO_READ 0x2000 /* MDIO read */ @@ -124,6 +128,9 @@ #define MID_3M 0x82 /* MID3 Medium */ #define MID_3H 0x84 /* MID3 High */ #define PHY_CC 0x88 /* PHY status change configuration register */ +#define SCEN 0x8000 /* PHY status change enable */ +#define PHYAD_SHIFT 8 /* PHY address shift */ +#define TMRDIV_SHIFT 0 /* Timer divider shift */ #define PHY_ST 0x8A /* PHY status register */ #define MAC_SM 0xAC /* MAC status machine */ #define MAC_SM_RST 0x0002 /* MAC status machine reset */ @@ -137,6 +144,8 @@ #define MBCR_DEFAULT 0x012A /* MAC Bus Control Register */ #define MCAST_MAX 3 /* Max number multicast addresses to filter */ +#define MAC_DEF_TIMEOUT 2048 /* Default MAC read/write operation timeout */ + /* Descriptor status */ #define DSC_OWNER_MAC 0x8000 /* MAC is the owner of this descriptor */ #define DSC_RX_OK 0x4000 /* RX was successful */ @@ -187,7 +196,7 @@ struct r6040_private { dma_addr_t rx_ring_dma; dma_addr_t tx_ring_dma; u16 tx_free_desc; - u16 mcr0, mcr1; + u16 mcr0; struct net_device *dev; struct mii_bus *mii_bus; struct napi_struct napi; @@ -204,7 +213,7 @@ static char version[] __devinitdata = DRV_NAME /* Read a word data from PHY Chip */ static int r6040_phy_read(void __iomem *ioaddr, int phy_addr, int reg) { - int limit = 2048; + int limit = MAC_DEF_TIMEOUT; u16 cmd; iowrite16(MDIO_READ + reg + (phy_addr << 8), ioaddr + MMDIO); @@ -222,7 +231,7 @@ static int r6040_phy_read(void __iomem *ioaddr, int phy_addr, int reg) static void r6040_phy_write(void __iomem *ioaddr, int phy_addr, int reg, u16 val) { - int limit = 2048; + int limit = MAC_DEF_TIMEOUT; u16 cmd; iowrite16(val, ioaddr + MMWD); @@ -358,27 +367,35 @@ static int r6040_alloc_rxbufs(struct net_device *dev) return rc; } -static void r6040_init_mac_regs(struct net_device *dev) +static void r6040_reset_mac(struct r6040_private *lp) { - struct r6040_private *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; - int limit = 2048; + int limit = MAC_DEF_TIMEOUT; u16 cmd; - /* Mask Off Interrupt */ - iowrite16(MSK_INT, ioaddr + MIER); - - /* Reset RDC MAC */ iowrite16(MAC_RST, ioaddr + MCR1); while (limit--) { cmd = ioread16(ioaddr + MCR1); if (cmd & MAC_RST) break; } + /* Reset internal state machine */ iowrite16(MAC_SM_RST, ioaddr + MAC_SM); iowrite16(0, ioaddr + MAC_SM); mdelay(5); +} + +static void r6040_init_mac_regs(struct net_device *dev) +{ + struct r6040_private *lp = netdev_priv(dev); + void __iomem *ioaddr = lp->base; + + /* Mask Off Interrupt */ + iowrite16(MSK_INT, ioaddr + MIER); + + /* Reset RDC MAC */ + r6040_reset_mac(lp); /* MAC Bus Control Register */ iowrite16(MBCR_DEFAULT, ioaddr + MBCR); @@ -407,7 +424,7 @@ static void r6040_init_mac_regs(struct net_device *dev) /* Let TX poll the descriptors * we may got called by r6040_tx_timeout which has left * some unsent tx buffers */ - iowrite16(0x01, ioaddr + MTPR); + iowrite16(TM2TX, ioaddr + MTPR); } static void r6040_tx_timeout(struct net_device *dev) @@ -445,18 +462,13 @@ static void r6040_down(struct net_device *dev) { struct r6040_private *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; - int limit = 2048; u16 *adrp; - u16 cmd; /* Stop MAC */ iowrite16(MSK_INT, ioaddr + MIER); /* Mask Off Interrupt */ - iowrite16(MAC_RST, ioaddr + MCR1); /* Reset RDC MAC */ - while (limit--) { - cmd = ioread16(ioaddr + MCR1); - if (cmd & MAC_RST) - break; - } + + /* Reset RDC MAC */ + r6040_reset_mac(lp); /* Restore MAC Address to MIDx */ adrp = (u16 *) dev->dev_addr; @@ -599,9 +611,9 @@ static void r6040_tx(struct net_device *dev) /* Check for errors */ err = ioread16(ioaddr + MLSR); - if (err & 0x0200) - dev->stats.rx_fifo_errors++; - if (err & (0x2000 | 0x4000)) + if (err & TX_FIFO_UNDR) + dev->stats.tx_fifo_errors++; + if (err & (TX_EXCEEDC | TX_LATEC)) dev->stats.tx_carrier_errors++; if (descptr->status & DSC_OWNER_MAC) @@ -736,11 +748,7 @@ static void r6040_mac_address(struct net_device *dev) u16 *adrp; /* Reset MAC */ - iowrite16(MAC_RST, ioaddr + MCR1); - /* Reset internal state machine */ - iowrite16(MAC_SM_RST, ioaddr + MAC_SM); - iowrite16(0, ioaddr + MAC_SM); - mdelay(5); + r6040_reset_mac(lp); /* Restore MAC Address */ adrp = (u16 *) dev->dev_addr; @@ -840,7 +848,7 @@ static netdev_tx_t r6040_start_xmit(struct sk_buff *skb, skb_tx_timestamp(skb); /* Trigger the MAC to check the TX descriptor */ - iowrite16(0x01, ioaddr + MTPR); + iowrite16(TM2TX, ioaddr + MTPR); lp->tx_insert_ptr = descptr->vndescp; /* If no tx resource, stop */ @@ -973,6 +981,7 @@ static const struct ethtool_ops netdev_ethtool_ops = { .get_settings = netdev_get_settings, .set_settings = netdev_set_settings, .get_link = ethtool_op_get_link, + .get_ts_info = ethtool_op_get_ts_info, }; static const struct net_device_ops r6040_netdev_ops = { @@ -1126,10 +1135,15 @@ static int __devinit r6040_init_one(struct pci_dev *pdev, err = -EIO; goto err_out_free_res; } + /* If PHY status change register is still set to zero it means the - * bootloader didn't initialize it */ + * bootloader didn't initialize it, so we set it to: + * - enable phy status change + * - enable all phy addresses + * - set to lowest timer divider */ if (ioread16(ioaddr + PHY_CC) == 0) - iowrite16(0x9f07, ioaddr + PHY_CC); + iowrite16(SCEN | PHY_MAX_ADDR << PHYAD_SHIFT | + 7 << TMRDIV_SHIFT, ioaddr + PHY_CC); /* Init system & device */ lp->base = ioaddr; diff --git a/trunk/drivers/net/ethernet/realtek/8139cp.c b/trunk/drivers/net/ethernet/realtek/8139cp.c index b3287c0fe279..5eef290997f9 100644 --- a/trunk/drivers/net/ethernet/realtek/8139cp.c +++ b/trunk/drivers/net/ethernet/realtek/8139cp.c @@ -635,9 +635,12 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance) */ static void cp_poll_controller(struct net_device *dev) { - disable_irq(dev->irq); - cp_interrupt(dev->irq, dev); - enable_irq(dev->irq); + struct cp_private *cp = netdev_priv(dev); + const int irq = cp->pdev->irq; + + disable_irq(irq); + cp_interrupt(irq, dev); + enable_irq(irq); } #endif @@ -1117,6 +1120,7 @@ static void cp_free_rings (struct cp_private *cp) static int cp_open (struct net_device *dev) { struct cp_private *cp = netdev_priv(dev); + const int irq = cp->pdev->irq; int rc; netif_dbg(cp, ifup, dev, "enabling interface\n"); @@ -1129,7 +1133,7 @@ static int cp_open (struct net_device *dev) cp_init_hw(cp); - rc = request_irq(dev->irq, cp_interrupt, IRQF_SHARED, dev->name, dev); + rc = request_irq(irq, cp_interrupt, IRQF_SHARED, dev->name, dev); if (rc) goto err_out_hw; @@ -1166,7 +1170,7 @@ static int cp_close (struct net_device *dev) spin_unlock_irqrestore(&cp->lock, flags); - free_irq(dev->irq, dev); + free_irq(cp->pdev->irq, dev); cp_free_rings(cp); return 0; @@ -1914,7 +1918,6 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) (unsigned long long)pciaddr); goto err_out_res; } - dev->base_addr = (unsigned long) regs; cp->regs = regs; cp_stop_hw(cp); @@ -1942,14 +1945,12 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | NETIF_F_HIGHDMA; - dev->irq = pdev->irq; - rc = register_netdev(dev); if (rc) goto err_out_iomap; - netdev_info(dev, "RTL-8139C+ at 0x%lx, %pM, IRQ %d\n", - dev->base_addr, dev->dev_addr, dev->irq); + netdev_info(dev, "RTL-8139C+ at 0x%p, %pM, IRQ %d\n", + regs, dev->dev_addr, pdev->irq); pci_set_drvdata(pdev, dev); diff --git a/trunk/drivers/net/ethernet/realtek/8139too.c b/trunk/drivers/net/ethernet/realtek/8139too.c index df7fd8d083dc..03df076ed596 100644 --- a/trunk/drivers/net/ethernet/realtek/8139too.c +++ b/trunk/drivers/net/ethernet/realtek/8139too.c @@ -148,9 +148,9 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; /* Whether to use MMIO or PIO. Default to MMIO. */ #ifdef CONFIG_8139TOO_PIO -static int use_io = 1; +static bool use_io = true; #else -static int use_io = 0; +static bool use_io = false; #endif /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). @@ -620,7 +620,7 @@ MODULE_DESCRIPTION ("RealTek RTL-8139 Fast Ethernet driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); -module_param(use_io, int, 0); +module_param(use_io, bool, 0); MODULE_PARM_DESC(use_io, "Force use of I/O access mode. 0=MMIO 1=PIO"); module_param(multicast_filter_limit, int, 0); module_param_array(media, int, NULL, 0); @@ -750,15 +750,22 @@ static void rtl8139_chip_reset (void __iomem *ioaddr) static __devinit struct net_device * rtl8139_init_board (struct pci_dev *pdev) { + struct device *d = &pdev->dev; void __iomem *ioaddr; struct net_device *dev; struct rtl8139_private *tp; u8 tmp8; int rc, disable_dev_on_err = 0; - unsigned int i; - unsigned long pio_start, pio_end, pio_flags, pio_len; - unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; + unsigned int i, bar; + unsigned long io_len; u32 version; + static const struct { + unsigned long mask; + char *type; + } res[] = { + { IORESOURCE_IO, "PIO" }, + { IORESOURCE_MEM, "MMIO" } + }; assert (pdev != NULL); @@ -777,78 +784,45 @@ static __devinit struct net_device * rtl8139_init_board (struct pci_dev *pdev) if (rc) goto err_out; - pio_start = pci_resource_start (pdev, 0); - pio_end = pci_resource_end (pdev, 0); - pio_flags = pci_resource_flags (pdev, 0); - pio_len = pci_resource_len (pdev, 0); - - mmio_start = pci_resource_start (pdev, 1); - mmio_end = pci_resource_end (pdev, 1); - mmio_flags = pci_resource_flags (pdev, 1); - mmio_len = pci_resource_len (pdev, 1); - - /* set this immediately, we need to know before - * we talk to the chip directly */ - pr_debug("PIO region size == 0x%02lX\n", pio_len); - pr_debug("MMIO region size == 0x%02lX\n", mmio_len); - -retry: - if (use_io) { - /* make sure PCI base addr 0 is PIO */ - if (!(pio_flags & IORESOURCE_IO)) { - dev_err(&pdev->dev, "region #0 not a PIO resource, aborting\n"); - rc = -ENODEV; - goto err_out; - } - /* check for weird/broken PCI region reporting */ - if (pio_len < RTL_MIN_IO_SIZE) { - dev_err(&pdev->dev, "Invalid PCI I/O region size(s), aborting\n"); - rc = -ENODEV; - goto err_out; - } - } else { - /* make sure PCI base addr 1 is MMIO */ - if (!(mmio_flags & IORESOURCE_MEM)) { - dev_err(&pdev->dev, "region #1 not an MMIO resource, aborting\n"); - rc = -ENODEV; - goto err_out; - } - if (mmio_len < RTL_MIN_IO_SIZE) { - dev_err(&pdev->dev, "Invalid PCI mem region size(s), aborting\n"); - rc = -ENODEV; - goto err_out; - } - } - rc = pci_request_regions (pdev, DRV_NAME); if (rc) goto err_out; disable_dev_on_err = 1; - /* enable PCI bus-mastering */ pci_set_master (pdev); - if (use_io) { - ioaddr = pci_iomap(pdev, 0, 0); - if (!ioaddr) { - dev_err(&pdev->dev, "cannot map PIO, aborting\n"); - rc = -EIO; - goto err_out; - } - dev->base_addr = pio_start; - tp->regs_len = pio_len; - } else { - /* ioremap MMIO region */ - ioaddr = pci_iomap(pdev, 1, 0); - if (ioaddr == NULL) { - dev_err(&pdev->dev, "cannot remap MMIO, trying PIO\n"); - pci_release_regions(pdev); - use_io = 1; +retry: + /* PIO bar register comes first. */ + bar = !use_io; + + io_len = pci_resource_len(pdev, bar); + + dev_dbg(d, "%s region size = 0x%02lX\n", res[bar].type, io_len); + + if (!(pci_resource_flags(pdev, bar) & res[bar].mask)) { + dev_err(d, "region #%d not a %s resource, aborting\n", bar, + res[bar].type); + rc = -ENODEV; + goto err_out; + } + if (io_len < RTL_MIN_IO_SIZE) { + dev_err(d, "Invalid PCI %s region size(s), aborting\n", + res[bar].type); + rc = -ENODEV; + goto err_out; + } + + ioaddr = pci_iomap(pdev, bar, 0); + if (!ioaddr) { + dev_err(d, "cannot map %s\n", res[bar].type); + if (!use_io) { + use_io = true; goto retry; } - dev->base_addr = (long) ioaddr; - tp->regs_len = mmio_len; + rc = -ENODEV; + goto err_out; } + tp->regs_len = io_len; tp->mmio_addr = ioaddr; /* Bring old chips out of low-power mode. */ @@ -1035,8 +1009,6 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, dev->hw_features |= NETIF_F_RXALL; dev->hw_features |= NETIF_F_RXFCS; - dev->irq = pdev->irq; - /* tp zeroed and aligned in alloc_etherdev */ tp = netdev_priv(dev); @@ -1062,9 +1034,9 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, pci_set_drvdata (pdev, dev); - netdev_info(dev, "%s at 0x%lx, %pM, IRQ %d\n", + netdev_info(dev, "%s at 0x%p, %pM, IRQ %d\n", board_info[ent->driver_data].name, - dev->base_addr, dev->dev_addr, dev->irq); + ioaddr, dev->dev_addr, pdev->irq); netdev_dbg(dev, "Identified 8139 chip type '%s'\n", rtl_chip_info[tp->chipset].name); @@ -1339,10 +1311,11 @@ static void mdio_write (struct net_device *dev, int phy_id, int location, static int rtl8139_open (struct net_device *dev) { struct rtl8139_private *tp = netdev_priv(dev); - int retval; void __iomem *ioaddr = tp->mmio_addr; + const int irq = tp->pci_dev->irq; + int retval; - retval = request_irq (dev->irq, rtl8139_interrupt, IRQF_SHARED, dev->name, dev); + retval = request_irq(irq, rtl8139_interrupt, IRQF_SHARED, dev->name, dev); if (retval) return retval; @@ -1351,7 +1324,7 @@ static int rtl8139_open (struct net_device *dev) tp->rx_ring = dma_alloc_coherent(&tp->pci_dev->dev, RX_BUF_TOT_LEN, &tp->rx_ring_dma, GFP_KERNEL); if (tp->tx_bufs == NULL || tp->rx_ring == NULL) { - free_irq(dev->irq, dev); + free_irq(irq, dev); if (tp->tx_bufs) dma_free_coherent(&tp->pci_dev->dev, TX_BUF_TOT_LEN, @@ -1377,7 +1350,7 @@ static int rtl8139_open (struct net_device *dev) "%s() ioaddr %#llx IRQ %d GP Pins %02x %s-duplex\n", __func__, (unsigned long long)pci_resource_start (tp->pci_dev, 1), - dev->irq, RTL_R8 (MediaStatus), + irq, RTL_R8 (MediaStatus), tp->mii.full_duplex ? "full" : "half"); rtl8139_start_thread(tp); @@ -2240,9 +2213,12 @@ static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance) */ static void rtl8139_poll_controller(struct net_device *dev) { - disable_irq(dev->irq); - rtl8139_interrupt(dev->irq, dev); - enable_irq(dev->irq); + struct rtl8139_private *tp = netdev_priv(dev); + const int irq = tp->pci_dev->irq; + + disable_irq(irq); + rtl8139_interrupt(irq, dev); + enable_irq(irq); } #endif @@ -2295,7 +2271,7 @@ static int rtl8139_close (struct net_device *dev) spin_unlock_irqrestore (&tp->lock, flags); - free_irq (dev->irq, dev); + free_irq(tp->pci_dev->irq, dev); rtl8139_tx_clear (tp); diff --git a/trunk/drivers/net/ethernet/realtek/r8169.c b/trunk/drivers/net/ethernet/realtek/r8169.c index ce6b44d1f252..00b4f56a671c 100644 --- a/trunk/drivers/net/ethernet/realtek/r8169.c +++ b/trunk/drivers/net/ethernet/realtek/r8169.c @@ -44,6 +44,8 @@ #define FIRMWARE_8168F_1 "rtl_nic/rtl8168f-1.fw" #define FIRMWARE_8168F_2 "rtl_nic/rtl8168f-2.fw" #define FIRMWARE_8105E_1 "rtl_nic/rtl8105e-1.fw" +#define FIRMWARE_8402_1 "rtl_nic/rtl8402-1.fw" +#define FIRMWARE_8411_1 "rtl_nic/rtl8411-1.fw" #ifdef RTL8169_DEBUG #define assert(expr) \ @@ -137,6 +139,8 @@ enum mac_version { RTL_GIGA_MAC_VER_34, RTL_GIGA_MAC_VER_35, RTL_GIGA_MAC_VER_36, + RTL_GIGA_MAC_VER_37, + RTL_GIGA_MAC_VER_38, RTL_GIGA_MAC_NONE = 0xff, }; @@ -249,6 +253,12 @@ static const struct { [RTL_GIGA_MAC_VER_36] = _R("RTL8168f/8111f", RTL_TD_1, FIRMWARE_8168F_2, JUMBO_9K, false), + [RTL_GIGA_MAC_VER_37] = + _R("RTL8402", RTL_TD_1, FIRMWARE_8402_1, + JUMBO_1K, true), + [RTL_GIGA_MAC_VER_38] = + _R("RTL8411", RTL_TD_1, FIRMWARE_8411_1, + JUMBO_9K, false), }; #undef _R @@ -319,6 +329,8 @@ enum rtl_registers { Config0 = 0x51, Config1 = 0x52, Config2 = 0x53, +#define PME_SIGNAL (1 << 5) /* 8168c and later */ + Config3 = 0x54, Config4 = 0x55, Config5 = 0x56, @@ -359,6 +371,9 @@ enum rtl8168_8101_registers { #define CSIAR_BYTE_ENABLE 0x0f #define CSIAR_BYTE_ENABLE_SHIFT 12 #define CSIAR_ADDR_MASK 0x0fff +#define CSIAR_FUNC_CARD 0x00000000 +#define CSIAR_FUNC_SDIO 0x00010000 +#define CSIAR_FUNC_NIC 0x00020000 PMCH = 0x6f, EPHYAR = 0x80, #define EPHYAR_FLAG 0x80000000 @@ -720,6 +735,11 @@ struct rtl8169_private { void (*disable)(struct rtl8169_private *); } jumbo_ops; + struct csi_ops { + void (*write)(void __iomem *, int, int); + u32 (*read)(void __iomem *, int); + } csi_ops; + int (*set_speed)(struct net_device *, u8 aneg, u16 sp, u8 dpx, u32 adv); int (*get_settings)(struct net_device *, struct ethtool_cmd *); void (*phy_reset_enable)(struct rtl8169_private *tp); @@ -772,6 +792,8 @@ MODULE_FIRMWARE(FIRMWARE_8168E_3); MODULE_FIRMWARE(FIRMWARE_8105E_1); MODULE_FIRMWARE(FIRMWARE_8168F_1); MODULE_FIRMWARE(FIRMWARE_8168F_2); +MODULE_FIRMWARE(FIRMWARE_8402_1); +MODULE_FIRMWARE(FIRMWARE_8411_1); static void rtl_lock_work(struct rtl8169_private *tp) { @@ -1082,40 +1104,6 @@ static u16 rtl_ephy_read(void __iomem *ioaddr, int reg_addr) return value; } -static void rtl_csi_write(void __iomem *ioaddr, int addr, int value) -{ - unsigned int i; - - RTL_W32(CSIDR, value); - RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) | - CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT); - - for (i = 0; i < 100; i++) { - if (!(RTL_R32(CSIAR) & CSIAR_FLAG)) - break; - udelay(10); - } -} - -static u32 rtl_csi_read(void __iomem *ioaddr, int addr) -{ - u32 value = ~0x00; - unsigned int i; - - RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) | - CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT); - - for (i = 0; i < 100; i++) { - if (RTL_R32(CSIAR) & CSIAR_FLAG) { - value = RTL_R32(CSIDR); - break; - } - udelay(10); - } - - return value; -} - static void rtl_eri_write(void __iomem *ioaddr, int addr, u32 mask, u32 val, int type) { @@ -1285,7 +1273,8 @@ static void rtl_link_chg_patch(struct rtl8169_private *tp) if (!netif_running(dev)) return; - if (tp->mac_version == RTL_GIGA_MAC_VER_34) { + if (tp->mac_version == RTL_GIGA_MAC_VER_34 || + tp->mac_version == RTL_GIGA_MAC_VER_38) { if (RTL_R8(PHYstatus) & _1000bpsF) { rtl_eri_write(ioaddr, 0x1bc, ERIAR_MASK_1111, 0x00000011, ERIAR_EXGMAC); @@ -1320,6 +1309,16 @@ static void rtl_link_chg_patch(struct rtl8169_private *tp) rtl_eri_write(ioaddr, 0x1dc, ERIAR_MASK_1111, 0x0000003f, ERIAR_EXGMAC); } + } else if (tp->mac_version == RTL_GIGA_MAC_VER_37) { + if (RTL_R8(PHYstatus) & _10bps) { + rtl_eri_write(ioaddr, 0x1d0, ERIAR_MASK_0011, + 0x4d02, ERIAR_EXGMAC); + rtl_eri_write(ioaddr, 0x1dc, ERIAR_MASK_0011, + 0x0060, ERIAR_EXGMAC); + } else { + rtl_eri_write(ioaddr, 0x1d0, ERIAR_MASK_0011, + 0x0000, ERIAR_EXGMAC); + } } } @@ -1400,7 +1399,6 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) u16 reg; u8 mask; } cfg[] = { - { WAKE_ANY, Config1, PMEnable }, { WAKE_PHY, Config3, LinkUp }, { WAKE_MAGIC, Config3, MagicPacket }, { WAKE_UCAST, Config5, UWF }, @@ -1408,16 +1406,32 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) { WAKE_MCAST, Config5, MWF }, { WAKE_ANY, Config5, LanWake } }; + u8 options; RTL_W8(Cfg9346, Cfg9346_Unlock); for (i = 0; i < ARRAY_SIZE(cfg); i++) { - u8 options = RTL_R8(cfg[i].reg) & ~cfg[i].mask; + options = RTL_R8(cfg[i].reg) & ~cfg[i].mask; if (wolopts & cfg[i].opt) options |= cfg[i].mask; RTL_W8(cfg[i].reg, options); } + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_01 ... RTL_GIGA_MAC_VER_17: + options = RTL_R8(Config1) & ~PMEnable; + if (wolopts) + options |= PMEnable; + RTL_W8(Config1, options); + break; + default: + options = RTL_R8(Config2) & ~PME_SIGNAL; + if (wolopts) + options |= PME_SIGNAL; + RTL_W8(Config2, options); + break; + } + RTL_W8(Cfg9346, Cfg9346_Lock); } @@ -1857,6 +1871,7 @@ static const struct ethtool_ops rtl8169_ethtool_ops = { .get_strings = rtl8169_get_strings, .get_sset_count = rtl8169_get_sset_count, .get_ethtool_stats = rtl8169_get_ethtool_stats, + .get_ts_info = ethtool_op_get_ts_info, }; static void rtl8169_get_mac_version(struct rtl8169_private *tp, @@ -1880,6 +1895,7 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, int mac_version; } mac_info[] = { /* 8168F family. */ + { 0x7c800000, 0x48800000, RTL_GIGA_MAC_VER_38 }, { 0x7cf00000, 0x48100000, RTL_GIGA_MAC_VER_36 }, { 0x7cf00000, 0x48000000, RTL_GIGA_MAC_VER_35 }, @@ -1917,6 +1933,7 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, { 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 }, /* 8101 family. */ + { 0x7c800000, 0x44000000, RTL_GIGA_MAC_VER_37 }, { 0x7cf00000, 0x40b00000, RTL_GIGA_MAC_VER_30 }, { 0x7cf00000, 0x40a00000, RTL_GIGA_MAC_VER_30 }, { 0x7cf00000, 0x40900000, RTL_GIGA_MAC_VER_29 }, @@ -3017,6 +3034,28 @@ static void rtl8168e_2_hw_phy_config(struct rtl8169_private *tp) rtl_writephy(tp, 0x1f, 0x0000); } +static void rtl8168f_hw_phy_config(struct rtl8169_private *tp) +{ + /* For 4-corner performance improve */ + rtl_writephy(tp, 0x1f, 0x0005); + rtl_writephy(tp, 0x05, 0x8b80); + rtl_w1w0_phy(tp, 0x06, 0x0006, 0x0000); + rtl_writephy(tp, 0x1f, 0x0000); + + /* PHY auto speed down */ + rtl_writephy(tp, 0x1f, 0x0007); + rtl_writephy(tp, 0x1e, 0x002d); + rtl_w1w0_phy(tp, 0x18, 0x0010, 0x0000); + rtl_writephy(tp, 0x1f, 0x0000); + rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000); + + /* Improve 10M EEE waveform */ + rtl_writephy(tp, 0x1f, 0x0005); + rtl_writephy(tp, 0x05, 0x8b86); + rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000); + rtl_writephy(tp, 0x1f, 0x0000); +} + static void rtl8168f_1_hw_phy_config(struct rtl8169_private *tp) { static const struct phy_reg phy_reg_init[] = { @@ -3058,24 +3097,7 @@ static void rtl8168f_1_hw_phy_config(struct rtl8169_private *tp) rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init)); - /* For 4-corner performance improve */ - rtl_writephy(tp, 0x1f, 0x0005); - rtl_writephy(tp, 0x05, 0x8b80); - rtl_w1w0_phy(tp, 0x06, 0x0006, 0x0000); - rtl_writephy(tp, 0x1f, 0x0000); - - /* PHY auto speed down */ - rtl_writephy(tp, 0x1f, 0x0007); - rtl_writephy(tp, 0x1e, 0x002d); - rtl_w1w0_phy(tp, 0x18, 0x0010, 0x0000); - rtl_writephy(tp, 0x1f, 0x0000); - rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000); - - /* Improve 10M EEE waveform */ - rtl_writephy(tp, 0x1f, 0x0005); - rtl_writephy(tp, 0x05, 0x8b86); - rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000); - rtl_writephy(tp, 0x1f, 0x0000); + rtl8168f_hw_phy_config(tp); /* Improve 2-pair detection performance */ rtl_writephy(tp, 0x1f, 0x0005); @@ -3088,23 +3110,104 @@ static void rtl8168f_2_hw_phy_config(struct rtl8169_private *tp) { rtl_apply_firmware(tp); - /* For 4-corner performance improve */ + rtl8168f_hw_phy_config(tp); +} + +static void rtl8411_hw_phy_config(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + static const struct phy_reg phy_reg_init[] = { + /* Channel estimation fine tune */ + { 0x1f, 0x0003 }, + { 0x09, 0xa20f }, + { 0x1f, 0x0000 }, + + /* Modify green table for giga & fnet */ + { 0x1f, 0x0005 }, + { 0x05, 0x8b55 }, + { 0x06, 0x0000 }, + { 0x05, 0x8b5e }, + { 0x06, 0x0000 }, + { 0x05, 0x8b67 }, + { 0x06, 0x0000 }, + { 0x05, 0x8b70 }, + { 0x06, 0x0000 }, + { 0x1f, 0x0000 }, + { 0x1f, 0x0007 }, + { 0x1e, 0x0078 }, + { 0x17, 0x0000 }, + { 0x19, 0x00aa }, + { 0x1f, 0x0000 }, + + /* Modify green table for 10M */ + { 0x1f, 0x0005 }, + { 0x05, 0x8b79 }, + { 0x06, 0xaa00 }, + { 0x1f, 0x0000 }, + + /* Disable hiimpedance detection (RTCT) */ + { 0x1f, 0x0003 }, + { 0x01, 0x328a }, + { 0x1f, 0x0000 } + }; + + + rtl_apply_firmware(tp); + + rtl8168f_hw_phy_config(tp); + + /* Improve 2-pair detection performance */ rtl_writephy(tp, 0x1f, 0x0005); - rtl_writephy(tp, 0x05, 0x8b80); - rtl_w1w0_phy(tp, 0x06, 0x0006, 0x0000); + rtl_writephy(tp, 0x05, 0x8b85); + rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000); rtl_writephy(tp, 0x1f, 0x0000); - /* PHY auto speed down */ - rtl_writephy(tp, 0x1f, 0x0007); - rtl_writephy(tp, 0x1e, 0x002d); - rtl_w1w0_phy(tp, 0x18, 0x0010, 0x0000); + rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init)); + + /* Modify green table for giga */ + rtl_writephy(tp, 0x1f, 0x0005); + rtl_writephy(tp, 0x05, 0x8b54); + rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0800); + rtl_writephy(tp, 0x05, 0x8b5d); + rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0800); + rtl_writephy(tp, 0x05, 0x8a7c); + rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100); + rtl_writephy(tp, 0x05, 0x8a7f); + rtl_w1w0_phy(tp, 0x06, 0x0100, 0x0000); + rtl_writephy(tp, 0x05, 0x8a82); + rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100); + rtl_writephy(tp, 0x05, 0x8a85); + rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100); + rtl_writephy(tp, 0x05, 0x8a88); + rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100); rtl_writephy(tp, 0x1f, 0x0000); - rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000); - /* Improve 10M EEE waveform */ + /* uc same-seed solution */ rtl_writephy(tp, 0x1f, 0x0005); - rtl_writephy(tp, 0x05, 0x8b86); - rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000); + rtl_writephy(tp, 0x05, 0x8b85); + rtl_w1w0_phy(tp, 0x06, 0x8000, 0x0000); + rtl_writephy(tp, 0x1f, 0x0000); + + /* eee setting */ + rtl_w1w0_eri(ioaddr, 0x1b0, ERIAR_MASK_0001, 0x00, 0x03, ERIAR_EXGMAC); + rtl_writephy(tp, 0x1f, 0x0005); + rtl_writephy(tp, 0x05, 0x8b85); + rtl_w1w0_phy(tp, 0x06, 0x0000, 0x2000); + rtl_writephy(tp, 0x1f, 0x0004); + rtl_writephy(tp, 0x1f, 0x0007); + rtl_writephy(tp, 0x1e, 0x0020); + rtl_w1w0_phy(tp, 0x15, 0x0000, 0x0100); + rtl_writephy(tp, 0x1f, 0x0000); + rtl_writephy(tp, 0x0d, 0x0007); + rtl_writephy(tp, 0x0e, 0x003c); + rtl_writephy(tp, 0x0d, 0x4007); + rtl_writephy(tp, 0x0e, 0x0000); + rtl_writephy(tp, 0x0d, 0x0000); + + /* Green feature */ + rtl_writephy(tp, 0x1f, 0x0003); + rtl_w1w0_phy(tp, 0x19, 0x0000, 0x0001); + rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0400); rtl_writephy(tp, 0x1f, 0x0000); } @@ -3151,6 +3254,25 @@ static void rtl8105e_hw_phy_config(struct rtl8169_private *tp) rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init)); } +static void rtl8402_hw_phy_config(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + + /* Disable ALDPS before setting firmware */ + rtl_writephy(tp, 0x1f, 0x0000); + rtl_writephy(tp, 0x18, 0x0310); + msleep(20); + + rtl_apply_firmware(tp); + + /* EEE setting */ + rtl_eri_write(ioaddr, 0x1b0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC); + rtl_writephy(tp, 0x1f, 0x0004); + rtl_writephy(tp, 0x10, 0x401f); + rtl_writephy(tp, 0x19, 0x7030); + rtl_writephy(tp, 0x1f, 0x0000); +} + static void rtl_hw_phy_config(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); @@ -3239,6 +3361,14 @@ static void rtl_hw_phy_config(struct net_device *dev) rtl8168f_2_hw_phy_config(tp); break; + case RTL_GIGA_MAC_VER_37: + rtl8402_hw_phy_config(tp); + break; + + case RTL_GIGA_MAC_VER_38: + rtl8411_hw_phy_config(tp); + break; + default: break; } @@ -3476,6 +3606,8 @@ static void rtl_wol_suspend_quirk(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_32: case RTL_GIGA_MAC_VER_33: case RTL_GIGA_MAC_VER_34: + case RTL_GIGA_MAC_VER_37: + case RTL_GIGA_MAC_VER_38: RTL_W32(RxConfig, RTL_R32(RxConfig) | AcceptBroadcast | AcceptMulticast | AcceptMyPhys); break; @@ -3511,15 +3643,45 @@ static void r810x_phy_power_up(struct rtl8169_private *tp) static void r810x_pll_power_down(struct rtl8169_private *tp) { + void __iomem *ioaddr = tp->mmio_addr; + if (rtl_wol_pll_power_down(tp)) return; r810x_phy_power_down(tp); + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_07: + case RTL_GIGA_MAC_VER_08: + case RTL_GIGA_MAC_VER_09: + case RTL_GIGA_MAC_VER_10: + case RTL_GIGA_MAC_VER_13: + case RTL_GIGA_MAC_VER_16: + break; + default: + RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80); + break; + } } static void r810x_pll_power_up(struct rtl8169_private *tp) { + void __iomem *ioaddr = tp->mmio_addr; + r810x_phy_power_up(tp); + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_07: + case RTL_GIGA_MAC_VER_08: + case RTL_GIGA_MAC_VER_09: + case RTL_GIGA_MAC_VER_10: + case RTL_GIGA_MAC_VER_13: + case RTL_GIGA_MAC_VER_16: + break; + default: + RTL_W8(PMCH, RTL_R8(PMCH) | 0x80); + break; + } } static void r8168_phy_power_up(struct rtl8169_private *tp) @@ -3623,13 +3785,6 @@ static void r8168_pll_power_up(struct rtl8169_private *tp) { void __iomem *ioaddr = tp->mmio_addr; - if ((tp->mac_version == RTL_GIGA_MAC_VER_27 || - tp->mac_version == RTL_GIGA_MAC_VER_28 || - tp->mac_version == RTL_GIGA_MAC_VER_31) && - r8168dp_check_dash(tp)) { - return; - } - switch (tp->mac_version) { case RTL_GIGA_MAC_VER_25: case RTL_GIGA_MAC_VER_26: @@ -3674,6 +3829,7 @@ static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_16: case RTL_GIGA_MAC_VER_29: case RTL_GIGA_MAC_VER_30: + case RTL_GIGA_MAC_VER_37: ops->down = r810x_pll_power_down; ops->up = r810x_pll_power_up; break; @@ -3698,6 +3854,7 @@ static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_34: case RTL_GIGA_MAC_VER_35: case RTL_GIGA_MAC_VER_36: + case RTL_GIGA_MAC_VER_38: ops->down = r8168_pll_power_down; ops->up = r8168_pll_power_up; break; @@ -3983,7 +4140,9 @@ static void rtl8169_hw_reset(struct rtl8169_private *tp) udelay(20); } else if (tp->mac_version == RTL_GIGA_MAC_VER_34 || tp->mac_version == RTL_GIGA_MAC_VER_35 || - tp->mac_version == RTL_GIGA_MAC_VER_36) { + tp->mac_version == RTL_GIGA_MAC_VER_36 || + tp->mac_version == RTL_GIGA_MAC_VER_37 || + tp->mac_version == RTL_GIGA_MAC_VER_38) { RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq); while (!(RTL_R32(TxConfig) & TXCFG_EMPTY)) udelay(100); @@ -4189,22 +4348,141 @@ static void rtl_hw_start_8169(struct net_device *dev) RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000); } -static void rtl_csi_access_enable(void __iomem *ioaddr, u32 bits) +static void rtl_csi_write(struct rtl8169_private *tp, int addr, int value) +{ + if (tp->csi_ops.write) + tp->csi_ops.write(tp->mmio_addr, addr, value); +} + +static u32 rtl_csi_read(struct rtl8169_private *tp, int addr) +{ + if (tp->csi_ops.read) + return tp->csi_ops.read(tp->mmio_addr, addr); + else + return ~0; +} + +static void rtl_csi_access_enable(struct rtl8169_private *tp, u32 bits) { u32 csi; - csi = rtl_csi_read(ioaddr, 0x070c) & 0x00ffffff; - rtl_csi_write(ioaddr, 0x070c, csi | bits); + csi = rtl_csi_read(tp, 0x070c) & 0x00ffffff; + rtl_csi_write(tp, 0x070c, csi | bits); +} + +static void rtl_csi_access_enable_1(struct rtl8169_private *tp) +{ + rtl_csi_access_enable(tp, 0x17000000); +} + +static void rtl_csi_access_enable_2(struct rtl8169_private *tp) +{ + rtl_csi_access_enable(tp, 0x27000000); +} + +static void r8169_csi_write(void __iomem *ioaddr, int addr, int value) +{ + unsigned int i; + + RTL_W32(CSIDR, value); + RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) | + CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT); + + for (i = 0; i < 100; i++) { + if (!(RTL_R32(CSIAR) & CSIAR_FLAG)) + break; + udelay(10); + } +} + +static u32 r8169_csi_read(void __iomem *ioaddr, int addr) +{ + u32 value = ~0x00; + unsigned int i; + + RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) | + CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT); + + for (i = 0; i < 100; i++) { + if (RTL_R32(CSIAR) & CSIAR_FLAG) { + value = RTL_R32(CSIDR); + break; + } + udelay(10); + } + + return value; +} + +static void r8402_csi_write(void __iomem *ioaddr, int addr, int value) +{ + unsigned int i; + + RTL_W32(CSIDR, value); + RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) | + CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT | + CSIAR_FUNC_NIC); + + for (i = 0; i < 100; i++) { + if (!(RTL_R32(CSIAR) & CSIAR_FLAG)) + break; + udelay(10); + } } -static void rtl_csi_access_enable_1(void __iomem *ioaddr) +static u32 r8402_csi_read(void __iomem *ioaddr, int addr) { - rtl_csi_access_enable(ioaddr, 0x17000000); + u32 value = ~0x00; + unsigned int i; + + RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) | CSIAR_FUNC_NIC | + CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT); + + for (i = 0; i < 100; i++) { + if (RTL_R32(CSIAR) & CSIAR_FLAG) { + value = RTL_R32(CSIDR); + break; + } + udelay(10); + } + + return value; } -static void rtl_csi_access_enable_2(void __iomem *ioaddr) +static void __devinit rtl_init_csi_ops(struct rtl8169_private *tp) { - rtl_csi_access_enable(ioaddr, 0x27000000); + struct csi_ops *ops = &tp->csi_ops; + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_01: + case RTL_GIGA_MAC_VER_02: + case RTL_GIGA_MAC_VER_03: + case RTL_GIGA_MAC_VER_04: + case RTL_GIGA_MAC_VER_05: + case RTL_GIGA_MAC_VER_06: + case RTL_GIGA_MAC_VER_10: + case RTL_GIGA_MAC_VER_11: + case RTL_GIGA_MAC_VER_12: + case RTL_GIGA_MAC_VER_13: + case RTL_GIGA_MAC_VER_14: + case RTL_GIGA_MAC_VER_15: + case RTL_GIGA_MAC_VER_16: + case RTL_GIGA_MAC_VER_17: + ops->write = NULL; + ops->read = NULL; + break; + + case RTL_GIGA_MAC_VER_37: + case RTL_GIGA_MAC_VER_38: + ops->write = r8402_csi_write; + ops->read = r8402_csi_read; + break; + + default: + ops->write = r8169_csi_write; + ops->read = r8169_csi_read; + break; + } } struct ephy_info { @@ -4261,8 +4539,11 @@ static void rtl_enable_clock_request(struct pci_dev *pdev) PktCntrDisable | \ Mac_dbgo_sel) -static void rtl_hw_start_8168bb(void __iomem *ioaddr, struct pci_dev *pdev) +static void rtl_hw_start_8168bb(struct rtl8169_private *tp) { + void __iomem *ioaddr = tp->mmio_addr; + struct pci_dev *pdev = tp->pci_dev; + RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); @@ -4271,17 +4552,22 @@ static void rtl_hw_start_8168bb(void __iomem *ioaddr, struct pci_dev *pdev) (0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN); } -static void rtl_hw_start_8168bef(void __iomem *ioaddr, struct pci_dev *pdev) +static void rtl_hw_start_8168bef(struct rtl8169_private *tp) { - rtl_hw_start_8168bb(ioaddr, pdev); + void __iomem *ioaddr = tp->mmio_addr; + + rtl_hw_start_8168bb(tp); RTL_W8(MaxTxPacketSize, TxPacketMax); RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0)); } -static void __rtl_hw_start_8168cp(void __iomem *ioaddr, struct pci_dev *pdev) +static void __rtl_hw_start_8168cp(struct rtl8169_private *tp) { + void __iomem *ioaddr = tp->mmio_addr; + struct pci_dev *pdev = tp->pci_dev; + RTL_W8(Config1, RTL_R8(Config1) | Speed_down); RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); @@ -4293,8 +4579,9 @@ static void __rtl_hw_start_8168cp(void __iomem *ioaddr, struct pci_dev *pdev) RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); } -static void rtl_hw_start_8168cp_1(void __iomem *ioaddr, struct pci_dev *pdev) +static void rtl_hw_start_8168cp_1(struct rtl8169_private *tp) { + void __iomem *ioaddr = tp->mmio_addr; static const struct ephy_info e_info_8168cp[] = { { 0x01, 0, 0x0001 }, { 0x02, 0x0800, 0x1000 }, @@ -4303,16 +4590,19 @@ static void rtl_hw_start_8168cp_1(void __iomem *ioaddr, struct pci_dev *pdev) { 0x07, 0, 0x2000 } }; - rtl_csi_access_enable_2(ioaddr); + rtl_csi_access_enable_2(tp); rtl_ephy_init(ioaddr, e_info_8168cp, ARRAY_SIZE(e_info_8168cp)); - __rtl_hw_start_8168cp(ioaddr, pdev); + __rtl_hw_start_8168cp(tp); } -static void rtl_hw_start_8168cp_2(void __iomem *ioaddr, struct pci_dev *pdev) +static void rtl_hw_start_8168cp_2(struct rtl8169_private *tp) { - rtl_csi_access_enable_2(ioaddr); + void __iomem *ioaddr = tp->mmio_addr; + struct pci_dev *pdev = tp->pci_dev; + + rtl_csi_access_enable_2(tp); RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); @@ -4321,9 +4611,12 @@ static void rtl_hw_start_8168cp_2(void __iomem *ioaddr, struct pci_dev *pdev) RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); } -static void rtl_hw_start_8168cp_3(void __iomem *ioaddr, struct pci_dev *pdev) +static void rtl_hw_start_8168cp_3(struct rtl8169_private *tp) { - rtl_csi_access_enable_2(ioaddr); + void __iomem *ioaddr = tp->mmio_addr; + struct pci_dev *pdev = tp->pci_dev; + + rtl_csi_access_enable_2(tp); RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); @@ -4337,52 +4630,57 @@ static void rtl_hw_start_8168cp_3(void __iomem *ioaddr, struct pci_dev *pdev) RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); } -static void rtl_hw_start_8168c_1(void __iomem *ioaddr, struct pci_dev *pdev) +static void rtl_hw_start_8168c_1(struct rtl8169_private *tp) { + void __iomem *ioaddr = tp->mmio_addr; static const struct ephy_info e_info_8168c_1[] = { { 0x02, 0x0800, 0x1000 }, { 0x03, 0, 0x0002 }, { 0x06, 0x0080, 0x0000 } }; - rtl_csi_access_enable_2(ioaddr); + rtl_csi_access_enable_2(tp); RTL_W8(DBG_REG, 0x06 | FIX_NAK_1 | FIX_NAK_2); rtl_ephy_init(ioaddr, e_info_8168c_1, ARRAY_SIZE(e_info_8168c_1)); - __rtl_hw_start_8168cp(ioaddr, pdev); + __rtl_hw_start_8168cp(tp); } -static void rtl_hw_start_8168c_2(void __iomem *ioaddr, struct pci_dev *pdev) +static void rtl_hw_start_8168c_2(struct rtl8169_private *tp) { + void __iomem *ioaddr = tp->mmio_addr; static const struct ephy_info e_info_8168c_2[] = { { 0x01, 0, 0x0001 }, { 0x03, 0x0400, 0x0220 } }; - rtl_csi_access_enable_2(ioaddr); + rtl_csi_access_enable_2(tp); rtl_ephy_init(ioaddr, e_info_8168c_2, ARRAY_SIZE(e_info_8168c_2)); - __rtl_hw_start_8168cp(ioaddr, pdev); + __rtl_hw_start_8168cp(tp); } -static void rtl_hw_start_8168c_3(void __iomem *ioaddr, struct pci_dev *pdev) +static void rtl_hw_start_8168c_3(struct rtl8169_private *tp) { - rtl_hw_start_8168c_2(ioaddr, pdev); + rtl_hw_start_8168c_2(tp); } -static void rtl_hw_start_8168c_4(void __iomem *ioaddr, struct pci_dev *pdev) +static void rtl_hw_start_8168c_4(struct rtl8169_private *tp) { - rtl_csi_access_enable_2(ioaddr); + rtl_csi_access_enable_2(tp); - __rtl_hw_start_8168cp(ioaddr, pdev); + __rtl_hw_start_8168cp(tp); } -static void rtl_hw_start_8168d(void __iomem *ioaddr, struct pci_dev *pdev) +static void rtl_hw_start_8168d(struct rtl8169_private *tp) { - rtl_csi_access_enable_2(ioaddr); + void __iomem *ioaddr = tp->mmio_addr; + struct pci_dev *pdev = tp->pci_dev; + + rtl_csi_access_enable_2(tp); rtl_disable_clock_request(pdev); @@ -4393,9 +4691,12 @@ static void rtl_hw_start_8168d(void __iomem *ioaddr, struct pci_dev *pdev) RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); } -static void rtl_hw_start_8168dp(void __iomem *ioaddr, struct pci_dev *pdev) +static void rtl_hw_start_8168dp(struct rtl8169_private *tp) { - rtl_csi_access_enable_1(ioaddr); + void __iomem *ioaddr = tp->mmio_addr; + struct pci_dev *pdev = tp->pci_dev; + + rtl_csi_access_enable_1(tp); rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); @@ -4404,8 +4705,10 @@ static void rtl_hw_start_8168dp(void __iomem *ioaddr, struct pci_dev *pdev) rtl_disable_clock_request(pdev); } -static void rtl_hw_start_8168d_4(void __iomem *ioaddr, struct pci_dev *pdev) +static void rtl_hw_start_8168d_4(struct rtl8169_private *tp) { + void __iomem *ioaddr = tp->mmio_addr; + struct pci_dev *pdev = tp->pci_dev; static const struct ephy_info e_info_8168d_4[] = { { 0x0b, ~0, 0x48 }, { 0x19, 0x20, 0x50 }, @@ -4413,7 +4716,7 @@ static void rtl_hw_start_8168d_4(void __iomem *ioaddr, struct pci_dev *pdev) }; int i; - rtl_csi_access_enable_1(ioaddr); + rtl_csi_access_enable_1(tp); rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); @@ -4430,8 +4733,10 @@ static void rtl_hw_start_8168d_4(void __iomem *ioaddr, struct pci_dev *pdev) rtl_enable_clock_request(pdev); } -static void rtl_hw_start_8168e_1(void __iomem *ioaddr, struct pci_dev *pdev) +static void rtl_hw_start_8168e_1(struct rtl8169_private *tp) { + void __iomem *ioaddr = tp->mmio_addr; + struct pci_dev *pdev = tp->pci_dev; static const struct ephy_info e_info_8168e_1[] = { { 0x00, 0x0200, 0x0100 }, { 0x00, 0x0000, 0x0004 }, @@ -4448,7 +4753,7 @@ static void rtl_hw_start_8168e_1(void __iomem *ioaddr, struct pci_dev *pdev) { 0x0a, 0x0000, 0x0040 } }; - rtl_csi_access_enable_2(ioaddr); + rtl_csi_access_enable_2(tp); rtl_ephy_init(ioaddr, e_info_8168e_1, ARRAY_SIZE(e_info_8168e_1)); @@ -4465,14 +4770,16 @@ static void rtl_hw_start_8168e_1(void __iomem *ioaddr, struct pci_dev *pdev) RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en); } -static void rtl_hw_start_8168e_2(void __iomem *ioaddr, struct pci_dev *pdev) +static void rtl_hw_start_8168e_2(struct rtl8169_private *tp) { + void __iomem *ioaddr = tp->mmio_addr; + struct pci_dev *pdev = tp->pci_dev; static const struct ephy_info e_info_8168e_2[] = { { 0x09, 0x0000, 0x0080 }, { 0x19, 0x0000, 0x0224 } }; - rtl_csi_access_enable_1(ioaddr); + rtl_csi_access_enable_1(tp); rtl_ephy_init(ioaddr, e_info_8168e_2, ARRAY_SIZE(e_info_8168e_2)); @@ -4503,18 +4810,12 @@ static void rtl_hw_start_8168e_2(void __iomem *ioaddr, struct pci_dev *pdev) RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en); } -static void rtl_hw_start_8168f_1(void __iomem *ioaddr, struct pci_dev *pdev) +static void rtl_hw_start_8168f(struct rtl8169_private *tp) { - static const struct ephy_info e_info_8168f_1[] = { - { 0x06, 0x00c0, 0x0020 }, - { 0x08, 0x0001, 0x0002 }, - { 0x09, 0x0000, 0x0080 }, - { 0x19, 0x0000, 0x0224 } - }; - - rtl_csi_access_enable_1(ioaddr); + void __iomem *ioaddr = tp->mmio_addr; + struct pci_dev *pdev = tp->pci_dev; - rtl_ephy_init(ioaddr, e_info_8168f_1, ARRAY_SIZE(e_info_8168f_1)); + rtl_csi_access_enable_2(tp); rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); @@ -4528,8 +4829,6 @@ static void rtl_hw_start_8168f_1(void __iomem *ioaddr, struct pci_dev *pdev) rtl_w1w0_eri(ioaddr, 0x1d0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC); rtl_eri_write(ioaddr, 0xcc, ERIAR_MASK_1111, 0x00000050, ERIAR_EXGMAC); rtl_eri_write(ioaddr, 0xd0, ERIAR_MASK_1111, 0x00000060, ERIAR_EXGMAC); - rtl_w1w0_eri(ioaddr, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0xff00, - ERIAR_EXGMAC); RTL_W8(MaxTxPacketSize, EarlySize); @@ -4537,20 +4836,54 @@ static void rtl_hw_start_8168f_1(void __iomem *ioaddr, struct pci_dev *pdev) RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO); RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB); + RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN); + RTL_W32(MISC, RTL_R32(MISC) | PWM_EN); + RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en); +} + +static void rtl_hw_start_8168f_1(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + static const struct ephy_info e_info_8168f_1[] = { + { 0x06, 0x00c0, 0x0020 }, + { 0x08, 0x0001, 0x0002 }, + { 0x09, 0x0000, 0x0080 }, + { 0x19, 0x0000, 0x0224 } + }; + + rtl_hw_start_8168f(tp); + + rtl_ephy_init(ioaddr, e_info_8168f_1, ARRAY_SIZE(e_info_8168f_1)); + + rtl_w1w0_eri(ioaddr, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0xff00, + ERIAR_EXGMAC); /* Adjust EEE LED frequency */ RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07); +} - RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN); - RTL_W32(MISC, RTL_R32(MISC) | PWM_EN); - RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en); +static void rtl_hw_start_8411(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + static const struct ephy_info e_info_8168f_1[] = { + { 0x06, 0x00c0, 0x0020 }, + { 0x0f, 0xffff, 0x5200 }, + { 0x1e, 0x0000, 0x4000 }, + { 0x19, 0x0000, 0x0224 } + }; + + rtl_hw_start_8168f(tp); + + rtl_ephy_init(ioaddr, e_info_8168f_1, ARRAY_SIZE(e_info_8168f_1)); + + rtl_w1w0_eri(ioaddr, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0x0000, + ERIAR_EXGMAC); } static void rtl_hw_start_8168(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; - struct pci_dev *pdev = tp->pci_dev; RTL_W8(Cfg9346, Cfg9346_Unlock); @@ -4581,67 +4914,71 @@ static void rtl_hw_start_8168(struct net_device *dev) switch (tp->mac_version) { case RTL_GIGA_MAC_VER_11: - rtl_hw_start_8168bb(ioaddr, pdev); + rtl_hw_start_8168bb(tp); break; case RTL_GIGA_MAC_VER_12: case RTL_GIGA_MAC_VER_17: - rtl_hw_start_8168bef(ioaddr, pdev); + rtl_hw_start_8168bef(tp); break; case RTL_GIGA_MAC_VER_18: - rtl_hw_start_8168cp_1(ioaddr, pdev); + rtl_hw_start_8168cp_1(tp); break; case RTL_GIGA_MAC_VER_19: - rtl_hw_start_8168c_1(ioaddr, pdev); + rtl_hw_start_8168c_1(tp); break; case RTL_GIGA_MAC_VER_20: - rtl_hw_start_8168c_2(ioaddr, pdev); + rtl_hw_start_8168c_2(tp); break; case RTL_GIGA_MAC_VER_21: - rtl_hw_start_8168c_3(ioaddr, pdev); + rtl_hw_start_8168c_3(tp); break; case RTL_GIGA_MAC_VER_22: - rtl_hw_start_8168c_4(ioaddr, pdev); + rtl_hw_start_8168c_4(tp); break; case RTL_GIGA_MAC_VER_23: - rtl_hw_start_8168cp_2(ioaddr, pdev); + rtl_hw_start_8168cp_2(tp); break; case RTL_GIGA_MAC_VER_24: - rtl_hw_start_8168cp_3(ioaddr, pdev); + rtl_hw_start_8168cp_3(tp); break; case RTL_GIGA_MAC_VER_25: case RTL_GIGA_MAC_VER_26: case RTL_GIGA_MAC_VER_27: - rtl_hw_start_8168d(ioaddr, pdev); + rtl_hw_start_8168d(tp); break; case RTL_GIGA_MAC_VER_28: - rtl_hw_start_8168d_4(ioaddr, pdev); + rtl_hw_start_8168d_4(tp); break; case RTL_GIGA_MAC_VER_31: - rtl_hw_start_8168dp(ioaddr, pdev); + rtl_hw_start_8168dp(tp); break; case RTL_GIGA_MAC_VER_32: case RTL_GIGA_MAC_VER_33: - rtl_hw_start_8168e_1(ioaddr, pdev); + rtl_hw_start_8168e_1(tp); break; case RTL_GIGA_MAC_VER_34: - rtl_hw_start_8168e_2(ioaddr, pdev); + rtl_hw_start_8168e_2(tp); break; case RTL_GIGA_MAC_VER_35: case RTL_GIGA_MAC_VER_36: - rtl_hw_start_8168f_1(ioaddr, pdev); + rtl_hw_start_8168f_1(tp); + break; + + case RTL_GIGA_MAC_VER_38: + rtl_hw_start_8411(tp); break; default: @@ -4668,8 +5005,10 @@ static void rtl_hw_start_8168(struct net_device *dev) PktCntrDisable | \ Mac_dbgo_sel) -static void rtl_hw_start_8102e_1(void __iomem *ioaddr, struct pci_dev *pdev) +static void rtl_hw_start_8102e_1(struct rtl8169_private *tp) { + void __iomem *ioaddr = tp->mmio_addr; + struct pci_dev *pdev = tp->pci_dev; static const struct ephy_info e_info_8102e_1[] = { { 0x01, 0, 0x6e65 }, { 0x02, 0, 0x091f }, @@ -4682,7 +5021,7 @@ static void rtl_hw_start_8102e_1(void __iomem *ioaddr, struct pci_dev *pdev) }; u8 cfg1; - rtl_csi_access_enable_2(ioaddr); + rtl_csi_access_enable_2(tp); RTL_W8(DBG_REG, FIX_NAK_1); @@ -4699,9 +5038,12 @@ static void rtl_hw_start_8102e_1(void __iomem *ioaddr, struct pci_dev *pdev) rtl_ephy_init(ioaddr, e_info_8102e_1, ARRAY_SIZE(e_info_8102e_1)); } -static void rtl_hw_start_8102e_2(void __iomem *ioaddr, struct pci_dev *pdev) +static void rtl_hw_start_8102e_2(struct rtl8169_private *tp) { - rtl_csi_access_enable_2(ioaddr); + void __iomem *ioaddr = tp->mmio_addr; + struct pci_dev *pdev = tp->pci_dev; + + rtl_csi_access_enable_2(tp); rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); @@ -4709,15 +5051,16 @@ static void rtl_hw_start_8102e_2(void __iomem *ioaddr, struct pci_dev *pdev) RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); } -static void rtl_hw_start_8102e_3(void __iomem *ioaddr, struct pci_dev *pdev) +static void rtl_hw_start_8102e_3(struct rtl8169_private *tp) { - rtl_hw_start_8102e_2(ioaddr, pdev); + rtl_hw_start_8102e_2(tp); - rtl_ephy_write(ioaddr, 0x03, 0xc2f9); + rtl_ephy_write(tp->mmio_addr, 0x03, 0xc2f9); } -static void rtl_hw_start_8105e_1(void __iomem *ioaddr, struct pci_dev *pdev) +static void rtl_hw_start_8105e_1(struct rtl8169_private *tp) { + void __iomem *ioaddr = tp->mmio_addr; static const struct ephy_info e_info_8105e_1[] = { { 0x07, 0, 0x4000 }, { 0x19, 0, 0x0200 }, @@ -4741,12 +5084,44 @@ static void rtl_hw_start_8105e_1(void __iomem *ioaddr, struct pci_dev *pdev) rtl_ephy_init(ioaddr, e_info_8105e_1, ARRAY_SIZE(e_info_8105e_1)); } -static void rtl_hw_start_8105e_2(void __iomem *ioaddr, struct pci_dev *pdev) +static void rtl_hw_start_8105e_2(struct rtl8169_private *tp) { - rtl_hw_start_8105e_1(ioaddr, pdev); + void __iomem *ioaddr = tp->mmio_addr; + + rtl_hw_start_8105e_1(tp); rtl_ephy_write(ioaddr, 0x1e, rtl_ephy_read(ioaddr, 0x1e) | 0x8000); } +static void rtl_hw_start_8402(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + static const struct ephy_info e_info_8402[] = { + { 0x19, 0xffff, 0xff64 }, + { 0x1e, 0, 0x4000 } + }; + + rtl_csi_access_enable_2(tp); + + /* Force LAN exit from ASPM if Rx/Tx are not idle */ + RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800); + + RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO); + RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB); + + rtl_ephy_init(ioaddr, e_info_8402, ARRAY_SIZE(e_info_8402)); + + rtl_tx_performance_tweak(tp->pci_dev, 0x5 << MAX_READ_REQUEST_SHIFT); + + rtl_eri_write(ioaddr, 0xc8, ERIAR_MASK_1111, 0x00000002, ERIAR_EXGMAC); + rtl_eri_write(ioaddr, 0xe8, ERIAR_MASK_1111, 0x00000006, ERIAR_EXGMAC); + rtl_w1w0_eri(ioaddr, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC); + rtl_w1w0_eri(ioaddr, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC); + rtl_eri_write(ioaddr, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC); + rtl_eri_write(ioaddr, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC); + rtl_w1w0_eri(ioaddr, 0x0d4, ERIAR_MASK_0011, 0x0e00, 0xff00, + ERIAR_EXGMAC); +} + static void rtl_hw_start_8101(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); @@ -4770,22 +5145,26 @@ static void rtl_hw_start_8101(struct net_device *dev) switch (tp->mac_version) { case RTL_GIGA_MAC_VER_07: - rtl_hw_start_8102e_1(ioaddr, pdev); + rtl_hw_start_8102e_1(tp); break; case RTL_GIGA_MAC_VER_08: - rtl_hw_start_8102e_3(ioaddr, pdev); + rtl_hw_start_8102e_3(tp); break; case RTL_GIGA_MAC_VER_09: - rtl_hw_start_8102e_2(ioaddr, pdev); + rtl_hw_start_8102e_2(tp); break; case RTL_GIGA_MAC_VER_29: - rtl_hw_start_8105e_1(ioaddr, pdev); + rtl_hw_start_8105e_1(tp); break; case RTL_GIGA_MAC_VER_30: - rtl_hw_start_8105e_2(ioaddr, pdev); + rtl_hw_start_8105e_2(tp); + break; + + case RTL_GIGA_MAC_VER_37: + rtl_hw_start_8402(tp); break; } @@ -5672,7 +6051,7 @@ static int rtl_open(struct net_device *dev) pm_runtime_get_sync(&pdev->dev); /* - * Rx and Tx desscriptors needs 256 bytes alignment. + * Rx and Tx descriptors needs 256 bytes alignment. * dma_alloc_coherent provides more. */ tp->TxDescArray = dma_alloc_coherent(&pdev->dev, R8169_TX_RING_BYTES, @@ -6182,6 +6561,7 @@ rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rtl_init_mdio_ops(tp); rtl_init_pll_power_ops(tp); rtl_init_jumbo_ops(tp); + rtl_init_csi_ops(tp); rtl8169_print_mac_version(tp); diff --git a/trunk/drivers/net/ethernet/renesas/Kconfig b/trunk/drivers/net/ethernet/renesas/Kconfig index 3fb2355af37e..46df3a04030c 100644 --- a/trunk/drivers/net/ethernet/renesas/Kconfig +++ b/trunk/drivers/net/ethernet/renesas/Kconfig @@ -4,11 +4,11 @@ config SH_ETH tristate "Renesas SuperH Ethernet support" - depends on SUPERH && \ + depends on (SUPERH || ARCH_SHMOBILE) && \ (CPU_SUBTYPE_SH7710 || CPU_SUBTYPE_SH7712 || \ CPU_SUBTYPE_SH7763 || CPU_SUBTYPE_SH7619 || \ CPU_SUBTYPE_SH7724 || CPU_SUBTYPE_SH7734 || \ - CPU_SUBTYPE_SH7757) + CPU_SUBTYPE_SH7757 || ARCH_R8A7740) select CRC32 select NET_CORE select MII @@ -17,4 +17,5 @@ config SH_ETH ---help--- Renesas SuperH Ethernet device driver. This driver supporting CPUs are: - - SH7619, SH7710, SH7712, SH7724, SH7734, SH7763 and SH7757. + - SH7619, SH7710, SH7712, SH7724, SH7734, SH7763, SH7757, + and R8A7740. diff --git a/trunk/drivers/net/ethernet/renesas/sh_eth.c b/trunk/drivers/net/ethernet/renesas/sh_eth.c index d63e09b29a96..be3c22179161 100644 --- a/trunk/drivers/net/ethernet/renesas/sh_eth.c +++ b/trunk/drivers/net/ethernet/renesas/sh_eth.c @@ -386,6 +386,114 @@ static void sh_eth_reset_hw_crc(struct net_device *ndev) sh_eth_write(ndev, 0x0, CSMR); } +#elif defined(CONFIG_ARCH_R8A7740) +#define SH_ETH_HAS_TSU 1 +static void sh_eth_chip_reset(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + unsigned long mii; + + /* reset device */ + sh_eth_tsu_write(mdp, ARSTR_ARSTR, ARSTR); + mdelay(1); + + switch (mdp->phy_interface) { + case PHY_INTERFACE_MODE_GMII: + mii = 2; + break; + case PHY_INTERFACE_MODE_MII: + mii = 1; + break; + case PHY_INTERFACE_MODE_RMII: + default: + mii = 0; + break; + } + sh_eth_write(ndev, mii, RMII_MII); +} + +static void sh_eth_reset(struct net_device *ndev) +{ + int cnt = 100; + + sh_eth_write(ndev, EDSR_ENALL, EDSR); + sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_GETHER, EDMR); + while (cnt > 0) { + if (!(sh_eth_read(ndev, EDMR) & 0x3)) + break; + mdelay(1); + cnt--; + } + if (cnt == 0) + printk(KERN_ERR "Device reset fail\n"); + + /* Table Init */ + sh_eth_write(ndev, 0x0, TDLAR); + sh_eth_write(ndev, 0x0, TDFAR); + sh_eth_write(ndev, 0x0, TDFXR); + sh_eth_write(ndev, 0x0, TDFFR); + sh_eth_write(ndev, 0x0, RDLAR); + sh_eth_write(ndev, 0x0, RDFAR); + sh_eth_write(ndev, 0x0, RDFXR); + sh_eth_write(ndev, 0x0, RDFFR); +} + +static void sh_eth_set_duplex(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + + if (mdp->duplex) /* Full */ + sh_eth_write(ndev, sh_eth_read(ndev, ECMR) | ECMR_DM, ECMR); + else /* Half */ + sh_eth_write(ndev, sh_eth_read(ndev, ECMR) & ~ECMR_DM, ECMR); +} + +static void sh_eth_set_rate(struct net_device *ndev) +{ + struct sh_eth_private *mdp = netdev_priv(ndev); + + switch (mdp->speed) { + case 10: /* 10BASE */ + sh_eth_write(ndev, GECMR_10, GECMR); + break; + case 100:/* 100BASE */ + sh_eth_write(ndev, GECMR_100, GECMR); + break; + case 1000: /* 1000BASE */ + sh_eth_write(ndev, GECMR_1000, GECMR); + break; + default: + break; + } +} + +/* R8A7740 */ +static struct sh_eth_cpu_data sh_eth_my_cpu_data = { + .chip_reset = sh_eth_chip_reset, + .set_duplex = sh_eth_set_duplex, + .set_rate = sh_eth_set_rate, + + .ecsr_value = ECSR_ICD | ECSR_MPD, + .ecsipr_value = ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP, + .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff, + + .tx_check = EESR_TC1 | EESR_FTC, + .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT | \ + EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE | \ + EESR_ECI, + .tx_error_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_TDE | \ + EESR_TFE, + + .apr = 1, + .mpr = 1, + .tpauser = 1, + .bculr = 1, + .hw_swap = 1, + .no_trimd = 1, + .no_ade = 1, + .tsu = 1, +}; + #elif defined(CONFIG_CPU_SUBTYPE_SH7619) #define SH_ETH_RESET_DEFAULT 1 static struct sh_eth_cpu_data sh_eth_my_cpu_data = { @@ -443,7 +551,7 @@ static void sh_eth_reset(struct net_device *ndev) } #endif -#if defined(CONFIG_CPU_SH4) +#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) static void sh_eth_set_receive_align(struct sk_buff *skb) { int reserve; @@ -919,6 +1027,10 @@ static int sh_eth_rx(struct net_device *ndev) desc_status = edmac_to_cpu(mdp, rxdesc->status); pkt_len = rxdesc->frame_length; +#if defined(CONFIG_ARCH_R8A7740) + desc_status >>= 16; +#endif + if (--boguscnt < 0) break; diff --git a/trunk/drivers/net/ethernet/renesas/sh_eth.h b/trunk/drivers/net/ethernet/renesas/sh_eth.h index 0fa14afce23d..57b8e1fc5d15 100644 --- a/trunk/drivers/net/ethernet/renesas/sh_eth.h +++ b/trunk/drivers/net/ethernet/renesas/sh_eth.h @@ -372,7 +372,7 @@ static const u16 sh_eth_offset_fast_sh3_sh2[SH_ETH_MAX_REGISTER_OFFSET] = { }; /* Driver's parameters */ -#if defined(CONFIG_CPU_SH4) +#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) #define SH4_SKB_RX_ALIGN 32 #else #define SH2_SH3_SKB_RX_ALIGN 2 @@ -381,7 +381,8 @@ static const u16 sh_eth_offset_fast_sh3_sh2[SH_ETH_MAX_REGISTER_OFFSET] = { /* * Register's bits */ -#if defined(CONFIG_CPU_SUBTYPE_SH7734) || defined(CONFIG_CPU_SUBTYPE_SH7763) +#if defined(CONFIG_CPU_SUBTYPE_SH7734) || defined(CONFIG_CPU_SUBTYPE_SH7763) ||\ + defined(CONFIG_ARCH_R8A7740) /* EDSR */ enum EDSR_BIT { EDSR_ENT = 0x01, EDSR_ENR = 0x02, diff --git a/trunk/drivers/net/ethernet/s6gmac.c b/trunk/drivers/net/ethernet/s6gmac.c index 1895605abb35..2ed3ab4b3c2d 100644 --- a/trunk/drivers/net/ethernet/s6gmac.c +++ b/trunk/drivers/net/ethernet/s6gmac.c @@ -1,7 +1,7 @@ /* * Ethernet driver for S6105 on chip network device * (c)2008 emlix GmbH http://www.emlix.com - * Authors: Oskar Schirmer + * Authors: Oskar Schirmer * Daniel Gloeckner * * This program is free software; you can redistribute it and/or @@ -937,7 +937,7 @@ static struct net_device_stats *s6gmac_stats(struct net_device *dev) do { unsigned long flags; spin_lock_irqsave(&pd->lock, flags); - for (i = 0; i < sizeof(pd->stats) / sizeof(unsigned long); i++) + for (i = 0; i < ARRAY_SIZE(pd->stats); i++) pd->stats[i] = pd->carry[i] << (S6_GMAC_STAT_SIZE_MIN - 1); s6gmac_stats_collect(pd, &statinf[0][0]); @@ -1070,4 +1070,4 @@ module_exit(s6gmac_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("S6105 on chip Ethernet driver"); -MODULE_AUTHOR("Oskar Schirmer "); +MODULE_AUTHOR("Oskar Schirmer "); diff --git a/trunk/drivers/net/ethernet/sfc/efx.c b/trunk/drivers/net/ethernet/sfc/efx.c index 4a0005342e65..b95f2e1b33f0 100644 --- a/trunk/drivers/net/ethernet/sfc/efx.c +++ b/trunk/drivers/net/ethernet/sfc/efx.c @@ -656,25 +656,30 @@ static void efx_stop_datapath(struct efx_nic *efx) struct efx_channel *channel; struct efx_tx_queue *tx_queue; struct efx_rx_queue *rx_queue; + struct pci_dev *dev = efx->pci_dev; int rc; EFX_ASSERT_RESET_SERIALISED(efx); BUG_ON(efx->port_enabled); - rc = efx_nic_flush_queues(efx); - if (rc && EFX_WORKAROUND_7803(efx)) { - /* Schedule a reset to recover from the flush failure. The - * descriptor caches reference memory we're about to free, - * but falcon_reconfigure_mac_wrapper() won't reconnect - * the MACs because of the pending reset. */ - netif_err(efx, drv, efx->net_dev, - "Resetting to recover from flush failure\n"); - efx_schedule_reset(efx, RESET_TYPE_ALL); - } else if (rc) { - netif_err(efx, drv, efx->net_dev, "failed to flush queues\n"); - } else { - netif_dbg(efx, drv, efx->net_dev, - "successfully flushed all queues\n"); + /* Only perform flush if dma is enabled */ + if (dev->is_busmaster) { + rc = efx_nic_flush_queues(efx); + + if (rc && EFX_WORKAROUND_7803(efx)) { + /* Schedule a reset to recover from the flush failure. The + * descriptor caches reference memory we're about to free, + * but falcon_reconfigure_mac_wrapper() won't reconnect + * the MACs because of the pending reset. */ + netif_err(efx, drv, efx->net_dev, + "Resetting to recover from flush failure\n"); + efx_schedule_reset(efx, RESET_TYPE_ALL); + } else if (rc) { + netif_err(efx, drv, efx->net_dev, "failed to flush queues\n"); + } else { + netif_dbg(efx, drv, efx->net_dev, + "successfully flushed all queues\n"); + } } efx_for_each_channel(channel, efx) { @@ -2492,8 +2497,8 @@ static void efx_pci_remove(struct pci_dev *pci_dev) efx_fini_io(efx); netif_dbg(efx, drv, efx->net_dev, "shutdown successful\n"); - pci_set_drvdata(pci_dev, NULL); efx_fini_struct(efx); + pci_set_drvdata(pci_dev, NULL); free_netdev(efx->net_dev); }; @@ -2695,6 +2700,7 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, fail2: efx_fini_struct(efx); fail1: + pci_set_drvdata(pci_dev, NULL); WARN_ON(rc > 0); netif_dbg(efx, drv, efx->net_dev, "initialisation failed. rc=%d\n", rc); free_netdev(net_dev); diff --git a/trunk/drivers/net/ethernet/sfc/ethtool.c b/trunk/drivers/net/ethernet/sfc/ethtool.c index f22f45f515a8..03ded364c8da 100644 --- a/trunk/drivers/net/ethernet/sfc/ethtool.c +++ b/trunk/drivers/net/ethernet/sfc/ethtool.c @@ -1023,7 +1023,7 @@ static int efx_ethtool_set_class_rule(struct efx_nic *efx, return -EINVAL; /* Is it a default UC or MC filter? */ - if (!compare_ether_addr(mac_mask->h_dest, mac_addr_mc_mask) && + if (ether_addr_equal(mac_mask->h_dest, mac_addr_mc_mask) && vlan_tag_mask == 0) { if (is_multicast_ether_addr(mac_entry->h_dest)) rc = efx_filter_set_mc_def(&spec); @@ -1108,6 +1108,39 @@ static int efx_ethtool_set_rxfh_indir(struct net_device *net_dev, return 0; } +static int efx_ethtool_get_module_eeprom(struct net_device *net_dev, + struct ethtool_eeprom *ee, + u8 *data) +{ + struct efx_nic *efx = netdev_priv(net_dev); + int ret; + + if (!efx->phy_op || !efx->phy_op->get_module_eeprom) + return -EOPNOTSUPP; + + mutex_lock(&efx->mac_lock); + ret = efx->phy_op->get_module_eeprom(efx, ee, data); + mutex_unlock(&efx->mac_lock); + + return ret; +} + +static int efx_ethtool_get_module_info(struct net_device *net_dev, + struct ethtool_modinfo *modinfo) +{ + struct efx_nic *efx = netdev_priv(net_dev); + int ret; + + if (!efx->phy_op || !efx->phy_op->get_module_info) + return -EOPNOTSUPP; + + mutex_lock(&efx->mac_lock); + ret = efx->phy_op->get_module_info(efx, modinfo); + mutex_unlock(&efx->mac_lock); + + return ret; +} + const struct ethtool_ops efx_ethtool_ops = { .get_settings = efx_ethtool_get_settings, .set_settings = efx_ethtool_set_settings, @@ -1137,4 +1170,6 @@ const struct ethtool_ops efx_ethtool_ops = { .get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size, .get_rxfh_indir = efx_ethtool_get_rxfh_indir, .set_rxfh_indir = efx_ethtool_set_rxfh_indir, + .get_module_info = efx_ethtool_get_module_info, + .get_module_eeprom = efx_ethtool_get_module_eeprom, }; diff --git a/trunk/drivers/net/ethernet/sfc/mcdi_phy.c b/trunk/drivers/net/ethernet/sfc/mcdi_phy.c index 7bcad899a936..13cb40fe90c1 100644 --- a/trunk/drivers/net/ethernet/sfc/mcdi_phy.c +++ b/trunk/drivers/net/ethernet/sfc/mcdi_phy.c @@ -739,6 +739,80 @@ static const char *efx_mcdi_phy_test_name(struct efx_nic *efx, return NULL; } +#define SFP_PAGE_SIZE 128 +#define SFP_NUM_PAGES 2 +static int efx_mcdi_phy_get_module_eeprom(struct efx_nic *efx, + struct ethtool_eeprom *ee, u8 *data) +{ + u8 outbuf[MC_CMD_GET_PHY_MEDIA_INFO_OUT_LENMAX]; + u8 inbuf[MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN]; + size_t outlen; + int rc; + unsigned int payload_len; + unsigned int space_remaining = ee->len; + unsigned int page; + unsigned int page_off; + unsigned int to_copy; + u8 *user_data = data; + + BUILD_BUG_ON(SFP_PAGE_SIZE * SFP_NUM_PAGES != ETH_MODULE_SFF_8079_LEN); + + page_off = ee->offset % SFP_PAGE_SIZE; + page = ee->offset / SFP_PAGE_SIZE; + + while (space_remaining && (page < SFP_NUM_PAGES)) { + MCDI_SET_DWORD(inbuf, GET_PHY_MEDIA_INFO_IN_PAGE, page); + + rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_MEDIA_INFO, + inbuf, sizeof(inbuf), + outbuf, sizeof(outbuf), + &outlen); + if (rc) + return rc; + + if (outlen < (MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATA_OFST + + SFP_PAGE_SIZE)) + return -EIO; + + payload_len = MCDI_DWORD(outbuf, + GET_PHY_MEDIA_INFO_OUT_DATALEN); + if (payload_len != SFP_PAGE_SIZE) + return -EIO; + + /* Copy as much as we can into data */ + payload_len -= page_off; + to_copy = (space_remaining < payload_len) ? + space_remaining : payload_len; + + memcpy(user_data, + outbuf + page_off + + MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATA_OFST, + to_copy); + + space_remaining -= to_copy; + user_data += to_copy; + page_off = 0; + page++; + } + + return 0; +} + +static int efx_mcdi_phy_get_module_info(struct efx_nic *efx, + struct ethtool_modinfo *modinfo) +{ + struct efx_mcdi_phy_data *phy_cfg = efx->phy_data; + + switch (phy_cfg->media) { + case MC_CMD_MEDIA_SFP_PLUS: + modinfo->type = ETH_MODULE_SFF_8079; + modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; + return 0; + default: + return -EOPNOTSUPP; + } +} + const struct efx_phy_operations efx_mcdi_phy_ops = { .probe = efx_mcdi_phy_probe, .init = efx_port_dummy_op_int, @@ -751,4 +825,6 @@ const struct efx_phy_operations efx_mcdi_phy_ops = { .test_alive = efx_mcdi_phy_test_alive, .run_tests = efx_mcdi_phy_run_tests, .test_name = efx_mcdi_phy_test_name, + .get_module_eeprom = efx_mcdi_phy_get_module_eeprom, + .get_module_info = efx_mcdi_phy_get_module_info, }; diff --git a/trunk/drivers/net/ethernet/sfc/net_driver.h b/trunk/drivers/net/ethernet/sfc/net_driver.h index f0385e1fb2d8..0e575359af17 100644 --- a/trunk/drivers/net/ethernet/sfc/net_driver.h +++ b/trunk/drivers/net/ethernet/sfc/net_driver.h @@ -252,8 +252,6 @@ struct efx_rx_page_state { * @max_fill: RX descriptor maximum fill level (<= ring size) * @fast_fill_trigger: RX descriptor fill level that will trigger a fast fill * (<= @max_fill) - * @fast_fill_limit: The level to which a fast fill will fill - * (@fast_fill_trigger <= @fast_fill_limit <= @max_fill) * @min_fill: RX descriptor minimum non-zero fill level. * This records the minimum fill level observed when a ring * refill was triggered. @@ -274,7 +272,6 @@ struct efx_rx_queue { int removed_count; unsigned int max_fill; unsigned int fast_fill_trigger; - unsigned int fast_fill_limit; unsigned int min_fill; unsigned int min_overfill; unsigned int alloc_page_count; @@ -522,6 +519,11 @@ struct efx_phy_operations { int (*test_alive) (struct efx_nic *efx); const char *(*test_name) (struct efx_nic *efx, unsigned int index); int (*run_tests) (struct efx_nic *efx, int *results, unsigned flags); + int (*get_module_eeprom) (struct efx_nic *efx, + struct ethtool_eeprom *ee, + u8 *data); + int (*get_module_info) (struct efx_nic *efx, + struct ethtool_modinfo *modinfo); }; /** diff --git a/trunk/drivers/net/ethernet/sfc/qt202x_phy.c b/trunk/drivers/net/ethernet/sfc/qt202x_phy.c index 8a7caf88ffb6..326a28637f3c 100644 --- a/trunk/drivers/net/ethernet/sfc/qt202x_phy.c +++ b/trunk/drivers/net/ethernet/sfc/qt202x_phy.c @@ -449,6 +449,37 @@ static void qt202x_phy_remove(struct efx_nic *efx) efx->phy_data = NULL; } +static int qt202x_phy_get_module_info(struct efx_nic *efx, + struct ethtool_modinfo *modinfo) +{ + modinfo->type = ETH_MODULE_SFF_8079; + modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; + return 0; +} + +static int qt202x_phy_get_module_eeprom(struct efx_nic *efx, + struct ethtool_eeprom *ee, u8 *data) +{ + int mmd, reg_base, rc, i; + + if (efx->phy_type == PHY_TYPE_QT2025C) { + mmd = MDIO_MMD_PCS; + reg_base = 0xd000; + } else { + mmd = MDIO_MMD_PMAPMD; + reg_base = 0x8007; + } + + for (i = 0; i < ee->len; i++) { + rc = efx_mdio_read(efx, mmd, reg_base + ee->offset + i); + if (rc < 0) + return rc; + data[i] = rc; + } + + return 0; +} + const struct efx_phy_operations falcon_qt202x_phy_ops = { .probe = qt202x_phy_probe, .init = qt202x_phy_init, @@ -459,4 +490,6 @@ const struct efx_phy_operations falcon_qt202x_phy_ops = { .get_settings = qt202x_phy_get_settings, .set_settings = efx_mdio_set_settings, .test_alive = efx_mdio_test_alive, + .get_module_eeprom = qt202x_phy_get_module_eeprom, + .get_module_info = qt202x_phy_get_module_info, }; diff --git a/trunk/drivers/net/ethernet/sfc/rx.c b/trunk/drivers/net/ethernet/sfc/rx.c index 763fa2fe1a38..243e91f3dff9 100644 --- a/trunk/drivers/net/ethernet/sfc/rx.c +++ b/trunk/drivers/net/ethernet/sfc/rx.c @@ -76,12 +76,7 @@ static int rx_alloc_method = RX_ALLOC_METHOD_AUTO; /* This is the percentage fill level below which new RX descriptors * will be added to the RX descriptor ring. */ -static unsigned int rx_refill_threshold = 90; - -/* This is the percentage fill level to which an RX queue will be refilled - * when the "RX refill threshold" is reached. - */ -static unsigned int rx_refill_limit = 95; +static unsigned int rx_refill_threshold; /* * RX maximum head room required. @@ -342,7 +337,7 @@ static void efx_recycle_rx_buffer(struct efx_channel *channel, * efx_fast_push_rx_descriptors - push new RX descriptors quickly * @rx_queue: RX descriptor queue * This will aim to fill the RX descriptor queue up to - * @rx_queue->@fast_fill_limit. If there is insufficient atomic + * @rx_queue->@max_fill. If there is insufficient atomic * memory to do so, a slow fill will be scheduled. * * The caller must provide serialisation (none is used here). In practise, @@ -367,15 +362,14 @@ void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue) rx_queue->min_fill = fill_level; } - space = rx_queue->fast_fill_limit - fill_level; - if (space < EFX_RX_BATCH) - goto out; + space = rx_queue->max_fill - fill_level; + EFX_BUG_ON_PARANOID(space < EFX_RX_BATCH); netif_vdbg(rx_queue->efx, rx_status, rx_queue->efx->net_dev, "RX queue %d fast-filling descriptor ring from" " level %d to level %d using %s allocation\n", efx_rx_queue_index(rx_queue), fill_level, - rx_queue->fast_fill_limit, + rx_queue->max_fill, channel->rx_alloc_push_pages ? "page" : "skb"); do { @@ -681,7 +675,7 @@ int efx_probe_rx_queue(struct efx_rx_queue *rx_queue) void efx_init_rx_queue(struct efx_rx_queue *rx_queue) { struct efx_nic *efx = rx_queue->efx; - unsigned int max_fill, trigger, limit; + unsigned int max_fill, trigger, max_trigger; netif_dbg(rx_queue->efx, drv, rx_queue->efx->net_dev, "initialising RX queue %d\n", efx_rx_queue_index(rx_queue)); @@ -694,12 +688,17 @@ void efx_init_rx_queue(struct efx_rx_queue *rx_queue) /* Initialise limit fields */ max_fill = efx->rxq_entries - EFX_RXD_HEAD_ROOM; - trigger = max_fill * min(rx_refill_threshold, 100U) / 100U; - limit = max_fill * min(rx_refill_limit, 100U) / 100U; + max_trigger = max_fill - EFX_RX_BATCH; + if (rx_refill_threshold != 0) { + trigger = max_fill * min(rx_refill_threshold, 100U) / 100U; + if (trigger > max_trigger) + trigger = max_trigger; + } else { + trigger = max_trigger; + } rx_queue->max_fill = max_fill; rx_queue->fast_fill_trigger = trigger; - rx_queue->fast_fill_limit = limit; /* Set up RX descriptor ring */ rx_queue->enabled = true; @@ -746,5 +745,5 @@ MODULE_PARM_DESC(rx_alloc_method, "Allocation method used for RX buffers"); module_param(rx_refill_threshold, uint, 0444); MODULE_PARM_DESC(rx_refill_threshold, - "RX descriptor ring fast/slow fill threshold (%)"); + "RX descriptor ring refill threshold (%)"); diff --git a/trunk/drivers/net/ethernet/silan/sc92031.c b/trunk/drivers/net/ethernet/silan/sc92031.c index a284d6440538..32e55664df6e 100644 --- a/trunk/drivers/net/ethernet/silan/sc92031.c +++ b/trunk/drivers/net/ethernet/silan/sc92031.c @@ -39,9 +39,7 @@ #define SC92031_NAME "sc92031" /* BAR 0 is MMIO, BAR 1 is PIO */ -#ifndef SC92031_USE_BAR -#define SC92031_USE_BAR 0 -#endif +#define SC92031_USE_PIO 0 /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). */ static int multicast_filter_limit = 64; @@ -366,7 +364,7 @@ static void sc92031_disable_interrupts(struct net_device *dev) mmiowb(); /* wait for any concurrent interrupt/tasklet to finish */ - synchronize_irq(dev->irq); + synchronize_irq(priv->pdev->irq); tasklet_disable(&priv->tasklet); } @@ -1114,10 +1112,13 @@ static void sc92031_tx_timeout(struct net_device *dev) #ifdef CONFIG_NET_POLL_CONTROLLER static void sc92031_poll_controller(struct net_device *dev) { - disable_irq(dev->irq); - if (sc92031_interrupt(dev->irq, dev) != IRQ_NONE) + struct sc92031_priv *priv = netdev_priv(dev); + const int irq = priv->pdev->irq; + + disable_irq(irq); + if (sc92031_interrupt(irq, dev) != IRQ_NONE) sc92031_tasklet((unsigned long)dev); - enable_irq(dev->irq); + enable_irq(irq); } #endif @@ -1402,7 +1403,6 @@ static int __devinit sc92031_probe(struct pci_dev *pdev, struct net_device *dev; struct sc92031_priv *priv; u32 mac0, mac1; - unsigned long base_addr; err = pci_enable_device(pdev); if (unlikely(err < 0)) @@ -1422,7 +1422,7 @@ static int __devinit sc92031_probe(struct pci_dev *pdev, if (unlikely(err < 0)) goto out_request_regions; - port_base = pci_iomap(pdev, SC92031_USE_BAR, 0); + port_base = pci_iomap(pdev, SC92031_USE_PIO, 0); if (unlikely(!port_base)) { err = -EIO; goto out_iomap; @@ -1437,14 +1437,6 @@ static int __devinit sc92031_probe(struct pci_dev *pdev, pci_set_drvdata(pdev, dev); SET_NETDEV_DEV(dev, &pdev->dev); -#if SC92031_USE_BAR == 0 - dev->mem_start = pci_resource_start(pdev, SC92031_USE_BAR); - dev->mem_end = pci_resource_end(pdev, SC92031_USE_BAR); -#elif SC92031_USE_BAR == 1 - dev->base_addr = pci_resource_start(pdev, SC92031_USE_BAR); -#endif - dev->irq = pdev->irq; - /* faked with skb_copy_and_csum_dev */ dev->features = NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; @@ -1478,13 +1470,9 @@ static int __devinit sc92031_probe(struct pci_dev *pdev, if (err < 0) goto out_register_netdev; -#if SC92031_USE_BAR == 0 - base_addr = dev->mem_start; -#elif SC92031_USE_BAR == 1 - base_addr = dev->base_addr; -#endif printk(KERN_INFO "%s: SC92031 at 0x%lx, %pM, IRQ %d\n", dev->name, - base_addr, dev->dev_addr, dev->irq); + (long)pci_resource_start(pdev, SC92031_USE_PIO), dev->dev_addr, + pdev->irq); return 0; diff --git a/trunk/drivers/net/ethernet/sis/sis190.c b/trunk/drivers/net/ethernet/sis/sis190.c index a9deda8eaf63..4613591b43e7 100644 --- a/trunk/drivers/net/ethernet/sis/sis190.c +++ b/trunk/drivers/net/ethernet/sis/sis190.c @@ -729,7 +729,7 @@ static void sis190_tx_interrupt(struct net_device *dev, * The interrupt handler does all of the Rx thread work and cleans up after * the Tx thread. */ -static irqreturn_t sis190_interrupt(int irq, void *__dev) +static irqreturn_t sis190_irq(int irq, void *__dev) { struct net_device *dev = __dev; struct sis190_private *tp = netdev_priv(dev); @@ -772,11 +772,11 @@ static irqreturn_t sis190_interrupt(int irq, void *__dev) static void sis190_netpoll(struct net_device *dev) { struct sis190_private *tp = netdev_priv(dev); - struct pci_dev *pdev = tp->pci_dev; + const int irq = tp->pci_dev->irq; - disable_irq(pdev->irq); - sis190_interrupt(pdev->irq, dev); - enable_irq(pdev->irq); + disable_irq(irq); + sis190_irq(irq, dev); + enable_irq(irq); } #endif @@ -1085,7 +1085,7 @@ static int sis190_open(struct net_device *dev) sis190_request_timer(dev); - rc = request_irq(dev->irq, sis190_interrupt, IRQF_SHARED, dev->name, dev); + rc = request_irq(pdev->irq, sis190_irq, IRQF_SHARED, dev->name, dev); if (rc < 0) goto err_release_timer_2; @@ -1097,11 +1097,9 @@ static int sis190_open(struct net_device *dev) sis190_delete_timer(dev); sis190_rx_clear(tp); err_free_rx_1: - pci_free_consistent(tp->pci_dev, RX_RING_BYTES, tp->RxDescRing, - tp->rx_dma); + pci_free_consistent(pdev, RX_RING_BYTES, tp->RxDescRing, tp->rx_dma); err_free_tx_0: - pci_free_consistent(tp->pci_dev, TX_RING_BYTES, tp->TxDescRing, - tp->tx_dma); + pci_free_consistent(pdev, TX_RING_BYTES, tp->TxDescRing, tp->tx_dma); goto out; } @@ -1141,7 +1139,7 @@ static void sis190_down(struct net_device *dev) spin_unlock_irq(&tp->lock); - synchronize_irq(dev->irq); + synchronize_irq(tp->pci_dev->irq); if (!poll_locked) poll_locked++; @@ -1161,7 +1159,7 @@ static int sis190_close(struct net_device *dev) sis190_down(dev); - free_irq(dev->irq, dev); + free_irq(pdev->irq, dev); pci_free_consistent(pdev, TX_RING_BYTES, tp->TxDescRing, tp->tx_dma); pci_free_consistent(pdev, RX_RING_BYTES, tp->RxDescRing, tp->rx_dma); @@ -1884,8 +1882,6 @@ static int __devinit sis190_init_one(struct pci_dev *pdev, dev->netdev_ops = &sis190_netdev_ops; SET_ETHTOOL_OPS(dev, &sis190_ethtool_ops); - dev->irq = pdev->irq; - dev->base_addr = (unsigned long) 0xdead; dev->watchdog_timeo = SIS190_TX_TIMEOUT; spin_lock_init(&tp->lock); @@ -1902,7 +1898,7 @@ static int __devinit sis190_init_one(struct pci_dev *pdev, netdev_info(dev, "%s: %s at %p (IRQ: %d), %pM\n", pci_name(pdev), sis_chip_info[ent->driver_data].name, - ioaddr, dev->irq, dev->dev_addr); + ioaddr, pdev->irq, dev->dev_addr); netdev_info(dev, "%s mode.\n", (tp->features & F_HAS_RGMII) ? "RGMII" : "GMII"); } diff --git a/trunk/drivers/net/ethernet/sis/sis900.c b/trunk/drivers/net/ethernet/sis/sis900.c index 5ccf02e7e3ad..203d9c6ec23a 100644 --- a/trunk/drivers/net/ethernet/sis/sis900.c +++ b/trunk/drivers/net/ethernet/sis/sis900.c @@ -168,6 +168,8 @@ struct sis900_private { unsigned int cur_phy; struct mii_if_info mii_info; + void __iomem *ioaddr; + struct timer_list timer; /* Link status detection timer. */ u8 autong_complete; /* 1: auto-negotiate complete */ @@ -201,13 +203,18 @@ MODULE_PARM_DESC(multicast_filter_limit, "SiS 900/7016 maximum number of filtere MODULE_PARM_DESC(max_interrupt_work, "SiS 900/7016 maximum events handled per interrupt"); MODULE_PARM_DESC(sis900_debug, "SiS 900/7016 bitmapped debugging message level"); +#define sw32(reg, val) iowrite32(val, ioaddr + (reg)) +#define sw8(reg, val) iowrite8(val, ioaddr + (reg)) +#define sr32(reg) ioread32(ioaddr + (reg)) +#define sr16(reg) ioread16(ioaddr + (reg)) + #ifdef CONFIG_NET_POLL_CONTROLLER static void sis900_poll(struct net_device *dev); #endif static int sis900_open(struct net_device *net_dev); static int sis900_mii_probe (struct net_device * net_dev); static void sis900_init_rxfilter (struct net_device * net_dev); -static u16 read_eeprom(long ioaddr, int location); +static u16 read_eeprom(void __iomem *ioaddr, int location); static int mdio_read(struct net_device *net_dev, int phy_id, int location); static void mdio_write(struct net_device *net_dev, int phy_id, int location, int val); static void sis900_timer(unsigned long data); @@ -231,7 +238,7 @@ static u16 sis900_default_phy(struct net_device * net_dev); static void sis900_set_capability( struct net_device *net_dev ,struct mii_phy *phy); static u16 sis900_reset_phy(struct net_device *net_dev, int phy_addr); static void sis900_auto_negotiate(struct net_device *net_dev, int phy_addr); -static void sis900_set_mode (long ioaddr, int speed, int duplex); +static void sis900_set_mode(struct sis900_private *, int speed, int duplex); static const struct ethtool_ops sis900_ethtool_ops; /** @@ -246,7 +253,8 @@ static const struct ethtool_ops sis900_ethtool_ops; static int __devinit sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev) { - long ioaddr = pci_resource_start(pci_dev, 0); + struct sis900_private *sis_priv = netdev_priv(net_dev); + void __iomem *ioaddr = sis_priv->ioaddr; u16 signature; int i; @@ -325,29 +333,30 @@ static int __devinit sis630e_get_mac_addr(struct pci_dev * pci_dev, static int __devinit sis635_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev) { - long ioaddr = net_dev->base_addr; + struct sis900_private *sis_priv = netdev_priv(net_dev); + void __iomem *ioaddr = sis_priv->ioaddr; u32 rfcrSave; u32 i; - rfcrSave = inl(rfcr + ioaddr); + rfcrSave = sr32(rfcr); - outl(rfcrSave | RELOAD, ioaddr + cr); - outl(0, ioaddr + cr); + sw32(cr, rfcrSave | RELOAD); + sw32(cr, 0); /* disable packet filtering before setting filter */ - outl(rfcrSave & ~RFEN, rfcr + ioaddr); + sw32(rfcr, rfcrSave & ~RFEN); /* load MAC addr to filter data register */ for (i = 0 ; i < 3 ; i++) { - outl((i << RFADDR_shift), ioaddr + rfcr); - *( ((u16 *)net_dev->dev_addr) + i) = inw(ioaddr + rfdr); + sw32(rfcr, (i << RFADDR_shift)); + *( ((u16 *)net_dev->dev_addr) + i) = sr16(rfdr); } /* Store MAC Address in perm_addr */ memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN); /* enable packet filtering */ - outl(rfcrSave | RFEN, rfcr + ioaddr); + sw32(rfcr, rfcrSave | RFEN); return 1; } @@ -371,31 +380,30 @@ static int __devinit sis635_get_mac_addr(struct pci_dev * pci_dev, static int __devinit sis96x_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev) { - long ioaddr = net_dev->base_addr; - long ee_addr = ioaddr + mear; - u32 waittime = 0; - int i; + struct sis900_private *sis_priv = netdev_priv(net_dev); + void __iomem *ioaddr = sis_priv->ioaddr; + int wait, rc = 0; - outl(EEREQ, ee_addr); - while(waittime < 2000) { - if(inl(ee_addr) & EEGNT) { + sw32(mear, EEREQ); + for (wait = 0; wait < 2000; wait++) { + if (sr32(mear) & EEGNT) { + u16 *mac = (u16 *)net_dev->dev_addr; + int i; /* get MAC address from EEPROM */ for (i = 0; i < 3; i++) - ((u16 *)(net_dev->dev_addr))[i] = read_eeprom(ioaddr, i+EEPROMMACAddr); + mac[i] = read_eeprom(ioaddr, i + EEPROMMACAddr); /* Store MAC Address in perm_addr */ memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN); - outl(EEDONE, ee_addr); - return 1; - } else { - udelay(1); - waittime ++; + rc = 1; + break; } + udelay(1); } - outl(EEDONE, ee_addr); - return 0; + sw32(mear, EEDONE); + return rc; } static const struct net_device_ops sis900_netdev_ops = { @@ -433,7 +441,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, struct pci_dev *dev; dma_addr_t ring_dma; void *ring_space; - long ioaddr; + void __iomem *ioaddr; int i, ret; const char *card_name = card_names[pci_id->driver_data]; const char *dev_name = pci_name(pci_dev); @@ -464,14 +472,17 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, SET_NETDEV_DEV(net_dev, &pci_dev->dev); /* We do a request_region() to register /proc/ioports info. */ - ioaddr = pci_resource_start(pci_dev, 0); ret = pci_request_regions(pci_dev, "sis900"); if (ret) goto err_out; + /* IO region. */ + ioaddr = pci_iomap(pci_dev, 0, 0); + if (!ioaddr) + goto err_out_cleardev; + sis_priv = netdev_priv(net_dev); - net_dev->base_addr = ioaddr; - net_dev->irq = pci_dev->irq; + sis_priv->ioaddr = ioaddr; sis_priv->pci_dev = pci_dev; spin_lock_init(&sis_priv->lock); @@ -480,7 +491,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, ring_space = pci_alloc_consistent(pci_dev, TX_TOTAL_SIZE, &ring_dma); if (!ring_space) { ret = -ENOMEM; - goto err_out_cleardev; + goto err_out_unmap; } sis_priv->tx_ring = ring_space; sis_priv->tx_ring_dma = ring_dma; @@ -534,7 +545,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, /* 630ET : set the mii access mode as software-mode */ if (sis_priv->chipset_rev == SIS630ET_900_REV) - outl(ACCESSMODE | inl(ioaddr + cr), ioaddr + cr); + sw32(cr, ACCESSMODE | sr32(cr)); /* probe for mii transceiver */ if (sis900_mii_probe(net_dev) == 0) { @@ -556,25 +567,27 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, goto err_unmap_rx; /* print some information about our NIC */ - printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %pM\n", - net_dev->name, card_name, ioaddr, net_dev->irq, + printk(KERN_INFO "%s: %s at 0x%p, IRQ %d, %pM\n", + net_dev->name, card_name, ioaddr, pci_dev->irq, net_dev->dev_addr); /* Detect Wake on Lan support */ - ret = (inl(net_dev->base_addr + CFGPMC) & PMESP) >> 27; + ret = (sr32(CFGPMC) & PMESP) >> 27; if (netif_msg_probe(sis_priv) && (ret & PME_D3C) == 0) printk(KERN_INFO "%s: Wake on LAN only available from suspend to RAM.", net_dev->name); return 0; - err_unmap_rx: +err_unmap_rx: pci_free_consistent(pci_dev, RX_TOTAL_SIZE, sis_priv->rx_ring, sis_priv->rx_ring_dma); - err_unmap_tx: +err_unmap_tx: pci_free_consistent(pci_dev, TX_TOTAL_SIZE, sis_priv->tx_ring, sis_priv->tx_ring_dma); - err_out_cleardev: - pci_set_drvdata(pci_dev, NULL); +err_out_unmap: + pci_iounmap(pci_dev, ioaddr); +err_out_cleardev: + pci_set_drvdata(pci_dev, NULL); pci_release_regions(pci_dev); err_out: free_netdev(net_dev); @@ -798,7 +811,7 @@ static void sis900_set_capability(struct net_device *net_dev, struct mii_phy *ph /* Delay between EEPROM clock transitions. */ -#define eeprom_delay() inl(ee_addr) +#define eeprom_delay() sr32(mear) /** * read_eeprom - Read Serial EEPROM @@ -809,41 +822,41 @@ static void sis900_set_capability(struct net_device *net_dev, struct mii_phy *ph * Note that location is in word (16 bits) unit */ -static u16 __devinit read_eeprom(long ioaddr, int location) +static u16 __devinit read_eeprom(void __iomem *ioaddr, int location) { + u32 read_cmd = location | EEread; int i; u16 retval = 0; - long ee_addr = ioaddr + mear; - u32 read_cmd = location | EEread; - outl(0, ee_addr); + sw32(mear, 0); eeprom_delay(); - outl(EECS, ee_addr); + sw32(mear, EECS); eeprom_delay(); /* Shift the read command (9) bits out. */ for (i = 8; i >= 0; i--) { u32 dataval = (read_cmd & (1 << i)) ? EEDI | EECS : EECS; - outl(dataval, ee_addr); + + sw32(mear, dataval); eeprom_delay(); - outl(dataval | EECLK, ee_addr); + sw32(mear, dataval | EECLK); eeprom_delay(); } - outl(EECS, ee_addr); + sw32(mear, EECS); eeprom_delay(); /* read the 16-bits data in */ for (i = 16; i > 0; i--) { - outl(EECS, ee_addr); + sw32(mear, EECS); eeprom_delay(); - outl(EECS | EECLK, ee_addr); + sw32(mear, EECS | EECLK); eeprom_delay(); - retval = (retval << 1) | ((inl(ee_addr) & EEDO) ? 1 : 0); + retval = (retval << 1) | ((sr32(mear) & EEDO) ? 1 : 0); eeprom_delay(); } /* Terminate the EEPROM access. */ - outl(0, ee_addr); + sw32(mear, 0); eeprom_delay(); return retval; @@ -852,24 +865,27 @@ static u16 __devinit read_eeprom(long ioaddr, int location) /* Read and write the MII management registers using software-generated serial MDIO protocol. Note that the command bits and data bits are send out separately */ -#define mdio_delay() inl(mdio_addr) +#define mdio_delay() sr32(mear) -static void mdio_idle(long mdio_addr) +static void mdio_idle(struct sis900_private *sp) { - outl(MDIO | MDDIR, mdio_addr); + void __iomem *ioaddr = sp->ioaddr; + + sw32(mear, MDIO | MDDIR); mdio_delay(); - outl(MDIO | MDDIR | MDC, mdio_addr); + sw32(mear, MDIO | MDDIR | MDC); } -/* Syncronize the MII management interface by shifting 32 one bits out. */ -static void mdio_reset(long mdio_addr) +/* Synchronize the MII management interface by shifting 32 one bits out. */ +static void mdio_reset(struct sis900_private *sp) { + void __iomem *ioaddr = sp->ioaddr; int i; for (i = 31; i >= 0; i--) { - outl(MDDIR | MDIO, mdio_addr); + sw32(mear, MDDIR | MDIO); mdio_delay(); - outl(MDDIR | MDIO | MDC, mdio_addr); + sw32(mear, MDDIR | MDIO | MDC); mdio_delay(); } } @@ -887,31 +903,33 @@ static void mdio_reset(long mdio_addr) static int mdio_read(struct net_device *net_dev, int phy_id, int location) { - long mdio_addr = net_dev->base_addr + mear; int mii_cmd = MIIread|(phy_id<ioaddr; u16 retval = 0; int i; - mdio_reset(mdio_addr); - mdio_idle(mdio_addr); + mdio_reset(sp); + mdio_idle(sp); for (i = 15; i >= 0; i--) { int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR; - outl(dataval, mdio_addr); + + sw32(mear, dataval); mdio_delay(); - outl(dataval | MDC, mdio_addr); + sw32(mear, dataval | MDC); mdio_delay(); } /* Read the 16 data bits. */ for (i = 16; i > 0; i--) { - outl(0, mdio_addr); + sw32(mear, 0); mdio_delay(); - retval = (retval << 1) | ((inl(mdio_addr) & MDIO) ? 1 : 0); - outl(MDC, mdio_addr); + retval = (retval << 1) | ((sr32(mear) & MDIO) ? 1 : 0); + sw32(mear, MDC); mdio_delay(); } - outl(0x00, mdio_addr); + sw32(mear, 0x00); return retval; } @@ -931,19 +949,21 @@ static int mdio_read(struct net_device *net_dev, int phy_id, int location) static void mdio_write(struct net_device *net_dev, int phy_id, int location, int value) { - long mdio_addr = net_dev->base_addr + mear; int mii_cmd = MIIwrite|(phy_id<ioaddr; int i; - mdio_reset(mdio_addr); - mdio_idle(mdio_addr); + mdio_reset(sp); + mdio_idle(sp); /* Shift the command bits out. */ for (i = 15; i >= 0; i--) { int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR; - outb(dataval, mdio_addr); + + sw8(mear, dataval); mdio_delay(); - outb(dataval | MDC, mdio_addr); + sw8(mear, dataval | MDC); mdio_delay(); } mdio_delay(); @@ -951,21 +971,22 @@ static void mdio_write(struct net_device *net_dev, int phy_id, int location, /* Shift the value bits out. */ for (i = 15; i >= 0; i--) { int dataval = (value & (1 << i)) ? MDDIR | MDIO : MDDIR; - outl(dataval, mdio_addr); + + sw32(mear, dataval); mdio_delay(); - outl(dataval | MDC, mdio_addr); + sw32(mear, dataval | MDC); mdio_delay(); } mdio_delay(); /* Clear out extra bits. */ for (i = 2; i > 0; i--) { - outb(0, mdio_addr); + sw8(mear, 0); mdio_delay(); - outb(MDC, mdio_addr); + sw8(mear, MDC); mdio_delay(); } - outl(0x00, mdio_addr); + sw32(mear, 0x00); } @@ -1000,9 +1021,12 @@ static u16 sis900_reset_phy(struct net_device *net_dev, int phy_addr) */ static void sis900_poll(struct net_device *dev) { - disable_irq(dev->irq); - sis900_interrupt(dev->irq, dev); - enable_irq(dev->irq); + struct sis900_private *sp = netdev_priv(dev); + const int irq = sp->pci_dev->irq; + + disable_irq(irq); + sis900_interrupt(irq, dev); + enable_irq(irq); } #endif @@ -1018,7 +1042,7 @@ static int sis900_open(struct net_device *net_dev) { struct sis900_private *sis_priv = netdev_priv(net_dev); - long ioaddr = net_dev->base_addr; + void __iomem *ioaddr = sis_priv->ioaddr; int ret; /* Soft reset the chip. */ @@ -1027,8 +1051,8 @@ sis900_open(struct net_device *net_dev) /* Equalizer workaround Rule */ sis630_set_eq(net_dev, sis_priv->chipset_rev); - ret = request_irq(net_dev->irq, sis900_interrupt, IRQF_SHARED, - net_dev->name, net_dev); + ret = request_irq(sis_priv->pci_dev->irq, sis900_interrupt, IRQF_SHARED, + net_dev->name, net_dev); if (ret) return ret; @@ -1042,12 +1066,12 @@ sis900_open(struct net_device *net_dev) netif_start_queue(net_dev); /* Workaround for EDB */ - sis900_set_mode(ioaddr, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED); + sis900_set_mode(sis_priv, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED); /* Enable all known interrupts by setting the interrupt mask. */ - outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr); - outl(RxENA | inl(ioaddr + cr), ioaddr + cr); - outl(IE, ioaddr + ier); + sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE); + sw32(cr, RxENA | sr32(cr)); + sw32(ier, IE); sis900_check_mode(net_dev, sis_priv->mii); @@ -1074,31 +1098,30 @@ static void sis900_init_rxfilter (struct net_device * net_dev) { struct sis900_private *sis_priv = netdev_priv(net_dev); - long ioaddr = net_dev->base_addr; + void __iomem *ioaddr = sis_priv->ioaddr; u32 rfcrSave; u32 i; - rfcrSave = inl(rfcr + ioaddr); + rfcrSave = sr32(rfcr); /* disable packet filtering before setting filter */ - outl(rfcrSave & ~RFEN, rfcr + ioaddr); + sw32(rfcr, rfcrSave & ~RFEN); /* load MAC addr to filter data register */ for (i = 0 ; i < 3 ; i++) { - u32 w; + u32 w = (u32) *((u16 *)(net_dev->dev_addr)+i); - w = (u32) *((u16 *)(net_dev->dev_addr)+i); - outl((i << RFADDR_shift), ioaddr + rfcr); - outl(w, ioaddr + rfdr); + sw32(rfcr, i << RFADDR_shift); + sw32(rfdr, w); if (netif_msg_hw(sis_priv)) { printk(KERN_DEBUG "%s: Receive Filter Addrss[%d]=%x\n", - net_dev->name, i, inl(ioaddr + rfdr)); + net_dev->name, i, sr32(rfdr)); } } /* enable packet filtering */ - outl(rfcrSave | RFEN, rfcr + ioaddr); + sw32(rfcr, rfcrSave | RFEN); } /** @@ -1112,7 +1135,7 @@ static void sis900_init_tx_ring(struct net_device *net_dev) { struct sis900_private *sis_priv = netdev_priv(net_dev); - long ioaddr = net_dev->base_addr; + void __iomem *ioaddr = sis_priv->ioaddr; int i; sis_priv->tx_full = 0; @@ -1128,10 +1151,10 @@ sis900_init_tx_ring(struct net_device *net_dev) } /* load Transmit Descriptor Register */ - outl(sis_priv->tx_ring_dma, ioaddr + txdp); + sw32(txdp, sis_priv->tx_ring_dma); if (netif_msg_hw(sis_priv)) printk(KERN_DEBUG "%s: TX descriptor register loaded with: %8.8x\n", - net_dev->name, inl(ioaddr + txdp)); + net_dev->name, sr32(txdp)); } /** @@ -1146,7 +1169,7 @@ static void sis900_init_rx_ring(struct net_device *net_dev) { struct sis900_private *sis_priv = netdev_priv(net_dev); - long ioaddr = net_dev->base_addr; + void __iomem *ioaddr = sis_priv->ioaddr; int i; sis_priv->cur_rx = 0; @@ -1181,10 +1204,10 @@ sis900_init_rx_ring(struct net_device *net_dev) sis_priv->dirty_rx = (unsigned int) (i - NUM_RX_DESC); /* load Receive Descriptor Register */ - outl(sis_priv->rx_ring_dma, ioaddr + rxdp); + sw32(rxdp, sis_priv->rx_ring_dma); if (netif_msg_hw(sis_priv)) printk(KERN_DEBUG "%s: RX descriptor register loaded with: %8.8x\n", - net_dev->name, inl(ioaddr + rxdp)); + net_dev->name, sr32(rxdp)); } /** @@ -1298,7 +1321,7 @@ static void sis900_timer(unsigned long data) sis900_read_mode(net_dev, &speed, &duplex); if (duplex){ - sis900_set_mode(net_dev->base_addr, speed, duplex); + sis900_set_mode(sis_priv, speed, duplex); sis630_set_eq(net_dev, sis_priv->chipset_rev); netif_start_queue(net_dev); } @@ -1359,25 +1382,25 @@ static void sis900_timer(unsigned long data) static void sis900_check_mode(struct net_device *net_dev, struct mii_phy *mii_phy) { struct sis900_private *sis_priv = netdev_priv(net_dev); - long ioaddr = net_dev->base_addr; + void __iomem *ioaddr = sis_priv->ioaddr; int speed, duplex; if (mii_phy->phy_types == LAN) { - outl(~EXD & inl(ioaddr + cfg), ioaddr + cfg); + sw32(cfg, ~EXD & sr32(cfg)); sis900_set_capability(net_dev , mii_phy); sis900_auto_negotiate(net_dev, sis_priv->cur_phy); } else { - outl(EXD | inl(ioaddr + cfg), ioaddr + cfg); + sw32(cfg, EXD | sr32(cfg)); speed = HW_SPEED_HOME; duplex = FDX_CAPABLE_HALF_SELECTED; - sis900_set_mode(ioaddr, speed, duplex); + sis900_set_mode(sis_priv, speed, duplex); sis_priv->autong_complete = 1; } } /** * sis900_set_mode - Set the media mode of mac register. - * @ioaddr: the address of the device + * @sp: the device private data * @speed : the transmit speed to be determined * @duplex: the duplex mode to be determined * @@ -1388,11 +1411,12 @@ static void sis900_check_mode(struct net_device *net_dev, struct mii_phy *mii_ph * double words. */ -static void sis900_set_mode (long ioaddr, int speed, int duplex) +static void sis900_set_mode(struct sis900_private *sp, int speed, int duplex) { + void __iomem *ioaddr = sp->ioaddr; u32 tx_flags = 0, rx_flags = 0; - if (inl(ioaddr + cfg) & EDB_MASTER_EN) { + if (sr32( cfg) & EDB_MASTER_EN) { tx_flags = TxATP | (DMA_BURST_64 << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift); rx_flags = DMA_BURST_64 << RxMXDMA_shift; @@ -1420,8 +1444,8 @@ static void sis900_set_mode (long ioaddr, int speed, int duplex) rx_flags |= RxAJAB; #endif - outl (tx_flags, ioaddr + txcfg); - outl (rx_flags, ioaddr + rxcfg); + sw32(txcfg, tx_flags); + sw32(rxcfg, rx_flags); } /** @@ -1528,16 +1552,17 @@ static void sis900_read_mode(struct net_device *net_dev, int *speed, int *duplex static void sis900_tx_timeout(struct net_device *net_dev) { struct sis900_private *sis_priv = netdev_priv(net_dev); - long ioaddr = net_dev->base_addr; + void __iomem *ioaddr = sis_priv->ioaddr; unsigned long flags; int i; - if(netif_msg_tx_err(sis_priv)) + if (netif_msg_tx_err(sis_priv)) { printk(KERN_INFO "%s: Transmit timeout, status %8.8x %8.8x\n", - net_dev->name, inl(ioaddr + cr), inl(ioaddr + isr)); + net_dev->name, sr32(cr), sr32(isr)); + } /* Disable interrupts by clearing the interrupt mask. */ - outl(0x0000, ioaddr + imr); + sw32(imr, 0x0000); /* use spinlock to prevent interrupt handler accessing buffer ring */ spin_lock_irqsave(&sis_priv->lock, flags); @@ -1566,10 +1591,10 @@ static void sis900_tx_timeout(struct net_device *net_dev) net_dev->trans_start = jiffies; /* prevent tx timeout */ /* load Transmit Descriptor Register */ - outl(sis_priv->tx_ring_dma, ioaddr + txdp); + sw32(txdp, sis_priv->tx_ring_dma); /* Enable all known interrupts by setting the interrupt mask. */ - outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr); + sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE); } /** @@ -1586,7 +1611,7 @@ static netdev_tx_t sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev) { struct sis900_private *sis_priv = netdev_priv(net_dev); - long ioaddr = net_dev->base_addr; + void __iomem *ioaddr = sis_priv->ioaddr; unsigned int entry; unsigned long flags; unsigned int index_cur_tx, index_dirty_tx; @@ -1608,7 +1633,7 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev) sis_priv->tx_ring[entry].bufptr = pci_map_single(sis_priv->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); sis_priv->tx_ring[entry].cmdsts = (OWN | skb->len); - outl(TxENA | inl(ioaddr + cr), ioaddr + cr); + sw32(cr, TxENA | sr32(cr)); sis_priv->cur_tx ++; index_cur_tx = sis_priv->cur_tx; @@ -1654,14 +1679,14 @@ static irqreturn_t sis900_interrupt(int irq, void *dev_instance) struct net_device *net_dev = dev_instance; struct sis900_private *sis_priv = netdev_priv(net_dev); int boguscnt = max_interrupt_work; - long ioaddr = net_dev->base_addr; + void __iomem *ioaddr = sis_priv->ioaddr; u32 status; unsigned int handled = 0; spin_lock (&sis_priv->lock); do { - status = inl(ioaddr + isr); + status = sr32(isr); if ((status & (HIBERR|TxURN|TxERR|TxIDLE|RxORN|RxERR|RxOK)) == 0) /* nothing intresting happened */ @@ -1696,7 +1721,7 @@ static irqreturn_t sis900_interrupt(int irq, void *dev_instance) if(netif_msg_intr(sis_priv)) printk(KERN_DEBUG "%s: exiting interrupt, " "interrupt status = 0x%#8.8x.\n", - net_dev->name, inl(ioaddr + isr)); + net_dev->name, sr32(isr)); spin_unlock (&sis_priv->lock); return IRQ_RETVAL(handled); @@ -1715,7 +1740,7 @@ static irqreturn_t sis900_interrupt(int irq, void *dev_instance) static int sis900_rx(struct net_device *net_dev) { struct sis900_private *sis_priv = netdev_priv(net_dev); - long ioaddr = net_dev->base_addr; + void __iomem *ioaddr = sis_priv->ioaddr; unsigned int entry = sis_priv->cur_rx % NUM_RX_DESC; u32 rx_status = sis_priv->rx_ring[entry].cmdsts; int rx_work_limit; @@ -1847,7 +1872,7 @@ static int sis900_rx(struct net_device *net_dev) } } /* re-enable the potentially idle receive state matchine */ - outl(RxENA | inl(ioaddr + cr), ioaddr + cr ); + sw32(cr , RxENA | sr32(cr)); return 0; } @@ -1932,31 +1957,31 @@ static void sis900_finish_xmit (struct net_device *net_dev) static int sis900_close(struct net_device *net_dev) { - long ioaddr = net_dev->base_addr; struct sis900_private *sis_priv = netdev_priv(net_dev); + struct pci_dev *pdev = sis_priv->pci_dev; + void __iomem *ioaddr = sis_priv->ioaddr; struct sk_buff *skb; int i; netif_stop_queue(net_dev); /* Disable interrupts by clearing the interrupt mask. */ - outl(0x0000, ioaddr + imr); - outl(0x0000, ioaddr + ier); + sw32(imr, 0x0000); + sw32(ier, 0x0000); /* Stop the chip's Tx and Rx Status Machine */ - outl(RxDIS | TxDIS | inl(ioaddr + cr), ioaddr + cr); + sw32(cr, RxDIS | TxDIS | sr32(cr)); del_timer(&sis_priv->timer); - free_irq(net_dev->irq, net_dev); + free_irq(pdev->irq, net_dev); /* Free Tx and RX skbuff */ for (i = 0; i < NUM_RX_DESC; i++) { skb = sis_priv->rx_skbuff[i]; if (skb) { - pci_unmap_single(sis_priv->pci_dev, - sis_priv->rx_ring[i].bufptr, - RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + pci_unmap_single(pdev, sis_priv->rx_ring[i].bufptr, + RX_BUF_SIZE, PCI_DMA_FROMDEVICE); dev_kfree_skb(skb); sis_priv->rx_skbuff[i] = NULL; } @@ -1964,9 +1989,8 @@ static int sis900_close(struct net_device *net_dev) for (i = 0; i < NUM_TX_DESC; i++) { skb = sis_priv->tx_skbuff[i]; if (skb) { - pci_unmap_single(sis_priv->pci_dev, - sis_priv->tx_ring[i].bufptr, skb->len, - PCI_DMA_TODEVICE); + pci_unmap_single(pdev, sis_priv->tx_ring[i].bufptr, + skb->len, PCI_DMA_TODEVICE); dev_kfree_skb(skb); sis_priv->tx_skbuff[i] = NULL; } @@ -2055,14 +2079,14 @@ static int sis900_nway_reset(struct net_device *net_dev) static int sis900_set_wol(struct net_device *net_dev, struct ethtool_wolinfo *wol) { struct sis900_private *sis_priv = netdev_priv(net_dev); - long pmctrl_addr = net_dev->base_addr + pmctrl; + void __iomem *ioaddr = sis_priv->ioaddr; u32 cfgpmcsr = 0, pmctrl_bits = 0; if (wol->wolopts == 0) { pci_read_config_dword(sis_priv->pci_dev, CFGPMCSR, &cfgpmcsr); cfgpmcsr &= ~PME_EN; pci_write_config_dword(sis_priv->pci_dev, CFGPMCSR, cfgpmcsr); - outl(pmctrl_bits, pmctrl_addr); + sw32(pmctrl, pmctrl_bits); if (netif_msg_wol(sis_priv)) printk(KERN_DEBUG "%s: Wake on LAN disabled\n", net_dev->name); return 0; @@ -2077,7 +2101,7 @@ static int sis900_set_wol(struct net_device *net_dev, struct ethtool_wolinfo *wo if (wol->wolopts & WAKE_PHY) pmctrl_bits |= LINKON; - outl(pmctrl_bits, pmctrl_addr); + sw32(pmctrl, pmctrl_bits); pci_read_config_dword(sis_priv->pci_dev, CFGPMCSR, &cfgpmcsr); cfgpmcsr |= PME_EN; @@ -2090,10 +2114,11 @@ static int sis900_set_wol(struct net_device *net_dev, struct ethtool_wolinfo *wo static void sis900_get_wol(struct net_device *net_dev, struct ethtool_wolinfo *wol) { - long pmctrl_addr = net_dev->base_addr + pmctrl; + struct sis900_private *sp = netdev_priv(net_dev); + void __iomem *ioaddr = sp->ioaddr; u32 pmctrl_bits; - pmctrl_bits = inl(pmctrl_addr); + pmctrl_bits = sr32(pmctrl); if (pmctrl_bits & MAGICPKT) wol->wolopts |= WAKE_MAGIC; if (pmctrl_bits & LINKON) @@ -2279,8 +2304,8 @@ static inline u16 sis900_mcast_bitnr(u8 *addr, u8 revision) static void set_rx_mode(struct net_device *net_dev) { - long ioaddr = net_dev->base_addr; struct sis900_private *sis_priv = netdev_priv(net_dev); + void __iomem *ioaddr = sis_priv->ioaddr; u16 mc_filter[16] = {0}; /* 256/128 bits multicast hash table */ int i, table_entries; u32 rx_mode; @@ -2322,24 +2347,24 @@ static void set_rx_mode(struct net_device *net_dev) /* update Multicast Hash Table in Receive Filter */ for (i = 0; i < table_entries; i++) { /* why plus 0x04 ??, That makes the correct value for hash table. */ - outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr); - outl(mc_filter[i], ioaddr + rfdr); + sw32(rfcr, (u32)(0x00000004 + i) << RFADDR_shift); + sw32(rfdr, mc_filter[i]); } - outl(RFEN | rx_mode, ioaddr + rfcr); + sw32(rfcr, RFEN | rx_mode); /* sis900 is capable of looping back packets at MAC level for * debugging purpose */ if (net_dev->flags & IFF_LOOPBACK) { u32 cr_saved; /* We must disable Tx/Rx before setting loopback mode */ - cr_saved = inl(ioaddr + cr); - outl(cr_saved | TxDIS | RxDIS, ioaddr + cr); + cr_saved = sr32(cr); + sw32(cr, cr_saved | TxDIS | RxDIS); /* enable loopback */ - outl(inl(ioaddr + txcfg) | TxMLB, ioaddr + txcfg); - outl(inl(ioaddr + rxcfg) | RxATX, ioaddr + rxcfg); + sw32(txcfg, sr32(txcfg) | TxMLB); + sw32(rxcfg, sr32(rxcfg) | RxATX); /* restore cr */ - outl(cr_saved, ioaddr + cr); + sw32(cr, cr_saved); } } @@ -2355,26 +2380,25 @@ static void set_rx_mode(struct net_device *net_dev) static void sis900_reset(struct net_device *net_dev) { struct sis900_private *sis_priv = netdev_priv(net_dev); - long ioaddr = net_dev->base_addr; - int i = 0; + void __iomem *ioaddr = sis_priv->ioaddr; u32 status = TxRCMP | RxRCMP; + int i; - outl(0, ioaddr + ier); - outl(0, ioaddr + imr); - outl(0, ioaddr + rfcr); + sw32(ier, 0); + sw32(imr, 0); + sw32(rfcr, 0); - outl(RxRESET | TxRESET | RESET | inl(ioaddr + cr), ioaddr + cr); + sw32(cr, RxRESET | TxRESET | RESET | sr32(cr)); /* Check that the chip has finished the reset. */ - while (status && (i++ < 1000)) { - status ^= (inl(isr + ioaddr) & status); - } + for (i = 0; status && (i < 1000); i++) + status ^= sr32(isr) & status; - if( (sis_priv->chipset_rev >= SIS635A_900_REV) || - (sis_priv->chipset_rev == SIS900B_900_REV) ) - outl(PESEL | RND_CNT, ioaddr + cfg); + if (sis_priv->chipset_rev >= SIS635A_900_REV || + sis_priv->chipset_rev == SIS900B_900_REV) + sw32(cfg, PESEL | RND_CNT); else - outl(PESEL, ioaddr + cfg); + sw32(cfg, PESEL); } /** @@ -2388,10 +2412,12 @@ static void __devexit sis900_remove(struct pci_dev *pci_dev) { struct net_device *net_dev = pci_get_drvdata(pci_dev); struct sis900_private *sis_priv = netdev_priv(net_dev); - struct mii_phy *phy = NULL; + + unregister_netdev(net_dev); while (sis_priv->first_mii) { - phy = sis_priv->first_mii; + struct mii_phy *phy = sis_priv->first_mii; + sis_priv->first_mii = phy->next; kfree(phy); } @@ -2400,7 +2426,7 @@ static void __devexit sis900_remove(struct pci_dev *pci_dev) sis_priv->rx_ring_dma); pci_free_consistent(pci_dev, TX_TOTAL_SIZE, sis_priv->tx_ring, sis_priv->tx_ring_dma); - unregister_netdev(net_dev); + pci_iounmap(pci_dev, sis_priv->ioaddr); free_netdev(net_dev); pci_release_regions(pci_dev); pci_set_drvdata(pci_dev, NULL); @@ -2411,7 +2437,8 @@ static void __devexit sis900_remove(struct pci_dev *pci_dev) static int sis900_suspend(struct pci_dev *pci_dev, pm_message_t state) { struct net_device *net_dev = pci_get_drvdata(pci_dev); - long ioaddr = net_dev->base_addr; + struct sis900_private *sis_priv = netdev_priv(net_dev); + void __iomem *ioaddr = sis_priv->ioaddr; if(!netif_running(net_dev)) return 0; @@ -2420,7 +2447,7 @@ static int sis900_suspend(struct pci_dev *pci_dev, pm_message_t state) netif_device_detach(net_dev); /* Stop the chip's Tx and Rx Status Machine */ - outl(RxDIS | TxDIS | inl(ioaddr + cr), ioaddr + cr); + sw32(cr, RxDIS | TxDIS | sr32(cr)); pci_set_power_state(pci_dev, PCI_D3hot); pci_save_state(pci_dev); @@ -2432,7 +2459,7 @@ static int sis900_resume(struct pci_dev *pci_dev) { struct net_device *net_dev = pci_get_drvdata(pci_dev); struct sis900_private *sis_priv = netdev_priv(net_dev); - long ioaddr = net_dev->base_addr; + void __iomem *ioaddr = sis_priv->ioaddr; if(!netif_running(net_dev)) return 0; @@ -2453,9 +2480,9 @@ static int sis900_resume(struct pci_dev *pci_dev) sis900_set_mode(ioaddr, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED); /* Enable all known interrupts by setting the interrupt mask. */ - outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr); - outl(RxENA | inl(ioaddr + cr), ioaddr + cr); - outl(IE, ioaddr + ier); + sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE); + sw32(cr, RxENA | sr32(cr)); + sw32(ier, IE); sis900_check_mode(net_dev, sis_priv->mii); diff --git a/trunk/drivers/net/ethernet/smsc/epic100.c b/trunk/drivers/net/ethernet/smsc/epic100.c index 2a662e6112e9..d01e59c348ad 100644 --- a/trunk/drivers/net/ethernet/smsc/epic100.c +++ b/trunk/drivers/net/ethernet/smsc/epic100.c @@ -146,6 +146,12 @@ enum chip_capability_flags { MII_PWRDWN=1, TYPE2_INTR=2, NO_MII=4 }; #define EPIC_TOTAL_SIZE 0x100 #define USE_IO_OPS 1 +#ifdef USE_IO_OPS +#define EPIC_BAR 0 +#else +#define EPIC_BAR 1 +#endif + typedef enum { SMSC_83C170_0, SMSC_83C170, @@ -176,21 +182,11 @@ static DEFINE_PCI_DEVICE_TABLE(epic_pci_tbl) = { }; MODULE_DEVICE_TABLE (pci, epic_pci_tbl); - -#ifndef USE_IO_OPS -#undef inb -#undef inw -#undef inl -#undef outb -#undef outw -#undef outl -#define inb readb -#define inw readw -#define inl readl -#define outb writeb -#define outw writew -#define outl writel -#endif +#define ew16(reg, val) iowrite16(val, ioaddr + (reg)) +#define ew32(reg, val) iowrite32(val, ioaddr + (reg)) +#define er8(reg) ioread8(ioaddr + (reg)) +#define er16(reg) ioread16(ioaddr + (reg)) +#define er32(reg) ioread32(ioaddr + (reg)) /* Offsets to registers, using the (ugh) SMC names. */ enum epic_registers { @@ -275,6 +271,7 @@ struct epic_private { u32 irq_mask; unsigned int rx_buf_sz; /* Based on MTU+slack. */ + void __iomem *ioaddr; struct pci_dev *pci_dev; /* PCI bus location. */ int chip_id, chip_flags; @@ -290,7 +287,7 @@ struct epic_private { }; static int epic_open(struct net_device *dev); -static int read_eeprom(long ioaddr, int location); +static int read_eeprom(struct epic_private *, int); static int mdio_read(struct net_device *dev, int phy_id, int location); static void mdio_write(struct net_device *dev, int phy_id, int loc, int val); static void epic_restart(struct net_device *dev); @@ -321,11 +318,11 @@ static const struct net_device_ops epic_netdev_ops = { .ndo_validate_addr = eth_validate_addr, }; -static int __devinit epic_init_one (struct pci_dev *pdev, - const struct pci_device_id *ent) +static int __devinit epic_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) { static int card_idx = -1; - long ioaddr; + void __iomem *ioaddr; int chip_idx = (int) ent->driver_data; int irq; struct net_device *dev; @@ -368,19 +365,15 @@ static int __devinit epic_init_one (struct pci_dev *pdev, SET_NETDEV_DEV(dev, &pdev->dev); -#ifdef USE_IO_OPS - ioaddr = pci_resource_start (pdev, 0); -#else - ioaddr = pci_resource_start (pdev, 1); - ioaddr = (long) pci_ioremap_bar(pdev, 1); + ioaddr = pci_iomap(pdev, EPIC_BAR, 0); if (!ioaddr) { dev_err(&pdev->dev, "ioremap failed\n"); goto err_out_free_netdev; } -#endif pci_set_drvdata(pdev, dev); ep = netdev_priv(dev); + ep->ioaddr = ioaddr; ep->mii.dev = dev; ep->mii.mdio_read = mdio_read; ep->mii.mdio_write = mdio_write; @@ -409,34 +402,31 @@ static int __devinit epic_init_one (struct pci_dev *pdev, duplex = full_duplex[card_idx]; } - dev->base_addr = ioaddr; - dev->irq = irq; - spin_lock_init(&ep->lock); spin_lock_init(&ep->napi_lock); ep->reschedule_in_poll = 0; /* Bring the chip out of low-power mode. */ - outl(0x4200, ioaddr + GENCTL); + ew32(GENCTL, 0x4200); /* Magic?! If we don't set this bit the MII interface won't work. */ /* This magic is documented in SMSC app note 7.15 */ for (i = 16; i > 0; i--) - outl(0x0008, ioaddr + TEST1); + ew32(TEST1, 0x0008); /* Turn on the MII transceiver. */ - outl(0x12, ioaddr + MIICfg); + ew32(MIICfg, 0x12); if (chip_idx == 1) - outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); - outl(0x0200, ioaddr + GENCTL); + ew32(NVCTL, (er32(NVCTL) & ~0x003c) | 0x4800); + ew32(GENCTL, 0x0200); /* Note: the '175 does not have a serial EEPROM. */ for (i = 0; i < 3; i++) - ((__le16 *)dev->dev_addr)[i] = cpu_to_le16(inw(ioaddr + LAN0 + i*4)); + ((__le16 *)dev->dev_addr)[i] = cpu_to_le16(er16(LAN0 + i*4)); if (debug > 2) { dev_printk(KERN_DEBUG, &pdev->dev, "EEPROM contents:\n"); for (i = 0; i < 64; i++) - printk(" %4.4x%s", read_eeprom(ioaddr, i), + printk(" %4.4x%s", read_eeprom(ep, i), i % 16 == 15 ? "\n" : ""); } @@ -481,8 +471,8 @@ static int __devinit epic_init_one (struct pci_dev *pdev, /* Turn off the MII xcvr (175 only!), leave the chip in low-power mode. */ if (ep->chip_flags & MII_PWRDWN) - outl(inl(ioaddr + NVCTL) & ~0x483C, ioaddr + NVCTL); - outl(0x0008, ioaddr + GENCTL); + ew32(NVCTL, er32(NVCTL) & ~0x483c); + ew32(GENCTL, 0x0008); /* The lower four bits are the media type. */ if (duplex) { @@ -501,8 +491,9 @@ static int __devinit epic_init_one (struct pci_dev *pdev, if (ret < 0) goto err_out_unmap_rx; - printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %pM\n", - dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq, + printk(KERN_INFO "%s: %s at %lx, IRQ %d, %pM\n", + dev->name, pci_id_tbl[chip_idx].name, + (long)pci_resource_start(pdev, EPIC_BAR), pdev->irq, dev->dev_addr); out: @@ -513,10 +504,8 @@ static int __devinit epic_init_one (struct pci_dev *pdev, err_out_unmap_tx: pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma); err_out_iounmap: -#ifndef USE_IO_OPS - iounmap(ioaddr); + pci_iounmap(pdev, ioaddr); err_out_free_netdev: -#endif free_netdev(dev); err_out_free_res: pci_release_regions(pdev); @@ -540,7 +529,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev, This serves to flush the operation to the PCI bus. */ -#define eeprom_delay() inl(ee_addr) +#define eeprom_delay() er32(EECTL) /* The EEPROM commands include the alway-set leading bit. */ #define EE_WRITE_CMD (5 << 6) @@ -550,67 +539,67 @@ static int __devinit epic_init_one (struct pci_dev *pdev, static void epic_disable_int(struct net_device *dev, struct epic_private *ep) { - long ioaddr = dev->base_addr; + void __iomem *ioaddr = ep->ioaddr; - outl(0x00000000, ioaddr + INTMASK); + ew32(INTMASK, 0x00000000); } -static inline void __epic_pci_commit(long ioaddr) +static inline void __epic_pci_commit(void __iomem *ioaddr) { #ifndef USE_IO_OPS - inl(ioaddr + INTMASK); + er32(INTMASK); #endif } static inline void epic_napi_irq_off(struct net_device *dev, struct epic_private *ep) { - long ioaddr = dev->base_addr; + void __iomem *ioaddr = ep->ioaddr; - outl(ep->irq_mask & ~EpicNapiEvent, ioaddr + INTMASK); + ew32(INTMASK, ep->irq_mask & ~EpicNapiEvent); __epic_pci_commit(ioaddr); } static inline void epic_napi_irq_on(struct net_device *dev, struct epic_private *ep) { - long ioaddr = dev->base_addr; + void __iomem *ioaddr = ep->ioaddr; /* No need to commit possible posted write */ - outl(ep->irq_mask | EpicNapiEvent, ioaddr + INTMASK); + ew32(INTMASK, ep->irq_mask | EpicNapiEvent); } -static int __devinit read_eeprom(long ioaddr, int location) +static int __devinit read_eeprom(struct epic_private *ep, int location) { + void __iomem *ioaddr = ep->ioaddr; int i; int retval = 0; - long ee_addr = ioaddr + EECTL; int read_cmd = location | - (inl(ee_addr) & 0x40 ? EE_READ64_CMD : EE_READ256_CMD); + (er32(EECTL) & 0x40 ? EE_READ64_CMD : EE_READ256_CMD); - outl(EE_ENB & ~EE_CS, ee_addr); - outl(EE_ENB, ee_addr); + ew32(EECTL, EE_ENB & ~EE_CS); + ew32(EECTL, EE_ENB); /* Shift the read command bits out. */ for (i = 12; i >= 0; i--) { short dataval = (read_cmd & (1 << i)) ? EE_WRITE_1 : EE_WRITE_0; - outl(EE_ENB | dataval, ee_addr); + ew32(EECTL, EE_ENB | dataval); eeprom_delay(); - outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); + ew32(EECTL, EE_ENB | dataval | EE_SHIFT_CLK); eeprom_delay(); } - outl(EE_ENB, ee_addr); + ew32(EECTL, EE_ENB); for (i = 16; i > 0; i--) { - outl(EE_ENB | EE_SHIFT_CLK, ee_addr); + ew32(EECTL, EE_ENB | EE_SHIFT_CLK); eeprom_delay(); - retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); - outl(EE_ENB, ee_addr); + retval = (retval << 1) | ((er32(EECTL) & EE_DATA_READ) ? 1 : 0); + ew32(EECTL, EE_ENB); eeprom_delay(); } /* Terminate the EEPROM access. */ - outl(EE_ENB & ~EE_CS, ee_addr); + ew32(EECTL, EE_ENB & ~EE_CS); return retval; } @@ -618,22 +607,23 @@ static int __devinit read_eeprom(long ioaddr, int location) #define MII_WRITEOP 2 static int mdio_read(struct net_device *dev, int phy_id, int location) { - long ioaddr = dev->base_addr; + struct epic_private *ep = netdev_priv(dev); + void __iomem *ioaddr = ep->ioaddr; int read_cmd = (phy_id << 9) | (location << 4) | MII_READOP; int i; - outl(read_cmd, ioaddr + MIICtrl); + ew32(MIICtrl, read_cmd); /* Typical operation takes 25 loops. */ for (i = 400; i > 0; i--) { barrier(); - if ((inl(ioaddr + MIICtrl) & MII_READOP) == 0) { + if ((er32(MIICtrl) & MII_READOP) == 0) { /* Work around read failure bug. */ if (phy_id == 1 && location < 6 && - inw(ioaddr + MIIData) == 0xffff) { - outl(read_cmd, ioaddr + MIICtrl); + er16(MIIData) == 0xffff) { + ew32(MIICtrl, read_cmd); continue; } - return inw(ioaddr + MIIData); + return er16(MIIData); } } return 0xffff; @@ -641,14 +631,15 @@ static int mdio_read(struct net_device *dev, int phy_id, int location) static void mdio_write(struct net_device *dev, int phy_id, int loc, int value) { - long ioaddr = dev->base_addr; + struct epic_private *ep = netdev_priv(dev); + void __iomem *ioaddr = ep->ioaddr; int i; - outw(value, ioaddr + MIIData); - outl((phy_id << 9) | (loc << 4) | MII_WRITEOP, ioaddr + MIICtrl); + ew16(MIIData, value); + ew32(MIICtrl, (phy_id << 9) | (loc << 4) | MII_WRITEOP); for (i = 10000; i > 0; i--) { barrier(); - if ((inl(ioaddr + MIICtrl) & MII_WRITEOP) == 0) + if ((er32(MIICtrl) & MII_WRITEOP) == 0) break; } } @@ -657,25 +648,26 @@ static void mdio_write(struct net_device *dev, int phy_id, int loc, int value) static int epic_open(struct net_device *dev) { struct epic_private *ep = netdev_priv(dev); - long ioaddr = dev->base_addr; - int i; - int retval; + void __iomem *ioaddr = ep->ioaddr; + const int irq = ep->pci_dev->irq; + int rc, i; /* Soft reset the chip. */ - outl(0x4001, ioaddr + GENCTL); + ew32(GENCTL, 0x4001); napi_enable(&ep->napi); - if ((retval = request_irq(dev->irq, epic_interrupt, IRQF_SHARED, dev->name, dev))) { + rc = request_irq(irq, epic_interrupt, IRQF_SHARED, dev->name, dev); + if (rc) { napi_disable(&ep->napi); - return retval; + return rc; } epic_init_ring(dev); - outl(0x4000, ioaddr + GENCTL); + ew32(GENCTL, 0x4000); /* This magic is documented in SMSC app note 7.15 */ for (i = 16; i > 0; i--) - outl(0x0008, ioaddr + TEST1); + ew32(TEST1, 0x0008); /* Pull the chip out of low-power mode, enable interrupts, and set for PCI read multiple. The MIIcfg setting and strange write order are @@ -683,29 +675,29 @@ static int epic_open(struct net_device *dev) wiring on the Ositech CardBus card. */ #if 0 - outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg); + ew32(MIICfg, dev->if_port == 1 ? 0x13 : 0x12); #endif if (ep->chip_flags & MII_PWRDWN) - outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); + ew32(NVCTL, (er32(NVCTL) & ~0x003c) | 0x4800); /* Tell the chip to byteswap descriptors on big-endian hosts */ #ifdef __BIG_ENDIAN - outl(0x4432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL); - inl(ioaddr + GENCTL); - outl(0x0432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL); + ew32(GENCTL, 0x4432 | (RX_FIFO_THRESH << 8)); + er32(GENCTL); + ew32(GENCTL, 0x0432 | (RX_FIFO_THRESH << 8)); #else - outl(0x4412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL); - inl(ioaddr + GENCTL); - outl(0x0412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL); + ew32(GENCTL, 0x4412 | (RX_FIFO_THRESH << 8)); + er32(GENCTL); + ew32(GENCTL, 0x0412 | (RX_FIFO_THRESH << 8)); #endif udelay(20); /* Looks like EPII needs that if you want reliable RX init. FIXME: pci posting bug? */ for (i = 0; i < 3; i++) - outl(le16_to_cpu(((__le16*)dev->dev_addr)[i]), ioaddr + LAN0 + i*4); + ew32(LAN0 + i*4, le16_to_cpu(((__le16*)dev->dev_addr)[i])); ep->tx_threshold = TX_FIFO_THRESH; - outl(ep->tx_threshold, ioaddr + TxThresh); + ew32(TxThresh, ep->tx_threshold); if (media2miictl[dev->if_port & 15]) { if (ep->mii_phy_cnt) @@ -731,26 +723,27 @@ static int epic_open(struct net_device *dev) } } - outl(ep->mii.full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl); - outl(ep->rx_ring_dma, ioaddr + PRxCDAR); - outl(ep->tx_ring_dma, ioaddr + PTxCDAR); + ew32(TxCtrl, ep->mii.full_duplex ? 0x7f : 0x79); + ew32(PRxCDAR, ep->rx_ring_dma); + ew32(PTxCDAR, ep->tx_ring_dma); /* Start the chip's Rx process. */ set_rx_mode(dev); - outl(StartRx | RxQueued, ioaddr + COMMAND); + ew32(COMMAND, StartRx | RxQueued); netif_start_queue(dev); /* Enable interrupts by setting the interrupt mask. */ - outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170) - | CntFull | TxUnderrun - | RxError | RxHeader | EpicNapiEvent, ioaddr + INTMASK); - - if (debug > 1) - printk(KERN_DEBUG "%s: epic_open() ioaddr %lx IRQ %d status %4.4x " - "%s-duplex.\n", - dev->name, ioaddr, dev->irq, (int)inl(ioaddr + GENCTL), - ep->mii.full_duplex ? "full" : "half"); + ew32(INTMASK, RxError | RxHeader | EpicNapiEvent | CntFull | + ((ep->chip_flags & TYPE2_INTR) ? PCIBusErr175 : PCIBusErr170) | + TxUnderrun); + + if (debug > 1) { + printk(KERN_DEBUG "%s: epic_open() ioaddr %p IRQ %d " + "status %4.4x %s-duplex.\n", + dev->name, ioaddr, irq, er32(GENCTL), + ep->mii.full_duplex ? "full" : "half"); + } /* Set the timer to switch to check for link beat and perhaps switch to an alternate media type. */ @@ -760,27 +753,29 @@ static int epic_open(struct net_device *dev) ep->timer.function = epic_timer; /* timer handler */ add_timer(&ep->timer); - return 0; + return rc; } /* Reset the chip to recover from a PCI transaction error. This may occur at interrupt time. */ static void epic_pause(struct net_device *dev) { - long ioaddr = dev->base_addr; + struct net_device_stats *stats = &dev->stats; + struct epic_private *ep = netdev_priv(dev); + void __iomem *ioaddr = ep->ioaddr; netif_stop_queue (dev); /* Disable interrupts by clearing the interrupt mask. */ - outl(0x00000000, ioaddr + INTMASK); + ew32(INTMASK, 0x00000000); /* Stop the chip's Tx and Rx DMA processes. */ - outw(StopRx | StopTxDMA | StopRxDMA, ioaddr + COMMAND); + ew16(COMMAND, StopRx | StopTxDMA | StopRxDMA); /* Update the error counts. */ - if (inw(ioaddr + COMMAND) != 0xffff) { - dev->stats.rx_missed_errors += inb(ioaddr + MPCNT); - dev->stats.rx_frame_errors += inb(ioaddr + ALICNT); - dev->stats.rx_crc_errors += inb(ioaddr + CRCCNT); + if (er16(COMMAND) != 0xffff) { + stats->rx_missed_errors += er8(MPCNT); + stats->rx_frame_errors += er8(ALICNT); + stats->rx_crc_errors += er8(CRCCNT); } /* Remove the packets on the Rx queue. */ @@ -789,12 +784,12 @@ static void epic_pause(struct net_device *dev) static void epic_restart(struct net_device *dev) { - long ioaddr = dev->base_addr; struct epic_private *ep = netdev_priv(dev); + void __iomem *ioaddr = ep->ioaddr; int i; /* Soft reset the chip. */ - outl(0x4001, ioaddr + GENCTL); + ew32(GENCTL, 0x4001); printk(KERN_DEBUG "%s: Restarting the EPIC chip, Rx %d/%d Tx %d/%d.\n", dev->name, ep->cur_rx, ep->dirty_rx, ep->dirty_tx, ep->cur_tx); @@ -802,47 +797,46 @@ static void epic_restart(struct net_device *dev) /* This magic is documented in SMSC app note 7.15 */ for (i = 16; i > 0; i--) - outl(0x0008, ioaddr + TEST1); + ew32(TEST1, 0x0008); #ifdef __BIG_ENDIAN - outl(0x0432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL); + ew32(GENCTL, 0x0432 | (RX_FIFO_THRESH << 8)); #else - outl(0x0412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL); + ew32(GENCTL, 0x0412 | (RX_FIFO_THRESH << 8)); #endif - outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg); + ew32(MIICfg, dev->if_port == 1 ? 0x13 : 0x12); if (ep->chip_flags & MII_PWRDWN) - outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); + ew32(NVCTL, (er32(NVCTL) & ~0x003c) | 0x4800); for (i = 0; i < 3; i++) - outl(le16_to_cpu(((__le16*)dev->dev_addr)[i]), ioaddr + LAN0 + i*4); + ew32(LAN0 + i*4, le16_to_cpu(((__le16*)dev->dev_addr)[i])); ep->tx_threshold = TX_FIFO_THRESH; - outl(ep->tx_threshold, ioaddr + TxThresh); - outl(ep->mii.full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl); - outl(ep->rx_ring_dma + (ep->cur_rx%RX_RING_SIZE)* - sizeof(struct epic_rx_desc), ioaddr + PRxCDAR); - outl(ep->tx_ring_dma + (ep->dirty_tx%TX_RING_SIZE)* - sizeof(struct epic_tx_desc), ioaddr + PTxCDAR); + ew32(TxThresh, ep->tx_threshold); + ew32(TxCtrl, ep->mii.full_duplex ? 0x7f : 0x79); + ew32(PRxCDAR, ep->rx_ring_dma + + (ep->cur_rx % RX_RING_SIZE) * sizeof(struct epic_rx_desc)); + ew32(PTxCDAR, ep->tx_ring_dma + + (ep->dirty_tx % TX_RING_SIZE) * sizeof(struct epic_tx_desc)); /* Start the chip's Rx process. */ set_rx_mode(dev); - outl(StartRx | RxQueued, ioaddr + COMMAND); + ew32(COMMAND, StartRx | RxQueued); /* Enable interrupts by setting the interrupt mask. */ - outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170) - | CntFull | TxUnderrun - | RxError | RxHeader | EpicNapiEvent, ioaddr + INTMASK); + ew32(INTMASK, RxError | RxHeader | EpicNapiEvent | CntFull | + ((ep->chip_flags & TYPE2_INTR) ? PCIBusErr175 : PCIBusErr170) | + TxUnderrun); printk(KERN_DEBUG "%s: epic_restart() done, cmd status %4.4x, ctl %4.4x" " interrupt %4.4x.\n", - dev->name, (int)inl(ioaddr + COMMAND), (int)inl(ioaddr + GENCTL), - (int)inl(ioaddr + INTSTAT)); + dev->name, er32(COMMAND), er32(GENCTL), er32(INTSTAT)); } static void check_media(struct net_device *dev) { struct epic_private *ep = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem *ioaddr = ep->ioaddr; int mii_lpa = ep->mii_phy_cnt ? mdio_read(dev, ep->phys[0], MII_LPA) : 0; int negotiated = mii_lpa & ep->mii.advertising; int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; @@ -856,7 +850,7 @@ static void check_media(struct net_device *dev) printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link" " partner capability of %4.4x.\n", dev->name, ep->mii.full_duplex ? "full" : "half", ep->phys[0], mii_lpa); - outl(ep->mii.full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl); + ew32(TxCtrl, ep->mii.full_duplex ? 0x7F : 0x79); } } @@ -864,16 +858,15 @@ static void epic_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; struct epic_private *ep = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem *ioaddr = ep->ioaddr; int next_tick = 5*HZ; if (debug > 3) { printk(KERN_DEBUG "%s: Media monitor tick, Tx status %8.8x.\n", - dev->name, (int)inl(ioaddr + TxSTAT)); + dev->name, er32(TxSTAT)); printk(KERN_DEBUG "%s: Other registers are IntMask %4.4x " - "IntStatus %4.4x RxStatus %4.4x.\n", - dev->name, (int)inl(ioaddr + INTMASK), - (int)inl(ioaddr + INTSTAT), (int)inl(ioaddr + RxSTAT)); + "IntStatus %4.4x RxStatus %4.4x.\n", dev->name, + er32(INTMASK), er32(INTSTAT), er32(RxSTAT)); } check_media(dev); @@ -885,23 +878,22 @@ static void epic_timer(unsigned long data) static void epic_tx_timeout(struct net_device *dev) { struct epic_private *ep = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem *ioaddr = ep->ioaddr; if (debug > 0) { printk(KERN_WARNING "%s: Transmit timeout using MII device, " - "Tx status %4.4x.\n", - dev->name, (int)inw(ioaddr + TxSTAT)); + "Tx status %4.4x.\n", dev->name, er16(TxSTAT)); if (debug > 1) { printk(KERN_DEBUG "%s: Tx indices: dirty_tx %d, cur_tx %d.\n", dev->name, ep->dirty_tx, ep->cur_tx); } } - if (inw(ioaddr + TxSTAT) & 0x10) { /* Tx FIFO underflow. */ + if (er16(TxSTAT) & 0x10) { /* Tx FIFO underflow. */ dev->stats.tx_fifo_errors++; - outl(RestartTx, ioaddr + COMMAND); + ew32(COMMAND, RestartTx); } else { epic_restart(dev); - outl(TxQueued, dev->base_addr + COMMAND); + ew32(COMMAND, TxQueued); } dev->trans_start = jiffies; /* prevent tx timeout */ @@ -959,6 +951,7 @@ static void epic_init_ring(struct net_device *dev) static netdev_tx_t epic_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct epic_private *ep = netdev_priv(dev); + void __iomem *ioaddr = ep->ioaddr; int entry, free_count; u32 ctrl_word; unsigned long flags; @@ -999,13 +992,12 @@ static netdev_tx_t epic_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&ep->lock, flags); /* Trigger an immediate transmit demand. */ - outl(TxQueued, dev->base_addr + COMMAND); + ew32(COMMAND, TxQueued); if (debug > 4) printk(KERN_DEBUG "%s: Queued Tx packet size %d to slot %d, " - "flag %2.2x Tx status %8.8x.\n", - dev->name, (int)skb->len, entry, ctrl_word, - (int)inl(dev->base_addr + TxSTAT)); + "flag %2.2x Tx status %8.8x.\n", dev->name, skb->len, + entry, ctrl_word, er32(TxSTAT)); return NETDEV_TX_OK; } @@ -1086,18 +1078,17 @@ static irqreturn_t epic_interrupt(int irq, void *dev_instance) { struct net_device *dev = dev_instance; struct epic_private *ep = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem *ioaddr = ep->ioaddr; unsigned int handled = 0; int status; - status = inl(ioaddr + INTSTAT); + status = er32(INTSTAT); /* Acknowledge all of the current interrupt sources ASAP. */ - outl(status & EpicNormalEvent, ioaddr + INTSTAT); + ew32(INTSTAT, status & EpicNormalEvent); if (debug > 4) { printk(KERN_DEBUG "%s: Interrupt, status=%#8.8x new " - "intstat=%#8.8x.\n", dev->name, status, - (int)inl(ioaddr + INTSTAT)); + "intstat=%#8.8x.\n", dev->name, status, er32(INTSTAT)); } if ((status & IntrSummary) == 0) @@ -1118,19 +1109,21 @@ static irqreturn_t epic_interrupt(int irq, void *dev_instance) /* Check uncommon events all at once. */ if (status & (CntFull | TxUnderrun | PCIBusErr170 | PCIBusErr175)) { + struct net_device_stats *stats = &dev->stats; + if (status == EpicRemoved) goto out; /* Always update the error counts to avoid overhead later. */ - dev->stats.rx_missed_errors += inb(ioaddr + MPCNT); - dev->stats.rx_frame_errors += inb(ioaddr + ALICNT); - dev->stats.rx_crc_errors += inb(ioaddr + CRCCNT); + stats->rx_missed_errors += er8(MPCNT); + stats->rx_frame_errors += er8(ALICNT); + stats->rx_crc_errors += er8(CRCCNT); if (status & TxUnderrun) { /* Tx FIFO underflow. */ - dev->stats.tx_fifo_errors++; - outl(ep->tx_threshold += 128, ioaddr + TxThresh); + stats->tx_fifo_errors++; + ew32(TxThresh, ep->tx_threshold += 128); /* Restart the transmit process. */ - outl(RestartTx, ioaddr + COMMAND); + ew32(COMMAND, RestartTx); } if (status & PCIBusErr170) { printk(KERN_ERR "%s: PCI Bus Error! status %4.4x.\n", @@ -1139,7 +1132,7 @@ static irqreturn_t epic_interrupt(int irq, void *dev_instance) epic_restart(dev); } /* Clear all error sources. */ - outl(status & 0x7f18, ioaddr + INTSTAT); + ew32(INTSTAT, status & 0x7f18); } out: @@ -1248,17 +1241,17 @@ static int epic_rx(struct net_device *dev, int budget) static void epic_rx_err(struct net_device *dev, struct epic_private *ep) { - long ioaddr = dev->base_addr; + void __iomem *ioaddr = ep->ioaddr; int status; - status = inl(ioaddr + INTSTAT); + status = er32(INTSTAT); if (status == EpicRemoved) return; if (status & RxOverflow) /* Missed a Rx frame. */ dev->stats.rx_errors++; if (status & (RxOverflow | RxFull)) - outw(RxQueued, ioaddr + COMMAND); + ew16(COMMAND, RxQueued); } static int epic_poll(struct napi_struct *napi, int budget) @@ -1266,7 +1259,7 @@ static int epic_poll(struct napi_struct *napi, int budget) struct epic_private *ep = container_of(napi, struct epic_private, napi); struct net_device *dev = ep->mii.dev; int work_done = 0; - long ioaddr = dev->base_addr; + void __iomem *ioaddr = ep->ioaddr; rx_action: @@ -1287,7 +1280,7 @@ static int epic_poll(struct napi_struct *napi, int budget) more = ep->reschedule_in_poll; if (!more) { __napi_complete(napi); - outl(EpicNapiEvent, ioaddr + INTSTAT); + ew32(INTSTAT, EpicNapiEvent); epic_napi_irq_on(dev, ep); } else ep->reschedule_in_poll--; @@ -1303,8 +1296,9 @@ static int epic_poll(struct napi_struct *napi, int budget) static int epic_close(struct net_device *dev) { - long ioaddr = dev->base_addr; struct epic_private *ep = netdev_priv(dev); + struct pci_dev *pdev = ep->pci_dev; + void __iomem *ioaddr = ep->ioaddr; struct sk_buff *skb; int i; @@ -1313,13 +1307,13 @@ static int epic_close(struct net_device *dev) if (debug > 1) printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", - dev->name, (int)inl(ioaddr + INTSTAT)); + dev->name, er32(INTSTAT)); del_timer_sync(&ep->timer); epic_disable_int(dev, ep); - free_irq(dev->irq, dev); + free_irq(pdev->irq, dev); epic_pause(dev); @@ -1330,7 +1324,7 @@ static int epic_close(struct net_device *dev) ep->rx_ring[i].rxstatus = 0; /* Not owned by Epic chip. */ ep->rx_ring[i].buflength = 0; if (skb) { - pci_unmap_single(ep->pci_dev, ep->rx_ring[i].bufaddr, + pci_unmap_single(pdev, ep->rx_ring[i].bufaddr, ep->rx_buf_sz, PCI_DMA_FROMDEVICE); dev_kfree_skb(skb); } @@ -1341,26 +1335,28 @@ static int epic_close(struct net_device *dev) ep->tx_skbuff[i] = NULL; if (!skb) continue; - pci_unmap_single(ep->pci_dev, ep->tx_ring[i].bufaddr, - skb->len, PCI_DMA_TODEVICE); + pci_unmap_single(pdev, ep->tx_ring[i].bufaddr, skb->len, + PCI_DMA_TODEVICE); dev_kfree_skb(skb); } /* Green! Leave the chip in low-power mode. */ - outl(0x0008, ioaddr + GENCTL); + ew32(GENCTL, 0x0008); return 0; } static struct net_device_stats *epic_get_stats(struct net_device *dev) { - long ioaddr = dev->base_addr; + struct epic_private *ep = netdev_priv(dev); + void __iomem *ioaddr = ep->ioaddr; if (netif_running(dev)) { - /* Update the error counts. */ - dev->stats.rx_missed_errors += inb(ioaddr + MPCNT); - dev->stats.rx_frame_errors += inb(ioaddr + ALICNT); - dev->stats.rx_crc_errors += inb(ioaddr + CRCCNT); + struct net_device_stats *stats = &dev->stats; + + stats->rx_missed_errors += er8(MPCNT); + stats->rx_frame_errors += er8(ALICNT); + stats->rx_crc_errors += er8(CRCCNT); } return &dev->stats; @@ -1373,13 +1369,13 @@ static struct net_device_stats *epic_get_stats(struct net_device *dev) static void set_rx_mode(struct net_device *dev) { - long ioaddr = dev->base_addr; struct epic_private *ep = netdev_priv(dev); + void __iomem *ioaddr = ep->ioaddr; unsigned char mc_filter[8]; /* Multicast hash filter */ int i; if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ - outl(0x002C, ioaddr + RxCtrl); + ew32(RxCtrl, 0x002c); /* Unconditionally log net taps. */ memset(mc_filter, 0xff, sizeof(mc_filter)); } else if ((!netdev_mc_empty(dev)) || (dev->flags & IFF_ALLMULTI)) { @@ -1387,9 +1383,9 @@ static void set_rx_mode(struct net_device *dev) is never enabled. */ /* Too many to filter perfectly -- accept all multicasts. */ memset(mc_filter, 0xff, sizeof(mc_filter)); - outl(0x000C, ioaddr + RxCtrl); + ew32(RxCtrl, 0x000c); } else if (netdev_mc_empty(dev)) { - outl(0x0004, ioaddr + RxCtrl); + ew32(RxCtrl, 0x0004); return; } else { /* Never executed, for now. */ struct netdev_hw_addr *ha; @@ -1404,7 +1400,7 @@ static void set_rx_mode(struct net_device *dev) /* ToDo: perhaps we need to stop the Tx and Rx process here? */ if (memcmp(mc_filter, ep->mc_filter, sizeof(mc_filter))) { for (i = 0; i < 4; i++) - outw(((u16 *)mc_filter)[i], ioaddr + MC0 + i*4); + ew16(MC0 + i*4, ((u16 *)mc_filter)[i]); memcpy(ep->mc_filter, mc_filter, sizeof(mc_filter)); } } @@ -1466,22 +1462,26 @@ static void netdev_set_msglevel(struct net_device *dev, u32 value) static int ethtool_begin(struct net_device *dev) { - unsigned long ioaddr = dev->base_addr; + struct epic_private *ep = netdev_priv(dev); + void __iomem *ioaddr = ep->ioaddr; + /* power-up, if interface is down */ - if (! netif_running(dev)) { - outl(0x0200, ioaddr + GENCTL); - outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); + if (!netif_running(dev)) { + ew32(GENCTL, 0x0200); + ew32(NVCTL, (er32(NVCTL) & ~0x003c) | 0x4800); } return 0; } static void ethtool_complete(struct net_device *dev) { - unsigned long ioaddr = dev->base_addr; + struct epic_private *ep = netdev_priv(dev); + void __iomem *ioaddr = ep->ioaddr; + /* power-down, if interface is down */ - if (! netif_running(dev)) { - outl(0x0008, ioaddr + GENCTL); - outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL); + if (!netif_running(dev)) { + ew32(GENCTL, 0x0008); + ew32(NVCTL, (er32(NVCTL) & ~0x483c) | 0x0000); } } @@ -1500,14 +1500,14 @@ static const struct ethtool_ops netdev_ethtool_ops = { static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct epic_private *np = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem *ioaddr = np->ioaddr; struct mii_ioctl_data *data = if_mii(rq); int rc; /* power-up, if interface is down */ if (! netif_running(dev)) { - outl(0x0200, ioaddr + GENCTL); - outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); + ew32(GENCTL, 0x0200); + ew32(NVCTL, (er32(NVCTL) & ~0x003c) | 0x4800); } /* all non-ethtool ioctls (the SIOC[GS]MIIxxx ioctls) */ @@ -1517,14 +1517,14 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) /* power-down, if interface is down */ if (! netif_running(dev)) { - outl(0x0008, ioaddr + GENCTL); - outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL); + ew32(GENCTL, 0x0008); + ew32(NVCTL, (er32(NVCTL) & ~0x483c) | 0x0000); } return rc; } -static void __devexit epic_remove_one (struct pci_dev *pdev) +static void __devexit epic_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); struct epic_private *ep = netdev_priv(dev); @@ -1532,9 +1532,7 @@ static void __devexit epic_remove_one (struct pci_dev *pdev) pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma); pci_free_consistent(pdev, RX_TOTAL_SIZE, ep->rx_ring, ep->rx_ring_dma); unregister_netdev(dev); -#ifndef USE_IO_OPS - iounmap((void*) dev->base_addr); -#endif + pci_iounmap(pdev, ep->ioaddr); pci_release_regions(pdev); free_netdev(dev); pci_disable_device(pdev); @@ -1548,13 +1546,14 @@ static void __devexit epic_remove_one (struct pci_dev *pdev) static int epic_suspend (struct pci_dev *pdev, pm_message_t state) { struct net_device *dev = pci_get_drvdata(pdev); - long ioaddr = dev->base_addr; + struct epic_private *ep = netdev_priv(dev); + void __iomem *ioaddr = ep->ioaddr; if (!netif_running(dev)) return 0; epic_pause(dev); /* Put the chip into low-power mode. */ - outl(0x0008, ioaddr + GENCTL); + ew32(GENCTL, 0x0008); /* pci_power_off(pdev, -1); */ return 0; } diff --git a/trunk/drivers/net/ethernet/smsc/smsc911x.c b/trunk/drivers/net/ethernet/smsc/smsc911x.c index cd3defb11ffb..dab9c6f671ec 100644 --- a/trunk/drivers/net/ethernet/smsc/smsc911x.c +++ b/trunk/drivers/net/ethernet/smsc/smsc911x.c @@ -2066,6 +2066,7 @@ static const struct ethtool_ops smsc911x_ethtool_ops = { .get_eeprom_len = smsc911x_ethtool_get_eeprom_len, .get_eeprom = smsc911x_ethtool_get_eeprom, .set_eeprom = smsc911x_ethtool_set_eeprom, + .get_ts_info = ethtool_op_get_ts_info, }; static const struct net_device_ops smsc911x_netdev_ops = { diff --git a/trunk/drivers/net/ethernet/smsc/smsc9420.c b/trunk/drivers/net/ethernet/smsc/smsc9420.c index 38386478532b..fd33b21f6c96 100644 --- a/trunk/drivers/net/ethernet/smsc/smsc9420.c +++ b/trunk/drivers/net/ethernet/smsc/smsc9420.c @@ -54,7 +54,7 @@ struct smsc9420_ring_info { }; struct smsc9420_pdata { - void __iomem *base_addr; + void __iomem *ioaddr; struct pci_dev *pdev; struct net_device *dev; @@ -114,13 +114,13 @@ do { if ((pd)->msg_enable & NETIF_MSG_##TYPE) \ static inline u32 smsc9420_reg_read(struct smsc9420_pdata *pd, u32 offset) { - return ioread32(pd->base_addr + offset); + return ioread32(pd->ioaddr + offset); } static inline void smsc9420_reg_write(struct smsc9420_pdata *pd, u32 offset, u32 value) { - iowrite32(value, pd->base_addr + offset); + iowrite32(value, pd->ioaddr + offset); } static inline void smsc9420_pci_flush_write(struct smsc9420_pdata *pd) @@ -469,6 +469,7 @@ static const struct ethtool_ops smsc9420_ethtool_ops = { .set_eeprom = smsc9420_ethtool_set_eeprom, .get_regs_len = smsc9420_ethtool_getregslen, .get_regs = smsc9420_ethtool_getregs, + .get_ts_info = ethtool_op_get_ts_info, }; /* Sets the device MAC address to dev_addr */ @@ -659,7 +660,7 @@ static irqreturn_t smsc9420_isr(int irq, void *dev_id) ulong flags; BUG_ON(!pd); - BUG_ON(!pd->base_addr); + BUG_ON(!pd->ioaddr); int_cfg = smsc9420_reg_read(pd, INT_CFG); @@ -720,9 +721,12 @@ static irqreturn_t smsc9420_isr(int irq, void *dev_id) #ifdef CONFIG_NET_POLL_CONTROLLER static void smsc9420_poll_controller(struct net_device *dev) { - disable_irq(dev->irq); + struct smsc9420_pdata *pd = netdev_priv(dev); + const int irq = pd->pdev->irq; + + disable_irq(irq); smsc9420_isr(0, dev); - enable_irq(dev->irq); + enable_irq(irq); } #endif /* CONFIG_NET_POLL_CONTROLLER */ @@ -759,7 +763,7 @@ static int smsc9420_stop(struct net_device *dev) smsc9420_stop_rx(pd); smsc9420_free_rx_ring(pd); - free_irq(dev->irq, pd); + free_irq(pd->pdev->irq, pd); smsc9420_dmac_soft_reset(pd); @@ -1331,15 +1335,12 @@ static int smsc9420_alloc_rx_ring(struct smsc9420_pdata *pd) static int smsc9420_open(struct net_device *dev) { - struct smsc9420_pdata *pd; + struct smsc9420_pdata *pd = netdev_priv(dev); u32 bus_mode, mac_cr, dmac_control, int_cfg, dma_intr_ena, int_ctl; + const int irq = pd->pdev->irq; unsigned long flags; int result = 0, timeout; - BUG_ON(!dev); - pd = netdev_priv(dev); - BUG_ON(!pd); - if (!is_valid_ether_addr(dev->dev_addr)) { smsc_warn(IFUP, "dev_addr is not a valid MAC address"); result = -EADDRNOTAVAIL; @@ -1358,9 +1359,10 @@ static int smsc9420_open(struct net_device *dev) smsc9420_reg_write(pd, INT_STAT, 0xFFFFFFFF); smsc9420_pci_flush_write(pd); - if (request_irq(dev->irq, smsc9420_isr, IRQF_SHARED | IRQF_DISABLED, - DRV_NAME, pd)) { - smsc_warn(IFUP, "Unable to use IRQ = %d", dev->irq); + result = request_irq(irq, smsc9420_isr, IRQF_SHARED | IRQF_DISABLED, + DRV_NAME, pd); + if (result) { + smsc_warn(IFUP, "Unable to use IRQ = %d", irq); result = -ENODEV; goto out_0; } @@ -1395,7 +1397,7 @@ static int smsc9420_open(struct net_device *dev) smsc9420_pci_flush_write(pd); /* test the IRQ connection to the ISR */ - smsc_dbg(IFUP, "Testing ISR using IRQ %d", dev->irq); + smsc_dbg(IFUP, "Testing ISR using IRQ %d", irq); pd->software_irq_signal = false; spin_lock_irqsave(&pd->int_lock, flags); @@ -1430,7 +1432,7 @@ static int smsc9420_open(struct net_device *dev) goto out_free_irq_1; } - smsc_dbg(IFUP, "ISR passed test using IRQ %d", dev->irq); + smsc_dbg(IFUP, "ISR passed test using IRQ %d", irq); result = smsc9420_alloc_tx_ring(pd); if (result) { @@ -1490,7 +1492,7 @@ static int smsc9420_open(struct net_device *dev) out_free_tx_ring_2: smsc9420_free_tx_ring(pd); out_free_irq_1: - free_irq(dev->irq, pd); + free_irq(irq, pd); out_0: return result; } @@ -1519,7 +1521,7 @@ static int smsc9420_suspend(struct pci_dev *pdev, pm_message_t state) smsc9420_stop_rx(pd); smsc9420_free_rx_ring(pd); - free_irq(dev->irq, pd); + free_irq(pd->pdev->irq, pd); netif_device_detach(dev); } @@ -1552,6 +1554,7 @@ static int smsc9420_resume(struct pci_dev *pdev) smsc_warn(IFUP, "pci_enable_wake failed: %d", err); if (netif_running(dev)) { + /* FIXME: gross. It looks like ancient PM relic.*/ err = smsc9420_open(dev); netif_device_attach(dev); } @@ -1625,8 +1628,6 @@ smsc9420_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* registers are double mapped with 0 offset for LE and 0x200 for BE */ virt_addr += LAN9420_CPSR_ENDIAN_OFFSET; - dev->base_addr = (ulong)virt_addr; - pd = netdev_priv(dev); /* pci descriptors are created in the PCI consistent area */ @@ -1646,7 +1647,7 @@ smsc9420_probe(struct pci_dev *pdev, const struct pci_device_id *id) pd->pdev = pdev; pd->dev = dev; - pd->base_addr = virt_addr; + pd->ioaddr = virt_addr; pd->msg_enable = smsc_debug; pd->rx_csum = true; @@ -1669,7 +1670,6 @@ smsc9420_probe(struct pci_dev *pdev, const struct pci_device_id *id) dev->netdev_ops = &smsc9420_netdev_ops; dev->ethtool_ops = &smsc9420_ethtool_ops; - dev->irq = pdev->irq; netif_napi_add(dev, &pd->napi, smsc9420_rx_poll, NAPI_WEIGHT); @@ -1727,7 +1727,7 @@ static void __devexit smsc9420_remove(struct pci_dev *pdev) pci_free_consistent(pdev, sizeof(struct smsc9420_dma_desc) * (RX_RING_SIZE + TX_RING_SIZE), pd->rx_ring, pd->rx_dma_addr); - iounmap(pd->base_addr - LAN9420_CPSR_ENDIAN_OFFSET); + iounmap(pd->ioaddr - LAN9420_CPSR_ENDIAN_OFFSET); pci_release_regions(pdev); free_netdev(dev); pci_disable_device(pdev); diff --git a/trunk/drivers/net/ethernet/stmicro/stmmac/common.h b/trunk/drivers/net/ethernet/stmicro/stmmac/common.h index 0319d640f728..bcd54d6e94fd 100644 --- a/trunk/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/trunk/drivers/net/ethernet/stmicro/stmmac/common.h @@ -97,6 +97,16 @@ struct stmmac_extra_stats { unsigned long normal_irq_n; }; +/* CSR Frequency Access Defines*/ +#define CSR_F_35M 35000000 +#define CSR_F_60M 60000000 +#define CSR_F_100M 100000000 +#define CSR_F_150M 150000000 +#define CSR_F_250M 250000000 +#define CSR_F_300M 300000000 + +#define MAC_CSR_H_FRQ_MASK 0x20 + #define HASH_TABLE_SIZE 64 #define PAUSE_TIME 0x200 @@ -137,6 +147,7 @@ struct stmmac_extra_stats { #define DMA_HW_FEAT_FLEXIPPSEN 0x04000000 /* Flexible PPS Output */ #define DMA_HW_FEAT_SAVLANINS 0x08000000 /* Source Addr or VLAN Insertion */ #define DMA_HW_FEAT_ACTPHYIF 0x70000000 /* Active/selected PHY interface */ +#define DEFAULT_DMA_PBL 8 enum rx_frame_status { /* IPC status */ good_frame = 0, @@ -228,7 +239,7 @@ struct stmmac_desc_ops { int (*get_rx_owner) (struct dma_desc *p); void (*set_rx_owner) (struct dma_desc *p); /* Get the receive frame size */ - int (*get_rx_frame_len) (struct dma_desc *p); + int (*get_rx_frame_len) (struct dma_desc *p, int rx_coe_type); /* Return the reception status looking at the RDES1 */ int (*rx_status) (void *data, struct stmmac_extra_stats *x, struct dma_desc *p); @@ -236,7 +247,8 @@ struct stmmac_desc_ops { struct stmmac_dma_ops { /* DMA core initialization */ - int (*init) (void __iomem *ioaddr, int pbl, u32 dma_tx, u32 dma_rx); + int (*init) (void __iomem *ioaddr, int pbl, int fb, int mb, + int burst_len, u32 dma_tx, u32 dma_rx); /* Dump DMA registers */ void (*dump_regs) (void __iomem *ioaddr); /* Set tx/rx threshold in the csr6 register @@ -261,14 +273,14 @@ struct stmmac_dma_ops { struct stmmac_ops { /* MAC core initialization */ void (*core_init) (void __iomem *ioaddr) ____cacheline_aligned; - /* Support checksum offload engine */ - int (*rx_coe) (void __iomem *ioaddr); + /* Enable and verify that the IPC module is supported */ + int (*rx_ipc) (void __iomem *ioaddr); /* Dump MAC registers */ void (*dump_regs) (void __iomem *ioaddr); /* Handle extra events on specific interrupts hw dependent */ void (*host_irq_status) (void __iomem *ioaddr); /* Multicast filter setting */ - void (*set_filter) (struct net_device *dev); + void (*set_filter) (struct net_device *dev, int id); /* Flow control setting */ void (*flow_ctrl) (void __iomem *ioaddr, unsigned int duplex, unsigned int fc, unsigned int pause_time); diff --git a/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h index cfcef0ea0fa5..23478bf4ed7a 100644 --- a/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h +++ b/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h @@ -61,9 +61,11 @@ enum power_event { }; /* GMAC HW ADDR regs */ -#define GMAC_ADDR_HIGH(reg) (0x00000040+(reg * 8)) -#define GMAC_ADDR_LOW(reg) (0x00000044+(reg * 8)) -#define GMAC_MAX_UNICAST_ADDRESSES 16 +#define GMAC_ADDR_HIGH(reg) (((reg > 15) ? 0x00000800 : 0x00000040) + \ + (reg * 8)) +#define GMAC_ADDR_LOW(reg) (((reg > 15) ? 0x00000804 : 0x00000044) + \ + (reg * 8)) +#define GMAC_MAX_PERFECT_ADDRESSES 32 #define GMAC_AN_CTRL 0x000000c0 /* AN control */ #define GMAC_AN_STATUS 0x000000c4 /* AN status */ @@ -139,10 +141,11 @@ enum rx_tx_priority_ratio { }; #define DMA_BUS_MODE_FB 0x00010000 /* Fixed burst */ +#define DMA_BUS_MODE_MB 0x04000000 /* Mixed burst */ #define DMA_BUS_MODE_RPBL_MASK 0x003e0000 /* Rx-Programmable Burst Len */ #define DMA_BUS_MODE_RPBL_SHIFT 17 #define DMA_BUS_MODE_USP 0x00800000 -#define DMA_BUS_MODE_4PBL 0x01000000 +#define DMA_BUS_MODE_PBL 0x01000000 #define DMA_BUS_MODE_AAL 0x02000000 /* DMA CRS Control and Status Register Mapping */ @@ -205,4 +208,7 @@ enum rtc_control { #define GMAC_MMC_TX_INTR 0x108 #define GMAC_MMC_RX_CSUM_OFFLOAD 0x208 +/* Synopsys Core versions */ +#define DWMAC_CORE_3_40 34 + extern const struct stmmac_dma_ops dwmac1000_dma_ops; diff --git a/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c index b1c48b975945..b5e4d02f15c9 100644 --- a/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c +++ b/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c @@ -46,7 +46,7 @@ static void dwmac1000_core_init(void __iomem *ioaddr) #endif } -static int dwmac1000_rx_coe_supported(void __iomem *ioaddr) +static int dwmac1000_rx_ipc_enable(void __iomem *ioaddr) { u32 value = readl(ioaddr + GMAC_CONTROL); @@ -84,10 +84,11 @@ static void dwmac1000_get_umac_addr(void __iomem *ioaddr, unsigned char *addr, GMAC_ADDR_LOW(reg_n)); } -static void dwmac1000_set_filter(struct net_device *dev) +static void dwmac1000_set_filter(struct net_device *dev, int id) { void __iomem *ioaddr = (void __iomem *) dev->base_addr; unsigned int value = 0; + unsigned int perfect_addr_number; CHIP_DBG(KERN_INFO "%s: # mcasts %d, # unicast %d\n", __func__, netdev_mc_count(dev), netdev_uc_count(dev)); @@ -121,8 +122,14 @@ static void dwmac1000_set_filter(struct net_device *dev) writel(mc_filter[1], ioaddr + GMAC_HASH_HIGH); } + /* Extra 16 regs are available in cores newer than the 3.40. */ + if (id > DWMAC_CORE_3_40) + perfect_addr_number = GMAC_MAX_PERFECT_ADDRESSES; + else + perfect_addr_number = GMAC_MAX_PERFECT_ADDRESSES / 2; + /* Handle multiple unicast addresses (perfect filtering)*/ - if (netdev_uc_count(dev) > GMAC_MAX_UNICAST_ADDRESSES) + if (netdev_uc_count(dev) > perfect_addr_number) /* Switch to promiscuous mode is more than 16 addrs are required */ value |= GMAC_FRAME_FILTER_PR; @@ -211,7 +218,7 @@ static void dwmac1000_irq_status(void __iomem *ioaddr) static const struct stmmac_ops dwmac1000_ops = { .core_init = dwmac1000_core_init, - .rx_coe = dwmac1000_rx_coe_supported, + .rx_ipc = dwmac1000_rx_ipc_enable, .dump_regs = dwmac1000_dump_regs, .host_irq_status = dwmac1000_irq_status, .set_filter = dwmac1000_set_filter, diff --git a/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c index 4d5402a1d262..033500090f55 100644 --- a/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c +++ b/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c @@ -30,8 +30,8 @@ #include "dwmac1000.h" #include "dwmac_dma.h" -static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, u32 dma_tx, - u32 dma_rx) +static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb, + int mb, int burst_len, u32 dma_tx, u32 dma_rx) { u32 value = readl(ioaddr + DMA_BUS_MODE); int limit; @@ -48,15 +48,51 @@ static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, u32 dma_tx, if (limit < 0) return -EBUSY; - value = /* DMA_BUS_MODE_FB | */ DMA_BUS_MODE_4PBL | - ((pbl << DMA_BUS_MODE_PBL_SHIFT) | - (pbl << DMA_BUS_MODE_RPBL_SHIFT)); + /* + * Set the DMA PBL (Programmable Burst Length) mode + * Before stmmac core 3.50 this mode bit was 4xPBL, and + * post 3.5 mode bit acts as 8*PBL. + * For core rev < 3.5, when the core is set for 4xPBL mode, the + * DMA transfers the data in 4, 8, 16, 32, 64 & 128 beats + * depending on pbl value. + * For core rev > 3.5, when the core is set for 8xPBL mode, the + * DMA transfers the data in 8, 16, 32, 64, 128 & 256 beats + * depending on pbl value. + */ + value = DMA_BUS_MODE_PBL | ((pbl << DMA_BUS_MODE_PBL_SHIFT) | + (pbl << DMA_BUS_MODE_RPBL_SHIFT)); + + /* Set the Fixed burst mode */ + if (fb) + value |= DMA_BUS_MODE_FB; + + /* Mixed Burst has no effect when fb is set */ + if (mb) + value |= DMA_BUS_MODE_MB; #ifdef CONFIG_STMMAC_DA value |= DMA_BUS_MODE_DA; /* Rx has priority over tx */ #endif writel(value, ioaddr + DMA_BUS_MODE); + /* In case of GMAC AXI configuration, program the DMA_AXI_BUS_MODE + * for supported bursts. + * + * Note: This is applicable only for revision GMACv3.61a. For + * older version this register is reserved and shall have no + * effect. + * + * Note: + * For Fixed Burst Mode: if we directly write 0xFF to this + * register using the configurations pass from platform code, + * this would ensure that all bursts supported by core are set + * and those which are not supported would remain ineffective. + * + * For Non Fixed Burst Mode: provide the maximum value of the + * burst length. Any burst equal or below the provided burst + * length would be allowed to perform. */ + writel(burst_len, ioaddr + DMA_AXI_BUS_MODE); + /* Mask interrupts by writing to CSR7 */ writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA); diff --git a/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c b/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c index 138fb8dd1e87..19e0f4eed2bc 100644 --- a/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c +++ b/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c @@ -43,11 +43,6 @@ static void dwmac100_core_init(void __iomem *ioaddr) #endif } -static int dwmac100_rx_coe_supported(void __iomem *ioaddr) -{ - return 0; -} - static void dwmac100_dump_mac_regs(void __iomem *ioaddr) { pr_info("\t----------------------------------------------\n" @@ -72,6 +67,11 @@ static void dwmac100_dump_mac_regs(void __iomem *ioaddr) readl(ioaddr + MAC_VLAN2)); } +static int dwmac100_rx_ipc_enable(void __iomem *ioaddr) +{ + return 0; +} + static void dwmac100_irq_status(void __iomem *ioaddr) { return; @@ -89,7 +89,7 @@ static void dwmac100_get_umac_addr(void __iomem *ioaddr, unsigned char *addr, stmmac_get_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW); } -static void dwmac100_set_filter(struct net_device *dev) +static void dwmac100_set_filter(struct net_device *dev, int id) { void __iomem *ioaddr = (void __iomem *) dev->base_addr; u32 value = readl(ioaddr + MAC_CONTROL); @@ -160,7 +160,7 @@ static void dwmac100_pmt(void __iomem *ioaddr, unsigned long mode) static const struct stmmac_ops dwmac100_ops = { .core_init = dwmac100_core_init, - .rx_coe = dwmac100_rx_coe_supported, + .rx_ipc = dwmac100_rx_ipc_enable, .dump_regs = dwmac100_dump_mac_regs, .host_irq_status = dwmac100_irq_status, .set_filter = dwmac100_set_filter, diff --git a/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c b/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c index bc17fd08b55d..c2b4d55a79b6 100644 --- a/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c +++ b/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c @@ -32,8 +32,8 @@ #include "dwmac100.h" #include "dwmac_dma.h" -static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, u32 dma_tx, - u32 dma_rx) +static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, int fb, + int mb, int burst_len, u32 dma_tx, u32 dma_rx) { u32 value = readl(ioaddr + DMA_BUS_MODE); int limit; @@ -52,7 +52,7 @@ static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, u32 dma_tx, /* Enable Application Access by writing to DMA CSR0 */ writel(DMA_BUS_MODE_DEFAULT | (pbl << DMA_BUS_MODE_PBL_SHIFT), - ioaddr + DMA_BUS_MODE); + ioaddr + DMA_BUS_MODE); /* Mask interrupts by writing to CSR7 */ writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA); diff --git a/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h b/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h index 437edacd602e..6e0360f9cfde 100644 --- a/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h +++ b/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h @@ -32,6 +32,7 @@ #define DMA_CONTROL 0x00001018 /* Ctrl (Operational Mode) */ #define DMA_INTR_ENA 0x0000101c /* Interrupt Enable */ #define DMA_MISSED_FRAME_CTR 0x00001020 /* Missed Frame Counter */ +#define DMA_AXI_BUS_MODE 0x00001028 /* AXI Bus Mode */ #define DMA_CUR_TX_BUF_ADDR 0x00001050 /* Current Host Tx Buffer */ #define DMA_CUR_RX_BUF_ADDR 0x00001054 /* Current Host Rx Buffer */ #define DMA_HW_FEATURE 0x00001058 /* HW Feature Register */ diff --git a/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c index f20aa12931d0..4e0e18a44fcc 100644 --- a/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c +++ b/trunk/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c @@ -31,6 +31,8 @@ #define DWMAC_LIB_DBG(fmt, args...) do { } while (0) #endif +#define GMAC_HI_REG_AE 0x80000000 + /* CSR1 enables the transmit DMA to check for new descriptor */ void dwmac_enable_dma_transmission(void __iomem *ioaddr) { @@ -233,7 +235,11 @@ void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6], unsigned long data; data = (addr[5] << 8) | addr[4]; - writel(data, ioaddr + high); + /* For MAC Addr registers se have to set the Address Enable (AE) + * bit that has no effect on the High Reg 0 where the bit 31 (MO) + * is RO. + */ + writel(data | GMAC_HI_REG_AE, ioaddr + high); data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; writel(data, ioaddr + low); } diff --git a/trunk/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/trunk/drivers/net/ethernet/stmicro/stmmac/enh_desc.c index ad1b627f8ec2..2fc8ef95f97a 100644 --- a/trunk/drivers/net/ethernet/stmicro/stmmac/enh_desc.c +++ b/trunk/drivers/net/ethernet/stmicro/stmmac/enh_desc.c @@ -22,6 +22,7 @@ Author: Giuseppe Cavallaro *******************************************************************************/ +#include #include "common.h" #include "descs_com.h" @@ -309,9 +310,17 @@ static void enh_desc_close_tx_desc(struct dma_desc *p) p->des01.etx.interrupt = 1; } -static int enh_desc_get_rx_frame_len(struct dma_desc *p) +static int enh_desc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type) { - return p->des01.erx.frame_length; + /* The type-1 checksum offload engines append the checksum at + * the end of frame and the two bytes of checksum are added in + * the length. + * Adjust for that in the framelen for type-1 checksum offload + * engines. */ + if (rx_coe_type == STMMAC_RX_COE_TYPE1) + return p->des01.erx.frame_length - 2; + else + return p->des01.erx.frame_length; } const struct stmmac_desc_ops enh_desc_ops = { diff --git a/trunk/drivers/net/ethernet/stmicro/stmmac/norm_desc.c b/trunk/drivers/net/ethernet/stmicro/stmmac/norm_desc.c index 25953bb45a73..68962c549a2d 100644 --- a/trunk/drivers/net/ethernet/stmicro/stmmac/norm_desc.c +++ b/trunk/drivers/net/ethernet/stmicro/stmmac/norm_desc.c @@ -22,6 +22,7 @@ Author: Giuseppe Cavallaro *******************************************************************************/ +#include #include "common.h" #include "descs_com.h" @@ -201,9 +202,17 @@ static void ndesc_close_tx_desc(struct dma_desc *p) p->des01.tx.interrupt = 1; } -static int ndesc_get_rx_frame_len(struct dma_desc *p) +static int ndesc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type) { - return p->des01.rx.frame_length; + /* The type-1 checksum offload engines append the checksum at + * the end of frame and the two bytes of checksum are added in + * the length. + * Adjust for that in the framelen for type-1 checksum offload + * engines. */ + if (rx_coe_type == STMMAC_RX_COE_TYPE1) + return p->des01.rx.frame_length - 2; + else + return p->des01.rx.frame_length; } const struct stmmac_desc_ops ndesc_ops = { diff --git a/trunk/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/trunk/drivers/net/ethernet/stmicro/stmmac/stmmac.h index b4b095fdcf29..6b5d060ee9de 100644 --- a/trunk/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/trunk/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -21,7 +21,9 @@ *******************************************************************************/ #define STMMAC_RESOURCE_NAME "stmmaceth" -#define DRV_MODULE_VERSION "Feb_2012" +#define DRV_MODULE_VERSION "March_2012" + +#include #include #include #include "common.h" @@ -56,8 +58,6 @@ struct stmmac_priv { struct stmmac_extra_stats xstats; struct napi_struct napi; - - int rx_coe; int no_csum_insertion; struct phy_device *phydev; @@ -81,6 +81,11 @@ struct stmmac_priv { struct stmmac_counters mmc; struct dma_features dma_cap; int hw_cap_support; +#ifdef CONFIG_HAVE_CLK + struct clk *stmmac_clk; +#endif + int clk_csr; + int synopsys_id; }; extern int phyaddr; @@ -99,3 +104,42 @@ int stmmac_dvr_remove(struct net_device *ndev); struct stmmac_priv *stmmac_dvr_probe(struct device *device, struct plat_stmmacenet_data *plat_dat, void __iomem *addr); + +#ifdef CONFIG_HAVE_CLK +static inline int stmmac_clk_enable(struct stmmac_priv *priv) +{ + if (!IS_ERR(priv->stmmac_clk)) + return clk_enable(priv->stmmac_clk); + + return 0; +} + +static inline void stmmac_clk_disable(struct stmmac_priv *priv) +{ + if (IS_ERR(priv->stmmac_clk)) + return; + + clk_disable(priv->stmmac_clk); +} +static inline int stmmac_clk_get(struct stmmac_priv *priv) +{ + priv->stmmac_clk = clk_get(priv->device, NULL); + + if (IS_ERR(priv->stmmac_clk)) + return PTR_ERR(priv->stmmac_clk); + + return 0; +} +#else +static inline int stmmac_clk_enable(struct stmmac_priv *priv) +{ + return 0; +} +static inline void stmmac_clk_disable(struct stmmac_priv *priv) +{ +} +static inline int stmmac_clk_get(struct stmmac_priv *priv) +{ + return 0; +} +#endif /* CONFIG_HAVE_CLK */ diff --git a/trunk/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/trunk/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index f98e1511660f..ce431846fc6f 100644 --- a/trunk/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/trunk/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -481,6 +481,7 @@ static const struct ethtool_ops stmmac_ethtool_ops = { .get_wol = stmmac_get_wol, .set_wol = stmmac_set_wol, .get_sset_count = stmmac_get_sset_count, + .get_ts_info = ethtool_op_get_ts_info, }; void stmmac_set_ethtool_ops(struct net_device *netdev) diff --git a/trunk/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/trunk/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 48d56da62f08..70966330f44e 100644 --- a/trunk/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/trunk/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -163,6 +163,38 @@ static void stmmac_verify_args(void) pause = PAUSE_TIME; } +static void stmmac_clk_csr_set(struct stmmac_priv *priv) +{ +#ifdef CONFIG_HAVE_CLK + u32 clk_rate; + + if (IS_ERR(priv->stmmac_clk)) + return; + + clk_rate = clk_get_rate(priv->stmmac_clk); + + /* Platform provided default clk_csr would be assumed valid + * for all other cases except for the below mentioned ones. */ + if (!(priv->clk_csr & MAC_CSR_H_FRQ_MASK)) { + if (clk_rate < CSR_F_35M) + priv->clk_csr = STMMAC_CSR_20_35M; + else if ((clk_rate >= CSR_F_35M) && (clk_rate < CSR_F_60M)) + priv->clk_csr = STMMAC_CSR_35_60M; + else if ((clk_rate >= CSR_F_60M) && (clk_rate < CSR_F_100M)) + priv->clk_csr = STMMAC_CSR_60_100M; + else if ((clk_rate >= CSR_F_100M) && (clk_rate < CSR_F_150M)) + priv->clk_csr = STMMAC_CSR_100_150M; + else if ((clk_rate >= CSR_F_150M) && (clk_rate < CSR_F_250M)) + priv->clk_csr = STMMAC_CSR_150_250M; + else if ((clk_rate >= CSR_F_250M) && (clk_rate < CSR_F_300M)) + priv->clk_csr = STMMAC_CSR_250_300M; + } /* For values higher than the IEEE 802.3 specified frequency + * we can not estimate the proper divider as it is not known + * the frequency of clk_csr_i. So we do not change the default + * divider. */ +#endif +} + #if defined(STMMAC_XMIT_DEBUG) || defined(STMMAC_RX_DEBUG) static void print_pkt(unsigned char *buf, int len) { @@ -307,7 +339,13 @@ static int stmmac_init_phy(struct net_device *dev) priv->speed = 0; priv->oldduplex = -1; - snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x", priv->plat->bus_id); + if (priv->plat->phy_bus_name) + snprintf(bus_id, MII_BUS_ID_SIZE, "%s-%x", + priv->plat->phy_bus_name, priv->plat->bus_id); + else + snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x", + priv->plat->bus_id); + snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id, priv->plat->phy_addr); pr_debug("stmmac_init_phy: trying to attach to %s\n", phy_id); @@ -884,6 +922,26 @@ static void stmmac_check_ether_addr(struct stmmac_priv *priv) priv->dev->dev_addr); } +static int stmmac_init_dma_engine(struct stmmac_priv *priv) +{ + int pbl = DEFAULT_DMA_PBL, fixed_burst = 0, burst_len = 0; + int mixed_burst = 0; + + /* Some DMA parameters can be passed from the platform; + * in case of these are not passed we keep a default + * (good for all the chips) and init the DMA! */ + if (priv->plat->dma_cfg) { + pbl = priv->plat->dma_cfg->pbl; + fixed_burst = priv->plat->dma_cfg->fixed_burst; + mixed_burst = priv->plat->dma_cfg->mixed_burst; + burst_len = priv->plat->dma_cfg->burst_len; + } + + return priv->hw->dma->init(priv->ioaddr, pbl, fixed_burst, mixed_burst, + burst_len, priv->dma_tx_phy, + priv->dma_rx_phy); +} + /** * stmmac_open - open entry point of the driver * @dev : pointer to the device structure. @@ -898,16 +956,6 @@ static int stmmac_open(struct net_device *dev) struct stmmac_priv *priv = netdev_priv(dev); int ret; - stmmac_check_ether_addr(priv); - - /* MDIO bus Registration */ - ret = stmmac_mdio_register(dev); - if (ret < 0) { - pr_debug("%s: MDIO bus (id: %d) registration failed", - __func__, priv->plat->bus_id); - return ret; - } - #ifdef CONFIG_STMMAC_TIMER priv->tm = kzalloc(sizeof(struct stmmac_timer *), GFP_KERNEL); if (unlikely(priv->tm == NULL)) @@ -925,6 +973,10 @@ static int stmmac_open(struct net_device *dev) } else priv->tm->enable = 1; #endif + stmmac_clk_enable(priv); + + stmmac_check_ether_addr(priv); + ret = stmmac_init_phy(dev); if (unlikely(ret)) { pr_err("%s: Cannot attach to PHY (error: %d)\n", __func__, ret); @@ -938,8 +990,7 @@ static int stmmac_open(struct net_device *dev) init_dma_desc_rings(dev); /* DMA initialization and SW reset */ - ret = priv->hw->dma->init(priv->ioaddr, priv->plat->pbl, - priv->dma_tx_phy, priv->dma_rx_phy); + ret = stmmac_init_dma_engine(priv); if (ret < 0) { pr_err("%s: DMA initialization failed\n", __func__); goto open_error; @@ -1026,6 +1077,8 @@ static int stmmac_open(struct net_device *dev) if (priv->phydev) phy_disconnect(priv->phydev); + stmmac_clk_disable(priv); + return ret; } @@ -1077,7 +1130,7 @@ static int stmmac_release(struct net_device *dev) #ifdef CONFIG_STMMAC_DEBUG_FS stmmac_exit_fs(); #endif - stmmac_mdio_unregister(dev); + stmmac_clk_disable(priv); return 0; } @@ -1276,7 +1329,8 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit) struct sk_buff *skb; int frame_len; - frame_len = priv->hw->desc->get_rx_frame_len(p); + frame_len = priv->hw->desc->get_rx_frame_len(p, + priv->plat->rx_coe); /* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3 * Type frames (LLC/LLC-SNAP) */ if (unlikely(status != llc_snap)) @@ -1312,7 +1366,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit) #endif skb->protocol = eth_type_trans(skb, priv->dev); - if (unlikely(!priv->rx_coe)) { + if (unlikely(!priv->plat->rx_coe)) { /* No RX COE for old mac10/100 devices */ skb_checksum_none_assert(skb); netif_receive_skb(skb); @@ -1413,7 +1467,7 @@ static void stmmac_set_rx_mode(struct net_device *dev) struct stmmac_priv *priv = netdev_priv(dev); spin_lock(&priv->lock); - priv->hw->mac->set_filter(dev); + priv->hw->mac->set_filter(dev, priv->synopsys_id); spin_unlock(&priv->lock); } @@ -1459,8 +1513,10 @@ static netdev_features_t stmmac_fix_features(struct net_device *dev, { struct stmmac_priv *priv = netdev_priv(dev); - if (!priv->rx_coe) + if (priv->plat->rx_coe == STMMAC_RX_COE_NONE) features &= ~NETIF_F_RXCSUM; + else if (priv->plat->rx_coe == STMMAC_RX_COE_TYPE1) + features &= ~NETIF_F_IPV6_CSUM; if (!priv->plat->tx_coe) features &= ~NETIF_F_ALL_CSUM; @@ -1584,7 +1640,7 @@ static const struct file_operations stmmac_rings_status_fops = { .open = stmmac_sysfs_ring_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = single_release, }; static int stmmac_sysfs_dma_cap_read(struct seq_file *seq, void *v) @@ -1656,7 +1712,7 @@ static const struct file_operations stmmac_dma_cap_fops = { .open = stmmac_sysfs_dma_cap_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = single_release, }; static int stmmac_init_fs(struct net_device *dev) @@ -1752,7 +1808,7 @@ static int stmmac_hw_init(struct stmmac_priv *priv) priv->hw->ring = &ring_mode_ops; /* Get and dump the chip ID */ - stmmac_get_synopsys_id(priv); + priv->synopsys_id = stmmac_get_synopsys_id(priv); /* Get the HW capability (new GMAC newer than 3.50a) */ priv->hw_cap_support = stmmac_get_hw_features(priv); @@ -1765,17 +1821,32 @@ static int stmmac_hw_init(struct stmmac_priv *priv) * register (if supported). */ priv->plat->enh_desc = priv->dma_cap.enh_desc; - priv->plat->tx_coe = priv->dma_cap.tx_coe; priv->plat->pmt = priv->dma_cap.pmt_remote_wake_up; + + priv->plat->tx_coe = priv->dma_cap.tx_coe; + + if (priv->dma_cap.rx_coe_type2) + priv->plat->rx_coe = STMMAC_RX_COE_TYPE2; + else if (priv->dma_cap.rx_coe_type1) + priv->plat->rx_coe = STMMAC_RX_COE_TYPE1; + } else pr_info(" No HW DMA feature register supported"); /* Select the enhnaced/normal descriptor structures */ stmmac_selec_desc_mode(priv); - priv->rx_coe = priv->hw->mac->rx_coe(priv->ioaddr); - if (priv->rx_coe) - pr_info(" RX Checksum Offload Engine supported\n"); + /* Enable the IPC (Checksum Offload) and check if the feature has been + * enabled during the core configuration. */ + ret = priv->hw->mac->rx_ipc(priv->ioaddr); + if (!ret) { + pr_warning(" RX IPC Checksum Offload not configured.\n"); + priv->plat->rx_coe = STMMAC_RX_COE_NONE; + } + + if (priv->plat->rx_coe) + pr_info(" RX Checksum Offload Engine supported (type %d)\n", + priv->plat->rx_coe); if (priv->plat->tx_coe) pr_info(" TX Checksum insertion supported\n"); @@ -1856,6 +1927,28 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device, goto error; } + if (stmmac_clk_get(priv)) + pr_warning("%s: warning: cannot get CSR clock\n", __func__); + + /* If a specific clk_csr value is passed from the platform + * this means that the CSR Clock Range selection cannot be + * changed at run-time and it is fixed. Viceversa the driver'll try to + * set the MDC clock dynamically according to the csr actual + * clock input. + */ + if (!priv->plat->clk_csr) + stmmac_clk_csr_set(priv); + else + priv->clk_csr = priv->plat->clk_csr; + + /* MDIO bus Registration */ + ret = stmmac_mdio_register(ndev); + if (ret < 0) { + pr_debug("%s: MDIO bus (id: %d) registration failed", + __func__, priv->plat->bus_id); + goto error; + } + return priv; error: @@ -1883,6 +1976,7 @@ int stmmac_dvr_remove(struct net_device *ndev) priv->hw->dma->stop_tx(priv->ioaddr); stmmac_set_mac(priv->ioaddr, false); + stmmac_mdio_unregister(ndev); netif_carrier_off(ndev); unregister_netdev(ndev); free_netdev(ndev); @@ -1895,6 +1989,7 @@ int stmmac_suspend(struct net_device *ndev) { struct stmmac_priv *priv = netdev_priv(ndev); int dis_ic = 0; + unsigned long flags; if (!ndev || !netif_running(ndev)) return 0; @@ -1902,7 +1997,7 @@ int stmmac_suspend(struct net_device *ndev) if (priv->phydev) phy_stop(priv->phydev); - spin_lock(&priv->lock); + spin_lock_irqsave(&priv->lock, flags); netif_device_detach(ndev); netif_stop_queue(ndev); @@ -1925,21 +2020,24 @@ int stmmac_suspend(struct net_device *ndev) /* Enable Power down mode by programming the PMT regs */ if (device_may_wakeup(priv->device)) priv->hw->mac->pmt(priv->ioaddr, priv->wolopts); - else + else { stmmac_set_mac(priv->ioaddr, false); - - spin_unlock(&priv->lock); + /* Disable clock in case of PWM is off */ + stmmac_clk_disable(priv); + } + spin_unlock_irqrestore(&priv->lock, flags); return 0; } int stmmac_resume(struct net_device *ndev) { struct stmmac_priv *priv = netdev_priv(ndev); + unsigned long flags; if (!netif_running(ndev)) return 0; - spin_lock(&priv->lock); + spin_lock_irqsave(&priv->lock, flags); /* Power Down bit, into the PM register, is cleared * automatically as soon as a magic packet or a Wake-up frame @@ -1948,6 +2046,9 @@ int stmmac_resume(struct net_device *ndev) * from another devices (e.g. serial console). */ if (device_may_wakeup(priv->device)) priv->hw->mac->pmt(priv->ioaddr, 0); + else + /* enable the clk prevously disabled */ + stmmac_clk_enable(priv); netif_device_attach(ndev); @@ -1964,7 +2065,7 @@ int stmmac_resume(struct net_device *ndev) netif_start_queue(ndev); - spin_unlock(&priv->lock); + spin_unlock_irqrestore(&priv->lock, flags); if (priv->phydev) phy_start(priv->phydev); diff --git a/trunk/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/trunk/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c index 73195329aa46..ade108232048 100644 --- a/trunk/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +++ b/trunk/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c @@ -34,6 +34,22 @@ #define MII_BUSY 0x00000001 #define MII_WRITE 0x00000002 +static int stmmac_mdio_busy_wait(void __iomem *ioaddr, unsigned int mii_addr) +{ + unsigned long curr; + unsigned long finish = jiffies + 3 * HZ; + + do { + curr = jiffies; + if (readl(ioaddr + mii_addr) & MII_BUSY) + cpu_relax(); + else + return 0; + } while (!time_after_eq(curr, finish)); + + return -EBUSY; +} + /** * stmmac_mdio_read * @bus: points to the mii_bus structure @@ -54,11 +70,15 @@ static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg) int data; u16 regValue = (((phyaddr << 11) & (0x0000F800)) | ((phyreg << 6) & (0x000007C0))); - regValue |= MII_BUSY | ((priv->plat->clk_csr & 7) << 2); + regValue |= MII_BUSY | ((priv->clk_csr & 0xF) << 2); + + if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address)) + return -EBUSY; - do {} while (((readl(priv->ioaddr + mii_address)) & MII_BUSY) == 1); writel(regValue, priv->ioaddr + mii_address); - do {} while (((readl(priv->ioaddr + mii_address)) & MII_BUSY) == 1); + + if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address)) + return -EBUSY; /* Read the data from the MII data register */ data = (int)readl(priv->ioaddr + mii_data); @@ -86,20 +106,18 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg, (((phyaddr << 11) & (0x0000F800)) | ((phyreg << 6) & (0x000007C0))) | MII_WRITE; - value |= MII_BUSY | ((priv->plat->clk_csr & 7) << 2); - + value |= MII_BUSY | ((priv->clk_csr & 0xF) << 2); /* Wait until any existing MII operation is complete */ - do {} while (((readl(priv->ioaddr + mii_address)) & MII_BUSY) == 1); + if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address)) + return -EBUSY; /* Set the MII address register to write */ writel(phydata, priv->ioaddr + mii_data); writel(value, priv->ioaddr + mii_address); /* Wait until any existing MII operation is complete */ - do {} while (((readl(priv->ioaddr + mii_address)) & MII_BUSY) == 1); - - return 0; + return stmmac_mdio_busy_wait(priv->ioaddr, mii_address); } /** diff --git a/trunk/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/trunk/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index da66ed7c3c5d..58fab5303e9c 100644 --- a/trunk/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +++ b/trunk/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c @@ -28,6 +28,7 @@ struct plat_stmmacenet_data plat_dat; struct stmmac_mdio_bus_data mdio_data; +struct stmmac_dma_cfg dma_cfg; static void stmmac_default_data(void) { @@ -35,7 +36,6 @@ static void stmmac_default_data(void) plat_dat.bus_id = 1; plat_dat.phy_addr = 0; plat_dat.interface = PHY_INTERFACE_MODE_GMII; - plat_dat.pbl = 32; plat_dat.clk_csr = 2; /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */ plat_dat.has_gmac = 1; plat_dat.force_sf_dma_mode = 1; @@ -44,6 +44,10 @@ static void stmmac_default_data(void) mdio_data.phy_reset = NULL; mdio_data.phy_mask = 0; plat_dat.mdio_bus_data = &mdio_data; + + dma_cfg.pbl = 32; + dma_cfg.burst_len = DMA_AXI_BLEN_256; + plat_dat.dma_cfg = &dma_cfg; } /** diff --git a/trunk/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/trunk/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 116529a366b2..3dd8f0803808 100644 --- a/trunk/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/trunk/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -50,7 +50,6 @@ static int __devinit stmmac_probe_config_dt(struct platform_device *pdev, * once needed on other platforms. */ if (of_device_is_compatible(np, "st,spear600-gmac")) { - plat->pbl = 8; plat->has_gmac = 1; plat->pmt = 1; } @@ -186,9 +185,6 @@ static int stmmac_pltfr_remove(struct platform_device *pdev) struct resource *res; int ret = stmmac_dvr_remove(ndev); - if (priv->plat->exit) - priv->plat->exit(pdev); - if (priv->plat->exit) priv->plat->exit(pdev); @@ -218,14 +214,26 @@ static int stmmac_pltfr_resume(struct device *dev) int stmmac_pltfr_freeze(struct device *dev) { + int ret; + struct plat_stmmacenet_data *plat_dat = dev_get_platdata(dev); struct net_device *ndev = dev_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); - return stmmac_freeze(ndev); + ret = stmmac_freeze(ndev); + if (plat_dat->exit) + plat_dat->exit(pdev); + + return ret; } int stmmac_pltfr_restore(struct device *dev) { + struct plat_stmmacenet_data *plat_dat = dev_get_platdata(dev); struct net_device *ndev = dev_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + + if (plat_dat->init) + plat_dat->init(pdev); return stmmac_restore(ndev); } diff --git a/trunk/drivers/net/ethernet/sun/niu.c b/trunk/drivers/net/ethernet/sun/niu.c index c99b3b0e2eae..703c8cce2a2c 100644 --- a/trunk/drivers/net/ethernet/sun/niu.c +++ b/trunk/drivers/net/ethernet/sun/niu.c @@ -9838,7 +9838,7 @@ static int __devinit niu_pci_init_one(struct pci_dev *pdev, goto err_out_release_parent; } } - if (err || dma_mask == DMA_BIT_MASK(32)) { + if (err) { err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (err) { dev_err(&pdev->dev, "No usable DMA configuration, aborting\n"); diff --git a/trunk/drivers/net/ethernet/sun/sungem.c b/trunk/drivers/net/ethernet/sun/sungem.c index 4ba969096717..3cf4ab755838 100644 --- a/trunk/drivers/net/ethernet/sun/sungem.c +++ b/trunk/drivers/net/ethernet/sun/sungem.c @@ -401,7 +401,7 @@ static int gem_rxmac_reset(struct gem *gp) return 1; } - udelay(5000); + mdelay(5); /* Execute RX reset command. */ writel(gp->swrst_base | GREG_SWRST_RXRST, @@ -2898,7 +2898,6 @@ static int __devinit gem_init_one(struct pci_dev *pdev, } gp->pdev = pdev; - dev->base_addr = (long) pdev; gp->dev = dev; gp->msg_enable = DEFAULT_MSG; @@ -2972,7 +2971,6 @@ static int __devinit gem_init_one(struct pci_dev *pdev, netif_napi_add(dev, &gp->napi, gem_poll, 64); dev->ethtool_ops = &gem_ethtool_ops; dev->watchdog_timeo = 5 * HZ; - dev->irq = pdev->irq; dev->dma = 0; /* Set that now, in case PM kicks in now */ diff --git a/trunk/drivers/net/ethernet/sun/sunhme.c b/trunk/drivers/net/ethernet/sun/sunhme.c index b95e7e681b38..dfc00c4683e5 100644 --- a/trunk/drivers/net/ethernet/sun/sunhme.c +++ b/trunk/drivers/net/ethernet/sun/sunhme.c @@ -2182,11 +2182,12 @@ static int happy_meal_open(struct net_device *dev) * into a single source which we register handling at probe time. */ if ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO) { - if (request_irq(dev->irq, happy_meal_interrupt, - IRQF_SHARED, dev->name, (void *)dev)) { + res = request_irq(hp->irq, happy_meal_interrupt, IRQF_SHARED, + dev->name, dev); + if (res) { HMD(("EAGAIN\n")); printk(KERN_ERR "happy_meal(SBUS): Can't order irq %d to go.\n", - dev->irq); + hp->irq); return -EAGAIN; } @@ -2199,7 +2200,7 @@ static int happy_meal_open(struct net_device *dev) spin_unlock_irq(&hp->happy_lock); if (res && ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO)) - free_irq(dev->irq, dev); + free_irq(hp->irq, dev); return res; } @@ -2221,7 +2222,7 @@ static int happy_meal_close(struct net_device *dev) * time and never unregister. */ if ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO) - free_irq(dev->irq, dev); + free_irq(hp->irq, dev); return 0; } @@ -2777,7 +2778,7 @@ static int __devinit happy_meal_sbus_probe_one(struct platform_device *op, int i dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM; dev->features |= dev->hw_features | NETIF_F_RXCSUM; - dev->irq = op->archdata.irqs[0]; + hp->irq = op->archdata.irqs[0]; #if defined(CONFIG_SBUS) && defined(CONFIG_PCI) /* Hook up SBUS register/descriptor accessors. */ @@ -2981,8 +2982,6 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, if (hme_version_printed++ == 0) printk(KERN_INFO "%s", version); - dev->base_addr = (long) pdev; - hp = netdev_priv(dev); hp->happy_dev = pdev; @@ -3087,12 +3086,11 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, init_timer(&hp->happy_timer); + hp->irq = pdev->irq; hp->dev = dev; dev->netdev_ops = &hme_netdev_ops; dev->watchdog_timeo = 5*HZ; dev->ethtool_ops = &hme_ethtool_ops; - dev->irq = pdev->irq; - dev->dma = 0; /* Happy Meal can do it all... */ dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM; diff --git a/trunk/drivers/net/ethernet/sun/sunhme.h b/trunk/drivers/net/ethernet/sun/sunhme.h index 64f278360d89..f4307654e4ae 100644 --- a/trunk/drivers/net/ethernet/sun/sunhme.h +++ b/trunk/drivers/net/ethernet/sun/sunhme.h @@ -432,6 +432,7 @@ struct happy_meal { dma_addr_t hblock_dvma; /* DVMA visible address happy block */ unsigned int happy_flags; /* Driver state flags */ + int irq; enum happy_transceiver tcvr_type; /* Kind of transceiver in use */ unsigned int happy_bursts; /* Get your mind out of the gutter */ unsigned int paddr; /* PHY address for transceiver */ diff --git a/trunk/drivers/net/ethernet/sun/sunvnet.c b/trunk/drivers/net/ethernet/sun/sunvnet.c index 38e3ae9155b7..a108db35924e 100644 --- a/trunk/drivers/net/ethernet/sun/sunvnet.c +++ b/trunk/drivers/net/ethernet/sun/sunvnet.c @@ -618,7 +618,7 @@ struct vnet_port *__tx_port_find(struct vnet *vp, struct sk_buff *skb) struct vnet_port *port; hlist_for_each_entry(port, n, hp, hash) { - if (!compare_ether_addr(port->raddr, skb->data)) + if (ether_addr_equal(port->raddr, skb->data)) return port; } port = NULL; diff --git a/trunk/drivers/net/ethernet/tehuti/tehuti.c b/trunk/drivers/net/ethernet/tehuti/tehuti.c index ad973ffc9ff3..447a6932cab3 100644 --- a/trunk/drivers/net/ethernet/tehuti/tehuti.c +++ b/trunk/drivers/net/ethernet/tehuti/tehuti.c @@ -341,8 +341,8 @@ static int bdx_fw_load(struct bdx_priv *priv) out: if (master) WRITE_REG(priv, regINIT_SEMAPHORE, 1); - if (fw) - release_firmware(fw); + + release_firmware(fw); if (rc) { netdev_err(priv->ndev, "firmware loading failed\n"); @@ -1317,7 +1317,7 @@ static void print_rxdd(struct rxd_desc *rxdd, u32 rxd_val1, u16 len, static void print_rxfd(struct rxf_desc *rxfd) { - DBG("=== RxF desc CHIP ORDER/ENDIANESS =============\n" + DBG("=== RxF desc CHIP ORDER/ENDIANNESS =============\n" "info 0x%x va_lo %u pa_lo 0x%x pa_hi 0x%x len 0x%x\n", rxfd->info, rxfd->va_lo, rxfd->pa_lo, rxfd->pa_hi, rxfd->len); } @@ -1988,10 +1988,6 @@ bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* these fields are used for info purposes only * so we can have them same for all ports of the board */ ndev->if_port = port; - ndev->base_addr = pciaddr; - ndev->mem_start = pciaddr; - ndev->mem_end = pciaddr + regionSize; - ndev->irq = pdev->irq; ndev->features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER | NETIF_F_RXCSUM diff --git a/trunk/drivers/net/ethernet/ti/davinci_cpdma.c b/trunk/drivers/net/ethernet/ti/davinci_cpdma.c index 34558766cbf0..d614c374ed9d 100644 --- a/trunk/drivers/net/ethernet/ti/davinci_cpdma.c +++ b/trunk/drivers/net/ethernet/ti/davinci_cpdma.c @@ -92,7 +92,7 @@ enum cpdma_state { CPDMA_STATE_TEARDOWN, }; -const char *cpdma_state_str[] = { "idle", "active", "teardown" }; +static const char *cpdma_state_str[] = { "idle", "active", "teardown" }; struct cpdma_ctlr { enum cpdma_state state; @@ -276,6 +276,7 @@ struct cpdma_ctlr *cpdma_ctlr_create(struct cpdma_params *params) ctlr->num_chan = CPDMA_MAX_CHANNELS; return ctlr; } +EXPORT_SYMBOL_GPL(cpdma_ctlr_create); int cpdma_ctlr_start(struct cpdma_ctlr *ctlr) { @@ -321,6 +322,7 @@ int cpdma_ctlr_start(struct cpdma_ctlr *ctlr) spin_unlock_irqrestore(&ctlr->lock, flags); return 0; } +EXPORT_SYMBOL_GPL(cpdma_ctlr_start); int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr) { @@ -351,6 +353,7 @@ int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr) spin_unlock_irqrestore(&ctlr->lock, flags); return 0; } +EXPORT_SYMBOL_GPL(cpdma_ctlr_stop); int cpdma_ctlr_dump(struct cpdma_ctlr *ctlr) { @@ -421,6 +424,7 @@ int cpdma_ctlr_dump(struct cpdma_ctlr *ctlr) spin_unlock_irqrestore(&ctlr->lock, flags); return 0; } +EXPORT_SYMBOL_GPL(cpdma_ctlr_dump); int cpdma_ctlr_destroy(struct cpdma_ctlr *ctlr) { @@ -444,6 +448,7 @@ int cpdma_ctlr_destroy(struct cpdma_ctlr *ctlr) kfree(ctlr); return ret; } +EXPORT_SYMBOL_GPL(cpdma_ctlr_destroy); int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable) { @@ -528,6 +533,7 @@ struct cpdma_chan *cpdma_chan_create(struct cpdma_ctlr *ctlr, int chan_num, err_chan_alloc: return ERR_PTR(ret); } +EXPORT_SYMBOL_GPL(cpdma_chan_create); int cpdma_chan_destroy(struct cpdma_chan *chan) { @@ -545,6 +551,7 @@ int cpdma_chan_destroy(struct cpdma_chan *chan) kfree(chan); return 0; } +EXPORT_SYMBOL_GPL(cpdma_chan_destroy); int cpdma_chan_get_stats(struct cpdma_chan *chan, struct cpdma_chan_stats *stats) @@ -693,6 +700,7 @@ int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data, spin_unlock_irqrestore(&chan->lock, flags); return ret; } +EXPORT_SYMBOL_GPL(cpdma_chan_submit); static void __cpdma_chan_free(struct cpdma_chan *chan, struct cpdma_desc __iomem *desc, @@ -776,6 +784,7 @@ int cpdma_chan_process(struct cpdma_chan *chan, int quota) } return used; } +EXPORT_SYMBOL_GPL(cpdma_chan_process); int cpdma_chan_start(struct cpdma_chan *chan) { @@ -803,6 +812,7 @@ int cpdma_chan_start(struct cpdma_chan *chan) spin_unlock_irqrestore(&chan->lock, flags); return 0; } +EXPORT_SYMBOL_GPL(cpdma_chan_start); int cpdma_chan_stop(struct cpdma_chan *chan) { @@ -863,6 +873,7 @@ int cpdma_chan_stop(struct cpdma_chan *chan) spin_unlock_irqrestore(&chan->lock, flags); return 0; } +EXPORT_SYMBOL_GPL(cpdma_chan_stop); int cpdma_chan_int_ctrl(struct cpdma_chan *chan, bool enable) { diff --git a/trunk/drivers/net/ethernet/ti/davinci_emac.c b/trunk/drivers/net/ethernet/ti/davinci_emac.c index 08aff1a2087c..4da93a5d7ec6 100644 --- a/trunk/drivers/net/ethernet/ti/davinci_emac.c +++ b/trunk/drivers/net/ethernet/ti/davinci_emac.c @@ -627,6 +627,7 @@ static const struct ethtool_ops ethtool_ops = { .get_link = ethtool_op_get_link, .get_coalesce = emac_get_coalesce, .set_coalesce = emac_set_coalesce, + .get_ts_info = ethtool_op_get_ts_info, }; /** diff --git a/trunk/drivers/net/ethernet/ti/tlan.c b/trunk/drivers/net/ethernet/ti/tlan.c index efd36691ce54..3e6abf0f2771 100644 --- a/trunk/drivers/net/ethernet/ti/tlan.c +++ b/trunk/drivers/net/ethernet/ti/tlan.c @@ -2545,7 +2545,7 @@ static void tlan_phy_reset(struct net_device *dev) phy = priv->phy[priv->phy_num]; - TLAN_DBG(TLAN_DEBUG_GNRL, "%s: Reseting PHY.\n", dev->name); + TLAN_DBG(TLAN_DEBUG_GNRL, "%s: Resetting PHY.\n", dev->name); tlan_mii_sync(dev->base_addr); value = MII_GC_LOOPBK | MII_GC_RESET; tlan_mii_write_reg(dev, phy, MII_GEN_CTL, value); diff --git a/trunk/drivers/net/ethernet/tile/tilepro.c b/trunk/drivers/net/ethernet/tile/tilepro.c index 3d501ec7fad7..96070e9b50dc 100644 --- a/trunk/drivers/net/ethernet/tile/tilepro.c +++ b/trunk/drivers/net/ethernet/tile/tilepro.c @@ -843,7 +843,7 @@ static bool tile_net_poll_aux(struct tile_net_cpu *info, int index) if (!is_multicast_ether_addr(buf)) { /* Filter packets not for our address. */ const u8 *mine = dev->dev_addr; - filter = compare_ether_addr(mine, buf); + filter = !ether_addr_equal(mine, buf); } } diff --git a/trunk/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c b/trunk/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c index 5c14f82c4954..961c8321451f 100644 --- a/trunk/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c +++ b/trunk/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c @@ -1590,8 +1590,8 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl) found = 0; oldest = NULL; list_for_each_entry(target, &wl->network_list, list) { - if (!compare_ether_addr(&target->hwinfo->bssid[2], - &scan_info->bssid[2])) { + if (ether_addr_equal(&target->hwinfo->bssid[2], + &scan_info->bssid[2])) { found = 1; pr_debug("%s: same BBS found scanned list\n", __func__); @@ -1691,8 +1691,8 @@ struct gelic_wl_scan_info *gelic_wl_find_best_bss(struct gelic_wl_info *wl) /* If bss specified, check it only */ if (test_bit(GELIC_WL_STAT_BSSID_SET, &wl->stat)) { - if (!compare_ether_addr(&scan_info->hwinfo->bssid[2], - wl->bssid)) { + if (ether_addr_equal(&scan_info->hwinfo->bssid[2], + wl->bssid)) { best_bss = scan_info; pr_debug("%s: bssid matched\n", __func__); break; diff --git a/trunk/drivers/net/ethernet/via/via-rhine.c b/trunk/drivers/net/ethernet/via/via-rhine.c index fcfa01f7ceb6..0459c096629f 100644 --- a/trunk/drivers/net/ethernet/via/via-rhine.c +++ b/trunk/drivers/net/ethernet/via/via-rhine.c @@ -689,9 +689,12 @@ static void __devinit rhine_reload_eeprom(long pioaddr, struct net_device *dev) #ifdef CONFIG_NET_POLL_CONTROLLER static void rhine_poll(struct net_device *dev) { - disable_irq(dev->irq); - rhine_interrupt(dev->irq, (void *)dev); - enable_irq(dev->irq); + struct rhine_private *rp = netdev_priv(dev); + const int irq = rp->pdev->irq; + + disable_irq(irq); + rhine_interrupt(irq, dev); + enable_irq(irq); } #endif @@ -972,7 +975,6 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, } #endif /* USE_MMIO */ - dev->base_addr = (unsigned long)ioaddr; rp->base = ioaddr; /* Get chip registers into a sane state */ @@ -995,8 +997,6 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, if (!phy_id) phy_id = ioread8(ioaddr + 0x6C); - dev->irq = pdev->irq; - spin_lock_init(&rp->lock); mutex_init(&rp->task_lock); INIT_WORK(&rp->reset_task, rhine_reset_task); diff --git a/trunk/drivers/net/ethernet/via/via-velocity.c b/trunk/drivers/net/ethernet/via/via-velocity.c index 8a5d7c100a5e..ea3e0a21ba74 100644 --- a/trunk/drivers/net/ethernet/via/via-velocity.c +++ b/trunk/drivers/net/ethernet/via/via-velocity.c @@ -2488,8 +2488,8 @@ static int velocity_close(struct net_device *dev) if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) velocity_get_ip(vptr); - if (dev->irq != 0) - free_irq(dev->irq, dev); + + free_irq(vptr->pdev->irq, dev); velocity_free_rings(vptr); @@ -2755,8 +2755,6 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi if (ret < 0) goto err_free_dev; - dev->irq = pdev->irq; - ret = velocity_get_pci_info(vptr, pdev); if (ret < 0) { /* error message already printed */ @@ -2779,8 +2777,6 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi mac_wol_reset(regs); - dev->base_addr = vptr->ioaddr; - for (i = 0; i < 6; i++) dev->dev_addr[i] = readb(®s->PAR[i]); @@ -2806,7 +2802,6 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs); - dev->irq = pdev->irq; dev->netdev_ops = &velocity_netdev_ops; dev->ethtool_ops = &velocity_ethtool_ops; netif_napi_add(dev, &vptr->napi, velocity_poll, VELOCITY_NAPI_WEIGHT); diff --git a/trunk/drivers/net/ethernet/wiznet/Kconfig b/trunk/drivers/net/ethernet/wiznet/Kconfig new file mode 100644 index 000000000000..cb18043f5830 --- /dev/null +++ b/trunk/drivers/net/ethernet/wiznet/Kconfig @@ -0,0 +1,73 @@ +# +# WIZnet devices configuration +# + +config NET_VENDOR_WIZNET + bool "WIZnet devices" + default y + ---help--- + If you have a network (Ethernet) card belonging to this class, say Y + and read the Ethernet-HOWTO, available from + . + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about WIZnet devices. If you say Y, you will be asked + for your specific card in the following questions. + +if NET_VENDOR_WIZNET + +config WIZNET_W5100 + tristate "WIZnet W5100 Ethernet support" + depends on HAS_IOMEM + ---help--- + Support for WIZnet W5100 chips. + + W5100 is a single chip with integrated 10/100 Ethernet MAC, + PHY and hardware TCP/IP stack, but this driver is limited to + the MAC and PHY functions only, onchip TCP/IP is unused. + + To compile this driver as a module, choose M here: the module + will be called w5100. + +config WIZNET_W5300 + tristate "WIZnet W5300 Ethernet support" + depends on HAS_IOMEM + ---help--- + Support for WIZnet W5300 chips. + + W5300 is a single chip with integrated 10/100 Ethernet MAC, + PHY and hardware TCP/IP stack, but this driver is limited to + the MAC and PHY functions only, onchip TCP/IP is unused. + + To compile this driver as a module, choose M here: the module + will be called w5300. + +choice + prompt "WIZnet interface mode" + depends on WIZNET_W5100 || WIZNET_W5300 + default WIZNET_BUS_ANY + +config WIZNET_BUS_DIRECT + bool "Direct address bus mode" + ---help--- + In direct address mode host system can directly access all registers + after mapping to Memory-Mapped I/O space. + +config WIZNET_BUS_INDIRECT + bool "Indirect address bus mode" + ---help--- + In indirect address mode host system indirectly accesses registers + using Indirect Mode Address Register and Indirect Mode Data Register, + which are directly mapped to Memory-Mapped I/O space. + +config WIZNET_BUS_ANY + bool "Select interface mode in runtime" + ---help--- + If interface mode is unknown in compile time, it can be selected + in runtime from board/platform resources configuration. + + Performance may decrease compared to explicitly selected bus mode. +endchoice + +endif # NET_VENDOR_WIZNET diff --git a/trunk/drivers/net/ethernet/wiznet/Makefile b/trunk/drivers/net/ethernet/wiznet/Makefile new file mode 100644 index 000000000000..c614535227e8 --- /dev/null +++ b/trunk/drivers/net/ethernet/wiznet/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_WIZNET_W5100) += w5100.o +obj-$(CONFIG_WIZNET_W5300) += w5300.o diff --git a/trunk/drivers/net/ethernet/wiznet/w5100.c b/trunk/drivers/net/ethernet/wiznet/w5100.c new file mode 100644 index 000000000000..a75e9ef5a4ce --- /dev/null +++ b/trunk/drivers/net/ethernet/wiznet/w5100.c @@ -0,0 +1,808 @@ +/* + * Ethernet driver for the WIZnet W5100 chip. + * + * Copyright (C) 2006-2008 WIZnet Co.,Ltd. + * Copyright (C) 2012 Mike Sinkovsky + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "w5100" +#define DRV_VERSION "2012-04-04" + +MODULE_DESCRIPTION("WIZnet W5100 Ethernet driver v"DRV_VERSION); +MODULE_AUTHOR("Mike Sinkovsky "); +MODULE_ALIAS("platform:"DRV_NAME); +MODULE_LICENSE("GPL"); + +/* + * Registers + */ +#define W5100_COMMON_REGS 0x0000 +#define W5100_MR 0x0000 /* Mode Register */ +#define MR_RST 0x80 /* S/W reset */ +#define MR_PB 0x10 /* Ping block */ +#define MR_AI 0x02 /* Address Auto-Increment */ +#define MR_IND 0x01 /* Indirect mode */ +#define W5100_SHAR 0x0009 /* Source MAC address */ +#define W5100_IR 0x0015 /* Interrupt Register */ +#define W5100_IMR 0x0016 /* Interrupt Mask Register */ +#define IR_S0 0x01 /* S0 interrupt */ +#define W5100_RTR 0x0017 /* Retry Time-value Register */ +#define RTR_DEFAULT 2000 /* =0x07d0 (2000) */ +#define W5100_RMSR 0x001a /* Receive Memory Size */ +#define W5100_TMSR 0x001b /* Transmit Memory Size */ +#define W5100_COMMON_REGS_LEN 0x0040 + +#define W5100_S0_REGS 0x0400 +#define W5100_S0_MR 0x0400 /* S0 Mode Register */ +#define S0_MR_MACRAW 0x04 /* MAC RAW mode (promiscous) */ +#define S0_MR_MACRAW_MF 0x44 /* MAC RAW mode (filtered) */ +#define W5100_S0_CR 0x0401 /* S0 Command Register */ +#define S0_CR_OPEN 0x01 /* OPEN command */ +#define S0_CR_CLOSE 0x10 /* CLOSE command */ +#define S0_CR_SEND 0x20 /* SEND command */ +#define S0_CR_RECV 0x40 /* RECV command */ +#define W5100_S0_IR 0x0402 /* S0 Interrupt Register */ +#define S0_IR_SENDOK 0x10 /* complete sending */ +#define S0_IR_RECV 0x04 /* receiving data */ +#define W5100_S0_SR 0x0403 /* S0 Status Register */ +#define S0_SR_MACRAW 0x42 /* mac raw mode */ +#define W5100_S0_TX_FSR 0x0420 /* S0 Transmit free memory size */ +#define W5100_S0_TX_RD 0x0422 /* S0 Transmit memory read pointer */ +#define W5100_S0_TX_WR 0x0424 /* S0 Transmit memory write pointer */ +#define W5100_S0_RX_RSR 0x0426 /* S0 Receive free memory size */ +#define W5100_S0_RX_RD 0x0428 /* S0 Receive memory read pointer */ +#define W5100_S0_REGS_LEN 0x0040 + +#define W5100_TX_MEM_START 0x4000 +#define W5100_TX_MEM_END 0x5fff +#define W5100_TX_MEM_MASK 0x1fff +#define W5100_RX_MEM_START 0x6000 +#define W5100_RX_MEM_END 0x7fff +#define W5100_RX_MEM_MASK 0x1fff + +/* + * Device driver private data structure + */ +struct w5100_priv { + void __iomem *base; + spinlock_t reg_lock; + bool indirect; + u8 (*read)(struct w5100_priv *priv, u16 addr); + void (*write)(struct w5100_priv *priv, u16 addr, u8 data); + u16 (*read16)(struct w5100_priv *priv, u16 addr); + void (*write16)(struct w5100_priv *priv, u16 addr, u16 data); + void (*readbuf)(struct w5100_priv *priv, u16 addr, u8 *buf, int len); + void (*writebuf)(struct w5100_priv *priv, u16 addr, u8 *buf, int len); + int irq; + int link_irq; + int link_gpio; + + struct napi_struct napi; + struct net_device *ndev; + bool promisc; + u32 msg_enable; +}; + +/************************************************************************ + * + * Lowlevel I/O functions + * + ***********************************************************************/ + +/* + * In direct address mode host system can directly access W5100 registers + * after mapping to Memory-Mapped I/O space. + * + * 0x8000 bytes are required for memory space. + */ +static inline u8 w5100_read_direct(struct w5100_priv *priv, u16 addr) +{ + return ioread8(priv->base + (addr << CONFIG_WIZNET_BUS_SHIFT)); +} + +static inline void w5100_write_direct(struct w5100_priv *priv, + u16 addr, u8 data) +{ + iowrite8(data, priv->base + (addr << CONFIG_WIZNET_BUS_SHIFT)); +} + +static u16 w5100_read16_direct(struct w5100_priv *priv, u16 addr) +{ + u16 data; + data = w5100_read_direct(priv, addr) << 8; + data |= w5100_read_direct(priv, addr + 1); + return data; +} + +static void w5100_write16_direct(struct w5100_priv *priv, u16 addr, u16 data) +{ + w5100_write_direct(priv, addr, data >> 8); + w5100_write_direct(priv, addr + 1, data); +} + +static void w5100_readbuf_direct(struct w5100_priv *priv, + u16 offset, u8 *buf, int len) +{ + u16 addr = W5100_RX_MEM_START + (offset & W5100_RX_MEM_MASK); + int i; + + for (i = 0; i < len; i++, addr++) { + if (unlikely(addr > W5100_RX_MEM_END)) + addr = W5100_RX_MEM_START; + *buf++ = w5100_read_direct(priv, addr); + } +} + +static void w5100_writebuf_direct(struct w5100_priv *priv, + u16 offset, u8 *buf, int len) +{ + u16 addr = W5100_TX_MEM_START + (offset & W5100_TX_MEM_MASK); + int i; + + for (i = 0; i < len; i++, addr++) { + if (unlikely(addr > W5100_TX_MEM_END)) + addr = W5100_TX_MEM_START; + w5100_write_direct(priv, addr, *buf++); + } +} + +/* + * In indirect address mode host system indirectly accesses registers by + * using Indirect Mode Address Register (IDM_AR) and Indirect Mode Data + * Register (IDM_DR), which are directly mapped to Memory-Mapped I/O space. + * Mode Register (MR) is directly accessible. + * + * Only 0x04 bytes are required for memory space. + */ +#define W5100_IDM_AR 0x01 /* Indirect Mode Address Register */ +#define W5100_IDM_DR 0x03 /* Indirect Mode Data Register */ + +static u8 w5100_read_indirect(struct w5100_priv *priv, u16 addr) +{ + unsigned long flags; + u8 data; + + spin_lock_irqsave(&priv->reg_lock, flags); + w5100_write16_direct(priv, W5100_IDM_AR, addr); + mmiowb(); + data = w5100_read_direct(priv, W5100_IDM_DR); + spin_unlock_irqrestore(&priv->reg_lock, flags); + + return data; +} + +static void w5100_write_indirect(struct w5100_priv *priv, u16 addr, u8 data) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + w5100_write16_direct(priv, W5100_IDM_AR, addr); + mmiowb(); + w5100_write_direct(priv, W5100_IDM_DR, data); + mmiowb(); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +static u16 w5100_read16_indirect(struct w5100_priv *priv, u16 addr) +{ + unsigned long flags; + u16 data; + + spin_lock_irqsave(&priv->reg_lock, flags); + w5100_write16_direct(priv, W5100_IDM_AR, addr); + mmiowb(); + data = w5100_read_direct(priv, W5100_IDM_DR) << 8; + data |= w5100_read_direct(priv, W5100_IDM_DR); + spin_unlock_irqrestore(&priv->reg_lock, flags); + + return data; +} + +static void w5100_write16_indirect(struct w5100_priv *priv, u16 addr, u16 data) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + w5100_write16_direct(priv, W5100_IDM_AR, addr); + mmiowb(); + w5100_write_direct(priv, W5100_IDM_DR, data >> 8); + w5100_write_direct(priv, W5100_IDM_DR, data); + mmiowb(); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +static void w5100_readbuf_indirect(struct w5100_priv *priv, + u16 offset, u8 *buf, int len) +{ + u16 addr = W5100_RX_MEM_START + (offset & W5100_RX_MEM_MASK); + unsigned long flags; + int i; + + spin_lock_irqsave(&priv->reg_lock, flags); + w5100_write16_direct(priv, W5100_IDM_AR, addr); + mmiowb(); + + for (i = 0; i < len; i++, addr++) { + if (unlikely(addr > W5100_RX_MEM_END)) { + addr = W5100_RX_MEM_START; + w5100_write16_direct(priv, W5100_IDM_AR, addr); + mmiowb(); + } + *buf++ = w5100_read_direct(priv, W5100_IDM_DR); + } + mmiowb(); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +static void w5100_writebuf_indirect(struct w5100_priv *priv, + u16 offset, u8 *buf, int len) +{ + u16 addr = W5100_TX_MEM_START + (offset & W5100_TX_MEM_MASK); + unsigned long flags; + int i; + + spin_lock_irqsave(&priv->reg_lock, flags); + w5100_write16_direct(priv, W5100_IDM_AR, addr); + mmiowb(); + + for (i = 0; i < len; i++, addr++) { + if (unlikely(addr > W5100_TX_MEM_END)) { + addr = W5100_TX_MEM_START; + w5100_write16_direct(priv, W5100_IDM_AR, addr); + mmiowb(); + } + w5100_write_direct(priv, W5100_IDM_DR, *buf++); + } + mmiowb(); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +#if defined(CONFIG_WIZNET_BUS_DIRECT) +#define w5100_read w5100_read_direct +#define w5100_write w5100_write_direct +#define w5100_read16 w5100_read16_direct +#define w5100_write16 w5100_write16_direct +#define w5100_readbuf w5100_readbuf_direct +#define w5100_writebuf w5100_writebuf_direct + +#elif defined(CONFIG_WIZNET_BUS_INDIRECT) +#define w5100_read w5100_read_indirect +#define w5100_write w5100_write_indirect +#define w5100_read16 w5100_read16_indirect +#define w5100_write16 w5100_write16_indirect +#define w5100_readbuf w5100_readbuf_indirect +#define w5100_writebuf w5100_writebuf_indirect + +#else /* CONFIG_WIZNET_BUS_ANY */ +#define w5100_read priv->read +#define w5100_write priv->write +#define w5100_read16 priv->read16 +#define w5100_write16 priv->write16 +#define w5100_readbuf priv->readbuf +#define w5100_writebuf priv->writebuf +#endif + +static int w5100_command(struct w5100_priv *priv, u16 cmd) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(100); + + w5100_write(priv, W5100_S0_CR, cmd); + mmiowb(); + + while (w5100_read(priv, W5100_S0_CR) != 0) { + if (time_after(jiffies, timeout)) + return -EIO; + cpu_relax(); + } + + return 0; +} + +static void w5100_write_macaddr(struct w5100_priv *priv) +{ + struct net_device *ndev = priv->ndev; + int i; + + for (i = 0; i < ETH_ALEN; i++) + w5100_write(priv, W5100_SHAR + i, ndev->dev_addr[i]); + mmiowb(); +} + +static void w5100_hw_reset(struct w5100_priv *priv) +{ + w5100_write_direct(priv, W5100_MR, MR_RST); + mmiowb(); + mdelay(5); + w5100_write_direct(priv, W5100_MR, priv->indirect ? + MR_PB | MR_AI | MR_IND : + MR_PB); + mmiowb(); + w5100_write(priv, W5100_IMR, 0); + w5100_write_macaddr(priv); + + /* Configure 16K of internal memory + * as 8K RX buffer and 8K TX buffer + */ + w5100_write(priv, W5100_RMSR, 0x03); + w5100_write(priv, W5100_TMSR, 0x03); + mmiowb(); +} + +static void w5100_hw_start(struct w5100_priv *priv) +{ + w5100_write(priv, W5100_S0_MR, priv->promisc ? + S0_MR_MACRAW : S0_MR_MACRAW_MF); + mmiowb(); + w5100_command(priv, S0_CR_OPEN); + w5100_write(priv, W5100_IMR, IR_S0); + mmiowb(); +} + +static void w5100_hw_close(struct w5100_priv *priv) +{ + w5100_write(priv, W5100_IMR, 0); + mmiowb(); + w5100_command(priv, S0_CR_CLOSE); +} + +/*********************************************************************** + * + * Device driver functions / callbacks + * + ***********************************************************************/ + +static void w5100_get_drvinfo(struct net_device *ndev, + struct ethtool_drvinfo *info) +{ + strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); + strlcpy(info->version, DRV_VERSION, sizeof(info->version)); + strlcpy(info->bus_info, dev_name(ndev->dev.parent), + sizeof(info->bus_info)); +} + +static u32 w5100_get_link(struct net_device *ndev) +{ + struct w5100_priv *priv = netdev_priv(ndev); + + if (gpio_is_valid(priv->link_gpio)) + return !!gpio_get_value(priv->link_gpio); + + return 1; +} + +static u32 w5100_get_msglevel(struct net_device *ndev) +{ + struct w5100_priv *priv = netdev_priv(ndev); + + return priv->msg_enable; +} + +static void w5100_set_msglevel(struct net_device *ndev, u32 value) +{ + struct w5100_priv *priv = netdev_priv(ndev); + + priv->msg_enable = value; +} + +static int w5100_get_regs_len(struct net_device *ndev) +{ + return W5100_COMMON_REGS_LEN + W5100_S0_REGS_LEN; +} + +static void w5100_get_regs(struct net_device *ndev, + struct ethtool_regs *regs, void *_buf) +{ + struct w5100_priv *priv = netdev_priv(ndev); + u8 *buf = _buf; + u16 i; + + regs->version = 1; + for (i = 0; i < W5100_COMMON_REGS_LEN; i++) + *buf++ = w5100_read(priv, W5100_COMMON_REGS + i); + for (i = 0; i < W5100_S0_REGS_LEN; i++) + *buf++ = w5100_read(priv, W5100_S0_REGS + i); +} + +static void w5100_tx_timeout(struct net_device *ndev) +{ + struct w5100_priv *priv = netdev_priv(ndev); + + netif_stop_queue(ndev); + w5100_hw_reset(priv); + w5100_hw_start(priv); + ndev->stats.tx_errors++; + ndev->trans_start = jiffies; + netif_wake_queue(ndev); +} + +static int w5100_start_tx(struct sk_buff *skb, struct net_device *ndev) +{ + struct w5100_priv *priv = netdev_priv(ndev); + u16 offset; + + netif_stop_queue(ndev); + + offset = w5100_read16(priv, W5100_S0_TX_WR); + w5100_writebuf(priv, offset, skb->data, skb->len); + w5100_write16(priv, W5100_S0_TX_WR, offset + skb->len); + mmiowb(); + ndev->stats.tx_bytes += skb->len; + ndev->stats.tx_packets++; + dev_kfree_skb(skb); + + w5100_command(priv, S0_CR_SEND); + + return NETDEV_TX_OK; +} + +static int w5100_napi_poll(struct napi_struct *napi, int budget) +{ + struct w5100_priv *priv = container_of(napi, struct w5100_priv, napi); + struct net_device *ndev = priv->ndev; + struct sk_buff *skb; + int rx_count; + u16 rx_len; + u16 offset; + u8 header[2]; + + for (rx_count = 0; rx_count < budget; rx_count++) { + u16 rx_buf_len = w5100_read16(priv, W5100_S0_RX_RSR); + if (rx_buf_len == 0) + break; + + offset = w5100_read16(priv, W5100_S0_RX_RD); + w5100_readbuf(priv, offset, header, 2); + rx_len = get_unaligned_be16(header) - 2; + + skb = netdev_alloc_skb_ip_align(ndev, rx_len); + if (unlikely(!skb)) { + w5100_write16(priv, W5100_S0_RX_RD, + offset + rx_buf_len); + w5100_command(priv, S0_CR_RECV); + ndev->stats.rx_dropped++; + return -ENOMEM; + } + + skb_put(skb, rx_len); + w5100_readbuf(priv, offset + 2, skb->data, rx_len); + w5100_write16(priv, W5100_S0_RX_RD, offset + 2 + rx_len); + mmiowb(); + w5100_command(priv, S0_CR_RECV); + skb->protocol = eth_type_trans(skb, ndev); + + netif_receive_skb(skb); + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += rx_len; + } + + if (rx_count < budget) { + w5100_write(priv, W5100_IMR, IR_S0); + mmiowb(); + napi_complete(napi); + } + + return rx_count; +} + +static irqreturn_t w5100_interrupt(int irq, void *ndev_instance) +{ + struct net_device *ndev = ndev_instance; + struct w5100_priv *priv = netdev_priv(ndev); + + int ir = w5100_read(priv, W5100_S0_IR); + if (!ir) + return IRQ_NONE; + w5100_write(priv, W5100_S0_IR, ir); + mmiowb(); + + if (ir & S0_IR_SENDOK) { + netif_dbg(priv, tx_done, ndev, "tx done\n"); + netif_wake_queue(ndev); + } + + if (ir & S0_IR_RECV) { + if (napi_schedule_prep(&priv->napi)) { + w5100_write(priv, W5100_IMR, 0); + mmiowb(); + __napi_schedule(&priv->napi); + } + } + + return IRQ_HANDLED; +} + +static irqreturn_t w5100_detect_link(int irq, void *ndev_instance) +{ + struct net_device *ndev = ndev_instance; + struct w5100_priv *priv = netdev_priv(ndev); + + if (netif_running(ndev)) { + if (gpio_get_value(priv->link_gpio) != 0) { + netif_info(priv, link, ndev, "link is up\n"); + netif_carrier_on(ndev); + } else { + netif_info(priv, link, ndev, "link is down\n"); + netif_carrier_off(ndev); + } + } + + return IRQ_HANDLED; +} + +static void w5100_set_rx_mode(struct net_device *ndev) +{ + struct w5100_priv *priv = netdev_priv(ndev); + bool set_promisc = (ndev->flags & IFF_PROMISC) != 0; + + if (priv->promisc != set_promisc) { + priv->promisc = set_promisc; + w5100_hw_start(priv); + } +} + +static int w5100_set_macaddr(struct net_device *ndev, void *addr) +{ + struct w5100_priv *priv = netdev_priv(ndev); + struct sockaddr *sock_addr = addr; + + if (!is_valid_ether_addr(sock_addr->sa_data)) + return -EADDRNOTAVAIL; + memcpy(ndev->dev_addr, sock_addr->sa_data, ETH_ALEN); + ndev->addr_assign_type &= ~NET_ADDR_RANDOM; + w5100_write_macaddr(priv); + return 0; +} + +static int w5100_open(struct net_device *ndev) +{ + struct w5100_priv *priv = netdev_priv(ndev); + + netif_info(priv, ifup, ndev, "enabling\n"); + if (!is_valid_ether_addr(ndev->dev_addr)) + return -EINVAL; + w5100_hw_start(priv); + napi_enable(&priv->napi); + netif_start_queue(ndev); + if (!gpio_is_valid(priv->link_gpio) || + gpio_get_value(priv->link_gpio) != 0) + netif_carrier_on(ndev); + return 0; +} + +static int w5100_stop(struct net_device *ndev) +{ + struct w5100_priv *priv = netdev_priv(ndev); + + netif_info(priv, ifdown, ndev, "shutting down\n"); + w5100_hw_close(priv); + netif_carrier_off(ndev); + netif_stop_queue(ndev); + napi_disable(&priv->napi); + return 0; +} + +static const struct ethtool_ops w5100_ethtool_ops = { + .get_drvinfo = w5100_get_drvinfo, + .get_msglevel = w5100_get_msglevel, + .set_msglevel = w5100_set_msglevel, + .get_link = w5100_get_link, + .get_regs_len = w5100_get_regs_len, + .get_regs = w5100_get_regs, +}; + +static const struct net_device_ops w5100_netdev_ops = { + .ndo_open = w5100_open, + .ndo_stop = w5100_stop, + .ndo_start_xmit = w5100_start_tx, + .ndo_tx_timeout = w5100_tx_timeout, + .ndo_set_rx_mode = w5100_set_rx_mode, + .ndo_set_mac_address = w5100_set_macaddr, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +}; + +static int __devinit w5100_hw_probe(struct platform_device *pdev) +{ + struct wiznet_platform_data *data = pdev->dev.platform_data; + struct net_device *ndev = platform_get_drvdata(pdev); + struct w5100_priv *priv = netdev_priv(ndev); + const char *name = netdev_name(ndev); + struct resource *mem; + int mem_size; + int irq; + int ret; + + if (data && is_valid_ether_addr(data->mac_addr)) { + memcpy(ndev->dev_addr, data->mac_addr, ETH_ALEN); + } else { + random_ether_addr(ndev->dev_addr); + ndev->addr_assign_type |= NET_ADDR_RANDOM; + } + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) + return -ENXIO; + mem_size = resource_size(mem); + if (!devm_request_mem_region(&pdev->dev, mem->start, mem_size, name)) + return -EBUSY; + priv->base = devm_ioremap(&pdev->dev, mem->start, mem_size); + if (!priv->base) + return -EBUSY; + + spin_lock_init(&priv->reg_lock); + priv->indirect = mem_size < W5100_BUS_DIRECT_SIZE; + if (priv->indirect) { + priv->read = w5100_read_indirect; + priv->write = w5100_write_indirect; + priv->read16 = w5100_read16_indirect; + priv->write16 = w5100_write16_indirect; + priv->readbuf = w5100_readbuf_indirect; + priv->writebuf = w5100_writebuf_indirect; + } else { + priv->read = w5100_read_direct; + priv->write = w5100_write_direct; + priv->read16 = w5100_read16_direct; + priv->write16 = w5100_write16_direct; + priv->readbuf = w5100_readbuf_direct; + priv->writebuf = w5100_writebuf_direct; + } + + w5100_hw_reset(priv); + if (w5100_read16(priv, W5100_RTR) != RTR_DEFAULT) + return -ENODEV; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + ret = request_irq(irq, w5100_interrupt, + IRQ_TYPE_LEVEL_LOW, name, ndev); + if (ret < 0) + return ret; + priv->irq = irq; + + priv->link_gpio = data ? data->link_gpio : -EINVAL; + if (gpio_is_valid(priv->link_gpio)) { + char *link_name = devm_kzalloc(&pdev->dev, 16, GFP_KERNEL); + if (!link_name) + return -ENOMEM; + snprintf(link_name, 16, "%s-link", name); + priv->link_irq = gpio_to_irq(priv->link_gpio); + if (request_any_context_irq(priv->link_irq, w5100_detect_link, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + link_name, priv->ndev) < 0) + priv->link_gpio = -EINVAL; + } + + netdev_info(ndev, "at 0x%llx irq %d\n", (u64)mem->start, irq); + return 0; +} + +static int __devinit w5100_probe(struct platform_device *pdev) +{ + struct w5100_priv *priv; + struct net_device *ndev; + int err; + + ndev = alloc_etherdev(sizeof(*priv)); + if (!ndev) + return -ENOMEM; + SET_NETDEV_DEV(ndev, &pdev->dev); + platform_set_drvdata(pdev, ndev); + priv = netdev_priv(ndev); + priv->ndev = ndev; + + ether_setup(ndev); + ndev->netdev_ops = &w5100_netdev_ops; + ndev->ethtool_ops = &w5100_ethtool_ops; + ndev->watchdog_timeo = HZ; + netif_napi_add(ndev, &priv->napi, w5100_napi_poll, 16); + + /* This chip doesn't support VLAN packets with normal MTU, + * so disable VLAN for this device. + */ + ndev->features |= NETIF_F_VLAN_CHALLENGED; + + err = register_netdev(ndev); + if (err < 0) + goto err_register; + + err = w5100_hw_probe(pdev); + if (err < 0) + goto err_hw_probe; + + return 0; + +err_hw_probe: + unregister_netdev(ndev); +err_register: + free_netdev(ndev); + platform_set_drvdata(pdev, NULL); + return err; +} + +static int __devexit w5100_remove(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct w5100_priv *priv = netdev_priv(ndev); + + w5100_hw_reset(priv); + free_irq(priv->irq, ndev); + if (gpio_is_valid(priv->link_gpio)) + free_irq(priv->link_irq, ndev); + + unregister_netdev(ndev); + free_netdev(ndev); + platform_set_drvdata(pdev, NULL); + return 0; +} + +#ifdef CONFIG_PM +static int w5100_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct net_device *ndev = platform_get_drvdata(pdev); + struct w5100_priv *priv = netdev_priv(ndev); + + if (netif_running(ndev)) { + netif_carrier_off(ndev); + netif_device_detach(ndev); + + w5100_hw_close(priv); + } + return 0; +} + +static int w5100_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct net_device *ndev = platform_get_drvdata(pdev); + struct w5100_priv *priv = netdev_priv(ndev); + + if (netif_running(ndev)) { + w5100_hw_reset(priv); + w5100_hw_start(priv); + + netif_device_attach(ndev); + if (!gpio_is_valid(priv->link_gpio) || + gpio_get_value(priv->link_gpio) != 0) + netif_carrier_on(ndev); + } + return 0; +} +#endif /* CONFIG_PM */ + +static SIMPLE_DEV_PM_OPS(w5100_pm_ops, w5100_suspend, w5100_resume); + +static struct platform_driver w5100_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .pm = &w5100_pm_ops, + }, + .probe = w5100_probe, + .remove = __devexit_p(w5100_remove), +}; + +module_platform_driver(w5100_driver); diff --git a/trunk/drivers/net/ethernet/wiznet/w5300.c b/trunk/drivers/net/ethernet/wiznet/w5300.c new file mode 100644 index 000000000000..3306a20ec211 --- /dev/null +++ b/trunk/drivers/net/ethernet/wiznet/w5300.c @@ -0,0 +1,720 @@ +/* + * Ethernet driver for the WIZnet W5300 chip. + * + * Copyright (C) 2008-2009 WIZnet Co.,Ltd. + * Copyright (C) 2011 Taehun Kim gmail.com> + * Copyright (C) 2012 Mike Sinkovsky + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "w5300" +#define DRV_VERSION "2012-04-04" + +MODULE_DESCRIPTION("WIZnet W5300 Ethernet driver v"DRV_VERSION); +MODULE_AUTHOR("Mike Sinkovsky "); +MODULE_ALIAS("platform:"DRV_NAME); +MODULE_LICENSE("GPL"); + +/* + * Registers + */ +#define W5300_MR 0x0000 /* Mode Register */ +#define MR_DBW (1 << 15) /* Data bus width */ +#define MR_MPF (1 << 14) /* Mac layer pause frame */ +#define MR_WDF(n) (((n)&7)<<11) /* Write data fetch time */ +#define MR_RDH (1 << 10) /* Read data hold time */ +#define MR_FS (1 << 8) /* FIFO swap */ +#define MR_RST (1 << 7) /* S/W reset */ +#define MR_PB (1 << 4) /* Ping block */ +#define MR_DBS (1 << 2) /* Data bus swap */ +#define MR_IND (1 << 0) /* Indirect mode */ +#define W5300_IR 0x0002 /* Interrupt Register */ +#define W5300_IMR 0x0004 /* Interrupt Mask Register */ +#define IR_S0 0x0001 /* S0 interrupt */ +#define W5300_SHARL 0x0008 /* Source MAC address (0123) */ +#define W5300_SHARH 0x000c /* Source MAC address (45) */ +#define W5300_TMSRL 0x0020 /* Transmit Memory Size (0123) */ +#define W5300_TMSRH 0x0024 /* Transmit Memory Size (4567) */ +#define W5300_RMSRL 0x0028 /* Receive Memory Size (0123) */ +#define W5300_RMSRH 0x002c /* Receive Memory Size (4567) */ +#define W5300_MTYPE 0x0030 /* Memory Type */ +#define W5300_IDR 0x00fe /* Chip ID register */ +#define IDR_W5300 0x5300 /* =0x5300 for WIZnet W5300 */ +#define W5300_S0_MR 0x0200 /* S0 Mode Register */ +#define S0_MR_CLOSED 0x0000 /* Close mode */ +#define S0_MR_MACRAW 0x0004 /* MAC RAW mode (promiscous) */ +#define S0_MR_MACRAW_MF 0x0044 /* MAC RAW mode (filtered) */ +#define W5300_S0_CR 0x0202 /* S0 Command Register */ +#define S0_CR_OPEN 0x0001 /* OPEN command */ +#define S0_CR_CLOSE 0x0010 /* CLOSE command */ +#define S0_CR_SEND 0x0020 /* SEND command */ +#define S0_CR_RECV 0x0040 /* RECV command */ +#define W5300_S0_IMR 0x0204 /* S0 Interrupt Mask Register */ +#define W5300_S0_IR 0x0206 /* S0 Interrupt Register */ +#define S0_IR_RECV 0x0004 /* Receive interrupt */ +#define S0_IR_SENDOK 0x0010 /* Send OK interrupt */ +#define W5300_S0_SSR 0x0208 /* S0 Socket Status Register */ +#define W5300_S0_TX_WRSR 0x0220 /* S0 TX Write Size Register */ +#define W5300_S0_TX_FSR 0x0224 /* S0 TX Free Size Register */ +#define W5300_S0_RX_RSR 0x0228 /* S0 Received data Size */ +#define W5300_S0_TX_FIFO 0x022e /* S0 Transmit FIFO */ +#define W5300_S0_RX_FIFO 0x0230 /* S0 Receive FIFO */ +#define W5300_REGS_LEN 0x0400 + +/* + * Device driver private data structure + */ +struct w5300_priv { + void __iomem *base; + spinlock_t reg_lock; + bool indirect; + u16 (*read) (struct w5300_priv *priv, u16 addr); + void (*write)(struct w5300_priv *priv, u16 addr, u16 data); + int irq; + int link_irq; + int link_gpio; + + struct napi_struct napi; + struct net_device *ndev; + bool promisc; + u32 msg_enable; +}; + +/************************************************************************ + * + * Lowlevel I/O functions + * + ***********************************************************************/ + +/* + * In direct address mode host system can directly access W5300 registers + * after mapping to Memory-Mapped I/O space. + * + * 0x400 bytes are required for memory space. + */ +static inline u16 w5300_read_direct(struct w5300_priv *priv, u16 addr) +{ + return ioread16(priv->base + (addr << CONFIG_WIZNET_BUS_SHIFT)); +} + +static inline void w5300_write_direct(struct w5300_priv *priv, + u16 addr, u16 data) +{ + iowrite16(data, priv->base + (addr << CONFIG_WIZNET_BUS_SHIFT)); +} + +/* + * In indirect address mode host system indirectly accesses registers by + * using Indirect Mode Address Register (IDM_AR) and Indirect Mode Data + * Register (IDM_DR), which are directly mapped to Memory-Mapped I/O space. + * Mode Register (MR) is directly accessible. + * + * Only 0x06 bytes are required for memory space. + */ +#define W5300_IDM_AR 0x0002 /* Indirect Mode Address */ +#define W5300_IDM_DR 0x0004 /* Indirect Mode Data */ + +static u16 w5300_read_indirect(struct w5300_priv *priv, u16 addr) +{ + unsigned long flags; + u16 data; + + spin_lock_irqsave(&priv->reg_lock, flags); + w5300_write_direct(priv, W5300_IDM_AR, addr); + mmiowb(); + data = w5300_read_direct(priv, W5300_IDM_DR); + spin_unlock_irqrestore(&priv->reg_lock, flags); + + return data; +} + +static void w5300_write_indirect(struct w5300_priv *priv, u16 addr, u16 data) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->reg_lock, flags); + w5300_write_direct(priv, W5300_IDM_AR, addr); + mmiowb(); + w5300_write_direct(priv, W5300_IDM_DR, data); + mmiowb(); + spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +#if defined(CONFIG_WIZNET_BUS_DIRECT) +#define w5300_read w5300_read_direct +#define w5300_write w5300_write_direct + +#elif defined(CONFIG_WIZNET_BUS_INDIRECT) +#define w5300_read w5300_read_indirect +#define w5300_write w5300_write_indirect + +#else /* CONFIG_WIZNET_BUS_ANY */ +#define w5300_read priv->read +#define w5300_write priv->write +#endif + +static u32 w5300_read32(struct w5300_priv *priv, u16 addr) +{ + u32 data; + data = w5300_read(priv, addr) << 16; + data |= w5300_read(priv, addr + 2); + return data; +} + +static void w5300_write32(struct w5300_priv *priv, u16 addr, u32 data) +{ + w5300_write(priv, addr, data >> 16); + w5300_write(priv, addr + 2, data); +} + +static int w5300_command(struct w5300_priv *priv, u16 cmd) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(100); + + w5300_write(priv, W5300_S0_CR, cmd); + mmiowb(); + + while (w5300_read(priv, W5300_S0_CR) != 0) { + if (time_after(jiffies, timeout)) + return -EIO; + cpu_relax(); + } + + return 0; +} + +static void w5300_read_frame(struct w5300_priv *priv, u8 *buf, int len) +{ + u16 fifo; + int i; + + for (i = 0; i < len; i += 2) { + fifo = w5300_read(priv, W5300_S0_RX_FIFO); + *buf++ = fifo >> 8; + *buf++ = fifo; + } + fifo = w5300_read(priv, W5300_S0_RX_FIFO); + fifo = w5300_read(priv, W5300_S0_RX_FIFO); +} + +static void w5300_write_frame(struct w5300_priv *priv, u8 *buf, int len) +{ + u16 fifo; + int i; + + for (i = 0; i < len; i += 2) { + fifo = *buf++ << 8; + fifo |= *buf++; + w5300_write(priv, W5300_S0_TX_FIFO, fifo); + } + w5300_write32(priv, W5300_S0_TX_WRSR, len); +} + +static void w5300_write_macaddr(struct w5300_priv *priv) +{ + struct net_device *ndev = priv->ndev; + w5300_write32(priv, W5300_SHARL, + ndev->dev_addr[0] << 24 | + ndev->dev_addr[1] << 16 | + ndev->dev_addr[2] << 8 | + ndev->dev_addr[3]); + w5300_write(priv, W5300_SHARH, + ndev->dev_addr[4] << 8 | + ndev->dev_addr[5]); + mmiowb(); +} + +static void w5300_hw_reset(struct w5300_priv *priv) +{ + w5300_write_direct(priv, W5300_MR, MR_RST); + mmiowb(); + mdelay(5); + w5300_write_direct(priv, W5300_MR, priv->indirect ? + MR_WDF(7) | MR_PB | MR_IND : + MR_WDF(7) | MR_PB); + mmiowb(); + w5300_write(priv, W5300_IMR, 0); + w5300_write_macaddr(priv); + + /* Configure 128K of internal memory + * as 64K RX fifo and 64K TX fifo + */ + w5300_write32(priv, W5300_RMSRL, 64 << 24); + w5300_write32(priv, W5300_RMSRH, 0); + w5300_write32(priv, W5300_TMSRL, 64 << 24); + w5300_write32(priv, W5300_TMSRH, 0); + w5300_write(priv, W5300_MTYPE, 0x00ff); + mmiowb(); +} + +static void w5300_hw_start(struct w5300_priv *priv) +{ + w5300_write(priv, W5300_S0_MR, priv->promisc ? + S0_MR_MACRAW : S0_MR_MACRAW_MF); + mmiowb(); + w5300_command(priv, S0_CR_OPEN); + w5300_write(priv, W5300_S0_IMR, S0_IR_RECV | S0_IR_SENDOK); + w5300_write(priv, W5300_IMR, IR_S0); + mmiowb(); +} + +static void w5300_hw_close(struct w5300_priv *priv) +{ + w5300_write(priv, W5300_IMR, 0); + mmiowb(); + w5300_command(priv, S0_CR_CLOSE); +} + +/*********************************************************************** + * + * Device driver functions / callbacks + * + ***********************************************************************/ + +static void w5300_get_drvinfo(struct net_device *ndev, + struct ethtool_drvinfo *info) +{ + strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); + strlcpy(info->version, DRV_VERSION, sizeof(info->version)); + strlcpy(info->bus_info, dev_name(ndev->dev.parent), + sizeof(info->bus_info)); +} + +static u32 w5300_get_link(struct net_device *ndev) +{ + struct w5300_priv *priv = netdev_priv(ndev); + + if (gpio_is_valid(priv->link_gpio)) + return !!gpio_get_value(priv->link_gpio); + + return 1; +} + +static u32 w5300_get_msglevel(struct net_device *ndev) +{ + struct w5300_priv *priv = netdev_priv(ndev); + + return priv->msg_enable; +} + +static void w5300_set_msglevel(struct net_device *ndev, u32 value) +{ + struct w5300_priv *priv = netdev_priv(ndev); + + priv->msg_enable = value; +} + +static int w5300_get_regs_len(struct net_device *ndev) +{ + return W5300_REGS_LEN; +} + +static void w5300_get_regs(struct net_device *ndev, + struct ethtool_regs *regs, void *_buf) +{ + struct w5300_priv *priv = netdev_priv(ndev); + u8 *buf = _buf; + u16 addr; + u16 data; + + regs->version = 1; + for (addr = 0; addr < W5300_REGS_LEN; addr += 2) { + switch (addr & 0x23f) { + case W5300_S0_TX_FIFO: /* cannot read TX_FIFO */ + case W5300_S0_RX_FIFO: /* cannot read RX_FIFO */ + data = 0xffff; + break; + default: + data = w5300_read(priv, addr); + break; + } + *buf++ = data >> 8; + *buf++ = data; + } +} + +static void w5300_tx_timeout(struct net_device *ndev) +{ + struct w5300_priv *priv = netdev_priv(ndev); + + netif_stop_queue(ndev); + w5300_hw_reset(priv); + w5300_hw_start(priv); + ndev->stats.tx_errors++; + ndev->trans_start = jiffies; + netif_wake_queue(ndev); +} + +static int w5300_start_tx(struct sk_buff *skb, struct net_device *ndev) +{ + struct w5300_priv *priv = netdev_priv(ndev); + + netif_stop_queue(ndev); + + w5300_write_frame(priv, skb->data, skb->len); + mmiowb(); + ndev->stats.tx_packets++; + ndev->stats.tx_bytes += skb->len; + dev_kfree_skb(skb); + netif_dbg(priv, tx_queued, ndev, "tx queued\n"); + + w5300_command(priv, S0_CR_SEND); + + return NETDEV_TX_OK; +} + +static int w5300_napi_poll(struct napi_struct *napi, int budget) +{ + struct w5300_priv *priv = container_of(napi, struct w5300_priv, napi); + struct net_device *ndev = priv->ndev; + struct sk_buff *skb; + int rx_count; + u16 rx_len; + + for (rx_count = 0; rx_count < budget; rx_count++) { + u32 rx_fifo_len = w5300_read32(priv, W5300_S0_RX_RSR); + if (rx_fifo_len == 0) + break; + + rx_len = w5300_read(priv, W5300_S0_RX_FIFO); + + skb = netdev_alloc_skb_ip_align(ndev, roundup(rx_len, 2)); + if (unlikely(!skb)) { + u32 i; + for (i = 0; i < rx_fifo_len; i += 2) + w5300_read(priv, W5300_S0_RX_FIFO); + ndev->stats.rx_dropped++; + return -ENOMEM; + } + + skb_put(skb, rx_len); + w5300_read_frame(priv, skb->data, rx_len); + skb->protocol = eth_type_trans(skb, ndev); + + netif_receive_skb(skb); + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += rx_len; + } + + if (rx_count < budget) { + w5300_write(priv, W5300_IMR, IR_S0); + mmiowb(); + napi_complete(napi); + } + + return rx_count; +} + +static irqreturn_t w5300_interrupt(int irq, void *ndev_instance) +{ + struct net_device *ndev = ndev_instance; + struct w5300_priv *priv = netdev_priv(ndev); + + int ir = w5300_read(priv, W5300_S0_IR); + if (!ir) + return IRQ_NONE; + w5300_write(priv, W5300_S0_IR, ir); + mmiowb(); + + if (ir & S0_IR_SENDOK) { + netif_dbg(priv, tx_done, ndev, "tx done\n"); + netif_wake_queue(ndev); + } + + if (ir & S0_IR_RECV) { + if (napi_schedule_prep(&priv->napi)) { + w5300_write(priv, W5300_IMR, 0); + mmiowb(); + __napi_schedule(&priv->napi); + } + } + + return IRQ_HANDLED; +} + +static irqreturn_t w5300_detect_link(int irq, void *ndev_instance) +{ + struct net_device *ndev = ndev_instance; + struct w5300_priv *priv = netdev_priv(ndev); + + if (netif_running(ndev)) { + if (gpio_get_value(priv->link_gpio) != 0) { + netif_info(priv, link, ndev, "link is up\n"); + netif_carrier_on(ndev); + } else { + netif_info(priv, link, ndev, "link is down\n"); + netif_carrier_off(ndev); + } + } + + return IRQ_HANDLED; +} + +static void w5300_set_rx_mode(struct net_device *ndev) +{ + struct w5300_priv *priv = netdev_priv(ndev); + bool set_promisc = (ndev->flags & IFF_PROMISC) != 0; + + if (priv->promisc != set_promisc) { + priv->promisc = set_promisc; + w5300_hw_start(priv); + } +} + +static int w5300_set_macaddr(struct net_device *ndev, void *addr) +{ + struct w5300_priv *priv = netdev_priv(ndev); + struct sockaddr *sock_addr = addr; + + if (!is_valid_ether_addr(sock_addr->sa_data)) + return -EADDRNOTAVAIL; + memcpy(ndev->dev_addr, sock_addr->sa_data, ETH_ALEN); + ndev->addr_assign_type &= ~NET_ADDR_RANDOM; + w5300_write_macaddr(priv); + return 0; +} + +static int w5300_open(struct net_device *ndev) +{ + struct w5300_priv *priv = netdev_priv(ndev); + + netif_info(priv, ifup, ndev, "enabling\n"); + if (!is_valid_ether_addr(ndev->dev_addr)) + return -EINVAL; + w5300_hw_start(priv); + napi_enable(&priv->napi); + netif_start_queue(ndev); + if (!gpio_is_valid(priv->link_gpio) || + gpio_get_value(priv->link_gpio) != 0) + netif_carrier_on(ndev); + return 0; +} + +static int w5300_stop(struct net_device *ndev) +{ + struct w5300_priv *priv = netdev_priv(ndev); + + netif_info(priv, ifdown, ndev, "shutting down\n"); + w5300_hw_close(priv); + netif_carrier_off(ndev); + netif_stop_queue(ndev); + napi_disable(&priv->napi); + return 0; +} + +static const struct ethtool_ops w5300_ethtool_ops = { + .get_drvinfo = w5300_get_drvinfo, + .get_msglevel = w5300_get_msglevel, + .set_msglevel = w5300_set_msglevel, + .get_link = w5300_get_link, + .get_regs_len = w5300_get_regs_len, + .get_regs = w5300_get_regs, +}; + +static const struct net_device_ops w5300_netdev_ops = { + .ndo_open = w5300_open, + .ndo_stop = w5300_stop, + .ndo_start_xmit = w5300_start_tx, + .ndo_tx_timeout = w5300_tx_timeout, + .ndo_set_rx_mode = w5300_set_rx_mode, + .ndo_set_mac_address = w5300_set_macaddr, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +}; + +static int __devinit w5300_hw_probe(struct platform_device *pdev) +{ + struct wiznet_platform_data *data = pdev->dev.platform_data; + struct net_device *ndev = platform_get_drvdata(pdev); + struct w5300_priv *priv = netdev_priv(ndev); + const char *name = netdev_name(ndev); + struct resource *mem; + int mem_size; + int irq; + int ret; + + if (data && is_valid_ether_addr(data->mac_addr)) { + memcpy(ndev->dev_addr, data->mac_addr, ETH_ALEN); + } else { + random_ether_addr(ndev->dev_addr); + ndev->addr_assign_type |= NET_ADDR_RANDOM; + } + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) + return -ENXIO; + mem_size = resource_size(mem); + if (!devm_request_mem_region(&pdev->dev, mem->start, mem_size, name)) + return -EBUSY; + priv->base = devm_ioremap(&pdev->dev, mem->start, mem_size); + if (!priv->base) + return -EBUSY; + + spin_lock_init(&priv->reg_lock); + priv->indirect = mem_size < W5300_BUS_DIRECT_SIZE; + if (priv->indirect) { + priv->read = w5300_read_indirect; + priv->write = w5300_write_indirect; + } else { + priv->read = w5300_read_direct; + priv->write = w5300_write_direct; + } + + w5300_hw_reset(priv); + if (w5300_read(priv, W5300_IDR) != IDR_W5300) + return -ENODEV; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + ret = request_irq(irq, w5300_interrupt, + IRQ_TYPE_LEVEL_LOW, name, ndev); + if (ret < 0) + return ret; + priv->irq = irq; + + priv->link_gpio = data ? data->link_gpio : -EINVAL; + if (gpio_is_valid(priv->link_gpio)) { + char *link_name = devm_kzalloc(&pdev->dev, 16, GFP_KERNEL); + if (!link_name) + return -ENOMEM; + snprintf(link_name, 16, "%s-link", name); + priv->link_irq = gpio_to_irq(priv->link_gpio); + if (request_any_context_irq(priv->link_irq, w5300_detect_link, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + link_name, priv->ndev) < 0) + priv->link_gpio = -EINVAL; + } + + netdev_info(ndev, "at 0x%llx irq %d\n", (u64)mem->start, irq); + return 0; +} + +static int __devinit w5300_probe(struct platform_device *pdev) +{ + struct w5300_priv *priv; + struct net_device *ndev; + int err; + + ndev = alloc_etherdev(sizeof(*priv)); + if (!ndev) + return -ENOMEM; + SET_NETDEV_DEV(ndev, &pdev->dev); + platform_set_drvdata(pdev, ndev); + priv = netdev_priv(ndev); + priv->ndev = ndev; + + ether_setup(ndev); + ndev->netdev_ops = &w5300_netdev_ops; + ndev->ethtool_ops = &w5300_ethtool_ops; + ndev->watchdog_timeo = HZ; + netif_napi_add(ndev, &priv->napi, w5300_napi_poll, 16); + + /* This chip doesn't support VLAN packets with normal MTU, + * so disable VLAN for this device. + */ + ndev->features |= NETIF_F_VLAN_CHALLENGED; + + err = register_netdev(ndev); + if (err < 0) + goto err_register; + + err = w5300_hw_probe(pdev); + if (err < 0) + goto err_hw_probe; + + return 0; + +err_hw_probe: + unregister_netdev(ndev); +err_register: + free_netdev(ndev); + platform_set_drvdata(pdev, NULL); + return err; +} + +static int __devexit w5300_remove(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct w5300_priv *priv = netdev_priv(ndev); + + w5300_hw_reset(priv); + free_irq(priv->irq, ndev); + if (gpio_is_valid(priv->link_gpio)) + free_irq(priv->link_irq, ndev); + + unregister_netdev(ndev); + free_netdev(ndev); + platform_set_drvdata(pdev, NULL); + return 0; +} + +#ifdef CONFIG_PM +static int w5300_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct net_device *ndev = platform_get_drvdata(pdev); + struct w5300_priv *priv = netdev_priv(ndev); + + if (netif_running(ndev)) { + netif_carrier_off(ndev); + netif_device_detach(ndev); + + w5300_hw_close(priv); + } + return 0; +} + +static int w5300_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct net_device *ndev = platform_get_drvdata(pdev); + struct w5300_priv *priv = netdev_priv(ndev); + + if (!netif_running(ndev)) { + w5300_hw_reset(priv); + w5300_hw_start(priv); + + netif_device_attach(ndev); + if (!gpio_is_valid(priv->link_gpio) || + gpio_get_value(priv->link_gpio) != 0) + netif_carrier_on(ndev); + } + return 0; +} +#endif /* CONFIG_PM */ + +static SIMPLE_DEV_PM_OPS(w5300_pm_ops, w5300_suspend, w5300_resume); + +static struct platform_driver w5300_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .pm = &w5300_pm_ops, + }, + .probe = w5300_probe, + .remove = __devexit_p(w5300_remove), +}; + +module_platform_driver(w5300_driver); diff --git a/trunk/drivers/net/ethernet/xilinx/ll_temac_main.c b/trunk/drivers/net/ethernet/xilinx/ll_temac_main.c index d21591a2c593..1eaf7128afee 100644 --- a/trunk/drivers/net/ethernet/xilinx/ll_temac_main.c +++ b/trunk/drivers/net/ethernet/xilinx/ll_temac_main.c @@ -1000,6 +1000,7 @@ static const struct ethtool_ops temac_ethtool_ops = { .set_settings = temac_set_settings, .nway_reset = temac_nway_reset, .get_link = ethtool_op_get_link, + .get_ts_info = ethtool_op_get_ts_info, }; static int __devinit temac_of_probe(struct platform_device *op) diff --git a/trunk/drivers/net/ethernet/xscale/Kconfig b/trunk/drivers/net/ethernet/xscale/Kconfig index cf67352cea14..3f431019e615 100644 --- a/trunk/drivers/net/ethernet/xscale/Kconfig +++ b/trunk/drivers/net/ethernet/xscale/Kconfig @@ -5,8 +5,8 @@ config NET_VENDOR_XSCALE bool "Intel XScale IXP devices" default y - depends on NET_VENDOR_INTEL && ((ARM && ARCH_IXP4XX && \ - IXP4XX_NPE && IXP4XX_QMGR) || ARCH_ENP2611) + depends on NET_VENDOR_INTEL && (ARM && ARCH_IXP4XX && \ + IXP4XX_NPE && IXP4XX_QMGR) ---help--- If you have a network (Ethernet) card belonging to this class, say Y and read the Ethernet-HOWTO, available from @@ -27,6 +27,4 @@ config IXP4XX_ETH Say Y here if you want to use built-in Ethernet ports on IXP4xx processor. -source "drivers/net/ethernet/xscale/ixp2000/Kconfig" - endif # NET_VENDOR_XSCALE diff --git a/trunk/drivers/net/ethernet/xscale/Makefile b/trunk/drivers/net/ethernet/xscale/Makefile index b195b9d7fe81..abc3b031fba7 100644 --- a/trunk/drivers/net/ethernet/xscale/Makefile +++ b/trunk/drivers/net/ethernet/xscale/Makefile @@ -2,5 +2,4 @@ # Makefile for the Intel XScale IXP device drivers. # -obj-$(CONFIG_ENP2611_MSF_NET) += ixp2000/ obj-$(CONFIG_IXP4XX_ETH) += ixp4xx_eth.o diff --git a/trunk/drivers/net/ethernet/xscale/ixp2000/Kconfig b/trunk/drivers/net/ethernet/xscale/ixp2000/Kconfig deleted file mode 100644 index 58dbc5b876bc..000000000000 --- a/trunk/drivers/net/ethernet/xscale/ixp2000/Kconfig +++ /dev/null @@ -1,6 +0,0 @@ -config ENP2611_MSF_NET - tristate "Radisys ENP2611 MSF network interface support" - depends on ARCH_ENP2611 - ---help--- - This is a driver for the MSF network interface unit in - the IXP2400 on the Radisys ENP2611 platform. diff --git a/trunk/drivers/net/ethernet/xscale/ixp2000/Makefile b/trunk/drivers/net/ethernet/xscale/ixp2000/Makefile deleted file mode 100644 index fd38351ceaa7..000000000000 --- a/trunk/drivers/net/ethernet/xscale/ixp2000/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-$(CONFIG_ENP2611_MSF_NET) += enp2611_mod.o - -enp2611_mod-objs := caleb.o enp2611.o ixp2400-msf.o ixpdev.o pm3386.o diff --git a/trunk/drivers/net/ethernet/xscale/ixp2000/caleb.c b/trunk/drivers/net/ethernet/xscale/ixp2000/caleb.c deleted file mode 100644 index 7dea5b95012c..000000000000 --- a/trunk/drivers/net/ethernet/xscale/ixp2000/caleb.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Helper functions for the SPI-3 bridge FPGA on the Radisys ENP2611 - * Copyright (C) 2004, 2005 Lennert Buytenhek - * Dedicated to Marija Kulikova. - * - * 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 "caleb.h" - -#define CALEB_IDLO 0x00 -#define CALEB_IDHI 0x01 -#define CALEB_RID 0x02 -#define CALEB_RESET 0x03 -#define CALEB_INTREN0 0x04 -#define CALEB_INTREN1 0x05 -#define CALEB_INTRSTAT0 0x06 -#define CALEB_INTRSTAT1 0x07 -#define CALEB_PORTEN 0x08 -#define CALEB_BURST 0x09 -#define CALEB_PORTPAUS 0x0A -#define CALEB_PORTPAUSD 0x0B -#define CALEB_PHY0RX 0x10 -#define CALEB_PHY1RX 0x11 -#define CALEB_PHY0TX 0x12 -#define CALEB_PHY1TX 0x13 -#define CALEB_IXPRX_HI_CNTR 0x15 -#define CALEB_PHY0RX_HI_CNTR 0x16 -#define CALEB_PHY1RX_HI_CNTR 0x17 -#define CALEB_IXPRX_CNTR 0x18 -#define CALEB_PHY0RX_CNTR 0x19 -#define CALEB_PHY1RX_CNTR 0x1A -#define CALEB_IXPTX_CNTR 0x1B -#define CALEB_PHY0TX_CNTR 0x1C -#define CALEB_PHY1TX_CNTR 0x1D -#define CALEB_DEBUG0 0x1E -#define CALEB_DEBUG1 0x1F - - -static u8 caleb_reg_read(int reg) -{ - u8 value; - - value = *((volatile u8 *)(ENP2611_CALEB_VIRT_BASE + reg)); - -// printk(KERN_INFO "caleb_reg_read(%d) = %.2x\n", reg, value); - - return value; -} - -static void caleb_reg_write(int reg, u8 value) -{ - u8 dummy; - -// printk(KERN_INFO "caleb_reg_write(%d, %.2x)\n", reg, value); - - *((volatile u8 *)(ENP2611_CALEB_VIRT_BASE + reg)) = value; - - dummy = *((volatile u8 *)ENP2611_CALEB_VIRT_BASE); - __asm__ __volatile__("mov %0, %0" : "+r" (dummy)); -} - - -void caleb_reset(void) -{ - /* - * Perform a chip reset. - */ - caleb_reg_write(CALEB_RESET, 0x02); - udelay(1); - - /* - * Enable all interrupt sources. This is needed to get - * meaningful results out of the status bits (register 6 - * and 7.) - */ - caleb_reg_write(CALEB_INTREN0, 0xff); - caleb_reg_write(CALEB_INTREN1, 0x07); - - /* - * Set RX and TX FIFO thresholds to 1.5kb. - */ - caleb_reg_write(CALEB_PHY0RX, 0x11); - caleb_reg_write(CALEB_PHY1RX, 0x11); - caleb_reg_write(CALEB_PHY0TX, 0x11); - caleb_reg_write(CALEB_PHY1TX, 0x11); - - /* - * Program SPI-3 burst size. - */ - caleb_reg_write(CALEB_BURST, 0); // 64-byte RBUF mpackets -// caleb_reg_write(CALEB_BURST, 1); // 128-byte RBUF mpackets -// caleb_reg_write(CALEB_BURST, 2); // 256-byte RBUF mpackets -} - -void caleb_enable_rx(int port) -{ - u8 temp; - - temp = caleb_reg_read(CALEB_PORTEN); - temp |= 1 << port; - caleb_reg_write(CALEB_PORTEN, temp); -} - -void caleb_disable_rx(int port) -{ - u8 temp; - - temp = caleb_reg_read(CALEB_PORTEN); - temp &= ~(1 << port); - caleb_reg_write(CALEB_PORTEN, temp); -} - -void caleb_enable_tx(int port) -{ - u8 temp; - - temp = caleb_reg_read(CALEB_PORTEN); - temp |= 1 << (port + 4); - caleb_reg_write(CALEB_PORTEN, temp); -} - -void caleb_disable_tx(int port) -{ - u8 temp; - - temp = caleb_reg_read(CALEB_PORTEN); - temp &= ~(1 << (port + 4)); - caleb_reg_write(CALEB_PORTEN, temp); -} diff --git a/trunk/drivers/net/ethernet/xscale/ixp2000/caleb.h b/trunk/drivers/net/ethernet/xscale/ixp2000/caleb.h deleted file mode 100644 index e93a1ef5b8a3..000000000000 --- a/trunk/drivers/net/ethernet/xscale/ixp2000/caleb.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Helper functions for the SPI-3 bridge FPGA on the Radisys ENP2611 - * Copyright (C) 2004, 2005 Lennert Buytenhek - * Dedicated to Marija Kulikova. - * - * 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 __CALEB_H -#define __CALEB_H - -void caleb_reset(void); -void caleb_enable_rx(int port); -void caleb_disable_rx(int port); -void caleb_enable_tx(int port); -void caleb_disable_tx(int port); - - -#endif diff --git a/trunk/drivers/net/ethernet/xscale/ixp2000/enp2611.c b/trunk/drivers/net/ethernet/xscale/ixp2000/enp2611.c deleted file mode 100644 index 34a6cfd17930..000000000000 --- a/trunk/drivers/net/ethernet/xscale/ixp2000/enp2611.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * IXP2400 MSF network device driver for the Radisys ENP2611 - * Copyright (C) 2004, 2005 Lennert Buytenhek - * Dedicated to Marija Kulikova. - * - * 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 "ixpdev.h" -#include "caleb.h" -#include "ixp2400-msf.h" -#include "pm3386.h" - -/*********************************************************************** - * The Radisys ENP2611 is a PCI form factor board with three SFP GBIC - * slots, connected via two PMC/Sierra 3386s and an SPI-3 bridge FPGA - * to the IXP2400. - * - * +-------------+ - * SFP GBIC #0 ---+ | +---------+ - * | PM3386 #0 +-------+ | - * SFP GBIC #1 ---+ | | "Caleb" | +---------+ - * +-------------+ | | | | - * | SPI-3 +---------+ IXP2400 | - * +-------------+ | bridge | | | - * SFP GBIC #2 ---+ | | FPGA | +---------+ - * | PM3386 #1 +-------+ | - * | | +---------+ - * +-------------+ - * ^ ^ ^ - * | 1.25Gbaud | 104MHz | 104MHz - * | SERDES ea. | SPI-3 ea. | SPI-3 - * - ***********************************************************************/ -static struct ixp2400_msf_parameters enp2611_msf_parameters = -{ - .rx_mode = IXP2400_RX_MODE_UTOPIA_POS | - IXP2400_RX_MODE_1x32 | - IXP2400_RX_MODE_MPHY | - IXP2400_RX_MODE_MPHY_32 | - IXP2400_RX_MODE_MPHY_POLLED_STATUS | - IXP2400_RX_MODE_MPHY_LEVEL3 | - IXP2400_RX_MODE_RBUF_SIZE_64, - - .rxclk01_multiplier = IXP2400_PLL_MULTIPLIER_16, - - .rx_poll_ports = 3, - - .rx_channel_mode = { - IXP2400_PORT_RX_MODE_MASTER | - IXP2400_PORT_RX_MODE_POS_PHY | - IXP2400_PORT_RX_MODE_POS_PHY_L3 | - IXP2400_PORT_RX_MODE_ODD_PARITY | - IXP2400_PORT_RX_MODE_2_CYCLE_DECODE, - - IXP2400_PORT_RX_MODE_MASTER | - IXP2400_PORT_RX_MODE_POS_PHY | - IXP2400_PORT_RX_MODE_POS_PHY_L3 | - IXP2400_PORT_RX_MODE_ODD_PARITY | - IXP2400_PORT_RX_MODE_2_CYCLE_DECODE, - - IXP2400_PORT_RX_MODE_MASTER | - IXP2400_PORT_RX_MODE_POS_PHY | - IXP2400_PORT_RX_MODE_POS_PHY_L3 | - IXP2400_PORT_RX_MODE_ODD_PARITY | - IXP2400_PORT_RX_MODE_2_CYCLE_DECODE, - - IXP2400_PORT_RX_MODE_MASTER | - IXP2400_PORT_RX_MODE_POS_PHY | - IXP2400_PORT_RX_MODE_POS_PHY_L3 | - IXP2400_PORT_RX_MODE_ODD_PARITY | - IXP2400_PORT_RX_MODE_2_CYCLE_DECODE - }, - - .tx_mode = IXP2400_TX_MODE_UTOPIA_POS | - IXP2400_TX_MODE_1x32 | - IXP2400_TX_MODE_MPHY | - IXP2400_TX_MODE_MPHY_32 | - IXP2400_TX_MODE_MPHY_POLLED_STATUS | - IXP2400_TX_MODE_MPHY_LEVEL3 | - IXP2400_TX_MODE_TBUF_SIZE_64, - - .txclk01_multiplier = IXP2400_PLL_MULTIPLIER_16, - - .tx_poll_ports = 3, - - .tx_channel_mode = { - IXP2400_PORT_TX_MODE_MASTER | - IXP2400_PORT_TX_MODE_POS_PHY | - IXP2400_PORT_TX_MODE_ODD_PARITY | - IXP2400_PORT_TX_MODE_2_CYCLE_DECODE, - - IXP2400_PORT_TX_MODE_MASTER | - IXP2400_PORT_TX_MODE_POS_PHY | - IXP2400_PORT_TX_MODE_ODD_PARITY | - IXP2400_PORT_TX_MODE_2_CYCLE_DECODE, - - IXP2400_PORT_TX_MODE_MASTER | - IXP2400_PORT_TX_MODE_POS_PHY | - IXP2400_PORT_TX_MODE_ODD_PARITY | - IXP2400_PORT_TX_MODE_2_CYCLE_DECODE, - - IXP2400_PORT_TX_MODE_MASTER | - IXP2400_PORT_TX_MODE_POS_PHY | - IXP2400_PORT_TX_MODE_ODD_PARITY | - IXP2400_PORT_TX_MODE_2_CYCLE_DECODE - } -}; - -static struct net_device *nds[3]; -static struct timer_list link_check_timer; - -/* @@@ Poll the SFP moddef0 line too. */ -/* @@@ Try to use the pm3386 DOOL interrupt as well. */ -static void enp2611_check_link_status(unsigned long __dummy) -{ - int i; - - for (i = 0; i < 3; i++) { - struct net_device *dev; - int status; - - dev = nds[i]; - if (dev == NULL) - continue; - - status = pm3386_is_link_up(i); - if (status && !netif_carrier_ok(dev)) { - /* @@@ Should report autonegotiation status. */ - printk(KERN_INFO "%s: NIC Link is Up\n", dev->name); - - pm3386_enable_tx(i); - caleb_enable_tx(i); - netif_carrier_on(dev); - } else if (!status && netif_carrier_ok(dev)) { - printk(KERN_INFO "%s: NIC Link is Down\n", dev->name); - - netif_carrier_off(dev); - caleb_disable_tx(i); - pm3386_disable_tx(i); - } - } - - link_check_timer.expires = jiffies + HZ / 10; - add_timer(&link_check_timer); -} - -static void enp2611_set_port_admin_status(int port, int up) -{ - if (up) { - caleb_enable_rx(port); - - pm3386_set_carrier(port, 1); - pm3386_enable_rx(port); - } else { - caleb_disable_tx(port); - pm3386_disable_tx(port); - /* @@@ Flush out pending packets. */ - pm3386_set_carrier(port, 0); - - pm3386_disable_rx(port); - caleb_disable_rx(port); - } -} - -static int __init enp2611_init_module(void) -{ - int ports; - int i; - - if (!machine_is_enp2611()) - return -ENODEV; - - caleb_reset(); - pm3386_reset(); - - ports = pm3386_port_count(); - for (i = 0; i < ports; i++) { - nds[i] = ixpdev_alloc(i, sizeof(struct ixpdev_priv)); - if (nds[i] == NULL) { - while (--i >= 0) - free_netdev(nds[i]); - return -ENOMEM; - } - - pm3386_init_port(i); - pm3386_get_mac(i, nds[i]->dev_addr); - } - - ixp2400_msf_init(&enp2611_msf_parameters); - - if (ixpdev_init(ports, nds, enp2611_set_port_admin_status)) { - for (i = 0; i < ports; i++) - if (nds[i]) - free_netdev(nds[i]); - return -EINVAL; - } - - init_timer(&link_check_timer); - link_check_timer.function = enp2611_check_link_status; - link_check_timer.expires = jiffies; - add_timer(&link_check_timer); - - return 0; -} - -static void __exit enp2611_cleanup_module(void) -{ - int i; - - del_timer_sync(&link_check_timer); - - ixpdev_deinit(); - for (i = 0; i < 3; i++) - free_netdev(nds[i]); -} - -module_init(enp2611_init_module); -module_exit(enp2611_cleanup_module); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/net/ethernet/xscale/ixp2000/ixp2400-msf.c b/trunk/drivers/net/ethernet/xscale/ixp2000/ixp2400-msf.c deleted file mode 100644 index f5ffd7e05d26..000000000000 --- a/trunk/drivers/net/ethernet/xscale/ixp2000/ixp2400-msf.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Generic library functions for the MSF (Media and Switch Fabric) unit - * found on the Intel IXP2400 network processor. - * - * Copyright (C) 2004, 2005 Lennert Buytenhek - * Dedicated to Marija Kulikova. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of the - * License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include "ixp2400-msf.h" - -/* - * This is the Intel recommended PLL init procedure as described on - * page 340 of the IXP2400/IXP2800 Programmer's Reference Manual. - */ -static void ixp2400_pll_init(struct ixp2400_msf_parameters *mp) -{ - int rx_dual_clock; - int tx_dual_clock; - u32 value; - - /* - * If the RX mode is not 1x32, we have to enable both RX PLLs - * (#0 and #1.) The same thing for the TX direction. - */ - rx_dual_clock = !!(mp->rx_mode & IXP2400_RX_MODE_WIDTH_MASK); - tx_dual_clock = !!(mp->tx_mode & IXP2400_TX_MODE_WIDTH_MASK); - - /* - * Read initial value. - */ - value = ixp2000_reg_read(IXP2000_MSF_CLK_CNTRL); - - /* - * Put PLLs in powerdown and bypass mode. - */ - value |= 0x0000f0f0; - ixp2000_reg_write(IXP2000_MSF_CLK_CNTRL, value); - - /* - * Set single or dual clock mode bits. - */ - value &= ~0x03000000; - value |= (rx_dual_clock << 24) | (tx_dual_clock << 25); - - /* - * Set multipliers. - */ - value &= ~0x00ff0000; - value |= mp->rxclk01_multiplier << 16; - value |= mp->rxclk23_multiplier << 18; - value |= mp->txclk01_multiplier << 20; - value |= mp->txclk23_multiplier << 22; - - /* - * And write value. - */ - ixp2000_reg_write(IXP2000_MSF_CLK_CNTRL, value); - - /* - * Disable PLL bypass mode. - */ - value &= ~(0x00005000 | rx_dual_clock << 13 | tx_dual_clock << 15); - ixp2000_reg_write(IXP2000_MSF_CLK_CNTRL, value); - - /* - * Turn on PLLs. - */ - value &= ~(0x00000050 | rx_dual_clock << 5 | tx_dual_clock << 7); - ixp2000_reg_write(IXP2000_MSF_CLK_CNTRL, value); - - /* - * Wait for PLLs to lock. There are lock status bits, but IXP2400 - * erratum #65 says that these lock bits should not be relied upon - * as they might not accurately reflect the true state of the PLLs. - */ - udelay(100); -} - -/* - * Needed according to p480 of Programmer's Reference Manual. - */ -static void ixp2400_msf_free_rbuf_entries(struct ixp2400_msf_parameters *mp) -{ - int size_bits; - int i; - - /* - * Work around IXP2400 erratum #69 (silent RBUF-to-DRAM transfer - * corruption) in the Intel-recommended way: do not add the RBUF - * elements susceptible to corruption to the freelist. - */ - size_bits = mp->rx_mode & IXP2400_RX_MODE_RBUF_SIZE_MASK; - if (size_bits == IXP2400_RX_MODE_RBUF_SIZE_64) { - for (i = 1; i < 128; i++) { - if (i == 9 || i == 18 || i == 27) - continue; - ixp2000_reg_write(IXP2000_MSF_RBUF_ELEMENT_DONE, i); - } - } else if (size_bits == IXP2400_RX_MODE_RBUF_SIZE_128) { - for (i = 1; i < 64; i++) { - if (i == 4 || i == 9 || i == 13) - continue; - ixp2000_reg_write(IXP2000_MSF_RBUF_ELEMENT_DONE, i); - } - } else if (size_bits == IXP2400_RX_MODE_RBUF_SIZE_256) { - for (i = 1; i < 32; i++) { - if (i == 2 || i == 4 || i == 6) - continue; - ixp2000_reg_write(IXP2000_MSF_RBUF_ELEMENT_DONE, i); - } - } -} - -static u32 ixp2400_msf_valid_channels(u32 reg) -{ - u32 channels; - - channels = 0; - switch (reg & IXP2400_RX_MODE_WIDTH_MASK) { - case IXP2400_RX_MODE_1x32: - channels = 0x1; - if (reg & IXP2400_RX_MODE_MPHY && - !(reg & IXP2400_RX_MODE_MPHY_32)) - channels = 0xf; - break; - - case IXP2400_RX_MODE_2x16: - channels = 0x5; - break; - - case IXP2400_RX_MODE_4x8: - channels = 0xf; - break; - - case IXP2400_RX_MODE_1x16_2x8: - channels = 0xd; - break; - } - - return channels; -} - -static void ixp2400_msf_enable_rx(struct ixp2400_msf_parameters *mp) -{ - u32 value; - - value = ixp2000_reg_read(IXP2000_MSF_RX_CONTROL) & 0x0fffffff; - value |= ixp2400_msf_valid_channels(mp->rx_mode) << 28; - ixp2000_reg_write(IXP2000_MSF_RX_CONTROL, value); -} - -static void ixp2400_msf_enable_tx(struct ixp2400_msf_parameters *mp) -{ - u32 value; - - value = ixp2000_reg_read(IXP2000_MSF_TX_CONTROL) & 0x0fffffff; - value |= ixp2400_msf_valid_channels(mp->tx_mode) << 28; - ixp2000_reg_write(IXP2000_MSF_TX_CONTROL, value); -} - - -void ixp2400_msf_init(struct ixp2400_msf_parameters *mp) -{ - u32 value; - int i; - - /* - * Init the RX/TX PLLs based on the passed parameter block. - */ - ixp2400_pll_init(mp); - - /* - * Reset MSF. Bit 7 in IXP_RESET_0 resets the MSF. - */ - value = ixp2000_reg_read(IXP2000_RESET0); - ixp2000_reg_write(IXP2000_RESET0, value | 0x80); - ixp2000_reg_write(IXP2000_RESET0, value & ~0x80); - - /* - * Initialise the RX section. - */ - ixp2000_reg_write(IXP2000_MSF_RX_MPHY_POLL_LIMIT, mp->rx_poll_ports - 1); - ixp2000_reg_write(IXP2000_MSF_RX_CONTROL, mp->rx_mode); - for (i = 0; i < 4; i++) { - ixp2000_reg_write(IXP2000_MSF_RX_UP_CONTROL_0 + i, - mp->rx_channel_mode[i]); - } - ixp2400_msf_free_rbuf_entries(mp); - ixp2400_msf_enable_rx(mp); - - /* - * Initialise the TX section. - */ - ixp2000_reg_write(IXP2000_MSF_TX_MPHY_POLL_LIMIT, mp->tx_poll_ports - 1); - ixp2000_reg_write(IXP2000_MSF_TX_CONTROL, mp->tx_mode); - for (i = 0; i < 4; i++) { - ixp2000_reg_write(IXP2000_MSF_TX_UP_CONTROL_0 + i, - mp->tx_channel_mode[i]); - } - ixp2400_msf_enable_tx(mp); -} diff --git a/trunk/drivers/net/ethernet/xscale/ixp2000/ixp2400-msf.h b/trunk/drivers/net/ethernet/xscale/ixp2000/ixp2400-msf.h deleted file mode 100644 index 3ac1af2771da..000000000000 --- a/trunk/drivers/net/ethernet/xscale/ixp2000/ixp2400-msf.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Generic library functions for the MSF (Media and Switch Fabric) unit - * found on the Intel IXP2400 network processor. - * - * Copyright (C) 2004, 2005 Lennert Buytenhek - * Dedicated to Marija Kulikova. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of the - * License, or (at your option) any later version. - */ - -#ifndef __IXP2400_MSF_H -#define __IXP2400_MSF_H - -struct ixp2400_msf_parameters -{ - u32 rx_mode; - unsigned rxclk01_multiplier:2; - unsigned rxclk23_multiplier:2; - unsigned rx_poll_ports:6; - u32 rx_channel_mode[4]; - - u32 tx_mode; - unsigned txclk01_multiplier:2; - unsigned txclk23_multiplier:2; - unsigned tx_poll_ports:6; - u32 tx_channel_mode[4]; -}; - -void ixp2400_msf_init(struct ixp2400_msf_parameters *mp); - -#define IXP2400_PLL_MULTIPLIER_48 0x00 -#define IXP2400_PLL_MULTIPLIER_24 0x01 -#define IXP2400_PLL_MULTIPLIER_16 0x02 -#define IXP2400_PLL_MULTIPLIER_12 0x03 - -#define IXP2400_RX_MODE_CSIX 0x00400000 -#define IXP2400_RX_MODE_UTOPIA_POS 0x00000000 -#define IXP2400_RX_MODE_WIDTH_MASK 0x00300000 -#define IXP2400_RX_MODE_1x16_2x8 0x00300000 -#define IXP2400_RX_MODE_4x8 0x00200000 -#define IXP2400_RX_MODE_2x16 0x00100000 -#define IXP2400_RX_MODE_1x32 0x00000000 -#define IXP2400_RX_MODE_MPHY 0x00080000 -#define IXP2400_RX_MODE_SPHY 0x00000000 -#define IXP2400_RX_MODE_MPHY_32 0x00040000 -#define IXP2400_RX_MODE_MPHY_4 0x00000000 -#define IXP2400_RX_MODE_MPHY_POLLED_STATUS 0x00020000 -#define IXP2400_RX_MODE_MPHY_DIRECT_STATUS 0x00000000 -#define IXP2400_RX_MODE_CBUS_FULL_DUPLEX 0x00010000 -#define IXP2400_RX_MODE_CBUS_SIMPLEX 0x00000000 -#define IXP2400_RX_MODE_MPHY_LEVEL2 0x00004000 -#define IXP2400_RX_MODE_MPHY_LEVEL3 0x00000000 -#define IXP2400_RX_MODE_CBUS_8BIT 0x00002000 -#define IXP2400_RX_MODE_CBUS_4BIT 0x00000000 -#define IXP2400_RX_MODE_CSIX_SINGLE_FREELIST 0x00000200 -#define IXP2400_RX_MODE_CSIX_SPLIT_FREELISTS 0x00000000 -#define IXP2400_RX_MODE_RBUF_SIZE_MASK 0x0000000c -#define IXP2400_RX_MODE_RBUF_SIZE_256 0x00000008 -#define IXP2400_RX_MODE_RBUF_SIZE_128 0x00000004 -#define IXP2400_RX_MODE_RBUF_SIZE_64 0x00000000 - -#define IXP2400_PORT_RX_MODE_SLAVE 0x00000040 -#define IXP2400_PORT_RX_MODE_MASTER 0x00000000 -#define IXP2400_PORT_RX_MODE_POS_PHY_L3 0x00000020 -#define IXP2400_PORT_RX_MODE_POS_PHY_L2 0x00000000 -#define IXP2400_PORT_RX_MODE_POS_PHY 0x00000010 -#define IXP2400_PORT_RX_MODE_UTOPIA 0x00000000 -#define IXP2400_PORT_RX_MODE_EVEN_PARITY 0x0000000c -#define IXP2400_PORT_RX_MODE_ODD_PARITY 0x00000008 -#define IXP2400_PORT_RX_MODE_NO_PARITY 0x00000000 -#define IXP2400_PORT_RX_MODE_UTOPIA_BIG_CELLS 0x00000002 -#define IXP2400_PORT_RX_MODE_UTOPIA_NORMAL_CELLS 0x00000000 -#define IXP2400_PORT_RX_MODE_2_CYCLE_DECODE 0x00000001 -#define IXP2400_PORT_RX_MODE_1_CYCLE_DECODE 0x00000000 - -#define IXP2400_TX_MODE_CSIX 0x00400000 -#define IXP2400_TX_MODE_UTOPIA_POS 0x00000000 -#define IXP2400_TX_MODE_WIDTH_MASK 0x00300000 -#define IXP2400_TX_MODE_1x16_2x8 0x00300000 -#define IXP2400_TX_MODE_4x8 0x00200000 -#define IXP2400_TX_MODE_2x16 0x00100000 -#define IXP2400_TX_MODE_1x32 0x00000000 -#define IXP2400_TX_MODE_MPHY 0x00080000 -#define IXP2400_TX_MODE_SPHY 0x00000000 -#define IXP2400_TX_MODE_MPHY_32 0x00040000 -#define IXP2400_TX_MODE_MPHY_4 0x00000000 -#define IXP2400_TX_MODE_MPHY_POLLED_STATUS 0x00020000 -#define IXP2400_TX_MODE_MPHY_DIRECT_STATUS 0x00000000 -#define IXP2400_TX_MODE_CBUS_FULL_DUPLEX 0x00010000 -#define IXP2400_TX_MODE_CBUS_SIMPLEX 0x00000000 -#define IXP2400_TX_MODE_MPHY_LEVEL2 0x00004000 -#define IXP2400_TX_MODE_MPHY_LEVEL3 0x00000000 -#define IXP2400_TX_MODE_CBUS_8BIT 0x00002000 -#define IXP2400_TX_MODE_CBUS_4BIT 0x00000000 -#define IXP2400_TX_MODE_TBUF_SIZE_MASK 0x0000000c -#define IXP2400_TX_MODE_TBUF_SIZE_256 0x00000008 -#define IXP2400_TX_MODE_TBUF_SIZE_128 0x00000004 -#define IXP2400_TX_MODE_TBUF_SIZE_64 0x00000000 - -#define IXP2400_PORT_TX_MODE_SLAVE 0x00000040 -#define IXP2400_PORT_TX_MODE_MASTER 0x00000000 -#define IXP2400_PORT_TX_MODE_POS_PHY 0x00000010 -#define IXP2400_PORT_TX_MODE_UTOPIA 0x00000000 -#define IXP2400_PORT_TX_MODE_EVEN_PARITY 0x0000000c -#define IXP2400_PORT_TX_MODE_ODD_PARITY 0x00000008 -#define IXP2400_PORT_TX_MODE_NO_PARITY 0x00000000 -#define IXP2400_PORT_TX_MODE_UTOPIA_BIG_CELLS 0x00000002 -#define IXP2400_PORT_TX_MODE_2_CYCLE_DECODE 0x00000001 -#define IXP2400_PORT_TX_MODE_1_CYCLE_DECODE 0x00000000 - - -#endif diff --git a/trunk/drivers/net/ethernet/xscale/ixp2000/ixp2400_rx.uc b/trunk/drivers/net/ethernet/xscale/ixp2000/ixp2400_rx.uc deleted file mode 100644 index 42a73e357afa..000000000000 --- a/trunk/drivers/net/ethernet/xscale/ixp2000/ixp2400_rx.uc +++ /dev/null @@ -1,408 +0,0 @@ -/* - * RX ucode for the Intel IXP2400 in POS-PHY mode. - * Copyright (C) 2004, 2005 Lennert Buytenhek - * Dedicated to Marija Kulikova. - * - * 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. - * - * Assumptions made in this code: - * - The IXP2400 MSF is configured for POS-PHY mode, in a mode where - * only one full element list is used. This includes, for example, - * 1x32 SPHY and 1x32 MPHY32, but not 4x8 SPHY or 1x32 MPHY4. (This - * is not an exhaustive list.) - * - The RBUF uses 64-byte mpackets. - * - RX descriptors reside in SRAM, and have the following format: - * struct rx_desc - * { - * // to uengine - * u32 buf_phys_addr; - * u32 buf_length; - * - * // from uengine - * u32 channel; - * u32 pkt_length; - * }; - * - Packet data resides in DRAM. - * - Packet buffer addresses are 8-byte aligned. - * - Scratch ring 0 is rx_pending. - * - Scratch ring 1 is rx_done, and has status condition 'full'. - * - The host triggers rx_done flush and rx_pending refill on seeing INTA. - * - This code is run on all eight threads of the microengine it runs on. - * - * Local memory is used for per-channel RX state. - */ - -#define RX_THREAD_FREELIST_0 0x0030 -#define RBUF_ELEMENT_DONE 0x0044 - -#define CHANNEL_FLAGS *l$index0[0] -#define CHANNEL_FLAG_RECEIVING 1 -#define PACKET_LENGTH *l$index0[1] -#define PACKET_CHECKSUM *l$index0[2] -#define BUFFER_HANDLE *l$index0[3] -#define BUFFER_START *l$index0[4] -#define BUFFER_LENGTH *l$index0[5] - -#define CHANNEL_STATE_SIZE 24 // in bytes -#define CHANNEL_STATE_SHIFT 5 // ceil(log2(state size)) - - - .sig volatile sig1 - .sig volatile sig2 - .sig volatile sig3 - - .sig mpacket_arrived - .reg add_to_rx_freelist - .reg read $rsw0, $rsw1 - .xfer_order $rsw0 $rsw1 - - .reg zero - - /* - * Initialise add_to_rx_freelist. - */ - .begin - .reg temp - .reg temp2 - - immed[add_to_rx_freelist, RX_THREAD_FREELIST_0] - immed_w1[add_to_rx_freelist, (&$rsw0 | (&mpacket_arrived << 12))] - - local_csr_rd[ACTIVE_CTX_STS] - immed[temp, 0] - alu[temp2, temp, and, 0x1f] - alu_shf[add_to_rx_freelist, add_to_rx_freelist, or, temp2, <<20] - alu[temp2, temp, and, 0x80] - alu_shf[add_to_rx_freelist, add_to_rx_freelist, or, temp2, <<18] - .end - - immed[zero, 0] - - /* - * Skip context 0 initialisation? - */ - .begin - br!=ctx[0, mpacket_receive_loop#] - .end - - /* - * Initialise local memory. - */ - .begin - .reg addr - .reg temp - - immed[temp, 0] - init_local_mem_loop#: - alu_shf[addr, --, b, temp, <>8] - bne[abort_rswerr#] - .end - - /* - * Point local memory pointer to this channel's state area. - */ - .begin - .reg chanaddr - - alu[chanaddr, $rsw0, and, 0x1f] - alu_shf[chanaddr, --, b, chanaddr, < abort) If everything's - * okay, update the RECEIVING flag to reflect our new state. - */ - .begin - .reg temp - .reg eop - - #if CHANNEL_FLAG_RECEIVING != 1 - #error CHANNEL_FLAG_RECEIVING is not 1 - #endif - - alu_shf[temp, 1, and, $rsw0, >>15] - alu[temp, temp, xor, CHANNEL_FLAGS] - alu[--, temp, and, CHANNEL_FLAG_RECEIVING] - beq[abort_proterr#] - - alu_shf[eop, 1, and, $rsw0, >>14] - alu[CHANNEL_FLAGS, temp, xor, eop] - .end - - /* - * Copy the mpacket into the right spot, and in case of EOP, - * write back the descriptor and pass the packet on. - */ - .begin - .reg buffer_offset - .reg _packet_length - .reg _packet_checksum - .reg _buffer_handle - .reg _buffer_start - .reg _buffer_length - - /* - * Determine buffer_offset, _packet_length and - * _packet_checksum. - */ - .begin - .reg temp - - alu[--, 1, and, $rsw0, >>15] - beq[not_sop#] - - immed[PACKET_LENGTH, 0] - immed[PACKET_CHECKSUM, 0] - - not_sop#: - alu[buffer_offset, --, b, PACKET_LENGTH] - alu_shf[temp, 0xff, and, $rsw0, >>16] - alu[_packet_length, buffer_offset, +, temp] - alu[PACKET_LENGTH, --, b, _packet_length] - - immed[temp, 0xffff] - alu[temp, $rsw1, and, temp] - alu[_packet_checksum, PACKET_CHECKSUM, +, temp] - alu[PACKET_CHECKSUM, --, b, _packet_checksum] - .end - - /* - * Allocate buffer in case of SOP. - */ - .begin - .reg temp - - alu[temp, 1, and, $rsw0, >>15] - beq[skip_buffer_alloc#] - - .begin - .sig zzz - .reg read $stemp $stemp2 - .xfer_order $stemp $stemp2 - - rx_nobufs#: - scratch[get, $stemp, zero, 0, 1], ctx_swap[zzz] - alu[_buffer_handle, --, b, $stemp] - beq[rx_nobufs#] - - sram[read, $stemp, _buffer_handle, 0, 2], - ctx_swap[zzz] - alu[_buffer_start, --, b, $stemp] - alu[_buffer_length, --, b, $stemp2] - .end - - skip_buffer_alloc#: - .end - - /* - * Resynchronise. - */ - .begin - ctx_arb[sig2] - local_csr_wr[SAME_ME_SIGNAL, (0x80 | (&sig2 << 3))] - .end - - /* - * Synchronise buffer state. - */ - .begin - .reg temp - - alu[temp, 1, and, $rsw0, >>15] - beq[copy_from_local_mem#] - - alu[BUFFER_HANDLE, --, b, _buffer_handle] - alu[BUFFER_START, --, b, _buffer_start] - alu[BUFFER_LENGTH, --, b, _buffer_length] - br[sync_state_done#] - - copy_from_local_mem#: - alu[_buffer_handle, --, b, BUFFER_HANDLE] - alu[_buffer_start, --, b, BUFFER_START] - alu[_buffer_length, --, b, BUFFER_LENGTH] - - sync_state_done#: - .end - -#if 0 - /* - * Debug buffer state management. - */ - .begin - .reg temp - - alu[temp, 1, and, $rsw0, >>14] - beq[no_poison#] - immed[BUFFER_HANDLE, 0xdead] - immed[BUFFER_START, 0xdead] - immed[BUFFER_LENGTH, 0xdead] - no_poison#: - - immed[temp, 0xdead] - alu[--, _buffer_handle, -, temp] - beq[state_corrupted#] - alu[--, _buffer_start, -, temp] - beq[state_corrupted#] - alu[--, _buffer_length, -, temp] - beq[state_corrupted#] - .end -#endif - - /* - * Check buffer length. - */ - .begin - alu[--, _buffer_length, -, _packet_length] - blo[buffer_overflow#] - .end - - /* - * Copy the mpacket and give back the RBUF element. - */ - .begin - .reg element - .reg xfer_size - .reg temp - .sig copy_sig - - alu_shf[element, 0x7f, and, $rsw0, >>24] - alu_shf[xfer_size, 0xff, and, $rsw0, >>16] - - alu[xfer_size, xfer_size, -, 1] - alu_shf[xfer_size, 0x10, or, xfer_size, >>3] - alu_shf[temp, 0x10, or, xfer_size, <<21] - alu_shf[temp, temp, or, element, <<11] - alu_shf[--, temp, or, 1, <<18] - - dram[rbuf_rd, --, _buffer_start, buffer_offset, max_8], - indirect_ref, sig_done[copy_sig] - ctx_arb[copy_sig] - - alu[temp, RBUF_ELEMENT_DONE, or, element, <<16] - msf[fast_wr, --, temp, 0] - .end - - /* - * If EOP, write back the packet descriptor. - */ - .begin - .reg write $stemp $stemp2 - .xfer_order $stemp $stemp2 - .sig zzz - - alu_shf[--, 1, and, $rsw0, >>14] - beq[no_writeback#] - - alu[$stemp, $rsw0, and, 0x1f] - alu[$stemp2, --, b, _packet_length] - sram[write, $stemp, _buffer_handle, 8, 2], ctx_swap[zzz] - - no_writeback#: - .end - - /* - * Resynchronise. - */ - .begin - ctx_arb[sig3] - local_csr_wr[SAME_ME_SIGNAL, (0x80 | (&sig3 << 3))] - .end - - /* - * If EOP, put the buffer back onto the scratch ring. - */ - .begin - .reg write $stemp - .sig zzz - - br_inp_state[SCR_Ring1_Status, rx_done_ring_overflow#] - - alu_shf[--, 1, and, $rsw0, >>14] - beq[mpacket_receive_loop#] - - alu[--, 1, and, $rsw0, >>10] - bne[rxerr#] - - alu[$stemp, --, b, _buffer_handle] - scratch[put, $stemp, zero, 4, 1], ctx_swap[zzz] - cap[fast_wr, 0, XSCALE_INT_A] - br[mpacket_receive_loop#] - - rxerr#: - alu[$stemp, --, b, _buffer_handle] - scratch[put, $stemp, zero, 0, 1], ctx_swap[zzz] - br[mpacket_receive_loop#] - .end - .end - - -abort_rswerr#: - halt - -abort_proterr#: - halt - -state_corrupted#: - halt - -buffer_overflow#: - halt - -rx_done_ring_overflow#: - halt - - diff --git a/trunk/drivers/net/ethernet/xscale/ixp2000/ixp2400_rx.ucode b/trunk/drivers/net/ethernet/xscale/ixp2000/ixp2400_rx.ucode deleted file mode 100644 index e8aee2f81aad..000000000000 --- a/trunk/drivers/net/ethernet/xscale/ixp2000/ixp2400_rx.ucode +++ /dev/null @@ -1,130 +0,0 @@ -static struct ixp2000_uengine_code ixp2400_rx = -{ - .cpu_model_bitmask = 0x000003fe, - .cpu_min_revision = 0, - .cpu_max_revision = 255, - - .uengine_parameters = IXP2000_UENGINE_8_CONTEXTS | - IXP2000_UENGINE_PRN_UPDATE_EVERY | - IXP2000_UENGINE_NN_FROM_PREVIOUS | - IXP2000_UENGINE_ASSERT_EMPTY_AT_0 | - IXP2000_UENGINE_LM_ADDR1_PER_CONTEXT | - IXP2000_UENGINE_LM_ADDR0_PER_CONTEXT, - - .initial_reg_values = (struct ixp2000_reg_value []) { - { -1, -1 } - }, - - .num_insns = 109, - .insns = (u8 []) { - 0xf0, 0x00, 0x0c, 0xc0, 0x05, - 0xf4, 0x44, 0x0c, 0x00, 0x05, - 0xfc, 0x04, 0x4c, 0x00, 0x00, - 0xf0, 0x00, 0x00, 0x3b, 0x00, - 0xb4, 0x40, 0xf0, 0x3b, 0x1f, - 0x8a, 0xc0, 0x50, 0x3e, 0x05, - 0xb4, 0x40, 0xf0, 0x3b, 0x80, - 0x9a, 0xe0, 0x00, 0x3e, 0x05, - 0xf0, 0x00, 0x00, 0x07, 0x00, - 0xd8, 0x05, 0xc0, 0x00, 0x11, - 0xf0, 0x00, 0x00, 0x0f, 0x00, - 0x91, 0xb0, 0x20, 0x0e, 0x00, - 0xfc, 0x06, 0x60, 0x0b, 0x00, - 0xf0, 0x00, 0x0c, 0x03, 0x00, - 0xf0, 0x00, 0x0c, 0x03, 0x00, - 0xf0, 0x00, 0x0c, 0x03, 0x00, - 0xf0, 0x00, 0x0c, 0x02, 0x00, - 0xb0, 0xc0, 0x30, 0x0f, 0x01, - 0xa4, 0x70, 0x00, 0x0f, 0x20, - 0xd8, 0x02, 0xc0, 0x01, 0x00, - 0xfc, 0x10, 0xac, 0x23, 0x08, - 0xfc, 0x10, 0xac, 0x43, 0x10, - 0xfc, 0x10, 0xac, 0x63, 0x18, - 0xe0, 0x00, 0x00, 0x00, 0x02, - 0xfc, 0x10, 0xae, 0x23, 0x88, - 0x3d, 0x00, 0x04, 0x03, 0x20, - 0xe0, 0x00, 0x00, 0x00, 0x10, - 0x84, 0x82, 0x02, 0x01, 0x3b, - 0xd8, 0x1a, 0x00, 0x01, 0x01, - 0xb4, 0x00, 0x8c, 0x7d, 0x80, - 0x91, 0xb0, 0x80, 0x22, 0x00, - 0xfc, 0x06, 0x60, 0x23, 0x00, - 0xf0, 0x00, 0x0c, 0x03, 0x00, - 0xf0, 0x00, 0x0c, 0x03, 0x00, - 0xf0, 0x00, 0x0c, 0x03, 0x00, - 0x94, 0xf0, 0x92, 0x01, 0x21, - 0xac, 0x40, 0x60, 0x26, 0x00, - 0xa4, 0x30, 0x0c, 0x04, 0x06, - 0xd8, 0x1a, 0x40, 0x01, 0x00, - 0x94, 0xe0, 0xa2, 0x01, 0x21, - 0xac, 0x20, 0x00, 0x28, 0x06, - 0x84, 0xf2, 0x02, 0x01, 0x21, - 0xd8, 0x0b, 0x40, 0x01, 0x00, - 0xf0, 0x00, 0x0c, 0x02, 0x01, - 0xf0, 0x00, 0x0c, 0x02, 0x02, - 0xa0, 0x00, 0x08, 0x04, 0x00, - 0x95, 0x00, 0xc6, 0x01, 0xff, - 0xa0, 0x80, 0x10, 0x30, 0x00, - 0xa0, 0x60, 0x1c, 0x00, 0x01, - 0xf0, 0x0f, 0xf0, 0x33, 0xff, - 0xb4, 0x00, 0xc0, 0x31, 0x81, - 0xb0, 0x80, 0xb0, 0x32, 0x02, - 0xa0, 0x20, 0x20, 0x2c, 0x00, - 0x94, 0xf0, 0xd2, 0x01, 0x21, - 0xd8, 0x0f, 0x40, 0x01, 0x00, - 0x19, 0x40, 0x10, 0x04, 0x20, - 0xa0, 0x00, 0x26, 0x04, 0x00, - 0xd8, 0x0d, 0xc0, 0x01, 0x00, - 0x00, 0x42, 0x10, 0x80, 0x02, - 0xb0, 0x00, 0x46, 0x04, 0x00, - 0xb0, 0x00, 0x56, 0x08, 0x00, - 0xe0, 0x00, 0x00, 0x00, 0x04, - 0xfc, 0x10, 0xae, 0x43, 0x90, - 0x84, 0xf0, 0x32, 0x01, 0x21, - 0xd8, 0x11, 0x40, 0x01, 0x00, - 0xa0, 0x60, 0x3c, 0x00, 0x02, - 0xa0, 0x20, 0x40, 0x10, 0x00, - 0xa0, 0x20, 0x50, 0x14, 0x00, - 0xd8, 0x12, 0x00, 0x00, 0x18, - 0xa0, 0x00, 0x28, 0x0c, 0x00, - 0xb0, 0x00, 0x48, 0x10, 0x00, - 0xb0, 0x00, 0x58, 0x14, 0x00, - 0xaa, 0xf0, 0x00, 0x14, 0x01, - 0xd8, 0x1a, 0xc0, 0x01, 0x05, - 0x85, 0x80, 0x42, 0x01, 0xff, - 0x95, 0x00, 0x66, 0x01, 0xff, - 0xba, 0xc0, 0x60, 0x1b, 0x01, - 0x9a, 0x30, 0x60, 0x19, 0x30, - 0x9a, 0xb0, 0x70, 0x1a, 0x30, - 0x9b, 0x50, 0x78, 0x1e, 0x04, - 0x8a, 0xe2, 0x08, 0x1e, 0x21, - 0x6a, 0x4e, 0x00, 0x13, 0x00, - 0xe0, 0x00, 0x00, 0x00, 0x30, - 0x9b, 0x00, 0x7a, 0x92, 0x04, - 0x3d, 0x00, 0x04, 0x1f, 0x20, - 0x84, 0xe2, 0x02, 0x01, 0x21, - 0xd8, 0x16, 0x80, 0x01, 0x00, - 0xa4, 0x18, 0x0c, 0x7d, 0x80, - 0xa0, 0x58, 0x1c, 0x00, 0x01, - 0x01, 0x42, 0x00, 0xa0, 0x02, - 0xe0, 0x00, 0x00, 0x00, 0x08, - 0xfc, 0x10, 0xae, 0x63, 0x98, - 0xd8, 0x1b, 0x00, 0xc2, 0x14, - 0x84, 0xe2, 0x02, 0x01, 0x21, - 0xd8, 0x05, 0xc0, 0x01, 0x00, - 0x84, 0xa2, 0x02, 0x01, 0x21, - 0xd8, 0x19, 0x40, 0x01, 0x01, - 0xa0, 0x58, 0x0c, 0x00, 0x02, - 0x1a, 0x40, 0x00, 0x04, 0x24, - 0x33, 0x00, 0x01, 0x2f, 0x20, - 0xd8, 0x05, 0xc0, 0x00, 0x18, - 0xa0, 0x58, 0x0c, 0x00, 0x02, - 0x1a, 0x40, 0x00, 0x04, 0x20, - 0xd8, 0x05, 0xc0, 0x00, 0x18, - 0xe0, 0x00, 0x02, 0x00, 0x00, - 0xe0, 0x00, 0x02, 0x00, 0x00, - 0xe0, 0x00, 0x02, 0x00, 0x00, - 0xe0, 0x00, 0x02, 0x00, 0x00, - 0xe0, 0x00, 0x02, 0x00, 0x00, - } -}; diff --git a/trunk/drivers/net/ethernet/xscale/ixp2000/ixp2400_tx.uc b/trunk/drivers/net/ethernet/xscale/ixp2000/ixp2400_tx.uc deleted file mode 100644 index d090d1884fb7..000000000000 --- a/trunk/drivers/net/ethernet/xscale/ixp2000/ixp2400_tx.uc +++ /dev/null @@ -1,272 +0,0 @@ -/* - * TX ucode for the Intel IXP2400 in POS-PHY mode. - * Copyright (C) 2004, 2005 Lennert Buytenhek - * Dedicated to Marija Kulikova. - * - * 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. - * - * Assumptions made in this code: - * - The IXP2400 MSF is configured for POS-PHY mode, in a mode where - * only one TBUF partition is used. This includes, for example, - * 1x32 SPHY and 1x32 MPHY32, but not 4x8 SPHY or 1x32 MPHY4. (This - * is not an exhaustive list.) - * - The TBUF uses 64-byte mpackets. - * - TX descriptors reside in SRAM, and have the following format: - * struct tx_desc - * { - * // to uengine - * u32 buf_phys_addr; - * u32 pkt_length; - * u32 channel; - * }; - * - Packet data resides in DRAM. - * - Packet buffer addresses are 8-byte aligned. - * - Scratch ring 2 is tx_pending. - * - Scratch ring 3 is tx_done, and has status condition 'full'. - * - This code is run on all eight threads of the microengine it runs on. - */ - -#define TX_SEQUENCE_0 0x0060 -#define TBUF_CTRL 0x1800 - -#define PARTITION_SIZE 128 -#define PARTITION_THRESH 96 - - - .sig volatile sig1 - .sig volatile sig2 - .sig volatile sig3 - - .reg @old_tx_seq_0 - .reg @mpkts_in_flight - .reg @next_tbuf_mpacket - - .reg @buffer_handle - .reg @buffer_start - .reg @packet_length - .reg @channel - .reg @packet_offset - - .reg zero - - immed[zero, 0] - - /* - * Skip context 0 initialisation? - */ - .begin - br!=ctx[0, mpacket_tx_loop#] - .end - - /* - * Wait until all pending TBUF elements have been transmitted. - */ - .begin - .reg read $tx - .sig zzz - - loop_empty#: - msf[read, $tx, zero, TX_SEQUENCE_0, 1], ctx_swap[zzz] - alu_shf[--, --, b, $tx, >>31] - beq[loop_empty#] - - alu[@old_tx_seq_0, --, b, $tx] - .end - - immed[@mpkts_in_flight, 0] - alu[@next_tbuf_mpacket, @old_tx_seq_0, and, (PARTITION_SIZE - 1)] - - immed[@buffer_handle, 0] - - /* - * Initialise signal pipeline. - */ - .begin - local_csr_wr[SAME_ME_SIGNAL, (&sig1 << 3)] - .set_sig sig1 - - local_csr_wr[SAME_ME_SIGNAL, (&sig2 << 3)] - .set_sig sig2 - - local_csr_wr[SAME_ME_SIGNAL, (&sig3 << 3)] - .set_sig sig3 - .end - -mpacket_tx_loop#: - .begin - .reg tbuf_element_index - .reg buffer_handle - .reg sop_eop - .reg packet_data - .reg channel - .reg mpacket_size - - /* - * If there is no packet currently being transmitted, - * dequeue the next TX descriptor, and fetch the buffer - * address, packet length and destination channel number. - */ - .begin - .reg read $stemp $stemp2 $stemp3 - .xfer_order $stemp $stemp2 $stemp3 - .sig zzz - - ctx_arb[sig1] - - alu[--, --, b, @buffer_handle] - bne[already_got_packet#] - - tx_nobufs#: - scratch[get, $stemp, zero, 8, 1], ctx_swap[zzz] - alu[@buffer_handle, --, b, $stemp] - beq[tx_nobufs#] - - sram[read, $stemp, $stemp, 0, 3], ctx_swap[zzz] - alu[@buffer_start, --, b, $stemp] - alu[@packet_length, --, b, $stemp2] - beq[zero_byte_packet#] - alu[@channel, --, b, $stemp3] - immed[@packet_offset, 0] - - already_got_packet#: - local_csr_wr[SAME_ME_SIGNAL, (0x80 | (&sig1 << 3))] - .end - - /* - * Determine tbuf element index, SOP/EOP flags, mpacket - * offset and mpacket size and cache buffer_handle and - * channel number. - */ - .begin - alu[tbuf_element_index, --, b, @next_tbuf_mpacket] - alu[@next_tbuf_mpacket, @next_tbuf_mpacket, +, 1] - alu[@next_tbuf_mpacket, @next_tbuf_mpacket, and, - (PARTITION_SIZE - 1)] - - alu[buffer_handle, --, b, @buffer_handle] - immed[@buffer_handle, 0] - - immed[sop_eop, 1] - - alu[packet_data, --, b, @packet_offset] - bne[no_sop#] - alu[sop_eop, sop_eop, or, 2] - no_sop#: - alu[packet_data, packet_data, +, @buffer_start] - - alu[channel, --, b, @channel] - - alu[mpacket_size, @packet_length, -, @packet_offset] - alu[--, 64, -, mpacket_size] - bhs[eop#] - alu[@buffer_handle, --, b, buffer_handle] - immed[mpacket_size, 64] - alu[sop_eop, sop_eop, and, 2] - eop#: - - alu[@packet_offset, @packet_offset, +, mpacket_size] - .end - - /* - * Wait until there's enough space in the TBUF. - */ - .begin - .reg read $tx - .reg temp - .sig zzz - - ctx_arb[sig2] - - br[test_space#] - - loop_space#: - msf[read, $tx, zero, TX_SEQUENCE_0, 1], ctx_swap[zzz] - - alu[temp, $tx, -, @old_tx_seq_0] - alu[temp, temp, and, 0xff] - alu[@mpkts_in_flight, @mpkts_in_flight, -, temp] - - alu[@old_tx_seq_0, --, b, $tx] - - test_space#: - alu[--, PARTITION_THRESH, -, @mpkts_in_flight] - blo[loop_space#] - - alu[@mpkts_in_flight, @mpkts_in_flight, +, 1] - - local_csr_wr[SAME_ME_SIGNAL, (0x80 | (&sig2 << 3))] - .end - - /* - * Copy the packet data to the TBUF. - */ - .begin - .reg temp - .sig copy_sig - - alu[temp, mpacket_size, -, 1] - alu_shf[temp, 0x10, or, temp, >>3] - alu_shf[temp, 0x10, or, temp, <<21] - alu_shf[temp, temp, or, tbuf_element_index, <<11] - alu_shf[--, temp, or, 1, <<18] - - dram[tbuf_wr, --, packet_data, 0, max_8], - indirect_ref, sig_done[copy_sig] - ctx_arb[copy_sig] - .end - - /* - * Mark TBUF element as ready-to-be-transmitted. - */ - .begin - .reg write $tsw $tsw2 - .xfer_order $tsw $tsw2 - .reg temp - .sig zzz - - alu_shf[temp, channel, or, mpacket_size, <<24] - alu_shf[$tsw, temp, or, sop_eop, <<8] - immed[$tsw2, 0] - - immed[temp, TBUF_CTRL] - alu_shf[temp, temp, or, tbuf_element_index, <<3] - msf[write, $tsw, temp, 0, 2], ctx_swap[zzz] - .end - - /* - * Resynchronise. - */ - .begin - ctx_arb[sig3] - local_csr_wr[SAME_ME_SIGNAL, (0x80 | (&sig3 << 3))] - .end - - /* - * If this was an EOP mpacket, recycle the TX buffer - * and signal the host. - */ - .begin - .reg write $stemp - .sig zzz - - alu[--, sop_eop, and, 1] - beq[mpacket_tx_loop#] - - tx_done_ring_full#: - br_inp_state[SCR_Ring3_Status, tx_done_ring_full#] - - alu[$stemp, --, b, buffer_handle] - scratch[put, $stemp, zero, 12, 1], ctx_swap[zzz] - cap[fast_wr, 0, XSCALE_INT_A] - br[mpacket_tx_loop#] - .end - .end - - -zero_byte_packet#: - halt - - diff --git a/trunk/drivers/net/ethernet/xscale/ixp2000/ixp2400_tx.ucode b/trunk/drivers/net/ethernet/xscale/ixp2000/ixp2400_tx.ucode deleted file mode 100644 index a433e24b0a51..000000000000 --- a/trunk/drivers/net/ethernet/xscale/ixp2000/ixp2400_tx.ucode +++ /dev/null @@ -1,98 +0,0 @@ -static struct ixp2000_uengine_code ixp2400_tx = -{ - .cpu_model_bitmask = 0x000003fe, - .cpu_min_revision = 0, - .cpu_max_revision = 255, - - .uengine_parameters = IXP2000_UENGINE_8_CONTEXTS | - IXP2000_UENGINE_PRN_UPDATE_EVERY | - IXP2000_UENGINE_NN_FROM_PREVIOUS | - IXP2000_UENGINE_ASSERT_EMPTY_AT_0 | - IXP2000_UENGINE_LM_ADDR1_PER_CONTEXT | - IXP2000_UENGINE_LM_ADDR0_PER_CONTEXT, - - .initial_reg_values = (struct ixp2000_reg_value []) { - { -1, -1 } - }, - - .num_insns = 77, - .insns = (u8 []) { - 0xf0, 0x00, 0x00, 0x07, 0x00, - 0xd8, 0x03, 0x00, 0x00, 0x11, - 0x3c, 0x40, 0x00, 0x04, 0xe0, - 0x81, 0xf2, 0x02, 0x01, 0x00, - 0xd8, 0x00, 0x80, 0x01, 0x00, - 0xb0, 0x08, 0x06, 0x00, 0x00, - 0xf0, 0x00, 0x0c, 0x00, 0x80, - 0xb4, 0x49, 0x02, 0x03, 0x7f, - 0xf0, 0x00, 0x02, 0x83, 0x00, - 0xfc, 0x10, 0xac, 0x23, 0x08, - 0xfc, 0x10, 0xac, 0x43, 0x10, - 0xfc, 0x10, 0xac, 0x63, 0x18, - 0xe0, 0x00, 0x00, 0x00, 0x02, - 0xa0, 0x30, 0x02, 0x80, 0x00, - 0xd8, 0x06, 0x00, 0x01, 0x01, - 0x19, 0x40, 0x00, 0x04, 0x28, - 0xb0, 0x0a, 0x06, 0x00, 0x00, - 0xd8, 0x03, 0xc0, 0x01, 0x00, - 0x00, 0x44, 0x00, 0x80, 0x80, - 0xa0, 0x09, 0x06, 0x00, 0x00, - 0xb0, 0x0b, 0x06, 0x04, 0x00, - 0xd8, 0x13, 0x00, 0x01, 0x00, - 0xb0, 0x0c, 0x06, 0x08, 0x00, - 0xf0, 0x00, 0x0c, 0x00, 0xa0, - 0xfc, 0x10, 0xae, 0x23, 0x88, - 0xa0, 0x00, 0x12, 0x40, 0x00, - 0xb0, 0xc9, 0x02, 0x43, 0x01, - 0xb4, 0x49, 0x02, 0x43, 0x7f, - 0xb0, 0x00, 0x22, 0x80, 0x00, - 0xf0, 0x00, 0x02, 0x83, 0x00, - 0xf0, 0x00, 0x0c, 0x04, 0x02, - 0xb0, 0x40, 0x6c, 0x00, 0xa0, - 0xd8, 0x08, 0x80, 0x01, 0x01, - 0xaa, 0x00, 0x2c, 0x08, 0x02, - 0xa0, 0xc0, 0x30, 0x18, 0x90, - 0xa0, 0x00, 0x43, 0x00, 0x00, - 0xba, 0xc0, 0x32, 0xc0, 0xa0, - 0xaa, 0xb0, 0x00, 0x0f, 0x40, - 0xd8, 0x0a, 0x80, 0x01, 0x04, - 0xb0, 0x0a, 0x00, 0x08, 0x00, - 0xf0, 0x00, 0x00, 0x0f, 0x40, - 0xa4, 0x00, 0x2c, 0x08, 0x02, - 0xa0, 0x8a, 0x00, 0x0c, 0xa0, - 0xe0, 0x00, 0x00, 0x00, 0x04, - 0xd8, 0x0c, 0x80, 0x00, 0x18, - 0x3c, 0x40, 0x00, 0x04, 0xe0, - 0xba, 0x80, 0x42, 0x01, 0x80, - 0xb4, 0x40, 0x40, 0x13, 0xff, - 0xaa, 0x88, 0x00, 0x10, 0x80, - 0xb0, 0x08, 0x06, 0x00, 0x00, - 0xaa, 0xf0, 0x0d, 0x80, 0x80, - 0xd8, 0x0b, 0x40, 0x01, 0x05, - 0xa0, 0x88, 0x0c, 0x04, 0x80, - 0xfc, 0x10, 0xae, 0x43, 0x90, - 0xba, 0xc0, 0x50, 0x0f, 0x01, - 0x9a, 0x30, 0x50, 0x15, 0x30, - 0x9a, 0xb0, 0x50, 0x16, 0x30, - 0x9b, 0x50, 0x58, 0x16, 0x01, - 0x8a, 0xe2, 0x08, 0x16, 0x21, - 0x6b, 0x4e, 0x00, 0x83, 0x03, - 0xe0, 0x00, 0x00, 0x00, 0x30, - 0x9a, 0x80, 0x70, 0x0e, 0x04, - 0x8b, 0x88, 0x08, 0x1e, 0x02, - 0xf0, 0x00, 0x0c, 0x01, 0x81, - 0xf0, 0x01, 0x80, 0x1f, 0x00, - 0x9b, 0xd0, 0x78, 0x1e, 0x01, - 0x3d, 0x42, 0x00, 0x1c, 0x20, - 0xe0, 0x00, 0x00, 0x00, 0x08, - 0xfc, 0x10, 0xae, 0x63, 0x98, - 0xa4, 0x30, 0x0c, 0x04, 0x02, - 0xd8, 0x03, 0x00, 0x01, 0x00, - 0xd8, 0x11, 0xc1, 0x42, 0x14, - 0xa0, 0x18, 0x00, 0x08, 0x00, - 0x1a, 0x40, 0x00, 0x04, 0x2c, - 0x33, 0x00, 0x01, 0x2f, 0x20, - 0xd8, 0x03, 0x00, 0x00, 0x18, - 0xe0, 0x00, 0x02, 0x00, 0x00, - } -}; diff --git a/trunk/drivers/net/ethernet/xscale/ixp2000/ixpdev.c b/trunk/drivers/net/ethernet/xscale/ixp2000/ixpdev.c deleted file mode 100644 index 45008377c8bf..000000000000 --- a/trunk/drivers/net/ethernet/xscale/ixp2000/ixpdev.c +++ /dev/null @@ -1,437 +0,0 @@ -/* - * IXP2000 MSF network device driver - * Copyright (C) 2004, 2005 Lennert Buytenhek - * Dedicated to Marija Kulikova. - * - * 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 "ixp2400_rx.ucode" -#include "ixp2400_tx.ucode" -#include "ixpdev_priv.h" -#include "ixpdev.h" -#include "pm3386.h" - -#define DRV_MODULE_VERSION "0.2" - -static int nds_count; -static struct net_device **nds; -static int nds_open; -static void (*set_port_admin_status)(int port, int up); - -static struct ixpdev_rx_desc * const rx_desc = - (struct ixpdev_rx_desc *)(IXP2000_SRAM0_VIRT_BASE + RX_BUF_DESC_BASE); -static struct ixpdev_tx_desc * const tx_desc = - (struct ixpdev_tx_desc *)(IXP2000_SRAM0_VIRT_BASE + TX_BUF_DESC_BASE); -static int tx_pointer; - - -static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct ixpdev_priv *ip = netdev_priv(dev); - struct ixpdev_tx_desc *desc; - int entry; - unsigned long flags; - - if (unlikely(skb->len > PAGE_SIZE)) { - /* @@@ Count drops. */ - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - entry = tx_pointer; - tx_pointer = (tx_pointer + 1) % TX_BUF_COUNT; - - desc = tx_desc + entry; - desc->pkt_length = skb->len; - desc->channel = ip->channel; - - skb_copy_and_csum_dev(skb, phys_to_virt(desc->buf_addr)); - dev_kfree_skb(skb); - - ixp2000_reg_write(RING_TX_PENDING, - TX_BUF_DESC_BASE + (entry * sizeof(struct ixpdev_tx_desc))); - - local_irq_save(flags); - ip->tx_queue_entries++; - if (ip->tx_queue_entries == TX_BUF_COUNT_PER_CHAN) - netif_stop_queue(dev); - local_irq_restore(flags); - - return NETDEV_TX_OK; -} - - -static int ixpdev_rx(struct net_device *dev, int processed, int budget) -{ - while (processed < budget) { - struct ixpdev_rx_desc *desc; - struct sk_buff *skb; - void *buf; - u32 _desc; - - _desc = ixp2000_reg_read(RING_RX_DONE); - if (_desc == 0) - return 0; - - desc = rx_desc + - ((_desc - RX_BUF_DESC_BASE) / sizeof(struct ixpdev_rx_desc)); - buf = phys_to_virt(desc->buf_addr); - - if (desc->pkt_length < 4 || desc->pkt_length > PAGE_SIZE) { - printk(KERN_ERR "ixp2000: rx err, length %d\n", - desc->pkt_length); - goto err; - } - - if (desc->channel < 0 || desc->channel >= nds_count) { - printk(KERN_ERR "ixp2000: rx err, channel %d\n", - desc->channel); - goto err; - } - - /* @@@ Make FCS stripping configurable. */ - desc->pkt_length -= 4; - - if (unlikely(!netif_running(nds[desc->channel]))) - goto err; - - skb = netdev_alloc_skb_ip_align(dev, desc->pkt_length); - if (likely(skb != NULL)) { - skb_copy_to_linear_data(skb, buf, desc->pkt_length); - skb_put(skb, desc->pkt_length); - skb->protocol = eth_type_trans(skb, nds[desc->channel]); - - netif_receive_skb(skb); - } - -err: - ixp2000_reg_write(RING_RX_PENDING, _desc); - processed++; - } - - return processed; -} - -/* dev always points to nds[0]. */ -static int ixpdev_poll(struct napi_struct *napi, int budget) -{ - struct ixpdev_priv *ip = container_of(napi, struct ixpdev_priv, napi); - struct net_device *dev = ip->dev; - int rx; - - rx = 0; - do { - ixp2000_reg_write(IXP2000_IRQ_THD_RAW_STATUS_A_0, 0x00ff); - - rx = ixpdev_rx(dev, rx, budget); - if (rx >= budget) - break; - } while (ixp2000_reg_read(IXP2000_IRQ_THD_RAW_STATUS_A_0) & 0x00ff); - - napi_complete(napi); - ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_SET_A_0, 0x00ff); - - return rx; -} - -static void ixpdev_tx_complete(void) -{ - int channel; - u32 wake; - - wake = 0; - while (1) { - struct ixpdev_priv *ip; - u32 desc; - int entry; - - desc = ixp2000_reg_read(RING_TX_DONE); - if (desc == 0) - break; - - /* @@@ Check whether entries come back in order. */ - entry = (desc - TX_BUF_DESC_BASE) / sizeof(struct ixpdev_tx_desc); - channel = tx_desc[entry].channel; - - if (channel < 0 || channel >= nds_count) { - printk(KERN_ERR "ixp2000: txcomp channel index " - "out of bounds (%d, %.8i, %d)\n", - channel, (unsigned int)desc, entry); - continue; - } - - ip = netdev_priv(nds[channel]); - if (ip->tx_queue_entries == TX_BUF_COUNT_PER_CHAN) - wake |= 1 << channel; - ip->tx_queue_entries--; - } - - for (channel = 0; wake != 0; channel++) { - if (wake & (1 << channel)) { - netif_wake_queue(nds[channel]); - wake &= ~(1 << channel); - } - } -} - -static irqreturn_t ixpdev_interrupt(int irq, void *dev_id) -{ - u32 status; - - status = ixp2000_reg_read(IXP2000_IRQ_THD_STATUS_A_0); - if (status == 0) - return IRQ_NONE; - - /* - * Any of the eight receive units signaled RX? - */ - if (status & 0x00ff) { - struct net_device *dev = nds[0]; - struct ixpdev_priv *ip = netdev_priv(dev); - - ixp2000_reg_wrb(IXP2000_IRQ_THD_ENABLE_CLEAR_A_0, 0x00ff); - if (likely(napi_schedule_prep(&ip->napi))) { - __napi_schedule(&ip->napi); - } else { - printk(KERN_CRIT "ixp2000: irq while polling!!\n"); - } - } - - /* - * Any of the eight transmit units signaled TXdone? - */ - if (status & 0xff00) { - ixp2000_reg_wrb(IXP2000_IRQ_THD_RAW_STATUS_A_0, 0xff00); - ixpdev_tx_complete(); - } - - return IRQ_HANDLED; -} - -#ifdef CONFIG_NET_POLL_CONTROLLER -static void ixpdev_poll_controller(struct net_device *dev) -{ - disable_irq(IRQ_IXP2000_THDA0); - ixpdev_interrupt(IRQ_IXP2000_THDA0, dev); - enable_irq(IRQ_IXP2000_THDA0); -} -#endif - -static int ixpdev_open(struct net_device *dev) -{ - struct ixpdev_priv *ip = netdev_priv(dev); - int err; - - napi_enable(&ip->napi); - if (!nds_open++) { - err = request_irq(IRQ_IXP2000_THDA0, ixpdev_interrupt, - IRQF_SHARED, "ixp2000_eth", nds); - if (err) { - nds_open--; - napi_disable(&ip->napi); - return err; - } - - ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_SET_A_0, 0xffff); - } - - set_port_admin_status(ip->channel, 1); - netif_start_queue(dev); - - return 0; -} - -static int ixpdev_close(struct net_device *dev) -{ - struct ixpdev_priv *ip = netdev_priv(dev); - - netif_stop_queue(dev); - napi_disable(&ip->napi); - set_port_admin_status(ip->channel, 0); - - if (!--nds_open) { - ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_CLEAR_A_0, 0xffff); - free_irq(IRQ_IXP2000_THDA0, nds); - } - - return 0; -} - -static struct net_device_stats *ixpdev_get_stats(struct net_device *dev) -{ - struct ixpdev_priv *ip = netdev_priv(dev); - - pm3386_get_stats(ip->channel, &(dev->stats)); - - return &(dev->stats); -} - -static const struct net_device_ops ixpdev_netdev_ops = { - .ndo_open = ixpdev_open, - .ndo_stop = ixpdev_close, - .ndo_start_xmit = ixpdev_xmit, - .ndo_change_mtu = eth_change_mtu, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = eth_mac_addr, - .ndo_get_stats = ixpdev_get_stats, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = ixpdev_poll_controller, -#endif -}; - -struct net_device *ixpdev_alloc(int channel, int sizeof_priv) -{ - struct net_device *dev; - struct ixpdev_priv *ip; - - dev = alloc_etherdev(sizeof_priv); - if (dev == NULL) - return NULL; - - dev->netdev_ops = &ixpdev_netdev_ops; - - dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; - - ip = netdev_priv(dev); - ip->dev = dev; - netif_napi_add(dev, &ip->napi, ixpdev_poll, 64); - ip->channel = channel; - ip->tx_queue_entries = 0; - - return dev; -} - -int ixpdev_init(int __nds_count, struct net_device **__nds, - void (*__set_port_admin_status)(int port, int up)) -{ - int i; - int err; - - BUILD_BUG_ON(RX_BUF_COUNT > 192 || TX_BUF_COUNT > 192); - - printk(KERN_INFO "IXP2000 MSF ethernet driver %s\n", DRV_MODULE_VERSION); - - nds_count = __nds_count; - nds = __nds; - set_port_admin_status = __set_port_admin_status; - - for (i = 0; i < RX_BUF_COUNT; i++) { - void *buf; - - buf = (void *)get_zeroed_page(GFP_KERNEL); - if (buf == NULL) { - err = -ENOMEM; - while (--i >= 0) - free_page((unsigned long)phys_to_virt(rx_desc[i].buf_addr)); - goto err_out; - } - rx_desc[i].buf_addr = virt_to_phys(buf); - rx_desc[i].buf_length = PAGE_SIZE; - } - - /* @@@ Maybe we shouldn't be preallocating TX buffers. */ - for (i = 0; i < TX_BUF_COUNT; i++) { - void *buf; - - buf = (void *)get_zeroed_page(GFP_KERNEL); - if (buf == NULL) { - err = -ENOMEM; - while (--i >= 0) - free_page((unsigned long)phys_to_virt(tx_desc[i].buf_addr)); - goto err_free_rx; - } - tx_desc[i].buf_addr = virt_to_phys(buf); - } - - /* 256 entries, ring status set means 'empty', base address 0x0000. */ - ixp2000_reg_write(RING_RX_PENDING_BASE, 0x44000000); - ixp2000_reg_write(RING_RX_PENDING_HEAD, 0x00000000); - ixp2000_reg_write(RING_RX_PENDING_TAIL, 0x00000000); - - /* 256 entries, ring status set means 'full', base address 0x0400. */ - ixp2000_reg_write(RING_RX_DONE_BASE, 0x40000400); - ixp2000_reg_write(RING_RX_DONE_HEAD, 0x00000000); - ixp2000_reg_write(RING_RX_DONE_TAIL, 0x00000000); - - for (i = 0; i < RX_BUF_COUNT; i++) { - ixp2000_reg_write(RING_RX_PENDING, - RX_BUF_DESC_BASE + (i * sizeof(struct ixpdev_rx_desc))); - } - - ixp2000_uengine_load(0, &ixp2400_rx); - ixp2000_uengine_start_contexts(0, 0xff); - - /* 256 entries, ring status set means 'empty', base address 0x0800. */ - ixp2000_reg_write(RING_TX_PENDING_BASE, 0x44000800); - ixp2000_reg_write(RING_TX_PENDING_HEAD, 0x00000000); - ixp2000_reg_write(RING_TX_PENDING_TAIL, 0x00000000); - - /* 256 entries, ring status set means 'full', base address 0x0c00. */ - ixp2000_reg_write(RING_TX_DONE_BASE, 0x40000c00); - ixp2000_reg_write(RING_TX_DONE_HEAD, 0x00000000); - ixp2000_reg_write(RING_TX_DONE_TAIL, 0x00000000); - - ixp2000_uengine_load(1, &ixp2400_tx); - ixp2000_uengine_start_contexts(1, 0xff); - - for (i = 0; i < nds_count; i++) { - err = register_netdev(nds[i]); - if (err) { - while (--i >= 0) - unregister_netdev(nds[i]); - goto err_free_tx; - } - } - - for (i = 0; i < nds_count; i++) { - printk(KERN_INFO "%s: IXP2000 MSF ethernet (port %d), %pM.\n", - nds[i]->name, i, nds[i]->dev_addr); - } - - return 0; - -err_free_tx: - for (i = 0; i < TX_BUF_COUNT; i++) - free_page((unsigned long)phys_to_virt(tx_desc[i].buf_addr)); - -err_free_rx: - for (i = 0; i < RX_BUF_COUNT; i++) - free_page((unsigned long)phys_to_virt(rx_desc[i].buf_addr)); - -err_out: - return err; -} - -void ixpdev_deinit(void) -{ - int i; - - /* @@@ Flush out pending packets. */ - - for (i = 0; i < nds_count; i++) - unregister_netdev(nds[i]); - - ixp2000_uengine_stop_contexts(1, 0xff); - ixp2000_uengine_stop_contexts(0, 0xff); - ixp2000_uengine_reset(0x3); - - for (i = 0; i < TX_BUF_COUNT; i++) - free_page((unsigned long)phys_to_virt(tx_desc[i].buf_addr)); - - for (i = 0; i < RX_BUF_COUNT; i++) - free_page((unsigned long)phys_to_virt(rx_desc[i].buf_addr)); -} diff --git a/trunk/drivers/net/ethernet/xscale/ixp2000/ixpdev.h b/trunk/drivers/net/ethernet/xscale/ixp2000/ixpdev.h deleted file mode 100644 index 391ece623243..000000000000 --- a/trunk/drivers/net/ethernet/xscale/ixp2000/ixpdev.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * IXP2000 MSF network device driver - * Copyright (C) 2004, 2005 Lennert Buytenhek - * Dedicated to Marija Kulikova. - * - * 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 __IXPDEV_H -#define __IXPDEV_H - -struct ixpdev_priv -{ - struct net_device *dev; - struct napi_struct napi; - int channel; - int tx_queue_entries; -}; - -struct net_device *ixpdev_alloc(int channel, int sizeof_priv); -int ixpdev_init(int num_ports, struct net_device **nds, - void (*set_port_admin_status)(int port, int up)); -void ixpdev_deinit(void); - - -#endif diff --git a/trunk/drivers/net/ethernet/xscale/ixp2000/ixpdev_priv.h b/trunk/drivers/net/ethernet/xscale/ixp2000/ixpdev_priv.h deleted file mode 100644 index 86aa08ea0c33..000000000000 --- a/trunk/drivers/net/ethernet/xscale/ixp2000/ixpdev_priv.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * IXP2000 MSF network device driver - * Copyright (C) 2004, 2005 Lennert Buytenhek - * Dedicated to Marija Kulikova. - * - * 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 __IXPDEV_PRIV_H -#define __IXPDEV_PRIV_H - -#define RX_BUF_DESC_BASE 0x00001000 -#define RX_BUF_COUNT ((3 * PAGE_SIZE) / (4 * sizeof(struct ixpdev_rx_desc))) -#define TX_BUF_DESC_BASE 0x00002000 -#define TX_BUF_COUNT ((3 * PAGE_SIZE) / (4 * sizeof(struct ixpdev_tx_desc))) -#define TX_BUF_COUNT_PER_CHAN (TX_BUF_COUNT / 4) - -#define RING_RX_PENDING ((u32 *)IXP2000_SCRATCH_RING_VIRT_BASE) -#define RING_RX_DONE ((u32 *)(IXP2000_SCRATCH_RING_VIRT_BASE + 4)) -#define RING_TX_PENDING ((u32 *)(IXP2000_SCRATCH_RING_VIRT_BASE + 8)) -#define RING_TX_DONE ((u32 *)(IXP2000_SCRATCH_RING_VIRT_BASE + 12)) - -#define SCRATCH_REG(x) ((u32 *)(IXP2000_GLOBAL_REG_VIRT_BASE | 0x0800 | (x))) -#define RING_RX_PENDING_BASE SCRATCH_REG(0x00) -#define RING_RX_PENDING_HEAD SCRATCH_REG(0x04) -#define RING_RX_PENDING_TAIL SCRATCH_REG(0x08) -#define RING_RX_DONE_BASE SCRATCH_REG(0x10) -#define RING_RX_DONE_HEAD SCRATCH_REG(0x14) -#define RING_RX_DONE_TAIL SCRATCH_REG(0x18) -#define RING_TX_PENDING_BASE SCRATCH_REG(0x20) -#define RING_TX_PENDING_HEAD SCRATCH_REG(0x24) -#define RING_TX_PENDING_TAIL SCRATCH_REG(0x28) -#define RING_TX_DONE_BASE SCRATCH_REG(0x30) -#define RING_TX_DONE_HEAD SCRATCH_REG(0x34) -#define RING_TX_DONE_TAIL SCRATCH_REG(0x38) - -struct ixpdev_rx_desc -{ - u32 buf_addr; - u32 buf_length; - u32 channel; - u32 pkt_length; -}; - -struct ixpdev_tx_desc -{ - u32 buf_addr; - u32 pkt_length; - u32 channel; - u32 unused; -}; - - -#endif diff --git a/trunk/drivers/net/ethernet/xscale/ixp2000/pm3386.c b/trunk/drivers/net/ethernet/xscale/ixp2000/pm3386.c deleted file mode 100644 index e08d3f9863b8..000000000000 --- a/trunk/drivers/net/ethernet/xscale/ixp2000/pm3386.c +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Helper functions for the PM3386s on the Radisys ENP2611 - * Copyright (C) 2004, 2005 Lennert Buytenhek - * Dedicated to Marija Kulikova. - * - * 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 "pm3386.h" - -/* - * Read from register 'reg' of PM3386 device 'pm'. - */ -static u16 pm3386_reg_read(int pm, int reg) -{ - void *_reg; - u16 value; - - _reg = (void *)ENP2611_PM3386_0_VIRT_BASE; - if (pm == 1) - _reg = (void *)ENP2611_PM3386_1_VIRT_BASE; - - value = *((volatile u16 *)(_reg + (reg << 1))); - -// printk(KERN_INFO "pm3386_reg_read(%d, %.3x) = %.8x\n", pm, reg, value); - - return value; -} - -/* - * Write to register 'reg' of PM3386 device 'pm', and perform - * a readback from the identification register. - */ -static void pm3386_reg_write(int pm, int reg, u16 value) -{ - void *_reg; - u16 dummy; - -// printk(KERN_INFO "pm3386_reg_write(%d, %.3x, %.8x)\n", pm, reg, value); - - _reg = (void *)ENP2611_PM3386_0_VIRT_BASE; - if (pm == 1) - _reg = (void *)ENP2611_PM3386_1_VIRT_BASE; - - *((volatile u16 *)(_reg + (reg << 1))) = value; - - dummy = *((volatile u16 *)_reg); - __asm__ __volatile__("mov %0, %0" : "+r" (dummy)); -} - -/* - * Read from port 'port' register 'reg', where the registers - * for the different ports are 'spacing' registers apart. - */ -static u16 pm3386_port_reg_read(int port, int _reg, int spacing) -{ - int reg; - - reg = _reg; - if (port & 1) - reg += spacing; - - return pm3386_reg_read(port >> 1, reg); -} - -/* - * Write to port 'port' register 'reg', where the registers - * for the different ports are 'spacing' registers apart. - */ -static void pm3386_port_reg_write(int port, int _reg, int spacing, u16 value) -{ - int reg; - - reg = _reg; - if (port & 1) - reg += spacing; - - pm3386_reg_write(port >> 1, reg, value); -} - -int pm3386_secondary_present(void) -{ - return pm3386_reg_read(1, 0) == 0x3386; -} - -void pm3386_reset(void) -{ - u8 mac[3][6]; - int secondary; - - secondary = pm3386_secondary_present(); - - /* Save programmed MAC addresses. */ - pm3386_get_mac(0, mac[0]); - pm3386_get_mac(1, mac[1]); - if (secondary) - pm3386_get_mac(2, mac[2]); - - /* Assert analog and digital reset. */ - pm3386_reg_write(0, 0x002, 0x0060); - if (secondary) - pm3386_reg_write(1, 0x002, 0x0060); - mdelay(1); - - /* Deassert analog reset. */ - pm3386_reg_write(0, 0x002, 0x0062); - if (secondary) - pm3386_reg_write(1, 0x002, 0x0062); - mdelay(10); - - /* Deassert digital reset. */ - pm3386_reg_write(0, 0x002, 0x0063); - if (secondary) - pm3386_reg_write(1, 0x002, 0x0063); - mdelay(10); - - /* Restore programmed MAC addresses. */ - pm3386_set_mac(0, mac[0]); - pm3386_set_mac(1, mac[1]); - if (secondary) - pm3386_set_mac(2, mac[2]); - - /* Disable carrier on all ports. */ - pm3386_set_carrier(0, 0); - pm3386_set_carrier(1, 0); - if (secondary) - pm3386_set_carrier(2, 0); -} - -static u16 swaph(u16 x) -{ - return ((x << 8) | (x >> 8)) & 0xffff; -} - -int pm3386_port_count(void) -{ - return 2 + pm3386_secondary_present(); -} - -void pm3386_init_port(int port) -{ - int pm = port >> 1; - - /* - * Work around ENP2611 bootloader programming MAC address - * in reverse. - */ - if (pm3386_port_reg_read(port, 0x30a, 0x100) == 0x0000 && - (pm3386_port_reg_read(port, 0x309, 0x100) & 0xff00) == 0x5000) { - u16 temp[3]; - - temp[0] = pm3386_port_reg_read(port, 0x308, 0x100); - temp[1] = pm3386_port_reg_read(port, 0x309, 0x100); - temp[2] = pm3386_port_reg_read(port, 0x30a, 0x100); - pm3386_port_reg_write(port, 0x308, 0x100, swaph(temp[2])); - pm3386_port_reg_write(port, 0x309, 0x100, swaph(temp[1])); - pm3386_port_reg_write(port, 0x30a, 0x100, swaph(temp[0])); - } - - /* - * Initialise narrowbanding mode. See application note 2010486 - * for more information. (@@@ We also need to issue a reset - * when ROOL or DOOL are detected.) - */ - pm3386_port_reg_write(port, 0x708, 0x10, 0xd055); - udelay(500); - pm3386_port_reg_write(port, 0x708, 0x10, 0x5055); - - /* - * SPI-3 ingress block. Set 64 bytes SPI-3 burst size - * towards SPI-3 bridge. - */ - pm3386_port_reg_write(port, 0x122, 0x20, 0x0002); - - /* - * Enable ingress protocol checking, and soft reset the - * SPI-3 ingress block. - */ - pm3386_reg_write(pm, 0x103, 0x0003); - while (!(pm3386_reg_read(pm, 0x103) & 0x80)) - ; - - /* - * SPI-3 egress block. Gather 12288 bytes of the current - * packet in the TX fifo before initiating transmit on the - * SERDES interface. (Prevents TX underflows.) - */ - pm3386_port_reg_write(port, 0x221, 0x20, 0x0007); - - /* - * Enforce odd parity from the SPI-3 bridge, and soft reset - * the SPI-3 egress block. - */ - pm3386_reg_write(pm, 0x203, 0x000d & ~(4 << (port & 1))); - while ((pm3386_reg_read(pm, 0x203) & 0x000c) != 0x000c) - ; - - /* - * EGMAC block. Set this channels to reject long preambles, - * not send or transmit PAUSE frames, enable preamble checking, - * disable frame length checking, enable FCS appending, enable - * TX frame padding. - */ - pm3386_port_reg_write(port, 0x302, 0x100, 0x0113); - - /* - * Soft reset the EGMAC block. - */ - pm3386_port_reg_write(port, 0x301, 0x100, 0x8000); - pm3386_port_reg_write(port, 0x301, 0x100, 0x0000); - - /* - * Auto-sense autonegotiation status. - */ - pm3386_port_reg_write(port, 0x306, 0x100, 0x0100); - - /* - * Allow reception of jumbo frames. - */ - pm3386_port_reg_write(port, 0x310, 0x100, 9018); - - /* - * Allow transmission of jumbo frames. - */ - pm3386_port_reg_write(port, 0x336, 0x100, 9018); - - /* @@@ Should set 0x337/0x437 (RX forwarding threshold.) */ - - /* - * Set autonegotiation parameters to 'no PAUSE, full duplex.' - */ - pm3386_port_reg_write(port, 0x31c, 0x100, 0x0020); - - /* - * Enable and restart autonegotiation. - */ - pm3386_port_reg_write(port, 0x318, 0x100, 0x0003); - pm3386_port_reg_write(port, 0x318, 0x100, 0x0002); -} - -void pm3386_get_mac(int port, u8 *mac) -{ - u16 temp; - - temp = pm3386_port_reg_read(port, 0x308, 0x100); - mac[0] = temp & 0xff; - mac[1] = (temp >> 8) & 0xff; - - temp = pm3386_port_reg_read(port, 0x309, 0x100); - mac[2] = temp & 0xff; - mac[3] = (temp >> 8) & 0xff; - - temp = pm3386_port_reg_read(port, 0x30a, 0x100); - mac[4] = temp & 0xff; - mac[5] = (temp >> 8) & 0xff; -} - -void pm3386_set_mac(int port, u8 *mac) -{ - pm3386_port_reg_write(port, 0x308, 0x100, (mac[1] << 8) | mac[0]); - pm3386_port_reg_write(port, 0x309, 0x100, (mac[3] << 8) | mac[2]); - pm3386_port_reg_write(port, 0x30a, 0x100, (mac[5] << 8) | mac[4]); -} - -static u32 pm3386_get_stat(int port, u16 base) -{ - u32 value; - - value = pm3386_port_reg_read(port, base, 0x100); - value |= pm3386_port_reg_read(port, base + 1, 0x100) << 16; - - return value; -} - -void pm3386_get_stats(int port, struct net_device_stats *stats) -{ - /* - * Snapshot statistics counters. - */ - pm3386_port_reg_write(port, 0x500, 0x100, 0x0001); - while (pm3386_port_reg_read(port, 0x500, 0x100) & 0x0001) - ; - - memset(stats, 0, sizeof(*stats)); - - stats->rx_packets = pm3386_get_stat(port, 0x510); - stats->tx_packets = pm3386_get_stat(port, 0x590); - stats->rx_bytes = pm3386_get_stat(port, 0x514); - stats->tx_bytes = pm3386_get_stat(port, 0x594); - /* @@@ Add other stats. */ -} - -void pm3386_set_carrier(int port, int state) -{ - pm3386_port_reg_write(port, 0x703, 0x10, state ? 0x1001 : 0x0000); -} - -int pm3386_is_link_up(int port) -{ - u16 temp; - - temp = pm3386_port_reg_read(port, 0x31a, 0x100); - temp = pm3386_port_reg_read(port, 0x31a, 0x100); - - return !!(temp & 0x0002); -} - -void pm3386_enable_rx(int port) -{ - u16 temp; - - temp = pm3386_port_reg_read(port, 0x303, 0x100); - temp |= 0x1000; - pm3386_port_reg_write(port, 0x303, 0x100, temp); -} - -void pm3386_disable_rx(int port) -{ - u16 temp; - - temp = pm3386_port_reg_read(port, 0x303, 0x100); - temp &= 0xefff; - pm3386_port_reg_write(port, 0x303, 0x100, temp); -} - -void pm3386_enable_tx(int port) -{ - u16 temp; - - temp = pm3386_port_reg_read(port, 0x303, 0x100); - temp |= 0x4000; - pm3386_port_reg_write(port, 0x303, 0x100, temp); -} - -void pm3386_disable_tx(int port) -{ - u16 temp; - - temp = pm3386_port_reg_read(port, 0x303, 0x100); - temp &= 0xbfff; - pm3386_port_reg_write(port, 0x303, 0x100, temp); -} - -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/net/ethernet/xscale/ixp2000/pm3386.h b/trunk/drivers/net/ethernet/xscale/ixp2000/pm3386.h deleted file mode 100644 index cc4183dca911..000000000000 --- a/trunk/drivers/net/ethernet/xscale/ixp2000/pm3386.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Helper functions for the PM3386s on the Radisys ENP2611 - * Copyright (C) 2004, 2005 Lennert Buytenhek - * Dedicated to Marija Kulikova. - * - * 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 __PM3386_H -#define __PM3386_H - -void pm3386_reset(void); -int pm3386_port_count(void); -void pm3386_init_port(int port); -void pm3386_get_mac(int port, u8 *mac); -void pm3386_set_mac(int port, u8 *mac); -void pm3386_get_stats(int port, struct net_device_stats *stats); -void pm3386_set_carrier(int port, int state); -int pm3386_is_link_up(int port); -void pm3386_enable_rx(int port); -void pm3386_disable_rx(int port); -void pm3386_enable_tx(int port); -void pm3386_disable_tx(int port); - - -#endif diff --git a/trunk/drivers/net/ethernet/xscale/ixp4xx_eth.c b/trunk/drivers/net/ethernet/xscale/ixp4xx_eth.c index 41a8b5a9849e..482648fcf0b6 100644 --- a/trunk/drivers/net/ethernet/xscale/ixp4xx_eth.c +++ b/trunk/drivers/net/ethernet/xscale/ixp4xx_eth.c @@ -1002,12 +1002,41 @@ static int ixp4xx_nway_reset(struct net_device *dev) return phy_start_aneg(port->phydev); } +int ixp46x_phc_index = -1; + +static int ixp4xx_get_ts_info(struct net_device *dev, + struct ethtool_ts_info *info) +{ + if (!cpu_is_ixp46x()) { + info->so_timestamping = + SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE; + info->phc_index = -1; + return 0; + } + info->so_timestamping = + SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + info->phc_index = ixp46x_phc_index; + info->tx_types = + (1 << HWTSTAMP_TX_OFF) | + (1 << HWTSTAMP_TX_ON); + info->rx_filters = + (1 << HWTSTAMP_FILTER_NONE) | + (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | + (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ); + return 0; +} + static const struct ethtool_ops ixp4xx_ethtool_ops = { .get_drvinfo = ixp4xx_get_drvinfo, .get_settings = ixp4xx_get_settings, .set_settings = ixp4xx_set_settings, .nway_reset = ixp4xx_nway_reset, .get_link = ethtool_op_get_link, + .get_ts_info = ixp4xx_get_ts_info, }; diff --git a/trunk/drivers/net/hippi/rrunner.c b/trunk/drivers/net/hippi/rrunner.c index 168c8f41d09f..d4719632ffc6 100644 --- a/trunk/drivers/net/hippi/rrunner.c +++ b/trunk/drivers/net/hippi/rrunner.c @@ -113,10 +113,9 @@ static int __devinit rr_init_one(struct pci_dev *pdev, SET_NETDEV_DEV(dev, &pdev->dev); - if (pci_request_regions(pdev, "rrunner")) { - ret = -EIO; + ret = pci_request_regions(pdev, "rrunner"); + if (ret < 0) goto out; - } pci_set_drvdata(pdev, dev); @@ -124,11 +123,8 @@ static int __devinit rr_init_one(struct pci_dev *pdev, spin_lock_init(&rrpriv->lock); - dev->irq = pdev->irq; dev->netdev_ops = &rr_netdev_ops; - dev->base_addr = pci_resource_start(pdev, 0); - /* display version info if adapter is found */ if (!version_disp) { /* set display flag to TRUE so that */ @@ -146,16 +142,15 @@ static int __devinit rr_init_one(struct pci_dev *pdev, pci_set_master(pdev); printk(KERN_INFO "%s: Essential RoadRunner serial HIPPI " - "at 0x%08lx, irq %i, PCI latency %i\n", dev->name, - dev->base_addr, dev->irq, pci_latency); + "at 0x%llx, irq %i, PCI latency %i\n", dev->name, + (unsigned long long)pci_resource_start(pdev, 0), + pdev->irq, pci_latency); /* - * Remap the regs into kernel space. + * Remap the MMIO regs into kernel space. */ - - rrpriv->regs = ioremap(dev->base_addr, 0x1000); - - if (!rrpriv->regs){ + rrpriv->regs = pci_iomap(pdev, 0, 0x1000); + if (!rrpriv->regs) { printk(KERN_ERR "%s: Unable to map I/O register, " "RoadRunner will be disabled.\n", dev->name); ret = -EIO; @@ -202,8 +197,6 @@ static int __devinit rr_init_one(struct pci_dev *pdev, rr_init(dev); - dev->base_addr = 0; - ret = register_netdev(dev); if (ret) goto out; @@ -217,7 +210,7 @@ static int __devinit rr_init_one(struct pci_dev *pdev, pci_free_consistent(pdev, TX_TOTAL_SIZE, rrpriv->tx_ring, rrpriv->tx_ring_dma); if (rrpriv->regs) - iounmap(rrpriv->regs); + pci_iounmap(pdev, rrpriv->regs); if (pdev) { pci_release_regions(pdev); pci_set_drvdata(pdev, NULL); @@ -231,29 +224,26 @@ static int __devinit rr_init_one(struct pci_dev *pdev, static void __devexit rr_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); + struct rr_private *rr = netdev_priv(dev); - if (dev) { - struct rr_private *rr = netdev_priv(dev); - - if (!(readl(&rr->regs->HostCtrl) & NIC_HALTED)){ - printk(KERN_ERR "%s: trying to unload running NIC\n", - dev->name); - writel(HALT_NIC, &rr->regs->HostCtrl); - } - - pci_free_consistent(pdev, EVT_RING_SIZE, rr->evt_ring, - rr->evt_ring_dma); - pci_free_consistent(pdev, RX_TOTAL_SIZE, rr->rx_ring, - rr->rx_ring_dma); - pci_free_consistent(pdev, TX_TOTAL_SIZE, rr->tx_ring, - rr->tx_ring_dma); - unregister_netdev(dev); - iounmap(rr->regs); - free_netdev(dev); - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); + if (!(readl(&rr->regs->HostCtrl) & NIC_HALTED)) { + printk(KERN_ERR "%s: trying to unload running NIC\n", + dev->name); + writel(HALT_NIC, &rr->regs->HostCtrl); } + + unregister_netdev(dev); + pci_free_consistent(pdev, EVT_RING_SIZE, rr->evt_ring, + rr->evt_ring_dma); + pci_free_consistent(pdev, RX_TOTAL_SIZE, rr->rx_ring, + rr->rx_ring_dma); + pci_free_consistent(pdev, TX_TOTAL_SIZE, rr->tx_ring, + rr->tx_ring_dma); + pci_iounmap(pdev, rr->regs); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + free_netdev(dev); } @@ -1229,9 +1219,9 @@ static int rr_open(struct net_device *dev) readl(®s->HostCtrl); spin_unlock_irqrestore(&rrpriv->lock, flags); - if (request_irq(dev->irq, rr_interrupt, IRQF_SHARED, dev->name, dev)) { + if (request_irq(pdev->irq, rr_interrupt, IRQF_SHARED, dev->name, dev)) { printk(KERN_WARNING "%s: Requested IRQ %d is busy\n", - dev->name, dev->irq); + dev->name, pdev->irq); ecode = -EAGAIN; goto error; } @@ -1338,16 +1328,15 @@ static void rr_dump(struct net_device *dev) static int rr_close(struct net_device *dev) { - struct rr_private *rrpriv; - struct rr_regs __iomem *regs; + struct rr_private *rrpriv = netdev_priv(dev); + struct rr_regs __iomem *regs = rrpriv->regs; + struct pci_dev *pdev = rrpriv->pci_dev; unsigned long flags; u32 tmp; short i; netif_stop_queue(dev); - rrpriv = netdev_priv(dev); - regs = rrpriv->regs; /* * Lock to make sure we are not cleaning up while another CPU @@ -1386,15 +1375,15 @@ static int rr_close(struct net_device *dev) rr_raz_tx(rrpriv, dev); rr_raz_rx(rrpriv, dev); - pci_free_consistent(rrpriv->pci_dev, 256 * sizeof(struct ring_ctrl), + pci_free_consistent(pdev, 256 * sizeof(struct ring_ctrl), rrpriv->rx_ctrl, rrpriv->rx_ctrl_dma); rrpriv->rx_ctrl = NULL; - pci_free_consistent(rrpriv->pci_dev, sizeof(struct rr_info), - rrpriv->info, rrpriv->info_dma); + pci_free_consistent(pdev, sizeof(struct rr_info), rrpriv->info, + rrpriv->info_dma); rrpriv->info = NULL; - free_irq(dev->irq, dev); + free_irq(pdev->irq, dev); spin_unlock_irqrestore(&rrpriv->lock, flags); return 0; diff --git a/trunk/drivers/net/hyperv/hyperv_net.h b/trunk/drivers/net/hyperv/hyperv_net.h index c35824552792..4ffcd57b011b 100644 --- a/trunk/drivers/net/hyperv/hyperv_net.h +++ b/trunk/drivers/net/hyperv/hyperv_net.h @@ -27,6 +27,7 @@ #include #include +#include /* Fwd declaration */ struct hv_netvsc_packet; @@ -506,295 +507,6 @@ struct netvsc_device { void *extension; }; - -/* Status codes */ - - -#ifndef STATUS_SUCCESS -#define STATUS_SUCCESS (0x00000000L) -#endif - -#ifndef STATUS_UNSUCCESSFUL -#define STATUS_UNSUCCESSFUL (0xC0000001L) -#endif - -#ifndef STATUS_PENDING -#define STATUS_PENDING (0x00000103L) -#endif - -#ifndef STATUS_INSUFFICIENT_RESOURCES -#define STATUS_INSUFFICIENT_RESOURCES (0xC000009AL) -#endif - -#ifndef STATUS_BUFFER_OVERFLOW -#define STATUS_BUFFER_OVERFLOW (0x80000005L) -#endif - -#ifndef STATUS_NOT_SUPPORTED -#define STATUS_NOT_SUPPORTED (0xC00000BBL) -#endif - -#define RNDIS_STATUS_SUCCESS (STATUS_SUCCESS) -#define RNDIS_STATUS_PENDING (STATUS_PENDING) -#define RNDIS_STATUS_NOT_RECOGNIZED (0x00010001L) -#define RNDIS_STATUS_NOT_COPIED (0x00010002L) -#define RNDIS_STATUS_NOT_ACCEPTED (0x00010003L) -#define RNDIS_STATUS_CALL_ACTIVE (0x00010007L) - -#define RNDIS_STATUS_ONLINE (0x40010003L) -#define RNDIS_STATUS_RESET_START (0x40010004L) -#define RNDIS_STATUS_RESET_END (0x40010005L) -#define RNDIS_STATUS_RING_STATUS (0x40010006L) -#define RNDIS_STATUS_CLOSED (0x40010007L) -#define RNDIS_STATUS_WAN_LINE_UP (0x40010008L) -#define RNDIS_STATUS_WAN_LINE_DOWN (0x40010009L) -#define RNDIS_STATUS_WAN_FRAGMENT (0x4001000AL) -#define RNDIS_STATUS_MEDIA_CONNECT (0x4001000BL) -#define RNDIS_STATUS_MEDIA_DISCONNECT (0x4001000CL) -#define RNDIS_STATUS_HARDWARE_LINE_UP (0x4001000DL) -#define RNDIS_STATUS_HARDWARE_LINE_DOWN (0x4001000EL) -#define RNDIS_STATUS_INTERFACE_UP (0x4001000FL) -#define RNDIS_STATUS_INTERFACE_DOWN (0x40010010L) -#define RNDIS_STATUS_MEDIA_BUSY (0x40010011L) -#define RNDIS_STATUS_MEDIA_SPECIFIC_INDICATION (0x40010012L) -#define RNDIS_STATUS_WW_INDICATION RDIA_SPECIFIC_INDICATION -#define RNDIS_STATUS_LINK_SPEED_CHANGE (0x40010013L) - -#define RNDIS_STATUS_NOT_RESETTABLE (0x80010001L) -#define RNDIS_STATUS_SOFT_ERRORS (0x80010003L) -#define RNDIS_STATUS_HARD_ERRORS (0x80010004L) -#define RNDIS_STATUS_BUFFER_OVERFLOW (STATUS_BUFFER_OVERFLOW) - -#define RNDIS_STATUS_FAILURE (STATUS_UNSUCCESSFUL) -#define RNDIS_STATUS_RESOURCES (STATUS_INSUFFICIENT_RESOURCES) -#define RNDIS_STATUS_CLOSING (0xC0010002L) -#define RNDIS_STATUS_BAD_VERSION (0xC0010004L) -#define RNDIS_STATUS_BAD_CHARACTERISTICS (0xC0010005L) -#define RNDIS_STATUS_ADAPTER_NOT_FOUND (0xC0010006L) -#define RNDIS_STATUS_OPEN_FAILED (0xC0010007L) -#define RNDIS_STATUS_DEVICE_FAILED (0xC0010008L) -#define RNDIS_STATUS_MULTICAST_FULL (0xC0010009L) -#define RNDIS_STATUS_MULTICAST_EXISTS (0xC001000AL) -#define RNDIS_STATUS_MULTICAST_NOT_FOUND (0xC001000BL) -#define RNDIS_STATUS_REQUEST_ABORTED (0xC001000CL) -#define RNDIS_STATUS_RESET_IN_PROGRESS (0xC001000DL) -#define RNDIS_STATUS_CLOSING_INDICATING (0xC001000EL) -#define RNDIS_STATUS_NOT_SUPPORTED (STATUS_NOT_SUPPORTED) -#define RNDIS_STATUS_INVALID_PACKET (0xC001000FL) -#define RNDIS_STATUS_OPEN_LIST_FULL (0xC0010010L) -#define RNDIS_STATUS_ADAPTER_NOT_READY (0xC0010011L) -#define RNDIS_STATUS_ADAPTER_NOT_OPEN (0xC0010012L) -#define RNDIS_STATUS_NOT_INDICATING (0xC0010013L) -#define RNDIS_STATUS_INVALID_LENGTH (0xC0010014L) -#define RNDIS_STATUS_INVALID_DATA (0xC0010015L) -#define RNDIS_STATUS_BUFFER_TOO_SHORT (0xC0010016L) -#define RNDIS_STATUS_INVALID_OID (0xC0010017L) -#define RNDIS_STATUS_ADAPTER_REMOVED (0xC0010018L) -#define RNDIS_STATUS_UNSUPPORTED_MEDIA (0xC0010019L) -#define RNDIS_STATUS_GROUP_ADDRESS_IN_USE (0xC001001AL) -#define RNDIS_STATUS_FILE_NOT_FOUND (0xC001001BL) -#define RNDIS_STATUS_ERROR_READING_FILE (0xC001001CL) -#define RNDIS_STATUS_ALREADY_MAPPED (0xC001001DL) -#define RNDIS_STATUS_RESOURCE_CONFLICT (0xC001001EL) -#define RNDIS_STATUS_NO_CABLE (0xC001001FL) - -#define RNDIS_STATUS_INVALID_SAP (0xC0010020L) -#define RNDIS_STATUS_SAP_IN_USE (0xC0010021L) -#define RNDIS_STATUS_INVALID_ADDRESS (0xC0010022L) -#define RNDIS_STATUS_VC_NOT_ACTIVATED (0xC0010023L) -#define RNDIS_STATUS_DEST_OUT_OF_ORDER (0xC0010024L) -#define RNDIS_STATUS_VC_NOT_AVAILABLE (0xC0010025L) -#define RNDIS_STATUS_CELLRATE_NOT_AVAILABLE (0xC0010026L) -#define RNDIS_STATUS_INCOMPATABLE_QOS (0xC0010027L) -#define RNDIS_STATUS_AAL_PARAMS_UNSUPPORTED (0xC0010028L) -#define RNDIS_STATUS_NO_ROUTE_TO_DESTINATION (0xC0010029L) - -#define RNDIS_STATUS_TOKEN_RING_OPEN_ERROR (0xC0011000L) - -/* Object Identifiers used by NdisRequest Query/Set Information */ -/* General Objects */ -#define RNDIS_OID_GEN_SUPPORTED_LIST 0x00010101 -#define RNDIS_OID_GEN_HARDWARE_STATUS 0x00010102 -#define RNDIS_OID_GEN_MEDIA_SUPPORTED 0x00010103 -#define RNDIS_OID_GEN_MEDIA_IN_USE 0x00010104 -#define RNDIS_OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105 -#define RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106 -#define RNDIS_OID_GEN_LINK_SPEED 0x00010107 -#define RNDIS_OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108 -#define RNDIS_OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109 -#define RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A -#define RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B -#define RNDIS_OID_GEN_VENDOR_ID 0x0001010C -#define RNDIS_OID_GEN_VENDOR_DESCRIPTION 0x0001010D -#define RNDIS_OID_GEN_CURRENT_PACKET_FILTER 0x0001010E -#define RNDIS_OID_GEN_CURRENT_LOOKAHEAD 0x0001010F -#define RNDIS_OID_GEN_DRIVER_VERSION 0x00010110 -#define RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111 -#define RNDIS_OID_GEN_PROTOCOL_OPTIONS 0x00010112 -#define RNDIS_OID_GEN_MAC_OPTIONS 0x00010113 -#define RNDIS_OID_GEN_MEDIA_CONNECT_STATUS 0x00010114 -#define RNDIS_OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115 -#define RNDIS_OID_GEN_VENDOR_DRIVER_VERSION 0x00010116 -#define RNDIS_OID_GEN_NETWORK_LAYER_ADDRESSES 0x00010118 -#define RNDIS_OID_GEN_TRANSPORT_HEADER_OFFSET 0x00010119 -#define RNDIS_OID_GEN_MACHINE_NAME 0x0001021A -#define RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER 0x0001021B - -#define RNDIS_OID_GEN_XMIT_OK 0x00020101 -#define RNDIS_OID_GEN_RCV_OK 0x00020102 -#define RNDIS_OID_GEN_XMIT_ERROR 0x00020103 -#define RNDIS_OID_GEN_RCV_ERROR 0x00020104 -#define RNDIS_OID_GEN_RCV_NO_BUFFER 0x00020105 - -#define RNDIS_OID_GEN_DIRECTED_BYTES_XMIT 0x00020201 -#define RNDIS_OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202 -#define RNDIS_OID_GEN_MULTICAST_BYTES_XMIT 0x00020203 -#define RNDIS_OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204 -#define RNDIS_OID_GEN_BROADCAST_BYTES_XMIT 0x00020205 -#define RNDIS_OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206 -#define RNDIS_OID_GEN_DIRECTED_BYTES_RCV 0x00020207 -#define RNDIS_OID_GEN_DIRECTED_FRAMES_RCV 0x00020208 -#define RNDIS_OID_GEN_MULTICAST_BYTES_RCV 0x00020209 -#define RNDIS_OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A -#define RNDIS_OID_GEN_BROADCAST_BYTES_RCV 0x0002020B -#define RNDIS_OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C - -#define RNDIS_OID_GEN_RCV_CRC_ERROR 0x0002020D -#define RNDIS_OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E - -#define RNDIS_OID_GEN_GET_TIME_CAPS 0x0002020F -#define RNDIS_OID_GEN_GET_NETCARD_TIME 0x00020210 - -/* These are connection-oriented general OIDs. */ -/* These replace the above OIDs for connection-oriented media. */ -#define RNDIS_OID_GEN_CO_SUPPORTED_LIST 0x00010101 -#define RNDIS_OID_GEN_CO_HARDWARE_STATUS 0x00010102 -#define RNDIS_OID_GEN_CO_MEDIA_SUPPORTED 0x00010103 -#define RNDIS_OID_GEN_CO_MEDIA_IN_USE 0x00010104 -#define RNDIS_OID_GEN_CO_LINK_SPEED 0x00010105 -#define RNDIS_OID_GEN_CO_VENDOR_ID 0x00010106 -#define RNDIS_OID_GEN_CO_VENDOR_DESCRIPTION 0x00010107 -#define RNDIS_OID_GEN_CO_DRIVER_VERSION 0x00010108 -#define RNDIS_OID_GEN_CO_PROTOCOL_OPTIONS 0x00010109 -#define RNDIS_OID_GEN_CO_MAC_OPTIONS 0x0001010A -#define RNDIS_OID_GEN_CO_MEDIA_CONNECT_STATUS 0x0001010B -#define RNDIS_OID_GEN_CO_VENDOR_DRIVER_VERSION 0x0001010C -#define RNDIS_OID_GEN_CO_MINIMUM_LINK_SPEED 0x0001010D - -#define RNDIS_OID_GEN_CO_GET_TIME_CAPS 0x00010201 -#define RNDIS_OID_GEN_CO_GET_NETCARD_TIME 0x00010202 - -/* These are connection-oriented statistics OIDs. */ -#define RNDIS_OID_GEN_CO_XMIT_PDUS_OK 0x00020101 -#define RNDIS_OID_GEN_CO_RCV_PDUS_OK 0x00020102 -#define RNDIS_OID_GEN_CO_XMIT_PDUS_ERROR 0x00020103 -#define RNDIS_OID_GEN_CO_RCV_PDUS_ERROR 0x00020104 -#define RNDIS_OID_GEN_CO_RCV_PDUS_NO_BUFFER 0x00020105 - - -#define RNDIS_OID_GEN_CO_RCV_CRC_ERROR 0x00020201 -#define RNDIS_OID_GEN_CO_TRANSMIT_QUEUE_LENGTH 0x00020202 -#define RNDIS_OID_GEN_CO_BYTES_XMIT 0x00020203 -#define RNDIS_OID_GEN_CO_BYTES_RCV 0x00020204 -#define RNDIS_OID_GEN_CO_BYTES_XMIT_OUTSTANDING 0x00020205 -#define RNDIS_OID_GEN_CO_NETCARD_LOAD 0x00020206 - -/* These are objects for Connection-oriented media call-managers. */ -#define RNDIS_OID_CO_ADD_PVC 0xFF000001 -#define RNDIS_OID_CO_DELETE_PVC 0xFF000002 -#define RNDIS_OID_CO_GET_CALL_INFORMATION 0xFF000003 -#define RNDIS_OID_CO_ADD_ADDRESS 0xFF000004 -#define RNDIS_OID_CO_DELETE_ADDRESS 0xFF000005 -#define RNDIS_OID_CO_GET_ADDRESSES 0xFF000006 -#define RNDIS_OID_CO_ADDRESS_CHANGE 0xFF000007 -#define RNDIS_OID_CO_SIGNALING_ENABLED 0xFF000008 -#define RNDIS_OID_CO_SIGNALING_DISABLED 0xFF000009 - -/* 802.3 Objects (Ethernet) */ -#define RNDIS_OID_802_3_PERMANENT_ADDRESS 0x01010101 -#define RNDIS_OID_802_3_CURRENT_ADDRESS 0x01010102 -#define RNDIS_OID_802_3_MULTICAST_LIST 0x01010103 -#define RNDIS_OID_802_3_MAXIMUM_LIST_SIZE 0x01010104 -#define RNDIS_OID_802_3_MAC_OPTIONS 0x01010105 - -#define NDIS_802_3_MAC_OPTION_PRIORITY 0x00000001 - -#define RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT 0x01020101 -#define RNDIS_OID_802_3_XMIT_ONE_COLLISION 0x01020102 -#define RNDIS_OID_802_3_XMIT_MORE_COLLISIONS 0x01020103 - -#define RNDIS_OID_802_3_XMIT_DEFERRED 0x01020201 -#define RNDIS_OID_802_3_XMIT_MAX_COLLISIONS 0x01020202 -#define RNDIS_OID_802_3_RCV_OVERRUN 0x01020203 -#define RNDIS_OID_802_3_XMIT_UNDERRUN 0x01020204 -#define RNDIS_OID_802_3_XMIT_HEARTBEAT_FAILURE 0x01020205 -#define RNDIS_OID_802_3_XMIT_TIMES_CRS_LOST 0x01020206 -#define RNDIS_OID_802_3_XMIT_LATE_COLLISIONS 0x01020207 - -/* Remote NDIS message types */ -#define REMOTE_NDIS_PACKET_MSG 0x00000001 -#define REMOTE_NDIS_INITIALIZE_MSG 0x00000002 -#define REMOTE_NDIS_HALT_MSG 0x00000003 -#define REMOTE_NDIS_QUERY_MSG 0x00000004 -#define REMOTE_NDIS_SET_MSG 0x00000005 -#define REMOTE_NDIS_RESET_MSG 0x00000006 -#define REMOTE_NDIS_INDICATE_STATUS_MSG 0x00000007 -#define REMOTE_NDIS_KEEPALIVE_MSG 0x00000008 - -#define REMOTE_CONDIS_MP_CREATE_VC_MSG 0x00008001 -#define REMOTE_CONDIS_MP_DELETE_VC_MSG 0x00008002 -#define REMOTE_CONDIS_MP_ACTIVATE_VC_MSG 0x00008005 -#define REMOTE_CONDIS_MP_DEACTIVATE_VC_MSG 0x00008006 -#define REMOTE_CONDIS_INDICATE_STATUS_MSG 0x00008007 - -/* Remote NDIS message completion types */ -#define REMOTE_NDIS_INITIALIZE_CMPLT 0x80000002 -#define REMOTE_NDIS_QUERY_CMPLT 0x80000004 -#define REMOTE_NDIS_SET_CMPLT 0x80000005 -#define REMOTE_NDIS_RESET_CMPLT 0x80000006 -#define REMOTE_NDIS_KEEPALIVE_CMPLT 0x80000008 - -#define REMOTE_CONDIS_MP_CREATE_VC_CMPLT 0x80008001 -#define REMOTE_CONDIS_MP_DELETE_VC_CMPLT 0x80008002 -#define REMOTE_CONDIS_MP_ACTIVATE_VC_CMPLT 0x80008005 -#define REMOTE_CONDIS_MP_DEACTIVATE_VC_CMPLT 0x80008006 - -/* - * Reserved message type for private communication between lower-layer host - * driver and remote device, if necessary. - */ -#define REMOTE_NDIS_BUS_MSG 0xff000001 - -/* Defines for DeviceFlags in struct rndis_initialize_complete */ -#define RNDIS_DF_CONNECTIONLESS 0x00000001 -#define RNDIS_DF_CONNECTION_ORIENTED 0x00000002 -#define RNDIS_DF_RAW_DATA 0x00000004 - -/* Remote NDIS medium types. */ -#define RNDIS_MEDIUM_802_3 0x00000000 -#define RNDIS_MEDIUM_802_5 0x00000001 -#define RNDIS_MEDIUM_FDDI 0x00000002 -#define RNDIS_MEDIUM_WAN 0x00000003 -#define RNDIS_MEDIUM_LOCAL_TALK 0x00000004 -#define RNDIS_MEDIUM_ARCNET_RAW 0x00000006 -#define RNDIS_MEDIUM_ARCNET_878_2 0x00000007 -#define RNDIS_MEDIUM_ATM 0x00000008 -#define RNDIS_MEDIUM_WIRELESS_WAN 0x00000009 -#define RNDIS_MEDIUM_IRDA 0x0000000a -#define RNDIS_MEDIUM_CO_WAN 0x0000000b -/* Not a real medium, defined as an upper-bound */ -#define RNDIS_MEDIUM_MAX 0x0000000d - - -/* Remote NDIS medium connection states. */ -#define RNDIS_MEDIA_STATE_CONNECTED 0x00000000 -#define RNDIS_MEDIA_STATE_DISCONNECTED 0x00000001 - -/* Remote NDIS version numbers */ -#define RNDIS_MAJOR_VERSION 0x00000001 -#define RNDIS_MINOR_VERSION 0x00000000 - - /* NdisInitialize message */ struct rndis_initialize_request { u32 req_id; diff --git a/trunk/drivers/net/hyperv/netvsc.c b/trunk/drivers/net/hyperv/netvsc.c index d025c83cd12a..8b919471472f 100644 --- a/trunk/drivers/net/hyperv/netvsc.c +++ b/trunk/drivers/net/hyperv/netvsc.c @@ -428,6 +428,24 @@ int netvsc_device_remove(struct hv_device *device) return 0; } + +#define RING_AVAIL_PERCENT_HIWATER 20 +#define RING_AVAIL_PERCENT_LOWATER 10 + +/* + * Get the percentage of available bytes to write in the ring. + * The return value is in range from 0 to 100. + */ +static inline u32 hv_ringbuf_avail_percent( + struct hv_ring_buffer_info *ring_info) +{ + u32 avail_read, avail_write; + + hv_get_ringbuffer_availbytes(ring_info, &avail_read, &avail_write); + + return avail_write * 100 / ring_info->ring_datasize; +} + static void netvsc_send_completion(struct hv_device *device, struct vmpacket_descriptor *packet) { @@ -455,6 +473,8 @@ static void netvsc_send_completion(struct hv_device *device, complete(&net_device->channel_init_wait); } else if (nvsp_packet->hdr.msg_type == NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE) { + int num_outstanding_sends; + /* Get the send context */ nvsc_packet = (struct hv_netvsc_packet *)(unsigned long) packet->trans_id; @@ -463,10 +483,14 @@ static void netvsc_send_completion(struct hv_device *device, nvsc_packet->completion.send.send_completion( nvsc_packet->completion.send.send_completion_ctx); - atomic_dec(&net_device->num_outstanding_sends); + num_outstanding_sends = + atomic_dec_return(&net_device->num_outstanding_sends); - if (netif_queue_stopped(ndev) && !net_device->start_remove) - netif_wake_queue(ndev); + 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); } else { netdev_err(ndev, "Unknown send completion packet type- " "%d received!!\n", nvsp_packet->hdr.msg_type); @@ -519,10 +543,19 @@ 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) < + RING_AVAIL_PERCENT_LOWATER) { + netif_stop_queue(ndev); + if (atomic_read(&net_device-> + num_outstanding_sends) < 1) + netif_wake_queue(ndev); + } } else if (ret == -EAGAIN) { netif_stop_queue(ndev); - if (atomic_read(&net_device->num_outstanding_sends) < 1) + if (atomic_read(&net_device->num_outstanding_sends) < 1) { netif_wake_queue(ndev); + ret = -ENOSPC; + } } else { netdev_err(ndev, "Unable to send packet %p ret %d\n", packet, ret); diff --git a/trunk/drivers/net/hyperv/netvsc_drv.c b/trunk/drivers/net/hyperv/netvsc_drv.c index 2d59138db7f3..8f8ed3320425 100644 --- a/trunk/drivers/net/hyperv/netvsc_drv.c +++ b/trunk/drivers/net/hyperv/netvsc_drv.c @@ -211,9 +211,13 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) net->stats.tx_packets++; } else { kfree(packet); + if (ret != -EAGAIN) { + dev_kfree_skb_any(skb); + net->stats.tx_dropped++; + } } - return ret ? NETDEV_TX_BUSY : NETDEV_TX_OK; + return (ret == -EAGAIN) ? NETDEV_TX_BUSY : NETDEV_TX_OK; } /* diff --git a/trunk/drivers/net/hyperv/rndis_filter.c b/trunk/drivers/net/hyperv/rndis_filter.c index d6be64bcefd4..981ebb115637 100644 --- a/trunk/drivers/net/hyperv/rndis_filter.c +++ b/trunk/drivers/net/hyperv/rndis_filter.c @@ -129,8 +129,8 @@ static void dump_rndis_message(struct hv_device *hv_dev, netdev = net_device->ndev; switch (rndis_msg->ndis_msg_type) { - case REMOTE_NDIS_PACKET_MSG: - netdev_dbg(netdev, "REMOTE_NDIS_PACKET_MSG (len %u, " + case RNDIS_MSG_PACKET: + netdev_dbg(netdev, "RNDIS_MSG_PACKET (len %u, " "data offset %u data len %u, # oob %u, " "oob offset %u, oob len %u, pkt offset %u, " "pkt len %u\n", @@ -144,8 +144,8 @@ static void dump_rndis_message(struct hv_device *hv_dev, rndis_msg->msg.pkt.per_pkt_info_len); break; - case REMOTE_NDIS_INITIALIZE_CMPLT: - netdev_dbg(netdev, "REMOTE_NDIS_INITIALIZE_CMPLT " + case RNDIS_MSG_INIT_C: + netdev_dbg(netdev, "RNDIS_MSG_INIT_C " "(len %u, id 0x%x, status 0x%x, major %d, minor %d, " "device flags %d, max xfer size 0x%x, max pkts %u, " "pkt aligned %u)\n", @@ -162,8 +162,8 @@ static void dump_rndis_message(struct hv_device *hv_dev, pkt_alignment_factor); break; - case REMOTE_NDIS_QUERY_CMPLT: - netdev_dbg(netdev, "REMOTE_NDIS_QUERY_CMPLT " + case RNDIS_MSG_QUERY_C: + netdev_dbg(netdev, "RNDIS_MSG_QUERY_C " "(len %u, id 0x%x, status 0x%x, buf len %u, " "buf offset %u)\n", rndis_msg->msg_len, @@ -175,16 +175,16 @@ static void dump_rndis_message(struct hv_device *hv_dev, info_buf_offset); break; - case REMOTE_NDIS_SET_CMPLT: + case RNDIS_MSG_SET_C: netdev_dbg(netdev, - "REMOTE_NDIS_SET_CMPLT (len %u, id 0x%x, status 0x%x)\n", + "RNDIS_MSG_SET_C (len %u, id 0x%x, status 0x%x)\n", rndis_msg->msg_len, rndis_msg->msg.set_complete.req_id, rndis_msg->msg.set_complete.status); break; - case REMOTE_NDIS_INDICATE_STATUS_MSG: - netdev_dbg(netdev, "REMOTE_NDIS_INDICATE_STATUS_MSG " + case RNDIS_MSG_INDICATE: + netdev_dbg(netdev, "RNDIS_MSG_INDICATE " "(len %u, status 0x%x, buf len %u, buf offset %u)\n", rndis_msg->msg_len, rndis_msg->msg.indicate_status.status, @@ -264,14 +264,14 @@ static void rndis_filter_receive_response(struct rndis_device *dev, sizeof(struct rndis_filter_packet)); if (resp->ndis_msg_type == - REMOTE_NDIS_RESET_CMPLT) { + RNDIS_MSG_RESET_C) { /* does not have a request id field */ request->response_msg.msg.reset_complete. - status = STATUS_BUFFER_OVERFLOW; + status = RNDIS_STATUS_BUFFER_OVERFLOW; } else { request->response_msg.msg. init_complete.status = - STATUS_BUFFER_OVERFLOW; + RNDIS_STATUS_BUFFER_OVERFLOW; } } @@ -415,19 +415,19 @@ int rndis_filter_receive(struct hv_device *dev, dump_rndis_message(dev, rndis_msg); switch (rndis_msg->ndis_msg_type) { - case REMOTE_NDIS_PACKET_MSG: + case RNDIS_MSG_PACKET: /* data msg */ rndis_filter_receive_data(rndis_dev, rndis_msg, pkt); break; - case REMOTE_NDIS_INITIALIZE_CMPLT: - case REMOTE_NDIS_QUERY_CMPLT: - case REMOTE_NDIS_SET_CMPLT: + case RNDIS_MSG_INIT_C: + case RNDIS_MSG_QUERY_C: + case RNDIS_MSG_SET_C: /* completion msgs */ rndis_filter_receive_response(rndis_dev, rndis_msg); break; - case REMOTE_NDIS_INDICATE_STATUS_MSG: + case RNDIS_MSG_INDICATE: /* notification msgs */ rndis_filter_receive_indicate_status(rndis_dev, rndis_msg); break; @@ -456,7 +456,7 @@ static int rndis_filter_query_device(struct rndis_device *dev, u32 oid, return -EINVAL; *result_size = 0; - request = get_rndis_request(dev, REMOTE_NDIS_QUERY_MSG, + request = get_rndis_request(dev, RNDIS_MSG_QUERY, RNDIS_MESSAGE_SIZE(struct rndis_query_request)); if (!request) { ret = -ENOMEM; @@ -536,7 +536,7 @@ int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter) ndev = dev->net_dev->ndev; - request = get_rndis_request(dev, REMOTE_NDIS_SET_MSG, + request = get_rndis_request(dev, RNDIS_MSG_SET, RNDIS_MESSAGE_SIZE(struct rndis_set_request) + sizeof(u32)); if (!request) { @@ -588,7 +588,7 @@ static int rndis_filter_init_device(struct rndis_device *dev) u32 status; int ret, t; - request = get_rndis_request(dev, REMOTE_NDIS_INITIALIZE_MSG, + request = get_rndis_request(dev, RNDIS_MSG_INIT, RNDIS_MESSAGE_SIZE(struct rndis_initialize_request)); if (!request) { ret = -ENOMEM; @@ -641,7 +641,7 @@ static void rndis_filter_halt_device(struct rndis_device *dev) struct rndis_halt_request *halt; /* Attempt to do a rndis device halt */ - request = get_rndis_request(dev, REMOTE_NDIS_HALT_MSG, + request = get_rndis_request(dev, RNDIS_MSG_HALT, RNDIS_MESSAGE_SIZE(struct rndis_halt_request)); if (!request) goto cleanup; @@ -805,7 +805,7 @@ int rndis_filter_send(struct hv_device *dev, if (isvlan) rndis_msg_size += NDIS_VLAN_PPI_SIZE; - rndis_msg->ndis_msg_type = REMOTE_NDIS_PACKET_MSG; + rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET; rndis_msg->msg_len = pkt->total_data_buflen + rndis_msg_size; diff --git a/trunk/drivers/net/irda/Kconfig b/trunk/drivers/net/irda/Kconfig index 468047866c8c..595205406d73 100644 --- a/trunk/drivers/net/irda/Kconfig +++ b/trunk/drivers/net/irda/Kconfig @@ -211,8 +211,8 @@ config KINGSUN_DONGLE kingsun-sir. config EP7211_DONGLE - tristate "EP7211 I/R support" - depends on IRTTY_SIR && ARCH_EP7211 && IRDA && EXPERIMENTAL + tristate "Cirrus Logic clps711x I/R support" + depends on IRTTY_SIR && ARCH_CLPS711X && IRDA && EXPERIMENTAL help Say Y here if you want to build support for the Cirrus logic EP7211 chipset's infrared module. @@ -316,13 +316,13 @@ config AU1000_FIR tristate "Alchemy IrDA SIR/FIR" depends on IRDA && MIPS_ALCHEMY help - Say Y/M here to build suppor the the IrDA peripheral on the + Say Y/M here to build support the IrDA peripheral on the Alchemy Au1000 and Au1100 SoCs. Say M to build a module; it will be called au1k_ir.ko config SMC_IRCC_FIR - tristate "SMSC IrCC (EXPERIMENTAL)" - depends on EXPERIMENTAL && IRDA && ISA_DMA_API + tristate "SMSC IrCC" + depends on IRDA && ISA_DMA_API help Say Y here if you want to build support for the SMC Infrared Communications Controller. It is used in a wide variety of diff --git a/trunk/drivers/net/irda/donauboe.c b/trunk/drivers/net/irda/donauboe.c index 4351296dde32..510b9c8d23a9 100644 --- a/trunk/drivers/net/irda/donauboe.c +++ b/trunk/drivers/net/irda/donauboe.c @@ -1710,7 +1710,7 @@ toshoboe_gotosleep (struct pci_dev *pci_dev, pm_message_t crap) /* Flush all packets */ while ((i--) && (self->txpending)) - udelay (10000); + msleep(10); spin_lock_irqsave(&self->spinlock, flags); diff --git a/trunk/drivers/net/irda/irda-usb.c b/trunk/drivers/net/irda/irda-usb.c index 72f687b40d66..f9a86bdb12fa 100644 --- a/trunk/drivers/net/irda/irda-usb.c +++ b/trunk/drivers/net/irda/irda-usb.c @@ -1671,7 +1671,7 @@ static int irda_usb_probe(struct usb_interface *intf, /* Is this really necessary? (no, except maybe for broken devices) */ if (usb_reset_configuration (dev) < 0) { - err("reset_configuration failed"); + dev_err(&intf->dev, "reset_configuration failed\n"); ret = -EIO; goto err_out_3; } diff --git a/trunk/drivers/net/irda/kingsun-sir.c b/trunk/drivers/net/irda/kingsun-sir.c index 79aebeee928c..7b4833874ef5 100644 --- a/trunk/drivers/net/irda/kingsun-sir.c +++ b/trunk/drivers/net/irda/kingsun-sir.c @@ -134,14 +134,16 @@ static void kingsun_send_irq(struct urb *urb) /* in process of stopping, just drop data */ if (!netif_running(kingsun->netdev)) { - err("kingsun_send_irq: Network not running!"); + dev_err(&kingsun->usbdev->dev, + "kingsun_send_irq: Network not running!\n"); return; } /* unlink, shutdown, unplug, other nasties */ if (urb->status != 0) { - err("kingsun_send_irq: urb asynchronously failed - %d", - urb->status); + dev_err(&kingsun->usbdev->dev, + "kingsun_send_irq: urb asynchronously failed - %d\n", + urb->status); } netif_wake_queue(netdev); } @@ -177,7 +179,8 @@ static netdev_tx_t kingsun_hard_xmit(struct sk_buff *skb, kingsun, 1); if ((ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC))) { - err("kingsun_hard_xmit: failed tx_urb submit: %d", ret); + dev_err(&kingsun->usbdev->dev, + "kingsun_hard_xmit: failed tx_urb submit: %d\n", ret); switch (ret) { case -ENODEV: case -EPIPE: @@ -211,8 +214,9 @@ static void kingsun_rcv_irq(struct urb *urb) /* unlink, shutdown, unplug, other nasties */ if (urb->status != 0) { - err("kingsun_rcv_irq: urb asynchronously failed - %d", - urb->status); + dev_err(&kingsun->usbdev->dev, + "kingsun_rcv_irq: urb asynchronously failed - %d\n", + urb->status); kingsun->receiving = 0; return; } @@ -238,8 +242,9 @@ static void kingsun_rcv_irq(struct urb *urb) ? 1 : 0; } } else if (urb->actual_length > 0) { - err("%s(): Unexpected response length, expected %d got %d", - __func__, kingsun->max_rx, urb->actual_length); + dev_err(&kingsun->usbdev->dev, + "%s(): Unexpected response length, expected %d got %d\n", + __func__, kingsun->max_rx, urb->actual_length); } /* This urb has already been filled in kingsun_net_open */ ret = usb_submit_urb(urb, GFP_ATOMIC); @@ -286,7 +291,7 @@ static int kingsun_net_open(struct net_device *netdev) sprintf(hwname, "usb#%d", kingsun->usbdev->devnum); kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname); if (!kingsun->irlap) { - err("kingsun-sir: irlap_open failed"); + dev_err(&kingsun->usbdev->dev, "irlap_open failed\n"); goto free_mem; } @@ -298,7 +303,8 @@ static int kingsun_net_open(struct net_device *netdev) kingsun->rx_urb->status = 0; err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); if (err) { - err("kingsun-sir: first urb-submit failed: %d", err); + dev_err(&kingsun->usbdev->dev, + "first urb-submit failed: %d\n", err); goto close_irlap; } @@ -446,13 +452,15 @@ static int kingsun_probe(struct usb_interface *intf, */ interface = intf->cur_altsetting; if (interface->desc.bNumEndpoints != 2) { - err("kingsun-sir: expected 2 endpoints, found %d", - interface->desc.bNumEndpoints); + dev_err(&intf->dev, + "kingsun-sir: expected 2 endpoints, found %d\n", + interface->desc.bNumEndpoints); return -ENODEV; } endpoint = &interface->endpoint[KINGSUN_EP_IN].desc; if (!usb_endpoint_is_int_in(endpoint)) { - err("kingsun-sir: endpoint 0 is not interrupt IN"); + dev_err(&intf->dev, + "kingsun-sir: endpoint 0 is not interrupt IN\n"); return -ENODEV; } @@ -460,14 +468,16 @@ static int kingsun_probe(struct usb_interface *intf, pipe = usb_rcvintpipe(dev, ep_in); maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); if (maxp_in > 255 || maxp_in <= 1) { - err("%s: endpoint 0 has max packet size %d not in range", - __FILE__, maxp_in); + dev_err(&intf->dev, + "endpoint 0 has max packet size %d not in range\n", + maxp_in); return -ENODEV; } endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc; if (!usb_endpoint_is_int_out(endpoint)) { - err("kingsun-sir: endpoint 1 is not interrupt OUT"); + dev_err(&intf->dev, + "kingsun-sir: endpoint 1 is not interrupt OUT\n"); return -ENODEV; } diff --git a/trunk/drivers/net/irda/ks959-sir.c b/trunk/drivers/net/irda/ks959-sir.c index abe689dffc72..824e2a93fe8a 100644 --- a/trunk/drivers/net/irda/ks959-sir.c +++ b/trunk/drivers/net/irda/ks959-sir.c @@ -247,8 +247,9 @@ static void ks959_speed_irq(struct urb *urb) { /* unlink, shutdown, unplug, other nasties */ if (urb->status != 0) { - err("ks959_speed_irq: urb asynchronously failed - %d", - urb->status); + dev_err(&urb->dev->dev, + "ks959_speed_irq: urb asynchronously failed - %d\n", + urb->status); } } @@ -332,14 +333,16 @@ static void ks959_send_irq(struct urb *urb) /* in process of stopping, just drop data */ if (!netif_running(kingsun->netdev)) { - err("ks959_send_irq: Network not running!"); + dev_err(&kingsun->usbdev->dev, + "ks959_send_irq: Network not running!\n"); return; } /* unlink, shutdown, unplug, other nasties */ if (urb->status != 0) { - err("ks959_send_irq: urb asynchronously failed - %d", - urb->status); + dev_err(&kingsun->usbdev->dev, + "ks959_send_irq: urb asynchronously failed - %d\n", + urb->status); return; } @@ -358,8 +361,9 @@ static void ks959_send_irq(struct urb *urb) if (kingsun->tx_buf_clear_used > 0) { /* There is more data to be sent */ if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) { - err("ks959_send_irq: failed tx_urb submit: %d", - ret); + dev_err(&kingsun->usbdev->dev, + "ks959_send_irq: failed tx_urb submit: %d\n", + ret); switch (ret) { case -ENODEV: case -EPIPE: @@ -407,7 +411,8 @@ static netdev_tx_t ks959_hard_xmit(struct sk_buff *skb, kingsun->tx_buf_clear_used = wraplen; if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) { - err("ks959_hard_xmit: failed tx_urb submit: %d", ret); + dev_err(&kingsun->usbdev->dev, + "ks959_hard_xmit: failed tx_urb submit: %d\n", ret); switch (ret) { case -ENODEV: case -EPIPE: @@ -442,8 +447,9 @@ static void ks959_rcv_irq(struct urb *urb) /* unlink, shutdown, unplug, other nasties */ if (urb->status != 0) { - err("kingsun_rcv_irq: urb asynchronously failed - %d", - urb->status); + dev_err(&kingsun->usbdev->dev, + "kingsun_rcv_irq: urb asynchronously failed - %d\n", + urb->status); kingsun->receiving = 0; return; } @@ -536,7 +542,7 @@ static int ks959_net_open(struct net_device *netdev) sprintf(hwname, "usb#%d", kingsun->usbdev->devnum); kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname); if (!kingsun->irlap) { - err("ks959-sir: irlap_open failed"); + dev_err(&kingsun->usbdev->dev, "irlap_open failed\n"); goto free_mem; } @@ -549,7 +555,8 @@ static int ks959_net_open(struct net_device *netdev) kingsun->rx_urb->status = 0; err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); if (err) { - err("ks959-sir: first urb-submit failed: %d", err); + dev_err(&kingsun->usbdev->dev, + "first urb-submit failed: %d\n", err); goto close_irlap; } diff --git a/trunk/drivers/net/irda/ksdazzle-sir.c b/trunk/drivers/net/irda/ksdazzle-sir.c index f8c01088eeb7..5a278ab83c2f 100644 --- a/trunk/drivers/net/irda/ksdazzle-sir.c +++ b/trunk/drivers/net/irda/ksdazzle-sir.c @@ -168,10 +168,10 @@ struct ksdazzle_cb { static void ksdazzle_speed_irq(struct urb *urb) { /* unlink, shutdown, unplug, other nasties */ - if (urb->status != 0) { - err("ksdazzle_speed_irq: urb asynchronously failed - %d", - urb->status); - } + if (urb->status != 0) + dev_err(&urb->dev->dev, + "ksdazzle_speed_irq: urb asynchronously failed - %d\n", + urb->status); } /* Send a control request to change speed of the dongle */ @@ -245,14 +245,16 @@ static void ksdazzle_send_irq(struct urb *urb) /* in process of stopping, just drop data */ if (!netif_running(kingsun->netdev)) { - err("ksdazzle_send_irq: Network not running!"); + dev_err(&kingsun->usbdev->dev, + "ksdazzle_send_irq: Network not running!\n"); return; } /* unlink, shutdown, unplug, other nasties */ if (urb->status != 0) { - err("ksdazzle_send_irq: urb asynchronously failed - %d", - urb->status); + dev_err(&kingsun->usbdev->dev, + "ksdazzle_send_irq: urb asynchronously failed - %d\n", + urb->status); return; } @@ -271,7 +273,9 @@ static void ksdazzle_send_irq(struct urb *urb) if (kingsun->tx_buf_clear_used > 0) { /* There is more data to be sent */ if ((ret = ksdazzle_submit_tx_fragment(kingsun)) != 0) { - err("ksdazzle_send_irq: failed tx_urb submit: %d", ret); + dev_err(&kingsun->usbdev->dev, + "ksdazzle_send_irq: failed tx_urb submit: %d\n", + ret); switch (ret) { case -ENODEV: case -EPIPE: @@ -320,7 +324,8 @@ static netdev_tx_t ksdazzle_hard_xmit(struct sk_buff *skb, kingsun->tx_buf_clear_used = wraplen; if ((ret = ksdazzle_submit_tx_fragment(kingsun)) != 0) { - err("ksdazzle_hard_xmit: failed tx_urb submit: %d", ret); + dev_err(&kingsun->usbdev->dev, + "ksdazzle_hard_xmit: failed tx_urb submit: %d\n", ret); switch (ret) { case -ENODEV: case -EPIPE: @@ -355,8 +360,9 @@ static void ksdazzle_rcv_irq(struct urb *urb) /* unlink, shutdown, unplug, other nasties */ if (urb->status != 0) { - err("ksdazzle_rcv_irq: urb asynchronously failed - %d", - urb->status); + dev_err(&kingsun->usbdev->dev, + "ksdazzle_rcv_irq: urb asynchronously failed - %d\n", + urb->status); kingsun->receiving = 0; return; } @@ -430,7 +436,7 @@ static int ksdazzle_net_open(struct net_device *netdev) sprintf(hwname, "usb#%d", kingsun->usbdev->devnum); kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname); if (!kingsun->irlap) { - err("ksdazzle-sir: irlap_open failed"); + dev_err(&kingsun->usbdev->dev, "irlap_open failed\n"); goto free_mem; } @@ -442,7 +448,7 @@ static int ksdazzle_net_open(struct net_device *netdev) kingsun->rx_urb->status = 0; err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); if (err) { - err("ksdazzle-sir: first urb-submit failed: %d", err); + dev_err(&kingsun->usbdev->dev, "first urb-submit failed: %d\n", err); goto close_irlap; } @@ -590,13 +596,14 @@ static int ksdazzle_probe(struct usb_interface *intf, */ interface = intf->cur_altsetting; if (interface->desc.bNumEndpoints != 2) { - err("ksdazzle: expected 2 endpoints, found %d", - interface->desc.bNumEndpoints); + dev_err(&intf->dev, "ksdazzle: expected 2 endpoints, found %d\n", + interface->desc.bNumEndpoints); return -ENODEV; } endpoint = &interface->endpoint[KINGSUN_EP_IN].desc; if (!usb_endpoint_is_int_in(endpoint)) { - err("ksdazzle: endpoint 0 is not interrupt IN"); + dev_err(&intf->dev, + "ksdazzle: endpoint 0 is not interrupt IN\n"); return -ENODEV; } @@ -604,13 +611,16 @@ static int ksdazzle_probe(struct usb_interface *intf, pipe = usb_rcvintpipe(dev, ep_in); maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); if (maxp_in > 255 || maxp_in <= 1) { - err("ksdazzle: endpoint 0 has max packet size %d not in range [2..255]", maxp_in); + dev_err(&intf->dev, + "ksdazzle: endpoint 0 has max packet size %d not in range [2..255]\n", + maxp_in); return -ENODEV; } endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc; if (!usb_endpoint_is_int_out(endpoint)) { - err("ksdazzle: endpoint 1 is not interrupt OUT"); + dev_err(&intf->dev, + "ksdazzle: endpoint 1 is not interrupt OUT\n"); return -ENODEV; } diff --git a/trunk/drivers/net/irda/sh_irda.c b/trunk/drivers/net/irda/sh_irda.c index 725d6b367822..eb315b8d07a3 100644 --- a/trunk/drivers/net/irda/sh_irda.c +++ b/trunk/drivers/net/irda/sh_irda.c @@ -737,7 +737,7 @@ static int sh_irda_stop(struct net_device *ndev) netif_stop_queue(ndev); pm_runtime_put_sync(&self->pdev->dev); - dev_info(&ndev->dev, "stoped\n"); + dev_info(&ndev->dev, "stopped\n"); return 0; } diff --git a/trunk/drivers/net/irda/sh_sir.c b/trunk/drivers/net/irda/sh_sir.c index e6661b5c1f83..256eddf1f75a 100644 --- a/trunk/drivers/net/irda/sh_sir.c +++ b/trunk/drivers/net/irda/sh_sir.c @@ -685,7 +685,7 @@ static int sh_sir_stop(struct net_device *ndev) netif_stop_queue(ndev); - dev_info(&ndev->dev, "stoped\n"); + dev_info(&ndev->dev, "stopped\n"); return 0; } diff --git a/trunk/drivers/net/irda/smsc-ircc2.c b/trunk/drivers/net/irda/smsc-ircc2.c index 6c95d4087b2d..a926813ee91d 100644 --- a/trunk/drivers/net/irda/smsc-ircc2.c +++ b/trunk/drivers/net/irda/smsc-ircc2.c @@ -1,7 +1,6 @@ /********************************************************************* * * Description: Driver for the SMC Infrared Communications Controller - * Status: Experimental. * Author: Daniele Peri (peri@csai.unipa.it) * Created at: * Modified at: diff --git a/trunk/drivers/net/irda/stir4200.c b/trunk/drivers/net/irda/stir4200.c index e6e59a078ef4..876e709b65ba 100644 --- a/trunk/drivers/net/irda/stir4200.c +++ b/trunk/drivers/net/irda/stir4200.c @@ -904,7 +904,7 @@ static int stir_net_open(struct net_device *netdev) sprintf(hwname, "usb#%d", stir->usbdev->devnum); stir->irlap = irlap_open(netdev, &stir->qos, hwname); if (!stir->irlap) { - err("stir4200: irlap_open failed"); + dev_err(&stir->usbdev->dev, "irlap_open failed\n"); goto err_out5; } @@ -913,7 +913,7 @@ static int stir_net_open(struct net_device *netdev) "%s", stir->netdev->name); if (IS_ERR(stir->thread)) { err = PTR_ERR(stir->thread); - err("stir4200: unable to start kernel thread"); + dev_err(&stir->usbdev->dev, "unable to start kernel thread\n"); goto err_out6; } @@ -1042,7 +1042,7 @@ static int stir_probe(struct usb_interface *intf, ret = usb_reset_configuration(dev); if (ret != 0) { - err("stir4200: usb reset configuration failed"); + dev_err(&intf->dev, "usb reset configuration failed\n"); goto err_out2; } diff --git a/trunk/drivers/net/macvlan.c b/trunk/drivers/net/macvlan.c index 025367a94add..66a9bfe7b1c8 100644 --- a/trunk/drivers/net/macvlan.c +++ b/trunk/drivers/net/macvlan.c @@ -57,7 +57,7 @@ static struct macvlan_dev *macvlan_hash_lookup(const struct macvlan_port *port, struct hlist_node *n; hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[addr[5]], hlist) { - if (!compare_ether_addr_64bits(vlan->dev->dev_addr, addr)) + if (ether_addr_equal_64bits(vlan->dev->dev_addr, addr)) return vlan; } return NULL; @@ -96,7 +96,7 @@ static int macvlan_addr_busy(const struct macvlan_port *port, * currently in use by the underlying device or * another macvlan. */ - if (!compare_ether_addr_64bits(port->dev->dev_addr, addr)) + if (ether_addr_equal_64bits(port->dev->dev_addr, addr)) return 1; if (macvlan_hash_lookup(port, addr)) @@ -118,8 +118,7 @@ static int macvlan_broadcast_one(struct sk_buff *skb, return vlan->forward(dev, skb); skb->dev = dev; - if (!compare_ether_addr_64bits(eth->h_dest, - dev->broadcast)) + if (ether_addr_equal_64bits(eth->h_dest, dev->broadcast)) skb->pkt_type = PACKET_BROADCAST; else skb->pkt_type = PACKET_MULTICAST; @@ -312,7 +311,8 @@ static int macvlan_open(struct net_device *dev) int err; if (vlan->port->passthru) { - dev_set_promiscuity(lowerdev, 1); + if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC)) + dev_set_promiscuity(lowerdev, 1); goto hash_add; } @@ -344,12 +344,15 @@ static int macvlan_stop(struct net_device *dev) struct macvlan_dev *vlan = netdev_priv(dev); struct net_device *lowerdev = vlan->lowerdev; + dev_uc_unsync(lowerdev, dev); + dev_mc_unsync(lowerdev, dev); + if (vlan->port->passthru) { - dev_set_promiscuity(lowerdev, -1); + if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC)) + dev_set_promiscuity(lowerdev, -1); goto hash_del; } - dev_mc_unsync(lowerdev, dev); if (dev->flags & IFF_ALLMULTI) dev_set_allmulti(lowerdev, -1); @@ -399,10 +402,11 @@ static void macvlan_change_rx_flags(struct net_device *dev, int change) dev_set_allmulti(lowerdev, dev->flags & IFF_ALLMULTI ? 1 : -1); } -static void macvlan_set_multicast_list(struct net_device *dev) +static void macvlan_set_mac_lists(struct net_device *dev) { struct macvlan_dev *vlan = netdev_priv(dev); + dev_uc_sync(vlan->lowerdev, dev); dev_mc_sync(vlan->lowerdev, dev); } @@ -542,6 +546,43 @@ static int macvlan_vlan_rx_kill_vid(struct net_device *dev, return 0; } +static int macvlan_fdb_add(struct ndmsg *ndm, + struct net_device *dev, + unsigned char *addr, + u16 flags) +{ + struct macvlan_dev *vlan = netdev_priv(dev); + int err = -EINVAL; + + if (!vlan->port->passthru) + return -EOPNOTSUPP; + + if (is_unicast_ether_addr(addr)) + err = dev_uc_add_excl(dev, addr); + else if (is_multicast_ether_addr(addr)) + err = dev_mc_add_excl(dev, addr); + + return err; +} + +static int macvlan_fdb_del(struct ndmsg *ndm, + struct net_device *dev, + unsigned char *addr) +{ + struct macvlan_dev *vlan = netdev_priv(dev); + int err = -EINVAL; + + if (!vlan->port->passthru) + return -EOPNOTSUPP; + + 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); + + return err; +} + static void macvlan_ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) { @@ -572,11 +613,14 @@ static const struct net_device_ops macvlan_netdev_ops = { .ndo_change_mtu = macvlan_change_mtu, .ndo_change_rx_flags = macvlan_change_rx_flags, .ndo_set_mac_address = macvlan_set_mac_address, - .ndo_set_rx_mode = macvlan_set_multicast_list, + .ndo_set_rx_mode = macvlan_set_mac_lists, .ndo_get_stats64 = macvlan_dev_get_stats64, .ndo_validate_addr = eth_validate_addr, .ndo_vlan_rx_add_vid = macvlan_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = macvlan_vlan_rx_kill_vid, + .ndo_fdb_add = macvlan_fdb_add, + .ndo_fdb_del = macvlan_fdb_del, + .ndo_fdb_dump = ndo_dflt_fdb_dump, }; void macvlan_common_setup(struct net_device *dev) @@ -711,6 +755,9 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, if (data && data[IFLA_MACVLAN_MODE]) vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); + if (data && data[IFLA_MACVLAN_FLAGS]) + vlan->flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]); + if (vlan->mode == MACVLAN_MODE_PASSTHRU) { if (port->count) return -EINVAL; @@ -760,6 +807,16 @@ static int macvlan_changelink(struct net_device *dev, struct macvlan_dev *vlan = netdev_priv(dev); if (data && data[IFLA_MACVLAN_MODE]) vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); + if (data && data[IFLA_MACVLAN_FLAGS]) { + __u16 flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]); + bool promisc = (flags ^ vlan->flags) & MACVLAN_FLAG_NOPROMISC; + + if (promisc && (flags & MACVLAN_FLAG_NOPROMISC)) + dev_set_promiscuity(vlan->lowerdev, -1); + else if (promisc && !(flags & MACVLAN_FLAG_NOPROMISC)) + dev_set_promiscuity(vlan->lowerdev, 1); + vlan->flags = flags; + } return 0; } @@ -773,7 +830,10 @@ static int macvlan_fill_info(struct sk_buff *skb, { struct macvlan_dev *vlan = netdev_priv(dev); - NLA_PUT_U32(skb, IFLA_MACVLAN_MODE, vlan->mode); + if (nla_put_u32(skb, IFLA_MACVLAN_MODE, vlan->mode)) + goto nla_put_failure; + if (nla_put_u16(skb, IFLA_MACVLAN_FLAGS, vlan->flags)) + goto nla_put_failure; return 0; nla_put_failure: @@ -781,7 +841,8 @@ static int macvlan_fill_info(struct sk_buff *skb, } static const struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX + 1] = { - [IFLA_MACVLAN_MODE] = { .type = NLA_U32 }, + [IFLA_MACVLAN_MODE] = { .type = NLA_U32 }, + [IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 }, }; int macvlan_link_register(struct rtnl_link_ops *ops) diff --git a/trunk/drivers/net/macvtap.c b/trunk/drivers/net/macvtap.c index cb8fd5069dbe..2ee56de7b0ca 100644 --- a/trunk/drivers/net/macvtap.c +++ b/trunk/drivers/net/macvtap.c @@ -506,10 +506,11 @@ static int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from, if (copy > size) { ++from; --count; - } + offset = 0; + } else + offset += size; copy -= size; offset1 += size; - offset = 0; } if (len == offset1) @@ -519,24 +520,29 @@ static int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from, struct page *page[MAX_SKB_FRAGS]; int num_pages; unsigned long base; + unsigned long truesize; - len = from->iov_len - offset1; + len = from->iov_len - offset; if (!len) { - offset1 = 0; + offset = 0; ++from; continue; } - base = (unsigned long)from->iov_base + offset1; + base = (unsigned long)from->iov_base + offset; size = ((base & ~PAGE_MASK) + len + ~PAGE_MASK) >> PAGE_SHIFT; + if (i + size > MAX_SKB_FRAGS) + return -EMSGSIZE; num_pages = get_user_pages_fast(base, size, 0, &page[i]); - if ((num_pages != size) || - (num_pages > MAX_SKB_FRAGS - skb_shinfo(skb)->nr_frags)) - /* put_page is in skb free */ + if (num_pages != size) { + for (i = 0; i < num_pages; i++) + put_page(page[i]); return -EFAULT; + } + truesize = size * PAGE_SIZE; skb->data_len += len; skb->len += len; - skb->truesize += len; - atomic_add(len, &skb->sk->sk_wmem_alloc); + skb->truesize += truesize; + atomic_add(truesize, &skb->sk->sk_wmem_alloc); while (len) { int off = base & ~PAGE_MASK; int size = min_t(int, len, PAGE_SIZE - off); @@ -547,7 +553,7 @@ static int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from, len -= size; i++; } - offset1 = 0; + offset = 0; ++from; } return 0; @@ -647,7 +653,7 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m, int err; struct virtio_net_hdr vnet_hdr = { 0 }; int vnet_hdr_len = 0; - int copylen; + int copylen = 0; bool zerocopy = false; if (q->flags & IFF_VNET_HDR) { @@ -676,15 +682,31 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m, if (unlikely(len < ETH_HLEN)) goto err; + err = -EMSGSIZE; + if (unlikely(count > UIO_MAXIOV)) + goto err; + if (m && m->msg_control && sock_flag(&q->sk, SOCK_ZEROCOPY)) zerocopy = true; if (zerocopy) { + /* Userspace may produce vectors with count greater than + * MAX_SKB_FRAGS, so we need to linearize parts of the skb + * to let the rest of data to be fit in the frags. + */ + if (count > MAX_SKB_FRAGS) { + copylen = iov_length(iv, count - MAX_SKB_FRAGS); + if (copylen < vnet_hdr_len) + copylen = 0; + else + copylen -= vnet_hdr_len; + } /* There are 256 bytes to be copied in skb, so there is enough * room for skb expand head in case it is used. * The rest buffer is mapped from userspace. */ - copylen = vnet_hdr.hdr_len; + if (copylen < vnet_hdr.hdr_len) + copylen = vnet_hdr.hdr_len; if (!copylen) copylen = GOODCOPY_LEN; } else @@ -695,10 +717,9 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m, if (!skb) goto err; - if (zerocopy) { + if (zerocopy) err = zerocopy_sg_from_iovec(skb, iv, vnet_hdr_len, count); - skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY; - } else + else err = skb_copy_datagram_from_iovec(skb, 0, iv, vnet_hdr_len, len); if (err) @@ -717,8 +738,10 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m, rcu_read_lock_bh(); vlan = rcu_dereference_bh(q->vlan); /* copy skb_ubuf_info for callback when skb has no error */ - if (zerocopy) + if (zerocopy) { skb_shinfo(skb)->destructor_arg = m->msg_control; + skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY; + } if (vlan) macvlan_start_xmit(skb, vlan->dev); else diff --git a/trunk/drivers/net/phy/Kconfig b/trunk/drivers/net/phy/Kconfig index 0e01f4e5cd64..944cdfb80fe4 100644 --- a/trunk/drivers/net/phy/Kconfig +++ b/trunk/drivers/net/phy/Kconfig @@ -135,6 +135,25 @@ config MDIO_OCTEON If in doubt, say Y. +config MDIO_BUS_MUX + tristate + depends on OF_MDIO + help + This module provides a driver framework for MDIO bus + multiplexers which connect one of several child MDIO busses + to a parent bus. Switching between child busses is done by + device specific drivers. + +config MDIO_BUS_MUX_GPIO + tristate "Support for GPIO controlled MDIO bus multiplexers" + depends on OF_GPIO && OF_MDIO + select MDIO_BUS_MUX + help + This module provides a driver for MDIO bus multiplexers that + are controlled via GPIO lines. The multiplexer connects one of + several child MDIO busses to a parent bus. Child bus + selection is under the control of GPIO lines. + endif # PHYLIB config MICREL_KS8995MA diff --git a/trunk/drivers/net/phy/Makefile b/trunk/drivers/net/phy/Makefile index b7438b1b94b9..f51af688ef8b 100644 --- a/trunk/drivers/net/phy/Makefile +++ b/trunk/drivers/net/phy/Makefile @@ -25,3 +25,5 @@ obj-$(CONFIG_MICREL_PHY) += micrel.o obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o obj-$(CONFIG_AMD_PHY) += amd.o +obj-$(CONFIG_MDIO_BUS_MUX) += mdio-mux.o +obj-$(CONFIG_MDIO_BUS_MUX_GPIO) += mdio-mux-gpio.o diff --git a/trunk/drivers/net/phy/bcm63xx.c b/trunk/drivers/net/phy/bcm63xx.c index e16f98cb4f04..cd802eb25fd2 100644 --- a/trunk/drivers/net/phy/bcm63xx.c +++ b/trunk/drivers/net/phy/bcm63xx.c @@ -39,10 +39,7 @@ static int bcm63xx_config_init(struct phy_device *phydev) MII_BCM63XX_IR_SPEED | MII_BCM63XX_IR_LINK) | MII_BCM63XX_IR_EN; - err = phy_write(phydev, MII_BCM63XX_IR, reg); - if (err < 0) - return err; - return 0; + return phy_write(phydev, MII_BCM63XX_IR, reg); } static int bcm63xx_ack_interrupt(struct phy_device *phydev) diff --git a/trunk/drivers/net/phy/davicom.c b/trunk/drivers/net/phy/davicom.c index 2f774acdb551..5f59cc064778 100644 --- a/trunk/drivers/net/phy/davicom.c +++ b/trunk/drivers/net/phy/davicom.c @@ -134,12 +134,7 @@ static int dm9161_config_init(struct phy_device *phydev) return err; /* Reconnect the PHY, and enable Autonegotiation */ - err = phy_write(phydev, MII_BMCR, BMCR_ANENABLE); - - if (err < 0) - return err; - - return 0; + return phy_write(phydev, MII_BMCR, BMCR_ANENABLE); } static int dm9161_ack_interrupt(struct phy_device *phydev) diff --git a/trunk/drivers/net/phy/dp83640.c b/trunk/drivers/net/phy/dp83640.c index dd7ae19579d1..940b29022d0c 100644 --- a/trunk/drivers/net/phy/dp83640.c +++ b/trunk/drivers/net/phy/dp83640.c @@ -1215,6 +1215,36 @@ static void dp83640_txtstamp(struct phy_device *phydev, } } +static int dp83640_ts_info(struct phy_device *dev, struct ethtool_ts_info *info) +{ + struct dp83640_private *dp83640 = dev->priv; + + info->so_timestamping = + SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + info->phc_index = ptp_clock_index(dp83640->clock->ptp_clock); + info->tx_types = + (1 << HWTSTAMP_TX_OFF) | + (1 << HWTSTAMP_TX_ON) | + (1 << HWTSTAMP_TX_ONESTEP_SYNC); + info->rx_filters = + (1 << HWTSTAMP_FILTER_NONE) | + (1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) | + (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | + (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | + (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | + (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | + (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) | + (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | + (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | + (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) | + (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) | + (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | + (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ); + return 0; +} + static struct phy_driver dp83640_driver = { .phy_id = DP83640_PHY_ID, .phy_id_mask = 0xfffffff0, @@ -1225,6 +1255,7 @@ static struct phy_driver dp83640_driver = { .remove = dp83640_remove, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, + .ts_info = dp83640_ts_info, .hwtstamp = dp83640_hwtstamp, .rxtstamp = dp83640_rxtstamp, .txtstamp = dp83640_txtstamp, diff --git a/trunk/drivers/net/phy/marvell.c b/trunk/drivers/net/phy/marvell.c index e8b9c53c304b..418928d644bf 100644 --- a/trunk/drivers/net/phy/marvell.c +++ b/trunk/drivers/net/phy/marvell.c @@ -455,11 +455,7 @@ static int m88e1111_config_init(struct phy_device *phydev) if (err < 0) return err; - err = phy_write(phydev, MII_BMCR, BMCR_RESET); - if (err < 0) - return err; - - return 0; + return phy_write(phydev, MII_BMCR, BMCR_RESET); } static int m88e1118_config_aneg(struct phy_device *phydev) @@ -515,11 +511,7 @@ static int m88e1118_config_init(struct phy_device *phydev) if (err < 0) return err; - err = phy_write(phydev, MII_BMCR, BMCR_RESET); - if (err < 0) - return err; - - return 0; + return phy_write(phydev, MII_BMCR, BMCR_RESET); } static int m88e1149_config_init(struct phy_device *phydev) @@ -545,11 +537,7 @@ static int m88e1149_config_init(struct phy_device *phydev) if (err < 0) return err; - err = phy_write(phydev, MII_BMCR, BMCR_RESET); - if (err < 0) - return err; - - return 0; + return phy_write(phydev, MII_BMCR, BMCR_RESET); } static int m88e1145_config_init(struct phy_device *phydev) diff --git a/trunk/drivers/net/phy/mdio-mux-gpio.c b/trunk/drivers/net/phy/mdio-mux-gpio.c new file mode 100644 index 000000000000..e0cc4ef33dee --- /dev/null +++ b/trunk/drivers/net/phy/mdio-mux-gpio.c @@ -0,0 +1,142 @@ +/* + * 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) 2011, 2012 Cavium, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_VERSION "1.0" +#define DRV_DESCRIPTION "GPIO controlled MDIO bus multiplexer driver" + +#define MDIO_MUX_GPIO_MAX_BITS 8 + +struct mdio_mux_gpio_state { + int gpio[MDIO_MUX_GPIO_MAX_BITS]; + unsigned int num_gpios; + void *mux_handle; +}; + +static int mdio_mux_gpio_switch_fn(int current_child, int desired_child, + void *data) +{ + int change; + unsigned int n; + struct mdio_mux_gpio_state *s = data; + + if (current_child == desired_child) + return 0; + + change = current_child == -1 ? -1 : current_child ^ desired_child; + + for (n = 0; n < s->num_gpios; n++) { + if (change & 1) + gpio_set_value_cansleep(s->gpio[n], + (desired_child & 1) != 0); + change >>= 1; + desired_child >>= 1; + } + + return 0; +} + +static int __devinit mdio_mux_gpio_probe(struct platform_device *pdev) +{ + enum of_gpio_flags f; + struct mdio_mux_gpio_state *s; + unsigned int num_gpios; + unsigned int n; + int r; + + if (!pdev->dev.of_node) + return -ENODEV; + + num_gpios = of_gpio_count(pdev->dev.of_node); + if (num_gpios == 0 || num_gpios > MDIO_MUX_GPIO_MAX_BITS) + return -ENODEV; + + s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL); + if (!s) + return -ENOMEM; + + s->num_gpios = num_gpios; + + for (n = 0; n < num_gpios; ) { + int gpio = of_get_gpio_flags(pdev->dev.of_node, n, &f); + if (gpio < 0) { + r = (gpio == -ENODEV) ? -EPROBE_DEFER : gpio; + goto err; + } + s->gpio[n] = gpio; + + n++; + + r = gpio_request(gpio, "mdio_mux_gpio"); + if (r) + goto err; + + r = gpio_direction_output(gpio, 0); + if (r) + goto err; + } + + r = mdio_mux_init(&pdev->dev, + mdio_mux_gpio_switch_fn, &s->mux_handle, s); + + if (r == 0) { + pdev->dev.platform_data = s; + return 0; + } +err: + while (n) { + n--; + gpio_free(s->gpio[n]); + } + devm_kfree(&pdev->dev, s); + return r; +} + +static int __devexit mdio_mux_gpio_remove(struct platform_device *pdev) +{ + struct mdio_mux_gpio_state *s = pdev->dev.platform_data; + mdio_mux_uninit(s->mux_handle); + return 0; +} + +static struct of_device_id mdio_mux_gpio_match[] = { + { + .compatible = "mdio-mux-gpio", + }, + { + /* Legacy compatible property. */ + .compatible = "cavium,mdio-mux-sn74cbtlv3253", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, mdio_mux_gpio_match); + +static struct platform_driver mdio_mux_gpio_driver = { + .driver = { + .name = "mdio-mux-gpio", + .owner = THIS_MODULE, + .of_match_table = mdio_mux_gpio_match, + }, + .probe = mdio_mux_gpio_probe, + .remove = __devexit_p(mdio_mux_gpio_remove), +}; + +module_platform_driver(mdio_mux_gpio_driver); + +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_VERSION(DRV_VERSION); +MODULE_AUTHOR("David Daney"); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/net/phy/mdio-mux.c b/trunk/drivers/net/phy/mdio-mux.c new file mode 100644 index 000000000000..39ea0674dcde --- /dev/null +++ b/trunk/drivers/net/phy/mdio-mux.c @@ -0,0 +1,192 @@ +/* + * 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) 2011, 2012 Cavium, Inc. + */ + +#include +#include +#include +#include +#include +#include + +#define DRV_VERSION "1.0" +#define DRV_DESCRIPTION "MDIO bus multiplexer driver" + +struct mdio_mux_child_bus; + +struct mdio_mux_parent_bus { + struct mii_bus *mii_bus; + int current_child; + int parent_id; + void *switch_data; + int (*switch_fn)(int current_child, int desired_child, void *data); + + /* List of our children linked through their next fields. */ + struct mdio_mux_child_bus *children; +}; + +struct mdio_mux_child_bus { + struct mii_bus *mii_bus; + struct mdio_mux_parent_bus *parent; + struct mdio_mux_child_bus *next; + int bus_number; + int phy_irq[PHY_MAX_ADDR]; +}; + +/* + * The parent bus' lock is used to order access to the switch_fn. + */ +static int mdio_mux_read(struct mii_bus *bus, int phy_id, int regnum) +{ + struct mdio_mux_child_bus *cb = bus->priv; + struct mdio_mux_parent_bus *pb = cb->parent; + int r; + + mutex_lock(&pb->mii_bus->mdio_lock); + r = pb->switch_fn(pb->current_child, cb->bus_number, pb->switch_data); + if (r) + goto out; + + pb->current_child = cb->bus_number; + + r = pb->mii_bus->read(pb->mii_bus, phy_id, regnum); +out: + mutex_unlock(&pb->mii_bus->mdio_lock); + + return r; +} + +/* + * The parent bus' lock is used to order access to the switch_fn. + */ +static int mdio_mux_write(struct mii_bus *bus, int phy_id, + int regnum, u16 val) +{ + struct mdio_mux_child_bus *cb = bus->priv; + struct mdio_mux_parent_bus *pb = cb->parent; + + int r; + + mutex_lock(&pb->mii_bus->mdio_lock); + r = pb->switch_fn(pb->current_child, cb->bus_number, pb->switch_data); + if (r) + goto out; + + pb->current_child = cb->bus_number; + + r = pb->mii_bus->write(pb->mii_bus, phy_id, regnum, val); +out: + mutex_unlock(&pb->mii_bus->mdio_lock); + + return r; +} + +static int parent_count; + +int mdio_mux_init(struct device *dev, + int (*switch_fn)(int cur, int desired, void *data), + void **mux_handle, + void *data) +{ + struct device_node *parent_bus_node; + struct device_node *child_bus_node; + int r, ret_val; + struct mii_bus *parent_bus; + struct mdio_mux_parent_bus *pb; + struct mdio_mux_child_bus *cb; + + if (!dev->of_node) + return -ENODEV; + + parent_bus_node = of_parse_phandle(dev->of_node, "mdio-parent-bus", 0); + + if (!parent_bus_node) + return -ENODEV; + + parent_bus = of_mdio_find_bus(parent_bus_node); + if (parent_bus == NULL) { + ret_val = -EPROBE_DEFER; + goto err_parent_bus; + } + + pb = devm_kzalloc(dev, sizeof(*pb), GFP_KERNEL); + if (pb == NULL) { + ret_val = -ENOMEM; + goto err_parent_bus; + } + + pb->switch_data = data; + pb->switch_fn = switch_fn; + pb->current_child = -1; + pb->parent_id = parent_count++; + pb->mii_bus = parent_bus; + + ret_val = -ENODEV; + for_each_child_of_node(dev->of_node, child_bus_node) { + u32 v; + + r = of_property_read_u32(child_bus_node, "reg", &v); + if (r) + continue; + + cb = devm_kzalloc(dev, sizeof(*cb), GFP_KERNEL); + if (cb == NULL) { + dev_err(dev, + "Error: Failed to allocate memory for child\n"); + ret_val = -ENOMEM; + break; + } + cb->bus_number = v; + cb->parent = pb; + cb->mii_bus = mdiobus_alloc(); + cb->mii_bus->priv = cb; + + cb->mii_bus->irq = cb->phy_irq; + cb->mii_bus->name = "mdio_mux"; + snprintf(cb->mii_bus->id, MII_BUS_ID_SIZE, "%x.%x", + pb->parent_id, v); + cb->mii_bus->parent = dev; + cb->mii_bus->read = mdio_mux_read; + cb->mii_bus->write = mdio_mux_write; + r = of_mdiobus_register(cb->mii_bus, child_bus_node); + if (r) { + mdiobus_free(cb->mii_bus); + devm_kfree(dev, cb); + } else { + of_node_get(child_bus_node); + cb->next = pb->children; + pb->children = cb; + } + } + if (pb->children) { + *mux_handle = pb; + dev_info(dev, "Version " DRV_VERSION "\n"); + return 0; + } +err_parent_bus: + of_node_put(parent_bus_node); + return ret_val; +} +EXPORT_SYMBOL_GPL(mdio_mux_init); + +void mdio_mux_uninit(void *mux_handle) +{ + struct mdio_mux_parent_bus *pb = mux_handle; + struct mdio_mux_child_bus *cb = pb->children; + + while (cb) { + mdiobus_unregister(cb->mii_bus); + mdiobus_free(cb->mii_bus); + cb = cb->next; + } +} +EXPORT_SYMBOL_GPL(mdio_mux_uninit); + +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_VERSION(DRV_VERSION); +MODULE_AUTHOR("David Daney"); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/net/phy/mdio_bus.c b/trunk/drivers/net/phy/mdio_bus.c index 8985cc62cf41..683ef1ce5519 100644 --- a/trunk/drivers/net/phy/mdio_bus.c +++ b/trunk/drivers/net/phy/mdio_bus.c @@ -88,6 +88,38 @@ static struct class mdio_bus_class = { .dev_release = mdiobus_release, }; +#if IS_ENABLED(CONFIG_OF_MDIO) +/* Helper function for of_mdio_find_bus */ +static int of_mdio_bus_match(struct device *dev, void *mdio_bus_np) +{ + return dev->of_node == mdio_bus_np; +} +/** + * of_mdio_find_bus - Given an mii_bus node, find the mii_bus. + * @mdio_np: Pointer to the mii_bus. + * + * Returns a pointer to the mii_bus, or NULL if none found. + * + * Because the association of a device_node and mii_bus is made via + * of_mdiobus_register(), the mii_bus cannot be found before it is + * registered with of_mdiobus_register(). + * + */ +struct mii_bus *of_mdio_find_bus(struct device_node *mdio_bus_np) +{ + struct device *d; + + if (!mdio_bus_np) + return NULL; + + d = class_find_device(&mdio_bus_class, NULL, mdio_bus_np, + of_mdio_bus_match); + + return d ? to_mii_bus(d) : NULL; +} +EXPORT_SYMBOL(of_mdio_find_bus); +#endif + /** * mdiobus_register - bring up all the PHYs on a given bus and attach them to bus * @bus: target mii_bus diff --git a/trunk/drivers/net/phy/phy_device.c b/trunk/drivers/net/phy/phy_device.c index e8c42d6a7d1c..de86a5582224 100644 --- a/trunk/drivers/net/phy/phy_device.c +++ b/trunk/drivers/net/phy/phy_device.c @@ -207,7 +207,7 @@ static struct phy_device* phy_device_create(struct mii_bus *bus, * Description: Reads the ID registers of the PHY at @addr on the * @bus, stores it in @phy_id and returns zero on success. */ -int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id) +static int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id) { int phy_reg; @@ -230,7 +230,6 @@ int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id) return 0; } -EXPORT_SYMBOL(get_phy_id); /** * get_phy_device - reads the specified PHY device and returns its @phy_device struct diff --git a/trunk/drivers/net/phy/spi_ks8995.c b/trunk/drivers/net/phy/spi_ks8995.c index 116a2dd7c879..4eb98bc52a0a 100644 --- a/trunk/drivers/net/phy/spi_ks8995.c +++ b/trunk/drivers/net/phy/spi_ks8995.c @@ -348,7 +348,6 @@ static int __devexit ks8995_remove(struct spi_device *spi) static struct spi_driver ks8995_driver = { .driver = { .name = "spi-ks8995", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = ks8995_probe, diff --git a/trunk/drivers/net/ppp/ppp_async.c b/trunk/drivers/net/ppp/ppp_async.c index af95a98fd86f..a031f6b456b4 100644 --- a/trunk/drivers/net/ppp/ppp_async.c +++ b/trunk/drivers/net/ppp/ppp_async.c @@ -613,7 +613,7 @@ ppp_async_encode(struct asyncppp *ap) *buf++ = PPP_FLAG; ap->olim = buf; - kfree_skb(ap->tpkt); + consume_skb(ap->tpkt); ap->tpkt = NULL; return 1; } diff --git a/trunk/drivers/net/ppp/ppp_generic.c b/trunk/drivers/net/ppp/ppp_generic.c index 21d7151fb0ab..5c0557222f20 100644 --- a/trunk/drivers/net/ppp/ppp_generic.c +++ b/trunk/drivers/net/ppp/ppp_generic.c @@ -1092,13 +1092,13 @@ pad_compress_skb(struct ppp *ppp, struct sk_buff *skb) new_skb->data, skb->len + 2, compressor_skb_size); if (len > 0 && (ppp->flags & SC_CCP_UP)) { - kfree_skb(skb); + consume_skb(skb); skb = new_skb; skb_put(skb, len); skb_pull(skb, 2); /* pull off A/C bytes */ } else if (len == 0) { /* didn't compress, or CCP not up yet */ - kfree_skb(new_skb); + consume_skb(new_skb); new_skb = skb; } else { /* @@ -1112,7 +1112,7 @@ pad_compress_skb(struct ppp *ppp, struct sk_buff *skb) if (net_ratelimit()) netdev_err(ppp->dev, "ppp: compressor dropped pkt\n"); kfree_skb(skb); - kfree_skb(new_skb); + consume_skb(new_skb); new_skb = NULL; } return new_skb; @@ -1178,7 +1178,7 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) !(ppp->flags & SC_NO_TCP_CCID)); if (cp == skb->data + 2) { /* didn't compress */ - kfree_skb(new_skb); + consume_skb(new_skb); } else { if (cp[0] & SL_TYPE_COMPRESSED_TCP) { proto = PPP_VJC_COMP; @@ -1187,7 +1187,7 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) proto = PPP_VJC_UNCOMP; cp[0] = skb->data[2]; } - kfree_skb(skb); + consume_skb(skb); skb = new_skb; cp = skb_put(skb, len + 2); cp[0] = 0; @@ -1703,7 +1703,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) } skb_reserve(ns, 2); skb_copy_bits(skb, 0, skb_put(ns, skb->len), skb->len); - kfree_skb(skb); + consume_skb(skb); skb = ns; } else @@ -1851,7 +1851,7 @@ ppp_decompress_frame(struct ppp *ppp, struct sk_buff *skb) goto err; } - kfree_skb(skb); + consume_skb(skb); skb = ns; skb_put(skb, len); skb_pull(skb, 2); /* pull off the A/C bytes */ diff --git a/trunk/drivers/net/ppp/ppp_synctty.c b/trunk/drivers/net/ppp/ppp_synctty.c index 55e466c511d5..1a12033d2efa 100644 --- a/trunk/drivers/net/ppp/ppp_synctty.c +++ b/trunk/drivers/net/ppp/ppp_synctty.c @@ -588,7 +588,7 @@ ppp_sync_txmunge(struct syncppp *ap, struct sk_buff *skb) skb_reserve(npkt,2); skb_copy_from_linear_data(skb, skb_put(npkt, skb->len), skb->len); - kfree_skb(skb); + consume_skb(skb); skb = npkt; } skb_push(skb,2); @@ -656,7 +656,7 @@ ppp_sync_push(struct syncppp *ap) if (sent < ap->tpkt->len) { tty_stuffed = 1; } else { - kfree_skb(ap->tpkt); + consume_skb(ap->tpkt); ap->tpkt = NULL; clear_bit(XMIT_FULL, &ap->xmit_flags); done = 1; diff --git a/trunk/drivers/net/ppp/pppoe.c b/trunk/drivers/net/ppp/pppoe.c index 2fa1a9b6f498..cbf7047decc0 100644 --- a/trunk/drivers/net/ppp/pppoe.c +++ b/trunk/drivers/net/ppp/pppoe.c @@ -201,7 +201,7 @@ static int __set_item(struct pppoe_net *pn, struct pppox_sock *po) return 0; } -static struct pppox_sock *__delete_item(struct pppoe_net *pn, __be16 sid, +static void __delete_item(struct pppoe_net *pn, __be16 sid, char *addr, int ifindex) { int hash = hash_item(sid, addr); @@ -220,8 +220,6 @@ static struct pppox_sock *__delete_item(struct pppoe_net *pn, __be16 sid, src = &ret->next; ret = ret->next; } - - return ret; } /********************************************************************** @@ -264,16 +262,12 @@ static inline struct pppox_sock *get_item_by_addr(struct net *net, return pppox_sock; } -static inline struct pppox_sock *delete_item(struct pppoe_net *pn, __be16 sid, +static inline void delete_item(struct pppoe_net *pn, __be16 sid, char *addr, int ifindex) { - struct pppox_sock *ret; - write_lock_bh(&pn->hash_lock); - ret = __delete_item(pn, sid, addr, ifindex); + __delete_item(pn, sid, addr, ifindex); write_unlock_bh(&pn->hash_lock); - - return ret; } /*************************************************************************** @@ -990,8 +984,10 @@ static int pppoe_recvmsg(struct kiocb *iocb, struct socket *sock, if (skb) { total_len = min_t(size_t, total_len, skb->len); error = skb_copy_datagram_iovec(skb, 0, m->msg_iov, total_len); - if (error == 0) - error = total_len; + if (error == 0) { + consume_skb(skb); + return total_len; + } } kfree_skb(skb); diff --git a/trunk/drivers/net/ppp/pptp.c b/trunk/drivers/net/ppp/pptp.c index 885dbdd9c39e..1c98321b56cc 100644 --- a/trunk/drivers/net/ppp/pptp.c +++ b/trunk/drivers/net/ppp/pptp.c @@ -116,8 +116,8 @@ static int lookup_chan_dst(u16 call_id, __be32 d_addr) int i; rcu_read_lock(); - for (i = find_next_bit(callid_bitmap, MAX_CALLID, 1); i < MAX_CALLID; - i = find_next_bit(callid_bitmap, MAX_CALLID, i + 1)) { + i = 1; + for_each_set_bit_from(i, callid_bitmap, MAX_CALLID) { sock = rcu_dereference(callid_sock[i]); if (!sock) continue; @@ -209,7 +209,7 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb) } if (skb->sk) skb_set_owner_w(new_skb, skb->sk); - kfree_skb(skb); + consume_skb(skb); skb = new_skb; } diff --git a/trunk/drivers/net/team/Kconfig b/trunk/drivers/net/team/Kconfig index 248a144033ca..89024d5fc33a 100644 --- a/trunk/drivers/net/team/Kconfig +++ b/trunk/drivers/net/team/Kconfig @@ -40,4 +40,15 @@ config NET_TEAM_MODE_ACTIVEBACKUP To compile this team mode as a module, choose M here: the module will be called team_mode_activebackup. +config NET_TEAM_MODE_LOADBALANCE + tristate "Load-balance mode support" + depends on NET_TEAM + ---help--- + This mode provides load balancing functionality. Tx port selection + is done using BPF function set up from userspace (bpf_hash_func + option) + + To compile this team mode as a module, choose M here: the module + will be called team_mode_loadbalance. + endif # NET_TEAM diff --git a/trunk/drivers/net/team/Makefile b/trunk/drivers/net/team/Makefile index 85f2028a87af..fb9f4c1c51ff 100644 --- a/trunk/drivers/net/team/Makefile +++ b/trunk/drivers/net/team/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_NET_TEAM) += team.o obj-$(CONFIG_NET_TEAM_MODE_ROUNDROBIN) += team_mode_roundrobin.o obj-$(CONFIG_NET_TEAM_MODE_ACTIVEBACKUP) += team_mode_activebackup.o +obj-$(CONFIG_NET_TEAM_MODE_LOADBALANCE) += team_mode_loadbalance.o diff --git a/trunk/drivers/net/team/team.c b/trunk/drivers/net/team/team.c index 8f81805c6825..c61ae35a53ce 100644 --- a/trunk/drivers/net/team/team.c +++ b/trunk/drivers/net/team/team.c @@ -65,7 +65,7 @@ static int __set_port_mac(struct net_device *port_dev, return dev_set_mac_address(port_dev, &addr); } -int team_port_set_orig_mac(struct team_port *port) +static int team_port_set_orig_mac(struct team_port *port) { return __set_port_mac(port->dev, port->orig.dev_addr); } @@ -76,12 +76,26 @@ int team_port_set_team_mac(struct team_port *port) } EXPORT_SYMBOL(team_port_set_team_mac); +static void team_refresh_port_linkup(struct team_port *port) +{ + port->linkup = port->user.linkup_enabled ? port->user.linkup : + port->state.linkup; +} /******************* * Options handling *******************/ -struct team_option *__team_find_option(struct team *team, const char *opt_name) +struct team_option_inst { /* One for each option instance */ + struct list_head list; + struct team_option *option; + struct team_port *port; /* != NULL if per-port */ + bool changed; + bool removed; +}; + +static struct team_option *__team_find_option(struct team *team, + const char *opt_name) { struct team_option *option; @@ -92,9 +106,121 @@ struct team_option *__team_find_option(struct team *team, const char *opt_name) return NULL; } -int __team_options_register(struct team *team, - const struct team_option *option, - size_t option_count) +static int __team_option_inst_add(struct team *team, struct team_option *option, + struct team_port *port) +{ + struct team_option_inst *opt_inst; + + opt_inst = kmalloc(sizeof(*opt_inst), GFP_KERNEL); + if (!opt_inst) + return -ENOMEM; + opt_inst->option = option; + opt_inst->port = port; + opt_inst->changed = true; + opt_inst->removed = false; + list_add_tail(&opt_inst->list, &team->option_inst_list); + return 0; +} + +static void __team_option_inst_del(struct team_option_inst *opt_inst) +{ + list_del(&opt_inst->list); + kfree(opt_inst); +} + +static void __team_option_inst_del_option(struct team *team, + struct team_option *option) +{ + struct team_option_inst *opt_inst, *tmp; + + list_for_each_entry_safe(opt_inst, tmp, &team->option_inst_list, list) { + if (opt_inst->option == option) + __team_option_inst_del(opt_inst); + } +} + +static int __team_option_inst_add_option(struct team *team, + struct team_option *option) +{ + struct team_port *port; + int err; + + if (!option->per_port) + return __team_option_inst_add(team, option, 0); + + list_for_each_entry(port, &team->port_list, list) { + err = __team_option_inst_add(team, option, port); + if (err) + goto inst_del_option; + } + return 0; + +inst_del_option: + __team_option_inst_del_option(team, option); + return err; +} + +static void __team_option_inst_mark_removed_option(struct team *team, + struct team_option *option) +{ + struct team_option_inst *opt_inst; + + list_for_each_entry(opt_inst, &team->option_inst_list, list) { + if (opt_inst->option == option) { + opt_inst->changed = true; + opt_inst->removed = true; + } + } +} + +static void __team_option_inst_del_port(struct team *team, + struct team_port *port) +{ + struct team_option_inst *opt_inst, *tmp; + + list_for_each_entry_safe(opt_inst, tmp, &team->option_inst_list, list) { + if (opt_inst->option->per_port && + opt_inst->port == port) + __team_option_inst_del(opt_inst); + } +} + +static int __team_option_inst_add_port(struct team *team, + struct team_port *port) +{ + struct team_option *option; + int err; + + list_for_each_entry(option, &team->option_list, list) { + if (!option->per_port) + continue; + err = __team_option_inst_add(team, option, port); + if (err) + goto inst_del_port; + } + return 0; + +inst_del_port: + __team_option_inst_del_port(team, port); + return err; +} + +static void __team_option_inst_mark_removed_port(struct team *team, + struct team_port *port) +{ + struct team_option_inst *opt_inst; + + list_for_each_entry(opt_inst, &team->option_inst_list, list) { + if (opt_inst->port == port) { + opt_inst->changed = true; + opt_inst->removed = true; + } + } +} + +static int __team_options_register(struct team *team, + const struct team_option *option, + size_t option_count) { int i; struct team_option **dst_opts; @@ -107,26 +233,32 @@ int __team_options_register(struct team *team, for (i = 0; i < option_count; i++, option++) { if (__team_find_option(team, option->name)) { err = -EEXIST; - goto rollback; + goto alloc_rollback; } dst_opts[i] = kmemdup(option, sizeof(*option), GFP_KERNEL); if (!dst_opts[i]) { err = -ENOMEM; - goto rollback; + goto alloc_rollback; } } for (i = 0; i < option_count; i++) { - dst_opts[i]->changed = true; - dst_opts[i]->removed = false; + err = __team_option_inst_add_option(team, dst_opts[i]); + if (err) + goto inst_rollback; list_add_tail(&dst_opts[i]->list, &team->option_list); } kfree(dst_opts); return 0; -rollback: - for (i = 0; i < option_count; i++) +inst_rollback: + for (i--; i >= 0; i--) + __team_option_inst_del_option(team, dst_opts[i]); + + i = option_count - 1; +alloc_rollback: + for (i--; i >= 0; i--) kfree(dst_opts[i]); kfree(dst_opts); @@ -143,10 +275,8 @@ static void __team_options_mark_removed(struct team *team, struct team_option *del_opt; del_opt = __team_find_option(team, option->name); - if (del_opt) { - del_opt->changed = true; - del_opt->removed = true; - } + if (del_opt) + __team_option_inst_mark_removed_option(team, del_opt); } } @@ -161,6 +291,7 @@ static void __team_options_unregister(struct team *team, del_opt = __team_find_option(team, option->name); if (del_opt) { + __team_option_inst_del_option(team, del_opt); list_del(&del_opt->list); kfree(del_opt); } @@ -193,22 +324,42 @@ void team_options_unregister(struct team *team, } EXPORT_SYMBOL(team_options_unregister); -static int team_option_get(struct team *team, struct team_option *option, - void *arg) +static int team_option_port_add(struct team *team, struct team_port *port) +{ + int err; + + err = __team_option_inst_add_port(team, port); + if (err) + return err; + __team_options_change_check(team); + return 0; +} + +static void team_option_port_del(struct team *team, struct team_port *port) +{ + __team_option_inst_mark_removed_port(team, port); + __team_options_change_check(team); + __team_option_inst_del_port(team, port); +} + +static int team_option_get(struct team *team, + struct team_option_inst *opt_inst, + struct team_gsetter_ctx *ctx) { - return option->getter(team, arg); + return opt_inst->option->getter(team, ctx); } -static int team_option_set(struct team *team, struct team_option *option, - void *arg) +static int team_option_set(struct team *team, + struct team_option_inst *opt_inst, + struct team_gsetter_ctx *ctx) { int err; - err = option->setter(team, arg); + err = opt_inst->option->setter(team, ctx); if (err) return err; - option->changed = true; + opt_inst->changed = true; __team_options_change_check(team); return err; } @@ -408,6 +559,8 @@ static int team_change_mode(struct team *team, const char *kind) * Rx path frame handler ************************/ +static bool team_port_enabled(struct team_port *port); + /* note: already called with rcu_read_lock */ static rx_handler_result_t team_handle_frame(struct sk_buff **pskb) { @@ -424,8 +577,12 @@ static rx_handler_result_t team_handle_frame(struct sk_buff **pskb) port = team_port_get_rcu(skb->dev); team = port->team; - - res = team->ops.receive(team, port, skb); + if (!team_port_enabled(port)) { + /* allow exact match delivery for disabled ports */ + res = RX_HANDLER_EXACT; + } else { + res = team->ops.receive(team, port, skb); + } if (res == RX_HANDLER_ANOTHER) { struct team_pcpu_stats *pcpu_stats; @@ -461,17 +618,25 @@ static bool team_port_find(const struct team *team, return false; } +static bool team_port_enabled(struct team_port *port) +{ + return port->index != -1; +} + /* - * Add/delete port to the team port list. Write guarded by rtnl_lock. - * Takes care of correct port->index setup (might be racy). + * Enable/disable port by adding to enabled port hashlist and setting + * port->index (Might be racy so reader could see incorrect ifindex when + * processing a flying packet, but that is not a problem). Write guarded + * by team->lock. */ -static void team_port_list_add_port(struct team *team, - struct team_port *port) +static void team_port_enable(struct team *team, + struct team_port *port) { - port->index = team->port_count++; + if (team_port_enabled(port)) + return; + port->index = team->en_port_count++; hlist_add_head_rcu(&port->hlist, team_port_index_hash(team, port->index)); - list_add_tail_rcu(&port->list, &team->port_list); } static void __reconstruct_port_hlist(struct team *team, int rm_index) @@ -479,7 +644,7 @@ static void __reconstruct_port_hlist(struct team *team, int rm_index) int i; struct team_port *port; - for (i = rm_index + 1; i < team->port_count; i++) { + for (i = rm_index + 1; i < team->en_port_count; i++) { port = team_get_port_by_index(team, i); hlist_del_rcu(&port->hlist); port->index--; @@ -488,15 +653,17 @@ static void __reconstruct_port_hlist(struct team *team, int rm_index) } } -static void team_port_list_del_port(struct team *team, - struct team_port *port) +static void team_port_disable(struct team *team, + struct team_port *port) { int rm_index = port->index; + if (!team_port_enabled(port)) + return; hlist_del_rcu(&port->hlist); - list_del_rcu(&port->list); __reconstruct_port_hlist(team, rm_index); - team->port_count--; + team->en_port_count--; + port->index = -1; } #define TEAM_VLAN_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | \ @@ -642,7 +809,16 @@ static int team_port_add(struct team *team, struct net_device *port_dev) goto err_handler_register; } - team_port_list_add_port(team, port); + err = team_option_port_add(team, port); + if (err) { + netdev_err(dev, "Device %s failed to add per-port options\n", + portname); + goto err_option_port_add; + } + + port->index = -1; + team_port_enable(team, port); + list_add_tail_rcu(&port->list, &team->port_list); team_adjust_ops(team); __team_compute_features(team); __team_port_change_check(port, !!netif_carrier_ok(port_dev)); @@ -651,6 +827,9 @@ static int team_port_add(struct team *team, struct net_device *port_dev) return 0; +err_option_port_add: + netdev_rx_handler_unregister(port_dev); + err_handler_register: netdev_set_master(port_dev, NULL); @@ -688,8 +867,10 @@ static int team_port_del(struct team *team, struct net_device *port_dev) port->removed = true; __team_port_change_check(port, false); - team_port_list_del_port(team, port); + team_port_disable(team, port); + list_del_rcu(&port->list); team_adjust_ops(team); + team_option_port_del(team, port); netdev_rx_handler_unregister(port_dev); netdev_set_master(port_dev, NULL); vlan_vids_del_by_dev(port_dev, dev); @@ -712,19 +893,66 @@ static int team_port_del(struct team *team, struct net_device *port_dev) static const char team_no_mode_kind[] = "*NOMODE*"; -static int team_mode_option_get(struct team *team, void *arg) +static int team_mode_option_get(struct team *team, struct team_gsetter_ctx *ctx) +{ + ctx->data.str_val = team->mode ? team->mode->kind : team_no_mode_kind; + return 0; +} + +static int team_mode_option_set(struct team *team, struct team_gsetter_ctx *ctx) +{ + return team_change_mode(team, ctx->data.str_val); +} + +static int team_port_en_option_get(struct team *team, + struct team_gsetter_ctx *ctx) +{ + ctx->data.bool_val = team_port_enabled(ctx->port); + return 0; +} + +static int team_port_en_option_set(struct team *team, + struct team_gsetter_ctx *ctx) +{ + if (ctx->data.bool_val) + team_port_enable(team, ctx->port); + else + team_port_disable(team, ctx->port); + return 0; +} + +static int team_user_linkup_option_get(struct team *team, + struct team_gsetter_ctx *ctx) +{ + ctx->data.bool_val = ctx->port->user.linkup; + return 0; +} + +static int team_user_linkup_option_set(struct team *team, + struct team_gsetter_ctx *ctx) +{ + ctx->port->user.linkup = ctx->data.bool_val; + team_refresh_port_linkup(ctx->port); + return 0; +} + +static int team_user_linkup_en_option_get(struct team *team, + struct team_gsetter_ctx *ctx) { - const char **str = arg; + struct team_port *port = ctx->port; - *str = team->mode ? team->mode->kind : team_no_mode_kind; + ctx->data.bool_val = port->user.linkup_enabled; return 0; } -static int team_mode_option_set(struct team *team, void *arg) +static int team_user_linkup_en_option_set(struct team *team, + struct team_gsetter_ctx *ctx) { - const char **str = arg; + struct team_port *port = ctx->port; - return team_change_mode(team, *str); + port->user.linkup_enabled = ctx->data.bool_val; + team_refresh_port_linkup(ctx->port); + return 0; } static const struct team_option team_options[] = { @@ -734,6 +962,27 @@ static const struct team_option team_options[] = { .getter = team_mode_option_get, .setter = team_mode_option_set, }, + { + .name = "enabled", + .type = TEAM_OPTION_TYPE_BOOL, + .per_port = true, + .getter = team_port_en_option_get, + .setter = team_port_en_option_set, + }, + { + .name = "user_linkup", + .type = TEAM_OPTION_TYPE_BOOL, + .per_port = true, + .getter = team_user_linkup_option_get, + .setter = team_user_linkup_option_set, + }, + { + .name = "user_linkup_enabled", + .type = TEAM_OPTION_TYPE_BOOL, + .per_port = true, + .getter = team_user_linkup_en_option_get, + .setter = team_user_linkup_en_option_set, + }, }; static int team_init(struct net_device *dev) @@ -750,12 +999,13 @@ static int team_init(struct net_device *dev) return -ENOMEM; for (i = 0; i < TEAM_PORT_HASHENTRIES; i++) - INIT_HLIST_HEAD(&team->port_hlist[i]); + INIT_HLIST_HEAD(&team->en_port_hlist[i]); INIT_LIST_HEAD(&team->port_list); team_adjust_ops(team); INIT_LIST_HEAD(&team->option_list); + INIT_LIST_HEAD(&team->option_inst_list); err = team_options_register(team, team_options, ARRAY_SIZE(team_options)); if (err) goto err_options_register; @@ -1145,10 +1395,7 @@ team_nl_option_policy[TEAM_ATTR_OPTION_MAX + 1] = { }, [TEAM_ATTR_OPTION_CHANGED] = { .type = NLA_FLAG }, [TEAM_ATTR_OPTION_TYPE] = { .type = NLA_U8 }, - [TEAM_ATTR_OPTION_DATA] = { - .type = NLA_BINARY, - .len = TEAM_STRING_MAX_LEN, - }, + [TEAM_ATTR_OPTION_DATA] = { .type = NLA_BINARY }, }; static int team_nl_cmd_noop(struct sk_buff *skb, struct genl_info *info) @@ -1241,46 +1488,86 @@ static int team_nl_fill_options_get(struct sk_buff *skb, { struct nlattr *option_list; void *hdr; - struct team_option *option; + struct team_option_inst *opt_inst; + int err; hdr = genlmsg_put(skb, pid, seq, &team_nl_family, flags, TEAM_CMD_OPTIONS_GET); if (IS_ERR(hdr)) return PTR_ERR(hdr); - NLA_PUT_U32(skb, TEAM_ATTR_TEAM_IFINDEX, team->dev->ifindex); + if (nla_put_u32(skb, TEAM_ATTR_TEAM_IFINDEX, team->dev->ifindex)) + goto nla_put_failure; option_list = nla_nest_start(skb, TEAM_ATTR_LIST_OPTION); if (!option_list) return -EMSGSIZE; - list_for_each_entry(option, &team->option_list, list) { + list_for_each_entry(opt_inst, &team->option_inst_list, list) { struct nlattr *option_item; - long arg; + struct team_option *option = opt_inst->option; + struct team_gsetter_ctx ctx; /* Include only changed options if fill all mode is not on */ - if (!fillall && !option->changed) + if (!fillall && !opt_inst->changed) continue; option_item = nla_nest_start(skb, TEAM_ATTR_ITEM_OPTION); if (!option_item) goto nla_put_failure; - NLA_PUT_STRING(skb, TEAM_ATTR_OPTION_NAME, option->name); - if (option->changed) { - NLA_PUT_FLAG(skb, TEAM_ATTR_OPTION_CHANGED); - option->changed = false; + if (nla_put_string(skb, TEAM_ATTR_OPTION_NAME, option->name)) + goto nla_put_failure; + if (opt_inst->changed) { + if (nla_put_flag(skb, TEAM_ATTR_OPTION_CHANGED)) + goto nla_put_failure; + opt_inst->changed = false; } - if (option->removed) - NLA_PUT_FLAG(skb, TEAM_ATTR_OPTION_REMOVED); + if (opt_inst->removed && + nla_put_flag(skb, TEAM_ATTR_OPTION_REMOVED)) + goto nla_put_failure; + if (opt_inst->port && + nla_put_u32(skb, TEAM_ATTR_OPTION_PORT_IFINDEX, + opt_inst->port->dev->ifindex)) + goto nla_put_failure; + ctx.port = opt_inst->port; switch (option->type) { case TEAM_OPTION_TYPE_U32: - NLA_PUT_U8(skb, TEAM_ATTR_OPTION_TYPE, NLA_U32); - team_option_get(team, option, &arg); - NLA_PUT_U32(skb, TEAM_ATTR_OPTION_DATA, arg); + if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_U32)) + goto nla_put_failure; + err = team_option_get(team, opt_inst, &ctx); + if (err) + goto errout; + if (nla_put_u32(skb, TEAM_ATTR_OPTION_DATA, + ctx.data.u32_val)) + goto nla_put_failure; break; case TEAM_OPTION_TYPE_STRING: - NLA_PUT_U8(skb, TEAM_ATTR_OPTION_TYPE, NLA_STRING); - team_option_get(team, option, &arg); - NLA_PUT_STRING(skb, TEAM_ATTR_OPTION_DATA, - (char *) arg); + if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_STRING)) + goto nla_put_failure; + err = team_option_get(team, opt_inst, &ctx); + if (err) + goto errout; + if (nla_put_string(skb, TEAM_ATTR_OPTION_DATA, + ctx.data.str_val)) + goto nla_put_failure; + break; + case TEAM_OPTION_TYPE_BINARY: + if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_BINARY)) + goto nla_put_failure; + err = team_option_get(team, opt_inst, &ctx); + if (err) + goto errout; + if (nla_put(skb, TEAM_ATTR_OPTION_DATA, + ctx.data.bin_val.len, ctx.data.bin_val.ptr)) + goto nla_put_failure; + break; + case TEAM_OPTION_TYPE_BOOL: + if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_FLAG)) + goto nla_put_failure; + err = team_option_get(team, opt_inst, &ctx); + if (err) + goto errout; + if (ctx.data.bool_val && + nla_put_flag(skb, TEAM_ATTR_OPTION_DATA)) + goto nla_put_failure; break; default: BUG(); @@ -1292,8 +1579,10 @@ static int team_nl_fill_options_get(struct sk_buff *skb, return genlmsg_end(skb, hdr); nla_put_failure: + err = -EMSGSIZE; +errout: genlmsg_cancel(skb, hdr); - return -EMSGSIZE; + return err; } static int team_nl_fill_options_get_all(struct sk_buff *skb, @@ -1339,9 +1628,12 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info) } nla_for_each_nested(nl_option, info->attrs[TEAM_ATTR_LIST_OPTION], i) { - struct nlattr *mode_attrs[TEAM_ATTR_OPTION_MAX + 1]; + struct nlattr *opt_attrs[TEAM_ATTR_OPTION_MAX + 1]; + struct nlattr *attr_port_ifindex; + struct nlattr *attr_data; enum team_option_type opt_type; - struct team_option *option; + int opt_port_ifindex = 0; /* != 0 for per-port options */ + struct team_option_inst *opt_inst; char *opt_name; bool opt_found = false; @@ -1349,48 +1641,78 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info) err = -EINVAL; goto team_put; } - err = nla_parse_nested(mode_attrs, TEAM_ATTR_OPTION_MAX, + err = nla_parse_nested(opt_attrs, TEAM_ATTR_OPTION_MAX, nl_option, team_nl_option_policy); if (err) goto team_put; - if (!mode_attrs[TEAM_ATTR_OPTION_NAME] || - !mode_attrs[TEAM_ATTR_OPTION_TYPE] || - !mode_attrs[TEAM_ATTR_OPTION_DATA]) { + if (!opt_attrs[TEAM_ATTR_OPTION_NAME] || + !opt_attrs[TEAM_ATTR_OPTION_TYPE]) { err = -EINVAL; goto team_put; } - switch (nla_get_u8(mode_attrs[TEAM_ATTR_OPTION_TYPE])) { + switch (nla_get_u8(opt_attrs[TEAM_ATTR_OPTION_TYPE])) { case NLA_U32: opt_type = TEAM_OPTION_TYPE_U32; break; case NLA_STRING: opt_type = TEAM_OPTION_TYPE_STRING; break; + case NLA_BINARY: + opt_type = TEAM_OPTION_TYPE_BINARY; + break; + case NLA_FLAG: + opt_type = TEAM_OPTION_TYPE_BOOL; + break; default: goto team_put; } - opt_name = nla_data(mode_attrs[TEAM_ATTR_OPTION_NAME]); - list_for_each_entry(option, &team->option_list, list) { - long arg; - struct nlattr *opt_data_attr; + attr_data = opt_attrs[TEAM_ATTR_OPTION_DATA]; + if (opt_type != TEAM_OPTION_TYPE_BOOL && !attr_data) { + err = -EINVAL; + goto team_put; + } + + opt_name = nla_data(opt_attrs[TEAM_ATTR_OPTION_NAME]); + attr_port_ifindex = opt_attrs[TEAM_ATTR_OPTION_PORT_IFINDEX]; + if (attr_port_ifindex) + opt_port_ifindex = nla_get_u32(attr_port_ifindex); + + list_for_each_entry(opt_inst, &team->option_inst_list, list) { + struct team_option *option = opt_inst->option; + struct team_gsetter_ctx ctx; + int tmp_ifindex; + tmp_ifindex = opt_inst->port ? + opt_inst->port->dev->ifindex : 0; if (option->type != opt_type || - strcmp(option->name, opt_name)) + strcmp(option->name, opt_name) || + tmp_ifindex != opt_port_ifindex) continue; opt_found = true; - opt_data_attr = mode_attrs[TEAM_ATTR_OPTION_DATA]; + ctx.port = opt_inst->port; switch (opt_type) { case TEAM_OPTION_TYPE_U32: - arg = nla_get_u32(opt_data_attr); + ctx.data.u32_val = nla_get_u32(attr_data); break; case TEAM_OPTION_TYPE_STRING: - arg = (long) nla_data(opt_data_attr); + if (nla_len(attr_data) > TEAM_STRING_MAX_LEN) { + err = -EINVAL; + goto team_put; + } + ctx.data.str_val = nla_data(attr_data); + break; + case TEAM_OPTION_TYPE_BINARY: + ctx.data.bin_val.len = nla_len(attr_data); + ctx.data.bin_val.ptr = nla_data(attr_data); + break; + case TEAM_OPTION_TYPE_BOOL: + ctx.data.bool_val = attr_data ? true : false; break; default: BUG(); } - err = team_option_set(team, option, &arg); + err = team_option_set(team, opt_inst, &ctx); if (err) goto team_put; } @@ -1420,7 +1742,8 @@ static int team_nl_fill_port_list_get(struct sk_buff *skb, if (IS_ERR(hdr)) return PTR_ERR(hdr); - NLA_PUT_U32(skb, TEAM_ATTR_TEAM_IFINDEX, team->dev->ifindex); + if (nla_put_u32(skb, TEAM_ATTR_TEAM_IFINDEX, team->dev->ifindex)) + goto nla_put_failure; port_list = nla_nest_start(skb, TEAM_ATTR_LIST_PORT); if (!port_list) return -EMSGSIZE; @@ -1434,17 +1757,20 @@ static int team_nl_fill_port_list_get(struct sk_buff *skb, port_item = nla_nest_start(skb, TEAM_ATTR_ITEM_PORT); if (!port_item) goto nla_put_failure; - NLA_PUT_U32(skb, TEAM_ATTR_PORT_IFINDEX, port->dev->ifindex); + if (nla_put_u32(skb, TEAM_ATTR_PORT_IFINDEX, port->dev->ifindex)) + goto nla_put_failure; if (port->changed) { - NLA_PUT_FLAG(skb, TEAM_ATTR_PORT_CHANGED); + if (nla_put_flag(skb, TEAM_ATTR_PORT_CHANGED)) + goto nla_put_failure; port->changed = false; } - if (port->removed) - NLA_PUT_FLAG(skb, TEAM_ATTR_PORT_REMOVED); - if (port->linkup) - NLA_PUT_FLAG(skb, TEAM_ATTR_PORT_LINKUP); - NLA_PUT_U32(skb, TEAM_ATTR_PORT_SPEED, port->speed); - NLA_PUT_U8(skb, TEAM_ATTR_PORT_DUPLEX, port->duplex); + if ((port->removed && + nla_put_flag(skb, TEAM_ATTR_PORT_REMOVED)) || + (port->state.linkup && + nla_put_flag(skb, TEAM_ATTR_PORT_LINKUP)) || + nla_put_u32(skb, TEAM_ATTR_PORT_SPEED, port->state.speed) || + nla_put_u8(skb, TEAM_ATTR_PORT_DUPLEX, port->state.duplex)) + goto nla_put_failure; nla_nest_end(skb, port_item); } @@ -1603,23 +1929,24 @@ static void __team_port_change_check(struct team_port *port, bool linkup) { int err; - if (!port->removed && port->linkup == linkup) + if (!port->removed && port->state.linkup == linkup) return; port->changed = true; - port->linkup = linkup; + port->state.linkup = linkup; + team_refresh_port_linkup(port); if (linkup) { struct ethtool_cmd ecmd; err = __ethtool_get_settings(port->dev, &ecmd); if (!err) { - port->speed = ethtool_cmd_speed(&ecmd); - port->duplex = ecmd.duplex; + port->state.speed = ethtool_cmd_speed(&ecmd); + port->state.duplex = ecmd.duplex; goto send_event; } } - port->speed = 0; - port->duplex = 0; + port->state.speed = 0; + port->state.duplex = 0; send_event: err = team_nl_send_event_port_list_get(port->team); diff --git a/trunk/drivers/net/team/team_mode_activebackup.c b/trunk/drivers/net/team/team_mode_activebackup.c index f4d960e82e29..fd6bd03aaa89 100644 --- a/trunk/drivers/net/team/team_mode_activebackup.c +++ b/trunk/drivers/net/team/team_mode_activebackup.c @@ -59,23 +59,21 @@ static void ab_port_leave(struct team *team, struct team_port *port) RCU_INIT_POINTER(ab_priv(team)->active_port, NULL); } -static int ab_active_port_get(struct team *team, void *arg) +static int ab_active_port_get(struct team *team, struct team_gsetter_ctx *ctx) { - u32 *ifindex = arg; - - *ifindex = 0; if (ab_priv(team)->active_port) - *ifindex = ab_priv(team)->active_port->dev->ifindex; + ctx->data.u32_val = ab_priv(team)->active_port->dev->ifindex; + else + ctx->data.u32_val = 0; return 0; } -static int ab_active_port_set(struct team *team, void *arg) +static int ab_active_port_set(struct team *team, struct team_gsetter_ctx *ctx) { - u32 *ifindex = arg; struct team_port *port; - list_for_each_entry_rcu(port, &team->port_list, list) { - if (port->dev->ifindex == *ifindex) { + list_for_each_entry(port, &team->port_list, list) { + if (port->dev->ifindex == ctx->data.u32_val) { rcu_assign_pointer(ab_priv(team)->active_port, port); return 0; } @@ -92,12 +90,12 @@ static const struct team_option ab_options[] = { }, }; -int ab_init(struct team *team) +static int ab_init(struct team *team) { return team_options_register(team, ab_options, ARRAY_SIZE(ab_options)); } -void ab_exit(struct team *team) +static void ab_exit(struct team *team) { team_options_unregister(team, ab_options, ARRAY_SIZE(ab_options)); } diff --git a/trunk/drivers/net/team/team_mode_loadbalance.c b/trunk/drivers/net/team/team_mode_loadbalance.c new file mode 100644 index 000000000000..86e8183c8e3d --- /dev/null +++ b/trunk/drivers/net/team/team_mode_loadbalance.c @@ -0,0 +1,174 @@ +/* + * drivers/net/team/team_mode_loadbalance.c - Load-balancing mode for team + * Copyright (c) 2012 Jiri Pirko + * + * 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 lb_priv { + struct sk_filter __rcu *fp; + struct sock_fprog *orig_fprog; +}; + +static struct lb_priv *lb_priv(struct team *team) +{ + return (struct lb_priv *) &team->mode_priv; +} + +static bool lb_transmit(struct team *team, struct sk_buff *skb) +{ + struct sk_filter *fp; + struct team_port *port; + unsigned int hash; + int port_index; + + fp = rcu_dereference(lb_priv(team)->fp); + if (unlikely(!fp)) + goto drop; + hash = SK_RUN_FILTER(fp, skb); + port_index = hash % team->en_port_count; + port = team_get_port_by_index_rcu(team, port_index); + if (unlikely(!port)) + goto drop; + skb->dev = port->dev; + if (dev_queue_xmit(skb)) + return false; + return true; + +drop: + dev_kfree_skb_any(skb); + return false; +} + +static int lb_bpf_func_get(struct team *team, struct team_gsetter_ctx *ctx) +{ + if (!lb_priv(team)->orig_fprog) { + ctx->data.bin_val.len = 0; + ctx->data.bin_val.ptr = NULL; + return 0; + } + ctx->data.bin_val.len = lb_priv(team)->orig_fprog->len * + sizeof(struct sock_filter); + ctx->data.bin_val.ptr = lb_priv(team)->orig_fprog->filter; + return 0; +} + +static int __fprog_create(struct sock_fprog **pfprog, u32 data_len, + const void *data) +{ + struct sock_fprog *fprog; + struct sock_filter *filter = (struct sock_filter *) data; + + if (data_len % sizeof(struct sock_filter)) + return -EINVAL; + fprog = kmalloc(sizeof(struct sock_fprog), GFP_KERNEL); + if (!fprog) + return -ENOMEM; + fprog->filter = kmemdup(filter, data_len, GFP_KERNEL); + if (!fprog->filter) { + kfree(fprog); + return -ENOMEM; + } + fprog->len = data_len / sizeof(struct sock_filter); + *pfprog = fprog; + return 0; +} + +static void __fprog_destroy(struct sock_fprog *fprog) +{ + kfree(fprog->filter); + kfree(fprog); +} + +static int lb_bpf_func_set(struct team *team, struct team_gsetter_ctx *ctx) +{ + struct sk_filter *fp = NULL; + struct sock_fprog *fprog = NULL; + int err; + + if (ctx->data.bin_val.len) { + err = __fprog_create(&fprog, ctx->data.bin_val.len, + ctx->data.bin_val.ptr); + if (err) + return err; + err = sk_unattached_filter_create(&fp, fprog); + if (err) { + __fprog_destroy(fprog); + return err; + } + } + + if (lb_priv(team)->orig_fprog) { + /* Clear old filter data */ + __fprog_destroy(lb_priv(team)->orig_fprog); + sk_unattached_filter_destroy(lb_priv(team)->fp); + } + + rcu_assign_pointer(lb_priv(team)->fp, fp); + lb_priv(team)->orig_fprog = fprog; + return 0; +} + +static const struct team_option lb_options[] = { + { + .name = "bpf_hash_func", + .type = TEAM_OPTION_TYPE_BINARY, + .getter = lb_bpf_func_get, + .setter = lb_bpf_func_set, + }, +}; + +static int lb_init(struct team *team) +{ + return team_options_register(team, lb_options, + ARRAY_SIZE(lb_options)); +} + +static void lb_exit(struct team *team) +{ + team_options_unregister(team, lb_options, + ARRAY_SIZE(lb_options)); +} + +static const struct team_mode_ops lb_mode_ops = { + .init = lb_init, + .exit = lb_exit, + .transmit = lb_transmit, +}; + +static struct team_mode lb_mode = { + .kind = "loadbalance", + .owner = THIS_MODULE, + .priv_size = sizeof(struct lb_priv), + .ops = &lb_mode_ops, +}; + +static int __init lb_init_module(void) +{ + return team_mode_register(&lb_mode); +} + +static void __exit lb_cleanup_module(void) +{ + team_mode_unregister(&lb_mode); +} + +module_init(lb_init_module); +module_exit(lb_cleanup_module); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Jiri Pirko "); +MODULE_DESCRIPTION("Load-balancing mode for team"); +MODULE_ALIAS("team-mode-loadbalance"); diff --git a/trunk/drivers/net/team/team_mode_roundrobin.c b/trunk/drivers/net/team/team_mode_roundrobin.c index a0e8f806331a..6abfbdc96be5 100644 --- a/trunk/drivers/net/team/team_mode_roundrobin.c +++ b/trunk/drivers/net/team/team_mode_roundrobin.c @@ -50,7 +50,7 @@ static bool rr_transmit(struct team *team, struct sk_buff *skb) struct team_port *port; int port_index; - port_index = rr_priv(team)->sent_packets++ % team->port_count; + port_index = rr_priv(team)->sent_packets++ % team->en_port_count; port = team_get_port_by_index_rcu(team, port_index); port = __get_first_port_up(team, port); if (unlikely(!port)) diff --git a/trunk/drivers/net/tokenring/3c359.c b/trunk/drivers/net/tokenring/3c359.c deleted file mode 100644 index b15ac81d46fa..000000000000 --- a/trunk/drivers/net/tokenring/3c359.c +++ /dev/null @@ -1,1843 +0,0 @@ -/* - * 3c359.c (c) 2000 Mike Phillips (mikep@linuxtr.net) All Rights Reserved - * - * Linux driver for 3Com 3c359 Tokenlink Velocity XL PCI NIC - * - * Base Driver Olympic: - * Written 1999 Peter De Schrijver & Mike Phillips - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * 7/17/00 - Clean up, version number 0.9.0. Ready to release to the world. - * - * 2/16/01 - Port up to kernel 2.4.2 ready for submission into the kernel. - * 3/05/01 - Last clean up stuff before submission. - * 2/15/01 - Finally, update to new pci api. - * - * To Do: - */ - -/* - * Technical Card Details - * - * All access to data is done with 16/8 bit transfers. The transfer - * method really sucks. You can only read or write one location at a time. - * - * Also, the microcode for the card must be uploaded if the card does not have - * the flashrom on board. This is a 28K bloat in the driver when compiled - * as a module. - * - * Rx is very simple, status into a ring of descriptors, dma data transfer, - * interrupts to tell us when a packet is received. - * - * Tx is a little more interesting. Similar scenario, descriptor and dma data - * transfers, but we don't have to interrupt the card to tell it another packet - * is ready for transmission, we are just doing simple memory writes, not io or mmio - * writes. The card can be set up to simply poll on the next - * descriptor pointer and when this value is non-zero will automatically download - * the next packet. The card then interrupts us when the packet is done. - * - */ - -#define XL_DEBUG 0 - -#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 "3c359.h" - -static char version[] __devinitdata = -"3c359.c v1.2.0 2/17/01 - Mike Phillips (mikep@linuxtr.net)" ; - -#define FW_NAME "3com/3C359.bin" -MODULE_AUTHOR("Mike Phillips ") ; -MODULE_DESCRIPTION("3Com 3C359 Velocity XL Token Ring Adapter Driver\n") ; -MODULE_FIRMWARE(FW_NAME); - -/* Module parameters */ - -/* Ring Speed 0,4,16 - * 0 = Autosense - * 4,16 = Selected speed only, no autosense - * This allows the card to be the first on the ring - * and become the active monitor. - * - * WARNING: Some hubs will allow you to insert - * at the wrong speed. - * - * The adapter will _not_ fail to open if there are no - * active monitors on the ring, it will simply open up in - * its last known ringspeed if no ringspeed is specified. - */ - -static int ringspeed[XL_MAX_ADAPTERS] = {0,} ; - -module_param_array(ringspeed, int, NULL, 0); -MODULE_PARM_DESC(ringspeed,"3c359: Ringspeed selection - 4,16 or 0") ; - -/* Packet buffer size */ - -static int pkt_buf_sz[XL_MAX_ADAPTERS] = {0,} ; - -module_param_array(pkt_buf_sz, int, NULL, 0) ; -MODULE_PARM_DESC(pkt_buf_sz,"3c359: Initial buffer size") ; -/* Message Level */ - -static int message_level[XL_MAX_ADAPTERS] = {0,} ; - -module_param_array(message_level, int, NULL, 0) ; -MODULE_PARM_DESC(message_level, "3c359: Level of reported messages") ; -/* - * This is a real nasty way of doing this, but otherwise you - * will be stuck with 1555 lines of hex #'s in the code. - */ - -static DEFINE_PCI_DEVICE_TABLE(xl_pci_tbl) = -{ - {PCI_VENDOR_ID_3COM,PCI_DEVICE_ID_3COM_3C359, PCI_ANY_ID, PCI_ANY_ID, }, - { } /* terminate list */ -}; -MODULE_DEVICE_TABLE(pci,xl_pci_tbl) ; - -static int xl_init(struct net_device *dev); -static int xl_open(struct net_device *dev); -static int xl_open_hw(struct net_device *dev) ; -static int xl_hw_reset(struct net_device *dev); -static netdev_tx_t xl_xmit(struct sk_buff *skb, struct net_device *dev); -static void xl_dn_comp(struct net_device *dev); -static int xl_close(struct net_device *dev); -static void xl_set_rx_mode(struct net_device *dev); -static irqreturn_t xl_interrupt(int irq, void *dev_id); -static int xl_set_mac_address(struct net_device *dev, void *addr) ; -static void xl_arb_cmd(struct net_device *dev); -static void xl_asb_cmd(struct net_device *dev) ; -static void xl_srb_cmd(struct net_device *dev, int srb_cmd) ; -static void xl_wait_misr_flags(struct net_device *dev) ; -static int xl_change_mtu(struct net_device *dev, int mtu); -static void xl_srb_bh(struct net_device *dev) ; -static void xl_asb_bh(struct net_device *dev) ; -static void xl_reset(struct net_device *dev) ; -static void xl_freemem(struct net_device *dev) ; - - -/* EEProm Access Functions */ -static u16 xl_ee_read(struct net_device *dev, int ee_addr) ; -static void xl_ee_write(struct net_device *dev, int ee_addr, u16 ee_value) ; - -/* Debugging functions */ -#if XL_DEBUG -static void print_tx_state(struct net_device *dev) ; -static void print_rx_state(struct net_device *dev) ; - -static void print_tx_state(struct net_device *dev) -{ - - struct xl_private *xl_priv = netdev_priv(dev); - struct xl_tx_desc *txd ; - u8 __iomem *xl_mmio = xl_priv->xl_mmio ; - int i ; - - printk("tx_ring_head: %d, tx_ring_tail: %d, free_ent: %d\n",xl_priv->tx_ring_head, - xl_priv->tx_ring_tail, xl_priv->free_ring_entries) ; - printk("Ring , Address , FSH , DnNextPtr, Buffer, Buffer_Len\n"); - for (i = 0; i < 16; i++) { - txd = &(xl_priv->xl_tx_ring[i]) ; - printk("%d, %08lx, %08x, %08x, %08x, %08x\n", i, virt_to_bus(txd), - txd->framestartheader, txd->dnnextptr, txd->buffer, txd->buffer_length ) ; - } - - printk("DNLISTPTR = %04x\n", readl(xl_mmio + MMIO_DNLISTPTR) ); - - printk("DmaCtl = %04x\n", readl(xl_mmio + MMIO_DMA_CTRL) ); - printk("Queue status = %0x\n",netif_running(dev) ) ; -} - -static void print_rx_state(struct net_device *dev) -{ - - struct xl_private *xl_priv = netdev_priv(dev); - struct xl_rx_desc *rxd ; - u8 __iomem *xl_mmio = xl_priv->xl_mmio ; - int i ; - - printk("rx_ring_tail: %d\n", xl_priv->rx_ring_tail); - printk("Ring , Address , FrameState , UPNextPtr, FragAddr, Frag_Len\n"); - for (i = 0; i < 16; i++) { - /* rxd = (struct xl_rx_desc *)xl_priv->rx_ring_dma_addr + (i * sizeof(struct xl_rx_desc)) ; */ - rxd = &(xl_priv->xl_rx_ring[i]) ; - printk("%d, %08lx, %08x, %08x, %08x, %08x\n", i, virt_to_bus(rxd), - rxd->framestatus, rxd->upnextptr, rxd->upfragaddr, rxd->upfraglen ) ; - } - - printk("UPLISTPTR = %04x\n", readl(xl_mmio + MMIO_UPLISTPTR)); - - printk("DmaCtl = %04x\n", readl(xl_mmio + MMIO_DMA_CTRL)); - printk("Queue status = %0x\n",netif_running(dev)); -} -#endif - -/* - * Read values from the on-board EEProm. This looks very strange - * but you have to wait for the EEProm to get/set the value before - * passing/getting the next value from the nic. As with all requests - * on this nic it has to be done in two stages, a) tell the nic which - * memory address you want to access and b) pass/get the value from the nic. - * With the EEProm, you have to wait before and between access a) and b). - * As this is only read at initialization time and the wait period is very - * small we shouldn't have to worry about scheduling issues. - */ - -static u16 xl_ee_read(struct net_device *dev, int ee_addr) -{ - struct xl_private *xl_priv = netdev_priv(dev); - u8 __iomem *xl_mmio = xl_priv->xl_mmio ; - - /* Wait for EEProm to not be busy */ - writel(IO_WORD_READ | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - while ( readw(xl_mmio + MMIO_MACDATA) & EEBUSY ) ; - - /* Tell EEProm what we want to do and where */ - writel(IO_WORD_WRITE | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writew(EEREAD + ee_addr, xl_mmio + MMIO_MACDATA) ; - - /* Wait for EEProm to not be busy */ - writel(IO_WORD_READ | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - while ( readw(xl_mmio + MMIO_MACDATA) & EEBUSY ) ; - - /* Tell EEProm what we want to do and where */ - writel(IO_WORD_WRITE | EECONTROL , xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writew(EEREAD + ee_addr, xl_mmio + MMIO_MACDATA) ; - - /* Finally read the value from the EEProm */ - writel(IO_WORD_READ | EEDATA , xl_mmio + MMIO_MAC_ACCESS_CMD) ; - return readw(xl_mmio + MMIO_MACDATA) ; -} - -/* - * Write values to the onboard eeprom. As with eeprom read you need to - * set which location to write, wait, value to write, wait, with the - * added twist of having to enable eeprom writes as well. - */ - -static void xl_ee_write(struct net_device *dev, int ee_addr, u16 ee_value) -{ - struct xl_private *xl_priv = netdev_priv(dev); - u8 __iomem *xl_mmio = xl_priv->xl_mmio ; - - /* Wait for EEProm to not be busy */ - writel(IO_WORD_READ | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - while ( readw(xl_mmio + MMIO_MACDATA) & EEBUSY ) ; - - /* Enable write/erase */ - writel(IO_WORD_WRITE | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writew(EE_ENABLE_WRITE, xl_mmio + MMIO_MACDATA) ; - - /* Wait for EEProm to not be busy */ - writel(IO_WORD_READ | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - while ( readw(xl_mmio + MMIO_MACDATA) & EEBUSY ) ; - - /* Put the value we want to write into EEDATA */ - writel(IO_WORD_WRITE | EEDATA, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writew(ee_value, xl_mmio + MMIO_MACDATA) ; - - /* Tell EEProm to write eevalue into ee_addr */ - writel(IO_WORD_WRITE | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writew(EEWRITE + ee_addr, xl_mmio + MMIO_MACDATA) ; - - /* Wait for EEProm to not be busy, to ensure write gets done */ - writel(IO_WORD_READ | EECONTROL, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - while ( readw(xl_mmio + MMIO_MACDATA) & EEBUSY ) ; - - return ; -} - -static const struct net_device_ops xl_netdev_ops = { - .ndo_open = xl_open, - .ndo_stop = xl_close, - .ndo_start_xmit = xl_xmit, - .ndo_change_mtu = xl_change_mtu, - .ndo_set_rx_mode = xl_set_rx_mode, - .ndo_set_mac_address = xl_set_mac_address, -}; - -static int __devinit xl_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct net_device *dev ; - struct xl_private *xl_priv ; - static int card_no = -1 ; - int i ; - - card_no++ ; - - if (pci_enable_device(pdev)) { - return -ENODEV ; - } - - pci_set_master(pdev); - - if ((i = pci_request_regions(pdev,"3c359"))) { - return i ; - } - - /* - * Allowing init_trdev to allocate the private data will align - * xl_private on a 32 bytes boundary which we need for the rx/tx - * descriptors - */ - - dev = alloc_trdev(sizeof(struct xl_private)) ; - if (!dev) { - pci_release_regions(pdev) ; - return -ENOMEM ; - } - xl_priv = netdev_priv(dev); - -#if XL_DEBUG - printk("pci_device: %p, dev:%p, dev->priv: %p, ba[0]: %10x, ba[1]:%10x\n", - pdev, dev, netdev_priv(dev), (unsigned int)pdev->resource[0].start, (unsigned int)pdev->resource[1].start); -#endif - - dev->irq=pdev->irq; - dev->base_addr=pci_resource_start(pdev,0) ; - xl_priv->xl_card_name = pci_name(pdev); - xl_priv->xl_mmio=ioremap(pci_resource_start(pdev,1), XL_IO_SPACE); - xl_priv->pdev = pdev ; - - if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000) ) - xl_priv->pkt_buf_sz = PKT_BUF_SZ ; - else - xl_priv->pkt_buf_sz = pkt_buf_sz[card_no] ; - - dev->mtu = xl_priv->pkt_buf_sz - TR_HLEN ; - xl_priv->xl_ring_speed = ringspeed[card_no] ; - xl_priv->xl_message_level = message_level[card_no] ; - xl_priv->xl_functional_addr[0] = xl_priv->xl_functional_addr[1] = xl_priv->xl_functional_addr[2] = xl_priv->xl_functional_addr[3] = 0 ; - xl_priv->xl_copy_all_options = 0 ; - - if((i = xl_init(dev))) { - iounmap(xl_priv->xl_mmio) ; - free_netdev(dev) ; - pci_release_regions(pdev) ; - return i ; - } - - dev->netdev_ops = &xl_netdev_ops; - SET_NETDEV_DEV(dev, &pdev->dev); - - pci_set_drvdata(pdev,dev) ; - if ((i = register_netdev(dev))) { - printk(KERN_ERR "3C359, register netdev failed\n") ; - pci_set_drvdata(pdev,NULL) ; - iounmap(xl_priv->xl_mmio) ; - free_netdev(dev) ; - pci_release_regions(pdev) ; - return i ; - } - - printk(KERN_INFO "3C359: %s registered as: %s\n",xl_priv->xl_card_name,dev->name) ; - - return 0; -} - -static int xl_init_firmware(struct xl_private *xl_priv) -{ - int err; - - err = request_firmware(&xl_priv->fw, FW_NAME, &xl_priv->pdev->dev); - if (err) { - printk(KERN_ERR "Failed to load firmware \"%s\"\n", FW_NAME); - return err; - } - - if (xl_priv->fw->size < 16) { - printk(KERN_ERR "Bogus length %zu in \"%s\"\n", - xl_priv->fw->size, FW_NAME); - release_firmware(xl_priv->fw); - err = -EINVAL; - } - - return err; -} - -static int __devinit xl_init(struct net_device *dev) -{ - struct xl_private *xl_priv = netdev_priv(dev); - int err; - - printk(KERN_INFO "%s\n", version); - printk(KERN_INFO "%s: I/O at %hx, MMIO at %p, using irq %d\n", - xl_priv->xl_card_name, (unsigned int)dev->base_addr ,xl_priv->xl_mmio, dev->irq); - - spin_lock_init(&xl_priv->xl_lock) ; - - err = xl_init_firmware(xl_priv); - if (err == 0) - err = xl_hw_reset(dev); - - return err; -} - - -/* - * Hardware reset. This needs to be a separate entity as we need to reset the card - * when we change the EEProm settings. - */ - -static int xl_hw_reset(struct net_device *dev) -{ - struct xl_private *xl_priv = netdev_priv(dev); - u8 __iomem *xl_mmio = xl_priv->xl_mmio ; - unsigned long t ; - u16 i ; - u16 result_16 ; - u8 result_8 ; - u16 start ; - int j ; - - if (xl_priv->fw == NULL) - return -EINVAL; - - /* - * Reset the card. If the card has got the microcode on board, we have - * missed the initialization interrupt, so we must always do this. - */ - - writew( GLOBAL_RESET, xl_mmio + MMIO_COMMAND ) ; - - /* - * Must wait for cmdInProgress bit (12) to clear before continuing with - * card configuration. - */ - - t=jiffies; - while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { - schedule(); - if (time_after(jiffies, t + 40 * HZ)) { - printk(KERN_ERR "%s: 3COM 3C359 Velocity XL card not responding to global reset.\n", dev->name); - return -ENODEV; - } - } - - /* - * Enable pmbar by setting bit in CPAttention - */ - - writel( (IO_BYTE_READ | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; - result_8 = readb(xl_mmio + MMIO_MACDATA) ; - result_8 = result_8 | CPA_PMBARVIS ; - writel( (IO_BYTE_WRITE | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(result_8, xl_mmio + MMIO_MACDATA) ; - - /* - * Read cpHold bit in pmbar, if cleared we have got Flashrom on board. - * If not, we need to upload the microcode to the card - */ - - writel( (IO_WORD_READ | PMBAR),xl_mmio + MMIO_MAC_ACCESS_CMD); - -#if XL_DEBUG - printk(KERN_INFO "Read from PMBAR = %04x\n", readw(xl_mmio + MMIO_MACDATA)); -#endif - - if ( readw( (xl_mmio + MMIO_MACDATA)) & PMB_CPHOLD ) { - - /* Set PmBar, privateMemoryBase bits (8:2) to 0 */ - - writel( (IO_WORD_READ | PMBAR),xl_mmio + MMIO_MAC_ACCESS_CMD); - result_16 = readw(xl_mmio + MMIO_MACDATA) ; - result_16 = result_16 & ~((0x7F) << 2) ; - writel( (IO_WORD_WRITE | PMBAR), xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writew(result_16,xl_mmio + MMIO_MACDATA) ; - - /* Set CPAttention, memWrEn bit */ - - writel( (IO_BYTE_READ | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; - result_8 = readb(xl_mmio + MMIO_MACDATA) ; - result_8 = result_8 | CPA_MEMWREN ; - writel( (IO_BYTE_WRITE | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(result_8, xl_mmio + MMIO_MACDATA) ; - - /* - * Now to write the microcode into the shared ram - * The microcode must finish at position 0xFFFF, - * so we must subtract to get the start position for the code - * - * Looks strange but ensures compiler only uses - * 16 bit unsigned int - */ - start = (0xFFFF - (xl_priv->fw->size) + 1) ; - - printk(KERN_INFO "3C359: Uploading Microcode: "); - - for (i = start, j = 0; j < xl_priv->fw->size; i++, j++) { - writel(MEM_BYTE_WRITE | 0XD0000 | i, - xl_mmio + MMIO_MAC_ACCESS_CMD); - writeb(xl_priv->fw->data[j], xl_mmio + MMIO_MACDATA); - if (j % 1024 == 0) - printk("."); - } - printk("\n") ; - - for (i = 0; i < 16; i++) { - writel((MEM_BYTE_WRITE | 0xDFFF0) + i, - xl_mmio + MMIO_MAC_ACCESS_CMD); - writeb(xl_priv->fw->data[xl_priv->fw->size - 16 + i], - xl_mmio + MMIO_MACDATA); - } - - /* - * Have to write the start address of the upload to FFF4, but - * the address must be >> 4. You do not want to know how long - * it took me to discover this. - */ - - writel(MEM_WORD_WRITE | 0xDFFF4, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writew(start >> 4, xl_mmio + MMIO_MACDATA); - - /* Clear the CPAttention, memWrEn Bit */ - - writel( (IO_BYTE_READ | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; - result_8 = readb(xl_mmio + MMIO_MACDATA) ; - result_8 = result_8 & ~CPA_MEMWREN ; - writel( (IO_BYTE_WRITE | CPATTENTION), xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(result_8, xl_mmio + MMIO_MACDATA) ; - - /* Clear the cpHold bit in pmbar */ - - writel( (IO_WORD_READ | PMBAR),xl_mmio + MMIO_MAC_ACCESS_CMD); - result_16 = readw(xl_mmio + MMIO_MACDATA) ; - result_16 = result_16 & ~PMB_CPHOLD ; - writel( (IO_WORD_WRITE | PMBAR), xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writew(result_16,xl_mmio + MMIO_MACDATA) ; - - - } /* If microcode upload required */ - - /* - * The card should now go though a self test procedure and get itself ready - * to be opened, we must wait for an srb response with the initialization - * information. - */ - -#if XL_DEBUG - printk(KERN_INFO "%s: Microcode uploaded, must wait for the self test to complete\n", dev->name); -#endif - - writew(SETINDENABLE | 0xFFF, xl_mmio + MMIO_COMMAND) ; - - t=jiffies; - while ( !(readw(xl_mmio + MMIO_INTSTATUS_AUTO) & INTSTAT_SRB) ) { - schedule(); - if (time_after(jiffies, t + 15 * HZ)) { - printk(KERN_ERR "3COM 3C359 Velocity XL card not responding.\n"); - return -ENODEV; - } - } - - /* - * Write the RxBufArea with D000, RxEarlyThresh, TxStartThresh, - * DnPriReqThresh, read the tech docs if you want to know what - * values they need to be. - */ - - writel(MMIO_WORD_WRITE | RXBUFAREA, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writew(0xD000, xl_mmio + MMIO_MACDATA) ; - - writel(MMIO_WORD_WRITE | RXEARLYTHRESH, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writew(0X0020, xl_mmio + MMIO_MACDATA) ; - - writew( SETTXSTARTTHRESH | 0x40 , xl_mmio + MMIO_COMMAND) ; - - writeb(0x04, xl_mmio + MMIO_DNBURSTTHRESH) ; - writeb(0x04, xl_mmio + DNPRIREQTHRESH) ; - - /* - * Read WRBR to provide the location of the srb block, have to use byte reads not word reads. - * Tech docs have this wrong !!!! - */ - - writel(MMIO_BYTE_READ | WRBR, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - xl_priv->srb = readb(xl_mmio + MMIO_MACDATA) << 8 ; - writel( (MMIO_BYTE_READ | WRBR) + 1, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - xl_priv->srb = xl_priv->srb | readb(xl_mmio + MMIO_MACDATA) ; - -#if XL_DEBUG - writel(IO_WORD_READ | SWITCHSETTINGS, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - if ( readw(xl_mmio + MMIO_MACDATA) & 2) { - printk(KERN_INFO "Default ring speed 4 mbps\n"); - } else { - printk(KERN_INFO "Default ring speed 16 mbps\n"); - } - printk(KERN_INFO "%s: xl_priv->srb = %04x\n",xl_priv->xl_card_name, xl_priv->srb); -#endif - - return 0; -} - -static int xl_open(struct net_device *dev) -{ - struct xl_private *xl_priv=netdev_priv(dev); - u8 __iomem *xl_mmio = xl_priv->xl_mmio ; - u8 i ; - __le16 hwaddr[3] ; /* Should be u8[6] but we get word return values */ - int open_err ; - - u16 switchsettings, switchsettings_eeprom ; - - if (request_irq(dev->irq, xl_interrupt, IRQF_SHARED , "3c359", dev)) - return -EAGAIN; - - /* - * Read the information from the EEPROM that we need. - */ - - hwaddr[0] = cpu_to_le16(xl_ee_read(dev,0x10)); - hwaddr[1] = cpu_to_le16(xl_ee_read(dev,0x11)); - hwaddr[2] = cpu_to_le16(xl_ee_read(dev,0x12)); - - /* Ring speed */ - - switchsettings_eeprom = xl_ee_read(dev,0x08) ; - switchsettings = switchsettings_eeprom ; - - if (xl_priv->xl_ring_speed != 0) { - if (xl_priv->xl_ring_speed == 4) - switchsettings = switchsettings | 0x02 ; - else - switchsettings = switchsettings & ~0x02 ; - } - - /* Only write EEProm if there has been a change */ - if (switchsettings != switchsettings_eeprom) { - xl_ee_write(dev,0x08,switchsettings) ; - /* Hardware reset after changing EEProm */ - xl_hw_reset(dev) ; - } - - memcpy(dev->dev_addr,hwaddr,dev->addr_len) ; - - open_err = xl_open_hw(dev) ; - - /* - * This really needs to be cleaned up with better error reporting. - */ - - if (open_err != 0) { /* Something went wrong with the open command */ - if (open_err & 0x07) { /* Wrong speed, retry at different speed */ - printk(KERN_WARNING "%s: Open Error, retrying at different ringspeed\n", dev->name); - switchsettings = switchsettings ^ 2 ; - xl_ee_write(dev,0x08,switchsettings) ; - xl_hw_reset(dev) ; - open_err = xl_open_hw(dev) ; - if (open_err != 0) { - printk(KERN_WARNING "%s: Open error returned a second time, we're bombing out now\n", dev->name); - free_irq(dev->irq,dev) ; - return -ENODEV ; - } - } else { - printk(KERN_WARNING "%s: Open Error = %04x\n", dev->name, open_err) ; - free_irq(dev->irq,dev) ; - return -ENODEV ; - } - } - - /* - * Now to set up the Rx and Tx buffer structures - */ - /* These MUST be on 8 byte boundaries */ - xl_priv->xl_tx_ring = kzalloc((sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) + 7, GFP_DMA | GFP_KERNEL); - if (xl_priv->xl_tx_ring == NULL) { - free_irq(dev->irq,dev); - return -ENOMEM; - } - xl_priv->xl_rx_ring = kzalloc((sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) +7, GFP_DMA | GFP_KERNEL); - if (xl_priv->xl_rx_ring == NULL) { - free_irq(dev->irq,dev); - kfree(xl_priv->xl_tx_ring); - return -ENOMEM; - } - - /* Setup Rx Ring */ - for (i=0 ; i < XL_RX_RING_SIZE ; i++) { - struct sk_buff *skb ; - - skb = dev_alloc_skb(xl_priv->pkt_buf_sz) ; - if (skb==NULL) - break ; - - skb->dev = dev ; - xl_priv->xl_rx_ring[i].upfragaddr = cpu_to_le32(pci_map_single(xl_priv->pdev, skb->data,xl_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE)); - xl_priv->xl_rx_ring[i].upfraglen = cpu_to_le32(xl_priv->pkt_buf_sz) | RXUPLASTFRAG; - xl_priv->rx_ring_skb[i] = skb ; - } - - if (i==0) { - printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers. Adapter disabled\n",dev->name); - free_irq(dev->irq,dev) ; - kfree(xl_priv->xl_tx_ring); - kfree(xl_priv->xl_rx_ring); - return -EIO ; - } - - xl_priv->rx_ring_no = i ; - xl_priv->rx_ring_tail = 0 ; - xl_priv->rx_ring_dma_addr = pci_map_single(xl_priv->pdev,xl_priv->xl_rx_ring, sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE, PCI_DMA_TODEVICE) ; - for (i=0;i<(xl_priv->rx_ring_no-1);i++) { - xl_priv->xl_rx_ring[i].upnextptr = cpu_to_le32(xl_priv->rx_ring_dma_addr + (sizeof (struct xl_rx_desc) * (i+1))); - } - xl_priv->xl_rx_ring[i].upnextptr = 0 ; - - writel(xl_priv->rx_ring_dma_addr, xl_mmio + MMIO_UPLISTPTR) ; - - /* Setup Tx Ring */ - - xl_priv->tx_ring_dma_addr = pci_map_single(xl_priv->pdev,xl_priv->xl_tx_ring, sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE,PCI_DMA_TODEVICE) ; - - xl_priv->tx_ring_head = 1 ; - xl_priv->tx_ring_tail = 255 ; /* Special marker for first packet */ - xl_priv->free_ring_entries = XL_TX_RING_SIZE ; - - /* - * Setup the first dummy DPD entry for polling to start working. - */ - - xl_priv->xl_tx_ring[0].framestartheader = TXDPDEMPTY; - xl_priv->xl_tx_ring[0].buffer = 0 ; - xl_priv->xl_tx_ring[0].buffer_length = 0 ; - xl_priv->xl_tx_ring[0].dnnextptr = 0 ; - - writel(xl_priv->tx_ring_dma_addr, xl_mmio + MMIO_DNLISTPTR) ; - writel(DNUNSTALL, xl_mmio + MMIO_COMMAND) ; - writel(UPUNSTALL, xl_mmio + MMIO_COMMAND) ; - writel(DNENABLE, xl_mmio + MMIO_COMMAND) ; - writeb(0x40, xl_mmio + MMIO_DNPOLL) ; - - /* - * Enable interrupts on the card - */ - - writel(SETINTENABLE | INT_MASK, xl_mmio + MMIO_COMMAND) ; - writel(SETINDENABLE | INT_MASK, xl_mmio + MMIO_COMMAND) ; - - netif_start_queue(dev) ; - return 0; - -} - -static int xl_open_hw(struct net_device *dev) -{ - struct xl_private *xl_priv=netdev_priv(dev); - u8 __iomem *xl_mmio = xl_priv->xl_mmio ; - u16 vsoff ; - char ver_str[33]; - int open_err ; - int i ; - unsigned long t ; - - /* - * Okay, let's build up the Open.NIC srb command - * - */ - - writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb), xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(OPEN_NIC, xl_mmio + MMIO_MACDATA) ; - - /* - * Use this as a test byte, if it comes back with the same value, the command didn't work - */ - - writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb)+ 2, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(0xff,xl_mmio + MMIO_MACDATA) ; - - /* Open options */ - writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb) + 8, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(0x00, xl_mmio + MMIO_MACDATA) ; - writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb) + 9, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(0x00, xl_mmio + MMIO_MACDATA) ; - - /* - * Node address, be careful here, the docs say you can just put zeros here and it will use - * the hardware address, it doesn't, you must include the node address in the open command. - */ - - if (xl_priv->xl_laa[0]) { /* If using a LAA address */ - for (i=10;i<16;i++) { - writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb) + i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(xl_priv->xl_laa[i-10],xl_mmio + MMIO_MACDATA) ; - } - memcpy(dev->dev_addr,xl_priv->xl_laa,dev->addr_len) ; - } else { /* Regular hardware address */ - for (i=10;i<16;i++) { - writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb) + i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(dev->dev_addr[i-10], xl_mmio + MMIO_MACDATA) ; - } - } - - /* Default everything else to 0 */ - for (i = 16; i < 34; i++) { - writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb) + i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(0x00,xl_mmio + MMIO_MACDATA) ; - } - - /* - * Set the csrb bit in the MISR register - */ - - xl_wait_misr_flags(dev) ; - writel(MEM_BYTE_WRITE | MF_CSRB, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(0xFF, xl_mmio + MMIO_MACDATA) ; - writel(MMIO_BYTE_WRITE | MISR_SET, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(MISR_CSRB , xl_mmio + MMIO_MACDATA) ; - - /* - * Now wait for the command to run - */ - - t=jiffies; - while (! (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_SRB)) { - schedule(); - if (time_after(jiffies, t + 40 * HZ)) { - printk(KERN_ERR "3COM 3C359 Velocity XL card not responding.\n"); - break ; - } - } - - /* - * Let's interpret the open response - */ - - writel( (MEM_BYTE_READ | 0xD0000 | xl_priv->srb)+2, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - if (readb(xl_mmio + MMIO_MACDATA)!=0) { - open_err = readb(xl_mmio + MMIO_MACDATA) << 8 ; - writel( (MEM_BYTE_READ | 0xD0000 | xl_priv->srb) + 7, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - open_err |= readb(xl_mmio + MMIO_MACDATA) ; - return open_err ; - } else { - writel( (MEM_WORD_READ | 0xD0000 | xl_priv->srb) + 8, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - xl_priv->asb = swab16(readw(xl_mmio + MMIO_MACDATA)) ; - printk(KERN_INFO "%s: Adapter Opened Details: ",dev->name) ; - printk("ASB: %04x",xl_priv->asb ) ; - writel( (MEM_WORD_READ | 0xD0000 | xl_priv->srb) + 10, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - printk(", SRB: %04x",swab16(readw(xl_mmio + MMIO_MACDATA)) ) ; - - writel( (MEM_WORD_READ | 0xD0000 | xl_priv->srb) + 12, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - xl_priv->arb = swab16(readw(xl_mmio + MMIO_MACDATA)) ; - printk(", ARB: %04x\n",xl_priv->arb ); - writel( (MEM_WORD_READ | 0xD0000 | xl_priv->srb) + 14, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - vsoff = swab16(readw(xl_mmio + MMIO_MACDATA)) ; - - /* - * Interesting, sending the individual characters directly to printk was causing klogd to use - * use 100% of processor time, so we build up the string and print that instead. - */ - - for (i=0;i<0x20;i++) { - writel( (MEM_BYTE_READ | 0xD0000 | vsoff) + i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - ver_str[i] = readb(xl_mmio + MMIO_MACDATA) ; - } - ver_str[i] = '\0' ; - printk(KERN_INFO "%s: Microcode version String: %s\n",dev->name,ver_str); - } - - /* - * Issue the AckInterrupt - */ - writew(ACK_INTERRUPT | SRBRACK | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; - - return 0 ; -} - -/* - * There are two ways of implementing rx on the 359 NIC, either - * interrupt driven or polling. We are going to uses interrupts, - * it is the easier way of doing things. - * - * The Rx works with a ring of Rx descriptors. At initialise time the ring - * entries point to the next entry except for the last entry in the ring - * which points to 0. The card is programmed with the location of the first - * available descriptor and keeps reading the next_ptr until next_ptr is set - * to 0. Hopefully with a ring size of 16 the card will never get to read a next_ptr - * of 0. As the Rx interrupt is received we copy the frame up to the protocol layers - * and then point the end of the ring to our current position and point our current - * position to 0, therefore making the current position the last position on the ring. - * The last position on the ring therefore loops continually loops around the rx ring. - * - * rx_ring_tail is the position on the ring to process next. (Think of a snake, the head - * expands as the card adds new packets and we go around eating the tail processing the - * packets.) - * - * Undoubtably it could be streamlined and improved upon, but at the moment it works - * and the fast path through the routine is fine. - * - * adv_rx_ring could be inlined to increase performance, but its called a *lot* of times - * in xl_rx so would increase the size of the function significantly. - */ - -static void adv_rx_ring(struct net_device *dev) /* Advance rx_ring, cut down on bloat in xl_rx */ -{ - struct xl_private *xl_priv=netdev_priv(dev); - int n = xl_priv->rx_ring_tail; - int prev_ring_loc; - - prev_ring_loc = (n + XL_RX_RING_SIZE - 1) & (XL_RX_RING_SIZE - 1); - xl_priv->xl_rx_ring[prev_ring_loc].upnextptr = cpu_to_le32(xl_priv->rx_ring_dma_addr + (sizeof (struct xl_rx_desc) * n)); - xl_priv->xl_rx_ring[n].framestatus = 0; - xl_priv->xl_rx_ring[n].upnextptr = 0; - xl_priv->rx_ring_tail++; - xl_priv->rx_ring_tail &= (XL_RX_RING_SIZE-1); -} - -static void xl_rx(struct net_device *dev) -{ - struct xl_private *xl_priv=netdev_priv(dev); - u8 __iomem * xl_mmio = xl_priv->xl_mmio ; - struct sk_buff *skb, *skb2 ; - int frame_length = 0, copy_len = 0 ; - int temp_ring_loc ; - - /* - * Receive the next frame, loop around the ring until all frames - * have been received. - */ - - while (xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].framestatus & (RXUPDCOMPLETE | RXUPDFULL) ) { /* Descriptor to process */ - - if (xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].framestatus & RXUPDFULL ) { /* UpdFull, Multiple Descriptors used for the frame */ - - /* - * This is a pain, you need to go through all the descriptors until the last one - * for this frame to find the framelength - */ - - temp_ring_loc = xl_priv->rx_ring_tail ; - - while (xl_priv->xl_rx_ring[temp_ring_loc].framestatus & RXUPDFULL ) { - temp_ring_loc++ ; - temp_ring_loc &= (XL_RX_RING_SIZE-1) ; - } - - frame_length = le32_to_cpu(xl_priv->xl_rx_ring[temp_ring_loc].framestatus) & 0x7FFF; - - skb = dev_alloc_skb(frame_length) ; - - if (skb==NULL) { /* No memory for frame, still need to roll forward the rx ring */ - printk(KERN_WARNING "%s: dev_alloc_skb failed - multi buffer !\n", dev->name) ; - while (xl_priv->rx_ring_tail != temp_ring_loc) - adv_rx_ring(dev) ; - - adv_rx_ring(dev) ; /* One more time just for luck :) */ - dev->stats.rx_dropped++ ; - - writel(ACK_INTERRUPT | UPCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; - return ; - } - - while (xl_priv->rx_ring_tail != temp_ring_loc) { - copy_len = le32_to_cpu(xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfraglen) & 0x7FFF; - frame_length -= copy_len ; - pci_dma_sync_single_for_cpu(xl_priv->pdev,le32_to_cpu(xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr),xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE); - skb_copy_from_linear_data(xl_priv->rx_ring_skb[xl_priv->rx_ring_tail], - skb_put(skb, copy_len), - copy_len); - pci_dma_sync_single_for_device(xl_priv->pdev,le32_to_cpu(xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr),xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE); - adv_rx_ring(dev) ; - } - - /* Now we have found the last fragment */ - pci_dma_sync_single_for_cpu(xl_priv->pdev,le32_to_cpu(xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr),xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE); - skb_copy_from_linear_data(xl_priv->rx_ring_skb[xl_priv->rx_ring_tail], - skb_put(skb,copy_len), frame_length); -/* memcpy(skb_put(skb,frame_length), bus_to_virt(xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr), frame_length) ; */ - pci_dma_sync_single_for_device(xl_priv->pdev,le32_to_cpu(xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr),xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE); - adv_rx_ring(dev) ; - skb->protocol = tr_type_trans(skb,dev) ; - netif_rx(skb) ; - - } else { /* Single Descriptor Used, simply swap buffers over, fast path */ - - frame_length = le32_to_cpu(xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].framestatus) & 0x7FFF; - - skb = dev_alloc_skb(xl_priv->pkt_buf_sz) ; - - if (skb==NULL) { /* Still need to fix the rx ring */ - printk(KERN_WARNING "%s: dev_alloc_skb failed in rx, single buffer\n",dev->name); - adv_rx_ring(dev) ; - dev->stats.rx_dropped++ ; - writel(ACK_INTERRUPT | UPCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; - return ; - } - - skb2 = xl_priv->rx_ring_skb[xl_priv->rx_ring_tail] ; - pci_unmap_single(xl_priv->pdev, le32_to_cpu(xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr), xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; - skb_put(skb2, frame_length) ; - skb2->protocol = tr_type_trans(skb2,dev) ; - - xl_priv->rx_ring_skb[xl_priv->rx_ring_tail] = skb ; - xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr = cpu_to_le32(pci_map_single(xl_priv->pdev,skb->data,xl_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE)); - xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfraglen = cpu_to_le32(xl_priv->pkt_buf_sz) | RXUPLASTFRAG; - adv_rx_ring(dev) ; - dev->stats.rx_packets++ ; - dev->stats.rx_bytes += frame_length ; - - netif_rx(skb2) ; - } /* if multiple buffers */ - } /* while packet to do */ - - /* Clear the updComplete interrupt */ - writel(ACK_INTERRUPT | UPCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; - return ; -} - -/* - * This is ruthless, it doesn't care what state the card is in it will - * completely reset the adapter. - */ - -static void xl_reset(struct net_device *dev) -{ - struct xl_private *xl_priv=netdev_priv(dev); - u8 __iomem * xl_mmio = xl_priv->xl_mmio ; - unsigned long t; - - writew( GLOBAL_RESET, xl_mmio + MMIO_COMMAND ) ; - - /* - * Must wait for cmdInProgress bit (12) to clear before continuing with - * card configuration. - */ - - t=jiffies; - while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { - if (time_after(jiffies, t + 40 * HZ)) { - printk(KERN_ERR "3COM 3C359 Velocity XL card not responding.\n"); - break ; - } - } - -} - -static void xl_freemem(struct net_device *dev) -{ - struct xl_private *xl_priv=netdev_priv(dev); - int i ; - - for (i=0;irx_ring_skb[xl_priv->rx_ring_tail]) ; - pci_unmap_single(xl_priv->pdev,le32_to_cpu(xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr),xl_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE); - xl_priv->rx_ring_tail++ ; - xl_priv->rx_ring_tail &= XL_RX_RING_SIZE-1; - } - - /* unmap ring */ - pci_unmap_single(xl_priv->pdev,xl_priv->rx_ring_dma_addr, sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE, PCI_DMA_FROMDEVICE) ; - - pci_unmap_single(xl_priv->pdev,xl_priv->tx_ring_dma_addr, sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE, PCI_DMA_TODEVICE) ; - - kfree(xl_priv->xl_rx_ring) ; - kfree(xl_priv->xl_tx_ring) ; - - return ; -} - -static irqreturn_t xl_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = (struct net_device *)dev_id; - struct xl_private *xl_priv =netdev_priv(dev); - u8 __iomem * xl_mmio = xl_priv->xl_mmio ; - u16 intstatus, macstatus ; - - intstatus = readw(xl_mmio + MMIO_INTSTATUS) ; - - if (!(intstatus & 1)) /* We didn't generate the interrupt */ - return IRQ_NONE; - - spin_lock(&xl_priv->xl_lock) ; - - /* - * Process the interrupt - */ - /* - * Something fishy going on here, we shouldn't get 0001 ints, not fatal though. - */ - if (intstatus == 0x0001) { - writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; - printk(KERN_INFO "%s: 00001 int received\n",dev->name); - } else { - if (intstatus & (HOSTERRINT | SRBRINT | ARBCINT | UPCOMPINT | DNCOMPINT | HARDERRINT | (1<<8) | TXUNDERRUN | ASBFINT)) { - - /* - * Host Error. - * It may be possible to recover from this, but usually it means something - * is seriously fubar, so we just close the adapter. - */ - - if (intstatus & HOSTERRINT) { - printk(KERN_WARNING "%s: Host Error, performing global reset, intstatus = %04x\n",dev->name,intstatus); - writew( GLOBAL_RESET, xl_mmio + MMIO_COMMAND ) ; - printk(KERN_WARNING "%s: Resetting hardware:\n", dev->name); - netif_stop_queue(dev) ; - xl_freemem(dev) ; - free_irq(dev->irq,dev); - xl_reset(dev) ; - writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; - spin_unlock(&xl_priv->xl_lock) ; - return IRQ_HANDLED; - } /* Host Error */ - - if (intstatus & SRBRINT ) { /* Srbc interrupt */ - writel(ACK_INTERRUPT | SRBRACK | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; - if (xl_priv->srb_queued) - xl_srb_bh(dev) ; - } /* SRBR Interrupt */ - - if (intstatus & TXUNDERRUN) { /* Issue DnReset command */ - writel(DNRESET, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { /* Wait for command to run */ - /* !!! FIX-ME !!!! - Must put a timeout check here ! */ - /* Empty Loop */ - } - printk(KERN_WARNING "%s: TX Underrun received\n",dev->name); - writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; - } /* TxUnderRun */ - - if (intstatus & ARBCINT ) { /* Arbc interrupt */ - xl_arb_cmd(dev) ; - } /* Arbc */ - - if (intstatus & ASBFINT) { - if (xl_priv->asb_queued == 1) { - xl_asb_cmd(dev) ; - } else if (xl_priv->asb_queued == 2) { - xl_asb_bh(dev) ; - } else { - writel(ACK_INTERRUPT | LATCH_ACK | ASBFACK, xl_mmio + MMIO_COMMAND) ; - } - } /* Asbf */ - - if (intstatus & UPCOMPINT ) /* UpComplete */ - xl_rx(dev) ; - - if (intstatus & DNCOMPINT ) /* DnComplete */ - xl_dn_comp(dev) ; - - if (intstatus & HARDERRINT ) { /* Hardware error */ - writel(MMIO_WORD_READ | MACSTATUS, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - macstatus = readw(xl_mmio + MMIO_MACDATA) ; - printk(KERN_WARNING "%s: MacStatusError, details: ", dev->name); - if (macstatus & (1<<14)) - printk(KERN_WARNING "tchk error: Unrecoverable error\n"); - if (macstatus & (1<<3)) - printk(KERN_WARNING "eint error: Internal watchdog timer expired\n"); - if (macstatus & (1<<2)) - printk(KERN_WARNING "aint error: Host tried to perform invalid operation\n"); - printk(KERN_WARNING "Instatus = %02x, macstatus = %02x\n",intstatus,macstatus) ; - printk(KERN_WARNING "%s: Resetting hardware:\n", dev->name); - netif_stop_queue(dev) ; - xl_freemem(dev) ; - free_irq(dev->irq,dev); - unregister_netdev(dev) ; - free_netdev(dev) ; - xl_reset(dev) ; - writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; - spin_unlock(&xl_priv->xl_lock) ; - return IRQ_HANDLED; - } - } else { - printk(KERN_WARNING "%s: Received Unknown interrupt : %04x\n", dev->name, intstatus); - writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; - } - } - - /* Turn interrupts back on */ - - writel( SETINDENABLE | INT_MASK, xl_mmio + MMIO_COMMAND) ; - writel( SETINTENABLE | INT_MASK, xl_mmio + MMIO_COMMAND) ; - - spin_unlock(&xl_priv->xl_lock) ; - return IRQ_HANDLED; -} - -/* - * Tx - Polling configuration - */ - -static netdev_tx_t xl_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct xl_private *xl_priv=netdev_priv(dev); - struct xl_tx_desc *txd ; - int tx_head, tx_tail, tx_prev ; - unsigned long flags ; - - spin_lock_irqsave(&xl_priv->xl_lock,flags) ; - - netif_stop_queue(dev) ; - - if (xl_priv->free_ring_entries > 1 ) { - /* - * Set up the descriptor for the packet - */ - tx_head = xl_priv->tx_ring_head ; - tx_tail = xl_priv->tx_ring_tail ; - - txd = &(xl_priv->xl_tx_ring[tx_head]) ; - txd->dnnextptr = 0 ; - txd->framestartheader = cpu_to_le32(skb->len) | TXDNINDICATE; - txd->buffer = cpu_to_le32(pci_map_single(xl_priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE)); - txd->buffer_length = cpu_to_le32(skb->len) | TXDNFRAGLAST; - xl_priv->tx_ring_skb[tx_head] = skb ; - dev->stats.tx_packets++ ; - dev->stats.tx_bytes += skb->len ; - - /* - * Set the nextptr of the previous descriptor equal to this descriptor, add XL_TX_RING_SIZE -1 - * to ensure no negative numbers in unsigned locations. - */ - - tx_prev = (xl_priv->tx_ring_head + XL_TX_RING_SIZE - 1) & (XL_TX_RING_SIZE - 1) ; - - xl_priv->tx_ring_head++ ; - xl_priv->tx_ring_head &= (XL_TX_RING_SIZE - 1) ; - xl_priv->free_ring_entries-- ; - - xl_priv->xl_tx_ring[tx_prev].dnnextptr = cpu_to_le32(xl_priv->tx_ring_dma_addr + (sizeof (struct xl_tx_desc) * tx_head)); - - /* Sneaky, by doing a read on DnListPtr we can force the card to poll on the DnNextPtr */ - /* readl(xl_mmio + MMIO_DNLISTPTR) ; */ - - netif_wake_queue(dev) ; - - spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ; - - return NETDEV_TX_OK; - } else { - spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ; - return NETDEV_TX_BUSY; - } - -} - -/* - * The NIC has told us that a packet has been downloaded onto the card, we must - * find out which packet it has done, clear the skb and information for the packet - * then advance around the ring for all transmitted packets - */ - -static void xl_dn_comp(struct net_device *dev) -{ - struct xl_private *xl_priv=netdev_priv(dev); - u8 __iomem * xl_mmio = xl_priv->xl_mmio ; - struct xl_tx_desc *txd ; - - - if (xl_priv->tx_ring_tail == 255) {/* First time */ - xl_priv->xl_tx_ring[0].framestartheader = 0 ; - xl_priv->xl_tx_ring[0].dnnextptr = 0 ; - xl_priv->tx_ring_tail = 1 ; - } - - while (xl_priv->xl_tx_ring[xl_priv->tx_ring_tail].framestartheader & TXDNCOMPLETE ) { - txd = &(xl_priv->xl_tx_ring[xl_priv->tx_ring_tail]) ; - pci_unmap_single(xl_priv->pdev, le32_to_cpu(txd->buffer), xl_priv->tx_ring_skb[xl_priv->tx_ring_tail]->len, PCI_DMA_TODEVICE); - txd->framestartheader = 0 ; - txd->buffer = cpu_to_le32(0xdeadbeef); - txd->buffer_length = 0 ; - dev_kfree_skb_irq(xl_priv->tx_ring_skb[xl_priv->tx_ring_tail]) ; - xl_priv->tx_ring_tail++ ; - xl_priv->tx_ring_tail &= (XL_TX_RING_SIZE - 1) ; - xl_priv->free_ring_entries++ ; - } - - netif_wake_queue(dev) ; - - writel(ACK_INTERRUPT | DNCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; -} - -/* - * Close the adapter properly. - * This srb reply cannot be handled from interrupt context as we have - * to free the interrupt from the driver. - */ - -static int xl_close(struct net_device *dev) -{ - struct xl_private *xl_priv = netdev_priv(dev); - u8 __iomem * xl_mmio = xl_priv->xl_mmio ; - unsigned long t ; - - netif_stop_queue(dev) ; - - /* - * Close the adapter, need to stall the rx and tx queues. - */ - - writew(DNSTALL, xl_mmio + MMIO_COMMAND) ; - t=jiffies; - while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { - schedule(); - if (time_after(jiffies, t + 10 * HZ)) { - printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-DNSTALL not responding.\n", dev->name); - break ; - } - } - writew(DNDISABLE, xl_mmio + MMIO_COMMAND) ; - t=jiffies; - while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { - schedule(); - if (time_after(jiffies, t + 10 * HZ)) { - printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-DNDISABLE not responding.\n", dev->name); - break ; - } - } - writew(UPSTALL, xl_mmio + MMIO_COMMAND) ; - t=jiffies; - while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { - schedule(); - if (time_after(jiffies, t + 10 * HZ)) { - printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-UPSTALL not responding.\n", dev->name); - break ; - } - } - - /* Turn off interrupts, we will still get the indication though - * so we can trap it - */ - - writel(SETINTENABLE, xl_mmio + MMIO_COMMAND) ; - - xl_srb_cmd(dev,CLOSE_NIC) ; - - t=jiffies; - while (!(readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_SRB)) { - schedule(); - if (time_after(jiffies, t + 10 * HZ)) { - printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-CLOSENIC not responding.\n", dev->name); - break ; - } - } - /* Read the srb response from the adapter */ - - writel(MEM_BYTE_READ | 0xd0000 | xl_priv->srb, xl_mmio + MMIO_MAC_ACCESS_CMD); - if (readb(xl_mmio + MMIO_MACDATA) != CLOSE_NIC) { - printk(KERN_INFO "%s: CLOSE_NIC did not get a CLOSE_NIC response\n",dev->name); - } else { - writel((MEM_BYTE_READ | 0xd0000 | xl_priv->srb) +2, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - if (readb(xl_mmio + MMIO_MACDATA)==0) { - printk(KERN_INFO "%s: Adapter has been closed\n",dev->name); - writew(ACK_INTERRUPT | SRBRACK | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; - - xl_freemem(dev) ; - free_irq(dev->irq,dev) ; - } else { - printk(KERN_INFO "%s: Close nic command returned error code %02x\n",dev->name, readb(xl_mmio + MMIO_MACDATA)) ; - } - } - - /* Reset the upload and download logic */ - - writew(UPRESET, xl_mmio + MMIO_COMMAND) ; - t=jiffies; - while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { - schedule(); - if (time_after(jiffies, t + 10 * HZ)) { - printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-UPRESET not responding.\n", dev->name); - break ; - } - } - writew(DNRESET, xl_mmio + MMIO_COMMAND) ; - t=jiffies; - while (readw(xl_mmio + MMIO_INTSTATUS) & INTSTAT_CMD_IN_PROGRESS) { - schedule(); - if (time_after(jiffies, t + 10 * HZ)) { - printk(KERN_ERR "%s: 3COM 3C359 Velocity XL-DNRESET not responding.\n", dev->name); - break ; - } - } - xl_hw_reset(dev) ; - return 0 ; -} - -static void xl_set_rx_mode(struct net_device *dev) -{ - struct xl_private *xl_priv = netdev_priv(dev); - struct netdev_hw_addr *ha; - unsigned char dev_mc_address[4] ; - u16 options ; - - if (dev->flags & IFF_PROMISC) - options = 0x0004 ; - else - options = 0x0000 ; - - if (options ^ xl_priv->xl_copy_all_options) { /* Changed, must send command */ - xl_priv->xl_copy_all_options = options ; - xl_srb_cmd(dev, SET_RECEIVE_MODE) ; - return ; - } - - dev_mc_address[0] = dev_mc_address[1] = dev_mc_address[2] = dev_mc_address[3] = 0 ; - - netdev_for_each_mc_addr(ha, dev) { - dev_mc_address[0] |= ha->addr[2]; - dev_mc_address[1] |= ha->addr[3]; - dev_mc_address[2] |= ha->addr[4]; - dev_mc_address[3] |= ha->addr[5]; - } - - if (memcmp(xl_priv->xl_functional_addr,dev_mc_address,4) != 0) { /* Options have changed, run the command */ - memcpy(xl_priv->xl_functional_addr, dev_mc_address,4) ; - xl_srb_cmd(dev, SET_FUNC_ADDRESS) ; - } - return ; -} - - -/* - * We issued an srb command and now we must read - * the response from the completed command. - */ - -static void xl_srb_bh(struct net_device *dev) -{ - struct xl_private *xl_priv = netdev_priv(dev); - u8 __iomem * xl_mmio = xl_priv->xl_mmio ; - u8 srb_cmd, ret_code ; - int i ; - - writel(MEM_BYTE_READ | 0xd0000 | xl_priv->srb, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - srb_cmd = readb(xl_mmio + MMIO_MACDATA) ; - writel((MEM_BYTE_READ | 0xd0000 | xl_priv->srb) +2, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - ret_code = readb(xl_mmio + MMIO_MACDATA) ; - - /* Ret_code is standard across all commands */ - - switch (ret_code) { - case 1: - printk(KERN_INFO "%s: Command: %d - Invalid Command code\n",dev->name,srb_cmd) ; - break ; - case 4: - printk(KERN_INFO "%s: Command: %d - Adapter is closed, must be open for this command\n",dev->name,srb_cmd); - break ; - - case 6: - printk(KERN_INFO "%s: Command: %d - Options Invalid for command\n",dev->name,srb_cmd); - break ; - - case 0: /* Successful command execution */ - switch (srb_cmd) { - case READ_LOG: /* Returns 14 bytes of data from the NIC */ - if(xl_priv->xl_message_level) - printk(KERN_INFO "%s: READ.LOG 14 bytes of data ",dev->name) ; - /* - * We still have to read the log even if message_level = 0 and we don't want - * to see it - */ - for (i=0;i<14;i++) { - writel(MEM_BYTE_READ | 0xd0000 | xl_priv->srb | i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - if(xl_priv->xl_message_level) - printk("%02x:",readb(xl_mmio + MMIO_MACDATA)) ; - } - printk("\n") ; - break ; - case SET_FUNC_ADDRESS: - if(xl_priv->xl_message_level) - printk(KERN_INFO "%s: Functional Address Set\n",dev->name); - break ; - case CLOSE_NIC: - if(xl_priv->xl_message_level) - printk(KERN_INFO "%s: Received CLOSE_NIC interrupt in interrupt handler\n",dev->name); - break ; - case SET_MULTICAST_MODE: - if(xl_priv->xl_message_level) - printk(KERN_INFO "%s: Multicast options successfully changed\n",dev->name) ; - break ; - case SET_RECEIVE_MODE: - if(xl_priv->xl_message_level) { - if (xl_priv->xl_copy_all_options == 0x0004) - printk(KERN_INFO "%s: Entering promiscuous mode\n", dev->name); - else - printk(KERN_INFO "%s: Entering normal receive mode\n",dev->name); - } - break ; - - } /* switch */ - break ; - } /* switch */ - return ; -} - -static int xl_set_mac_address (struct net_device *dev, void *addr) -{ - struct sockaddr *saddr = addr ; - struct xl_private *xl_priv = netdev_priv(dev); - - if (netif_running(dev)) { - printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name) ; - return -EIO ; - } - - memcpy(xl_priv->xl_laa, saddr->sa_data,dev->addr_len) ; - - if (xl_priv->xl_message_level) { - printk(KERN_INFO "%s: MAC/LAA Set to = %x.%x.%x.%x.%x.%x\n",dev->name, xl_priv->xl_laa[0], - xl_priv->xl_laa[1], xl_priv->xl_laa[2], - xl_priv->xl_laa[3], xl_priv->xl_laa[4], - xl_priv->xl_laa[5]); - } - - return 0 ; -} - -static void xl_arb_cmd(struct net_device *dev) -{ - struct xl_private *xl_priv = netdev_priv(dev); - u8 __iomem * xl_mmio = xl_priv->xl_mmio ; - u8 arb_cmd ; - u16 lan_status, lan_status_diff ; - - writel( ( MEM_BYTE_READ | 0xD0000 | xl_priv->arb), xl_mmio + MMIO_MAC_ACCESS_CMD) ; - arb_cmd = readb(xl_mmio + MMIO_MACDATA) ; - - if (arb_cmd == RING_STATUS_CHANGE) { /* Ring.Status.Change */ - writel( ( (MEM_WORD_READ | 0xD0000 | xl_priv->arb) + 6), xl_mmio + MMIO_MAC_ACCESS_CMD) ; - - printk(KERN_INFO "%s: Ring Status Change: New Status = %04x\n", dev->name, swab16(readw(xl_mmio + MMIO_MACDATA) )) ; - - lan_status = swab16(readw(xl_mmio + MMIO_MACDATA)); - - /* Acknowledge interrupt, this tells nic we are done with the arb */ - writel(ACK_INTERRUPT | ARBCACK | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; - - lan_status_diff = xl_priv->xl_lan_status ^ lan_status ; - - if (lan_status_diff & (LSC_LWF | LSC_ARW | LSC_FPE | LSC_RR) ) { - if (lan_status_diff & LSC_LWF) - printk(KERN_WARNING "%s: Short circuit detected on the lobe\n",dev->name); - if (lan_status_diff & LSC_ARW) - printk(KERN_WARNING "%s: Auto removal error\n",dev->name); - if (lan_status_diff & LSC_FPE) - printk(KERN_WARNING "%s: FDX Protocol Error\n",dev->name); - if (lan_status_diff & LSC_RR) - printk(KERN_WARNING "%s: Force remove MAC frame received\n",dev->name); - - /* Adapter has been closed by the hardware */ - - netif_stop_queue(dev); - xl_freemem(dev) ; - free_irq(dev->irq,dev); - - printk(KERN_WARNING "%s: Adapter has been closed\n", dev->name); - } /* If serious error */ - - if (xl_priv->xl_message_level) { - if (lan_status_diff & LSC_SIG_LOSS) - printk(KERN_WARNING "%s: No receive signal detected\n", dev->name); - if (lan_status_diff & LSC_HARD_ERR) - printk(KERN_INFO "%s: Beaconing\n",dev->name); - if (lan_status_diff & LSC_SOFT_ERR) - printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame\n",dev->name); - if (lan_status_diff & LSC_TRAN_BCN) - printk(KERN_INFO "%s: We are transmitting the beacon, aaah\n",dev->name); - if (lan_status_diff & LSC_SS) - printk(KERN_INFO "%s: Single Station on the ring\n", dev->name); - if (lan_status_diff & LSC_RING_REC) - printk(KERN_INFO "%s: Ring recovery ongoing\n",dev->name); - if (lan_status_diff & LSC_FDX_MODE) - printk(KERN_INFO "%s: Operating in FDX mode\n",dev->name); - } - - if (lan_status_diff & LSC_CO) { - if (xl_priv->xl_message_level) - printk(KERN_INFO "%s: Counter Overflow\n", dev->name); - /* Issue READ.LOG command */ - xl_srb_cmd(dev, READ_LOG) ; - } - - /* There is no command in the tech docs to issue the read_sr_counters */ - if (lan_status_diff & LSC_SR_CO) { - if (xl_priv->xl_message_level) - printk(KERN_INFO "%s: Source routing counters overflow\n", dev->name); - } - - xl_priv->xl_lan_status = lan_status ; - - } /* Lan.change.status */ - else if ( arb_cmd == RECEIVE_DATA) { /* Received.Data */ -#if XL_DEBUG - printk(KERN_INFO "Received.Data\n"); -#endif - writel( ((MEM_WORD_READ | 0xD0000 | xl_priv->arb) + 6), xl_mmio + MMIO_MAC_ACCESS_CMD) ; - xl_priv->mac_buffer = swab16(readw(xl_mmio + MMIO_MACDATA)) ; - - /* Now we are going to be really basic here and not do anything - * with the data at all. The tech docs do not give me enough - * information to calculate the buffers properly so we're - * just going to tell the nic that we've dealt with the frame - * anyway. - */ - - /* Acknowledge interrupt, this tells nic we are done with the arb */ - writel(ACK_INTERRUPT | ARBCACK | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; - - /* Is the ASB free ? */ - - xl_priv->asb_queued = 0 ; - writel( ((MEM_BYTE_READ | 0xD0000 | xl_priv->asb) + 2), xl_mmio + MMIO_MAC_ACCESS_CMD) ; - if (readb(xl_mmio + MMIO_MACDATA) != 0xff) { - xl_priv->asb_queued = 1 ; - - xl_wait_misr_flags(dev) ; - - writel(MEM_BYTE_WRITE | MF_ASBFR, xl_mmio + MMIO_MAC_ACCESS_CMD); - writeb(0xff, xl_mmio + MMIO_MACDATA) ; - writel(MMIO_BYTE_WRITE | MISR_SET, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(MISR_ASBFR, xl_mmio + MMIO_MACDATA) ; - return ; - /* Drop out and wait for the bottom half to be run */ - } - - xl_asb_cmd(dev) ; - - } else { - printk(KERN_WARNING "%s: Received unknown arb (xl_priv) command: %02x\n",dev->name,arb_cmd); - } - - /* Acknowledge the arb interrupt */ - - writel(ACK_INTERRUPT | ARBCACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; - - return ; -} - - -/* - * There is only one asb command, but we can get called from different - * places. - */ - -static void xl_asb_cmd(struct net_device *dev) -{ - struct xl_private *xl_priv = netdev_priv(dev); - u8 __iomem * xl_mmio = xl_priv->xl_mmio ; - - if (xl_priv->asb_queued == 1) - writel(ACK_INTERRUPT | LATCH_ACK | ASBFACK, xl_mmio + MMIO_COMMAND) ; - - writel(MEM_BYTE_WRITE | 0xd0000 | xl_priv->asb, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(0x81, xl_mmio + MMIO_MACDATA) ; - - writel(MEM_WORD_WRITE | 0xd0000 | xl_priv->asb | 6, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writew(swab16(xl_priv->mac_buffer), xl_mmio + MMIO_MACDATA) ; - - xl_wait_misr_flags(dev) ; - - writel(MEM_BYTE_WRITE | MF_RASB, xl_mmio + MMIO_MAC_ACCESS_CMD); - writeb(0xff, xl_mmio + MMIO_MACDATA) ; - - writel(MMIO_BYTE_WRITE | MISR_SET, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(MISR_RASB, xl_mmio + MMIO_MACDATA) ; - - xl_priv->asb_queued = 2 ; - - return ; -} - -/* - * This will only get called if there was an error - * from the asb cmd. - */ -static void xl_asb_bh(struct net_device *dev) -{ - struct xl_private *xl_priv = netdev_priv(dev); - u8 __iomem * xl_mmio = xl_priv->xl_mmio ; - u8 ret_code ; - - writel(MMIO_BYTE_READ | 0xd0000 | xl_priv->asb | 2, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - ret_code = readb(xl_mmio + MMIO_MACDATA) ; - switch (ret_code) { - case 0x01: - printk(KERN_INFO "%s: ASB Command, unrecognized command code\n",dev->name); - break ; - case 0x26: - printk(KERN_INFO "%s: ASB Command, unexpected receive buffer\n", dev->name); - break ; - case 0x40: - printk(KERN_INFO "%s: ASB Command, Invalid Station ID\n", dev->name); - break ; - } - xl_priv->asb_queued = 0 ; - writel(ACK_INTERRUPT | LATCH_ACK | ASBFACK, xl_mmio + MMIO_COMMAND) ; - return ; -} - -/* - * Issue srb commands to the nic - */ - -static void xl_srb_cmd(struct net_device *dev, int srb_cmd) -{ - struct xl_private *xl_priv = netdev_priv(dev); - u8 __iomem * xl_mmio = xl_priv->xl_mmio ; - - switch (srb_cmd) { - case READ_LOG: - writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(READ_LOG, xl_mmio + MMIO_MACDATA) ; - break; - - case CLOSE_NIC: - writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(CLOSE_NIC, xl_mmio + MMIO_MACDATA) ; - break ; - - case SET_RECEIVE_MODE: - writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(SET_RECEIVE_MODE, xl_mmio + MMIO_MACDATA) ; - writel(MEM_WORD_WRITE | 0xD0000 | xl_priv->srb | 4, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writew(xl_priv->xl_copy_all_options, xl_mmio + MMIO_MACDATA) ; - break ; - - case SET_FUNC_ADDRESS: - writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(SET_FUNC_ADDRESS, xl_mmio + MMIO_MACDATA) ; - writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb | 6 , xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(xl_priv->xl_functional_addr[0], xl_mmio + MMIO_MACDATA) ; - writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb | 7 , xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(xl_priv->xl_functional_addr[1], xl_mmio + MMIO_MACDATA) ; - writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb | 8 , xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(xl_priv->xl_functional_addr[2], xl_mmio + MMIO_MACDATA) ; - writel(MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb | 9 , xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(xl_priv->xl_functional_addr[3], xl_mmio + MMIO_MACDATA) ; - break ; - } /* switch */ - - - xl_wait_misr_flags(dev) ; - - /* Write 0xff to the CSRB flag */ - writel(MEM_BYTE_WRITE | MF_CSRB , xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(0xFF, xl_mmio + MMIO_MACDATA) ; - /* Set csrb bit in MISR register to process command */ - writel(MMIO_BYTE_WRITE | MISR_SET, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(MISR_CSRB, xl_mmio + MMIO_MACDATA) ; - xl_priv->srb_queued = 1 ; - - return ; -} - -/* - * This is nasty, to use the MISR command you have to wait for 6 memory locations - * to be zero. This is the way the driver does on other OS'es so we should be ok with - * the empty loop. - */ - -static void xl_wait_misr_flags(struct net_device *dev) -{ - struct xl_private *xl_priv = netdev_priv(dev); - u8 __iomem * xl_mmio = xl_priv->xl_mmio ; - - int i ; - - writel(MMIO_BYTE_READ | MISR_RW, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - if (readb(xl_mmio + MMIO_MACDATA) != 0) { /* Misr not clear */ - for (i=0; i<6; i++) { - writel(MEM_BYTE_READ | 0xDFFE0 | i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - while (readb(xl_mmio + MMIO_MACDATA) != 0) { - ; /* Empty Loop */ - } - } - } - - writel(MMIO_BYTE_WRITE | MISR_AND, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(0x80, xl_mmio + MMIO_MACDATA) ; - - return ; -} - -/* - * Change mtu size, this should work the same as olympic - */ - -static int xl_change_mtu(struct net_device *dev, int mtu) -{ - struct xl_private *xl_priv = netdev_priv(dev); - u16 max_mtu ; - - if (xl_priv->xl_ring_speed == 4) - max_mtu = 4500 ; - else - max_mtu = 18000 ; - - if (mtu > max_mtu) - return -EINVAL ; - if (mtu < 100) - return -EINVAL ; - - dev->mtu = mtu ; - xl_priv->pkt_buf_sz = mtu + TR_HLEN ; - - return 0 ; -} - -static void __devexit xl_remove_one (struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct xl_private *xl_priv=netdev_priv(dev); - - release_firmware(xl_priv->fw); - unregister_netdev(dev); - iounmap(xl_priv->xl_mmio) ; - pci_release_regions(pdev) ; - pci_set_drvdata(pdev,NULL) ; - free_netdev(dev); - return ; -} - -static struct pci_driver xl_3c359_driver = { - .name = "3c359", - .id_table = xl_pci_tbl, - .probe = xl_probe, - .remove = __devexit_p(xl_remove_one), -}; - -static int __init xl_pci_init (void) -{ - return pci_register_driver(&xl_3c359_driver); -} - - -static void __exit xl_pci_cleanup (void) -{ - pci_unregister_driver (&xl_3c359_driver); -} - -module_init(xl_pci_init); -module_exit(xl_pci_cleanup); - -MODULE_LICENSE("GPL") ; diff --git a/trunk/drivers/net/tokenring/3c359.h b/trunk/drivers/net/tokenring/3c359.h deleted file mode 100644 index bcb1a6b4a4c7..000000000000 --- a/trunk/drivers/net/tokenring/3c359.h +++ /dev/null @@ -1,291 +0,0 @@ -/* - * 3c359.h (c) 2000 Mike Phillips (mikep@linuxtr.net) All Rights Reserved - * - * Linux driver for 3Com 3C359 Token Link PCI XL cards. - * - * This software may be used and distributed according to the terms - * of the GNU General Public License Version 2 or (at your option) - * any later verion, incorporated herein by reference. - */ - -/* Memory Access Commands */ -#define IO_BYTE_READ 0x28 << 24 -#define IO_BYTE_WRITE 0x18 << 24 -#define IO_WORD_READ 0x20 << 24 -#define IO_WORD_WRITE 0x10 << 24 -#define MMIO_BYTE_READ 0x88 << 24 -#define MMIO_BYTE_WRITE 0x48 << 24 -#define MMIO_WORD_READ 0x80 << 24 -#define MMIO_WORD_WRITE 0x40 << 24 -#define MEM_BYTE_READ 0x8C << 24 -#define MEM_BYTE_WRITE 0x4C << 24 -#define MEM_WORD_READ 0x84 << 24 -#define MEM_WORD_WRITE 0x44 << 24 - -#define PMBAR 0x1C80 -#define PMB_CPHOLD (1<<10) - -#define CPATTENTION 0x180D -#define CPA_PMBARVIS (1<<7) -#define CPA_MEMWREN (1<<6) - -#define SWITCHSETTINGS 0x1C88 -#define EECONTROL 0x1C8A -#define EEDATA 0x1C8C -#define EEREAD 0x0080 -#define EEWRITE 0x0040 -#define EEERASE 0x0060 -#define EE_ENABLE_WRITE 0x0030 -#define EEBUSY (1<<15) - -#define WRBR 0xCDE02 -#define WWOR 0xCDE04 -#define WWCR 0xCDE06 -#define MACSTATUS 0xCDE08 -#define MISR_RW 0xCDE0B -#define MISR_AND 0xCDE2B -#define MISR_SET 0xCDE4B -#define RXBUFAREA 0xCDE10 -#define RXEARLYTHRESH 0xCDE12 -#define TXSTARTTHRESH 0x58 -#define DNPRIREQTHRESH 0x2C - -#define MISR_CSRB (1<<5) -#define MISR_RASB (1<<4) -#define MISR_SRBFR (1<<3) -#define MISR_ASBFR (1<<2) -#define MISR_ARBF (1<<1) - -/* MISR Flags memory locations */ -#define MF_SSBF 0xDFFE0 -#define MF_ARBF 0xDFFE1 -#define MF_ASBFR 0xDFFE2 -#define MF_SRBFR 0xDFFE3 -#define MF_RASB 0xDFFE4 -#define MF_CSRB 0xDFFE5 - -#define MMIO_MACDATA 0x10 -#define MMIO_MAC_ACCESS_CMD 0x14 -#define MMIO_TIMER 0x1A -#define MMIO_DMA_CTRL 0x20 -#define MMIO_DNLISTPTR 0x24 -#define MMIO_HASHFILTER 0x28 -#define MMIO_CONFIG 0x29 -#define MMIO_DNPRIREQTHRESH 0x2C -#define MMIO_DNPOLL 0x2D -#define MMIO_UPPKTSTATUS 0x30 -#define MMIO_FREETIMER 0x34 -#define MMIO_COUNTDOWN 0x36 -#define MMIO_UPLISTPTR 0x38 -#define MMIO_UPPOLL 0x3C -#define MMIO_UPBURSTTHRESH 0x40 -#define MMIO_DNBURSTTHRESH 0x41 -#define MMIO_INTSTATUS_AUTO 0x56 -#define MMIO_TXSTARTTHRESH 0x58 -#define MMIO_INTERRUPTENABLE 0x5A -#define MMIO_INDICATIONENABLE 0x5C -#define MMIO_COMMAND 0x5E /* These two are meant to be the same */ -#define MMIO_INTSTATUS 0x5E /* Makes the code more readable this way */ -#define INTSTAT_CMD_IN_PROGRESS (1<<12) -#define INTSTAT_SRB (1<<14) -#define INTSTAT_INTLATCH (1<<0) - -/* Indication / Interrupt Mask - * Annoyingly the bits to be set in the indication and interrupt enable - * do not match with the actual bits received in the interrupt, although - * they are in the same order. - * The mapping for the indication / interrupt are: - * Bit Indication / Interrupt - * 0 HostError - * 1 txcomplete - * 2 updneeded - * 3 rxcomplete - * 4 intrequested - * 5 macerror - * 6 dncomplete - * 7 upcomplete - * 8 txunderrun - * 9 asbf - * 10 srbr - * 11 arbc - * - * The only ones we don't want to receive are txcomplete and rxcomplete - * we use dncomplete and upcomplete instead. - */ - -#define INT_MASK 0xFF5 - -/* Note the subtle difference here, IND and INT */ - -#define SETINDENABLE (8<<12) -#define SETINTENABLE (7<<12) -#define SRBBIT (1<<10) -#define ASBBIT (1<<9) -#define ARBBIT (1<<11) - -#define SRB 0xDFE90 -#define ASB 0xDFED0 -#define ARB 0xD0000 -#define SCRATCH 0xDFEF0 - -#define INT_REQUEST 0x6000 /* (6 << 12) */ -#define ACK_INTERRUPT 0x6800 /* (13 <<11) */ -#define GLOBAL_RESET 0x00 -#define DNDISABLE 0x5000 -#define DNENABLE 0x4800 -#define DNSTALL 0x3002 -#define DNRESET 0x5800 -#define DNUNSTALL 0x3003 -#define UPRESET 0x2800 -#define UPSTALL 0x3000 -#define UPUNSTALL 0x3001 -#define SETCONFIG 0x4000 -#define SETTXSTARTTHRESH 0x9800 - -/* Received Interrupts */ -#define ASBFINT (1<<13) -#define SRBRINT (1<<14) -#define ARBCINT (1<<15) -#define TXUNDERRUN (1<<11) - -#define UPCOMPINT (1<<10) -#define DNCOMPINT (1<<9) -#define HARDERRINT (1<<7) -#define RXCOMPLETE (1<<4) -#define TXCOMPINT (1<<2) -#define HOSTERRINT (1<<1) - -/* Receive descriptor bits */ -#define RXOVERRUN cpu_to_le32(1<<19) -#define RXFC cpu_to_le32(1<<21) -#define RXAR cpu_to_le32(1<<22) -#define RXUPDCOMPLETE cpu_to_le32(1<<23) -#define RXUPDFULL cpu_to_le32(1<<24) -#define RXUPLASTFRAG cpu_to_le32(1<<31) - -/* Transmit descriptor bits */ -#define TXDNCOMPLETE cpu_to_le32(1<<16) -#define TXTXINDICATE cpu_to_le32(1<<27) -#define TXDPDEMPTY cpu_to_le32(1<<29) -#define TXDNINDICATE cpu_to_le32(1<<31) -#define TXDNFRAGLAST cpu_to_le32(1<<31) - -/* Interrupts to Acknowledge */ -#define LATCH_ACK 1 -#define TXCOMPACK (1<<1) -#define INTREQACK (1<<2) -#define DNCOMPACK (1<<3) -#define UPCOMPACK (1<<4) -#define ASBFACK (1<<5) -#define SRBRACK (1<<6) -#define ARBCACK (1<<7) - -#define XL_IO_SPACE 128 -#define SRB_COMMAND_SIZE 50 - -/* Adapter Commands */ -#define REQUEST_INT 0x00 -#define MODIFY_OPEN_PARMS 0x01 -#define RESTORE_OPEN_PARMS 0x02 -#define OPEN_NIC 0x03 -#define CLOSE_NIC 0x04 -#define SET_SLEEP_MODE 0x05 -#define SET_GROUP_ADDRESS 0x06 -#define SET_FUNC_ADDRESS 0x07 -#define READ_LOG 0x08 -#define SET_MULTICAST_MODE 0x0C -#define CHANGE_WAKEUP_PATTERN 0x0D -#define GET_STATISTICS 0x13 -#define SET_RECEIVE_MODE 0x1F - -/* ARB Commands */ -#define RECEIVE_DATA 0x81 -#define RING_STATUS_CHANGE 0x84 - -/* ASB Commands */ -#define ASB_RECEIVE_DATE 0x81 - -/* Defines for LAN STATUS CHANGE reports */ -#define LSC_SIG_LOSS 0x8000 -#define LSC_HARD_ERR 0x4000 -#define LSC_SOFT_ERR 0x2000 -#define LSC_TRAN_BCN 0x1000 -#define LSC_LWF 0x0800 -#define LSC_ARW 0x0400 -#define LSC_FPE 0x0200 -#define LSC_RR 0x0100 -#define LSC_CO 0x0080 -#define LSC_SS 0x0040 -#define LSC_RING_REC 0x0020 -#define LSC_SR_CO 0x0010 -#define LSC_FDX_MODE 0x0004 - -#define XL_MAX_ADAPTERS 8 /* 0x08 __MODULE_STRING can't hand 0xnn */ - -/* 3c359 defaults for buffers */ - -#define XL_RX_RING_SIZE 16 /* must be a power of 2 */ -#define XL_TX_RING_SIZE 16 /* must be a power of 2 */ - -#define PKT_BUF_SZ 4096 /* Default packet size */ - -/* 3c359 data structures */ - -struct xl_tx_desc { - __le32 dnnextptr; - __le32 framestartheader; - __le32 buffer; - __le32 buffer_length; -}; - -struct xl_rx_desc { - __le32 upnextptr; - __le32 framestatus; - __le32 upfragaddr; - __le32 upfraglen; -}; - -struct xl_private { - - - /* These two structures must be aligned on 8 byte boundaries */ - - /* struct xl_rx_desc xl_rx_ring[XL_RX_RING_SIZE]; */ - /* struct xl_tx_desc xl_tx_ring[XL_TX_RING_SIZE]; */ - struct xl_rx_desc *xl_rx_ring ; - struct xl_tx_desc *xl_tx_ring ; - struct sk_buff *tx_ring_skb[XL_TX_RING_SIZE], *rx_ring_skb[XL_RX_RING_SIZE]; - int tx_ring_head, tx_ring_tail ; - int rx_ring_tail, rx_ring_no ; - int free_ring_entries ; - - u16 srb; - u16 arb; - u16 asb; - - u8 __iomem *xl_mmio; - const char *xl_card_name; - struct pci_dev *pdev ; - - spinlock_t xl_lock ; - - volatile int srb_queued; - struct wait_queue *srb_wait; - volatile int asb_queued; - - u16 mac_buffer ; - u16 xl_lan_status ; - u8 xl_ring_speed ; - u16 pkt_buf_sz ; - u8 xl_message_level; - u16 xl_copy_all_options ; - unsigned char xl_functional_addr[4] ; - u16 xl_addr_table_addr, xl_parms_addr ; - u8 xl_laa[6] ; - u32 rx_ring_dma_addr ; - u32 tx_ring_dma_addr ; - - /* firmware section */ - const struct firmware *fw; -}; - diff --git a/trunk/drivers/net/tokenring/Kconfig b/trunk/drivers/net/tokenring/Kconfig deleted file mode 100644 index 45550d42b368..000000000000 --- a/trunk/drivers/net/tokenring/Kconfig +++ /dev/null @@ -1,199 +0,0 @@ -# -# Token Ring driver configuration -# - -# So far, we only have PCI, ISA, and MCA token ring devices -menuconfig TR - bool "Token Ring driver support" - depends on NETDEVICES && !UML - depends on (PCI || ISA || MCA || CCW || PCMCIA) - help - Token Ring is IBM's way of communication on a local network; the - rest of the world uses Ethernet. To participate on a Token Ring - network, you need a special Token ring network card. If you are - connected to such a Token Ring network and want to use your Token - Ring card under Linux, say Y here and to the driver for your - particular card below and read the Token-Ring mini-HOWTO, available - from . Most people can - say N here. - -if TR - -config WANT_LLC - def_bool y - select LLC - -config PCMCIA_IBMTR - tristate "IBM PCMCIA tokenring adapter support" - depends on IBMTR!=y && PCMCIA - ---help--- - Say Y here if you intend to attach this type of Token Ring PCMCIA - card to your computer. You then also need to say Y to "Token Ring - driver support". - - To compile this driver as a module, choose M here: the module will be - called ibmtr_cs. - -config IBMTR - tristate "IBM Tropic chipset based adapter support" - depends on ISA || MCA - ---help--- - This is support for all IBM Token Ring cards that don't use DMA. If - you have such a beast, say Y and read the Token-Ring mini-HOWTO, - available from . - - Warning: this driver will almost definitely fail if more than one - active Token Ring card is present. - - To compile this driver as a module, choose M here: the module will be - called ibmtr. - -config IBMOL - tristate "IBM Olympic chipset PCI adapter support" - depends on PCI - ---help--- - This is support for all non-Lanstreamer IBM PCI Token Ring Cards. - Specifically this is all IBM PCI, PCI Wake On Lan, PCI II, PCI II - Wake On Lan, and PCI 100/16/4 adapters. - - If you have such an adapter, say Y and read the Token-Ring - mini-HOWTO, available from . - - To compile this driver as a module, choose M here: the module will be - called olympic. - - Also read or check the - Linux Token Ring Project site for the latest information at - . - -config IBMLS - tristate "IBM Lanstreamer chipset PCI adapter support" - depends on PCI && !64BIT - help - This is support for IBM Lanstreamer PCI Token Ring Cards. - - If you have such an adapter, say Y and read the Token-Ring - mini-HOWTO, available from . - - To compile this driver as a module, choose M here: the module will be - called lanstreamer. - -config 3C359 - tristate "3Com 3C359 Token Link Velocity XL adapter support" - depends on PCI - ---help--- - This is support for the 3Com PCI Velocity XL cards, specifically - the 3Com 3C359, please note this is not for the 3C339 cards, you - should use the tms380 driver instead. - - If you have such an adapter, say Y and read the Token-Ring - mini-HOWTO, available from . - - To compile this driver as a module, choose M here: the module will be - called 3c359. - - Also read the file or check the - Linux Token Ring Project site for the latest information at - - -config TMS380TR - tristate "Generic TMS380 Token Ring ISA/PCI adapter support" - depends on PCI || ISA && ISA_DMA_API || MCA - select FW_LOADER - ---help--- - This driver provides generic support for token ring adapters - based on the Texas Instruments TMS380 series chipsets. This - includes the SysKonnect TR4/16(+) ISA (SK-4190), SysKonnect - TR4/16(+) PCI (SK-4590), SysKonnect TR4/16 PCI (SK-4591), - Compaq 4/16 PCI, Thomas-Conrad TC4048 4/16 PCI, and several - Madge adapters. If you say Y here, you will be asked to select - which cards to support below. If you're using modules, each - class of card will be supported by a separate module. - - If you have such an adapter and would like to use it, say Y and - read the Token-Ring mini-HOWTO, available from - . - - Also read the file or - check . - - To compile this driver as a module, choose M here: the module will be - called tms380tr. - -config TMSPCI - tristate "Generic TMS380 PCI support" - depends on TMS380TR && PCI - ---help--- - This tms380 module supports generic TMS380-based PCI cards. - - These cards are known to work: - - Compaq 4/16 TR PCI - - SysKonnect TR4/16 PCI (SK-4590/SK-4591) - - Thomas-Conrad TC4048 PCI 4/16 - - 3Com Token Link Velocity - - To compile this driver as a module, choose M here: the module will be - called tmspci. - -config SKISA - tristate "SysKonnect TR4/16 ISA support" - depends on TMS380TR && ISA - help - This tms380 module supports SysKonnect TR4/16 ISA cards. - - These cards are known to work: - - SysKonnect TR4/16 ISA (SK-4190) - - To compile this driver as a module, choose M here: the module will be - called skisa. - -config PROTEON - tristate "Proteon ISA support" - depends on TMS380TR && ISA - help - This tms380 module supports Proteon ISA cards. - - These cards are known to work: - - Proteon 1392 - - Proteon 1392 plus - - To compile this driver as a module, choose M here: the module will be - called proteon. - -config ABYSS - tristate "Madge Smart 16/4 PCI Mk2 support" - depends on TMS380TR && PCI - help - This tms380 module supports the Madge Smart 16/4 PCI Mk2 - cards (51-02). - - To compile this driver as a module, choose M here: the module will be - called abyss. - -config MADGEMC - tristate "Madge Smart 16/4 Ringnode MicroChannel" - depends on TMS380TR && MCA - help - This tms380 module supports the Madge Smart 16/4 MC16 and MC32 - MicroChannel adapters. - - To compile this driver as a module, choose M here: the module will be - called madgemc. - -config SMCTR - tristate "SMC ISA/MCA adapter support" - depends on (ISA || MCA_LEGACY) && (BROKEN || !64BIT) - ---help--- - This is support for the ISA and MCA SMC Token Ring cards, - specifically SMC TokenCard Elite (8115T) and SMC TokenCard Elite/A - (8115T/A) adapters. - - If you have such an adapter and would like to use it, say Y or M and - read the Token-Ring mini-HOWTO, available from - and the file - . - - To compile this driver as a module, choose M here: the module will be - called smctr. - -endif # TR diff --git a/trunk/drivers/net/tokenring/Makefile b/trunk/drivers/net/tokenring/Makefile deleted file mode 100644 index f1be8d97b7a8..000000000000 --- a/trunk/drivers/net/tokenring/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# -# Makefile for drivers/net/tokenring -# - -obj-$(CONFIG_PCMCIA_IBMTR) += ibmtr_cs.o -obj-$(CONFIG_IBMTR) += ibmtr.o -obj-$(CONFIG_IBMOL) += olympic.o -obj-$(CONFIG_IBMLS) += lanstreamer.o -obj-$(CONFIG_TMS380TR) += tms380tr.o -obj-$(CONFIG_ABYSS) += abyss.o -obj-$(CONFIG_MADGEMC) += madgemc.o -obj-$(CONFIG_PROTEON) += proteon.o -obj-$(CONFIG_TMSPCI) += tmspci.o -obj-$(CONFIG_SKISA) += skisa.o -obj-$(CONFIG_SMCTR) += smctr.o -obj-$(CONFIG_3C359) += 3c359.o diff --git a/trunk/drivers/net/tokenring/abyss.c b/trunk/drivers/net/tokenring/abyss.c deleted file mode 100644 index b715e6b444da..000000000000 --- a/trunk/drivers/net/tokenring/abyss.c +++ /dev/null @@ -1,468 +0,0 @@ -/* - * abyss.c: Network driver for the Madge Smart 16/4 PCI Mk2 token ring card. - * - * Written 1999-2000 by Adam Fritzler - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * This driver module supports the following cards: - * - Madge Smart 16/4 PCI Mk2 - * - * Maintainer(s): - * AF Adam Fritzler - * - * Modification History: - * 30-Dec-99 AF Split off from the tms380tr driver. - * 22-Jan-00 AF Updated to use indirect read/writes - * 23-Nov-00 JG New PCI API, cleanups - * - * - * TODO: - * 1. See if we can use MMIO instead of inb/outb/inw/outw - * 2. Add support for Mk1 (has AT24 attached to the PCI - * config registers) - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "tms380tr.h" -#include "abyss.h" /* Madge-specific constants */ - -static char version[] __devinitdata = -"abyss.c: v1.02 23/11/2000 by Adam Fritzler\n"; - -#define ABYSS_IO_EXTENT 64 - -static DEFINE_PCI_DEVICE_TABLE(abyss_pci_tbl) = { - { PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_MK2, - PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_TOKEN_RING << 8, 0x00ffffff, }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(pci, abyss_pci_tbl); - -MODULE_LICENSE("GPL"); - -static int abyss_open(struct net_device *dev); -static int abyss_close(struct net_device *dev); -static void abyss_enable(struct net_device *dev); -static int abyss_chipset_init(struct net_device *dev); -static void abyss_read_eeprom(struct net_device *dev); -static unsigned short abyss_setnselout_pins(struct net_device *dev); - -static void at24_writedatabyte(unsigned long regaddr, unsigned char byte); -static int at24_sendfullcmd(unsigned long regaddr, unsigned char cmd, unsigned char addr); -static int at24_sendcmd(unsigned long regaddr, unsigned char cmd); -static unsigned char at24_readdatabit(unsigned long regaddr); -static unsigned char at24_readdatabyte(unsigned long regaddr); -static int at24_waitforack(unsigned long regaddr); -static int at24_waitfornack(unsigned long regaddr); -static void at24_setlines(unsigned long regaddr, unsigned char clock, unsigned char data); -static void at24_start(unsigned long regaddr); -static unsigned char at24_readb(unsigned long regaddr, unsigned char addr); - -static unsigned short abyss_sifreadb(struct net_device *dev, unsigned short reg) -{ - return inb(dev->base_addr + reg); -} - -static unsigned short abyss_sifreadw(struct net_device *dev, unsigned short reg) -{ - return inw(dev->base_addr + reg); -} - -static void abyss_sifwriteb(struct net_device *dev, unsigned short val, unsigned short reg) -{ - outb(val, dev->base_addr + reg); -} - -static void abyss_sifwritew(struct net_device *dev, unsigned short val, unsigned short reg) -{ - outw(val, dev->base_addr + reg); -} - -static struct net_device_ops abyss_netdev_ops; - -static int __devinit abyss_attach(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - static int versionprinted; - struct net_device *dev; - struct net_local *tp; - int ret, pci_irq_line; - unsigned long pci_ioaddr; - - if (versionprinted++ == 0) - printk("%s", version); - - if (pci_enable_device(pdev)) - return -EIO; - - /* Remove I/O space marker in bit 0. */ - pci_irq_line = pdev->irq; - pci_ioaddr = pci_resource_start (pdev, 0); - - /* At this point we have found a valid card. */ - - dev = alloc_trdev(sizeof(struct net_local)); - if (!dev) - return -ENOMEM; - - if (!request_region(pci_ioaddr, ABYSS_IO_EXTENT, dev->name)) { - ret = -EBUSY; - goto err_out_trdev; - } - - ret = request_irq(pdev->irq, tms380tr_interrupt, IRQF_SHARED, - dev->name, dev); - if (ret) - goto err_out_region; - - dev->base_addr = pci_ioaddr; - dev->irq = pci_irq_line; - - printk("%s: Madge Smart 16/4 PCI Mk2 (Abyss)\n", dev->name); - printk("%s: IO: %#4lx IRQ: %d\n", - dev->name, pci_ioaddr, dev->irq); - /* - * The TMS SIF registers lay 0x10 above the card base address. - */ - dev->base_addr += 0x10; - - ret = tmsdev_init(dev, &pdev->dev); - if (ret) { - printk("%s: unable to get memory for dev->priv.\n", - dev->name); - goto err_out_irq; - } - - abyss_read_eeprom(dev); - - printk("%s: Ring Station Address: %pM\n", dev->name, dev->dev_addr); - - tp = netdev_priv(dev); - tp->setnselout = abyss_setnselout_pins; - tp->sifreadb = abyss_sifreadb; - tp->sifreadw = abyss_sifreadw; - tp->sifwriteb = abyss_sifwriteb; - tp->sifwritew = abyss_sifwritew; - - memcpy(tp->ProductID, "Madge PCI 16/4 Mk2", PROD_ID_SIZE + 1); - - dev->netdev_ops = &abyss_netdev_ops; - - pci_set_drvdata(pdev, dev); - SET_NETDEV_DEV(dev, &pdev->dev); - - ret = register_netdev(dev); - if (ret) - goto err_out_tmsdev; - return 0; - -err_out_tmsdev: - pci_set_drvdata(pdev, NULL); - tmsdev_term(dev); -err_out_irq: - free_irq(pdev->irq, dev); -err_out_region: - release_region(pci_ioaddr, ABYSS_IO_EXTENT); -err_out_trdev: - free_netdev(dev); - return ret; -} - -static unsigned short abyss_setnselout_pins(struct net_device *dev) -{ - unsigned short val = 0; - struct net_local *tp = netdev_priv(dev); - - if(tp->DataRate == SPEED_4) - val |= 0x01; /* Set 4Mbps */ - else - val |= 0x00; /* Set 16Mbps */ - - return val; -} - -/* - * The following Madge boards should use this code: - * - Smart 16/4 PCI Mk2 (Abyss) - * - Smart 16/4 PCI Mk1 (PCI T) - * - Smart 16/4 Client Plus PnP (Big Apple) - * - Smart 16/4 Cardbus Mk2 - * - * These access an Atmel AT24 SEEPROM using their glue chip registers. - * - */ -static void at24_writedatabyte(unsigned long regaddr, unsigned char byte) -{ - int i; - - for (i = 0; i < 8; i++) { - at24_setlines(regaddr, 0, (byte >> (7-i))&0x01); - at24_setlines(regaddr, 1, (byte >> (7-i))&0x01); - at24_setlines(regaddr, 0, (byte >> (7-i))&0x01); - } -} - -static int at24_sendfullcmd(unsigned long regaddr, unsigned char cmd, unsigned char addr) -{ - if (at24_sendcmd(regaddr, cmd)) { - at24_writedatabyte(regaddr, addr); - return at24_waitforack(regaddr); - } - return 0; -} - -static int at24_sendcmd(unsigned long regaddr, unsigned char cmd) -{ - int i; - - for (i = 0; i < 10; i++) { - at24_start(regaddr); - at24_writedatabyte(regaddr, cmd); - if (at24_waitforack(regaddr)) - return 1; - } - return 0; -} - -static unsigned char at24_readdatabit(unsigned long regaddr) -{ - unsigned char val; - - at24_setlines(regaddr, 0, 1); - at24_setlines(regaddr, 1, 1); - val = (inb(regaddr) & AT24_DATA)?1:0; - at24_setlines(regaddr, 1, 1); - at24_setlines(regaddr, 0, 1); - return val; -} - -static unsigned char at24_readdatabyte(unsigned long regaddr) -{ - unsigned char data = 0; - int i; - - for (i = 0; i < 8; i++) { - data <<= 1; - data |= at24_readdatabit(regaddr); - } - - return data; -} - -static int at24_waitforack(unsigned long regaddr) -{ - int i; - - for (i = 0; i < 10; i++) { - if ((at24_readdatabit(regaddr) & 0x01) == 0x00) - return 1; - } - return 0; -} - -static int at24_waitfornack(unsigned long regaddr) -{ - int i; - for (i = 0; i < 10; i++) { - if ((at24_readdatabit(regaddr) & 0x01) == 0x01) - return 1; - } - return 0; -} - -static void at24_setlines(unsigned long regaddr, unsigned char clock, unsigned char data) -{ - unsigned char val = AT24_ENABLE; - if (clock) - val |= AT24_CLOCK; - if (data) - val |= AT24_DATA; - - outb(val, regaddr); - tms380tr_wait(20); /* Very necessary. */ -} - -static void at24_start(unsigned long regaddr) -{ - at24_setlines(regaddr, 0, 1); - at24_setlines(regaddr, 1, 1); - at24_setlines(regaddr, 1, 0); - at24_setlines(regaddr, 0, 1); -} - -static unsigned char at24_readb(unsigned long regaddr, unsigned char addr) -{ - unsigned char data = 0xff; - - if (at24_sendfullcmd(regaddr, AT24_WRITE, addr)) { - if (at24_sendcmd(regaddr, AT24_READ)) { - data = at24_readdatabyte(regaddr); - if (!at24_waitfornack(regaddr)) - data = 0xff; - } - } - return data; -} - - -/* - * Enable basic functions of the Madge chipset needed - * for initialization. - */ -static void abyss_enable(struct net_device *dev) -{ - unsigned char reset_reg; - unsigned long ioaddr; - - ioaddr = dev->base_addr; - reset_reg = inb(ioaddr + PCIBM2_RESET_REG); - reset_reg |= PCIBM2_RESET_REG_CHIP_NRES; - outb(reset_reg, ioaddr + PCIBM2_RESET_REG); - tms380tr_wait(100); -} - -/* - * Enable the functions of the Madge chipset needed for - * full working order. - */ -static int abyss_chipset_init(struct net_device *dev) -{ - unsigned char reset_reg; - unsigned long ioaddr; - - ioaddr = dev->base_addr; - - reset_reg = inb(ioaddr + PCIBM2_RESET_REG); - - reset_reg |= PCIBM2_RESET_REG_CHIP_NRES; - outb(reset_reg, ioaddr + PCIBM2_RESET_REG); - - reset_reg &= ~(PCIBM2_RESET_REG_CHIP_NRES | - PCIBM2_RESET_REG_FIFO_NRES | - PCIBM2_RESET_REG_SIF_NRES); - outb(reset_reg, ioaddr + PCIBM2_RESET_REG); - - tms380tr_wait(100); - - reset_reg |= PCIBM2_RESET_REG_CHIP_NRES; - outb(reset_reg, ioaddr + PCIBM2_RESET_REG); - - reset_reg |= PCIBM2_RESET_REG_SIF_NRES; - outb(reset_reg, ioaddr + PCIBM2_RESET_REG); - - reset_reg |= PCIBM2_RESET_REG_FIFO_NRES; - outb(reset_reg, ioaddr + PCIBM2_RESET_REG); - - outb(PCIBM2_INT_CONTROL_REG_SINTEN | - PCIBM2_INT_CONTROL_REG_PCI_ERR_ENABLE, - ioaddr + PCIBM2_INT_CONTROL_REG); - - outb(30, ioaddr + PCIBM2_FIFO_THRESHOLD); - - return 0; -} - -static inline void abyss_chipset_close(struct net_device *dev) -{ - unsigned long ioaddr; - - ioaddr = dev->base_addr; - outb(0, ioaddr + PCIBM2_RESET_REG); -} - -/* - * Read configuration data from the AT24 SEEPROM on Madge cards. - * - */ -static void abyss_read_eeprom(struct net_device *dev) -{ - struct net_local *tp; - unsigned long ioaddr; - unsigned short val; - int i; - - tp = netdev_priv(dev); - ioaddr = dev->base_addr; - - /* Must enable glue chip first */ - abyss_enable(dev); - - val = at24_readb(ioaddr + PCIBM2_SEEPROM_REG, - PCIBM2_SEEPROM_RING_SPEED); - tp->DataRate = val?SPEED_4:SPEED_16; /* set open speed */ - printk("%s: SEEPROM: ring speed: %dMb/sec\n", dev->name, tp->DataRate); - - val = at24_readb(ioaddr + PCIBM2_SEEPROM_REG, - PCIBM2_SEEPROM_RAM_SIZE) * 128; - printk("%s: SEEPROM: adapter RAM: %dkb\n", dev->name, val); - - dev->addr_len = 6; - for (i = 0; i < 6; i++) - dev->dev_addr[i] = at24_readb(ioaddr + PCIBM2_SEEPROM_REG, - PCIBM2_SEEPROM_BIA+i); -} - -static int abyss_open(struct net_device *dev) -{ - abyss_chipset_init(dev); - tms380tr_open(dev); - return 0; -} - -static int abyss_close(struct net_device *dev) -{ - tms380tr_close(dev); - abyss_chipset_close(dev); - return 0; -} - -static void __devexit abyss_detach (struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - - BUG_ON(!dev); - unregister_netdev(dev); - release_region(dev->base_addr-0x10, ABYSS_IO_EXTENT); - free_irq(dev->irq, dev); - tmsdev_term(dev); - free_netdev(dev); - pci_set_drvdata(pdev, NULL); -} - -static struct pci_driver abyss_driver = { - .name = "abyss", - .id_table = abyss_pci_tbl, - .probe = abyss_attach, - .remove = __devexit_p(abyss_detach), -}; - -static int __init abyss_init (void) -{ - abyss_netdev_ops = tms380tr_netdev_ops; - - abyss_netdev_ops.ndo_open = abyss_open; - abyss_netdev_ops.ndo_stop = abyss_close; - - return pci_register_driver(&abyss_driver); -} - -static void __exit abyss_rmmod (void) -{ - pci_unregister_driver (&abyss_driver); -} - -module_init(abyss_init); -module_exit(abyss_rmmod); - diff --git a/trunk/drivers/net/tokenring/abyss.h b/trunk/drivers/net/tokenring/abyss.h deleted file mode 100644 index b0a473b89133..000000000000 --- a/trunk/drivers/net/tokenring/abyss.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * abyss.h: Header for the abyss tms380tr module - * - * Authors: - * - Adam Fritzler - */ - -#ifndef __LINUX_MADGETR_H -#define __LINUX_MADGETR_H - -#ifdef __KERNEL__ - -/* - * For Madge Smart 16/4 PCI Mk2. Since we increment the base address - * to get everything correct for the TMS SIF, we do these as negatives - * as they fall below the SIF in addressing. - */ -#define PCIBM2_INT_STATUS_REG ((short)-15)/* 0x01 */ -#define PCIBM2_INT_CONTROL_REG ((short)-14)/* 0x02 */ -#define PCIBM2_RESET_REG ((short)-12)/* 0x04 */ -#define PCIBM2_SEEPROM_REG ((short)-9) /* 0x07 */ - -#define PCIBM2_INT_CONTROL_REG_SINTEN 0x02 -#define PCIBM2_INT_CONTROL_REG_PCI_ERR_ENABLE 0x80 -#define PCIBM2_INT_STATUS_REG_PCI_ERR 0x80 - -#define PCIBM2_RESET_REG_CHIP_NRES 0x01 -#define PCIBM2_RESET_REG_FIFO_NRES 0x02 -#define PCIBM2_RESET_REG_SIF_NRES 0x04 - -#define PCIBM2_FIFO_THRESHOLD 0x21 -#define PCIBM2_BURST_LENGTH 0x22 - -/* - * Bits in PCIBM2_SEEPROM_REG. - */ -#define AT24_ENABLE 0x04 -#define AT24_DATA 0x02 -#define AT24_CLOCK 0x01 - -/* - * AT24 Commands. - */ -#define AT24_WRITE 0xA0 -#define AT24_READ 0xA1 - -/* - * Addresses in AT24 SEEPROM. - */ -#define PCIBM2_SEEPROM_BIA 0x12 -#define PCIBM2_SEEPROM_RING_SPEED 0x18 -#define PCIBM2_SEEPROM_RAM_SIZE 0x1A -#define PCIBM2_SEEPROM_HWF1 0x1C -#define PCIBM2_SEEPROM_HWF2 0x1E - - -#endif /* __KERNEL__ */ -#endif /* __LINUX_MADGETR_H */ diff --git a/trunk/drivers/net/tokenring/ibmtr.c b/trunk/drivers/net/tokenring/ibmtr.c deleted file mode 100644 index b5c8c18f5046..000000000000 --- a/trunk/drivers/net/tokenring/ibmtr.c +++ /dev/null @@ -1,1964 +0,0 @@ -/* ibmtr.c: A shared-memory IBM Token Ring 16/4 driver for linux - * - * Written 1993 by Mark Swanson and Peter De Schrijver. - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * This device driver should work with Any IBM Token Ring Card that does - * not use DMA. - * - * I used Donald Becker's (becker@scyld.com) device driver work - * as a base for most of my initial work. - * - * Changes by Peter De Schrijver - * (Peter.Deschrijver@linux.cc.kuleuven.ac.be) : - * - * + changed name to ibmtr.c in anticipation of other tr boards. - * + changed reset code and adapter open code. - * + added SAP open code. - * + a first attempt to write interrupt, transmit and receive routines. - * - * Changes by David W. Morris (dwm@shell.portal.com) : - * 941003 dwm: - Restructure tok_probe for multiple adapters, devices. - * + Add comments, misc reorg for clarity. - * + Flatten interrupt handler levels. - * - * Changes by Farzad Farid (farzy@zen.via.ecp.fr) - * and Pascal Andre (andre@chimay.via.ecp.fr) (March 9 1995) : - * + multi ring support clean up. - * + RFC1042 compliance enhanced. - * - * Changes by Pascal Andre (andre@chimay.via.ecp.fr) (September 7 1995) : - * + bug correction in tr_tx - * + removed redundant information display - * + some code reworking - * - * Changes by Michel Lespinasse (walken@via.ecp.fr), - * Yann Doussot (doussot@via.ecp.fr) and Pascal Andre (andre@via.ecp.fr) - * (February 18, 1996) : - * + modified shared memory and mmio access port the driver to - * alpha platform (structure access -> readb/writeb) - * - * Changes by Steve Kipisz (bungy@ibm.net or kipisz@vnet.ibm.com) - * (January 18 1996): - * + swapped WWOR and WWCR in ibmtr.h - * + moved some init code from tok_probe into trdev_init. The - * PCMCIA code can call trdev_init to complete initializing - * the driver. - * + added -DPCMCIA to support PCMCIA - * + detecting PCMCIA Card Removal in interrupt handler. If - * ISRP is FF, then a PCMCIA card has been removed - * 10/2000 Burt needed a new method to avoid crashing the OS - * - * Changes by Paul Norton (pnorton@cts.com) : - * + restructured the READ.LOG logic to prevent the transmit SRB - * from being rudely overwritten before the transmit cycle is - * complete. (August 15 1996) - * + completed multiple adapter support. (November 20 1996) - * + implemented csum_partial_copy in tr_rx and increased receive - * buffer size and count. Minor fixes. (March 15, 1997) - * - * Changes by Christopher Turcksin - * + Now compiles ok as a module again. - * - * Changes by Paul Norton (pnorton@ieee.org) : - * + moved the header manipulation code in tr_tx and tr_rx to - * net/802/tr.c. (July 12 1997) - * + add retry and timeout on open if cable disconnected. (May 5 1998) - * + lifted 2000 byte mtu limit. now depends on shared-RAM size. - * May 25 1998) - * + can't allocate 2k recv buff at 8k shared-RAM. (20 October 1998) - * - * Changes by Joel Sloan (jjs@c-me.com) : - * + disable verbose debug messages by default - to enable verbose - * debugging, edit the IBMTR_DEBUG_MESSAGES define below - * - * Changes by Mike Phillips : - * + Added extra #ifdef's to work with new PCMCIA Token Ring Code. - * The PCMCIA code now just sets up the card so it can be recognized - * by ibmtr_probe. Also checks allocated memory vs. on-board memory - * for correct figure to use. - * - * Changes by Tim Hockin (thockin@isunix.it.ilstu.edu) : - * + added spinlocks for SMP sanity (10 March 1999) - * - * Changes by Jochen Friedrich to enable RFC1469 Option 2 multicasting - * i.e. using functional address C0 00 00 04 00 00 to transmit and - * receive multicast packets. - * - * Changes by Mike Sullivan (based on original sram patch by Dave Grothe - * to support windowing into on adapter shared ram. - * i.e. Use LANAID to setup a PnP configuration with 16K RAM. Paging - * will shift this 16K window over the entire available shared RAM. - * - * Changes by Peter De Schrijver (p2@mind.be) : - * + fixed a problem with PCMCIA card removal - * - * Change by Mike Sullivan et al.: - * + added turbo card support. No need to use lanaid to configure - * the adapter into isa compatibility mode. - * - * Changes by Burt Silverman to allow the computer to behave nicely when - * a cable is pulled or not in place, or a PCMCIA card is removed hot. - */ - -/* change the define of IBMTR_DEBUG_MESSAGES to a nonzero value -in the event that chatty debug messages are desired - jjs 12/30/98 */ - -#define IBMTR_DEBUG_MESSAGES 0 - -#include -#include - -#ifdef PCMCIA /* required for ibmtr_cs.c to build */ -#undef MODULE /* yes, really */ -#undef ENABLE_PAGING -#else -#define ENABLE_PAGING 1 -#endif - -/* changes the output format of driver initialization */ -#define TR_VERBOSE 0 - -/* some 95 OS send many non UI frame; this allow removing the warning */ -#define TR_FILTERNONUI 1 - -#include -#include -#include -#include -#include -#include - -#include - -#include - -#define DPRINTK(format, args...) printk("%s: " format, dev->name , ## args) -#define DPRINTD(format, args...) DummyCall("%s: " format, dev->name , ## args) - -/* version and credits */ -#ifndef PCMCIA -static char version[] __devinitdata = - "\nibmtr.c: v1.3.57 8/ 7/94 Peter De Schrijver and Mark Swanson\n" - " v2.1.125 10/20/98 Paul Norton \n" - " v2.2.0 12/30/98 Joel Sloan \n" - " v2.2.1 02/08/00 Mike Sullivan \n" - " v2.2.2 07/27/00 Burt Silverman \n" - " v2.4.0 03/01/01 Mike Sullivan \n"; -#endif - -/* this allows displaying full adapter information */ - -static char *channel_def[] __devinitdata = { "ISA", "MCA", "ISA P&P" }; - -static char pcchannelid[] __devinitdata = { - 0x05, 0x00, 0x04, 0x09, - 0x04, 0x03, 0x04, 0x0f, - 0x03, 0x06, 0x03, 0x01, - 0x03, 0x01, 0x03, 0x00, - 0x03, 0x09, 0x03, 0x09, - 0x03, 0x00, 0x02, 0x00 -}; - -static char mcchannelid[] __devinitdata = { - 0x04, 0x0d, 0x04, 0x01, - 0x05, 0x02, 0x05, 0x03, - 0x03, 0x06, 0x03, 0x03, - 0x05, 0x08, 0x03, 0x04, - 0x03, 0x05, 0x03, 0x01, - 0x03, 0x08, 0x02, 0x00 -}; - -static char __devinit *adapter_def(char type) -{ - switch (type) { - case 0xF: return "PC Adapter | PC Adapter II | Adapter/A"; - case 0xE: return "16/4 Adapter | 16/4 Adapter/A (long)"; - case 0xD: return "16/4 Adapter/A (short) | 16/4 ISA-16 Adapter"; - case 0xC: return "Auto 16/4 Adapter"; - default: return "adapter (unknown type)"; - } -}; - -#define TRC_INIT 0x01 /* Trace initialization & PROBEs */ -#define TRC_INITV 0x02 /* verbose init trace points */ -static unsigned char ibmtr_debug_trace = 0; - -static int ibmtr_probe1(struct net_device *dev, int ioaddr); -static unsigned char get_sram_size(struct tok_info *adapt_info); -static int trdev_init(struct net_device *dev); -static int tok_open(struct net_device *dev); -static int tok_init_card(struct net_device *dev); -static void tok_open_adapter(unsigned long dev_addr); -static void open_sap(unsigned char type, struct net_device *dev); -static void tok_set_multicast_list(struct net_device *dev); -static netdev_tx_t tok_send_packet(struct sk_buff *skb, - struct net_device *dev); -static int tok_close(struct net_device *dev); -static irqreturn_t tok_interrupt(int irq, void *dev_id); -static void initial_tok_int(struct net_device *dev); -static void tr_tx(struct net_device *dev); -static void tr_rx(struct net_device *dev); -static void ibmtr_reset_timer(struct timer_list*tmr,struct net_device *dev); -static void tok_rerun(unsigned long dev_addr); -static void ibmtr_readlog(struct net_device *dev); -static int ibmtr_change_mtu(struct net_device *dev, int mtu); -static void find_turbo_adapters(int *iolist); - -static int ibmtr_portlist[IBMTR_MAX_ADAPTERS+1] __devinitdata = { - 0xa20, 0xa24, 0, 0, 0 -}; -static int __devinitdata turbo_io[IBMTR_MAX_ADAPTERS] = {0}; -static int __devinitdata turbo_irq[IBMTR_MAX_ADAPTERS] = {0}; -static int __devinitdata turbo_searched = 0; - -#ifndef PCMCIA -static __u32 ibmtr_mem_base __devinitdata = 0xd0000; -#endif - -static void __devinit PrtChanID(char *pcid, short stride) -{ - short i, j; - for (i = 0, j = 0; i < 24; i++, j += stride) - printk("%1x", ((int) pcid[j]) & 0x0f); - printk("\n"); -} - -static void __devinit HWPrtChanID(void __iomem *pcid, short stride) -{ - short i, j; - for (i = 0, j = 0; i < 24; i++, j += stride) - printk("%1x", ((int) readb(pcid + j)) & 0x0f); - printk("\n"); -} - -/* We have to ioremap every checked address, because isa_readb is - * going away. - */ - -static void __devinit find_turbo_adapters(int *iolist) -{ - int ram_addr; - int index=0; - void __iomem *chanid; - int found_turbo=0; - unsigned char *tchanid, ctemp; - int i, j; - unsigned long jif; - void __iomem *ram_mapped ; - - if (turbo_searched == 1) return; - turbo_searched=1; - for (ram_addr=0xC0000; ram_addr < 0xE0000; ram_addr+=0x2000) { - - __u32 intf_tbl=0; - - found_turbo=1; - ram_mapped = ioremap((u32)ram_addr,0x1fff) ; - if (ram_mapped==NULL) - continue ; - chanid=(CHANNEL_ID + ram_mapped); - tchanid=pcchannelid; - ctemp=readb(chanid) & 0x0f; - if (ctemp != *tchanid) continue; - for (i=2,j=1; i<=46; i=i+2,j++) { - if ((readb(chanid+i) & 0x0f) != tchanid[j]){ - found_turbo=0; - break; - } - } - if (!found_turbo) continue; - - writeb(0x90, ram_mapped+0x1E01); - for(i=2; i<0x0f; i++) { - writeb(0x00, ram_mapped+0x1E01+i); - } - writeb(0x00, ram_mapped+0x1E01); - for(jif=jiffies+TR_BUSY_INTERVAL; time_before_eq(jiffies,jif);); - intf_tbl=ntohs(readw(ram_mapped+ACA_OFFSET+ACA_RW+WRBR_EVEN)); - if (intf_tbl) { -#if IBMTR_DEBUG_MESSAGES - printk("ibmtr::find_turbo_adapters, Turbo found at " - "ram_addr %x\n",ram_addr); - printk("ibmtr::find_turbo_adapters, interface_table "); - for(i=0; i<6; i++) { - printk("%x:",readb(ram_addr+intf_tbl+i)); - } - printk("\n"); -#endif - turbo_io[index]=ntohs(readw(ram_mapped+intf_tbl+4)); - turbo_irq[index]=readb(ram_mapped+intf_tbl+3); - outb(0, turbo_io[index] + ADAPTRESET); - for(jif=jiffies+TR_RST_TIME;time_before_eq(jiffies,jif);); - outb(0, turbo_io[index] + ADAPTRESETREL); - index++; - continue; - } -#if IBMTR_DEBUG_MESSAGES - printk("ibmtr::find_turbo_adapters, ibmtr card found at" - " %x but not a Turbo model\n",ram_addr); -#endif - iounmap(ram_mapped) ; - } /* for */ - for(i=0; ibase_addr) { - outb(0,dev->base_addr+ADAPTRESET); - - schedule_timeout_uninterruptible(TR_RST_TIME); /* wait 50ms */ - - outb(0,dev->base_addr+ADAPTRESETREL); - } - -#ifndef PCMCIA - free_irq(dev->irq, dev); - release_region(dev->base_addr, IBMTR_IO_EXTENT); - - { - struct tok_info *ti = netdev_priv(dev); - iounmap(ti->mmio); - iounmap(ti->sram_virt); - } -#endif -} - -/**************************************************************************** - * ibmtr_probe(): Routine specified in the network device structure - * to probe for an IBM Token Ring Adapter. Routine outline: - * I. Interrogate hardware to determine if an adapter exists - * and what the speeds and feeds are - * II. Setup data structures to control execution based upon - * adapter characteristics. - * - * We expect ibmtr_probe to be called once for each device entry - * which references it. - ****************************************************************************/ - -static int __devinit ibmtr_probe(struct net_device *dev) -{ - int i; - int base_addr = dev->base_addr; - - if (base_addr && base_addr <= 0x1ff) /* Don't probe at all. */ - return -ENXIO; - if (base_addr > 0x1ff) { /* Check a single specified location. */ - if (!ibmtr_probe1(dev, base_addr)) return 0; - return -ENODEV; - } - find_turbo_adapters(ibmtr_portlist); - for (i = 0; ibmtr_portlist[i]; i++) { - int ioaddr = ibmtr_portlist[i]; - - if (!ibmtr_probe1(dev, ioaddr)) return 0; - } - return -ENODEV; -} - -int __devinit ibmtr_probe_card(struct net_device *dev) -{ - int err = ibmtr_probe(dev); - if (!err) { - err = register_netdev(dev); - if (err) - ibmtr_cleanup_card(dev); - } - return err; -} - -/*****************************************************************************/ - -static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr) -{ - - unsigned char segment, intr=0, irq=0, i, j, cardpresent=NOTOK, temp=0; - void __iomem * t_mmio = NULL; - struct tok_info *ti = netdev_priv(dev); - void __iomem *cd_chanid; - unsigned char *tchanid, ctemp; -#ifndef PCMCIA - unsigned char t_irq=0; - unsigned long timeout; - static int version_printed; -#endif - - /* Query the adapter PIO base port which will return - * indication of where MMIO was placed. We also have a - * coded interrupt number. - */ - segment = inb(PIOaddr); - if (segment < 0x40 || segment > 0xe0) { - /* Out of range values so we'll assume non-existent IO device - * but this is not necessarily a problem, esp if a turbo - * adapter is being used. */ -#if IBMTR_DEBUG_MESSAGES - DPRINTK("ibmtr_probe1(): unhappy that inb(0x%X) == 0x%X, " - "Hardware Problem?\n",PIOaddr,segment); -#endif - return -ENODEV; - } - /* - * Compute the linear base address of the MMIO area - * as LINUX doesn't care about segments - */ - t_mmio = ioremap(((__u32) (segment & 0xfc) << 11) + 0x80000,2048); - if (!t_mmio) { - DPRINTK("Cannot remap mmiobase memory area") ; - return -ENODEV ; - } - intr = segment & 0x03; /* low bits is coded interrupt # */ - if (ibmtr_debug_trace & TRC_INIT) - DPRINTK("PIOaddr: %4hx seg/intr: %2x mmio base: %p intr: %d\n" - , PIOaddr, (int) segment, t_mmio, (int) intr); - - /* - * Now we will compare expected 'channelid' strings with - * what we is there to learn of ISA/MCA or not TR card - */ -#ifdef PCMCIA - iounmap(t_mmio); - t_mmio = ti->mmio; /*BMS to get virtual address */ - irq = ti->irq; /*BMS to display the irq! */ -#endif - cd_chanid = (CHANNEL_ID + t_mmio); /* for efficiency */ - tchanid = pcchannelid; - cardpresent = TR_ISA; /* try ISA */ - - /* Suboptimize knowing first byte different */ - ctemp = readb(cd_chanid) & 0x0f; - if (ctemp != *tchanid) { /* NOT ISA card, try MCA */ - tchanid = mcchannelid; - cardpresent = TR_MCA; - if (ctemp != *tchanid) /* Neither ISA nor MCA */ - cardpresent = NOTOK; - } - if (cardpresent != NOTOK) { - /* Know presumed type, try rest of ID */ - for (i = 2, j = 1; i <= 46; i = i + 2, j++) { - if( (readb(cd_chanid+i)&0x0f) == tchanid[j]) continue; - /* match failed, not TR card */ - cardpresent = NOTOK; - break; - } - } - /* - * If we have an ISA board check for the ISA P&P version, - * as it has different IRQ settings - */ - if (cardpresent == TR_ISA && (readb(AIPFID + t_mmio) == 0x0e)) - cardpresent = TR_ISAPNP; - if (cardpresent == NOTOK) { /* "channel_id" did not match, report */ - if (!(ibmtr_debug_trace & TRC_INIT)) { -#ifndef PCMCIA - iounmap(t_mmio); -#endif - return -ENODEV; - } - DPRINTK( "Channel ID string not found for PIOaddr: %4hx\n", - PIOaddr); - DPRINTK("Expected for ISA: "); - PrtChanID(pcchannelid, 1); - DPRINTK(" found: "); -/* BMS Note that this can be misleading, when hardware is flaky, because you - are reading it a second time here. So with my flaky hardware, I'll see my- - self in this block, with the HW ID matching the ISA ID exactly! */ - HWPrtChanID(cd_chanid, 2); - DPRINTK("Expected for MCA: "); - PrtChanID(mcchannelid, 1); - } - /* Now, setup some of the pl0 buffers for this driver.. */ - /* If called from PCMCIA, it is already set up, so no need to - waste the memory, just use the existing structure */ -#ifndef PCMCIA - ti->mmio = t_mmio; - for (i = 0; i < IBMTR_MAX_ADAPTERS; i++) { - if (turbo_io[i] != PIOaddr) - continue; -#if IBMTR_DEBUG_MESSAGES - printk("ibmtr::tr_probe1, setting PIOaddr %x to Turbo\n", - PIOaddr); -#endif - ti->turbo = 1; - t_irq = turbo_irq[i]; - } -#endif /* !PCMCIA */ - ti->readlog_pending = 0; - init_waitqueue_head(&ti->wait_for_reset); - - /* if PCMCIA, the card can be recognized as either TR_ISA or TR_ISAPNP - * depending which card is inserted. */ - -#ifndef PCMCIA - switch (cardpresent) { - case TR_ISA: - if (intr == 0) irq = 9; /* irq2 really is irq9 */ - if (intr == 1) irq = 3; - if (intr == 2) irq = 6; - if (intr == 3) irq = 7; - ti->adapter_int_enable = PIOaddr + ADAPTINTREL; - break; - case TR_MCA: - if (intr == 0) irq = 9; - if (intr == 1) irq = 3; - if (intr == 2) irq = 10; - if (intr == 3) irq = 11; - ti->global_int_enable = 0; - ti->adapter_int_enable = 0; - ti->sram_phys=(__u32)(inb(PIOaddr+ADAPTRESETREL) & 0xfe) << 12; - break; - case TR_ISAPNP: - if (!t_irq) { - if (intr == 0) irq = 9; - if (intr == 1) irq = 3; - if (intr == 2) irq = 10; - if (intr == 3) irq = 11; - } else - irq=t_irq; - timeout = jiffies + TR_SPIN_INTERVAL; - while (!readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)){ - if (!time_after(jiffies, timeout)) continue; - DPRINTK( "Hardware timeout during initialization.\n"); - iounmap(t_mmio); - return -ENODEV; - } - ti->sram_phys = - ((__u32)readb(ti->mmio+ACA_OFFSET+ACA_RW+RRR_EVEN)<<12); - ti->adapter_int_enable = PIOaddr + ADAPTINTREL; - break; - } /*end switch (cardpresent) */ -#endif /*not PCMCIA */ - - if (ibmtr_debug_trace & TRC_INIT) { /* just report int */ - DPRINTK("irq=%d", irq); - printk(", sram_phys=0x%x", ti->sram_phys); - if(ibmtr_debug_trace&TRC_INITV){ /* full chat in verbose only */ - DPRINTK(", ti->mmio=%p", ti->mmio); - printk(", segment=%02X", segment); - } - printk(".\n"); - } - - /* Get hw address of token ring card */ - j = 0; - for (i = 0; i < 0x18; i = i + 2) { - /* technical reference states to do this */ - temp = readb(ti->mmio + AIP + i) & 0x0f; - ti->hw_address[j] = temp; - if (j & 1) - dev->dev_addr[(j / 2)] = - ti->hw_address[j]+ (ti->hw_address[j - 1] << 4); - ++j; - } - /* get Adapter type: 'F' = Adapter/A, 'E' = 16/4 Adapter II,... */ - ti->adapter_type = readb(ti->mmio + AIPADAPTYPE); - - /* get Data Rate: F=4Mb, E=16Mb, D=4Mb & 16Mb ?? */ - ti->data_rate = readb(ti->mmio + AIPDATARATE); - - /* Get Early Token Release support?: F=no, E=4Mb, D=16Mb, C=4&16Mb */ - ti->token_release = readb(ti->mmio + AIPEARLYTOKEN); - - /* How much shared RAM is on adapter ? */ - if (ti->turbo) { - ti->avail_shared_ram=127; - } else { - ti->avail_shared_ram = get_sram_size(ti);/*in 512 byte units */ - } - /* We need to set or do a bunch of work here based on previous results*/ - /* Support paging? What sizes?: F=no, E=16k, D=32k, C=16 & 32k */ - ti->shared_ram_paging = readb(ti->mmio + AIPSHRAMPAGE); - - /* Available DHB 4Mb size: F=2048, E=4096, D=4464 */ - switch (readb(ti->mmio + AIP4MBDHB)) { - case 0xe: ti->dhb_size4mb = 4096; break; - case 0xd: ti->dhb_size4mb = 4464; break; - default: ti->dhb_size4mb = 2048; break; - } - - /* Available DHB 16Mb size: F=2048, E=4096, D=8192, C=16384, B=17960 */ - switch (readb(ti->mmio + AIP16MBDHB)) { - case 0xe: ti->dhb_size16mb = 4096; break; - case 0xd: ti->dhb_size16mb = 8192; break; - case 0xc: ti->dhb_size16mb = 16384; break; - case 0xb: ti->dhb_size16mb = 17960; break; - default: ti->dhb_size16mb = 2048; break; - } - - /* We must figure out how much shared memory space this adapter - * will occupy so that if there are two adapters we can fit both - * in. Given a choice, we will limit this adapter to 32K. The - * maximum space will will use for two adapters is 64K so if the - * adapter we are working on demands 64K (it also doesn't support - * paging), then only one adapter can be supported. - */ - - /* - * determine how much of total RAM is mapped into PC space - */ - ti->mapped_ram_size= /*sixteen to onehundredtwentyeight 512byte blocks*/ - 1<< ((readb(ti->mmio+ACA_OFFSET+ACA_RW+RRR_ODD) >> 2 & 0x03) + 4); - ti->page_mask = 0; - if (ti->turbo) ti->page_mask=0xf0; - else if (ti->shared_ram_paging == 0xf); /* No paging in adapter */ - else { -#ifdef ENABLE_PAGING - unsigned char pg_size = 0; - /* BMS: page size: PCMCIA, use configuration register; - ISAPNP, use LANAIDC config tool from www.ibm.com */ - switch (ti->shared_ram_paging) { - case 0xf: - break; - case 0xe: - ti->page_mask = (ti->mapped_ram_size == 32) ? 0xc0 : 0; - pg_size = 32; /* 16KB page size */ - break; - case 0xd: - ti->page_mask = (ti->mapped_ram_size == 64) ? 0x80 : 0; - pg_size = 64; /* 32KB page size */ - break; - case 0xc: - switch (ti->mapped_ram_size) { - case 32: - ti->page_mask = 0xc0; - pg_size = 32; - break; - case 64: - ti->page_mask = 0x80; - pg_size = 64; - break; - } - break; - default: - DPRINTK("Unknown shared ram paging info %01X\n", - ti->shared_ram_paging); - iounmap(t_mmio); - return -ENODEV; - break; - } /*end switch shared_ram_paging */ - - if (ibmtr_debug_trace & TRC_INIT) - DPRINTK("Shared RAM paging code: %02X, " - "mapped RAM size: %dK, shared RAM size: %dK, " - "page mask: %02X\n:", - ti->shared_ram_paging, ti->mapped_ram_size / 2, - ti->avail_shared_ram / 2, ti->page_mask); -#endif /*ENABLE_PAGING */ - } - -#ifndef PCMCIA - /* finish figuring the shared RAM address */ - if (cardpresent == TR_ISA) { - static const __u32 ram_bndry_mask[] = { - 0xffffe000, 0xffffc000, 0xffff8000, 0xffff0000 - }; - __u32 new_base, rrr_32, chk_base, rbm; - - rrr_32=readb(ti->mmio+ACA_OFFSET+ACA_RW+RRR_ODD) >> 2 & 0x03; - rbm = ram_bndry_mask[rrr_32]; - new_base = (ibmtr_mem_base + (~rbm)) & rbm;/* up to boundary */ - chk_base = new_base + (ti->mapped_ram_size << 9); - if (chk_base > (ibmtr_mem_base + IBMTR_SHARED_RAM_SIZE)) { - DPRINTK("Shared RAM for this adapter (%05x) exceeds " - "driver limit (%05x), adapter not started.\n", - chk_base, ibmtr_mem_base + IBMTR_SHARED_RAM_SIZE); - iounmap(t_mmio); - return -ENODEV; - } else { /* seems cool, record what we have figured out */ - ti->sram_base = new_base >> 12; - ibmtr_mem_base = chk_base; - } - } - else ti->sram_base = ti->sram_phys >> 12; - - /* The PCMCIA has already got the interrupt line and the io port, - so no chance of anybody else getting it - MLP */ - if (request_irq(dev->irq = irq, tok_interrupt, 0, "ibmtr", dev) != 0) { - DPRINTK("Could not grab irq %d. Halting Token Ring driver.\n", - irq); - iounmap(t_mmio); - return -ENODEV; - } - /*?? Now, allocate some of the PIO PORTs for this driver.. */ - /* record PIOaddr range as busy */ - if (!request_region(PIOaddr, IBMTR_IO_EXTENT, "ibmtr")) { - DPRINTK("Could not grab PIO range. Halting driver.\n"); - free_irq(dev->irq, dev); - iounmap(t_mmio); - return -EBUSY; - } - - if (!version_printed++) { - printk(version); - } -#endif /* !PCMCIA */ - DPRINTK("%s %s found\n", - channel_def[cardpresent - 1], adapter_def(ti->adapter_type)); - DPRINTK("using irq %d, PIOaddr %hx, %dK shared RAM.\n", - irq, PIOaddr, ti->mapped_ram_size / 2); - DPRINTK("Hardware address : %pM\n", dev->dev_addr); - if (ti->page_mask) - DPRINTK("Shared RAM paging enabled. " - "Page size: %uK Shared Ram size %dK\n", - ((ti->page_mask^0xff)+1) >>2, ti->avail_shared_ram / 2); - else - DPRINTK("Shared RAM paging disabled. ti->page_mask %x\n", - ti->page_mask); - - /* Calculate the maximum DHB we can use */ - /* two cases where avail_shared_ram doesn't equal mapped_ram_size: - 1. avail_shared_ram is 127 but mapped_ram_size is 128 (typical) - 2. user has configured adapter for less than avail_shared_ram - but is not using paging (she should use paging, I believe) - */ - if (!ti->page_mask) { - ti->avail_shared_ram= - min(ti->mapped_ram_size,ti->avail_shared_ram); - } - - switch (ti->avail_shared_ram) { - case 16: /* 8KB shared RAM */ - ti->dhb_size4mb = min(ti->dhb_size4mb, (unsigned short)2048); - ti->rbuf_len4 = 1032; - ti->rbuf_cnt4=2; - ti->dhb_size16mb = min(ti->dhb_size16mb, (unsigned short)2048); - ti->rbuf_len16 = 1032; - ti->rbuf_cnt16=2; - break; - case 32: /* 16KB shared RAM */ - ti->dhb_size4mb = min(ti->dhb_size4mb, (unsigned short)4464); - ti->rbuf_len4 = 1032; - ti->rbuf_cnt4=4; - ti->dhb_size16mb = min(ti->dhb_size16mb, (unsigned short)4096); - ti->rbuf_len16 = 1032; /*1024 usable */ - ti->rbuf_cnt16=4; - break; - case 64: /* 32KB shared RAM */ - ti->dhb_size4mb = min(ti->dhb_size4mb, (unsigned short)4464); - ti->rbuf_len4 = 1032; - ti->rbuf_cnt4=6; - ti->dhb_size16mb = min(ti->dhb_size16mb, (unsigned short)10240); - ti->rbuf_len16 = 1032; - ti->rbuf_cnt16=6; - break; - case 127: /* 63.5KB shared RAM */ - ti->dhb_size4mb = min(ti->dhb_size4mb, (unsigned short)4464); - ti->rbuf_len4 = 1032; - ti->rbuf_cnt4=6; - ti->dhb_size16mb = min(ti->dhb_size16mb, (unsigned short)16384); - ti->rbuf_len16 = 1032; - ti->rbuf_cnt16=16; - break; - case 128: /* 64KB shared RAM */ - ti->dhb_size4mb = min(ti->dhb_size4mb, (unsigned short)4464); - ti->rbuf_len4 = 1032; - ti->rbuf_cnt4=6; - ti->dhb_size16mb = min(ti->dhb_size16mb, (unsigned short)17960); - ti->rbuf_len16 = 1032; - ti->rbuf_cnt16=16; - break; - default: - ti->dhb_size4mb = 2048; - ti->rbuf_len4 = 1032; - ti->rbuf_cnt4=2; - ti->dhb_size16mb = 2048; - ti->rbuf_len16 = 1032; - ti->rbuf_cnt16=2; - break; - } - /* this formula is not smart enough for the paging case - ti->rbuf_cnt = (ti->avail_shared_ram * BLOCKSZ - ADAPT_PRIVATE - - ARBLENGTH - SSBLENGTH - DLC_MAX_SAP * SAPLENGTH - - DLC_MAX_STA * STALENGTH - ti->dhb_sizemb * NUM_DHB - - SRBLENGTH - ASBLENGTH) / ti->rbuf_len; - */ - ti->maxmtu16 = (ti->rbuf_len16 - 8) * ti->rbuf_cnt16 - TR_HLEN; - ti->maxmtu4 = (ti->rbuf_len4 - 8) * ti->rbuf_cnt4 - TR_HLEN; - /*BMS assuming 18 bytes of Routing Information (usually works) */ - DPRINTK("Maximum Receive Internet Protocol MTU 16Mbps: %d, 4Mbps: %d\n", - ti->maxmtu16, ti->maxmtu4); - - dev->base_addr = PIOaddr; /* set the value for device */ - dev->mem_start = ti->sram_base << 12; - dev->mem_end = dev->mem_start + (ti->mapped_ram_size << 9) - 1; - trdev_init(dev); - return 0; /* Return 0 to indicate we have found a Token Ring card. */ -} /*ibmtr_probe1() */ - -/*****************************************************************************/ - -/* query the adapter for the size of shared RAM */ -/* the function returns the RAM size in units of 512 bytes */ - -static unsigned char __devinit get_sram_size(struct tok_info *adapt_info) -{ - unsigned char avail_sram_code; - static unsigned char size_code[] = { 0, 16, 32, 64, 127, 128 }; - /* Adapter gives - 'F' -- use RRR bits 3,2 - 'E' -- 8kb 'D' -- 16kb - 'C' -- 32kb 'A' -- 64KB - 'B' - 64KB less 512 bytes at top - (WARNING ... must zero top bytes in INIT */ - - avail_sram_code = 0xf - readb(adapt_info->mmio + AIPAVAILSHRAM); - if (avail_sram_code) return size_code[avail_sram_code]; - else /* for code 'F', must compute size from RRR(3,2) bits */ - return 1 << - ((readb(adapt_info->mmio+ACA_OFFSET+ACA_RW+RRR_ODD)>>2&3)+4); -} - -/*****************************************************************************/ - -static const struct net_device_ops trdev_netdev_ops = { - .ndo_open = tok_open, - .ndo_stop = tok_close, - .ndo_start_xmit = tok_send_packet, - .ndo_set_rx_mode = tok_set_multicast_list, - .ndo_change_mtu = ibmtr_change_mtu, -}; - -static int __devinit trdev_init(struct net_device *dev) -{ - struct tok_info *ti = netdev_priv(dev); - - SET_PAGE(ti->srb_page); - ti->open_failure = NO ; - dev->netdev_ops = &trdev_netdev_ops; - - return 0; -} - -/*****************************************************************************/ - -static int tok_init_card(struct net_device *dev) -{ - struct tok_info *ti; - short PIOaddr; - unsigned long i; - - PIOaddr = dev->base_addr; - ti = netdev_priv(dev); - /* Special processing for first interrupt after reset */ - ti->do_tok_int = FIRST_INT; - /* Reset adapter */ - writeb(~INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN); - outb(0, PIOaddr + ADAPTRESET); - - schedule_timeout_uninterruptible(TR_RST_TIME); /* wait 50ms */ - - outb(0, PIOaddr + ADAPTRESETREL); -#ifdef ENABLE_PAGING - if (ti->page_mask) - writeb(SRPR_ENABLE_PAGING,ti->mmio+ACA_OFFSET+ACA_RW+SRPR_EVEN); -#endif - writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); - i = sleep_on_timeout(&ti->wait_for_reset, 4 * HZ); - return i? 0 : -EAGAIN; -} - -/*****************************************************************************/ -static int tok_open(struct net_device *dev) -{ - struct tok_info *ti = netdev_priv(dev); - int i; - - /*the case we were left in a failure state during a previous open */ - if (ti->open_failure == YES) { - DPRINTK("Last time you were disconnected, how about now?\n"); - printk("You can't insert with an ICS connector half-cocked.\n"); - } - - ti->open_status = CLOSED; /* CLOSED or OPEN */ - ti->sap_status = CLOSED; /* CLOSED or OPEN */ - ti->open_failure = NO; /* NO or YES */ - ti->open_mode = MANUAL; /* MANUAL or AUTOMATIC */ - - ti->sram_phys &= ~1; /* to reverse what we do in tok_close */ - /* init the spinlock */ - spin_lock_init(&ti->lock); - init_timer(&ti->tr_timer); - - i = tok_init_card(dev); - if (i) return i; - - while (1){ - tok_open_adapter((unsigned long) dev); - i= interruptible_sleep_on_timeout(&ti->wait_for_reset, 25 * HZ); - /* sig catch: estimate opening adapter takes more than .5 sec*/ - if (i>(245*HZ)/10) break; /* fancier than if (i==25*HZ) */ - if (i==0) break; - if (ti->open_status == OPEN && ti->sap_status==OPEN) { - netif_start_queue(dev); - DPRINTK("Adapter is up and running\n"); - return 0; - } - i=schedule_timeout_interruptible(TR_RETRY_INTERVAL); - /* wait 30 seconds */ - if(i!=0) break; /*prob. a signal, like the i>24*HZ case above */ - } - outb(0, dev->base_addr + ADAPTRESET);/* kill pending interrupts*/ - DPRINTK("TERMINATED via signal\n"); /*BMS useful */ - return -EAGAIN; -} - -/*****************************************************************************/ - -#define COMMAND_OFST 0 -#define OPEN_OPTIONS_OFST 8 -#define NUM_RCV_BUF_OFST 24 -#define RCV_BUF_LEN_OFST 26 -#define DHB_LENGTH_OFST 28 -#define NUM_DHB_OFST 30 -#define DLC_MAX_SAP_OFST 32 -#define DLC_MAX_STA_OFST 33 - -static void tok_open_adapter(unsigned long dev_addr) -{ - struct net_device *dev = (struct net_device *) dev_addr; - struct tok_info *ti; - int i; - - ti = netdev_priv(dev); - SET_PAGE(ti->init_srb_page); - writeb(~SRB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD); - for (i = 0; i < sizeof(struct dir_open_adapter); i++) - writeb(0, ti->init_srb + i); - writeb(DIR_OPEN_ADAPTER, ti->init_srb + COMMAND_OFST); - writew(htons(OPEN_PASS_BCON_MAC), ti->init_srb + OPEN_OPTIONS_OFST); - if (ti->ring_speed == 16) { - writew(htons(ti->dhb_size16mb), ti->init_srb + DHB_LENGTH_OFST); - writew(htons(ti->rbuf_cnt16), ti->init_srb + NUM_RCV_BUF_OFST); - writew(htons(ti->rbuf_len16), ti->init_srb + RCV_BUF_LEN_OFST); - } else { - writew(htons(ti->dhb_size4mb), ti->init_srb + DHB_LENGTH_OFST); - writew(htons(ti->rbuf_cnt4), ti->init_srb + NUM_RCV_BUF_OFST); - writew(htons(ti->rbuf_len4), ti->init_srb + RCV_BUF_LEN_OFST); - } - writeb(NUM_DHB, /* always 2 */ ti->init_srb + NUM_DHB_OFST); - writeb(DLC_MAX_SAP, ti->init_srb + DLC_MAX_SAP_OFST); - writeb(DLC_MAX_STA, ti->init_srb + DLC_MAX_STA_OFST); - ti->srb = ti->init_srb; /* We use this one in the interrupt handler */ - ti->srb_page = ti->init_srb_page; - DPRINTK("Opening adapter: Xmit bfrs: %d X %d, Rcv bfrs: %d X %d\n", - readb(ti->init_srb + NUM_DHB_OFST), - ntohs(readw(ti->init_srb + DHB_LENGTH_OFST)), - ntohs(readw(ti->init_srb + NUM_RCV_BUF_OFST)), - ntohs(readw(ti->init_srb + RCV_BUF_LEN_OFST))); - writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); - writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); -} - -/*****************************************************************************/ - -static void open_sap(unsigned char type, struct net_device *dev) -{ - int i; - struct tok_info *ti = netdev_priv(dev); - - SET_PAGE(ti->srb_page); - for (i = 0; i < sizeof(struct dlc_open_sap); i++) - writeb(0, ti->srb + i); - -#define MAX_I_FIELD_OFST 14 -#define SAP_VALUE_OFST 16 -#define SAP_OPTIONS_OFST 17 -#define STATION_COUNT_OFST 18 - - writeb(DLC_OPEN_SAP, ti->srb + COMMAND_OFST); - writew(htons(MAX_I_FIELD), ti->srb + MAX_I_FIELD_OFST); - writeb(SAP_OPEN_IND_SAP | SAP_OPEN_PRIORITY, ti->srb+ SAP_OPTIONS_OFST); - writeb(SAP_OPEN_STATION_CNT, ti->srb + STATION_COUNT_OFST); - writeb(type, ti->srb + SAP_VALUE_OFST); - writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); -} - - -/*****************************************************************************/ - -static void tok_set_multicast_list(struct net_device *dev) -{ - struct tok_info *ti = netdev_priv(dev); - struct netdev_hw_addr *ha; - unsigned char address[4]; - - int i; - - /*BMS the next line is CRUCIAL or you may be sad when you */ - /*BMS ifconfig tr down or hot unplug a PCMCIA card ??hownowbrowncow*/ - if (/*BMSHELPdev->start == 0 ||*/ ti->open_status != OPEN) return; - address[0] = address[1] = address[2] = address[3] = 0; - netdev_for_each_mc_addr(ha, dev) { - address[0] |= ha->addr[2]; - address[1] |= ha->addr[3]; - address[2] |= ha->addr[4]; - address[3] |= ha->addr[5]; - } - SET_PAGE(ti->srb_page); - for (i = 0; i < sizeof(struct srb_set_funct_addr); i++) - writeb(0, ti->srb + i); - -#define FUNCT_ADDRESS_OFST 6 - - writeb(DIR_SET_FUNC_ADDR, ti->srb + COMMAND_OFST); - for (i = 0; i < 4; i++) - writeb(address[i], ti->srb + FUNCT_ADDRESS_OFST + i); - writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); -#if TR_VERBOSE - DPRINTK("Setting functional address: "); - for (i=0;i<4;i++) printk("%02X ", address[i]); - printk("\n"); -#endif -} - -/*****************************************************************************/ - -#define STATION_ID_OFST 4 - -static netdev_tx_t tok_send_packet(struct sk_buff *skb, - struct net_device *dev) -{ - struct tok_info *ti; - unsigned long flags; - ti = netdev_priv(dev); - - netif_stop_queue(dev); - - /* lock against other CPUs */ - spin_lock_irqsave(&(ti->lock), flags); - - /* Save skb; we'll need it when the adapter asks for the data */ - ti->current_skb = skb; - SET_PAGE(ti->srb_page); - writeb(XMIT_UI_FRAME, ti->srb + COMMAND_OFST); - writew(ti->exsap_station_id, ti->srb + STATION_ID_OFST); - writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); - spin_unlock_irqrestore(&(ti->lock), flags); - return NETDEV_TX_OK; -} - -/*****************************************************************************/ - -static int tok_close(struct net_device *dev) -{ - struct tok_info *ti = netdev_priv(dev); - - /* Important for PCMCIA hot unplug, otherwise, we'll pull the card, */ - /* unloading the module from memory, and then if a timer pops, ouch */ - del_timer_sync(&ti->tr_timer); - outb(0, dev->base_addr + ADAPTRESET); - ti->sram_phys |= 1; - ti->open_status = CLOSED; - - netif_stop_queue(dev); - DPRINTK("Adapter is closed.\n"); - return 0; -} - -/*****************************************************************************/ - -#define RETCODE_OFST 2 -#define OPEN_ERROR_CODE_OFST 6 -#define ASB_ADDRESS_OFST 8 -#define SRB_ADDRESS_OFST 10 -#define ARB_ADDRESS_OFST 12 -#define SSB_ADDRESS_OFST 14 - -static char *printphase[]= {"Lobe media test","Physical insertion", - "Address verification","Roll call poll","Request Parameters"}; -static char *printerror[]={"Function failure","Signal loss","Reserved", - "Frequency error","Timeout","Ring failure","Ring beaconing", - "Duplicate node address", - "Parameter request-retry count exceeded","Remove received", - "IMPL force received","Duplicate modifier", - "No monitor detected","Monitor contention failed for RPL"}; - -static void __iomem *map_address(struct tok_info *ti, unsigned index, __u8 *page) -{ - if (ti->page_mask) { - *page = (index >> 8) & ti->page_mask; - index &= ~(ti->page_mask << 8); - } - return ti->sram_virt + index; -} - -static void dir_open_adapter (struct net_device *dev) -{ - struct tok_info *ti = netdev_priv(dev); - unsigned char ret_code; - __u16 err; - - ti->srb = map_address(ti, - ntohs(readw(ti->init_srb + SRB_ADDRESS_OFST)), - &ti->srb_page); - ti->ssb = map_address(ti, - ntohs(readw(ti->init_srb + SSB_ADDRESS_OFST)), - &ti->ssb_page); - ti->arb = map_address(ti, - ntohs(readw(ti->init_srb + ARB_ADDRESS_OFST)), - &ti->arb_page); - ti->asb = map_address(ti, - ntohs(readw(ti->init_srb + ASB_ADDRESS_OFST)), - &ti->asb_page); - ti->current_skb = NULL; - ret_code = readb(ti->init_srb + RETCODE_OFST); - err = ntohs(readw(ti->init_srb + OPEN_ERROR_CODE_OFST)); - if (!ret_code) { - ti->open_status = OPEN; /* TR adapter is now available */ - if (ti->open_mode == AUTOMATIC) { - DPRINTK("Adapter reopened.\n"); - } - writeb(~SRB_RESP_INT, ti->mmio+ACA_OFFSET+ACA_RESET+ISRP_ODD); - open_sap(EXTENDED_SAP, dev); - return; - } - ti->open_failure = YES; - if (ret_code == 7){ - if (err == 0x24) { - if (!ti->auto_speedsave) { - DPRINTK("Open failed: Adapter speed must match " - "ring speed if Automatic Ring Speed Save is " - "disabled.\n"); - ti->open_action = FAIL; - }else - DPRINTK("Retrying open to adjust to " - "ring speed, "); - } else if (err == 0x2d) { - DPRINTK("Physical Insertion: No Monitor Detected, "); - printk("retrying after %ds delay...\n", - TR_RETRY_INTERVAL/HZ); - } else if (err == 0x11) { - DPRINTK("Lobe Media Function Failure (0x11), "); - printk(" retrying after %ds delay...\n", - TR_RETRY_INTERVAL/HZ); - } else { - char **prphase = printphase; - char **prerror = printerror; - int pnr = err / 16 - 1; - int enr = err % 16 - 1; - DPRINTK("TR Adapter misc open failure, error code = "); - if (pnr < 0 || pnr >= ARRAY_SIZE(printphase) || - enr < 0 || - enr >= ARRAY_SIZE(printerror)) - printk("0x%x, invalid Phase/Error.", err); - else - printk("0x%x, Phase: %s, Error: %s\n", err, - prphase[pnr], prerror[enr]); - printk(" retrying after %ds delay...\n", - TR_RETRY_INTERVAL/HZ); - } - } else DPRINTK("open failed: ret_code = %02X..., ", ret_code); - if (ti->open_action != FAIL) { - if (ti->open_mode==AUTOMATIC){ - ti->open_action = REOPEN; - ibmtr_reset_timer(&(ti->tr_timer), dev); - return; - } - wake_up(&ti->wait_for_reset); - return; - } - DPRINTK("FAILURE, CAPUT\n"); -} - -/******************************************************************************/ - -static irqreturn_t tok_interrupt(int irq, void *dev_id) -{ - unsigned char status; - /* unsigned char status_even ; */ - struct tok_info *ti; - struct net_device *dev; -#ifdef ENABLE_PAGING - unsigned char save_srpr; -#endif - - dev = dev_id; -#if TR_VERBOSE - DPRINTK("Int from tok_driver, dev : %p irq%d\n", dev,irq); -#endif - ti = netdev_priv(dev); - if (ti->sram_phys & 1) - return IRQ_NONE; /* PCMCIA card extraction flag */ - spin_lock(&(ti->lock)); -#ifdef ENABLE_PAGING - save_srpr = readb(ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN); -#endif - - /* Disable interrupts till processing is finished */ - writeb((~INT_ENABLE), ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN); - - /* Reset interrupt for ISA boards */ - if (ti->adapter_int_enable) - outb(0, ti->adapter_int_enable); - else /* used for PCMCIA cards */ - outb(0, ti->global_int_enable); - if (ti->do_tok_int == FIRST_INT){ - initial_tok_int(dev); -#ifdef ENABLE_PAGING - writeb(save_srpr, ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN); -#endif - spin_unlock(&(ti->lock)); - return IRQ_HANDLED; - } - /* Begin interrupt handler HERE inline to avoid the extra - levels of logic and call depth for the original solution. */ - status = readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_ODD); - /*BMSstatus_even = readb (ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN) */ - /*BMSdebugprintk("tok_interrupt: ISRP_ODD = 0x%x ISRP_EVEN = 0x%x\n", */ - /*BMS status,status_even); */ - - if (status & ADAP_CHK_INT) { - int i; - void __iomem *check_reason; - __u8 check_reason_page = 0; - check_reason = map_address(ti, - ntohs(readw(ti->mmio+ ACA_OFFSET+ACA_RW + WWCR_EVEN)), - &check_reason_page); - SET_PAGE(check_reason_page); - - DPRINTK("Adapter check interrupt\n"); - DPRINTK("8 reason bytes follow: "); - for (i = 0; i < 8; i++, check_reason++) - printk("%02X ", (int) readb(check_reason)); - printk("\n"); - writeb(~ADAP_CHK_INT, ti->mmio+ ACA_OFFSET+ACA_RESET+ ISRP_ODD); - status = readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRA_EVEN); - DPRINTK("ISRA_EVEN == 0x02%x\n",status); - ti->open_status = CLOSED; - ti->sap_status = CLOSED; - ti->open_mode = AUTOMATIC; - netif_carrier_off(dev); - netif_stop_queue(dev); - ti->open_action = RESTART; - outb(0, dev->base_addr + ADAPTRESET); - ibmtr_reset_timer(&(ti->tr_timer), dev);/*BMS try to reopen*/ - spin_unlock(&(ti->lock)); - return IRQ_HANDLED; - } - if (readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN) - & (TCR_INT | ERR_INT | ACCESS_INT)) { - DPRINTK("adapter error: ISRP_EVEN : %02x\n", - (int)readb(ti->mmio+ ACA_OFFSET + ACA_RW + ISRP_EVEN)); - writeb(~(TCR_INT | ERR_INT | ACCESS_INT), - ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN); - status= readb(ti->mmio+ ACA_OFFSET + ACA_RW + ISRA_EVEN);/*BMS*/ - DPRINTK("ISRA_EVEN == 0x02%x\n",status);/*BMS*/ - writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); -#ifdef ENABLE_PAGING - writeb(save_srpr, ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN); -#endif - spin_unlock(&(ti->lock)); - return IRQ_HANDLED; - } - if (status & SRB_RESP_INT) { /* SRB response */ - SET_PAGE(ti->srb_page); -#if TR_VERBOSE - DPRINTK("SRB resp: cmd=%02X rsp=%02X\n", - readb(ti->srb), readb(ti->srb + RETCODE_OFST)); -#endif - switch (readb(ti->srb)) { /* SRB command check */ - case XMIT_DIR_FRAME:{ - unsigned char xmit_ret_code; - xmit_ret_code = readb(ti->srb + RETCODE_OFST); - if (xmit_ret_code == 0xff) break; - DPRINTK("error on xmit_dir_frame request: %02X\n", - xmit_ret_code); - if (ti->current_skb) { - dev_kfree_skb_irq(ti->current_skb); - ti->current_skb = NULL; - } - /*dev->tbusy = 0;*/ - netif_wake_queue(dev); - if (ti->readlog_pending) - ibmtr_readlog(dev); - break; - } - case XMIT_UI_FRAME:{ - unsigned char xmit_ret_code; - - xmit_ret_code = readb(ti->srb + RETCODE_OFST); - if (xmit_ret_code == 0xff) break; - DPRINTK("error on xmit_ui_frame request: %02X\n", - xmit_ret_code); - if (ti->current_skb) { - dev_kfree_skb_irq(ti->current_skb); - ti->current_skb = NULL; - } - netif_wake_queue(dev); - if (ti->readlog_pending) - ibmtr_readlog(dev); - break; - } - case DIR_OPEN_ADAPTER: - dir_open_adapter(dev); - break; - case DLC_OPEN_SAP: - if (readb(ti->srb + RETCODE_OFST)) { - DPRINTK("open_sap failed: ret_code = %02X, " - "retrying\n", - (int) readb(ti->srb + RETCODE_OFST)); - ti->open_action = REOPEN; - ibmtr_reset_timer(&(ti->tr_timer), dev); - break; - } - ti->exsap_station_id = readw(ti->srb + STATION_ID_OFST); - ti->sap_status = OPEN;/* TR adapter is now available */ - if (ti->open_mode==MANUAL){ - wake_up(&ti->wait_for_reset); - break; - } - netif_wake_queue(dev); - netif_carrier_on(dev); - break; - case DIR_INTERRUPT: - case DIR_MOD_OPEN_PARAMS: - case DIR_SET_GRP_ADDR: - case DIR_SET_FUNC_ADDR: - case DLC_CLOSE_SAP: - if (readb(ti->srb + RETCODE_OFST)) - DPRINTK("error on %02X: %02X\n", - (int) readb(ti->srb + COMMAND_OFST), - (int) readb(ti->srb + RETCODE_OFST)); - break; - case DIR_READ_LOG: - if (readb(ti->srb + RETCODE_OFST)){ - DPRINTK("error on dir_read_log: %02X\n", - (int) readb(ti->srb + RETCODE_OFST)); - netif_wake_queue(dev); - break; - } -#if IBMTR_DEBUG_MESSAGES - -#define LINE_ERRORS_OFST 0 -#define INTERNAL_ERRORS_OFST 1 -#define BURST_ERRORS_OFST 2 -#define AC_ERRORS_OFST 3 -#define ABORT_DELIMITERS_OFST 4 -#define LOST_FRAMES_OFST 6 -#define RECV_CONGEST_COUNT_OFST 7 -#define FRAME_COPIED_ERRORS_OFST 8 -#define FREQUENCY_ERRORS_OFST 9 -#define TOKEN_ERRORS_OFST 10 - - DPRINTK("Line errors %02X, Internal errors %02X, " - "Burst errors %02X\n" "A/C errors %02X, " - "Abort delimiters %02X, Lost frames %02X\n" - "Receive congestion count %02X, " - "Frame copied errors %02X\nFrequency errors %02X, " - "Token errors %02X\n", - (int) readb(ti->srb + LINE_ERRORS_OFST), - (int) readb(ti->srb + INTERNAL_ERRORS_OFST), - (int) readb(ti->srb + BURST_ERRORS_OFST), - (int) readb(ti->srb + AC_ERRORS_OFST), - (int) readb(ti->srb + ABORT_DELIMITERS_OFST), - (int) readb(ti->srb + LOST_FRAMES_OFST), - (int) readb(ti->srb + RECV_CONGEST_COUNT_OFST), - (int) readb(ti->srb + FRAME_COPIED_ERRORS_OFST), - (int) readb(ti->srb + FREQUENCY_ERRORS_OFST), - (int) readb(ti->srb + TOKEN_ERRORS_OFST)); -#endif - netif_wake_queue(dev); - break; - default: - DPRINTK("Unknown command %02X encountered\n", - (int) readb(ti->srb)); - } /* end switch SRB command check */ - writeb(~SRB_RESP_INT, ti->mmio+ ACA_OFFSET+ACA_RESET+ ISRP_ODD); - } /* if SRB response */ - if (status & ASB_FREE_INT) { /* ASB response */ - SET_PAGE(ti->asb_page); -#if TR_VERBOSE - DPRINTK("ASB resp: cmd=%02X\n", readb(ti->asb)); -#endif - - switch (readb(ti->asb)) { /* ASB command check */ - case REC_DATA: - case XMIT_UI_FRAME: - case XMIT_DIR_FRAME: - break; - default: - DPRINTK("unknown command in asb %02X\n", - (int) readb(ti->asb)); - } /* switch ASB command check */ - if (readb(ti->asb + 2) != 0xff) /* checks ret_code */ - DPRINTK("ASB error %02X in cmd %02X\n", - (int) readb(ti->asb + 2), (int) readb(ti->asb)); - writeb(~ASB_FREE_INT, ti->mmio+ ACA_OFFSET+ACA_RESET+ ISRP_ODD); - } /* if ASB response */ - -#define STATUS_OFST 6 -#define NETW_STATUS_OFST 6 - - if (status & ARB_CMD_INT) { /* ARB response */ - SET_PAGE(ti->arb_page); -#if TR_VERBOSE - DPRINTK("ARB resp: cmd=%02X\n", readb(ti->arb)); -#endif - - switch (readb(ti->arb)) { /* ARB command check */ - case DLC_STATUS: - DPRINTK("DLC_STATUS new status: %02X on station %02X\n", - ntohs(readw(ti->arb + STATUS_OFST)), - ntohs(readw(ti->arb+ STATION_ID_OFST))); - break; - case REC_DATA: - tr_rx(dev); - break; - case RING_STAT_CHANGE:{ - unsigned short ring_status; - ring_status= ntohs(readw(ti->arb + NETW_STATUS_OFST)); - if (ibmtr_debug_trace & TRC_INIT) - DPRINTK("Ring Status Change...(0x%x)\n", - ring_status); - if(ring_status& (REMOVE_RECV|AUTO_REMOVAL|LOBE_FAULT)){ - netif_stop_queue(dev); - netif_carrier_off(dev); - DPRINTK("Remove received, or Auto-removal error" - ", or Lobe fault\n"); - DPRINTK("We'll try to reopen the closed adapter" - " after a %d second delay.\n", - TR_RETRY_INTERVAL/HZ); - /*I was confused: I saw the TR reopening but */ - /*forgot:with an RJ45 in an RJ45/ICS adapter */ - /*but adapter not in the ring, the TR will */ - /* open, and then soon close and come here. */ - ti->open_mode = AUTOMATIC; - ti->open_status = CLOSED; /*12/2000 BMS*/ - ti->open_action = REOPEN; - ibmtr_reset_timer(&(ti->tr_timer), dev); - } else if (ring_status & LOG_OVERFLOW) { - if(netif_queue_stopped(dev)) - ti->readlog_pending = 1; - else - ibmtr_readlog(dev); - } - break; - } - case XMIT_DATA_REQ: - tr_tx(dev); - break; - default: - DPRINTK("Unknown command %02X in arb\n", - (int) readb(ti->arb)); - break; - } /* switch ARB command check */ - writeb(~ARB_CMD_INT, ti->mmio+ ACA_OFFSET+ACA_RESET + ISRP_ODD); - writeb(ARB_FREE, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); - } /* if ARB response */ - if (status & SSB_RESP_INT) { /* SSB response */ - unsigned char retcode; - SET_PAGE(ti->ssb_page); -#if TR_VERBOSE - DPRINTK("SSB resp: cmd=%02X rsp=%02X\n", - readb(ti->ssb), readb(ti->ssb + 2)); -#endif - - switch (readb(ti->ssb)) { /* SSB command check */ - case XMIT_DIR_FRAME: - case XMIT_UI_FRAME: - retcode = readb(ti->ssb + 2); - if (retcode && (retcode != 0x22))/* checks ret_code */ - DPRINTK("xmit ret_code: %02X xmit error code: " - "%02X\n", - (int)retcode, (int)readb(ti->ssb + 6)); - else - dev->stats.tx_packets++; - break; - case XMIT_XID_CMD: - DPRINTK("xmit xid ret_code: %02X\n", - (int) readb(ti->ssb + 2)); - default: - DPRINTK("Unknown command %02X in ssb\n", - (int) readb(ti->ssb)); - } /* SSB command check */ - writeb(~SSB_RESP_INT, ti->mmio+ ACA_OFFSET+ACA_RESET+ ISRP_ODD); - writeb(SSB_FREE, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); - } /* if SSB response */ -#ifdef ENABLE_PAGING - writeb(save_srpr, ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN); -#endif - writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); - spin_unlock(&(ti->lock)); - return IRQ_HANDLED; -} /*tok_interrupt */ - -/*****************************************************************************/ - -#define INIT_STATUS_OFST 1 -#define INIT_STATUS_2_OFST 2 -#define ENCODED_ADDRESS_OFST 8 - -static void initial_tok_int(struct net_device *dev) -{ - - __u32 encoded_addr, hw_encoded_addr; - struct tok_info *ti; - unsigned char init_status; /*BMS 12/2000*/ - - ti = netdev_priv(dev); - - ti->do_tok_int = NOT_FIRST; - - /* we assign the shared-ram address for ISA devices */ - writeb(ti->sram_base, ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN); -#ifndef PCMCIA - ti->sram_virt = ioremap(((__u32)ti->sram_base << 12), ti->avail_shared_ram); -#endif - ti->init_srb = map_address(ti, - ntohs(readw(ti->mmio + ACA_OFFSET + WRBR_EVEN)), - &ti->init_srb_page); - if (ti->page_mask && ti->avail_shared_ram == 127) { - void __iomem *last_512; - __u8 last_512_page=0; - int i; - last_512 = map_address(ti, 0xfe00, &last_512_page); - /* initialize high section of ram (if necessary) */ - SET_PAGE(last_512_page); - for (i = 0; i < 512; i++) - writeb(0, last_512 + i); - } - SET_PAGE(ti->init_srb_page); - -#if TR_VERBOSE - { - int i; - - DPRINTK("ti->init_srb_page=0x%x\n", ti->init_srb_page); - DPRINTK("init_srb(%p):", ti->init_srb ); - for (i = 0; i < 20; i++) - printk("%02X ", (int) readb(ti->init_srb + i)); - printk("\n"); - } -#endif - - hw_encoded_addr = readw(ti->init_srb + ENCODED_ADDRESS_OFST); - encoded_addr = ntohs(hw_encoded_addr); - init_status= /*BMS 12/2000 check for shallow mode possibility (Turbo)*/ - readb(ti->init_srb+offsetof(struct srb_init_response,init_status)); - /*printk("Initial interrupt: init_status= 0x%02x\n",init_status);*/ - ti->ring_speed = init_status & 0x01 ? 16 : 4; - DPRINTK("Initial interrupt : %d Mbps, shared RAM base %08x.\n", - ti->ring_speed, (unsigned int)dev->mem_start); - ti->auto_speedsave = (readb(ti->init_srb+INIT_STATUS_2_OFST) & 4) != 0; - - if (ti->open_mode == MANUAL) wake_up(&ti->wait_for_reset); - else tok_open_adapter((unsigned long)dev); - -} /*initial_tok_int() */ - -/*****************************************************************************/ - -#define CMD_CORRELATE_OFST 1 -#define DHB_ADDRESS_OFST 6 - -#define FRAME_LENGTH_OFST 6 -#define HEADER_LENGTH_OFST 8 -#define RSAP_VALUE_OFST 9 - -static void tr_tx(struct net_device *dev) -{ - struct tok_info *ti = netdev_priv(dev); - struct trh_hdr *trhdr = (struct trh_hdr *) ti->current_skb->data; - unsigned int hdr_len; - __u32 dhb=0,dhb_base; - void __iomem *dhbuf = NULL; - unsigned char xmit_command; - int i,dhb_len=0x4000,src_len,src_offset; - struct trllc *llc; - struct srb_xmit xsrb; - __u8 dhb_page = 0; - __u8 llc_ssap; - - SET_PAGE(ti->asb_page); - - if (readb(ti->asb+RETCODE_OFST) != 0xFF) DPRINTK("ASB not free !!!\n"); - - /* in providing the transmit interrupts, is telling us it is ready for - data and providing a shared memory address for us to stuff with data. - Here we compute the effective address where we will place data. - */ - SET_PAGE(ti->arb_page); - dhb=dhb_base=ntohs(readw(ti->arb + DHB_ADDRESS_OFST)); - if (ti->page_mask) { - dhb_page = (dhb_base >> 8) & ti->page_mask; - dhb=dhb_base & ~(ti->page_mask << 8); - } - dhbuf = ti->sram_virt + dhb; - - /* Figure out the size of the 802.5 header */ - if (!(trhdr->saddr[0] & 0x80)) /* RIF present? */ - hdr_len = sizeof(struct trh_hdr) - TR_MAXRIFLEN; - else - hdr_len = ((ntohs(trhdr->rcf) & TR_RCF_LEN_MASK) >> 8) - + sizeof(struct trh_hdr) - TR_MAXRIFLEN; - - llc = (struct trllc *) (ti->current_skb->data + hdr_len); - - llc_ssap = llc->ssap; - SET_PAGE(ti->srb_page); - memcpy_fromio(&xsrb, ti->srb, sizeof(xsrb)); - SET_PAGE(ti->asb_page); - xmit_command = xsrb.command; - - writeb(xmit_command, ti->asb + COMMAND_OFST); - writew(xsrb.station_id, ti->asb + STATION_ID_OFST); - writeb(llc_ssap, ti->asb + RSAP_VALUE_OFST); - writeb(xsrb.cmd_corr, ti->asb + CMD_CORRELATE_OFST); - writeb(0, ti->asb + RETCODE_OFST); - if ((xmit_command == XMIT_XID_CMD) || (xmit_command == XMIT_TEST_CMD)) { - writew(htons(0x11), ti->asb + FRAME_LENGTH_OFST); - writeb(0x0e, ti->asb + HEADER_LENGTH_OFST); - SET_PAGE(dhb_page); - writeb(AC, dhbuf); - writeb(LLC_FRAME, dhbuf + 1); - for (i = 0; i < TR_ALEN; i++) - writeb((int) 0x0FF, dhbuf + i + 2); - for (i = 0; i < TR_ALEN; i++) - writeb(0, dhbuf + i + TR_ALEN + 2); - writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); - return; - } - /* - * the token ring packet is copied from sk_buff to the adapter - * buffer identified in the command data received with the interrupt. - */ - writeb(hdr_len, ti->asb + HEADER_LENGTH_OFST); - writew(htons(ti->current_skb->len), ti->asb + FRAME_LENGTH_OFST); - src_len=ti->current_skb->len; - src_offset=0; - dhb=dhb_base; - while(1) { - if (ti->page_mask) { - dhb_page=(dhb >> 8) & ti->page_mask; - dhb=dhb & ~(ti->page_mask << 8); - dhb_len=0x4000-dhb; /* remaining size of this page */ - } - dhbuf = ti->sram_virt + dhb; - SET_PAGE(dhb_page); - if (src_len > dhb_len) { - memcpy_toio(dhbuf,&ti->current_skb->data[src_offset], - dhb_len); - src_len -= dhb_len; - src_offset += dhb_len; - dhb_base+=dhb_len; - dhb=dhb_base; - continue; - } - memcpy_toio(dhbuf, &ti->current_skb->data[src_offset], src_len); - break; - } - writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); - dev->stats.tx_bytes += ti->current_skb->len; - dev_kfree_skb_irq(ti->current_skb); - ti->current_skb = NULL; - netif_wake_queue(dev); - if (ti->readlog_pending) - ibmtr_readlog(dev); -} /*tr_tx */ - -/*****************************************************************************/ - - -#define RECEIVE_BUFFER_OFST 6 -#define LAN_HDR_LENGTH_OFST 8 -#define DLC_HDR_LENGTH_OFST 9 - -#define DSAP_OFST 0 -#define SSAP_OFST 1 -#define LLC_OFST 2 -#define PROTID_OFST 3 -#define ETHERTYPE_OFST 6 - -static void tr_rx(struct net_device *dev) -{ - struct tok_info *ti = netdev_priv(dev); - __u32 rbuffer; - void __iomem *rbuf, *rbufdata, *llc; - __u8 rbuffer_page = 0; - unsigned char *data; - unsigned int rbuffer_len, lan_hdr_len, hdr_len, ip_len, length; - unsigned char dlc_hdr_len; - struct sk_buff *skb; - unsigned int skb_size = 0; - int IPv4_p = 0; - unsigned int chksum = 0; - struct iphdr *iph; - struct arb_rec_req rarb; - - SET_PAGE(ti->arb_page); - memcpy_fromio(&rarb, ti->arb, sizeof(rarb)); - rbuffer = ntohs(rarb.rec_buf_addr) ; - rbuf = map_address(ti, rbuffer, &rbuffer_page); - - SET_PAGE(ti->asb_page); - - if (readb(ti->asb + RETCODE_OFST) !=0xFF) DPRINTK("ASB not free !!!\n"); - - writeb(REC_DATA, ti->asb + COMMAND_OFST); - writew(rarb.station_id, ti->asb + STATION_ID_OFST); - writew(rarb.rec_buf_addr, ti->asb + RECEIVE_BUFFER_OFST); - - lan_hdr_len = rarb.lan_hdr_len; - if (lan_hdr_len > sizeof(struct trh_hdr)) { - DPRINTK("Linux cannot handle greater than 18 bytes RIF\n"); - return; - } /*BMS I added this above just to be very safe */ - dlc_hdr_len = readb(ti->arb + DLC_HDR_LENGTH_OFST); - hdr_len = lan_hdr_len + sizeof(struct trllc) + sizeof(struct iphdr); - - SET_PAGE(rbuffer_page); - llc = rbuf + offsetof(struct rec_buf, data) + lan_hdr_len; - -#if TR_VERBOSE - DPRINTK("offsetof data: %02X lan_hdr_len: %02X\n", - (__u32) offsetof(struct rec_buf, data), (unsigned int) lan_hdr_len); - DPRINTK("llc: %08X rec_buf_addr: %04X dev->mem_start: %lX\n", - llc, ntohs(rarb.rec_buf_addr), dev->mem_start); - DPRINTK("dsap: %02X, ssap: %02X, llc: %02X, protid: %02X%02X%02X, " - "ethertype: %04X\n", - (int) readb(llc + DSAP_OFST), (int) readb(llc + SSAP_OFST), - (int) readb(llc + LLC_OFST), (int) readb(llc + PROTID_OFST), - (int) readb(llc+PROTID_OFST+1),(int)readb(llc+PROTID_OFST + 2), - (int) ntohs(readw(llc + ETHERTYPE_OFST))); -#endif - if (readb(llc + offsetof(struct trllc, llc)) != UI_CMD) { - SET_PAGE(ti->asb_page); - writeb(DATA_LOST, ti->asb + RETCODE_OFST); - dev->stats.rx_dropped++; - writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); - return; - } - length = ntohs(rarb.frame_len); - if (readb(llc + DSAP_OFST) == EXTENDED_SAP && - readb(llc + SSAP_OFST) == EXTENDED_SAP && - length >= hdr_len) IPv4_p = 1; -#if TR_VERBOSE -#define SADDR_OFST 8 -#define DADDR_OFST 2 - - if (!IPv4_p) { - - void __iomem *trhhdr = rbuf + offsetof(struct rec_buf, data); - u8 saddr[6]; - u8 daddr[6]; - int i; - for (i = 0 ; i < 6 ; i++) - saddr[i] = readb(trhhdr + SADDR_OFST + i); - for (i = 0 ; i < 6 ; i++) - daddr[i] = readb(trhhdr + DADDR_OFST + i); - DPRINTK("Probably non-IP frame received.\n"); - DPRINTK("ssap: %02X dsap: %02X " - "saddr: %pM daddr: %pM\n", - readb(llc + SSAP_OFST), readb(llc + DSAP_OFST), - saddr, daddr); - } -#endif - - /*BMS handle the case she comes in with few hops but leaves with many */ - skb_size=length-lan_hdr_len+sizeof(struct trh_hdr)+sizeof(struct trllc); - - if (!(skb = dev_alloc_skb(skb_size))) { - DPRINTK("out of memory. frame dropped.\n"); - dev->stats.rx_dropped++; - SET_PAGE(ti->asb_page); - writeb(DATA_LOST, ti->asb + offsetof(struct asb_rec, ret_code)); - writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); - return; - } - /*BMS again, if she comes in with few but leaves with many */ - skb_reserve(skb, sizeof(struct trh_hdr) - lan_hdr_len); - skb_put(skb, length); - data = skb->data; - rbuffer_len = ntohs(readw(rbuf + offsetof(struct rec_buf, buf_len))); - rbufdata = rbuf + offsetof(struct rec_buf, data); - - if (IPv4_p) { - /* Copy the headers without checksumming */ - memcpy_fromio(data, rbufdata, hdr_len); - - /* Watch for padded packets and bogons */ - iph= (struct iphdr *)(data+ lan_hdr_len + sizeof(struct trllc)); - ip_len = ntohs(iph->tot_len) - sizeof(struct iphdr); - length -= hdr_len; - if ((ip_len <= length) && (ip_len > 7)) - length = ip_len; - data += hdr_len; - rbuffer_len -= hdr_len; - rbufdata += hdr_len; - } - /* Copy the payload... */ -#define BUFFER_POINTER_OFST 2 -#define BUFFER_LENGTH_OFST 6 - for (;;) { - if (ibmtr_debug_trace&TRC_INITV && length < rbuffer_len) - DPRINTK("CURIOUS, length=%d < rbuffer_len=%d\n", - length,rbuffer_len); - if (IPv4_p) - chksum=csum_partial_copy_nocheck((void*)rbufdata, - data,lengthasb_page); - writeb(0, ti->asb + offsetof(struct asb_rec, ret_code)); - - writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); - - dev->stats.rx_bytes += skb->len; - dev->stats.rx_packets++; - - skb->protocol = tr_type_trans(skb, dev); - if (IPv4_p) { - skb->csum = chksum; - skb->ip_summed = CHECKSUM_COMPLETE; - } - netif_rx(skb); -} /*tr_rx */ - -/*****************************************************************************/ - -static void ibmtr_reset_timer(struct timer_list *tmr, struct net_device *dev) -{ - tmr->expires = jiffies + TR_RETRY_INTERVAL; - tmr->data = (unsigned long) dev; - tmr->function = tok_rerun; - init_timer(tmr); - add_timer(tmr); -} - -/*****************************************************************************/ - -static void tok_rerun(unsigned long dev_addr) -{ - struct net_device *dev = (struct net_device *)dev_addr; - struct tok_info *ti = netdev_priv(dev); - - if ( ti->open_action == RESTART){ - ti->do_tok_int = FIRST_INT; - outb(0, dev->base_addr + ADAPTRESETREL); -#ifdef ENABLE_PAGING - if (ti->page_mask) - writeb(SRPR_ENABLE_PAGING, - ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN); -#endif - - writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); - } else - tok_open_adapter(dev_addr); -} - -/*****************************************************************************/ - -static void ibmtr_readlog(struct net_device *dev) -{ - struct tok_info *ti; - - ti = netdev_priv(dev); - - ti->readlog_pending = 0; - SET_PAGE(ti->srb_page); - writeb(DIR_READ_LOG, ti->srb); - writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); - writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); - - netif_stop_queue(dev); - -} - -/*****************************************************************************/ - -static int ibmtr_change_mtu(struct net_device *dev, int mtu) -{ - struct tok_info *ti = netdev_priv(dev); - - if (ti->ring_speed == 16 && mtu > ti->maxmtu16) - return -EINVAL; - if (ti->ring_speed == 4 && mtu > ti->maxmtu4) - return -EINVAL; - dev->mtu = mtu; - return 0; -} - -/*****************************************************************************/ -#ifdef MODULE - -/* 3COM 3C619C supports 8 interrupts, 32 I/O ports */ -static struct net_device *dev_ibmtr[IBMTR_MAX_ADAPTERS]; -static int io[IBMTR_MAX_ADAPTERS] = { 0xa20, 0xa24 }; -static int irq[IBMTR_MAX_ADAPTERS]; -static int mem[IBMTR_MAX_ADAPTERS]; - -MODULE_LICENSE("GPL"); - -module_param_array(io, int, NULL, 0); -module_param_array(irq, int, NULL, 0); -module_param_array(mem, int, NULL, 0); - -static int __init ibmtr_init(void) -{ - int i; - int count=0; - - find_turbo_adapters(io); - - for (i = 0; i < IBMTR_MAX_ADAPTERS && io[i]; i++) { - struct net_device *dev; - irq[i] = 0; - mem[i] = 0; - dev = alloc_trdev(sizeof(struct tok_info)); - if (dev == NULL) { - if (i == 0) - return -ENOMEM; - break; - } - dev->base_addr = io[i]; - dev->irq = irq[i]; - dev->mem_start = mem[i]; - - if (ibmtr_probe_card(dev)) { - free_netdev(dev); - continue; - } - dev_ibmtr[i] = dev; - count++; - } - if (count) return 0; - printk("ibmtr: register_netdev() returned non-zero.\n"); - return -EIO; -} -module_init(ibmtr_init); - -static void __exit ibmtr_cleanup(void) -{ - int i; - - for (i = 0; i < IBMTR_MAX_ADAPTERS; i++){ - if (!dev_ibmtr[i]) - continue; - unregister_netdev(dev_ibmtr[i]); - ibmtr_cleanup_card(dev_ibmtr[i]); - free_netdev(dev_ibmtr[i]); - } -} -module_exit(ibmtr_cleanup); -#endif diff --git a/trunk/drivers/net/tokenring/ibmtr_cs.c b/trunk/drivers/net/tokenring/ibmtr_cs.c deleted file mode 100644 index 356e28e4881b..000000000000 --- a/trunk/drivers/net/tokenring/ibmtr_cs.c +++ /dev/null @@ -1,370 +0,0 @@ -/*====================================================================== - - A PCMCIA token-ring driver for IBM-based cards - - This driver supports the IBM PCMCIA Token-Ring Card. - Written by Steve Kipisz, kipisz@vnet.ibm.com or - bungy@ibm.net - - Written 1995,1996. - - This code is based on pcnet_cs.c from David Hinds. - - V2.2.0 February 1999 - Mike Phillips phillim@amtrak.com - - Linux V2.2.x presented significant changes to the underlying - ibmtr.c code. Mainly the code became a lot more organized and - modular. - - This caused the old PCMCIA Token Ring driver to give up and go - home early. Instead of just patching the old code to make it - work, the PCMCIA code has been streamlined, updated and possibly - improved. - - This code now only contains code required for the Card Services. - All we do here is set the card up enough so that the real ibmtr.c - driver can find it and work with it properly. - - i.e. We set up the io port, irq, mmio memory and shared ram - memory. This enables ibmtr_probe in ibmtr.c to find the card and - configure it as though it was a normal ISA and/or PnP card. - - CHANGES - - v2.2.5 April 1999 Mike Phillips (phillim@amtrak.com) - Obscure bug fix, required changed to ibmtr.c not ibmtr_cs.c - - v2.2.7 May 1999 Mike Phillips (phillim@amtrak.com) - Updated to version 2.2.7 to match the first version of the kernel - that the modification to ibmtr.c were incorporated into. - - v2.2.17 July 2000 Burt Silverman (burts@us.ibm.com) - Address translation feature of PCMCIA controller is usable so - memory windows can be placed in High memory (meaning above - 0xFFFFF.) - -======================================================================*/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#define PCMCIA -#include "ibmtr.c" - - -/*====================================================================*/ - -/* Parameters that can be set with 'insmod' */ - -/* MMIO base address */ -static u_long mmiobase = 0xce000; - -/* SRAM base address */ -static u_long srambase = 0xd0000; - -/* SRAM size 8,16,32,64 */ -static u_long sramsize = 64; - -/* Ringspeed 4,16 */ -static int ringspeed = 16; - -module_param(mmiobase, ulong, 0); -module_param(srambase, ulong, 0); -module_param(sramsize, ulong, 0); -module_param(ringspeed, int, 0); -MODULE_LICENSE("GPL"); - -/*====================================================================*/ - -static int ibmtr_config(struct pcmcia_device *link); -static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase); -static void ibmtr_release(struct pcmcia_device *link); -static void ibmtr_detach(struct pcmcia_device *p_dev); - -/*====================================================================*/ - -typedef struct ibmtr_dev_t { - struct pcmcia_device *p_dev; - struct net_device *dev; - struct tok_info *ti; -} ibmtr_dev_t; - -static irqreturn_t ibmtr_interrupt(int irq, void *dev_id) { - ibmtr_dev_t *info = dev_id; - struct net_device *dev = info->dev; - return tok_interrupt(irq, dev); -}; - -static int __devinit ibmtr_attach(struct pcmcia_device *link) -{ - ibmtr_dev_t *info; - struct net_device *dev; - - dev_dbg(&link->dev, "ibmtr_attach()\n"); - - /* Create new token-ring device */ - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) return -ENOMEM; - dev = alloc_trdev(sizeof(struct tok_info)); - if (!dev) { - kfree(info); - return -ENOMEM; - } - - info->p_dev = link; - link->priv = info; - info->ti = netdev_priv(dev); - - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - link->resource[0]->end = 4; - link->config_flags |= CONF_ENABLE_IRQ; - link->config_regs = PRESENT_OPTION; - - info->dev = dev; - - return ibmtr_config(link); -} /* ibmtr_attach */ - -static void ibmtr_detach(struct pcmcia_device *link) -{ - struct ibmtr_dev_t *info = link->priv; - struct net_device *dev = info->dev; - struct tok_info *ti = netdev_priv(dev); - - dev_dbg(&link->dev, "ibmtr_detach\n"); - - /* - * When the card removal interrupt hits tok_interrupt(), - * bail out early, so we don't crash the machine - */ - ti->sram_phys |= 1; - - unregister_netdev(dev); - - del_timer_sync(&(ti->tr_timer)); - - ibmtr_release(link); - - free_netdev(dev); - kfree(info); -} /* ibmtr_detach */ - -static int __devinit ibmtr_config(struct pcmcia_device *link) -{ - ibmtr_dev_t *info = link->priv; - struct net_device *dev = info->dev; - struct tok_info *ti = netdev_priv(dev); - int i, ret; - - dev_dbg(&link->dev, "ibmtr_config\n"); - - link->io_lines = 16; - link->config_index = 0x61; - - /* Determine if this is PRIMARY or ALTERNATE. */ - - /* Try PRIMARY card at 0xA20-0xA23 */ - link->resource[0]->start = 0xA20; - i = pcmcia_request_io(link); - if (i != 0) { - /* Couldn't get 0xA20-0xA23. Try ALTERNATE at 0xA24-0xA27. */ - link->resource[0]->start = 0xA24; - ret = pcmcia_request_io(link); - if (ret) - goto failed; - } - dev->base_addr = link->resource[0]->start; - - ret = pcmcia_request_exclusive_irq(link, ibmtr_interrupt); - if (ret) - goto failed; - dev->irq = link->irq; - ti->irq = link->irq; - ti->global_int_enable=GLOBAL_INT_ENABLE+((dev->irq==9) ? 2 : dev->irq); - - /* Allocate the MMIO memory window */ - link->resource[2]->flags |= WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE; - link->resource[2]->flags |= WIN_USE_WAIT; - link->resource[2]->start = 0; - link->resource[2]->end = 0x2000; - ret = pcmcia_request_window(link, link->resource[2], 250); - if (ret) - goto failed; - - ret = pcmcia_map_mem_page(link, link->resource[2], mmiobase); - if (ret) - goto failed; - ti->mmio = ioremap(link->resource[2]->start, - resource_size(link->resource[2])); - - /* Allocate the SRAM memory window */ - link->resource[3]->flags = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE; - link->resource[3]->flags |= WIN_USE_WAIT; - link->resource[3]->start = 0; - link->resource[3]->end = sramsize * 1024; - ret = pcmcia_request_window(link, link->resource[3], 250); - if (ret) - goto failed; - - ret = pcmcia_map_mem_page(link, link->resource[3], srambase); - if (ret) - goto failed; - - ti->sram_base = srambase >> 12; - ti->sram_virt = ioremap(link->resource[3]->start, - resource_size(link->resource[3])); - ti->sram_phys = link->resource[3]->start; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - /* Set up the Token-Ring Controller Configuration Register and - turn on the card. Check the "Local Area Network Credit Card - Adapters Technical Reference" SC30-3585 for this info. */ - ibmtr_hw_setup(dev, mmiobase); - - SET_NETDEV_DEV(dev, &link->dev); - - i = ibmtr_probe_card(dev); - if (i != 0) { - pr_notice("register_netdev() failed\n"); - goto failed; - } - - netdev_info(dev, "port %#3lx, irq %d, mmio %#5lx, sram %#5lx, hwaddr=%pM\n", - dev->base_addr, dev->irq, - (u_long)ti->mmio, (u_long)(ti->sram_base << 12), - dev->dev_addr); - return 0; - -failed: - ibmtr_release(link); - return -ENODEV; -} /* ibmtr_config */ - -static void ibmtr_release(struct pcmcia_device *link) -{ - ibmtr_dev_t *info = link->priv; - struct net_device *dev = info->dev; - - dev_dbg(&link->dev, "ibmtr_release\n"); - - if (link->resource[2]->end) { - struct tok_info *ti = netdev_priv(dev); - iounmap(ti->mmio); - } - pcmcia_disable_device(link); -} - -static int ibmtr_suspend(struct pcmcia_device *link) -{ - ibmtr_dev_t *info = link->priv; - struct net_device *dev = info->dev; - - if (link->open) - netif_device_detach(dev); - - return 0; -} - -static int __devinit ibmtr_resume(struct pcmcia_device *link) -{ - ibmtr_dev_t *info = link->priv; - struct net_device *dev = info->dev; - - if (link->open) { - ibmtr_probe(dev); /* really? */ - netif_device_attach(dev); - } - - return 0; -} - - -/*====================================================================*/ - -static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase) -{ - int i; - - /* Bizarre IBM behavior, there are 16 bits of information we - need to set, but the card only allows us to send 4 bits at a - time. For each byte sent to base_addr, bits 7-4 tell the - card which part of the 16 bits we are setting, bits 3-0 contain - the actual information */ - - /* First nibble provides 4 bits of mmio */ - i = (mmiobase >> 16) & 0x0F; - outb(i, dev->base_addr); - - /* Second nibble provides 3 bits of mmio */ - i = 0x10 | ((mmiobase >> 12) & 0x0E); - outb(i, dev->base_addr); - - /* Third nibble, hard-coded values */ - i = 0x26; - outb(i, dev->base_addr); - - /* Fourth nibble sets shared ram page size */ - - /* 8 = 00, 16 = 01, 32 = 10, 64 = 11 */ - i = (sramsize >> 4) & 0x07; - i = ((i == 4) ? 3 : i) << 2; - i |= 0x30; - - if (ringspeed == 16) - i |= 2; - if (dev->base_addr == 0xA24) - i |= 1; - outb(i, dev->base_addr); - - /* 0x40 will release the card for use */ - outb(0x40, dev->base_addr); -} - -static const struct pcmcia_device_id ibmtr_ids[] = { - PCMCIA_DEVICE_PROD_ID12("3Com", "TokenLink Velocity PC Card", 0x41240e5b, 0x82c3734e), - PCMCIA_DEVICE_PROD_ID12("IBM", "TOKEN RING", 0xb569a6e5, 0xbf8eed47), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, ibmtr_ids); - -static struct pcmcia_driver ibmtr_cs_driver = { - .owner = THIS_MODULE, - .name = "ibmtr_cs", - .probe = ibmtr_attach, - .remove = ibmtr_detach, - .id_table = ibmtr_ids, - .suspend = ibmtr_suspend, - .resume = ibmtr_resume, -}; - -static int __init init_ibmtr_cs(void) -{ - return pcmcia_register_driver(&ibmtr_cs_driver); -} - -static void __exit exit_ibmtr_cs(void) -{ - pcmcia_unregister_driver(&ibmtr_cs_driver); -} - -module_init(init_ibmtr_cs); -module_exit(exit_ibmtr_cs); diff --git a/trunk/drivers/net/tokenring/lanstreamer.c b/trunk/drivers/net/tokenring/lanstreamer.c deleted file mode 100644 index 3e4b4f091113..000000000000 --- a/trunk/drivers/net/tokenring/lanstreamer.c +++ /dev/null @@ -1,1917 +0,0 @@ -/* - * lanstreamer.c -- driver for the IBM Auto LANStreamer PCI Adapter - * - * Written By: Mike Sullivan, IBM Corporation - * - * Copyright (C) 1999 IBM Corporation - * - * Linux driver for IBM PCI tokenring cards based on the LanStreamer MPC - * chipset. - * - * This driver is based on the olympic driver for IBM PCI TokenRing cards (Pit/Pit-Phy/Olympic - * chipsets) written by: - * 1999 Peter De Schrijver All Rights Reserved - * 1999 Mike Phillips (phillim@amtrak.com) - * - * Base Driver Skeleton: - * Written 1993-94 by Donald Becker. - * - * Copyright 1993 United States Government as represented by the - * Director, National Security Agency. - * - * 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. - * - * NO WARRANTY - * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - * solely responsible for determining the appropriateness of using and - * distributing the Program and assumes all risks associated with its - * exercise of rights under this Agreement, including but not limited to - * the risks and costs of program errors, damage to or loss of data, - * programs or equipment, and unavailability or interruption of operations. - * - * DISCLAIMER OF LIABILITY - * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - * - * 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 - * - * - * 12/10/99 - Alpha Release 0.1.0 - * First release to the public - * 03/03/00 - Merged to kernel, indented -kr -i8 -bri0, fixed some missing - * malloc free checks, reviewed code. - * 03/13/00 - Added spinlocks for smp - * 03/08/01 - Added support for module_init() and module_exit() - * 08/15/01 - Added ioctl() functionality for debugging, changed netif_*_queue - * calls and other incorrectness - Kent Yoder - * 11/05/01 - Restructured the interrupt function, added delays, reduced the - * the number of TX descriptors to 1, which together can prevent - * the card from locking up the box - - * 09/27/02 - New PCI interface + bug fix. - - * 11/13/02 - Removed free_irq calls which could cause a hang, added - * netif_carrier_{on|off} - - * - * To Do: - * - * - * If Problems do Occur - * Most problems can be rectified by either closing and opening the interface - * (ifconfig down and up) or rmmod and insmod'ing the driver (a bit difficult - * if compiled into the kernel). - */ - -/* Change STREAMER_DEBUG to 1 to get verbose, and I mean really verbose, messages */ - -#define STREAMER_DEBUG 0 -#define STREAMER_DEBUG_PACKETS 0 - -/* Change STREAMER_NETWORK_MONITOR to receive mac frames through the arb channel. - * Will also create a /proc/net/streamer_tr entry if proc_fs is compiled into the - * kernel. - * Intended to be used to create a ring-error reporting network module - * i.e. it will give you the source address of beaconers on the ring - */ - -#define STREAMER_NETWORK_MONITOR 0 - -/* #define CONFIG_PROC_FS */ - -/* - * Allow or disallow ioctl's for debugging - */ - -#define STREAMER_IOCTL 0 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include "lanstreamer.h" - -#if (BITS_PER_LONG == 64) -#error broken on 64-bit: stores pointer to rx_ring->buffer in 32-bit int -#endif - - -/* I've got to put some intelligence into the version number so that Peter and I know - * which version of the code somebody has got. - * Version Number = a.b.c.d where a.b.c is the level of code and d is the latest author. - * So 0.0.1.pds = Peter, 0.0.1.mlp = Mike - * - * Official releases will only have an a.b.c version number format. - */ - -static char version[] = "LanStreamer.c v0.4.0 03/08/01 - Mike Sullivan\n" - " v0.5.3 11/13/02 - Kent Yoder"; - -static DEFINE_PCI_DEVICE_TABLE(streamer_pci_tbl) = { - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR, PCI_ANY_ID, PCI_ANY_ID,}, - {} /* terminating entry */ -}; -MODULE_DEVICE_TABLE(pci,streamer_pci_tbl); - - -static char *open_maj_error[] = { - "No error", "Lobe Media Test", "Physical Insertion", - "Address Verification", "Neighbor Notification (Ring Poll)", - "Request Parameters", "FDX Registration Request", - "FDX Lobe Media Test", "FDX Duplicate Address Check", - "Unknown stage" -}; - -static char *open_min_error[] = { - "No error", "Function Failure", "Signal Lost", "Wire Fault", - "Ring Speed Mismatch", "Timeout", "Ring Failure", "Ring Beaconing", - "Duplicate Node Address", "Request Parameters", "Remove Received", - "Reserved", "Reserved", "No Monitor Detected for RPL", - "Monitor Contention failer for RPL", "FDX Protocol Error" -}; - -/* Module parameters */ - -/* Ring Speed 0,4,16 - * 0 = Autosense - * 4,16 = Selected speed only, no autosense - * This allows the card to be the first on the ring - * and become the active monitor. - * - * WARNING: Some hubs will allow you to insert - * at the wrong speed - */ - -static int ringspeed[STREAMER_MAX_ADAPTERS] = { 0, }; - -module_param_array(ringspeed, int, NULL, 0); - -/* Packet buffer size */ - -static int pkt_buf_sz[STREAMER_MAX_ADAPTERS] = { 0, }; - -module_param_array(pkt_buf_sz, int, NULL, 0); - -/* Message Level */ - -static int message_level[STREAMER_MAX_ADAPTERS] = { 1, }; - -module_param_array(message_level, int, NULL, 0); - -#if STREAMER_IOCTL -static int streamer_ioctl(struct net_device *, struct ifreq *, int); -#endif - -static int streamer_reset(struct net_device *dev); -static int streamer_open(struct net_device *dev); -static netdev_tx_t streamer_xmit(struct sk_buff *skb, - struct net_device *dev); -static int streamer_close(struct net_device *dev); -static void streamer_set_rx_mode(struct net_device *dev); -static irqreturn_t streamer_interrupt(int irq, void *dev_id); -static int streamer_set_mac_address(struct net_device *dev, void *addr); -static void streamer_arb_cmd(struct net_device *dev); -static int streamer_change_mtu(struct net_device *dev, int mtu); -static void streamer_srb_bh(struct net_device *dev); -static void streamer_asb_bh(struct net_device *dev); -#if STREAMER_NETWORK_MONITOR -#ifdef CONFIG_PROC_FS -static int streamer_proc_info(char *buffer, char **start, off_t offset, - int length, int *eof, void *data); -static int sprintf_info(char *buffer, struct net_device *dev); -struct streamer_private *dev_streamer=NULL; -#endif -#endif - -static const struct net_device_ops streamer_netdev_ops = { - .ndo_open = streamer_open, - .ndo_stop = streamer_close, - .ndo_start_xmit = streamer_xmit, - .ndo_change_mtu = streamer_change_mtu, -#if STREAMER_IOCTL - .ndo_do_ioctl = streamer_ioctl, -#endif - .ndo_set_rx_mode = streamer_set_rx_mode, - .ndo_set_mac_address = streamer_set_mac_address, -}; - -static int __devinit streamer_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct net_device *dev; - struct streamer_private *streamer_priv; - unsigned long pio_start, pio_end, pio_flags, pio_len; - unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; - int rc = 0; - static int card_no=-1; - u16 pcr; - -#if STREAMER_DEBUG - printk("lanstreamer::streamer_init_one, entry pdev %p\n",pdev); -#endif - - card_no++; - dev = alloc_trdev(sizeof(*streamer_priv)); - if (dev==NULL) { - printk(KERN_ERR "lanstreamer: out of memory.\n"); - return -ENOMEM; - } - - streamer_priv = netdev_priv(dev); - -#if STREAMER_NETWORK_MONITOR -#ifdef CONFIG_PROC_FS - if (!dev_streamer) - create_proc_read_entry("streamer_tr", 0, init_net.proc_net, - streamer_proc_info, NULL); - streamer_priv->next = dev_streamer; - dev_streamer = streamer_priv; -#endif -#endif - - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc) { - printk(KERN_ERR "%s: No suitable PCI mapping available.\n", - dev->name); - rc = -ENODEV; - goto err_out; - } - - rc = pci_enable_device(pdev); - if (rc) { - printk(KERN_ERR "lanstreamer: unable to enable pci device\n"); - rc=-EIO; - goto err_out; - } - - pci_set_master(pdev); - - rc = pci_set_mwi(pdev); - if (rc) { - printk(KERN_ERR "lanstreamer: unable to enable MWI on pci device\n"); - goto err_out_disable; - } - - pio_start = pci_resource_start(pdev, 0); - pio_end = pci_resource_end(pdev, 0); - pio_flags = pci_resource_flags(pdev, 0); - pio_len = pci_resource_len(pdev, 0); - - mmio_start = pci_resource_start(pdev, 1); - mmio_end = pci_resource_end(pdev, 1); - mmio_flags = pci_resource_flags(pdev, 1); - mmio_len = pci_resource_len(pdev, 1); - -#if STREAMER_DEBUG - printk("lanstreamer: pio_start %x pio_end %x pio_len %x pio_flags %x\n", - pio_start, pio_end, pio_len, pio_flags); - printk("lanstreamer: mmio_start %x mmio_end %x mmio_len %x mmio_flags %x\n", - mmio_start, mmio_end, mmio_flags, mmio_len); -#endif - - if (!request_region(pio_start, pio_len, "lanstreamer")) { - printk(KERN_ERR "lanstreamer: unable to get pci io addr %lx\n", - pio_start); - rc= -EBUSY; - goto err_out_mwi; - } - - if (!request_mem_region(mmio_start, mmio_len, "lanstreamer")) { - printk(KERN_ERR "lanstreamer: unable to get pci mmio addr %lx\n", - mmio_start); - rc= -EBUSY; - goto err_out_free_pio; - } - - streamer_priv->streamer_mmio=ioremap(mmio_start, mmio_len); - if (streamer_priv->streamer_mmio == NULL) { - printk(KERN_ERR "lanstreamer: unable to remap MMIO %lx\n", - mmio_start); - rc= -EIO; - goto err_out_free_mmio; - } - - init_waitqueue_head(&streamer_priv->srb_wait); - init_waitqueue_head(&streamer_priv->trb_wait); - - dev->netdev_ops = &streamer_netdev_ops; - dev->irq = pdev->irq; - dev->base_addr=pio_start; - SET_NETDEV_DEV(dev, &pdev->dev); - - streamer_priv->streamer_card_name = (char *)pdev->resource[0].name; - streamer_priv->pci_dev = pdev; - - if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000)) - streamer_priv->pkt_buf_sz = PKT_BUF_SZ; - else - streamer_priv->pkt_buf_sz = pkt_buf_sz[card_no]; - - streamer_priv->streamer_ring_speed = ringspeed[card_no]; - streamer_priv->streamer_message_level = message_level[card_no]; - - pci_set_drvdata(pdev, dev); - - spin_lock_init(&streamer_priv->streamer_lock); - - pci_read_config_word (pdev, PCI_COMMAND, &pcr); - pcr |= PCI_COMMAND_SERR; - pci_write_config_word (pdev, PCI_COMMAND, pcr); - - printk("%s\n", version); - printk("%s: %s. I/O at %hx, MMIO at %p, using irq %d\n",dev->name, - streamer_priv->streamer_card_name, - (unsigned int) dev->base_addr, - streamer_priv->streamer_mmio, - dev->irq); - - if (streamer_reset(dev)) - goto err_out_unmap; - - rc = register_netdev(dev); - if (rc) - goto err_out_unmap; - return 0; - -err_out_unmap: - iounmap(streamer_priv->streamer_mmio); -err_out_free_mmio: - release_mem_region(mmio_start, mmio_len); -err_out_free_pio: - release_region(pio_start, pio_len); -err_out_mwi: - pci_clear_mwi(pdev); -err_out_disable: - pci_disable_device(pdev); -err_out: - free_netdev(dev); -#if STREAMER_DEBUG - printk("lanstreamer: Exit error %x\n",rc); -#endif - return rc; -} - -static void __devexit streamer_remove_one(struct pci_dev *pdev) -{ - struct net_device *dev=pci_get_drvdata(pdev); - struct streamer_private *streamer_priv; - -#if STREAMER_DEBUG - printk("lanstreamer::streamer_remove_one entry pdev %p\n",pdev); -#endif - - if (dev == NULL) { - printk(KERN_ERR "lanstreamer::streamer_remove_one, ERROR dev is NULL\n"); - return; - } - - streamer_priv=netdev_priv(dev); - if (streamer_priv == NULL) { - printk(KERN_ERR "lanstreamer::streamer_remove_one, ERROR dev->priv is NULL\n"); - return; - } - -#if STREAMER_NETWORK_MONITOR -#ifdef CONFIG_PROC_FS - { - struct streamer_private **p, **next; - - for (p = &dev_streamer; *p; p = next) { - next = &(*p)->next; - if (*p == streamer_priv) { - *p = *next; - break; - } - } - if (!dev_streamer) - remove_proc_entry("streamer_tr", init_net.proc_net); - } -#endif -#endif - - unregister_netdev(dev); - iounmap(streamer_priv->streamer_mmio); - release_mem_region(pci_resource_start(pdev, 1), pci_resource_len(pdev,1)); - release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev,0)); - pci_clear_mwi(pdev); - pci_disable_device(pdev); - free_netdev(dev); - pci_set_drvdata(pdev, NULL); -} - - -static int streamer_reset(struct net_device *dev) -{ - struct streamer_private *streamer_priv; - __u8 __iomem *streamer_mmio; - unsigned long t; - unsigned int uaa_addr; - struct sk_buff *skb = NULL; - __u16 misr; - - streamer_priv = netdev_priv(dev); - streamer_mmio = streamer_priv->streamer_mmio; - - writew(readw(streamer_mmio + BCTL) | BCTL_SOFTRESET, streamer_mmio + BCTL); - t = jiffies; - /* Hold soft reset bit for a while */ - ssleep(1); - - writew(readw(streamer_mmio + BCTL) & ~BCTL_SOFTRESET, - streamer_mmio + BCTL); - -#if STREAMER_DEBUG - printk("BCTL: %x\n", readw(streamer_mmio + BCTL)); - printk("GPR: %x\n", readw(streamer_mmio + GPR)); - printk("SISRMASK: %x\n", readw(streamer_mmio + SISR_MASK)); -#endif - writew(readw(streamer_mmio + BCTL) | (BCTL_RX_FIFO_8 | BCTL_TX_FIFO_8), streamer_mmio + BCTL ); - - if (streamer_priv->streamer_ring_speed == 0) { /* Autosense */ - writew(readw(streamer_mmio + GPR) | GPR_AUTOSENSE, - streamer_mmio + GPR); - if (streamer_priv->streamer_message_level) - printk(KERN_INFO "%s: Ringspeed autosense mode on\n", - dev->name); - } else if (streamer_priv->streamer_ring_speed == 16) { - if (streamer_priv->streamer_message_level) - printk(KERN_INFO "%s: Trying to open at 16 Mbps as requested\n", - dev->name); - writew(GPR_16MBPS, streamer_mmio + GPR); - } else if (streamer_priv->streamer_ring_speed == 4) { - if (streamer_priv->streamer_message_level) - printk(KERN_INFO "%s: Trying to open at 4 Mbps as requested\n", - dev->name); - writew(0, streamer_mmio + GPR); - } - - skb = dev_alloc_skb(streamer_priv->pkt_buf_sz); - if (!skb) { - printk(KERN_INFO "%s: skb allocation for diagnostics failed...proceeding\n", - dev->name); - } else { - struct streamer_rx_desc *rx_ring; - u8 *data; - - rx_ring=(struct streamer_rx_desc *)skb->data; - data=((u8 *)skb->data)+sizeof(struct streamer_rx_desc); - rx_ring->forward=0; - rx_ring->status=0; - rx_ring->buffer=cpu_to_le32(pci_map_single(streamer_priv->pci_dev, data, - 512, PCI_DMA_FROMDEVICE)); - rx_ring->framelen_buflen=512; - writel(cpu_to_le32(pci_map_single(streamer_priv->pci_dev, rx_ring, 512, PCI_DMA_FROMDEVICE)), - streamer_mmio+RXBDA); - } - -#if STREAMER_DEBUG - printk("GPR = %x\n", readw(streamer_mmio + GPR)); -#endif - /* start solo init */ - writew(SISR_MI, streamer_mmio + SISR_MASK_SUM); - - while (!((readw(streamer_mmio + SISR)) & SISR_SRB_REPLY)) { - msleep_interruptible(100); - if (time_after(jiffies, t + 40 * HZ)) { - printk(KERN_ERR - "IBM PCI tokenring card not responding\n"); - release_region(dev->base_addr, STREAMER_IO_SPACE); - if (skb) - dev_kfree_skb(skb); - return -1; - } - } - writew(~SISR_SRB_REPLY, streamer_mmio + SISR_RUM); - misr = readw(streamer_mmio + MISR_RUM); - writew(~misr, streamer_mmio + MISR_RUM); - - if (skb) - dev_kfree_skb(skb); /* release skb used for diagnostics */ - -#if STREAMER_DEBUG - printk("LAPWWO: %x, LAPA: %x LAPE: %x\n", - readw(streamer_mmio + LAPWWO), readw(streamer_mmio + LAPA), - readw(streamer_mmio + LAPE)); -#endif - -#if STREAMER_DEBUG - { - int i; - writew(readw(streamer_mmio + LAPWWO), - streamer_mmio + LAPA); - printk("initialization response srb dump: "); - for (i = 0; i < 10; i++) - printk("%x:", - ntohs(readw(streamer_mmio + LAPDINC))); - printk("\n"); - } -#endif - - writew(readw(streamer_mmio + LAPWWO) + 6, streamer_mmio + LAPA); - if (readw(streamer_mmio + LAPD)) { - printk(KERN_INFO "tokenring card initialization failed. errorcode : %x\n", - ntohs(readw(streamer_mmio + LAPD))); - release_region(dev->base_addr, STREAMER_IO_SPACE); - return -1; - } - - writew(readw(streamer_mmio + LAPWWO) + 8, streamer_mmio + LAPA); - uaa_addr = ntohs(readw(streamer_mmio + LAPDINC)); - readw(streamer_mmio + LAPDINC); /* skip over Level.Addr field */ - streamer_priv->streamer_addr_table_addr = ntohs(readw(streamer_mmio + LAPDINC)); - streamer_priv->streamer_parms_addr = ntohs(readw(streamer_mmio + LAPDINC)); - -#if STREAMER_DEBUG - printk("UAA resides at %x\n", uaa_addr); -#endif - - /* setup uaa area for access with LAPD */ - { - int i; - __u16 addr; - writew(uaa_addr, streamer_mmio + LAPA); - for (i = 0; i < 6; i += 2) { - addr=ntohs(readw(streamer_mmio+LAPDINC)); - dev->dev_addr[i]= (addr >> 8) & 0xff; - dev->dev_addr[i+1]= addr & 0xff; - } -#if STREAMER_DEBUG - printk("Adapter address: %pM\n", dev->dev_addr); -#endif - } - return 0; -} - -static int streamer_open(struct net_device *dev) -{ - struct streamer_private *streamer_priv = netdev_priv(dev); - __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; - unsigned long flags; - char open_error[255]; - int i, open_finished = 1; - __u16 srb_word; - __u16 srb_open; - int rc; - - if (readw(streamer_mmio+BMCTL_SUM) & BMCTL_RX_ENABLED) { - rc=streamer_reset(dev); - } - - if (request_irq(dev->irq, streamer_interrupt, IRQF_SHARED, "lanstreamer", dev)) { - return -EAGAIN; - } -#if STREAMER_DEBUG - printk("BMCTL: %x\n", readw(streamer_mmio + BMCTL_SUM)); - printk("pending ints: %x\n", readw(streamer_mmio + SISR)); -#endif - - writew(SISR_MI | SISR_SRB_REPLY, streamer_mmio + SISR_MASK); /* more ints later, doesn't stop arb cmd interrupt */ - writew(LISR_LIE, streamer_mmio + LISR); /* more ints later */ - - /* adapter is closed, so SRB is pointed to by LAPWWO */ - writew(readw(streamer_mmio + LAPWWO), streamer_mmio + LAPA); - -#if STREAMER_DEBUG - printk("LAPWWO: %x, LAPA: %x\n", readw(streamer_mmio + LAPWWO), - readw(streamer_mmio + LAPA)); - printk("LAPE: %x\n", readw(streamer_mmio + LAPE)); - printk("SISR Mask = %04x\n", readw(streamer_mmio + SISR_MASK)); -#endif - do { - for (i = 0; i < SRB_COMMAND_SIZE; i += 2) { - writew(0, streamer_mmio + LAPDINC); - } - - writew(readw(streamer_mmio+LAPWWO),streamer_mmio+LAPA); - writew(htons(SRB_OPEN_ADAPTER<<8),streamer_mmio+LAPDINC) ; /* open */ - writew(htons(STREAMER_CLEAR_RET_CODE<<8),streamer_mmio+LAPDINC); - writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC); - - writew(readw(streamer_mmio + LAPWWO) + 8, streamer_mmio + LAPA); -#if STREAMER_NETWORK_MONITOR - /* If Network Monitor, instruct card to copy MAC frames through the ARB */ - writew(htons(OPEN_ADAPTER_ENABLE_FDX | OPEN_ADAPTER_PASS_ADC_MAC | OPEN_ADAPTER_PASS_ATT_MAC | OPEN_ADAPTER_PASS_BEACON), streamer_mmio + LAPDINC); /* offset 8 word contains open options */ -#else - writew(htons(OPEN_ADAPTER_ENABLE_FDX), streamer_mmio + LAPDINC); /* Offset 8 word contains Open.Options */ -#endif - - if (streamer_priv->streamer_laa[0]) { - writew(readw(streamer_mmio + LAPWWO) + 12, streamer_mmio + LAPA); - writew(htons((streamer_priv->streamer_laa[0] << 8) | - streamer_priv->streamer_laa[1]),streamer_mmio+LAPDINC); - writew(htons((streamer_priv->streamer_laa[2] << 8) | - streamer_priv->streamer_laa[3]),streamer_mmio+LAPDINC); - writew(htons((streamer_priv->streamer_laa[4] << 8) | - streamer_priv->streamer_laa[5]),streamer_mmio+LAPDINC); - memcpy(dev->dev_addr, streamer_priv->streamer_laa, dev->addr_len); - } - - /* save off srb open offset */ - srb_open = readw(streamer_mmio + LAPWWO); -#if STREAMER_DEBUG - writew(readw(streamer_mmio + LAPWWO), - streamer_mmio + LAPA); - printk("srb open request:\n"); - for (i = 0; i < 16; i++) { - printk("%x:", ntohs(readw(streamer_mmio + LAPDINC))); - } - printk("\n"); -#endif - spin_lock_irqsave(&streamer_priv->streamer_lock, flags); - streamer_priv->srb_queued = 1; - - /* signal solo that SRB command has been issued */ - writew(LISR_SRB_CMD, streamer_mmio + LISR_SUM); - spin_unlock_irqrestore(&streamer_priv->streamer_lock, flags); - - while (streamer_priv->srb_queued) { - interruptible_sleep_on_timeout(&streamer_priv->srb_wait, 5 * HZ); - if (signal_pending(current)) { - printk(KERN_WARNING "%s: SRB timed out.\n", dev->name); - printk(KERN_WARNING "SISR=%x MISR=%x, LISR=%x\n", - readw(streamer_mmio + SISR), - readw(streamer_mmio + MISR_RUM), - readw(streamer_mmio + LISR)); - streamer_priv->srb_queued = 0; - break; - } - } - -#if STREAMER_DEBUG - printk("SISR_MASK: %x\n", readw(streamer_mmio + SISR_MASK)); - printk("srb open response:\n"); - writew(srb_open, streamer_mmio + LAPA); - for (i = 0; i < 10; i++) { - printk("%x:", - ntohs(readw(streamer_mmio + LAPDINC))); - } -#endif - - /* If we get the same return response as we set, the interrupt wasn't raised and the open - * timed out. - */ - writew(srb_open + 2, streamer_mmio + LAPA); - srb_word = ntohs(readw(streamer_mmio + LAPD)) >> 8; - if (srb_word == STREAMER_CLEAR_RET_CODE) { - printk(KERN_WARNING "%s: Adapter Open time out or error.\n", - dev->name); - return -EIO; - } - - if (srb_word != 0) { - if (srb_word == 0x07) { - if (!streamer_priv->streamer_ring_speed && open_finished) { /* Autosense , first time around */ - printk(KERN_WARNING "%s: Retrying at different ring speed\n", - dev->name); - open_finished = 0; - } else { - __u16 error_code; - - writew(srb_open + 6, streamer_mmio + LAPA); - error_code = ntohs(readw(streamer_mmio + LAPD)); - strcpy(open_error, open_maj_error[(error_code & 0xf0) >> 4]); - strcat(open_error, " - "); - strcat(open_error, open_min_error[(error_code & 0x0f)]); - - if (!streamer_priv->streamer_ring_speed && - ((error_code & 0x0f) == 0x0d)) - { - printk(KERN_WARNING "%s: Tried to autosense ring speed with no monitors present\n", dev->name); - printk(KERN_WARNING "%s: Please try again with a specified ring speed\n", dev->name); - free_irq(dev->irq, dev); - return -EIO; - } - - printk(KERN_WARNING "%s: %s\n", - dev->name, open_error); - free_irq(dev->irq, dev); - return -EIO; - - } /* if autosense && open_finished */ - } else { - printk(KERN_WARNING "%s: Bad OPEN response: %x\n", - dev->name, srb_word); - free_irq(dev->irq, dev); - return -EIO; - } - } else - open_finished = 1; - } while (!(open_finished)); /* Will only loop if ring speed mismatch re-open attempted && autosense is on */ - - writew(srb_open + 18, streamer_mmio + LAPA); - srb_word=ntohs(readw(streamer_mmio+LAPD)) >> 8; - if (srb_word & (1 << 3)) - if (streamer_priv->streamer_message_level) - printk(KERN_INFO "%s: Opened in FDX Mode\n", dev->name); - - if (srb_word & 1) - streamer_priv->streamer_ring_speed = 16; - else - streamer_priv->streamer_ring_speed = 4; - - if (streamer_priv->streamer_message_level) - printk(KERN_INFO "%s: Opened in %d Mbps mode\n", - dev->name, - streamer_priv->streamer_ring_speed); - - writew(srb_open + 8, streamer_mmio + LAPA); - streamer_priv->asb = ntohs(readw(streamer_mmio + LAPDINC)); - streamer_priv->srb = ntohs(readw(streamer_mmio + LAPDINC)); - streamer_priv->arb = ntohs(readw(streamer_mmio + LAPDINC)); - readw(streamer_mmio + LAPDINC); /* offset 14 word is rsvd */ - streamer_priv->trb = ntohs(readw(streamer_mmio + LAPDINC)); - - streamer_priv->streamer_receive_options = 0x00; - streamer_priv->streamer_copy_all_options = 0; - - /* setup rx ring */ - /* enable rx channel */ - writew(~BMCTL_RX_DIS, streamer_mmio + BMCTL_RUM); - - /* setup rx descriptors */ - streamer_priv->streamer_rx_ring= - kmalloc( sizeof(struct streamer_rx_desc)* - STREAMER_RX_RING_SIZE,GFP_KERNEL); - if (!streamer_priv->streamer_rx_ring) { - printk(KERN_WARNING "%s ALLOC of streamer rx ring FAILED!!\n",dev->name); - return -EIO; - } - - for (i = 0; i < STREAMER_RX_RING_SIZE; i++) { - struct sk_buff *skb; - - skb = dev_alloc_skb(streamer_priv->pkt_buf_sz); - if (skb == NULL) - break; - - skb->dev = dev; - - streamer_priv->streamer_rx_ring[i].forward = - cpu_to_le32(pci_map_single(streamer_priv->pci_dev, &streamer_priv->streamer_rx_ring[i + 1], - sizeof(struct streamer_rx_desc), PCI_DMA_FROMDEVICE)); - streamer_priv->streamer_rx_ring[i].status = 0; - streamer_priv->streamer_rx_ring[i].buffer = - cpu_to_le32(pci_map_single(streamer_priv->pci_dev, skb->data, - streamer_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE)); - streamer_priv->streamer_rx_ring[i].framelen_buflen = streamer_priv->pkt_buf_sz; - streamer_priv->rx_ring_skb[i] = skb; - } - streamer_priv->streamer_rx_ring[STREAMER_RX_RING_SIZE - 1].forward = - cpu_to_le32(pci_map_single(streamer_priv->pci_dev, &streamer_priv->streamer_rx_ring[0], - sizeof(struct streamer_rx_desc), PCI_DMA_FROMDEVICE)); - - if (i == 0) { - printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers. Adapter disabled\n", dev->name); - free_irq(dev->irq, dev); - return -EIO; - } - - streamer_priv->rx_ring_last_received = STREAMER_RX_RING_SIZE - 1; /* last processed rx status */ - - writel(cpu_to_le32(pci_map_single(streamer_priv->pci_dev, &streamer_priv->streamer_rx_ring[0], - sizeof(struct streamer_rx_desc), PCI_DMA_TODEVICE)), - streamer_mmio + RXBDA); - writel(cpu_to_le32(pci_map_single(streamer_priv->pci_dev, &streamer_priv->streamer_rx_ring[STREAMER_RX_RING_SIZE - 1], - sizeof(struct streamer_rx_desc), PCI_DMA_TODEVICE)), - streamer_mmio + RXLBDA); - - /* set bus master interrupt event mask */ - writew(MISR_RX_NOBUF | MISR_RX_EOF, streamer_mmio + MISR_MASK); - - - /* setup tx ring */ - streamer_priv->streamer_tx_ring=kmalloc(sizeof(struct streamer_tx_desc)* - STREAMER_TX_RING_SIZE,GFP_KERNEL); - if (!streamer_priv->streamer_tx_ring) { - printk(KERN_WARNING "%s ALLOC of streamer_tx_ring FAILED\n",dev->name); - return -EIO; - } - - writew(~BMCTL_TX2_DIS, streamer_mmio + BMCTL_RUM); /* Enables TX channel 2 */ - for (i = 0; i < STREAMER_TX_RING_SIZE; i++) { - streamer_priv->streamer_tx_ring[i].forward = cpu_to_le32(pci_map_single(streamer_priv->pci_dev, - &streamer_priv->streamer_tx_ring[i + 1], - sizeof(struct streamer_tx_desc), - PCI_DMA_TODEVICE)); - streamer_priv->streamer_tx_ring[i].status = 0; - streamer_priv->streamer_tx_ring[i].bufcnt_framelen = 0; - streamer_priv->streamer_tx_ring[i].buffer = 0; - streamer_priv->streamer_tx_ring[i].buflen = 0; - streamer_priv->streamer_tx_ring[i].rsvd1 = 0; - streamer_priv->streamer_tx_ring[i].rsvd2 = 0; - streamer_priv->streamer_tx_ring[i].rsvd3 = 0; - } - streamer_priv->streamer_tx_ring[STREAMER_TX_RING_SIZE - 1].forward = - cpu_to_le32(pci_map_single(streamer_priv->pci_dev, &streamer_priv->streamer_tx_ring[0], - sizeof(struct streamer_tx_desc), PCI_DMA_TODEVICE)); - - streamer_priv->free_tx_ring_entries = STREAMER_TX_RING_SIZE; - streamer_priv->tx_ring_free = 0; /* next entry in tx ring to use */ - streamer_priv->tx_ring_last_status = STREAMER_TX_RING_SIZE - 1; - - /* set Busmaster interrupt event mask (handle receives on interrupt only */ - writew(MISR_TX2_EOF | MISR_RX_NOBUF | MISR_RX_EOF, streamer_mmio + MISR_MASK); - /* set system event interrupt mask */ - writew(SISR_ADAPTER_CHECK | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_ASB_FREE, streamer_mmio + SISR_MASK_SUM); - -#if STREAMER_DEBUG - printk("BMCTL: %x\n", readw(streamer_mmio + BMCTL_SUM)); - printk("SISR MASK: %x\n", readw(streamer_mmio + SISR_MASK)); -#endif - -#if STREAMER_NETWORK_MONITOR - - writew(streamer_priv->streamer_addr_table_addr, streamer_mmio + LAPA); - printk("%s: Node Address: %04x:%04x:%04x\n", dev->name, - ntohs(readw(streamer_mmio + LAPDINC)), - ntohs(readw(streamer_mmio + LAPDINC)), - ntohs(readw(streamer_mmio + LAPDINC))); - readw(streamer_mmio + LAPDINC); - readw(streamer_mmio + LAPDINC); - printk("%s: Functional Address: %04x:%04x\n", dev->name, - ntohs(readw(streamer_mmio + LAPDINC)), - ntohs(readw(streamer_mmio + LAPDINC))); - - writew(streamer_priv->streamer_parms_addr + 4, - streamer_mmio + LAPA); - printk("%s: NAUN Address: %04x:%04x:%04x\n", dev->name, - ntohs(readw(streamer_mmio + LAPDINC)), - ntohs(readw(streamer_mmio + LAPDINC)), - ntohs(readw(streamer_mmio + LAPDINC))); -#endif - - netif_start_queue(dev); - netif_carrier_on(dev); - return 0; -} - -/* - * When we enter the rx routine we do not know how many frames have been - * queued on the rx channel. Therefore we start at the next rx status - * position and travel around the receive ring until we have completed - * all the frames. - * - * This means that we may process the frame before we receive the end - * of frame interrupt. This is why we always test the status instead - * of blindly processing the next frame. - * - */ -static void streamer_rx(struct net_device *dev) -{ - struct streamer_private *streamer_priv = - netdev_priv(dev); - __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; - struct streamer_rx_desc *rx_desc; - int rx_ring_last_received, length, frame_length, buffer_cnt = 0; - struct sk_buff *skb, *skb2; - - /* setup the next rx descriptor to be received */ - rx_desc = &streamer_priv->streamer_rx_ring[(streamer_priv->rx_ring_last_received + 1) & (STREAMER_RX_RING_SIZE - 1)]; - rx_ring_last_received = streamer_priv->rx_ring_last_received; - - while (rx_desc->status & 0x01000000) { /* While processed descriptors are available */ - if (rx_ring_last_received != streamer_priv->rx_ring_last_received) - { - printk(KERN_WARNING "RX Error 1 rx_ring_last_received not the same %x %x\n", - rx_ring_last_received, streamer_priv->rx_ring_last_received); - } - streamer_priv->rx_ring_last_received = (streamer_priv->rx_ring_last_received + 1) & (STREAMER_RX_RING_SIZE - 1); - rx_ring_last_received = streamer_priv->rx_ring_last_received; - - length = rx_desc->framelen_buflen & 0xffff; /* buffer length */ - frame_length = (rx_desc->framelen_buflen >> 16) & 0xffff; - - if (rx_desc->status & 0x7E830000) { /* errors */ - if (streamer_priv->streamer_message_level) { - printk(KERN_WARNING "%s: Rx Error %x\n", - dev->name, rx_desc->status); - } - } else { /* received without errors */ - if (rx_desc->status & 0x80000000) { /* frame complete */ - buffer_cnt = 1; - skb = dev_alloc_skb(streamer_priv->pkt_buf_sz); - } else { - skb = dev_alloc_skb(frame_length); - } - - if (skb == NULL) - { - printk(KERN_WARNING "%s: Not enough memory to copy packet to upper layers.\n", dev->name); - dev->stats.rx_dropped++; - } else { /* we allocated an skb OK */ - if (buffer_cnt == 1) { - /* release the DMA mapping */ - pci_unmap_single(streamer_priv->pci_dev, - le32_to_cpu(streamer_priv->streamer_rx_ring[rx_ring_last_received].buffer), - streamer_priv->pkt_buf_sz, - PCI_DMA_FROMDEVICE); - skb2 = streamer_priv->rx_ring_skb[rx_ring_last_received]; -#if STREAMER_DEBUG_PACKETS - { - int i; - printk("streamer_rx packet print: skb->data2 %p skb->head %p\n", skb2->data, skb2->head); - for (i = 0; i < frame_length; i++) - { - printk("%x:", skb2->data[i]); - if (((i + 1) % 16) == 0) - printk("\n"); - } - printk("\n"); - } -#endif - skb_put(skb2, length); - skb2->protocol = tr_type_trans(skb2, dev); - /* recycle this descriptor */ - streamer_priv->streamer_rx_ring[rx_ring_last_received].status = 0; - streamer_priv->streamer_rx_ring[rx_ring_last_received].framelen_buflen = streamer_priv->pkt_buf_sz; - streamer_priv->streamer_rx_ring[rx_ring_last_received].buffer = - cpu_to_le32(pci_map_single(streamer_priv->pci_dev, skb->data, streamer_priv->pkt_buf_sz, - PCI_DMA_FROMDEVICE)); - streamer_priv->rx_ring_skb[rx_ring_last_received] = skb; - /* place recycled descriptor back on the adapter */ - writel(cpu_to_le32(pci_map_single(streamer_priv->pci_dev, - &streamer_priv->streamer_rx_ring[rx_ring_last_received], - sizeof(struct streamer_rx_desc), PCI_DMA_FROMDEVICE)), - streamer_mmio + RXLBDA); - /* pass the received skb up to the protocol */ - netif_rx(skb2); - } else { - do { /* Walk the buffers */ - pci_unmap_single(streamer_priv->pci_dev, le32_to_cpu(rx_desc->buffer), length, PCI_DMA_FROMDEVICE), - memcpy(skb_put(skb, length), (void *)rx_desc->buffer, length); /* copy this fragment */ - streamer_priv->streamer_rx_ring[rx_ring_last_received].status = 0; - streamer_priv->streamer_rx_ring[rx_ring_last_received].framelen_buflen = streamer_priv->pkt_buf_sz; - - /* give descriptor back to the adapter */ - writel(cpu_to_le32(pci_map_single(streamer_priv->pci_dev, - &streamer_priv->streamer_rx_ring[rx_ring_last_received], - length, PCI_DMA_FROMDEVICE)), - streamer_mmio + RXLBDA); - - if (rx_desc->status & 0x80000000) - break; /* this descriptor completes the frame */ - - /* else get the next pending descriptor */ - if (rx_ring_last_received!= streamer_priv->rx_ring_last_received) - { - printk("RX Error rx_ring_last_received not the same %x %x\n", - rx_ring_last_received, - streamer_priv->rx_ring_last_received); - } - rx_desc = &streamer_priv->streamer_rx_ring[(streamer_priv->rx_ring_last_received+1) & (STREAMER_RX_RING_SIZE-1)]; - - length = rx_desc->framelen_buflen & 0xffff; /* buffer length */ - streamer_priv->rx_ring_last_received = (streamer_priv->rx_ring_last_received+1) & (STREAMER_RX_RING_SIZE - 1); - rx_ring_last_received = streamer_priv->rx_ring_last_received; - } while (1); - - skb->protocol = tr_type_trans(skb, dev); - /* send up to the protocol */ - netif_rx(skb); - } - dev->stats.rx_packets++; - dev->stats.rx_bytes += length; - } /* if skb == null */ - } /* end received without errors */ - - /* try the next one */ - rx_desc = &streamer_priv->streamer_rx_ring[(rx_ring_last_received + 1) & (STREAMER_RX_RING_SIZE - 1)]; - } /* end for all completed rx descriptors */ -} - -static irqreturn_t streamer_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = (struct net_device *) dev_id; - struct streamer_private *streamer_priv = - netdev_priv(dev); - __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; - __u16 sisr; - __u16 misr; - u8 max_intr = MAX_INTR; - - spin_lock(&streamer_priv->streamer_lock); - sisr = readw(streamer_mmio + SISR); - - while((sisr & (SISR_MI | SISR_SRB_REPLY | SISR_ADAPTER_CHECK | SISR_ASB_FREE | - SISR_ARB_CMD | SISR_TRB_REPLY | SISR_PAR_ERR | SISR_SERR_ERR)) && - (max_intr > 0)) { - - if(sisr & SISR_PAR_ERR) { - writew(~SISR_PAR_ERR, streamer_mmio + SISR_RUM); - (void)readw(streamer_mmio + SISR_RUM); - } - - else if(sisr & SISR_SERR_ERR) { - writew(~SISR_SERR_ERR, streamer_mmio + SISR_RUM); - (void)readw(streamer_mmio + SISR_RUM); - } - - else if(sisr & SISR_MI) { - misr = readw(streamer_mmio + MISR_RUM); - - if (misr & MISR_TX2_EOF) { - while(streamer_priv->streamer_tx_ring[(streamer_priv->tx_ring_last_status + 1) & (STREAMER_TX_RING_SIZE - 1)].status) { - streamer_priv->tx_ring_last_status = (streamer_priv->tx_ring_last_status + 1) & (STREAMER_TX_RING_SIZE - 1); - streamer_priv->free_tx_ring_entries++; - dev->stats.tx_bytes += streamer_priv->tx_ring_skb[streamer_priv->tx_ring_last_status]->len; - dev->stats.tx_packets++; - dev_kfree_skb_irq(streamer_priv->tx_ring_skb[streamer_priv->tx_ring_last_status]); - streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].buffer = 0xdeadbeef; - streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].status = 0; - streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].bufcnt_framelen = 0; - streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].buflen = 0; - streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].rsvd1 = 0; - streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].rsvd2 = 0; - streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].rsvd3 = 0; - } - netif_wake_queue(dev); - } - - if (misr & MISR_RX_EOF) { - streamer_rx(dev); - } - /* MISR_RX_EOF */ - - if (misr & MISR_RX_NOBUF) { - /* According to the documentation, we don't have to do anything, - * but trapping it keeps it out of /var/log/messages. - */ - } /* SISR_RX_NOBUF */ - - writew(~misr, streamer_mmio + MISR_RUM); - (void)readw(streamer_mmio + MISR_RUM); - } - - else if (sisr & SISR_SRB_REPLY) { - if (streamer_priv->srb_queued == 1) { - wake_up_interruptible(&streamer_priv->srb_wait); - } else if (streamer_priv->srb_queued == 2) { - streamer_srb_bh(dev); - } - streamer_priv->srb_queued = 0; - - writew(~SISR_SRB_REPLY, streamer_mmio + SISR_RUM); - (void)readw(streamer_mmio + SISR_RUM); - } - - else if (sisr & SISR_ADAPTER_CHECK) { - printk(KERN_WARNING "%s: Adapter Check Interrupt Raised, 8 bytes of information follow:\n", dev->name); - writel(readl(streamer_mmio + LAPWWO), streamer_mmio + LAPA); - printk(KERN_WARNING "%s: Words %x:%x:%x:%x:\n", - dev->name, readw(streamer_mmio + LAPDINC), - ntohs(readw(streamer_mmio + LAPDINC)), - ntohs(readw(streamer_mmio + LAPDINC)), - ntohs(readw(streamer_mmio + LAPDINC))); - netif_stop_queue(dev); - netif_carrier_off(dev); - printk(KERN_WARNING "%s: Adapter must be manually reset.\n", dev->name); - } - - /* SISR_ADAPTER_CHECK */ - else if (sisr & SISR_ASB_FREE) { - /* Wake up anything that is waiting for the asb response */ - if (streamer_priv->asb_queued) { - streamer_asb_bh(dev); - } - writew(~SISR_ASB_FREE, streamer_mmio + SISR_RUM); - (void)readw(streamer_mmio + SISR_RUM); - } - /* SISR_ASB_FREE */ - else if (sisr & SISR_ARB_CMD) { - streamer_arb_cmd(dev); - writew(~SISR_ARB_CMD, streamer_mmio + SISR_RUM); - (void)readw(streamer_mmio + SISR_RUM); - } - /* SISR_ARB_CMD */ - else if (sisr & SISR_TRB_REPLY) { - /* Wake up anything that is waiting for the trb response */ - if (streamer_priv->trb_queued) { - wake_up_interruptible(&streamer_priv-> - trb_wait); - } - streamer_priv->trb_queued = 0; - writew(~SISR_TRB_REPLY, streamer_mmio + SISR_RUM); - (void)readw(streamer_mmio + SISR_RUM); - } - /* SISR_TRB_REPLY */ - - sisr = readw(streamer_mmio + SISR); - max_intr--; - } /* while() */ - - spin_unlock(&streamer_priv->streamer_lock) ; - return IRQ_HANDLED; -} - -static netdev_tx_t streamer_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct streamer_private *streamer_priv = - netdev_priv(dev); - __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; - unsigned long flags ; - - spin_lock_irqsave(&streamer_priv->streamer_lock, flags); - - if (streamer_priv->free_tx_ring_entries) { - streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].status = 0; - streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].bufcnt_framelen = 0x00020000 | skb->len; - streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].buffer = - cpu_to_le32(pci_map_single(streamer_priv->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE)); - streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd1 = skb->len; - streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd2 = 0; - streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd3 = 0; - streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].buflen = skb->len; - - streamer_priv->tx_ring_skb[streamer_priv->tx_ring_free] = skb; - streamer_priv->free_tx_ring_entries--; -#if STREAMER_DEBUG_PACKETS - { - int i; - printk("streamer_xmit packet print:\n"); - for (i = 0; i < skb->len; i++) { - printk("%x:", skb->data[i]); - if (((i + 1) % 16) == 0) - printk("\n"); - } - printk("\n"); - } -#endif - - writel(cpu_to_le32(pci_map_single(streamer_priv->pci_dev, - &streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free], - sizeof(struct streamer_tx_desc), PCI_DMA_TODEVICE)), - streamer_mmio + TX2LFDA); - (void)readl(streamer_mmio + TX2LFDA); - - streamer_priv->tx_ring_free = (streamer_priv->tx_ring_free + 1) & (STREAMER_TX_RING_SIZE - 1); - spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags); - return NETDEV_TX_OK; - } else { - netif_stop_queue(dev); - spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags); - return NETDEV_TX_BUSY; - } -} - - -static int streamer_close(struct net_device *dev) -{ - struct streamer_private *streamer_priv = - netdev_priv(dev); - __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; - unsigned long flags; - int i; - - netif_stop_queue(dev); - netif_carrier_off(dev); - writew(streamer_priv->srb, streamer_mmio + LAPA); - writew(htons(SRB_CLOSE_ADAPTER << 8),streamer_mmio+LAPDINC); - writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC); - - spin_lock_irqsave(&streamer_priv->streamer_lock, flags); - - streamer_priv->srb_queued = 1; - writew(LISR_SRB_CMD, streamer_mmio + LISR_SUM); - - spin_unlock_irqrestore(&streamer_priv->streamer_lock, flags); - - while (streamer_priv->srb_queued) - { - interruptible_sleep_on_timeout(&streamer_priv->srb_wait, - jiffies + 60 * HZ); - if (signal_pending(current)) - { - printk(KERN_WARNING "%s: SRB timed out.\n", dev->name); - printk(KERN_WARNING "SISR=%x MISR=%x LISR=%x\n", - readw(streamer_mmio + SISR), - readw(streamer_mmio + MISR_RUM), - readw(streamer_mmio + LISR)); - streamer_priv->srb_queued = 0; - break; - } - } - - streamer_priv->rx_ring_last_received = (streamer_priv->rx_ring_last_received + 1) & (STREAMER_RX_RING_SIZE - 1); - - for (i = 0; i < STREAMER_RX_RING_SIZE; i++) { - if (streamer_priv->rx_ring_skb[streamer_priv->rx_ring_last_received]) { - dev_kfree_skb(streamer_priv->rx_ring_skb[streamer_priv->rx_ring_last_received]); - } - streamer_priv->rx_ring_last_received = (streamer_priv->rx_ring_last_received + 1) & (STREAMER_RX_RING_SIZE - 1); - } - - /* reset tx/rx fifo's and busmaster logic */ - - /* TBD. Add graceful way to reset the LLC channel without doing a soft reset. - writel(readl(streamer_mmio+BCTL)|(3<<13),streamer_mmio+BCTL); - udelay(1); - writel(readl(streamer_mmio+BCTL)&~(3<<13),streamer_mmio+BCTL); - */ - -#if STREAMER_DEBUG - writew(streamer_priv->srb, streamer_mmio + LAPA); - printk("srb): "); - for (i = 0; i < 2; i++) { - printk("%x ", ntohs(readw(streamer_mmio + LAPDINC))); - } - printk("\n"); -#endif - free_irq(dev->irq, dev); - return 0; -} - -static void streamer_set_rx_mode(struct net_device *dev) -{ - struct streamer_private *streamer_priv = - netdev_priv(dev); - __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; - __u8 options = 0; - struct netdev_hw_addr *ha; - unsigned char dev_mc_address[5]; - - writel(streamer_priv->srb, streamer_mmio + LAPA); - options = streamer_priv->streamer_copy_all_options; - - if (dev->flags & IFF_PROMISC) - options |= (3 << 5); /* All LLC and MAC frames, all through the main rx channel */ - else - options &= ~(3 << 5); - - /* Only issue the srb if there is a change in options */ - - if ((options ^ streamer_priv->streamer_copy_all_options)) - { - /* Now to issue the srb command to alter the copy.all.options */ - writew(htons(SRB_MODIFY_RECEIVE_OPTIONS << 8), streamer_mmio+LAPDINC); - writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC); - writew(htons((streamer_priv->streamer_receive_options << 8) | options),streamer_mmio+LAPDINC); - writew(htons(0x4a41),streamer_mmio+LAPDINC); - writew(htons(0x4d45),streamer_mmio+LAPDINC); - writew(htons(0x5320),streamer_mmio+LAPDINC); - writew(0x2020, streamer_mmio + LAPDINC); - - streamer_priv->srb_queued = 2; /* Can't sleep, use srb_bh */ - - writel(LISR_SRB_CMD, streamer_mmio + LISR_SUM); - - streamer_priv->streamer_copy_all_options = options; - return; - } - - /* Set the functional addresses we need for multicast */ - writel(streamer_priv->srb,streamer_mmio+LAPA); - dev_mc_address[0] = dev_mc_address[1] = dev_mc_address[2] = dev_mc_address[3] = 0 ; - - netdev_for_each_mc_addr(ha, dev) { - dev_mc_address[0] |= ha->addr[2]; - dev_mc_address[1] |= ha->addr[3]; - dev_mc_address[2] |= ha->addr[4]; - dev_mc_address[3] |= ha->addr[5]; - } - - writew(htons(SRB_SET_FUNC_ADDRESS << 8),streamer_mmio+LAPDINC); - writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC); - writew(0,streamer_mmio+LAPDINC); - writew(htons( (dev_mc_address[0] << 8) | dev_mc_address[1]),streamer_mmio+LAPDINC); - writew(htons( (dev_mc_address[2] << 8) | dev_mc_address[3]),streamer_mmio+LAPDINC); - streamer_priv->srb_queued = 2 ; - writel(LISR_SRB_CMD,streamer_mmio+LISR_SUM); -} - -static void streamer_srb_bh(struct net_device *dev) -{ - struct streamer_private *streamer_priv = netdev_priv(dev); - __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; - __u16 srb_word; - - writew(streamer_priv->srb, streamer_mmio + LAPA); - srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8; - - switch (srb_word) { - - /* SRB_MODIFY_RECEIVE_OPTIONS i.e. set_multicast_list options (promiscuous) - * At some point we should do something if we get an error, such as - * resetting the IFF_PROMISC flag in dev - */ - - case SRB_MODIFY_RECEIVE_OPTIONS: - srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8; - - switch (srb_word) { - case 0x01: - printk(KERN_WARNING "%s: Unrecognized srb command\n", dev->name); - break; - case 0x04: - printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n", dev->name); - break; - default: - if (streamer_priv->streamer_message_level) - printk(KERN_WARNING "%s: Receive Options Modified to %x,%x\n", - dev->name, - streamer_priv->streamer_copy_all_options, - streamer_priv->streamer_receive_options); - break; - } /* switch srb[2] */ - break; - - - /* SRB_SET_GROUP_ADDRESS - Multicast group setting - */ - case SRB_SET_GROUP_ADDRESS: - srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8; - switch (srb_word) { - case 0x00: - break; - case 0x01: - printk(KERN_WARNING "%s: Unrecognized srb command\n",dev->name); - break; - case 0x04: - printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n", dev->name); - break; - case 0x3c: - printk(KERN_WARNING "%s: Group/Functional address indicator bits not set correctly\n", dev->name); - break; - case 0x3e: /* If we ever implement individual multicast addresses, will need to deal with this */ - printk(KERN_WARNING "%s: Group address registers full\n", dev->name); - break; - case 0x55: - printk(KERN_INFO "%s: Group Address already set.\n", dev->name); - break; - default: - break; - } /* switch srb[2] */ - break; - - - /* SRB_RESET_GROUP_ADDRESS - Remove a multicast address from group list - */ - case SRB_RESET_GROUP_ADDRESS: - srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8; - switch (srb_word) { - case 0x00: - break; - case 0x01: - printk(KERN_WARNING "%s: Unrecognized srb command\n", dev->name); - break; - case 0x04: - printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n", dev->name); - break; - case 0x39: /* Must deal with this if individual multicast addresses used */ - printk(KERN_INFO "%s: Group address not found\n", dev->name); - break; - default: - break; - } /* switch srb[2] */ - break; - - - /* SRB_SET_FUNC_ADDRESS - Called by the set_rx_mode - */ - - case SRB_SET_FUNC_ADDRESS: - srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8; - switch (srb_word) { - case 0x00: - if (streamer_priv->streamer_message_level) - printk(KERN_INFO "%s: Functional Address Mask Set\n", dev->name); - break; - case 0x01: - printk(KERN_WARNING "%s: Unrecognized srb command\n", dev->name); - break; - case 0x04: - printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n", dev->name); - break; - default: - break; - } /* switch srb[2] */ - break; - - /* SRB_READ_LOG - Read and reset the adapter error counters - */ - - case SRB_READ_LOG: - srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8; - switch (srb_word) { - case 0x00: - { - int i; - if (streamer_priv->streamer_message_level) - printk(KERN_INFO "%s: Read Log command complete\n", dev->name); - printk("Read Log statistics: "); - writew(streamer_priv->srb + 6, - streamer_mmio + LAPA); - for (i = 0; i < 5; i++) { - printk("%x:", ntohs(readw(streamer_mmio + LAPDINC))); - } - printk("\n"); - } - break; - case 0x01: - printk(KERN_WARNING "%s: Unrecognized srb command\n", dev->name); - break; - case 0x04: - printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n", dev->name); - break; - - } /* switch srb[2] */ - break; - - /* SRB_READ_SR_COUNTERS - Read and reset the source routing bridge related counters */ - - case SRB_READ_SR_COUNTERS: - srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8; - switch (srb_word) { - case 0x00: - if (streamer_priv->streamer_message_level) - printk(KERN_INFO "%s: Read Source Routing Counters issued\n", dev->name); - break; - case 0x01: - printk(KERN_WARNING "%s: Unrecognized srb command\n", dev->name); - break; - case 0x04: - printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n", dev->name); - break; - default: - break; - } /* switch srb[2] */ - break; - - default: - printk(KERN_WARNING "%s: Unrecognized srb bh return value.\n", dev->name); - break; - } /* switch srb[0] */ -} - -static int streamer_set_mac_address(struct net_device *dev, void *addr) -{ - struct sockaddr *saddr = addr; - struct streamer_private *streamer_priv = netdev_priv(dev); - - if (netif_running(dev)) - { - printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name); - return -EIO; - } - - memcpy(streamer_priv->streamer_laa, saddr->sa_data, dev->addr_len); - - if (streamer_priv->streamer_message_level) { - printk(KERN_INFO "%s: MAC/LAA Set to = %x.%x.%x.%x.%x.%x\n", - dev->name, streamer_priv->streamer_laa[0], - streamer_priv->streamer_laa[1], - streamer_priv->streamer_laa[2], - streamer_priv->streamer_laa[3], - streamer_priv->streamer_laa[4], - streamer_priv->streamer_laa[5]); - } - return 0; -} - -static void streamer_arb_cmd(struct net_device *dev) -{ - struct streamer_private *streamer_priv = - netdev_priv(dev); - __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; - __u8 header_len; - __u16 frame_len, buffer_len; - struct sk_buff *mac_frame; - __u8 frame_data[256]; - __u16 buff_off; - __u16 lan_status = 0, lan_status_diff; /* Initialize to stop compiler warning */ - __u8 fdx_prot_error; - __u16 next_ptr; - __u16 arb_word; - -#if STREAMER_NETWORK_MONITOR - struct trh_hdr *mac_hdr; -#endif - - writew(streamer_priv->arb, streamer_mmio + LAPA); - arb_word=ntohs(readw(streamer_mmio+LAPD)) >> 8; - - if (arb_word == ARB_RECEIVE_DATA) { /* Receive.data, MAC frames */ - writew(streamer_priv->arb + 6, streamer_mmio + LAPA); - streamer_priv->mac_rx_buffer = buff_off = ntohs(readw(streamer_mmio + LAPDINC)); - header_len=ntohs(readw(streamer_mmio+LAPDINC)) >> 8; /* 802.5 Token-Ring Header Length */ - frame_len = ntohs(readw(streamer_mmio + LAPDINC)); - -#if STREAMER_DEBUG - { - int i; - __u16 next; - __u8 status; - __u16 len; - - writew(ntohs(buff_off), streamer_mmio + LAPA); /*setup window to frame data */ - next = htons(readw(streamer_mmio + LAPDINC)); - status = - ntohs(readw(streamer_mmio + LAPDINC)) & 0xff; - len = ntohs(readw(streamer_mmio + LAPDINC)); - - /* print out 1st 14 bytes of frame data */ - for (i = 0; i < 7; i++) { - printk("Loc %d = %04x\n", i, - ntohs(readw - (streamer_mmio + LAPDINC))); - } - - printk("next %04x, fs %02x, len %04x\n", next, - status, len); - } -#endif - if (!(mac_frame = dev_alloc_skb(frame_len))) { - printk(KERN_WARNING "%s: Memory squeeze, dropping frame.\n", - dev->name); - goto drop_frame; - } - /* Walk the buffer chain, creating the frame */ - - do { - int i; - __u16 rx_word; - - writew(htons(buff_off), streamer_mmio + LAPA); /* setup window to frame data */ - next_ptr = ntohs(readw(streamer_mmio + LAPDINC)); - readw(streamer_mmio + LAPDINC); /* read thru status word */ - buffer_len = ntohs(readw(streamer_mmio + LAPDINC)); - - if (buffer_len > 256) - break; - - i = 0; - while (i < buffer_len) { - rx_word=ntohs(readw(streamer_mmio+LAPDINC)); - frame_data[i]=rx_word >> 8; - frame_data[i+1]=rx_word & 0xff; - i += 2; - } - - memcpy(skb_put(mac_frame, buffer_len), - frame_data, buffer_len); - } while (next_ptr && (buff_off = next_ptr)); - - mac_frame->protocol = tr_type_trans(mac_frame, dev); -#if STREAMER_NETWORK_MONITOR - printk(KERN_WARNING "%s: Received MAC Frame, details:\n", - dev->name); - mac_hdr = tr_hdr(mac_frame); - printk(KERN_WARNING - "%s: MAC Frame Dest. Addr: %pM\n", - dev->name, mac_hdr->daddr); - printk(KERN_WARNING - "%s: MAC Frame Srce. Addr: %pM\n", - dev->name, mac_hdr->saddr); -#endif - netif_rx(mac_frame); - - /* Now tell the card we have dealt with the received frame */ -drop_frame: - /* Set LISR Bit 1 */ - writel(LISR_ARB_FREE, streamer_priv->streamer_mmio + LISR_SUM); - - /* Is the ASB free ? */ - - if (!(readl(streamer_priv->streamer_mmio + SISR) & SISR_ASB_FREE)) - { - streamer_priv->asb_queued = 1; - writel(LISR_ASB_FREE_REQ, streamer_priv->streamer_mmio + LISR_SUM); - return; - /* Drop out and wait for the bottom half to be run */ - } - - - writew(streamer_priv->asb, streamer_mmio + LAPA); - writew(htons(ASB_RECEIVE_DATA << 8), streamer_mmio+LAPDINC); - writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC); - writew(0, streamer_mmio + LAPDINC); - writew(htons(streamer_priv->mac_rx_buffer), streamer_mmio + LAPD); - - writel(LISR_ASB_REPLY | LISR_ASB_FREE_REQ, streamer_priv->streamer_mmio + LISR_SUM); - - streamer_priv->asb_queued = 2; - return; - - } else if (arb_word == ARB_LAN_CHANGE_STATUS) { /* Lan.change.status */ - writew(streamer_priv->arb + 6, streamer_mmio + LAPA); - lan_status = ntohs(readw(streamer_mmio + LAPDINC)); - fdx_prot_error = ntohs(readw(streamer_mmio+LAPD)) >> 8; - - /* Issue ARB Free */ - writew(LISR_ARB_FREE, streamer_priv->streamer_mmio + LISR_SUM); - - lan_status_diff = (streamer_priv->streamer_lan_status ^ lan_status) & - lan_status; - - if (lan_status_diff & (LSC_LWF | LSC_ARW | LSC_FPE | LSC_RR)) - { - if (lan_status_diff & LSC_LWF) - printk(KERN_WARNING "%s: Short circuit detected on the lobe\n", dev->name); - if (lan_status_diff & LSC_ARW) - printk(KERN_WARNING "%s: Auto removal error\n", dev->name); - if (lan_status_diff & LSC_FPE) - printk(KERN_WARNING "%s: FDX Protocol Error\n", dev->name); - if (lan_status_diff & LSC_RR) - printk(KERN_WARNING "%s: Force remove MAC frame received\n", dev->name); - - /* Adapter has been closed by the hardware */ - - /* reset tx/rx fifo's and busmaster logic */ - - /* @TBD. no llc reset on autostreamer writel(readl(streamer_mmio+BCTL)|(3<<13),streamer_mmio+BCTL); - udelay(1); - writel(readl(streamer_mmio+BCTL)&~(3<<13),streamer_mmio+BCTL); */ - - netif_stop_queue(dev); - netif_carrier_off(dev); - printk(KERN_WARNING "%s: Adapter must be manually reset.\n", dev->name); - } - /* If serious error */ - if (streamer_priv->streamer_message_level) { - if (lan_status_diff & LSC_SIG_LOSS) - printk(KERN_WARNING "%s: No receive signal detected\n", dev->name); - if (lan_status_diff & LSC_HARD_ERR) - printk(KERN_INFO "%s: Beaconing\n", dev->name); - if (lan_status_diff & LSC_SOFT_ERR) - printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame\n", dev->name); - if (lan_status_diff & LSC_TRAN_BCN) - printk(KERN_INFO "%s: We are transmitting the beacon, aaah\n", dev->name); - if (lan_status_diff & LSC_SS) - printk(KERN_INFO "%s: Single Station on the ring\n", dev->name); - if (lan_status_diff & LSC_RING_REC) - printk(KERN_INFO "%s: Ring recovery ongoing\n", dev->name); - if (lan_status_diff & LSC_FDX_MODE) - printk(KERN_INFO "%s: Operating in FDX mode\n", dev->name); - } - - if (lan_status_diff & LSC_CO) { - if (streamer_priv->streamer_message_level) - printk(KERN_INFO "%s: Counter Overflow\n", dev->name); - - /* Issue READ.LOG command */ - - writew(streamer_priv->srb, streamer_mmio + LAPA); - writew(htons(SRB_READ_LOG << 8),streamer_mmio+LAPDINC); - writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC); - writew(0, streamer_mmio + LAPDINC); - streamer_priv->srb_queued = 2; /* Can't sleep, use srb_bh */ - - writew(LISR_SRB_CMD, streamer_mmio + LISR_SUM); - } - - if (lan_status_diff & LSC_SR_CO) { - if (streamer_priv->streamer_message_level) - printk(KERN_INFO "%s: Source routing counters overflow\n", dev->name); - - /* Issue a READ.SR.COUNTERS */ - writew(streamer_priv->srb, streamer_mmio + LAPA); - writew(htons(SRB_READ_SR_COUNTERS << 8), - streamer_mmio+LAPDINC); - writew(htons(STREAMER_CLEAR_RET_CODE << 8), - streamer_mmio+LAPDINC); - streamer_priv->srb_queued = 2; /* Can't sleep, use srb_bh */ - writew(LISR_SRB_CMD, streamer_mmio + LISR_SUM); - - } - streamer_priv->streamer_lan_status = lan_status; - } /* Lan.change.status */ - else - printk(KERN_WARNING "%s: Unknown arb command\n", dev->name); -} - -static void streamer_asb_bh(struct net_device *dev) -{ - struct streamer_private *streamer_priv = - netdev_priv(dev); - __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; - - if (streamer_priv->asb_queued == 1) - { - /* Dropped through the first time */ - - writew(streamer_priv->asb, streamer_mmio + LAPA); - writew(htons(ASB_RECEIVE_DATA << 8),streamer_mmio+LAPDINC); - writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC); - writew(0, streamer_mmio + LAPDINC); - writew(htons(streamer_priv->mac_rx_buffer), streamer_mmio + LAPD); - - writel(LISR_ASB_REPLY | LISR_ASB_FREE_REQ, streamer_priv->streamer_mmio + LISR_SUM); - streamer_priv->asb_queued = 2; - - return; - } - - if (streamer_priv->asb_queued == 2) { - __u8 rc; - writew(streamer_priv->asb + 2, streamer_mmio + LAPA); - rc=ntohs(readw(streamer_mmio+LAPD)) >> 8; - switch (rc) { - case 0x01: - printk(KERN_WARNING "%s: Unrecognized command code\n", dev->name); - break; - case 0x26: - printk(KERN_WARNING "%s: Unrecognized buffer address\n", dev->name); - break; - case 0xFF: - /* Valid response, everything should be ok again */ - break; - default: - printk(KERN_WARNING "%s: Invalid return code in asb\n", dev->name); - break; - } - } - streamer_priv->asb_queued = 0; -} - -static int streamer_change_mtu(struct net_device *dev, int mtu) -{ - struct streamer_private *streamer_priv = - netdev_priv(dev); - __u16 max_mtu; - - if (streamer_priv->streamer_ring_speed == 4) - max_mtu = 4500; - else - max_mtu = 18000; - - if (mtu > max_mtu) - return -EINVAL; - if (mtu < 100) - return -EINVAL; - - dev->mtu = mtu; - streamer_priv->pkt_buf_sz = mtu + TR_HLEN; - - return 0; -} - -#if STREAMER_NETWORK_MONITOR -#ifdef CONFIG_PROC_FS -static int streamer_proc_info(char *buffer, char **start, off_t offset, - int length, int *eof, void *data) -{ - struct streamer_private *sdev=NULL; - struct pci_dev *pci_device = NULL; - int len = 0; - off_t begin = 0; - off_t pos = 0; - int size; - - struct net_device *dev; - - size = sprintf(buffer, "IBM LanStreamer/MPC Chipset Token Ring Adapters\n"); - - pos += size; - len += size; - - for(sdev=dev_streamer; sdev; sdev=sdev->next) { - pci_device=sdev->pci_dev; - dev=pci_get_drvdata(pci_device); - - size = sprintf_info(buffer + len, dev); - len += size; - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) - break; - } /* for */ - - *start = buffer + (offset - begin); /* Start of wanted data */ - len -= (offset - begin); /* Start slop */ - if (len > length) - len = length; /* Ending slop */ - return len; -} - -static int sprintf_info(char *buffer, struct net_device *dev) -{ - struct streamer_private *streamer_priv = - netdev_priv(dev); - __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio; - struct streamer_adapter_addr_table sat; - struct streamer_parameters_table spt; - int size = 0; - int i; - - writew(streamer_priv->streamer_addr_table_addr, streamer_mmio + LAPA); - for (i = 0; i < 14; i += 2) { - __u16 io_word; - __u8 *datap = (__u8 *) & sat; - io_word=ntohs(readw(streamer_mmio+LAPDINC)); - datap[size]=io_word >> 8; - datap[size+1]=io_word & 0xff; - } - writew(streamer_priv->streamer_parms_addr, streamer_mmio + LAPA); - for (i = 0; i < 68; i += 2) { - __u16 io_word; - __u8 *datap = (__u8 *) & spt; - io_word=ntohs(readw(streamer_mmio+LAPDINC)); - datap[size]=io_word >> 8; - datap[size+1]=io_word & 0xff; - } - - size = sprintf(buffer, "\n%6s: Adapter Address : Node Address : Functional Addr\n", dev->name); - - size += sprintf(buffer + size, - "%6s: %pM : %pM : %02x:%02x:%02x:%02x\n", - dev->name, dev->dev_addr, sat.node_addr, - sat.func_addr[0], sat.func_addr[1], - sat.func_addr[2], sat.func_addr[3]); - - size += sprintf(buffer + size, "\n%6s: Token Ring Parameters Table:\n", dev->name); - - size += sprintf(buffer + size, "%6s: Physical Addr : Up Node Address : Poll Address : AccPri : Auth Src : Att Code :\n", dev->name); - - size += sprintf(buffer + size, - "%6s: %02x:%02x:%02x:%02x : %pM : %pM : %04x : %04x : %04x :\n", - dev->name, spt.phys_addr[0], spt.phys_addr[1], - spt.phys_addr[2], spt.phys_addr[3], - spt.up_node_addr, spt.poll_addr, - ntohs(spt.acc_priority), ntohs(spt.auth_source_class), - ntohs(spt.att_code)); - - size += sprintf(buffer + size, "%6s: Source Address : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n", dev->name); - - size += sprintf(buffer + size, - "%6s: %pM : %04x : %04x : %04x : %04x : %04x : %04x : \n", - dev->name, spt.source_addr, - ntohs(spt.beacon_type), ntohs(spt.major_vector), - ntohs(spt.lan_status), ntohs(spt.local_ring), - ntohs(spt.mon_error), ntohs(spt.frame_correl)); - - size += sprintf(buffer + size, "%6s: Beacon Details : Tx : Rx : NAUN Node Address : NAUN Node Phys : \n", - dev->name); - - size += sprintf(buffer + size, - "%6s: : %02x : %02x : %pM : %02x:%02x:%02x:%02x : \n", - dev->name, ntohs(spt.beacon_transmit), - ntohs(spt.beacon_receive), - spt.beacon_naun, - spt.beacon_phys[0], spt.beacon_phys[1], - spt.beacon_phys[2], spt.beacon_phys[3]); - return size; -} -#endif -#endif - -static struct pci_driver streamer_pci_driver = { - .name = "lanstreamer", - .id_table = streamer_pci_tbl, - .probe = streamer_init_one, - .remove = __devexit_p(streamer_remove_one), -}; - -static int __init streamer_init_module(void) { - return pci_register_driver(&streamer_pci_driver); -} - -static void __exit streamer_cleanup_module(void) { - pci_unregister_driver(&streamer_pci_driver); -} - -module_init(streamer_init_module); -module_exit(streamer_cleanup_module); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/net/tokenring/lanstreamer.h b/trunk/drivers/net/tokenring/lanstreamer.h deleted file mode 100644 index 3c58d6a3fbc9..000000000000 --- a/trunk/drivers/net/tokenring/lanstreamer.h +++ /dev/null @@ -1,343 +0,0 @@ -/* - * lanstreamer.h -- driver for the IBM Auto LANStreamer PCI Adapter - * - * Written By: Mike Sullivan, IBM Corporation - * - * Copyright (C) 1999 IBM Corporation - * - * Linux driver for IBM PCI tokenring cards based on the LanStreamer MPC - * chipset. - * - * This driver is based on the olympic driver for IBM PCI TokenRing cards (Pit/Pit-Phy/Olympic - * chipsets) written by: - * 1999 Peter De Schrijver All Rights Reserved - * 1999 Mike Phillips (phillim@amtrak.com) - * - * Base Driver Skeleton: - * Written 1993-94 by Donald Becker. - * - * Copyright 1993 United States Government as represented by the - * Director, National Security Agency. - * - * 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. - * - * NO WARRANTY - * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - * solely responsible for determining the appropriateness of using and - * distributing the Program and assumes all risks associated with its - * exercise of rights under this Agreement, including but not limited to - * the risks and costs of program errors, damage to or loss of data, - * programs or equipment, and unavailability or interruption of operations. - * - * DISCLAIMER OF LIABILITY - * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - * - * 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 - * - * - * 12/10/99 - Alpha Release 0.1.0 - * First release to the public - * 08/15/01 - Added ioctl() definitions and others - Kent Yoder - * - */ - -/* MAX_INTR - the maximum number of times we can loop - * inside the interrupt function before returning - * control to the OS (maximum value is 256) - */ -#define MAX_INTR 5 - -#define CLS 0x0C -#define MLR 0x86 -#define LTR 0x0D - -#define BCTL 0x60 -#define BCTL_SOFTRESET (1<<15) -#define BCTL_RX_FIFO_8 (1<<1) -#define BCTL_TX_FIFO_8 (1<<3) - -#define GPR 0x4a -#define GPR_AUTOSENSE (1<<2) -#define GPR_16MBPS (1<<3) - -#define LISR 0x10 -#define LISR_SUM 0x12 -#define LISR_RUM 0x14 - -#define LISR_LIE (1<<15) -#define LISR_SLIM (1<<13) -#define LISR_SLI (1<<12) -#define LISR_BPEI (1<<9) -#define LISR_BPE (1<<8) -#define LISR_SRB_CMD (1<<5) -#define LISR_ASB_REPLY (1<<4) -#define LISR_ASB_FREE_REQ (1<<2) -#define LISR_ARB_FREE (1<<1) -#define LISR_TRB_FRAME (1<<0) - -#define SISR 0x16 -#define SISR_SUM 0x18 -#define SISR_RUM 0x1A -#define SISR_MASK 0x54 -#define SISR_MASK_SUM 0x56 -#define SISR_MASK_RUM 0x58 - -#define SISR_MI (1<<15) -#define SISR_SERR_ERR (1<<14) -#define SISR_TIMER (1<<11) -#define SISR_LAP_PAR_ERR (1<<10) -#define SISR_LAP_ACC_ERR (1<<9) -#define SISR_PAR_ERR (1<<8) -#define SISR_ADAPTER_CHECK (1<<6) -#define SISR_SRB_REPLY (1<<5) -#define SISR_ASB_FREE (1<<4) -#define SISR_ARB_CMD (1<<3) -#define SISR_TRB_REPLY (1<<2) - -#define MISR_RUM 0x5A -#define MISR_MASK 0x5C -#define MISR_MASK_RUM 0x5E - -#define MISR_TX2_IDLE (1<<15) -#define MISR_TX2_NO_STATUS (1<<14) -#define MISR_TX2_HALT (1<<13) -#define MISR_TX2_EOF (1<<12) -#define MISR_TX1_IDLE (1<<11) -#define MISR_TX1_NO_STATUS (1<<10) -#define MISR_TX1_HALT (1<<9) -#define MISR_TX1_EOF (1<<8) -#define MISR_RX_NOBUF (1<<5) -#define MISR_RX_EOB (1<<4) -#define MISR_RX_NO_STATUS (1<<2) -#define MISR_RX_HALT (1<<1) -#define MISR_RX_EOF (1<<0) - -#define LAPA 0x62 -#define LAPE 0x64 -#define LAPD 0x66 -#define LAPDINC 0x68 -#define LAPWWO 0x6A -#define LAPWWC 0x6C -#define LAPCTL 0x6E - -#define TIMER 0x4E4 - -#define BMCTL_SUM 0x50 -#define BMCTL_RUM 0x52 -#define BMCTL_TX1_DIS (1<<14) -#define BMCTL_TX2_DIS (1<<10) -#define BMCTL_RX_DIS (1<<6) -#define BMCTL_RX_ENABLED (1<<5) - -#define RXLBDA 0x90 -#define RXBDA 0x94 -#define RXSTAT 0x98 -#define RXDBA 0x9C - -#define TX1LFDA 0xA0 -#define TX1FDA 0xA4 -#define TX1STAT 0xA8 -#define TX1DBA 0xAC -#define TX2LFDA 0xB0 -#define TX2FDA 0xB4 -#define TX2STAT 0xB8 -#define TX2DBA 0xBC - -#define STREAMER_IO_SPACE 256 - -#define SRB_COMMAND_SIZE 50 - -#define STREAMER_MAX_ADAPTERS 8 /* 0x08 __MODULE_STRING can't hand 0xnn */ - -/* Defines for LAN STATUS CHANGE reports */ -#define LSC_SIG_LOSS 0x8000 -#define LSC_HARD_ERR 0x4000 -#define LSC_SOFT_ERR 0x2000 -#define LSC_TRAN_BCN 0x1000 -#define LSC_LWF 0x0800 -#define LSC_ARW 0x0400 -#define LSC_FPE 0x0200 -#define LSC_RR 0x0100 -#define LSC_CO 0x0080 -#define LSC_SS 0x0040 -#define LSC_RING_REC 0x0020 -#define LSC_SR_CO 0x0010 -#define LSC_FDX_MODE 0x0004 - -/* Defines for OPEN ADAPTER command */ - -#define OPEN_ADAPTER_EXT_WRAP (1<<15) -#define OPEN_ADAPTER_DIS_HARDEE (1<<14) -#define OPEN_ADAPTER_DIS_SOFTERR (1<<13) -#define OPEN_ADAPTER_PASS_ADC_MAC (1<<12) -#define OPEN_ADAPTER_PASS_ATT_MAC (1<<11) -#define OPEN_ADAPTER_ENABLE_EC (1<<10) -#define OPEN_ADAPTER_CONTENDER (1<<8) -#define OPEN_ADAPTER_PASS_BEACON (1<<7) -#define OPEN_ADAPTER_ENABLE_FDX (1<<6) -#define OPEN_ADAPTER_ENABLE_RPL (1<<5) -#define OPEN_ADAPTER_INHIBIT_ETR (1<<4) -#define OPEN_ADAPTER_INTERNAL_WRAP (1<<3) - - -/* Defines for SRB Commands */ -#define SRB_CLOSE_ADAPTER 0x04 -#define SRB_CONFIGURE_BRIDGE 0x0c -#define SRB_CONFIGURE_HP_CHANNEL 0x13 -#define SRB_MODIFY_BRIDGE_PARMS 0x15 -#define SRB_MODIFY_OPEN_OPTIONS 0x01 -#define SRB_MODIFY_RECEIVE_OPTIONS 0x17 -#define SRB_NO_OPERATION 0x00 -#define SRB_OPEN_ADAPTER 0x03 -#define SRB_READ_LOG 0x08 -#define SRB_READ_SR_COUNTERS 0x16 -#define SRB_RESET_GROUP_ADDRESS 0x02 -#define SRB_RESET_TARGET_SEGMETN 0x14 -#define SRB_SAVE_CONFIGURATION 0x1b -#define SRB_SET_BRIDGE_PARMS 0x09 -#define SRB_SET_FUNC_ADDRESS 0x07 -#define SRB_SET_GROUP_ADDRESS 0x06 -#define SRB_SET_TARGET_SEGMENT 0x05 - -/* Clear return code */ -#define STREAMER_CLEAR_RET_CODE 0xfe - -/* ARB Commands */ -#define ARB_RECEIVE_DATA 0x81 -#define ARB_LAN_CHANGE_STATUS 0x84 - -/* ASB Response commands */ -#define ASB_RECEIVE_DATA 0x81 - - -/* Streamer defaults for buffers */ - -#define STREAMER_RX_RING_SIZE 16 /* should be a power of 2 */ -/* Setting the number of TX descriptors to 1 is a workaround for an - * undocumented hardware problem with the lanstreamer board. Setting - * this to something higher may slightly increase the throughput you - * can get from the card, but at the risk of locking up the box. - - * - */ -#define STREAMER_TX_RING_SIZE 1 /* should be a power of 2 */ - -#define PKT_BUF_SZ 4096 /* Default packet size */ - -/* Streamer data structures */ - -struct streamer_tx_desc { - __u32 forward; - __u32 status; - __u32 bufcnt_framelen; - __u32 buffer; - __u32 buflen; - __u32 rsvd1; - __u32 rsvd2; - __u32 rsvd3; -}; - -struct streamer_rx_desc { - __u32 forward; - __u32 status; - __u32 buffer; - __u32 framelen_buflen; -}; - -struct mac_receive_buffer { - __u16 next; - __u8 padding; - __u8 frame_status; - __u16 buffer_length; - __u8 frame_data; -}; - -struct streamer_private { - - __u16 srb; - __u16 trb; - __u16 arb; - __u16 asb; - - struct streamer_private *next; - struct pci_dev *pci_dev; - __u8 __iomem *streamer_mmio; - char *streamer_card_name; - - spinlock_t streamer_lock; - - volatile int srb_queued; /* True if an SRB is still posted */ - wait_queue_head_t srb_wait; - - volatile int asb_queued; /* True if an ASB is posted */ - - volatile int trb_queued; /* True if a TRB is posted */ - wait_queue_head_t trb_wait; - - struct streamer_rx_desc *streamer_rx_ring; - struct streamer_tx_desc *streamer_tx_ring; - struct sk_buff *tx_ring_skb[STREAMER_TX_RING_SIZE], - *rx_ring_skb[STREAMER_RX_RING_SIZE]; - int tx_ring_free, tx_ring_last_status, rx_ring_last_received, - free_tx_ring_entries; - - __u16 streamer_lan_status; - __u8 streamer_ring_speed; - __u16 pkt_buf_sz; - __u8 streamer_receive_options, streamer_copy_all_options, - streamer_message_level; - __u16 streamer_addr_table_addr, streamer_parms_addr; - __u16 mac_rx_buffer; - __u8 streamer_laa[6]; -}; - -struct streamer_adapter_addr_table { - - __u8 node_addr[6]; - __u8 reserved[4]; - __u8 func_addr[4]; -}; - -struct streamer_parameters_table { - - __u8 phys_addr[4]; - __u8 up_node_addr[6]; - __u8 up_phys_addr[4]; - __u8 poll_addr[6]; - __u16 reserved; - __u16 acc_priority; - __u16 auth_source_class; - __u16 att_code; - __u8 source_addr[6]; - __u16 beacon_type; - __u16 major_vector; - __u16 lan_status; - __u16 soft_error_time; - __u16 reserved1; - __u16 local_ring; - __u16 mon_error; - __u16 beacon_transmit; - __u16 beacon_receive; - __u16 frame_correl; - __u8 beacon_naun[6]; - __u32 reserved2; - __u8 beacon_phys[4]; -}; diff --git a/trunk/drivers/net/tokenring/madgemc.c b/trunk/drivers/net/tokenring/madgemc.c deleted file mode 100644 index 28adcdf3b14c..000000000000 --- a/trunk/drivers/net/tokenring/madgemc.c +++ /dev/null @@ -1,761 +0,0 @@ -/* - * madgemc.c: Driver for the Madge Smart 16/4 MC16 MCA token ring card. - * - * Written 2000 by Adam Fritzler - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * This driver module supports the following cards: - * - Madge Smart 16/4 Ringnode MC16 - * - Madge Smart 16/4 Ringnode MC32 (??) - * - * Maintainer(s): - * AF Adam Fritzler - * - * Modification History: - * 16-Jan-00 AF Created - * - */ -static const char version[] = "madgemc.c: v0.91 23/01/2000 by Adam Fritzler\n"; - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "tms380tr.h" -#include "madgemc.h" /* Madge-specific constants */ - -#define MADGEMC_IO_EXTENT 32 -#define MADGEMC_SIF_OFFSET 0x08 - -struct card_info { - /* - * These are read from the BIA ROM. - */ - unsigned int manid; - unsigned int cardtype; - unsigned int cardrev; - unsigned int ramsize; - - /* - * These are read from the MCA POS registers. - */ - unsigned int burstmode:2; - unsigned int fairness:1; /* 0 = Fair, 1 = Unfair */ - unsigned int arblevel:4; - unsigned int ringspeed:2; /* 0 = 4mb, 1 = 16, 2 = Auto/none */ - unsigned int cabletype:1; /* 0 = RJ45, 1 = DB9 */ -}; - -static int madgemc_open(struct net_device *dev); -static int madgemc_close(struct net_device *dev); -static int madgemc_chipset_init(struct net_device *dev); -static void madgemc_read_rom(struct net_device *dev, struct card_info *card); -static unsigned short madgemc_setnselout_pins(struct net_device *dev); -static void madgemc_setcabletype(struct net_device *dev, int type); - -static int madgemc_mcaproc(char *buf, int slot, void *d); - -static void madgemc_setregpage(struct net_device *dev, int page); -static void madgemc_setsifsel(struct net_device *dev, int val); -static void madgemc_setint(struct net_device *dev, int val); - -static irqreturn_t madgemc_interrupt(int irq, void *dev_id); - -/* - * These work around paging, however they don't guarantee you're on the - * right page. - */ -#define SIFREADB(reg) (inb(dev->base_addr + ((reg<0x8)?reg:reg-0x8))) -#define SIFWRITEB(val, reg) (outb(val, dev->base_addr + ((reg<0x8)?reg:reg-0x8))) -#define SIFREADW(reg) (inw(dev->base_addr + ((reg<0x8)?reg:reg-0x8))) -#define SIFWRITEW(val, reg) (outw(val, dev->base_addr + ((reg<0x8)?reg:reg-0x8))) - -/* - * Read a byte-length value from the register. - */ -static unsigned short madgemc_sifreadb(struct net_device *dev, unsigned short reg) -{ - unsigned short ret; - if (reg<0x8) - ret = SIFREADB(reg); - else { - madgemc_setregpage(dev, 1); - ret = SIFREADB(reg); - madgemc_setregpage(dev, 0); - } - return ret; -} - -/* - * Write a byte-length value to a register. - */ -static void madgemc_sifwriteb(struct net_device *dev, unsigned short val, unsigned short reg) -{ - if (reg<0x8) - SIFWRITEB(val, reg); - else { - madgemc_setregpage(dev, 1); - SIFWRITEB(val, reg); - madgemc_setregpage(dev, 0); - } -} - -/* - * Read a word-length value from a register - */ -static unsigned short madgemc_sifreadw(struct net_device *dev, unsigned short reg) -{ - unsigned short ret; - if (reg<0x8) - ret = SIFREADW(reg); - else { - madgemc_setregpage(dev, 1); - ret = SIFREADW(reg); - madgemc_setregpage(dev, 0); - } - return ret; -} - -/* - * Write a word-length value to a register. - */ -static void madgemc_sifwritew(struct net_device *dev, unsigned short val, unsigned short reg) -{ - if (reg<0x8) - SIFWRITEW(val, reg); - else { - madgemc_setregpage(dev, 1); - SIFWRITEW(val, reg); - madgemc_setregpage(dev, 0); - } -} - -static struct net_device_ops madgemc_netdev_ops __read_mostly; - -static int __devinit madgemc_probe(struct device *device) -{ - static int versionprinted; - struct net_device *dev; - struct net_local *tp; - struct card_info *card; - struct mca_device *mdev = to_mca_device(device); - int ret = 0; - - if (versionprinted++ == 0) - printk("%s", version); - - if(mca_device_claimed(mdev)) - return -EBUSY; - mca_device_set_claim(mdev, 1); - - dev = alloc_trdev(sizeof(struct net_local)); - if (!dev) { - printk("madgemc: unable to allocate dev space\n"); - mca_device_set_claim(mdev, 0); - ret = -ENOMEM; - goto getout; - } - - dev->netdev_ops = &madgemc_netdev_ops; - - card = kmalloc(sizeof(struct card_info), GFP_KERNEL); - if (card==NULL) { - ret = -ENOMEM; - goto getout1; - } - - /* - * Parse configuration information. This all comes - * directly from the publicly available @002d.ADF. - * Get it from Madge or your local ADF library. - */ - - /* - * Base address - */ - dev->base_addr = 0x0a20 + - ((mdev->pos[2] & MC16_POS2_ADDR2)?0x0400:0) + - ((mdev->pos[0] & MC16_POS0_ADDR1)?0x1000:0) + - ((mdev->pos[3] & MC16_POS3_ADDR3)?0x2000:0); - - /* - * Interrupt line - */ - switch(mdev->pos[0] >> 6) { /* upper two bits */ - case 0x1: dev->irq = 3; break; - case 0x2: dev->irq = 9; break; /* IRQ 2 = IRQ 9 */ - case 0x3: dev->irq = 10; break; - default: dev->irq = 0; break; - } - - if (dev->irq == 0) { - printk("%s: invalid IRQ\n", dev->name); - ret = -EBUSY; - goto getout2; - } - - if (!request_region(dev->base_addr, MADGEMC_IO_EXTENT, - "madgemc")) { - printk(KERN_INFO "madgemc: unable to setup Smart MC in slot %d because of I/O base conflict at 0x%04lx\n", mdev->slot, dev->base_addr); - dev->base_addr += MADGEMC_SIF_OFFSET; - ret = -EBUSY; - goto getout2; - } - dev->base_addr += MADGEMC_SIF_OFFSET; - - /* - * Arbitration Level - */ - card->arblevel = ((mdev->pos[0] >> 1) & 0x7) + 8; - - /* - * Burst mode and Fairness - */ - card->burstmode = ((mdev->pos[2] >> 6) & 0x3); - card->fairness = ((mdev->pos[2] >> 4) & 0x1); - - /* - * Ring Speed - */ - if ((mdev->pos[1] >> 2)&0x1) - card->ringspeed = 2; /* not selected */ - else if ((mdev->pos[2] >> 5) & 0x1) - card->ringspeed = 1; /* 16Mb */ - else - card->ringspeed = 0; /* 4Mb */ - - /* - * Cable type - */ - if ((mdev->pos[1] >> 6)&0x1) - card->cabletype = 1; /* STP/DB9 */ - else - card->cabletype = 0; /* UTP/RJ-45 */ - - - /* - * ROM Info. This requires us to actually twiddle - * bits on the card, so we must ensure above that - * the base address is free of conflict (request_region above). - */ - madgemc_read_rom(dev, card); - - if (card->manid != 0x4d) { /* something went wrong */ - printk(KERN_INFO "%s: Madge MC ROM read failed (unknown manufacturer ID %02x)\n", dev->name, card->manid); - goto getout3; - } - - if ((card->cardtype != 0x08) && (card->cardtype != 0x0d)) { - printk(KERN_INFO "%s: Madge MC ROM read failed (unknown card ID %02x)\n", dev->name, card->cardtype); - ret = -EIO; - goto getout3; - } - - /* All cards except Rev 0 and 1 MC16's have 256kb of RAM */ - if ((card->cardtype == 0x08) && (card->cardrev <= 0x01)) - card->ramsize = 128; - else - card->ramsize = 256; - - printk("%s: %s Rev %d at 0x%04lx IRQ %d\n", - dev->name, - (card->cardtype == 0x08)?MADGEMC16_CARDNAME: - MADGEMC32_CARDNAME, card->cardrev, - dev->base_addr, dev->irq); - - if (card->cardtype == 0x0d) - printk("%s: Warning: MC32 support is experimental and highly untested\n", dev->name); - - if (card->ringspeed==2) { /* Unknown */ - printk("%s: Warning: Ring speed not set in POS -- Please run the reference disk and set it!\n", dev->name); - card->ringspeed = 1; /* default to 16mb */ - } - - printk("%s: RAM Size: %dKB\n", dev->name, card->ramsize); - - printk("%s: Ring Speed: %dMb/sec on %s\n", dev->name, - (card->ringspeed)?16:4, - card->cabletype?"STP/DB9":"UTP/RJ-45"); - printk("%s: Arbitration Level: %d\n", dev->name, - card->arblevel); - - printk("%s: Burst Mode: ", dev->name); - switch(card->burstmode) { - case 0: printk("Cycle steal"); break; - case 1: printk("Limited burst"); break; - case 2: printk("Delayed release"); break; - case 3: printk("Immediate release"); break; - } - printk(" (%s)\n", (card->fairness)?"Unfair":"Fair"); - - - /* - * Enable SIF before we assign the interrupt handler, - * just in case we get spurious interrupts that need - * handling. - */ - outb(0, dev->base_addr + MC_CONTROL_REG0); /* sanity */ - madgemc_setsifsel(dev, 1); - if (request_irq(dev->irq, madgemc_interrupt, IRQF_SHARED, - "madgemc", dev)) { - ret = -EBUSY; - goto getout3; - } - - madgemc_chipset_init(dev); /* enables interrupts! */ - madgemc_setcabletype(dev, card->cabletype); - - /* Setup MCA structures */ - mca_device_set_name(mdev, (card->cardtype == 0x08)?MADGEMC16_CARDNAME:MADGEMC32_CARDNAME); - mca_set_adapter_procfn(mdev->slot, madgemc_mcaproc, dev); - - printk("%s: Ring Station Address: %pM\n", - dev->name, dev->dev_addr); - - if (tmsdev_init(dev, device)) { - printk("%s: unable to get memory for dev->priv.\n", - dev->name); - ret = -ENOMEM; - goto getout4; - } - tp = netdev_priv(dev); - - /* - * The MC16 is physically a 32bit card. However, Madge - * insists on calling it 16bit, so I'll assume here that - * they know what they're talking about. Cut off DMA - * at 16mb. - */ - tp->setnselout = madgemc_setnselout_pins; - tp->sifwriteb = madgemc_sifwriteb; - tp->sifreadb = madgemc_sifreadb; - tp->sifwritew = madgemc_sifwritew; - tp->sifreadw = madgemc_sifreadw; - tp->DataRate = (card->ringspeed)?SPEED_16:SPEED_4; - - memcpy(tp->ProductID, "Madge MCA 16/4 ", PROD_ID_SIZE + 1); - - tp->tmspriv = card; - dev_set_drvdata(device, dev); - - if (register_netdev(dev) == 0) - return 0; - - dev_set_drvdata(device, NULL); - ret = -ENOMEM; -getout4: - free_irq(dev->irq, dev); -getout3: - release_region(dev->base_addr-MADGEMC_SIF_OFFSET, - MADGEMC_IO_EXTENT); -getout2: - kfree(card); -getout1: - free_netdev(dev); -getout: - mca_device_set_claim(mdev, 0); - return ret; -} - -/* - * Handle interrupts generated by the card - * - * The MicroChannel Madge cards need slightly more handling - * after an interrupt than other TMS380 cards do. - * - * First we must make sure it was this card that generated the - * interrupt (since interrupt sharing is allowed). Then, - * because we're using level-triggered interrupts (as is - * standard on MCA), we must toggle the interrupt line - * on the card in order to claim and acknowledge the interrupt. - * Once that is done, the interrupt should be handlable in - * the normal tms380tr_interrupt() routine. - * - * There's two ways we can check to see if the interrupt is ours, - * both with their own disadvantages... - * - * 1) Read in the SIFSTS register from the TMS controller. This - * is guaranteed to be accurate, however, there's a fairly - * large performance penalty for doing so: the Madge chips - * must request the register from the Eagle, the Eagle must - * read them from its internal bus, and then take the route - * back out again, for a 16bit read. - * - * 2) Use the MC_CONTROL_REG0_SINTR bit from the Madge ASICs. - * The major disadvantage here is that the accuracy of the - * bit is in question. However, it cuts out the extra read - * cycles it takes to read the Eagle's SIF, as its only an - * 8bit read, and theoretically the Madge bit is directly - * connected to the interrupt latch coming out of the Eagle - * hardware (that statement is not verified). - * - * I can't determine which of these methods has the best win. For now, - * we make a compromise. Use the Madge way for the first interrupt, - * which should be the fast-path, and then once we hit the first - * interrupt, keep on trying using the SIF method until we've - * exhausted all contiguous interrupts. - * - */ -static irqreturn_t madgemc_interrupt(int irq, void *dev_id) -{ - int pending,reg1; - struct net_device *dev; - - if (!dev_id) { - printk("madgemc_interrupt: was not passed a dev_id!\n"); - return IRQ_NONE; - } - - dev = dev_id; - - /* Make sure its really us. -- the Madge way */ - pending = inb(dev->base_addr + MC_CONTROL_REG0); - if (!(pending & MC_CONTROL_REG0_SINTR)) - return IRQ_NONE; /* not our interrupt */ - - /* - * Since we're level-triggered, we may miss the rising edge - * of the next interrupt while we're off handling this one, - * so keep checking until the SIF verifies that it has nothing - * left for us to do. - */ - pending = STS_SYSTEM_IRQ; - do { - if (pending & STS_SYSTEM_IRQ) { - - /* Toggle the interrupt to reset the latch on card */ - reg1 = inb(dev->base_addr + MC_CONTROL_REG1); - outb(reg1 ^ MC_CONTROL_REG1_SINTEN, - dev->base_addr + MC_CONTROL_REG1); - outb(reg1, dev->base_addr + MC_CONTROL_REG1); - - /* Continue handling as normal */ - tms380tr_interrupt(irq, dev_id); - - pending = SIFREADW(SIFSTS); /* restart - the SIF way */ - - } else - return IRQ_HANDLED; - } while (1); - - return IRQ_HANDLED; /* not reachable */ -} - -/* - * Set the card to the preferred ring speed. - * - * Unlike newer cards, the MC16/32 have their speed selection - * circuit connected to the Madge ASICs and not to the TMS380 - * NSELOUT pins. Set the ASIC bits correctly here, and return - * zero to leave the TMS NSELOUT bits unaffected. - * - */ -static unsigned short madgemc_setnselout_pins(struct net_device *dev) -{ - unsigned char reg1; - struct net_local *tp = netdev_priv(dev); - - reg1 = inb(dev->base_addr + MC_CONTROL_REG1); - - if(tp->DataRate == SPEED_16) - reg1 |= MC_CONTROL_REG1_SPEED_SEL; /* add for 16mb */ - else if (reg1 & MC_CONTROL_REG1_SPEED_SEL) - reg1 ^= MC_CONTROL_REG1_SPEED_SEL; /* remove for 4mb */ - outb(reg1, dev->base_addr + MC_CONTROL_REG1); - - return 0; /* no change */ -} - -/* - * Set the register page. This equates to the SRSX line - * on the TMS380Cx6. - * - * Register selection is normally done via three contiguous - * bits. However, some boards (such as the MC16/32) use only - * two bits, plus a separate bit in the glue chip. This - * sets the SRSX bit (the top bit). See page 4-17 in the - * Yellow Book for which registers are affected. - * - */ -static void madgemc_setregpage(struct net_device *dev, int page) -{ - static int reg1; - - reg1 = inb(dev->base_addr + MC_CONTROL_REG1); - if ((page == 0) && (reg1 & MC_CONTROL_REG1_SRSX)) { - outb(reg1 ^ MC_CONTROL_REG1_SRSX, - dev->base_addr + MC_CONTROL_REG1); - } - else if (page == 1) { - outb(reg1 | MC_CONTROL_REG1_SRSX, - dev->base_addr + MC_CONTROL_REG1); - } - reg1 = inb(dev->base_addr + MC_CONTROL_REG1); -} - -/* - * The SIF registers are not mapped into register space by default - * Set this to 1 to map them, 0 to map the BIA ROM. - * - */ -static void madgemc_setsifsel(struct net_device *dev, int val) -{ - unsigned int reg0; - - reg0 = inb(dev->base_addr + MC_CONTROL_REG0); - if ((val == 0) && (reg0 & MC_CONTROL_REG0_SIFSEL)) { - outb(reg0 ^ MC_CONTROL_REG0_SIFSEL, - dev->base_addr + MC_CONTROL_REG0); - } else if (val == 1) { - outb(reg0 | MC_CONTROL_REG0_SIFSEL, - dev->base_addr + MC_CONTROL_REG0); - } - reg0 = inb(dev->base_addr + MC_CONTROL_REG0); -} - -/* - * Enable SIF interrupts - * - * This does not enable interrupts in the SIF, but rather - * enables SIF interrupts to be passed onto the host. - * - */ -static void madgemc_setint(struct net_device *dev, int val) -{ - unsigned int reg1; - - reg1 = inb(dev->base_addr + MC_CONTROL_REG1); - if ((val == 0) && (reg1 & MC_CONTROL_REG1_SINTEN)) { - outb(reg1 ^ MC_CONTROL_REG1_SINTEN, - dev->base_addr + MC_CONTROL_REG1); - } else if (val == 1) { - outb(reg1 | MC_CONTROL_REG1_SINTEN, - dev->base_addr + MC_CONTROL_REG1); - } -} - -/* - * Cable type is set via control register 7. Bit zero high - * for UTP, low for STP. - */ -static void madgemc_setcabletype(struct net_device *dev, int type) -{ - outb((type==0)?MC_CONTROL_REG7_CABLEUTP:MC_CONTROL_REG7_CABLESTP, - dev->base_addr + MC_CONTROL_REG7); -} - -/* - * Enable the functions of the Madge chipset needed for - * full working order. - */ -static int madgemc_chipset_init(struct net_device *dev) -{ - outb(0, dev->base_addr + MC_CONTROL_REG1); /* pull SRESET low */ - tms380tr_wait(100); /* wait for card to reset */ - - /* bring back into normal operating mode */ - outb(MC_CONTROL_REG1_NSRESET, dev->base_addr + MC_CONTROL_REG1); - - /* map SIF registers */ - madgemc_setsifsel(dev, 1); - - /* enable SIF interrupts */ - madgemc_setint(dev, 1); - - return 0; -} - -/* - * Disable the board, and put back into power-up state. - */ -static void madgemc_chipset_close(struct net_device *dev) -{ - /* disable interrupts */ - madgemc_setint(dev, 0); - /* unmap SIF registers */ - madgemc_setsifsel(dev, 0); -} - -/* - * Read the card type (MC16 or MC32) from the card. - * - * The configuration registers are stored in two separate - * pages. Pages are flipped by clearing bit 3 of CONTROL_REG0 (PAGE) - * for page zero, or setting bit 3 for page one. - * - * Page zero contains the following data: - * Byte 0: Manufacturer ID (0x4D -- ASCII "M") - * Byte 1: Card type: - * 0x08 for MC16 - * 0x0D for MC32 - * Byte 2: Card revision - * Byte 3: Mirror of POS config register 0 - * Byte 4: Mirror of POS 1 - * Byte 5: Mirror of POS 2 - * - * Page one contains the following data: - * Byte 0: Unused - * Byte 1-6: BIA, MSB to LSB. - * - * Note that to read the BIA, we must unmap the SIF registers - * by clearing bit 2 of CONTROL_REG0 (SIFSEL), as the data - * will reside in the same logical location. For this reason, - * _never_ read the BIA while the Eagle processor is running! - * The SIF will be completely inaccessible until the BIA operation - * is complete. - * - */ -static void madgemc_read_rom(struct net_device *dev, struct card_info *card) -{ - unsigned long ioaddr; - unsigned char reg0, reg1, tmpreg0, i; - - ioaddr = dev->base_addr; - - reg0 = inb(ioaddr + MC_CONTROL_REG0); - reg1 = inb(ioaddr + MC_CONTROL_REG1); - - /* Switch to page zero and unmap SIF */ - tmpreg0 = reg0 & ~(MC_CONTROL_REG0_PAGE + MC_CONTROL_REG0_SIFSEL); - outb(tmpreg0, ioaddr + MC_CONTROL_REG0); - - card->manid = inb(ioaddr + MC_ROM_MANUFACTURERID); - card->cardtype = inb(ioaddr + MC_ROM_ADAPTERID); - card->cardrev = inb(ioaddr + MC_ROM_REVISION); - - /* Switch to rom page one */ - outb(tmpreg0 | MC_CONTROL_REG0_PAGE, ioaddr + MC_CONTROL_REG0); - - /* Read BIA */ - dev->addr_len = 6; - for (i = 0; i < 6; i++) - dev->dev_addr[i] = inb(ioaddr + MC_ROM_BIA_START + i); - - /* Restore original register values */ - outb(reg0, ioaddr + MC_CONTROL_REG0); - outb(reg1, ioaddr + MC_CONTROL_REG1); -} - -static int madgemc_open(struct net_device *dev) -{ - /* - * Go ahead and reinitialize the chipset again, just to - * make sure we didn't get left in a bad state. - */ - madgemc_chipset_init(dev); - tms380tr_open(dev); - return 0; -} - -static int madgemc_close(struct net_device *dev) -{ - tms380tr_close(dev); - madgemc_chipset_close(dev); - return 0; -} - -/* - * Give some details available from /proc/mca/slotX - */ -static int madgemc_mcaproc(char *buf, int slot, void *d) -{ - struct net_device *dev = (struct net_device *)d; - struct net_local *tp = netdev_priv(dev); - struct card_info *curcard = tp->tmspriv; - int len = 0; - - len += sprintf(buf+len, "-------\n"); - if (curcard) { - len += sprintf(buf+len, "Card Revision: %d\n", curcard->cardrev); - len += sprintf(buf+len, "RAM Size: %dkb\n", curcard->ramsize); - len += sprintf(buf+len, "Cable type: %s\n", (curcard->cabletype)?"STP/DB9":"UTP/RJ-45"); - len += sprintf(buf+len, "Configured ring speed: %dMb/sec\n", (curcard->ringspeed)?16:4); - len += sprintf(buf+len, "Running ring speed: %dMb/sec\n", (tp->DataRate==SPEED_16)?16:4); - len += sprintf(buf+len, "Device: %s\n", dev->name); - len += sprintf(buf+len, "IO Port: 0x%04lx\n", dev->base_addr); - len += sprintf(buf+len, "IRQ: %d\n", dev->irq); - len += sprintf(buf+len, "Arbitration Level: %d\n", curcard->arblevel); - len += sprintf(buf+len, "Burst Mode: "); - switch(curcard->burstmode) { - case 0: len += sprintf(buf+len, "Cycle steal"); break; - case 1: len += sprintf(buf+len, "Limited burst"); break; - case 2: len += sprintf(buf+len, "Delayed release"); break; - case 3: len += sprintf(buf+len, "Immediate release"); break; - } - len += sprintf(buf+len, " (%s)\n", (curcard->fairness)?"Unfair":"Fair"); - - len += sprintf(buf+len, "Ring Station Address: %pM\n", - dev->dev_addr); - } else - len += sprintf(buf+len, "Card not configured\n"); - - return len; -} - -static int __devexit madgemc_remove(struct device *device) -{ - struct net_device *dev = dev_get_drvdata(device); - struct net_local *tp; - struct card_info *card; - - BUG_ON(!dev); - - tp = netdev_priv(dev); - card = tp->tmspriv; - kfree(card); - tp->tmspriv = NULL; - - unregister_netdev(dev); - release_region(dev->base_addr-MADGEMC_SIF_OFFSET, MADGEMC_IO_EXTENT); - free_irq(dev->irq, dev); - tmsdev_term(dev); - free_netdev(dev); - dev_set_drvdata(device, NULL); - - return 0; -} - -static short madgemc_adapter_ids[] __initdata = { - 0x002d, - 0x0000 -}; - -static struct mca_driver madgemc_driver = { - .id_table = madgemc_adapter_ids, - .driver = { - .name = "madgemc", - .bus = &mca_bus_type, - .probe = madgemc_probe, - .remove = __devexit_p(madgemc_remove), - }, -}; - -static int __init madgemc_init (void) -{ - madgemc_netdev_ops = tms380tr_netdev_ops; - madgemc_netdev_ops.ndo_open = madgemc_open; - madgemc_netdev_ops.ndo_stop = madgemc_close; - - return mca_register_driver (&madgemc_driver); -} - -static void __exit madgemc_exit (void) -{ - mca_unregister_driver (&madgemc_driver); -} - -module_init(madgemc_init); -module_exit(madgemc_exit); - -MODULE_LICENSE("GPL"); - diff --git a/trunk/drivers/net/tokenring/madgemc.h b/trunk/drivers/net/tokenring/madgemc.h deleted file mode 100644 index fe88e272c531..000000000000 --- a/trunk/drivers/net/tokenring/madgemc.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * madgemc.h: Header for the madgemc tms380tr module - * - * Authors: - * - Adam Fritzler - */ - -#ifndef __LINUX_MADGEMC_H -#define __LINUX_MADGEMC_H - -#ifdef __KERNEL__ - -#define MADGEMC16_CARDNAME "Madge Smart 16/4 MC16 Ringnode" -#define MADGEMC32_CARDNAME "Madge Smart 16/4 MC32 Ringnode" - -/* - * Bit definitions for the POS config registers - */ -#define MC16_POS0_ADDR1 0x20 -#define MC16_POS2_ADDR2 0x04 -#define MC16_POS3_ADDR3 0x20 - -#define MC_CONTROL_REG0 ((long)-8) /* 0x00 */ -#define MC_CONTROL_REG1 ((long)-7) /* 0x01 */ -#define MC_ADAPTER_POS_REG0 ((long)-6) /* 0x02 */ -#define MC_ADAPTER_POS_REG1 ((long)-5) /* 0x03 */ -#define MC_ADAPTER_POS_REG2 ((long)-4) /* 0x04 */ -#define MC_ADAPTER_REG5_UNUSED ((long)-3) /* 0x05 */ -#define MC_ADAPTER_REG6_UNUSED ((long)-2) /* 0x06 */ -#define MC_CONTROL_REG7 ((long)-1) /* 0x07 */ - -#define MC_CONTROL_REG0_UNKNOWN1 0x01 -#define MC_CONTROL_REG0_UNKNOWN2 0x02 -#define MC_CONTROL_REG0_SIFSEL 0x04 -#define MC_CONTROL_REG0_PAGE 0x08 -#define MC_CONTROL_REG0_TESTINTERRUPT 0x10 -#define MC_CONTROL_REG0_UNKNOWN20 0x20 -#define MC_CONTROL_REG0_SINTR 0x40 -#define MC_CONTROL_REG0_UNKNOWN80 0x80 - -#define MC_CONTROL_REG1_SINTEN 0x01 -#define MC_CONTROL_REG1_BITOFDEATH 0x02 -#define MC_CONTROL_REG1_NSRESET 0x04 -#define MC_CONTROL_REG1_UNKNOWN8 0x08 -#define MC_CONTROL_REG1_UNKNOWN10 0x10 -#define MC_CONTROL_REG1_UNKNOWN20 0x20 -#define MC_CONTROL_REG1_SRSX 0x40 -#define MC_CONTROL_REG1_SPEED_SEL 0x80 - -#define MC_CONTROL_REG7_CABLESTP 0x00 -#define MC_CONTROL_REG7_CABLEUTP 0x01 - -/* - * ROM Page Zero - */ -#define MC_ROM_MANUFACTURERID 0x00 -#define MC_ROM_ADAPTERID 0x01 -#define MC_ROM_REVISION 0x02 -#define MC_ROM_CONFIG0 0x03 -#define MC_ROM_CONFIG1 0x04 -#define MC_ROM_CONFIG2 0x05 - -/* - * ROM Page One - */ -#define MC_ROM_UNUSED_BYTE 0x00 -#define MC_ROM_BIA_START 0x01 - -#endif /* __KERNEL__ */ -#endif /* __LINUX_MADGEMC_H */ diff --git a/trunk/drivers/net/tokenring/olympic.c b/trunk/drivers/net/tokenring/olympic.c deleted file mode 100644 index 0e234741cc79..000000000000 --- a/trunk/drivers/net/tokenring/olympic.c +++ /dev/null @@ -1,1749 +0,0 @@ -/* - * olympic.c (c) 1999 Peter De Schrijver All Rights Reserved - * 1999/2000 Mike Phillips (mikep@linuxtr.net) - * - * Linux driver for IBM PCI tokenring cards based on the Pit/Pit-Phy/Olympic - * chipset. - * - * Base Driver Skeleton: - * Written 1993-94 by Donald Becker. - * - * Copyright 1993 United States Government as represented by the - * Director, National Security Agency. - * - * Thanks to Erik De Cock, Adrian Bridgett and Frank Fiene for their - * assistance and perserverance with the testing of this driver. - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * 4/27/99 - Alpha Release 0.1.0 - * First release to the public - * - * 6/8/99 - Official Release 0.2.0 - * Merged into the kernel code - * 8/18/99 - Updated driver for 2.3.13 kernel to use new pci - * resource. Driver also reports the card name returned by - * the pci resource. - * 1/11/00 - Added spinlocks for smp - * 2/23/00 - Updated to dev_kfree_irq - * 3/10/00 - Fixed FDX enable which triggered other bugs also - * squashed. - * 5/20/00 - Changes to handle Olympic on LinuxPPC. Endian changes. - * The odd thing about the changes is that the fix for - * endian issues with the big-endian data in the arb, asb... - * was to always swab() the bytes, no matter what CPU. - * That's because the read[wl]() functions always swap the - * bytes on the way in on PPC. - * Fixing the hardware descriptors was another matter, - * because they weren't going through read[wl](), there all - * the results had to be in memory in le32 values. kdaaker - * - * 12/23/00 - Added minimal Cardbus support (Thanks Donald). - * - * 03/09/01 - Add new pci api, dev_base_lock, general clean up. - * - * 03/27/01 - Add new dma pci (Thanks to Kyle Lucke) and alloc_trdev - * Change proc_fs behaviour, now one entry per adapter. - * - * 04/09/01 - Couple of bug fixes to the dma unmaps and ejecting the - * adapter when live does not take the system down with it. - * - * 06/02/01 - Clean up, copy skb for small packets - * - * 06/22/01 - Add EISR error handling routines - * - * 07/19/01 - Improve bad LAA reporting, strip out freemem - * into a separate function, its called from 3 - * different places now. - * 02/09/02 - Replaced sleep_on. - * 03/01/02 - Replace access to several registers from 32 bit to - * 16 bit. Fixes alignment errors on PPC 64 bit machines. - * Thanks to Al Trautman for this one. - * 03/10/02 - Fix BUG in arb_cmd. Bug was there all along but was - * silently ignored until the error checking code - * went into version 1.0.0 - * 06/04/02 - Add correct start up sequence for the cardbus adapters. - * Required for strict compliance with pci power mgmt specs. - * To Do: - * - * Wake on lan - * - * If Problems do Occur - * Most problems can be rectified by either closing and opening the interface - * (ifconfig down and up) or rmmod and insmod'ing the driver (a bit difficult - * if compiled into the kernel). - */ - -/* Change OLYMPIC_DEBUG to 1 to get verbose, and I mean really verbose, messages */ - -#define OLYMPIC_DEBUG 0 - - -#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 "olympic.h" - -/* I've got to put some intelligence into the version number so that Peter and I know - * which version of the code somebody has got. - * Version Number = a.b.c.d where a.b.c is the level of code and d is the latest author. - * So 0.0.1.pds = Peter, 0.0.1.mlp = Mike - * - * Official releases will only have an a.b.c version number format. - */ - -static char version[] = -"Olympic.c v1.0.5 6/04/02 - Peter De Schrijver & Mike Phillips" ; - -static char *open_maj_error[] = {"No error", "Lobe Media Test", "Physical Insertion", - "Address Verification", "Neighbor Notification (Ring Poll)", - "Request Parameters","FDX Registration Request", - "FDX Duplicate Address Check", "Station registration Query Wait", - "Unknown stage"}; - -static char *open_min_error[] = {"No error", "Function Failure", "Signal Lost", "Wire Fault", - "Ring Speed Mismatch", "Timeout","Ring Failure","Ring Beaconing", - "Duplicate Node Address","Request Parameters","Remove Received", - "Reserved", "Reserved", "No Monitor Detected for RPL", - "Monitor Contention failer for RPL", "FDX Protocol Error"}; - -/* Module parameters */ - -MODULE_AUTHOR("Mike Phillips ") ; -MODULE_DESCRIPTION("Olympic PCI/Cardbus Chipset Driver") ; - -/* Ring Speed 0,4,16,100 - * 0 = Autosense - * 4,16 = Selected speed only, no autosense - * This allows the card to be the first on the ring - * and become the active monitor. - * 100 = Nothing at present, 100mbps is autodetected - * if FDX is turned on. May be implemented in the future to - * fail if 100mpbs is not detected. - * - * WARNING: Some hubs will allow you to insert - * at the wrong speed - */ - -static int ringspeed[OLYMPIC_MAX_ADAPTERS] = {0,} ; -module_param_array(ringspeed, int, NULL, 0); - -/* Packet buffer size */ - -static int pkt_buf_sz[OLYMPIC_MAX_ADAPTERS] = {0,} ; -module_param_array(pkt_buf_sz, int, NULL, 0) ; - -/* Message Level */ - -static int message_level[OLYMPIC_MAX_ADAPTERS] = {0,} ; -module_param_array(message_level, int, NULL, 0) ; - -/* Change network_monitor to receive mac frames through the arb channel. - * Will also create a /proc/net/olympic_tr%d entry, where %d is the tr - * device, i.e. tr0, tr1 etc. - * Intended to be used to create a ring-error reporting network module - * i.e. it will give you the source address of beaconers on the ring - */ -static int network_monitor[OLYMPIC_MAX_ADAPTERS] = {0,}; -module_param_array(network_monitor, int, NULL, 0); - -static DEFINE_PCI_DEVICE_TABLE(olympic_pci_tbl) = { - {PCI_VENDOR_ID_IBM,PCI_DEVICE_ID_IBM_TR_WAKE,PCI_ANY_ID,PCI_ANY_ID,}, - { } /* Terminating Entry */ -}; -MODULE_DEVICE_TABLE(pci,olympic_pci_tbl) ; - - -static int olympic_probe(struct pci_dev *pdev, const struct pci_device_id *ent); -static int olympic_init(struct net_device *dev); -static int olympic_open(struct net_device *dev); -static netdev_tx_t olympic_xmit(struct sk_buff *skb, - struct net_device *dev); -static int olympic_close(struct net_device *dev); -static void olympic_set_rx_mode(struct net_device *dev); -static void olympic_freemem(struct net_device *dev) ; -static irqreturn_t olympic_interrupt(int irq, void *dev_id); -static int olympic_set_mac_address(struct net_device *dev, void *addr) ; -static void olympic_arb_cmd(struct net_device *dev); -static int olympic_change_mtu(struct net_device *dev, int mtu); -static void olympic_srb_bh(struct net_device *dev) ; -static void olympic_asb_bh(struct net_device *dev) ; -static const struct file_operations olympic_proc_ops; - -static const struct net_device_ops olympic_netdev_ops = { - .ndo_open = olympic_open, - .ndo_stop = olympic_close, - .ndo_start_xmit = olympic_xmit, - .ndo_change_mtu = olympic_change_mtu, - .ndo_set_rx_mode = olympic_set_rx_mode, - .ndo_set_mac_address = olympic_set_mac_address, -}; - -static int __devinit olympic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - struct net_device *dev ; - struct olympic_private *olympic_priv; - static int card_no = -1 ; - int i ; - - card_no++ ; - - if ((i = pci_enable_device(pdev))) { - return i ; - } - - pci_set_master(pdev); - - if ((i = pci_request_regions(pdev,"olympic"))) { - goto op_disable_dev; - } - - dev = alloc_trdev(sizeof(struct olympic_private)) ; - if (!dev) { - i = -ENOMEM; - goto op_release_dev; - } - - olympic_priv = netdev_priv(dev) ; - - spin_lock_init(&olympic_priv->olympic_lock) ; - - init_waitqueue_head(&olympic_priv->srb_wait); - init_waitqueue_head(&olympic_priv->trb_wait); -#if OLYMPIC_DEBUG - printk(KERN_INFO "pci_device: %p, dev:%p, dev->priv: %p\n", pdev, dev, netdev_priv(dev)); -#endif - dev->irq=pdev->irq; - dev->base_addr=pci_resource_start(pdev, 0); - olympic_priv->olympic_card_name = pci_name(pdev); - olympic_priv->pdev = pdev; - olympic_priv->olympic_mmio = ioremap(pci_resource_start(pdev,1),256); - olympic_priv->olympic_lap = ioremap(pci_resource_start(pdev,2),2048); - if (!olympic_priv->olympic_mmio || !olympic_priv->olympic_lap) { - goto op_free_iomap; - } - - if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000) ) - olympic_priv->pkt_buf_sz = PKT_BUF_SZ ; - else - olympic_priv->pkt_buf_sz = pkt_buf_sz[card_no] ; - - dev->mtu = olympic_priv->pkt_buf_sz - TR_HLEN ; - olympic_priv->olympic_ring_speed = ringspeed[card_no] ; - olympic_priv->olympic_message_level = message_level[card_no] ; - olympic_priv->olympic_network_monitor = network_monitor[card_no]; - - if ((i = olympic_init(dev))) { - goto op_free_iomap; - } - - dev->netdev_ops = &olympic_netdev_ops; - SET_NETDEV_DEV(dev, &pdev->dev); - - pci_set_drvdata(pdev,dev) ; - register_netdev(dev) ; - printk("Olympic: %s registered as: %s\n",olympic_priv->olympic_card_name,dev->name); - if (olympic_priv->olympic_network_monitor) { /* Must go after register_netdev as we need the device name */ - char proc_name[20] ; - strcpy(proc_name,"olympic_") ; - strcat(proc_name,dev->name) ; - proc_create_data(proc_name, 0, init_net.proc_net, &olympic_proc_ops, dev); - printk("Olympic: Network Monitor information: /proc/%s\n",proc_name); - } - return 0 ; - -op_free_iomap: - if (olympic_priv->olympic_mmio) - iounmap(olympic_priv->olympic_mmio); - if (olympic_priv->olympic_lap) - iounmap(olympic_priv->olympic_lap); - - free_netdev(dev); -op_release_dev: - pci_release_regions(pdev); - -op_disable_dev: - pci_disable_device(pdev); - return i; -} - -static int olympic_init(struct net_device *dev) -{ - struct olympic_private *olympic_priv; - u8 __iomem *olympic_mmio, *init_srb,*adapter_addr; - unsigned long t; - unsigned int uaa_addr; - - olympic_priv=netdev_priv(dev); - olympic_mmio=olympic_priv->olympic_mmio; - - printk("%s\n", version); - printk("%s. I/O at %hx, MMIO at %p, LAP at %p, using irq %d\n", olympic_priv->olympic_card_name, (unsigned int) dev->base_addr,olympic_priv->olympic_mmio, olympic_priv->olympic_lap, dev->irq); - - writel(readl(olympic_mmio+BCTL) | BCTL_SOFTRESET,olympic_mmio+BCTL); - t=jiffies; - while((readl(olympic_mmio+BCTL)) & BCTL_SOFTRESET) { - schedule(); - if(time_after(jiffies, t + 40*HZ)) { - printk(KERN_ERR "IBM PCI tokenring card not responding.\n"); - return -ENODEV; - } - } - - - /* Needed for cardbus */ - if(!(readl(olympic_mmio+BCTL) & BCTL_MODE_INDICATOR)) { - writel(readl(olympic_priv->olympic_mmio+FERMASK)|FERMASK_INT_BIT, olympic_mmio+FERMASK); - } - -#if OLYMPIC_DEBUG - printk("BCTL: %x\n",readl(olympic_mmio+BCTL)); - printk("GPR: %x\n",readw(olympic_mmio+GPR)); - printk("SISRMASK: %x\n",readl(olympic_mmio+SISR_MASK)); -#endif - /* Aaaahhh, You have got to be real careful setting GPR, the card - holds the previous values from flash memory, including autosense - and ring speed */ - - writel(readl(olympic_mmio+BCTL)|BCTL_MIMREB,olympic_mmio+BCTL); - - if (olympic_priv->olympic_ring_speed == 0) { /* Autosense */ - writew(readw(olympic_mmio+GPR)|GPR_AUTOSENSE,olympic_mmio+GPR); - if (olympic_priv->olympic_message_level) - printk(KERN_INFO "%s: Ringspeed autosense mode on\n",olympic_priv->olympic_card_name); - } else if (olympic_priv->olympic_ring_speed == 16) { - if (olympic_priv->olympic_message_level) - printk(KERN_INFO "%s: Trying to open at 16 Mbps as requested\n", olympic_priv->olympic_card_name); - writew(GPR_16MBPS, olympic_mmio+GPR); - } else if (olympic_priv->olympic_ring_speed == 4) { - if (olympic_priv->olympic_message_level) - printk(KERN_INFO "%s: Trying to open at 4 Mbps as requested\n", olympic_priv->olympic_card_name) ; - writew(0, olympic_mmio+GPR); - } - - writew(readw(olympic_mmio+GPR)|GPR_NEPTUNE_BF,olympic_mmio+GPR); - -#if OLYMPIC_DEBUG - printk("GPR = %x\n",readw(olympic_mmio + GPR) ) ; -#endif - /* Solo has been paused to meet the Cardbus power - * specs if the adapter is cardbus. Check to - * see its been paused and then restart solo. The - * adapter should set the pause bit within 1 second. - */ - - if(!(readl(olympic_mmio+BCTL) & BCTL_MODE_INDICATOR)) { - t=jiffies; - while (!(readl(olympic_mmio+CLKCTL) & CLKCTL_PAUSE)) { - schedule() ; - if(time_after(jiffies, t + 2*HZ)) { - printk(KERN_ERR "IBM Cardbus tokenring adapter not responsing.\n") ; - return -ENODEV; - } - } - writel(readl(olympic_mmio+CLKCTL) & ~CLKCTL_PAUSE, olympic_mmio+CLKCTL) ; - } - - /* start solo init */ - writel((1<<15),olympic_mmio+SISR_MASK_SUM); - - t=jiffies; - while(!((readl(olympic_mmio+SISR_RR)) & SISR_SRB_REPLY)) { - schedule(); - if(time_after(jiffies, t + 15*HZ)) { - printk(KERN_ERR "IBM PCI tokenring card not responding.\n"); - return -ENODEV; - } - } - - writel(readw(olympic_mmio+LAPWWO),olympic_mmio+LAPA); - -#if OLYMPIC_DEBUG - printk("LAPWWO: %x, LAPA: %x\n",readl(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA)); -#endif - - init_srb=olympic_priv->olympic_lap + ((readw(olympic_mmio+LAPWWO)) & (~0xf800)); - -#if OLYMPIC_DEBUG -{ - int i; - printk("init_srb(%p): ",init_srb); - for(i=0;i<20;i++) - printk("%x ",readb(init_srb+i)); - printk("\n"); -} -#endif - if(readw(init_srb+6)) { - printk(KERN_INFO "tokenring card initialization failed. errorcode : %x\n",readw(init_srb+6)); - return -ENODEV; - } - - if (olympic_priv->olympic_message_level) { - if ( readb(init_srb +2) & 0x40) { - printk(KERN_INFO "Olympic: Adapter is FDX capable.\n") ; - } else { - printk(KERN_INFO "Olympic: Adapter cannot do FDX.\n"); - } - } - - uaa_addr=swab16(readw(init_srb+8)); - -#if OLYMPIC_DEBUG - printk("UAA resides at %x\n",uaa_addr); -#endif - - writel(uaa_addr,olympic_mmio+LAPA); - adapter_addr=olympic_priv->olympic_lap + (uaa_addr & (~0xf800)); - - memcpy_fromio(&dev->dev_addr[0], adapter_addr,6); - -#if OLYMPIC_DEBUG - printk("adapter address: %pM\n", dev->dev_addr); -#endif - - olympic_priv->olympic_addr_table_addr = swab16(readw(init_srb + 12)); - olympic_priv->olympic_parms_addr = swab16(readw(init_srb + 14)); - - return 0; - -} - -static int olympic_open(struct net_device *dev) -{ - struct olympic_private *olympic_priv=netdev_priv(dev); - u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio,*init_srb; - unsigned long flags, t; - int i, open_finished = 1 ; - u8 resp, err; - - DECLARE_WAITQUEUE(wait,current) ; - - olympic_init(dev); - - if (request_irq(dev->irq, olympic_interrupt, IRQF_SHARED , "olympic", - dev)) - return -EAGAIN; - -#if OLYMPIC_DEBUG - printk("BMCTL: %x\n",readl(olympic_mmio+BMCTL_SUM)); - printk("pending ints: %x\n",readl(olympic_mmio+SISR_RR)); -#endif - - writel(SISR_MI,olympic_mmio+SISR_MASK_SUM); - - writel(SISR_MI | SISR_SRB_REPLY, olympic_mmio+SISR_MASK); /* more ints later, doesn't stop arb cmd interrupt */ - - writel(LISR_LIE,olympic_mmio+LISR); /* more ints later */ - - /* adapter is closed, so SRB is pointed to by LAPWWO */ - - writel(readw(olympic_mmio+LAPWWO),olympic_mmio+LAPA); - init_srb=olympic_priv->olympic_lap + ((readw(olympic_mmio+LAPWWO)) & (~0xf800)); - -#if OLYMPIC_DEBUG - printk("LAPWWO: %x, LAPA: %x\n",readw(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA)); - printk("SISR Mask = %04x\n", readl(olympic_mmio+SISR_MASK)); - printk("Before the open command\n"); -#endif - do { - memset_io(init_srb,0,SRB_COMMAND_SIZE); - - writeb(SRB_OPEN_ADAPTER,init_srb) ; /* open */ - writeb(OLYMPIC_CLEAR_RET_CODE,init_srb+2); - - /* If Network Monitor, instruct card to copy MAC frames through the ARB */ - if (olympic_priv->olympic_network_monitor) - writew(swab16(OPEN_ADAPTER_ENABLE_FDX | OPEN_ADAPTER_PASS_ADC_MAC | OPEN_ADAPTER_PASS_ATT_MAC | OPEN_ADAPTER_PASS_BEACON), init_srb+8); - else - writew(swab16(OPEN_ADAPTER_ENABLE_FDX), init_srb+8); - - /* Test OR of first 3 bytes as its totally possible for - * someone to set the first 2 bytes to be zero, although this - * is an error, the first byte must have bit 6 set to 1 */ - - if (olympic_priv->olympic_laa[0] | olympic_priv->olympic_laa[1] | olympic_priv->olympic_laa[2]) { - writeb(olympic_priv->olympic_laa[0],init_srb+12); - writeb(olympic_priv->olympic_laa[1],init_srb+13); - writeb(olympic_priv->olympic_laa[2],init_srb+14); - writeb(olympic_priv->olympic_laa[3],init_srb+15); - writeb(olympic_priv->olympic_laa[4],init_srb+16); - writeb(olympic_priv->olympic_laa[5],init_srb+17); - memcpy(dev->dev_addr,olympic_priv->olympic_laa,dev->addr_len) ; - } - writeb(1,init_srb+30); - - spin_lock_irqsave(&olympic_priv->olympic_lock,flags); - olympic_priv->srb_queued=1; - - writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); - spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags); - - t = jiffies ; - - add_wait_queue(&olympic_priv->srb_wait,&wait) ; - set_current_state(TASK_INTERRUPTIBLE) ; - - while(olympic_priv->srb_queued) { - schedule() ; - if(signal_pending(current)) { - printk(KERN_WARNING "%s: Signal received in open.\n", - dev->name); - printk(KERN_WARNING "SISR=%x LISR=%x\n", - readl(olympic_mmio+SISR), - readl(olympic_mmio+LISR)); - olympic_priv->srb_queued=0; - break; - } - if (time_after(jiffies, t + 10*HZ)) { - printk(KERN_WARNING "%s: SRB timed out.\n",dev->name); - olympic_priv->srb_queued=0; - break ; - } - set_current_state(TASK_INTERRUPTIBLE) ; - } - remove_wait_queue(&olympic_priv->srb_wait,&wait) ; - set_current_state(TASK_RUNNING) ; - olympic_priv->srb_queued = 0 ; -#if OLYMPIC_DEBUG - printk("init_srb(%p): ",init_srb); - for(i=0;i<20;i++) - printk("%02x ",readb(init_srb+i)); - printk("\n"); -#endif - - /* If we get the same return response as we set, the interrupt wasn't raised and the open - * timed out. - */ - - switch (resp = readb(init_srb+2)) { - case OLYMPIC_CLEAR_RET_CODE: - printk(KERN_WARNING "%s: Adapter Open time out or error.\n", dev->name) ; - goto out; - case 0: - open_finished = 1; - break; - case 0x07: - if (!olympic_priv->olympic_ring_speed && open_finished) { /* Autosense , first time around */ - printk(KERN_WARNING "%s: Retrying at different ring speed\n", dev->name); - open_finished = 0 ; - continue; - } - - err = readb(init_srb+7); - - if (!olympic_priv->olympic_ring_speed && ((err & 0x0f) == 0x0d)) { - printk(KERN_WARNING "%s: Tried to autosense ring speed with no monitors present\n",dev->name); - printk(KERN_WARNING "%s: Please try again with a specified ring speed\n",dev->name); - } else { - printk(KERN_WARNING "%s: %s - %s\n", dev->name, - open_maj_error[(err & 0xf0) >> 4], - open_min_error[(err & 0x0f)]); - } - goto out; - - case 0x32: - printk(KERN_WARNING "%s: Invalid LAA: %pM\n", - dev->name, olympic_priv->olympic_laa); - goto out; - - default: - printk(KERN_WARNING "%s: Bad OPEN response: %x\n", dev->name, resp); - goto out; - - } - } while (!(open_finished)) ; /* Will only loop if ring speed mismatch re-open attempted && autosense is on */ - - if (readb(init_srb+18) & (1<<3)) - if (olympic_priv->olympic_message_level) - printk(KERN_INFO "%s: Opened in FDX Mode\n",dev->name); - - if (readb(init_srb+18) & (1<<1)) - olympic_priv->olympic_ring_speed = 100 ; - else if (readb(init_srb+18) & 1) - olympic_priv->olympic_ring_speed = 16 ; - else - olympic_priv->olympic_ring_speed = 4 ; - - if (olympic_priv->olympic_message_level) - printk(KERN_INFO "%s: Opened in %d Mbps mode\n",dev->name, olympic_priv->olympic_ring_speed); - - olympic_priv->asb = swab16(readw(init_srb+8)); - olympic_priv->srb = swab16(readw(init_srb+10)); - olympic_priv->arb = swab16(readw(init_srb+12)); - olympic_priv->trb = swab16(readw(init_srb+16)); - - olympic_priv->olympic_receive_options = 0x01 ; - olympic_priv->olympic_copy_all_options = 0 ; - - /* setup rx ring */ - - writel((3<<16),olympic_mmio+BMCTL_RWM); /* Ensure end of frame generated interrupts */ - - writel(BMCTL_RX_DIS|3,olympic_mmio+BMCTL_RWM); /* Yes, this the enables RX channel */ - - for(i=0;ipkt_buf_sz); - if(skb == NULL) - break; - - skb->dev = dev; - - olympic_priv->olympic_rx_ring[i].buffer = cpu_to_le32(pci_map_single(olympic_priv->pdev, - skb->data,olympic_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE)) ; - olympic_priv->olympic_rx_ring[i].res_length = cpu_to_le32(olympic_priv->pkt_buf_sz); - olympic_priv->rx_ring_skb[i]=skb; - } - - if (i==0) { - printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers. Adapter disabled\n",dev->name); - goto out; - } - - olympic_priv->rx_ring_dma_addr = pci_map_single(olympic_priv->pdev,olympic_priv->olympic_rx_ring, - sizeof(struct olympic_rx_desc) * OLYMPIC_RX_RING_SIZE, PCI_DMA_TODEVICE); - writel(olympic_priv->rx_ring_dma_addr, olympic_mmio+RXDESCQ); - writel(olympic_priv->rx_ring_dma_addr, olympic_mmio+RXCDA); - writew(i, olympic_mmio+RXDESCQCNT); - - olympic_priv->rx_status_ring_dma_addr = pci_map_single(olympic_priv->pdev, olympic_priv->olympic_rx_status_ring, - sizeof(struct olympic_rx_status) * OLYMPIC_RX_RING_SIZE, PCI_DMA_FROMDEVICE); - writel(olympic_priv->rx_status_ring_dma_addr, olympic_mmio+RXSTATQ); - writel(olympic_priv->rx_status_ring_dma_addr, olympic_mmio+RXCSA); - - olympic_priv->rx_ring_last_received = OLYMPIC_RX_RING_SIZE - 1; /* last processed rx status */ - olympic_priv->rx_status_last_received = OLYMPIC_RX_RING_SIZE - 1; - - writew(i, olympic_mmio+RXSTATQCNT); - -#if OLYMPIC_DEBUG - printk("# of rx buffers: %d, RXENQ: %x\n",i, readw(olympic_mmio+RXENQ)); - printk("RXCSA: %x, rx_status_ring[0]: %p\n",readl(olympic_mmio+RXCSA),&olympic_priv->olympic_rx_status_ring[0]); - printk(" stat_ring[1]: %p, stat_ring[2]: %p, stat_ring[3]: %p\n", &(olympic_priv->olympic_rx_status_ring[1]), &(olympic_priv->olympic_rx_status_ring[2]), &(olympic_priv->olympic_rx_status_ring[3]) ); - printk(" stat_ring[4]: %p, stat_ring[5]: %p, stat_ring[6]: %p\n", &(olympic_priv->olympic_rx_status_ring[4]), &(olympic_priv->olympic_rx_status_ring[5]), &(olympic_priv->olympic_rx_status_ring[6]) ); - printk(" stat_ring[7]: %p\n", &(olympic_priv->olympic_rx_status_ring[7]) ); - - printk("RXCDA: %x, rx_ring[0]: %p\n",readl(olympic_mmio+RXCDA),&olympic_priv->olympic_rx_ring[0]); - printk("Rx_ring_dma_addr = %08x, rx_status_dma_addr = %08x\n", - olympic_priv->rx_ring_dma_addr,olympic_priv->rx_status_ring_dma_addr) ; -#endif - - writew((((readw(olympic_mmio+RXENQ)) & 0x8000) ^ 0x8000) | i,olympic_mmio+RXENQ); - -#if OLYMPIC_DEBUG - printk("# of rx buffers: %d, RXENQ: %x\n",i, readw(olympic_mmio+RXENQ)); - printk("RXCSA: %x, rx_ring[0]: %p\n",readl(olympic_mmio+RXCSA),&olympic_priv->olympic_rx_status_ring[0]); - printk("RXCDA: %x, rx_ring[0]: %p\n",readl(olympic_mmio+RXCDA),&olympic_priv->olympic_rx_ring[0]); -#endif - - writel(SISR_RX_STATUS | SISR_RX_NOBUF,olympic_mmio+SISR_MASK_SUM); - - /* setup tx ring */ - - writel(BMCTL_TX1_DIS,olympic_mmio+BMCTL_RWM); /* Yes, this enables TX channel 1 */ - for(i=0;iolympic_tx_ring[i].buffer=cpu_to_le32(0xdeadbeef); - - olympic_priv->free_tx_ring_entries=OLYMPIC_TX_RING_SIZE; - olympic_priv->tx_ring_dma_addr = pci_map_single(olympic_priv->pdev,olympic_priv->olympic_tx_ring, - sizeof(struct olympic_tx_desc) * OLYMPIC_TX_RING_SIZE,PCI_DMA_TODEVICE) ; - writel(olympic_priv->tx_ring_dma_addr, olympic_mmio+TXDESCQ_1); - writel(olympic_priv->tx_ring_dma_addr, olympic_mmio+TXCDA_1); - writew(OLYMPIC_TX_RING_SIZE, olympic_mmio+TXDESCQCNT_1); - - olympic_priv->tx_status_ring_dma_addr = pci_map_single(olympic_priv->pdev, olympic_priv->olympic_tx_status_ring, - sizeof(struct olympic_tx_status) * OLYMPIC_TX_RING_SIZE, PCI_DMA_FROMDEVICE); - writel(olympic_priv->tx_status_ring_dma_addr,olympic_mmio+TXSTATQ_1); - writel(olympic_priv->tx_status_ring_dma_addr,olympic_mmio+TXCSA_1); - writew(OLYMPIC_TX_RING_SIZE,olympic_mmio+TXSTATQCNT_1); - - olympic_priv->tx_ring_free=0; /* next entry in tx ring to use */ - olympic_priv->tx_ring_last_status=OLYMPIC_TX_RING_SIZE-1; /* last processed tx status */ - - writel(0xffffffff, olympic_mmio+EISR_RWM) ; /* clean the eisr */ - writel(0,olympic_mmio+EISR) ; - writel(EISR_MASK_OPTIONS,olympic_mmio+EISR_MASK) ; /* enables most of the TX error interrupts */ - writel(SISR_TX1_EOF | SISR_ADAPTER_CHECK | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_ASB_FREE | SISR_ERR,olympic_mmio+SISR_MASK_SUM); - -#if OLYMPIC_DEBUG - printk("BMCTL: %x\n",readl(olympic_mmio+BMCTL_SUM)); - printk("SISR MASK: %x\n",readl(olympic_mmio+SISR_MASK)); -#endif - - if (olympic_priv->olympic_network_monitor) { - u8 __iomem *oat; - u8 __iomem *opt; - u8 addr[6]; - oat = (olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr); - opt = (olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr); - - for (i = 0; i < 6; i++) - addr[i] = readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+i); - printk("%s: Node Address: %pM\n", dev->name, addr); - printk("%s: Functional Address: %02x:%02x:%02x:%02x\n",dev->name, - readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), - readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1), - readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2), - readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+3)); - - for (i = 0; i < 6; i++) - addr[i] = readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+i); - printk("%s: NAUN Address: %pM\n", dev->name, addr); - } - - netif_start_queue(dev); - return 0; - -out: - free_irq(dev->irq, dev); - return -EIO; -} - -/* - * When we enter the rx routine we do not know how many frames have been - * queued on the rx channel. Therefore we start at the next rx status - * position and travel around the receive ring until we have completed - * all the frames. - * - * This means that we may process the frame before we receive the end - * of frame interrupt. This is why we always test the status instead - * of blindly processing the next frame. - * - * We also remove the last 4 bytes from the packet as well, these are - * just token ring trailer info and upset protocols that don't check - * their own length, i.e. SNA. - * - */ -static void olympic_rx(struct net_device *dev) -{ - struct olympic_private *olympic_priv=netdev_priv(dev); - u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio; - struct olympic_rx_status *rx_status; - struct olympic_rx_desc *rx_desc ; - int rx_ring_last_received,length, buffer_cnt, cpy_length, frag_len; - struct sk_buff *skb, *skb2; - int i; - - rx_status=&(olympic_priv->olympic_rx_status_ring[(olympic_priv->rx_status_last_received + 1) & (OLYMPIC_RX_RING_SIZE - 1)]) ; - - while (rx_status->status_buffercnt) { - u32 l_status_buffercnt; - - olympic_priv->rx_status_last_received++ ; - olympic_priv->rx_status_last_received &= (OLYMPIC_RX_RING_SIZE -1); -#if OLYMPIC_DEBUG - printk("rx status: %x rx len: %x\n", le32_to_cpu(rx_status->status_buffercnt), le32_to_cpu(rx_status->fragmentcnt_framelen)); -#endif - length = le32_to_cpu(rx_status->fragmentcnt_framelen) & 0xffff; - buffer_cnt = le32_to_cpu(rx_status->status_buffercnt) & 0xffff; - i = buffer_cnt ; /* Need buffer_cnt later for rxenq update */ - frag_len = le32_to_cpu(rx_status->fragmentcnt_framelen) >> 16; - -#if OLYMPIC_DEBUG - printk("length: %x, frag_len: %x, buffer_cnt: %x\n", length, frag_len, buffer_cnt); -#endif - l_status_buffercnt = le32_to_cpu(rx_status->status_buffercnt); - if(l_status_buffercnt & 0xC0000000) { - if (l_status_buffercnt & 0x3B000000) { - if (olympic_priv->olympic_message_level) { - if (l_status_buffercnt & (1<<29)) /* Rx Frame Truncated */ - printk(KERN_WARNING "%s: Rx Frame Truncated\n",dev->name); - if (l_status_buffercnt & (1<<28)) /*Rx receive overrun */ - printk(KERN_WARNING "%s: Rx Frame Receive overrun\n",dev->name); - if (l_status_buffercnt & (1<<27)) /* No receive buffers */ - printk(KERN_WARNING "%s: No receive buffers\n",dev->name); - if (l_status_buffercnt & (1<<25)) /* Receive frame error detect */ - printk(KERN_WARNING "%s: Receive frame error detect\n",dev->name); - if (l_status_buffercnt & (1<<24)) /* Received Error Detect */ - printk(KERN_WARNING "%s: Received Error Detect\n",dev->name); - } - olympic_priv->rx_ring_last_received += i ; - olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1) ; - dev->stats.rx_errors++; - } else { - - if (buffer_cnt == 1) { - skb = dev_alloc_skb(max_t(int, olympic_priv->pkt_buf_sz,length)) ; - } else { - skb = dev_alloc_skb(length) ; - } - - if (skb == NULL) { - printk(KERN_WARNING "%s: Not enough memory to copy packet to upper layers.\n",dev->name) ; - dev->stats.rx_dropped++; - /* Update counters even though we don't transfer the frame */ - olympic_priv->rx_ring_last_received += i ; - olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1) ; - } else { - /* Optimise based upon number of buffers used. - If only one buffer is used we can simply swap the buffers around. - If more than one then we must use the new buffer and copy the information - first. Ideally all frames would be in a single buffer, this can be tuned by - altering the buffer size. If the length of the packet is less than - 1500 bytes we're going to copy it over anyway to stop packets getting - dropped from sockets with buffers smaller than our pkt_buf_sz. */ - - if (buffer_cnt==1) { - olympic_priv->rx_ring_last_received++ ; - olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1); - rx_ring_last_received = olympic_priv->rx_ring_last_received ; - if (length > 1500) { - skb2=olympic_priv->rx_ring_skb[rx_ring_last_received] ; - /* unmap buffer */ - pci_unmap_single(olympic_priv->pdev, - le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer), - olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; - skb_put(skb2,length-4); - skb2->protocol = tr_type_trans(skb2,dev); - olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer = - cpu_to_le32(pci_map_single(olympic_priv->pdev, skb->data, - olympic_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE)); - olympic_priv->olympic_rx_ring[rx_ring_last_received].res_length = - cpu_to_le32(olympic_priv->pkt_buf_sz); - olympic_priv->rx_ring_skb[rx_ring_last_received] = skb ; - netif_rx(skb2) ; - } else { - pci_dma_sync_single_for_cpu(olympic_priv->pdev, - le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer), - olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; - skb_copy_from_linear_data(olympic_priv->rx_ring_skb[rx_ring_last_received], - skb_put(skb,length - 4), - length - 4); - pci_dma_sync_single_for_device(olympic_priv->pdev, - le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer), - olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; - skb->protocol = tr_type_trans(skb,dev) ; - netif_rx(skb) ; - } - } else { - do { /* Walk the buffers */ - olympic_priv->rx_ring_last_received++ ; - olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1); - rx_ring_last_received = olympic_priv->rx_ring_last_received ; - pci_dma_sync_single_for_cpu(olympic_priv->pdev, - le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer), - olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; - rx_desc = &(olympic_priv->olympic_rx_ring[rx_ring_last_received]); - cpy_length = (i == 1 ? frag_len : le32_to_cpu(rx_desc->res_length)); - skb_copy_from_linear_data(olympic_priv->rx_ring_skb[rx_ring_last_received], - skb_put(skb, cpy_length), - cpy_length); - pci_dma_sync_single_for_device(olympic_priv->pdev, - le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer), - olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; - } while (--i) ; - skb_trim(skb,skb->len-4) ; - skb->protocol = tr_type_trans(skb,dev); - netif_rx(skb) ; - } - dev->stats.rx_packets++ ; - dev->stats.rx_bytes += length ; - } /* if skb == null */ - } /* If status & 0x3b */ - - } else { /*if buffercnt & 0xC */ - olympic_priv->rx_ring_last_received += i ; - olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE - 1) ; - } - - rx_status->fragmentcnt_framelen = 0 ; - rx_status->status_buffercnt = 0 ; - rx_status = &(olympic_priv->olympic_rx_status_ring[(olympic_priv->rx_status_last_received+1) & (OLYMPIC_RX_RING_SIZE -1) ]); - - writew((((readw(olympic_mmio+RXENQ)) & 0x8000) ^ 0x8000) | buffer_cnt , olympic_mmio+RXENQ); - } /* while */ - -} - -static void olympic_freemem(struct net_device *dev) -{ - struct olympic_private *olympic_priv=netdev_priv(dev); - int i; - - for(i=0;irx_ring_skb[olympic_priv->rx_status_last_received] != NULL) { - dev_kfree_skb_irq(olympic_priv->rx_ring_skb[olympic_priv->rx_status_last_received]); - olympic_priv->rx_ring_skb[olympic_priv->rx_status_last_received] = NULL; - } - if (olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer != cpu_to_le32(0xdeadbeef)) { - pci_unmap_single(olympic_priv->pdev, - le32_to_cpu(olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer), - olympic_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE); - } - olympic_priv->rx_status_last_received++; - olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1; - } - /* unmap rings */ - pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_status_ring_dma_addr, - sizeof(struct olympic_rx_status) * OLYMPIC_RX_RING_SIZE, PCI_DMA_FROMDEVICE); - pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_ring_dma_addr, - sizeof(struct olympic_rx_desc) * OLYMPIC_RX_RING_SIZE, PCI_DMA_TODEVICE); - - pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_status_ring_dma_addr, - sizeof(struct olympic_tx_status) * OLYMPIC_TX_RING_SIZE, PCI_DMA_FROMDEVICE); - pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_ring_dma_addr, - sizeof(struct olympic_tx_desc) * OLYMPIC_TX_RING_SIZE, PCI_DMA_TODEVICE); - - return ; -} - -static irqreturn_t olympic_interrupt(int irq, void *dev_id) -{ - struct net_device *dev= (struct net_device *)dev_id; - struct olympic_private *olympic_priv=netdev_priv(dev); - u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio; - u32 sisr; - u8 __iomem *adapter_check_area ; - - /* - * Read sisr but don't reset it yet. - * The indication bit may have been set but the interrupt latch - * bit may not be set, so we'd lose the interrupt later. - */ - sisr=readl(olympic_mmio+SISR) ; - if (!(sisr & SISR_MI)) /* Interrupt isn't for us */ - return IRQ_NONE; - sisr=readl(olympic_mmio+SISR_RR) ; /* Read & Reset sisr */ - - spin_lock(&olympic_priv->olympic_lock); - - /* Hotswap gives us this on removal */ - if (sisr == 0xffffffff) { - printk(KERN_WARNING "%s: Hotswap adapter removal.\n",dev->name) ; - spin_unlock(&olympic_priv->olympic_lock) ; - return IRQ_NONE; - } - - if (sisr & (SISR_SRB_REPLY | SISR_TX1_EOF | SISR_RX_STATUS | SISR_ADAPTER_CHECK | - SISR_ASB_FREE | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_RX_NOBUF | SISR_ERR)) { - - /* If we ever get this the adapter is seriously dead. Only a reset is going to - * bring it back to life. We're talking pci bus errors and such like :( */ - if((sisr & SISR_ERR) && (readl(olympic_mmio+EISR) & EISR_MASK_OPTIONS)) { - printk(KERN_ERR "Olympic: EISR Error, EISR=%08x\n",readl(olympic_mmio+EISR)) ; - printk(KERN_ERR "The adapter must be reset to clear this condition.\n") ; - printk(KERN_ERR "Please report this error to the driver maintainer and/\n") ; - printk(KERN_ERR "or the linux-tr mailing list.\n") ; - wake_up_interruptible(&olympic_priv->srb_wait); - spin_unlock(&olympic_priv->olympic_lock) ; - return IRQ_HANDLED; - } /* SISR_ERR */ - - if(sisr & SISR_SRB_REPLY) { - if(olympic_priv->srb_queued==1) { - wake_up_interruptible(&olympic_priv->srb_wait); - } else if (olympic_priv->srb_queued==2) { - olympic_srb_bh(dev) ; - } - olympic_priv->srb_queued=0; - } /* SISR_SRB_REPLY */ - - /* We shouldn't ever miss the Tx interrupt, but the you never know, hence the loop to ensure - we get all tx completions. */ - if (sisr & SISR_TX1_EOF) { - while(olympic_priv->olympic_tx_status_ring[(olympic_priv->tx_ring_last_status + 1) & (OLYMPIC_TX_RING_SIZE-1)].status) { - olympic_priv->tx_ring_last_status++; - olympic_priv->tx_ring_last_status &= (OLYMPIC_TX_RING_SIZE-1); - olympic_priv->free_tx_ring_entries++; - dev->stats.tx_bytes += olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]->len; - dev->stats.tx_packets++ ; - pci_unmap_single(olympic_priv->pdev, - le32_to_cpu(olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_last_status].buffer), - olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]->len,PCI_DMA_TODEVICE); - dev_kfree_skb_irq(olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]); - olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_last_status].buffer=cpu_to_le32(0xdeadbeef); - olympic_priv->olympic_tx_status_ring[olympic_priv->tx_ring_last_status].status=0; - } - netif_wake_queue(dev); - } /* SISR_TX1_EOF */ - - if (sisr & SISR_RX_STATUS) { - olympic_rx(dev); - } /* SISR_RX_STATUS */ - - if (sisr & SISR_ADAPTER_CHECK) { - netif_stop_queue(dev); - printk(KERN_WARNING "%s: Adapter Check Interrupt Raised, 8 bytes of information follow:\n", dev->name); - writel(readl(olympic_mmio+LAPWWC),olympic_mmio+LAPA); - adapter_check_area = olympic_priv->olympic_lap + ((readl(olympic_mmio+LAPWWC)) & (~0xf800)) ; - printk(KERN_WARNING "%s: Bytes %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, readb(adapter_check_area+0), readb(adapter_check_area+1), readb(adapter_check_area+2), readb(adapter_check_area+3), readb(adapter_check_area+4), readb(adapter_check_area+5), readb(adapter_check_area+6), readb(adapter_check_area+7)) ; - spin_unlock(&olympic_priv->olympic_lock) ; - return IRQ_HANDLED; - } /* SISR_ADAPTER_CHECK */ - - if (sisr & SISR_ASB_FREE) { - /* Wake up anything that is waiting for the asb response */ - if (olympic_priv->asb_queued) { - olympic_asb_bh(dev) ; - } - } /* SISR_ASB_FREE */ - - if (sisr & SISR_ARB_CMD) { - olympic_arb_cmd(dev) ; - } /* SISR_ARB_CMD */ - - if (sisr & SISR_TRB_REPLY) { - /* Wake up anything that is waiting for the trb response */ - if (olympic_priv->trb_queued) { - wake_up_interruptible(&olympic_priv->trb_wait); - } - olympic_priv->trb_queued = 0 ; - } /* SISR_TRB_REPLY */ - - if (sisr & SISR_RX_NOBUF) { - /* According to the documentation, we don't have to do anything, but trapping it keeps it out of - /var/log/messages. */ - } /* SISR_RX_NOBUF */ - } else { - printk(KERN_WARNING "%s: Unexpected interrupt: %x\n",dev->name, sisr); - printk(KERN_WARNING "%s: SISR_MASK: %x\n",dev->name, readl(olympic_mmio+SISR_MASK)) ; - } /* One if the interrupts we want */ - writel(SISR_MI,olympic_mmio+SISR_MASK_SUM); - - spin_unlock(&olympic_priv->olympic_lock) ; - return IRQ_HANDLED; -} - -static netdev_tx_t olympic_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct olympic_private *olympic_priv=netdev_priv(dev); - u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio; - unsigned long flags ; - - spin_lock_irqsave(&olympic_priv->olympic_lock, flags); - - netif_stop_queue(dev); - - if(olympic_priv->free_tx_ring_entries) { - olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_free].buffer = - cpu_to_le32(pci_map_single(olympic_priv->pdev, skb->data, skb->len,PCI_DMA_TODEVICE)); - olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_free].status_length = cpu_to_le32(skb->len | (0x80000000)); - olympic_priv->tx_ring_skb[olympic_priv->tx_ring_free]=skb; - olympic_priv->free_tx_ring_entries--; - - olympic_priv->tx_ring_free++; - olympic_priv->tx_ring_free &= (OLYMPIC_TX_RING_SIZE-1); - writew((((readw(olympic_mmio+TXENQ_1)) & 0x8000) ^ 0x8000) | 1,olympic_mmio+TXENQ_1); - netif_wake_queue(dev); - spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags); - return NETDEV_TX_OK; - } else { - spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags); - return NETDEV_TX_BUSY; - } - -} - - -static int olympic_close(struct net_device *dev) -{ - struct olympic_private *olympic_priv=netdev_priv(dev); - u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio,*srb; - unsigned long t,flags; - - DECLARE_WAITQUEUE(wait,current) ; - - netif_stop_queue(dev); - - writel(olympic_priv->srb,olympic_mmio+LAPA); - srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800)); - - writeb(SRB_CLOSE_ADAPTER,srb+0); - writeb(0,srb+1); - writeb(OLYMPIC_CLEAR_RET_CODE,srb+2); - - add_wait_queue(&olympic_priv->srb_wait,&wait) ; - set_current_state(TASK_INTERRUPTIBLE) ; - - spin_lock_irqsave(&olympic_priv->olympic_lock,flags); - olympic_priv->srb_queued=1; - - writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); - spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags); - - while(olympic_priv->srb_queued) { - - t = schedule_timeout_interruptible(60*HZ); - - if(signal_pending(current)) { - printk(KERN_WARNING "%s: SRB timed out.\n",dev->name); - printk(KERN_WARNING "SISR=%x MISR=%x\n",readl(olympic_mmio+SISR),readl(olympic_mmio+LISR)); - olympic_priv->srb_queued=0; - break; - } - - if (t == 0) { - printk(KERN_WARNING "%s: SRB timed out. May not be fatal.\n",dev->name); - } - olympic_priv->srb_queued=0; - } - remove_wait_queue(&olympic_priv->srb_wait,&wait) ; - - olympic_priv->rx_status_last_received++; - olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1; - - olympic_freemem(dev) ; - - /* reset tx/rx fifo's and busmaster logic */ - - writel(readl(olympic_mmio+BCTL)|(3<<13),olympic_mmio+BCTL); - udelay(1); - writel(readl(olympic_mmio+BCTL)&~(3<<13),olympic_mmio+BCTL); - -#if OLYMPIC_DEBUG - { - int i ; - printk("srb(%p): ",srb); - for(i=0;i<4;i++) - printk("%x ",readb(srb+i)); - printk("\n"); - } -#endif - free_irq(dev->irq,dev); - - return 0; - -} - -static void olympic_set_rx_mode(struct net_device *dev) -{ - struct olympic_private *olympic_priv = netdev_priv(dev); - u8 __iomem *olympic_mmio = olympic_priv->olympic_mmio ; - u8 options = 0; - u8 __iomem *srb; - struct netdev_hw_addr *ha; - unsigned char dev_mc_address[4] ; - - writel(olympic_priv->srb,olympic_mmio+LAPA); - srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800)); - options = olympic_priv->olympic_copy_all_options; - - if (dev->flags&IFF_PROMISC) - options |= 0x61 ; - else - options &= ~0x61 ; - - /* Only issue the srb if there is a change in options */ - - if ((options ^ olympic_priv->olympic_copy_all_options)) { - - /* Now to issue the srb command to alter the copy.all.options */ - - writeb(SRB_MODIFY_RECEIVE_OPTIONS,srb); - writeb(0,srb+1); - writeb(OLYMPIC_CLEAR_RET_CODE,srb+2); - writeb(0,srb+3); - writeb(olympic_priv->olympic_receive_options,srb+4); - writeb(options,srb+5); - - olympic_priv->srb_queued=2; /* Can't sleep, use srb_bh */ - - writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); - - olympic_priv->olympic_copy_all_options = options ; - - return ; - } - - /* Set the functional addresses we need for multicast */ - - dev_mc_address[0] = dev_mc_address[1] = dev_mc_address[2] = dev_mc_address[3] = 0 ; - - netdev_for_each_mc_addr(ha, dev) { - dev_mc_address[0] |= ha->addr[2]; - dev_mc_address[1] |= ha->addr[3]; - dev_mc_address[2] |= ha->addr[4]; - dev_mc_address[3] |= ha->addr[5]; - } - - writeb(SRB_SET_FUNC_ADDRESS,srb+0); - writeb(0,srb+1); - writeb(OLYMPIC_CLEAR_RET_CODE,srb+2); - writeb(0,srb+3); - writeb(0,srb+4); - writeb(0,srb+5); - writeb(dev_mc_address[0],srb+6); - writeb(dev_mc_address[1],srb+7); - writeb(dev_mc_address[2],srb+8); - writeb(dev_mc_address[3],srb+9); - - olympic_priv->srb_queued = 2 ; - writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); - -} - -static void olympic_srb_bh(struct net_device *dev) -{ - struct olympic_private *olympic_priv = netdev_priv(dev); - u8 __iomem *olympic_mmio = olympic_priv->olympic_mmio ; - u8 __iomem *srb; - - writel(olympic_priv->srb,olympic_mmio+LAPA); - srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800)); - - switch (readb(srb)) { - - /* SRB_MODIFY_RECEIVE_OPTIONS i.e. set_multicast_list options (promiscuous) - * At some point we should do something if we get an error, such as - * resetting the IFF_PROMISC flag in dev - */ - - case SRB_MODIFY_RECEIVE_OPTIONS: - switch (readb(srb+2)) { - case 0x01: - printk(KERN_WARNING "%s: Unrecognized srb command\n",dev->name) ; - break ; - case 0x04: - printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name); - break ; - default: - if (olympic_priv->olympic_message_level) - printk(KERN_WARNING "%s: Receive Options Modified to %x,%x\n",dev->name,olympic_priv->olympic_copy_all_options, olympic_priv->olympic_receive_options) ; - break ; - } /* switch srb[2] */ - break ; - - /* SRB_SET_GROUP_ADDRESS - Multicast group setting - */ - - case SRB_SET_GROUP_ADDRESS: - switch (readb(srb+2)) { - case 0x00: - break ; - case 0x01: - printk(KERN_WARNING "%s: Unrecognized srb command\n",dev->name); - break ; - case 0x04: - printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name); - break ; - case 0x3c: - printk(KERN_WARNING "%s: Group/Functional address indicator bits not set correctly\n",dev->name) ; - break ; - case 0x3e: /* If we ever implement individual multicast addresses, will need to deal with this */ - printk(KERN_WARNING "%s: Group address registers full\n",dev->name) ; - break ; - case 0x55: - printk(KERN_INFO "%s: Group Address already set.\n",dev->name) ; - break ; - default: - break ; - } /* switch srb[2] */ - break ; - - /* SRB_RESET_GROUP_ADDRESS - Remove a multicast address from group list - */ - - case SRB_RESET_GROUP_ADDRESS: - switch (readb(srb+2)) { - case 0x00: - break ; - case 0x01: - printk(KERN_WARNING "%s: Unrecognized srb command\n",dev->name); - break ; - case 0x04: - printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; - break ; - case 0x39: /* Must deal with this if individual multicast addresses used */ - printk(KERN_INFO "%s: Group address not found\n",dev->name); - break ; - default: - break ; - } /* switch srb[2] */ - break ; - - - /* SRB_SET_FUNC_ADDRESS - Called by the set_rx_mode - */ - - case SRB_SET_FUNC_ADDRESS: - switch (readb(srb+2)) { - case 0x00: - if (olympic_priv->olympic_message_level) - printk(KERN_INFO "%s: Functional Address Mask Set\n",dev->name); - break ; - case 0x01: - printk(KERN_WARNING "%s: Unrecognized srb command\n",dev->name); - break ; - case 0x04: - printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; - break ; - default: - break ; - } /* switch srb[2] */ - break ; - - /* SRB_READ_LOG - Read and reset the adapter error counters - */ - - case SRB_READ_LOG: - switch (readb(srb+2)) { - case 0x00: - if (olympic_priv->olympic_message_level) - printk(KERN_INFO "%s: Read Log issued\n",dev->name) ; - break ; - case 0x01: - printk(KERN_WARNING "%s: Unrecognized srb command\n",dev->name); - break ; - case 0x04: - printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; - break ; - - } /* switch srb[2] */ - break ; - - /* SRB_READ_SR_COUNTERS - Read and reset the source routing bridge related counters */ - - case SRB_READ_SR_COUNTERS: - switch (readb(srb+2)) { - case 0x00: - if (olympic_priv->olympic_message_level) - printk(KERN_INFO "%s: Read Source Routing Counters issued\n",dev->name) ; - break ; - case 0x01: - printk(KERN_WARNING "%s: Unrecognized srb command\n",dev->name); - break ; - case 0x04: - printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; - break ; - default: - break ; - } /* switch srb[2] */ - break ; - - default: - printk(KERN_WARNING "%s: Unrecognized srb bh return value.\n",dev->name); - break ; - } /* switch srb[0] */ - -} - -static int olympic_set_mac_address (struct net_device *dev, void *addr) -{ - struct sockaddr *saddr = addr ; - struct olympic_private *olympic_priv = netdev_priv(dev); - - if (netif_running(dev)) { - printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name) ; - return -EIO ; - } - - memcpy(olympic_priv->olympic_laa, saddr->sa_data,dev->addr_len) ; - - if (olympic_priv->olympic_message_level) { - printk(KERN_INFO "%s: MAC/LAA Set to = %x.%x.%x.%x.%x.%x\n",dev->name, olympic_priv->olympic_laa[0], - olympic_priv->olympic_laa[1], olympic_priv->olympic_laa[2], - olympic_priv->olympic_laa[3], olympic_priv->olympic_laa[4], - olympic_priv->olympic_laa[5]); - } - - return 0 ; -} - -static void olympic_arb_cmd(struct net_device *dev) -{ - struct olympic_private *olympic_priv = netdev_priv(dev); - u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio; - u8 __iomem *arb_block, *asb_block, *srb ; - u8 header_len ; - u16 frame_len, buffer_len ; - struct sk_buff *mac_frame ; - u8 __iomem *buf_ptr ; - u8 __iomem *frame_data ; - u16 buff_off ; - u16 lan_status = 0, lan_status_diff ; /* Initialize to stop compiler warning */ - u8 fdx_prot_error ; - u16 next_ptr; - - arb_block = (olympic_priv->olympic_lap + olympic_priv->arb) ; - asb_block = (olympic_priv->olympic_lap + olympic_priv->asb) ; - srb = (olympic_priv->olympic_lap + olympic_priv->srb) ; - - if (readb(arb_block+0) == ARB_RECEIVE_DATA) { /* Receive.data, MAC frames */ - - header_len = readb(arb_block+8) ; /* 802.5 Token-Ring Header Length */ - frame_len = swab16(readw(arb_block + 10)) ; - - buff_off = swab16(readw(arb_block + 6)) ; - - buf_ptr = olympic_priv->olympic_lap + buff_off ; - -#if OLYMPIC_DEBUG -{ - int i; - frame_data = buf_ptr+offsetof(struct mac_receive_buffer,frame_data) ; - - for (i=0 ; i < 14 ; i++) { - printk("Loc %d = %02x\n",i,readb(frame_data + i)); - } - - printk("next %04x, fs %02x, len %04x\n",readw(buf_ptr+offsetof(struct mac_receive_buffer,next)), readb(buf_ptr+offsetof(struct mac_receive_buffer,frame_status)), readw(buf_ptr+offsetof(struct mac_receive_buffer,buffer_length))); -} -#endif - mac_frame = dev_alloc_skb(frame_len) ; - if (!mac_frame) { - printk(KERN_WARNING "%s: Memory squeeze, dropping frame.\n", dev->name); - goto drop_frame; - } - - /* Walk the buffer chain, creating the frame */ - - do { - frame_data = buf_ptr+offsetof(struct mac_receive_buffer,frame_data) ; - buffer_len = swab16(readw(buf_ptr+offsetof(struct mac_receive_buffer,buffer_length))); - memcpy_fromio(skb_put(mac_frame, buffer_len), frame_data , buffer_len ) ; - next_ptr=readw(buf_ptr+offsetof(struct mac_receive_buffer,next)); - } while (next_ptr && (buf_ptr=olympic_priv->olympic_lap + swab16(next_ptr))); - - mac_frame->protocol = tr_type_trans(mac_frame, dev); - - if (olympic_priv->olympic_network_monitor) { - struct trh_hdr *mac_hdr; - printk(KERN_WARNING "%s: Received MAC Frame, details:\n",dev->name); - mac_hdr = tr_hdr(mac_frame); - printk(KERN_WARNING "%s: MAC Frame Dest. Addr: %pM\n", - dev->name, mac_hdr->daddr); - printk(KERN_WARNING "%s: MAC Frame Srce. Addr: %pM\n", - dev->name, mac_hdr->saddr); - } - netif_rx(mac_frame); - -drop_frame: - /* Now tell the card we have dealt with the received frame */ - - /* Set LISR Bit 1 */ - writel(LISR_ARB_FREE,olympic_priv->olympic_mmio + LISR_SUM); - - /* Is the ASB free ? */ - - if (readb(asb_block + 2) != 0xff) { - olympic_priv->asb_queued = 1 ; - writel(LISR_ASB_FREE_REQ,olympic_priv->olympic_mmio+LISR_SUM); - return ; - /* Drop out and wait for the bottom half to be run */ - } - - writeb(ASB_RECEIVE_DATA,asb_block); /* Receive data */ - writeb(OLYMPIC_CLEAR_RET_CODE,asb_block+2); /* Necessary ?? */ - writeb(readb(arb_block+6),asb_block+6); /* Must send the address back to the adapter */ - writeb(readb(arb_block+7),asb_block+7); /* To let it know we have dealt with the data */ - - writel(LISR_ASB_REPLY | LISR_ASB_FREE_REQ,olympic_priv->olympic_mmio+LISR_SUM); - - olympic_priv->asb_queued = 2 ; - - return ; - - } else if (readb(arb_block) == ARB_LAN_CHANGE_STATUS) { /* Lan.change.status */ - lan_status = swab16(readw(arb_block+6)); - fdx_prot_error = readb(arb_block+8) ; - - /* Issue ARB Free */ - writel(LISR_ARB_FREE,olympic_priv->olympic_mmio+LISR_SUM); - - lan_status_diff = olympic_priv->olympic_lan_status ^ lan_status ; - - if (lan_status_diff & (LSC_LWF | LSC_ARW | LSC_FPE | LSC_RR) ) { - if (lan_status_diff & LSC_LWF) - printk(KERN_WARNING "%s: Short circuit detected on the lobe\n",dev->name); - if (lan_status_diff & LSC_ARW) - printk(KERN_WARNING "%s: Auto removal error\n",dev->name); - if (lan_status_diff & LSC_FPE) - printk(KERN_WARNING "%s: FDX Protocol Error\n",dev->name); - if (lan_status_diff & LSC_RR) - printk(KERN_WARNING "%s: Force remove MAC frame received\n",dev->name); - - /* Adapter has been closed by the hardware */ - - /* reset tx/rx fifo's and busmaster logic */ - - writel(readl(olympic_mmio+BCTL)|(3<<13),olympic_mmio+BCTL); - udelay(1); - writel(readl(olympic_mmio+BCTL)&~(3<<13),olympic_mmio+BCTL); - netif_stop_queue(dev); - olympic_priv->srb = readw(olympic_priv->olympic_lap + LAPWWO) ; - printk(KERN_WARNING "%s: Adapter has been closed\n", dev->name); - } /* If serious error */ - - if (olympic_priv->olympic_message_level) { - if (lan_status_diff & LSC_SIG_LOSS) - printk(KERN_WARNING "%s: No receive signal detected\n", dev->name); - if (lan_status_diff & LSC_HARD_ERR) - printk(KERN_INFO "%s: Beaconing\n",dev->name); - if (lan_status_diff & LSC_SOFT_ERR) - printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame\n",dev->name); - if (lan_status_diff & LSC_TRAN_BCN) - printk(KERN_INFO "%s: We are transmitting the beacon, aaah\n",dev->name); - if (lan_status_diff & LSC_SS) - printk(KERN_INFO "%s: Single Station on the ring\n", dev->name); - if (lan_status_diff & LSC_RING_REC) - printk(KERN_INFO "%s: Ring recovery ongoing\n",dev->name); - if (lan_status_diff & LSC_FDX_MODE) - printk(KERN_INFO "%s: Operating in FDX mode\n",dev->name); - } - - if (lan_status_diff & LSC_CO) { - - if (olympic_priv->olympic_message_level) - printk(KERN_INFO "%s: Counter Overflow\n", dev->name); - - /* Issue READ.LOG command */ - - writeb(SRB_READ_LOG, srb); - writeb(0,srb+1); - writeb(OLYMPIC_CLEAR_RET_CODE,srb+2); - writeb(0,srb+3); - writeb(0,srb+4); - writeb(0,srb+5); - - olympic_priv->srb_queued=2; /* Can't sleep, use srb_bh */ - - writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); - - } - - if (lan_status_diff & LSC_SR_CO) { - - if (olympic_priv->olympic_message_level) - printk(KERN_INFO "%s: Source routing counters overflow\n", dev->name); - - /* Issue a READ.SR.COUNTERS */ - - writeb(SRB_READ_SR_COUNTERS,srb); - writeb(0,srb+1); - writeb(OLYMPIC_CLEAR_RET_CODE,srb+2); - writeb(0,srb+3); - - olympic_priv->srb_queued=2; /* Can't sleep, use srb_bh */ - - writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); - - } - - olympic_priv->olympic_lan_status = lan_status ; - - } /* Lan.change.status */ - else - printk(KERN_WARNING "%s: Unknown arb command\n", dev->name); -} - -static void olympic_asb_bh(struct net_device *dev) -{ - struct olympic_private *olympic_priv = netdev_priv(dev); - u8 __iomem *arb_block, *asb_block ; - - arb_block = (olympic_priv->olympic_lap + olympic_priv->arb) ; - asb_block = (olympic_priv->olympic_lap + olympic_priv->asb) ; - - if (olympic_priv->asb_queued == 1) { /* Dropped through the first time */ - - writeb(ASB_RECEIVE_DATA,asb_block); /* Receive data */ - writeb(OLYMPIC_CLEAR_RET_CODE,asb_block+2); /* Necessary ?? */ - writeb(readb(arb_block+6),asb_block+6); /* Must send the address back to the adapter */ - writeb(readb(arb_block+7),asb_block+7); /* To let it know we have dealt with the data */ - - writel(LISR_ASB_REPLY | LISR_ASB_FREE_REQ,olympic_priv->olympic_mmio+LISR_SUM); - olympic_priv->asb_queued = 2 ; - - return ; - } - - if (olympic_priv->asb_queued == 2) { - switch (readb(asb_block+2)) { - case 0x01: - printk(KERN_WARNING "%s: Unrecognized command code\n", dev->name); - break ; - case 0x26: - printk(KERN_WARNING "%s: Unrecognized buffer address\n", dev->name); - break ; - case 0xFF: - /* Valid response, everything should be ok again */ - break ; - default: - printk(KERN_WARNING "%s: Invalid return code in asb\n",dev->name); - break ; - } - } - olympic_priv->asb_queued = 0 ; -} - -static int olympic_change_mtu(struct net_device *dev, int mtu) -{ - struct olympic_private *olympic_priv = netdev_priv(dev); - u16 max_mtu ; - - if (olympic_priv->olympic_ring_speed == 4) - max_mtu = 4500 ; - else - max_mtu = 18000 ; - - if (mtu > max_mtu) - return -EINVAL ; - if (mtu < 100) - return -EINVAL ; - - dev->mtu = mtu ; - olympic_priv->pkt_buf_sz = mtu + TR_HLEN ; - - return 0 ; -} - -static int olympic_proc_show(struct seq_file *m, void *v) -{ - struct net_device *dev = m->private; - struct olympic_private *olympic_priv=netdev_priv(dev); - u8 __iomem *oat = (olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; - u8 __iomem *opt = (olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; - u8 addr[6]; - u8 addr2[6]; - int i; - - seq_printf(m, - "IBM Pit/Pit-Phy/Olympic Chipset Token Ring Adapter %s\n",dev->name); - seq_printf(m, "\n%6s: Adapter Address : Node Address : Functional Addr\n", - dev->name); - - for (i = 0 ; i < 6 ; i++) - addr[i] = readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr) + i); - - seq_printf(m, "%6s: %pM : %pM : %02x:%02x:%02x:%02x\n", - dev->name, - dev->dev_addr, addr, - readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), - readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1), - readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2), - readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+3)); - - seq_printf(m, "\n%6s: Token Ring Parameters Table:\n", dev->name); - - seq_printf(m, "%6s: Physical Addr : Up Node Address : Poll Address : AccPri : Auth Src : Att Code :\n", - dev->name) ; - - for (i = 0 ; i < 6 ; i++) - addr[i] = readb(opt+offsetof(struct olympic_parameters_table, up_node_addr) + i); - for (i = 0 ; i < 6 ; i++) - addr2[i] = readb(opt+offsetof(struct olympic_parameters_table, poll_addr) + i); - - seq_printf(m, "%6s: %02x:%02x:%02x:%02x : %pM : %pM : %04x : %04x : %04x :\n", - dev->name, - readb(opt+offsetof(struct olympic_parameters_table, phys_addr)), - readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+1), - readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+2), - readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+3), - addr, addr2, - swab16(readw(opt+offsetof(struct olympic_parameters_table, acc_priority))), - swab16(readw(opt+offsetof(struct olympic_parameters_table, auth_source_class))), - swab16(readw(opt+offsetof(struct olympic_parameters_table, att_code)))); - - seq_printf(m, "%6s: Source Address : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n", - dev->name) ; - - for (i = 0 ; i < 6 ; i++) - addr[i] = readb(opt+offsetof(struct olympic_parameters_table, source_addr) + i); - seq_printf(m, "%6s: %pM : %04x : %04x : %04x : %04x : %04x : %04x : \n", - dev->name, addr, - swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_type))), - swab16(readw(opt+offsetof(struct olympic_parameters_table, major_vector))), - swab16(readw(opt+offsetof(struct olympic_parameters_table, lan_status))), - swab16(readw(opt+offsetof(struct olympic_parameters_table, local_ring))), - swab16(readw(opt+offsetof(struct olympic_parameters_table, mon_error))), - swab16(readw(opt+offsetof(struct olympic_parameters_table, frame_correl)))); - - seq_printf(m, "%6s: Beacon Details : Tx : Rx : NAUN Node Address : NAUN Node Phys : \n", - dev->name) ; - - for (i = 0 ; i < 6 ; i++) - addr[i] = readb(opt+offsetof(struct olympic_parameters_table, beacon_naun) + i); - seq_printf(m, "%6s: : %02x : %02x : %pM : %02x:%02x:%02x:%02x : \n", - dev->name, - swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_transmit))), - swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_receive))), - addr, - readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)), - readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+1), - readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+2), - readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+3)); - - return 0; -} - -static int olympic_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, olympic_proc_show, PDE(inode)->data); -} - -static const struct file_operations olympic_proc_ops = { - .open = olympic_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static void __devexit olympic_remove_one(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev) ; - struct olympic_private *olympic_priv=netdev_priv(dev); - - if (olympic_priv->olympic_network_monitor) { - char proc_name[20] ; - strcpy(proc_name,"olympic_") ; - strcat(proc_name,dev->name) ; - remove_proc_entry(proc_name,init_net.proc_net); - } - unregister_netdev(dev) ; - iounmap(olympic_priv->olympic_mmio) ; - iounmap(olympic_priv->olympic_lap) ; - pci_release_regions(pdev) ; - pci_set_drvdata(pdev,NULL) ; - free_netdev(dev) ; -} - -static struct pci_driver olympic_driver = { - .name = "olympic", - .id_table = olympic_pci_tbl, - .probe = olympic_probe, - .remove = __devexit_p(olympic_remove_one), -}; - -static int __init olympic_pci_init(void) -{ - return pci_register_driver(&olympic_driver) ; -} - -static void __exit olympic_pci_cleanup(void) -{ - pci_unregister_driver(&olympic_driver) ; -} - - -module_init(olympic_pci_init) ; -module_exit(olympic_pci_cleanup) ; - -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/net/tokenring/olympic.h b/trunk/drivers/net/tokenring/olympic.h deleted file mode 100644 index 30631bae4c94..000000000000 --- a/trunk/drivers/net/tokenring/olympic.h +++ /dev/null @@ -1,321 +0,0 @@ -/* - * olympic.h (c) 1999 Peter De Schrijver All Rights Reserved - * 1999,2000 Mike Phillips (mikep@linuxtr.net) - * - * Linux driver for IBM PCI tokenring cards based on the olympic and the PIT/PHY chipset. - * - * Base Driver Skeleton: - * Written 1993-94 by Donald Becker. - * - * Copyright 1993 United States Government as represented by the - * Director, National Security Agency. - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - */ - -#define CID 0x4e - -#define BCTL 0x70 -#define BCTL_SOFTRESET (1<<15) -#define BCTL_MIMREB (1<<6) -#define BCTL_MODE_INDICATOR (1<<5) - -#define GPR 0x4a -#define GPR_OPTI_BF (1<<6) -#define GPR_NEPTUNE_BF (1<<4) -#define GPR_AUTOSENSE (1<<2) -#define GPR_16MBPS (1<<3) - -#define PAG 0x85 -#define LBC 0x8e - -#define LISR 0x10 -#define LISR_SUM 0x14 -#define LISR_RWM 0x18 - -#define LISR_LIE (1<<15) -#define LISR_SLIM (1<<13) -#define LISR_SLI (1<<12) -#define LISR_PCMSRMASK (1<<11) -#define LISR_PCMSRINT (1<<10) -#define LISR_WOLMASK (1<<9) -#define LISR_WOL (1<<8) -#define LISR_SRB_CMD (1<<5) -#define LISR_ASB_REPLY (1<<4) -#define LISR_ASB_FREE_REQ (1<<2) -#define LISR_ARB_FREE (1<<1) -#define LISR_TRB_FRAME (1<<0) - -#define SISR 0x20 -#define SISR_SUM 0x24 -#define SISR_RWM 0x28 -#define SISR_RR 0x2C -#define SISR_RESMASK 0x30 -#define SISR_MASK 0x54 -#define SISR_MASK_SUM 0x58 -#define SISR_MASK_RWM 0x5C - -#define SISR_TX2_IDLE (1<<31) -#define SISR_TX2_HALT (1<<29) -#define SISR_TX2_EOF (1<<28) -#define SISR_TX1_IDLE (1<<27) -#define SISR_TX1_HALT (1<<25) -#define SISR_TX1_EOF (1<<24) -#define SISR_TIMEOUT (1<<23) -#define SISR_RX_NOBUF (1<<22) -#define SISR_RX_STATUS (1<<21) -#define SISR_RX_HALT (1<<18) -#define SISR_RX_EOF_EARLY (1<<16) -#define SISR_MI (1<<15) -#define SISR_PI (1<<13) -#define SISR_ERR (1<<9) -#define SISR_ADAPTER_CHECK (1<<6) -#define SISR_SRB_REPLY (1<<5) -#define SISR_ASB_FREE (1<<4) -#define SISR_ARB_CMD (1<<3) -#define SISR_TRB_REPLY (1<<2) - -#define EISR 0x34 -#define EISR_RWM 0x38 -#define EISR_MASK 0x3c -#define EISR_MASK_OPTIONS 0x001FFF7F - -#define LAPA 0x60 -#define LAPWWO 0x64 -#define LAPWWC 0x68 -#define LAPCTL 0x6C -#define LAIPD 0x78 -#define LAIPDDINC 0x7C - -#define TIMER 0x50 - -#define CLKCTL 0x74 -#define CLKCTL_PAUSE (1<<15) - -#define PM_CON 0x4 - -#define BMCTL_SUM 0x40 -#define BMCTL_RWM 0x44 -#define BMCTL_TX2_DIS (1<<30) -#define BMCTL_TX1_DIS (1<<26) -#define BMCTL_RX_DIS (1<<22) - -#define BMASR 0xcc - -#define RXDESCQ 0x90 -#define RXDESCQCNT 0x94 -#define RXCDA 0x98 -#define RXENQ 0x9C -#define RXSTATQ 0xA0 -#define RXSTATQCNT 0xA4 -#define RXCSA 0xA8 -#define RXCLEN 0xAC -#define RXHLEN 0xAE - -#define TXDESCQ_1 0xb0 -#define TXDESCQ_2 0xd0 -#define TXDESCQCNT_1 0xb4 -#define TXDESCQCNT_2 0xd4 -#define TXCDA_1 0xb8 -#define TXCDA_2 0xd8 -#define TXENQ_1 0xbc -#define TXENQ_2 0xdc -#define TXSTATQ_1 0xc0 -#define TXSTATQ_2 0xe0 -#define TXSTATQCNT_1 0xc4 -#define TXSTATQCNT_2 0xe4 -#define TXCSA_1 0xc8 -#define TXCSA_2 0xe8 -/* Cardbus */ -#define FERMASK 0xf4 -#define FERMASK_INT_BIT (1<<15) - -#define OLYMPIC_IO_SPACE 256 - -#define SRB_COMMAND_SIZE 50 - -#define OLYMPIC_MAX_ADAPTERS 8 /* 0x08 __MODULE_STRING can't hand 0xnn */ - -/* Defines for LAN STATUS CHANGE reports */ -#define LSC_SIG_LOSS 0x8000 -#define LSC_HARD_ERR 0x4000 -#define LSC_SOFT_ERR 0x2000 -#define LSC_TRAN_BCN 0x1000 -#define LSC_LWF 0x0800 -#define LSC_ARW 0x0400 -#define LSC_FPE 0x0200 -#define LSC_RR 0x0100 -#define LSC_CO 0x0080 -#define LSC_SS 0x0040 -#define LSC_RING_REC 0x0020 -#define LSC_SR_CO 0x0010 -#define LSC_FDX_MODE 0x0004 - -/* Defines for OPEN ADAPTER command */ - -#define OPEN_ADAPTER_EXT_WRAP (1<<15) -#define OPEN_ADAPTER_DIS_HARDEE (1<<14) -#define OPEN_ADAPTER_DIS_SOFTERR (1<<13) -#define OPEN_ADAPTER_PASS_ADC_MAC (1<<12) -#define OPEN_ADAPTER_PASS_ATT_MAC (1<<11) -#define OPEN_ADAPTER_ENABLE_EC (1<<10) -#define OPEN_ADAPTER_CONTENDER (1<<8) -#define OPEN_ADAPTER_PASS_BEACON (1<<7) -#define OPEN_ADAPTER_ENABLE_FDX (1<<6) -#define OPEN_ADAPTER_ENABLE_RPL (1<<5) -#define OPEN_ADAPTER_INHIBIT_ETR (1<<4) -#define OPEN_ADAPTER_INTERNAL_WRAP (1<<3) -#define OPEN_ADAPTER_USE_OPTS2 (1<<0) - -#define OPEN_ADAPTER_2_ENABLE_ONNOW (1<<15) - -/* Defines for SRB Commands */ - -#define SRB_ACCESS_REGISTER 0x1f -#define SRB_CLOSE_ADAPTER 0x04 -#define SRB_CONFIGURE_BRIDGE 0x0c -#define SRB_CONFIGURE_WAKEUP_EVENT 0x1a -#define SRB_MODIFY_BRIDGE_PARMS 0x15 -#define SRB_MODIFY_OPEN_OPTIONS 0x01 -#define SRB_MODIFY_RECEIVE_OPTIONS 0x17 -#define SRB_NO_OPERATION 0x00 -#define SRB_OPEN_ADAPTER 0x03 -#define SRB_READ_LOG 0x08 -#define SRB_READ_SR_COUNTERS 0x16 -#define SRB_RESET_GROUP_ADDRESS 0x02 -#define SRB_SAVE_CONFIGURATION 0x1b -#define SRB_SET_BRIDGE_PARMS 0x09 -#define SRB_SET_BRIDGE_TARGETS 0x10 -#define SRB_SET_FUNC_ADDRESS 0x07 -#define SRB_SET_GROUP_ADDRESS 0x06 -#define SRB_SET_GROUP_ADDR_OPTIONS 0x11 -#define SRB_UPDATE_WAKEUP_PATTERN 0x19 - -/* Clear return code */ - -#define OLYMPIC_CLEAR_RET_CODE 0xfe - -/* ARB Commands */ -#define ARB_RECEIVE_DATA 0x81 -#define ARB_LAN_CHANGE_STATUS 0x84 -/* ASB Response commands */ - -#define ASB_RECEIVE_DATA 0x81 - - -/* Olympic defaults for buffers */ - -#define OLYMPIC_RX_RING_SIZE 16 /* should be a power of 2 */ -#define OLYMPIC_TX_RING_SIZE 8 /* should be a power of 2 */ - -#define PKT_BUF_SZ 4096 /* Default packet size */ - -/* Olympic data structures */ - -/* xxxx These structures are all little endian in hardware. */ - -struct olympic_tx_desc { - __le32 buffer; - __le32 status_length; -}; - -struct olympic_tx_status { - __le32 status; -}; - -struct olympic_rx_desc { - __le32 buffer; - __le32 res_length; -}; - -struct olympic_rx_status { - __le32 fragmentcnt_framelen; - __le32 status_buffercnt; -}; -/* xxxx END These structures are all little endian in hardware. */ -/* xxxx There may be more, but I'm pretty sure about these */ - -struct mac_receive_buffer { - __le16 next ; - u8 padding ; - u8 frame_status ; - __le16 buffer_length ; - u8 frame_data ; -}; - -struct olympic_private { - - u16 srb; /* be16 */ - u16 trb; /* be16 */ - u16 arb; /* be16 */ - u16 asb; /* be16 */ - - u8 __iomem *olympic_mmio; - u8 __iomem *olympic_lap; - struct pci_dev *pdev ; - const char *olympic_card_name; - - spinlock_t olympic_lock ; - - volatile int srb_queued; /* True if an SRB is still posted */ - wait_queue_head_t srb_wait; - - volatile int asb_queued; /* True if an ASB is posted */ - - volatile int trb_queued; /* True if a TRB is posted */ - wait_queue_head_t trb_wait ; - - /* These must be on a 4 byte boundary. */ - struct olympic_rx_desc olympic_rx_ring[OLYMPIC_RX_RING_SIZE]; - struct olympic_tx_desc olympic_tx_ring[OLYMPIC_TX_RING_SIZE]; - struct olympic_rx_status olympic_rx_status_ring[OLYMPIC_RX_RING_SIZE]; - struct olympic_tx_status olympic_tx_status_ring[OLYMPIC_TX_RING_SIZE]; - - struct sk_buff *tx_ring_skb[OLYMPIC_TX_RING_SIZE], *rx_ring_skb[OLYMPIC_RX_RING_SIZE]; - int tx_ring_free, tx_ring_last_status, rx_ring_last_received,rx_status_last_received, free_tx_ring_entries; - - u16 olympic_lan_status ; - u8 olympic_ring_speed ; - u16 pkt_buf_sz ; - u8 olympic_receive_options, olympic_copy_all_options,olympic_message_level, olympic_network_monitor; - u16 olympic_addr_table_addr, olympic_parms_addr ; - u8 olympic_laa[6] ; - u32 rx_ring_dma_addr; - u32 rx_status_ring_dma_addr; - u32 tx_ring_dma_addr; - u32 tx_status_ring_dma_addr; -}; - -struct olympic_adapter_addr_table { - - u8 node_addr[6] ; - u8 reserved[4] ; - u8 func_addr[4] ; -} ; - -struct olympic_parameters_table { - - u8 phys_addr[4] ; - u8 up_node_addr[6] ; - u8 up_phys_addr[4] ; - u8 poll_addr[6] ; - u16 reserved ; - u16 acc_priority ; - u16 auth_source_class ; - u16 att_code ; - u8 source_addr[6] ; - u16 beacon_type ; - u16 major_vector ; - u16 lan_status ; - u16 soft_error_time ; - u16 reserved1 ; - u16 local_ring ; - u16 mon_error ; - u16 beacon_transmit ; - u16 beacon_receive ; - u16 frame_correl ; - u8 beacon_naun[6] ; - u32 reserved2 ; - u8 beacon_phys[4] ; -}; diff --git a/trunk/drivers/net/tokenring/proteon.c b/trunk/drivers/net/tokenring/proteon.c deleted file mode 100644 index 62d90e40f9ec..000000000000 --- a/trunk/drivers/net/tokenring/proteon.c +++ /dev/null @@ -1,422 +0,0 @@ -/* - * proteon.c: A network driver for Proteon ISA token ring cards. - * - * Based on tmspci written 1999 by Adam Fritzler - * - * Written 2003 by Jochen Friedrich - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * This driver module supports the following cards: - * - Proteon 1392, 1392+ - * - * Maintainer(s): - * AF Adam Fritzler - * JF Jochen Friedrich jochen@scram.de - * - * Modification History: - * 02-Jan-03 JF Created - * - */ -static const char version[] = "proteon.c: v1.00 02/01/2003 by Jochen Friedrich\n"; - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "tms380tr.h" - -#define PROTEON_IO_EXTENT 32 - -/* A zero-terminated list of I/O addresses to be probed. */ -static unsigned int portlist[] __initdata = { - 0x0A20, 0x0E20, 0x1A20, 0x1E20, 0x2A20, 0x2E20, 0x3A20, 0x3E20,// Prot. - 0x4A20, 0x4E20, 0x5A20, 0x5E20, 0x6A20, 0x6E20, 0x7A20, 0x7E20,// Prot. - 0x8A20, 0x8E20, 0x9A20, 0x9E20, 0xAA20, 0xAE20, 0xBA20, 0xBE20,// Prot. - 0xCA20, 0xCE20, 0xDA20, 0xDE20, 0xEA20, 0xEE20, 0xFA20, 0xFE20,// Prot. - 0 -}; - -/* A zero-terminated list of IRQs to be probed. */ -static unsigned short irqlist[] = { - 7, 6, 5, 4, 3, 12, 11, 10, 9, - 0 -}; - -/* A zero-terminated list of DMAs to be probed. */ -static int dmalist[] __initdata = { - 5, 6, 7, - 0 -}; - -static char cardname[] = "Proteon 1392\0"; -static u64 dma_mask = ISA_MAX_ADDRESS; -static int proteon_open(struct net_device *dev); -static void proteon_read_eeprom(struct net_device *dev); -static unsigned short proteon_setnselout_pins(struct net_device *dev); - -static unsigned short proteon_sifreadb(struct net_device *dev, unsigned short reg) -{ - return inb(dev->base_addr + reg); -} - -static unsigned short proteon_sifreadw(struct net_device *dev, unsigned short reg) -{ - return inw(dev->base_addr + reg); -} - -static void proteon_sifwriteb(struct net_device *dev, unsigned short val, unsigned short reg) -{ - outb(val, dev->base_addr + reg); -} - -static void proteon_sifwritew(struct net_device *dev, unsigned short val, unsigned short reg) -{ - outw(val, dev->base_addr + reg); -} - -static int __init proteon_probe1(struct net_device *dev, int ioaddr) -{ - unsigned char chk1, chk2; - int i; - - if (!request_region(ioaddr, PROTEON_IO_EXTENT, cardname)) - return -ENODEV; - - - chk1 = inb(ioaddr + 0x1f); /* Get Proteon ID reg 1 */ - if (chk1 != 0x1f) - goto nodev; - - chk1 = inb(ioaddr + 0x1e) & 0x07; /* Get Proteon ID reg 0 */ - for (i=0; i<16; i++) { - chk2 = inb(ioaddr + 0x1e) & 0x07; - if (((chk1 + 1) & 0x07) != chk2) - goto nodev; - chk1 = chk2; - } - - dev->base_addr = ioaddr; - return 0; -nodev: - release_region(ioaddr, PROTEON_IO_EXTENT); - return -ENODEV; -} - -static struct net_device_ops proteon_netdev_ops __read_mostly; - -static int __init setup_card(struct net_device *dev, struct device *pdev) -{ - struct net_local *tp; - static int versionprinted; - const unsigned *port; - int j,err = 0; - - if (!dev) - return -ENOMEM; - - if (dev->base_addr) /* probe specific location */ - err = proteon_probe1(dev, dev->base_addr); - else { - for (port = portlist; *port; port++) { - err = proteon_probe1(dev, *port); - if (!err) - break; - } - } - if (err) - goto out5; - - /* At this point we have found a valid card. */ - - if (versionprinted++ == 0) - printk(KERN_DEBUG "%s", version); - - err = -EIO; - pdev->dma_mask = &dma_mask; - if (tmsdev_init(dev, pdev)) - goto out4; - - dev->base_addr &= ~3; - - proteon_read_eeprom(dev); - - printk(KERN_DEBUG "proteon.c: Ring Station Address: %pM\n", - dev->dev_addr); - - tp = netdev_priv(dev); - tp->setnselout = proteon_setnselout_pins; - - tp->sifreadb = proteon_sifreadb; - tp->sifreadw = proteon_sifreadw; - tp->sifwriteb = proteon_sifwriteb; - tp->sifwritew = proteon_sifwritew; - - memcpy(tp->ProductID, cardname, PROD_ID_SIZE + 1); - - tp->tmspriv = NULL; - - dev->netdev_ops = &proteon_netdev_ops; - - if (dev->irq == 0) - { - for(j = 0; irqlist[j] != 0; j++) - { - dev->irq = irqlist[j]; - if (!request_irq(dev->irq, tms380tr_interrupt, 0, - cardname, dev)) - break; - } - - if(irqlist[j] == 0) - { - printk(KERN_INFO "proteon.c: AutoSelect no IRQ available\n"); - goto out3; - } - } - else - { - for(j = 0; irqlist[j] != 0; j++) - if (irqlist[j] == dev->irq) - break; - if (irqlist[j] == 0) - { - printk(KERN_INFO "proteon.c: Illegal IRQ %d specified\n", - dev->irq); - goto out3; - } - if (request_irq(dev->irq, tms380tr_interrupt, 0, - cardname, dev)) - { - printk(KERN_INFO "proteon.c: Selected IRQ %d not available\n", - dev->irq); - goto out3; - } - } - - if (dev->dma == 0) - { - for(j = 0; dmalist[j] != 0; j++) - { - dev->dma = dmalist[j]; - if (!request_dma(dev->dma, cardname)) - break; - } - - if(dmalist[j] == 0) - { - printk(KERN_INFO "proteon.c: AutoSelect no DMA available\n"); - goto out2; - } - } - else - { - for(j = 0; dmalist[j] != 0; j++) - if (dmalist[j] == dev->dma) - break; - if (dmalist[j] == 0) - { - printk(KERN_INFO "proteon.c: Illegal DMA %d specified\n", - dev->dma); - goto out2; - } - if (request_dma(dev->dma, cardname)) - { - printk(KERN_INFO "proteon.c: Selected DMA %d not available\n", - dev->dma); - goto out2; - } - } - - err = register_netdev(dev); - if (err) - goto out; - - printk(KERN_DEBUG "%s: IO: %#4lx IRQ: %d DMA: %d\n", - dev->name, dev->base_addr, dev->irq, dev->dma); - - return 0; -out: - free_dma(dev->dma); -out2: - free_irq(dev->irq, dev); -out3: - tmsdev_term(dev); -out4: - release_region(dev->base_addr, PROTEON_IO_EXTENT); -out5: - return err; -} - -/* - * Reads MAC address from adapter RAM, which should've read it from - * the onboard ROM. - * - * Calling this on a board that does not support it can be a very - * dangerous thing. The Madge board, for instance, will lock your - * machine hard when this is called. Luckily, its supported in a - * separate driver. --ASF - */ -static void proteon_read_eeprom(struct net_device *dev) -{ - int i; - - /* Address: 0000:0000 */ - proteon_sifwritew(dev, 0, SIFADX); - proteon_sifwritew(dev, 0, SIFADR); - - /* Read six byte MAC address data */ - dev->addr_len = 6; - for(i = 0; i < 6; i++) - dev->dev_addr[i] = proteon_sifreadw(dev, SIFINC) >> 8; -} - -static unsigned short proteon_setnselout_pins(struct net_device *dev) -{ - return 0; -} - -static int proteon_open(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - unsigned short val = 0; - int i; - - /* Proteon reset sequence */ - outb(0, dev->base_addr + 0x11); - mdelay(20); - outb(0x04, dev->base_addr + 0x11); - mdelay(20); - outb(0, dev->base_addr + 0x11); - mdelay(100); - - /* set control/status reg */ - val = inb(dev->base_addr + 0x11); - val |= 0x78; - val &= 0xf9; - if(tp->DataRate == SPEED_4) - val |= 0x20; - else - val &= ~0x20; - - outb(val, dev->base_addr + 0x11); - outb(0xff, dev->base_addr + 0x12); - for(i = 0; irqlist[i] != 0; i++) - { - if(irqlist[i] == dev->irq) - break; - } - val = i; - i = (7 - dev->dma) << 4; - val |= i; - outb(val, dev->base_addr + 0x13); - - return tms380tr_open(dev); -} - -#define ISATR_MAX_ADAPTERS 3 - -static int io[ISATR_MAX_ADAPTERS]; -static int irq[ISATR_MAX_ADAPTERS]; -static int dma[ISATR_MAX_ADAPTERS]; - -MODULE_LICENSE("GPL"); - -module_param_array(io, int, NULL, 0); -module_param_array(irq, int, NULL, 0); -module_param_array(dma, int, NULL, 0); - -static struct platform_device *proteon_dev[ISATR_MAX_ADAPTERS]; - -static struct platform_driver proteon_driver = { - .driver = { - .name = "proteon", - }, -}; - -static int __init proteon_init(void) -{ - struct net_device *dev; - struct platform_device *pdev; - int i, num = 0, err = 0; - - proteon_netdev_ops = tms380tr_netdev_ops; - proteon_netdev_ops.ndo_open = proteon_open; - proteon_netdev_ops.ndo_stop = tms380tr_close; - - err = platform_driver_register(&proteon_driver); - if (err) - return err; - - for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { - dev = alloc_trdev(sizeof(struct net_local)); - if (!dev) - continue; - - dev->base_addr = io[i]; - dev->irq = irq[i]; - dev->dma = dma[i]; - pdev = platform_device_register_simple("proteon", - i, NULL, 0); - if (IS_ERR(pdev)) { - free_netdev(dev); - continue; - } - err = setup_card(dev, &pdev->dev); - if (!err) { - proteon_dev[i] = pdev; - platform_set_drvdata(pdev, dev); - ++num; - } else { - platform_device_unregister(pdev); - free_netdev(dev); - } - } - - printk(KERN_NOTICE "proteon.c: %d cards found.\n", num); - /* Probe for cards. */ - if (num == 0) { - printk(KERN_NOTICE "proteon.c: No cards found.\n"); - platform_driver_unregister(&proteon_driver); - return -ENODEV; - } - return 0; -} - -static void __exit proteon_cleanup(void) -{ - struct net_device *dev; - int i; - - for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { - struct platform_device *pdev = proteon_dev[i]; - - if (!pdev) - continue; - dev = platform_get_drvdata(pdev); - unregister_netdev(dev); - release_region(dev->base_addr, PROTEON_IO_EXTENT); - free_irq(dev->irq, dev); - free_dma(dev->dma); - tmsdev_term(dev); - free_netdev(dev); - platform_set_drvdata(pdev, NULL); - platform_device_unregister(pdev); - } - platform_driver_unregister(&proteon_driver); -} - -module_init(proteon_init); -module_exit(proteon_cleanup); diff --git a/trunk/drivers/net/tokenring/skisa.c b/trunk/drivers/net/tokenring/skisa.c deleted file mode 100644 index ee11e93dc30e..000000000000 --- a/trunk/drivers/net/tokenring/skisa.c +++ /dev/null @@ -1,432 +0,0 @@ -/* - * skisa.c: A network driver for SK-NET TMS380-based ISA token ring cards. - * - * Based on tmspci written 1999 by Adam Fritzler - * - * Written 2000 by Jochen Friedrich - * Dedicated to my girlfriend Steffi Bopp - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * This driver module supports the following cards: - * - SysKonnect TR4/16(+) ISA (SK-4190) - * - * Maintainer(s): - * AF Adam Fritzler - * JF Jochen Friedrich jochen@scram.de - * - * Modification History: - * 14-Jan-01 JF Created - * 28-Oct-02 JF Fixed probe of card for static compilation. - * Fixed module init to not make hotplug go wild. - * 09-Nov-02 JF Fixed early bail out on out of memory - * situations if multiple cards are found. - * Cleaned up some unnecessary console SPAM. - * 09-Dec-02 JF Fixed module reference counting. - * 02-Jan-03 JF Renamed to skisa.c - * - */ -static const char version[] = "skisa.c: v1.03 09/12/2002 by Jochen Friedrich\n"; - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "tms380tr.h" - -#define SK_ISA_IO_EXTENT 32 - -/* A zero-terminated list of I/O addresses to be probed. */ -static unsigned int portlist[] __initdata = { - 0x0A20, 0x1A20, 0x0B20, 0x1B20, 0x0980, 0x1980, 0x0900, 0x1900,// SK - 0 -}; - -/* A zero-terminated list of IRQs to be probed. - * Used again after initial probe for sktr_chipset_init, called from sktr_open. - */ -static const unsigned short irqlist[] = { - 3, 5, 9, 10, 11, 12, 15, - 0 -}; - -/* A zero-terminated list of DMAs to be probed. */ -static int dmalist[] __initdata = { - 5, 6, 7, - 0 -}; - -static char isa_cardname[] = "SK NET TR 4/16 ISA\0"; -static u64 dma_mask = ISA_MAX_ADDRESS; -static int sk_isa_open(struct net_device *dev); -static void sk_isa_read_eeprom(struct net_device *dev); -static unsigned short sk_isa_setnselout_pins(struct net_device *dev); - -static unsigned short sk_isa_sifreadb(struct net_device *dev, unsigned short reg) -{ - return inb(dev->base_addr + reg); -} - -static unsigned short sk_isa_sifreadw(struct net_device *dev, unsigned short reg) -{ - return inw(dev->base_addr + reg); -} - -static void sk_isa_sifwriteb(struct net_device *dev, unsigned short val, unsigned short reg) -{ - outb(val, dev->base_addr + reg); -} - -static void sk_isa_sifwritew(struct net_device *dev, unsigned short val, unsigned short reg) -{ - outw(val, dev->base_addr + reg); -} - - -static int __init sk_isa_probe1(struct net_device *dev, int ioaddr) -{ - unsigned char old, chk1, chk2; - - if (!request_region(ioaddr, SK_ISA_IO_EXTENT, isa_cardname)) - return -ENODEV; - - old = inb(ioaddr + SIFADR); /* Get the old SIFADR value */ - - chk1 = 0; /* Begin with check value 0 */ - do { - /* Write new SIFADR value */ - outb(chk1, ioaddr + SIFADR); - - /* Read, invert and write */ - chk2 = inb(ioaddr + SIFADD); - chk2 ^= 0x0FE; - outb(chk2, ioaddr + SIFADR); - - /* Read, invert and compare */ - chk2 = inb(ioaddr + SIFADD); - chk2 ^= 0x0FE; - - if(chk1 != chk2) { - release_region(ioaddr, SK_ISA_IO_EXTENT); - return -ENODEV; - } - - chk1 -= 2; - } while(chk1 != 0); /* Repeat 128 times (all byte values) */ - - /* Restore the SIFADR value */ - outb(old, ioaddr + SIFADR); - - dev->base_addr = ioaddr; - return 0; -} - -static struct net_device_ops sk_isa_netdev_ops __read_mostly; - -static int __init setup_card(struct net_device *dev, struct device *pdev) -{ - struct net_local *tp; - static int versionprinted; - const unsigned *port; - int j, err = 0; - - if (!dev) - return -ENOMEM; - - if (dev->base_addr) /* probe specific location */ - err = sk_isa_probe1(dev, dev->base_addr); - else { - for (port = portlist; *port; port++) { - err = sk_isa_probe1(dev, *port); - if (!err) - break; - } - } - if (err) - goto out5; - - /* At this point we have found a valid card. */ - - if (versionprinted++ == 0) - printk(KERN_DEBUG "%s", version); - - err = -EIO; - pdev->dma_mask = &dma_mask; - if (tmsdev_init(dev, pdev)) - goto out4; - - dev->base_addr &= ~3; - - sk_isa_read_eeprom(dev); - - printk(KERN_DEBUG "skisa.c: Ring Station Address: %pM\n", - dev->dev_addr); - - tp = netdev_priv(dev); - tp->setnselout = sk_isa_setnselout_pins; - - tp->sifreadb = sk_isa_sifreadb; - tp->sifreadw = sk_isa_sifreadw; - tp->sifwriteb = sk_isa_sifwriteb; - tp->sifwritew = sk_isa_sifwritew; - - memcpy(tp->ProductID, isa_cardname, PROD_ID_SIZE + 1); - - tp->tmspriv = NULL; - - dev->netdev_ops = &sk_isa_netdev_ops; - - if (dev->irq == 0) - { - for(j = 0; irqlist[j] != 0; j++) - { - dev->irq = irqlist[j]; - if (!request_irq(dev->irq, tms380tr_interrupt, 0, - isa_cardname, dev)) - break; - } - - if(irqlist[j] == 0) - { - printk(KERN_INFO "skisa.c: AutoSelect no IRQ available\n"); - goto out3; - } - } - else - { - for(j = 0; irqlist[j] != 0; j++) - if (irqlist[j] == dev->irq) - break; - if (irqlist[j] == 0) - { - printk(KERN_INFO "skisa.c: Illegal IRQ %d specified\n", - dev->irq); - goto out3; - } - if (request_irq(dev->irq, tms380tr_interrupt, 0, - isa_cardname, dev)) - { - printk(KERN_INFO "skisa.c: Selected IRQ %d not available\n", - dev->irq); - goto out3; - } - } - - if (dev->dma == 0) - { - for(j = 0; dmalist[j] != 0; j++) - { - dev->dma = dmalist[j]; - if (!request_dma(dev->dma, isa_cardname)) - break; - } - - if(dmalist[j] == 0) - { - printk(KERN_INFO "skisa.c: AutoSelect no DMA available\n"); - goto out2; - } - } - else - { - for(j = 0; dmalist[j] != 0; j++) - if (dmalist[j] == dev->dma) - break; - if (dmalist[j] == 0) - { - printk(KERN_INFO "skisa.c: Illegal DMA %d specified\n", - dev->dma); - goto out2; - } - if (request_dma(dev->dma, isa_cardname)) - { - printk(KERN_INFO "skisa.c: Selected DMA %d not available\n", - dev->dma); - goto out2; - } - } - - err = register_netdev(dev); - if (err) - goto out; - - printk(KERN_DEBUG "%s: IO: %#4lx IRQ: %d DMA: %d\n", - dev->name, dev->base_addr, dev->irq, dev->dma); - - return 0; -out: - free_dma(dev->dma); -out2: - free_irq(dev->irq, dev); -out3: - tmsdev_term(dev); -out4: - release_region(dev->base_addr, SK_ISA_IO_EXTENT); -out5: - return err; -} - -/* - * Reads MAC address from adapter RAM, which should've read it from - * the onboard ROM. - * - * Calling this on a board that does not support it can be a very - * dangerous thing. The Madge board, for instance, will lock your - * machine hard when this is called. Luckily, its supported in a - * separate driver. --ASF - */ -static void sk_isa_read_eeprom(struct net_device *dev) -{ - int i; - - /* Address: 0000:0000 */ - sk_isa_sifwritew(dev, 0, SIFADX); - sk_isa_sifwritew(dev, 0, SIFADR); - - /* Read six byte MAC address data */ - dev->addr_len = 6; - for(i = 0; i < 6; i++) - dev->dev_addr[i] = sk_isa_sifreadw(dev, SIFINC) >> 8; -} - -static unsigned short sk_isa_setnselout_pins(struct net_device *dev) -{ - return 0; -} - -static int sk_isa_open(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - unsigned short val = 0; - unsigned short oldval; - int i; - - val = 0; - for(i = 0; irqlist[i] != 0; i++) - { - if(irqlist[i] == dev->irq) - break; - } - - val |= CYCLE_TIME << 2; - val |= i << 4; - i = dev->dma - 5; - val |= i; - if(tp->DataRate == SPEED_4) - val |= LINE_SPEED_BIT; - else - val &= ~LINE_SPEED_BIT; - oldval = sk_isa_sifreadb(dev, POSREG); - /* Leave cycle bits alone */ - oldval |= 0xf3; - val &= oldval; - sk_isa_sifwriteb(dev, val, POSREG); - - return tms380tr_open(dev); -} - -#define ISATR_MAX_ADAPTERS 3 - -static int io[ISATR_MAX_ADAPTERS]; -static int irq[ISATR_MAX_ADAPTERS]; -static int dma[ISATR_MAX_ADAPTERS]; - -MODULE_LICENSE("GPL"); - -module_param_array(io, int, NULL, 0); -module_param_array(irq, int, NULL, 0); -module_param_array(dma, int, NULL, 0); - -static struct platform_device *sk_isa_dev[ISATR_MAX_ADAPTERS]; - -static struct platform_driver sk_isa_driver = { - .driver = { - .name = "skisa", - }, -}; - -static int __init sk_isa_init(void) -{ - struct net_device *dev; - struct platform_device *pdev; - int i, num = 0, err = 0; - - sk_isa_netdev_ops = tms380tr_netdev_ops; - sk_isa_netdev_ops.ndo_open = sk_isa_open; - sk_isa_netdev_ops.ndo_stop = tms380tr_close; - - err = platform_driver_register(&sk_isa_driver); - if (err) - return err; - - for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { - dev = alloc_trdev(sizeof(struct net_local)); - if (!dev) - continue; - - dev->base_addr = io[i]; - dev->irq = irq[i]; - dev->dma = dma[i]; - pdev = platform_device_register_simple("skisa", - i, NULL, 0); - if (IS_ERR(pdev)) { - free_netdev(dev); - continue; - } - err = setup_card(dev, &pdev->dev); - if (!err) { - sk_isa_dev[i] = pdev; - platform_set_drvdata(sk_isa_dev[i], dev); - ++num; - } else { - platform_device_unregister(pdev); - free_netdev(dev); - } - } - - printk(KERN_NOTICE "skisa.c: %d cards found.\n", num); - /* Probe for cards. */ - if (num == 0) { - printk(KERN_NOTICE "skisa.c: No cards found.\n"); - platform_driver_unregister(&sk_isa_driver); - return -ENODEV; - } - return 0; -} - -static void __exit sk_isa_cleanup(void) -{ - struct net_device *dev; - int i; - - for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { - struct platform_device *pdev = sk_isa_dev[i]; - - if (!pdev) - continue; - dev = platform_get_drvdata(pdev); - unregister_netdev(dev); - release_region(dev->base_addr, SK_ISA_IO_EXTENT); - free_irq(dev->irq, dev); - free_dma(dev->dma); - tmsdev_term(dev); - free_netdev(dev); - platform_set_drvdata(pdev, NULL); - platform_device_unregister(pdev); - } - platform_driver_unregister(&sk_isa_driver); -} - -module_init(sk_isa_init); -module_exit(sk_isa_cleanup); diff --git a/trunk/drivers/net/tokenring/smctr.c b/trunk/drivers/net/tokenring/smctr.c deleted file mode 100644 index cb35fb79e016..000000000000 --- a/trunk/drivers/net/tokenring/smctr.c +++ /dev/null @@ -1,5717 +0,0 @@ -/* - * smctr.c: A network driver for the SMC Token Ring Adapters. - * - * Written by Jay Schulist - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * This device driver works with the following SMC adapters: - * - SMC TokenCard Elite (8115T, chips 825/584) - * - SMC TokenCard Elite/A MCA (8115T/A, chips 825/594) - * - * Source(s): - * - SMC TokenCard SDK. - * - * Maintainer(s): - * JS Jay Schulist - * - * Changes: - * 07102000 JS Fixed a timing problem in smctr_wait_cmd(); - * Also added a bit more discriptive error msgs. - * 07122000 JS Fixed problem with detecting a card with - * module io/irq/mem specified. - * - * To do: - * 1. Multicast support. - * - * Initial 2.5 cleanup Alan Cox 2002/10/28 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#if BITS_PER_LONG == 64 -#error FIXME: driver does not support 64-bit platforms -#endif - -#include "smctr.h" /* Our Stuff */ - -static const char version[] __initdata = - KERN_INFO "smctr.c: v1.4 7/12/00 by jschlst@samba.org\n"; -static const char cardname[] = "smctr"; - - -#define SMCTR_IO_EXTENT 20 - -#ifdef CONFIG_MCA_LEGACY -static unsigned int smctr_posid = 0x6ec6; -#endif - -static int ringspeed; - -/* SMC Name of the Adapter. */ -static char smctr_name[] = "SMC TokenCard"; -static char *smctr_model = "Unknown"; - -/* Use 0 for production, 1 for verification, 2 for debug, and - * 3 for very verbose debug. - */ -#ifndef SMCTR_DEBUG -#define SMCTR_DEBUG 1 -#endif -static unsigned int smctr_debug = SMCTR_DEBUG; - -/* smctr.c prototypes and functions are arranged alphabeticly - * for clearity, maintainability and pure old fashion fun. - */ -/* A */ -static int smctr_alloc_shared_memory(struct net_device *dev); - -/* B */ -static int smctr_bypass_state(struct net_device *dev); - -/* C */ -static int smctr_checksum_firmware(struct net_device *dev); -static int __init smctr_chk_isa(struct net_device *dev); -static int smctr_chg_rx_mask(struct net_device *dev); -static int smctr_clear_int(struct net_device *dev); -static int smctr_clear_trc_reset(int ioaddr); -static int smctr_close(struct net_device *dev); - -/* D */ -static int smctr_decode_firmware(struct net_device *dev, - const struct firmware *fw); -static int smctr_disable_16bit(struct net_device *dev); -static int smctr_disable_adapter_ctrl_store(struct net_device *dev); -static int smctr_disable_bic_int(struct net_device *dev); - -/* E */ -static int smctr_enable_16bit(struct net_device *dev); -static int smctr_enable_adapter_ctrl_store(struct net_device *dev); -static int smctr_enable_adapter_ram(struct net_device *dev); -static int smctr_enable_bic_int(struct net_device *dev); - -/* G */ -static int __init smctr_get_boardid(struct net_device *dev, int mca); -static int smctr_get_group_address(struct net_device *dev); -static int smctr_get_functional_address(struct net_device *dev); -static unsigned int smctr_get_num_rx_bdbs(struct net_device *dev); -static int smctr_get_physical_drop_number(struct net_device *dev); -static __u8 *smctr_get_rx_pointer(struct net_device *dev, short queue); -static int smctr_get_station_id(struct net_device *dev); -static FCBlock *smctr_get_tx_fcb(struct net_device *dev, __u16 queue, - __u16 bytes_count); -static int smctr_get_upstream_neighbor_addr(struct net_device *dev); - -/* H */ -static int smctr_hardware_send_packet(struct net_device *dev, - struct net_local *tp); -/* I */ -static int smctr_init_acbs(struct net_device *dev); -static int smctr_init_adapter(struct net_device *dev); -static int smctr_init_card_real(struct net_device *dev); -static int smctr_init_rx_bdbs(struct net_device *dev); -static int smctr_init_rx_fcbs(struct net_device *dev); -static int smctr_init_shared_memory(struct net_device *dev); -static int smctr_init_tx_bdbs(struct net_device *dev); -static int smctr_init_tx_fcbs(struct net_device *dev); -static int smctr_internal_self_test(struct net_device *dev); -static irqreturn_t smctr_interrupt(int irq, void *dev_id); -static int smctr_issue_enable_int_cmd(struct net_device *dev, - __u16 interrupt_enable_mask); -static int smctr_issue_int_ack(struct net_device *dev, __u16 iack_code, - __u16 ibits); -static int smctr_issue_init_timers_cmd(struct net_device *dev); -static int smctr_issue_init_txrx_cmd(struct net_device *dev); -static int smctr_issue_insert_cmd(struct net_device *dev); -static int smctr_issue_read_ring_status_cmd(struct net_device *dev); -static int smctr_issue_read_word_cmd(struct net_device *dev, __u16 aword_cnt); -static int smctr_issue_remove_cmd(struct net_device *dev); -static int smctr_issue_resume_acb_cmd(struct net_device *dev); -static int smctr_issue_resume_rx_bdb_cmd(struct net_device *dev, __u16 queue); -static int smctr_issue_resume_rx_fcb_cmd(struct net_device *dev, __u16 queue); -static int smctr_issue_resume_tx_fcb_cmd(struct net_device *dev, __u16 queue); -static int smctr_issue_test_internal_rom_cmd(struct net_device *dev); -static int smctr_issue_test_hic_cmd(struct net_device *dev); -static int smctr_issue_test_mac_reg_cmd(struct net_device *dev); -static int smctr_issue_trc_loopback_cmd(struct net_device *dev); -static int smctr_issue_tri_loopback_cmd(struct net_device *dev); -static int smctr_issue_write_byte_cmd(struct net_device *dev, - short aword_cnt, void *byte); -static int smctr_issue_write_word_cmd(struct net_device *dev, - short aword_cnt, void *word); - -/* J */ -static int smctr_join_complete_state(struct net_device *dev); - -/* L */ -static int smctr_link_tx_fcbs_to_bdbs(struct net_device *dev); -static int smctr_load_firmware(struct net_device *dev); -static int smctr_load_node_addr(struct net_device *dev); -static int smctr_lobe_media_test(struct net_device *dev); -static int smctr_lobe_media_test_cmd(struct net_device *dev); -static int smctr_lobe_media_test_state(struct net_device *dev); - -/* M */ -static int smctr_make_8025_hdr(struct net_device *dev, - MAC_HEADER *rmf, MAC_HEADER *tmf, __u16 ac_fc); -static int smctr_make_access_pri(struct net_device *dev, - MAC_SUB_VECTOR *tsv); -static int smctr_make_addr_mod(struct net_device *dev, MAC_SUB_VECTOR *tsv); -static int smctr_make_auth_funct_class(struct net_device *dev, - MAC_SUB_VECTOR *tsv); -static int smctr_make_corr(struct net_device *dev, - MAC_SUB_VECTOR *tsv, __u16 correlator); -static int smctr_make_funct_addr(struct net_device *dev, - MAC_SUB_VECTOR *tsv); -static int smctr_make_group_addr(struct net_device *dev, - MAC_SUB_VECTOR *tsv); -static int smctr_make_phy_drop_num(struct net_device *dev, - MAC_SUB_VECTOR *tsv); -static int smctr_make_product_id(struct net_device *dev, MAC_SUB_VECTOR *tsv); -static int smctr_make_station_id(struct net_device *dev, MAC_SUB_VECTOR *tsv); -static int smctr_make_ring_station_status(struct net_device *dev, - MAC_SUB_VECTOR *tsv); -static int smctr_make_ring_station_version(struct net_device *dev, - MAC_SUB_VECTOR *tsv); -static int smctr_make_tx_status_code(struct net_device *dev, - MAC_SUB_VECTOR *tsv, __u16 tx_fstatus); -static int smctr_make_upstream_neighbor_addr(struct net_device *dev, - MAC_SUB_VECTOR *tsv); -static int smctr_make_wrap_data(struct net_device *dev, - MAC_SUB_VECTOR *tsv); - -/* O */ -static int smctr_open(struct net_device *dev); -static int smctr_open_tr(struct net_device *dev); - -/* P */ -struct net_device *smctr_probe(int unit); -static int __init smctr_probe1(struct net_device *dev, int ioaddr); -static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size, - struct net_device *dev, __u16 rx_status); - -/* R */ -static int smctr_ram_memory_test(struct net_device *dev); -static int smctr_rcv_chg_param(struct net_device *dev, MAC_HEADER *rmf, - __u16 *correlator); -static int smctr_rcv_init(struct net_device *dev, MAC_HEADER *rmf, - __u16 *correlator); -static int smctr_rcv_tx_forward(struct net_device *dev, MAC_HEADER *rmf); -static int smctr_rcv_rq_addr_state_attch(struct net_device *dev, - MAC_HEADER *rmf, __u16 *correlator); -static int smctr_rcv_unknown(struct net_device *dev, MAC_HEADER *rmf, - __u16 *correlator); -static int smctr_reset_adapter(struct net_device *dev); -static int smctr_restart_tx_chain(struct net_device *dev, short queue); -static int smctr_ring_status_chg(struct net_device *dev); -static int smctr_rx_frame(struct net_device *dev); - -/* S */ -static int smctr_send_dat(struct net_device *dev); -static netdev_tx_t smctr_send_packet(struct sk_buff *skb, - struct net_device *dev); -static int smctr_send_lobe_media_test(struct net_device *dev); -static int smctr_send_rpt_addr(struct net_device *dev, MAC_HEADER *rmf, - __u16 correlator); -static int smctr_send_rpt_attch(struct net_device *dev, MAC_HEADER *rmf, - __u16 correlator); -static int smctr_send_rpt_state(struct net_device *dev, MAC_HEADER *rmf, - __u16 correlator); -static int smctr_send_rpt_tx_forward(struct net_device *dev, - MAC_HEADER *rmf, __u16 tx_fstatus); -static int smctr_send_rsp(struct net_device *dev, MAC_HEADER *rmf, - __u16 rcode, __u16 correlator); -static int smctr_send_rq_init(struct net_device *dev); -static int smctr_send_tx_forward(struct net_device *dev, MAC_HEADER *rmf, - __u16 *tx_fstatus); -static int smctr_set_auth_access_pri(struct net_device *dev, - MAC_SUB_VECTOR *rsv); -static int smctr_set_auth_funct_class(struct net_device *dev, - MAC_SUB_VECTOR *rsv); -static int smctr_set_corr(struct net_device *dev, MAC_SUB_VECTOR *rsv, - __u16 *correlator); -static int smctr_set_error_timer_value(struct net_device *dev, - MAC_SUB_VECTOR *rsv); -static int smctr_set_frame_forward(struct net_device *dev, - MAC_SUB_VECTOR *rsv, __u8 dc_sc); -static int smctr_set_local_ring_num(struct net_device *dev, - MAC_SUB_VECTOR *rsv); -static unsigned short smctr_set_ctrl_attention(struct net_device *dev); -static void smctr_set_multicast_list(struct net_device *dev); -static int smctr_set_page(struct net_device *dev, __u8 *buf); -static int smctr_set_phy_drop(struct net_device *dev, - MAC_SUB_VECTOR *rsv); -static int smctr_set_ring_speed(struct net_device *dev); -static int smctr_set_rx_look_ahead(struct net_device *dev); -static int smctr_set_trc_reset(int ioaddr); -static int smctr_setup_single_cmd(struct net_device *dev, - __u16 command, __u16 subcommand); -static int smctr_setup_single_cmd_w_data(struct net_device *dev, - __u16 command, __u16 subcommand); -static char *smctr_malloc(struct net_device *dev, __u16 size); -static int smctr_status_chg(struct net_device *dev); - -/* T */ -static void smctr_timeout(struct net_device *dev); -static int smctr_trc_send_packet(struct net_device *dev, FCBlock *fcb, - __u16 queue); -static __u16 smctr_tx_complete(struct net_device *dev, __u16 queue); -static unsigned short smctr_tx_move_frame(struct net_device *dev, - struct sk_buff *skb, __u8 *pbuff, unsigned int bytes); - -/* U */ -static int smctr_update_err_stats(struct net_device *dev); -static int smctr_update_rx_chain(struct net_device *dev, __u16 queue); -static int smctr_update_tx_chain(struct net_device *dev, FCBlock *fcb, - __u16 queue); - -/* W */ -static int smctr_wait_cmd(struct net_device *dev); -static int smctr_wait_while_cbusy(struct net_device *dev); - -#define TO_256_BYTE_BOUNDRY(X) (((X + 0xff) & 0xff00) - X) -#define TO_PARAGRAPH_BOUNDRY(X) (((X + 0x0f) & 0xfff0) - X) -#define PARAGRAPH_BOUNDRY(X) smctr_malloc(dev, TO_PARAGRAPH_BOUNDRY(X)) - -/* Allocate Adapter Shared Memory. - * IMPORTANT NOTE: Any changes to this function MUST be mirrored in the - * function "get_num_rx_bdbs" below!!! - * - * Order of memory allocation: - * - * 0. Initial System Configuration Block Pointer - * 1. System Configuration Block - * 2. System Control Block - * 3. Action Command Block - * 4. Interrupt Status Block - * - * 5. MAC TX FCB'S - * 6. NON-MAC TX FCB'S - * 7. MAC TX BDB'S - * 8. NON-MAC TX BDB'S - * 9. MAC RX FCB'S - * 10. NON-MAC RX FCB'S - * 11. MAC RX BDB'S - * 12. NON-MAC RX BDB'S - * 13. MAC TX Data Buffer( 1, 256 byte buffer) - * 14. MAC RX Data Buffer( 1, 256 byte buffer) - * - * 15. NON-MAC TX Data Buffer - * 16. NON-MAC RX Data Buffer - */ -static int smctr_alloc_shared_memory(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_alloc_shared_memory\n", dev->name); - - /* Allocate initial System Control Block pointer. - * This pointer is located in the last page, last offset - 4. - */ - tp->iscpb_ptr = (ISCPBlock *)(tp->ram_access + ((__u32)64 * 0x400) - - (long)ISCP_BLOCK_SIZE); - - /* Allocate System Control Blocks. */ - tp->scgb_ptr = (SCGBlock *)smctr_malloc(dev, sizeof(SCGBlock)); - PARAGRAPH_BOUNDRY(tp->sh_mem_used); - - tp->sclb_ptr = (SCLBlock *)smctr_malloc(dev, sizeof(SCLBlock)); - PARAGRAPH_BOUNDRY(tp->sh_mem_used); - - tp->acb_head = (ACBlock *)smctr_malloc(dev, - sizeof(ACBlock)*tp->num_acbs); - PARAGRAPH_BOUNDRY(tp->sh_mem_used); - - tp->isb_ptr = (ISBlock *)smctr_malloc(dev, sizeof(ISBlock)); - PARAGRAPH_BOUNDRY(tp->sh_mem_used); - - tp->misc_command_data = (__u16 *)smctr_malloc(dev, MISC_DATA_SIZE); - PARAGRAPH_BOUNDRY(tp->sh_mem_used); - - /* Allocate transmit FCBs. */ - tp->tx_fcb_head[MAC_QUEUE] = (FCBlock *)smctr_malloc(dev, - sizeof(FCBlock) * tp->num_tx_fcbs[MAC_QUEUE]); - - tp->tx_fcb_head[NON_MAC_QUEUE] = (FCBlock *)smctr_malloc(dev, - sizeof(FCBlock) * tp->num_tx_fcbs[NON_MAC_QUEUE]); - - tp->tx_fcb_head[BUG_QUEUE] = (FCBlock *)smctr_malloc(dev, - sizeof(FCBlock) * tp->num_tx_fcbs[BUG_QUEUE]); - - /* Allocate transmit BDBs. */ - tp->tx_bdb_head[MAC_QUEUE] = (BDBlock *)smctr_malloc(dev, - sizeof(BDBlock) * tp->num_tx_bdbs[MAC_QUEUE]); - - tp->tx_bdb_head[NON_MAC_QUEUE] = (BDBlock *)smctr_malloc(dev, - sizeof(BDBlock) * tp->num_tx_bdbs[NON_MAC_QUEUE]); - - tp->tx_bdb_head[BUG_QUEUE] = (BDBlock *)smctr_malloc(dev, - sizeof(BDBlock) * tp->num_tx_bdbs[BUG_QUEUE]); - - /* Allocate receive FCBs. */ - tp->rx_fcb_head[MAC_QUEUE] = (FCBlock *)smctr_malloc(dev, - sizeof(FCBlock) * tp->num_rx_fcbs[MAC_QUEUE]); - - tp->rx_fcb_head[NON_MAC_QUEUE] = (FCBlock *)smctr_malloc(dev, - sizeof(FCBlock) * tp->num_rx_fcbs[NON_MAC_QUEUE]); - - /* Allocate receive BDBs. */ - tp->rx_bdb_head[MAC_QUEUE] = (BDBlock *)smctr_malloc(dev, - sizeof(BDBlock) * tp->num_rx_bdbs[MAC_QUEUE]); - - tp->rx_bdb_end[MAC_QUEUE] = (BDBlock *)smctr_malloc(dev, 0); - - tp->rx_bdb_head[NON_MAC_QUEUE] = (BDBlock *)smctr_malloc(dev, - sizeof(BDBlock) * tp->num_rx_bdbs[NON_MAC_QUEUE]); - - tp->rx_bdb_end[NON_MAC_QUEUE] = (BDBlock *)smctr_malloc(dev, 0); - - /* Allocate MAC transmit buffers. - * MAC Tx Buffers doen't have to be on an ODD Boundary. - */ - tp->tx_buff_head[MAC_QUEUE] - = (__u16 *)smctr_malloc(dev, tp->tx_buff_size[MAC_QUEUE]); - tp->tx_buff_curr[MAC_QUEUE] = tp->tx_buff_head[MAC_QUEUE]; - tp->tx_buff_end [MAC_QUEUE] = (__u16 *)smctr_malloc(dev, 0); - - /* Allocate BUG transmit buffers. */ - tp->tx_buff_head[BUG_QUEUE] - = (__u16 *)smctr_malloc(dev, tp->tx_buff_size[BUG_QUEUE]); - tp->tx_buff_curr[BUG_QUEUE] = tp->tx_buff_head[BUG_QUEUE]; - tp->tx_buff_end[BUG_QUEUE] = (__u16 *)smctr_malloc(dev, 0); - - /* Allocate MAC receive data buffers. - * MAC Rx buffer doesn't have to be on a 256 byte boundary. - */ - tp->rx_buff_head[MAC_QUEUE] = (__u16 *)smctr_malloc(dev, - RX_DATA_BUFFER_SIZE * tp->num_rx_bdbs[MAC_QUEUE]); - tp->rx_buff_end[MAC_QUEUE] = (__u16 *)smctr_malloc(dev, 0); - - /* Allocate Non-MAC transmit buffers. - * ?? For maximum Netware performance, put Tx Buffers on - * ODD Boundary and then restore malloc to Even Boundrys. - */ - smctr_malloc(dev, 1L); - tp->tx_buff_head[NON_MAC_QUEUE] - = (__u16 *)smctr_malloc(dev, tp->tx_buff_size[NON_MAC_QUEUE]); - tp->tx_buff_curr[NON_MAC_QUEUE] = tp->tx_buff_head[NON_MAC_QUEUE]; - tp->tx_buff_end [NON_MAC_QUEUE] = (__u16 *)smctr_malloc(dev, 0); - smctr_malloc(dev, 1L); - - /* Allocate Non-MAC receive data buffers. - * To guarantee a minimum of 256 contiguous memory to - * UM_Receive_Packet's lookahead pointer, before a page - * change or ring end is encountered, place each rx buffer on - * a 256 byte boundary. - */ - smctr_malloc(dev, TO_256_BYTE_BOUNDRY(tp->sh_mem_used)); - tp->rx_buff_head[NON_MAC_QUEUE] = (__u16 *)smctr_malloc(dev, - RX_DATA_BUFFER_SIZE * tp->num_rx_bdbs[NON_MAC_QUEUE]); - tp->rx_buff_end[NON_MAC_QUEUE] = (__u16 *)smctr_malloc(dev, 0); - - return 0; -} - -/* Enter Bypass state. */ -static int smctr_bypass_state(struct net_device *dev) -{ - int err; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_bypass_state\n", dev->name); - - err = smctr_setup_single_cmd(dev, ACB_CMD_CHANGE_JOIN_STATE, JS_BYPASS_STATE); - - return err; -} - -static int smctr_checksum_firmware(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - __u16 i, checksum = 0; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_checksum_firmware\n", dev->name); - - smctr_enable_adapter_ctrl_store(dev); - - for(i = 0; i < CS_RAM_SIZE; i += 2) - checksum += *((__u16 *)(tp->ram_access + i)); - - tp->microcode_version = *(__u16 *)(tp->ram_access - + CS_RAM_VERSION_OFFSET); - tp->microcode_version >>= 8; - - smctr_disable_adapter_ctrl_store(dev); - - if(checksum) - return checksum; - - return 0; -} - -static int __init smctr_chk_mca(struct net_device *dev) -{ -#ifdef CONFIG_MCA_LEGACY - struct net_local *tp = netdev_priv(dev); - int current_slot; - __u8 r1, r2, r3, r4, r5; - - current_slot = mca_find_unused_adapter(smctr_posid, 0); - if(current_slot == MCA_NOTFOUND) - return -ENODEV; - - mca_set_adapter_name(current_slot, smctr_name); - mca_mark_as_used(current_slot); - tp->slot_num = current_slot; - - r1 = mca_read_stored_pos(tp->slot_num, 2); - r2 = mca_read_stored_pos(tp->slot_num, 3); - - if(tp->slot_num) - outb(CNFG_POS_CONTROL_REG, (__u8)((tp->slot_num - 1) | CNFG_SLOT_ENABLE_BIT)); - else - outb(CNFG_POS_CONTROL_REG, (__u8)((tp->slot_num) | CNFG_SLOT_ENABLE_BIT)); - - r1 = inb(CNFG_POS_REG1); - r2 = inb(CNFG_POS_REG0); - - tp->bic_type = BIC_594_CHIP; - - /* IO */ - r2 = mca_read_stored_pos(tp->slot_num, 2); - r2 &= 0xF0; - dev->base_addr = ((__u16)r2 << 8) + (__u16)0x800; - request_region(dev->base_addr, SMCTR_IO_EXTENT, smctr_name); - - /* IRQ */ - r5 = mca_read_stored_pos(tp->slot_num, 5); - r5 &= 0xC; - switch(r5) - { - case 0: - dev->irq = 3; - break; - - case 0x4: - dev->irq = 4; - break; - - case 0x8: - dev->irq = 10; - break; - - default: - dev->irq = 15; - break; - } - if (request_irq(dev->irq, smctr_interrupt, IRQF_SHARED, smctr_name, dev)) { - release_region(dev->base_addr, SMCTR_IO_EXTENT); - return -ENODEV; - } - - /* Get RAM base */ - r3 = mca_read_stored_pos(tp->slot_num, 3); - tp->ram_base = ((__u32)(r3 & 0x7) << 13) + 0x0C0000; - if (r3 & 0x8) - tp->ram_base += 0x010000; - if (r3 & 0x80) - tp->ram_base += 0xF00000; - - /* Get Ram Size */ - r3 &= 0x30; - r3 >>= 4; - - tp->ram_usable = (__u16)CNFG_SIZE_8KB << r3; - tp->ram_size = (__u16)CNFG_SIZE_64KB; - tp->board_id |= TOKEN_MEDIA; - - r4 = mca_read_stored_pos(tp->slot_num, 4); - tp->rom_base = ((__u32)(r4 & 0x7) << 13) + 0x0C0000; - if (r4 & 0x8) - tp->rom_base += 0x010000; - - /* Get ROM size. */ - r4 >>= 4; - switch (r4) { - case 0: - tp->rom_size = CNFG_SIZE_8KB; - break; - case 1: - tp->rom_size = CNFG_SIZE_16KB; - break; - case 2: - tp->rom_size = CNFG_SIZE_32KB; - break; - default: - tp->rom_size = ROM_DISABLE; - } - - /* Get Media Type. */ - r5 = mca_read_stored_pos(tp->slot_num, 5); - r5 &= CNFG_MEDIA_TYPE_MASK; - switch(r5) - { - case (0): - tp->media_type = MEDIA_STP_4; - break; - - case (1): - tp->media_type = MEDIA_STP_16; - break; - - case (3): - tp->media_type = MEDIA_UTP_16; - break; - - default: - tp->media_type = MEDIA_UTP_4; - break; - } - tp->media_menu = 14; - - r2 = mca_read_stored_pos(tp->slot_num, 2); - if(!(r2 & 0x02)) - tp->mode_bits |= EARLY_TOKEN_REL; - - /* Disable slot */ - outb(CNFG_POS_CONTROL_REG, 0); - - tp->board_id = smctr_get_boardid(dev, 1); - switch(tp->board_id & 0xffff) - { - case WD8115TA: - smctr_model = "8115T/A"; - break; - - case WD8115T: - if(tp->extra_info & CHIP_REV_MASK) - smctr_model = "8115T rev XE"; - else - smctr_model = "8115T rev XD"; - break; - - default: - smctr_model = "Unknown"; - break; - } - - return 0; -#else - return -1; -#endif /* CONFIG_MCA_LEGACY */ -} - -static int smctr_chg_rx_mask(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - int err = 0; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_chg_rx_mask\n", dev->name); - - smctr_enable_16bit(dev); - smctr_set_page(dev, (__u8 *)tp->ram_access); - - if(tp->mode_bits & LOOPING_MODE_MASK) - tp->config_word0 |= RX_OWN_BIT; - else - tp->config_word0 &= ~RX_OWN_BIT; - - if(tp->receive_mask & PROMISCUOUS_MODE) - tp->config_word0 |= PROMISCUOUS_BIT; - else - tp->config_word0 &= ~PROMISCUOUS_BIT; - - if(tp->receive_mask & ACCEPT_ERR_PACKETS) - tp->config_word0 |= SAVBAD_BIT; - else - tp->config_word0 &= ~SAVBAD_BIT; - - if(tp->receive_mask & ACCEPT_ATT_MAC_FRAMES) - tp->config_word0 |= RXATMAC; - else - tp->config_word0 &= ~RXATMAC; - - if(tp->receive_mask & ACCEPT_MULTI_PROM) - tp->config_word1 |= MULTICAST_ADDRESS_BIT; - else - tp->config_word1 &= ~MULTICAST_ADDRESS_BIT; - - if(tp->receive_mask & ACCEPT_SOURCE_ROUTING_SPANNING) - tp->config_word1 |= SOURCE_ROUTING_SPANNING_BITS; - else - { - if(tp->receive_mask & ACCEPT_SOURCE_ROUTING) - tp->config_word1 |= SOURCE_ROUTING_EXPLORER_BIT; - else - tp->config_word1 &= ~SOURCE_ROUTING_SPANNING_BITS; - } - - if((err = smctr_issue_write_word_cmd(dev, RW_CONFIG_REGISTER_0, - &tp->config_word0))) - { - return err; - } - - if((err = smctr_issue_write_word_cmd(dev, RW_CONFIG_REGISTER_1, - &tp->config_word1))) - { - return err; - } - - smctr_disable_16bit(dev); - - return 0; -} - -static int smctr_clear_int(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - - outb((tp->trc_mask | CSR_CLRTINT), dev->base_addr + CSR); - - return 0; -} - -static int smctr_clear_trc_reset(int ioaddr) -{ - __u8 r; - - r = inb(ioaddr + MSR); - outb(~MSR_RST & r, ioaddr + MSR); - - return 0; -} - -/* - * The inverse routine to smctr_open(). - */ -static int smctr_close(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - struct sk_buff *skb; - int err; - - netif_stop_queue(dev); - - tp->cleanup = 1; - - /* Check to see if adapter is already in a closed state. */ - if(tp->status != OPEN) - return 0; - - smctr_enable_16bit(dev); - smctr_set_page(dev, (__u8 *)tp->ram_access); - - if((err = smctr_issue_remove_cmd(dev))) - { - smctr_disable_16bit(dev); - return err; - } - - for(;;) - { - skb = skb_dequeue(&tp->SendSkbQueue); - if(skb == NULL) - break; - tp->QueueSkb++; - dev_kfree_skb(skb); - } - - - return 0; -} - -static int smctr_decode_firmware(struct net_device *dev, - const struct firmware *fw) -{ - struct net_local *tp = netdev_priv(dev); - short bit = 0x80, shift = 12; - DECODE_TREE_NODE *tree; - short branch, tsize; - __u16 buff = 0; - long weight; - __u8 *ucode; - __u16 *mem; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_decode_firmware\n", dev->name); - - weight = *(long *)(fw->data + WEIGHT_OFFSET); - tsize = *(__u8 *)(fw->data + TREE_SIZE_OFFSET); - tree = (DECODE_TREE_NODE *)(fw->data + TREE_OFFSET); - ucode = (__u8 *)(fw->data + TREE_OFFSET - + (tsize * sizeof(DECODE_TREE_NODE))); - mem = (__u16 *)(tp->ram_access); - - while(weight) - { - branch = ROOT; - while((tree + branch)->tag != LEAF && weight) - { - branch = *ucode & bit ? (tree + branch)->llink - : (tree + branch)->rlink; - - bit >>= 1; - weight--; - - if(bit == 0) - { - bit = 0x80; - ucode++; - } - } - - buff |= (tree + branch)->info << shift; - shift -= 4; - - if(shift < 0) - { - *(mem++) = SWAP_BYTES(buff); - buff = 0; - shift = 12; - } - } - - /* The following assumes the Control Store Memory has - * been initialized to zero. If the last partial word - * is zero, it will not be written. - */ - if(buff) - *(mem++) = SWAP_BYTES(buff); - - return 0; -} - -static int smctr_disable_16bit(struct net_device *dev) -{ - return 0; -} - -/* - * On Exit, Adapter is: - * 1. TRC is in a reset state and un-initialized. - * 2. Adapter memory is enabled. - * 3. Control Store memory is out of context (-WCSS is 1). - */ -static int smctr_disable_adapter_ctrl_store(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - int ioaddr = dev->base_addr; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_disable_adapter_ctrl_store\n", dev->name); - - tp->trc_mask |= CSR_WCSS; - outb(tp->trc_mask, ioaddr + CSR); - - return 0; -} - -static int smctr_disable_bic_int(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - int ioaddr = dev->base_addr; - - tp->trc_mask = CSR_MSK_ALL | CSR_MSKCBUSY - | CSR_MSKTINT | CSR_WCSS; - outb(tp->trc_mask, ioaddr + CSR); - - return 0; -} - -static int smctr_enable_16bit(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - __u8 r; - - if(tp->adapter_bus == BUS_ISA16_TYPE) - { - r = inb(dev->base_addr + LAAR); - outb((r | LAAR_MEM16ENB), dev->base_addr + LAAR); - } - - return 0; -} - -/* - * To enable the adapter control store memory: - * 1. Adapter must be in a RESET state. - * 2. Adapter memory must be enabled. - * 3. Control Store Memory is in context (-WCSS is 0). - */ -static int smctr_enable_adapter_ctrl_store(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - int ioaddr = dev->base_addr; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_enable_adapter_ctrl_store\n", dev->name); - - smctr_set_trc_reset(ioaddr); - smctr_enable_adapter_ram(dev); - - tp->trc_mask &= ~CSR_WCSS; - outb(tp->trc_mask, ioaddr + CSR); - - return 0; -} - -static int smctr_enable_adapter_ram(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - __u8 r; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_enable_adapter_ram\n", dev->name); - - r = inb(ioaddr + MSR); - outb(MSR_MEMB | r, ioaddr + MSR); - - return 0; -} - -static int smctr_enable_bic_int(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - int ioaddr = dev->base_addr; - __u8 r; - - switch(tp->bic_type) - { - case (BIC_584_CHIP): - tp->trc_mask = CSR_MSKCBUSY | CSR_WCSS; - outb(tp->trc_mask, ioaddr + CSR); - r = inb(ioaddr + IRR); - outb(r | IRR_IEN, ioaddr + IRR); - break; - - case (BIC_594_CHIP): - tp->trc_mask = CSR_MSKCBUSY | CSR_WCSS; - outb(tp->trc_mask, ioaddr + CSR); - r = inb(ioaddr + IMCCR); - outb(r | IMCCR_EIL, ioaddr + IMCCR); - break; - } - - return 0; -} - -static int __init smctr_chk_isa(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - int ioaddr = dev->base_addr; - __u8 r1, r2, b, chksum = 0; - __u16 r; - int i; - int err = -ENODEV; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_chk_isa %#4x\n", dev->name, ioaddr); - - if((ioaddr & 0x1F) != 0) - goto out; - - /* Grab the region so that no one else tries to probe our ioports. */ - if (!request_region(ioaddr, SMCTR_IO_EXTENT, smctr_name)) { - err = -EBUSY; - goto out; - } - - /* Checksum SMC node address */ - for(i = 0; i < 8; i++) - { - b = inb(ioaddr + LAR0 + i); - chksum += b; - } - - if (chksum != NODE_ADDR_CKSUM) - goto out2; - - b = inb(ioaddr + BDID); - if(b != BRD_ID_8115T) - { - printk(KERN_ERR "%s: The adapter found is not supported\n", dev->name); - goto out2; - } - - /* Check for 8115T Board ID */ - r2 = 0; - for(r = 0; r < 8; r++) - { - r1 = inb(ioaddr + 0x8 + r); - r2 += r1; - } - - /* value of RegF adds up the sum to 0xFF */ - if((r2 != 0xFF) && (r2 != 0xEE)) - goto out2; - - /* Get adapter ID */ - tp->board_id = smctr_get_boardid(dev, 0); - switch(tp->board_id & 0xffff) - { - case WD8115TA: - smctr_model = "8115T/A"; - break; - - case WD8115T: - if(tp->extra_info & CHIP_REV_MASK) - smctr_model = "8115T rev XE"; - else - smctr_model = "8115T rev XD"; - break; - - default: - smctr_model = "Unknown"; - break; - } - - /* Store BIC type. */ - tp->bic_type = BIC_584_CHIP; - tp->nic_type = NIC_825_CHIP; - - /* Copy Ram Size */ - tp->ram_usable = CNFG_SIZE_16KB; - tp->ram_size = CNFG_SIZE_64KB; - - /* Get 58x Ram Base */ - r1 = inb(ioaddr); - r1 &= 0x3F; - - r2 = inb(ioaddr + CNFG_LAAR_584); - r2 &= CNFG_LAAR_MASK; - r2 <<= 3; - r2 |= ((r1 & 0x38) >> 3); - - tp->ram_base = ((__u32)r2 << 16) + (((__u32)(r1 & 0x7)) << 13); - - /* Get 584 Irq */ - r1 = 0; - r1 = inb(ioaddr + CNFG_ICR_583); - r1 &= CNFG_ICR_IR2_584; - - r2 = inb(ioaddr + CNFG_IRR_583); - r2 &= CNFG_IRR_IRQS; /* 0x60 */ - r2 >>= 5; - - switch(r2) - { - case 0: - if(r1 == 0) - dev->irq = 2; - else - dev->irq = 10; - break; - - case 1: - if(r1 == 0) - dev->irq = 3; - else - dev->irq = 11; - break; - - case 2: - if(r1 == 0) - { - if(tp->extra_info & ALTERNATE_IRQ_BIT) - dev->irq = 5; - else - dev->irq = 4; - } - else - dev->irq = 15; - break; - - case 3: - if(r1 == 0) - dev->irq = 7; - else - dev->irq = 4; - break; - - default: - printk(KERN_ERR "%s: No IRQ found aborting\n", dev->name); - goto out2; - } - - if (request_irq(dev->irq, smctr_interrupt, IRQF_SHARED, smctr_name, dev)) - goto out2; - - /* Get 58x Rom Base */ - r1 = inb(ioaddr + CNFG_BIO_583); - r1 &= 0x3E; - r1 |= 0x40; - - tp->rom_base = (__u32)r1 << 13; - - /* Get 58x Rom Size */ - r1 = inb(ioaddr + CNFG_BIO_583); - r1 &= 0xC0; - if(r1 == 0) - tp->rom_size = ROM_DISABLE; - else - { - r1 >>= 6; - tp->rom_size = (__u16)CNFG_SIZE_8KB << r1; - } - - /* Get 58x Boot Status */ - r1 = inb(ioaddr + CNFG_GP2); - - tp->mode_bits &= (~BOOT_STATUS_MASK); - - if(r1 & CNFG_GP2_BOOT_NIBBLE) - tp->mode_bits |= BOOT_TYPE_1; - - /* Get 58x Zero Wait State */ - tp->mode_bits &= (~ZERO_WAIT_STATE_MASK); - - r1 = inb(ioaddr + CNFG_IRR_583); - - if(r1 & CNFG_IRR_ZWS) - tp->mode_bits |= ZERO_WAIT_STATE_8_BIT; - - if(tp->board_id & BOARD_16BIT) - { - r1 = inb(ioaddr + CNFG_LAAR_584); - - if(r1 & CNFG_LAAR_ZWS) - tp->mode_bits |= ZERO_WAIT_STATE_16_BIT; - } - - /* Get 584 Media Menu */ - tp->media_menu = 14; - r1 = inb(ioaddr + CNFG_IRR_583); - - tp->mode_bits &= 0xf8ff; /* (~CNFG_INTERFACE_TYPE_MASK) */ - if((tp->board_id & TOKEN_MEDIA) == TOKEN_MEDIA) - { - /* Get Advanced Features */ - if(((r1 & 0x6) >> 1) == 0x3) - tp->media_type |= MEDIA_UTP_16; - else - { - if(((r1 & 0x6) >> 1) == 0x2) - tp->media_type |= MEDIA_STP_16; - else - { - if(((r1 & 0x6) >> 1) == 0x1) - tp->media_type |= MEDIA_UTP_4; - - else - tp->media_type |= MEDIA_STP_4; - } - } - - r1 = inb(ioaddr + CNFG_GP2); - if(!(r1 & 0x2) ) /* GP2_ETRD */ - tp->mode_bits |= EARLY_TOKEN_REL; - - /* see if the chip is corrupted - if(smctr_read_584_chksum(ioaddr)) - { - printk(KERN_ERR "%s: EEPROM Checksum Failure\n", dev->name); - free_irq(dev->irq, dev); - goto out2; - } - */ - } - - return 0; - -out2: - release_region(ioaddr, SMCTR_IO_EXTENT); -out: - return err; -} - -static int __init smctr_get_boardid(struct net_device *dev, int mca) -{ - struct net_local *tp = netdev_priv(dev); - int ioaddr = dev->base_addr; - __u8 r, r1, IdByte; - __u16 BoardIdMask; - - tp->board_id = BoardIdMask = 0; - - if(mca) - { - BoardIdMask |= (MICROCHANNEL+INTERFACE_CHIP+TOKEN_MEDIA+PAGED_RAM+BOARD_16BIT); - tp->extra_info |= (INTERFACE_594_CHIP+RAM_SIZE_64K+NIC_825_BIT+ALTERNATE_IRQ_BIT+SLOT_16BIT); - } - else - { - BoardIdMask|=(INTERFACE_CHIP+TOKEN_MEDIA+PAGED_RAM+BOARD_16BIT); - tp->extra_info |= (INTERFACE_584_CHIP + RAM_SIZE_64K - + NIC_825_BIT + ALTERNATE_IRQ_BIT); - } - - if(!mca) - { - r = inb(ioaddr + BID_REG_1); - r &= 0x0c; - outb(r, ioaddr + BID_REG_1); - r = inb(ioaddr + BID_REG_1); - - if(r & BID_SIXTEEN_BIT_BIT) - { - tp->extra_info |= SLOT_16BIT; - tp->adapter_bus = BUS_ISA16_TYPE; - } - else - tp->adapter_bus = BUS_ISA8_TYPE; - } - else - tp->adapter_bus = BUS_MCA_TYPE; - - /* Get Board Id Byte */ - IdByte = inb(ioaddr + BID_BOARD_ID_BYTE); - - /* if Major version > 1.0 then - * return; - */ - if(IdByte & 0xF8) - return -1; - - r1 = inb(ioaddr + BID_REG_1); - r1 &= BID_ICR_MASK; - r1 |= BID_OTHER_BIT; - - outb(r1, ioaddr + BID_REG_1); - r1 = inb(ioaddr + BID_REG_3); - - r1 &= BID_EAR_MASK; - r1 |= BID_ENGR_PAGE; - - outb(r1, ioaddr + BID_REG_3); - r1 = inb(ioaddr + BID_REG_1); - r1 &= BID_ICR_MASK; - r1 |= (BID_RLA | BID_OTHER_BIT); - - outb(r1, ioaddr + BID_REG_1); - - r1 = inb(ioaddr + BID_REG_1); - while(r1 & BID_RECALL_DONE_MASK) - r1 = inb(ioaddr + BID_REG_1); - - r = inb(ioaddr + BID_LAR_0 + BID_REG_6); - - /* clear chip rev bits */ - tp->extra_info &= ~CHIP_REV_MASK; - tp->extra_info |= ((r & BID_EEPROM_CHIP_REV_MASK) << 6); - - r1 = inb(ioaddr + BID_REG_1); - r1 &= BID_ICR_MASK; - r1 |= BID_OTHER_BIT; - - outb(r1, ioaddr + BID_REG_1); - r1 = inb(ioaddr + BID_REG_3); - - r1 &= BID_EAR_MASK; - r1 |= BID_EA6; - - outb(r1, ioaddr + BID_REG_3); - r1 = inb(ioaddr + BID_REG_1); - - r1 &= BID_ICR_MASK; - r1 |= BID_RLA; - - outb(r1, ioaddr + BID_REG_1); - r1 = inb(ioaddr + BID_REG_1); - - while(r1 & BID_RECALL_DONE_MASK) - r1 = inb(ioaddr + BID_REG_1); - - return BoardIdMask; -} - -static int smctr_get_group_address(struct net_device *dev) -{ - smctr_issue_read_word_cmd(dev, RW_INDIVIDUAL_GROUP_ADDR); - - return smctr_wait_cmd(dev); -} - -static int smctr_get_functional_address(struct net_device *dev) -{ - smctr_issue_read_word_cmd(dev, RW_FUNCTIONAL_ADDR); - - return smctr_wait_cmd(dev); -} - -/* Calculate number of Non-MAC receive BDB's and data buffers. - * This function must simulate allocateing shared memory exactly - * as the allocate_shared_memory function above. - */ -static unsigned int smctr_get_num_rx_bdbs(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - unsigned int mem_used = 0; - - /* Allocate System Control Blocks. */ - mem_used += sizeof(SCGBlock); - - mem_used += TO_PARAGRAPH_BOUNDRY(mem_used); - mem_used += sizeof(SCLBlock); - - mem_used += TO_PARAGRAPH_BOUNDRY(mem_used); - mem_used += sizeof(ACBlock) * tp->num_acbs; - - mem_used += TO_PARAGRAPH_BOUNDRY(mem_used); - mem_used += sizeof(ISBlock); - - mem_used += TO_PARAGRAPH_BOUNDRY(mem_used); - mem_used += MISC_DATA_SIZE; - - /* Allocate transmit FCB's. */ - mem_used += TO_PARAGRAPH_BOUNDRY(mem_used); - - mem_used += sizeof(FCBlock) * tp->num_tx_fcbs[MAC_QUEUE]; - mem_used += sizeof(FCBlock) * tp->num_tx_fcbs[NON_MAC_QUEUE]; - mem_used += sizeof(FCBlock) * tp->num_tx_fcbs[BUG_QUEUE]; - - /* Allocate transmit BDBs. */ - mem_used += sizeof(BDBlock) * tp->num_tx_bdbs[MAC_QUEUE]; - mem_used += sizeof(BDBlock) * tp->num_tx_bdbs[NON_MAC_QUEUE]; - mem_used += sizeof(BDBlock) * tp->num_tx_bdbs[BUG_QUEUE]; - - /* Allocate receive FCBs. */ - mem_used += sizeof(FCBlock) * tp->num_rx_fcbs[MAC_QUEUE]; - mem_used += sizeof(FCBlock) * tp->num_rx_fcbs[NON_MAC_QUEUE]; - - /* Allocate receive BDBs. */ - mem_used += sizeof(BDBlock) * tp->num_rx_bdbs[MAC_QUEUE]; - - /* Allocate MAC transmit buffers. - * MAC transmit buffers don't have to be on an ODD Boundary. - */ - mem_used += tp->tx_buff_size[MAC_QUEUE]; - - /* Allocate BUG transmit buffers. */ - mem_used += tp->tx_buff_size[BUG_QUEUE]; - - /* Allocate MAC receive data buffers. - * MAC receive buffers don't have to be on a 256 byte boundary. - */ - mem_used += RX_DATA_BUFFER_SIZE * tp->num_rx_bdbs[MAC_QUEUE]; - - /* Allocate Non-MAC transmit buffers. - * For maximum Netware performance, put Tx Buffers on - * ODD Boundary,and then restore malloc to Even Boundrys. - */ - mem_used += 1L; - mem_used += tp->tx_buff_size[NON_MAC_QUEUE]; - mem_used += 1L; - - /* CALCULATE NUMBER OF NON-MAC RX BDB'S - * AND NON-MAC RX DATA BUFFERS - * - * Make sure the mem_used offset at this point is the - * same as in allocate_shared memory or the following - * boundary adjustment will be incorrect (i.e. not allocating - * the non-mac receive buffers above cannot change the 256 - * byte offset). - * - * Since this cannot be guaranteed, adding the full 256 bytes - * to the amount of shared memory used at this point will guaranteed - * that the rx data buffers do not overflow shared memory. - */ - mem_used += 0x100; - - return (0xffff - mem_used) / (RX_DATA_BUFFER_SIZE + sizeof(BDBlock)); -} - -static int smctr_get_physical_drop_number(struct net_device *dev) -{ - smctr_issue_read_word_cmd(dev, RW_PHYSICAL_DROP_NUMBER); - - return smctr_wait_cmd(dev); -} - -static __u8 * smctr_get_rx_pointer(struct net_device *dev, short queue) -{ - struct net_local *tp = netdev_priv(dev); - BDBlock *bdb; - - bdb = (BDBlock *)((__u32)tp->ram_access - + (__u32)(tp->rx_fcb_curr[queue]->trc_bdb_ptr)); - - tp->rx_fcb_curr[queue]->bdb_ptr = bdb; - - return (__u8 *)bdb->data_block_ptr; -} - -static int smctr_get_station_id(struct net_device *dev) -{ - smctr_issue_read_word_cmd(dev, RW_INDIVIDUAL_MAC_ADDRESS); - - return smctr_wait_cmd(dev); -} - -/* - * Get the current statistics. This may be called with the card open - * or closed. - */ -static struct net_device_stats *smctr_get_stats(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - - return (struct net_device_stats *)&tp->MacStat; -} - -static FCBlock *smctr_get_tx_fcb(struct net_device *dev, __u16 queue, - __u16 bytes_count) -{ - struct net_local *tp = netdev_priv(dev); - FCBlock *pFCB; - BDBlock *pbdb; - unsigned short alloc_size; - unsigned short *temp; - - if(smctr_debug > 20) - printk(KERN_DEBUG "smctr_get_tx_fcb\n"); - - /* check if there is enough FCB blocks */ - if(tp->num_tx_fcbs_used[queue] >= tp->num_tx_fcbs[queue]) - return (FCBlock *)(-1L); - - /* round off the input pkt size to the nearest even number */ - alloc_size = (bytes_count + 1) & 0xfffe; - - /* check if enough mem */ - if((tp->tx_buff_used[queue] + alloc_size) > tp->tx_buff_size[queue]) - return (FCBlock *)(-1L); - - /* check if past the end ; - * if exactly enough mem to end of ring, alloc from front. - * this avoids update of curr when curr = end - */ - if(((unsigned long)(tp->tx_buff_curr[queue]) + alloc_size) - >= (unsigned long)(tp->tx_buff_end[queue])) - { - /* check if enough memory from ring head */ - alloc_size = alloc_size + - (__u16)((__u32)tp->tx_buff_end[queue] - - (__u32)tp->tx_buff_curr[queue]); - - if((tp->tx_buff_used[queue] + alloc_size) - > tp->tx_buff_size[queue]) - { - return (FCBlock *)(-1L); - } - - /* ring wrap */ - tp->tx_buff_curr[queue] = tp->tx_buff_head[queue]; - } - - tp->tx_buff_used[queue] += alloc_size; - tp->num_tx_fcbs_used[queue]++; - tp->tx_fcb_curr[queue]->frame_length = bytes_count; - tp->tx_fcb_curr[queue]->memory_alloc = alloc_size; - temp = tp->tx_buff_curr[queue]; - tp->tx_buff_curr[queue] - = (__u16 *)((__u32)temp + (__u32)((bytes_count + 1) & 0xfffe)); - - pbdb = tp->tx_fcb_curr[queue]->bdb_ptr; - pbdb->buffer_length = bytes_count; - pbdb->data_block_ptr = temp; - pbdb->trc_data_block_ptr = TRC_POINTER(temp); - - pFCB = tp->tx_fcb_curr[queue]; - tp->tx_fcb_curr[queue] = tp->tx_fcb_curr[queue]->next_ptr; - - return pFCB; -} - -static int smctr_get_upstream_neighbor_addr(struct net_device *dev) -{ - smctr_issue_read_word_cmd(dev, RW_UPSTREAM_NEIGHBOR_ADDRESS); - - return smctr_wait_cmd(dev); -} - -static int smctr_hardware_send_packet(struct net_device *dev, - struct net_local *tp) -{ - struct tr_statistics *tstat = &tp->MacStat; - struct sk_buff *skb; - FCBlock *fcb; - - if(smctr_debug > 10) - printk(KERN_DEBUG"%s: smctr_hardware_send_packet\n", dev->name); - - if(tp->status != OPEN) - return -1; - - if(tp->monitor_state_ready != 1) - return -1; - - for(;;) - { - /* Send first buffer from queue */ - skb = skb_dequeue(&tp->SendSkbQueue); - if(skb == NULL) - return -1; - - tp->QueueSkb++; - - if(skb->len < SMC_HEADER_SIZE || skb->len > tp->max_packet_size) - return -1; - - smctr_enable_16bit(dev); - smctr_set_page(dev, (__u8 *)tp->ram_access); - - if((fcb = smctr_get_tx_fcb(dev, NON_MAC_QUEUE, skb->len)) - == (FCBlock *)(-1L)) - { - smctr_disable_16bit(dev); - return -1; - } - - smctr_tx_move_frame(dev, skb, - (__u8 *)fcb->bdb_ptr->data_block_ptr, skb->len); - - smctr_set_page(dev, (__u8 *)fcb); - - smctr_trc_send_packet(dev, fcb, NON_MAC_QUEUE); - dev_kfree_skb(skb); - - tstat->tx_packets++; - - smctr_disable_16bit(dev); - } - - return 0; -} - -static int smctr_init_acbs(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - unsigned int i; - ACBlock *acb; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_init_acbs\n", dev->name); - - acb = tp->acb_head; - acb->cmd_done_status = (ACB_COMMAND_DONE | ACB_COMMAND_SUCCESSFUL); - acb->cmd_info = ACB_CHAIN_END; - acb->cmd = 0; - acb->subcmd = 0; - acb->data_offset_lo = 0; - acb->data_offset_hi = 0; - acb->next_ptr - = (ACBlock *)(((char *)acb) + sizeof(ACBlock)); - acb->trc_next_ptr = TRC_POINTER(acb->next_ptr); - - for(i = 1; i < tp->num_acbs; i++) - { - acb = acb->next_ptr; - acb->cmd_done_status - = (ACB_COMMAND_DONE | ACB_COMMAND_SUCCESSFUL); - acb->cmd_info = ACB_CHAIN_END; - acb->cmd = 0; - acb->subcmd = 0; - acb->data_offset_lo = 0; - acb->data_offset_hi = 0; - acb->next_ptr - = (ACBlock *)(((char *)acb) + sizeof(ACBlock)); - acb->trc_next_ptr = TRC_POINTER(acb->next_ptr); - } - - acb->next_ptr = tp->acb_head; - acb->trc_next_ptr = TRC_POINTER(tp->acb_head); - tp->acb_next = tp->acb_head->next_ptr; - tp->acb_curr = tp->acb_head->next_ptr; - tp->num_acbs_used = 0; - - return 0; -} - -static int smctr_init_adapter(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - int err; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_init_adapter\n", dev->name); - - tp->status = CLOSED; - tp->page_offset_mask = (tp->ram_usable * 1024) - 1; - skb_queue_head_init(&tp->SendSkbQueue); - tp->QueueSkb = MAX_TX_QUEUE; - - if(!(tp->group_address_0 & 0x0080)) - tp->group_address_0 |= 0x00C0; - - if(!(tp->functional_address_0 & 0x00C0)) - tp->functional_address_0 |= 0x00C0; - - tp->functional_address[0] &= 0xFF7F; - - if(tp->authorized_function_classes == 0) - tp->authorized_function_classes = 0x7FFF; - - if(tp->authorized_access_priority == 0) - tp->authorized_access_priority = 0x06; - - smctr_disable_bic_int(dev); - smctr_set_trc_reset(dev->base_addr); - - smctr_enable_16bit(dev); - smctr_set_page(dev, (__u8 *)tp->ram_access); - - if(smctr_checksum_firmware(dev)) - { - printk(KERN_ERR "%s: Previously loaded firmware is missing\n",dev->name); - return -ENOENT; - } - - if((err = smctr_ram_memory_test(dev))) - { - printk(KERN_ERR "%s: RAM memory test failed.\n", dev->name); - return -EIO; - } - - smctr_set_rx_look_ahead(dev); - smctr_load_node_addr(dev); - - /* Initialize adapter for Internal Self Test. */ - smctr_reset_adapter(dev); - if((err = smctr_init_card_real(dev))) - { - printk(KERN_ERR "%s: Initialization of card failed (%d)\n", - dev->name, err); - return -EINVAL; - } - - /* This routine clobbers the TRC's internal registers. */ - if((err = smctr_internal_self_test(dev))) - { - printk(KERN_ERR "%s: Card failed internal self test (%d)\n", - dev->name, err); - return -EINVAL; - } - - /* Re-Initialize adapter's internal registers */ - smctr_reset_adapter(dev); - if((err = smctr_init_card_real(dev))) - { - printk(KERN_ERR "%s: Initialization of card failed (%d)\n", - dev->name, err); - return -EINVAL; - } - - smctr_enable_bic_int(dev); - - if((err = smctr_issue_enable_int_cmd(dev, TRC_INTERRUPT_ENABLE_MASK))) - return err; - - smctr_disable_16bit(dev); - - return 0; -} - -static int smctr_init_card_real(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - int err = 0; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_init_card_real\n", dev->name); - - tp->sh_mem_used = 0; - tp->num_acbs = NUM_OF_ACBS; - - /* Range Check Max Packet Size */ - if(tp->max_packet_size < 256) - tp->max_packet_size = 256; - else - { - if(tp->max_packet_size > NON_MAC_TX_BUFFER_MEMORY) - tp->max_packet_size = NON_MAC_TX_BUFFER_MEMORY; - } - - tp->num_of_tx_buffs = (NON_MAC_TX_BUFFER_MEMORY - / tp->max_packet_size) - 1; - - if(tp->num_of_tx_buffs > NUM_NON_MAC_TX_FCBS) - tp->num_of_tx_buffs = NUM_NON_MAC_TX_FCBS; - else - { - if(tp->num_of_tx_buffs == 0) - tp->num_of_tx_buffs = 1; - } - - /* Tx queue constants */ - tp->num_tx_fcbs [BUG_QUEUE] = NUM_BUG_TX_FCBS; - tp->num_tx_bdbs [BUG_QUEUE] = NUM_BUG_TX_BDBS; - tp->tx_buff_size [BUG_QUEUE] = BUG_TX_BUFFER_MEMORY; - tp->tx_buff_used [BUG_QUEUE] = 0; - tp->tx_queue_status [BUG_QUEUE] = NOT_TRANSMITING; - - tp->num_tx_fcbs [MAC_QUEUE] = NUM_MAC_TX_FCBS; - tp->num_tx_bdbs [MAC_QUEUE] = NUM_MAC_TX_BDBS; - tp->tx_buff_size [MAC_QUEUE] = MAC_TX_BUFFER_MEMORY; - tp->tx_buff_used [MAC_QUEUE] = 0; - tp->tx_queue_status [MAC_QUEUE] = NOT_TRANSMITING; - - tp->num_tx_fcbs [NON_MAC_QUEUE] = NUM_NON_MAC_TX_FCBS; - tp->num_tx_bdbs [NON_MAC_QUEUE] = NUM_NON_MAC_TX_BDBS; - tp->tx_buff_size [NON_MAC_QUEUE] = NON_MAC_TX_BUFFER_MEMORY; - tp->tx_buff_used [NON_MAC_QUEUE] = 0; - tp->tx_queue_status [NON_MAC_QUEUE] = NOT_TRANSMITING; - - /* Receive Queue Constants */ - tp->num_rx_fcbs[MAC_QUEUE] = NUM_MAC_RX_FCBS; - tp->num_rx_bdbs[MAC_QUEUE] = NUM_MAC_RX_BDBS; - - if(tp->extra_info & CHIP_REV_MASK) - tp->num_rx_fcbs[NON_MAC_QUEUE] = 78; /* 825 Rev. XE */ - else - tp->num_rx_fcbs[NON_MAC_QUEUE] = 7; /* 825 Rev. XD */ - - tp->num_rx_bdbs[NON_MAC_QUEUE] = smctr_get_num_rx_bdbs(dev); - - smctr_alloc_shared_memory(dev); - smctr_init_shared_memory(dev); - - if((err = smctr_issue_init_timers_cmd(dev))) - return err; - - if((err = smctr_issue_init_txrx_cmd(dev))) - { - printk(KERN_ERR "%s: Hardware failure\n", dev->name); - return err; - } - - return 0; -} - -static int smctr_init_rx_bdbs(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - unsigned int i, j; - BDBlock *bdb; - __u16 *buf; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_init_rx_bdbs\n", dev->name); - - for(i = 0; i < NUM_RX_QS_USED; i++) - { - bdb = tp->rx_bdb_head[i]; - buf = tp->rx_buff_head[i]; - bdb->info = (BDB_CHAIN_END | BDB_NO_WARNING); - bdb->buffer_length = RX_DATA_BUFFER_SIZE; - bdb->next_ptr = (BDBlock *)(((char *)bdb) + sizeof(BDBlock)); - bdb->data_block_ptr = buf; - bdb->trc_next_ptr = TRC_POINTER(bdb->next_ptr); - - if(i == NON_MAC_QUEUE) - bdb->trc_data_block_ptr = RX_BUFF_TRC_POINTER(buf); - else - bdb->trc_data_block_ptr = TRC_POINTER(buf); - - for(j = 1; j < tp->num_rx_bdbs[i]; j++) - { - bdb->next_ptr->back_ptr = bdb; - bdb = bdb->next_ptr; - buf = (__u16 *)((char *)buf + RX_DATA_BUFFER_SIZE); - bdb->info = (BDB_NOT_CHAIN_END | BDB_NO_WARNING); - bdb->buffer_length = RX_DATA_BUFFER_SIZE; - bdb->next_ptr = (BDBlock *)(((char *)bdb) + sizeof(BDBlock)); - bdb->data_block_ptr = buf; - bdb->trc_next_ptr = TRC_POINTER(bdb->next_ptr); - - if(i == NON_MAC_QUEUE) - bdb->trc_data_block_ptr = RX_BUFF_TRC_POINTER(buf); - else - bdb->trc_data_block_ptr = TRC_POINTER(buf); - } - - bdb->next_ptr = tp->rx_bdb_head[i]; - bdb->trc_next_ptr = TRC_POINTER(tp->rx_bdb_head[i]); - - tp->rx_bdb_head[i]->back_ptr = bdb; - tp->rx_bdb_curr[i] = tp->rx_bdb_head[i]->next_ptr; - } - - return 0; -} - -static int smctr_init_rx_fcbs(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - unsigned int i, j; - FCBlock *fcb; - - for(i = 0; i < NUM_RX_QS_USED; i++) - { - fcb = tp->rx_fcb_head[i]; - fcb->frame_status = 0; - fcb->frame_length = 0; - fcb->info = FCB_CHAIN_END; - fcb->next_ptr = (FCBlock *)(((char*)fcb) + sizeof(FCBlock)); - if(i == NON_MAC_QUEUE) - fcb->trc_next_ptr = RX_FCB_TRC_POINTER(fcb->next_ptr); - else - fcb->trc_next_ptr = TRC_POINTER(fcb->next_ptr); - - for(j = 1; j < tp->num_rx_fcbs[i]; j++) - { - fcb->next_ptr->back_ptr = fcb; - fcb = fcb->next_ptr; - fcb->frame_status = 0; - fcb->frame_length = 0; - fcb->info = FCB_WARNING; - fcb->next_ptr - = (FCBlock *)(((char *)fcb) + sizeof(FCBlock)); - - if(i == NON_MAC_QUEUE) - fcb->trc_next_ptr - = RX_FCB_TRC_POINTER(fcb->next_ptr); - else - fcb->trc_next_ptr - = TRC_POINTER(fcb->next_ptr); - } - - fcb->next_ptr = tp->rx_fcb_head[i]; - - if(i == NON_MAC_QUEUE) - fcb->trc_next_ptr = RX_FCB_TRC_POINTER(fcb->next_ptr); - else - fcb->trc_next_ptr = TRC_POINTER(fcb->next_ptr); - - tp->rx_fcb_head[i]->back_ptr = fcb; - tp->rx_fcb_curr[i] = tp->rx_fcb_head[i]->next_ptr; - } - - return 0; -} - -static int smctr_init_shared_memory(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - unsigned int i; - __u32 *iscpb; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_init_shared_memory\n", dev->name); - - smctr_set_page(dev, (__u8 *)(unsigned int)tp->iscpb_ptr); - - /* Initialize Initial System Configuration Point. (ISCP) */ - iscpb = (__u32 *)PAGE_POINTER(&tp->iscpb_ptr->trc_scgb_ptr); - *iscpb = (__u32)(SWAP_WORDS(TRC_POINTER(tp->scgb_ptr))); - - smctr_set_page(dev, (__u8 *)tp->ram_access); - - /* Initialize System Configuration Pointers. (SCP) */ - tp->scgb_ptr->config = (SCGB_ADDRESS_POINTER_FORMAT - | SCGB_MULTI_WORD_CONTROL | SCGB_DATA_FORMAT - | SCGB_BURST_LENGTH); - - tp->scgb_ptr->trc_sclb_ptr = TRC_POINTER(tp->sclb_ptr); - tp->scgb_ptr->trc_acb_ptr = TRC_POINTER(tp->acb_head); - tp->scgb_ptr->trc_isb_ptr = TRC_POINTER(tp->isb_ptr); - tp->scgb_ptr->isbsiz = (sizeof(ISBlock)) - 2; - - /* Initialize System Control Block. (SCB) */ - tp->sclb_ptr->valid_command = SCLB_VALID | SCLB_CMD_NOP; - tp->sclb_ptr->iack_code = 0; - tp->sclb_ptr->resume_control = 0; - tp->sclb_ptr->int_mask_control = 0; - tp->sclb_ptr->int_mask_state = 0; - - /* Initialize Interrupt Status Block. (ISB) */ - for(i = 0; i < NUM_OF_INTERRUPTS; i++) - { - tp->isb_ptr->IStatus[i].IType = 0xf0; - tp->isb_ptr->IStatus[i].ISubtype = 0; - } - - tp->current_isb_index = 0; - - /* Initialize Action Command Block. (ACB) */ - smctr_init_acbs(dev); - - /* Initialize transmit FCB's and BDB's. */ - smctr_link_tx_fcbs_to_bdbs(dev); - smctr_init_tx_bdbs(dev); - smctr_init_tx_fcbs(dev); - - /* Initialize receive FCB's and BDB's. */ - smctr_init_rx_bdbs(dev); - smctr_init_rx_fcbs(dev); - - return 0; -} - -static int smctr_init_tx_bdbs(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - unsigned int i, j; - BDBlock *bdb; - - for(i = 0; i < NUM_TX_QS_USED; i++) - { - bdb = tp->tx_bdb_head[i]; - bdb->info = (BDB_NOT_CHAIN_END | BDB_NO_WARNING); - bdb->next_ptr = (BDBlock *)(((char *)bdb) + sizeof(BDBlock)); - bdb->trc_next_ptr = TRC_POINTER(bdb->next_ptr); - - for(j = 1; j < tp->num_tx_bdbs[i]; j++) - { - bdb->next_ptr->back_ptr = bdb; - bdb = bdb->next_ptr; - bdb->info = (BDB_NOT_CHAIN_END | BDB_NO_WARNING); - bdb->next_ptr - = (BDBlock *)(((char *)bdb) + sizeof( BDBlock)); bdb->trc_next_ptr = TRC_POINTER(bdb->next_ptr); - } - - bdb->next_ptr = tp->tx_bdb_head[i]; - bdb->trc_next_ptr = TRC_POINTER(tp->tx_bdb_head[i]); - tp->tx_bdb_head[i]->back_ptr = bdb; - } - - return 0; -} - -static int smctr_init_tx_fcbs(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - unsigned int i, j; - FCBlock *fcb; - - for(i = 0; i < NUM_TX_QS_USED; i++) - { - fcb = tp->tx_fcb_head[i]; - fcb->frame_status = 0; - fcb->frame_length = 0; - fcb->info = FCB_CHAIN_END; - fcb->next_ptr = (FCBlock *)(((char *)fcb) + sizeof(FCBlock)); - fcb->trc_next_ptr = TRC_POINTER(fcb->next_ptr); - - for(j = 1; j < tp->num_tx_fcbs[i]; j++) - { - fcb->next_ptr->back_ptr = fcb; - fcb = fcb->next_ptr; - fcb->frame_status = 0; - fcb->frame_length = 0; - fcb->info = FCB_CHAIN_END; - fcb->next_ptr - = (FCBlock *)(((char *)fcb) + sizeof(FCBlock)); - fcb->trc_next_ptr = TRC_POINTER(fcb->next_ptr); - } - - fcb->next_ptr = tp->tx_fcb_head[i]; - fcb->trc_next_ptr = TRC_POINTER(tp->tx_fcb_head[i]); - - tp->tx_fcb_head[i]->back_ptr = fcb; - tp->tx_fcb_end[i] = tp->tx_fcb_head[i]->next_ptr; - tp->tx_fcb_curr[i] = tp->tx_fcb_head[i]->next_ptr; - tp->num_tx_fcbs_used[i] = 0; - } - - return 0; -} - -static int smctr_internal_self_test(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - int err; - - if((err = smctr_issue_test_internal_rom_cmd(dev))) - return err; - - if((err = smctr_wait_cmd(dev))) - return err; - - if(tp->acb_head->cmd_done_status & 0xff) - return -1; - - if((err = smctr_issue_test_hic_cmd(dev))) - return err; - - if((err = smctr_wait_cmd(dev))) - return err; - - if(tp->acb_head->cmd_done_status & 0xff) - return -1; - - if((err = smctr_issue_test_mac_reg_cmd(dev))) - return err; - - if((err = smctr_wait_cmd(dev))) - return err; - - if(tp->acb_head->cmd_done_status & 0xff) - return -1; - - return 0; -} - -/* - * The typical workload of the driver: Handle the network interface interrupts. - */ -static irqreturn_t smctr_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct net_local *tp; - int ioaddr; - __u16 interrupt_unmask_bits = 0, interrupt_ack_code = 0xff00; - __u16 err1, err = NOT_MY_INTERRUPT; - __u8 isb_type, isb_subtype; - __u16 isb_index; - - ioaddr = dev->base_addr; - tp = netdev_priv(dev); - - if(tp->status == NOT_INITIALIZED) - return IRQ_NONE; - - spin_lock(&tp->lock); - - smctr_disable_bic_int(dev); - smctr_enable_16bit(dev); - - smctr_clear_int(dev); - - /* First read the LSB */ - while((tp->isb_ptr->IStatus[tp->current_isb_index].IType & 0xf0) == 0) - { - isb_index = tp->current_isb_index; - isb_type = tp->isb_ptr->IStatus[isb_index].IType; - isb_subtype = tp->isb_ptr->IStatus[isb_index].ISubtype; - - (tp->current_isb_index)++; - if(tp->current_isb_index == NUM_OF_INTERRUPTS) - tp->current_isb_index = 0; - - if(isb_type >= 0x10) - { - smctr_disable_16bit(dev); - spin_unlock(&tp->lock); - return IRQ_HANDLED; - } - - err = HARDWARE_FAILED; - interrupt_ack_code = isb_index; - tp->isb_ptr->IStatus[isb_index].IType |= 0xf0; - - interrupt_unmask_bits |= (1 << (__u16)isb_type); - - switch(isb_type) - { - case ISB_IMC_MAC_TYPE_3: - smctr_disable_16bit(dev); - - switch(isb_subtype) - { - case 0: - tp->monitor_state = MS_MONITOR_FSM_INACTIVE; - break; - - case 1: - tp->monitor_state = MS_REPEAT_BEACON_STATE; - break; - - case 2: - tp->monitor_state = MS_REPEAT_CLAIM_TOKEN_STATE; - break; - - case 3: - tp->monitor_state = MS_TRANSMIT_CLAIM_TOKEN_STATE; break; - - case 4: - tp->monitor_state = MS_STANDBY_MONITOR_STATE; - break; - - case 5: - tp->monitor_state = MS_TRANSMIT_BEACON_STATE; - break; - - case 6: - tp->monitor_state = MS_ACTIVE_MONITOR_STATE; - break; - - case 7: - tp->monitor_state = MS_TRANSMIT_RING_PURGE_STATE; - break; - - case 8: /* diagnostic state */ - break; - - case 9: - tp->monitor_state = MS_BEACON_TEST_STATE; - if(smctr_lobe_media_test(dev)) - { - tp->ring_status_flags = RING_STATUS_CHANGED; - tp->ring_status = AUTO_REMOVAL_ERROR; - smctr_ring_status_chg(dev); - smctr_bypass_state(dev); - } - else - smctr_issue_insert_cmd(dev); - break; - - /* case 0x0a-0xff, illegal states */ - default: - break; - } - - tp->ring_status_flags = MONITOR_STATE_CHANGED; - err = smctr_ring_status_chg(dev); - - smctr_enable_16bit(dev); - break; - - /* Type 0x02 - MAC Error Counters Interrupt - * One or more MAC Error Counter is half full - * MAC Error Counters - * Lost_FR_Error_Counter - * RCV_Congestion_Counter - * FR_copied_Error_Counter - * FREQ_Error_Counter - * Token_Error_Counter - * Line_Error_Counter - * Internal_Error_Count - */ - case ISB_IMC_MAC_ERROR_COUNTERS: - /* Read 802.5 Error Counters */ - err = smctr_issue_read_ring_status_cmd(dev); - break; - - /* Type 0x04 - MAC Type 2 Interrupt - * HOST needs to enqueue MAC Frame for transmission - * SubType Bit 15 - RQ_INIT_PDU( Request Initialization) * Changed from RQ_INIT_PDU to - * TRC_Status_Changed_Indicate - */ - case ISB_IMC_MAC_TYPE_2: - err = smctr_issue_read_ring_status_cmd(dev); - break; - - - /* Type 0x05 - TX Frame Interrupt (FI). */ - case ISB_IMC_TX_FRAME: - /* BUG QUEUE for TRC stuck receive BUG */ - if(isb_subtype & TX_PENDING_PRIORITY_2) - { - if((err = smctr_tx_complete(dev, BUG_QUEUE)) != SUCCESS) - break; - } - - /* NON-MAC frames only */ - if(isb_subtype & TX_PENDING_PRIORITY_1) - { - if((err = smctr_tx_complete(dev, NON_MAC_QUEUE)) != SUCCESS) - break; - } - - /* MAC frames only */ - if(isb_subtype & TX_PENDING_PRIORITY_0) - err = smctr_tx_complete(dev, MAC_QUEUE); break; - - /* Type 0x06 - TX END OF QUEUE (FE) */ - case ISB_IMC_END_OF_TX_QUEUE: - /* BUG queue */ - if(isb_subtype & TX_PENDING_PRIORITY_2) - { - /* ok to clear Receive FIFO overrun - * imask send_BUG now completes. - */ - interrupt_unmask_bits |= 0x800; - - tp->tx_queue_status[BUG_QUEUE] = NOT_TRANSMITING; - if((err = smctr_tx_complete(dev, BUG_QUEUE)) != SUCCESS) - break; - if((err = smctr_restart_tx_chain(dev, BUG_QUEUE)) != SUCCESS) - break; - } - - /* NON-MAC queue only */ - if(isb_subtype & TX_PENDING_PRIORITY_1) - { - tp->tx_queue_status[NON_MAC_QUEUE] = NOT_TRANSMITING; - if((err = smctr_tx_complete(dev, NON_MAC_QUEUE)) != SUCCESS) - break; - if((err = smctr_restart_tx_chain(dev, NON_MAC_QUEUE)) != SUCCESS) - break; - } - - /* MAC queue only */ - if(isb_subtype & TX_PENDING_PRIORITY_0) - { - tp->tx_queue_status[MAC_QUEUE] = NOT_TRANSMITING; - if((err = smctr_tx_complete(dev, MAC_QUEUE)) != SUCCESS) - break; - - err = smctr_restart_tx_chain(dev, MAC_QUEUE); - } - break; - - /* Type 0x07 - NON-MAC RX Resource Interrupt - * Subtype bit 12 - (BW) BDB warning - * Subtype bit 13 - (FW) FCB warning - * Subtype bit 14 - (BE) BDB End of chain - * Subtype bit 15 - (FE) FCB End of chain - */ - case ISB_IMC_NON_MAC_RX_RESOURCE: - tp->rx_fifo_overrun_count = 0; - tp->receive_queue_number = NON_MAC_QUEUE; - err1 = smctr_rx_frame(dev); - - if(isb_subtype & NON_MAC_RX_RESOURCE_FE) - { - if((err = smctr_issue_resume_rx_fcb_cmd( dev, NON_MAC_QUEUE)) != SUCCESS) break; - - if(tp->ptr_rx_fcb_overruns) - (*tp->ptr_rx_fcb_overruns)++; - } - - if(isb_subtype & NON_MAC_RX_RESOURCE_BE) - { - if((err = smctr_issue_resume_rx_bdb_cmd( dev, NON_MAC_QUEUE)) != SUCCESS) break; - - if(tp->ptr_rx_bdb_overruns) - (*tp->ptr_rx_bdb_overruns)++; - } - err = err1; - break; - - /* Type 0x08 - MAC RX Resource Interrupt - * Subtype bit 12 - (BW) BDB warning - * Subtype bit 13 - (FW) FCB warning - * Subtype bit 14 - (BE) BDB End of chain - * Subtype bit 15 - (FE) FCB End of chain - */ - case ISB_IMC_MAC_RX_RESOURCE: - tp->receive_queue_number = MAC_QUEUE; - err1 = smctr_rx_frame(dev); - - if(isb_subtype & MAC_RX_RESOURCE_FE) - { - if((err = smctr_issue_resume_rx_fcb_cmd( dev, MAC_QUEUE)) != SUCCESS) - break; - - if(tp->ptr_rx_fcb_overruns) - (*tp->ptr_rx_fcb_overruns)++; - } - - if(isb_subtype & MAC_RX_RESOURCE_BE) - { - if((err = smctr_issue_resume_rx_bdb_cmd( dev, MAC_QUEUE)) != SUCCESS) - break; - - if(tp->ptr_rx_bdb_overruns) - (*tp->ptr_rx_bdb_overruns)++; - } - err = err1; - break; - - /* Type 0x09 - NON_MAC RX Frame Interrupt */ - case ISB_IMC_NON_MAC_RX_FRAME: - tp->rx_fifo_overrun_count = 0; - tp->receive_queue_number = NON_MAC_QUEUE; - err = smctr_rx_frame(dev); - break; - - /* Type 0x0A - MAC RX Frame Interrupt */ - case ISB_IMC_MAC_RX_FRAME: - tp->receive_queue_number = MAC_QUEUE; - err = smctr_rx_frame(dev); - break; - - /* Type 0x0B - TRC status - * TRC has encountered an error condition - * subtype bit 14 - transmit FIFO underrun - * subtype bit 15 - receive FIFO overrun - */ - case ISB_IMC_TRC_FIFO_STATUS: - if(isb_subtype & TRC_FIFO_STATUS_TX_UNDERRUN) - { - if(tp->ptr_tx_fifo_underruns) - (*tp->ptr_tx_fifo_underruns)++; - } - - if(isb_subtype & TRC_FIFO_STATUS_RX_OVERRUN) - { - /* update overrun stuck receive counter - * if >= 3, has to clear it by sending - * back to back frames. We pick - * DAT(duplicate address MAC frame) - */ - tp->rx_fifo_overrun_count++; - - if(tp->rx_fifo_overrun_count >= 3) - { - tp->rx_fifo_overrun_count = 0; - - /* delay clearing fifo overrun - * imask till send_BUG tx - * complete posted - */ - interrupt_unmask_bits &= (~0x800); - printk(KERN_CRIT "Jay please send bug\n");// smctr_send_bug(dev); - } - - if(tp->ptr_rx_fifo_overruns) - (*tp->ptr_rx_fifo_overruns)++; - } - - err = SUCCESS; - break; - - /* Type 0x0C - Action Command Status Interrupt - * Subtype bit 14 - CB end of command chain (CE) - * Subtype bit 15 - CB command interrupt (CI) - */ - case ISB_IMC_COMMAND_STATUS: - err = SUCCESS; - if(tp->acb_head->cmd == ACB_CMD_HIC_NOP) - { - printk(KERN_ERR "i1\n"); - smctr_disable_16bit(dev); - - /* XXXXXXXXXXXXXXXXX */ - /* err = UM_Interrupt(dev); */ - - smctr_enable_16bit(dev); - } - else - { - if((tp->acb_head->cmd - == ACB_CMD_READ_TRC_STATUS) && - (tp->acb_head->subcmd - == RW_TRC_STATUS_BLOCK)) - { - if(tp->ptr_bcn_type) - { - *(tp->ptr_bcn_type) - = (__u32)((SBlock *)tp->misc_command_data)->BCN_Type; - } - - if(((SBlock *)tp->misc_command_data)->Status_CHG_Indicate & ERROR_COUNTERS_CHANGED) - { - smctr_update_err_stats(dev); - } - - if(((SBlock *)tp->misc_command_data)->Status_CHG_Indicate & TI_NDIS_RING_STATUS_CHANGED) - { - tp->ring_status - = ((SBlock*)tp->misc_command_data)->TI_NDIS_Ring_Status; - smctr_disable_16bit(dev); - err = smctr_ring_status_chg(dev); - smctr_enable_16bit(dev); - if((tp->ring_status & REMOVE_RECEIVED) && - (tp->config_word0 & NO_AUTOREMOVE)) - { - smctr_issue_remove_cmd(dev); - } - - if(err != SUCCESS) - { - tp->acb_pending = 0; - break; - } - } - - if(((SBlock *)tp->misc_command_data)->Status_CHG_Indicate & UNA_CHANGED) - { - if(tp->ptr_una) - { - tp->ptr_una[0] = SWAP_BYTES(((SBlock *)tp->misc_command_data)->UNA[0]); - tp->ptr_una[1] = SWAP_BYTES(((SBlock *)tp->misc_command_data)->UNA[1]); - tp->ptr_una[2] = SWAP_BYTES(((SBlock *)tp->misc_command_data)->UNA[2]); - } - - } - - if(((SBlock *)tp->misc_command_data)->Status_CHG_Indicate & READY_TO_SEND_RQ_INIT) { - err = smctr_send_rq_init(dev); - } - } - } - - tp->acb_pending = 0; - break; - - /* Type 0x0D - MAC Type 1 interrupt - * Subtype -- 00 FR_BCN received at S12 - * 01 FR_BCN received at S21 - * 02 FR_DAT(DA=MA, A<>0) received at S21 - * 03 TSM_EXP at S21 - * 04 FR_REMOVE received at S42 - * 05 TBR_EXP, BR_FLAG_SET at S42 - * 06 TBT_EXP at S53 - */ - case ISB_IMC_MAC_TYPE_1: - if(isb_subtype > 8) - { - err = HARDWARE_FAILED; - break; - } - - err = SUCCESS; - switch(isb_subtype) - { - case 0: - tp->join_state = JS_BYPASS_STATE; - if(tp->status != CLOSED) - { - tp->status = CLOSED; - err = smctr_status_chg(dev); - } - break; - - case 1: - tp->join_state = JS_LOBE_TEST_STATE; - break; - - case 2: - tp->join_state = JS_DETECT_MONITOR_PRESENT_STATE; - break; - - case 3: - tp->join_state = JS_AWAIT_NEW_MONITOR_STATE; - break; - - case 4: - tp->join_state = JS_DUPLICATE_ADDRESS_TEST_STATE; - break; - - case 5: - tp->join_state = JS_NEIGHBOR_NOTIFICATION_STATE; - break; - - case 6: - tp->join_state = JS_REQUEST_INITIALIZATION_STATE; - break; - - case 7: - tp->join_state = JS_JOIN_COMPLETE_STATE; - tp->status = OPEN; - err = smctr_status_chg(dev); - break; - - case 8: - tp->join_state = JS_BYPASS_WAIT_STATE; - break; - } - break ; - - /* Type 0x0E - TRC Initialization Sequence Interrupt - * Subtype -- 00-FF Initializatin sequence complete - */ - case ISB_IMC_TRC_INTRNL_TST_STATUS: - tp->status = INITIALIZED; - smctr_disable_16bit(dev); - err = smctr_status_chg(dev); - smctr_enable_16bit(dev); - break; - - /* other interrupt types, illegal */ - default: - break; - } - - if(err != SUCCESS) - break; - } - - /* Checking the ack code instead of the unmask bits here is because : - * while fixing the stuck receive, DAT frame are sent and mask off - * FIFO overrun interrupt temporarily (interrupt_unmask_bits = 0) - * but we still want to issue ack to ISB - */ - if(!(interrupt_ack_code & 0xff00)) - smctr_issue_int_ack(dev, interrupt_ack_code, interrupt_unmask_bits); - - smctr_disable_16bit(dev); - smctr_enable_bic_int(dev); - spin_unlock(&tp->lock); - - return IRQ_HANDLED; -} - -static int smctr_issue_enable_int_cmd(struct net_device *dev, - __u16 interrupt_enable_mask) -{ - struct net_local *tp = netdev_priv(dev); - int err; - - if((err = smctr_wait_while_cbusy(dev))) - return err; - - tp->sclb_ptr->int_mask_control = interrupt_enable_mask; - tp->sclb_ptr->valid_command = SCLB_VALID | SCLB_CMD_CLEAR_INTERRUPT_MASK; - - smctr_set_ctrl_attention(dev); - - return 0; -} - -static int smctr_issue_int_ack(struct net_device *dev, __u16 iack_code, __u16 ibits) -{ - struct net_local *tp = netdev_priv(dev); - - if(smctr_wait_while_cbusy(dev)) - return -1; - - tp->sclb_ptr->int_mask_control = ibits; - tp->sclb_ptr->iack_code = iack_code << 1; /* use the offset from base */ tp->sclb_ptr->resume_control = 0; - tp->sclb_ptr->valid_command = SCLB_VALID | SCLB_IACK_CODE_VALID | SCLB_CMD_CLEAR_INTERRUPT_MASK; - - smctr_set_ctrl_attention(dev); - - return 0; -} - -static int smctr_issue_init_timers_cmd(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - unsigned int i; - int err; - __u16 *pTimer_Struc = (__u16 *)tp->misc_command_data; - - if((err = smctr_wait_while_cbusy(dev))) - return err; - - if((err = smctr_wait_cmd(dev))) - return err; - - tp->config_word0 = THDREN | DMA_TRIGGER | USETPT | NO_AUTOREMOVE; - tp->config_word1 = 0; - - if((tp->media_type == MEDIA_STP_16) || - (tp->media_type == MEDIA_UTP_16) || - (tp->media_type == MEDIA_STP_16_UTP_16)) - { - tp->config_word0 |= FREQ_16MB_BIT; - } - - if(tp->mode_bits & EARLY_TOKEN_REL) - tp->config_word0 |= ETREN; - - if(tp->mode_bits & LOOPING_MODE_MASK) - tp->config_word0 |= RX_OWN_BIT; - else - tp->config_word0 &= ~RX_OWN_BIT; - - if(tp->receive_mask & PROMISCUOUS_MODE) - tp->config_word0 |= PROMISCUOUS_BIT; - else - tp->config_word0 &= ~PROMISCUOUS_BIT; - - if(tp->receive_mask & ACCEPT_ERR_PACKETS) - tp->config_word0 |= SAVBAD_BIT; - else - tp->config_word0 &= ~SAVBAD_BIT; - - if(tp->receive_mask & ACCEPT_ATT_MAC_FRAMES) - tp->config_word0 |= RXATMAC; - else - tp->config_word0 &= ~RXATMAC; - - if(tp->receive_mask & ACCEPT_MULTI_PROM) - tp->config_word1 |= MULTICAST_ADDRESS_BIT; - else - tp->config_word1 &= ~MULTICAST_ADDRESS_BIT; - - if(tp->receive_mask & ACCEPT_SOURCE_ROUTING_SPANNING) - tp->config_word1 |= SOURCE_ROUTING_SPANNING_BITS; - else - { - if(tp->receive_mask & ACCEPT_SOURCE_ROUTING) - tp->config_word1 |= SOURCE_ROUTING_EXPLORER_BIT; - else - tp->config_word1 &= ~SOURCE_ROUTING_SPANNING_BITS; - } - - if((tp->media_type == MEDIA_STP_16) || - (tp->media_type == MEDIA_UTP_16) || - (tp->media_type == MEDIA_STP_16_UTP_16)) - { - tp->config_word1 |= INTERFRAME_SPACING_16; - } - else - tp->config_word1 |= INTERFRAME_SPACING_4; - - *pTimer_Struc++ = tp->config_word0; - *pTimer_Struc++ = tp->config_word1; - - if((tp->media_type == MEDIA_STP_4) || - (tp->media_type == MEDIA_UTP_4) || - (tp->media_type == MEDIA_STP_4_UTP_4)) - { - *pTimer_Struc++ = 0x00FA; /* prescale */ - *pTimer_Struc++ = 0x2710; /* TPT_limit */ - *pTimer_Struc++ = 0x2710; /* TQP_limit */ - *pTimer_Struc++ = 0x0A28; /* TNT_limit */ - *pTimer_Struc++ = 0x3E80; /* TBT_limit */ - *pTimer_Struc++ = 0x3A98; /* TSM_limit */ - *pTimer_Struc++ = 0x1B58; /* TAM_limit */ - *pTimer_Struc++ = 0x00C8; /* TBR_limit */ - *pTimer_Struc++ = 0x07D0; /* TER_limit */ - *pTimer_Struc++ = 0x000A; /* TGT_limit */ - *pTimer_Struc++ = 0x1162; /* THT_limit */ - *pTimer_Struc++ = 0x07D0; /* TRR_limit */ - *pTimer_Struc++ = 0x1388; /* TVX_limit */ - *pTimer_Struc++ = 0x0000; /* reserved */ - } - else - { - *pTimer_Struc++ = 0x03E8; /* prescale */ - *pTimer_Struc++ = 0x9C40; /* TPT_limit */ - *pTimer_Struc++ = 0x9C40; /* TQP_limit */ - *pTimer_Struc++ = 0x0A28; /* TNT_limit */ - *pTimer_Struc++ = 0x3E80; /* TBT_limit */ - *pTimer_Struc++ = 0x3A98; /* TSM_limit */ - *pTimer_Struc++ = 0x1B58; /* TAM_limit */ - *pTimer_Struc++ = 0x00C8; /* TBR_limit */ - *pTimer_Struc++ = 0x07D0; /* TER_limit */ - *pTimer_Struc++ = 0x000A; /* TGT_limit */ - *pTimer_Struc++ = 0x4588; /* THT_limit */ - *pTimer_Struc++ = 0x1F40; /* TRR_limit */ - *pTimer_Struc++ = 0x4E20; /* TVX_limit */ - *pTimer_Struc++ = 0x0000; /* reserved */ - } - - /* Set node address. */ - *pTimer_Struc++ = dev->dev_addr[0] << 8 - | (dev->dev_addr[1] & 0xFF); - *pTimer_Struc++ = dev->dev_addr[2] << 8 - | (dev->dev_addr[3] & 0xFF); - *pTimer_Struc++ = dev->dev_addr[4] << 8 - | (dev->dev_addr[5] & 0xFF); - - /* Set group address. */ - *pTimer_Struc++ = tp->group_address_0 << 8 - | tp->group_address_0 >> 8; - *pTimer_Struc++ = tp->group_address[0] << 8 - | tp->group_address[0] >> 8; - *pTimer_Struc++ = tp->group_address[1] << 8 - | tp->group_address[1] >> 8; - - /* Set functional address. */ - *pTimer_Struc++ = tp->functional_address_0 << 8 - | tp->functional_address_0 >> 8; - *pTimer_Struc++ = tp->functional_address[0] << 8 - | tp->functional_address[0] >> 8; - *pTimer_Struc++ = tp->functional_address[1] << 8 - | tp->functional_address[1] >> 8; - - /* Set Bit-Wise group address. */ - *pTimer_Struc++ = tp->bitwise_group_address[0] << 8 - | tp->bitwise_group_address[0] >> 8; - *pTimer_Struc++ = tp->bitwise_group_address[1] << 8 - | tp->bitwise_group_address[1] >> 8; - - /* Set ring number address. */ - *pTimer_Struc++ = tp->source_ring_number; - *pTimer_Struc++ = tp->target_ring_number; - - /* Physical drop number. */ - *pTimer_Struc++ = (unsigned short)0; - *pTimer_Struc++ = (unsigned short)0; - - /* Product instance ID. */ - for(i = 0; i < 9; i++) - *pTimer_Struc++ = (unsigned short)0; - - err = smctr_setup_single_cmd_w_data(dev, ACB_CMD_INIT_TRC_TIMERS, 0); - - return err; -} - -static int smctr_issue_init_txrx_cmd(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - unsigned int i; - int err; - void **txrx_ptrs = (void *)tp->misc_command_data; - - if((err = smctr_wait_while_cbusy(dev))) - return err; - - if((err = smctr_wait_cmd(dev))) - { - printk(KERN_ERR "%s: Hardware failure\n", dev->name); - return err; - } - - /* Initialize Transmit Queue Pointers that are used, to point to - * a single FCB. - */ - for(i = 0; i < NUM_TX_QS_USED; i++) - *txrx_ptrs++ = (void *)TRC_POINTER(tp->tx_fcb_head[i]); - - /* Initialize Transmit Queue Pointers that are NOT used to ZERO. */ - for(; i < MAX_TX_QS; i++) - *txrx_ptrs++ = (void *)0; - - /* Initialize Receive Queue Pointers (MAC and Non-MAC) that are - * used, to point to a single FCB and a BDB chain of buffers. - */ - for(i = 0; i < NUM_RX_QS_USED; i++) - { - *txrx_ptrs++ = (void *)TRC_POINTER(tp->rx_fcb_head[i]); - *txrx_ptrs++ = (void *)TRC_POINTER(tp->rx_bdb_head[i]); - } - - /* Initialize Receive Queue Pointers that are NOT used to ZERO. */ - for(; i < MAX_RX_QS; i++) - { - *txrx_ptrs++ = (void *)0; - *txrx_ptrs++ = (void *)0; - } - - err = smctr_setup_single_cmd_w_data(dev, ACB_CMD_INIT_TX_RX, 0); - - return err; -} - -static int smctr_issue_insert_cmd(struct net_device *dev) -{ - int err; - - err = smctr_setup_single_cmd(dev, ACB_CMD_INSERT, ACB_SUB_CMD_NOP); - - return err; -} - -static int smctr_issue_read_ring_status_cmd(struct net_device *dev) -{ - int err; - - if((err = smctr_wait_while_cbusy(dev))) - return err; - - if((err = smctr_wait_cmd(dev))) - return err; - - err = smctr_setup_single_cmd_w_data(dev, ACB_CMD_READ_TRC_STATUS, - RW_TRC_STATUS_BLOCK); - - return err; -} - -static int smctr_issue_read_word_cmd(struct net_device *dev, __u16 aword_cnt) -{ - int err; - - if((err = smctr_wait_while_cbusy(dev))) - return err; - - if((err = smctr_wait_cmd(dev))) - return err; - - err = smctr_setup_single_cmd_w_data(dev, ACB_CMD_MCT_READ_VALUE, - aword_cnt); - - return err; -} - -static int smctr_issue_remove_cmd(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - int err; - - if((err = smctr_wait_while_cbusy(dev))) - return err; - - tp->sclb_ptr->resume_control = 0; - tp->sclb_ptr->valid_command = SCLB_VALID | SCLB_CMD_REMOVE; - - smctr_set_ctrl_attention(dev); - - return 0; -} - -static int smctr_issue_resume_acb_cmd(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - int err; - - if((err = smctr_wait_while_cbusy(dev))) - return err; - - tp->sclb_ptr->resume_control = SCLB_RC_ACB; - tp->sclb_ptr->valid_command = SCLB_VALID | SCLB_RESUME_CONTROL_VALID; - - tp->acb_pending = 1; - - smctr_set_ctrl_attention(dev); - - return 0; -} - -static int smctr_issue_resume_rx_bdb_cmd(struct net_device *dev, __u16 queue) -{ - struct net_local *tp = netdev_priv(dev); - int err; - - if((err = smctr_wait_while_cbusy(dev))) - return err; - - if(queue == MAC_QUEUE) - tp->sclb_ptr->resume_control = SCLB_RC_RX_MAC_BDB; - else - tp->sclb_ptr->resume_control = SCLB_RC_RX_NON_MAC_BDB; - - tp->sclb_ptr->valid_command = SCLB_VALID | SCLB_RESUME_CONTROL_VALID; - - smctr_set_ctrl_attention(dev); - - return 0; -} - -static int smctr_issue_resume_rx_fcb_cmd(struct net_device *dev, __u16 queue) -{ - struct net_local *tp = netdev_priv(dev); - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_issue_resume_rx_fcb_cmd\n", dev->name); - - if(smctr_wait_while_cbusy(dev)) - return -1; - - if(queue == MAC_QUEUE) - tp->sclb_ptr->resume_control = SCLB_RC_RX_MAC_FCB; - else - tp->sclb_ptr->resume_control = SCLB_RC_RX_NON_MAC_FCB; - - tp->sclb_ptr->valid_command = SCLB_VALID | SCLB_RESUME_CONTROL_VALID; - - smctr_set_ctrl_attention(dev); - - return 0; -} - -static int smctr_issue_resume_tx_fcb_cmd(struct net_device *dev, __u16 queue) -{ - struct net_local *tp = netdev_priv(dev); - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_issue_resume_tx_fcb_cmd\n", dev->name); - - if(smctr_wait_while_cbusy(dev)) - return -1; - - tp->sclb_ptr->resume_control = (SCLB_RC_TFCB0 << queue); - tp->sclb_ptr->valid_command = SCLB_RESUME_CONTROL_VALID | SCLB_VALID; - - smctr_set_ctrl_attention(dev); - - return 0; -} - -static int smctr_issue_test_internal_rom_cmd(struct net_device *dev) -{ - int err; - - err = smctr_setup_single_cmd(dev, ACB_CMD_MCT_TEST, - TRC_INTERNAL_ROM_TEST); - - return err; -} - -static int smctr_issue_test_hic_cmd(struct net_device *dev) -{ - int err; - - err = smctr_setup_single_cmd(dev, ACB_CMD_HIC_TEST, - TRC_HOST_INTERFACE_REG_TEST); - - return err; -} - -static int smctr_issue_test_mac_reg_cmd(struct net_device *dev) -{ - int err; - - err = smctr_setup_single_cmd(dev, ACB_CMD_MCT_TEST, - TRC_MAC_REGISTERS_TEST); - - return err; -} - -static int smctr_issue_trc_loopback_cmd(struct net_device *dev) -{ - int err; - - err = smctr_setup_single_cmd(dev, ACB_CMD_MCT_TEST, - TRC_INTERNAL_LOOPBACK); - - return err; -} - -static int smctr_issue_tri_loopback_cmd(struct net_device *dev) -{ - int err; - - err = smctr_setup_single_cmd(dev, ACB_CMD_MCT_TEST, - TRC_TRI_LOOPBACK); - - return err; -} - -static int smctr_issue_write_byte_cmd(struct net_device *dev, - short aword_cnt, void *byte) -{ - struct net_local *tp = netdev_priv(dev); - unsigned int iword, ibyte; - int err; - - if((err = smctr_wait_while_cbusy(dev))) - return err; - - if((err = smctr_wait_cmd(dev))) - return err; - - for(iword = 0, ibyte = 0; iword < (unsigned int)(aword_cnt & 0xff); - iword++, ibyte += 2) - { - tp->misc_command_data[iword] = (*((__u8 *)byte + ibyte) << 8) - | (*((__u8 *)byte + ibyte + 1)); - } - - return smctr_setup_single_cmd_w_data(dev, ACB_CMD_MCT_WRITE_VALUE, - aword_cnt); -} - -static int smctr_issue_write_word_cmd(struct net_device *dev, - short aword_cnt, void *word) -{ - struct net_local *tp = netdev_priv(dev); - unsigned int i, err; - - if((err = smctr_wait_while_cbusy(dev))) - return err; - - if((err = smctr_wait_cmd(dev))) - return err; - - for(i = 0; i < (unsigned int)(aword_cnt & 0xff); i++) - tp->misc_command_data[i] = *((__u16 *)word + i); - - err = smctr_setup_single_cmd_w_data(dev, ACB_CMD_MCT_WRITE_VALUE, - aword_cnt); - - return err; -} - -static int smctr_join_complete_state(struct net_device *dev) -{ - int err; - - err = smctr_setup_single_cmd(dev, ACB_CMD_CHANGE_JOIN_STATE, - JS_JOIN_COMPLETE_STATE); - - return err; -} - -static int smctr_link_tx_fcbs_to_bdbs(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - unsigned int i, j; - FCBlock *fcb; - BDBlock *bdb; - - for(i = 0; i < NUM_TX_QS_USED; i++) - { - fcb = tp->tx_fcb_head[i]; - bdb = tp->tx_bdb_head[i]; - - for(j = 0; j < tp->num_tx_fcbs[i]; j++) - { - fcb->bdb_ptr = bdb; - fcb->trc_bdb_ptr = TRC_POINTER(bdb); - fcb = (FCBlock *)((char *)fcb + sizeof(FCBlock)); - bdb = (BDBlock *)((char *)bdb + sizeof(BDBlock)); - } - } - - return 0; -} - -static int smctr_load_firmware(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - const struct firmware *fw; - __u16 i, checksum = 0; - int err = 0; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_load_firmware\n", dev->name); - - if (request_firmware(&fw, "tr_smctr.bin", &dev->dev)) { - printk(KERN_ERR "%s: firmware not found\n", dev->name); - return UCODE_NOT_PRESENT; - } - - tp->num_of_tx_buffs = 4; - tp->mode_bits |= UMAC; - tp->receive_mask = 0; - tp->max_packet_size = 4177; - - /* Can only upload the firmware once per adapter reset. */ - if (tp->microcode_version != 0) { - err = (UCODE_PRESENT); - goto out; - } - - /* Verify the firmware exists and is there in the right amount. */ - if (!fw->data || - (*(fw->data + UCODE_VERSION_OFFSET) < UCODE_VERSION)) - { - err = (UCODE_NOT_PRESENT); - goto out; - } - - /* UCODE_SIZE is not included in Checksum. */ - for(i = 0; i < *((__u16 *)(fw->data + UCODE_SIZE_OFFSET)); i += 2) - checksum += *((__u16 *)(fw->data + 2 + i)); - if (checksum) { - err = (UCODE_NOT_PRESENT); - goto out; - } - - /* At this point we have a valid firmware image, lets kick it on up. */ - smctr_enable_adapter_ram(dev); - smctr_enable_16bit(dev); - smctr_set_page(dev, (__u8 *)tp->ram_access); - - if((smctr_checksum_firmware(dev)) || - (*(fw->data + UCODE_VERSION_OFFSET) > tp->microcode_version)) - { - smctr_enable_adapter_ctrl_store(dev); - - /* Zero out ram space for firmware. */ - for(i = 0; i < CS_RAM_SIZE; i += 2) - *((__u16 *)(tp->ram_access + i)) = 0; - - smctr_decode_firmware(dev, fw); - - tp->microcode_version = *(fw->data + UCODE_VERSION_OFFSET); *((__u16 *)(tp->ram_access + CS_RAM_VERSION_OFFSET)) - = (tp->microcode_version << 8); - *((__u16 *)(tp->ram_access + CS_RAM_CHECKSUM_OFFSET)) - = ~(tp->microcode_version << 8) + 1; - - smctr_disable_adapter_ctrl_store(dev); - - if(smctr_checksum_firmware(dev)) - err = HARDWARE_FAILED; - } - else - err = UCODE_PRESENT; - - smctr_disable_16bit(dev); - out: - release_firmware(fw); - return err; -} - -static int smctr_load_node_addr(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - unsigned int i; - __u8 r; - - for(i = 0; i < 6; i++) - { - r = inb(ioaddr + LAR0 + i); - dev->dev_addr[i] = (char)r; - } - dev->addr_len = 6; - - return 0; -} - -/* Lobe Media Test. - * During the transmission of the initial 1500 lobe media MAC frames, - * the phase lock loop in the 805 chip may lock, and then un-lock, causing - * the 825 to go into a PURGE state. When performing a PURGE, the MCT - * microcode will not transmit any frames given to it by the host, and - * will consequently cause a timeout. - * - * NOTE 1: If the monitor_state is MS_BEACON_TEST_STATE, all transmit - * queues other than the one used for the lobe_media_test should be - * disabled.!? - * - * NOTE 2: If the monitor_state is MS_BEACON_TEST_STATE and the receive_mask - * has any multi-cast or promiscuous bits set, the receive_mask needs to - * be changed to clear the multi-cast or promiscuous mode bits, the lobe_test - * run, and then the receive mask set back to its original value if the test - * is successful. - */ -static int smctr_lobe_media_test(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - unsigned int i, perror = 0; - unsigned short saved_rcv_mask; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_lobe_media_test\n", dev->name); - - /* Clear receive mask for lobe test. */ - saved_rcv_mask = tp->receive_mask; - tp->receive_mask = 0; - - smctr_chg_rx_mask(dev); - - /* Setup the lobe media test. */ - smctr_lobe_media_test_cmd(dev); - if(smctr_wait_cmd(dev)) - goto err; - - /* Tx lobe media test frames. */ - for(i = 0; i < 1500; ++i) - { - if(smctr_send_lobe_media_test(dev)) - { - if(perror) - goto err; - else - { - perror = 1; - if(smctr_lobe_media_test_cmd(dev)) - goto err; - } - } - } - - if(smctr_send_dat(dev)) - { - if(smctr_send_dat(dev)) - goto err; - } - - /* Check if any frames received during test. */ - if((tp->rx_fcb_curr[MAC_QUEUE]->frame_status) || - (tp->rx_fcb_curr[NON_MAC_QUEUE]->frame_status)) - goto err; - - /* Set receive mask to "Promisc" mode. */ - tp->receive_mask = saved_rcv_mask; - - smctr_chg_rx_mask(dev); - - return 0; -err: - smctr_reset_adapter(dev); - tp->status = CLOSED; - return LOBE_MEDIA_TEST_FAILED; -} - -static int smctr_lobe_media_test_cmd(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - int err; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_lobe_media_test_cmd\n", dev->name); - - /* Change to lobe media test state. */ - if(tp->monitor_state != MS_BEACON_TEST_STATE) - { - smctr_lobe_media_test_state(dev); - if(smctr_wait_cmd(dev)) - { - printk(KERN_ERR "Lobe Failed test state\n"); - return LOBE_MEDIA_TEST_FAILED; - } - } - - err = smctr_setup_single_cmd(dev, ACB_CMD_MCT_TEST, - TRC_LOBE_MEDIA_TEST); - - return err; -} - -static int smctr_lobe_media_test_state(struct net_device *dev) -{ - int err; - - err = smctr_setup_single_cmd(dev, ACB_CMD_CHANGE_JOIN_STATE, - JS_LOBE_TEST_STATE); - - return err; -} - -static int smctr_make_8025_hdr(struct net_device *dev, - MAC_HEADER *rmf, MAC_HEADER *tmf, __u16 ac_fc) -{ - tmf->ac = MSB(ac_fc); /* msb is access control */ - tmf->fc = LSB(ac_fc); /* lsb is frame control */ - - tmf->sa[0] = dev->dev_addr[0]; - tmf->sa[1] = dev->dev_addr[1]; - tmf->sa[2] = dev->dev_addr[2]; - tmf->sa[3] = dev->dev_addr[3]; - tmf->sa[4] = dev->dev_addr[4]; - tmf->sa[5] = dev->dev_addr[5]; - - switch(tmf->vc) - { - /* Send RQ_INIT to RPS */ - case RQ_INIT: - tmf->da[0] = 0xc0; - tmf->da[1] = 0x00; - tmf->da[2] = 0x00; - tmf->da[3] = 0x00; - tmf->da[4] = 0x00; - tmf->da[5] = 0x02; - break; - - /* Send RPT_TX_FORWARD to CRS */ - case RPT_TX_FORWARD: - tmf->da[0] = 0xc0; - tmf->da[1] = 0x00; - tmf->da[2] = 0x00; - tmf->da[3] = 0x00; - tmf->da[4] = 0x00; - tmf->da[5] = 0x10; - break; - - /* Everything else goes to sender */ - default: - tmf->da[0] = rmf->sa[0]; - tmf->da[1] = rmf->sa[1]; - tmf->da[2] = rmf->sa[2]; - tmf->da[3] = rmf->sa[3]; - tmf->da[4] = rmf->sa[4]; - tmf->da[5] = rmf->sa[5]; - break; - } - - return 0; -} - -static int smctr_make_access_pri(struct net_device *dev, MAC_SUB_VECTOR *tsv) -{ - struct net_local *tp = netdev_priv(dev); - - tsv->svi = AUTHORIZED_ACCESS_PRIORITY; - tsv->svl = S_AUTHORIZED_ACCESS_PRIORITY; - - tsv->svv[0] = MSB(tp->authorized_access_priority); - tsv->svv[1] = LSB(tp->authorized_access_priority); - - return 0; -} - -static int smctr_make_addr_mod(struct net_device *dev, MAC_SUB_VECTOR *tsv) -{ - tsv->svi = ADDRESS_MODIFER; - tsv->svl = S_ADDRESS_MODIFER; - - tsv->svv[0] = 0; - tsv->svv[1] = 0; - - return 0; -} - -static int smctr_make_auth_funct_class(struct net_device *dev, - MAC_SUB_VECTOR *tsv) -{ - struct net_local *tp = netdev_priv(dev); - - tsv->svi = AUTHORIZED_FUNCTION_CLASS; - tsv->svl = S_AUTHORIZED_FUNCTION_CLASS; - - tsv->svv[0] = MSB(tp->authorized_function_classes); - tsv->svv[1] = LSB(tp->authorized_function_classes); - - return 0; -} - -static int smctr_make_corr(struct net_device *dev, - MAC_SUB_VECTOR *tsv, __u16 correlator) -{ - tsv->svi = CORRELATOR; - tsv->svl = S_CORRELATOR; - - tsv->svv[0] = MSB(correlator); - tsv->svv[1] = LSB(correlator); - - return 0; -} - -static int smctr_make_funct_addr(struct net_device *dev, MAC_SUB_VECTOR *tsv) -{ - struct net_local *tp = netdev_priv(dev); - - smctr_get_functional_address(dev); - - tsv->svi = FUNCTIONAL_ADDRESS; - tsv->svl = S_FUNCTIONAL_ADDRESS; - - tsv->svv[0] = MSB(tp->misc_command_data[0]); - tsv->svv[1] = LSB(tp->misc_command_data[0]); - - tsv->svv[2] = MSB(tp->misc_command_data[1]); - tsv->svv[3] = LSB(tp->misc_command_data[1]); - - return 0; -} - -static int smctr_make_group_addr(struct net_device *dev, MAC_SUB_VECTOR *tsv) -{ - struct net_local *tp = netdev_priv(dev); - - smctr_get_group_address(dev); - - tsv->svi = GROUP_ADDRESS; - tsv->svl = S_GROUP_ADDRESS; - - tsv->svv[0] = MSB(tp->misc_command_data[0]); - tsv->svv[1] = LSB(tp->misc_command_data[0]); - - tsv->svv[2] = MSB(tp->misc_command_data[1]); - tsv->svv[3] = LSB(tp->misc_command_data[1]); - - /* Set Group Address Sub-vector to all zeros if only the - * Group Address/Functional Address Indicator is set. - */ - if(tsv->svv[0] == 0x80 && tsv->svv[1] == 0x00 && - tsv->svv[2] == 0x00 && tsv->svv[3] == 0x00) - tsv->svv[0] = 0x00; - - return 0; -} - -static int smctr_make_phy_drop_num(struct net_device *dev, - MAC_SUB_VECTOR *tsv) -{ - struct net_local *tp = netdev_priv(dev); - - smctr_get_physical_drop_number(dev); - - tsv->svi = PHYSICAL_DROP; - tsv->svl = S_PHYSICAL_DROP; - - tsv->svv[0] = MSB(tp->misc_command_data[0]); - tsv->svv[1] = LSB(tp->misc_command_data[0]); - - tsv->svv[2] = MSB(tp->misc_command_data[1]); - tsv->svv[3] = LSB(tp->misc_command_data[1]); - - return 0; -} - -static int smctr_make_product_id(struct net_device *dev, MAC_SUB_VECTOR *tsv) -{ - int i; - - tsv->svi = PRODUCT_INSTANCE_ID; - tsv->svl = S_PRODUCT_INSTANCE_ID; - - for(i = 0; i < 18; i++) - tsv->svv[i] = 0xF0; - - return 0; -} - -static int smctr_make_station_id(struct net_device *dev, MAC_SUB_VECTOR *tsv) -{ - struct net_local *tp = netdev_priv(dev); - - smctr_get_station_id(dev); - - tsv->svi = STATION_IDENTIFER; - tsv->svl = S_STATION_IDENTIFER; - - tsv->svv[0] = MSB(tp->misc_command_data[0]); - tsv->svv[1] = LSB(tp->misc_command_data[0]); - - tsv->svv[2] = MSB(tp->misc_command_data[1]); - tsv->svv[3] = LSB(tp->misc_command_data[1]); - - tsv->svv[4] = MSB(tp->misc_command_data[2]); - tsv->svv[5] = LSB(tp->misc_command_data[2]); - - return 0; -} - -static int smctr_make_ring_station_status(struct net_device *dev, - MAC_SUB_VECTOR * tsv) -{ - tsv->svi = RING_STATION_STATUS; - tsv->svl = S_RING_STATION_STATUS; - - tsv->svv[0] = 0; - tsv->svv[1] = 0; - tsv->svv[2] = 0; - tsv->svv[3] = 0; - tsv->svv[4] = 0; - tsv->svv[5] = 0; - - return 0; -} - -static int smctr_make_ring_station_version(struct net_device *dev, - MAC_SUB_VECTOR *tsv) -{ - struct net_local *tp = netdev_priv(dev); - - tsv->svi = RING_STATION_VERSION_NUMBER; - tsv->svl = S_RING_STATION_VERSION_NUMBER; - - tsv->svv[0] = 0xe2; /* EBCDIC - S */ - tsv->svv[1] = 0xd4; /* EBCDIC - M */ - tsv->svv[2] = 0xc3; /* EBCDIC - C */ - tsv->svv[3] = 0x40; /* EBCDIC - */ - tsv->svv[4] = 0xe5; /* EBCDIC - V */ - tsv->svv[5] = 0xF0 + (tp->microcode_version >> 4); - tsv->svv[6] = 0xF0 + (tp->microcode_version & 0x0f); - tsv->svv[7] = 0x40; /* EBCDIC - */ - tsv->svv[8] = 0xe7; /* EBCDIC - X */ - - if(tp->extra_info & CHIP_REV_MASK) - tsv->svv[9] = 0xc5; /* EBCDIC - E */ - else - tsv->svv[9] = 0xc4; /* EBCDIC - D */ - - return 0; -} - -static int smctr_make_tx_status_code(struct net_device *dev, - MAC_SUB_VECTOR *tsv, __u16 tx_fstatus) -{ - tsv->svi = TRANSMIT_STATUS_CODE; - tsv->svl = S_TRANSMIT_STATUS_CODE; - - tsv->svv[0] = ((tx_fstatus & 0x0100 >> 6) | IBM_PASS_SOURCE_ADDR); - - /* Stripped frame status of Transmitted Frame */ - tsv->svv[1] = tx_fstatus & 0xff; - - return 0; -} - -static int smctr_make_upstream_neighbor_addr(struct net_device *dev, - MAC_SUB_VECTOR *tsv) -{ - struct net_local *tp = netdev_priv(dev); - - smctr_get_upstream_neighbor_addr(dev); - - tsv->svi = UPSTREAM_NEIGHBOR_ADDRESS; - tsv->svl = S_UPSTREAM_NEIGHBOR_ADDRESS; - - tsv->svv[0] = MSB(tp->misc_command_data[0]); - tsv->svv[1] = LSB(tp->misc_command_data[0]); - - tsv->svv[2] = MSB(tp->misc_command_data[1]); - tsv->svv[3] = LSB(tp->misc_command_data[1]); - - tsv->svv[4] = MSB(tp->misc_command_data[2]); - tsv->svv[5] = LSB(tp->misc_command_data[2]); - - return 0; -} - -static int smctr_make_wrap_data(struct net_device *dev, MAC_SUB_VECTOR *tsv) -{ - tsv->svi = WRAP_DATA; - tsv->svl = S_WRAP_DATA; - - return 0; -} - -/* - * Open/initialize the board. This is called sometime after - * booting when the 'ifconfig' program is run. - * - * This routine should set everything up anew at each open, even - * registers that "should" only need to be set once at boot, so that - * there is non-reboot way to recover if something goes wrong. - */ -static int smctr_open(struct net_device *dev) -{ - int err; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_open\n", dev->name); - - err = smctr_init_adapter(dev); - if(err < 0) - return err; - - return err; -} - -/* Interrupt driven open of Token card. */ -static int smctr_open_tr(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - unsigned long flags; - int err; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_open_tr\n", dev->name); - - /* Now we can actually open the adapter. */ - if(tp->status == OPEN) - return 0; - if(tp->status != INITIALIZED) - return -1; - - /* FIXME: it would work a lot better if we masked the irq sources - on the card here, then we could skip the locking and poll nicely */ - spin_lock_irqsave(&tp->lock, flags); - - smctr_set_page(dev, (__u8 *)tp->ram_access); - - if((err = smctr_issue_resume_rx_fcb_cmd(dev, (short)MAC_QUEUE))) - goto out; - - if((err = smctr_issue_resume_rx_bdb_cmd(dev, (short)MAC_QUEUE))) - goto out; - - if((err = smctr_issue_resume_rx_fcb_cmd(dev, (short)NON_MAC_QUEUE))) - goto out; - - if((err = smctr_issue_resume_rx_bdb_cmd(dev, (short)NON_MAC_QUEUE))) - goto out; - - tp->status = CLOSED; - - /* Insert into the Ring or Enter Loopback Mode. */ - if((tp->mode_bits & LOOPING_MODE_MASK) == LOOPBACK_MODE_1) - { - tp->status = CLOSED; - - if(!(err = smctr_issue_trc_loopback_cmd(dev))) - { - if(!(err = smctr_wait_cmd(dev))) - tp->status = OPEN; - } - - smctr_status_chg(dev); - } - else - { - if((tp->mode_bits & LOOPING_MODE_MASK) == LOOPBACK_MODE_2) - { - tp->status = CLOSED; - if(!(err = smctr_issue_tri_loopback_cmd(dev))) - { - if(!(err = smctr_wait_cmd(dev))) - tp->status = OPEN; - } - - smctr_status_chg(dev); - } - else - { - if((tp->mode_bits & LOOPING_MODE_MASK) - == LOOPBACK_MODE_3) - { - tp->status = CLOSED; - if(!(err = smctr_lobe_media_test_cmd(dev))) - { - if(!(err = smctr_wait_cmd(dev))) - tp->status = OPEN; - } - smctr_status_chg(dev); - } - else - { - if(!(err = smctr_lobe_media_test(dev))) - err = smctr_issue_insert_cmd(dev); - else - { - if(err == LOBE_MEDIA_TEST_FAILED) - printk(KERN_WARNING "%s: Lobe Media Test Failure - Check cable?\n", dev->name); - } - } - } - } - -out: - spin_unlock_irqrestore(&tp->lock, flags); - - return err; -} - -/* Check for a network adapter of this type, - * and return device structure if one exists. - */ -struct net_device __init *smctr_probe(int unit) -{ - struct net_device *dev = alloc_trdev(sizeof(struct net_local)); - static const unsigned ports[] = { - 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, 0x300, - 0x320, 0x340, 0x360, 0x380, 0 - }; - const unsigned *port; - int err = 0; - - if (!dev) - return ERR_PTR(-ENOMEM); - - if (unit >= 0) { - sprintf(dev->name, "tr%d", unit); - netdev_boot_setup_check(dev); - } - - if (dev->base_addr > 0x1ff) /* Check a single specified location. */ - err = smctr_probe1(dev, dev->base_addr); - else if(dev->base_addr != 0) /* Don't probe at all. */ - err =-ENXIO; - else { - for (port = ports; *port; port++) { - err = smctr_probe1(dev, *port); - if (!err) - break; - } - } - if (err) - goto out; - err = register_netdev(dev); - if (err) - goto out1; - return dev; -out1: -#ifdef CONFIG_MCA_LEGACY - { struct net_local *tp = netdev_priv(dev); - if (tp->slot_num) - mca_mark_as_unused(tp->slot_num); - } -#endif - release_region(dev->base_addr, SMCTR_IO_EXTENT); - free_irq(dev->irq, dev); -out: - free_netdev(dev); - return ERR_PTR(err); -} - -static const struct net_device_ops smctr_netdev_ops = { - .ndo_open = smctr_open, - .ndo_stop = smctr_close, - .ndo_start_xmit = smctr_send_packet, - .ndo_tx_timeout = smctr_timeout, - .ndo_get_stats = smctr_get_stats, - .ndo_set_rx_mode = smctr_set_multicast_list, -}; - -static int __init smctr_probe1(struct net_device *dev, int ioaddr) -{ - static unsigned version_printed; - struct net_local *tp = netdev_priv(dev); - int err; - __u32 *ram; - - if(smctr_debug && version_printed++ == 0) - printk(version); - - spin_lock_init(&tp->lock); - dev->base_addr = ioaddr; - - /* Actually detect an adapter now. */ - err = smctr_chk_isa(dev); - if(err < 0) - { - if ((err = smctr_chk_mca(dev)) < 0) { - err = -ENODEV; - goto out; - } - } - - tp = netdev_priv(dev); - dev->mem_start = tp->ram_base; - dev->mem_end = dev->mem_start + 0x10000; - ram = (__u32 *)phys_to_virt(dev->mem_start); - tp->ram_access = *(__u32 *)&ram; - tp->status = NOT_INITIALIZED; - - err = smctr_load_firmware(dev); - if(err != UCODE_PRESENT && err != SUCCESS) - { - printk(KERN_ERR "%s: Firmware load failed (%d)\n", dev->name, err); - err = -EIO; - goto out; - } - - /* Allow user to specify ring speed on module insert. */ - if(ringspeed == 4) - tp->media_type = MEDIA_UTP_4; - else - tp->media_type = MEDIA_UTP_16; - - printk(KERN_INFO "%s: %s %s at Io %#4x, Irq %d, Rom %#4x, Ram %#4x.\n", - dev->name, smctr_name, smctr_model, - (unsigned int)dev->base_addr, - dev->irq, tp->rom_base, tp->ram_base); - - dev->netdev_ops = &smctr_netdev_ops; - dev->watchdog_timeo = HZ; - return 0; - -out: - return err; -} - -static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size, - struct net_device *dev, __u16 rx_status) -{ - struct net_local *tp = netdev_priv(dev); - struct sk_buff *skb; - __u16 rcode, correlator; - int err = 0; - __u8 xframe = 1; - - rmf->vl = SWAP_BYTES(rmf->vl); - if(rx_status & FCB_RX_STATUS_DA_MATCHED) - { - switch(rmf->vc) - { - /* Received MAC Frames Processed by RS. */ - case INIT: - if((rcode = smctr_rcv_init(dev, rmf, &correlator)) == HARDWARE_FAILED) - { - return rcode; - } - - if((err = smctr_send_rsp(dev, rmf, rcode, - correlator))) - { - return err; - } - break; - - case CHG_PARM: - if((rcode = smctr_rcv_chg_param(dev, rmf, - &correlator)) ==HARDWARE_FAILED) - { - return rcode; - } - - if((err = smctr_send_rsp(dev, rmf, rcode, - correlator))) - { - return err; - } - break; - - case RQ_ADDR: - if((rcode = smctr_rcv_rq_addr_state_attch(dev, - rmf, &correlator)) != POSITIVE_ACK) - { - if(rcode == HARDWARE_FAILED) - return rcode; - else - return smctr_send_rsp(dev, rmf, - rcode, correlator); - } - - if((err = smctr_send_rpt_addr(dev, rmf, - correlator))) - { - return err; - } - break; - - case RQ_ATTCH: - if((rcode = smctr_rcv_rq_addr_state_attch(dev, - rmf, &correlator)) != POSITIVE_ACK) - { - if(rcode == HARDWARE_FAILED) - return rcode; - else - return smctr_send_rsp(dev, rmf, - rcode, - correlator); - } - - if((err = smctr_send_rpt_attch(dev, rmf, - correlator))) - { - return err; - } - break; - - case RQ_STATE: - if((rcode = smctr_rcv_rq_addr_state_attch(dev, - rmf, &correlator)) != POSITIVE_ACK) - { - if(rcode == HARDWARE_FAILED) - return rcode; - else - return smctr_send_rsp(dev, rmf, - rcode, - correlator); - } - - if((err = smctr_send_rpt_state(dev, rmf, - correlator))) - { - return err; - } - break; - - case TX_FORWARD: { - __u16 uninitialized_var(tx_fstatus); - - if((rcode = smctr_rcv_tx_forward(dev, rmf)) - != POSITIVE_ACK) - { - if(rcode == HARDWARE_FAILED) - return rcode; - else - return smctr_send_rsp(dev, rmf, - rcode, - correlator); - } - - if((err = smctr_send_tx_forward(dev, rmf, - &tx_fstatus)) == HARDWARE_FAILED) - { - return err; - } - - if(err == A_FRAME_WAS_FORWARDED) - { - if((err = smctr_send_rpt_tx_forward(dev, - rmf, tx_fstatus)) - == HARDWARE_FAILED) - { - return err; - } - } - break; - } - - /* Received MAC Frames Processed by CRS/REM/RPS. */ - case RSP: - case RQ_INIT: - case RPT_NEW_MON: - case RPT_SUA_CHG: - case RPT_ACTIVE_ERR: - case RPT_NN_INCMP: - case RPT_ERROR: - case RPT_ATTCH: - case RPT_STATE: - case RPT_ADDR: - break; - - /* Rcvd Att. MAC Frame (if RXATMAC set) or UNKNOWN */ - default: - xframe = 0; - if(!(tp->receive_mask & ACCEPT_ATT_MAC_FRAMES)) - { - rcode = smctr_rcv_unknown(dev, rmf, - &correlator); - if((err = smctr_send_rsp(dev, rmf,rcode, - correlator))) - { - return err; - } - } - - break; - } - } - else - { - /* 1. DA doesn't match (Promiscuous Mode). - * 2. Parse for Extended MAC Frame Type. - */ - switch(rmf->vc) - { - case RSP: - case INIT: - case RQ_INIT: - case RQ_ADDR: - case RQ_ATTCH: - case RQ_STATE: - case CHG_PARM: - case RPT_ADDR: - case RPT_ERROR: - case RPT_ATTCH: - case RPT_STATE: - case RPT_NEW_MON: - case RPT_SUA_CHG: - case RPT_NN_INCMP: - case RPT_ACTIVE_ERR: - break; - - default: - xframe = 0; - break; - } - } - - /* NOTE: UNKNOWN MAC frames will NOT be passed up unless - * ACCEPT_ATT_MAC_FRAMES is set. - */ - if(((tp->receive_mask & ACCEPT_ATT_MAC_FRAMES) && - (xframe == (__u8)0)) || - ((tp->receive_mask & ACCEPT_EXT_MAC_FRAMES) && - (xframe == (__u8)1))) - { - rmf->vl = SWAP_BYTES(rmf->vl); - - if (!(skb = dev_alloc_skb(size))) - return -ENOMEM; - skb->len = size; - - /* Slide data into a sleek skb. */ - skb_put(skb, skb->len); - skb_copy_to_linear_data(skb, rmf, skb->len); - - /* Update Counters */ - tp->MacStat.rx_packets++; - tp->MacStat.rx_bytes += skb->len; - - /* Kick the packet on up. */ - skb->protocol = tr_type_trans(skb, dev); - netif_rx(skb); - err = 0; - } - - return err; -} - -/* Adapter RAM test. Incremental word ODD boundary data test. */ -static int smctr_ram_memory_test(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - __u16 page, pages_of_ram, start_pattern = 0, word_pattern = 0, - word_read = 0, err_word = 0, err_pattern = 0; - unsigned int err_offset; - __u32 j, pword; - __u8 err = 0; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_ram_memory_test\n", dev->name); - - start_pattern = 0x0001; - pages_of_ram = tp->ram_size / tp->ram_usable; - pword = tp->ram_access; - - /* Incremental word ODD boundary test. */ - for(page = 0; (page < pages_of_ram) && (~err); - page++, start_pattern += 0x8000) - { - smctr_set_page(dev, (__u8 *)(tp->ram_access - + (page * tp->ram_usable * 1024) + 1)); - word_pattern = start_pattern; - - for(j = 1; j < (__u32)(tp->ram_usable * 1024) - 1; j += 2) - *(__u16 *)(pword + j) = word_pattern++; - - word_pattern = start_pattern; - - for(j = 1; j < (__u32)(tp->ram_usable * 1024) - 1 && (~err); - j += 2, word_pattern++) - { - word_read = *(__u16 *)(pword + j); - if(word_read != word_pattern) - { - err = (__u8)1; - err_offset = j; - err_word = word_read; - err_pattern = word_pattern; - return RAM_TEST_FAILED; - } - } - } - - /* Zero out memory. */ - for(page = 0; page < pages_of_ram && (~err); page++) - { - smctr_set_page(dev, (__u8 *)(tp->ram_access - + (page * tp->ram_usable * 1024))); - word_pattern = 0; - - for(j = 0; j < (__u32)tp->ram_usable * 1024; j +=2) - *(__u16 *)(pword + j) = word_pattern; - - for(j =0; j < (__u32)tp->ram_usable * 1024 && (~err); j += 2) - { - word_read = *(__u16 *)(pword + j); - if(word_read != word_pattern) - { - err = (__u8)1; - err_offset = j; - err_word = word_read; - err_pattern = word_pattern; - return RAM_TEST_FAILED; - } - } - } - - smctr_set_page(dev, (__u8 *)tp->ram_access); - - return 0; -} - -static int smctr_rcv_chg_param(struct net_device *dev, MAC_HEADER *rmf, - __u16 *correlator) -{ - MAC_SUB_VECTOR *rsv; - signed short vlen; - __u16 rcode = POSITIVE_ACK; - unsigned int svectors = F_NO_SUB_VECTORS_FOUND; - - /* This Frame can only come from a CRS */ - if((rmf->dc_sc & SC_MASK) != SC_CRS) - return E_INAPPROPRIATE_SOURCE_CLASS; - - /* Remove MVID Length from total length. */ - vlen = (signed short)rmf->vl - 4; - - /* Point to First SVID */ - rsv = (MAC_SUB_VECTOR *)((__u32)rmf + sizeof(MAC_HEADER)); - - /* Search for Appropriate SVID's. */ - while((vlen > 0) && (rcode == POSITIVE_ACK)) - { - switch(rsv->svi) - { - case CORRELATOR: - svectors |= F_CORRELATOR; - rcode = smctr_set_corr(dev, rsv, correlator); - break; - - case LOCAL_RING_NUMBER: - svectors |= F_LOCAL_RING_NUMBER; - rcode = smctr_set_local_ring_num(dev, rsv); - break; - - case ASSIGN_PHYSICAL_DROP: - svectors |= F_ASSIGN_PHYSICAL_DROP; - rcode = smctr_set_phy_drop(dev, rsv); - break; - - case ERROR_TIMER_VALUE: - svectors |= F_ERROR_TIMER_VALUE; - rcode = smctr_set_error_timer_value(dev, rsv); - break; - - case AUTHORIZED_FUNCTION_CLASS: - svectors |= F_AUTHORIZED_FUNCTION_CLASS; - rcode = smctr_set_auth_funct_class(dev, rsv); - break; - - case AUTHORIZED_ACCESS_PRIORITY: - svectors |= F_AUTHORIZED_ACCESS_PRIORITY; - rcode = smctr_set_auth_access_pri(dev, rsv); - break; - - default: - rcode = E_SUB_VECTOR_UNKNOWN; - break; - } - - /* Let Sender Know if SUM of SV length's is - * larger then length in MVID length field - */ - if((vlen -= rsv->svl) < 0) - rcode = E_VECTOR_LENGTH_ERROR; - - rsv = (MAC_SUB_VECTOR *)((__u32)rsv + rsv->svl); - } - - if(rcode == POSITIVE_ACK) - { - /* Let Sender Know if MVID length field - * is larger then SUM of SV length's - */ - if(vlen != 0) - rcode = E_VECTOR_LENGTH_ERROR; - else - { - /* Let Sender Know if Expected SVID Missing */ - if((svectors & R_CHG_PARM) ^ R_CHG_PARM) - rcode = E_MISSING_SUB_VECTOR; - } - } - - return rcode; -} - -static int smctr_rcv_init(struct net_device *dev, MAC_HEADER *rmf, - __u16 *correlator) -{ - MAC_SUB_VECTOR *rsv; - signed short vlen; - __u16 rcode = POSITIVE_ACK; - unsigned int svectors = F_NO_SUB_VECTORS_FOUND; - - /* This Frame can only come from a RPS */ - if((rmf->dc_sc & SC_MASK) != SC_RPS) - return E_INAPPROPRIATE_SOURCE_CLASS; - - /* Remove MVID Length from total length. */ - vlen = (signed short)rmf->vl - 4; - - /* Point to First SVID */ - rsv = (MAC_SUB_VECTOR *)((__u32)rmf + sizeof(MAC_HEADER)); - - /* Search for Appropriate SVID's */ - while((vlen > 0) && (rcode == POSITIVE_ACK)) - { - switch(rsv->svi) - { - case CORRELATOR: - svectors |= F_CORRELATOR; - rcode = smctr_set_corr(dev, rsv, correlator); - break; - - case LOCAL_RING_NUMBER: - svectors |= F_LOCAL_RING_NUMBER; - rcode = smctr_set_local_ring_num(dev, rsv); - break; - - case ASSIGN_PHYSICAL_DROP: - svectors |= F_ASSIGN_PHYSICAL_DROP; - rcode = smctr_set_phy_drop(dev, rsv); - break; - - case ERROR_TIMER_VALUE: - svectors |= F_ERROR_TIMER_VALUE; - rcode = smctr_set_error_timer_value(dev, rsv); - break; - - default: - rcode = E_SUB_VECTOR_UNKNOWN; - break; - } - - /* Let Sender Know if SUM of SV length's is - * larger then length in MVID length field - */ - if((vlen -= rsv->svl) < 0) - rcode = E_VECTOR_LENGTH_ERROR; - - rsv = (MAC_SUB_VECTOR *)((__u32)rsv + rsv->svl); - } - - if(rcode == POSITIVE_ACK) - { - /* Let Sender Know if MVID length field - * is larger then SUM of SV length's - */ - if(vlen != 0) - rcode = E_VECTOR_LENGTH_ERROR; - else - { - /* Let Sender Know if Expected SV Missing */ - if((svectors & R_INIT) ^ R_INIT) - rcode = E_MISSING_SUB_VECTOR; - } - } - - return rcode; -} - -static int smctr_rcv_tx_forward(struct net_device *dev, MAC_HEADER *rmf) -{ - MAC_SUB_VECTOR *rsv; - signed short vlen; - __u16 rcode = POSITIVE_ACK; - unsigned int svectors = F_NO_SUB_VECTORS_FOUND; - - /* This Frame can only come from a CRS */ - if((rmf->dc_sc & SC_MASK) != SC_CRS) - return E_INAPPROPRIATE_SOURCE_CLASS; - - /* Remove MVID Length from total length */ - vlen = (signed short)rmf->vl - 4; - - /* Point to First SVID */ - rsv = (MAC_SUB_VECTOR *)((__u32)rmf + sizeof(MAC_HEADER)); - - /* Search for Appropriate SVID's */ - while((vlen > 0) && (rcode == POSITIVE_ACK)) - { - switch(rsv->svi) - { - case FRAME_FORWARD: - svectors |= F_FRAME_FORWARD; - rcode = smctr_set_frame_forward(dev, rsv, - rmf->dc_sc); - break; - - default: - rcode = E_SUB_VECTOR_UNKNOWN; - break; - } - - /* Let Sender Know if SUM of SV length's is - * larger then length in MVID length field - */ - if((vlen -= rsv->svl) < 0) - rcode = E_VECTOR_LENGTH_ERROR; - - rsv = (MAC_SUB_VECTOR *)((__u32)rsv + rsv->svl); - } - - if(rcode == POSITIVE_ACK) - { - /* Let Sender Know if MVID length field - * is larger then SUM of SV length's - */ - if(vlen != 0) - rcode = E_VECTOR_LENGTH_ERROR; - else - { - /* Let Sender Know if Expected SV Missing */ - if((svectors & R_TX_FORWARD) ^ R_TX_FORWARD) - rcode = E_MISSING_SUB_VECTOR; - } - } - - return rcode; -} - -static int smctr_rcv_rq_addr_state_attch(struct net_device *dev, - MAC_HEADER *rmf, __u16 *correlator) -{ - MAC_SUB_VECTOR *rsv; - signed short vlen; - __u16 rcode = POSITIVE_ACK; - unsigned int svectors = F_NO_SUB_VECTORS_FOUND; - - /* Remove MVID Length from total length */ - vlen = (signed short)rmf->vl - 4; - - /* Point to First SVID */ - rsv = (MAC_SUB_VECTOR *)((__u32)rmf + sizeof(MAC_HEADER)); - - /* Search for Appropriate SVID's */ - while((vlen > 0) && (rcode == POSITIVE_ACK)) - { - switch(rsv->svi) - { - case CORRELATOR: - svectors |= F_CORRELATOR; - rcode = smctr_set_corr(dev, rsv, correlator); - break; - - default: - rcode = E_SUB_VECTOR_UNKNOWN; - break; - } - - /* Let Sender Know if SUM of SV length's is - * larger then length in MVID length field - */ - if((vlen -= rsv->svl) < 0) - rcode = E_VECTOR_LENGTH_ERROR; - - rsv = (MAC_SUB_VECTOR *)((__u32)rsv + rsv->svl); - } - - if(rcode == POSITIVE_ACK) - { - /* Let Sender Know if MVID length field - * is larger then SUM of SV length's - */ - if(vlen != 0) - rcode = E_VECTOR_LENGTH_ERROR; - else - { - /* Let Sender Know if Expected SVID Missing */ - if((svectors & R_RQ_ATTCH_STATE_ADDR) - ^ R_RQ_ATTCH_STATE_ADDR) - rcode = E_MISSING_SUB_VECTOR; - } - } - - return rcode; -} - -static int smctr_rcv_unknown(struct net_device *dev, MAC_HEADER *rmf, - __u16 *correlator) -{ - MAC_SUB_VECTOR *rsv; - signed short vlen; - - *correlator = 0; - - /* Remove MVID Length from total length */ - vlen = (signed short)rmf->vl - 4; - - /* Point to First SVID */ - rsv = (MAC_SUB_VECTOR *)((__u32)rmf + sizeof(MAC_HEADER)); - - /* Search for CORRELATOR for RSP to UNKNOWN */ - while((vlen > 0) && (*correlator == 0)) - { - switch(rsv->svi) - { - case CORRELATOR: - smctr_set_corr(dev, rsv, correlator); - break; - - default: - break; - } - - vlen -= rsv->svl; - rsv = (MAC_SUB_VECTOR *)((__u32)rsv + rsv->svl); - } - - return E_UNRECOGNIZED_VECTOR_ID; -} - -/* - * Reset the 825 NIC and exit w: - * 1. The NIC reset cleared (non-reset state), halted and un-initialized. - * 2. TINT masked. - * 3. CBUSY masked. - * 4. TINT clear. - * 5. CBUSY clear. - */ -static int smctr_reset_adapter(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - int ioaddr = dev->base_addr; - - /* Reseting the NIC will put it in a halted and un-initialized state. */ smctr_set_trc_reset(ioaddr); - mdelay(200); /* ~2 ms */ - - smctr_clear_trc_reset(ioaddr); - mdelay(200); /* ~2 ms */ - - /* Remove any latched interrupts that occurred prior to reseting the - * adapter or possibily caused by line glitches due to the reset. - */ - outb(tp->trc_mask | CSR_CLRTINT | CSR_CLRCBUSY, ioaddr + CSR); - - return 0; -} - -static int smctr_restart_tx_chain(struct net_device *dev, short queue) -{ - struct net_local *tp = netdev_priv(dev); - int err = 0; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_restart_tx_chain\n", dev->name); - - if(tp->num_tx_fcbs_used[queue] != 0 && - tp->tx_queue_status[queue] == NOT_TRANSMITING) - { - tp->tx_queue_status[queue] = TRANSMITING; - err = smctr_issue_resume_tx_fcb_cmd(dev, queue); - } - - return err; -} - -static int smctr_ring_status_chg(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_ring_status_chg\n", dev->name); - - /* Check for ring_status_flag: whenever MONITOR_STATE_BIT - * Bit is set, check value of monitor_state, only then we - * enable and start transmit/receive timeout (if and only - * if it is MS_ACTIVE_MONITOR_STATE or MS_STANDBY_MONITOR_STATE) - */ - if(tp->ring_status_flags == MONITOR_STATE_CHANGED) - { - if((tp->monitor_state == MS_ACTIVE_MONITOR_STATE) || - (tp->monitor_state == MS_STANDBY_MONITOR_STATE)) - { - tp->monitor_state_ready = 1; - } - else - { - /* if adapter is NOT in either active monitor - * or standby monitor state => Disable - * transmit/receive timeout. - */ - tp->monitor_state_ready = 0; - - /* Ring speed problem, switching to auto mode. */ - if(tp->monitor_state == MS_MONITOR_FSM_INACTIVE && - !tp->cleanup) - { - printk(KERN_INFO "%s: Incorrect ring speed switching.\n", - dev->name); - smctr_set_ring_speed(dev); - } - } - } - - if(!(tp->ring_status_flags & RING_STATUS_CHANGED)) - return 0; - - switch(tp->ring_status) - { - case RING_RECOVERY: - printk(KERN_INFO "%s: Ring Recovery\n", dev->name); - break; - - case SINGLE_STATION: - printk(KERN_INFO "%s: Single Statinon\n", dev->name); - break; - - case COUNTER_OVERFLOW: - printk(KERN_INFO "%s: Counter Overflow\n", dev->name); - break; - - case REMOVE_RECEIVED: - printk(KERN_INFO "%s: Remove Received\n", dev->name); - break; - - case AUTO_REMOVAL_ERROR: - printk(KERN_INFO "%s: Auto Remove Error\n", dev->name); - break; - - case LOBE_WIRE_FAULT: - printk(KERN_INFO "%s: Lobe Wire Fault\n", dev->name); - break; - - case TRANSMIT_BEACON: - printk(KERN_INFO "%s: Transmit Beacon\n", dev->name); - break; - - case SOFT_ERROR: - printk(KERN_INFO "%s: Soft Error\n", dev->name); - break; - - case HARD_ERROR: - printk(KERN_INFO "%s: Hard Error\n", dev->name); - break; - - case SIGNAL_LOSS: - printk(KERN_INFO "%s: Signal Loss\n", dev->name); - break; - - default: - printk(KERN_INFO "%s: Unknown ring status change\n", - dev->name); - break; - } - - return 0; -} - -static int smctr_rx_frame(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - __u16 queue, status, rx_size, err = 0; - __u8 *pbuff; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_rx_frame\n", dev->name); - - queue = tp->receive_queue_number; - - while((status = tp->rx_fcb_curr[queue]->frame_status) != SUCCESS) - { - err = HARDWARE_FAILED; - - if(((status & 0x007f) == 0) || - ((tp->receive_mask & ACCEPT_ERR_PACKETS) != 0)) - { - /* frame length less the CRC (4 bytes) + FS (1 byte) */ - rx_size = tp->rx_fcb_curr[queue]->frame_length - 5; - - pbuff = smctr_get_rx_pointer(dev, queue); - - smctr_set_page(dev, pbuff); - smctr_disable_16bit(dev); - - /* pbuff points to addr within one page */ - pbuff = (__u8 *)PAGE_POINTER(pbuff); - - if(queue == NON_MAC_QUEUE) - { - struct sk_buff *skb; - - skb = dev_alloc_skb(rx_size); - if (skb) { - skb_put(skb, rx_size); - - skb_copy_to_linear_data(skb, pbuff, rx_size); - - /* Update Counters */ - tp->MacStat.rx_packets++; - tp->MacStat.rx_bytes += skb->len; - - /* Kick the packet on up. */ - skb->protocol = tr_type_trans(skb, dev); - netif_rx(skb); - } else { - } - } - else - smctr_process_rx_packet((MAC_HEADER *)pbuff, - rx_size, dev, status); - } - - smctr_enable_16bit(dev); - smctr_set_page(dev, (__u8 *)tp->ram_access); - smctr_update_rx_chain(dev, queue); - - if(err != SUCCESS) - break; - } - - return err; -} - -static int smctr_send_dat(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - unsigned int i, err; - MAC_HEADER *tmf; - FCBlock *fcb; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_send_dat\n", dev->name); - - if((fcb = smctr_get_tx_fcb(dev, MAC_QUEUE, - sizeof(MAC_HEADER))) == (FCBlock *)(-1L)) - { - return OUT_OF_RESOURCES; - } - - /* Initialize DAT Data Fields. */ - tmf = (MAC_HEADER *)fcb->bdb_ptr->data_block_ptr; - tmf->ac = MSB(AC_FC_DAT); - tmf->fc = LSB(AC_FC_DAT); - - for(i = 0; i < 6; i++) - { - tmf->sa[i] = dev->dev_addr[i]; - tmf->da[i] = dev->dev_addr[i]; - - } - - tmf->vc = DAT; - tmf->dc_sc = DC_RS | SC_RS; - tmf->vl = 4; - tmf->vl = SWAP_BYTES(tmf->vl); - - /* Start Transmit. */ - if((err = smctr_trc_send_packet(dev, fcb, MAC_QUEUE))) - return err; - - /* Wait for Transmit to Complete */ - for(i = 0; i < 10000; i++) - { - if(fcb->frame_status & FCB_COMMAND_DONE) - break; - mdelay(1); - } - - /* Check if GOOD frame Tx'ed. */ - if(!(fcb->frame_status & FCB_COMMAND_DONE) || - fcb->frame_status & (FCB_TX_STATUS_E | FCB_TX_AC_BITS)) - { - return INITIALIZE_FAILED; - } - - /* De-allocated Tx FCB and Frame Buffer - * The FCB must be de-allocated manually if executing with - * interrupts disabled, other wise the ISR (LM_Service_Events) - * will de-allocate it when the interrupt occurs. - */ - tp->tx_queue_status[MAC_QUEUE] = NOT_TRANSMITING; - smctr_update_tx_chain(dev, fcb, MAC_QUEUE); - - return 0; -} - -static void smctr_timeout(struct net_device *dev) -{ - /* - * If we get here, some higher level has decided we are broken. - * There should really be a "kick me" function call instead. - * - * Resetting the token ring adapter takes a long time so just - * fake transmission time and go on trying. Our own timeout - * routine is in sktr_timer_chk() - */ - dev->trans_start = jiffies; /* prevent tx timeout */ - netif_wake_queue(dev); -} - -/* - * Gets skb from system, queues it and checks if it can be sent - */ -static netdev_tx_t smctr_send_packet(struct sk_buff *skb, - struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_send_packet\n", dev->name); - - /* - * Block a transmit overlap - */ - - netif_stop_queue(dev); - - if(tp->QueueSkb == 0) - return NETDEV_TX_BUSY; /* Return with tbusy set: queue full */ - - tp->QueueSkb--; - skb_queue_tail(&tp->SendSkbQueue, skb); - smctr_hardware_send_packet(dev, tp); - if(tp->QueueSkb > 0) - netif_wake_queue(dev); - - return NETDEV_TX_OK; -} - -static int smctr_send_lobe_media_test(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - MAC_SUB_VECTOR *tsv; - MAC_HEADER *tmf; - FCBlock *fcb; - __u32 i; - int err; - - if(smctr_debug > 15) - printk(KERN_DEBUG "%s: smctr_send_lobe_media_test\n", dev->name); - - if((fcb = smctr_get_tx_fcb(dev, MAC_QUEUE, sizeof(struct trh_hdr) - + S_WRAP_DATA + S_WRAP_DATA)) == (FCBlock *)(-1L)) - { - return OUT_OF_RESOURCES; - } - - /* Initialize DAT Data Fields. */ - tmf = (MAC_HEADER *)fcb->bdb_ptr->data_block_ptr; - tmf->ac = MSB(AC_FC_LOBE_MEDIA_TEST); - tmf->fc = LSB(AC_FC_LOBE_MEDIA_TEST); - - for(i = 0; i < 6; i++) - { - tmf->da[i] = 0; - tmf->sa[i] = dev->dev_addr[i]; - } - - tmf->vc = LOBE_MEDIA_TEST; - tmf->dc_sc = DC_RS | SC_RS; - tmf->vl = 4; - - tsv = (MAC_SUB_VECTOR *)((__u32)tmf + sizeof(MAC_HEADER)); - smctr_make_wrap_data(dev, tsv); - tmf->vl += tsv->svl; - - tsv = (MAC_SUB_VECTOR *)((__u32)tsv + tsv->svl); - smctr_make_wrap_data(dev, tsv); - tmf->vl += tsv->svl; - - /* Start Transmit. */ - tmf->vl = SWAP_BYTES(tmf->vl); - if((err = smctr_trc_send_packet(dev, fcb, MAC_QUEUE))) - return err; - - /* Wait for Transmit to Complete. (10 ms). */ - for(i=0; i < 10000; i++) - { - if(fcb->frame_status & FCB_COMMAND_DONE) - break; - mdelay(1); - } - - /* Check if GOOD frame Tx'ed */ - if(!(fcb->frame_status & FCB_COMMAND_DONE) || - fcb->frame_status & (FCB_TX_STATUS_E | FCB_TX_AC_BITS)) - { - return LOBE_MEDIA_TEST_FAILED; - } - - /* De-allocated Tx FCB and Frame Buffer - * The FCB must be de-allocated manually if executing with - * interrupts disabled, other wise the ISR (LM_Service_Events) - * will de-allocate it when the interrupt occurs. - */ - tp->tx_queue_status[MAC_QUEUE] = NOT_TRANSMITING; - smctr_update_tx_chain(dev, fcb, MAC_QUEUE); - - return 0; -} - -static int smctr_send_rpt_addr(struct net_device *dev, MAC_HEADER *rmf, - __u16 correlator) -{ - MAC_HEADER *tmf; - MAC_SUB_VECTOR *tsv; - FCBlock *fcb; - - if((fcb = smctr_get_tx_fcb(dev, MAC_QUEUE, sizeof(MAC_HEADER) - + S_CORRELATOR + S_PHYSICAL_DROP + S_UPSTREAM_NEIGHBOR_ADDRESS - + S_ADDRESS_MODIFER + S_GROUP_ADDRESS + S_FUNCTIONAL_ADDRESS)) - == (FCBlock *)(-1L)) - { - return 0; - } - - tmf = (MAC_HEADER *)fcb->bdb_ptr->data_block_ptr; - tmf->vc = RPT_ADDR; - tmf->dc_sc = (rmf->dc_sc & SC_MASK) << 4; - tmf->vl = 4; - - smctr_make_8025_hdr(dev, rmf, tmf, AC_FC_RPT_ADDR); - - tsv = (MAC_SUB_VECTOR *)((__u32)tmf + sizeof(MAC_HEADER)); - smctr_make_corr(dev, tsv, correlator); - - tmf->vl += tsv->svl; - tsv = (MAC_SUB_VECTOR *)((__u32)tsv + tsv->svl); - smctr_make_phy_drop_num(dev, tsv); - - tmf->vl += tsv->svl; - tsv = (MAC_SUB_VECTOR *)((__u32)tsv + tsv->svl); - smctr_make_upstream_neighbor_addr(dev, tsv); - - tmf->vl += tsv->svl; - tsv = (MAC_SUB_VECTOR *)((__u32)tsv + tsv->svl); - smctr_make_addr_mod(dev, tsv); - - tmf->vl += tsv->svl; - tsv = (MAC_SUB_VECTOR *)((__u32)tsv + tsv->svl); - smctr_make_group_addr(dev, tsv); - - tmf->vl += tsv->svl; - tsv = (MAC_SUB_VECTOR *)((__u32)tsv + tsv->svl); - smctr_make_funct_addr(dev, tsv); - - tmf->vl += tsv->svl; - - /* Subtract out MVID and MVL which is - * include in both vl and MAC_HEADER - */ -/* fcb->frame_length = tmf->vl + sizeof(MAC_HEADER) - 4; - fcb->bdb_ptr->buffer_length = tmf->vl + sizeof(MAC_HEADER) - 4; -*/ - tmf->vl = SWAP_BYTES(tmf->vl); - - return smctr_trc_send_packet(dev, fcb, MAC_QUEUE); -} - -static int smctr_send_rpt_attch(struct net_device *dev, MAC_HEADER *rmf, - __u16 correlator) -{ - MAC_HEADER *tmf; - MAC_SUB_VECTOR *tsv; - FCBlock *fcb; - - if((fcb = smctr_get_tx_fcb(dev, MAC_QUEUE, sizeof(MAC_HEADER) - + S_CORRELATOR + S_PRODUCT_INSTANCE_ID + S_FUNCTIONAL_ADDRESS - + S_AUTHORIZED_FUNCTION_CLASS + S_AUTHORIZED_ACCESS_PRIORITY)) - == (FCBlock *)(-1L)) - { - return 0; - } - - tmf = (MAC_HEADER *)fcb->bdb_ptr->data_block_ptr; - tmf->vc = RPT_ATTCH; - tmf->dc_sc = (rmf->dc_sc & SC_MASK) << 4; - tmf->vl = 4; - - smctr_make_8025_hdr(dev, rmf, tmf, AC_FC_RPT_ATTCH); - - tsv = (MAC_SUB_VECTOR *)((__u32)tmf + sizeof(MAC_HEADER)); - smctr_make_corr(dev, tsv, correlator); - - tmf->vl += tsv->svl; - tsv = (MAC_SUB_VECTOR *)((__u32)tsv + tsv->svl); - smctr_make_product_id(dev, tsv); - - tmf->vl += tsv->svl; - tsv = (MAC_SUB_VECTOR *)((__u32)tsv + tsv->svl); - smctr_make_funct_addr(dev, tsv); - - tmf->vl += tsv->svl; - tsv = (MAC_SUB_VECTOR *)((__u32)tsv + tsv->svl); - smctr_make_auth_funct_class(dev, tsv); - - tmf->vl += tsv->svl; - tsv = (MAC_SUB_VECTOR *)((__u32)tsv + tsv->svl); - smctr_make_access_pri(dev, tsv); - - tmf->vl += tsv->svl; - - /* Subtract out MVID and MVL which is - * include in both vl and MAC_HEADER - */ -/* fcb->frame_length = tmf->vl + sizeof(MAC_HEADER) - 4; - fcb->bdb_ptr->buffer_length = tmf->vl + sizeof(MAC_HEADER) - 4; -*/ - tmf->vl = SWAP_BYTES(tmf->vl); - - return smctr_trc_send_packet(dev, fcb, MAC_QUEUE); -} - -static int smctr_send_rpt_state(struct net_device *dev, MAC_HEADER *rmf, - __u16 correlator) -{ - MAC_HEADER *tmf; - MAC_SUB_VECTOR *tsv; - FCBlock *fcb; - - if((fcb = smctr_get_tx_fcb(dev, MAC_QUEUE, sizeof(MAC_HEADER) - + S_CORRELATOR + S_RING_STATION_VERSION_NUMBER - + S_RING_STATION_STATUS + S_STATION_IDENTIFER)) - == (FCBlock *)(-1L)) - { - return 0; - } - - tmf = (MAC_HEADER *)fcb->bdb_ptr->data_block_ptr; - tmf->vc = RPT_STATE; - tmf->dc_sc = (rmf->dc_sc & SC_MASK) << 4; - tmf->vl = 4; - - smctr_make_8025_hdr(dev, rmf, tmf, AC_FC_RPT_STATE); - - tsv = (MAC_SUB_VECTOR *)((__u32)tmf + sizeof(MAC_HEADER)); - smctr_make_corr(dev, tsv, correlator); - - tmf->vl += tsv->svl; - tsv = (MAC_SUB_VECTOR *)((__u32)tsv + tsv->svl); - smctr_make_ring_station_version(dev, tsv); - - tmf->vl += tsv->svl; - tsv = (MAC_SUB_VECTOR *)((__u32)tsv + tsv->svl); - smctr_make_ring_station_status(dev, tsv); - - tmf->vl += tsv->svl; - tsv = (MAC_SUB_VECTOR *)((__u32)tsv + tsv->svl); - smctr_make_station_id(dev, tsv); - - tmf->vl += tsv->svl; - - /* Subtract out MVID and MVL which is - * include in both vl and MAC_HEADER - */ -/* fcb->frame_length = tmf->vl + sizeof(MAC_HEADER) - 4; - fcb->bdb_ptr->buffer_length = tmf->vl + sizeof(MAC_HEADER) - 4; -*/ - tmf->vl = SWAP_BYTES(tmf->vl); - - return smctr_trc_send_packet(dev, fcb, MAC_QUEUE); -} - -static int smctr_send_rpt_tx_forward(struct net_device *dev, - MAC_HEADER *rmf, __u16 tx_fstatus) -{ - MAC_HEADER *tmf; - MAC_SUB_VECTOR *tsv; - FCBlock *fcb; - - if((fcb = smctr_get_tx_fcb(dev, MAC_QUEUE, sizeof(MAC_HEADER) - + S_TRANSMIT_STATUS_CODE)) == (FCBlock *)(-1L)) - { - return 0; - } - - tmf = (MAC_HEADER *)fcb->bdb_ptr->data_block_ptr; - tmf->vc = RPT_TX_FORWARD; - tmf->dc_sc = (rmf->dc_sc & SC_MASK) << 4; - tmf->vl = 4; - - smctr_make_8025_hdr(dev, rmf, tmf, AC_FC_RPT_TX_FORWARD); - - tsv = (MAC_SUB_VECTOR *)((__u32)tmf + sizeof(MAC_HEADER)); - smctr_make_tx_status_code(dev, tsv, tx_fstatus); - - tmf->vl += tsv->svl; - - /* Subtract out MVID and MVL which is - * include in both vl and MAC_HEADER - */ -/* fcb->frame_length = tmf->vl + sizeof(MAC_HEADER) - 4; - fcb->bdb_ptr->buffer_length = tmf->vl + sizeof(MAC_HEADER) - 4; -*/ - tmf->vl = SWAP_BYTES(tmf->vl); - - return smctr_trc_send_packet(dev, fcb, MAC_QUEUE); -} - -static int smctr_send_rsp(struct net_device *dev, MAC_HEADER *rmf, - __u16 rcode, __u16 correlator) -{ - MAC_HEADER *tmf; - MAC_SUB_VECTOR *tsv; - FCBlock *fcb; - - if((fcb = smctr_get_tx_fcb(dev, MAC_QUEUE, sizeof(MAC_HEADER) - + S_CORRELATOR + S_RESPONSE_CODE)) == (FCBlock *)(-1L)) - { - return 0; - } - - tmf = (MAC_HEADER *)fcb->bdb_ptr->data_block_ptr; - tmf->vc = RSP; - tmf->dc_sc = (rmf->dc_sc & SC_MASK) << 4; - tmf->vl = 4; - - smctr_make_8025_hdr(dev, rmf, tmf, AC_FC_RSP); - - tsv = (MAC_SUB_VECTOR *)((__u32)tmf + sizeof(MAC_HEADER)); - smctr_make_corr(dev, tsv, correlator); - - return 0; -} - -static int smctr_send_rq_init(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - MAC_HEADER *tmf; - MAC_SUB_VECTOR *tsv; - FCBlock *fcb; - unsigned int i, count = 0; - __u16 fstatus; - int err; - - do { - if(((fcb = smctr_get_tx_fcb(dev, MAC_QUEUE, sizeof(MAC_HEADER) - + S_PRODUCT_INSTANCE_ID + S_UPSTREAM_NEIGHBOR_ADDRESS - + S_RING_STATION_VERSION_NUMBER + S_ADDRESS_MODIFER)) - == (FCBlock *)(-1L))) - { - return 0; - } - - tmf = (MAC_HEADER *)fcb->bdb_ptr->data_block_ptr; - tmf->vc = RQ_INIT; - tmf->dc_sc = DC_RPS | SC_RS; - tmf->vl = 4; - - smctr_make_8025_hdr(dev, NULL, tmf, AC_FC_RQ_INIT); - - tsv = (MAC_SUB_VECTOR *)((__u32)tmf + sizeof(MAC_HEADER)); - smctr_make_product_id(dev, tsv); - - tmf->vl += tsv->svl; - tsv = (MAC_SUB_VECTOR *)((__u32)tsv + tsv->svl); - smctr_make_upstream_neighbor_addr(dev, tsv); - - tmf->vl += tsv->svl; - tsv = (MAC_SUB_VECTOR *)((__u32)tsv + tsv->svl); - smctr_make_ring_station_version(dev, tsv); - - tmf->vl += tsv->svl; - tsv = (MAC_SUB_VECTOR *)((__u32)tsv + tsv->svl); - smctr_make_addr_mod(dev, tsv); - - tmf->vl += tsv->svl; - - /* Subtract out MVID and MVL which is - * include in both vl and MAC_HEADER - */ -/* fcb->frame_length = tmf->vl + sizeof(MAC_HEADER) - 4; - fcb->bdb_ptr->buffer_length = tmf->vl + sizeof(MAC_HEADER) - 4; -*/ - tmf->vl = SWAP_BYTES(tmf->vl); - - if((err = smctr_trc_send_packet(dev, fcb, MAC_QUEUE))) - return err; - - /* Wait for Transmit to Complete */ - for(i = 0; i < 10000; i++) - { - if(fcb->frame_status & FCB_COMMAND_DONE) - break; - mdelay(1); - } - - /* Check if GOOD frame Tx'ed */ - fstatus = fcb->frame_status; - - if(!(fstatus & FCB_COMMAND_DONE)) - return HARDWARE_FAILED; - - if(!(fstatus & FCB_TX_STATUS_E)) - count++; - - /* De-allocated Tx FCB and Frame Buffer - * The FCB must be de-allocated manually if executing with - * interrupts disabled, other wise the ISR (LM_Service_Events) - * will de-allocate it when the interrupt occurs. - */ - tp->tx_queue_status[MAC_QUEUE] = NOT_TRANSMITING; - smctr_update_tx_chain(dev, fcb, MAC_QUEUE); - } while(count < 4 && ((fstatus & FCB_TX_AC_BITS) ^ FCB_TX_AC_BITS)); - - return smctr_join_complete_state(dev); -} - -static int smctr_send_tx_forward(struct net_device *dev, MAC_HEADER *rmf, - __u16 *tx_fstatus) -{ - struct net_local *tp = netdev_priv(dev); - FCBlock *fcb; - unsigned int i; - int err; - - /* Check if this is the END POINT of the Transmit Forward Chain. */ - if(rmf->vl <= 18) - return 0; - - /* Allocate Transmit FCB only by requesting 0 bytes - * of data buffer. - */ - if((fcb = smctr_get_tx_fcb(dev, MAC_QUEUE, 0)) == (FCBlock *)(-1L)) - return 0; - - /* Set pointer to Transmit Frame Buffer to the data - * portion of the received TX Forward frame, making - * sure to skip over the Vector Code (vc) and Vector - * length (vl). - */ - fcb->bdb_ptr->trc_data_block_ptr = TRC_POINTER((__u32)rmf - + sizeof(MAC_HEADER) + 2); - fcb->bdb_ptr->data_block_ptr = (__u16 *)((__u32)rmf - + sizeof(MAC_HEADER) + 2); - - fcb->frame_length = rmf->vl - 4 - 2; - fcb->bdb_ptr->buffer_length = rmf->vl - 4 - 2; - - if((err = smctr_trc_send_packet(dev, fcb, MAC_QUEUE))) - return err; - - /* Wait for Transmit to Complete */ - for(i = 0; i < 10000; i++) - { - if(fcb->frame_status & FCB_COMMAND_DONE) - break; - mdelay(1); - } - - /* Check if GOOD frame Tx'ed */ - if(!(fcb->frame_status & FCB_COMMAND_DONE)) - { - if((err = smctr_issue_resume_tx_fcb_cmd(dev, MAC_QUEUE))) - return err; - - for(i = 0; i < 10000; i++) - { - if(fcb->frame_status & FCB_COMMAND_DONE) - break; - mdelay(1); - } - - if(!(fcb->frame_status & FCB_COMMAND_DONE)) - return HARDWARE_FAILED; - } - - *tx_fstatus = fcb->frame_status; - - return A_FRAME_WAS_FORWARDED; -} - -static int smctr_set_auth_access_pri(struct net_device *dev, - MAC_SUB_VECTOR *rsv) -{ - struct net_local *tp = netdev_priv(dev); - - if(rsv->svl != S_AUTHORIZED_ACCESS_PRIORITY) - return E_SUB_VECTOR_LENGTH_ERROR; - - tp->authorized_access_priority = (rsv->svv[0] << 8 | rsv->svv[1]); - - return POSITIVE_ACK; -} - -static int smctr_set_auth_funct_class(struct net_device *dev, - MAC_SUB_VECTOR *rsv) -{ - struct net_local *tp = netdev_priv(dev); - - if(rsv->svl != S_AUTHORIZED_FUNCTION_CLASS) - return E_SUB_VECTOR_LENGTH_ERROR; - - tp->authorized_function_classes = (rsv->svv[0] << 8 | rsv->svv[1]); - - return POSITIVE_ACK; -} - -static int smctr_set_corr(struct net_device *dev, MAC_SUB_VECTOR *rsv, - __u16 *correlator) -{ - if(rsv->svl != S_CORRELATOR) - return E_SUB_VECTOR_LENGTH_ERROR; - - *correlator = (rsv->svv[0] << 8 | rsv->svv[1]); - - return POSITIVE_ACK; -} - -static int smctr_set_error_timer_value(struct net_device *dev, - MAC_SUB_VECTOR *rsv) -{ - __u16 err_tval; - int err; - - if(rsv->svl != S_ERROR_TIMER_VALUE) - return E_SUB_VECTOR_LENGTH_ERROR; - - err_tval = (rsv->svv[0] << 8 | rsv->svv[1])*10; - - smctr_issue_write_word_cmd(dev, RW_TER_THRESHOLD, &err_tval); - - if((err = smctr_wait_cmd(dev))) - return err; - - return POSITIVE_ACK; -} - -static int smctr_set_frame_forward(struct net_device *dev, - MAC_SUB_VECTOR *rsv, __u8 dc_sc) -{ - if((rsv->svl < 2) || (rsv->svl > S_FRAME_FORWARD)) - return E_SUB_VECTOR_LENGTH_ERROR; - - if((dc_sc & DC_MASK) != DC_CRS) - { - if(rsv->svl >= 2 && rsv->svl < 20) - return E_TRANSMIT_FORWARD_INVALID; - - if((rsv->svv[0] != 0) || (rsv->svv[1] != 0)) - return E_TRANSMIT_FORWARD_INVALID; - } - - return POSITIVE_ACK; -} - -static int smctr_set_local_ring_num(struct net_device *dev, - MAC_SUB_VECTOR *rsv) -{ - struct net_local *tp = netdev_priv(dev); - - if(rsv->svl != S_LOCAL_RING_NUMBER) - return E_SUB_VECTOR_LENGTH_ERROR; - - if(tp->ptr_local_ring_num) - *(__u16 *)(tp->ptr_local_ring_num) - = (rsv->svv[0] << 8 | rsv->svv[1]); - - return POSITIVE_ACK; -} - -static unsigned short smctr_set_ctrl_attention(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - int ioaddr = dev->base_addr; - - if(tp->bic_type == BIC_585_CHIP) - outb((tp->trc_mask | HWR_CA), ioaddr + HWR); - else - { - outb((tp->trc_mask | CSR_CA), ioaddr + CSR); - outb(tp->trc_mask, ioaddr + CSR); - } - - return 0; -} - -static void smctr_set_multicast_list(struct net_device *dev) -{ - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_set_multicast_list\n", dev->name); -} - -static int smctr_set_page(struct net_device *dev, __u8 *buf) -{ - struct net_local *tp = netdev_priv(dev); - __u8 amask; - __u32 tptr; - - tptr = (__u32)buf - (__u32)tp->ram_access; - amask = (__u8)((tptr & PR_PAGE_MASK) >> 8); - outb(amask, dev->base_addr + PR); - - return 0; -} - -static int smctr_set_phy_drop(struct net_device *dev, MAC_SUB_VECTOR *rsv) -{ - int err; - - if(rsv->svl != S_PHYSICAL_DROP) - return E_SUB_VECTOR_LENGTH_ERROR; - - smctr_issue_write_byte_cmd(dev, RW_PHYSICAL_DROP_NUMBER, &rsv->svv[0]); - if((err = smctr_wait_cmd(dev))) - return err; - - return POSITIVE_ACK; -} - -/* Reset the ring speed to the opposite of what it was. This auto-pilot - * mode requires a complete reset and re-init of the adapter. - */ -static int smctr_set_ring_speed(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - int err; - - if(tp->media_type == MEDIA_UTP_16) - tp->media_type = MEDIA_UTP_4; - else - tp->media_type = MEDIA_UTP_16; - - smctr_enable_16bit(dev); - - /* Re-Initialize adapter's internal registers */ - smctr_reset_adapter(dev); - - if((err = smctr_init_card_real(dev))) - return err; - - smctr_enable_bic_int(dev); - - if((err = smctr_issue_enable_int_cmd(dev, TRC_INTERRUPT_ENABLE_MASK))) - return err; - - smctr_disable_16bit(dev); - - return 0; -} - -static int smctr_set_rx_look_ahead(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - __u16 sword, rword; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_set_rx_look_ahead_flag\n", dev->name); - - tp->adapter_flags &= ~(FORCED_16BIT_MODE); - tp->adapter_flags |= RX_VALID_LOOKAHEAD; - - if(tp->adapter_bus == BUS_ISA16_TYPE) - { - sword = *((__u16 *)(tp->ram_access)); - *((__u16 *)(tp->ram_access)) = 0x1234; - - smctr_disable_16bit(dev); - rword = *((__u16 *)(tp->ram_access)); - smctr_enable_16bit(dev); - - if(rword != 0x1234) - tp->adapter_flags |= FORCED_16BIT_MODE; - - *((__u16 *)(tp->ram_access)) = sword; - } - - return 0; -} - -static int smctr_set_trc_reset(int ioaddr) -{ - __u8 r; - - r = inb(ioaddr + MSR); - outb(MSR_RST | r, ioaddr + MSR); - - return 0; -} - -/* - * This function can be called if the adapter is busy or not. - */ -static int smctr_setup_single_cmd(struct net_device *dev, - __u16 command, __u16 subcommand) -{ - struct net_local *tp = netdev_priv(dev); - unsigned int err; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_setup_single_cmd\n", dev->name); - - if((err = smctr_wait_while_cbusy(dev))) - return err; - - if((err = (unsigned int)smctr_wait_cmd(dev))) - return err; - - tp->acb_head->cmd_done_status = 0; - tp->acb_head->cmd = command; - tp->acb_head->subcmd = subcommand; - - err = smctr_issue_resume_acb_cmd(dev); - - return err; -} - -/* - * This function can not be called with the adapter busy. - */ -static int smctr_setup_single_cmd_w_data(struct net_device *dev, - __u16 command, __u16 subcommand) -{ - struct net_local *tp = netdev_priv(dev); - - tp->acb_head->cmd_done_status = ACB_COMMAND_NOT_DONE; - tp->acb_head->cmd = command; - tp->acb_head->subcmd = subcommand; - tp->acb_head->data_offset_lo - = (__u16)TRC_POINTER(tp->misc_command_data); - - return smctr_issue_resume_acb_cmd(dev); -} - -static char *smctr_malloc(struct net_device *dev, __u16 size) -{ - struct net_local *tp = netdev_priv(dev); - char *m; - - m = (char *)(tp->ram_access + tp->sh_mem_used); - tp->sh_mem_used += (__u32)size; - - return m; -} - -static int smctr_status_chg(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_status_chg\n", dev->name); - - switch(tp->status) - { - case OPEN: - break; - - case CLOSED: - break; - - /* Interrupt driven open() completion. XXX */ - case INITIALIZED: - tp->group_address_0 = 0; - tp->group_address[0] = 0; - tp->group_address[1] = 0; - tp->functional_address_0 = 0; - tp->functional_address[0] = 0; - tp->functional_address[1] = 0; - smctr_open_tr(dev); - break; - - default: - printk(KERN_INFO "%s: status change unknown %x\n", - dev->name, tp->status); - break; - } - - return 0; -} - -static int smctr_trc_send_packet(struct net_device *dev, FCBlock *fcb, - __u16 queue) -{ - struct net_local *tp = netdev_priv(dev); - int err = 0; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_trc_send_packet\n", dev->name); - - fcb->info = FCB_CHAIN_END | FCB_ENABLE_TFS; - if(tp->num_tx_fcbs[queue] != 1) - fcb->back_ptr->info = FCB_INTERRUPT_ENABLE | FCB_ENABLE_TFS; - - if(tp->tx_queue_status[queue] == NOT_TRANSMITING) - { - tp->tx_queue_status[queue] = TRANSMITING; - err = smctr_issue_resume_tx_fcb_cmd(dev, queue); - } - - return err; -} - -static __u16 smctr_tx_complete(struct net_device *dev, __u16 queue) -{ - struct net_local *tp = netdev_priv(dev); - __u16 status, err = 0; - int cstatus; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_tx_complete\n", dev->name); - - while((status = tp->tx_fcb_end[queue]->frame_status) != SUCCESS) - { - if(status & 0x7e00 ) - { - err = HARDWARE_FAILED; - break; - } - - if((err = smctr_update_tx_chain(dev, tp->tx_fcb_end[queue], - queue)) != SUCCESS) - break; - - smctr_disable_16bit(dev); - - if(tp->mode_bits & UMAC) - { - if(!(status & (FCB_TX_STATUS_AR1 | FCB_TX_STATUS_AR2))) - cstatus = NO_SUCH_DESTINATION; - else - { - if(!(status & (FCB_TX_STATUS_CR1 | FCB_TX_STATUS_CR2))) - cstatus = DEST_OUT_OF_RESOURCES; - else - { - if(status & FCB_TX_STATUS_E) - cstatus = MAX_COLLISIONS; - else - cstatus = SUCCESS; - } - } - } - else - cstatus = SUCCESS; - - if(queue == BUG_QUEUE) - err = SUCCESS; - - smctr_enable_16bit(dev); - if(err != SUCCESS) - break; - } - - return err; -} - -static unsigned short smctr_tx_move_frame(struct net_device *dev, - struct sk_buff *skb, __u8 *pbuff, unsigned int bytes) -{ - struct net_local *tp = netdev_priv(dev); - unsigned int ram_usable; - __u32 flen, len, offset = 0; - __u8 *frag, *page; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_tx_move_frame\n", dev->name); - - ram_usable = ((unsigned int)tp->ram_usable) << 10; - frag = skb->data; - flen = skb->len; - - while(flen > 0 && bytes > 0) - { - smctr_set_page(dev, pbuff); - - offset = SMC_PAGE_OFFSET(pbuff); - - if(offset + flen > ram_usable) - len = ram_usable - offset; - else - len = flen; - - if(len > bytes) - len = bytes; - - page = (char *) (offset + tp->ram_access); - memcpy(page, frag, len); - - flen -=len; - bytes -= len; - frag += len; - pbuff += len; - } - - return 0; -} - -/* Update the error statistic counters for this adapter. */ -static int smctr_update_err_stats(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - struct tr_statistics *tstat = &tp->MacStat; - - if(tstat->internal_errors) - tstat->internal_errors - += *(tp->misc_command_data + 0) & 0x00ff; - - if(tstat->line_errors) - tstat->line_errors += *(tp->misc_command_data + 0) >> 8; - - if(tstat->A_C_errors) - tstat->A_C_errors += *(tp->misc_command_data + 1) & 0x00ff; - - if(tstat->burst_errors) - tstat->burst_errors += *(tp->misc_command_data + 1) >> 8; - - if(tstat->abort_delimiters) - tstat->abort_delimiters += *(tp->misc_command_data + 2) >> 8; - - if(tstat->recv_congest_count) - tstat->recv_congest_count - += *(tp->misc_command_data + 3) & 0x00ff; - - if(tstat->lost_frames) - tstat->lost_frames - += *(tp->misc_command_data + 3) >> 8; - - if(tstat->frequency_errors) - tstat->frequency_errors += *(tp->misc_command_data + 4) & 0x00ff; - - if(tstat->frame_copied_errors) - tstat->frame_copied_errors - += *(tp->misc_command_data + 4) >> 8; - - if(tstat->token_errors) - tstat->token_errors += *(tp->misc_command_data + 5) >> 8; - - return 0; -} - -static int smctr_update_rx_chain(struct net_device *dev, __u16 queue) -{ - struct net_local *tp = netdev_priv(dev); - FCBlock *fcb; - BDBlock *bdb; - __u16 size, len; - - fcb = tp->rx_fcb_curr[queue]; - len = fcb->frame_length; - - fcb->frame_status = 0; - fcb->info = FCB_CHAIN_END; - fcb->back_ptr->info = FCB_WARNING; - - tp->rx_fcb_curr[queue] = tp->rx_fcb_curr[queue]->next_ptr; - - /* update RX BDBs */ - size = (len >> RX_BDB_SIZE_SHIFT); - if(len & RX_DATA_BUFFER_SIZE_MASK) - size += sizeof(BDBlock); - size &= (~RX_BDB_SIZE_MASK); - - /* check if wrap around */ - bdb = (BDBlock *)((__u32)(tp->rx_bdb_curr[queue]) + (__u32)(size)); - if((__u32)bdb >= (__u32)tp->rx_bdb_end[queue]) - { - bdb = (BDBlock *)((__u32)(tp->rx_bdb_head[queue]) - + (__u32)(bdb) - (__u32)(tp->rx_bdb_end[queue])); - } - - bdb->back_ptr->info = BDB_CHAIN_END; - tp->rx_bdb_curr[queue]->back_ptr->info = BDB_NOT_CHAIN_END; - tp->rx_bdb_curr[queue] = bdb; - - return 0; -} - -static int smctr_update_tx_chain(struct net_device *dev, FCBlock *fcb, - __u16 queue) -{ - struct net_local *tp = netdev_priv(dev); - - if(smctr_debug > 20) - printk(KERN_DEBUG "smctr_update_tx_chain\n"); - - if(tp->num_tx_fcbs_used[queue] <= 0) - return HARDWARE_FAILED; - else - { - if(tp->tx_buff_used[queue] < fcb->memory_alloc) - { - tp->tx_buff_used[queue] = 0; - return HARDWARE_FAILED; - } - - tp->tx_buff_used[queue] -= fcb->memory_alloc; - - /* if all transmit buffer are cleared - * need to set the tx_buff_curr[] to tx_buff_head[] - * otherwise, tx buffer will be segregate and cannot - * accommodate and buffer greater than (curr - head) and - * (end - curr) since we do not allow wrap around allocation. - */ - if(tp->tx_buff_used[queue] == 0) - tp->tx_buff_curr[queue] = tp->tx_buff_head[queue]; - - tp->num_tx_fcbs_used[queue]--; - fcb->frame_status = 0; - tp->tx_fcb_end[queue] = fcb->next_ptr; - netif_wake_queue(dev); - return 0; - } -} - -static int smctr_wait_cmd(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - unsigned int loop_count = 0x20000; - - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_wait_cmd\n", dev->name); - - while(loop_count) - { - if(tp->acb_head->cmd_done_status & ACB_COMMAND_DONE) - break; - udelay(1); - loop_count--; - } - - if(loop_count == 0) - return HARDWARE_FAILED; - - if(tp->acb_head->cmd_done_status & 0xff) - return HARDWARE_FAILED; - - return 0; -} - -static int smctr_wait_while_cbusy(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - unsigned int timeout = 0x20000; - int ioaddr = dev->base_addr; - __u8 r; - - if(tp->bic_type == BIC_585_CHIP) - { - while(timeout) - { - r = inb(ioaddr + HWR); - if((r & HWR_CBUSY) == 0) - break; - timeout--; - } - } - else - { - while(timeout) - { - r = inb(ioaddr + CSR); - if((r & CSR_CBUSY) == 0) - break; - timeout--; - } - } - - if(timeout) - return 0; - else - return HARDWARE_FAILED; -} - -#ifdef MODULE - -static struct net_device* dev_smctr[SMCTR_MAX_ADAPTERS]; -static int io[SMCTR_MAX_ADAPTERS]; -static int irq[SMCTR_MAX_ADAPTERS]; - -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE("tr_smctr.bin"); - -module_param_array(io, int, NULL, 0); -module_param_array(irq, int, NULL, 0); -module_param(ringspeed, int, 0); - -static struct net_device * __init setup_card(int n) -{ - struct net_device *dev = alloc_trdev(sizeof(struct net_local)); - int err; - - if (!dev) - return ERR_PTR(-ENOMEM); - - dev->irq = irq[n]; - err = smctr_probe1(dev, io[n]); - if (err) - goto out; - - err = register_netdev(dev); - if (err) - goto out1; - return dev; - out1: -#ifdef CONFIG_MCA_LEGACY - { struct net_local *tp = netdev_priv(dev); - if (tp->slot_num) - mca_mark_as_unused(tp->slot_num); - } -#endif - release_region(dev->base_addr, SMCTR_IO_EXTENT); - free_irq(dev->irq, dev); -out: - free_netdev(dev); - return ERR_PTR(err); -} - -int __init init_module(void) -{ - int i, found = 0; - struct net_device *dev; - - for(i = 0; i < SMCTR_MAX_ADAPTERS; i++) { - dev = io[0]? setup_card(i) : smctr_probe(-1); - if (!IS_ERR(dev)) { - ++found; - dev_smctr[i] = dev; - } - } - - return found ? 0 : -ENODEV; -} - -void __exit cleanup_module(void) -{ - int i; - - for(i = 0; i < SMCTR_MAX_ADAPTERS; i++) { - struct net_device *dev = dev_smctr[i]; - - if (dev) { - - unregister_netdev(dev); -#ifdef CONFIG_MCA_LEGACY - { struct net_local *tp = netdev_priv(dev); - if (tp->slot_num) - mca_mark_as_unused(tp->slot_num); - } -#endif - release_region(dev->base_addr, SMCTR_IO_EXTENT); - if (dev->irq) - free_irq(dev->irq, dev); - - free_netdev(dev); - } - } -} -#endif /* MODULE */ diff --git a/trunk/drivers/net/tokenring/smctr.h b/trunk/drivers/net/tokenring/smctr.h deleted file mode 100644 index 6e5700ab4fc3..000000000000 --- a/trunk/drivers/net/tokenring/smctr.h +++ /dev/null @@ -1,1585 +0,0 @@ -/* smctr.h: SMC Token Ring driver header for Linux - * - * Authors: - * - Jay Schulist - */ - -#ifndef __LINUX_SMCTR_H -#define __LINUX_SMCTR_H - -#ifdef __KERNEL__ - -#define MAX_TX_QUEUE 10 - -#define SMC_HEADER_SIZE 14 - -#define SMC_PAGE_OFFSET(X) (((unsigned long)(X) - tp->ram_access) & tp->page_offset_mask) - -#define INIT 0x0D -#define RQ_ATTCH 0x10 -#define RQ_STATE 0x0F -#define RQ_ADDR 0x0E -#define CHG_PARM 0x0C -#define RSP 0x00 -#define TX_FORWARD 0x09 - -#define AC_FC_DAT ((3<<13) | 1) -#define DAT 0x07 - -#define RPT_NEW_MON 0x25 -#define RPT_SUA_CHG 0x26 -#define RPT_ACTIVE_ERR 0x28 -#define RPT_NN_INCMP 0x27 -#define RPT_ERROR 0x29 - -#define RQ_INIT 0x20 -#define RPT_ATTCH 0x24 -#define RPT_STATE 0x23 -#define RPT_ADDR 0x22 - -#define POSITIVE_ACK 0x0001 -#define A_FRAME_WAS_FORWARDED 0x8888 - -#define GROUP_ADDRESS 0x2B -#define PHYSICAL_DROP 0x0B -#define AUTHORIZED_ACCESS_PRIORITY 0x07 -#define AUTHORIZED_FUNCTION_CLASS 0x06 -#define FUNCTIONAL_ADDRESS 0x2C -#define RING_STATION_STATUS 0x29 -#define TRANSMIT_STATUS_CODE 0x2A -#define IBM_PASS_SOURCE_ADDR 0x01 -#define AC_FC_RPT_TX_FORWARD ((0<<13) | 0) -#define AC_FC_RPT_STATE ((0<<13) | 0) -#define AC_FC_RPT_ADDR ((0<<13) | 0) -#define CORRELATOR 0x09 - -#define POSITIVE_ACK 0x0001 /* */ -#define E_MAC_DATA_INCOMPLETE 0x8001 /* not used */ -#define E_VECTOR_LENGTH_ERROR 0x8002 /* */ -#define E_UNRECOGNIZED_VECTOR_ID 0x8003 /* */ -#define E_INAPPROPRIATE_SOURCE_CLASS 0x8004 /* */ -#define E_SUB_VECTOR_LENGTH_ERROR 0x8005 /* */ -#define E_TRANSMIT_FORWARD_INVALID 0x8006 /* def. by IBM */ -#define E_MISSING_SUB_VECTOR 0x8007 /* */ -#define E_SUB_VECTOR_UNKNOWN 0x8008 /* */ -#define E_MAC_HEADER_TOO_LONG 0x8009 /* */ -#define E_FUNCTION_DISABLED 0x800A /* not used */ - -#define A_FRAME_WAS_FORWARDED 0x8888 /* used by send_TX_FORWARD */ - -#define UPSTREAM_NEIGHBOR_ADDRESS 0x02 -#define LOCAL_RING_NUMBER 0x03 -#define ASSIGN_PHYSICAL_DROP 0x04 -#define ERROR_TIMER_VALUE 0x05 -#define AUTHORIZED_FUNCTION_CLASS 0x06 -#define AUTHORIZED_ACCESS_PRIORITY 0x07 -#define CORRELATOR 0x09 -#define PHYSICAL_DROP 0x0B -#define RESPONSE_CODE 0x20 -#define ADDRESS_MODIFER 0x21 -#define PRODUCT_INSTANCE_ID 0x22 -#define RING_STATION_VERSION_NUMBER 0x23 -#define WRAP_DATA 0x26 -#define FRAME_FORWARD 0x27 -#define STATION_IDENTIFER 0x28 -#define RING_STATION_STATUS 0x29 -#define TRANSMIT_STATUS_CODE 0x2A -#define GROUP_ADDRESS 0x2B -#define FUNCTIONAL_ADDRESS 0x2C - -#define F_NO_SUB_VECTORS_FOUND 0x0000 -#define F_UPSTREAM_NEIGHBOR_ADDRESS 0x0001 -#define F_LOCAL_RING_NUMBER 0x0002 -#define F_ASSIGN_PHYSICAL_DROP 0x0004 -#define F_ERROR_TIMER_VALUE 0x0008 -#define F_AUTHORIZED_FUNCTION_CLASS 0x0010 -#define F_AUTHORIZED_ACCESS_PRIORITY 0x0020 -#define F_CORRELATOR 0x0040 -#define F_PHYSICAL_DROP 0x0080 -#define F_RESPONSE_CODE 0x0100 -#define F_PRODUCT_INSTANCE_ID 0x0200 -#define F_RING_STATION_VERSION_NUMBER 0x0400 -#define F_STATION_IDENTIFER 0x0800 -#define F_RING_STATION_STATUS 0x1000 -#define F_GROUP_ADDRESS 0x2000 -#define F_FUNCTIONAL_ADDRESS 0x4000 -#define F_FRAME_FORWARD 0x8000 - -#define R_INIT 0x00 -#define R_RQ_ATTCH_STATE_ADDR 0x00 -#define R_CHG_PARM 0x00 -#define R_TX_FORWARD F_FRAME_FORWARD - - -#define UPSTREAM_NEIGHBOR_ADDRESS 0x02 -#define ADDRESS_MODIFER 0x21 -#define RING_STATION_VERSION_NUMBER 0x23 -#define PRODUCT_INSTANCE_ID 0x22 - -#define RPT_TX_FORWARD 0x2A - -#define AC_FC_INIT (3<<13) | 0 /* */ -#define AC_FC_RQ_INIT ((3<<13) | 0) /* */ -#define AC_FC_RQ_ATTCH (3<<13) | 0 /* DC = SC of rx frame */ -#define AC_FC_RQ_STATE (3<<13) | 0 /* DC = SC of rx frame */ -#define AC_FC_RQ_ADDR (3<<13) | 0 /* DC = SC of rx frame */ -#define AC_FC_CHG_PARM (3<<13) | 0 /* */ -#define AC_FC_RSP (0<<13) | 0 /* DC = SC of rx frame */ -#define AC_FC_RPT_ATTCH (0<<13) | 0 - -#define S_UPSTREAM_NEIGHBOR_ADDRESS 6 + 2 -#define S_LOCAL_RING_NUMBER 2 + 2 -#define S_ASSIGN_PHYSICAL_DROP 4 + 2 -#define S_ERROR_TIMER_VALUE 2 + 2 -#define S_AUTHORIZED_FUNCTION_CLASS 2 + 2 -#define S_AUTHORIZED_ACCESS_PRIORITY 2 + 2 -#define S_CORRELATOR 2 + 2 -#define S_PHYSICAL_DROP 4 + 2 -#define S_RESPONSE_CODE 4 + 2 -#define S_ADDRESS_MODIFER 2 + 2 -#define S_PRODUCT_INSTANCE_ID 18 + 2 -#define S_RING_STATION_VERSION_NUMBER 10 + 2 -#define S_STATION_IDENTIFER 6 + 2 -#define S_RING_STATION_STATUS 6 + 2 -#define S_GROUP_ADDRESS 4 + 2 -#define S_FUNCTIONAL_ADDRESS 4 + 2 -#define S_FRAME_FORWARD 252 + 2 -#define S_TRANSMIT_STATUS_CODE 2 + 2 - -#define ISB_IMC_RES0 0x0000 /* */ -#define ISB_IMC_MAC_TYPE_3 0x0001 /* MAC_ARC_INDICATE */ -#define ISB_IMC_MAC_ERROR_COUNTERS 0x0002 /* */ -#define ISB_IMC_RES1 0x0003 /* */ -#define ISB_IMC_MAC_TYPE_2 0x0004 /* QUE_MAC_INDICATE */ -#define ISB_IMC_TX_FRAME 0x0005 /* */ -#define ISB_IMC_END_OF_TX_QUEUE 0x0006 /* */ -#define ISB_IMC_NON_MAC_RX_RESOURCE 0x0007 /* */ -#define ISB_IMC_MAC_RX_RESOURCE 0x0008 /* */ -#define ISB_IMC_NON_MAC_RX_FRAME 0x0009 /* */ -#define ISB_IMC_MAC_RX_FRAME 0x000A /* */ -#define ISB_IMC_TRC_FIFO_STATUS 0x000B /* */ -#define ISB_IMC_COMMAND_STATUS 0x000C /* */ -#define ISB_IMC_MAC_TYPE_1 0x000D /* Self Removed */ -#define ISB_IMC_TRC_INTRNL_TST_STATUS 0x000E /* */ -#define ISB_IMC_RES2 0x000F /* */ - -#define NON_MAC_RX_RESOURCE_BW 0x10 /* shifted right 8 bits */ -#define NON_MAC_RX_RESOURCE_FW 0x20 /* shifted right 8 bits */ -#define NON_MAC_RX_RESOURCE_BE 0x40 /* shifted right 8 bits */ -#define NON_MAC_RX_RESOURCE_FE 0x80 /* shifted right 8 bits */ -#define RAW_NON_MAC_RX_RESOURCE_BW 0x1000 /* */ -#define RAW_NON_MAC_RX_RESOURCE_FW 0x2000 /* */ -#define RAW_NON_MAC_RX_RESOURCE_BE 0x4000 /* */ -#define RAW_NON_MAC_RX_RESOURCE_FE 0x8000 /* */ - -#define MAC_RX_RESOURCE_BW 0x10 /* shifted right 8 bits */ -#define MAC_RX_RESOURCE_FW 0x20 /* shifted right 8 bits */ -#define MAC_RX_RESOURCE_BE 0x40 /* shifted right 8 bits */ -#define MAC_RX_RESOURCE_FE 0x80 /* shifted right 8 bits */ -#define RAW_MAC_RX_RESOURCE_BW 0x1000 /* */ -#define RAW_MAC_RX_RESOURCE_FW 0x2000 /* */ -#define RAW_MAC_RX_RESOURCE_BE 0x4000 /* */ -#define RAW_MAC_RX_RESOURCE_FE 0x8000 /* */ - -#define TRC_FIFO_STATUS_TX_UNDERRUN 0x40 /* shifted right 8 bits */ -#define TRC_FIFO_STATUS_RX_OVERRUN 0x80 /* shifted right 8 bits */ -#define RAW_TRC_FIFO_STATUS_TX_UNDERRUN 0x4000 /* */ -#define RAW_TRC_FIFO_STATUS_RX_OVERRUN 0x8000 /* */ - -#define CSR_CLRTINT 0x08 - -#define MSB(X) ((__u8)((__u16) X >> 8)) -#define LSB(X) ((__u8)((__u16) X & 0xff)) - -#define AC_FC_LOBE_MEDIA_TEST ((3<<13) | 0) -#define S_WRAP_DATA 248 + 2 /* 500 + 2 */ -#define WRAP_DATA 0x26 -#define LOBE_MEDIA_TEST 0x08 - -/* Destination Class (dc) */ - -#define DC_MASK 0xF0 -#define DC_RS 0x00 -#define DC_CRS 0x40 -#define DC_RPS 0x50 -#define DC_REM 0x60 - -/* Source Classes (sc) */ - -#define SC_MASK 0x0F -#define SC_RS 0x00 -#define SC_CRS 0x04 -#define SC_RPS 0x05 -#define SC_REM 0x06 - -#define PR 0x11 -#define PR_PAGE_MASK 0x0C000 - -#define MICROCHANNEL 0x0008 -#define INTERFACE_CHIP 0x0010 -#define BOARD_16BIT 0x0040 -#define PAGED_RAM 0x0080 -#define WD8115TA (TOKEN_MEDIA | MICROCHANNEL | INTERFACE_CHIP | PAGED_RAM) -#define WD8115T (TOKEN_MEDIA | INTERFACE_CHIP | BOARD_16BIT | PAGED_RAM) - -#define BRD_ID_8316 0x50 - -#define r587_SER 0x001 -#define SER_DIN 0x80 -#define SER_DOUT 0x40 -#define SER_CLK 0x20 -#define SER_ECS 0x10 -#define SER_E806 0x08 -#define SER_PNP 0x04 -#define SER_BIO 0x02 -#define SER_16B 0x01 - -#define r587_IDR 0x004 -#define IDR_IRQ_MASK 0x0F0 -#define IDR_DCS_MASK 0x007 -#define IDR_RWS 0x008 - - -#define r587_BIO 0x003 -#define BIO_ENB 0x080 -#define BIO_MASK 0x03F - -#define r587_PCR 0x005 -#define PCR_RAMS 0x040 - - - -#define NUM_ADDR_BITS 8 - -#define ISA_MAX_ADDRESS 0x00ffffff - -#define SMCTR_MAX_ADAPTERS 7 - -#define MC_TABLE_ENTRIES 16 - -#define MAXFRAGMENTS 32 - -#define CHIP_REV_MASK 0x3000 - -#define MAX_TX_QS 8 -#define NUM_TX_QS_USED 3 - -#define MAX_RX_QS 2 -#define NUM_RX_QS_USED 2 - -#define INTEL_DATA_FORMAT 0x4000 -#define INTEL_ADDRESS_POINTER_FORMAT 0x8000 -#define PAGE_POINTER(X) ((((unsigned long)(X) - tp->ram_access) & tp->page_offset_mask) + tp->ram_access) -#define SWAP_WORDS(X) (((X & 0xFFFF) << 16) | (X >> 16)) - -#define INTERFACE_CHIP 0x0010 /* Soft Config Adapter */ -#define ADVANCED_FEATURES 0x0020 /* Adv. netw. interface features */ -#define BOARD_16BIT 0x0040 /* 16 bit capability */ -#define PAGED_RAM 0x0080 /* Adapter has paged RAM */ - -#define PAGED_ROM 0x0100 /* Adapter has paged ROM */ - -#define RAM_SIZE_UNKNOWN 0x0000 /* Unknown RAM size */ -#define RAM_SIZE_0K 0x0001 /* 0K RAM */ -#define RAM_SIZE_8K 0x0002 /* 8k RAM */ -#define RAM_SIZE_16K 0x0003 /* 16k RAM */ -#define RAM_SIZE_32K 0x0004 /* 32k RAM */ -#define RAM_SIZE_64K 0x0005 /* 64k RAM */ -#define RAM_SIZE_RESERVED_6 0x0006 /* Reserved RAM size */ -#define RAM_SIZE_RESERVED_7 0x0007 /* Reserved RAM size */ -#define RAM_SIZE_MASK 0x0007 /* Isolates RAM Size */ - -#define TOKEN_MEDIA 0x0005 - -#define BID_REG_0 0x00 -#define BID_REG_1 0x01 -#define BID_REG_2 0x02 -#define BID_REG_3 0x03 -#define BID_REG_4 0x04 -#define BID_REG_5 0x05 -#define BID_REG_6 0x06 -#define BID_REG_7 0x07 -#define BID_LAR_0 0x08 -#define BID_LAR_1 0x09 -#define BID_LAR_2 0x0A -#define BID_LAR_3 0x0B -#define BID_LAR_4 0x0C -#define BID_LAR_5 0x0D - -#define BID_BOARD_ID_BYTE 0x0E -#define BID_CHCKSM_BYTE 0x0F -#define BID_LAR_OFFSET 0x08 - -#define BID_MSZ_583_BIT 0x08 -#define BID_SIXTEEN_BIT_BIT 0x01 - -#define BID_BOARD_REV_MASK 0x1E - -#define BID_MEDIA_TYPE_BIT 0x01 -#define BID_SOFT_CONFIG_BIT 0x20 -#define BID_RAM_SIZE_BIT 0x40 -#define BID_BUS_TYPE_BIT 0x80 - -#define BID_CR 0x10 - -#define BID_TXP 0x04 /* Transmit Packet Command */ - -#define BID_TCR_DIFF 0x0D /* Transmit Configuration Register */ - -#define BID_TCR_VAL 0x18 /* Value to Test 8390 or 690 */ -#define BID_PS0 0x00 /* Register Page Select 0 */ -#define BID_PS1 0x40 /* Register Page Select 1 */ -#define BID_PS2 0x80 /* Register Page Select 2 */ -#define BID_PS_MASK 0x3F /* For Masking Off Page Select Bits */ - -#define BID_EEPROM_0 0x08 -#define BID_EEPROM_1 0x09 -#define BID_EEPROM_2 0x0A -#define BID_EEPROM_3 0x0B -#define BID_EEPROM_4 0x0C -#define BID_EEPROM_5 0x0D -#define BID_EEPROM_6 0x0E -#define BID_EEPROM_7 0x0F - -#define BID_OTHER_BIT 0x02 -#define BID_ICR_MASK 0x0C -#define BID_EAR_MASK 0x0F -#define BID_ENGR_PAGE 0x0A0 -#define BID_RLA 0x10 -#define BID_EA6 0x80 -#define BID_RECALL_DONE_MASK 0x10 -#define BID_BID_EEPROM_OVERRIDE 0xFFB0 -#define BID_EXTRA_EEPROM_OVERRIDE 0xFFD0 -#define BID_EEPROM_MEDIA_MASK 0x07 -#define BID_STARLAN_TYPE 0x00 -#define BID_ETHERNET_TYPE 0x01 -#define BID_TP_TYPE 0x02 -#define BID_EW_TYPE 0x03 -#define BID_TOKEN_RING_TYPE 0x04 -#define BID_UTP2_TYPE 0x05 -#define BID_EEPROM_IRQ_MASK 0x18 -#define BID_PRIMARY_IRQ 0x00 -#define BID_ALTERNATE_IRQ_1 0x08 -#define BID_ALTERNATE_IRQ_2 0x10 -#define BID_ALTERNATE_IRQ_3 0x18 -#define BID_EEPROM_RAM_SIZE_MASK 0xE0 -#define BID_EEPROM_RAM_SIZE_RES1 0x00 -#define BID_EEPROM_RAM_SIZE_RES2 0x20 -#define BID_EEPROM_RAM_SIZE_8K 0x40 -#define BID_EEPROM_RAM_SIZE_16K 0x60 -#define BID_EEPROM_RAM_SIZE_32K 0x80 -#define BID_EEPROM_RAM_SIZE_64K 0xA0 -#define BID_EEPROM_RAM_SIZE_RES3 0xC0 -#define BID_EEPROM_RAM_SIZE_RES4 0xE0 -#define BID_EEPROM_BUS_TYPE_MASK 0x07 -#define BID_EEPROM_BUS_TYPE_AT 0x00 -#define BID_EEPROM_BUS_TYPE_MCA 0x01 -#define BID_EEPROM_BUS_TYPE_EISA 0x02 -#define BID_EEPROM_BUS_TYPE_NEC 0x03 -#define BID_EEPROM_BUS_SIZE_MASK 0x18 -#define BID_EEPROM_BUS_SIZE_8BIT 0x00 -#define BID_EEPROM_BUS_SIZE_16BIT 0x08 -#define BID_EEPROM_BUS_SIZE_32BIT 0x10 -#define BID_EEPROM_BUS_SIZE_64BIT 0x18 -#define BID_EEPROM_BUS_MASTER 0x20 -#define BID_EEPROM_RAM_PAGING 0x40 -#define BID_EEPROM_ROM_PAGING 0x80 -#define BID_EEPROM_PAGING_MASK 0xC0 -#define BID_EEPROM_LOW_COST 0x08 -#define BID_EEPROM_IO_MAPPED 0x10 -#define BID_EEPROM_HMI 0x01 -#define BID_EEPROM_AUTO_MEDIA_DETECT 0x01 -#define BID_EEPROM_CHIP_REV_MASK 0x0C - -#define BID_EEPROM_LAN_ADDR 0x30 - -#define BID_EEPROM_MEDIA_OPTION 0x54 -#define BID_EEPROM_MEDIA_UTP 0x01 -#define BID_EEPROM_4MB_RING 0x08 -#define BID_EEPROM_16MB_RING 0x10 -#define BID_EEPROM_MEDIA_STP 0x40 - -#define BID_EEPROM_MISC_DATA 0x56 -#define BID_EEPROM_EARLY_TOKEN_RELEASE 0x02 - -#define CNFG_ID_8003E 0x6fc0 -#define CNFG_ID_8003S 0x6fc1 -#define CNFG_ID_8003W 0x6fc2 -#define CNFG_ID_8115TRA 0x6ec6 -#define CNFG_ID_8013E 0x61C8 -#define CNFG_ID_8013W 0x61C9 -#define CNFG_ID_BISTRO03E 0xEFE5 -#define CNFG_ID_BISTRO13E 0xEFD5 -#define CNFG_ID_BISTRO13W 0xEFD4 -#define CNFG_MSR_583 0x0 -#define CNFG_ICR_583 0x1 -#define CNFG_IAR_583 0x2 -#define CNFG_BIO_583 0x3 -#define CNFG_EAR_583 0x3 -#define CNFG_IRR_583 0x4 -#define CNFG_LAAR_584 0x5 -#define CNFG_GP2 0x7 -#define CNFG_LAAR_MASK 0x1F -#define CNFG_LAAR_ZWS 0x20 -#define CNFG_LAAR_L16E 0x40 -#define CNFG_ICR_IR2_584 0x04 -#define CNFG_ICR_MASK 0x08 -#define CNFG_ICR_MSZ 0x08 -#define CNFG_ICR_RLA 0x10 -#define CNFG_ICR_STO 0x80 -#define CNFG_IRR_IRQS 0x60 -#define CNFG_IRR_IEN 0x80 -#define CNFG_IRR_ZWS 0x01 -#define CNFG_GP2_BOOT_NIBBLE 0x0F -#define CNFG_IRR_OUT2 0x04 -#define CNFG_IRR_OUT1 0x02 - -#define CNFG_SIZE_8KB 8 -#define CNFG_SIZE_16KB 16 -#define CNFG_SIZE_32KB 32 -#define CNFG_SIZE_64KB 64 -#define CNFG_SIZE_128KB 128 -#define CNFG_SIZE_256KB 256 -#define ROM_DISABLE 0x0 - -#define CNFG_SLOT_ENABLE_BIT 0x08 - -#define CNFG_POS_CONTROL_REG 0x096 -#define CNFG_POS_REG0 0x100 -#define CNFG_POS_REG1 0x101 -#define CNFG_POS_REG2 0x102 -#define CNFG_POS_REG3 0x103 -#define CNFG_POS_REG4 0x104 -#define CNFG_POS_REG5 0x105 - -#define CNFG_ADAPTER_TYPE_MASK 0x0e - -#define SLOT_16BIT 0x0008 -#define INTERFACE_5X3_CHIP 0x0000 /* 0000 = 583 or 593 chips */ -#define NIC_690_BIT 0x0010 /* NIC is 690 */ -#define ALTERNATE_IRQ_BIT 0x0020 /* Alternate IRQ is used */ -#define INTERFACE_584_CHIP 0x0040 /* 0001 = 584 chip */ -#define INTERFACE_594_CHIP 0x0080 /* 0010 = 594 chip */ -#define INTERFACE_585_CHIP 0x0100 /* 0100 = 585/790 chip */ -#define INTERFACE_CHIP_MASK 0x03C0 /* Isolates Intfc Chip Type */ - -#define BOARD_16BIT 0x0040 -#define NODE_ADDR_CKSUM 0xEE -#define BRD_ID_8115T 0x04 - -#define NIC_825_BIT 0x0400 /* TRC 83C825 NIC */ -#define NIC_790_BIT 0x0800 /* NIC is 83C790 Ethernet */ - -#define CHIP_REV_MASK 0x3000 - -#define HWR_CBUSY 0x02 -#define HWR_CA 0x01 - -#define MAC_QUEUE 0 -#define NON_MAC_QUEUE 1 -#define BUG_QUEUE 2 /* NO RECEIVE QUEUE, ONLY TX */ - -#define NUM_MAC_TX_FCBS 8 -#define NUM_MAC_TX_BDBS NUM_MAC_TX_FCBS -#define NUM_MAC_RX_FCBS 7 -#define NUM_MAC_RX_BDBS 8 - -#define NUM_NON_MAC_TX_FCBS 6 -#define NUM_NON_MAC_TX_BDBS NUM_NON_MAC_TX_FCBS - -#define NUM_NON_MAC_RX_BDBS 0 /* CALCULATED DYNAMICALLY */ - -#define NUM_BUG_TX_FCBS 8 -#define NUM_BUG_TX_BDBS NUM_BUG_TX_FCBS - -#define MAC_TX_BUFFER_MEMORY 1024 -#define NON_MAC_TX_BUFFER_MEMORY (20 * 1024) -#define BUG_TX_BUFFER_MEMORY (NUM_BUG_TX_FCBS * 32) - -#define RX_BUFFER_MEMORY 0 /* CALCULATED DYNAMICALLY */ -#define RX_DATA_BUFFER_SIZE 256 -#define RX_BDB_SIZE_SHIFT 3 /* log2(RX_DATA_BUFFER_SIZE)-log2(sizeof(BDBlock)) */ -#define RX_BDB_SIZE_MASK (sizeof(BDBlock) - 1) -#define RX_DATA_BUFFER_SIZE_MASK (RX_DATA_BUFFER_SIZE-1) - -#define NUM_OF_INTERRUPTS 0x20 - -#define NOT_TRANSMITING 0 -#define TRANSMITING 1 - -#define TRC_INTERRUPT_ENABLE_MASK 0x7FF6 - -#define UCODE_VERSION 0x58 - -#define UCODE_SIZE_OFFSET 0x0000 /* WORD */ -#define UCODE_CHECKSUM_OFFSET 0x0002 /* WORD */ -#define UCODE_VERSION_OFFSET 0x0004 /* BYTE */ - -#define CS_RAM_SIZE 0X2000 -#define CS_RAM_CHECKSUM_OFFSET 0x1FFE /* WORD 1FFE(MSB)-1FFF(LSB)*/ -#define CS_RAM_VERSION_OFFSET 0x1FFC /* WORD 1FFC(MSB)-1FFD(LSB)*/ - -#define MISC_DATA_SIZE 128 -#define NUM_OF_ACBS 1 - -#define ACB_COMMAND_NOT_DONE 0x0000 /* Init, command not done */ -#define ACB_COMMAND_DONE 0x8000 /* TRC says command done */ -#define ACB_COMMAND_STATUS_MASK 0x00FF /* low byte is status */ -#define ACB_COMMAND_SUCCESSFUL 0x0000 /* means cmd was successful */ -#define ACB_NOT_CHAIN_END 0x0000 /* tell TRC more CBs in chain */ -#define ACB_CHAIN_END 0x8000 /* tell TRC last CB in chain */ -#define ACB_COMMAND_NO_INTERRUPT 0x0000 /* tell TRC no INT after CB */ -#define ACB_COMMAND_INTERRUPT 0x2000 /* tell TRC to INT after CB */ -#define ACB_SUB_CMD_NOP 0x0000 -#define ACB_CMD_HIC_NOP 0x0080 -#define ACB_CMD_MCT_NOP 0x0000 -#define ACB_CMD_MCT_TEST 0x0001 -#define ACB_CMD_HIC_TEST 0x0081 -#define ACB_CMD_INSERT 0x0002 -#define ACB_CMD_REMOVE 0x0003 -#define ACB_CMD_MCT_WRITE_VALUE 0x0004 -#define ACB_CMD_HIC_WRITE_VALUE 0x0084 -#define ACB_CMD_MCT_READ_VALUE 0x0005 -#define ACB_CMD_HIC_READ_VALUE 0x0085 -#define ACB_CMD_INIT_TX_RX 0x0086 -#define ACB_CMD_INIT_TRC_TIMERS 0x0006 -#define ACB_CMD_READ_TRC_STATUS 0x0007 -#define ACB_CMD_CHANGE_JOIN_STATE 0x0008 -#define ACB_CMD_RESERVED_9 0x0009 -#define ACB_CMD_RESERVED_A 0x000A -#define ACB_CMD_RESERVED_B 0x000B -#define ACB_CMD_RESERVED_C 0x000C -#define ACB_CMD_RESERVED_D 0x000D -#define ACB_CMD_RESERVED_E 0x000E -#define ACB_CMD_RESERVED_F 0x000F - -#define TRC_MAC_REGISTERS_TEST 0x0000 -#define TRC_INTERNAL_LOOPBACK 0x0001 -#define TRC_TRI_LOOPBACK 0x0002 -#define TRC_INTERNAL_ROM_TEST 0x0003 -#define TRC_LOBE_MEDIA_TEST 0x0004 -#define TRC_ANALOG_TEST 0x0005 -#define TRC_HOST_INTERFACE_REG_TEST 0x0003 - -#define TEST_DMA_1 0x0000 -#define TEST_DMA_2 0x0001 -#define TEST_MCT_ROM 0x0002 -#define HIC_INTERNAL_DIAG 0x0003 - -#define ABORT_TRANSMIT_PRIORITY_0 0x0001 -#define ABORT_TRANSMIT_PRIORITY_1 0x0002 -#define ABORT_TRANSMIT_PRIORITY_2 0x0004 -#define ABORT_TRANSMIT_PRIORITY_3 0x0008 -#define ABORT_TRANSMIT_PRIORITY_4 0x0010 -#define ABORT_TRANSMIT_PRIORITY_5 0x0020 -#define ABORT_TRANSMIT_PRIORITY_6 0x0040 -#define ABORT_TRANSMIT_PRIORITY_7 0x0080 - -#define TX_PENDING_PRIORITY_0 0x0001 -#define TX_PENDING_PRIORITY_1 0x0002 -#define TX_PENDING_PRIORITY_2 0x0004 -#define TX_PENDING_PRIORITY_3 0x0008 -#define TX_PENDING_PRIORITY_4 0x0010 -#define TX_PENDING_PRIORITY_5 0x0020 -#define TX_PENDING_PRIORITY_6 0x0040 -#define TX_PENDING_PRIORITY_7 0x0080 - -#define FCB_FRAME_LENGTH 0x100 -#define FCB_COMMAND_DONE 0x8000 /* FCB Word 0 */ -#define FCB_NOT_CHAIN_END 0x0000 /* FCB Word 1 */ -#define FCB_CHAIN_END 0x8000 -#define FCB_NO_WARNING 0x0000 -#define FCB_WARNING 0x4000 -#define FCB_INTERRUPT_DISABLE 0x0000 -#define FCB_INTERRUPT_ENABLE 0x2000 - -#define FCB_ENABLE_IMA 0x0008 -#define FCB_ENABLE_TES 0x0004 /* Guarantee Tx before Int */ -#define FCB_ENABLE_TFS 0x0002 /* Post Tx Frame Status */ -#define FCB_ENABLE_NTC 0x0001 /* No Tx CRC */ - -#define FCB_TX_STATUS_CR2 0x0004 -#define FCB_TX_STATUS_AR2 0x0008 -#define FCB_TX_STATUS_CR1 0x0040 -#define FCB_TX_STATUS_AR1 0x0080 -#define FCB_TX_AC_BITS (FCB_TX_STATUS_AR1+FCB_TX_STATUS_AR2+FCB_TX_STATUS_CR1+FCB_TX_STATUS_CR2) -#define FCB_TX_STATUS_E 0x0100 - -#define FCB_RX_STATUS_ANY_ERROR 0x0001 -#define FCB_RX_STATUS_FCS_ERROR 0x0002 - -#define FCB_RX_STATUS_IA_MATCHED 0x0400 -#define FCB_RX_STATUS_IGA_BSGA_MATCHED 0x0500 -#define FCB_RX_STATUS_FA_MATCHED 0x0600 -#define FCB_RX_STATUS_BA_MATCHED 0x0700 -#define FCB_RX_STATUS_DA_MATCHED 0x0400 -#define FCB_RX_STATUS_SOURCE_ROUTING 0x0800 - -#define BDB_BUFFER_SIZE 0x100 -#define BDB_NOT_CHAIN_END 0x0000 -#define BDB_CHAIN_END 0x8000 -#define BDB_NO_WARNING 0x0000 -#define BDB_WARNING 0x4000 - -#define ERROR_COUNTERS_CHANGED 0x0001 -#define TI_NDIS_RING_STATUS_CHANGED 0x0002 -#define UNA_CHANGED 0x0004 -#define READY_TO_SEND_RQ_INIT 0x0008 - -#define SCGB_ADDRESS_POINTER_FORMAT INTEL_ADDRESS_POINTER_FORMAT -#define SCGB_DATA_FORMAT INTEL_DATA_FORMAT -#define SCGB_MULTI_WORD_CONTROL 0 -#define SCGB_BURST_LENGTH 0x000E /* DMA Burst Length */ - -#define SCGB_CONFIG (INTEL_ADDRESS_POINTER_FORMAT+INTEL_DATA_FORMAT+SCGB_BURST_LENGTH) - -#define ISCP_BLOCK_SIZE 0x0A -#define RAM_SIZE 0x10000 -#define INIT_SYS_CONFIG_PTR_OFFSET (RAM_SIZE-ISCP_BLOCK_SIZE) -#define SCGP_BLOCK_OFFSET 0 - -#define SCLB_NOT_VALID 0x0000 /* Initially, SCLB not valid */ -#define SCLB_VALID 0x8000 /* Host tells TRC SCLB valid */ -#define SCLB_PROCESSED 0x0000 /* TRC says SCLB processed */ -#define SCLB_RESUME_CONTROL_NOT_VALID 0x0000 /* Initially, RC not valid */ -#define SCLB_RESUME_CONTROL_VALID 0x4000 /* Host tells TRC RC valid */ -#define SCLB_IACK_CODE_NOT_VALID 0x0000 /* Initially, IACK not valid */ -#define SCLB_IACK_CODE_VALID 0x2000 /* Host tells TRC IACK valid */ -#define SCLB_CMD_NOP 0x0000 -#define SCLB_CMD_REMOVE 0x0001 -#define SCLB_CMD_SUSPEND_ACB_CHAIN 0x0002 -#define SCLB_CMD_SET_INTERRUPT_MASK 0x0003 -#define SCLB_CMD_CLEAR_INTERRUPT_MASK 0x0004 -#define SCLB_CMD_RESERVED_5 0x0005 -#define SCLB_CMD_RESERVED_6 0x0006 -#define SCLB_CMD_RESERVED_7 0x0007 -#define SCLB_CMD_RESERVED_8 0x0008 -#define SCLB_CMD_RESERVED_9 0x0009 -#define SCLB_CMD_RESERVED_A 0x000A -#define SCLB_CMD_RESERVED_B 0x000B -#define SCLB_CMD_RESERVED_C 0x000C -#define SCLB_CMD_RESERVED_D 0x000D -#define SCLB_CMD_RESERVED_E 0x000E -#define SCLB_CMD_RESERVED_F 0x000F - -#define SCLB_RC_ACB 0x0001 /* Action Command Block Chain */ -#define SCLB_RC_RES0 0x0002 /* Always Zero */ -#define SCLB_RC_RES1 0x0004 /* Always Zero */ -#define SCLB_RC_RES2 0x0008 /* Always Zero */ -#define SCLB_RC_RX_MAC_FCB 0x0010 /* RX_MAC_FCB Chain */ -#define SCLB_RC_RX_MAC_BDB 0x0020 /* RX_MAC_BDB Chain */ -#define SCLB_RC_RX_NON_MAC_FCB 0x0040 /* RX_NON_MAC_FCB Chain */ -#define SCLB_RC_RX_NON_MAC_BDB 0x0080 /* RX_NON_MAC_BDB Chain */ -#define SCLB_RC_TFCB0 0x0100 /* TX Priority 0 FCB Chain */ -#define SCLB_RC_TFCB1 0x0200 /* TX Priority 1 FCB Chain */ -#define SCLB_RC_TFCB2 0x0400 /* TX Priority 2 FCB Chain */ -#define SCLB_RC_TFCB3 0x0800 /* TX Priority 3 FCB Chain */ -#define SCLB_RC_TFCB4 0x1000 /* TX Priority 4 FCB Chain */ -#define SCLB_RC_TFCB5 0x2000 /* TX Priority 5 FCB Chain */ -#define SCLB_RC_TFCB6 0x4000 /* TX Priority 6 FCB Chain */ -#define SCLB_RC_TFCB7 0x8000 /* TX Priority 7 FCB Chain */ - -#define SCLB_IMC_RES0 0x0001 /* */ -#define SCLB_IMC_MAC_TYPE_3 0x0002 /* MAC_ARC_INDICATE */ -#define SCLB_IMC_MAC_ERROR_COUNTERS 0x0004 /* */ -#define SCLB_IMC_RES1 0x0008 /* */ -#define SCLB_IMC_MAC_TYPE_2 0x0010 /* QUE_MAC_INDICATE */ -#define SCLB_IMC_TX_FRAME 0x0020 /* */ -#define SCLB_IMC_END_OF_TX_QUEUE 0x0040 /* */ -#define SCLB_IMC_NON_MAC_RX_RESOURCE 0x0080 /* */ -#define SCLB_IMC_MAC_RX_RESOURCE 0x0100 /* */ -#define SCLB_IMC_NON_MAC_RX_FRAME 0x0200 /* */ -#define SCLB_IMC_MAC_RX_FRAME 0x0400 /* */ -#define SCLB_IMC_TRC_FIFO_STATUS 0x0800 /* */ -#define SCLB_IMC_COMMAND_STATUS 0x1000 /* */ -#define SCLB_IMC_MAC_TYPE_1 0x2000 /* Self Removed */ -#define SCLB_IMC_TRC_INTRNL_TST_STATUS 0x4000 /* */ -#define SCLB_IMC_RES2 0x8000 /* */ - -#define DMA_TRIGGER 0x0004 -#define FREQ_16MB_BIT 0x0010 -#define THDREN 0x0020 -#define CFG0_RSV1 0x0040 -#define CFG0_RSV2 0x0080 -#define ETREN 0x0100 -#define RX_OWN_BIT 0x0200 -#define RXATMAC 0x0400 -#define PROMISCUOUS_BIT 0x0800 -#define USETPT 0x1000 -#define SAVBAD_BIT 0x2000 -#define ONEQUE 0x4000 -#define NO_AUTOREMOVE 0x8000 - -#define RX_FCB_AREA_8316 0x00000000 -#define RX_BUFF_AREA_8316 0x00000000 - -#define TRC_POINTER(X) ((unsigned long)(X) - tp->ram_access) -#define RX_FCB_TRC_POINTER(X) ((unsigned long)(X) - tp->ram_access + RX_FCB_AREA_8316) -#define RX_BUFF_TRC_POINTER(X) ((unsigned long)(X) - tp->ram_access + RX_BUFF_AREA_8316) - -// Offset 0: MSR - Memory Select Register -// -#define r587_MSR 0x000 // Register Offset -//#define MSR_RST 0x080 // LAN Controller Reset -#define MSR_MENB 0x040 // Shared Memory Enable -#define MSR_RA18 0x020 // Ram Address bit 18 (583, 584, 587) -#define MSR_RA17 0x010 // Ram Address bit 17 (583, 584, 585/790) -#define MSR_RA16 0x008 // Ram Address bit 16 (583, 584, 585/790) -#define MSR_RA15 0x004 // Ram Address bit 15 (583, 584, 585/790) -#define MSR_RA14 0x002 // Ram Address bit 14 (583, 584, 585/790) -#define MSR_RA13 0x001 // Ram Address bit 13 (583, 584, 585/790) - -#define MSR_MASK 0x03F // Mask for Address bits RA18-RA13 (583, 584, 587) - -#define MSR 0x00 -#define IRR 0x04 -#define HWR 0x04 -#define LAAR 0x05 -#define IMCCR 0x05 -#define LAR0 0x08 -#define BDID 0x0E // Adapter ID byte register offset -#define CSR 0x10 -#define PR 0x11 - -#define MSR_RST 0x80 -#define MSR_MEMB 0x40 -#define MSR_0WS 0x20 - -#define FORCED_16BIT_MODE 0x0002 - -#define INTERFRAME_SPACING_16 0x0003 /* 6 bytes */ -#define INTERFRAME_SPACING_4 0x0001 /* 2 bytes */ -#define MULTICAST_ADDRESS_BIT 0x0010 -#define NON_SRC_ROUTING_BIT 0x0020 - -#define LOOPING_MODE_MASK 0x0007 - -/* - * Decode firmware defines. - */ -#define SWAP_BYTES(X) ((X & 0xff) << 8) | (X >> 8) -#define WEIGHT_OFFSET 5 -#define TREE_SIZE_OFFSET 9 -#define TREE_OFFSET 11 - -/* The Huffman Encoding Tree is constructed of these nodes. */ -typedef struct { - __u8 llink; /* Short version of above node. */ - __u8 tag; - __u8 info; /* This node is used on decodes. */ - __u8 rlink; -} DECODE_TREE_NODE; - -#define ROOT 0 /* Branch value. */ -#define LEAF 0 /* Tag field value. */ -#define BRANCH 1 /* Tag field value. */ - -/* - * Multicast Table Structure - */ -typedef struct { - __u8 address[6]; - __u8 instance_count; -} McTable; - -/* - * Fragment Descriptor Definition - */ -typedef struct { - __u8 *fragment_ptr; - __u32 fragment_length; -} FragmentStructure; - -/* - * Data Buffer Structure Definition - */ -typedef struct { - __u32 fragment_count; - FragmentStructure fragment_list[MAXFRAGMENTS]; -} DataBufferStructure; - -#pragma pack(1) -typedef struct { - __u8 IType; - __u8 ISubtype; -} Interrupt_Status_Word; - -#pragma pack(1) -typedef struct BDBlockType { - __u16 info; /* 02 */ - __u32 trc_next_ptr; /* 06 */ - __u32 trc_data_block_ptr; /* 10 */ - __u16 buffer_length; /* 12 */ - - __u16 *data_block_ptr; /* 16 */ - struct BDBlockType *next_ptr; /* 20 */ - struct BDBlockType *back_ptr; /* 24 */ - __u8 filler[8]; /* 32 */ -} BDBlock; - -#pragma pack(1) -typedef struct FCBlockType { - __u16 frame_status; /* 02 */ - __u16 info; /* 04 */ - __u32 trc_next_ptr; /* 08 */ - __u32 trc_bdb_ptr; /* 12 */ - __u16 frame_length; /* 14 */ - - BDBlock *bdb_ptr; /* 18 */ - struct FCBlockType *next_ptr; /* 22 */ - struct FCBlockType *back_ptr; /* 26 */ - __u16 memory_alloc; /* 28 */ - __u8 filler[4]; /* 32 */ - -} FCBlock; - -#pragma pack(1) -typedef struct SBlockType{ - __u8 Internal_Error_Count; - __u8 Line_Error_Count; - __u8 AC_Error_Count; - __u8 Burst_Error_Count; - __u8 RESERVED_COUNTER_0; - __u8 AD_TRANS_Count; - __u8 RCV_Congestion_Count; - __u8 Lost_FR_Error_Count; - __u8 FREQ_Error_Count; - __u8 FR_Copied_Error_Count; - __u8 RESERVED_COUNTER_1; - __u8 Token_Error_Count; - - __u16 TI_NDIS_Ring_Status; - __u16 BCN_Type; - __u16 Error_Code; - __u16 SA_of_Last_AMP_SMP[3]; - __u16 UNA[3]; - __u16 Ucode_Version_Number; - __u16 Status_CHG_Indicate; - __u16 RESERVED_STATUS_0; -} SBlock; - -#pragma pack(1) -typedef struct ACBlockType { - __u16 cmd_done_status; /* 02 */ - __u16 cmd_info; /* 04 */ - __u32 trc_next_ptr; /* 08 */ - __u16 cmd; /* 10 */ - __u16 subcmd; /* 12 */ - __u16 data_offset_lo; /* 14 */ - __u16 data_offset_hi; /* 16 */ - - struct ACBlockType *next_ptr; /* 20 */ - - __u8 filler[12]; /* 32 */ -} ACBlock; - -#define NUM_OF_INTERRUPTS 0x20 - -#pragma pack(1) -typedef struct { - Interrupt_Status_Word IStatus[NUM_OF_INTERRUPTS]; -} ISBlock; - -#pragma pack(1) -typedef struct { - __u16 valid_command; /* 02 */ - __u16 iack_code; /* 04 */ - __u16 resume_control; /* 06 */ - __u16 int_mask_control; /* 08 */ - __u16 int_mask_state; /* 10 */ - - __u8 filler[6]; /* 16 */ -} SCLBlock; - -#pragma pack(1) -typedef struct -{ - __u16 config; /* 02 */ - __u32 trc_sclb_ptr; /* 06 */ - __u32 trc_acb_ptr; /* 10 */ - __u32 trc_isb_ptr; /* 14 */ - __u16 isbsiz; /* 16 */ - - SCLBlock *sclb_ptr; /* 20 */ - ACBlock *acb_ptr; /* 24 */ - ISBlock *isb_ptr; /* 28 */ - - __u16 Non_Mac_Rx_Bdbs; /* 30 DEBUG */ - __u8 filler[2]; /* 32 */ - -} SCGBlock; - -#pragma pack(1) -typedef struct -{ - __u32 trc_scgb_ptr; - SCGBlock *scgb_ptr; -} ISCPBlock; -#pragma pack() - -typedef struct net_local { - ISCPBlock *iscpb_ptr; - SCGBlock *scgb_ptr; - SCLBlock *sclb_ptr; - ISBlock *isb_ptr; - - ACBlock *acb_head; - ACBlock *acb_curr; - ACBlock *acb_next; - - __u8 adapter_name[12]; - - __u16 num_rx_bdbs [NUM_RX_QS_USED]; - __u16 num_rx_fcbs [NUM_RX_QS_USED]; - - __u16 num_tx_bdbs [NUM_TX_QS_USED]; - __u16 num_tx_fcbs [NUM_TX_QS_USED]; - - __u16 num_of_tx_buffs; - - __u16 tx_buff_size [NUM_TX_QS_USED]; - __u16 tx_buff_used [NUM_TX_QS_USED]; - __u16 tx_queue_status [NUM_TX_QS_USED]; - - FCBlock *tx_fcb_head[NUM_TX_QS_USED]; - FCBlock *tx_fcb_curr[NUM_TX_QS_USED]; - FCBlock *tx_fcb_end[NUM_TX_QS_USED]; - BDBlock *tx_bdb_head[NUM_TX_QS_USED]; - __u16 *tx_buff_head[NUM_TX_QS_USED]; - __u16 *tx_buff_end[NUM_TX_QS_USED]; - __u16 *tx_buff_curr[NUM_TX_QS_USED]; - __u16 num_tx_fcbs_used[NUM_TX_QS_USED]; - - FCBlock *rx_fcb_head[NUM_RX_QS_USED]; - FCBlock *rx_fcb_curr[NUM_RX_QS_USED]; - BDBlock *rx_bdb_head[NUM_RX_QS_USED]; - BDBlock *rx_bdb_curr[NUM_RX_QS_USED]; - BDBlock *rx_bdb_end[NUM_RX_QS_USED]; - __u16 *rx_buff_head[NUM_RX_QS_USED]; - __u16 *rx_buff_end[NUM_RX_QS_USED]; - - __u32 *ptr_local_ring_num; - - __u32 sh_mem_used; - - __u16 page_offset_mask; - - __u16 authorized_function_classes; - __u16 authorized_access_priority; - - __u16 num_acbs; - __u16 num_acbs_used; - __u16 acb_pending; - - __u16 current_isb_index; - - __u8 monitor_state; - __u8 monitor_state_ready; - __u16 ring_status; - __u8 ring_status_flags; - __u8 state; - - __u8 join_state; - - __u8 slot_num; - __u16 pos_id; - - __u32 *ptr_una; - __u32 *ptr_bcn_type; - __u32 *ptr_tx_fifo_underruns; - __u32 *ptr_rx_fifo_underruns; - __u32 *ptr_rx_fifo_overruns; - __u32 *ptr_tx_fifo_overruns; - __u32 *ptr_tx_fcb_overruns; - __u32 *ptr_rx_fcb_overruns; - __u32 *ptr_tx_bdb_overruns; - __u32 *ptr_rx_bdb_overruns; - - __u16 receive_queue_number; - - __u8 rx_fifo_overrun_count; - __u8 tx_fifo_overrun_count; - - __u16 adapter_flags; - __u16 adapter_flags1; - __u16 *misc_command_data; - __u16 max_packet_size; - - __u16 config_word0; - __u16 config_word1; - - __u8 trc_mask; - - __u16 source_ring_number; - __u16 target_ring_number; - - __u16 microcode_version; - - __u16 bic_type; - __u16 nic_type; - __u16 board_id; - - __u16 rom_size; - __u32 rom_base; - __u16 ram_size; - __u16 ram_usable; - __u32 ram_base; - __u32 ram_access; - - __u16 extra_info; - __u16 mode_bits; - __u16 media_menu; - __u16 media_type; - __u16 adapter_bus; - - __u16 status; - __u16 receive_mask; - - __u16 group_address_0; - __u16 group_address[2]; - __u16 functional_address_0; - __u16 functional_address[2]; - __u16 bitwise_group_address[2]; - - __u8 cleanup; - - struct sk_buff_head SendSkbQueue; - __u16 QueueSkb; - - struct tr_statistics MacStat; /* MAC statistics structure */ - - spinlock_t lock; -} NET_LOCAL; - -/************************************ - * SNMP-ON-BOARD Agent Link Structure - ************************************/ - -typedef struct { - __u8 LnkSigStr[12]; /* signature string "SmcLinkTable" */ - __u8 LnkDrvTyp; /* 1=Redbox ODI, 2=ODI DOS, 3=ODI OS/2, 4=NDIS DOS */ - __u8 LnkFlg; /* 0 if no agent linked, 1 if agent linked */ - void *LnkNfo; /* routine which returns pointer to NIC info */ - void *LnkAgtRcv; /* pointer to agent receive trap entry */ - void *LnkAgtXmt; /* pointer to agent transmit trap -entry */ -void *LnkGet; /* pointer to NIC receive data -copy routine */ - void *LnkSnd; /* pointer to NIC send routine -*/ - void *LnkRst; /* pointer to NIC driver reset -routine */ - void *LnkMib; /* pointer to MIB data base */ - void *LnkMibAct; /* pointer to MIB action routine list */ - __u16 LnkCntOffset; /* offset to error counters */ - __u16 LnkCntNum; /* number of error counters */ - __u16 LnkCntSize; /* size of error counters i.e. 32 = 32 bits */ - void *LnkISR; /* pointer to interrupt vector */ - __u8 LnkFrmTyp; /* 1=Ethernet, 2=Token Ring */ - __u8 LnkDrvVer1 ; /* driver major version */ - __u8 LnkDrvVer2 ; /* driver minor version */ -} AgentLink; - -/* - * Definitions for pcm_card_flags(bit_mapped) - */ -#define REG_COMPLETE 0x0001 -#define INSERTED 0x0002 -#define PCC_INSERTED 0x0004 /* 1=currently inserted, 0=cur removed */ - -/* - * Adapter RAM test patterns - */ -#define RAM_PATTERN_1 0x55AA -#define RAM_PATTERN_2 0x9249 -#define RAM_PATTERN_3 0xDB6D - -/* - * definitions for RAM test - */ -#define ROM_SIGNATURE 0xAA55 -#define MIN_ROM_SIZE 0x2000 - -/* - * Return Codes - */ -#define SUCCESS 0x0000 -#define ADAPTER_AND_CONFIG 0x0001 -#define ADAPTER_NO_CONFIG 0x0002 -#define NOT_MY_INTERRUPT 0x0003 -#define FRAME_REJECTED 0x0004 -#define EVENTS_DISABLED 0x0005 -#define OUT_OF_RESOURCES 0x0006 -#define INVALID_PARAMETER 0x0007 -#define INVALID_FUNCTION 0x0008 -#define INITIALIZE_FAILED 0x0009 -#define CLOSE_FAILED 0x000A -#define MAX_COLLISIONS 0x000B -#define NO_SUCH_DESTINATION 0x000C -#define BUFFER_TOO_SMALL_ERROR 0x000D -#define ADAPTER_CLOSED 0x000E -#define UCODE_NOT_PRESENT 0x000F -#define FIFO_UNDERRUN 0x0010 -#define DEST_OUT_OF_RESOURCES 0x0011 -#define ADAPTER_NOT_INITIALIZED 0x0012 -#define PENDING 0x0013 -#define UCODE_PRESENT 0x0014 -#define NOT_INIT_BY_BRIDGE 0x0015 - -#define OPEN_FAILED 0x0080 -#define HARDWARE_FAILED 0x0081 -#define SELF_TEST_FAILED 0x0082 -#define RAM_TEST_FAILED 0x0083 -#define RAM_CONFLICT 0x0084 -#define ROM_CONFLICT 0x0085 -#define UNKNOWN_ADAPTER 0x0086 -#define CONFIG_ERROR 0x0087 -#define CONFIG_WARNING 0x0088 -#define NO_FIXED_CNFG 0x0089 -#define EEROM_CKSUM_ERROR 0x008A -#define ROM_SIGNATURE_ERROR 0x008B -#define ROM_CHECKSUM_ERROR 0x008C -#define ROM_SIZE_ERROR 0x008D -#define UNSUPPORTED_NIC_CHIP 0x008E -#define NIC_REG_ERROR 0x008F -#define BIC_REG_ERROR 0x0090 -#define MICROCODE_TEST_ERROR 0x0091 -#define LOBE_MEDIA_TEST_FAILED 0x0092 - -#define ADAPTER_FOUND_LAN_CORRUPT 0x009B - -#define ADAPTER_NOT_FOUND 0xFFFF - -#define ILLEGAL_FUNCTION INVALID_FUNCTION - -/* Errors */ -#define IO_BASE_INVALID 0x0001 -#define IO_BASE_RANGE 0x0002 -#define IRQ_INVALID 0x0004 -#define IRQ_RANGE 0x0008 -#define RAM_BASE_INVALID 0x0010 -#define RAM_BASE_RANGE 0x0020 -#define RAM_SIZE_RANGE 0x0040 -#define MEDIA_INVALID 0x0800 - -/* Warnings */ -#define IRQ_MISMATCH 0x0080 -#define RAM_BASE_MISMATCH 0x0100 -#define RAM_SIZE_MISMATCH 0x0200 -#define BUS_MODE_MISMATCH 0x0400 - -#define RX_CRC_ERROR 0x01 -#define RX_ALIGNMENT_ERROR 0x02 -#define RX_HW_FAILED 0x80 - -/* - * Definitions for the field RING_STATUS_FLAGS - */ -#define RING_STATUS_CHANGED 0X01 -#define MONITOR_STATE_CHANGED 0X02 -#define JOIN_STATE_CHANGED 0X04 - -/* - * Definitions for the field JOIN_STATE - */ -#define JS_BYPASS_STATE 0x00 -#define JS_LOBE_TEST_STATE 0x01 -#define JS_DETECT_MONITOR_PRESENT_STATE 0x02 -#define JS_AWAIT_NEW_MONITOR_STATE 0x03 -#define JS_DUPLICATE_ADDRESS_TEST_STATE 0x04 -#define JS_NEIGHBOR_NOTIFICATION_STATE 0x05 -#define JS_REQUEST_INITIALIZATION_STATE 0x06 -#define JS_JOIN_COMPLETE_STATE 0x07 -#define JS_BYPASS_WAIT_STATE 0x08 - -/* - * Definitions for the field MONITOR_STATE - */ -#define MS_MONITOR_FSM_INACTIVE 0x00 -#define MS_REPEAT_BEACON_STATE 0x01 -#define MS_REPEAT_CLAIM_TOKEN_STATE 0x02 -#define MS_TRANSMIT_CLAIM_TOKEN_STATE 0x03 -#define MS_STANDBY_MONITOR_STATE 0x04 -#define MS_TRANSMIT_BEACON_STATE 0x05 -#define MS_ACTIVE_MONITOR_STATE 0x06 -#define MS_TRANSMIT_RING_PURGE_STATE 0x07 -#define MS_BEACON_TEST_STATE 0x09 - -/* - * Definitions for the bit-field RING_STATUS - */ -#define SIGNAL_LOSS 0x8000 -#define HARD_ERROR 0x4000 -#define SOFT_ERROR 0x2000 -#define TRANSMIT_BEACON 0x1000 -#define LOBE_WIRE_FAULT 0x0800 -#define AUTO_REMOVAL_ERROR 0x0400 -#define REMOVE_RECEIVED 0x0100 -#define COUNTER_OVERFLOW 0x0080 -#define SINGLE_STATION 0x0040 -#define RING_RECOVERY 0x0020 - -/* - * Definitions for the field BUS_TYPE - */ -#define AT_BUS 0x00 -#define MCA_BUS 0x01 -#define EISA_BUS 0x02 -#define PCI_BUS 0x03 -#define PCMCIA_BUS 0x04 - -/* - * Definitions for adapter_flags - */ -#define RX_VALID_LOOKAHEAD 0x0001 -#define FORCED_16BIT_MODE 0x0002 -#define ADAPTER_DISABLED 0x0004 -#define TRANSMIT_CHAIN_INT 0x0008 -#define EARLY_RX_FRAME 0x0010 -#define EARLY_TX 0x0020 -#define EARLY_RX_COPY 0x0040 -#define USES_PHYSICAL_ADDR 0x0080 /* Rsvd for DEC PCI and 9232 */ -#define NEEDS_PHYSICAL_ADDR 0x0100 /* Reserved*/ -#define RX_STATUS_PENDING 0x0200 -#define ERX_DISABLED 0x0400 /* EARLY_RX_ENABLE rcv_mask */ -#define ENABLE_TX_PENDING 0x0800 -#define ENABLE_RX_PENDING 0x1000 -#define PERM_CLOSE 0x2000 -#define IO_MAPPED 0x4000 /* IOmapped bus interface 795 */ -#define ETX_DISABLED 0x8000 - - -/* - * Definitions for adapter_flags1 - */ -#define TX_PHY_RX_VIRT 0x0001 -#define NEEDS_HOST_RAM 0x0002 -#define NEEDS_MEDIA_TYPE 0x0004 -#define EARLY_RX_DONE 0x0008 -#define PNP_BOOT_BIT 0x0010 /* activates PnP & config on power-up */ - /* clear => regular PnP operation */ -#define PNP_ENABLE 0x0020 /* regular PnP operation clear => */ - /* no PnP, overrides PNP_BOOT_BIT */ -#define SATURN_ENABLE 0x0040 - -#define ADAPTER_REMOVABLE 0x0080 /* adapter is hot swappable */ -#define TX_PHY 0x0100 /* Uses physical address for tx bufs */ -#define RX_PHY 0x0200 /* Uses physical address for rx bufs */ -#define TX_VIRT 0x0400 /* Uses virtual addr for tx bufs */ -#define RX_VIRT 0x0800 -#define NEEDS_SERVICE 0x1000 - -/* - * Adapter Status Codes - */ -#define OPEN 0x0001 -#define INITIALIZED 0x0002 -#define CLOSED 0x0003 -#define FAILED 0x0005 -#define NOT_INITIALIZED 0x0006 -#define IO_CONFLICT 0x0007 -#define CARD_REMOVED 0x0008 -#define CARD_INSERTED 0x0009 - -/* - * Mode Bit Definitions - */ -#define INTERRUPT_STATUS_BIT 0x8000 /* PC Interrupt Line: 0 = Not Enabled */ -#define BOOT_STATUS_MASK 0x6000 /* Mask to isolate BOOT_STATUS */ -#define BOOT_INHIBIT 0x0000 /* BOOT_STATUS is 'inhibited' */ -#define BOOT_TYPE_1 0x2000 /* Unused BOOT_STATUS value */ -#define BOOT_TYPE_2 0x4000 /* Unused BOOT_STATUS value */ -#define BOOT_TYPE_3 0x6000 /* Unused BOOT_STATUS value */ -#define ZERO_WAIT_STATE_MASK 0x1800 /* Mask to isolate Wait State flags */ -#define ZERO_WAIT_STATE_8_BIT 0x1000 /* 0 = Disabled (Inserts Wait States) */ -#define ZERO_WAIT_STATE_16_BIT 0x0800 /* 0 = Disabled (Inserts Wait States) */ -#define LOOPING_MODE_MASK 0x0007 -#define LOOPBACK_MODE_0 0x0000 -#define LOOPBACK_MODE_1 0x0001 -#define LOOPBACK_MODE_2 0x0002 -#define LOOPBACK_MODE_3 0x0003 -#define LOOPBACK_MODE_4 0x0004 -#define LOOPBACK_MODE_5 0x0005 -#define LOOPBACK_MODE_6 0x0006 -#define LOOPBACK_MODE_7 0x0007 -#define AUTO_MEDIA_DETECT 0x0008 -#define MANUAL_CRC 0x0010 -#define EARLY_TOKEN_REL 0x0020 /* Early Token Release for Token Ring */ -#define UMAC 0x0040 -#define UTP2_PORT 0x0080 /* For 8216T2, 0=port A, 1=Port B. */ -#define BNC_10BT_INTERFACE 0x0600 /* BNC and UTP current media set */ -#define UTP_INTERFACE 0x0500 /* Ethernet UTP Only. */ -#define BNC_INTERFACE 0x0400 -#define AUI_INTERFACE 0x0300 -#define AUI_10BT_INTERFACE 0x0200 -#define STARLAN_10_INTERFACE 0x0100 -#define INTERFACE_TYPE_MASK 0x0700 - -/* - * Media Type Bit Definitions - * - * legend: TP = Twisted Pair - * STP = Shielded twisted pair - * UTP = Unshielded twisted pair - */ - -#define CNFG_MEDIA_TYPE_MASK 0x001e /* POS Register 3 Mask */ - -#define MEDIA_S10 0x0000 /* Ethernet adapter, TP. */ -#define MEDIA_AUI_UTP 0x0001 /* Ethernet adapter, AUI/UTP media */ -#define MEDIA_BNC 0x0002 /* Ethernet adapter, BNC media. */ -#define MEDIA_AUI 0x0003 /* Ethernet Adapter, AUI media. */ -#define MEDIA_STP_16 0x0004 /* TokenRing adap, 16Mbit STP. */ -#define MEDIA_STP_4 0x0005 /* TokenRing adap, 4Mbit STP. */ -#define MEDIA_UTP_16 0x0006 /* TokenRing adap, 16Mbit UTP. */ -#define MEDIA_UTP_4 0x0007 /* TokenRing adap, 4Mbit UTP. */ -#define MEDIA_UTP 0x0008 /* Ethernet adapter, UTP media (no AUI) -*/ -#define MEDIA_BNC_UTP 0x0010 /* Ethernet adapter, BNC/UTP media */ -#define MEDIA_UTPFD 0x0011 /* Ethernet adapter, TP full duplex */ -#define MEDIA_UTPNL 0x0012 /* Ethernet adapter, TP with link integrity test disabled */ -#define MEDIA_AUI_BNC 0x0013 /* Ethernet adapter, AUI/BNC media */ -#define MEDIA_AUI_BNC_UTP 0x0014 /* Ethernet adapter, AUI_BNC/UTP */ -#define MEDIA_UTPA 0x0015 /* Ethernet UTP-10Mbps Ports A */ -#define MEDIA_UTPB 0x0016 /* Ethernet UTP-10Mbps Ports B */ -#define MEDIA_STP_16_UTP_16 0x0017 /* Token Ring STP-16Mbps/UTP-16Mbps */ -#define MEDIA_STP_4_UTP_4 0x0018 /* Token Ring STP-4Mbps/UTP-4Mbps */ - -#define MEDIA_STP100_UTP100 0x0020 /* Ethernet STP-100Mbps/UTP-100Mbps */ -#define MEDIA_UTP100FD 0x0021 /* Ethernet UTP-100Mbps, full duplex */ -#define MEDIA_UTP100 0x0022 /* Ethernet UTP-100Mbps */ - - -#define MEDIA_UNKNOWN 0xFFFF /* Unknown adapter/media type */ - -/* - * Definitions for the field: - * media_type2 - */ -#define MEDIA_TYPE_MII 0x0001 -#define MEDIA_TYPE_UTP 0x0002 -#define MEDIA_TYPE_BNC 0x0004 -#define MEDIA_TYPE_AUI 0x0008 -#define MEDIA_TYPE_S10 0x0010 -#define MEDIA_TYPE_AUTO_SENSE 0x1000 -#define MEDIA_TYPE_AUTO_DETECT 0x4000 -#define MEDIA_TYPE_AUTO_NEGOTIATE 0x8000 - -/* - * Definitions for the field: - * line_speed - */ -#define LINE_SPEED_UNKNOWN 0x0000 -#define LINE_SPEED_4 0x0001 -#define LINE_SPEED_10 0x0002 -#define LINE_SPEED_16 0x0004 -#define LINE_SPEED_100 0x0008 -#define LINE_SPEED_T4 0x0008 /* 100BaseT4 aliased for 9332BVT */ -#define LINE_SPEED_FULL_DUPLEX 0x8000 - -/* - * Definitions for the field: - * bic_type (Bus interface chip type) - */ -#define BIC_NO_CHIP 0x0000 /* Bus interface chip not implemented */ -#define BIC_583_CHIP 0x0001 /* 83C583 bus interface chip */ -#define BIC_584_CHIP 0x0002 /* 83C584 bus interface chip */ -#define BIC_585_CHIP 0x0003 /* 83C585 bus interface chip */ -#define BIC_593_CHIP 0x0004 /* 83C593 bus interface chip */ -#define BIC_594_CHIP 0x0005 /* 83C594 bus interface chip */ -#define BIC_564_CHIP 0x0006 /* PCMCIA Bus interface chip */ -#define BIC_790_CHIP 0x0007 /* 83C790 bus i-face/Ethernet NIC chip */ -#define BIC_571_CHIP 0x0008 /* 83C571 EISA bus master i-face */ -#define BIC_587_CHIP 0x0009 /* Token Ring AT bus master i-face */ -#define BIC_574_CHIP 0x0010 /* FEAST bus interface chip */ -#define BIC_8432_CHIP 0x0011 /* 8432 bus i-face/Ethernet NIC(DEC PCI) */ -#define BIC_9332_CHIP 0x0012 /* 9332 bus i-face/100Mbps Ether NIC(DEC PCI) */ -#define BIC_8432E_CHIP 0x0013 /* 8432 Enhanced bus iface/Ethernet NIC(DEC) */ -#define BIC_EPIC100_CHIP 0x0014 /* EPIC/100 10/100 Mbps Ethernet BIC/NIC */ -#define BIC_C94_CHIP 0x0015 /* 91C94 bus i-face in PCMCIA mode */ -#define BIC_X8020_CHIP 0x0016 /* Xilinx PCMCIA multi-func i-face */ - -/* - * Definitions for the field: - * nic_type (Bus interface chip type) - */ -#define NIC_UNK_CHIP 0x0000 /* Unknown NIC chip */ -#define NIC_8390_CHIP 0x0001 /* DP8390 Ethernet NIC */ -#define NIC_690_CHIP 0x0002 /* 83C690 Ethernet NIC */ -#define NIC_825_CHIP 0x0003 /* 83C825 Token Ring NIC */ -/* #define NIC_???_CHIP 0x0004 */ /* Not used */ -/* #define NIC_???_CHIP 0x0005 */ /* Not used */ -/* #define NIC_???_CHIP 0x0006 */ /* Not used */ -#define NIC_790_CHIP 0x0007 /* 83C790 bus i-face/Ethernet NIC chip */ -#define NIC_C100_CHIP 0x0010 /* FEAST 100Mbps Ethernet NIC */ -#define NIC_8432_CHIP 0x0011 /* 8432 bus i-face/Ethernet NIC(DEC PCI) */ -#define NIC_9332_CHIP 0x0012 /* 9332 bus i-face/100Mbps Ether NIC(DEC PCI) */ -#define NIC_8432E_CHIP 0x0013 /* 8432 enhanced bus iface/Ethernet NIC(DEC) */ -#define NIC_EPIC100_CHIP 0x0014 /* EPIC/100 10/100 Mbps Ethernet BIC/NIC */ -#define NIC_C94_CHIP 0x0015 /* 91C94 PC Card with multi func */ - -/* - * Definitions for the field: - * adapter_type The adapter_type field describes the adapter/bus - * configuration. - */ -#define BUS_ISA16_TYPE 0x0001 /* 16 bit adap in 16 bit (E)ISA slot */ -#define BUS_ISA8_TYPE 0x0002 /* 8/16b adap in 8 bit XT/(E)ISA slot */ -#define BUS_MCA_TYPE 0x0003 /* Micro Channel adapter */ - -/* - * Receive Mask definitions - */ -#define ACCEPT_MULTICAST 0x0001 -#define ACCEPT_BROADCAST 0x0002 -#define PROMISCUOUS_MODE 0x0004 -#define ACCEPT_SOURCE_ROUTING 0x0008 -#define ACCEPT_ERR_PACKETS 0x0010 -#define ACCEPT_ATT_MAC_FRAMES 0x0020 -#define ACCEPT_MULTI_PROM 0x0040 -#define TRANSMIT_ONLY 0x0080 -#define ACCEPT_EXT_MAC_FRAMES 0x0100 -#define EARLY_RX_ENABLE 0x0200 -#define PKT_SIZE_NOT_NEEDED 0x0400 -#define ACCEPT_SOURCE_ROUTING_SPANNING 0x0808 - -#define ACCEPT_ALL_MAC_FRAMES 0x0120 - -/* - * config_mode defs - */ -#define STORE_EEROM 0x0001 /* Store config in EEROM. */ -#define STORE_REGS 0x0002 /* Store config in register set. */ - -/* - * equates for lmac_flags in adapter structure (Ethernet) - */ -#define MEM_DISABLE 0x0001 -#define RX_STATUS_POLL 0x0002 -#define USE_RE_BIT 0x0004 -/*#define RESERVED 0x0008 */ -/*#define RESERVED 0x0010 */ -/*#define RESERVED 0x0020 */ -/*#define RESERVED 0x0040 */ -/*#define RESERVED 0x0080 */ -/*#define RESERVED 0x0100 */ -/*#define RESERVED 0x0200 */ -/*#define RESERVED 0x0400 */ -/*#define RESERVED 0x0800 */ -/*#define RESERVED 0x1000 */ -/*#define RESERVED 0x2000 */ -/*#define RESERVED 0x4000 */ -/*#define RESERVED 0x8000 */ - -/* media_opts & media_set Fields bit defs for Ethernet ... */ -#define MED_OPT_BNC 0x01 -#define MED_OPT_UTP 0x02 -#define MED_OPT_AUI 0x04 -#define MED_OPT_10MB 0x08 -#define MED_OPT_100MB 0x10 -#define MED_OPT_S10 0x20 - -/* media_opts & media_set Fields bit defs for Token Ring ... */ -#define MED_OPT_4MB 0x08 -#define MED_OPT_16MB 0x10 -#define MED_OPT_STP 0x40 - -#define MAX_8023_SIZE 1500 /* Max 802.3 size of frame. */ -#define DEFAULT_ERX_VALUE 4 /* Number of 16-byte blocks for 790B early Rx. */ -#define DEFAULT_ETX_VALUE 32 /* Number of bytes for 790B early Tx. */ -#define DEFAULT_TX_RETRIES 3 /* Number of transmit retries */ -#define LPBK_FRAME_SIZE 1024 /* Default loopback frame for Rx calibration test. */ -#define MAX_LOOKAHEAD_SIZE 252 /* Max lookahead size for ethernet. */ - -#define RW_MAC_STATE 0x1101 -#define RW_SA_OF_LAST_AMP_OR_SMP 0x2803 -#define RW_PHYSICAL_DROP_NUMBER 0x3B02 -#define RW_UPSTREAM_NEIGHBOR_ADDRESS 0x3E03 -#define RW_PRODUCT_INSTANCE_ID 0x4B09 - -#define RW_TRC_STATUS_BLOCK 0x5412 - -#define RW_MAC_ERROR_COUNTERS_NO_CLEAR 0x8006 -#define RW_MAC_ERROR_COUNTER_CLEAR 0x7A06 -#define RW_CONFIG_REGISTER_0 0xA001 -#define RW_CONFIG_REGISTER_1 0xA101 -#define RW_PRESCALE_TIMER_THRESHOLD 0xA201 -#define RW_TPT_THRESHOLD 0xA301 -#define RW_TQP_THRESHOLD 0xA401 -#define RW_TNT_THRESHOLD 0xA501 -#define RW_TBT_THRESHOLD 0xA601 -#define RW_TSM_THRESHOLD 0xA701 -#define RW_TAM_THRESHOLD 0xA801 -#define RW_TBR_THRESHOLD 0xA901 -#define RW_TER_THRESHOLD 0xAA01 -#define RW_TGT_THRESHOLD 0xAB01 -#define RW_THT_THRESHOLD 0xAC01 -#define RW_TRR_THRESHOLD 0xAD01 -#define RW_TVX_THRESHOLD 0xAE01 -#define RW_INDIVIDUAL_MAC_ADDRESS 0xB003 - -#define RW_INDIVIDUAL_GROUP_ADDRESS 0xB303 /* all of group addr */ -#define RW_INDIVIDUAL_GROUP_ADDR_WORD_0 0xB301 /* 1st word of group addr */ -#define RW_INDIVIDUAL_GROUP_ADDR 0xB402 /* 2nd-3rd word of group addr */ -#define RW_FUNCTIONAL_ADDRESS 0xB603 /* all of functional addr */ -#define RW_FUNCTIONAL_ADDR_WORD_0 0xB601 /* 1st word of func addr */ -#define RW_FUNCTIONAL_ADDR 0xB702 /* 2nd-3rd word func addr */ - -#define RW_BIT_SIGNIFICANT_GROUP_ADDR 0xB902 -#define RW_SOURCE_RING_BRIDGE_NUMBER 0xBB01 -#define RW_TARGET_RING_NUMBER 0xBC01 - -#define RW_HIC_INTERRUPT_MASK 0xC601 - -#define SOURCE_ROUTING_SPANNING_BITS 0x00C0 /* Spanning Tree Frames */ -#define SOURCE_ROUTING_EXPLORER_BIT 0x0040 /* Explorer and Single Route */ - - /* write */ - -#define CSR_MSK_ALL 0x80 // Bic 587 Only -#define CSR_MSKTINT 0x20 -#define CSR_MSKCBUSY 0x10 -#define CSR_CLRTINT 0x08 -#define CSR_CLRCBUSY 0x04 -#define CSR_WCSS 0x02 -#define CSR_CA 0x01 - - /* read */ - -#define CSR_TINT 0x20 -#define CSR_CINT 0x10 -#define CSR_TSTAT 0x08 -#define CSR_CSTAT 0x04 -#define CSR_FAULT 0x02 -#define CSR_CBUSY 0x01 - -#define LAAR_MEM16ENB 0x80 -#define Zws16 0x20 - -#define IRR_IEN 0x80 -#define Zws8 0x01 - -#define IMCCR_EIL 0x04 - -typedef struct { - __u8 ac; /* Access Control */ - __u8 fc; /* Frame Control */ - __u8 da[6]; /* Dest Addr */ - __u8 sa[6]; /* Source Addr */ - - __u16 vl; /* Vector Length */ - __u8 dc_sc; /* Dest/Source Class */ - __u8 vc; /* Vector Code */ - } MAC_HEADER; - -#define MAX_SUB_VECTOR_INFO (RX_DATA_BUFFER_SIZE - sizeof(MAC_HEADER) - 2) - -typedef struct - { - __u8 svl; /* Sub-vector Length */ - __u8 svi; /* Sub-vector Code */ - __u8 svv[MAX_SUB_VECTOR_INFO]; /* Sub-vector Info */ - } MAC_SUB_VECTOR; - -#endif /* __KERNEL__ */ -#endif /* __LINUX_SMCTR_H */ diff --git a/trunk/drivers/net/tokenring/tms380tr.c b/trunk/drivers/net/tokenring/tms380tr.c deleted file mode 100644 index be4813e0366c..000000000000 --- a/trunk/drivers/net/tokenring/tms380tr.c +++ /dev/null @@ -1,2306 +0,0 @@ -/* - * tms380tr.c: A network driver library for Texas Instruments TMS380-based - * Token Ring Adapters. - * - * Originally sktr.c: Written 1997 by Christoph Goos - * - * A fine result of the Linux Systems Network Architecture Project. - * http://www.vanheusden.com/sna/ - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * The following modules are currently available for card support: - * - tmspci (Generic PCI card support) - * - abyss (Madge PCI support) - * - tmsisa (SysKonnect TR4/16 ISA) - * - * Sources: - * - The hardware related parts of this driver are take from - * the SysKonnect Token Ring driver for Windows NT. - * - I used the IBM Token Ring driver 'ibmtr.c' as a base for this - * driver, as well as the 'skeleton.c' driver by Donald Becker. - * - Also various other drivers in the linux source tree were taken - * as samples for some tasks. - * - TI TMS380 Second-Generation Token Ring User's Guide - * - TI datasheets for respective chips - * - David Hein at Texas Instruments - * - Various Madge employees - * - * Maintainer(s): - * JS Jay Schulist jschlst@samba.org - * CG Christoph Goos cgoos@syskonnect.de - * AF Adam Fritzler - * MLP Mike Phillips phillim@amtrak.com - * JF Jochen Friedrich jochen@scram.de - * - * Modification History: - * 29-Aug-97 CG Created - * 04-Apr-98 CG Fixed problems caused by tok_timer_check - * 10-Apr-98 CG Fixed lockups at cable disconnection - * 27-May-98 JS Formated to Linux Kernel Format - * 31-May-98 JS Hacked in PCI support - * 16-Jun-98 JS Modulized for multiple cards with one driver - * Sep-99 AF Renamed to tms380tr (supports more than SK's) - * 23-Sep-99 AF Added Compaq and Thomas-Conrad PCI support - * Fixed a bug causing double copies on PCI - * Fixed for new multicast stuff (2.2/2.3) - * 25-Sep-99 AF Uped TPL_NUM from 3 to 9 - * Removed extraneous 'No free TPL' - * 22-Dec-99 AF Added Madge PCI Mk2 support and generalized - * parts of the initilization procedure. - * 30-Dec-99 AF Turned tms380tr into a library ala 8390. - * Madge support is provided in the abyss module - * Generic PCI support is in the tmspci module. - * 30-Nov-00 JF Updated PCI code to support IO MMU via - * pci_map_static(). Alpha uses this MMU for ISA - * as well. - * 14-Jan-01 JF Fix DMA on ifdown/ifup sequences. Some - * cleanup. - * 13-Jan-02 JF Add spinlock to fix race condition. - * 09-Nov-02 JF Fixed printks to not SPAM the console during - * normal operation. - * 30-Dec-02 JF Removed incorrect __init from - * tms380tr_init_card. - * 22-Jul-05 JF Converted to dma-mapping. - * - * To do: - * 1. Multi/Broadcast packet handling (this may have fixed itself) - * 2. Write a sktrisa module that includes the old ISA support (done) - * 3. Allow modules to load their own microcode - * 4. Speed up the BUD process -- freezing the kernel for 3+sec is - * quite unacceptable. - * 5. Still a few remaining stalls when the cable is unplugged. - */ - -#ifdef MODULE -static const char version[] = "tms380tr.c: v1.10 30/12/2002 by Christoph Goos, Adam Fritzler\n"; -#endif - -#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 "tms380tr.h" /* Our Stuff */ - -/* Use 0 for production, 1 for verification, 2 for debug, and - * 3 for very verbose debug. - */ -#ifndef TMS380TR_DEBUG -#define TMS380TR_DEBUG 0 -#endif -static unsigned int tms380tr_debug = TMS380TR_DEBUG; - -/* Index to functions, as function prototypes. - * Alphabetical by function name. - */ - -/* "A" */ -/* "B" */ -static int tms380tr_bringup_diags(struct net_device *dev); -/* "C" */ -static void tms380tr_cancel_tx_queue(struct net_local* tp); -static int tms380tr_chipset_init(struct net_device *dev); -static void tms380tr_chk_irq(struct net_device *dev); -static void tms380tr_chk_outstanding_cmds(struct net_device *dev); -static void tms380tr_chk_src_addr(unsigned char *frame, unsigned char *hw_addr); -static unsigned char tms380tr_chk_ssb(struct net_local *tp, unsigned short IrqType); -int tms380tr_close(struct net_device *dev); -static void tms380tr_cmd_status_irq(struct net_device *dev); -/* "D" */ -static void tms380tr_disable_interrupts(struct net_device *dev); -#if TMS380TR_DEBUG > 0 -static void tms380tr_dump(unsigned char *Data, int length); -#endif -/* "E" */ -static void tms380tr_enable_interrupts(struct net_device *dev); -static void tms380tr_exec_cmd(struct net_device *dev, unsigned short Command); -static void tms380tr_exec_sifcmd(struct net_device *dev, unsigned int WriteValue); -/* "F" */ -/* "G" */ -static struct net_device_stats *tms380tr_get_stats(struct net_device *dev); -/* "H" */ -static netdev_tx_t tms380tr_hardware_send_packet(struct sk_buff *skb, - struct net_device *dev); -/* "I" */ -static int tms380tr_init_adapter(struct net_device *dev); -static void tms380tr_init_ipb(struct net_local *tp); -static void tms380tr_init_net_local(struct net_device *dev); -static void tms380tr_init_opb(struct net_device *dev); -/* "M" */ -/* "O" */ -int tms380tr_open(struct net_device *dev); -static void tms380tr_open_adapter(struct net_device *dev); -/* "P" */ -/* "R" */ -static void tms380tr_rcv_status_irq(struct net_device *dev); -static int tms380tr_read_ptr(struct net_device *dev); -static void tms380tr_read_ram(struct net_device *dev, unsigned char *Data, - unsigned short Address, int Length); -static int tms380tr_reset_adapter(struct net_device *dev); -static void tms380tr_reset_interrupt(struct net_device *dev); -static void tms380tr_ring_status_irq(struct net_device *dev); -/* "S" */ -static netdev_tx_t tms380tr_send_packet(struct sk_buff *skb, - struct net_device *dev); -static void tms380tr_set_multicast_list(struct net_device *dev); -static int tms380tr_set_mac_address(struct net_device *dev, void *addr); -/* "T" */ -static void tms380tr_timer_chk(unsigned long data); -static void tms380tr_timer_end_wait(unsigned long data); -static void tms380tr_tx_status_irq(struct net_device *dev); -/* "U" */ -static void tms380tr_update_rcv_stats(struct net_local *tp, - unsigned char DataPtr[], unsigned int Length); -/* "W" */ -void tms380tr_wait(unsigned long time); -static void tms380tr_write_rpl_status(RPL *rpl, unsigned int Status); -static void tms380tr_write_tpl_status(TPL *tpl, unsigned int Status); - -#define SIFREADB(reg) \ - (((struct net_local *)netdev_priv(dev))->sifreadb(dev, reg)) -#define SIFWRITEB(val, reg) \ - (((struct net_local *)netdev_priv(dev))->sifwriteb(dev, val, reg)) -#define SIFREADW(reg) \ - (((struct net_local *)netdev_priv(dev))->sifreadw(dev, reg)) -#define SIFWRITEW(val, reg) \ - (((struct net_local *)netdev_priv(dev))->sifwritew(dev, val, reg)) - - - -#if 0 /* TMS380TR_DEBUG > 0 */ -static int madgemc_sifprobe(struct net_device *dev) -{ - unsigned char old, chk1, chk2; - - old = SIFREADB(SIFADR); /* Get the old SIFADR value */ - - chk1 = 0; /* Begin with check value 0 */ - do { - madgemc_setregpage(dev, 0); - /* Write new SIFADR value */ - SIFWRITEB(chk1, SIFADR); - chk2 = SIFREADB(SIFADR); - if (chk2 != chk1) - return -1; - - madgemc_setregpage(dev, 1); - /* Read, invert and write */ - chk2 = SIFREADB(SIFADD); - if (chk2 != chk1) - return -1; - - madgemc_setregpage(dev, 0); - chk2 ^= 0x0FE; - SIFWRITEB(chk2, SIFADR); - - /* Read, invert and compare */ - madgemc_setregpage(dev, 1); - chk2 = SIFREADB(SIFADD); - madgemc_setregpage(dev, 0); - chk2 ^= 0x0FE; - - if(chk1 != chk2) - return -1; /* No adapter */ - chk1 -= 2; - } while(chk1 != 0); /* Repeat 128 times (all byte values) */ - - madgemc_setregpage(dev, 0); /* sanity */ - /* Restore the SIFADR value */ - SIFWRITEB(old, SIFADR); - - return 0; -} -#endif - -/* - * Open/initialize the board. This is called sometime after - * booting when the 'ifconfig' program is run. - * - * This routine should set everything up anew at each open, even - * registers that "should" only need to be set once at boot, so that - * there is non-reboot way to recover if something goes wrong. - */ -int tms380tr_open(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - int err; - - /* init the spinlock */ - spin_lock_init(&tp->lock); - init_timer(&tp->timer); - - /* Reset the hardware here. Don't forget to set the station address. */ - -#ifdef CONFIG_ISA - if(dev->dma > 0) - { - unsigned long flags=claim_dma_lock(); - disable_dma(dev->dma); - set_dma_mode(dev->dma, DMA_MODE_CASCADE); - enable_dma(dev->dma); - release_dma_lock(flags); - } -#endif - - err = tms380tr_chipset_init(dev); - if(err) - { - printk(KERN_INFO "%s: Chipset initialization error\n", - dev->name); - return -1; - } - - tp->timer.expires = jiffies + 30*HZ; - tp->timer.function = tms380tr_timer_end_wait; - tp->timer.data = (unsigned long)dev; - add_timer(&tp->timer); - - printk(KERN_DEBUG "%s: Adapter RAM size: %dK\n", - dev->name, tms380tr_read_ptr(dev)); - - tms380tr_enable_interrupts(dev); - tms380tr_open_adapter(dev); - - netif_start_queue(dev); - - /* Wait for interrupt from hardware. If interrupt does not come, - * there will be a timeout from the timer. - */ - tp->Sleeping = 1; - interruptible_sleep_on(&tp->wait_for_tok_int); - del_timer(&tp->timer); - - /* If AdapterVirtOpenFlag is 1, the adapter is now open for use */ - if(tp->AdapterVirtOpenFlag == 0) - { - tms380tr_disable_interrupts(dev); - return -1; - } - - tp->StartTime = jiffies; - - /* Start function control timer */ - tp->timer.expires = jiffies + 2*HZ; - tp->timer.function = tms380tr_timer_chk; - tp->timer.data = (unsigned long)dev; - add_timer(&tp->timer); - - return 0; -} - -/* - * Timeout function while waiting for event - */ -static void tms380tr_timer_end_wait(unsigned long data) -{ - struct net_device *dev = (struct net_device*)data; - struct net_local *tp = netdev_priv(dev); - - if(tp->Sleeping) - { - tp->Sleeping = 0; - wake_up_interruptible(&tp->wait_for_tok_int); - } -} - -/* - * Initialize the chipset - */ -static int tms380tr_chipset_init(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - int err; - - tms380tr_init_ipb(tp); - tms380tr_init_opb(dev); - tms380tr_init_net_local(dev); - - if(tms380tr_debug > 3) - printk(KERN_DEBUG "%s: Resetting adapter...\n", dev->name); - err = tms380tr_reset_adapter(dev); - if(err < 0) - return -1; - - if(tms380tr_debug > 3) - printk(KERN_DEBUG "%s: Bringup diags...\n", dev->name); - err = tms380tr_bringup_diags(dev); - if(err < 0) - return -1; - - if(tms380tr_debug > 3) - printk(KERN_DEBUG "%s: Init adapter...\n", dev->name); - err = tms380tr_init_adapter(dev); - if(err < 0) - return -1; - - if(tms380tr_debug > 3) - printk(KERN_DEBUG "%s: Done!\n", dev->name); - return 0; -} - -/* - * Initializes the net_local structure. - */ -static void tms380tr_init_net_local(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - int i; - dma_addr_t dmabuf; - - tp->scb.CMD = 0; - tp->scb.Parm[0] = 0; - tp->scb.Parm[1] = 0; - - tp->ssb.STS = 0; - tp->ssb.Parm[0] = 0; - tp->ssb.Parm[1] = 0; - tp->ssb.Parm[2] = 0; - - tp->CMDqueue = 0; - - tp->AdapterOpenFlag = 0; - tp->AdapterVirtOpenFlag = 0; - tp->ScbInUse = 0; - tp->OpenCommandIssued = 0; - tp->ReOpenInProgress = 0; - tp->HaltInProgress = 0; - tp->TransmitHaltScheduled = 0; - tp->LobeWireFaultLogged = 0; - tp->LastOpenStatus = 0; - tp->MaxPacketSize = DEFAULT_PACKET_SIZE; - - /* Create circular chain of transmit lists */ - for (i = 0; i < TPL_NUM; i++) - { - tp->Tpl[i].NextTPLAddr = htonl(((char *)(&tp->Tpl[(i+1) % TPL_NUM]) - (char *)tp) + tp->dmabuffer); /* DMA buffer may be MMU driven */ - tp->Tpl[i].Status = 0; - tp->Tpl[i].FrameSize = 0; - tp->Tpl[i].FragList[0].DataCount = 0; - tp->Tpl[i].FragList[0].DataAddr = 0; - tp->Tpl[i].NextTPLPtr = &tp->Tpl[(i+1) % TPL_NUM]; - tp->Tpl[i].MData = NULL; - tp->Tpl[i].TPLIndex = i; - tp->Tpl[i].DMABuff = 0; - tp->Tpl[i].BusyFlag = 0; - } - - tp->TplFree = tp->TplBusy = &tp->Tpl[0]; - - /* Create circular chain of receive lists */ - for (i = 0; i < RPL_NUM; i++) - { - tp->Rpl[i].NextRPLAddr = htonl(((char *)(&tp->Rpl[(i+1) % RPL_NUM]) - (char *)tp) + tp->dmabuffer); /* DMA buffer may be MMU driven */ - tp->Rpl[i].Status = (RX_VALID | RX_START_FRAME | RX_END_FRAME | RX_FRAME_IRQ); - tp->Rpl[i].FrameSize = 0; - tp->Rpl[i].FragList[0].DataCount = cpu_to_be16((unsigned short)tp->MaxPacketSize); - - /* Alloc skb and point adapter to data area */ - tp->Rpl[i].Skb = dev_alloc_skb(tp->MaxPacketSize); - tp->Rpl[i].DMABuff = 0; - - /* skb == NULL ? then use local buffer */ - if(tp->Rpl[i].Skb == NULL) - { - tp->Rpl[i].SkbStat = SKB_UNAVAILABLE; - tp->Rpl[i].FragList[0].DataAddr = htonl(((char *)tp->LocalRxBuffers[i] - (char *)tp) + tp->dmabuffer); - tp->Rpl[i].MData = tp->LocalRxBuffers[i]; - } - else /* SKB != NULL */ - { - tp->Rpl[i].Skb->dev = dev; - skb_put(tp->Rpl[i].Skb, tp->MaxPacketSize); - - /* data unreachable for DMA ? then use local buffer */ - dmabuf = dma_map_single(tp->pdev, tp->Rpl[i].Skb->data, tp->MaxPacketSize, DMA_FROM_DEVICE); - if(tp->dmalimit && (dmabuf + tp->MaxPacketSize > tp->dmalimit)) - { - tp->Rpl[i].SkbStat = SKB_DATA_COPY; - tp->Rpl[i].FragList[0].DataAddr = htonl(((char *)tp->LocalRxBuffers[i] - (char *)tp) + tp->dmabuffer); - tp->Rpl[i].MData = tp->LocalRxBuffers[i]; - } - else /* DMA directly in skb->data */ - { - tp->Rpl[i].SkbStat = SKB_DMA_DIRECT; - tp->Rpl[i].FragList[0].DataAddr = htonl(dmabuf); - tp->Rpl[i].MData = tp->Rpl[i].Skb->data; - tp->Rpl[i].DMABuff = dmabuf; - } - } - - tp->Rpl[i].NextRPLPtr = &tp->Rpl[(i+1) % RPL_NUM]; - tp->Rpl[i].RPLIndex = i; - } - - tp->RplHead = &tp->Rpl[0]; - tp->RplTail = &tp->Rpl[RPL_NUM-1]; - tp->RplTail->Status = (RX_START_FRAME | RX_END_FRAME | RX_FRAME_IRQ); -} - -/* - * Initializes the initialisation parameter block. - */ -static void tms380tr_init_ipb(struct net_local *tp) -{ - tp->ipb.Init_Options = BURST_MODE; - tp->ipb.CMD_Status_IV = 0; - tp->ipb.TX_IV = 0; - tp->ipb.RX_IV = 0; - tp->ipb.Ring_Status_IV = 0; - tp->ipb.SCB_Clear_IV = 0; - tp->ipb.Adapter_CHK_IV = 0; - tp->ipb.RX_Burst_Size = BURST_SIZE; - tp->ipb.TX_Burst_Size = BURST_SIZE; - tp->ipb.DMA_Abort_Thrhld = DMA_RETRIES; - tp->ipb.SCB_Addr = 0; - tp->ipb.SSB_Addr = 0; -} - -/* - * Initializes the open parameter block. - */ -static void tms380tr_init_opb(struct net_device *dev) -{ - struct net_local *tp; - unsigned long Addr; - unsigned short RplSize = RPL_SIZE; - unsigned short TplSize = TPL_SIZE; - unsigned short BufferSize = BUFFER_SIZE; - int i; - - tp = netdev_priv(dev); - - tp->ocpl.OPENOptions = 0; - tp->ocpl.OPENOptions |= ENABLE_FULL_DUPLEX_SELECTION; - tp->ocpl.FullDuplex = 0; - tp->ocpl.FullDuplex |= OPEN_FULL_DUPLEX_OFF; - - /* - * Set node address - * - * We go ahead and put it in the OPB even though on - * most of the generic adapters this isn't required. - * Its simpler this way. -- ASF - */ - for (i=0;i<6;i++) - tp->ocpl.NodeAddr[i] = ((unsigned char *)dev->dev_addr)[i]; - - tp->ocpl.GroupAddr = 0; - tp->ocpl.FunctAddr = 0; - tp->ocpl.RxListSize = cpu_to_be16((unsigned short)RplSize); - tp->ocpl.TxListSize = cpu_to_be16((unsigned short)TplSize); - tp->ocpl.BufSize = cpu_to_be16((unsigned short)BufferSize); - tp->ocpl.Reserved = 0; - tp->ocpl.TXBufMin = TX_BUF_MIN; - tp->ocpl.TXBufMax = TX_BUF_MAX; - - Addr = htonl(((char *)tp->ProductID - (char *)tp) + tp->dmabuffer); - - tp->ocpl.ProdIDAddr[0] = LOWORD(Addr); - tp->ocpl.ProdIDAddr[1] = HIWORD(Addr); -} - -/* - * Send OPEN command to adapter - */ -static void tms380tr_open_adapter(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - - if(tp->OpenCommandIssued) - return; - - tp->OpenCommandIssued = 1; - tms380tr_exec_cmd(dev, OC_OPEN); -} - -/* - * Clear the adapter's interrupt flag. Clear system interrupt enable - * (SINTEN): disable adapter to system interrupts. - */ -static void tms380tr_disable_interrupts(struct net_device *dev) -{ - SIFWRITEB(0, SIFACL); -} - -/* - * Set the adapter's interrupt flag. Set system interrupt enable - * (SINTEN): enable adapter to system interrupts. - */ -static void tms380tr_enable_interrupts(struct net_device *dev) -{ - SIFWRITEB(ACL_SINTEN, SIFACL); -} - -/* - * Put command in command queue, try to execute it. - */ -static void tms380tr_exec_cmd(struct net_device *dev, unsigned short Command) -{ - struct net_local *tp = netdev_priv(dev); - - tp->CMDqueue |= Command; - tms380tr_chk_outstanding_cmds(dev); -} - -static void tms380tr_timeout(struct net_device *dev) -{ - /* - * If we get here, some higher level has decided we are broken. - * There should really be a "kick me" function call instead. - * - * Resetting the token ring adapter takes a long time so just - * fake transmission time and go on trying. Our own timeout - * routine is in tms380tr_timer_chk() - */ - dev->trans_start = jiffies; /* prevent tx timeout */ - netif_wake_queue(dev); -} - -/* - * Gets skb from system, queues it and checks if it can be sent - */ -static netdev_tx_t tms380tr_send_packet(struct sk_buff *skb, - struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - netdev_tx_t rc; - - rc = tms380tr_hardware_send_packet(skb, dev); - if(tp->TplFree->NextTPLPtr->BusyFlag) - netif_stop_queue(dev); - return rc; -} - -/* - * Move frames into adapter tx queue - */ -static netdev_tx_t tms380tr_hardware_send_packet(struct sk_buff *skb, - struct net_device *dev) -{ - TPL *tpl; - short length; - unsigned char *buf; - unsigned long flags; - int i; - dma_addr_t dmabuf, newbuf; - struct net_local *tp = netdev_priv(dev); - - /* Try to get a free TPL from the chain. - * - * NOTE: We *must* always leave one unused TPL in the chain, - * because otherwise the adapter might send frames twice. - */ - spin_lock_irqsave(&tp->lock, flags); - if(tp->TplFree->NextTPLPtr->BusyFlag) { /* No free TPL */ - if (tms380tr_debug > 0) - printk(KERN_DEBUG "%s: No free TPL\n", dev->name); - spin_unlock_irqrestore(&tp->lock, flags); - return NETDEV_TX_BUSY; - } - - dmabuf = 0; - - /* Is buffer reachable for Busmaster-DMA? */ - - length = skb->len; - dmabuf = dma_map_single(tp->pdev, skb->data, length, DMA_TO_DEVICE); - if(tp->dmalimit && (dmabuf + length > tp->dmalimit)) { - /* Copy frame to local buffer */ - dma_unmap_single(tp->pdev, dmabuf, length, DMA_TO_DEVICE); - dmabuf = 0; - i = tp->TplFree->TPLIndex; - buf = tp->LocalTxBuffers[i]; - skb_copy_from_linear_data(skb, buf, length); - newbuf = ((char *)buf - (char *)tp) + tp->dmabuffer; - } - else { - /* Send direct from skb->data */ - newbuf = dmabuf; - buf = skb->data; - } - /* Source address in packet? */ - tms380tr_chk_src_addr(buf, dev->dev_addr); - tp->LastSendTime = jiffies; - tpl = tp->TplFree; /* Get the "free" TPL */ - tpl->BusyFlag = 1; /* Mark TPL as busy */ - tp->TplFree = tpl->NextTPLPtr; - - /* Save the skb for delayed return of skb to system */ - tpl->Skb = skb; - tpl->DMABuff = dmabuf; - tpl->FragList[0].DataCount = cpu_to_be16((unsigned short)length); - tpl->FragList[0].DataAddr = htonl(newbuf); - - /* Write the data length in the transmit list. */ - tpl->FrameSize = cpu_to_be16((unsigned short)length); - tpl->MData = buf; - - /* Transmit the frame and set the status values. */ - tms380tr_write_tpl_status(tpl, TX_VALID | TX_START_FRAME - | TX_END_FRAME | TX_PASS_SRC_ADDR - | TX_FRAME_IRQ); - - /* Let adapter send the frame. */ - tms380tr_exec_sifcmd(dev, CMD_TX_VALID); - spin_unlock_irqrestore(&tp->lock, flags); - - return NETDEV_TX_OK; -} - -/* - * Write the given value to the 'Status' field of the specified TPL. - * NOTE: This function should be used whenever the status of any TPL must be - * modified by the driver, because the compiler may otherwise change the - * order of instructions such that writing the TPL status may be executed at - * an undesirable time. When this function is used, the status is always - * written when the function is called. - */ -static void tms380tr_write_tpl_status(TPL *tpl, unsigned int Status) -{ - tpl->Status = Status; -} - -static void tms380tr_chk_src_addr(unsigned char *frame, unsigned char *hw_addr) -{ - unsigned char SRBit; - - if((((unsigned long)frame[8]) & ~0x80) != 0) /* Compare 4 bytes */ - return; - if((unsigned short)frame[12] != 0) /* Compare 2 bytes */ - return; - - SRBit = frame[8] & 0x80; - memcpy(&frame[8], hw_addr, 6); - frame[8] |= SRBit; -} - -/* - * The timer routine: Check if adapter still open and working, reopen if not. - */ -static void tms380tr_timer_chk(unsigned long data) -{ - struct net_device *dev = (struct net_device*)data; - struct net_local *tp = netdev_priv(dev); - - if(tp->HaltInProgress) - return; - - tms380tr_chk_outstanding_cmds(dev); - if(time_before(tp->LastSendTime + SEND_TIMEOUT, jiffies) && - (tp->TplFree != tp->TplBusy)) - { - /* Anything to send, but stalled too long */ - tp->LastSendTime = jiffies; - tms380tr_exec_cmd(dev, OC_CLOSE); /* Does reopen automatically */ - } - - tp->timer.expires = jiffies + 2*HZ; - add_timer(&tp->timer); - - if(tp->AdapterOpenFlag || tp->ReOpenInProgress) - return; - tp->ReOpenInProgress = 1; - tms380tr_open_adapter(dev); -} - -/* - * The typical workload of the driver: Handle the network interface interrupts. - */ -irqreturn_t tms380tr_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct net_local *tp; - unsigned short irq_type; - int handled = 0; - - tp = netdev_priv(dev); - - irq_type = SIFREADW(SIFSTS); - - while(irq_type & STS_SYSTEM_IRQ) { - handled = 1; - irq_type &= STS_IRQ_MASK; - - if(!tms380tr_chk_ssb(tp, irq_type)) { - printk(KERN_DEBUG "%s: DATA LATE occurred\n", dev->name); - break; - } - - switch(irq_type) { - case STS_IRQ_RECEIVE_STATUS: - tms380tr_reset_interrupt(dev); - tms380tr_rcv_status_irq(dev); - break; - - case STS_IRQ_TRANSMIT_STATUS: - /* Check if TRANSMIT.HALT command is complete */ - if(tp->ssb.Parm[0] & COMMAND_COMPLETE) { - tp->TransmitCommandActive = 0; - tp->TransmitHaltScheduled = 0; - - /* Issue a new transmit command. */ - tms380tr_exec_cmd(dev, OC_TRANSMIT); - } - - tms380tr_reset_interrupt(dev); - tms380tr_tx_status_irq(dev); - break; - - case STS_IRQ_COMMAND_STATUS: - /* The SSB contains status of last command - * other than receive/transmit. - */ - tms380tr_cmd_status_irq(dev); - break; - - case STS_IRQ_SCB_CLEAR: - /* The SCB is free for another command. */ - tp->ScbInUse = 0; - tms380tr_chk_outstanding_cmds(dev); - break; - - case STS_IRQ_RING_STATUS: - tms380tr_ring_status_irq(dev); - break; - - case STS_IRQ_ADAPTER_CHECK: - tms380tr_chk_irq(dev); - break; - - case STS_IRQ_LLC_STATUS: - printk(KERN_DEBUG "tms380tr: unexpected LLC status IRQ\n"); - break; - - case STS_IRQ_TIMER: - printk(KERN_DEBUG "tms380tr: unexpected Timer IRQ\n"); - break; - - case STS_IRQ_RECEIVE_PENDING: - printk(KERN_DEBUG "tms380tr: unexpected Receive Pending IRQ\n"); - break; - - default: - printk(KERN_DEBUG "Unknown Token Ring IRQ (0x%04x)\n", irq_type); - break; - } - - /* Reset system interrupt if not already done. */ - if(irq_type != STS_IRQ_TRANSMIT_STATUS && - irq_type != STS_IRQ_RECEIVE_STATUS) { - tms380tr_reset_interrupt(dev); - } - - irq_type = SIFREADW(SIFSTS); - } - - return IRQ_RETVAL(handled); -} - -/* - * Reset the INTERRUPT SYSTEM bit and issue SSB CLEAR command. - */ -static void tms380tr_reset_interrupt(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - SSB *ssb = &tp->ssb; - - /* - * [Workaround for "Data Late"] - * Set all fields of the SSB to well-defined values so we can - * check if the adapter has written the SSB. - */ - - ssb->STS = (unsigned short) -1; - ssb->Parm[0] = (unsigned short) -1; - ssb->Parm[1] = (unsigned short) -1; - ssb->Parm[2] = (unsigned short) -1; - - /* Free SSB by issuing SSB_CLEAR command after reading IRQ code - * and clear STS_SYSTEM_IRQ bit: enable adapter for further interrupts. - */ - tms380tr_exec_sifcmd(dev, CMD_SSB_CLEAR | CMD_CLEAR_SYSTEM_IRQ); -} - -/* - * Check if the SSB has actually been written by the adapter. - */ -static unsigned char tms380tr_chk_ssb(struct net_local *tp, unsigned short IrqType) -{ - SSB *ssb = &tp->ssb; /* The address of the SSB. */ - - /* C 0 1 2 INTERRUPT CODE - * - - - - -------------- - * 1 1 1 1 TRANSMIT STATUS - * 1 1 1 1 RECEIVE STATUS - * 1 ? ? 0 COMMAND STATUS - * 0 0 0 0 SCB CLEAR - * 1 1 0 0 RING STATUS - * 0 0 0 0 ADAPTER CHECK - * - * 0 = SSB field not affected by interrupt - * 1 = SSB field is affected by interrupt - * - * C = SSB ADDRESS +0: COMMAND - * 0 = SSB ADDRESS +2: STATUS 0 - * 1 = SSB ADDRESS +4: STATUS 1 - * 2 = SSB ADDRESS +6: STATUS 2 - */ - - /* Check if this interrupt does use the SSB. */ - - if(IrqType != STS_IRQ_TRANSMIT_STATUS && - IrqType != STS_IRQ_RECEIVE_STATUS && - IrqType != STS_IRQ_COMMAND_STATUS && - IrqType != STS_IRQ_RING_STATUS) - { - return 1; /* SSB not involved. */ - } - - /* Note: All fields of the SSB have been set to all ones (-1) after it - * has last been used by the software (see DriverIsr()). - * - * Check if the affected SSB fields are still unchanged. - */ - - if(ssb->STS == (unsigned short) -1) - return 0; /* Command field not yet available. */ - if(IrqType == STS_IRQ_COMMAND_STATUS) - return 1; /* Status fields not always affected. */ - if(ssb->Parm[0] == (unsigned short) -1) - return 0; /* Status 1 field not yet available. */ - if(IrqType == STS_IRQ_RING_STATUS) - return 1; /* Status 2 & 3 fields not affected. */ - - /* Note: At this point, the interrupt is either TRANSMIT or RECEIVE. */ - if(ssb->Parm[1] == (unsigned short) -1) - return 0; /* Status 2 field not yet available. */ - if(ssb->Parm[2] == (unsigned short) -1) - return 0; /* Status 3 field not yet available. */ - - return 1; /* All SSB fields have been written by the adapter. */ -} - -/* - * Evaluates the command results status in the SSB status field. - */ -static void tms380tr_cmd_status_irq(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - unsigned short ssb_cmd, ssb_parm_0; - unsigned short ssb_parm_1; - char *open_err = "Open error -"; - char *code_err = "Open code -"; - - /* Copy the ssb values to local variables */ - ssb_cmd = tp->ssb.STS; - ssb_parm_0 = tp->ssb.Parm[0]; - ssb_parm_1 = tp->ssb.Parm[1]; - - if(ssb_cmd == OPEN) - { - tp->Sleeping = 0; - if(!tp->ReOpenInProgress) - wake_up_interruptible(&tp->wait_for_tok_int); - - tp->OpenCommandIssued = 0; - tp->ScbInUse = 0; - - if((ssb_parm_0 & 0x00FF) == GOOD_COMPLETION) - { - /* Success, the adapter is open. */ - tp->LobeWireFaultLogged = 0; - tp->AdapterOpenFlag = 1; - tp->AdapterVirtOpenFlag = 1; - tp->TransmitCommandActive = 0; - tms380tr_exec_cmd(dev, OC_TRANSMIT); - tms380tr_exec_cmd(dev, OC_RECEIVE); - - if(tp->ReOpenInProgress) - tp->ReOpenInProgress = 0; - - return; - } - else /* The adapter did not open. */ - { - if(ssb_parm_0 & NODE_ADDR_ERROR) - printk(KERN_INFO "%s: Node address error\n", - dev->name); - if(ssb_parm_0 & LIST_SIZE_ERROR) - printk(KERN_INFO "%s: List size error\n", - dev->name); - if(ssb_parm_0 & BUF_SIZE_ERROR) - printk(KERN_INFO "%s: Buffer size error\n", - dev->name); - if(ssb_parm_0 & TX_BUF_COUNT_ERROR) - printk(KERN_INFO "%s: Tx buffer count error\n", - dev->name); - if(ssb_parm_0 & INVALID_OPEN_OPTION) - printk(KERN_INFO "%s: Invalid open option\n", - dev->name); - if(ssb_parm_0 & OPEN_ERROR) - { - /* Show the open phase. */ - switch(ssb_parm_0 & OPEN_PHASES_MASK) - { - case LOBE_MEDIA_TEST: - if(!tp->LobeWireFaultLogged) - { - tp->LobeWireFaultLogged = 1; - printk(KERN_INFO "%s: %s Lobe wire fault (check cable !).\n", dev->name, open_err); - } - tp->ReOpenInProgress = 1; - tp->AdapterOpenFlag = 0; - tp->AdapterVirtOpenFlag = 1; - tms380tr_open_adapter(dev); - return; - - case PHYSICAL_INSERTION: - printk(KERN_INFO "%s: %s Physical insertion.\n", dev->name, open_err); - break; - - case ADDRESS_VERIFICATION: - printk(KERN_INFO "%s: %s Address verification.\n", dev->name, open_err); - break; - - case PARTICIPATION_IN_RING_POLL: - printk(KERN_INFO "%s: %s Participation in ring poll.\n", dev->name, open_err); - break; - - case REQUEST_INITIALISATION: - printk(KERN_INFO "%s: %s Request initialisation.\n", dev->name, open_err); - break; - - case FULLDUPLEX_CHECK: - printk(KERN_INFO "%s: %s Full duplex check.\n", dev->name, open_err); - break; - - default: - printk(KERN_INFO "%s: %s Unknown open phase\n", dev->name, open_err); - break; - } - - /* Show the open errors. */ - switch(ssb_parm_0 & OPEN_ERROR_CODES_MASK) - { - case OPEN_FUNCTION_FAILURE: - printk(KERN_INFO "%s: %s OPEN_FUNCTION_FAILURE", dev->name, code_err); - tp->LastOpenStatus = - OPEN_FUNCTION_FAILURE; - break; - - case OPEN_SIGNAL_LOSS: - printk(KERN_INFO "%s: %s OPEN_SIGNAL_LOSS\n", dev->name, code_err); - tp->LastOpenStatus = - OPEN_SIGNAL_LOSS; - break; - - case OPEN_TIMEOUT: - printk(KERN_INFO "%s: %s OPEN_TIMEOUT\n", dev->name, code_err); - tp->LastOpenStatus = - OPEN_TIMEOUT; - break; - - case OPEN_RING_FAILURE: - printk(KERN_INFO "%s: %s OPEN_RING_FAILURE\n", dev->name, code_err); - tp->LastOpenStatus = - OPEN_RING_FAILURE; - break; - - case OPEN_RING_BEACONING: - printk(KERN_INFO "%s: %s OPEN_RING_BEACONING\n", dev->name, code_err); - tp->LastOpenStatus = - OPEN_RING_BEACONING; - break; - - case OPEN_DUPLICATE_NODEADDR: - printk(KERN_INFO "%s: %s OPEN_DUPLICATE_NODEADDR\n", dev->name, code_err); - tp->LastOpenStatus = - OPEN_DUPLICATE_NODEADDR; - break; - - case OPEN_REQUEST_INIT: - printk(KERN_INFO "%s: %s OPEN_REQUEST_INIT\n", dev->name, code_err); - tp->LastOpenStatus = - OPEN_REQUEST_INIT; - break; - - case OPEN_REMOVE_RECEIVED: - printk(KERN_INFO "%s: %s OPEN_REMOVE_RECEIVED", dev->name, code_err); - tp->LastOpenStatus = - OPEN_REMOVE_RECEIVED; - break; - - case OPEN_FULLDUPLEX_SET: - printk(KERN_INFO "%s: %s OPEN_FULLDUPLEX_SET\n", dev->name, code_err); - tp->LastOpenStatus = - OPEN_FULLDUPLEX_SET; - break; - - default: - printk(KERN_INFO "%s: %s Unknown open err code", dev->name, code_err); - tp->LastOpenStatus = - OPEN_FUNCTION_FAILURE; - break; - } - } - - tp->AdapterOpenFlag = 0; - tp->AdapterVirtOpenFlag = 0; - - return; - } - } - else - { - if(ssb_cmd != READ_ERROR_LOG) - return; - - /* Add values from the error log table to the MAC - * statistics counters and update the errorlogtable - * memory. - */ - tp->MacStat.line_errors += tp->errorlogtable.Line_Error; - tp->MacStat.burst_errors += tp->errorlogtable.Burst_Error; - tp->MacStat.A_C_errors += tp->errorlogtable.ARI_FCI_Error; - tp->MacStat.lost_frames += tp->errorlogtable.Lost_Frame_Error; - tp->MacStat.recv_congest_count += tp->errorlogtable.Rx_Congest_Error; - tp->MacStat.rx_errors += tp->errorlogtable.Rx_Congest_Error; - tp->MacStat.frame_copied_errors += tp->errorlogtable.Frame_Copied_Error; - tp->MacStat.token_errors += tp->errorlogtable.Token_Error; - tp->MacStat.dummy1 += tp->errorlogtable.DMA_Bus_Error; - tp->MacStat.dummy1 += tp->errorlogtable.DMA_Parity_Error; - tp->MacStat.abort_delimiters += tp->errorlogtable.AbortDelimeters; - tp->MacStat.frequency_errors += tp->errorlogtable.Frequency_Error; - tp->MacStat.internal_errors += tp->errorlogtable.Internal_Error; - } -} - -/* - * The inverse routine to tms380tr_open(). - */ -int tms380tr_close(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - netif_stop_queue(dev); - - del_timer(&tp->timer); - - /* Flush the Tx and disable Rx here. */ - - tp->HaltInProgress = 1; - tms380tr_exec_cmd(dev, OC_CLOSE); - tp->timer.expires = jiffies + 1*HZ; - tp->timer.function = tms380tr_timer_end_wait; - tp->timer.data = (unsigned long)dev; - add_timer(&tp->timer); - - tms380tr_enable_interrupts(dev); - - tp->Sleeping = 1; - interruptible_sleep_on(&tp->wait_for_tok_int); - tp->TransmitCommandActive = 0; - - del_timer(&tp->timer); - tms380tr_disable_interrupts(dev); - -#ifdef CONFIG_ISA - if(dev->dma > 0) - { - unsigned long flags=claim_dma_lock(); - disable_dma(dev->dma); - release_dma_lock(flags); - } -#endif - - SIFWRITEW(0xFF00, SIFCMD); -#if 0 - if(dev->dma > 0) /* what the? */ - SIFWRITEB(0xff, POSREG); -#endif - tms380tr_cancel_tx_queue(tp); - - return 0; -} - -/* - * Get the current statistics. This may be called with the card open - * or closed. - */ -static struct net_device_stats *tms380tr_get_stats(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - - return (struct net_device_stats *)&tp->MacStat; -} - -/* - * Set or clear the multicast filter for this adapter. - */ -static void tms380tr_set_multicast_list(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - unsigned int OpenOptions; - - OpenOptions = tp->ocpl.OPENOptions & - ~(PASS_ADAPTER_MAC_FRAMES - | PASS_ATTENTION_FRAMES - | PASS_BEACON_MAC_FRAMES - | COPY_ALL_MAC_FRAMES - | COPY_ALL_NON_MAC_FRAMES); - - tp->ocpl.FunctAddr = 0; - - if(dev->flags & IFF_PROMISC) - /* Enable promiscuous mode */ - OpenOptions |= COPY_ALL_NON_MAC_FRAMES | - COPY_ALL_MAC_FRAMES; - else - { - if(dev->flags & IFF_ALLMULTI) - { - /* Disable promiscuous mode, use normal mode. */ - tp->ocpl.FunctAddr = 0xFFFFFFFF; - } - else - { - struct netdev_hw_addr *ha; - - netdev_for_each_mc_addr(ha, dev) { - ((char *)(&tp->ocpl.FunctAddr))[0] |= - ha->addr[2]; - ((char *)(&tp->ocpl.FunctAddr))[1] |= - ha->addr[3]; - ((char *)(&tp->ocpl.FunctAddr))[2] |= - ha->addr[4]; - ((char *)(&tp->ocpl.FunctAddr))[3] |= - ha->addr[5]; - } - } - tms380tr_exec_cmd(dev, OC_SET_FUNCT_ADDR); - } - - tp->ocpl.OPENOptions = OpenOptions; - tms380tr_exec_cmd(dev, OC_MODIFY_OPEN_PARMS); -} - -/* - * Wait for some time (microseconds) - */ -void tms380tr_wait(unsigned long time) -{ -#if 0 - long tmp; - - tmp = jiffies + time/(1000000/HZ); - do { - tmp = schedule_timeout_interruptible(tmp); - } while(time_after(tmp, jiffies)); -#else - mdelay(time / 1000); -#endif -} - -/* - * Write a command value to the SIFCMD register - */ -static void tms380tr_exec_sifcmd(struct net_device *dev, unsigned int WriteValue) -{ - unsigned short cmd; - unsigned short SifStsValue; - unsigned long loop_counter; - - WriteValue = ((WriteValue ^ CMD_SYSTEM_IRQ) | CMD_INTERRUPT_ADAPTER); - cmd = (unsigned short)WriteValue; - loop_counter = 0,5 * 800000; - do { - SifStsValue = SIFREADW(SIFSTS); - } while((SifStsValue & CMD_INTERRUPT_ADAPTER) && loop_counter--); - SIFWRITEW(cmd, SIFCMD); -} - -/* - * Processes adapter hardware reset, halts adapter and downloads firmware, - * clears the halt bit. - */ -static int tms380tr_reset_adapter(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - unsigned short *fw_ptr; - unsigned short count, c, count2; - const struct firmware *fw_entry = NULL; - - if (request_firmware(&fw_entry, "tms380tr.bin", tp->pdev) != 0) { - printk(KERN_ALERT "%s: firmware %s is missing, cannot start.\n", - dev->name, "tms380tr.bin"); - return -1; - } - - fw_ptr = (unsigned short *)fw_entry->data; - count2 = fw_entry->size / 2; - - /* Hardware adapter reset */ - SIFWRITEW(ACL_ARESET, SIFACL); - tms380tr_wait(40); - - c = SIFREADW(SIFACL); - tms380tr_wait(20); - - if(dev->dma == 0) /* For PCI adapters */ - { - c &= ~(ACL_NSELOUT0 | ACL_NSELOUT1); /* Clear bits */ - if(tp->setnselout) - c |= (*tp->setnselout)(dev); - } - - /* In case a command is pending - forget it */ - tp->ScbInUse = 0; - - c &= ~ACL_ARESET; /* Clear adapter reset bit */ - c |= ACL_CPHALT; /* Halt adapter CPU, allow download */ - c |= ACL_BOOT; - c |= ACL_SINTEN; - c &= ~ACL_PSDMAEN; /* Clear pseudo dma bit */ - SIFWRITEW(c, SIFACL); - tms380tr_wait(40); - - count = 0; - /* Download firmware via DIO interface: */ - do { - if (count2 < 3) continue; - - /* Download first address part */ - SIFWRITEW(*fw_ptr, SIFADX); - fw_ptr++; - count2--; - /* Download second address part */ - SIFWRITEW(*fw_ptr, SIFADD); - fw_ptr++; - count2--; - - if((count = *fw_ptr) != 0) /* Load loop counter */ - { - fw_ptr++; /* Download block data */ - count2--; - if (count > count2) continue; - - for(; count > 0; count--) - { - SIFWRITEW(*fw_ptr, SIFINC); - fw_ptr++; - count2--; - } - } - else /* Stop, if last block downloaded */ - { - c = SIFREADW(SIFACL); - c &= (~ACL_CPHALT | ACL_SINTEN); - - /* Clear CPHALT and start BUD */ - SIFWRITEW(c, SIFACL); - release_firmware(fw_entry); - return 1; - } - } while(count == 0); - - release_firmware(fw_entry); - printk(KERN_INFO "%s: Adapter Download Failed\n", dev->name); - return -1; -} - -MODULE_FIRMWARE("tms380tr.bin"); - -/* - * Starts bring up diagnostics of token ring adapter and evaluates - * diagnostic results. - */ -static int tms380tr_bringup_diags(struct net_device *dev) -{ - int loop_cnt, retry_cnt; - unsigned short Status; - - tms380tr_wait(HALF_SECOND); - tms380tr_exec_sifcmd(dev, EXEC_SOFT_RESET); - tms380tr_wait(HALF_SECOND); - - retry_cnt = BUD_MAX_RETRIES; /* maximal number of retrys */ - - do { - retry_cnt--; - if(tms380tr_debug > 3) - printk(KERN_DEBUG "BUD-Status: "); - loop_cnt = BUD_MAX_LOOPCNT; /* maximum: three seconds*/ - do { /* Inspect BUD results */ - loop_cnt--; - tms380tr_wait(HALF_SECOND); - Status = SIFREADW(SIFSTS); - Status &= STS_MASK; - - if(tms380tr_debug > 3) - printk(KERN_DEBUG " %04X\n", Status); - /* BUD successfully completed */ - if(Status == STS_INITIALIZE) - return 1; - /* Unrecoverable hardware error, BUD not completed? */ - } while((loop_cnt > 0) && ((Status & (STS_ERROR | STS_TEST)) - != (STS_ERROR | STS_TEST))); - - /* Error preventing completion of BUD */ - if(retry_cnt > 0) - { - printk(KERN_INFO "%s: Adapter Software Reset.\n", - dev->name); - tms380tr_exec_sifcmd(dev, EXEC_SOFT_RESET); - tms380tr_wait(HALF_SECOND); - } - } while(retry_cnt > 0); - - Status = SIFREADW(SIFSTS); - - printk(KERN_INFO "%s: Hardware error\n", dev->name); - /* Hardware error occurred! */ - Status &= 0x001f; - if (Status & 0x0010) - printk(KERN_INFO "%s: BUD Error: Timeout\n", dev->name); - else if ((Status & 0x000f) > 6) - printk(KERN_INFO "%s: BUD Error: Illegal Failure\n", dev->name); - else - printk(KERN_INFO "%s: Bring Up Diagnostics Error (%04X) occurred\n", dev->name, Status & 0x000f); - - return -1; -} - -/* - * Copy initialisation data to adapter memory, beginning at address - * 1:0A00; Starting DMA test and evaluating result bits. - */ -static int tms380tr_init_adapter(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - - const unsigned char SCB_Test[6] = {0x00, 0x00, 0xC1, 0xE2, 0xD4, 0x8B}; - const unsigned char SSB_Test[8] = {0xFF, 0xFF, 0xD1, 0xD7, - 0xC5, 0xD9, 0xC3, 0xD4}; - void *ptr = (void *)&tp->ipb; - unsigned short *ipb_ptr = (unsigned short *)ptr; - unsigned char *cb_ptr = (unsigned char *) &tp->scb; - unsigned char *sb_ptr = (unsigned char *) &tp->ssb; - unsigned short Status; - int i, loop_cnt, retry_cnt; - - /* Normalize: byte order low/high, word order high/low! (only IPB!) */ - tp->ipb.SCB_Addr = SWAPW(((char *)&tp->scb - (char *)tp) + tp->dmabuffer); - tp->ipb.SSB_Addr = SWAPW(((char *)&tp->ssb - (char *)tp) + tp->dmabuffer); - - if(tms380tr_debug > 3) - { - printk(KERN_DEBUG "%s: buffer (real): %lx\n", dev->name, (long) &tp->scb); - printk(KERN_DEBUG "%s: buffer (virt): %lx\n", dev->name, (long) ((char *)&tp->scb - (char *)tp) + (long) tp->dmabuffer); - printk(KERN_DEBUG "%s: buffer (DMA) : %lx\n", dev->name, (long) tp->dmabuffer); - printk(KERN_DEBUG "%s: buffer (tp) : %lx\n", dev->name, (long) tp); - } - /* Maximum: three initialization retries */ - retry_cnt = INIT_MAX_RETRIES; - - do { - retry_cnt--; - - /* Transfer initialization block */ - SIFWRITEW(0x0001, SIFADX); - - /* To address 0001:0A00 of adapter RAM */ - SIFWRITEW(0x0A00, SIFADD); - - /* Write 11 words to adapter RAM */ - for(i = 0; i < 11; i++) - SIFWRITEW(ipb_ptr[i], SIFINC); - - /* Execute SCB adapter command */ - tms380tr_exec_sifcmd(dev, CMD_EXECUTE); - - loop_cnt = INIT_MAX_LOOPCNT; /* Maximum: 11 seconds */ - - /* While remaining retries, no error and not completed */ - do { - Status = 0; - loop_cnt--; - tms380tr_wait(HALF_SECOND); - - /* Mask interesting status bits */ - Status = SIFREADW(SIFSTS); - Status &= STS_MASK; - } while(((Status &(STS_INITIALIZE | STS_ERROR | STS_TEST)) != 0) && - ((Status & STS_ERROR) == 0) && (loop_cnt != 0)); - - if((Status & (STS_INITIALIZE | STS_ERROR | STS_TEST)) == 0) - { - /* Initialization completed without error */ - i = 0; - do { /* Test if contents of SCB is valid */ - if(SCB_Test[i] != *(cb_ptr + i)) - { - printk(KERN_INFO "%s: DMA failed\n", dev->name); - /* DMA data error: wrong data in SCB */ - return -1; - } - i++; - } while(i < 6); - - i = 0; - do { /* Test if contents of SSB is valid */ - if(SSB_Test[i] != *(sb_ptr + i)) - /* DMA data error: wrong data in SSB */ - return -1; - i++; - } while (i < 8); - - return 1; /* Adapter successfully initialized */ - } - else - { - if((Status & STS_ERROR) != 0) - { - /* Initialization error occurred */ - Status = SIFREADW(SIFSTS); - Status &= STS_ERROR_MASK; - /* ShowInitialisationErrorCode(Status); */ - printk(KERN_INFO "%s: Status error: %d\n", dev->name, Status); - return -1; /* Unrecoverable error */ - } - else - { - if(retry_cnt > 0) - { - /* Reset adapter and try init again */ - tms380tr_exec_sifcmd(dev, EXEC_SOFT_RESET); - tms380tr_wait(HALF_SECOND); - } - } - } - } while(retry_cnt > 0); - - printk(KERN_INFO "%s: Retry exceeded\n", dev->name); - return -1; -} - -/* - * Check for outstanding commands in command queue and tries to execute - * command immediately. Corresponding command flag in command queue is cleared. - */ -static void tms380tr_chk_outstanding_cmds(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - unsigned long Addr = 0; - - if(tp->CMDqueue == 0) - return; /* No command execution */ - - /* If SCB in use: no command */ - if(tp->ScbInUse == 1) - return; - - /* Check if adapter is opened, avoiding COMMAND_REJECT - * interrupt by the adapter! - */ - if (tp->AdapterOpenFlag == 0) { - if (tp->CMDqueue & OC_OPEN) { - /* Execute OPEN command */ - tp->CMDqueue ^= OC_OPEN; - - Addr = htonl(((char *)&tp->ocpl - (char *)tp) + tp->dmabuffer); - tp->scb.Parm[0] = LOWORD(Addr); - tp->scb.Parm[1] = HIWORD(Addr); - tp->scb.CMD = OPEN; - } else - /* No OPEN command queued, but adapter closed. Note: - * We'll try to re-open the adapter in DriverPoll() - */ - return; /* No adapter command issued */ - } else { - /* Adapter is open; evaluate command queue: try to execute - * outstanding commands (depending on priority!) CLOSE - * command queued - */ - if (tp->CMDqueue & OC_CLOSE) { - tp->CMDqueue ^= OC_CLOSE; - tp->AdapterOpenFlag = 0; - tp->scb.Parm[0] = 0; /* Parm[0], Parm[1] are ignored */ - tp->scb.Parm[1] = 0; /* but should be set to zero! */ - tp->scb.CMD = CLOSE; - if(!tp->HaltInProgress) - tp->CMDqueue |= OC_OPEN; /* re-open adapter */ - else - tp->CMDqueue = 0; /* no more commands */ - } else if (tp->CMDqueue & OC_RECEIVE) { - tp->CMDqueue ^= OC_RECEIVE; - Addr = htonl(((char *)tp->RplHead - (char *)tp) + tp->dmabuffer); - tp->scb.Parm[0] = LOWORD(Addr); - tp->scb.Parm[1] = HIWORD(Addr); - tp->scb.CMD = RECEIVE; - } else if (tp->CMDqueue & OC_TRANSMIT_HALT) { - /* NOTE: TRANSMIT.HALT must be checked - * before TRANSMIT. - */ - tp->CMDqueue ^= OC_TRANSMIT_HALT; - tp->scb.CMD = TRANSMIT_HALT; - - /* Parm[0] and Parm[1] are ignored - * but should be set to zero! - */ - tp->scb.Parm[0] = 0; - tp->scb.Parm[1] = 0; - } else if (tp->CMDqueue & OC_TRANSMIT) { - /* NOTE: TRANSMIT must be - * checked after TRANSMIT.HALT - */ - if (tp->TransmitCommandActive) { - if (!tp->TransmitHaltScheduled) { - tp->TransmitHaltScheduled = 1; - tms380tr_exec_cmd(dev, OC_TRANSMIT_HALT); - } - tp->TransmitCommandActive = 0; - return; - } - - tp->CMDqueue ^= OC_TRANSMIT; - tms380tr_cancel_tx_queue(tp); - Addr = htonl(((char *)tp->TplBusy - (char *)tp) + tp->dmabuffer); - tp->scb.Parm[0] = LOWORD(Addr); - tp->scb.Parm[1] = HIWORD(Addr); - tp->scb.CMD = TRANSMIT; - tp->TransmitCommandActive = 1; - } else if (tp->CMDqueue & OC_MODIFY_OPEN_PARMS) { - tp->CMDqueue ^= OC_MODIFY_OPEN_PARMS; - tp->scb.Parm[0] = tp->ocpl.OPENOptions; /* new OPEN options*/ - tp->scb.Parm[0] |= ENABLE_FULL_DUPLEX_SELECTION; - tp->scb.Parm[1] = 0; /* is ignored but should be zero */ - tp->scb.CMD = MODIFY_OPEN_PARMS; - } else if (tp->CMDqueue & OC_SET_FUNCT_ADDR) { - tp->CMDqueue ^= OC_SET_FUNCT_ADDR; - tp->scb.Parm[0] = LOWORD(tp->ocpl.FunctAddr); - tp->scb.Parm[1] = HIWORD(tp->ocpl.FunctAddr); - tp->scb.CMD = SET_FUNCT_ADDR; - } else if (tp->CMDqueue & OC_SET_GROUP_ADDR) { - tp->CMDqueue ^= OC_SET_GROUP_ADDR; - tp->scb.Parm[0] = LOWORD(tp->ocpl.GroupAddr); - tp->scb.Parm[1] = HIWORD(tp->ocpl.GroupAddr); - tp->scb.CMD = SET_GROUP_ADDR; - } else if (tp->CMDqueue & OC_READ_ERROR_LOG) { - tp->CMDqueue ^= OC_READ_ERROR_LOG; - Addr = htonl(((char *)&tp->errorlogtable - (char *)tp) + tp->dmabuffer); - tp->scb.Parm[0] = LOWORD(Addr); - tp->scb.Parm[1] = HIWORD(Addr); - tp->scb.CMD = READ_ERROR_LOG; - } else { - printk(KERN_WARNING "CheckForOutstandingCommand: unknown Command\n"); - tp->CMDqueue = 0; - return; - } - } - - tp->ScbInUse = 1; /* Set semaphore: SCB in use. */ - - /* Execute SCB and generate IRQ when done. */ - tms380tr_exec_sifcmd(dev, CMD_EXECUTE | CMD_SCB_REQUEST); -} - -/* - * IRQ conditions: signal loss on the ring, transmit or receive of beacon - * frames (disabled if bit 1 of OPEN option is set); report error MAC - * frame transmit (disabled if bit 2 of OPEN option is set); open or short - * circuit fault on the lobe is detected; remove MAC frame received; - * error counter overflow (255); opened adapter is the only station in ring. - * After some of the IRQs the adapter is closed! - */ -static void tms380tr_ring_status_irq(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - - tp->CurrentRingStatus = be16_to_cpu((unsigned short)tp->ssb.Parm[0]); - - /* First: fill up statistics */ - if(tp->ssb.Parm[0] & SIGNAL_LOSS) - { - printk(KERN_INFO "%s: Signal Loss\n", dev->name); - tp->MacStat.line_errors++; - } - - /* Adapter is closed, but initialized */ - if(tp->ssb.Parm[0] & LOBE_WIRE_FAULT) - { - printk(KERN_INFO "%s: Lobe Wire Fault, Reopen Adapter\n", - dev->name); - tp->MacStat.line_errors++; - } - - if(tp->ssb.Parm[0] & RING_RECOVERY) - printk(KERN_INFO "%s: Ring Recovery\n", dev->name); - - /* Counter overflow: read error log */ - if(tp->ssb.Parm[0] & COUNTER_OVERFLOW) - { - printk(KERN_INFO "%s: Counter Overflow\n", dev->name); - tms380tr_exec_cmd(dev, OC_READ_ERROR_LOG); - } - - /* Adapter is closed, but initialized */ - if(tp->ssb.Parm[0] & REMOVE_RECEIVED) - printk(KERN_INFO "%s: Remove Received, Reopen Adapter\n", - dev->name); - - /* Adapter is closed, but initialized */ - if(tp->ssb.Parm[0] & AUTO_REMOVAL_ERROR) - printk(KERN_INFO "%s: Auto Removal Error, Reopen Adapter\n", - dev->name); - - if(tp->ssb.Parm[0] & HARD_ERROR) - printk(KERN_INFO "%s: Hard Error\n", dev->name); - - if(tp->ssb.Parm[0] & SOFT_ERROR) - printk(KERN_INFO "%s: Soft Error\n", dev->name); - - if(tp->ssb.Parm[0] & TRANSMIT_BEACON) - printk(KERN_INFO "%s: Transmit Beacon\n", dev->name); - - if(tp->ssb.Parm[0] & SINGLE_STATION) - printk(KERN_INFO "%s: Single Station\n", dev->name); - - /* Check if adapter has been closed */ - if(tp->ssb.Parm[0] & ADAPTER_CLOSED) - { - printk(KERN_INFO "%s: Adapter closed (Reopening)," - "CurrentRingStat %x\n", - dev->name, tp->CurrentRingStatus); - tp->AdapterOpenFlag = 0; - tms380tr_open_adapter(dev); - } -} - -/* - * Issued if adapter has encountered an unrecoverable hardware - * or software error. - */ -static void tms380tr_chk_irq(struct net_device *dev) -{ - int i; - unsigned short AdapterCheckBlock[4]; - struct net_local *tp = netdev_priv(dev); - - tp->AdapterOpenFlag = 0; /* Adapter closed now */ - - /* Page number of adapter memory */ - SIFWRITEW(0x0001, SIFADX); - /* Address offset */ - SIFWRITEW(CHECKADDR, SIFADR); - - /* Reading 8 byte adapter check block. */ - for(i = 0; i < 4; i++) - AdapterCheckBlock[i] = SIFREADW(SIFINC); - - if(tms380tr_debug > 3) - { - printk(KERN_DEBUG "%s: AdapterCheckBlock: ", dev->name); - for (i = 0; i < 4; i++) - printk("%04X", AdapterCheckBlock[i]); - printk("\n"); - } - - switch(AdapterCheckBlock[0]) - { - case DIO_PARITY: - printk(KERN_INFO "%s: DIO parity error\n", dev->name); - break; - - case DMA_READ_ABORT: - printk(KERN_INFO "%s DMA read operation aborted:\n", - dev->name); - switch (AdapterCheckBlock[1]) - { - case 0: - printk(KERN_INFO "Timeout\n"); - printk(KERN_INFO "Address: %04X %04X\n", - AdapterCheckBlock[2], - AdapterCheckBlock[3]); - break; - - case 1: - printk(KERN_INFO "Parity error\n"); - printk(KERN_INFO "Address: %04X %04X\n", - AdapterCheckBlock[2], - AdapterCheckBlock[3]); - break; - - case 2: - printk(KERN_INFO "Bus error\n"); - printk(KERN_INFO "Address: %04X %04X\n", - AdapterCheckBlock[2], - AdapterCheckBlock[3]); - break; - - default: - printk(KERN_INFO "Unknown error.\n"); - break; - } - break; - - case DMA_WRITE_ABORT: - printk(KERN_INFO "%s: DMA write operation aborted:\n", - dev->name); - switch (AdapterCheckBlock[1]) - { - case 0: - printk(KERN_INFO "Timeout\n"); - printk(KERN_INFO "Address: %04X %04X\n", - AdapterCheckBlock[2], - AdapterCheckBlock[3]); - break; - - case 1: - printk(KERN_INFO "Parity error\n"); - printk(KERN_INFO "Address: %04X %04X\n", - AdapterCheckBlock[2], - AdapterCheckBlock[3]); - break; - - case 2: - printk(KERN_INFO "Bus error\n"); - printk(KERN_INFO "Address: %04X %04X\n", - AdapterCheckBlock[2], - AdapterCheckBlock[3]); - break; - - default: - printk(KERN_INFO "Unknown error.\n"); - break; - } - break; - - case ILLEGAL_OP_CODE: - printk(KERN_INFO "%s: Illegal operation code in firmware\n", - dev->name); - /* Parm[0-3]: adapter internal register R13-R15 */ - break; - - case PARITY_ERRORS: - printk(KERN_INFO "%s: Adapter internal bus parity error\n", - dev->name); - /* Parm[0-3]: adapter internal register R13-R15 */ - break; - - case RAM_DATA_ERROR: - printk(KERN_INFO "%s: RAM data error\n", dev->name); - /* Parm[0-1]: MSW/LSW address of RAM location. */ - break; - - case RAM_PARITY_ERROR: - printk(KERN_INFO "%s: RAM parity error\n", dev->name); - /* Parm[0-1]: MSW/LSW address of RAM location. */ - break; - - case RING_UNDERRUN: - printk(KERN_INFO "%s: Internal DMA underrun detected\n", - dev->name); - break; - - case INVALID_IRQ: - printk(KERN_INFO "%s: Unrecognized interrupt detected\n", - dev->name); - /* Parm[0-3]: adapter internal register R13-R15 */ - break; - - case INVALID_ERROR_IRQ: - printk(KERN_INFO "%s: Unrecognized error interrupt detected\n", - dev->name); - /* Parm[0-3]: adapter internal register R13-R15 */ - break; - - case INVALID_XOP: - printk(KERN_INFO "%s: Unrecognized XOP request detected\n", - dev->name); - /* Parm[0-3]: adapter internal register R13-R15 */ - break; - - default: - printk(KERN_INFO "%s: Unknown status", dev->name); - break; - } - - if(tms380tr_chipset_init(dev) == 1) - { - /* Restart of firmware successful */ - tp->AdapterOpenFlag = 1; - } -} - -/* - * Internal adapter pointer to RAM data are copied from adapter into - * host system. - */ -static int tms380tr_read_ptr(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - unsigned short adapterram; - - tms380tr_read_ram(dev, (unsigned char *)&tp->intptrs.BurnedInAddrPtr, - ADAPTER_INT_PTRS, 16); - tms380tr_read_ram(dev, (unsigned char *)&adapterram, - cpu_to_be16((unsigned short)tp->intptrs.AdapterRAMPtr), 2); - return be16_to_cpu(adapterram); -} - -/* - * Reads a number of bytes from adapter to system memory. - */ -static void tms380tr_read_ram(struct net_device *dev, unsigned char *Data, - unsigned short Address, int Length) -{ - int i; - unsigned short old_sifadx, old_sifadr, InWord; - - /* Save the current values */ - old_sifadx = SIFREADW(SIFADX); - old_sifadr = SIFREADW(SIFADR); - - /* Page number of adapter memory */ - SIFWRITEW(0x0001, SIFADX); - /* Address offset in adapter RAM */ - SIFWRITEW(Address, SIFADR); - - /* Copy len byte from adapter memory to system data area. */ - i = 0; - for(;;) - { - InWord = SIFREADW(SIFINC); - - *(Data + i) = HIBYTE(InWord); /* Write first byte */ - if(++i == Length) /* All is done break */ - break; - - *(Data + i) = LOBYTE(InWord); /* Write second byte */ - if (++i == Length) /* All is done break */ - break; - } - - /* Restore original values */ - SIFWRITEW(old_sifadx, SIFADX); - SIFWRITEW(old_sifadr, SIFADR); -} - -/* - * Cancel all queued packets in the transmission queue. - */ -static void tms380tr_cancel_tx_queue(struct net_local* tp) -{ - TPL *tpl; - - /* - * NOTE: There must not be an active TRANSMIT command pending, when - * this function is called. - */ - if(tp->TransmitCommandActive) - return; - - for(;;) - { - tpl = tp->TplBusy; - if(!tpl->BusyFlag) - break; - /* "Remove" TPL from busy list. */ - tp->TplBusy = tpl->NextTPLPtr; - tms380tr_write_tpl_status(tpl, 0); /* Clear VALID bit */ - tpl->BusyFlag = 0; /* "free" TPL */ - - printk(KERN_INFO "Cancel tx (%08lXh).\n", (unsigned long)tpl); - if (tpl->DMABuff) - dma_unmap_single(tp->pdev, tpl->DMABuff, tpl->Skb->len, DMA_TO_DEVICE); - dev_kfree_skb_any(tpl->Skb); - } -} - -/* - * This function is called whenever a transmit interrupt is generated by the - * adapter. For a command complete interrupt, it is checked if we have to - * issue a new transmit command or not. - */ -static void tms380tr_tx_status_irq(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - unsigned char HighByte, HighAc, LowAc; - TPL *tpl; - - /* NOTE: At this point the SSB from TRANSMIT STATUS is no longer - * available, because the CLEAR SSB command has already been issued. - * - * Process all complete transmissions. - */ - - for(;;) - { - tpl = tp->TplBusy; - if(!tpl->BusyFlag || (tpl->Status - & (TX_VALID | TX_FRAME_COMPLETE)) - != TX_FRAME_COMPLETE) - { - break; - } - - /* "Remove" TPL from busy list. */ - tp->TplBusy = tpl->NextTPLPtr ; - - /* Check the transmit status field only for directed frames*/ - if(DIRECTED_FRAME(tpl) && (tpl->Status & TX_ERROR) == 0) - { - HighByte = GET_TRANSMIT_STATUS_HIGH_BYTE(tpl->Status); - HighAc = GET_FRAME_STATUS_HIGH_AC(HighByte); - LowAc = GET_FRAME_STATUS_LOW_AC(HighByte); - - if((HighAc != LowAc) || (HighAc == AC_NOT_RECOGNIZED)) - { - printk(KERN_DEBUG "%s: (DA=%08lX not recognized)\n", - dev->name, - *(unsigned long *)&tpl->MData[2+2]); - } - else - { - if(tms380tr_debug > 3) - printk(KERN_DEBUG "%s: Directed frame tx'd\n", - dev->name); - } - } - else - { - if(!DIRECTED_FRAME(tpl)) - { - if(tms380tr_debug > 3) - printk(KERN_DEBUG "%s: Broadcast frame tx'd\n", - dev->name); - } - } - - tp->MacStat.tx_packets++; - if (tpl->DMABuff) - dma_unmap_single(tp->pdev, tpl->DMABuff, tpl->Skb->len, DMA_TO_DEVICE); - dev_kfree_skb_irq(tpl->Skb); - tpl->BusyFlag = 0; /* "free" TPL */ - } - - if(!tp->TplFree->NextTPLPtr->BusyFlag) - netif_wake_queue(dev); -} - -/* - * Called if a frame receive interrupt is generated by the adapter. - * Check if the frame is valid and indicate it to system. - */ -static void tms380tr_rcv_status_irq(struct net_device *dev) -{ - struct net_local *tp = netdev_priv(dev); - unsigned char *ReceiveDataPtr; - struct sk_buff *skb; - unsigned int Length, Length2; - RPL *rpl; - RPL *SaveHead; - dma_addr_t dmabuf; - - /* NOTE: At this point the SSB from RECEIVE STATUS is no longer - * available, because the CLEAR SSB command has already been issued. - * - * Process all complete receives. - */ - - for(;;) - { - rpl = tp->RplHead; - if(rpl->Status & RX_VALID) - break; /* RPL still in use by adapter */ - - /* Forward RPLHead pointer to next list. */ - SaveHead = tp->RplHead; - tp->RplHead = rpl->NextRPLPtr; - - /* Get the frame size (Byte swap for Intel). - * Do this early (see workaround comment below) - */ - Length = be16_to_cpu(rpl->FrameSize); - - /* Check if the Frame_Start, Frame_End and - * Frame_Complete bits are set. - */ - if((rpl->Status & VALID_SINGLE_BUFFER_FRAME) - == VALID_SINGLE_BUFFER_FRAME) - { - ReceiveDataPtr = rpl->MData; - - /* Workaround for delayed write of FrameSize on ISA - * (FrameSize is false but valid-bit is reset) - * Frame size is set to zero when the RPL is freed. - * Length2 is there because there have also been - * cases where the FrameSize was partially written - */ - Length2 = be16_to_cpu(rpl->FrameSize); - - if(Length == 0 || Length != Length2) - { - tp->RplHead = SaveHead; - break; /* Return to tms380tr_interrupt */ - } - tms380tr_update_rcv_stats(tp,ReceiveDataPtr,Length); - - if(tms380tr_debug > 3) - printk(KERN_DEBUG "%s: Packet Length %04X (%d)\n", - dev->name, Length, Length); - - /* Indicate the received frame to system the - * adapter does the Source-Routing padding for - * us. See: OpenOptions in tms380tr_init_opb() - */ - skb = rpl->Skb; - if(rpl->SkbStat == SKB_UNAVAILABLE) - { - /* Try again to allocate skb */ - skb = dev_alloc_skb(tp->MaxPacketSize); - if(skb == NULL) - { - /* Update Stats ?? */ - } - else - { - skb_put(skb, tp->MaxPacketSize); - rpl->SkbStat = SKB_DATA_COPY; - ReceiveDataPtr = rpl->MData; - } - } - - if(skb && (rpl->SkbStat == SKB_DATA_COPY || - rpl->SkbStat == SKB_DMA_DIRECT)) - { - if(rpl->SkbStat == SKB_DATA_COPY) - skb_copy_to_linear_data(skb, ReceiveDataPtr, - Length); - - /* Deliver frame to system */ - rpl->Skb = NULL; - skb_trim(skb,Length); - skb->protocol = tr_type_trans(skb,dev); - netif_rx(skb); - } - } - else /* Invalid frame */ - { - if(rpl->Skb != NULL) - dev_kfree_skb_irq(rpl->Skb); - - /* Skip list. */ - if(rpl->Status & RX_START_FRAME) - /* Frame start bit is set -> overflow. */ - tp->MacStat.rx_errors++; - } - if (rpl->DMABuff) - dma_unmap_single(tp->pdev, rpl->DMABuff, tp->MaxPacketSize, DMA_TO_DEVICE); - rpl->DMABuff = 0; - - /* Allocate new skb for rpl */ - rpl->Skb = dev_alloc_skb(tp->MaxPacketSize); - /* skb == NULL ? then use local buffer */ - if(rpl->Skb == NULL) - { - rpl->SkbStat = SKB_UNAVAILABLE; - rpl->FragList[0].DataAddr = htonl(((char *)tp->LocalRxBuffers[rpl->RPLIndex] - (char *)tp) + tp->dmabuffer); - rpl->MData = tp->LocalRxBuffers[rpl->RPLIndex]; - } - else /* skb != NULL */ - { - rpl->Skb->dev = dev; - skb_put(rpl->Skb, tp->MaxPacketSize); - - /* Data unreachable for DMA ? then use local buffer */ - dmabuf = dma_map_single(tp->pdev, rpl->Skb->data, tp->MaxPacketSize, DMA_FROM_DEVICE); - if(tp->dmalimit && (dmabuf + tp->MaxPacketSize > tp->dmalimit)) - { - rpl->SkbStat = SKB_DATA_COPY; - rpl->FragList[0].DataAddr = htonl(((char *)tp->LocalRxBuffers[rpl->RPLIndex] - (char *)tp) + tp->dmabuffer); - rpl->MData = tp->LocalRxBuffers[rpl->RPLIndex]; - } - else - { - /* DMA directly in skb->data */ - rpl->SkbStat = SKB_DMA_DIRECT; - rpl->FragList[0].DataAddr = htonl(dmabuf); - rpl->MData = rpl->Skb->data; - rpl->DMABuff = dmabuf; - } - } - - rpl->FragList[0].DataCount = cpu_to_be16((unsigned short)tp->MaxPacketSize); - rpl->FrameSize = 0; - - /* Pass the last RPL back to the adapter */ - tp->RplTail->FrameSize = 0; - - /* Reset the CSTAT field in the list. */ - tms380tr_write_rpl_status(tp->RplTail, RX_VALID | RX_FRAME_IRQ); - - /* Current RPL becomes last one in list. */ - tp->RplTail = tp->RplTail->NextRPLPtr; - - /* Inform adapter about RPL valid. */ - tms380tr_exec_sifcmd(dev, CMD_RX_VALID); - } -} - -/* - * This function should be used whenever the status of any RPL must be - * modified by the driver, because the compiler may otherwise change the - * order of instructions such that writing the RPL status may be executed - * at an undesirable time. When this function is used, the status is - * always written when the function is called. - */ -static void tms380tr_write_rpl_status(RPL *rpl, unsigned int Status) -{ - rpl->Status = Status; -} - -/* - * The function updates the statistic counters in mac->MacStat. - * It differtiates between directed and broadcast/multicast ( ==functional) - * frames. - */ -static void tms380tr_update_rcv_stats(struct net_local *tp, unsigned char DataPtr[], - unsigned int Length) -{ - tp->MacStat.rx_packets++; - tp->MacStat.rx_bytes += Length; - - /* Test functional bit */ - if(DataPtr[2] & GROUP_BIT) - tp->MacStat.multicast++; -} - -static int tms380tr_set_mac_address(struct net_device *dev, void *addr) -{ - struct net_local *tp = netdev_priv(dev); - struct sockaddr *saddr = addr; - - if (tp->AdapterOpenFlag || tp->AdapterVirtOpenFlag) { - printk(KERN_WARNING "%s: Cannot set MAC/LAA address while card is open\n", dev->name); - return -EIO; - } - memcpy(dev->dev_addr, saddr->sa_data, dev->addr_len); - return 0; -} - -#if TMS380TR_DEBUG > 0 -/* - * Dump Packet (data) - */ -static void tms380tr_dump(unsigned char *Data, int length) -{ - int i, j; - - for (i = 0, j = 0; i < length / 8; i++, j += 8) - { - printk(KERN_DEBUG "%02x %02x %02x %02x %02x %02x %02x %02x\n", - Data[j+0],Data[j+1],Data[j+2],Data[j+3], - Data[j+4],Data[j+5],Data[j+6],Data[j+7]); - } -} -#endif - -void tmsdev_term(struct net_device *dev) -{ - struct net_local *tp; - - tp = netdev_priv(dev); - dma_unmap_single(tp->pdev, tp->dmabuffer, sizeof(struct net_local), - DMA_BIDIRECTIONAL); -} - -const struct net_device_ops tms380tr_netdev_ops = { - .ndo_open = tms380tr_open, - .ndo_stop = tms380tr_close, - .ndo_start_xmit = tms380tr_send_packet, - .ndo_tx_timeout = tms380tr_timeout, - .ndo_get_stats = tms380tr_get_stats, - .ndo_set_rx_mode = tms380tr_set_multicast_list, - .ndo_set_mac_address = tms380tr_set_mac_address, -}; -EXPORT_SYMBOL(tms380tr_netdev_ops); - -int tmsdev_init(struct net_device *dev, struct device *pdev) -{ - struct net_local *tms_local; - - memset(netdev_priv(dev), 0, sizeof(struct net_local)); - tms_local = netdev_priv(dev); - init_waitqueue_head(&tms_local->wait_for_tok_int); - if (pdev->dma_mask) - tms_local->dmalimit = *pdev->dma_mask; - else - return -ENOMEM; - tms_local->pdev = pdev; - tms_local->dmabuffer = dma_map_single(pdev, (void *)tms_local, - sizeof(struct net_local), DMA_BIDIRECTIONAL); - if (tms_local->dmabuffer + sizeof(struct net_local) > - tms_local->dmalimit) - { - printk(KERN_INFO "%s: Memory not accessible for DMA\n", - dev->name); - tmsdev_term(dev); - return -ENOMEM; - } - - dev->netdev_ops = &tms380tr_netdev_ops; - dev->watchdog_timeo = HZ; - - return 0; -} - -EXPORT_SYMBOL(tms380tr_open); -EXPORT_SYMBOL(tms380tr_close); -EXPORT_SYMBOL(tms380tr_interrupt); -EXPORT_SYMBOL(tmsdev_init); -EXPORT_SYMBOL(tmsdev_term); -EXPORT_SYMBOL(tms380tr_wait); - -#ifdef MODULE - -static struct module *TMS380_module = NULL; - -int init_module(void) -{ - printk(KERN_DEBUG "%s", version); - - TMS380_module = &__this_module; - return 0; -} - -void cleanup_module(void) -{ - TMS380_module = NULL; -} -#endif - -MODULE_LICENSE("GPL"); - diff --git a/trunk/drivers/net/tokenring/tms380tr.h b/trunk/drivers/net/tokenring/tms380tr.h deleted file mode 100644 index e5a617c586c2..000000000000 --- a/trunk/drivers/net/tokenring/tms380tr.h +++ /dev/null @@ -1,1141 +0,0 @@ -/* - * tms380tr.h: TI TMS380 Token Ring driver for Linux - * - * Authors: - * - Christoph Goos - * - Adam Fritzler - */ - -#ifndef __LINUX_TMS380TR_H -#define __LINUX_TMS380TR_H - -#ifdef __KERNEL__ - -#include - -/* module prototypes */ -extern const struct net_device_ops tms380tr_netdev_ops; -int tms380tr_open(struct net_device *dev); -int tms380tr_close(struct net_device *dev); -irqreturn_t tms380tr_interrupt(int irq, void *dev_id); -int tmsdev_init(struct net_device *dev, struct device *pdev); -void tmsdev_term(struct net_device *dev); -void tms380tr_wait(unsigned long time); - -#define TMS380TR_MAX_ADAPTERS 7 - -#define SEND_TIMEOUT 10*HZ - -#define TR_RCF_LONGEST_FRAME_MASK 0x0070 -#define TR_RCF_FRAME4K 0x0030 - -/*------------------------------------------------------------------*/ -/* Bit order for adapter communication with DMA */ -/* -------------------------------------------------------------- */ -/* Bit 8 | 9| 10| 11|| 12| 13| 14| 15|| 0| 1| 2| 3|| 4| 5| 6| 7| */ -/* -------------------------------------------------------------- */ -/* The bytes in a word must be byte swapped. Also, if a double */ -/* word is used for storage, then the words, as well as the bytes, */ -/* must be swapped. */ -/* Bit order for adapter communication with DIO */ -/* -------------------------------------------------------------- */ -/* Bit 0 | 1| 2| 3|| 4| 5| 6| 7|| 8| 9| 10| 11|| 12| 13| 14| 15| */ -/* -------------------------------------------------------------- */ -/*------------------------------------------------------------------*/ - -/* Swap words of a long. */ -#define SWAPW(x) (((x) << 16) | ((x) >> 16)) - -/* Get the low byte of a word. */ -#define LOBYTE(w) ((unsigned char)(w)) - -/* Get the high byte of a word. */ -#define HIBYTE(w) ((unsigned char)((unsigned short)(w) >> 8)) - -/* Get the low word of a long. */ -#define LOWORD(l) ((unsigned short)(l)) - -/* Get the high word of a long. */ -#define HIWORD(l) ((unsigned short)((unsigned long)(l) >> 16)) - - - -/* Token ring adapter I/O addresses for normal mode. */ - -/* - * The SIF registers. Common to all adapters. - */ -/* Basic SIF (SRSX = 0) */ -#define SIFDAT 0x00 /* SIF/DMA data. */ -#define SIFINC 0x02 /* IO Word data with auto increment. */ -#define SIFINH 0x03 /* IO Byte data with auto increment. */ -#define SIFADR 0x04 /* SIF/DMA Address. */ -#define SIFCMD 0x06 /* SIF Command. */ -#define SIFSTS 0x06 /* SIF Status. */ - -/* "Extended" SIF (SRSX = 1) */ -#define SIFACL 0x08 /* SIF Adapter Control Register. */ -#define SIFADD 0x0a /* SIF/DMA Address. -- 0x0a */ -#define SIFADX 0x0c /* 0x0c */ -#define DMALEN 0x0e /* SIF DMA length. -- 0x0e */ - -/* - * POS Registers. Only for ISA Adapters. - */ -#define POSREG 0x10 /* Adapter Program Option Select (POS) - * Register: base IO address + 16 byte. - */ -#define POSREG_2 24L /* only for TR4/16+ adapter - * base IO address + 24 byte. -- 0x18 - */ - -/* SIFCMD command codes (high-low) */ -#define CMD_INTERRUPT_ADAPTER 0x8000 /* Cause internal adapter interrupt */ -#define CMD_ADAPTER_RESET 0x4000 /* Hardware reset of adapter */ -#define CMD_SSB_CLEAR 0x2000 /* Acknowledge to adapter to - * system interrupts. - */ -#define CMD_EXECUTE 0x1000 /* Execute SCB command */ -#define CMD_SCB_REQUEST 0x0800 /* Request adapter to interrupt - * system when SCB is available for - * another command. - */ -#define CMD_RX_CONTINUE 0x0400 /* Continue receive after odd pointer - * stop. (odd pointer receive method) - */ -#define CMD_RX_VALID 0x0200 /* Now actual RPL is valid. */ -#define CMD_TX_VALID 0x0100 /* Now actual TPL is valid. (valid - * bit receive/transmit method) - */ -#define CMD_SYSTEM_IRQ 0x0080 /* Adapter-to-attached-system - * interrupt is reset. - */ -#define CMD_CLEAR_SYSTEM_IRQ 0x0080 /* Clear SYSTEM_INTERRUPT bit. - * (write: 1=ignore, 0=reset) - */ -#define EXEC_SOFT_RESET 0xFF00 /* adapter soft reset. (restart - * adapter after hardware reset) - */ - - -/* ACL commands (high-low) */ -#define ACL_SWHLDA 0x0800 /* Software hold acknowledge. */ -#define ACL_SWDDIR 0x0400 /* Data transfer direction. */ -#define ACL_SWHRQ 0x0200 /* Pseudo DMA operation. */ -#define ACL_PSDMAEN 0x0100 /* Enable pseudo system DMA. */ -#define ACL_ARESET 0x0080 /* Adapter hardware reset command. - * (held in reset condition as - * long as bit is set) - */ -#define ACL_CPHALT 0x0040 /* Communication processor halt. - * (can only be set while ACL_ARESET - * bit is set; prevents adapter - * processor from executing code while - * downloading firmware) - */ -#define ACL_BOOT 0x0020 -#define ACL_SINTEN 0x0008 /* System interrupt enable/disable - * (1/0): can be written if ACL_ARESET - * is zero. - */ -#define ACL_PEN 0x0004 - -#define ACL_NSELOUT0 0x0002 -#define ACL_NSELOUT1 0x0001 /* NSELOUTx have a card-specific - * meaning for setting ring speed. - */ - -#define PS_DMA_MASK (ACL_SWHRQ | ACL_PSDMAEN) - - -/* SIFSTS register return codes (high-low) */ -#define STS_SYSTEM_IRQ 0x0080 /* Adapter-to-attached-system - * interrupt is valid. - */ -#define STS_INITIALIZE 0x0040 /* INITIALIZE status. (ready to - * initialize) - */ -#define STS_TEST 0x0020 /* TEST status. (BUD not completed) */ -#define STS_ERROR 0x0010 /* ERROR status. (unrecoverable - * HW error occurred) - */ -#define STS_MASK 0x00F0 /* Mask interesting status bits. */ -#define STS_ERROR_MASK 0x000F /* Get Error Code by masking the - * interrupt code bits. - */ -#define ADAPTER_INT_PTRS 0x0A00 /* Address offset of adapter internal - * pointers 01:0a00 (high-low) have to - * be read after init and before open. - */ - - -/* Interrupt Codes (only MAC IRQs) */ -#define STS_IRQ_ADAPTER_CHECK 0x0000 /* unrecoverable hardware or - * software error. - */ -#define STS_IRQ_RING_STATUS 0x0004 /* SSB is updated with ring status. */ -#define STS_IRQ_LLC_STATUS 0x0005 /* Not used in MAC-only microcode */ -#define STS_IRQ_SCB_CLEAR 0x0006 /* SCB clear, following an - * SCB_REQUEST IRQ. - */ -#define STS_IRQ_TIMER 0x0007 /* Not normally used in MAC ucode */ -#define STS_IRQ_COMMAND_STATUS 0x0008 /* SSB is updated with command - * status. - */ -#define STS_IRQ_RECEIVE_STATUS 0x000A /* SSB is updated with receive - * status. - */ -#define STS_IRQ_TRANSMIT_STATUS 0x000C /* SSB is updated with transmit - * status - */ -#define STS_IRQ_RECEIVE_PENDING 0x000E /* Not used in MAC-only microcode */ -#define STS_IRQ_MASK 0x000F /* = STS_ERROR_MASK. */ - - -/* TRANSMIT_STATUS completion code: (SSB.Parm[0]) */ -#define COMMAND_COMPLETE 0x0080 /* TRANSMIT command completed - * (avoid this!) issue another transmit - * to send additional frames. - */ -#define FRAME_COMPLETE 0x0040 /* Frame has been transmitted; - * INTERRUPT_FRAME bit was set in the - * CSTAT request; indication of possibly - * more than one frame transmissions! - * SSB.Parm[0-1]: 32 bit pointer to - * TPL of last frame. - */ -#define LIST_ERROR 0x0020 /* Error in one of the TPLs that - * compose the frame; TRANSMIT - * terminated; Parm[1-2]: 32bit pointer - * to TPL which starts the error - * frame; error details in bits 8-13. - * (14?) - */ -#define FRAME_SIZE_ERROR 0x8000 /* FRAME_SIZE does not equal the sum of - * the valid DATA_COUNT fields; - * FRAME_SIZE less than header plus - * information field. (15 bytes + - * routing field) Or if FRAME_SIZE - * was specified as zero in one list. - */ -#define TX_THRESHOLD 0x4000 /* FRAME_SIZE greater than (BUFFER_SIZE - * - 9) * TX_BUF_MAX. - */ -#define ODD_ADDRESS 0x2000 /* Odd forward pointer value is - * read on a list without END_FRAME - * indication. - */ -#define FRAME_ERROR 0x1000 /* START_FRAME bit (not) anticipated, - * but (not) set. - */ -#define ACCESS_PRIORITY_ERROR 0x0800 /* Access priority requested has not - * been allowed. - */ -#define UNENABLED_MAC_FRAME 0x0400 /* MAC frame has source class of zero - * or MAC frame PCF ATTN field is - * greater than one. - */ -#define ILLEGAL_FRAME_FORMAT 0x0200 /* Bit 0 or FC field was set to one. */ - - -/* - * Since we need to support some functions even if the adapter is in a - * CLOSED state, we have a (pseudo-) command queue which holds commands - * that are outstandig to be executed. - * - * Each time a command completes, an interrupt occurs and the next - * command is executed. The command queue is actually a simple word with - * a bit for each outstandig command. Therefore the commands will not be - * executed in the order they have been queued. - * - * The following defines the command code bits and the command queue: - */ -#define OC_OPEN 0x0001 /* OPEN command */ -#define OC_TRANSMIT 0x0002 /* TRANSMIT command */ -#define OC_TRANSMIT_HALT 0x0004 /* TRANSMIT_HALT command */ -#define OC_RECEIVE 0x0008 /* RECEIVE command */ -#define OC_CLOSE 0x0010 /* CLOSE command */ -#define OC_SET_GROUP_ADDR 0x0020 /* SET_GROUP_ADDR command */ -#define OC_SET_FUNCT_ADDR 0x0040 /* SET_FUNCT_ADDR command */ -#define OC_READ_ERROR_LOG 0x0080 /* READ_ERROR_LOG command */ -#define OC_READ_ADAPTER 0x0100 /* READ_ADAPTER command */ -#define OC_MODIFY_OPEN_PARMS 0x0400 /* MODIFY_OPEN_PARMS command */ -#define OC_RESTORE_OPEN_PARMS 0x0800 /* RESTORE_OPEN_PARMS command */ -#define OC_SET_FIRST_16_GROUP 0x1000 /* SET_FIRST_16_GROUP command */ -#define OC_SET_BRIDGE_PARMS 0x2000 /* SET_BRIDGE_PARMS command */ -#define OC_CONFIG_BRIDGE_PARMS 0x4000 /* CONFIG_BRIDGE_PARMS command */ - -#define OPEN 0x0300 /* C: open command. S: completion. */ -#define TRANSMIT 0x0400 /* C: transmit command. S: completion - * status. (reject: COMMAND_REJECT if - * adapter not opened, TRANSMIT already - * issued or address passed in the SCB - * not word aligned) - */ -#define TRANSMIT_HALT 0x0500 /* C: interrupt TX TPL chain; if no - * TRANSMIT command issued, the command - * is ignored (completion with TRANSMIT - * status (0x0400)!) - */ -#define RECEIVE 0x0600 /* C: receive command. S: completion - * status. (reject: COMMAND_REJECT if - * adapter not opened, RECEIVE already - * issued or address passed in the SCB - * not word aligned) - */ -#define CLOSE 0x0700 /* C: close adapter. S: completion. - * (COMMAND_REJECT if adapter not open) - */ -#define SET_GROUP_ADDR 0x0800 /* C: alter adapter group address after - * OPEN. S: completion. (COMMAND_REJECT - * if adapter not open) - */ -#define SET_FUNCT_ADDR 0x0900 /* C: alter adapter functional address - * after OPEN. S: completion. - * (COMMAND_REJECT if adapter not open) - */ -#define READ_ERROR_LOG 0x0A00 /* C: read adapter error counters. - * S: completion. (command ignored - * if adapter not open!) - */ -#define READ_ADAPTER 0x0B00 /* C: read data from adapter memory. - * (important: after init and before - * open!) S: completion. (ADAPTER_CHECK - * interrupt if undefined storage area - * read) - */ -#define MODIFY_OPEN_PARMS 0x0D00 /* C: modify some adapter operational - * parameters. (bit correspondend to - * WRAP_INTERFACE is ignored) - * S: completion. (reject: - * COMMAND_REJECT) - */ -#define RESTORE_OPEN_PARMS 0x0E00 /* C: modify some adapter operational - * parameters. (bit correspondend - * to WRAP_INTERFACE is ignored) - * S: completion. (reject: - * COMMAND_REJECT) - */ -#define SET_FIRST_16_GROUP 0x0F00 /* C: alter the first two bytes in - * adapter group address. - * S: completion. (reject: - * COMMAND_REJECT) - */ -#define SET_BRIDGE_PARMS 0x1000 /* C: values and conditions for the - * adapter hardware to use when frames - * are copied for forwarding. - * S: completion. (reject: - * COMMAND_REJECT) - */ -#define CONFIG_BRIDGE_PARMS 0x1100 /* C: .. - * S: completion. (reject: - * COMMAND_REJECT) - */ - -#define SPEED_4 4 -#define SPEED_16 16 /* Default transmission speed */ - - -/* Initialization Parameter Block (IPB); word alignment necessary! */ -#define BURST_SIZE 0x0018 /* Default burst size */ -#define BURST_MODE 0x9F00 /* Burst mode enable */ -#define DMA_RETRIES 0x0505 /* Magic DMA retry number... */ - -#define CYCLE_TIME 3 /* Default AT-bus cycle time: 500 ns - * (later adapter version: fix cycle time!) - */ -#define LINE_SPEED_BIT 0x80 - -/* Macro definition for the wait function. */ -#define ONE_SECOND_TICKS 1000000 -#define HALF_SECOND (ONE_SECOND_TICKS / 2) -#define ONE_SECOND (ONE_SECOND_TICKS) -#define TWO_SECONDS (ONE_SECOND_TICKS * 2) -#define THREE_SECONDS (ONE_SECOND_TICKS * 3) -#define FOUR_SECONDS (ONE_SECOND_TICKS * 4) -#define FIVE_SECONDS (ONE_SECOND_TICKS * 5) - -#define BUFFER_SIZE 2048 /* Buffers on Adapter */ - -#pragma pack(1) -typedef struct { - unsigned short Init_Options; /* Initialize with burst mode; - * LLC disabled. (MAC only) - */ - - /* Interrupt vectors the adapter places on attached system bus. */ - u_int8_t CMD_Status_IV; /* Interrupt vector: command status. */ - u_int8_t TX_IV; /* Interrupt vector: transmit. */ - u_int8_t RX_IV; /* Interrupt vector: receive. */ - u_int8_t Ring_Status_IV; /* Interrupt vector: ring status. */ - u_int8_t SCB_Clear_IV; /* Interrupt vector: SCB clear. */ - u_int8_t Adapter_CHK_IV; /* Interrupt vector: adapter check. */ - - u_int16_t RX_Burst_Size; /* Max. number of transfer cycles. */ - u_int16_t TX_Burst_Size; /* During DMA burst; even value! */ - u_int16_t DMA_Abort_Thrhld; /* Number of DMA retries. */ - - u_int32_t SCB_Addr; /* SCB address: even, word aligned, high-low */ - u_int32_t SSB_Addr; /* SSB address: even, word aligned, high-low */ -} IPB, *IPB_Ptr; -#pragma pack() - -/* - * OPEN Command Parameter List (OCPL) (can be reused, if the adapter has to - * be reopened) - */ -#define BUFFER_SIZE 2048 /* Buffers on Adapter. */ -#define TPL_SIZE 8+6*TX_FRAG_NUM /* Depending on fragments per TPL. */ -#define RPL_SIZE 14 /* (with TI firmware v2.26 handling - * up to nine fragments possible) - */ -#define TX_BUF_MIN 20 /* ??? (Stephan: calculation with */ -#define TX_BUF_MAX 40 /* BUFFER_SIZE and MAX_FRAME_SIZE) ??? - */ -#define DISABLE_EARLY_TOKEN_RELEASE 0x1000 - -/* OPEN Options (high-low) */ -#define WRAP_INTERFACE 0x0080 /* Inserting omitted for test - * purposes; transmit data appears - * as receive data. (useful for - * testing; change: CLOSE necessary) - */ -#define DISABLE_HARD_ERROR 0x0040 /* On HARD_ERROR & TRANSMIT_BEACON - * no RING.STATUS interrupt. - */ -#define DISABLE_SOFT_ERROR 0x0020 /* On SOFT_ERROR, no RING.STATUS - * interrupt. - */ -#define PASS_ADAPTER_MAC_FRAMES 0x0010 /* Passing unsupported MAC frames - * to system. - */ -#define PASS_ATTENTION_FRAMES 0x0008 /* All changed attention MAC frames are - * passed to the system. - */ -#define PAD_ROUTING_FIELD 0x0004 /* Routing field is padded to 18 - * bytes. - */ -#define FRAME_HOLD 0x0002 /*Adapter waits for entire frame before - * initiating DMA transfer; otherwise: - * DMA transfer initiation if internal - * buffer filled. - */ -#define CONTENDER 0x0001 /* Adapter participates in the monitor - * contention process. - */ -#define PASS_BEACON_MAC_FRAMES 0x8000 /* Adapter passes beacon MAC frames - * to the system. - */ -#define EARLY_TOKEN_RELEASE 0x1000 /* Only valid in 16 Mbps operation; - * 0 = ETR. (no effect in 4 Mbps - * operation) - */ -#define COPY_ALL_MAC_FRAMES 0x0400 /* All MAC frames are copied to - * the system. (after OPEN: duplicate - * address test (DAT) MAC frame is - * first received frame copied to the - * system) - */ -#define COPY_ALL_NON_MAC_FRAMES 0x0200 /* All non MAC frames are copied to - * the system. - */ -#define PASS_FIRST_BUF_ONLY 0x0100 /* Passes only first internal buffer - * of each received frame; FrameSize - * of RPLs must contain internal - * BUFFER_SIZE bits for promiscuous mode. - */ -#define ENABLE_FULL_DUPLEX_SELECTION 0x2000 - /* Enable the use of full-duplex - * settings with bits in byte 22 in - * ocpl. (new feature in firmware - * version 3.09) - */ - -/* Full-duplex settings */ -#define OPEN_FULL_DUPLEX_OFF 0x0000 -#define OPEN_FULL_DUPLEX_ON 0x00c0 -#define OPEN_FULL_DUPLEX_AUTO 0x0080 - -#define PROD_ID_SIZE 18 /* Length of product ID. */ - -#define TX_FRAG_NUM 3 /* Number of fragments used in one TPL. */ -#define TX_MORE_FRAGMENTS 0x8000 /* Bit set in DataCount to indicate more - * fragments following. - */ - -/* XXX is there some better way to do this? */ -#define ISA_MAX_ADDRESS 0x00ffffff -#define PCI_MAX_ADDRESS 0xffffffff - -#pragma pack(1) -typedef struct { - u_int16_t OPENOptions; - u_int8_t NodeAddr[6]; /* Adapter node address; use ROM - * address - */ - u_int32_t GroupAddr; /* Multicast: high order - * bytes = 0xC000 - */ - u_int32_t FunctAddr; /* High order bytes = 0xC000 */ - __be16 RxListSize; /* RPL size: 0 (=26), 14, 20 or - * 26 bytes read by the adapter. - * (Depending on the number of - * fragments/list) - */ - __be16 TxListSize; /* TPL size */ - __be16 BufSize; /* Is automatically rounded up to the - * nearest nK boundary. - */ - u_int16_t FullDuplex; - u_int16_t Reserved; - u_int8_t TXBufMin; /* Number of adapter buffers reserved - * for transmission a minimum of 2 - * buffers must be allocated. - */ - u_int8_t TXBufMax; /* Maximum number of adapter buffers - * for transmit; a minimum of 2 buffers - * must be available for receive. - * Default: 6 - */ - u_int16_t ProdIDAddr[2];/* Pointer to product ID. */ -} OPB, *OPB_Ptr; -#pragma pack() - -/* - * SCB: adapter commands enabled by the host system started by writing - * CMD_INTERRUPT_ADAPTER | CMD_EXECUTE (|SCB_REQUEST) to the SIFCMD IO - * register. (special case: | CMD_SYSTEM_IRQ for initialization) - */ -#pragma pack(1) -typedef struct { - u_int16_t CMD; /* Command code */ - u_int16_t Parm[2]; /* Pointer to Command Parameter Block */ -} SCB; /* System Command Block (32 bit physical address; big endian)*/ -#pragma pack() - -/* - * SSB: adapter command return status can be evaluated after COMMAND_STATUS - * adapter to system interrupt after reading SSB, the availability of the SSB - * has to be told the adapter by writing CMD_INTERRUPT_ADAPTER | CMD_SSB_CLEAR - * in the SIFCMD IO register. - */ -#pragma pack(1) -typedef struct { - u_int16_t STS; /* Status code */ - u_int16_t Parm[3]; /* Parameter or pointer to Status Parameter - * Block. - */ -} SSB; /* System Status Block (big endian - physical address) */ -#pragma pack() - -typedef struct { - unsigned short BurnedInAddrPtr; /* Pointer to adapter burned in - * address. (BIA) - */ - unsigned short SoftwareLevelPtr;/* Pointer to software level data. */ - unsigned short AdapterAddrPtr; /* Pointer to adapter addresses. */ - unsigned short AdapterParmsPtr; /* Pointer to adapter parameters. */ - unsigned short MACBufferPtr; /* Pointer to MAC buffer. (internal) */ - unsigned short LLCCountersPtr; /* Pointer to LLC counters. */ - unsigned short SpeedFlagPtr; /* Pointer to data rate flag. - * (4/16 Mbps) - */ - unsigned short AdapterRAMPtr; /* Pointer to adapter RAM found. (KB) */ -} INTPTRS; /* Adapter internal pointers */ - -#pragma pack(1) -typedef struct { - u_int8_t Line_Error; /* Line error: code violation in - * frame or in a token, or FCS error. - */ - u_int8_t Internal_Error; /* IBM specific. (Reserved_1) */ - u_int8_t Burst_Error; - u_int8_t ARI_FCI_Error; /* ARI/FCI bit zero in AMP or - * SMP MAC frame. - */ - u_int8_t AbortDelimeters; /* IBM specific. (Reserved_2) */ - u_int8_t Reserved_3; - u_int8_t Lost_Frame_Error; /* Receive of end of transmitted - * frame failed. - */ - u_int8_t Rx_Congest_Error; /* Adapter in repeat mode has not - * enough buffer space to copy incoming - * frame. - */ - u_int8_t Frame_Copied_Error; /* ARI bit not zero in frame - * addressed to adapter. - */ - u_int8_t Frequency_Error; /* IBM specific. (Reserved_4) */ - u_int8_t Token_Error; /* (active only in monitor station) */ - u_int8_t Reserved_5; - u_int8_t DMA_Bus_Error; /* DMA bus errors not exceeding the - * abort thresholds. - */ - u_int8_t DMA_Parity_Error; /* DMA parity errors not exceeding - * the abort thresholds. - */ -} ERRORTAB; /* Adapter error counters */ -#pragma pack() - - -/*--------------------- Send and Receive definitions -------------------*/ -#pragma pack(1) -typedef struct { - __be16 DataCount; /* Value 0, even and odd values are - * permitted; value is unaltered most - * significant bit set: following - * fragments last fragment: most - * significant bit is not evaluated. - * (???) - */ - __be32 DataAddr; /* Pointer to frame data fragment; - * even or odd. - */ -} Fragment; -#pragma pack() - -#define MAX_FRAG_NUMBERS 9 /* Maximal number of fragments possible to use - * in one RPL/TPL. (depending on TI firmware - * version) - */ - -/* - * AC (1), FC (1), Dst (6), Src (6), RIF (18), Data (4472) = 4504 - * The packet size can be one of the follows: 548, 1502, 2084, 4504, 8176, - * 11439, 17832. Refer to TMS380 Second Generation Token Ring User's Guide - * Page 2-27. - */ -#define HEADER_SIZE (1 + 1 + 6 + 6) -#define SRC_SIZE 18 -#define MIN_DATA_SIZE 516 -#define DEFAULT_DATA_SIZE 4472 -#define MAX_DATA_SIZE 17800 - -#define DEFAULT_PACKET_SIZE (HEADER_SIZE + SRC_SIZE + DEFAULT_DATA_SIZE) -#define MIN_PACKET_SIZE (HEADER_SIZE + SRC_SIZE + MIN_DATA_SIZE) -#define MAX_PACKET_SIZE (HEADER_SIZE + SRC_SIZE + MAX_DATA_SIZE) - -/* - * Macros to deal with the frame status field. - */ -#define AC_NOT_RECOGNIZED 0x00 -#define GROUP_BIT 0x80 -#define GET_TRANSMIT_STATUS_HIGH_BYTE(Ts) ((unsigned char)((Ts) >> 8)) -#define GET_FRAME_STATUS_HIGH_AC(Fs) ((unsigned char)(((Fs) & 0xC0) >> 6)) -#define GET_FRAME_STATUS_LOW_AC(Fs) ((unsigned char)(((Fs) & 0x0C) >> 2)) -#define DIRECTED_FRAME(Context) (!((Context)->MData[2] & GROUP_BIT)) - - -/*--------------------- Send Functions ---------------------------------*/ -/* define TX_CSTAT _REQUEST (R) and _COMPLETE (C) values (high-low) */ - -#define TX_VALID 0x0080 /* R: set via TRANSMIT.VALID interrupt. - * C: always reset to zero! - */ -#define TX_FRAME_COMPLETE 0x0040 /* R: must be reset to zero. - * C: set to one. - */ -#define TX_START_FRAME 0x0020 /* R: start of a frame: 1 - * C: unchanged. - */ -#define TX_END_FRAME 0x0010 /* R: end of a frame: 1 - * C: unchanged. - */ -#define TX_FRAME_IRQ 0x0008 /* R: request interrupt generation - * after transmission. - * C: unchanged. - */ -#define TX_ERROR 0x0004 /* R: reserved. - * C: set to one if Error occurred. - */ -#define TX_INTERFRAME_WAIT 0x0004 -#define TX_PASS_CRC 0x0002 /* R: set if CRC value is already - * calculated. (valid only in - * FRAME_START TPL) - * C: unchanged. - */ -#define TX_PASS_SRC_ADDR 0x0001 /* R: adapter uses explicit frame - * source address and does not overwrite - * with the adapter node address. - * (valid only in FRAME_START TPL) - * - * C: unchanged. - */ -#define TX_STRIP_FS 0xFF00 /* R: reserved. - * C: if no Transmission Error, - * field contains copy of FS byte after - * stripping of frame. - */ - -/* - * Structure of Transmit Parameter Lists (TPLs) (only one frame every TPL, - * but possibly multiple TPLs for one frame) the length of the TPLs has to be - * initialized in the OPL. (OPEN parameter list) - */ -#define TPL_NUM 3 /* Number of Transmit Parameter Lists. - * !! MUST BE >= 3 !! - */ - -#pragma pack(1) -typedef struct s_TPL TPL; - -struct s_TPL { /* Transmit Parameter List (align on even word boundaries) */ - __be32 NextTPLAddr; /* Pointer to next TPL in chain; if - * pointer is odd: this is the last - * TPL. Pointing to itself can cause - * problems! - */ - volatile u_int16_t Status; /* Initialized by the adapter: - * CSTAT_REQUEST important: update least - * significant bit first! Set by the - * adapter: CSTAT_COMPLETE status. - */ - __be16 FrameSize; /* Number of bytes to be transmitted - * as a frame including AC/FC, - * Destination, Source, Routing field - * not including CRC, FS, End Delimiter - * (valid only if START_FRAME bit in - * CSTAT nonzero) must not be zero in - * any list; maximum value: (BUFFER_SIZE - * - 8) * TX_BUF_MAX sum of DataCount - * values in FragmentList must equal - * Frame_Size value in START_FRAME TPL! - * frame data fragment list. - */ - - /* TPL/RPL size in OPEN parameter list depending on maximal - * numbers of fragments used in one parameter list. - */ - Fragment FragList[TX_FRAG_NUM]; /* Maximum: nine frame fragments in one - * TPL actual version of firmware: 9 - * fragments possible. - */ -#pragma pack() - - /* Special proprietary data and precalculations */ - - TPL *NextTPLPtr; /* Pointer to next TPL in chain. */ - unsigned char *MData; - struct sk_buff *Skb; - unsigned char TPLIndex; - volatile unsigned char BusyFlag;/* Flag: TPL busy? */ - dma_addr_t DMABuff; /* DMA IO bus address from dma_map */ -}; - -/* ---------------------Receive Functions-------------------------------* - * define RECEIVE_CSTAT_REQUEST (R) and RECEIVE_CSTAT_COMPLETE (C) values. - * (high-low) - */ -#define RX_VALID 0x0080 /* R: set; tell adapter with - * RECEIVE.VALID interrupt. - * C: reset to zero. - */ -#define RX_FRAME_COMPLETE 0x0040 /* R: must be reset to zero, - * C: set to one. - */ -#define RX_START_FRAME 0x0020 /* R: must be reset to zero. - * C: set to one on the list. - */ -#define RX_END_FRAME 0x0010 /* R: must be reset to zero. - * C: set to one on the list - * that ends the frame. - */ -#define RX_FRAME_IRQ 0x0008 /* R: request interrupt generation - * after receive. - * C: unchanged. - */ -#define RX_INTERFRAME_WAIT 0x0004 /* R: after receiving a frame: - * interrupt and wait for a - * RECEIVE.CONTINUE. - * C: unchanged. - */ -#define RX_PASS_CRC 0x0002 /* R: if set, the adapter includes - * the CRC in data passed. (last four - * bytes; valid only if FRAME_START is - * set) - * C: set, if CRC is included in - * received data. - */ -#define RX_PASS_SRC_ADDR 0x0001 /* R: adapter uses explicit frame - * source address and does not - * overwrite with the adapter node - * address. (valid only if FRAME_START - * is set) - * C: unchanged. - */ -#define RX_RECEIVE_FS 0xFC00 /* R: reserved; must be reset to zero. - * C: on lists with START_FRAME, field - * contains frame status field from - * received frame; otherwise cleared. - */ -#define RX_ADDR_MATCH 0x0300 /* R: reserved; must be reset to zero. - * C: address match code mask. - */ -#define RX_STATUS_MASK 0x00FF /* Mask for receive status bits. */ - -#define RX_INTERN_ADDR_MATCH 0x0100 /* C: internally address match. */ -#define RX_EXTERN_ADDR_MATCH 0x0200 /* C: externally matched via - * XMATCH/XFAIL interface. - */ -#define RX_INTEXT_ADDR_MATCH 0x0300 /* C: internally and externally - * matched. - */ -#define RX_READY (RX_VALID | RX_FRAME_IRQ) /* Ready for receive. */ - -/* Constants for Command Status Interrupt. - * COMMAND_REJECT status field bit functions (SSB.Parm[0]) - */ -#define ILLEGAL_COMMAND 0x0080 /* Set if an unknown command - * is issued to the adapter - */ -#define ADDRESS_ERROR 0x0040 /* Set if any address field in - * the SCB is odd. (not word aligned) - */ -#define ADAPTER_OPEN 0x0020 /* Command issued illegal with - * open adapter. - */ -#define ADAPTER_CLOSE 0x0010 /* Command issued illegal with - * closed adapter. - */ -#define SAME_COMMAND 0x0008 /* Command issued with same command - * already executing. - */ - -/* OPEN_COMPLETION values (SSB.Parm[0], MSB) */ -#define NODE_ADDR_ERROR 0x0040 /* Wrong address or BIA read - * zero address. - */ -#define LIST_SIZE_ERROR 0x0020 /* If List_Size value not in 0, - * 14, 20, 26. - */ -#define BUF_SIZE_ERROR 0x0010 /* Not enough available memory for - * two buffers. - */ -#define TX_BUF_COUNT_ERROR 0x0004 /* Remaining receive buffers less than - * two. - */ -#define OPEN_ERROR 0x0002 /* Error during ring insertion; more - * information in bits 8-15. - */ - -/* Standard return codes */ -#define GOOD_COMPLETION 0x0080 /* =OPEN_SUCCESSFULL */ -#define INVALID_OPEN_OPTION 0x0001 /* OPEN options are not supported by - * the adapter. - */ - -/* OPEN phases; details of OPEN_ERROR (SSB.Parm[0], LSB) */ -#define OPEN_PHASES_MASK 0xF000 /* Check only the bits 8-11. */ -#define LOBE_MEDIA_TEST 0x1000 -#define PHYSICAL_INSERTION 0x2000 -#define ADDRESS_VERIFICATION 0x3000 -#define PARTICIPATION_IN_RING_POLL 0x4000 -#define REQUEST_INITIALISATION 0x5000 -#define FULLDUPLEX_CHECK 0x6000 - -/* OPEN error codes; details of OPEN_ERROR (SSB.Parm[0], LSB) */ -#define OPEN_ERROR_CODES_MASK 0x0F00 /* Check only the bits 12-15. */ -#define OPEN_FUNCTION_FAILURE 0x0100 /* Unable to transmit to itself or - * frames received before insertion. - */ -#define OPEN_SIGNAL_LOSS 0x0200 /* Signal loss condition detected at - * receiver. - */ -#define OPEN_TIMEOUT 0x0500 /* Insertion timer expired before - * logical insertion. - */ -#define OPEN_RING_FAILURE 0x0600 /* Unable to receive own ring purge - * MAC frames. - */ -#define OPEN_RING_BEACONING 0x0700 /* Beacon MAC frame received after - * ring insertion. - */ -#define OPEN_DUPLICATE_NODEADDR 0x0800 /* Other station in ring found - * with the same address. - */ -#define OPEN_REQUEST_INIT 0x0900 /* RPS present but does not respond. */ -#define OPEN_REMOVE_RECEIVED 0x0A00 /* Adapter received a remove adapter - * MAC frame. - */ -#define OPEN_FULLDUPLEX_SET 0x0D00 /* Got this with full duplex on when - * trying to connect to a normal ring. - */ - -/* SET_BRIDGE_PARMS return codes: */ -#define BRIDGE_INVALID_MAX_LEN 0x4000 /* MAX_ROUTING_FIELD_LENGTH odd, - * less than 6 or > 30. - */ -#define BRIDGE_INVALID_SRC_RING 0x2000 /* SOURCE_RING number zero, too large - * or = TARGET_RING. - */ -#define BRIDGE_INVALID_TRG_RING 0x1000 /* TARGET_RING number zero, too large - * or = SOURCE_RING. - */ -#define BRIDGE_INVALID_BRDGE_NO 0x0800 /* BRIDGE_NUMBER too large. */ -#define BRIDGE_INVALID_OPTIONS 0x0400 /* Invalid bridge options. */ -#define BRIDGE_DIAGS_FAILED 0x0200 /* Diagnostics of TMS380SRA failed. */ -#define BRIDGE_NO_SRA 0x0100 /* The TMS380SRA does not exist in HW - * configuration. - */ - -/* - * Bring Up Diagnostics error codes. - */ -#define BUD_INITIAL_ERROR 0x0 -#define BUD_CHECKSUM_ERROR 0x1 -#define BUD_ADAPTER_RAM_ERROR 0x2 -#define BUD_INSTRUCTION_ERROR 0x3 -#define BUD_CONTEXT_ERROR 0x4 -#define BUD_PROTOCOL_ERROR 0x5 -#define BUD_INTERFACE_ERROR 0x6 - -/* BUD constants */ -#define BUD_MAX_RETRIES 3 -#define BUD_MAX_LOOPCNT 6 -#define BUD_TIMEOUT 3000 - -/* Initialization constants */ -#define INIT_MAX_RETRIES 3 /* Maximum three retries. */ -#define INIT_MAX_LOOPCNT 22 /* Maximum loop counts. */ - -/* RING STATUS field values (high/low) */ -#define SIGNAL_LOSS 0x0080 /* Loss of signal on the ring - * detected. - */ -#define HARD_ERROR 0x0040 /* Transmitting or receiving beacon - * frames. - */ -#define SOFT_ERROR 0x0020 /* Report error MAC frame - * transmitted. - */ -#define TRANSMIT_BEACON 0x0010 /* Transmitting beacon frames on the - * ring. - */ -#define LOBE_WIRE_FAULT 0x0008 /* Open or short circuit in the - * cable to concentrator; adapter - * closed. - */ -#define AUTO_REMOVAL_ERROR 0x0004 /* Lobe wrap test failed, deinserted; - * adapter closed. - */ -#define REMOVE_RECEIVED 0x0001 /* Received a remove ring station MAC - * MAC frame request; adapter closed. - */ -#define COUNTER_OVERFLOW 0x8000 /* Overflow of one of the adapters - * error counters; READ.ERROR.LOG. - */ -#define SINGLE_STATION 0x4000 /* Adapter is the only station on the - * ring. - */ -#define RING_RECOVERY 0x2000 /* Claim token MAC frames on the ring; - * reset after ring purge frame. - */ - -#define ADAPTER_CLOSED (LOBE_WIRE_FAULT | AUTO_REMOVAL_ERROR |\ - REMOVE_RECEIVED) - -/* Adapter_check_block.Status field bit assignments: */ -#define DIO_PARITY 0x8000 /* Adapter detects bad parity - * through direct I/O access. - */ -#define DMA_READ_ABORT 0x4000 /* Aborting DMA read operation - * from system Parm[0]: 0=timeout, - * 1=parity error, 2=bus error; - * Parm[1]: 32 bit pointer to host - * system address at failure. - */ -#define DMA_WRITE_ABORT 0x2000 /* Aborting DMA write operation - * to system. (parameters analogous to - * DMA_READ_ABORT) - */ -#define ILLEGAL_OP_CODE 0x1000 /* Illegal operation code in the - * the adapters firmware Parm[0]-2: - * communications processor registers - * R13-R15. - */ -#define PARITY_ERRORS 0x0800 /* Adapter detects internal bus - * parity error. - */ -#define RAM_DATA_ERROR 0x0080 /* Valid only during RAM testing; - * RAM data error Parm[0-1]: 32 bit - * pointer to RAM location. - */ -#define RAM_PARITY_ERROR 0x0040 /* Valid only during RAM testing; - * RAM parity error Parm[0-1]: 32 bit - * pointer to RAM location. - */ -#define RING_UNDERRUN 0x0020 /* Internal DMA underrun when - * transmitting onto ring. - */ -#define INVALID_IRQ 0x0008 /* Unrecognized interrupt generated - * internal to adapter Parm[0-2]: - * adapter register R13-R15. - */ -#define INVALID_ERROR_IRQ 0x0004 /* Unrecognized error interrupt - * generated Parm[0-2]: adapter register - * R13-R15. - */ -#define INVALID_XOP 0x0002 /* Unrecognized XOP request in - * communication processor Parm[0-2]: - * adapter register R13-R15. - */ -#define CHECKADDR 0x05E0 /* Adapter check status information - * address offset. - */ -#define ROM_PAGE_0 0x0000 /* Adapter ROM page 0. */ - -/* - * RECEIVE.STATUS interrupt result SSB values: (high-low) - * (RECEIVE_COMPLETE field bit definitions in SSB.Parm[0]) - */ -#define RX_COMPLETE 0x0080 /* SSB.Parm[0]; SSB.Parm[1]: 32 - * bit pointer to last RPL. - */ -#define RX_SUSPENDED 0x0040 /* SSB.Parm[0]; SSB.Parm[1]: 32 - * bit pointer to RPL with odd - * forward pointer. - */ - -/* Valid receive CSTAT: */ -#define RX_FRAME_CONTROL_BITS (RX_VALID | RX_START_FRAME | RX_END_FRAME | \ - RX_FRAME_COMPLETE) -#define VALID_SINGLE_BUFFER_FRAME (RX_START_FRAME | RX_END_FRAME | \ - RX_FRAME_COMPLETE) - -typedef enum SKB_STAT SKB_STAT; -enum SKB_STAT { - SKB_UNAVAILABLE, - SKB_DMA_DIRECT, - SKB_DATA_COPY -}; - -/* Receive Parameter List (RPL) The length of the RPLs has to be initialized - * in the OPL. (OPEN parameter list) - */ -#define RPL_NUM 3 - -#define RX_FRAG_NUM 1 /* Maximal number of used fragments in one RPL. - * (up to firmware v2.24: 3, now: up to 9) - */ - -#pragma pack(1) -typedef struct s_RPL RPL; -struct s_RPL { /* Receive Parameter List */ - __be32 NextRPLAddr; /* Pointer to next RPL in chain - * (normalized = physical 32 bit - * address) if pointer is odd: this - * is last RPL. Pointing to itself can - * cause problems! - */ - volatile u_int16_t Status; /* Set by creation of Receive Parameter - * List RECEIVE_CSTAT_COMPLETE set by - * adapter in lists that start or end - * a frame. - */ - volatile __be16 FrameSize; /* Number of bytes received as a - * frame including AC/FC, Destination, - * Source, Routing field not including - * CRC, FS (Frame Status), End Delimiter - * (valid only if START_FRAME bit in - * CSTAT nonzero) must not be zero in - * any list; maximum value: (BUFFER_SIZE - * - 8) * TX_BUF_MAX sum of DataCount - * values in FragmentList must equal - * Frame_Size value in START_FRAME TPL! - * frame data fragment list - */ - - /* TPL/RPL size in OPEN parameter list depending on maximal numbers - * of fragments used in one parameter list. - */ - Fragment FragList[RX_FRAG_NUM]; /* Maximum: nine frame fragments in - * one TPL. Actual version of firmware: - * 9 fragments possible. - */ -#pragma pack() - - /* Special proprietary data and precalculations. */ - RPL *NextRPLPtr; /* Logical pointer to next RPL in chain. */ - unsigned char *MData; - struct sk_buff *Skb; - SKB_STAT SkbStat; - int RPLIndex; - dma_addr_t DMABuff; /* DMA IO bus address from dma_map */ -}; - -/* Information that need to be kept for each board. */ -typedef struct net_local { -#pragma pack(1) - IPB ipb; /* Initialization Parameter Block. */ - SCB scb; /* System Command Block: system to adapter - * communication. - */ - SSB ssb; /* System Status Block: adapter to system - * communication. - */ - OPB ocpl; /* Open Options Parameter Block. */ - - ERRORTAB errorlogtable; /* Adapter statistic error counters. - * (read from adapter memory) - */ - unsigned char ProductID[PROD_ID_SIZE + 1]; /* Product ID */ -#pragma pack() - - TPL Tpl[TPL_NUM]; - TPL *TplFree; - TPL *TplBusy; - unsigned char LocalTxBuffers[TPL_NUM][DEFAULT_PACKET_SIZE]; - - RPL Rpl[RPL_NUM]; - RPL *RplHead; - RPL *RplTail; - unsigned char LocalRxBuffers[RPL_NUM][DEFAULT_PACKET_SIZE]; - - struct device *pdev; - int DataRate; - unsigned char ScbInUse; - unsigned short CMDqueue; - - unsigned long AdapterOpenFlag:1; - unsigned long AdapterVirtOpenFlag:1; - unsigned long OpenCommandIssued:1; - unsigned long TransmitCommandActive:1; - unsigned long TransmitHaltScheduled:1; - unsigned long HaltInProgress:1; - unsigned long LobeWireFaultLogged:1; - unsigned long ReOpenInProgress:1; - unsigned long Sleeping:1; - - unsigned long LastOpenStatus; - unsigned short CurrentRingStatus; - unsigned long MaxPacketSize; - - unsigned long StartTime; - unsigned long LastSendTime; - - struct tr_statistics MacStat; /* MAC statistics structure */ - - unsigned long dmalimit; /* the max DMA address (ie, ISA) */ - dma_addr_t dmabuffer; /* the DMA bus address corresponding to - priv. Might be different from virt_to_bus() - for architectures with IO MMU (Alpha) */ - - struct timer_list timer; - - wait_queue_head_t wait_for_tok_int; - - INTPTRS intptrs; /* Internal adapter pointer. Must be read - * before OPEN command. - */ - unsigned short (*setnselout)(struct net_device *); - unsigned short (*sifreadb)(struct net_device *, unsigned short); - void (*sifwriteb)(struct net_device *, unsigned short, unsigned short); - unsigned short (*sifreadw)(struct net_device *, unsigned short); - void (*sifwritew)(struct net_device *, unsigned short, unsigned short); - - spinlock_t lock; /* SMP protection */ - void *tmspriv; -} NET_LOCAL; - -#endif /* __KERNEL__ */ -#endif /* __LINUX_TMS380TR_H */ diff --git a/trunk/drivers/net/tokenring/tmspci.c b/trunk/drivers/net/tokenring/tmspci.c deleted file mode 100644 index fb9918da5792..000000000000 --- a/trunk/drivers/net/tokenring/tmspci.c +++ /dev/null @@ -1,248 +0,0 @@ -/* - * tmspci.c: A generic network driver for TMS380-based PCI token ring cards. - * - * Written 1999 by Adam Fritzler - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * This driver module supports the following cards: - * - SysKonnect TR4/16(+) PCI (SK-4590) - * - SysKonnect TR4/16 PCI (SK-4591) - * - Compaq TR 4/16 PCI - * - Thomas-Conrad TC4048 4/16 PCI - * - 3Com 3C339 Token Link Velocity - * - * Maintainer(s): - * AF Adam Fritzler - * - * Modification History: - * 30-Dec-99 AF Split off from the tms380tr driver. - * 22-Jan-00 AF Updated to use indirect read/writes - * 23-Nov-00 JG New PCI API, cleanups - * - * TODO: - * 1. See if we can use MMIO instead of port accesses - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "tms380tr.h" - -static char version[] __devinitdata = -"tmspci.c: v1.02 23/11/2000 by Adam Fritzler\n"; - -#define TMS_PCI_IO_EXTENT 32 - -struct card_info { - unsigned char nselout[2]; /* NSELOUT vals for 4mb([0]) and 16mb([1]) */ - char *name; -}; - -static struct card_info card_info_table[] = { - { {0x03, 0x01}, "Compaq 4/16 TR PCI"}, - { {0x03, 0x01}, "SK NET TR 4/16 PCI"}, - { {0x03, 0x01}, "Thomas-Conrad TC4048 PCI 4/16"}, - { {0x03, 0x01}, "3Com Token Link Velocity"}, -}; - -static DEFINE_PCI_DEVICE_TABLE(tmspci_pci_tbl) = { - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TOKENRING, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_TR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, - { PCI_VENDOR_ID_TCONRAD, PCI_DEVICE_ID_TCONRAD_TOKENRING, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 }, - { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C339, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(pci, tmspci_pci_tbl); - -MODULE_LICENSE("GPL"); - -static void tms_pci_read_eeprom(struct net_device *dev); -static unsigned short tms_pci_setnselout_pins(struct net_device *dev); - -static unsigned short tms_pci_sifreadb(struct net_device *dev, unsigned short reg) -{ - return inb(dev->base_addr + reg); -} - -static unsigned short tms_pci_sifreadw(struct net_device *dev, unsigned short reg) -{ - return inw(dev->base_addr + reg); -} - -static void tms_pci_sifwriteb(struct net_device *dev, unsigned short val, unsigned short reg) -{ - outb(val, dev->base_addr + reg); -} - -static void tms_pci_sifwritew(struct net_device *dev, unsigned short val, unsigned short reg) -{ - outw(val, dev->base_addr + reg); -} - -static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - static int versionprinted; - struct net_device *dev; - struct net_local *tp; - int ret; - unsigned int pci_irq_line; - unsigned long pci_ioaddr; - struct card_info *cardinfo = &card_info_table[ent->driver_data]; - - if (versionprinted++ == 0) - printk("%s", version); - - if (pci_enable_device(pdev)) - return -EIO; - - /* Remove I/O space marker in bit 0. */ - pci_irq_line = pdev->irq; - pci_ioaddr = pci_resource_start (pdev, 0); - - /* At this point we have found a valid card. */ - dev = alloc_trdev(sizeof(struct net_local)); - if (!dev) - return -ENOMEM; - - if (!request_region(pci_ioaddr, TMS_PCI_IO_EXTENT, dev->name)) { - ret = -EBUSY; - goto err_out_trdev; - } - - dev->base_addr = pci_ioaddr; - dev->irq = pci_irq_line; - dev->dma = 0; - - dev_info(&pdev->dev, "%s\n", cardinfo->name); - dev_info(&pdev->dev, " IO: %#4lx IRQ: %d\n", dev->base_addr, dev->irq); - - tms_pci_read_eeprom(dev); - - dev_info(&pdev->dev, " Ring Station Address: %pM\n", dev->dev_addr); - - ret = tmsdev_init(dev, &pdev->dev); - if (ret) { - dev_info(&pdev->dev, "unable to get memory for dev->priv.\n"); - goto err_out_region; - } - - tp = netdev_priv(dev); - tp->setnselout = tms_pci_setnselout_pins; - - tp->sifreadb = tms_pci_sifreadb; - tp->sifreadw = tms_pci_sifreadw; - tp->sifwriteb = tms_pci_sifwriteb; - tp->sifwritew = tms_pci_sifwritew; - - memcpy(tp->ProductID, cardinfo->name, PROD_ID_SIZE + 1); - - tp->tmspriv = cardinfo; - - dev->netdev_ops = &tms380tr_netdev_ops; - - ret = request_irq(pdev->irq, tms380tr_interrupt, IRQF_SHARED, - dev->name, dev); - if (ret) - goto err_out_tmsdev; - - pci_set_drvdata(pdev, dev); - SET_NETDEV_DEV(dev, &pdev->dev); - - ret = register_netdev(dev); - if (ret) - goto err_out_irq; - - return 0; - -err_out_irq: - free_irq(pdev->irq, dev); -err_out_tmsdev: - pci_set_drvdata(pdev, NULL); - tmsdev_term(dev); -err_out_region: - release_region(pci_ioaddr, TMS_PCI_IO_EXTENT); -err_out_trdev: - free_netdev(dev); - return ret; -} - -/* - * Reads MAC address from adapter RAM, which should've read it from - * the onboard ROM. - * - * Calling this on a board that does not support it can be a very - * dangerous thing. The Madge board, for instance, will lock your - * machine hard when this is called. Luckily, its supported in a - * separate driver. --ASF - */ -static void tms_pci_read_eeprom(struct net_device *dev) -{ - int i; - - /* Address: 0000:0000 */ - tms_pci_sifwritew(dev, 0, SIFADX); - tms_pci_sifwritew(dev, 0, SIFADR); - - /* Read six byte MAC address data */ - dev->addr_len = 6; - for(i = 0; i < 6; i++) - dev->dev_addr[i] = tms_pci_sifreadw(dev, SIFINC) >> 8; -} - -static unsigned short tms_pci_setnselout_pins(struct net_device *dev) -{ - unsigned short val = 0; - struct net_local *tp = netdev_priv(dev); - struct card_info *cardinfo = tp->tmspriv; - - if(tp->DataRate == SPEED_4) - val |= cardinfo->nselout[0]; /* Set 4Mbps */ - else - val |= cardinfo->nselout[1]; /* Set 16Mbps */ - return val; -} - -static void __devexit tms_pci_detach (struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - - BUG_ON(!dev); - unregister_netdev(dev); - release_region(dev->base_addr, TMS_PCI_IO_EXTENT); - free_irq(dev->irq, dev); - tmsdev_term(dev); - free_netdev(dev); - pci_set_drvdata(pdev, NULL); -} - -static struct pci_driver tms_pci_driver = { - .name = "tmspci", - .id_table = tmspci_pci_tbl, - .probe = tms_pci_attach, - .remove = __devexit_p(tms_pci_detach), -}; - -static int __init tms_pci_init (void) -{ - return pci_register_driver(&tms_pci_driver); -} - -static void __exit tms_pci_rmmod (void) -{ - pci_unregister_driver (&tms_pci_driver); -} - -module_init(tms_pci_init); -module_exit(tms_pci_rmmod); - diff --git a/trunk/drivers/net/tun.c b/trunk/drivers/net/tun.c index bb8c72c79c6f..987aeefbc774 100644 --- a/trunk/drivers/net/tun.c +++ b/trunk/drivers/net/tun.c @@ -313,7 +313,7 @@ static int run_filter(struct tap_filter *filter, const struct sk_buff *skb) /* Exact match */ for (i = 0; i < filter->count; i++) - if (!compare_ether_addr(eh->h_dest, filter->addr[i])) + if (ether_addr_equal(eh->h_dest, filter->addr[i])) return 1; /* Inexact match (multicast only) */ diff --git a/trunk/drivers/net/usb/asix.c b/trunk/drivers/net/usb/asix.c index 42b5151aa78a..71e2b0523bc2 100644 --- a/trunk/drivers/net/usb/asix.c +++ b/trunk/drivers/net/usb/asix.c @@ -1647,6 +1647,7 @@ static struct usb_driver asix_driver = { .resume = usbnet_resume, .disconnect = usbnet_disconnect, .supports_autosuspend = 1, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(asix_driver); diff --git a/trunk/drivers/net/usb/catc.c b/trunk/drivers/net/usb/catc.c index 182cfb4aeb1d..26c5bebd9eca 100644 --- a/trunk/drivers/net/usb/catc.c +++ b/trunk/drivers/net/usb/catc.c @@ -338,16 +338,18 @@ static void catc_irq_done(struct urb *urb) } else { catc->rx_urb->dev = catc->usbdev; if ((res = usb_submit_urb(catc->rx_urb, GFP_ATOMIC)) < 0) { - err("submit(rx_urb) status %d", res); + dev_err(&catc->usbdev->dev, + "submit(rx_urb) status %d\n", res); } } } resubmit: res = usb_submit_urb (urb, GFP_ATOMIC); if (res) - err ("can't resubmit intr, %s-%s, status %d", - catc->usbdev->bus->bus_name, - catc->usbdev->devpath, res); + dev_err(&catc->usbdev->dev, + "can't resubmit intr, %s-%s, status %d\n", + catc->usbdev->bus->bus_name, + catc->usbdev->devpath, res); } /* @@ -366,7 +368,8 @@ static int catc_tx_run(struct catc *catc) catc->tx_urb->dev = catc->usbdev; if ((status = usb_submit_urb(catc->tx_urb, GFP_ATOMIC)) < 0) - err("submit(tx_urb), status %d", status); + dev_err(&catc->usbdev->dev, "submit(tx_urb), status %d\n", + status); catc->tx_idx = !catc->tx_idx; catc->tx_ptr = 0; @@ -496,7 +499,8 @@ static void catc_ctrl_run(struct catc *catc) memcpy(catc->ctrl_buf, q->buf, q->len); if ((status = usb_submit_urb(catc->ctrl_urb, GFP_ATOMIC))) - err("submit(ctrl_urb) status %d", status); + dev_err(&catc->usbdev->dev, "submit(ctrl_urb) status %d\n", + status); } static void catc_ctrl_done(struct urb *urb) @@ -555,7 +559,7 @@ static int catc_ctrl_async(struct catc *catc, u8 dir, u8 request, u16 value, catc->ctrl_head = (catc->ctrl_head + 1) & (CTRL_QUEUE - 1); if (catc->ctrl_head == catc->ctrl_tail) { - err("ctrl queue full"); + dev_err(&catc->usbdev->dev, "ctrl queue full\n"); catc->ctrl_tail = (catc->ctrl_tail + 1) & (CTRL_QUEUE - 1); retval = -1; } @@ -714,7 +718,8 @@ static int catc_open(struct net_device *netdev) catc->irq_urb->dev = catc->usbdev; if ((status = usb_submit_urb(catc->irq_urb, GFP_KERNEL)) < 0) { - err("submit(irq_urb) status %d", status); + dev_err(&catc->usbdev->dev, "submit(irq_urb) status %d\n", + status); return -1; } @@ -769,7 +774,7 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id if (usb_set_interface(usbdev, intf->altsetting->desc.bInterfaceNumber, 1)) { - err("Can't set altsetting 1."); + dev_err(&intf->dev, "Can't set altsetting 1.\n"); return -EIO; } @@ -799,7 +804,7 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id catc->irq_urb = usb_alloc_urb(0, GFP_KERNEL); if ((!catc->ctrl_urb) || (!catc->tx_urb) || (!catc->rx_urb) || (!catc->irq_urb)) { - err("No free urbs available."); + dev_err(&intf->dev, "No free urbs available.\n"); usb_free_urb(catc->ctrl_urb); usb_free_urb(catc->tx_urb); usb_free_urb(catc->rx_urb); @@ -947,6 +952,7 @@ static struct usb_driver catc_driver = { .probe = catc_probe, .disconnect = catc_disconnect, .id_table = catc_id_table, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(catc_driver); diff --git a/trunk/drivers/net/usb/cdc-phonet.c b/trunk/drivers/net/usb/cdc-phonet.c index 3e41b00c6806..d848d4dd5754 100644 --- a/trunk/drivers/net/usb/cdc-phonet.c +++ b/trunk/drivers/net/usb/cdc-phonet.c @@ -457,6 +457,7 @@ static struct usb_driver usbpn_driver = { .probe = usbpn_probe, .disconnect = usbpn_disconnect, .id_table = usbpn_ids, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(usbpn_driver); diff --git a/trunk/drivers/net/usb/cdc_eem.c b/trunk/drivers/net/usb/cdc_eem.c index 685a4e22c768..434d5af8e6fb 100644 --- a/trunk/drivers/net/usb/cdc_eem.c +++ b/trunk/drivers/net/usb/cdc_eem.c @@ -368,6 +368,7 @@ static struct usb_driver eem_driver = { .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(eem_driver); diff --git a/trunk/drivers/net/usb/cdc_ether.c b/trunk/drivers/net/usb/cdc_ether.c index 425e201f597c..a03de7197049 100644 --- a/trunk/drivers/net/usb/cdc_ether.c +++ b/trunk/drivers/net/usb/cdc_ether.c @@ -486,6 +486,7 @@ static const struct driver_info wwan_info = { #define HUAWEI_VENDOR_ID 0x12D1 #define NOVATEL_VENDOR_ID 0x1410 +#define ZTE_VENDOR_ID 0x19D2 static const struct usb_device_id products [] = { /* @@ -617,6 +618,61 @@ static const struct usb_device_id products [] = { .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, .bInterfaceProtocol = USB_CDC_PROTO_NONE, .driver_info = (unsigned long)&wwan_info, +}, { + /* ZTE (Vodafone) K3805-Z */ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_PRODUCT + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = ZTE_VENDOR_ID, + .idProduct = 0x1003, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, + .bInterfaceProtocol = USB_CDC_PROTO_NONE, + .driver_info = (unsigned long)&wwan_info, +}, { + /* ZTE (Vodafone) K3806-Z */ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_PRODUCT + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = ZTE_VENDOR_ID, + .idProduct = 0x1015, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, + .bInterfaceProtocol = USB_CDC_PROTO_NONE, + .driver_info = (unsigned long)&wwan_info, +}, { + /* ZTE (Vodafone) K4510-Z */ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_PRODUCT + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = ZTE_VENDOR_ID, + .idProduct = 0x1173, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, + .bInterfaceProtocol = USB_CDC_PROTO_NONE, + .driver_info = (unsigned long)&wwan_info, +}, { + /* ZTE (Vodafone) K3770-Z */ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_PRODUCT + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = ZTE_VENDOR_ID, + .idProduct = 0x1177, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, + .bInterfaceProtocol = USB_CDC_PROTO_NONE, + .driver_info = (unsigned long)&wwan_info, +}, { + /* ZTE (Vodafone) K3772-Z */ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_PRODUCT + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = ZTE_VENDOR_ID, + .idProduct = 0x1181, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, + .bInterfaceProtocol = USB_CDC_PROTO_NONE, + .driver_info = (unsigned long)&wwan_info, }, { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), @@ -649,6 +705,7 @@ static struct usb_driver cdc_driver = { .resume = usbnet_resume, .reset_resume = usbnet_resume, .supports_autosuspend = 1, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(cdc_driver); diff --git a/trunk/drivers/net/usb/cdc_ncm.c b/trunk/drivers/net/usb/cdc_ncm.c index 7adc9f6b0ea1..4b9513fcf275 100644 --- a/trunk/drivers/net/usb/cdc_ncm.c +++ b/trunk/drivers/net/usb/cdc_ncm.c @@ -1212,6 +1212,7 @@ static struct usb_driver cdc_ncm_driver = { .resume = usbnet_resume, .reset_resume = usbnet_resume, .supports_autosuspend = 1, + .disable_hub_initiated_lpm = 1, }; static const struct ethtool_ops cdc_ncm_ethtool_ops = { diff --git a/trunk/drivers/net/usb/cdc_subset.c b/trunk/drivers/net/usb/cdc_subset.c index b403d934e4e3..0d1fe89ae0bd 100644 --- a/trunk/drivers/net/usb/cdc_subset.c +++ b/trunk/drivers/net/usb/cdc_subset.c @@ -336,6 +336,7 @@ static struct usb_driver cdc_subset_driver = { .resume = usbnet_resume, .disconnect = usbnet_disconnect, .id_table = products, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(cdc_subset_driver); diff --git a/trunk/drivers/net/usb/cx82310_eth.c b/trunk/drivers/net/usb/cx82310_eth.c index 0e0531356e62..49ab45e17fe8 100644 --- a/trunk/drivers/net/usb/cx82310_eth.c +++ b/trunk/drivers/net/usb/cx82310_eth.c @@ -327,6 +327,7 @@ static struct usb_driver cx82310_driver = { .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(cx82310_driver); diff --git a/trunk/drivers/net/usb/dm9601.c b/trunk/drivers/net/usb/dm9601.c index b97226318ea5..e0433ce6ced7 100644 --- a/trunk/drivers/net/usb/dm9601.c +++ b/trunk/drivers/net/usb/dm9601.c @@ -670,6 +670,7 @@ static struct usb_driver dm9601_driver = { .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(dm9601_driver); diff --git a/trunk/drivers/net/usb/gl620a.c b/trunk/drivers/net/usb/gl620a.c index 38266bdae26b..db3c8021f2a3 100644 --- a/trunk/drivers/net/usb/gl620a.c +++ b/trunk/drivers/net/usb/gl620a.c @@ -225,6 +225,7 @@ static struct usb_driver gl620a_driver = { .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(gl620a_driver); diff --git a/trunk/drivers/net/usb/hso.c b/trunk/drivers/net/usb/hso.c index 2d2a6882ba33..62f30b46fa42 100644 --- a/trunk/drivers/net/usb/hso.c +++ b/trunk/drivers/net/usb/hso.c @@ -106,13 +106,6 @@ #define MAX_RX_URBS 2 -static inline struct hso_serial *get_serial_by_tty(struct tty_struct *tty) -{ - if (tty) - return tty->driver_data; - return NULL; -} - /*****************************************************************************/ /* Debugging functions */ /*****************************************************************************/ @@ -255,9 +248,8 @@ struct hso_serial { u8 dtr_state; unsigned tx_urb_used:1; + struct tty_port port; /* from usb_serial_port */ - struct tty_struct *tty; - int open_count; spinlock_t serial_lock; int (*write_data) (struct hso_serial *serial); @@ -1114,7 +1106,7 @@ static void hso_init_termios(struct ktermios *termios) static void _hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) { - struct hso_serial *serial = get_serial_by_tty(tty); + struct hso_serial *serial = tty->driver_data; struct ktermios *termios; if (!serial) { @@ -1190,7 +1182,7 @@ static void put_rxbuf_data_and_resubmit_ctrl_urb(struct hso_serial *serial) struct urb *urb; urb = serial->rx_urb[0]; - if (serial->open_count > 0) { + if (serial->port.count > 0) { count = put_rxbuf_data(urb, serial); if (count == -1) return; @@ -1226,7 +1218,7 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb) DUMP1(urb->transfer_buffer, urb->actual_length); /* Anyone listening? */ - if (serial->open_count == 0) + if (serial->port.count == 0) return; if (status == 0) { @@ -1268,7 +1260,7 @@ static void hso_unthrottle_tasklet(struct hso_serial *serial) static void hso_unthrottle(struct tty_struct *tty) { - struct hso_serial *serial = get_serial_by_tty(tty); + struct hso_serial *serial = tty->driver_data; tasklet_hi_schedule(&serial->unthrottle_tasklet); } @@ -1304,15 +1296,12 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp) kref_get(&serial->parent->ref); /* setup */ - spin_lock_irq(&serial->serial_lock); tty->driver_data = serial; - tty_kref_put(serial->tty); - serial->tty = tty_kref_get(tty); - spin_unlock_irq(&serial->serial_lock); + tty_port_tty_set(&serial->port, tty); /* check for port already opened, if not set the termios */ - serial->open_count++; - if (serial->open_count == 1) { + serial->port.count++; + if (serial->port.count == 1) { serial->rx_state = RX_IDLE; /* Force default termio settings */ _hso_serial_set_termios(tty, NULL); @@ -1324,7 +1313,7 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp) result = hso_start_serial_device(serial->parent, GFP_KERNEL); if (result) { hso_stop_serial_device(serial->parent); - serial->open_count--; + serial->port.count--; kref_put(&serial->parent->ref, hso_serial_ref_free); } } else { @@ -1361,17 +1350,11 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp) /* reset the rts and dtr */ /* do the actual close */ - serial->open_count--; + serial->port.count--; - if (serial->open_count <= 0) { - serial->open_count = 0; - spin_lock_irq(&serial->serial_lock); - if (serial->tty == tty) { - serial->tty->driver_data = NULL; - serial->tty = NULL; - tty_kref_put(tty); - } - spin_unlock_irq(&serial->serial_lock); + if (serial->port.count <= 0) { + serial->port.count = 0; + tty_port_tty_set(&serial->port, NULL); if (!usb_gone) hso_stop_serial_device(serial->parent); tasklet_kill(&serial->unthrottle_tasklet); @@ -1390,7 +1373,7 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp) static int hso_serial_write(struct tty_struct *tty, const unsigned char *buf, int count) { - struct hso_serial *serial = get_serial_by_tty(tty); + struct hso_serial *serial = tty->driver_data; int space, tx_bytes; unsigned long flags; @@ -1422,7 +1405,7 @@ static int hso_serial_write(struct tty_struct *tty, const unsigned char *buf, /* how much room is there for writing */ static int hso_serial_write_room(struct tty_struct *tty) { - struct hso_serial *serial = get_serial_by_tty(tty); + struct hso_serial *serial = tty->driver_data; int room; unsigned long flags; @@ -1437,7 +1420,7 @@ static int hso_serial_write_room(struct tty_struct *tty) /* setup the term */ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) { - struct hso_serial *serial = get_serial_by_tty(tty); + struct hso_serial *serial = tty->driver_data; unsigned long flags; if (old) @@ -1446,7 +1429,7 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) /* the actual setup */ spin_lock_irqsave(&serial->serial_lock, flags); - if (serial->open_count) + if (serial->port.count) _hso_serial_set_termios(tty, old); else tty->termios = old; @@ -1458,7 +1441,7 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) /* how many characters in the buffer */ static int hso_serial_chars_in_buffer(struct tty_struct *tty) { - struct hso_serial *serial = get_serial_by_tty(tty); + struct hso_serial *serial = tty->driver_data; int chars; unsigned long flags; @@ -1629,7 +1612,7 @@ static int hso_get_count(struct tty_struct *tty, struct serial_icounter_struct *icount) { struct uart_icount cnow; - struct hso_serial *serial = get_serial_by_tty(tty); + struct hso_serial *serial = tty->driver_data; struct hso_tiocmget *tiocmget = serial->tiocmget; memset(icount, 0, sizeof(struct serial_icounter_struct)); @@ -1659,7 +1642,7 @@ static int hso_get_count(struct tty_struct *tty, static int hso_serial_tiocmget(struct tty_struct *tty) { int retval; - struct hso_serial *serial = get_serial_by_tty(tty); + struct hso_serial *serial = tty->driver_data; struct hso_tiocmget *tiocmget; u16 UART_state_bitmap; @@ -1693,7 +1676,7 @@ static int hso_serial_tiocmset(struct tty_struct *tty, int val = 0; unsigned long flags; int if_num; - struct hso_serial *serial = get_serial_by_tty(tty); + struct hso_serial *serial = tty->driver_data; /* sanity check */ if (!serial) { @@ -1733,7 +1716,7 @@ static int hso_serial_tiocmset(struct tty_struct *tty, static int hso_serial_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { - struct hso_serial *serial = get_serial_by_tty(tty); + struct hso_serial *serial = tty->driver_data; int ret = 0; D4("IOCTL cmd: %d, arg: %ld", cmd, arg); @@ -1905,7 +1888,7 @@ static void intr_callback(struct urb *urb) D1("Pending read interrupt on port %d\n", i); spin_lock(&serial->serial_lock); if (serial->rx_state == RX_IDLE && - serial->open_count > 0) { + serial->port.count > 0) { /* Setup and send a ctrl req read on * port i */ if (!serial->rx_urb_filled[0]) { @@ -1954,14 +1937,13 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb) spin_lock(&serial->serial_lock); serial->tx_urb_used = 0; - tty = tty_kref_get(serial->tty); spin_unlock(&serial->serial_lock); if (status) { handle_usb_error(status, __func__, serial->parent); - tty_kref_put(tty); return; } hso_put_activity(serial->parent); + tty = tty_port_tty_get(&serial->port); if (tty) { tty_wakeup(tty); tty_kref_put(tty); @@ -2001,7 +1983,6 @@ static void ctrl_callback(struct urb *urb) struct hso_serial *serial = urb->context; struct usb_ctrlrequest *req; int status = urb->status; - struct tty_struct *tty; /* sanity check */ if (!serial) @@ -2009,11 +1990,9 @@ static void ctrl_callback(struct urb *urb) spin_lock(&serial->serial_lock); serial->tx_urb_used = 0; - tty = tty_kref_get(serial->tty); spin_unlock(&serial->serial_lock); if (status) { handle_usb_error(status, __func__, serial->parent); - tty_kref_put(tty); return; } @@ -2031,13 +2010,15 @@ static void ctrl_callback(struct urb *urb) put_rxbuf_data_and_resubmit_ctrl_urb(serial); spin_unlock(&serial->serial_lock); } else { + struct tty_struct *tty = tty_port_tty_get(&serial->port); hso_put_activity(serial->parent); - if (tty) + if (tty) { tty_wakeup(tty); + tty_kref_put(tty); + } /* response to a write command */ hso_kick_transmit(serial); } - tty_kref_put(tty); } /* handle RX data for serial port */ @@ -2053,8 +2034,7 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial) return -2; } - /* All callers to put_rxbuf_data hold serial_lock */ - tty = tty_kref_get(serial->tty); + tty = tty_port_tty_get(&serial->port); /* Push data to tty */ if (tty) { @@ -2074,12 +2054,12 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial) write_length_remaining -= curr_write_len; tty_flip_buffer_push(tty); } + tty_kref_put(tty); } if (write_length_remaining == 0) { serial->curr_rx_urb_offset = 0; serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; } - tty_kref_put(tty); return write_length_remaining; } @@ -2320,6 +2300,7 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs, serial->minor = minor; serial->magic = HSO_SERIAL_MAGIC; spin_lock_init(&serial->serial_lock); + tty_port_init(&serial->port); serial->num_rx_urbs = num_urbs; /* RX, allocate urb and initialize */ @@ -3098,7 +3079,7 @@ static int hso_resume(struct usb_interface *iface) /* Start all serial ports */ for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { if (serial_table[i] && (serial_table[i]->interface == iface)) { - if (dev2ser(serial_table[i])->open_count) { + if (dev2ser(serial_table[i])->port.count) { result = hso_start_serial_device(serial_table[i], GFP_NOIO); hso_kick_transmit(dev2ser(serial_table[i])); @@ -3172,13 +3153,12 @@ static void hso_free_interface(struct usb_interface *interface) if (serial_table[i] && (serial_table[i]->interface == interface)) { hso_dev = dev2ser(serial_table[i]); - spin_lock_irq(&hso_dev->serial_lock); - tty = tty_kref_get(hso_dev->tty); - spin_unlock_irq(&hso_dev->serial_lock); - if (tty) + tty = tty_port_tty_get(&hso_dev->port); + if (tty) { tty_hangup(tty); + tty_kref_put(tty); + } mutex_lock(&hso_dev->parent->mutex); - tty_kref_put(tty); hso_dev->parent->usb_gone = 1; mutex_unlock(&hso_dev->parent->mutex); kref_put(&serial_table[i]->ref, hso_serial_ref_free); @@ -3291,6 +3271,7 @@ static struct usb_driver hso_driver = { .resume = hso_resume, .reset_resume = hso_resume, .supports_autosuspend = 1, + .disable_hub_initiated_lpm = 1, }; static int __init hso_init(void) @@ -3312,7 +3293,6 @@ static int __init hso_init(void) return -ENOMEM; /* fill in all needed values */ - tty_drv->magic = TTY_DRIVER_MAGIC; tty_drv->driver_name = driver_name; tty_drv->name = tty_filename; @@ -3333,7 +3313,7 @@ static int __init hso_init(void) if (result) { printk(KERN_ERR "%s - tty_register_driver failed(%d)\n", __func__, result); - return result; + goto err_free_tty; } /* register this module as an usb driver */ @@ -3341,13 +3321,16 @@ static int __init hso_init(void) if (result) { printk(KERN_ERR "Could not register hso driver? error: %d\n", result); - /* cleanup serial interface */ - tty_unregister_driver(tty_drv); - return result; + goto err_unreg_tty; } /* done */ return 0; +err_unreg_tty: + tty_unregister_driver(tty_drv); +err_free_tty: + put_tty_driver(tty_drv); + return result; } static void __exit hso_exit(void) @@ -3355,6 +3338,7 @@ static void __exit hso_exit(void) printk(KERN_INFO "hso: unloaded\n"); tty_unregister_driver(tty_drv); + put_tty_driver(tty_drv); /* deregister the usb driver */ usb_deregister(&hso_driver); } diff --git a/trunk/drivers/net/usb/int51x1.c b/trunk/drivers/net/usb/int51x1.c index 12a22a453ff1..8de641713d5f 100644 --- a/trunk/drivers/net/usb/int51x1.c +++ b/trunk/drivers/net/usb/int51x1.c @@ -236,6 +236,7 @@ static struct usb_driver int51x1_driver = { .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(int51x1_driver); diff --git a/trunk/drivers/net/usb/ipheth.c b/trunk/drivers/net/usb/ipheth.c index dd78c4cbd459..964031e3da87 100644 --- a/trunk/drivers/net/usb/ipheth.c +++ b/trunk/drivers/net/usb/ipheth.c @@ -209,7 +209,8 @@ static void ipheth_rcvbulk_callback(struct urb *urb) case 0: break; default: - err("%s: urb status: %d", __func__, status); + dev_err(&dev->intf->dev, "%s: urb status: %d\n", + __func__, status); return; } @@ -222,7 +223,8 @@ static void ipheth_rcvbulk_callback(struct urb *urb) skb = dev_alloc_skb(len); if (!skb) { - err("%s: dev_alloc_skb: -ENOMEM", __func__); + dev_err(&dev->intf->dev, "%s: dev_alloc_skb: -ENOMEM\n", + __func__); dev->net->stats.rx_dropped++; return; } @@ -251,7 +253,8 @@ static void ipheth_sndbulk_callback(struct urb *urb) status != -ENOENT && status != -ECONNRESET && status != -ESHUTDOWN) - err("%s: urb status: %d", __func__, status); + dev_err(&dev->intf->dev, "%s: urb status: %d\n", + __func__, status); dev_kfree_skb_irq(dev->tx_skb); netif_wake_queue(dev->net); @@ -271,7 +274,8 @@ static int ipheth_carrier_set(struct ipheth_device *dev) dev->ctrl_buf, IPHETH_CTRL_BUF_SIZE, IPHETH_CTRL_TIMEOUT); if (retval < 0) { - err("%s: usb_control_msg: %d", __func__, retval); + dev_err(&dev->intf->dev, "%s: usb_control_msg: %d\n", + __func__, retval); return retval; } @@ -308,9 +312,11 @@ static int ipheth_get_macaddr(struct ipheth_device *dev) IPHETH_CTRL_BUF_SIZE, IPHETH_CTRL_TIMEOUT); if (retval < 0) { - err("%s: usb_control_msg: %d", __func__, retval); + dev_err(&dev->intf->dev, "%s: usb_control_msg: %d\n", + __func__, retval); } else if (retval < ETH_ALEN) { - err("%s: usb_control_msg: short packet: %d bytes", + dev_err(&dev->intf->dev, + "%s: usb_control_msg: short packet: %d bytes\n", __func__, retval); retval = -EINVAL; } else { @@ -335,7 +341,8 @@ static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags) retval = usb_submit_urb(dev->rx_urb, mem_flags); if (retval) - err("%s: usb_submit_urb: %d", __func__, retval); + dev_err(&dev->intf->dev, "%s: usb_submit_urb: %d\n", + __func__, retval); return retval; } @@ -396,7 +403,8 @@ static int ipheth_tx(struct sk_buff *skb, struct net_device *net) retval = usb_submit_urb(dev->tx_urb, GFP_ATOMIC); if (retval) { - err("%s: usb_submit_urb: %d", __func__, retval); + dev_err(&dev->intf->dev, "%s: usb_submit_urb: %d\n", + __func__, retval); dev->net->stats.tx_errors++; dev_kfree_skb_irq(skb); } else { @@ -414,7 +422,7 @@ static void ipheth_tx_timeout(struct net_device *net) { struct ipheth_device *dev = netdev_priv(net); - err("%s: TX timeout", __func__); + dev_err(&dev->intf->dev, "%s: TX timeout\n", __func__); dev->net->stats.tx_errors++; usb_unlink_urb(dev->tx_urb); } @@ -464,7 +472,7 @@ static int ipheth_probe(struct usb_interface *intf, hintf = usb_altnum_to_altsetting(intf, IPHETH_ALT_INTFNUM); if (hintf == NULL) { retval = -ENODEV; - err("Unable to find alternate settings interface"); + dev_err(&intf->dev, "Unable to find alternate settings interface\n"); goto err_endpoints; } @@ -477,7 +485,7 @@ static int ipheth_probe(struct usb_interface *intf, } if (!(dev->bulk_in && dev->bulk_out)) { retval = -ENODEV; - err("Unable to find endpoints"); + dev_err(&intf->dev, "Unable to find endpoints\n"); goto err_endpoints; } @@ -495,7 +503,7 @@ static int ipheth_probe(struct usb_interface *intf, retval = ipheth_alloc_urbs(dev); if (retval) { - err("error allocating urbs: %d", retval); + dev_err(&intf->dev, "error allocating urbs: %d\n", retval); goto err_alloc_urbs; } @@ -506,7 +514,7 @@ static int ipheth_probe(struct usb_interface *intf, retval = register_netdev(netdev); if (retval) { - err("error registering netdev: %d", retval); + dev_err(&intf->dev, "error registering netdev: %d\n", retval); retval = -EIO; goto err_register_netdev; } @@ -546,6 +554,7 @@ static struct usb_driver ipheth_driver = { .probe = ipheth_probe, .disconnect = ipheth_disconnect, .id_table = ipheth_table, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(ipheth_driver); diff --git a/trunk/drivers/net/usb/kalmia.c b/trunk/drivers/net/usb/kalmia.c index 7562649b3d6b..92c49e0a59ec 100644 --- a/trunk/drivers/net/usb/kalmia.c +++ b/trunk/drivers/net/usb/kalmia.c @@ -372,7 +372,8 @@ static struct usb_driver kalmia_driver = { .probe = usbnet_probe, .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, - .resume = usbnet_resume + .resume = usbnet_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(kalmia_driver); diff --git a/trunk/drivers/net/usb/kaweth.c b/trunk/drivers/net/usb/kaweth.c index df2a2cf35a99..d8ad55284389 100644 --- a/trunk/drivers/net/usb/kaweth.c +++ b/trunk/drivers/net/usb/kaweth.c @@ -179,6 +179,7 @@ static struct usb_driver kaweth_driver = { .resume = kaweth_resume, .id_table = usb_klsi_table, .supports_autosuspend = 1, + .disable_hub_initiated_lpm = 1, }; typedef __u8 eth_addr_t[6]; @@ -400,12 +401,13 @@ static int kaweth_download_firmware(struct kaweth_device *kaweth, ret = request_firmware(&fw, fwname, &kaweth->dev->dev); if (ret) { - err("Firmware request failed\n"); + dev_err(&kaweth->intf->dev, "Firmware request failed\n"); return ret; } if (fw->size > KAWETH_FIRMWARE_BUF_SIZE) { - err("Firmware too big: %zu", fw->size); + dev_err(&kaweth->intf->dev, "Firmware too big: %zu\n", + fw->size); release_firmware(fw); return -ENOSPC; } @@ -501,9 +503,10 @@ static void kaweth_resubmit_int_urb(struct kaweth_device *kaweth, gfp_t mf) } if (status) - err ("can't resubmit intr, %s-%s, status %d", - kaweth->dev->bus->bus_name, - kaweth->dev->devpath, status); + dev_err(&kaweth->intf->dev, + "can't resubmit intr, %s-%s, status %d\n", + kaweth->dev->bus->bus_name, + kaweth->dev->devpath, status); } static void int_callback(struct urb *u) @@ -576,7 +579,8 @@ static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth, kaweth->suspend_lowmem_rx = 1; schedule_delayed_work(&kaweth->lowmem_work, HZ/4); } - err("resubmitting rx_urb %d failed", result); + dev_err(&kaweth->intf->dev, "resubmitting rx_urb %d failed\n", + result); } else { kaweth->suspend_lowmem_rx = 0; } @@ -634,20 +638,21 @@ static void kaweth_usb_receive(struct urb *urb) spin_unlock(&kaweth->device_lock); if(status && status != -EREMOTEIO && count != 1) { - err("%s RX status: %d count: %d packet_len: %d", - net->name, - status, - count, - (int)pkt_len); + dev_err(&kaweth->intf->dev, + "%s RX status: %d count: %d packet_len: %d\n", + net->name, status, count, (int)pkt_len); kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); return; } if(kaweth->net && (count > 2)) { if(pkt_len > (count - 2)) { - err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count); - err("Packet len & 2047: %x", pkt_len & 2047); - err("Count 2: %x", count2); + dev_err(&kaweth->intf->dev, + "Packet length too long for USB frame (pkt_len: %x, count: %x)\n", + pkt_len, count); + dev_err(&kaweth->intf->dev, "Packet len & 2047: %x\n", + pkt_len & 2047); + dev_err(&kaweth->intf->dev, "Count 2: %x\n", count2); kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); return; } @@ -686,7 +691,7 @@ static int kaweth_open(struct net_device *net) res = usb_autopm_get_interface(kaweth->intf); if (res) { - err("Interface cannot be resumed."); + dev_err(&kaweth->intf->dev, "Interface cannot be resumed.\n"); return -EIO; } res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL); @@ -907,7 +912,8 @@ static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth) KAWETH_CONTROL_TIMEOUT); if(result < 0) { - err("Failed to set Rx mode: %d", result); + dev_err(&kaweth->intf->dev, "Failed to set Rx mode: %d\n", + result); } else { dbg("Set Rx mode to %d", packet_filter_bitmap); @@ -1045,7 +1051,8 @@ static int kaweth_probe( "kaweth/new_code.bin", 100, 2)) < 0) { - err("Error downloading firmware (%d)", result); + dev_err(&intf->dev, "Error downloading firmware (%d)\n", + result); goto err_fw; } @@ -1053,7 +1060,9 @@ static int kaweth_probe( "kaweth/new_code_fix.bin", 100, 3)) < 0) { - err("Error downloading firmware fix (%d)", result); + dev_err(&intf->dev, + "Error downloading firmware fix (%d)\n", + result); goto err_fw; } @@ -1061,7 +1070,9 @@ static int kaweth_probe( "kaweth/trigger_code.bin", 126, 2)) < 0) { - err("Error downloading trigger code (%d)", result); + dev_err(&intf->dev, + "Error downloading trigger code (%d)\n", + result); goto err_fw; } @@ -1070,13 +1081,14 @@ static int kaweth_probe( "kaweth/trigger_code_fix.bin", 126, 3)) < 0) { - err("Error downloading trigger code fix (%d)", result); + dev_err(&intf->dev, "Error downloading trigger code fix (%d)\n", result); goto err_fw; } if ((result = kaweth_trigger_firmware(kaweth, 126)) < 0) { - err("Error triggering firmware (%d)", result); + dev_err(&intf->dev, "Error triggering firmware (%d)\n", + result); goto err_fw; } @@ -1091,7 +1103,7 @@ static int kaweth_probe( result = kaweth_read_configuration(kaweth); if(result < 0) { - err("Error reading configuration (%d), no net device created", result); + dev_err(&intf->dev, "Error reading configuration (%d), no net device created\n", result); goto err_free_netdev; } @@ -1103,7 +1115,7 @@ static int kaweth_probe( if(!memcmp(&kaweth->configuration.hw_addr, &bcast_addr, sizeof(bcast_addr))) { - err("Firmware not functioning properly, no net device created"); + dev_err(&intf->dev, "Firmware not functioning properly, no net device created\n"); goto err_free_netdev; } @@ -1113,7 +1125,7 @@ static int kaweth_probe( } if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) { - err("Error setting SOFS wait"); + dev_err(&intf->dev, "Error setting SOFS wait\n"); goto err_free_netdev; } @@ -1123,7 +1135,7 @@ static int kaweth_probe( KAWETH_PACKET_FILTER_MULTICAST); if(result < 0) { - err("Error setting receive filter"); + dev_err(&intf->dev, "Error setting receive filter\n"); goto err_free_netdev; } @@ -1175,7 +1187,7 @@ static int kaweth_probe( SET_NETDEV_DEV(netdev, &intf->dev); if (register_netdev(netdev) != 0) { - err("Error registering netdev."); + dev_err(&intf->dev, "Error registering netdev.\n"); goto err_intfdata; } diff --git a/trunk/drivers/net/usb/lg-vl600.c b/trunk/drivers/net/usb/lg-vl600.c index 45a981fde43f..808d6506da41 100644 --- a/trunk/drivers/net/usb/lg-vl600.c +++ b/trunk/drivers/net/usb/lg-vl600.c @@ -344,6 +344,7 @@ static struct usb_driver lg_vl600_driver = { .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(lg_vl600_driver); diff --git a/trunk/drivers/net/usb/mcs7830.c b/trunk/drivers/net/usb/mcs7830.c index c434b6ba0337..add1064f755d 100644 --- a/trunk/drivers/net/usb/mcs7830.c +++ b/trunk/drivers/net/usb/mcs7830.c @@ -690,6 +690,7 @@ static struct usb_driver mcs7830_driver = { .suspend = usbnet_suspend, .resume = usbnet_resume, .reset_resume = mcs7830_reset_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(mcs7830_driver); diff --git a/trunk/drivers/net/usb/net1080.c b/trunk/drivers/net/usb/net1080.c index 83f965cb69e7..28c4d513ba85 100644 --- a/trunk/drivers/net/usb/net1080.c +++ b/trunk/drivers/net/usb/net1080.c @@ -587,6 +587,7 @@ static struct usb_driver net1080_driver = { .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(net1080_driver); diff --git a/trunk/drivers/net/usb/pegasus.c b/trunk/drivers/net/usb/pegasus.c index 752393092325..7023220456c5 100644 --- a/trunk/drivers/net/usb/pegasus.c +++ b/trunk/drivers/net/usb/pegasus.c @@ -1489,6 +1489,7 @@ static struct usb_driver pegasus_driver = { .id_table = pegasus_ids, .suspend = pegasus_suspend, .resume = pegasus_resume, + .disable_hub_initiated_lpm = 1, }; static void __init parse_id(char *id) diff --git a/trunk/drivers/net/usb/plusb.c b/trunk/drivers/net/usb/plusb.c index b2b035e29978..4584b9a805b3 100644 --- a/trunk/drivers/net/usb/plusb.c +++ b/trunk/drivers/net/usb/plusb.c @@ -152,6 +152,7 @@ static struct usb_driver plusb_driver = { .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(plusb_driver); diff --git a/trunk/drivers/net/usb/qmi_wwan.c b/trunk/drivers/net/usb/qmi_wwan.c index d316503b35d4..380dbea6109d 100644 --- a/trunk/drivers/net/usb/qmi_wwan.c +++ b/trunk/drivers/net/usb/qmi_wwan.c @@ -356,10 +356,19 @@ static const struct driver_info qmi_wwan_gobi = { }; /* ZTE suck at making USB descriptors */ +static const struct driver_info qmi_wwan_force_int1 = { + .description = "Qualcomm WWAN/QMI device", + .flags = FLAG_WWAN, + .bind = qmi_wwan_bind_shared, + .unbind = qmi_wwan_unbind_shared, + .manage_power = qmi_wwan_manage_power, + .data = BIT(1), /* interface whitelist bitmap */ +}; + static const struct driver_info qmi_wwan_force_int4 = { - .description = "Qualcomm Gobi wwan/QMI device", + .description = "Qualcomm WWAN/QMI device", .flags = FLAG_WWAN, - .bind = qmi_wwan_bind_gobi, + .bind = qmi_wwan_bind_shared, .unbind = qmi_wwan_unbind_shared, .manage_power = qmi_wwan_manage_power, .data = BIT(4), /* interface whitelist bitmap */ @@ -401,6 +410,14 @@ static const struct usb_device_id products[] = { .bInterfaceProtocol = 8, /* NOTE: This is the *slave* interface of the CDC Union! */ .driver_info = (unsigned long)&qmi_wwan_info, }, + { /* Vodafone/Huawei K5005 (12d1:14c8) and similar modems */ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = HUAWEI_VENDOR_ID, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 56, /* NOTE: This is the *slave* interface of the CDC Union! */ + .driver_info = (unsigned long)&qmi_wwan_info, + }, { /* Huawei E392, E398 and possibly others in "Windows mode" * using a combined control and data interface without any CDC * functional descriptors @@ -430,6 +447,15 @@ static const struct usb_device_id products[] = { .bInterfaceProtocol = 0xff, .driver_info = (unsigned long)&qmi_wwan_force_int4, }, + { /* ZTE (Vodafone) K3520-Z */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x19d2, + .idProduct = 0x0055, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0xff, + .driver_info = (unsigned long)&qmi_wwan_force_int1, + }, { /* ZTE (Vodafone) K3565-Z */ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x19d2, @@ -457,6 +483,15 @@ static const struct usb_device_id products[] = { .bInterfaceProtocol = 0xff, .driver_info = (unsigned long)&qmi_wwan_force_int4, }, + { /* ZTE (Vodafone) K3765-Z */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x19d2, + .idProduct = 0x2002, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0xff, + .driver_info = (unsigned long)&qmi_wwan_force_int4, + }, { /* ZTE (Vodafone) K4505-Z */ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x19d2, @@ -525,6 +560,7 @@ static struct usb_driver qmi_wwan_driver = { .resume = qmi_wwan_resume, .reset_resume = qmi_wwan_resume, .supports_autosuspend = 1, + .disable_hub_initiated_lpm = 1, }; static int __init qmi_wwan_init(void) diff --git a/trunk/drivers/net/usb/rndis_host.c b/trunk/drivers/net/usb/rndis_host.c index c8f1b5b3aff3..4a4335833c36 100644 --- a/trunk/drivers/net/usb/rndis_host.c +++ b/trunk/drivers/net/usb/rndis_host.c @@ -77,7 +77,9 @@ static void rndis_msg_indicate(struct usbnet *dev, struct rndis_indicate *msg, if (dev->driver_info->indication) { dev->driver_info->indication(dev, msg, buflen); } else { - switch (msg->status) { + u32 status = le32_to_cpu(msg->status); + + switch (status) { case RNDIS_STATUS_MEDIA_CONNECT: dev_info(udev, "rndis media connect\n"); break; @@ -85,8 +87,7 @@ static void rndis_msg_indicate(struct usbnet *dev, struct rndis_indicate *msg, dev_info(udev, "rndis media disconnect\n"); break; default: - dev_info(udev, "rndis indication: 0x%08x\n", - le32_to_cpu(msg->status)); + dev_info(udev, "rndis indication: 0x%08x\n", status); } } } @@ -109,16 +110,17 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) int retval; int partial; unsigned count; - __le32 rsp; - u32 xid = 0, msg_len, request_id; + u32 xid = 0, msg_len, request_id, msg_type, rsp, + status; /* REVISIT when this gets called from contexts other than probe() or * disconnect(): either serialize, or dispatch responses on xid */ + msg_type = le32_to_cpu(buf->msg_type); + /* Issue the request; xid is unique, don't bother byteswapping it */ - if (likely(buf->msg_type != RNDIS_MSG_HALT && - buf->msg_type != RNDIS_MSG_RESET)) { + if (likely(msg_type != RNDIS_MSG_HALT && msg_type != RNDIS_MSG_RESET)) { xid = dev->xid++; if (!xid) xid = dev->xid++; @@ -149,7 +151,7 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) } /* Poll the control channel; the request probably completed immediately */ - rsp = buf->msg_type | RNDIS_MSG_COMPLETION; + rsp = le32_to_cpu(buf->msg_type) | RNDIS_MSG_COMPLETION; for (count = 0; count < 10; count++) { memset(buf, 0, CONTROL_BUFFER_SIZE); retval = usb_control_msg(dev->udev, @@ -160,35 +162,36 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) buf, buflen, RNDIS_CONTROL_TIMEOUT_MS); if (likely(retval >= 8)) { + msg_type = le32_to_cpu(buf->msg_type); msg_len = le32_to_cpu(buf->msg_len); + status = le32_to_cpu(buf->status); request_id = (__force u32) buf->request_id; - if (likely(buf->msg_type == rsp)) { + if (likely(msg_type == rsp)) { if (likely(request_id == xid)) { if (unlikely(rsp == RNDIS_MSG_RESET_C)) return 0; - if (likely(RNDIS_STATUS_SUCCESS - == buf->status)) + if (likely(RNDIS_STATUS_SUCCESS == + status)) return 0; dev_dbg(&info->control->dev, "rndis reply status %08x\n", - le32_to_cpu(buf->status)); + status); return -EL3RST; } dev_dbg(&info->control->dev, "rndis reply id %d expected %d\n", request_id, xid); /* then likely retry */ - } else switch (buf->msg_type) { - case RNDIS_MSG_INDICATE: /* fault/event */ + } else switch (msg_type) { + case RNDIS_MSG_INDICATE: /* fault/event */ rndis_msg_indicate(dev, (void *)buf, buflen); - break; - case RNDIS_MSG_KEEPALIVE: { /* ping */ + case RNDIS_MSG_KEEPALIVE: { /* ping */ struct rndis_keepalive_c *msg = (void *)buf; - msg->msg_type = RNDIS_MSG_KEEPALIVE_C; + msg->msg_type = cpu_to_le32(RNDIS_MSG_KEEPALIVE_C); msg->msg_len = cpu_to_le32(sizeof *msg); - msg->status = RNDIS_STATUS_SUCCESS; + msg->status = cpu_to_le32(RNDIS_STATUS_SUCCESS); retval = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), USB_CDC_SEND_ENCAPSULATED_COMMAND, @@ -236,7 +239,7 @@ EXPORT_SYMBOL_GPL(rndis_command); * ActiveSync 4.1 Windows driver. */ static int rndis_query(struct usbnet *dev, struct usb_interface *intf, - void *buf, __le32 oid, u32 in_len, + void *buf, u32 oid, u32 in_len, void **reply, int *reply_len) { int retval; @@ -251,9 +254,9 @@ static int rndis_query(struct usbnet *dev, struct usb_interface *intf, u.buf = buf; memset(u.get, 0, sizeof *u.get + in_len); - u.get->msg_type = RNDIS_MSG_QUERY; + u.get->msg_type = cpu_to_le32(RNDIS_MSG_QUERY); u.get->msg_len = cpu_to_le32(sizeof *u.get + in_len); - u.get->oid = oid; + u.get->oid = cpu_to_le32(oid); u.get->len = cpu_to_le32(in_len); u.get->offset = cpu_to_le32(20); @@ -324,7 +327,7 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags) if (retval < 0) goto fail; - u.init->msg_type = RNDIS_MSG_INIT; + u.init->msg_type = cpu_to_le32(RNDIS_MSG_INIT); u.init->msg_len = cpu_to_le32(sizeof *u.init); u.init->major_version = cpu_to_le32(1); u.init->minor_version = cpu_to_le32(0); @@ -395,22 +398,23 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags) /* Check physical medium */ phym = NULL; reply_len = sizeof *phym; - retval = rndis_query(dev, intf, u.buf, OID_GEN_PHYSICAL_MEDIUM, - 0, (void **) &phym, &reply_len); + retval = rndis_query(dev, intf, u.buf, + RNDIS_OID_GEN_PHYSICAL_MEDIUM, + 0, (void **) &phym, &reply_len); if (retval != 0 || !phym) { /* OID is optional so don't fail here. */ - phym_unspec = RNDIS_PHYSICAL_MEDIUM_UNSPECIFIED; + phym_unspec = cpu_to_le32(RNDIS_PHYSICAL_MEDIUM_UNSPECIFIED); phym = &phym_unspec; } if ((flags & FLAG_RNDIS_PHYM_WIRELESS) && - *phym != RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) { + le32_to_cpup(phym) != RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) { netif_dbg(dev, probe, dev->net, "driver requires wireless physical medium, but device is not\n"); retval = -ENODEV; goto halt_fail_and_release; } if ((flags & FLAG_RNDIS_PHYM_NOT_WIRELESS) && - *phym == RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) { + le32_to_cpup(phym) == RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) { netif_dbg(dev, probe, dev->net, "driver requires non-wireless physical medium, but device is wireless.\n"); retval = -ENODEV; @@ -419,8 +423,9 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags) /* Get designated host ethernet address */ reply_len = ETH_ALEN; - retval = rndis_query(dev, intf, u.buf, OID_802_3_PERMANENT_ADDRESS, - 48, (void **) &bp, &reply_len); + retval = rndis_query(dev, intf, u.buf, + RNDIS_OID_802_3_PERMANENT_ADDRESS, + 48, (void **) &bp, &reply_len); if (unlikely(retval< 0)) { dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval); goto halt_fail_and_release; @@ -430,12 +435,12 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags) /* set a nonzero filter to enable data transfers */ memset(u.set, 0, sizeof *u.set); - u.set->msg_type = RNDIS_MSG_SET; + u.set->msg_type = cpu_to_le32(RNDIS_MSG_SET); u.set->msg_len = cpu_to_le32(4 + sizeof *u.set); - u.set->oid = OID_GEN_CURRENT_PACKET_FILTER; + u.set->oid = cpu_to_le32(RNDIS_OID_GEN_CURRENT_PACKET_FILTER); u.set->len = cpu_to_le32(4); u.set->offset = cpu_to_le32((sizeof *u.set) - 8); - *(__le32 *)(u.buf + sizeof *u.set) = RNDIS_DEFAULT_FILTER; + *(__le32 *)(u.buf + sizeof *u.set) = cpu_to_le32(RNDIS_DEFAULT_FILTER); retval = rndis_command(dev, u.header, CONTROL_BUFFER_SIZE); if (unlikely(retval < 0)) { @@ -450,7 +455,7 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags) halt_fail_and_release: memset(u.halt, 0, sizeof *u.halt); - u.halt->msg_type = RNDIS_MSG_HALT; + u.halt->msg_type = cpu_to_le32(RNDIS_MSG_HALT); u.halt->msg_len = cpu_to_le32(sizeof *u.halt); (void) rndis_command(dev, (void *)u.halt, CONTROL_BUFFER_SIZE); fail_and_release: @@ -475,7 +480,7 @@ void rndis_unbind(struct usbnet *dev, struct usb_interface *intf) /* try to clear any rndis state/activity (no i/o from stack!) */ halt = kzalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL); if (halt) { - halt->msg_type = RNDIS_MSG_HALT; + halt->msg_type = cpu_to_le32(RNDIS_MSG_HALT); halt->msg_len = cpu_to_le32(sizeof *halt); (void) rndis_command(dev, (void *)halt, CONTROL_BUFFER_SIZE); kfree(halt); @@ -494,16 +499,16 @@ int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb) while (likely(skb->len)) { struct rndis_data_hdr *hdr = (void *)skb->data; struct sk_buff *skb2; - u32 msg_len, data_offset, data_len; + u32 msg_type, msg_len, data_offset, data_len; + msg_type = le32_to_cpu(hdr->msg_type); msg_len = le32_to_cpu(hdr->msg_len); data_offset = le32_to_cpu(hdr->data_offset); data_len = le32_to_cpu(hdr->data_len); /* don't choke if we see oob, per-packet data, etc */ - if (unlikely(hdr->msg_type != RNDIS_MSG_PACKET || - skb->len < msg_len || - (data_offset + data_len + 8) > msg_len)) { + if (unlikely(msg_type != RNDIS_MSG_PACKET || skb->len < msg_len + || (data_offset + data_len + 8) > msg_len)) { dev->net->stats.rx_frame_errors++; netdev_dbg(dev->net, "bad rndis message %d/%d/%d/%d, len %d\n", le32_to_cpu(hdr->msg_type), @@ -569,7 +574,7 @@ rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) fill: hdr = (void *) __skb_push(skb, sizeof *hdr); memset(hdr, 0, sizeof *hdr); - hdr->msg_type = RNDIS_MSG_PACKET; + hdr->msg_type = cpu_to_le32(RNDIS_MSG_PACKET); hdr->msg_len = cpu_to_le32(skb->len); hdr->data_offset = cpu_to_le32(sizeof(*hdr) - 8); hdr->data_len = cpu_to_le32(len); @@ -633,6 +638,7 @@ static struct usb_driver rndis_driver = { .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(rndis_driver); diff --git a/trunk/drivers/net/usb/rtl8150.c b/trunk/drivers/net/usb/rtl8150.c index d363b31053da..0e2c92e0e532 100644 --- a/trunk/drivers/net/usb/rtl8150.c +++ b/trunk/drivers/net/usb/rtl8150.c @@ -203,7 +203,8 @@ static int async_set_registers(rtl8150_t * dev, u16 indx, u16 size) if ((ret = usb_submit_urb(dev->ctrl_urb, GFP_ATOMIC))) { if (ret == -ENODEV) netif_device_detach(dev->netdev); - err("control request submission failed: %d", ret); + dev_err(&dev->udev->dev, + "control request submission failed: %d\n", ret); } else set_bit(RX_REG_SET, &dev->flags); @@ -516,9 +517,9 @@ static void intr_callback(struct urb *urb) if (res == -ENODEV) netif_device_detach(dev->netdev); else if (res) - err ("can't resubmit intr, %s-%s/input0, status %d", - dev->udev->bus->bus_name, - dev->udev->devpath, res); + dev_err(&dev->udev->dev, + "can't resubmit intr, %s-%s/input0, status %d\n", + dev->udev->bus->bus_name, dev->udev->devpath, res); } static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message) @@ -890,11 +891,11 @@ static int rtl8150_probe(struct usb_interface *intf, dev->intr_interval = 100; /* 100ms */ if (!alloc_all_urbs(dev)) { - err("out of memory"); + dev_err(&intf->dev, "out of memory\n"); goto out; } if (!rtl8150_reset(dev)) { - err("couldn't reset the device"); + dev_err(&intf->dev, "couldn't reset the device\n"); goto out1; } fill_skb_pool(dev); @@ -903,7 +904,7 @@ static int rtl8150_probe(struct usb_interface *intf, usb_set_intfdata(intf, dev); SET_NETDEV_DEV(netdev, &intf->dev); if (register_netdev(netdev) != 0) { - err("couldn't register the device"); + dev_err(&intf->dev, "couldn't register the device\n"); goto out2; } @@ -947,7 +948,8 @@ static struct usb_driver rtl8150_driver = { .disconnect = rtl8150_disconnect, .id_table = rtl8150_table, .suspend = rtl8150_suspend, - .resume = rtl8150_resume + .resume = rtl8150_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(rtl8150_driver); diff --git a/trunk/drivers/net/usb/sierra_net.c b/trunk/drivers/net/usb/sierra_net.c index b59cf20c7817..3faef5670d1f 100644 --- a/trunk/drivers/net/usb/sierra_net.c +++ b/trunk/drivers/net/usb/sierra_net.c @@ -982,6 +982,7 @@ static struct usb_driver sierra_net_driver = { .suspend = usbnet_suspend, .resume = usbnet_resume, .no_dynamic_id = 1, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(sierra_net_driver); diff --git a/trunk/drivers/net/usb/smsc75xx.c b/trunk/drivers/net/usb/smsc75xx.c index 00103a8c5e04..1c6e51588da7 100644 --- a/trunk/drivers/net/usb/smsc75xx.c +++ b/trunk/drivers/net/usb/smsc75xx.c @@ -508,10 +508,9 @@ static int smsc75xx_link_reset(struct usbnet *dev) u16 lcladv, rmtadv; int ret; - /* read and write to clear phy interrupt status */ - ret = smsc75xx_mdio_read(dev->net, mii->phy_id, PHY_INT_SRC); - check_warn_return(ret, "Error reading PHY_INT_SRC"); - smsc75xx_mdio_write(dev->net, mii->phy_id, PHY_INT_SRC, 0xffff); + /* write to clear phy interrupt status */ + smsc75xx_mdio_write(dev->net, mii->phy_id, PHY_INT_SRC, + PHY_INT_SRC_CLEAR_ALL); ret = smsc75xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL); check_warn_return(ret, "Error writing INT_STS"); @@ -904,15 +903,20 @@ static int smsc75xx_reset(struct usbnet *dev) netif_dbg(dev, ifup, dev->net, "ID_REV = 0x%08x", buf); - /* Configure GPIO pins as LED outputs */ - ret = smsc75xx_read_reg(dev, LED_GPIO_CFG, &buf); - check_warn_return(ret, "Failed to read LED_GPIO_CFG: %d", ret); + ret = smsc75xx_read_reg(dev, E2P_CMD, &buf); + check_warn_return(ret, "Failed to read E2P_CMD: %d", ret); - buf &= ~(LED_GPIO_CFG_LED2_FUN_SEL | LED_GPIO_CFG_LED10_FUN_SEL); - buf |= LED_GPIO_CFG_LEDGPIO_EN | LED_GPIO_CFG_LED2_FUN_SEL; + /* only set default GPIO/LED settings if no EEPROM is detected */ + if (!(buf & E2P_CMD_LOADED)) { + ret = smsc75xx_read_reg(dev, LED_GPIO_CFG, &buf); + check_warn_return(ret, "Failed to read LED_GPIO_CFG: %d", ret); - ret = smsc75xx_write_reg(dev, LED_GPIO_CFG, buf); - check_warn_return(ret, "Failed to write LED_GPIO_CFG: %d", ret); + buf &= ~(LED_GPIO_CFG_LED2_FUN_SEL | LED_GPIO_CFG_LED10_FUN_SEL); + buf |= LED_GPIO_CFG_LEDGPIO_EN | LED_GPIO_CFG_LED2_FUN_SEL; + + ret = smsc75xx_write_reg(dev, LED_GPIO_CFG, buf); + check_warn_return(ret, "Failed to write LED_GPIO_CFG: %d", ret); + } ret = smsc75xx_write_reg(dev, FLOW, 0); check_warn_return(ret, "Failed to write FLOW: %d", ret); @@ -1250,6 +1254,7 @@ static struct usb_driver smsc75xx_driver = { .suspend = usbnet_suspend, .resume = usbnet_resume, .disconnect = usbnet_disconnect, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(smsc75xx_driver); diff --git a/trunk/drivers/net/usb/smsc75xx.h b/trunk/drivers/net/usb/smsc75xx.h index 16e98c778344..67eba39e6ee2 100644 --- a/trunk/drivers/net/usb/smsc75xx.h +++ b/trunk/drivers/net/usb/smsc75xx.h @@ -388,6 +388,7 @@ #define PHY_INT_SRC_ANEG_COMP ((u16)0x0040) #define PHY_INT_SRC_REMOTE_FAULT ((u16)0x0020) #define PHY_INT_SRC_LINK_DOWN ((u16)0x0010) +#define PHY_INT_SRC_CLEAR_ALL ((u16)0xffff) #define PHY_INT_MASK (30) #define PHY_INT_MASK_ENERGY_ON ((u16)0x0080) diff --git a/trunk/drivers/net/usb/smsc95xx.c b/trunk/drivers/net/usb/smsc95xx.c index 94ae66999f59..b1112e753859 100644 --- a/trunk/drivers/net/usb/smsc95xx.c +++ b/trunk/drivers/net/usb/smsc95xx.c @@ -1297,6 +1297,7 @@ static struct usb_driver smsc95xx_driver = { .suspend = usbnet_suspend, .resume = usbnet_resume, .disconnect = usbnet_disconnect, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(smsc95xx_driver); diff --git a/trunk/drivers/net/usb/usbnet.c b/trunk/drivers/net/usb/usbnet.c index b38db48b1ce0..9f58330f1312 100644 --- a/trunk/drivers/net/usb/usbnet.c +++ b/trunk/drivers/net/usb/usbnet.c @@ -909,6 +909,7 @@ static const struct ethtool_ops usbnet_ethtool_ops = { .get_drvinfo = usbnet_get_drvinfo, .get_msglevel = usbnet_get_msglevel, .set_msglevel = usbnet_set_msglevel, + .get_ts_info = ethtool_op_get_ts_info, }; /*-------------------------------------------------------------------------*/ diff --git a/trunk/drivers/net/usb/zaurus.c b/trunk/drivers/net/usb/zaurus.c index 34db195fb8b0..35c90307d473 100644 --- a/trunk/drivers/net/usb/zaurus.c +++ b/trunk/drivers/net/usb/zaurus.c @@ -377,6 +377,7 @@ static struct usb_driver zaurus_driver = { .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(zaurus_driver); diff --git a/trunk/drivers/net/virtio_net.c b/trunk/drivers/net/virtio_net.c index cbefe671bcc6..9ce6995e8d08 100644 --- a/trunk/drivers/net/virtio_net.c +++ b/trunk/drivers/net/virtio_net.c @@ -66,12 +66,21 @@ struct virtnet_info { /* Host will merge rx buffers for big packets (shake it! shake it!) */ bool mergeable_rx_bufs; + /* enable config space updates */ + bool config_enable; + /* Active statistics */ struct virtnet_stats __percpu *stats; /* Work struct for refilling if we run low on memory. */ struct delayed_work refill; + /* Work struct for config space updates */ + struct work_struct config_work; + + /* Lock for config space updates */ + struct mutex config_lock; + /* Chain pages by the private ptr. */ struct page *pages; @@ -782,6 +791,16 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd, return status == VIRTIO_NET_OK; } +static void virtnet_ack_link_announce(struct virtnet_info *vi) +{ + rtnl_lock(); + if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_ANNOUNCE, + VIRTIO_NET_CTRL_ANNOUNCE_ACK, NULL, + 0, 0)) + dev_warn(&vi->dev->dev, "Failed to ack link announce.\n"); + rtnl_unlock(); +} + static int virtnet_close(struct net_device *dev) { struct virtnet_info *vi = netdev_priv(dev); @@ -953,20 +972,31 @@ static const struct net_device_ops virtnet_netdev = { #endif }; -static void virtnet_update_status(struct virtnet_info *vi) +static void virtnet_config_changed_work(struct work_struct *work) { + struct virtnet_info *vi = + container_of(work, struct virtnet_info, config_work); u16 v; + mutex_lock(&vi->config_lock); + if (!vi->config_enable) + goto done; + if (virtio_config_val(vi->vdev, VIRTIO_NET_F_STATUS, offsetof(struct virtio_net_config, status), &v) < 0) - return; + goto done; + + if (v & VIRTIO_NET_S_ANNOUNCE) { + netif_notify_peers(vi->dev); + virtnet_ack_link_announce(vi); + } /* Ignore unknown (future) status bits */ v &= VIRTIO_NET_S_LINK_UP; if (vi->status == v) - return; + goto done; vi->status = v; @@ -977,13 +1007,15 @@ static void virtnet_update_status(struct virtnet_info *vi) netif_carrier_off(vi->dev); netif_stop_queue(vi->dev); } +done: + mutex_unlock(&vi->config_lock); } static void virtnet_config_changed(struct virtio_device *vdev) { struct virtnet_info *vi = vdev->priv; - virtnet_update_status(vi); + queue_work(system_nrt_wq, &vi->config_work); } static int init_vqs(struct virtnet_info *vi) @@ -1077,6 +1109,9 @@ static int virtnet_probe(struct virtio_device *vdev) goto free; INIT_DELAYED_WORK(&vi->refill, refill_work); + mutex_init(&vi->config_lock); + vi->config_enable = true; + INIT_WORK(&vi->config_work, virtnet_config_changed_work); sg_init_table(vi->rx_sg, ARRAY_SIZE(vi->rx_sg)); sg_init_table(vi->tx_sg, ARRAY_SIZE(vi->tx_sg)); @@ -1112,7 +1147,7 @@ static int virtnet_probe(struct virtio_device *vdev) otherwise get link status from config. */ if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) { netif_carrier_off(dev); - virtnet_update_status(vi); + queue_work(system_nrt_wq, &vi->config_work); } else { vi->status = VIRTIO_NET_S_LINK_UP; netif_carrier_on(dev); @@ -1171,10 +1206,17 @@ static void __devexit virtnet_remove(struct virtio_device *vdev) { struct virtnet_info *vi = vdev->priv; + /* Prevent config work handler from accessing the device. */ + mutex_lock(&vi->config_lock); + vi->config_enable = false; + mutex_unlock(&vi->config_lock); + unregister_netdev(vi->dev); remove_vq_common(vi); + flush_work(&vi->config_work); + free_percpu(vi->stats); free_netdev(vi->dev); } @@ -1184,6 +1226,11 @@ static int virtnet_freeze(struct virtio_device *vdev) { struct virtnet_info *vi = vdev->priv; + /* Prevent config work handler from accessing the device */ + mutex_lock(&vi->config_lock); + vi->config_enable = false; + mutex_unlock(&vi->config_lock); + virtqueue_disable_cb(vi->rvq); virtqueue_disable_cb(vi->svq); if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) @@ -1197,6 +1244,8 @@ static int virtnet_freeze(struct virtio_device *vdev) remove_vq_common(vi); + flush_work(&vi->config_work); + return 0; } @@ -1217,6 +1266,10 @@ static int virtnet_restore(struct virtio_device *vdev) if (!try_fill_recv(vi, GFP_KERNEL)) queue_delayed_work(system_nrt_wq, &vi->refill, 0); + mutex_lock(&vi->config_lock); + vi->config_enable = true; + mutex_unlock(&vi->config_lock); + return 0; } #endif @@ -1234,6 +1287,7 @@ static unsigned int features[] = { VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_UFO, VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, + VIRTIO_NET_F_GUEST_ANNOUNCE, }; static struct virtio_driver virtio_net_driver = { diff --git a/trunk/drivers/net/wan/Kconfig b/trunk/drivers/net/wan/Kconfig index d70ede7a7f96..d58431e99f73 100644 --- a/trunk/drivers/net/wan/Kconfig +++ b/trunk/drivers/net/wan/Kconfig @@ -203,37 +203,6 @@ config WANXL_BUILD_FIRMWARE You should never need this option, say N. -config PC300 - tristate "Cyclades-PC300 support (RS-232/V.35, X.21, T1/E1 boards)" - depends on HDLC && PCI && BROKEN - ---help--- - This driver is broken because of struct tty_driver change. - - Driver for the Cyclades-PC300 synchronous communication boards. - - These boards provide synchronous serial interfaces to your - Linux box (interfaces currently available are RS-232/V.35, X.21 and - T1/E1). If you wish to support Multilink PPP, please select the - option later and read the file README.mlppp provided by PC300 - package. - - To compile this as a module, choose M here: the module - will be called pc300. - - If unsure, say N. - -config PC300_MLPPP - bool "Cyclades-PC300 MLPPP support" - depends on PC300 && PPP_MULTILINK && PPP_SYNC_TTY && HDLC_PPP - help - Multilink PPP over the PC300 synchronous communication boards. - -comment "Cyclades-PC300 MLPPP support is disabled." - depends on HDLC && PC300 && (PPP=n || !PPP_MULTILINK || PPP_SYNC_TTY=n || !HDLC_PPP) - -comment "Refer to the file README.mlppp, provided by PC300 package." - depends on HDLC && PC300 && (PPP=n || !PPP_MULTILINK || PPP_SYNC_TTY=n || !HDLC_PPP) - config PC300TOO tristate "Cyclades PC300 RSV/X21 alternative support" depends on HDLC && PCI diff --git a/trunk/drivers/net/wan/Makefile b/trunk/drivers/net/wan/Makefile index 19d14bc28356..eac709bed7ae 100644 --- a/trunk/drivers/net/wan/Makefile +++ b/trunk/drivers/net/wan/Makefile @@ -17,10 +17,6 @@ obj-$(CONFIG_HDLC_FR) += hdlc_fr.o obj-$(CONFIG_HDLC_PPP) += hdlc_ppp.o obj-$(CONFIG_HDLC_X25) += hdlc_x25.o -pc300-y := pc300_drv.o -pc300-$(CONFIG_PC300_MLPPP) += pc300_tty.o -pc300-objs := $(pc300-y) - obj-$(CONFIG_HOSTESS_SV11) += z85230.o hostess_sv11.o obj-$(CONFIG_SEALEVEL_4021) += z85230.o sealevel.o obj-$(CONFIG_COSA) += cosa.o @@ -35,7 +31,6 @@ obj-$(CONFIG_SDLA) += sdla.o obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o obj-$(CONFIG_LAPBETHER) += lapbether.o obj-$(CONFIG_SBNI) += sbni.o -obj-$(CONFIG_PC300) += pc300.o obj-$(CONFIG_N2) += n2.o obj-$(CONFIG_C101) += c101.o obj-$(CONFIG_WANXL) += wanxl.o diff --git a/trunk/drivers/net/wan/dscc4.c b/trunk/drivers/net/wan/dscc4.c index c676de7de024..9eb6479306d6 100644 --- a/trunk/drivers/net/wan/dscc4.c +++ b/trunk/drivers/net/wan/dscc4.c @@ -2055,15 +2055,4 @@ static struct pci_driver dscc4_driver = { .remove = __devexit_p(dscc4_remove_one), }; -static int __init dscc4_init_module(void) -{ - return pci_register_driver(&dscc4_driver); -} - -static void __exit dscc4_cleanup_module(void) -{ - pci_unregister_driver(&dscc4_driver); -} - -module_init(dscc4_init_module); -module_exit(dscc4_cleanup_module); +module_pci_driver(dscc4_driver); diff --git a/trunk/drivers/net/wan/lmc/lmc_main.c b/trunk/drivers/net/wan/lmc/lmc_main.c index 76a8a4a522e9..f5d533a706ea 100644 --- a/trunk/drivers/net/wan/lmc/lmc_main.c +++ b/trunk/drivers/net/wan/lmc/lmc_main.c @@ -1120,7 +1120,7 @@ static void lmc_running_reset (struct net_device *dev) /*fold00*/ { lmc_softc_t *sc = dev_to_sc(dev); - lmc_trace(dev, "lmc_runnig_reset in"); + lmc_trace(dev, "lmc_running_reset in"); /* stop interrupts */ /* Clear the interrupt mask */ @@ -1736,18 +1736,7 @@ static struct pci_driver lmc_driver = { .remove = __devexit_p(lmc_remove_one), }; -static int __init init_lmc(void) -{ - return pci_register_driver(&lmc_driver); -} - -static void __exit exit_lmc(void) -{ - pci_unregister_driver(&lmc_driver); -} - -module_init(init_lmc); -module_exit(exit_lmc); +module_pci_driver(lmc_driver); unsigned lmc_mii_readreg (lmc_softc_t * const sc, unsigned devaddr, unsigned regno) /*fold00*/ { diff --git a/trunk/drivers/net/wimax/i2400m/Kconfig b/trunk/drivers/net/wimax/i2400m/Kconfig index 3f703384295e..672de18a776c 100644 --- a/trunk/drivers/net/wimax/i2400m/Kconfig +++ b/trunk/drivers/net/wimax/i2400m/Kconfig @@ -32,8 +32,9 @@ config WIMAX_I2400M_SDIO If unsure, it is safe to select M (module). config WIMAX_IWMC3200_SDIO - bool "Intel Wireless Multicom WiMAX Connection 3200 over SDIO" + bool "Intel Wireless Multicom WiMAX Connection 3200 over SDIO (EXPERIMENTAL)" depends on WIMAX_I2400M_SDIO + depends on EXPERIMENTAL select IWMC3200TOP help Select if you have a device based on the Intel Multicom WiMAX diff --git a/trunk/drivers/net/wimax/i2400m/usb-rx.c b/trunk/drivers/net/wimax/i2400m/usb-rx.c index e3257681e360..b78ee676e102 100644 --- a/trunk/drivers/net/wimax/i2400m/usb-rx.c +++ b/trunk/drivers/net/wimax/i2400m/usb-rx.c @@ -277,7 +277,7 @@ struct sk_buff *i2400mu_rx(struct i2400mu *i2400mu, struct sk_buff *rx_skb) d_printf(1, dev, "RX: size changed to %d, received %d, " "copied %d, capacity %ld\n", rx_size, read_size, rx_skb->len, - (long) (skb_end_pointer(new_skb) - new_skb->head)); + (long) skb_end_offset(new_skb)); goto retry; } /* In most cases, it happens due to the hardware scheduling a diff --git a/trunk/drivers/net/wimax/i2400m/usb.c b/trunk/drivers/net/wimax/i2400m/usb.c index 29b1e033a10b..713d033891e6 100644 --- a/trunk/drivers/net/wimax/i2400m/usb.c +++ b/trunk/drivers/net/wimax/i2400m/usb.c @@ -695,7 +695,7 @@ int i2400mu_resume(struct usb_interface *iface) d_fnstart(3, dev, "(iface %p)\n", iface); rmb(); /* see i2400m->updown's documentation */ if (i2400m->updown == 0) { - d_printf(1, dev, "fw was down, no resume neeed\n"); + d_printf(1, dev, "fw was down, no resume needed\n"); goto out; } d_printf(1, dev, "fw was up, resuming\n"); diff --git a/trunk/drivers/net/wireless/Kconfig b/trunk/drivers/net/wireless/Kconfig index abd3b71cd4ab..5f58fa53238c 100644 --- a/trunk/drivers/net/wireless/Kconfig +++ b/trunk/drivers/net/wireless/Kconfig @@ -282,8 +282,7 @@ source "drivers/net/wireless/orinoco/Kconfig" source "drivers/net/wireless/p54/Kconfig" source "drivers/net/wireless/rt2x00/Kconfig" source "drivers/net/wireless/rtlwifi/Kconfig" -source "drivers/net/wireless/wl1251/Kconfig" -source "drivers/net/wireless/wl12xx/Kconfig" +source "drivers/net/wireless/ti/Kconfig" source "drivers/net/wireless/zd1211rw/Kconfig" source "drivers/net/wireless/mwifiex/Kconfig" diff --git a/trunk/drivers/net/wireless/Makefile b/trunk/drivers/net/wireless/Makefile index 98db76196b59..0ce218b931d4 100644 --- a/trunk/drivers/net/wireless/Makefile +++ b/trunk/drivers/net/wireless/Makefile @@ -51,9 +51,7 @@ obj-$(CONFIG_ATH_COMMON) += ath/ obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o -obj-$(CONFIG_WL1251) += wl1251/ -obj-$(CONFIG_WL12XX) += wl12xx/ -obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/ +obj-$(CONFIG_WL_TI) += ti/ obj-$(CONFIG_IWM) += iwmc3200wifi/ diff --git a/trunk/drivers/net/wireless/adm8211.c b/trunk/drivers/net/wireless/adm8211.c index f5ce5623da99..0ac09a2bd144 100644 --- a/trunk/drivers/net/wireless/adm8211.c +++ b/trunk/drivers/net/wireless/adm8211.c @@ -1991,19 +1991,4 @@ static struct pci_driver adm8211_driver = { #endif /* CONFIG_PM */ }; - - -static int __init adm8211_init(void) -{ - return pci_register_driver(&adm8211_driver); -} - - -static void __exit adm8211_exit(void) -{ - pci_unregister_driver(&adm8211_driver); -} - - -module_init(adm8211_init); -module_exit(adm8211_exit); +module_pci_driver(adm8211_driver); diff --git a/trunk/drivers/net/wireless/at76c50x-usb.c b/trunk/drivers/net/wireless/at76c50x-usb.c index 4045e5ab0555..efc162e0b511 100644 --- a/trunk/drivers/net/wireless/at76c50x-usb.c +++ b/trunk/drivers/net/wireless/at76c50x-usb.c @@ -1122,12 +1122,12 @@ static void at76_dump_mib_phy(struct at76_priv *priv) static void at76_dump_mib_local(struct at76_priv *priv) { int ret; - struct mib_local *m = kmalloc(sizeof(struct mib_phy), GFP_KERNEL); + struct mib_local *m = kmalloc(sizeof(*m), GFP_KERNEL); if (!m) return; - ret = at76_get_mib(priv->udev, MIB_LOCAL, m, sizeof(struct mib_local)); + ret = at76_get_mib(priv->udev, MIB_LOCAL, m, sizeof(*m)); if (ret < 0) { wiphy_err(priv->hw->wiphy, "at76_get_mib (LOCAL) failed: %d\n", ret); @@ -1751,7 +1751,7 @@ static void at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * following workaround is necessary. If the TX frame is an * authentication frame extract the bssid and send the CMD_JOIN. */ if (mgmt->frame_control & cpu_to_le16(IEEE80211_STYPE_AUTH)) { - if (compare_ether_addr(priv->bssid, mgmt->bssid)) { + if (!ether_addr_equal(priv->bssid, mgmt->bssid)) { memcpy(priv->bssid, mgmt->bssid, ETH_ALEN); ieee80211_queue_work(hw, &priv->work_join_bssid); dev_kfree_skb_any(skb); @@ -1955,7 +1955,7 @@ static int at76_hw_scan(struct ieee80211_hw *hw, ret = at76_set_card_command(priv->udev, CMD_SCAN, &scan, sizeof(scan)); if (ret < 0) { - err("CMD_SCAN failed: %d", ret); + wiphy_err(priv->hw->wiphy, "CMD_SCAN failed: %d\n", ret); goto exit; } @@ -2486,6 +2486,7 @@ static struct usb_driver at76_driver = { .probe = at76_probe, .disconnect = at76_disconnect, .id_table = dev_table, + .disable_hub_initiated_lpm = 1, }; static int __init at76_mod_init(void) @@ -2512,10 +2513,8 @@ static void __exit at76_mod_exit(void) printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION " unloading\n"); usb_deregister(&at76_driver); - for (i = 0; i < ARRAY_SIZE(firmwares); i++) { - if (firmwares[i].fw) - release_firmware(firmwares[i].fw); - } + for (i = 0; i < ARRAY_SIZE(firmwares); i++) + release_firmware(firmwares[i].fw); led_trigger_unregister_simple(ledtrig_tx); } diff --git a/trunk/drivers/net/wireless/ath/ath5k/ani.c b/trunk/drivers/net/wireless/ath/ath5k/ani.c index 35e93704c4ef..5c008757662b 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/ani.c +++ b/trunk/drivers/net/wireless/ath/ath5k/ani.c @@ -14,6 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "ath5k.h" #include "reg.h" #include "debug.h" @@ -728,33 +730,25 @@ void ath5k_ani_print_counters(struct ath5k_hw *ah) { /* clears too */ - printk(KERN_NOTICE "ACK fail\t%d\n", - ath5k_hw_reg_read(ah, AR5K_ACK_FAIL)); - printk(KERN_NOTICE "RTS fail\t%d\n", - ath5k_hw_reg_read(ah, AR5K_RTS_FAIL)); - printk(KERN_NOTICE "RTS success\t%d\n", - ath5k_hw_reg_read(ah, AR5K_RTS_OK)); - printk(KERN_NOTICE "FCS error\t%d\n", - ath5k_hw_reg_read(ah, AR5K_FCS_FAIL)); + pr_notice("ACK fail\t%d\n", ath5k_hw_reg_read(ah, AR5K_ACK_FAIL)); + pr_notice("RTS fail\t%d\n", ath5k_hw_reg_read(ah, AR5K_RTS_FAIL)); + pr_notice("RTS success\t%d\n", ath5k_hw_reg_read(ah, AR5K_RTS_OK)); + pr_notice("FCS error\t%d\n", ath5k_hw_reg_read(ah, AR5K_FCS_FAIL)); /* no clear */ - printk(KERN_NOTICE "tx\t%d\n", - ath5k_hw_reg_read(ah, AR5K_PROFCNT_TX)); - printk(KERN_NOTICE "rx\t%d\n", - ath5k_hw_reg_read(ah, AR5K_PROFCNT_RX)); - printk(KERN_NOTICE "busy\t%d\n", - ath5k_hw_reg_read(ah, AR5K_PROFCNT_RXCLR)); - printk(KERN_NOTICE "cycles\t%d\n", - ath5k_hw_reg_read(ah, AR5K_PROFCNT_CYCLE)); - - printk(KERN_NOTICE "AR5K_PHYERR_CNT1\t%d\n", - ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT1)); - printk(KERN_NOTICE "AR5K_PHYERR_CNT2\t%d\n", - ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT2)); - printk(KERN_NOTICE "AR5K_OFDM_FIL_CNT\t%d\n", - ath5k_hw_reg_read(ah, AR5K_OFDM_FIL_CNT)); - printk(KERN_NOTICE "AR5K_CCK_FIL_CNT\t%d\n", - ath5k_hw_reg_read(ah, AR5K_CCK_FIL_CNT)); + pr_notice("tx\t%d\n", ath5k_hw_reg_read(ah, AR5K_PROFCNT_TX)); + pr_notice("rx\t%d\n", ath5k_hw_reg_read(ah, AR5K_PROFCNT_RX)); + pr_notice("busy\t%d\n", ath5k_hw_reg_read(ah, AR5K_PROFCNT_RXCLR)); + pr_notice("cycles\t%d\n", ath5k_hw_reg_read(ah, AR5K_PROFCNT_CYCLE)); + + pr_notice("AR5K_PHYERR_CNT1\t%d\n", + ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT1)); + pr_notice("AR5K_PHYERR_CNT2\t%d\n", + ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT2)); + pr_notice("AR5K_OFDM_FIL_CNT\t%d\n", + ath5k_hw_reg_read(ah, AR5K_OFDM_FIL_CNT)); + pr_notice("AR5K_CCK_FIL_CNT\t%d\n", + ath5k_hw_reg_read(ah, AR5K_CCK_FIL_CNT)); } #endif diff --git a/trunk/drivers/net/wireless/ath/ath5k/ath5k.h b/trunk/drivers/net/wireless/ath/ath5k/ath5k.h index 8d434b8f5855..64a453a6dfe4 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/trunk/drivers/net/wireless/ath/ath5k/ath5k.h @@ -76,26 +76,29 @@ GENERIC DRIVER DEFINITIONS \****************************/ -#define ATH5K_PRINTF(fmt, ...) \ - printk(KERN_WARNING "%s: " fmt, __func__, ##__VA_ARGS__) +#define ATH5K_PRINTF(fmt, ...) \ + pr_warn("%s: " fmt, __func__, ##__VA_ARGS__) -#define ATH5K_PRINTK(_sc, _level, _fmt, ...) \ - printk(_level "ath5k %s: " _fmt, \ - ((_sc) && (_sc)->hw) ? wiphy_name((_sc)->hw->wiphy) : "", \ - ##__VA_ARGS__) +void __printf(3, 4) +_ath5k_printk(const struct ath5k_hw *ah, const char *level, + const char *fmt, ...); -#define ATH5K_PRINTK_LIMIT(_sc, _level, _fmt, ...) do { \ - if (net_ratelimit()) \ - ATH5K_PRINTK(_sc, _level, _fmt, ##__VA_ARGS__); \ - } while (0) +#define ATH5K_PRINTK(_sc, _level, _fmt, ...) \ + _ath5k_printk(_sc, _level, _fmt, ##__VA_ARGS__) -#define ATH5K_INFO(_sc, _fmt, ...) \ +#define ATH5K_PRINTK_LIMIT(_sc, _level, _fmt, ...) \ +do { \ + if (net_ratelimit()) \ + ATH5K_PRINTK(_sc, _level, _fmt, ##__VA_ARGS__); \ +} while (0) + +#define ATH5K_INFO(_sc, _fmt, ...) \ ATH5K_PRINTK(_sc, KERN_INFO, _fmt, ##__VA_ARGS__) -#define ATH5K_WARN(_sc, _fmt, ...) \ +#define ATH5K_WARN(_sc, _fmt, ...) \ ATH5K_PRINTK_LIMIT(_sc, KERN_WARNING, _fmt, ##__VA_ARGS__) -#define ATH5K_ERR(_sc, _fmt, ...) \ +#define ATH5K_ERR(_sc, _fmt, ...) \ ATH5K_PRINTK_LIMIT(_sc, KERN_ERR, _fmt, ##__VA_ARGS__) /* @@ -1524,7 +1527,7 @@ void ath5k_eeprom_detach(struct ath5k_hw *ah); /* Protocol Control Unit Functions */ /* Helpers */ -int ath5k_hw_get_frame_duration(struct ath5k_hw *ah, +int ath5k_hw_get_frame_duration(struct ath5k_hw *ah, enum ieee80211_band band, int len, struct ieee80211_rate *rate, bool shortpre); unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah); unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah); diff --git a/trunk/drivers/net/wireless/ath/ath5k/attach.c b/trunk/drivers/net/wireless/ath/ath5k/attach.c index d7114c75fe9b..7106547a14dd 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/attach.c +++ b/trunk/drivers/net/wireless/ath/ath5k/attach.c @@ -20,6 +20,8 @@ * Attach/Detach Functions and helpers * \*************************************/ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include "ath5k.h" diff --git a/trunk/drivers/net/wireless/ath/ath5k/base.c b/trunk/drivers/net/wireless/ath/ath5k/base.c index 0e643b016b32..0ba81a66061f 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/base.c +++ b/trunk/drivers/net/wireless/ath/ath5k/base.c @@ -40,6 +40,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -460,7 +462,7 @@ void ath5k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) } if (iter_data->need_set_hw_addr && iter_data->hw_macaddr) - if (compare_ether_addr(iter_data->hw_macaddr, mac) == 0) + if (ether_addr_equal(iter_data->hw_macaddr, mac)) iter_data->need_set_hw_addr = false; if (!iter_data->any_assoc) { @@ -1168,7 +1170,7 @@ ath5k_check_ibss_tsf(struct ath5k_hw *ah, struct sk_buff *skb, if (ieee80211_is_beacon(mgmt->frame_control) && le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS && - memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) == 0) { + ether_addr_equal(mgmt->bssid, common->curbssid)) { /* * Received an IBSS beacon with the same BSSID. Hardware *must* * have updated the local TSF. We have to work around various @@ -1232,7 +1234,7 @@ ath5k_update_beacon_rssi(struct ath5k_hw *ah, struct sk_buff *skb, int rssi) /* only beacons from our BSSID */ if (!ieee80211_is_beacon(mgmt->frame_control) || - memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) != 0) + !ether_addr_equal(mgmt->bssid, common->curbssid)) return; ewma_add(&ah->ah_beacon_rssi_avg, rssi); @@ -3038,3 +3040,23 @@ ath5k_set_beacon_filter(struct ieee80211_hw *hw, bool enable) ath5k_hw_set_rx_filter(ah, rfilt); ah->filter_flags = rfilt; } + +void _ath5k_printk(const struct ath5k_hw *ah, const char *level, + const char *fmt, ...) +{ + struct va_format vaf; + va_list args; + + va_start(args, fmt); + + vaf.fmt = fmt; + vaf.va = &args; + + if (ah && ah->hw) + printk("%s" pr_fmt("%s: %pV"), + level, wiphy_name(ah->hw->wiphy), &vaf); + else + printk("%s" pr_fmt("%pV"), level, &vaf); + + va_end(args); +} diff --git a/trunk/drivers/net/wireless/ath/ath5k/debug.c b/trunk/drivers/net/wireless/ath/ath5k/debug.c index e5e8f45d86ac..9d00dab666a8 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/debug.c +++ b/trunk/drivers/net/wireless/ath/ath5k/debug.c @@ -57,6 +57,9 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include @@ -247,10 +250,10 @@ static ssize_t write_file_beacon(struct file *file, if (strncmp(buf, "disable", 7) == 0) { AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE); - printk(KERN_INFO "debugfs disable beacons\n"); + pr_info("debugfs disable beacons\n"); } else if (strncmp(buf, "enable", 6) == 0) { AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE); - printk(KERN_INFO "debugfs enable beacons\n"); + pr_info("debugfs enable beacons\n"); } return count; } @@ -450,19 +453,19 @@ static ssize_t write_file_antenna(struct file *file, if (strncmp(buf, "diversity", 9) == 0) { ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT); - printk(KERN_INFO "ath5k debug: enable diversity\n"); + pr_info("debug: enable diversity\n"); } else if (strncmp(buf, "fixed-a", 7) == 0) { ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_FIXED_A); - printk(KERN_INFO "ath5k debugfs: fixed antenna A\n"); + pr_info("debug: fixed antenna A\n"); } else if (strncmp(buf, "fixed-b", 7) == 0) { ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_FIXED_B); - printk(KERN_INFO "ath5k debug: fixed antenna B\n"); + pr_info("debug: fixed antenna B\n"); } else if (strncmp(buf, "clear", 5) == 0) { for (i = 0; i < ARRAY_SIZE(ah->stats.antenna_rx); i++) { ah->stats.antenna_rx[i] = 0; ah->stats.antenna_tx[i] = 0; } - printk(KERN_INFO "ath5k debug: cleared antenna stats\n"); + pr_info("debug: cleared antenna stats\n"); } return count; } @@ -632,7 +635,7 @@ static ssize_t write_file_frameerrors(struct file *file, st->txerr_fifo = 0; st->txerr_filt = 0; st->tx_all_count = 0; - printk(KERN_INFO "ath5k debug: cleared frameerrors stats\n"); + pr_info("debug: cleared frameerrors stats\n"); } return count; } diff --git a/trunk/drivers/net/wireless/ath/ath5k/desc.c b/trunk/drivers/net/wireless/ath/ath5k/desc.c index f8bfa3ac2af0..bd8d4392d68b 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/desc.c +++ b/trunk/drivers/net/wireless/ath/ath5k/desc.c @@ -21,6 +21,8 @@ Hardware Descriptor Functions \******************************/ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "ath5k.h" #include "reg.h" #include "debug.h" @@ -441,10 +443,8 @@ ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, struct ath5k_desc *desc, struct ath5k_tx_status *ts) { - struct ath5k_hw_2w_tx_ctl *tx_ctl; struct ath5k_hw_tx_status *tx_status; - tx_ctl = &desc->ud.ds_tx5210.tx_ctl; tx_status = &desc->ud.ds_tx5210.tx_stat; /* No frame has been send or error */ @@ -495,11 +495,9 @@ ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, struct ath5k_desc *desc, struct ath5k_tx_status *ts) { - struct ath5k_hw_4w_tx_ctl *tx_ctl; struct ath5k_hw_tx_status *tx_status; u32 txstat0, txstat1; - tx_ctl = &desc->ud.ds_tx5212.tx_ctl; tx_status = &desc->ud.ds_tx5212.tx_stat; txstat1 = ACCESS_ONCE(tx_status->tx_status_1); diff --git a/trunk/drivers/net/wireless/ath/ath5k/dma.c b/trunk/drivers/net/wireless/ath/ath5k/dma.c index 5cc9aa814697..ce86f158423b 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/dma.c +++ b/trunk/drivers/net/wireless/ath/ath5k/dma.c @@ -29,6 +29,8 @@ * status registers (ISR). */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "ath5k.h" #include "reg.h" #include "debug.h" diff --git a/trunk/drivers/net/wireless/ath/ath5k/eeprom.c b/trunk/drivers/net/wireless/ath/ath5k/eeprom.c index cd708c15b774..4026c906cc7b 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/trunk/drivers/net/wireless/ath/ath5k/eeprom.c @@ -21,6 +21,8 @@ * EEPROM access functions and helpers * \*************************************/ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include "ath5k.h" diff --git a/trunk/drivers/net/wireless/ath/ath5k/initvals.c b/trunk/drivers/net/wireless/ath/ath5k/initvals.c index a1ea78e05b47..ee1c2fa8b591 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/initvals.c +++ b/trunk/drivers/net/wireless/ath/ath5k/initvals.c @@ -19,6 +19,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "ath5k.h" #include "reg.h" #include "debug.h" @@ -1574,8 +1576,7 @@ ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool skip_pcu) /* AR5K_MODE_11B */ if (mode > 2) { - ATH5K_ERR(ah, - "unsupported channel mode: %d\n", mode); + ATH5K_ERR(ah, "unsupported channel mode: %d\n", mode); return -EINVAL; } diff --git a/trunk/drivers/net/wireless/ath/ath5k/led.c b/trunk/drivers/net/wireless/ath/ath5k/led.c index c1151c723711..b9f708a45f4e 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/led.c +++ b/trunk/drivers/net/wireless/ath/ath5k/led.c @@ -39,6 +39,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include "ath5k.h" diff --git a/trunk/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/trunk/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 5c5329955414..22b80af0f47c 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/trunk/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -41,6 +41,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include diff --git a/trunk/drivers/net/wireless/ath/ath5k/pci.c b/trunk/drivers/net/wireless/ath/ath5k/pci.c index 849fa060ebc4..dff48fbc63bf 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/pci.c +++ b/trunk/drivers/net/wireless/ath/ath5k/pci.c @@ -14,6 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -45,6 +47,7 @@ static DEFINE_PCI_DEVICE_TABLE(ath5k_pci_id_table) = { { PCI_VDEVICE(ATHEROS, 0x001b) }, /* 5413 Eagle */ { PCI_VDEVICE(ATHEROS, 0x001c) }, /* PCI-E cards */ { PCI_VDEVICE(ATHEROS, 0x001d) }, /* 2417 Nala */ + { PCI_VDEVICE(ATHEROS, 0xff1b) }, /* AR5BXB63 */ { 0 } }; MODULE_DEVICE_TABLE(pci, ath5k_pci_id_table); @@ -337,28 +340,4 @@ static struct pci_driver ath5k_pci_driver = { .driver.pm = ATH5K_PM_OPS, }; -/* - * Module init/exit functions - */ -static int __init -init_ath5k_pci(void) -{ - int ret; - - ret = pci_register_driver(&ath5k_pci_driver); - if (ret) { - printk(KERN_ERR "ath5k_pci: can't register pci driver\n"); - return ret; - } - - return 0; -} - -static void __exit -exit_ath5k_pci(void) -{ - pci_unregister_driver(&ath5k_pci_driver); -} - -module_init(init_ath5k_pci); -module_exit(exit_ath5k_pci); +module_pci_driver(ath5k_pci_driver); diff --git a/trunk/drivers/net/wireless/ath/ath5k/pcu.c b/trunk/drivers/net/wireless/ath/ath5k/pcu.c index cebfd6fd31d3..1f16b4227d8f 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/pcu.c +++ b/trunk/drivers/net/wireless/ath/ath5k/pcu.c @@ -110,7 +110,7 @@ static const unsigned int ack_rates_high[] = * bwmodes. */ int -ath5k_hw_get_frame_duration(struct ath5k_hw *ah, +ath5k_hw_get_frame_duration(struct ath5k_hw *ah, enum ieee80211_band band, int len, struct ieee80211_rate *rate, bool shortpre) { int sifs, preamble, plcp_bits, sym_time; @@ -120,7 +120,7 @@ ath5k_hw_get_frame_duration(struct ath5k_hw *ah, /* Fallback */ if (!ah->ah_bwmode) { __le16 raw_dur = ieee80211_generic_frame_duration(ah->hw, - NULL, len, rate); + NULL, band, len, rate); /* subtract difference between long and short preamble */ dur = le16_to_cpu(raw_dur); @@ -302,14 +302,15 @@ ath5k_hw_write_rate_duration(struct ath5k_hw *ah) * actual rate for this rate. See mac80211 tx.c * ieee80211_duration() for a brief description of * what rate we should choose to TX ACKs. */ - tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, false); + tx_time = ath5k_hw_get_frame_duration(ah, band, 10, + rate, false); ath5k_hw_reg_write(ah, tx_time, reg); if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)) continue; - tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, true); + tx_time = ath5k_hw_get_frame_duration(ah, band, 10, rate, true); ath5k_hw_reg_write(ah, tx_time, reg + (AR5K_SET_SHORT_PREAMBLE << 2)); } diff --git a/trunk/drivers/net/wireless/ath/ath5k/phy.c b/trunk/drivers/net/wireless/ath/ath5k/phy.c index 3a2845489a1b..8b71a2d947e0 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/phy.c +++ b/trunk/drivers/net/wireless/ath/ath5k/phy.c @@ -22,6 +22,8 @@ * PHY related functions * \***********************/ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include diff --git a/trunk/drivers/net/wireless/ath/ath5k/qcu.c b/trunk/drivers/net/wireless/ath/ath5k/qcu.c index 30b50f934172..65fe929529a8 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/qcu.c +++ b/trunk/drivers/net/wireless/ath/ath5k/qcu.c @@ -20,6 +20,8 @@ Queue Control Unit, DCF Control Unit Functions \********************************************/ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "ath5k.h" #include "reg.h" #include "debug.h" @@ -563,6 +565,7 @@ ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time) { struct ieee80211_channel *channel = ah->ah_current_channel; + enum ieee80211_band band; struct ieee80211_rate *rate; u32 ack_tx_time, eifs, eifs_clock, sifs, sifs_clock; u32 slot_time_clock = ath5k_hw_htoclock(ah, slot_time); @@ -598,11 +601,12 @@ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time) * Also we have different lowest rate for 802.11a */ if (channel->band == IEEE80211_BAND_5GHZ) - rate = &ah->sbands[IEEE80211_BAND_5GHZ].bitrates[0]; + band = IEEE80211_BAND_5GHZ; else - rate = &ah->sbands[IEEE80211_BAND_2GHZ].bitrates[0]; + band = IEEE80211_BAND_2GHZ; - ack_tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, false); + rate = &ah->sbands[band].bitrates[0]; + ack_tx_time = ath5k_hw_get_frame_duration(ah, band, 10, rate, false); /* ack_tx_time includes an SIFS already */ eifs = ack_tx_time + sifs + 2 * slot_time; diff --git a/trunk/drivers/net/wireless/ath/ath5k/reset.c b/trunk/drivers/net/wireless/ath/ath5k/reset.c index 200f165c0c6d..0c2dd4771c36 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/reset.c +++ b/trunk/drivers/net/wireless/ath/ath5k/reset.c @@ -23,6 +23,8 @@ Reset function and helpers \****************************/ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include /* To determine if a card is pci-e */ diff --git a/trunk/drivers/net/wireless/ath/ath5k/sysfs.c b/trunk/drivers/net/wireless/ath/ath5k/sysfs.c index 9364da7bd131..04cf0ca72610 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/sysfs.c +++ b/trunk/drivers/net/wireless/ath/ath5k/sysfs.c @@ -1,3 +1,5 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include diff --git a/trunk/drivers/net/wireless/ath/ath6kl/Makefile b/trunk/drivers/net/wireless/ath/ath6kl/Makefile index 85746c3eb027..8cae8886f17d 100644 --- a/trunk/drivers/net/wireless/ath/ath6kl/Makefile +++ b/trunk/drivers/net/wireless/ath/ath6kl/Makefile @@ -25,7 +25,8 @@ obj-$(CONFIG_ATH6KL) += ath6kl_core.o ath6kl_core-y += debug.o ath6kl_core-y += hif.o -ath6kl_core-y += htc.o +ath6kl_core-y += htc_mbox.o +ath6kl_core-y += htc_pipe.o ath6kl_core-y += bmi.o ath6kl_core-y += cfg80211.o ath6kl_core-y += init.o diff --git a/trunk/drivers/net/wireless/ath/ath6kl/cfg80211.c b/trunk/drivers/net/wireless/ath/ath6kl/cfg80211.c index 00d38952b5fb..28a65d3a03d0 100644 --- a/trunk/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/trunk/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -15,6 +15,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -49,6 +51,8 @@ .max_power = 30, \ } +#define DEFAULT_BG_SCAN_PERIOD 60 + static struct ieee80211_rate ath6kl_rates[] = { RATETAB_ENT(10, 0x1, 0), RATETAB_ENT(20, 0x2, 0), @@ -69,7 +73,8 @@ static struct ieee80211_rate ath6kl_rates[] = { #define ath6kl_g_rates (ath6kl_rates + 0) #define ath6kl_g_rates_size 12 -#define ath6kl_g_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ +#define ath6kl_g_htcap IEEE80211_HT_CAP_SGI_20 +#define ath6kl_a_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ IEEE80211_HT_CAP_SGI_20 | \ IEEE80211_HT_CAP_SGI_40) @@ -126,7 +131,7 @@ static struct ieee80211_supported_band ath6kl_band_5ghz = { .channels = ath6kl_5ghz_a_channels, .n_bitrates = ath6kl_a_rates_size, .bitrates = ath6kl_a_rates, - .ht_cap.cap = ath6kl_g_htcap, + .ht_cap.cap = ath6kl_a_htcap, .ht_cap.ht_supported = true, }; @@ -607,6 +612,17 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, vif->req_bssid, vif->ch_hint, ar->connect_ctrl_flags, nw_subtype); + /* disable background scan if period is 0 */ + if (sme->bg_scan_period == 0) + sme->bg_scan_period = 0xffff; + + /* configure default value if not specified */ + if (sme->bg_scan_period == -1) + sme->bg_scan_period = DEFAULT_BG_SCAN_PERIOD; + + ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0, 0, + sme->bg_scan_period, 0, 0, 0, 3, 0, 0, 0); + up(&ar->sem); if (status == -EINVAL) { @@ -941,6 +957,8 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, if (test_bit(CONNECTED, &vif->flags)) force_fg_scan = 1; + vif->scan_req = request; + if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, ar->fw_capabilities)) { /* @@ -963,10 +981,10 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, ATH6KL_FG_SCAN_INTERVAL, n_channels, channels); } - if (ret) + if (ret) { ath6kl_err("wmi_startscan_cmd failed\n"); - else - vif->scan_req = request; + vif->scan_req = NULL; + } kfree(channels); @@ -1436,9 +1454,38 @@ static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy, struct vif_params *params) { struct ath6kl_vif *vif = netdev_priv(ndev); + int i; ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type); + /* + * Don't bring up p2p on an interface which is not initialized + * for p2p operation where fw does not have capability to switch + * dynamically between non-p2p and p2p type interface. + */ + if (!test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, + vif->ar->fw_capabilities) && + (type == NL80211_IFTYPE_P2P_CLIENT || + type == NL80211_IFTYPE_P2P_GO)) { + if (vif->ar->vif_max == 1) { + if (vif->fw_vif_idx != 0) + return -EINVAL; + else + goto set_iface_type; + } + + for (i = vif->ar->max_norm_iface; i < vif->ar->vif_max; i++) { + if (i == vif->fw_vif_idx) + break; + } + + if (i == vif->ar->vif_max) { + ath6kl_err("Invalid interface to bring up P2P\n"); + return -EINVAL; + } + } + +set_iface_type: switch (type) { case NL80211_IFTYPE_STATION: vif->next_mode = INFRA_NETWORK; @@ -1924,12 +1971,61 @@ static int ath6kl_wow_sta(struct ath6kl *ar, struct ath6kl_vif *vif) return 0; } +static int is_hsleep_mode_procsed(struct ath6kl_vif *vif) +{ + return test_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags); +} + +static bool is_ctrl_ep_empty(struct ath6kl *ar) +{ + return !ar->tx_pending[ar->ctrl_ep]; +} + +static int ath6kl_cfg80211_host_sleep(struct ath6kl *ar, struct ath6kl_vif *vif) +{ + int ret, left; + + clear_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags); + + ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, + ATH6KL_HOST_MODE_ASLEEP); + if (ret) + return ret; + + left = wait_event_interruptible_timeout(ar->event_wq, + is_hsleep_mode_procsed(vif), + WMI_TIMEOUT); + if (left == 0) { + ath6kl_warn("timeout, didn't get host sleep cmd processed event\n"); + ret = -ETIMEDOUT; + } else if (left < 0) { + ath6kl_warn("error while waiting for host sleep cmd processed event %d\n", + left); + ret = left; + } + + if (ar->tx_pending[ar->ctrl_ep]) { + left = wait_event_interruptible_timeout(ar->event_wq, + is_ctrl_ep_empty(ar), + WMI_TIMEOUT); + if (left == 0) { + ath6kl_warn("clear wmi ctrl data timeout\n"); + ret = -ETIMEDOUT; + } else if (left < 0) { + ath6kl_warn("clear wmi ctrl data failed: %d\n", left); + ret = left; + } + } + + return ret; +} + static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) { struct in_device *in_dev; struct in_ifaddr *ifa; struct ath6kl_vif *vif; - int ret, left; + int ret; u32 filter = 0; u16 i, bmiss_time; u8 index = 0; @@ -2030,39 +2126,11 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) if (ret) return ret; - clear_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags); - - ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, - ATH6KL_HOST_MODE_ASLEEP); + ret = ath6kl_cfg80211_host_sleep(ar, vif); if (ret) return ret; - left = wait_event_interruptible_timeout(ar->event_wq, - test_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags), - WMI_TIMEOUT); - if (left == 0) { - ath6kl_warn("timeout, didn't get host sleep cmd " - "processed event\n"); - ret = -ETIMEDOUT; - } else if (left < 0) { - ath6kl_warn("error while waiting for host sleep cmd " - "processed event %d\n", left); - ret = left; - } - - if (ar->tx_pending[ar->ctrl_ep]) { - left = wait_event_interruptible_timeout(ar->event_wq, - ar->tx_pending[ar->ctrl_ep] == 0, WMI_TIMEOUT); - if (left == 0) { - ath6kl_warn("clear wmi ctrl data timeout\n"); - ret = -ETIMEDOUT; - } else if (left < 0) { - ath6kl_warn("clear wmi ctrl data failed: %d\n", left); - ret = left; - } - } - - return ret; + return 0; } static int ath6kl_wow_resume(struct ath6kl *ar) @@ -2109,10 +2177,82 @@ static int ath6kl_wow_resume(struct ath6kl *ar) return 0; } +static int ath6kl_cfg80211_deepsleep_suspend(struct ath6kl *ar) +{ + struct ath6kl_vif *vif; + int ret; + + vif = ath6kl_vif_first(ar); + if (!vif) + return -EIO; + + if (!ath6kl_cfg80211_ready(vif)) + return -EIO; + + ath6kl_cfg80211_stop_all(ar); + + /* Save the current power mode before enabling power save */ + ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode; + + ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER); + if (ret) + return ret; + + /* Disable WOW mode */ + ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx, + ATH6KL_WOW_MODE_DISABLE, + 0, 0); + if (ret) + return ret; + + /* Flush all non control pkts in TX path */ + ath6kl_tx_data_cleanup(ar); + + ret = ath6kl_cfg80211_host_sleep(ar, vif); + if (ret) + return ret; + + return 0; +} + +static int ath6kl_cfg80211_deepsleep_resume(struct ath6kl *ar) +{ + struct ath6kl_vif *vif; + int ret; + + vif = ath6kl_vif_first(ar); + + if (!vif) + return -EIO; + + if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) { + ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, + ar->wmi->saved_pwr_mode); + if (ret) + return ret; + } + + ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, + ATH6KL_HOST_MODE_AWAKE); + if (ret) + return ret; + + ar->state = ATH6KL_STATE_ON; + + /* Reset scan parameter to default values */ + ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, + 0, 0, 0, 0, 0, 0, 3, 0, 0, 0); + if (ret) + return ret; + + return 0; +} + int ath6kl_cfg80211_suspend(struct ath6kl *ar, enum ath6kl_cfg_suspend_mode mode, struct cfg80211_wowlan *wow) { + struct ath6kl_vif *vif; enum ath6kl_state prev_state; int ret; @@ -2137,15 +2277,12 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar, case ATH6KL_CFG_SUSPEND_DEEPSLEEP: - ath6kl_cfg80211_stop_all(ar); - - /* save the current power mode before enabling power save */ - ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode; + ath6kl_dbg(ATH6KL_DBG_SUSPEND, "deep sleep suspend\n"); - ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER); + ret = ath6kl_cfg80211_deepsleep_suspend(ar); if (ret) { - ath6kl_warn("wmi powermode command failed during suspend: %d\n", - ret); + ath6kl_err("deepsleep suspend failed: %d\n", ret); + return ret; } ar->state = ATH6KL_STATE_DEEPSLEEP; @@ -2185,6 +2322,9 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar, break; } + list_for_each_entry(vif, &ar->vif_list, list) + ath6kl_cfg80211_scan_complete_event(vif, true); + return 0; } EXPORT_SYMBOL(ath6kl_cfg80211_suspend); @@ -2206,17 +2346,13 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar) break; case ATH6KL_STATE_DEEPSLEEP: - if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) { - ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0, - ar->wmi->saved_pwr_mode); - if (ret) { - ath6kl_warn("wmi powermode command failed during resume: %d\n", - ret); - } - } - - ar->state = ATH6KL_STATE_ON; + ath6kl_dbg(ATH6KL_DBG_SUSPEND, "deep sleep resume\n"); + ret = ath6kl_cfg80211_deepsleep_resume(ar); + if (ret) { + ath6kl_warn("deep sleep resume failed: %d\n", ret); + return ret; + } break; case ATH6KL_STATE_CUTPOWER: @@ -2290,31 +2426,25 @@ void ath6kl_check_wow_status(struct ath6kl *ar) } #endif -static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type) +static int ath6kl_set_htcap(struct ath6kl_vif *vif, enum ieee80211_band band, + bool ht_enable) { - struct ath6kl_vif *vif; - - /* - * 'dev' could be NULL if a channel change is required for the hardware - * device itself, instead of a particular VIF. - * - * FIXME: To be handled properly when monitor mode is supported. - */ - if (!dev) - return -EBUSY; - - vif = netdev_priv(dev); + struct ath6kl_htcap *htcap = &vif->htcap; - if (!ath6kl_cfg80211_ready(vif)) - return -EIO; + if (htcap->ht_enable == ht_enable) + return 0; - ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n", - __func__, chan->center_freq, chan->hw_value); - vif->next_chan = chan->center_freq; + if (ht_enable) { + /* Set default ht capabilities */ + htcap->ht_enable = true; + htcap->cap_info = (band == IEEE80211_BAND_2GHZ) ? + ath6kl_g_htcap : ath6kl_a_htcap; + htcap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K; + } else /* Disable ht */ + memset(htcap, 0, sizeof(*htcap)); - return 0; + return ath6kl_wmi_set_htcap_cmd(vif->ar->wmi, vif->fw_vif_idx, + band, htcap); } static bool ath6kl_is_p2p_ie(const u8 *pos) @@ -2391,6 +2521,81 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif, return 0; } +static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +{ + struct ath6kl_vif *vif; + + /* + * 'dev' could be NULL if a channel change is required for the hardware + * device itself, instead of a particular VIF. + * + * FIXME: To be handled properly when monitor mode is supported. + */ + if (!dev) + return -EBUSY; + + vif = netdev_priv(dev); + + if (!ath6kl_cfg80211_ready(vif)) + return -EIO; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n", + __func__, chan->center_freq, chan->hw_value); + vif->next_chan = chan->center_freq; + vif->next_ch_type = channel_type; + vif->next_ch_band = chan->band; + + return 0; +} + +static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon, + u8 *rsn_capab) +{ + const u8 *rsn_ie; + size_t rsn_ie_len; + u16 cnt; + + if (!beacon->tail) + return -EINVAL; + + rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, beacon->tail, beacon->tail_len); + if (!rsn_ie) + return -EINVAL; + + rsn_ie_len = *(rsn_ie + 1); + /* skip element id and length */ + rsn_ie += 2; + + /* skip version, group cipher */ + if (rsn_ie_len < 6) + return -EINVAL; + rsn_ie += 6; + rsn_ie_len -= 6; + + /* skip pairwise cipher suite */ + if (rsn_ie_len < 2) + return -EINVAL; + cnt = *((u16 *) rsn_ie); + rsn_ie += (2 + cnt * 4); + rsn_ie_len -= (2 + cnt * 4); + + /* skip akm suite */ + if (rsn_ie_len < 2) + return -EINVAL; + cnt = *((u16 *) rsn_ie); + rsn_ie += (2 + cnt * 4); + rsn_ie_len -= (2 + cnt * 4); + + if (rsn_ie_len < 2) + return -EINVAL; + + memcpy(rsn_capab, rsn_ie, 2); + + return 0; +} + static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ap_settings *info) { @@ -2403,6 +2608,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, struct wmi_connect_cmd p; int res; int i, ret; + u16 rsn_capab = 0; ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__); @@ -2532,6 +2738,34 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, p.nw_subtype = SUBTYPE_NONE; } + if (info->inactivity_timeout) { + res = ath6kl_wmi_set_inact_period(ar->wmi, vif->fw_vif_idx, + info->inactivity_timeout); + if (res < 0) + return res; + } + + if (ath6kl_set_htcap(vif, vif->next_ch_band, + vif->next_ch_type != NL80211_CHAN_NO_HT)) + return -EIO; + + /* + * Get the PTKSA replay counter in the RSN IE. Supplicant + * will use the RSN IE in M3 message and firmware has to + * advertise the same in beacon/probe response. Send + * the complete RSN IE capability field to firmware + */ + if (!ath6kl_get_rsn_capab(&info->beacon, (u8 *) &rsn_capab) && + test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE, + ar->fw_capabilities)) { + res = ath6kl_wmi_set_ie_cmd(ar->wmi, vif->fw_vif_idx, + WLAN_EID_RSN, WMI_RSN_IE_CAPB, + (const u8 *) &rsn_capab, + sizeof(rsn_capab)); + if (res < 0) + return res; + } + res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p); if (res < 0) return res; @@ -2566,6 +2800,13 @@ static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev) ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx); clear_bit(CONNECTED, &vif->flags); + /* Restore ht setting in firmware */ + if (ath6kl_set_htcap(vif, IEEE80211_BAND_2GHZ, true)) + return -EIO; + + if (ath6kl_set_htcap(vif, IEEE80211_BAND_5GHZ, true)) + return -EIO; + return 0; } @@ -2747,6 +2988,21 @@ static bool ath6kl_mgmt_powersave_ap(struct ath6kl_vif *vif, return false; } +/* Check if SSID length is greater than DIRECT- */ +static bool ath6kl_is_p2p_go_ssid(const u8 *buf, size_t len) +{ + const struct ieee80211_mgmt *mgmt; + mgmt = (const struct ieee80211_mgmt *) buf; + + /* variable[1] contains the SSID tag length */ + if (buf + len >= &mgmt->u.probe_resp.variable[1] && + (mgmt->u.probe_resp.variable[1] > P2P_WILDCARD_SSID_LEN)) { + return true; + } + + return false; +} + static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel *chan, bool offchan, enum nl80211_channel_type channel_type, @@ -2761,11 +3017,11 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, bool more_data, queued; mgmt = (const struct ieee80211_mgmt *) buf; - if (buf + len >= mgmt->u.probe_resp.variable && - vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) && - ieee80211_is_probe_resp(mgmt->frame_control)) { + if (vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) && + ieee80211_is_probe_resp(mgmt->frame_control) && + ath6kl_is_p2p_go_ssid(buf, len)) { /* - * Send Probe Response frame in AP mode using a separate WMI + * Send Probe Response frame in GO mode using a separate WMI * command to allow the target to fill in the generic IEs. */ *cookie = 0; /* TX status not supported */ @@ -2833,6 +3089,8 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, if (vif->sme_state != SME_DISCONNECTED) return -EBUSY; + ath6kl_cfg80211_scan_complete_event(vif, true); + for (i = 0; i < ar->wiphy->max_sched_scan_ssids; i++) { ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i, DISABLE_SSID_FLAG, @@ -3094,6 +3352,7 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, vif->next_mode = nw_type; vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL; vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME; + vif->htcap.ht_enable = true; memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); if (fw_vif_idx != 0) @@ -3181,6 +3440,10 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities)) ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; + if (test_bit(ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT, + ar->fw_capabilities)) + ar->wiphy->features = NL80211_FEATURE_INACTIVITY_TIMER; + ar->wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | diff --git a/trunk/drivers/net/wireless/ath/ath6kl/common.h b/trunk/drivers/net/wireless/ath/ath6kl/common.h index a60e78c0472f..98a886154d9c 100644 --- a/trunk/drivers/net/wireless/ath/ath6kl/common.h +++ b/trunk/drivers/net/wireless/ath/ath6kl/common.h @@ -22,7 +22,8 @@ #define ATH6KL_MAX_IE 256 -extern int ath6kl_printk(const char *level, const char *fmt, ...); +extern __printf(2, 3) +int ath6kl_printk(const char *level, const char *fmt, ...); /* * Reflects the version of binary interface exposed by ATH6KL target @@ -77,6 +78,7 @@ enum crypto_type { struct htc_endpoint_credit_dist; struct ath6kl; +struct ath6kl_htcap; enum htc_credit_dist_reason; struct ath6kl_htc_credit_info; diff --git a/trunk/drivers/net/wireless/ath/ath6kl/core.c b/trunk/drivers/net/wireless/ath/ath6kl/core.c index 45e641f3a41b..fdb3b1decc76 100644 --- a/trunk/drivers/net/wireless/ath/ath6kl/core.c +++ b/trunk/drivers/net/wireless/ath/ath6kl/core.c @@ -20,9 +20,11 @@ #include #include #include +#include #include "debug.h" #include "hif-ops.h" +#include "htc-ops.h" #include "cfg80211.h" unsigned int debug_mask; @@ -39,12 +41,36 @@ module_param(uart_debug, uint, 0644); module_param(ath6kl_p2p, uint, 0644); module_param(testmode, uint, 0644); -int ath6kl_core_init(struct ath6kl *ar) +void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb) +{ + ath6kl_htc_tx_complete(ar, skb); +} +EXPORT_SYMBOL(ath6kl_core_tx_complete); + +void ath6kl_core_rx_complete(struct ath6kl *ar, struct sk_buff *skb, u8 pipe) +{ + ath6kl_htc_rx_complete(ar, skb, pipe); +} +EXPORT_SYMBOL(ath6kl_core_rx_complete); + +int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) { struct ath6kl_bmi_target_info targ_info; struct net_device *ndev; int ret = 0, i; + switch (htc_type) { + case ATH6KL_HTC_TYPE_MBOX: + ath6kl_htc_mbox_attach(ar); + break; + case ATH6KL_HTC_TYPE_PIPE: + ath6kl_htc_pipe_attach(ar); + break; + default: + WARN_ON(1); + return -ENOMEM; + } + ar->ath6kl_wq = create_singlethread_workqueue("ath6kl"); if (!ar->ath6kl_wq) return -ENOMEM; @@ -280,7 +306,7 @@ void ath6kl_core_cleanup(struct ath6kl *ar) kfree(ar->fw_board); kfree(ar->fw_otp); - kfree(ar->fw); + vfree(ar->fw); kfree(ar->fw_patch); kfree(ar->fw_testscript); diff --git a/trunk/drivers/net/wireless/ath/ath6kl/core.h b/trunk/drivers/net/wireless/ath/ath6kl/core.h index f1dd8906be45..9d67964a51dd 100644 --- a/trunk/drivers/net/wireless/ath/ath6kl/core.h +++ b/trunk/drivers/net/wireless/ath/ath6kl/core.h @@ -91,6 +91,15 @@ enum ath6kl_fw_capability { */ ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, + /* + * Firmware has support to cleanup inactive stations + * in AP mode. + */ + ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT, + + /* Firmware has support to override rsn cap of rsn ie */ + ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE, + /* this needs to be last */ ATH6KL_FW_CAPABILITY_MAX, }; @@ -205,6 +214,8 @@ struct ath6kl_fw_ie { #define ATH6KL_CONF_ENABLE_TX_BURST BIT(3) #define ATH6KL_CONF_UART_DEBUG BIT(4) +#define P2P_WILDCARD_SSID_LEN 7 /* DIRECT- */ + enum wlan_low_pwr_state { WLAN_POWER_STATE_ON, WLAN_POWER_STATE_CUT_PWR, @@ -454,6 +465,11 @@ enum ath6kl_hif_type { ATH6KL_HIF_TYPE_USB, }; +enum ath6kl_htc_type { + ATH6KL_HTC_TYPE_MBOX, + ATH6KL_HTC_TYPE_PIPE, +}; + /* Max number of filters that hw supports */ #define ATH6K_MAX_MC_FILTERS_PER_LIST 7 struct ath6kl_mc_filter { @@ -461,6 +477,12 @@ struct ath6kl_mc_filter { char hw_addr[ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE]; }; +struct ath6kl_htcap { + bool ht_enable; + u8 ampdu_factor; + unsigned short cap_info; +}; + /* * Driver's maximum limit, note that some firmwares support only one vif * and the runtime (current) limit must be checked from ar->vif_max. @@ -509,6 +531,7 @@ struct ath6kl_vif { struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1]; struct ath6kl_key keys[WMI_MAX_KEY_INDEX + 1]; struct aggr_info *aggr_cntxt; + struct ath6kl_htcap htcap; struct timer_list disconnect_timer; struct timer_list sched_scan_timer; @@ -521,6 +544,8 @@ struct ath6kl_vif { u32 send_action_id; bool probe_req_report; u16 next_chan; + enum nl80211_channel_type next_ch_type; + enum ieee80211_band next_ch_band; u16 assoc_bss_beacon_int; u16 listen_intvl_t; u16 bmiss_time_t; @@ -568,6 +593,7 @@ struct ath6kl { struct ath6kl_bmi bmi; const struct ath6kl_hif_ops *hif_ops; + const struct ath6kl_htc_ops *htc_ops; struct wmi *wmi; int tx_pending[ENDPOINT_MAX]; int total_tx_data_pend; @@ -746,7 +772,8 @@ void init_netdev(struct net_device *dev); void ath6kl_cookie_init(struct ath6kl *ar); void ath6kl_cookie_cleanup(struct ath6kl *ar); void ath6kl_rx(struct htc_target *target, struct htc_packet *packet); -void ath6kl_tx_complete(void *context, struct list_head *packet_queue); +void ath6kl_tx_complete(struct htc_target *context, + struct list_head *packet_queue); enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, struct htc_packet *packet); void ath6kl_stop_txrx(struct ath6kl *ar); @@ -821,8 +848,11 @@ int ath6kl_init_hw_params(struct ath6kl *ar); void ath6kl_check_wow_status(struct ath6kl *ar); +void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb); +void ath6kl_core_rx_complete(struct ath6kl *ar, struct sk_buff *skb, u8 pipe); + struct ath6kl *ath6kl_core_create(struct device *dev); -int ath6kl_core_init(struct ath6kl *ar); +int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type); void ath6kl_core_cleanup(struct ath6kl *ar); void ath6kl_core_destroy(struct ath6kl *ar); diff --git a/trunk/drivers/net/wireless/ath/ath6kl/debug.c b/trunk/drivers/net/wireless/ath/ath6kl/debug.c index d01403a263ff..1b76aff78508 100644 --- a/trunk/drivers/net/wireless/ath/ath6kl/debug.c +++ b/trunk/drivers/net/wireless/ath/ath6kl/debug.c @@ -616,6 +616,12 @@ static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf, "Num disconnects", tgt_stats->cs_discon_cnt); len += scnprintf(buf + len, buf_len - len, "%20s %10d\n", "Beacon avg rssi", tgt_stats->cs_ave_beacon_rssi); + len += scnprintf(buf + len, buf_len - len, "%20s %10d\n", + "ARP pkt received", tgt_stats->arp_received); + len += scnprintf(buf + len, buf_len - len, "%20s %10d\n", + "ARP pkt matched", tgt_stats->arp_matched); + len += scnprintf(buf + len, buf_len - len, "%20s %10d\n", + "ARP pkt replied", tgt_stats->arp_replied); if (len > buf_len) len = buf_len; diff --git a/trunk/drivers/net/wireless/ath/ath6kl/debug.h b/trunk/drivers/net/wireless/ath/ath6kl/debug.h index 1803a0baae82..49639d8266c2 100644 --- a/trunk/drivers/net/wireless/ath/ath6kl/debug.h +++ b/trunk/drivers/net/wireless/ath/ath6kl/debug.h @@ -43,6 +43,7 @@ enum ATH6K_DEBUG_MASK { ATH6KL_DBG_WMI_DUMP = BIT(19), ATH6KL_DBG_SUSPEND = BIT(20), ATH6KL_DBG_USB = BIT(21), + ATH6KL_DBG_USB_BULK = BIT(22), ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */ }; diff --git a/trunk/drivers/net/wireless/ath/ath6kl/hif-ops.h b/trunk/drivers/net/wireless/ath/ath6kl/hif-ops.h index fd84086638e3..8c9e72d5250d 100644 --- a/trunk/drivers/net/wireless/ath/ath6kl/hif-ops.h +++ b/trunk/drivers/net/wireless/ath/ath6kl/hif-ops.h @@ -150,4 +150,38 @@ static inline void ath6kl_hif_stop(struct ath6kl *ar) ar->hif_ops->stop(ar); } +static inline int ath6kl_hif_pipe_send(struct ath6kl *ar, + u8 pipe, struct sk_buff *hdr_buf, + struct sk_buff *buf) +{ + ath6kl_dbg(ATH6KL_DBG_HIF, "hif pipe send\n"); + + return ar->hif_ops->pipe_send(ar, pipe, hdr_buf, buf); +} + +static inline void ath6kl_hif_pipe_get_default(struct ath6kl *ar, + u8 *ul_pipe, u8 *dl_pipe) +{ + ath6kl_dbg(ATH6KL_DBG_HIF, "hif pipe get default\n"); + + ar->hif_ops->pipe_get_default(ar, ul_pipe, dl_pipe); +} + +static inline int ath6kl_hif_pipe_map_service(struct ath6kl *ar, + u16 service_id, u8 *ul_pipe, + u8 *dl_pipe) +{ + ath6kl_dbg(ATH6KL_DBG_HIF, "hif pipe get default\n"); + + return ar->hif_ops->pipe_map_service(ar, service_id, ul_pipe, dl_pipe); +} + +static inline u16 ath6kl_hif_pipe_get_free_queue_number(struct ath6kl *ar, + u8 pipe) +{ + ath6kl_dbg(ATH6KL_DBG_HIF, "hif pipe get free queue number\n"); + + return ar->hif_ops->pipe_get_free_queue_number(ar, pipe); +} + #endif diff --git a/trunk/drivers/net/wireless/ath/ath6kl/hif.h b/trunk/drivers/net/wireless/ath/ath6kl/hif.h index 20ed6b73517b..61f6b21fb0ae 100644 --- a/trunk/drivers/net/wireless/ath/ath6kl/hif.h +++ b/trunk/drivers/net/wireless/ath/ath6kl/hif.h @@ -256,6 +256,12 @@ struct ath6kl_hif_ops { int (*power_on)(struct ath6kl *ar); int (*power_off)(struct ath6kl *ar); void (*stop)(struct ath6kl *ar); + int (*pipe_send)(struct ath6kl *ar, u8 pipe, struct sk_buff *hdr_buf, + struct sk_buff *buf); + void (*pipe_get_default)(struct ath6kl *ar, u8 *pipe_ul, u8 *pipe_dl); + int (*pipe_map_service)(struct ath6kl *ar, u16 service_id, u8 *pipe_ul, + u8 *pipe_dl); + u16 (*pipe_get_free_queue_number)(struct ath6kl *ar, u8 pipe); }; int ath6kl_hif_setup(struct ath6kl_device *dev); diff --git a/trunk/drivers/net/wireless/ath/ath6kl/htc-ops.h b/trunk/drivers/net/wireless/ath/ath6kl/htc-ops.h new file mode 100644 index 000000000000..2d4eed55cfd1 --- /dev/null +++ b/trunk/drivers/net/wireless/ath/ath6kl/htc-ops.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2004-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef HTC_OPS_H +#define HTC_OPS_H + +#include "htc.h" +#include "debug.h" + +static inline void *ath6kl_htc_create(struct ath6kl *ar) +{ + return ar->htc_ops->create(ar); +} + +static inline int ath6kl_htc_wait_target(struct htc_target *target) +{ + return target->dev->ar->htc_ops->wait_target(target); +} + +static inline int ath6kl_htc_start(struct htc_target *target) +{ + return target->dev->ar->htc_ops->start(target); +} + +static inline int ath6kl_htc_conn_service(struct htc_target *target, + struct htc_service_connect_req *req, + struct htc_service_connect_resp *resp) +{ + return target->dev->ar->htc_ops->conn_service(target, req, resp); +} + +static inline int ath6kl_htc_tx(struct htc_target *target, + struct htc_packet *packet) +{ + return target->dev->ar->htc_ops->tx(target, packet); +} + +static inline void ath6kl_htc_stop(struct htc_target *target) +{ + return target->dev->ar->htc_ops->stop(target); +} + +static inline void ath6kl_htc_cleanup(struct htc_target *target) +{ + return target->dev->ar->htc_ops->cleanup(target); +} + +static inline void ath6kl_htc_flush_txep(struct htc_target *target, + enum htc_endpoint_id endpoint, + u16 tag) +{ + return target->dev->ar->htc_ops->flush_txep(target, endpoint, tag); +} + +static inline void ath6kl_htc_flush_rx_buf(struct htc_target *target) +{ + return target->dev->ar->htc_ops->flush_rx_buf(target); +} + +static inline void ath6kl_htc_activity_changed(struct htc_target *target, + enum htc_endpoint_id endpoint, + bool active) +{ + return target->dev->ar->htc_ops->activity_changed(target, endpoint, + active); +} + +static inline int ath6kl_htc_get_rxbuf_num(struct htc_target *target, + enum htc_endpoint_id endpoint) +{ + return target->dev->ar->htc_ops->get_rxbuf_num(target, endpoint); +} + +static inline int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target, + struct list_head *pktq) +{ + return target->dev->ar->htc_ops->add_rxbuf_multiple(target, pktq); +} + +static inline int ath6kl_htc_credit_setup(struct htc_target *target, + struct ath6kl_htc_credit_info *info) +{ + return target->dev->ar->htc_ops->credit_setup(target, info); +} + +static inline void ath6kl_htc_tx_complete(struct ath6kl *ar, + struct sk_buff *skb) +{ + ar->htc_ops->tx_complete(ar, skb); +} + + +static inline void ath6kl_htc_rx_complete(struct ath6kl *ar, + struct sk_buff *skb, u8 pipe) +{ + ar->htc_ops->rx_complete(ar, skb, pipe); +} + + +#endif diff --git a/trunk/drivers/net/wireless/ath/ath6kl/htc.c b/trunk/drivers/net/wireless/ath/ath6kl/htc.c deleted file mode 100644 index 4849d99cce77..000000000000 --- a/trunk/drivers/net/wireless/ath/ath6kl/htc.c +++ /dev/null @@ -1,2890 +0,0 @@ -/* - * Copyright (c) 2007-2011 Atheros Communications Inc. - * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "core.h" -#include "hif.h" -#include "debug.h" -#include "hif-ops.h" -#include - -#define CALC_TXRX_PADDED_LEN(dev, len) (__ALIGN_MASK((len), (dev)->block_mask)) - -/* threshold to re-enable Tx bundling for an AC*/ -#define TX_RESUME_BUNDLE_THRESHOLD 1500 - -/* Functions for Tx credit handling */ -static void ath6kl_credit_deposit(struct ath6kl_htc_credit_info *cred_info, - struct htc_endpoint_credit_dist *ep_dist, - int credits) -{ - ath6kl_dbg(ATH6KL_DBG_CREDIT, "credit deposit ep %d credits %d\n", - ep_dist->endpoint, credits); - - ep_dist->credits += credits; - ep_dist->cred_assngd += credits; - cred_info->cur_free_credits -= credits; -} - -static void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_info, - struct list_head *ep_list, - int tot_credits) -{ - struct htc_endpoint_credit_dist *cur_ep_dist; - int count; - - ath6kl_dbg(ATH6KL_DBG_CREDIT, "credit init total %d\n", tot_credits); - - cred_info->cur_free_credits = tot_credits; - cred_info->total_avail_credits = tot_credits; - - list_for_each_entry(cur_ep_dist, ep_list, list) { - if (cur_ep_dist->endpoint == ENDPOINT_0) - continue; - - cur_ep_dist->cred_min = cur_ep_dist->cred_per_msg; - - if (tot_credits > 4) { - if ((cur_ep_dist->svc_id == WMI_DATA_BK_SVC) || - (cur_ep_dist->svc_id == WMI_DATA_BE_SVC)) { - ath6kl_credit_deposit(cred_info, - cur_ep_dist, - cur_ep_dist->cred_min); - cur_ep_dist->dist_flags |= HTC_EP_ACTIVE; - } - } - - if (cur_ep_dist->svc_id == WMI_CONTROL_SVC) { - ath6kl_credit_deposit(cred_info, cur_ep_dist, - cur_ep_dist->cred_min); - /* - * Control service is always marked active, it - * never goes inactive EVER. - */ - cur_ep_dist->dist_flags |= HTC_EP_ACTIVE; - } else if (cur_ep_dist->svc_id == WMI_DATA_BK_SVC) - /* this is the lowest priority data endpoint */ - /* FIXME: this looks fishy, check */ - cred_info->lowestpri_ep_dist = cur_ep_dist->list; - - /* - * Streams have to be created (explicit | implicit) for all - * kinds of traffic. BE endpoints are also inactive in the - * beginning. When BE traffic starts it creates implicit - * streams that redistributes credits. - * - * Note: all other endpoints have minimums set but are - * initially given NO credits. credits will be distributed - * as traffic activity demands - */ - } - - WARN_ON(cred_info->cur_free_credits <= 0); - - list_for_each_entry(cur_ep_dist, ep_list, list) { - if (cur_ep_dist->endpoint == ENDPOINT_0) - continue; - - if (cur_ep_dist->svc_id == WMI_CONTROL_SVC) - cur_ep_dist->cred_norm = cur_ep_dist->cred_per_msg; - else { - /* - * For the remaining data endpoints, we assume that - * each cred_per_msg are the same. We use a simple - * calculation here, we take the remaining credits - * and determine how many max messages this can - * cover and then set each endpoint's normal value - * equal to 3/4 this amount. - */ - count = (cred_info->cur_free_credits / - cur_ep_dist->cred_per_msg) - * cur_ep_dist->cred_per_msg; - count = (count * 3) >> 2; - count = max(count, cur_ep_dist->cred_per_msg); - cur_ep_dist->cred_norm = count; - - } - - ath6kl_dbg(ATH6KL_DBG_CREDIT, - "credit ep %d svc_id %d credits %d per_msg %d norm %d min %d\n", - cur_ep_dist->endpoint, - cur_ep_dist->svc_id, - cur_ep_dist->credits, - cur_ep_dist->cred_per_msg, - cur_ep_dist->cred_norm, - cur_ep_dist->cred_min); - } -} - -/* initialize and setup credit distribution */ -int ath6kl_credit_setup(void *htc_handle, - struct ath6kl_htc_credit_info *cred_info) -{ - u16 servicepriority[5]; - - memset(cred_info, 0, sizeof(struct ath6kl_htc_credit_info)); - - servicepriority[0] = WMI_CONTROL_SVC; /* highest */ - servicepriority[1] = WMI_DATA_VO_SVC; - servicepriority[2] = WMI_DATA_VI_SVC; - servicepriority[3] = WMI_DATA_BE_SVC; - servicepriority[4] = WMI_DATA_BK_SVC; /* lowest */ - - /* set priority list */ - ath6kl_htc_set_credit_dist(htc_handle, cred_info, servicepriority, 5); - - return 0; -} - -/* reduce an ep's credits back to a set limit */ -static void ath6kl_credit_reduce(struct ath6kl_htc_credit_info *cred_info, - struct htc_endpoint_credit_dist *ep_dist, - int limit) -{ - int credits; - - ath6kl_dbg(ATH6KL_DBG_CREDIT, "credit reduce ep %d limit %d\n", - ep_dist->endpoint, limit); - - ep_dist->cred_assngd = limit; - - if (ep_dist->credits <= limit) - return; - - credits = ep_dist->credits - limit; - ep_dist->credits -= credits; - cred_info->cur_free_credits += credits; -} - -static void ath6kl_credit_update(struct ath6kl_htc_credit_info *cred_info, - struct list_head *epdist_list) -{ - struct htc_endpoint_credit_dist *cur_list; - - list_for_each_entry(cur_list, epdist_list, list) { - if (cur_list->endpoint == ENDPOINT_0) - continue; - - if (cur_list->cred_to_dist > 0) { - cur_list->credits += cur_list->cred_to_dist; - cur_list->cred_to_dist = 0; - - if (cur_list->credits > cur_list->cred_assngd) - ath6kl_credit_reduce(cred_info, - cur_list, - cur_list->cred_assngd); - - if (cur_list->credits > cur_list->cred_norm) - ath6kl_credit_reduce(cred_info, cur_list, - cur_list->cred_norm); - - if (!(cur_list->dist_flags & HTC_EP_ACTIVE)) { - if (cur_list->txq_depth == 0) - ath6kl_credit_reduce(cred_info, - cur_list, 0); - } - } - } -} - -/* - * HTC has an endpoint that needs credits, ep_dist is the endpoint in - * question. - */ -static void ath6kl_credit_seek(struct ath6kl_htc_credit_info *cred_info, - struct htc_endpoint_credit_dist *ep_dist) -{ - struct htc_endpoint_credit_dist *curdist_list; - int credits = 0; - int need; - - if (ep_dist->svc_id == WMI_CONTROL_SVC) - goto out; - - if ((ep_dist->svc_id == WMI_DATA_VI_SVC) || - (ep_dist->svc_id == WMI_DATA_VO_SVC)) - if ((ep_dist->cred_assngd >= ep_dist->cred_norm)) - goto out; - - /* - * For all other services, we follow a simple algorithm of: - * - * 1. checking the free pool for credits - * 2. checking lower priority endpoints for credits to take - */ - - credits = min(cred_info->cur_free_credits, ep_dist->seek_cred); - - if (credits >= ep_dist->seek_cred) - goto out; - - /* - * We don't have enough in the free pool, try taking away from - * lower priority services The rule for taking away credits: - * - * 1. Only take from lower priority endpoints - * 2. Only take what is allocated above the minimum (never - * starve an endpoint completely) - * 3. Only take what you need. - */ - - list_for_each_entry_reverse(curdist_list, - &cred_info->lowestpri_ep_dist, - list) { - if (curdist_list == ep_dist) - break; - - need = ep_dist->seek_cred - cred_info->cur_free_credits; - - if ((curdist_list->cred_assngd - need) >= - curdist_list->cred_min) { - /* - * The current one has been allocated more than - * it's minimum and it has enough credits assigned - * above it's minimum to fulfill our need try to - * take away just enough to fulfill our need. - */ - ath6kl_credit_reduce(cred_info, curdist_list, - curdist_list->cred_assngd - need); - - if (cred_info->cur_free_credits >= - ep_dist->seek_cred) - break; - } - - if (curdist_list->endpoint == ENDPOINT_0) - break; - } - - credits = min(cred_info->cur_free_credits, ep_dist->seek_cred); - -out: - /* did we find some credits? */ - if (credits) - ath6kl_credit_deposit(cred_info, ep_dist, credits); - - ep_dist->seek_cred = 0; -} - -/* redistribute credits based on activity change */ -static void ath6kl_credit_redistribute(struct ath6kl_htc_credit_info *info, - struct list_head *ep_dist_list) -{ - struct htc_endpoint_credit_dist *curdist_list; - - list_for_each_entry(curdist_list, ep_dist_list, list) { - if (curdist_list->endpoint == ENDPOINT_0) - continue; - - if ((curdist_list->svc_id == WMI_DATA_BK_SVC) || - (curdist_list->svc_id == WMI_DATA_BE_SVC)) - curdist_list->dist_flags |= HTC_EP_ACTIVE; - - if ((curdist_list->svc_id != WMI_CONTROL_SVC) && - !(curdist_list->dist_flags & HTC_EP_ACTIVE)) { - if (curdist_list->txq_depth == 0) - ath6kl_credit_reduce(info, curdist_list, 0); - else - ath6kl_credit_reduce(info, - curdist_list, - curdist_list->cred_min); - } - } -} - -/* - * - * This function is invoked whenever endpoints require credit - * distributions. A lock is held while this function is invoked, this - * function shall NOT block. The ep_dist_list is a list of distribution - * structures in prioritized order as defined by the call to the - * htc_set_credit_dist() api. - */ -static void ath6kl_credit_distribute(struct ath6kl_htc_credit_info *cred_info, - struct list_head *ep_dist_list, - enum htc_credit_dist_reason reason) -{ - switch (reason) { - case HTC_CREDIT_DIST_SEND_COMPLETE: - ath6kl_credit_update(cred_info, ep_dist_list); - break; - case HTC_CREDIT_DIST_ACTIVITY_CHANGE: - ath6kl_credit_redistribute(cred_info, ep_dist_list); - break; - default: - break; - } - - WARN_ON(cred_info->cur_free_credits > cred_info->total_avail_credits); - WARN_ON(cred_info->cur_free_credits < 0); -} - -static void ath6kl_htc_tx_buf_align(u8 **buf, unsigned long len) -{ - u8 *align_addr; - - if (!IS_ALIGNED((unsigned long) *buf, 4)) { - align_addr = PTR_ALIGN(*buf - 4, 4); - memmove(align_addr, *buf, len); - *buf = align_addr; - } -} - -static void ath6kl_htc_tx_prep_pkt(struct htc_packet *packet, u8 flags, - int ctrl0, int ctrl1) -{ - struct htc_frame_hdr *hdr; - - packet->buf -= HTC_HDR_LENGTH; - hdr = (struct htc_frame_hdr *)packet->buf; - - /* Endianess? */ - put_unaligned((u16)packet->act_len, &hdr->payld_len); - hdr->flags = flags; - hdr->eid = packet->endpoint; - hdr->ctrl[0] = ctrl0; - hdr->ctrl[1] = ctrl1; -} - -static void htc_reclaim_txctrl_buf(struct htc_target *target, - struct htc_packet *pkt) -{ - spin_lock_bh(&target->htc_lock); - list_add_tail(&pkt->list, &target->free_ctrl_txbuf); - spin_unlock_bh(&target->htc_lock); -} - -static struct htc_packet *htc_get_control_buf(struct htc_target *target, - bool tx) -{ - struct htc_packet *packet = NULL; - struct list_head *buf_list; - - buf_list = tx ? &target->free_ctrl_txbuf : &target->free_ctrl_rxbuf; - - spin_lock_bh(&target->htc_lock); - - if (list_empty(buf_list)) { - spin_unlock_bh(&target->htc_lock); - return NULL; - } - - packet = list_first_entry(buf_list, struct htc_packet, list); - list_del(&packet->list); - spin_unlock_bh(&target->htc_lock); - - if (tx) - packet->buf = packet->buf_start + HTC_HDR_LENGTH; - - return packet; -} - -static void htc_tx_comp_update(struct htc_target *target, - struct htc_endpoint *endpoint, - struct htc_packet *packet) -{ - packet->completion = NULL; - packet->buf += HTC_HDR_LENGTH; - - if (!packet->status) - return; - - ath6kl_err("req failed (status:%d, ep:%d, len:%d creds:%d)\n", - packet->status, packet->endpoint, packet->act_len, - packet->info.tx.cred_used); - - /* on failure to submit, reclaim credits for this packet */ - spin_lock_bh(&target->tx_lock); - endpoint->cred_dist.cred_to_dist += - packet->info.tx.cred_used; - endpoint->cred_dist.txq_depth = get_queue_depth(&endpoint->txq); - - ath6kl_dbg(ATH6KL_DBG_HTC, "htc tx ctxt 0x%p dist 0x%p\n", - target->credit_info, &target->cred_dist_list); - - ath6kl_credit_distribute(target->credit_info, - &target->cred_dist_list, - HTC_CREDIT_DIST_SEND_COMPLETE); - - spin_unlock_bh(&target->tx_lock); -} - -static void htc_tx_complete(struct htc_endpoint *endpoint, - struct list_head *txq) -{ - if (list_empty(txq)) - return; - - ath6kl_dbg(ATH6KL_DBG_HTC, - "htc tx complete ep %d pkts %d\n", - endpoint->eid, get_queue_depth(txq)); - - ath6kl_tx_complete(endpoint->target->dev->ar, txq); -} - -static void htc_tx_comp_handler(struct htc_target *target, - struct htc_packet *packet) -{ - struct htc_endpoint *endpoint = &target->endpoint[packet->endpoint]; - struct list_head container; - - ath6kl_dbg(ATH6KL_DBG_HTC, "htc tx complete seqno %d\n", - packet->info.tx.seqno); - - htc_tx_comp_update(target, endpoint, packet); - INIT_LIST_HEAD(&container); - list_add_tail(&packet->list, &container); - /* do completion */ - htc_tx_complete(endpoint, &container); -} - -static void htc_async_tx_scat_complete(struct htc_target *target, - struct hif_scatter_req *scat_req) -{ - struct htc_endpoint *endpoint; - struct htc_packet *packet; - struct list_head tx_compq; - int i; - - INIT_LIST_HEAD(&tx_compq); - - ath6kl_dbg(ATH6KL_DBG_HTC, - "htc tx scat complete len %d entries %d\n", - scat_req->len, scat_req->scat_entries); - - if (scat_req->status) - ath6kl_err("send scatter req failed: %d\n", scat_req->status); - - packet = scat_req->scat_list[0].packet; - endpoint = &target->endpoint[packet->endpoint]; - - /* walk through the scatter list and process */ - for (i = 0; i < scat_req->scat_entries; i++) { - packet = scat_req->scat_list[i].packet; - if (!packet) { - WARN_ON(1); - return; - } - - packet->status = scat_req->status; - htc_tx_comp_update(target, endpoint, packet); - list_add_tail(&packet->list, &tx_compq); - } - - /* free scatter request */ - hif_scatter_req_add(target->dev->ar, scat_req); - - /* complete all packets */ - htc_tx_complete(endpoint, &tx_compq); -} - -static int ath6kl_htc_tx_issue(struct htc_target *target, - struct htc_packet *packet) -{ - int status; - bool sync = false; - u32 padded_len, send_len; - - if (!packet->completion) - sync = true; - - send_len = packet->act_len + HTC_HDR_LENGTH; - - padded_len = CALC_TXRX_PADDED_LEN(target, send_len); - - ath6kl_dbg(ATH6KL_DBG_HTC, - "htc tx issue len %d seqno %d padded_len %d mbox 0x%X %s\n", - send_len, packet->info.tx.seqno, padded_len, - target->dev->ar->mbox_info.htc_addr, - sync ? "sync" : "async"); - - if (sync) { - status = hif_read_write_sync(target->dev->ar, - target->dev->ar->mbox_info.htc_addr, - packet->buf, padded_len, - HIF_WR_SYNC_BLOCK_INC); - - packet->status = status; - packet->buf += HTC_HDR_LENGTH; - } else - status = hif_write_async(target->dev->ar, - target->dev->ar->mbox_info.htc_addr, - packet->buf, padded_len, - HIF_WR_ASYNC_BLOCK_INC, packet); - - return status; -} - -static int htc_check_credits(struct htc_target *target, - struct htc_endpoint *ep, u8 *flags, - 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; - - ath6kl_dbg(ATH6KL_DBG_CREDIT, "credit check need %d got %d\n", - *req_cred, ep->cred_dist.credits); - - if (ep->cred_dist.credits < *req_cred) { - if (eid == ENDPOINT_0) - return -EINVAL; - - /* Seek more credits */ - ep->cred_dist.seek_cred = *req_cred - ep->cred_dist.credits; - - ath6kl_credit_seek(target->credit_info, &ep->cred_dist); - - ep->cred_dist.seek_cred = 0; - - if (ep->cred_dist.credits < *req_cred) { - ath6kl_dbg(ATH6KL_DBG_CREDIT, - "credit not found for ep %d\n", - eid); - return -EINVAL; - } - } - - ep->cred_dist.credits -= *req_cred; - ep->ep_st.cred_cosumd += *req_cred; - - /* When we are getting low on credits, ask for more */ - if (ep->cred_dist.credits < ep->cred_dist.cred_per_msg) { - ep->cred_dist.seek_cred = - ep->cred_dist.cred_per_msg - ep->cred_dist.credits; - - ath6kl_credit_seek(target->credit_info, &ep->cred_dist); - - /* see if we were successful in getting more */ - if (ep->cred_dist.credits < ep->cred_dist.cred_per_msg) { - /* tell the target we need credits ASAP! */ - *flags |= HTC_FLAGS_NEED_CREDIT_UPDATE; - ep->ep_st.cred_low_indicate += 1; - ath6kl_dbg(ATH6KL_DBG_CREDIT, - "credit we need credits asap\n"); - } - } - - return 0; -} - -static void ath6kl_htc_tx_pkts_get(struct htc_target *target, - struct htc_endpoint *endpoint, - struct list_head *queue) -{ - int req_cred; - u8 flags; - struct htc_packet *packet; - unsigned int len; - - while (true) { - - flags = 0; - - if (list_empty(&endpoint->txq)) - break; - packet = list_first_entry(&endpoint->txq, struct htc_packet, - list); - - ath6kl_dbg(ATH6KL_DBG_HTC, - "htc tx got packet 0x%p queue depth %d\n", - packet, get_queue_depth(&endpoint->txq)); - - len = CALC_TXRX_PADDED_LEN(target, - packet->act_len + HTC_HDR_LENGTH); - - if (htc_check_credits(target, endpoint, &flags, - packet->endpoint, len, &req_cred)) - break; - - /* now we can fully move onto caller's queue */ - packet = list_first_entry(&endpoint->txq, struct htc_packet, - list); - list_move_tail(&packet->list, queue); - - /* save the number of credits this packet consumed */ - packet->info.tx.cred_used = req_cred; - - /* all TX packets are handled asynchronously */ - packet->completion = htc_tx_comp_handler; - packet->context = target; - endpoint->ep_st.tx_issued += 1; - - /* save send flags */ - packet->info.tx.flags = flags; - packet->info.tx.seqno = endpoint->seqno; - endpoint->seqno++; - } -} - -/* See if the padded tx length falls on a credit boundary */ -static int htc_get_credit_padding(unsigned int cred_sz, int *len, - struct htc_endpoint *ep) -{ - int rem_cred, cred_pad; - - rem_cred = *len % cred_sz; - - /* No padding needed */ - if (!rem_cred) - return 0; - - if (!(ep->conn_flags & HTC_FLGS_TX_BNDL_PAD_EN)) - return -1; - - /* - * The transfer consumes a "partial" credit, this - * packet cannot be bundled unless we add - * additional "dummy" padding (max 255 bytes) to - * consume the entire credit. - */ - cred_pad = *len < cred_sz ? (cred_sz - *len) : rem_cred; - - if ((cred_pad > 0) && (cred_pad <= 255)) - *len += cred_pad; - else - /* The amount of padding is too large, send as non-bundled */ - return -1; - - return cred_pad; -} - -static int ath6kl_htc_tx_setup_scat_list(struct htc_target *target, - struct htc_endpoint *endpoint, - struct hif_scatter_req *scat_req, - int n_scat, - struct list_head *queue) -{ - struct htc_packet *packet; - int i, len, rem_scat, cred_pad; - int status = 0; - u8 flags; - - rem_scat = target->max_tx_bndl_sz; - - for (i = 0; i < n_scat; i++) { - scat_req->scat_list[i].packet = NULL; - - if (list_empty(queue)) - break; - - packet = list_first_entry(queue, struct htc_packet, list); - len = CALC_TXRX_PADDED_LEN(target, - packet->act_len + HTC_HDR_LENGTH); - - cred_pad = htc_get_credit_padding(target->tgt_cred_sz, - &len, endpoint); - if (cred_pad < 0 || rem_scat < len) { - status = -ENOSPC; - break; - } - - rem_scat -= len; - /* now remove it from the queue */ - list_del(&packet->list); - - scat_req->scat_list[i].packet = packet; - /* prepare packet and flag message as part of a send bundle */ - flags = packet->info.tx.flags | HTC_FLAGS_SEND_BUNDLE; - ath6kl_htc_tx_prep_pkt(packet, flags, - cred_pad, packet->info.tx.seqno); - /* Make sure the buffer is 4-byte aligned */ - ath6kl_htc_tx_buf_align(&packet->buf, - packet->act_len + HTC_HDR_LENGTH); - scat_req->scat_list[i].buf = packet->buf; - scat_req->scat_list[i].len = len; - - scat_req->len += len; - scat_req->scat_entries++; - ath6kl_dbg(ATH6KL_DBG_HTC, - "htc tx adding (%d) pkt 0x%p seqno %d len %d remaining %d\n", - i, packet, packet->info.tx.seqno, len, rem_scat); - } - - /* Roll back scatter setup in case of any failure */ - if (scat_req->scat_entries < HTC_MIN_HTC_MSGS_TO_BUNDLE) { - for (i = scat_req->scat_entries - 1; i >= 0; i--) { - packet = scat_req->scat_list[i].packet; - if (packet) { - packet->buf += HTC_HDR_LENGTH; - list_add(&packet->list, queue); - } - } - return -EAGAIN; - } - - return status; -} - -/* - * Drain a queue and send as bundles this function may return without fully - * draining the queue when - * - * 1. scatter resources are exhausted - * 2. a message that will consume a partial credit will stop the - * bundling process early - * 3. we drop below the minimum number of messages for a bundle - */ -static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint, - struct list_head *queue, - int *sent_bundle, int *n_bundle_pkts) -{ - struct htc_target *target = endpoint->target; - struct hif_scatter_req *scat_req = NULL; - int n_scat, n_sent_bundle = 0, tot_pkts_bundle = 0; - int status; - u32 txb_mask; - u8 ac = WMM_NUM_AC; - - if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) || - (WMI_CONTROL_SVC != endpoint->svc_id)) - ac = target->dev->ar->ep2ac_map[endpoint->eid]; - - while (true) { - status = 0; - n_scat = get_queue_depth(queue); - n_scat = min(n_scat, target->msg_per_bndl_max); - - if (n_scat < HTC_MIN_HTC_MSGS_TO_BUNDLE) - /* not enough to bundle */ - break; - - scat_req = hif_scatter_req_get(target->dev->ar); - - if (!scat_req) { - /* no scatter resources */ - ath6kl_dbg(ATH6KL_DBG_HTC, - "htc tx no more scatter resources\n"); - break; - } - - if ((ac < WMM_NUM_AC) && (ac != WMM_AC_BK)) { - if (WMM_AC_BE == ac) - /* - * BE, BK have priorities and bit - * positions reversed - */ - txb_mask = (1 << WMM_AC_BK); - else - /* - * any AC with priority lower than - * itself - */ - txb_mask = ((1 << ac) - 1); - /* - * when the scatter request resources drop below a - * certain threshold, disable Tx bundling for all - * AC's with priority lower than the current requesting - * AC. Otherwise re-enable Tx bundling for them - */ - if (scat_req->scat_q_depth < ATH6KL_SCATTER_REQS) - target->tx_bndl_mask &= ~txb_mask; - else - target->tx_bndl_mask |= txb_mask; - } - - ath6kl_dbg(ATH6KL_DBG_HTC, "htc tx pkts to scatter: %d\n", - n_scat); - - scat_req->len = 0; - scat_req->scat_entries = 0; - - status = ath6kl_htc_tx_setup_scat_list(target, endpoint, - scat_req, n_scat, - queue); - if (status == -EAGAIN) { - hif_scatter_req_add(target->dev->ar, scat_req); - break; - } - - /* send path is always asynchronous */ - scat_req->complete = htc_async_tx_scat_complete; - n_sent_bundle++; - tot_pkts_bundle += scat_req->scat_entries; - - ath6kl_dbg(ATH6KL_DBG_HTC, - "htc tx scatter bytes %d entries %d\n", - scat_req->len, scat_req->scat_entries); - ath6kl_hif_submit_scat_req(target->dev, scat_req, false); - - if (status) - break; - } - - *sent_bundle = n_sent_bundle; - *n_bundle_pkts = tot_pkts_bundle; - ath6kl_dbg(ATH6KL_DBG_HTC, "htc tx bundle sent %d pkts\n", - n_sent_bundle); - - return; -} - -static void ath6kl_htc_tx_from_queue(struct htc_target *target, - struct htc_endpoint *endpoint) -{ - struct list_head txq; - struct htc_packet *packet; - int bundle_sent; - int n_pkts_bundle; - u8 ac = WMM_NUM_AC; - - spin_lock_bh(&target->tx_lock); - - endpoint->tx_proc_cnt++; - if (endpoint->tx_proc_cnt > 1) { - endpoint->tx_proc_cnt--; - spin_unlock_bh(&target->tx_lock); - ath6kl_dbg(ATH6KL_DBG_HTC, "htc tx busy\n"); - return; - } - - /* - * drain the endpoint TX queue for transmission as long - * as we have enough credits. - */ - INIT_LIST_HEAD(&txq); - - if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) || - (WMI_CONTROL_SVC != endpoint->svc_id)) - ac = target->dev->ar->ep2ac_map[endpoint->eid]; - - while (true) { - - if (list_empty(&endpoint->txq)) - break; - - ath6kl_htc_tx_pkts_get(target, endpoint, &txq); - - if (list_empty(&txq)) - break; - - spin_unlock_bh(&target->tx_lock); - - bundle_sent = 0; - n_pkts_bundle = 0; - - while (true) { - /* try to send a bundle on each pass */ - if ((target->tx_bndl_mask) && - (get_queue_depth(&txq) >= - HTC_MIN_HTC_MSGS_TO_BUNDLE)) { - int temp1 = 0, temp2 = 0; - - /* check if bundling is enabled for an AC */ - if (target->tx_bndl_mask & (1 << ac)) { - ath6kl_htc_tx_bundle(endpoint, &txq, - &temp1, &temp2); - bundle_sent += temp1; - n_pkts_bundle += temp2; - } - } - - if (list_empty(&txq)) - break; - - packet = list_first_entry(&txq, struct htc_packet, - list); - list_del(&packet->list); - - ath6kl_htc_tx_prep_pkt(packet, packet->info.tx.flags, - 0, packet->info.tx.seqno); - ath6kl_htc_tx_issue(target, packet); - } - - spin_lock_bh(&target->tx_lock); - - endpoint->ep_st.tx_bundles += bundle_sent; - endpoint->ep_st.tx_pkt_bundled += n_pkts_bundle; - - /* - * if an AC has bundling disabled and no tx bundling - * has occured continously for a certain number of TX, - * enable tx bundling for this AC - */ - if (!bundle_sent) { - if (!(target->tx_bndl_mask & (1 << ac)) && - (ac < WMM_NUM_AC)) { - if (++target->ac_tx_count[ac] >= - TX_RESUME_BUNDLE_THRESHOLD) { - target->ac_tx_count[ac] = 0; - target->tx_bndl_mask |= (1 << ac); - } - } - } else { - /* tx bundling will reset the counter */ - if (ac < WMM_NUM_AC) - target->ac_tx_count[ac] = 0; - } - } - - endpoint->tx_proc_cnt = 0; - spin_unlock_bh(&target->tx_lock); -} - -static bool ath6kl_htc_tx_try(struct htc_target *target, - struct htc_endpoint *endpoint, - struct htc_packet *tx_pkt) -{ - struct htc_ep_callbacks ep_cb; - int txq_depth; - bool overflow = false; - - ep_cb = endpoint->ep_cb; - - spin_lock_bh(&target->tx_lock); - txq_depth = get_queue_depth(&endpoint->txq); - spin_unlock_bh(&target->tx_lock); - - if (txq_depth >= endpoint->max_txq_depth) - overflow = true; - - if (overflow) - ath6kl_dbg(ATH6KL_DBG_HTC, - "htc tx overflow ep %d depth %d max %d\n", - endpoint->eid, txq_depth, - endpoint->max_txq_depth); - - if (overflow && ep_cb.tx_full) { - if (ep_cb.tx_full(endpoint->target, tx_pkt) == - HTC_SEND_FULL_DROP) { - endpoint->ep_st.tx_dropped += 1; - return false; - } - } - - spin_lock_bh(&target->tx_lock); - list_add_tail(&tx_pkt->list, &endpoint->txq); - spin_unlock_bh(&target->tx_lock); - - ath6kl_htc_tx_from_queue(target, endpoint); - - return true; -} - -static void htc_chk_ep_txq(struct htc_target *target) -{ - struct htc_endpoint *endpoint; - struct htc_endpoint_credit_dist *cred_dist; - - /* - * Run through the credit distribution list to see if there are - * packets queued. NOTE: no locks need to be taken since the - * distribution list is not dynamic (cannot be re-ordered) and we - * are not modifying any state. - */ - list_for_each_entry(cred_dist, &target->cred_dist_list, list) { - endpoint = cred_dist->htc_ep; - - spin_lock_bh(&target->tx_lock); - if (!list_empty(&endpoint->txq)) { - ath6kl_dbg(ATH6KL_DBG_HTC, - "htc creds ep %d credits %d pkts %d\n", - cred_dist->endpoint, - endpoint->cred_dist.credits, - get_queue_depth(&endpoint->txq)); - spin_unlock_bh(&target->tx_lock); - /* - * Try to start the stalled queue, this list is - * ordered by priority. If there are credits - * available the highest priority queue will get a - * chance to reclaim credits from lower priority - * ones. - */ - ath6kl_htc_tx_from_queue(target, endpoint); - spin_lock_bh(&target->tx_lock); - } - spin_unlock_bh(&target->tx_lock); - } -} - -static int htc_setup_tx_complete(struct htc_target *target) -{ - struct htc_packet *send_pkt = NULL; - int status; - - send_pkt = htc_get_control_buf(target, true); - - if (!send_pkt) - return -ENOMEM; - - if (target->htc_tgt_ver >= HTC_VERSION_2P1) { - struct htc_setup_comp_ext_msg *setup_comp_ext; - u32 flags = 0; - - setup_comp_ext = - (struct htc_setup_comp_ext_msg *)send_pkt->buf; - memset(setup_comp_ext, 0, sizeof(*setup_comp_ext)); - setup_comp_ext->msg_id = - cpu_to_le16(HTC_MSG_SETUP_COMPLETE_EX_ID); - - if (target->msg_per_bndl_max > 0) { - /* Indicate HTC bundling to the target */ - flags |= HTC_SETUP_COMP_FLG_RX_BNDL_EN; - setup_comp_ext->msg_per_rxbndl = - target->msg_per_bndl_max; - } - - memcpy(&setup_comp_ext->flags, &flags, - sizeof(setup_comp_ext->flags)); - set_htc_pkt_info(send_pkt, NULL, (u8 *) setup_comp_ext, - sizeof(struct htc_setup_comp_ext_msg), - ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); - - } else { - struct htc_setup_comp_msg *setup_comp; - setup_comp = (struct htc_setup_comp_msg *)send_pkt->buf; - memset(setup_comp, 0, sizeof(struct htc_setup_comp_msg)); - setup_comp->msg_id = cpu_to_le16(HTC_MSG_SETUP_COMPLETE_ID); - set_htc_pkt_info(send_pkt, NULL, (u8 *) setup_comp, - sizeof(struct htc_setup_comp_msg), - ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); - } - - /* we want synchronous operation */ - send_pkt->completion = NULL; - ath6kl_htc_tx_prep_pkt(send_pkt, 0, 0, 0); - status = ath6kl_htc_tx_issue(target, send_pkt); - - if (send_pkt != NULL) - htc_reclaim_txctrl_buf(target, send_pkt); - - return status; -} - -void ath6kl_htc_set_credit_dist(struct htc_target *target, - struct ath6kl_htc_credit_info *credit_info, - u16 srvc_pri_order[], int list_len) -{ - struct htc_endpoint *endpoint; - int i, ep; - - target->credit_info = credit_info; - - list_add_tail(&target->endpoint[ENDPOINT_0].cred_dist.list, - &target->cred_dist_list); - - for (i = 0; i < list_len; i++) { - for (ep = ENDPOINT_1; ep < ENDPOINT_MAX; ep++) { - endpoint = &target->endpoint[ep]; - if (endpoint->svc_id == srvc_pri_order[i]) { - list_add_tail(&endpoint->cred_dist.list, - &target->cred_dist_list); - break; - } - } - if (ep >= ENDPOINT_MAX) { - WARN_ON(1); - return; - } - } -} - -int ath6kl_htc_tx(struct htc_target *target, struct htc_packet *packet) -{ - struct htc_endpoint *endpoint; - struct list_head queue; - - ath6kl_dbg(ATH6KL_DBG_HTC, - "htc tx ep id %d buf 0x%p len %d\n", - packet->endpoint, packet->buf, packet->act_len); - - if (packet->endpoint >= ENDPOINT_MAX) { - WARN_ON(1); - return -EINVAL; - } - - endpoint = &target->endpoint[packet->endpoint]; - - if (!ath6kl_htc_tx_try(target, endpoint, packet)) { - packet->status = (target->htc_flags & HTC_OP_STATE_STOPPING) ? - -ECANCELED : -ENOSPC; - INIT_LIST_HEAD(&queue); - list_add(&packet->list, &queue); - htc_tx_complete(endpoint, &queue); - } - - return 0; -} - -/* flush endpoint TX queue */ -void ath6kl_htc_flush_txep(struct htc_target *target, - enum htc_endpoint_id eid, u16 tag) -{ - struct htc_packet *packet, *tmp_pkt; - struct list_head discard_q, container; - struct htc_endpoint *endpoint = &target->endpoint[eid]; - - if (!endpoint->svc_id) { - WARN_ON(1); - return; - } - - /* initialize the discard queue */ - INIT_LIST_HEAD(&discard_q); - - spin_lock_bh(&target->tx_lock); - - list_for_each_entry_safe(packet, tmp_pkt, &endpoint->txq, list) { - if ((tag == HTC_TX_PACKET_TAG_ALL) || - (tag == packet->info.tx.tag)) - list_move_tail(&packet->list, &discard_q); - } - - spin_unlock_bh(&target->tx_lock); - - list_for_each_entry_safe(packet, tmp_pkt, &discard_q, list) { - packet->status = -ECANCELED; - list_del(&packet->list); - ath6kl_dbg(ATH6KL_DBG_HTC, - "htc tx flushing pkt 0x%p len %d ep %d tag 0x%x\n", - packet, packet->act_len, - packet->endpoint, packet->info.tx.tag); - - INIT_LIST_HEAD(&container); - list_add_tail(&packet->list, &container); - htc_tx_complete(endpoint, &container); - } - -} - -static void ath6kl_htc_flush_txep_all(struct htc_target *target) -{ - struct htc_endpoint *endpoint; - int i; - - dump_cred_dist_stats(target); - - for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) { - endpoint = &target->endpoint[i]; - if (endpoint->svc_id == 0) - /* not in use.. */ - continue; - ath6kl_htc_flush_txep(target, i, HTC_TX_PACKET_TAG_ALL); - } -} - -void ath6kl_htc_indicate_activity_change(struct htc_target *target, - enum htc_endpoint_id eid, bool active) -{ - struct htc_endpoint *endpoint = &target->endpoint[eid]; - bool dist = false; - - if (endpoint->svc_id == 0) { - WARN_ON(1); - return; - } - - spin_lock_bh(&target->tx_lock); - - if (active) { - if (!(endpoint->cred_dist.dist_flags & HTC_EP_ACTIVE)) { - endpoint->cred_dist.dist_flags |= HTC_EP_ACTIVE; - dist = true; - } - } else { - if (endpoint->cred_dist.dist_flags & HTC_EP_ACTIVE) { - endpoint->cred_dist.dist_flags &= ~HTC_EP_ACTIVE; - dist = true; - } - } - - if (dist) { - endpoint->cred_dist.txq_depth = - get_queue_depth(&endpoint->txq); - - ath6kl_dbg(ATH6KL_DBG_HTC, - "htc tx activity ctxt 0x%p dist 0x%p\n", - target->credit_info, &target->cred_dist_list); - - ath6kl_credit_distribute(target->credit_info, - &target->cred_dist_list, - HTC_CREDIT_DIST_ACTIVITY_CHANGE); - } - - spin_unlock_bh(&target->tx_lock); - - if (dist && !active) - htc_chk_ep_txq(target); -} - -/* HTC Rx */ - -static inline void ath6kl_htc_rx_update_stats(struct htc_endpoint *endpoint, - int n_look_ahds) -{ - endpoint->ep_st.rx_pkts++; - if (n_look_ahds == 1) - endpoint->ep_st.rx_lkahds++; - else if (n_look_ahds > 1) - endpoint->ep_st.rx_bundle_lkahd++; -} - -static inline bool htc_valid_rx_frame_len(struct htc_target *target, - enum htc_endpoint_id eid, int len) -{ - return (eid == target->dev->ar->ctrl_ep) ? - len <= ATH6KL_BUFFER_SIZE : len <= ATH6KL_AMSDU_BUFFER_SIZE; -} - -static int htc_add_rxbuf(struct htc_target *target, struct htc_packet *packet) -{ - struct list_head queue; - - INIT_LIST_HEAD(&queue); - list_add_tail(&packet->list, &queue); - return ath6kl_htc_add_rxbuf_multiple(target, &queue); -} - -static void htc_reclaim_rxbuf(struct htc_target *target, - struct htc_packet *packet, - struct htc_endpoint *ep) -{ - if (packet->info.rx.rx_flags & HTC_RX_PKT_NO_RECYCLE) { - htc_rxpkt_reset(packet); - packet->status = -ECANCELED; - ep->ep_cb.rx(ep->target, packet); - } else { - htc_rxpkt_reset(packet); - htc_add_rxbuf((void *)(target), packet); - } -} - -static void reclaim_rx_ctrl_buf(struct htc_target *target, - struct htc_packet *packet) -{ - spin_lock_bh(&target->htc_lock); - list_add_tail(&packet->list, &target->free_ctrl_rxbuf); - spin_unlock_bh(&target->htc_lock); -} - -static int ath6kl_htc_rx_packet(struct htc_target *target, - struct htc_packet *packet, - u32 rx_len) -{ - struct ath6kl_device *dev = target->dev; - u32 padded_len; - int status; - - padded_len = CALC_TXRX_PADDED_LEN(target, rx_len); - - if (padded_len > packet->buf_len) { - ath6kl_err("not enough receive space for packet - padlen %d recvlen %d bufferlen %d\n", - padded_len, rx_len, packet->buf_len); - return -ENOMEM; - } - - ath6kl_dbg(ATH6KL_DBG_HTC, - "htc rx 0x%p hdr x%x len %d mbox 0x%x\n", - packet, packet->info.rx.exp_hdr, - padded_len, dev->ar->mbox_info.htc_addr); - - status = hif_read_write_sync(dev->ar, - dev->ar->mbox_info.htc_addr, - packet->buf, padded_len, - HIF_RD_SYNC_BLOCK_FIX); - - packet->status = status; - - return status; -} - -/* - * optimization for recv packets, we can indicate a - * "hint" that there are more single-packets to fetch - * on this endpoint. - */ -static void ath6kl_htc_rx_set_indicate(u32 lk_ahd, - struct htc_endpoint *endpoint, - struct htc_packet *packet) -{ - struct htc_frame_hdr *htc_hdr = (struct htc_frame_hdr *)&lk_ahd; - - if (htc_hdr->eid == packet->endpoint) { - if (!list_empty(&endpoint->rx_bufq)) - packet->info.rx.indicat_flags |= - HTC_RX_FLAGS_INDICATE_MORE_PKTS; - } -} - -static void ath6kl_htc_rx_chk_water_mark(struct htc_endpoint *endpoint) -{ - struct htc_ep_callbacks ep_cb = endpoint->ep_cb; - - if (ep_cb.rx_refill_thresh > 0) { - spin_lock_bh(&endpoint->target->rx_lock); - if (get_queue_depth(&endpoint->rx_bufq) - < ep_cb.rx_refill_thresh) { - spin_unlock_bh(&endpoint->target->rx_lock); - ep_cb.rx_refill(endpoint->target, endpoint->eid); - return; - } - spin_unlock_bh(&endpoint->target->rx_lock); - } -} - -/* This function is called with rx_lock held */ -static int ath6kl_htc_rx_setup(struct htc_target *target, - struct htc_endpoint *ep, - u32 *lk_ahds, struct list_head *queue, int n_msg) -{ - struct htc_packet *packet; - /* FIXME: type of lk_ahds can't be right */ - struct htc_frame_hdr *htc_hdr = (struct htc_frame_hdr *)lk_ahds; - struct htc_ep_callbacks ep_cb; - int status = 0, j, full_len; - bool no_recycle; - - full_len = CALC_TXRX_PADDED_LEN(target, - le16_to_cpu(htc_hdr->payld_len) + - sizeof(*htc_hdr)); - - if (!htc_valid_rx_frame_len(target, ep->eid, full_len)) { - ath6kl_warn("Rx buffer requested with invalid length\n"); - return -EINVAL; - } - - 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 - * cleanup,they must be explicitly returned. - */ - no_recycle = false; - - if (ep_cb.rx_allocthresh && - (full_len > ep_cb.rx_alloc_thresh)) { - ep->ep_st.rx_alloc_thresh_hit += 1; - ep->ep_st.rxalloc_thresh_byte += - le16_to_cpu(htc_hdr->payld_len); - - spin_unlock_bh(&target->rx_lock); - no_recycle = true; - - packet = ep_cb.rx_allocthresh(ep->target, ep->eid, - full_len); - spin_lock_bh(&target->rx_lock); - } else { - /* refill handler is being used */ - if (list_empty(&ep->rx_bufq)) { - if (ep_cb.rx_refill) { - spin_unlock_bh(&target->rx_lock); - ep_cb.rx_refill(ep->target, ep->eid); - spin_lock_bh(&target->rx_lock); - } - } - - if (list_empty(&ep->rx_bufq)) - packet = NULL; - else { - packet = list_first_entry(&ep->rx_bufq, - struct htc_packet, list); - list_del(&packet->list); - } - } - - if (!packet) { - target->rx_st_flags |= HTC_RECV_WAIT_BUFFERS; - target->ep_waiting = ep->eid; - return -ENOSPC; - } - - /* clear flags */ - packet->info.rx.rx_flags = 0; - packet->info.rx.indicat_flags = 0; - packet->status = 0; - - if (no_recycle) - /* - * flag that these packets cannot be - * recycled, they have to be returned to - * the user - */ - packet->info.rx.rx_flags |= HTC_RX_PKT_NO_RECYCLE; - - /* Caller needs to free this upon any failure */ - list_add_tail(&packet->list, queue); - - if (target->htc_flags & HTC_OP_STATE_STOPPING) { - status = -ECANCELED; - break; - } - - if (j) { - packet->info.rx.rx_flags |= HTC_RX_PKT_REFRESH_HDR; - packet->info.rx.exp_hdr = 0xFFFFFFFF; - } else - /* set expected look ahead */ - packet->info.rx.exp_hdr = *lk_ahds; - - packet->act_len = le16_to_cpu(htc_hdr->payld_len) + - HTC_HDR_LENGTH; - } - - return status; -} - -static int ath6kl_htc_rx_alloc(struct htc_target *target, - u32 lk_ahds[], int msg, - struct htc_endpoint *endpoint, - struct list_head *queue) -{ - int status = 0; - struct htc_packet *packet, *tmp_pkt; - struct htc_frame_hdr *htc_hdr; - int i, n_msg; - - 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) { - ath6kl_err("invalid ep in look-ahead: %d\n", - htc_hdr->eid); - status = -ENOMEM; - break; - } - - if (htc_hdr->eid != endpoint->eid) { - ath6kl_err("invalid ep in look-ahead: %d should be : %d (index:%d)\n", - htc_hdr->eid, endpoint->eid, i); - status = -ENOMEM; - break; - } - - if (le16_to_cpu(htc_hdr->payld_len) > HTC_MAX_PAYLOAD_LENGTH) { - ath6kl_err("payload len %d exceeds max htc : %d !\n", - htc_hdr->payld_len, - (u32) HTC_MAX_PAYLOAD_LENGTH); - status = -ENOMEM; - break; - } - - if (endpoint->svc_id == 0) { - ath6kl_err("ep %d is not connected !\n", htc_hdr->eid); - status = -ENOMEM; - break; - } - - if (htc_hdr->flags & HTC_FLG_RX_BNDL_CNT) { - /* - * HTC header indicates that every packet to follow - * has the same padded length so that it can be - * optimally fetched as a full bundle. - */ - n_msg = (htc_hdr->flags & HTC_FLG_RX_BNDL_CNT) >> - HTC_FLG_RX_BNDL_CNT_S; - - /* the count doesn't include the starter frame */ - n_msg++; - if (n_msg > target->msg_per_bndl_max) { - status = -ENOMEM; - break; - } - - endpoint->ep_st.rx_bundle_from_hdr += 1; - ath6kl_dbg(ATH6KL_DBG_HTC, - "htc rx bundle pkts %d\n", - n_msg); - } else - /* HTC header only indicates 1 message to fetch */ - n_msg = 1; - - /* Setup packet buffers for each message */ - status = ath6kl_htc_rx_setup(target, endpoint, &lk_ahds[i], - queue, n_msg); - - /* - * This is due to unavailabilty of buffers to rx entire data. - * Return no error so that free buffers from queue can be used - * to receive partial data. - */ - if (status == -ENOSPC) { - spin_unlock_bh(&target->rx_lock); - return 0; - } - - if (status) - break; - } - - spin_unlock_bh(&target->rx_lock); - - if (status) { - list_for_each_entry_safe(packet, tmp_pkt, queue, list) { - list_del(&packet->list); - htc_reclaim_rxbuf(target, packet, - &target->endpoint[packet->endpoint]); - } - } - - return status; -} - -static void htc_ctrl_rx(struct htc_target *context, struct htc_packet *packets) -{ - if (packets->endpoint != ENDPOINT_0) { - WARN_ON(1); - return; - } - - if (packets->status == -ECANCELED) { - reclaim_rx_ctrl_buf(context, packets); - return; - } - - if (packets->act_len > 0) { - ath6kl_err("htc_ctrl_rx, got message with len:%zu\n", - packets->act_len + HTC_HDR_LENGTH); - - ath6kl_dbg_dump(ATH6KL_DBG_HTC, - "htc rx unexpected endpoint 0 message", "", - packets->buf - HTC_HDR_LENGTH, - packets->act_len + HTC_HDR_LENGTH); - } - - htc_reclaim_rxbuf(context, packets, &context->endpoint[0]); -} - -static void htc_proc_cred_rpt(struct htc_target *target, - struct htc_credit_report *rpt, - int n_entries, - enum htc_endpoint_id from_ep) -{ - struct htc_endpoint *endpoint; - int tot_credits = 0, i; - bool dist = false; - - spin_lock_bh(&target->tx_lock); - - for (i = 0; i < n_entries; i++, rpt++) { - if (rpt->eid >= ENDPOINT_MAX) { - WARN_ON(1); - spin_unlock_bh(&target->tx_lock); - return; - } - - endpoint = &target->endpoint[rpt->eid]; - - ath6kl_dbg(ATH6KL_DBG_CREDIT, - "credit report ep %d credits %d\n", - rpt->eid, rpt->credits); - - endpoint->ep_st.tx_cred_rpt += 1; - endpoint->ep_st.cred_retnd += rpt->credits; - - if (from_ep == rpt->eid) { - /* - * This credit report arrived on the same endpoint - * indicating it arrived in an RX packet. - */ - endpoint->ep_st.cred_from_rx += rpt->credits; - endpoint->ep_st.cred_rpt_from_rx += 1; - } else if (from_ep == ENDPOINT_0) { - /* credit arrived on endpoint 0 as a NULL message */ - endpoint->ep_st.cred_from_ep0 += rpt->credits; - endpoint->ep_st.cred_rpt_ep0 += 1; - } else { - endpoint->ep_st.cred_from_other += rpt->credits; - endpoint->ep_st.cred_rpt_from_other += 1; - } - - if (rpt->eid == ENDPOINT_0) - /* always give endpoint 0 credits back */ - endpoint->cred_dist.credits += rpt->credits; - else { - endpoint->cred_dist.cred_to_dist += rpt->credits; - dist = true; - } - - /* - * Refresh tx depth for distribution function that will - * recover these credits NOTE: this is only valid when - * there are credits to recover! - */ - endpoint->cred_dist.txq_depth = - get_queue_depth(&endpoint->txq); - - tot_credits += rpt->credits; - } - - if (dist) { - /* - * This was a credit return based on a completed send - * operations note, this is done with the lock held - */ - ath6kl_credit_distribute(target->credit_info, - &target->cred_dist_list, - HTC_CREDIT_DIST_SEND_COMPLETE); - } - - spin_unlock_bh(&target->tx_lock); - - if (tot_credits) - htc_chk_ep_txq(target); -} - -static int htc_parse_trailer(struct htc_target *target, - struct htc_record_hdr *record, - u8 *record_buf, u32 *next_lk_ahds, - enum htc_endpoint_id endpoint, - int *n_lk_ahds) -{ - struct htc_bundle_lkahd_rpt *bundle_lkahd_rpt; - struct htc_lookahead_report *lk_ahd; - int len; - - switch (record->rec_id) { - case HTC_RECORD_CREDITS: - len = record->len / sizeof(struct htc_credit_report); - if (!len) { - WARN_ON(1); - return -EINVAL; - } - - htc_proc_cred_rpt(target, - (struct htc_credit_report *) record_buf, - len, endpoint); - break; - case HTC_RECORD_LOOKAHEAD: - len = record->len / sizeof(*lk_ahd); - if (!len) { - WARN_ON(1); - return -EINVAL; - } - - 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); - - /* look ahead bytes are valid, copy them over */ - memcpy((u8 *)&next_lk_ahds[0], lk_ahd->lk_ahd, 4); - - ath6kl_dbg_dump(ATH6KL_DBG_HTC, - "htc rx next look ahead", - "", next_lk_ahds, 4); - - *n_lk_ahds = 1; - } - break; - case HTC_RECORD_LOOKAHEAD_BUNDLE: - len = record->len / sizeof(*bundle_lkahd_rpt); - if (!len || (len > HTC_HOST_MAX_MSG_PER_BUNDLE)) { - WARN_ON(1); - return -EINVAL; - } - - if (next_lk_ahds) { - int i; - - bundle_lkahd_rpt = - (struct htc_bundle_lkahd_rpt *) record_buf; - - ath6kl_dbg_dump(ATH6KL_DBG_HTC, "htc rx bundle lk_ahd", - "", record_buf, record->len); - - for (i = 0; i < len; i++) { - memcpy((u8 *)&next_lk_ahds[i], - bundle_lkahd_rpt->lk_ahd, 4); - bundle_lkahd_rpt++; - } - - *n_lk_ahds = i; - } - break; - default: - ath6kl_err("unhandled record: id:%d len:%d\n", - record->rec_id, record->len); - break; - } - - return 0; - -} - -static int htc_proc_trailer(struct htc_target *target, - u8 *buf, int len, u32 *next_lk_ahds, - int *n_lk_ahds, enum htc_endpoint_id endpoint) -{ - struct htc_record_hdr *record; - int orig_len; - int status; - u8 *record_buf; - u8 *orig_buf; - - ath6kl_dbg(ATH6KL_DBG_HTC, "htc rx trailer len %d\n", len); - ath6kl_dbg_dump(ATH6KL_DBG_HTC, NULL, "", buf, len); - - orig_buf = buf; - orig_len = len; - status = 0; - - while (len > 0) { - - if (len < sizeof(struct htc_record_hdr)) { - status = -ENOMEM; - break; - } - /* these are byte aligned structs */ - record = (struct htc_record_hdr *) buf; - len -= sizeof(struct htc_record_hdr); - buf += sizeof(struct htc_record_hdr); - - if (record->len > len) { - ath6kl_err("invalid record len: %d (id:%d) buf has: %d bytes left\n", - record->len, record->rec_id, len); - status = -ENOMEM; - break; - } - record_buf = buf; - - status = htc_parse_trailer(target, record, record_buf, - next_lk_ahds, endpoint, n_lk_ahds); - - if (status) - break; - - /* advance buffer past this record for next time around */ - buf += record->len; - len -= record->len; - } - - if (status) - ath6kl_dbg_dump(ATH6KL_DBG_HTC, "htc rx bad trailer", - "", orig_buf, orig_len); - - return status; -} - -static int ath6kl_htc_rx_process_hdr(struct htc_target *target, - struct htc_packet *packet, - u32 *next_lkahds, int *n_lkahds) -{ - int status = 0; - u16 payload_len; - u32 lk_ahd; - struct htc_frame_hdr *htc_hdr = (struct htc_frame_hdr *)packet->buf; - - if (n_lkahds != NULL) - *n_lkahds = 0; - - /* - * NOTE: we cannot assume the alignment of buf, so we use the safe - * macros to retrieve 16 bit fields. - */ - payload_len = le16_to_cpu(get_unaligned(&htc_hdr->payld_len)); - - memcpy((u8 *)&lk_ahd, packet->buf, sizeof(lk_ahd)); - - if (packet->info.rx.rx_flags & HTC_RX_PKT_REFRESH_HDR) { - /* - * Refresh the expected header and the actual length as it - * was unknown when this packet was grabbed as part of the - * bundle. - */ - packet->info.rx.exp_hdr = lk_ahd; - packet->act_len = payload_len + HTC_HDR_LENGTH; - - /* validate the actual header that was refreshed */ - if (packet->act_len > packet->buf_len) { - ath6kl_err("refreshed hdr payload len (%d) in bundled recv is invalid (hdr: 0x%X)\n", - payload_len, lk_ahd); - /* - * Limit this to max buffer just to print out some - * of the buffer. - */ - packet->act_len = min(packet->act_len, packet->buf_len); - status = -ENOMEM; - goto fail_rx; - } - - if (packet->endpoint != htc_hdr->eid) { - ath6kl_err("refreshed hdr ep (%d) does not match expected ep (%d)\n", - htc_hdr->eid, packet->endpoint); - status = -ENOMEM; - goto fail_rx; - } - } - - if (lk_ahd != packet->info.rx.exp_hdr) { - ath6kl_err("%s(): lk_ahd mismatch! (pPkt:0x%p flags:0x%X)\n", - __func__, packet, packet->info.rx.rx_flags); - ath6kl_dbg_dump(ATH6KL_DBG_HTC, "htc rx expected lk_ahd", - "", &packet->info.rx.exp_hdr, 4); - ath6kl_dbg_dump(ATH6KL_DBG_HTC, "htc rx current header", - "", (u8 *)&lk_ahd, sizeof(lk_ahd)); - status = -ENOMEM; - goto fail_rx; - } - - if (htc_hdr->flags & HTC_FLG_RX_TRAILER) { - if (htc_hdr->ctrl[0] < sizeof(struct htc_record_hdr) || - htc_hdr->ctrl[0] > payload_len) { - ath6kl_err("%s(): invalid hdr (payload len should be :%d, CB[0] is:%d)\n", - __func__, payload_len, htc_hdr->ctrl[0]); - status = -ENOMEM; - goto fail_rx; - } - - if (packet->info.rx.rx_flags & HTC_RX_PKT_IGNORE_LOOKAHEAD) { - next_lkahds = NULL; - n_lkahds = NULL; - } - - status = htc_proc_trailer(target, packet->buf + HTC_HDR_LENGTH - + payload_len - htc_hdr->ctrl[0], - htc_hdr->ctrl[0], next_lkahds, - n_lkahds, packet->endpoint); - - if (status) - goto fail_rx; - - packet->act_len -= htc_hdr->ctrl[0]; - } - - packet->buf += HTC_HDR_LENGTH; - packet->act_len -= HTC_HDR_LENGTH; - -fail_rx: - if (status) - ath6kl_dbg_dump(ATH6KL_DBG_HTC, "htc rx bad packet", - "", packet->buf, packet->act_len); - - return status; -} - -static void ath6kl_htc_rx_complete(struct htc_endpoint *endpoint, - struct htc_packet *packet) -{ - ath6kl_dbg(ATH6KL_DBG_HTC, - "htc rx complete ep %d packet 0x%p\n", - endpoint->eid, packet); - endpoint->ep_cb.rx(endpoint->target, packet); -} - -static int ath6kl_htc_rx_bundle(struct htc_target *target, - struct list_head *rxq, - struct list_head *sync_compq, - int *n_pkt_fetched, bool part_bundle) -{ - struct hif_scatter_req *scat_req; - struct htc_packet *packet; - int rem_space = target->max_rx_bndl_sz; - int n_scat_pkt, status = 0, i, len; - - n_scat_pkt = get_queue_depth(rxq); - n_scat_pkt = min(n_scat_pkt, target->msg_per_bndl_max); - - if ((get_queue_depth(rxq) - n_scat_pkt) > 0) { - /* - * We were forced to split this bundle receive operation - * all packets in this partial bundle must have their - * lookaheads ignored. - */ - part_bundle = true; - - /* - * This would only happen if the target ignored our max - * bundle limit. - */ - ath6kl_warn("%s(): partial bundle detected num:%d , %d\n", - __func__, get_queue_depth(rxq), n_scat_pkt); - } - - len = 0; - - ath6kl_dbg(ATH6KL_DBG_HTC, - "htc rx bundle depth %d pkts %d\n", - get_queue_depth(rxq), n_scat_pkt); - - scat_req = hif_scatter_req_get(target->dev->ar); - - if (scat_req == NULL) - goto fail_rx_pkt; - - for (i = 0; i < n_scat_pkt; i++) { - int pad_len; - - packet = list_first_entry(rxq, struct htc_packet, list); - list_del(&packet->list); - - pad_len = CALC_TXRX_PADDED_LEN(target, - packet->act_len); - - if ((rem_space - pad_len) < 0) { - list_add(&packet->list, rxq); - break; - } - - rem_space -= pad_len; - - if (part_bundle || (i < (n_scat_pkt - 1))) - /* - * Packet 0..n-1 cannot be checked for look-aheads - * since we are fetching a bundle the last packet - * however can have it's lookahead used - */ - packet->info.rx.rx_flags |= - HTC_RX_PKT_IGNORE_LOOKAHEAD; - - /* NOTE: 1 HTC packet per scatter entry */ - scat_req->scat_list[i].buf = packet->buf; - scat_req->scat_list[i].len = pad_len; - - packet->info.rx.rx_flags |= HTC_RX_PKT_PART_OF_BUNDLE; - - list_add_tail(&packet->list, sync_compq); - - WARN_ON(!scat_req->scat_list[i].len); - len += scat_req->scat_list[i].len; - } - - scat_req->len = len; - scat_req->scat_entries = i; - - status = ath6kl_hif_submit_scat_req(target->dev, scat_req, true); - - if (!status) - *n_pkt_fetched = i; - - /* free scatter request */ - hif_scatter_req_add(target->dev->ar, scat_req); - -fail_rx_pkt: - - return status; -} - -static int ath6kl_htc_rx_process_packets(struct htc_target *target, - struct list_head *comp_pktq, - u32 lk_ahds[], - int *n_lk_ahd) -{ - struct htc_packet *packet, *tmp_pkt; - struct htc_endpoint *ep; - int status = 0; - - list_for_each_entry_safe(packet, tmp_pkt, comp_pktq, list) { - ep = &target->endpoint[packet->endpoint]; - - /* process header for each of the recv packet */ - status = ath6kl_htc_rx_process_hdr(target, packet, lk_ahds, - n_lk_ahd); - if (status) - return status; - - list_del(&packet->list); - - if (list_empty(comp_pktq)) { - /* - * Last packet's more packet flag is set - * based on the lookahead. - */ - if (*n_lk_ahd > 0) - ath6kl_htc_rx_set_indicate(lk_ahds[0], - ep, packet); - } else - /* - * Packets in a bundle automatically have - * this flag set. - */ - packet->info.rx.indicat_flags |= - HTC_RX_FLAGS_INDICATE_MORE_PKTS; - - ath6kl_htc_rx_update_stats(ep, *n_lk_ahd); - - if (packet->info.rx.rx_flags & HTC_RX_PKT_PART_OF_BUNDLE) - ep->ep_st.rx_bundl += 1; - - ath6kl_htc_rx_complete(ep, packet); - } - - return status; -} - -static int ath6kl_htc_rx_fetch(struct htc_target *target, - struct list_head *rx_pktq, - struct list_head *comp_pktq) -{ - int fetched_pkts; - bool part_bundle = false; - int status = 0; - struct list_head tmp_rxq; - struct htc_packet *packet, *tmp_pkt; - - /* now go fetch the list of HTC packets */ - while (!list_empty(rx_pktq)) { - fetched_pkts = 0; - - INIT_LIST_HEAD(&tmp_rxq); - - if (target->rx_bndl_enable && (get_queue_depth(rx_pktq) > 1)) { - /* - * There are enough packets to attempt a - * bundle transfer and recv bundling is - * allowed. - */ - status = ath6kl_htc_rx_bundle(target, rx_pktq, - &tmp_rxq, - &fetched_pkts, - part_bundle); - if (status) - goto fail_rx; - - if (!list_empty(rx_pktq)) - part_bundle = true; - - list_splice_tail_init(&tmp_rxq, comp_pktq); - } - - if (!fetched_pkts) { - - packet = list_first_entry(rx_pktq, struct htc_packet, - list); - - /* fully synchronous */ - packet->completion = NULL; - - if (!list_is_singular(rx_pktq)) - /* - * look_aheads in all packet - * except the last one in the - * bundle must be ignored - */ - packet->info.rx.rx_flags |= - HTC_RX_PKT_IGNORE_LOOKAHEAD; - - /* go fetch the packet */ - status = ath6kl_htc_rx_packet(target, packet, - packet->act_len); - - list_move_tail(&packet->list, &tmp_rxq); - - if (status) - goto fail_rx; - - list_splice_tail_init(&tmp_rxq, comp_pktq); - } - } - - return 0; - -fail_rx: - - /* - * Cleanup any packets we allocated but didn't use to - * actually fetch any packets. - */ - - list_for_each_entry_safe(packet, tmp_pkt, rx_pktq, list) { - list_del(&packet->list); - htc_reclaim_rxbuf(target, packet, - &target->endpoint[packet->endpoint]); - } - - list_for_each_entry_safe(packet, tmp_pkt, &tmp_rxq, list) { - list_del(&packet->list); - htc_reclaim_rxbuf(target, packet, - &target->endpoint[packet->endpoint]); - } - - return status; -} - -int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target, - u32 msg_look_ahead, int *num_pkts) -{ - struct htc_packet *packets, *tmp_pkt; - struct htc_endpoint *endpoint; - struct list_head rx_pktq, comp_pktq; - int status = 0; - u32 look_aheads[HTC_HOST_MAX_MSG_PER_BUNDLE]; - int num_look_ahead = 1; - enum htc_endpoint_id id; - int n_fetched = 0; - - INIT_LIST_HEAD(&comp_pktq); - *num_pkts = 0; - - /* - * On first entry copy the look_aheads into our temp array for - * processing - */ - look_aheads[0] = msg_look_ahead; - - while (true) { - - /* - * First lookahead sets the expected endpoint IDs for all - * packets in a bundle. - */ - id = ((struct htc_frame_hdr *)&look_aheads[0])->eid; - endpoint = &target->endpoint[id]; - - if (id >= ENDPOINT_MAX) { - ath6kl_err("MsgPend, invalid endpoint in look-ahead: %d\n", - id); - status = -ENOMEM; - break; - } - - INIT_LIST_HEAD(&rx_pktq); - INIT_LIST_HEAD(&comp_pktq); - - /* - * Try to allocate as many HTC RX packets indicated by the - * look_aheads. - */ - status = ath6kl_htc_rx_alloc(target, look_aheads, - num_look_ahead, endpoint, - &rx_pktq); - if (status) - break; - - if (get_queue_depth(&rx_pktq) >= 2) - /* - * A recv bundle was detected, force IRQ status - * re-check again - */ - target->chk_irq_status_cnt = 1; - - n_fetched += get_queue_depth(&rx_pktq); - - num_look_ahead = 0; - - status = ath6kl_htc_rx_fetch(target, &rx_pktq, &comp_pktq); - - if (!status) - ath6kl_htc_rx_chk_water_mark(endpoint); - - /* Process fetched packets */ - status = ath6kl_htc_rx_process_packets(target, &comp_pktq, - look_aheads, - &num_look_ahead); - - if (!num_look_ahead || status) - break; - - /* - * For SYNCH processing, if we get here, we are running - * through the loop again due to a detected lookahead. Set - * flag that we should re-check IRQ status registers again - * before leaving IRQ processing, this can net better - * performance in high throughput situations. - */ - target->chk_irq_status_cnt = 1; - } - - if (status) { - ath6kl_err("failed to get pending recv messages: %d\n", - status); - - /* cleanup any packets in sync completion queue */ - list_for_each_entry_safe(packets, tmp_pkt, &comp_pktq, list) { - list_del(&packets->list); - htc_reclaim_rxbuf(target, packets, - &target->endpoint[packets->endpoint]); - } - - if (target->htc_flags & HTC_OP_STATE_STOPPING) { - ath6kl_warn("host is going to stop blocking receiver for htc_stop\n"); - ath6kl_hif_rx_control(target->dev, false); - } - } - - /* - * Before leaving, check to see if host ran out of buffers and - * needs to stop the receiver. - */ - if (target->rx_st_flags & HTC_RECV_WAIT_BUFFERS) { - ath6kl_warn("host has no rx buffers blocking receiver to prevent overrun\n"); - ath6kl_hif_rx_control(target->dev, false); - } - *num_pkts = n_fetched; - - return status; -} - -/* - * Synchronously wait for a control message from the target, - * This function is used at initialization time ONLY. At init messages - * on ENDPOINT 0 are expected. - */ -static struct htc_packet *htc_wait_for_ctrl_msg(struct htc_target *target) -{ - struct htc_packet *packet = NULL; - struct htc_frame_hdr *htc_hdr; - u32 look_ahead; - - if (ath6kl_hif_poll_mboxmsg_rx(target->dev, &look_ahead, - HTC_TARGET_RESPONSE_TIMEOUT)) - return NULL; - - ath6kl_dbg(ATH6KL_DBG_HTC, - "htc rx wait ctrl look_ahead 0x%X\n", look_ahead); - - htc_hdr = (struct htc_frame_hdr *)&look_ahead; - - if (htc_hdr->eid != ENDPOINT_0) - return NULL; - - packet = htc_get_control_buf(target, false); - - if (!packet) - return NULL; - - packet->info.rx.rx_flags = 0; - packet->info.rx.exp_hdr = look_ahead; - packet->act_len = le16_to_cpu(htc_hdr->payld_len) + HTC_HDR_LENGTH; - - if (packet->act_len > packet->buf_len) - goto fail_ctrl_rx; - - /* we want synchronous operation */ - packet->completion = NULL; - - /* get the message from the device, this will block */ - if (ath6kl_htc_rx_packet(target, packet, packet->act_len)) - goto fail_ctrl_rx; - - /* process receive header */ - packet->status = ath6kl_htc_rx_process_hdr(target, packet, NULL, NULL); - - if (packet->status) { - ath6kl_err("htc_wait_for_ctrl_msg, ath6kl_htc_rx_process_hdr failed (status = %d)\n", - packet->status); - goto fail_ctrl_rx; - } - - return packet; - -fail_ctrl_rx: - if (packet != NULL) { - htc_rxpkt_reset(packet); - reclaim_rx_ctrl_buf(target, packet); - } - - return NULL; -} - -int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target, - struct list_head *pkt_queue) -{ - struct htc_endpoint *endpoint; - struct htc_packet *first_pkt; - bool rx_unblock = false; - int status = 0, depth; - - if (list_empty(pkt_queue)) - return -ENOMEM; - - first_pkt = list_first_entry(pkt_queue, struct htc_packet, list); - - if (first_pkt->endpoint >= ENDPOINT_MAX) - return status; - - depth = get_queue_depth(pkt_queue); - - ath6kl_dbg(ATH6KL_DBG_HTC, - "htc rx add multiple ep id %d cnt %d len %d\n", - first_pkt->endpoint, depth, first_pkt->buf_len); - - endpoint = &target->endpoint[first_pkt->endpoint]; - - if (target->htc_flags & HTC_OP_STATE_STOPPING) { - struct htc_packet *packet, *tmp_pkt; - - /* walk through queue and mark each one canceled */ - list_for_each_entry_safe(packet, tmp_pkt, pkt_queue, list) { - packet->status = -ECANCELED; - list_del(&packet->list); - ath6kl_htc_rx_complete(endpoint, packet); - } - - return status; - } - - spin_lock_bh(&target->rx_lock); - - list_splice_tail_init(pkt_queue, &endpoint->rx_bufq); - - /* check if we are blocked waiting for a new buffer */ - if (target->rx_st_flags & HTC_RECV_WAIT_BUFFERS) { - if (target->ep_waiting == first_pkt->endpoint) { - ath6kl_dbg(ATH6KL_DBG_HTC, - "htc rx blocked on ep %d, unblocking\n", - target->ep_waiting); - target->rx_st_flags &= ~HTC_RECV_WAIT_BUFFERS; - target->ep_waiting = ENDPOINT_MAX; - rx_unblock = true; - } - } - - spin_unlock_bh(&target->rx_lock); - - if (rx_unblock && !(target->htc_flags & HTC_OP_STATE_STOPPING)) - /* TODO : implement a buffer threshold count? */ - ath6kl_hif_rx_control(target->dev, true); - - return status; -} - -void ath6kl_htc_flush_rx_buf(struct htc_target *target) -{ - struct htc_endpoint *endpoint; - struct htc_packet *packet, *tmp_pkt; - int i; - - for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) { - endpoint = &target->endpoint[i]; - if (!endpoint->svc_id) - /* not in use.. */ - continue; - - spin_lock_bh(&target->rx_lock); - list_for_each_entry_safe(packet, tmp_pkt, - &endpoint->rx_bufq, list) { - list_del(&packet->list); - spin_unlock_bh(&target->rx_lock); - ath6kl_dbg(ATH6KL_DBG_HTC, - "htc rx flush pkt 0x%p len %d ep %d\n", - packet, packet->buf_len, - packet->endpoint); - /* - * packets in rx_bufq of endpoint 0 have originally - * been queued from target->free_ctrl_rxbuf where - * packet and packet->buf_start are allocated - * separately using kmalloc(). For other endpoint - * rx_bufq, it is allocated as skb where packet is - * skb->head. Take care of this difference while freeing - * the memory. - */ - if (packet->endpoint == ENDPOINT_0) { - kfree(packet->buf_start); - kfree(packet); - } else { - dev_kfree_skb(packet->pkt_cntxt); - } - spin_lock_bh(&target->rx_lock); - } - spin_unlock_bh(&target->rx_lock); - } -} - -int ath6kl_htc_conn_service(struct htc_target *target, - struct htc_service_connect_req *conn_req, - struct htc_service_connect_resp *conn_resp) -{ - struct htc_packet *rx_pkt = NULL; - struct htc_packet *tx_pkt = NULL; - struct htc_conn_service_resp *resp_msg; - struct htc_conn_service_msg *conn_msg; - struct htc_endpoint *endpoint; - enum htc_endpoint_id assigned_ep = ENDPOINT_MAX; - unsigned int max_msg_sz = 0; - int status = 0; - u16 msg_id; - - ath6kl_dbg(ATH6KL_DBG_HTC, - "htc connect service target 0x%p service id 0x%x\n", - target, conn_req->svc_id); - - if (conn_req->svc_id == HTC_CTRL_RSVD_SVC) { - /* special case for pseudo control service */ - assigned_ep = ENDPOINT_0; - max_msg_sz = HTC_MAX_CTRL_MSG_LEN; - } else { - /* allocate a packet to send to the target */ - tx_pkt = htc_get_control_buf(target, true); - - if (!tx_pkt) - return -ENOMEM; - - conn_msg = (struct htc_conn_service_msg *)tx_pkt->buf; - memset(conn_msg, 0, sizeof(*conn_msg)); - conn_msg->msg_id = cpu_to_le16(HTC_MSG_CONN_SVC_ID); - conn_msg->svc_id = cpu_to_le16(conn_req->svc_id); - conn_msg->conn_flags = cpu_to_le16(conn_req->conn_flags); - - set_htc_pkt_info(tx_pkt, NULL, (u8 *) conn_msg, - sizeof(*conn_msg) + conn_msg->svc_meta_len, - ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); - - /* we want synchronous operation */ - tx_pkt->completion = NULL; - ath6kl_htc_tx_prep_pkt(tx_pkt, 0, 0, 0); - status = ath6kl_htc_tx_issue(target, tx_pkt); - - if (status) - goto fail_tx; - - /* wait for response */ - rx_pkt = htc_wait_for_ctrl_msg(target); - - if (!rx_pkt) { - status = -ENOMEM; - goto fail_tx; - } - - resp_msg = (struct htc_conn_service_resp *)rx_pkt->buf; - msg_id = le16_to_cpu(resp_msg->msg_id); - - if ((msg_id != HTC_MSG_CONN_SVC_RESP_ID) || - (rx_pkt->act_len < sizeof(*resp_msg))) { - status = -ENOMEM; - goto fail_tx; - } - - conn_resp->resp_code = resp_msg->status; - /* check response status */ - if (resp_msg->status != HTC_SERVICE_SUCCESS) { - ath6kl_err("target failed service 0x%X connect request (status:%d)\n", - resp_msg->svc_id, resp_msg->status); - status = -ENOMEM; - goto fail_tx; - } - - assigned_ep = (enum htc_endpoint_id)resp_msg->eid; - max_msg_sz = le16_to_cpu(resp_msg->max_msg_sz); - } - - if (assigned_ep >= ENDPOINT_MAX || !max_msg_sz) { - status = -ENOMEM; - goto fail_tx; - } - - endpoint = &target->endpoint[assigned_ep]; - endpoint->eid = assigned_ep; - if (endpoint->svc_id) { - status = -ENOMEM; - goto fail_tx; - } - - /* return assigned endpoint to caller */ - conn_resp->endpoint = assigned_ep; - conn_resp->len_max = max_msg_sz; - - /* setup the endpoint */ - - /* this marks the endpoint in use */ - endpoint->svc_id = conn_req->svc_id; - - endpoint->max_txq_depth = conn_req->max_txq_depth; - endpoint->len_max = max_msg_sz; - endpoint->ep_cb = conn_req->ep_cb; - endpoint->cred_dist.svc_id = conn_req->svc_id; - endpoint->cred_dist.htc_ep = endpoint; - endpoint->cred_dist.endpoint = assigned_ep; - endpoint->cred_dist.cred_sz = target->tgt_cred_sz; - - switch (endpoint->svc_id) { - case WMI_DATA_BK_SVC: - endpoint->tx_drop_packet_threshold = MAX_DEF_COOKIE_NUM / 3; - break; - default: - endpoint->tx_drop_packet_threshold = MAX_HI_COOKIE_NUM; - break; - } - - if (conn_req->max_rxmsg_sz) { - /* - * Override cred_per_msg calculation, this optimizes - * the credit-low indications since the host will actually - * issue smaller messages in the Send path. - */ - if (conn_req->max_rxmsg_sz > max_msg_sz) { - status = -ENOMEM; - goto fail_tx; - } - endpoint->cred_dist.cred_per_msg = - conn_req->max_rxmsg_sz / target->tgt_cred_sz; - } else - endpoint->cred_dist.cred_per_msg = - max_msg_sz / target->tgt_cred_sz; - - if (!endpoint->cred_dist.cred_per_msg) - endpoint->cred_dist.cred_per_msg = 1; - - /* save local connection flags */ - endpoint->conn_flags = conn_req->flags; - -fail_tx: - if (tx_pkt) - htc_reclaim_txctrl_buf(target, tx_pkt); - - if (rx_pkt) { - htc_rxpkt_reset(rx_pkt); - reclaim_rx_ctrl_buf(target, rx_pkt); - } - - return status; -} - -static void reset_ep_state(struct htc_target *target) -{ - struct htc_endpoint *endpoint; - int i; - - for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) { - endpoint = &target->endpoint[i]; - memset(&endpoint->cred_dist, 0, sizeof(endpoint->cred_dist)); - endpoint->svc_id = 0; - endpoint->len_max = 0; - endpoint->max_txq_depth = 0; - memset(&endpoint->ep_st, 0, - sizeof(endpoint->ep_st)); - INIT_LIST_HEAD(&endpoint->rx_bufq); - INIT_LIST_HEAD(&endpoint->txq); - endpoint->target = target; - } - - /* reset distribution list */ - /* FIXME: free existing entries */ - INIT_LIST_HEAD(&target->cred_dist_list); -} - -int ath6kl_htc_get_rxbuf_num(struct htc_target *target, - enum htc_endpoint_id endpoint) -{ - int num; - - spin_lock_bh(&target->rx_lock); - num = get_queue_depth(&(target->endpoint[endpoint].rx_bufq)); - spin_unlock_bh(&target->rx_lock); - return num; -} - -static void htc_setup_msg_bndl(struct htc_target *target) -{ - /* limit what HTC can handle */ - target->msg_per_bndl_max = min(HTC_HOST_MAX_MSG_PER_BUNDLE, - target->msg_per_bndl_max); - - if (ath6kl_hif_enable_scatter(target->dev->ar)) { - target->msg_per_bndl_max = 0; - return; - } - - /* limit bundle what the device layer can handle */ - target->msg_per_bndl_max = min(target->max_scat_entries, - target->msg_per_bndl_max); - - ath6kl_dbg(ATH6KL_DBG_BOOT, - "htc bundling allowed msg_per_bndl_max %d\n", - target->msg_per_bndl_max); - - /* Max rx bundle size is limited by the max tx bundle size */ - target->max_rx_bndl_sz = target->max_xfer_szper_scatreq; - /* Max tx bundle size if limited by the extended mbox address range */ - target->max_tx_bndl_sz = min(HIF_MBOX0_EXT_WIDTH, - target->max_xfer_szper_scatreq); - - ath6kl_dbg(ATH6KL_DBG_BOOT, "htc max_rx_bndl_sz %d max_tx_bndl_sz %d\n", - target->max_rx_bndl_sz, target->max_tx_bndl_sz); - - if (target->max_tx_bndl_sz) - /* tx_bndl_mask is enabled per AC, each has 1 bit */ - target->tx_bndl_mask = (1 << WMM_NUM_AC) - 1; - - if (target->max_rx_bndl_sz) - target->rx_bndl_enable = true; - - if ((target->tgt_cred_sz % target->block_sz) != 0) { - ath6kl_warn("credit size: %d is not block aligned! Disabling send bundling\n", - target->tgt_cred_sz); - - /* - * Disallow send bundling since the credit size is - * not aligned to a block size the I/O block - * padding will spill into the next credit buffer - * which is fatal. - */ - target->tx_bndl_mask = 0; - } -} - -int ath6kl_htc_wait_target(struct htc_target *target) -{ - struct htc_packet *packet = NULL; - struct htc_ready_ext_msg *rdy_msg; - struct htc_service_connect_req connect; - struct htc_service_connect_resp resp; - int status; - - /* FIXME: remove once USB support is implemented */ - if (target->dev->ar->hif_type == ATH6KL_HIF_TYPE_USB) { - ath6kl_err("HTC doesn't support USB yet. Patience!\n"); - return -EOPNOTSUPP; - } - - /* we should be getting 1 control message that the target is ready */ - packet = htc_wait_for_ctrl_msg(target); - - if (!packet) - return -ENOMEM; - - /* we controlled the buffer creation so it's properly aligned */ - rdy_msg = (struct htc_ready_ext_msg *)packet->buf; - - if ((le16_to_cpu(rdy_msg->ver2_0_info.msg_id) != HTC_MSG_READY_ID) || - (packet->act_len < sizeof(struct htc_ready_msg))) { - status = -ENOMEM; - goto fail_wait_target; - } - - if (!rdy_msg->ver2_0_info.cred_cnt || !rdy_msg->ver2_0_info.cred_sz) { - status = -ENOMEM; - goto fail_wait_target; - } - - target->tgt_creds = le16_to_cpu(rdy_msg->ver2_0_info.cred_cnt); - target->tgt_cred_sz = le16_to_cpu(rdy_msg->ver2_0_info.cred_sz); - - ath6kl_dbg(ATH6KL_DBG_BOOT, - "htc target ready credits %d size %d\n", - target->tgt_creds, target->tgt_cred_sz); - - /* check if this is an extended ready message */ - if (packet->act_len >= sizeof(struct htc_ready_ext_msg)) { - /* this is an extended message */ - target->htc_tgt_ver = rdy_msg->htc_ver; - target->msg_per_bndl_max = rdy_msg->msg_per_htc_bndl; - } else { - /* legacy */ - target->htc_tgt_ver = HTC_VERSION_2P0; - target->msg_per_bndl_max = 0; - } - - ath6kl_dbg(ATH6KL_DBG_BOOT, "htc using protocol %s (%d)\n", - (target->htc_tgt_ver == HTC_VERSION_2P0) ? "2.0" : ">= 2.1", - target->htc_tgt_ver); - - if (target->msg_per_bndl_max > 0) - htc_setup_msg_bndl(target); - - /* setup our pseudo HTC control endpoint connection */ - memset(&connect, 0, sizeof(connect)); - memset(&resp, 0, sizeof(resp)); - connect.ep_cb.rx = htc_ctrl_rx; - connect.ep_cb.rx_refill = NULL; - connect.ep_cb.tx_full = NULL; - connect.max_txq_depth = NUM_CONTROL_BUFFERS; - connect.svc_id = HTC_CTRL_RSVD_SVC; - - /* connect fake service */ - status = ath6kl_htc_conn_service((void *)target, &connect, &resp); - - if (status) - /* - * FIXME: this call doesn't make sense, the caller should - * call ath6kl_htc_cleanup() when it wants remove htc - */ - ath6kl_hif_cleanup_scatter(target->dev->ar); - -fail_wait_target: - if (packet) { - htc_rxpkt_reset(packet); - reclaim_rx_ctrl_buf(target, packet); - } - - return status; -} - -/* - * Start HTC, enable interrupts and let the target know - * host has finished setup. - */ -int ath6kl_htc_start(struct htc_target *target) -{ - struct htc_packet *packet; - int status; - - memset(&target->dev->irq_proc_reg, 0, - sizeof(target->dev->irq_proc_reg)); - - /* Disable interrupts at the chip level */ - ath6kl_hif_disable_intrs(target->dev); - - target->htc_flags = 0; - target->rx_st_flags = 0; - - /* Push control receive buffers into htc control endpoint */ - while ((packet = htc_get_control_buf(target, false)) != NULL) { - status = htc_add_rxbuf(target, packet); - if (status) - return status; - } - - /* NOTE: the first entry in the distribution list is ENDPOINT_0 */ - ath6kl_credit_init(target->credit_info, &target->cred_dist_list, - target->tgt_creds); - - dump_cred_dist_stats(target); - - /* Indicate to the target of the setup completion */ - status = htc_setup_tx_complete(target); - - if (status) - return status; - - /* unmask interrupts */ - status = ath6kl_hif_unmask_intrs(target->dev); - - if (status) - ath6kl_htc_stop(target); - - return status; -} - -static int ath6kl_htc_reset(struct htc_target *target) -{ - u32 block_size, ctrl_bufsz; - struct htc_packet *packet; - int i; - - reset_ep_state(target); - - block_size = target->dev->ar->mbox_info.block_size; - - ctrl_bufsz = (block_size > HTC_MAX_CTRL_MSG_LEN) ? - (block_size + HTC_HDR_LENGTH) : - (HTC_MAX_CTRL_MSG_LEN + HTC_HDR_LENGTH); - - for (i = 0; i < NUM_CONTROL_BUFFERS; i++) { - packet = kzalloc(sizeof(*packet), GFP_KERNEL); - if (!packet) - return -ENOMEM; - - packet->buf_start = kzalloc(ctrl_bufsz, GFP_KERNEL); - if (!packet->buf_start) { - kfree(packet); - return -ENOMEM; - } - - packet->buf_len = ctrl_bufsz; - if (i < NUM_CONTROL_RX_BUFFERS) { - packet->act_len = 0; - packet->buf = packet->buf_start; - packet->endpoint = ENDPOINT_0; - list_add_tail(&packet->list, &target->free_ctrl_rxbuf); - } else - list_add_tail(&packet->list, &target->free_ctrl_txbuf); - } - - return 0; -} - -/* htc_stop: stop interrupt reception, and flush all queued buffers */ -void ath6kl_htc_stop(struct htc_target *target) -{ - spin_lock_bh(&target->htc_lock); - target->htc_flags |= HTC_OP_STATE_STOPPING; - spin_unlock_bh(&target->htc_lock); - - /* - * Masking interrupts is a synchronous operation, when this - * function returns all pending HIF I/O has completed, we can - * safely flush the queues. - */ - ath6kl_hif_mask_intrs(target->dev); - - ath6kl_htc_flush_txep_all(target); - - ath6kl_htc_flush_rx_buf(target); - - ath6kl_htc_reset(target); -} - -void *ath6kl_htc_create(struct ath6kl *ar) -{ - struct htc_target *target = NULL; - int status = 0; - - target = kzalloc(sizeof(*target), GFP_KERNEL); - if (!target) { - ath6kl_err("unable to allocate memory\n"); - return NULL; - } - - target->dev = kzalloc(sizeof(*target->dev), GFP_KERNEL); - if (!target->dev) { - ath6kl_err("unable to allocate memory\n"); - status = -ENOMEM; - goto err_htc_cleanup; - } - - spin_lock_init(&target->htc_lock); - spin_lock_init(&target->rx_lock); - spin_lock_init(&target->tx_lock); - - INIT_LIST_HEAD(&target->free_ctrl_txbuf); - INIT_LIST_HEAD(&target->free_ctrl_rxbuf); - INIT_LIST_HEAD(&target->cred_dist_list); - - target->dev->ar = ar; - target->dev->htc_cnxt = target; - target->ep_waiting = ENDPOINT_MAX; - - status = ath6kl_hif_setup(target->dev); - if (status) - goto err_htc_cleanup; - - status = ath6kl_htc_reset(target); - if (status) - goto err_htc_cleanup; - - return target; - -err_htc_cleanup: - ath6kl_htc_cleanup(target); - - return NULL; -} - -/* cleanup the HTC instance */ -void ath6kl_htc_cleanup(struct htc_target *target) -{ - struct htc_packet *packet, *tmp_packet; - - /* FIXME: remove check once USB support is implemented */ - if (target->dev->ar->hif_type != ATH6KL_HIF_TYPE_USB) - ath6kl_hif_cleanup_scatter(target->dev->ar); - - list_for_each_entry_safe(packet, tmp_packet, - &target->free_ctrl_txbuf, list) { - list_del(&packet->list); - kfree(packet->buf_start); - kfree(packet); - } - - list_for_each_entry_safe(packet, tmp_packet, - &target->free_ctrl_rxbuf, list) { - list_del(&packet->list); - kfree(packet->buf_start); - kfree(packet); - } - - kfree(target->dev); - kfree(target); -} diff --git a/trunk/drivers/net/wireless/ath/ath6kl/htc.h b/trunk/drivers/net/wireless/ath/ath6kl/htc.h index 5027ccc36b62..a2c8ff809793 100644 --- a/trunk/drivers/net/wireless/ath/ath6kl/htc.h +++ b/trunk/drivers/net/wireless/ath/ath6kl/htc.h @@ -25,6 +25,7 @@ /* send direction */ #define HTC_FLAGS_NEED_CREDIT_UPDATE (1 << 0) #define HTC_FLAGS_SEND_BUNDLE (1 << 1) +#define HTC_FLAGS_TX_FIXUP_NETBUF (1 << 2) /* receive direction */ #define HTC_FLG_RX_UNUSED (1 << 0) @@ -56,6 +57,10 @@ #define HTC_CONN_FLGS_THRESH_LVL_THREE_QUAT 0x2 #define HTC_CONN_FLGS_REDUCE_CRED_DRIB 0x4 #define HTC_CONN_FLGS_THRESH_MASK 0x3 +/* disable credit flow control on a specific service */ +#define HTC_CONN_FLGS_DISABLE_CRED_FLOW_CTRL (1 << 3) +#define HTC_CONN_FLGS_SET_RECV_ALLOC_SHIFT 8 +#define HTC_CONN_FLGS_SET_RECV_ALLOC_MASK 0xFF00 /* connect response status codes */ #define HTC_SERVICE_SUCCESS 0 @@ -75,6 +80,7 @@ #define HTC_RECORD_LOOKAHEAD_BUNDLE 3 #define HTC_SETUP_COMP_FLG_RX_BNDL_EN (1 << 0) +#define HTC_SETUP_COMP_FLG_DISABLE_TX_CREDIT_FLOW (1 << 1) #define MAKE_SERVICE_ID(group, index) \ (int)(((int)group << 8) | (int)(index)) @@ -109,6 +115,8 @@ /* HTC operational parameters */ #define HTC_TARGET_RESPONSE_TIMEOUT 2000 /* in ms */ +#define HTC_TARGET_RESPONSE_POLL_WAIT 10 +#define HTC_TARGET_RESPONSE_POLL_COUNT 200 #define HTC_TARGET_DEBUG_INTR_MASK 0x01 #define HTC_TARGET_CREDIT_INTR_MASK 0xF0 @@ -128,6 +136,7 @@ #define HTC_RECV_WAIT_BUFFERS (1 << 0) #define HTC_OP_STATE_STOPPING (1 << 0) +#define HTC_OP_STATE_SETUP_COMPLETE (1 << 1) /* * The frame header length and message formats defined herein were selected @@ -311,6 +320,14 @@ struct htc_packet { void (*completion) (struct htc_target *, struct htc_packet *); struct htc_target *context; + + /* + * optimization for network-oriented data, the HTC packet + * can pass the network buffer corresponding to the HTC packet + * lower layers may optimized the transfer knowing this is + * a network buffer + */ + struct sk_buff *skb; }; enum htc_send_full_action { @@ -319,12 +336,14 @@ enum htc_send_full_action { }; struct htc_ep_callbacks { + void (*tx_complete) (struct htc_target *, struct htc_packet *); void (*rx) (struct htc_target *, struct htc_packet *); void (*rx_refill) (struct htc_target *, enum htc_endpoint_id endpoint); enum htc_send_full_action (*tx_full) (struct htc_target *, struct htc_packet *); struct htc_packet *(*rx_allocthresh) (struct htc_target *, enum htc_endpoint_id, int); + void (*tx_comp_multi) (struct htc_target *, struct list_head *); int rx_alloc_thresh; int rx_refill_thresh; }; @@ -502,6 +521,13 @@ struct htc_endpoint { u32 conn_flags; struct htc_endpoint_stats ep_st; u16 tx_drop_packet_threshold; + + struct { + u8 pipeid_ul; + u8 pipeid_dl; + struct list_head tx_lookup_queue; + bool tx_credit_flow_enabled; + } pipe; }; struct htc_control_buffer { @@ -509,6 +535,42 @@ struct htc_control_buffer { u8 *buf; }; +struct htc_pipe_txcredit_alloc { + u16 service_id; + u8 credit_alloc; +}; + +enum htc_send_queue_result { + HTC_SEND_QUEUE_OK = 0, /* packet was queued */ + HTC_SEND_QUEUE_DROP = 1, /* this packet should be dropped */ +}; + +struct ath6kl_htc_ops { + void* (*create)(struct ath6kl *ar); + int (*wait_target)(struct htc_target *target); + int (*start)(struct htc_target *target); + int (*conn_service)(struct htc_target *target, + struct htc_service_connect_req *req, + struct htc_service_connect_resp *resp); + int (*tx)(struct htc_target *target, struct htc_packet *packet); + void (*stop)(struct htc_target *target); + void (*cleanup)(struct htc_target *target); + void (*flush_txep)(struct htc_target *target, + enum htc_endpoint_id endpoint, u16 tag); + void (*flush_rx_buf)(struct htc_target *target); + void (*activity_changed)(struct htc_target *target, + enum htc_endpoint_id endpoint, + bool active); + int (*get_rxbuf_num)(struct htc_target *target, + enum htc_endpoint_id endpoint); + int (*add_rxbuf_multiple)(struct htc_target *target, + struct list_head *pktq); + int (*credit_setup)(struct htc_target *target, + struct ath6kl_htc_credit_info *cred_info); + int (*tx_complete)(struct ath6kl *ar, struct sk_buff *skb); + int (*rx_complete)(struct ath6kl *ar, struct sk_buff *skb, u8 pipe); +}; + struct ath6kl_device; /* our HTC target state */ @@ -557,36 +619,19 @@ struct htc_target { /* counts the number of Tx without bundling continously per AC */ u32 ac_tx_count[WMM_NUM_AC]; + + struct { + struct htc_packet *htc_packet_pool; + u8 ctrl_response_buf[HTC_MAX_CTRL_MSG_LEN]; + int ctrl_response_len; + bool ctrl_response_valid; + struct htc_pipe_txcredit_alloc txcredit_alloc[ENDPOINT_MAX]; + } pipe; }; -void *ath6kl_htc_create(struct ath6kl *ar); -void ath6kl_htc_set_credit_dist(struct htc_target *target, - struct ath6kl_htc_credit_info *cred_info, - u16 svc_pri_order[], int len); -int ath6kl_htc_wait_target(struct htc_target *target); -int ath6kl_htc_start(struct htc_target *target); -int ath6kl_htc_conn_service(struct htc_target *target, - struct htc_service_connect_req *req, - struct htc_service_connect_resp *resp); -int ath6kl_htc_tx(struct htc_target *target, struct htc_packet *packet); -void ath6kl_htc_stop(struct htc_target *target); -void ath6kl_htc_cleanup(struct htc_target *target); -void ath6kl_htc_flush_txep(struct htc_target *target, - enum htc_endpoint_id endpoint, u16 tag); -void ath6kl_htc_flush_rx_buf(struct htc_target *target); -void ath6kl_htc_indicate_activity_change(struct htc_target *target, - enum htc_endpoint_id endpoint, - bool active); -int ath6kl_htc_get_rxbuf_num(struct htc_target *target, - enum htc_endpoint_id endpoint); -int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target, - struct list_head *pktq); int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target, u32 msg_look_ahead, int *n_pkts); -int ath6kl_credit_setup(void *htc_handle, - struct ath6kl_htc_credit_info *cred_info); - static inline void set_htc_pkt_info(struct htc_packet *packet, void *context, u8 *buf, unsigned int len, enum htc_endpoint_id eid, u16 tag) @@ -626,4 +671,7 @@ static inline int get_queue_depth(struct list_head *queue) return depth; } +void ath6kl_htc_pipe_attach(struct ath6kl *ar); +void ath6kl_htc_mbox_attach(struct ath6kl *ar); + #endif diff --git a/trunk/drivers/net/wireless/ath/ath6kl/htc_mbox.c b/trunk/drivers/net/wireless/ath/ath6kl/htc_mbox.c new file mode 100644 index 000000000000..065e61516d7a --- /dev/null +++ b/trunk/drivers/net/wireless/ath/ath6kl/htc_mbox.c @@ -0,0 +1,2923 @@ +/* + * Copyright (c) 2007-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "core.h" +#include "hif.h" +#include "debug.h" +#include "hif-ops.h" +#include + +#define CALC_TXRX_PADDED_LEN(dev, len) (__ALIGN_MASK((len), (dev)->block_mask)) + +static void ath6kl_htc_mbox_cleanup(struct htc_target *target); +static void ath6kl_htc_mbox_stop(struct htc_target *target); +static int ath6kl_htc_mbox_add_rxbuf_multiple(struct htc_target *target, + struct list_head *pkt_queue); +static void ath6kl_htc_set_credit_dist(struct htc_target *target, + struct ath6kl_htc_credit_info *cred_info, + u16 svc_pri_order[], int len); + +/* threshold to re-enable Tx bundling for an AC*/ +#define TX_RESUME_BUNDLE_THRESHOLD 1500 + +/* Functions for Tx credit handling */ +static void ath6kl_credit_deposit(struct ath6kl_htc_credit_info *cred_info, + struct htc_endpoint_credit_dist *ep_dist, + int credits) +{ + ath6kl_dbg(ATH6KL_DBG_CREDIT, "credit deposit ep %d credits %d\n", + ep_dist->endpoint, credits); + + ep_dist->credits += credits; + ep_dist->cred_assngd += credits; + cred_info->cur_free_credits -= credits; +} + +static void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_info, + struct list_head *ep_list, + int tot_credits) +{ + struct htc_endpoint_credit_dist *cur_ep_dist; + int count; + + ath6kl_dbg(ATH6KL_DBG_CREDIT, "credit init total %d\n", tot_credits); + + cred_info->cur_free_credits = tot_credits; + cred_info->total_avail_credits = tot_credits; + + list_for_each_entry(cur_ep_dist, ep_list, list) { + if (cur_ep_dist->endpoint == ENDPOINT_0) + continue; + + cur_ep_dist->cred_min = cur_ep_dist->cred_per_msg; + + if (tot_credits > 4) { + if ((cur_ep_dist->svc_id == WMI_DATA_BK_SVC) || + (cur_ep_dist->svc_id == WMI_DATA_BE_SVC)) { + ath6kl_credit_deposit(cred_info, + cur_ep_dist, + cur_ep_dist->cred_min); + cur_ep_dist->dist_flags |= HTC_EP_ACTIVE; + } + } + + if (cur_ep_dist->svc_id == WMI_CONTROL_SVC) { + ath6kl_credit_deposit(cred_info, cur_ep_dist, + cur_ep_dist->cred_min); + /* + * Control service is always marked active, it + * never goes inactive EVER. + */ + cur_ep_dist->dist_flags |= HTC_EP_ACTIVE; + } else if (cur_ep_dist->svc_id == WMI_DATA_BK_SVC) + /* this is the lowest priority data endpoint */ + /* FIXME: this looks fishy, check */ + cred_info->lowestpri_ep_dist = cur_ep_dist->list; + + /* + * Streams have to be created (explicit | implicit) for all + * kinds of traffic. BE endpoints are also inactive in the + * beginning. When BE traffic starts it creates implicit + * streams that redistributes credits. + * + * Note: all other endpoints have minimums set but are + * initially given NO credits. credits will be distributed + * as traffic activity demands + */ + } + + WARN_ON(cred_info->cur_free_credits <= 0); + + list_for_each_entry(cur_ep_dist, ep_list, list) { + if (cur_ep_dist->endpoint == ENDPOINT_0) + continue; + + if (cur_ep_dist->svc_id == WMI_CONTROL_SVC) + cur_ep_dist->cred_norm = cur_ep_dist->cred_per_msg; + else { + /* + * For the remaining data endpoints, we assume that + * each cred_per_msg are the same. We use a simple + * calculation here, we take the remaining credits + * and determine how many max messages this can + * cover and then set each endpoint's normal value + * equal to 3/4 this amount. + */ + count = (cred_info->cur_free_credits / + cur_ep_dist->cred_per_msg) + * cur_ep_dist->cred_per_msg; + count = (count * 3) >> 2; + count = max(count, cur_ep_dist->cred_per_msg); + cur_ep_dist->cred_norm = count; + + } + + ath6kl_dbg(ATH6KL_DBG_CREDIT, + "credit ep %d svc_id %d credits %d per_msg %d norm %d min %d\n", + cur_ep_dist->endpoint, + cur_ep_dist->svc_id, + cur_ep_dist->credits, + cur_ep_dist->cred_per_msg, + cur_ep_dist->cred_norm, + cur_ep_dist->cred_min); + } +} + +/* initialize and setup credit distribution */ +static int ath6kl_htc_mbox_credit_setup(struct htc_target *htc_target, + struct ath6kl_htc_credit_info *cred_info) +{ + u16 servicepriority[5]; + + memset(cred_info, 0, sizeof(struct ath6kl_htc_credit_info)); + + servicepriority[0] = WMI_CONTROL_SVC; /* highest */ + servicepriority[1] = WMI_DATA_VO_SVC; + servicepriority[2] = WMI_DATA_VI_SVC; + servicepriority[3] = WMI_DATA_BE_SVC; + servicepriority[4] = WMI_DATA_BK_SVC; /* lowest */ + + /* set priority list */ + ath6kl_htc_set_credit_dist(htc_target, cred_info, servicepriority, 5); + + return 0; +} + +/* reduce an ep's credits back to a set limit */ +static void ath6kl_credit_reduce(struct ath6kl_htc_credit_info *cred_info, + struct htc_endpoint_credit_dist *ep_dist, + int limit) +{ + int credits; + + ath6kl_dbg(ATH6KL_DBG_CREDIT, "credit reduce ep %d limit %d\n", + ep_dist->endpoint, limit); + + ep_dist->cred_assngd = limit; + + if (ep_dist->credits <= limit) + return; + + credits = ep_dist->credits - limit; + ep_dist->credits -= credits; + cred_info->cur_free_credits += credits; +} + +static void ath6kl_credit_update(struct ath6kl_htc_credit_info *cred_info, + struct list_head *epdist_list) +{ + struct htc_endpoint_credit_dist *cur_list; + + list_for_each_entry(cur_list, epdist_list, list) { + if (cur_list->endpoint == ENDPOINT_0) + continue; + + if (cur_list->cred_to_dist > 0) { + cur_list->credits += cur_list->cred_to_dist; + cur_list->cred_to_dist = 0; + + if (cur_list->credits > cur_list->cred_assngd) + ath6kl_credit_reduce(cred_info, + cur_list, + cur_list->cred_assngd); + + if (cur_list->credits > cur_list->cred_norm) + ath6kl_credit_reduce(cred_info, cur_list, + cur_list->cred_norm); + + if (!(cur_list->dist_flags & HTC_EP_ACTIVE)) { + if (cur_list->txq_depth == 0) + ath6kl_credit_reduce(cred_info, + cur_list, 0); + } + } + } +} + +/* + * HTC has an endpoint that needs credits, ep_dist is the endpoint in + * question. + */ +static void ath6kl_credit_seek(struct ath6kl_htc_credit_info *cred_info, + struct htc_endpoint_credit_dist *ep_dist) +{ + struct htc_endpoint_credit_dist *curdist_list; + int credits = 0; + int need; + + if (ep_dist->svc_id == WMI_CONTROL_SVC) + goto out; + + if ((ep_dist->svc_id == WMI_DATA_VI_SVC) || + (ep_dist->svc_id == WMI_DATA_VO_SVC)) + if ((ep_dist->cred_assngd >= ep_dist->cred_norm)) + goto out; + + /* + * For all other services, we follow a simple algorithm of: + * + * 1. checking the free pool for credits + * 2. checking lower priority endpoints for credits to take + */ + + credits = min(cred_info->cur_free_credits, ep_dist->seek_cred); + + if (credits >= ep_dist->seek_cred) + goto out; + + /* + * We don't have enough in the free pool, try taking away from + * lower priority services The rule for taking away credits: + * + * 1. Only take from lower priority endpoints + * 2. Only take what is allocated above the minimum (never + * starve an endpoint completely) + * 3. Only take what you need. + */ + + list_for_each_entry_reverse(curdist_list, + &cred_info->lowestpri_ep_dist, + list) { + if (curdist_list == ep_dist) + break; + + need = ep_dist->seek_cred - cred_info->cur_free_credits; + + if ((curdist_list->cred_assngd - need) >= + curdist_list->cred_min) { + /* + * The current one has been allocated more than + * it's minimum and it has enough credits assigned + * above it's minimum to fulfill our need try to + * take away just enough to fulfill our need. + */ + ath6kl_credit_reduce(cred_info, curdist_list, + curdist_list->cred_assngd - need); + + if (cred_info->cur_free_credits >= + ep_dist->seek_cred) + break; + } + + if (curdist_list->endpoint == ENDPOINT_0) + break; + } + + credits = min(cred_info->cur_free_credits, ep_dist->seek_cred); + +out: + /* did we find some credits? */ + if (credits) + ath6kl_credit_deposit(cred_info, ep_dist, credits); + + ep_dist->seek_cred = 0; +} + +/* redistribute credits based on activity change */ +static void ath6kl_credit_redistribute(struct ath6kl_htc_credit_info *info, + struct list_head *ep_dist_list) +{ + struct htc_endpoint_credit_dist *curdist_list; + + list_for_each_entry(curdist_list, ep_dist_list, list) { + if (curdist_list->endpoint == ENDPOINT_0) + continue; + + if ((curdist_list->svc_id == WMI_DATA_BK_SVC) || + (curdist_list->svc_id == WMI_DATA_BE_SVC)) + curdist_list->dist_flags |= HTC_EP_ACTIVE; + + if ((curdist_list->svc_id != WMI_CONTROL_SVC) && + !(curdist_list->dist_flags & HTC_EP_ACTIVE)) { + if (curdist_list->txq_depth == 0) + ath6kl_credit_reduce(info, curdist_list, 0); + else + ath6kl_credit_reduce(info, + curdist_list, + curdist_list->cred_min); + } + } +} + +/* + * + * This function is invoked whenever endpoints require credit + * distributions. A lock is held while this function is invoked, this + * function shall NOT block. The ep_dist_list is a list of distribution + * structures in prioritized order as defined by the call to the + * htc_set_credit_dist() api. + */ +static void ath6kl_credit_distribute(struct ath6kl_htc_credit_info *cred_info, + struct list_head *ep_dist_list, + enum htc_credit_dist_reason reason) +{ + switch (reason) { + case HTC_CREDIT_DIST_SEND_COMPLETE: + ath6kl_credit_update(cred_info, ep_dist_list); + break; + case HTC_CREDIT_DIST_ACTIVITY_CHANGE: + ath6kl_credit_redistribute(cred_info, ep_dist_list); + break; + default: + break; + } + + WARN_ON(cred_info->cur_free_credits > cred_info->total_avail_credits); + WARN_ON(cred_info->cur_free_credits < 0); +} + +static void ath6kl_htc_tx_buf_align(u8 **buf, unsigned long len) +{ + u8 *align_addr; + + if (!IS_ALIGNED((unsigned long) *buf, 4)) { + align_addr = PTR_ALIGN(*buf - 4, 4); + memmove(align_addr, *buf, len); + *buf = align_addr; + } +} + +static void ath6kl_htc_tx_prep_pkt(struct htc_packet *packet, u8 flags, + int ctrl0, int ctrl1) +{ + struct htc_frame_hdr *hdr; + + packet->buf -= HTC_HDR_LENGTH; + hdr = (struct htc_frame_hdr *)packet->buf; + + /* Endianess? */ + put_unaligned((u16)packet->act_len, &hdr->payld_len); + hdr->flags = flags; + hdr->eid = packet->endpoint; + hdr->ctrl[0] = ctrl0; + hdr->ctrl[1] = ctrl1; +} + +static void htc_reclaim_txctrl_buf(struct htc_target *target, + struct htc_packet *pkt) +{ + spin_lock_bh(&target->htc_lock); + list_add_tail(&pkt->list, &target->free_ctrl_txbuf); + spin_unlock_bh(&target->htc_lock); +} + +static struct htc_packet *htc_get_control_buf(struct htc_target *target, + bool tx) +{ + struct htc_packet *packet = NULL; + struct list_head *buf_list; + + buf_list = tx ? &target->free_ctrl_txbuf : &target->free_ctrl_rxbuf; + + spin_lock_bh(&target->htc_lock); + + if (list_empty(buf_list)) { + spin_unlock_bh(&target->htc_lock); + return NULL; + } + + packet = list_first_entry(buf_list, struct htc_packet, list); + list_del(&packet->list); + spin_unlock_bh(&target->htc_lock); + + if (tx) + packet->buf = packet->buf_start + HTC_HDR_LENGTH; + + return packet; +} + +static void htc_tx_comp_update(struct htc_target *target, + struct htc_endpoint *endpoint, + struct htc_packet *packet) +{ + packet->completion = NULL; + packet->buf += HTC_HDR_LENGTH; + + if (!packet->status) + return; + + ath6kl_err("req failed (status:%d, ep:%d, len:%d creds:%d)\n", + packet->status, packet->endpoint, packet->act_len, + packet->info.tx.cred_used); + + /* on failure to submit, reclaim credits for this packet */ + spin_lock_bh(&target->tx_lock); + endpoint->cred_dist.cred_to_dist += + packet->info.tx.cred_used; + endpoint->cred_dist.txq_depth = get_queue_depth(&endpoint->txq); + + ath6kl_dbg(ATH6KL_DBG_HTC, "htc tx ctxt 0x%p dist 0x%p\n", + target->credit_info, &target->cred_dist_list); + + ath6kl_credit_distribute(target->credit_info, + &target->cred_dist_list, + HTC_CREDIT_DIST_SEND_COMPLETE); + + spin_unlock_bh(&target->tx_lock); +} + +static void htc_tx_complete(struct htc_endpoint *endpoint, + struct list_head *txq) +{ + if (list_empty(txq)) + return; + + ath6kl_dbg(ATH6KL_DBG_HTC, + "htc tx complete ep %d pkts %d\n", + endpoint->eid, get_queue_depth(txq)); + + ath6kl_tx_complete(endpoint->target, txq); +} + +static void htc_tx_comp_handler(struct htc_target *target, + struct htc_packet *packet) +{ + struct htc_endpoint *endpoint = &target->endpoint[packet->endpoint]; + struct list_head container; + + ath6kl_dbg(ATH6KL_DBG_HTC, "htc tx complete seqno %d\n", + packet->info.tx.seqno); + + htc_tx_comp_update(target, endpoint, packet); + INIT_LIST_HEAD(&container); + list_add_tail(&packet->list, &container); + /* do completion */ + htc_tx_complete(endpoint, &container); +} + +static void htc_async_tx_scat_complete(struct htc_target *target, + struct hif_scatter_req *scat_req) +{ + struct htc_endpoint *endpoint; + struct htc_packet *packet; + struct list_head tx_compq; + int i; + + INIT_LIST_HEAD(&tx_compq); + + ath6kl_dbg(ATH6KL_DBG_HTC, + "htc tx scat complete len %d entries %d\n", + scat_req->len, scat_req->scat_entries); + + if (scat_req->status) + ath6kl_err("send scatter req failed: %d\n", scat_req->status); + + packet = scat_req->scat_list[0].packet; + endpoint = &target->endpoint[packet->endpoint]; + + /* walk through the scatter list and process */ + for (i = 0; i < scat_req->scat_entries; i++) { + packet = scat_req->scat_list[i].packet; + if (!packet) { + WARN_ON(1); + return; + } + + packet->status = scat_req->status; + htc_tx_comp_update(target, endpoint, packet); + list_add_tail(&packet->list, &tx_compq); + } + + /* free scatter request */ + hif_scatter_req_add(target->dev->ar, scat_req); + + /* complete all packets */ + htc_tx_complete(endpoint, &tx_compq); +} + +static int ath6kl_htc_tx_issue(struct htc_target *target, + struct htc_packet *packet) +{ + int status; + bool sync = false; + u32 padded_len, send_len; + + if (!packet->completion) + sync = true; + + send_len = packet->act_len + HTC_HDR_LENGTH; + + padded_len = CALC_TXRX_PADDED_LEN(target, send_len); + + ath6kl_dbg(ATH6KL_DBG_HTC, + "htc tx issue len %d seqno %d padded_len %d mbox 0x%X %s\n", + send_len, packet->info.tx.seqno, padded_len, + target->dev->ar->mbox_info.htc_addr, + sync ? "sync" : "async"); + + if (sync) { + status = hif_read_write_sync(target->dev->ar, + target->dev->ar->mbox_info.htc_addr, + packet->buf, padded_len, + HIF_WR_SYNC_BLOCK_INC); + + packet->status = status; + packet->buf += HTC_HDR_LENGTH; + } else + status = hif_write_async(target->dev->ar, + target->dev->ar->mbox_info.htc_addr, + packet->buf, padded_len, + HIF_WR_ASYNC_BLOCK_INC, packet); + + return status; +} + +static int htc_check_credits(struct htc_target *target, + struct htc_endpoint *ep, u8 *flags, + 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; + + ath6kl_dbg(ATH6KL_DBG_CREDIT, "credit check need %d got %d\n", + *req_cred, ep->cred_dist.credits); + + if (ep->cred_dist.credits < *req_cred) { + if (eid == ENDPOINT_0) + return -EINVAL; + + /* Seek more credits */ + ep->cred_dist.seek_cred = *req_cred - ep->cred_dist.credits; + + ath6kl_credit_seek(target->credit_info, &ep->cred_dist); + + ep->cred_dist.seek_cred = 0; + + if (ep->cred_dist.credits < *req_cred) { + ath6kl_dbg(ATH6KL_DBG_CREDIT, + "credit not found for ep %d\n", + eid); + return -EINVAL; + } + } + + ep->cred_dist.credits -= *req_cred; + ep->ep_st.cred_cosumd += *req_cred; + + /* When we are getting low on credits, ask for more */ + if (ep->cred_dist.credits < ep->cred_dist.cred_per_msg) { + ep->cred_dist.seek_cred = + ep->cred_dist.cred_per_msg - ep->cred_dist.credits; + + ath6kl_credit_seek(target->credit_info, &ep->cred_dist); + + /* see if we were successful in getting more */ + if (ep->cred_dist.credits < ep->cred_dist.cred_per_msg) { + /* tell the target we need credits ASAP! */ + *flags |= HTC_FLAGS_NEED_CREDIT_UPDATE; + ep->ep_st.cred_low_indicate += 1; + ath6kl_dbg(ATH6KL_DBG_CREDIT, + "credit we need credits asap\n"); + } + } + + return 0; +} + +static void ath6kl_htc_tx_pkts_get(struct htc_target *target, + struct htc_endpoint *endpoint, + struct list_head *queue) +{ + int req_cred; + u8 flags; + struct htc_packet *packet; + unsigned int len; + + while (true) { + + flags = 0; + + if (list_empty(&endpoint->txq)) + break; + packet = list_first_entry(&endpoint->txq, struct htc_packet, + list); + + ath6kl_dbg(ATH6KL_DBG_HTC, + "htc tx got packet 0x%p queue depth %d\n", + packet, get_queue_depth(&endpoint->txq)); + + len = CALC_TXRX_PADDED_LEN(target, + packet->act_len + HTC_HDR_LENGTH); + + if (htc_check_credits(target, endpoint, &flags, + packet->endpoint, len, &req_cred)) + break; + + /* now we can fully move onto caller's queue */ + packet = list_first_entry(&endpoint->txq, struct htc_packet, + list); + list_move_tail(&packet->list, queue); + + /* save the number of credits this packet consumed */ + packet->info.tx.cred_used = req_cred; + + /* all TX packets are handled asynchronously */ + packet->completion = htc_tx_comp_handler; + packet->context = target; + endpoint->ep_st.tx_issued += 1; + + /* save send flags */ + packet->info.tx.flags = flags; + packet->info.tx.seqno = endpoint->seqno; + endpoint->seqno++; + } +} + +/* See if the padded tx length falls on a credit boundary */ +static int htc_get_credit_padding(unsigned int cred_sz, int *len, + struct htc_endpoint *ep) +{ + int rem_cred, cred_pad; + + rem_cred = *len % cred_sz; + + /* No padding needed */ + if (!rem_cred) + return 0; + + if (!(ep->conn_flags & HTC_FLGS_TX_BNDL_PAD_EN)) + return -1; + + /* + * The transfer consumes a "partial" credit, this + * packet cannot be bundled unless we add + * additional "dummy" padding (max 255 bytes) to + * consume the entire credit. + */ + cred_pad = *len < cred_sz ? (cred_sz - *len) : rem_cred; + + if ((cred_pad > 0) && (cred_pad <= 255)) + *len += cred_pad; + else + /* The amount of padding is too large, send as non-bundled */ + return -1; + + return cred_pad; +} + +static int ath6kl_htc_tx_setup_scat_list(struct htc_target *target, + struct htc_endpoint *endpoint, + struct hif_scatter_req *scat_req, + int n_scat, + struct list_head *queue) +{ + struct htc_packet *packet; + int i, len, rem_scat, cred_pad; + int status = 0; + u8 flags; + + rem_scat = target->max_tx_bndl_sz; + + for (i = 0; i < n_scat; i++) { + scat_req->scat_list[i].packet = NULL; + + if (list_empty(queue)) + break; + + packet = list_first_entry(queue, struct htc_packet, list); + len = CALC_TXRX_PADDED_LEN(target, + packet->act_len + HTC_HDR_LENGTH); + + cred_pad = htc_get_credit_padding(target->tgt_cred_sz, + &len, endpoint); + if (cred_pad < 0 || rem_scat < len) { + status = -ENOSPC; + break; + } + + rem_scat -= len; + /* now remove it from the queue */ + list_del(&packet->list); + + scat_req->scat_list[i].packet = packet; + /* prepare packet and flag message as part of a send bundle */ + flags = packet->info.tx.flags | HTC_FLAGS_SEND_BUNDLE; + ath6kl_htc_tx_prep_pkt(packet, flags, + cred_pad, packet->info.tx.seqno); + /* Make sure the buffer is 4-byte aligned */ + ath6kl_htc_tx_buf_align(&packet->buf, + packet->act_len + HTC_HDR_LENGTH); + scat_req->scat_list[i].buf = packet->buf; + scat_req->scat_list[i].len = len; + + scat_req->len += len; + scat_req->scat_entries++; + ath6kl_dbg(ATH6KL_DBG_HTC, + "htc tx adding (%d) pkt 0x%p seqno %d len %d remaining %d\n", + i, packet, packet->info.tx.seqno, len, rem_scat); + } + + /* Roll back scatter setup in case of any failure */ + if (scat_req->scat_entries < HTC_MIN_HTC_MSGS_TO_BUNDLE) { + for (i = scat_req->scat_entries - 1; i >= 0; i--) { + packet = scat_req->scat_list[i].packet; + if (packet) { + packet->buf += HTC_HDR_LENGTH; + list_add(&packet->list, queue); + } + } + return -EAGAIN; + } + + return status; +} + +/* + * Drain a queue and send as bundles this function may return without fully + * draining the queue when + * + * 1. scatter resources are exhausted + * 2. a message that will consume a partial credit will stop the + * bundling process early + * 3. we drop below the minimum number of messages for a bundle + */ +static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint, + struct list_head *queue, + int *sent_bundle, int *n_bundle_pkts) +{ + struct htc_target *target = endpoint->target; + struct hif_scatter_req *scat_req = NULL; + int n_scat, n_sent_bundle = 0, tot_pkts_bundle = 0; + int status; + u32 txb_mask; + u8 ac = WMM_NUM_AC; + + if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) || + (WMI_CONTROL_SVC != endpoint->svc_id)) + ac = target->dev->ar->ep2ac_map[endpoint->eid]; + + while (true) { + status = 0; + n_scat = get_queue_depth(queue); + n_scat = min(n_scat, target->msg_per_bndl_max); + + if (n_scat < HTC_MIN_HTC_MSGS_TO_BUNDLE) + /* not enough to bundle */ + break; + + scat_req = hif_scatter_req_get(target->dev->ar); + + if (!scat_req) { + /* no scatter resources */ + ath6kl_dbg(ATH6KL_DBG_HTC, + "htc tx no more scatter resources\n"); + break; + } + + if ((ac < WMM_NUM_AC) && (ac != WMM_AC_BK)) { + if (WMM_AC_BE == ac) + /* + * BE, BK have priorities and bit + * positions reversed + */ + txb_mask = (1 << WMM_AC_BK); + else + /* + * any AC with priority lower than + * itself + */ + txb_mask = ((1 << ac) - 1); + /* + * when the scatter request resources drop below a + * certain threshold, disable Tx bundling for all + * AC's with priority lower than the current requesting + * AC. Otherwise re-enable Tx bundling for them + */ + if (scat_req->scat_q_depth < ATH6KL_SCATTER_REQS) + target->tx_bndl_mask &= ~txb_mask; + else + target->tx_bndl_mask |= txb_mask; + } + + ath6kl_dbg(ATH6KL_DBG_HTC, "htc tx pkts to scatter: %d\n", + n_scat); + + scat_req->len = 0; + scat_req->scat_entries = 0; + + status = ath6kl_htc_tx_setup_scat_list(target, endpoint, + scat_req, n_scat, + queue); + if (status == -EAGAIN) { + hif_scatter_req_add(target->dev->ar, scat_req); + break; + } + + /* send path is always asynchronous */ + scat_req->complete = htc_async_tx_scat_complete; + n_sent_bundle++; + tot_pkts_bundle += scat_req->scat_entries; + + ath6kl_dbg(ATH6KL_DBG_HTC, + "htc tx scatter bytes %d entries %d\n", + scat_req->len, scat_req->scat_entries); + ath6kl_hif_submit_scat_req(target->dev, scat_req, false); + + if (status) + break; + } + + *sent_bundle = n_sent_bundle; + *n_bundle_pkts = tot_pkts_bundle; + ath6kl_dbg(ATH6KL_DBG_HTC, "htc tx bundle sent %d pkts\n", + n_sent_bundle); + + return; +} + +static void ath6kl_htc_tx_from_queue(struct htc_target *target, + struct htc_endpoint *endpoint) +{ + struct list_head txq; + struct htc_packet *packet; + int bundle_sent; + int n_pkts_bundle; + u8 ac = WMM_NUM_AC; + + spin_lock_bh(&target->tx_lock); + + endpoint->tx_proc_cnt++; + if (endpoint->tx_proc_cnt > 1) { + endpoint->tx_proc_cnt--; + spin_unlock_bh(&target->tx_lock); + ath6kl_dbg(ATH6KL_DBG_HTC, "htc tx busy\n"); + return; + } + + /* + * drain the endpoint TX queue for transmission as long + * as we have enough credits. + */ + INIT_LIST_HEAD(&txq); + + if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) || + (WMI_CONTROL_SVC != endpoint->svc_id)) + ac = target->dev->ar->ep2ac_map[endpoint->eid]; + + while (true) { + + if (list_empty(&endpoint->txq)) + break; + + ath6kl_htc_tx_pkts_get(target, endpoint, &txq); + + if (list_empty(&txq)) + break; + + spin_unlock_bh(&target->tx_lock); + + bundle_sent = 0; + n_pkts_bundle = 0; + + while (true) { + /* try to send a bundle on each pass */ + if ((target->tx_bndl_mask) && + (get_queue_depth(&txq) >= + HTC_MIN_HTC_MSGS_TO_BUNDLE)) { + int temp1 = 0, temp2 = 0; + + /* check if bundling is enabled for an AC */ + if (target->tx_bndl_mask & (1 << ac)) { + ath6kl_htc_tx_bundle(endpoint, &txq, + &temp1, &temp2); + bundle_sent += temp1; + n_pkts_bundle += temp2; + } + } + + if (list_empty(&txq)) + break; + + packet = list_first_entry(&txq, struct htc_packet, + list); + list_del(&packet->list); + + ath6kl_htc_tx_prep_pkt(packet, packet->info.tx.flags, + 0, packet->info.tx.seqno); + ath6kl_htc_tx_issue(target, packet); + } + + spin_lock_bh(&target->tx_lock); + + endpoint->ep_st.tx_bundles += bundle_sent; + endpoint->ep_st.tx_pkt_bundled += n_pkts_bundle; + + /* + * if an AC has bundling disabled and no tx bundling + * has occured continously for a certain number of TX, + * enable tx bundling for this AC + */ + if (!bundle_sent) { + if (!(target->tx_bndl_mask & (1 << ac)) && + (ac < WMM_NUM_AC)) { + if (++target->ac_tx_count[ac] >= + TX_RESUME_BUNDLE_THRESHOLD) { + target->ac_tx_count[ac] = 0; + target->tx_bndl_mask |= (1 << ac); + } + } + } else { + /* tx bundling will reset the counter */ + if (ac < WMM_NUM_AC) + target->ac_tx_count[ac] = 0; + } + } + + endpoint->tx_proc_cnt = 0; + spin_unlock_bh(&target->tx_lock); +} + +static bool ath6kl_htc_tx_try(struct htc_target *target, + struct htc_endpoint *endpoint, + struct htc_packet *tx_pkt) +{ + struct htc_ep_callbacks ep_cb; + int txq_depth; + bool overflow = false; + + ep_cb = endpoint->ep_cb; + + spin_lock_bh(&target->tx_lock); + txq_depth = get_queue_depth(&endpoint->txq); + spin_unlock_bh(&target->tx_lock); + + if (txq_depth >= endpoint->max_txq_depth) + overflow = true; + + if (overflow) + ath6kl_dbg(ATH6KL_DBG_HTC, + "htc tx overflow ep %d depth %d max %d\n", + endpoint->eid, txq_depth, + endpoint->max_txq_depth); + + if (overflow && ep_cb.tx_full) { + if (ep_cb.tx_full(endpoint->target, tx_pkt) == + HTC_SEND_FULL_DROP) { + endpoint->ep_st.tx_dropped += 1; + return false; + } + } + + spin_lock_bh(&target->tx_lock); + list_add_tail(&tx_pkt->list, &endpoint->txq); + spin_unlock_bh(&target->tx_lock); + + ath6kl_htc_tx_from_queue(target, endpoint); + + return true; +} + +static void htc_chk_ep_txq(struct htc_target *target) +{ + struct htc_endpoint *endpoint; + struct htc_endpoint_credit_dist *cred_dist; + + /* + * Run through the credit distribution list to see if there are + * packets queued. NOTE: no locks need to be taken since the + * distribution list is not dynamic (cannot be re-ordered) and we + * are not modifying any state. + */ + list_for_each_entry(cred_dist, &target->cred_dist_list, list) { + endpoint = cred_dist->htc_ep; + + spin_lock_bh(&target->tx_lock); + if (!list_empty(&endpoint->txq)) { + ath6kl_dbg(ATH6KL_DBG_HTC, + "htc creds ep %d credits %d pkts %d\n", + cred_dist->endpoint, + endpoint->cred_dist.credits, + get_queue_depth(&endpoint->txq)); + spin_unlock_bh(&target->tx_lock); + /* + * Try to start the stalled queue, this list is + * ordered by priority. If there are credits + * available the highest priority queue will get a + * chance to reclaim credits from lower priority + * ones. + */ + ath6kl_htc_tx_from_queue(target, endpoint); + spin_lock_bh(&target->tx_lock); + } + spin_unlock_bh(&target->tx_lock); + } +} + +static int htc_setup_tx_complete(struct htc_target *target) +{ + struct htc_packet *send_pkt = NULL; + int status; + + send_pkt = htc_get_control_buf(target, true); + + if (!send_pkt) + return -ENOMEM; + + if (target->htc_tgt_ver >= HTC_VERSION_2P1) { + struct htc_setup_comp_ext_msg *setup_comp_ext; + u32 flags = 0; + + setup_comp_ext = + (struct htc_setup_comp_ext_msg *)send_pkt->buf; + memset(setup_comp_ext, 0, sizeof(*setup_comp_ext)); + setup_comp_ext->msg_id = + cpu_to_le16(HTC_MSG_SETUP_COMPLETE_EX_ID); + + if (target->msg_per_bndl_max > 0) { + /* Indicate HTC bundling to the target */ + flags |= HTC_SETUP_COMP_FLG_RX_BNDL_EN; + setup_comp_ext->msg_per_rxbndl = + target->msg_per_bndl_max; + } + + memcpy(&setup_comp_ext->flags, &flags, + sizeof(setup_comp_ext->flags)); + set_htc_pkt_info(send_pkt, NULL, (u8 *) setup_comp_ext, + sizeof(struct htc_setup_comp_ext_msg), + ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); + + } else { + struct htc_setup_comp_msg *setup_comp; + setup_comp = (struct htc_setup_comp_msg *)send_pkt->buf; + memset(setup_comp, 0, sizeof(struct htc_setup_comp_msg)); + setup_comp->msg_id = cpu_to_le16(HTC_MSG_SETUP_COMPLETE_ID); + set_htc_pkt_info(send_pkt, NULL, (u8 *) setup_comp, + sizeof(struct htc_setup_comp_msg), + ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); + } + + /* we want synchronous operation */ + send_pkt->completion = NULL; + ath6kl_htc_tx_prep_pkt(send_pkt, 0, 0, 0); + status = ath6kl_htc_tx_issue(target, send_pkt); + + if (send_pkt != NULL) + htc_reclaim_txctrl_buf(target, send_pkt); + + return status; +} + +static void ath6kl_htc_set_credit_dist(struct htc_target *target, + struct ath6kl_htc_credit_info *credit_info, + u16 srvc_pri_order[], int list_len) +{ + struct htc_endpoint *endpoint; + int i, ep; + + target->credit_info = credit_info; + + list_add_tail(&target->endpoint[ENDPOINT_0].cred_dist.list, + &target->cred_dist_list); + + for (i = 0; i < list_len; i++) { + for (ep = ENDPOINT_1; ep < ENDPOINT_MAX; ep++) { + endpoint = &target->endpoint[ep]; + if (endpoint->svc_id == srvc_pri_order[i]) { + list_add_tail(&endpoint->cred_dist.list, + &target->cred_dist_list); + break; + } + } + if (ep >= ENDPOINT_MAX) { + WARN_ON(1); + return; + } + } +} + +static int ath6kl_htc_mbox_tx(struct htc_target *target, + struct htc_packet *packet) +{ + struct htc_endpoint *endpoint; + struct list_head queue; + + ath6kl_dbg(ATH6KL_DBG_HTC, + "htc tx ep id %d buf 0x%p len %d\n", + packet->endpoint, packet->buf, packet->act_len); + + if (packet->endpoint >= ENDPOINT_MAX) { + WARN_ON(1); + return -EINVAL; + } + + endpoint = &target->endpoint[packet->endpoint]; + + if (!ath6kl_htc_tx_try(target, endpoint, packet)) { + packet->status = (target->htc_flags & HTC_OP_STATE_STOPPING) ? + -ECANCELED : -ENOSPC; + INIT_LIST_HEAD(&queue); + list_add(&packet->list, &queue); + htc_tx_complete(endpoint, &queue); + } + + return 0; +} + +/* flush endpoint TX queue */ +static void ath6kl_htc_mbox_flush_txep(struct htc_target *target, + enum htc_endpoint_id eid, u16 tag) +{ + struct htc_packet *packet, *tmp_pkt; + struct list_head discard_q, container; + struct htc_endpoint *endpoint = &target->endpoint[eid]; + + if (!endpoint->svc_id) { + WARN_ON(1); + return; + } + + /* initialize the discard queue */ + INIT_LIST_HEAD(&discard_q); + + spin_lock_bh(&target->tx_lock); + + list_for_each_entry_safe(packet, tmp_pkt, &endpoint->txq, list) { + if ((tag == HTC_TX_PACKET_TAG_ALL) || + (tag == packet->info.tx.tag)) + list_move_tail(&packet->list, &discard_q); + } + + spin_unlock_bh(&target->tx_lock); + + list_for_each_entry_safe(packet, tmp_pkt, &discard_q, list) { + packet->status = -ECANCELED; + list_del(&packet->list); + ath6kl_dbg(ATH6KL_DBG_HTC, + "htc tx flushing pkt 0x%p len %d ep %d tag 0x%x\n", + packet, packet->act_len, + packet->endpoint, packet->info.tx.tag); + + INIT_LIST_HEAD(&container); + list_add_tail(&packet->list, &container); + htc_tx_complete(endpoint, &container); + } + +} + +static void ath6kl_htc_flush_txep_all(struct htc_target *target) +{ + struct htc_endpoint *endpoint; + int i; + + dump_cred_dist_stats(target); + + for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) { + endpoint = &target->endpoint[i]; + if (endpoint->svc_id == 0) + /* not in use.. */ + continue; + ath6kl_htc_mbox_flush_txep(target, i, HTC_TX_PACKET_TAG_ALL); + } +} + +static void ath6kl_htc_mbox_activity_changed(struct htc_target *target, + enum htc_endpoint_id eid, + bool active) +{ + struct htc_endpoint *endpoint = &target->endpoint[eid]; + bool dist = false; + + if (endpoint->svc_id == 0) { + WARN_ON(1); + return; + } + + spin_lock_bh(&target->tx_lock); + + if (active) { + if (!(endpoint->cred_dist.dist_flags & HTC_EP_ACTIVE)) { + endpoint->cred_dist.dist_flags |= HTC_EP_ACTIVE; + dist = true; + } + } else { + if (endpoint->cred_dist.dist_flags & HTC_EP_ACTIVE) { + endpoint->cred_dist.dist_flags &= ~HTC_EP_ACTIVE; + dist = true; + } + } + + if (dist) { + endpoint->cred_dist.txq_depth = + get_queue_depth(&endpoint->txq); + + ath6kl_dbg(ATH6KL_DBG_HTC, + "htc tx activity ctxt 0x%p dist 0x%p\n", + target->credit_info, &target->cred_dist_list); + + ath6kl_credit_distribute(target->credit_info, + &target->cred_dist_list, + HTC_CREDIT_DIST_ACTIVITY_CHANGE); + } + + spin_unlock_bh(&target->tx_lock); + + if (dist && !active) + htc_chk_ep_txq(target); +} + +/* HTC Rx */ + +static inline void ath6kl_htc_rx_update_stats(struct htc_endpoint *endpoint, + int n_look_ahds) +{ + endpoint->ep_st.rx_pkts++; + if (n_look_ahds == 1) + endpoint->ep_st.rx_lkahds++; + else if (n_look_ahds > 1) + endpoint->ep_st.rx_bundle_lkahd++; +} + +static inline bool htc_valid_rx_frame_len(struct htc_target *target, + enum htc_endpoint_id eid, int len) +{ + return (eid == target->dev->ar->ctrl_ep) ? + len <= ATH6KL_BUFFER_SIZE : len <= ATH6KL_AMSDU_BUFFER_SIZE; +} + +static int htc_add_rxbuf(struct htc_target *target, struct htc_packet *packet) +{ + struct list_head queue; + + INIT_LIST_HEAD(&queue); + list_add_tail(&packet->list, &queue); + return ath6kl_htc_mbox_add_rxbuf_multiple(target, &queue); +} + +static void htc_reclaim_rxbuf(struct htc_target *target, + struct htc_packet *packet, + struct htc_endpoint *ep) +{ + if (packet->info.rx.rx_flags & HTC_RX_PKT_NO_RECYCLE) { + htc_rxpkt_reset(packet); + packet->status = -ECANCELED; + ep->ep_cb.rx(ep->target, packet); + } else { + htc_rxpkt_reset(packet); + htc_add_rxbuf((void *)(target), packet); + } +} + +static void reclaim_rx_ctrl_buf(struct htc_target *target, + struct htc_packet *packet) +{ + spin_lock_bh(&target->htc_lock); + list_add_tail(&packet->list, &target->free_ctrl_rxbuf); + spin_unlock_bh(&target->htc_lock); +} + +static int ath6kl_htc_rx_packet(struct htc_target *target, + struct htc_packet *packet, + u32 rx_len) +{ + struct ath6kl_device *dev = target->dev; + u32 padded_len; + int status; + + padded_len = CALC_TXRX_PADDED_LEN(target, rx_len); + + if (padded_len > packet->buf_len) { + ath6kl_err("not enough receive space for packet - padlen %d recvlen %d bufferlen %d\n", + padded_len, rx_len, packet->buf_len); + return -ENOMEM; + } + + ath6kl_dbg(ATH6KL_DBG_HTC, + "htc rx 0x%p hdr x%x len %d mbox 0x%x\n", + packet, packet->info.rx.exp_hdr, + padded_len, dev->ar->mbox_info.htc_addr); + + status = hif_read_write_sync(dev->ar, + dev->ar->mbox_info.htc_addr, + packet->buf, padded_len, + HIF_RD_SYNC_BLOCK_FIX); + + packet->status = status; + + return status; +} + +/* + * optimization for recv packets, we can indicate a + * "hint" that there are more single-packets to fetch + * on this endpoint. + */ +static void ath6kl_htc_rx_set_indicate(u32 lk_ahd, + struct htc_endpoint *endpoint, + struct htc_packet *packet) +{ + struct htc_frame_hdr *htc_hdr = (struct htc_frame_hdr *)&lk_ahd; + + if (htc_hdr->eid == packet->endpoint) { + if (!list_empty(&endpoint->rx_bufq)) + packet->info.rx.indicat_flags |= + HTC_RX_FLAGS_INDICATE_MORE_PKTS; + } +} + +static void ath6kl_htc_rx_chk_water_mark(struct htc_endpoint *endpoint) +{ + struct htc_ep_callbacks ep_cb = endpoint->ep_cb; + + if (ep_cb.rx_refill_thresh > 0) { + spin_lock_bh(&endpoint->target->rx_lock); + if (get_queue_depth(&endpoint->rx_bufq) + < ep_cb.rx_refill_thresh) { + spin_unlock_bh(&endpoint->target->rx_lock); + ep_cb.rx_refill(endpoint->target, endpoint->eid); + return; + } + spin_unlock_bh(&endpoint->target->rx_lock); + } +} + +/* This function is called with rx_lock held */ +static int ath6kl_htc_rx_setup(struct htc_target *target, + struct htc_endpoint *ep, + u32 *lk_ahds, struct list_head *queue, int n_msg) +{ + struct htc_packet *packet; + /* FIXME: type of lk_ahds can't be right */ + struct htc_frame_hdr *htc_hdr = (struct htc_frame_hdr *)lk_ahds; + struct htc_ep_callbacks ep_cb; + int status = 0, j, full_len; + bool no_recycle; + + full_len = CALC_TXRX_PADDED_LEN(target, + le16_to_cpu(htc_hdr->payld_len) + + sizeof(*htc_hdr)); + + if (!htc_valid_rx_frame_len(target, ep->eid, full_len)) { + ath6kl_warn("Rx buffer requested with invalid length htc_hdr:eid %d, flags 0x%x, len %d\n", + htc_hdr->eid, htc_hdr->flags, + le16_to_cpu(htc_hdr->payld_len)); + return -EINVAL; + } + + 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 + * cleanup,they must be explicitly returned. + */ + no_recycle = false; + + if (ep_cb.rx_allocthresh && + (full_len > ep_cb.rx_alloc_thresh)) { + ep->ep_st.rx_alloc_thresh_hit += 1; + ep->ep_st.rxalloc_thresh_byte += + le16_to_cpu(htc_hdr->payld_len); + + spin_unlock_bh(&target->rx_lock); + no_recycle = true; + + packet = ep_cb.rx_allocthresh(ep->target, ep->eid, + full_len); + spin_lock_bh(&target->rx_lock); + } else { + /* refill handler is being used */ + if (list_empty(&ep->rx_bufq)) { + if (ep_cb.rx_refill) { + spin_unlock_bh(&target->rx_lock); + ep_cb.rx_refill(ep->target, ep->eid); + spin_lock_bh(&target->rx_lock); + } + } + + if (list_empty(&ep->rx_bufq)) + packet = NULL; + else { + packet = list_first_entry(&ep->rx_bufq, + struct htc_packet, list); + list_del(&packet->list); + } + } + + if (!packet) { + target->rx_st_flags |= HTC_RECV_WAIT_BUFFERS; + target->ep_waiting = ep->eid; + return -ENOSPC; + } + + /* clear flags */ + packet->info.rx.rx_flags = 0; + packet->info.rx.indicat_flags = 0; + packet->status = 0; + + if (no_recycle) + /* + * flag that these packets cannot be + * recycled, they have to be returned to + * the user + */ + packet->info.rx.rx_flags |= HTC_RX_PKT_NO_RECYCLE; + + /* Caller needs to free this upon any failure */ + list_add_tail(&packet->list, queue); + + if (target->htc_flags & HTC_OP_STATE_STOPPING) { + status = -ECANCELED; + break; + } + + if (j) { + packet->info.rx.rx_flags |= HTC_RX_PKT_REFRESH_HDR; + packet->info.rx.exp_hdr = 0xFFFFFFFF; + } else + /* set expected look ahead */ + packet->info.rx.exp_hdr = *lk_ahds; + + packet->act_len = le16_to_cpu(htc_hdr->payld_len) + + HTC_HDR_LENGTH; + } + + return status; +} + +static int ath6kl_htc_rx_alloc(struct htc_target *target, + u32 lk_ahds[], int msg, + struct htc_endpoint *endpoint, + struct list_head *queue) +{ + int status = 0; + struct htc_packet *packet, *tmp_pkt; + struct htc_frame_hdr *htc_hdr; + int i, n_msg; + + 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) { + ath6kl_err("invalid ep in look-ahead: %d\n", + htc_hdr->eid); + status = -ENOMEM; + break; + } + + if (htc_hdr->eid != endpoint->eid) { + ath6kl_err("invalid ep in look-ahead: %d should be : %d (index:%d)\n", + htc_hdr->eid, endpoint->eid, i); + status = -ENOMEM; + break; + } + + if (le16_to_cpu(htc_hdr->payld_len) > HTC_MAX_PAYLOAD_LENGTH) { + ath6kl_err("payload len %d exceeds max htc : %d !\n", + htc_hdr->payld_len, + (u32) HTC_MAX_PAYLOAD_LENGTH); + status = -ENOMEM; + break; + } + + if (endpoint->svc_id == 0) { + ath6kl_err("ep %d is not connected !\n", htc_hdr->eid); + status = -ENOMEM; + break; + } + + if (htc_hdr->flags & HTC_FLG_RX_BNDL_CNT) { + /* + * HTC header indicates that every packet to follow + * has the same padded length so that it can be + * optimally fetched as a full bundle. + */ + n_msg = (htc_hdr->flags & HTC_FLG_RX_BNDL_CNT) >> + HTC_FLG_RX_BNDL_CNT_S; + + /* the count doesn't include the starter frame */ + n_msg++; + if (n_msg > target->msg_per_bndl_max) { + status = -ENOMEM; + break; + } + + endpoint->ep_st.rx_bundle_from_hdr += 1; + ath6kl_dbg(ATH6KL_DBG_HTC, + "htc rx bundle pkts %d\n", + n_msg); + } else + /* HTC header only indicates 1 message to fetch */ + n_msg = 1; + + /* Setup packet buffers for each message */ + status = ath6kl_htc_rx_setup(target, endpoint, &lk_ahds[i], + queue, n_msg); + + /* + * This is due to unavailabilty of buffers to rx entire data. + * Return no error so that free buffers from queue can be used + * to receive partial data. + */ + if (status == -ENOSPC) { + spin_unlock_bh(&target->rx_lock); + return 0; + } + + if (status) + break; + } + + spin_unlock_bh(&target->rx_lock); + + if (status) { + list_for_each_entry_safe(packet, tmp_pkt, queue, list) { + list_del(&packet->list); + htc_reclaim_rxbuf(target, packet, + &target->endpoint[packet->endpoint]); + } + } + + return status; +} + +static void htc_ctrl_rx(struct htc_target *context, struct htc_packet *packets) +{ + if (packets->endpoint != ENDPOINT_0) { + WARN_ON(1); + return; + } + + if (packets->status == -ECANCELED) { + reclaim_rx_ctrl_buf(context, packets); + return; + } + + if (packets->act_len > 0) { + ath6kl_err("htc_ctrl_rx, got message with len:%zu\n", + packets->act_len + HTC_HDR_LENGTH); + + ath6kl_dbg_dump(ATH6KL_DBG_HTC, + "htc rx unexpected endpoint 0 message", "", + packets->buf - HTC_HDR_LENGTH, + packets->act_len + HTC_HDR_LENGTH); + } + + htc_reclaim_rxbuf(context, packets, &context->endpoint[0]); +} + +static void htc_proc_cred_rpt(struct htc_target *target, + struct htc_credit_report *rpt, + int n_entries, + enum htc_endpoint_id from_ep) +{ + struct htc_endpoint *endpoint; + int tot_credits = 0, i; + bool dist = false; + + spin_lock_bh(&target->tx_lock); + + for (i = 0; i < n_entries; i++, rpt++) { + if (rpt->eid >= ENDPOINT_MAX) { + WARN_ON(1); + spin_unlock_bh(&target->tx_lock); + return; + } + + endpoint = &target->endpoint[rpt->eid]; + + ath6kl_dbg(ATH6KL_DBG_CREDIT, + "credit report ep %d credits %d\n", + rpt->eid, rpt->credits); + + endpoint->ep_st.tx_cred_rpt += 1; + endpoint->ep_st.cred_retnd += rpt->credits; + + if (from_ep == rpt->eid) { + /* + * This credit report arrived on the same endpoint + * indicating it arrived in an RX packet. + */ + endpoint->ep_st.cred_from_rx += rpt->credits; + endpoint->ep_st.cred_rpt_from_rx += 1; + } else if (from_ep == ENDPOINT_0) { + /* credit arrived on endpoint 0 as a NULL message */ + endpoint->ep_st.cred_from_ep0 += rpt->credits; + endpoint->ep_st.cred_rpt_ep0 += 1; + } else { + endpoint->ep_st.cred_from_other += rpt->credits; + endpoint->ep_st.cred_rpt_from_other += 1; + } + + if (rpt->eid == ENDPOINT_0) + /* always give endpoint 0 credits back */ + endpoint->cred_dist.credits += rpt->credits; + else { + endpoint->cred_dist.cred_to_dist += rpt->credits; + dist = true; + } + + /* + * Refresh tx depth for distribution function that will + * recover these credits NOTE: this is only valid when + * there are credits to recover! + */ + endpoint->cred_dist.txq_depth = + get_queue_depth(&endpoint->txq); + + tot_credits += rpt->credits; + } + + if (dist) { + /* + * This was a credit return based on a completed send + * operations note, this is done with the lock held + */ + ath6kl_credit_distribute(target->credit_info, + &target->cred_dist_list, + HTC_CREDIT_DIST_SEND_COMPLETE); + } + + spin_unlock_bh(&target->tx_lock); + + if (tot_credits) + htc_chk_ep_txq(target); +} + +static int htc_parse_trailer(struct htc_target *target, + struct htc_record_hdr *record, + u8 *record_buf, u32 *next_lk_ahds, + enum htc_endpoint_id endpoint, + int *n_lk_ahds) +{ + struct htc_bundle_lkahd_rpt *bundle_lkahd_rpt; + struct htc_lookahead_report *lk_ahd; + int len; + + switch (record->rec_id) { + case HTC_RECORD_CREDITS: + len = record->len / sizeof(struct htc_credit_report); + if (!len) { + WARN_ON(1); + return -EINVAL; + } + + htc_proc_cred_rpt(target, + (struct htc_credit_report *) record_buf, + len, endpoint); + break; + case HTC_RECORD_LOOKAHEAD: + len = record->len / sizeof(*lk_ahd); + if (!len) { + WARN_ON(1); + return -EINVAL; + } + + 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); + + /* look ahead bytes are valid, copy them over */ + memcpy((u8 *)&next_lk_ahds[0], lk_ahd->lk_ahd, 4); + + ath6kl_dbg_dump(ATH6KL_DBG_HTC, + "htc rx next look ahead", + "", next_lk_ahds, 4); + + *n_lk_ahds = 1; + } + break; + case HTC_RECORD_LOOKAHEAD_BUNDLE: + len = record->len / sizeof(*bundle_lkahd_rpt); + if (!len || (len > HTC_HOST_MAX_MSG_PER_BUNDLE)) { + WARN_ON(1); + return -EINVAL; + } + + if (next_lk_ahds) { + int i; + + bundle_lkahd_rpt = + (struct htc_bundle_lkahd_rpt *) record_buf; + + ath6kl_dbg_dump(ATH6KL_DBG_HTC, "htc rx bundle lk_ahd", + "", record_buf, record->len); + + for (i = 0; i < len; i++) { + memcpy((u8 *)&next_lk_ahds[i], + bundle_lkahd_rpt->lk_ahd, 4); + bundle_lkahd_rpt++; + } + + *n_lk_ahds = i; + } + break; + default: + ath6kl_err("unhandled record: id:%d len:%d\n", + record->rec_id, record->len); + break; + } + + return 0; + +} + +static int htc_proc_trailer(struct htc_target *target, + u8 *buf, int len, u32 *next_lk_ahds, + int *n_lk_ahds, enum htc_endpoint_id endpoint) +{ + struct htc_record_hdr *record; + int orig_len; + int status; + u8 *record_buf; + u8 *orig_buf; + + ath6kl_dbg(ATH6KL_DBG_HTC, "htc rx trailer len %d\n", len); + ath6kl_dbg_dump(ATH6KL_DBG_HTC, NULL, "", buf, len); + + orig_buf = buf; + orig_len = len; + status = 0; + + while (len > 0) { + + if (len < sizeof(struct htc_record_hdr)) { + status = -ENOMEM; + break; + } + /* these are byte aligned structs */ + record = (struct htc_record_hdr *) buf; + len -= sizeof(struct htc_record_hdr); + buf += sizeof(struct htc_record_hdr); + + if (record->len > len) { + ath6kl_err("invalid record len: %d (id:%d) buf has: %d bytes left\n", + record->len, record->rec_id, len); + status = -ENOMEM; + break; + } + record_buf = buf; + + status = htc_parse_trailer(target, record, record_buf, + next_lk_ahds, endpoint, n_lk_ahds); + + if (status) + break; + + /* advance buffer past this record for next time around */ + buf += record->len; + len -= record->len; + } + + if (status) + ath6kl_dbg_dump(ATH6KL_DBG_HTC, "htc rx bad trailer", + "", orig_buf, orig_len); + + return status; +} + +static int ath6kl_htc_rx_process_hdr(struct htc_target *target, + struct htc_packet *packet, + u32 *next_lkahds, int *n_lkahds) +{ + int status = 0; + u16 payload_len; + u32 lk_ahd; + struct htc_frame_hdr *htc_hdr = (struct htc_frame_hdr *)packet->buf; + + if (n_lkahds != NULL) + *n_lkahds = 0; + + /* + * NOTE: we cannot assume the alignment of buf, so we use the safe + * macros to retrieve 16 bit fields. + */ + payload_len = le16_to_cpu(get_unaligned(&htc_hdr->payld_len)); + + memcpy((u8 *)&lk_ahd, packet->buf, sizeof(lk_ahd)); + + if (packet->info.rx.rx_flags & HTC_RX_PKT_REFRESH_HDR) { + /* + * Refresh the expected header and the actual length as it + * was unknown when this packet was grabbed as part of the + * bundle. + */ + packet->info.rx.exp_hdr = lk_ahd; + packet->act_len = payload_len + HTC_HDR_LENGTH; + + /* validate the actual header that was refreshed */ + if (packet->act_len > packet->buf_len) { + ath6kl_err("refreshed hdr payload len (%d) in bundled recv is invalid (hdr: 0x%X)\n", + payload_len, lk_ahd); + /* + * Limit this to max buffer just to print out some + * of the buffer. + */ + packet->act_len = min(packet->act_len, packet->buf_len); + status = -ENOMEM; + goto fail_rx; + } + + if (packet->endpoint != htc_hdr->eid) { + ath6kl_err("refreshed hdr ep (%d) does not match expected ep (%d)\n", + htc_hdr->eid, packet->endpoint); + status = -ENOMEM; + goto fail_rx; + } + } + + if (lk_ahd != packet->info.rx.exp_hdr) { + ath6kl_err("%s(): lk_ahd mismatch! (pPkt:0x%p flags:0x%X)\n", + __func__, packet, packet->info.rx.rx_flags); + ath6kl_dbg_dump(ATH6KL_DBG_HTC, "htc rx expected lk_ahd", + "", &packet->info.rx.exp_hdr, 4); + ath6kl_dbg_dump(ATH6KL_DBG_HTC, "htc rx current header", + "", (u8 *)&lk_ahd, sizeof(lk_ahd)); + status = -ENOMEM; + goto fail_rx; + } + + if (htc_hdr->flags & HTC_FLG_RX_TRAILER) { + if (htc_hdr->ctrl[0] < sizeof(struct htc_record_hdr) || + htc_hdr->ctrl[0] > payload_len) { + ath6kl_err("%s(): invalid hdr (payload len should be :%d, CB[0] is:%d)\n", + __func__, payload_len, htc_hdr->ctrl[0]); + status = -ENOMEM; + goto fail_rx; + } + + if (packet->info.rx.rx_flags & HTC_RX_PKT_IGNORE_LOOKAHEAD) { + next_lkahds = NULL; + n_lkahds = NULL; + } + + status = htc_proc_trailer(target, packet->buf + HTC_HDR_LENGTH + + payload_len - htc_hdr->ctrl[0], + htc_hdr->ctrl[0], next_lkahds, + n_lkahds, packet->endpoint); + + if (status) + goto fail_rx; + + packet->act_len -= htc_hdr->ctrl[0]; + } + + packet->buf += HTC_HDR_LENGTH; + packet->act_len -= HTC_HDR_LENGTH; + +fail_rx: + if (status) + ath6kl_dbg_dump(ATH6KL_DBG_HTC, "htc rx bad packet", + "", packet->buf, packet->act_len); + + return status; +} + +static void ath6kl_htc_rx_complete(struct htc_endpoint *endpoint, + struct htc_packet *packet) +{ + ath6kl_dbg(ATH6KL_DBG_HTC, + "htc rx complete ep %d packet 0x%p\n", + endpoint->eid, packet); + endpoint->ep_cb.rx(endpoint->target, packet); +} + +static int ath6kl_htc_rx_bundle(struct htc_target *target, + struct list_head *rxq, + struct list_head *sync_compq, + int *n_pkt_fetched, bool part_bundle) +{ + struct hif_scatter_req *scat_req; + struct htc_packet *packet; + int rem_space = target->max_rx_bndl_sz; + int n_scat_pkt, status = 0, i, len; + + n_scat_pkt = get_queue_depth(rxq); + n_scat_pkt = min(n_scat_pkt, target->msg_per_bndl_max); + + if ((get_queue_depth(rxq) - n_scat_pkt) > 0) { + /* + * We were forced to split this bundle receive operation + * all packets in this partial bundle must have their + * lookaheads ignored. + */ + part_bundle = true; + + /* + * This would only happen if the target ignored our max + * bundle limit. + */ + ath6kl_warn("%s(): partial bundle detected num:%d , %d\n", + __func__, get_queue_depth(rxq), n_scat_pkt); + } + + len = 0; + + ath6kl_dbg(ATH6KL_DBG_HTC, + "htc rx bundle depth %d pkts %d\n", + get_queue_depth(rxq), n_scat_pkt); + + scat_req = hif_scatter_req_get(target->dev->ar); + + if (scat_req == NULL) + goto fail_rx_pkt; + + for (i = 0; i < n_scat_pkt; i++) { + int pad_len; + + packet = list_first_entry(rxq, struct htc_packet, list); + list_del(&packet->list); + + pad_len = CALC_TXRX_PADDED_LEN(target, + packet->act_len); + + if ((rem_space - pad_len) < 0) { + list_add(&packet->list, rxq); + break; + } + + rem_space -= pad_len; + + if (part_bundle || (i < (n_scat_pkt - 1))) + /* + * Packet 0..n-1 cannot be checked for look-aheads + * since we are fetching a bundle the last packet + * however can have it's lookahead used + */ + packet->info.rx.rx_flags |= + HTC_RX_PKT_IGNORE_LOOKAHEAD; + + /* NOTE: 1 HTC packet per scatter entry */ + scat_req->scat_list[i].buf = packet->buf; + scat_req->scat_list[i].len = pad_len; + + packet->info.rx.rx_flags |= HTC_RX_PKT_PART_OF_BUNDLE; + + list_add_tail(&packet->list, sync_compq); + + WARN_ON(!scat_req->scat_list[i].len); + len += scat_req->scat_list[i].len; + } + + scat_req->len = len; + scat_req->scat_entries = i; + + status = ath6kl_hif_submit_scat_req(target->dev, scat_req, true); + + if (!status) + *n_pkt_fetched = i; + + /* free scatter request */ + hif_scatter_req_add(target->dev->ar, scat_req); + +fail_rx_pkt: + + return status; +} + +static int ath6kl_htc_rx_process_packets(struct htc_target *target, + struct list_head *comp_pktq, + u32 lk_ahds[], + int *n_lk_ahd) +{ + struct htc_packet *packet, *tmp_pkt; + struct htc_endpoint *ep; + int status = 0; + + list_for_each_entry_safe(packet, tmp_pkt, comp_pktq, list) { + ep = &target->endpoint[packet->endpoint]; + + /* process header for each of the recv packet */ + status = ath6kl_htc_rx_process_hdr(target, packet, lk_ahds, + n_lk_ahd); + if (status) + return status; + + list_del(&packet->list); + + if (list_empty(comp_pktq)) { + /* + * Last packet's more packet flag is set + * based on the lookahead. + */ + if (*n_lk_ahd > 0) + ath6kl_htc_rx_set_indicate(lk_ahds[0], + ep, packet); + } else + /* + * Packets in a bundle automatically have + * this flag set. + */ + packet->info.rx.indicat_flags |= + HTC_RX_FLAGS_INDICATE_MORE_PKTS; + + ath6kl_htc_rx_update_stats(ep, *n_lk_ahd); + + if (packet->info.rx.rx_flags & HTC_RX_PKT_PART_OF_BUNDLE) + ep->ep_st.rx_bundl += 1; + + ath6kl_htc_rx_complete(ep, packet); + } + + return status; +} + +static int ath6kl_htc_rx_fetch(struct htc_target *target, + struct list_head *rx_pktq, + struct list_head *comp_pktq) +{ + int fetched_pkts; + bool part_bundle = false; + int status = 0; + struct list_head tmp_rxq; + struct htc_packet *packet, *tmp_pkt; + + /* now go fetch the list of HTC packets */ + while (!list_empty(rx_pktq)) { + fetched_pkts = 0; + + INIT_LIST_HEAD(&tmp_rxq); + + if (target->rx_bndl_enable && (get_queue_depth(rx_pktq) > 1)) { + /* + * There are enough packets to attempt a + * bundle transfer and recv bundling is + * allowed. + */ + status = ath6kl_htc_rx_bundle(target, rx_pktq, + &tmp_rxq, + &fetched_pkts, + part_bundle); + if (status) + goto fail_rx; + + if (!list_empty(rx_pktq)) + part_bundle = true; + + list_splice_tail_init(&tmp_rxq, comp_pktq); + } + + if (!fetched_pkts) { + + packet = list_first_entry(rx_pktq, struct htc_packet, + list); + + /* fully synchronous */ + packet->completion = NULL; + + if (!list_is_singular(rx_pktq)) + /* + * look_aheads in all packet + * except the last one in the + * bundle must be ignored + */ + packet->info.rx.rx_flags |= + HTC_RX_PKT_IGNORE_LOOKAHEAD; + + /* go fetch the packet */ + status = ath6kl_htc_rx_packet(target, packet, + packet->act_len); + + list_move_tail(&packet->list, &tmp_rxq); + + if (status) + goto fail_rx; + + list_splice_tail_init(&tmp_rxq, comp_pktq); + } + } + + return 0; + +fail_rx: + + /* + * Cleanup any packets we allocated but didn't use to + * actually fetch any packets. + */ + + list_for_each_entry_safe(packet, tmp_pkt, rx_pktq, list) { + list_del(&packet->list); + htc_reclaim_rxbuf(target, packet, + &target->endpoint[packet->endpoint]); + } + + list_for_each_entry_safe(packet, tmp_pkt, &tmp_rxq, list) { + list_del(&packet->list); + htc_reclaim_rxbuf(target, packet, + &target->endpoint[packet->endpoint]); + } + + return status; +} + +int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target, + u32 msg_look_ahead, int *num_pkts) +{ + struct htc_packet *packets, *tmp_pkt; + struct htc_endpoint *endpoint; + struct list_head rx_pktq, comp_pktq; + int status = 0; + u32 look_aheads[HTC_HOST_MAX_MSG_PER_BUNDLE]; + int num_look_ahead = 1; + enum htc_endpoint_id id; + int n_fetched = 0; + + INIT_LIST_HEAD(&comp_pktq); + *num_pkts = 0; + + /* + * On first entry copy the look_aheads into our temp array for + * processing + */ + look_aheads[0] = msg_look_ahead; + + while (true) { + + /* + * First lookahead sets the expected endpoint IDs for all + * packets in a bundle. + */ + id = ((struct htc_frame_hdr *)&look_aheads[0])->eid; + endpoint = &target->endpoint[id]; + + if (id >= ENDPOINT_MAX) { + ath6kl_err("MsgPend, invalid endpoint in look-ahead: %d\n", + id); + status = -ENOMEM; + break; + } + + INIT_LIST_HEAD(&rx_pktq); + INIT_LIST_HEAD(&comp_pktq); + + /* + * Try to allocate as many HTC RX packets indicated by the + * look_aheads. + */ + status = ath6kl_htc_rx_alloc(target, look_aheads, + num_look_ahead, endpoint, + &rx_pktq); + if (status) + break; + + if (get_queue_depth(&rx_pktq) >= 2) + /* + * A recv bundle was detected, force IRQ status + * re-check again + */ + target->chk_irq_status_cnt = 1; + + n_fetched += get_queue_depth(&rx_pktq); + + num_look_ahead = 0; + + status = ath6kl_htc_rx_fetch(target, &rx_pktq, &comp_pktq); + + if (!status) + ath6kl_htc_rx_chk_water_mark(endpoint); + + /* Process fetched packets */ + status = ath6kl_htc_rx_process_packets(target, &comp_pktq, + look_aheads, + &num_look_ahead); + + if (!num_look_ahead || status) + break; + + /* + * For SYNCH processing, if we get here, we are running + * through the loop again due to a detected lookahead. Set + * flag that we should re-check IRQ status registers again + * before leaving IRQ processing, this can net better + * performance in high throughput situations. + */ + target->chk_irq_status_cnt = 1; + } + + if (status) { + ath6kl_err("failed to get pending recv messages: %d\n", + status); + + /* cleanup any packets in sync completion queue */ + list_for_each_entry_safe(packets, tmp_pkt, &comp_pktq, list) { + list_del(&packets->list); + htc_reclaim_rxbuf(target, packets, + &target->endpoint[packets->endpoint]); + } + + if (target->htc_flags & HTC_OP_STATE_STOPPING) { + ath6kl_warn("host is going to stop blocking receiver for htc_stop\n"); + ath6kl_hif_rx_control(target->dev, false); + } + } + + /* + * Before leaving, check to see if host ran out of buffers and + * needs to stop the receiver. + */ + if (target->rx_st_flags & HTC_RECV_WAIT_BUFFERS) { + ath6kl_warn("host has no rx buffers blocking receiver to prevent overrun\n"); + ath6kl_hif_rx_control(target->dev, false); + } + *num_pkts = n_fetched; + + return status; +} + +/* + * Synchronously wait for a control message from the target, + * This function is used at initialization time ONLY. At init messages + * on ENDPOINT 0 are expected. + */ +static struct htc_packet *htc_wait_for_ctrl_msg(struct htc_target *target) +{ + struct htc_packet *packet = NULL; + struct htc_frame_hdr *htc_hdr; + u32 look_ahead; + + if (ath6kl_hif_poll_mboxmsg_rx(target->dev, &look_ahead, + HTC_TARGET_RESPONSE_TIMEOUT)) + return NULL; + + ath6kl_dbg(ATH6KL_DBG_HTC, + "htc rx wait ctrl look_ahead 0x%X\n", look_ahead); + + htc_hdr = (struct htc_frame_hdr *)&look_ahead; + + if (htc_hdr->eid != ENDPOINT_0) + return NULL; + + packet = htc_get_control_buf(target, false); + + if (!packet) + return NULL; + + packet->info.rx.rx_flags = 0; + packet->info.rx.exp_hdr = look_ahead; + packet->act_len = le16_to_cpu(htc_hdr->payld_len) + HTC_HDR_LENGTH; + + if (packet->act_len > packet->buf_len) + goto fail_ctrl_rx; + + /* we want synchronous operation */ + packet->completion = NULL; + + /* get the message from the device, this will block */ + if (ath6kl_htc_rx_packet(target, packet, packet->act_len)) + goto fail_ctrl_rx; + + /* process receive header */ + packet->status = ath6kl_htc_rx_process_hdr(target, packet, NULL, NULL); + + if (packet->status) { + ath6kl_err("htc_wait_for_ctrl_msg, ath6kl_htc_rx_process_hdr failed (status = %d)\n", + packet->status); + goto fail_ctrl_rx; + } + + return packet; + +fail_ctrl_rx: + if (packet != NULL) { + htc_rxpkt_reset(packet); + reclaim_rx_ctrl_buf(target, packet); + } + + return NULL; +} + +static int ath6kl_htc_mbox_add_rxbuf_multiple(struct htc_target *target, + struct list_head *pkt_queue) +{ + struct htc_endpoint *endpoint; + struct htc_packet *first_pkt; + bool rx_unblock = false; + int status = 0, depth; + + if (list_empty(pkt_queue)) + return -ENOMEM; + + first_pkt = list_first_entry(pkt_queue, struct htc_packet, list); + + if (first_pkt->endpoint >= ENDPOINT_MAX) + return status; + + depth = get_queue_depth(pkt_queue); + + ath6kl_dbg(ATH6KL_DBG_HTC, + "htc rx add multiple ep id %d cnt %d len %d\n", + first_pkt->endpoint, depth, first_pkt->buf_len); + + endpoint = &target->endpoint[first_pkt->endpoint]; + + if (target->htc_flags & HTC_OP_STATE_STOPPING) { + struct htc_packet *packet, *tmp_pkt; + + /* walk through queue and mark each one canceled */ + list_for_each_entry_safe(packet, tmp_pkt, pkt_queue, list) { + packet->status = -ECANCELED; + list_del(&packet->list); + ath6kl_htc_rx_complete(endpoint, packet); + } + + return status; + } + + spin_lock_bh(&target->rx_lock); + + list_splice_tail_init(pkt_queue, &endpoint->rx_bufq); + + /* check if we are blocked waiting for a new buffer */ + if (target->rx_st_flags & HTC_RECV_WAIT_BUFFERS) { + if (target->ep_waiting == first_pkt->endpoint) { + ath6kl_dbg(ATH6KL_DBG_HTC, + "htc rx blocked on ep %d, unblocking\n", + target->ep_waiting); + target->rx_st_flags &= ~HTC_RECV_WAIT_BUFFERS; + target->ep_waiting = ENDPOINT_MAX; + rx_unblock = true; + } + } + + spin_unlock_bh(&target->rx_lock); + + if (rx_unblock && !(target->htc_flags & HTC_OP_STATE_STOPPING)) + /* TODO : implement a buffer threshold count? */ + ath6kl_hif_rx_control(target->dev, true); + + return status; +} + +static void ath6kl_htc_mbox_flush_rx_buf(struct htc_target *target) +{ + struct htc_endpoint *endpoint; + struct htc_packet *packet, *tmp_pkt; + int i; + + for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) { + endpoint = &target->endpoint[i]; + if (!endpoint->svc_id) + /* not in use.. */ + continue; + + spin_lock_bh(&target->rx_lock); + list_for_each_entry_safe(packet, tmp_pkt, + &endpoint->rx_bufq, list) { + list_del(&packet->list); + spin_unlock_bh(&target->rx_lock); + ath6kl_dbg(ATH6KL_DBG_HTC, + "htc rx flush pkt 0x%p len %d ep %d\n", + packet, packet->buf_len, + packet->endpoint); + /* + * packets in rx_bufq of endpoint 0 have originally + * been queued from target->free_ctrl_rxbuf where + * packet and packet->buf_start are allocated + * separately using kmalloc(). For other endpoint + * rx_bufq, it is allocated as skb where packet is + * skb->head. Take care of this difference while freeing + * the memory. + */ + if (packet->endpoint == ENDPOINT_0) { + kfree(packet->buf_start); + kfree(packet); + } else { + dev_kfree_skb(packet->pkt_cntxt); + } + spin_lock_bh(&target->rx_lock); + } + spin_unlock_bh(&target->rx_lock); + } +} + +static int ath6kl_htc_mbox_conn_service(struct htc_target *target, + struct htc_service_connect_req *conn_req, + struct htc_service_connect_resp *conn_resp) +{ + struct htc_packet *rx_pkt = NULL; + struct htc_packet *tx_pkt = NULL; + struct htc_conn_service_resp *resp_msg; + struct htc_conn_service_msg *conn_msg; + struct htc_endpoint *endpoint; + enum htc_endpoint_id assigned_ep = ENDPOINT_MAX; + unsigned int max_msg_sz = 0; + int status = 0; + u16 msg_id; + + ath6kl_dbg(ATH6KL_DBG_HTC, + "htc connect service target 0x%p service id 0x%x\n", + target, conn_req->svc_id); + + if (conn_req->svc_id == HTC_CTRL_RSVD_SVC) { + /* special case for pseudo control service */ + assigned_ep = ENDPOINT_0; + max_msg_sz = HTC_MAX_CTRL_MSG_LEN; + } else { + /* allocate a packet to send to the target */ + tx_pkt = htc_get_control_buf(target, true); + + if (!tx_pkt) + return -ENOMEM; + + conn_msg = (struct htc_conn_service_msg *)tx_pkt->buf; + memset(conn_msg, 0, sizeof(*conn_msg)); + conn_msg->msg_id = cpu_to_le16(HTC_MSG_CONN_SVC_ID); + conn_msg->svc_id = cpu_to_le16(conn_req->svc_id); + conn_msg->conn_flags = cpu_to_le16(conn_req->conn_flags); + + set_htc_pkt_info(tx_pkt, NULL, (u8 *) conn_msg, + sizeof(*conn_msg) + conn_msg->svc_meta_len, + ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); + + /* we want synchronous operation */ + tx_pkt->completion = NULL; + ath6kl_htc_tx_prep_pkt(tx_pkt, 0, 0, 0); + status = ath6kl_htc_tx_issue(target, tx_pkt); + + if (status) + goto fail_tx; + + /* wait for response */ + rx_pkt = htc_wait_for_ctrl_msg(target); + + if (!rx_pkt) { + status = -ENOMEM; + goto fail_tx; + } + + resp_msg = (struct htc_conn_service_resp *)rx_pkt->buf; + msg_id = le16_to_cpu(resp_msg->msg_id); + + if ((msg_id != HTC_MSG_CONN_SVC_RESP_ID) || + (rx_pkt->act_len < sizeof(*resp_msg))) { + status = -ENOMEM; + goto fail_tx; + } + + conn_resp->resp_code = resp_msg->status; + /* check response status */ + if (resp_msg->status != HTC_SERVICE_SUCCESS) { + ath6kl_err("target failed service 0x%X connect request (status:%d)\n", + resp_msg->svc_id, resp_msg->status); + status = -ENOMEM; + goto fail_tx; + } + + assigned_ep = (enum htc_endpoint_id)resp_msg->eid; + max_msg_sz = le16_to_cpu(resp_msg->max_msg_sz); + } + + if (assigned_ep >= ENDPOINT_MAX || !max_msg_sz) { + status = -ENOMEM; + goto fail_tx; + } + + endpoint = &target->endpoint[assigned_ep]; + endpoint->eid = assigned_ep; + if (endpoint->svc_id) { + status = -ENOMEM; + goto fail_tx; + } + + /* return assigned endpoint to caller */ + conn_resp->endpoint = assigned_ep; + conn_resp->len_max = max_msg_sz; + + /* setup the endpoint */ + + /* this marks the endpoint in use */ + endpoint->svc_id = conn_req->svc_id; + + endpoint->max_txq_depth = conn_req->max_txq_depth; + endpoint->len_max = max_msg_sz; + endpoint->ep_cb = conn_req->ep_cb; + endpoint->cred_dist.svc_id = conn_req->svc_id; + endpoint->cred_dist.htc_ep = endpoint; + endpoint->cred_dist.endpoint = assigned_ep; + endpoint->cred_dist.cred_sz = target->tgt_cred_sz; + + switch (endpoint->svc_id) { + case WMI_DATA_BK_SVC: + endpoint->tx_drop_packet_threshold = MAX_DEF_COOKIE_NUM / 3; + break; + default: + endpoint->tx_drop_packet_threshold = MAX_HI_COOKIE_NUM; + break; + } + + if (conn_req->max_rxmsg_sz) { + /* + * Override cred_per_msg calculation, this optimizes + * the credit-low indications since the host will actually + * issue smaller messages in the Send path. + */ + if (conn_req->max_rxmsg_sz > max_msg_sz) { + status = -ENOMEM; + goto fail_tx; + } + endpoint->cred_dist.cred_per_msg = + conn_req->max_rxmsg_sz / target->tgt_cred_sz; + } else + endpoint->cred_dist.cred_per_msg = + max_msg_sz / target->tgt_cred_sz; + + if (!endpoint->cred_dist.cred_per_msg) + endpoint->cred_dist.cred_per_msg = 1; + + /* save local connection flags */ + endpoint->conn_flags = conn_req->flags; + +fail_tx: + if (tx_pkt) + htc_reclaim_txctrl_buf(target, tx_pkt); + + if (rx_pkt) { + htc_rxpkt_reset(rx_pkt); + reclaim_rx_ctrl_buf(target, rx_pkt); + } + + return status; +} + +static void reset_ep_state(struct htc_target *target) +{ + struct htc_endpoint *endpoint; + int i; + + for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) { + endpoint = &target->endpoint[i]; + memset(&endpoint->cred_dist, 0, sizeof(endpoint->cred_dist)); + endpoint->svc_id = 0; + endpoint->len_max = 0; + endpoint->max_txq_depth = 0; + memset(&endpoint->ep_st, 0, + sizeof(endpoint->ep_st)); + INIT_LIST_HEAD(&endpoint->rx_bufq); + INIT_LIST_HEAD(&endpoint->txq); + endpoint->target = target; + } + + /* reset distribution list */ + /* FIXME: free existing entries */ + INIT_LIST_HEAD(&target->cred_dist_list); +} + +static int ath6kl_htc_mbox_get_rxbuf_num(struct htc_target *target, + enum htc_endpoint_id endpoint) +{ + int num; + + spin_lock_bh(&target->rx_lock); + num = get_queue_depth(&(target->endpoint[endpoint].rx_bufq)); + spin_unlock_bh(&target->rx_lock); + return num; +} + +static void htc_setup_msg_bndl(struct htc_target *target) +{ + /* limit what HTC can handle */ + target->msg_per_bndl_max = min(HTC_HOST_MAX_MSG_PER_BUNDLE, + target->msg_per_bndl_max); + + if (ath6kl_hif_enable_scatter(target->dev->ar)) { + target->msg_per_bndl_max = 0; + return; + } + + /* limit bundle what the device layer can handle */ + target->msg_per_bndl_max = min(target->max_scat_entries, + target->msg_per_bndl_max); + + ath6kl_dbg(ATH6KL_DBG_BOOT, + "htc bundling allowed msg_per_bndl_max %d\n", + target->msg_per_bndl_max); + + /* Max rx bundle size is limited by the max tx bundle size */ + target->max_rx_bndl_sz = target->max_xfer_szper_scatreq; + /* Max tx bundle size if limited by the extended mbox address range */ + target->max_tx_bndl_sz = min(HIF_MBOX0_EXT_WIDTH, + target->max_xfer_szper_scatreq); + + ath6kl_dbg(ATH6KL_DBG_BOOT, "htc max_rx_bndl_sz %d max_tx_bndl_sz %d\n", + target->max_rx_bndl_sz, target->max_tx_bndl_sz); + + if (target->max_tx_bndl_sz) + /* tx_bndl_mask is enabled per AC, each has 1 bit */ + target->tx_bndl_mask = (1 << WMM_NUM_AC) - 1; + + if (target->max_rx_bndl_sz) + target->rx_bndl_enable = true; + + if ((target->tgt_cred_sz % target->block_sz) != 0) { + ath6kl_warn("credit size: %d is not block aligned! Disabling send bundling\n", + target->tgt_cred_sz); + + /* + * Disallow send bundling since the credit size is + * not aligned to a block size the I/O block + * padding will spill into the next credit buffer + * which is fatal. + */ + target->tx_bndl_mask = 0; + } +} + +static int ath6kl_htc_mbox_wait_target(struct htc_target *target) +{ + struct htc_packet *packet = NULL; + struct htc_ready_ext_msg *rdy_msg; + struct htc_service_connect_req connect; + struct htc_service_connect_resp resp; + int status; + + /* FIXME: remove once USB support is implemented */ + if (target->dev->ar->hif_type == ATH6KL_HIF_TYPE_USB) { + ath6kl_err("HTC doesn't support USB yet. Patience!\n"); + return -EOPNOTSUPP; + } + + /* we should be getting 1 control message that the target is ready */ + packet = htc_wait_for_ctrl_msg(target); + + if (!packet) + return -ENOMEM; + + /* we controlled the buffer creation so it's properly aligned */ + rdy_msg = (struct htc_ready_ext_msg *)packet->buf; + + if ((le16_to_cpu(rdy_msg->ver2_0_info.msg_id) != HTC_MSG_READY_ID) || + (packet->act_len < sizeof(struct htc_ready_msg))) { + status = -ENOMEM; + goto fail_wait_target; + } + + if (!rdy_msg->ver2_0_info.cred_cnt || !rdy_msg->ver2_0_info.cred_sz) { + status = -ENOMEM; + goto fail_wait_target; + } + + target->tgt_creds = le16_to_cpu(rdy_msg->ver2_0_info.cred_cnt); + target->tgt_cred_sz = le16_to_cpu(rdy_msg->ver2_0_info.cred_sz); + + ath6kl_dbg(ATH6KL_DBG_BOOT, + "htc target ready credits %d size %d\n", + target->tgt_creds, target->tgt_cred_sz); + + /* check if this is an extended ready message */ + if (packet->act_len >= sizeof(struct htc_ready_ext_msg)) { + /* this is an extended message */ + target->htc_tgt_ver = rdy_msg->htc_ver; + target->msg_per_bndl_max = rdy_msg->msg_per_htc_bndl; + } else { + /* legacy */ + target->htc_tgt_ver = HTC_VERSION_2P0; + target->msg_per_bndl_max = 0; + } + + ath6kl_dbg(ATH6KL_DBG_BOOT, "htc using protocol %s (%d)\n", + (target->htc_tgt_ver == HTC_VERSION_2P0) ? "2.0" : ">= 2.1", + target->htc_tgt_ver); + + if (target->msg_per_bndl_max > 0) + htc_setup_msg_bndl(target); + + /* setup our pseudo HTC control endpoint connection */ + memset(&connect, 0, sizeof(connect)); + memset(&resp, 0, sizeof(resp)); + connect.ep_cb.rx = htc_ctrl_rx; + connect.ep_cb.rx_refill = NULL; + connect.ep_cb.tx_full = NULL; + connect.max_txq_depth = NUM_CONTROL_BUFFERS; + connect.svc_id = HTC_CTRL_RSVD_SVC; + + /* connect fake service */ + status = ath6kl_htc_mbox_conn_service((void *)target, &connect, &resp); + + if (status) + /* + * FIXME: this call doesn't make sense, the caller should + * call ath6kl_htc_mbox_cleanup() when it wants remove htc + */ + ath6kl_hif_cleanup_scatter(target->dev->ar); + +fail_wait_target: + if (packet) { + htc_rxpkt_reset(packet); + reclaim_rx_ctrl_buf(target, packet); + } + + return status; +} + +/* + * Start HTC, enable interrupts and let the target know + * host has finished setup. + */ +static int ath6kl_htc_mbox_start(struct htc_target *target) +{ + struct htc_packet *packet; + int status; + + memset(&target->dev->irq_proc_reg, 0, + sizeof(target->dev->irq_proc_reg)); + + /* Disable interrupts at the chip level */ + ath6kl_hif_disable_intrs(target->dev); + + target->htc_flags = 0; + target->rx_st_flags = 0; + + /* Push control receive buffers into htc control endpoint */ + while ((packet = htc_get_control_buf(target, false)) != NULL) { + status = htc_add_rxbuf(target, packet); + if (status) + return status; + } + + /* NOTE: the first entry in the distribution list is ENDPOINT_0 */ + ath6kl_credit_init(target->credit_info, &target->cred_dist_list, + target->tgt_creds); + + dump_cred_dist_stats(target); + + /* Indicate to the target of the setup completion */ + status = htc_setup_tx_complete(target); + + if (status) + return status; + + /* unmask interrupts */ + status = ath6kl_hif_unmask_intrs(target->dev); + + if (status) + ath6kl_htc_mbox_stop(target); + + return status; +} + +static int ath6kl_htc_reset(struct htc_target *target) +{ + u32 block_size, ctrl_bufsz; + struct htc_packet *packet; + int i; + + reset_ep_state(target); + + block_size = target->dev->ar->mbox_info.block_size; + + ctrl_bufsz = (block_size > HTC_MAX_CTRL_MSG_LEN) ? + (block_size + HTC_HDR_LENGTH) : + (HTC_MAX_CTRL_MSG_LEN + HTC_HDR_LENGTH); + + for (i = 0; i < NUM_CONTROL_BUFFERS; i++) { + packet = kzalloc(sizeof(*packet), GFP_KERNEL); + if (!packet) + return -ENOMEM; + + packet->buf_start = kzalloc(ctrl_bufsz, GFP_KERNEL); + if (!packet->buf_start) { + kfree(packet); + return -ENOMEM; + } + + packet->buf_len = ctrl_bufsz; + if (i < NUM_CONTROL_RX_BUFFERS) { + packet->act_len = 0; + packet->buf = packet->buf_start; + packet->endpoint = ENDPOINT_0; + list_add_tail(&packet->list, &target->free_ctrl_rxbuf); + } else + list_add_tail(&packet->list, &target->free_ctrl_txbuf); + } + + return 0; +} + +/* htc_stop: stop interrupt reception, and flush all queued buffers */ +static void ath6kl_htc_mbox_stop(struct htc_target *target) +{ + spin_lock_bh(&target->htc_lock); + target->htc_flags |= HTC_OP_STATE_STOPPING; + spin_unlock_bh(&target->htc_lock); + + /* + * Masking interrupts is a synchronous operation, when this + * function returns all pending HIF I/O has completed, we can + * safely flush the queues. + */ + ath6kl_hif_mask_intrs(target->dev); + + ath6kl_htc_flush_txep_all(target); + + ath6kl_htc_mbox_flush_rx_buf(target); + + ath6kl_htc_reset(target); +} + +static void *ath6kl_htc_mbox_create(struct ath6kl *ar) +{ + struct htc_target *target = NULL; + int status = 0; + + target = kzalloc(sizeof(*target), GFP_KERNEL); + if (!target) { + ath6kl_err("unable to allocate memory\n"); + return NULL; + } + + target->dev = kzalloc(sizeof(*target->dev), GFP_KERNEL); + if (!target->dev) { + ath6kl_err("unable to allocate memory\n"); + status = -ENOMEM; + goto err_htc_cleanup; + } + + spin_lock_init(&target->htc_lock); + spin_lock_init(&target->rx_lock); + spin_lock_init(&target->tx_lock); + + INIT_LIST_HEAD(&target->free_ctrl_txbuf); + INIT_LIST_HEAD(&target->free_ctrl_rxbuf); + INIT_LIST_HEAD(&target->cred_dist_list); + + target->dev->ar = ar; + target->dev->htc_cnxt = target; + target->ep_waiting = ENDPOINT_MAX; + + status = ath6kl_hif_setup(target->dev); + if (status) + goto err_htc_cleanup; + + status = ath6kl_htc_reset(target); + if (status) + goto err_htc_cleanup; + + return target; + +err_htc_cleanup: + ath6kl_htc_mbox_cleanup(target); + + return NULL; +} + +/* cleanup the HTC instance */ +static void ath6kl_htc_mbox_cleanup(struct htc_target *target) +{ + struct htc_packet *packet, *tmp_packet; + + /* FIXME: remove check once USB support is implemented */ + if (target->dev->ar->hif_type != ATH6KL_HIF_TYPE_USB) + ath6kl_hif_cleanup_scatter(target->dev->ar); + + list_for_each_entry_safe(packet, tmp_packet, + &target->free_ctrl_txbuf, list) { + list_del(&packet->list); + kfree(packet->buf_start); + kfree(packet); + } + + list_for_each_entry_safe(packet, tmp_packet, + &target->free_ctrl_rxbuf, list) { + list_del(&packet->list); + kfree(packet->buf_start); + kfree(packet); + } + + kfree(target->dev); + kfree(target); +} + +static const struct ath6kl_htc_ops ath6kl_htc_mbox_ops = { + .create = ath6kl_htc_mbox_create, + .wait_target = ath6kl_htc_mbox_wait_target, + .start = ath6kl_htc_mbox_start, + .conn_service = ath6kl_htc_mbox_conn_service, + .tx = ath6kl_htc_mbox_tx, + .stop = ath6kl_htc_mbox_stop, + .cleanup = ath6kl_htc_mbox_cleanup, + .flush_txep = ath6kl_htc_mbox_flush_txep, + .flush_rx_buf = ath6kl_htc_mbox_flush_rx_buf, + .activity_changed = ath6kl_htc_mbox_activity_changed, + .get_rxbuf_num = ath6kl_htc_mbox_get_rxbuf_num, + .add_rxbuf_multiple = ath6kl_htc_mbox_add_rxbuf_multiple, + .credit_setup = ath6kl_htc_mbox_credit_setup, +}; + +void ath6kl_htc_mbox_attach(struct ath6kl *ar) +{ + ar->htc_ops = &ath6kl_htc_mbox_ops; +} diff --git a/trunk/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/trunk/drivers/net/wireless/ath/ath6kl/htc_pipe.c new file mode 100644 index 000000000000..b277b3446882 --- /dev/null +++ b/trunk/drivers/net/wireless/ath/ath6kl/htc_pipe.c @@ -0,0 +1,1713 @@ +/* + * Copyright (c) 2007-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "core.h" +#include "debug.h" +#include "hif-ops.h" + +#define HTC_PACKET_CONTAINER_ALLOCATION 32 +#define HTC_CONTROL_BUFFER_SIZE (HTC_MAX_CTRL_MSG_LEN + HTC_HDR_LENGTH) + +static int ath6kl_htc_pipe_tx(struct htc_target *handle, + struct htc_packet *packet); +static void ath6kl_htc_pipe_cleanup(struct htc_target *handle); + +/* htc pipe tx path */ +static inline void restore_tx_packet(struct htc_packet *packet) +{ + if (packet->info.tx.flags & HTC_FLAGS_TX_FIXUP_NETBUF) { + skb_pull(packet->skb, sizeof(struct htc_frame_hdr)); + packet->info.tx.flags &= ~HTC_FLAGS_TX_FIXUP_NETBUF; + } +} + +static void do_send_completion(struct htc_endpoint *ep, + struct list_head *queue_to_indicate) +{ + struct htc_packet *packet; + + if (list_empty(queue_to_indicate)) { + /* nothing to indicate */ + return; + } + + if (ep->ep_cb.tx_comp_multi != NULL) { + ath6kl_dbg(ATH6KL_DBG_HTC, + "%s: calling ep %d, send complete multiple callback (%d pkts)\n", + __func__, ep->eid, + get_queue_depth(queue_to_indicate)); + /* + * a multiple send complete handler is being used, + * pass the queue to the handler + */ + ep->ep_cb.tx_comp_multi(ep->target, queue_to_indicate); + /* + * all packets are now owned by the callback, + * reset queue to be safe + */ + INIT_LIST_HEAD(queue_to_indicate); + } else { + /* using legacy EpTxComplete */ + do { + packet = list_first_entry(queue_to_indicate, + struct htc_packet, list); + + list_del(&packet->list); + ath6kl_dbg(ATH6KL_DBG_HTC, + "%s: calling ep %d send complete callback on packet 0x%p\n", + __func__, ep->eid, packet); + ep->ep_cb.tx_complete(ep->target, packet); + } while (!list_empty(queue_to_indicate)); + } +} + +static void send_packet_completion(struct htc_target *target, + struct htc_packet *packet) +{ + struct htc_endpoint *ep = &target->endpoint[packet->endpoint]; + struct list_head container; + + restore_tx_packet(packet); + INIT_LIST_HEAD(&container); + list_add_tail(&packet->list, &container); + + /* do completion */ + do_send_completion(ep, &container); +} + +static void get_htc_packet_credit_based(struct htc_target *target, + struct htc_endpoint *ep, + struct list_head *queue) +{ + int credits_required; + int remainder; + u8 send_flags; + struct htc_packet *packet; + unsigned int transfer_len; + + /* NOTE : the TX lock is held when this function is called */ + + /* loop until we can grab as many packets out of the queue as we can */ + while (true) { + send_flags = 0; + if (list_empty(&ep->txq)) + break; + + /* get packet at head, but don't remove it */ + packet = list_first_entry(&ep->txq, struct htc_packet, list); + if (packet == NULL) + break; + + ath6kl_dbg(ATH6KL_DBG_HTC, + "%s: got head packet:0x%p , queue depth: %d\n", + __func__, packet, get_queue_depth(&ep->txq)); + + transfer_len = packet->act_len + HTC_HDR_LENGTH; + + if (transfer_len <= target->tgt_cred_sz) { + credits_required = 1; + } else { + /* figure out how many credits this message requires */ + credits_required = transfer_len / target->tgt_cred_sz; + remainder = transfer_len % target->tgt_cred_sz; + + if (remainder) + credits_required++; + } + + ath6kl_dbg(ATH6KL_DBG_HTC, "%s: creds required:%d got:%d\n", + __func__, credits_required, ep->cred_dist.credits); + + if (ep->eid == ENDPOINT_0) { + /* + * endpoint 0 is special, it always has a credit and + * does not require credit based flow control + */ + credits_required = 0; + + } else { + + if (ep->cred_dist.credits < credits_required) + break; + + ep->cred_dist.credits -= credits_required; + ep->ep_st.cred_cosumd += credits_required; + + /* check if we need credits back from the target */ + if (ep->cred_dist.credits < + ep->cred_dist.cred_per_msg) { + /* tell the target we need credits ASAP! */ + send_flags |= HTC_FLAGS_NEED_CREDIT_UPDATE; + ep->ep_st.cred_low_indicate += 1; + ath6kl_dbg(ATH6KL_DBG_HTC, + "%s: host needs credits\n", + __func__); + } + } + + /* now we can fully dequeue */ + packet = list_first_entry(&ep->txq, struct htc_packet, list); + + list_del(&packet->list); + /* save the number of credits this packet consumed */ + packet->info.tx.cred_used = credits_required; + /* save send flags */ + packet->info.tx.flags = send_flags; + packet->info.tx.seqno = ep->seqno; + ep->seqno++; + /* queue this packet into the caller's queue */ + list_add_tail(&packet->list, queue); + } + +} + +static void get_htc_packet(struct htc_target *target, + struct htc_endpoint *ep, + struct list_head *queue, int resources) +{ + struct htc_packet *packet; + + /* NOTE : the TX lock is held when this function is called */ + + /* loop until we can grab as many packets out of the queue as we can */ + while (resources) { + if (list_empty(&ep->txq)) + break; + + packet = list_first_entry(&ep->txq, struct htc_packet, list); + list_del(&packet->list); + + ath6kl_dbg(ATH6KL_DBG_HTC, + "%s: got packet:0x%p , new queue depth: %d\n", + __func__, packet, get_queue_depth(&ep->txq)); + packet->info.tx.seqno = ep->seqno; + packet->info.tx.flags = 0; + packet->info.tx.cred_used = 0; + ep->seqno++; + + /* queue this packet into the caller's queue */ + list_add_tail(&packet->list, queue); + resources--; + } +} + +static int htc_issue_packets(struct htc_target *target, + struct htc_endpoint *ep, + struct list_head *pkt_queue) +{ + int status = 0; + u16 payload_len; + struct sk_buff *skb; + struct htc_frame_hdr *htc_hdr; + struct htc_packet *packet; + + ath6kl_dbg(ATH6KL_DBG_HTC, + "%s: queue: 0x%p, pkts %d\n", __func__, + pkt_queue, get_queue_depth(pkt_queue)); + + while (!list_empty(pkt_queue)) { + packet = list_first_entry(pkt_queue, struct htc_packet, list); + list_del(&packet->list); + + skb = packet->skb; + if (!skb) { + WARN_ON_ONCE(1); + status = -EINVAL; + break; + } + + payload_len = packet->act_len; + + /* setup HTC frame header */ + htc_hdr = (struct htc_frame_hdr *) skb_push(skb, + sizeof(*htc_hdr)); + if (!htc_hdr) { + WARN_ON_ONCE(1); + status = -EINVAL; + break; + } + + packet->info.tx.flags |= HTC_FLAGS_TX_FIXUP_NETBUF; + + /* Endianess? */ + put_unaligned((u16) payload_len, &htc_hdr->payld_len); + htc_hdr->flags = packet->info.tx.flags; + htc_hdr->eid = (u8) packet->endpoint; + htc_hdr->ctrl[0] = 0; + htc_hdr->ctrl[1] = (u8) packet->info.tx.seqno; + + spin_lock_bh(&target->tx_lock); + + /* store in look up queue to match completions */ + list_add_tail(&packet->list, &ep->pipe.tx_lookup_queue); + ep->ep_st.tx_issued += 1; + spin_unlock_bh(&target->tx_lock); + + status = ath6kl_hif_pipe_send(target->dev->ar, + ep->pipe.pipeid_ul, NULL, skb); + + if (status != 0) { + if (status != -ENOMEM) { + /* TODO: if more than 1 endpoint maps to the + * same PipeID, it is possible to run out of + * resources in the HIF layer. + * Don't emit the error + */ + ath6kl_dbg(ATH6KL_DBG_HTC, + "%s: failed status:%d\n", + __func__, status); + } + spin_lock_bh(&target->tx_lock); + list_del(&packet->list); + + /* reclaim credits */ + ep->cred_dist.credits += packet->info.tx.cred_used; + spin_unlock_bh(&target->tx_lock); + + /* put it back into the callers queue */ + list_add(&packet->list, pkt_queue); + break; + } + + } + + if (status != 0) { + while (!list_empty(pkt_queue)) { + if (status != -ENOMEM) { + ath6kl_dbg(ATH6KL_DBG_HTC, + "%s: failed pkt:0x%p status:%d\n", + __func__, packet, status); + } + + packet = list_first_entry(pkt_queue, + struct htc_packet, list); + list_del(&packet->list); + packet->status = status; + send_packet_completion(target, packet); + } + } + + return status; +} + +static enum htc_send_queue_result htc_try_send(struct htc_target *target, + struct htc_endpoint *ep, + struct list_head *txq) +{ + struct list_head send_queue; /* temp queue to hold packets */ + struct htc_packet *packet, *tmp_pkt; + struct ath6kl *ar = target->dev->ar; + enum htc_send_full_action action; + int tx_resources, overflow, txqueue_depth, i, good_pkts; + u8 pipeid; + + ath6kl_dbg(ATH6KL_DBG_HTC, "%s: (queue:0x%p depth:%d)\n", + __func__, txq, + (txq == NULL) ? 0 : get_queue_depth(txq)); + + /* init the local send queue */ + INIT_LIST_HEAD(&send_queue); + + /* + * txq equals to NULL means + * caller didn't provide a queue, just wants us to + * check queues and send + */ + if (txq != NULL) { + if (list_empty(txq)) { + /* empty queue */ + return HTC_SEND_QUEUE_DROP; + } + + spin_lock_bh(&target->tx_lock); + txqueue_depth = get_queue_depth(&ep->txq); + spin_unlock_bh(&target->tx_lock); + + if (txqueue_depth >= ep->max_txq_depth) { + /* we've already overflowed */ + overflow = get_queue_depth(txq); + } else { + /* get how much we will overflow by */ + overflow = txqueue_depth; + overflow += get_queue_depth(txq); + /* get how much we will overflow the TX queue by */ + overflow -= ep->max_txq_depth; + } + + /* if overflow is negative or zero, we are okay */ + if (overflow > 0) { + ath6kl_dbg(ATH6KL_DBG_HTC, + "%s: Endpoint %d, TX queue will overflow :%d, Tx Depth:%d, Max:%d\n", + __func__, ep->eid, overflow, txqueue_depth, + ep->max_txq_depth); + } + if ((overflow <= 0) || + (ep->ep_cb.tx_full == NULL)) { + /* + * all packets will fit or caller did not provide send + * full indication handler -- just move all of them + * to the local send_queue object + */ + list_splice_tail_init(txq, &send_queue); + } else { + good_pkts = get_queue_depth(txq) - overflow; + if (good_pkts < 0) { + WARN_ON_ONCE(1); + return HTC_SEND_QUEUE_DROP; + } + + /* we have overflowed, and a callback is provided */ + /* dequeue all non-overflow packets to the sendqueue */ + for (i = 0; i < good_pkts; i++) { + /* pop off caller's queue */ + packet = list_first_entry(txq, + struct htc_packet, + list); + list_del(&packet->list); + /* insert into local queue */ + list_add_tail(&packet->list, &send_queue); + } + + /* + * the caller's queue has all the packets that won't fit + * walk through the caller's queue and indicate each to + * the send full handler + */ + list_for_each_entry_safe(packet, tmp_pkt, + txq, list) { + + ath6kl_dbg(ATH6KL_DBG_HTC, + "%s: Indicat overflowed TX pkts: %p\n", + __func__, packet); + action = ep->ep_cb.tx_full(ep->target, packet); + if (action == HTC_SEND_FULL_DROP) { + /* callback wants the packet dropped */ + ep->ep_st.tx_dropped += 1; + + /* leave this one in the caller's queue + * for cleanup */ + } else { + /* callback wants to keep this packet, + * remove from caller's queue */ + list_del(&packet->list); + /* put it in the send queue */ + list_add_tail(&packet->list, + &send_queue); + } + + } + + if (list_empty(&send_queue)) { + /* no packets made it in, caller will cleanup */ + return HTC_SEND_QUEUE_DROP; + } + } + } + + if (!ep->pipe.tx_credit_flow_enabled) { + tx_resources = + ath6kl_hif_pipe_get_free_queue_number(ar, + ep->pipe.pipeid_ul); + } else { + tx_resources = 0; + } + + spin_lock_bh(&target->tx_lock); + if (!list_empty(&send_queue)) { + /* transfer packets to tail */ + list_splice_tail_init(&send_queue, &ep->txq); + if (!list_empty(&send_queue)) { + WARN_ON_ONCE(1); + spin_unlock_bh(&target->tx_lock); + return HTC_SEND_QUEUE_DROP; + } + INIT_LIST_HEAD(&send_queue); + } + + /* increment tx processing count on entry */ + ep->tx_proc_cnt++; + + if (ep->tx_proc_cnt > 1) { + /* + * Another thread or task is draining the TX queues on this + * endpoint that thread will reset the tx processing count + * when the queue is drained. + */ + ep->tx_proc_cnt--; + spin_unlock_bh(&target->tx_lock); + return HTC_SEND_QUEUE_OK; + } + + /***** beyond this point only 1 thread may enter ******/ + + /* + * Now drain the endpoint TX queue for transmission as long as we have + * enough transmit resources. + */ + while (true) { + + if (get_queue_depth(&ep->txq) == 0) + break; + + if (ep->pipe.tx_credit_flow_enabled) { + /* + * Credit based mechanism provides flow control + * based on target transmit resource availability, + * we assume that the HIF layer will always have + * bus resources greater than target transmit + * resources. + */ + get_htc_packet_credit_based(target, ep, &send_queue); + } else { + /* + * Get all packets for this endpoint that we can + * for this pass. + */ + get_htc_packet(target, ep, &send_queue, tx_resources); + } + + if (get_queue_depth(&send_queue) == 0) { + /* + * Didn't get packets due to out of resources or TX + * queue was drained. + */ + break; + } + + spin_unlock_bh(&target->tx_lock); + + /* send what we can */ + htc_issue_packets(target, ep, &send_queue); + + if (!ep->pipe.tx_credit_flow_enabled) { + pipeid = ep->pipe.pipeid_ul; + tx_resources = + ath6kl_hif_pipe_get_free_queue_number(ar, pipeid); + } + + 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); + + return HTC_SEND_QUEUE_OK; +} + +/* htc control packet manipulation */ +static void destroy_htc_txctrl_packet(struct htc_packet *packet) +{ + struct sk_buff *skb; + skb = packet->skb; + if (skb != NULL) + dev_kfree_skb(skb); + + kfree(packet); +} + +static struct htc_packet *build_htc_txctrl_packet(void) +{ + struct htc_packet *packet = NULL; + struct sk_buff *skb; + + packet = kzalloc(sizeof(struct htc_packet), GFP_KERNEL); + if (packet == NULL) + return NULL; + + skb = __dev_alloc_skb(HTC_CONTROL_BUFFER_SIZE, GFP_KERNEL); + + if (skb == NULL) { + kfree(packet); + return NULL; + } + packet->skb = skb; + + return packet; +} + +static void htc_free_txctrl_packet(struct htc_target *target, + struct htc_packet *packet) +{ + destroy_htc_txctrl_packet(packet); +} + +static struct htc_packet *htc_alloc_txctrl_packet(struct htc_target *target) +{ + return build_htc_txctrl_packet(); +} + +static void htc_txctrl_complete(struct htc_target *target, + struct htc_packet *packet) +{ + htc_free_txctrl_packet(target, packet); +} + +#define MAX_MESSAGE_SIZE 1536 + +static int htc_setup_target_buffer_assignments(struct htc_target *target) +{ + int status, credits, credit_per_maxmsg, i; + struct htc_pipe_txcredit_alloc *entry; + unsigned int hif_usbaudioclass = 0; + + credit_per_maxmsg = MAX_MESSAGE_SIZE / target->tgt_cred_sz; + if (MAX_MESSAGE_SIZE % target->tgt_cred_sz) + credit_per_maxmsg++; + + /* TODO, this should be configured by the caller! */ + + credits = target->tgt_creds; + entry = &target->pipe.txcredit_alloc[0]; + + status = -ENOMEM; + + /* FIXME: hif_usbaudioclass is always zero */ + if (hif_usbaudioclass) { + ath6kl_dbg(ATH6KL_DBG_HTC, + "%s: For USB Audio Class- Total:%d\n", + __func__, credits); + entry++; + entry++; + /* Setup VO Service To have Max Credits */ + entry->service_id = WMI_DATA_VO_SVC; + entry->credit_alloc = (credits - 6); + if (entry->credit_alloc == 0) + entry->credit_alloc++; + + credits -= (int) entry->credit_alloc; + if (credits <= 0) + return status; + + entry++; + entry->service_id = WMI_CONTROL_SVC; + entry->credit_alloc = credit_per_maxmsg; + credits -= (int) entry->credit_alloc; + if (credits <= 0) + return status; + + /* leftovers go to best effort */ + entry++; + entry++; + entry->service_id = WMI_DATA_BE_SVC; + entry->credit_alloc = (u8) credits; + status = 0; + } else { + entry++; + entry->service_id = WMI_DATA_VI_SVC; + entry->credit_alloc = credits / 4; + if (entry->credit_alloc == 0) + entry->credit_alloc++; + + credits -= (int) entry->credit_alloc; + if (credits <= 0) + return status; + + entry++; + entry->service_id = WMI_DATA_VO_SVC; + entry->credit_alloc = credits / 4; + if (entry->credit_alloc == 0) + entry->credit_alloc++; + + credits -= (int) entry->credit_alloc; + if (credits <= 0) + return status; + + entry++; + entry->service_id = WMI_CONTROL_SVC; + entry->credit_alloc = credit_per_maxmsg; + credits -= (int) entry->credit_alloc; + if (credits <= 0) + return status; + + entry++; + entry->service_id = WMI_DATA_BK_SVC; + entry->credit_alloc = credit_per_maxmsg; + credits -= (int) entry->credit_alloc; + if (credits <= 0) + return status; + + /* leftovers go to best effort */ + entry++; + entry->service_id = WMI_DATA_BE_SVC; + entry->credit_alloc = (u8) credits; + status = 0; + } + + if (status == 0) { + for (i = 0; i < ENDPOINT_MAX; i++) { + if (target->pipe.txcredit_alloc[i].service_id != 0) { + ath6kl_dbg(ATH6KL_DBG_HTC, + "HTC Service Index : %d TX : 0x%2.2X : alloc:%d\n", + i, + target->pipe.txcredit_alloc[i]. + service_id, + target->pipe.txcredit_alloc[i]. + credit_alloc); + } + } + } + return status; +} + +/* process credit reports and call distribution function */ +static void htc_process_credit_report(struct htc_target *target, + struct htc_credit_report *rpt, + int num_entries, + enum htc_endpoint_id from_ep) +{ + int total_credits = 0, i; + struct htc_endpoint *ep; + + /* lock out TX while we update credits */ + spin_lock_bh(&target->tx_lock); + + for (i = 0; i < num_entries; i++, rpt++) { + if (rpt->eid >= ENDPOINT_MAX) { + WARN_ON_ONCE(1); + spin_unlock_bh(&target->tx_lock); + return; + } + + ep = &target->endpoint[rpt->eid]; + ep->cred_dist.credits += rpt->credits; + + if (ep->cred_dist.credits && get_queue_depth(&ep->txq)) { + spin_unlock_bh(&target->tx_lock); + htc_try_send(target, ep, NULL); + spin_lock_bh(&target->tx_lock); + } + + total_credits += rpt->credits; + } + ath6kl_dbg(ATH6KL_DBG_HTC, + "Report indicated %d credits to distribute\n", + total_credits); + + spin_unlock_bh(&target->tx_lock); +} + +/* flush endpoint TX queue */ +static void htc_flush_tx_endpoint(struct htc_target *target, + struct htc_endpoint *ep, u16 tag) +{ + struct htc_packet *packet; + + spin_lock_bh(&target->tx_lock); + while (get_queue_depth(&ep->txq)) { + packet = list_first_entry(&ep->txq, struct htc_packet, list); + list_del(&packet->list); + packet->status = 0; + send_packet_completion(target, packet); + } + spin_unlock_bh(&target->tx_lock); +} + +/* + * In the adapted HIF layer, struct sk_buff * are passed between HIF and HTC, + * since upper layers expects struct htc_packet containers we use the completed + * skb and lookup it's corresponding HTC packet buffer from a lookup list. + * This is extra overhead that can be fixed by re-aligning HIF interfaces with + * HTC. + */ +static struct htc_packet *htc_lookup_tx_packet(struct htc_target *target, + struct htc_endpoint *ep, + struct sk_buff *skb) +{ + struct htc_packet *packet, *tmp_pkt, *found_packet = NULL; + + spin_lock_bh(&target->tx_lock); + + /* + * interate from the front of tx lookup queue + * this lookup should be fast since lower layers completes in-order and + * so the completed packet should be at the head of the list generally + */ + list_for_each_entry_safe(packet, tmp_pkt, &ep->pipe.tx_lookup_queue, + list) { + /* check for removal */ + if (skb == packet->skb) { + /* found it */ + list_del(&packet->list); + found_packet = packet; + break; + } + } + + spin_unlock_bh(&target->tx_lock); + + return found_packet; +} + +static int ath6kl_htc_pipe_tx_complete(struct ath6kl *ar, struct sk_buff *skb) +{ + struct htc_target *target = ar->htc_target; + struct htc_frame_hdr *htc_hdr; + struct htc_endpoint *ep; + struct htc_packet *packet; + u8 ep_id, *netdata; + u32 netlen; + + netdata = skb->data; + netlen = skb->len; + + htc_hdr = (struct htc_frame_hdr *) netdata; + + ep_id = htc_hdr->eid; + ep = &target->endpoint[ep_id]; + + packet = htc_lookup_tx_packet(target, ep, skb); + if (packet == NULL) { + /* may have already been flushed and freed */ + ath6kl_err("HTC TX lookup failed!\n"); + } else { + /* will be giving this buffer back to upper layers */ + packet->status = 0; + send_packet_completion(target, packet); + } + skb = NULL; + + if (!ep->pipe.tx_credit_flow_enabled) { + /* + * note: when using TX credit flow, the re-checking of queues + * happens when credits flow back from the target. in the + * non-TX credit case, we recheck after the packet completes + */ + htc_try_send(target, ep, NULL); + } + + return 0; +} + +static int htc_send_packets_multiple(struct htc_target *target, + struct list_head *pkt_queue) +{ + struct htc_endpoint *ep; + struct htc_packet *packet, *tmp_pkt; + + if (list_empty(pkt_queue)) + return -EINVAL; + + /* get first packet to find out which ep the packets will go into */ + packet = list_first_entry(pkt_queue, struct htc_packet, list); + if (packet == NULL) + return -EINVAL; + + if (packet->endpoint >= ENDPOINT_MAX) { + WARN_ON_ONCE(1); + return -EINVAL; + } + ep = &target->endpoint[packet->endpoint]; + + htc_try_send(target, ep, pkt_queue); + + /* do completion on any packets that couldn't get in */ + if (!list_empty(pkt_queue)) { + list_for_each_entry_safe(packet, tmp_pkt, pkt_queue, list) { + packet->status = -ENOMEM; + } + + do_send_completion(ep, pkt_queue); + } + + return 0; +} + +/* htc pipe rx path */ +static struct htc_packet *alloc_htc_packet_container(struct htc_target *target) +{ + struct htc_packet *packet; + spin_lock_bh(&target->rx_lock); + + if (target->pipe.htc_packet_pool == NULL) { + spin_unlock_bh(&target->rx_lock); + return NULL; + } + + packet = target->pipe.htc_packet_pool; + target->pipe.htc_packet_pool = (struct htc_packet *) packet->list.next; + + spin_unlock_bh(&target->rx_lock); + + packet->list.next = NULL; + return packet; +} + +static void free_htc_packet_container(struct htc_target *target, + struct htc_packet *packet) +{ + struct list_head *lh; + + spin_lock_bh(&target->rx_lock); + + if (target->pipe.htc_packet_pool == NULL) { + target->pipe.htc_packet_pool = packet; + packet->list.next = NULL; + } else { + lh = (struct list_head *) target->pipe.htc_packet_pool; + packet->list.next = lh; + target->pipe.htc_packet_pool = packet; + } + + spin_unlock_bh(&target->rx_lock); +} + +static int htc_process_trailer(struct htc_target *target, u8 *buffer, + int len, enum htc_endpoint_id from_ep) +{ + struct htc_credit_report *report; + struct htc_record_hdr *record; + u8 *record_buf, *orig_buf; + int orig_len, status; + + orig_buf = buffer; + orig_len = len; + status = 0; + + while (len > 0) { + if (len < sizeof(struct htc_record_hdr)) { + status = -EINVAL; + break; + } + + /* these are byte aligned structs */ + record = (struct htc_record_hdr *) buffer; + len -= sizeof(struct htc_record_hdr); + buffer += sizeof(struct htc_record_hdr); + + if (record->len > len) { + /* no room left in buffer for record */ + ath6kl_dbg(ATH6KL_DBG_HTC, + "invalid length: %d (id:%d) buffer has: %d bytes left\n", + record->len, record->rec_id, len); + status = -EINVAL; + break; + } + + /* start of record follows the header */ + record_buf = buffer; + + switch (record->rec_id) { + case HTC_RECORD_CREDITS: + if (record->len < sizeof(struct htc_credit_report)) { + WARN_ON_ONCE(1); + return -EINVAL; + } + + report = (struct htc_credit_report *) record_buf; + htc_process_credit_report(target, report, + record->len / sizeof(*report), + from_ep); + break; + default: + ath6kl_dbg(ATH6KL_DBG_HTC, + "unhandled record: id:%d length:%d\n", + record->rec_id, record->len); + break; + } + + if (status != 0) + break; + + /* advance buffer past this record for next time around */ + buffer += record->len; + len -= record->len; + } + + return status; +} + +static void do_recv_completion(struct htc_endpoint *ep, + struct list_head *queue_to_indicate) +{ + struct htc_packet *packet; + + if (list_empty(queue_to_indicate)) { + /* nothing to indicate */ + return; + } + + /* using legacy EpRecv */ + while (!list_empty(queue_to_indicate)) { + packet = list_first_entry(queue_to_indicate, + struct htc_packet, list); + list_del(&packet->list); + ep->ep_cb.rx(ep->target, packet); + } + + return; +} + +static void recv_packet_completion(struct htc_target *target, + struct htc_endpoint *ep, + struct htc_packet *packet) +{ + struct list_head container; + INIT_LIST_HEAD(&container); + list_add_tail(&packet->list, &container); + + /* do completion */ + do_recv_completion(ep, &container); +} + +static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb, + u8 pipeid) +{ + struct htc_target *target = ar->htc_target; + u8 *netdata, *trailer, hdr_info; + struct htc_frame_hdr *htc_hdr; + u32 netlen, trailerlen = 0; + struct htc_packet *packet; + struct htc_endpoint *ep; + u16 payload_len; + int status = 0; + + netdata = skb->data; + netlen = skb->len; + + htc_hdr = (struct htc_frame_hdr *) netdata; + + ep = &target->endpoint[htc_hdr->eid]; + + if (htc_hdr->eid >= ENDPOINT_MAX) { + ath6kl_dbg(ATH6KL_DBG_HTC, + "HTC Rx: invalid EndpointID=%d\n", + htc_hdr->eid); + status = -EINVAL; + goto free_skb; + } + + payload_len = le16_to_cpu(get_unaligned(&htc_hdr->payld_len)); + + if (netlen < (payload_len + HTC_HDR_LENGTH)) { + ath6kl_dbg(ATH6KL_DBG_HTC, + "HTC Rx: insufficient length, got:%d expected =%u\n", + netlen, payload_len + HTC_HDR_LENGTH); + status = -EINVAL; + goto free_skb; + } + + /* get flags to check for trailer */ + hdr_info = htc_hdr->flags; + if (hdr_info & HTC_FLG_RX_TRAILER) { + /* extract the trailer length */ + hdr_info = htc_hdr->ctrl[0]; + if ((hdr_info < sizeof(struct htc_record_hdr)) || + (hdr_info > payload_len)) { + ath6kl_dbg(ATH6KL_DBG_HTC, + "invalid header: payloadlen should be %d, CB[0]: %d\n", + payload_len, hdr_info); + status = -EINVAL; + goto free_skb; + } + + trailerlen = hdr_info; + /* process trailer after hdr/apps payload */ + trailer = (u8 *) htc_hdr + HTC_HDR_LENGTH + + payload_len - hdr_info; + status = htc_process_trailer(target, trailer, hdr_info, + htc_hdr->eid); + if (status != 0) + goto free_skb; + } + + if (((int) payload_len - (int) trailerlen) <= 0) { + /* zero length packet with trailer, just drop these */ + goto free_skb; + } + + if (htc_hdr->eid == ENDPOINT_0) { + /* handle HTC control message */ + if (target->htc_flags & HTC_OP_STATE_SETUP_COMPLETE) { + /* + * fatal: target should not send unsolicited + * messageson the endpoint 0 + */ + ath6kl_dbg(ATH6KL_DBG_HTC, + "HTC ignores Rx Ctrl after setup complete\n"); + status = -EINVAL; + goto free_skb; + } + + /* remove HTC header */ + skb_pull(skb, HTC_HDR_LENGTH); + + netdata = skb->data; + netlen = skb->len; + + spin_lock_bh(&target->rx_lock); + + target->pipe.ctrl_response_valid = true; + target->pipe.ctrl_response_len = min_t(int, netlen, + HTC_MAX_CTRL_MSG_LEN); + memcpy(target->pipe.ctrl_response_buf, netdata, + target->pipe.ctrl_response_len); + + spin_unlock_bh(&target->rx_lock); + + dev_kfree_skb(skb); + skb = NULL; + goto free_skb; + } + + /* + * TODO: the message based HIF architecture allocates net bufs + * for recv packets since it bridges that HIF to upper layers, + * which expects HTC packets, we form the packets here + */ + packet = alloc_htc_packet_container(target); + if (packet == NULL) { + status = -ENOMEM; + goto free_skb; + } + + packet->status = 0; + packet->endpoint = htc_hdr->eid; + packet->pkt_cntxt = skb; + + /* TODO: for backwards compatibility */ + packet->buf = skb_push(skb, 0) + HTC_HDR_LENGTH; + packet->act_len = netlen - HTC_HDR_LENGTH - trailerlen; + + /* + * TODO: this is a hack because the driver layer will set the + * actual len of the skb again which will just double the len + */ + skb_trim(skb, 0); + + recv_packet_completion(target, ep, packet); + + /* recover the packet container */ + free_htc_packet_container(target, packet); + skb = NULL; + +free_skb: + if (skb != NULL) + dev_kfree_skb(skb); + + return status; + +} + +static void htc_flush_rx_queue(struct htc_target *target, + struct htc_endpoint *ep) +{ + struct list_head container; + struct htc_packet *packet; + + spin_lock_bh(&target->rx_lock); + + while (1) { + if (list_empty(&ep->rx_bufq)) + break; + + packet = list_first_entry(&ep->rx_bufq, + struct htc_packet, list); + list_del(&packet->list); + + spin_unlock_bh(&target->rx_lock); + packet->status = -ECANCELED; + packet->act_len = 0; + + ath6kl_dbg(ATH6KL_DBG_HTC, + "Flushing RX packet:0x%p, length:%d, ep:%d\n", + packet, packet->buf_len, + packet->endpoint); + + INIT_LIST_HEAD(&container); + list_add_tail(&packet->list, &container); + + /* give the packet back */ + do_recv_completion(ep, &container); + spin_lock_bh(&target->rx_lock); + } + + spin_unlock_bh(&target->rx_lock); +} + +/* polling routine to wait for a control packet to be received */ +static int htc_wait_recv_ctrl_message(struct htc_target *target) +{ + int count = HTC_TARGET_RESPONSE_POLL_COUNT; + + while (count > 0) { + spin_lock_bh(&target->rx_lock); + + if (target->pipe.ctrl_response_valid) { + target->pipe.ctrl_response_valid = false; + spin_unlock_bh(&target->rx_lock); + break; + } + + spin_unlock_bh(&target->rx_lock); + + count--; + + msleep_interruptible(HTC_TARGET_RESPONSE_POLL_WAIT); + } + + if (count <= 0) { + ath6kl_dbg(ATH6KL_DBG_HTC, "%s: Timeout!\n", __func__); + return -ECOMM; + } + + return 0; +} + +static void htc_rxctrl_complete(struct htc_target *context, + struct htc_packet *packet) +{ + /* TODO, can't really receive HTC control messages yet.... */ + ath6kl_dbg(ATH6KL_DBG_HTC, "%s: invalid call function\n", __func__); +} + +/* htc pipe initialization */ +static void reset_endpoint_states(struct htc_target *target) +{ + struct htc_endpoint *ep; + int i; + + for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) { + ep = &target->endpoint[i]; + ep->svc_id = 0; + ep->len_max = 0; + ep->max_txq_depth = 0; + ep->eid = i; + INIT_LIST_HEAD(&ep->txq); + INIT_LIST_HEAD(&ep->pipe.tx_lookup_queue); + INIT_LIST_HEAD(&ep->rx_bufq); + ep->target = target; + ep->pipe.tx_credit_flow_enabled = (bool) 1; /* FIXME */ + } +} + +/* start HTC, this is called after all services are connected */ +static int htc_config_target_hif_pipe(struct htc_target *target) +{ + return 0; +} + +/* htc service functions */ +static u8 htc_get_credit_alloc(struct htc_target *target, u16 service_id) +{ + u8 allocation = 0; + int i; + + for (i = 0; i < ENDPOINT_MAX; i++) { + if (target->pipe.txcredit_alloc[i].service_id == service_id) + allocation = + target->pipe.txcredit_alloc[i].credit_alloc; + } + + if (allocation == 0) { + ath6kl_dbg(ATH6KL_DBG_HTC, + "HTC Service TX : 0x%2.2X : allocation is zero!\n", + service_id); + } + + return allocation; +} + +static int ath6kl_htc_pipe_conn_service(struct htc_target *target, + struct htc_service_connect_req *conn_req, + struct htc_service_connect_resp *conn_resp) +{ + struct ath6kl *ar = target->dev->ar; + struct htc_packet *packet = NULL; + struct htc_conn_service_resp *resp_msg; + struct htc_conn_service_msg *conn_msg; + enum htc_endpoint_id assigned_epid = ENDPOINT_MAX; + bool disable_credit_flowctrl = false; + unsigned int max_msg_size = 0; + struct htc_endpoint *ep; + int length, status = 0; + struct sk_buff *skb; + u8 tx_alloc; + u16 flags; + + if (conn_req->svc_id == 0) { + WARN_ON_ONCE(1); + status = -EINVAL; + goto free_packet; + } + + if (conn_req->svc_id == HTC_CTRL_RSVD_SVC) { + /* special case for pseudo control service */ + assigned_epid = ENDPOINT_0; + max_msg_size = HTC_MAX_CTRL_MSG_LEN; + tx_alloc = 0; + + } else { + + tx_alloc = htc_get_credit_alloc(target, conn_req->svc_id); + if (tx_alloc == 0) { + status = -ENOMEM; + goto free_packet; + } + + /* allocate a packet to send to the target */ + packet = htc_alloc_txctrl_packet(target); + + if (packet == NULL) { + WARN_ON_ONCE(1); + status = -ENOMEM; + goto free_packet; + } + + skb = packet->skb; + length = sizeof(struct htc_conn_service_msg); + + /* assemble connect service message */ + conn_msg = (struct htc_conn_service_msg *) skb_put(skb, + length); + if (conn_msg == NULL) { + WARN_ON_ONCE(1); + status = -EINVAL; + goto free_packet; + } + + memset(conn_msg, 0, + sizeof(struct htc_conn_service_msg)); + conn_msg->msg_id = cpu_to_le16(HTC_MSG_CONN_SVC_ID); + conn_msg->svc_id = cpu_to_le16(conn_req->svc_id); + conn_msg->conn_flags = cpu_to_le16(conn_req->conn_flags & + ~HTC_CONN_FLGS_SET_RECV_ALLOC_MASK); + + /* tell target desired recv alloc for this ep */ + flags = tx_alloc << HTC_CONN_FLGS_SET_RECV_ALLOC_SHIFT; + conn_msg->conn_flags |= cpu_to_le16(flags); + + if (conn_req->conn_flags & + HTC_CONN_FLGS_DISABLE_CRED_FLOW_CTRL) { + disable_credit_flowctrl = true; + } + + set_htc_pkt_info(packet, NULL, (u8 *) conn_msg, + length, + ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); + + status = ath6kl_htc_pipe_tx(target, packet); + + /* we don't own it anymore */ + packet = NULL; + if (status != 0) + goto free_packet; + + /* wait for response */ + status = htc_wait_recv_ctrl_message(target); + if (status != 0) + goto free_packet; + + /* we controlled the buffer creation so it has to be + * properly aligned + */ + resp_msg = (struct htc_conn_service_resp *) + target->pipe.ctrl_response_buf; + + if (resp_msg->msg_id != cpu_to_le16(HTC_MSG_CONN_SVC_RESP_ID) || + (target->pipe.ctrl_response_len < sizeof(*resp_msg))) { + /* this message is not valid */ + WARN_ON_ONCE(1); + status = -EINVAL; + goto free_packet; + } + + ath6kl_dbg(ATH6KL_DBG_TRC, + "%s: service 0x%X conn resp: status: %d ep: %d\n", + __func__, resp_msg->svc_id, resp_msg->status, + resp_msg->eid); + + conn_resp->resp_code = resp_msg->status; + /* check response status */ + if (resp_msg->status != HTC_SERVICE_SUCCESS) { + ath6kl_dbg(ATH6KL_DBG_HTC, + "Target failed service 0x%X connect request (status:%d)\n", + resp_msg->svc_id, resp_msg->status); + status = -EINVAL; + goto free_packet; + } + + assigned_epid = (enum htc_endpoint_id) resp_msg->eid; + max_msg_size = le16_to_cpu(resp_msg->max_msg_sz); + } + + /* the rest are parameter checks so set the error status */ + status = -EINVAL; + + if (assigned_epid >= ENDPOINT_MAX) { + WARN_ON_ONCE(1); + goto free_packet; + } + + if (max_msg_size == 0) { + WARN_ON_ONCE(1); + goto free_packet; + } + + ep = &target->endpoint[assigned_epid]; + ep->eid = assigned_epid; + if (ep->svc_id != 0) { + /* endpoint already in use! */ + WARN_ON_ONCE(1); + goto free_packet; + } + + /* return assigned endpoint to caller */ + conn_resp->endpoint = assigned_epid; + conn_resp->len_max = max_msg_size; + + /* setup the endpoint */ + ep->svc_id = conn_req->svc_id; /* this marks ep in use */ + ep->max_txq_depth = conn_req->max_txq_depth; + ep->len_max = max_msg_size; + ep->cred_dist.credits = tx_alloc; + ep->cred_dist.cred_sz = target->tgt_cred_sz; + ep->cred_dist.cred_per_msg = max_msg_size / target->tgt_cred_sz; + if (max_msg_size % target->tgt_cred_sz) + ep->cred_dist.cred_per_msg++; + + /* copy all the callbacks */ + ep->ep_cb = conn_req->ep_cb; + + status = ath6kl_hif_pipe_map_service(ar, ep->svc_id, + &ep->pipe.pipeid_ul, + &ep->pipe.pipeid_dl); + if (status != 0) + goto free_packet; + + ath6kl_dbg(ATH6KL_DBG_HTC, + "SVC Ready: 0x%4.4X: ULpipe:%d DLpipe:%d id:%d\n", + ep->svc_id, ep->pipe.pipeid_ul, + ep->pipe.pipeid_dl, ep->eid); + + if (disable_credit_flowctrl && ep->pipe.tx_credit_flow_enabled) { + ep->pipe.tx_credit_flow_enabled = false; + ath6kl_dbg(ATH6KL_DBG_HTC, + "SVC: 0x%4.4X ep:%d TX flow control off\n", + ep->svc_id, assigned_epid); + } + +free_packet: + if (packet != NULL) + htc_free_txctrl_packet(target, packet); + return status; +} + +/* htc export functions */ +static void *ath6kl_htc_pipe_create(struct ath6kl *ar) +{ + int status = 0; + struct htc_endpoint *ep = NULL; + struct htc_target *target = NULL; + struct htc_packet *packet; + int i; + + target = kzalloc(sizeof(struct htc_target), GFP_KERNEL); + if (target == NULL) { + ath6kl_err("htc create unable to allocate memory\n"); + status = -ENOMEM; + goto fail_htc_create; + } + + spin_lock_init(&target->htc_lock); + spin_lock_init(&target->rx_lock); + spin_lock_init(&target->tx_lock); + + reset_endpoint_states(target); + + for (i = 0; i < HTC_PACKET_CONTAINER_ALLOCATION; i++) { + packet = kzalloc(sizeof(struct htc_packet), GFP_KERNEL); + + if (packet != NULL) + free_htc_packet_container(target, packet); + } + + target->dev = kzalloc(sizeof(*target->dev), GFP_KERNEL); + if (!target->dev) { + ath6kl_err("unable to allocate memory\n"); + status = -ENOMEM; + goto fail_htc_create; + } + target->dev->ar = ar; + target->dev->htc_cnxt = target; + + /* Get HIF default pipe for HTC message exchange */ + ep = &target->endpoint[ENDPOINT_0]; + + ath6kl_hif_pipe_get_default(ar, &ep->pipe.pipeid_ul, + &ep->pipe.pipeid_dl); + + return target; + +fail_htc_create: + if (status != 0) { + if (target != NULL) + ath6kl_htc_pipe_cleanup(target); + + target = NULL; + } + return target; +} + +/* cleanup the HTC instance */ +static void ath6kl_htc_pipe_cleanup(struct htc_target *target) +{ + struct htc_packet *packet; + + while (true) { + packet = alloc_htc_packet_container(target); + if (packet == NULL) + break; + kfree(packet); + } + + kfree(target->dev); + + /* kfree our instance */ + kfree(target); +} + +static int ath6kl_htc_pipe_start(struct htc_target *target) +{ + struct sk_buff *skb; + struct htc_setup_comp_ext_msg *setup; + struct htc_packet *packet; + + htc_config_target_hif_pipe(target); + + /* allocate a buffer to send */ + packet = htc_alloc_txctrl_packet(target); + if (packet == NULL) { + WARN_ON_ONCE(1); + return -ENOMEM; + } + + skb = packet->skb; + + /* assemble setup complete message */ + setup = (struct htc_setup_comp_ext_msg *) skb_put(skb, + sizeof(*setup)); + memset(setup, 0, sizeof(struct htc_setup_comp_ext_msg)); + setup->msg_id = cpu_to_le16(HTC_MSG_SETUP_COMPLETE_EX_ID); + + ath6kl_dbg(ATH6KL_DBG_HTC, "HTC using TX credit flow control\n"); + + set_htc_pkt_info(packet, NULL, (u8 *) setup, + sizeof(struct htc_setup_comp_ext_msg), + ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); + + target->htc_flags |= HTC_OP_STATE_SETUP_COMPLETE; + + return ath6kl_htc_pipe_tx(target, packet); +} + +static void ath6kl_htc_pipe_stop(struct htc_target *target) +{ + int i; + struct htc_endpoint *ep; + + /* cleanup endpoints */ + for (i = 0; i < ENDPOINT_MAX; i++) { + ep = &target->endpoint[i]; + htc_flush_rx_queue(target, ep); + htc_flush_tx_endpoint(target, ep, HTC_TX_PACKET_TAG_ALL); + } + + reset_endpoint_states(target); + target->htc_flags &= ~HTC_OP_STATE_SETUP_COMPLETE; +} + +static int ath6kl_htc_pipe_get_rxbuf_num(struct htc_target *target, + enum htc_endpoint_id endpoint) +{ + int num; + + spin_lock_bh(&target->rx_lock); + num = get_queue_depth(&(target->endpoint[endpoint].rx_bufq)); + spin_unlock_bh(&target->rx_lock); + + return num; +} + +static int ath6kl_htc_pipe_tx(struct htc_target *target, + struct htc_packet *packet) +{ + struct list_head queue; + + ath6kl_dbg(ATH6KL_DBG_HTC, + "%s: endPointId: %d, buffer: 0x%p, length: %d\n", + __func__, packet->endpoint, packet->buf, + packet->act_len); + + INIT_LIST_HEAD(&queue); + list_add_tail(&packet->list, &queue); + + return htc_send_packets_multiple(target, &queue); +} + +static int ath6kl_htc_pipe_wait_target(struct htc_target *target) +{ + struct htc_ready_ext_msg *ready_msg; + struct htc_service_connect_req connect; + struct htc_service_connect_resp resp; + int status = 0; + + status = htc_wait_recv_ctrl_message(target); + + if (status != 0) + return status; + + if (target->pipe.ctrl_response_len < sizeof(*ready_msg)) { + ath6kl_dbg(ATH6KL_DBG_HTC, "invalid htc ready msg len:%d!\n", + target->pipe.ctrl_response_len); + return -ECOMM; + } + + ready_msg = (struct htc_ready_ext_msg *) target->pipe.ctrl_response_buf; + + if (ready_msg->ver2_0_info.msg_id != cpu_to_le16(HTC_MSG_READY_ID)) { + ath6kl_dbg(ATH6KL_DBG_HTC, "invalid htc ready msg : 0x%X !\n", + ready_msg->ver2_0_info.msg_id); + return -ECOMM; + } + + ath6kl_dbg(ATH6KL_DBG_HTC, + "Target Ready! : transmit resources : %d size:%d\n", + ready_msg->ver2_0_info.cred_cnt, + ready_msg->ver2_0_info.cred_sz); + + target->tgt_creds = le16_to_cpu(ready_msg->ver2_0_info.cred_cnt); + target->tgt_cred_sz = le16_to_cpu(ready_msg->ver2_0_info.cred_sz); + + if ((target->tgt_creds == 0) || (target->tgt_cred_sz == 0)) + return -ECOMM; + + htc_setup_target_buffer_assignments(target); + + /* setup our pseudo HTC control endpoint connection */ + memset(&connect, 0, sizeof(connect)); + memset(&resp, 0, sizeof(resp)); + connect.ep_cb.tx_complete = htc_txctrl_complete; + connect.ep_cb.rx = htc_rxctrl_complete; + connect.max_txq_depth = NUM_CONTROL_TX_BUFFERS; + connect.svc_id = HTC_CTRL_RSVD_SVC; + + /* connect fake service */ + status = ath6kl_htc_pipe_conn_service(target, &connect, &resp); + + return status; +} + +static void ath6kl_htc_pipe_flush_txep(struct htc_target *target, + enum htc_endpoint_id endpoint, u16 tag) +{ + struct htc_endpoint *ep = &target->endpoint[endpoint]; + + if (ep->svc_id == 0) { + WARN_ON_ONCE(1); + /* not in use.. */ + return; + } + + htc_flush_tx_endpoint(target, ep, tag); +} + +static int ath6kl_htc_pipe_add_rxbuf_multiple(struct htc_target *target, + struct list_head *pkt_queue) +{ + struct htc_packet *packet, *tmp_pkt, *first; + struct htc_endpoint *ep; + int status = 0; + + if (list_empty(pkt_queue)) + return -EINVAL; + + first = list_first_entry(pkt_queue, struct htc_packet, list); + if (first == NULL) { + WARN_ON_ONCE(1); + return -EINVAL; + } + + if (first->endpoint >= ENDPOINT_MAX) { + WARN_ON_ONCE(1); + return -EINVAL; + } + + ath6kl_dbg(ATH6KL_DBG_HTC, "%s: epid: %d, cnt:%d, len: %d\n", + __func__, first->endpoint, get_queue_depth(pkt_queue), + first->buf_len); + + ep = &target->endpoint[first->endpoint]; + + spin_lock_bh(&target->rx_lock); + + /* store receive packets */ + list_splice_tail_init(pkt_queue, &ep->rx_bufq); + + spin_unlock_bh(&target->rx_lock); + + if (status != 0) { + /* walk through queue and mark each one canceled */ + list_for_each_entry_safe(packet, tmp_pkt, pkt_queue, list) { + packet->status = -ECANCELED; + } + + do_recv_completion(ep, pkt_queue); + } + + return status; +} + +static void ath6kl_htc_pipe_activity_changed(struct htc_target *target, + enum htc_endpoint_id ep, + bool active) +{ + /* TODO */ +} + +static void ath6kl_htc_pipe_flush_rx_buf(struct htc_target *target) +{ + /* TODO */ +} + +static int ath6kl_htc_pipe_credit_setup(struct htc_target *target, + struct ath6kl_htc_credit_info *info) +{ + return 0; +} + +static const struct ath6kl_htc_ops ath6kl_htc_pipe_ops = { + .create = ath6kl_htc_pipe_create, + .wait_target = ath6kl_htc_pipe_wait_target, + .start = ath6kl_htc_pipe_start, + .conn_service = ath6kl_htc_pipe_conn_service, + .tx = ath6kl_htc_pipe_tx, + .stop = ath6kl_htc_pipe_stop, + .cleanup = ath6kl_htc_pipe_cleanup, + .flush_txep = ath6kl_htc_pipe_flush_txep, + .flush_rx_buf = ath6kl_htc_pipe_flush_rx_buf, + .activity_changed = ath6kl_htc_pipe_activity_changed, + .get_rxbuf_num = ath6kl_htc_pipe_get_rxbuf_num, + .add_rxbuf_multiple = ath6kl_htc_pipe_add_rxbuf_multiple, + .credit_setup = ath6kl_htc_pipe_credit_setup, + .tx_complete = ath6kl_htc_pipe_tx_complete, + .rx_complete = ath6kl_htc_pipe_rx_complete, +}; + +void ath6kl_htc_pipe_attach(struct ath6kl *ar) +{ + ar->htc_ops = &ath6kl_htc_pipe_ops; +} diff --git a/trunk/drivers/net/wireless/ath/ath6kl/init.c b/trunk/drivers/net/wireless/ath/ath6kl/init.c index 03cae142f178..29ef50ea07d5 100644 --- a/trunk/drivers/net/wireless/ath/ath6kl/init.c +++ b/trunk/drivers/net/wireless/ath/ath6kl/init.c @@ -16,17 +16,21 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include #include #include +#include #include "core.h" #include "cfg80211.h" #include "target.h" #include "debug.h" #include "hif-ops.h" +#include "htc-ops.h" static const struct ath6kl_hw hw_list[] = { { @@ -256,6 +260,7 @@ static int ath6kl_init_service_ep(struct ath6kl *ar) memset(&connect, 0, sizeof(connect)); /* these fields are the same for all service endpoints */ + connect.ep_cb.tx_comp_multi = ath6kl_tx_complete; connect.ep_cb.rx = ath6kl_rx; connect.ep_cb.rx_refill = ath6kl_rx_refill; connect.ep_cb.tx_full = ath6kl_tx_queue_full; @@ -485,22 +490,31 @@ int ath6kl_configure_target(struct ath6kl *ar) fw_mode |= fw_iftype << (i * HI_OPTION_FW_MODE_BITS); /* - * By default, submodes : + * Submodes when fw does not support dynamic interface + * switching: * vif[0] - AP/STA/IBSS * vif[1] - "P2P dev"/"P2P GO"/"P2P Client" * vif[2] - "P2P dev"/"P2P GO"/"P2P Client" + * Otherwise, All the interface are initialized to p2p dev. */ - for (i = 0; i < ar->max_norm_iface; i++) - fw_submode |= HI_OPTION_FW_SUBMODE_NONE << - (i * HI_OPTION_FW_SUBMODE_BITS); + if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, + ar->fw_capabilities)) { + for (i = 0; i < ar->vif_max; i++) + fw_submode |= HI_OPTION_FW_SUBMODE_P2PDEV << + (i * HI_OPTION_FW_SUBMODE_BITS); + } else { + for (i = 0; i < ar->max_norm_iface; i++) + fw_submode |= HI_OPTION_FW_SUBMODE_NONE << + (i * HI_OPTION_FW_SUBMODE_BITS); - for (i = ar->max_norm_iface; i < ar->vif_max; i++) - fw_submode |= HI_OPTION_FW_SUBMODE_P2PDEV << - (i * HI_OPTION_FW_SUBMODE_BITS); + for (i = ar->max_norm_iface; i < ar->vif_max; i++) + fw_submode |= HI_OPTION_FW_SUBMODE_P2PDEV << + (i * HI_OPTION_FW_SUBMODE_BITS); - if (ar->p2p && ar->vif_max == 1) - fw_submode = HI_OPTION_FW_SUBMODE_P2PDEV; + if (ar->p2p && ar->vif_max == 1) + fw_submode = HI_OPTION_FW_SUBMODE_P2PDEV; + } if (ath6kl_bmi_write_hi32(ar, hi_app_host_interest, HTC_PROTOCOL_VERSION) != 0) { @@ -539,18 +553,20 @@ int ath6kl_configure_target(struct ath6kl *ar) * but possible in theory. */ - param = ar->hw.board_ext_data_addr; - ram_reserved_size = ar->hw.reserved_ram_size; + if (ar->target_type == TARGET_TYPE_AR6003) { + param = ar->hw.board_ext_data_addr; + ram_reserved_size = ar->hw.reserved_ram_size; - if (ath6kl_bmi_write_hi32(ar, hi_board_ext_data, param) != 0) { - ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n"); - return -EIO; - } + if (ath6kl_bmi_write_hi32(ar, hi_board_ext_data, param) != 0) { + ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n"); + return -EIO; + } - if (ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz, - ram_reserved_size) != 0) { - ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n"); - return -EIO; + if (ath6kl_bmi_write_hi32(ar, hi_end_ram_reserve_sz, + ram_reserved_size) != 0) { + ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n"); + return -EIO; + } } /* set the block size for the target */ @@ -924,13 +940,14 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) if (ar->fw != NULL) break; - ar->fw = kmemdup(data, ie_len, GFP_KERNEL); + ar->fw = vmalloc(ie_len); if (ar->fw == NULL) { ret = -ENOMEM; goto out; } + memcpy(ar->fw, data, ie_len); ar->fw_len = ie_len; break; case ATH6KL_FW_IE_PATCH_IMAGE: @@ -1507,7 +1524,7 @@ int ath6kl_init_hw_start(struct ath6kl *ar) } /* setup credit distribution */ - ath6kl_credit_setup(ar->htc_target, &ar->credit_state_info); + ath6kl_htc_credit_setup(ar->htc_target, &ar->credit_state_info); /* start HTC */ ret = ath6kl_htc_start(ar->htc_target); diff --git a/trunk/drivers/net/wireless/ath/ath6kl/main.c b/trunk/drivers/net/wireless/ath/ath6kl/main.c index 229e1922ebe4..4d818f96c415 100644 --- a/trunk/drivers/net/wireless/ath/ath6kl/main.c +++ b/trunk/drivers/net/wireless/ath/ath6kl/main.c @@ -15,6 +15,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "core.h" #include "hif-ops.h" #include "cfg80211.h" @@ -756,6 +758,10 @@ static void ath6kl_update_target_stats(struct ath6kl_vif *vif, u8 *ptr, u32 len) stats->wow_evt_discarded += le16_to_cpu(tgt_stats->wow_stats.wow_evt_discarded); + stats->arp_received = le32_to_cpu(tgt_stats->arp_stats.arp_received); + stats->arp_replied = le32_to_cpu(tgt_stats->arp_stats.arp_replied); + stats->arp_matched = le32_to_cpu(tgt_stats->arp_stats.arp_matched); + if (test_bit(STATS_UPDATE_PEND, &vif->flags)) { clear_bit(STATS_UPDATE_PEND, &vif->flags); wake_up(&ar->event_wq); diff --git a/trunk/drivers/net/wireless/ath/ath6kl/sdio.c b/trunk/drivers/net/wireless/ath/ath6kl/sdio.c index 53528648b425..44ea7a742101 100644 --- a/trunk/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/trunk/drivers/net/wireless/ath/ath6kl/sdio.c @@ -1362,7 +1362,7 @@ static int ath6kl_sdio_probe(struct sdio_func *func, goto err_core_alloc; } - ret = ath6kl_core_init(ar); + ret = ath6kl_core_init(ar, ATH6KL_HTC_TYPE_MBOX); if (ret) { ath6kl_err("Failed to init ath6kl core\n"); goto err_core_alloc; diff --git a/trunk/drivers/net/wireless/ath/ath6kl/testmode.c b/trunk/drivers/net/wireless/ath/ath6kl/testmode.c index 6675c92b542b..acc9aa832f76 100644 --- a/trunk/drivers/net/wireless/ath/ath6kl/testmode.c +++ b/trunk/drivers/net/wireless/ath/ath6kl/testmode.c @@ -55,8 +55,9 @@ void ath6kl_tm_rx_event(struct ath6kl *ar, void *buf, size_t buf_len) ath6kl_warn("failed to allocate testmode rx skb!\n"); return; } - NLA_PUT_U32(skb, ATH6KL_TM_ATTR_CMD, ATH6KL_TM_CMD_TCMD); - NLA_PUT(skb, ATH6KL_TM_ATTR_DATA, buf_len, buf); + if (nla_put_u32(skb, ATH6KL_TM_ATTR_CMD, ATH6KL_TM_CMD_TCMD) || + nla_put(skb, ATH6KL_TM_ATTR_DATA, buf_len, buf)) + goto nla_put_failure; cfg80211_testmode_event(skb, GFP_KERNEL); return; diff --git a/trunk/drivers/net/wireless/ath/ath6kl/txrx.c b/trunk/drivers/net/wireless/ath/ath6kl/txrx.c index f85353fd1792..82f2f5cb475b 100644 --- a/trunk/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/trunk/drivers/net/wireless/ath/ath6kl/txrx.c @@ -15,8 +15,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "core.h" #include "debug.h" +#include "htc-ops.h" /* * tid - tid_mux0..tid_mux3 @@ -322,6 +325,7 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb, cookie->map_no = 0; set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len, eid, ATH6KL_CONTROL_PKT_TAG); + cookie->htc_pkt.skb = skb; /* * This interface is asynchronous, if there is an error, cleanup @@ -490,6 +494,7 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) cookie->map_no = map_no; set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len, eid, htc_tag); + cookie->htc_pkt.skb = skb; ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "tx ", skb->data, skb->len); @@ -570,7 +575,7 @@ void ath6kl_indicate_tx_activity(void *devt, u8 traffic_class, bool active) notify_htc: /* notify HTC, this may cause credit distribution changes */ - ath6kl_htc_indicate_activity_change(ar->htc_target, eid, active); + ath6kl_htc_activity_changed(ar->htc_target, eid, active); } enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, @@ -666,9 +671,10 @@ static void ath6kl_tx_clear_node_map(struct ath6kl_vif *vif, } } -void ath6kl_tx_complete(void *context, struct list_head *packet_queue) +void ath6kl_tx_complete(struct htc_target *target, + struct list_head *packet_queue) { - struct ath6kl *ar = context; + struct ath6kl *ar = target->dev->ar; struct sk_buff_head skb_queue; struct htc_packet *packet; struct sk_buff *skb; @@ -887,6 +893,7 @@ void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint) skb->data = PTR_ALIGN(skb->data - 4, 4); set_htc_rxpkt_info(packet, skb, skb->data, ATH6KL_BUFFER_SIZE, endpoint); + packet->skb = skb; list_add_tail(&packet->list, &queue); } @@ -909,6 +916,8 @@ void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count) skb->data = PTR_ALIGN(skb->data - 4, 4); set_htc_rxpkt_info(packet, skb, skb->data, ATH6KL_AMSDU_BUFFER_SIZE, 0); + packet->skb = skb; + spin_lock_bh(&ar->lock); list_add_tail(&packet->list, &ar->amsdu_rx_buffer_queue); spin_unlock_bh(&ar->lock); @@ -1281,6 +1290,7 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) struct wmi_data_hdr *dhdr; int min_hdr_len; u8 meta_type, dot11_hdr = 0; + u8 pad_before_data_start; int status = packet->status; enum htc_endpoint_id ept = packet->endpoint; bool is_amsdu, prev_ps, ps_state = false; @@ -1492,6 +1502,10 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) seq_no = wmi_data_hdr_get_seqno(dhdr); meta_type = wmi_data_hdr_get_meta(dhdr); dot11_hdr = wmi_data_hdr_get_dot11(dhdr); + pad_before_data_start = + (le16_to_cpu(dhdr->info3) >> WMI_DATA_HDR_PAD_BEFORE_DATA_SHIFT) + & WMI_DATA_HDR_PAD_BEFORE_DATA_MASK; + skb_pull(skb, sizeof(struct wmi_data_hdr)); switch (meta_type) { @@ -1510,6 +1524,8 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) break; } + skb_pull(skb, pad_before_data_start); + if (dot11_hdr) status = ath6kl_wmi_dot11_hdr_remove(ar->wmi, skb); else if (!is_amsdu) @@ -1579,7 +1595,8 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) /* aggregation code will handle the skb */ return; } - } + } else if (!is_broadcast_ether_addr(datap->h_dest)) + vif->net_stats.multicast++; ath6kl_deliver_frames_to_nw_stack(vif->ndev, skb); } diff --git a/trunk/drivers/net/wireless/ath/ath6kl/usb.c b/trunk/drivers/net/wireless/ath/ath6kl/usb.c index 325b1224c2b1..44a795f14da9 100644 --- a/trunk/drivers/net/wireless/ath/ath6kl/usb.c +++ b/trunk/drivers/net/wireless/ath/ath6kl/usb.c @@ -21,15 +21,77 @@ #include "debug.h" #include "core.h" +/* constants */ +#define TX_URB_COUNT 32 +#define RX_URB_COUNT 32 +#define ATH6KL_USB_RX_BUFFER_SIZE 1700 + +/* tx/rx pipes for usb */ +enum ATH6KL_USB_PIPE_ID { + ATH6KL_USB_PIPE_TX_CTRL = 0, + ATH6KL_USB_PIPE_TX_DATA_LP, + ATH6KL_USB_PIPE_TX_DATA_MP, + ATH6KL_USB_PIPE_TX_DATA_HP, + ATH6KL_USB_PIPE_RX_CTRL, + ATH6KL_USB_PIPE_RX_DATA, + ATH6KL_USB_PIPE_RX_DATA2, + ATH6KL_USB_PIPE_RX_INT, + ATH6KL_USB_PIPE_MAX +}; + +#define ATH6KL_USB_PIPE_INVALID ATH6KL_USB_PIPE_MAX + +struct ath6kl_usb_pipe { + struct list_head urb_list_head; + struct usb_anchor urb_submitted; + u32 urb_alloc; + u32 urb_cnt; + u32 urb_cnt_thresh; + unsigned int usb_pipe_handle; + u32 flags; + u8 ep_address; + u8 logical_pipe_num; + struct ath6kl_usb *ar_usb; + u16 max_packet_size; + struct work_struct io_complete_work; + struct sk_buff_head io_comp_queue; + struct usb_endpoint_descriptor *ep_desc; +}; + +#define ATH6KL_USB_PIPE_FLAG_TX (1 << 0) + /* usb device object */ struct ath6kl_usb { + /* protects pipe->urb_list_head and pipe->urb_cnt */ + spinlock_t cs_lock; + struct usb_device *udev; struct usb_interface *interface; + struct ath6kl_usb_pipe pipes[ATH6KL_USB_PIPE_MAX]; u8 *diag_cmd_buffer; u8 *diag_resp_buffer; struct ath6kl *ar; }; +/* usb urb object */ +struct ath6kl_urb_context { + struct list_head link; + struct ath6kl_usb_pipe *pipe; + struct sk_buff *skb; + struct ath6kl *ar; +}; + +/* USB endpoint definitions */ +#define ATH6KL_USB_EP_ADDR_APP_CTRL_IN 0x81 +#define ATH6KL_USB_EP_ADDR_APP_DATA_IN 0x82 +#define ATH6KL_USB_EP_ADDR_APP_DATA2_IN 0x83 +#define ATH6KL_USB_EP_ADDR_APP_INT_IN 0x84 + +#define ATH6KL_USB_EP_ADDR_APP_CTRL_OUT 0x01 +#define ATH6KL_USB_EP_ADDR_APP_DATA_LP_OUT 0x02 +#define ATH6KL_USB_EP_ADDR_APP_DATA_MP_OUT 0x03 +#define ATH6KL_USB_EP_ADDR_APP_DATA_HP_OUT 0x04 + /* diagnostic command defnitions */ #define ATH6KL_USB_CONTROL_REQ_SEND_BMI_CMD 1 #define ATH6KL_USB_CONTROL_REQ_RECV_BMI_RESP 2 @@ -55,11 +117,493 @@ struct ath6kl_usb_ctrl_diag_resp_read { __le32 value; } __packed; +/* function declarations */ +static void ath6kl_usb_recv_complete(struct urb *urb); + +#define ATH6KL_USB_IS_BULK_EP(attr) (((attr) & 3) == 0x02) +#define ATH6KL_USB_IS_INT_EP(attr) (((attr) & 3) == 0x03) +#define ATH6KL_USB_IS_ISOC_EP(attr) (((attr) & 3) == 0x01) +#define ATH6KL_USB_IS_DIR_IN(addr) ((addr) & 0x80) + +/* pipe/urb operations */ +static struct ath6kl_urb_context * +ath6kl_usb_alloc_urb_from_pipe(struct ath6kl_usb_pipe *pipe) +{ + struct ath6kl_urb_context *urb_context = NULL; + unsigned long flags; + + spin_lock_irqsave(&pipe->ar_usb->cs_lock, flags); + if (!list_empty(&pipe->urb_list_head)) { + urb_context = + list_first_entry(&pipe->urb_list_head, + struct ath6kl_urb_context, link); + list_del(&urb_context->link); + pipe->urb_cnt--; + } + spin_unlock_irqrestore(&pipe->ar_usb->cs_lock, flags); + + return urb_context; +} + +static void ath6kl_usb_free_urb_to_pipe(struct ath6kl_usb_pipe *pipe, + struct ath6kl_urb_context *urb_context) +{ + unsigned long flags; + + spin_lock_irqsave(&pipe->ar_usb->cs_lock, flags); + pipe->urb_cnt++; + + list_add(&urb_context->link, &pipe->urb_list_head); + spin_unlock_irqrestore(&pipe->ar_usb->cs_lock, flags); +} + +static void ath6kl_usb_cleanup_recv_urb(struct ath6kl_urb_context *urb_context) +{ + if (urb_context->skb != NULL) { + dev_kfree_skb(urb_context->skb); + urb_context->skb = NULL; + } + + ath6kl_usb_free_urb_to_pipe(urb_context->pipe, urb_context); +} + +static inline struct ath6kl_usb *ath6kl_usb_priv(struct ath6kl *ar) +{ + return ar->hif_priv; +} + +/* pipe resource allocation/cleanup */ +static int ath6kl_usb_alloc_pipe_resources(struct ath6kl_usb_pipe *pipe, + int urb_cnt) +{ + struct ath6kl_urb_context *urb_context; + int status = 0, i; + + INIT_LIST_HEAD(&pipe->urb_list_head); + init_usb_anchor(&pipe->urb_submitted); + + for (i = 0; i < urb_cnt; i++) { + urb_context = kzalloc(sizeof(struct ath6kl_urb_context), + GFP_KERNEL); + if (urb_context == NULL) + /* FIXME: set status to -ENOMEM */ + break; + + urb_context->pipe = pipe; + + /* + * we are only allocate the urb contexts here, the actual URB + * is allocated from the kernel as needed to do a transaction + */ + pipe->urb_alloc++; + ath6kl_usb_free_urb_to_pipe(pipe, urb_context); + } + + ath6kl_dbg(ATH6KL_DBG_USB, + "ath6kl usb: alloc resources lpipe:%d hpipe:0x%X urbs:%d\n", + pipe->logical_pipe_num, pipe->usb_pipe_handle, + pipe->urb_alloc); + + return status; +} + +static void ath6kl_usb_free_pipe_resources(struct ath6kl_usb_pipe *pipe) +{ + struct ath6kl_urb_context *urb_context; + + if (pipe->ar_usb == NULL) { + /* nothing allocated for this pipe */ + return; + } + + ath6kl_dbg(ATH6KL_DBG_USB, + "ath6kl usb: free resources lpipe:%d" + "hpipe:0x%X urbs:%d avail:%d\n", + pipe->logical_pipe_num, pipe->usb_pipe_handle, + pipe->urb_alloc, pipe->urb_cnt); + + if (pipe->urb_alloc != pipe->urb_cnt) { + ath6kl_dbg(ATH6KL_DBG_USB, + "ath6kl usb: urb leak! lpipe:%d" + "hpipe:0x%X urbs:%d avail:%d\n", + pipe->logical_pipe_num, pipe->usb_pipe_handle, + pipe->urb_alloc, pipe->urb_cnt); + } + + while (true) { + urb_context = ath6kl_usb_alloc_urb_from_pipe(pipe); + if (urb_context == NULL) + break; + kfree(urb_context); + } + +} + +static void ath6kl_usb_cleanup_pipe_resources(struct ath6kl_usb *ar_usb) +{ + int i; + + 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, + u8 ep_address, int *urb_count) +{ + u8 pipe_num = ATH6KL_USB_PIPE_INVALID; + + switch (ep_address) { + case ATH6KL_USB_EP_ADDR_APP_CTRL_IN: + pipe_num = ATH6KL_USB_PIPE_RX_CTRL; + *urb_count = RX_URB_COUNT; + break; + case ATH6KL_USB_EP_ADDR_APP_DATA_IN: + pipe_num = ATH6KL_USB_PIPE_RX_DATA; + *urb_count = RX_URB_COUNT; + break; + case ATH6KL_USB_EP_ADDR_APP_INT_IN: + pipe_num = ATH6KL_USB_PIPE_RX_INT; + *urb_count = RX_URB_COUNT; + break; + case ATH6KL_USB_EP_ADDR_APP_DATA2_IN: + pipe_num = ATH6KL_USB_PIPE_RX_DATA2; + *urb_count = RX_URB_COUNT; + break; + case ATH6KL_USB_EP_ADDR_APP_CTRL_OUT: + pipe_num = ATH6KL_USB_PIPE_TX_CTRL; + *urb_count = TX_URB_COUNT; + break; + case ATH6KL_USB_EP_ADDR_APP_DATA_LP_OUT: + pipe_num = ATH6KL_USB_PIPE_TX_DATA_LP; + *urb_count = TX_URB_COUNT; + break; + case ATH6KL_USB_EP_ADDR_APP_DATA_MP_OUT: + pipe_num = ATH6KL_USB_PIPE_TX_DATA_MP; + *urb_count = TX_URB_COUNT; + break; + case ATH6KL_USB_EP_ADDR_APP_DATA_HP_OUT: + pipe_num = ATH6KL_USB_PIPE_TX_DATA_HP; + *urb_count = TX_URB_COUNT; + break; + default: + /* note: there may be endpoints not currently used */ + break; + } + + return pipe_num; +} + +static int ath6kl_usb_setup_pipe_resources(struct ath6kl_usb *ar_usb) +{ + struct usb_interface *interface = ar_usb->interface; + struct usb_host_interface *iface_desc = interface->cur_altsetting; + struct usb_endpoint_descriptor *endpoint; + struct ath6kl_usb_pipe *pipe; + int i, urbcount, status = 0; + u8 pipe_num; + + ath6kl_dbg(ATH6KL_DBG_USB, "setting up USB Pipes using interface\n"); + + /* walk decriptors and setup pipes */ + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + + if (ATH6KL_USB_IS_BULK_EP(endpoint->bmAttributes)) { + ath6kl_dbg(ATH6KL_DBG_USB, + "%s Bulk Ep:0x%2.2X maxpktsz:%d\n", + ATH6KL_USB_IS_DIR_IN + (endpoint->bEndpointAddress) ? + "RX" : "TX", endpoint->bEndpointAddress, + le16_to_cpu(endpoint->wMaxPacketSize)); + } else if (ATH6KL_USB_IS_INT_EP(endpoint->bmAttributes)) { + ath6kl_dbg(ATH6KL_DBG_USB, + "%s Int Ep:0x%2.2X maxpktsz:%d interval:%d\n", + ATH6KL_USB_IS_DIR_IN + (endpoint->bEndpointAddress) ? + "RX" : "TX", endpoint->bEndpointAddress, + le16_to_cpu(endpoint->wMaxPacketSize), + endpoint->bInterval); + } else if (ATH6KL_USB_IS_ISOC_EP(endpoint->bmAttributes)) { + /* TODO for ISO */ + ath6kl_dbg(ATH6KL_DBG_USB, + "%s ISOC Ep:0x%2.2X maxpktsz:%d interval:%d\n", + ATH6KL_USB_IS_DIR_IN + (endpoint->bEndpointAddress) ? + "RX" : "TX", endpoint->bEndpointAddress, + le16_to_cpu(endpoint->wMaxPacketSize), + endpoint->bInterval); + } + urbcount = 0; + + pipe_num = + ath6kl_usb_get_logical_pipe_num(ar_usb, + endpoint->bEndpointAddress, + &urbcount); + if (pipe_num == ATH6KL_USB_PIPE_INVALID) + continue; + + pipe = &ar_usb->pipes[pipe_num]; + if (pipe->ar_usb != NULL) { + /* hmmm..pipe was already setup */ + continue; + } + + pipe->ar_usb = ar_usb; + pipe->logical_pipe_num = pipe_num; + pipe->ep_address = endpoint->bEndpointAddress; + pipe->max_packet_size = le16_to_cpu(endpoint->wMaxPacketSize); + + if (ATH6KL_USB_IS_BULK_EP(endpoint->bmAttributes)) { + if (ATH6KL_USB_IS_DIR_IN(pipe->ep_address)) { + pipe->usb_pipe_handle = + usb_rcvbulkpipe(ar_usb->udev, + pipe->ep_address); + } else { + pipe->usb_pipe_handle = + usb_sndbulkpipe(ar_usb->udev, + pipe->ep_address); + } + } else if (ATH6KL_USB_IS_INT_EP(endpoint->bmAttributes)) { + if (ATH6KL_USB_IS_DIR_IN(pipe->ep_address)) { + pipe->usb_pipe_handle = + usb_rcvintpipe(ar_usb->udev, + pipe->ep_address); + } else { + pipe->usb_pipe_handle = + usb_sndintpipe(ar_usb->udev, + pipe->ep_address); + } + } else if (ATH6KL_USB_IS_ISOC_EP(endpoint->bmAttributes)) { + /* TODO for ISO */ + if (ATH6KL_USB_IS_DIR_IN(pipe->ep_address)) { + pipe->usb_pipe_handle = + usb_rcvisocpipe(ar_usb->udev, + pipe->ep_address); + } else { + pipe->usb_pipe_handle = + usb_sndisocpipe(ar_usb->udev, + pipe->ep_address); + } + } + + pipe->ep_desc = endpoint; + + if (!ATH6KL_USB_IS_DIR_IN(pipe->ep_address)) + pipe->flags |= ATH6KL_USB_PIPE_FLAG_TX; + + status = ath6kl_usb_alloc_pipe_resources(pipe, urbcount); + if (status != 0) + break; + } + + return status; +} + +/* pipe operations */ +static void ath6kl_usb_post_recv_transfers(struct ath6kl_usb_pipe *recv_pipe, + int buffer_length) +{ + struct ath6kl_urb_context *urb_context; + struct urb *urb; + int usb_status; + + while (true) { + urb_context = ath6kl_usb_alloc_urb_from_pipe(recv_pipe); + if (urb_context == NULL) + break; + + urb_context->skb = dev_alloc_skb(buffer_length); + if (urb_context->skb == NULL) + goto err_cleanup_urb; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (urb == NULL) + goto err_cleanup_urb; + + usb_fill_bulk_urb(urb, + recv_pipe->ar_usb->udev, + recv_pipe->usb_pipe_handle, + urb_context->skb->data, + buffer_length, + ath6kl_usb_recv_complete, urb_context); + + ath6kl_dbg(ATH6KL_DBG_USB_BULK, + "ath6kl usb: bulk recv submit:%d, 0x%X (ep:0x%2.2X), %d bytes buf:0x%p\n", + recv_pipe->logical_pipe_num, + recv_pipe->usb_pipe_handle, recv_pipe->ep_address, + buffer_length, urb_context->skb); + + usb_anchor_urb(urb, &recv_pipe->urb_submitted); + usb_status = usb_submit_urb(urb, GFP_ATOMIC); + + if (usb_status) { + ath6kl_dbg(ATH6KL_DBG_USB_BULK, + "ath6kl usb : usb bulk recv failed %d\n", + usb_status); + usb_unanchor_urb(urb); + usb_free_urb(urb); + goto err_cleanup_urb; + } + usb_free_urb(urb); + } + return; + +err_cleanup_urb: + ath6kl_usb_cleanup_recv_urb(urb_context); + return; +} + +static void ath6kl_usb_flush_all(struct ath6kl_usb *ar_usb) +{ + int i; + + for (i = 0; i < ATH6KL_USB_PIPE_MAX; i++) { + if (ar_usb->pipes[i].ar_usb != NULL) + usb_kill_anchored_urbs(&ar_usb->pipes[i].urb_submitted); + } + + /* + * Flushing any pending I/O may schedule work this call will block + * until all scheduled work runs to completion. + */ + flush_scheduled_work(); +} + +static void ath6kl_usb_start_recv_pipes(struct ath6kl_usb *ar_usb) +{ + /* + * note: control pipe is no longer used + * ar_usb->pipes[ATH6KL_USB_PIPE_RX_CTRL].urb_cnt_thresh = + * ar_usb->pipes[ATH6KL_USB_PIPE_RX_CTRL].urb_alloc/2; + * ath6kl_usb_post_recv_transfers(&ar_usb-> + * pipes[ATH6KL_USB_PIPE_RX_CTRL], + * ATH6KL_USB_RX_BUFFER_SIZE); + */ + + ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_cnt_thresh = + ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA].urb_alloc / 2; + ath6kl_usb_post_recv_transfers(&ar_usb->pipes[ATH6KL_USB_PIPE_RX_DATA], + ATH6KL_USB_RX_BUFFER_SIZE); +} + +/* hif usb rx/tx completion functions */ +static void ath6kl_usb_recv_complete(struct urb *urb) +{ + struct ath6kl_urb_context *urb_context = urb->context; + struct ath6kl_usb_pipe *pipe = urb_context->pipe; + struct sk_buff *skb = NULL; + int status = 0; + + ath6kl_dbg(ATH6KL_DBG_USB_BULK, + "%s: recv pipe: %d, stat:%d, len:%d urb:0x%p\n", __func__, + pipe->logical_pipe_num, urb->status, urb->actual_length, + urb); + + if (urb->status != 0) { + status = -EIO; + switch (urb->status) { + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* + * no need to spew these errors when device + * removed or urb killed due to driver shutdown + */ + status = -ECANCELED; + break; + default: + ath6kl_dbg(ATH6KL_DBG_USB_BULK, + "%s recv pipe: %d (ep:0x%2.2X), failed:%d\n", + __func__, pipe->logical_pipe_num, + pipe->ep_address, urb->status); + break; + } + goto cleanup_recv_urb; + } + + if (urb->actual_length == 0) + goto cleanup_recv_urb; + + skb = urb_context->skb; + + /* we are going to pass it up */ + urb_context->skb = NULL; + skb_put(skb, urb->actual_length); + + /* note: queue implements a lock */ + skb_queue_tail(&pipe->io_comp_queue, skb); + schedule_work(&pipe->io_complete_work); + +cleanup_recv_urb: + ath6kl_usb_cleanup_recv_urb(urb_context); + + if (status == 0 && + pipe->urb_cnt >= pipe->urb_cnt_thresh) { + /* our free urbs are piling up, post more transfers */ + ath6kl_usb_post_recv_transfers(pipe, ATH6KL_USB_RX_BUFFER_SIZE); + } +} + +static void ath6kl_usb_usb_transmit_complete(struct urb *urb) +{ + struct ath6kl_urb_context *urb_context = urb->context; + struct ath6kl_usb_pipe *pipe = urb_context->pipe; + struct sk_buff *skb; + + ath6kl_dbg(ATH6KL_DBG_USB_BULK, + "%s: pipe: %d, stat:%d, len:%d\n", + __func__, pipe->logical_pipe_num, urb->status, + urb->actual_length); + + if (urb->status != 0) { + ath6kl_dbg(ATH6KL_DBG_USB_BULK, + "%s: pipe: %d, failed:%d\n", + __func__, pipe->logical_pipe_num, urb->status); + } + + skb = urb_context->skb; + urb_context->skb = NULL; + ath6kl_usb_free_urb_to_pipe(urb_context->pipe, urb_context); + + /* note: queue implements a lock */ + skb_queue_tail(&pipe->io_comp_queue, skb); + schedule_work(&pipe->io_complete_work); +} + +static void ath6kl_usb_io_comp_work(struct work_struct *work) +{ + struct ath6kl_usb_pipe *pipe = container_of(work, + struct ath6kl_usb_pipe, + io_complete_work); + struct ath6kl_usb *ar_usb; + struct sk_buff *skb; + + ar_usb = pipe->ar_usb; + + while ((skb = skb_dequeue(&pipe->io_comp_queue))) { + if (pipe->flags & ATH6KL_USB_PIPE_FLAG_TX) { + ath6kl_dbg(ATH6KL_DBG_USB_BULK, + "ath6kl usb xmit callback buf:0x%p\n", skb); + ath6kl_core_tx_complete(ar_usb->ar, skb); + } else { + ath6kl_dbg(ATH6KL_DBG_USB_BULK, + "ath6kl usb recv callback buf:0x%p\n", skb); + ath6kl_core_rx_complete(ar_usb->ar, skb, + pipe->logical_pipe_num); + } + } +} + #define ATH6KL_USB_MAX_DIAG_CMD (sizeof(struct ath6kl_usb_ctrl_diag_cmd_write)) #define ATH6KL_USB_MAX_DIAG_RESP (sizeof(struct ath6kl_usb_ctrl_diag_resp_read)) static void ath6kl_usb_destroy(struct ath6kl_usb *ar_usb) { + ath6kl_usb_flush_all(ar_usb); + + ath6kl_usb_cleanup_pipe_resources(ar_usb); + usb_set_intfdata(ar_usb->interface, NULL); kfree(ar_usb->diag_cmd_buffer); @@ -70,19 +614,28 @@ static void ath6kl_usb_destroy(struct ath6kl_usb *ar_usb) static struct ath6kl_usb *ath6kl_usb_create(struct usb_interface *interface) { - struct ath6kl_usb *ar_usb = NULL; struct usb_device *dev = interface_to_usbdev(interface); + struct ath6kl_usb *ar_usb; + struct ath6kl_usb_pipe *pipe; int status = 0; + int i; ar_usb = kzalloc(sizeof(struct ath6kl_usb), GFP_KERNEL); if (ar_usb == NULL) goto fail_ath6kl_usb_create; - memset(ar_usb, 0, sizeof(struct ath6kl_usb)); usb_set_intfdata(interface, ar_usb); + spin_lock_init(&(ar_usb->cs_lock)); ar_usb->udev = dev; ar_usb->interface = interface; + for (i = 0; i < ATH6KL_USB_PIPE_MAX; i++) { + pipe = &ar_usb->pipes[i]; + INIT_WORK(&pipe->io_complete_work, + ath6kl_usb_io_comp_work); + skb_queue_head_init(&pipe->io_comp_queue); + } + ar_usb->diag_cmd_buffer = kzalloc(ATH6KL_USB_MAX_DIAG_CMD, GFP_KERNEL); if (ar_usb->diag_cmd_buffer == NULL) { status = -ENOMEM; @@ -96,6 +649,8 @@ static struct ath6kl_usb *ath6kl_usb_create(struct usb_interface *interface) goto fail_ath6kl_usb_create; } + status = ath6kl_usb_setup_pipe_resources(ar_usb); + fail_ath6kl_usb_create: if (status != 0) { ath6kl_usb_destroy(ar_usb); @@ -114,11 +669,177 @@ static void ath6kl_usb_device_detached(struct usb_interface *interface) ath6kl_stop_txrx(ar_usb->ar); + /* Delay to wait for the target to reboot */ + mdelay(20); ath6kl_core_cleanup(ar_usb->ar); - ath6kl_usb_destroy(ar_usb); } +/* exported hif usb APIs for htc pipe */ +static void hif_start(struct ath6kl *ar) +{ + struct ath6kl_usb *device = ath6kl_usb_priv(ar); + int i; + + ath6kl_usb_start_recv_pipes(device); + + /* set the TX resource avail threshold for each TX pipe */ + for (i = ATH6KL_USB_PIPE_TX_CTRL; + i <= ATH6KL_USB_PIPE_TX_DATA_HP; i++) { + device->pipes[i].urb_cnt_thresh = + device->pipes[i].urb_alloc / 2; + } +} + +static int ath6kl_usb_send(struct ath6kl *ar, u8 PipeID, + struct sk_buff *hdr_skb, struct sk_buff *skb) +{ + struct ath6kl_usb *device = ath6kl_usb_priv(ar); + struct ath6kl_usb_pipe *pipe = &device->pipes[PipeID]; + struct ath6kl_urb_context *urb_context; + int usb_status, status = 0; + struct urb *urb; + u8 *data; + u32 len; + + ath6kl_dbg(ATH6KL_DBG_USB_BULK, "+%s pipe : %d, buf:0x%p\n", + __func__, PipeID, skb); + + urb_context = ath6kl_usb_alloc_urb_from_pipe(pipe); + + if (urb_context == NULL) { + /* + * TODO: it is possible to run out of urbs if + * 2 endpoints map to the same pipe ID + */ + ath6kl_dbg(ATH6KL_DBG_USB_BULK, + "%s pipe:%d no urbs left. URB Cnt : %d\n", + __func__, PipeID, pipe->urb_cnt); + status = -ENOMEM; + goto fail_hif_send; + } + + urb_context->skb = skb; + + data = skb->data; + len = skb->len; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (urb == NULL) { + status = -ENOMEM; + ath6kl_usb_free_urb_to_pipe(urb_context->pipe, + urb_context); + goto fail_hif_send; + } + + usb_fill_bulk_urb(urb, + device->udev, + pipe->usb_pipe_handle, + data, + len, + ath6kl_usb_usb_transmit_complete, urb_context); + + if ((len % pipe->max_packet_size) == 0) { + /* hit a max packet boundary on this pipe */ + urb->transfer_flags |= URB_ZERO_PACKET; + } + + ath6kl_dbg(ATH6KL_DBG_USB_BULK, + "athusb bulk send submit:%d, 0x%X (ep:0x%2.2X), %d bytes\n", + pipe->logical_pipe_num, pipe->usb_pipe_handle, + pipe->ep_address, len); + + usb_anchor_urb(urb, &pipe->urb_submitted); + usb_status = usb_submit_urb(urb, GFP_ATOMIC); + + if (usb_status) { + ath6kl_dbg(ATH6KL_DBG_USB_BULK, + "ath6kl usb : usb bulk transmit failed %d\n", + usb_status); + usb_unanchor_urb(urb); + ath6kl_usb_free_urb_to_pipe(urb_context->pipe, + urb_context); + status = -EINVAL; + } + usb_free_urb(urb); + +fail_hif_send: + return status; +} + +static void hif_stop(struct ath6kl *ar) +{ + struct ath6kl_usb *device = ath6kl_usb_priv(ar); + + ath6kl_usb_flush_all(device); +} + +static void ath6kl_usb_get_default_pipe(struct ath6kl *ar, + u8 *ul_pipe, u8 *dl_pipe) +{ + *ul_pipe = ATH6KL_USB_PIPE_TX_CTRL; + *dl_pipe = ATH6KL_USB_PIPE_RX_CTRL; +} + +static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id, + u8 *ul_pipe, u8 *dl_pipe) +{ + int status = 0; + + switch (svc_id) { + case HTC_CTRL_RSVD_SVC: + case WMI_CONTROL_SVC: + *ul_pipe = ATH6KL_USB_PIPE_TX_CTRL; + /* due to large control packets, shift to data pipe */ + *dl_pipe = ATH6KL_USB_PIPE_RX_DATA; + break; + case WMI_DATA_BE_SVC: + case WMI_DATA_BK_SVC: + *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP; + /* + * Disable rxdata2 directly, it will be enabled + * if FW enable rxdata2 + */ + *dl_pipe = ATH6KL_USB_PIPE_RX_DATA; + break; + case WMI_DATA_VI_SVC: + *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP; + /* + * Disable rxdata2 directly, it will be enabled + * if FW enable rxdata2 + */ + *dl_pipe = ATH6KL_USB_PIPE_RX_DATA; + break; + case WMI_DATA_VO_SVC: + *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_HP; + /* + * Disable rxdata2 directly, it will be enabled + * if FW enable rxdata2 + */ + *dl_pipe = ATH6KL_USB_PIPE_RX_DATA; + break; + default: + status = -EPERM; + break; + } + + return status; +} + +static u16 ath6kl_usb_get_free_queue_number(struct ath6kl *ar, u8 pipe_id) +{ + struct ath6kl_usb *device = ath6kl_usb_priv(ar); + + return device->pipes[pipe_id].urb_cnt; +} + +static void hif_detach_htc(struct ath6kl *ar) +{ + struct ath6kl_usb *device = ath6kl_usb_priv(ar); + + ath6kl_usb_flush_all(device); +} + static int ath6kl_usb_submit_ctrl_out(struct ath6kl_usb *ar_usb, u8 req, u16 value, u16 index, void *data, u32 size) @@ -301,14 +1022,21 @@ static int ath6kl_usb_bmi_write(struct ath6kl *ar, u8 *buf, u32 len) static int ath6kl_usb_power_on(struct ath6kl *ar) { + hif_start(ar); return 0; } static int ath6kl_usb_power_off(struct ath6kl *ar) { + hif_detach_htc(ar); return 0; } +static void ath6kl_usb_stop(struct ath6kl *ar) +{ + hif_stop(ar); +} + static const struct ath6kl_hif_ops ath6kl_usb_ops = { .diag_read32 = ath6kl_usb_diag_read32, .diag_write32 = ath6kl_usb_diag_write32, @@ -316,6 +1044,11 @@ static const struct ath6kl_hif_ops ath6kl_usb_ops = { .bmi_write = ath6kl_usb_bmi_write, .power_on = ath6kl_usb_power_on, .power_off = ath6kl_usb_power_off, + .stop = ath6kl_usb_stop, + .pipe_send = ath6kl_usb_send, + .pipe_get_default = ath6kl_usb_get_default_pipe, + .pipe_map_service = ath6kl_usb_map_service_pipe, + .pipe_get_free_queue_number = ath6kl_usb_get_free_queue_number, }; /* ath6kl usb driver registered functions */ @@ -368,7 +1101,7 @@ static int ath6kl_usb_probe(struct usb_interface *interface, ar_usb->ar = ar; - ret = ath6kl_core_init(ar); + ret = ath6kl_core_init(ar, ATH6KL_HTC_TYPE_PIPE); if (ret) { ath6kl_err("Failed to init ath6kl core: %d\n", ret); goto err_core_free; @@ -392,6 +1125,46 @@ static void ath6kl_usb_remove(struct usb_interface *interface) ath6kl_usb_device_detached(interface); } +#ifdef CONFIG_PM + +static int ath6kl_usb_suspend(struct usb_interface *interface, + pm_message_t message) +{ + struct ath6kl_usb *device; + device = usb_get_intfdata(interface); + + ath6kl_usb_flush_all(device); + return 0; +} + +static int ath6kl_usb_resume(struct usb_interface *interface) +{ + struct ath6kl_usb *device; + device = usb_get_intfdata(interface); + + ath6kl_usb_post_recv_transfers(&device->pipes[ATH6KL_USB_PIPE_RX_DATA], + ATH6KL_USB_RX_BUFFER_SIZE); + ath6kl_usb_post_recv_transfers(&device->pipes[ATH6KL_USB_PIPE_RX_DATA2], + ATH6KL_USB_RX_BUFFER_SIZE); + + return 0; +} + +static int ath6kl_usb_reset_resume(struct usb_interface *intf) +{ + if (usb_get_intfdata(intf)) + ath6kl_usb_remove(intf); + return 0; +} + +#else + +#define ath6kl_usb_suspend NULL +#define ath6kl_usb_resume NULL +#define ath6kl_usb_reset_resume NULL + +#endif + /* table of devices that work with this driver */ static struct usb_device_id ath6kl_usb_ids[] = { {USB_DEVICE(0x0cf3, 0x9374)}, @@ -403,8 +1176,13 @@ MODULE_DEVICE_TABLE(usb, ath6kl_usb_ids); static struct usb_driver ath6kl_usb_driver = { .name = "ath6kl_usb", .probe = ath6kl_usb_probe, + .suspend = ath6kl_usb_suspend, + .resume = ath6kl_usb_resume, + .reset_resume = ath6kl_usb_reset_resume, .disconnect = ath6kl_usb_remove, .id_table = ath6kl_usb_ids, + .supports_autosuspend = true, + .disable_hub_initiated_lpm = 1, }; static int ath6kl_usb_init(void) diff --git a/trunk/drivers/net/wireless/ath/ath6kl/wmi.c b/trunk/drivers/net/wireless/ath/ath6kl/wmi.c index 2b442332cd0f..7c8a9977faf5 100644 --- a/trunk/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/trunk/drivers/net/wireless/ath/ath6kl/wmi.c @@ -2882,6 +2882,43 @@ int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 if_idx, return ret; } +int ath6kl_wmi_set_htcap_cmd(struct wmi *wmi, u8 if_idx, + enum ieee80211_band band, + struct ath6kl_htcap *htcap) +{ + struct sk_buff *skb; + struct wmi_set_htcap_cmd *cmd; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_set_htcap_cmd *) skb->data; + + /* + * NOTE: Band in firmware matches enum ieee80211_band, it is unlikely + * this will be changed in firmware. If at all there is any change in + * band value, the host needs to be fixed. + */ + cmd->band = band; + cmd->ht_enable = !!htcap->ht_enable; + cmd->ht20_sgi = !!(htcap->cap_info & IEEE80211_HT_CAP_SGI_20); + cmd->ht40_supported = + !!(htcap->cap_info & IEEE80211_HT_CAP_SUP_WIDTH_20_40); + cmd->ht40_sgi = !!(htcap->cap_info & IEEE80211_HT_CAP_SGI_40); + cmd->intolerant_40mhz = + !!(htcap->cap_info & IEEE80211_HT_CAP_40MHZ_INTOLERANT); + cmd->max_ampdu_len_exp = htcap->ampdu_factor; + + ath6kl_dbg(ATH6KL_DBG_WMI, + "Set htcap: band:%d ht_enable:%d 40mhz:%d sgi_20mhz:%d sgi_40mhz:%d 40mhz_intolerant:%d ampdu_len_exp:%d\n", + cmd->band, cmd->ht_enable, cmd->ht40_supported, + cmd->ht20_sgi, cmd->ht40_sgi, cmd->intolerant_40mhz, + cmd->max_ampdu_len_exp); + return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_HT_CAP_CMDID, + NO_SYNC_WMIFLAG); +} + int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len) { struct sk_buff *skb; @@ -3032,6 +3069,9 @@ int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 if_idx, u8 cmd, const u8 *mac, cm->reason = cpu_to_le16(reason); cm->cmd = cmd; + ath6kl_dbg(ATH6KL_DBG_WMI, "ap_set_mlme: cmd=%d reason=%d\n", cm->cmd, + cm->reason); + return ath6kl_wmi_cmd_send(wmip, if_idx, skb, WMI_AP_SET_MLME_CMDID, NO_SYNC_WMIFLAG); } @@ -3181,6 +3221,29 @@ int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type, NO_SYNC_WMIFLAG); } +int ath6kl_wmi_set_ie_cmd(struct wmi *wmi, u8 if_idx, u8 ie_id, u8 ie_field, + const u8 *ie_info, u8 ie_len) +{ + struct sk_buff *skb; + struct wmi_set_ie_cmd *p; + + skb = ath6kl_wmi_get_new_buf(sizeof(*p) + ie_len); + if (!skb) + return -ENOMEM; + + ath6kl_dbg(ATH6KL_DBG_WMI, "set_ie_cmd: ie_id=%u ie_ie_field=%u ie_len=%u\n", + ie_id, ie_field, ie_len); + p = (struct wmi_set_ie_cmd *) skb->data; + p->ie_id = ie_id; + p->ie_field = ie_field; + p->ie_len = ie_len; + if (ie_info && ie_len > 0) + memcpy(p->ie_info, ie_info, ie_len); + + return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_IE_CMDID, + NO_SYNC_WMIFLAG); +} + int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable) { struct sk_buff *skb; @@ -3392,6 +3455,23 @@ int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx) WMI_CANCEL_REMAIN_ON_CHNL_CMDID); } +int ath6kl_wmi_set_inact_period(struct wmi *wmi, u8 if_idx, int inact_timeout) +{ + struct sk_buff *skb; + struct wmi_set_inact_period_cmd *cmd; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_set_inact_period_cmd *) skb->data; + cmd->inact_period = cpu_to_le32(inact_timeout); + cmd->num_null_func = 0; + + return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_CONN_INACT_CMDID, + NO_SYNC_WMIFLAG); +} + static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb) { struct wmix_cmd_hdr *cmd; diff --git a/trunk/drivers/net/wireless/ath/ath6kl/wmi.h b/trunk/drivers/net/wireless/ath/ath6kl/wmi.h index 4092e3e80790..d3d2ab5c1689 100644 --- a/trunk/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/trunk/drivers/net/wireless/ath/ath6kl/wmi.h @@ -182,6 +182,9 @@ enum wmi_data_hdr_flags { #define WMI_DATA_HDR_META_MASK 0x7 #define WMI_DATA_HDR_META_SHIFT 13 +#define WMI_DATA_HDR_PAD_BEFORE_DATA_MASK 0xFF +#define WMI_DATA_HDR_PAD_BEFORE_DATA_SHIFT 0x8 + /* Macros for operating on WMI_DATA_HDR (info3) field */ #define WMI_DATA_HDR_IF_IDX_MASK 0xF @@ -423,6 +426,7 @@ enum wmi_cmd_id { WMI_SET_FRAMERATES_CMDID, WMI_SET_AP_PS_CMDID, WMI_SET_QOS_SUPP_CMDID, + WMI_SET_IE_CMDID, /* WMI_THIN_RESERVED_... mark the start and end * values for WMI_THIN_RESERVED command IDs. These @@ -629,6 +633,11 @@ enum wmi_mgmt_frame_type { WMI_NUM_MGMT_FRAME }; +enum wmi_ie_field_type { + WMI_RSN_IE_CAPB = 0x1, + WMI_IE_FULL = 0xFF, /* indicats full IE */ +}; + /* WMI_CONNECT_CMDID */ enum network_type { INFRA_NETWORK = 0x01, @@ -1268,6 +1277,16 @@ struct wmi_mcast_filter_add_del_cmd { u8 mcast_mac[ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE]; } __packed; +struct wmi_set_htcap_cmd { + u8 band; + u8 ht_enable; + u8 ht40_supported; + u8 ht20_sgi; + u8 ht40_sgi; + u8 intolerant_40mhz; + u8 max_ampdu_len_exp; +} __packed; + /* Command Replies */ /* WMI_GET_CHANNEL_LIST_CMDID reply */ @@ -1913,6 +1932,14 @@ struct wmi_set_appie_cmd { u8 ie_info[0]; } __packed; +struct wmi_set_ie_cmd { + u8 ie_id; + u8 ie_field; /* enum wmi_ie_field_type */ + u8 ie_len; + u8 reserved; + u8 ie_info[0]; +} __packed; + /* Notify the WSC registration status to the target */ #define WSC_REG_ACTIVE 1 #define WSC_REG_INACTIVE 0 @@ -2141,6 +2168,11 @@ struct wmi_ap_hidden_ssid_cmd { u8 hidden_ssid; } __packed; +struct wmi_set_inact_period_cmd { + __le32 inact_period; + u8 num_null_func; +} __packed; + /* AP mode events */ struct wmi_ap_set_apsd_cmd { u8 enable; @@ -2465,6 +2497,9 @@ int ath6kl_wmi_get_roam_tbl_cmd(struct wmi *wmi); int ath6kl_wmi_set_wmm_txop(struct wmi *wmi, u8 if_idx, enum wmi_txop_cfg cfg); int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 if_idx, u8 keep_alive_intvl); +int ath6kl_wmi_set_htcap_cmd(struct wmi *wmi, u8 if_idx, + enum ieee80211_band band, + struct ath6kl_htcap *htcap); int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len); s32 ath6kl_wmi_get_rate(s8 rate_index); @@ -2515,6 +2550,9 @@ int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 if_idx, int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type, const u8 *ie, u8 ie_len); +int ath6kl_wmi_set_ie_cmd(struct wmi *wmi, u8 if_idx, u8 ie_id, u8 ie_field, + const u8 *ie_info, u8 ie_len); + /* P2P */ int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable); @@ -2538,6 +2576,8 @@ int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx); int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type, const u8 *ie, u8 ie_len); +int ath6kl_wmi_set_inact_period(struct wmi *wmi, u8 if_idx, int inact_timeout); + void ath6kl_wmi_sscan_timer(unsigned long ptr); struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx); diff --git a/trunk/drivers/net/wireless/ath/ath9k/Makefile b/trunk/drivers/net/wireless/ath/ath9k/Makefile index 27d95fe5ade0..3f0b84723789 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/Makefile +++ b/trunk/drivers/net/wireless/ath/ath9k/Makefile @@ -11,7 +11,10 @@ ath9k-$(CONFIG_ATH9K_PCI) += pci.o ath9k-$(CONFIG_ATH9K_AHB) += ahb.o ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o -ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += dfs.o +ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += \ + dfs.o \ + dfs_pattern_detector.o \ + dfs_pri_detector.o obj-$(CONFIG_ATH9K) += ath9k.o diff --git a/trunk/drivers/net/wireless/ath/ath9k/ani.c b/trunk/drivers/net/wireless/ath/ath9k/ani.c index 7e0ea4e98334..b4c77f9d7470 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/ani.c +++ b/trunk/drivers/net/wireless/ath/ath9k/ani.c @@ -46,8 +46,8 @@ static const struct ani_ofdm_level_entry ofdm_level_table[] = { { 5, 4, 1 }, /* lvl 5 */ { 6, 5, 1 }, /* lvl 6 */ { 7, 6, 1 }, /* lvl 7 */ - { 7, 7, 1 }, /* lvl 8 */ - { 7, 8, 0 } /* lvl 9 */ + { 7, 6, 0 }, /* lvl 8 */ + { 7, 7, 0 } /* lvl 9 */ }; #define ATH9K_ANI_OFDM_NUM_LEVEL \ ARRAY_SIZE(ofdm_level_table) @@ -91,8 +91,8 @@ static const struct ani_cck_level_entry cck_level_table[] = { { 4, 0 }, /* lvl 4 */ { 5, 0 }, /* lvl 5 */ { 6, 0 }, /* lvl 6 */ - { 7, 0 }, /* lvl 7 (only for high rssi) */ - { 8, 0 } /* lvl 8 (only for high rssi) */ + { 6, 0 }, /* lvl 7 (only for high rssi) */ + { 7, 0 } /* lvl 8 (only for high rssi) */ }; #define ATH9K_ANI_CCK_NUM_LEVEL \ @@ -274,7 +274,9 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel) aniState->rssiThrLow, aniState->rssiThrHigh); if (aniState->update_ani) - aniState->ofdmNoiseImmunityLevel = immunityLevel; + aniState->ofdmNoiseImmunityLevel = + (immunityLevel > ATH9K_ANI_OFDM_DEF_LEVEL) ? + immunityLevel : ATH9K_ANI_OFDM_DEF_LEVEL; entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel]; entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel]; @@ -290,16 +292,9 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel) ATH9K_ANI_FIRSTEP_LEVEL, entry_ofdm->fir_step_level); - if ((ah->opmode != NL80211_IFTYPE_STATION && - ah->opmode != NL80211_IFTYPE_ADHOC) || - aniState->noiseFloor <= aniState->rssiThrHigh) { - if (aniState->ofdmWeakSigDetectOff) - /* force on ofdm weak sig detect */ - ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - true); - else if (aniState->ofdmWeakSigDetectOff == - entry_ofdm->ofdm_weak_signal_on) + if ((aniState->noiseFloor >= aniState->rssiThrHigh) && + (!aniState->ofdmWeakSigDetectOff != + entry_ofdm->ofdm_weak_signal_on)) { ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, entry_ofdm->ofdm_weak_signal_on); @@ -347,7 +342,9 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel) immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI; if (aniState->update_ani) - aniState->cckNoiseImmunityLevel = immunityLevel; + aniState->cckNoiseImmunityLevel = + (immunityLevel > ATH9K_ANI_CCK_DEF_LEVEL) ? + immunityLevel : ATH9K_ANI_CCK_DEF_LEVEL; entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel]; entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel]; @@ -717,26 +714,30 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan) ofdmPhyErrRate, aniState->cckNoiseImmunityLevel, cckPhyErrRate, aniState->ofdmsTurn); - if (aniState->listenTime > 5 * ah->aniperiod) { - if (ofdmPhyErrRate <= ah->config.ofdm_trig_low && - cckPhyErrRate <= ah->config.cck_trig_low) { + if (aniState->listenTime > ah->aniperiod) { + if (cckPhyErrRate < ah->config.cck_trig_low && + ((ofdmPhyErrRate < ah->config.ofdm_trig_low && + aniState->ofdmNoiseImmunityLevel < + ATH9K_ANI_OFDM_DEF_LEVEL) || + (ofdmPhyErrRate < ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI && + aniState->ofdmNoiseImmunityLevel >= + ATH9K_ANI_OFDM_DEF_LEVEL))) { ath9k_hw_ani_lower_immunity(ah); aniState->ofdmsTurn = !aniState->ofdmsTurn; - } - ath9k_ani_restart(ah); - } else if (aniState->listenTime > ah->aniperiod) { - /* check to see if need to raise immunity */ - if (ofdmPhyErrRate > ah->config.ofdm_trig_high && - (cckPhyErrRate <= ah->config.cck_trig_high || - aniState->ofdmsTurn)) { + } else if ((ofdmPhyErrRate > ah->config.ofdm_trig_high && + aniState->ofdmNoiseImmunityLevel >= + ATH9K_ANI_OFDM_DEF_LEVEL) || + (ofdmPhyErrRate > + ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI && + aniState->ofdmNoiseImmunityLevel < + ATH9K_ANI_OFDM_DEF_LEVEL)) { ath9k_hw_ani_ofdm_err_trigger(ah); - ath9k_ani_restart(ah); aniState->ofdmsTurn = false; } else if (cckPhyErrRate > ah->config.cck_trig_high) { ath9k_hw_ani_cck_err_trigger(ah); - ath9k_ani_restart(ah); aniState->ofdmsTurn = true; } + ath9k_ani_restart(ah); } } EXPORT_SYMBOL(ath9k_hw_ani_monitor); diff --git a/trunk/drivers/net/wireless/ath/ath9k/ani.h b/trunk/drivers/net/wireless/ath/ath9k/ani.h index 83029d6c7b22..72e2b874e179 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/ani.h +++ b/trunk/drivers/net/wireless/ath/ath9k/ani.h @@ -25,11 +25,13 @@ /* units are errors per second */ #define ATH9K_ANI_OFDM_TRIG_HIGH_OLD 500 -#define ATH9K_ANI_OFDM_TRIG_HIGH_NEW 1000 +#define ATH9K_ANI_OFDM_TRIG_HIGH_NEW 3500 +#define ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI 1000 /* units are errors per second */ #define ATH9K_ANI_OFDM_TRIG_LOW_OLD 200 #define ATH9K_ANI_OFDM_TRIG_LOW_NEW 400 +#define ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI 900 /* units are errors per second */ #define ATH9K_ANI_CCK_TRIG_HIGH_OLD 200 @@ -53,7 +55,7 @@ #define ATH9K_ANI_RSSI_THR_LOW 7 #define ATH9K_ANI_PERIOD_OLD 100 -#define ATH9K_ANI_PERIOD_NEW 1000 +#define ATH9K_ANI_PERIOD_NEW 300 /* in ms */ #define ATH9K_ANI_POLLINTERVAL_OLD 100 diff --git a/trunk/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/trunk/drivers/net/wireless/ath/ath9k/ar5008_phy.c index aba088005b22..c7492c6a2519 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/trunk/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -245,7 +245,6 @@ static int ar5008_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) REG_WRITE(ah, AR_PHY(0x37), reg32); ah->curchan = chan; - ah->curchan_rad_index = -1; return 0; } @@ -619,19 +618,10 @@ static void ar5008_hw_init_bb(struct ath_hw *ah, u32 synthDelay; synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; - if (IS_CHAN_B(chan)) - synthDelay = (4 * synthDelay) / 22; - else - synthDelay /= 10; - - if (IS_CHAN_HALF_RATE(chan)) - synthDelay *= 2; - else if (IS_CHAN_QUARTER_RATE(chan)) - synthDelay *= 4; REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); - udelay(synthDelay + BASE_ACTIVATE_DELAY); + ath9k_hw_synth_delay(ah, chan, synthDelay); } static void ar5008_hw_init_chain_masks(struct ath_hw *ah) @@ -949,12 +939,8 @@ static bool ar5008_hw_rfbus_req(struct ath_hw *ah) static void ar5008_hw_rfbus_done(struct ath_hw *ah) { u32 synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; - if (IS_CHAN_B(ah->curchan)) - synthDelay = (4 * synthDelay) / 22; - else - synthDelay /= 10; - udelay(synthDelay + BASE_ACTIVATE_DELAY); + ath9k_hw_synth_delay(ah, ah->curchan, synthDelay); REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0); } @@ -1047,46 +1033,8 @@ static bool ar5008_hw_ani_control_old(struct ath_hw *ah, break; } case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{ - static const int m1ThreshLow[] = { 127, 50 }; - static const int m2ThreshLow[] = { 127, 40 }; - static const int m1Thresh[] = { 127, 0x4d }; - static const int m2Thresh[] = { 127, 0x40 }; - static const int m2CountThr[] = { 31, 16 }; - static const int m2CountThrLow[] = { 63, 48 }; u32 on = param ? 1 : 0; - REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_M1_THRESH_LOW, - m1ThreshLow[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_M2_THRESH_LOW, - m2ThreshLow[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR, - AR_PHY_SFCORR_M1_THRESH, - m1Thresh[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR, - AR_PHY_SFCORR_M2_THRESH, - m2Thresh[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR, - AR_PHY_SFCORR_M2COUNT_THR, - m2CountThr[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, - m2CountThrLow[on]); - - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M1_THRESH_LOW, - m1ThreshLow[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M2_THRESH_LOW, - m2ThreshLow[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M1_THRESH, - m1Thresh[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M2_THRESH, - m2Thresh[on]); - if (on) REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); diff --git a/trunk/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/trunk/drivers/net/wireless/ath/ath9k/ar9002_mac.c index aa2abaf31cba..8d78253c26ce 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/trunk/drivers/net/wireless/ath/ath9k/ar9002_mac.c @@ -136,6 +136,7 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) } if (sync_cause) { + ath9k_debug_sync_cause(common, sync_cause); fatal_int = (sync_cause & (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR)) diff --git a/trunk/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/trunk/drivers/net/wireless/ath/ath9k/ar9002_phy.c index 3cbbb033fcea..846dd7974eb8 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/ar9002_phy.c +++ b/trunk/drivers/net/wireless/ath/ath9k/ar9002_phy.c @@ -152,7 +152,6 @@ static int ar9002_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32); ah->curchan = chan; - ah->curchan_rad_index = -1; return 0; } diff --git a/trunk/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/trunk/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h index 46c79a3d4737..952cb2b4656b 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/trunk/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -777,11 +777,11 @@ static const u32 ar9300Common_rx_gain_table_2p2[][2] = { {0x0000a074, 0x00000000}, {0x0000a078, 0x00000000}, {0x0000a07c, 0x00000000}, - {0x0000a080, 0x22222229}, - {0x0000a084, 0x1d1d1d1d}, - {0x0000a088, 0x1d1d1d1d}, - {0x0000a08c, 0x1d1d1d1d}, - {0x0000a090, 0x171d1d1d}, + {0x0000a080, 0x1a1a1a1a}, + {0x0000a084, 0x1a1a1a1a}, + {0x0000a088, 0x1a1a1a1a}, + {0x0000a08c, 0x1a1a1a1a}, + {0x0000a090, 0x171a1a1a}, {0x0000a094, 0x11111717}, {0x0000a098, 0x00030311}, {0x0000a09c, 0x00000000}, diff --git a/trunk/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/trunk/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 63089cc1fafd..a0387a027db0 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/trunk/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -1000,10 +1000,12 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, if (mci && IS_CHAN_2GHZ(chan) && run_agc_cal) ar9003_mci_init_cal_req(ah, &is_reusable); - txiqcal_done = ar9003_hw_tx_iq_cal_run(ah); - REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); - udelay(5); - REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + if (!(IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))) { + txiqcal_done = ar9003_hw_tx_iq_cal_run(ah); + REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); + udelay(5); + REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + } skip_tx_iqcal: if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) { diff --git a/trunk/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/trunk/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 6bb4db052bb0..ac53d901801d 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/trunk/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -30,11 +30,6 @@ #define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE) #define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE) #define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE) -#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ -#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 9 /* 10*log10(3)*2 */ -#define PWRINCR_3_TO_1_CHAIN 9 /* 10*log(3)*2 */ -#define PWRINCR_3_TO_2_CHAIN 3 /* floor(10*log(3/2)*2) */ -#define PWRINCR_2_TO_1_CHAIN 6 /* 10*log(2)*2 */ #define SUB_NUM_CTL_MODES_AT_5G_40 2 /* excluding HT40, EXT-OFDM */ #define SUB_NUM_CTL_MODES_AT_2G_40 3 /* excluding HT40, EXT-OFDM, EXT-CCK */ @@ -2936,15 +2931,6 @@ static const struct ar9300_eeprom *ar9003_eeprom_struct_find_by_id(int id) #undef N_LOOP } - -static u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz) -{ - if (fbin == AR5416_BCHAN_UNUSED) - return fbin; - - return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); -} - static int ath9k_hw_ar9300_check_eeprom(struct ath_hw *ah) { return 0; @@ -4070,7 +4056,7 @@ static u8 ar9003_hw_eeprom_get_tgt_pwr(struct ath_hw *ah, * targetpower piers stored on eeprom */ for (i = 0; i < numPiers; i++) { - freqArray[i] = FBIN2FREQ(pFreqBin[i], is2GHz); + freqArray[i] = ath9k_hw_fbin2freq(pFreqBin[i], is2GHz); targetPowerArray[i] = pEepromTargetPwr[i].tPow2x[rateIndex]; } @@ -4106,7 +4092,7 @@ static u8 ar9003_hw_eeprom_get_ht20_tgt_pwr(struct ath_hw *ah, * from targetpower piers stored on eeprom */ for (i = 0; i < numPiers; i++) { - freqArray[i] = FBIN2FREQ(pFreqBin[i], is2GHz); + freqArray[i] = ath9k_hw_fbin2freq(pFreqBin[i], is2GHz); targetPowerArray[i] = pEepromTargetPwr[i].tPow2x[rateIndex]; } @@ -4142,7 +4128,7 @@ static u8 ar9003_hw_eeprom_get_ht40_tgt_pwr(struct ath_hw *ah, * targetpower piers stored on eeprom */ for (i = 0; i < numPiers; i++) { - freqArray[i] = FBIN2FREQ(pFreqBin[i], is2GHz); + freqArray[i] = ath9k_hw_fbin2freq(pFreqBin[i], is2GHz); targetPowerArray[i] = pEepromTargetPwr[i].tPow2x[rateIndex]; } @@ -4167,7 +4153,7 @@ static u8 ar9003_hw_eeprom_get_cck_tgt_pwr(struct ath_hw *ah, * targetpower piers stored on eeprom */ for (i = 0; i < numPiers; i++) { - freqArray[i] = FBIN2FREQ(pFreqBin[i], 1); + freqArray[i] = ath9k_hw_fbin2freq(pFreqBin[i], 1); targetPowerArray[i] = pEepromTargetPwr[i].tPow2x[rateIndex]; } @@ -4295,18 +4281,10 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) #undef POW_SM } -static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq, - u8 *targetPowerValT2) +static void ar9003_hw_get_legacy_target_powers(struct ath_hw *ah, u16 freq, + u8 *targetPowerValT2, + bool is2GHz) { - /* XXX: hard code for now, need to get from eeprom struct */ - u8 ht40PowerIncForPdadc = 0; - bool is2GHz = false; - unsigned int i = 0; - struct ath_common *common = ath9k_hw_common(ah); - - if (freq < 4000) - is2GHz = true; - targetPowerValT2[ALL_TARGET_LEGACY_6_24] = ar9003_hw_eeprom_get_tgt_pwr(ah, LEGACY_TARGET_RATE_6_24, freq, is2GHz); @@ -4319,6 +4297,11 @@ static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq, targetPowerValT2[ALL_TARGET_LEGACY_54] = ar9003_hw_eeprom_get_tgt_pwr(ah, LEGACY_TARGET_RATE_54, freq, is2GHz); +} + +static void ar9003_hw_get_cck_target_powers(struct ath_hw *ah, u16 freq, + u8 *targetPowerValT2) +{ targetPowerValT2[ALL_TARGET_LEGACY_1L_5L] = ar9003_hw_eeprom_get_cck_tgt_pwr(ah, LEGACY_TARGET_RATE_1L_5L, freq); @@ -4328,6 +4311,11 @@ static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq, ar9003_hw_eeprom_get_cck_tgt_pwr(ah, LEGACY_TARGET_RATE_11L, freq); targetPowerValT2[ALL_TARGET_LEGACY_11S] = ar9003_hw_eeprom_get_cck_tgt_pwr(ah, LEGACY_TARGET_RATE_11S, freq); +} + +static void ar9003_hw_get_ht20_target_powers(struct ath_hw *ah, u16 freq, + u8 *targetPowerValT2, bool is2GHz) +{ targetPowerValT2[ALL_TARGET_HT20_0_8_16] = ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_0_8_16, freq, is2GHz); @@ -4370,6 +4358,16 @@ static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq, targetPowerValT2[ALL_TARGET_HT20_23] = ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_23, freq, is2GHz); +} + +static void ar9003_hw_get_ht40_target_powers(struct ath_hw *ah, + u16 freq, + u8 *targetPowerValT2, + bool is2GHz) +{ + /* XXX: hard code for now, need to get from eeprom struct */ + u8 ht40PowerIncForPdadc = 0; + targetPowerValT2[ALL_TARGET_HT40_0_8_16] = ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_0_8_16, freq, is2GHz) + ht40PowerIncForPdadc; @@ -4413,6 +4411,26 @@ static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq, targetPowerValT2[ALL_TARGET_HT40_23] = ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_23, freq, is2GHz) + ht40PowerIncForPdadc; +} + +static void ar9003_hw_get_target_power_eeprom(struct ath_hw *ah, + struct ath9k_channel *chan, + u8 *targetPowerValT2) +{ + bool is2GHz = IS_CHAN_2GHZ(chan); + unsigned int i = 0; + struct ath_common *common = ath9k_hw_common(ah); + u16 freq = chan->channel; + + if (is2GHz) + ar9003_hw_get_cck_target_powers(ah, freq, targetPowerValT2); + + ar9003_hw_get_legacy_target_powers(ah, freq, targetPowerValT2, is2GHz); + ar9003_hw_get_ht20_target_powers(ah, freq, targetPowerValT2, is2GHz); + + if (IS_CHAN_HT40(chan)) + ar9003_hw_get_ht40_target_powers(ah, freq, targetPowerValT2, + is2GHz); for (i = 0; i < ar9300RateSize; i++) { ath_dbg(common, EEPROM, "TPC[%02d] 0x%08x\n", @@ -4464,7 +4482,7 @@ static int ar9003_hw_cal_pier_get(struct ath_hw *ah, is2GHz = 1; } - *pfrequency = FBIN2FREQ(*pCalPier, is2GHz); + *pfrequency = ath9k_hw_fbin2freq(*pCalPier, is2GHz); *pcorrection = pCalPierStruct->refPower; *ptemperature = pCalPierStruct->tempMeas; *pvoltage = pCalPierStruct->voltMeas; @@ -4789,34 +4807,9 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah, bool is2ghz = IS_CHAN_2GHZ(chan); ath9k_hw_get_channel_centers(ah, chan, ¢ers); - scaledPower = powerLimit - antenna_reduction; - - /* - * Reduce scaled Power by number of chains active to get - * to per chain tx power level - */ - switch (ar5416_get_ntxchains(ah->txchainmask)) { - case 1: - break; - case 2: - if (scaledPower > REDUCE_SCALED_POWER_BY_TWO_CHAIN) - scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; - else - scaledPower = 0; - break; - case 3: - if (scaledPower > REDUCE_SCALED_POWER_BY_THREE_CHAIN) - scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; - else - scaledPower = 0; - break; - } + scaledPower = ath9k_hw_get_scaled_power(ah, powerLimit, + antenna_reduction); - scaledPower = max((u16)0, scaledPower); - - /* - * Get target powers from EEPROM - our baseline for TX Power - */ if (is2ghz) { /* Setup for CTL modes */ /* CTL_11B, CTL_11G, CTL_2GHT20 */ @@ -4988,7 +4981,12 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, unsigned int i = 0, paprd_scale_factor = 0; u8 pwr_idx, min_pwridx = 0; - ar9003_hw_set_target_power_eeprom(ah, chan->channel, targetPowerValT2); + memset(targetPowerValT2, 0 , sizeof(targetPowerValT2)); + + /* + * Get target powers from EEPROM - our baseline for TX Power + */ + ar9003_hw_get_target_power_eeprom(ah, chan, targetPowerValT2); if (ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) { if (IS_CHAN_2GHZ(chan)) @@ -5060,8 +5058,6 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, i, targetPowerValT2[i]); } - ah->txpower_limit = regulatory->max_power_level; - /* Write target power array to registers */ ar9003_hw_tx_power_regwrite(ah, targetPowerValT2); ar9003_hw_calibration_apply(ah, chan->channel); diff --git a/trunk/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/trunk/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h index bb223fe82816..2505ac44f0c1 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h +++ b/trunk/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h @@ -42,7 +42,6 @@ #define AR9300_EEPMISC_WOW 0x02 #define AR9300_CUSTOMER_DATA_SIZE 20 -#define FBIN2FREQ(x, y) ((y) ? (2300 + x) : (4800 + 5 * x)) #define AR9300_MAX_CHAINS 3 #define AR9300_ANT_16S 25 #define AR9300_FUTURE_MODAL_SZ 6 diff --git a/trunk/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/trunk/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 0f56e322dd3b..a0e3394b10dc 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/trunk/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -305,11 +305,6 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ar9462_common_rx_gain_table_2p0, ARRAY_SIZE(ar9462_common_rx_gain_table_2p0), 2); - INIT_INI_ARRAY(&ah->ini_BTCOEX_MAX_TXPWR, - ar9462_2p0_BTCOEX_MAX_TXPWR_table, - ARRAY_SIZE(ar9462_2p0_BTCOEX_MAX_TXPWR_table), - 2); - /* Awake -> Sleep Setting */ INIT_INI_ARRAY(&ah->iniPcieSerdes, PCIE_PLL_ON_CREQ_DIS_L1_2P0, diff --git a/trunk/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/trunk/drivers/net/wireless/ath/ath9k/ar9003_mac.c index a66a13b76848..d9e0824af093 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/trunk/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -306,6 +306,8 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) ar9003_mci_get_isr(ah, masked); if (sync_cause) { + ath9k_debug_sync_cause(common, sync_cause); + if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { REG_WRITE(ah, AR_RC, AR_RC_HOSTIF); REG_WRITE(ah, AR_RC, 0); diff --git a/trunk/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/trunk/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 600aca9fe6b1..11abb972be1f 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/trunk/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -152,7 +152,6 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) REG_WRITE(ah, AR_PHY_65NM_CH0_SYNTH7, reg32); ah->curchan = chan; - ah->curchan_rad_index = -1; return 0; } @@ -209,11 +208,12 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah, continue; negative = 0; if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah)) - cur_bb_spur = FBIN2FREQ(spur_fbin_ptr[i], - IS_CHAN_2GHZ(chan)) - synth_freq; + cur_bb_spur = ath9k_hw_fbin2freq(spur_fbin_ptr[i], + IS_CHAN_2GHZ(chan)); else - cur_bb_spur = spur_freq[i] - synth_freq; + cur_bb_spur = spur_freq[i]; + cur_bb_spur -= synth_freq; if (cur_bb_spur < 0) { negative = 1; cur_bb_spur = -cur_bb_spur; @@ -443,7 +443,8 @@ static void ar9003_hw_spur_mitigate_ofdm(struct ath_hw *ah, ar9003_hw_spur_ofdm_clear(ah); for (i = 0; i < AR_EEPROM_MODAL_SPURS && spurChansPtr[i]; i++) { - freq_offset = FBIN2FREQ(spurChansPtr[i], mode) - synth_freq; + freq_offset = ath9k_hw_fbin2freq(spurChansPtr[i], mode); + freq_offset -= synth_freq; if (abs(freq_offset) < range) { ar9003_hw_spur_ofdm_work(ah, chan, freq_offset); break; @@ -525,22 +526,10 @@ static void ar9003_hw_init_bb(struct ath_hw *ah, * Value is in 100ns increments. */ synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; - if (IS_CHAN_B(chan)) - synthDelay = (4 * synthDelay) / 22; - else - synthDelay /= 10; /* Activate the PHY (includes baseband activate + synthesizer on) */ REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); - - /* - * There is an issue if the AP starts the calibration before - * the base band timeout completes. This could result in the - * rx_clear false triggering. As a workaround we add delay an - * extra BASE_ACTIVATE_DELAY usecs to ensure this condition - * does not happen. - */ - udelay(synthDelay + BASE_ACTIVATE_DELAY); + ath9k_hw_synth_delay(ah, chan, synthDelay); } static void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx) @@ -684,9 +673,6 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, REG_WRITE_ARRAY(&ah->iniAdditional, 1, regWrites); - if (AR_SREV_9462(ah)) - ar9003_hw_prog_ini(ah, &ah->ini_BTCOEX_MAX_TXPWR, 1); - if (chan->channel == 2484) ar9003_hw_prog_ini(ah, &ah->ini_japan2484, 1); @@ -725,6 +711,14 @@ static void ar9003_hw_set_rfmode(struct ath_hw *ah, if (IS_CHAN_A_FAST_CLOCK(ah, chan)) rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE); + if (IS_CHAN_QUARTER_RATE(chan)) + rfMode |= AR_PHY_MODE_QUARTER; + if (IS_CHAN_HALF_RATE(chan)) + rfMode |= AR_PHY_MODE_HALF; + + if (rfMode & (AR_PHY_MODE_QUARTER | AR_PHY_MODE_HALF)) + REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, + AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW, 3); REG_WRITE(ah, AR_PHY_MODE, rfMode); } @@ -795,12 +789,8 @@ static bool ar9003_hw_rfbus_req(struct ath_hw *ah) static void ar9003_hw_rfbus_done(struct ath_hw *ah) { u32 synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; - if (IS_CHAN_B(ah->curchan)) - synthDelay = (4 * synthDelay) / 22; - else - synthDelay /= 10; - udelay(synthDelay + BASE_ACTIVATE_DELAY); + ath9k_hw_synth_delay(ah, ah->curchan, synthDelay); REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0); } @@ -823,55 +813,6 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah, * on == 0 means more noise imm */ u32 on = param ? 1 : 0; - /* - * make register setting for default - * (weak sig detect ON) come from INI file - */ - int m1ThreshLow = on ? - aniState->iniDef.m1ThreshLow : m1ThreshLow_off; - int m2ThreshLow = on ? - aniState->iniDef.m2ThreshLow : m2ThreshLow_off; - int m1Thresh = on ? - aniState->iniDef.m1Thresh : m1Thresh_off; - int m2Thresh = on ? - aniState->iniDef.m2Thresh : m2Thresh_off; - int m2CountThr = on ? - aniState->iniDef.m2CountThr : m2CountThr_off; - int m2CountThrLow = on ? - aniState->iniDef.m2CountThrLow : m2CountThrLow_off; - int m1ThreshLowExt = on ? - aniState->iniDef.m1ThreshLowExt : m1ThreshLowExt_off; - int m2ThreshLowExt = on ? - aniState->iniDef.m2ThreshLowExt : m2ThreshLowExt_off; - int m1ThreshExt = on ? - aniState->iniDef.m1ThreshExt : m1ThreshExt_off; - int m2ThreshExt = on ? - aniState->iniDef.m2ThreshExt : m2ThreshExt_off; - - REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_M1_THRESH_LOW, - m1ThreshLow); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_M2_THRESH_LOW, - m2ThreshLow); - REG_RMW_FIELD(ah, AR_PHY_SFCORR, - AR_PHY_SFCORR_M1_THRESH, m1Thresh); - REG_RMW_FIELD(ah, AR_PHY_SFCORR, - AR_PHY_SFCORR_M2_THRESH, m2Thresh); - REG_RMW_FIELD(ah, AR_PHY_SFCORR, - AR_PHY_SFCORR_M2COUNT_THR, m2CountThr); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, - m2CountThrLow); - - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLowExt); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2ThreshLowExt); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M1_THRESH, m1ThreshExt); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M2_THRESH, m2ThreshExt); if (on) REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, diff --git a/trunk/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/trunk/drivers/net/wireless/ath/ath9k/ar9003_phy.h index d834d97fe727..7268a48a92a1 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/trunk/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -468,6 +468,9 @@ #define AR_PHY_ADDAC_PARA_CTL (AR_SM_BASE + 0x150) #define AR_PHY_XPA_CFG (AR_SM_BASE + 0x158) +#define AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW 3 +#define AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW_S 0 + #define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A 0x0001FC00 #define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A_S 10 #define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A 0x3FF diff --git a/trunk/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h b/trunk/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h index b6ba1e8149be..1d6658e139b5 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h +++ b/trunk/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h @@ -1115,9 +1115,9 @@ static const u32 ar9462_2p0_mac_core[][2] = { {0x000081f8, 0x00000000}, {0x000081fc, 0x00000000}, {0x00008240, 0x00100000}, - {0x00008244, 0x0010f400}, + {0x00008244, 0x0010f424}, {0x00008248, 0x00000800}, - {0x0000824c, 0x0001e800}, + {0x0000824c, 0x0001e848}, {0x00008250, 0x00000000}, {0x00008254, 0x00000000}, {0x00008258, 0x00000000}, @@ -1448,16 +1448,4 @@ static const u32 ar9462_common_mixed_rx_gain_table_2p0[][2] = { {0x0000b1fc, 0x00000196}, }; -static const u32 ar9462_2p0_BTCOEX_MAX_TXPWR_table[][2] = { - /* Addr allmodes */ - {0x000018c0, 0x10101010}, - {0x000018c4, 0x10101010}, - {0x000018c8, 0x10101010}, - {0x000018cc, 0x10101010}, - {0x000018d0, 0x10101010}, - {0x000018d4, 0x10101010}, - {0x000018d8, 0x10101010}, - {0x000018dc, 0x10101010}, -}; - #endif /* INITVALS_9462_2P0_H */ diff --git a/trunk/drivers/net/wireless/ath/ath9k/ath9k.h b/trunk/drivers/net/wireless/ath/ath9k/ath9k.h index 8c84049682ab..a277cf6f339d 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/trunk/drivers/net/wireless/ath/ath9k/ath9k.h @@ -26,6 +26,7 @@ #include "debug.h" #include "common.h" #include "mci.h" +#include "dfs.h" /* * Header for the ath9k.ko driver core *only* -- hw code nor any other driver @@ -369,7 +370,7 @@ struct ath_vif { * number of beacon intervals, the game's up. */ #define BSTUCK_THRESH 9 -#define ATH_BCBUF 4 +#define ATH_BCBUF 8 #define ATH_DEFAULT_BINTVAL 100 /* TU */ #define ATH_DEFAULT_BMISS_LIMIT 10 #define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) @@ -430,6 +431,8 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status); void ath_reset_work(struct work_struct *work); void ath_hw_check(struct work_struct *work); void ath_hw_pll_work(struct work_struct *work); +void ath_rx_poll(unsigned long data); +void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon); void ath_paprd_calibrate(struct work_struct *work); void ath_ani_calibrate(unsigned long data); void ath_start_ani(struct ath_common *common); @@ -670,6 +673,7 @@ struct ath_softc { struct ath_beacon_config cur_beacon_conf; struct delayed_work tx_complete_work; struct delayed_work hw_pll_work; + struct timer_list rx_poll_timer; #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT struct ath_btcoex btcoex; @@ -680,6 +684,7 @@ struct ath_softc { struct ath_ant_comb ant_comb; u8 ant_tx, ant_rx; + struct dfs_pattern_detector *dfs_detector; }; void ath9k_tasklet(unsigned long data); diff --git a/trunk/drivers/net/wireless/ath/ath9k/beacon.c b/trunk/drivers/net/wireless/ath/ath9k/beacon.c index 626418222c85..11bc55e3d697 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/beacon.c +++ b/trunk/drivers/net/wireless/ath/ath9k/beacon.c @@ -91,7 +91,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif, info.txpower = MAX_RATE_POWER; info.keyix = ATH9K_TXKEYIX_INVALID; info.keytype = ATH9K_KEY_TYPE_CLEAR; - info.flags = ATH9K_TXDESC_NOACK | ATH9K_TXDESC_INTREQ; + info.flags = ATH9K_TXDESC_NOACK | ATH9K_TXDESC_CLRDMASK; info.buf_addr[0] = bf->bf_buf_addr; info.buf_len[0] = roundup(skb->len, 4); @@ -359,6 +359,11 @@ void ath_beacon_tasklet(unsigned long data) int slot; u32 bfaddr, bc = 0; + if (work_pending(&sc->hw_reset_work)) { + ath_dbg(common, RESET, + "reset work is pending, skip beaconing now\n"); + return; + } /* * Check if the previous beacon has gone out. If * not don't try to post another, skip this period @@ -369,6 +374,9 @@ void ath_beacon_tasklet(unsigned long data) if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) { sc->beacon.bmisscnt++; + if (!ath9k_hw_check_alive(ah)) + ieee80211_queue_work(sc->hw, &sc->hw_check_work); + if (sc->beacon.bmisscnt < BSTUCK_THRESH * sc->nbcnvifs) { ath_dbg(common, BSTUCK, "missed %u consecutive beacons\n", @@ -378,6 +386,7 @@ void ath_beacon_tasklet(unsigned long data) ath9k_hw_bstuck_nfcal(ah); } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { ath_dbg(common, BSTUCK, "beacon is officially stuck\n"); + sc->beacon.bmisscnt = 0; sc->sc_flags |= SC_OP_TSF_RESET; ieee80211_queue_work(sc->hw, &sc->hw_reset_work); } @@ -650,6 +659,8 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, u32 tsf, intval, nexttbtt; ath9k_reset_beacon_status(sc); + if (!(sc->sc_flags & SC_OP_BEACONS)) + ath9k_hw_settsf64(ah, sc->beacon.bc_tstamp); intval = TU_TO_USEC(conf->beacon_interval); tsf = roundup(ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE), intval); @@ -806,8 +817,10 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status) { struct ath_hw *ah = sc->sc_ah; - if (!ath_has_valid_bslot(sc)) + if (!ath_has_valid_bslot(sc)) { + sc->sc_flags &= ~SC_OP_BEACONS; return; + } ath9k_ps_wakeup(sc); if (status) { diff --git a/trunk/drivers/net/wireless/ath/ath9k/btcoex.c b/trunk/drivers/net/wireless/ath/ath9k/btcoex.c index ec3271993411..1ca6da80d4ad 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/trunk/drivers/net/wireless/ath/ath9k/btcoex.c @@ -108,9 +108,7 @@ void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah) return; } - if (AR_SREV_9462(ah)) { - btcoex_hw->scheme = ATH_BTCOEX_CFG_MCI; - } else if (AR_SREV_9300_20_OR_LATER(ah)) { + if (AR_SREV_9300_20_OR_LATER(ah)) { btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE; btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300; btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300; @@ -284,11 +282,12 @@ void ath9k_hw_btcoex_enable(struct ath_hw *ah) ath9k_hw_btcoex_enable_2wire(ah); break; case ATH_BTCOEX_CFG_3WIRE: + if (AR_SREV_9462(ah)) { + ath9k_hw_btcoex_enable_mci(ah); + return; + } ath9k_hw_btcoex_enable_3wire(ah); break; - case ATH_BTCOEX_CFG_MCI: - ath9k_hw_btcoex_enable_mci(ah); - return; } REG_RMW(ah, AR_GPIO_PDPU, @@ -305,11 +304,12 @@ void ath9k_hw_btcoex_disable(struct ath_hw *ah) int i; btcoex_hw->enabled = false; - if (btcoex_hw->scheme == ATH_BTCOEX_CFG_MCI) { + if (AR_SREV_9462(ah)) { ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE); for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++) REG_WRITE(ah, AR_MCI_COEX_WL_WEIGHTS(i), btcoex_hw->wlan_weight[i]); + return; } ath9k_hw_set_gpio(ah, btcoex_hw->wlanactive_gpio, 0); diff --git a/trunk/drivers/net/wireless/ath/ath9k/btcoex.h b/trunk/drivers/net/wireless/ath/ath9k/btcoex.h index 8f93aef4414f..3a1e1cfabd5e 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/trunk/drivers/net/wireless/ath/ath9k/btcoex.h @@ -51,7 +51,6 @@ enum ath_btcoex_scheme { ATH_BTCOEX_CFG_NONE, ATH_BTCOEX_CFG_2WIRE, ATH_BTCOEX_CFG_3WIRE, - ATH_BTCOEX_CFG_MCI, }; struct ath9k_hw_mci { diff --git a/trunk/drivers/net/wireless/ath/ath9k/debug.c b/trunk/drivers/net/wireless/ath/ath9k/debug.c index ff47b32ecaf4..fde700c4e490 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/debug.c +++ b/trunk/drivers/net/wireless/ath/ath9k/debug.c @@ -380,63 +380,75 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; - char buf[512]; unsigned int len = 0; + int rv; + int mxlen = 4000; + char *buf = kmalloc(mxlen, GFP_KERNEL); + if (!buf) + return -ENOMEM; + +#define PR_IS(a, s) \ + do { \ + len += snprintf(buf + len, mxlen - len, \ + "%21s: %10u\n", a, \ + sc->debug.stats.istats.s); \ + } while (0) if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "RXLP", sc->debug.stats.istats.rxlp); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "RXHP", sc->debug.stats.istats.rxhp); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "WATCHDOG", - sc->debug.stats.istats.bb_watchdog); + PR_IS("RXLP", rxlp); + PR_IS("RXHP", rxhp); + PR_IS("WATHDOG", bb_watchdog); } else { - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "RX", sc->debug.stats.istats.rxok); + PR_IS("RX", rxok); } - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "RXEOL", sc->debug.stats.istats.rxeol); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "RXORN", sc->debug.stats.istats.rxorn); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "TX", sc->debug.stats.istats.txok); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "TXURN", sc->debug.stats.istats.txurn); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "MIB", sc->debug.stats.istats.mib); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "RXPHY", sc->debug.stats.istats.rxphyerr); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "RXKCM", sc->debug.stats.istats.rx_keycache_miss); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "SWBA", sc->debug.stats.istats.swba); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "BMISS", sc->debug.stats.istats.bmiss); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "BNR", sc->debug.stats.istats.bnr); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "CST", sc->debug.stats.istats.cst); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "GTT", sc->debug.stats.istats.gtt); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "TIM", sc->debug.stats.istats.tim); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "CABEND", sc->debug.stats.istats.cabend); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "DTIMSYNC", sc->debug.stats.istats.dtimsync); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "DTIM", sc->debug.stats.istats.dtim); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "TSFOOR", sc->debug.stats.istats.tsfoor); - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "TOTAL", sc->debug.stats.istats.total); - - - if (len > sizeof(buf)) - len = sizeof(buf); - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); + PR_IS("RXEOL", rxeol); + PR_IS("RXORN", rxorn); + PR_IS("TX", txok); + PR_IS("TXURN", txurn); + PR_IS("MIB", mib); + PR_IS("RXPHY", rxphyerr); + PR_IS("RXKCM", rx_keycache_miss); + PR_IS("SWBA", swba); + PR_IS("BMISS", bmiss); + PR_IS("BNR", bnr); + PR_IS("CST", cst); + PR_IS("GTT", gtt); + PR_IS("TIM", tim); + PR_IS("CABEND", cabend); + PR_IS("DTIMSYNC", dtimsync); + PR_IS("DTIM", dtim); + PR_IS("TSFOOR", tsfoor); + PR_IS("TOTAL", total); + + len += snprintf(buf + len, mxlen - len, + "SYNC_CAUSE stats:\n"); + + PR_IS("Sync-All", sync_cause_all); + PR_IS("RTC-IRQ", sync_rtc_irq); + PR_IS("MAC-IRQ", sync_mac_irq); + PR_IS("EEPROM-Illegal-Access", eeprom_illegal_access); + PR_IS("APB-Timeout", apb_timeout); + PR_IS("PCI-Mode-Conflict", pci_mode_conflict); + PR_IS("HOST1-Fatal", host1_fatal); + PR_IS("HOST1-Perr", host1_perr); + PR_IS("TRCV-FIFO-Perr", trcv_fifo_perr); + PR_IS("RADM-CPL-EP", radm_cpl_ep); + PR_IS("RADM-CPL-DLLP-Abort", radm_cpl_dllp_abort); + PR_IS("RADM-CPL-TLP-Abort", radm_cpl_tlp_abort); + PR_IS("RADM-CPL-ECRC-Err", radm_cpl_ecrc_err); + PR_IS("RADM-CPL-Timeout", radm_cpl_timeout); + PR_IS("Local-Bus-Timeout", local_timeout); + PR_IS("PM-Access", pm_access); + PR_IS("MAC-Awake", mac_awake); + PR_IS("MAC-Asleep", mac_asleep); + PR_IS("MAC-Sleep-Access", mac_sleep_access); + + if (len > mxlen) + len = mxlen; + + rv = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + return rv; } static const struct file_operations fops_interrupt = { @@ -524,6 +536,7 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, PR("hw-put-tx-buf: ", puttxbuf); PR("hw-tx-start: ", txstart); PR("hw-tx-proc-desc: ", txprocdesc); + PR("TX-Failed: ", txfailed); len += snprintf(buf + len, size - len, "%s%11p%11p%10p%10p\n", "txq-memory-address:", sc->tx.txq_map[WME_AC_BE], @@ -880,6 +893,13 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, len += snprintf(buf + len, size - len, "%22s : %10u\n", s, \ sc->debug.stats.rxstats.phy_err_stats[p]); +#define RXS_ERR(s, e) \ + do { \ + len += snprintf(buf + len, size - len, \ + "%22s : %10u\n", s, \ + sc->debug.stats.rxstats.e); \ + } while (0) + struct ath_softc *sc = file->private_data; char *buf; unsigned int len = 0, size = 1600; @@ -889,27 +909,18 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, if (buf == NULL) return -ENOMEM; - len += snprintf(buf + len, size - len, - "%22s : %10u\n", "CRC ERR", - sc->debug.stats.rxstats.crc_err); - len += snprintf(buf + len, size - len, - "%22s : %10u\n", "DECRYPT CRC ERR", - sc->debug.stats.rxstats.decrypt_crc_err); - len += snprintf(buf + len, size - len, - "%22s : %10u\n", "PHY ERR", - sc->debug.stats.rxstats.phy_err); - len += snprintf(buf + len, size - len, - "%22s : %10u\n", "MIC ERR", - sc->debug.stats.rxstats.mic_err); - len += snprintf(buf + len, size - len, - "%22s : %10u\n", "PRE-DELIM CRC ERR", - sc->debug.stats.rxstats.pre_delim_crc_err); - len += snprintf(buf + len, size - len, - "%22s : %10u\n", "POST-DELIM CRC ERR", - sc->debug.stats.rxstats.post_delim_crc_err); - len += snprintf(buf + len, size - len, - "%22s : %10u\n", "DECRYPT BUSY ERR", - sc->debug.stats.rxstats.decrypt_busy_err); + RXS_ERR("CRC ERR", crc_err); + RXS_ERR("DECRYPT CRC ERR", decrypt_crc_err); + RXS_ERR("PHY ERR", phy_err); + RXS_ERR("MIC ERR", mic_err); + RXS_ERR("PRE-DELIM CRC ERR", pre_delim_crc_err); + RXS_ERR("POST-DELIM CRC ERR", post_delim_crc_err); + RXS_ERR("DECRYPT BUSY ERR", decrypt_busy_err); + RXS_ERR("RX-LENGTH-ERR", rx_len_err); + RXS_ERR("RX-OOM-ERR", rx_oom_err); + RXS_ERR("RX-RATE-ERR", rx_rate_err); + RXS_ERR("RX-DROP-RXFLUSH", rx_drop_rxflush); + RXS_ERR("RX-TOO-MANY-FRAGS", rx_too_many_frags_err); PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN); PHY_ERR("TIMING ERR", ATH9K_PHYERR_TIMING); @@ -938,12 +949,10 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, PHY_ERR("HT-LENGTH ERR", ATH9K_PHYERR_HT_LENGTH_ILLEGAL); PHY_ERR("HT-RATE ERR", ATH9K_PHYERR_HT_RATE_ILLEGAL); - len += snprintf(buf + len, size - len, - "%22s : %10u\n", "RX-Pkts-All", - sc->debug.stats.rxstats.rx_pkts_all); - len += snprintf(buf + len, size - len, - "%22s : %10u\n", "RX-Bytes-All", - sc->debug.stats.rxstats.rx_bytes_all); + RXS_ERR("RX-Pkts-All", rx_pkts_all); + RXS_ERR("RX-Bytes-All", rx_bytes_all); + RXS_ERR("RX-Beacons", rx_beacons); + RXS_ERR("RX-Frags", rx_frags); if (len > size) len = size; @@ -953,12 +962,12 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, return retval; +#undef RXS_ERR #undef PHY_ERR } void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) { -#define RX_STAT_INC(c) sc->debug.stats.rxstats.c++ #define RX_PHY_ERR_INC(c) sc->debug.stats.rxstats.phy_err_stats[c]++ #define RX_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].rs\ [sc->debug.rsidx].c) @@ -1004,7 +1013,6 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) #endif -#undef RX_STAT_INC #undef RX_PHY_ERR_INC #undef RX_SAMP_DBG } diff --git a/trunk/drivers/net/wireless/ath/ath9k/debug.h b/trunk/drivers/net/wireless/ath/ath9k/debug.h index 64fcfad467bf..c34da09d9103 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/debug.h +++ b/trunk/drivers/net/wireless/ath/ath9k/debug.h @@ -60,6 +60,7 @@ struct ath_buf; * @tsfoor: TSF out of range, indicates that the corrected TSF received * from a beacon differs from the PCU's internal TSF by more than a * (programmable) threshold + * @local_timeout: Internal bus timeout. */ struct ath_interrupt_stats { u32 total; @@ -85,8 +86,30 @@ struct ath_interrupt_stats { u32 dtim; u32 bb_watchdog; u32 tsfoor; + + /* Sync-cause stats */ + u32 sync_cause_all; + u32 sync_rtc_irq; + u32 sync_mac_irq; + u32 eeprom_illegal_access; + u32 apb_timeout; + u32 pci_mode_conflict; + u32 host1_fatal; + u32 host1_perr; + u32 trcv_fifo_perr; + u32 radm_cpl_ep; + u32 radm_cpl_dllp_abort; + u32 radm_cpl_tlp_abort; + u32 radm_cpl_ecrc_err; + u32 radm_cpl_timeout; + u32 local_timeout; + u32 pm_access; + u32 mac_awake; + u32 mac_asleep; + u32 mac_sleep_access; }; + /** * struct ath_tx_stats - Statistics about TX * @tx_pkts_all: No. of total frames transmitted, including ones that @@ -113,6 +136,7 @@ struct ath_interrupt_stats { * @puttxbuf: Number of times hardware was given txbuf to write. * @txstart: Number of times hardware was told to start tx. * @txprocdesc: Number of times tx descriptor was processed + * @txfailed: Out-of-memory or other errors in xmit path. */ struct ath_tx_stats { u32 tx_pkts_all; @@ -135,8 +159,11 @@ struct ath_tx_stats { u32 puttxbuf; u32 txstart; u32 txprocdesc; + u32 txfailed; }; +#define RX_STAT_INC(c) (sc->debug.stats.rxstats.c++) + /** * struct ath_rx_stats - RX Statistics * @rx_pkts_all: No. of total frames received, including ones that @@ -153,6 +180,13 @@ struct ath_tx_stats { * @post_delim_crc_err: Post-Frame delimiter CRC error detections * @decrypt_busy_err: Decryption interruptions counter * @phy_err_stats: Individual PHY error statistics + * @rx_len_err: No. of frames discarded due to bad length. + * @rx_oom_err: No. of frames dropped due to OOM issues. + * @rx_rate_err: No. of frames dropped due to rate errors. + * @rx_too_many_frags_err: Frames dropped due to too-many-frags received. + * @rx_drop_rxflush: No. of frames dropped due to RX-FLUSH. + * @rx_beacons: No. of beacons received. + * @rx_frags: No. of rx-fragements received. */ struct ath_rx_stats { u32 rx_pkts_all; @@ -165,6 +199,13 @@ struct ath_rx_stats { u32 post_delim_crc_err; u32 decrypt_busy_err; u32 phy_err_stats[ATH9K_PHYERR_MAX]; + u32 rx_len_err; + u32 rx_oom_err; + u32 rx_rate_err; + u32 rx_too_many_frags_err; + u32 rx_drop_rxflush; + u32 rx_beacons; + u32 rx_frags; }; enum ath_reset_type { @@ -174,6 +215,7 @@ enum ath_reset_type { RESET_TYPE_TX_ERROR, RESET_TYPE_TX_HANG, RESET_TYPE_PLL_HANG, + RESET_TYPE_MAC_HANG, __RESET_TYPE_MAX }; @@ -247,6 +289,8 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs); #else +#define RX_STAT_INC(c) /* NOP */ + static inline int ath9k_init_debug(struct ath_hw *ah) { return 0; diff --git a/trunk/drivers/net/wireless/ath/ath9k/dfs.c b/trunk/drivers/net/wireless/ath/ath9k/dfs.c index f4f56aff1e9d..ecc81792f2dc 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/dfs.c +++ b/trunk/drivers/net/wireless/ath/ath9k/dfs.c @@ -21,17 +21,6 @@ #include "dfs.h" #include "dfs_debug.h" -/* - * TODO: move into or synchronize this with generic header - * as soon as IF is defined - */ -struct dfs_radar_pulse { - u16 freq; - u64 ts; - u32 width; - u8 rssi; -}; - /* internal struct to pass radar data */ struct ath_radar_data { u8 pulse_bw_info; @@ -60,44 +49,44 @@ static u32 dur_to_usecs(struct ath_hw *ah, u32 dur) #define EXT_CH_RADAR_FOUND 0x02 static bool ath9k_postprocess_radar_event(struct ath_softc *sc, - struct ath_radar_data *are, - struct dfs_radar_pulse *drp) + struct ath_radar_data *ard, + struct pulse_event *pe) { u8 rssi; u16 dur; ath_dbg(ath9k_hw_common(sc->sc_ah), DFS, "pulse_bw_info=0x%x, pri,ext len/rssi=(%u/%u, %u/%u)\n", - are->pulse_bw_info, - are->pulse_length_pri, are->rssi, - are->pulse_length_ext, are->ext_rssi); + ard->pulse_bw_info, + ard->pulse_length_pri, ard->rssi, + ard->pulse_length_ext, ard->ext_rssi); /* * Only the last 2 bits of the BW info are relevant, they indicate * which channel the radar was detected in. */ - are->pulse_bw_info &= 0x03; + ard->pulse_bw_info &= 0x03; - switch (are->pulse_bw_info) { + switch (ard->pulse_bw_info) { case PRI_CH_RADAR_FOUND: /* radar in ctrl channel */ - dur = are->pulse_length_pri; + dur = ard->pulse_length_pri; DFS_STAT_INC(sc, pri_phy_errors); /* * cannot use ctrl channel RSSI * if extension channel is stronger */ - rssi = (are->ext_rssi >= (are->rssi + 3)) ? 0 : are->rssi; + rssi = (ard->ext_rssi >= (ard->rssi + 3)) ? 0 : ard->rssi; break; case EXT_CH_RADAR_FOUND: /* radar in extension channel */ - dur = are->pulse_length_ext; + dur = ard->pulse_length_ext; DFS_STAT_INC(sc, ext_phy_errors); /* * cannot use extension channel RSSI * if control channel is stronger */ - rssi = (are->rssi >= (are->ext_rssi + 12)) ? 0 : are->ext_rssi; + rssi = (ard->rssi >= (ard->ext_rssi + 12)) ? 0 : ard->ext_rssi; break; case (PRI_CH_RADAR_FOUND | EXT_CH_RADAR_FOUND): /* @@ -107,14 +96,14 @@ ath9k_postprocess_radar_event(struct ath_softc *sc, * Radiated testing, when pulse is on DC, different pri and * ext durations are reported, so take the larger of the two */ - if (are->pulse_length_ext >= are->pulse_length_pri) - dur = are->pulse_length_ext; + if (ard->pulse_length_ext >= ard->pulse_length_pri) + dur = ard->pulse_length_ext; else - dur = are->pulse_length_pri; + dur = ard->pulse_length_pri; DFS_STAT_INC(sc, dc_phy_errors); /* when both are present use stronger one */ - rssi = (are->rssi < are->ext_rssi) ? are->ext_rssi : are->rssi; + rssi = (ard->rssi < ard->ext_rssi) ? ard->ext_rssi : ard->rssi; break; default: /* @@ -137,8 +126,8 @@ ath9k_postprocess_radar_event(struct ath_softc *sc, */ /* convert duration to usecs */ - drp->width = dur_to_usecs(sc->sc_ah, dur); - drp->rssi = rssi; + pe->width = dur_to_usecs(sc->sc_ah, dur); + pe->rssi = rssi; DFS_STAT_INC(sc, pulses_detected); return true; @@ -155,15 +144,17 @@ void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data, struct ath_radar_data ard; u16 datalen; char *vdata_end; - struct dfs_radar_pulse drp; + struct pulse_event pe; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - if ((!(rs->rs_phyerr != ATH9K_PHYERR_RADAR)) && - (!(rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT))) { + DFS_STAT_INC(sc, pulses_total); + if ((rs->rs_phyerr != ATH9K_PHYERR_RADAR) && + (rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT)) { ath_dbg(common, DFS, "Error: rs_phyer=0x%x not a radar error\n", rs->rs_phyerr); + DFS_STAT_INC(sc, pulses_no_dfs); return; } @@ -189,27 +180,22 @@ void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data, ard.pulse_bw_info = vdata_end[-1]; ard.pulse_length_ext = vdata_end[-2]; ard.pulse_length_pri = vdata_end[-3]; - - ath_dbg(common, DFS, - "bw_info=%d, length_pri=%d, length_ext=%d, " - "rssi_pri=%d, rssi_ext=%d\n", - ard.pulse_bw_info, ard.pulse_length_pri, ard.pulse_length_ext, - ard.rssi, ard.ext_rssi); - - drp.freq = ah->curchan->channel; - drp.ts = mactime; - if (ath9k_postprocess_radar_event(sc, &ard, &drp)) { + pe.freq = ah->curchan->channel; + pe.ts = mactime; + if (ath9k_postprocess_radar_event(sc, &ard, &pe)) { + struct dfs_pattern_detector *pd = sc->dfs_detector; static u64 last_ts; ath_dbg(common, DFS, "ath9k_dfs_process_phyerr: channel=%d, ts=%llu, " "width=%d, rssi=%d, delta_ts=%llu\n", - drp.freq, drp.ts, drp.width, drp.rssi, drp.ts-last_ts); - last_ts = drp.ts; - /* - * TODO: forward pulse to pattern detector - * - * ieee80211_add_radar_pulse(drp.freq, drp.ts, - * drp.width, drp.rssi); - */ + pe.freq, pe.ts, pe.width, pe.rssi, pe.ts-last_ts); + last_ts = pe.ts; + DFS_STAT_INC(sc, pulses_processed); + if (pd != NULL && pd->add_pulse(pd, &pe)) { + DFS_STAT_INC(sc, radar_detected); + /* + * TODO: forward radar event to DFS management layer + */ + } } } diff --git a/trunk/drivers/net/wireless/ath/ath9k/dfs.h b/trunk/drivers/net/wireless/ath/ath9k/dfs.h index c2412857f122..3c839f06a06a 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/dfs.h +++ b/trunk/drivers/net/wireless/ath/ath9k/dfs.h @@ -17,6 +17,7 @@ #ifndef ATH9K_DFS_H #define ATH9K_DFS_H +#include "dfs_pattern_detector.h" #if defined(CONFIG_ATH9K_DFS_CERTIFIED) /** @@ -31,13 +32,14 @@ * * The radar information provided as raw payload data is validated and * filtered for false pulses. Events passing all tests are forwarded to - * the upper layer for pattern detection. + * the DFS detector for pattern detection. */ void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data, struct ath_rx_status *rs, u64 mactime); #else -static inline void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data, - struct ath_rx_status *rs, u64 mactime) { } +static inline void +ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data, + struct ath_rx_status *rs, u64 mactime) { } #endif #endif /* ATH9K_DFS_H */ diff --git a/trunk/drivers/net/wireless/ath/ath9k/dfs_debug.c b/trunk/drivers/net/wireless/ath/ath9k/dfs_debug.c index 4364c103ed33..55d28072adeb 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/dfs_debug.c +++ b/trunk/drivers/net/wireless/ath/ath9k/dfs_debug.c @@ -21,9 +21,15 @@ #include "ath9k.h" #include "dfs_debug.h" + +struct ath_dfs_pool_stats global_dfs_pool_stats = { 0 }; + #define ATH9K_DFS_STAT(s, p) \ len += snprintf(buf + len, size - len, "%28s : %10u\n", s, \ sc->debug.stats.dfs_stats.p); +#define ATH9K_DFS_POOL_STAT(s, p) \ + len += snprintf(buf + len, size - len, "%28s : %10u\n", s, \ + global_dfs_pool_stats.p); static ssize_t read_file_dfs(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -43,6 +49,9 @@ static ssize_t read_file_dfs(struct file *file, char __user *user_buf, hw_ver->macVersion, hw_ver->macRev, (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_DFS) ? "enabled" : "disabled"); + len += snprintf(buf + len, size - len, "Pulse detector statistics:\n"); + ATH9K_DFS_STAT("pulse events reported ", pulses_total); + ATH9K_DFS_STAT("invalid pulse events ", pulses_no_dfs); ATH9K_DFS_STAT("DFS pulses detected ", pulses_detected); ATH9K_DFS_STAT("Datalen discards ", datalen_discards); ATH9K_DFS_STAT("RSSI discards ", rssi_discards); @@ -50,6 +59,18 @@ static ssize_t read_file_dfs(struct file *file, char __user *user_buf, ATH9K_DFS_STAT("Primary channel pulses ", pri_phy_errors); ATH9K_DFS_STAT("Secondary channel pulses", ext_phy_errors); ATH9K_DFS_STAT("Dual channel pulses ", dc_phy_errors); + len += snprintf(buf + len, size - len, "Radar detector statistics " + "(current DFS region: %d)\n", sc->dfs_detector->region); + ATH9K_DFS_STAT("Pulse events processed ", pulses_processed); + ATH9K_DFS_STAT("Radars detected ", radar_detected); + len += snprintf(buf + len, size - len, "Global Pool statistics:\n"); + ATH9K_DFS_POOL_STAT("Pool references ", pool_reference); + ATH9K_DFS_POOL_STAT("Pulses allocated ", pulse_allocated); + ATH9K_DFS_POOL_STAT("Pulses alloc error ", pulse_alloc_error); + ATH9K_DFS_POOL_STAT("Pulses in use ", pulse_used); + ATH9K_DFS_POOL_STAT("Seqs. allocated ", pseq_allocated); + ATH9K_DFS_POOL_STAT("Seqs. alloc error ", pseq_alloc_error); + ATH9K_DFS_POOL_STAT("Seqs. in use ", pseq_used); if (len > size) len = size; @@ -60,8 +81,33 @@ static ssize_t read_file_dfs(struct file *file, char __user *user_buf, return retval; } +/* magic number to prevent accidental reset of DFS statistics */ +#define DFS_STATS_RESET_MAGIC 0x80000000 +static ssize_t write_file_dfs(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + unsigned long val; + char buf[32]; + ssize_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + if (strict_strtoul(buf, 0, &val)) + return -EINVAL; + + if (val == DFS_STATS_RESET_MAGIC) + memset(&sc->debug.stats.dfs_stats, 0, + sizeof(sc->debug.stats.dfs_stats)); + return count; +} + static const struct file_operations fops_dfs_stats = { .read = read_file_dfs, + .write = write_file_dfs, .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, diff --git a/trunk/drivers/net/wireless/ath/ath9k/dfs_debug.h b/trunk/drivers/net/wireless/ath/ath9k/dfs_debug.h index 4911724cb445..e36810a4b585 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/dfs_debug.h +++ b/trunk/drivers/net/wireless/ath/ath9k/dfs_debug.h @@ -22,17 +22,23 @@ #include "hw.h" /** - * struct ath_dfs_stats - DFS Statistics - * - * @pulses_detected: No. of pulses detected so far - * @datalen_discards: No. of pulses discarded due to invalid datalen - * @rssi_discards: No. of pulses discarded due to invalid RSSI - * @bwinfo_discards: No. of pulses discarded due to invalid BW info - * @pri_phy_errors: No. of pulses reported for primary channel - * @ext_phy_errors: No. of pulses reported for extension channel - * @dc_phy_errors: No. of pulses reported for primary + extension channel + * struct ath_dfs_stats - DFS Statistics per wiphy + * @pulses_total: pulses reported by HW + * @pulses_no_dfs: pulses wrongly reported as DFS + * @pulses_detected: pulses detected so far + * @datalen_discards: pulses discarded due to invalid datalen + * @rssi_discards: pulses discarded due to invalid RSSI + * @bwinfo_discards: pulses discarded due to invalid BW info + * @pri_phy_errors: pulses reported for primary channel + * @ext_phy_errors: pulses reported for extension channel + * @dc_phy_errors: pulses reported for primary + extension channel + * @pulses_processed: pulses forwarded to detector + * @radar_detected: radars detected */ struct ath_dfs_stats { + /* pulse stats */ + u32 pulses_total; + u32 pulses_no_dfs; u32 pulses_detected; u32 datalen_discards; u32 rssi_discards; @@ -40,18 +46,39 @@ struct ath_dfs_stats { u32 pri_phy_errors; u32 ext_phy_errors; u32 dc_phy_errors; + /* pattern detection stats */ + u32 pulses_processed; + u32 radar_detected; }; +/** + * struct ath_dfs_pool_stats - DFS Statistics for global pools + */ +struct ath_dfs_pool_stats { + u32 pool_reference; + u32 pulse_allocated; + u32 pulse_alloc_error; + u32 pulse_used; + u32 pseq_allocated; + u32 pseq_alloc_error; + u32 pseq_used; +}; #if defined(CONFIG_ATH9K_DFS_DEBUGFS) #define DFS_STAT_INC(sc, c) (sc->debug.stats.dfs_stats.c++) void ath9k_dfs_init_debug(struct ath_softc *sc); +#define DFS_POOL_STAT_INC(c) (global_dfs_pool_stats.c++) +#define DFS_POOL_STAT_DEC(c) (global_dfs_pool_stats.c--) +extern struct ath_dfs_pool_stats global_dfs_pool_stats; + #else #define DFS_STAT_INC(sc, c) do { } while (0) static inline void ath9k_dfs_init_debug(struct ath_softc *sc) { } +#define DFS_POOL_STAT_INC(c) do { } while (0) +#define DFS_POOL_STAT_DEC(c) do { } while (0) #endif /* CONFIG_ATH9K_DFS_DEBUGFS */ #endif /* ATH9K_DFS_DEBUG_H */ diff --git a/trunk/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c b/trunk/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c new file mode 100644 index 000000000000..ea2a6cf7ef23 --- /dev/null +++ b/trunk/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2012 Neratec Solutions AG + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include "dfs_pattern_detector.h" +#include "dfs_pri_detector.h" + +/* + * tolerated deviation of radar time stamp in usecs on both sides + * TODO: this might need to be HW-dependent + */ +#define PRI_TOLERANCE 16 + +/** + * struct radar_types - contains array of patterns defined for one DFS domain + * @domain: DFS regulatory domain + * @num_radar_types: number of radar types to follow + * @radar_types: radar types array + */ +struct radar_types { + enum nl80211_dfs_regions region; + u32 num_radar_types; + const struct radar_detector_specs *radar_types; +}; + +/* percentage on ppb threshold to trigger detection */ +#define MIN_PPB_THRESH 50 +#define PPB_THRESH(PPB) ((PPB * MIN_PPB_THRESH + 50) / 100) +#define PRF2PRI(PRF) ((1000000 + PRF / 2) / PRF) + +#define ETSI_PATTERN(ID, WMIN, WMAX, PMIN, PMAX, PRF, PPB) \ +{ \ + ID, WMIN, WMAX, (PRF2PRI(PMAX) - PRI_TOLERANCE), \ + (PRF2PRI(PMIN) * PRF + PRI_TOLERANCE), PRF, PPB * PRF, \ + PPB_THRESH(PPB), PRI_TOLERANCE, \ +} + +/* radar types as defined by ETSI EN-301-893 v1.5.1 */ +static const struct radar_detector_specs etsi_radar_ref_types_v15[] = { + ETSI_PATTERN(0, 0, 1, 700, 700, 1, 18), + ETSI_PATTERN(1, 0, 5, 200, 1000, 1, 10), + ETSI_PATTERN(2, 0, 15, 200, 1600, 1, 15), + ETSI_PATTERN(3, 0, 15, 2300, 4000, 1, 25), + ETSI_PATTERN(4, 20, 30, 2000, 4000, 1, 20), + ETSI_PATTERN(5, 0, 2, 300, 400, 3, 10), + ETSI_PATTERN(6, 0, 2, 400, 1200, 3, 15), +}; + +static const struct radar_types etsi_radar_types_v15 = { + .region = NL80211_DFS_ETSI, + .num_radar_types = ARRAY_SIZE(etsi_radar_ref_types_v15), + .radar_types = etsi_radar_ref_types_v15, +}; + +/* for now, we support ETSI radar types, FCC and JP are TODO */ +static const struct radar_types *dfs_domains[] = { + &etsi_radar_types_v15, +}; + +/** + * get_dfs_domain_radar_types() - get radar types for a given DFS domain + * @param domain DFS domain + * @return radar_types ptr on success, NULL if DFS domain is not supported + */ +static const struct radar_types * +get_dfs_domain_radar_types(enum nl80211_dfs_regions region) +{ + u32 i; + for (i = 0; i < ARRAY_SIZE(dfs_domains); i++) { + if (dfs_domains[i]->region == region) + return dfs_domains[i]; + } + return NULL; +} + +/** + * struct channel_detector - detector elements for a DFS channel + * @head: list_head + * @freq: frequency for this channel detector in MHz + * @detectors: array of dynamically created detector elements for this freq + * + * Channel detectors are required to provide multi-channel DFS detection, e.g. + * to support off-channel scanning. A pattern detector has a list of channels + * radar pulses have been reported for in the past. + */ +struct channel_detector { + struct list_head head; + u16 freq; + struct pri_detector **detectors; +}; + +/* channel_detector_reset() - reset detector lines for a given channel */ +static void channel_detector_reset(struct dfs_pattern_detector *dpd, + struct channel_detector *cd) +{ + u32 i; + if (cd == NULL) + return; + for (i = 0; i < dpd->num_radar_types; i++) + cd->detectors[i]->reset(cd->detectors[i], dpd->last_pulse_ts); +} + +/* channel_detector_exit() - destructor */ +static void channel_detector_exit(struct dfs_pattern_detector *dpd, + struct channel_detector *cd) +{ + u32 i; + if (cd == NULL) + return; + list_del(&cd->head); + for (i = 0; i < dpd->num_radar_types; i++) { + struct pri_detector *de = cd->detectors[i]; + if (de != NULL) + de->exit(de); + } + kfree(cd->detectors); + kfree(cd); +} + +static struct channel_detector * +channel_detector_create(struct dfs_pattern_detector *dpd, u16 freq) +{ + u32 sz, i; + struct channel_detector *cd; + + cd = kmalloc(sizeof(*cd), GFP_KERNEL); + if (cd == NULL) + goto fail; + + INIT_LIST_HEAD(&cd->head); + cd->freq = freq; + sz = sizeof(cd->detectors) * dpd->num_radar_types; + cd->detectors = kzalloc(sz, GFP_KERNEL); + if (cd->detectors == NULL) + goto fail; + + for (i = 0; i < dpd->num_radar_types; i++) { + const struct radar_detector_specs *rs = &dpd->radar_spec[i]; + struct pri_detector *de = pri_detector_init(rs); + if (de == NULL) + goto fail; + cd->detectors[i] = de; + } + list_add(&cd->head, &dpd->channel_detectors); + return cd; + +fail: + pr_err("failed to allocate channel_detector for freq=%d\n", freq); + channel_detector_exit(dpd, cd); + return NULL; +} + +/** + * channel_detector_get() - get channel detector for given frequency + * @param dpd instance pointer + * @param freq frequency in MHz + * @return pointer to channel detector on success, NULL otherwise + * + * Return existing channel detector for the given frequency or return a + * newly create one. + */ +static struct channel_detector * +channel_detector_get(struct dfs_pattern_detector *dpd, u16 freq) +{ + struct channel_detector *cd; + list_for_each_entry(cd, &dpd->channel_detectors, head) { + if (cd->freq == freq) + return cd; + } + return channel_detector_create(dpd, freq); +} + +/* + * DFS Pattern Detector + */ + +/* dpd_reset(): reset all channel detectors */ +static void dpd_reset(struct dfs_pattern_detector *dpd) +{ + struct channel_detector *cd; + if (!list_empty(&dpd->channel_detectors)) + list_for_each_entry(cd, &dpd->channel_detectors, head) + channel_detector_reset(dpd, cd); + +} +static void dpd_exit(struct dfs_pattern_detector *dpd) +{ + struct channel_detector *cd, *cd0; + if (!list_empty(&dpd->channel_detectors)) + list_for_each_entry_safe(cd, cd0, &dpd->channel_detectors, head) + channel_detector_exit(dpd, cd); + kfree(dpd); +} + +static bool +dpd_add_pulse(struct dfs_pattern_detector *dpd, struct pulse_event *event) +{ + u32 i; + bool ts_wraparound; + struct channel_detector *cd; + + if (dpd->region == NL80211_DFS_UNSET) { + /* + * pulses received for a non-supported or un-initialized + * domain are treated as detected radars + */ + return true; + } + + cd = channel_detector_get(dpd, event->freq); + if (cd == NULL) + return false; + + ts_wraparound = (event->ts < dpd->last_pulse_ts); + dpd->last_pulse_ts = event->ts; + if (ts_wraparound) { + /* + * reset detector on time stamp wraparound + * with monotonic time stamps, this should never happen + */ + pr_warn("DFS: time stamp wraparound detected, resetting\n"); + dpd_reset(dpd); + } + /* do type individual pattern matching */ + for (i = 0; i < dpd->num_radar_types; i++) { + if (cd->detectors[i]->add_pulse(cd->detectors[i], event) != 0) { + channel_detector_reset(dpd, cd); + return true; + } + } + return false; +} + +static bool dpd_set_domain(struct dfs_pattern_detector *dpd, + enum nl80211_dfs_regions region) +{ + const struct radar_types *rt; + struct channel_detector *cd, *cd0; + + if (dpd->region == region) + return true; + + dpd->region = NL80211_DFS_UNSET; + + rt = get_dfs_domain_radar_types(region); + if (rt == NULL) + return false; + + /* delete all channel detectors for previous DFS domain */ + if (!list_empty(&dpd->channel_detectors)) + list_for_each_entry_safe(cd, cd0, &dpd->channel_detectors, head) + channel_detector_exit(dpd, cd); + dpd->radar_spec = rt->radar_types; + dpd->num_radar_types = rt->num_radar_types; + + dpd->region = region; + return true; +} + +static struct dfs_pattern_detector default_dpd = { + .exit = dpd_exit, + .set_domain = dpd_set_domain, + .add_pulse = dpd_add_pulse, + .region = NL80211_DFS_UNSET, +}; + +struct dfs_pattern_detector * +dfs_pattern_detector_init(enum nl80211_dfs_regions region) +{ + struct dfs_pattern_detector *dpd; + dpd = kmalloc(sizeof(*dpd), GFP_KERNEL); + if (dpd == NULL) { + pr_err("allocation of dfs_pattern_detector failed\n"); + return NULL; + } + *dpd = default_dpd; + INIT_LIST_HEAD(&dpd->channel_detectors); + + if (dpd->set_domain(dpd, region)) + return dpd; + + pr_err("Could not set DFS domain to %d. ", region); + return NULL; +} +EXPORT_SYMBOL(dfs_pattern_detector_init); diff --git a/trunk/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h b/trunk/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h new file mode 100644 index 000000000000..fd0328a30995 --- /dev/null +++ b/trunk/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2012 Neratec Solutions AG + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef DFS_PATTERN_DETECTOR_H +#define DFS_PATTERN_DETECTOR_H + +#include +#include +#include + +/** + * struct pulse_event - describing pulses reported by PHY + * @ts: pulse time stamp in us + * @freq: channel frequency in MHz + * @width: pulse duration in us + * @rssi: rssi of radar event + */ +struct pulse_event { + u64 ts; + u16 freq; + u8 width; + u8 rssi; +}; + +/** + * struct radar_detector_specs - detector specs for a radar pattern type + * @type_id: pattern type, as defined by regulatory + * @width_min: minimum radar pulse width in [us] + * @width_max: maximum radar pulse width in [us] + * @pri_min: minimum pulse repetition interval in [us] (including tolerance) + * @pri_max: minimum pri in [us] (including tolerance) + * @num_pri: maximum number of different pri for this type + * @ppb: pulses per bursts for this type + * @ppb_thresh: number of pulses required to trigger detection + * @max_pri_tolerance: pulse time stamp tolerance on both sides [us] + */ +struct radar_detector_specs { + u8 type_id; + u8 width_min; + u8 width_max; + u16 pri_min; + u16 pri_max; + u8 num_pri; + u8 ppb; + u8 ppb_thresh; + u8 max_pri_tolerance; +}; + +/** + * struct dfs_pattern_detector - DFS pattern detector + * @exit(): destructor + * @set_domain(): set DFS domain, resets detector lines upon domain changes + * @add_pulse(): add radar pulse to detector, returns true on detection + * @region: active DFS region, NL80211_DFS_UNSET until set + * @num_radar_types: number of different radar types + * @last_pulse_ts: time stamp of last valid pulse in usecs + * @radar_detector_specs: array of radar detection specs + * @channel_detectors: list connecting channel_detector elements + */ +struct dfs_pattern_detector { + void (*exit)(struct dfs_pattern_detector *dpd); + bool (*set_domain)(struct dfs_pattern_detector *dpd, + enum nl80211_dfs_regions region); + bool (*add_pulse)(struct dfs_pattern_detector *dpd, + struct pulse_event *pe); + + enum nl80211_dfs_regions region; + u8 num_radar_types; + u64 last_pulse_ts; + + const struct radar_detector_specs *radar_spec; + struct list_head channel_detectors; +}; + +/** + * dfs_pattern_detector_init() - constructor for pattern detector class + * @param region: DFS domain to be used, can be NL80211_DFS_UNSET at creation + * @return instance pointer on success, NULL otherwise + */ +#if defined(CONFIG_ATH9K_DFS_CERTIFIED) +extern struct dfs_pattern_detector * +dfs_pattern_detector_init(enum nl80211_dfs_regions region); +#else +static inline struct dfs_pattern_detector * +dfs_pattern_detector_init(enum nl80211_dfs_regions region) +{ + return NULL; +} +#endif /* CONFIG_ATH9K_DFS_CERTIFIED */ + +#endif /* DFS_PATTERN_DETECTOR_H */ diff --git a/trunk/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c b/trunk/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c new file mode 100644 index 000000000000..91b8dceeadb1 --- /dev/null +++ b/trunk/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c @@ -0,0 +1,452 @@ +/* + * Copyright (c) 2012 Neratec Solutions AG + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include "ath9k.h" +#include "dfs_pattern_detector.h" +#include "dfs_pri_detector.h" +#include "dfs_debug.h" + +/** + * struct pri_sequence - sequence of pulses matching one PRI + * @head: list_head + * @pri: pulse repetition interval (PRI) in usecs + * @dur: duration of sequence in usecs + * @count: number of pulses in this sequence + * @count_falses: number of not matching pulses in this sequence + * @first_ts: time stamp of first pulse in usecs + * @last_ts: time stamp of last pulse in usecs + * @deadline_ts: deadline when this sequence becomes invalid (first_ts + dur) + */ +struct pri_sequence { + struct list_head head; + u32 pri; + u32 dur; + u32 count; + u32 count_falses; + u64 first_ts; + u64 last_ts; + u64 deadline_ts; +}; + +/** + * struct pulse_elem - elements in pulse queue + * @ts: time stamp in usecs + */ +struct pulse_elem { + struct list_head head; + u64 ts; +}; + +/** + * pde_get_multiple() - get number of multiples considering a given tolerance + * @return factor if abs(val - factor*fraction) <= tolerance, 0 otherwise + */ +static u32 pde_get_multiple(u32 val, u32 fraction, u32 tolerance) +{ + u32 remainder; + u32 factor; + u32 delta; + + if (fraction == 0) + return 0; + + delta = (val < fraction) ? (fraction - val) : (val - fraction); + + if (delta <= tolerance) + /* val and fraction are within tolerance */ + return 1; + + factor = val / fraction; + remainder = val % fraction; + if (remainder > tolerance) { + /* no exact match */ + if ((fraction - remainder) <= tolerance) + /* remainder is within tolerance */ + factor++; + else + factor = 0; + } + return factor; +} + +/** + * DOC: Singleton Pulse and Sequence Pools + * + * Instances of pri_sequence and pulse_elem are kept in singleton pools to + * reduce the number of dynamic allocations. They are shared between all + * instances and grow up to the peak number of simultaneously used objects. + * + * Memory is freed after all references to the pools are released. + */ +static u32 singleton_pool_references; +static LIST_HEAD(pulse_pool); +static LIST_HEAD(pseq_pool); +static DEFINE_SPINLOCK(pool_lock); + +static void pool_register_ref(void) +{ + spin_lock_bh(&pool_lock); + singleton_pool_references++; + DFS_POOL_STAT_INC(pool_reference); + spin_unlock_bh(&pool_lock); +} + +static void pool_deregister_ref(void) +{ + spin_lock_bh(&pool_lock); + singleton_pool_references--; + DFS_POOL_STAT_DEC(pool_reference); + if (singleton_pool_references == 0) { + /* free singleton pools with no references left */ + struct pri_sequence *ps, *ps0; + struct pulse_elem *p, *p0; + + list_for_each_entry_safe(p, p0, &pulse_pool, head) { + list_del(&p->head); + DFS_POOL_STAT_DEC(pulse_allocated); + kfree(p); + } + list_for_each_entry_safe(ps, ps0, &pseq_pool, head) { + list_del(&ps->head); + DFS_POOL_STAT_DEC(pseq_allocated); + kfree(ps); + } + } + spin_unlock_bh(&pool_lock); +} + +static void pool_put_pulse_elem(struct pulse_elem *pe) +{ + spin_lock_bh(&pool_lock); + list_add(&pe->head, &pulse_pool); + DFS_POOL_STAT_DEC(pulse_used); + spin_unlock_bh(&pool_lock); +} + +static void pool_put_pseq_elem(struct pri_sequence *pse) +{ + spin_lock_bh(&pool_lock); + list_add(&pse->head, &pseq_pool); + DFS_POOL_STAT_DEC(pseq_used); + spin_unlock_bh(&pool_lock); +} + +static struct pri_sequence *pool_get_pseq_elem(void) +{ + struct pri_sequence *pse = NULL; + spin_lock_bh(&pool_lock); + if (!list_empty(&pseq_pool)) { + pse = list_first_entry(&pseq_pool, struct pri_sequence, head); + list_del(&pse->head); + DFS_POOL_STAT_INC(pseq_used); + } + spin_unlock_bh(&pool_lock); + return pse; +} + +static struct pulse_elem *pool_get_pulse_elem(void) +{ + struct pulse_elem *pe = NULL; + spin_lock_bh(&pool_lock); + if (!list_empty(&pulse_pool)) { + pe = list_first_entry(&pulse_pool, struct pulse_elem, head); + list_del(&pe->head); + DFS_POOL_STAT_INC(pulse_used); + } + spin_unlock_bh(&pool_lock); + return pe; +} + +static struct pulse_elem *pulse_queue_get_tail(struct pri_detector *pde) +{ + struct list_head *l = &pde->pulses; + if (list_empty(l)) + return NULL; + return list_entry(l->prev, struct pulse_elem, head); +} + +static bool pulse_queue_dequeue(struct pri_detector *pde) +{ + struct pulse_elem *p = pulse_queue_get_tail(pde); + if (p != NULL) { + list_del_init(&p->head); + pde->count--; + /* give it back to pool */ + pool_put_pulse_elem(p); + } + return (pde->count > 0); +} + +/* remove pulses older than window */ +static void pulse_queue_check_window(struct pri_detector *pde) +{ + u64 min_valid_ts; + struct pulse_elem *p; + + /* there is no delta time with less than 2 pulses */ + if (pde->count < 2) + return; + + if (pde->last_ts <= pde->window_size) + return; + + min_valid_ts = pde->last_ts - pde->window_size; + while ((p = pulse_queue_get_tail(pde)) != NULL) { + if (p->ts >= min_valid_ts) + return; + pulse_queue_dequeue(pde); + } +} + +static bool pulse_queue_enqueue(struct pri_detector *pde, u64 ts) +{ + struct pulse_elem *p = pool_get_pulse_elem(); + if (p == NULL) { + p = kmalloc(sizeof(*p), GFP_KERNEL); + if (p == NULL) { + DFS_POOL_STAT_INC(pulse_alloc_error); + return false; + } + DFS_POOL_STAT_INC(pulse_allocated); + DFS_POOL_STAT_INC(pulse_used); + } + INIT_LIST_HEAD(&p->head); + p->ts = ts; + list_add(&p->head, &pde->pulses); + pde->count++; + pde->last_ts = ts; + pulse_queue_check_window(pde); + if (pde->count >= pde->max_count) + pulse_queue_dequeue(pde); + return true; +} + +static bool pseq_handler_create_sequences(struct pri_detector *pde, + u64 ts, u32 min_count) +{ + struct pulse_elem *p; + list_for_each_entry(p, &pde->pulses, head) { + struct pri_sequence ps, *new_ps; + struct pulse_elem *p2; + u32 tmp_false_count; + u64 min_valid_ts; + u32 delta_ts = ts - p->ts; + + if (delta_ts < pde->rs->pri_min) + /* ignore too small pri */ + continue; + + if (delta_ts > pde->rs->pri_max) + /* stop on too large pri (sorted list) */ + break; + + /* build a new sequence with new potential pri */ + ps.count = 2; + ps.count_falses = 0; + ps.first_ts = p->ts; + ps.last_ts = ts; + ps.pri = ts - p->ts; + ps.dur = ps.pri * (pde->rs->ppb - 1) + + 2 * pde->rs->max_pri_tolerance; + + p2 = p; + tmp_false_count = 0; + min_valid_ts = ts - ps.dur; + /* check which past pulses are candidates for new sequence */ + list_for_each_entry_continue(p2, &pde->pulses, head) { + u32 factor; + if (p2->ts < min_valid_ts) + /* stop on crossing window border */ + break; + /* check if pulse match (multi)PRI */ + factor = pde_get_multiple(ps.last_ts - p2->ts, ps.pri, + pde->rs->max_pri_tolerance); + if (factor > 0) { + ps.count++; + ps.first_ts = p2->ts; + /* + * on match, add the intermediate falses + * and reset counter + */ + ps.count_falses += tmp_false_count; + tmp_false_count = 0; + } else { + /* this is a potential false one */ + tmp_false_count++; + } + } + if (ps.count < min_count) + /* did not reach minimum count, drop sequence */ + continue; + + /* this is a valid one, add it */ + ps.deadline_ts = ps.first_ts + ps.dur; + new_ps = pool_get_pseq_elem(); + if (new_ps == NULL) { + new_ps = kmalloc(sizeof(*new_ps), GFP_KERNEL); + if (new_ps == NULL) { + DFS_POOL_STAT_INC(pseq_alloc_error); + return false; + } + DFS_POOL_STAT_INC(pseq_allocated); + DFS_POOL_STAT_INC(pseq_used); + } + memcpy(new_ps, &ps, sizeof(ps)); + INIT_LIST_HEAD(&new_ps->head); + list_add(&new_ps->head, &pde->sequences); + } + return true; +} + +/* check new ts and add to all matching existing sequences */ +static u32 +pseq_handler_add_to_existing_seqs(struct pri_detector *pde, u64 ts) +{ + u32 max_count = 0; + struct pri_sequence *ps, *ps2; + list_for_each_entry_safe(ps, ps2, &pde->sequences, head) { + u32 delta_ts; + u32 factor; + + /* first ensure that sequence is within window */ + if (ts > ps->deadline_ts) { + list_del_init(&ps->head); + pool_put_pseq_elem(ps); + continue; + } + + delta_ts = ts - ps->last_ts; + factor = pde_get_multiple(delta_ts, ps->pri, + pde->rs->max_pri_tolerance); + if (factor > 0) { + ps->last_ts = ts; + ps->count++; + + if (max_count < ps->count) + max_count = ps->count; + } else { + ps->count_falses++; + } + } + return max_count; +} + +static struct pri_sequence * +pseq_handler_check_detection(struct pri_detector *pde) +{ + struct pri_sequence *ps; + + if (list_empty(&pde->sequences)) + return NULL; + + list_for_each_entry(ps, &pde->sequences, head) { + /* + * we assume to have enough matching confidence if we + * 1) have enough pulses + * 2) have more matching than false pulses + */ + if ((ps->count >= pde->rs->ppb_thresh) && + (ps->count * pde->rs->num_pri >= ps->count_falses)) + return ps; + } + return NULL; +} + + +/* free pulse queue and sequences list and give objects back to pools */ +static void pri_detector_reset(struct pri_detector *pde, u64 ts) +{ + struct pri_sequence *ps, *ps0; + struct pulse_elem *p, *p0; + list_for_each_entry_safe(ps, ps0, &pde->sequences, head) { + list_del_init(&ps->head); + pool_put_pseq_elem(ps); + } + list_for_each_entry_safe(p, p0, &pde->pulses, head) { + list_del_init(&p->head); + pool_put_pulse_elem(p); + } + pde->count = 0; + pde->last_ts = ts; +} + +static void pri_detector_exit(struct pri_detector *de) +{ + pri_detector_reset(de, 0); + pool_deregister_ref(); + kfree(de); +} + +static bool pri_detector_add_pulse(struct pri_detector *de, + struct pulse_event *event) +{ + u32 max_updated_seq; + struct pri_sequence *ps; + u64 ts = event->ts; + const struct radar_detector_specs *rs = de->rs; + + /* ignore pulses not within width range */ + if ((rs->width_min > event->width) || (rs->width_max < event->width)) + return false; + + if ((ts - de->last_ts) < rs->max_pri_tolerance) + /* if delta to last pulse is too short, don't use this pulse */ + return false; + de->last_ts = ts; + + max_updated_seq = pseq_handler_add_to_existing_seqs(de, ts); + + if (!pseq_handler_create_sequences(de, ts, max_updated_seq)) { + pr_err("failed to create pulse sequences\n"); + pri_detector_reset(de, ts); + return false; + } + + ps = pseq_handler_check_detection(de); + + if (ps != NULL) { + pr_info("DFS: radar found: pri=%d, count=%d, count_false=%d\n", + ps->pri, ps->count, ps->count_falses); + pri_detector_reset(de, ts); + return true; + } + pulse_queue_enqueue(de, ts); + return false; +} + +struct pri_detector * +pri_detector_init(const struct radar_detector_specs *rs) +{ + struct pri_detector *de; + de = kzalloc(sizeof(*de), GFP_KERNEL); + if (de == NULL) + return NULL; + de->exit = pri_detector_exit; + de->add_pulse = pri_detector_add_pulse; + de->reset = pri_detector_reset; + + INIT_LIST_HEAD(&de->sequences); + INIT_LIST_HEAD(&de->pulses); + de->window_size = rs->pri_max * rs->ppb * rs->num_pri; + de->max_count = rs->ppb * 2; + de->rs = rs; + + pool_register_ref(); + return de; +} diff --git a/trunk/drivers/net/wireless/ath/ath9k/dfs_pri_detector.h b/trunk/drivers/net/wireless/ath/ath9k/dfs_pri_detector.h new file mode 100644 index 000000000000..81cde9f28e44 --- /dev/null +++ b/trunk/drivers/net/wireless/ath/ath9k/dfs_pri_detector.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2012 Neratec Solutions AG + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef DFS_PRI_DETECTOR_H +#define DFS_PRI_DETECTOR_H + +#include + +/** + * struct pri_detector - PRI detector element for a dedicated radar type + * @exit(): destructor + * @add_pulse(): add pulse event, returns true if pattern was detected + * @reset(): clear states and reset to given time stamp + * @rs: detector specs for this detector element + * @last_ts: last pulse time stamp considered for this element in usecs + * @sequences: list_head holding potential pulse sequences + * @pulses: list connecting pulse_elem objects + * @count: number of pulses in queue + * @max_count: maximum number of pulses to be queued + * @window_size: window size back from newest pulse time stamp in usecs + */ +struct pri_detector { + void (*exit) (struct pri_detector *de); + bool (*add_pulse)(struct pri_detector *de, struct pulse_event *e); + void (*reset) (struct pri_detector *de, u64 ts); + +/* private: internal use only */ + const struct radar_detector_specs *rs; + u64 last_ts; + struct list_head sequences; + struct list_head pulses; + u32 count; + u32 max_count; + u32 window_size; +}; + +struct pri_detector *pri_detector_init(const struct radar_detector_specs *rs); + +#endif /* DFS_PRI_DETECTOR_H */ diff --git a/trunk/drivers/net/wireless/ath/ath9k/eeprom.c b/trunk/drivers/net/wireless/ath/ath9k/eeprom.c index c43523233319..0512397a293c 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/trunk/drivers/net/wireless/ath/ath9k/eeprom.c @@ -16,14 +16,6 @@ #include "hw.h" -static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz) -{ - if (fbin == AR5416_BCHAN_UNUSED) - return fbin; - - return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); -} - void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val) { REG_WRITE(ah, reg, val); @@ -290,6 +282,34 @@ u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower, return twiceMaxEdgePower; } +u16 ath9k_hw_get_scaled_power(struct ath_hw *ah, u16 power_limit, + u8 antenna_reduction) +{ + u16 reduction = antenna_reduction; + + /* + * Reduce scaled Power by number of chains active + * to get the per chain tx power level. + */ + switch (ar5416_get_ntxchains(ah->txchainmask)) { + case 1: + break; + case 2: + reduction += POWER_CORRECTION_FOR_TWO_CHAIN; + break; + case 3: + reduction += POWER_CORRECTION_FOR_THREE_CHAIN; + break; + } + + if (power_limit > reduction) + power_limit -= reduction; + else + power_limit = 0; + + return power_limit; +} + void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); @@ -299,10 +319,10 @@ void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah) case 1: break; case 2: - regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN; + regulatory->max_power_level += POWER_CORRECTION_FOR_TWO_CHAIN; break; case 3: - regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; + regulatory->max_power_level += POWER_CORRECTION_FOR_THREE_CHAIN; break; default: ath_dbg(common, EEPROM, "Invalid chainmask configuration\n"); diff --git a/trunk/drivers/net/wireless/ath/ath9k/eeprom.h b/trunk/drivers/net/wireless/ath/ath9k/eeprom.h index 5ff7ab965120..33acb920ed3f 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/trunk/drivers/net/wireless/ath/ath9k/eeprom.h @@ -79,8 +79,8 @@ #define SUB_NUM_CTL_MODES_AT_5G_40 2 #define SUB_NUM_CTL_MODES_AT_2G_40 3 -#define INCREASE_MAXPOW_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ -#define INCREASE_MAXPOW_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ +#define POWER_CORRECTION_FOR_TWO_CHAIN 6 /* 10*log10(2)*2 */ +#define POWER_CORRECTION_FOR_THREE_CHAIN 10 /* 10*log10(3)*2 */ /* * For AR9285 and later chipsets, the following bits are not being programmed @@ -686,6 +686,8 @@ void ath9k_hw_get_target_powers(struct ath_hw *ah, u16 numRates, bool isHt40Target); u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower, bool is2GHz, int num_band_edges); +u16 ath9k_hw_get_scaled_power(struct ath_hw *ah, u16 power_limit, + u8 antenna_reduction); void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah); int ath9k_hw_eeprom_init(struct ath_hw *ah); @@ -697,6 +699,14 @@ void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah, u16 *pPdGainBoundaries, u8 *pPDADCValues, u16 numXpdGains); +static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz) +{ + if (fbin == AR5416_BCHAN_UNUSED) + return fbin; + + return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); +} + #define ar5416_get_ntxchains(_txchainmask) \ (((_txchainmask >> 2) & 1) + \ ((_txchainmask >> 1) & 1) + (_txchainmask & 1)) diff --git a/trunk/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/trunk/drivers/net/wireless/ath/ath9k/eeprom_9287.c index b34e8b2990b1..aa614767adff 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/trunk/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -564,9 +564,6 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah, (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \ ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL)) -#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 -#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 - u16 twiceMaxEdgePower; int i; struct cal_ctl_data_ar9287 *rep; @@ -591,29 +588,8 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah, tx_chainmask = ah->txchainmask; ath9k_hw_get_channel_centers(ah, chan, ¢ers); - scaledPower = powerLimit - antenna_reduction; - - /* - * Reduce scaled Power by number of chains active - * to get the per chain tx power level. - */ - switch (ar5416_get_ntxchains(tx_chainmask)) { - case 1: - break; - case 2: - if (scaledPower > REDUCE_SCALED_POWER_BY_TWO_CHAIN) - scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; - else - scaledPower = 0; - break; - case 3: - if (scaledPower > REDUCE_SCALED_POWER_BY_THREE_CHAIN) - scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; - else - scaledPower = 0; - break; - } - scaledPower = max((u16)0, scaledPower); + scaledPower = ath9k_hw_get_scaled_power(ah, powerLimit, + antenna_reduction); /* * Get TX power from EEPROM. @@ -786,8 +762,6 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah, #undef CMP_CTL #undef CMP_NO_CTL -#undef REDUCE_SCALED_POWER_BY_TWO_CHAIN -#undef REDUCE_SCALED_POWER_BY_THREE_CHAIN } static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, diff --git a/trunk/drivers/net/wireless/ath/ath9k/eeprom_def.c b/trunk/drivers/net/wireless/ath/ath9k/eeprom_def.c index 619b95d764ff..b5fba8b18b8b 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/trunk/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -991,9 +991,6 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, u16 antenna_reduction, u16 powerLimit) { -#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ -#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 9 /* 10*log10(3)*2 */ - struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; u16 twiceMaxEdgePower; int i; @@ -1027,24 +1024,8 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, ath9k_hw_get_channel_centers(ah, chan, ¢ers); - scaledPower = powerLimit - antenna_reduction; - - switch (ar5416_get_ntxchains(tx_chainmask)) { - case 1: - break; - case 2: - if (scaledPower > REDUCE_SCALED_POWER_BY_TWO_CHAIN) - scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; - else - scaledPower = 0; - break; - case 3: - if (scaledPower > REDUCE_SCALED_POWER_BY_THREE_CHAIN) - scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; - else - scaledPower = 0; - break; - } + scaledPower = ath9k_hw_get_scaled_power(ah, powerLimit, + antenna_reduction); if (IS_CHAN_2GHZ(chan)) { numCtlModes = ARRAY_SIZE(ctlModesFor11g) - @@ -1263,20 +1244,7 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, regulatory->max_power_level = ratesArray[i]; } - switch(ar5416_get_ntxchains(ah->txchainmask)) { - case 1: - break; - case 2: - regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN; - break; - case 3: - regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; - break; - default: - ath_dbg(ath9k_hw_common(ah), EEPROM, - "Invalid chainmask configuration\n"); - break; - } + ath9k_hw_update_regulatory_maxpower(ah); if (test) return; diff --git a/trunk/drivers/net/wireless/ath/ath9k/gpio.c b/trunk/drivers/net/wireless/ath/ath9k/gpio.c index fbe23de1297f..281a9af0f1b6 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/gpio.c +++ b/trunk/drivers/net/wireless/ath/ath9k/gpio.c @@ -41,6 +41,9 @@ void ath_init_leds(struct ath_softc *sc) { int ret; + if (AR_SREV_9100(sc->sc_ah)) + return; + if (sc->sc_ah->led_pin < 0) { if (AR_SREV_9287(sc->sc_ah)) sc->sc_ah->led_pin = ATH_LED_PIN_9287; @@ -362,7 +365,7 @@ void ath9k_stop_btcoex(struct ath_softc *sc) ath9k_hw_btcoex_disable(ah); if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) ath9k_btcoex_timer_pause(sc); - if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_MCI) + if (AR_SREV_9462(ah)) ath_mci_flush_profile(&sc->btcoex.mci); } } @@ -373,7 +376,7 @@ void ath9k_deinit_btcoex(struct ath_softc *sc) ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_3WIRE) ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer); - if (ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_MCI) + if (AR_SREV_9462(sc->sc_ah)) ath_mci_cleanup(sc); } @@ -399,17 +402,16 @@ int ath9k_init_btcoex(struct ath_softc *sc) txq = sc->tx.txq_map[WME_AC_BE]; ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum); sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; - break; - case ATH_BTCOEX_CFG_MCI: - sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; - sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE; - INIT_LIST_HEAD(&sc->btcoex.mci.info); + if (AR_SREV_9462(ah)) { + sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE; + INIT_LIST_HEAD(&sc->btcoex.mci.info); - r = ath_mci_setup(sc); - if (r) - return r; + r = ath_mci_setup(sc); + if (r) + return r; - ath9k_hw_btcoex_init_mci(ah); + ath9k_hw_btcoex_init_mci(ah); + } break; default: diff --git a/trunk/drivers/net/wireless/ath/ath9k/hif_usb.c b/trunk/drivers/net/wireless/ath/ath9k/hif_usb.c index 424aabb2c730..aa327adcc3d8 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/trunk/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -53,6 +53,8 @@ static struct usb_device_id ath9k_hif_usb_ids[] = { .driver_info = AR9280_USB }, /* SMC Networks */ { USB_DEVICE(0x0411, 0x017f), .driver_info = AR9280_USB }, /* Sony UWA-BR100 */ + { USB_DEVICE(0x04da, 0x3904), + .driver_info = AR9280_USB }, { USB_DEVICE(0x0cf3, 0x20ff), .driver_info = STORAGE_DEVICE }, @@ -1356,6 +1358,7 @@ static struct usb_driver ath9k_hif_usb_driver = { #endif .id_table = ath9k_hif_usb_ids, .soft_unbind = 1, + .disable_hub_initiated_lpm = 1, }; int ath9k_hif_usb_init(void) diff --git a/trunk/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/trunk/drivers/net/wireless/ath/ath9k/htc_drv_init.c index de5ee15ee639..25213d521bc2 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/trunk/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -14,6 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "htc.h" MODULE_AUTHOR("Atheros Communications"); @@ -711,7 +713,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; - hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN | + WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; hw->queues = 4; hw->channel_change_time = 5000; @@ -966,9 +969,7 @@ int ath9k_htc_resume(struct htc_target *htc_handle) static int __init ath9k_htc_init(void) { if (ath9k_hif_usb_init() < 0) { - printk(KERN_ERR - "ath9k_htc: No USB devices found," - " driver not installed.\n"); + pr_err("No USB devices found, driver not installed\n"); return -ENODEV; } @@ -979,6 +980,6 @@ module_init(ath9k_htc_init); static void __exit ath9k_htc_exit(void) { ath9k_hif_usb_exit(); - printk(KERN_INFO "ath9k_htc: Driver unloaded\n"); + pr_info("Driver unloaded\n"); } module_exit(ath9k_htc_exit); diff --git a/trunk/drivers/net/wireless/ath/ath9k/htc_hst.c b/trunk/drivers/net/wireless/ath/ath9k/htc_hst.c index c25226a32ddc..4a9570dfba72 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/trunk/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -14,6 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "htc.h" static int htc_issue_send(struct htc_target *target, struct sk_buff* skb, @@ -461,7 +463,7 @@ int ath9k_htc_hw_init(struct htc_target *target, char *product, u32 drv_info) { if (ath9k_htc_probe_device(target, dev, devid, product, drv_info)) { - printk(KERN_ERR "Failed to initialize the device\n"); + pr_err("Failed to initialize the device\n"); return -ENODEV; } diff --git a/trunk/drivers/net/wireless/ath/ath9k/hw.c b/trunk/drivers/net/wireless/ath/ath9k/hw.c index fa84e37bf091..f84477c5ebb1 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/hw.c +++ b/trunk/drivers/net/wireless/ath/ath9k/hw.c @@ -24,6 +24,8 @@ #include "rc.h" #include "ar9003_mac.h" #include "ar9003_mci.h" +#include "debug.h" +#include "ath9k.h" static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type); @@ -83,6 +85,53 @@ static void ath9k_hw_ani_cache_ini_regs(struct ath_hw *ah) /* Helper Functions */ /********************/ +#ifdef CONFIG_ATH9K_DEBUGFS + +void ath9k_debug_sync_cause(struct ath_common *common, u32 sync_cause) +{ + struct ath_softc *sc = common->priv; + if (sync_cause) + sc->debug.stats.istats.sync_cause_all++; + if (sync_cause & AR_INTR_SYNC_RTC_IRQ) + sc->debug.stats.istats.sync_rtc_irq++; + if (sync_cause & AR_INTR_SYNC_MAC_IRQ) + sc->debug.stats.istats.sync_mac_irq++; + if (sync_cause & AR_INTR_SYNC_EEPROM_ILLEGAL_ACCESS) + sc->debug.stats.istats.eeprom_illegal_access++; + if (sync_cause & AR_INTR_SYNC_APB_TIMEOUT) + sc->debug.stats.istats.apb_timeout++; + if (sync_cause & AR_INTR_SYNC_PCI_MODE_CONFLICT) + sc->debug.stats.istats.pci_mode_conflict++; + if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) + sc->debug.stats.istats.host1_fatal++; + if (sync_cause & AR_INTR_SYNC_HOST1_PERR) + sc->debug.stats.istats.host1_perr++; + if (sync_cause & AR_INTR_SYNC_TRCV_FIFO_PERR) + sc->debug.stats.istats.trcv_fifo_perr++; + if (sync_cause & AR_INTR_SYNC_RADM_CPL_EP) + sc->debug.stats.istats.radm_cpl_ep++; + if (sync_cause & AR_INTR_SYNC_RADM_CPL_DLLP_ABORT) + sc->debug.stats.istats.radm_cpl_dllp_abort++; + if (sync_cause & AR_INTR_SYNC_RADM_CPL_TLP_ABORT) + sc->debug.stats.istats.radm_cpl_tlp_abort++; + if (sync_cause & AR_INTR_SYNC_RADM_CPL_ECRC_ERR) + sc->debug.stats.istats.radm_cpl_ecrc_err++; + if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) + sc->debug.stats.istats.radm_cpl_timeout++; + if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) + sc->debug.stats.istats.local_timeout++; + if (sync_cause & AR_INTR_SYNC_PM_ACCESS) + sc->debug.stats.istats.pm_access++; + if (sync_cause & AR_INTR_SYNC_MAC_AWAKE) + sc->debug.stats.istats.mac_awake++; + if (sync_cause & AR_INTR_SYNC_MAC_ASLEEP) + sc->debug.stats.istats.mac_asleep++; + if (sync_cause & AR_INTR_SYNC_MAC_SLEEP_ACCESS) + sc->debug.stats.istats.mac_sleep_access++; +} +#endif + + static void ath9k_hw_set_clockrate(struct ath_hw *ah) { struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; @@ -142,6 +191,22 @@ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout) } EXPORT_SYMBOL(ath9k_hw_wait); +void ath9k_hw_synth_delay(struct ath_hw *ah, struct ath9k_channel *chan, + int hw_delay) +{ + if (IS_CHAN_B(chan)) + hw_delay = (4 * hw_delay) / 22; + else + hw_delay /= 10; + + if (IS_CHAN_HALF_RATE(chan)) + hw_delay *= 2; + else if (IS_CHAN_QUARTER_RATE(chan)) + hw_delay *= 4; + + udelay(hw_delay + BASE_ACTIVATE_DELAY); +} + void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array, int column, unsigned int *writecnt) { @@ -388,8 +453,8 @@ static void ath9k_hw_init_config(struct ath_hw *ah) { int i; - ah->config.dma_beacon_response_time = 2; - ah->config.sw_beacon_response_time = 10; + ah->config.dma_beacon_response_time = 1; + ah->config.sw_beacon_response_time = 6; ah->config.additional_swba_backoff = 0; ah->config.ack_6mb = 0x0; ah->config.cwm_ignore_extcca = 0; @@ -445,7 +510,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) AR_STA_ID1_MCAST_KSRCH; if (AR_SREV_9100(ah)) ah->sta_id1_defaults |= AR_STA_ID1_AR9100_BA_FIX; - ah->enable_32kHz_clock = DONT_USE_32KHZ; ah->slottime = ATH9K_SLOT_TIME_9; ah->globaltxtimeout = (u32) -1; ah->power_mode = ATH9K_PM_UNDEFINED; @@ -972,7 +1036,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_conf *conf = &common->hw->conf; const struct ath9k_channel *chan = ah->curchan; - int acktimeout, ctstimeout; + int acktimeout, ctstimeout, ack_offset = 0; int slottime; int sifstime; int rx_lat = 0, tx_lat = 0, eifs = 0; @@ -993,6 +1057,11 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) rx_lat = 37; tx_lat = 54; + if (IS_CHAN_5GHZ(chan)) + sifstime = 16; + else + sifstime = 10; + if (IS_CHAN_HALF_RATE(chan)) { eifs = 175; rx_lat *= 2; @@ -1000,8 +1069,9 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) if (IS_CHAN_A_FAST_CLOCK(ah, chan)) tx_lat += 11; + sifstime *= 2; + ack_offset = 16; slottime = 13; - sifstime = 32; } else if (IS_CHAN_QUARTER_RATE(chan)) { eifs = 340; rx_lat = (rx_lat * 4) - 1; @@ -1009,8 +1079,9 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) if (IS_CHAN_A_FAST_CLOCK(ah, chan)) tx_lat += 22; + sifstime *= 4; + ack_offset = 32; slottime = 21; - sifstime = 64; } else { if (AR_SREV_9287(ah) && AR_SREV_9287_13_OR_LATER(ah)) { eifs = AR_D_GBL_IFS_EIFS_ASYNC_FIFO; @@ -1024,14 +1095,10 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) tx_lat = MS(reg, AR_USEC_TX_LAT); slottime = ah->slottime; - if (IS_CHAN_5GHZ(chan)) - sifstime = 16; - else - sifstime = 10; } /* As defined by IEEE 802.11-2007 17.3.8.6 */ - acktimeout = slottime + sifstime + 3 * ah->coverage_class; + acktimeout = slottime + sifstime + 3 * ah->coverage_class + ack_offset; ctstimeout = acktimeout; /* @@ -1041,7 +1108,8 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) * BA frames in some implementations, but it has been found to fix ACK * timeout issues in other cases as well. */ - if (conf->channel && conf->channel->band == IEEE80211_BAND_2GHZ) { + if (conf->channel && conf->channel->band == IEEE80211_BAND_2GHZ && + !IS_CHAN_HALF_RATE(chan) && !IS_CHAN_QUARTER_RATE(chan)) { acktimeout += 64 - sifstime - ah->slottime; ctstimeout += 48 - sifstime - ah->slottime; } @@ -1491,11 +1559,84 @@ static void ath9k_hw_apply_gpio_override(struct ath_hw *ah) } } +static bool ath9k_hw_check_dcs(u32 dma_dbg, u32 num_dcu_states, + int *hang_state, int *hang_pos) +{ + static u32 dcu_chain_state[] = {5, 6, 9}; /* DCU chain stuck states */ + u32 chain_state, dcs_pos, i; + + for (dcs_pos = 0; dcs_pos < num_dcu_states; dcs_pos++) { + chain_state = (dma_dbg >> (5 * dcs_pos)) & 0x1f; + for (i = 0; i < 3; i++) { + if (chain_state == dcu_chain_state[i]) { + *hang_state = chain_state; + *hang_pos = dcs_pos; + return true; + } + } + } + return false; +} + +#define DCU_COMPLETE_STATE 1 +#define DCU_COMPLETE_STATE_MASK 0x3 +#define NUM_STATUS_READS 50 +static bool ath9k_hw_detect_mac_hang(struct ath_hw *ah) +{ + u32 chain_state, comp_state, dcs_reg = AR_DMADBG_4; + u32 i, hang_pos, hang_state, num_state = 6; + + comp_state = REG_READ(ah, AR_DMADBG_6); + + if ((comp_state & DCU_COMPLETE_STATE_MASK) != DCU_COMPLETE_STATE) { + ath_dbg(ath9k_hw_common(ah), RESET, + "MAC Hang signature not found at DCU complete\n"); + return false; + } + + chain_state = REG_READ(ah, dcs_reg); + if (ath9k_hw_check_dcs(chain_state, num_state, &hang_state, &hang_pos)) + goto hang_check_iter; + + dcs_reg = AR_DMADBG_5; + num_state = 4; + chain_state = REG_READ(ah, dcs_reg); + if (ath9k_hw_check_dcs(chain_state, num_state, &hang_state, &hang_pos)) + goto hang_check_iter; + + ath_dbg(ath9k_hw_common(ah), RESET, + "MAC Hang signature 1 not found\n"); + return false; + +hang_check_iter: + ath_dbg(ath9k_hw_common(ah), RESET, + "DCU registers: chain %08x complete %08x Hang: state %d pos %d\n", + chain_state, comp_state, hang_state, hang_pos); + + for (i = 0; i < NUM_STATUS_READS; i++) { + chain_state = REG_READ(ah, dcs_reg); + chain_state = (chain_state >> (5 * hang_pos)) & 0x1f; + comp_state = REG_READ(ah, AR_DMADBG_6); + + if (((comp_state & DCU_COMPLETE_STATE_MASK) != + DCU_COMPLETE_STATE) || + (chain_state != hang_state)) + return false; + } + + ath_dbg(ath9k_hw_common(ah), RESET, "MAC Hang signature 1 found\n"); + + return true; +} + bool ath9k_hw_check_alive(struct ath_hw *ah) { int count = 50; u32 reg; + if (AR_SREV_9300(ah)) + return !ath9k_hw_detect_mac_hang(ah); + if (AR_SREV_9285_12_OR_LATER(ah)) return true; @@ -1546,6 +1687,10 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan) if (chan->channel == ah->curchan->channel) goto fail; + if ((ah->curchan->channelFlags | chan->channelFlags) & + (CHANNEL_HALF | CHANNEL_QUARTER)) + goto fail; + if ((chan->channelFlags & CHANNEL_ALL) != (ah->curchan->channelFlags & CHANNEL_ALL)) goto fail; diff --git a/trunk/drivers/net/wireless/ath/ath9k/hw.h b/trunk/drivers/net/wireless/ath/ath9k/hw.h index e88f182ff45c..828b9bbc456d 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/hw.h +++ b/trunk/drivers/net/wireless/ath/ath9k/hw.h @@ -708,7 +708,6 @@ struct ath_hw { struct ar5416Stats stats; struct ath9k_tx_queue_info txq[ATH9K_NUM_TX_QUEUES]; - int16_t curchan_rad_index; enum ath9k_int imask; u32 imrs2_reg; u32 txok_interrupt_mask; @@ -762,11 +761,6 @@ struct ath_hw { u32 sta_id1_defaults; u32 misc_mode; - enum { - AUTO_32KHZ, - USE_32KHZ, - DONT_USE_32KHZ, - } enable_32kHz_clock; /* Private to hardware code */ struct ath_hw_private_ops private_ops; @@ -783,7 +777,6 @@ struct ath_hw { u32 *analogBank7Data; u32 *bank6Temp; - u8 txpower_limit; int coverage_class; u32 slottime; u32 globaltxtimeout; @@ -848,7 +841,6 @@ struct ath_hw { struct ath_gen_timer_table hw_gen_timers; struct ar9003_txs *ts_ring; - void *ts_start; u32 ts_paddr_start; u32 ts_paddr_end; u16 ts_tail; @@ -915,7 +907,6 @@ static inline u8 get_streams(int mask) } /* Initialization, Detach, Reset */ -const char *ath9k_hw_probe(u16 vendorid, u16 devid); void ath9k_hw_deinit(struct ath_hw *ah); int ath9k_hw_init(struct ath_hw *ah); int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, @@ -932,6 +923,8 @@ void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val); void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna); /* General Operation */ +void ath9k_hw_synth_delay(struct ath_hw *ah, struct ath9k_channel *chan, + int hw_delay); bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout); void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array, int column, unsigned int *writecnt); @@ -965,6 +958,13 @@ bool ath9k_hw_check_alive(struct ath_hw *ah); bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode); +#ifdef CONFIG_ATH9K_DEBUGFS +void ath9k_debug_sync_cause(struct ath_common *common, u32 sync_cause); +#else +static inline void ath9k_debug_sync_cause(struct ath_common *common, + u32 sync_cause) {} +#endif + /* Generic hw timer primitives */ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, void (*trigger)(void *), @@ -1012,7 +1012,6 @@ int ar9003_paprd_create_curve(struct ath_hw *ah, int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain); int ar9003_paprd_init_table(struct ath_hw *ah); bool ar9003_paprd_is_done(struct ath_hw *ah); -void ar9003_hw_set_paprd_txdesc(struct ath_hw *ah, void *ds, u8 chains); /* Hardware family op attach helpers */ void ar5008_hw_attach_phy_ops(struct ath_hw *ah); diff --git a/trunk/drivers/net/wireless/ath/ath9k/init.c b/trunk/drivers/net/wireless/ath/ath9k/init.c index cb006458fc4b..dee9e092449a 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/init.c +++ b/trunk/drivers/net/wireless/ath/ath9k/init.c @@ -14,6 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -519,6 +521,8 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, atomic_set(&ah->intr_ref_cnt, -1); sc->sc_ah = ah; + sc->dfs_detector = dfs_pattern_detector_init(NL80211_DFS_UNSET); + if (!pdata) { ah->ah_flags |= AH_USE_EEPROM; sc->sc_ah->led_pin = -1; @@ -642,6 +646,24 @@ void ath9k_reload_chainmask_settings(struct ath_softc *sc) setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); } +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_P2P_GO) }, +}; + +static const struct ieee80211_iface_combination if_comb = { + .limits = if_limits, + .n_limits = ARRAY_SIZE(if_limits), + .max_interfaces = 2048, + .num_different_channels = 1, +}; void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) { @@ -671,11 +693,15 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MESH_POINT); + hw->wiphy->iface_combinations = &if_comb; + hw->wiphy->n_iface_combinations = 1; + if (AR_SREV_5416(sc->sc_ah)) hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; + hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; hw->queues = 4; hw->max_rates = 4; @@ -779,6 +805,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, goto error_world; } + setup_timer(&sc->rx_poll_timer, ath_rx_poll, (unsigned long)sc); sc->last_rssi = ATH_RSSI_DUMMY_MARKER; ath_init_leds(sc); @@ -821,6 +848,8 @@ static void ath9k_deinit_softc(struct ath_softc *sc) ath_tx_cleanupq(sc, &sc->tx.txq[i]); ath9k_hw_deinit(sc->sc_ah); + if (sc->dfs_detector != NULL) + sc->dfs_detector->exit(sc->dfs_detector); kfree(sc->sc_ah); sc->sc_ah = NULL; @@ -866,17 +895,14 @@ static int __init ath9k_init(void) /* Register rate control algorithm */ error = ath_rate_control_register(); if (error != 0) { - printk(KERN_ERR - "ath9k: Unable to register rate control " - "algorithm: %d\n", - error); + pr_err("Unable to register rate control algorithm: %d\n", + error); goto err_out; } error = ath_pci_init(); if (error < 0) { - printk(KERN_ERR - "ath9k: No PCI devices found, driver not installed.\n"); + pr_err("No PCI devices found, driver not installed\n"); error = -ENODEV; goto err_rate_unregister; } @@ -905,6 +931,6 @@ static void __exit ath9k_exit(void) ath_ahb_exit(); ath_pci_exit(); ath_rate_control_unregister(); - printk(KERN_INFO "%s: Driver unloaded\n", dev_info); + pr_info("%s: Driver unloaded\n", dev_info); } module_exit(ath9k_exit); diff --git a/trunk/drivers/net/wireless/ath/ath9k/mac.c b/trunk/drivers/net/wireless/ath/ath9k/mac.c index f7bd2532269c..04ef775ccee1 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/mac.c +++ b/trunk/drivers/net/wireless/ath/ath9k/mac.c @@ -133,8 +133,16 @@ EXPORT_SYMBOL(ath9k_hw_updatetxtriglevel); void ath9k_hw_abort_tx_dma(struct ath_hw *ah) { + int maxdelay = 1000; int i, q; + if (ah->curchan) { + if (IS_CHAN_HALF_RATE(ah->curchan)) + maxdelay *= 2; + else if (IS_CHAN_QUARTER_RATE(ah->curchan)) + maxdelay *= 4; + } + REG_WRITE(ah, AR_Q_TXD, AR_Q_TXD_M); REG_SET_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF); @@ -142,7 +150,7 @@ void ath9k_hw_abort_tx_dma(struct ath_hw *ah) REG_SET_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF); for (q = 0; q < AR_NUM_QCU; q++) { - for (i = 0; i < 1000; i++) { + for (i = 0; i < maxdelay; i++) { if (i) udelay(5); diff --git a/trunk/drivers/net/wireless/ath/ath9k/main.c b/trunk/drivers/net/wireless/ath/ath9k/main.c index 798ea57252b4..dfa78e8b6470 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/main.c +++ b/trunk/drivers/net/wireless/ath/ath9k/main.c @@ -113,21 +113,25 @@ void ath9k_ps_restore(struct ath_softc *sc) struct ath_common *common = ath9k_hw_common(sc->sc_ah); enum ath9k_power_mode mode; unsigned long flags; + bool reset; spin_lock_irqsave(&sc->sc_pm_lock, flags); if (--sc->ps_usecount != 0) goto unlock; - if (sc->ps_idle && (sc->ps_flags & PS_WAIT_FOR_TX_ACK)) + if (sc->ps_idle) { + ath9k_hw_setrxabort(sc->sc_ah, 1); + ath9k_hw_stopdmarecv(sc->sc_ah, &reset); mode = ATH9K_PM_FULL_SLEEP; - else if (sc->ps_enabled && - !(sc->ps_flags & (PS_WAIT_FOR_BEACON | - PS_WAIT_FOR_CAB | - PS_WAIT_FOR_PSPOLL_DATA | - PS_WAIT_FOR_TX_ACK))) + } else if (sc->ps_enabled && + !(sc->ps_flags & (PS_WAIT_FOR_BEACON | + PS_WAIT_FOR_CAB | + PS_WAIT_FOR_PSPOLL_DATA | + PS_WAIT_FOR_TX_ACK))) { mode = ATH9K_PM_NETWORK_SLEEP; - else + } else { goto unlock; + } spin_lock(&common->cc_lock); ath_hw_cycle_counters_update(common); @@ -241,6 +245,7 @@ static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush) sc->hw_busy_count = 0; del_timer_sync(&common->ani.timer); + del_timer_sync(&sc->rx_poll_timer); ath9k_debug_samp_bb_mac(sc); ath9k_hw_disable_interrupts(ah); @@ -282,6 +287,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2); + ath_start_rx_poll(sc, 3); if (!common->disable_ani) ath_start_ani(common); } @@ -690,17 +696,6 @@ void ath9k_tasklet(unsigned long data) goto out; } - /* - * Only run the baseband hang check if beacons stop working in AP or - * IBSS mode, because it has a high false positive rate. For station - * mode it should not be necessary, since the upper layers will detect - * this through a beacon miss automatically and the following channel - * change will trigger a hardware reset anyway - */ - if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0 && - !ath9k_hw_check_alive(ah)) - ieee80211_queue_work(sc->hw, &sc->hw_check_work); - if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) { /* * TSF sync does not look correct; remain awake to sync with @@ -912,10 +907,19 @@ void ath_hw_check(struct work_struct *work) struct ath_common *common = ath9k_hw_common(sc->sc_ah); unsigned long flags; int busy; + u8 is_alive, nbeacon = 1; ath9k_ps_wakeup(sc); - if (ath9k_hw_check_alive(sc->sc_ah)) + is_alive = ath9k_hw_check_alive(sc->sc_ah); + + if (is_alive && !AR_SREV_9300(sc->sc_ah)) goto out; + else if (!is_alive && AR_SREV_9300(sc->sc_ah)) { + ath_dbg(common, RESET, + "DCU stuck is detected. Schedule chip reset\n"); + RESET_STAT_INC(sc, RESET_TYPE_MAC_HANG); + goto sched_reset; + } spin_lock_irqsave(&common->cc_lock, flags); busy = ath_update_survey_stats(sc); @@ -926,12 +930,18 @@ void ath_hw_check(struct work_struct *work) if (busy >= 99) { if (++sc->hw_busy_count >= 3) { RESET_STAT_INC(sc, RESET_TYPE_BB_HANG); - ieee80211_queue_work(sc->hw, &sc->hw_reset_work); + goto sched_reset; } - - } else if (busy >= 0) + } else if (busy >= 0) { sc->hw_busy_count = 0; + nbeacon = 3; + } + ath_start_rx_poll(sc, nbeacon); + goto out; + +sched_reset: + ieee80211_queue_work(sc->hw, &sc->hw_reset_work); out: ath9k_ps_restore(sc); } @@ -1094,14 +1104,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) } } - /* - * Cannot tx while the hardware is in full sleep, it first needs a full - * chip reset to recover from that - */ - if (unlikely(sc->sc_ah->power_mode == ATH9K_PM_FULL_SLEEP)) - goto exit; - - if (unlikely(sc->sc_ah->power_mode != ATH9K_PM_AWAKE)) { + if (unlikely(sc->sc_ah->power_mode == ATH9K_PM_NETWORK_SLEEP)) { /* * We are using PS-Poll and mac80211 can request TX while in * power save mode. Need to wake up hardware for the TX to be @@ -1120,12 +1123,21 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) } /* * The actual restore operation will happen only after - * the sc_flags bit is cleared. We are just dropping + * the ps_flags bit is cleared. We are just dropping * the ps_usecount here. */ ath9k_ps_restore(sc); } + /* + * Cannot tx while the hardware is in full sleep, it first needs a full + * chip reset to recover from that + */ + if (unlikely(sc->sc_ah->power_mode == ATH9K_PM_FULL_SLEEP)) { + ath_err(common, "TX while HW is in FULL_SLEEP mode\n"); + goto exit; + } + memset(&txctl, 0, sizeof(struct ath_tx_control)); txctl.txq = sc->tx.txq_map[skb_get_queue_mapping(skb)]; @@ -1133,6 +1145,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if (ath_tx_start(hw, skb, &txctl) != 0) { ath_dbg(common, XMIT, "TX failed\n"); + TX_STAT_INC(txctl.txq->axq_qnum, txfailed); goto exit; } @@ -1151,6 +1164,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) mutex_lock(&sc->mutex); ath_cancel_work(sc); + del_timer_sync(&sc->rx_poll_timer); if (sc->sc_flags & SC_OP_INVALID) { ath_dbg(common, ANY, "Device not present\n"); @@ -1237,7 +1251,6 @@ static void ath9k_reclaim_beacon(struct ath_softc *sc, ath9k_set_beaconing_status(sc, false); ath_beacon_return(sc, avp); ath9k_set_beaconing_status(sc, true); - sc->sc_flags &= ~SC_OP_BEACONS; } static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) @@ -1368,21 +1381,31 @@ static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw, ath9k_calculate_summary_state(hw, vif); if (ath9k_uses_beacons(vif->type)) { - int error; - /* This may fail because upper levels do not have beacons - * properly configured yet. That's OK, we assume it - * will be properly configured and then we will be notified - * in the info_changed method and set up beacons properly - * there. - */ + /* Reserve a beacon slot for the vif */ ath9k_set_beaconing_status(sc, false); - error = ath_beacon_alloc(sc, vif); - if (!error) - ath_beacon_config(sc, vif); + ath_beacon_alloc(sc, vif); ath9k_set_beaconing_status(sc, true); } } +void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon) +{ + if (!AR_SREV_9300(sc->sc_ah)) + return; + + if (!(sc->sc_flags & SC_OP_PRIM_STA_VIF)) + return; + + mod_timer(&sc->rx_poll_timer, jiffies + msecs_to_jiffies + (nbeacon * sc->cur_beacon_conf.beacon_interval)); +} + +void ath_rx_poll(unsigned long data) +{ + struct ath_softc *sc = (struct ath_softc *)data; + + ieee80211_queue_work(sc->hw, &sc->hw_check_work); +} static int ath9k_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) @@ -1511,6 +1534,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, static void ath9k_enable_ps(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); sc->ps_enabled = true; if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { @@ -1520,11 +1544,13 @@ static void ath9k_enable_ps(struct ath_softc *sc) } ath9k_hw_setrxabort(ah, 1); } + ath_dbg(common, PS, "PowerSave enabled\n"); } static void ath9k_disable_ps(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); sc->ps_enabled = false; ath9k_hw_setpower(ah, ATH9K_PM_AWAKE); @@ -1539,7 +1565,7 @@ static void ath9k_disable_ps(struct ath_softc *sc) ath9k_hw_set_interrupts(ah); } } - + ath_dbg(common, PS, "PowerSave disabled\n"); } static int ath9k_config(struct ieee80211_hw *hw, u32 changed) @@ -1911,6 +1937,8 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) sc->last_rssi = ATH_RSSI_DUMMY_MARKER; sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; + ath_start_rx_poll(sc, 3); + if (!common->disable_ani) { sc->sc_flags |= SC_OP_ANI_RUN; ath_start_ani(common); @@ -1950,6 +1978,7 @@ static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif) /* Stop ANI */ sc->sc_flags &= ~SC_OP_ANI_RUN; del_timer_sync(&common->ani.timer); + del_timer_sync(&sc->rx_poll_timer); memset(&sc->caldata, 0, sizeof(sc->caldata)); } } @@ -1964,7 +1993,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, struct ath_common *common = ath9k_hw_common(ah); struct ath_vif *avp = (void *)vif->drv_priv; int slottime; - int error; ath9k_ps_wakeup(sc); mutex_lock(&sc->mutex); @@ -1993,16 +2021,29 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, } else { sc->sc_flags &= ~SC_OP_ANI_RUN; del_timer_sync(&common->ani.timer); + del_timer_sync(&sc->rx_poll_timer); } } - /* Enable transmission of beacons (AP, IBSS, MESH) */ - if ((changed & BSS_CHANGED_BEACON) || - ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon)) { + /* + * In case of AP mode, the HW TSF has to be reset + * when the beacon interval changes. + */ + if ((changed & BSS_CHANGED_BEACON_INT) && + (vif->type == NL80211_IFTYPE_AP)) + sc->sc_flags |= SC_OP_TSF_RESET; + + /* Configure beaconing (AP, IBSS, MESH) */ + if (ath9k_uses_beacons(vif->type) && + ((changed & BSS_CHANGED_BEACON) || + (changed & BSS_CHANGED_BEACON_ENABLED) || + (changed & BSS_CHANGED_BEACON_INT))) { ath9k_set_beaconing_status(sc, false); - error = ath_beacon_alloc(sc, vif); - if (!error) - ath_beacon_config(sc, vif); + if (bss_conf->enable_beacon) + ath_beacon_alloc(sc, vif); + else + avp->is_bslot_active = false; + ath_beacon_config(sc, vif); ath9k_set_beaconing_status(sc, true); } @@ -2025,30 +2066,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, } } - /* Disable transmission of beacons */ - if ((changed & BSS_CHANGED_BEACON_ENABLED) && - !bss_conf->enable_beacon) { - ath9k_set_beaconing_status(sc, false); - avp->is_bslot_active = false; - ath9k_set_beaconing_status(sc, true); - } - - if (changed & BSS_CHANGED_BEACON_INT) { - /* - * In case of AP mode, the HW TSF has to be reset - * when the beacon interval changes. - */ - if (vif->type == NL80211_IFTYPE_AP) { - sc->sc_flags |= SC_OP_TSF_RESET; - ath9k_set_beaconing_status(sc, false); - error = ath_beacon_alloc(sc, vif); - if (!error) - ath_beacon_config(sc, vif); - ath9k_set_beaconing_status(sc, true); - } else - ath_beacon_config(sc, vif); - } - mutex_unlock(&sc->mutex); ath9k_ps_restore(sc); } diff --git a/trunk/drivers/net/wireless/ath/ath9k/pci.c b/trunk/drivers/net/wireless/ath/ath9k/pci.c index 77dc327def8d..a856b51255f4 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/pci.c +++ b/trunk/drivers/net/wireless/ath/ath9k/pci.c @@ -14,6 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -171,14 +173,13 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (ret) { - printk(KERN_ERR "ath9k: 32-bit DMA not available\n"); + pr_err("32-bit DMA not available\n"); goto err_dma; } ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); if (ret) { - printk(KERN_ERR "ath9k: 32-bit DMA consistent " - "DMA enable failed\n"); + pr_err("32-bit DMA consistent DMA enable failed\n"); goto err_dma; } @@ -224,7 +225,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) mem = pci_iomap(pdev, 0, 0); if (!mem) { - printk(KERN_ERR "PCI memory map error\n") ; + pr_err("PCI memory map error\n") ; ret = -EIO; goto err_iomap; } diff --git a/trunk/drivers/net/wireless/ath/ath9k/rc.c b/trunk/drivers/net/wireless/ath/ath9k/rc.c index 08bb45532701..92a6c0a87f89 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/rc.c +++ b/trunk/drivers/net/wireless/ath/ath9k/rc.c @@ -1436,7 +1436,7 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta, - u32 changed, enum nl80211_channel_type oper_chan_type) + u32 changed) { struct ath_softc *sc = priv; struct ath_rate_priv *ath_rc_priv = priv_sta; @@ -1447,12 +1447,11 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, /* FIXME: Handle AP mode later when we support CWM */ - if (changed & IEEE80211_RC_HT_CHANGED) { + if (changed & IEEE80211_RC_BW_CHANGED) { if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION) return; - if (oper_chan_type == NL80211_CHAN_HT40MINUS || - oper_chan_type == NL80211_CHAN_HT40PLUS) + if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) oper_cw40 = true; if (oper_cw40) diff --git a/trunk/drivers/net/wireless/ath/ath9k/recv.c b/trunk/drivers/net/wireless/ath/ath9k/recv.c index 1c4583c7ff7c..e1fcc68124dc 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/recv.c +++ b/trunk/drivers/net/wireless/ath/ath9k/recv.c @@ -812,6 +812,7 @@ static bool ath9k_rx_accept(struct ath_common *common, is_valid_tkip = rx_stats->rs_keyix != ATH9K_RXKEYIX_INVALID && test_bit(rx_stats->rs_keyix, common->tkip_keymap); strip_mic = is_valid_tkip && ieee80211_is_data(fc) && + ieee80211_has_protected(fc) && !(rx_stats->rs_status & (ATH9K_RXERR_DECRYPT | ATH9K_RXERR_CRC | ATH9K_RXERR_MIC | ATH9K_RXERR_KEYMISS)); @@ -824,15 +825,20 @@ static bool ath9k_rx_accept(struct ath_common *common, if (rx_stats->rs_keyix == ATH9K_RXKEYIX_INVALID) rx_stats->rs_status &= ~ATH9K_RXERR_KEYMISS; - if (!rx_stats->rs_datalen) + if (!rx_stats->rs_datalen) { + RX_STAT_INC(rx_len_err); return false; + } + /* * rs_status follows rs_datalen so if rs_datalen is too large * we can take a hint that hardware corrupted it, so ignore * those frames. */ - if (rx_stats->rs_datalen > (common->rx_bufsize - rx_status_len)) + if (rx_stats->rs_datalen > (common->rx_bufsize - rx_status_len)) { + RX_STAT_INC(rx_len_err); return false; + } /* Only use error bits from the last fragment */ if (rx_stats->rs_more) @@ -902,6 +908,7 @@ static int ath9k_process_rate(struct ath_common *common, struct ieee80211_supported_band *sband; enum ieee80211_band band; unsigned int i = 0; + struct ath_softc __maybe_unused *sc = common->priv; band = hw->conf.channel->band; sband = hw->wiphy->bands[band]; @@ -936,7 +943,7 @@ static int ath9k_process_rate(struct ath_common *common, ath_dbg(common, ANY, "unsupported hw bitrate detected 0x%02x using 1 Mbit\n", rx_stats->rs_rate); - + RX_STAT_INC(rx_rate_err); return -EINVAL; } @@ -1823,10 +1830,14 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) hdr = (struct ieee80211_hdr *) (hdr_skb->data + rx_status_len); rxs = IEEE80211_SKB_RXCB(hdr_skb); - if (ieee80211_is_beacon(hdr->frame_control) && - !is_zero_ether_addr(common->curbssid) && - !compare_ether_addr(hdr->addr3, common->curbssid)) - rs.is_mybeacon = true; + if (ieee80211_is_beacon(hdr->frame_control)) { + RX_STAT_INC(rx_beacons); + if (!is_zero_ether_addr(common->curbssid) && + ether_addr_equal(hdr->addr3, common->curbssid)) + rs.is_mybeacon = true; + else + rs.is_mybeacon = false; + } else rs.is_mybeacon = false; @@ -1836,8 +1847,10 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) * If we're asked to flush receive queue, directly * chain it back at the queue without processing it. */ - if (sc->sc_flags & SC_OP_RXFLUSH) + if (sc->sc_flags & SC_OP_RXFLUSH) { + RX_STAT_INC(rx_drop_rxflush); goto requeue_drop_frag; + } memset(rxs, 0, sizeof(struct ieee80211_rx_status)); @@ -1855,6 +1868,10 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) if (retval) goto requeue_drop_frag; + if (rs.is_mybeacon) { + sc->hw_busy_count = 0; + ath_start_rx_poll(sc, 3); + } /* Ensure we always have an skb to requeue once we are done * processing the current buffer's skb */ requeue_skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_ATOMIC); @@ -1863,8 +1880,10 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) * tell hardware it can give us a new frame using the old * skb and put it at the tail of the sc->rx.rxbuf list for * processing. */ - if (!requeue_skb) + if (!requeue_skb) { + RX_STAT_INC(rx_oom_err); goto requeue_drop_frag; + } /* Unmap the frame */ dma_unmap_single(sc->dev, bf->bf_buf_addr, @@ -1895,6 +1914,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) } if (rs.rs_more) { + RX_STAT_INC(rx_frags); /* * rs_more indicates chained descriptors which can be * used to link buffers together for a sort of @@ -1904,6 +1924,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) /* too many fragments - cannot handle frame */ dev_kfree_skb_any(sc->rx.frag); dev_kfree_skb_any(skb); + RX_STAT_INC(rx_too_many_frags_err); skb = NULL; } sc->rx.frag = skb; @@ -1915,6 +1936,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) if (pskb_expand_head(hdr_skb, 0, space, GFP_ATOMIC) < 0) { dev_kfree_skb(skb); + RX_STAT_INC(rx_oom_err); goto requeue_drop_frag; } diff --git a/trunk/drivers/net/wireless/ath/carl9170/cmd.h b/trunk/drivers/net/wireless/ath/carl9170/cmd.h index 885c42778b8b..65919c902f55 100644 --- a/trunk/drivers/net/wireless/ath/carl9170/cmd.h +++ b/trunk/drivers/net/wireless/ath/carl9170/cmd.h @@ -114,7 +114,7 @@ __regwrite_out : \ #define carl9170_regwrite_result() \ __err; \ -} while (0); +} while (0) #define carl9170_async_regwrite_get_buf() \ @@ -126,7 +126,7 @@ do { \ __err = -ENOMEM; \ goto __async_regwrite_out; \ } \ -} while (0); +} while (0) #define carl9170_async_regwrite_begin(carl) \ do { \ @@ -169,6 +169,6 @@ __async_regwrite_out: \ #define carl9170_async_regwrite_result() \ __err; \ -} while (0); +} while (0) #endif /* __CMD_H */ diff --git a/trunk/drivers/net/wireless/ath/carl9170/fw.c b/trunk/drivers/net/wireless/ath/carl9170/fw.c index cffde8d9a521..5c73c03872f3 100644 --- a/trunk/drivers/net/wireless/ath/carl9170/fw.c +++ b/trunk/drivers/net/wireless/ath/carl9170/fw.c @@ -355,6 +355,8 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len) ar->hw->wiphy->interface_modes |= if_comb_types; + ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + #undef SUPPORTED return carl9170_fw_tx_sequence(ar); } diff --git a/trunk/drivers/net/wireless/ath/carl9170/rx.c b/trunk/drivers/net/wireless/ath/carl9170/rx.c index dc99030ea8b6..84b22eec7abd 100644 --- a/trunk/drivers/net/wireless/ath/carl9170/rx.c +++ b/trunk/drivers/net/wireless/ath/carl9170/rx.c @@ -538,7 +538,7 @@ static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len) return; /* and only beacons from the associated BSSID, please */ - if (compare_ether_addr(hdr->addr3, ar->common.curbssid) || + if (!ether_addr_equal(hdr->addr3, ar->common.curbssid) || !ar->common.curaid) return; diff --git a/trunk/drivers/net/wireless/ath/carl9170/usb.c b/trunk/drivers/net/wireless/ath/carl9170/usb.c index 89821e4835c7..888152ce3eca 100644 --- a/trunk/drivers/net/wireless/ath/carl9170/usb.c +++ b/trunk/drivers/net/wireless/ath/carl9170/usb.c @@ -1159,6 +1159,7 @@ static struct usb_driver carl9170_driver = { .resume = carl9170_usb_resume, .reset_resume = carl9170_usb_resume, #endif /* CONFIG_PM */ + .disable_hub_initiated_lpm = 1, }; module_usb_driver(carl9170_driver); diff --git a/trunk/drivers/net/wireless/ath/main.c b/trunk/drivers/net/wireless/ath/main.c index ea2c737138d3..8e99540cd90e 100644 --- a/trunk/drivers/net/wireless/ath/main.c +++ b/trunk/drivers/net/wireless/ath/main.c @@ -14,6 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include @@ -49,7 +51,7 @@ struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, if (off != 0) skb_reserve(skb, common->cachelsz - off); } else { - printk(KERN_ERR "skbuff alloc of size %u failed\n", len); + pr_err("skbuff alloc of size %u failed\n", len); return NULL; } diff --git a/trunk/drivers/net/wireless/ath/regd.c b/trunk/drivers/net/wireless/ath/regd.c index 10dea37431b3..d81698015bf7 100644 --- a/trunk/drivers/net/wireless/ath/regd.c +++ b/trunk/drivers/net/wireless/ath/regd.c @@ -14,6 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -562,7 +564,7 @@ static int __ath_regd_init(struct ath_regulatory *reg) printk(KERN_DEBUG "ath: EEPROM regdomain: 0x%0x\n", reg->current_rd); if (!ath_regd_is_eeprom_valid(reg)) { - printk(KERN_ERR "ath: Invalid EEPROM contents\n"); + pr_err("Invalid EEPROM contents\n"); return -EINVAL; } diff --git a/trunk/drivers/net/wireless/atmel.c b/trunk/drivers/net/wireless/atmel.c index 6c87a823f5a9..d07c0301da6a 100644 --- a/trunk/drivers/net/wireless/atmel.c +++ b/trunk/drivers/net/wireless/atmel.c @@ -3989,8 +3989,7 @@ static int reset_atmel_card(struct net_device *dev) atmel_copy_to_card(priv->dev, 0x8000, &fw[0x6000], len - 0x6000); } - if (fw_entry) - release_firmware(fw_entry); + release_firmware(fw_entry); } err = atmel_wakeup_firmware(priv); diff --git a/trunk/drivers/net/wireless/atmel_pci.c b/trunk/drivers/net/wireless/atmel_pci.c index 9ab1192004c0..51e33b53386e 100644 --- a/trunk/drivers/net/wireless/atmel_pci.c +++ b/trunk/drivers/net/wireless/atmel_pci.c @@ -74,15 +74,4 @@ static void __devexit atmel_pci_remove(struct pci_dev *pdev) stop_atmel_card(pci_get_drvdata(pdev)); } -static int __init atmel_init_module(void) -{ - return pci_register_driver(&atmel_driver); -} - -static void __exit atmel_cleanup_module(void) -{ - pci_unregister_driver(&atmel_driver); -} - -module_init(atmel_init_module); -module_exit(atmel_cleanup_module); +module_pci_driver(atmel_driver); diff --git a/trunk/drivers/net/wireless/b43/main.c b/trunk/drivers/net/wireless/b43/main.c index e4d6dc2e37d1..617afc8211b2 100644 --- a/trunk/drivers/net/wireless/b43/main.c +++ b/trunk/drivers/net/wireless/b43/main.c @@ -4010,6 +4010,20 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (modparam_nohwcrypt) return -ENOSPC; /* User disabled HW-crypto */ + if ((vif->type == NL80211_IFTYPE_ADHOC || + vif->type == NL80211_IFTYPE_MESH_POINT) && + (key->cipher == WLAN_CIPHER_SUITE_TKIP || + key->cipher == WLAN_CIPHER_SUITE_CCMP) && + !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { + /* + * For now, disable hw crypto for the RSN IBSS group keys. This + * could be optimized in the future, but until that gets + * implemented, use of software crypto for group addressed + * frames is a acceptable to allow RSN IBSS to be used. + */ + return -EOPNOTSUPP; + } + mutex_lock(&wl->mutex); dev = wl->current_dev; @@ -5281,6 +5295,8 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev) BIT(NL80211_IFTYPE_WDS) | BIT(NL80211_IFTYPE_ADHOC); + hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + hw->queues = modparam_qos ? B43_QOS_QUEUE_NUM : 1; wl->mac80211_initially_registered_queues = hw->queues; hw->max_rates = 2; diff --git a/trunk/drivers/net/wireless/b43/sdio.c b/trunk/drivers/net/wireless/b43/sdio.c index 80b0755ed3af..a54fb2d29089 100644 --- a/trunk/drivers/net/wireless/b43/sdio.c +++ b/trunk/drivers/net/wireless/b43/sdio.c @@ -193,7 +193,7 @@ static struct sdio_driver b43_sdio_driver = { .name = "b43-sdio", .id_table = b43_sdio_ids, .probe = b43_sdio_probe, - .remove = b43_sdio_remove, + .remove = __devexit_p(b43_sdio_remove), }; int b43_sdio_init(void) diff --git a/trunk/drivers/net/wireless/b43/xmit.c b/trunk/drivers/net/wireless/b43/xmit.c index 2c5367884b3f..b31ccc02fa21 100644 --- a/trunk/drivers/net/wireless/b43/xmit.c +++ b/trunk/drivers/net/wireless/b43/xmit.c @@ -290,7 +290,8 @@ int b43_generate_txhdr(struct b43_wldev *dev, txhdr->dur_fb = wlhdr->duration_id; } else { txhdr->dur_fb = ieee80211_generic_frame_duration( - dev->wl->hw, info->control.vif, fragment_len, fbrate); + dev->wl->hw, info->control.vif, info->band, + fragment_len, fbrate); } plcp_fragment_len = fragment_len + FCS_LEN; @@ -378,7 +379,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) phy_ctl |= B43_TXH_PHY_SHORTPRMBL; - switch (b43_ieee80211_antenna_sanitize(dev, info->antenna_sel_tx)) { + switch (b43_ieee80211_antenna_sanitize(dev, 0)) { case 0: /* Default */ phy_ctl |= B43_TXH_PHY_ANT01AUTO; break; diff --git a/trunk/drivers/net/wireless/b43legacy/main.c b/trunk/drivers/net/wireless/b43legacy/main.c index df7e16dfb36c..1be214b815fb 100644 --- a/trunk/drivers/net/wireless/b43legacy/main.c +++ b/trunk/drivers/net/wireless/b43legacy/main.c @@ -1056,6 +1056,7 @@ static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev, b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->hw_value); dur = ieee80211_generic_frame_duration(dev->wl->hw, dev->wl->vif, + IEEE80211_BAND_2GHZ, size, rate); /* Write PLCP in two parts and timing for packet transfer */ @@ -1121,6 +1122,7 @@ static const u8 *b43legacy_generate_probe_resp(struct b43legacy_wldev *dev, IEEE80211_STYPE_PROBE_RESP); dur = ieee80211_generic_frame_duration(dev->wl->hw, dev->wl->vif, + IEEE80211_BAND_2GHZ, *dest_size, rate); hdr->duration_id = dur; diff --git a/trunk/drivers/net/wireless/b43legacy/xmit.c b/trunk/drivers/net/wireless/b43legacy/xmit.c index 5188fab0b377..a8012f2749ee 100644 --- a/trunk/drivers/net/wireless/b43legacy/xmit.c +++ b/trunk/drivers/net/wireless/b43legacy/xmit.c @@ -228,6 +228,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, } else { txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw, info->control.vif, + info->band, fragment_len, rate_fb); } @@ -277,19 +278,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, phy_ctl |= B43legacy_TX4_PHY_ENC_OFDM; if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL; - switch (info->antenna_sel_tx) { - case 0: - phy_ctl |= B43legacy_TX4_PHY_ANTLAST; - break; - case 1: - phy_ctl |= B43legacy_TX4_PHY_ANT0; - break; - case 2: - phy_ctl |= B43legacy_TX4_PHY_ANT1; - break; - default: - B43legacy_BUG_ON(1); - } + phy_ctl |= B43legacy_TX4_PHY_ANTLAST; /* MAC control */ rates = info->control.rates; diff --git a/trunk/drivers/net/wireless/brcm80211/Kconfig b/trunk/drivers/net/wireless/brcm80211/Kconfig index c5104533e24e..b480088b3dbe 100644 --- a/trunk/drivers/net/wireless/brcm80211/Kconfig +++ b/trunk/drivers/net/wireless/brcm80211/Kconfig @@ -36,6 +36,15 @@ config BRCMFMAC_SDIO IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to use the driver for a SDIO wireless card. +config BRCMFMAC_SDIO_OOB + bool "Out of band interrupt support for SDIO interface chipset" + depends on BRCMFMAC_SDIO + ---help--- + This option enables out-of-band interrupt support for Broadcom + SDIO Wifi chipset using fullmac in order to gain better + performance and deep sleep wake up capability on certain + platforms. Say N if you are unsure. + config BRCMFMAC_USB bool "USB bus interface support for FullMAC driver" depends on USB diff --git a/trunk/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/trunk/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index e925290b432b..4add7da24681 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/trunk/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -39,37 +39,113 @@ #define SDIOH_API_ACCESS_RETRY_LIMIT 2 -static void brcmf_sdioh_irqhandler(struct sdio_func *func) +#ifdef CONFIG_BRCMFMAC_SDIO_OOB +static irqreturn_t brcmf_sdio_irqhandler(int irq, void *dev_id) { - struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev); + struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(dev_id); - brcmf_dbg(TRACE, "***IRQHandler\n"); + brcmf_dbg(INTR, "oob intr triggered\n"); - sdio_release_host(func); + /* + * out-of-band interrupt is level-triggered which won't + * be cleared until dpc + */ + if (sdiodev->irq_en) { + disable_irq_nosync(irq); + sdiodev->irq_en = false; + } brcmf_sdbrcm_isr(sdiodev->bus); - sdio_claim_host(func); + return IRQ_HANDLED; +} + +int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev) +{ + int ret = 0; + u8 data; + unsigned long flags; + + brcmf_dbg(TRACE, "Entering\n"); + + brcmf_dbg(ERROR, "requesting irq %d\n", sdiodev->irq); + ret = request_irq(sdiodev->irq, brcmf_sdio_irqhandler, + sdiodev->irq_flags, "brcmf_oob_intr", + &sdiodev->func[1]->card->dev); + if (ret != 0) + return ret; + spin_lock_init(&sdiodev->irq_en_lock); + spin_lock_irqsave(&sdiodev->irq_en_lock, flags); + sdiodev->irq_en = true; + spin_unlock_irqrestore(&sdiodev->irq_en_lock, flags); + + ret = enable_irq_wake(sdiodev->irq); + if (ret != 0) + return ret; + sdiodev->irq_wake = true; + + /* must configure SDIO_CCCR_IENx to enable irq */ + data = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_0, + SDIO_CCCR_IENx, &ret); + data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1; + brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_IENx, + data, &ret); + + /* redirect, configure ane enable io for interrupt signal */ + data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE; + if (sdiodev->irq_flags | IRQF_TRIGGER_HIGH) + data |= SDIO_SEPINT_ACT_HI; + brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_BRCM_SEPINT, + data, &ret); + + return 0; +} + +int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev) +{ + brcmf_dbg(TRACE, "Entering\n"); + + brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_BRCM_SEPINT, + 0, NULL); + brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_IENx, 0, NULL); + + if (sdiodev->irq_wake) { + disable_irq_wake(sdiodev->irq); + sdiodev->irq_wake = false; + } + free_irq(sdiodev->irq, &sdiodev->func[1]->card->dev); + sdiodev->irq_en = false; + + return 0; +} +#else /* CONFIG_BRCMFMAC_SDIO_OOB */ +static void brcmf_sdio_irqhandler(struct sdio_func *func) +{ + struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev); + + brcmf_dbg(INTR, "ib intr triggered\n"); + + brcmf_sdbrcm_isr(sdiodev->bus); } /* dummy handler for SDIO function 2 interrupt */ -static void brcmf_sdioh_dummy_irq_handler(struct sdio_func *func) +static void brcmf_sdio_dummy_irqhandler(struct sdio_func *func) { } -int brcmf_sdcard_intr_reg(struct brcmf_sdio_dev *sdiodev) +int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev) { brcmf_dbg(TRACE, "Entering\n"); sdio_claim_host(sdiodev->func[1]); - sdio_claim_irq(sdiodev->func[1], brcmf_sdioh_irqhandler); - sdio_claim_irq(sdiodev->func[2], brcmf_sdioh_dummy_irq_handler); + sdio_claim_irq(sdiodev->func[1], brcmf_sdio_irqhandler); + sdio_claim_irq(sdiodev->func[2], brcmf_sdio_dummy_irqhandler); sdio_release_host(sdiodev->func[1]); return 0; } -int brcmf_sdcard_intr_dereg(struct brcmf_sdio_dev *sdiodev) +int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev) { brcmf_dbg(TRACE, "Entering\n"); @@ -80,6 +156,7 @@ int brcmf_sdcard_intr_dereg(struct brcmf_sdio_dev *sdiodev) return 0; } +#endif /* CONFIG_BRCMFMAC_SDIO_OOB */ u8 brcmf_sdcard_cfg_read(struct brcmf_sdio_dev *sdiodev, uint fnc_num, u32 addr, int *err) diff --git a/trunk/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/trunk/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c index 758c115b556e..dd07d33a927c 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/trunk/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c @@ -27,6 +27,7 @@ #include #include /* request_irq() */ #include +#include #include #include @@ -55,6 +56,15 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = { }; MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); +#ifdef CONFIG_BRCMFMAC_SDIO_OOB +static struct list_head oobirq_lh; +struct brcmf_sdio_oobirq { + unsigned int irq; + unsigned long flags; + struct list_head list; +}; +#endif /* CONFIG_BRCMFMAC_SDIO_OOB */ + static bool brcmf_pm_resume_error(struct brcmf_sdio_dev *sdiodev) { @@ -107,7 +117,8 @@ static inline int brcmf_sdioh_f0_write_byte(struct brcmf_sdio_dev *sdiodev, } sdio_release_host(sdfunc); } - } else if (regaddr == SDIO_CCCR_ABORT) { + } else if ((regaddr == SDIO_CCCR_ABORT) || + (regaddr == SDIO_CCCR_IENx)) { sdfunc = kmemdup(sdiodev->func[0], sizeof(struct sdio_func), GFP_KERNEL); if (!sdfunc) @@ -467,12 +478,40 @@ void brcmf_sdioh_detach(struct brcmf_sdio_dev *sdiodev) } +#ifdef CONFIG_BRCMFMAC_SDIO_OOB +static int brcmf_sdio_getintrcfg(struct brcmf_sdio_dev *sdiodev) +{ + struct brcmf_sdio_oobirq *oobirq_entry; + + if (list_empty(&oobirq_lh)) { + brcmf_dbg(ERROR, "no valid oob irq resource\n"); + return -ENXIO; + } + + oobirq_entry = list_first_entry(&oobirq_lh, struct brcmf_sdio_oobirq, + list); + + sdiodev->irq = oobirq_entry->irq; + sdiodev->irq_flags = oobirq_entry->flags; + list_del(&oobirq_entry->list); + kfree(oobirq_entry); + + return 0; +} +#else +static inline int brcmf_sdio_getintrcfg(struct brcmf_sdio_dev *sdiodev) +{ + return 0; +} +#endif /* CONFIG_BRCMFMAC_SDIO_OOB */ + static int brcmf_ops_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) { int ret = 0; struct brcmf_sdio_dev *sdiodev; struct brcmf_bus *bus_if; + brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "func->class=%x\n", func->class); brcmf_dbg(TRACE, "sdio_vendor: 0x%04x\n", func->vendor); @@ -511,6 +550,10 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func, sdiodev = dev_get_drvdata(&func->card->dev); if ((!sdiodev) || (sdiodev->func[1]->card != func->card)) return -ENODEV; + + ret = brcmf_sdio_getintrcfg(sdiodev); + if (ret) + return ret; sdiodev->func[2] = func; bus_if = sdiodev->bus_if; @@ -603,6 +646,65 @@ static struct sdio_driver brcmf_sdmmc_driver = { #endif /* CONFIG_PM_SLEEP */ }; +#ifdef CONFIG_BRCMFMAC_SDIO_OOB +static int brcmf_sdio_pd_probe(struct platform_device *pdev) +{ + struct resource *res; + struct brcmf_sdio_oobirq *oobirq_entry; + int i, ret; + + INIT_LIST_HEAD(&oobirq_lh); + + for (i = 0; ; i++) { + res = platform_get_resource(pdev, IORESOURCE_IRQ, i); + if (!res) + break; + + oobirq_entry = kzalloc(sizeof(struct brcmf_sdio_oobirq), + GFP_KERNEL); + oobirq_entry->irq = res->start; + oobirq_entry->flags = res->flags & IRQF_TRIGGER_MASK; + list_add_tail(&oobirq_entry->list, &oobirq_lh); + } + if (i == 0) + return -ENXIO; + + ret = sdio_register_driver(&brcmf_sdmmc_driver); + + if (ret) + brcmf_dbg(ERROR, "sdio_register_driver failed: %d\n", ret); + + return ret; +} + +static struct platform_driver brcmf_sdio_pd = { + .probe = brcmf_sdio_pd_probe, + .driver = { + .name = "brcmf_sdio_pd" + } +}; + +void brcmf_sdio_exit(void) +{ + brcmf_dbg(TRACE, "Enter\n"); + + sdio_unregister_driver(&brcmf_sdmmc_driver); + + platform_driver_unregister(&brcmf_sdio_pd); +} + +void brcmf_sdio_init(void) +{ + int ret; + + brcmf_dbg(TRACE, "Enter\n"); + + ret = platform_driver_register(&brcmf_sdio_pd); + + if (ret) + brcmf_dbg(ERROR, "platform_driver_register failed: %d\n", ret); +} +#else void brcmf_sdio_exit(void) { brcmf_dbg(TRACE, "Enter\n"); @@ -621,3 +723,4 @@ void brcmf_sdio_init(void) if (ret) brcmf_dbg(ERROR, "sdio_register_driver failed: %d\n", ret); } +#endif /* CONFIG_BRCMFMAC_SDIO_OOB */ diff --git a/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index 07686a748d3c..9f637014486e 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -632,7 +632,6 @@ extern const struct bcmevent_name bcmevent_names[]; extern uint brcmf_c_mkiovar(char *name, char *data, uint datalen, char *buf, uint len); -extern int brcmf_net_attach(struct brcmf_pub *drvr, int idx); extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev); extern s32 brcmf_exec_dcmd(struct net_device *dev, u32 cmd, void *arg, u32 len); diff --git a/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c b/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c index b3e3b7f25d82..a5c15cac5e7d 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c +++ b/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c @@ -421,6 +421,7 @@ int brcmf_proto_hdrpull(struct device *dev, int *ifidx, pktbuf->priority = h->priority & BDC_PRIORITY_MASK; skb_pull(pktbuf, BDC_HEADER_LEN); + skb_pull(pktbuf, h->data_offset << 2); return 0; } diff --git a/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c index 4187435220f3..236cb9fa460c 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c +++ b/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c @@ -799,7 +799,6 @@ int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr) { char iovbuf[BRCMF_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ - uint up = 0; char buf[128], *ptr; u32 dongle_align = drvr->bus_if->align; u32 glom = 0; @@ -853,9 +852,6 @@ int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr) brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf)); - /* Force STA UP */ - brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_UP, (char *)&up, sizeof(up)); - /* Setup event_msgs */ brcmf_c_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); diff --git a/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index 2a1e5ae0c402..8933f9b31a9a 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -799,6 +799,7 @@ static int brcmf_netdev_open(struct net_device *ndev) struct brcmf_bus *bus_if = drvr->bus_if; u32 toe_ol; s32 ret = 0; + uint up = 0; brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx); @@ -822,6 +823,10 @@ static int brcmf_netdev_open(struct net_device *ndev) drvr->iflist[ifp->idx]->ndev->features &= ~NETIF_F_IP_CSUM; } + + /* make sure RF is ready for work */ + brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_UP, (char *)&up, sizeof(up)); + /* Allow transmit calls */ netif_start_queue(ndev); drvr->bus_if->drvr_up = true; @@ -843,6 +848,63 @@ static const struct net_device_ops brcmf_netdev_ops_pri = { .ndo_set_rx_mode = brcmf_netdev_set_multicast_list }; +static int brcmf_net_attach(struct brcmf_if *ifp) +{ + struct brcmf_pub *drvr = ifp->drvr; + struct net_device *ndev; + u8 temp_addr[ETH_ALEN]; + + brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx); + + ndev = drvr->iflist[ifp->idx]->ndev; + ndev->netdev_ops = &brcmf_netdev_ops_pri; + + /* + * determine mac address to use + */ + if (is_valid_ether_addr(ifp->mac_addr)) + memcpy(temp_addr, ifp->mac_addr, ETH_ALEN); + else + memcpy(temp_addr, drvr->mac, ETH_ALEN); + + if (ifp->idx == 1) { + brcmf_dbg(TRACE, "ACCESS POINT MAC:\n"); + /* ACCESSPOINT INTERFACE CASE */ + temp_addr[0] |= 0X02; /* set bit 2 , + - Locally Administered address */ + + } + ndev->hard_header_len = ETH_HLEN + drvr->hdrlen; + ndev->ethtool_ops = &brcmf_ethtool_ops; + + drvr->rxsz = ndev->mtu + ndev->hard_header_len + + drvr->hdrlen; + + memcpy(ndev->dev_addr, temp_addr, ETH_ALEN); + + /* attach to cfg80211 for primary interface */ + if (!ifp->idx) { + drvr->config = brcmf_cfg80211_attach(ndev, drvr->dev, drvr); + if (drvr->config == NULL) { + brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n"); + goto fail; + } + } + + if (register_netdev(ndev) != 0) { + brcmf_dbg(ERROR, "couldn't register the net device\n"); + goto fail; + } + + brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name); + + return 0; + +fail: + ndev->netdev_ops = NULL; + return -EBADE; +} + int brcmf_add_if(struct device *dev, int ifidx, char *name, u8 *mac_addr) { @@ -882,7 +944,7 @@ brcmf_add_if(struct device *dev, int ifidx, char *name, u8 *mac_addr) if (mac_addr != NULL) memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN); - if (brcmf_net_attach(drvr, ifp->idx)) { + if (brcmf_net_attach(ifp)) { brcmf_dbg(ERROR, "brcmf_net_attach failed"); free_netdev(ifp->ndev); drvr->iflist[ifidx] = NULL; @@ -1016,69 +1078,16 @@ int brcmf_bus_start(struct device *dev) if (ret < 0) return ret; + /* add primary networking interface */ + ret = brcmf_add_if(dev, 0, "wlan%d", drvr->mac); + if (ret < 0) + return ret; + /* signal bus ready */ bus_if->state = BRCMF_BUS_DATA; return 0; } -int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx) -{ - struct net_device *ndev; - u8 temp_addr[ETH_ALEN] = { - 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33}; - - brcmf_dbg(TRACE, "ifidx %d\n", ifidx); - - ndev = drvr->iflist[ifidx]->ndev; - ndev->netdev_ops = &brcmf_netdev_ops_pri; - - /* - * We have to use the primary MAC for virtual interfaces - */ - if (ifidx != 0) { - /* for virtual interfaces use the primary MAC */ - memcpy(temp_addr, drvr->mac, ETH_ALEN); - - } - - if (ifidx == 1) { - brcmf_dbg(TRACE, "ACCESS POINT MAC:\n"); - /* ACCESSPOINT INTERFACE CASE */ - temp_addr[0] |= 0X02; /* set bit 2 , - - Locally Administered address */ - - } - ndev->hard_header_len = ETH_HLEN + drvr->hdrlen; - ndev->ethtool_ops = &brcmf_ethtool_ops; - - drvr->rxsz = ndev->mtu + ndev->hard_header_len + - drvr->hdrlen; - - memcpy(ndev->dev_addr, temp_addr, ETH_ALEN); - - /* attach to cfg80211 for primary interface */ - if (!ifidx) { - drvr->config = brcmf_cfg80211_attach(ndev, drvr->dev, drvr); - if (drvr->config == NULL) { - brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n"); - goto fail; - } - } - - if (register_netdev(ndev) != 0) { - brcmf_dbg(ERROR, "couldn't register the net device\n"); - goto fail; - } - - brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name); - - return 0; - -fail: - ndev->netdev_ops = NULL; - return -EBADE; -} - static void brcmf_bus_detach(struct brcmf_pub *drvr) { brcmf_dbg(TRACE, "Enter\n"); diff --git a/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index e2b34e1563f4..149ee67beb2e 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/trunk/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -2352,6 +2352,24 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev) up(&bus->sdsem); } +#ifdef CONFIG_BRCMFMAC_SDIO_OOB +static inline void brcmf_sdbrcm_clrintr(struct brcmf_sdio *bus) +{ + unsigned long flags; + + spin_lock_irqsave(&bus->sdiodev->irq_en_lock, flags); + if (!bus->sdiodev->irq_en && !bus->ipend) { + enable_irq(bus->sdiodev->irq); + bus->sdiodev->irq_en = true; + } + spin_unlock_irqrestore(&bus->sdiodev->irq_en_lock, flags); +} +#else +static inline void brcmf_sdbrcm_clrintr(struct brcmf_sdio *bus) +{ +} +#endif /* CONFIG_BRCMFMAC_SDIO_OOB */ + static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) { u32 intstatus, newstatus = 0; @@ -2509,6 +2527,8 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) bus->intstatus = intstatus; clkwait: + brcmf_sdbrcm_clrintr(bus); + if (data_ok(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) { int ret, i; @@ -3508,8 +3528,14 @@ static int brcmf_sdbrcm_bus_init(struct device *dev) brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err); + if (ret == 0) { + ret = brcmf_sdio_intr_register(bus->sdiodev); + if (ret != 0) + brcmf_dbg(ERROR, "intr register failed:%d\n", ret); + } + /* If we didn't come up, turn off backplane clock */ - if (!ret) + if (bus_if->state != BRCMF_BUS_DATA) brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); exit: @@ -3867,7 +3893,7 @@ static void brcmf_sdbrcm_release(struct brcmf_sdio *bus) if (bus) { /* De-register interrupt handler */ - brcmf_sdcard_intr_dereg(bus->sdiodev); + brcmf_sdio_intr_unregister(bus->sdiodev); if (bus->sdiodev->bus_if->drvr) { brcmf_detach(bus->sdiodev->dev); @@ -3968,15 +3994,6 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) goto fail; } - /* Register interrupt callback, but mask it (not operational yet). */ - brcmf_dbg(INTR, "disable SDIO interrupts (not interested yet)\n"); - ret = brcmf_sdcard_intr_reg(bus->sdiodev); - if (ret != 0) { - brcmf_dbg(ERROR, "FAILED: sdcard_intr_reg returned %d\n", ret); - goto fail; - } - brcmf_dbg(INTR, "registered SDIO interrupt function ok\n"); - brcmf_dbg(INFO, "completed!!\n"); /* if firmware path present try to download and bring up bus */ @@ -3988,12 +4005,6 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) } } - /* add interface and open for business */ - if (brcmf_add_if(bus->sdiodev->dev, 0, "wlan%d", NULL)) { - brcmf_dbg(ERROR, "Add primary net device interface failed!!\n"); - goto fail; - } - return bus; fail: diff --git a/trunk/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h b/trunk/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h index 0281d207d998..7010eaf71f99 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h +++ b/trunk/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h @@ -43,6 +43,13 @@ /* as of sdiod rev 0, supports 3 functions */ #define SBSDIO_NUM_FUNCTION 3 +/* function 0 vendor specific CCCR registers */ +#define SDIO_CCCR_BRCM_SEPINT 0xf2 + +#define SDIO_SEPINT_MASK 0x01 +#define SDIO_SEPINT_OE 0x02 +#define SDIO_SEPINT_ACT_HI 0x04 + /* function 1 miscellaneous registers */ /* sprom command and status */ @@ -144,13 +151,18 @@ struct brcmf_sdio_dev { wait_queue_head_t request_buffer_wait; struct device *dev; struct brcmf_bus *bus_if; +#ifdef CONFIG_BRCMFMAC_SDIO_OOB + unsigned int irq; /* oob interrupt number */ + unsigned long irq_flags; /* board specific oob flags */ + bool irq_en; /* irq enable flags */ + spinlock_t irq_en_lock; + bool irq_wake; /* irq wake enable flags */ +#endif /* CONFIG_BRCMFMAC_SDIO_OOB */ }; -/* Register/deregister device interrupt handler. */ -extern int -brcmf_sdcard_intr_reg(struct brcmf_sdio_dev *sdiodev); - -extern int brcmf_sdcard_intr_dereg(struct brcmf_sdio_dev *sdiodev); +/* Register/deregister interrupt handler. */ +extern int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev); +extern int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev); /* Access SDIO address space (e.g. CCCR) using CMD52 (single-byte interface). * fn: function number diff --git a/trunk/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/trunk/drivers/net/wireless/brcm80211/brcmfmac/usb.c index 82364223e817..c5a34ffe6459 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/trunk/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -1383,14 +1383,6 @@ static int brcmf_usb_probe_cb(struct device *dev, const char *desc, goto fail; } - /* add interface and open for business */ - ret = brcmf_add_if(dev, 0, "wlan%d", NULL); - if (ret) { - brcmf_dbg(ERROR, "Add primary net device interface failed!!\n"); - brcmf_detach(dev); - goto fail; - } - return 0; fail: /* Release resources in reverse order */ @@ -1604,7 +1596,8 @@ static struct usb_driver brcmf_usbdrvr = { .id_table = brcmf_usb_devid_table, .suspend = brcmf_usb_suspend, .resume = brcmf_usb_resume, - .supports_autosuspend = 1 + .supports_autosuspend = 1, + .disable_hub_initiated_lpm = 1, }; void brcmf_usb_exit(void) diff --git a/trunk/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/trunk/drivers/net/wireless/brcm80211/brcmsmac/channel.c index 55e9f45fce22..0efe88e25a9a 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmsmac/channel.c +++ b/trunk/drivers/net/wireless/brcm80211/brcmsmac/channel.c @@ -628,6 +628,40 @@ brcms_c_country_aggregate_map(struct brcms_cm_info *wlc_cm, const char *ccode, return false; } +/* + * Indicates whether the country provided is valid to pass + * to cfg80211 or not. + * + * returns true if valid; false if not. + */ +static bool brcms_c_country_valid(const char *ccode) +{ + /* + * only allow ascii alpha uppercase for the first 2 + * chars. + */ + if (!((0x80 & ccode[0]) == 0 && ccode[0] >= 0x41 && ccode[0] <= 0x5A && + (0x80 & ccode[1]) == 0 && ccode[1] >= 0x41 && ccode[1] <= 0x5A && + ccode[2] == '\0')) + return false; + + /* + * do not match ISO 3166-1 user assigned country codes + * that may be in the driver table + */ + if (!strcmp("AA", ccode) || /* AA */ + !strcmp("ZZ", ccode) || /* ZZ */ + ccode[0] == 'X' || /* XA - XZ */ + (ccode[0] == 'Q' && /* QM - QZ */ + (ccode[1] >= 'M' && ccode[1] <= 'Z'))) + return false; + + if (!strcmp("NA", ccode)) + return false; + + return true; +} + /* Lookup a country info structure from a null terminated country * abbreviation and regrev directly with no translation. */ @@ -1089,7 +1123,7 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc) /* store the country code for passing up as a regulatory hint */ ccode = getvar(wlc->hw->sih, BRCMS_SROM_CCODE); - if (ccode) + if (ccode && brcms_c_country_valid(ccode)) strncpy(wlc->pub->srom_ccode, ccode, BRCM_CNTRY_BUF_SZ - 1); /* diff --git a/trunk/drivers/net/wireless/brcm80211/brcmsmac/d11.h b/trunk/drivers/net/wireless/brcm80211/brcmsmac/d11.h index 1948cb2771e9..3f659e09f1cc 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmsmac/d11.h +++ b/trunk/drivers/net/wireless/brcm80211/brcmsmac/d11.h @@ -733,7 +733,7 @@ struct cck_phy_hdr { do { \ plcp[1] = len & 0xff; \ plcp[2] = ((len >> 8) & 0xff); \ - } while (0); + } while (0) #define BRCMS_SET_MIMO_PLCP_AMPDU(plcp) (plcp[3] |= MIMO_PLCP_AMPDU) #define BRCMS_CLR_MIMO_PLCP_AMPDU(plcp) (plcp[3] &= ~MIMO_PLCP_AMPDU) diff --git a/trunk/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/trunk/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 569ab8abd2a1..aa15558f75c8 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/trunk/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -1069,11 +1069,7 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev) wiphy_err(wl->wiphy, "%s: ieee80211_register_hw failed, status" "%d\n", __func__, err); - if (wl->pub->srom_ccode[0]) - err = brcms_set_hint(wl, wl->pub->srom_ccode); - else - err = brcms_set_hint(wl, "US"); - if (err) + if (wl->pub->srom_ccode[0] && brcms_set_hint(wl, wl->pub->srom_ccode)) wiphy_err(wl->wiphy, "%s: regulatory_hint failed, status %d\n", __func__, err); diff --git a/trunk/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/trunk/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c index ce8562aa5db0..0fce56235f38 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/trunk/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c @@ -207,8 +207,7 @@ static const iqcal_gain_params_lcnphy *tbl_iqcal_gainparams_lcnphy[1] = { }; static const u16 iqcal_gainparams_numgains_lcnphy[1] = { - sizeof(tbl_iqcal_gainparams_lcnphy_2G) / - sizeof(*tbl_iqcal_gainparams_lcnphy_2G), + ARRAY_SIZE(tbl_iqcal_gainparams_lcnphy_2G), }; static const struct lcnphy_sfo_cfg lcnphy_sfo_cfg[] = { diff --git a/trunk/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c b/trunk/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c index 39095741fd05..812b6e38526e 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c +++ b/trunk/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c @@ -16353,11 +16353,7 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi) wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_RX2TX, rfseq_rx2tx_events_rev3_ipa, rfseq_rx2tx_dlys_rev3_ipa, - sizeof - (rfseq_rx2tx_events_rev3_ipa) / - sizeof - (rfseq_rx2tx_events_rev3_ipa - [0])); + ARRAY_SIZE(rfseq_rx2tx_events_rev3_ipa)); mod_phy_reg(pi, 0x299, (0x3 << 14), (0x1 << 14)); mod_phy_reg(pi, 0x29d, (0x3 << 14), (0x1 << 14)); @@ -16858,18 +16854,13 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi) wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_TX2RX, rfseq_tx2rx_events_rev3, rfseq_tx2rx_dlys_rev3, - sizeof(rfseq_tx2rx_events_rev3) / - sizeof(rfseq_tx2rx_events_rev3[0])); + ARRAY_SIZE(rfseq_tx2rx_events_rev3)); if (PHY_IPA(pi)) wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_RX2TX, rfseq_rx2tx_events_rev3_ipa, rfseq_rx2tx_dlys_rev3_ipa, - sizeof - (rfseq_rx2tx_events_rev3_ipa) / - sizeof - (rfseq_rx2tx_events_rev3_ipa - [0])); + ARRAY_SIZE(rfseq_rx2tx_events_rev3_ipa)); if ((pi->sh->hw_phyrxchain != 0x3) && (pi->sh->hw_phyrxchain != pi->sh->hw_phytxchain)) { @@ -16885,8 +16876,7 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi) pi, NPHY_RFSEQ_RX2TX, rfseq_rx2tx_events_rev3, rfseq_rx2tx_dlys_rev3, - sizeof(rfseq_rx2tx_events_rev3) / - sizeof(rfseq_rx2tx_events_rev3[0])); + ARRAY_SIZE(rfseq_rx2tx_events_rev3)); } if (CHSPEC_IS2G(pi->radio_chanspec)) @@ -17209,13 +17199,11 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi) wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_RX2TX, rfseq_rx2tx_events, rfseq_rx2tx_dlys, - sizeof(rfseq_rx2tx_events) / - sizeof(rfseq_rx2tx_events[0])); + ARRAY_SIZE(rfseq_rx2tx_events)); wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_TX2RX, rfseq_tx2rx_events, rfseq_tx2rx_dlys, - sizeof(rfseq_tx2rx_events) / - sizeof(rfseq_tx2rx_events[0])); + ARRAY_SIZE(rfseq_tx2rx_events)); wlc_phy_workarounds_nphy_gainctrl(pi); @@ -19357,8 +19345,7 @@ static void wlc_phy_spurwar_nphy(struct brcms_phy *pi) } if (isAdjustNoiseVar) { - numTonesAdjust = sizeof(nphy_adj_tone_id_buf) / - sizeof(nphy_adj_tone_id_buf[0]); + numTonesAdjust = ARRAY_SIZE(nphy_adj_tone_id_buf); wlc_phy_adjust_min_noisevar_nphy( pi, @@ -25204,32 +25191,26 @@ static u8 wlc_phy_a3_nphy(struct brcms_phy *pi, u8 start_gain, u8 core) phy_a15 = pad_gain_codes_used_2057rev5; phy_a13 = - sizeof(pad_gain_codes_used_2057rev5) / - sizeof(pad_gain_codes_used_2057rev5 - [0]) - 1; + ARRAY_SIZE(pad_gain_codes_used_2057rev5) - 1; } else if ((pi->pubpi.radiorev == 7) || (pi->pubpi.radiorev == 8)) { phy_a15 = pad_gain_codes_used_2057rev7; phy_a13 = - sizeof(pad_gain_codes_used_2057rev7) / - sizeof(pad_gain_codes_used_2057rev7 - [0]) - 1; + ARRAY_SIZE(pad_gain_codes_used_2057rev7) - 1; } else { phy_a15 = pad_all_gain_codes_2057; - phy_a13 = sizeof(pad_all_gain_codes_2057) / - sizeof(pad_all_gain_codes_2057[0]) - + phy_a13 = ARRAY_SIZE(pad_all_gain_codes_2057) - 1; } } else { phy_a15 = pga_all_gain_codes_2057; - phy_a13 = sizeof(pga_all_gain_codes_2057) / - sizeof(pga_all_gain_codes_2057[0]) - 1; + phy_a13 = ARRAY_SIZE(pga_all_gain_codes_2057) - 1; } phy_a14 = 0; diff --git a/trunk/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h b/trunk/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h index 5fb17d53c9b2..333193f20e1c 100644 --- a/trunk/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h +++ b/trunk/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h @@ -17,17 +17,7 @@ #ifndef _BRCM_HW_IDS_H_ #define _BRCM_HW_IDS_H_ -#define BCM4325_D11DUAL_ID 0x431b -#define BCM4325_D11G_ID 0x431c -#define BCM4325_D11A_ID 0x431d - -#define BCM4329_D11N2G_ID 0x432f /* 4329 802.11n 2.4G device */ -#define BCM4329_D11N5G_ID 0x4330 /* 4329 802.11n 5G device */ -#define BCM4329_D11NDUAL_ID 0x432e - -#define BCM4319_D11N_ID 0x4337 /* 4319 802.11n dualband device */ -#define BCM4319_D11N2G_ID 0x4338 /* 4319 802.11n 2.4G device */ -#define BCM4319_D11N5G_ID 0x4339 /* 4319 802.11n 5G device */ +#define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */ #define BCM43224_D11N_ID 0x4353 /* 43224 802.11n dualband device */ #define BCM43224_D11N_ID_VEN1 0x0576 /* Vendor specific 43224 802.11n db */ @@ -37,23 +27,15 @@ #define BCM43236_D11N_ID 0x4346 /* 43236 802.11n dualband device */ #define BCM43236_D11N2G_ID 0x4347 /* 43236 802.11n 2.4GHz device */ -#define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */ - -/* Chip IDs */ -#define BCM4313_CHIP_ID 0x4313 /* 4313 chip id */ -#define BCM4319_CHIP_ID 0x4319 /* 4319 chip id */ - -#define BCM43224_CHIP_ID 43224 /* 43224 chipcommon chipid */ -#define BCM43225_CHIP_ID 43225 /* 43225 chipcommon chipid */ -#define BCM43421_CHIP_ID 43421 /* 43421 chipcommon chipid */ -#define BCM43235_CHIP_ID 43235 /* 43235 chipcommon chipid */ -#define BCM43236_CHIP_ID 43236 /* 43236 chipcommon chipid */ -#define BCM43238_CHIP_ID 43238 /* 43238 chipcommon chipid */ -#define BCM4329_CHIP_ID 0x4329 /* 4329 chipcommon chipid */ -#define BCM4325_CHIP_ID 0x4325 /* 4325 chipcommon chipid */ -#define BCM4331_CHIP_ID 0x4331 /* 4331 chipcommon chipid */ -#define BCM4336_CHIP_ID 0x4336 /* 4336 chipcommon chipid */ -#define BCM4330_CHIP_ID 0x4330 /* 4330 chipcommon chipid */ -#define BCM6362_CHIP_ID 0x6362 /* 6362 chipcommon chipid */ +/* Chipcommon Core Chip IDs */ +#define BCM4313_CHIP_ID 0x4313 +#define BCM43224_CHIP_ID 43224 +#define BCM43225_CHIP_ID 43225 +#define BCM43235_CHIP_ID 43235 +#define BCM43236_CHIP_ID 43236 +#define BCM43238_CHIP_ID 43238 +#define BCM4329_CHIP_ID 0x4329 +#define BCM4330_CHIP_ID 0x4330 +#define BCM4331_CHIP_ID 0x4331 #endif /* _BRCM_HW_IDS_H_ */ diff --git a/trunk/drivers/net/wireless/hostap/hostap_main.c b/trunk/drivers/net/wireless/hostap/hostap_main.c index bfa0d54221e8..627bc12074c7 100644 --- a/trunk/drivers/net/wireless/hostap/hostap_main.c +++ b/trunk/drivers/net/wireless/hostap/hostap_main.c @@ -244,8 +244,7 @@ u16 hostap_tx_callback_register(local_info_t *local, unsigned long flags; struct hostap_tx_callback_info *entry; - entry = kmalloc(sizeof(*entry), - GFP_ATOMIC); + entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (entry == NULL) return 0; diff --git a/trunk/drivers/net/wireless/hostap/hostap_pci.c b/trunk/drivers/net/wireless/hostap/hostap_pci.c index 972a9c3af39e..05ca3402dca7 100644 --- a/trunk/drivers/net/wireless/hostap/hostap_pci.c +++ b/trunk/drivers/net/wireless/hostap/hostap_pci.c @@ -457,18 +457,4 @@ static struct pci_driver prism2_pci_driver = { #endif /* CONFIG_PM */ }; - -static int __init init_prism2_pci(void) -{ - return pci_register_driver(&prism2_pci_driver); -} - - -static void __exit exit_prism2_pci(void) -{ - pci_unregister_driver(&prism2_pci_driver); -} - - -module_init(init_prism2_pci); -module_exit(exit_prism2_pci); +module_pci_driver(prism2_pci_driver); diff --git a/trunk/drivers/net/wireless/hostap/hostap_plx.c b/trunk/drivers/net/wireless/hostap/hostap_plx.c index 33e79037770b..c3d067ee4db9 100644 --- a/trunk/drivers/net/wireless/hostap/hostap_plx.c +++ b/trunk/drivers/net/wireless/hostap/hostap_plx.c @@ -616,18 +616,4 @@ static struct pci_driver prism2_plx_driver = { .remove = prism2_plx_remove, }; - -static int __init init_prism2_plx(void) -{ - return pci_register_driver(&prism2_plx_driver); -} - - -static void __exit exit_prism2_plx(void) -{ - pci_unregister_driver(&prism2_plx_driver); -} - - -module_init(init_prism2_plx); -module_exit(exit_prism2_plx); +module_pci_driver(prism2_plx_driver); diff --git a/trunk/drivers/net/wireless/ipw2x00/ipw.h b/trunk/drivers/net/wireless/ipw2x00/ipw.h new file mode 100644 index 000000000000..4007bf5ed6f3 --- /dev/null +++ b/trunk/drivers/net/wireless/ipw2x00/ipw.h @@ -0,0 +1,23 @@ +/* + * Intel Pro/Wireless 2100, 2200BG, 2915ABG network connection driver + * + * Copyright 2012 Stanislav Yakovlev + * + * 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 __IPW_H__ +#define __IPW_H__ + +#include + +static const u32 ipw_cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, +}; + +#endif diff --git a/trunk/drivers/net/wireless/ipw2x00/ipw2100.c b/trunk/drivers/net/wireless/ipw2x00/ipw2100.c index f0551f807f69..9cfae0c08707 100644 --- a/trunk/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/trunk/drivers/net/wireless/ipw2x00/ipw2100.c @@ -166,6 +166,7 @@ that only one external action is invoked at a time. #include #include "ipw2100.h" +#include "ipw.h" #define IPW2100_VERSION "git-1.2.2" @@ -343,38 +344,50 @@ static struct iw_handler_def ipw2100_wx_handler_def; static inline void read_register(struct net_device *dev, u32 reg, u32 * val) { - *val = readl((void __iomem *)(dev->base_addr + reg)); + struct ipw2100_priv *priv = libipw_priv(dev); + + *val = ioread32(priv->ioaddr + reg); IPW_DEBUG_IO("r: 0x%08X => 0x%08X\n", reg, *val); } static inline void write_register(struct net_device *dev, u32 reg, u32 val) { - writel(val, (void __iomem *)(dev->base_addr + reg)); + struct ipw2100_priv *priv = libipw_priv(dev); + + iowrite32(val, priv->ioaddr + reg); IPW_DEBUG_IO("w: 0x%08X <= 0x%08X\n", reg, val); } static inline void read_register_word(struct net_device *dev, u32 reg, u16 * val) { - *val = readw((void __iomem *)(dev->base_addr + reg)); + struct ipw2100_priv *priv = libipw_priv(dev); + + *val = ioread16(priv->ioaddr + reg); IPW_DEBUG_IO("r: 0x%08X => %04X\n", reg, *val); } static inline void read_register_byte(struct net_device *dev, u32 reg, u8 * val) { - *val = readb((void __iomem *)(dev->base_addr + reg)); + struct ipw2100_priv *priv = libipw_priv(dev); + + *val = ioread8(priv->ioaddr + reg); IPW_DEBUG_IO("r: 0x%08X => %02X\n", reg, *val); } static inline void write_register_word(struct net_device *dev, u32 reg, u16 val) { - writew(val, (void __iomem *)(dev->base_addr + reg)); + struct ipw2100_priv *priv = libipw_priv(dev); + + iowrite16(val, priv->ioaddr + reg); IPW_DEBUG_IO("w: 0x%08X <= %04X\n", reg, val); } static inline void write_register_byte(struct net_device *dev, u32 reg, u8 val) { - writeb(val, (void __iomem *)(dev->base_addr + reg)); + struct ipw2100_priv *priv = libipw_priv(dev); + + iowrite8(val, priv->ioaddr + reg); IPW_DEBUG_IO("w: 0x%08X =< %02X\n", reg, val); } @@ -506,13 +519,13 @@ static void read_nic_memory(struct net_device *dev, u32 addr, u32 len, read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i, buf); } -static inline int ipw2100_hw_is_adapter_in_system(struct net_device *dev) +static bool ipw2100_hw_is_adapter_in_system(struct net_device *dev) { - return (dev->base_addr && - (readl - ((void __iomem *)(dev->base_addr + - IPW_REG_DOA_DEBUG_AREA_START)) - == IPW_DATA_DOA_DEBUG_VALUE)); + u32 dbg; + + read_register(dev, IPW_REG_DOA_DEBUG_AREA_START, &dbg); + + return dbg == IPW_DATA_DOA_DEBUG_VALUE; } static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord, @@ -1946,11 +1959,12 @@ static int ipw2100_wdev_init(struct net_device *dev) wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = bg_band; } + wdev->wiphy->cipher_suites = ipw_cipher_suites; + wdev->wiphy->n_cipher_suites = ARRAY_SIZE(ipw_cipher_suites); + set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev); - if (wiphy_register(wdev->wiphy)) { - ipw2100_down(priv); + if (wiphy_register(wdev->wiphy)) return -EIO; - } return 0; } @@ -3773,7 +3787,7 @@ IPW2100_ORD(STAT_TX_HOST_REQUESTS, "requested Host Tx's (MSDU)"), IPW2100_ORD(COUNTRY_CODE, "IEEE country code as recv'd from beacon"), IPW2100_ORD(COUNTRY_CHANNELS, - "channels suported by country"), + "channels supported by country"), IPW2100_ORD(RESET_CNT, "adapter resets (warm)"), IPW2100_ORD(BEACON_INTERVAL, "Beacon interval"), IPW2100_ORD(ANTENNA_DIVERSITY, @@ -4062,7 +4076,7 @@ static int ipw2100_switch_mode(struct ipw2100_priv *priv, u32 mode) ipw2100_firmware.version = 0; #endif - printk(KERN_INFO "%s: Reseting on mode change.\n", priv->net_dev->name); + printk(KERN_INFO "%s: Resetting on mode change.\n", priv->net_dev->name); priv->reset_backoff = 0; schedule_reset(priv); @@ -6082,9 +6096,7 @@ static const struct net_device_ops ipw2100_netdev_ops = { /* Look into using netdev destructor to shutdown libipw? */ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, - void __iomem * base_addr, - unsigned long mem_start, - unsigned long mem_len) + void __iomem * ioaddr) { struct ipw2100_priv *priv; struct net_device *dev; @@ -6096,6 +6108,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, priv->ieee = netdev_priv(dev); priv->pci_dev = pci_dev; priv->net_dev = dev; + priv->ioaddr = ioaddr; priv->ieee->hard_start_xmit = ipw2100_tx; priv->ieee->set_security = shim__set_security; @@ -6111,10 +6124,6 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, dev->watchdog_timeo = 3 * HZ; dev->irq = 0; - dev->base_addr = (unsigned long)base_addr; - dev->mem_start = mem_start; - dev->mem_end = dev->mem_start + mem_len - 1; - /* NOTE: We don't use the wireless_handlers hook * in dev as the system will start throwing WX requests * to us before we're actually initialized and it just @@ -6215,8 +6224,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, static int ipw2100_pci_init_one(struct pci_dev *pci_dev, const struct pci_device_id *ent) { - unsigned long mem_start, mem_len, mem_flags; - void __iomem *base_addr = NULL; + void __iomem *ioaddr; struct net_device *dev = NULL; struct ipw2100_priv *priv = NULL; int err = 0; @@ -6225,18 +6233,14 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, IPW_DEBUG_INFO("enter\n"); - mem_start = pci_resource_start(pci_dev, 0); - mem_len = pci_resource_len(pci_dev, 0); - mem_flags = pci_resource_flags(pci_dev, 0); - - if ((mem_flags & IORESOURCE_MEM) != IORESOURCE_MEM) { + if (!(pci_resource_flags(pci_dev, 0) & IORESOURCE_MEM)) { IPW_DEBUG_INFO("weird - resource type is not memory\n"); err = -ENODEV; - goto fail; + goto out; } - base_addr = ioremap_nocache(mem_start, mem_len); - if (!base_addr) { + ioaddr = pci_iomap(pci_dev, 0, 0); + if (!ioaddr) { printk(KERN_WARNING DRV_NAME "Error calling ioremap_nocache.\n"); err = -EIO; @@ -6244,7 +6248,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, } /* allocate and initialize our net_device */ - dev = ipw2100_alloc_device(pci_dev, base_addr, mem_start, mem_len); + dev = ipw2100_alloc_device(pci_dev, ioaddr); if (!dev) { printk(KERN_WARNING DRV_NAME "Error calling ipw2100_alloc_device.\n"); @@ -6325,6 +6329,11 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, printk(KERN_INFO DRV_NAME ": Detected Intel PRO/Wireless 2100 Network Connection\n"); + err = ipw2100_wdev_init(dev); + if (err) + goto fail; + registered = 1; + /* Bring up the interface. Pre 0.46, after we registered the * network device we would call ipw2100_up. This introduced a race * condition with newer hotplug configurations (network was coming @@ -6341,11 +6350,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, "Error calling register_netdev.\n"); goto fail; } - registered = 1; - - err = ipw2100_wdev_init(dev); - if (err) - goto fail; + registered = 2; mutex_lock(&priv->action_mutex); @@ -6379,18 +6384,21 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, priv->status |= STATUS_INITIALIZED; mutex_unlock(&priv->action_mutex); - - return 0; +out: + return err; fail_unlock: mutex_unlock(&priv->action_mutex); - wiphy_unregister(priv->ieee->wdev.wiphy); - kfree(priv->ieee->bg_band.channels); fail: if (dev) { - if (registered) + if (registered >= 2) unregister_netdev(dev); + if (registered) { + wiphy_unregister(priv->ieee->wdev.wiphy); + kfree(priv->ieee->bg_band.channels); + } + ipw2100_hw_stop_adapter(priv); ipw2100_disable_interrupts(priv); @@ -6409,63 +6417,56 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, pci_set_drvdata(pci_dev, NULL); } - if (base_addr) - iounmap(base_addr); + pci_iounmap(pci_dev, ioaddr); pci_release_regions(pci_dev); pci_disable_device(pci_dev); - - return err; + goto out; } static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev) { struct ipw2100_priv *priv = pci_get_drvdata(pci_dev); - struct net_device *dev; + struct net_device *dev = priv->net_dev; - if (priv) { - mutex_lock(&priv->action_mutex); + mutex_lock(&priv->action_mutex); - priv->status &= ~STATUS_INITIALIZED; + priv->status &= ~STATUS_INITIALIZED; - dev = priv->net_dev; - sysfs_remove_group(&pci_dev->dev.kobj, - &ipw2100_attribute_group); + sysfs_remove_group(&pci_dev->dev.kobj, &ipw2100_attribute_group); #ifdef CONFIG_PM - if (ipw2100_firmware.version) - ipw2100_release_firmware(priv, &ipw2100_firmware); + if (ipw2100_firmware.version) + ipw2100_release_firmware(priv, &ipw2100_firmware); #endif - /* Take down the hardware */ - ipw2100_down(priv); + /* Take down the hardware */ + ipw2100_down(priv); - /* Release the mutex so that the network subsystem can - * complete any needed calls into the driver... */ - mutex_unlock(&priv->action_mutex); + /* Release the mutex so that the network subsystem can + * complete any needed calls into the driver... */ + mutex_unlock(&priv->action_mutex); - /* Unregister the device first - this results in close() - * being called if the device is open. If we free storage - * first, then close() will crash. */ - unregister_netdev(dev); + /* Unregister the device first - this results in close() + * being called if the device is open. If we free storage + * first, then close() will crash. + * FIXME: remove the comment above. */ + unregister_netdev(dev); - ipw2100_kill_works(priv); + ipw2100_kill_works(priv); - ipw2100_queues_free(priv); + ipw2100_queues_free(priv); - /* Free potential debugging firmware snapshot */ - ipw2100_snapshot_free(priv); + /* Free potential debugging firmware snapshot */ + ipw2100_snapshot_free(priv); - if (dev->irq) - free_irq(dev->irq, priv); + free_irq(dev->irq, priv); - if (dev->base_addr) - iounmap((void __iomem *)dev->base_addr); + pci_iounmap(pci_dev, priv->ioaddr); - /* wiphy_unregister needs to be here, before free_libipw */ - wiphy_unregister(priv->ieee->wdev.wiphy); - kfree(priv->ieee->bg_band.channels); - free_libipw(dev, 0); - } + /* wiphy_unregister needs to be here, before free_libipw */ + wiphy_unregister(priv->ieee->wdev.wiphy); + kfree(priv->ieee->bg_band.channels); + free_libipw(dev, 0); pci_release_regions(pci_dev); pci_disable_device(pci_dev); @@ -8508,8 +8509,7 @@ static void ipw2100_release_firmware(struct ipw2100_priv *priv, struct ipw2100_fw *fw) { fw->version = 0; - if (fw->fw_entry) - release_firmware(fw->fw_entry); + release_firmware(fw->fw_entry); fw->fw_entry = NULL; } @@ -8609,7 +8609,7 @@ static int ipw2100_ucode_download(struct ipw2100_priv *priv, struct net_device *dev = priv->net_dev; const unsigned char *microcode_data = fw->uc.data; unsigned int microcode_data_left = fw->uc.size; - void __iomem *reg = (void __iomem *)dev->base_addr; + void __iomem *reg = priv->ioaddr; struct symbol_alive_response response; int i, j; diff --git a/trunk/drivers/net/wireless/ipw2x00/ipw2100.h b/trunk/drivers/net/wireless/ipw2x00/ipw2100.h index 99cba968aa58..973125242490 100644 --- a/trunk/drivers/net/wireless/ipw2x00/ipw2100.h +++ b/trunk/drivers/net/wireless/ipw2x00/ipw2100.h @@ -135,15 +135,6 @@ enum { IPW_HW_STATE_ENABLED = 0 }; -struct ssid_context { - char ssid[IW_ESSID_MAX_SIZE + 1]; - int ssid_len; - unsigned char bssid[ETH_ALEN]; - int port_type; - int channel; - -}; - extern const char *port_type_str[]; extern const char *band_str[]; @@ -488,6 +479,7 @@ enum { #define CAP_PRIVACY_ON (1<<1) /* Off = No privacy */ struct ipw2100_priv { + void __iomem *ioaddr; int stop_hang_check; /* Set 1 when shutting down to kill hang_check */ int stop_rf_kill; /* Set 1 when shutting down to kill rf_kill */ diff --git a/trunk/drivers/net/wireless/ipw2x00/ipw2200.c b/trunk/drivers/net/wireless/ipw2x00/ipw2200.c index 1779db3aa2b0..0036737fe8e3 100644 --- a/trunk/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/trunk/drivers/net/wireless/ipw2x00/ipw2200.c @@ -34,6 +34,7 @@ #include #include #include "ipw2200.h" +#include "ipw.h" #ifndef KBUILD_EXTMOD @@ -3668,8 +3669,7 @@ static int ipw_load(struct ipw_priv *priv) priv->rxq = NULL; } ipw_tx_queue_free(priv); - if (raw) - release_firmware(raw); + release_firmware(raw); #ifdef CONFIG_PM fw_loaded = 0; raw = NULL; @@ -7035,7 +7035,7 @@ static int ipw_qos_activate(struct ipw_priv *priv, cpu_to_le16(burst_duration); } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) { if (type == IEEE_B) { - IPW_DEBUG_QOS("QoS activate IBSS nework mode %d\n", + IPW_DEBUG_QOS("QoS activate IBSS network mode %d\n", type); if (priv->qos_data.qos_enable == 0) active_one = &def_parameters_CCK; @@ -11443,20 +11443,6 @@ static void ipw_bg_down(struct work_struct *work) mutex_unlock(&priv->mutex); } -/* Called by register_netdev() */ -static int ipw_net_init(struct net_device *dev) -{ - int rc = 0; - struct ipw_priv *priv = libipw_priv(dev); - - mutex_lock(&priv->mutex); - if (ipw_up(priv)) - rc = -EIO; - mutex_unlock(&priv->mutex); - - return rc; -} - static int ipw_wdev_init(struct net_device *dev) { int i, rc = 0; @@ -11544,6 +11530,9 @@ static int ipw_wdev_init(struct net_device *dev) wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = a_band; } + wdev->wiphy->cipher_suites = ipw_cipher_suites; + wdev->wiphy->n_cipher_suites = ARRAY_SIZE(ipw_cipher_suites); + set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev); /* With that information in place, we can now register the wiphy... */ @@ -11722,7 +11711,6 @@ static void ipw_prom_free(struct ipw_priv *priv) #endif static const struct net_device_ops ipw_netdev_ops = { - .ndo_init = ipw_net_init, .ndo_open = ipw_net_open, .ndo_stop = ipw_net_stop, .ndo_set_rx_mode = ipw_net_set_multicast_list, @@ -11837,10 +11825,6 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev, net_dev->wireless_data = &priv->wireless_data; net_dev->wireless_handlers = &ipw_wx_handler_def; net_dev->ethtool_ops = &ipw_ethtool_ops; - net_dev->irq = pdev->irq; - net_dev->base_addr = (unsigned long)priv->hw_base; - net_dev->mem_start = pci_resource_start(pdev, 0); - net_dev->mem_end = net_dev->mem_start + pci_resource_len(pdev, 0) - 1; err = sysfs_create_group(&pdev->dev.kobj, &ipw_attribute_group); if (err) { @@ -11849,17 +11833,24 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev, goto out_release_irq; } - mutex_unlock(&priv->mutex); - err = register_netdev(net_dev); - if (err) { - IPW_ERROR("failed to register network device\n"); + if (ipw_up(priv)) { + mutex_unlock(&priv->mutex); + err = -EIO; goto out_remove_sysfs; } + mutex_unlock(&priv->mutex); + err = ipw_wdev_init(net_dev); if (err) { IPW_ERROR("failed to register wireless device\n"); - goto out_unregister_netdev; + goto out_remove_sysfs; + } + + err = register_netdev(net_dev); + if (err) { + IPW_ERROR("failed to register network device\n"); + goto out_unregister_wiphy; } #ifdef CONFIG_IPW2200_PROMISCUOUS @@ -11868,10 +11859,8 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev, if (err) { IPW_ERROR("Failed to register promiscuous network " "device (error %d).\n", err); - wiphy_unregister(priv->ieee->wdev.wiphy); - kfree(priv->ieee->a_band.channels); - kfree(priv->ieee->bg_band.channels); - goto out_unregister_netdev; + unregister_netdev(priv->net_dev); + goto out_unregister_wiphy; } } #endif @@ -11883,8 +11872,10 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev, return 0; - out_unregister_netdev: - unregister_netdev(priv->net_dev); + out_unregister_wiphy: + wiphy_unregister(priv->ieee->wdev.wiphy); + kfree(priv->ieee->a_band.channels); + kfree(priv->ieee->bg_band.channels); out_remove_sysfs: sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group); out_release_irq: diff --git a/trunk/drivers/net/wireless/ipw2x00/libipw.h b/trunk/drivers/net/wireless/ipw2x00/libipw.h index 8874588fb929..0b22fb421735 100644 --- a/trunk/drivers/net/wireless/ipw2x00/libipw.h +++ b/trunk/drivers/net/wireless/ipw2x00/libipw.h @@ -584,61 +584,6 @@ struct libipw_tim_parameters { /*******************************************************/ -enum { /* libipw_basic_report.map */ - LIBIPW_BASIC_MAP_BSS = (1 << 0), - LIBIPW_BASIC_MAP_OFDM = (1 << 1), - LIBIPW_BASIC_MAP_UNIDENTIFIED = (1 << 2), - LIBIPW_BASIC_MAP_RADAR = (1 << 3), - LIBIPW_BASIC_MAP_UNMEASURED = (1 << 4), - /* Bits 5-7 are reserved */ - -}; -struct libipw_basic_report { - u8 channel; - __le64 start_time; - __le16 duration; - u8 map; -} __packed; - -enum { /* libipw_measurement_request.mode */ - /* Bit 0 is reserved */ - LIBIPW_MEASUREMENT_ENABLE = (1 << 1), - LIBIPW_MEASUREMENT_REQUEST = (1 << 2), - LIBIPW_MEASUREMENT_REPORT = (1 << 3), - /* Bits 4-7 are reserved */ -}; - -enum { - LIBIPW_REPORT_BASIC = 0, /* required */ - LIBIPW_REPORT_CCA = 1, /* optional */ - LIBIPW_REPORT_RPI = 2, /* optional */ - /* 3-255 reserved */ -}; - -struct libipw_measurement_params { - u8 channel; - __le64 start_time; - __le16 duration; -} __packed; - -struct libipw_measurement_request { - struct libipw_info_element ie; - u8 token; - u8 mode; - u8 type; - struct libipw_measurement_params params[0]; -} __packed; - -struct libipw_measurement_report { - struct libipw_info_element ie; - u8 token; - u8 mode; - u8 type; - union { - struct libipw_basic_report basic[0]; - } u; -} __packed; - struct libipw_tpc_report { u8 transmit_power; u8 link_margin; diff --git a/trunk/drivers/net/wireless/ipw2x00/libipw_rx.c b/trunk/drivers/net/wireless/ipw2x00/libipw_rx.c index c4955d25a19a..02e057923236 100644 --- a/trunk/drivers/net/wireless/ipw2x00/libipw_rx.c +++ b/trunk/drivers/net/wireless/ipw2x00/libipw_rx.c @@ -77,8 +77,8 @@ static struct libipw_frag_entry *libipw_frag_cache_find(struct if (entry->skb != NULL && entry->seq == seq && (entry->last_frag + 1 == frag || frag == -1) && - !compare_ether_addr(entry->src_addr, src) && - !compare_ether_addr(entry->dst_addr, dst)) + ether_addr_equal(entry->src_addr, src) && + ether_addr_equal(entry->dst_addr, dst)) return entry; } @@ -245,12 +245,12 @@ static int libipw_is_eapol_frame(struct libipw_device *ieee, /* check that the frame is unicast frame to us */ if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_TODS && - !compare_ether_addr(hdr->addr1, dev->dev_addr) && - !compare_ether_addr(hdr->addr3, dev->dev_addr)) { + ether_addr_equal(hdr->addr1, dev->dev_addr) && + ether_addr_equal(hdr->addr3, dev->dev_addr)) { /* ToDS frame with own addr BSSID and DA */ } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS && - !compare_ether_addr(hdr->addr1, dev->dev_addr)) { + ether_addr_equal(hdr->addr1, dev->dev_addr)) { /* FromDS frame with own addr as DA */ } else return 0; @@ -523,8 +523,8 @@ int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb, if (ieee->iw_mode == IW_MODE_MASTER && !wds && (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == - IEEE80211_FCTL_FROMDS && ieee->stadev - && !compare_ether_addr(hdr->addr2, ieee->assoc_ap_addr)) { + IEEE80211_FCTL_FROMDS && ieee->stadev && + ether_addr_equal(hdr->addr2, ieee->assoc_ap_addr)) { /* Frame from BSSID of the AP for which we are a client */ skb->dev = dev = ieee->stadev; stats = hostap_get_stats(dev); @@ -1468,7 +1468,7 @@ static inline int is_same_network(struct libipw_network *src, * as one network */ return ((src->ssid_len == dst->ssid_len) && (src->channel == dst->channel) && - !compare_ether_addr(src->bssid, dst->bssid) && + ether_addr_equal(src->bssid, dst->bssid) && !memcmp(src->ssid, dst->ssid, src->ssid_len)); } diff --git a/trunk/drivers/net/wireless/iwlegacy/3945.c b/trunk/drivers/net/wireless/iwlegacy/3945.c index b25c01be0d90..87e539894330 100644 --- a/trunk/drivers/net/wireless/iwlegacy/3945.c +++ b/trunk/drivers/net/wireless/iwlegacy/3945.c @@ -453,10 +453,10 @@ il3945_is_network_packet(struct il_priv *il, struct ieee80211_hdr *header) switch (il->iw_mode) { case NL80211_IFTYPE_ADHOC: /* Header: Dest. | Source | BSSID */ /* packets to our IBSS update information */ - return !compare_ether_addr(header->addr3, il->bssid); + return ether_addr_equal(header->addr3, il->bssid); case NL80211_IFTYPE_STATION: /* Header: Dest. | AP{BSSID} | Source */ /* packets to our IBSS update information */ - return !compare_ether_addr(header->addr2, il->bssid); + return ether_addr_equal(header->addr2, il->bssid); default: return 1; } diff --git a/trunk/drivers/net/wireless/iwlegacy/4965-mac.c b/trunk/drivers/net/wireless/iwlegacy/4965-mac.c index c46275a92565..509301a5e7e2 100644 --- a/trunk/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/trunk/drivers/net/wireless/iwlegacy/4965-mac.c @@ -2565,7 +2565,7 @@ il4965_find_station(struct il_priv *il, const u8 *addr) spin_lock_irqsave(&il->sta_lock, flags); for (i = start; i < il->hw_params.max_stations; i++) if (il->stations[i].used && - (!compare_ether_addr(il->stations[i].sta.sta.addr, addr))) { + ether_addr_equal(il->stations[i].sta.sta.addr, addr)) { ret = i; goto out; } @@ -2850,9 +2850,9 @@ void il4965_hwrate_to_tx_control(struct il_priv *il, u32 rate_n_flags, struct ieee80211_tx_info *info) { - struct ieee80211_tx_rate *r = &info->control.rates[0]; + struct ieee80211_tx_rate *r = &info->status.rates[0]; - info->antenna_sel_tx = + info->status.antenna = ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS); if (rate_n_flags & RATE_MCS_HT_MSK) r->flags |= IEEE80211_TX_RC_MCS; diff --git a/trunk/drivers/net/wireless/iwlegacy/4965-rs.c b/trunk/drivers/net/wireless/iwlegacy/4965-rs.c index 11ab1247fae1..f3b8e91aa3dc 100644 --- a/trunk/drivers/net/wireless/iwlegacy/4965-rs.c +++ b/trunk/drivers/net/wireless/iwlegacy/4965-rs.c @@ -873,7 +873,7 @@ il4965_rs_tx_status(void *il_r, struct ieee80211_supported_band *sband, tbl_type.is_SGI != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI) || tbl_type.is_ht40 != !!(mac_flags & IEEE80211_TX_RC_40_MHZ_WIDTH) || tbl_type.is_dup != !!(mac_flags & IEEE80211_TX_RC_DUP_DATA) || - tbl_type.ant_type != info->antenna_sel_tx || + tbl_type.ant_type != info->status.antenna || !!(tx_rate & RATE_MCS_HT_MSK) != !!(mac_flags & IEEE80211_TX_RC_MCS) || !!(tx_rate & RATE_MCS_GF_MSK) != !!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD) || rs_idx != mac_idx) { diff --git a/trunk/drivers/net/wireless/iwlegacy/common.c b/trunk/drivers/net/wireless/iwlegacy/common.c index eaf249452e51..cbf2dc18341f 100644 --- a/trunk/drivers/net/wireless/iwlegacy/common.c +++ b/trunk/drivers/net/wireless/iwlegacy/common.c @@ -1896,8 +1896,8 @@ il_prep_station(struct il_priv *il, const u8 *addr, bool is_ap, sta_id = il->hw_params.bcast_id; else for (i = IL_STA_ID; i < il->hw_params.max_stations; i++) { - if (!compare_ether_addr - (il->stations[i].sta.sta.addr, addr)) { + if (ether_addr_equal(il->stations[i].sta.sta.addr, + addr)) { sta_id = i; break; } @@ -1926,7 +1926,7 @@ il_prep_station(struct il_priv *il, const u8 *addr, bool is_ap, if ((il->stations[sta_id].used & IL_STA_DRIVER_ACTIVE) && (il->stations[sta_id].used & IL_STA_UCODE_ACTIVE) && - !compare_ether_addr(il->stations[sta_id].sta.sta.addr, addr)) { + ether_addr_equal(il->stations[sta_id].sta.sta.addr, addr)) { D_ASSOC("STA %d (%pM) already added, not adding again.\n", sta_id, addr); return sta_id; @@ -3744,10 +3744,10 @@ il_full_rxon_required(struct il_priv *il) /* These items are only settable from the full RXON command */ CHK(!il_is_associated(il)); - CHK(compare_ether_addr(staging->bssid_addr, active->bssid_addr)); - CHK(compare_ether_addr(staging->node_addr, active->node_addr)); - CHK(compare_ether_addr - (staging->wlap_bssid_addr, active->wlap_bssid_addr)); + CHK(!ether_addr_equal(staging->bssid_addr, active->bssid_addr)); + CHK(!ether_addr_equal(staging->node_addr, active->node_addr)); + CHK(!ether_addr_equal(staging->wlap_bssid_addr, + active->wlap_bssid_addr)); CHK_NEQ(staging->dev_type, active->dev_type); CHK_NEQ(staging->channel, active->channel); CHK_NEQ(staging->air_propagation, active->air_propagation); diff --git a/trunk/drivers/net/wireless/iwlwifi/Kconfig b/trunk/drivers/net/wireless/iwlwifi/Kconfig index 2fe62730dddd..db6c6e528022 100644 --- a/trunk/drivers/net/wireless/iwlwifi/Kconfig +++ b/trunk/drivers/net/wireless/iwlwifi/Kconfig @@ -113,20 +113,21 @@ config IWLWIFI_DEVICE_TESTMODE generic netlink message via NL80211_TESTMODE channel. config IWLWIFI_P2P - bool "iwlwifi experimental P2P support" - depends on IWLWIFI - help - This option enables experimental P2P support for some devices - based on microcode support. Since P2P support is still under - development, this option may even enable it for some devices - now that turn out to not support it in the future due to - microcode restrictions. + def_bool y + bool "iwlwifi experimental P2P support" + depends on IWLWIFI + help + This option enables experimental P2P support for some devices + based on microcode support. Since P2P support is still under + development, this option may even enable it for some devices + now that turn out to not support it in the future due to + microcode restrictions. - To determine if your microcode supports the experimental P2P - offered by this option, check if the driver advertises AP - support when it is loaded. + To determine if your microcode supports the experimental P2P + offered by this option, check if the driver advertises AP + support when it is loaded. - Say Y only if you want to experiment with P2P. + Say Y only if you want to experiment with P2P. config IWLWIFI_EXPERIMENTAL_MFP bool "support MFP (802.11w) even if uCode doesn't advertise" @@ -136,3 +137,11 @@ config IWLWIFI_EXPERIMENTAL_MFP even if the microcode doesn't advertise it. Say Y only if you want to experiment with MFP. + +config IWLWIFI_UCODE16 + bool "support uCode 16.0" + depends on IWLWIFI + help + This option enables support for uCode version 16.0. + + Say Y if you want to use 16.0 microcode. diff --git a/trunk/drivers/net/wireless/iwlwifi/Makefile b/trunk/drivers/net/wireless/iwlwifi/Makefile index 85d163ed3db1..406f297a9a56 100644 --- a/trunk/drivers/net/wireless/iwlwifi/Makefile +++ b/trunk/drivers/net/wireless/iwlwifi/Makefile @@ -5,9 +5,9 @@ iwlwifi-objs += iwl-ucode.o iwl-agn-tx.o iwl-debug.o iwlwifi-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o iwlwifi-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-rx.o -iwlwifi-objs += iwl-core.o iwl-eeprom.o iwl-power.o +iwlwifi-objs += iwl-eeprom.o iwl-power.o iwlwifi-objs += iwl-scan.o iwl-led.o -iwlwifi-objs += iwl-agn-rxon.o +iwlwifi-objs += iwl-agn-rxon.o iwl-agn-devices.o iwlwifi-objs += iwl-5000.o iwlwifi-objs += iwl-6000.o iwlwifi-objs += iwl-1000.o @@ -17,6 +17,8 @@ iwlwifi-objs += iwl-drv.o iwlwifi-objs += iwl-notif-wait.o iwlwifi-objs += iwl-trans-pcie.o iwl-trans-pcie-rx.o iwl-trans-pcie-tx.o + +iwlwifi-$(CONFIG_IWLWIFI_UCODE16) += iwl-phy-db.o iwlwifi-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TESTMODE) += iwl-testmode.o diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-1000.c b/trunk/drivers/net/wireless/iwlwifi/iwl-1000.c index 8d80e233bc7a..2629a6602dfa 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -24,26 +24,12 @@ * *****************************************************************************/ -#include #include -#include -#include -#include -#include -#include -#include -#include #include - -#include "iwl-eeprom.h" -#include "iwl-dev.h" -#include "iwl-core.h" -#include "iwl-io.h" -#include "iwl-agn.h" -#include "iwl-agn-hw.h" -#include "iwl-shared.h" +#include "iwl-config.h" #include "iwl-cfg.h" -#include "iwl-prph.h" +#include "iwl-csr.h" +#include "iwl-agn-hw.h" /* Highest firmware API version supported */ #define IWL1000_UCODE_API_MAX 5 @@ -57,6 +43,10 @@ #define IWL1000_UCODE_API_MIN 1 #define IWL100_UCODE_API_MIN 5 +/* EEPROM version */ +#define EEPROM_1000_TX_POWER_VERSION (4) +#define EEPROM_1000_EEPROM_VERSION (0x15C) + #define IWL1000_FW_PRE "iwlwifi-1000-" #define IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE __stringify(api) ".ucode" @@ -64,100 +54,8 @@ #define IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE __stringify(api) ".ucode" -/* - * For 1000, use advance thermal throttling critical temperature threshold, - * but legacy thermal management implementation for now. - * This is for the reason of 1000 uCode using advance thermal throttling API - * but not implement ct_kill_exit based on ct_kill exit temperature - * so the thermal throttling will still based on legacy thermal throttling - * management. - * The code here need to be modified once 1000 uCode has the advanced thermal - * throttling algorithm in place - */ -static void iwl1000_set_ct_threshold(struct iwl_priv *priv) -{ - /* want Celsius */ - hw_params(priv).ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY; - hw_params(priv).ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; -} - -/* NIC configuration for 1000 series */ -static void iwl1000_nic_config(struct iwl_priv *priv) -{ - /* set CSR_HW_CONFIG_REG for uCode use */ - iwl_set_bit(trans(priv), CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | - CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); - - /* Setting digital SVR for 1000 card to 1.32V */ - /* locking is acquired in iwl_set_bits_mask_prph() function */ - iwl_set_bits_mask_prph(trans(priv), APMG_DIGITAL_SVR_REG, - APMG_SVR_DIGITAL_VOLTAGE_1_32, - ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK); -} - -static const struct iwl_sensitivity_ranges iwl1000_sensitivity = { - .min_nrg_cck = 95, - .auto_corr_min_ofdm = 90, - .auto_corr_min_ofdm_mrc = 170, - .auto_corr_min_ofdm_x1 = 120, - .auto_corr_min_ofdm_mrc_x1 = 240, - - .auto_corr_max_ofdm = 120, - .auto_corr_max_ofdm_mrc = 210, - .auto_corr_max_ofdm_x1 = 155, - .auto_corr_max_ofdm_mrc_x1 = 290, - - .auto_corr_min_cck = 125, - .auto_corr_max_cck = 200, - .auto_corr_min_cck_mrc = 170, - .auto_corr_max_cck_mrc = 400, - .nrg_th_cck = 95, - .nrg_th_ofdm = 95, - - .barker_corr_th_min = 190, - .barker_corr_th_min_mrc = 390, - .nrg_th_cca = 62, -}; - -static void iwl1000_hw_set_hw_params(struct iwl_priv *priv) -{ - hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ); - - hw_params(priv).tx_chains_num = - num_of_ant(hw_params(priv).valid_tx_ant); - if (cfg(priv)->rx_with_siso_diversity) - hw_params(priv).rx_chains_num = 1; - else - hw_params(priv).rx_chains_num = - num_of_ant(hw_params(priv).valid_rx_ant); - - iwl1000_set_ct_threshold(priv); - - /* Set initial sensitivity parameters */ - hw_params(priv).sens = &iwl1000_sensitivity; -} - -static struct iwl_lib_ops iwl1000_lib = { - .set_hw_params = iwl1000_hw_set_hw_params, - .nic_config = iwl1000_nic_config, - .eeprom_ops = { - .regulatory_bands = { - EEPROM_REG_BAND_1_CHANNELS, - EEPROM_REG_BAND_2_CHANNELS, - EEPROM_REG_BAND_3_CHANNELS, - EEPROM_REG_BAND_4_CHANNELS, - EEPROM_REG_BAND_5_CHANNELS, - EEPROM_REG_BAND_24_HT40_CHANNELS, - EEPROM_REGULATORY_BAND_NO_HT40, - }, - }, - .temperature = iwlagn_temperature, -}; - static const struct iwl_base_params iwl1000_base_params = { .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .eeprom_size = OTP_LOW_IMAGE_SIZE, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, .max_ll_items = OTP_MAX_LL_ITEMS_1000, @@ -166,15 +64,13 @@ static const struct iwl_base_params iwl1000_base_params = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .wd_timeout = IWL_DEF_WD_TIMEOUT, + .wd_timeout = IWL_WATCHHDOG_DISABLED, .max_event_log_size = 128, - .wd_disable = true, }; static const struct iwl_ht_params iwl1000_ht_params = { .ht_greenfield_support = true, .use_rts_for_aggregation = true, /* use rts/cts protection */ - .smps_mode = IEEE80211_SMPS_DYNAMIC, }; #define IWL_DEVICE_1000 \ @@ -182,11 +78,11 @@ static const struct iwl_ht_params iwl1000_ht_params = { .ucode_api_max = IWL1000_UCODE_API_MAX, \ .ucode_api_ok = IWL1000_UCODE_API_OK, \ .ucode_api_min = IWL1000_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_1000, \ .max_inst_size = IWLAGN_RTC_INST_SIZE, \ .max_data_size = IWLAGN_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_1000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ - .lib = &iwl1000_lib, \ .base_params = &iwl1000_base_params, \ .led_mode = IWL_LED_BLINK @@ -206,11 +102,11 @@ const struct iwl_cfg iwl1000_bg_cfg = { .ucode_api_max = IWL100_UCODE_API_MAX, \ .ucode_api_ok = IWL100_UCODE_API_OK, \ .ucode_api_min = IWL100_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_100, \ .max_inst_size = IWLAGN_RTC_INST_SIZE, \ .max_data_size = IWLAGN_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_1000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ - .lib = &iwl1000_lib, \ .base_params = &iwl1000_base_params, \ .led_mode = IWL_LED_RF_STATE, \ .rx_with_siso_diversity = true diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-2000.c b/trunk/drivers/net/wireless/iwlwifi/iwl-2000.c index ea108622e0bd..7f793417c787 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -24,25 +24,12 @@ * *****************************************************************************/ -#include #include -#include -#include -#include -#include -#include -#include -#include #include - -#include "iwl-eeprom.h" -#include "iwl-dev.h" -#include "iwl-core.h" -#include "iwl-io.h" -#include "iwl-agn.h" -#include "iwl-agn-hw.h" -#include "iwl-shared.h" +#include "iwl-config.h" #include "iwl-cfg.h" +#include "iwl-agn-hw.h" +#include "iwl-commands.h" /* needed for BT for now */ /* Highest firmware API version supported */ #define IWL2030_UCODE_API_MAX 6 @@ -62,6 +49,11 @@ #define IWL105_UCODE_API_MIN 5 #define IWL135_UCODE_API_MIN 5 +/* EEPROM version */ +#define EEPROM_2000_TX_POWER_VERSION (6) +#define EEPROM_2000_EEPROM_VERSION (0x805) + + #define IWL2030_FW_PRE "iwlwifi-2030-" #define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE __stringify(api) ".ucode" @@ -74,105 +66,9 @@ #define IWL135_FW_PRE "iwlwifi-135-" #define IWL135_MODULE_FIRMWARE(api) IWL135_FW_PRE __stringify(api) ".ucode" -static void iwl2000_set_ct_threshold(struct iwl_priv *priv) -{ - /* want Celsius */ - hw_params(priv).ct_kill_threshold = CT_KILL_THRESHOLD; - hw_params(priv).ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; -} - -/* NIC configuration for 2000 series */ -static void iwl2000_nic_config(struct iwl_priv *priv) -{ - iwl_rf_config(priv); - - if (cfg(priv)->iq_invert) - iwl_set_bit(trans(priv), CSR_GP_DRIVER_REG, - CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER); -} - -static const struct iwl_sensitivity_ranges iwl2000_sensitivity = { - .min_nrg_cck = 97, - .auto_corr_min_ofdm = 80, - .auto_corr_min_ofdm_mrc = 128, - .auto_corr_min_ofdm_x1 = 105, - .auto_corr_min_ofdm_mrc_x1 = 192, - - .auto_corr_max_ofdm = 145, - .auto_corr_max_ofdm_mrc = 232, - .auto_corr_max_ofdm_x1 = 110, - .auto_corr_max_ofdm_mrc_x1 = 232, - - .auto_corr_min_cck = 125, - .auto_corr_max_cck = 175, - .auto_corr_min_cck_mrc = 160, - .auto_corr_max_cck_mrc = 310, - .nrg_th_cck = 97, - .nrg_th_ofdm = 100, - - .barker_corr_th_min = 190, - .barker_corr_th_min_mrc = 390, - .nrg_th_cca = 62, -}; - -static void iwl2000_hw_set_hw_params(struct iwl_priv *priv) -{ - hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ); - - hw_params(priv).tx_chains_num = - num_of_ant(hw_params(priv).valid_tx_ant); - if (cfg(priv)->rx_with_siso_diversity) - hw_params(priv).rx_chains_num = 1; - else - hw_params(priv).rx_chains_num = - num_of_ant(hw_params(priv).valid_rx_ant); - - iwl2000_set_ct_threshold(priv); - - /* Set initial sensitivity parameters */ - hw_params(priv).sens = &iwl2000_sensitivity; -} - -static struct iwl_lib_ops iwl2000_lib = { - .set_hw_params = iwl2000_hw_set_hw_params, - .nic_config = iwl2000_nic_config, - .eeprom_ops = { - .regulatory_bands = { - EEPROM_REG_BAND_1_CHANNELS, - EEPROM_REG_BAND_2_CHANNELS, - EEPROM_REG_BAND_3_CHANNELS, - EEPROM_REG_BAND_4_CHANNELS, - EEPROM_REG_BAND_5_CHANNELS, - EEPROM_6000_REG_BAND_24_HT40_CHANNELS, - EEPROM_REGULATORY_BAND_NO_HT40, - }, - .enhanced_txpower = true, - }, - .temperature = iwlagn_temperature, -}; - -static struct iwl_lib_ops iwl2030_lib = { - .set_hw_params = iwl2000_hw_set_hw_params, - .nic_config = iwl2000_nic_config, - .eeprom_ops = { - .regulatory_bands = { - EEPROM_REG_BAND_1_CHANNELS, - EEPROM_REG_BAND_2_CHANNELS, - EEPROM_REG_BAND_3_CHANNELS, - EEPROM_REG_BAND_4_CHANNELS, - EEPROM_REG_BAND_5_CHANNELS, - EEPROM_6000_REG_BAND_24_HT40_CHANNELS, - EEPROM_REGULATORY_BAND_NO_HT40, - }, - .enhanced_txpower = true, - }, - .temperature = iwlagn_temperature, -}; - static const struct iwl_base_params iwl2000_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, .max_ll_items = OTP_MAX_LL_ITEMS_2x00, .shadow_ram_support = true, @@ -191,7 +87,6 @@ static const struct iwl_base_params iwl2000_base_params = { static const struct iwl_base_params iwl2030_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, .max_ll_items = OTP_MAX_LL_ITEMS_2x00, .shadow_ram_support = true, @@ -226,16 +121,15 @@ static const struct iwl_bt_params iwl2030_bt_params = { .ucode_api_max = IWL2000_UCODE_API_MAX, \ .ucode_api_ok = IWL2000_UCODE_API_OK, \ .ucode_api_min = IWL2000_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_2000, \ .max_inst_size = IWL60_RTC_INST_SIZE, \ .max_data_size = IWL60_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ - .lib = &iwl2000_lib, \ .base_params = &iwl2000_base_params, \ .need_temp_offset_calib = true, \ .temp_offset_v2 = true, \ - .led_mode = IWL_LED_RF_STATE, \ - .iq_invert = true \ + .led_mode = IWL_LED_RF_STATE const struct iwl_cfg iwl2000_2bgn_cfg = { .name = "Intel(R) Centrino(R) Wireless-N 2200 BGN", @@ -254,18 +148,17 @@ const struct iwl_cfg iwl2000_2bgn_d_cfg = { .ucode_api_max = IWL2030_UCODE_API_MAX, \ .ucode_api_ok = IWL2030_UCODE_API_OK, \ .ucode_api_min = IWL2030_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_2030, \ .max_inst_size = IWL60_RTC_INST_SIZE, \ .max_data_size = IWL60_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ - .lib = &iwl2030_lib, \ .base_params = &iwl2030_base_params, \ .bt_params = &iwl2030_bt_params, \ .need_temp_offset_calib = true, \ .temp_offset_v2 = true, \ .led_mode = IWL_LED_RF_STATE, \ - .adv_pm = true, \ - .iq_invert = true \ + .adv_pm = true const struct iwl_cfg iwl2030_2bgn_cfg = { .name = "Intel(R) Centrino(R) Wireless-N 2230 BGN", @@ -278,18 +171,17 @@ const struct iwl_cfg iwl2030_2bgn_cfg = { .ucode_api_max = IWL105_UCODE_API_MAX, \ .ucode_api_ok = IWL105_UCODE_API_OK, \ .ucode_api_min = IWL105_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_105, \ .max_inst_size = IWL60_RTC_INST_SIZE, \ .max_data_size = IWL60_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ - .lib = &iwl2000_lib, \ .base_params = &iwl2000_base_params, \ .need_temp_offset_calib = true, \ .temp_offset_v2 = true, \ .led_mode = IWL_LED_RF_STATE, \ .adv_pm = true, \ - .rx_with_siso_diversity = true, \ - .iq_invert = true \ + .rx_with_siso_diversity = true const struct iwl_cfg iwl105_bgn_cfg = { .name = "Intel(R) Centrino(R) Wireless-N 105 BGN", @@ -308,19 +200,18 @@ const struct iwl_cfg iwl105_bgn_d_cfg = { .ucode_api_max = IWL135_UCODE_API_MAX, \ .ucode_api_ok = IWL135_UCODE_API_OK, \ .ucode_api_min = IWL135_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_135, \ .max_inst_size = IWL60_RTC_INST_SIZE, \ .max_data_size = IWL60_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ - .lib = &iwl2030_lib, \ .base_params = &iwl2030_base_params, \ .bt_params = &iwl2030_bt_params, \ .need_temp_offset_calib = true, \ .temp_offset_v2 = true, \ .led_mode = IWL_LED_RF_STATE, \ .adv_pm = true, \ - .rx_with_siso_diversity = true, \ - .iq_invert = true \ + .rx_with_siso_diversity = true const struct iwl_cfg iwl135_bgn_cfg = { .name = "Intel(R) Centrino(R) Wireless-N 135 BGN", diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-5000.c b/trunk/drivers/net/wireless/iwlwifi/iwl-5000.c index de0920c74cdd..8e26bc825f23 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -24,28 +24,12 @@ * *****************************************************************************/ -#include #include -#include -#include -#include -#include -#include -#include -#include -#include #include - -#include "iwl-eeprom.h" -#include "iwl-dev.h" -#include "iwl-core.h" -#include "iwl-io.h" -#include "iwl-agn.h" -#include "iwl-agn-hw.h" -#include "iwl-trans.h" -#include "iwl-shared.h" +#include "iwl-config.h" #include "iwl-cfg.h" -#include "iwl-prph.h" +#include "iwl-agn-hw.h" +#include "iwl-csr.h" /* Highest firmware API version supported */ #define IWL5000_UCODE_API_MAX 5 @@ -59,268 +43,28 @@ #define IWL5000_UCODE_API_MIN 1 #define IWL5150_UCODE_API_MIN 1 +/* EEPROM versions */ +#define EEPROM_5000_TX_POWER_VERSION (4) +#define EEPROM_5000_EEPROM_VERSION (0x11A) +#define EEPROM_5050_TX_POWER_VERSION (4) +#define EEPROM_5050_EEPROM_VERSION (0x21E) + #define IWL5000_FW_PRE "iwlwifi-5000-" #define IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE __stringify(api) ".ucode" #define IWL5150_FW_PRE "iwlwifi-5150-" #define IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE __stringify(api) ".ucode" -/* NIC configuration for 5000 series */ -static void iwl5000_nic_config(struct iwl_priv *priv) -{ - iwl_rf_config(priv); - - /* W/A : NIC is stuck in a reset state after Early PCIe power off - * (PCIe power is lost before PERST# is asserted), - * causing ME FW to lose ownership and not being able to obtain it back. - */ - iwl_set_bits_mask_prph(trans(priv), APMG_PS_CTRL_REG, - APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, - ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); -} - -static const struct iwl_sensitivity_ranges iwl5000_sensitivity = { - .min_nrg_cck = 100, - .auto_corr_min_ofdm = 90, - .auto_corr_min_ofdm_mrc = 170, - .auto_corr_min_ofdm_x1 = 105, - .auto_corr_min_ofdm_mrc_x1 = 220, - - .auto_corr_max_ofdm = 120, - .auto_corr_max_ofdm_mrc = 210, - .auto_corr_max_ofdm_x1 = 120, - .auto_corr_max_ofdm_mrc_x1 = 240, - - .auto_corr_min_cck = 125, - .auto_corr_max_cck = 200, - .auto_corr_min_cck_mrc = 200, - .auto_corr_max_cck_mrc = 400, - .nrg_th_cck = 100, - .nrg_th_ofdm = 100, - - .barker_corr_th_min = 190, - .barker_corr_th_min_mrc = 390, - .nrg_th_cca = 62, -}; - -static struct iwl_sensitivity_ranges iwl5150_sensitivity = { - .min_nrg_cck = 95, - .auto_corr_min_ofdm = 90, - .auto_corr_min_ofdm_mrc = 170, - .auto_corr_min_ofdm_x1 = 105, - .auto_corr_min_ofdm_mrc_x1 = 220, - - .auto_corr_max_ofdm = 120, - .auto_corr_max_ofdm_mrc = 210, - /* max = min for performance bug in 5150 DSP */ - .auto_corr_max_ofdm_x1 = 105, - .auto_corr_max_ofdm_mrc_x1 = 220, - - .auto_corr_min_cck = 125, - .auto_corr_max_cck = 200, - .auto_corr_min_cck_mrc = 170, - .auto_corr_max_cck_mrc = 400, - .nrg_th_cck = 95, - .nrg_th_ofdm = 95, - - .barker_corr_th_min = 190, - .barker_corr_th_min_mrc = 390, - .nrg_th_cca = 62, -}; - -#define IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF (-5) - -static s32 iwl_temp_calib_to_offset(struct iwl_shared *shrd) -{ - u16 temperature, voltage; - __le16 *temp_calib = (__le16 *)iwl_eeprom_query_addr(shrd, - EEPROM_KELVIN_TEMPERATURE); - - temperature = le16_to_cpu(temp_calib[0]); - voltage = le16_to_cpu(temp_calib[1]); - - /* offset = temp - volt / coeff */ - return (s32)(temperature - voltage / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF); -} - -static void iwl5150_set_ct_threshold(struct iwl_priv *priv) -{ - const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF; - s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY) - - iwl_temp_calib_to_offset(priv->shrd); - - hw_params(priv).ct_kill_threshold = threshold * volt2temp_coef; -} - -static void iwl5000_set_ct_threshold(struct iwl_priv *priv) -{ - /* want Celsius */ - hw_params(priv).ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY; -} - -static void iwl5000_hw_set_hw_params(struct iwl_priv *priv) -{ - hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ) | - BIT(IEEE80211_BAND_5GHZ); - - hw_params(priv).tx_chains_num = - num_of_ant(hw_params(priv).valid_tx_ant); - hw_params(priv).rx_chains_num = - num_of_ant(hw_params(priv).valid_rx_ant); - - iwl5000_set_ct_threshold(priv); - - /* Set initial sensitivity parameters */ - hw_params(priv).sens = &iwl5000_sensitivity; -} - -static void iwl5150_hw_set_hw_params(struct iwl_priv *priv) -{ - hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ) | - BIT(IEEE80211_BAND_5GHZ); - - hw_params(priv).tx_chains_num = - num_of_ant(hw_params(priv).valid_tx_ant); - hw_params(priv).rx_chains_num = - num_of_ant(hw_params(priv).valid_rx_ant); - - iwl5150_set_ct_threshold(priv); - - /* Set initial sensitivity parameters */ - hw_params(priv).sens = &iwl5150_sensitivity; -} - -static void iwl5150_temperature(struct iwl_priv *priv) -{ - u32 vt = 0; - s32 offset = iwl_temp_calib_to_offset(priv->shrd); - - vt = le32_to_cpu(priv->statistics.common.temperature); - vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset; - /* now vt hold the temperature in Kelvin */ - priv->temperature = KELVIN_TO_CELSIUS(vt); - iwl_tt_handler(priv); -} - -static int iwl5000_hw_channel_switch(struct iwl_priv *priv, - struct ieee80211_channel_switch *ch_switch) -{ - /* - * MULTI-FIXME - * See iwlagn_mac_channel_switch. - */ - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - struct iwl5000_channel_switch_cmd cmd; - const struct iwl_channel_info *ch_info; - u32 switch_time_in_usec, ucode_switch_time; - u16 ch; - u32 tsf_low; - u8 switch_count; - u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval); - struct ieee80211_vif *vif = ctx->vif; - struct iwl_host_cmd hcmd = { - .id = REPLY_CHANNEL_SWITCH, - .len = { sizeof(cmd), }, - .flags = CMD_SYNC, - .data = { &cmd, }, - }; - - cmd.band = priv->band == IEEE80211_BAND_2GHZ; - ch = ch_switch->channel->hw_value; - IWL_DEBUG_11H(priv, "channel switch from %d to %d\n", - ctx->active.channel, ch); - cmd.channel = cpu_to_le16(ch); - cmd.rxon_flags = ctx->staging.flags; - cmd.rxon_filter_flags = ctx->staging.filter_flags; - switch_count = ch_switch->count; - tsf_low = ch_switch->timestamp & 0x0ffffffff; - /* - * calculate the ucode channel switch time - * adding TSF as one of the factor for when to switch - */ - if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) { - if (switch_count > ((priv->ucode_beacon_time - tsf_low) / - beacon_interval)) { - switch_count -= (priv->ucode_beacon_time - - tsf_low) / beacon_interval; - } else - switch_count = 0; - } - if (switch_count <= 1) - cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); - else { - switch_time_in_usec = - vif->bss_conf.beacon_int * switch_count * TIME_UNIT; - ucode_switch_time = iwl_usecs_to_beacons(priv, - switch_time_in_usec, - beacon_interval); - cmd.switch_time = iwl_add_beacon_time(priv, - priv->ucode_beacon_time, - ucode_switch_time, - beacon_interval); - } - IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n", - cmd.switch_time); - ch_info = iwl_get_channel_info(priv, priv->band, ch); - if (ch_info) - cmd.expect_beacon = is_channel_radar(ch_info); - else { - IWL_ERR(priv, "invalid channel switch from %u to %u\n", - ctx->active.channel, ch); - return -EFAULT; - } - - return iwl_dvm_send_cmd(priv, &hcmd); -} - -static struct iwl_lib_ops iwl5000_lib = { - .set_hw_params = iwl5000_hw_set_hw_params, - .set_channel_switch = iwl5000_hw_channel_switch, - .nic_config = iwl5000_nic_config, - .eeprom_ops = { - .regulatory_bands = { - EEPROM_REG_BAND_1_CHANNELS, - EEPROM_REG_BAND_2_CHANNELS, - EEPROM_REG_BAND_3_CHANNELS, - EEPROM_REG_BAND_4_CHANNELS, - EEPROM_REG_BAND_5_CHANNELS, - EEPROM_REG_BAND_24_HT40_CHANNELS, - EEPROM_REG_BAND_52_HT40_CHANNELS - }, - }, - .temperature = iwlagn_temperature, -}; - -static struct iwl_lib_ops iwl5150_lib = { - .set_hw_params = iwl5150_hw_set_hw_params, - .set_channel_switch = iwl5000_hw_channel_switch, - .nic_config = iwl5000_nic_config, - .eeprom_ops = { - .regulatory_bands = { - EEPROM_REG_BAND_1_CHANNELS, - EEPROM_REG_BAND_2_CHANNELS, - EEPROM_REG_BAND_3_CHANNELS, - EEPROM_REG_BAND_4_CHANNELS, - EEPROM_REG_BAND_5_CHANNELS, - EEPROM_REG_BAND_24_HT40_CHANNELS, - EEPROM_REG_BAND_52_HT40_CHANNELS - }, - }, - .temperature = iwl5150_temperature, -}; - static const struct iwl_base_params iwl5000_base_params = { .eeprom_size = IWLAGN_EEPROM_IMG_SIZE, .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, .led_compensation = 51, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .wd_timeout = IWL_LONG_WD_TIMEOUT, + .wd_timeout = IWL_WATCHHDOG_DISABLED, .max_event_log_size = 512, .no_idle_support = true, - .wd_disable = true, }; static const struct iwl_ht_params iwl5000_ht_params = { @@ -332,11 +76,11 @@ static const struct iwl_ht_params iwl5000_ht_params = { .ucode_api_max = IWL5000_UCODE_API_MAX, \ .ucode_api_ok = IWL5000_UCODE_API_OK, \ .ucode_api_min = IWL5000_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_5000, \ .max_inst_size = IWLAGN_RTC_INST_SIZE, \ .max_data_size = IWLAGN_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_5000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, \ - .lib = &iwl5000_lib, \ .base_params = &iwl5000_base_params, \ .led_mode = IWL_LED_BLINK @@ -378,11 +122,11 @@ const struct iwl_cfg iwl5350_agn_cfg = { .ucode_api_max = IWL5000_UCODE_API_MAX, .ucode_api_ok = IWL5000_UCODE_API_OK, .ucode_api_min = IWL5000_UCODE_API_MIN, + .device_family = IWL_DEVICE_FAMILY_5000, .max_inst_size = IWLAGN_RTC_INST_SIZE, .max_data_size = IWLAGN_RTC_DATA_SIZE, .eeprom_ver = EEPROM_5050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, - .lib = &iwl5000_lib, .base_params = &iwl5000_base_params, .ht_params = &iwl5000_ht_params, .led_mode = IWL_LED_BLINK, @@ -394,11 +138,11 @@ const struct iwl_cfg iwl5350_agn_cfg = { .ucode_api_max = IWL5150_UCODE_API_MAX, \ .ucode_api_ok = IWL5150_UCODE_API_OK, \ .ucode_api_min = IWL5150_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_5150, \ .max_inst_size = IWLAGN_RTC_INST_SIZE, \ .max_data_size = IWLAGN_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_5050_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, \ - .lib = &iwl5150_lib, \ .base_params = &iwl5000_base_params, \ .no_xtal_calib = true, \ .led_mode = IWL_LED_BLINK, \ diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-6000.c b/trunk/drivers/net/wireless/iwlwifi/iwl-6000.c index f0c91505a7f7..381b02cf339c 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -24,26 +24,12 @@ * *****************************************************************************/ -#include #include -#include -#include -#include -#include -#include -#include -#include #include - -#include "iwl-eeprom.h" -#include "iwl-dev.h" -#include "iwl-core.h" -#include "iwl-io.h" -#include "iwl-agn.h" -#include "iwl-agn-hw.h" -#include "iwl-trans.h" -#include "iwl-shared.h" +#include "iwl-config.h" #include "iwl-cfg.h" +#include "iwl-agn-hw.h" +#include "iwl-commands.h" /* needed for BT for now */ /* Highest firmware API version supported */ #define IWL6000_UCODE_API_MAX 6 @@ -61,6 +47,20 @@ #define IWL6050_UCODE_API_MIN 4 #define IWL6000G2_UCODE_API_MIN 4 +/* EEPROM versions */ +#define EEPROM_6000_TX_POWER_VERSION (4) +#define EEPROM_6000_EEPROM_VERSION (0x423) +#define EEPROM_6050_TX_POWER_VERSION (4) +#define EEPROM_6050_EEPROM_VERSION (0x532) +#define EEPROM_6150_TX_POWER_VERSION (6) +#define EEPROM_6150_EEPROM_VERSION (0x553) +#define EEPROM_6005_TX_POWER_VERSION (6) +#define EEPROM_6005_EEPROM_VERSION (0x709) +#define EEPROM_6030_TX_POWER_VERSION (6) +#define EEPROM_6030_EEPROM_VERSION (0x709) +#define EEPROM_6035_TX_POWER_VERSION (6) +#define EEPROM_6035_EEPROM_VERSION (0x753) + #define IWL6000_FW_PRE "iwlwifi-6000-" #define IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE __stringify(api) ".ucode" @@ -73,205 +73,9 @@ #define IWL6030_FW_PRE "iwlwifi-6000g2b-" #define IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE __stringify(api) ".ucode" -static void iwl6000_set_ct_threshold(struct iwl_priv *priv) -{ - /* want Celsius */ - hw_params(priv).ct_kill_threshold = CT_KILL_THRESHOLD; - hw_params(priv).ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; -} - -static void iwl6050_additional_nic_config(struct iwl_priv *priv) -{ - /* Indicate calibration version to uCode. */ - if (iwl_eeprom_calib_version(priv->shrd) >= 6) - iwl_set_bit(trans(priv), CSR_GP_DRIVER_REG, - CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); -} - -static void iwl6150_additional_nic_config(struct iwl_priv *priv) -{ - /* Indicate calibration version to uCode. */ - if (iwl_eeprom_calib_version(priv->shrd) >= 6) - iwl_set_bit(trans(priv), CSR_GP_DRIVER_REG, - CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); - iwl_set_bit(trans(priv), CSR_GP_DRIVER_REG, - CSR_GP_DRIVER_REG_BIT_6050_1x2); -} - -static void iwl6000i_additional_nic_config(struct iwl_priv *priv) -{ - /* 2x2 IPA phy type */ - iwl_write32(trans(priv), CSR_GP_DRIVER_REG, - CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA); -} - -/* NIC configuration for 6000 series */ -static void iwl6000_nic_config(struct iwl_priv *priv) -{ - iwl_rf_config(priv); - - /* do additional nic configuration if needed */ - if (cfg(priv)->additional_nic_config) - cfg(priv)->additional_nic_config(priv); -} - -static const struct iwl_sensitivity_ranges iwl6000_sensitivity = { - .min_nrg_cck = 110, - .auto_corr_min_ofdm = 80, - .auto_corr_min_ofdm_mrc = 128, - .auto_corr_min_ofdm_x1 = 105, - .auto_corr_min_ofdm_mrc_x1 = 192, - - .auto_corr_max_ofdm = 145, - .auto_corr_max_ofdm_mrc = 232, - .auto_corr_max_ofdm_x1 = 110, - .auto_corr_max_ofdm_mrc_x1 = 232, - - .auto_corr_min_cck = 125, - .auto_corr_max_cck = 175, - .auto_corr_min_cck_mrc = 160, - .auto_corr_max_cck_mrc = 310, - .nrg_th_cck = 110, - .nrg_th_ofdm = 110, - - .barker_corr_th_min = 190, - .barker_corr_th_min_mrc = 336, - .nrg_th_cca = 62, -}; - -static void iwl6000_hw_set_hw_params(struct iwl_priv *priv) -{ - hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ) | - BIT(IEEE80211_BAND_5GHZ); - - hw_params(priv).tx_chains_num = - num_of_ant(hw_params(priv).valid_tx_ant); - if (cfg(priv)->rx_with_siso_diversity) - hw_params(priv).rx_chains_num = 1; - else - hw_params(priv).rx_chains_num = - num_of_ant(hw_params(priv).valid_rx_ant); - - iwl6000_set_ct_threshold(priv); - - /* Set initial sensitivity parameters */ - hw_params(priv).sens = &iwl6000_sensitivity; - -} - -static int iwl6000_hw_channel_switch(struct iwl_priv *priv, - struct ieee80211_channel_switch *ch_switch) -{ - /* - * MULTI-FIXME - * See iwlagn_mac_channel_switch. - */ - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - struct iwl6000_channel_switch_cmd cmd; - const struct iwl_channel_info *ch_info; - u32 switch_time_in_usec, ucode_switch_time; - u16 ch; - u32 tsf_low; - u8 switch_count; - u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval); - struct ieee80211_vif *vif = ctx->vif; - struct iwl_host_cmd hcmd = { - .id = REPLY_CHANNEL_SWITCH, - .len = { sizeof(cmd), }, - .flags = CMD_SYNC, - .data = { &cmd, }, - }; - - cmd.band = priv->band == IEEE80211_BAND_2GHZ; - ch = ch_switch->channel->hw_value; - IWL_DEBUG_11H(priv, "channel switch from %u to %u\n", - ctx->active.channel, ch); - cmd.channel = cpu_to_le16(ch); - cmd.rxon_flags = ctx->staging.flags; - cmd.rxon_filter_flags = ctx->staging.filter_flags; - switch_count = ch_switch->count; - tsf_low = ch_switch->timestamp & 0x0ffffffff; - /* - * calculate the ucode channel switch time - * adding TSF as one of the factor for when to switch - */ - if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) { - if (switch_count > ((priv->ucode_beacon_time - tsf_low) / - beacon_interval)) { - switch_count -= (priv->ucode_beacon_time - - tsf_low) / beacon_interval; - } else - switch_count = 0; - } - if (switch_count <= 1) - cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); - else { - switch_time_in_usec = - vif->bss_conf.beacon_int * switch_count * TIME_UNIT; - ucode_switch_time = iwl_usecs_to_beacons(priv, - switch_time_in_usec, - beacon_interval); - cmd.switch_time = iwl_add_beacon_time(priv, - priv->ucode_beacon_time, - ucode_switch_time, - beacon_interval); - } - IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n", - cmd.switch_time); - ch_info = iwl_get_channel_info(priv, priv->band, ch); - if (ch_info) - cmd.expect_beacon = is_channel_radar(ch_info); - else { - IWL_ERR(priv, "invalid channel switch from %u to %u\n", - ctx->active.channel, ch); - return -EFAULT; - } - - return iwl_dvm_send_cmd(priv, &hcmd); -} - -static struct iwl_lib_ops iwl6000_lib = { - .set_hw_params = iwl6000_hw_set_hw_params, - .set_channel_switch = iwl6000_hw_channel_switch, - .nic_config = iwl6000_nic_config, - .eeprom_ops = { - .regulatory_bands = { - EEPROM_REG_BAND_1_CHANNELS, - EEPROM_REG_BAND_2_CHANNELS, - EEPROM_REG_BAND_3_CHANNELS, - EEPROM_REG_BAND_4_CHANNELS, - EEPROM_REG_BAND_5_CHANNELS, - EEPROM_6000_REG_BAND_24_HT40_CHANNELS, - EEPROM_REG_BAND_52_HT40_CHANNELS - }, - .enhanced_txpower = true, - }, - .temperature = iwlagn_temperature, -}; - -static struct iwl_lib_ops iwl6030_lib = { - .set_hw_params = iwl6000_hw_set_hw_params, - .set_channel_switch = iwl6000_hw_channel_switch, - .nic_config = iwl6000_nic_config, - .eeprom_ops = { - .regulatory_bands = { - EEPROM_REG_BAND_1_CHANNELS, - EEPROM_REG_BAND_2_CHANNELS, - EEPROM_REG_BAND_3_CHANNELS, - EEPROM_REG_BAND_4_CHANNELS, - EEPROM_REG_BAND_5_CHANNELS, - EEPROM_6000_REG_BAND_24_HT40_CHANNELS, - EEPROM_REG_BAND_52_HT40_CHANNELS - }, - .enhanced_txpower = true, - }, - .temperature = iwlagn_temperature, -}; - static const struct iwl_base_params iwl6000_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, @@ -288,7 +92,6 @@ static const struct iwl_base_params iwl6000_base_params = { static const struct iwl_base_params iwl6050_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, .max_ll_items = OTP_MAX_LL_ITEMS_6x50, .shadow_ram_support = true, @@ -305,7 +108,6 @@ static const struct iwl_base_params iwl6050_base_params = { static const struct iwl_base_params iwl6000_g2_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .num_of_queues = IWLAGN_NUM_QUEUES, - .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = 0, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, @@ -338,11 +140,11 @@ static const struct iwl_bt_params iwl6000_bt_params = { .ucode_api_max = IWL6000G2_UCODE_API_MAX, \ .ucode_api_ok = IWL6000G2_UCODE_API_OK, \ .ucode_api_min = IWL6000G2_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_6005, \ .max_inst_size = IWL60_RTC_INST_SIZE, \ .max_data_size = IWL60_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_6005_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION, \ - .lib = &iwl6000_lib, \ .base_params = &iwl6000_g2_base_params, \ .need_temp_offset_calib = true, \ .led_mode = IWL_LED_RF_STATE @@ -392,11 +194,11 @@ const struct iwl_cfg iwl6005_2agn_mow2_cfg = { .ucode_api_max = IWL6000G2_UCODE_API_MAX, \ .ucode_api_ok = IWL6000G2B_UCODE_API_OK, \ .ucode_api_min = IWL6000G2_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_6030, \ .max_inst_size = IWL60_RTC_INST_SIZE, \ .max_data_size = IWL60_RTC_DATA_SIZE, \ .eeprom_ver = EEPROM_6030_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ - .lib = &iwl6030_lib, \ .base_params = &iwl6000_g2_base_params, \ .bt_params = &iwl6000_bt_params, \ .need_temp_offset_calib = true, \ @@ -463,14 +265,13 @@ const struct iwl_cfg iwl130_bg_cfg = { .ucode_api_max = IWL6000_UCODE_API_MAX, \ .ucode_api_ok = IWL6000_UCODE_API_OK, \ .ucode_api_min = IWL6000_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_6000i, \ .max_inst_size = IWL60_RTC_INST_SIZE, \ .max_data_size = IWL60_RTC_DATA_SIZE, \ .valid_tx_ant = ANT_BC, /* .cfg overwrite */ \ .valid_rx_ant = ANT_BC, /* .cfg overwrite */ \ .eeprom_ver = EEPROM_6000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION, \ - .lib = &iwl6000_lib, \ - .additional_nic_config = iwl6000i_additional_nic_config,\ .base_params = &iwl6000_base_params, \ .led_mode = IWL_LED_BLINK @@ -494,12 +295,11 @@ const struct iwl_cfg iwl6000i_2bg_cfg = { .fw_name_pre = IWL6050_FW_PRE, \ .ucode_api_max = IWL6050_UCODE_API_MAX, \ .ucode_api_min = IWL6050_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_6050, \ .max_inst_size = IWL60_RTC_INST_SIZE, \ .max_data_size = IWL60_RTC_DATA_SIZE, \ .valid_tx_ant = ANT_AB, /* .cfg overwrite */ \ .valid_rx_ant = ANT_AB, /* .cfg overwrite */ \ - .lib = &iwl6000_lib, \ - .additional_nic_config = iwl6050_additional_nic_config, \ .eeprom_ver = EEPROM_6050_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION, \ .base_params = &iwl6050_base_params, \ @@ -521,10 +321,9 @@ const struct iwl_cfg iwl6050_2abg_cfg = { .fw_name_pre = IWL6050_FW_PRE, \ .ucode_api_max = IWL6050_UCODE_API_MAX, \ .ucode_api_min = IWL6050_UCODE_API_MIN, \ + .device_family = IWL_DEVICE_FAMILY_6150, \ .max_inst_size = IWL60_RTC_INST_SIZE, \ .max_data_size = IWL60_RTC_DATA_SIZE, \ - .lib = &iwl6000_lib, \ - .additional_nic_config = iwl6150_additional_nic_config, \ .eeprom_ver = EEPROM_6150_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6150_TX_POWER_VERSION, \ .base_params = &iwl6050_base_params, \ @@ -548,11 +347,11 @@ const struct iwl_cfg iwl6000_3agn_cfg = { .ucode_api_max = IWL6000_UCODE_API_MAX, .ucode_api_ok = IWL6000_UCODE_API_OK, .ucode_api_min = IWL6000_UCODE_API_MIN, + .device_family = IWL_DEVICE_FAMILY_6000, .max_inst_size = IWL60_RTC_INST_SIZE, .max_data_size = IWL60_RTC_DATA_SIZE, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION, - .lib = &iwl6000_lib, .base_params = &iwl6000_base_params, .ht_params = &iwl6000_ht_params, .led_mode = IWL_LED_BLINK, diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-calib.c index 84cbe7bb504c..95f27f1a423b 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-calib.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-calib.c @@ -64,7 +64,6 @@ #include #include "iwl-dev.h" -#include "iwl-core.h" #include "iwl-agn-calib.h" #include "iwl-trans.h" #include "iwl-agn.h" @@ -190,7 +189,7 @@ static int iwl_sens_energy_cck(struct iwl_priv *priv, u32 max_false_alarms = MAX_FA_CCK * rx_enable_time; u32 min_false_alarms = MIN_FA_CCK * rx_enable_time; struct iwl_sensitivity_data *data = NULL; - const struct iwl_sensitivity_ranges *ranges = hw_params(priv).sens; + const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens; data = &(priv->sensitivity_data); @@ -373,7 +372,7 @@ static int iwl_sens_auto_corr_ofdm(struct iwl_priv *priv, u32 max_false_alarms = MAX_FA_OFDM * rx_enable_time; u32 min_false_alarms = MIN_FA_OFDM * rx_enable_time; struct iwl_sensitivity_data *data = NULL; - const struct iwl_sensitivity_ranges *ranges = hw_params(priv).sens; + const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens; data = &(priv->sensitivity_data); @@ -521,7 +520,7 @@ static int iwl_enhance_sensitivity_write(struct iwl_priv *priv) iwl_prepare_legacy_sensitivity_tbl(priv, data, &cmd.enhance_table[0]); - if (cfg(priv)->base_params->hd_v2) { + if (priv->cfg->base_params->hd_v2) { cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] = HD_INA_NON_SQUARE_DET_OFDM_DATA_V2; cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] = @@ -597,9 +596,9 @@ void iwl_init_sensitivity(struct iwl_priv *priv) int ret = 0; int i; struct iwl_sensitivity_data *data = NULL; - const struct iwl_sensitivity_ranges *ranges = hw_params(priv).sens; + const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens; - if (priv->disable_sens_cal) + if (priv->calib_disabled & IWL_SENSITIVITY_CALIB_DISABLED) return; IWL_DEBUG_CALIB(priv, "Start iwl_init_sensitivity\n"); @@ -663,7 +662,7 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv) struct statistics_rx_phy *ofdm, *cck; struct statistics_general_data statis; - if (priv->disable_sens_cal) + if (priv->calib_disabled & IWL_SENSITIVITY_CALIB_DISABLED) return; data = &(priv->sensitivity_data); @@ -833,28 +832,28 @@ static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig, * To be safe, simply mask out any chains that we know * are not on the device. */ - active_chains &= hw_params(priv).valid_rx_ant; + active_chains &= priv->hw_params.valid_rx_ant; num_tx_chains = 0; for (i = 0; i < NUM_RX_CHAINS; i++) { /* loops on all the bits of * priv->hw_setting.valid_tx_ant */ u8 ant_msk = (1 << i); - if (!(hw_params(priv).valid_tx_ant & ant_msk)) + if (!(priv->hw_params.valid_tx_ant & ant_msk)) continue; num_tx_chains++; if (data->disconn_array[i] == 0) /* there is a Tx antenna connected */ break; - if (num_tx_chains == hw_params(priv).tx_chains_num && + if (num_tx_chains == priv->hw_params.tx_chains_num && data->disconn_array[i]) { /* * If all chains are disconnected * connect the first valid tx chain */ first_chain = - find_first_chain(hw_params(priv).valid_tx_ant); + find_first_chain(priv->hw_params.valid_tx_ant); data->disconn_array[first_chain] = 0; active_chains |= BIT(first_chain); IWL_DEBUG_CALIB(priv, @@ -864,13 +863,13 @@ static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig, } } - if (active_chains != hw_params(priv).valid_rx_ant && + if (active_chains != priv->hw_params.valid_rx_ant && active_chains != priv->chain_noise_data.active_chains) IWL_DEBUG_CALIB(priv, "Detected that not all antennas are connected! " "Connected: %#x, valid: %#x.\n", active_chains, - hw_params(priv).valid_rx_ant); + priv->hw_params.valid_rx_ant); /* Save for use within RXON, TX, SCAN commands, etc. */ data->active_chains = active_chains; @@ -895,7 +894,7 @@ static void iwlagn_gain_computation(struct iwl_priv *priv, continue; } - delta_g = (cfg(priv)->base_params->chain_noise_scale * + delta_g = (priv->cfg->base_params->chain_noise_scale * ((s32)average_noise[default_chain] - (s32)average_noise[i])) / 1500; @@ -970,7 +969,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv) */ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - if (priv->disable_chain_noise_cal) + if (priv->calib_disabled & IWL_CHAIN_NOISE_CALIB_DISABLED) return; data = &(priv->chain_noise_data); @@ -1051,11 +1050,11 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv) return; /* Analyze signal for disconnected antenna */ - if (cfg(priv)->bt_params && - cfg(priv)->bt_params->advanced_bt_coexist) { + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist) { /* Disable disconnected antenna algorithm for advanced bt coex, assuming valid antennas are connected */ - data->active_chains = hw_params(priv).valid_rx_ant; + data->active_chains = priv->hw_params.valid_rx_ant; for (i = 0; i < NUM_RX_CHAINS; i++) if (!(data->active_chains & (1<disconn_array[i] = 1; @@ -1085,7 +1084,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv) min_average_noise, min_average_noise_antenna_i); iwlagn_gain_computation(priv, average_noise, - find_first_chain(hw_params(priv).valid_rx_ant)); + find_first_chain(priv->hw_params.valid_rx_ant)); /* Some power changes may have been made during the calibration. * Update and commit the RXON diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-calib.h b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-calib.h index 9ed6683314a7..dbe13787f272 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-calib.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-calib.h @@ -63,7 +63,6 @@ #define __iwl_calib_h__ #include "iwl-dev.h" -#include "iwl-core.h" #include "iwl-commands.h" void iwl_chain_noise_calibration(struct iwl_priv *priv); diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-devices.c b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-devices.c new file mode 100644 index 000000000000..48533b3a0f9a --- /dev/null +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-devices.c @@ -0,0 +1,755 @@ +/****************************************************************************** + * + * Copyright(c) 2008 - 2012 Intel 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 + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +/* + * DVM device-specific data & functions + */ +#include "iwl-agn.h" +#include "iwl-dev.h" +#include "iwl-commands.h" +#include "iwl-io.h" +#include "iwl-prph.h" + +/* + * 1000 series + * =========== + */ + +/* + * For 1000, use advance thermal throttling critical temperature threshold, + * but legacy thermal management implementation for now. + * This is for the reason of 1000 uCode using advance thermal throttling API + * but not implement ct_kill_exit based on ct_kill exit temperature + * so the thermal throttling will still based on legacy thermal throttling + * management. + * The code here need to be modified once 1000 uCode has the advanced thermal + * throttling algorithm in place + */ +static void iwl1000_set_ct_threshold(struct iwl_priv *priv) +{ + /* want Celsius */ + priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY; + priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; +} + +/* NIC configuration for 1000 series */ +static void iwl1000_nic_config(struct iwl_priv *priv) +{ + /* set CSR_HW_CONFIG_REG for uCode use */ + iwl_set_bit(priv->trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | + CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); + + /* Setting digital SVR for 1000 card to 1.32V */ + /* locking is acquired in iwl_set_bits_mask_prph() function */ + iwl_set_bits_mask_prph(priv->trans, APMG_DIGITAL_SVR_REG, + APMG_SVR_DIGITAL_VOLTAGE_1_32, + ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK); +} + +/** + * iwl_beacon_time_mask_low - mask of lower 32 bit of beacon time + * @priv -- pointer to iwl_priv data structure + * @tsf_bits -- number of bits need to shift for masking) + */ +static inline u32 iwl_beacon_time_mask_low(struct iwl_priv *priv, + u16 tsf_bits) +{ + return (1 << tsf_bits) - 1; +} + +/** + * iwl_beacon_time_mask_high - mask of higher 32 bit of beacon time + * @priv -- pointer to iwl_priv data structure + * @tsf_bits -- number of bits need to shift for masking) + */ +static inline u32 iwl_beacon_time_mask_high(struct iwl_priv *priv, + u16 tsf_bits) +{ + return ((1 << (32 - tsf_bits)) - 1) << tsf_bits; +} + +/* + * extended beacon time format + * time in usec will be changed into a 32-bit value in extended:internal format + * the extended part is the beacon counts + * the internal part is the time in usec within one beacon interval + */ +static u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, + u32 beacon_interval) +{ + u32 quot; + u32 rem; + u32 interval = beacon_interval * TIME_UNIT; + + if (!interval || !usec) + return 0; + + quot = (usec / interval) & + (iwl_beacon_time_mask_high(priv, IWLAGN_EXT_BEACON_TIME_POS) >> + IWLAGN_EXT_BEACON_TIME_POS); + rem = (usec % interval) & iwl_beacon_time_mask_low(priv, + IWLAGN_EXT_BEACON_TIME_POS); + + return (quot << IWLAGN_EXT_BEACON_TIME_POS) + rem; +} + +/* base is usually what we get from ucode with each received frame, + * the same as HW timer counter counting down + */ +static __le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base, + u32 addon, u32 beacon_interval) +{ + u32 base_low = base & iwl_beacon_time_mask_low(priv, + IWLAGN_EXT_BEACON_TIME_POS); + u32 addon_low = addon & iwl_beacon_time_mask_low(priv, + IWLAGN_EXT_BEACON_TIME_POS); + u32 interval = beacon_interval * TIME_UNIT; + u32 res = (base & iwl_beacon_time_mask_high(priv, + IWLAGN_EXT_BEACON_TIME_POS)) + + (addon & iwl_beacon_time_mask_high(priv, + IWLAGN_EXT_BEACON_TIME_POS)); + + if (base_low > addon_low) + res += base_low - addon_low; + else if (base_low < addon_low) { + res += interval + base_low - addon_low; + res += (1 << IWLAGN_EXT_BEACON_TIME_POS); + } else + res += (1 << IWLAGN_EXT_BEACON_TIME_POS); + + return cpu_to_le32(res); +} + +static const struct iwl_sensitivity_ranges iwl1000_sensitivity = { + .min_nrg_cck = 95, + .auto_corr_min_ofdm = 90, + .auto_corr_min_ofdm_mrc = 170, + .auto_corr_min_ofdm_x1 = 120, + .auto_corr_min_ofdm_mrc_x1 = 240, + + .auto_corr_max_ofdm = 120, + .auto_corr_max_ofdm_mrc = 210, + .auto_corr_max_ofdm_x1 = 155, + .auto_corr_max_ofdm_mrc_x1 = 290, + + .auto_corr_min_cck = 125, + .auto_corr_max_cck = 200, + .auto_corr_min_cck_mrc = 170, + .auto_corr_max_cck_mrc = 400, + .nrg_th_cck = 95, + .nrg_th_ofdm = 95, + + .barker_corr_th_min = 190, + .barker_corr_th_min_mrc = 390, + .nrg_th_cca = 62, +}; + +static void iwl1000_hw_set_hw_params(struct iwl_priv *priv) +{ + priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ); + + priv->hw_params.tx_chains_num = + num_of_ant(priv->hw_params.valid_tx_ant); + if (priv->cfg->rx_with_siso_diversity) + priv->hw_params.rx_chains_num = 1; + else + priv->hw_params.rx_chains_num = + num_of_ant(priv->hw_params.valid_rx_ant); + + iwl1000_set_ct_threshold(priv); + + /* Set initial sensitivity parameters */ + priv->hw_params.sens = &iwl1000_sensitivity; +} + +struct iwl_lib_ops iwl1000_lib = { + .set_hw_params = iwl1000_hw_set_hw_params, + .nic_config = iwl1000_nic_config, + .eeprom_ops = { + .regulatory_bands = { + EEPROM_REG_BAND_1_CHANNELS, + EEPROM_REG_BAND_2_CHANNELS, + EEPROM_REG_BAND_3_CHANNELS, + EEPROM_REG_BAND_4_CHANNELS, + EEPROM_REG_BAND_5_CHANNELS, + EEPROM_REG_BAND_24_HT40_CHANNELS, + EEPROM_REGULATORY_BAND_NO_HT40, + }, + }, + .temperature = iwlagn_temperature, +}; + + +/* + * 2000 series + * =========== + */ + +static void iwl2000_set_ct_threshold(struct iwl_priv *priv) +{ + /* want Celsius */ + priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; + priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; +} + +/* NIC configuration for 2000 series */ +static void iwl2000_nic_config(struct iwl_priv *priv) +{ + iwl_rf_config(priv); + + iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG, + CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER); +} + +static const struct iwl_sensitivity_ranges iwl2000_sensitivity = { + .min_nrg_cck = 97, + .auto_corr_min_ofdm = 80, + .auto_corr_min_ofdm_mrc = 128, + .auto_corr_min_ofdm_x1 = 105, + .auto_corr_min_ofdm_mrc_x1 = 192, + + .auto_corr_max_ofdm = 145, + .auto_corr_max_ofdm_mrc = 232, + .auto_corr_max_ofdm_x1 = 110, + .auto_corr_max_ofdm_mrc_x1 = 232, + + .auto_corr_min_cck = 125, + .auto_corr_max_cck = 175, + .auto_corr_min_cck_mrc = 160, + .auto_corr_max_cck_mrc = 310, + .nrg_th_cck = 97, + .nrg_th_ofdm = 100, + + .barker_corr_th_min = 190, + .barker_corr_th_min_mrc = 390, + .nrg_th_cca = 62, +}; + +static void iwl2000_hw_set_hw_params(struct iwl_priv *priv) +{ + priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ); + + priv->hw_params.tx_chains_num = + num_of_ant(priv->hw_params.valid_tx_ant); + if (priv->cfg->rx_with_siso_diversity) + priv->hw_params.rx_chains_num = 1; + else + priv->hw_params.rx_chains_num = + num_of_ant(priv->hw_params.valid_rx_ant); + + iwl2000_set_ct_threshold(priv); + + /* Set initial sensitivity parameters */ + priv->hw_params.sens = &iwl2000_sensitivity; +} + +struct iwl_lib_ops iwl2000_lib = { + .set_hw_params = iwl2000_hw_set_hw_params, + .nic_config = iwl2000_nic_config, + .eeprom_ops = { + .regulatory_bands = { + EEPROM_REG_BAND_1_CHANNELS, + EEPROM_REG_BAND_2_CHANNELS, + EEPROM_REG_BAND_3_CHANNELS, + EEPROM_REG_BAND_4_CHANNELS, + EEPROM_REG_BAND_5_CHANNELS, + EEPROM_6000_REG_BAND_24_HT40_CHANNELS, + EEPROM_REGULATORY_BAND_NO_HT40, + }, + .enhanced_txpower = true, + }, + .temperature = iwlagn_temperature, +}; + +struct iwl_lib_ops iwl2030_lib = { + .set_hw_params = iwl2000_hw_set_hw_params, + .nic_config = iwl2000_nic_config, + .eeprom_ops = { + .regulatory_bands = { + EEPROM_REG_BAND_1_CHANNELS, + EEPROM_REG_BAND_2_CHANNELS, + EEPROM_REG_BAND_3_CHANNELS, + EEPROM_REG_BAND_4_CHANNELS, + EEPROM_REG_BAND_5_CHANNELS, + EEPROM_6000_REG_BAND_24_HT40_CHANNELS, + EEPROM_REGULATORY_BAND_NO_HT40, + }, + .enhanced_txpower = true, + }, + .temperature = iwlagn_temperature, +}; + +/* + * 5000 series + * =========== + */ + +/* NIC configuration for 5000 series */ +static void iwl5000_nic_config(struct iwl_priv *priv) +{ + iwl_rf_config(priv); + + /* W/A : NIC is stuck in a reset state after Early PCIe power off + * (PCIe power is lost before PERST# is asserted), + * causing ME FW to lose ownership and not being able to obtain it back. + */ + iwl_set_bits_mask_prph(priv->trans, APMG_PS_CTRL_REG, + APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, + ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); +} + +static const struct iwl_sensitivity_ranges iwl5000_sensitivity = { + .min_nrg_cck = 100, + .auto_corr_min_ofdm = 90, + .auto_corr_min_ofdm_mrc = 170, + .auto_corr_min_ofdm_x1 = 105, + .auto_corr_min_ofdm_mrc_x1 = 220, + + .auto_corr_max_ofdm = 120, + .auto_corr_max_ofdm_mrc = 210, + .auto_corr_max_ofdm_x1 = 120, + .auto_corr_max_ofdm_mrc_x1 = 240, + + .auto_corr_min_cck = 125, + .auto_corr_max_cck = 200, + .auto_corr_min_cck_mrc = 200, + .auto_corr_max_cck_mrc = 400, + .nrg_th_cck = 100, + .nrg_th_ofdm = 100, + + .barker_corr_th_min = 190, + .barker_corr_th_min_mrc = 390, + .nrg_th_cca = 62, +}; + +static struct iwl_sensitivity_ranges iwl5150_sensitivity = { + .min_nrg_cck = 95, + .auto_corr_min_ofdm = 90, + .auto_corr_min_ofdm_mrc = 170, + .auto_corr_min_ofdm_x1 = 105, + .auto_corr_min_ofdm_mrc_x1 = 220, + + .auto_corr_max_ofdm = 120, + .auto_corr_max_ofdm_mrc = 210, + /* max = min for performance bug in 5150 DSP */ + .auto_corr_max_ofdm_x1 = 105, + .auto_corr_max_ofdm_mrc_x1 = 220, + + .auto_corr_min_cck = 125, + .auto_corr_max_cck = 200, + .auto_corr_min_cck_mrc = 170, + .auto_corr_max_cck_mrc = 400, + .nrg_th_cck = 95, + .nrg_th_ofdm = 95, + + .barker_corr_th_min = 190, + .barker_corr_th_min_mrc = 390, + .nrg_th_cca = 62, +}; + +#define IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF (-5) + +static s32 iwl_temp_calib_to_offset(struct iwl_priv *priv) +{ + u16 temperature, voltage; + __le16 *temp_calib = (__le16 *)iwl_eeprom_query_addr(priv, + EEPROM_KELVIN_TEMPERATURE); + + temperature = le16_to_cpu(temp_calib[0]); + voltage = le16_to_cpu(temp_calib[1]); + + /* offset = temp - volt / coeff */ + return (s32)(temperature - + voltage / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF); +} + +static void iwl5150_set_ct_threshold(struct iwl_priv *priv) +{ + const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF; + s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY) - + iwl_temp_calib_to_offset(priv); + + priv->hw_params.ct_kill_threshold = threshold * volt2temp_coef; +} + +static void iwl5000_set_ct_threshold(struct iwl_priv *priv) +{ + /* want Celsius */ + priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY; +} + +static void iwl5000_hw_set_hw_params(struct iwl_priv *priv) +{ + priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | + BIT(IEEE80211_BAND_5GHZ); + + priv->hw_params.tx_chains_num = + num_of_ant(priv->hw_params.valid_tx_ant); + priv->hw_params.rx_chains_num = + num_of_ant(priv->hw_params.valid_rx_ant); + + iwl5000_set_ct_threshold(priv); + + /* Set initial sensitivity parameters */ + priv->hw_params.sens = &iwl5000_sensitivity; +} + +static void iwl5150_hw_set_hw_params(struct iwl_priv *priv) +{ + priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | + BIT(IEEE80211_BAND_5GHZ); + + priv->hw_params.tx_chains_num = + num_of_ant(priv->hw_params.valid_tx_ant); + priv->hw_params.rx_chains_num = + num_of_ant(priv->hw_params.valid_rx_ant); + + iwl5150_set_ct_threshold(priv); + + /* Set initial sensitivity parameters */ + priv->hw_params.sens = &iwl5150_sensitivity; +} + +static void iwl5150_temperature(struct iwl_priv *priv) +{ + u32 vt = 0; + s32 offset = iwl_temp_calib_to_offset(priv); + + vt = le32_to_cpu(priv->statistics.common.temperature); + vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset; + /* now vt hold the temperature in Kelvin */ + priv->temperature = KELVIN_TO_CELSIUS(vt); + iwl_tt_handler(priv); +} + +static int iwl5000_hw_channel_switch(struct iwl_priv *priv, + struct ieee80211_channel_switch *ch_switch) +{ + /* + * MULTI-FIXME + * See iwlagn_mac_channel_switch. + */ + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; + struct iwl5000_channel_switch_cmd cmd; + const struct iwl_channel_info *ch_info; + u32 switch_time_in_usec, ucode_switch_time; + u16 ch; + u32 tsf_low; + u8 switch_count; + u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval); + struct ieee80211_vif *vif = ctx->vif; + struct iwl_host_cmd hcmd = { + .id = REPLY_CHANNEL_SWITCH, + .len = { sizeof(cmd), }, + .flags = CMD_SYNC, + .data = { &cmd, }, + }; + + cmd.band = priv->band == IEEE80211_BAND_2GHZ; + ch = ch_switch->channel->hw_value; + IWL_DEBUG_11H(priv, "channel switch from %d to %d\n", + ctx->active.channel, ch); + cmd.channel = cpu_to_le16(ch); + cmd.rxon_flags = ctx->staging.flags; + cmd.rxon_filter_flags = ctx->staging.filter_flags; + switch_count = ch_switch->count; + tsf_low = ch_switch->timestamp & 0x0ffffffff; + /* + * calculate the ucode channel switch time + * adding TSF as one of the factor for when to switch + */ + if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) { + if (switch_count > ((priv->ucode_beacon_time - tsf_low) / + beacon_interval)) { + switch_count -= (priv->ucode_beacon_time - + tsf_low) / beacon_interval; + } else + switch_count = 0; + } + if (switch_count <= 1) + cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); + else { + switch_time_in_usec = + vif->bss_conf.beacon_int * switch_count * TIME_UNIT; + ucode_switch_time = iwl_usecs_to_beacons(priv, + switch_time_in_usec, + beacon_interval); + cmd.switch_time = iwl_add_beacon_time(priv, + priv->ucode_beacon_time, + ucode_switch_time, + beacon_interval); + } + IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n", + cmd.switch_time); + ch_info = iwl_get_channel_info(priv, priv->band, ch); + if (ch_info) + cmd.expect_beacon = is_channel_radar(ch_info); + else { + IWL_ERR(priv, "invalid channel switch from %u to %u\n", + ctx->active.channel, ch); + return -EFAULT; + } + + return iwl_dvm_send_cmd(priv, &hcmd); +} + +struct iwl_lib_ops iwl5000_lib = { + .set_hw_params = iwl5000_hw_set_hw_params, + .set_channel_switch = iwl5000_hw_channel_switch, + .nic_config = iwl5000_nic_config, + .eeprom_ops = { + .regulatory_bands = { + EEPROM_REG_BAND_1_CHANNELS, + EEPROM_REG_BAND_2_CHANNELS, + EEPROM_REG_BAND_3_CHANNELS, + EEPROM_REG_BAND_4_CHANNELS, + EEPROM_REG_BAND_5_CHANNELS, + EEPROM_REG_BAND_24_HT40_CHANNELS, + EEPROM_REG_BAND_52_HT40_CHANNELS + }, + }, + .temperature = iwlagn_temperature, +}; + +struct iwl_lib_ops iwl5150_lib = { + .set_hw_params = iwl5150_hw_set_hw_params, + .set_channel_switch = iwl5000_hw_channel_switch, + .nic_config = iwl5000_nic_config, + .eeprom_ops = { + .regulatory_bands = { + EEPROM_REG_BAND_1_CHANNELS, + EEPROM_REG_BAND_2_CHANNELS, + EEPROM_REG_BAND_3_CHANNELS, + EEPROM_REG_BAND_4_CHANNELS, + EEPROM_REG_BAND_5_CHANNELS, + EEPROM_REG_BAND_24_HT40_CHANNELS, + EEPROM_REG_BAND_52_HT40_CHANNELS + }, + }, + .temperature = iwl5150_temperature, +}; + + + +/* + * 6000 series + * =========== + */ + +static void iwl6000_set_ct_threshold(struct iwl_priv *priv) +{ + /* want Celsius */ + priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; + priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; +} + +/* NIC configuration for 6000 series */ +static void iwl6000_nic_config(struct iwl_priv *priv) +{ + iwl_rf_config(priv); + + switch (priv->cfg->device_family) { + case IWL_DEVICE_FAMILY_6005: + case IWL_DEVICE_FAMILY_6030: + case IWL_DEVICE_FAMILY_6000: + break; + case IWL_DEVICE_FAMILY_6000i: + /* 2x2 IPA phy type */ + iwl_write32(priv->trans, CSR_GP_DRIVER_REG, + CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA); + break; + case IWL_DEVICE_FAMILY_6050: + /* Indicate calibration version to uCode. */ + if (iwl_eeprom_calib_version(priv) >= 6) + iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG, + CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); + break; + case IWL_DEVICE_FAMILY_6150: + /* Indicate calibration version to uCode. */ + if (iwl_eeprom_calib_version(priv) >= 6) + iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG, + CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); + iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG, + CSR_GP_DRIVER_REG_BIT_6050_1x2); + break; + default: + WARN_ON(1); + } +} + +static const struct iwl_sensitivity_ranges iwl6000_sensitivity = { + .min_nrg_cck = 110, + .auto_corr_min_ofdm = 80, + .auto_corr_min_ofdm_mrc = 128, + .auto_corr_min_ofdm_x1 = 105, + .auto_corr_min_ofdm_mrc_x1 = 192, + + .auto_corr_max_ofdm = 145, + .auto_corr_max_ofdm_mrc = 232, + .auto_corr_max_ofdm_x1 = 110, + .auto_corr_max_ofdm_mrc_x1 = 232, + + .auto_corr_min_cck = 125, + .auto_corr_max_cck = 175, + .auto_corr_min_cck_mrc = 160, + .auto_corr_max_cck_mrc = 310, + .nrg_th_cck = 110, + .nrg_th_ofdm = 110, + + .barker_corr_th_min = 190, + .barker_corr_th_min_mrc = 336, + .nrg_th_cca = 62, +}; + +static void iwl6000_hw_set_hw_params(struct iwl_priv *priv) +{ + priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | + BIT(IEEE80211_BAND_5GHZ); + + priv->hw_params.tx_chains_num = + num_of_ant(priv->hw_params.valid_tx_ant); + if (priv->cfg->rx_with_siso_diversity) + priv->hw_params.rx_chains_num = 1; + else + priv->hw_params.rx_chains_num = + num_of_ant(priv->hw_params.valid_rx_ant); + + iwl6000_set_ct_threshold(priv); + + /* Set initial sensitivity parameters */ + priv->hw_params.sens = &iwl6000_sensitivity; + +} + +static int iwl6000_hw_channel_switch(struct iwl_priv *priv, + struct ieee80211_channel_switch *ch_switch) +{ + /* + * MULTI-FIXME + * See iwlagn_mac_channel_switch. + */ + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; + struct iwl6000_channel_switch_cmd cmd; + const struct iwl_channel_info *ch_info; + u32 switch_time_in_usec, ucode_switch_time; + u16 ch; + u32 tsf_low; + u8 switch_count; + u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval); + struct ieee80211_vif *vif = ctx->vif; + struct iwl_host_cmd hcmd = { + .id = REPLY_CHANNEL_SWITCH, + .len = { sizeof(cmd), }, + .flags = CMD_SYNC, + .data = { &cmd, }, + }; + + cmd.band = priv->band == IEEE80211_BAND_2GHZ; + ch = ch_switch->channel->hw_value; + IWL_DEBUG_11H(priv, "channel switch from %u to %u\n", + ctx->active.channel, ch); + cmd.channel = cpu_to_le16(ch); + cmd.rxon_flags = ctx->staging.flags; + cmd.rxon_filter_flags = ctx->staging.filter_flags; + switch_count = ch_switch->count; + tsf_low = ch_switch->timestamp & 0x0ffffffff; + /* + * calculate the ucode channel switch time + * adding TSF as one of the factor for when to switch + */ + if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) { + if (switch_count > ((priv->ucode_beacon_time - tsf_low) / + beacon_interval)) { + switch_count -= (priv->ucode_beacon_time - + tsf_low) / beacon_interval; + } else + switch_count = 0; + } + if (switch_count <= 1) + cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); + else { + switch_time_in_usec = + vif->bss_conf.beacon_int * switch_count * TIME_UNIT; + ucode_switch_time = iwl_usecs_to_beacons(priv, + switch_time_in_usec, + beacon_interval); + cmd.switch_time = iwl_add_beacon_time(priv, + priv->ucode_beacon_time, + ucode_switch_time, + beacon_interval); + } + IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n", + cmd.switch_time); + ch_info = iwl_get_channel_info(priv, priv->band, ch); + if (ch_info) + cmd.expect_beacon = is_channel_radar(ch_info); + else { + IWL_ERR(priv, "invalid channel switch from %u to %u\n", + ctx->active.channel, ch); + return -EFAULT; + } + + return iwl_dvm_send_cmd(priv, &hcmd); +} + +struct iwl_lib_ops iwl6000_lib = { + .set_hw_params = iwl6000_hw_set_hw_params, + .set_channel_switch = iwl6000_hw_channel_switch, + .nic_config = iwl6000_nic_config, + .eeprom_ops = { + .regulatory_bands = { + EEPROM_REG_BAND_1_CHANNELS, + EEPROM_REG_BAND_2_CHANNELS, + EEPROM_REG_BAND_3_CHANNELS, + EEPROM_REG_BAND_4_CHANNELS, + EEPROM_REG_BAND_5_CHANNELS, + EEPROM_6000_REG_BAND_24_HT40_CHANNELS, + EEPROM_REG_BAND_52_HT40_CHANNELS + }, + .enhanced_txpower = true, + }, + .temperature = iwlagn_temperature, +}; + +struct iwl_lib_ops iwl6030_lib = { + .set_hw_params = iwl6000_hw_set_hw_params, + .set_channel_switch = iwl6000_hw_channel_switch, + .nic_config = iwl6000_nic_config, + .eeprom_ops = { + .regulatory_bands = { + EEPROM_REG_BAND_1_CHANNELS, + EEPROM_REG_BAND_2_CHANNELS, + EEPROM_REG_BAND_3_CHANNELS, + EEPROM_REG_BAND_4_CHANNELS, + EEPROM_REG_BAND_5_CHANNELS, + EEPROM_6000_REG_BAND_24_HT40_CHANNELS, + EEPROM_REG_BAND_52_HT40_CHANNELS + }, + .enhanced_txpower = true, + }, + .temperature = iwlagn_temperature, +}; diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-hw.h b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-hw.h index d0ec0abd3c89..7960a52f6ad4 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-hw.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-hw.h @@ -102,10 +102,18 @@ /* 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 */ +#define OTP_MAX_LL_ITEMS_1000 (3) /* OTP blocks for 1000 */ +#define OTP_MAX_LL_ITEMS_6x00 (4) /* OTP blocks for 6x00 */ +#define OTP_MAX_LL_ITEMS_6x50 (7) /* OTP blocks for 6x50 */ +#define OTP_MAX_LL_ITEMS_2x00 (4) /* OTP blocks for 2x00 */ + -#define IWLAGN_CMD_FIFO_NUM 7 #define IWLAGN_NUM_QUEUES 20 -#define IWLAGN_NUM_AMPDU_QUEUES 9 -#define IWLAGN_FIRST_AMPDU_QUEUE 11 #endif /* __iwl_agn_hw_h__ */ diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 56f41c9409d1..01dc44267317 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -33,12 +33,11 @@ #include #include "iwl-dev.h" -#include "iwl-core.h" #include "iwl-io.h" #include "iwl-agn-hw.h" #include "iwl-agn.h" #include "iwl-trans.h" -#include "iwl-shared.h" +#include "iwl-modparams.h" int iwlagn_hw_valid_rtc_data_addr(u32 addr) { @@ -94,81 +93,6 @@ void iwlagn_temperature(struct iwl_priv *priv) iwl_tt_handler(priv); } -u16 iwl_eeprom_calib_version(struct iwl_shared *shrd) -{ - struct iwl_eeprom_calib_hdr *hdr; - - hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(shrd, - EEPROM_CALIB_ALL); - return hdr->version; - -} - -/* - * EEPROM - */ -static u32 eeprom_indirect_address(const struct iwl_shared *shrd, u32 address) -{ - u16 offset = 0; - - if ((address & INDIRECT_ADDRESS) == 0) - return address; - - switch (address & INDIRECT_TYPE_MSK) { - case INDIRECT_HOST: - offset = iwl_eeprom_query16(shrd, EEPROM_LINK_HOST); - break; - case INDIRECT_GENERAL: - offset = iwl_eeprom_query16(shrd, EEPROM_LINK_GENERAL); - break; - case INDIRECT_REGULATORY: - offset = iwl_eeprom_query16(shrd, EEPROM_LINK_REGULATORY); - break; - case INDIRECT_TXP_LIMIT: - offset = iwl_eeprom_query16(shrd, EEPROM_LINK_TXP_LIMIT); - break; - case INDIRECT_TXP_LIMIT_SIZE: - offset = iwl_eeprom_query16(shrd, EEPROM_LINK_TXP_LIMIT_SIZE); - break; - case INDIRECT_CALIBRATION: - offset = iwl_eeprom_query16(shrd, EEPROM_LINK_CALIBRATION); - break; - case INDIRECT_PROCESS_ADJST: - offset = iwl_eeprom_query16(shrd, EEPROM_LINK_PROCESS_ADJST); - break; - case INDIRECT_OTHERS: - offset = iwl_eeprom_query16(shrd, EEPROM_LINK_OTHERS); - break; - default: - IWL_ERR(shrd->trans, "illegal indirect type: 0x%X\n", - address & INDIRECT_TYPE_MSK); - break; - } - - /* translate the offset from words to byte */ - return (address & ADDRESS_MSK) + (offset << 1); -} - -const u8 *iwl_eeprom_query_addr(const struct iwl_shared *shrd, size_t offset) -{ - u32 address = eeprom_indirect_address(shrd, offset); - BUG_ON(address >= shrd->cfg->base_params->eeprom_size); - return &shrd->eeprom[address]; -} - -struct iwl_mod_params iwlagn_mod_params = { - .amsdu_size_8K = 1, - .restart_fw = 1, - .plcp_check = true, - .bt_coex_active = true, - .no_sleep_autoadjust = true, - .power_level = IWL_POWER_INDEX_1, - .bt_ch_announce = true, - .wanted_ucode_alternative = 1, - .auto_agg = true, - /* the rest are 0 by default */ -}; - int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band) { int idx = 0; @@ -228,13 +152,13 @@ int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control) IWL_SCD_BE_MSK | IWL_SCD_BK_MSK | IWL_SCD_MGMT_MSK; if ((flush_control & BIT(IWL_RXON_CTX_PAN)) && - (priv->shrd->valid_contexts != BIT(IWL_RXON_CTX_BSS))) + (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))) flush_cmd.fifo_control |= IWL_PAN_SCD_VO_MSK | IWL_PAN_SCD_VI_MSK | IWL_PAN_SCD_BE_MSK | IWL_PAN_SCD_BK_MSK | IWL_PAN_SCD_MGMT_MSK | IWL_PAN_SCD_MULTICAST_MSK; - if (hw_params(priv).sku & EEPROM_SKU_CAP_11N_ENABLE) + if (priv->hw_params.sku & EEPROM_SKU_CAP_11N_ENABLE) flush_cmd.fifo_control |= IWL_AGG_TX_QUEUE_MSK; IWL_DEBUG_INFO(priv, "fifo queue control: 0X%x\n", @@ -253,7 +177,7 @@ void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control) goto done; } IWL_DEBUG_INFO(priv, "wait transmit/flush all frames\n"); - iwl_trans_wait_tx_queue_empty(trans(priv)); + iwl_trans_wait_tx_queue_empty(priv->trans); done: ieee80211_wake_queues(priv->hw); mutex_unlock(&priv->mutex); @@ -262,76 +186,8 @@ void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control) /* * BT coex */ -/* - * Macros to access the lookup table. - * - * The lookup table has 7 inputs: bt3_prio, bt3_txrx, bt_rf_act, wifi_req, -* wifi_prio, wifi_txrx and wifi_sh_ant_req. - * - * It has three outputs: WLAN_ACTIVE, WLAN_KILL and ANT_SWITCH - * - * The format is that "registers" 8 through 11 contain the WLAN_ACTIVE bits - * one after another in 32-bit registers, and "registers" 0 through 7 contain - * the WLAN_KILL and ANT_SWITCH bits interleaved (in that order). - * - * These macros encode that format. - */ -#define LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, wifi_req, wifi_prio, \ - wifi_txrx, wifi_sh_ant_req) \ - (bt3_prio | (bt3_txrx << 1) | (bt_rf_act << 2) | (wifi_req << 3) | \ - (wifi_prio << 4) | (wifi_txrx << 5) | (wifi_sh_ant_req << 6)) - -#define LUT_PTA_WLAN_ACTIVE_OP(lut, op, val) \ - lut[8 + ((val) >> 5)] op (cpu_to_le32(BIT((val) & 0x1f))) -#define LUT_TEST_PTA_WLAN_ACTIVE(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \ - wifi_prio, wifi_txrx, wifi_sh_ant_req) \ - (!!(LUT_PTA_WLAN_ACTIVE_OP(lut, &, LUT_VALUE(bt3_prio, bt3_txrx, \ - bt_rf_act, wifi_req, wifi_prio, wifi_txrx, \ - wifi_sh_ant_req)))) -#define LUT_SET_PTA_WLAN_ACTIVE(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \ - wifi_prio, wifi_txrx, wifi_sh_ant_req) \ - LUT_PTA_WLAN_ACTIVE_OP(lut, |=, LUT_VALUE(bt3_prio, bt3_txrx, \ - bt_rf_act, wifi_req, wifi_prio, wifi_txrx, \ - wifi_sh_ant_req)) -#define LUT_CLEAR_PTA_WLAN_ACTIVE(lut, bt3_prio, bt3_txrx, bt_rf_act, \ - wifi_req, wifi_prio, wifi_txrx, \ - wifi_sh_ant_req) \ - LUT_PTA_WLAN_ACTIVE_OP(lut, &= ~, LUT_VALUE(bt3_prio, bt3_txrx, \ - bt_rf_act, wifi_req, wifi_prio, wifi_txrx, \ - wifi_sh_ant_req)) - -#define LUT_WLAN_KILL_OP(lut, op, val) \ - lut[(val) >> 4] op (cpu_to_le32(BIT(((val) << 1) & 0x1e))) -#define LUT_TEST_WLAN_KILL(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \ - wifi_prio, wifi_txrx, wifi_sh_ant_req) \ - (!!(LUT_WLAN_KILL_OP(lut, &, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \ - wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req)))) -#define LUT_SET_WLAN_KILL(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \ - wifi_prio, wifi_txrx, wifi_sh_ant_req) \ - LUT_WLAN_KILL_OP(lut, |=, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \ - wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req)) -#define LUT_CLEAR_WLAN_KILL(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \ - wifi_prio, wifi_txrx, wifi_sh_ant_req) \ - LUT_WLAN_KILL_OP(lut, &= ~, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \ - wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req)) - -#define LUT_ANT_SWITCH_OP(lut, op, val) \ - lut[(val) >> 4] op (cpu_to_le32(BIT((((val) << 1) & 0x1e) + 1))) -#define LUT_TEST_ANT_SWITCH(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \ - wifi_prio, wifi_txrx, wifi_sh_ant_req) \ - (!!(LUT_ANT_SWITCH_OP(lut, &, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \ - wifi_req, wifi_prio, wifi_txrx, \ - wifi_sh_ant_req)))) -#define LUT_SET_ANT_SWITCH(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \ - wifi_prio, wifi_txrx, wifi_sh_ant_req) \ - LUT_ANT_SWITCH_OP(lut, |=, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \ - wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req)) -#define LUT_CLEAR_ANT_SWITCH(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \ - wifi_prio, wifi_txrx, wifi_sh_ant_req) \ - LUT_ANT_SWITCH_OP(lut, &= ~, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \ - wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req)) - -static const __le32 iwlagn_def_3w_lookup[12] = { +/* Notmal TDM */ +static const __le32 iwlagn_def_3w_lookup[IWLAGN_BT_DECISION_LUT_SIZE] = { cpu_to_le32(0xaaaaaaaa), cpu_to_le32(0xaaaaaaaa), cpu_to_le32(0xaeaaaaaa), @@ -346,7 +202,25 @@ static const __le32 iwlagn_def_3w_lookup[12] = { cpu_to_le32(0xf0005000), }; -static const __le32 iwlagn_concurrent_lookup[12] = { + +/* Loose Coex */ +static const __le32 iwlagn_loose_lookup[IWLAGN_BT_DECISION_LUT_SIZE] = { + cpu_to_le32(0xaaaaaaaa), + cpu_to_le32(0xaaaaaaaa), + cpu_to_le32(0xaeaaaaaa), + cpu_to_le32(0xaaaaaaaa), + cpu_to_le32(0xcc00ff28), + cpu_to_le32(0x0000aaaa), + cpu_to_le32(0xcc00aaaa), + cpu_to_le32(0x0000aaaa), + cpu_to_le32(0x00000000), + cpu_to_le32(0x00000000), + cpu_to_le32(0xf0005000), + cpu_to_le32(0xf0005000), +}; + +/* Full concurrency */ +static const __le32 iwlagn_concurrent_lookup[IWLAGN_BT_DECISION_LUT_SIZE] = { cpu_to_le32(0xaaaaaaaa), cpu_to_le32(0xaaaaaaaa), cpu_to_le32(0xaaaaaaaa), @@ -369,24 +243,30 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv) .bt3_prio_sample_time = IWLAGN_BT3_PRIO_SAMPLE_DEFAULT, .bt3_timer_t2_value = IWLAGN_BT3_T2_DEFAULT, }; - struct iwl6000_bt_cmd bt_cmd_6000; - struct iwl2000_bt_cmd bt_cmd_2000; + struct iwl_bt_cmd_v1 bt_cmd_v1; + struct iwl_bt_cmd_v2 bt_cmd_v2; int ret; BUILD_BUG_ON(sizeof(iwlagn_def_3w_lookup) != sizeof(basic.bt3_lookup_table)); - if (cfg(priv)->bt_params) { - if (cfg(priv)->bt_params->bt_session_2) { - bt_cmd_2000.prio_boost = cpu_to_le32( - cfg(priv)->bt_params->bt_prio_boost); - bt_cmd_2000.tx_prio_boost = 0; - bt_cmd_2000.rx_prio_boost = 0; + if (priv->cfg->bt_params) { + /* + * newer generation of devices (2000 series and newer) + * use the version 2 of the bt command + * we need to make sure sending the host command + * with correct data structure to avoid uCode assert + */ + if (priv->cfg->bt_params->bt_session_2) { + bt_cmd_v2.prio_boost = cpu_to_le32( + priv->cfg->bt_params->bt_prio_boost); + bt_cmd_v2.tx_prio_boost = 0; + bt_cmd_v2.rx_prio_boost = 0; } else { - bt_cmd_6000.prio_boost = - cfg(priv)->bt_params->bt_prio_boost; - bt_cmd_6000.tx_prio_boost = 0; - bt_cmd_6000.rx_prio_boost = 0; + bt_cmd_v1.prio_boost = + priv->cfg->bt_params->bt_prio_boost; + bt_cmd_v1.tx_prio_boost = 0; + bt_cmd_v1.rx_prio_boost = 0; } } else { IWL_ERR(priv, "failed to construct BT Coex Config\n"); @@ -395,6 +275,7 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv) basic.kill_ack_mask = priv->kill_ack_mask; basic.kill_cts_mask = priv->kill_cts_mask; + basic.reduce_txpower = priv->reduced_txpower; basic.valid = priv->bt_valid; /* @@ -403,7 +284,7 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv) * (might be in monitor mode), or the interface is in * IBSS mode (no proper uCode support for coex then). */ - if (!iwlagn_mod_params.bt_coex_active || + if (!iwlwifi_mod_params.bt_coex_active || priv->iw_mode == NL80211_IFTYPE_ADHOC) { basic.flags = IWLAGN_BT_FLAG_COEX_MODE_DISABLED; } else { @@ -432,16 +313,16 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv) priv->bt_full_concurrent ? "full concurrency" : "3-wire"); - if (cfg(priv)->bt_params->bt_session_2) { - memcpy(&bt_cmd_2000.basic, &basic, + if (priv->cfg->bt_params->bt_session_2) { + memcpy(&bt_cmd_v2.basic, &basic, sizeof(basic)); ret = iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG, - CMD_SYNC, sizeof(bt_cmd_2000), &bt_cmd_2000); + CMD_SYNC, sizeof(bt_cmd_v2), &bt_cmd_v2); } else { - memcpy(&bt_cmd_6000.basic, &basic, + memcpy(&bt_cmd_v1.basic, &basic, sizeof(basic)); ret = iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG, - CMD_SYNC, sizeof(bt_cmd_6000), &bt_cmd_6000); + CMD_SYNC, sizeof(bt_cmd_v1), &bt_cmd_v1); } if (ret) IWL_ERR(priv, "failed to send BT Coex Config\n"); @@ -615,7 +496,7 @@ static void iwlagn_print_uartmsg(struct iwl_priv *priv, struct iwl_bt_uart_msg *uart_msg) { IWL_DEBUG_COEX(priv, "Message Type = 0x%X, SSN = 0x%X, " - "Update Req = 0x%X", + "Update Req = 0x%X\n", (BT_UART_MSG_FRAME1MSGTYPE_MSK & uart_msg->frame1) >> BT_UART_MSG_FRAME1MSGTYPE_POS, (BT_UART_MSG_FRAME1SSN_MSK & uart_msg->frame1) >> @@ -624,7 +505,7 @@ static void iwlagn_print_uartmsg(struct iwl_priv *priv, BT_UART_MSG_FRAME1UPDATEREQ_POS); IWL_DEBUG_COEX(priv, "Open connections = 0x%X, Traffic load = 0x%X, " - "Chl_SeqN = 0x%X, In band = 0x%X", + "Chl_SeqN = 0x%X, In band = 0x%X\n", (BT_UART_MSG_FRAME2OPENCONNECTIONS_MSK & uart_msg->frame2) >> BT_UART_MSG_FRAME2OPENCONNECTIONS_POS, (BT_UART_MSG_FRAME2TRAFFICLOAD_MSK & uart_msg->frame2) >> @@ -635,7 +516,7 @@ static void iwlagn_print_uartmsg(struct iwl_priv *priv, BT_UART_MSG_FRAME2INBAND_POS); IWL_DEBUG_COEX(priv, "SCO/eSCO = 0x%X, Sniff = 0x%X, A2DP = 0x%X, " - "ACL = 0x%X, Master = 0x%X, OBEX = 0x%X", + "ACL = 0x%X, Master = 0x%X, OBEX = 0x%X\n", (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3) >> BT_UART_MSG_FRAME3SCOESCO_POS, (BT_UART_MSG_FRAME3SNIFF_MSK & uart_msg->frame3) >> @@ -649,12 +530,12 @@ static void iwlagn_print_uartmsg(struct iwl_priv *priv, (BT_UART_MSG_FRAME3OBEX_MSK & uart_msg->frame3) >> BT_UART_MSG_FRAME3OBEX_POS); - IWL_DEBUG_COEX(priv, "Idle duration = 0x%X", + IWL_DEBUG_COEX(priv, "Idle duration = 0x%X\n", (BT_UART_MSG_FRAME4IDLEDURATION_MSK & uart_msg->frame4) >> BT_UART_MSG_FRAME4IDLEDURATION_POS); IWL_DEBUG_COEX(priv, "Tx Activity = 0x%X, Rx Activity = 0x%X, " - "eSCO Retransmissions = 0x%X", + "eSCO Retransmissions = 0x%X\n", (BT_UART_MSG_FRAME5TXACTIVITY_MSK & uart_msg->frame5) >> BT_UART_MSG_FRAME5TXACTIVITY_POS, (BT_UART_MSG_FRAME5RXACTIVITY_MSK & uart_msg->frame5) >> @@ -662,14 +543,14 @@ static void iwlagn_print_uartmsg(struct iwl_priv *priv, (BT_UART_MSG_FRAME5ESCORETRANSMIT_MSK & uart_msg->frame5) >> BT_UART_MSG_FRAME5ESCORETRANSMIT_POS); - IWL_DEBUG_COEX(priv, "Sniff Interval = 0x%X, Discoverable = 0x%X", + IWL_DEBUG_COEX(priv, "Sniff Interval = 0x%X, Discoverable = 0x%X\n", (BT_UART_MSG_FRAME6SNIFFINTERVAL_MSK & uart_msg->frame6) >> BT_UART_MSG_FRAME6SNIFFINTERVAL_POS, (BT_UART_MSG_FRAME6DISCOVERABLE_MSK & uart_msg->frame6) >> BT_UART_MSG_FRAME6DISCOVERABLE_POS); IWL_DEBUG_COEX(priv, "Sniff Activity = 0x%X, Page = " - "0x%X, Inquiry = 0x%X, Connectable = 0x%X", + "0x%X, Inquiry = 0x%X, Connectable = 0x%X\n", (BT_UART_MSG_FRAME7SNIFFACTIVITY_MSK & uart_msg->frame7) >> BT_UART_MSG_FRAME7SNIFFACTIVITY_POS, (BT_UART_MSG_FRAME7PAGE_MSK & uart_msg->frame7) >> @@ -680,29 +561,62 @@ static void iwlagn_print_uartmsg(struct iwl_priv *priv, BT_UART_MSG_FRAME7CONNECTABLE_POS); } -static void iwlagn_set_kill_msk(struct iwl_priv *priv, +static bool iwlagn_set_kill_msk(struct iwl_priv *priv, struct iwl_bt_uart_msg *uart_msg) { - u8 kill_msk; - static const __le32 bt_kill_ack_msg[2] = { + bool need_update = false; + u8 kill_msk = IWL_BT_KILL_REDUCE; + static const __le32 bt_kill_ack_msg[3] = { IWLAGN_BT_KILL_ACK_MASK_DEFAULT, - IWLAGN_BT_KILL_ACK_CTS_MASK_SCO }; - static const __le32 bt_kill_cts_msg[2] = { + IWLAGN_BT_KILL_ACK_CTS_MASK_SCO, + IWLAGN_BT_KILL_ACK_CTS_MASK_REDUCE}; + static const __le32 bt_kill_cts_msg[3] = { IWLAGN_BT_KILL_CTS_MASK_DEFAULT, - IWLAGN_BT_KILL_ACK_CTS_MASK_SCO }; + IWLAGN_BT_KILL_ACK_CTS_MASK_SCO, + IWLAGN_BT_KILL_ACK_CTS_MASK_REDUCE}; - kill_msk = (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3) - ? 1 : 0; + if (!priv->reduced_txpower) + kill_msk = (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3) + ? IWL_BT_KILL_OVERRIDE : IWL_BT_KILL_DEFAULT; if (priv->kill_ack_mask != bt_kill_ack_msg[kill_msk] || priv->kill_cts_mask != bt_kill_cts_msg[kill_msk]) { priv->bt_valid |= IWLAGN_BT_VALID_KILL_ACK_MASK; priv->kill_ack_mask = bt_kill_ack_msg[kill_msk]; priv->bt_valid |= IWLAGN_BT_VALID_KILL_CTS_MASK; priv->kill_cts_mask = bt_kill_cts_msg[kill_msk]; + need_update = true; + } + return need_update; +} - /* schedule to send runtime bt_config */ - queue_work(priv->workqueue, &priv->bt_runtime_config); +static bool iwlagn_fill_txpower_mode(struct iwl_priv *priv, + struct iwl_bt_uart_msg *uart_msg) +{ + bool need_update = false; + + if (!priv->reduced_txpower && + !iwl_is_associated(priv, IWL_RXON_CTX_PAN) && + (uart_msg->frame3 & (BT_UART_MSG_FRAME3ACL_MSK | + BT_UART_MSG_FRAME3OBEX_MSK)) && + !(uart_msg->frame3 & (BT_UART_MSG_FRAME3SCOESCO_MSK | + BT_UART_MSG_FRAME3SNIFF_MSK | BT_UART_MSG_FRAME3A2DP_MSK))) { + /* enabling reduced tx power */ + priv->reduced_txpower = true; + priv->bt_valid |= IWLAGN_BT_VALID_REDUCED_TX_PWR; + need_update = true; + } else if (priv->reduced_txpower && + (iwl_is_associated(priv, IWL_RXON_CTX_PAN) || + (uart_msg->frame3 & (BT_UART_MSG_FRAME3SCOESCO_MSK | + BT_UART_MSG_FRAME3SNIFF_MSK | BT_UART_MSG_FRAME3A2DP_MSK)) || + !(uart_msg->frame3 & (BT_UART_MSG_FRAME3ACL_MSK | + BT_UART_MSG_FRAME3OBEX_MSK)))) { + /* disable reduced tx power */ + priv->reduced_txpower = false; + priv->bt_valid &= ~IWLAGN_BT_VALID_REDUCED_TX_PWR; + need_update = true; } + + return need_update; } int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, @@ -750,7 +664,12 @@ int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, } } - iwlagn_set_kill_msk(priv, uart_msg); + /* schedule to send runtime bt_config */ + /* check reduce power before change ack/cts kill mask */ + if (iwlagn_fill_txpower_mode(priv, uart_msg) || + iwlagn_set_kill_msk(priv, uart_msg)) + queue_work(priv->workqueue, &priv->bt_runtime_config); + /* FIXME: based on notification, adjust the prio_boost */ @@ -798,8 +717,8 @@ static bool is_single_rx_stream(struct iwl_priv *priv) */ static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) { - if (cfg(priv)->bt_params && - cfg(priv)->bt_params->advanced_bt_coexist && + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist && (priv->bt_full_concurrent || priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) { /* @@ -856,7 +775,7 @@ static u8 iwl_count_chain_bitmap(u32 chain_bitmap) void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { bool is_single = is_single_rx_stream(priv); - bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->shrd->status); + bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); u8 idle_rx_cnt, active_rx_cnt, valid_rx_cnt; u32 active_chains; u16 rx_chain; @@ -868,10 +787,10 @@ void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx) if (priv->chain_noise_data.active_chains) active_chains = priv->chain_noise_data.active_chains; else - active_chains = hw_params(priv).valid_rx_ant; + active_chains = priv->hw_params.valid_rx_ant; - if (cfg(priv)->bt_params && - cfg(priv)->bt_params->advanced_bt_coexist && + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist && (priv->bt_full_concurrent || priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) { /* @@ -1190,7 +1109,7 @@ int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan) memcpy(&rxon, &ctx->active, sizeof(rxon)); priv->ucode_loaded = false; - iwl_trans_stop_device(trans(priv)); + iwl_trans_stop_device(priv->trans); priv->wowlan = true; @@ -1212,7 +1131,7 @@ int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan) if (ret) goto out; - if (!iwlagn_mod_params.sw_crypto) { + if (!iwlwifi_mod_params.sw_crypto) { /* mark all keys clear */ priv->ucode_key_table = 0; ctx->key_mapping_keys = 0; @@ -1298,6 +1217,12 @@ int iwl_dvm_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) return -EIO; } + if (test_bit(STATUS_FW_ERROR, &priv->status)) { + IWL_ERR(priv, "Command %s failed: FW Error\n", + iwl_dvm_get_cmd_string(cmd->id)); + return -EIO; + } + /* * Synchronous commands from this op-mode must hold * the mutex, this ensures we don't try to send two @@ -1312,7 +1237,7 @@ int iwl_dvm_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) return -EIO; } - return iwl_trans_send_cmd(trans(priv), cmd); + return iwl_trans_send_cmd(priv->trans, cmd); } int iwl_dvm_send_cmd_pdu(struct iwl_priv *priv, u8 id, diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 7e590b349dd7..51e1a69ffdda 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -36,9 +36,9 @@ #include #include "iwl-dev.h" -#include "iwl-core.h" #include "iwl-agn.h" #include "iwl-op-mode.h" +#include "iwl-modparams.h" #define RS_NAME "iwl-agn-rs" @@ -420,7 +420,7 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv, load = rs_tl_get_load(lq_data, tid); - if ((iwlagn_mod_params.auto_agg) || (load > IWL_AGG_LOAD_THRESHOLD)) { + if ((iwlwifi_mod_params.auto_agg) || (load > IWL_AGG_LOAD_THRESHOLD)) { IWL_DEBUG_HT(priv, "Starting Tx agg: STA: %pM tid: %d\n", sta->addr, tid); ret = ieee80211_start_tx_ba_session(sta, tid, 5000); @@ -819,7 +819,7 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, if (num_of_ant(tbl->ant_type) > 1) tbl->ant_type = - first_antenna(hw_params(priv).valid_tx_ant); + first_antenna(priv->hw_params.valid_tx_ant); tbl->is_ht40 = 0; tbl->is_SGI = 0; @@ -969,7 +969,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, (tbl_type.is_SGI != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) || (tbl_type.is_ht40 != !!(mac_flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) || (tbl_type.is_dup != !!(mac_flags & IEEE80211_TX_RC_DUP_DATA)) || - (tbl_type.ant_type != info->antenna_sel_tx) || + (tbl_type.ant_type != info->status.antenna) || (!!(tx_rate & RATE_MCS_HT_MSK) != !!(mac_flags & IEEE80211_TX_RC_MCS)) || (!!(tx_rate & RATE_MCS_GF_MSK) != !!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD)) || (rs_index != mac_index)) { @@ -1085,7 +1085,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, (priv->tm_fixed_rate != lq_sta->dbg_fixed_rate)) rs_program_fix_rate(priv, lq_sta); #endif - if (cfg(priv)->bt_params && cfg(priv)->bt_params->advanced_bt_coexist) + if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist) rs_bt_update_lq(priv, ctx, lq_sta); } @@ -1291,7 +1291,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, return -1; /* Need both Tx chains/antennas to support MIMO */ - if (hw_params(priv).tx_chains_num < 2) + if (priv->hw_params.tx_chains_num < 2) return -1; IWL_DEBUG_RATE(priv, "LQ: try to switch to MIMO2\n"); @@ -1347,7 +1347,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv, return -1; /* Need both Tx chains/antennas to support MIMO */ - if (hw_params(priv).tx_chains_num < 3) + if (priv->hw_params.tx_chains_num < 3) return -1; IWL_DEBUG_RATE(priv, "LQ: try to switch to MIMO3\n"); @@ -1446,8 +1446,8 @@ static int rs_move_legacy_other(struct iwl_priv *priv, u32 sz = (sizeof(struct iwl_scale_tbl_info) - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action; - u8 valid_tx_ant = hw_params(priv).valid_tx_ant; - u8 tx_chains_num = hw_params(priv).tx_chains_num; + u8 valid_tx_ant = priv->hw_params.valid_tx_ant; + u8 tx_chains_num = priv->hw_params.tx_chains_num; int ret = 0; u8 update_search_tbl_counter = 0; @@ -1464,7 +1464,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv, case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS: /* avoid antenna B and MIMO */ valid_tx_ant = - first_antenna(hw_params(priv).valid_tx_ant); + first_antenna(priv->hw_params.valid_tx_ant); if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2 && tbl->action != IWL_LEGACY_SWITCH_SISO) tbl->action = IWL_LEGACY_SWITCH_SISO; @@ -1488,7 +1488,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv, else if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2) tbl->action = IWL_LEGACY_SWITCH_SISO; valid_tx_ant = - first_antenna(hw_params(priv).valid_tx_ant); + first_antenna(priv->hw_params.valid_tx_ant); } start_action = tbl->action; @@ -1622,8 +1622,8 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, u32 sz = (sizeof(struct iwl_scale_tbl_info) - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action; - u8 valid_tx_ant = hw_params(priv).valid_tx_ant; - u8 tx_chains_num = hw_params(priv).tx_chains_num; + u8 valid_tx_ant = priv->hw_params.valid_tx_ant; + u8 tx_chains_num = priv->hw_params.tx_chains_num; u8 update_search_tbl_counter = 0; int ret; @@ -1640,7 +1640,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS: /* avoid antenna B and MIMO */ valid_tx_ant = - first_antenna(hw_params(priv).valid_tx_ant); + first_antenna(priv->hw_params.valid_tx_ant); if (tbl->action != IWL_SISO_SWITCH_ANTENNA1) tbl->action = IWL_SISO_SWITCH_ANTENNA1; break; @@ -1658,7 +1658,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, /* configure as 1x1 if bt full concurrency */ if (priv->bt_full_concurrent) { valid_tx_ant = - first_antenna(hw_params(priv).valid_tx_ant); + first_antenna(priv->hw_params.valid_tx_ant); if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2) tbl->action = IWL_SISO_SWITCH_ANTENNA1; } @@ -1794,8 +1794,8 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, u32 sz = (sizeof(struct iwl_scale_tbl_info) - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action; - u8 valid_tx_ant = hw_params(priv).valid_tx_ant; - u8 tx_chains_num = hw_params(priv).tx_chains_num; + u8 valid_tx_ant = priv->hw_params.valid_tx_ant; + u8 tx_chains_num = priv->hw_params.tx_chains_num; u8 update_search_tbl_counter = 0; int ret; @@ -1964,8 +1964,8 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, u32 sz = (sizeof(struct iwl_scale_tbl_info) - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action; - u8 valid_tx_ant = hw_params(priv).valid_tx_ant; - u8 tx_chains_num = hw_params(priv).tx_chains_num; + u8 valid_tx_ant = priv->hw_params.valid_tx_ant; + u8 tx_chains_num = priv->hw_params.tx_chains_num; int ret; u8 update_search_tbl_counter = 0; @@ -2166,7 +2166,7 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) (lq_sta->total_success > lq_sta->max_success_limit) || ((!lq_sta->search_better_tbl) && (lq_sta->flush_timer) && (flush_interval_passed))) { - IWL_DEBUG_RATE(priv, "LQ: stay is expired %d %d %d\n:", + IWL_DEBUG_RATE(priv, "LQ: stay is expired %d %d %d\n", lq_sta->total_failed, lq_sta->total_success, flush_interval_passed); @@ -2698,7 +2698,7 @@ static void rs_initialize_lq(struct iwl_priv *priv, i = lq_sta->last_txrate_idx; - valid_tx_ant = hw_params(priv).valid_tx_ant; + valid_tx_ant = priv->hw_params.valid_tx_ant; if (!lq_sta->search_better_tbl) active_tbl = lq_sta->active_tbl; @@ -2826,6 +2826,7 @@ void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_i struct iwl_station_priv *sta_priv; struct iwl_lq_sta *lq_sta; struct ieee80211_supported_band *sband; + unsigned long supp; /* must be unsigned long for for_each_set_bit */ sta_priv = (struct iwl_station_priv *) sta->drv_priv; lq_sta = &sta_priv->lq_sta; @@ -2855,8 +2856,15 @@ void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_i lq_sta->max_rate_idx = -1; lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX; lq_sta->is_green = rs_use_green(sta); - lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000); - lq_sta->band = priv->band; + lq_sta->band = sband->band; + /* + * active legacy rates as per supported rates bitmap + */ + supp = sta->supp_rates[sband->band]; + lq_sta->active_legacy_rate = 0; + for_each_set_bit(i, &supp, BITS_PER_LONG) + lq_sta->active_legacy_rate |= BIT(sband->bitrates[i].hw_value); + /* * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3), * supp_rates[] does not; shift to convert format, force 9 MBits off. @@ -2884,15 +2892,15 @@ void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_i /* These values will be overridden later */ lq_sta->lq.general_params.single_stream_ant_msk = - first_antenna(hw_params(priv).valid_tx_ant); + first_antenna(priv->hw_params.valid_tx_ant); lq_sta->lq.general_params.dual_stream_ant_msk = - hw_params(priv).valid_tx_ant & - ~first_antenna(hw_params(priv).valid_tx_ant); + priv->hw_params.valid_tx_ant & + ~first_antenna(priv->hw_params.valid_tx_ant); if (!lq_sta->lq.general_params.dual_stream_ant_msk) { lq_sta->lq.general_params.dual_stream_ant_msk = ANT_AB; - } else if (num_of_ant(hw_params(priv).valid_tx_ant) == 2) { + } else if (num_of_ant(priv->hw_params.valid_tx_ant) == 2) { lq_sta->lq.general_params.dual_stream_ant_msk = - hw_params(priv).valid_tx_ant; + priv->hw_params.valid_tx_ant; } /* as default allow aggregation for all tids */ @@ -2938,7 +2946,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv, if (priv && priv->bt_full_concurrent) { /* 1x1 only */ tbl_type.ant_type = - first_antenna(hw_params(priv).valid_tx_ant); + first_antenna(priv->hw_params.valid_tx_ant); } /* How many times should we repeat the initial rate? */ @@ -2970,7 +2978,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv, if (priv->bt_full_concurrent) valid_tx_ant = ANT_A; else - valid_tx_ant = hw_params(priv).valid_tx_ant; + valid_tx_ant = priv->hw_params.valid_tx_ant; } /* Fill rest of rate table */ @@ -3004,7 +3012,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv, if (priv && priv->bt_full_concurrent) { /* 1x1 only */ tbl_type.ant_type = - first_antenna(hw_params(priv).valid_tx_ant); + first_antenna(priv->hw_params.valid_tx_ant); } /* Indicate to uCode which entries might be MIMO. @@ -3055,11 +3063,11 @@ static void rs_fill_link_cmd(struct iwl_priv *priv, * overwrite if needed, pass aggregation time limit * to uCode in uSec */ - if (priv && cfg(priv)->bt_params && - cfg(priv)->bt_params->agg_time_limit && + if (priv && priv->cfg->bt_params && + priv->cfg->bt_params->agg_time_limit && priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) lq_cmd->agg_params.agg_time_limit = - cpu_to_le16(cfg(priv)->bt_params->agg_time_limit); + cpu_to_le16(priv->cfg->bt_params->agg_time_limit); } static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) @@ -3091,7 +3099,7 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, u8 ant_sel_tx; priv = lq_sta->drv; - valid_tx_ant = hw_params(priv).valid_tx_ant; + valid_tx_ant = priv->hw_params.valid_tx_ant; if (lq_sta->dbg_fixed_rate) { ant_sel_tx = ((lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK) @@ -3162,9 +3170,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, desc += sprintf(buff+desc, "fixed rate 0x%X\n", lq_sta->dbg_fixed_rate); desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n", - (hw_params(priv).valid_tx_ant & ANT_A) ? "ANT_A," : "", - (hw_params(priv).valid_tx_ant & ANT_B) ? "ANT_B," : "", - (hw_params(priv).valid_tx_ant & ANT_C) ? "ANT_C" : ""); + (priv->hw_params.valid_tx_ant & ANT_A) ? "ANT_A," : "", + (priv->hw_params.valid_tx_ant & ANT_B) ? "ANT_B," : "", + (priv->hw_params.valid_tx_ant & ANT_C) ? "ANT_C" : ""); desc += sprintf(buff+desc, "lq type %s\n", (is_legacy(tbl->lq_type)) ? "legacy" : "HT"); if (is_Ht(tbl->lq_type)) { diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index 203b1c13c491..82d02e1ae89f 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -30,6 +30,7 @@ #include #include "iwl-commands.h" +#include "iwl-config.h" struct iwl_rate_info { u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ @@ -174,32 +175,6 @@ enum { IWL_RATE_11M_IEEE = 22, }; -#define IWL_CCK_BASIC_RATES_MASK \ - (IWL_RATE_1M_MASK | \ - IWL_RATE_2M_MASK) - -#define IWL_CCK_RATES_MASK \ - (IWL_CCK_BASIC_RATES_MASK | \ - IWL_RATE_5M_MASK | \ - IWL_RATE_11M_MASK) - -#define IWL_OFDM_BASIC_RATES_MASK \ - (IWL_RATE_6M_MASK | \ - IWL_RATE_12M_MASK | \ - IWL_RATE_24M_MASK) - -#define IWL_OFDM_RATES_MASK \ - (IWL_OFDM_BASIC_RATES_MASK | \ - IWL_RATE_9M_MASK | \ - IWL_RATE_18M_MASK | \ - IWL_RATE_36M_MASK | \ - IWL_RATE_48M_MASK | \ - IWL_RATE_54M_MASK) - -#define IWL_BASIC_RATES_MASK \ - (IWL_OFDM_BASIC_RATES_MASK | \ - IWL_CCK_BASIC_RATES_MASK) - #define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1) #define IWL_INVALID_VALUE -1 @@ -306,15 +281,6 @@ enum iwl_table_type { #define is_a_band(tbl) ((tbl) == LQ_A) #define is_g_and(tbl) ((tbl) == LQ_G) -#define ANT_NONE 0x0 -#define ANT_A BIT(0) -#define ANT_B BIT(1) -#define ANT_AB (ANT_A | ANT_B) -#define ANT_C BIT(2) -#define ANT_AC (ANT_A | ANT_C) -#define ANT_BC (ANT_B | ANT_C) -#define ANT_ABC (ANT_AB | ANT_C) - #define IWL_MAX_MCS_DISPLAY_SIZE 12 struct iwl_rate_mcs_info { diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rx.c index 22474608a70b..403de96f9747 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rx.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rx.c @@ -34,95 +34,91 @@ #include #include "iwl-eeprom.h" #include "iwl-dev.h" -#include "iwl-core.h" #include "iwl-io.h" #include "iwl-agn-calib.h" #include "iwl-agn.h" -#include "iwl-shared.h" - -const char *get_cmd_string(u8 cmd) -{ - switch (cmd) { - IWL_CMD(REPLY_ALIVE); - IWL_CMD(REPLY_ERROR); - IWL_CMD(REPLY_ECHO); - IWL_CMD(REPLY_RXON); - IWL_CMD(REPLY_RXON_ASSOC); - IWL_CMD(REPLY_QOS_PARAM); - IWL_CMD(REPLY_RXON_TIMING); - IWL_CMD(REPLY_ADD_STA); - IWL_CMD(REPLY_REMOVE_STA); - IWL_CMD(REPLY_REMOVE_ALL_STA); - IWL_CMD(REPLY_TXFIFO_FLUSH); - IWL_CMD(REPLY_WEPKEY); - IWL_CMD(REPLY_TX); - IWL_CMD(REPLY_LEDS_CMD); - IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); - IWL_CMD(COEX_PRIORITY_TABLE_CMD); - IWL_CMD(COEX_MEDIUM_NOTIFICATION); - IWL_CMD(COEX_EVENT_CMD); - IWL_CMD(REPLY_QUIET_CMD); - IWL_CMD(REPLY_CHANNEL_SWITCH); - IWL_CMD(CHANNEL_SWITCH_NOTIFICATION); - IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD); - IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION); - IWL_CMD(POWER_TABLE_CMD); - IWL_CMD(PM_SLEEP_NOTIFICATION); - IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC); - IWL_CMD(REPLY_SCAN_CMD); - IWL_CMD(REPLY_SCAN_ABORT_CMD); - IWL_CMD(SCAN_START_NOTIFICATION); - IWL_CMD(SCAN_RESULTS_NOTIFICATION); - IWL_CMD(SCAN_COMPLETE_NOTIFICATION); - IWL_CMD(BEACON_NOTIFICATION); - IWL_CMD(REPLY_TX_BEACON); - IWL_CMD(WHO_IS_AWAKE_NOTIFICATION); - IWL_CMD(QUIET_NOTIFICATION); - IWL_CMD(REPLY_TX_PWR_TABLE_CMD); - IWL_CMD(MEASURE_ABORT_NOTIFICATION); - IWL_CMD(REPLY_BT_CONFIG); - IWL_CMD(REPLY_STATISTICS_CMD); - IWL_CMD(STATISTICS_NOTIFICATION); - IWL_CMD(REPLY_CARD_STATE_CMD); - IWL_CMD(CARD_STATE_NOTIFICATION); - IWL_CMD(MISSED_BEACONS_NOTIFICATION); - IWL_CMD(REPLY_CT_KILL_CONFIG_CMD); - IWL_CMD(SENSITIVITY_CMD); - IWL_CMD(REPLY_PHY_CALIBRATION_CMD); - IWL_CMD(REPLY_RX_PHY_CMD); - IWL_CMD(REPLY_RX_MPDU_CMD); - IWL_CMD(REPLY_RX); - IWL_CMD(REPLY_COMPRESSED_BA); - IWL_CMD(CALIBRATION_CFG_CMD); - IWL_CMD(CALIBRATION_RES_NOTIFICATION); - IWL_CMD(CALIBRATION_COMPLETE_NOTIFICATION); - IWL_CMD(REPLY_TX_POWER_DBM_CMD); - IWL_CMD(TEMPERATURE_NOTIFICATION); - IWL_CMD(TX_ANT_CONFIGURATION_CMD); - IWL_CMD(REPLY_BT_COEX_PROFILE_NOTIF); - IWL_CMD(REPLY_BT_COEX_PRIO_TABLE); - IWL_CMD(REPLY_BT_COEX_PROT_ENV); - IWL_CMD(REPLY_WIPAN_PARAMS); - IWL_CMD(REPLY_WIPAN_RXON); - IWL_CMD(REPLY_WIPAN_RXON_TIMING); - IWL_CMD(REPLY_WIPAN_RXON_ASSOC); - IWL_CMD(REPLY_WIPAN_QOS_PARAM); - IWL_CMD(REPLY_WIPAN_WEPKEY); - IWL_CMD(REPLY_WIPAN_P2P_CHANNEL_SWITCH); - IWL_CMD(REPLY_WIPAN_NOA_NOTIFICATION); - IWL_CMD(REPLY_WIPAN_DEACTIVATION_COMPLETE); - IWL_CMD(REPLY_WOWLAN_PATTERNS); - IWL_CMD(REPLY_WOWLAN_WAKEUP_FILTER); - IWL_CMD(REPLY_WOWLAN_TSC_RSC_PARAMS); - IWL_CMD(REPLY_WOWLAN_TKIP_PARAMS); - IWL_CMD(REPLY_WOWLAN_KEK_KCK_MATERIAL); - IWL_CMD(REPLY_WOWLAN_GET_STATUS); - IWL_CMD(REPLY_D3_CONFIG); - default: - return "UNKNOWN"; - - } -} +#include "iwl-modparams.h" + +#define IWL_CMD_ENTRY(x) [x] = #x + +const char *iwl_dvm_cmd_strings[REPLY_MAX] = { + IWL_CMD_ENTRY(REPLY_ALIVE), + IWL_CMD_ENTRY(REPLY_ERROR), + IWL_CMD_ENTRY(REPLY_ECHO), + IWL_CMD_ENTRY(REPLY_RXON), + IWL_CMD_ENTRY(REPLY_RXON_ASSOC), + IWL_CMD_ENTRY(REPLY_QOS_PARAM), + IWL_CMD_ENTRY(REPLY_RXON_TIMING), + IWL_CMD_ENTRY(REPLY_ADD_STA), + IWL_CMD_ENTRY(REPLY_REMOVE_STA), + IWL_CMD_ENTRY(REPLY_REMOVE_ALL_STA), + IWL_CMD_ENTRY(REPLY_TXFIFO_FLUSH), + IWL_CMD_ENTRY(REPLY_WEPKEY), + IWL_CMD_ENTRY(REPLY_TX), + IWL_CMD_ENTRY(REPLY_LEDS_CMD), + IWL_CMD_ENTRY(REPLY_TX_LINK_QUALITY_CMD), + IWL_CMD_ENTRY(COEX_PRIORITY_TABLE_CMD), + IWL_CMD_ENTRY(COEX_MEDIUM_NOTIFICATION), + IWL_CMD_ENTRY(COEX_EVENT_CMD), + IWL_CMD_ENTRY(REPLY_QUIET_CMD), + IWL_CMD_ENTRY(REPLY_CHANNEL_SWITCH), + IWL_CMD_ENTRY(CHANNEL_SWITCH_NOTIFICATION), + IWL_CMD_ENTRY(REPLY_SPECTRUM_MEASUREMENT_CMD), + IWL_CMD_ENTRY(SPECTRUM_MEASURE_NOTIFICATION), + IWL_CMD_ENTRY(POWER_TABLE_CMD), + IWL_CMD_ENTRY(PM_SLEEP_NOTIFICATION), + IWL_CMD_ENTRY(PM_DEBUG_STATISTIC_NOTIFIC), + IWL_CMD_ENTRY(REPLY_SCAN_CMD), + IWL_CMD_ENTRY(REPLY_SCAN_ABORT_CMD), + IWL_CMD_ENTRY(SCAN_START_NOTIFICATION), + IWL_CMD_ENTRY(SCAN_RESULTS_NOTIFICATION), + IWL_CMD_ENTRY(SCAN_COMPLETE_NOTIFICATION), + IWL_CMD_ENTRY(BEACON_NOTIFICATION), + IWL_CMD_ENTRY(REPLY_TX_BEACON), + IWL_CMD_ENTRY(WHO_IS_AWAKE_NOTIFICATION), + IWL_CMD_ENTRY(QUIET_NOTIFICATION), + IWL_CMD_ENTRY(REPLY_TX_PWR_TABLE_CMD), + IWL_CMD_ENTRY(MEASURE_ABORT_NOTIFICATION), + IWL_CMD_ENTRY(REPLY_BT_CONFIG), + IWL_CMD_ENTRY(REPLY_STATISTICS_CMD), + IWL_CMD_ENTRY(STATISTICS_NOTIFICATION), + IWL_CMD_ENTRY(REPLY_CARD_STATE_CMD), + IWL_CMD_ENTRY(CARD_STATE_NOTIFICATION), + IWL_CMD_ENTRY(MISSED_BEACONS_NOTIFICATION), + IWL_CMD_ENTRY(REPLY_CT_KILL_CONFIG_CMD), + IWL_CMD_ENTRY(SENSITIVITY_CMD), + IWL_CMD_ENTRY(REPLY_PHY_CALIBRATION_CMD), + IWL_CMD_ENTRY(REPLY_RX_PHY_CMD), + IWL_CMD_ENTRY(REPLY_RX_MPDU_CMD), + IWL_CMD_ENTRY(REPLY_RX), + IWL_CMD_ENTRY(REPLY_COMPRESSED_BA), + IWL_CMD_ENTRY(CALIBRATION_CFG_CMD), + IWL_CMD_ENTRY(CALIBRATION_RES_NOTIFICATION), + IWL_CMD_ENTRY(CALIBRATION_COMPLETE_NOTIFICATION), + IWL_CMD_ENTRY(REPLY_TX_POWER_DBM_CMD), + IWL_CMD_ENTRY(TEMPERATURE_NOTIFICATION), + IWL_CMD_ENTRY(TX_ANT_CONFIGURATION_CMD), + IWL_CMD_ENTRY(REPLY_BT_COEX_PROFILE_NOTIF), + IWL_CMD_ENTRY(REPLY_BT_COEX_PRIO_TABLE), + IWL_CMD_ENTRY(REPLY_BT_COEX_PROT_ENV), + IWL_CMD_ENTRY(REPLY_WIPAN_PARAMS), + IWL_CMD_ENTRY(REPLY_WIPAN_RXON), + IWL_CMD_ENTRY(REPLY_WIPAN_RXON_TIMING), + IWL_CMD_ENTRY(REPLY_WIPAN_RXON_ASSOC), + IWL_CMD_ENTRY(REPLY_WIPAN_QOS_PARAM), + IWL_CMD_ENTRY(REPLY_WIPAN_WEPKEY), + IWL_CMD_ENTRY(REPLY_WIPAN_P2P_CHANNEL_SWITCH), + IWL_CMD_ENTRY(REPLY_WIPAN_NOA_NOTIFICATION), + IWL_CMD_ENTRY(REPLY_WIPAN_DEACTIVATION_COMPLETE), + IWL_CMD_ENTRY(REPLY_WOWLAN_PATTERNS), + IWL_CMD_ENTRY(REPLY_WOWLAN_WAKEUP_FILTER), + IWL_CMD_ENTRY(REPLY_WOWLAN_TSC_RSC_PARAMS), + IWL_CMD_ENTRY(REPLY_WOWLAN_TKIP_PARAMS), + IWL_CMD_ENTRY(REPLY_WOWLAN_KEK_KCK_MATERIAL), + IWL_CMD_ENTRY(REPLY_WOWLAN_GET_STATUS), + IWL_CMD_ENTRY(REPLY_D3_CONFIG), +}; +#undef IWL_CMD_ENTRY /****************************************************************************** * @@ -137,10 +133,9 @@ static int iwlagn_rx_reply_error(struct iwl_priv *priv, struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_error_resp *err_resp = (void *)pkt->data; - IWL_ERR(priv, "Error Reply type 0x%08X cmd %s (0x%02X) " + IWL_ERR(priv, "Error Reply type 0x%08X cmd REPLY_ERROR (0x%02X) " "seq 0x%04X ser 0x%08X\n", le32_to_cpu(err_resp->error_type), - get_cmd_string(err_resp->cmd_id), err_resp->cmd_id, le16_to_cpu(err_resp->bad_cmd_seq_num), le32_to_cpu(err_resp->error_info)); @@ -216,8 +211,7 @@ static int iwlagn_rx_pm_debug_statistics_notif(struct iwl_priv *priv, u32 __maybe_unused len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " - "notification for %s:\n", len, - get_cmd_string(pkt->hdr.cmd)); + "notification for PM_DEBUG_STATISTIC_NOTIFIC:\n", len); iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->data, len); return 0; } @@ -246,69 +240,6 @@ static int iwlagn_rx_beacon_notif(struct iwl_priv *priv, return 0; } -/* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */ -#define ACK_CNT_RATIO (50) -#define BA_TIMEOUT_CNT (5) -#define BA_TIMEOUT_MAX (16) - -/** - * iwl_good_ack_health - checks for ACK count ratios, BA timeout retries. - * - * When the ACK count ratio is low and aggregated BA timeout retries exceeding - * the BA_TIMEOUT_MAX, reload firmware and bring system back to normal - * operation state. - */ -static bool iwlagn_good_ack_health(struct iwl_priv *priv, - struct statistics_tx *cur) -{ - int actual_delta, expected_delta, ba_timeout_delta; - struct statistics_tx *old; - - if (priv->agg_tids_count) - return true; - - lockdep_assert_held(&priv->statistics.lock); - - old = &priv->statistics.tx; - - actual_delta = le32_to_cpu(cur->actual_ack_cnt) - - le32_to_cpu(old->actual_ack_cnt); - expected_delta = le32_to_cpu(cur->expected_ack_cnt) - - le32_to_cpu(old->expected_ack_cnt); - - /* Values should not be negative, but we do not trust the firmware */ - if (actual_delta <= 0 || expected_delta <= 0) - return true; - - ba_timeout_delta = le32_to_cpu(cur->agg.ba_timeout) - - le32_to_cpu(old->agg.ba_timeout); - - if ((actual_delta * 100 / expected_delta) < ACK_CNT_RATIO && - ba_timeout_delta > BA_TIMEOUT_CNT) { - IWL_DEBUG_RADIO(priv, - "deltas: actual %d expected %d ba_timeout %d\n", - actual_delta, expected_delta, ba_timeout_delta); - -#ifdef CONFIG_IWLWIFI_DEBUGFS - /* - * This is ifdef'ed on DEBUGFS because otherwise the - * statistics aren't available. If DEBUGFS is set but - * DEBUG is not, these will just compile out. - */ - IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta %d\n", - priv->delta_stats.tx.rx_detected_cnt); - IWL_DEBUG_RADIO(priv, - "ack_or_ba_timeout_collision delta %d\n", - priv->delta_stats.tx.ack_or_ba_timeout_collision); -#endif - - if (ba_timeout_delta >= BA_TIMEOUT_MAX) - return false; - } - - return true; -} - /** * iwl_good_plcp_health - checks for plcp error. * @@ -347,6 +278,45 @@ static bool iwlagn_good_plcp_health(struct iwl_priv *priv, return true; } +int iwl_force_rf_reset(struct iwl_priv *priv, bool external) +{ + struct iwl_rf_reset *rf_reset; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return -EAGAIN; + + if (!iwl_is_any_associated(priv)) { + IWL_DEBUG_SCAN(priv, "force reset rejected: not associated\n"); + return -ENOLINK; + } + + rf_reset = &priv->rf_reset; + rf_reset->reset_request_count++; + if (!external && rf_reset->last_reset_jiffies && + time_after(rf_reset->last_reset_jiffies + + IWL_DELAY_NEXT_FORCE_RF_RESET, jiffies)) { + IWL_DEBUG_INFO(priv, "RF reset rejected\n"); + rf_reset->reset_reject_count++; + return -EAGAIN; + } + rf_reset->reset_success_count++; + rf_reset->last_reset_jiffies = jiffies; + + /* + * There is no easy and better way to force reset the radio, + * the only known method is switching channel which will force to + * reset and tune the radio. + * Use internal short scan (single channel) operation to should + * achieve this objective. + * Driver should reset the radio when number of consecutive missed + * beacon, or any other uCode error condition detected. + */ + IWL_DEBUG_INFO(priv, "perform radio reset.\n"); + iwl_internal_short_hw_scan(priv); + return 0; +} + + static void iwlagn_recover_from_statistics(struct iwl_priv *priv, struct statistics_rx_phy *cur_ofdm, struct statistics_rx_ht_phy *cur_ofdm_ht, @@ -368,15 +338,9 @@ static void iwlagn_recover_from_statistics(struct iwl_priv *priv, if (msecs < 99) return; - if (iwlagn_mod_params.ack_check && !iwlagn_good_ack_health(priv, tx)) { - IWL_ERR(priv, "low ack count detected, restart firmware\n"); - if (!iwl_force_reset(priv, IWL_FW_RESET, false)) - return; - } - - if (iwlagn_mod_params.plcp_check && + if (iwlwifi_mod_params.plcp_check && !iwlagn_good_plcp_health(priv, cur_ofdm, cur_ofdm_ht, msecs)) - iwl_force_reset(priv, IWL_RF_RESET, false); + iwl_force_rf_reset(priv, false); } /* Calculate noise level, based on measurements during network silence just @@ -589,8 +553,8 @@ static int iwlagn_rx_statistics(struct iwl_priv *priv, iwlagn_rx_calc_noise(priv); queue_work(priv->workqueue, &priv->run_time_calib_work); } - if (cfg(priv)->lib->temperature && change) - cfg(priv)->lib->temperature(priv); + if (priv->lib->temperature && change) + priv->lib->temperature(priv); spin_unlock(&priv->statistics.lock); @@ -639,16 +603,16 @@ static int iwlagn_rx_card_state_notif(struct iwl_priv *priv, if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED | CT_CARD_DISABLED)) { - iwl_write32(trans(priv), CSR_UCODE_DRV_GP1_SET, + iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - iwl_write_direct32(trans(priv), HBUS_TARG_MBX_C, + iwl_write_direct32(priv->trans, HBUS_TARG_MBX_C, HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); if (!(flags & RXON_CARD_DISABLED)) { - iwl_write32(trans(priv), CSR_UCODE_DRV_GP1_CLR, + iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - iwl_write_direct32(trans(priv), HBUS_TARG_MBX_C, + iwl_write_direct32(priv->trans, HBUS_TARG_MBX_C, HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); } if (flags & CT_CARD_DISABLED) @@ -671,7 +635,7 @@ static int iwlagn_rx_card_state_notif(struct iwl_priv *priv, wiphy_rfkill_set_hw_state(priv->hw->wiphy, test_bit(STATUS_RF_KILL_HW, &priv->status)); else - wake_up(&trans(priv)->wait_command_queue); + wake_up(&priv->trans->wait_command_queue); return 0; } @@ -783,7 +747,7 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv, } /* In case of HW accelerated crypto and bad decryption, drop */ - if (!iwlagn_mod_params.sw_crypto && + if (!iwlwifi_mod_params.sw_crypto && iwlagn_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; @@ -795,17 +759,22 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv, IWL_ERR(priv, "alloc_skb failed\n"); return; } - hdrlen = min_t(unsigned int, len, skb_tailroom(skb)); + /* If frame is small enough to fit in skb->head, pull it completely. + * If not, only pull ieee80211_hdr so that splice() or TCP coalesce + * are more efficient. + */ + hdrlen = (len <= skb_tailroom(skb)) ? len : sizeof(*hdr); + memcpy(skb_put(skb, hdrlen), hdr, hdrlen); fraglen = len - hdrlen; if (fraglen) { - int offset = (void *)hdr + hdrlen - rxb_addr(rxb); + int offset = (void *)hdr + hdrlen - + rxb_addr(rxb) + rxb_offset(rxb); skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset, fraglen, rxb->truesize); } - iwl_update_stats(priv, false, fc, len); /* * Wake any queues that were stopped due to a passive channel tx @@ -816,8 +785,8 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv, */ if (unlikely(ieee80211_is_beacon(fc) && priv->passive_no_rx)) { for_each_context(priv, ctx) { - if (compare_ether_addr(hdr->addr3, - ctx->active.bssid_addr)) + if (!ether_addr_equal(hdr->addr3, + ctx->active.bssid_addr)) continue; iwlagn_lift_passive_no_rx(priv); } @@ -977,7 +946,7 @@ static int iwlagn_rx_reply_rx(struct iwl_priv *priv, } if ((unlikely(phy_res->cfg_phy_cnt > 20))) { - IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n", + IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d\n", phy_res->cfg_phy_cnt); return 0; } @@ -1012,7 +981,6 @@ static int iwlagn_rx_reply_rx(struct iwl_priv *priv, /* Find max signal strength (dBm) among 3 antenna/receiver chains */ rx_status.signal = iwlagn_calc_rssi(priv, phy_res); - iwl_dbg_log_rx_data_frame(priv, len, header); IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, TSF %llu\n", rx_status.signal, (unsigned long long)rx_status.mactime); @@ -1141,16 +1109,13 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv) handlers[REPLY_COMPRESSED_BA] = iwlagn_rx_reply_compressed_ba; - /* init calibration handlers */ - priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] = - iwlagn_rx_calib_result; priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx; /* set up notification wait support */ iwl_notification_wait_init(&priv->notif_wait); /* Set up BT Rx handlers */ - if (cfg(priv)->bt_params) + if (priv->cfg->bt_params) iwlagn_bt_rx_handler_setup(priv); } @@ -1192,9 +1157,9 @@ int iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb, err = priv->rx_handlers[pkt->hdr.cmd] (priv, rxb, cmd); } else { /* No handling needed */ - IWL_DEBUG_RX(priv, - "No handler needed for %s, 0x%02x\n", - get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); + IWL_DEBUG_RX(priv, "No handler needed for %s, 0x%02x\n", + iwl_dvm_get_cmd_string(pkt->hdr.cmd), + pkt->hdr.cmd); } } return err; diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 2e1a31797a9e..74fbee627306 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -24,12 +24,79 @@ * *****************************************************************************/ +#include #include "iwl-dev.h" #include "iwl-agn.h" -#include "iwl-core.h" #include "iwl-agn-calib.h" #include "iwl-trans.h" -#include "iwl-shared.h" +#include "iwl-modparams.h" + +/* + * initialize rxon structure with default values from eeprom + */ +void iwl_connection_init_rx_config(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + const struct iwl_channel_info *ch_info; + + memset(&ctx->staging, 0, sizeof(ctx->staging)); + + if (!ctx->vif) { + ctx->staging.dev_type = ctx->unused_devtype; + } else + switch (ctx->vif->type) { + case NL80211_IFTYPE_AP: + ctx->staging.dev_type = ctx->ap_devtype; + break; + + case NL80211_IFTYPE_STATION: + ctx->staging.dev_type = ctx->station_devtype; + ctx->staging.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK; + break; + + case NL80211_IFTYPE_ADHOC: + ctx->staging.dev_type = ctx->ibss_devtype; + ctx->staging.flags = RXON_FLG_SHORT_PREAMBLE_MSK; + ctx->staging.filter_flags = RXON_FILTER_BCON_AWARE_MSK | + RXON_FILTER_ACCEPT_GRP_MSK; + break; + + default: + IWL_ERR(priv, "Unsupported interface type %d\n", + ctx->vif->type); + break; + } + +#if 0 + /* TODO: Figure out when short_preamble would be set and cache from + * that */ + if (!hw_to_local(priv->hw)->short_preamble) + ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; + else + ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; +#endif + + ch_info = iwl_get_channel_info(priv, priv->band, + le16_to_cpu(ctx->active.channel)); + + if (!ch_info) + ch_info = &priv->channel_info[0]; + + ctx->staging.channel = cpu_to_le16(ch_info->channel); + priv->band = ch_info->band; + + iwl_set_flags_for_band(priv, ctx, priv->band, ctx->vif); + + /* clear both MIX and PURE40 mode flag */ + ctx->staging.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED | + RXON_FLG_CHANNEL_MODE_PURE_40); + if (ctx->vif) + memcpy(ctx->staging.node_addr, ctx->vif->addr, ETH_ALEN); + + ctx->staging.ofdm_ht_single_stream_basic_rates = 0xff; + ctx->staging.ofdm_ht_dual_stream_basic_rates = 0xff; + ctx->staging.ofdm_ht_triple_stream_basic_rates = 0xff; +} static int iwlagn_disable_bss(struct iwl_priv *priv, struct iwl_rxon_context *ctx, @@ -59,9 +126,12 @@ static int iwlagn_disable_pan(struct iwl_priv *priv, __le32 old_filter = send->filter_flags; u8 old_dev_type = send->dev_type; int ret; + static const u8 deactivate_cmd[] = { + REPLY_WIPAN_DEACTIVATION_COMPLETE + }; iwl_init_notification_wait(&priv->notif_wait, &disable_wait, - REPLY_WIPAN_DEACTIVATION_COMPLETE, + deactivate_cmd, ARRAY_SIZE(deactivate_cmd), NULL, NULL); send->filter_flags &= ~RXON_FILTER_ASSOC_MSK; @@ -101,8 +171,7 @@ static int iwlagn_disconn_pan(struct iwl_priv *priv, return ret; } -static void iwlagn_update_qos(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) +void iwlagn_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { int ret; @@ -129,8 +198,8 @@ static void iwlagn_update_qos(struct iwl_priv *priv, IWL_DEBUG_QUIET_RFKILL(priv, "Failed to update QoS\n"); } -static int iwlagn_update_beacon(struct iwl_priv *priv, - struct ieee80211_vif *vif) +int iwlagn_update_beacon(struct iwl_priv *priv, + struct ieee80211_vif *vif) { lockdep_assert_held(&priv->mutex); @@ -186,6 +255,109 @@ static int iwlagn_send_rxon_assoc(struct iwl_priv *priv, return ret; } +static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val) +{ + u16 new_val; + u16 beacon_factor; + + /* + * If mac80211 hasn't given us a beacon interval, program + * the default into the device (not checking this here + * would cause the adjustment below to return the maximum + * value, which may break PAN.) + */ + if (!beacon_val) + return DEFAULT_BEACON_INTERVAL; + + /* + * If the beacon interval we obtained from the peer + * is too large, we'll have to wake up more often + * (and in IBSS case, we'll beacon too much) + * + * For example, if max_beacon_val is 4096, and the + * requested beacon interval is 7000, we'll have to + * use 3500 to be able to wake up on the beacons. + * + * This could badly influence beacon detection stats. + */ + + beacon_factor = (beacon_val + max_beacon_val) / max_beacon_val; + new_val = beacon_val / beacon_factor; + + if (!new_val) + new_val = max_beacon_val; + + return new_val; +} + +static int iwl_send_rxon_timing(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + u64 tsf; + s32 interval_tm, rem; + struct ieee80211_conf *conf = NULL; + u16 beacon_int; + struct ieee80211_vif *vif = ctx->vif; + + conf = &priv->hw->conf; + + lockdep_assert_held(&priv->mutex); + + memset(&ctx->timing, 0, sizeof(struct iwl_rxon_time_cmd)); + + ctx->timing.timestamp = cpu_to_le64(priv->timestamp); + ctx->timing.listen_interval = cpu_to_le16(conf->listen_interval); + + beacon_int = vif ? vif->bss_conf.beacon_int : 0; + + /* + * TODO: For IBSS we need to get atim_window from mac80211, + * for now just always use 0 + */ + ctx->timing.atim_window = 0; + + if (ctx->ctxid == IWL_RXON_CTX_PAN && + (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION) && + iwl_is_associated(priv, IWL_RXON_CTX_BSS) && + priv->contexts[IWL_RXON_CTX_BSS].vif && + priv->contexts[IWL_RXON_CTX_BSS].vif->bss_conf.beacon_int) { + ctx->timing.beacon_interval = + priv->contexts[IWL_RXON_CTX_BSS].timing.beacon_interval; + beacon_int = le16_to_cpu(ctx->timing.beacon_interval); + } else if (ctx->ctxid == IWL_RXON_CTX_BSS && + iwl_is_associated(priv, IWL_RXON_CTX_PAN) && + priv->contexts[IWL_RXON_CTX_PAN].vif && + priv->contexts[IWL_RXON_CTX_PAN].vif->bss_conf.beacon_int && + (!iwl_is_associated_ctx(ctx) || !ctx->vif || + !ctx->vif->bss_conf.beacon_int)) { + ctx->timing.beacon_interval = + priv->contexts[IWL_RXON_CTX_PAN].timing.beacon_interval; + beacon_int = le16_to_cpu(ctx->timing.beacon_interval); + } else { + beacon_int = iwl_adjust_beacon_interval(beacon_int, + IWL_MAX_UCODE_BEACON_INTERVAL * TIME_UNIT); + ctx->timing.beacon_interval = cpu_to_le16(beacon_int); + } + + ctx->beacon_int = beacon_int; + + tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */ + interval_tm = beacon_int * TIME_UNIT; + rem = do_div(tsf, interval_tm); + ctx->timing.beacon_init_val = cpu_to_le32(interval_tm - rem); + + ctx->timing.dtim_period = vif ? (vif->bss_conf.dtim_period ?: 1) : 1; + + IWL_DEBUG_ASSOC(priv, + "beacon interval %d beacon timer %d beacon tim %d\n", + le16_to_cpu(ctx->timing.beacon_interval), + le32_to_cpu(ctx->timing.beacon_init_val), + le16_to_cpu(ctx->timing.atim_window)); + + return iwl_dvm_send_cmd_pdu(priv, ctx->rxon_timing_cmd, + CMD_SYNC, sizeof(ctx->timing), &ctx->timing); +} + static int iwlagn_rxon_disconn(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { @@ -228,6 +400,64 @@ static int iwlagn_rxon_disconn(struct iwl_priv *priv, return 0; } +static int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) +{ + int ret; + s8 prev_tx_power; + bool defer; + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; + + if (priv->calib_disabled & IWL_TX_POWER_CALIB_DISABLED) + return 0; + + lockdep_assert_held(&priv->mutex); + + if (priv->tx_power_user_lmt == tx_power && !force) + return 0; + + if (tx_power < IWLAGN_TX_POWER_TARGET_POWER_MIN) { + IWL_WARN(priv, + "Requested user TXPOWER %d below lower limit %d.\n", + tx_power, + IWLAGN_TX_POWER_TARGET_POWER_MIN); + return -EINVAL; + } + + if (tx_power > priv->tx_power_device_lmt) { + IWL_WARN(priv, + "Requested user TXPOWER %d above upper limit %d.\n", + tx_power, priv->tx_power_device_lmt); + return -EINVAL; + } + + if (!iwl_is_ready_rf(priv)) + return -EIO; + + /* scan complete and commit_rxon use tx_power_next value, + * it always need to be updated for newest request */ + priv->tx_power_next = tx_power; + + /* do not set tx power when scanning or channel changing */ + defer = test_bit(STATUS_SCANNING, &priv->status) || + memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging)); + if (defer && !force) { + IWL_DEBUG_INFO(priv, "Deferring tx power set\n"); + return 0; + } + + prev_tx_power = priv->tx_power_user_lmt; + priv->tx_power_user_lmt = tx_power; + + ret = iwlagn_send_tx_power(priv); + + /* if fail to set tx_power, restore the orig. tx power */ + if (ret) { + priv->tx_power_user_lmt = prev_tx_power; + priv->tx_power_next = prev_tx_power; + } + return ret; +} + static int iwlagn_rxon_connect(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { @@ -295,9 +525,9 @@ static int iwlagn_rxon_connect(struct iwl_priv *priv, } if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION && - cfg(priv)->ht_params && cfg(priv)->ht_params->smps_mode) + priv->cfg->ht_params && priv->cfg->ht_params->smps_mode) ieee80211_request_smps(ctx->vif, - cfg(priv)->ht_params->smps_mode); + priv->cfg->ht_params->smps_mode); return 0; } @@ -309,7 +539,7 @@ int iwlagn_set_pan_params(struct iwl_priv *priv) int slot0 = 300, slot1 = 0; int ret; - if (priv->shrd->valid_contexts == BIT(IWL_RXON_CTX_BSS)) + if (priv->valid_contexts == BIT(IWL_RXON_CTX_BSS)) return 0; BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); @@ -394,6 +624,414 @@ int iwlagn_set_pan_params(struct iwl_priv *priv) return ret; } +static void _iwl_set_rxon_ht(struct iwl_priv *priv, + struct iwl_ht_config *ht_conf, + struct iwl_rxon_context *ctx) +{ + struct iwl_rxon_cmd *rxon = &ctx->staging; + + if (!ctx->ht.enabled) { + rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | + RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | + RXON_FLG_HT40_PROT_MSK | + RXON_FLG_HT_PROT_MSK); + return; + } + + /* FIXME: if the definition of ht.protection changed, the "translation" + * will be needed for rxon->flags + */ + rxon->flags |= cpu_to_le32(ctx->ht.protection << + RXON_FLG_HT_OPERATING_MODE_POS); + + /* Set up channel bandwidth: + * 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */ + /* clear the HT channel mode before set the mode */ + rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | + RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); + if (iwl_is_ht40_tx_allowed(priv, ctx, NULL)) { + /* pure ht40 */ + if (ctx->ht.protection == + IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) { + rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40; + /* + * Note: control channel is opposite of extension + * channel + */ + switch (ctx->ht.extension_chan_offset) { + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: + rxon->flags &= + ~RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; + break; + case IEEE80211_HT_PARAM_CHA_SEC_BELOW: + rxon->flags |= + RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; + break; + } + } else { + /* + * Note: control channel is opposite of extension + * channel + */ + switch (ctx->ht.extension_chan_offset) { + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: + rxon->flags &= + ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); + rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED; + break; + case IEEE80211_HT_PARAM_CHA_SEC_BELOW: + rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; + rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED; + break; + case IEEE80211_HT_PARAM_CHA_SEC_NONE: + default: + /* + * channel location only valid if in Mixed + * mode + */ + IWL_ERR(priv, + "invalid extension channel offset\n"); + break; + } + } + } else { + rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY; + } + + iwlagn_set_rxon_chain(priv, ctx); + + IWL_DEBUG_ASSOC(priv, "rxon flags 0x%X operation mode :0x%X " + "extension channel offset 0x%x\n", + le32_to_cpu(rxon->flags), ctx->ht.protection, + ctx->ht.extension_chan_offset); +} + +void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf) +{ + struct iwl_rxon_context *ctx; + + for_each_context(priv, ctx) + _iwl_set_rxon_ht(priv, ht_conf, ctx); +} + +/** + * iwl_set_rxon_channel - Set the band and channel values in staging RXON + * @ch: requested channel as a pointer to struct ieee80211_channel + + * NOTE: Does not commit to the hardware; it sets appropriate bit fields + * in the staging RXON flag structure based on the ch->band + */ +void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch, + struct iwl_rxon_context *ctx) +{ + enum ieee80211_band band = ch->band; + u16 channel = ch->hw_value; + + if ((le16_to_cpu(ctx->staging.channel) == channel) && + (priv->band == band)) + return; + + ctx->staging.channel = cpu_to_le16(channel); + if (band == IEEE80211_BAND_5GHZ) + ctx->staging.flags &= ~RXON_FLG_BAND_24G_MSK; + else + ctx->staging.flags |= RXON_FLG_BAND_24G_MSK; + + priv->band = band; + + IWL_DEBUG_INFO(priv, "Staging channel set to %d [%d]\n", channel, band); + +} + +void iwl_set_flags_for_band(struct iwl_priv *priv, + struct iwl_rxon_context *ctx, + enum ieee80211_band band, + struct ieee80211_vif *vif) +{ + if (band == IEEE80211_BAND_5GHZ) { + ctx->staging.flags &= + ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK + | RXON_FLG_CCK_MSK); + ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK; + } else { + /* Copied from iwl_post_associate() */ + if (vif && vif->bss_conf.use_short_slot) + ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK; + else + ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + + ctx->staging.flags |= RXON_FLG_BAND_24G_MSK; + ctx->staging.flags |= RXON_FLG_AUTO_DETECT_MSK; + ctx->staging.flags &= ~RXON_FLG_CCK_MSK; + } +} + +static void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, + struct iwl_rxon_context *ctx, int hw_decrypt) +{ + struct iwl_rxon_cmd *rxon = &ctx->staging; + + if (hw_decrypt) + rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK; + else + rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK; + +} + +/* validate RXON structure is valid */ +static int iwl_check_rxon_cmd(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + struct iwl_rxon_cmd *rxon = &ctx->staging; + u32 errors = 0; + + if (rxon->flags & RXON_FLG_BAND_24G_MSK) { + if (rxon->flags & RXON_FLG_TGJ_NARROW_BAND_MSK) { + IWL_WARN(priv, "check 2.4G: wrong narrow\n"); + errors |= BIT(0); + } + if (rxon->flags & RXON_FLG_RADAR_DETECT_MSK) { + IWL_WARN(priv, "check 2.4G: wrong radar\n"); + errors |= BIT(1); + } + } else { + if (!(rxon->flags & RXON_FLG_SHORT_SLOT_MSK)) { + IWL_WARN(priv, "check 5.2G: not short slot!\n"); + errors |= BIT(2); + } + if (rxon->flags & RXON_FLG_CCK_MSK) { + IWL_WARN(priv, "check 5.2G: CCK!\n"); + errors |= BIT(3); + } + } + if ((rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1) { + IWL_WARN(priv, "mac/bssid mcast!\n"); + errors |= BIT(4); + } + + /* make sure basic rates 6Mbps and 1Mbps are supported */ + if ((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0 && + (rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0) { + IWL_WARN(priv, "neither 1 nor 6 are basic\n"); + errors |= BIT(5); + } + + if (le16_to_cpu(rxon->assoc_id) > 2007) { + IWL_WARN(priv, "aid > 2007\n"); + errors |= BIT(6); + } + + if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) + == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) { + IWL_WARN(priv, "CCK and short slot\n"); + errors |= BIT(7); + } + + if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) + == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) { + IWL_WARN(priv, "CCK and auto detect"); + errors |= BIT(8); + } + + if ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK | + RXON_FLG_TGG_PROTECT_MSK)) == + RXON_FLG_TGG_PROTECT_MSK) { + IWL_WARN(priv, "TGg but no auto-detect\n"); + errors |= BIT(9); + } + + if (rxon->channel == 0) { + IWL_WARN(priv, "zero channel is invalid\n"); + errors |= BIT(10); + } + + WARN(errors, "Invalid RXON (%#x), channel %d", + errors, le16_to_cpu(rxon->channel)); + + return errors ? -EINVAL : 0; +} + +/** + * iwl_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed + * @priv: staging_rxon is compared to active_rxon + * + * If the RXON structure is changing enough to require a new tune, + * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that + * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required. + */ +int iwl_full_rxon_required(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + const struct iwl_rxon_cmd *staging = &ctx->staging; + const struct iwl_rxon_cmd *active = &ctx->active; + +#define CHK(cond) \ + if ((cond)) { \ + IWL_DEBUG_INFO(priv, "need full RXON - " #cond "\n"); \ + return 1; \ + } + +#define CHK_NEQ(c1, c2) \ + if ((c1) != (c2)) { \ + IWL_DEBUG_INFO(priv, "need full RXON - " \ + #c1 " != " #c2 " - %d != %d\n", \ + (c1), (c2)); \ + return 1; \ + } + + /* These items are only settable from the full RXON command */ + CHK(!iwl_is_associated_ctx(ctx)); + CHK(!ether_addr_equal(staging->bssid_addr, active->bssid_addr)); + CHK(!ether_addr_equal(staging->node_addr, active->node_addr)); + CHK(!ether_addr_equal(staging->wlap_bssid_addr, + active->wlap_bssid_addr)); + CHK_NEQ(staging->dev_type, active->dev_type); + CHK_NEQ(staging->channel, active->channel); + CHK_NEQ(staging->air_propagation, active->air_propagation); + CHK_NEQ(staging->ofdm_ht_single_stream_basic_rates, + active->ofdm_ht_single_stream_basic_rates); + CHK_NEQ(staging->ofdm_ht_dual_stream_basic_rates, + active->ofdm_ht_dual_stream_basic_rates); + CHK_NEQ(staging->ofdm_ht_triple_stream_basic_rates, + active->ofdm_ht_triple_stream_basic_rates); + CHK_NEQ(staging->assoc_id, active->assoc_id); + + /* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can + * be updated with the RXON_ASSOC command -- however only some + * flag transitions are allowed using RXON_ASSOC */ + + /* Check if we are not switching bands */ + CHK_NEQ(staging->flags & RXON_FLG_BAND_24G_MSK, + active->flags & RXON_FLG_BAND_24G_MSK); + + /* Check if we are switching association toggle */ + CHK_NEQ(staging->filter_flags & RXON_FILTER_ASSOC_MSK, + active->filter_flags & RXON_FILTER_ASSOC_MSK); + +#undef CHK +#undef CHK_NEQ + + return 0; +} + +#ifdef CONFIG_IWLWIFI_DEBUG +void iwl_print_rx_config_cmd(struct iwl_priv *priv, + enum iwl_rxon_context_id ctxid) +{ + struct iwl_rxon_context *ctx = &priv->contexts[ctxid]; + struct iwl_rxon_cmd *rxon = &ctx->staging; + + IWL_DEBUG_RADIO(priv, "RX CONFIG:\n"); + iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); + IWL_DEBUG_RADIO(priv, "u16 channel: 0x%x\n", + le16_to_cpu(rxon->channel)); + IWL_DEBUG_RADIO(priv, "u32 flags: 0x%08X\n", + le32_to_cpu(rxon->flags)); + IWL_DEBUG_RADIO(priv, "u32 filter_flags: 0x%08x\n", + le32_to_cpu(rxon->filter_flags)); + IWL_DEBUG_RADIO(priv, "u8 dev_type: 0x%x\n", rxon->dev_type); + IWL_DEBUG_RADIO(priv, "u8 ofdm_basic_rates: 0x%02x\n", + rxon->ofdm_basic_rates); + IWL_DEBUG_RADIO(priv, "u8 cck_basic_rates: 0x%02x\n", + rxon->cck_basic_rates); + IWL_DEBUG_RADIO(priv, "u8[6] node_addr: %pM\n", rxon->node_addr); + IWL_DEBUG_RADIO(priv, "u8[6] bssid_addr: %pM\n", rxon->bssid_addr); + IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", + le16_to_cpu(rxon->assoc_id)); +} +#endif + +static void iwl_calc_basic_rates(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + int lowest_present_ofdm = 100; + int lowest_present_cck = 100; + u8 cck = 0; + u8 ofdm = 0; + + if (ctx->vif) { + struct ieee80211_supported_band *sband; + unsigned long basic = ctx->vif->bss_conf.basic_rates; + int i; + + sband = priv->hw->wiphy->bands[priv->hw->conf.channel->band]; + + for_each_set_bit(i, &basic, BITS_PER_LONG) { + int hw = sband->bitrates[i].hw_value; + if (hw >= IWL_FIRST_OFDM_RATE) { + ofdm |= BIT(hw - IWL_FIRST_OFDM_RATE); + if (lowest_present_ofdm > hw) + lowest_present_ofdm = hw; + } else { + BUILD_BUG_ON(IWL_FIRST_CCK_RATE != 0); + + cck |= BIT(hw); + if (lowest_present_cck > hw) + lowest_present_cck = hw; + } + } + } + + /* + * Now we've got the basic rates as bitmaps in the ofdm and cck + * variables. This isn't sufficient though, as there might not + * be all the right rates in the bitmap. E.g. if the only basic + * rates are 5.5 Mbps and 11 Mbps, we still need to add 1 Mbps + * and 6 Mbps because the 802.11-2007 standard says in 9.6: + * + * [...] a STA responding to a received frame shall transmit + * its Control Response frame [...] at the highest rate in the + * BSSBasicRateSet parameter that is less than or equal to the + * rate of the immediately previous frame in the frame exchange + * sequence ([...]) and that is of the same modulation class + * ([...]) as the received frame. If no rate contained in the + * BSSBasicRateSet parameter meets these conditions, then the + * control frame sent in response to a received frame shall be + * transmitted at the highest mandatory rate of the PHY that is + * less than or equal to the rate of the received frame, and + * that is of the same modulation class as the received frame. + * + * As a consequence, we need to add all mandatory rates that are + * lower than all of the basic rates to these bitmaps. + */ + + if (IWL_RATE_24M_INDEX < lowest_present_ofdm) + ofdm |= IWL_RATE_24M_MASK >> IWL_FIRST_OFDM_RATE; + if (IWL_RATE_12M_INDEX < lowest_present_ofdm) + ofdm |= IWL_RATE_12M_MASK >> IWL_FIRST_OFDM_RATE; + /* 6M already there or needed so always add */ + ofdm |= IWL_RATE_6M_MASK >> IWL_FIRST_OFDM_RATE; + + /* + * CCK is a bit more complex with DSSS vs. HR/DSSS vs. ERP. + * Note, however: + * - if no CCK rates are basic, it must be ERP since there must + * be some basic rates at all, so they're OFDM => ERP PHY + * (or we're in 5 GHz, and the cck bitmap will never be used) + * - if 11M is a basic rate, it must be ERP as well, so add 5.5M + * - if 5.5M is basic, 1M and 2M are mandatory + * - if 2M is basic, 1M is mandatory + * - if 1M is basic, that's the only valid ACK rate. + * As a consequence, it's not as complicated as it sounds, just add + * any lower rates to the ACK rate bitmap. + */ + if (IWL_RATE_11M_INDEX < lowest_present_ofdm) + ofdm |= IWL_RATE_11M_MASK >> IWL_FIRST_CCK_RATE; + if (IWL_RATE_5M_INDEX < lowest_present_ofdm) + ofdm |= IWL_RATE_5M_MASK >> IWL_FIRST_CCK_RATE; + if (IWL_RATE_2M_INDEX < lowest_present_ofdm) + ofdm |= IWL_RATE_2M_MASK >> IWL_FIRST_CCK_RATE; + /* 1M already there or needed so always add */ + cck |= IWL_RATE_1M_MASK >> IWL_FIRST_CCK_RATE; + + IWL_DEBUG_RATE(priv, "Set basic rates cck:0x%.2x ofdm:0x%.2x\n", + cck, ofdm); + + /* "basic_rates" is a misnomer here -- should be called ACK rates */ + ctx->staging.cck_basic_rates = cck; + ctx->staging.ofdm_basic_rates = ofdm; +} + /** * iwlagn_commit_rxon - commit staging_rxon to hardware * @@ -433,11 +1071,14 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) /* always get timestamp with Rx frame */ ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK; + /* recalculate basic rates */ + iwl_calc_basic_rates(priv, ctx); + /* * force CTS-to-self frames protection if RTS-CTS is not preferred * one aggregation protection method */ - if (!hw_params(priv).use_rts_for_aggregation) + if (!priv->hw_params.use_rts_for_aggregation) ctx->staging.flags |= RXON_FLG_SELF_CTS_EN; if ((ctx->vif && ctx->vif->bss_conf.use_short_slot) || @@ -489,7 +1130,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) return 0; } - iwl_set_rxon_hwcrypto(priv, ctx, !iwlagn_mod_params.sw_crypto); + iwl_set_rxon_hwcrypto(priv, ctx, !iwlwifi_mod_params.sw_crypto); IWL_DEBUG_INFO(priv, "Going to commit RXON\n" @@ -547,7 +1188,7 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) const struct iwl_channel_info *ch_info; int ret = 0; - IWL_DEBUG_MAC80211(priv, "enter: changed %#x", changed); + IWL_DEBUG_MAC80211(priv, "enter: changed %#x\n", changed); mutex_lock(&priv->mutex); @@ -621,13 +1262,6 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) } iwl_update_bcast_stations(priv); - - /* - * The list of supported rates and rate mask can be different - * for each band; since the band may have changed, reset - * the rate mask to what mac80211 lists. - */ - iwl_set_rate(priv); } if (changed & (IEEE80211_CONF_CHANGE_PS | @@ -656,9 +1290,9 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) return ret; } -static void iwlagn_check_needed_chains(struct iwl_priv *priv, - struct iwl_rxon_context *ctx, - struct ieee80211_bss_conf *bss_conf) +void iwlagn_check_needed_chains(struct iwl_priv *priv, + struct iwl_rxon_context *ctx, + struct ieee80211_bss_conf *bss_conf) { struct ieee80211_vif *vif = ctx->vif; struct iwl_rxon_context *tmp; @@ -750,11 +1384,14 @@ static void iwlagn_check_needed_chains(struct iwl_priv *priv, ht_conf->single_chain_sufficient = !need_multiple; } -static void iwlagn_chain_noise_reset(struct iwl_priv *priv) +void iwlagn_chain_noise_reset(struct iwl_priv *priv) { struct iwl_chain_noise_data *data = &priv->chain_noise_data; int ret; + if (!(priv->calib_disabled & IWL_CHAIN_NOISE_CALIB_DISABLED)) + return; + if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_any_associated(priv)) { struct iwl_calib_chain_noise_reset_cmd cmd; @@ -907,8 +1544,7 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, iwl_power_update_mode(priv, false); /* Enable RX differential gain and sensitivity calibrations */ - if (!priv->disable_chain_noise_cal) - iwlagn_chain_noise_reset(priv); + iwlagn_chain_noise_reset(priv); priv->start_calib = 1; } diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-sta.c index c4175603864b..b31584e87bc7 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-sta.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-sta.c @@ -30,10 +30,11 @@ #include #include "iwl-dev.h" -#include "iwl-core.h" #include "iwl-agn.h" #include "iwl-trans.h" +const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + static int iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) { lockdep_assert_held(&priv->sta_lock); @@ -170,6 +171,50 @@ int iwl_send_add_sta(struct iwl_priv *priv, return cmd.handler_status; } +static bool iwl_is_channel_extension(struct iwl_priv *priv, + enum ieee80211_band band, + u16 channel, u8 extension_chan_offset) +{ + const struct iwl_channel_info *ch_info; + + ch_info = iwl_get_channel_info(priv, band, channel); + if (!is_channel_valid(ch_info)) + return false; + + if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) + return !(ch_info->ht40_extension_channel & + IEEE80211_CHAN_NO_HT40PLUS); + else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) + return !(ch_info->ht40_extension_channel & + IEEE80211_CHAN_NO_HT40MINUS); + + return false; +} + +bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, + struct iwl_rxon_context *ctx, + struct ieee80211_sta_ht_cap *ht_cap) +{ + if (!ctx->ht.enabled || !ctx->ht.is_40mhz) + return false; + + /* + * We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40 + * the bit will not set if it is pure 40MHz case + */ + if (ht_cap && !ht_cap->ht_supported) + return false; + +#ifdef CONFIG_IWLWIFI_DEBUGFS + if (priv->disable_ht40) + return false; +#endif + + return iwl_is_channel_extension(priv, priv->band, + le16_to_cpu(ctx->staging.channel), + ctx->ht.extension_chan_offset); +} + static void iwl_sta_calc_ht_flags(struct iwl_priv *priv, struct ieee80211_sta *sta, struct iwl_rxon_context *ctx, @@ -277,8 +322,8 @@ u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, sta_id = ctx->bcast_sta_id; else for (i = IWL_STA_ID; i < IWLAGN_STATION_COUNT; i++) { - if (!compare_ether_addr(priv->stations[i].sta.sta.addr, - addr)) { + if (ether_addr_equal(priv->stations[i].sta.sta.addr, + addr)) { sta_id = i; break; } @@ -308,7 +353,7 @@ u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) && (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) && - !compare_ether_addr(priv->stations[sta_id].sta.sta.addr, addr)) { + ether_addr_equal(priv->stations[sta_id].sta.sta.addr, addr)) { IWL_DEBUG_ASSOC(priv, "STA %d (%pM) already added, not " "adding again.\n", sta_id, addr); return sta_id; @@ -581,6 +626,56 @@ void iwl_deactivate_station(struct iwl_priv *priv, const u8 sta_id, spin_unlock_bh(&priv->sta_lock); } +static void iwl_sta_fill_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, + u8 sta_id, struct iwl_link_quality_cmd *link_cmd) +{ + int i, r; + u32 rate_flags = 0; + __le32 rate_n_flags; + + lockdep_assert_held(&priv->mutex); + + memset(link_cmd, 0, sizeof(*link_cmd)); + + /* Set up the rate scaling to start at selected rate, fall back + * all the way down to 1M in IEEE order, and then spin on 1M */ + if (priv->band == IEEE80211_BAND_5GHZ) + r = IWL_RATE_6M_INDEX; + else if (ctx && ctx->vif && ctx->vif->p2p) + r = IWL_RATE_6M_INDEX; + else + r = IWL_RATE_1M_INDEX; + + if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) + rate_flags |= RATE_MCS_CCK_MSK; + + rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) << + RATE_MCS_ANT_POS; + rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); + for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) + link_cmd->rs_table[i].rate_n_flags = rate_n_flags; + + link_cmd->general_params.single_stream_ant_msk = + first_antenna(priv->hw_params.valid_tx_ant); + + link_cmd->general_params.dual_stream_ant_msk = + priv->hw_params.valid_tx_ant & + ~first_antenna(priv->hw_params.valid_tx_ant); + if (!link_cmd->general_params.dual_stream_ant_msk) { + link_cmd->general_params.dual_stream_ant_msk = ANT_AB; + } else if (num_of_ant(priv->hw_params.valid_tx_ant) == 2) { + link_cmd->general_params.dual_stream_ant_msk = + priv->hw_params.valid_tx_ant; + } + + link_cmd->agg_params.agg_dis_start_th = + LINK_QUAL_AGG_DISABLE_START_DEF; + link_cmd->agg_params.agg_time_limit = + cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); + + link_cmd->sta_id = sta_id; +} + /** * iwl_clear_ucode_stations - clear ucode station table bits * @@ -841,56 +936,6 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx, } -void iwl_sta_fill_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, - u8 sta_id, struct iwl_link_quality_cmd *link_cmd) -{ - int i, r; - u32 rate_flags = 0; - __le32 rate_n_flags; - - lockdep_assert_held(&priv->mutex); - - memset(link_cmd, 0, sizeof(*link_cmd)); - - /* Set up the rate scaling to start at selected rate, fall back - * all the way down to 1M in IEEE order, and then spin on 1M */ - if (priv->band == IEEE80211_BAND_5GHZ) - r = IWL_RATE_6M_INDEX; - else if (ctx && ctx->vif && ctx->vif->p2p) - r = IWL_RATE_6M_INDEX; - else - r = IWL_RATE_1M_INDEX; - - if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) - rate_flags |= RATE_MCS_CCK_MSK; - - rate_flags |= first_antenna(hw_params(priv).valid_tx_ant) << - RATE_MCS_ANT_POS; - rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); - for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) - link_cmd->rs_table[i].rate_n_flags = rate_n_flags; - - link_cmd->general_params.single_stream_ant_msk = - first_antenna(hw_params(priv).valid_tx_ant); - - link_cmd->general_params.dual_stream_ant_msk = - hw_params(priv).valid_tx_ant & - ~first_antenna(hw_params(priv).valid_tx_ant); - if (!link_cmd->general_params.dual_stream_ant_msk) { - link_cmd->general_params.dual_stream_ant_msk = ANT_AB; - } else if (num_of_ant(hw_params(priv).valid_tx_ant) == 2) { - link_cmd->general_params.dual_stream_ant_msk = - hw_params(priv).valid_tx_ant; - } - - link_cmd->agg_params.agg_dis_start_th = - LINK_QUAL_AGG_DISABLE_START_DEF; - link_cmd->agg_params.agg_time_limit = - cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); - - link_cmd->sta_id = sta_id; -} - static struct iwl_link_quality_cmd * iwl_sta_alloc_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, u8 sta_id) diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-tt.c b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-tt.c index baaf5ba2fc38..a5cfe0aceedb 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-tt.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-tt.c @@ -37,11 +37,11 @@ #include "iwl-agn.h" #include "iwl-eeprom.h" #include "iwl-dev.h" -#include "iwl-core.h" #include "iwl-io.h" #include "iwl-commands.h" #include "iwl-debug.h" #include "iwl-agn-tt.h" +#include "iwl-modparams.h" /* default Thermal Throttling transaction table * Current state | Throttling Down | Throttling Up @@ -179,19 +179,19 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data) if (tt->state == IWL_TI_CT_KILL) { if (priv->thermal_throttle.ct_kill_toggle) { - iwl_write32(trans(priv), CSR_UCODE_DRV_GP1_CLR, + iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); priv->thermal_throttle.ct_kill_toggle = false; } else { - iwl_write32(trans(priv), CSR_UCODE_DRV_GP1_SET, + iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); priv->thermal_throttle.ct_kill_toggle = true; } - iwl_read32(trans(priv), CSR_UCODE_DRV_GP1); - spin_lock_irqsave(&trans(priv)->reg_lock, flags); - if (likely(iwl_grab_nic_access(trans(priv)))) - iwl_release_nic_access(trans(priv)); - spin_unlock_irqrestore(&trans(priv)->reg_lock, flags); + iwl_read32(priv->trans, CSR_UCODE_DRV_GP1); + spin_lock_irqsave(&priv->trans->reg_lock, flags); + if (likely(iwl_grab_nic_access(priv->trans))) + iwl_release_nic_access(priv->trans); + spin_unlock_irqrestore(&priv->trans->reg_lock, flags); /* Reschedule the ct_kill timer to occur in * CT_KILL_EXIT_DURATION seconds to ensure we get a @@ -632,7 +632,7 @@ void iwl_tt_initialize(struct iwl_priv *priv) INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter); INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit); - if (cfg(priv)->base_params->adv_thermal_throttle) { + if (priv->cfg->base_params->adv_thermal_throttle) { IWL_DEBUG_TEMP(priv, "Advanced Thermal Throttling\n"); tt->restriction = kcalloc(IWL_TI_STATE_MAX, sizeof(struct iwl_tt_restriction), diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 34adedc74d35..f2e9f298a947 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -34,12 +34,22 @@ #include #include "iwl-dev.h" -#include "iwl-core.h" #include "iwl-io.h" #include "iwl-agn-hw.h" #include "iwl-agn.h" #include "iwl-trans.h" +static const u8 tid_to_ac[] = { + IEEE80211_AC_BE, + IEEE80211_AC_BK, + IEEE80211_AC_BK, + IEEE80211_AC_BE, + IEEE80211_AC_VI, + IEEE80211_AC_VI, + IEEE80211_AC_VO, + IEEE80211_AC_VO, +}; + static void iwlagn_tx_cmd_protection(struct iwl_priv *priv, struct ieee80211_tx_info *info, __le16 fc, __le32 *tx_flags) @@ -74,8 +84,8 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv, else if (ieee80211_is_back_req(fc)) tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK; else if (info->band == IEEE80211_BAND_2GHZ && - cfg(priv)->bt_params && - cfg(priv)->bt_params->advanced_bt_coexist && + priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist && (ieee80211_is_auth(fc) || ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc) || skb->protocol == cpu_to_be16(ETH_P_PAE))) @@ -192,15 +202,15 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv, rate_flags |= RATE_MCS_CCK_MSK; /* Set up antennas */ - if (cfg(priv)->bt_params && - cfg(priv)->bt_params->advanced_bt_coexist && + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist && priv->bt_full_concurrent) { /* operated as 1x1 in full concurrency mode */ priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant, - first_antenna(hw_params(priv).valid_tx_ant)); + first_antenna(priv->hw_params.valid_tx_ant)); } else priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant, - hw_params(priv).valid_tx_ant); + priv->hw_params.valid_tx_ant); rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant); /* Set the rate in the TX cmd */ @@ -293,6 +303,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) u16 len, seq_number = 0; u8 sta_id, tid = IWL_MAX_TID_COUNT; bool is_agg = false; + int txq_id; if (info->control.vif) ctx = iwl_rxon_ctx_from_vif(info->control.vif); @@ -384,12 +395,9 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* TODO need this for burst mode later on */ iwlagn_tx_cmd_build_basic(priv, skb, tx_cmd, info, hdr, sta_id); - iwl_dbg_log_tx_data_frame(priv, len, hdr); iwlagn_tx_cmd_build_rate(priv, tx_cmd, info, fc); - iwl_update_stats(priv, true, fc, len); - memset(&info->status, 0, sizeof(info->status)); info->driver_data[0] = ctx; @@ -435,7 +443,31 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Copy MAC header from skb into command buffer */ memcpy(tx_cmd->hdr, hdr, hdr_len); - if (iwl_trans_tx(trans(priv), skb, dev_cmd, ctx->ctxid, sta_id, tid)) + if (is_agg) + txq_id = priv->tid_data[sta_id][tid].agg.txq_id; + else if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { + /* + * Send this frame after DTIM -- there's a special queue + * reserved for this for contexts that support AP mode. + */ + txq_id = ctx->mcast_queue; + + /* + * The microcode will clear the more data + * bit in the last frame it transmits. + */ + hdr->frame_control |= + cpu_to_le16(IEEE80211_FCTL_MOREDATA); + } else if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) + txq_id = IWL_AUX_QUEUE; + else + txq_id = ctx->ac_to_queue[skb_get_queue_mapping(skb)]; + + WARN_ON_ONCE(!is_agg && txq_id != info->hw_queue); + WARN_ON_ONCE(is_agg && + priv->queue_to_mac80211[txq_id] != info->hw_queue); + + if (iwl_trans_tx(priv->trans, skb, dev_cmd, txq_id)) goto drop_unlock_sta; if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc) && @@ -464,11 +496,33 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) return -1; } +static int iwlagn_alloc_agg_txq(struct iwl_priv *priv, int mq) +{ + int q; + + for (q = IWLAGN_FIRST_AMPDU_QUEUE; + q < priv->cfg->base_params->num_of_queues; q++) { + if (!test_and_set_bit(q, priv->agg_q_alloc)) { + priv->queue_to_mac80211[q] = mq; + return q; + } + } + + return -ENOSPC; +} + +static void iwlagn_dealloc_agg_txq(struct iwl_priv *priv, int q) +{ + clear_bit(q, priv->agg_q_alloc); + priv->queue_to_mac80211[q] = IWL_INVALID_MAC80211_QUEUE; +} + int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid) { struct iwl_tid_data *tid_data; - int sta_id; + int sta_id, txq_id; + enum iwl_agg_state agg_state; sta_id = iwl_sta_id(sta); @@ -480,6 +534,7 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, spin_lock_bh(&priv->sta_lock); tid_data = &priv->tid_data[sta_id][tid]; + txq_id = priv->tid_data[sta_id][tid].agg.txq_id; switch (priv->tid_data[sta_id][tid].agg.state) { case IWL_EMPTYING_HW_QUEUE_ADDBA: @@ -491,6 +546,13 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, */ IWL_DEBUG_HT(priv, "AGG stop before setup done\n"); goto turn_off; + case IWL_AGG_STARTING: + /* + * This can happen when the session is stopped before + * we receive ADDBA response + */ + IWL_DEBUG_HT(priv, "AGG stop before AGG became operational\n"); + goto turn_off; case IWL_AGG_ON: break; default: @@ -504,9 +566,13 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number); /* There are still packets for this RA / TID in the HW */ - if (tid_data->agg.ssn != tid_data->next_reclaimed) { + if (!test_bit(txq_id, priv->agg_q_alloc)) { + IWL_DEBUG_TX_QUEUES(priv, + "stopping AGG on STA/TID %d/%d but hwq %d not used\n", + sta_id, tid, txq_id); + } else if (tid_data->agg.ssn != tid_data->next_reclaimed) { IWL_DEBUG_TX_QUEUES(priv, "Can't proceed: ssn %d, " - "next_recl = %d", + "next_recl = %d\n", tid_data->agg.ssn, tid_data->next_reclaimed); priv->tid_data[sta_id][tid].agg.state = @@ -515,14 +581,22 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, return 0; } - IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d", + IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d\n", tid_data->agg.ssn); turn_off: + agg_state = priv->tid_data[sta_id][tid].agg.state; priv->tid_data[sta_id][tid].agg.state = IWL_AGG_OFF; spin_unlock_bh(&priv->sta_lock); - iwl_trans_tx_agg_disable(trans(priv), sta_id, tid); + if (test_bit(txq_id, priv->agg_q_alloc)) { + /* If the transport didn't know that we wanted to start + * agreggation, don't tell it that we want to stop them + */ + if (agg_state != IWL_AGG_STARTING) + iwl_trans_tx_agg_disable(priv->trans, txq_id); + iwlagn_dealloc_agg_txq(priv, txq_id); + } ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); @@ -532,9 +606,9 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { + struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); struct iwl_tid_data *tid_data; - int sta_id; - int ret; + int sta_id, txq_id, ret; IWL_DEBUG_HT(priv, "TX AGG request on ra = %pM tid = %d\n", sta->addr, tid); @@ -552,36 +626,37 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, return -ENXIO; } + txq_id = iwlagn_alloc_agg_txq(priv, ctx->ac_to_queue[tid_to_ac[tid]]); + if (txq_id < 0) { + IWL_DEBUG_TX_QUEUES(priv, + "No free aggregation queue for %pM/%d\n", + sta->addr, tid); + return txq_id; + } + ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); if (ret) return ret; spin_lock_bh(&priv->sta_lock); - tid_data = &priv->tid_data[sta_id][tid]; tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number); + tid_data->agg.txq_id = txq_id; *ssn = tid_data->agg.ssn; - ret = iwl_trans_tx_agg_alloc(trans(priv), sta_id, tid); - if (ret) { - spin_unlock_bh(&priv->sta_lock); - return ret; - } - if (*ssn == tid_data->next_reclaimed) { - IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d", + IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d\n", tid_data->agg.ssn); - tid_data->agg.state = IWL_AGG_ON; + tid_data->agg.state = IWL_AGG_STARTING; ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); } else { IWL_DEBUG_TX_QUEUES(priv, "Can't proceed: ssn %d, " - "next_reclaimed = %d", + "next_reclaimed = %d\n", tid_data->agg.ssn, tid_data->next_reclaimed); tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA; } - spin_unlock_bh(&priv->sta_lock); return ret; @@ -592,15 +667,21 @@ int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif, { struct iwl_station_priv *sta_priv = (void *) sta->drv_priv; struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); + int q, fifo; u16 ssn; buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF); spin_lock_bh(&priv->sta_lock); ssn = priv->tid_data[sta_priv->sta_id][tid].agg.ssn; + q = priv->tid_data[sta_priv->sta_id][tid].agg.txq_id; + priv->tid_data[sta_priv->sta_id][tid].agg.state = IWL_AGG_ON; spin_unlock_bh(&priv->sta_lock); - iwl_trans_tx_agg_setup(trans(priv), ctx->ctxid, sta_priv->sta_id, tid, + fifo = ctx->ac_to_fifo[tid_to_ac[tid]]; + + iwl_trans_tx_agg_setup(priv->trans, q, fifo, + sta_priv->sta_id, tid, buf_size, ssn); /* @@ -623,7 +704,7 @@ int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif, sta_priv->max_agg_bufsize = min(sta_priv->max_agg_bufsize, buf_size); - if (hw_params(priv).use_rts_for_aggregation) { + if (priv->hw_params.use_rts_for_aggregation) { /* * switch to RTS/CTS if it is the prefer protection * method for HT traffic @@ -666,7 +747,9 @@ static void iwlagn_check_ratid_empty(struct iwl_priv *priv, int sta_id, u8 tid) IWL_DEBUG_TX_QUEUES(priv, "Can continue DELBA flow ssn = next_recl =" " %d", tid_data->next_reclaimed); - iwl_trans_tx_agg_disable(trans(priv), sta_id, tid); + iwl_trans_tx_agg_disable(priv->trans, + tid_data->agg.txq_id); + iwlagn_dealloc_agg_txq(priv, tid_data->agg.txq_id); tid_data->agg.state = IWL_AGG_OFF; ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid); } @@ -677,7 +760,7 @@ static void iwlagn_check_ratid_empty(struct iwl_priv *priv, int sta_id, u8 tid) IWL_DEBUG_TX_QUEUES(priv, "Can continue ADDBA flow ssn = next_recl =" " %d", tid_data->next_reclaimed); - tid_data->agg.state = IWL_AGG_ON; + tid_data->agg.state = IWL_AGG_STARTING; ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid); } break; @@ -711,9 +794,9 @@ static void iwlagn_non_agg_tx_status(struct iwl_priv *priv, static void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, struct ieee80211_tx_info *info) { - struct ieee80211_tx_rate *r = &info->control.rates[0]; + struct ieee80211_tx_rate *r = &info->status.rates[0]; - info->antenna_sel_tx = + info->status.antenna = ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS); if (rate_n_flags & RATE_MCS_HT_MSK) r->flags |= IEEE80211_TX_RC_MCS; @@ -841,8 +924,8 @@ static void iwl_rx_reply_tx_agg(struct iwl_priv *priv, * notification again. */ if (tx_resp->bt_kill_count && tx_resp->frame_count == 1 && - cfg(priv)->bt_params && - cfg(priv)->bt_params->advanced_bt_coexist) { + priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist) { IWL_DEBUG_COEX(priv, "receive reply tx w/ bt_kill\n"); } @@ -1005,6 +1088,29 @@ static void iwl_check_abort_status(struct iwl_priv *priv, } } +static int iwl_reclaim(struct iwl_priv *priv, int sta_id, int tid, + int txq_id, int ssn, struct sk_buff_head *skbs) +{ + if (unlikely(txq_id >= IWLAGN_FIRST_AMPDU_QUEUE && + tid != IWL_TID_NON_QOS && + txq_id != priv->tid_data[sta_id][tid].agg.txq_id)) { + /* + * FIXME: this is a uCode bug which need to be addressed, + * log the information and return for now. + * Since it is can possibly happen very often and in order + * not to fill the syslog, don't use IWL_ERR or IWL_WARN + */ + IWL_DEBUG_TX_QUEUES(priv, + "Bad queue mapping txq_id=%d, agg_txq[sta:%d,tid:%d]=%d\n", + txq_id, sta_id, tid, + priv->tid_data[sta_id][tid].agg.txq_id); + return 1; + } + + iwl_trans_reclaim(priv->trans, txq_id, ssn, skbs); + return 0; +} + int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd) { @@ -1059,13 +1165,12 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, if (tid != IWL_TID_NON_QOS) { priv->tid_data[sta_id][tid].next_reclaimed = next_reclaimed; - IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d", + IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n", next_reclaimed); } /*we can free until ssn % q.n_bd not inclusive */ - WARN_ON(iwl_trans_reclaim(trans(priv), sta_id, tid, - txq_id, ssn, &skbs)); + WARN_ON(iwl_reclaim(priv, sta_id, tid, txq_id, ssn, &skbs)); iwlagn_check_ratid_empty(priv, sta_id, tid); freed = 0; @@ -1159,7 +1264,7 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, * (in Tx queue's circular buffer) of first TFD/frame in window */ u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn); - if (scd_flow >= cfg(priv)->base_params->num_of_queues) { + if (scd_flow >= priv->cfg->base_params->num_of_queues) { IWL_ERR(priv, "BUG_ON scd_flow is bigger than number of queues\n"); return 0; @@ -1183,8 +1288,8 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, /* Release all TFDs before the SSN, i.e. all TFDs in front of * block-ack window (we assume that they've been successfully * transmitted ... if not, it's too late anyway). */ - if (iwl_trans_reclaim(trans(priv), sta_id, tid, scd_flow, - ba_resp_scd_ssn, &reclaimed_skbs)) { + if (iwl_reclaim(priv, sta_id, tid, scd_flow, + ba_resp_scd_ssn, &reclaimed_skbs)) { spin_unlock(&priv->sta_lock); return 0; } diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-agn.c b/trunk/drivers/net/wireless/iwlwifi/iwl-agn.c index 2a9a16f901c3..8d7637083fcf 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -26,6 +26,9 @@ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -43,13 +46,13 @@ #include "iwl-eeprom.h" #include "iwl-dev.h" -#include "iwl-core.h" #include "iwl-io.h" #include "iwl-agn-calib.h" #include "iwl-agn.h" -#include "iwl-shared.h" #include "iwl-trans.h" #include "iwl-op-mode.h" +#include "iwl-drv.h" +#include "iwl-modparams.h" /****************************************************************************** * @@ -177,7 +180,7 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv) rate = info->control.rates[0].idx; priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant, - hw_params(priv).valid_tx_ant); + priv->hw_params.valid_tx_ant); rate_flags = iwl_ant_idx_to_flags(priv->mgmt_tx_ant); /* In mac80211, rates for 5 GHz start at 0 */ @@ -286,6 +289,25 @@ static void iwl_bg_bt_full_concurrency(struct work_struct *work) mutex_unlock(&priv->mutex); } +int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear) +{ + struct iwl_statistics_cmd statistics_cmd = { + .configuration_flags = + clear ? IWL_STATS_CONF_CLEAR_STATS : 0, + }; + + if (flags & CMD_ASYNC) + return iwl_dvm_send_cmd_pdu(priv, REPLY_STATISTICS_CMD, + CMD_ASYNC, + sizeof(struct iwl_statistics_cmd), + &statistics_cmd); + else + return iwl_dvm_send_cmd_pdu(priv, REPLY_STATISTICS_CMD, + CMD_SYNC, + sizeof(struct iwl_statistics_cmd), + &statistics_cmd); +} + /** * iwl_bg_statistics_periodic - Timer callback to queue statistics * @@ -326,14 +348,14 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32)); /* Make sure device is powered up for SRAM reads */ - spin_lock_irqsave(&trans(priv)->reg_lock, reg_flags); - if (unlikely(!iwl_grab_nic_access(trans(priv)))) { - spin_unlock_irqrestore(&trans(priv)->reg_lock, reg_flags); + spin_lock_irqsave(&priv->trans->reg_lock, reg_flags); + if (unlikely(!iwl_grab_nic_access(priv->trans))) { + spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags); return; } /* Set starting address; reads will auto-increment */ - iwl_write32(trans(priv), HBUS_TARG_MEM_RADDR, ptr); + iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, ptr); /* * Refuse to read more than would have fit into the log from @@ -349,20 +371,20 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, * place event id # at far right for easier visual parsing. */ for (i = 0; i < num_events; i++) { - ev = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT); - time = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT); + ev = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT); + time = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT); if (mode == 0) { trace_iwlwifi_dev_ucode_cont_event( - trans(priv)->dev, 0, time, ev); + priv->trans->dev, 0, time, ev); } else { - data = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT); + data = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT); trace_iwlwifi_dev_ucode_cont_event( - trans(priv)->dev, time, data, ev); + priv->trans->dev, time, data, ev); } } /* Allow device to power down */ - iwl_release_nic_access(trans(priv)); - spin_unlock_irqrestore(&trans(priv)->reg_lock, reg_flags); + iwl_release_nic_access(priv->trans); + spin_unlock_irqrestore(&priv->trans->reg_lock, reg_flags); } static void iwl_continuous_event_trace(struct iwl_priv *priv) @@ -379,10 +401,9 @@ static void iwl_continuous_event_trace(struct iwl_priv *priv) u32 num_wraps; /* # times uCode wrapped to top of log */ u32 next_entry; /* index of next entry to be written by uCode */ - base = priv->shrd->device_pointers.log_event_table; + base = priv->device_pointers.log_event_table; if (iwlagn_hw_valid_rtc_data_addr(base)) { - iwl_read_targ_mem_words(trans(priv), base, &read, sizeof(read)); - + iwl_read_targ_mem_words(priv->trans, base, &read, sizeof(read)); capacity = read.capacity; mode = read.mode; num_wraps = read.wrap_counter; @@ -422,7 +443,7 @@ static void iwl_continuous_event_trace(struct iwl_priv *priv) else priv->event_log.wraps_once_count++; - trace_iwlwifi_dev_ucode_wrap_event(trans(priv)->dev, + trace_iwlwifi_dev_ucode_wrap_event(priv->trans->dev, num_wraps - priv->event_log.num_wraps, next_entry, priv->event_log.next_entry); @@ -488,7 +509,76 @@ static void iwl_bg_tx_flush(struct work_struct *work) iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL); } -static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags) +/* + * queue/FIFO/AC mapping definitions + */ + +#define IWL_TX_FIFO_BK 0 /* shared */ +#define IWL_TX_FIFO_BE 1 +#define IWL_TX_FIFO_VI 2 /* shared */ +#define IWL_TX_FIFO_VO 3 +#define IWL_TX_FIFO_BK_IPAN IWL_TX_FIFO_BK +#define IWL_TX_FIFO_BE_IPAN 4 +#define IWL_TX_FIFO_VI_IPAN IWL_TX_FIFO_VI +#define IWL_TX_FIFO_VO_IPAN 5 +/* re-uses the VO FIFO, uCode will properly flush/schedule */ +#define IWL_TX_FIFO_AUX 5 +#define IWL_TX_FIFO_UNUSED -1 + +#define IWLAGN_CMD_FIFO_NUM 7 + +/* + * This queue number is required for proper operation + * because the ucode will stop/start the scheduler as + * required. + */ +#define IWL_IPAN_MCAST_QUEUE 8 + +static const u8 iwlagn_default_queue_to_tx_fifo[] = { + IWL_TX_FIFO_VO, + IWL_TX_FIFO_VI, + IWL_TX_FIFO_BE, + IWL_TX_FIFO_BK, + IWLAGN_CMD_FIFO_NUM, +}; + +static const u8 iwlagn_ipan_queue_to_tx_fifo[] = { + IWL_TX_FIFO_VO, + IWL_TX_FIFO_VI, + IWL_TX_FIFO_BE, + IWL_TX_FIFO_BK, + IWL_TX_FIFO_BK_IPAN, + IWL_TX_FIFO_BE_IPAN, + IWL_TX_FIFO_VI_IPAN, + IWL_TX_FIFO_VO_IPAN, + IWL_TX_FIFO_BE_IPAN, + IWLAGN_CMD_FIFO_NUM, + IWL_TX_FIFO_AUX, +}; + +static const u8 iwlagn_bss_ac_to_fifo[] = { + IWL_TX_FIFO_VO, + IWL_TX_FIFO_VI, + IWL_TX_FIFO_BE, + IWL_TX_FIFO_BK, +}; + +static const u8 iwlagn_bss_ac_to_queue[] = { + 0, 1, 2, 3, +}; + +static const u8 iwlagn_pan_ac_to_fifo[] = { + IWL_TX_FIFO_VO_IPAN, + IWL_TX_FIFO_VI_IPAN, + IWL_TX_FIFO_BE_IPAN, + IWL_TX_FIFO_BK_IPAN, +}; + +static const u8 iwlagn_pan_ac_to_queue[] = { + 7, 6, 5, 4, +}; + +void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags) { int i; @@ -496,9 +586,9 @@ static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags) * The default context is always valid, * the PAN context depends on uCode. */ - priv->shrd->valid_contexts = BIT(IWL_RXON_CTX_BSS); + priv->valid_contexts = BIT(IWL_RXON_CTX_BSS); if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN) - priv->shrd->valid_contexts |= BIT(IWL_RXON_CTX_PAN); + priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN); for (i = 0; i < NUM_IWL_RXON_CTX; i++) priv->contexts[i].ctxid = i; @@ -520,6 +610,10 @@ static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags) priv->contexts[IWL_RXON_CTX_BSS].ibss_devtype = RXON_DEV_TYPE_IBSS; priv->contexts[IWL_RXON_CTX_BSS].station_devtype = RXON_DEV_TYPE_ESS; priv->contexts[IWL_RXON_CTX_BSS].unused_devtype = RXON_DEV_TYPE_ESS; + memcpy(priv->contexts[IWL_RXON_CTX_BSS].ac_to_queue, + iwlagn_bss_ac_to_queue, sizeof(iwlagn_bss_ac_to_queue)); + memcpy(priv->contexts[IWL_RXON_CTX_BSS].ac_to_fifo, + iwlagn_bss_ac_to_fifo, sizeof(iwlagn_bss_ac_to_fifo)); priv->contexts[IWL_RXON_CTX_PAN].rxon_cmd = REPLY_WIPAN_RXON; priv->contexts[IWL_RXON_CTX_PAN].rxon_timing_cmd = @@ -542,26 +636,31 @@ static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags) priv->contexts[IWL_RXON_CTX_PAN].ap_devtype = RXON_DEV_TYPE_CP; priv->contexts[IWL_RXON_CTX_PAN].station_devtype = RXON_DEV_TYPE_2STA; priv->contexts[IWL_RXON_CTX_PAN].unused_devtype = RXON_DEV_TYPE_P2P; + memcpy(priv->contexts[IWL_RXON_CTX_PAN].ac_to_queue, + iwlagn_pan_ac_to_queue, sizeof(iwlagn_pan_ac_to_queue)); + memcpy(priv->contexts[IWL_RXON_CTX_PAN].ac_to_fifo, + iwlagn_pan_ac_to_fifo, sizeof(iwlagn_pan_ac_to_fifo)); + priv->contexts[IWL_RXON_CTX_PAN].mcast_queue = IWL_IPAN_MCAST_QUEUE; BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); } -static void iwl_rf_kill_ct_config(struct iwl_priv *priv) +void iwl_rf_kill_ct_config(struct iwl_priv *priv) { struct iwl_ct_kill_config cmd; struct iwl_ct_kill_throttling_config adv_cmd; int ret = 0; - iwl_write32(trans(priv), CSR_UCODE_DRV_GP1_CLR, + iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); priv->thermal_throttle.ct_kill_toggle = false; - if (cfg(priv)->base_params->support_ct_kill_exit) { + if (priv->cfg->base_params->support_ct_kill_exit) { adv_cmd.critical_temperature_enter = - cpu_to_le32(hw_params(priv).ct_kill_threshold); + cpu_to_le32(priv->hw_params.ct_kill_threshold); adv_cmd.critical_temperature_exit = - cpu_to_le32(hw_params(priv).ct_kill_exit_threshold); + cpu_to_le32(priv->hw_params.ct_kill_exit_threshold); ret = iwl_dvm_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, @@ -572,11 +671,11 @@ static void iwl_rf_kill_ct_config(struct iwl_priv *priv) IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD " "succeeded, critical temperature enter is %d," "exit is %d\n", - hw_params(priv).ct_kill_threshold, - hw_params(priv).ct_kill_exit_threshold); + priv->hw_params.ct_kill_threshold, + priv->hw_params.ct_kill_exit_threshold); } else { cmd.critical_temperature_R = - cpu_to_le32(hw_params(priv).ct_kill_threshold); + cpu_to_le32(priv->hw_params.ct_kill_threshold); ret = iwl_dvm_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, @@ -587,7 +686,7 @@ static void iwl_rf_kill_ct_config(struct iwl_priv *priv) IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD " "succeeded, " "critical temperature is %d\n", - hw_params(priv).ct_kill_threshold); + priv->hw_params.ct_kill_threshold); } } @@ -627,6 +726,29 @@ static int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant) } } +void iwl_send_bt_config(struct iwl_priv *priv) +{ + struct iwl_bt_cmd bt_cmd = { + .lead_time = BT_LEAD_TIME_DEF, + .max_kill = BT_MAX_KILL_DEF, + .kill_ack_mask = 0, + .kill_cts_mask = 0, + }; + + if (!iwlwifi_mod_params.bt_coex_active) + bt_cmd.flags = BT_COEX_DISABLE; + else + bt_cmd.flags = BT_COEX_ENABLE; + + priv->bt_enable_flag = bt_cmd.flags; + IWL_DEBUG_INFO(priv, "BT coex %s\n", + (bt_cmd.flags == BT_COEX_DISABLE) ? "disable" : "active"); + + if (iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG, + CMD_SYNC, sizeof(struct iwl_bt_cmd), &bt_cmd)) + IWL_ERR(priv, "failed to send BT Coex Config\n"); +} + /** * iwl_alive_start - called after REPLY_ALIVE notification received * from protocol/runtime uCode (initialization uCode's @@ -642,9 +764,6 @@ int iwl_alive_start(struct iwl_priv *priv) /* After the ALIVE response, we can send host commands to the uCode */ set_bit(STATUS_ALIVE, &priv->status); - /* Enable watchdog to monitor the driver tx queues */ - iwl_setup_watchdog(priv); - if (iwl_is_rfkill(priv)) return -ERFKILL; @@ -654,10 +773,10 @@ int iwl_alive_start(struct iwl_priv *priv) } /* download priority table before any calibration request */ - if (cfg(priv)->bt_params && - cfg(priv)->bt_params->advanced_bt_coexist) { + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist) { /* Configure Bluetooth device coexistence support */ - if (cfg(priv)->bt_params->bt_sco_disable) + if (priv->cfg->bt_params->bt_sco_disable) priv->bt_enable_pspoll = false; else priv->bt_enable_pspoll = true; @@ -694,10 +813,8 @@ int iwl_alive_start(struct iwl_priv *priv) ieee80211_wake_queues(priv->hw); - priv->active_rate = IWL_RATES_MASK; - /* Configure Tx antenna selection based on H/W config */ - iwlagn_send_tx_ant_config(priv, hw_params(priv).valid_tx_ant); + iwlagn_send_tx_ant_config(priv, priv->hw_params.valid_tx_ant); if (iwl_is_associated_ctx(ctx) && !priv->wowlan) { struct iwl_rxon_cmd *active_rxon = @@ -788,10 +905,6 @@ void iwl_down(struct iwl_priv *priv) exit_pending = test_and_set_bit(STATUS_EXIT_PENDING, &priv->status); - /* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set - * to prevent rearm timer */ - del_timer_sync(&priv->watchdog); - iwl_clear_ucode_stations(priv, NULL); iwl_dealloc_bcast_stations(priv); iwl_clear_driver_stations(priv); @@ -800,9 +913,9 @@ void iwl_down(struct iwl_priv *priv) priv->bt_status = 0; priv->cur_rssi_ctx = NULL; priv->bt_is_sco = 0; - if (cfg(priv)->bt_params) + if (priv->cfg->bt_params) priv->bt_traffic_load = - cfg(priv)->bt_params->bt_init_traffic_load; + priv->cfg->bt_params->bt_init_traffic_load; else priv->bt_traffic_load = 0; priv->bt_full_concurrent = false; @@ -817,18 +930,17 @@ void iwl_down(struct iwl_priv *priv) ieee80211_stop_queues(priv->hw); priv->ucode_loaded = false; - iwl_trans_stop_device(trans(priv)); + iwl_trans_stop_device(priv->trans); /* Clear out all status bits but a few that are stable across reset */ priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) << STATUS_RF_KILL_HW | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << STATUS_GEO_CONFIGURED | + test_bit(STATUS_FW_ERROR, &priv->status) << + STATUS_FW_ERROR | test_bit(STATUS_EXIT_PENDING, &priv->status) << STATUS_EXIT_PENDING; - priv->shrd->status &= - test_bit(STATUS_FW_ERROR, &priv->shrd->status) << - STATUS_FW_ERROR; dev_kfree_skb(priv->beacon_skb); priv->beacon_skb = NULL; @@ -868,6 +980,7 @@ void iwlagn_prepare_restart(struct iwl_priv *priv) u8 bt_load; u8 bt_status; bool bt_is_sco; + int i; lockdep_assert_held(&priv->mutex); @@ -895,6 +1008,15 @@ void iwlagn_prepare_restart(struct iwl_priv *priv) priv->bt_traffic_load = bt_load; priv->bt_status = bt_status; priv->bt_is_sco = bt_is_sco; + + /* reset aggregation queues */ + for (i = IWLAGN_FIRST_AMPDU_QUEUE; i < IWL_MAX_HW_QUEUES; i++) + priv->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE; + /* and stop counts */ + for (i = 0; i < IWL_MAX_HW_QUEUES; i++) + atomic_set(&priv->queue_stop_count[i], 0); + + memset(priv->agg_q_alloc, 0, sizeof(priv->agg_q_alloc)); } static void iwl_bg_restart(struct work_struct *data) @@ -904,7 +1026,7 @@ static void iwl_bg_restart(struct work_struct *data) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - if (test_and_clear_bit(STATUS_FW_ERROR, &priv->shrd->status)) { + if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) { mutex_lock(&priv->mutex); iwlagn_prepare_restart(priv); mutex_unlock(&priv->mutex); @@ -956,7 +1078,7 @@ static void iwlagn_disable_roc_work(struct work_struct *work) * *****************************************************************************/ -static void iwl_setup_deferred_work(struct iwl_priv *priv) +void iwl_setup_deferred_work(struct iwl_priv *priv) { priv->workqueue = create_singlethread_workqueue(DRV_NAME); @@ -971,7 +1093,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) iwl_setup_scan_deferred_work(priv); - if (cfg(priv)->bt_params) + if (priv->cfg->bt_params) iwlagn_bt_setup_deferred_work(priv); init_timer(&priv->statistics_periodic); @@ -981,15 +1103,11 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) init_timer(&priv->ucode_trace); priv->ucode_trace.data = (unsigned long)priv; priv->ucode_trace.function = iwl_bg_ucode_trace; - - init_timer(&priv->watchdog); - priv->watchdog.data = (unsigned long)priv; - priv->watchdog.function = iwl_bg_watchdog; } void iwl_cancel_deferred_work(struct iwl_priv *priv) { - if (cfg(priv)->bt_params) + if (priv->cfg->bt_params) iwlagn_bt_cancel_deferred_work(priv); cancel_work_sync(&priv->run_time_calib_work); @@ -1025,7 +1143,193 @@ static void iwl_init_hw_rates(struct ieee80211_rate *rates) } } -static int iwl_init_drv(struct iwl_priv *priv) +#define MAX_BIT_RATE_40_MHZ 150 /* Mbps */ +#define MAX_BIT_RATE_20_MHZ 72 /* Mbps */ +static void iwl_init_ht_hw_capab(const struct iwl_priv *priv, + struct ieee80211_sta_ht_cap *ht_info, + enum ieee80211_band band) +{ + u16 max_bit_rate = 0; + u8 rx_chains_num = priv->hw_params.rx_chains_num; + u8 tx_chains_num = priv->hw_params.tx_chains_num; + + ht_info->cap = 0; + memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); + + ht_info->ht_supported = true; + + if (priv->cfg->ht_params && + priv->cfg->ht_params->ht_greenfield_support) + ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; + ht_info->cap |= IEEE80211_HT_CAP_SGI_20; + max_bit_rate = MAX_BIT_RATE_20_MHZ; + if (priv->hw_params.ht40_channel & BIT(band)) { + ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; + ht_info->cap |= IEEE80211_HT_CAP_SGI_40; + ht_info->mcs.rx_mask[4] = 0x01; + max_bit_rate = MAX_BIT_RATE_40_MHZ; + } + + if (iwlwifi_mod_params.amsdu_size_8K) + ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; + + ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF; + ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF; + + ht_info->mcs.rx_mask[0] = 0xFF; + if (rx_chains_num >= 2) + ht_info->mcs.rx_mask[1] = 0xFF; + if (rx_chains_num >= 3) + ht_info->mcs.rx_mask[2] = 0xFF; + + /* Highest supported Rx data rate */ + max_bit_rate *= rx_chains_num; + WARN_ON(max_bit_rate & ~IEEE80211_HT_MCS_RX_HIGHEST_MASK); + ht_info->mcs.rx_highest = cpu_to_le16(max_bit_rate); + + /* Tx MCS capabilities */ + ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; + if (tx_chains_num != rx_chains_num) { + ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; + ht_info->mcs.tx_params |= ((tx_chains_num - 1) << + IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); + } +} + +/** + * iwl_init_geos - Initialize mac80211's geo/channel info based from eeprom + */ +static int iwl_init_geos(struct iwl_priv *priv) +{ + struct iwl_channel_info *ch; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *channels; + struct ieee80211_channel *geo_ch; + struct ieee80211_rate *rates; + int i = 0; + s8 max_tx_power = IWLAGN_TX_POWER_TARGET_POWER_MIN; + + if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates || + priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) { + IWL_DEBUG_INFO(priv, "Geography modes already initialized.\n"); + set_bit(STATUS_GEO_CONFIGURED, &priv->status); + return 0; + } + + channels = kcalloc(priv->channel_count, + sizeof(struct ieee80211_channel), GFP_KERNEL); + if (!channels) + return -ENOMEM; + + rates = kcalloc(IWL_RATE_COUNT_LEGACY, sizeof(struct ieee80211_rate), + GFP_KERNEL); + if (!rates) { + kfree(channels); + return -ENOMEM; + } + + /* 5.2GHz channels start after the 2.4GHz channels */ + sband = &priv->bands[IEEE80211_BAND_5GHZ]; + sband->channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)]; + /* just OFDM */ + sband->bitrates = &rates[IWL_FIRST_OFDM_RATE]; + sband->n_bitrates = IWL_RATE_COUNT_LEGACY - IWL_FIRST_OFDM_RATE; + + if (priv->hw_params.sku & EEPROM_SKU_CAP_11N_ENABLE) + iwl_init_ht_hw_capab(priv, &sband->ht_cap, + IEEE80211_BAND_5GHZ); + + sband = &priv->bands[IEEE80211_BAND_2GHZ]; + sband->channels = channels; + /* OFDM & CCK */ + sband->bitrates = rates; + sband->n_bitrates = IWL_RATE_COUNT_LEGACY; + + if (priv->hw_params.sku & EEPROM_SKU_CAP_11N_ENABLE) + iwl_init_ht_hw_capab(priv, &sband->ht_cap, + IEEE80211_BAND_2GHZ); + + priv->ieee_channels = channels; + priv->ieee_rates = rates; + + for (i = 0; i < priv->channel_count; i++) { + ch = &priv->channel_info[i]; + + /* FIXME: might be removed if scan is OK */ + if (!is_channel_valid(ch)) + continue; + + sband = &priv->bands[ch->band]; + + geo_ch = &sband->channels[sband->n_channels++]; + + geo_ch->center_freq = + ieee80211_channel_to_frequency(ch->channel, ch->band); + geo_ch->max_power = ch->max_power_avg; + geo_ch->max_antenna_gain = 0xff; + geo_ch->hw_value = ch->channel; + + if (is_channel_valid(ch)) { + if (!(ch->flags & EEPROM_CHANNEL_IBSS)) + geo_ch->flags |= IEEE80211_CHAN_NO_IBSS; + + if (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) + geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN; + + if (ch->flags & EEPROM_CHANNEL_RADAR) + geo_ch->flags |= IEEE80211_CHAN_RADAR; + + geo_ch->flags |= ch->ht40_extension_channel; + + if (ch->max_power_avg > max_tx_power) + max_tx_power = ch->max_power_avg; + } else { + geo_ch->flags |= IEEE80211_CHAN_DISABLED; + } + + IWL_DEBUG_INFO(priv, "Channel %d Freq=%d[%sGHz] %s flag=0x%X\n", + ch->channel, geo_ch->center_freq, + is_channel_a_band(ch) ? "5.2" : "2.4", + geo_ch->flags & IEEE80211_CHAN_DISABLED ? + "restricted" : "valid", + geo_ch->flags); + } + + priv->tx_power_device_lmt = max_tx_power; + priv->tx_power_user_lmt = max_tx_power; + priv->tx_power_next = max_tx_power; + + if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) && + priv->hw_params.sku & EEPROM_SKU_CAP_BAND_52GHZ) { + IWL_INFO(priv, "Incorrectly detected BG card as ABG. " + "Please send your %s to maintainer.\n", + priv->trans->hw_id_str); + priv->hw_params.sku &= ~EEPROM_SKU_CAP_BAND_52GHZ; + } + + if (iwlwifi_mod_params.disable_5ghz) + priv->bands[IEEE80211_BAND_5GHZ].n_channels = 0; + + IWL_INFO(priv, "Tunable channels: %d 802.11bg, %d 802.11a channels\n", + priv->bands[IEEE80211_BAND_2GHZ].n_channels, + priv->bands[IEEE80211_BAND_5GHZ].n_channels); + + set_bit(STATUS_GEO_CONFIGURED, &priv->status); + + return 0; +} + +/* + * iwl_free_geos - undo allocations in iwl_init_geos + */ +static void iwl_free_geos(struct iwl_priv *priv) +{ + kfree(priv->ieee_channels); + kfree(priv->ieee_rates); + clear_bit(STATUS_GEO_CONFIGURED, &priv->status); +} + +int iwl_init_drv(struct iwl_priv *priv) { int ret; @@ -1040,7 +1344,7 @@ static int iwl_init_drv(struct iwl_priv *priv) priv->band = IEEE80211_BAND_2GHZ; priv->plcp_delta_threshold = - cfg(priv)->base_params->plcp_delta_threshold; + priv->cfg->base_params->plcp_delta_threshold; priv->iw_mode = NL80211_IFTYPE_STATION; priv->current_ht_config.smps = IEEE80211_SMPS_STATIC; @@ -1049,12 +1353,6 @@ static int iwl_init_drv(struct iwl_priv *priv) priv->ucode_owner = IWL_OWNERSHIP_DRIVER; - /* initialize force reset */ - priv->force_reset[IWL_RF_RESET].reset_duration = - IWL_DELAY_NEXT_FORCE_RF_RESET; - priv->force_reset[IWL_FW_RESET].reset_duration = - IWL_DELAY_NEXT_FORCE_FW_RELOAD; - priv->rx_statistics_jiffies = jiffies; /* Choose which receivers/antennas to use */ @@ -1063,8 +1361,8 @@ static int iwl_init_drv(struct iwl_priv *priv) iwl_init_scan_params(priv); /* init bt coex */ - if (cfg(priv)->bt_params && - cfg(priv)->bt_params->advanced_bt_coexist) { + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist) { priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT; priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT; priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK; @@ -1094,7 +1392,7 @@ static int iwl_init_drv(struct iwl_priv *priv) return ret; } -static void iwl_uninit_drv(struct iwl_priv *priv) +void iwl_uninit_drv(struct iwl_priv *priv) { iwl_free_geos(priv); iwl_free_channel_map(priv); @@ -1107,75 +1405,59 @@ static void iwl_uninit_drv(struct iwl_priv *priv) #endif } -/* Size of one Rx buffer in host DRAM */ -#define IWL_RX_BUF_SIZE_4K (4 * 1024) -#define IWL_RX_BUF_SIZE_8K (8 * 1024) - -static void iwl_set_hw_params(struct iwl_priv *priv) +void iwl_set_hw_params(struct iwl_priv *priv) { - if (cfg(priv)->ht_params) - hw_params(priv).use_rts_for_aggregation = - cfg(priv)->ht_params->use_rts_for_aggregation; - - if (iwlagn_mod_params.amsdu_size_8K) - hw_params(priv).rx_page_order = - get_order(IWL_RX_BUF_SIZE_8K); - else - hw_params(priv).rx_page_order = - get_order(IWL_RX_BUF_SIZE_4K); - - if (iwlagn_mod_params.disable_11n & IWL_DISABLE_HT_ALL) - hw_params(priv).sku &= ~EEPROM_SKU_CAP_11N_ENABLE; + if (priv->cfg->ht_params) + priv->hw_params.use_rts_for_aggregation = + priv->cfg->ht_params->use_rts_for_aggregation; - hw_params(priv).num_ampdu_queues = - cfg(priv)->base_params->num_of_ampdu_queues; - hw_params(priv).wd_timeout = cfg(priv)->base_params->wd_timeout; + if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL) + priv->hw_params.sku &= ~EEPROM_SKU_CAP_11N_ENABLE; /* Device-specific setup */ - cfg(priv)->lib->set_hw_params(priv); + priv->lib->set_hw_params(priv); } -static void iwl_debug_config(struct iwl_priv *priv) +/* show what optional capabilities we have */ +void iwl_option_config(struct iwl_priv *priv) { - dev_printk(KERN_INFO, trans(priv)->dev, "CONFIG_IWLWIFI_DEBUG " #ifdef CONFIG_IWLWIFI_DEBUG - "enabled\n"); + IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUG enabled\n"); #else - "disabled\n"); + IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUG disabled\n"); #endif - dev_printk(KERN_INFO, trans(priv)->dev, "CONFIG_IWLWIFI_DEBUGFS " + #ifdef CONFIG_IWLWIFI_DEBUGFS - "enabled\n"); + IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUGFS enabled\n"); #else - "disabled\n"); + IWL_INFO(priv, "CONFIG_IWLWIFI_DEBUGFS disabled\n"); #endif - dev_printk(KERN_INFO, trans(priv)->dev, "CONFIG_IWLWIFI_DEVICE_TRACING " + #ifdef CONFIG_IWLWIFI_DEVICE_TRACING - "enabled\n"); + IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TRACING enabled\n"); #else - "disabled\n"); + IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TRACING disabled\n"); #endif - dev_printk(KERN_INFO, trans(priv)->dev, "CONFIG_IWLWIFI_DEVICE_TESTMODE " #ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE - "enabled\n"); + IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TESTMODE enabled\n"); #else - "disabled\n"); + IWL_INFO(priv, "CONFIG_IWLWIFI_DEVICE_TESTMODE disabled\n"); #endif - dev_printk(KERN_INFO, trans(priv)->dev, "CONFIG_IWLWIFI_P2P " + #ifdef CONFIG_IWLWIFI_P2P - "enabled\n"); + IWL_INFO(priv, "CONFIG_IWLWIFI_P2P enabled\n"); #else - "disabled\n"); + IWL_INFO(priv, "CONFIG_IWLWIFI_P2P disabled\n"); #endif } static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, + const struct iwl_cfg *cfg, const struct iwl_fw *fw) { - int err = 0; struct iwl_priv *priv; struct ieee80211_hw *hw; struct iwl_op_mode *op_mode; @@ -1190,25 +1472,60 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, STATISTICS_NOTIFICATION, REPLY_TX, }; + int i; /************************ * 1. Allocating HW data ************************/ hw = iwl_alloc_all(); if (!hw) { - pr_err("%s: Cannot allocate network device\n", - cfg(trans)->name); - err = -ENOMEM; + pr_err("%s: Cannot allocate network device\n", cfg->name); goto out; } op_mode = hw->priv; op_mode->ops = &iwl_dvm_ops; priv = IWL_OP_MODE_GET_DVM(op_mode); - priv->shrd = trans->shrd; + priv->trans = trans; + priv->dev = trans->dev; + priv->cfg = cfg; priv->fw = fw; - /* TODO: remove fw from shared data later */ - priv->shrd->fw = fw; + + switch (priv->cfg->device_family) { + case IWL_DEVICE_FAMILY_1000: + case IWL_DEVICE_FAMILY_100: + priv->lib = &iwl1000_lib; + break; + case IWL_DEVICE_FAMILY_2000: + case IWL_DEVICE_FAMILY_105: + priv->lib = &iwl2000_lib; + break; + case IWL_DEVICE_FAMILY_2030: + case IWL_DEVICE_FAMILY_135: + priv->lib = &iwl2030_lib; + break; + case IWL_DEVICE_FAMILY_5000: + priv->lib = &iwl5000_lib; + break; + case IWL_DEVICE_FAMILY_5150: + priv->lib = &iwl5150_lib; + break; + case IWL_DEVICE_FAMILY_6000: + case IWL_DEVICE_FAMILY_6005: + case IWL_DEVICE_FAMILY_6000i: + case IWL_DEVICE_FAMILY_6050: + case IWL_DEVICE_FAMILY_6150: + priv->lib = &iwl6000_lib; + break; + case IWL_DEVICE_FAMILY_6030: + priv->lib = &iwl6030_lib; + break; + default: + break; + } + + if (WARN_ON(!priv->lib)) + goto out_free_hw; /* * Populate the state variables that the transport layer needs @@ -1217,87 +1534,90 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, trans_cfg.op_mode = op_mode; trans_cfg.no_reclaim_cmds = no_reclaim_cmds; trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); + trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K; + if (!iwlwifi_mod_params.wd_disable) + trans_cfg.queue_watchdog_timeout = + priv->cfg->base_params->wd_timeout; + else + trans_cfg.queue_watchdog_timeout = IWL_WATCHHDOG_DISABLED; + trans_cfg.command_names = iwl_dvm_cmd_strings; ucode_flags = fw->ucode_capa.flags; #ifndef CONFIG_IWLWIFI_P2P - ucode_flags &= ~IWL_UCODE_TLV_FLAGS_PAN; + ucode_flags &= ~IWL_UCODE_TLV_FLAGS_P2P; #endif if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN) { priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN; trans_cfg.cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; + trans_cfg.queue_to_fifo = iwlagn_ipan_queue_to_tx_fifo; + trans_cfg.n_queue_to_fifo = + ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo); } else { priv->sta_key_max_num = STA_KEY_MAX_NUM; trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; + trans_cfg.queue_to_fifo = iwlagn_default_queue_to_tx_fifo; + trans_cfg.n_queue_to_fifo = + ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo); } /* Configure transport layer */ - iwl_trans_configure(trans(priv), &trans_cfg); + iwl_trans_configure(priv->trans, &trans_cfg); /* At this point both hw and priv are allocated. */ - SET_IEEE80211_DEV(priv->hw, trans(priv)->dev); + SET_IEEE80211_DEV(priv->hw, priv->trans->dev); - /* show what debugging capabilities we have */ - iwl_debug_config(priv); + iwl_option_config(priv); IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n"); /* is antenna coupling more than 35dB ? */ priv->bt_ant_couple_ok = - (iwlagn_mod_params.ant_coupling > + (iwlwifi_mod_params.ant_coupling > IWL_BT_ANTENNA_COUPLING_THRESHOLD) ? true : false; /* enable/disable bt channel inhibition */ - priv->bt_ch_announce = iwlagn_mod_params.bt_ch_announce; + priv->bt_ch_announce = iwlwifi_mod_params.bt_ch_announce; IWL_DEBUG_INFO(priv, "BT channel inhibition is %s\n", (priv->bt_ch_announce) ? "On" : "Off"); - if (iwl_alloc_traffic_mem(priv)) - IWL_ERR(priv, "Not enough memory to generate traffic log\n"); - /* these spin locks will be used in apm_ops.init and EEPROM access * we should init now */ - spin_lock_init(&trans(priv)->reg_lock); spin_lock_init(&priv->statistics.lock); /*********************** * 2. Read REV register ***********************/ IWL_INFO(priv, "Detected %s, REV=0x%X\n", - cfg(priv)->name, trans(priv)->hw_rev); + priv->cfg->name, priv->trans->hw_rev); - err = iwl_trans_start_hw(trans(priv)); - if (err) - goto out_free_traffic_mem; + if (iwl_trans_start_hw(priv->trans)) + goto out_free_hw; - /***************** - * 3. Read EEPROM - *****************/ - err = iwl_eeprom_init(trans(priv), trans(priv)->hw_rev); - /* Reset chip to save power until we load uCode during "up". */ - iwl_trans_stop_hw(trans(priv)); - if (err) { + /* Read the EEPROM */ + if (iwl_eeprom_init(priv, priv->trans->hw_rev)) { IWL_ERR(priv, "Unable to init EEPROM\n"); - goto out_free_traffic_mem; + goto out_free_hw; } - err = iwl_eeprom_check_version(priv); - if (err) + /* Reset chip to save power until we load uCode during "up". */ + iwl_trans_stop_hw(priv->trans, false); + + if (iwl_eeprom_check_version(priv)) goto out_free_eeprom; - err = iwl_eeprom_init_hw_params(priv); - if (err) + if (iwl_eeprom_init_hw_params(priv)) goto out_free_eeprom; /* extract MAC Address */ - iwl_eeprom_get_mac(priv->shrd, priv->addresses[0].addr); + iwl_eeprom_get_mac(priv, priv->addresses[0].addr); IWL_DEBUG_INFO(priv, "MAC address: %pM\n", priv->addresses[0].addr); priv->hw->wiphy->addresses = priv->addresses; priv->hw->wiphy->n_addresses = 1; - num_mac = iwl_eeprom_query16(priv->shrd, EEPROM_NUM_MAC_ADDRESS); + num_mac = iwl_eeprom_query16(priv, EEPROM_NUM_MAC_ADDRESS); if (num_mac > 1) { memcpy(priv->addresses[1].addr, priv->addresses[0].addr, ETH_ALEN); @@ -1310,7 +1630,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, ************************/ iwl_set_hw_params(priv); - if (!(hw_params(priv).sku & EEPROM_SKU_CAP_IPAN_ENABLE)) { + if (!(priv->hw_params.sku & EEPROM_SKU_CAP_IPAN_ENABLE)) { IWL_DEBUG_INFO(priv, "Your EEPROM disabled PAN"); ucode_flags &= ~IWL_UCODE_TLV_FLAGS_PAN; /* @@ -1320,18 +1640,32 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, ucode_flags &= ~IWL_UCODE_TLV_FLAGS_P2P; priv->sta_key_max_num = STA_KEY_MAX_NUM; trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; + trans_cfg.queue_to_fifo = iwlagn_default_queue_to_tx_fifo; + trans_cfg.n_queue_to_fifo = + ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo); /* Configure transport layer again*/ - iwl_trans_configure(trans(priv), &trans_cfg); + iwl_trans_configure(priv->trans, &trans_cfg); } /******************* * 5. Setup priv *******************/ + for (i = 0; i < IWL_MAX_HW_QUEUES; i++) { + priv->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE; + if (i < IWLAGN_FIRST_AMPDU_QUEUE && + i != IWL_DEFAULT_CMD_QUEUE_NUM && + i != IWL_IPAN_CMD_QUEUE_NUM) + priv->queue_to_mac80211[i] = i; + atomic_set(&priv->queue_stop_count[i], 0); + } + + WARN_ON(trans_cfg.queue_to_fifo[trans_cfg.cmd_queue] != + IWLAGN_CMD_FIFO_NUM); - err = iwl_init_drv(priv); - if (err) + if (iwl_init_drv(priv)) goto out_free_eeprom; + /* At this point both hw and priv are initialized. */ /******************** @@ -1364,15 +1698,12 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, * * 7. Setup and register with mac80211 and debugfs **************************************************/ - err = iwlagn_mac_setup_register(priv, &fw->ucode_capa); - if (err) + if (iwlagn_mac_setup_register(priv, &fw->ucode_capa)) goto out_destroy_workqueue; - err = iwl_dbgfs_register(priv, DRV_NAME); - if (err) + if (iwl_dbgfs_register(priv, DRV_NAME)) IWL_ERR(priv, - "failed to create debugfs files. Ignoring error: %d\n", - err); + "failed to create debugfs files. Ignoring error\n"); return op_mode; @@ -1381,16 +1712,15 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, priv->workqueue = NULL; iwl_uninit_drv(priv); out_free_eeprom: - iwl_eeprom_free(priv->shrd); -out_free_traffic_mem: - iwl_free_traffic_mem(priv); + iwl_eeprom_free(priv); +out_free_hw: ieee80211_free_hw(priv->hw); out: op_mode = NULL; return op_mode; } -static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode) +void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode) { struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); @@ -1405,9 +1735,9 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode) /*This will stop the queues, move the device to low power state */ priv->ucode_loaded = false; - iwl_trans_stop_device(trans(priv)); + iwl_trans_stop_device(priv->trans); - iwl_eeprom_free(priv->shrd); + iwl_eeprom_free(priv); /*netif_stop_queue(dev); */ flush_workqueue(priv->workqueue); @@ -1417,69 +1747,562 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode) * until now... */ destroy_workqueue(priv->workqueue); priv->workqueue = NULL; - iwl_free_traffic_mem(priv); iwl_uninit_drv(priv); dev_kfree_skb(priv->beacon_skb); + iwl_trans_stop_hw(priv->trans, true); ieee80211_free_hw(priv->hw); } -static void iwl_cmd_queue_full(struct iwl_op_mode *op_mode) +static const char * const desc_lookup_text[] = { + "OK", + "FAIL", + "BAD_PARAM", + "BAD_CHECKSUM", + "NMI_INTERRUPT_WDG", + "SYSASSERT", + "FATAL_ERROR", + "BAD_COMMAND", + "HW_ERROR_TUNE_LOCK", + "HW_ERROR_TEMPERATURE", + "ILLEGAL_CHAN_FREQ", + "VCC_NOT_STABLE", + "FH_ERROR", + "NMI_INTERRUPT_HOST", + "NMI_INTERRUPT_ACTION_PT", + "NMI_INTERRUPT_UNKNOWN", + "UCODE_VERSION_MISMATCH", + "HW_ERROR_ABS_LOCK", + "HW_ERROR_CAL_LOCK_FAIL", + "NMI_INTERRUPT_INST_ACTION_PT", + "NMI_INTERRUPT_DATA_ACTION_PT", + "NMI_TRM_HW_ER", + "NMI_INTERRUPT_TRM", + "NMI_INTERRUPT_BREAK_POINT", + "DEBUG_0", + "DEBUG_1", + "DEBUG_2", + "DEBUG_3", +}; + +static struct { char *name; u8 num; } advanced_lookup[] = { + { "NMI_INTERRUPT_WDG", 0x34 }, + { "SYSASSERT", 0x35 }, + { "UCODE_VERSION_MISMATCH", 0x37 }, + { "BAD_COMMAND", 0x38 }, + { "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C }, + { "FATAL_ERROR", 0x3D }, + { "NMI_TRM_HW_ERR", 0x46 }, + { "NMI_INTERRUPT_TRM", 0x4C }, + { "NMI_INTERRUPT_BREAK_POINT", 0x54 }, + { "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C }, + { "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 }, + { "NMI_INTERRUPT_HOST", 0x66 }, + { "NMI_INTERRUPT_ACTION_PT", 0x7C }, + { "NMI_INTERRUPT_UNKNOWN", 0x84 }, + { "NMI_INTERRUPT_INST_ACTION_PT", 0x86 }, + { "ADVANCED_SYSASSERT", 0 }, +}; + +static const char *desc_lookup(u32 num) +{ + int i; + int max = ARRAY_SIZE(desc_lookup_text); + + if (num < max) + return desc_lookup_text[num]; + + max = ARRAY_SIZE(advanced_lookup) - 1; + for (i = 0; i < max; i++) { + if (advanced_lookup[i].num == num) + break; + } + return advanced_lookup[i].name; +} + +#define ERROR_START_OFFSET (1 * sizeof(u32)) +#define ERROR_ELEM_SIZE (7 * sizeof(u32)) + +static void iwl_dump_nic_error_log(struct iwl_priv *priv) +{ + struct iwl_trans *trans = priv->trans; + u32 base; + struct iwl_error_event_table table; + + base = priv->device_pointers.error_event_table; + if (priv->cur_ucode == IWL_UCODE_INIT) { + if (!base) + base = priv->fw->init_errlog_ptr; + } else { + if (!base) + base = priv->fw->inst_errlog_ptr; + } + + if (!iwlagn_hw_valid_rtc_data_addr(base)) { + IWL_ERR(priv, + "Not valid error log pointer 0x%08X for %s uCode\n", + base, + (priv->cur_ucode == IWL_UCODE_INIT) + ? "Init" : "RT"); + return; + } + + /*TODO: Update dbgfs with ISR error stats obtained below */ + iwl_read_targ_mem_words(trans, base, &table, sizeof(table)); + + if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { + IWL_ERR(trans, "Start IWL Error Log Dump:\n"); + IWL_ERR(trans, "Status: 0x%08lX, count: %d\n", + priv->status, table.valid); + } + + trace_iwlwifi_dev_ucode_error(trans->dev, table.error_id, table.tsf_low, + table.data1, table.data2, table.line, + table.blink1, table.blink2, table.ilink1, + table.ilink2, table.bcon_time, table.gp1, + table.gp2, table.gp3, table.ucode_ver, + table.hw_ver, table.brd_ver); + IWL_ERR(priv, "0x%08X | %-28s\n", table.error_id, + desc_lookup(table.error_id)); + IWL_ERR(priv, "0x%08X | uPc\n", table.pc); + IWL_ERR(priv, "0x%08X | branchlink1\n", table.blink1); + IWL_ERR(priv, "0x%08X | branchlink2\n", table.blink2); + IWL_ERR(priv, "0x%08X | interruptlink1\n", table.ilink1); + IWL_ERR(priv, "0x%08X | interruptlink2\n", table.ilink2); + IWL_ERR(priv, "0x%08X | data1\n", table.data1); + IWL_ERR(priv, "0x%08X | data2\n", table.data2); + IWL_ERR(priv, "0x%08X | line\n", table.line); + IWL_ERR(priv, "0x%08X | beacon time\n", table.bcon_time); + IWL_ERR(priv, "0x%08X | tsf low\n", table.tsf_low); + IWL_ERR(priv, "0x%08X | tsf hi\n", table.tsf_hi); + IWL_ERR(priv, "0x%08X | time gp1\n", table.gp1); + IWL_ERR(priv, "0x%08X | time gp2\n", table.gp2); + IWL_ERR(priv, "0x%08X | time gp3\n", table.gp3); + IWL_ERR(priv, "0x%08X | uCode version\n", table.ucode_ver); + IWL_ERR(priv, "0x%08X | hw version\n", table.hw_ver); + IWL_ERR(priv, "0x%08X | board version\n", table.brd_ver); + IWL_ERR(priv, "0x%08X | hcmd\n", table.hcmd); + IWL_ERR(priv, "0x%08X | isr0\n", table.isr0); + IWL_ERR(priv, "0x%08X | isr1\n", table.isr1); + IWL_ERR(priv, "0x%08X | isr2\n", table.isr2); + IWL_ERR(priv, "0x%08X | isr3\n", table.isr3); + IWL_ERR(priv, "0x%08X | isr4\n", table.isr4); + IWL_ERR(priv, "0x%08X | isr_pref\n", table.isr_pref); + IWL_ERR(priv, "0x%08X | wait_event\n", table.wait_event); + IWL_ERR(priv, "0x%08X | l2p_control\n", table.l2p_control); + IWL_ERR(priv, "0x%08X | l2p_duration\n", table.l2p_duration); + IWL_ERR(priv, "0x%08X | l2p_mhvalid\n", table.l2p_mhvalid); + IWL_ERR(priv, "0x%08X | l2p_addr_match\n", table.l2p_addr_match); + IWL_ERR(priv, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel); + IWL_ERR(priv, "0x%08X | timestamp\n", table.u_timestamp); + IWL_ERR(priv, "0x%08X | flow_handler\n", table.flow_handler); +} + +#define EVENT_START_OFFSET (4 * sizeof(u32)) + +/** + * iwl_print_event_log - Dump error event log to syslog + * + */ +static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, + u32 num_events, u32 mode, + int pos, char **buf, size_t bufsz) +{ + u32 i; + u32 base; /* SRAM byte address of event log header */ + u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ + u32 ptr; /* SRAM byte address of log data */ + u32 ev, time, data; /* event log data */ + unsigned long reg_flags; + + struct iwl_trans *trans = priv->trans; + + if (num_events == 0) + return pos; + + base = priv->device_pointers.log_event_table; + if (priv->cur_ucode == IWL_UCODE_INIT) { + if (!base) + base = priv->fw->init_evtlog_ptr; + } else { + if (!base) + base = priv->fw->inst_evtlog_ptr; + } + + if (mode == 0) + event_size = 2 * sizeof(u32); + else + event_size = 3 * sizeof(u32); + + ptr = base + EVENT_START_OFFSET + (start_idx * event_size); + + /* Make sure device is powered up for SRAM reads */ + spin_lock_irqsave(&trans->reg_lock, reg_flags); + if (unlikely(!iwl_grab_nic_access(trans))) + goto out_unlock; + + /* Set starting address; reads will auto-increment */ + iwl_write32(trans, HBUS_TARG_MEM_RADDR, ptr); + + /* "time" is actually "data" for mode 0 (no timestamp). + * place event id # at far right for easier visual parsing. */ + for (i = 0; i < num_events; i++) { + ev = iwl_read32(trans, HBUS_TARG_MEM_RDAT); + time = iwl_read32(trans, HBUS_TARG_MEM_RDAT); + if (mode == 0) { + /* data, ev */ + if (bufsz) { + pos += scnprintf(*buf + pos, bufsz - pos, + "EVT_LOG:0x%08x:%04u\n", + time, ev); + } else { + trace_iwlwifi_dev_ucode_event(trans->dev, 0, + time, ev); + IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", + time, ev); + } + } else { + data = iwl_read32(trans, HBUS_TARG_MEM_RDAT); + if (bufsz) { + pos += scnprintf(*buf + pos, bufsz - pos, + "EVT_LOGT:%010u:0x%08x:%04u\n", + time, data, ev); + } else { + IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n", + time, data, ev); + trace_iwlwifi_dev_ucode_event(trans->dev, time, + data, ev); + } + } + } + + /* Allow device to power down */ + iwl_release_nic_access(trans); +out_unlock: + spin_unlock_irqrestore(&trans->reg_lock, reg_flags); + return pos; +} + +/** + * iwl_print_last_event_logs - Dump the newest # of event log to syslog + */ +static int iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity, + u32 num_wraps, u32 next_entry, + u32 size, u32 mode, + int pos, char **buf, size_t bufsz) +{ + /* + * display the newest DEFAULT_LOG_ENTRIES entries + * i.e the entries just before the next ont that uCode would fill. + */ + if (num_wraps) { + if (next_entry < size) { + pos = iwl_print_event_log(priv, + capacity - (size - next_entry), + size - next_entry, mode, + pos, buf, bufsz); + pos = iwl_print_event_log(priv, 0, + next_entry, mode, + pos, buf, bufsz); + } else + pos = iwl_print_event_log(priv, next_entry - size, + size, mode, pos, buf, bufsz); + } else { + if (next_entry < size) { + pos = iwl_print_event_log(priv, 0, next_entry, + mode, pos, buf, bufsz); + } else { + pos = iwl_print_event_log(priv, next_entry - size, + size, mode, pos, buf, bufsz); + } + } + return pos; +} + +#define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20) + +int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, + char **buf, bool display) +{ + u32 base; /* SRAM byte address of event log header */ + u32 capacity; /* event log capacity in # entries */ + u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ + u32 num_wraps; /* # times uCode wrapped to top of log */ + u32 next_entry; /* index of next entry to be written by uCode */ + u32 size; /* # entries that we'll print */ + u32 logsize; + int pos = 0; + size_t bufsz = 0; + struct iwl_trans *trans = priv->trans; + + base = priv->device_pointers.log_event_table; + if (priv->cur_ucode == IWL_UCODE_INIT) { + logsize = priv->fw->init_evtlog_size; + if (!base) + base = priv->fw->init_evtlog_ptr; + } else { + logsize = priv->fw->inst_evtlog_size; + if (!base) + base = priv->fw->inst_evtlog_ptr; + } + + if (!iwlagn_hw_valid_rtc_data_addr(base)) { + IWL_ERR(priv, + "Invalid event log pointer 0x%08X for %s uCode\n", + base, + (priv->cur_ucode == IWL_UCODE_INIT) + ? "Init" : "RT"); + return -EINVAL; + } + + /* event log header */ + capacity = iwl_read_targ_mem(trans, base); + mode = iwl_read_targ_mem(trans, base + (1 * sizeof(u32))); + num_wraps = iwl_read_targ_mem(trans, base + (2 * sizeof(u32))); + next_entry = iwl_read_targ_mem(trans, base + (3 * sizeof(u32))); + + if (capacity > logsize) { + IWL_ERR(priv, "Log capacity %d is bogus, limit to %d " + "entries\n", capacity, logsize); + capacity = logsize; + } + + if (next_entry > logsize) { + IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n", + next_entry, logsize); + next_entry = logsize; + } + + size = num_wraps ? capacity : next_entry; + + /* bail out if nothing in log */ + if (size == 0) { + IWL_ERR(trans, "Start IWL Event Log Dump: nothing in log\n"); + return pos; + } + +#ifdef CONFIG_IWLWIFI_DEBUG + if (!(iwl_have_debug_level(IWL_DL_FW_ERRORS)) && !full_log) + size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES) + ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size; +#else + size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES) + ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size; +#endif + IWL_ERR(priv, "Start IWL Event Log Dump: display last %u entries\n", + size); + +#ifdef CONFIG_IWLWIFI_DEBUG + if (display) { + if (full_log) + bufsz = capacity * 48; + else + bufsz = size * 48; + *buf = kmalloc(bufsz, GFP_KERNEL); + if (!*buf) + return -ENOMEM; + } + if (iwl_have_debug_level(IWL_DL_FW_ERRORS) || full_log) { + /* + * if uCode has wrapped back to top of log, + * start at the oldest entry, + * i.e the next one that uCode would fill. + */ + if (num_wraps) + pos = iwl_print_event_log(priv, next_entry, + capacity - next_entry, mode, + pos, buf, bufsz); + /* (then/else) start at top of log */ + pos = iwl_print_event_log(priv, 0, + next_entry, mode, pos, buf, bufsz); + } else + pos = iwl_print_last_event_logs(priv, capacity, num_wraps, + next_entry, size, mode, + pos, buf, bufsz); +#else + pos = iwl_print_last_event_logs(priv, capacity, num_wraps, + next_entry, size, mode, + pos, buf, bufsz); +#endif + return pos; +} + +static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) +{ + unsigned int reload_msec; + unsigned long reload_jiffies; + +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_have_debug_level(IWL_DL_FW_ERRORS)) + iwl_print_rx_config_cmd(priv, IWL_RXON_CTX_BSS); +#endif + + /* uCode is no longer loaded. */ + priv->ucode_loaded = false; + + /* Set the FW error flag -- cleared on iwl_down */ + set_bit(STATUS_FW_ERROR, &priv->status); + + iwl_abort_notification_waits(&priv->notif_wait); + + /* Keep the restart process from trying to send host + * commands by clearing the ready bit */ + clear_bit(STATUS_READY, &priv->status); + + wake_up(&priv->trans->wait_command_queue); + + if (!ondemand) { + /* + * If firmware keep reloading, then it indicate something + * serious wrong and firmware having problem to recover + * from it. Instead of keep trying which will fill the syslog + * and hang the system, let's just stop it + */ + reload_jiffies = jiffies; + reload_msec = jiffies_to_msecs((long) reload_jiffies - + (long) priv->reload_jiffies); + priv->reload_jiffies = reload_jiffies; + if (reload_msec <= IWL_MIN_RELOAD_DURATION) { + priv->reload_count++; + if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) { + IWL_ERR(priv, "BUG_ON, Stop restarting\n"); + return; + } + } else + priv->reload_count = 0; + } + + if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { + if (iwlwifi_mod_params.restart_fw) { + IWL_DEBUG_FW_ERRORS(priv, + "Restarting adapter due to uCode error.\n"); + queue_work(priv->workqueue, &priv->restart); + } else + IWL_DEBUG_FW_ERRORS(priv, + "Detected FW error, but not restarting\n"); + } +} + +void iwl_nic_error(struct iwl_op_mode *op_mode) +{ + struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); + + IWL_ERR(priv, "Loaded firmware version: %s\n", + priv->fw->fw_version); + + iwl_dump_nic_error_log(priv); + iwl_dump_nic_event_log(priv, false, NULL, false); + + iwlagn_fw_error(priv, false); +} + +void iwl_cmd_queue_full(struct iwl_op_mode *op_mode) { struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); if (!iwl_check_for_ct_kill(priv)) { IWL_ERR(priv, "Restarting adapter queue is full\n"); - iwl_nic_error(op_mode); + iwlagn_fw_error(priv, false); } } -static void iwl_nic_config(struct iwl_op_mode *op_mode) +void iwl_nic_config(struct iwl_op_mode *op_mode) { struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); - cfg(priv)->lib->nic_config(priv); + priv->lib->nic_config(priv); } -static void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, u8 ac) +static void iwl_wimax_active(struct iwl_op_mode *op_mode) { struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); - set_bit(ac, &priv->transport_queue_stop); - ieee80211_stop_queue(priv->hw, ac); + clear_bit(STATUS_READY, &priv->status); + IWL_ERR(priv, "RF is used by WiMAX\n"); } -static void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, u8 ac) +void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, int queue) { struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); + int mq = priv->queue_to_mac80211[queue]; + + if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE)) + return; - clear_bit(ac, &priv->transport_queue_stop); + if (atomic_inc_return(&priv->queue_stop_count[mq]) > 1) { + IWL_DEBUG_TX_QUEUES(priv, + "queue %d (mac80211 %d) already stopped\n", + queue, mq); + return; + } + + set_bit(mq, &priv->transport_queue_stop); + ieee80211_stop_queue(priv->hw, mq); +} + +void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, int queue) +{ + struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); + int mq = priv->queue_to_mac80211[queue]; + + if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE)) + return; + + if (atomic_dec_return(&priv->queue_stop_count[mq]) > 0) { + IWL_DEBUG_TX_QUEUES(priv, + "queue %d (mac80211 %d) already awake\n", + queue, mq); + return; + } + + clear_bit(mq, &priv->transport_queue_stop); if (!priv->passive_no_rx) - ieee80211_wake_queue(priv->hw, ac); + ieee80211_wake_queue(priv->hw, mq); } void iwlagn_lift_passive_no_rx(struct iwl_priv *priv) { - int ac; + int mq; if (!priv->passive_no_rx) return; - for (ac = IEEE80211_AC_VO; ac < IEEE80211_NUM_ACS; ac++) { - if (!test_bit(ac, &priv->transport_queue_stop)) { - IWL_DEBUG_TX_QUEUES(priv, "Wake queue %d"); - ieee80211_wake_queue(priv->hw, ac); + for (mq = 0; mq < IWLAGN_FIRST_AMPDU_QUEUE; mq++) { + if (!test_bit(mq, &priv->transport_queue_stop)) { + IWL_DEBUG_TX_QUEUES(priv, "Wake queue %d", mq); + ieee80211_wake_queue(priv->hw, mq); } else { - IWL_DEBUG_TX_QUEUES(priv, "Don't wake queue %d"); + IWL_DEBUG_TX_QUEUES(priv, "Don't wake queue %d", mq); } } priv->passive_no_rx = false; } +void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) +{ + struct ieee80211_tx_info *info; + + info = IEEE80211_SKB_CB(skb); + kmem_cache_free(iwl_tx_cmd_pool, (info->driver_data[1])); + dev_kfree_skb_any(skb); +} + +void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) +{ + struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); + + if (state) + set_bit(STATUS_RF_KILL_HW, &priv->status); + else + clear_bit(STATUS_RF_KILL_HW, &priv->status); + + wiphy_rfkill_set_hw_state(priv->hw->wiphy, state); +} + const struct iwl_op_mode_ops iwl_dvm_ops = { .start = iwl_op_mode_dvm_start, .stop = iwl_op_mode_dvm_stop, @@ -1491,6 +2314,7 @@ const struct iwl_op_mode_ops iwl_dvm_ops = { .nic_error = iwl_nic_error, .cmd_queue_full = iwl_cmd_queue_full, .nic_config = iwl_nic_config, + .wimax_active = iwl_wimax_active, }; /***************************************************************************** @@ -1541,96 +2365,3 @@ static void __exit iwl_exit(void) module_exit(iwl_exit); module_init(iwl_init); - -#ifdef CONFIG_IWLWIFI_DEBUG -module_param_named(debug, iwlagn_mod_params.debug_level, uint, - S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "debug output mask"); -#endif - -module_param_named(swcrypto, iwlagn_mod_params.sw_crypto, int, S_IRUGO); -MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); -module_param_named(11n_disable, iwlagn_mod_params.disable_11n, uint, S_IRUGO); -MODULE_PARM_DESC(11n_disable, - "disable 11n functionality, bitmap: 1: full, 2: agg TX, 4: agg RX"); -module_param_named(amsdu_size_8K, iwlagn_mod_params.amsdu_size_8K, - int, S_IRUGO); -MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size"); -module_param_named(fw_restart, iwlagn_mod_params.restart_fw, int, S_IRUGO); -MODULE_PARM_DESC(fw_restart, "restart firmware in case of error"); - -module_param_named(ucode_alternative, - iwlagn_mod_params.wanted_ucode_alternative, - int, S_IRUGO); -MODULE_PARM_DESC(ucode_alternative, - "specify ucode alternative to use from ucode file"); - -module_param_named(antenna_coupling, iwlagn_mod_params.ant_coupling, - int, S_IRUGO); -MODULE_PARM_DESC(antenna_coupling, - "specify antenna coupling in dB (defualt: 0 dB)"); - -module_param_named(bt_ch_inhibition, iwlagn_mod_params.bt_ch_announce, - bool, S_IRUGO); -MODULE_PARM_DESC(bt_ch_inhibition, - "Enable BT channel inhibition (default: enable)"); - -module_param_named(plcp_check, iwlagn_mod_params.plcp_check, bool, S_IRUGO); -MODULE_PARM_DESC(plcp_check, "Check plcp health (default: 1 [enabled])"); - -module_param_named(ack_check, iwlagn_mod_params.ack_check, bool, S_IRUGO); -MODULE_PARM_DESC(ack_check, "Check ack health (default: 0 [disabled])"); - -module_param_named(wd_disable, iwlagn_mod_params.wd_disable, int, S_IRUGO); -MODULE_PARM_DESC(wd_disable, - "Disable stuck queue watchdog timer 0=system default, " - "1=disable, 2=enable (default: 0)"); - -/* - * set bt_coex_active to true, uCode will do kill/defer - * every time the priority line is asserted (BT is sending signals on the - * priority line in the PCIx). - * set bt_coex_active to false, uCode will ignore the BT activity and - * perform the normal operation - * - * User might experience transmit issue on some platform due to WiFi/BT - * co-exist problem. The possible behaviors are: - * Able to scan and finding all the available AP - * Not able to associate with any AP - * On those platforms, WiFi communication can be restored by set - * "bt_coex_active" module parameter to "false" - * - * default: bt_coex_active = true (BT_COEX_ENABLE) - */ -module_param_named(bt_coex_active, iwlagn_mod_params.bt_coex_active, - bool, S_IRUGO); -MODULE_PARM_DESC(bt_coex_active, "enable wifi/bt co-exist (default: enable)"); - -module_param_named(led_mode, iwlagn_mod_params.led_mode, int, S_IRUGO); -MODULE_PARM_DESC(led_mode, "0=system default, " - "1=On(RF On)/Off(RF Off), 2=blinking, 3=Off (default: 0)"); - -module_param_named(power_save, iwlagn_mod_params.power_save, - bool, S_IRUGO); -MODULE_PARM_DESC(power_save, - "enable WiFi power management (default: disable)"); - -module_param_named(power_level, iwlagn_mod_params.power_level, - int, S_IRUGO); -MODULE_PARM_DESC(power_level, - "default power save level (range from 1 - 5, default: 1)"); - -module_param_named(auto_agg, iwlagn_mod_params.auto_agg, - bool, S_IRUGO); -MODULE_PARM_DESC(auto_agg, - "enable agg w/o check traffic load (default: enable)"); - -/* - * For now, keep using power level 1 instead of automatically - * adjusting ... - */ -module_param_named(no_sleep_autoadjust, iwlagn_mod_params.no_sleep_autoadjust, - bool, S_IRUGO); -MODULE_PARM_DESC(no_sleep_autoadjust, - "don't automatically adjust sleep level " - "according to maximum network latency (default: true)"); diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-agn.h b/trunk/drivers/net/wireless/iwlwifi/iwl-agn.h index 3780a03f2716..79c0fe06f4db 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -64,6 +64,43 @@ #define __iwl_agn_h__ #include "iwl-dev.h" +#include "iwl-config.h" + +/* The first 11 queues (0-10) are used otherwise */ +#define IWLAGN_FIRST_AMPDU_QUEUE 11 + +/* AUX (TX during scan dwell) queue */ +#define IWL_AUX_QUEUE 10 + +/* device operations */ +extern struct iwl_lib_ops iwl1000_lib; +extern struct iwl_lib_ops iwl2000_lib; +extern struct iwl_lib_ops iwl2030_lib; +extern struct iwl_lib_ops iwl5000_lib; +extern struct iwl_lib_ops iwl5150_lib; +extern struct iwl_lib_ops iwl6000_lib; +extern struct iwl_lib_ops iwl6030_lib; + + +#define TIME_UNIT 1024 + +/***************************************************** +* DRIVER STATUS FUNCTIONS +******************************************************/ +#define STATUS_RF_KILL_HW 0 +#define STATUS_CT_KILL 1 +#define STATUS_ALIVE 2 +#define STATUS_READY 3 +#define STATUS_GEO_CONFIGURED 4 +#define STATUS_EXIT_PENDING 5 +#define STATUS_STATISTICS 6 +#define STATUS_SCANNING 7 +#define STATUS_SCAN_ABORTING 8 +#define STATUS_SCAN_HW 9 +#define STATUS_FW_ERROR 10 +#define STATUS_CHANNEL_SWITCH_PENDING 11 +#define STATUS_SCAN_COMPLETE 12 +#define STATUS_POWER_PMI 13 struct iwl_ucode_capabilities; @@ -80,12 +117,9 @@ static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd) void iwl_down(struct iwl_priv *priv); void iwl_cancel_deferred_work(struct iwl_priv *priv); void iwlagn_prepare_restart(struct iwl_priv *priv); -void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb); int __must_check iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd); -void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state); -void iwl_nic_error(struct iwl_op_mode *op_mode); bool iwl_check_for_ct_kill(struct iwl_priv *priv); @@ -103,6 +137,8 @@ int iwl_dvm_send_cmd_pdu(struct iwl_priv *priv, u8 id, u32 flags, u16 len, const void *data); /* RXON */ +void iwl_connection_init_rx_config(struct iwl_priv *priv, + struct iwl_rxon_context *ctx); int iwlagn_set_pan_params(struct iwl_priv *priv); int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx); void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx); @@ -113,11 +149,15 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, u32 changes); void iwlagn_config_ht40(struct ieee80211_conf *conf, struct iwl_rxon_context *ctx); +void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf); +void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch, + struct iwl_rxon_context *ctx); +void iwl_set_flags_for_band(struct iwl_priv *priv, + struct iwl_rxon_context *ctx, + enum ieee80211_band band, + struct ieee80211_vif *vif); /* uCode */ -int iwlagn_rx_calib_result(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); int iwl_send_bt_env(struct iwl_priv *priv, u8 action, u8 type); void iwl_send_prio_tbl(struct iwl_priv *priv); int iwl_init_alive_start(struct iwl_priv *priv); @@ -128,14 +168,25 @@ int iwl_send_calib_results(struct iwl_priv *priv); int iwl_calib_set(struct iwl_priv *priv, const struct iwl_calib_hdr *cmd, int len); void iwl_calib_free_results(struct iwl_priv *priv); +int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, + char **buf, bool display); +int iwlagn_hw_valid_rtc_data_addr(u32 addr); /* lib */ int iwlagn_send_tx_power(struct iwl_priv *priv); void iwlagn_temperature(struct iwl_priv *priv); -u16 iwl_eeprom_calib_version(struct iwl_shared *shrd); int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control); void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control); int iwlagn_send_beacon_cmd(struct iwl_priv *priv); +int iwl_send_statistics_request(struct iwl_priv *priv, + u8 flags, bool clear); + +static inline const struct ieee80211_supported_band *iwl_get_hw_mode( + struct iwl_priv *priv, enum ieee80211_band band) +{ + return priv->hw->wiphy->bands[band]; +} + #ifdef CONFIG_PM_SLEEP int iwlagn_send_patterns(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan); @@ -145,6 +196,7 @@ int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan); /* rx */ int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band); void iwl_setup_rx_handlers(struct iwl_priv *priv); +void iwl_chswitch_done(struct iwl_priv *priv, bool is_success); /* tx */ @@ -189,6 +241,31 @@ u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx, u8 valid); /* scan */ void iwlagn_post_scan(struct iwl_priv *priv); void iwlagn_disable_roc(struct iwl_priv *priv); +int iwl_force_rf_reset(struct iwl_priv *priv, bool external); +void iwl_init_scan_params(struct iwl_priv *priv); +int iwl_scan_cancel(struct iwl_priv *priv); +void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms); +void iwl_force_scan_end(struct iwl_priv *priv); +void iwl_internal_short_hw_scan(struct iwl_priv *priv); +void iwl_setup_rx_scan_handlers(struct iwl_priv *priv); +void iwl_setup_scan_deferred_work(struct iwl_priv *priv); +void iwl_cancel_scan_deferred_work(struct iwl_priv *priv); +int __must_check iwl_scan_initiate(struct iwl_priv *priv, + struct ieee80211_vif *vif, + enum iwl_scan_type scan_type, + enum ieee80211_band band); + +/* For faster active scanning, scan will move to the next channel if fewer than + * PLCP_QUIET_THRESH packets are heard on this channel within + * ACTIVE_QUIET_TIME after sending probe request. This shortens the dwell + * time if it's a quiet channel (nothing responded to our probe, and there's + * no other traffic). + * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */ +#define IWL_ACTIVE_QUIET_TIME cpu_to_le16(10) /* msec */ +#define IWL_PLCP_QUIET_THRESH cpu_to_le16(1) /* packets */ + +#define IWL_SCAN_CHECK_WATCHDOG (HZ * 7) + /* bt coex */ void iwlagn_send_advance_bt_config(struct iwl_priv *priv); @@ -201,6 +278,12 @@ void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv); void iwlagn_bt_coex_rssi_monitor(struct iwl_priv *priv); void iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena); +static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv) +{ + return priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist; +} + #ifdef CONFIG_IWLWIFI_DEBUG const char *iwl_get_tx_fail_reason(u32 status); const char *iwl_get_agg_tx_fail_reason(u16 status); @@ -239,8 +322,6 @@ void iwl_deactivate_station(struct iwl_priv *priv, const u8 sta_id, u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, const u8 *addr, bool is_ap, struct ieee80211_sta *sta); -void iwl_sta_fill_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, - u8 sta_id, struct iwl_link_quality_cmd *link_cmd); int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx, struct iwl_link_quality_cmd *lq, u8 flags, bool init); int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, @@ -248,6 +329,9 @@ int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, int iwl_sta_update_ht(struct iwl_priv *priv, struct iwl_rxon_context *ctx, struct ieee80211_sta *sta); +bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, + struct iwl_rxon_context *ctx, + struct ieee80211_sta_ht_cap *ht_cap); static inline int iwl_sta_id(struct ieee80211_sta *sta) { @@ -305,9 +389,6 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags) return cpu_to_le32(flags|(u32)rate); } -/* eeprom */ -void iwl_eeprom_get_mac(const struct iwl_shared *shrd, u8 *mac); - extern int iwl_alive_start(struct iwl_priv *priv); /* svtool */ #ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE @@ -386,13 +467,35 @@ static inline int iwl_is_ready_rf(struct iwl_priv *priv) return iwl_is_ready(priv); } +static inline void iwl_dvm_set_pmi(struct iwl_priv *priv, bool state) +{ + if (state) + set_bit(STATUS_POWER_PMI, &priv->status); + else + clear_bit(STATUS_POWER_PMI, &priv->status); + iwl_trans_set_pmi(priv->trans, state); +} + +#ifdef CONFIG_IWLWIFI_DEBUGFS +int iwl_dbgfs_register(struct iwl_priv *priv, const char *name); +void iwl_dbgfs_unregister(struct iwl_priv *priv); +#else +static inline int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) +{ + return 0; +} +static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) +{ +} +#endif /* CONFIG_IWLWIFI_DEBUGFS */ + #ifdef CONFIG_IWLWIFI_DEBUG #define IWL_DEBUG_QUIET_RFKILL(m, fmt, args...) \ do { \ if (!iwl_is_rfkill((m))) \ IWL_ERR(m, fmt, ##args); \ else \ - __iwl_err(trans(m)->dev, true, \ + __iwl_err((m)->dev, true, \ !iwl_have_debug_level(IWL_DL_RADIO), \ fmt, ##args); \ } while (0) @@ -402,8 +505,98 @@ do { \ if (!iwl_is_rfkill((m))) \ IWL_ERR(m, fmt, ##args); \ else \ - __iwl_err(trans(m)->dev, true, true, fmt, ##args); \ + __iwl_err((m)->dev, true, true, fmt, ##args); \ } while (0) #endif /* CONFIG_IWLWIFI_DEBUG */ +extern const char *iwl_dvm_cmd_strings[REPLY_MAX]; + +static inline const char *iwl_dvm_get_cmd_string(u8 cmd) +{ + const char *s = iwl_dvm_cmd_strings[cmd]; + if (s) + return s; + return "UNKNOWN"; +} + +/* API method exported for mvm hybrid state */ +void iwl_setup_deferred_work(struct iwl_priv *priv); +int iwl_send_wimax_coex(struct iwl_priv *priv); +int iwl_send_bt_env(struct iwl_priv *priv, u8 action, u8 type); +void iwl_option_config(struct iwl_priv *priv); +void iwl_set_hw_params(struct iwl_priv *priv); +void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags); +int iwl_init_drv(struct iwl_priv *priv); +void iwl_uninit_drv(struct iwl_priv *priv); +void iwl_send_bt_config(struct iwl_priv *priv); +void iwl_rf_kill_ct_config(struct iwl_priv *priv); +int iwl_setup_interface(struct iwl_priv *priv, struct iwl_rxon_context *ctx); +void iwl_teardown_interface(struct iwl_priv *priv, + struct ieee80211_vif *vif, + bool mode_change); +int iwl_full_rxon_required(struct iwl_priv *priv, struct iwl_rxon_context *ctx); +void iwlagn_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx); +void iwlagn_check_needed_chains(struct iwl_priv *priv, + struct iwl_rxon_context *ctx, + struct ieee80211_bss_conf *bss_conf); +void iwlagn_chain_noise_reset(struct iwl_priv *priv); +int iwlagn_update_beacon(struct iwl_priv *priv, + struct ieee80211_vif *vif); +void iwl_tt_handler(struct iwl_priv *priv); +void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode); +void iwl_stop_sw_queue(struct iwl_op_mode *op_mode, int queue); +void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state); +void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb); +void iwl_nic_error(struct iwl_op_mode *op_mode); +void iwl_cmd_queue_full(struct iwl_op_mode *op_mode); +void iwl_nic_config(struct iwl_op_mode *op_mode); +int iwlagn_mac_set_tim(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, bool set); +void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw, + enum ieee80211_rssi_event rssi_event); +int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw); +int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw); +void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop); +void iwl_wake_sw_queue(struct iwl_op_mode *op_mode, int queue); +void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, + struct ieee80211_channel_switch *ch_switch); +int iwlagn_mac_sta_state(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + enum ieee80211_sta_state old_state, + enum ieee80211_sta_state new_state); +int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, u16 tid, u16 *ssn, + u8 buf_size); +int iwlagn_mac_hw_scan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_scan_request *req); +void iwlagn_mac_sta_notify(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, + struct ieee80211_sta *sta); +void iwlagn_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 multicast); +int iwlagn_mac_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, + const struct ieee80211_tx_queue_params *params); +void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_gtk_rekey_data *data); +void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_key_conf *keyconf, + struct ieee80211_sta *sta, + u32 iv32, u16 *phase1key); +int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key); +void iwlagn_mac_stop(struct ieee80211_hw *hw); +void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb); +int iwlagn_mac_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan); #endif /* __iwl_agn_h__ */ diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-commands.h b/trunk/drivers/net/wireless/iwlwifi/iwl-commands.h index 9ed73e5154be..83a6930f3658 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -1877,9 +1877,16 @@ struct iwl_bt_cmd { #define IWLAGN_BT3_T7_DEFAULT 1 +enum iwl_bt_kill_idx { + IWL_BT_KILL_DEFAULT = 0, + IWL_BT_KILL_OVERRIDE = 1, + IWL_BT_KILL_REDUCE = 2, +}; + #define IWLAGN_BT_KILL_ACK_MASK_DEFAULT cpu_to_le32(0xffff0000) #define IWLAGN_BT_KILL_CTS_MASK_DEFAULT cpu_to_le32(0xffff0000) #define IWLAGN_BT_KILL_ACK_CTS_MASK_SCO cpu_to_le32(0xffffffff) +#define IWLAGN_BT_KILL_ACK_CTS_MASK_REDUCE cpu_to_le32(0) #define IWLAGN_BT3_PRIO_SAMPLE_DEFAULT 2 @@ -1891,7 +1898,7 @@ struct iwl_bt_cmd { #define IWLAGN_BT_VALID_3W_TIMERS cpu_to_le16(BIT(3)) #define IWLAGN_BT_VALID_KILL_ACK_MASK cpu_to_le16(BIT(4)) #define IWLAGN_BT_VALID_KILL_CTS_MASK cpu_to_le16(BIT(5)) -#define IWLAGN_BT_VALID_BT4_TIMES cpu_to_le16(BIT(6)) +#define IWLAGN_BT_VALID_REDUCED_TX_PWR cpu_to_le16(BIT(6)) #define IWLAGN_BT_VALID_3W_LUT cpu_to_le16(BIT(7)) #define IWLAGN_BT_ALL_VALID_MSK (IWLAGN_BT_VALID_ENABLE_FLAGS | \ @@ -1900,9 +1907,11 @@ struct iwl_bt_cmd { IWLAGN_BT_VALID_3W_TIMERS | \ IWLAGN_BT_VALID_KILL_ACK_MASK | \ IWLAGN_BT_VALID_KILL_CTS_MASK | \ - IWLAGN_BT_VALID_BT4_TIMES | \ + IWLAGN_BT_VALID_REDUCED_TX_PWR | \ IWLAGN_BT_VALID_3W_LUT) +#define IWLAGN_BT_DECISION_LUT_SIZE 12 + struct iwl_basic_bt_cmd { u8 flags; u8 ledtime; /* unused */ @@ -1913,12 +1922,13 @@ struct iwl_basic_bt_cmd { u8 bt3_prio_sample_time; u8 bt3_timer_t2_value; __le16 bt4_reaction_time; /* unused */ - __le32 bt3_lookup_table[12]; - __le16 bt4_decision_time; /* unused */ + __le32 bt3_lookup_table[IWLAGN_BT_DECISION_LUT_SIZE]; + u8 reduce_txpower; + u8 reserved; __le16 valid; }; -struct iwl6000_bt_cmd { +struct iwl_bt_cmd_v1 { struct iwl_basic_bt_cmd basic; u8 prio_boost; /* @@ -1929,7 +1939,7 @@ struct iwl6000_bt_cmd { __le16 rx_prio_boost; /* SW boost of WiFi rx priority */ }; -struct iwl2000_bt_cmd { +struct iwl_bt_cmd_v2 { struct iwl_basic_bt_cmd basic; __le32 prio_boost; /* @@ -3634,6 +3644,9 @@ enum iwl_bt_coex_profile_traffic_load { (0x3< + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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. + * + *****************************************************************************/ +#ifndef __IWL_CONFIG_H__ +#define __IWL_CONFIG_H__ + +#include +#include + + +enum iwl_device_family { + IWL_DEVICE_FAMILY_UNDEFINED, + IWL_DEVICE_FAMILY_1000, + IWL_DEVICE_FAMILY_100, + IWL_DEVICE_FAMILY_2000, + IWL_DEVICE_FAMILY_2030, + IWL_DEVICE_FAMILY_105, + IWL_DEVICE_FAMILY_135, + IWL_DEVICE_FAMILY_5000, + IWL_DEVICE_FAMILY_5150, + IWL_DEVICE_FAMILY_6000, + IWL_DEVICE_FAMILY_6000i, + IWL_DEVICE_FAMILY_6005, + IWL_DEVICE_FAMILY_6030, + IWL_DEVICE_FAMILY_6050, + IWL_DEVICE_FAMILY_6150, +}; + +/* + * LED mode + * IWL_LED_DEFAULT: use device default + * IWL_LED_RF_STATE: turn LED on/off based on RF state + * LED ON = RF ON + * LED OFF = RF OFF + * IWL_LED_BLINK: adjust led blink rate based on blink table + * IWL_LED_DISABLE: led disabled + */ +enum iwl_led_mode { + IWL_LED_DEFAULT, + IWL_LED_RF_STATE, + IWL_LED_BLINK, + IWL_LED_DISABLE, +}; + +/* + * This is the threshold value of plcp error rate per 100mSecs. It is + * used to set and check for the validity of plcp_delta. + */ +#define IWL_MAX_PLCP_ERR_THRESHOLD_MIN 1 +#define IWL_MAX_PLCP_ERR_THRESHOLD_DEF 50 +#define IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF 100 +#define IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF 200 +#define IWL_MAX_PLCP_ERR_THRESHOLD_MAX 255 +#define IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE 0 + +/* TX queue watchdog timeouts in mSecs */ +#define IWL_WATCHHDOG_DISABLED 0 +#define IWL_DEF_WD_TIMEOUT 2000 +#define IWL_LONG_WD_TIMEOUT 10000 +#define IWL_MAX_WD_TIMEOUT 120000 + +/* Antenna presence definitions */ +#define ANT_NONE 0x0 +#define ANT_A BIT(0) +#define ANT_B BIT(1) +#define ANT_C BIT(2) +#define ANT_AB (ANT_A | ANT_B) +#define ANT_AC (ANT_A | ANT_C) +#define ANT_BC (ANT_B | ANT_C) +#define ANT_ABC (ANT_A | ANT_B | ANT_C) + + +/* + * @max_ll_items: max number of OTP blocks + * @shadow_ram_support: shadow support for OTP memory + * @led_compensation: compensate on the led on/off time per HW according + * to the deviation to achieve the desired led frequency. + * The detail algorithm is described in iwl-led.c + * @chain_noise_num_beacons: number of beacons used to compute chain noise + * @adv_thermal_throttle: support advance thermal throttle + * @support_ct_kill_exit: support ct kill exit condition + * @plcp_delta_threshold: plcp error rate threshold used to trigger + * radio tuning when there is a high receiving plcp error rate + * @chain_noise_scale: default chain noise scale used for gain computation + * @wd_timeout: TX queues watchdog timeout + * @max_event_log_size: size of event log buffer size for ucode event logging + * @shadow_reg_enable: HW shadhow register bit + * @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up + * @no_idle_support: do not support idle mode + */ +struct iwl_base_params { + int eeprom_size; + int num_of_queues; /* def: HW dependent */ + /* for iwl_apm_init() */ + u32 pll_cfg_val; + + const u16 max_ll_items; + const bool shadow_ram_support; + u16 led_compensation; + bool adv_thermal_throttle; + bool support_ct_kill_exit; + u8 plcp_delta_threshold; + s32 chain_noise_scale; + unsigned int wd_timeout; + u32 max_event_log_size; + const bool shadow_reg_enable; + const bool hd_v2; + const bool no_idle_support; +}; + +/* + * @advanced_bt_coexist: support advanced bt coexist + * @bt_init_traffic_load: specify initial bt traffic load + * @bt_prio_boost: default bt priority boost value + * @agg_time_limit: maximum number of uSec in aggregation + * @bt_sco_disable: uCode should not response to BT in SCO/ESCO mode + */ +struct iwl_bt_params { + bool advanced_bt_coexist; + u8 bt_init_traffic_load; + u8 bt_prio_boost; + u16 agg_time_limit; + bool bt_sco_disable; + bool bt_session_2; +}; +/* + * @use_rts_for_aggregation: use rts/cts protection for HT traffic + */ +struct iwl_ht_params { + const bool ht_greenfield_support; /* if used set to true */ + bool use_rts_for_aggregation; + enum ieee80211_smps_mode smps_mode; +}; + +/** + * struct iwl_cfg + * @name: Offical name of the device + * @fw_name_pre: Firmware filename prefix. The api version and extension + * (.ucode) will be added to filename before loading from disk. The + * filename is constructed as fw_name_pre.ucode. + * @ucode_api_max: Highest version of uCode API supported by driver. + * @ucode_api_ok: oldest version of the uCode API that is OK to load + * without a warning, for use in transitions + * @ucode_api_min: Lowest version of uCode API supported by driver. + * @max_inst_size: The maximal length of the fw inst section + * @max_data_size: The maximal length of the fw data section + * @valid_tx_ant: valid transmit antenna + * @valid_rx_ant: valid receive antenna + * @eeprom_ver: EEPROM version + * @eeprom_calib_ver: EEPROM calibration version + * @lib: pointer to the lib ops + * @base_params: pointer to basic parameters + * @ht_params: point to ht patameters + * @bt_params: pointer to bt parameters + * @need_temp_offset_calib: need to perform temperature offset calibration + * @no_xtal_calib: some devices do not need crystal calibration data, + * don't send it to those + * @led_mode: 0=blinking, 1=On(RF On)/Off(RF Off) + * @adv_pm: advance power management + * @rx_with_siso_diversity: 1x1 device with rx antenna diversity + * @internal_wimax_coex: internal wifi/wimax combo device + * @temp_offset_v2: support v2 of temperature offset calibration + * + * We enable the driver to be backward compatible wrt. hardware features. + * API differences in uCode shouldn't be handled here but through TLVs + * and/or the uCode API version instead. + */ +struct iwl_cfg { + /* params specific to an individual device within a device family */ + const char *name; + const char *fw_name_pre; + const unsigned int ucode_api_max; + const unsigned int ucode_api_ok; + const unsigned int ucode_api_min; + const enum iwl_device_family device_family; + const u32 max_data_size; + const u32 max_inst_size; + u8 valid_tx_ant; + u8 valid_rx_ant; + u16 eeprom_ver; + u16 eeprom_calib_ver; + /* params not likely to change within a device family */ + const struct iwl_base_params *base_params; + /* params likely to change within a device family */ + const struct iwl_ht_params *ht_params; + const struct iwl_bt_params *bt_params; + const bool need_temp_offset_calib; /* if used set to true */ + const bool no_xtal_calib; + enum iwl_led_mode led_mode; + const bool adv_pm; + const bool rx_with_siso_diversity; + const bool internal_wimax_coex; + const bool temp_offset_v2; +}; + +#endif /* __IWL_CONFIG_H__ */ diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-core.c b/trunk/drivers/net/wireless/iwlwifi/iwl-core.c deleted file mode 100644 index 46490d3b95b9..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-core.c +++ /dev/null @@ -1,1480 +0,0 @@ -/****************************************************************************** - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2012 Intel 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 - * - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - *****************************************************************************/ - -#include -#include -#include -#include -#include -#include - -#include "iwl-eeprom.h" -#include "iwl-debug.h" -#include "iwl-core.h" -#include "iwl-io.h" -#include "iwl-power.h" -#include "iwl-shared.h" -#include "iwl-agn.h" -#include "iwl-trans.h" - -const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - -#define MAX_BIT_RATE_40_MHZ 150 /* Mbps */ -#define MAX_BIT_RATE_20_MHZ 72 /* Mbps */ -static void iwl_init_ht_hw_capab(const struct iwl_priv *priv, - struct ieee80211_sta_ht_cap *ht_info, - enum ieee80211_band band) -{ - u16 max_bit_rate = 0; - u8 rx_chains_num = hw_params(priv).rx_chains_num; - u8 tx_chains_num = hw_params(priv).tx_chains_num; - - ht_info->cap = 0; - memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); - - ht_info->ht_supported = true; - - if (cfg(priv)->ht_params && - cfg(priv)->ht_params->ht_greenfield_support) - ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; - ht_info->cap |= IEEE80211_HT_CAP_SGI_20; - max_bit_rate = MAX_BIT_RATE_20_MHZ; - if (hw_params(priv).ht40_channel & BIT(band)) { - ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; - ht_info->cap |= IEEE80211_HT_CAP_SGI_40; - ht_info->mcs.rx_mask[4] = 0x01; - max_bit_rate = MAX_BIT_RATE_40_MHZ; - } - - if (iwlagn_mod_params.amsdu_size_8K) - ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; - - ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF; - ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF; - - ht_info->mcs.rx_mask[0] = 0xFF; - if (rx_chains_num >= 2) - ht_info->mcs.rx_mask[1] = 0xFF; - if (rx_chains_num >= 3) - ht_info->mcs.rx_mask[2] = 0xFF; - - /* Highest supported Rx data rate */ - max_bit_rate *= rx_chains_num; - WARN_ON(max_bit_rate & ~IEEE80211_HT_MCS_RX_HIGHEST_MASK); - ht_info->mcs.rx_highest = cpu_to_le16(max_bit_rate); - - /* Tx MCS capabilities */ - ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; - if (tx_chains_num != rx_chains_num) { - ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; - ht_info->mcs.tx_params |= ((tx_chains_num - 1) << - IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); - } -} - -/** - * iwl_init_geos - Initialize mac80211's geo/channel info based from eeprom - */ -int iwl_init_geos(struct iwl_priv *priv) -{ - struct iwl_channel_info *ch; - struct ieee80211_supported_band *sband; - struct ieee80211_channel *channels; - struct ieee80211_channel *geo_ch; - struct ieee80211_rate *rates; - int i = 0; - s8 max_tx_power = IWLAGN_TX_POWER_TARGET_POWER_MIN; - - if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates || - priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) { - IWL_DEBUG_INFO(priv, "Geography modes already initialized.\n"); - set_bit(STATUS_GEO_CONFIGURED, &priv->status); - return 0; - } - - channels = kcalloc(priv->channel_count, - sizeof(struct ieee80211_channel), GFP_KERNEL); - if (!channels) - return -ENOMEM; - - rates = kcalloc(IWL_RATE_COUNT_LEGACY, sizeof(struct ieee80211_rate), - GFP_KERNEL); - if (!rates) { - kfree(channels); - return -ENOMEM; - } - - /* 5.2GHz channels start after the 2.4GHz channels */ - sband = &priv->bands[IEEE80211_BAND_5GHZ]; - sband->channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)]; - /* just OFDM */ - sband->bitrates = &rates[IWL_FIRST_OFDM_RATE]; - sband->n_bitrates = IWL_RATE_COUNT_LEGACY - IWL_FIRST_OFDM_RATE; - - if (hw_params(priv).sku & EEPROM_SKU_CAP_11N_ENABLE) - iwl_init_ht_hw_capab(priv, &sband->ht_cap, - IEEE80211_BAND_5GHZ); - - sband = &priv->bands[IEEE80211_BAND_2GHZ]; - sband->channels = channels; - /* OFDM & CCK */ - sband->bitrates = rates; - sband->n_bitrates = IWL_RATE_COUNT_LEGACY; - - if (hw_params(priv).sku & EEPROM_SKU_CAP_11N_ENABLE) - iwl_init_ht_hw_capab(priv, &sband->ht_cap, - IEEE80211_BAND_2GHZ); - - priv->ieee_channels = channels; - priv->ieee_rates = rates; - - for (i = 0; i < priv->channel_count; i++) { - ch = &priv->channel_info[i]; - - /* FIXME: might be removed if scan is OK */ - if (!is_channel_valid(ch)) - continue; - - sband = &priv->bands[ch->band]; - - geo_ch = &sband->channels[sband->n_channels++]; - - geo_ch->center_freq = - ieee80211_channel_to_frequency(ch->channel, ch->band); - geo_ch->max_power = ch->max_power_avg; - geo_ch->max_antenna_gain = 0xff; - geo_ch->hw_value = ch->channel; - - if (is_channel_valid(ch)) { - if (!(ch->flags & EEPROM_CHANNEL_IBSS)) - geo_ch->flags |= IEEE80211_CHAN_NO_IBSS; - - if (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) - geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN; - - if (ch->flags & EEPROM_CHANNEL_RADAR) - geo_ch->flags |= IEEE80211_CHAN_RADAR; - - geo_ch->flags |= ch->ht40_extension_channel; - - if (ch->max_power_avg > max_tx_power) - max_tx_power = ch->max_power_avg; - } else { - geo_ch->flags |= IEEE80211_CHAN_DISABLED; - } - - IWL_DEBUG_INFO(priv, "Channel %d Freq=%d[%sGHz] %s flag=0x%X\n", - ch->channel, geo_ch->center_freq, - is_channel_a_band(ch) ? "5.2" : "2.4", - geo_ch->flags & IEEE80211_CHAN_DISABLED ? - "restricted" : "valid", - geo_ch->flags); - } - - priv->tx_power_device_lmt = max_tx_power; - priv->tx_power_user_lmt = max_tx_power; - priv->tx_power_next = max_tx_power; - - if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) && - hw_params(priv).sku & EEPROM_SKU_CAP_BAND_52GHZ) { - IWL_INFO(priv, "Incorrectly detected BG card as ABG. " - "Please send your %s to maintainer.\n", - trans(priv)->hw_id_str); - hw_params(priv).sku &= ~EEPROM_SKU_CAP_BAND_52GHZ; - } - - IWL_INFO(priv, "Tunable channels: %d 802.11bg, %d 802.11a channels\n", - priv->bands[IEEE80211_BAND_2GHZ].n_channels, - priv->bands[IEEE80211_BAND_5GHZ].n_channels); - - set_bit(STATUS_GEO_CONFIGURED, &priv->status); - - return 0; -} - -/* - * iwl_free_geos - undo allocations in iwl_init_geos - */ -void iwl_free_geos(struct iwl_priv *priv) -{ - kfree(priv->ieee_channels); - kfree(priv->ieee_rates); - clear_bit(STATUS_GEO_CONFIGURED, &priv->status); -} - -static bool iwl_is_channel_extension(struct iwl_priv *priv, - enum ieee80211_band band, - u16 channel, u8 extension_chan_offset) -{ - const struct iwl_channel_info *ch_info; - - ch_info = iwl_get_channel_info(priv, band, channel); - if (!is_channel_valid(ch_info)) - return false; - - if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) - return !(ch_info->ht40_extension_channel & - IEEE80211_CHAN_NO_HT40PLUS); - else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) - return !(ch_info->ht40_extension_channel & - IEEE80211_CHAN_NO_HT40MINUS); - - return false; -} - -bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, - struct iwl_rxon_context *ctx, - struct ieee80211_sta_ht_cap *ht_cap) -{ - if (!ctx->ht.enabled || !ctx->ht.is_40mhz) - return false; - - /* - * We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40 - * the bit will not set if it is pure 40MHz case - */ - if (ht_cap && !ht_cap->ht_supported) - return false; - -#ifdef CONFIG_IWLWIFI_DEBUGFS - if (priv->disable_ht40) - return false; -#endif - - return iwl_is_channel_extension(priv, priv->band, - le16_to_cpu(ctx->staging.channel), - ctx->ht.extension_chan_offset); -} - -static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val) -{ - u16 new_val; - u16 beacon_factor; - - /* - * If mac80211 hasn't given us a beacon interval, program - * the default into the device (not checking this here - * would cause the adjustment below to return the maximum - * value, which may break PAN.) - */ - if (!beacon_val) - return DEFAULT_BEACON_INTERVAL; - - /* - * If the beacon interval we obtained from the peer - * is too large, we'll have to wake up more often - * (and in IBSS case, we'll beacon too much) - * - * For example, if max_beacon_val is 4096, and the - * requested beacon interval is 7000, we'll have to - * use 3500 to be able to wake up on the beacons. - * - * This could badly influence beacon detection stats. - */ - - beacon_factor = (beacon_val + max_beacon_val) / max_beacon_val; - new_val = beacon_val / beacon_factor; - - if (!new_val) - new_val = max_beacon_val; - - return new_val; -} - -int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx) -{ - u64 tsf; - s32 interval_tm, rem; - struct ieee80211_conf *conf = NULL; - u16 beacon_int; - struct ieee80211_vif *vif = ctx->vif; - - conf = &priv->hw->conf; - - lockdep_assert_held(&priv->mutex); - - memset(&ctx->timing, 0, sizeof(struct iwl_rxon_time_cmd)); - - ctx->timing.timestamp = cpu_to_le64(priv->timestamp); - ctx->timing.listen_interval = cpu_to_le16(conf->listen_interval); - - beacon_int = vif ? vif->bss_conf.beacon_int : 0; - - /* - * TODO: For IBSS we need to get atim_window from mac80211, - * for now just always use 0 - */ - ctx->timing.atim_window = 0; - - if (ctx->ctxid == IWL_RXON_CTX_PAN && - (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION) && - iwl_is_associated(priv, IWL_RXON_CTX_BSS) && - priv->contexts[IWL_RXON_CTX_BSS].vif && - priv->contexts[IWL_RXON_CTX_BSS].vif->bss_conf.beacon_int) { - ctx->timing.beacon_interval = - priv->contexts[IWL_RXON_CTX_BSS].timing.beacon_interval; - beacon_int = le16_to_cpu(ctx->timing.beacon_interval); - } else if (ctx->ctxid == IWL_RXON_CTX_BSS && - iwl_is_associated(priv, IWL_RXON_CTX_PAN) && - priv->contexts[IWL_RXON_CTX_PAN].vif && - priv->contexts[IWL_RXON_CTX_PAN].vif->bss_conf.beacon_int && - (!iwl_is_associated_ctx(ctx) || !ctx->vif || - !ctx->vif->bss_conf.beacon_int)) { - ctx->timing.beacon_interval = - priv->contexts[IWL_RXON_CTX_PAN].timing.beacon_interval; - beacon_int = le16_to_cpu(ctx->timing.beacon_interval); - } else { - beacon_int = iwl_adjust_beacon_interval(beacon_int, - IWL_MAX_UCODE_BEACON_INTERVAL * TIME_UNIT); - ctx->timing.beacon_interval = cpu_to_le16(beacon_int); - } - - ctx->beacon_int = beacon_int; - - tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */ - interval_tm = beacon_int * TIME_UNIT; - rem = do_div(tsf, interval_tm); - ctx->timing.beacon_init_val = cpu_to_le32(interval_tm - rem); - - ctx->timing.dtim_period = vif ? (vif->bss_conf.dtim_period ?: 1) : 1; - - IWL_DEBUG_ASSOC(priv, - "beacon interval %d beacon timer %d beacon tim %d\n", - le16_to_cpu(ctx->timing.beacon_interval), - le32_to_cpu(ctx->timing.beacon_init_val), - le16_to_cpu(ctx->timing.atim_window)); - - return iwl_dvm_send_cmd_pdu(priv, ctx->rxon_timing_cmd, - CMD_SYNC, sizeof(ctx->timing), &ctx->timing); -} - -void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx, - int hw_decrypt) -{ - struct iwl_rxon_cmd *rxon = &ctx->staging; - - if (hw_decrypt) - rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK; - else - rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK; - -} - -/* validate RXON structure is valid */ -int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx) -{ - struct iwl_rxon_cmd *rxon = &ctx->staging; - u32 errors = 0; - - if (rxon->flags & RXON_FLG_BAND_24G_MSK) { - if (rxon->flags & RXON_FLG_TGJ_NARROW_BAND_MSK) { - IWL_WARN(priv, "check 2.4G: wrong narrow\n"); - errors |= BIT(0); - } - if (rxon->flags & RXON_FLG_RADAR_DETECT_MSK) { - IWL_WARN(priv, "check 2.4G: wrong radar\n"); - errors |= BIT(1); - } - } else { - if (!(rxon->flags & RXON_FLG_SHORT_SLOT_MSK)) { - IWL_WARN(priv, "check 5.2G: not short slot!\n"); - errors |= BIT(2); - } - if (rxon->flags & RXON_FLG_CCK_MSK) { - IWL_WARN(priv, "check 5.2G: CCK!\n"); - errors |= BIT(3); - } - } - if ((rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1) { - IWL_WARN(priv, "mac/bssid mcast!\n"); - errors |= BIT(4); - } - - /* make sure basic rates 6Mbps and 1Mbps are supported */ - if ((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0 && - (rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0) { - IWL_WARN(priv, "neither 1 nor 6 are basic\n"); - errors |= BIT(5); - } - - if (le16_to_cpu(rxon->assoc_id) > 2007) { - IWL_WARN(priv, "aid > 2007\n"); - errors |= BIT(6); - } - - if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) - == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) { - IWL_WARN(priv, "CCK and short slot\n"); - errors |= BIT(7); - } - - if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) - == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) { - IWL_WARN(priv, "CCK and auto detect"); - errors |= BIT(8); - } - - if ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK | - RXON_FLG_TGG_PROTECT_MSK)) == - RXON_FLG_TGG_PROTECT_MSK) { - IWL_WARN(priv, "TGg but no auto-detect\n"); - errors |= BIT(9); - } - - if (rxon->channel == 0) { - IWL_WARN(priv, "zero channel is invalid\n"); - errors |= BIT(10); - } - - WARN(errors, "Invalid RXON (%#x), channel %d", - errors, le16_to_cpu(rxon->channel)); - - return errors ? -EINVAL : 0; -} - -/** - * iwl_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed - * @priv: staging_rxon is compared to active_rxon - * - * If the RXON structure is changing enough to require a new tune, - * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that - * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required. - */ -int iwl_full_rxon_required(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) -{ - const struct iwl_rxon_cmd *staging = &ctx->staging; - const struct iwl_rxon_cmd *active = &ctx->active; - -#define CHK(cond) \ - if ((cond)) { \ - IWL_DEBUG_INFO(priv, "need full RXON - " #cond "\n"); \ - return 1; \ - } - -#define CHK_NEQ(c1, c2) \ - if ((c1) != (c2)) { \ - IWL_DEBUG_INFO(priv, "need full RXON - " \ - #c1 " != " #c2 " - %d != %d\n", \ - (c1), (c2)); \ - return 1; \ - } - - /* These items are only settable from the full RXON command */ - CHK(!iwl_is_associated_ctx(ctx)); - CHK(compare_ether_addr(staging->bssid_addr, active->bssid_addr)); - CHK(compare_ether_addr(staging->node_addr, active->node_addr)); - CHK(compare_ether_addr(staging->wlap_bssid_addr, - active->wlap_bssid_addr)); - CHK_NEQ(staging->dev_type, active->dev_type); - CHK_NEQ(staging->channel, active->channel); - CHK_NEQ(staging->air_propagation, active->air_propagation); - CHK_NEQ(staging->ofdm_ht_single_stream_basic_rates, - active->ofdm_ht_single_stream_basic_rates); - CHK_NEQ(staging->ofdm_ht_dual_stream_basic_rates, - active->ofdm_ht_dual_stream_basic_rates); - CHK_NEQ(staging->ofdm_ht_triple_stream_basic_rates, - active->ofdm_ht_triple_stream_basic_rates); - CHK_NEQ(staging->assoc_id, active->assoc_id); - - /* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can - * be updated with the RXON_ASSOC command -- however only some - * flag transitions are allowed using RXON_ASSOC */ - - /* Check if we are not switching bands */ - CHK_NEQ(staging->flags & RXON_FLG_BAND_24G_MSK, - active->flags & RXON_FLG_BAND_24G_MSK); - - /* Check if we are switching association toggle */ - CHK_NEQ(staging->filter_flags & RXON_FILTER_ASSOC_MSK, - active->filter_flags & RXON_FILTER_ASSOC_MSK); - -#undef CHK -#undef CHK_NEQ - - return 0; -} - -static void _iwl_set_rxon_ht(struct iwl_priv *priv, - struct iwl_ht_config *ht_conf, - struct iwl_rxon_context *ctx) -{ - struct iwl_rxon_cmd *rxon = &ctx->staging; - - if (!ctx->ht.enabled) { - rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | - RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | - RXON_FLG_HT40_PROT_MSK | - RXON_FLG_HT_PROT_MSK); - return; - } - - /* FIXME: if the definition of ht.protection changed, the "translation" - * will be needed for rxon->flags - */ - rxon->flags |= cpu_to_le32(ctx->ht.protection << RXON_FLG_HT_OPERATING_MODE_POS); - - /* Set up channel bandwidth: - * 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */ - /* clear the HT channel mode before set the mode */ - rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | - RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); - if (iwl_is_ht40_tx_allowed(priv, ctx, NULL)) { - /* pure ht40 */ - if (ctx->ht.protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) { - rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40; - /* Note: control channel is opposite of extension channel */ - switch (ctx->ht.extension_chan_offset) { - case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: - rxon->flags &= ~RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; - break; - case IEEE80211_HT_PARAM_CHA_SEC_BELOW: - rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; - break; - } - } else { - /* Note: control channel is opposite of extension channel */ - switch (ctx->ht.extension_chan_offset) { - case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: - rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); - rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED; - break; - case IEEE80211_HT_PARAM_CHA_SEC_BELOW: - rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; - rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED; - break; - case IEEE80211_HT_PARAM_CHA_SEC_NONE: - default: - /* channel location only valid if in Mixed mode */ - IWL_ERR(priv, "invalid extension channel offset\n"); - break; - } - } - } else { - rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY; - } - - iwlagn_set_rxon_chain(priv, ctx); - - IWL_DEBUG_ASSOC(priv, "rxon flags 0x%X operation mode :0x%X " - "extension channel offset 0x%x\n", - le32_to_cpu(rxon->flags), ctx->ht.protection, - ctx->ht.extension_chan_offset); -} - -void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf) -{ - struct iwl_rxon_context *ctx; - - for_each_context(priv, ctx) - _iwl_set_rxon_ht(priv, ht_conf, ctx); -} - -/* Return valid, unused, channel for a passive scan to reset the RF */ -u8 iwl_get_single_channel_number(struct iwl_priv *priv, - enum ieee80211_band band) -{ - const struct iwl_channel_info *ch_info; - int i; - u8 channel = 0; - u8 min, max; - struct iwl_rxon_context *ctx; - - if (band == IEEE80211_BAND_5GHZ) { - min = 14; - max = priv->channel_count; - } else { - min = 0; - max = 14; - } - - for (i = min; i < max; i++) { - bool busy = false; - - for_each_context(priv, ctx) { - busy = priv->channel_info[i].channel == - le16_to_cpu(ctx->staging.channel); - if (busy) - break; - } - - if (busy) - continue; - - channel = priv->channel_info[i].channel; - ch_info = iwl_get_channel_info(priv, band, channel); - if (is_channel_valid(ch_info)) - break; - } - - return channel; -} - -/** - * iwl_set_rxon_channel - Set the band and channel values in staging RXON - * @ch: requested channel as a pointer to struct ieee80211_channel - - * NOTE: Does not commit to the hardware; it sets appropriate bit fields - * in the staging RXON flag structure based on the ch->band - */ -void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch, - struct iwl_rxon_context *ctx) -{ - enum ieee80211_band band = ch->band; - u16 channel = ch->hw_value; - - if ((le16_to_cpu(ctx->staging.channel) == channel) && - (priv->band == band)) - return; - - ctx->staging.channel = cpu_to_le16(channel); - if (band == IEEE80211_BAND_5GHZ) - ctx->staging.flags &= ~RXON_FLG_BAND_24G_MSK; - else - ctx->staging.flags |= RXON_FLG_BAND_24G_MSK; - - priv->band = band; - - IWL_DEBUG_INFO(priv, "Staging channel set to %d [%d]\n", channel, band); - -} - -void iwl_set_flags_for_band(struct iwl_priv *priv, - struct iwl_rxon_context *ctx, - enum ieee80211_band band, - struct ieee80211_vif *vif) -{ - if (band == IEEE80211_BAND_5GHZ) { - ctx->staging.flags &= - ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK - | RXON_FLG_CCK_MSK); - ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK; - } else { - /* Copied from iwl_post_associate() */ - if (vif && vif->bss_conf.use_short_slot) - ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK; - else - ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK; - - ctx->staging.flags |= RXON_FLG_BAND_24G_MSK; - ctx->staging.flags |= RXON_FLG_AUTO_DETECT_MSK; - ctx->staging.flags &= ~RXON_FLG_CCK_MSK; - } -} - -/* - * initialize rxon structure with default values from eeprom - */ -void iwl_connection_init_rx_config(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) -{ - const struct iwl_channel_info *ch_info; - - memset(&ctx->staging, 0, sizeof(ctx->staging)); - - if (!ctx->vif) { - ctx->staging.dev_type = ctx->unused_devtype; - } else switch (ctx->vif->type) { - case NL80211_IFTYPE_AP: - ctx->staging.dev_type = ctx->ap_devtype; - break; - - case NL80211_IFTYPE_STATION: - ctx->staging.dev_type = ctx->station_devtype; - ctx->staging.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK; - break; - - case NL80211_IFTYPE_ADHOC: - ctx->staging.dev_type = ctx->ibss_devtype; - ctx->staging.flags = RXON_FLG_SHORT_PREAMBLE_MSK; - ctx->staging.filter_flags = RXON_FILTER_BCON_AWARE_MSK | - RXON_FILTER_ACCEPT_GRP_MSK; - break; - - default: - IWL_ERR(priv, "Unsupported interface type %d\n", - ctx->vif->type); - break; - } - -#if 0 - /* TODO: Figure out when short_preamble would be set and cache from - * that */ - if (!hw_to_local(priv->hw)->short_preamble) - ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; - else - ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; -#endif - - ch_info = iwl_get_channel_info(priv, priv->band, - le16_to_cpu(ctx->active.channel)); - - if (!ch_info) - ch_info = &priv->channel_info[0]; - - ctx->staging.channel = cpu_to_le16(ch_info->channel); - priv->band = ch_info->band; - - iwl_set_flags_for_band(priv, ctx, priv->band, ctx->vif); - - ctx->staging.ofdm_basic_rates = - (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; - ctx->staging.cck_basic_rates = - (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF; - - /* clear both MIX and PURE40 mode flag */ - ctx->staging.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED | - RXON_FLG_CHANNEL_MODE_PURE_40); - if (ctx->vif) - memcpy(ctx->staging.node_addr, ctx->vif->addr, ETH_ALEN); - - ctx->staging.ofdm_ht_single_stream_basic_rates = 0xff; - ctx->staging.ofdm_ht_dual_stream_basic_rates = 0xff; - ctx->staging.ofdm_ht_triple_stream_basic_rates = 0xff; -} - -void iwl_set_rate(struct iwl_priv *priv) -{ - const struct ieee80211_supported_band *hw = NULL; - struct ieee80211_rate *rate; - struct iwl_rxon_context *ctx; - int i; - - hw = iwl_get_hw_mode(priv, priv->band); - if (!hw) { - IWL_ERR(priv, "Failed to set rate: unable to get hw mode\n"); - return; - } - - priv->active_rate = 0; - - for (i = 0; i < hw->n_bitrates; i++) { - rate = &(hw->bitrates[i]); - if (rate->hw_value < IWL_RATE_COUNT_LEGACY) - priv->active_rate |= (1 << rate->hw_value); - } - - IWL_DEBUG_RATE(priv, "Set active_rate = %0x\n", priv->active_rate); - - for_each_context(priv, ctx) { - ctx->staging.cck_basic_rates = - (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF; - - ctx->staging.ofdm_basic_rates = - (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; - } -} - -void iwl_chswitch_done(struct iwl_priv *priv, bool is_success) -{ - /* - * MULTI-FIXME - * See iwlagn_mac_channel_switch. - */ - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status)) - ieee80211_chswitch_done(ctx->vif, is_success); -} - -#ifdef CONFIG_IWLWIFI_DEBUG -void iwl_print_rx_config_cmd(struct iwl_priv *priv, - enum iwl_rxon_context_id ctxid) -{ - struct iwl_rxon_context *ctx = &priv->contexts[ctxid]; - struct iwl_rxon_cmd *rxon = &ctx->staging; - - IWL_DEBUG_RADIO(priv, "RX CONFIG:\n"); - iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); - IWL_DEBUG_RADIO(priv, "u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); - IWL_DEBUG_RADIO(priv, "u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags)); - IWL_DEBUG_RADIO(priv, "u32 filter_flags: 0x%08x\n", - le32_to_cpu(rxon->filter_flags)); - IWL_DEBUG_RADIO(priv, "u8 dev_type: 0x%x\n", rxon->dev_type); - IWL_DEBUG_RADIO(priv, "u8 ofdm_basic_rates: 0x%02x\n", - rxon->ofdm_basic_rates); - IWL_DEBUG_RADIO(priv, "u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates); - IWL_DEBUG_RADIO(priv, "u8[6] node_addr: %pM\n", rxon->node_addr); - IWL_DEBUG_RADIO(priv, "u8[6] bssid_addr: %pM\n", rxon->bssid_addr); - IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); -} -#endif - -static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) -{ - unsigned int reload_msec; - unsigned long reload_jiffies; - -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_have_debug_level(IWL_DL_FW_ERRORS)) - iwl_print_rx_config_cmd(priv, IWL_RXON_CTX_BSS); -#endif - - /* uCode is no longer loaded. */ - priv->ucode_loaded = false; - - /* Set the FW error flag -- cleared on iwl_down */ - set_bit(STATUS_FW_ERROR, &priv->shrd->status); - - /* Cancel currently queued command. */ - clear_bit(STATUS_HCMD_ACTIVE, &priv->shrd->status); - - iwl_abort_notification_waits(&priv->notif_wait); - - /* Keep the restart process from trying to send host - * commands by clearing the ready bit */ - clear_bit(STATUS_READY, &priv->status); - - wake_up(&trans(priv)->wait_command_queue); - - if (!ondemand) { - /* - * If firmware keep reloading, then it indicate something - * serious wrong and firmware having problem to recover - * from it. Instead of keep trying which will fill the syslog - * and hang the system, let's just stop it - */ - reload_jiffies = jiffies; - reload_msec = jiffies_to_msecs((long) reload_jiffies - - (long) priv->reload_jiffies); - priv->reload_jiffies = reload_jiffies; - if (reload_msec <= IWL_MIN_RELOAD_DURATION) { - priv->reload_count++; - if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) { - IWL_ERR(priv, "BUG_ON, Stop restarting\n"); - return; - } - } else - priv->reload_count = 0; - } - - if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { - if (iwlagn_mod_params.restart_fw) { - IWL_DEBUG_FW_ERRORS(priv, - "Restarting adapter due to uCode error.\n"); - queue_work(priv->workqueue, &priv->restart); - } else - IWL_DEBUG_FW_ERRORS(priv, - "Detected FW error, but not restarting\n"); - } -} - -int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) -{ - int ret; - s8 prev_tx_power; - bool defer; - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - - lockdep_assert_held(&priv->mutex); - - if (priv->tx_power_user_lmt == tx_power && !force) - return 0; - - if (tx_power < IWLAGN_TX_POWER_TARGET_POWER_MIN) { - IWL_WARN(priv, - "Requested user TXPOWER %d below lower limit %d.\n", - tx_power, - IWLAGN_TX_POWER_TARGET_POWER_MIN); - return -EINVAL; - } - - if (tx_power > priv->tx_power_device_lmt) { - IWL_WARN(priv, - "Requested user TXPOWER %d above upper limit %d.\n", - tx_power, priv->tx_power_device_lmt); - return -EINVAL; - } - - if (!iwl_is_ready_rf(priv)) - return -EIO; - - /* scan complete and commit_rxon use tx_power_next value, - * it always need to be updated for newest request */ - priv->tx_power_next = tx_power; - - /* do not set tx power when scanning or channel changing */ - defer = test_bit(STATUS_SCANNING, &priv->status) || - memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging)); - if (defer && !force) { - IWL_DEBUG_INFO(priv, "Deferring tx power set\n"); - return 0; - } - - prev_tx_power = priv->tx_power_user_lmt; - priv->tx_power_user_lmt = tx_power; - - ret = iwlagn_send_tx_power(priv); - - /* if fail to set tx_power, restore the orig. tx power */ - if (ret) { - priv->tx_power_user_lmt = prev_tx_power; - priv->tx_power_next = prev_tx_power; - } - return ret; -} - -void iwl_send_bt_config(struct iwl_priv *priv) -{ - struct iwl_bt_cmd bt_cmd = { - .lead_time = BT_LEAD_TIME_DEF, - .max_kill = BT_MAX_KILL_DEF, - .kill_ack_mask = 0, - .kill_cts_mask = 0, - }; - - if (!iwlagn_mod_params.bt_coex_active) - bt_cmd.flags = BT_COEX_DISABLE; - else - bt_cmd.flags = BT_COEX_ENABLE; - - priv->bt_enable_flag = bt_cmd.flags; - IWL_DEBUG_INFO(priv, "BT coex %s\n", - (bt_cmd.flags == BT_COEX_DISABLE) ? "disable" : "active"); - - if (iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG, - CMD_SYNC, sizeof(struct iwl_bt_cmd), &bt_cmd)) - IWL_ERR(priv, "failed to send BT Coex Config\n"); -} - -int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear) -{ - struct iwl_statistics_cmd statistics_cmd = { - .configuration_flags = - clear ? IWL_STATS_CONF_CLEAR_STATS : 0, - }; - - if (flags & CMD_ASYNC) - return iwl_dvm_send_cmd_pdu(priv, REPLY_STATISTICS_CMD, - CMD_ASYNC, - sizeof(struct iwl_statistics_cmd), - &statistics_cmd); - else - return iwl_dvm_send_cmd_pdu(priv, REPLY_STATISTICS_CMD, - CMD_SYNC, - sizeof(struct iwl_statistics_cmd), - &statistics_cmd); -} - - - - -#ifdef CONFIG_IWLWIFI_DEBUGFS - -#define IWL_TRAFFIC_DUMP_SIZE (IWL_TRAFFIC_ENTRY_SIZE * IWL_TRAFFIC_ENTRIES) - -void iwl_reset_traffic_log(struct iwl_priv *priv) -{ - priv->tx_traffic_idx = 0; - priv->rx_traffic_idx = 0; - if (priv->tx_traffic) - memset(priv->tx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE); - if (priv->rx_traffic) - memset(priv->rx_traffic, 0, IWL_TRAFFIC_DUMP_SIZE); -} - -int iwl_alloc_traffic_mem(struct iwl_priv *priv) -{ - u32 traffic_size = IWL_TRAFFIC_DUMP_SIZE; - - if (iwl_have_debug_level(IWL_DL_TX)) { - if (!priv->tx_traffic) { - priv->tx_traffic = - kzalloc(traffic_size, GFP_KERNEL); - if (!priv->tx_traffic) - return -ENOMEM; - } - } - if (iwl_have_debug_level(IWL_DL_RX)) { - if (!priv->rx_traffic) { - priv->rx_traffic = - kzalloc(traffic_size, GFP_KERNEL); - if (!priv->rx_traffic) - return -ENOMEM; - } - } - iwl_reset_traffic_log(priv); - return 0; -} - -void iwl_free_traffic_mem(struct iwl_priv *priv) -{ - kfree(priv->tx_traffic); - priv->tx_traffic = NULL; - - kfree(priv->rx_traffic); - priv->rx_traffic = NULL; -} - -void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv, - u16 length, struct ieee80211_hdr *header) -{ - __le16 fc; - u16 len; - - if (likely(!iwl_have_debug_level(IWL_DL_TX))) - return; - - if (!priv->tx_traffic) - return; - - fc = header->frame_control; - if (ieee80211_is_data(fc)) { - len = (length > IWL_TRAFFIC_ENTRY_SIZE) - ? IWL_TRAFFIC_ENTRY_SIZE : length; - memcpy((priv->tx_traffic + - (priv->tx_traffic_idx * IWL_TRAFFIC_ENTRY_SIZE)), - header, len); - priv->tx_traffic_idx = - (priv->tx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES; - } -} - -void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, - u16 length, struct ieee80211_hdr *header) -{ - __le16 fc; - u16 len; - - if (likely(!iwl_have_debug_level(IWL_DL_RX))) - return; - - if (!priv->rx_traffic) - return; - - fc = header->frame_control; - if (ieee80211_is_data(fc)) { - len = (length > IWL_TRAFFIC_ENTRY_SIZE) - ? IWL_TRAFFIC_ENTRY_SIZE : length; - memcpy((priv->rx_traffic + - (priv->rx_traffic_idx * IWL_TRAFFIC_ENTRY_SIZE)), - header, len); - priv->rx_traffic_idx = - (priv->rx_traffic_idx + 1) % IWL_TRAFFIC_ENTRIES; - } -} - -const char *get_mgmt_string(int cmd) -{ - switch (cmd) { - IWL_CMD(MANAGEMENT_ASSOC_REQ); - IWL_CMD(MANAGEMENT_ASSOC_RESP); - IWL_CMD(MANAGEMENT_REASSOC_REQ); - IWL_CMD(MANAGEMENT_REASSOC_RESP); - IWL_CMD(MANAGEMENT_PROBE_REQ); - IWL_CMD(MANAGEMENT_PROBE_RESP); - IWL_CMD(MANAGEMENT_BEACON); - IWL_CMD(MANAGEMENT_ATIM); - IWL_CMD(MANAGEMENT_DISASSOC); - IWL_CMD(MANAGEMENT_AUTH); - IWL_CMD(MANAGEMENT_DEAUTH); - IWL_CMD(MANAGEMENT_ACTION); - default: - return "UNKNOWN"; - - } -} - -const char *get_ctrl_string(int cmd) -{ - switch (cmd) { - IWL_CMD(CONTROL_BACK_REQ); - IWL_CMD(CONTROL_BACK); - IWL_CMD(CONTROL_PSPOLL); - IWL_CMD(CONTROL_RTS); - IWL_CMD(CONTROL_CTS); - IWL_CMD(CONTROL_ACK); - IWL_CMD(CONTROL_CFEND); - IWL_CMD(CONTROL_CFENDACK); - default: - return "UNKNOWN"; - - } -} - -void iwl_clear_traffic_stats(struct iwl_priv *priv) -{ - memset(&priv->tx_stats, 0, sizeof(struct traffic_stats)); - memset(&priv->rx_stats, 0, sizeof(struct traffic_stats)); -} - -/* - * if CONFIG_IWLWIFI_DEBUGFS defined, iwl_update_stats function will - * record all the MGMT, CTRL and DATA pkt for both TX and Rx pass. - * Use debugFs to display the rx/rx_statistics - * if CONFIG_IWLWIFI_DEBUGFS not being defined, then no MGMT and CTRL - * information will be recorded, but DATA pkt still will be recorded - * for the reason of iwl_led.c need to control the led blinking based on - * number of tx and rx data. - * - */ -void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len) -{ - struct traffic_stats *stats; - - if (is_tx) - stats = &priv->tx_stats; - else - stats = &priv->rx_stats; - - if (ieee80211_is_mgmt(fc)) { - switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { - case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ): - stats->mgmt[MANAGEMENT_ASSOC_REQ]++; - break; - case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP): - stats->mgmt[MANAGEMENT_ASSOC_RESP]++; - break; - case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ): - stats->mgmt[MANAGEMENT_REASSOC_REQ]++; - break; - case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP): - stats->mgmt[MANAGEMENT_REASSOC_RESP]++; - break; - case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ): - stats->mgmt[MANAGEMENT_PROBE_REQ]++; - break; - case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP): - stats->mgmt[MANAGEMENT_PROBE_RESP]++; - break; - case cpu_to_le16(IEEE80211_STYPE_BEACON): - stats->mgmt[MANAGEMENT_BEACON]++; - break; - case cpu_to_le16(IEEE80211_STYPE_ATIM): - stats->mgmt[MANAGEMENT_ATIM]++; - break; - case cpu_to_le16(IEEE80211_STYPE_DISASSOC): - stats->mgmt[MANAGEMENT_DISASSOC]++; - break; - case cpu_to_le16(IEEE80211_STYPE_AUTH): - stats->mgmt[MANAGEMENT_AUTH]++; - break; - case cpu_to_le16(IEEE80211_STYPE_DEAUTH): - stats->mgmt[MANAGEMENT_DEAUTH]++; - break; - case cpu_to_le16(IEEE80211_STYPE_ACTION): - stats->mgmt[MANAGEMENT_ACTION]++; - break; - } - } else if (ieee80211_is_ctl(fc)) { - switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { - case cpu_to_le16(IEEE80211_STYPE_BACK_REQ): - stats->ctrl[CONTROL_BACK_REQ]++; - break; - case cpu_to_le16(IEEE80211_STYPE_BACK): - stats->ctrl[CONTROL_BACK]++; - break; - case cpu_to_le16(IEEE80211_STYPE_PSPOLL): - stats->ctrl[CONTROL_PSPOLL]++; - break; - case cpu_to_le16(IEEE80211_STYPE_RTS): - stats->ctrl[CONTROL_RTS]++; - break; - case cpu_to_le16(IEEE80211_STYPE_CTS): - stats->ctrl[CONTROL_CTS]++; - break; - case cpu_to_le16(IEEE80211_STYPE_ACK): - stats->ctrl[CONTROL_ACK]++; - break; - case cpu_to_le16(IEEE80211_STYPE_CFEND): - stats->ctrl[CONTROL_CFEND]++; - break; - case cpu_to_le16(IEEE80211_STYPE_CFENDACK): - stats->ctrl[CONTROL_CFENDACK]++; - break; - } - } else { - /* data */ - stats->data_cnt++; - stats->data_bytes += len; - } -} -#endif - -static void iwl_force_rf_reset(struct iwl_priv *priv) -{ - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - if (!iwl_is_any_associated(priv)) { - IWL_DEBUG_SCAN(priv, "force reset rejected: not associated\n"); - return; - } - /* - * There is no easy and better way to force reset the radio, - * the only known method is switching channel which will force to - * reset and tune the radio. - * Use internal short scan (single channel) operation to should - * achieve this objective. - * Driver should reset the radio when number of consecutive missed - * beacon, or any other uCode error condition detected. - */ - IWL_DEBUG_INFO(priv, "perform radio reset.\n"); - iwl_internal_short_hw_scan(priv); -} - - -int iwl_force_reset(struct iwl_priv *priv, int mode, bool external) -{ - struct iwl_force_reset *force_reset; - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return -EINVAL; - - if (mode >= IWL_MAX_FORCE_RESET) { - IWL_DEBUG_INFO(priv, "invalid reset request.\n"); - return -EINVAL; - } - force_reset = &priv->force_reset[mode]; - force_reset->reset_request_count++; - if (!external) { - if (force_reset->last_force_reset_jiffies && - time_after(force_reset->last_force_reset_jiffies + - force_reset->reset_duration, jiffies)) { - IWL_DEBUG_INFO(priv, "force reset rejected\n"); - force_reset->reset_reject_count++; - return -EAGAIN; - } - } - force_reset->reset_success_count++; - force_reset->last_force_reset_jiffies = jiffies; - IWL_DEBUG_INFO(priv, "perform force reset (%d)\n", mode); - switch (mode) { - case IWL_RF_RESET: - iwl_force_rf_reset(priv); - break; - case IWL_FW_RESET: - /* - * if the request is from external(ex: debugfs), - * then always perform the request in regardless the module - * parameter setting - * if the request is from internal (uCode error or driver - * detect failure), then fw_restart module parameter - * need to be check before performing firmware reload - */ - if (!external && !iwlagn_mod_params.restart_fw) { - IWL_DEBUG_INFO(priv, "Cancel firmware reload based on " - "module parameter setting\n"); - break; - } - IWL_ERR(priv, "On demand firmware reload\n"); - iwlagn_fw_error(priv, true); - break; - } - return 0; -} - - -int iwl_cmd_echo_test(struct iwl_priv *priv) -{ - int ret; - struct iwl_host_cmd cmd = { - .id = REPLY_ECHO, - .len = { 0 }, - .flags = CMD_SYNC, - }; - - ret = iwl_dvm_send_cmd(priv, &cmd); - if (ret) - IWL_ERR(priv, "echo testing fail: 0X%x\n", ret); - else - IWL_DEBUG_INFO(priv, "echo testing pass\n"); - return ret; -} - -static inline int iwl_check_stuck_queue(struct iwl_priv *priv, int txq) -{ - if (iwl_trans_check_stuck_queue(trans(priv), txq)) { - int ret; - ret = iwl_force_reset(priv, IWL_FW_RESET, false); - return (ret == -EAGAIN) ? 0 : 1; - } - return 0; -} - -/* - * Making watchdog tick be a quarter of timeout assure we will - * discover the queue hung between timeout and 1.25*timeout - */ -#define IWL_WD_TICK(timeout) ((timeout) / 4) - -/* - * Watchdog timer callback, we check each tx queue for stuck, if if hung - * we reset the firmware. If everything is fine just rearm the timer. - */ -void iwl_bg_watchdog(unsigned long data) -{ - struct iwl_priv *priv = (struct iwl_priv *)data; - int cnt; - unsigned long timeout; - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - if (iwl_is_rfkill(priv)) - return; - - timeout = hw_params(priv).wd_timeout; - if (timeout == 0) - return; - - /* monitor and check for stuck queues */ - for (cnt = 0; cnt < cfg(priv)->base_params->num_of_queues; cnt++) - if (iwl_check_stuck_queue(priv, cnt)) - return; - - mod_timer(&priv->watchdog, jiffies + - msecs_to_jiffies(IWL_WD_TICK(timeout))); -} - -void iwl_setup_watchdog(struct iwl_priv *priv) -{ - unsigned int timeout = hw_params(priv).wd_timeout; - - if (!iwlagn_mod_params.wd_disable) { - /* use system default */ - if (timeout && !cfg(priv)->base_params->wd_disable) - mod_timer(&priv->watchdog, - jiffies + - msecs_to_jiffies(IWL_WD_TICK(timeout))); - else - del_timer(&priv->watchdog); - } else { - /* module parameter overwrite default configuration */ - if (timeout && iwlagn_mod_params.wd_disable == 2) - mod_timer(&priv->watchdog, - jiffies + - msecs_to_jiffies(IWL_WD_TICK(timeout))); - else - del_timer(&priv->watchdog); - } -} - -/** - * iwl_beacon_time_mask_low - mask of lower 32 bit of beacon time - * @priv -- pointer to iwl_priv data structure - * @tsf_bits -- number of bits need to shift for masking) - */ -static inline u32 iwl_beacon_time_mask_low(struct iwl_priv *priv, - u16 tsf_bits) -{ - return (1 << tsf_bits) - 1; -} - -/** - * iwl_beacon_time_mask_high - mask of higher 32 bit of beacon time - * @priv -- pointer to iwl_priv data structure - * @tsf_bits -- number of bits need to shift for masking) - */ -static inline u32 iwl_beacon_time_mask_high(struct iwl_priv *priv, - u16 tsf_bits) -{ - return ((1 << (32 - tsf_bits)) - 1) << tsf_bits; -} - -/* - * extended beacon time format - * time in usec will be changed into a 32-bit value in extended:internal format - * the extended part is the beacon counts - * the internal part is the time in usec within one beacon interval - */ -u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, u32 beacon_interval) -{ - u32 quot; - u32 rem; - u32 interval = beacon_interval * TIME_UNIT; - - if (!interval || !usec) - return 0; - - quot = (usec / interval) & - (iwl_beacon_time_mask_high(priv, IWLAGN_EXT_BEACON_TIME_POS) >> - IWLAGN_EXT_BEACON_TIME_POS); - rem = (usec % interval) & iwl_beacon_time_mask_low(priv, - IWLAGN_EXT_BEACON_TIME_POS); - - return (quot << IWLAGN_EXT_BEACON_TIME_POS) + rem; -} - -/* base is usually what we get from ucode with each received frame, - * the same as HW timer counter counting down - */ -__le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base, - u32 addon, u32 beacon_interval) -{ - u32 base_low = base & iwl_beacon_time_mask_low(priv, - IWLAGN_EXT_BEACON_TIME_POS); - u32 addon_low = addon & iwl_beacon_time_mask_low(priv, - IWLAGN_EXT_BEACON_TIME_POS); - u32 interval = beacon_interval * TIME_UNIT; - u32 res = (base & iwl_beacon_time_mask_high(priv, - IWLAGN_EXT_BEACON_TIME_POS)) + - (addon & iwl_beacon_time_mask_high(priv, - IWLAGN_EXT_BEACON_TIME_POS)); - - if (base_low > addon_low) - res += base_low - addon_low; - else if (base_low < addon_low) { - res += interval + base_low - addon_low; - res += (1 << IWLAGN_EXT_BEACON_TIME_POS); - } else - res += (1 << IWLAGN_EXT_BEACON_TIME_POS); - - return cpu_to_le32(res); -} - -void iwl_nic_error(struct iwl_op_mode *op_mode) -{ - struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); - - iwlagn_fw_error(priv, false); -} - -void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) -{ - struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); - - if (state) - set_bit(STATUS_RF_KILL_HW, &priv->status); - else - clear_bit(STATUS_RF_KILL_HW, &priv->status); - - wiphy_rfkill_set_hw_state(priv->hw->wiphy, state); -} - -void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) -{ - struct ieee80211_tx_info *info; - - info = IEEE80211_SKB_CB(skb); - kmem_cache_free(iwl_tx_cmd_pool, (info->driver_data[1])); - dev_kfree_skb_any(skb); -} diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-core.h b/trunk/drivers/net/wireless/iwlwifi/iwl-core.h deleted file mode 100644 index 635eb685edeb..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-core.h +++ /dev/null @@ -1,234 +0,0 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2012 Intel 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 - * - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * 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. - *****************************************************************************/ - -#ifndef __iwl_core_h__ -#define __iwl_core_h__ - -#include "iwl-dev.h" -#include "iwl-io.h" - -/************************ - * forward declarations * - ************************/ -struct iwl_host_cmd; -struct iwl_cmd; - -#define TIME_UNIT 1024 - -struct iwl_lib_ops { - /* set hw dependent parameters */ - void (*set_hw_params)(struct iwl_priv *priv); - int (*set_channel_switch)(struct iwl_priv *priv, - struct ieee80211_channel_switch *ch_switch); - /* device specific configuration */ - void (*nic_config)(struct iwl_priv *priv); - - /* eeprom operations (as defined in iwl-eeprom.h) */ - struct iwl_eeprom_ops eeprom_ops; - - /* temperature */ - void (*temperature)(struct iwl_priv *priv); -}; - -/*************************** - * L i b * - ***************************/ - -void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx, - int hw_decrypt); -int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx); -int iwl_full_rxon_required(struct iwl_priv *priv, struct iwl_rxon_context *ctx); -void iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch, - struct iwl_rxon_context *ctx); -void iwl_set_flags_for_band(struct iwl_priv *priv, - struct iwl_rxon_context *ctx, - enum ieee80211_band band, - struct ieee80211_vif *vif); -u8 iwl_get_single_channel_number(struct iwl_priv *priv, - enum ieee80211_band band); -void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf); -bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, - struct iwl_rxon_context *ctx, - struct ieee80211_sta_ht_cap *ht_cap); -void iwl_connection_init_rx_config(struct iwl_priv *priv, - struct iwl_rxon_context *ctx); -void iwl_set_rate(struct iwl_priv *priv); -int iwl_cmd_echo_test(struct iwl_priv *priv); -#ifdef CONFIG_IWLWIFI_DEBUGFS -int iwl_alloc_traffic_mem(struct iwl_priv *priv); -void iwl_free_traffic_mem(struct iwl_priv *priv); -void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv, - u16 length, struct ieee80211_hdr *header); -void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, - u16 length, struct ieee80211_hdr *header); -const char *get_mgmt_string(int cmd); -const char *get_ctrl_string(int cmd); -void iwl_clear_traffic_stats(struct iwl_priv *priv); -void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, - u16 len); -void iwl_reset_traffic_log(struct iwl_priv *priv); - -#else -static inline int iwl_alloc_traffic_mem(struct iwl_priv *priv) -{ - return 0; -} -static inline void iwl_free_traffic_mem(struct iwl_priv *priv) -{ -} -static inline void iwl_reset_traffic_log(struct iwl_priv *priv) -{ -} -static inline void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv, - u16 length, struct ieee80211_hdr *header) -{ -} -static inline void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, - u16 length, struct ieee80211_hdr *header) -{ -} -static inline void iwl_update_stats(struct iwl_priv *priv, bool is_tx, - __le16 fc, u16 len) -{ -} -#endif - -/***************************************************** -* RX -******************************************************/ -void iwl_chswitch_done(struct iwl_priv *priv, bool is_success); - -void iwl_setup_watchdog(struct iwl_priv *priv); -/***************************************************** - * TX power - ****************************************************/ -int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force); - -/******************************************************************************* - * Scanning - ******************************************************************************/ -void iwl_init_scan_params(struct iwl_priv *priv); -int iwl_scan_cancel(struct iwl_priv *priv); -void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms); -void iwl_force_scan_end(struct iwl_priv *priv); -void iwl_internal_short_hw_scan(struct iwl_priv *priv); -int iwl_force_reset(struct iwl_priv *priv, int mode, bool external); -void iwl_setup_rx_scan_handlers(struct iwl_priv *priv); -void iwl_setup_scan_deferred_work(struct iwl_priv *priv); -void iwl_cancel_scan_deferred_work(struct iwl_priv *priv); -int __must_check iwl_scan_initiate(struct iwl_priv *priv, - struct ieee80211_vif *vif, - enum iwl_scan_type scan_type, - enum ieee80211_band band); - -/* For faster active scanning, scan will move to the next channel if fewer than - * PLCP_QUIET_THRESH packets are heard on this channel within - * ACTIVE_QUIET_TIME after sending probe request. This shortens the dwell - * time if it's a quiet channel (nothing responded to our probe, and there's - * no other traffic). - * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */ -#define IWL_ACTIVE_QUIET_TIME cpu_to_le16(10) /* msec */ -#define IWL_PLCP_QUIET_THRESH cpu_to_le16(1) /* packets */ - -#define IWL_SCAN_CHECK_WATCHDOG (HZ * 7) - -/* traffic log definitions */ -#define IWL_TRAFFIC_ENTRIES (256) -#define IWL_TRAFFIC_ENTRY_SIZE (64) - -/***************************************************** - * S e n d i n g H o s t C o m m a n d s * - *****************************************************/ - -void iwl_bg_watchdog(unsigned long data); -u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, u32 beacon_interval); -__le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base, - u32 addon, u32 beacon_interval); - - -/***************************************************** -* GEOS -******************************************************/ -int iwl_init_geos(struct iwl_priv *priv); -void iwl_free_geos(struct iwl_priv *priv); - -extern void iwl_send_bt_config(struct iwl_priv *priv); -extern int iwl_send_statistics_request(struct iwl_priv *priv, - u8 flags, bool clear); - -int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx); - -static inline const struct ieee80211_supported_band *iwl_get_hw_mode( - struct iwl_priv *priv, enum ieee80211_band band) -{ - return priv->hw->wiphy->bands[band]; -} - -static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv) -{ - return cfg(priv)->bt_params && - cfg(priv)->bt_params->advanced_bt_coexist; -} - -extern bool bt_siso_mode; - -#endif /* __iwl_core_h__ */ diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-csr.h b/trunk/drivers/net/wireless/iwlwifi/iwl-csr.h index 5f96ce105f08..59750543fce7 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -430,6 +430,9 @@ #define HBUS_TARG_PRPH_WDAT (HBUS_BASE+0x04c) #define HBUS_TARG_PRPH_RDAT (HBUS_BASE+0x050) +/* Used to enable DBGM */ +#define HBUS_TARG_TEST_REG (HBUS_BASE+0x05c) + /* * Per-Tx-queue write pointer (index, really!) * Indicates index to next TFD that driver will fill (1 past latest filled). diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-debug.c b/trunk/drivers/net/wireless/iwlwifi/iwl-debug.c index 059efabda184..2d1b42847b9b 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-debug.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-debug.c @@ -63,6 +63,7 @@ #include #include "iwl-debug.h" +#include "iwl-devtrace.h" #define __iwl_fn(fn) \ void __iwl_ ##fn(struct device *dev, const char *fmt, ...) \ diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-debug.h b/trunk/drivers/net/wireless/iwlwifi/iwl-debug.h index a6b32a11e103..8376b842bdba 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -29,10 +29,13 @@ #ifndef __iwl_debug_h__ #define __iwl_debug_h__ -#include "iwl-shared.h" -#include "iwl-devtrace.h" +#include "iwl-modparams.h" -struct iwl_priv; + +static inline bool iwl_have_debug_level(u32 level) +{ + return iwlwifi_mod_params.debug_level & level; +} void __iwl_err(struct device *dev, bool rfkill_prefix, bool only_trace, const char *fmt, ...); @@ -41,10 +44,10 @@ void __iwl_info(struct device *dev, const char *fmt, ...); void __iwl_crit(struct device *dev, const char *fmt, ...); /* No matter what is m (priv, bus, trans), this will work */ -#define IWL_ERR(m, f, a...) __iwl_err(trans(m)->dev, false, false, f, ## a) -#define IWL_WARN(m, f, a...) __iwl_warn(trans(m)->dev, f, ## a) -#define IWL_INFO(m, f, a...) __iwl_info(trans(m)->dev, f, ## a) -#define IWL_CRIT(m, f, a...) __iwl_crit(trans(m)->dev, f, ## a) +#define IWL_ERR(m, f, a...) __iwl_err((m)->dev, false, false, f, ## a) +#define IWL_WARN(m, f, a...) __iwl_warn((m)->dev, f, ## a) +#define IWL_INFO(m, f, a...) __iwl_info((m)->dev, f, ## a) +#define IWL_CRIT(m, f, a...) __iwl_crit((m)->dev, f, ## a) #if defined(CONFIG_IWLWIFI_DEBUG) || defined(CONFIG_IWLWIFI_DEVICE_TRACING) void __iwl_dbg(struct device *dev, @@ -65,9 +68,9 @@ do { \ } while (0) #define IWL_DEBUG(m, level, fmt, args...) \ - __iwl_dbg(trans(m)->dev, level, false, __func__, fmt, ##args) + __iwl_dbg((m)->dev, level, false, __func__, fmt, ##args) #define IWL_DEBUG_LIMIT(m, level, fmt, args...) \ - __iwl_dbg(trans(m)->dev, level, true, __func__, fmt, ##args) + __iwl_dbg((m)->dev, level, true, __func__, fmt, ##args) #ifdef CONFIG_IWLWIFI_DEBUG #define iwl_print_hex_dump(m, level, p, len) \ @@ -80,19 +83,6 @@ do { \ #define iwl_print_hex_dump(m, level, p, len) #endif /* CONFIG_IWLWIFI_DEBUG */ -#ifdef CONFIG_IWLWIFI_DEBUGFS -int iwl_dbgfs_register(struct iwl_priv *priv, const char *name); -void iwl_dbgfs_unregister(struct iwl_priv *priv); -#else -static inline int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) -{ - return 0; -} -static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) -{ -} -#endif /* CONFIG_IWLWIFI_DEBUGFS */ - /* * To use the debug system: * diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/trunk/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 2bbaebd99ad4..e7c157e5ebeb 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -37,9 +37,9 @@ #include "iwl-dev.h" #include "iwl-debug.h" -#include "iwl-core.h" #include "iwl-io.h" #include "iwl-agn.h" +#include "iwl-modparams.h" /* create and remove of files */ #define DEBUGFS_ADD_FILE(name, parent, mode) do { \ @@ -111,105 +111,6 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \ .llseek = generic_file_llseek, \ }; -static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) { - - struct iwl_priv *priv = file->private_data; - char *buf; - int pos = 0; - - int cnt; - ssize_t ret; - const size_t bufsz = 100 + - sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX); - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) - return -ENOMEM; - pos += scnprintf(buf + pos, bufsz - pos, "Management:\n"); - for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) { - pos += scnprintf(buf + pos, bufsz - pos, - "\t%25s\t\t: %u\n", - get_mgmt_string(cnt), - priv->tx_stats.mgmt[cnt]); - } - pos += scnprintf(buf + pos, bufsz - pos, "Control\n"); - for (cnt = 0; cnt < CONTROL_MAX; cnt++) { - pos += scnprintf(buf + pos, bufsz - pos, - "\t%25s\t\t: %u\n", - get_ctrl_string(cnt), - priv->tx_stats.ctrl[cnt]); - } - pos += scnprintf(buf + pos, bufsz - pos, "Data:\n"); - pos += scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n", - priv->tx_stats.data_cnt); - pos += scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n", - priv->tx_stats.data_bytes); - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} - -static ssize_t iwl_dbgfs_clear_traffic_statistics_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - u32 clear_flag; - char buf[8]; - int buf_size; - - memset(buf, 0, sizeof(buf)); - buf_size = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - if (sscanf(buf, "%x", &clear_flag) != 1) - return -EFAULT; - iwl_clear_traffic_stats(priv); - - return count; -} - -static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) { - - struct iwl_priv *priv = file->private_data; - char *buf; - int pos = 0; - int cnt; - ssize_t ret; - const size_t bufsz = 100 + - sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX); - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - pos += scnprintf(buf + pos, bufsz - pos, "Management:\n"); - for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) { - pos += scnprintf(buf + pos, bufsz - pos, - "\t%25s\t\t: %u\n", - get_mgmt_string(cnt), - priv->rx_stats.mgmt[cnt]); - } - pos += scnprintf(buf + pos, bufsz - pos, "Control:\n"); - for (cnt = 0; cnt < CONTROL_MAX; cnt++) { - pos += scnprintf(buf + pos, bufsz - pos, - "\t%25s\t\t: %u\n", - get_ctrl_string(cnt), - priv->rx_stats.ctrl[cnt]); - } - pos += scnprintf(buf + pos, bufsz - pos, "Data:\n"); - pos += scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n", - priv->rx_stats.data_cnt); - pos += scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n", - priv->rx_stats.data_bytes); - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} - static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -230,11 +131,9 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, /* default is to dump the entire data segment */ if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) { priv->dbgfs_sram_offset = 0x800000; - if (!priv->ucode_loaded) { - IWL_ERR(priv, "No uCode has been loadded.\n"); + if (!priv->ucode_loaded) return -EINVAL; - } - img = &priv->fw->img[priv->shrd->ucode_type]; + img = &priv->fw->img[priv->cur_ucode]; priv->dbgfs_sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; } len = priv->dbgfs_sram_len; @@ -259,7 +158,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, sram = priv->dbgfs_sram_offset & ~0x3; /* read the first u32 from sram */ - val = iwl_read_targ_mem(trans(priv), sram); + val = iwl_read_targ_mem(priv->trans, sram); for (; len; len--) { /* put the address at the start of every line */ @@ -278,7 +177,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, if (++offset == 4) { sram += 4; offset = 0; - val = iwl_read_targ_mem(trans(priv), sram); + val = iwl_read_targ_mem(priv->trans, sram); } /* put in extra spaces and split lines for human readability */ @@ -369,14 +268,19 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, i, station->sta.sta.addr, station->sta.station_flags_msk); pos += scnprintf(buf + pos, bufsz - pos, - "TID\tseq_num\trate_n_flags\n"); + "TID seqno next_rclmd " + "rate_n_flags state txq\n"); for (j = 0; j < IWL_MAX_TID_COUNT; j++) { tid_data = &priv->tid_data[i][j]; pos += scnprintf(buf + pos, bufsz - pos, - "%d:\t%#x\t%#x", + "%d: 0x%.4x 0x%.4x 0x%.8x " + "%d %.2d", j, tid_data->seq_number, - tid_data->agg.rate_n_flags); + tid_data->next_reclaimed, + tid_data->agg.rate_n_flags, + tid_data->agg.state, + tid_data->agg.txq_id); if (tid_data->agg.wait_for_ba) pos += scnprintf(buf + pos, bufsz - pos, @@ -403,30 +307,25 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file, const u8 *ptr; char *buf; u16 eeprom_ver; - size_t eeprom_len = cfg(priv)->base_params->eeprom_size; + size_t eeprom_len = priv->cfg->base_params->eeprom_size; buf_size = 4 * eeprom_len + 256; - if (eeprom_len % 16) { - IWL_ERR(priv, "NVM size is not multiple of 16.\n"); + if (eeprom_len % 16) return -ENODATA; - } - ptr = priv->shrd->eeprom; - if (!ptr) { - IWL_ERR(priv, "Invalid EEPROM/OTP memory\n"); + ptr = priv->eeprom; + if (!ptr) return -ENOMEM; - } /* 4 characters for byte 0xYY */ buf = kzalloc(buf_size, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); + if (!buf) return -ENOMEM; - } - eeprom_ver = iwl_eeprom_query16(priv->shrd, EEPROM_VERSION); + + eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s, " "version: 0x%x\n", - (trans(priv)->nvm_device_type == NVM_DEVICE_TYPE_OTP) + (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) ? "OTP" : "EEPROM", eeprom_ver); for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) { pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs); @@ -456,10 +355,8 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf, return -EAGAIN; buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); + if (!buf) return -ENOMEM; - } supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ); if (supp_band) { @@ -521,8 +418,6 @@ static ssize_t iwl_dbgfs_status_read(struct file *file, int pos = 0; const size_t bufsz = sizeof(buf); - pos += scnprintf(buf + pos, bufsz - pos, "STATUS_HCMD_ACTIVE:\t %d\n", - test_bit(STATUS_HCMD_ACTIVE, &priv->shrd->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n", test_bit(STATUS_RF_KILL_HW, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_CT_KILL:\t\t %d\n", @@ -544,9 +439,9 @@ static ssize_t iwl_dbgfs_status_read(struct file *file, pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_HW:\t\t %d\n", test_bit(STATUS_SCAN_HW, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_POWER_PMI:\t %d\n", - test_bit(STATUS_POWER_PMI, &priv->shrd->status)); + test_bit(STATUS_POWER_PMI, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_FW_ERROR:\t %d\n", - test_bit(STATUS_FW_ERROR, &priv->shrd->status)); + test_bit(STATUS_FW_ERROR, &priv->status)); return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } @@ -563,16 +458,14 @@ static ssize_t iwl_dbgfs_rx_handlers_read(struct file *file, ssize_t ret; buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); + if (!buf) return -ENOMEM; - } for (cnt = 0; cnt < REPLY_MAX; cnt++) { if (priv->rx_handlers_stats[cnt] > 0) pos += scnprintf(buf + pos, bufsz - pos, "\tRx handler[%36s]:\t\t %u\n", - get_cmd_string(cnt), + iwl_dvm_get_cmd_string(cnt), priv->rx_handlers_stats[cnt]); } @@ -680,11 +573,8 @@ static ssize_t iwl_dbgfs_disable_ht40_write(struct file *file, return -EFAULT; if (!iwl_is_any_associated(priv)) priv->disable_ht40 = ht40 ? true : false; - else { - IWL_ERR(priv, "Sta associated with AP - " - "Change to 40MHz channel support is not allowed\n"); + else return -EINVAL; - } return count; } @@ -816,87 +706,6 @@ DEBUGFS_READ_FILE_OPS(temperature); DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override); DEBUGFS_READ_FILE_OPS(current_sleep_command); -static ssize_t iwl_dbgfs_traffic_log_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - int pos = 0, ofs = 0; - int cnt = 0, entry; - - char *buf; - int bufsz = ((IWL_TRAFFIC_ENTRIES * IWL_TRAFFIC_ENTRY_SIZE * 64) * 2) + - (cfg(priv)->base_params->num_of_queues * 32 * 8) + 400; - const u8 *ptr; - ssize_t ret; - - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate buffer\n"); - return -ENOMEM; - } - if (priv->tx_traffic && iwl_have_debug_level(IWL_DL_TX)) { - ptr = priv->tx_traffic; - pos += scnprintf(buf + pos, bufsz - pos, - "Tx Traffic idx: %u\n", priv->tx_traffic_idx); - for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) { - for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16; - entry++, ofs += 16) { - pos += scnprintf(buf + pos, bufsz - pos, - "0x%.4x ", ofs); - hex_dump_to_buffer(ptr + ofs, 16, 16, 2, - buf + pos, bufsz - pos, 0); - pos += strlen(buf + pos); - if (bufsz - pos > 0) - buf[pos++] = '\n'; - } - } - } - - if (priv->rx_traffic && iwl_have_debug_level(IWL_DL_RX)) { - ptr = priv->rx_traffic; - pos += scnprintf(buf + pos, bufsz - pos, - "Rx Traffic idx: %u\n", priv->rx_traffic_idx); - for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) { - for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16; - entry++, ofs += 16) { - pos += scnprintf(buf + pos, bufsz - pos, - "0x%.4x ", ofs); - hex_dump_to_buffer(ptr + ofs, 16, 16, 2, - buf + pos, bufsz - pos, 0); - pos += strlen(buf + pos); - if (bufsz - pos > 0) - buf[pos++] = '\n'; - } - } - } - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} - -static ssize_t iwl_dbgfs_traffic_log_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - char buf[8]; - int buf_size; - int traffic_log; - - memset(buf, 0, sizeof(buf)); - buf_size = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - if (sscanf(buf, "%d", &traffic_log) != 1) - return -EFAULT; - if (traffic_log == 0) - iwl_reset_traffic_log(priv); - - return count; -} - static const char *fmt_value = " %-30s %10u\n"; static const char *fmt_hex = " %-30s 0x%02X\n"; static const char *fmt_table = " %-30s %10u %10u %10u %10u\n"; @@ -947,10 +756,8 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, return -EAGAIN; buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); + if (!buf) return -ENOMEM; - } /* * the statistic information display here is based on @@ -1376,10 +1183,8 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, return -EAGAIN; buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); + if (!buf) return -ENOMEM; - } /* the statistic information display here is based on * the last statistics notification from uCode @@ -1536,17 +1341,17 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, if (tx->tx_power.ant_a || tx->tx_power.ant_b || tx->tx_power.ant_c) { pos += scnprintf(buf + pos, bufsz - pos, "tx power: (1/2 dB step)\n"); - if ((hw_params(priv).valid_tx_ant & ANT_A) && + if ((priv->hw_params.valid_tx_ant & ANT_A) && tx->tx_power.ant_a) pos += scnprintf(buf + pos, bufsz - pos, fmt_hex, "antenna A:", tx->tx_power.ant_a); - if ((hw_params(priv).valid_tx_ant & ANT_B) && + if ((priv->hw_params.valid_tx_ant & ANT_B) && tx->tx_power.ant_b) pos += scnprintf(buf + pos, bufsz - pos, fmt_hex, "antenna B:", tx->tx_power.ant_b); - if ((hw_params(priv).valid_tx_ant & ANT_C) && + if ((priv->hw_params.valid_tx_ant & ANT_C) && tx->tx_power.ant_c) pos += scnprintf(buf + pos, bufsz - pos, fmt_hex, "antenna C:", @@ -1578,10 +1383,8 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, return -EAGAIN; buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); + if (!buf) return -ENOMEM; - } /* the statistic information display here is based on * the last statistics notification from uCode @@ -1704,16 +1507,11 @@ static ssize_t iwl_dbgfs_ucode_bt_stats_read(struct file *file, ret = iwl_send_statistics_request(priv, CMD_SYNC, false); mutex_unlock(&priv->mutex); - if (ret) { - IWL_ERR(priv, - "Error sending statistics request: %zd\n", ret); + if (ret) return -EAGAIN; - } buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); + if (!buf) return -ENOMEM; - } /* * the statistic information display here is based on @@ -1790,10 +1588,8 @@ static ssize_t iwl_dbgfs_reply_tx_error_read(struct file *file, return -EAGAIN; buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); + if (!buf) return -ENOMEM; - } pos += scnprintf(buf + pos, bufsz - pos, "Statistics_TX_Error:\n"); pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t\t%u\n", @@ -1933,10 +1729,8 @@ static ssize_t iwl_dbgfs_sensitivity_read(struct file *file, data = &priv->sensitivity_data; buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); + if (!buf) return -ENOMEM; - } pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm:\t\t\t %u\n", data->auto_corr_ofdm); @@ -2014,10 +1808,8 @@ static ssize_t iwl_dbgfs_chain_noise_read(struct file *file, data = &priv->chain_noise_data; buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); + if (!buf) return -ENOMEM; - } pos += scnprintf(buf + pos, bufsz - pos, "active_chains:\t\t\t %u\n", data->active_chains); @@ -2068,7 +1860,7 @@ static ssize_t iwl_dbgfs_power_save_status_read(struct file *file, const size_t bufsz = sizeof(buf); u32 pwrsave_status; - pwrsave_status = iwl_read32(trans(priv), CSR_GP_CNTRL) & + pwrsave_status = iwl_read32(priv->trans, CSR_GP_CNTRL) & CSR_GP_REG_POWER_SAVE_STATUS_MSK; pos += scnprintf(buf + pos, bufsz - pos, "Power Save Status: "); @@ -2262,59 +2054,39 @@ static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file, return count; } -static ssize_t iwl_dbgfs_force_reset_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) +static ssize_t iwl_dbgfs_rf_reset_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { struct iwl_priv *priv = file->private_data; - int i, pos = 0; + int pos = 0; char buf[300]; const size_t bufsz = sizeof(buf); - struct iwl_force_reset *force_reset; + struct iwl_rf_reset *rf_reset = &priv->rf_reset; + + pos += scnprintf(buf + pos, bufsz - pos, + "RF reset statistics\n"); + pos += scnprintf(buf + pos, bufsz - pos, + "\tnumber of reset request: %d\n", + rf_reset->reset_request_count); + pos += scnprintf(buf + pos, bufsz - pos, + "\tnumber of reset request success: %d\n", + rf_reset->reset_success_count); + pos += scnprintf(buf + pos, bufsz - pos, + "\tnumber of reset request reject: %d\n", + rf_reset->reset_reject_count); - for (i = 0; i < IWL_MAX_FORCE_RESET; i++) { - force_reset = &priv->force_reset[i]; - pos += scnprintf(buf + pos, bufsz - pos, - "Force reset method %d\n", i); - pos += scnprintf(buf + pos, bufsz - pos, - "\tnumber of reset request: %d\n", - force_reset->reset_request_count); - pos += scnprintf(buf + pos, bufsz - pos, - "\tnumber of reset request success: %d\n", - force_reset->reset_success_count); - pos += scnprintf(buf + pos, bufsz - pos, - "\tnumber of reset request reject: %d\n", - force_reset->reset_reject_count); - pos += scnprintf(buf + pos, bufsz - pos, - "\treset duration: %lu\n", - force_reset->reset_duration); - } return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } -static ssize_t iwl_dbgfs_force_reset_write(struct file *file, +static ssize_t iwl_dbgfs_rf_reset_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct iwl_priv *priv = file->private_data; - char buf[8]; - int buf_size; - int reset, ret; + int ret; - memset(buf, 0, sizeof(buf)); - buf_size = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - if (sscanf(buf, "%d", &reset) != 1) - return -EINVAL; - switch (reset) { - case IWL_RF_RESET: - case IWL_FW_RESET: - ret = iwl_force_reset(priv, reset, true); - break; - default: - return -EINVAL; - } + ret = iwl_force_rf_reset(priv, true); return ret ? ret : count; } @@ -2342,29 +2114,6 @@ static ssize_t iwl_dbgfs_txfifo_flush_write(struct file *file, return count; } -static ssize_t iwl_dbgfs_wd_timeout_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - char buf[8]; - int buf_size; - int timeout; - - memset(buf, 0, sizeof(buf)); - buf_size = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - if (sscanf(buf, "%d", &timeout) != 1) - return -EINVAL; - if (timeout < 0 || timeout > IWL_MAX_WD_TIMEOUT) - timeout = IWL_DEF_WD_TIMEOUT; - - hw_params(priv).wd_timeout = timeout; - iwl_setup_watchdog(priv); - return count; -} - static ssize_t iwl_dbgfs_bt_traffic_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -2420,10 +2169,10 @@ static ssize_t iwl_dbgfs_protection_mode_read(struct file *file, char buf[40]; const size_t bufsz = sizeof(buf); - if (cfg(priv)->ht_params) + if (priv->cfg->ht_params) pos += scnprintf(buf + pos, bufsz - pos, "use %s for aggregation\n", - (hw_params(priv).use_rts_for_aggregation) ? + (priv->hw_params.use_rts_for_aggregation) ? "rts/cts" : "cts-to-self"); else pos += scnprintf(buf + pos, bufsz - pos, "N/A"); @@ -2440,7 +2189,7 @@ static ssize_t iwl_dbgfs_protection_mode_write(struct file *file, int buf_size; int rts; - if (!cfg(priv)->ht_params) + if (!priv->cfg->ht_params) return -EINVAL; memset(buf, 0, sizeof(buf)); @@ -2450,12 +2199,29 @@ static ssize_t iwl_dbgfs_protection_mode_write(struct file *file, if (sscanf(buf, "%d", &rts) != 1) return -EINVAL; if (rts) - hw_params(priv).use_rts_for_aggregation = true; + priv->hw_params.use_rts_for_aggregation = true; else - hw_params(priv).use_rts_for_aggregation = false; + priv->hw_params.use_rts_for_aggregation = false; return count; } +static int iwl_cmd_echo_test(struct iwl_priv *priv) +{ + int ret; + struct iwl_host_cmd cmd = { + .id = REPLY_ECHO, + .len = { 0 }, + .flags = CMD_SYNC, + }; + + ret = iwl_dvm_send_cmd(priv, &cmd); + if (ret) + IWL_ERR(priv, "echo testing fail: 0X%x\n", ret); + else + IWL_DEBUG_INFO(priv, "echo testing pass\n"); + return ret; +} + static ssize_t iwl_dbgfs_echo_test_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) @@ -2473,9 +2239,93 @@ static ssize_t iwl_dbgfs_echo_test_write(struct file *file, return count; } -DEBUGFS_READ_FILE_OPS(rx_statistics); -DEBUGFS_READ_FILE_OPS(tx_statistics); -DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); +static ssize_t iwl_dbgfs_log_event_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + char *buf; + int pos = 0; + ssize_t ret = -ENOMEM; + + ret = pos = iwl_dump_nic_event_log(priv, true, &buf, true); + if (buf) { + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + } + return ret; +} + +static ssize_t iwl_dbgfs_log_event_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + u32 event_log_flag; + char buf[8]; + int buf_size; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%d", &event_log_flag) != 1) + return -EFAULT; + if (event_log_flag == 1) + iwl_dump_nic_event_log(priv, true, NULL, false); + + return count; +} + +static ssize_t iwl_dbgfs_calib_disabled_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + char buf[120]; + int pos = 0; + const size_t bufsz = sizeof(buf); + + pos += scnprintf(buf + pos, bufsz - pos, + "Sensitivity calibrations %s\n", + (priv->calib_disabled & + IWL_SENSITIVITY_CALIB_DISABLED) ? + "DISABLED" : "ENABLED"); + pos += scnprintf(buf + pos, bufsz - pos, + "Chain noise calibrations %s\n", + (priv->calib_disabled & + IWL_CHAIN_NOISE_CALIB_DISABLED) ? + "DISABLED" : "ENABLED"); + pos += scnprintf(buf + pos, bufsz - pos, + "Tx power calibrations %s\n", + (priv->calib_disabled & + IWL_TX_POWER_CALIB_DISABLED) ? + "DISABLED" : "ENABLED"); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_calib_disabled_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + char buf[8]; + u32 calib_disabled; + int buf_size; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%x", &calib_disabled) != 1) + return -EFAULT; + + priv->calib_disabled = calib_disabled; + + return count; +} + DEBUGFS_READ_FILE_OPS(ucode_rx_stats); DEBUGFS_READ_FILE_OPS(ucode_tx_stats); DEBUGFS_READ_FILE_OPS(ucode_general_stats); @@ -2483,20 +2333,20 @@ DEBUGFS_READ_FILE_OPS(sensitivity); DEBUGFS_READ_FILE_OPS(chain_noise); DEBUGFS_READ_FILE_OPS(power_save_status); DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics); -DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics); DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing); DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon); DEBUGFS_READ_WRITE_FILE_OPS(plcp_delta); -DEBUGFS_READ_WRITE_FILE_OPS(force_reset); +DEBUGFS_READ_WRITE_FILE_OPS(rf_reset); DEBUGFS_READ_FILE_OPS(rxon_flags); DEBUGFS_READ_FILE_OPS(rxon_filter_flags); DEBUGFS_WRITE_FILE_OPS(txfifo_flush); DEBUGFS_READ_FILE_OPS(ucode_bt_stats); -DEBUGFS_WRITE_FILE_OPS(wd_timeout); DEBUGFS_READ_FILE_OPS(bt_traffic); DEBUGFS_READ_WRITE_FILE_OPS(protection_mode); DEBUGFS_READ_FILE_OPS(reply_tx_error); DEBUGFS_WRITE_FILE_OPS(echo_test); +DEBUGFS_READ_WRITE_FILE_OPS(log_event); +DEBUGFS_READ_WRITE_FILE_OPS(calib_disabled); /* * Create the debugfs files and directories @@ -2537,15 +2387,11 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(temperature, dir_data, S_IRUSR); - DEBUGFS_ADD_FILE(rx_statistics, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(tx_statistics, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(traffic_log, dir_debug, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(clear_ucode_statistics, dir_debug, S_IWUSR); - DEBUGFS_ADD_FILE(clear_traffic_statistics, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(plcp_delta, dir_debug, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(force_reset, dir_debug, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(rf_reset, dir_debug, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR); @@ -2558,17 +2404,16 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR); - DEBUGFS_ADD_FILE(wd_timeout, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(echo_test, dir_debug, S_IWUSR); + DEBUGFS_ADD_FILE(log_event, dir_debug, S_IWUSR | S_IRUSR); + if (iwl_advanced_bt_coexist(priv)) DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR); - DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf, - &priv->disable_sens_cal); - DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf, - &priv->disable_chain_noise_cal); + /* Calibrations disabled/enabled status*/ + DEBUGFS_ADD_FILE(calib_disabled, dir_rf, S_IWUSR | S_IRUSR); - if (iwl_trans_dbgfs_register(trans(priv), dir_debug)) + if (iwl_trans_dbgfs_register(priv->trans, dir_debug)) goto err; return 0; diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-dev.h b/trunk/drivers/net/wireless/iwlwifi/iwl-dev.h index 16956b777f96..70062379d0ec 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -38,6 +38,7 @@ #include #include +#include "iwl-fw.h" #include "iwl-eeprom.h" #include "iwl-csr.h" #include "iwl-debug.h" @@ -47,12 +48,9 @@ #include "iwl-agn-rs.h" #include "iwl-agn-tt.h" #include "iwl-trans.h" -#include "iwl-shared.h" #include "iwl-op-mode.h" #include "iwl-notif-wait.h" -struct iwl_tx_queue; - /* CT-KILL constants */ #define CT_KILL_THRESHOLD_LEGACY 110 /* in Celsius */ #define CT_KILL_THRESHOLD 114 /* in Celsius */ @@ -196,6 +194,7 @@ struct iwl_qos_info { * These states relate to a specific RA / TID. * * @IWL_AGG_OFF: aggregation is not used + * @IWL_AGG_STARTING: aggregation are starting (between start and oper) * @IWL_AGG_ON: aggregation session is up * @IWL_EMPTYING_HW_QUEUE_ADDBA: establishing a BA session - waiting for the * HW queue to be empty from packets for this RA /TID. @@ -204,6 +203,7 @@ struct iwl_qos_info { */ enum iwl_agg_state { IWL_AGG_OFF = 0, + IWL_AGG_STARTING, IWL_AGG_ON, IWL_EMPTYING_HW_QUEUE_ADDBA, IWL_EMPTYING_HW_QUEUE_DELBA, @@ -220,8 +220,7 @@ enum iwl_agg_state { * Tx response (REPLY_TX), and the block ack notification * (REPLY_COMPRESSED_BA). * @state: state of the BA agreement establishment / tear down. - * @txq_id: Tx queue used by the BA session - used by the transport layer. - * Needed by the upper layer for debugfs only. + * @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 * the first packet to be sent in legacy HW queue in Tx AGG stop flow. * Basically when next_reclaimed reaches ssn, we can tell mac80211 that @@ -507,44 +506,6 @@ struct reply_agg_tx_error_statistics { u32 unknown; }; -/* management statistics */ -enum iwl_mgmt_stats { - MANAGEMENT_ASSOC_REQ = 0, - MANAGEMENT_ASSOC_RESP, - MANAGEMENT_REASSOC_REQ, - MANAGEMENT_REASSOC_RESP, - MANAGEMENT_PROBE_REQ, - MANAGEMENT_PROBE_RESP, - MANAGEMENT_BEACON, - MANAGEMENT_ATIM, - MANAGEMENT_DISASSOC, - MANAGEMENT_AUTH, - MANAGEMENT_DEAUTH, - MANAGEMENT_ACTION, - MANAGEMENT_MAX, -}; -/* control statistics */ -enum iwl_ctrl_stats { - CONTROL_BACK_REQ = 0, - CONTROL_BACK, - CONTROL_PSPOLL, - CONTROL_RTS, - CONTROL_CTS, - CONTROL_ACK, - CONTROL_CFEND, - CONTROL_CFENDACK, - CONTROL_MAX, -}; - -struct traffic_stats { -#ifdef CONFIG_IWLWIFI_DEBUGFS - u32 mgmt[MANAGEMENT_MAX]; - u32 ctrl[CONTROL_MAX]; - u32 data_cnt; - u64 data_bytes; -#endif -}; - /* * schedule the timer to wake up every UCODE_TRACE_PERIOD milliseconds * to perform continuous uCode event logging operation if enabled @@ -571,24 +532,7 @@ struct iwl_event_log { int wraps_more_count; }; -/* - * This is the threshold value of plcp error rate per 100mSecs. It is - * used to set and check for the validity of plcp_delta. - */ -#define IWL_MAX_PLCP_ERR_THRESHOLD_MIN (1) -#define IWL_MAX_PLCP_ERR_THRESHOLD_DEF (50) -#define IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF (100) -#define IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF (200) -#define IWL_MAX_PLCP_ERR_THRESHOLD_MAX (255) -#define IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE (0) - #define IWL_DELAY_NEXT_FORCE_RF_RESET (HZ*3) -#define IWL_DELAY_NEXT_FORCE_FW_RELOAD (HZ*5) - -/* TX queue watchdog timeouts in mSecs */ -#define IWL_DEF_WD_TIMEOUT (2000) -#define IWL_LONG_WD_TIMEOUT (10000) -#define IWL_MAX_WD_TIMEOUT (120000) /* BT Antenna Coupling Threshold (dB) */ #define IWL_BT_ANTENNA_COUPLING_THRESHOLD (35) @@ -598,18 +542,18 @@ struct iwl_event_log { #define IWL_MAX_CONTINUE_RELOAD_CNT 4 -enum iwl_reset { - IWL_RF_RESET = 0, - IWL_FW_RESET, - IWL_MAX_FORCE_RESET, -}; - -struct iwl_force_reset { +struct iwl_rf_reset { int reset_request_count; int reset_success_count; int reset_reject_count; - unsigned long reset_duration; - unsigned long last_force_reset_jiffies; + unsigned long last_reset_jiffies; +}; + +enum iwl_rxon_context_id { + IWL_RXON_CTX_BSS, + IWL_RXON_CTX_PAN, + + NUM_IWL_RXON_CTX }; /* extend beacon time format bit shifting */ @@ -623,6 +567,10 @@ struct iwl_force_reset { struct iwl_rxon_context { struct ieee80211_vif *vif; + u8 mcast_queue; + u8 ac_to_queue[IEEE80211_NUM_ACS]; + u8 ac_to_fifo[IEEE80211_NUM_ACS]; + /* * We could use the vif to indicate active, but we * also need it to be active during disabling when @@ -677,6 +625,52 @@ enum iwl_scan_type { IWL_SCAN_ROC, }; +/** + * struct iwl_hw_params + * + * Holds the module parameters + * + * @tx_chains_num: Number of TX chains + * @rx_chains_num: Number of RX chains + * @valid_tx_ant: usable antennas for TX + * @valid_rx_ant: usable antennas for RX + * @ht40_channel: is 40MHz width possible: BIT(IEEE80211_BAND_XXX) + * @sku: sku read from EEPROM + * @ct_kill_threshold: temperature threshold - in hw dependent unit + * @ct_kill_exit_threshold: when to reeable the device - in hw dependent unit + * relevant for 1000, 6000 and up + * @struct iwl_sensitivity_ranges: range of sensitivity values + * @use_rts_for_aggregation: use rts/cts protection for HT traffic + */ +struct iwl_hw_params { + u8 tx_chains_num; + u8 rx_chains_num; + u8 valid_tx_ant; + u8 valid_rx_ant; + u8 ht40_channel; + bool use_rts_for_aggregation; + u16 sku; + u32 ct_kill_threshold; + u32 ct_kill_exit_threshold; + + const struct iwl_sensitivity_ranges *sens; +}; + +struct iwl_lib_ops { + /* set hw dependent parameters */ + void (*set_hw_params)(struct iwl_priv *priv); + int (*set_channel_switch)(struct iwl_priv *priv, + struct ieee80211_channel_switch *ch_switch); + /* device specific configuration */ + void (*nic_config)(struct iwl_priv *priv); + + /* eeprom operations (as defined in iwl-eeprom.h) */ + struct iwl_eeprom_ops eeprom_ops; + + /* temperature */ + void (*temperature)(struct iwl_priv *priv); +}; + #ifdef CONFIG_IWLWIFI_DEVICE_TESTMODE struct iwl_testmode_trace { u32 buff_size; @@ -701,6 +695,17 @@ struct iwl_wipan_noa_data { u8 data[]; }; +/* Calibration disabling bit mask */ +enum { + IWL_CALIB_ENABLE_ALL = 0, + + IWL_SENSITIVITY_CALIB_DISABLED = BIT(0), + IWL_CHAIN_NOISE_CALIB_DISABLED = BIT(1), + IWL_TX_POWER_CALIB_DISABLED = BIT(2), + + IWL_CALIB_DISABLE_ALL = 0xFFFFFFFF, +}; + #define IWL_OP_MODE_GET_DVM(_iwl_op_mode) \ ((struct iwl_priv *) ((_iwl_op_mode)->op_mode_specific)) @@ -710,9 +715,11 @@ struct iwl_wipan_noa_data { struct iwl_priv { - /*data shared among all the driver's layers */ - struct iwl_shared *shrd; + struct iwl_trans *trans; + struct device *dev; /* for debug prints only */ + const struct iwl_cfg *cfg; const struct iwl_fw *fw; + const struct iwl_lib_ops *lib; unsigned long status; spinlock_t sta_lock; @@ -720,6 +727,11 @@ struct iwl_priv { unsigned long transport_queue_stop; bool passive_no_rx; +#define IWL_INVALID_MAC80211_QUEUE 0xff + u8 queue_to_mac80211[IWL_MAX_HW_QUEUES]; + atomic_t queue_stop_count[IWL_MAX_HW_QUEUES]; + + unsigned long agg_q_alloc[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)]; /* ieee device used by generic ieee processing code */ struct ieee80211_hw *hw; @@ -730,7 +742,10 @@ struct iwl_priv { struct workqueue_struct *workqueue; + struct iwl_hw_params hw_params; + enum ieee80211_band band; + u8 valid_contexts; void (*pre_rx_handler)(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb); @@ -763,8 +778,8 @@ struct iwl_priv { /*counters */ u32 rx_handlers_stats[REPLY_MAX]; - /* force reset */ - struct iwl_force_reset force_reset[IWL_MAX_FORCE_RESET]; + /* rf reset */ + struct iwl_rf_reset rf_reset; /* firmware reload counter and timestamp */ unsigned long reload_jiffies; @@ -810,8 +825,6 @@ struct iwl_priv { __le16 switch_channel; - u16 active_rate; - u8 start_calib; struct iwl_sensitivity_data sensitivity_data; struct iwl_chain_noise_data chain_noise_data; @@ -825,10 +838,6 @@ struct iwl_priv { int activity_timer_active; - /* counts mgmt, ctl, and data packets */ - struct traffic_stats tx_stats; - struct traffic_stats rx_stats; - struct iwl_power_mgr power_data; struct iwl_tt_mgmt thermal_throttle; @@ -912,6 +921,7 @@ struct iwl_priv { __le32 kill_ack_mask; __le32 kill_cts_mask; __le16 bt_valid; + bool reduced_txpower; u16 bt_on_thresh; u16 bt_duration; u16 dynamic_frag_thresh; @@ -948,23 +958,21 @@ struct iwl_priv { #ifdef CONFIG_IWLWIFI_DEBUGFS /* debugfs */ - u16 tx_traffic_idx; - u16 rx_traffic_idx; - u8 *tx_traffic; - u8 *rx_traffic; struct dentry *debugfs_dir; u32 dbgfs_sram_offset, dbgfs_sram_len; bool disable_ht40; void *wowlan_sram; #endif /* CONFIG_IWLWIFI_DEBUGFS */ + /* eeprom -- this is in the card's little endian byte order */ + u8 *eeprom; + enum iwl_nvm_type nvm_device_type; + struct work_struct txpower_work; - u32 disable_sens_cal; - u32 disable_chain_noise_cal; + u32 calib_disabled; struct work_struct run_time_calib_work; struct timer_list statistics_periodic; struct timer_list ucode_trace; - struct timer_list watchdog; struct iwl_event_log event_log; @@ -982,10 +990,18 @@ struct iwl_priv { __le64 replay_ctr; __le16 last_seq_ctl; bool have_rekey_data; + + /* device_pointers: pointers to ucode event tables */ + struct { + u32 error_event_table; + u32 log_event_table; + } device_pointers; + + /* indicator of loaded ucode image */ + enum iwl_ucode_type cur_ucode; }; /*iwl_priv */ extern struct kmem_cache *iwl_tx_cmd_pool; -extern struct iwl_mod_params iwlagn_mod_params; static inline struct iwl_rxon_context * iwl_rxon_ctx_from_vif(struct ieee80211_vif *vif) @@ -998,7 +1014,7 @@ iwl_rxon_ctx_from_vif(struct ieee80211_vif *vif) #define for_each_context(priv, ctx) \ for (ctx = &priv->contexts[IWL_RXON_CTX_BSS]; \ ctx < &priv->contexts[NUM_IWL_RXON_CTX]; ctx++) \ - if (priv->shrd->valid_contexts & BIT(ctx->ctxid)) + if (priv->valid_contexts & BIT(ctx->ctxid)) static inline int iwl_is_associated_ctx(struct iwl_rxon_context *ctx) { diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-drv.c b/trunk/drivers/net/wireless/iwlwifi/iwl-drv.c index 6f312c77af5e..3c72bad0ae56 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -66,10 +66,13 @@ #include #include "iwl-drv.h" +#include "iwl-debug.h" #include "iwl-trans.h" -#include "iwl-shared.h" #include "iwl-op-mode.h" #include "iwl-agn-hw.h" +#include "iwl-fw.h" +#include "iwl-config.h" +#include "iwl-modparams.h" /* private includes */ #include "iwl-fw-file.h" @@ -77,8 +80,10 @@ /** * struct iwl_drv - drv common data * @fw: the iwl_fw structure - * @shrd: pointer to common shared structure * @op_mode: the running op_mode + * @trans: transport layer + * @dev: for debug prints only + * @cfg: configuration struct * @fw_index: firmware revision to try loading * @firmware_name: composite filename of ucode file to load * @request_firmware_complete: the firmware has been obtained from user space @@ -86,8 +91,10 @@ struct iwl_drv { struct iwl_fw fw; - struct iwl_shared *shrd; struct iwl_op_mode *op_mode; + struct iwl_trans *trans; + struct device *dev; + const struct iwl_cfg *cfg; int fw_index; /* firmware we're trying to load */ char firmware_name[25]; /* name of firmware file to load */ @@ -110,7 +117,7 @@ struct fw_sec { static void iwl_free_fw_desc(struct iwl_drv *drv, struct fw_desc *desc) { if (desc->v_addr) - dma_free_coherent(trans(drv)->dev, desc->len, + dma_free_coherent(drv->trans->dev, desc->len, desc->v_addr, desc->p_addr); desc->v_addr = NULL; desc->len = 0; @@ -138,7 +145,7 @@ static int iwl_alloc_fw_desc(struct iwl_drv *drv, struct fw_desc *desc, return -EINVAL; } - desc->v_addr = dma_alloc_coherent(trans(drv)->dev, sec->size, + desc->v_addr = dma_alloc_coherent(drv->trans->dev, sec->size, &desc->p_addr, GFP_KERNEL); if (!desc->v_addr) return -ENOMEM; @@ -156,8 +163,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); static int iwl_request_firmware(struct iwl_drv *drv, bool first) { - const struct iwl_cfg *cfg = cfg(drv); - const char *name_pre = cfg->fw_name_pre; + const char *name_pre = drv->cfg->fw_name_pre; char tag[8]; if (first) { @@ -166,14 +172,14 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) strcpy(tag, UCODE_EXPERIMENTAL_TAG); } else if (drv->fw_index == UCODE_EXPERIMENTAL_INDEX) { #endif - drv->fw_index = cfg->ucode_api_max; + drv->fw_index = drv->cfg->ucode_api_max; sprintf(tag, "%d", drv->fw_index); } else { drv->fw_index--; sprintf(tag, "%d", drv->fw_index); } - if (drv->fw_index < cfg->ucode_api_min) { + if (drv->fw_index < drv->cfg->ucode_api_min) { IWL_ERR(drv, "no suitable firmware found!\n"); return -ENOENT; } @@ -186,7 +192,7 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) drv->firmware_name); return request_firmware_nowait(THIS_MODULE, 1, drv->firmware_name, - trans(drv)->dev, + drv->trans->dev, GFP_KERNEL, drv, iwl_ucode_callback); } @@ -284,6 +290,7 @@ static int iwl_store_ucode_sec(struct iwl_firmware_pieces *pieces, sec->offset = le32_to_cpu(sec_parse->offset); sec->data = sec_parse->data; + sec->size = size - sizeof(sec_parse->offset); ++img->sec_counter; @@ -414,9 +421,6 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, struct iwl_ucode_tlv *tlv; size_t len = ucode_raw->size; const u8 *data; - int wanted_alternative = iwlagn_mod_params.wanted_ucode_alternative; - int tmp; - u64 alternatives; u32 tlv_len; enum iwl_ucode_tlv_type tlv_type; const u8 *tlv_data; @@ -434,23 +438,6 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, return -EINVAL; } - /* - * Check which alternatives are present, and "downgrade" - * when the chosen alternative is not present, warning - * the user when that happens. Some files may not have - * any alternatives, so don't warn in that case. - */ - alternatives = le64_to_cpu(ucode->alternatives); - tmp = wanted_alternative; - if (wanted_alternative > 63) - wanted_alternative = 63; - while (wanted_alternative && !(alternatives & BIT(wanted_alternative))) - wanted_alternative--; - if (wanted_alternative && wanted_alternative != tmp) - IWL_WARN(drv, - "uCode alternative %d not available, choosing %d\n", - tmp, wanted_alternative); - drv->fw.ucode_ver = le32_to_cpu(ucode->ver); build = le32_to_cpu(ucode->build); @@ -475,14 +462,11 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, len -= sizeof(*ucode); while (len >= sizeof(*tlv)) { - u16 tlv_alt; - len -= sizeof(*tlv); tlv = (void *)data; tlv_len = le32_to_cpu(tlv->length); - tlv_type = le16_to_cpu(tlv->type); - tlv_alt = le16_to_cpu(tlv->alternative); + tlv_type = le32_to_cpu(tlv->type); tlv_data = tlv->data; if (len < tlv_len) { @@ -493,14 +477,6 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, len -= ALIGN(tlv_len, 4); data += sizeof(*tlv) + ALIGN(tlv_len, 4); - /* - * Alternative 0 is always valid. - * - * Skip alternative TLVs that are not selected. - */ - if (tlv_alt != 0 && tlv_alt != wanted_alternative) - continue; - switch (tlv_type) { case IWL_UCODE_TLV_INST: set_sec_data(pieces, IWL_UCODE_REGULAR, @@ -755,14 +731,13 @@ static int validate_sec_sizes(struct iwl_drv *drv, static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) { struct iwl_drv *drv = context; - const struct iwl_cfg *cfg = cfg(drv); struct iwl_fw *fw = &drv->fw; struct iwl_ucode_header *ucode; int err; struct iwl_firmware_pieces pieces; - const unsigned int api_max = cfg->ucode_api_max; - unsigned int api_ok = cfg->ucode_api_ok; - const unsigned int api_min = cfg->ucode_api_min; + const unsigned int api_max = drv->cfg->ucode_api_max; + unsigned int api_ok = drv->cfg->ucode_api_ok; + const unsigned int api_min = drv->cfg->ucode_api_min; u32 api_ver; int i; @@ -837,47 +812,11 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) IWL_INFO(drv, "loaded firmware version %s", drv->fw.fw_version); - /* - * For any of the failures below (before allocating pci memory) - * we will try to load a version with a smaller API -- maybe the - * user just got a corrupted version of the latest API. - */ - - IWL_DEBUG_INFO(drv, "f/w package hdr ucode version raw = 0x%x\n", - drv->fw.ucode_ver); - IWL_DEBUG_INFO(drv, "f/w package hdr runtime inst size = %Zd\n", - get_sec_size(&pieces, IWL_UCODE_REGULAR, - IWL_UCODE_SECTION_INST)); - IWL_DEBUG_INFO(drv, "f/w package hdr runtime data size = %Zd\n", - get_sec_size(&pieces, IWL_UCODE_REGULAR, - IWL_UCODE_SECTION_DATA)); - IWL_DEBUG_INFO(drv, "f/w package hdr init inst size = %Zd\n", - get_sec_size(&pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST)); - IWL_DEBUG_INFO(drv, "f/w package hdr init data size = %Zd\n", - get_sec_size(&pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA)); - - /* Verify that uCode images will fit in card's SRAM */ - if (get_sec_size(&pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST) > - cfg->max_inst_size) { - IWL_ERR(drv, "uCode instr len %Zd too large to fit in\n", - get_sec_size(&pieces, IWL_UCODE_REGULAR, - IWL_UCODE_SECTION_INST)); - goto try_again; - } - - if (get_sec_size(&pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA) > - cfg->max_data_size) { - IWL_ERR(drv, "uCode data len %Zd too large to fit in\n", - get_sec_size(&pieces, IWL_UCODE_REGULAR, - IWL_UCODE_SECTION_DATA)); - goto try_again; - } - /* * In mvm uCode there is no difference between data and instructions * sections. */ - if (!fw->mvm_fw && validate_sec_sizes(drv, &pieces, cfg)) + if (!fw->mvm_fw && validate_sec_sizes(drv, &pieces, drv->cfg)) goto try_again; /* Allocate ucode buffers for card's bus-master loading ... */ @@ -901,14 +840,14 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) fw->init_evtlog_size = (pieces.init_evtlog_size - 16)/12; else fw->init_evtlog_size = - cfg->base_params->max_event_log_size; + drv->cfg->base_params->max_event_log_size; fw->init_errlog_ptr = pieces.init_errlog_ptr; fw->inst_evtlog_ptr = pieces.inst_evtlog_ptr; if (pieces.inst_evtlog_size) fw->inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12; else fw->inst_evtlog_size = - cfg->base_params->max_event_log_size; + drv->cfg->base_params->max_event_log_size; fw->inst_errlog_ptr = pieces.inst_errlog_ptr; /* @@ -924,7 +863,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) release_firmware(ucode_raw); complete(&drv->request_firmware_complete); - drv->op_mode = iwl_dvm_ops.start(drv->shrd->trans, &drv->fw); + drv->op_mode = iwl_dvm_ops.start(drv->trans, drv->cfg, &drv->fw); if (!drv->op_mode) goto out_unbind; @@ -944,42 +883,38 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) release_firmware(ucode_raw); out_unbind: complete(&drv->request_firmware_complete); - device_release_driver(trans(drv)->dev); + device_release_driver(drv->trans->dev); } -int iwl_drv_start(struct iwl_shared *shrd, - struct iwl_trans *trans, const struct iwl_cfg *cfg) +struct iwl_drv *iwl_drv_start(struct iwl_trans *trans, + const struct iwl_cfg *cfg) { struct iwl_drv *drv; int ret; - shrd->cfg = cfg; - drv = kzalloc(sizeof(*drv), GFP_KERNEL); - if (!drv) { - dev_printk(KERN_ERR, trans->dev, "Couldn't allocate iwl_drv"); - return -ENOMEM; - } - drv->shrd = shrd; - shrd->drv = drv; + if (!drv) + return NULL; + + drv->trans = trans; + drv->dev = trans->dev; + drv->cfg = cfg; init_completion(&drv->request_firmware_complete); ret = iwl_request_firmware(drv, true); if (ret) { - dev_printk(KERN_ERR, trans->dev, "Couldn't request the fw"); + IWL_ERR(trans, "Couldn't request the fw\n"); kfree(drv); - shrd->drv = NULL; + drv = NULL; } - return ret; + return drv; } -void iwl_drv_stop(struct iwl_shared *shrd) +void iwl_drv_stop(struct iwl_drv *drv) { - struct iwl_drv *drv = shrd->drv; - wait_for_completion(&drv->request_firmware_complete); /* op_mode can be NULL if its start failed */ @@ -989,5 +924,95 @@ void iwl_drv_stop(struct iwl_shared *shrd) iwl_dealloc_ucode(drv); kfree(drv); - shrd->drv = NULL; } + + +/* shared module parameters */ +struct iwl_mod_params iwlwifi_mod_params = { + .amsdu_size_8K = 1, + .restart_fw = 1, + .plcp_check = true, + .bt_coex_active = true, + .power_level = IWL_POWER_INDEX_1, + .bt_ch_announce = true, + .auto_agg = true, + /* the rest are 0 by default */ +}; + +#ifdef CONFIG_IWLWIFI_DEBUG +module_param_named(debug, iwlwifi_mod_params.debug_level, uint, + S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "debug output mask"); +#endif + +module_param_named(swcrypto, iwlwifi_mod_params.sw_crypto, int, S_IRUGO); +MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); +module_param_named(11n_disable, iwlwifi_mod_params.disable_11n, uint, S_IRUGO); +MODULE_PARM_DESC(11n_disable, + "disable 11n functionality, bitmap: 1: full, 2: agg TX, 4: agg RX"); +module_param_named(amsdu_size_8K, iwlwifi_mod_params.amsdu_size_8K, + int, S_IRUGO); +MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size"); +module_param_named(fw_restart, iwlwifi_mod_params.restart_fw, int, S_IRUGO); +MODULE_PARM_DESC(fw_restart, "restart firmware in case of error"); + +module_param_named(antenna_coupling, iwlwifi_mod_params.ant_coupling, + int, S_IRUGO); +MODULE_PARM_DESC(antenna_coupling, + "specify antenna coupling in dB (defualt: 0 dB)"); + +module_param_named(bt_ch_inhibition, iwlwifi_mod_params.bt_ch_announce, + bool, S_IRUGO); +MODULE_PARM_DESC(bt_ch_inhibition, + "Enable BT channel inhibition (default: enable)"); + +module_param_named(plcp_check, iwlwifi_mod_params.plcp_check, bool, S_IRUGO); +MODULE_PARM_DESC(plcp_check, "Check plcp health (default: 1 [enabled])"); + +module_param_named(wd_disable, iwlwifi_mod_params.wd_disable, int, S_IRUGO); +MODULE_PARM_DESC(wd_disable, + "Disable stuck queue watchdog timer 0=system default, " + "1=disable, 2=enable (default: 0)"); + +/* + * set bt_coex_active to true, uCode will do kill/defer + * every time the priority line is asserted (BT is sending signals on the + * priority line in the PCIx). + * set bt_coex_active to false, uCode will ignore the BT activity and + * perform the normal operation + * + * User might experience transmit issue on some platform due to WiFi/BT + * co-exist problem. The possible behaviors are: + * Able to scan and finding all the available AP + * Not able to associate with any AP + * On those platforms, WiFi communication can be restored by set + * "bt_coex_active" module parameter to "false" + * + * default: bt_coex_active = true (BT_COEX_ENABLE) + */ +module_param_named(bt_coex_active, iwlwifi_mod_params.bt_coex_active, + bool, S_IRUGO); +MODULE_PARM_DESC(bt_coex_active, "enable wifi/bt co-exist (default: enable)"); + +module_param_named(led_mode, iwlwifi_mod_params.led_mode, int, S_IRUGO); +MODULE_PARM_DESC(led_mode, "0=system default, " + "1=On(RF On)/Off(RF Off), 2=blinking, 3=Off (default: 0)"); + +module_param_named(power_save, iwlwifi_mod_params.power_save, + bool, S_IRUGO); +MODULE_PARM_DESC(power_save, + "enable WiFi power management (default: disable)"); + +module_param_named(power_level, iwlwifi_mod_params.power_level, + int, S_IRUGO); +MODULE_PARM_DESC(power_level, + "default power save level (range from 1 - 5, default: 1)"); + +module_param_named(auto_agg, iwlwifi_mod_params.auto_agg, + bool, S_IRUGO); +MODULE_PARM_DESC(auto_agg, + "enable agg w/o check traffic load (default: enable)"); + +module_param_named(5ghz_disable, iwlwifi_mod_params.disable_5ghz, + bool, S_IRUGO); +MODULE_PARM_DESC(5ghz_disable, "disable 5GHz band (default: 0 [enabled])"); diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-drv.h b/trunk/drivers/net/wireless/iwlwifi/iwl-drv.h index 3b771c1d9096..2cbf137b25bf 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-drv.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-drv.h @@ -63,7 +63,12 @@ #ifndef __iwl_drv_h__ #define __iwl_drv_h__ -#include "iwl-shared.h" +/* for all modules */ +#define DRV_NAME "iwlwifi" +#define IWLWIFI_VERSION "in-tree:" +#define DRV_COPYRIGHT "Copyright(c) 2003-2012 Intel Corporation" +#define DRV_AUTHOR "" + /** * DOC: Driver system flows - drv component @@ -90,34 +95,32 @@ * 8) iwl_ucode_callback starts the wifi implementation to matches the fw */ +struct iwl_drv; +struct iwl_trans; +struct iwl_cfg; /** * iwl_drv_start - start the drv * - * @shrd: the shrd area * @trans_ops: the ops of the transport * @cfg: device specific constants / virtual functions * - * TODO: review the parameters given to this function - * * starts the driver: fetches the firmware. This should be called by bus * specific system flows implementations. For example, the bus specific probe * function should do bus related operations only, and then call to this - * function. + * function. It returns the driver object or %NULL if an error occured. */ -int iwl_drv_start(struct iwl_shared *shrd, - struct iwl_trans *trans, const struct iwl_cfg *cfg); +struct iwl_drv *iwl_drv_start(struct iwl_trans *trans, + const struct iwl_cfg *cfg); /** * iwl_drv_stop - stop the drv * - * @shrd: the shrd area - * - * TODO: review the parameters given to this function + * @drv: * * Stop the driver. This should be called by bus specific system flows * implementations. For example, the bus specific remove function should first * call this function and then do the bus related operations only. */ -void iwl_drv_stop(struct iwl_shared *shrd); +void iwl_drv_stop(struct iwl_drv *drv); #endif /* __iwl_drv_h__ */ diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 23cea42b9495..50c58911e718 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -68,9 +68,7 @@ #include -#include "iwl-commands.h" #include "iwl-dev.h" -#include "iwl-core.h" #include "iwl-debug.h" #include "iwl-agn.h" #include "iwl-eeprom.h" @@ -187,33 +185,33 @@ static void iwl_eeprom_release_semaphore(struct iwl_trans *trans) } -static int iwl_eeprom_verify_signature(struct iwl_trans *trans) +static int iwl_eeprom_verify_signature(struct iwl_priv *priv) { - u32 gp = iwl_read32(trans, CSR_EEPROM_GP) & + u32 gp = iwl_read32(priv->trans, CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK; int ret = 0; - IWL_DEBUG_EEPROM(trans, "EEPROM signature=0x%08x\n", gp); + IWL_DEBUG_EEPROM(priv, "EEPROM signature=0x%08x\n", gp); switch (gp) { case CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP: - if (trans->nvm_device_type != NVM_DEVICE_TYPE_OTP) { - IWL_ERR(trans, "EEPROM with bad signature: 0x%08x\n", + if (priv->nvm_device_type != NVM_DEVICE_TYPE_OTP) { + IWL_ERR(priv, "EEPROM with bad signature: 0x%08x\n", gp); ret = -ENOENT; } break; case CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K: case CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K: - if (trans->nvm_device_type != NVM_DEVICE_TYPE_EEPROM) { - IWL_ERR(trans, "OTP with bad signature: 0x%08x\n", gp); + if (priv->nvm_device_type != NVM_DEVICE_TYPE_EEPROM) { + IWL_ERR(priv, "OTP with bad signature: 0x%08x\n", gp); ret = -ENOENT; } break; case CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP: default: - IWL_ERR(trans, "bad EEPROM/OTP signature, type=%s, " + IWL_ERR(priv, "bad EEPROM/OTP signature, type=%s, " "EEPROM_GP=0x%08x\n", - (trans->nvm_device_type == NVM_DEVICE_TYPE_OTP) + (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) ? "OTP" : "EEPROM", gp); ret = -ENOENT; break; @@ -221,11 +219,11 @@ static int iwl_eeprom_verify_signature(struct iwl_trans *trans) return ret; } -u16 iwl_eeprom_query16(const struct iwl_shared *shrd, size_t offset) +u16 iwl_eeprom_query16(struct iwl_priv *priv, size_t offset) { - if (!shrd->eeprom) + if (!priv->eeprom) return 0; - return (u16)shrd->eeprom[offset] | ((u16)shrd->eeprom[offset + 1] << 8); + return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8); } int iwl_eeprom_check_version(struct iwl_priv *priv) @@ -233,11 +231,11 @@ int iwl_eeprom_check_version(struct iwl_priv *priv) u16 eeprom_ver; u16 calib_ver; - eeprom_ver = iwl_eeprom_query16(priv->shrd, EEPROM_VERSION); - calib_ver = iwl_eeprom_calib_version(priv->shrd); + eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); + calib_ver = iwl_eeprom_calib_version(priv); - if (eeprom_ver < cfg(priv)->eeprom_ver || - calib_ver < cfg(priv)->eeprom_calib_ver) + if (eeprom_ver < priv->cfg->eeprom_ver || + calib_ver < priv->cfg->eeprom_calib_ver) goto err; IWL_INFO(priv, "device EEPROM VER=0x%x, CALIB=0x%x\n", @@ -247,58 +245,115 @@ int iwl_eeprom_check_version(struct iwl_priv *priv) err: IWL_ERR(priv, "Unsupported (too old) EEPROM VER=0x%x < 0x%x " "CALIB=0x%x < 0x%x\n", - eeprom_ver, cfg(priv)->eeprom_ver, - calib_ver, cfg(priv)->eeprom_calib_ver); + eeprom_ver, priv->cfg->eeprom_ver, + calib_ver, priv->cfg->eeprom_calib_ver); return -EINVAL; } int iwl_eeprom_init_hw_params(struct iwl_priv *priv) { - struct iwl_shared *shrd = priv->shrd; u16 radio_cfg; - hw_params(priv).sku = iwl_eeprom_query16(shrd, EEPROM_SKU_CAP); - if (hw_params(priv).sku & EEPROM_SKU_CAP_11N_ENABLE && - !cfg(priv)->ht_params) { + priv->hw_params.sku = iwl_eeprom_query16(priv, EEPROM_SKU_CAP); + if (priv->hw_params.sku & EEPROM_SKU_CAP_11N_ENABLE && + !priv->cfg->ht_params) { IWL_ERR(priv, "Invalid 11n configuration\n"); return -EINVAL; } - if (!hw_params(priv).sku) { + if (!priv->hw_params.sku) { IWL_ERR(priv, "Invalid device sku\n"); return -EINVAL; } - IWL_INFO(priv, "Device SKU: 0x%X\n", hw_params(priv).sku); + IWL_INFO(priv, "Device SKU: 0x%X\n", priv->hw_params.sku); - radio_cfg = iwl_eeprom_query16(shrd, EEPROM_RADIO_CONFIG); + radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); - hw_params(priv).valid_tx_ant = EEPROM_RF_CFG_TX_ANT_MSK(radio_cfg); - hw_params(priv).valid_rx_ant = EEPROM_RF_CFG_RX_ANT_MSK(radio_cfg); + priv->hw_params.valid_tx_ant = EEPROM_RF_CFG_TX_ANT_MSK(radio_cfg); + priv->hw_params.valid_rx_ant = EEPROM_RF_CFG_RX_ANT_MSK(radio_cfg); /* check overrides (some devices have wrong EEPROM) */ - if (cfg(priv)->valid_tx_ant) - hw_params(priv).valid_tx_ant = cfg(priv)->valid_tx_ant; - if (cfg(priv)->valid_rx_ant) - hw_params(priv).valid_rx_ant = cfg(priv)->valid_rx_ant; + if (priv->cfg->valid_tx_ant) + priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; + if (priv->cfg->valid_rx_ant) + priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant; - if (!hw_params(priv).valid_tx_ant || !hw_params(priv).valid_rx_ant) { + if (!priv->hw_params.valid_tx_ant || !priv->hw_params.valid_rx_ant) { IWL_ERR(priv, "Invalid chain (0x%X, 0x%X)\n", - hw_params(priv).valid_tx_ant, - hw_params(priv).valid_rx_ant); + priv->hw_params.valid_tx_ant, + priv->hw_params.valid_rx_ant); return -EINVAL; } IWL_INFO(priv, "Valid Tx ant: 0x%X, Valid Rx ant: 0x%X\n", - hw_params(priv).valid_tx_ant, hw_params(priv).valid_rx_ant); + priv->hw_params.valid_tx_ant, priv->hw_params.valid_rx_ant); return 0; } -void iwl_eeprom_get_mac(const struct iwl_shared *shrd, u8 *mac) +u16 iwl_eeprom_calib_version(struct iwl_priv *priv) { - const u8 *addr = iwl_eeprom_query_addr(shrd, + struct iwl_eeprom_calib_hdr *hdr; + + hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv, + EEPROM_CALIB_ALL); + return hdr->version; +} + +static u32 eeprom_indirect_address(struct iwl_priv *priv, u32 address) +{ + u16 offset = 0; + + if ((address & INDIRECT_ADDRESS) == 0) + return address; + + switch (address & INDIRECT_TYPE_MSK) { + case INDIRECT_HOST: + offset = iwl_eeprom_query16(priv, EEPROM_LINK_HOST); + break; + case INDIRECT_GENERAL: + offset = iwl_eeprom_query16(priv, EEPROM_LINK_GENERAL); + break; + case INDIRECT_REGULATORY: + offset = iwl_eeprom_query16(priv, EEPROM_LINK_REGULATORY); + break; + case INDIRECT_TXP_LIMIT: + offset = iwl_eeprom_query16(priv, EEPROM_LINK_TXP_LIMIT); + break; + case INDIRECT_TXP_LIMIT_SIZE: + offset = iwl_eeprom_query16(priv, EEPROM_LINK_TXP_LIMIT_SIZE); + break; + case INDIRECT_CALIBRATION: + offset = iwl_eeprom_query16(priv, EEPROM_LINK_CALIBRATION); + break; + case INDIRECT_PROCESS_ADJST: + offset = iwl_eeprom_query16(priv, EEPROM_LINK_PROCESS_ADJST); + break; + case INDIRECT_OTHERS: + offset = iwl_eeprom_query16(priv, EEPROM_LINK_OTHERS); + break; + default: + IWL_ERR(priv, "illegal indirect type: 0x%X\n", + address & INDIRECT_TYPE_MSK); + break; + } + + /* translate the offset from words to byte */ + return (address & ADDRESS_MSK) + (offset << 1); +} + +const u8 *iwl_eeprom_query_addr(struct iwl_priv *priv, size_t offset) +{ + u32 address = eeprom_indirect_address(priv, offset); + BUG_ON(address >= priv->cfg->base_params->eeprom_size); + return &priv->eeprom[address]; +} + +void iwl_eeprom_get_mac(struct iwl_priv *priv, u8 *mac) +{ + const u8 *addr = iwl_eeprom_query_addr(priv, EEPROM_MAC_ADDRESS); memcpy(mac, addr, ETH_ALEN); } @@ -376,7 +431,7 @@ static int iwl_init_otp_access(struct iwl_trans *trans) * CSR auto clock gate disable bit - * this is only applicable for HW with OTP shadow RAM */ - if (cfg(trans)->base_params->shadow_ram_support) + if (trans->cfg->base_params->shadow_ram_support) iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, CSR_RESET_LINK_PWR_MGMT_DISABLED); } @@ -497,7 +552,7 @@ static int iwl_find_otp_image(struct iwl_trans *trans, } /* more in the link list, continue */ usedblocks++; - } while (usedblocks <= cfg(trans)->base_params->max_ll_items); + } while (usedblocks <= trans->cfg->base_params->max_ll_items); /* OTP has no valid blocks */ IWL_DEBUG_EEPROM(trans, "OTP has no valid blocks\n"); @@ -591,7 +646,6 @@ iwl_eeprom_enh_txp_read_element(struct iwl_priv *priv, static void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv) { - struct iwl_shared *shrd = priv->shrd; struct iwl_eeprom_enhanced_txpwr *txp_array, *txp; int idx, entries; __le16 *txp_len; @@ -600,10 +654,10 @@ static void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv) BUILD_BUG_ON(sizeof(struct iwl_eeprom_enhanced_txpwr) != 8); /* the length is in 16-bit words, but we want entries */ - txp_len = (__le16 *) iwl_eeprom_query_addr(shrd, EEPROM_TXP_SZ_OFFS); + txp_len = (__le16 *) iwl_eeprom_query_addr(priv, EEPROM_TXP_SZ_OFFS); entries = le16_to_cpup(txp_len) * 2 / EEPROM_TXP_ENTRY_LEN; - txp_array = (void *) iwl_eeprom_query_addr(shrd, EEPROM_TXP_OFFS); + txp_array = (void *) iwl_eeprom_query_addr(priv, EEPROM_TXP_OFFS); for (idx = 0; idx < entries; idx++) { txp = &txp_array[idx]; @@ -637,7 +691,7 @@ static void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv) ((txp->delta_20_in_40 & 0xf0) >> 4), (txp->delta_20_in_40 & 0x0f)); - max_txp_avg = iwl_get_max_txpower_avg(cfg(priv), txp_array, idx, + max_txp_avg = iwl_get_max_txpower_avg(priv->cfg, txp_array, idx, &max_txp_avg_halfdbm); /* @@ -656,66 +710,66 @@ static void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv) /** * iwl_eeprom_init - read EEPROM contents * - * Load the EEPROM contents from adapter into shrd->eeprom + * Load the EEPROM contents from adapter into priv->eeprom * * NOTE: This routine uses the non-debug IO access functions. */ -int iwl_eeprom_init(struct iwl_trans *trans, u32 hw_rev) +int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) { __le16 *e; - u32 gp = iwl_read32(trans, CSR_EEPROM_GP); + u32 gp = iwl_read32(priv->trans, CSR_EEPROM_GP); int sz; int ret; u16 addr; u16 validblockaddr = 0; u16 cache_addr = 0; - trans->nvm_device_type = iwl_get_nvm_type(trans, hw_rev); - if (trans->nvm_device_type == -ENOENT) + priv->nvm_device_type = iwl_get_nvm_type(priv->trans, hw_rev); + if (priv->nvm_device_type == -ENOENT) return -ENOENT; /* allocate eeprom */ - sz = cfg(trans)->base_params->eeprom_size; - IWL_DEBUG_EEPROM(trans, "NVM size = %d\n", sz); - trans->shrd->eeprom = kzalloc(sz, GFP_KERNEL); - if (!trans->shrd->eeprom) { + sz = priv->cfg->base_params->eeprom_size; + IWL_DEBUG_EEPROM(priv, "NVM size = %d\n", sz); + priv->eeprom = kzalloc(sz, GFP_KERNEL); + if (!priv->eeprom) { ret = -ENOMEM; goto alloc_err; } - e = (__le16 *)trans->shrd->eeprom; + e = (__le16 *)priv->eeprom; - ret = iwl_eeprom_verify_signature(trans); + ret = iwl_eeprom_verify_signature(priv); if (ret < 0) { - IWL_ERR(trans, "EEPROM not found, EEPROM_GP=0x%08x\n", gp); + IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp); ret = -ENOENT; goto err; } /* Make sure driver (instead of uCode) is allowed to read EEPROM */ - ret = iwl_eeprom_acquire_semaphore(trans); + ret = iwl_eeprom_acquire_semaphore(priv->trans); if (ret < 0) { - IWL_ERR(trans, "Failed to acquire EEPROM semaphore.\n"); + IWL_ERR(priv, "Failed to acquire EEPROM semaphore.\n"); ret = -ENOENT; goto err; } - if (trans->nvm_device_type == NVM_DEVICE_TYPE_OTP) { + if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) { - ret = iwl_init_otp_access(trans); + ret = iwl_init_otp_access(priv->trans); if (ret) { - IWL_ERR(trans, "Failed to initialize OTP access.\n"); + IWL_ERR(priv, "Failed to initialize OTP access.\n"); ret = -ENOENT; goto done; } - iwl_write32(trans, CSR_EEPROM_GP, - iwl_read32(trans, CSR_EEPROM_GP) & + iwl_write32(priv->trans, CSR_EEPROM_GP, + iwl_read32(priv->trans, CSR_EEPROM_GP) & ~CSR_EEPROM_GP_IF_OWNER_MSK); - iwl_set_bit(trans, CSR_OTP_GP_REG, + iwl_set_bit(priv->trans, CSR_OTP_GP_REG, CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK | CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); /* traversing the linked list if no shadow ram supported */ - if (!cfg(trans)->base_params->shadow_ram_support) { - if (iwl_find_otp_image(trans, &validblockaddr)) { + if (!priv->cfg->base_params->shadow_ram_support) { + if (iwl_find_otp_image(priv->trans, &validblockaddr)) { ret = -ENOENT; goto done; } @@ -724,7 +778,8 @@ int iwl_eeprom_init(struct iwl_trans *trans, u32 hw_rev) addr += sizeof(u16)) { __le16 eeprom_data; - ret = iwl_read_otp_word(trans, addr, &eeprom_data); + ret = iwl_read_otp_word(priv->trans, addr, + &eeprom_data); if (ret) goto done; e[cache_addr / 2] = eeprom_data; @@ -735,94 +790,93 @@ int iwl_eeprom_init(struct iwl_trans *trans, u32 hw_rev) for (addr = 0; addr < sz; addr += sizeof(u16)) { u32 r; - iwl_write32(trans, CSR_EEPROM_REG, + iwl_write32(priv->trans, CSR_EEPROM_REG, CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - ret = iwl_poll_bit(trans, CSR_EEPROM_REG, + ret = iwl_poll_bit(priv->trans, CSR_EEPROM_REG, CSR_EEPROM_REG_READ_VALID_MSK, CSR_EEPROM_REG_READ_VALID_MSK, IWL_EEPROM_ACCESS_TIMEOUT); if (ret < 0) { - IWL_ERR(trans, + IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr); goto done; } - r = iwl_read32(trans, CSR_EEPROM_REG); + r = iwl_read32(priv->trans, CSR_EEPROM_REG); e[addr / 2] = cpu_to_le16(r >> 16); } } - IWL_DEBUG_EEPROM(trans, "NVM Type: %s, version: 0x%x\n", - (trans->nvm_device_type == NVM_DEVICE_TYPE_OTP) + IWL_DEBUG_EEPROM(priv, "NVM Type: %s, version: 0x%x\n", + (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) ? "OTP" : "EEPROM", - iwl_eeprom_query16(trans->shrd, EEPROM_VERSION)); + iwl_eeprom_query16(priv, EEPROM_VERSION)); ret = 0; done: - iwl_eeprom_release_semaphore(trans); + iwl_eeprom_release_semaphore(priv->trans); err: if (ret) - iwl_eeprom_free(trans->shrd); + iwl_eeprom_free(priv); alloc_err: return ret; } -void iwl_eeprom_free(struct iwl_shared *shrd) +void iwl_eeprom_free(struct iwl_priv *priv) { - kfree(shrd->eeprom); - shrd->eeprom = NULL; + kfree(priv->eeprom); + priv->eeprom = NULL; } -static void iwl_init_band_reference(const struct iwl_priv *priv, +static void iwl_init_band_reference(struct iwl_priv *priv, int eep_band, int *eeprom_ch_count, const struct iwl_eeprom_channel **eeprom_ch_info, const u8 **eeprom_ch_index) { - struct iwl_shared *shrd = priv->shrd; - u32 offset = cfg(priv)->lib-> + u32 offset = priv->lib-> eeprom_ops.regulatory_bands[eep_band - 1]; switch (eep_band) { case 1: /* 2.4GHz band */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_1); *eeprom_ch_info = (struct iwl_eeprom_channel *) - iwl_eeprom_query_addr(shrd, offset); + iwl_eeprom_query_addr(priv, offset); *eeprom_ch_index = iwl_eeprom_band_1; break; case 2: /* 4.9GHz band */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_2); *eeprom_ch_info = (struct iwl_eeprom_channel *) - iwl_eeprom_query_addr(shrd, offset); + iwl_eeprom_query_addr(priv, offset); *eeprom_ch_index = iwl_eeprom_band_2; break; case 3: /* 5.2GHz band */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_3); *eeprom_ch_info = (struct iwl_eeprom_channel *) - iwl_eeprom_query_addr(shrd, offset); + iwl_eeprom_query_addr(priv, offset); *eeprom_ch_index = iwl_eeprom_band_3; break; case 4: /* 5.5GHz band */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_4); *eeprom_ch_info = (struct iwl_eeprom_channel *) - iwl_eeprom_query_addr(shrd, offset); + iwl_eeprom_query_addr(priv, offset); *eeprom_ch_index = iwl_eeprom_band_4; break; case 5: /* 5.7GHz band */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_5); *eeprom_ch_info = (struct iwl_eeprom_channel *) - iwl_eeprom_query_addr(shrd, offset); + iwl_eeprom_query_addr(priv, offset); *eeprom_ch_index = iwl_eeprom_band_5; break; case 6: /* 2.4GHz ht40 channels */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6); *eeprom_ch_info = (struct iwl_eeprom_channel *) - iwl_eeprom_query_addr(shrd, offset); + iwl_eeprom_query_addr(priv, offset); *eeprom_ch_index = iwl_eeprom_band_6; break; case 7: /* 5 GHz ht40 channels */ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7); *eeprom_ch_info = (struct iwl_eeprom_channel *) - iwl_eeprom_query_addr(shrd, offset); + iwl_eeprom_query_addr(priv, offset); *eeprom_ch_index = iwl_eeprom_band_7; break; default: @@ -987,9 +1041,9 @@ int iwl_init_channel_map(struct iwl_priv *priv) } /* Check if we do have HT40 channels */ - if (cfg(priv)->lib->eeprom_ops.regulatory_bands[5] == + if (priv->lib->eeprom_ops.regulatory_bands[5] == EEPROM_REGULATORY_BAND_NO_HT40 && - cfg(priv)->lib->eeprom_ops.regulatory_bands[6] == + priv->lib->eeprom_ops.regulatory_bands[6] == EEPROM_REGULATORY_BAND_NO_HT40) return 0; @@ -1025,7 +1079,7 @@ int iwl_init_channel_map(struct iwl_priv *priv) * driver need to process addition information * to determine the max channel tx power limits */ - if (cfg(priv)->lib->eeprom_ops.enhanced_txpower) + if (priv->lib->eeprom_ops.enhanced_txpower) iwl_eeprom_enhanced_txpower(priv); return 0; @@ -1072,11 +1126,11 @@ void iwl_rf_config(struct iwl_priv *priv) { u16 radio_cfg; - radio_cfg = iwl_eeprom_query16(priv->shrd, EEPROM_RADIO_CONFIG); + radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); /* write radio config values to register */ if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) <= EEPROM_RF_CONFIG_TYPE_MAX) { - iwl_set_bit(trans(priv), CSR_HW_IF_CONFIG_REG, + iwl_set_bit(priv->trans, CSR_HW_IF_CONFIG_REG, EEPROM_RF_CFG_TYPE_MSK(radio_cfg) | EEPROM_RF_CFG_STEP_MSK(radio_cfg) | EEPROM_RF_CFG_DASH_MSK(radio_cfg)); @@ -1088,7 +1142,7 @@ void iwl_rf_config(struct iwl_priv *priv) WARN_ON(1); /* set CSR_HW_CONFIG_REG for uCode use */ - iwl_set_bit(trans(priv), CSR_HW_IF_CONFIG_REG, + iwl_set_bit(priv->trans, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); } diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom.h index e4a758340996..64bfd947caeb 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -66,8 +66,6 @@ #include struct iwl_priv; -struct iwl_shared; -struct iwl_trans; /* * EEPROM access time values: @@ -208,59 +206,6 @@ struct iwl_eeprom_calib_hdr { /* 6000 regulatory - indirect access */ #define EEPROM_6000_REG_BAND_24_HT40_CHANNELS ((0x80)\ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 14 bytes */ - -/* 5000 Specific */ -#define EEPROM_5000_TX_POWER_VERSION (4) -#define EEPROM_5000_EEPROM_VERSION (0x11A) - -/* 5050 Specific */ -#define EEPROM_5050_TX_POWER_VERSION (4) -#define EEPROM_5050_EEPROM_VERSION (0x21E) - -/* 1000 Specific */ -#define EEPROM_1000_TX_POWER_VERSION (4) -#define EEPROM_1000_EEPROM_VERSION (0x15C) - -/* 6x00 Specific */ -#define EEPROM_6000_TX_POWER_VERSION (4) -#define EEPROM_6000_EEPROM_VERSION (0x423) - -/* 6x50 Specific */ -#define EEPROM_6050_TX_POWER_VERSION (4) -#define EEPROM_6050_EEPROM_VERSION (0x532) - -/* 6150 Specific */ -#define EEPROM_6150_TX_POWER_VERSION (6) -#define EEPROM_6150_EEPROM_VERSION (0x553) - -/* 6x05 Specific */ -#define EEPROM_6005_TX_POWER_VERSION (6) -#define EEPROM_6005_EEPROM_VERSION (0x709) - -/* 6x30 Specific */ -#define EEPROM_6030_TX_POWER_VERSION (6) -#define EEPROM_6030_EEPROM_VERSION (0x709) - -/* 2x00 Specific */ -#define EEPROM_2000_TX_POWER_VERSION (6) -#define EEPROM_2000_EEPROM_VERSION (0x805) - -/* 6x35 Specific */ -#define EEPROM_6035_TX_POWER_VERSION (6) -#define EEPROM_6035_EEPROM_VERSION (0x753) - - -/* 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 */ -#define OTP_MAX_LL_ITEMS_1000 (3) /* OTP blocks for 1000 */ -#define OTP_MAX_LL_ITEMS_6x00 (4) /* OTP blocks for 6x00 */ -#define OTP_MAX_LL_ITEMS_6x50 (7) /* OTP blocks for 6x50 */ -#define OTP_MAX_LL_ITEMS_2x00 (4) /* OTP blocks for 2x00 */ - /* 2.4 GHz */ extern const u8 iwl_eeprom_band_1[14]; @@ -306,12 +251,14 @@ struct iwl_eeprom_ops { }; -int iwl_eeprom_init(struct iwl_trans *trans, u32 hw_rev); -void iwl_eeprom_free(struct iwl_shared *shrd); -int iwl_eeprom_check_version(struct iwl_priv *priv); +int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev); +void iwl_eeprom_free(struct iwl_priv *priv); +int iwl_eeprom_check_version(struct iwl_priv *priv); int iwl_eeprom_init_hw_params(struct iwl_priv *priv); -const u8 *iwl_eeprom_query_addr(const struct iwl_shared *shrd, size_t offset); -u16 iwl_eeprom_query16(const struct iwl_shared *shrd, size_t offset); +u16 iwl_eeprom_calib_version(struct iwl_priv *priv); +const u8 *iwl_eeprom_query_addr(struct iwl_priv *priv, size_t offset); +u16 iwl_eeprom_query16(struct iwl_priv *priv, size_t offset); +void iwl_eeprom_get_mac(struct iwl_priv *priv, u8 *mac); int iwl_init_channel_map(struct iwl_priv *priv); void iwl_free_channel_map(struct iwl_priv *priv); const struct iwl_channel_info *iwl_get_channel_info( diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/trunk/drivers/net/wireless/iwlwifi/iwl-fw-file.h index c924ccb93c8c..e71564053e7f 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -93,15 +93,7 @@ struct iwl_ucode_header { * new TLV uCode file layout * * The new TLV file format contains TLVs, that each specify - * some piece of data. To facilitate "groups", for example - * different instruction image with different capabilities, - * bundled with the same init image, an alternative mechanism - * is provided: - * When the alternative field is 0, that means that the item - * is always valid. When it is non-zero, then it is only - * valid in conjunction with items of the same alternative, - * in which case the driver (user) selects one alternative - * to use. + * some piece of data. */ enum iwl_ucode_tlv_type { @@ -132,8 +124,7 @@ enum iwl_ucode_tlv_type { }; struct iwl_ucode_tlv { - __le16 type; /* see above */ - __le16 alternative; /* see comment */ + __le32 type; /* see above */ __le32 length; /* not including type/length fields */ u8 data[0]; }; @@ -152,7 +143,7 @@ struct iwl_tlv_ucode_header { u8 human_readable[64]; __le32 ver; /* major/minor/API/serial */ __le32 build; - __le64 alternatives; /* bitmask of valid alternatives */ + __le64 ignore; /* * The data contained herein has a TLV layout, * see above for the TLV header and types. diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-fw.h b/trunk/drivers/net/wireless/iwlwifi/iwl-fw.h index 8e36bdc1e522..2153e4cc5572 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -63,6 +63,7 @@ #ifndef __iwl_fw_h__ #define __iwl_fw_h__ #include +#include /** * enum iwl_ucode_tlv_flag - ucode API flags diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-io.h b/trunk/drivers/net/wireless/iwlwifi/iwl-io.h index 09b856768f62..abb3250164ba 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-io.h @@ -30,7 +30,6 @@ #define __iwl_io_h__ #include "iwl-devtrace.h" -#include "iwl-shared.h" #include "iwl-trans.h" static inline void iwl_write8(struct iwl_trans *trans, u32 ofs, u8 val) diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-led.c b/trunk/drivers/net/wireless/iwlwifi/iwl-led.c index 1993a2b7ae63..47000419f916 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-led.c @@ -36,11 +36,10 @@ #include #include "iwl-dev.h" -#include "iwl-core.h" #include "iwl-agn.h" #include "iwl-io.h" #include "iwl-trans.h" -#include "iwl-shared.h" +#include "iwl-modparams.h" /* Throughput OFF time(ms) ON time (ms) * >300 25 25 @@ -71,7 +70,7 @@ static const struct ieee80211_tpt_blink iwl_blink[] = { /* Set led register off */ void iwlagn_led_enable(struct iwl_priv *priv) { - iwl_write32(trans(priv), CSR_LED_REG, CSR_LED_REG_TRUN_ON); + iwl_write32(priv->trans, CSR_LED_REG, CSR_LED_REG_TRUN_ON); } /* @@ -107,9 +106,9 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd) }; u32 reg; - reg = iwl_read32(trans(priv), CSR_LED_REG); + reg = iwl_read32(priv->trans, CSR_LED_REG); if (reg != (reg & CSR_LED_BSM_CTRL_MSK)) - iwl_write32(trans(priv), CSR_LED_REG, + iwl_write32(priv->trans, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK); return iwl_dvm_send_cmd(priv, &cmd); @@ -138,11 +137,11 @@ static int iwl_led_cmd(struct iwl_priv *priv, } IWL_DEBUG_LED(priv, "Led blink time compensation=%u\n", - cfg(priv)->base_params->led_compensation); + priv->cfg->base_params->led_compensation); led_cmd.on = iwl_blink_compensation(priv, on, - cfg(priv)->base_params->led_compensation); + priv->cfg->base_params->led_compensation); led_cmd.off = iwl_blink_compensation(priv, off, - cfg(priv)->base_params->led_compensation); + priv->cfg->base_params->led_compensation); ret = iwl_send_led_cmd(priv, &led_cmd); if (!ret) { @@ -175,7 +174,7 @@ static int iwl_led_blink_set(struct led_classdev *led_cdev, void iwl_leds_init(struct iwl_priv *priv) { - int mode = iwlagn_mod_params.led_mode; + int mode = iwlwifi_mod_params.led_mode; int ret; if (mode == IWL_LED_DISABLE) { @@ -183,7 +182,7 @@ void iwl_leds_init(struct iwl_priv *priv) return; } if (mode == IWL_LED_DEFAULT) - mode = cfg(priv)->led_mode; + mode = priv->cfg->led_mode; priv->led.name = kasprintf(GFP_KERNEL, "%s-led", wiphy_name(priv->hw->wiphy)); @@ -207,7 +206,7 @@ void iwl_leds_init(struct iwl_priv *priv) break; } - ret = led_classdev_register(trans(priv)->dev, &priv->led); + ret = led_classdev_register(priv->trans->dev, &priv->led); if (ret) { kfree(priv->led.name); return; diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/trunk/drivers/net/wireless/iwlwifi/iwl-mac80211.c index c24a7134a6f9..d33cc9cc7d3f 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-mac80211.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-mac80211.c @@ -44,13 +44,12 @@ #include "iwl-eeprom.h" #include "iwl-dev.h" -#include "iwl-core.h" #include "iwl-io.h" #include "iwl-agn-calib.h" #include "iwl-agn.h" -#include "iwl-shared.h" #include "iwl-trans.h" #include "iwl-op-mode.h" +#include "iwl-modparams.h" /***************************************************************************** * @@ -147,7 +146,13 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_NEED_DTIM_PERIOD | IEEE80211_HW_SPECTRUM_MGMT | - IEEE80211_HW_REPORTS_TX_ACK_STATUS; + IEEE80211_HW_REPORTS_TX_ACK_STATUS | + IEEE80211_HW_QUEUE_CONTROL | + IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_SUPPORTS_DYNAMIC_PS | + IEEE80211_HW_SCAN_WHILE_IDLE; + + hw->offchannel_tx_hw_queue = IWL_AUX_QUEUE; /* * Including the following line will crash some AP's. This @@ -156,10 +161,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF; */ - hw->flags |= IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_SUPPORTS_DYNAMIC_PS; - - if (hw_params(priv).sku & EEPROM_SKU_CAP_11N_ENABLE) + if (priv->hw_params.sku & EEPROM_SKU_CAP_11N_ENABLE) hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | IEEE80211_HW_SUPPORTS_STATIC_SMPS; @@ -197,13 +199,13 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, WIPHY_FLAG_IBSS_RSN; if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len && - trans(priv)->ops->wowlan_suspend && - device_can_wakeup(trans(priv)->dev)) { + priv->trans->ops->wowlan_suspend && + device_can_wakeup(priv->trans->dev)) { hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | WIPHY_WOWLAN_EAP_IDENTITY_REQ | WIPHY_WOWLAN_RFKILL_RELEASE; - if (!iwlagn_mod_params.sw_crypto) + if (!iwlwifi_mod_params.sw_crypto) hw->wiphy->wowlan.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | WIPHY_WOWLAN_GTK_REKEY_FAILURE; @@ -215,7 +217,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, IWLAGN_WOWLAN_MAX_PATTERN_LEN; } - if (iwlagn_mod_params.power_save) + if (iwlwifi_mod_params.power_save) hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; else hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; @@ -224,8 +226,11 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, /* we create the 802.11 header and a zero-length SSID element */ hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 2; - /* Default value; 4 EDCA QOS priorities */ - hw->queues = 4; + /* + * We don't use all queues: 4 and 9 are unused and any + * aggregation queue gets mapped down to the AC queue. + */ + hw->queues = IWLAGN_FIRST_AMPDU_QUEUE; hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL; @@ -236,7 +241,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &priv->bands[IEEE80211_BAND_5GHZ]; - hw->wiphy->hw_version = trans(priv)->hw_id; + hw->wiphy->hw_version = priv->trans->hw_id; iwl_leds_init(priv); @@ -332,7 +337,7 @@ static int iwlagn_mac_start(struct ieee80211_hw *hw) return 0; } -static void iwlagn_mac_stop(struct ieee80211_hw *hw) +void iwlagn_mac_stop(struct ieee80211_hw *hw) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); @@ -355,18 +360,18 @@ static void iwlagn_mac_stop(struct ieee80211_hw *hw) * even if interface is down, trans->down will leave the RF * kill interrupt enabled */ - iwl_trans_stop_hw(trans(priv)); + iwl_trans_stop_hw(priv->trans, false); IWL_DEBUG_MAC80211(priv, "leave\n"); } -static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct cfg80211_gtk_rekey_data *data) +void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_gtk_rekey_data *data) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); - if (iwlagn_mod_params.sw_crypto) + if (iwlwifi_mod_params.sw_crypto) return; IWL_DEBUG_MAC80211(priv, "enter\n"); @@ -388,8 +393,7 @@ static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw, #ifdef CONFIG_PM_SLEEP -static int iwlagn_mac_suspend(struct ieee80211_hw *hw, - struct cfg80211_wowlan *wowlan) +int iwlagn_mac_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; @@ -412,9 +416,9 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw, if (ret) goto error; - device_set_wakeup_enable(trans(priv)->dev, true); + device_set_wakeup_enable(priv->trans->dev, true); - iwl_trans_wowlan_suspend(trans(priv)); + iwl_trans_wowlan_suspend(priv->trans); goto out; @@ -437,27 +441,28 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) unsigned long flags; u32 base, status = 0xffffffff; int ret = -EIO; - const struct fw_img *img; IWL_DEBUG_MAC80211(priv, "enter\n"); mutex_lock(&priv->mutex); - iwl_write32(trans(priv), CSR_UCODE_DRV_GP1_CLR, + iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); - base = priv->shrd->device_pointers.error_event_table; + base = priv->device_pointers.error_event_table; if (iwlagn_hw_valid_rtc_data_addr(base)) { - spin_lock_irqsave(&trans(priv)->reg_lock, flags); - ret = iwl_grab_nic_access_silent(trans(priv)); + spin_lock_irqsave(&priv->trans->reg_lock, flags); + ret = iwl_grab_nic_access_silent(priv->trans); if (likely(ret == 0)) { - iwl_write32(trans(priv), HBUS_TARG_MEM_RADDR, base); - status = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT); - iwl_release_nic_access(trans(priv)); + iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, base); + status = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT); + iwl_release_nic_access(priv->trans); } - spin_unlock_irqrestore(&trans(priv)->reg_lock, flags); + spin_unlock_irqrestore(&priv->trans->reg_lock, flags); #ifdef CONFIG_IWLWIFI_DEBUGFS if (ret == 0) { + const struct fw_img *img; + img = &(priv->fw->img[IWL_UCODE_WOWLAN]); if (!priv->wowlan_sram) { priv->wowlan_sram = @@ -467,7 +472,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) if (priv->wowlan_sram) _iwl_read_targ_mem_words( - trans(priv), 0x800000, + priv->trans, 0x800000, priv->wowlan_sram, img->sec[IWL_UCODE_SECTION_DATA].len / 4); } @@ -479,7 +484,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) priv->wowlan = false; - device_set_wakeup_enable(trans(priv)->dev, false); + device_set_wakeup_enable(priv->trans->dev, false); iwlagn_prepare_restart(priv); @@ -497,7 +502,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) #endif -static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); @@ -508,21 +513,21 @@ static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) dev_kfree_skb_any(skb); } -static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_key_conf *keyconf, - struct ieee80211_sta *sta, - u32 iv32, u16 *phase1key) +void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_key_conf *keyconf, + struct ieee80211_sta *sta, + u32 iv32, u16 *phase1key) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); iwl_update_tkip_key(priv, vif, keyconf, sta, iv32, phase1key); } -static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) +int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; @@ -532,7 +537,7 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, IWL_DEBUG_MAC80211(priv, "enter\n"); - if (iwlagn_mod_params.sw_crypto) { + if (iwlwifi_mod_params.sw_crypto) { IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n"); return -EOPNOTSUPP; } @@ -622,11 +627,11 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return ret; } -static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size) +int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, u16 tid, u16 *ssn, + u8 buf_size) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); int ret = -EINVAL; @@ -635,7 +640,7 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n", sta->addr, tid); - if (!(hw_params(priv).sku & EEPROM_SKU_CAP_11N_ENABLE)) + if (!(priv->hw_params.sku & EEPROM_SKU_CAP_11N_ENABLE)) return -EACCES; IWL_DEBUG_MAC80211(priv, "enter\n"); @@ -643,7 +648,7 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, switch (action) { case IEEE80211_AMPDU_RX_START: - if (iwlagn_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG) + if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG) break; IWL_DEBUG_HT(priv, "start Rx\n"); ret = iwl_sta_rx_agg_start(priv, sta, tid, *ssn); @@ -653,7 +658,9 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, ret = iwl_sta_rx_agg_stop(priv, sta, tid); break; case IEEE80211_AMPDU_TX_START: - if (iwlagn_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG) + if (!priv->trans->ops->tx_agg_setup) + break; + if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG) break; IWL_DEBUG_HT(priv, "start Tx\n"); ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn); @@ -667,7 +674,7 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, priv->agg_tids_count); } if (!priv->agg_tids_count && - hw_params(priv).use_rts_for_aggregation) { + priv->hw_params.use_rts_for_aggregation) { /* * switch off RTS/CTS if it was previously enabled */ @@ -746,11 +753,11 @@ static int iwlagn_mac_sta_remove(struct ieee80211_hw *hw, return ret; } -static int iwlagn_mac_sta_state(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - enum ieee80211_sta_state old_state, - enum ieee80211_sta_state new_state) +int iwlagn_mac_sta_state(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + enum ieee80211_sta_state old_state, + enum ieee80211_sta_state new_state) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; @@ -829,8 +836,8 @@ static int iwlagn_mac_sta_state(struct ieee80211_hw *hw, return ret; } -static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, - struct ieee80211_channel_switch *ch_switch) +void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, + struct ieee80211_channel_switch *ch_switch) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); const struct iwl_channel_info *ch_info; @@ -863,7 +870,7 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, if (!iwl_is_associated_ctx(ctx)) goto out; - if (!cfg(priv)->lib->set_channel_switch) + if (!priv->lib->set_channel_switch) goto out; ch = channel->hw_value; @@ -892,14 +899,13 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, iwl_set_rxon_ht(priv, ht_conf); iwl_set_flags_for_band(priv, ctx, channel->band, ctx->vif); - iwl_set_rate(priv); /* * at this point, staging_rxon has the * configuration for channel switch */ set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status); priv->switch_channel = cpu_to_le16(ch); - if (cfg(priv)->lib->set_channel_switch(priv, ch_switch)) { + if (priv->lib->set_channel_switch(priv, ch_switch)) { clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status); priv->switch_channel = 0; ieee80211_chswitch_done(ctx->vif, false); @@ -910,10 +916,25 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(priv, "leave\n"); } -static void iwlagn_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - u64 multicast) +void iwl_chswitch_done(struct iwl_priv *priv, bool is_success) +{ + /* + * MULTI-FIXME + * See iwlagn_mac_channel_switch. + */ + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status)) + ieee80211_chswitch_done(ctx->vif, is_success); +} + +void iwlagn_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 multicast) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); __le32 filter_or = 0, filter_nand = 0; @@ -960,7 +981,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw, FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; } -static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop) +void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); @@ -988,7 +1009,7 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop) } } IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n"); - iwl_trans_wait_tx_queue_empty(trans(priv)); + iwl_trans_wait_tx_queue_empty(priv->trans); done: mutex_unlock(&priv->mutex); IWL_DEBUG_MAC80211(priv, "leave\n"); @@ -1003,7 +1024,7 @@ static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw, struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN]; int err = 0; - if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN))) + if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) return -EOPNOTSUPP; if (!(ctx->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT))) @@ -1087,11 +1108,11 @@ static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw, return err; } -static int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw) +int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); - if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN))) + if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) return -EOPNOTSUPP; IWL_DEBUG_MAC80211(priv, "enter\n"); @@ -1104,16 +1125,16 @@ static int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw) return 0; } -static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw, - enum ieee80211_rssi_event rssi_event) +void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw, + enum ieee80211_rssi_event rssi_event) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); IWL_DEBUG_MAC80211(priv, "enter\n"); mutex_lock(&priv->mutex); - if (cfg(priv)->bt_params && - cfg(priv)->bt_params->advanced_bt_coexist) { + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist) { if (rssi_event == RSSI_EVENT_LOW) priv->bt_enable_pspoll = true; else if (rssi_event == RSSI_EVENT_HIGH) @@ -1129,8 +1150,8 @@ static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(priv, "leave\n"); } -static int iwlagn_mac_set_tim(struct ieee80211_hw *hw, - struct ieee80211_sta *sta, bool set) +int iwlagn_mac_set_tim(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, bool set) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); @@ -1139,9 +1160,9 @@ static int iwlagn_mac_set_tim(struct ieee80211_hw *hw, return 0; } -static int iwlagn_mac_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 queue, - const struct ieee80211_tx_queue_params *params) +int iwlagn_mac_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, + const struct ieee80211_tx_queue_params *params) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; @@ -1183,7 +1204,7 @@ static int iwlagn_mac_conf_tx(struct ieee80211_hw *hw, return 0; } -static int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw) +int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); @@ -1199,11 +1220,10 @@ static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx) return iwlagn_commit_rxon(priv, ctx); } -static int iwl_setup_interface(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) +int iwl_setup_interface(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { struct ieee80211_vif *vif = ctx->vif; - int err; + int err, ac; lockdep_assert_held(&priv->mutex); @@ -1223,7 +1243,7 @@ static int iwl_setup_interface(struct iwl_priv *priv, return err; } - if (cfg(priv)->bt_params && cfg(priv)->bt_params->advanced_bt_coexist && + if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist && vif->type == NL80211_IFTYPE_ADHOC) { /* * pretend to have high BT traffic as long as we @@ -1233,11 +1253,20 @@ static int iwl_setup_interface(struct iwl_priv *priv, priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH; } + /* set up queue mappings */ + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) + vif->hw_queue[ac] = ctx->ac_to_queue[ac]; + + if (vif->type == NL80211_IFTYPE_AP) + vif->cab_queue = ctx->mcast_queue; + else + vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; + return 0; } static int iwlagn_mac_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_vif *vif) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; @@ -1311,9 +1340,9 @@ static int iwlagn_mac_add_interface(struct ieee80211_hw *hw, return err; } -static void iwl_teardown_interface(struct iwl_priv *priv, - struct ieee80211_vif *vif, - bool mode_change) +void iwl_teardown_interface(struct iwl_priv *priv, + struct ieee80211_vif *vif, + bool mode_change) { struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); @@ -1454,9 +1483,9 @@ static int iwlagn_mac_change_interface(struct ieee80211_hw *hw, return err; } -static int iwlagn_mac_hw_scan(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct cfg80211_scan_request *req) +int iwlagn_mac_hw_scan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_scan_request *req) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); int ret; @@ -1511,7 +1540,7 @@ static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) iwl_send_add_sta(priv, &cmd, CMD_ASYNC); } -static void iwlagn_mac_sta_notify(struct ieee80211_hw *hw, +void iwlagn_mac_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_cmd cmd, struct ieee80211_sta *sta) diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-modparams.h b/trunk/drivers/net/wireless/iwlwifi/iwl-modparams.h new file mode 100644 index 000000000000..d9a86d6b2bd7 --- /dev/null +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-modparams.h @@ -0,0 +1,126 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007 - 2012 Intel 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 + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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. + * + *****************************************************************************/ +#ifndef __iwl_modparams_h__ +#define __iwl_modparams_h__ + +#include +#include +#include +#include + +extern struct iwl_mod_params iwlwifi_mod_params; + +enum iwl_power_level { + IWL_POWER_INDEX_1, + IWL_POWER_INDEX_2, + IWL_POWER_INDEX_3, + IWL_POWER_INDEX_4, + IWL_POWER_INDEX_5, + IWL_POWER_NUM +}; + +#define IWL_DISABLE_HT_ALL BIT(0) +#define IWL_DISABLE_HT_TXAGG BIT(1) +#define IWL_DISABLE_HT_RXAGG BIT(2) + +/** + * struct iwl_mod_params + * + * Holds the module parameters + * + * @sw_crypto: using hardware encryption, default = 0 + * @disable_11n: disable 11n capabilities, default = 0, + * use IWL_DISABLE_HT_* constants + * @amsdu_size_8K: enable 8K amsdu size, default = 1 + * @restart_fw: restart firmware, default = 1 + * @plcp_check: enable plcp health check, default = true + * @wd_disable: enable stuck queue check, default = 0 + * @bt_coex_active: enable bt coex, default = true + * @led_mode: system default, default = 0 + * @power_save: disable power save, default = false + * @power_level: power level, default = 1 + * @debug_level: levels are IWL_DL_* + * @ant_coupling: antenna coupling in dB, default = 0 + * @bt_ch_announce: BT channel inhibition, default = enable + * @auto_agg: enable agg. without check, default = true + * @disable_5ghz: disable 5GHz capability, default = false + */ +struct iwl_mod_params { + int sw_crypto; + unsigned int disable_11n; + int amsdu_size_8K; + int restart_fw; + bool plcp_check; + int wd_disable; + bool bt_coex_active; + int led_mode; + bool power_save; + int power_level; + u32 debug_level; + int ant_coupling; + bool bt_ch_announce; + bool auto_agg; + bool disable_5ghz; +}; + +#endif /* #__iwl_modparams_h__ */ diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-notif-wait.c b/trunk/drivers/net/wireless/iwlwifi/iwl-notif-wait.c index 88dc4a0f96b4..0066b899fe5c 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-notif-wait.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-notif-wait.c @@ -75,21 +75,45 @@ void iwl_notification_wait_init(struct iwl_notif_wait_data *notif_wait) void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait, struct iwl_rx_packet *pkt) { + bool triggered = false; + if (!list_empty(¬if_wait->notif_waits)) { struct iwl_notification_wait *w; spin_lock(¬if_wait->notif_wait_lock); list_for_each_entry(w, ¬if_wait->notif_waits, list) { - if (w->cmd != pkt->hdr.cmd) + int i; + bool found = false; + + /* + * If it already finished (triggered) or has been + * aborted then don't evaluate it again to avoid races, + * Otherwise the function could be called again even + * though it returned true before + */ + if (w->triggered || w->aborted) + continue; + + for (i = 0; i < w->n_cmds; i++) { + if (w->cmds[i] == pkt->hdr.cmd) { + found = true; + break; + } + } + if (!found) continue; - w->triggered = true; - if (w->fn) - w->fn(notif_wait, pkt, w->fn_data); + + if (!w->fn || w->fn(notif_wait, pkt, w->fn_data)) { + w->triggered = true; + triggered = true; + } } spin_unlock(¬if_wait->notif_wait_lock); - wake_up_all(¬if_wait->notif_waitq); } + + if (triggered) + wake_up_all(¬if_wait->notif_waitq); } void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait) @@ -109,14 +133,18 @@ void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait) void iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait, struct iwl_notification_wait *wait_entry, - u8 cmd, - void (*fn)(struct iwl_notif_wait_data *notif_wait, + const u8 *cmds, int n_cmds, + bool (*fn)(struct iwl_notif_wait_data *notif_wait, struct iwl_rx_packet *pkt, void *data), void *fn_data) { + if (WARN_ON(n_cmds > MAX_NOTIF_CMDS)) + n_cmds = MAX_NOTIF_CMDS; + wait_entry->fn = fn; wait_entry->fn_data = fn_data; - wait_entry->cmd = cmd; + wait_entry->n_cmds = n_cmds; + memcpy(wait_entry->cmds, cmds, n_cmds); wait_entry->triggered = false; wait_entry->aborted = false; diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-notif-wait.h b/trunk/drivers/net/wireless/iwlwifi/iwl-notif-wait.h index 5e8af957aa7b..821523100cf1 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-notif-wait.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-notif-wait.h @@ -72,11 +72,19 @@ struct iwl_notif_wait_data { wait_queue_head_t notif_waitq; }; +#define MAX_NOTIF_CMDS 5 + /** * struct iwl_notification_wait - notification wait entry * @list: list head for global list - * @fn: function called with the notification - * @cmd: command ID + * @fn: Function called with the notification. If the function + * returns true, the wait is over, if it returns false then + * the waiter stays blocked. If no function is given, any + * of the listed commands will unblock the waiter. + * @cmds: command IDs + * @n_cmds: number of command IDs + * @triggered: waiter should be woken up + * @aborted: wait was aborted * * This structure is not used directly, to wait for a * notification declare it on the stack, and call @@ -93,11 +101,12 @@ struct iwl_notif_wait_data { struct iwl_notification_wait { struct list_head list; - void (*fn)(struct iwl_notif_wait_data *notif_data, + bool (*fn)(struct iwl_notif_wait_data *notif_data, struct iwl_rx_packet *pkt, void *data); void *fn_data; - u8 cmd; + u8 cmds[MAX_NOTIF_CMDS]; + u8 n_cmds; bool triggered, aborted; }; @@ -112,8 +121,8 @@ void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_data); void __acquires(wait_entry) iwl_init_notification_wait(struct iwl_notif_wait_data *notif_data, struct iwl_notification_wait *wait_entry, - u8 cmd, - void (*fn)(struct iwl_notif_wait_data *notif_data, + const u8 *cmds, int n_cmds, + bool (*fn)(struct iwl_notif_wait_data *notif_data, struct iwl_rx_packet *pkt, void *data), void *fn_data); diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/trunk/drivers/net/wireless/iwlwifi/iwl-op-mode.h index 6ea4163ff56a..4ef742b28e08 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-op-mode.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-op-mode.h @@ -69,6 +69,7 @@ struct sk_buff; struct iwl_device_cmd; struct iwl_rx_cmd_buffer; struct iwl_fw; +struct iwl_cfg; /** * DOC: Operational mode - what is it ? @@ -111,10 +112,10 @@ struct iwl_fw; * @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the * HCMD the this Rx responds to. * Must be atomic. - * @queue_full: notifies that a HW queue is full. Ac is the ac of the queue + * @queue_full: notifies that a HW queue is full. * Must be atomic * @queue_not_full: notifies that a HW queue is not full any more. - * Ac is the ac of the queue. Must be atomic + * Must be atomic * @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that * the radio is killed. Must be atomic. * @free_skb: allows the transport layer to free skbs that haven't been @@ -125,20 +126,23 @@ struct iwl_fw; * @cmd_queue_full: Called when the command queue gets full. Must be atomic. * @nic_config: configure NIC, called before firmware is started. * May sleep + * @wimax_active: invoked when WiMax becomes active. Must be atomic. */ struct iwl_op_mode_ops { struct iwl_op_mode *(*start)(struct iwl_trans *trans, + const struct iwl_cfg *cfg, const struct iwl_fw *fw); 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 (*queue_full)(struct iwl_op_mode *op_mode, u8 ac); - void (*queue_not_full)(struct iwl_op_mode *op_mode, u8 ac); + void (*queue_full)(struct iwl_op_mode *op_mode, int queue); + void (*queue_not_full)(struct iwl_op_mode *op_mode, int queue); void (*hw_rf_kill)(struct iwl_op_mode *op_mode, bool state); void (*free_skb)(struct iwl_op_mode *op_mode, struct sk_buff *skb); void (*nic_error)(struct iwl_op_mode *op_mode); void (*cmd_queue_full)(struct iwl_op_mode *op_mode); void (*nic_config)(struct iwl_op_mode *op_mode); + void (*wimax_active)(struct iwl_op_mode *op_mode); }; /** @@ -169,15 +173,16 @@ static inline int iwl_op_mode_rx(struct iwl_op_mode *op_mode, return op_mode->ops->rx(op_mode, rxb, cmd); } -static inline void iwl_op_mode_queue_full(struct iwl_op_mode *op_mode, u8 ac) +static inline void iwl_op_mode_queue_full(struct iwl_op_mode *op_mode, + int queue) { - op_mode->ops->queue_full(op_mode, ac); + op_mode->ops->queue_full(op_mode, queue); } static inline void iwl_op_mode_queue_not_full(struct iwl_op_mode *op_mode, - u8 ac) + int queue) { - op_mode->ops->queue_not_full(op_mode, ac); + op_mode->ops->queue_not_full(op_mode, queue); } static inline void iwl_op_mode_hw_rf_kill(struct iwl_op_mode *op_mode, @@ -208,6 +213,11 @@ static inline void iwl_op_mode_nic_config(struct iwl_op_mode *op_mode) op_mode->ops->nic_config(op_mode); } +static inline void iwl_op_mode_wimax_active(struct iwl_op_mode *op_mode) +{ + op_mode->ops->wimax_active(op_mode); +} + /***************************************************** * Op mode layers implementations ******************************************************/ diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-pci.c b/trunk/drivers/net/wireless/iwlwifi/iwl-pci.c index c5e339ee918b..0c8a1c2d8847 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-pci.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-pci.c @@ -60,17 +60,18 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *****************************************************************************/ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include -#include "iwl-io.h" -#include "iwl-shared.h" #include "iwl-trans.h" -#include "iwl-csr.h" #include "iwl-cfg.h" #include "iwl-drv.h" #include "iwl-trans.h" +#include "iwl-trans-pcie-int.h" #define IWL_PCI_DEVICE(dev, subdev, cfg) \ .vendor = PCI_VENDOR_ID_INTEL, .device = (dev), \ @@ -261,61 +262,46 @@ MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); /* PCI registers */ #define PCI_CFG_RETRY_TIMEOUT 0x041 +#ifndef CONFIG_IWLWIFI_IDI + static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { const struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); - struct iwl_shared *shrd; struct iwl_trans *iwl_trans; - int err; - - shrd = kzalloc(sizeof(*iwl_trans->shrd), GFP_KERNEL); - if (!shrd) { - dev_printk(KERN_ERR, &pdev->dev, - "Couldn't allocate iwl_shared"); - err = -ENOMEM; - goto out_free_bus; - } + struct iwl_trans_pcie *trans_pcie; -#ifdef CONFIG_IWLWIFI_IDI - iwl_trans = iwl_trans_idi_alloc(shrd, pdev, ent); -#else - iwl_trans = iwl_trans_pcie_alloc(shrd, pdev, ent); -#endif - if (iwl_trans == NULL) { - err = -ENOMEM; - goto out_free_bus; - } + iwl_trans = iwl_trans_pcie_alloc(pdev, ent, cfg); + if (iwl_trans == NULL) + return -ENOMEM; - shrd->trans = iwl_trans; pci_set_drvdata(pdev, iwl_trans); - err = iwl_drv_start(shrd, iwl_trans, cfg); - if (err) + trans_pcie = IWL_TRANS_GET_PCIE_TRANS(iwl_trans); + trans_pcie->drv = iwl_drv_start(iwl_trans, cfg); + if (!trans_pcie->drv) goto out_free_trans; return 0; out_free_trans: - iwl_trans_free(iwl_trans); + iwl_trans_pcie_free(iwl_trans); pci_set_drvdata(pdev, NULL); -out_free_bus: - kfree(shrd); - return err; + return -EFAULT; } static void __devexit iwl_pci_remove(struct pci_dev *pdev) { - struct iwl_trans *iwl_trans = pci_get_drvdata(pdev); - struct iwl_shared *shrd = iwl_trans->shrd; + struct iwl_trans *trans = pci_get_drvdata(pdev); + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - iwl_drv_stop(shrd); - iwl_trans_free(shrd->trans); + iwl_drv_stop(trans_pcie->drv); + iwl_trans_pcie_free(trans); pci_set_drvdata(pdev, NULL); - - kfree(shrd); } +#endif /* CONFIG_IWLWIFI_IDI */ + #ifdef CONFIG_PM_SLEEP static int iwl_pci_suspend(struct device *device) @@ -360,6 +346,15 @@ static SIMPLE_DEV_PM_OPS(iwl_dev_pm_ops, iwl_pci_suspend, iwl_pci_resume); #endif +#ifdef CONFIG_IWLWIFI_IDI +/* + * Defined externally in iwl-idi.c + */ +int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent); +void __devexit iwl_pci_remove(struct pci_dev *pdev); + +#endif /* CONFIG_IWLWIFI_IDI */ + static struct pci_driver iwl_pci_driver = { .name = DRV_NAME, .id_table = iwl_hw_card_ids, diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-phy-db.c b/trunk/drivers/net/wireless/iwlwifi/iwl-phy-db.c new file mode 100644 index 000000000000..f166955340fe --- /dev/null +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-phy-db.c @@ -0,0 +1,288 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007 - 2012 Intel 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 + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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 +#include + +#include "iwl-debug.h" +#include "iwl-dev.h" + +#include "iwl-phy-db.h" + +#define CHANNEL_NUM_SIZE 4 /* num of channels in calib_ch size */ + +struct iwl_phy_db *iwl_phy_db_init(struct device *dev) +{ + struct iwl_phy_db *phy_db = kzalloc(sizeof(struct iwl_phy_db), + GFP_KERNEL); + + if (!phy_db) + return phy_db; + + phy_db->dev = dev; + + /* TODO: add default values of the phy db. */ + return phy_db; +} + +/* + * get phy db section: returns a pointer to a phy db section specified by + * type and channel group id. + */ +static struct iwl_phy_db_entry * +iwl_phy_db_get_section(struct iwl_phy_db *phy_db, + enum iwl_phy_db_section_type type, + u16 chg_id) +{ + if (!phy_db || type < 0 || type >= IWL_PHY_DB_MAX) + return NULL; + + switch (type) { + case IWL_PHY_DB_CFG: + return &phy_db->cfg; + case IWL_PHY_DB_CALIB_NCH: + return &phy_db->calib_nch; + case IWL_PHY_DB_CALIB_CH: + return &phy_db->calib_ch; + case IWL_PHY_DB_CALIB_CHG_PAPD: + if (chg_id < 0 || chg_id >= IWL_NUM_PAPD_CH_GROUPS) + return NULL; + return &phy_db->calib_ch_group_papd[chg_id]; + case IWL_PHY_DB_CALIB_CHG_TXP: + if (chg_id < 0 || chg_id >= IWL_NUM_TXP_CH_GROUPS) + return NULL; + return &phy_db->calib_ch_group_txp[chg_id]; + default: + return NULL; + } + return NULL; +} + +static void iwl_phy_db_free_section(struct iwl_phy_db *phy_db, + enum iwl_phy_db_section_type type, + u16 chg_id) +{ + struct iwl_phy_db_entry *entry = + iwl_phy_db_get_section(phy_db, type, chg_id); + if (!entry) + return; + + kfree(entry->data); + entry->data = NULL; + entry->size = 0; +} + +void iwl_phy_db_free(struct iwl_phy_db *phy_db) +{ + int i; + + if (!phy_db) + return; + + iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CFG, 0); + iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_NCH, 0); + iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CH, 0); + for (i = 0; i < IWL_NUM_PAPD_CH_GROUPS; i++) + iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CHG_PAPD, i); + for (i = 0; i < IWL_NUM_TXP_CH_GROUPS; i++) + iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CHG_TXP, i); + + kfree(phy_db); +} + +int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, + enum iwl_phy_db_section_type type, u8 *data, + u16 size, gfp_t alloc_ctx) +{ + struct iwl_phy_db_entry *entry; + u16 chg_id = 0; + + if (!phy_db) + return -EINVAL; + + if (type == IWL_PHY_DB_CALIB_CHG_PAPD || + type == IWL_PHY_DB_CALIB_CHG_TXP) + chg_id = le16_to_cpup((__le16 *)data); + + entry = iwl_phy_db_get_section(phy_db, type, chg_id); + if (!entry) + return -EINVAL; + + kfree(entry->data); + entry->data = kmemdup(data, size, alloc_ctx); + if (!entry->data) { + entry->size = 0; + return -ENOMEM; + } + + entry->size = size; + + if (type == IWL_PHY_DB_CALIB_CH) { + phy_db->channel_num = le32_to_cpup((__le32 *)data); + phy_db->channel_size = + (size - CHANNEL_NUM_SIZE) / phy_db->channel_num; + } + + return 0; +} + +static int is_valid_channel(u16 ch_id) +{ + if (ch_id <= 14 || + (36 <= ch_id && ch_id <= 64 && ch_id % 4 == 0) || + (100 <= ch_id && ch_id <= 140 && ch_id % 4 == 0) || + (145 <= ch_id && ch_id <= 165 && ch_id % 4 == 1)) + return 1; + return 0; +} + +static u8 ch_id_to_ch_index(u16 ch_id) +{ + if (WARN_ON(!is_valid_channel(ch_id))) + return 0xff; + + if (ch_id <= 14) + return ch_id - 1; + if (ch_id <= 64) + return (ch_id + 20) / 4; + if (ch_id <= 140) + return (ch_id - 12) / 4; + return (ch_id - 13) / 4; +} + + +static u16 channel_id_to_papd(u16 ch_id) +{ + if (WARN_ON(!is_valid_channel(ch_id))) + return 0xff; + + if (1 <= ch_id && ch_id <= 14) + return 0; + if (36 <= ch_id && ch_id <= 64) + return 1; + if (100 <= ch_id && ch_id <= 140) + return 2; + return 3; +} + +static u16 channel_id_to_txp(struct iwl_phy_db *phy_db, u16 ch_id) +{ + struct iwl_phy_db_chg_txp *txp_chg; + int i; + u8 ch_index = ch_id_to_ch_index(ch_id); + if (ch_index == 0xff) + return 0xff; + + for (i = 0; i < IWL_NUM_TXP_CH_GROUPS; i++) { + txp_chg = (void *)phy_db->calib_ch_group_txp[i].data; + if (!txp_chg) + return 0xff; + /* + * Looking for the first channel group that its max channel is + * higher then wanted channel. + */ + if (le16_to_cpu(txp_chg->max_channel_idx) >= ch_index) + return i; + } + return 0xff; +} + +int iwl_phy_db_get_section_data(struct iwl_phy_db *phy_db, + enum iwl_phy_db_section_type type, u8 **data, + u16 *size, u16 ch_id) +{ + struct iwl_phy_db_entry *entry; + u32 channel_num; + u32 channel_size; + u16 ch_group_id = 0; + u16 index; + + if (!phy_db) + return -EINVAL; + + /* find wanted channel group */ + if (type == IWL_PHY_DB_CALIB_CHG_PAPD) + ch_group_id = channel_id_to_papd(ch_id); + else if (type == IWL_PHY_DB_CALIB_CHG_TXP) + ch_group_id = channel_id_to_txp(phy_db, ch_id); + + entry = iwl_phy_db_get_section(phy_db, type, ch_group_id); + if (!entry) + return -EINVAL; + + if (type == IWL_PHY_DB_CALIB_CH) { + index = ch_id_to_ch_index(ch_id); + channel_num = phy_db->channel_num; + channel_size = phy_db->channel_size; + if (index >= channel_num) { + IWL_ERR(phy_db, "Wrong channel number %d", ch_id); + return -EINVAL; + } + *data = entry->data + CHANNEL_NUM_SIZE + index * channel_size; + *size = channel_size; + } else { + *data = entry->data; + *size = entry->size; + } + return 0; +} diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-phy-db.h b/trunk/drivers/net/wireless/iwlwifi/iwl-phy-db.h new file mode 100644 index 000000000000..c34c6a9303ab --- /dev/null +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-phy-db.h @@ -0,0 +1,129 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007 - 2012 Intel 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 + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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. + * + *****************************************************************************/ + +#ifndef __IWL_PHYDB_H__ +#define __IWL_PHYDB_H__ + +#include + +#define IWL_NUM_PAPD_CH_GROUPS 4 +#define IWL_NUM_TXP_CH_GROUPS 8 + +struct iwl_phy_db_entry { + u16 size; + u8 *data; +}; + +struct iwl_shared; + +/** + * struct iwl_phy_db - stores phy configuration and calibration data. + * + * @cfg: phy configuration. + * @calib_nch: non channel specific calibration data. + * @calib_ch: channel specific calibration data. + * @calib_ch_group_papd: calibration data related to papd channel group. + * @calib_ch_group_txp: calibration data related to tx power chanel group. + */ +struct iwl_phy_db { + struct iwl_phy_db_entry cfg; + struct iwl_phy_db_entry calib_nch; + struct iwl_phy_db_entry calib_ch; + struct iwl_phy_db_entry calib_ch_group_papd[IWL_NUM_PAPD_CH_GROUPS]; + struct iwl_phy_db_entry calib_ch_group_txp[IWL_NUM_TXP_CH_GROUPS]; + + u32 channel_num; + u32 channel_size; + + /* for an access to the logger */ + struct device *dev; +}; + +enum iwl_phy_db_section_type { + IWL_PHY_DB_CFG = 1, + IWL_PHY_DB_CALIB_NCH, + IWL_PHY_DB_CALIB_CH, + IWL_PHY_DB_CALIB_CHG_PAPD, + IWL_PHY_DB_CALIB_CHG_TXP, + IWL_PHY_DB_MAX +}; + +/* for parsing of tx power channel group data that comes from the firmware*/ +struct iwl_phy_db_chg_txp { + __le32 space; + __le16 max_channel_idx; +} __packed; + +struct iwl_phy_db *iwl_phy_db_init(struct device *dev); + +void iwl_phy_db_free(struct iwl_phy_db *phy_db); + +int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, + enum iwl_phy_db_section_type type, u8 *data, + u16 size, gfp_t alloc_ctx); + +int iwl_phy_db_get_section_data(struct iwl_phy_db *phy_db, + enum iwl_phy_db_section_type type, u8 **data, + u16 *size, u16 ch_id); + +#endif /* __IWL_PHYDB_H__ */ diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-power.c b/trunk/drivers/net/wireless/iwlwifi/iwl-power.c index 958d9d09aee3..8352265dbc4b 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-power.c @@ -37,13 +37,12 @@ #include "iwl-eeprom.h" #include "iwl-dev.h" #include "iwl-agn.h" -#include "iwl-core.h" #include "iwl-io.h" #include "iwl-commands.h" #include "iwl-debug.h" #include "iwl-power.h" #include "iwl-trans.h" -#include "iwl-shared.h" +#include "iwl-modparams.h" /* * Setting power level allows the card to go to sleep when not busy. @@ -167,7 +166,7 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv, u8 skip; u32 slp_itrvl; - if (cfg(priv)->adv_pm) { + if (priv->cfg->adv_pm) { table = apm_range_2; if (period <= IWL_DTIM_RANGE_1_MAX) table = apm_range_1; @@ -215,13 +214,13 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv, else cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; - if (cfg(priv)->base_params->shadow_reg_enable) + if (priv->cfg->base_params->shadow_reg_enable) cmd->flags |= IWL_POWER_SHADOW_REG_ENA; else cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA; if (iwl_advanced_bt_coexist(priv)) { - if (!cfg(priv)->bt_params->bt_sco_disable) + if (!priv->cfg->bt_params->bt_sco_disable) cmd->flags |= IWL_POWER_BT_SCO_ENA; else cmd->flags &= ~IWL_POWER_BT_SCO_ENA; @@ -268,61 +267,6 @@ static void iwl_power_sleep_cam_cmd(struct iwl_priv *priv, IWL_DEBUG_POWER(priv, "Sleep command for CAM\n"); } -static void iwl_power_fill_sleep_cmd(struct iwl_priv *priv, - struct iwl_powertable_cmd *cmd, - int dynps_ms, int wakeup_period) -{ - /* - * These are the original power level 3 sleep successions. The - * device may behave better with such succession and was also - * only tested with that. Just like the original sleep commands, - * also adjust the succession here to the wakeup_period below. - * The ranges are the same as for the sleep commands, 0-2, 3-9 - * and >10, which is selected based on the DTIM interval for - * the sleep index but here we use the wakeup period since that - * is what we need to do for the latency requirements. - */ - static const u8 slp_succ_r0[IWL_POWER_VEC_SIZE] = { 2, 2, 2, 2, 2 }; - static const u8 slp_succ_r1[IWL_POWER_VEC_SIZE] = { 2, 4, 6, 7, 9 }; - static const u8 slp_succ_r2[IWL_POWER_VEC_SIZE] = { 2, 7, 9, 9, 0xFF }; - const u8 *slp_succ = slp_succ_r0; - int i; - - if (wakeup_period > IWL_DTIM_RANGE_0_MAX) - slp_succ = slp_succ_r1; - if (wakeup_period > IWL_DTIM_RANGE_1_MAX) - slp_succ = slp_succ_r2; - - memset(cmd, 0, sizeof(*cmd)); - - cmd->flags = IWL_POWER_DRIVER_ALLOW_SLEEP_MSK | - IWL_POWER_FAST_PD; /* no use seeing frames for others */ - - if (priv->power_data.bus_pm) - cmd->flags |= IWL_POWER_PCI_PM_MSK; - - if (cfg(priv)->base_params->shadow_reg_enable) - cmd->flags |= IWL_POWER_SHADOW_REG_ENA; - else - cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA; - - if (iwl_advanced_bt_coexist(priv)) { - if (!cfg(priv)->bt_params->bt_sco_disable) - cmd->flags |= IWL_POWER_BT_SCO_ENA; - else - cmd->flags &= ~IWL_POWER_BT_SCO_ENA; - } - - cmd->rx_data_timeout = cpu_to_le32(1000 * dynps_ms); - cmd->tx_data_timeout = cpu_to_le32(1000 * dynps_ms); - - for (i = 0; i < IWL_POWER_VEC_SIZE; i++) - cmd->sleep_interval[i] = - cpu_to_le32(min_t(int, slp_succ[i], wakeup_period)); - - IWL_DEBUG_POWER(priv, "Automatic sleep command\n"); -} - static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd) { IWL_DEBUG_POWER(priv, "Sending power/sleep command\n"); @@ -350,7 +294,7 @@ static void iwl_power_build_cmd(struct iwl_priv *priv, if (priv->wowlan) iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, dtimper); - else if (!cfg(priv)->base_params->no_idle_support && + else if (!priv->cfg->base_params->no_idle_support && priv->hw->conf.flags & IEEE80211_CONF_IDLE) iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20); else if (iwl_tt_is_low_power_state(priv)) { @@ -363,18 +307,15 @@ static void iwl_power_build_cmd(struct iwl_priv *priv, iwl_static_sleep_cmd(priv, cmd, priv->power_data.debug_sleep_level_override, dtimper); - else if (iwlagn_mod_params.no_sleep_autoadjust) { - if (iwlagn_mod_params.power_level > IWL_POWER_INDEX_1 && - iwlagn_mod_params.power_level <= IWL_POWER_INDEX_5) + else { + if (iwlwifi_mod_params.power_level > IWL_POWER_INDEX_1 && + iwlwifi_mod_params.power_level <= IWL_POWER_INDEX_5) iwl_static_sleep_cmd(priv, cmd, - iwlagn_mod_params.power_level, dtimper); + iwlwifi_mod_params.power_level, dtimper); else iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_1, dtimper); - } else - iwl_power_fill_sleep_cmd(priv, cmd, - priv->hw->conf.dynamic_ps_timeout, - priv->hw->conf.max_sleep_period); + } } int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd, @@ -403,12 +344,12 @@ int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd, } if (cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK) - set_bit(STATUS_POWER_PMI, &priv->shrd->status); + iwl_dvm_set_pmi(priv, true); ret = iwl_set_power(priv, cmd); if (!ret) { if (!(cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)) - clear_bit(STATUS_POWER_PMI, &priv->shrd->status); + iwl_dvm_set_pmi(priv, false); if (update_chains) iwl_update_chain_flags(priv); @@ -436,7 +377,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) /* initialize to default */ void iwl_power_initialize(struct iwl_priv *priv) { - priv->power_data.bus_pm = trans(priv)->pm_support; + priv->power_data.bus_pm = priv->trans->pm_support; priv->power_data.debug_sleep_level_override = -1; diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-power.h b/trunk/drivers/net/wireless/iwlwifi/iwl-power.h index 07a19fce5fdc..21afc92efacb 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-power.h @@ -30,15 +30,6 @@ #include "iwl-commands.h" -enum iwl_power_level { - IWL_POWER_INDEX_1, - IWL_POWER_INDEX_2, - IWL_POWER_INDEX_3, - IWL_POWER_INDEX_4, - IWL_POWER_INDEX_5, - IWL_POWER_NUM -}; - struct iwl_power_mgr { struct iwl_powertable_cmd sleep_cmd; struct iwl_powertable_cmd sleep_cmd_next; diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-scan.c b/trunk/drivers/net/wireless/iwlwifi/iwl-scan.c index 902efe4bc898..a8437a6bc18e 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -32,7 +32,6 @@ #include "iwl-eeprom.h" #include "iwl-dev.h" -#include "iwl-core.h" #include "iwl-io.h" #include "iwl-agn.h" #include "iwl-trans.h" @@ -69,7 +68,7 @@ static int iwl_send_scan_abort(struct iwl_priv *priv) if (!test_bit(STATUS_READY, &priv->status) || !test_bit(STATUS_GEO_CONFIGURED, &priv->status) || !test_bit(STATUS_SCAN_HW, &priv->status) || - test_bit(STATUS_FW_ERROR, &priv->shrd->status)) + test_bit(STATUS_FW_ERROR, &priv->status)) return -EIO; ret = iwl_dvm_send_cmd(priv, &cmd); @@ -451,6 +450,46 @@ static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, return iwl_limit_dwell(priv, passive); } +/* Return valid, unused, channel for a passive scan to reset the RF */ +static u8 iwl_get_single_channel_number(struct iwl_priv *priv, + enum ieee80211_band band) +{ + const struct iwl_channel_info *ch_info; + int i; + u8 channel = 0; + u8 min, max; + struct iwl_rxon_context *ctx; + + if (band == IEEE80211_BAND_5GHZ) { + min = 14; + max = priv->channel_count; + } else { + min = 0; + max = 14; + } + + for (i = min; i < max; i++) { + bool busy = false; + + for_each_context(priv, ctx) { + busy = priv->channel_info[i].channel == + le16_to_cpu(ctx->staging.channel); + if (busy) + break; + } + + if (busy) + continue; + + channel = priv->channel_info[i].channel; + ch_info = iwl_get_channel_info(priv, band, channel); + if (is_channel_valid(ch_info)) + break; + } + + return channel; +} + static int iwl_get_single_channel_for_scan(struct iwl_priv *priv, struct ieee80211_vif *vif, enum ieee80211_band band, @@ -633,12 +672,12 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) u16 rx_chain = 0; enum ieee80211_band band; u8 n_probes = 0; - u8 rx_ant = hw_params(priv).valid_rx_ant; + u8 rx_ant = priv->hw_params.valid_rx_ant; u8 rate; bool is_active = false; int chan_mod; u8 active_chains; - u8 scan_tx_antennas = hw_params(priv).valid_tx_ant; + u8 scan_tx_antennas = priv->hw_params.valid_tx_ant; int ret; lockdep_assert_held(&priv->mutex); @@ -751,8 +790,8 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) * Internal scans are passive, so we can indiscriminately set * the BT ignore flag on 2.4 GHz since it applies to TX only. */ - if (cfg(priv)->bt_params && - cfg(priv)->bt_params->advanced_bt_coexist) + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist) scan->tx_cmd.tx_flags |= TX_CMD_FLG_IGNORE_BT; break; case IEEE80211_BAND_5GHZ: @@ -793,12 +832,9 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) band = priv->scan_band; - if (cfg(priv)->scan_rx_antennas[band]) - rx_ant = cfg(priv)->scan_rx_antennas[band]; - if (band == IEEE80211_BAND_2GHZ && - cfg(priv)->bt_params && - cfg(priv)->bt_params->advanced_bt_coexist) { + priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist) { /* transmit 2.4 GHz probes only on first antenna */ scan_tx_antennas = first_antenna(scan_tx_antennas); } @@ -809,8 +845,12 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]); scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags); - /* In power save mode use one chain, otherwise use all chains */ - if (test_bit(STATUS_POWER_PMI, &priv->shrd->status)) { + /* + * In power save mode while associated use one chain, + * otherwise use all chains + */ + if (test_bit(STATUS_POWER_PMI, &priv->status) && + !(priv->hw->conf.flags & IEEE80211_CONF_IDLE)) { /* rx_ant has been set to all valid chains previously */ active_chains = rx_ant & ((u8)(priv->chain_noise_data.active_chains)); @@ -822,8 +862,8 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) rx_ant = first_antenna(active_chains); } - if (cfg(priv)->bt_params && - cfg(priv)->bt_params->advanced_bt_coexist && + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist && priv->bt_full_concurrent) { /* operated as 1x1 in full concurrency mode */ rx_ant = first_antenna(rx_ant); @@ -831,7 +871,7 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) /* MIMO is not used here, but value is required */ rx_chain |= - hw_params(priv).valid_rx_ant << RXON_RX_CHAIN_VALID_POS; + priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS; rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS; rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS; rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS; @@ -944,7 +984,7 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) void iwl_init_scan_params(struct iwl_priv *priv) { - u8 ant_idx = fls(hw_params(priv).valid_tx_ant) - 1; + u8 ant_idx = fls(priv->hw_params.valid_tx_ant) - 1; if (!priv->scan_tx_ant[IEEE80211_BAND_5GHZ]) priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = ant_idx; if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ]) diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-shared.h b/trunk/drivers/net/wireless/iwlwifi/iwl-shared.h deleted file mode 100644 index b515d657a0ad..000000000000 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-shared.h +++ /dev/null @@ -1,435 +0,0 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2007 - 2012 Intel 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 - * - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * Contact Information: - * Intel Linux Wireless - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * 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. - * - *****************************************************************************/ -#ifndef __iwl_shared_h__ -#define __iwl_shared_h__ - -#include -#include -#include -#include - -#include "iwl-commands.h" -#include "iwl-fw.h" - -/** - * DOC: shared area - role and goal - * - * The shared area contains all the data exported by the upper layer to the - * other layers. Since the bus and transport layer shouldn't dereference - * iwl_priv, all the data needed by the upper layer and the transport / bus - * layer must be here. - * The shared area also holds pointer to all the other layers. This allows a - * layer to call a function from another layer. - * - * NOTE: All the layers hold a pointer to the shared area which must be shrd. - * A few macros assume that (_m)->shrd points to the shared area no matter - * what _m is. - * - * gets notifications about enumeration, suspend, resume. - * For the moment, the bus layer is not a linux kernel module as itself, and - * the module_init function of the driver must call the bus specific - * registration functions. These functions are listed at the end of this file. - * For the moment, there is only one implementation of this interface: PCI-e. - * This implementation is iwl-pci.c - */ - -struct iwl_priv; -struct iwl_trans; -struct iwl_sensitivity_ranges; -struct iwl_trans_ops; - -#define DRV_NAME "iwlwifi" -#define IWLWIFI_VERSION "in-tree:" -#define DRV_COPYRIGHT "Copyright(c) 2003-2012 Intel Corporation" -#define DRV_AUTHOR "" - -extern struct iwl_mod_params iwlagn_mod_params; - -#define IWL_DISABLE_HT_ALL BIT(0) -#define IWL_DISABLE_HT_TXAGG BIT(1) -#define IWL_DISABLE_HT_RXAGG BIT(2) - -/** - * struct iwl_mod_params - * - * Holds the module parameters - * - * @sw_crypto: using hardware encryption, default = 0 - * @disable_11n: disable 11n capabilities, default = 0, - * use IWL_DISABLE_HT_* constants - * @amsdu_size_8K: enable 8K amsdu size, default = 1 - * @antenna: both antennas (use diversity), default = 0 - * @restart_fw: restart firmware, default = 1 - * @plcp_check: enable plcp health check, default = true - * @ack_check: disable ack health check, default = false - * @wd_disable: enable stuck queue check, default = 0 - * @bt_coex_active: enable bt coex, default = true - * @led_mode: system default, default = 0 - * @no_sleep_autoadjust: disable autoadjust, default = true - * @power_save: disable power save, default = false - * @power_level: power level, default = 1 - * @debug_level: levels are IWL_DL_* - * @ant_coupling: antenna coupling in dB, default = 0 - * @bt_ch_announce: BT channel inhibition, default = enable - * @wanted_ucode_alternative: ucode alternative to use, default = 1 - * @auto_agg: enable agg. without check, default = true - */ -struct iwl_mod_params { - int sw_crypto; - unsigned int disable_11n; - int amsdu_size_8K; - int antenna; - int restart_fw; - bool plcp_check; - bool ack_check; - int wd_disable; - bool bt_coex_active; - int led_mode; - bool no_sleep_autoadjust; - bool power_save; - int power_level; - u32 debug_level; - int ant_coupling; - bool bt_ch_announce; - int wanted_ucode_alternative; - bool auto_agg; -}; - -/** - * struct iwl_hw_params - * - * Holds the module parameters - * - * @num_ampdu_queues: num of ampdu queues - * @tx_chains_num: Number of TX chains - * @rx_chains_num: Number of RX chains - * @valid_tx_ant: usable antennas for TX - * @valid_rx_ant: usable antennas for RX - * @ht40_channel: is 40MHz width possible: BIT(IEEE80211_BAND_XXX) - * @sku: sku read from EEPROM - * @rx_page_order: Rx buffer page order - * @ct_kill_threshold: temperature threshold - in hw dependent unit - * @ct_kill_exit_threshold: when to reeable the device - in hw dependent unit - * relevant for 1000, 6000 and up - * @wd_timeout: TX queues watchdog timeout - * @struct iwl_sensitivity_ranges: range of sensitivity values - * @use_rts_for_aggregation: use rts/cts protection for HT traffic - */ -struct iwl_hw_params { - u8 num_ampdu_queues; - u8 tx_chains_num; - u8 rx_chains_num; - u8 valid_tx_ant; - u8 valid_rx_ant; - u8 ht40_channel; - bool use_rts_for_aggregation; - u16 sku; - u32 rx_page_order; - u32 ct_kill_threshold; - u32 ct_kill_exit_threshold; - unsigned int wd_timeout; - - const struct iwl_sensitivity_ranges *sens; -}; - -/* - * LED mode - * IWL_LED_DEFAULT: use device default - * IWL_LED_RF_STATE: turn LED on/off based on RF state - * LED ON = RF ON - * LED OFF = RF OFF - * IWL_LED_BLINK: adjust led blink rate based on blink table - * IWL_LED_DISABLE: led disabled - */ -enum iwl_led_mode { - IWL_LED_DEFAULT, - IWL_LED_RF_STATE, - IWL_LED_BLINK, - IWL_LED_DISABLE, -}; - -/* - * @max_ll_items: max number of OTP blocks - * @shadow_ram_support: shadow support for OTP memory - * @led_compensation: compensate on the led on/off time per HW according - * to the deviation to achieve the desired led frequency. - * The detail algorithm is described in iwl-led.c - * @chain_noise_num_beacons: number of beacons used to compute chain noise - * @adv_thermal_throttle: support advance thermal throttle - * @support_ct_kill_exit: support ct kill exit condition - * @support_wimax_coexist: support wimax/wifi co-exist - * @plcp_delta_threshold: plcp error rate threshold used to trigger - * radio tuning when there is a high receiving plcp error rate - * @chain_noise_scale: default chain noise scale used for gain computation - * @wd_timeout: TX queues watchdog timeout - * @max_event_log_size: size of event log buffer size for ucode event logging - * @shadow_reg_enable: HW shadhow register bit - * @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up - * @no_idle_support: do not support idle mode - * wd_disable: disable watchdog timer - */ -struct iwl_base_params { - int eeprom_size; - int num_of_queues; /* def: HW dependent */ - int num_of_ampdu_queues;/* def: HW dependent */ - /* for iwl_apm_init() */ - u32 pll_cfg_val; - - const u16 max_ll_items; - const bool shadow_ram_support; - u16 led_compensation; - bool adv_thermal_throttle; - bool support_ct_kill_exit; - const bool support_wimax_coexist; - u8 plcp_delta_threshold; - s32 chain_noise_scale; - unsigned int wd_timeout; - u32 max_event_log_size; - const bool shadow_reg_enable; - const bool hd_v2; - const bool no_idle_support; - const bool wd_disable; -}; - -/* - * @advanced_bt_coexist: support advanced bt coexist - * @bt_init_traffic_load: specify initial bt traffic load - * @bt_prio_boost: default bt priority boost value - * @agg_time_limit: maximum number of uSec in aggregation - * @bt_sco_disable: uCode should not response to BT in SCO/ESCO mode - */ -struct iwl_bt_params { - bool advanced_bt_coexist; - u8 bt_init_traffic_load; - u8 bt_prio_boost; - u16 agg_time_limit; - bool bt_sco_disable; - bool bt_session_2; -}; -/* - * @use_rts_for_aggregation: use rts/cts protection for HT traffic - */ -struct iwl_ht_params { - const bool ht_greenfield_support; /* if used set to true */ - bool use_rts_for_aggregation; - enum ieee80211_smps_mode smps_mode; -}; - -/** - * struct iwl_cfg - * @name: Offical name of the device - * @fw_name_pre: Firmware filename prefix. The api version and extension - * (.ucode) will be added to filename before loading from disk. The - * filename is constructed as fw_name_pre.ucode. - * @ucode_api_max: Highest version of uCode API supported by driver. - * @ucode_api_ok: oldest version of the uCode API that is OK to load - * without a warning, for use in transitions - * @ucode_api_min: Lowest version of uCode API supported by driver. - * @max_inst_size: The maximal length of the fw inst section - * @max_data_size: The maximal length of the fw data section - * @valid_tx_ant: valid transmit antenna - * @valid_rx_ant: valid receive antenna - * @eeprom_ver: EEPROM version - * @eeprom_calib_ver: EEPROM calibration version - * @lib: pointer to the lib ops - * @additional_nic_config: additional nic configuration - * @base_params: pointer to basic parameters - * @ht_params: point to ht patameters - * @bt_params: pointer to bt parameters - * @need_temp_offset_calib: need to perform temperature offset calibration - * @no_xtal_calib: some devices do not need crystal calibration data, - * don't send it to those - * @scan_rx_antennas: available antenna for scan operation - * @led_mode: 0=blinking, 1=On(RF On)/Off(RF Off) - * @adv_pm: advance power management - * @rx_with_siso_diversity: 1x1 device with rx antenna diversity - * @internal_wimax_coex: internal wifi/wimax combo device - * @iq_invert: I/Q inversion - * @temp_offset_v2: support v2 of temperature offset calibration - * - * We enable the driver to be backward compatible wrt API version. The - * driver specifies which APIs it supports (with @ucode_api_max being the - * highest and @ucode_api_min the lowest). Firmware will only be loaded if - * it has a supported API version. - * - * The ideal usage of this infrastructure is to treat a new ucode API - * release as a new hardware revision. - */ -struct iwl_cfg { - /* params specific to an individual device within a device family */ - const char *name; - const char *fw_name_pre; - const unsigned int ucode_api_max; - const unsigned int ucode_api_ok; - const unsigned int ucode_api_min; - const u32 max_data_size; - const u32 max_inst_size; - u8 valid_tx_ant; - u8 valid_rx_ant; - u16 eeprom_ver; - u16 eeprom_calib_ver; - const struct iwl_lib_ops *lib; - void (*additional_nic_config)(struct iwl_priv *priv); - /* params not likely to change within a device family */ - const struct iwl_base_params *base_params; - /* params likely to change within a device family */ - const struct iwl_ht_params *ht_params; - const struct iwl_bt_params *bt_params; - const bool need_temp_offset_calib; /* if used set to true */ - const bool no_xtal_calib; - u8 scan_rx_antennas[IEEE80211_NUM_BANDS]; - enum iwl_led_mode led_mode; - const bool adv_pm; - const bool rx_with_siso_diversity; - const bool internal_wimax_coex; - const bool iq_invert; - const bool temp_offset_v2; -}; - -/** - * struct iwl_shared - shared fields for all the layers of the driver - * - * @status: STATUS_* - * @wowlan: are we running wowlan uCode - * @valid_contexts: microcode/device supports multiple contexts - * @bus: pointer to the bus layer data - * @cfg: see struct iwl_cfg - * @priv: pointer to the upper layer data - * @trans: pointer to the transport layer data - * @nic: pointer to the nic data - * @hw_params: see struct iwl_hw_params - * @lock: protect general shared data - * @eeprom: pointer to the eeprom/OTP image - * @ucode_type: indicator of loaded ucode image - * @device_pointers: pointers to ucode event tables - */ -struct iwl_shared { - unsigned long status; - u8 valid_contexts; - - const struct iwl_cfg *cfg; - struct iwl_trans *trans; - void *drv; - struct iwl_hw_params hw_params; - const struct iwl_fw *fw; - - /* eeprom -- this is in the card's little endian byte order */ - u8 *eeprom; - - /* ucode related variables */ - enum iwl_ucode_type ucode_type; - - struct { - u32 error_event_table; - u32 log_event_table; - } device_pointers; - -}; - -/*Whatever _m is (iwl_trans, iwl_priv, these macros will work */ -#define cfg(_m) ((_m)->shrd->cfg) -#define trans(_m) ((_m)->shrd->trans) -#define hw_params(_m) ((_m)->shrd->hw_params) - -static inline bool iwl_have_debug_level(u32 level) -{ - return iwlagn_mod_params.debug_level & level; -} - -enum iwl_rxon_context_id { - IWL_RXON_CTX_BSS, - IWL_RXON_CTX_PAN, - - NUM_IWL_RXON_CTX -}; - -int iwlagn_hw_valid_rtc_data_addr(u32 addr); -const char *get_cmd_string(u8 cmd); - -#define IWL_CMD(x) case x: return #x - -/***************************************************** -* DRIVER STATUS FUNCTIONS -******************************************************/ -#define STATUS_HCMD_ACTIVE 0 /* host command in progress */ -/* 1 is unused (used to be STATUS_HCMD_SYNC_ACTIVE) */ -#define STATUS_INT_ENABLED 2 -#define STATUS_RF_KILL_HW 3 -#define STATUS_CT_KILL 4 -#define STATUS_INIT 5 -#define STATUS_ALIVE 6 -#define STATUS_READY 7 -#define STATUS_TEMPERATURE 8 -#define STATUS_GEO_CONFIGURED 9 -#define STATUS_EXIT_PENDING 10 -#define STATUS_STATISTICS 12 -#define STATUS_SCANNING 13 -#define STATUS_SCAN_ABORTING 14 -#define STATUS_SCAN_HW 15 -#define STATUS_POWER_PMI 16 -#define STATUS_FW_ERROR 17 -#define STATUS_DEVICE_ENABLED 18 -#define STATUS_CHANNEL_SWITCH_PENDING 19 -#define STATUS_SCAN_COMPLETE 20 - -#endif /* #__iwl_shared_h__ */ diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-testmode.c b/trunk/drivers/net/wireless/iwlwifi/iwl-testmode.c index 76f7f9251436..060aac3e22f1 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-testmode.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-testmode.c @@ -71,7 +71,6 @@ #include #include "iwl-dev.h" -#include "iwl-core.h" #include "iwl-debug.h" #include "iwl-io.h" #include "iwl-agn.h" @@ -184,9 +183,10 @@ static void iwl_testmode_ucode_rx_pkt(struct iwl_priv *priv, "Run out of memory for messages to user space ?\n"); return; } - NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_UCODE_RX_PKT); - /* the length doesn't include len_n_flags field, so add it manually */ - NLA_PUT(skb, IWL_TM_ATTR_UCODE_RX_PKT, length + sizeof(__le32), data); + if (nla_put_u32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_UCODE_RX_PKT) || + /* the length doesn't include len_n_flags field, so add it manually */ + nla_put(skb, IWL_TM_ATTR_UCODE_RX_PKT, length + sizeof(__le32), data)) + goto nla_put_failure; cfg80211_testmode_event(skb, GFP_ATOMIC); return; @@ -218,7 +218,7 @@ static void iwl_trace_cleanup(struct iwl_priv *priv) if (priv->testmode_trace.trace_enabled) { if (priv->testmode_trace.cpu_addr && priv->testmode_trace.dma_addr) - dma_free_coherent(trans(priv)->dev, + dma_free_coherent(priv->trans->dev, priv->testmode_trace.total_size, priv->testmode_trace.cpu_addr, priv->testmode_trace.dma_addr); @@ -314,8 +314,9 @@ static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb) memcpy(reply_buf, &(pkt->hdr), reply_len); iwl_free_resp(&cmd); - NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_UCODE_RX_PKT); - NLA_PUT(skb, IWL_TM_ATTR_UCODE_RX_PKT, reply_len, reply_buf); + if (nla_put_u32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_UCODE_RX_PKT) || + nla_put(skb, IWL_TM_ATTR_UCODE_RX_PKT, reply_len, reply_buf)) + goto nla_put_failure; return cfg80211_testmode_reply(skb); nla_put_failure: @@ -371,7 +372,7 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) switch (cmd) { case IWL_TM_CMD_APP2DEV_DIRECT_REG_READ32: - val32 = iwl_read_direct32(trans(priv), ofs); + val32 = iwl_read_direct32(priv->trans, ofs); IWL_INFO(priv, "32bit value to read 0x%x\n", val32); skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); @@ -379,7 +380,8 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) IWL_ERR(priv, "Memory allocation fail\n"); return -ENOMEM; } - NLA_PUT_U32(skb, IWL_TM_ATTR_REG_VALUE32, val32); + if (nla_put_u32(skb, IWL_TM_ATTR_REG_VALUE32, val32)) + goto nla_put_failure; status = cfg80211_testmode_reply(skb); if (status < 0) IWL_ERR(priv, "Error sending msg : %d\n", status); @@ -391,7 +393,7 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) } else { val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]); IWL_INFO(priv, "32bit value to write 0x%x\n", val32); - iwl_write_direct32(trans(priv), ofs, val32); + iwl_write_direct32(priv->trans, ofs, val32); } break; case IWL_TM_CMD_APP2DEV_DIRECT_REG_WRITE8: @@ -401,7 +403,7 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) } else { val8 = nla_get_u8(tb[IWL_TM_ATTR_REG_VALUE8]); IWL_INFO(priv, "8bit value to write 0x%x\n", val8); - iwl_write8(trans(priv), ofs, val8); + iwl_write8(priv->trans, ofs, val8); } break; default: @@ -420,10 +422,13 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv) { struct iwl_notification_wait calib_wait; + static const u8 calib_complete[] = { + CALIBRATION_COMPLETE_NOTIFICATION + }; int ret; iwl_init_notification_wait(&priv->notif_wait, &calib_wait, - CALIBRATION_COMPLETE_NOTIFICATION, + calib_complete, ARRAY_SIZE(calib_complete), NULL, NULL); ret = iwl_init_alive_start(priv); if (ret) { @@ -461,7 +466,7 @@ static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv) static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); - struct iwl_trans *trans = trans(priv); + struct iwl_trans *trans = priv->trans; struct sk_buff *skb; unsigned char *rsp_data_ptr = NULL; int status = 0, rsp_data_len = 0; @@ -470,18 +475,19 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) { case IWL_TM_CMD_APP2DEV_GET_DEVICENAME: - rsp_data_ptr = (unsigned char *)cfg(priv)->name; - rsp_data_len = strlen(cfg(priv)->name); + rsp_data_ptr = (unsigned char *)priv->cfg->name; + rsp_data_len = strlen(priv->cfg->name); skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, rsp_data_len + 20); if (!skb) { IWL_ERR(priv, "Memory allocation fail\n"); return -ENOMEM; } - NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, - IWL_TM_CMD_DEV2APP_SYNC_RSP); - NLA_PUT(skb, IWL_TM_ATTR_SYNC_RSP, - rsp_data_len, rsp_data_ptr); + if (nla_put_u32(skb, IWL_TM_ATTR_COMMAND, + IWL_TM_CMD_DEV2APP_SYNC_RSP) || + nla_put(skb, IWL_TM_ATTR_SYNC_RSP, + rsp_data_len, rsp_data_ptr)) + goto nla_put_failure; status = cfg80211_testmode_reply(skb); if (status < 0) IWL_ERR(priv, "Error sending msg : %d\n", status); @@ -529,18 +535,19 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) break; case IWL_TM_CMD_APP2DEV_GET_EEPROM: - if (priv->shrd->eeprom) { + if (priv->eeprom) { skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, - cfg(priv)->base_params->eeprom_size + 20); + priv->cfg->base_params->eeprom_size + 20); if (!skb) { IWL_ERR(priv, "Memory allocation fail\n"); return -ENOMEM; } - NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, - IWL_TM_CMD_DEV2APP_EEPROM_RSP); - NLA_PUT(skb, IWL_TM_ATTR_EEPROM, - cfg(priv)->base_params->eeprom_size, - priv->shrd->eeprom); + if (nla_put_u32(skb, IWL_TM_ATTR_COMMAND, + IWL_TM_CMD_DEV2APP_EEPROM_RSP) || + nla_put(skb, IWL_TM_ATTR_EEPROM, + priv->cfg->base_params->eeprom_size, + priv->eeprom)) + goto nla_put_failure; status = cfg80211_testmode_reply(skb); if (status < 0) IWL_ERR(priv, "Error sending msg : %d\n", @@ -566,15 +573,16 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) IWL_ERR(priv, "Memory allocation fail\n"); return -ENOMEM; } - NLA_PUT_U32(skb, IWL_TM_ATTR_FW_VERSION, - priv->fw->ucode_ver); + if (nla_put_u32(skb, IWL_TM_ATTR_FW_VERSION, + priv->fw->ucode_ver)) + goto nla_put_failure; status = cfg80211_testmode_reply(skb); if (status < 0) IWL_ERR(priv, "Error sending msg : %d\n", status); break; case IWL_TM_CMD_APP2DEV_GET_DEVICE_ID: - devid = trans(priv)->hw_id; + devid = priv->trans->hw_id; IWL_INFO(priv, "hw version: 0x%x\n", devid); skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); @@ -582,7 +590,8 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) IWL_ERR(priv, "Memory allocation fail\n"); return -ENOMEM; } - NLA_PUT_U32(skb, IWL_TM_ATTR_DEVICE_ID, devid); + if (nla_put_u32(skb, IWL_TM_ATTR_DEVICE_ID, devid)) + goto nla_put_failure; status = cfg80211_testmode_reply(skb); if (status < 0) IWL_ERR(priv, "Error sending msg : %d\n", status); @@ -598,13 +607,14 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) IWL_ERR(priv, "No uCode has not been loaded\n"); return -EINVAL; } else { - img = &priv->fw->img[priv->shrd->ucode_type]; + img = &priv->fw->img[priv->cur_ucode]; inst_size = img->sec[IWL_UCODE_SECTION_INST].len; data_size = img->sec[IWL_UCODE_SECTION_DATA].len; } - NLA_PUT_U32(skb, IWL_TM_ATTR_FW_TYPE, priv->shrd->ucode_type); - NLA_PUT_U32(skb, IWL_TM_ATTR_FW_INST_SIZE, inst_size); - NLA_PUT_U32(skb, IWL_TM_ATTR_FW_DATA_SIZE, data_size); + if (nla_put_u32(skb, IWL_TM_ATTR_FW_TYPE, priv->cur_ucode) || + nla_put_u32(skb, IWL_TM_ATTR_FW_INST_SIZE, inst_size) || + nla_put_u32(skb, IWL_TM_ATTR_FW_DATA_SIZE, data_size)) + goto nla_put_failure; status = cfg80211_testmode_reply(skb); if (status < 0) IWL_ERR(priv, "Error sending msg : %d\n", status); @@ -639,7 +649,7 @@ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb) struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct sk_buff *skb; int status = 0; - struct device *dev = trans(priv)->dev; + struct device *dev = priv->trans->dev; switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) { case IWL_TM_CMD_APP2DEV_BEGIN_TRACE: @@ -678,9 +688,10 @@ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb) iwl_trace_cleanup(priv); return -ENOMEM; } - NLA_PUT(skb, IWL_TM_ATTR_TRACE_ADDR, - sizeof(priv->testmode_trace.dma_addr), - (u64 *)&priv->testmode_trace.dma_addr); + if (nla_put(skb, IWL_TM_ATTR_TRACE_ADDR, + sizeof(priv->testmode_trace.dma_addr), + (u64 *)&priv->testmode_trace.dma_addr)) + goto nla_put_failure; status = cfg80211_testmode_reply(skb); if (status < 0) { IWL_ERR(priv, "Error sending msg : %d\n", status); @@ -725,9 +736,10 @@ static int iwl_testmode_trace_dump(struct ieee80211_hw *hw, length = priv->testmode_trace.buff_size % DUMP_CHUNK_SIZE; - NLA_PUT(skb, IWL_TM_ATTR_TRACE_DUMP, length, - priv->testmode_trace.trace_addr + - (DUMP_CHUNK_SIZE * idx)); + if (nla_put(skb, IWL_TM_ATTR_TRACE_DUMP, length, + priv->testmode_trace.trace_addr + + (DUMP_CHUNK_SIZE * idx))) + goto nla_put_failure; idx++; cb->args[4] = idx; return 0; @@ -779,7 +791,7 @@ static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb) static int iwl_testmode_indirect_read(struct iwl_priv *priv, u32 addr, u32 size) { - struct iwl_trans *trans = trans(priv); + struct iwl_trans *trans = priv->trans; unsigned long flags; int i; @@ -819,7 +831,7 @@ static int iwl_testmode_indirect_read(struct iwl_priv *priv, u32 addr, u32 size) static int iwl_testmode_indirect_write(struct iwl_priv *priv, u32 addr, u32 size, unsigned char *buf) { - struct iwl_trans *trans = trans(priv); + struct iwl_trans *trans = priv->trans; u32 val, i; unsigned long flags; @@ -922,9 +934,10 @@ static int iwl_testmode_buffer_dump(struct ieee80211_hw *hw, length = priv->testmode_mem.buff_size % DUMP_CHUNK_SIZE; - NLA_PUT(skb, IWL_TM_ATTR_BUFFER_DUMP, length, - priv->testmode_mem.buff_addr + - (DUMP_CHUNK_SIZE * idx)); + if (nla_put(skb, IWL_TM_ATTR_BUFFER_DUMP, length, + priv->testmode_mem.buff_addr + + (DUMP_CHUNK_SIZE * idx))) + goto nla_put_failure; idx++; cb->args[4] = idx; return 0; diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h b/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h index 1c2fe87bd7e2..6213c05a4b52 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h @@ -34,17 +34,15 @@ #include #include #include +#include #include "iwl-fh.h" #include "iwl-csr.h" -#include "iwl-shared.h" #include "iwl-trans.h" #include "iwl-debug.h" #include "iwl-io.h" #include "iwl-op-mode.h" -struct iwl_tx_queue; -struct iwl_queue; struct iwl_host_cmd; /*This file includes the declaration that are internal to the @@ -136,21 +134,14 @@ static inline int iwl_queue_dec_wrap(int index, int n_bd) return --index & (n_bd - 1); } -/* - * This queue number is required for proper operation - * because the ucode will stop/start the scheduler as - * required. - */ -#define IWL_IPAN_MCAST_QUEUE 8 - struct iwl_cmd_meta { /* only for SYNC commands, iff the reply skb is wanted */ struct iwl_host_cmd *source; - u32 flags; - DEFINE_DMA_UNMAP_ADDR(mapping); DEFINE_DMA_UNMAP_LEN(len); + + u32 flags; }; /* @@ -188,72 +179,66 @@ struct iwl_queue { * space less than this */ }; +#define TFD_TX_CMD_SLOTS 256 +#define TFD_CMD_SLOTS 32 + +struct iwl_pcie_tx_queue_entry { + struct iwl_device_cmd *cmd; + struct sk_buff *skb; + struct iwl_cmd_meta meta; +}; + /** * struct iwl_tx_queue - Tx Queue for DMA * @q: generic Rx/Tx queue descriptor - * @bd: base of circular buffer of TFDs - * @cmd: array of command/TX buffer pointers - * @meta: array of meta data for each command/tx buffer - * @dma_addr_cmd: physical address of cmd/tx buffer array - * @txb: array of per-TFD driver data - * lock: queue lock - * @time_stamp: time (in jiffies) of last read_ptr change + * @tfds: transmit frame descriptors (DMA memory) + * @entries: transmit entries (driver state) + * @lock: queue lock + * @stuck_timer: timer that fires if queue gets stuck + * @trans_pcie: pointer back to transport (for timer) * @need_update: indicates need to update read/write index - * @sched_retry: indicates queue is high-throughput aggregation (HT AGG) enabled - * @sta_id: valid if sched_retry is set - * @tid: valid if sched_retry is set + * @active: stores if queue is active * * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame * descriptors) and required locking structures. */ -#define TFD_TX_CMD_SLOTS 256 -#define TFD_CMD_SLOTS 32 - struct iwl_tx_queue { struct iwl_queue q; struct iwl_tfd *tfds; - struct iwl_device_cmd **cmd; - struct iwl_cmd_meta *meta; - struct sk_buff **skbs; + struct iwl_pcie_tx_queue_entry *entries; spinlock_t lock; - unsigned long time_stamp; + struct timer_list stuck_timer; + struct iwl_trans_pcie *trans_pcie; u8 need_update; - u8 sched_retry; u8 active; - u8 swq_id; - - u16 sta_id; - u16 tid; }; /** * struct iwl_trans_pcie - PCIe transport specific data * @rxq: all the RX queue data * @rx_replenish: work that will be called when buffers need to be allocated + * @drv - pointer to iwl_drv * @trans: pointer to the generic transport area * @irq - the irq number for the device * @irq_requested: true when the irq has been requested * @scd_base_addr: scheduler sram base address in SRAM * @scd_bc_tbls: pointer to the byte count table of the scheduler * @kw: keep warm address - * @ac_to_fifo: to what fifo is a specifc AC mapped ? - * @ac_to_queue: to what tx queue is a specifc AC mapped ? - * @mcast_queue: - * @txq: Tx DMA processing queues - * @txq_ctx_active_msk: what queue is active - * queue_stopped: tracks what queue is stopped - * queue_stop_count: tracks what SW queue is stopped * @pci_dev: basic pci-network driver stuff * @hw_base: pci hardware address support * @ucode_write_complete: indicates that the ucode has been copied. * @ucode_write_waitq: wait queue for uCode load * @status - transport specific status flags * @cmd_queue - command queue number + * @rx_buf_size_8k: 8 kB RX buffer size + * @rx_page_order: page order for receive buffer size + * @wd_timeout: queue watchdog timeout (jiffies) */ struct iwl_trans_pcie { struct iwl_rx_queue rxq; struct work_struct rx_replenish; struct iwl_trans *trans; + struct iwl_drv *drv; /* INT ICT Table */ __le32 *ict_tbl; @@ -272,16 +257,9 @@ struct iwl_trans_pcie { struct iwl_dma_ptr scd_bc_tbls; struct iwl_dma_ptr kw; - const u8 *ac_to_fifo[NUM_IWL_RXON_CTX]; - const u8 *ac_to_queue[NUM_IWL_RXON_CTX]; - u8 mcast_queue[NUM_IWL_RXON_CTX]; - u8 agg_txq[IWLAGN_STATION_COUNT][IWL_MAX_TID_COUNT]; - struct iwl_tx_queue *txq; - unsigned long txq_ctx_active_msk; -#define IWL_MAX_HW_QUEUES 32 + unsigned long queue_used[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)]; unsigned long queue_stopped[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)]; - atomic_t queue_stop_count[4]; /* PCI bus related data */ struct pci_dev *pci_dev; @@ -293,11 +271,41 @@ struct iwl_trans_pcie { u8 cmd_queue; u8 n_no_reclaim_cmds; u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS]; + u8 setup_q_to_fifo[IWL_MAX_HW_QUEUES]; + u8 n_q_to_fifo; + + bool rx_buf_size_8k; + u32 rx_page_order; + + const char **command_names; + + /* queue watchdog */ + unsigned long wd_timeout; }; +/***************************************************** +* DRIVER STATUS FUNCTIONS +******************************************************/ +#define STATUS_HCMD_ACTIVE 0 +#define STATUS_DEVICE_ENABLED 1 +#define STATUS_TPOWER_PMI 2 +#define STATUS_INT_ENABLED 3 + #define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \ ((struct iwl_trans_pcie *) ((_iwl_trans)->trans_specific)) +static inline struct iwl_trans * +iwl_trans_pcie_get_trans(struct iwl_trans_pcie *trans_pcie) +{ + return container_of((void *)trans_pcie, struct iwl_trans, + trans_specific); +} + +struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, + const struct pci_device_id *ent, + const struct iwl_cfg *cfg); +void iwl_trans_pcie_free(struct iwl_trans *trans); + /***************************************************** * RX ******************************************************/ @@ -331,15 +339,12 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans, struct iwl_tx_queue *txq, u16 byte_cnt); -int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, - int sta_id, int tid); +void iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, int queue); void iwl_trans_set_wr_ptrs(struct iwl_trans *trans, int txq_id, u32 index); void iwl_trans_tx_queue_set_status(struct iwl_trans *trans, - struct iwl_tx_queue *txq, - int tx_fifo_id, int scd_retry); -int iwl_trans_pcie_tx_agg_alloc(struct iwl_trans *trans, int sta_id, int tid); -void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, - enum iwl_rxon_context_id ctx, + struct iwl_tx_queue *txq, + int tx_fifo_id, bool active); +void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, int queue, int fifo, int sta_id, int tid, int frame_limit, u16 ssn); void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq, int index, enum dma_data_direction dma_dir); @@ -350,8 +355,6 @@ int iwl_queue_space(const struct iwl_queue *q); /***************************************************** * Error handling ******************************************************/ -int iwl_dump_nic_event_log(struct iwl_trans *trans, bool full_log, - char **buf, bool display); int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display); void iwl_dump_csr(struct iwl_trans *trans); @@ -388,91 +391,28 @@ static inline void iwl_enable_rfkill_int(struct iwl_trans *trans) iwl_write32(trans, CSR_INT_MASK, CSR_INT_BIT_RF_KILL); } -/* - * we have 8 bits used like this: - * - * 7 6 5 4 3 2 1 0 - * | | | | | | | | - * | | | | | | +-+-------- AC queue (0-3) - * | | | | | | - * | +-+-+-+-+------------ HW queue ID - * | - * +---------------------- unused - */ -static inline void iwl_set_swq_id(struct iwl_tx_queue *txq, u8 ac, u8 hwq) -{ - BUG_ON(ac > 3); /* only have 2 bits */ - BUG_ON(hwq > 31); /* only use 5 bits */ - - txq->swq_id = (hwq << 2) | ac; -} - -static inline u8 iwl_get_queue_ac(struct iwl_tx_queue *txq) -{ - return txq->swq_id & 0x3; -} - static inline void iwl_wake_queue(struct iwl_trans *trans, struct iwl_tx_queue *txq) { - u8 queue = txq->swq_id; - u8 ac = queue & 3; - u8 hwq = (queue >> 2) & 0x1f; - struct iwl_trans_pcie *trans_pcie = - IWL_TRANS_GET_PCIE_TRANS(trans); - - if (test_and_clear_bit(hwq, trans_pcie->queue_stopped)) { - if (atomic_dec_return(&trans_pcie->queue_stop_count[ac]) <= 0) { - iwl_op_mode_queue_not_full(trans->op_mode, ac); - IWL_DEBUG_TX_QUEUES(trans, "Wake hwq %d ac %d", - hwq, ac); - } else { - IWL_DEBUG_TX_QUEUES(trans, - "Don't wake hwq %d ac %d stop count %d", - hwq, ac, - atomic_read(&trans_pcie->queue_stop_count[ac])); - } + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + if (test_and_clear_bit(txq->q.id, trans_pcie->queue_stopped)) { + IWL_DEBUG_TX_QUEUES(trans, "Wake hwq %d\n", txq->q.id); + iwl_op_mode_queue_not_full(trans->op_mode, txq->q.id); } } static inline void iwl_stop_queue(struct iwl_trans *trans, struct iwl_tx_queue *txq) { - u8 queue = txq->swq_id; - u8 ac = queue & 3; - u8 hwq = (queue >> 2) & 0x1f; - struct iwl_trans_pcie *trans_pcie = - IWL_TRANS_GET_PCIE_TRANS(trans); - - if (!test_and_set_bit(hwq, trans_pcie->queue_stopped)) { - if (atomic_inc_return(&trans_pcie->queue_stop_count[ac]) > 0) { - iwl_op_mode_queue_full(trans->op_mode, ac); - IWL_DEBUG_TX_QUEUES(trans, - "Stop hwq %d ac %d stop count %d", - hwq, ac, - atomic_read(&trans_pcie->queue_stop_count[ac])); - } else { - IWL_DEBUG_TX_QUEUES(trans, - "Don't stop hwq %d ac %d stop count %d", - hwq, ac, - atomic_read(&trans_pcie->queue_stop_count[ac])); - } - } else { - IWL_DEBUG_TX_QUEUES(trans, "stop hwq %d, but it is stopped", - hwq); - } -} - -static inline void iwl_txq_ctx_activate(struct iwl_trans_pcie *trans_pcie, - int txq_id) -{ - set_bit(txq_id, &trans_pcie->txq_ctx_active_msk); -} + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); -static inline void iwl_txq_ctx_deactivate(struct iwl_trans_pcie *trans_pcie, - int txq_id) -{ - clear_bit(txq_id, &trans_pcie->txq_ctx_active_msk); + if (!test_and_set_bit(txq->q.id, trans_pcie->queue_stopped)) { + iwl_op_mode_queue_full(trans->op_mode, txq->q.id); + IWL_DEBUG_TX_QUEUES(trans, "Stop hwq %d\n", txq->q.id); + } else + IWL_DEBUG_TX_QUEUES(trans, "hwq %d already stopped\n", + txq->q.id); } static inline int iwl_queue_used(const struct iwl_queue *q, int i) @@ -487,19 +427,18 @@ static inline u8 get_cmd_index(struct iwl_queue *q, u32 index) return index & (q->n_window - 1); } -#define IWL_TX_FIFO_BK 0 /* shared */ -#define IWL_TX_FIFO_BE 1 -#define IWL_TX_FIFO_VI 2 /* shared */ -#define IWL_TX_FIFO_VO 3 -#define IWL_TX_FIFO_BK_IPAN IWL_TX_FIFO_BK -#define IWL_TX_FIFO_BE_IPAN 4 -#define IWL_TX_FIFO_VI_IPAN IWL_TX_FIFO_VI -#define IWL_TX_FIFO_VO_IPAN 5 -/* re-uses the VO FIFO, uCode will properly flush/schedule */ -#define IWL_TX_FIFO_AUX 5 -#define IWL_TX_FIFO_UNUSED -1 - -/* AUX (TX during scan dwell) queue */ -#define IWL_AUX_QUEUE 10 +static inline const char * +trans_pcie_get_cmd_string(struct iwl_trans_pcie *trans_pcie, u8 cmd) +{ + if (!trans_pcie->command_names || !trans_pcie->command_names[cmd]) + return "UNKNOWN"; + return trans_pcie->command_names[cmd]; +} + +static inline bool iwl_is_rfkill_set(struct iwl_trans *trans) +{ + return !(iwl_read32(trans, CSR_GP_CNTRL) & + CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW); +} #endif /* __iwl_trans_int_pcie_h__ */ diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c b/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c index aa7aea168138..08517d3c80bb 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c @@ -140,14 +140,17 @@ void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans, if (q->need_update == 0) goto exit_unlock; - if (cfg(trans)->base_params->shadow_reg_enable) { + if (trans->cfg->base_params->shadow_reg_enable) { /* shadow register enabled */ /* Device expects a multiple of 8 */ q->write_actual = (q->write & ~0x7); iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, q->write_actual); } else { + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + /* If power-saving is in use, make sure device is awake */ - if (test_bit(STATUS_POWER_PMI, &trans->shrd->status)) { + if (test_bit(STATUS_TPOWER_PMI, &trans_pcie->status)) { reg = iwl_read32(trans, CSR_UCODE_DRV_GP1); if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { @@ -271,17 +274,17 @@ static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority) if (rxq->free_count > RX_LOW_WATERMARK) gfp_mask |= __GFP_NOWARN; - if (hw_params(trans).rx_page_order > 0) + if (trans_pcie->rx_page_order > 0) gfp_mask |= __GFP_COMP; /* Alloc a new receive buffer */ page = alloc_pages(gfp_mask, - hw_params(trans).rx_page_order); + trans_pcie->rx_page_order); if (!page) { if (net_ratelimit()) IWL_DEBUG_INFO(trans, "alloc_pages failed, " "order: %d\n", - hw_params(trans).rx_page_order); + trans_pcie->rx_page_order); if ((rxq->free_count <= RX_LOW_WATERMARK) && net_ratelimit()) @@ -300,7 +303,7 @@ static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority) if (list_empty(&rxq->rx_used)) { spin_unlock_irqrestore(&rxq->lock, flags); - __free_pages(page, hw_params(trans).rx_page_order); + __free_pages(page, trans_pcie->rx_page_order); return; } element = rxq->rx_used.next; @@ -313,7 +316,7 @@ static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority) rxb->page = page; /* Get physical address of the RB */ rxb->page_dma = dma_map_page(trans->dev, page, 0, - PAGE_SIZE << hw_params(trans).rx_page_order, + PAGE_SIZE << trans_pcie->rx_page_order, DMA_FROM_DEVICE); /* dma address must be no more than 36 bits */ BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36)); @@ -362,84 +365,98 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans, struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rx_queue *rxq = &trans_pcie->rxq; struct iwl_tx_queue *txq = &trans_pcie->txq[trans_pcie->cmd_queue]; - struct iwl_device_cmd *cmd; unsigned long flags; - int len, err; - u16 sequence; - struct iwl_rx_cmd_buffer rxcb; - struct iwl_rx_packet *pkt; - bool reclaim; - int index, cmd_index; + bool page_stolen = false; + int max_len = PAGE_SIZE << trans_pcie->rx_page_order; + u32 offset = 0; if (WARN_ON(!rxb)) return; - rxcb.truesize = PAGE_SIZE << hw_params(trans).rx_page_order; - dma_unmap_page(trans->dev, rxb->page_dma, - rxcb.truesize, - DMA_FROM_DEVICE); - - rxcb._page = rxb->page; - pkt = rxb_addr(&rxcb); + dma_unmap_page(trans->dev, rxb->page_dma, max_len, DMA_FROM_DEVICE); - IWL_DEBUG_RX(trans, "%s, 0x%02x\n", - get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); + while (offset + sizeof(u32) + sizeof(struct iwl_cmd_header) < max_len) { + struct iwl_rx_packet *pkt; + struct iwl_device_cmd *cmd; + u16 sequence; + bool reclaim; + int index, cmd_index, err, len; + struct iwl_rx_cmd_buffer rxcb = { + ._offset = offset, + ._page = rxb->page, + ._page_stolen = false, + .truesize = max_len, + }; + pkt = rxb_addr(&rxcb); - len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; - len += sizeof(u32); /* account for status word */ - trace_iwlwifi_dev_rx(trans->dev, pkt, len); - - /* Reclaim a command buffer only if this packet is a response - * to a (driver-originated) command. - * If the packet (e.g. Rx frame) originated from uCode, - * there is no command buffer to reclaim. - * Ucode should set SEQ_RX_FRAME bit if ucode-originated, - * but apparently a few don't get set; catch them here. */ - reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME); - if (reclaim) { - int i; + if (pkt->len_n_flags == cpu_to_le32(FH_RSCSR_FRAME_INVALID)) + break; - for (i = 0; i < trans_pcie->n_no_reclaim_cmds; i++) { - if (trans_pcie->no_reclaim_cmds[i] == pkt->hdr.cmd) { - reclaim = false; - break; + IWL_DEBUG_RX(trans, "cmd at offset %d: %s (0x%.2x)\n", + rxcb._offset, + trans_pcie_get_cmd_string(trans_pcie, pkt->hdr.cmd), + pkt->hdr.cmd); + + len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; + len += sizeof(u32); /* account for status word */ + trace_iwlwifi_dev_rx(trans->dev, pkt, len); + + /* Reclaim a command buffer only if this packet is a response + * to a (driver-originated) command. + * If the packet (e.g. Rx frame) originated from uCode, + * there is no command buffer to reclaim. + * Ucode should set SEQ_RX_FRAME bit if ucode-originated, + * but apparently a few don't get set; catch them here. */ + reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME); + if (reclaim) { + int i; + + for (i = 0; i < trans_pcie->n_no_reclaim_cmds; i++) { + if (trans_pcie->no_reclaim_cmds[i] == + pkt->hdr.cmd) { + reclaim = false; + break; + } } } - } - sequence = le16_to_cpu(pkt->hdr.sequence); - index = SEQ_TO_INDEX(sequence); - cmd_index = get_cmd_index(&txq->q, index); + sequence = le16_to_cpu(pkt->hdr.sequence); + index = SEQ_TO_INDEX(sequence); + cmd_index = get_cmd_index(&txq->q, index); - if (reclaim) - cmd = txq->cmd[cmd_index]; - else - cmd = NULL; + if (reclaim) + cmd = txq->entries[cmd_index].cmd; + else + cmd = NULL; - err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd); + err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd); - /* - * XXX: After here, we should always check rxcb._page - * against NULL before touching it or its virtual - * memory (pkt). Because some rx_handler might have - * already taken or freed the pages. - */ + /* + * After here, we should always check rxcb._page_stolen, + * if it is true then one of the handlers took the page. + */ - if (reclaim) { - /* Invoke any callbacks, transfer the buffer to caller, - * and fire off the (possibly) blocking - * iwl_trans_send_cmd() - * as we reclaim the driver command queue */ - if (rxcb._page) - iwl_tx_cmd_complete(trans, &rxcb, err); - else - IWL_WARN(trans, "Claim null rxb?\n"); + if (reclaim) { + /* Invoke any callbacks, transfer the buffer to caller, + * and fire off the (possibly) blocking + * iwl_trans_send_cmd() + * as we reclaim the driver command queue */ + if (!rxcb._page_stolen) + iwl_tx_cmd_complete(trans, &rxcb, err); + else + IWL_WARN(trans, "Claim null rxb?\n"); + } + + page_stolen |= rxcb._page_stolen; + offset += ALIGN(len, FH_RSCSR_FRAME_ALIGN); } - /* page was stolen from us */ - if (rxcb._page == NULL) + /* page was stolen from us -- free our reference */ + if (page_stolen) { + __free_pages(rxb->page, trans_pcie->rx_page_order); rxb->page = NULL; + } /* Reuse the page if possible. For notification packets and * SKBs that fail to Rx correctly, add them back into the @@ -448,7 +465,7 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans, if (rxb->page != NULL) { rxb->page_dma = dma_map_page(trans->dev, rxb->page, 0, - PAGE_SIZE << hw_params(trans).rx_page_order, + PAGE_SIZE << trans_pcie->rx_page_order, DMA_FROM_DEVICE); list_add_tail(&rxb->list, &rxq->rx_free); rxq->free_count++; @@ -521,412 +538,32 @@ static void iwl_rx_handle(struct iwl_trans *trans) iwlagn_rx_queue_restock(trans); } -static const char * const desc_lookup_text[] = { - "OK", - "FAIL", - "BAD_PARAM", - "BAD_CHECKSUM", - "NMI_INTERRUPT_WDG", - "SYSASSERT", - "FATAL_ERROR", - "BAD_COMMAND", - "HW_ERROR_TUNE_LOCK", - "HW_ERROR_TEMPERATURE", - "ILLEGAL_CHAN_FREQ", - "VCC_NOT_STABLE", - "FH_ERROR", - "NMI_INTERRUPT_HOST", - "NMI_INTERRUPT_ACTION_PT", - "NMI_INTERRUPT_UNKNOWN", - "UCODE_VERSION_MISMATCH", - "HW_ERROR_ABS_LOCK", - "HW_ERROR_CAL_LOCK_FAIL", - "NMI_INTERRUPT_INST_ACTION_PT", - "NMI_INTERRUPT_DATA_ACTION_PT", - "NMI_TRM_HW_ER", - "NMI_INTERRUPT_TRM", - "NMI_INTERRUPT_BREAK_POINT", - "DEBUG_0", - "DEBUG_1", - "DEBUG_2", - "DEBUG_3", -}; - -static struct { char *name; u8 num; } advanced_lookup[] = { - { "NMI_INTERRUPT_WDG", 0x34 }, - { "SYSASSERT", 0x35 }, - { "UCODE_VERSION_MISMATCH", 0x37 }, - { "BAD_COMMAND", 0x38 }, - { "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C }, - { "FATAL_ERROR", 0x3D }, - { "NMI_TRM_HW_ERR", 0x46 }, - { "NMI_INTERRUPT_TRM", 0x4C }, - { "NMI_INTERRUPT_BREAK_POINT", 0x54 }, - { "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C }, - { "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 }, - { "NMI_INTERRUPT_HOST", 0x66 }, - { "NMI_INTERRUPT_ACTION_PT", 0x7C }, - { "NMI_INTERRUPT_UNKNOWN", 0x84 }, - { "NMI_INTERRUPT_INST_ACTION_PT", 0x86 }, - { "ADVANCED_SYSASSERT", 0 }, -}; - -static const char *desc_lookup(u32 num) -{ - int i; - int max = ARRAY_SIZE(desc_lookup_text); - - if (num < max) - return desc_lookup_text[num]; - - max = ARRAY_SIZE(advanced_lookup) - 1; - for (i = 0; i < max; i++) { - if (advanced_lookup[i].num == num) - break; - } - return advanced_lookup[i].name; -} - -#define ERROR_START_OFFSET (1 * sizeof(u32)) -#define ERROR_ELEM_SIZE (7 * sizeof(u32)) - -static void iwl_dump_nic_error_log(struct iwl_trans *trans) -{ - u32 base; - struct iwl_error_event_table table; - struct iwl_trans_pcie *trans_pcie = - IWL_TRANS_GET_PCIE_TRANS(trans); - - base = trans->shrd->device_pointers.error_event_table; - if (trans->shrd->ucode_type == IWL_UCODE_INIT) { - if (!base) - base = trans->shrd->fw->init_errlog_ptr; - } else { - if (!base) - base = trans->shrd->fw->inst_errlog_ptr; - } - - if (!iwlagn_hw_valid_rtc_data_addr(base)) { - IWL_ERR(trans, - "Not valid error log pointer 0x%08X for %s uCode\n", - base, - (trans->shrd->ucode_type == IWL_UCODE_INIT) - ? "Init" : "RT"); - return; - } - - iwl_read_targ_mem_words(trans, base, &table, sizeof(table)); - - if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { - IWL_ERR(trans, "Start IWL Error Log Dump:\n"); - IWL_ERR(trans, "Status: 0x%08lX, count: %d\n", - trans->shrd->status, table.valid); - } - - trans_pcie->isr_stats.err_code = table.error_id; - - trace_iwlwifi_dev_ucode_error(trans->dev, table.error_id, table.tsf_low, - table.data1, table.data2, table.line, - table.blink1, table.blink2, table.ilink1, - table.ilink2, table.bcon_time, table.gp1, - table.gp2, table.gp3, table.ucode_ver, - table.hw_ver, table.brd_ver); - IWL_ERR(trans, "0x%08X | %-28s\n", table.error_id, - desc_lookup(table.error_id)); - IWL_ERR(trans, "0x%08X | uPc\n", table.pc); - IWL_ERR(trans, "0x%08X | branchlink1\n", table.blink1); - IWL_ERR(trans, "0x%08X | branchlink2\n", table.blink2); - IWL_ERR(trans, "0x%08X | interruptlink1\n", table.ilink1); - IWL_ERR(trans, "0x%08X | interruptlink2\n", table.ilink2); - IWL_ERR(trans, "0x%08X | data1\n", table.data1); - IWL_ERR(trans, "0x%08X | data2\n", table.data2); - IWL_ERR(trans, "0x%08X | line\n", table.line); - IWL_ERR(trans, "0x%08X | beacon time\n", table.bcon_time); - IWL_ERR(trans, "0x%08X | tsf low\n", table.tsf_low); - IWL_ERR(trans, "0x%08X | tsf hi\n", table.tsf_hi); - IWL_ERR(trans, "0x%08X | time gp1\n", table.gp1); - IWL_ERR(trans, "0x%08X | time gp2\n", table.gp2); - IWL_ERR(trans, "0x%08X | time gp3\n", table.gp3); - IWL_ERR(trans, "0x%08X | uCode version\n", table.ucode_ver); - IWL_ERR(trans, "0x%08X | hw version\n", table.hw_ver); - IWL_ERR(trans, "0x%08X | board version\n", table.brd_ver); - IWL_ERR(trans, "0x%08X | hcmd\n", table.hcmd); - - IWL_ERR(trans, "0x%08X | isr0\n", table.isr0); - IWL_ERR(trans, "0x%08X | isr1\n", table.isr1); - IWL_ERR(trans, "0x%08X | isr2\n", table.isr2); - IWL_ERR(trans, "0x%08X | isr3\n", table.isr3); - IWL_ERR(trans, "0x%08X | isr4\n", table.isr4); - IWL_ERR(trans, "0x%08X | isr_pref\n", table.isr_pref); - IWL_ERR(trans, "0x%08X | wait_event\n", table.wait_event); - IWL_ERR(trans, "0x%08X | l2p_control\n", table.l2p_control); - IWL_ERR(trans, "0x%08X | l2p_duration\n", table.l2p_duration); - IWL_ERR(trans, "0x%08X | l2p_mhvalid\n", table.l2p_mhvalid); - IWL_ERR(trans, "0x%08X | l2p_addr_match\n", table.l2p_addr_match); - IWL_ERR(trans, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel); - IWL_ERR(trans, "0x%08X | timestamp\n", table.u_timestamp); - IWL_ERR(trans, "0x%08X | flow_handler\n", table.flow_handler); -} - /** * iwl_irq_handle_error - called for HW or SW error interrupt from card */ static void iwl_irq_handle_error(struct iwl_trans *trans) { /* W/A for WiFi/WiMAX coex and WiMAX own the RF */ - if (cfg(trans)->internal_wimax_coex && + if (trans->cfg->internal_wimax_coex && (!(iwl_read_prph(trans, APMG_CLK_CTRL_REG) & APMS_CLK_VAL_MRB_FUNC_MODE) || (iwl_read_prph(trans, APMG_PS_CTRL_REG) & APMG_PS_CTRL_VAL_RESET_REQ))) { - /* - * Keep the restart process from trying to send host - * commands by clearing the ready bit. - */ - clear_bit(STATUS_READY, &trans->shrd->status); - clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status); + struct iwl_trans_pcie *trans_pcie; + + trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); + iwl_op_mode_wimax_active(trans->op_mode); wake_up(&trans->wait_command_queue); - IWL_ERR(trans, "RF is used by WiMAX\n"); return; } - IWL_ERR(trans, "Loaded firmware version: %s\n", - trans->shrd->fw->fw_version); - - iwl_dump_nic_error_log(trans); iwl_dump_csr(trans); iwl_dump_fh(trans, NULL, false); - iwl_dump_nic_event_log(trans, false, NULL, false); iwl_op_mode_nic_error(trans->op_mode); } -#define EVENT_START_OFFSET (4 * sizeof(u32)) - -/** - * iwl_print_event_log - Dump error event log to syslog - * - */ -static int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx, - u32 num_events, u32 mode, - int pos, char **buf, size_t bufsz) -{ - u32 i; - u32 base; /* SRAM byte address of event log header */ - u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ - u32 ptr; /* SRAM byte address of log data */ - u32 ev, time, data; /* event log data */ - unsigned long reg_flags; - - if (num_events == 0) - return pos; - - base = trans->shrd->device_pointers.log_event_table; - if (trans->shrd->ucode_type == IWL_UCODE_INIT) { - if (!base) - base = trans->shrd->fw->init_evtlog_ptr; - } else { - if (!base) - base = trans->shrd->fw->inst_evtlog_ptr; - } - - if (mode == 0) - event_size = 2 * sizeof(u32); - else - event_size = 3 * sizeof(u32); - - ptr = base + EVENT_START_OFFSET + (start_idx * event_size); - - /* Make sure device is powered up for SRAM reads */ - spin_lock_irqsave(&trans->reg_lock, reg_flags); - if (unlikely(!iwl_grab_nic_access(trans))) - goto out_unlock; - - /* Set starting address; reads will auto-increment */ - iwl_write32(trans, HBUS_TARG_MEM_RADDR, ptr); - - /* "time" is actually "data" for mode 0 (no timestamp). - * place event id # at far right for easier visual parsing. */ - for (i = 0; i < num_events; i++) { - ev = iwl_read32(trans, HBUS_TARG_MEM_RDAT); - time = iwl_read32(trans, HBUS_TARG_MEM_RDAT); - if (mode == 0) { - /* data, ev */ - if (bufsz) { - pos += scnprintf(*buf + pos, bufsz - pos, - "EVT_LOG:0x%08x:%04u\n", - time, ev); - } else { - trace_iwlwifi_dev_ucode_event(trans->dev, 0, - time, ev); - IWL_ERR(trans, "EVT_LOG:0x%08x:%04u\n", - time, ev); - } - } else { - data = iwl_read32(trans, HBUS_TARG_MEM_RDAT); - if (bufsz) { - pos += scnprintf(*buf + pos, bufsz - pos, - "EVT_LOGT:%010u:0x%08x:%04u\n", - time, data, ev); - } else { - IWL_ERR(trans, "EVT_LOGT:%010u:0x%08x:%04u\n", - time, data, ev); - trace_iwlwifi_dev_ucode_event(trans->dev, time, - data, ev); - } - } - } - - /* Allow device to power down */ - iwl_release_nic_access(trans); -out_unlock: - spin_unlock_irqrestore(&trans->reg_lock, reg_flags); - return pos; -} - -/** - * iwl_print_last_event_logs - Dump the newest # of event log to syslog - */ -static int iwl_print_last_event_logs(struct iwl_trans *trans, u32 capacity, - u32 num_wraps, u32 next_entry, - u32 size, u32 mode, - int pos, char **buf, size_t bufsz) -{ - /* - * display the newest DEFAULT_LOG_ENTRIES entries - * i.e the entries just before the next ont that uCode would fill. - */ - if (num_wraps) { - if (next_entry < size) { - pos = iwl_print_event_log(trans, - capacity - (size - next_entry), - size - next_entry, mode, - pos, buf, bufsz); - pos = iwl_print_event_log(trans, 0, - next_entry, mode, - pos, buf, bufsz); - } else - pos = iwl_print_event_log(trans, next_entry - size, - size, mode, pos, buf, bufsz); - } else { - if (next_entry < size) { - pos = iwl_print_event_log(trans, 0, next_entry, - mode, pos, buf, bufsz); - } else { - pos = iwl_print_event_log(trans, next_entry - size, - size, mode, pos, buf, bufsz); - } - } - return pos; -} - -#define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20) - -int iwl_dump_nic_event_log(struct iwl_trans *trans, bool full_log, - char **buf, bool display) -{ - u32 base; /* SRAM byte address of event log header */ - u32 capacity; /* event log capacity in # entries */ - u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ - u32 num_wraps; /* # times uCode wrapped to top of log */ - u32 next_entry; /* index of next entry to be written by uCode */ - u32 size; /* # entries that we'll print */ - u32 logsize; - int pos = 0; - size_t bufsz = 0; - - base = trans->shrd->device_pointers.log_event_table; - if (trans->shrd->ucode_type == IWL_UCODE_INIT) { - logsize = trans->shrd->fw->init_evtlog_size; - if (!base) - base = trans->shrd->fw->init_evtlog_ptr; - } else { - logsize = trans->shrd->fw->inst_evtlog_size; - if (!base) - base = trans->shrd->fw->inst_evtlog_ptr; - } - - if (!iwlagn_hw_valid_rtc_data_addr(base)) { - IWL_ERR(trans, - "Invalid event log pointer 0x%08X for %s uCode\n", - base, - (trans->shrd->ucode_type == IWL_UCODE_INIT) - ? "Init" : "RT"); - return -EINVAL; - } - - /* event log header */ - capacity = iwl_read_targ_mem(trans, base); - mode = iwl_read_targ_mem(trans, base + (1 * sizeof(u32))); - num_wraps = iwl_read_targ_mem(trans, base + (2 * sizeof(u32))); - next_entry = iwl_read_targ_mem(trans, base + (3 * sizeof(u32))); - - if (capacity > logsize) { - IWL_ERR(trans, "Log capacity %d is bogus, limit to %d " - "entries\n", capacity, logsize); - capacity = logsize; - } - - if (next_entry > logsize) { - IWL_ERR(trans, "Log write index %d is bogus, limit to %d\n", - next_entry, logsize); - next_entry = logsize; - } - - size = num_wraps ? capacity : next_entry; - - /* bail out if nothing in log */ - if (size == 0) { - IWL_ERR(trans, "Start IWL Event Log Dump: nothing in log\n"); - return pos; - } - -#ifdef CONFIG_IWLWIFI_DEBUG - if (!(iwl_have_debug_level(IWL_DL_FW_ERRORS)) && !full_log) - size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES) - ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size; -#else - size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES) - ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size; -#endif - IWL_ERR(trans, "Start IWL Event Log Dump: display last %u entries\n", - size); - -#ifdef CONFIG_IWLWIFI_DEBUG - if (display) { - if (full_log) - bufsz = capacity * 48; - else - bufsz = size * 48; - *buf = kmalloc(bufsz, GFP_KERNEL); - if (!*buf) - return -ENOMEM; - } - if (iwl_have_debug_level(IWL_DL_FW_ERRORS) || full_log) { - /* - * if uCode has wrapped back to top of log, - * start at the oldest entry, - * i.e the next one that uCode would fill. - */ - if (num_wraps) - pos = iwl_print_event_log(trans, next_entry, - capacity - next_entry, mode, - pos, buf, bufsz); - /* (then/else) start at top of log */ - pos = iwl_print_event_log(trans, 0, - next_entry, mode, pos, buf, bufsz); - } else - pos = iwl_print_last_event_logs(trans, capacity, num_wraps, - next_entry, size, mode, - pos, buf, bufsz); -#else - pos = iwl_print_last_event_logs(trans, capacity, num_wraps, - next_entry, size, mode, - pos, buf, bufsz); -#endif - return pos; -} - /* tasklet for iwlagn interrupt */ void iwl_irq_tasklet(struct iwl_trans *trans) { @@ -964,7 +601,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans) if (iwl_have_debug_level(IWL_DL_ISR)) { /* just for debug */ inta_mask = iwl_read32(trans, CSR_INT_MASK); - IWL_DEBUG_ISR(trans, "inta 0x%08x, enabled 0x%08x\n ", + IWL_DEBUG_ISR(trans, "inta 0x%08x, enabled 0x%08x\n", inta, inta_mask); } #endif @@ -1012,8 +649,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans) if (inta & CSR_INT_BIT_RF_KILL) { bool hw_rfkill; - hw_rfkill = !(iwl_read32(trans, CSR_GP_CNTRL) & - CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW); + hw_rfkill = iwl_is_rfkill_set(trans); IWL_WARN(trans, "RF_KILL bit toggled to %s.\n", hw_rfkill ? "disable radio" : "enable radio"); @@ -1044,7 +680,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans) if (inta & CSR_INT_BIT_WAKEUP) { IWL_DEBUG_ISR(trans, "Wakeup interrupt\n"); iwl_rx_queue_update_write_ptr(trans, &trans_pcie->rxq); - for (i = 0; i < cfg(trans)->base_params->num_of_queues; i++) + for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) iwl_txq_update_write_ptr(trans, &trans_pcie->txq[i]); diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c b/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c index e92972fd6ecf..21a8a672fbb2 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c @@ -37,47 +37,12 @@ #include "iwl-agn-hw.h" #include "iwl-op-mode.h" #include "iwl-trans-pcie-int.h" +/* FIXME: need to abstract out TX command (once we know what it looks like) */ +#include "iwl-commands.h" #define IWL_TX_CRC_SIZE 4 #define IWL_TX_DELIMITER_SIZE 4 -/* - * mac80211 queues, ACs, hardware queues, FIFOs. - * - * Cf. http://wireless.kernel.org/en/developers/Documentation/mac80211/queues - * - * Mac80211 uses the following numbers, which we get as from it - * by way of skb_get_queue_mapping(skb): - * - * VO 0 - * VI 1 - * BE 2 - * BK 3 - * - * - * Regular (not A-MPDU) frames are put into hardware queues corresponding - * to the FIFOs, see comments in iwl-prph.h. Aggregated frames get their - * own queue per aggregation session (RA/TID combination), such queues are - * set up to map into FIFOs too, for which we need an AC->FIFO mapping. In - * order to map frames to the right queue, we also need an AC->hw queue - * mapping. This is implemented here. - * - * Due to the way hw queues are set up (by the hw specific code), the AC->hw - * queue mapping is the identity mapping. - */ - -static const u8 tid_to_ac[] = { - IEEE80211_AC_BE, - IEEE80211_AC_BK, - IEEE80211_AC_BK, - IEEE80211_AC_BE, - IEEE80211_AC_VI, - IEEE80211_AC_VI, - IEEE80211_AC_VO, - IEEE80211_AC_VO -}; - - /** * iwl_trans_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array */ @@ -95,7 +60,7 @@ void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans, u16 len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; __le16 bc_ent; struct iwl_tx_cmd *tx_cmd = - (struct iwl_tx_cmd *) txq->cmd[txq->q.write_ptr]->payload; + (void *) txq->entries[txq->q.write_ptr].cmd->payload; scd_bc_tbl = trans_pcie->scd_bc_tbls.addr; @@ -136,13 +101,15 @@ void iwl_txq_update_write_ptr(struct iwl_trans *trans, struct iwl_tx_queue *txq) if (txq->need_update == 0) return; - if (cfg(trans)->base_params->shadow_reg_enable) { + if (trans->cfg->base_params->shadow_reg_enable) { /* shadow register enabled */ iwl_write32(trans, HBUS_TARG_WRPTR, txq->q.write_ptr | (txq_id << 8)); } else { + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); /* if we're trying to save power */ - if (test_bit(STATUS_POWER_PMI, &trans->shrd->status)) { + if (test_bit(STATUS_TPOWER_PMI, &trans_pcie->status)) { /* wake up nic if it's powered down ... * uCode will wake up, and interrupt us again, so next * time we'll skip this part. */ @@ -256,13 +223,14 @@ void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq, lockdep_assert_held(&txq->lock); - iwlagn_unmap_tfd(trans, &txq->meta[index], &tfd_tmp[index], dma_dir); + iwlagn_unmap_tfd(trans, &txq->entries[index].meta, + &tfd_tmp[index], dma_dir); /* free SKB */ - if (txq->skbs) { + if (txq->entries) { struct sk_buff *skb; - skb = txq->skbs[index]; + skb = txq->entries[index].skb; /* Can be called from irqs-disabled context * If skb is not NULL, it means that the whole queue is being @@ -270,7 +238,7 @@ void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq, */ if (skb) { iwl_op_mode_free_skb(trans->op_mode, skb); - txq->skbs[index] = NULL; + txq->entries[index].skb = NULL; } } } @@ -393,7 +361,7 @@ static void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_trans *trans, u8 sta_id = 0; __le16 bc_ent; struct iwl_tx_cmd *tx_cmd = - (struct iwl_tx_cmd *) txq->cmd[txq->q.read_ptr]->payload; + (void *)txq->entries[txq->q.read_ptr].cmd->payload; WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX); @@ -448,20 +416,17 @@ static void iwlagn_tx_queue_stop_scheduler(struct iwl_trans *trans, u16 txq_id) void iwl_trans_set_wr_ptrs(struct iwl_trans *trans, int txq_id, u32 index) { - IWL_DEBUG_TX_QUEUES(trans, "Q %d WrPtr: %d", txq_id, index & 0xff); + IWL_DEBUG_TX_QUEUES(trans, "Q %d WrPtr: %d\n", txq_id, index & 0xff); iwl_write_direct32(trans, HBUS_TARG_WRPTR, (index & 0xff) | (txq_id << 8)); iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), index); } void iwl_trans_tx_queue_set_status(struct iwl_trans *trans, - struct iwl_tx_queue *txq, - int tx_fifo_id, int scd_retry) + struct iwl_tx_queue *txq, + int tx_fifo_id, bool active) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int txq_id = txq->q.id; - int active = - test_bit(txq_id, &trans_pcie->txq_ctx_active_msk) ? 1 : 0; iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id), (active << SCD_QUEUE_STTS_REG_POS_ACTIVE) | @@ -469,77 +434,22 @@ void iwl_trans_tx_queue_set_status(struct iwl_trans *trans, (1 << SCD_QUEUE_STTS_REG_POS_WSL) | SCD_QUEUE_STTS_REG_MSK); - txq->sched_retry = scd_retry; - if (active) - IWL_DEBUG_TX_QUEUES(trans, "Activate %s Queue %d on FIFO %d\n", - scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id); + IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d on FIFO %d\n", + txq_id, tx_fifo_id); else - IWL_DEBUG_TX_QUEUES(trans, "Deactivate %s Queue %d\n", - scd_retry ? "BA" : "AC/CMD", txq_id); -} - -static inline int get_ac_from_tid(u16 tid) -{ - if (likely(tid < ARRAY_SIZE(tid_to_ac))) - return tid_to_ac[tid]; - - /* no support for TIDs 8-15 yet */ - return -EINVAL; -} - -static inline int get_fifo_from_tid(struct iwl_trans_pcie *trans_pcie, - u8 ctx, u16 tid) -{ - const u8 *ac_to_fifo = trans_pcie->ac_to_fifo[ctx]; - if (likely(tid < ARRAY_SIZE(tid_to_ac))) - return ac_to_fifo[tid_to_ac[tid]]; - - /* no support for TIDs 8-15 yet */ - return -EINVAL; + IWL_DEBUG_TX_QUEUES(trans, "Deactivate queue %d\n", txq_id); } -static inline bool is_agg_txqid_valid(struct iwl_trans *trans, int txq_id) +void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, int txq_id, int fifo, + int sta_id, int tid, int frame_limit, u16 ssn) { - if (txq_id < IWLAGN_FIRST_AMPDU_QUEUE) - return false; - return txq_id < (IWLAGN_FIRST_AMPDU_QUEUE + - hw_params(trans).num_ampdu_queues); -} - -void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, - enum iwl_rxon_context_id ctx, int sta_id, - int tid, int frame_limit, u16 ssn) -{ - int tx_fifo, txq_id; - u16 ra_tid; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); unsigned long flags; + u16 ra_tid = BUILD_RAxTID(sta_id, tid); - struct iwl_trans_pcie *trans_pcie = - IWL_TRANS_GET_PCIE_TRANS(trans); - - if (WARN_ON(sta_id == IWL_INVALID_STATION)) - return; - if (WARN_ON(tid >= IWL_MAX_TID_COUNT)) - return; - - tx_fifo = get_fifo_from_tid(trans_pcie, ctx, tid); - if (WARN_ON(tx_fifo < 0)) { - IWL_ERR(trans, "txq_agg_setup, bad fifo: %d\n", tx_fifo); - return; - } - - txq_id = trans_pcie->agg_txq[sta_id][tid]; - if (WARN_ON_ONCE(!is_agg_txqid_valid(trans, txq_id))) { - IWL_ERR(trans, - "queue number out of range: %d, must be %d to %d\n", - txq_id, IWLAGN_FIRST_AMPDU_QUEUE, - IWLAGN_FIRST_AMPDU_QUEUE + - hw_params(trans).num_ampdu_queues - 1); - return; - } - - ra_tid = BUILD_RAxTID(sta_id, tid); + if (test_and_set_bit(txq_id, trans_pcie->queue_used)) + WARN_ONCE(1, "queue %d already used - expect issues", txq_id); spin_lock_irqsave(&trans_pcie->irq_lock, flags); @@ -550,10 +460,10 @@ void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, iwlagn_tx_queue_set_q2ratid(trans, ra_tid, txq_id); /* Set this queue as a chain-building queue */ - iwl_set_bits_prph(trans, SCD_QUEUECHAIN_SEL, (1<scd_base_addr + - SCD_CONTEXT_QUEUE_OFFSET(txq_id) + - sizeof(u32), - ((frame_limit << - SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & - SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | - ((frame_limit << - SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & - SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); + SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32), + ((frame_limit << SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & + SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | + ((frame_limit << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & + SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); iwl_set_bits_prph(trans, SCD_INTERRUPT_MASK, (1 << txq_id)); /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */ iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[txq_id], - tx_fifo, 1); - - trans_pcie->txq[txq_id].sta_id = sta_id; - trans_pcie->txq[txq_id].tid = tid; + fifo, true); spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); } -/* - * Find first available (lowest unused) Tx Queue, mark it "active". - * Called only when finding queue for aggregation. - * Should never return anything < 7, because they should already - * be in use as EDCA AC (0-3), Command (4), reserved (5, 6) - */ -static int iwlagn_txq_ctx_activate_free(struct iwl_trans *trans) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - int txq_id; - - for (txq_id = 0; txq_id < cfg(trans)->base_params->num_of_queues; - txq_id++) - if (!test_and_set_bit(txq_id, - &trans_pcie->txq_ctx_active_msk)) - return txq_id; - return -1; -} - -int iwl_trans_pcie_tx_agg_alloc(struct iwl_trans *trans, - int sta_id, int tid) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - int txq_id; - - txq_id = iwlagn_txq_ctx_activate_free(trans); - if (txq_id == -1) { - IWL_ERR(trans, "No free aggregation queue available\n"); - return -ENXIO; - } - - trans_pcie->agg_txq[sta_id][tid] = txq_id; - iwl_set_swq_id(&trans_pcie->txq[txq_id], get_ac_from_tid(tid), txq_id); - - return 0; -} - -int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, int sta_id, int tid) +void iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, int txq_id) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - u8 txq_id = trans_pcie->agg_txq[sta_id][tid]; - if (WARN_ON_ONCE(!is_agg_txqid_valid(trans, txq_id))) { - IWL_ERR(trans, - "queue number out of range: %d, must be %d to %d\n", - txq_id, IWLAGN_FIRST_AMPDU_QUEUE, - IWLAGN_FIRST_AMPDU_QUEUE + - hw_params(trans).num_ampdu_queues - 1); - return -EINVAL; + if (!test_and_clear_bit(txq_id, trans_pcie->queue_used)) { + WARN_ONCE(1, "queue %d not used", txq_id); + return; } iwlagn_tx_queue_stop_scheduler(trans, txq_id); - iwl_clear_bits_prph(trans, SCD_AGGR_SEL, (1 << txq_id)); + iwl_clear_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id)); - trans_pcie->agg_txq[sta_id][tid] = 0; trans_pcie->txq[txq_id].q.read_ptr = 0; trans_pcie->txq[txq_id].q.write_ptr = 0; - /* supposes that ssn_idx is valid (!= 0xFFF) */ iwl_trans_set_wr_ptrs(trans, txq_id, 0); - iwl_clear_bits_prph(trans, SCD_INTERRUPT_MASK, (1 << txq_id)); - iwl_txq_ctx_deactivate(trans_pcie, txq_id); - iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[txq_id], 0, 0); - return 0; + iwl_clear_bits_prph(trans, SCD_INTERRUPT_MASK, BIT(txq_id)); + + iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[txq_id], + 0, false); } /*************** HOST COMMAND QUEUE FUNCTIONS *****/ @@ -681,11 +541,6 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) int trace_idx; #endif - if (test_bit(STATUS_FW_ERROR, &trans->shrd->status)) { - IWL_WARN(trans, "fw recovery, no hcmd send\n"); - return -EIO; - } - copy_size = sizeof(out_cmd->hdr); cmd_size = sizeof(out_cmd->hdr); @@ -726,8 +581,8 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) } idx = get_cmd_index(q, q->write_ptr); - out_cmd = txq->cmd[idx]; - out_meta = &txq->meta[idx]; + out_cmd = txq->entries[idx].cmd; + out_meta = &txq->entries[idx].meta; memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */ if (cmd->flags & CMD_WANT_SKB) @@ -753,12 +608,11 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) cmd_dest += cmd->len[i]; } - IWL_DEBUG_HC(trans, "Sending command %s (#%x), seq: 0x%04X, " - "%d bytes at %d[%d]:%d\n", - get_cmd_string(out_cmd->hdr.cmd), - out_cmd->hdr.cmd, - le16_to_cpu(out_cmd->hdr.sequence), cmd_size, - q->write_ptr, idx, trans_pcie->cmd_queue); + IWL_DEBUG_HC(trans, + "Sending command %s (#%x), seq: 0x%04X, %d bytes at %d[%d]:%d\n", + trans_pcie_get_cmd_string(trans_pcie, out_cmd->hdr.cmd), + out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), cmd_size, + q->write_ptr, idx, trans_pcie->cmd_queue); phys_addr = dma_map_single(trans->dev, &out_cmd->hdr, copy_size, DMA_BIDIRECTIONAL); @@ -816,6 +670,10 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) trace_bufs[2], trace_lens[2]); #endif + /* start timer if queue currently empty */ + if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout) + mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); + /* Increment and update queue's write index */ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); iwl_txq_update_write_ptr(trans, txq); @@ -825,6 +683,22 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) return idx; } +static inline void iwl_queue_progress(struct iwl_trans_pcie *trans_pcie, + struct iwl_tx_queue *txq) +{ + if (!trans_pcie->wd_timeout) + return; + + /* + * if empty delete timer, otherwise move timer forward + * since we're making progress on this queue + */ + if (txq->q.read_ptr == txq->q.write_ptr) + del_timer(&txq->stuck_timer); + else + mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); +} + /** * iwl_hcmd_queue_reclaim - Reclaim TX command queue entries already Tx'd * @@ -859,6 +733,8 @@ static void iwl_hcmd_queue_reclaim(struct iwl_trans *trans, int txq_id, } } + + iwl_queue_progress(trans_pcie, txq); } /** @@ -899,10 +775,8 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb, spin_lock(&txq->lock); cmd_index = get_cmd_index(&txq->q, index); - cmd = txq->cmd[cmd_index]; - meta = &txq->meta[cmd_index]; - - txq->time_stamp = jiffies; + cmd = txq->entries[cmd_index].cmd; + meta = &txq->entries[cmd_index].meta; iwlagn_unmap_tfd(trans, meta, &txq->tfds[index], DMA_BIDIRECTIONAL); @@ -913,21 +787,23 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb, meta->source->resp_pkt = pkt; meta->source->_rx_page_addr = (unsigned long)page_address(p); - meta->source->_rx_page_order = hw_params(trans).rx_page_order; + meta->source->_rx_page_order = trans_pcie->rx_page_order; meta->source->handler_status = handler_status; } iwl_hcmd_queue_reclaim(trans, txq_id, index); if (!(meta->flags & CMD_ASYNC)) { - if (!test_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status)) { + if (!test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status)) { IWL_WARN(trans, "HCMD_ACTIVE already clear for command %s\n", - get_cmd_string(cmd->hdr.cmd)); + trans_pcie_get_cmd_string(trans_pcie, + cmd->hdr.cmd)); } - clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status); + clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n", - get_cmd_string(cmd->hdr.cmd)); + trans_pcie_get_cmd_string(trans_pcie, + cmd->hdr.cmd)); wake_up(&trans->wait_command_queue); } @@ -940,6 +816,7 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb, static int iwl_send_cmd_async(struct iwl_trans *trans, struct iwl_host_cmd *cmd) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int ret; /* An asynchronous command can not expect an SKB to be set. */ @@ -951,7 +828,7 @@ static int iwl_send_cmd_async(struct iwl_trans *trans, struct iwl_host_cmd *cmd) if (ret < 0) { IWL_ERR(trans, "Error sending %s: enqueue_hcmd failed: %d\n", - get_cmd_string(cmd->id), ret); + trans_pcie_get_cmd_string(trans_pcie, cmd->id), ret); return ret; } return 0; @@ -964,55 +841,51 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd) int ret; IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n", - get_cmd_string(cmd->id)); - - if (test_bit(STATUS_FW_ERROR, &trans->shrd->status)) { - IWL_ERR(trans, "Command %s failed: FW Error\n", - get_cmd_string(cmd->id)); - return -EIO; - } + trans_pcie_get_cmd_string(trans_pcie, cmd->id)); if (WARN_ON(test_and_set_bit(STATUS_HCMD_ACTIVE, - &trans->shrd->status))) { + &trans_pcie->status))) { IWL_ERR(trans, "Command %s: a command is already active!\n", - get_cmd_string(cmd->id)); + trans_pcie_get_cmd_string(trans_pcie, cmd->id)); return -EIO; } IWL_DEBUG_INFO(trans, "Setting HCMD_ACTIVE for command %s\n", - get_cmd_string(cmd->id)); + trans_pcie_get_cmd_string(trans_pcie, cmd->id)); cmd_idx = iwl_enqueue_hcmd(trans, cmd); if (cmd_idx < 0) { ret = cmd_idx; - clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status); + clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); IWL_ERR(trans, "Error sending %s: enqueue_hcmd failed: %d\n", - get_cmd_string(cmd->id), ret); + trans_pcie_get_cmd_string(trans_pcie, cmd->id), ret); return ret; } ret = wait_event_timeout(trans->wait_command_queue, - !test_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status), + !test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status), HOST_COMPLETE_TIMEOUT); if (!ret) { - if (test_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status)) { + if (test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status)) { struct iwl_tx_queue *txq = &trans_pcie->txq[trans_pcie->cmd_queue]; struct iwl_queue *q = &txq->q; IWL_ERR(trans, "Error sending %s: time out after %dms.\n", - get_cmd_string(cmd->id), + trans_pcie_get_cmd_string(trans_pcie, cmd->id), jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); IWL_ERR(trans, "Current CMD queue read_ptr %d write_ptr %d\n", q->read_ptr, q->write_ptr); - clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status); - IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command" - "%s\n", get_cmd_string(cmd->id)); + clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); + IWL_DEBUG_INFO(trans, + "Clearing HCMD_ACTIVE for command %s\n", + trans_pcie_get_cmd_string(trans_pcie, + cmd->id)); ret = -ETIMEDOUT; goto cancel; } @@ -1020,7 +893,7 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd) if ((cmd->flags & CMD_WANT_SKB) && !cmd->resp_pkt) { IWL_ERR(trans, "Error: Response NULL in '%s'\n", - get_cmd_string(cmd->id)); + trans_pcie_get_cmd_string(trans_pcie, cmd->id)); ret = -EIO; goto cancel; } @@ -1035,8 +908,8 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd) * in later, it will possibly set an invalid * address (cmd->meta.source). */ - trans_pcie->txq[trans_pcie->cmd_queue].meta[cmd_idx].flags &= - ~CMD_WANT_SKB; + trans_pcie->txq[trans_pcie->cmd_queue]. + entries[cmd_idx].meta.flags &= ~CMD_WANT_SKB; } if (cmd->resp_pkt) { @@ -1091,17 +964,20 @@ int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index, q->read_ptr != index; q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { - if (WARN_ON_ONCE(txq->skbs[txq->q.read_ptr] == NULL)) + if (WARN_ON_ONCE(txq->entries[txq->q.read_ptr].skb == NULL)) continue; - __skb_queue_tail(skbs, txq->skbs[txq->q.read_ptr]); + __skb_queue_tail(skbs, txq->entries[txq->q.read_ptr].skb); - txq->skbs[txq->q.read_ptr] = NULL; + txq->entries[txq->q.read_ptr].skb = NULL; iwlagn_txq_inval_byte_cnt_tbl(trans, txq); iwlagn_txq_free_tfd(trans, txq, txq->q.read_ptr, DMA_TO_DEVICE); freed++; } + + iwl_queue_progress(trans_pcie, txq); + return freed; } diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c index 4d7b30d3e648..2e57161854b9 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c @@ -68,18 +68,20 @@ #include #include +#include "iwl-drv.h" #include "iwl-trans.h" #include "iwl-trans-pcie-int.h" #include "iwl-csr.h" #include "iwl-prph.h" -#include "iwl-shared.h" #include "iwl-eeprom.h" #include "iwl-agn-hw.h" +/* FIXME: need to abstract out TX command (once we know what it looks like) */ +#include "iwl-commands.h" #define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo)))) #define SCD_QUEUECHAIN_SEL_ALL(trans, trans_pcie) \ - (((1<base_params->num_of_queues) - 1) &\ + (((1<cfg->base_params->num_of_queues) - 1) &\ (~(1<<(trans_pcie)->cmd_queue))) static int iwl_trans_rx_alloc(struct iwl_trans *trans) @@ -132,10 +134,10 @@ static void iwl_trans_rxq_free_rx_bufs(struct iwl_trans *trans) * to an SKB, so we need to unmap and free potential storage */ if (rxq->pool[i].page != NULL) { dma_unmap_page(trans->dev, rxq->pool[i].page_dma, - PAGE_SIZE << hw_params(trans).rx_page_order, + PAGE_SIZE << trans_pcie->rx_page_order, DMA_FROM_DEVICE); __free_pages(rxq->pool[i].page, - hw_params(trans).rx_page_order); + trans_pcie->rx_page_order); rxq->pool[i].page = NULL; } list_add_tail(&rxq->pool[i].list, &rxq->rx_used); @@ -145,11 +147,12 @@ static void iwl_trans_rxq_free_rx_bufs(struct iwl_trans *trans) static void iwl_trans_rx_hw_init(struct iwl_trans *trans, struct iwl_rx_queue *rxq) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); u32 rb_size; const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */ u32 rb_timeout = RX_RB_TIMEOUT; /* FIXME: RX_RB_TIMEOUT for all devices? */ - if (iwlagn_mod_params.amsdu_size_8K) + if (trans_pcie->rx_buf_size_8k) rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K; else rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K; @@ -180,7 +183,6 @@ static void iwl_trans_rx_hw_init(struct iwl_trans *trans, FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY | FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | - FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK | rb_size| (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)| (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS)); @@ -299,6 +301,33 @@ static inline void iwlagn_free_dma_ptr(struct iwl_trans *trans, memset(ptr, 0, sizeof(*ptr)); } +static void iwl_trans_pcie_queue_stuck_timer(unsigned long data) +{ + struct iwl_tx_queue *txq = (void *)data; + struct iwl_trans_pcie *trans_pcie = txq->trans_pcie; + struct iwl_trans *trans = iwl_trans_pcie_get_trans(trans_pcie); + + spin_lock(&txq->lock); + /* check if triggered erroneously */ + if (txq->q.read_ptr == txq->q.write_ptr) { + spin_unlock(&txq->lock); + return; + } + spin_unlock(&txq->lock); + + + IWL_ERR(trans, "Queue %d stuck for %u ms.\n", txq->q.id, + jiffies_to_msecs(trans_pcie->wd_timeout)); + IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n", + txq->q.read_ptr, txq->q.write_ptr); + IWL_ERR(trans, "Current HW read_ptr %d write_ptr %d\n", + iwl_read_prph(trans, SCD_QUEUE_RDPTR(txq->q.id)) + & (TFD_QUEUE_SIZE_MAX - 1), + iwl_read_prph(trans, SCD_QUEUE_WRPTR(txq->q.id))); + + iwl_op_mode_nic_error(trans->op_mode); +} + static int iwl_trans_txq_alloc(struct iwl_trans *trans, struct iwl_tx_queue *txq, int slots_num, u32 txq_id) @@ -307,40 +336,31 @@ static int iwl_trans_txq_alloc(struct iwl_trans *trans, int i; struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - if (WARN_ON(txq->meta || txq->cmd || txq->skbs || txq->tfds)) + if (WARN_ON(txq->entries || txq->tfds)) return -EINVAL; + setup_timer(&txq->stuck_timer, iwl_trans_pcie_queue_stuck_timer, + (unsigned long)txq); + txq->trans_pcie = trans_pcie; + txq->q.n_window = slots_num; - txq->meta = kcalloc(slots_num, sizeof(txq->meta[0]), GFP_KERNEL); - txq->cmd = kcalloc(slots_num, sizeof(txq->cmd[0]), GFP_KERNEL); + txq->entries = kcalloc(slots_num, + sizeof(struct iwl_pcie_tx_queue_entry), + GFP_KERNEL); - if (!txq->meta || !txq->cmd) + if (!txq->entries) goto error; if (txq_id == trans_pcie->cmd_queue) for (i = 0; i < slots_num; i++) { - txq->cmd[i] = kmalloc(sizeof(struct iwl_device_cmd), - GFP_KERNEL); - if (!txq->cmd[i]) + txq->entries[i].cmd = + kmalloc(sizeof(struct iwl_device_cmd), + GFP_KERNEL); + if (!txq->entries[i].cmd) goto error; } - /* Alloc driver data array and TFD circular buffer */ - /* Driver private data, only for Tx (not command) queues, - * not shared with device. */ - if (txq_id != trans_pcie->cmd_queue) { - txq->skbs = kcalloc(TFD_QUEUE_SIZE_MAX, sizeof(txq->skbs[0]), - GFP_KERNEL); - if (!txq->skbs) { - IWL_ERR(trans, "kmalloc for auxiliary BD " - "structures failed\n"); - goto error; - } - } else { - txq->skbs = NULL; - } - /* Circular buffer of transmit frame descriptors (TFDs), * shared with device */ txq->tfds = dma_alloc_coherent(trans->dev, tfd_sz, @@ -353,37 +373,22 @@ static int iwl_trans_txq_alloc(struct iwl_trans *trans, return 0; error: - kfree(txq->skbs); - txq->skbs = NULL; - /* since txq->cmd has been zeroed, - * all non allocated cmd[i] will be NULL */ - if (txq->cmd && txq_id == trans_pcie->cmd_queue) + if (txq->entries && txq_id == trans_pcie->cmd_queue) for (i = 0; i < slots_num; i++) - kfree(txq->cmd[i]); - kfree(txq->meta); - kfree(txq->cmd); - txq->meta = NULL; - txq->cmd = NULL; + kfree(txq->entries[i].cmd); + kfree(txq->entries); + txq->entries = NULL; return -ENOMEM; } static int iwl_trans_txq_init(struct iwl_trans *trans, struct iwl_tx_queue *txq, - int slots_num, u32 txq_id) + int slots_num, u32 txq_id) { int ret; txq->need_update = 0; - memset(txq->meta, 0, sizeof(txq->meta[0]) * slots_num); - - /* - * For the default queues 0-3, set up the swq_id - * already -- all others need to get one later - * (if they need one at all). - */ - if (txq_id < 4) - iwl_set_swq_id(txq, txq_id, txq_id); /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */ @@ -461,7 +466,7 @@ static void iwl_tx_queue_free(struct iwl_trans *trans, int txq_id) if (txq_id == trans_pcie->cmd_queue) for (i = 0; i < txq->q.n_window; i++) - kfree(txq->cmd[i]); + kfree(txq->entries[i].cmd); /* De-alloc circular buffer of TFDs */ if (txq->q.n_bd) { @@ -470,15 +475,10 @@ static void iwl_tx_queue_free(struct iwl_trans *trans, int txq_id) memset(&txq->q.dma_addr, 0, sizeof(txq->q.dma_addr)); } - /* De-alloc array of per-TFD driver data */ - kfree(txq->skbs); - txq->skbs = NULL; + kfree(txq->entries); + txq->entries = NULL; - /* deallocate arrays */ - kfree(txq->cmd); - kfree(txq->meta); - txq->cmd = NULL; - txq->meta = NULL; + del_timer_sync(&txq->stuck_timer); /* 0-fill queue descriptor structure */ memset(txq, 0, sizeof(*txq)); @@ -497,7 +497,7 @@ static void iwl_trans_pcie_tx_free(struct iwl_trans *trans) /* Tx queues */ if (trans_pcie->txq) { for (txq_id = 0; - txq_id < cfg(trans)->base_params->num_of_queues; txq_id++) + txq_id < trans->cfg->base_params->num_of_queues; txq_id++) iwl_tx_queue_free(trans, txq_id); } @@ -522,7 +522,7 @@ static int iwl_trans_tx_alloc(struct iwl_trans *trans) int txq_id, slots_num; struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - u16 scd_bc_tbls_size = cfg(trans)->base_params->num_of_queues * + u16 scd_bc_tbls_size = trans->cfg->base_params->num_of_queues * sizeof(struct iwlagn_scd_bc_tbl); /*It is not allowed to alloc twice, so warn when this happens. @@ -546,7 +546,7 @@ static int iwl_trans_tx_alloc(struct iwl_trans *trans) goto error; } - trans_pcie->txq = kcalloc(cfg(trans)->base_params->num_of_queues, + trans_pcie->txq = kcalloc(trans->cfg->base_params->num_of_queues, sizeof(struct iwl_tx_queue), GFP_KERNEL); if (!trans_pcie->txq) { IWL_ERR(trans, "Not enough memory for txq\n"); @@ -555,7 +555,7 @@ static int iwl_trans_tx_alloc(struct iwl_trans *trans) } /* Alloc and init all Tx queues, including the command queue (#4/#9) */ - for (txq_id = 0; txq_id < cfg(trans)->base_params->num_of_queues; + for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues; txq_id++) { slots_num = (txq_id == trans_pcie->cmd_queue) ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; @@ -601,7 +601,7 @@ static int iwl_tx_init(struct iwl_trans *trans) spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); /* Alloc and init all Tx queues, including the command queue (#4/#9) */ - for (txq_id = 0; txq_id < cfg(trans)->base_params->num_of_queues; + for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues; txq_id++) { slots_num = (txq_id == trans_pcie->cmd_queue) ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; @@ -724,9 +724,9 @@ static int iwl_apm_init(struct iwl_trans *trans) iwl_apm_config(trans); /* Configure analog phase-lock-loop before activating to D0A */ - if (cfg(trans)->base_params->pll_cfg_val) + if (trans->cfg->base_params->pll_cfg_val) iwl_set_bit(trans, CSR_ANA_PLL_CFG, - cfg(trans)->base_params->pll_cfg_val); + trans->cfg->base_params->pll_cfg_val); /* * Set "initialization complete" bit to move adapter from @@ -836,7 +836,7 @@ static int iwl_nic_init(struct iwl_trans *trans) if (iwl_tx_init(trans)) return -ENOMEM; - if (cfg(trans)->base_params->shadow_reg_enable) { + if (trans->cfg->base_params->shadow_reg_enable) { /* enable shadow regs in HW */ iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL, 0x800FFFFF); @@ -895,59 +895,6 @@ static int iwl_prepare_card_hw(struct iwl_trans *trans) return ret; } -#define IWL_AC_UNSET -1 - -struct queue_to_fifo_ac { - s8 fifo, ac; -}; - -static const struct queue_to_fifo_ac iwlagn_default_queue_to_tx_fifo[] = { - { IWL_TX_FIFO_VO, IEEE80211_AC_VO, }, - { IWL_TX_FIFO_VI, IEEE80211_AC_VI, }, - { IWL_TX_FIFO_BE, IEEE80211_AC_BE, }, - { IWL_TX_FIFO_BK, IEEE80211_AC_BK, }, - { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, }, - { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, - { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, - { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, - { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, - { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, - { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, -}; - -static const struct queue_to_fifo_ac iwlagn_ipan_queue_to_tx_fifo[] = { - { IWL_TX_FIFO_VO, IEEE80211_AC_VO, }, - { IWL_TX_FIFO_VI, IEEE80211_AC_VI, }, - { IWL_TX_FIFO_BE, IEEE80211_AC_BE, }, - { IWL_TX_FIFO_BK, IEEE80211_AC_BK, }, - { IWL_TX_FIFO_BK_IPAN, IEEE80211_AC_BK, }, - { IWL_TX_FIFO_BE_IPAN, IEEE80211_AC_BE, }, - { IWL_TX_FIFO_VI_IPAN, IEEE80211_AC_VI, }, - { IWL_TX_FIFO_VO_IPAN, IEEE80211_AC_VO, }, - { IWL_TX_FIFO_BE_IPAN, 2, }, - { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, }, - { IWL_TX_FIFO_AUX, IWL_AC_UNSET, }, -}; - -static const u8 iwlagn_bss_ac_to_fifo[] = { - IWL_TX_FIFO_VO, - IWL_TX_FIFO_VI, - IWL_TX_FIFO_BE, - IWL_TX_FIFO_BK, -}; -static const u8 iwlagn_bss_ac_to_queue[] = { - 0, 1, 2, 3, -}; -static const u8 iwlagn_pan_ac_to_fifo[] = { - IWL_TX_FIFO_VO_IPAN, - IWL_TX_FIFO_VI_IPAN, - IWL_TX_FIFO_BE_IPAN, - IWL_TX_FIFO_BK_IPAN, -}; -static const u8 iwlagn_pan_ac_to_queue[] = { - 7, 6, 5, 4, -}; - /* * ucode */ @@ -1028,34 +975,21 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, const struct fw_img *fw) { int ret; - struct iwl_trans_pcie *trans_pcie = - IWL_TRANS_GET_PCIE_TRANS(trans); bool hw_rfkill; - trans_pcie->ac_to_queue[IWL_RXON_CTX_BSS] = iwlagn_bss_ac_to_queue; - trans_pcie->ac_to_queue[IWL_RXON_CTX_PAN] = iwlagn_pan_ac_to_queue; - - trans_pcie->ac_to_fifo[IWL_RXON_CTX_BSS] = iwlagn_bss_ac_to_fifo; - trans_pcie->ac_to_fifo[IWL_RXON_CTX_PAN] = iwlagn_pan_ac_to_fifo; - - trans_pcie->mcast_queue[IWL_RXON_CTX_BSS] = 0; - trans_pcie->mcast_queue[IWL_RXON_CTX_PAN] = IWL_IPAN_MCAST_QUEUE; - /* This may fail if AMT took ownership of the device */ if (iwl_prepare_card_hw(trans)) { IWL_WARN(trans, "Exit HW not ready\n"); return -EIO; } + iwl_enable_rfkill_int(trans); + /* If platform's RF_KILL switch is NOT set to KILL */ - hw_rfkill = !(iwl_read32(trans, CSR_GP_CNTRL) & - CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW); + hw_rfkill = iwl_is_rfkill_set(trans); iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); - - if (hw_rfkill) { - iwl_enable_rfkill_int(trans); + if (hw_rfkill) return -ERFKILL; - } iwl_write32(trans, CSR_INT, 0xFFFFFFFF); @@ -1098,9 +1032,7 @@ static void iwl_trans_txq_set_sched(struct iwl_trans *trans, u32 mask) static void iwl_tx_start(struct iwl_trans *trans) { - const struct queue_to_fifo_ac *queue_to_fifo; - struct iwl_trans_pcie *trans_pcie = - IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); u32 a; unsigned long flags; int i, chan; @@ -1121,7 +1053,7 @@ static void iwl_tx_start(struct iwl_trans *trans) iwl_write_targ_mem(trans, a, 0); for (; a < trans_pcie->scd_base_addr + SCD_TRANS_TBL_OFFSET_QUEUE( - cfg(trans)->base_params->num_of_queues); + trans->cfg->base_params->num_of_queues); a += 4) iwl_write_targ_mem(trans, a, 0); @@ -1144,7 +1076,7 @@ static void iwl_tx_start(struct iwl_trans *trans) iwl_write_prph(trans, SCD_AGGR_SEL, 0); /* initiate the queues */ - for (i = 0; i < cfg(trans)->base_params->num_of_queues; i++) { + for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) { iwl_write_prph(trans, SCD_QUEUE_RDPTR(i), 0); iwl_write_direct32(trans, HBUS_TARG_WRPTR, 0 | (i << 8)); iwl_write_targ_mem(trans, trans_pcie->scd_base_addr + @@ -1161,46 +1093,24 @@ static void iwl_tx_start(struct iwl_trans *trans) } iwl_write_prph(trans, SCD_INTERRUPT_MASK, - IWL_MASK(0, cfg(trans)->base_params->num_of_queues)); + IWL_MASK(0, trans->cfg->base_params->num_of_queues)); /* Activate all Tx DMA/FIFO channels */ iwl_trans_txq_set_sched(trans, IWL_MASK(0, 7)); - /* map queues to FIFOs */ - if (trans->shrd->valid_contexts != BIT(IWL_RXON_CTX_BSS)) - queue_to_fifo = iwlagn_ipan_queue_to_tx_fifo; - else - queue_to_fifo = iwlagn_default_queue_to_tx_fifo; - iwl_trans_set_wr_ptrs(trans, trans_pcie->cmd_queue, 0); - /* make sure all queue are not stopped */ - memset(&trans_pcie->queue_stopped[0], 0, - sizeof(trans_pcie->queue_stopped)); - for (i = 0; i < 4; i++) - atomic_set(&trans_pcie->queue_stop_count[i], 0); - - /* reset to 0 to enable all the queue first */ - trans_pcie->txq_ctx_active_msk = 0; + /* make sure all queue are not stopped/used */ + memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped)); + memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used)); - BUILD_BUG_ON(ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo) < - IWLAGN_FIRST_AMPDU_QUEUE); - BUILD_BUG_ON(ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo) < - IWLAGN_FIRST_AMPDU_QUEUE); + for (i = 0; i < trans_pcie->n_q_to_fifo; i++) { + int fifo = trans_pcie->setup_q_to_fifo[i]; - for (i = 0; i < IWLAGN_FIRST_AMPDU_QUEUE; i++) { - int fifo = queue_to_fifo[i].fifo; - int ac = queue_to_fifo[i].ac; + set_bit(i, trans_pcie->queue_used); - iwl_txq_ctx_activate(trans_pcie, i); - - if (fifo == IWL_TX_FIFO_UNUSED) - continue; - - if (ac != IWL_AC_UNSET) - iwl_set_swq_id(&trans_pcie->txq[i], ac, i); iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[i], - fifo, 0); + fifo, true); } spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); @@ -1251,7 +1161,7 @@ static int iwl_trans_tx_stop(struct iwl_trans *trans) } /* Unmap DMA from host system and free skb's */ - for (txq_id = 0; txq_id < cfg(trans)->base_params->num_of_queues; + for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues; txq_id++) iwl_tx_queue_unmap(trans, txq_id); @@ -1303,6 +1213,8 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) iwl_disable_interrupts(trans); spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); + iwl_enable_rfkill_int(trans); + /* wait to make sure we flush pending tasklet*/ synchronize_irq(trans_pcie->irq); tasklet_kill(&trans_pcie->irq_tasklet); @@ -1311,6 +1223,12 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) /* stop and reset the on-board processor */ iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); + + /* clear all status bits */ + clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); + clear_bit(STATUS_INT_ENABLED, &trans_pcie->status); + clear_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status); + clear_bit(STATUS_TPOWER_PMI, &trans_pcie->status); } static void iwl_trans_pcie_wowlan_suspend(struct iwl_trans *trans) @@ -1325,81 +1243,43 @@ static void iwl_trans_pcie_wowlan_suspend(struct iwl_trans *trans) } static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, - struct iwl_device_cmd *dev_cmd, enum iwl_rxon_context_id ctx, - u8 sta_id, u8 tid) + struct iwl_device_cmd *dev_cmd, int txq_id) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_tx_cmd *tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload; struct iwl_cmd_meta *out_meta; struct iwl_tx_queue *txq; struct iwl_queue *q; - dma_addr_t phys_addr = 0; dma_addr_t txcmd_phys; dma_addr_t scratch_phys; u16 len, firstlen, secondlen; u8 wait_write_ptr = 0; - u8 txq_id; - bool is_agg = false; __le16 fc = hdr->frame_control; u8 hdr_len = ieee80211_hdrlen(fc); u16 __maybe_unused wifi_seq; - /* - * Send this frame after DTIM -- there's a special queue - * reserved for this for contexts that support AP mode. - */ - if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { - txq_id = trans_pcie->mcast_queue[ctx]; - - /* - * The microcode will clear the more data - * bit in the last frame it transmits. - */ - hdr->frame_control |= - cpu_to_le16(IEEE80211_FCTL_MOREDATA); - } else if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) - txq_id = IWL_AUX_QUEUE; - else - txq_id = - trans_pcie->ac_to_queue[ctx][skb_get_queue_mapping(skb)]; - - /* aggregation is on for this */ - if (info->flags & IEEE80211_TX_CTL_AMPDU) { - WARN_ON(tid >= IWL_MAX_TID_COUNT); - txq_id = trans_pcie->agg_txq[sta_id][tid]; - is_agg = true; - } - txq = &trans_pcie->txq[txq_id]; q = &txq->q; - spin_lock(&txq->lock); + if (unlikely(!test_bit(txq_id, trans_pcie->queue_used))) { + WARN_ON_ONCE(1); + return -EINVAL; + } - /* In AGG mode, the index in the ring must correspond to the WiFi - * sequence number. This is a HW requirements to help the SCD to parse - * the BA. - * Check here that the packets are in the right place on the ring. - */ -#ifdef CONFIG_IWLWIFI_DEBUG - wifi_seq = SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); - WARN_ONCE(is_agg && ((wifi_seq & 0xff) != q->write_ptr), - "Q: %d WiFi Seq %d tfdNum %d", - txq_id, wifi_seq, q->write_ptr); -#endif + spin_lock(&txq->lock); /* Set up driver data for this TFD */ - txq->skbs[q->write_ptr] = skb; - txq->cmd[q->write_ptr] = dev_cmd; + txq->entries[q->write_ptr].skb = skb; + txq->entries[q->write_ptr].cmd = dev_cmd; dev_cmd->hdr.cmd = REPLY_TX; dev_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | INDEX_TO_SEQ(q->write_ptr))); /* Set up first empty entry in queue's array of Tx/cmd buffers */ - out_meta = &txq->meta[q->write_ptr]; + out_meta = &txq->entries[q->write_ptr].meta; /* * Use the first empty entry in this queue's command buffer array @@ -1481,6 +1361,10 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, &dev_cmd->hdr, firstlen, skb->data + hdr_len, secondlen); + /* start timer if queue currently empty */ + if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout) + 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_txq_update_write_ptr(trans, txq); @@ -1541,8 +1425,10 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) iwl_apm_init(trans); - hw_rfkill = !(iwl_read32(trans, CSR_GP_CNTRL) & - CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW); + /* From now on, the op_mode will be kept updated about RF kill state */ + iwl_enable_rfkill_int(trans); + + hw_rfkill = iwl_is_rfkill_set(trans); iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); return err; @@ -1555,18 +1441,41 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) return err; } -static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans) +static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans, + bool op_mode_leaving) { + bool hw_rfkill; + unsigned long flags; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + iwl_apm_stop(trans); + spin_lock_irqsave(&trans_pcie->irq_lock, flags); + iwl_disable_interrupts(trans); + spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); + iwl_write32(trans, CSR_INT, 0xFFFFFFFF); - /* Even if we stop the HW, we still want the RF kill interrupt */ - iwl_enable_rfkill_int(trans); + if (!op_mode_leaving) { + /* + * Even if we stop the HW, we still want the RF kill + * interrupt + */ + iwl_enable_rfkill_int(trans); + + /* + * Check again since the RF kill state may have changed while + * all the interrupts were disabled, in this case we couldn't + * receive the RF kill interrupt and update the state in the + * op_mode. + */ + hw_rfkill = iwl_is_rfkill_set(trans); + iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); + } } -static int iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid, - int txq_id, int ssn, struct sk_buff_head *skbs) +static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, + struct sk_buff_head *skbs) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id]; @@ -1576,35 +1485,15 @@ static int iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid, spin_lock(&txq->lock); - txq->time_stamp = jiffies; - - if (unlikely(txq_id >= IWLAGN_FIRST_AMPDU_QUEUE && - tid != IWL_TID_NON_QOS && - txq_id != trans_pcie->agg_txq[sta_id][tid])) { - /* - * FIXME: this is a uCode bug which need to be addressed, - * log the information and return for now. - * Since it is can possibly happen very often and in order - * not to fill the syslog, don't use IWL_ERR or IWL_WARN - */ - IWL_DEBUG_TX_QUEUES(trans, "Bad queue mapping txq_id %d, " - "agg_txq[sta_id[tid] %d", txq_id, - trans_pcie->agg_txq[sta_id][tid]); - spin_unlock(&txq->lock); - return 1; - } - if (txq->q.read_ptr != tfd_num) { - IWL_DEBUG_TX_REPLY(trans, "[Q %d | AC %d] %d -> %d (%d)\n", - txq_id, iwl_get_queue_ac(txq), txq->q.read_ptr, - tfd_num, ssn); + IWL_DEBUG_TX_REPLY(trans, "[Q %d] %d -> %d (%d)\n", + txq_id, txq->q.read_ptr, tfd_num, ssn); freed = iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs); if (iwl_queue_space(&txq->q) > txq->q.low_mark) iwl_wake_queue(trans, txq); } spin_unlock(&txq->lock); - return 0; } static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val) @@ -1623,7 +1512,7 @@ static u32 iwl_trans_pcie_read32(struct iwl_trans *trans, u32 ofs) } static void iwl_trans_pcie_configure(struct iwl_trans *trans, - const struct iwl_trans_config *trans_cfg) + const struct iwl_trans_config *trans_cfg) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -1635,9 +1524,31 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, if (trans_pcie->n_no_reclaim_cmds) memcpy(trans_pcie->no_reclaim_cmds, trans_cfg->no_reclaim_cmds, trans_pcie->n_no_reclaim_cmds * sizeof(u8)); + + trans_pcie->n_q_to_fifo = trans_cfg->n_queue_to_fifo; + + if (WARN_ON(trans_pcie->n_q_to_fifo > IWL_MAX_HW_QUEUES)) + trans_pcie->n_q_to_fifo = IWL_MAX_HW_QUEUES; + + /* at least the command queue must be mapped */ + WARN_ON(!trans_pcie->n_q_to_fifo); + + memcpy(trans_pcie->setup_q_to_fifo, trans_cfg->queue_to_fifo, + trans_pcie->n_q_to_fifo * sizeof(u8)); + + trans_pcie->rx_buf_size_8k = trans_cfg->rx_buf_size_8k; + if (trans_pcie->rx_buf_size_8k) + trans_pcie->rx_page_order = get_order(8 * 1024); + else + trans_pcie->rx_page_order = get_order(4 * 1024); + + trans_pcie->wd_timeout = + msecs_to_jiffies(trans_cfg->queue_watchdog_timeout); + + trans_pcie->command_names = trans_cfg->command_names; } -static void iwl_trans_pcie_free(struct iwl_trans *trans) +void iwl_trans_pcie_free(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -1656,10 +1567,19 @@ static void iwl_trans_pcie_free(struct iwl_trans *trans) pci_release_regions(trans_pcie->pci_dev); pci_disable_device(trans_pcie->pci_dev); - trans->shrd->trans = NULL; kfree(trans); } +static void iwl_trans_pcie_set_pmi(struct iwl_trans *trans, bool state) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + if (state) + set_bit(STATUS_TPOWER_PMI, &trans_pcie->status); + else + clear_bit(STATUS_TPOWER_PMI, &trans_pcie->status); +} + #ifdef CONFIG_PM_SLEEP static int iwl_trans_pcie_suspend(struct iwl_trans *trans) { @@ -1670,16 +1590,14 @@ static int iwl_trans_pcie_resume(struct iwl_trans *trans) { bool hw_rfkill; - hw_rfkill = !(iwl_read32(trans, CSR_GP_CNTRL) & - CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW); - - if (hw_rfkill) - iwl_enable_rfkill_int(trans); - else - iwl_enable_interrupts(trans); + iwl_enable_rfkill_int(trans); + hw_rfkill = iwl_is_rfkill_set(trans); iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); + if (!hw_rfkill) + iwl_enable_interrupts(trans); + return 0; } #endif /* CONFIG_PM_SLEEP */ @@ -1696,7 +1614,7 @@ static int iwl_trans_pcie_wait_tx_queue_empty(struct iwl_trans *trans) int ret = 0; /* waiting for all the tx frames complete might take a while */ - for (cnt = 0; cnt < cfg(trans)->base_params->num_of_queues; cnt++) { + for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) { if (cnt == trans_pcie->cmd_queue) continue; txq = &trans_pcie->txq[cnt]; @@ -1714,42 +1632,9 @@ static int iwl_trans_pcie_wait_tx_queue_empty(struct iwl_trans *trans) return ret; } -/* - * On every watchdog tick we check (latest) time stamp. If it does not - * change during timeout period and queue is not empty we reset firmware. - */ -static int iwl_trans_pcie_check_stuck_queue(struct iwl_trans *trans, int cnt) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_tx_queue *txq = &trans_pcie->txq[cnt]; - struct iwl_queue *q = &txq->q; - unsigned long timeout; - - if (q->read_ptr == q->write_ptr) { - txq->time_stamp = jiffies; - return 0; - } - - timeout = txq->time_stamp + - msecs_to_jiffies(hw_params(trans).wd_timeout); - - if (time_after(jiffies, timeout)) { - IWL_ERR(trans, "Queue %d stuck for %u ms.\n", q->id, - hw_params(trans).wd_timeout); - IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n", - q->read_ptr, q->write_ptr); - IWL_ERR(trans, "Current HW read_ptr %d write_ptr %d\n", - iwl_read_prph(trans, SCD_QUEUE_RDPTR(cnt)) - & (TFD_QUEUE_SIZE_MAX - 1), - iwl_read_prph(trans, SCD_QUEUE_WRPTR(cnt))); - return 1; - } - - return 0; -} - static const char *get_fh_string(int cmd) { +#define IWL_CMD(x) case x: return #x switch (cmd) { IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG); IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG); @@ -1763,6 +1648,7 @@ static const char *get_fh_string(int cmd) default: return "UNKNOWN"; } +#undef IWL_CMD } int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display) @@ -1811,6 +1697,7 @@ int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display) static const char *get_csr_string(int cmd) { +#define IWL_CMD(x) case x: return #x switch (cmd) { IWL_CMD(CSR_HW_IF_CONFIG_REG); IWL_CMD(CSR_INT_COALESCING); @@ -1838,6 +1725,7 @@ static const char *get_csr_string(int cmd) default: return "UNKNOWN"; } +#undef IWL_CMD } void iwl_dump_csr(struct iwl_trans *trans) @@ -1938,32 +1826,23 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file, int ret; size_t bufsz; - bufsz = sizeof(char) * 64 * cfg(trans)->base_params->num_of_queues; + bufsz = sizeof(char) * 64 * trans->cfg->base_params->num_of_queues; - if (!trans_pcie->txq) { - IWL_ERR(trans, "txq not ready\n"); + if (!trans_pcie->txq) return -EAGAIN; - } + buf = kzalloc(bufsz, GFP_KERNEL); if (!buf) return -ENOMEM; - for (cnt = 0; cnt < cfg(trans)->base_params->num_of_queues; cnt++) { + for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) { txq = &trans_pcie->txq[cnt]; q = &txq->q; pos += scnprintf(buf + pos, bufsz - pos, - "hwq %.2d: read=%u write=%u stop=%d" - " swq_id=%#.2x (ac %d/hwq %d)\n", + "hwq %.2d: read=%u write=%u use=%d stop=%d\n", cnt, q->read_ptr, q->write_ptr, - !!test_bit(cnt, trans_pcie->queue_stopped), - txq->swq_id, txq->swq_id & 3, - (txq->swq_id >> 2) & 0x1f); - if (cnt >= 4) - continue; - /* for the ACs, display the stop count too */ - pos += scnprintf(buf + pos, bufsz - pos, - " stop-count: %d\n", - atomic_read(&trans_pcie->queue_stop_count[cnt])); + !!test_bit(cnt, trans_pcie->queue_used), + !!test_bit(cnt, trans_pcie->queue_stopped)); } ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); @@ -1997,44 +1876,6 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } -static ssize_t iwl_dbgfs_log_event_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_trans *trans = file->private_data; - char *buf; - int pos = 0; - ssize_t ret = -ENOMEM; - - ret = pos = iwl_dump_nic_event_log(trans, true, &buf, true); - if (buf) { - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - } - return ret; -} - -static ssize_t iwl_dbgfs_log_event_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_trans *trans = file->private_data; - u32 event_log_flag; - char buf[8]; - int buf_size; - - memset(buf, 0, sizeof(buf)); - buf_size = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - if (sscanf(buf, "%d", &event_log_flag) != 1) - return -EFAULT; - if (event_log_flag == 1) - iwl_dump_nic_event_log(trans, true, NULL, false); - - return count; -} - static ssize_t iwl_dbgfs_interrupt_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -2050,10 +1891,8 @@ static ssize_t iwl_dbgfs_interrupt_read(struct file *file, ssize_t ret; buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(trans, "Can not allocate Buffer\n"); + if (!buf) return -ENOMEM; - } pos += scnprintf(buf + pos, bufsz - pos, "Interrupt Statistics Report:\n"); @@ -2161,12 +2000,26 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file, return ret; } -DEBUGFS_READ_WRITE_FILE_OPS(log_event); +static ssize_t iwl_dbgfs_fw_restart_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_trans *trans = file->private_data; + + if (!trans->op_mode) + return -EAGAIN; + + iwl_op_mode_nic_error(trans->op_mode); + + return count; +} + DEBUGFS_READ_WRITE_FILE_OPS(interrupt); DEBUGFS_READ_FILE_OPS(fh_reg); DEBUGFS_READ_FILE_OPS(rx_queue); DEBUGFS_READ_FILE_OPS(tx_queue); DEBUGFS_WRITE_FILE_OPS(csr); +DEBUGFS_WRITE_FILE_OPS(fw_restart); /* * Create the debugfs files and directories @@ -2177,10 +2030,10 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, { DEBUGFS_ADD_FILE(rx_queue, dir, S_IRUSR); DEBUGFS_ADD_FILE(tx_queue, dir, S_IRUSR); - DEBUGFS_ADD_FILE(log_event, dir, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(interrupt, dir, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(csr, dir, S_IWUSR); DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR); + DEBUGFS_ADD_FILE(fw_restart, dir, S_IWUSR); return 0; } #else @@ -2190,7 +2043,7 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, #endif /*CONFIG_IWLWIFI_DEBUGFS */ -const struct iwl_trans_ops trans_ops_pcie = { +static const struct iwl_trans_ops trans_ops_pcie = { .start_hw = iwl_trans_pcie_start_hw, .stop_hw = iwl_trans_pcie_stop_hw, .fw_alive = iwl_trans_pcie_fw_alive, @@ -2205,15 +2058,11 @@ const struct iwl_trans_ops trans_ops_pcie = { .reclaim = iwl_trans_pcie_reclaim, .tx_agg_disable = iwl_trans_pcie_tx_agg_disable, - .tx_agg_alloc = iwl_trans_pcie_tx_agg_alloc, .tx_agg_setup = iwl_trans_pcie_tx_agg_setup, - .free = iwl_trans_pcie_free, - .dbgfs_register = iwl_trans_pcie_dbgfs_register, .wait_tx_queue_empty = iwl_trans_pcie_wait_tx_queue_empty, - .check_stuck_queue = iwl_trans_pcie_check_stuck_queue, #ifdef CONFIG_PM_SLEEP .suspend = iwl_trans_pcie_suspend, @@ -2223,11 +2072,12 @@ const struct iwl_trans_ops trans_ops_pcie = { .write32 = iwl_trans_pcie_write32, .read32 = iwl_trans_pcie_read32, .configure = iwl_trans_pcie_configure, + .set_pmi = iwl_trans_pcie_set_pmi, }; -struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd, - struct pci_dev *pdev, - const struct pci_device_id *ent) +struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, + const struct pci_device_id *ent, + const struct iwl_cfg *cfg) { struct iwl_trans_pcie *trans_pcie; struct iwl_trans *trans; @@ -2243,7 +2093,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd, trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); trans->ops = &trans_ops_pcie; - trans->shrd = shrd; + trans->cfg = cfg; trans_pcie->trans = trans; spin_lock_init(&trans_pcie->irq_lock); init_waitqueue_head(&trans_pcie->ucode_write_waitq); @@ -2325,6 +2175,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd, /* Initialize the wait queue for commands */ init_waitqueue_head(&trans->wait_command_queue); + spin_lock_init(&trans->reg_lock); return trans; diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-trans.h b/trunk/drivers/net/wireless/iwlwifi/iwl-trans.h index fdf97886a5e4..79a1e7ae4995 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -66,8 +66,9 @@ #include #include /* for page_address */ -#include "iwl-shared.h" #include "iwl-debug.h" +#include "iwl-config.h" +#include "iwl-fw.h" /** * DOC: Transport layer - what is it ? @@ -104,13 +105,6 @@ * 6) Eventually, the free function will be called. */ -struct iwl_priv; -struct iwl_shared; -struct iwl_op_mode; -struct fw_img; -struct sk_buff; -struct dentry; - /** * DOC: Host command section * @@ -162,6 +156,8 @@ struct iwl_cmd_header { #define FH_RSCSR_FRAME_SIZE_MSK 0x00003FFF /* bits 0-13 */ +#define FH_RSCSR_FRAME_INVALID 0x55550000 +#define FH_RSCSR_FRAME_ALIGN 0x40 struct iwl_rx_packet { /* @@ -260,28 +256,43 @@ static inline void iwl_free_resp(struct iwl_host_cmd *cmd) struct iwl_rx_cmd_buffer { struct page *_page; + int _offset; + bool _page_stolen; unsigned int truesize; }; static inline void *rxb_addr(struct iwl_rx_cmd_buffer *r) { - return page_address(r->_page); + return (void *)((unsigned long)page_address(r->_page) + r->_offset); +} + +static inline int rxb_offset(struct iwl_rx_cmd_buffer *r) +{ + return r->_offset; } static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r) { - struct page *p = r->_page; - r->_page = NULL; - return p; + r->_page_stolen = true; + get_page(r->_page); + return r->_page; } #define MAX_NO_RECLAIM_CMDS 6 +/* + * Maximum number of HW queues the transport layer + * currently supports + */ +#define IWL_MAX_HW_QUEUES 32 + /** * struct iwl_trans_config - transport configuration * * @op_mode: pointer to the upper layer. - * Must be set before any other call. + * @queue_to_fifo: queue to FIFO mapping to set up by + * default + * @n_queue_to_fifo: number of queues to set up * @cmd_queue: the index of the command queue. * Must be set before start_fw. * @no_reclaim_cmds: Some devices erroneously don't set the @@ -289,14 +300,29 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r) * list of such notifications to filter. Max length is * %MAX_NO_RECLAIM_CMDS. * @n_no_reclaim_cmds: # of commands in list + * @rx_buf_size_8k: 8 kB RX buffer size needed for A-MSDUs, + * if unset 4k will be the RX buffer size + * @queue_watchdog_timeout: time (in ms) after which queues + * are considered stuck and will trigger device restart + * @command_names: array of command names, must be 256 entries + * (one for each command); for debugging only */ struct iwl_trans_config { struct iwl_op_mode *op_mode; + const u8 *queue_to_fifo; + u8 n_queue_to_fifo; + u8 cmd_queue; const u8 *no_reclaim_cmds; int n_no_reclaim_cmds; + + bool rx_buf_size_8k; + unsigned int queue_watchdog_timeout; + const char **command_names; }; +struct iwl_trans; + /** * struct iwl_trans_ops - transport specific operations * @@ -305,7 +331,8 @@ struct iwl_trans_config { * @start_hw: starts the HW- from that point on, the HW can send interrupts * May sleep * @stop_hw: stops the HW- from that point on, the HW will be in low power but - * will still issue interrupt if the HW RF kill is triggered. + * will still issue interrupt if the HW RF kill is triggered unless + * op_mode_leaving is true. * May sleep * @start_fw: allocates and inits all the resources for the transport * layer. Also kick a fw image. @@ -323,18 +350,11 @@ struct iwl_trans_config { * Must be atomic * @reclaim: free packet until ssn. Returns a list of freed packets. * Must be atomic - * @tx_agg_alloc: allocate resources for a TX BA session - * Must be atomic * @tx_agg_setup: setup a tx queue for AMPDU - will be called once the HW is * ready and a successful ADDBA response has been received. * May sleep * @tx_agg_disable: de-configure a Tx queue to send AMPDUs * Must be atomic - * @free: release all the ressource for the transport layer itself such as - * irq, tasklet etc... From this point on, the device may not issue - * any interrupt (incl. RFKILL). - * May sleep - * @check_stuck_queue: check if a specific queue is stuck * @wait_tx_queue_empty: wait until all tx queues are empty * May sleep * @dbgfs_register: add the dbgfs files under this directory. Files will be @@ -347,11 +367,12 @@ struct iwl_trans_config { * @configure: configure parameters required by the transport layer from * the op_mode. May be called several times before start_fw, can't be * called after that. + * @set_pmi: set the power pmi state */ struct iwl_trans_ops { int (*start_hw)(struct iwl_trans *iwl_trans); - void (*stop_hw)(struct iwl_trans *iwl_trans); + void (*stop_hw)(struct iwl_trans *iwl_trans, bool op_mode_leaving); int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw); void (*fw_alive)(struct iwl_trans *trans); void (*stop_device)(struct iwl_trans *trans); @@ -361,23 +382,15 @@ struct iwl_trans_ops { int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd); int (*tx)(struct iwl_trans *trans, struct sk_buff *skb, - struct iwl_device_cmd *dev_cmd, enum iwl_rxon_context_id ctx, - u8 sta_id, u8 tid); - int (*reclaim)(struct iwl_trans *trans, int sta_id, int tid, - int txq_id, int ssn, struct sk_buff_head *skbs); + struct iwl_device_cmd *dev_cmd, int queue); + void (*reclaim)(struct iwl_trans *trans, int queue, int ssn, + struct sk_buff_head *skbs); - int (*tx_agg_disable)(struct iwl_trans *trans, - int sta_id, int tid); - int (*tx_agg_alloc)(struct iwl_trans *trans, - int sta_id, int tid); - void (*tx_agg_setup)(struct iwl_trans *trans, - enum iwl_rxon_context_id ctx, int sta_id, int tid, - int frame_limit, u16 ssn); - - void (*free)(struct iwl_trans *trans); + void (*tx_agg_setup)(struct iwl_trans *trans, int queue, int fifo, + int sta_id, int tid, int frame_limit, u16 ssn); + void (*tx_agg_disable)(struct iwl_trans *trans, int queue); int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir); - int (*check_stuck_queue)(struct iwl_trans *trans, int q); int (*wait_tx_queue_empty)(struct iwl_trans *trans); #ifdef CONFIG_PM_SLEEP int (*suspend)(struct iwl_trans *trans); @@ -388,6 +401,7 @@ struct iwl_trans_ops { u32 (*read32)(struct iwl_trans *trans, u32 ofs); void (*configure)(struct iwl_trans *trans, const struct iwl_trans_config *trans_cfg); + void (*set_pmi)(struct iwl_trans *trans, bool state); }; /** @@ -406,20 +420,19 @@ enum iwl_trans_state { * * @ops - pointer to iwl_trans_ops * @op_mode - pointer to the op_mode - * @shrd - pointer to iwl_shared which holds shared data from the upper layer + * @cfg - pointer to the configuration * @reg_lock - protect hw register access * @dev - pointer to struct device * that represents the device * @hw_id: a u32 with the ID of the device / subdevice. * Set during transport allocation. * @hw_id_str: a string with info about HW ID. Set during transport allocation. - * @nvm_device_type: indicates OTP or eeprom * @pm_support: set to true in start_hw if link pm is supported * @wait_command_queue: the wait_queue for SYNC host commands */ struct iwl_trans { const struct iwl_trans_ops *ops; struct iwl_op_mode *op_mode; - struct iwl_shared *shrd; + const struct iwl_cfg *cfg; enum iwl_trans_state state; spinlock_t reg_lock; @@ -428,7 +441,6 @@ struct iwl_trans { u32 hw_id; char hw_id_str[52]; - int nvm_device_type; bool pm_support; wait_queue_head_t wait_command_queue; @@ -457,11 +469,12 @@ static inline int iwl_trans_start_hw(struct iwl_trans *trans) return trans->ops->start_hw(trans); } -static inline void iwl_trans_stop_hw(struct iwl_trans *trans) +static inline void iwl_trans_stop_hw(struct iwl_trans *trans, + bool op_mode_leaving) { might_sleep(); - trans->ops->stop_hw(trans); + trans->ops->stop_hw(trans, op_mode_leaving); trans->state = IWL_TRANS_NO_FW; } @@ -508,60 +521,42 @@ static inline int iwl_trans_send_cmd(struct iwl_trans *trans, } static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb, - struct iwl_device_cmd *dev_cmd, enum iwl_rxon_context_id ctx, - u8 sta_id, u8 tid) -{ - if (trans->state != IWL_TRANS_FW_ALIVE) - IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); - - return trans->ops->tx(trans, skb, dev_cmd, ctx, sta_id, tid); -} - -static inline int iwl_trans_reclaim(struct iwl_trans *trans, int sta_id, - int tid, int txq_id, int ssn, - struct sk_buff_head *skbs) + struct iwl_device_cmd *dev_cmd, int queue) { WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, "%s bad state = %d", __func__, trans->state); - return trans->ops->reclaim(trans, sta_id, tid, txq_id, ssn, skbs); + return trans->ops->tx(trans, skb, dev_cmd, queue); } -static inline int iwl_trans_tx_agg_disable(struct iwl_trans *trans, - int sta_id, int tid) +static inline void iwl_trans_reclaim(struct iwl_trans *trans, int queue, + int ssn, struct sk_buff_head *skbs) { WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, "%s bad state = %d", __func__, trans->state); - return trans->ops->tx_agg_disable(trans, sta_id, tid); + trans->ops->reclaim(trans, queue, ssn, skbs); } -static inline int iwl_trans_tx_agg_alloc(struct iwl_trans *trans, - int sta_id, int tid) +static inline void iwl_trans_tx_agg_disable(struct iwl_trans *trans, int queue) { WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, "%s bad state = %d", __func__, trans->state); - return trans->ops->tx_agg_alloc(trans, sta_id, tid); + trans->ops->tx_agg_disable(trans, queue); } - -static inline void iwl_trans_tx_agg_setup(struct iwl_trans *trans, - enum iwl_rxon_context_id ctx, - int sta_id, int tid, - int frame_limit, u16 ssn) +static inline void iwl_trans_tx_agg_setup(struct iwl_trans *trans, int queue, + int fifo, int sta_id, int tid, + int frame_limit, u16 ssn) { might_sleep(); WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, "%s bad state = %d", __func__, trans->state); - trans->ops->tx_agg_setup(trans, ctx, sta_id, tid, frame_limit, ssn); -} - -static inline void iwl_trans_free(struct iwl_trans *trans) -{ - trans->ops->free(trans); + trans->ops->tx_agg_setup(trans, queue, fifo, sta_id, tid, + frame_limit, ssn); } static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans) @@ -572,13 +567,6 @@ static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans) return trans->ops->wait_tx_queue_empty(trans); } -static inline int iwl_trans_check_stuck_queue(struct iwl_trans *trans, int q) -{ - WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, - "%s bad state = %d", __func__, trans->state); - - return trans->ops->check_stuck_queue(trans, q); -} static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans, struct dentry *dir) { @@ -612,20 +600,15 @@ static inline u32 iwl_trans_read32(struct iwl_trans *trans, u32 ofs) return trans->ops->read32(trans, ofs); } +static inline void iwl_trans_set_pmi(struct iwl_trans *trans, bool state) +{ + trans->ops->set_pmi(trans, state); +} + /***************************************************** -* Transport layers implementations + their allocation function +* driver (transport) register/unregister functions ******************************************************/ -struct pci_dev; -struct pci_device_id; -extern const struct iwl_trans_ops trans_ops_pcie; -struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd, - struct pci_dev *pdev, - const struct pci_device_id *ent); int __must_check iwl_pci_register_driver(void); void iwl_pci_unregister_driver(void); -extern const struct iwl_trans_ops trans_ops_idi; -struct iwl_trans *iwl_trans_idi_alloc(struct iwl_shared *shrd, - void *pdev_void, - const void *ent_void); #endif /* __iwl_trans_h__ */ diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-ucode.c b/trunk/drivers/net/wireless/iwlwifi/iwl-ucode.c index 252828728837..bc40dc68b0f4 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-ucode.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-ucode.c @@ -31,7 +31,6 @@ #include #include "iwl-dev.h" -#include "iwl-core.h" #include "iwl-io.h" #include "iwl-agn-hw.h" #include "iwl-agn.h" @@ -40,37 +39,6 @@ #include "iwl-fh.h" #include "iwl-op-mode.h" -static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = { - {COEX_CU_UNASSOC_IDLE_RP, COEX_CU_UNASSOC_IDLE_WP, - 0, COEX_UNASSOC_IDLE_FLAGS}, - {COEX_CU_UNASSOC_MANUAL_SCAN_RP, COEX_CU_UNASSOC_MANUAL_SCAN_WP, - 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS}, - {COEX_CU_UNASSOC_AUTO_SCAN_RP, COEX_CU_UNASSOC_AUTO_SCAN_WP, - 0, COEX_UNASSOC_AUTO_SCAN_FLAGS}, - {COEX_CU_CALIBRATION_RP, COEX_CU_CALIBRATION_WP, - 0, COEX_CALIBRATION_FLAGS}, - {COEX_CU_PERIODIC_CALIBRATION_RP, COEX_CU_PERIODIC_CALIBRATION_WP, - 0, COEX_PERIODIC_CALIBRATION_FLAGS}, - {COEX_CU_CONNECTION_ESTAB_RP, COEX_CU_CONNECTION_ESTAB_WP, - 0, COEX_CONNECTION_ESTAB_FLAGS}, - {COEX_CU_ASSOCIATED_IDLE_RP, COEX_CU_ASSOCIATED_IDLE_WP, - 0, COEX_ASSOCIATED_IDLE_FLAGS}, - {COEX_CU_ASSOC_MANUAL_SCAN_RP, COEX_CU_ASSOC_MANUAL_SCAN_WP, - 0, COEX_ASSOC_MANUAL_SCAN_FLAGS}, - {COEX_CU_ASSOC_AUTO_SCAN_RP, COEX_CU_ASSOC_AUTO_SCAN_WP, - 0, COEX_ASSOC_AUTO_SCAN_FLAGS}, - {COEX_CU_ASSOC_ACTIVE_LEVEL_RP, COEX_CU_ASSOC_ACTIVE_LEVEL_WP, - 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS}, - {COEX_CU_RF_ON_RP, COEX_CU_RF_ON_WP, 0, COEX_CU_RF_ON_FLAGS}, - {COEX_CU_RF_OFF_RP, COEX_CU_RF_OFF_WP, 0, COEX_RF_OFF_FLAGS}, - {COEX_CU_STAND_ALONE_DEBUG_RP, COEX_CU_STAND_ALONE_DEBUG_WP, - 0, COEX_STAND_ALONE_DEBUG_FLAGS}, - {COEX_CU_IPAN_ASSOC_LEVEL_RP, COEX_CU_IPAN_ASSOC_LEVEL_WP, - 0, COEX_IPAN_ASSOC_LEVEL_FLAGS}, - {COEX_CU_RSRVD1_RP, COEX_CU_RSRVD1_WP, 0, COEX_RSRVD1_FLAGS}, - {COEX_CU_RSRVD2_RP, COEX_CU_RSRVD2_WP, 0, COEX_RSRVD2_FLAGS} -}; - /****************************************************************************** * * uCode download functions @@ -93,7 +61,7 @@ static int iwl_set_Xtal_calib(struct iwl_priv *priv) { struct iwl_calib_xtal_freq_cmd cmd; __le16 *xtal_calib = - (__le16 *)iwl_eeprom_query_addr(priv->shrd, EEPROM_XTAL); + (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_XTAL); iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD); cmd.cap_pin1 = le16_to_cpu(xtal_calib[0]); @@ -105,8 +73,7 @@ static int iwl_set_temperature_offset_calib(struct iwl_priv *priv) { struct iwl_calib_temperature_offset_cmd cmd; __le16 *offset_calib = - (__le16 *)iwl_eeprom_query_addr(priv->shrd, - EEPROM_RAW_TEMPERATURE); + (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_RAW_TEMPERATURE); memset(&cmd, 0, sizeof(cmd)); iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD); @@ -122,16 +89,15 @@ static int iwl_set_temperature_offset_calib(struct iwl_priv *priv) static int iwl_set_temperature_offset_calib_v2(struct iwl_priv *priv) { struct iwl_calib_temperature_offset_v2_cmd cmd; - __le16 *offset_calib_high = (__le16 *)iwl_eeprom_query_addr(priv->shrd, + __le16 *offset_calib_high = (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_KELVIN_TEMPERATURE); __le16 *offset_calib_low = - (__le16 *)iwl_eeprom_query_addr(priv->shrd, - EEPROM_RAW_TEMPERATURE); + (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_RAW_TEMPERATURE); struct iwl_eeprom_calib_hdr *hdr; memset(&cmd, 0, sizeof(cmd)); iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD); - hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv->shrd, + hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv, EEPROM_CALIB_ALL); memcpy(&cmd.radio_sensor_offset_high, offset_calib_high, sizeof(*offset_calib_high)); @@ -174,30 +140,12 @@ static int iwl_send_calib_cfg(struct iwl_priv *priv) return iwl_dvm_send_cmd(priv, &cmd); } -int iwlagn_rx_calib_result(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->data; - int len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; - - /* reduce the size of the length field itself */ - len -= 4; - - if (iwl_calib_set(priv, hdr, len)) - IWL_ERR(priv, "Failed to record calibration data %d\n", - hdr->op_code); - - return 0; -} - int iwl_init_alive_start(struct iwl_priv *priv) { int ret; - if (cfg(priv)->bt_params && - cfg(priv)->bt_params->advanced_bt_coexist) { + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist) { /* * Tell uCode we are ready to perform calibration * need to perform this before any calibration @@ -219,8 +167,8 @@ int iwl_init_alive_start(struct iwl_priv *priv) * temperature offset calibration is only needed for runtime ucode, * so prepare the value now. */ - if (cfg(priv)->need_temp_offset_calib) { - if (cfg(priv)->temp_offset_v2) + if (priv->cfg->need_temp_offset_calib) { + if (priv->cfg->temp_offset_v2) return iwl_set_temperature_offset_calib_v2(priv); else return iwl_set_temperature_offset_calib(priv); @@ -229,29 +177,13 @@ int iwl_init_alive_start(struct iwl_priv *priv) return 0; } -static int iwl_send_wimax_coex(struct iwl_priv *priv) +int iwl_send_wimax_coex(struct iwl_priv *priv) { struct iwl_wimax_coex_cmd coex_cmd; - if (cfg(priv)->base_params->support_wimax_coexist) { - /* UnMask wake up src at associated sleep */ - coex_cmd.flags = COEX_FLAGS_ASSOC_WA_UNMASK_MSK; + /* coexistence is disabled */ + memset(&coex_cmd, 0, sizeof(coex_cmd)); - /* UnMask wake up src at unassociated sleep */ - coex_cmd.flags |= COEX_FLAGS_UNASSOC_WA_UNMASK_MSK; - memcpy(coex_cmd.sta_prio, cu_priorities, - sizeof(struct iwl_wimax_coex_event_entry) * - COEX_NUM_OF_EVENTS); - - /* enabling the coexistence feature */ - coex_cmd.flags |= COEX_FLAGS_COEX_ENABLE_MSK; - - /* enabling the priorities tables */ - coex_cmd.flags |= COEX_FLAGS_STA_TABLE_VALID_MSK; - } else { - /* coexistence is disabled */ - memset(&coex_cmd, 0, sizeof(coex_cmd)); - } return iwl_dvm_send_cmd_pdu(priv, COEX_PRIORITY_TABLE_CMD, CMD_SYNC, sizeof(coex_cmd), &coex_cmd); @@ -311,7 +243,7 @@ static int iwl_alive_notify(struct iwl_priv *priv) { int ret; - iwl_trans_fw_alive(trans(priv)); + iwl_trans_fw_alive(priv->trans); priv->passive_no_rx = false; priv->transport_queue_stop = 0; @@ -320,7 +252,7 @@ static int iwl_alive_notify(struct iwl_priv *priv) if (ret) return ret; - if (!cfg(priv)->no_xtal_calib) { + if (!priv->cfg->no_xtal_calib) { ret = iwl_set_Xtal_calib(priv); if (ret) return ret; @@ -349,9 +281,9 @@ static int iwl_verify_sec_sparse(struct iwl_priv *priv, /* read data comes through single port, auto-incr addr */ /* NOTE: Use the debugless read so we don't flood kernel log * if IWL_DL_IO is set */ - iwl_write_direct32(trans(priv), HBUS_TARG_MEM_RADDR, + iwl_write_direct32(priv->trans, HBUS_TARG_MEM_RADDR, i + fw_desc->offset); - val = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT); + val = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT); if (val != le32_to_cpu(*image)) return -EIO; } @@ -370,14 +302,14 @@ static void iwl_print_mismatch_sec(struct iwl_priv *priv, IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len); - iwl_write_direct32(trans(priv), HBUS_TARG_MEM_RADDR, + iwl_write_direct32(priv->trans, HBUS_TARG_MEM_RADDR, fw_desc->offset); for (offs = 0; offs < len && errors < 20; offs += sizeof(u32), image++) { /* read data comes through single port, auto-incr addr */ - val = iwl_read32(trans(priv), HBUS_TARG_MEM_RDAT); + val = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT); if (val != le32_to_cpu(*image)) { IWL_ERR(priv, "uCode INST section at " "offset 0x%x, is 0x%x, s/b 0x%x\n", @@ -417,9 +349,8 @@ struct iwl_alive_data { u8 subtype; }; -static void iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, - struct iwl_rx_packet *pkt, - void *data) +static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, + struct iwl_rx_packet *pkt, void *data) { struct iwl_priv *priv = container_of(notif_wait, struct iwl_priv, notif_wait); @@ -433,13 +364,15 @@ static void iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, palive->is_valid, palive->ver_type, palive->ver_subtype); - priv->shrd->device_pointers.error_event_table = + priv->device_pointers.error_event_table = le32_to_cpu(palive->error_event_table_ptr); - priv->shrd->device_pointers.log_event_table = + priv->device_pointers.log_event_table = le32_to_cpu(palive->log_event_table_ptr); alive_data->subtype = palive->ver_subtype; alive_data->valid = palive->is_valid == UCODE_VALID_OK; + + return true; } #define UCODE_ALIVE_TIMEOUT HZ @@ -453,9 +386,10 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv, const struct fw_img *fw; int ret; enum iwl_ucode_type old_type; + static const u8 alive_cmd[] = { REPLY_ALIVE }; - old_type = priv->shrd->ucode_type; - priv->shrd->ucode_type = ucode_type; + old_type = priv->cur_ucode; + priv->cur_ucode = ucode_type; fw = iwl_get_ucode_image(priv, ucode_type); priv->ucode_loaded = false; @@ -463,12 +397,13 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv, if (!fw) return -EINVAL; - iwl_init_notification_wait(&priv->notif_wait, &alive_wait, REPLY_ALIVE, - iwl_alive_fn, &alive_data); + iwl_init_notification_wait(&priv->notif_wait, &alive_wait, + alive_cmd, ARRAY_SIZE(alive_cmd), + iwl_alive_fn, &alive_data); - ret = iwl_trans_start_fw(trans(priv), fw); + ret = iwl_trans_start_fw(priv->trans, fw); if (ret) { - priv->shrd->ucode_type = old_type; + priv->cur_ucode = old_type; iwl_remove_notification(&priv->notif_wait, &alive_wait); return ret; } @@ -480,13 +415,13 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv, ret = iwl_wait_notification(&priv->notif_wait, &alive_wait, UCODE_ALIVE_TIMEOUT); if (ret) { - priv->shrd->ucode_type = old_type; + priv->cur_ucode = old_type; return ret; } if (!alive_data.valid) { IWL_ERR(priv, "Loaded ucode is not valid!\n"); - priv->shrd->ucode_type = old_type; + priv->cur_ucode = old_type; return -EIO; } @@ -498,7 +433,7 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv, if (ucode_type != IWL_UCODE_WOWLAN) { ret = iwl_verify_ucode(priv, ucode_type); if (ret) { - priv->shrd->ucode_type = old_type; + priv->cur_ucode = old_type; return ret; } @@ -510,7 +445,7 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv, if (ret) { IWL_WARN(priv, "Could not complete ALIVE transition: %d\n", ret); - priv->shrd->ucode_type = old_type; + priv->cur_ucode = old_type; return ret; } @@ -519,9 +454,38 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv, return 0; } +static bool iwlagn_wait_calib(struct iwl_notif_wait_data *notif_wait, + struct iwl_rx_packet *pkt, void *data) +{ + struct iwl_priv *priv = data; + struct iwl_calib_hdr *hdr; + int len; + + if (pkt->hdr.cmd != CALIBRATION_RES_NOTIFICATION) { + WARN_ON(pkt->hdr.cmd != CALIBRATION_COMPLETE_NOTIFICATION); + return true; + } + + hdr = (struct iwl_calib_hdr *)pkt->data; + len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; + + /* reduce the size by the length field itself */ + len -= sizeof(__le32); + + if (iwl_calib_set(priv, hdr, len)) + IWL_ERR(priv, "Failed to record calibration data %d\n", + hdr->op_code); + + return false; +} + int iwl_run_init_ucode(struct iwl_priv *priv) { struct iwl_notification_wait calib_wait; + static const u8 calib_complete[] = { + CALIBRATION_RES_NOTIFICATION, + CALIBRATION_COMPLETE_NOTIFICATION + }; int ret; lockdep_assert_held(&priv->mutex); @@ -534,8 +498,8 @@ int iwl_run_init_ucode(struct iwl_priv *priv) return 0; iwl_init_notification_wait(&priv->notif_wait, &calib_wait, - CALIBRATION_COMPLETE_NOTIFICATION, - NULL, NULL); + calib_complete, ARRAY_SIZE(calib_complete), + iwlagn_wait_calib, priv); /* Will also start the device */ ret = iwl_load_ucode_wait_alive(priv, IWL_UCODE_INIT); @@ -561,7 +525,7 @@ int iwl_run_init_ucode(struct iwl_priv *priv) iwl_remove_notification(&priv->notif_wait, &calib_wait); out: /* Whatever happened, stop the device */ - iwl_trans_stop_device(trans(priv)); + iwl_trans_stop_device(priv->trans); priv->ucode_loaded = false; return ret; diff --git a/trunk/drivers/net/wireless/iwmc3200wifi/Kconfig b/trunk/drivers/net/wireless/iwmc3200wifi/Kconfig index 03f998d098c5..7107ce53d4d4 100644 --- a/trunk/drivers/net/wireless/iwmc3200wifi/Kconfig +++ b/trunk/drivers/net/wireless/iwmc3200wifi/Kconfig @@ -1,5 +1,5 @@ config IWM - tristate "Intel Wireless Multicomm 3200 WiFi driver" + tristate "Intel Wireless Multicomm 3200 WiFi driver (EXPERIMENTAL)" depends on MMC && EXPERIMENTAL depends on CFG80211 select FW_LOADER diff --git a/trunk/drivers/net/wireless/libertas/Makefile b/trunk/drivers/net/wireless/libertas/Makefile index f7d01bfa2e4a..eac72f7bd341 100644 --- a/trunk/drivers/net/wireless/libertas/Makefile +++ b/trunk/drivers/net/wireless/libertas/Makefile @@ -6,6 +6,7 @@ libertas-y += ethtool.o libertas-y += main.o libertas-y += rx.o libertas-y += tx.o +libertas-y += firmware.o libertas-$(CONFIG_LIBERTAS_MESH) += mesh.o usb8xxx-objs += if_usb.o diff --git a/trunk/drivers/net/wireless/libertas/decl.h b/trunk/drivers/net/wireless/libertas/decl.h index bc951ab4b681..84a3aa7ac570 100644 --- a/trunk/drivers/net/wireless/libertas/decl.h +++ b/trunk/drivers/net/wireless/libertas/decl.h @@ -18,6 +18,10 @@ struct lbs_fw_table { const char *fwname; }; +struct lbs_private; +typedef void (*lbs_fw_cb)(struct lbs_private *priv, int ret, + const struct firmware *helper, const struct firmware *mainfw); + struct lbs_private; struct sk_buff; struct net_device; @@ -66,10 +70,13 @@ int lbs_exit_auto_deep_sleep(struct lbs_private *priv); u32 lbs_fw_index_to_data_rate(u8 index); u8 lbs_data_rate_to_fw_index(u32 rate); -int lbs_get_firmware(struct device *dev, const char *user_helper, - const char *user_mainfw, u32 card_model, +int lbs_get_firmware(struct device *dev, u32 card_model, const struct lbs_fw_table *fw_table, const struct firmware **helper, const struct firmware **mainfw); +int lbs_get_firmware_async(struct lbs_private *priv, struct device *device, + u32 card_model, const struct lbs_fw_table *fw_table, + lbs_fw_cb callback); +void lbs_wait_for_firmware_load(struct lbs_private *priv); #endif diff --git a/trunk/drivers/net/wireless/libertas/dev.h b/trunk/drivers/net/wireless/libertas/dev.h index f3fd447131c2..672005430aca 100644 --- a/trunk/drivers/net/wireless/libertas/dev.h +++ b/trunk/drivers/net/wireless/libertas/dev.h @@ -7,6 +7,7 @@ #define _LBS_DEV_H_ #include "defs.h" +#include "decl.h" #include "host.h" #include @@ -180,6 +181,15 @@ struct lbs_private { wait_queue_head_t scan_q; /* Whether the scan was initiated internally and not by cfg80211 */ bool internal_scan; + + /* Firmware load */ + u32 fw_model; + wait_queue_head_t fw_waitq; + struct device *fw_device; + const struct firmware *helper_fw; + const struct lbs_fw_table *fw_table; + const struct lbs_fw_table *fw_iter; + lbs_fw_cb fw_callback; }; extern struct cmd_confirm_sleep confirm_sleep; diff --git a/trunk/drivers/net/wireless/libertas/firmware.c b/trunk/drivers/net/wireless/libertas/firmware.c new file mode 100644 index 000000000000..601f2075355e --- /dev/null +++ b/trunk/drivers/net/wireless/libertas/firmware.c @@ -0,0 +1,224 @@ +/* + * Firmware loading and handling functions. + */ + +#include +#include +#include +#include +#include + +#include "dev.h" +#include "decl.h" + +static void load_next_firmware_from_table(struct lbs_private *private); + +static void lbs_fw_loaded(struct lbs_private *priv, int ret, + const struct firmware *helper, const struct firmware *mainfw) +{ + unsigned long flags; + + lbs_deb_fw("firmware load complete, code %d\n", ret); + + /* User must free helper/mainfw */ + priv->fw_callback(priv, ret, helper, mainfw); + + spin_lock_irqsave(&priv->driver_lock, flags); + priv->fw_callback = NULL; + wake_up(&priv->fw_waitq); + spin_unlock_irqrestore(&priv->driver_lock, flags); +} + +static void do_load_firmware(struct lbs_private *priv, const char *name, + void (*cb)(const struct firmware *fw, void *context)) +{ + int ret; + + lbs_deb_fw("Requesting %s\n", name); + ret = request_firmware_nowait(THIS_MODULE, true, name, + priv->fw_device, GFP_KERNEL, priv, cb); + if (ret) { + lbs_deb_fw("request_firmware_nowait error %d\n", ret); + lbs_fw_loaded(priv, ret, NULL, NULL); + } +} + +static void main_firmware_cb(const struct firmware *firmware, void *context) +{ + struct lbs_private *priv = context; + + if (!firmware) { + /* Failed to find firmware: try next table entry */ + load_next_firmware_from_table(priv); + return; + } + + /* Firmware found! */ + lbs_fw_loaded(priv, 0, priv->helper_fw, firmware); +} + +static void helper_firmware_cb(const struct firmware *firmware, void *context) +{ + struct lbs_private *priv = context; + + if (!firmware) { + /* Failed to find firmware: try next table entry */ + load_next_firmware_from_table(priv); + return; + } + + /* Firmware found! */ + if (priv->fw_iter->fwname) { + priv->helper_fw = firmware; + do_load_firmware(priv, priv->fw_iter->fwname, main_firmware_cb); + } else { + /* No main firmware needed for this helper --> success! */ + lbs_fw_loaded(priv, 0, firmware, NULL); + } +} + +static void load_next_firmware_from_table(struct lbs_private *priv) +{ + const struct lbs_fw_table *iter; + + if (!priv->fw_iter) + iter = priv->fw_table; + else + iter = ++priv->fw_iter; + + if (priv->helper_fw) { + release_firmware(priv->helper_fw); + priv->helper_fw = NULL; + } + +next: + if (!iter->helper) { + /* End of table hit. */ + lbs_fw_loaded(priv, -ENOENT, NULL, NULL); + return; + } + + if (iter->model != priv->fw_model) { + iter++; + goto next; + } + + priv->fw_iter = iter; + do_load_firmware(priv, iter->helper, helper_firmware_cb); +} + +void lbs_wait_for_firmware_load(struct lbs_private *priv) +{ + wait_event(priv->fw_waitq, priv->fw_callback == NULL); +} + +/** + * lbs_get_firmware_async - Retrieves firmware asynchronously. Can load + * either a helper firmware and a main firmware (2-stage), or just the helper. + * + * @priv: Pointer to lbs_private instance + * @dev: A pointer to &device structure + * @card_model: Bus-specific card model ID used to filter firmware table + * elements + * @fw_table: Table of firmware file names and device model numbers + * terminated by an entry with a NULL helper name + * @callback: User callback to invoke when firmware load succeeds or fails. + */ +int lbs_get_firmware_async(struct lbs_private *priv, struct device *device, + u32 card_model, const struct lbs_fw_table *fw_table, + lbs_fw_cb callback) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->driver_lock, flags); + if (priv->fw_callback) { + lbs_deb_fw("firmware load already in progress\n"); + spin_unlock_irqrestore(&priv->driver_lock, flags); + return -EBUSY; + } + + priv->fw_device = device; + priv->fw_callback = callback; + priv->fw_table = fw_table; + priv->fw_iter = NULL; + priv->fw_model = card_model; + spin_unlock_irqrestore(&priv->driver_lock, flags); + + lbs_deb_fw("Starting async firmware load\n"); + load_next_firmware_from_table(priv); + return 0; +} +EXPORT_SYMBOL_GPL(lbs_get_firmware_async); + +/** + * lbs_get_firmware - Retrieves two-stage firmware + * + * @dev: A pointer to &device structure + * @card_model: Bus-specific card model ID used to filter firmware table + * elements + * @fw_table: Table of firmware file names and device model numbers + * terminated by an entry with a NULL helper name + * @helper: On success, the helper firmware; caller must free + * @mainfw: On success, the main firmware; caller must free + * + * Deprecated: use lbs_get_firmware_async() instead. + * + * returns: 0 on success, non-zero on failure + */ +int lbs_get_firmware(struct device *dev, u32 card_model, + const struct lbs_fw_table *fw_table, + const struct firmware **helper, + const struct firmware **mainfw) +{ + const struct lbs_fw_table *iter; + int ret; + + BUG_ON(helper == NULL); + BUG_ON(mainfw == NULL); + + /* Search for firmware to use from the table. */ + iter = fw_table; + while (iter && iter->helper) { + if (iter->model != card_model) + goto next; + + if (*helper == NULL) { + ret = request_firmware(helper, iter->helper, dev); + if (ret) + goto next; + + /* If the device has one-stage firmware (ie cf8305) and + * we've got it then we don't need to bother with the + * main firmware. + */ + if (iter->fwname == NULL) + return 0; + } + + if (*mainfw == NULL) { + ret = request_firmware(mainfw, iter->fwname, dev); + if (ret) { + /* Clear the helper to ensure we don't have + * mismatched firmware pairs. + */ + release_firmware(*helper); + *helper = NULL; + } + } + + if (*helper && *mainfw) + return 0; + + next: + iter++; + } + + /* Failed */ + release_firmware(*helper); + *helper = NULL; + release_firmware(*mainfw); + *mainfw = NULL; + + return -ENOENT; +} +EXPORT_SYMBOL_GPL(lbs_get_firmware); diff --git a/trunk/drivers/net/wireless/libertas/if_cs.c b/trunk/drivers/net/wireless/libertas/if_cs.c index 234ee88dec95..16beaf39dc53 100644 --- a/trunk/drivers/net/wireless/libertas/if_cs.c +++ b/trunk/drivers/net/wireless/libertas/if_cs.c @@ -738,6 +738,50 @@ static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw) return ret; } +static void if_cs_prog_firmware(struct lbs_private *priv, int ret, + const struct firmware *helper, + const struct firmware *mainfw) +{ + struct if_cs_card *card = priv->card; + + if (ret) { + pr_err("failed to find firmware (%d)\n", ret); + return; + } + + /* Load the firmware */ + ret = if_cs_prog_helper(card, helper); + if (ret == 0 && (card->model != MODEL_8305)) + ret = if_cs_prog_real(card, mainfw); + if (ret) + goto out; + + /* Now actually get the IRQ */ + ret = request_irq(card->p_dev->irq, if_cs_interrupt, + IRQF_SHARED, DRV_NAME, card); + if (ret) { + pr_err("error in request_irq\n"); + goto out; + } + + /* + * Clear any interrupt cause that happened while sending + * firmware/initializing card + */ + if_cs_write16(card, IF_CS_CARD_INT_CAUSE, IF_CS_BIT_MASK); + if_cs_enable_ints(card); + + /* And finally bring the card up */ + priv->fw_ready = 1; + if (lbs_start_card(priv) != 0) { + pr_err("could not activate card\n"); + free_irq(card->p_dev->irq, card); + } + +out: + release_firmware(helper); + release_firmware(mainfw); +} /********************************************************************/ @@ -809,8 +853,6 @@ static int if_cs_probe(struct pcmcia_device *p_dev) unsigned int prod_id; struct lbs_private *priv; struct if_cs_card *card; - const struct firmware *helper = NULL; - const struct firmware *mainfw = NULL; lbs_deb_enter(LBS_DEB_CS); @@ -890,20 +932,6 @@ static int if_cs_probe(struct pcmcia_device *p_dev) goto out2; } - ret = lbs_get_firmware(&p_dev->dev, NULL, NULL, card->model, - &fw_table[0], &helper, &mainfw); - if (ret) { - pr_err("failed to find firmware (%d)\n", ret); - goto out2; - } - - /* Load the firmware early, before calling into libertas.ko */ - ret = if_cs_prog_helper(card, helper); - if (ret == 0 && (card->model != MODEL_8305)) - ret = if_cs_prog_real(card, mainfw); - if (ret) - goto out2; - /* Make this card known to the libertas driver */ priv = lbs_add_card(card, &p_dev->dev); if (!priv) { @@ -911,37 +939,22 @@ static int if_cs_probe(struct pcmcia_device *p_dev) goto out2; } - /* Finish setting up fields in lbs_private */ + /* Set up fields in lbs_private */ card->priv = priv; priv->card = card; priv->hw_host_to_card = if_cs_host_to_card; priv->enter_deep_sleep = NULL; priv->exit_deep_sleep = NULL; priv->reset_deep_sleep_wakeup = NULL; - priv->fw_ready = 1; - /* Now actually get the IRQ */ - ret = request_irq(p_dev->irq, if_cs_interrupt, - IRQF_SHARED, DRV_NAME, card); + /* Get firmware */ + ret = lbs_get_firmware_async(priv, &p_dev->dev, card->model, fw_table, + if_cs_prog_firmware); if (ret) { - pr_err("error in request_irq\n"); - goto out3; - } - - /* - * Clear any interrupt cause that happened while sending - * firmware/initializing card - */ - if_cs_write16(card, IF_CS_CARD_INT_CAUSE, IF_CS_BIT_MASK); - if_cs_enable_ints(card); - - /* And finally bring the card up */ - if (lbs_start_card(priv) != 0) { - pr_err("could not activate card\n"); + pr_err("failed to find firmware (%d)\n", ret); goto out3; } - ret = 0; goto out; out3: @@ -951,11 +964,6 @@ static int if_cs_probe(struct pcmcia_device *p_dev) out1: pcmcia_disable_device(p_dev); out: - if (helper) - release_firmware(helper); - if (mainfw) - release_firmware(mainfw); - lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); return ret; } diff --git a/trunk/drivers/net/wireless/libertas/if_sdio.c b/trunk/drivers/net/wireless/libertas/if_sdio.c index 9804ebc892d4..76caebaa4397 100644 --- a/trunk/drivers/net/wireless/libertas/if_sdio.c +++ b/trunk/drivers/net/wireless/libertas/if_sdio.c @@ -65,12 +65,6 @@ static void if_sdio_interrupt(struct sdio_func *func); */ static u8 user_rmmod; -static char *lbs_helper_name = NULL; -module_param_named(helper_name, lbs_helper_name, charp, 0644); - -static char *lbs_fw_name = NULL; -module_param_named(fw_name, lbs_fw_name, charp, 0644); - static const struct sdio_device_id if_sdio_ids[] = { { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_LIBERTAS) }, @@ -123,11 +117,8 @@ struct if_sdio_card { int model; unsigned long ioport; unsigned int scratch_reg; - - const char *helper; - const char *firmware; - bool helper_allocated; - bool firmware_allocated; + bool started; + wait_queue_head_t pwron_waitq; u8 buffer[65536] __attribute__((aligned(4))); @@ -140,6 +131,9 @@ struct if_sdio_card { u8 rx_unit; }; +static void if_sdio_finish_power_on(struct if_sdio_card *card); +static int if_sdio_power_off(struct if_sdio_card *card); + /********************************************************************/ /* I/O */ /********************************************************************/ @@ -680,12 +674,39 @@ static int if_sdio_prog_real(struct if_sdio_card *card, return ret; } +static void if_sdio_do_prog_firmware(struct lbs_private *priv, int ret, + const struct firmware *helper, + const struct firmware *mainfw) +{ + struct if_sdio_card *card = priv->card; + + if (ret) { + pr_err("failed to find firmware (%d)\n", ret); + return; + } + + ret = if_sdio_prog_helper(card, helper); + if (ret) + goto out; + + lbs_deb_sdio("Helper firmware loaded\n"); + + ret = if_sdio_prog_real(card, mainfw); + if (ret) + goto out; + + lbs_deb_sdio("Firmware loaded\n"); + if_sdio_finish_power_on(card); + +out: + release_firmware(helper); + release_firmware(mainfw); +} + static int if_sdio_prog_firmware(struct if_sdio_card *card) { int ret; u16 scratch; - const struct firmware *helper = NULL; - const struct firmware *mainfw = NULL; lbs_deb_enter(LBS_DEB_SDIO); @@ -719,43 +740,18 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card) */ if (scratch == IF_SDIO_FIRMWARE_OK) { lbs_deb_sdio("firmware already loaded\n"); - goto success; + if_sdio_finish_power_on(card); + return 0; } else if ((card->model == MODEL_8686) && (scratch & 0x7fff)) { lbs_deb_sdio("firmware may be running\n"); - goto success; - } - - ret = lbs_get_firmware(&card->func->dev, lbs_helper_name, lbs_fw_name, - card->model, &fw_table[0], &helper, &mainfw); - if (ret) { - pr_err("failed to find firmware (%d)\n", ret); - goto out; + if_sdio_finish_power_on(card); + return 0; } - ret = if_sdio_prog_helper(card, helper); - if (ret) - goto out; - - lbs_deb_sdio("Helper firmware loaded\n"); - - ret = if_sdio_prog_real(card, mainfw); - if (ret) - goto out; - - lbs_deb_sdio("Firmware loaded\n"); - -success: - sdio_claim_host(card->func); - sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE); - sdio_release_host(card->func); - ret = 0; + ret = lbs_get_firmware_async(card->priv, &card->func->dev, card->model, + fw_table, if_sdio_do_prog_firmware); out: - if (helper) - release_firmware(helper); - if (mainfw) - release_firmware(mainfw); - lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); return ret; } @@ -764,55 +760,15 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card) /* Power management */ /********************************************************************/ -static int if_sdio_power_on(struct if_sdio_card *card) +/* Finish power on sequence (after firmware is loaded) */ +static void if_sdio_finish_power_on(struct if_sdio_card *card) { struct sdio_func *func = card->func; struct lbs_private *priv = card->priv; - struct mmc_host *host = func->card->host; int ret; sdio_claim_host(func); - - ret = sdio_enable_func(func); - if (ret) - goto release; - - /* For 1-bit transfers to the 8686 model, we need to enable the - * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0 - * bit to allow access to non-vendor registers. */ - if ((card->model == MODEL_8686) && - (host->caps & MMC_CAP_SDIO_IRQ) && - (host->ios.bus_width == MMC_BUS_WIDTH_1)) { - u8 reg; - - func->card->quirks |= MMC_QUIRK_LENIENT_FN0; - reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret); - if (ret) - goto disable; - - reg |= SDIO_BUS_ECSI; - sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret); - if (ret) - goto disable; - } - - card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret); - if (ret) - goto disable; - - card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8; - if (ret) - goto disable; - - card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16; - if (ret) - goto disable; - - sdio_release_host(func); - ret = if_sdio_prog_firmware(card); - sdio_claim_host(func); - if (ret) - goto disable; + sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE); /* * Get rx_unit if the chip is SD8688 or newer. @@ -837,7 +793,7 @@ static int if_sdio_power_on(struct if_sdio_card *card) */ ret = sdio_claim_irq(func, if_sdio_interrupt); if (ret) - goto disable; + goto release; /* * Enable interrupts now that everything is set up @@ -863,11 +819,79 @@ static int if_sdio_power_on(struct if_sdio_card *card) } priv->fw_ready = 1; + wake_up(&card->pwron_waitq); - return 0; + if (!card->started) { + ret = lbs_start_card(priv); + if_sdio_power_off(card); + if (ret == 0) { + card->started = true; + /* Tell PM core that we don't need the card to be + * powered now */ + pm_runtime_put_noidle(&func->dev); + } + } + + return; release_irq: sdio_release_irq(func); +release: + sdio_release_host(func); +} + +static int if_sdio_power_on(struct if_sdio_card *card) +{ + struct sdio_func *func = card->func; + struct mmc_host *host = func->card->host; + int ret; + + sdio_claim_host(func); + + ret = sdio_enable_func(func); + if (ret) + goto release; + + /* For 1-bit transfers to the 8686 model, we need to enable the + * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0 + * bit to allow access to non-vendor registers. */ + if ((card->model == MODEL_8686) && + (host->caps & MMC_CAP_SDIO_IRQ) && + (host->ios.bus_width == MMC_BUS_WIDTH_1)) { + u8 reg; + + func->card->quirks |= MMC_QUIRK_LENIENT_FN0; + reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret); + if (ret) + goto disable; + + reg |= SDIO_BUS_ECSI; + sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret); + if (ret) + goto disable; + } + + card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret); + if (ret) + goto disable; + + card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8; + if (ret) + goto disable; + + card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16; + if (ret) + goto disable; + + sdio_release_host(func); + ret = if_sdio_prog_firmware(card); + if (ret) { + sdio_disable_func(func); + return ret; + } + + return 0; + disable: sdio_disable_func(func); release: @@ -1074,11 +1098,17 @@ static int if_sdio_power_save(struct lbs_private *priv) static int if_sdio_power_restore(struct lbs_private *priv) { struct if_sdio_card *card = priv->card; + int r; /* Make sure the card will not be powered off by runtime PM */ pm_runtime_get_sync(&card->func->dev); - return if_sdio_power_on(card); + r = if_sdio_power_on(card); + if (r) + return r; + + wait_event(card->pwron_waitq, priv->fw_ready); + return 0; } @@ -1179,6 +1209,7 @@ static int if_sdio_probe(struct sdio_func *func, spin_lock_init(&card->lock); card->workqueue = create_workqueue("libertas_sdio"); INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker); + init_waitqueue_head(&card->pwron_waitq); /* Check if we support this card */ for (i = 0; i < ARRAY_SIZE(fw_table); i++) { @@ -1220,14 +1251,6 @@ static int if_sdio_probe(struct sdio_func *func, if (ret) goto err_activate_card; - ret = lbs_start_card(priv); - if_sdio_power_off(card); - if (ret) - goto err_activate_card; - - /* Tell PM core that we don't need the card to be powered now */ - pm_runtime_put_noidle(&func->dev); - out: lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); @@ -1244,10 +1267,6 @@ static int if_sdio_probe(struct sdio_func *func, kfree(packet); } - if (card->helper_allocated) - kfree(card->helper); - if (card->firmware_allocated) - kfree(card->firmware); kfree(card); goto out; @@ -1295,12 +1314,6 @@ static void if_sdio_remove(struct sdio_func *func) kfree(packet); } - if (card->helper_allocated) - kfree(card->helper); - if (card->firmware_allocated) - kfree(card->firmware); - kfree(card); - lbs_deb_leave(LBS_DEB_SDIO); } diff --git a/trunk/drivers/net/wireless/libertas/if_spi.c b/trunk/drivers/net/wireless/libertas/if_spi.c index 50b1ee7721e9..9604a1c4a74d 100644 --- a/trunk/drivers/net/wireless/libertas/if_spi.c +++ b/trunk/drivers/net/wireless/libertas/if_spi.c @@ -1064,9 +1064,8 @@ static int if_spi_init_card(struct if_spi_card *card) goto out; } - err = lbs_get_firmware(&card->spi->dev, NULL, NULL, - card->card_id, &fw_table[0], &helper, - &mainfw); + err = lbs_get_firmware(&card->spi->dev, card->card_id, + &fw_table[0], &helper, &mainfw); if (err) { netdev_err(priv->dev, "failed to find firmware (%d)\n", err); @@ -1095,10 +1094,8 @@ static int if_spi_init_card(struct if_spi_card *card) goto out; out: - if (helper) - release_firmware(helper); - if (mainfw) - release_firmware(mainfw); + release_firmware(helper); + release_firmware(mainfw); lbs_deb_leave_args(LBS_DEB_SPI, "err %d\n", err); diff --git a/trunk/drivers/net/wireless/libertas/if_usb.c b/trunk/drivers/net/wireless/libertas/if_usb.c index 74da5f1ea243..cd3b0d400618 100644 --- a/trunk/drivers/net/wireless/libertas/if_usb.c +++ b/trunk/drivers/net/wireless/libertas/if_usb.c @@ -29,9 +29,6 @@ #define MESSAGE_HEADER_LEN 4 -static char *lbs_fw_name = NULL; -module_param_named(fw_name, lbs_fw_name, charp, 0644); - MODULE_FIRMWARE("libertas/usb8388_v9.bin"); MODULE_FIRMWARE("libertas/usb8388_v5.bin"); MODULE_FIRMWARE("libertas/usb8388.bin"); @@ -44,6 +41,16 @@ enum { MODEL_8682 = 0x2 }; +/* table of firmware file names */ +static const struct lbs_fw_table fw_table[] = { + { MODEL_8388, "libertas/usb8388_olpc.bin", NULL }, + { MODEL_8388, "libertas/usb8388_v9.bin", NULL }, + { MODEL_8388, "libertas/usb8388_v5.bin", NULL }, + { MODEL_8388, "libertas/usb8388.bin", NULL }, + { MODEL_8388, "usb8388.bin", NULL }, + { MODEL_8682, "libertas/usb8682.bin", NULL } +}; + static struct usb_device_id if_usb_table[] = { /* Enter the device signature inside */ { USB_DEVICE(0x1286, 0x2001), .driver_info = MODEL_8388 }, @@ -55,10 +62,9 @@ MODULE_DEVICE_TABLE(usb, if_usb_table); static void if_usb_receive(struct urb *urb); static void if_usb_receive_fwload(struct urb *urb); -static int __if_usb_prog_firmware(struct if_usb_card *cardp, - const char *fwname, int cmd); -static int if_usb_prog_firmware(struct if_usb_card *cardp, - const char *fwname, int cmd); +static void if_usb_prog_firmware(struct lbs_private *priv, int ret, + const struct firmware *fw, + const struct firmware *unused); static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type, uint8_t *payload, uint16_t nb); static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, @@ -67,69 +73,6 @@ static void if_usb_free(struct if_usb_card *cardp); static int if_usb_submit_rx_urb(struct if_usb_card *cardp); static int if_usb_reset_device(struct if_usb_card *cardp); -/* sysfs hooks */ - -/* - * Set function to write firmware to device's persistent memory - */ -static ssize_t if_usb_firmware_set(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct lbs_private *priv = to_net_dev(dev)->ml_priv; - struct if_usb_card *cardp = priv->card; - int ret; - - BUG_ON(buf == NULL); - - ret = if_usb_prog_firmware(cardp, buf, BOOT_CMD_UPDATE_FW); - if (ret == 0) - return count; - - return ret; -} - -/* - * lbs_flash_fw attribute to be exported per ethX interface through sysfs - * (/sys/class/net/ethX/lbs_flash_fw). Use this like so to write firmware to - * the device's persistent memory: - * echo usb8388-5.126.0.p5.bin > /sys/class/net/ethX/lbs_flash_fw - */ -static DEVICE_ATTR(lbs_flash_fw, 0200, NULL, if_usb_firmware_set); - -/** - * if_usb_boot2_set - write firmware to device's persistent memory - * - * @dev: target device - * @attr: device attributes - * @buf: firmware buffer to write - * @count: number of bytes to write - * - * returns: number of bytes written or negative error code - */ -static ssize_t if_usb_boot2_set(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct lbs_private *priv = to_net_dev(dev)->ml_priv; - struct if_usb_card *cardp = priv->card; - int ret; - - BUG_ON(buf == NULL); - - ret = if_usb_prog_firmware(cardp, buf, BOOT_CMD_UPDATE_BOOT2); - if (ret == 0) - return count; - - return ret; -} - -/* - * lbs_flash_boot2 attribute to be exported per ethX interface through sysfs - * (/sys/class/net/ethX/lbs_flash_boot2). Use this like so to write firmware - * to the device's persistent memory: - * echo usb8388-5.126.0.p5.bin > /sys/class/net/ethX/lbs_flash_boot2 - */ -static DEVICE_ATTR(lbs_flash_boot2, 0200, NULL, if_usb_boot2_set); - /** * if_usb_write_bulk_callback - callback function to handle the status * of the URB @@ -256,6 +199,7 @@ static int if_usb_probe(struct usb_interface *intf, struct usb_endpoint_descriptor *endpoint; struct lbs_private *priv; struct if_usb_card *cardp; + int r = -ENOMEM; int i; udev = interface_to_usbdev(intf); @@ -313,20 +257,10 @@ static int if_usb_probe(struct usb_interface *intf, goto dealloc; } - /* Upload firmware */ - kparam_block_sysfs_write(fw_name); - if (__if_usb_prog_firmware(cardp, lbs_fw_name, BOOT_CMD_FW_BY_USB)) { - kparam_unblock_sysfs_write(fw_name); - lbs_deb_usbd(&udev->dev, "FW upload failed\n"); - goto err_prog_firmware; - } - kparam_unblock_sysfs_write(fw_name); - if (!(priv = lbs_add_card(cardp, &intf->dev))) - goto err_prog_firmware; + goto err_add_card; cardp->priv = priv; - cardp->priv->fw_ready = 1; priv->hw_host_to_card = if_usb_host_to_card; priv->enter_deep_sleep = NULL; @@ -339,42 +273,25 @@ static int if_usb_probe(struct usb_interface *intf, cardp->boot2_version = udev->descriptor.bcdDevice; - if_usb_submit_rx_urb(cardp); - - if (lbs_start_card(priv)) - goto err_start_card; - - if_usb_setup_firmware(priv); - usb_get_dev(udev); usb_set_intfdata(intf, cardp); - if (device_create_file(&priv->dev->dev, &dev_attr_lbs_flash_fw)) - netdev_err(priv->dev, - "cannot register lbs_flash_fw attribute\n"); - - if (device_create_file(&priv->dev->dev, &dev_attr_lbs_flash_boot2)) - netdev_err(priv->dev, - "cannot register lbs_flash_boot2 attribute\n"); - - /* - * EHS_REMOVE_WAKEUP is not supported on all versions of the firmware. - */ - priv->wol_criteria = EHS_REMOVE_WAKEUP; - if (lbs_host_sleep_cfg(priv, priv->wol_criteria, NULL)) - priv->ehs_remove_supported = false; + r = lbs_get_firmware_async(priv, &udev->dev, cardp->model, + fw_table, if_usb_prog_firmware); + if (r) + goto err_get_fw; return 0; -err_start_card: +err_get_fw: lbs_remove_card(priv); -err_prog_firmware: +err_add_card: if_usb_reset_device(cardp); dealloc: if_usb_free(cardp); error: - return -ENOMEM; + return r; } /** @@ -389,9 +306,6 @@ static void if_usb_disconnect(struct usb_interface *intf) lbs_deb_enter(LBS_DEB_MAIN); - device_remove_file(&priv->dev->dev, &dev_attr_lbs_flash_boot2); - device_remove_file(&priv->dev->dev, &dev_attr_lbs_flash_fw); - cardp->surprise_removed = 1; if (priv) { @@ -912,121 +826,22 @@ static int check_fwfile_format(const uint8_t *data, uint32_t totlen) return ret; } - -/** -* if_usb_prog_firmware - programs the firmware subject to cmd -* -* @cardp: the if_usb_card descriptor -* @fwname: firmware or boot2 image file name -* @cmd: either BOOT_CMD_FW_BY_USB, BOOT_CMD_UPDATE_FW, -* or BOOT_CMD_UPDATE_BOOT2. -* returns: 0 or error code -*/ -static int if_usb_prog_firmware(struct if_usb_card *cardp, - const char *fwname, int cmd) -{ - struct lbs_private *priv = cardp->priv; - unsigned long flags, caps; - int ret; - - caps = priv->fwcapinfo; - if (((cmd == BOOT_CMD_UPDATE_FW) && !(caps & FW_CAPINFO_FIRMWARE_UPGRADE)) || - ((cmd == BOOT_CMD_UPDATE_BOOT2) && !(caps & FW_CAPINFO_BOOT2_UPGRADE))) - return -EOPNOTSUPP; - - /* Ensure main thread is idle. */ - spin_lock_irqsave(&priv->driver_lock, flags); - while (priv->cur_cmd != NULL || priv->dnld_sent != DNLD_RES_RECEIVED) { - spin_unlock_irqrestore(&priv->driver_lock, flags); - if (wait_event_interruptible(priv->waitq, - (priv->cur_cmd == NULL && - priv->dnld_sent == DNLD_RES_RECEIVED))) { - return -ERESTARTSYS; - } - spin_lock_irqsave(&priv->driver_lock, flags); - } - priv->dnld_sent = DNLD_BOOTCMD_SENT; - spin_unlock_irqrestore(&priv->driver_lock, flags); - - ret = __if_usb_prog_firmware(cardp, fwname, cmd); - - spin_lock_irqsave(&priv->driver_lock, flags); - priv->dnld_sent = DNLD_RES_RECEIVED; - spin_unlock_irqrestore(&priv->driver_lock, flags); - - wake_up(&priv->waitq); - - return ret; -} - -/* table of firmware file names */ -static const struct { - u32 model; - const char *fwname; -} fw_table[] = { - { MODEL_8388, "libertas/usb8388_v9.bin" }, - { MODEL_8388, "libertas/usb8388_v5.bin" }, - { MODEL_8388, "libertas/usb8388.bin" }, - { MODEL_8388, "usb8388.bin" }, - { MODEL_8682, "libertas/usb8682.bin" } -}; - -#ifdef CONFIG_OLPC - -static int try_olpc_fw(struct if_usb_card *cardp) -{ - int retval = -ENOENT; - - /* try the OLPC firmware first; fall back to fw_table list */ - if (machine_is_olpc() && cardp->model == MODEL_8388) - retval = request_firmware(&cardp->fw, - "libertas/usb8388_olpc.bin", &cardp->udev->dev); - return retval; -} - -#else -static int try_olpc_fw(struct if_usb_card *cardp) { return -ENOENT; } -#endif /* !CONFIG_OLPC */ - -static int get_fw(struct if_usb_card *cardp, const char *fwname) -{ - int i; - - /* Try user-specified firmware first */ - if (fwname) - return request_firmware(&cardp->fw, fwname, &cardp->udev->dev); - - /* Handle OLPC firmware */ - if (try_olpc_fw(cardp) == 0) - return 0; - - /* Otherwise search for firmware to use */ - for (i = 0; i < ARRAY_SIZE(fw_table); i++) { - if (fw_table[i].model != cardp->model) - continue; - if (request_firmware(&cardp->fw, fw_table[i].fwname, - &cardp->udev->dev) == 0) - return 0; - } - - return -ENOENT; -} - -static int __if_usb_prog_firmware(struct if_usb_card *cardp, - const char *fwname, int cmd) +static void if_usb_prog_firmware(struct lbs_private *priv, int ret, + const struct firmware *fw, + const struct firmware *unused) { + struct if_usb_card *cardp = priv->card; int i = 0; static int reset_count = 10; - int ret = 0; lbs_deb_enter(LBS_DEB_USB); - ret = get_fw(cardp, fwname); if (ret) { pr_err("failed to find firmware (%d)\n", ret); goto done; } + cardp->fw = fw; if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) { ret = -EINVAL; goto release_fw; @@ -1053,7 +868,7 @@ static int __if_usb_prog_firmware(struct if_usb_card *cardp, do { int j = 0; i++; - if_usb_issue_boot_command(cardp, cmd); + if_usb_issue_boot_command(cardp, BOOT_CMD_FW_BY_USB); /* wait for command response */ do { j++; @@ -1109,13 +924,27 @@ static int __if_usb_prog_firmware(struct if_usb_card *cardp, goto release_fw; } + cardp->priv->fw_ready = 1; + if_usb_submit_rx_urb(cardp); + + if (lbs_start_card(priv)) + goto release_fw; + + if_usb_setup_firmware(priv); + + /* + * EHS_REMOVE_WAKEUP is not supported on all versions of the firmware. + */ + priv->wol_criteria = EHS_REMOVE_WAKEUP; + if (lbs_host_sleep_cfg(priv, priv->wol_criteria, NULL)) + priv->ehs_remove_supported = false; + release_fw: release_firmware(cardp->fw); cardp->fw = NULL; done: - lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret); - return ret; + lbs_deb_leave(LBS_DEB_USB); } @@ -1128,8 +957,10 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) lbs_deb_enter(LBS_DEB_USB); - if (priv->psstate != PS_STATE_FULL_POWER) - return -1; + if (priv->psstate != PS_STATE_FULL_POWER) { + ret = -1; + goto out; + } #ifdef CONFIG_OLPC if (machine_is_olpc()) { @@ -1180,6 +1011,7 @@ static struct usb_driver if_usb_driver = { .suspend = if_usb_suspend, .resume = if_usb_resume, .reset_resume = if_usb_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(if_usb_driver); diff --git a/trunk/drivers/net/wireless/libertas/main.c b/trunk/drivers/net/wireless/libertas/main.c index 957681dede17..e96ee0aa8439 100644 --- a/trunk/drivers/net/wireless/libertas/main.c +++ b/trunk/drivers/net/wireless/libertas/main.c @@ -878,6 +878,7 @@ static int lbs_init_adapter(struct lbs_private *priv) priv->is_host_sleep_configured = 0; priv->is_host_sleep_activated = 0; init_waitqueue_head(&priv->host_sleep_q); + init_waitqueue_head(&priv->fw_waitq); mutex_init(&priv->lock); setup_timer(&priv->command_timer, lbs_cmd_timeout_handler, @@ -1033,7 +1034,11 @@ void lbs_remove_card(struct lbs_private *priv) lbs_deb_enter(LBS_DEB_MAIN); lbs_remove_mesh(priv); - lbs_scan_deinit(priv); + + if (priv->wiphy_registered) + lbs_scan_deinit(priv); + + lbs_wait_for_firmware_load(priv); /* worker thread destruction blocks on the in-flight command which * should have been cleared already in lbs_stop_card(). @@ -1128,6 +1133,11 @@ void lbs_stop_card(struct lbs_private *priv) goto out; dev = priv->dev; + /* If the netdev isn't registered, it means that lbs_start_card() was + * never called so we have nothing to do here. */ + if (dev->reg_state != NETREG_REGISTERED) + goto out; + netif_stop_queue(dev); netif_carrier_off(dev); @@ -1177,111 +1187,6 @@ void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx) } EXPORT_SYMBOL_GPL(lbs_notify_command_response); -/** - * lbs_get_firmware - Retrieves two-stage firmware - * - * @dev: A pointer to &device structure - * @user_helper: User-defined helper firmware file - * @user_mainfw: User-defined main firmware file - * @card_model: Bus-specific card model ID used to filter firmware table - * elements - * @fw_table: Table of firmware file names and device model numbers - * terminated by an entry with a NULL helper name - * @helper: On success, the helper firmware; caller must free - * @mainfw: On success, the main firmware; caller must free - * - * returns: 0 on success, non-zero on failure - */ -int lbs_get_firmware(struct device *dev, const char *user_helper, - const char *user_mainfw, u32 card_model, - const struct lbs_fw_table *fw_table, - const struct firmware **helper, - const struct firmware **mainfw) -{ - const struct lbs_fw_table *iter; - int ret; - - BUG_ON(helper == NULL); - BUG_ON(mainfw == NULL); - - /* Try user-specified firmware first */ - if (user_helper) { - ret = request_firmware(helper, user_helper, dev); - if (ret) { - dev_err(dev, "couldn't find helper firmware %s\n", - user_helper); - goto fail; - } - } - if (user_mainfw) { - ret = request_firmware(mainfw, user_mainfw, dev); - if (ret) { - dev_err(dev, "couldn't find main firmware %s\n", - user_mainfw); - goto fail; - } - } - - if (*helper && *mainfw) - return 0; - - /* Otherwise search for firmware to use. If neither the helper or - * the main firmware were specified by the user, then we need to - * make sure that found helper & main are from the same entry in - * fw_table. - */ - iter = fw_table; - while (iter && iter->helper) { - if (iter->model != card_model) - goto next; - - if (*helper == NULL) { - ret = request_firmware(helper, iter->helper, dev); - if (ret) - goto next; - - /* If the device has one-stage firmware (ie cf8305) and - * we've got it then we don't need to bother with the - * main firmware. - */ - if (iter->fwname == NULL) - return 0; - } - - if (*mainfw == NULL) { - ret = request_firmware(mainfw, iter->fwname, dev); - if (ret && !user_helper) { - /* Clear the helper if it wasn't user-specified - * and the main firmware load failed, to ensure - * we don't have mismatched firmware pairs. - */ - release_firmware(*helper); - *helper = NULL; - } - } - - if (*helper && *mainfw) - return 0; - - next: - iter++; - } - - fail: - /* Failed */ - if (*helper) { - release_firmware(*helper); - *helper = NULL; - } - if (*mainfw) { - release_firmware(*mainfw); - *mainfw = NULL; - } - - return -ENOENT; -} -EXPORT_SYMBOL_GPL(lbs_get_firmware); - static int __init lbs_init_module(void) { lbs_deb_enter(LBS_DEB_MAIN); diff --git a/trunk/drivers/net/wireless/libertas_tf/if_usb.c b/trunk/drivers/net/wireless/libertas_tf/if_usb.c index 7ced130f4f9e..19a5a92dd779 100644 --- a/trunk/drivers/net/wireless/libertas_tf/if_usb.c +++ b/trunk/drivers/net/wireless/libertas_tf/if_usb.c @@ -920,6 +920,7 @@ static struct usb_driver if_usb_driver = { .id_table = if_usb_table, .suspend = if_usb_suspend, .resume = if_usb_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(if_usb_driver); diff --git a/trunk/drivers/net/wireless/mac80211_hwsim.c b/trunk/drivers/net/wireless/mac80211_hwsim.c index b7ce6a6e355f..03c0c6b1372c 100644 --- a/trunk/drivers/net/wireless/mac80211_hwsim.c +++ b/trunk/drivers/net/wireless/mac80211_hwsim.c @@ -582,11 +582,13 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, goto nla_put_failure; } - NLA_PUT(skb, HWSIM_ATTR_ADDR_TRANSMITTER, - sizeof(struct mac_address), data->addresses[1].addr); + if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, + sizeof(struct mac_address), data->addresses[1].addr)) + goto nla_put_failure; /* We get the skb->data */ - NLA_PUT(skb, HWSIM_ATTR_FRAME, my_skb->len, my_skb->data); + if (nla_put(skb, HWSIM_ATTR_FRAME, my_skb->len, my_skb->data)) + goto nla_put_failure; /* We get the flags for this transmission, and we translate them to wmediumd flags */ @@ -597,7 +599,8 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, if (info->flags & IEEE80211_TX_CTL_NO_ACK) hwsim_flags |= HWSIM_TX_CTL_NO_ACK; - NLA_PUT_U32(skb, HWSIM_ATTR_FLAGS, hwsim_flags); + if (nla_put_u32(skb, HWSIM_ATTR_FLAGS, hwsim_flags)) + goto nla_put_failure; /* We get the tx control (rate and retries) info*/ @@ -606,12 +609,14 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, tx_attempts[i].count = info->status.rates[i].count; } - NLA_PUT(skb, HWSIM_ATTR_TX_INFO, - sizeof(struct hwsim_tx_rate)*IEEE80211_TX_MAX_RATES, - tx_attempts); + if (nla_put(skb, HWSIM_ATTR_TX_INFO, + sizeof(struct hwsim_tx_rate)*IEEE80211_TX_MAX_RATES, + tx_attempts)) + goto nla_put_failure; /* We create a cookie to identify this skb */ - NLA_PUT_U64(skb, HWSIM_ATTR_COOKIE, (unsigned long) my_skb); + if (nla_put_u64(skb, HWSIM_ATTR_COOKIE, (unsigned long) my_skb)) + goto nla_put_failure; genlmsg_end(skb, msg_head); genlmsg_unicast(&init_net, skb, dst_pid); @@ -632,6 +637,7 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_rx_status rx_status; + struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info); if (data->idle) { wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n"); @@ -666,6 +672,7 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, spin_lock(&hwsim_radio_lock); list_for_each_entry(data2, &hwsim_radios, list) { struct sk_buff *nskb; + struct ieee80211_mgmt *mgmt; if (data == data2) continue; @@ -683,8 +690,18 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, if (mac80211_hwsim_addr_match(data2, hdr->addr1)) ack = true; + + /* set bcn timestamp relative to receiver mactime */ rx_status.mactime = - le64_to_cpu(__mac80211_hwsim_get_tsf(data2)); + le64_to_cpu(__mac80211_hwsim_get_tsf(data2)); + mgmt = (struct ieee80211_mgmt *) nskb->data; + if (ieee80211_is_beacon(mgmt->frame_control) || + ieee80211_is_probe_resp(mgmt->frame_control)) + mgmt->u.beacon.timestamp = cpu_to_le64( + rx_status.mactime + + (data->tsf_offset - data2->tsf_offset) + + 24 * 8 * 10 / txrate->bitrate); + memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status)); ieee80211_rx_irqsafe(data2->hw, nskb); } @@ -698,12 +715,6 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) bool ack; struct ieee80211_tx_info *txi; u32 _pid; - struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) skb->data; - struct mac80211_hwsim_data *data = hw->priv; - - if (ieee80211_is_beacon(mgmt->frame_control) || - ieee80211_is_probe_resp(mgmt->frame_control)) - mgmt->u.beacon.timestamp = __mac80211_hwsim_get_tsf(data); mac80211_hwsim_monitor_rx(hw, skb); @@ -800,11 +811,9 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, struct ieee80211_vif *vif) { struct ieee80211_hw *hw = arg; - struct mac80211_hwsim_data *data = hw->priv; struct sk_buff *skb; struct ieee80211_tx_info *info; u32 _pid; - struct ieee80211_mgmt *mgmt; hwsim_check_magic(vif); @@ -818,9 +827,6 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, return; info = IEEE80211_SKB_CB(skb); - mgmt = (struct ieee80211_mgmt *) skb->data; - mgmt->u.beacon.timestamp = __mac80211_hwsim_get_tsf(data); - mac80211_hwsim_monitor_rx(hw, skb); /* wmediumd mode check */ @@ -1108,7 +1114,8 @@ static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw, nla_total_size(sizeof(u32))); if (!skb) return -ENOMEM; - NLA_PUT_U32(skb, HWSIM_TM_ATTR_PS, hwsim->ps); + if (nla_put_u32(skb, HWSIM_TM_ATTR_PS, hwsim->ps)) + goto nla_put_failure; return cfg80211_testmode_reply(skb); default: return -EOPNOTSUPP; @@ -1444,7 +1451,7 @@ DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_group, hwsim_fops_group_read, hwsim_fops_group_write, "%llx\n"); -struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr( +static struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr( struct mac_address *addr) { struct mac80211_hwsim_data *data; @@ -1789,9 +1796,11 @@ static int __init init_mac80211_hwsim(void) IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_STATIC_SMPS | IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | - IEEE80211_HW_AMPDU_AGGREGATION; + IEEE80211_HW_AMPDU_AGGREGATION | + IEEE80211_HW_WANT_MONITOR_VIF; - hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; + hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | + WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; /* ask mac80211 to reserve space for magic */ hw->vif_data_size = sizeof(struct hwsim_vif_priv); diff --git a/trunk/drivers/net/wireless/mwifiex/11n.c b/trunk/drivers/net/wireless/mwifiex/11n.c index a5e182b5e944..fe8ebfebcc0e 100644 --- a/trunk/drivers/net/wireless/mwifiex/11n.c +++ b/trunk/drivers/net/wireless/mwifiex/11n.c @@ -350,25 +350,26 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, ret_len += sizeof(struct mwifiex_ie_types_htcap); } - if (bss_desc->bcn_ht_info) { + if (bss_desc->bcn_ht_oper) { if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { ht_info = (struct mwifiex_ie_types_htinfo *) *buffer; memset(ht_info, 0, sizeof(struct mwifiex_ie_types_htinfo)); ht_info->header.type = - cpu_to_le16(WLAN_EID_HT_INFORMATION); + cpu_to_le16(WLAN_EID_HT_OPERATION); ht_info->header.len = - cpu_to_le16(sizeof(struct ieee80211_ht_info)); + cpu_to_le16( + sizeof(struct ieee80211_ht_operation)); memcpy((u8 *) ht_info + sizeof(struct mwifiex_ie_types_header), - (u8 *) bss_desc->bcn_ht_info + + (u8 *) bss_desc->bcn_ht_oper + sizeof(struct ieee_types_header), le16_to_cpu(ht_info->header.len)); if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) - ht_info->ht_info.ht_param &= + ht_info->ht_oper.ht_param &= ~(IEEE80211_HT_PARAM_CHAN_WIDTH_ANY | IEEE80211_HT_PARAM_CHA_SEC_OFFSET); @@ -385,16 +386,16 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, sizeof(struct mwifiex_ie_types_chan_list_param_set) - sizeof(struct mwifiex_ie_types_header)); chan_list->chan_scan_param[0].chan_number = - bss_desc->bcn_ht_info->control_chan; + bss_desc->bcn_ht_oper->primary_chan; chan_list->chan_scan_param[0].radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band); if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 && - bss_desc->bcn_ht_info->ht_param & + bss_desc->bcn_ht_oper->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY) SET_SECONDARYCHAN(chan_list->chan_scan_param[0]. radio_type, - (bss_desc->bcn_ht_info->ht_param & + (bss_desc->bcn_ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET)); *buffer += sizeof(struct mwifiex_ie_types_chan_list_param_set); diff --git a/trunk/drivers/net/wireless/mwifiex/11n_aggr.c b/trunk/drivers/net/wireless/mwifiex/11n_aggr.c index 9eefb2a0ce9f..ab84eb943749 100644 --- a/trunk/drivers/net/wireless/mwifiex/11n_aggr.c +++ b/trunk/drivers/net/wireless/mwifiex/11n_aggr.c @@ -233,21 +233,27 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, skb_push(skb_aggr, headroom); - /* - * 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; - - ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, - skb_aggr, &tx_param); + if (adapter->iface_type == MWIFIEX_USB) { + adapter->data_sent = true; + 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; + + ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, + skb_aggr, &tx_param); + } switch (ret) { case -EBUSY: spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); diff --git a/trunk/drivers/net/wireless/mwifiex/Kconfig b/trunk/drivers/net/wireless/mwifiex/Kconfig index 2a078cea830a..8e384fae3e68 100644 --- a/trunk/drivers/net/wireless/mwifiex/Kconfig +++ b/trunk/drivers/net/wireless/mwifiex/Kconfig @@ -10,12 +10,12 @@ config MWIFIEX mwifiex. config MWIFIEX_SDIO - tristate "Marvell WiFi-Ex Driver for SD8787/SD8797" + tristate "Marvell WiFi-Ex Driver for SD8786/SD8787/SD8797" depends on MWIFIEX && MMC select FW_LOADER ---help--- This adds support for wireless adapters based on Marvell - 8787/8797 chipsets with SDIO interface. + 8786/8787/8797 chipsets with SDIO interface. If you choose to build it as a module, it will be called mwifiex_sdio. @@ -30,3 +30,14 @@ config MWIFIEX_PCIE If you choose to build it as a module, it will be called mwifiex_pcie. + +config MWIFIEX_USB + tristate "Marvell WiFi-Ex Driver for USB8797" + depends on MWIFIEX && USB + select FW_LOADER + ---help--- + This adds support for wireless adapters based on Marvell + Avastar 88W8797 chipset with USB interface. + + If you choose to build it as a module, it will be called + mwifiex_usb. diff --git a/trunk/drivers/net/wireless/mwifiex/Makefile b/trunk/drivers/net/wireless/mwifiex/Makefile index b0257ad1bbed..5c1a46bf1e11 100644 --- a/trunk/drivers/net/wireless/mwifiex/Makefile +++ b/trunk/drivers/net/wireless/mwifiex/Makefile @@ -42,3 +42,6 @@ obj-$(CONFIG_MWIFIEX_SDIO) += mwifiex_sdio.o mwifiex_pcie-y += pcie.o obj-$(CONFIG_MWIFIEX_PCIE) += mwifiex_pcie.o + +mwifiex_usb-y += usb.o +obj-$(CONFIG_MWIFIEX_USB) += mwifiex_usb.o diff --git a/trunk/drivers/net/wireless/mwifiex/cfg80211.c b/trunk/drivers/net/wireless/mwifiex/cfg80211.c index 65050384c42b..c78ea873a63a 100644 --- a/trunk/drivers/net/wireless/mwifiex/cfg80211.c +++ b/trunk/drivers/net/wireless/mwifiex/cfg80211.c @@ -516,25 +516,23 @@ static int mwifiex_dump_station_info(struct mwifiex_private *priv, struct station_info *sinfo) { - struct mwifiex_ds_get_signal signal; struct mwifiex_rate_cfg rate; - int ret = 0; sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES | - STATION_INFO_RX_PACKETS | - STATION_INFO_TX_PACKETS - | STATION_INFO_SIGNAL | STATION_INFO_TX_BITRATE; + STATION_INFO_RX_PACKETS | STATION_INFO_TX_PACKETS | + STATION_INFO_TX_BITRATE | + STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; /* Get signal information from the firmware */ - memset(&signal, 0, sizeof(struct mwifiex_ds_get_signal)); - if (mwifiex_get_signal_info(priv, &signal)) { - dev_err(priv->adapter->dev, "getting signal information\n"); - ret = -EFAULT; + if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_RSSI_INFO, + HostCmd_ACT_GEN_GET, 0, NULL)) { + dev_err(priv->adapter->dev, "failed to get signal information\n"); + return -EFAULT; } if (mwifiex_drv_get_data_rate(priv, &rate)) { dev_err(priv->adapter->dev, "getting data rate\n"); - ret = -EFAULT; + return -EFAULT; } /* Get DTIM period information from firmware */ @@ -557,11 +555,12 @@ mwifiex_dump_station_info(struct mwifiex_private *priv, sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; } + sinfo->signal_avg = priv->bcn_rssi_avg; sinfo->rx_bytes = priv->stats.rx_bytes; sinfo->tx_bytes = priv->stats.tx_bytes; sinfo->rx_packets = priv->stats.rx_packets; sinfo->tx_packets = priv->stats.tx_packets; - sinfo->signal = priv->qual_level; + sinfo->signal = priv->bcn_rssi_avg; /* bit rate is in 500 kb/s units. Convert it to 100kb/s units */ sinfo->txrate.legacy = rate.rate * 5; @@ -581,7 +580,7 @@ mwifiex_dump_station_info(struct mwifiex_private *priv, priv->curr_bss_params.bss_descriptor.beacon_period; } - return ret; + return 0; } /* @@ -604,6 +603,23 @@ mwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, return mwifiex_dump_station_info(priv, sinfo); } +/* + * CFG802.11 operation handler to dump station information. + */ +static int +mwifiex_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *dev, + int idx, u8 *mac, struct station_info *sinfo) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + if (!priv->media_connected || idx) + return -ENOENT; + + memcpy(mac, priv->cfg_bssid, ETH_ALEN); + + return mwifiex_dump_station_info(priv, sinfo); +} + /* Supported rates to be advertised to the cfg80211 */ static struct ieee80211_rate mwifiex_rates[] = { @@ -749,6 +765,45 @@ static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy, return 0; } +/* + * CFG802.11 operation handler for connection quality monitoring. + * + * This function subscribes/unsubscribes HIGH_RSSI and LOW_RSSI + * events to FW. + */ +static int mwifiex_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy, + struct net_device *dev, + s32 rssi_thold, u32 rssi_hyst) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + struct mwifiex_ds_misc_subsc_evt subsc_evt; + + priv->cqm_rssi_thold = rssi_thold; + priv->cqm_rssi_hyst = rssi_hyst; + + memset(&subsc_evt, 0x00, sizeof(struct mwifiex_ds_misc_subsc_evt)); + subsc_evt.events = BITMASK_BCN_RSSI_LOW | BITMASK_BCN_RSSI_HIGH; + + /* Subscribe/unsubscribe low and high rssi events */ + if (rssi_thold && rssi_hyst) { + subsc_evt.action = HostCmd_ACT_BITWISE_SET; + subsc_evt.bcn_l_rssi_cfg.abs_value = abs(rssi_thold); + subsc_evt.bcn_h_rssi_cfg.abs_value = abs(rssi_thold); + subsc_evt.bcn_l_rssi_cfg.evt_freq = 1; + subsc_evt.bcn_h_rssi_cfg.evt_freq = 1; + return mwifiex_send_cmd_sync(priv, + HostCmd_CMD_802_11_SUBSCRIBE_EVENT, + 0, 0, &subsc_evt); + } else { + subsc_evt.action = HostCmd_ACT_BITWISE_CLR; + return mwifiex_send_cmd_sync(priv, + HostCmd_CMD_802_11_SUBSCRIBE_EVENT, + 0, 0, &subsc_evt); + } + + return 0; +} + /* * CFG802.11 operation handler for disconnection request. * @@ -1107,6 +1162,17 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev, priv->user_scan_cfg->num_ssids = request->n_ssids; priv->user_scan_cfg->ssid_list = request->ssids; + if (request->ie && request->ie_len) { + for (i = 0; i < MWIFIEX_MAX_VSIE_NUM; i++) { + if (priv->vs_ie[i].mask != MWIFIEX_VSIE_MASK_CLEAR) + continue; + priv->vs_ie[i].mask = MWIFIEX_VSIE_MASK_SCAN; + memcpy(&priv->vs_ie[i].ie, request->ie, + request->ie_len); + break; + } + } + for (i = 0; i < request->n_channels; i++) { chan = request->channels[i]; priv->user_scan_cfg->chan_list[i].chan_number = chan->hw_value; @@ -1124,6 +1190,15 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev, if (mwifiex_set_user_scan_ioctl(priv, priv->user_scan_cfg)) return -EFAULT; + if (request->ie && request->ie_len) { + for (i = 0; i < MWIFIEX_MAX_VSIE_NUM; i++) { + if (priv->vs_ie[i].mask == MWIFIEX_VSIE_MASK_SCAN) { + priv->vs_ie[i].mask = MWIFIEX_VSIE_MASK_CLEAR; + memset(&priv->vs_ie[i].ie, 0, + MWIFIEX_MAX_VSIE_LEN); + } + } + } return 0; } @@ -1340,6 +1415,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { .connect = mwifiex_cfg80211_connect, .disconnect = mwifiex_cfg80211_disconnect, .get_station = mwifiex_cfg80211_get_station, + .dump_station = mwifiex_cfg80211_dump_station, .set_wiphy_params = mwifiex_cfg80211_set_wiphy_params, .set_channel = mwifiex_cfg80211_set_channel, .join_ibss = mwifiex_cfg80211_join_ibss, @@ -1350,6 +1426,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { .set_power_mgmt = mwifiex_cfg80211_set_power_mgmt, .set_tx_power = mwifiex_cfg80211_set_tx_power, .set_bitrate_mask = mwifiex_cfg80211_set_bitrate_mask, + .set_cqm_rssi_config = mwifiex_cfg80211_set_cqm_rssi_config, }; /* @@ -1365,6 +1442,7 @@ int mwifiex_register_cfg80211(struct mwifiex_private *priv) void *wdev_priv; struct wireless_dev *wdev; struct ieee80211_sta_ht_cap *ht_info; + u8 *country_code; wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); if (!wdev) { @@ -1381,6 +1459,7 @@ int mwifiex_register_cfg80211(struct mwifiex_private *priv) } wdev->iftype = NL80211_IFTYPE_STATION; wdev->wiphy->max_scan_ssids = 10; + wdev->wiphy->max_scan_ie_len = MWIFIEX_MAX_VSIE_LEN; wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); @@ -1403,8 +1482,8 @@ int mwifiex_register_cfg80211(struct mwifiex_private *priv) memcpy(wdev->wiphy->perm_addr, priv->curr_addr, ETH_ALEN); wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; - /* Reserve space for bss band information */ - wdev->wiphy->bss_priv_size = sizeof(u8); + /* Reserve space for mwifiex specific private data for BSS */ + wdev->wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv); wdev->wiphy->reg_notifier = mwifiex_reg_notifier; @@ -1427,6 +1506,11 @@ int mwifiex_register_cfg80211(struct mwifiex_private *priv) "info: successfully registered wiphy device\n"); } + country_code = mwifiex_11d_code_2_region(priv->adapter->region_code); + if (country_code && regulatory_hint(wdev->wiphy, country_code)) + dev_err(priv->adapter->dev, + "%s: regulatory_hint failed\n", __func__); + priv->wdev = wdev; return ret; diff --git a/trunk/drivers/net/wireless/mwifiex/cfp.c b/trunk/drivers/net/wireless/mwifiex/cfp.c index 2fe1c33765b8..560871b0e236 100644 --- a/trunk/drivers/net/wireless/mwifiex/cfp.c +++ b/trunk/drivers/net/wireless/mwifiex/cfp.c @@ -71,6 +71,37 @@ u16 region_code_index[MWIFIEX_MAX_REGION_CODE] = { 0x10, 0x20, 0x30, static u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 }; +struct region_code_mapping { + u8 code; + u8 region[IEEE80211_COUNTRY_STRING_LEN]; +}; + +static struct region_code_mapping region_code_mapping_t[] = { + { 0x10, "US " }, /* US FCC */ + { 0x20, "CA " }, /* IC Canada */ + { 0x30, "EU " }, /* ETSI */ + { 0x31, "ES " }, /* Spain */ + { 0x32, "FR " }, /* France */ + { 0x40, "JP " }, /* Japan */ + { 0x41, "JP " }, /* Japan */ + { 0x50, "CN " }, /* China */ +}; + +/* This function converts integer code to region string */ +u8 *mwifiex_11d_code_2_region(u8 code) +{ + u8 i; + u8 size = sizeof(region_code_mapping_t)/ + sizeof(struct region_code_mapping); + + /* Look for code in mapping table */ + for (i = 0; i < size; i++) + if (region_code_mapping_t[i].code == code) + return region_code_mapping_t[i].region; + + return NULL; +} + /* * This function maps an index in supported rates table into * the corresponding data rate. diff --git a/trunk/drivers/net/wireless/mwifiex/cmdevt.c b/trunk/drivers/net/wireless/mwifiex/cmdevt.c index 07f6e0092552..1710beffb93a 100644 --- a/trunk/drivers/net/wireless/mwifiex/cmdevt.c +++ b/trunk/drivers/net/wireless/mwifiex/cmdevt.c @@ -139,6 +139,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, uint16_t cmd_size; struct timeval tstamp; unsigned long flags; + __le32 tmp; if (!adapter || !cmd_node) return -1; @@ -178,15 +179,28 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, le16_to_cpu(*(__le16 *) ((u8 *) host_cmd + S_DS_GEN)), cmd_size, le16_to_cpu(host_cmd->seq_num)); - skb_push(cmd_node->cmd_skb, INTF_HEADER_LEN); - - ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD, - cmd_node->cmd_skb, NULL); - - skb_pull(cmd_node->cmd_skb, INTF_HEADER_LEN); + if (adapter->iface_type == MWIFIEX_USB) { + tmp = cpu_to_le32(MWIFIEX_USB_TYPE_CMD); + skb_push(cmd_node->cmd_skb, MWIFIEX_TYPE_LEN); + memcpy(cmd_node->cmd_skb->data, &tmp, MWIFIEX_TYPE_LEN); + adapter->cmd_sent = true; + ret = adapter->if_ops.host_to_card(adapter, + MWIFIEX_USB_EP_CMD_EVENT, + cmd_node->cmd_skb, NULL); + skb_pull(cmd_node->cmd_skb, MWIFIEX_TYPE_LEN); + if (ret == -EBUSY) + cmd_node->cmd_skb = NULL; + } else { + skb_push(cmd_node->cmd_skb, INTF_HEADER_LEN); + ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD, + cmd_node->cmd_skb, NULL); + skb_pull(cmd_node->cmd_skb, INTF_HEADER_LEN); + } if (ret == -1) { dev_err(adapter->dev, "DNLD_CMD: host to card failed\n"); + if (adapter->iface_type == MWIFIEX_USB) + adapter->cmd_sent = false; if (cmd_node->wait_q_enabled) adapter->cmd_wait_q.status = -1; mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); @@ -232,6 +246,9 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter) struct mwifiex_opt_sleep_confirm *sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm *) adapter->sleep_cfm->data; + struct sk_buff *sleep_cfm_tmp; + __le32 tmp; + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); sleep_cfm_buf->seq_num = @@ -240,10 +257,28 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter) priv->bss_type))); adapter->seq_num++; - skb_push(adapter->sleep_cfm, INTF_HEADER_LEN); - ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD, - adapter->sleep_cfm, NULL); - skb_pull(adapter->sleep_cfm, INTF_HEADER_LEN); + if (adapter->iface_type == MWIFIEX_USB) { + sleep_cfm_tmp = + dev_alloc_skb(sizeof(struct mwifiex_opt_sleep_confirm) + + MWIFIEX_TYPE_LEN); + skb_put(sleep_cfm_tmp, sizeof(struct mwifiex_opt_sleep_confirm) + + MWIFIEX_TYPE_LEN); + tmp = cpu_to_le32(MWIFIEX_USB_TYPE_CMD); + memcpy(sleep_cfm_tmp->data, &tmp, MWIFIEX_TYPE_LEN); + memcpy(sleep_cfm_tmp->data + MWIFIEX_TYPE_LEN, + adapter->sleep_cfm->data, + sizeof(struct mwifiex_opt_sleep_confirm)); + ret = adapter->if_ops.host_to_card(adapter, + MWIFIEX_USB_EP_CMD_EVENT, + sleep_cfm_tmp, NULL); + if (ret != -EBUSY) + dev_kfree_skb_any(sleep_cfm_tmp); + } else { + skb_push(adapter->sleep_cfm, INTF_HEADER_LEN); + ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD, + adapter->sleep_cfm, NULL); + skb_pull(adapter->sleep_cfm, INTF_HEADER_LEN); + } if (ret == -1) { dev_err(adapter->dev, "SLEEP_CFM: failed\n"); @@ -343,7 +378,12 @@ int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter) } if (!cmd_array[i].resp_skb) continue; - dev_kfree_skb_any(cmd_array[i].resp_skb); + + if (adapter->iface_type == MWIFIEX_USB) + adapter->if_ops.cmdrsp_complete(adapter, + cmd_array[i].resp_skb); + else + dev_kfree_skb_any(cmd_array[i].resp_skb); } /* Release struct cmd_ctrl_node */ if (adapter->cmd_pool) { @@ -1083,6 +1123,7 @@ mwifiex_process_hs_config(struct mwifiex_adapter *adapter) MWIFIEX_BSS_ROLE_ANY), false); } +EXPORT_SYMBOL_GPL(mwifiex_process_hs_config); /* * This function handles the command response of a sleep confirm command. diff --git a/trunk/drivers/net/wireless/mwifiex/debugfs.c b/trunk/drivers/net/wireless/mwifiex/debugfs.c index 1a845074c52a..a870b5885c09 100644 --- a/trunk/drivers/net/wireless/mwifiex/debugfs.c +++ b/trunk/drivers/net/wireless/mwifiex/debugfs.c @@ -212,7 +212,7 @@ mwifiex_info_read(struct file *file, char __user *ubuf, p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid); p += sprintf(p, "bssid=\"%pM\"\n", info.bssid); p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan); - p += sprintf(p, "region_code = \"%02x\"\n", info.region_code); + p += sprintf(p, "country_code = \"%s\"\n", info.country_code); netdev_for_each_mc_addr(ha, netdev) p += sprintf(p, "multicast_address[%d]=\"%pM\"\n", diff --git a/trunk/drivers/net/wireless/mwifiex/decl.h b/trunk/drivers/net/wireless/mwifiex/decl.h index be5fd1652e53..d04aba4131dc 100644 --- a/trunk/drivers/net/wireless/mwifiex/decl.h +++ b/trunk/drivers/net/wireless/mwifiex/decl.h @@ -53,6 +53,7 @@ #define MWIFIEX_RATE_BITMAP_MCS127 159 #define MWIFIEX_RX_DATA_BUF_SIZE (4 * 1024) +#define MWIFIEX_RX_CMD_BUF_SIZE (2 * 1024) #define MWIFIEX_RTS_MIN_VALUE (0) #define MWIFIEX_RTS_MAX_VALUE (2347) diff --git a/trunk/drivers/net/wireless/mwifiex/fw.h b/trunk/drivers/net/wireless/mwifiex/fw.h index e98fc5af73dc..5f6adeb9b950 100644 --- a/trunk/drivers/net/wireless/mwifiex/fw.h +++ b/trunk/drivers/net/wireless/mwifiex/fw.h @@ -81,6 +81,11 @@ enum KEY_TYPE_ID { #define FIRMWARE_READY_SDIO 0xfedc #define FIRMWARE_READY_PCIE 0xfedcba00 +enum mwifiex_usb_ep { + MWIFIEX_USB_EP_CMD_EVENT = 1, + MWIFIEX_USB_EP_DATA = 2, +}; + enum MWIFIEX_802_11_PRIVACY_FILTER { MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL, MWIFIEX_802_11_PRIV_FILTER_8021X_WEP @@ -92,16 +97,19 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0) #define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 1) #define TLV_TYPE_NUMPROBES (PROPRIETARY_TLV_BASE_ID + 2) +#define TLV_TYPE_RSSI_LOW (PROPRIETARY_TLV_BASE_ID + 4) #define TLV_TYPE_PASSTHROUGH (PROPRIETARY_TLV_BASE_ID + 10) #define TLV_TYPE_WMMQSTATUS (PROPRIETARY_TLV_BASE_ID + 16) #define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 18) #define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19) +#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22) #define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31) #define TLV_TYPE_CHANNELBANDLIST (PROPRIETARY_TLV_BASE_ID + 42) #define TLV_TYPE_RATE_DROP_CONTROL (PROPRIETARY_TLV_BASE_ID + 82) #define TLV_TYPE_RATE_SCOPE (PROPRIETARY_TLV_BASE_ID + 83) #define TLV_TYPE_POWER_GROUP (PROPRIETARY_TLV_BASE_ID + 84) #define TLV_TYPE_WAPI_IE (PROPRIETARY_TLV_BASE_ID + 94) +#define TLV_TYPE_MGMT_IE (PROPRIETARY_TLV_BASE_ID + 105) #define TLV_TYPE_AUTO_DS_PARAM (PROPRIETARY_TLV_BASE_ID + 113) #define TLV_TYPE_PS_PARAM (PROPRIETARY_TLV_BASE_ID + 114) @@ -194,6 +202,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define HostCmd_CMD_802_11_KEY_MATERIAL 0x005e #define HostCmd_CMD_802_11_BG_SCAN_QUERY 0x006c #define HostCmd_CMD_WMM_GET_STATUS 0x0071 +#define HostCmd_CMD_802_11_SUBSCRIBE_EVENT 0x0075 #define HostCmd_CMD_802_11_TX_RATE_QUERY 0x007f #define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS 0x0083 #define HostCmd_CMD_VERSION_EXT 0x0097 @@ -228,6 +237,8 @@ enum ENH_PS_MODES { #define HostCmd_RET_BIT 0x8000 #define HostCmd_ACT_GEN_GET 0x0000 #define HostCmd_ACT_GEN_SET 0x0001 +#define HostCmd_ACT_BITWISE_SET 0x0002 +#define HostCmd_ACT_BITWISE_CLR 0x0003 #define HostCmd_RESULT_OK 0x0000 #define HostCmd_ACT_MAC_RX_ON 0x0001 @@ -813,7 +824,7 @@ struct host_cmd_ds_txpwr_cfg { struct mwifiex_bcn_param { u8 bssid[ETH_ALEN]; u8 rssi; - __le32 timestamp[2]; + __le64 timestamp; __le16 beacon_period; __le16 cap_info_bitmap; } __packed; @@ -982,8 +993,7 @@ struct mwifiex_ie_types_wmm_queue_status { struct ieee_types_vendor_header { u8 element_id; u8 len; - u8 oui[3]; - u8 oui_type; + u8 oui[4]; /* 0~2: oui, 3: oui_type */ u8 oui_subtype; u8 version; } __packed; @@ -1007,7 +1017,7 @@ struct ieee_types_wmm_parameter { struct ieee_types_vendor_header vend_hdr; u8 qos_info_bitmap; u8 reserved; - struct ieee_types_wmm_ac_parameters ac_params[IEEE80211_MAX_QUEUES]; + struct ieee_types_wmm_ac_parameters ac_params[IEEE80211_NUM_ACS]; } __packed; struct ieee_types_wmm_info { @@ -1028,7 +1038,7 @@ struct ieee_types_wmm_info { struct host_cmd_ds_wmm_get_status { u8 queue_status_tlv[sizeof(struct mwifiex_ie_types_wmm_queue_status) * - IEEE80211_MAX_QUEUES]; + IEEE80211_NUM_ACS]; u8 wmm_param_tlv[sizeof(struct ieee_types_wmm_parameter) + 2]; } __packed; @@ -1045,7 +1055,7 @@ struct mwifiex_ie_types_htcap { struct mwifiex_ie_types_htinfo { struct mwifiex_ie_types_header header; - struct ieee80211_ht_info ht_info; + struct ieee80211_ht_operation ht_oper; } __packed; struct mwifiex_ie_types_2040bssco { @@ -1146,6 +1156,17 @@ struct host_cmd_ds_pcie_details { u32 sleep_cookie_addr_hi; } __packed; +struct mwifiex_ie_types_rssi_threshold { + struct mwifiex_ie_types_header header; + u8 abs_value; + u8 evt_freq; +} __packed; + +struct host_cmd_ds_802_11_subsc_evt { + __le16 action; + __le16 events; +} __packed; + struct host_cmd_ds_command { __le16 command; __le16 size; @@ -1195,6 +1216,7 @@ struct host_cmd_ds_command { struct host_cmd_ds_set_bss_mode bss_mode; struct host_cmd_ds_pcie_details pcie_host_spec; struct host_cmd_ds_802_11_eeprom_access eeprom; + struct host_cmd_ds_802_11_subsc_evt subsc_evt; } params; } __packed; diff --git a/trunk/drivers/net/wireless/mwifiex/init.c b/trunk/drivers/net/wireless/mwifiex/init.c index 54bb4839b57c..d440c3eb640b 100644 --- a/trunk/drivers/net/wireless/mwifiex/init.c +++ b/trunk/drivers/net/wireless/mwifiex/init.c @@ -131,6 +131,8 @@ static int mwifiex_init_priv(struct mwifiex_private *priv) priv->wmm_qosinfo = 0; priv->curr_bcn_buf = NULL; priv->curr_bcn_size = 0; + priv->wps_ie = NULL; + priv->wps_ie_len = 0; priv->scan_block = false; @@ -186,10 +188,10 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) adapter->cmd_sent = false; - if (adapter->iface_type == MWIFIEX_PCIE) - adapter->data_sent = false; - else + if (adapter->iface_type == MWIFIEX_SDIO) adapter->data_sent = true; + else + adapter->data_sent = false; adapter->cmd_resp_received = false; adapter->event_received = false; @@ -377,7 +379,8 @@ mwifiex_free_adapter(struct mwifiex_adapter *adapter) dev_dbg(adapter->dev, "info: free scan table\n"); - adapter->if_ops.cleanup_if(adapter); + if (adapter->if_ops.cleanup_if) + adapter->if_ops.cleanup_if(adapter); if (adapter->sleep_cfm) dev_kfree_skb_any(adapter->sleep_cfm); @@ -417,6 +420,8 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) spin_lock_init(&adapter->cmd_pending_q_lock); spin_lock_init(&adapter->scan_pending_q_lock); + skb_queue_head_init(&adapter->usb_rx_data_q); + for (i = 0; i < adapter->priv_num; ++i) { INIT_LIST_HEAD(&adapter->bss_prio_tbl[i].bss_prio_head); adapter->bss_prio_tbl[i].bss_prio_cur = NULL; @@ -572,6 +577,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) struct mwifiex_private *priv; s32 i; unsigned long flags; + struct sk_buff *skb; /* mwifiex already shutdown */ if (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY) @@ -599,6 +605,18 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) spin_lock_irqsave(&adapter->mwifiex_lock, flags); + if (adapter->if_ops.data_complete) { + while ((skb = skb_dequeue(&adapter->usb_rx_data_q))) { + struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); + + priv = adapter->priv[rx_info->bss_num]; + if (priv) + priv->stats.rx_dropped++; + + adapter->if_ops.data_complete(adapter, skb); + } + } + /* Free adapter structure */ mwifiex_free_adapter(adapter); @@ -628,24 +646,28 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter, int ret; u32 poll_num = 1; - adapter->winner = 0; + if (adapter->if_ops.check_fw_status) { + adapter->winner = 0; - /* Check if firmware is already running */ - ret = adapter->if_ops.check_fw_status(adapter, poll_num); - if (!ret) { - dev_notice(adapter->dev, - "WLAN FW already running! Skip FW download\n"); - goto done; - } - poll_num = MAX_FIRMWARE_POLL_TRIES; - - /* Check if we are the winner for downloading FW */ - if (!adapter->winner) { - dev_notice(adapter->dev, - "Other intf already running! Skip FW download\n"); - poll_num = MAX_MULTI_INTERFACE_POLL_TRIES; - goto poll_fw; + /* check if firmware is already running */ + ret = adapter->if_ops.check_fw_status(adapter, poll_num); + if (!ret) { + dev_notice(adapter->dev, + "WLAN FW already running! Skip FW dnld\n"); + goto done; + } + + poll_num = MAX_FIRMWARE_POLL_TRIES; + + /* check if we are the winner for downloading FW */ + if (!adapter->winner) { + dev_notice(adapter->dev, + "FW already running! Skip FW dnld\n"); + poll_num = MAX_MULTI_INTERFACE_POLL_TRIES; + goto poll_fw; + } } + if (pmfw) { /* Download firmware with helper */ ret = adapter->if_ops.prog_fw(adapter, pmfw); @@ -664,6 +686,8 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter, } done: /* re-enable host interrupt for mwifiex after fw dnld is successful */ - adapter->if_ops.enable_int(adapter); + if (adapter->if_ops.enable_int) + adapter->if_ops.enable_int(adapter); + return ret; } diff --git a/trunk/drivers/net/wireless/mwifiex/ioctl.h b/trunk/drivers/net/wireless/mwifiex/ioctl.h index 7ca4e8234f3e..f0f95524e96b 100644 --- a/trunk/drivers/net/wireless/mwifiex/ioctl.h +++ b/trunk/drivers/net/wireless/mwifiex/ioctl.h @@ -85,34 +85,6 @@ struct mwifiex_ds_get_stats { u32 wep_icv_error[4]; }; -#define BCN_RSSI_AVG_MASK 0x00000002 -#define BCN_NF_AVG_MASK 0x00000200 -#define ALL_RSSI_INFO_MASK 0x00000fff - -struct mwifiex_ds_get_signal { - /* - * Bit0: Last Beacon RSSI, Bit1: Average Beacon RSSI, - * Bit2: Last Data RSSI, Bit3: Average Data RSSI, - * Bit4: Last Beacon SNR, Bit5: Average Beacon SNR, - * Bit6: Last Data SNR, Bit7: Average Data SNR, - * Bit8: Last Beacon NF, Bit9: Average Beacon NF, - * Bit10: Last Data NF, Bit11: Average Data NF - */ - u16 selector; - s16 bcn_rssi_last; - s16 bcn_rssi_avg; - s16 data_rssi_last; - s16 data_rssi_avg; - s16 bcn_snr_last; - s16 bcn_snr_avg; - s16 data_snr_last; - s16 data_snr_avg; - s16 bcn_nf_last; - s16 bcn_nf_avg; - s16 data_nf_last; - s16 data_nf_avg; -}; - #define MWIFIEX_MAX_VER_STR_LEN 128 struct mwifiex_ver_ext { @@ -124,7 +96,7 @@ struct mwifiex_bss_info { u32 bss_mode; struct cfg80211_ssid ssid; u32 bss_chan; - u32 region_code; + u8 country_code[3]; u32 media_connected; u32 max_power_level; u32 min_power_level; @@ -308,8 +280,30 @@ struct mwifiex_ds_misc_cmd { u8 cmd[MWIFIEX_SIZE_OF_CMD_BUFFER]; }; +#define BITMASK_BCN_RSSI_LOW BIT(0) +#define BITMASK_BCN_RSSI_HIGH BIT(4) + +enum subsc_evt_rssi_state { + EVENT_HANDLED, + RSSI_LOW_RECVD, + RSSI_HIGH_RECVD +}; + +struct subsc_evt_cfg { + u8 abs_value; + u8 evt_freq; +}; + +struct mwifiex_ds_misc_subsc_evt { + u16 action; + u16 events; + struct subsc_evt_cfg bcn_l_rssi_cfg; + struct subsc_evt_cfg bcn_h_rssi_cfg; +}; + #define MWIFIEX_MAX_VSIE_LEN (256) #define MWIFIEX_MAX_VSIE_NUM (8) +#define MWIFIEX_VSIE_MASK_CLEAR 0x00 #define MWIFIEX_VSIE_MASK_SCAN 0x01 #define MWIFIEX_VSIE_MASK_ASSOC 0x02 #define MWIFIEX_VSIE_MASK_ADHOC 0x04 diff --git a/trunk/drivers/net/wireless/mwifiex/join.c b/trunk/drivers/net/wireless/mwifiex/join.c index 8f9382b9c3ca..8a390982463e 100644 --- a/trunk/drivers/net/wireless/mwifiex/join.c +++ b/trunk/drivers/net/wireless/mwifiex/join.c @@ -118,15 +118,15 @@ mwifiex_cmd_append_tsf_tlv(struct mwifiex_private *priv, u8 **buffer, *buffer += sizeof(tsf_tlv.header); /* TSF at the time when beacon/probe_response was received */ - tsf_val = cpu_to_le64(bss_desc->network_tsf); + tsf_val = cpu_to_le64(bss_desc->fw_tsf); memcpy(*buffer, &tsf_val, sizeof(tsf_val)); *buffer += sizeof(tsf_val); - memcpy(&tsf_val, bss_desc->time_stamp, sizeof(tsf_val)); + tsf_val = cpu_to_le64(bss_desc->timestamp); dev_dbg(priv->adapter->dev, "info: %s: TSF offset calc: %016llx - %016llx\n", - __func__, tsf_val, bss_desc->network_tsf); + __func__, bss_desc->timestamp, bss_desc->fw_tsf); memcpy(*buffer, &tsf_val, sizeof(tsf_val)); *buffer += sizeof(tsf_val); @@ -224,6 +224,48 @@ mwifiex_setup_rates_from_bssdesc(struct mwifiex_private *priv, return 0; } +/* + * This function appends a WPS IE. It is called from the network join command + * preparation routine. + * + * If the IE buffer has been setup by the application, this routine appends + * the buffer as a WPS TLV type to the request. + */ +static int +mwifiex_cmd_append_wps_ie(struct mwifiex_private *priv, u8 **buffer) +{ + int retLen = 0; + struct mwifiex_ie_types_header ie_header; + + if (!buffer || !*buffer) + return 0; + + /* + * If there is a wps ie buffer setup, append it to the return + * parameter buffer pointer. + */ + if (priv->wps_ie_len) { + dev_dbg(priv->adapter->dev, "cmd: append wps ie %d to %p\n", + priv->wps_ie_len, *buffer); + + /* Wrap the generic IE buffer with a pass through TLV type */ + ie_header.type = cpu_to_le16(TLV_TYPE_MGMT_IE); + ie_header.len = cpu_to_le16(priv->wps_ie_len); + memcpy(*buffer, &ie_header, sizeof(ie_header)); + *buffer += sizeof(ie_header); + retLen += sizeof(ie_header); + + memcpy(*buffer, priv->wps_ie, priv->wps_ie_len); + *buffer += priv->wps_ie_len; + retLen += priv->wps_ie_len; + + } + + kfree(priv->wps_ie); + priv->wps_ie_len = 0; + return retLen; +} + /* * This function appends a WAPI IE. * @@ -480,6 +522,8 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, if (priv->sec_info.wapi_enabled && priv->wapi_ie_len) mwifiex_cmd_append_wapi_ie(priv, &pos); + if (priv->wps.session_enable && priv->wps_ie_len) + mwifiex_cmd_append_wps_ie(priv, &pos); mwifiex_cmd_append_generic_ie(priv, &pos); @@ -932,20 +976,20 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, /* Fill HT INFORMATION */ ht_info = (struct mwifiex_ie_types_htinfo *) pos; memset(ht_info, 0, sizeof(struct mwifiex_ie_types_htinfo)); - ht_info->header.type = cpu_to_le16(WLAN_EID_HT_INFORMATION); + ht_info->header.type = cpu_to_le16(WLAN_EID_HT_OPERATION); ht_info->header.len = - cpu_to_le16(sizeof(struct ieee80211_ht_info)); + cpu_to_le16(sizeof(struct ieee80211_ht_operation)); - ht_info->ht_info.control_chan = + ht_info->ht_oper.primary_chan = (u8) priv->curr_bss_params.bss_descriptor.channel; if (adapter->sec_chan_offset) { - ht_info->ht_info.ht_param = adapter->sec_chan_offset; - ht_info->ht_info.ht_param |= + ht_info->ht_oper.ht_param = adapter->sec_chan_offset; + ht_info->ht_oper.ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; } - ht_info->ht_info.operation_mode = + ht_info->ht_oper.operation_mode = cpu_to_le16(IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); - ht_info->ht_info.basic_set[0] = 0xff; + ht_info->ht_oper.basic_set[0] = 0xff; pos += sizeof(struct mwifiex_ie_types_htinfo); cmd_append_size += sizeof(struct mwifiex_ie_types_htinfo); diff --git a/trunk/drivers/net/wireless/mwifiex/main.c b/trunk/drivers/net/wireless/mwifiex/main.c index 9d1b3ca6334b..be0f0e583f75 100644 --- a/trunk/drivers/net/wireless/mwifiex/main.c +++ b/trunk/drivers/net/wireless/mwifiex/main.c @@ -58,8 +58,9 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, memmove(&adapter->if_ops, if_ops, sizeof(struct mwifiex_if_ops)); /* card specific initialization has been deferred until now .. */ - if (adapter->if_ops.init_if(adapter)) - goto error; + if (adapter->if_ops.init_if) + if (adapter->if_ops.init_if(adapter)) + goto error; adapter->priv_num = 0; @@ -140,6 +141,7 @@ int mwifiex_main_process(struct mwifiex_adapter *adapter) { int ret = 0; unsigned long flags; + struct sk_buff *skb; spin_lock_irqsave(&adapter->main_proc_lock, flags); @@ -161,7 +163,8 @@ int mwifiex_main_process(struct mwifiex_adapter *adapter) if (adapter->int_status) { if (adapter->hs_activated) mwifiex_process_hs_config(adapter); - adapter->if_ops.process_int_status(adapter); + if (adapter->if_ops.process_int_status) + adapter->if_ops.process_int_status(adapter); } /* Need to wake up the card ? */ @@ -174,6 +177,7 @@ int mwifiex_main_process(struct mwifiex_adapter *adapter) adapter->if_ops.wakeup(adapter); continue; } + if (IS_CARD_RX_RCVD(adapter)) { adapter->pm_wakeup_fw_try = false; if (adapter->ps_state == PS_STATE_SLEEP) @@ -194,6 +198,11 @@ int mwifiex_main_process(struct mwifiex_adapter *adapter) } } + /* Check Rx data for USB */ + if (adapter->iface_type == MWIFIEX_USB) + while ((skb = skb_dequeue(&adapter->usb_rx_data_q))) + mwifiex_handle_rx_packet(adapter, skb); + /* Check for Cmd Resp */ if (adapter->cmd_resp_received) { adapter->cmd_resp_received = false; @@ -292,33 +301,35 @@ static void mwifiex_free_adapter(struct mwifiex_adapter *adapter) } /* - * This function initializes the hardware and firmware. + * This function gets firmware and initializes it. * * The main initialization steps followed are - * - Download the correct firmware to card - * - Allocate and initialize the adapter structure - * - Initialize the private structures * - Issue the init commands to firmware */ -static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter) +static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) { - int ret, err; + int ret; + char fmt[64]; + struct mwifiex_private *priv; + struct mwifiex_adapter *adapter = context; struct mwifiex_fw_image fw; - memset(&fw, 0, sizeof(struct mwifiex_fw_image)); - - err = request_firmware(&adapter->firmware, adapter->fw_name, - adapter->dev); - if (err < 0) { - dev_err(adapter->dev, "request_firmware() returned" - " error code %#x\n", err); - ret = -1; + if (!firmware) { + dev_err(adapter->dev, + "Failed to get firmware %s\n", adapter->fw_name); goto done; } + + memset(&fw, 0, sizeof(struct mwifiex_fw_image)); + adapter->firmware = firmware; fw.fw_buf = (u8 *) adapter->firmware->data; fw.fw_len = adapter->firmware->size; - ret = mwifiex_dnld_fw(adapter, &fw); + if (adapter->if_ops.dnld_fw) + ret = adapter->if_ops.dnld_fw(adapter, &fw); + else + ret = mwifiex_dnld_fw(adapter, &fw); if (ret == -1) goto done; @@ -335,17 +346,54 @@ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter) /* Wait for mwifiex_init to complete */ wait_event_interruptible(adapter->init_wait_q, adapter->init_wait_q_woken); - if (adapter->hw_status != MWIFIEX_HW_STATUS_READY) { - ret = -1; + if (adapter->hw_status != MWIFIEX_HW_STATUS_READY) goto done; + + priv = adapter->priv[0]; + if (mwifiex_register_cfg80211(priv) != 0) { + dev_err(adapter->dev, "cannot register with cfg80211\n"); + goto err_init_fw; } - ret = 0; + rtnl_lock(); + /* Create station interface by default */ + if (!mwifiex_add_virtual_intf(priv->wdev->wiphy, "mlan%d", + NL80211_IFTYPE_STATION, NULL, NULL)) { + dev_err(adapter->dev, "cannot create default STA interface\n"); + goto err_add_intf; + } + rtnl_unlock(); + + mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1); + dev_notice(adapter->dev, "driver_version = %s\n", fmt); + goto done; + +err_add_intf: + mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev); + rtnl_unlock(); +err_init_fw: + pr_debug("info: %s: unregister device\n", __func__); + adapter->if_ops.unregister_dev(adapter); done: - if (adapter->firmware) - release_firmware(adapter->firmware); - if (ret) - ret = -1; + release_firmware(adapter->firmware); + complete(&adapter->fw_load); + return; +} + +/* + * This function initializes the hardware and gets firmware. + */ +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); + if (ret < 0) + dev_err(adapter->dev, + "request_firmware_nowait() returned error %d\n", ret); return ret; } @@ -650,8 +698,6 @@ mwifiex_add_card(void *card, struct semaphore *sem, struct mwifiex_if_ops *if_ops, u8 iface_type) { struct mwifiex_adapter *adapter; - char fmt[64]; - struct mwifiex_private *priv; if (down_interruptible(sem)) goto exit_sem_err; @@ -692,40 +738,13 @@ mwifiex_add_card(void *card, struct semaphore *sem, goto err_init_fw; } - priv = adapter->priv[0]; - - if (mwifiex_register_cfg80211(priv) != 0) { - dev_err(adapter->dev, "cannot register netdevice" - " with cfg80211\n"); - goto err_init_fw; - } - - rtnl_lock(); - /* Create station interface by default */ - if (!mwifiex_add_virtual_intf(priv->wdev->wiphy, "mlan%d", - NL80211_IFTYPE_STATION, NULL, NULL)) { - rtnl_unlock(); - dev_err(adapter->dev, "cannot create default station" - " interface\n"); - goto err_add_intf; - } - - rtnl_unlock(); - up(sem); - - mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1); - dev_notice(adapter->dev, "driver_version = %s\n", fmt); - return 0; -err_add_intf: - rtnl_lock(); - mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev); - rtnl_unlock(); err_init_fw: pr_debug("info: %s: unregister device\n", __func__); - adapter->if_ops.unregister_dev(adapter); + if (adapter->if_ops.unregister_dev) + adapter->if_ops.unregister_dev(adapter); err_registerdev: adapter->surprise_removed = true; mwifiex_terminate_workqueue(adapter); @@ -830,7 +849,8 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) /* Unregister device */ dev_dbg(adapter->dev, "info: unregister device\n"); - adapter->if_ops.unregister_dev(adapter); + if (adapter->if_ops.unregister_dev) + adapter->if_ops.unregister_dev(adapter); /* Free adapter structure */ dev_dbg(adapter->dev, "info: free adapter\n"); mwifiex_free_adapter(adapter); diff --git a/trunk/drivers/net/wireless/mwifiex/main.h b/trunk/drivers/net/wireless/mwifiex/main.h index 35225e9b1080..324ad390cacd 100644 --- a/trunk/drivers/net/wireless/mwifiex/main.h +++ b/trunk/drivers/net/wireless/mwifiex/main.h @@ -92,9 +92,16 @@ enum { #define MWIFIEX_OUI_NOT_PRESENT 0 #define MWIFIEX_OUI_PRESENT 1 +/* + * Do not check for data_received for USB, as data_received + * is handled in mwifiex_usb_recv for USB + */ #define IS_CARD_RX_RCVD(adapter) (adapter->cmd_resp_received || \ - adapter->event_received || \ - adapter->data_received) + adapter->event_received || \ + ((adapter->iface_type != MWIFIEX_USB) && \ + adapter->data_received) || \ + ((adapter->iface_type == MWIFIEX_USB) && \ + !skb_queue_empty(&adapter->usb_rx_data_q))) #define MWIFIEX_TYPE_CMD 1 #define MWIFIEX_TYPE_DATA 0 @@ -110,6 +117,11 @@ enum { #define MWIFIEX_EVENT_HEADER_LEN 4 +#define MWIFIEX_TYPE_LEN 4 +#define MWIFIEX_USB_TYPE_CMD 0xF00DFACE +#define MWIFIEX_USB_TYPE_DATA 0xBEADC0DE +#define MWIFIEX_USB_TYPE_EVENT 0xBEEFFACE + struct mwifiex_dbg { u32 num_cmd_host_to_card_failure; u32 num_cmd_sleep_cfm_host_to_card_failure; @@ -162,6 +174,7 @@ enum MWIFIEX_PS_STATE { enum mwifiex_iface_type { MWIFIEX_SDIO, MWIFIEX_PCIE, + MWIFIEX_USB }; struct mwifiex_add_ba_param { @@ -201,10 +214,10 @@ struct mwifiex_wmm_desc { u32 packets_out[MAX_NUM_TID]; /* spin lock to protect ra_list */ spinlock_t ra_list_spinlock; - struct mwifiex_wmm_ac_status ac_status[IEEE80211_MAX_QUEUES]; - enum mwifiex_wmm_ac_e ac_down_graded_vals[IEEE80211_MAX_QUEUES]; + struct mwifiex_wmm_ac_status ac_status[IEEE80211_NUM_ACS]; + enum mwifiex_wmm_ac_e ac_down_graded_vals[IEEE80211_NUM_ACS]; u32 drv_pkt_delay_max; - u8 queue_priority[IEEE80211_MAX_QUEUES]; + u8 queue_priority[IEEE80211_NUM_ACS]; u32 user_pri_pkt_tx_ctrl[WMM_HIGHEST_PRIORITY + 1]; /* UP: 0 to 7 */ /* Number of transmit packets queued */ atomic_t tx_pkts_queued; @@ -260,8 +273,8 @@ struct mwifiex_bssdescriptor { * BAND_A(0X04): 'a' band */ u16 bss_band; - u64 network_tsf; - u8 time_stamp[8]; + u64 fw_tsf; + u64 timestamp; union ieee_types_phy_param_set phy_param_set; union ieee_types_ss_param_set ss_param_set; u16 cap_info_bitmap; @@ -269,7 +282,7 @@ struct mwifiex_bssdescriptor { u8 disable_11n; struct ieee80211_ht_cap *bcn_ht_cap; u16 ht_cap_offset; - struct ieee80211_ht_info *bcn_ht_info; + struct ieee80211_ht_operation *bcn_ht_oper; u16 ht_info_offset; u8 *bcn_bss_co_2040; u16 bss_co_2040_offset; @@ -407,6 +420,8 @@ struct mwifiex_private { struct host_cmd_ds_802_11_key_material aes_key; u8 wapi_ie[256]; u8 wapi_ie_len; + u8 *wps_ie; + u8 wps_ie_len; u8 wmm_required; u8 wmm_enabled; u8 wmm_qosinfo; @@ -448,7 +463,6 @@ struct mwifiex_private { struct dentry *dfs_dev_dir; #endif u8 nick_name[16]; - u8 qual_level, qual_noise; u16 current_key_index; struct semaphore async_sem; u8 scan_pending_on_block; @@ -459,6 +473,9 @@ struct mwifiex_private { u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; struct wps wps; u8 scan_block; + s32 cqm_rssi_thold; + u32 cqm_rssi_hyst; + u8 subsc_evt_rssi_state; }; enum mwifiex_ba_status { @@ -518,6 +535,11 @@ struct cmd_ctrl_node { u8 cmd_wait_q_woken; }; +struct mwifiex_bss_priv { + u8 band; + u64 fw_tsf; +}; + struct mwifiex_if_ops { int (*init_if) (struct mwifiex_adapter *); void (*cleanup_if) (struct mwifiex_adapter *); @@ -537,6 +559,8 @@ struct mwifiex_if_ops { void (*cleanup_mpa_buf) (struct mwifiex_adapter *); int (*cmdrsp_complete) (struct mwifiex_adapter *, struct sk_buff *); int (*event_complete) (struct mwifiex_adapter *, struct sk_buff *); + int (*data_complete) (struct mwifiex_adapter *, struct sk_buff *); + int (*dnld_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *); }; struct mwifiex_adapter { @@ -599,6 +623,7 @@ struct mwifiex_adapter { struct list_head scan_pending_q; /* spin lock for scan_pending_q */ spinlock_t scan_pending_q_lock; + struct sk_buff_head usb_rx_data_q; u32 scan_processing; u16 region_code; struct mwifiex_802_11d_domain_reg domain_reg; @@ -651,6 +676,7 @@ struct mwifiex_adapter { u8 scan_wait_q_woken; struct cmd_ctrl_node *cmd_queued; spinlock_t queue_lock; /* lock for tx queues */ + struct completion fw_load; }; int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); @@ -896,8 +922,6 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type); int mwifiex_enable_hs(struct mwifiex_adapter *adapter); int mwifiex_disable_auto_ds(struct mwifiex_private *priv); -int mwifiex_get_signal_info(struct mwifiex_private *priv, - struct mwifiex_ds_get_signal *signal); int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, struct mwifiex_rate_cfg *rate); int mwifiex_request_scan(struct mwifiex_private *priv, @@ -950,13 +974,10 @@ int mwifiex_bss_set_channel(struct mwifiex_private *, int mwifiex_get_bss_info(struct mwifiex_private *, struct mwifiex_bss_info *); int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, - u8 *bssid, s32 rssi, u8 *ie_buf, - size_t ie_len, u16 beacon_period, - u16 cap_info_bitmap, u8 band, + struct cfg80211_bss *bss, struct mwifiex_bssdescriptor *bss_desc); int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, - struct mwifiex_bssdescriptor *bss_entry, - u8 *ie_buf, u32 ie_len); + struct mwifiex_bssdescriptor *bss_entry); int mwifiex_check_network_compatibility(struct mwifiex_private *priv, struct mwifiex_bssdescriptor *bss_desc); @@ -965,6 +986,7 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, u32 *flags, struct vif_params *params); int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev); +u8 *mwifiex_11d_code_2_region(u8 code); #ifdef CONFIG_DEBUG_FS void mwifiex_debugfs_init(void); diff --git a/trunk/drivers/net/wireless/mwifiex/pcie.c b/trunk/drivers/net/wireless/mwifiex/pcie.c index 5867facd415d..13fbc4eb1595 100644 --- a/trunk/drivers/net/wireless/mwifiex/pcie.c +++ b/trunk/drivers/net/wireless/mwifiex/pcie.c @@ -119,6 +119,9 @@ 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 if (adapter->is_suspended) diff --git a/trunk/drivers/net/wireless/mwifiex/scan.c b/trunk/drivers/net/wireless/mwifiex/scan.c index aff9cd763f2b..74f045715723 100644 --- a/trunk/drivers/net/wireless/mwifiex/scan.c +++ b/trunk/drivers/net/wireless/mwifiex/scan.c @@ -1048,10 +1048,8 @@ mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter, * This function parses provided beacon buffer and updates * respective fields in bss descriptor structure. */ -int -mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, - struct mwifiex_bssdescriptor *bss_entry, - u8 *ie_buf, u32 ie_len) +int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, + struct mwifiex_bssdescriptor *bss_entry) { int ret = 0; u8 element_id; @@ -1073,10 +1071,8 @@ mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, found_data_rate_ie = false; rate_size = 0; - current_ptr = ie_buf; - bytes_left = ie_len; - bss_entry->beacon_buf = ie_buf; - bss_entry->beacon_buf_size = ie_len; + current_ptr = bss_entry->beacon_buf; + bytes_left = bss_entry->beacon_buf_size; /* Process variable IE */ while (bytes_left >= 2) { @@ -1221,9 +1217,9 @@ mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, sizeof(struct ieee_types_header) - bss_entry->beacon_buf); break; - case WLAN_EID_HT_INFORMATION: - bss_entry->bcn_ht_info = (struct ieee80211_ht_info *) - (current_ptr + + case WLAN_EID_HT_OPERATION: + bss_entry->bcn_ht_oper = + (struct ieee80211_ht_operation *)(current_ptr + sizeof(struct ieee_types_header)); bss_entry->ht_info_offset = (u16) (current_ptr + sizeof(struct ieee_types_header) - @@ -1447,15 +1443,12 @@ int mwifiex_check_network_compatibility(struct mwifiex_private *priv, return ret; } -static int -mwifiex_update_curr_bss_params(struct mwifiex_private *priv, u8 *bssid, - s32 rssi, const u8 *ie_buf, size_t ie_len, - u16 beacon_period, u16 cap_info_bitmap, u8 band) +static int mwifiex_update_curr_bss_params(struct mwifiex_private *priv, + struct cfg80211_bss *bss) { struct mwifiex_bssdescriptor *bss_desc; int ret; unsigned long flags; - u8 *beacon_ie; /* Allocate and fill new bss descriptor */ bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor), @@ -1465,16 +1458,7 @@ mwifiex_update_curr_bss_params(struct mwifiex_private *priv, u8 *bssid, return -ENOMEM; } - beacon_ie = kmemdup(ie_buf, ie_len, GFP_KERNEL); - if (!beacon_ie) { - kfree(bss_desc); - dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n"); - return -ENOMEM; - } - - ret = mwifiex_fill_new_bss_desc(priv, bssid, rssi, beacon_ie, - ie_len, beacon_period, - cap_info_bitmap, band, bss_desc); + ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc); if (ret) goto done; @@ -1493,7 +1477,7 @@ mwifiex_update_curr_bss_params(struct mwifiex_private *priv, u8 *bssid, priv->curr_bss_params.bss_descriptor.bcn_ht_cap = NULL; priv->curr_bss_params.bss_descriptor.ht_cap_offset = 0; - priv->curr_bss_params.bss_descriptor.bcn_ht_info = NULL; + priv->curr_bss_params.bss_descriptor.bcn_ht_oper = NULL; priv->curr_bss_params.bss_descriptor.ht_info_offset = 0; priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 = @@ -1514,7 +1498,6 @@ mwifiex_update_curr_bss_params(struct mwifiex_private *priv, u8 *bssid, done: kfree(bss_desc); - kfree(beacon_ie); return 0; } @@ -1620,14 +1603,16 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, const u8 *ie_buf; size_t ie_len; u16 channel = 0; - u64 network_tsf = 0; + u64 fw_tsf = 0; u16 beacon_size = 0; u32 curr_bcn_bytes; u32 freq; u16 beacon_period; u16 cap_info_bitmap; u8 *current_ptr; + u64 timestamp; struct mwifiex_bcn_param *bcn_param; + struct mwifiex_bss_priv *bss_priv; if (bytes_left >= sizeof(beacon_size)) { /* Extract & convert beacon size from command buffer */ @@ -1667,9 +1652,11 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, memcpy(bssid, bcn_param->bssid, ETH_ALEN); - rssi = (s32) (bcn_param->rssi); - dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%02X\n", rssi); + rssi = (s32) bcn_param->rssi; + rssi = (-rssi) * 100; /* Convert dBm to mBm */ + dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%d\n", rssi); + timestamp = le64_to_cpu(bcn_param->timestamp); beacon_period = le16_to_cpu(bcn_param->beacon_period); cap_info_bitmap = le16_to_cpu(bcn_param->cap_info_bitmap); @@ -1709,14 +1696,13 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, /* * If the TSF TLV was appended to the scan results, save this - * entry's TSF value in the networkTSF field.The networkTSF is - * the firmware's TSF value at the time the beacon or probe - * response was received. + * entry's TSF value in the fw_tsf field. It is the firmware's + * TSF value at the time the beacon or probe response was + * received. */ if (tsf_tlv) - memcpy(&network_tsf, - &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE], - sizeof(network_tsf)); + memcpy(&fw_tsf, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE], + sizeof(fw_tsf)); if (channel) { struct ieee80211_channel *chan; @@ -1739,21 +1725,19 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) { bss = cfg80211_inform_bss(priv->wdev->wiphy, - chan, bssid, network_tsf, + chan, bssid, timestamp, cap_info_bitmap, beacon_period, ie_buf, ie_len, rssi, GFP_KERNEL); - *(u8 *)bss->priv = band; - cfg80211_put_bss(bss); - + bss_priv = (struct mwifiex_bss_priv *)bss->priv; + bss_priv->band = band; + bss_priv->fw_tsf = fw_tsf; if (priv->media_connected && !memcmp(bssid, priv->curr_bss_params.bss_descriptor .mac_address, ETH_ALEN)) - mwifiex_update_curr_bss_params - (priv, bssid, rssi, - ie_buf, ie_len, - beacon_period, - cap_info_bitmap, band); + mwifiex_update_curr_bss_params(priv, + bss); + cfg80211_put_bss(bss); } } else { dev_dbg(adapter->dev, "missing BSS channel IE\n"); @@ -2019,8 +2003,8 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv) (curr_bss->beacon_buf + curr_bss->ht_cap_offset); - if (curr_bss->bcn_ht_info) - curr_bss->bcn_ht_info = (struct ieee80211_ht_info *) + if (curr_bss->bcn_ht_oper) + curr_bss->bcn_ht_oper = (struct ieee80211_ht_operation *) (curr_bss->beacon_buf + curr_bss->ht_info_offset); diff --git a/trunk/drivers/net/wireless/mwifiex/sdio.c b/trunk/drivers/net/wireless/mwifiex/sdio.c index f8012e2b7f7c..e0377473282f 100644 --- a/trunk/drivers/net/wireless/mwifiex/sdio.c +++ b/trunk/drivers/net/wireless/mwifiex/sdio.c @@ -123,6 +123,9 @@ 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); @@ -250,6 +253,8 @@ static int mwifiex_sdio_resume(struct device *dev) return 0; } +/* Device ID for SD8786 */ +#define SDIO_DEVICE_ID_MARVELL_8786 (0x9116) /* Device ID for SD8787 */ #define SDIO_DEVICE_ID_MARVELL_8787 (0x9119) /* Device ID for SD8797 */ @@ -257,6 +262,7 @@ static int mwifiex_sdio_resume(struct device *dev) /* WLAN IDs */ static const struct sdio_device_id mwifiex_ids[] = { + {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8786)}, {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787)}, {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797)}, {}, @@ -1596,6 +1602,9 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) adapter->dev = &func->dev; switch (func->device) { + case SDIO_DEVICE_ID_MARVELL_8786: + strcpy(adapter->fw_name, SD8786_DEFAULT_FW_NAME); + break; case SDIO_DEVICE_ID_MARVELL_8797: strcpy(adapter->fw_name, SD8797_DEFAULT_FW_NAME); break; @@ -1804,5 +1813,6 @@ MODULE_AUTHOR("Marvell International Ltd."); MODULE_DESCRIPTION("Marvell WiFi-Ex SDIO Driver version " SDIO_VERSION); MODULE_VERSION(SDIO_VERSION); MODULE_LICENSE("GPL v2"); +MODULE_FIRMWARE(SD8786_DEFAULT_FW_NAME); MODULE_FIRMWARE(SD8787_DEFAULT_FW_NAME); MODULE_FIRMWARE(SD8797_DEFAULT_FW_NAME); diff --git a/trunk/drivers/net/wireless/mwifiex/sdio.h b/trunk/drivers/net/wireless/mwifiex/sdio.h index a3fb322205b0..21033738ef0c 100644 --- a/trunk/drivers/net/wireless/mwifiex/sdio.h +++ b/trunk/drivers/net/wireless/mwifiex/sdio.h @@ -28,6 +28,7 @@ #include "main.h" +#define SD8786_DEFAULT_FW_NAME "mrvl/sd8786_uapsta.bin" #define SD8787_DEFAULT_FW_NAME "mrvl/sd8787_uapsta.bin" #define SD8797_DEFAULT_FW_NAME "mrvl/sd8797_uapsta.bin" @@ -193,7 +194,7 @@ a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt+1+(MAX_PORT - \ a->mp_end_port))); \ a->mpa_tx.pkt_cnt++; \ -} while (0); +} while (0) /* SDIO Tx aggregation limit ? */ #define MP_TX_AGGR_PKT_LIMIT_REACHED(a) \ @@ -211,7 +212,7 @@ a->mpa_tx.buf_len = 0; \ a->mpa_tx.ports = 0; \ a->mpa_tx.start_port = 0; \ -} while (0); +} while (0) /* SDIO Rx aggregation limit ? */ #define MP_RX_AGGR_PKT_LIMIT_REACHED(a) \ @@ -242,7 +243,7 @@ a->mpa_rx.skb_arr[a->mpa_rx.pkt_cnt] = skb; \ a->mpa_rx.len_arr[a->mpa_rx.pkt_cnt] = skb->len; \ a->mpa_rx.pkt_cnt++; \ -} while (0); +} while (0) /* Reset SDIO Rx aggregation buffer parameters */ #define MP_RX_AGGR_BUF_RESET(a) do { \ @@ -250,7 +251,7 @@ a->mpa_rx.buf_len = 0; \ a->mpa_rx.ports = 0; \ a->mpa_rx.start_port = 0; \ -} while (0); +} while (0) /* data structure for SDIO MPA TX */ diff --git a/trunk/drivers/net/wireless/mwifiex/sta_cmd.c b/trunk/drivers/net/wireless/mwifiex/sta_cmd.c index 6c8e4594b48b..87ed2a1f6cd9 100644 --- a/trunk/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/trunk/drivers/net/wireless/mwifiex/sta_cmd.c @@ -906,6 +906,101 @@ mwifiex_cmd_pcie_host_spec(struct mwifiex_private *priv, return 0; } +/* + * This function prepares command for event subscription, configuration + * and query. Events can be subscribed or unsubscribed. Current subscribed + * events can be queried. Also, current subscribed events are reported in + * every FW response. + */ +static int +mwifiex_cmd_802_11_subsc_evt(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + struct mwifiex_ds_misc_subsc_evt *subsc_evt_cfg) +{ + struct host_cmd_ds_802_11_subsc_evt *subsc_evt = &cmd->params.subsc_evt; + struct mwifiex_ie_types_rssi_threshold *rssi_tlv; + u16 event_bitmap; + u8 *pos; + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SUBSCRIBE_EVENT); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_subsc_evt) + + S_DS_GEN); + + subsc_evt->action = cpu_to_le16(subsc_evt_cfg->action); + dev_dbg(priv->adapter->dev, "cmd: action: %d\n", subsc_evt_cfg->action); + + /*For query requests, no configuration TLV structures are to be added.*/ + if (subsc_evt_cfg->action == HostCmd_ACT_GEN_GET) + return 0; + + subsc_evt->events = cpu_to_le16(subsc_evt_cfg->events); + + event_bitmap = subsc_evt_cfg->events; + dev_dbg(priv->adapter->dev, "cmd: event bitmap : %16x\n", + event_bitmap); + + if (((subsc_evt_cfg->action == HostCmd_ACT_BITWISE_CLR) || + (subsc_evt_cfg->action == HostCmd_ACT_BITWISE_SET)) && + (event_bitmap == 0)) { + dev_dbg(priv->adapter->dev, "Error: No event specified " + "for bitwise action type\n"); + return -EINVAL; + } + + /* + * Append TLV structures for each of the specified events for + * subscribing or re-configuring. This is not required for + * bitwise unsubscribing request. + */ + if (subsc_evt_cfg->action == HostCmd_ACT_BITWISE_CLR) + return 0; + + pos = ((u8 *)subsc_evt) + + sizeof(struct host_cmd_ds_802_11_subsc_evt); + + if (event_bitmap & BITMASK_BCN_RSSI_LOW) { + rssi_tlv = (struct mwifiex_ie_types_rssi_threshold *) pos; + + rssi_tlv->header.type = cpu_to_le16(TLV_TYPE_RSSI_LOW); + rssi_tlv->header.len = + cpu_to_le16(sizeof(struct mwifiex_ie_types_rssi_threshold) - + sizeof(struct mwifiex_ie_types_header)); + rssi_tlv->abs_value = subsc_evt_cfg->bcn_l_rssi_cfg.abs_value; + rssi_tlv->evt_freq = subsc_evt_cfg->bcn_l_rssi_cfg.evt_freq; + + dev_dbg(priv->adapter->dev, "Cfg Beacon Low Rssi event, " + "RSSI:-%d dBm, Freq:%d\n", + subsc_evt_cfg->bcn_l_rssi_cfg.abs_value, + subsc_evt_cfg->bcn_l_rssi_cfg.evt_freq); + + pos += sizeof(struct mwifiex_ie_types_rssi_threshold); + le16_add_cpu(&cmd->size, + sizeof(struct mwifiex_ie_types_rssi_threshold)); + } + + if (event_bitmap & BITMASK_BCN_RSSI_HIGH) { + rssi_tlv = (struct mwifiex_ie_types_rssi_threshold *) pos; + + rssi_tlv->header.type = cpu_to_le16(TLV_TYPE_RSSI_HIGH); + rssi_tlv->header.len = + cpu_to_le16(sizeof(struct mwifiex_ie_types_rssi_threshold) - + sizeof(struct mwifiex_ie_types_header)); + rssi_tlv->abs_value = subsc_evt_cfg->bcn_h_rssi_cfg.abs_value; + rssi_tlv->evt_freq = subsc_evt_cfg->bcn_h_rssi_cfg.evt_freq; + + dev_dbg(priv->adapter->dev, "Cfg Beacon High Rssi event, " + "RSSI:-%d dBm, Freq:%d\n", + subsc_evt_cfg->bcn_h_rssi_cfg.abs_value, + subsc_evt_cfg->bcn_h_rssi_cfg.evt_freq); + + pos += sizeof(struct mwifiex_ie_types_rssi_threshold); + le16_add_cpu(&cmd->size, + sizeof(struct mwifiex_ie_types_rssi_threshold)); + } + + return 0; +} + /* * This function prepares the commands before sending them to the firmware. * @@ -1086,6 +1181,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, case HostCmd_CMD_PCIE_DESC_DETAILS: ret = mwifiex_cmd_pcie_host_spec(priv, cmd_ptr, cmd_action); break; + case HostCmd_CMD_802_11_SUBSCRIBE_EVENT: + ret = mwifiex_cmd_802_11_subsc_evt(priv, cmd_ptr, data_buf); + break; default: dev_err(priv->adapter->dev, "PREP_CMD: unknown cmd- %#x\n", cmd_no); @@ -1195,7 +1293,7 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) if (ret) return -1; - if (first_sta) { + if (first_sta && (priv->adapter->iface_type != MWIFIEX_USB)) { /* Enable auto deep sleep */ auto_ds.auto_ds = DEEP_SLEEP_ON; auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME; diff --git a/trunk/drivers/net/wireless/mwifiex/sta_cmdresp.c b/trunk/drivers/net/wireless/mwifiex/sta_cmdresp.c index 4da19ed0f078..3aa54243dea9 100644 --- a/trunk/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/trunk/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -119,11 +119,11 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv, * calculated SNR values. */ static int mwifiex_ret_802_11_rssi_info(struct mwifiex_private *priv, - struct host_cmd_ds_command *resp, - struct mwifiex_ds_get_signal *signal) + struct host_cmd_ds_command *resp) { struct host_cmd_ds_802_11_rssi_info_rsp *rssi_info_rsp = &resp->params.rssi_info_rsp; + struct mwifiex_ds_misc_subsc_evt subsc_evt; priv->data_rssi_last = le16_to_cpu(rssi_info_rsp->data_rssi_last); priv->data_nf_last = le16_to_cpu(rssi_info_rsp->data_nf_last); @@ -137,34 +137,29 @@ static int mwifiex_ret_802_11_rssi_info(struct mwifiex_private *priv, priv->bcn_rssi_avg = le16_to_cpu(rssi_info_rsp->bcn_rssi_avg); priv->bcn_nf_avg = le16_to_cpu(rssi_info_rsp->bcn_nf_avg); - /* Need to indicate IOCTL complete */ - if (signal) { - memset(signal, 0, sizeof(*signal)); - - signal->selector = ALL_RSSI_INFO_MASK; - - /* RSSI */ - signal->bcn_rssi_last = priv->bcn_rssi_last; - signal->bcn_rssi_avg = priv->bcn_rssi_avg; - signal->data_rssi_last = priv->data_rssi_last; - signal->data_rssi_avg = priv->data_rssi_avg; - - /* SNR */ - signal->bcn_snr_last = - CAL_SNR(priv->bcn_rssi_last, priv->bcn_nf_last); - signal->bcn_snr_avg = - CAL_SNR(priv->bcn_rssi_avg, priv->bcn_nf_avg); - signal->data_snr_last = - CAL_SNR(priv->data_rssi_last, priv->data_nf_last); - signal->data_snr_avg = - CAL_SNR(priv->data_rssi_avg, priv->data_nf_avg); - - /* NF */ - signal->bcn_nf_last = priv->bcn_nf_last; - signal->bcn_nf_avg = priv->bcn_nf_avg; - signal->data_nf_last = priv->data_nf_last; - signal->data_nf_avg = priv->data_nf_avg; + if (priv->subsc_evt_rssi_state == EVENT_HANDLED) + return 0; + + /* Resubscribe low and high rssi events with new thresholds */ + memset(&subsc_evt, 0x00, sizeof(struct mwifiex_ds_misc_subsc_evt)); + subsc_evt.events = BITMASK_BCN_RSSI_LOW | BITMASK_BCN_RSSI_HIGH; + subsc_evt.action = HostCmd_ACT_BITWISE_SET; + if (priv->subsc_evt_rssi_state == RSSI_LOW_RECVD) { + subsc_evt.bcn_l_rssi_cfg.abs_value = abs(priv->bcn_rssi_avg - + priv->cqm_rssi_hyst); + subsc_evt.bcn_h_rssi_cfg.abs_value = abs(priv->cqm_rssi_thold); + } else if (priv->subsc_evt_rssi_state == RSSI_HIGH_RECVD) { + subsc_evt.bcn_l_rssi_cfg.abs_value = abs(priv->cqm_rssi_thold); + subsc_evt.bcn_h_rssi_cfg.abs_value = abs(priv->bcn_rssi_avg + + priv->cqm_rssi_hyst); } + subsc_evt.bcn_l_rssi_cfg.evt_freq = 1; + subsc_evt.bcn_h_rssi_cfg.evt_freq = 1; + + priv->subsc_evt_rssi_state = EVENT_HANDLED; + + mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SUBSCRIBE_EVENT, + 0, 0, &subsc_evt); return 0; } @@ -784,6 +779,28 @@ static int mwifiex_ret_ibss_coalescing_status(struct mwifiex_private *priv, return 0; } +/* + * This function handles the command response for subscribe event command. + */ +static int mwifiex_ret_subsc_evt(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp, + struct mwifiex_ds_misc_subsc_evt *sub_event) +{ + struct host_cmd_ds_802_11_subsc_evt *cmd_sub_event = + (struct host_cmd_ds_802_11_subsc_evt *)&resp->params.subsc_evt; + + /* For every subscribe event command (Get/Set/Clear), FW reports the + * current set of subscribed events*/ + dev_dbg(priv->adapter->dev, "Bitmap of currently subscribed events: %16x\n", + le16_to_cpu(cmd_sub_event->events)); + + /*Return the subscribed event info for a Get request*/ + if (sub_event) + sub_event->events = le16_to_cpu(cmd_sub_event->events); + + return 0; +} + /* * This function handles the command responses. * @@ -853,7 +870,7 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, ret = mwifiex_ret_get_log(priv, resp, data_buf); break; case HostCmd_CMD_RSSI_INFO: - ret = mwifiex_ret_802_11_rssi_info(priv, resp, data_buf); + ret = mwifiex_ret_802_11_rssi_info(priv, resp); break; case HostCmd_CMD_802_11_SNMP_MIB: ret = mwifiex_ret_802_11_snmp_mib(priv, resp, data_buf); @@ -924,6 +941,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, break; case HostCmd_CMD_PCIE_DESC_DETAILS: break; + case HostCmd_CMD_802_11_SUBSCRIBE_EVENT: + ret = mwifiex_ret_subsc_evt(priv, resp, data_buf); + break; default: dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n", resp->command); diff --git a/trunk/drivers/net/wireless/mwifiex/sta_event.c b/trunk/drivers/net/wireless/mwifiex/sta_event.c index cc531b536a56..f6bbb9307f86 100644 --- a/trunk/drivers/net/wireless/mwifiex/sta_event.c +++ b/trunk/drivers/net/wireless/mwifiex/sta_event.c @@ -128,9 +128,6 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv) mwifiex_stop_net_dev_queue(priv->netdev, adapter); if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); - /* Reset wireless stats signal info */ - priv->qual_level = 0; - priv->qual_noise = 0; } /* @@ -317,6 +314,12 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) break; case EVENT_RSSI_LOW: + cfg80211_cqm_rssi_notify(priv->netdev, + NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW, + GFP_KERNEL); + mwifiex_send_cmd_async(priv, HostCmd_CMD_RSSI_INFO, + HostCmd_ACT_GEN_GET, 0, NULL); + priv->subsc_evt_rssi_state = RSSI_LOW_RECVD; dev_dbg(adapter->dev, "event: Beacon RSSI_LOW\n"); break; case EVENT_SNR_LOW: @@ -326,6 +329,12 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) dev_dbg(adapter->dev, "event: MAX_FAIL\n"); break; case EVENT_RSSI_HIGH: + cfg80211_cqm_rssi_notify(priv->netdev, + NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, + GFP_KERNEL); + mwifiex_send_cmd_async(priv, HostCmd_CMD_RSSI_INFO, + HostCmd_ACT_GEN_GET, 0, NULL); + priv->subsc_evt_rssi_state = RSSI_HIGH_RECVD; dev_dbg(adapter->dev, "event: Beacon RSSI_HIGH\n"); break; case EVENT_SNR_HIGH: diff --git a/trunk/drivers/net/wireless/mwifiex/sta_ioctl.c b/trunk/drivers/net/wireless/mwifiex/sta_ioctl.c index d7b11defafe0..58970e0f7d13 100644 --- a/trunk/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/trunk/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -155,20 +155,29 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv, * information. */ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, - u8 *bssid, s32 rssi, u8 *ie_buf, - size_t ie_len, u16 beacon_period, - u16 cap_info_bitmap, u8 band, + struct cfg80211_bss *bss, struct mwifiex_bssdescriptor *bss_desc) { int ret; + u8 *beacon_ie; + struct mwifiex_bss_priv *bss_priv = (void *)bss->priv; - memcpy(bss_desc->mac_address, bssid, ETH_ALEN); - bss_desc->rssi = rssi; - bss_desc->beacon_buf = ie_buf; - bss_desc->beacon_buf_size = ie_len; - bss_desc->beacon_period = beacon_period; - bss_desc->cap_info_bitmap = cap_info_bitmap; - bss_desc->bss_band = band; + beacon_ie = kmemdup(bss->information_elements, bss->len_beacon_ies, + GFP_KERNEL); + if (!beacon_ie) { + dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n"); + return -ENOMEM; + } + + memcpy(bss_desc->mac_address, bss->bssid, ETH_ALEN); + bss_desc->rssi = bss->signal; + bss_desc->beacon_buf = beacon_ie; + bss_desc->beacon_buf_size = bss->len_beacon_ies; + bss_desc->beacon_period = bss->beacon_interval; + bss_desc->cap_info_bitmap = bss->capability; + bss_desc->bss_band = bss_priv->band; + bss_desc->fw_tsf = bss_priv->fw_tsf; + bss_desc->timestamp = bss->tsf; if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) { dev_dbg(priv->adapter->dev, "info: InterpretIE: AP WEP enabled\n"); bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; @@ -180,9 +189,9 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, else bss_desc->bss_mode = NL80211_IFTYPE_STATION; - ret = mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc, - ie_buf, ie_len); + ret = mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc); + kfree(beacon_ie); return ret; } @@ -197,7 +206,6 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, int ret; struct mwifiex_adapter *adapter = priv->adapter; struct mwifiex_bssdescriptor *bss_desc = NULL; - u8 *beacon_ie = NULL; priv->scan_block = false; @@ -210,19 +218,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, return -ENOMEM; } - beacon_ie = kmemdup(bss->information_elements, - bss->len_beacon_ies, GFP_KERNEL); - if (!beacon_ie) { - kfree(bss_desc); - dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n"); - return -ENOMEM; - } - - ret = mwifiex_fill_new_bss_desc(priv, bss->bssid, bss->signal, - beacon_ie, bss->len_beacon_ies, - bss->beacon_interval, - bss->capability, - *(u8 *)bss->priv, bss_desc); + ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc); if (ret) goto done; } @@ -269,7 +265,6 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, (!mwifiex_ssid_cmp(&priv->curr_bss_params.bss_descriptor. ssid, &bss_desc->ssid))) { kfree(bss_desc); - kfree(beacon_ie); return 0; } @@ -304,7 +299,6 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, done: kfree(bss_desc); - kfree(beacon_ie); return ret; } @@ -468,7 +462,8 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv, info->bss_chan = bss_desc->channel; - info->region_code = adapter->region_code; + memcpy(info->country_code, priv->country_code, + IEEE80211_COUNTRY_STRING_LEN); info->media_connected = priv->media_connected; @@ -995,6 +990,39 @@ static int mwifiex_set_wapi_ie(struct mwifiex_private *priv, return 0; } +/* + * IOCTL request handler to set/reset WPS IE. + * + * The supplied WPS IE is treated as a opaque buffer. Only the first field + * is checked to internally enable WPS. If buffer length is zero, the existing + * WPS IE is reset. + */ +static int mwifiex_set_wps_ie(struct mwifiex_private *priv, + u8 *ie_data_ptr, u16 ie_len) +{ + if (ie_len) { + priv->wps_ie = kzalloc(MWIFIEX_MAX_VSIE_LEN, GFP_KERNEL); + if (!priv->wps_ie) + return -ENOMEM; + if (ie_len > sizeof(priv->wps_ie)) { + dev_dbg(priv->adapter->dev, + "info: failed to copy WPS IE, too big\n"); + kfree(priv->wps_ie); + return -1; + } + memcpy(priv->wps_ie, ie_data_ptr, ie_len); + priv->wps_ie_len = ie_len; + dev_dbg(priv->adapter->dev, "cmd: Set wps_ie_len=%d IE=%#x\n", + priv->wps_ie_len, priv->wps_ie[0]); + } else { + kfree(priv->wps_ie); + priv->wps_ie_len = ie_len; + dev_dbg(priv->adapter->dev, + "info: Reset wps_ie_len=%d\n", priv->wps_ie_len); + } + return 0; +} + /* * IOCTL request handler to set WAPI key. * @@ -1184,39 +1212,6 @@ mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version, return 0; } -/* - * Sends IOCTL request to get signal information. - * - * This function allocates the IOCTL request buffer, fills it - * with requisite parameters and calls the IOCTL handler. - */ -int mwifiex_get_signal_info(struct mwifiex_private *priv, - struct mwifiex_ds_get_signal *signal) -{ - int status; - - signal->selector = ALL_RSSI_INFO_MASK; - - /* Signal info can be obtained only if connected */ - if (!priv->media_connected) { - dev_dbg(priv->adapter->dev, - "info: Can not get signal in disconnected state\n"); - return -1; - } - - status = mwifiex_send_cmd_sync(priv, HostCmd_CMD_RSSI_INFO, - HostCmd_ACT_GEN_GET, 0, signal); - - if (!status) { - if (signal->selector & BCN_RSSI_AVG_MASK) - priv->qual_level = signal->bcn_rssi_avg; - if (signal->selector & BCN_NF_AVG_MASK) - priv->qual_noise = signal->bcn_nf_avg; - } - - return status; -} - /* * Sends IOCTL request to set encoding parameters. * @@ -1441,6 +1436,7 @@ mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr, priv->wps.session_enable = true; dev_dbg(priv->adapter->dev, "info: WPS Session Enabled.\n"); + ret = mwifiex_set_wps_ie(priv, ie_data_ptr, ie_len); } /* Append the passed data to the end of the diff --git a/trunk/drivers/net/wireless/mwifiex/sta_rx.c b/trunk/drivers/net/wireless/mwifiex/sta_rx.c index 750b695aca12..02ce3b77d3e7 100644 --- a/trunk/drivers/net/wireless/mwifiex/sta_rx.c +++ b/trunk/drivers/net/wireless/mwifiex/sta_rx.c @@ -145,7 +145,12 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter, " rx_pkt_offset=%d, rx_pkt_length=%d\n", skb->len, local_rx_pd->rx_pkt_offset, local_rx_pd->rx_pkt_length); priv->stats.rx_dropped++; - dev_kfree_skb_any(skb); + + if (adapter->if_ops.data_complete) + adapter->if_ops.data_complete(adapter, skb); + else + dev_kfree_skb_any(skb); + return ret; } @@ -196,8 +201,12 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter, (u8) local_rx_pd->rx_pkt_type, skb); - if (ret || (rx_pkt_type == PKT_TYPE_BAR)) - dev_kfree_skb_any(skb); + if (ret || (rx_pkt_type == PKT_TYPE_BAR)) { + if (adapter->if_ops.data_complete) + adapter->if_ops.data_complete(adapter, skb); + else + dev_kfree_skb_any(skb); + } if (ret) priv->stats.rx_dropped++; diff --git a/trunk/drivers/net/wireless/mwifiex/sta_tx.c b/trunk/drivers/net/wireless/mwifiex/sta_tx.c index 7af534feb420..0a046d3a0c16 100644 --- a/trunk/drivers/net/wireless/mwifiex/sta_tx.c +++ b/trunk/drivers/net/wireless/mwifiex/sta_tx.c @@ -149,10 +149,14 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags) local_tx_pd->bss_num = priv->bss_num; local_tx_pd->bss_type = priv->bss_type; - skb_push(skb, INTF_HEADER_LEN); - - ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, - skb, NULL); + if (adapter->iface_type == MWIFIEX_USB) { + ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_USB_EP_DATA, + skb, NULL); + } else { + skb_push(skb, INTF_HEADER_LEN); + ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, + skb, NULL); + } switch (ret) { case -EBUSY: adapter->data_sent = true; diff --git a/trunk/drivers/net/wireless/mwifiex/txrx.c b/trunk/drivers/net/wireless/mwifiex/txrx.c index d2af8cb98541..e2faec4db108 100644 --- a/trunk/drivers/net/wireless/mwifiex/txrx.c +++ b/trunk/drivers/net/wireless/mwifiex/txrx.c @@ -77,12 +77,23 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) local_tx_pd = (struct txpd *) (head_ptr + INTF_HEADER_LEN); - - ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, - skb, tx_param); + if (adapter->iface_type == MWIFIEX_USB) { + adapter->data_sent = true; + skb_pull(skb, INTF_HEADER_LEN); + ret = adapter->if_ops.host_to_card(adapter, + MWIFIEX_USB_EP_DATA, + skb, NULL); + } else { + ret = adapter->if_ops.host_to_card(adapter, + MWIFIEX_TYPE_DATA, + skb, tx_param); + } } switch (ret) { + case -ENOSR: + dev_err(adapter->dev, "data: -ENOSR is returned\n"); + break; case -EBUSY: if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && (adapter->pps_uapsd_mode) && (adapter->tx_lock_flag)) { @@ -135,6 +146,9 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, if (!priv) goto done; + if (adapter->iface_type == MWIFIEX_USB) + adapter->data_sent = false; + mwifiex_set_trans_start(priv->netdev); if (!status) { priv->stats.tx_packets++; @@ -162,4 +176,5 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, return 0; } +EXPORT_SYMBOL_GPL(mwifiex_write_data_complete); diff --git a/trunk/drivers/net/wireless/mwifiex/usb.c b/trunk/drivers/net/wireless/mwifiex/usb.c new file mode 100644 index 000000000000..49ebf20c56eb --- /dev/null +++ b/trunk/drivers/net/wireless/mwifiex/usb.c @@ -0,0 +1,1052 @@ +/* + * Marvell Wireless LAN device driver: USB specific handling + * + * Copyright (C) 2012, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "main.h" +#include "usb.h" + +#define USB_VERSION "1.0" + +static const char usbdriver_name[] = "usb8797"; + +static u8 user_rmmod; +static struct mwifiex_if_ops usb_ops; +static struct semaphore add_remove_card_sem; + +static struct usb_device_id mwifiex_usb_table[] = { + {USB_DEVICE(USB8797_VID, USB8797_PID_1)}, + {USB_DEVICE_AND_INTERFACE_INFO(USB8797_VID, USB8797_PID_2, + USB_CLASS_VENDOR_SPEC, + USB_SUBCLASS_VENDOR_SPEC, 0xff)}, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, mwifiex_usb_table); + +static int mwifiex_usb_submit_rx_urb(struct urb_context *ctx, int size); + +/* This function handles received packet. Necessary action is taken based on + * cmd/event/data. + */ +static int mwifiex_usb_recv(struct mwifiex_adapter *adapter, + struct sk_buff *skb, u8 ep) +{ + struct device *dev = adapter->dev; + u32 recv_type; + __le32 tmp; + + if (adapter->hs_activated) + mwifiex_process_hs_config(adapter); + + if (skb->len < INTF_HEADER_LEN) { + dev_err(dev, "%s: invalid skb->len\n", __func__); + return -1; + } + + switch (ep) { + case MWIFIEX_USB_EP_CMD_EVENT: + dev_dbg(dev, "%s: EP_CMD_EVENT\n", __func__); + skb_copy_from_linear_data(skb, &tmp, INTF_HEADER_LEN); + recv_type = le32_to_cpu(tmp); + skb_pull(skb, INTF_HEADER_LEN); + + switch (recv_type) { + case MWIFIEX_USB_TYPE_CMD: + if (skb->len > MWIFIEX_SIZE_OF_CMD_BUFFER) { + dev_err(dev, "CMD: skb->len too large\n"); + return -1; + } else if (!adapter->curr_cmd) { + dev_dbg(dev, "CMD: no curr_cmd\n"); + if (adapter->ps_state == PS_STATE_SLEEP_CFM) { + mwifiex_process_sleep_confirm_resp( + adapter, skb->data, + skb->len); + return 0; + } + return -1; + } + + adapter->curr_cmd->resp_skb = skb; + adapter->cmd_resp_received = true; + break; + case MWIFIEX_USB_TYPE_EVENT: + if (skb->len < sizeof(u32)) { + dev_err(dev, "EVENT: skb->len too small\n"); + return -1; + } + skb_copy_from_linear_data(skb, &tmp, sizeof(u32)); + adapter->event_cause = le32_to_cpu(tmp); + skb_pull(skb, sizeof(u32)); + dev_dbg(dev, "event_cause %#x\n", adapter->event_cause); + + if (skb->len > MAX_EVENT_SIZE) { + dev_err(dev, "EVENT: event body too large\n"); + return -1; + } + + skb_copy_from_linear_data(skb, adapter->event_body, + skb->len); + adapter->event_received = true; + adapter->event_skb = skb; + break; + default: + dev_err(dev, "unknown recv_type %#x\n", recv_type); + return -1; + } + break; + case MWIFIEX_USB_EP_DATA: + dev_dbg(dev, "%s: EP_DATA\n", __func__); + if (skb->len > MWIFIEX_RX_DATA_BUF_SIZE) { + dev_err(dev, "DATA: skb->len too large\n"); + return -1; + } + skb_queue_tail(&adapter->usb_rx_data_q, skb); + adapter->data_received = true; + break; + default: + dev_err(dev, "%s: unknown endport %#x\n", __func__, ep); + return -1; + } + + return -EINPROGRESS; +} + +static void mwifiex_usb_rx_complete(struct urb *urb) +{ + struct urb_context *context = (struct urb_context *)urb->context; + struct mwifiex_adapter *adapter = context->adapter; + struct sk_buff *skb = context->skb; + struct usb_card_rec *card; + int recv_length = urb->actual_length; + int size, status; + + if (!adapter || !adapter->card) { + pr_err("mwifiex adapter or card structure is not valid\n"); + return; + } + + card = (struct usb_card_rec *)adapter->card; + if (card->rx_cmd_ep == context->ep) + atomic_dec(&card->rx_cmd_urb_pending); + else + atomic_dec(&card->rx_data_urb_pending); + + if (recv_length) { + if (urb->status || (adapter->surprise_removed)) { + dev_err(adapter->dev, + "URB status is failed: %d\n", urb->status); + /* Do not free skb in case of command ep */ + if (card->rx_cmd_ep != context->ep) + dev_kfree_skb_any(skb); + goto setup_for_next; + } + if (skb->len > recv_length) + skb_trim(skb, recv_length); + else + skb_put(skb, recv_length - skb->len); + + atomic_inc(&adapter->rx_pending); + status = mwifiex_usb_recv(adapter, skb, context->ep); + + dev_dbg(adapter->dev, "info: recv_length=%d, status=%d\n", + recv_length, status); + if (status == -EINPROGRESS) { + queue_work(adapter->workqueue, &adapter->main_work); + + /* urb for data_ep is re-submitted now; + * urb for cmd_ep will be re-submitted in callback + * mwifiex_usb_recv_complete + */ + if (card->rx_cmd_ep == context->ep) + return; + } else { + atomic_dec(&adapter->rx_pending); + if (status == -1) + dev_err(adapter->dev, + "received data processing failed!\n"); + + /* Do not free skb in case of command ep */ + if (card->rx_cmd_ep != context->ep) + dev_kfree_skb_any(skb); + } + } else if (urb->status) { + if (!adapter->is_suspended) { + dev_warn(adapter->dev, + "Card is removed: %d\n", urb->status); + adapter->surprise_removed = true; + } + dev_kfree_skb_any(skb); + return; + } else { + /* Do not free skb in case of command ep */ + if (card->rx_cmd_ep != context->ep) + dev_kfree_skb_any(skb); + + /* fall through setup_for_next */ + } + +setup_for_next: + if (card->rx_cmd_ep == context->ep) + size = MWIFIEX_RX_CMD_BUF_SIZE; + else + size = MWIFIEX_RX_DATA_BUF_SIZE; + + mwifiex_usb_submit_rx_urb(context, size); + + return; +} + +static void mwifiex_usb_tx_complete(struct urb *urb) +{ + struct urb_context *context = (struct urb_context *)(urb->context); + struct mwifiex_adapter *adapter = context->adapter; + struct usb_card_rec *card = adapter->card; + + dev_dbg(adapter->dev, "%s: status: %d\n", __func__, urb->status); + + if (context->ep == card->tx_cmd_ep) { + dev_dbg(adapter->dev, "%s: CMD\n", __func__); + atomic_dec(&card->tx_cmd_urb_pending); + adapter->cmd_sent = false; + } else { + dev_dbg(adapter->dev, "%s: DATA\n", __func__); + atomic_dec(&card->tx_data_urb_pending); + mwifiex_write_data_complete(adapter, context->skb, + urb->status ? -1 : 0); + } + + queue_work(adapter->workqueue, &adapter->main_work); + + return; +} + +static int mwifiex_usb_submit_rx_urb(struct urb_context *ctx, int size) +{ + struct mwifiex_adapter *adapter = ctx->adapter; + struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; + + if (card->rx_cmd_ep != ctx->ep) { + ctx->skb = dev_alloc_skb(size); + if (!ctx->skb) { + dev_err(adapter->dev, + "%s: dev_alloc_skb failed\n", __func__); + return -ENOMEM; + } + } + + usb_fill_bulk_urb(ctx->urb, card->udev, + usb_rcvbulkpipe(card->udev, ctx->ep), ctx->skb->data, + size, mwifiex_usb_rx_complete, (void *)ctx); + + if (card->rx_cmd_ep == ctx->ep) + atomic_inc(&card->rx_cmd_urb_pending); + else + atomic_inc(&card->rx_data_urb_pending); + + if (usb_submit_urb(ctx->urb, GFP_ATOMIC)) { + dev_err(adapter->dev, "usb_submit_urb failed\n"); + dev_kfree_skb_any(ctx->skb); + ctx->skb = NULL; + + if (card->rx_cmd_ep == ctx->ep) + atomic_dec(&card->rx_cmd_urb_pending); + else + atomic_dec(&card->rx_data_urb_pending); + + return -1; + } + + return 0; +} + +static void mwifiex_usb_free(struct usb_card_rec *card) +{ + int i; + + if (atomic_read(&card->rx_cmd_urb_pending) && card->rx_cmd.urb) + usb_kill_urb(card->rx_cmd.urb); + + usb_free_urb(card->rx_cmd.urb); + card->rx_cmd.urb = NULL; + + if (atomic_read(&card->rx_data_urb_pending)) + for (i = 0; i < MWIFIEX_RX_DATA_URB; i++) + if (card->rx_data_list[i].urb) + usb_kill_urb(card->rx_data_list[i].urb); + + for (i = 0; i < MWIFIEX_RX_DATA_URB; i++) { + usb_free_urb(card->rx_data_list[i].urb); + card->rx_data_list[i].urb = NULL; + } + + for (i = 0; i < MWIFIEX_TX_DATA_URB; i++) { + usb_free_urb(card->tx_data_list[i].urb); + card->tx_data_list[i].urb = NULL; + } + + usb_free_urb(card->tx_cmd.urb); + card->tx_cmd.urb = NULL; + + return; +} + +/* This function probes an mwifiex device and registers it. It allocates + * the card structure, initiates the device registration and initialization + * procedure by adding a logical interface. + */ +static int mwifiex_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct usb_host_interface *iface_desc = intf->cur_altsetting; + struct usb_endpoint_descriptor *epd; + int ret, i; + struct usb_card_rec *card; + u16 id_vendor, id_product, bcd_device, bcd_usb; + + card = kzalloc(sizeof(struct usb_card_rec), GFP_KERNEL); + if (!card) + return -ENOMEM; + + id_vendor = le16_to_cpu(udev->descriptor.idVendor); + id_product = le16_to_cpu(udev->descriptor.idProduct); + bcd_device = le16_to_cpu(udev->descriptor.bcdDevice); + bcd_usb = le16_to_cpu(udev->descriptor.bcdUSB); + pr_debug("info: VID/PID = %X/%X, Boot2 version = %X\n", + id_vendor, id_product, bcd_device); + + /* PID_1 is used for firmware downloading only */ + if (id_product == USB8797_PID_1) + card->usb_boot_state = USB8797_FW_DNLD; + else + card->usb_boot_state = USB8797_FW_READY; + + card->udev = udev; + card->intf = intf; + + pr_debug("info: bcdUSB=%#x Device Class=%#x SubClass=%#x Protocl=%#x\n", + udev->descriptor.bcdUSB, udev->descriptor.bDeviceClass, + udev->descriptor.bDeviceSubClass, + udev->descriptor.bDeviceProtocol); + + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + epd = &iface_desc->endpoint[i].desc; + if (usb_endpoint_dir_in(epd) && + usb_endpoint_num(epd) == MWIFIEX_USB_EP_CMD_EVENT && + usb_endpoint_xfer_bulk(epd)) { + pr_debug("info: bulk IN: max pkt size: %d, addr: %d\n", + le16_to_cpu(epd->wMaxPacketSize), + epd->bEndpointAddress); + card->rx_cmd_ep = usb_endpoint_num(epd); + atomic_set(&card->rx_cmd_urb_pending, 0); + } + if (usb_endpoint_dir_in(epd) && + usb_endpoint_num(epd) == MWIFIEX_USB_EP_DATA && + usb_endpoint_xfer_bulk(epd)) { + pr_debug("info: bulk IN: max pkt size: %d, addr: %d\n", + le16_to_cpu(epd->wMaxPacketSize), + epd->bEndpointAddress); + card->rx_data_ep = usb_endpoint_num(epd); + atomic_set(&card->rx_data_urb_pending, 0); + } + if (usb_endpoint_dir_out(epd) && + usb_endpoint_num(epd) == MWIFIEX_USB_EP_DATA && + usb_endpoint_xfer_bulk(epd)) { + pr_debug("info: bulk OUT: max pkt size: %d, addr: %d\n", + le16_to_cpu(epd->wMaxPacketSize), + epd->bEndpointAddress); + card->tx_data_ep = usb_endpoint_num(epd); + atomic_set(&card->tx_data_urb_pending, 0); + } + if (usb_endpoint_dir_out(epd) && + usb_endpoint_num(epd) == MWIFIEX_USB_EP_CMD_EVENT && + usb_endpoint_xfer_bulk(epd)) { + pr_debug("info: bulk OUT: max pkt size: %d, addr: %d\n", + le16_to_cpu(epd->wMaxPacketSize), + epd->bEndpointAddress); + card->tx_cmd_ep = usb_endpoint_num(epd); + atomic_set(&card->tx_cmd_urb_pending, 0); + card->bulk_out_maxpktsize = + le16_to_cpu(epd->wMaxPacketSize); + } + } + + usb_set_intfdata(intf, card); + + ret = mwifiex_add_card(card, &add_remove_card_sem, &usb_ops, + MWIFIEX_USB); + if (ret) { + pr_err("%s: mwifiex_add_card failed: %d\n", __func__, ret); + usb_reset_device(udev); + kfree(card); + return ret; + } + + usb_get_dev(udev); + + return 0; +} + +/* Kernel needs to suspend all functions separately. Therefore all + * registered functions must have drivers with suspend and resume + * methods. Failing that the kernel simply removes the whole card. + * + * If already not suspended, this function allocates and sends a + * 'host sleep activate' request to the firmware and turns off the traffic. + */ +static int mwifiex_usb_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct usb_card_rec *card = usb_get_intfdata(intf); + struct mwifiex_adapter *adapter; + int i; + + if (!card || !card->adapter) { + pr_err("%s: card or card->adapter is NULL\n", __func__); + return 0; + } + adapter = card->adapter; + + if (unlikely(adapter->is_suspended)) + dev_warn(adapter->dev, "Device already suspended\n"); + + mwifiex_enable_hs(adapter); + + /* 'is_suspended' flag indicates device is suspended. + * It must be set here before the usb_kill_urb() calls. Reason + * is in the complete handlers, urb->status(= -ENOENT) and + * this flag is used in combination to distinguish between a + * 'suspended' state and a 'disconnect' one. + */ + adapter->is_suspended = true; + + for (i = 0; i < adapter->priv_num; i++) + netif_carrier_off(adapter->priv[i]->netdev); + + if (atomic_read(&card->rx_cmd_urb_pending) && card->rx_cmd.urb) + usb_kill_urb(card->rx_cmd.urb); + + if (atomic_read(&card->rx_data_urb_pending)) + for (i = 0; i < MWIFIEX_RX_DATA_URB; i++) + if (card->rx_data_list[i].urb) + usb_kill_urb(card->rx_data_list[i].urb); + + for (i = 0; i < MWIFIEX_TX_DATA_URB; i++) + if (card->tx_data_list[i].urb) + usb_kill_urb(card->tx_data_list[i].urb); + + if (card->tx_cmd.urb) + usb_kill_urb(card->tx_cmd.urb); + + return 0; +} + +/* Kernel needs to suspend all functions separately. Therefore all + * registered functions must have drivers with suspend and resume + * methods. Failing that the kernel simply removes the whole card. + * + * If already not resumed, this function turns on the traffic and + * sends a 'host sleep cancel' request to the firmware. + */ +static int mwifiex_usb_resume(struct usb_interface *intf) +{ + struct usb_card_rec *card = usb_get_intfdata(intf); + struct mwifiex_adapter *adapter; + int i; + + if (!card || !card->adapter) { + pr_err("%s: card or card->adapter is NULL\n", __func__); + return 0; + } + adapter = card->adapter; + + if (unlikely(!adapter->is_suspended)) { + dev_warn(adapter->dev, "Device already resumed\n"); + return 0; + } + + /* Indicate device resumed. The netdev queue will be resumed only + * after the urbs have been re-submitted + */ + adapter->is_suspended = false; + + if (!atomic_read(&card->rx_data_urb_pending)) + for (i = 0; i < MWIFIEX_RX_DATA_URB; i++) + mwifiex_usb_submit_rx_urb(&card->rx_data_list[i], + MWIFIEX_RX_DATA_BUF_SIZE); + + if (!atomic_read(&card->rx_cmd_urb_pending)) { + card->rx_cmd.skb = dev_alloc_skb(MWIFIEX_RX_CMD_BUF_SIZE); + if (card->rx_cmd.skb) + mwifiex_usb_submit_rx_urb(&card->rx_cmd, + MWIFIEX_RX_CMD_BUF_SIZE); + } + + for (i = 0; i < adapter->priv_num; i++) + if (adapter->priv[i]->media_connected) + netif_carrier_on(adapter->priv[i]->netdev); + + /* Disable Host Sleep */ + if (adapter->hs_activated) + mwifiex_cancel_hs(mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_ANY), + MWIFIEX_ASYNC_CMD); + +#ifdef CONFIG_PM + /* Resume handler may be called due to remote wakeup, + * force to exit suspend anyway + */ + usb_disable_autosuspend(card->udev); +#endif /* CONFIG_PM */ + + return 0; +} + +static void mwifiex_usb_disconnect(struct usb_interface *intf) +{ + struct usb_card_rec *card = usb_get_intfdata(intf); + struct mwifiex_adapter *adapter; + int i; + + if (!card || !card->adapter) { + pr_err("%s: card or card->adapter is NULL\n", __func__); + return; + } + + adapter = card->adapter; + if (!adapter->priv_num) + return; + + /* In case driver is removed when asynchronous FW downloading is + * in progress + */ + wait_for_completion(&adapter->fw_load); + + if (user_rmmod) { +#ifdef CONFIG_PM + if (adapter->is_suspended) + mwifiex_usb_resume(intf); +#endif + for (i = 0; i < adapter->priv_num; i++) + if ((GET_BSS_ROLE(adapter->priv[i]) == + MWIFIEX_BSS_ROLE_STA) && + adapter->priv[i]->media_connected) + mwifiex_deauthenticate(adapter->priv[i], NULL); + + 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); + + return; +} + +static struct usb_driver mwifiex_usb_driver = { + .name = usbdriver_name, + .probe = mwifiex_usb_probe, + .disconnect = mwifiex_usb_disconnect, + .id_table = mwifiex_usb_table, + .suspend = mwifiex_usb_suspend, + .resume = mwifiex_usb_resume, + .supports_autosuspend = 1, +}; + +static int mwifiex_usb_tx_init(struct mwifiex_adapter *adapter) +{ + struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; + int i; + + card->tx_cmd.adapter = adapter; + card->tx_cmd.ep = card->tx_cmd_ep; + + card->tx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL); + if (!card->tx_cmd.urb) { + dev_err(adapter->dev, "tx_cmd.urb allocation failed\n"); + return -ENOMEM; + } + + card->tx_data_ix = 0; + + for (i = 0; i < MWIFIEX_TX_DATA_URB; i++) { + card->tx_data_list[i].adapter = adapter; + card->tx_data_list[i].ep = card->tx_data_ep; + + card->tx_data_list[i].urb = usb_alloc_urb(0, GFP_KERNEL); + if (!card->tx_data_list[i].urb) { + dev_err(adapter->dev, + "tx_data_list[] urb allocation failed\n"); + return -ENOMEM; + } + } + + return 0; +} + +static int mwifiex_usb_rx_init(struct mwifiex_adapter *adapter) +{ + struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; + int i; + + card->rx_cmd.adapter = adapter; + card->rx_cmd.ep = card->rx_cmd_ep; + + card->rx_cmd.urb = usb_alloc_urb(0, GFP_KERNEL); + if (!card->rx_cmd.urb) { + dev_err(adapter->dev, "rx_cmd.urb allocation failed\n"); + return -ENOMEM; + } + + card->rx_cmd.skb = dev_alloc_skb(MWIFIEX_RX_CMD_BUF_SIZE); + if (!card->rx_cmd.skb) { + dev_err(adapter->dev, "rx_cmd.skb allocation failed\n"); + return -ENOMEM; + } + + if (mwifiex_usb_submit_rx_urb(&card->rx_cmd, MWIFIEX_RX_CMD_BUF_SIZE)) + return -1; + + for (i = 0; i < MWIFIEX_RX_DATA_URB; i++) { + card->rx_data_list[i].adapter = adapter; + card->rx_data_list[i].ep = card->rx_data_ep; + + card->rx_data_list[i].urb = usb_alloc_urb(0, GFP_KERNEL); + if (!card->rx_data_list[i].urb) { + dev_err(adapter->dev, + "rx_data_list[] urb allocation failed\n"); + return -1; + } + if (mwifiex_usb_submit_rx_urb(&card->rx_data_list[i], + MWIFIEX_RX_DATA_BUF_SIZE)) + return -1; + } + + return 0; +} + +static int mwifiex_write_data_sync(struct mwifiex_adapter *adapter, u8 *pbuf, + u32 *len, u8 ep, u32 timeout) +{ + struct usb_card_rec *card = adapter->card; + int actual_length, ret; + + if (!(*len % card->bulk_out_maxpktsize)) + (*len)++; + + /* Send the data block */ + ret = usb_bulk_msg(card->udev, usb_sndbulkpipe(card->udev, ep), pbuf, + *len, &actual_length, timeout); + if (ret) { + dev_err(adapter->dev, "usb_bulk_msg for tx failed: %d\n", ret); + ret = -1; + } + + *len = actual_length; + + return ret; +} + +static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *pbuf, + u32 *len, u8 ep, u32 timeout) +{ + struct usb_card_rec *card = adapter->card; + int actual_length, ret; + + /* Receive the data response */ + ret = usb_bulk_msg(card->udev, usb_rcvbulkpipe(card->udev, ep), pbuf, + *len, &actual_length, timeout); + if (ret) { + dev_err(adapter->dev, "usb_bulk_msg for rx failed: %d\n", ret); + ret = -1; + } + + *len = actual_length; + + return ret; +} + +/* This function write a command/data packet to card. */ +static int mwifiex_usb_host_to_card(struct mwifiex_adapter *adapter, u8 ep, + struct sk_buff *skb, + struct mwifiex_tx_param *tx_param) +{ + struct usb_card_rec *card = adapter->card; + struct urb_context *context; + u8 *data = (u8 *)skb->data; + struct urb *tx_urb; + + if (adapter->is_suspended) { + dev_err(adapter->dev, + "%s: not allowed while suspended\n", __func__); + return -1; + } + + if (adapter->surprise_removed) { + dev_err(adapter->dev, "%s: device removed\n", __func__); + return -1; + } + + if (ep == card->tx_data_ep && + atomic_read(&card->tx_data_urb_pending) >= MWIFIEX_TX_DATA_URB) { + return -EBUSY; + } + + dev_dbg(adapter->dev, "%s: ep=%d\n", __func__, ep); + + if (ep == card->tx_cmd_ep) { + context = &card->tx_cmd; + } else { + if (card->tx_data_ix >= MWIFIEX_TX_DATA_URB) + card->tx_data_ix = 0; + context = &card->tx_data_list[card->tx_data_ix++]; + } + + context->adapter = adapter; + context->ep = ep; + context->skb = skb; + tx_urb = context->urb; + + usb_fill_bulk_urb(tx_urb, card->udev, usb_sndbulkpipe(card->udev, ep), + data, skb->len, mwifiex_usb_tx_complete, + (void *)context); + + tx_urb->transfer_flags |= URB_ZERO_PACKET; + + if (ep == card->tx_cmd_ep) + atomic_inc(&card->tx_cmd_urb_pending); + else + atomic_inc(&card->tx_data_urb_pending); + + if (usb_submit_urb(tx_urb, GFP_ATOMIC)) { + dev_err(adapter->dev, "%s: usb_submit_urb failed\n", __func__); + if (ep == card->tx_cmd_ep) { + atomic_dec(&card->tx_cmd_urb_pending); + } else { + atomic_dec(&card->tx_data_urb_pending); + if (card->tx_data_ix) + card->tx_data_ix--; + else + card->tx_data_ix = MWIFIEX_TX_DATA_URB; + } + + return -1; + } else { + if (ep == card->tx_data_ep && + atomic_read(&card->tx_data_urb_pending) == + MWIFIEX_TX_DATA_URB) + return -ENOSR; + } + + return -EINPROGRESS; +} + +/* This function register usb device and initialize parameter. */ +static int mwifiex_register_dev(struct mwifiex_adapter *adapter) +{ + struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; + + card->adapter = adapter; + adapter->dev = &card->udev->dev; + strcpy(adapter->fw_name, USB8797_DEFAULT_FW_NAME); + + return 0; +} + +/* This function reads one block of firmware data. */ +static int mwifiex_get_fw_data(struct mwifiex_adapter *adapter, + u32 offset, u32 len, u8 *buf) +{ + if (!buf || !len) + return -1; + + if (offset + len > adapter->firmware->size) + return -1; + + memcpy(buf, adapter->firmware->data + offset, len); + + return 0; +} + +static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, + struct mwifiex_fw_image *fw) +{ + int ret = 0; + u8 *firmware = fw->fw_buf, *recv_buff; + u32 retries = USB8797_FW_MAX_RETRY, dlen; + u32 fw_seqnum = 0, tlen = 0, dnld_cmd = 0; + struct fw_data *fwdata; + struct fw_sync_header sync_fw; + u8 check_winner = 1; + + if (!firmware) { + dev_err(adapter->dev, + "No firmware image found! Terminating download\n"); + ret = -1; + goto fw_exit; + } + + /* Allocate memory for transmit */ + fwdata = kzalloc(FW_DNLD_TX_BUF_SIZE, GFP_KERNEL); + if (!fwdata) + goto fw_exit; + + /* Allocate memory for receive */ + recv_buff = kzalloc(FW_DNLD_RX_BUF_SIZE, GFP_KERNEL); + if (!recv_buff) + goto cleanup; + + do { + /* Send pseudo data to check winner status first */ + if (check_winner) { + memset(&fwdata->fw_hdr, 0, sizeof(struct fw_header)); + dlen = 0; + } else { + /* copy the header of the fw_data to get the length */ + if (firmware) + memcpy(&fwdata->fw_hdr, &firmware[tlen], + sizeof(struct fw_header)); + else + mwifiex_get_fw_data(adapter, tlen, + sizeof(struct fw_header), + (u8 *)&fwdata->fw_hdr); + + dlen = le32_to_cpu(fwdata->fw_hdr.data_len); + dnld_cmd = le32_to_cpu(fwdata->fw_hdr.dnld_cmd); + tlen += sizeof(struct fw_header); + + if (firmware) + memcpy(fwdata->data, &firmware[tlen], dlen); + else + mwifiex_get_fw_data(adapter, tlen, dlen, + (u8 *)fwdata->data); + + fwdata->seq_num = cpu_to_le32(fw_seqnum); + tlen += dlen; + } + + /* If the send/receive fails or CRC occurs then retry */ + while (retries--) { + u8 *buf = (u8 *)fwdata; + u32 len = FW_DATA_XMIT_SIZE; + + /* send the firmware block */ + ret = mwifiex_write_data_sync(adapter, buf, &len, + MWIFIEX_USB_EP_CMD_EVENT, + MWIFIEX_USB_TIMEOUT); + if (ret) { + dev_err(adapter->dev, + "write_data_sync: failed: %d\n", ret); + continue; + } + + buf = recv_buff; + len = FW_DNLD_RX_BUF_SIZE; + + /* Receive the firmware block response */ + ret = mwifiex_read_data_sync(adapter, buf, &len, + MWIFIEX_USB_EP_CMD_EVENT, + MWIFIEX_USB_TIMEOUT); + if (ret) { + dev_err(adapter->dev, + "read_data_sync: failed: %d\n", ret); + continue; + } + + memcpy(&sync_fw, recv_buff, + sizeof(struct fw_sync_header)); + + /* check 1st firmware block resp for highest bit set */ + if (check_winner) { + if (le32_to_cpu(sync_fw.cmd) & 0x80000000) { + dev_warn(adapter->dev, + "USB is not the winner %#x\n", + sync_fw.cmd); + + /* returning success */ + ret = 0; + goto cleanup; + } + + dev_dbg(adapter->dev, + "USB is the winner, start to download FW\n"); + + check_winner = 0; + break; + } + + /* check the firmware block response for CRC errors */ + if (sync_fw.cmd) { + dev_err(adapter->dev, + "FW received block with CRC %#x\n", + sync_fw.cmd); + ret = -1; + continue; + } + + retries = USB8797_FW_MAX_RETRY; + break; + } + fw_seqnum++; + } while ((dnld_cmd != FW_HAS_LAST_BLOCK) && retries); + +cleanup: + dev_dbg(adapter->dev, "%s: %d bytes downloaded\n", __func__, tlen); + + kfree(recv_buff); + kfree(fwdata); + + if (retries) + ret = 0; +fw_exit: + return ret; +} + +static int mwifiex_usb_dnld_fw(struct mwifiex_adapter *adapter, + struct mwifiex_fw_image *fw) +{ + int ret; + struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; + + if (card->usb_boot_state == USB8797_FW_DNLD) { + ret = mwifiex_prog_fw_w_helper(adapter, fw); + if (ret) + return -1; + + /* Boot state changes after successful firmware download */ + if (card->usb_boot_state == USB8797_FW_DNLD) + return -1; + } + + ret = mwifiex_usb_rx_init(adapter); + if (!ret) + ret = mwifiex_usb_tx_init(adapter); + + return ret; +} + +static void mwifiex_submit_rx_urb(struct mwifiex_adapter *adapter, u8 ep) +{ + struct usb_card_rec *card = (struct usb_card_rec *)adapter->card; + + skb_push(card->rx_cmd.skb, INTF_HEADER_LEN); + if ((ep == card->rx_cmd_ep) && + (!atomic_read(&card->rx_cmd_urb_pending))) + mwifiex_usb_submit_rx_urb(&card->rx_cmd, + MWIFIEX_RX_CMD_BUF_SIZE); + + return; +} + +static int mwifiex_usb_cmd_event_complete(struct mwifiex_adapter *adapter, + struct sk_buff *skb) +{ + atomic_dec(&adapter->rx_pending); + mwifiex_submit_rx_urb(adapter, MWIFIEX_USB_EP_CMD_EVENT); + + return 0; +} + +static int mwifiex_usb_data_complete(struct mwifiex_adapter *adapter, + struct sk_buff *skb) +{ + atomic_dec(&adapter->rx_pending); + dev_kfree_skb_any(skb); + + return 0; +} + +/* This function wakes up the card. */ +static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter) +{ + /* Simulation of HS_AWAKE event */ + adapter->pm_wakeup_fw_try = false; + adapter->pm_wakeup_card_req = false; + adapter->ps_state = PS_STATE_AWAKE; + + return 0; +} + +static struct mwifiex_if_ops usb_ops = { + .register_dev = mwifiex_register_dev, + .wakeup = mwifiex_pm_wakeup_card, + .wakeup_complete = mwifiex_pm_wakeup_card_complete, + + /* USB specific */ + .dnld_fw = mwifiex_usb_dnld_fw, + .cmdrsp_complete = mwifiex_usb_cmd_event_complete, + .event_complete = mwifiex_usb_cmd_event_complete, + .data_complete = mwifiex_usb_data_complete, + .host_to_card = mwifiex_usb_host_to_card, +}; + +/* This function initializes the USB driver module. + * + * This initiates the semaphore and registers the device with + * USB bus. + */ +static int mwifiex_usb_init_module(void) +{ + int ret; + + pr_debug("Marvell USB8797 Driver\n"); + + sema_init(&add_remove_card_sem, 1); + + ret = usb_register(&mwifiex_usb_driver); + if (ret) + pr_err("Driver register failed!\n"); + else + pr_debug("info: Driver registered successfully!\n"); + + return ret; +} + +/* This function cleans up the USB driver. + * + * The following major steps are followed in .disconnect for cleanup: + * - Resume the device if its suspended + * - Disconnect the device if connected + * - Shutdown the firmware + * - Unregister the device from USB bus. + */ +static void mwifiex_usb_cleanup_module(void) +{ + if (!down_interruptible(&add_remove_card_sem)) + up(&add_remove_card_sem); + + /* set the flag as user is removing this module */ + user_rmmod = 1; + + usb_deregister(&mwifiex_usb_driver); +} + +module_init(mwifiex_usb_init_module); +module_exit(mwifiex_usb_cleanup_module); + +MODULE_AUTHOR("Marvell International Ltd."); +MODULE_DESCRIPTION("Marvell WiFi-Ex USB Driver version" USB_VERSION); +MODULE_VERSION(USB_VERSION); +MODULE_LICENSE("GPL v2"); +MODULE_FIRMWARE("mrvl/usb8797_uapsta.bin"); diff --git a/trunk/drivers/net/wireless/mwifiex/usb.h b/trunk/drivers/net/wireless/mwifiex/usb.h new file mode 100644 index 000000000000..98c4316cd1a9 --- /dev/null +++ b/trunk/drivers/net/wireless/mwifiex/usb.h @@ -0,0 +1,99 @@ +/* + * This file contains definitions for mwifiex USB interface driver. + * + * Copyright (C) 2012, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#ifndef _MWIFIEX_USB_H +#define _MWIFIEX_USB_H + +#include + +#define USB8797_VID 0x1286 +#define USB8797_PID_1 0x2043 +#define USB8797_PID_2 0x2044 + +#define USB8797_FW_DNLD 1 +#define USB8797_FW_READY 2 +#define USB8797_FW_MAX_RETRY 3 + +#define MWIFIEX_TX_DATA_URB 6 +#define MWIFIEX_RX_DATA_URB 6 +#define MWIFIEX_USB_TIMEOUT 100 + +#define USB8797_DEFAULT_FW_NAME "mrvl/usb8797_uapsta.bin" + +#define FW_DNLD_TX_BUF_SIZE 620 +#define FW_DNLD_RX_BUF_SIZE 2048 +#define FW_HAS_LAST_BLOCK 0x00000004 + +#define FW_DATA_XMIT_SIZE \ + (sizeof(struct fw_header) + dlen + sizeof(u32)) + +struct urb_context { + struct mwifiex_adapter *adapter; + struct sk_buff *skb; + struct urb *urb; + u8 ep; +}; + +struct usb_card_rec { + struct mwifiex_adapter *adapter; + struct usb_device *udev; + struct usb_interface *intf; + u8 rx_cmd_ep; + struct urb_context rx_cmd; + atomic_t rx_cmd_urb_pending; + struct urb_context rx_data_list[MWIFIEX_RX_DATA_URB]; + u8 usb_boot_state; + u8 rx_data_ep; + atomic_t rx_data_urb_pending; + u8 tx_data_ep; + u8 tx_cmd_ep; + atomic_t tx_data_urb_pending; + atomic_t tx_cmd_urb_pending; + int bulk_out_maxpktsize; + struct urb_context tx_cmd; + int tx_data_ix; + struct urb_context tx_data_list[MWIFIEX_TX_DATA_URB]; +}; + +struct fw_header { + __le32 dnld_cmd; + __le32 base_addr; + __le32 data_len; + __le32 crc; +}; + +struct fw_sync_header { + __le32 cmd; + __le32 seq_num; +}; + +struct fw_data { + struct fw_header fw_hdr; + __le32 seq_num; + u8 data[1]; +}; + +/* This function is called after the card has woken up. */ +static inline int +mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter) +{ + return 0; +} + +#endif /*_MWIFIEX_USB_H */ diff --git a/trunk/drivers/net/wireless/mwifiex/util.c b/trunk/drivers/net/wireless/mwifiex/util.c index 6b399976d6c8..2864c74bdb6f 100644 --- a/trunk/drivers/net/wireless/mwifiex/util.c +++ b/trunk/drivers/net/wireless/mwifiex/util.c @@ -167,6 +167,28 @@ int mwifiex_recv_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb) skb->dev = priv->netdev; skb->protocol = eth_type_trans(skb, priv->netdev); skb->ip_summed = CHECKSUM_NONE; + + /* This is required only in case of 11n and USB as we alloc + * a buffer of 4K only if its 11N (to be able to receive 4K + * AMSDU packets). In case of SD we allocate buffers based + * on the size of packet and hence this is not needed. + * + * Modifying the truesize here as our allocation for each + * skb is 4K but we only receive 2K packets and this cause + * the kernel to start dropping packets in case where + * application has allocated buffer based on 2K size i.e. + * if there a 64K packet received (in IP fragments and + * application allocates 64K to receive this packet but + * this packet would almost double up because we allocate + * each 1.5K fragment in 4K and pass it up. As soon as the + * 64K limit hits kernel will start to drop rest of the + * fragments. Currently we fail the Filesndl-ht.scr script + * for UDP, hence this fix + */ + if ((adapter->iface_type == MWIFIEX_USB) && + (skb->truesize > MWIFIEX_RX_DATA_BUF_SIZE)) + skb->truesize += (skb->len - MWIFIEX_RX_DATA_BUF_SIZE); + priv->stats.rx_bytes += skb->len; priv->stats.rx_packets++; if (in_interrupt()) diff --git a/trunk/drivers/net/wireless/mwifiex/wmm.c b/trunk/drivers/net/wireless/mwifiex/wmm.c index 5a7316c6f125..429a1dee2d26 100644 --- a/trunk/drivers/net/wireless/mwifiex/wmm.c +++ b/trunk/drivers/net/wireless/mwifiex/wmm.c @@ -1120,11 +1120,19 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv, tx_info = MWIFIEX_SKB_TXCB(skb); spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); - tx_param.next_pkt_len = - ((skb_next) ? skb_next->len + - sizeof(struct txpd) : 0); - ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, skb, - &tx_param); + + if (adapter->iface_type == MWIFIEX_USB) { + adapter->data_sent = true; + ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_USB_EP_DATA, + skb, NULL); + } else { + tx_param.next_pkt_len = + ((skb_next) ? skb_next->len + + sizeof(struct txpd) : 0); + ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, + skb, &tx_param); + } + switch (ret) { case -EBUSY: dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); diff --git a/trunk/drivers/net/wireless/mwl8k.c b/trunk/drivers/net/wireless/mwl8k.c index b48674b577e6..cf7bdc66f822 100644 --- a/trunk/drivers/net/wireless/mwl8k.c +++ b/trunk/drivers/net/wireless/mwl8k.c @@ -1235,7 +1235,7 @@ mwl8k_capture_bssid(struct mwl8k_priv *priv, struct ieee80211_hdr *wh) { return priv->capture_beacon && ieee80211_is_beacon(wh->frame_control) && - !compare_ether_addr(wh->addr3, priv->capture_bssid); + ether_addr_equal(wh->addr3, priv->capture_bssid); } static inline void mwl8k_save_beacon(struct ieee80211_hw *hw, @@ -5893,18 +5893,7 @@ static struct pci_driver mwl8k_driver = { .shutdown = __devexit_p(mwl8k_shutdown), }; -static int __init mwl8k_init(void) -{ - return pci_register_driver(&mwl8k_driver); -} - -static void __exit mwl8k_exit(void) -{ - pci_unregister_driver(&mwl8k_driver); -} - -module_init(mwl8k_init); -module_exit(mwl8k_exit); +module_pci_driver(mwl8k_driver); MODULE_DESCRIPTION(MWL8K_DESC); MODULE_VERSION(MWL8K_VERSION); diff --git a/trunk/drivers/net/wireless/orinoco/fw.c b/trunk/drivers/net/wireless/orinoco/fw.c index 4df8cf64b56c..400a35217644 100644 --- a/trunk/drivers/net/wireless/orinoco/fw.c +++ b/trunk/drivers/net/wireless/orinoco/fw.c @@ -379,11 +379,8 @@ void orinoco_cache_fw(struct orinoco_private *priv, int ap) void orinoco_uncache_fw(struct orinoco_private *priv) { - if (priv->cached_pri_fw) - release_firmware(priv->cached_pri_fw); - if (priv->cached_fw) - release_firmware(priv->cached_fw); - + release_firmware(priv->cached_pri_fw); + release_firmware(priv->cached_fw); priv->cached_pri_fw = NULL; priv->cached_fw = NULL; } diff --git a/trunk/drivers/net/wireless/orinoco/orinoco_usb.c b/trunk/drivers/net/wireless/orinoco/orinoco_usb.c index f634d4582bfe..7f53cea2f205 100644 --- a/trunk/drivers/net/wireless/orinoco/orinoco_usb.c +++ b/trunk/drivers/net/wireless/orinoco/orinoco_usb.c @@ -1752,6 +1752,7 @@ static struct usb_driver orinoco_driver = { .probe = ezusb_probe, .disconnect = ezusb_disconnect, .id_table = ezusb_table, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(orinoco_driver); diff --git a/trunk/drivers/net/wireless/p54/main.c b/trunk/drivers/net/wireless/p54/main.c index ee8af1f047c8..7cffea795ad2 100644 --- a/trunk/drivers/net/wireless/p54/main.c +++ b/trunk/drivers/net/wireless/p54/main.c @@ -796,11 +796,14 @@ int p54_register_common(struct ieee80211_hw *dev, struct device *pdev) dev_err(pdev, "Cannot register device (%d).\n", err); return err; } + priv->registered = true; #ifdef CONFIG_P54_LEDS err = p54_init_leds(priv); - if (err) + if (err) { + p54_unregister_common(dev); return err; + } #endif /* CONFIG_P54_LEDS */ dev_info(pdev, "is registered as '%s'\n", wiphy_name(dev->wiphy)); @@ -840,7 +843,11 @@ void p54_unregister_common(struct ieee80211_hw *dev) p54_unregister_leds(priv); #endif /* CONFIG_P54_LEDS */ - ieee80211_unregister_hw(dev); + if (priv->registered) { + priv->registered = false; + ieee80211_unregister_hw(dev); + } + mutex_destroy(&priv->conf_mutex); mutex_destroy(&priv->eeprom_mutex); } diff --git a/trunk/drivers/net/wireless/p54/p54.h b/trunk/drivers/net/wireless/p54/p54.h index 452fa3a64aa1..40b401ed6845 100644 --- a/trunk/drivers/net/wireless/p54/p54.h +++ b/trunk/drivers/net/wireless/p54/p54.h @@ -173,6 +173,7 @@ struct p54_common { struct sk_buff_head tx_pending; struct sk_buff_head tx_queue; struct mutex conf_mutex; + bool registered; /* memory management (as seen by the firmware) */ u32 rx_start; diff --git a/trunk/drivers/net/wireless/p54/p54pci.c b/trunk/drivers/net/wireless/p54/p54pci.c index 45df728183fd..89318adc8c7f 100644 --- a/trunk/drivers/net/wireless/p54/p54pci.c +++ b/trunk/drivers/net/wireless/p54/p54pci.c @@ -667,15 +667,4 @@ static struct pci_driver p54p_driver = { .driver.pm = P54P_PM_OPS, }; -static int __init p54p_init(void) -{ - return pci_register_driver(&p54p_driver); -} - -static void __exit p54p_exit(void) -{ - pci_unregister_driver(&p54p_driver); -} - -module_init(p54p_init); -module_exit(p54p_exit); +module_pci_driver(p54p_driver); diff --git a/trunk/drivers/net/wireless/p54/p54usb.c b/trunk/drivers/net/wireless/p54/p54usb.c index f4d28c39aac7..7f207b6e9552 100644 --- a/trunk/drivers/net/wireless/p54/p54usb.c +++ b/trunk/drivers/net/wireless/p54/p54usb.c @@ -117,21 +117,18 @@ static const struct { u32 intf; enum p54u_hw_type type; const char *fw; - const char *fw_legacy; char hw[20]; } p54u_fwlist[__NUM_P54U_HWTYPES] = { { .type = P54U_NET2280, .intf = FW_LM86, .fw = "isl3886usb", - .fw_legacy = "isl3890usb", .hw = "ISL3886 + net2280", }, { .type = P54U_3887, .intf = FW_LM87, .fw = "isl3887usb", - .fw_legacy = "isl3887usb_bare", .hw = "ISL3887", }, }; @@ -208,6 +205,16 @@ static void p54u_free_urbs(struct ieee80211_hw *dev) usb_kill_anchored_urbs(&priv->submitted); } +static void p54u_stop(struct ieee80211_hw *dev) +{ + /* + * TODO: figure out how to reliably stop the 3887 and net2280 so + * the hardware is still usable next time we want to start it. + * until then, we just stop listening to the hardware.. + */ + p54u_free_urbs(dev); +} + static int p54u_init_urbs(struct ieee80211_hw *dev) { struct p54u_priv *priv = dev->priv; @@ -257,6 +264,16 @@ static int p54u_init_urbs(struct ieee80211_hw *dev) return ret; } +static int p54u_open(struct ieee80211_hw *dev) +{ + /* + * TODO: Because we don't know how to reliably stop the 3887 and + * the isl3886+net2280, other than brutally cut off all + * communications. We have to reinitialize the urbs on every start. + */ + return p54u_init_urbs(dev); +} + static __le32 p54u_lm87_chksum(const __le32 *data, size_t length) { u32 chk = 0; @@ -836,70 +853,137 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) return err; } -static int p54u_load_firmware(struct ieee80211_hw *dev) +static int p54_find_type(struct p54u_priv *priv) { - struct p54u_priv *priv = dev->priv; - int err, i; - - BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES); + int i; for (i = 0; i < __NUM_P54U_HWTYPES; i++) if (p54u_fwlist[i].type == priv->hw_type) break; - if (i == __NUM_P54U_HWTYPES) return -EOPNOTSUPP; - err = request_firmware(&priv->fw, p54u_fwlist[i].fw, &priv->udev->dev); - if (err) { - dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s " - "(%d)!\n", p54u_fwlist[i].fw, err); + return i; +} - err = request_firmware(&priv->fw, p54u_fwlist[i].fw_legacy, - &priv->udev->dev); - if (err) - return err; - } +static int p54u_start_ops(struct p54u_priv *priv) +{ + struct ieee80211_hw *dev = priv->common.hw; + int ret; - err = p54_parse_firmware(dev, priv->fw); - if (err) - goto out; + ret = p54_parse_firmware(dev, priv->fw); + if (ret) + goto err_out; + + ret = p54_find_type(priv); + if (ret < 0) + goto err_out; - if (priv->common.fw_interface != p54u_fwlist[i].intf) { + if (priv->common.fw_interface != p54u_fwlist[ret].intf) { dev_err(&priv->udev->dev, "wrong firmware, please get " "a firmware for \"%s\" and try again.\n", - p54u_fwlist[i].hw); - err = -EINVAL; + p54u_fwlist[ret].hw); + ret = -ENODEV; + goto err_out; } -out: - if (err) - release_firmware(priv->fw); + ret = priv->upload_fw(dev); + if (ret) + goto err_out; - return err; + ret = p54u_open(dev); + if (ret) + goto err_out; + + ret = p54_read_eeprom(dev); + if (ret) + goto err_stop; + + p54u_stop(dev); + + ret = p54_register_common(dev, &priv->udev->dev); + if (ret) + goto err_stop; + + return 0; + +err_stop: + p54u_stop(dev); + +err_out: + /* + * p54u_disconnect will do the rest of the + * cleanup + */ + return ret; } -static int p54u_open(struct ieee80211_hw *dev) +static void p54u_load_firmware_cb(const struct firmware *firmware, + void *context) { - struct p54u_priv *priv = dev->priv; + struct p54u_priv *priv = context; + struct usb_device *udev = priv->udev; int err; - err = p54u_init_urbs(dev); - if (err) { - return err; + complete(&priv->fw_wait_load); + if (firmware) { + priv->fw = firmware; + err = p54u_start_ops(priv); + } else { + err = -ENOENT; + dev_err(&udev->dev, "Firmware not found.\n"); } - priv->common.open = p54u_init_urbs; + if (err) { + struct device *parent = priv->udev->dev.parent; - return 0; + dev_err(&udev->dev, "failed to initialize device (%d)\n", err); + + if (parent) + device_lock(parent); + + device_release_driver(&udev->dev); + /* + * At this point p54u_disconnect has already freed + * the "priv" context. Do not use it anymore! + */ + priv = NULL; + + if (parent) + device_unlock(parent); + } + + usb_put_dev(udev); } -static void p54u_stop(struct ieee80211_hw *dev) +static int p54u_load_firmware(struct ieee80211_hw *dev, + struct usb_interface *intf) { - /* TODO: figure out how to reliably stop the 3887 and net2280 so - the hardware is still usable next time we want to start it. - until then, we just stop listening to the hardware.. */ - p54u_free_urbs(dev); + struct usb_device *udev = interface_to_usbdev(intf); + struct p54u_priv *priv = dev->priv; + struct device *device = &udev->dev; + int err, i; + + BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES); + + init_completion(&priv->fw_wait_load); + i = p54_find_type(priv); + if (i < 0) + return i; + + dev_info(&priv->udev->dev, "Loading firmware file %s\n", + p54u_fwlist[i].fw); + + usb_get_dev(udev); + err = request_firmware_nowait(THIS_MODULE, 1, p54u_fwlist[i].fw, + device, GFP_KERNEL, priv, + p54u_load_firmware_cb); + if (err) { + dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s " + "(%d)!\n", p54u_fwlist[i].fw, err); + } + + return err; } static int __devinit p54u_probe(struct usb_interface *intf, @@ -969,33 +1053,7 @@ static int __devinit p54u_probe(struct usb_interface *intf, priv->common.tx = p54u_tx_net2280; priv->upload_fw = p54u_upload_firmware_net2280; } - err = p54u_load_firmware(dev); - if (err) - goto err_free_dev; - - err = priv->upload_fw(dev); - if (err) - goto err_free_fw; - - p54u_open(dev); - err = p54_read_eeprom(dev); - p54u_stop(dev); - if (err) - goto err_free_fw; - - err = p54_register_common(dev, &udev->dev); - if (err) - goto err_free_fw; - - return 0; - -err_free_fw: - release_firmware(priv->fw); - -err_free_dev: - p54_free_common(dev); - usb_set_intfdata(intf, NULL); - usb_put_dev(udev); + err = p54u_load_firmware(dev, intf); return err; } @@ -1007,9 +1065,10 @@ static void __devexit p54u_disconnect(struct usb_interface *intf) if (!dev) return; + priv = dev->priv; + wait_for_completion(&priv->fw_wait_load); p54_unregister_common(dev); - priv = dev->priv; usb_put_dev(interface_to_usbdev(intf)); release_firmware(priv->fw); p54_free_common(dev); @@ -1072,7 +1131,7 @@ static struct usb_driver p54u_driver = { .name = "p54usb", .id_table = p54u_table, .probe = p54u_probe, - .disconnect = p54u_disconnect, + .disconnect = __devexit_p(p54u_disconnect), .pre_reset = p54u_pre_reset, .post_reset = p54u_post_reset, #ifdef CONFIG_PM @@ -1081,6 +1140,7 @@ static struct usb_driver p54u_driver = { .reset_resume = p54u_resume, #endif /* CONFIG_PM */ .soft_unbind = 1, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(p54u_driver); diff --git a/trunk/drivers/net/wireless/p54/p54usb.h b/trunk/drivers/net/wireless/p54/p54usb.h index ed4034ade59a..d273be7272b9 100644 --- a/trunk/drivers/net/wireless/p54/p54usb.h +++ b/trunk/drivers/net/wireless/p54/p54usb.h @@ -143,6 +143,9 @@ struct p54u_priv { struct sk_buff_head rx_queue; struct usb_anchor submitted; const struct firmware *fw; + + /* asynchronous firmware callback */ + struct completion fw_wait_load; }; #endif /* P54USB_H */ diff --git a/trunk/drivers/net/wireless/p54/txrx.c b/trunk/drivers/net/wireless/p54/txrx.c index a08a6f0e4dd1..82a1cac920bd 100644 --- a/trunk/drivers/net/wireless/p54/txrx.c +++ b/trunk/drivers/net/wireless/p54/txrx.c @@ -308,7 +308,7 @@ static void p54_pspoll_workaround(struct p54_common *priv, struct sk_buff *skb) return; /* only consider beacons from the associated BSSID */ - if (compare_ether_addr(hdr->addr3, priv->bssid)) + if (!ether_addr_equal(hdr->addr3, priv->bssid)) return; tim = p54_find_ie(skb, WLAN_EID_TIM); @@ -914,8 +914,7 @@ void p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb) txhdr->hw_queue = queue; txhdr->backlog = priv->tx_stats[queue].len - 1; memset(txhdr->durations, 0, sizeof(txhdr->durations)); - txhdr->tx_antenna = ((info->antenna_sel_tx == 0) ? - 2 : info->antenna_sel_tx - 1) & priv->tx_diversity_mask; + txhdr->tx_antenna = 2 & priv->tx_diversity_mask; if (priv->rxhw == 5) { txhdr->longbow.cts_rate = cts_rate; txhdr->longbow.output_power = cpu_to_le16(priv->output_power); diff --git a/trunk/drivers/net/wireless/prism54/oid_mgt.c b/trunk/drivers/net/wireless/prism54/oid_mgt.c index 9b796cae4afe..a01606b36e03 100644 --- a/trunk/drivers/net/wireless/prism54/oid_mgt.c +++ b/trunk/drivers/net/wireless/prism54/oid_mgt.c @@ -693,8 +693,6 @@ mgt_update_addr(islpci_private *priv) return ret; } -#define VEC_SIZE(a) ARRAY_SIZE(a) - int mgt_commit(islpci_private *priv) { @@ -704,10 +702,10 @@ mgt_commit(islpci_private *priv) if (islpci_get_state(priv) < PRV_STATE_INIT) return 0; - rvalue = mgt_commit_list(priv, commit_part1, VEC_SIZE(commit_part1)); + rvalue = mgt_commit_list(priv, commit_part1, ARRAY_SIZE(commit_part1)); if (priv->iw_mode != IW_MODE_MONITOR) - rvalue |= mgt_commit_list(priv, commit_part2, VEC_SIZE(commit_part2)); + rvalue |= mgt_commit_list(priv, commit_part2, ARRAY_SIZE(commit_part2)); u = OID_INL_MODE; rvalue |= mgt_commit_list(priv, &u, 1); diff --git a/trunk/drivers/net/wireless/rndis_wlan.c b/trunk/drivers/net/wireless/rndis_wlan.c index d66e2980bc27..c5404eb82b2f 100644 --- a/trunk/drivers/net/wireless/rndis_wlan.c +++ b/trunk/drivers/net/wireless/rndis_wlan.c @@ -88,49 +88,6 @@ module_param_named(workaround_interval, modparam_workaround_interval, MODULE_PARM_DESC(workaround_interval, "set stall workaround interval in msecs (0=disabled) (default: 0)"); - -/* various RNDIS OID defs */ -#define OID_GEN_LINK_SPEED cpu_to_le32(0x00010107) -#define OID_GEN_RNDIS_CONFIG_PARAMETER cpu_to_le32(0x0001021b) - -#define OID_GEN_XMIT_OK cpu_to_le32(0x00020101) -#define OID_GEN_RCV_OK cpu_to_le32(0x00020102) -#define OID_GEN_XMIT_ERROR cpu_to_le32(0x00020103) -#define OID_GEN_RCV_ERROR cpu_to_le32(0x00020104) -#define OID_GEN_RCV_NO_BUFFER cpu_to_le32(0x00020105) - -#define OID_802_3_CURRENT_ADDRESS cpu_to_le32(0x01010102) -#define OID_802_3_MULTICAST_LIST cpu_to_le32(0x01010103) -#define OID_802_3_MAXIMUM_LIST_SIZE cpu_to_le32(0x01010104) - -#define OID_802_11_BSSID cpu_to_le32(0x0d010101) -#define OID_802_11_SSID cpu_to_le32(0x0d010102) -#define OID_802_11_INFRASTRUCTURE_MODE cpu_to_le32(0x0d010108) -#define OID_802_11_ADD_WEP cpu_to_le32(0x0d010113) -#define OID_802_11_REMOVE_WEP cpu_to_le32(0x0d010114) -#define OID_802_11_DISASSOCIATE cpu_to_le32(0x0d010115) -#define OID_802_11_AUTHENTICATION_MODE cpu_to_le32(0x0d010118) -#define OID_802_11_PRIVACY_FILTER cpu_to_le32(0x0d010119) -#define OID_802_11_BSSID_LIST_SCAN cpu_to_le32(0x0d01011a) -#define OID_802_11_ENCRYPTION_STATUS cpu_to_le32(0x0d01011b) -#define OID_802_11_ADD_KEY cpu_to_le32(0x0d01011d) -#define OID_802_11_REMOVE_KEY cpu_to_le32(0x0d01011e) -#define OID_802_11_ASSOCIATION_INFORMATION cpu_to_le32(0x0d01011f) -#define OID_802_11_CAPABILITY cpu_to_le32(0x0d010122) -#define OID_802_11_PMKID cpu_to_le32(0x0d010123) -#define OID_802_11_NETWORK_TYPES_SUPPORTED cpu_to_le32(0x0d010203) -#define OID_802_11_NETWORK_TYPE_IN_USE cpu_to_le32(0x0d010204) -#define OID_802_11_TX_POWER_LEVEL cpu_to_le32(0x0d010205) -#define OID_802_11_RSSI cpu_to_le32(0x0d010206) -#define OID_802_11_RSSI_TRIGGER cpu_to_le32(0x0d010207) -#define OID_802_11_FRAGMENTATION_THRESHOLD cpu_to_le32(0x0d010209) -#define OID_802_11_RTS_THRESHOLD cpu_to_le32(0x0d01020a) -#define OID_802_11_SUPPORTED_RATES cpu_to_le32(0x0d01020e) -#define OID_802_11_CONFIGURATION cpu_to_le32(0x0d010211) -#define OID_802_11_POWER_MODE cpu_to_le32(0x0d010216) -#define OID_802_11_BSSID_LIST cpu_to_le32(0x0d010217) - - /* Typical noise/maximum signal level values taken from ndiswrapper iw_ndis.h */ #define WL_NOISE -96 /* typical noise level in dBm */ #define WL_SIGMAX -32 /* typical maximum signal level in dBm */ @@ -149,12 +106,6 @@ MODULE_PARM_DESC(workaround_interval, #define BCM4320_DEFAULT_TXPOWER_DBM_50 10 #define BCM4320_DEFAULT_TXPOWER_DBM_25 7 - -/* codes for "status" field of completion messages */ -#define RNDIS_STATUS_ADAPTER_NOT_READY cpu_to_le32(0xc0010011) -#define RNDIS_STATUS_ADAPTER_NOT_OPEN cpu_to_le32(0xc0010012) - - /* Known device types */ #define RNDIS_UNKNOWN 0 #define RNDIS_BCM4320A 1 @@ -515,7 +466,7 @@ struct rndis_wlan_private { int infra_mode; bool connected; u8 bssid[ETH_ALEN]; - __le32 current_command_oid; + u32 current_command_oid; /* encryption stuff */ u8 encr_tx_key_index; @@ -670,63 +621,63 @@ static int rndis_akm_suite_to_key_mgmt(u32 akm_suite) } #ifdef DEBUG -static const char *oid_to_string(__le32 oid) +static const char *oid_to_string(u32 oid) { switch (oid) { #define OID_STR(oid) case oid: return(#oid) /* from rndis_host.h */ - OID_STR(OID_802_3_PERMANENT_ADDRESS); - OID_STR(OID_GEN_MAXIMUM_FRAME_SIZE); - OID_STR(OID_GEN_CURRENT_PACKET_FILTER); - OID_STR(OID_GEN_PHYSICAL_MEDIUM); + OID_STR(RNDIS_OID_802_3_PERMANENT_ADDRESS); + OID_STR(RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE); + OID_STR(RNDIS_OID_GEN_CURRENT_PACKET_FILTER); + OID_STR(RNDIS_OID_GEN_PHYSICAL_MEDIUM); /* from rndis_wlan.c */ - OID_STR(OID_GEN_LINK_SPEED); - OID_STR(OID_GEN_RNDIS_CONFIG_PARAMETER); - - OID_STR(OID_GEN_XMIT_OK); - OID_STR(OID_GEN_RCV_OK); - OID_STR(OID_GEN_XMIT_ERROR); - OID_STR(OID_GEN_RCV_ERROR); - OID_STR(OID_GEN_RCV_NO_BUFFER); - - OID_STR(OID_802_3_CURRENT_ADDRESS); - OID_STR(OID_802_3_MULTICAST_LIST); - OID_STR(OID_802_3_MAXIMUM_LIST_SIZE); - - OID_STR(OID_802_11_BSSID); - OID_STR(OID_802_11_SSID); - OID_STR(OID_802_11_INFRASTRUCTURE_MODE); - OID_STR(OID_802_11_ADD_WEP); - OID_STR(OID_802_11_REMOVE_WEP); - OID_STR(OID_802_11_DISASSOCIATE); - OID_STR(OID_802_11_AUTHENTICATION_MODE); - OID_STR(OID_802_11_PRIVACY_FILTER); - OID_STR(OID_802_11_BSSID_LIST_SCAN); - OID_STR(OID_802_11_ENCRYPTION_STATUS); - OID_STR(OID_802_11_ADD_KEY); - OID_STR(OID_802_11_REMOVE_KEY); - OID_STR(OID_802_11_ASSOCIATION_INFORMATION); - OID_STR(OID_802_11_CAPABILITY); - OID_STR(OID_802_11_PMKID); - OID_STR(OID_802_11_NETWORK_TYPES_SUPPORTED); - OID_STR(OID_802_11_NETWORK_TYPE_IN_USE); - OID_STR(OID_802_11_TX_POWER_LEVEL); - OID_STR(OID_802_11_RSSI); - OID_STR(OID_802_11_RSSI_TRIGGER); - OID_STR(OID_802_11_FRAGMENTATION_THRESHOLD); - OID_STR(OID_802_11_RTS_THRESHOLD); - OID_STR(OID_802_11_SUPPORTED_RATES); - OID_STR(OID_802_11_CONFIGURATION); - OID_STR(OID_802_11_POWER_MODE); - OID_STR(OID_802_11_BSSID_LIST); + OID_STR(RNDIS_OID_GEN_LINK_SPEED); + OID_STR(RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER); + + OID_STR(RNDIS_OID_GEN_XMIT_OK); + OID_STR(RNDIS_OID_GEN_RCV_OK); + OID_STR(RNDIS_OID_GEN_XMIT_ERROR); + OID_STR(RNDIS_OID_GEN_RCV_ERROR); + OID_STR(RNDIS_OID_GEN_RCV_NO_BUFFER); + + OID_STR(RNDIS_OID_802_3_CURRENT_ADDRESS); + OID_STR(RNDIS_OID_802_3_MULTICAST_LIST); + OID_STR(RNDIS_OID_802_3_MAXIMUM_LIST_SIZE); + + OID_STR(RNDIS_OID_802_11_BSSID); + OID_STR(RNDIS_OID_802_11_SSID); + OID_STR(RNDIS_OID_802_11_INFRASTRUCTURE_MODE); + OID_STR(RNDIS_OID_802_11_ADD_WEP); + OID_STR(RNDIS_OID_802_11_REMOVE_WEP); + OID_STR(RNDIS_OID_802_11_DISASSOCIATE); + OID_STR(RNDIS_OID_802_11_AUTHENTICATION_MODE); + OID_STR(RNDIS_OID_802_11_PRIVACY_FILTER); + OID_STR(RNDIS_OID_802_11_BSSID_LIST_SCAN); + OID_STR(RNDIS_OID_802_11_ENCRYPTION_STATUS); + OID_STR(RNDIS_OID_802_11_ADD_KEY); + OID_STR(RNDIS_OID_802_11_REMOVE_KEY); + OID_STR(RNDIS_OID_802_11_ASSOCIATION_INFORMATION); + OID_STR(RNDIS_OID_802_11_CAPABILITY); + OID_STR(RNDIS_OID_802_11_PMKID); + OID_STR(RNDIS_OID_802_11_NETWORK_TYPES_SUPPORTED); + OID_STR(RNDIS_OID_802_11_NETWORK_TYPE_IN_USE); + OID_STR(RNDIS_OID_802_11_TX_POWER_LEVEL); + OID_STR(RNDIS_OID_802_11_RSSI); + OID_STR(RNDIS_OID_802_11_RSSI_TRIGGER); + OID_STR(RNDIS_OID_802_11_FRAGMENTATION_THRESHOLD); + OID_STR(RNDIS_OID_802_11_RTS_THRESHOLD); + OID_STR(RNDIS_OID_802_11_SUPPORTED_RATES); + OID_STR(RNDIS_OID_802_11_CONFIGURATION); + OID_STR(RNDIS_OID_802_11_POWER_MODE); + OID_STR(RNDIS_OID_802_11_BSSID_LIST); #undef OID_STR } return "?"; } #else -static const char *oid_to_string(__le32 oid) +static const char *oid_to_string(u32 oid) { return "?"; } @@ -736,7 +687,7 @@ static const char *oid_to_string(__le32 oid) static int rndis_error_status(__le32 rndis_status) { int ret = -EINVAL; - switch (rndis_status) { + switch (le32_to_cpu(rndis_status)) { case RNDIS_STATUS_SUCCESS: ret = 0; break; @@ -755,7 +706,7 @@ static int rndis_error_status(__le32 rndis_status) return ret; } -static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) +static int rndis_query_oid(struct usbnet *dev, u32 oid, void *data, int *len) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev); union { @@ -782,9 +733,9 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) mutex_lock(&priv->command_lock); memset(u.get, 0, sizeof *u.get); - u.get->msg_type = RNDIS_MSG_QUERY; + u.get->msg_type = cpu_to_le32(RNDIS_MSG_QUERY); u.get->msg_len = cpu_to_le32(sizeof *u.get); - u.get->oid = oid; + u.get->oid = cpu_to_le32(oid); priv->current_command_oid = oid; ret = rndis_command(dev, u.header, buflen); @@ -839,7 +790,7 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) return ret; } -static int rndis_set_oid(struct usbnet *dev, __le32 oid, const void *data, +static int rndis_set_oid(struct usbnet *dev, u32 oid, const void *data, int len) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev); @@ -866,9 +817,9 @@ static int rndis_set_oid(struct usbnet *dev, __le32 oid, const void *data, mutex_lock(&priv->command_lock); memset(u.set, 0, sizeof *u.set); - u.set->msg_type = RNDIS_MSG_SET; + u.set->msg_type = cpu_to_le32(RNDIS_MSG_SET); u.set->msg_len = cpu_to_le32(sizeof(*u.set) + len); - u.set->oid = oid; + u.set->oid = cpu_to_le32(oid); u.set->len = cpu_to_le32(len); u.set->offset = cpu_to_le32(sizeof(*u.set) - 8); u.set->handle = cpu_to_le32(0); @@ -908,7 +859,7 @@ static int rndis_reset(struct usbnet *usbdev) reset = (void *)priv->command_buffer; memset(reset, 0, sizeof(*reset)); - reset->msg_type = RNDIS_MSG_RESET; + reset->msg_type = cpu_to_le32(RNDIS_MSG_RESET); reset->msg_len = cpu_to_le32(sizeof(*reset)); priv->current_command_oid = 0; ret = rndis_command(usbdev, (void *)reset, CONTROL_BUFFER_SIZE); @@ -994,7 +945,7 @@ static int rndis_set_config_parameter(struct usbnet *dev, char *param, } #endif - ret = rndis_set_oid(dev, OID_GEN_RNDIS_CONFIG_PARAMETER, + ret = rndis_set_oid(dev, RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER, infobuf, info_len); if (ret != 0) netdev_dbg(dev->net, "setting rndis config parameter failed, %d\n", @@ -1031,9 +982,9 @@ static int rndis_start_bssid_list_scan(struct usbnet *usbdev) { __le32 tmp; - /* Note: OID_802_11_BSSID_LIST_SCAN clears internal BSS list. */ + /* Note: RNDIS_OID_802_11_BSSID_LIST_SCAN clears internal BSS list. */ tmp = cpu_to_le32(1); - return rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp, + return rndis_set_oid(usbdev, RNDIS_OID_802_11_BSSID_LIST_SCAN, &tmp, sizeof(tmp)); } @@ -1042,7 +993,8 @@ static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int ret; - ret = rndis_set_oid(usbdev, OID_802_11_SSID, ssid, sizeof(*ssid)); + ret = rndis_set_oid(usbdev, RNDIS_OID_802_11_SSID, + ssid, sizeof(*ssid)); if (ret < 0) { netdev_warn(usbdev->net, "setting SSID failed (%08X)\n", ret); return ret; @@ -1059,7 +1011,8 @@ static int set_bssid(struct usbnet *usbdev, const u8 *bssid) { int ret; - ret = rndis_set_oid(usbdev, OID_802_11_BSSID, bssid, ETH_ALEN); + ret = rndis_set_oid(usbdev, RNDIS_OID_802_11_BSSID, + bssid, ETH_ALEN); if (ret < 0) { netdev_warn(usbdev->net, "setting BSSID[%pM] failed (%08X)\n", bssid, ret); @@ -1083,7 +1036,8 @@ static int get_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN]) int ret, len; len = ETH_ALEN; - ret = rndis_query_oid(usbdev, OID_802_11_BSSID, bssid, &len); + ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_BSSID, + bssid, &len); if (ret != 0) memset(bssid, 0, ETH_ALEN); @@ -1094,8 +1048,9 @@ static int get_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN]) static int get_association_info(struct usbnet *usbdev, struct ndis_80211_assoc_info *info, int len) { - return rndis_query_oid(usbdev, OID_802_11_ASSOCIATION_INFORMATION, - info, &len); + return rndis_query_oid(usbdev, + RNDIS_OID_802_11_ASSOCIATION_INFORMATION, + info, &len); } static bool is_associated(struct usbnet *usbdev) @@ -1119,7 +1074,9 @@ static int disassociate(struct usbnet *usbdev, bool reset_ssid) int i, ret = 0; if (priv->radio_on) { - ret = rndis_set_oid(usbdev, OID_802_11_DISASSOCIATE, NULL, 0); + ret = rndis_set_oid(usbdev, + RNDIS_OID_802_11_DISASSOCIATE, + NULL, 0); if (ret == 0) { priv->radio_on = false; netdev_dbg(usbdev->net, "%s(): radio_on = false\n", @@ -1181,8 +1138,9 @@ static int set_auth_mode(struct usbnet *usbdev, u32 wpa_version, return -ENOTSUPP; tmp = cpu_to_le32(auth_mode); - ret = rndis_set_oid(usbdev, OID_802_11_AUTHENTICATION_MODE, &tmp, - sizeof(tmp)); + ret = rndis_set_oid(usbdev, + RNDIS_OID_802_11_AUTHENTICATION_MODE, + &tmp, sizeof(tmp)); if (ret != 0) { netdev_warn(usbdev->net, "setting auth mode failed (%08X)\n", ret); @@ -1208,8 +1166,9 @@ static int set_priv_filter(struct usbnet *usbdev) else tmp = cpu_to_le32(NDIS_80211_PRIV_ACCEPT_ALL); - return rndis_set_oid(usbdev, OID_802_11_PRIVACY_FILTER, &tmp, - sizeof(tmp)); + return rndis_set_oid(usbdev, + RNDIS_OID_802_11_PRIVACY_FILTER, &tmp, + sizeof(tmp)); } static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) @@ -1234,8 +1193,9 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise) encr_mode = NDIS_80211_ENCR_DISABLED; tmp = cpu_to_le32(encr_mode); - ret = rndis_set_oid(usbdev, OID_802_11_ENCRYPTION_STATUS, &tmp, - sizeof(tmp)); + ret = rndis_set_oid(usbdev, + RNDIS_OID_802_11_ENCRYPTION_STATUS, &tmp, + sizeof(tmp)); if (ret != 0) { netdev_warn(usbdev->net, "setting encr mode failed (%08X)\n", ret); @@ -1255,8 +1215,9 @@ static int set_infra_mode(struct usbnet *usbdev, int mode) __func__, priv->infra_mode); tmp = cpu_to_le32(mode); - ret = rndis_set_oid(usbdev, OID_802_11_INFRASTRUCTURE_MODE, &tmp, - sizeof(tmp)); + ret = rndis_set_oid(usbdev, + RNDIS_OID_802_11_INFRASTRUCTURE_MODE, + &tmp, sizeof(tmp)); if (ret != 0) { netdev_warn(usbdev->net, "setting infra mode failed (%08X)\n", ret); @@ -1282,8 +1243,9 @@ static int set_rts_threshold(struct usbnet *usbdev, u32 rts_threshold) rts_threshold = 2347; tmp = cpu_to_le32(rts_threshold); - return rndis_set_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp, - sizeof(tmp)); + return rndis_set_oid(usbdev, + RNDIS_OID_802_11_RTS_THRESHOLD, + &tmp, sizeof(tmp)); } static int set_frag_threshold(struct usbnet *usbdev, u32 frag_threshold) @@ -1296,8 +1258,9 @@ static int set_frag_threshold(struct usbnet *usbdev, u32 frag_threshold) frag_threshold = 2346; tmp = cpu_to_le32(frag_threshold); - return rndis_set_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp, - sizeof(tmp)); + return rndis_set_oid(usbdev, + RNDIS_OID_802_11_FRAGMENTATION_THRESHOLD, + &tmp, sizeof(tmp)); } static void set_default_iw_params(struct usbnet *usbdev) @@ -1333,7 +1296,9 @@ static int set_channel(struct usbnet *usbdev, int channel) dsconfig = ieee80211_dsss_chan_to_freq(channel) * 1000; len = sizeof(config); - ret = rndis_query_oid(usbdev, OID_802_11_CONFIGURATION, &config, &len); + ret = rndis_query_oid(usbdev, + RNDIS_OID_802_11_CONFIGURATION, + &config, &len); if (ret < 0) { netdev_dbg(usbdev->net, "%s(): querying configuration failed\n", __func__); @@ -1341,8 +1306,9 @@ static int set_channel(struct usbnet *usbdev, int channel) } config.ds_config = cpu_to_le32(dsconfig); - ret = rndis_set_oid(usbdev, OID_802_11_CONFIGURATION, &config, - sizeof(config)); + ret = rndis_set_oid(usbdev, + RNDIS_OID_802_11_CONFIGURATION, + &config, sizeof(config)); netdev_dbg(usbdev->net, "%s(): %d -> %d\n", __func__, channel, ret); @@ -1359,8 +1325,10 @@ static struct ieee80211_channel *get_current_channel(struct usbnet *usbdev, /* Get channel and beacon interval */ len = sizeof(config); - ret = rndis_query_oid(usbdev, OID_802_11_CONFIGURATION, &config, &len); - netdev_dbg(usbdev->net, "%s(): OID_802_11_CONFIGURATION -> %d\n", + ret = rndis_query_oid(usbdev, + RNDIS_OID_802_11_CONFIGURATION, + &config, &len); + netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_CONFIGURATION -> %d\n", __func__, ret); if (ret < 0) return NULL; @@ -1413,8 +1381,9 @@ static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len, ret); } - ret = rndis_set_oid(usbdev, OID_802_11_ADD_WEP, &ndis_key, - sizeof(ndis_key)); + ret = rndis_set_oid(usbdev, + RNDIS_OID_802_11_ADD_WEP, &ndis_key, + sizeof(ndis_key)); if (ret != 0) { netdev_warn(usbdev->net, "adding encryption key %d failed (%08X)\n", index + 1, ret); @@ -1504,9 +1473,10 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, get_bssid(usbdev, ndis_key.bssid); } - ret = rndis_set_oid(usbdev, OID_802_11_ADD_KEY, &ndis_key, - le32_to_cpu(ndis_key.size)); - netdev_dbg(usbdev->net, "%s(): OID_802_11_ADD_KEY -> %08X\n", + ret = rndis_set_oid(usbdev, + RNDIS_OID_802_11_ADD_KEY, &ndis_key, + le32_to_cpu(ndis_key.size)); + netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_ADD_KEY -> %08X\n", __func__, ret); if (ret != 0) return ret; @@ -1594,14 +1564,16 @@ static int remove_key(struct usbnet *usbdev, u8 index, const u8 *bssid) memset(remove_key.bssid, 0xff, sizeof(remove_key.bssid)); - ret = rndis_set_oid(usbdev, OID_802_11_REMOVE_KEY, &remove_key, - sizeof(remove_key)); + ret = rndis_set_oid(usbdev, + RNDIS_OID_802_11_REMOVE_KEY, + &remove_key, sizeof(remove_key)); if (ret != 0) return ret; } else { keyindex = cpu_to_le32(index); - ret = rndis_set_oid(usbdev, OID_802_11_REMOVE_WEP, &keyindex, - sizeof(keyindex)); + ret = rndis_set_oid(usbdev, + RNDIS_OID_802_11_REMOVE_WEP, + &keyindex, sizeof(keyindex)); if (ret != 0) { netdev_warn(usbdev->net, "removing encryption key %d failed (%08X)\n", @@ -1626,14 +1598,14 @@ static void set_multicast_list(struct usbnet *usbdev) char *mc_addrs = NULL; int mc_count; - basefilter = filter = RNDIS_PACKET_TYPE_DIRECTED | - RNDIS_PACKET_TYPE_BROADCAST; + basefilter = filter = cpu_to_le32(RNDIS_PACKET_TYPE_DIRECTED | + RNDIS_PACKET_TYPE_BROADCAST); if (usbdev->net->flags & IFF_PROMISC) { - filter |= RNDIS_PACKET_TYPE_PROMISCUOUS | - RNDIS_PACKET_TYPE_ALL_LOCAL; + filter |= cpu_to_le32(RNDIS_PACKET_TYPE_PROMISCUOUS | + RNDIS_PACKET_TYPE_ALL_LOCAL); } else if (usbdev->net->flags & IFF_ALLMULTI) { - filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST; + filter |= cpu_to_le32(RNDIS_PACKET_TYPE_ALL_MULTICAST); } if (filter != basefilter) @@ -1646,7 +1618,7 @@ static void set_multicast_list(struct usbnet *usbdev) netif_addr_lock_bh(usbdev->net); mc_count = netdev_mc_count(usbdev->net); if (mc_count > priv->multicast_size) { - filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST; + filter |= cpu_to_le32(RNDIS_PACKET_TYPE_ALL_MULTICAST); } else if (mc_count) { int i = 0; @@ -1669,27 +1641,28 @@ static void set_multicast_list(struct usbnet *usbdev) goto set_filter; if (mc_count) { - ret = rndis_set_oid(usbdev, OID_802_3_MULTICAST_LIST, mc_addrs, - mc_count * ETH_ALEN); + ret = rndis_set_oid(usbdev, + RNDIS_OID_802_3_MULTICAST_LIST, + mc_addrs, mc_count * ETH_ALEN); kfree(mc_addrs); if (ret == 0) - filter |= RNDIS_PACKET_TYPE_MULTICAST; + filter |= cpu_to_le32(RNDIS_PACKET_TYPE_MULTICAST); else - filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST; + filter |= cpu_to_le32(RNDIS_PACKET_TYPE_ALL_MULTICAST); - netdev_dbg(usbdev->net, "OID_802_3_MULTICAST_LIST(%d, max: %d) -> %d\n", + netdev_dbg(usbdev->net, "RNDIS_OID_802_3_MULTICAST_LIST(%d, max: %d) -> %d\n", mc_count, priv->multicast_size, ret); } set_filter: - ret = rndis_set_oid(usbdev, OID_GEN_CURRENT_PACKET_FILTER, &filter, + ret = rndis_set_oid(usbdev, RNDIS_OID_GEN_CURRENT_PACKET_FILTER, &filter, sizeof(filter)); if (ret < 0) { netdev_warn(usbdev->net, "couldn't set packet filter: %08x\n", le32_to_cpu(filter)); } - netdev_dbg(usbdev->net, "OID_GEN_CURRENT_PACKET_FILTER(%08x) -> %d\n", + netdev_dbg(usbdev->net, "RNDIS_OID_GEN_CURRENT_PACKET_FILTER(%08x) -> %d\n", le32_to_cpu(filter), ret); } @@ -1748,9 +1721,10 @@ static struct ndis_80211_pmkid *get_device_pmkids(struct usbnet *usbdev) pmkids->length = cpu_to_le32(len); pmkids->bssid_info_count = cpu_to_le32(max_pmkids); - ret = rndis_query_oid(usbdev, OID_802_11_PMKID, pmkids, &len); + ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_PMKID, + pmkids, &len); if (ret < 0) { - netdev_dbg(usbdev->net, "%s(): OID_802_11_PMKID(%d, %d)" + netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_PMKID(%d, %d)" " -> %d\n", __func__, len, max_pmkids, ret); kfree(pmkids); @@ -1776,10 +1750,10 @@ static int set_device_pmkids(struct usbnet *usbdev, debug_print_pmkids(usbdev, pmkids, __func__); - ret = rndis_set_oid(usbdev, OID_802_11_PMKID, pmkids, - le32_to_cpu(pmkids->length)); + ret = rndis_set_oid(usbdev, RNDIS_OID_802_11_PMKID, pmkids, + le32_to_cpu(pmkids->length)); if (ret < 0) { - netdev_dbg(usbdev->net, "%s(): OID_802_11_PMKID(%d, %d) -> %d" + netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_PMKID(%d, %d) -> %d" "\n", __func__, len, num_pmkids, ret); } @@ -1801,8 +1775,8 @@ static struct ndis_80211_pmkid *remove_pmkid(struct usbnet *usbdev, count = max_pmkids; for (i = 0; i < count; i++) - if (!compare_ether_addr(pmkids->bssid_info[i].bssid, - pmksa->bssid)) + if (ether_addr_equal(pmkids->bssid_info[i].bssid, + pmksa->bssid)) break; /* pmkid not found */ @@ -1843,8 +1817,8 @@ static struct ndis_80211_pmkid *update_pmkid(struct usbnet *usbdev, /* update with new pmkid */ for (i = 0; i < count; i++) { - if (compare_ether_addr(pmkids->bssid_info[i].bssid, - pmksa->bssid)) + if (!ether_addr_equal(pmkids->bssid_info[i].bssid, + pmksa->bssid)) continue; memcpy(pmkids->bssid_info[i].pmkid, pmksa->pmkid, @@ -2113,7 +2087,8 @@ static int rndis_check_bssid_list(struct usbnet *usbdev, u8 *match_bssid, * resizing until it won't get any bigger. */ new_len = len; - ret = rndis_query_oid(usbdev, OID_802_11_BSSID_LIST, buf, &new_len); + ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_BSSID_LIST, + buf, &new_len); if (ret != 0 || new_len < sizeof(struct ndis_80211_bssid_list_ex)) goto out; @@ -2139,7 +2114,7 @@ static int rndis_check_bssid_list(struct usbnet *usbdev, u8 *match_bssid, while (check_bssid_list_item(bssid, bssid_len, buf, len)) { if (rndis_bss_info_update(usbdev, bssid) && match_bssid && matched) { - if (compare_ether_addr(bssid->mac, match_bssid)) + if (!ether_addr_equal(bssid->mac, match_bssid)) *matched = true; } @@ -2511,14 +2486,15 @@ static void rndis_fill_station_info(struct usbnet *usbdev, memset(sinfo, 0, sizeof(*sinfo)); len = sizeof(linkspeed); - ret = rndis_query_oid(usbdev, OID_GEN_LINK_SPEED, &linkspeed, &len); + ret = rndis_query_oid(usbdev, RNDIS_OID_GEN_LINK_SPEED, &linkspeed, &len); if (ret == 0) { sinfo->txrate.legacy = le32_to_cpu(linkspeed) / 1000; sinfo->filled |= STATION_INFO_TX_BITRATE; } len = sizeof(rssi); - ret = rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len); + ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_RSSI, + &rssi, &len); if (ret == 0) { sinfo->signal = level_to_qual(le32_to_cpu(rssi)); sinfo->filled |= STATION_INFO_SIGNAL; @@ -2531,7 +2507,7 @@ static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev, struct rndis_wlan_private *priv = wiphy_priv(wiphy); struct usbnet *usbdev = priv->usbdev; - if (compare_ether_addr(priv->bssid, mac)) + if (!ether_addr_equal(priv->bssid, mac)) return -ENOENT; rndis_fill_station_info(usbdev, sinfo); @@ -2624,7 +2600,8 @@ static int rndis_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev) pmkid.length = cpu_to_le32(sizeof(pmkid)); pmkid.bssid_info_count = cpu_to_le32(0); - return rndis_set_oid(usbdev, OID_802_11_PMKID, &pmkid, sizeof(pmkid)); + return rndis_set_oid(usbdev, RNDIS_OID_802_11_PMKID, + &pmkid, sizeof(pmkid)); } static int rndis_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, @@ -2654,9 +2631,10 @@ static int rndis_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, priv->power_mode = power_mode; mode = cpu_to_le32(power_mode); - ret = rndis_set_oid(usbdev, OID_802_11_POWER_MODE, &mode, sizeof(mode)); + ret = rndis_set_oid(usbdev, RNDIS_OID_802_11_POWER_MODE, + &mode, sizeof(mode)); - netdev_dbg(usbdev->net, "%s(): OID_802_11_POWER_MODE -> %d\n", + netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_POWER_MODE -> %d\n", __func__, ret); return ret; @@ -2693,10 +2671,11 @@ static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid, /* Get signal quality, in case of error use rssi=0 and ignore error. */ len = sizeof(rssi); rssi = 0; - ret = rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len); + ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_RSSI, + &rssi, &len); signal = level_to_qual(le32_to_cpu(rssi)); - netdev_dbg(usbdev->net, "%s(): OID_802_11_RSSI -> %d, " + netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_RSSI -> %d, " "rssi:%d, qual: %d\n", __func__, ret, le32_to_cpu(rssi), level_to_qual(le32_to_cpu(rssi))); @@ -2720,8 +2699,9 @@ static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid, /* Get SSID, in case of error, use zero length SSID and ignore error. */ len = sizeof(ssid); memset(&ssid, 0, sizeof(ssid)); - ret = rndis_query_oid(usbdev, OID_802_11_SSID, &ssid, &len); - netdev_dbg(usbdev->net, "%s(): OID_802_11_SSID -> %d, len: %d, ssid: " + ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_SSID, + &ssid, &len); + netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_SSID -> %d, len: %d, ssid: " "'%.32s'\n", __func__, ret, le32_to_cpu(ssid.length), ssid.essid); @@ -2843,7 +2823,7 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) * NDIS spec says: "If the device is associated, but the associated * BSSID is not in its BSSID scan list, then the driver must add an * entry for the BSSID at the end of the data that it returns in - * response to query of OID_802_11_BSSID_LIST." + * response to query of RNDIS_OID_802_11_BSSID_LIST." * * NOTE: Seems to be true for BCM4320b variant, but not BCM4320a. */ @@ -3095,15 +3075,15 @@ static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen) struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct rndis_indicate *msg = ind; - switch (msg->status) { + switch (le32_to_cpu(msg->status)) { case RNDIS_STATUS_MEDIA_CONNECT: - if (priv->current_command_oid == OID_802_11_ADD_KEY) { - /* OID_802_11_ADD_KEY causes sometimes extra + if (priv->current_command_oid == RNDIS_OID_802_11_ADD_KEY) { + /* RNDIS_OID_802_11_ADD_KEY causes sometimes extra * "media connect" indications which confuses driver * and userspace to think that device is * roaming/reassociating when it isn't. */ - netdev_dbg(usbdev->net, "ignored OID_802_11_ADD_KEY triggered 'media connect'\n"); + netdev_dbg(usbdev->net, "ignored RNDIS_OID_802_11_ADD_KEY triggered 'media connect'\n"); return; } @@ -3148,8 +3128,9 @@ static int rndis_wlan_get_caps(struct usbnet *usbdev, struct wiphy *wiphy) /* determine supported modes */ len = sizeof(networks_supported); - retval = rndis_query_oid(usbdev, OID_802_11_NETWORK_TYPES_SUPPORTED, - &networks_supported, &len); + retval = rndis_query_oid(usbdev, + RNDIS_OID_802_11_NETWORK_TYPES_SUPPORTED, + &networks_supported, &len); if (retval >= 0) { n = le32_to_cpu(networks_supported.num_items); if (n > 8) @@ -3173,9 +3154,11 @@ static int rndis_wlan_get_caps(struct usbnet *usbdev, struct wiphy *wiphy) /* get device 802.11 capabilities, number of PMKIDs */ caps = (struct ndis_80211_capability *)caps_buf; len = sizeof(caps_buf); - retval = rndis_query_oid(usbdev, OID_802_11_CAPABILITY, caps, &len); + retval = rndis_query_oid(usbdev, + RNDIS_OID_802_11_CAPABILITY, + caps, &len); if (retval >= 0) { - netdev_dbg(usbdev->net, "OID_802_11_CAPABILITY -> len %d, " + netdev_dbg(usbdev->net, "RNDIS_OID_802_11_CAPABILITY -> len %d, " "ver %d, pmkids %d, auth-encr-pairs %d\n", le32_to_cpu(caps->length), le32_to_cpu(caps->version), @@ -3247,13 +3230,14 @@ static void rndis_device_poller(struct work_struct *work) } len = sizeof(rssi); - ret = rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len); + ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_RSSI, + &rssi, &len); if (ret == 0) { priv->last_qual = level_to_qual(le32_to_cpu(rssi)); rndis_do_cqm(usbdev, le32_to_cpu(rssi)); } - netdev_dbg(usbdev->net, "dev-poller: OID_802_11_RSSI -> %d, rssi:%d, qual: %d\n", + netdev_dbg(usbdev->net, "dev-poller: RNDIS_OID_802_11_RSSI -> %d, rssi:%d, qual: %d\n", ret, le32_to_cpu(rssi), level_to_qual(le32_to_cpu(rssi))); /* Workaround transfer stalls on poor quality links. @@ -3275,15 +3259,18 @@ static void rndis_device_poller(struct work_struct *work) * working. */ tmp = cpu_to_le32(1); - rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp, - sizeof(tmp)); + rndis_set_oid(usbdev, + RNDIS_OID_802_11_BSSID_LIST_SCAN, + &tmp, sizeof(tmp)); len = CONTROL_BUFFER_SIZE; buf = kmalloc(len, GFP_KERNEL); if (!buf) goto end; - rndis_query_oid(usbdev, OID_802_11_BSSID_LIST, buf, &len); + rndis_query_oid(usbdev, + RNDIS_OID_802_11_BSSID_LIST, + buf, &len); kfree(buf); } @@ -3465,13 +3452,15 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) */ usbdev->net->netdev_ops = &rndis_wlan_netdev_ops; - tmp = RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_BROADCAST; - retval = rndis_set_oid(usbdev, OID_GEN_CURRENT_PACKET_FILTER, &tmp, - sizeof(tmp)); + tmp = cpu_to_le32(RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_BROADCAST); + retval = rndis_set_oid(usbdev, + RNDIS_OID_GEN_CURRENT_PACKET_FILTER, + &tmp, sizeof(tmp)); len = sizeof(tmp); - retval = rndis_query_oid(usbdev, OID_802_3_MAXIMUM_LIST_SIZE, &tmp, - &len); + retval = rndis_query_oid(usbdev, + RNDIS_OID_802_3_MAXIMUM_LIST_SIZE, + &tmp, &len); priv->multicast_size = le32_to_cpu(tmp); if (retval < 0 || priv->multicast_size < 0) priv->multicast_size = 0; @@ -3601,7 +3590,7 @@ static int rndis_wlan_stop(struct usbnet *usbdev) /* Set current packet filter zero to block receiving data packets from device. */ filter = 0; - rndis_set_oid(usbdev, OID_GEN_CURRENT_PACKET_FILTER, &filter, + rndis_set_oid(usbdev, RNDIS_OID_GEN_CURRENT_PACKET_FILTER, &filter, sizeof(filter)); return retval; @@ -3776,6 +3765,7 @@ static struct usb_driver rndis_wlan_driver = { .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(rndis_wlan_driver); diff --git a/trunk/drivers/net/wireless/rt2x00/rt2400pci.c b/trunk/drivers/net/wireless/rt2x00/rt2400pci.c index 3a6b40239bc1..5e6b50143165 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1828,15 +1828,4 @@ static struct pci_driver rt2400pci_driver = { .resume = rt2x00pci_resume, }; -static int __init rt2400pci_init(void) -{ - return pci_register_driver(&rt2400pci_driver); -} - -static void __exit rt2400pci_exit(void) -{ - pci_unregister_driver(&rt2400pci_driver); -} - -module_init(rt2400pci_init); -module_exit(rt2400pci_exit); +module_pci_driver(rt2400pci_driver); diff --git a/trunk/drivers/net/wireless/rt2x00/rt2500pci.c b/trunk/drivers/net/wireless/rt2x00/rt2500pci.c index dcc0e1fcca77..136b849f11b5 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2500pci.c @@ -2119,15 +2119,4 @@ static struct pci_driver rt2500pci_driver = { .resume = rt2x00pci_resume, }; -static int __init rt2500pci_init(void) -{ - return pci_register_driver(&rt2500pci_driver); -} - -static void __exit rt2500pci_exit(void) -{ - pci_unregister_driver(&rt2500pci_driver); -} - -module_init(rt2500pci_init); -module_exit(rt2500pci_exit); +module_pci_driver(rt2500pci_driver); diff --git a/trunk/drivers/net/wireless/rt2x00/rt2500usb.c b/trunk/drivers/net/wireless/rt2x00/rt2500usb.c index 1de9c752c88b..669aecdb411d 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1912,7 +1912,7 @@ static struct usb_device_id rt2500usb_device_table[] = { { USB_DEVICE(0x0b05, 0x1706) }, { USB_DEVICE(0x0b05, 0x1707) }, /* Belkin */ - { USB_DEVICE(0x050d, 0x7050) }, + { USB_DEVICE(0x050d, 0x7050) }, /* FCC ID: K7SF5D7050A ver. 2.x */ { USB_DEVICE(0x050d, 0x7051) }, /* Cisco Systems */ { USB_DEVICE(0x13b1, 0x000d) }, @@ -1980,6 +1980,7 @@ static struct usb_driver rt2500usb_driver = { .disconnect = rt2x00usb_disconnect, .suspend = rt2x00usb_suspend, .resume = rt2x00usb_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(rt2500usb_driver); diff --git a/trunk/drivers/net/wireless/rt2x00/rt2800.h b/trunk/drivers/net/wireless/rt2x00/rt2800.h index 063bfa8b91f4..9348521e0832 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2800.h +++ b/trunk/drivers/net/wireless/rt2x00/rt2800.h @@ -83,6 +83,7 @@ #define REV_RT3090E 0x0211 #define REV_RT3390E 0x0211 #define REV_RT5390F 0x0502 +#define REV_RT5390R 0x1502 /* * Signal information. @@ -98,9 +99,11 @@ #define EEPROM_BASE 0x0000 #define EEPROM_SIZE 0x0110 #define BBP_BASE 0x0000 -#define BBP_SIZE 0x0080 +#define BBP_SIZE 0x00ff #define RF_BASE 0x0004 #define RF_SIZE 0x0010 +#define RFCSR_BASE 0x0000 +#define RFCSR_SIZE 0x0040 /* * Number of TX queues. diff --git a/trunk/drivers/net/wireless/rt2x00/rt2800lib.c b/trunk/drivers/net/wireless/rt2x00/rt2800lib.c index 6c0a12ea6a15..dfc90d34be6d 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2800lib.c @@ -290,11 +290,25 @@ int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev) msleep(10); } - ERROR(rt2x00dev, "WPDMA TX/RX busy, aborting.\n"); + ERROR(rt2x00dev, "WPDMA TX/RX busy [0x%08x].\n", reg); return -EACCES; } EXPORT_SYMBOL_GPL(rt2800_wait_wpdma_ready); +void rt2800_disable_wpdma(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_DMA_BUSY, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); + rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); +} +EXPORT_SYMBOL_GPL(rt2800_disable_wpdma); + static bool rt2800_check_firmware_crc(const u8 *data, const size_t len) { u16 fw_crc; @@ -412,6 +426,8 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev, rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000002); } + rt2800_disable_wpdma(rt2x00dev); + /* * Write firmware to the device. */ @@ -436,10 +452,7 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev, * Disable DMA, will be reenabled later when enabling * the radio. */ - rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); - rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + rt2800_disable_wpdma(rt2x00dev); /* * Initialize firmware. @@ -823,6 +836,13 @@ const struct rt2x00debug rt2800_rt2x00debug = { .word_size = sizeof(u32), .word_count = RF_SIZE / sizeof(u32), }, + .rfcsr = { + .read = rt2800_rfcsr_read, + .write = rt2800_rfcsr_write, + .word_base = RFCSR_BASE, + .word_size = sizeof(u8), + .word_count = RFCSR_SIZE / sizeof(u8), + }, }; EXPORT_SYMBOL_GPL(rt2800_rt2x00debug); #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ @@ -2717,13 +2737,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) unsigned int i; int ret; - rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_DMA_BUSY, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); - rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + rt2800_disable_wpdma(rt2x00dev); ret = rt2800_drv_init_registers(rt2x00dev); if (ret) @@ -3349,6 +3363,13 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, GPIO_CTRL_CFG, reg); } + /* This chip has hardware antenna diversity*/ + if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390R)) { + rt2800_bbp_write(rt2x00dev, 150, 0); /* Disable Antenna Software OFDM */ + rt2800_bbp_write(rt2x00dev, 151, 0); /* Disable Antenna Software CCK */ + rt2800_bbp_write(rt2x00dev, 154, 0); /* Clear previously selected antenna */ + } + rt2800_bbp_read(rt2x00dev, 152, &value); if (ant == 0) rt2x00_set_field8(&value, BBP152_RX_DEFAULT_ANT, 1); @@ -3997,10 +4018,7 @@ void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); - rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + rt2800_disable_wpdma(rt2x00dev); /* Wait for DMA, ignore error */ rt2800_wait_wpdma_ready(rt2x00dev); @@ -4287,6 +4305,11 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00dev->default_ant.rx = ANTENNA_A; } + if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390R)) { + rt2x00dev->default_ant.tx = ANTENNA_HW_DIVERSITY; /* Unused */ + rt2x00dev->default_ant.rx = ANTENNA_HW_DIVERSITY; /* Unused */ + } + /* * Determine external LNA informations. */ diff --git a/trunk/drivers/net/wireless/rt2x00/rt2800lib.h b/trunk/drivers/net/wireless/rt2x00/rt2800lib.h index 419e36cb06be..18a0b67b4c68 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/trunk/drivers/net/wireless/rt2x00/rt2800lib.h @@ -208,5 +208,6 @@ int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u8 buf_size); int rt2800_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey); +void rt2800_disable_wpdma(struct rt2x00_dev *rt2x00dev); #endif /* RT2800LIB_H */ diff --git a/trunk/drivers/net/wireless/rt2x00/rt2800pci.c b/trunk/drivers/net/wireless/rt2x00/rt2800pci.c index 0397bbf0ce01..931331d95217 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2800pci.c @@ -361,7 +361,6 @@ static void rt2800pci_clear_entry(struct queue_entry *entry) static int rt2800pci_init_queues(struct rt2x00_dev *rt2x00dev) { struct queue_entry_priv_pci *entry_priv; - u32 reg; /* * Initialize registers. @@ -394,6 +393,16 @@ static int rt2800pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX3, 0); rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX3, 0); + rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR4, 0); + rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT4, 0); + rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX4, 0); + rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX4, 0); + + rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR5, 0); + rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT5, 0); + rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX5, 0); + rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX5, 0); + entry_priv = rt2x00dev->rx->entries[0].priv_data; rt2x00pci_register_write(rt2x00dev, RX_BASE_PTR, entry_priv->desc_dma); rt2x00pci_register_write(rt2x00dev, RX_MAX_CNT, @@ -402,14 +411,7 @@ static int rt2800pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00dev->rx[0].limit - 1); rt2x00pci_register_write(rt2x00dev, RX_DRX_IDX, 0); - /* - * Enable global DMA configuration - */ - rt2x00pci_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); - rt2x00pci_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + rt2800_disable_wpdma(rt2x00dev); rt2x00pci_register_write(rt2x00dev, DELAY_INT_CFG, 0); @@ -504,8 +506,10 @@ static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev) { int retval; - if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) || - rt2800pci_init_queues(rt2x00dev))) + /* Wait for DMA, ignore error until we initialize queues. */ + rt2800_wait_wpdma_ready(rt2x00dev); + + if (unlikely(rt2800pci_init_queues(rt2x00dev))) return -EIO; retval = rt2800_enable_radio(rt2x00dev); @@ -1184,7 +1188,9 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = { { PCI_DEVICE(0x1814, 0x3593) }, #endif #ifdef CONFIG_RT2800PCI_RT53XX + { PCI_DEVICE(0x1814, 0x5362) }, { PCI_DEVICE(0x1814, 0x5390) }, + { PCI_DEVICE(0x1814, 0x5392) }, { PCI_DEVICE(0x1814, 0x539a) }, { PCI_DEVICE(0x1814, 0x539f) }, #endif diff --git a/trunk/drivers/net/wireless/rt2x00/rt2800usb.c b/trunk/drivers/net/wireless/rt2x00/rt2800usb.c index 001735f7a661..bf78317a6adb 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2800usb.c @@ -922,6 +922,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x1482, 0x3c09) }, /* AirTies */ { USB_DEVICE(0x1eda, 0x2012) }, + { USB_DEVICE(0x1eda, 0x2210) }, { USB_DEVICE(0x1eda, 0x2310) }, /* Allwin */ { USB_DEVICE(0x8516, 0x2070) }, @@ -991,6 +992,7 @@ static struct usb_device_id rt2800usb_device_table[] = { /* DVICO */ { USB_DEVICE(0x0fe9, 0xb307) }, /* Edimax */ + { USB_DEVICE(0x7392, 0x4085) }, { USB_DEVICE(0x7392, 0x7711) }, { USB_DEVICE(0x7392, 0x7717) }, { USB_DEVICE(0x7392, 0x7718) }, @@ -1066,6 +1068,7 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Philips */ { USB_DEVICE(0x0471, 0x200f) }, /* Planex */ + { USB_DEVICE(0x2019, 0x5201) }, { USB_DEVICE(0x2019, 0xab25) }, { USB_DEVICE(0x2019, 0xed06) }, /* Quanta */ @@ -1134,6 +1137,10 @@ static struct usb_device_id rt2800usb_device_table[] = { #ifdef CONFIG_RT2800USB_RT33XX /* Belkin */ { USB_DEVICE(0x050d, 0x945b) }, + /* Panasonic */ + { USB_DEVICE(0x083a, 0xb511) }, + /* Philips */ + { USB_DEVICE(0x0471, 0x20dd) }, /* Ralink */ { USB_DEVICE(0x148f, 0x3370) }, { USB_DEVICE(0x148f, 0x8070) }, @@ -1145,6 +1152,8 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x8516, 0x3572) }, /* Askey */ { USB_DEVICE(0x1690, 0x0744) }, + { USB_DEVICE(0x1690, 0x0761) }, + { USB_DEVICE(0x1690, 0x0764) }, /* Cisco */ { USB_DEVICE(0x167b, 0x4001) }, /* EnGenius */ @@ -1159,20 +1168,25 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Sitecom */ { USB_DEVICE(0x0df6, 0x0041) }, { USB_DEVICE(0x0df6, 0x0062) }, + { USB_DEVICE(0x0df6, 0x0065) }, + { USB_DEVICE(0x0df6, 0x0066) }, + { USB_DEVICE(0x0df6, 0x0068) }, /* Toshiba */ { USB_DEVICE(0x0930, 0x0a07) }, /* Zinwell */ { USB_DEVICE(0x5a57, 0x0284) }, #endif #ifdef CONFIG_RT2800USB_RT53XX - /* Alpha */ - { USB_DEVICE(0x2001, 0x3c15) }, - { USB_DEVICE(0x2001, 0x3c19) }, /* Arcadyan */ { USB_DEVICE(0x043e, 0x7a12) }, /* Azurewave */ { USB_DEVICE(0x13d3, 0x3329) }, { USB_DEVICE(0x13d3, 0x3365) }, + /* D-Link */ + { USB_DEVICE(0x2001, 0x3c15) }, + { USB_DEVICE(0x2001, 0x3c19) }, + { USB_DEVICE(0x2001, 0x3c1c) }, + { USB_DEVICE(0x2001, 0x3c1d) }, /* LG innotek */ { USB_DEVICE(0x043e, 0x7a22) }, /* Panasonic */ @@ -1224,12 +1238,8 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x07d1, 0x3c0b) }, { USB_DEVICE(0x07d1, 0x3c17) }, { USB_DEVICE(0x2001, 0x3c17) }, - /* Edimax */ - { USB_DEVICE(0x7392, 0x4085) }, /* Encore */ { USB_DEVICE(0x203d, 0x14a1) }, - /* Fujitsu Stylistic 550 */ - { USB_DEVICE(0x1690, 0x0761) }, /* Gemtek */ { USB_DEVICE(0x15a9, 0x0010) }, /* Gigabyte */ @@ -1250,7 +1260,6 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x05a6, 0x0101) }, { USB_DEVICE(0x1d4d, 0x0010) }, /* Planex */ - { USB_DEVICE(0x2019, 0x5201) }, { USB_DEVICE(0x2019, 0xab24) }, /* Qcom */ { USB_DEVICE(0x18e8, 0x6259) }, @@ -1293,6 +1302,7 @@ static struct usb_driver rt2800usb_driver = { .disconnect = rt2x00usb_disconnect, .suspend = rt2x00usb_suspend, .resume = rt2x00usb_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(rt2800usb_driver); diff --git a/trunk/drivers/net/wireless/rt2x00/rt2x00.h b/trunk/drivers/net/wireless/rt2x00/rt2x00.h index 471f87cab4ab..ca36cccaba31 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2x00.h +++ b/trunk/drivers/net/wireless/rt2x00/rt2x00.h @@ -692,6 +692,8 @@ enum rt2x00_state_flags { */ CONFIG_CHANNEL_HT40, CONFIG_POWERSAVING, + CONFIG_HT_DISABLED, + CONFIG_QOS_DISABLED, /* * Mark we currently are sequentially reading TX_STA_FIFO register @@ -1280,7 +1282,7 @@ void rt2x00lib_dmadone(struct queue_entry *entry); void rt2x00lib_txdone(struct queue_entry *entry, struct txdone_entry_desc *txdesc); void rt2x00lib_txdone_noinfo(struct queue_entry *entry, u32 status); -void rt2x00lib_rxdone(struct queue_entry *entry); +void rt2x00lib_rxdone(struct queue_entry *entry, gfp_t gfp); /* * mac80211 handlers. diff --git a/trunk/drivers/net/wireless/rt2x00/rt2x00config.c b/trunk/drivers/net/wireless/rt2x00/rt2x00config.c index 293676bfa571..e7361d913e8e 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2x00config.c @@ -217,6 +217,11 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, libconf.conf = conf; if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) { + if (!conf_is_ht(conf)) + set_bit(CONFIG_HT_DISABLED, &rt2x00dev->flags); + else + clear_bit(CONFIG_HT_DISABLED, &rt2x00dev->flags); + if (conf_is_ht40(conf)) { set_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags); hw_value = rt2x00ht_center_channel(rt2x00dev, conf); diff --git a/trunk/drivers/net/wireless/rt2x00/rt2x00debug.c b/trunk/drivers/net/wireless/rt2x00/rt2x00debug.c index 78787fcc919e..3bb8cafbac59 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -70,6 +70,7 @@ struct rt2x00debug_intf { * - eeprom offset/value files * - bbp offset/value files * - rf offset/value files + * - rfcsr offset/value files * - queue folder * - frame dump file * - queue stats file @@ -89,6 +90,8 @@ struct rt2x00debug_intf { struct dentry *bbp_val_entry; struct dentry *rf_off_entry; struct dentry *rf_val_entry; + struct dentry *rfcsr_off_entry; + struct dentry *rfcsr_val_entry; struct dentry *queue_folder; struct dentry *queue_frame_dump_entry; struct dentry *queue_stats_entry; @@ -131,6 +134,7 @@ struct rt2x00debug_intf { unsigned int offset_eeprom; unsigned int offset_bbp; unsigned int offset_rf; + unsigned int offset_rfcsr; }; void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev, @@ -525,6 +529,7 @@ RT2X00DEBUGFS_OPS(csr, "0x%.8x\n", u32); RT2X00DEBUGFS_OPS(eeprom, "0x%.4x\n", u16); RT2X00DEBUGFS_OPS(bbp, "0x%.2x\n", u8); RT2X00DEBUGFS_OPS(rf, "0x%.8x\n", u32); +RT2X00DEBUGFS_OPS(rfcsr, "0x%.2x\n", u8); static ssize_t rt2x00debug_read_dev_flags(struct file *file, char __user *buf, @@ -614,7 +619,7 @@ static struct dentry *rt2x00debug_create_file_chipset(const char *name, const struct rt2x00debug *debug = intf->debug; char *data; - data = kzalloc(8 * MAX_LINE_LENGTH, GFP_KERNEL); + data = kzalloc(9 * MAX_LINE_LENGTH, GFP_KERNEL); if (!data) return NULL; @@ -624,22 +629,22 @@ static struct dentry *rt2x00debug_create_file_chipset(const char *name, data += sprintf(data, "revision:\t%04x\n", intf->rt2x00dev->chip.rev); data += sprintf(data, "\n"); data += sprintf(data, "register\tbase\twords\twordsize\n"); - data += sprintf(data, "csr\t%d\t%d\t%d\n", - debug->csr.word_base, - debug->csr.word_count, - debug->csr.word_size); - data += sprintf(data, "eeprom\t%d\t%d\t%d\n", - debug->eeprom.word_base, - debug->eeprom.word_count, - debug->eeprom.word_size); - data += sprintf(data, "bbp\t%d\t%d\t%d\n", - debug->bbp.word_base, - debug->bbp.word_count, - debug->bbp.word_size); - data += sprintf(data, "rf\t%d\t%d\t%d\n", - debug->rf.word_base, - debug->rf.word_count, - debug->rf.word_size); +#define RT2X00DEBUGFS_SPRINTF_REGISTER(__name) \ +{ \ + if(debug->__name.read) \ + data += sprintf(data, __stringify(__name) \ + "\t%d\t%d\t%d\n", \ + debug->__name.word_base, \ + debug->__name.word_count, \ + debug->__name.word_size); \ +} + RT2X00DEBUGFS_SPRINTF_REGISTER(csr); + RT2X00DEBUGFS_SPRINTF_REGISTER(eeprom); + RT2X00DEBUGFS_SPRINTF_REGISTER(bbp); + RT2X00DEBUGFS_SPRINTF_REGISTER(rf); + RT2X00DEBUGFS_SPRINTF_REGISTER(rfcsr); +#undef RT2X00DEBUGFS_SPRINTF_REGISTER + blob->size = strlen(blob->data); return debugfs_create_blob(name, S_IRUSR, intf->driver_folder, blob); @@ -694,31 +699,34 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) if (IS_ERR(intf->register_folder) || !intf->register_folder) goto exit; -#define RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(__intf, __name) \ -({ \ - (__intf)->__name##_off_entry = \ - debugfs_create_u32(__stringify(__name) "_offset", \ - S_IRUSR | S_IWUSR, \ - (__intf)->register_folder, \ - &(__intf)->offset_##__name); \ - if (IS_ERR((__intf)->__name##_off_entry) \ - || !(__intf)->__name##_off_entry) \ - goto exit; \ - \ - (__intf)->__name##_val_entry = \ - debugfs_create_file(__stringify(__name) "_value", \ - S_IRUSR | S_IWUSR, \ - (__intf)->register_folder, \ - (__intf), &rt2x00debug_fop_##__name);\ - if (IS_ERR((__intf)->__name##_val_entry) \ - || !(__intf)->__name##_val_entry) \ - goto exit; \ +#define RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(__intf, __name) \ +({ \ + if(debug->__name.read) { \ + (__intf)->__name##_off_entry = \ + debugfs_create_u32(__stringify(__name) "_offset", \ + S_IRUSR | S_IWUSR, \ + (__intf)->register_folder, \ + &(__intf)->offset_##__name); \ + if (IS_ERR((__intf)->__name##_off_entry) \ + || !(__intf)->__name##_off_entry) \ + goto exit; \ + \ + (__intf)->__name##_val_entry = \ + debugfs_create_file(__stringify(__name) "_value", \ + S_IRUSR | S_IWUSR, \ + (__intf)->register_folder, \ + (__intf), &rt2x00debug_fop_##__name); \ + if (IS_ERR((__intf)->__name##_val_entry) \ + || !(__intf)->__name##_val_entry) \ + goto exit; \ + } \ }) RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, csr); RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, eeprom); RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, bbp); RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, rf); + RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, rfcsr); #undef RT2X00DEBUGFS_CREATE_REGISTER_ENTRY @@ -770,6 +778,8 @@ void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev) debugfs_remove(intf->queue_stats_entry); debugfs_remove(intf->queue_frame_dump_entry); debugfs_remove(intf->queue_folder); + debugfs_remove(intf->rfcsr_val_entry); + debugfs_remove(intf->rfcsr_off_entry); debugfs_remove(intf->rf_val_entry); debugfs_remove(intf->rf_off_entry); debugfs_remove(intf->bbp_val_entry); diff --git a/trunk/drivers/net/wireless/rt2x00/rt2x00debug.h b/trunk/drivers/net/wireless/rt2x00/rt2x00debug.h index fa11409cb5c6..e11d39bdfef7 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2x00debug.h +++ b/trunk/drivers/net/wireless/rt2x00/rt2x00debug.h @@ -65,6 +65,7 @@ struct rt2x00debug { RT2X00DEBUGFS_REGISTER_ENTRY(eeprom, u16); RT2X00DEBUGFS_REGISTER_ENTRY(bbp, u8); RT2X00DEBUGFS_REGISTER_ENTRY(rf, u32); + RT2X00DEBUGFS_REGISTER_ENTRY(rfcsr, u8); }; #endif /* RT2X00DEBUG_H */ diff --git a/trunk/drivers/net/wireless/rt2x00/rt2x00dev.c b/trunk/drivers/net/wireless/rt2x00/rt2x00dev.c index 90cc5e772650..e5404e576251 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -391,9 +391,10 @@ void rt2x00lib_txdone(struct queue_entry *entry, tx_info->flags |= IEEE80211_TX_STAT_AMPDU; tx_info->status.ampdu_len = 1; tx_info->status.ampdu_ack_len = success ? 1 : 0; - - if (!success) - tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; + /* + * TODO: Need to tear down BA session here + * if not successful. + */ } if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { @@ -587,7 +588,7 @@ static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev, return 0; } -void rt2x00lib_rxdone(struct queue_entry *entry) +void rt2x00lib_rxdone(struct queue_entry *entry, gfp_t gfp) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct rxdone_entry_desc rxdesc; @@ -607,7 +608,7 @@ void rt2x00lib_rxdone(struct queue_entry *entry) * Allocate a new sk_buffer. If no new buffer available, drop the * received frame and reuse the existing buffer. */ - skb = rt2x00queue_alloc_rxskb(entry); + skb = rt2x00queue_alloc_rxskb(entry, gfp); if (!skb) goto submit_entry; diff --git a/trunk/drivers/net/wireless/rt2x00/rt2x00leds.c b/trunk/drivers/net/wireless/rt2x00/rt2x00leds.c index ca585e34d00e..8679d781a264 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2x00leds.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2x00leds.c @@ -124,17 +124,15 @@ static int rt2x00leds_register_led(struct rt2x00_dev *rt2x00dev, void rt2x00leds_register(struct rt2x00_dev *rt2x00dev) { - char dev_name[16]; - char name[32]; + char name[36]; int retval; unsigned long on_period; unsigned long off_period; - - snprintf(dev_name, sizeof(dev_name), "%s-%s", - rt2x00dev->ops->name, wiphy_name(rt2x00dev->hw->wiphy)); + const char *phy_name = wiphy_name(rt2x00dev->hw->wiphy); if (rt2x00dev->led_radio.flags & LED_INITIALIZED) { - snprintf(name, sizeof(name), "%s::radio", dev_name); + snprintf(name, sizeof(name), "%s-%s::radio", + rt2x00dev->ops->name, phy_name); retval = rt2x00leds_register_led(rt2x00dev, &rt2x00dev->led_radio, @@ -144,7 +142,8 @@ void rt2x00leds_register(struct rt2x00_dev *rt2x00dev) } if (rt2x00dev->led_assoc.flags & LED_INITIALIZED) { - snprintf(name, sizeof(name), "%s::assoc", dev_name); + snprintf(name, sizeof(name), "%s-%s::assoc", + rt2x00dev->ops->name, phy_name); retval = rt2x00leds_register_led(rt2x00dev, &rt2x00dev->led_assoc, @@ -154,7 +153,8 @@ void rt2x00leds_register(struct rt2x00_dev *rt2x00dev) } if (rt2x00dev->led_qual.flags & LED_INITIALIZED) { - snprintf(name, sizeof(name), "%s::quality", dev_name); + snprintf(name, sizeof(name), "%s-%s::quality", + rt2x00dev->ops->name, phy_name); retval = rt2x00leds_register_led(rt2x00dev, &rt2x00dev->led_qual, diff --git a/trunk/drivers/net/wireless/rt2x00/rt2x00lib.h b/trunk/drivers/net/wireless/rt2x00/rt2x00lib.h index 78bd43b8961f..a0935987fa3a 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/trunk/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -103,7 +103,7 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, * rt2x00queue_alloc_rxskb - allocate a skb for RX purposes. * @entry: The entry for which the skb will be applicable. */ -struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry); +struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry, gfp_t gfp); /** * rt2x00queue_free_skb - free a skb diff --git a/trunk/drivers/net/wireless/rt2x00/rt2x00mac.c b/trunk/drivers/net/wireless/rt2x00/rt2x00mac.c index 2df2eb6d3e06..b49773ef72f2 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -709,8 +709,18 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, rt2x00dev->intf_associated--; rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated); + + clear_bit(CONFIG_QOS_DISABLED, &rt2x00dev->flags); } + /* + * Check for access point which do not support 802.11e . We have to + * generate data frames sequence number in S/W for such AP, because + * of H/W bug. + */ + if (changes & BSS_CHANGED_QOS && !bss_conf->qos) + set_bit(CONFIG_QOS_DISABLED, &rt2x00dev->flags); + /* * When the erp information has changed, we should perform * additional configuration steps. For all other changes we are done. diff --git a/trunk/drivers/net/wireless/rt2x00/rt2x00pci.c b/trunk/drivers/net/wireless/rt2x00/rt2x00pci.c index 17148bb24426..0a4653a92cab 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -92,7 +92,7 @@ bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) /* * Send the frame to rt2x00lib for further processing. */ - rt2x00lib_rxdone(entry); + rt2x00lib_rxdone(entry, GFP_ATOMIC); } return !max_rx; diff --git a/trunk/drivers/net/wireless/rt2x00/rt2x00queue.c b/trunk/drivers/net/wireless/rt2x00/rt2x00queue.c index 9b1b2b7a7807..4c662eccf53c 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -33,7 +33,7 @@ #include "rt2x00.h" #include "rt2x00lib.h" -struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry) +struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry, gfp_t gfp) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct sk_buff *skb; @@ -68,7 +68,7 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry) /* * Allocate skbuffer. */ - skb = dev_alloc_skb(frame_size + head_size + tail_size); + skb = __dev_alloc_skb(frame_size + head_size + tail_size, gfp); if (!skb) return NULL; @@ -213,8 +213,19 @@ static void rt2x00queue_create_tx_descriptor_seq(struct rt2x00_dev *rt2x00dev, __set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags); - if (!test_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags)) - return; + if (!test_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags)) { + /* + * rt2800 has a H/W (or F/W) bug, device incorrectly increase + * seqno on retransmited data (non-QOS) frames. To workaround + * the problem let's generate seqno in software if QOS is + * disabled. + */ + if (test_bit(CONFIG_QOS_DISABLED, &rt2x00dev->flags)) + __clear_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags); + else + /* H/W will generate sequence number */ + return; + } /* * The hardware is not able to insert a sequence number. Assign a @@ -320,14 +331,6 @@ static void rt2x00queue_create_tx_descriptor_ht(struct rt2x00_dev *rt2x00dev, txdesc->u.ht.wcid = sta_priv->wcid; } - txdesc->u.ht.ba_size = 7; /* FIXME: What value is needed? */ - - /* - * Only one STBC stream is supported for now. - */ - if (tx_info->flags & IEEE80211_TX_CTL_STBC) - txdesc->u.ht.stbc = 1; - /* * If IEEE80211_TX_RC_MCS is set txrate->idx just contains the * mcs rate to be used @@ -351,6 +354,24 @@ static void rt2x00queue_create_tx_descriptor_ht(struct rt2x00_dev *rt2x00dev, txdesc->u.ht.mcs |= 0x08; } + if (test_bit(CONFIG_HT_DISABLED, &rt2x00dev->flags)) { + if (!(tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)) + txdesc->u.ht.txop = TXOP_SIFS; + else + txdesc->u.ht.txop = TXOP_BACKOFF; + + /* Left zero on all other settings. */ + return; + } + + txdesc->u.ht.ba_size = 7; /* FIXME: What value is needed? */ + + /* + * Only one STBC stream is supported for now. + */ + if (tx_info->flags & IEEE80211_TX_CTL_STBC) + txdesc->u.ht.stbc = 1; + /* * This frame is eligible for an AMPDU, however, don't aggregate * frames that are intended to probe a specific tx rate. @@ -1142,7 +1163,7 @@ static int rt2x00queue_alloc_rxskbs(struct data_queue *queue) struct sk_buff *skb; for (i = 0; i < queue->limit; i++) { - skb = rt2x00queue_alloc_rxskb(&queue->entries[i]); + skb = rt2x00queue_alloc_rxskb(&queue->entries[i], GFP_KERNEL); if (!skb) return -ENOMEM; queue->entries[i].skb = skb; diff --git a/trunk/drivers/net/wireless/rt2x00/rt2x00usb.c b/trunk/drivers/net/wireless/rt2x00/rt2x00usb.c index 66094eb21b61..d357d1ed92f6 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/trunk/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -358,7 +358,7 @@ static void rt2x00usb_work_rxdone(struct work_struct *work) /* * Send the frame to rt2x00lib for further processing. */ - rt2x00lib_rxdone(entry); + rt2x00lib_rxdone(entry, GFP_KERNEL); } } diff --git a/trunk/drivers/net/wireless/rt2x00/rt61pci.c b/trunk/drivers/net/wireless/rt2x00/rt61pci.c index e0c6d117429d..ee22bd74579d 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt61pci.c +++ b/trunk/drivers/net/wireless/rt2x00/rt61pci.c @@ -3092,15 +3092,4 @@ static struct pci_driver rt61pci_driver = { .resume = rt2x00pci_resume, }; -static int __init rt61pci_init(void) -{ - return pci_register_driver(&rt61pci_driver); -} - -static void __exit rt61pci_exit(void) -{ - pci_unregister_driver(&rt61pci_driver); -} - -module_init(rt61pci_init); -module_exit(rt61pci_exit); +module_pci_driver(rt61pci_driver); diff --git a/trunk/drivers/net/wireless/rt2x00/rt73usb.c b/trunk/drivers/net/wireless/rt2x00/rt73usb.c index e477a964081d..77ccbbc7da41 100644 --- a/trunk/drivers/net/wireless/rt2x00/rt73usb.c +++ b/trunk/drivers/net/wireless/rt2x00/rt73usb.c @@ -2412,6 +2412,7 @@ static struct usb_device_id rt73usb_device_table[] = { { USB_DEVICE(0x0b05, 0x1723) }, { USB_DEVICE(0x0b05, 0x1724) }, /* Belkin */ + { USB_DEVICE(0x050d, 0x7050) }, /* FCC ID: K7SF5D7050B ver. 3.x */ { USB_DEVICE(0x050d, 0x705a) }, { USB_DEVICE(0x050d, 0x905b) }, { USB_DEVICE(0x050d, 0x905c) }, @@ -2526,6 +2527,7 @@ static struct usb_driver rt73usb_driver = { .disconnect = rt2x00usb_disconnect, .suspend = rt2x00usb_suspend, .resume = rt2x00usb_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(rt73usb_driver); diff --git a/trunk/drivers/net/wireless/rtl818x/rtl8180/dev.c b/trunk/drivers/net/wireless/rtl818x/rtl8180/dev.c index 2f14a5fb0cbb..2bebcb71a1e9 100644 --- a/trunk/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/trunk/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -1173,15 +1173,4 @@ static struct pci_driver rtl8180_driver = { #endif /* CONFIG_PM */ }; -static int __init rtl8180_init(void) -{ - return pci_register_driver(&rtl8180_driver); -} - -static void __exit rtl8180_exit(void) -{ - pci_unregister_driver(&rtl8180_driver); -} - -module_init(rtl8180_init); -module_exit(rtl8180_exit); +module_pci_driver(rtl8180_driver); diff --git a/trunk/drivers/net/wireless/rtl818x/rtl8187/dev.c b/trunk/drivers/net/wireless/rtl818x/rtl8187/dev.c index cf53ac9d6f23..4fb1ca1b86b9 100644 --- a/trunk/drivers/net/wireless/rtl818x/rtl8187/dev.c +++ b/trunk/drivers/net/wireless/rtl818x/rtl8187/dev.c @@ -294,6 +294,7 @@ static void rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8); hdr->tx_duration = ieee80211_generic_frame_duration(dev, priv->vif, + info->band, skb->len, txrate); buf = hdr; @@ -1662,6 +1663,7 @@ static struct usb_driver rtl8187_driver = { .id_table = rtl8187_table, .probe = rtl8187_probe, .disconnect = __devexit_p(rtl8187_disconnect), + .disable_hub_initiated_lpm = 1, }; module_usb_driver(rtl8187_driver); diff --git a/trunk/drivers/net/wireless/rtlwifi/base.c b/trunk/drivers/net/wireless/rtlwifi/base.c index e54488db0e10..f4c852c6749b 100644 --- a/trunk/drivers/net/wireless/rtlwifi/base.c +++ b/trunk/drivers/net/wireless/rtlwifi/base.c @@ -1460,7 +1460,7 @@ void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len) return; /* and only beacons from the associated BSSID, please */ - if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid)) + if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid)) return; if (rtl_find_221_ie(hw, data, len)) diff --git a/trunk/drivers/net/wireless/rtlwifi/cam.c b/trunk/drivers/net/wireless/rtlwifi/cam.c index 5c7d57947d23..3d8cc4a0c86d 100644 --- a/trunk/drivers/net/wireless/rtlwifi/cam.c +++ b/trunk/drivers/net/wireless/rtlwifi/cam.c @@ -328,10 +328,9 @@ void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr) RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG, "sta_addr is NULL\n"); } - if ((sta_addr[0]|sta_addr[1]|sta_addr[2]|sta_addr[3]|\ - sta_addr[4]|sta_addr[5]) == 0) { + if (is_zero_ether_addr(sta_addr)) { RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG, - "sta_addr is 00:00:00:00:00:00\n"); + "sta_addr is %pM\n", sta_addr); return; } /* Does STA already exist? */ diff --git a/trunk/drivers/net/wireless/rtlwifi/pci.c b/trunk/drivers/net/wireless/rtlwifi/pci.c index 67f9430ee197..2062ea1d7c80 100644 --- a/trunk/drivers/net/wireless/rtlwifi/pci.c +++ b/trunk/drivers/net/wireless/rtlwifi/pci.c @@ -34,6 +34,7 @@ #include "ps.h" #include "efuse.h" #include +#include static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = { PCI_VENDOR_ID_INTEL, @@ -1099,6 +1100,7 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw) u32 bufferaddress; if (!skb) return 0; + kmemleak_not_leak(skb); entry = &rtlpci->rx_ring[rx_queue_idx].desc[i]; /*skb->dev = dev; */ diff --git a/trunk/drivers/net/wireless/rtlwifi/ps.c b/trunk/drivers/net/wireless/rtlwifi/ps.c index 5b9c3b5e8c92..5ae26647f340 100644 --- a/trunk/drivers/net/wireless/rtlwifi/ps.c +++ b/trunk/drivers/net/wireless/rtlwifi/ps.c @@ -480,7 +480,7 @@ void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len) return; /* and only beacons from the associated BSSID, please */ - if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid)) + if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid)) return; rtlpriv->psc.last_beacon = jiffies; diff --git a/trunk/drivers/net/wireless/rtlwifi/rc.c b/trunk/drivers/net/wireless/rtlwifi/rc.c index c66f08a0524a..d5cbf01da8ac 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rc.c +++ b/trunk/drivers/net/wireless/rtlwifi/rc.c @@ -225,8 +225,7 @@ static void rtl_rate_init(void *ppriv, static void rtl_rate_update(void *ppriv, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta, - u32 changed, - enum nl80211_channel_type oper_chan_type) + u32 changed) { } diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/trunk/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c index 1208b753f62f..f7f48c7ac854 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c @@ -33,9 +33,6 @@ #include "../pci.h" #include "../base.h" -struct dig_t dm_digtable; -static struct ps_t dm_pstable; - #define BT_RSSI_STATE_NORMAL_POWER BIT_OFFSET_LEN_MASK_32(0, 1) #define BT_RSSI_STATE_AMDPU_OFF BIT_OFFSET_LEN_MASK_32(1, 1) #define BT_RSSI_STATE_SPECIAL_LOW BIT_OFFSET_LEN_MASK_32(2, 1) @@ -163,33 +160,37 @@ static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = { static void rtl92c_dm_diginit(struct ieee80211_hw *hw) { - dm_digtable.dig_enable_flag = true; - dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; - dm_digtable.cur_igvalue = 0x20; - dm_digtable.pre_igvalue = 0x0; - dm_digtable.cursta_connectctate = DIG_STA_DISCONNECT; - dm_digtable.presta_connectstate = DIG_STA_DISCONNECT; - dm_digtable.curmultista_connectstate = DIG_MULTISTA_DISCONNECT; - dm_digtable.rssi_lowthresh = DM_DIG_THRESH_LOW; - dm_digtable.rssi_highthresh = DM_DIG_THRESH_HIGH; - dm_digtable.fa_lowthresh = DM_FALSEALARM_THRESH_LOW; - dm_digtable.fa_highthresh = DM_FALSEALARM_THRESH_HIGH; - dm_digtable.rx_gain_range_max = DM_DIG_MAX; - dm_digtable.rx_gain_range_min = DM_DIG_MIN; - dm_digtable.backoff_val = DM_DIG_BACKOFF_DEFAULT; - dm_digtable.backoff_val_range_max = DM_DIG_BACKOFF_MAX; - dm_digtable.backoff_val_range_min = DM_DIG_BACKOFF_MIN; - dm_digtable.pre_cck_pd_state = CCK_PD_STAGE_MAX; - dm_digtable.cur_cck_pd_state = CCK_PD_STAGE_MAX; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct dig_t *dm_digtable = &rtlpriv->dm_digtable; + + dm_digtable->dig_enable_flag = true; + dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; + dm_digtable->cur_igvalue = 0x20; + dm_digtable->pre_igvalue = 0x0; + dm_digtable->cursta_connectctate = DIG_STA_DISCONNECT; + dm_digtable->presta_connectstate = DIG_STA_DISCONNECT; + dm_digtable->curmultista_connectstate = DIG_MULTISTA_DISCONNECT; + dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW; + dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH; + dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW; + dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH; + dm_digtable->rx_gain_range_max = DM_DIG_MAX; + dm_digtable->rx_gain_range_min = DM_DIG_MIN; + dm_digtable->backoff_val = DM_DIG_BACKOFF_DEFAULT; + dm_digtable->backoff_val_range_max = DM_DIG_BACKOFF_MAX; + dm_digtable->backoff_val_range_min = DM_DIG_BACKOFF_MIN; + dm_digtable->pre_cck_pd_state = CCK_PD_STAGE_MAX; + dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX; } static u8 rtl92c_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct dig_t *dm_digtable = &rtlpriv->dm_digtable; long rssi_val_min = 0; - if ((dm_digtable.curmultista_connectstate == DIG_MULTISTA_CONNECT) && - (dm_digtable.cursta_connectctate == DIG_STA_CONNECT)) { + if ((dm_digtable->curmultista_connectstate == DIG_MULTISTA_CONNECT) && + (dm_digtable->cursta_connectctate == DIG_STA_CONNECT)) { if (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb != 0) rssi_val_min = (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb > @@ -198,10 +199,10 @@ static u8 rtl92c_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw) rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; else rssi_val_min = rtlpriv->dm.undecorated_smoothed_pwdb; - } else if (dm_digtable.cursta_connectctate == DIG_STA_CONNECT || - dm_digtable.cursta_connectctate == DIG_STA_BEFORE_CONNECT) { + } else if (dm_digtable->cursta_connectctate == DIG_STA_CONNECT || + dm_digtable->cursta_connectctate == DIG_STA_BEFORE_CONNECT) { rssi_val_min = rtlpriv->dm.undecorated_smoothed_pwdb; - } else if (dm_digtable.curmultista_connectstate == + } else if (dm_digtable->curmultista_connectstate == DIG_MULTISTA_CONNECT) { rssi_val_min = rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; } @@ -260,7 +261,8 @@ static void rtl92c_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw) static void rtl92c_dm_ctrl_initgain_by_fa(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); - u8 value_igi = dm_digtable.cur_igvalue; + struct dig_t *dm_digtable = &rtlpriv->dm_digtable; + u8 value_igi = dm_digtable->cur_igvalue; if (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH0) value_igi--; @@ -277,43 +279,44 @@ static void rtl92c_dm_ctrl_initgain_by_fa(struct ieee80211_hw *hw) if (rtlpriv->falsealm_cnt.cnt_all > 10000) value_igi = 0x32; - dm_digtable.cur_igvalue = value_igi; + dm_digtable->cur_igvalue = value_igi; rtl92c_dm_write_dig(hw); } static void rtl92c_dm_ctrl_initgain_by_rssi(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct dig_t *dm_digtable = &rtlpriv->dm_digtable; - if (rtlpriv->falsealm_cnt.cnt_all > dm_digtable.fa_highthresh) { - if ((dm_digtable.backoff_val - 2) < - dm_digtable.backoff_val_range_min) - dm_digtable.backoff_val = - dm_digtable.backoff_val_range_min; + if (rtlpriv->falsealm_cnt.cnt_all > dm_digtable->fa_highthresh) { + if ((dm_digtable->backoff_val - 2) < + dm_digtable->backoff_val_range_min) + dm_digtable->backoff_val = + dm_digtable->backoff_val_range_min; else - dm_digtable.backoff_val -= 2; - } else if (rtlpriv->falsealm_cnt.cnt_all < dm_digtable.fa_lowthresh) { - if ((dm_digtable.backoff_val + 2) > - dm_digtable.backoff_val_range_max) - dm_digtable.backoff_val = - dm_digtable.backoff_val_range_max; + dm_digtable->backoff_val -= 2; + } else if (rtlpriv->falsealm_cnt.cnt_all < dm_digtable->fa_lowthresh) { + if ((dm_digtable->backoff_val + 2) > + dm_digtable->backoff_val_range_max) + dm_digtable->backoff_val = + dm_digtable->backoff_val_range_max; else - dm_digtable.backoff_val += 2; + dm_digtable->backoff_val += 2; } - if ((dm_digtable.rssi_val_min + 10 - dm_digtable.backoff_val) > - dm_digtable.rx_gain_range_max) - dm_digtable.cur_igvalue = dm_digtable.rx_gain_range_max; - else if ((dm_digtable.rssi_val_min + 10 - - dm_digtable.backoff_val) < dm_digtable.rx_gain_range_min) - dm_digtable.cur_igvalue = dm_digtable.rx_gain_range_min; + if ((dm_digtable->rssi_val_min + 10 - dm_digtable->backoff_val) > + dm_digtable->rx_gain_range_max) + dm_digtable->cur_igvalue = dm_digtable->rx_gain_range_max; + else if ((dm_digtable->rssi_val_min + 10 - + dm_digtable->backoff_val) < dm_digtable->rx_gain_range_min) + dm_digtable->cur_igvalue = dm_digtable->rx_gain_range_min; else - dm_digtable.cur_igvalue = dm_digtable.rssi_val_min + 10 - - dm_digtable.backoff_val; + dm_digtable->cur_igvalue = dm_digtable->rssi_val_min + 10 - + dm_digtable->backoff_val; RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, "rssi_val_min = %x backoff_val %x\n", - dm_digtable.rssi_val_min, dm_digtable.backoff_val); + dm_digtable->rssi_val_min, dm_digtable->backoff_val); rtl92c_dm_write_dig(hw); } @@ -322,6 +325,7 @@ static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw) { static u8 initialized; /* initialized to false */ struct rtl_priv *rtlpriv = rtl_priv(hw); + struct dig_t *dm_digtable = &rtlpriv->dm_digtable; struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); long rssi_strength = rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; bool multi_sta = false; @@ -330,68 +334,69 @@ static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw) multi_sta = true; if (!multi_sta || - dm_digtable.cursta_connectctate != DIG_STA_DISCONNECT) { + dm_digtable->cursta_connectctate != DIG_STA_DISCONNECT) { initialized = false; - dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; + dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; return; } else if (initialized == false) { initialized = true; - dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_0; - dm_digtable.cur_igvalue = 0x20; + dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_0; + dm_digtable->cur_igvalue = 0x20; rtl92c_dm_write_dig(hw); } - if (dm_digtable.curmultista_connectstate == DIG_MULTISTA_CONNECT) { - if ((rssi_strength < dm_digtable.rssi_lowthresh) && - (dm_digtable.dig_ext_port_stage != DIG_EXT_PORT_STAGE_1)) { + if (dm_digtable->curmultista_connectstate == DIG_MULTISTA_CONNECT) { + if ((rssi_strength < dm_digtable->rssi_lowthresh) && + (dm_digtable->dig_ext_port_stage != DIG_EXT_PORT_STAGE_1)) { - if (dm_digtable.dig_ext_port_stage == + if (dm_digtable->dig_ext_port_stage == DIG_EXT_PORT_STAGE_2) { - dm_digtable.cur_igvalue = 0x20; + dm_digtable->cur_igvalue = 0x20; rtl92c_dm_write_dig(hw); } - dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_1; - } else if (rssi_strength > dm_digtable.rssi_highthresh) { - dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_2; + dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_1; + } else if (rssi_strength > dm_digtable->rssi_highthresh) { + dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_2; rtl92c_dm_ctrl_initgain_by_fa(hw); } - } else if (dm_digtable.dig_ext_port_stage != DIG_EXT_PORT_STAGE_0) { - dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_0; - dm_digtable.cur_igvalue = 0x20; + } else if (dm_digtable->dig_ext_port_stage != DIG_EXT_PORT_STAGE_0) { + dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_0; + dm_digtable->cur_igvalue = 0x20; rtl92c_dm_write_dig(hw); } RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, "curmultista_connectstate = %x dig_ext_port_stage %x\n", - dm_digtable.curmultista_connectstate, - dm_digtable.dig_ext_port_stage); + dm_digtable->curmultista_connectstate, + dm_digtable->dig_ext_port_stage); } static void rtl92c_dm_initial_gain_sta(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct dig_t *dm_digtable = &rtlpriv->dm_digtable; RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, "presta_connectstate = %x, cursta_connectctate = %x\n", - dm_digtable.presta_connectstate, - dm_digtable.cursta_connectctate); + dm_digtable->presta_connectstate, + dm_digtable->cursta_connectctate); - if (dm_digtable.presta_connectstate == dm_digtable.cursta_connectctate - || dm_digtable.cursta_connectctate == DIG_STA_BEFORE_CONNECT - || dm_digtable.cursta_connectctate == DIG_STA_CONNECT) { + if (dm_digtable->presta_connectstate == dm_digtable->cursta_connectctate + || dm_digtable->cursta_connectctate == DIG_STA_BEFORE_CONNECT + || dm_digtable->cursta_connectctate == DIG_STA_CONNECT) { - if (dm_digtable.cursta_connectctate != DIG_STA_DISCONNECT) { - dm_digtable.rssi_val_min = + if (dm_digtable->cursta_connectctate != DIG_STA_DISCONNECT) { + dm_digtable->rssi_val_min = rtl92c_dm_initial_gain_min_pwdb(hw); rtl92c_dm_ctrl_initgain_by_rssi(hw); } } else { - dm_digtable.rssi_val_min = 0; - dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; - dm_digtable.backoff_val = DM_DIG_BACKOFF_DEFAULT; - dm_digtable.cur_igvalue = 0x20; - dm_digtable.pre_igvalue = 0; + dm_digtable->rssi_val_min = 0; + dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; + dm_digtable->backoff_val = DM_DIG_BACKOFF_DEFAULT; + dm_digtable->cur_igvalue = 0x20; + dm_digtable->pre_igvalue = 0; rtl92c_dm_write_dig(hw); } } @@ -400,40 +405,41 @@ static void rtl92c_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct dig_t *dm_digtable = &rtlpriv->dm_digtable; - if (dm_digtable.cursta_connectctate == DIG_STA_CONNECT) { - dm_digtable.rssi_val_min = rtl92c_dm_initial_gain_min_pwdb(hw); + if (dm_digtable->cursta_connectctate == DIG_STA_CONNECT) { + dm_digtable->rssi_val_min = rtl92c_dm_initial_gain_min_pwdb(hw); - if (dm_digtable.pre_cck_pd_state == CCK_PD_STAGE_LowRssi) { - if (dm_digtable.rssi_val_min <= 25) - dm_digtable.cur_cck_pd_state = + if (dm_digtable->pre_cck_pd_state == CCK_PD_STAGE_LowRssi) { + if (dm_digtable->rssi_val_min <= 25) + dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_LowRssi; else - dm_digtable.cur_cck_pd_state = + dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_HighRssi; } else { - if (dm_digtable.rssi_val_min <= 20) - dm_digtable.cur_cck_pd_state = + if (dm_digtable->rssi_val_min <= 20) + dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_LowRssi; else - dm_digtable.cur_cck_pd_state = + dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_HighRssi; } } else { - dm_digtable.cur_cck_pd_state = CCK_PD_STAGE_MAX; + dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX; } - if (dm_digtable.pre_cck_pd_state != dm_digtable.cur_cck_pd_state) { - if (dm_digtable.cur_cck_pd_state == CCK_PD_STAGE_LowRssi) { + if (dm_digtable->pre_cck_pd_state != dm_digtable->cur_cck_pd_state) { + if (dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_LowRssi) { if (rtlpriv->falsealm_cnt.cnt_cck_fail > 800) - dm_digtable.cur_cck_fa_state = + dm_digtable->cur_cck_fa_state = CCK_FA_STAGE_High; else - dm_digtable.cur_cck_fa_state = CCK_FA_STAGE_Low; + dm_digtable->cur_cck_fa_state = CCK_FA_STAGE_Low; - if (dm_digtable.pre_cck_fa_state != - dm_digtable.cur_cck_fa_state) { - if (dm_digtable.cur_cck_fa_state == + if (dm_digtable->pre_cck_fa_state != + dm_digtable->cur_cck_fa_state) { + if (dm_digtable->cur_cck_fa_state == CCK_FA_STAGE_Low) rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0x83); @@ -441,8 +447,8 @@ static void rtl92c_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw) rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0xcd); - dm_digtable.pre_cck_fa_state = - dm_digtable.cur_cck_fa_state; + dm_digtable->pre_cck_fa_state = + dm_digtable->cur_cck_fa_state; } rtl_set_bbreg(hw, RCCK0_SYSTEM, MASKBYTE1, 0x40); @@ -458,11 +464,11 @@ static void rtl92c_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw) rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, MASKBYTE2, 0xd3); } - dm_digtable.pre_cck_pd_state = dm_digtable.cur_cck_pd_state; + dm_digtable->pre_cck_pd_state = dm_digtable->cur_cck_pd_state; } RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, "CCKPDStage=%x\n", - dm_digtable.cur_cck_pd_state); + dm_digtable->cur_cck_pd_state); RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, "is92C=%x\n", IS_92C_SERIAL(rtlhal->version)); @@ -470,31 +476,34 @@ static void rtl92c_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw) static void rtl92c_dm_ctrl_initgain_by_twoport(struct ieee80211_hw *hw) { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct dig_t *dm_digtable = &rtlpriv->dm_digtable; struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); if (mac->act_scanning) return; if (mac->link_state >= MAC80211_LINKED) - dm_digtable.cursta_connectctate = DIG_STA_CONNECT; + dm_digtable->cursta_connectctate = DIG_STA_CONNECT; else - dm_digtable.cursta_connectctate = DIG_STA_DISCONNECT; + dm_digtable->cursta_connectctate = DIG_STA_DISCONNECT; rtl92c_dm_initial_gain_sta(hw); rtl92c_dm_initial_gain_multi_sta(hw); rtl92c_dm_cck_packet_detection_thresh(hw); - dm_digtable.presta_connectstate = dm_digtable.cursta_connectctate; + dm_digtable->presta_connectstate = dm_digtable->cursta_connectctate; } static void rtl92c_dm_dig(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct dig_t *dm_digtable = &rtlpriv->dm_digtable; if (rtlpriv->dm.dm_initialgain_enable == false) return; - if (dm_digtable.dig_enable_flag == false) + if (dm_digtable->dig_enable_flag == false) return; rtl92c_dm_ctrl_initgain_by_twoport(hw); @@ -514,23 +523,24 @@ static void rtl92c_dm_init_dynamic_txpower(struct ieee80211_hw *hw) void rtl92c_dm_write_dig(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct dig_t *dm_digtable = &rtlpriv->dm_digtable; RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "cur_igvalue = 0x%x, pre_igvalue = 0x%x, backoff_val = %d\n", - dm_digtable.cur_igvalue, dm_digtable.pre_igvalue, - dm_digtable.backoff_val); + dm_digtable->cur_igvalue, dm_digtable->pre_igvalue, + dm_digtable->backoff_val); - dm_digtable.cur_igvalue += 2; - if (dm_digtable.cur_igvalue > 0x3f) - dm_digtable.cur_igvalue = 0x3f; + dm_digtable->cur_igvalue += 2; + if (dm_digtable->cur_igvalue > 0x3f) + dm_digtable->cur_igvalue = 0x3f; - if (dm_digtable.pre_igvalue != dm_digtable.cur_igvalue) { + if (dm_digtable->pre_igvalue != dm_digtable->cur_igvalue) { rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f, - dm_digtable.cur_igvalue); + dm_digtable->cur_igvalue); rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, 0x7f, - dm_digtable.cur_igvalue); + dm_digtable->cur_igvalue); - dm_digtable.pre_igvalue = dm_digtable.cur_igvalue; + dm_digtable->pre_igvalue = dm_digtable->cur_igvalue; } } EXPORT_SYMBOL(rtl92c_dm_write_dig); @@ -1223,15 +1233,20 @@ static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw) static void rtl92c_dm_init_dynamic_bb_powersaving(struct ieee80211_hw *hw) { - dm_pstable.pre_ccastate = CCA_MAX; - dm_pstable.cur_ccasate = CCA_MAX; - dm_pstable.pre_rfstate = RF_MAX; - dm_pstable.cur_rfstate = RF_MAX; - dm_pstable.rssi_val_min = 0; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ps_t *dm_pstable = &rtlpriv->dm_pstable; + + dm_pstable->pre_ccastate = CCA_MAX; + dm_pstable->cur_ccasate = CCA_MAX; + dm_pstable->pre_rfstate = RF_MAX; + dm_pstable->cur_rfstate = RF_MAX; + dm_pstable->rssi_val_min = 0; } void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal) { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ps_t *dm_pstable = &rtlpriv->dm_pstable; static u8 initialize; static u32 reg_874, reg_c70, reg_85c, reg_a74; @@ -1251,27 +1266,27 @@ void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal) } if (!bforce_in_normal) { - if (dm_pstable.rssi_val_min != 0) { - if (dm_pstable.pre_rfstate == RF_NORMAL) { - if (dm_pstable.rssi_val_min >= 30) - dm_pstable.cur_rfstate = RF_SAVE; + if (dm_pstable->rssi_val_min != 0) { + if (dm_pstable->pre_rfstate == RF_NORMAL) { + if (dm_pstable->rssi_val_min >= 30) + dm_pstable->cur_rfstate = RF_SAVE; else - dm_pstable.cur_rfstate = RF_NORMAL; + dm_pstable->cur_rfstate = RF_NORMAL; } else { - if (dm_pstable.rssi_val_min <= 25) - dm_pstable.cur_rfstate = RF_NORMAL; + if (dm_pstable->rssi_val_min <= 25) + dm_pstable->cur_rfstate = RF_NORMAL; else - dm_pstable.cur_rfstate = RF_SAVE; + dm_pstable->cur_rfstate = RF_SAVE; } } else { - dm_pstable.cur_rfstate = RF_MAX; + dm_pstable->cur_rfstate = RF_MAX; } } else { - dm_pstable.cur_rfstate = RF_NORMAL; + dm_pstable->cur_rfstate = RF_NORMAL; } - if (dm_pstable.pre_rfstate != dm_pstable.cur_rfstate) { - if (dm_pstable.cur_rfstate == RF_SAVE) { + if (dm_pstable->pre_rfstate != dm_pstable->cur_rfstate) { + if (dm_pstable->cur_rfstate == RF_SAVE) { rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, 0x1C0000, 0x2); rtl_set_bbreg(hw, ROFDM0_AGCPARAMETER1, BIT(3), 0); @@ -1293,7 +1308,7 @@ void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal) rtl_set_bbreg(hw, 0x818, BIT(28), 0x0); } - dm_pstable.pre_rfstate = dm_pstable.cur_rfstate; + dm_pstable->pre_rfstate = dm_pstable->cur_rfstate; } } EXPORT_SYMBOL(rtl92c_dm_rf_saving); @@ -1301,36 +1316,37 @@ EXPORT_SYMBOL(rtl92c_dm_rf_saving); static void rtl92c_dm_dynamic_bb_powersaving(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ps_t *dm_pstable = &rtlpriv->dm_pstable; struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); if (((mac->link_state == MAC80211_NOLINK)) && (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) { - dm_pstable.rssi_val_min = 0; + dm_pstable->rssi_val_min = 0; RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, "Not connected to any\n"); } if (mac->link_state == MAC80211_LINKED) { if (mac->opmode == NL80211_IFTYPE_ADHOC) { - dm_pstable.rssi_val_min = + dm_pstable->rssi_val_min = rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, "AP Client PWDB = 0x%lx\n", - dm_pstable.rssi_val_min); + dm_pstable->rssi_val_min); } else { - dm_pstable.rssi_val_min = + dm_pstable->rssi_val_min = rtlpriv->dm.undecorated_smoothed_pwdb; RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, "STA Default Port PWDB = 0x%lx\n", - dm_pstable.rssi_val_min); + dm_pstable->rssi_val_min); } } else { - dm_pstable.rssi_val_min = + dm_pstable->rssi_val_min = rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, "AP Ext Port PWDB = 0x%lx\n", - dm_pstable.rssi_val_min); + dm_pstable->rssi_val_min); } if (IS_92C_SERIAL(rtlhal->version)) diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h b/trunk/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h index 2178e3761883..518e208c0180 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h @@ -91,40 +91,6 @@ #define TX_POWER_NEAR_FIELD_THRESH_LVL2 74 #define TX_POWER_NEAR_FIELD_THRESH_LVL1 67 -struct ps_t { - u8 pre_ccastate; - u8 cur_ccasate; - u8 pre_rfstate; - u8 cur_rfstate; - long rssi_val_min; -}; - -struct dig_t { - u8 dig_enable_flag; - u8 dig_ext_port_stage; - u32 rssi_lowthresh; - u32 rssi_highthresh; - u32 fa_lowthresh; - u32 fa_highthresh; - u8 cursta_connectctate; - u8 presta_connectstate; - u8 curmultista_connectstate; - u8 pre_igvalue; - u8 cur_igvalue; - char backoff_val; - char backoff_val_range_max; - char backoff_val_range_min; - u8 rx_gain_range_max; - u8 rx_gain_range_min; - u8 rssi_val_min; - u8 pre_cck_pd_state; - u8 cur_cck_pd_state; - u8 pre_cck_fa_state; - u8 cur_cck_fa_state; - u8 pre_ccastate; - u8 cur_ccasate; -}; - struct swat_t { u8 failure_cnt; u8 try_flag; @@ -189,7 +155,6 @@ enum dm_dig_connect_e { DIG_CONNECT_MAX }; -extern struct dig_t dm_digtable; void rtl92c_dm_init(struct ieee80211_hw *hw); void rtl92c_dm_watchdog(struct ieee80211_hw *hw); void rtl92c_dm_write_dig(struct ieee80211_hw *hw); diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/trunk/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c index c20b3c30f62e..692c8ef5ee89 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c @@ -34,6 +34,7 @@ #include "../rtl8192ce/def.h" #include "fw_common.h" #include +#include static void _rtl92c_enable_fw_download(struct ieee80211_hw *hw, bool enable) { @@ -776,6 +777,8 @@ void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished) skb = dev_alloc_skb(totalpacketlen); if (!skb) return; + kmemleak_not_leak(skb); + memcpy((u8 *) skb_put(skb, totalpacketlen), &reserved_page_packet, totalpacketlen); diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c b/trunk/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c index 4c016241f340..cdcad7d9f15e 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c @@ -1881,6 +1881,7 @@ void rtl92c_phy_set_io(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct dig_t dm_digtable = rtlpriv->dm_digtable; RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, "--->Cmd(%#x), set_io_inprogress(%d)\n", diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h b/trunk/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h index 26747fa86005..d4a3d032c7bf 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h @@ -86,40 +86,6 @@ #define TX_POWER_NEAR_FIELD_THRESH_LVL2 74 #define TX_POWER_NEAR_FIELD_THRESH_LVL1 67 -struct ps_t { - u8 pre_ccastate; - u8 cur_ccasate; - u8 pre_rfstate; - u8 cur_rfstate; - long rssi_val_min; -}; - -struct dig_t { - u8 dig_enable_flag; - u8 dig_ext_port_stage; - u32 rssi_lowthresh; - u32 rssi_highthresh; - u32 fa_lowthresh; - u32 fa_highthresh; - u8 cursta_connectctate; - u8 presta_connectstate; - u8 curmultista_connectstate; - u8 pre_igvalue; - u8 cur_igvalue; - char backoff_val; - char backoff_val_range_max; - char backoff_val_range_min; - u8 rx_gain_range_max; - u8 rx_gain_range_min; - u8 rssi_val_min; - u8 pre_cck_pd_state; - u8 cur_cck_pd_state; - u8 pre_cck_fa_state; - u8 cur_cck_fa_state; - u8 pre_ccastate; - u8 cur_ccasate; -}; - struct swat_t { u8 failure_cnt; u8 try_flag; @@ -184,7 +150,6 @@ enum dm_dig_connect_e { DIG_CONNECT_MAX }; -extern struct dig_t dm_digtable; void rtl92c_dm_init(struct ieee80211_hw *hw); void rtl92c_dm_watchdog(struct ieee80211_hw *hw); void rtl92c_dm_write_dig(struct ieee80211_hw *hw); diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/trunk/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c index 2c3b73366cd2..3aa927f8b9b9 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c @@ -389,21 +389,4 @@ static struct pci_driver rtl92ce_driver = { .driver.pm = &rtlwifi_pm_ops, }; -static int __init rtl92ce_module_init(void) -{ - int ret; - - ret = pci_register_driver(&rtl92ce_driver); - if (ret) - RT_ASSERT(false, "No device found\n"); - - return ret; -} - -static void __exit rtl92ce_module_exit(void) -{ - pci_unregister_driver(&rtl92ce_driver); -} - -module_init(rtl92ce_module_init); -module_exit(rtl92ce_module_exit); +module_pci_driver(rtl92ce_driver); diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/trunk/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c index 37b13636a778..3af874e69595 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c @@ -508,14 +508,14 @@ static void _rtl92ce_translate_rx_signal_stuff(struct ieee80211_hw *hw, packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) && - (!compare_ether_addr(mac->bssid, - (c_fc & IEEE80211_FCTL_TODS) ? - hdr->addr1 : (c_fc & IEEE80211_FCTL_FROMDS) ? - hdr->addr2 : hdr->addr3)) && + ether_addr_equal(mac->bssid, + (c_fc & IEEE80211_FCTL_TODS) ? hdr->addr1 : + (c_fc & IEEE80211_FCTL_FROMDS) ? hdr->addr2 : + hdr->addr3) && (!pstats->hwerror) && (!pstats->crc) && (!pstats->icv)); packet_toself = packet_matchbssid && - (!compare_ether_addr(praddr, rtlefuse->dev_addr)); + ether_addr_equal(praddr, rtlefuse->dev_addr); if (ieee80211_is_beacon(fc)) packet_beacon = true; diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h b/trunk/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h index efb9ab270403..c4adb9777365 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h @@ -530,12 +530,7 @@ SET_BITS_OFFSET_LE(__pdesc+28, 0, 32, __val) #define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size) \ -do { \ - if (_size > TX_DESC_NEXT_DESC_OFFSET) \ - memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \ - else \ - memset(__pdesc, 0, _size); \ -} while (0); + memset(__pdesc, 0, min_t(size_t, _size, TX_DESC_NEXT_DESC_OFFSET)) struct rx_fwinfo_92c { u8 gain_trsw[4]; diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/trunk/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c index 025bdc2eba44..7e91c76582ec 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c @@ -1099,14 +1099,14 @@ void rtl92c_translate_rx_signal_stuff(struct ieee80211_hw *hw, praddr = hdr->addr1; packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) && - (!compare_ether_addr(mac->bssid, - (cpu_fc & IEEE80211_FCTL_TODS) ? - hdr->addr1 : (cpu_fc & IEEE80211_FCTL_FROMDS) ? - hdr->addr2 : hdr->addr3)) && + ether_addr_equal(mac->bssid, + (cpu_fc & IEEE80211_FCTL_TODS) ? hdr->addr1 : + (cpu_fc & IEEE80211_FCTL_FROMDS) ? hdr->addr2 : + hdr->addr3) && (!pstats->hwerror) && (!pstats->crc) && (!pstats->icv)); packet_toself = packet_matchbssid && - (!compare_ether_addr(praddr, rtlefuse->dev_addr)); + ether_addr_equal(praddr, rtlefuse->dev_addr); if (ieee80211_is_beacon(fc)) packet_beacon = true; _rtl92c_query_rxphystatus(hw, pstats, pdesc, p_drvinfo, diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/trunk/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index 82c85286ab2e..d228358e6a40 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -338,6 +338,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = { {RTL_USB_DEVICE(0x2019, 0x1201, rtl92cu_hal_cfg)}, /*Planex-Vencer*/ /****** 8192CU ********/ + {RTL_USB_DEVICE(0x050d, 0x1004, rtl92cu_hal_cfg)}, /*Belcom-SurfN300*/ {RTL_USB_DEVICE(0x050d, 0x2102, rtl92cu_hal_cfg)}, /*Belcom-Sercomm*/ {RTL_USB_DEVICE(0x050d, 0x2103, rtl92cu_hal_cfg)}, /*Belcom-Edimax*/ {RTL_USB_DEVICE(0x0586, 0x341f, rtl92cu_hal_cfg)}, /*Zyxel -Abocom*/ @@ -372,6 +373,7 @@ static struct usb_driver rtl8192cu_driver = { #ifdef CONFIG_AUTOSUSPEND .supports_autosuspend = 1, #endif + .disable_hub_initiated_lpm = 1, }; module_usb_driver(rtl8192cu_driver); diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192de/def.h b/trunk/drivers/net/wireless/rtlwifi/rtl8192de/def.h index eafdf76ed64d..939c905f547f 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192de/def.h +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192de/def.h @@ -151,9 +151,6 @@ enum version_8192d { /* for 92D */ #define CHIP_92D_SINGLEPHY BIT(9) -#define C_CUT_VERSION BIT(13) -#define D_CUT_VERSION ((BIT(12)|BIT(13))) -#define E_CUT_VERSION BIT(14) /* Chip specific */ #define CHIP_BONDING_IDENTIFIER(_value) (((_value)>>22)&0x3) @@ -173,7 +170,10 @@ enum version_8192d { #define RF_TYPE_1T2R BIT(4) #define RF_TYPE_2T2R BIT(5) #define CHIP_VENDOR_UMC BIT(7) -#define B_CUT_VERSION BIT(12) +#define CHIP_92D_B_CUT BIT(12) +#define CHIP_92D_C_CUT BIT(13) +#define CHIP_92D_D_CUT (BIT(13)|BIT(12)) +#define CHIP_92D_E_CUT BIT(14) /* MASK */ #define IC_TYPE_MASK (BIT(0)|BIT(1)|BIT(2)) @@ -205,15 +205,13 @@ enum version_8192d { CHIP_92D) ? true : false) #define IS_92D_C_CUT(version) ((IS_92D(version)) ? \ ((GET_CVID_CUT_VERSION(version) == \ - 0x2000) ? true : false) : false) + CHIP_92D_C_CUT) ? true : false) : false) #define IS_92D_D_CUT(version) ((IS_92D(version)) ? \ ((GET_CVID_CUT_VERSION(version) == \ - 0x3000) ? true : false) : false) + CHIP_92D_D_CUT) ? true : false) : false) #define IS_92D_E_CUT(version) ((IS_92D(version)) ? \ ((GET_CVID_CUT_VERSION(version) == \ - 0x4000) ? true : false) : false) -#define CHIP_92D_C_CUT BIT(10) -#define CHIP_92D_D_CUT BIT(11) + CHIP_92D_E_CUT) ? true : false) : false) enum rf_optype { RF_OP_BY_SW_3WIRE = 0, diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192de/dm.c b/trunk/drivers/net/wireless/rtlwifi/rtl8192de/dm.c index 4737018c9daa..a7d63a84551a 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192de/dm.c +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192de/dm.c @@ -37,8 +37,6 @@ #define UNDEC_SM_PWDB entry_min_undecoratedsmoothed_pwdb -struct dig_t de_digtable; - static const u32 ofdmswing_table[OFDM_TABLE_SIZE_92D] = { 0x7f8001fe, /* 0, +6.0dB */ 0x788001e2, /* 1, +5.5dB */ @@ -159,27 +157,30 @@ static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = { static void rtl92d_dm_diginit(struct ieee80211_hw *hw) { - de_digtable.dig_enable_flag = true; - de_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; - de_digtable.cur_igvalue = 0x20; - de_digtable.pre_igvalue = 0x0; - de_digtable.cursta_connectctate = DIG_STA_DISCONNECT; - de_digtable.presta_connectstate = DIG_STA_DISCONNECT; - de_digtable.curmultista_connectstate = DIG_MULTISTA_DISCONNECT; - de_digtable.rssi_lowthresh = DM_DIG_THRESH_LOW; - de_digtable.rssi_highthresh = DM_DIG_THRESH_HIGH; - de_digtable.fa_lowthresh = DM_FALSEALARM_THRESH_LOW; - de_digtable.fa_highthresh = DM_FALSEALARM_THRESH_HIGH; - de_digtable.rx_gain_range_max = DM_DIG_FA_UPPER; - de_digtable.rx_gain_range_min = DM_DIG_FA_LOWER; - de_digtable.backoff_val = DM_DIG_BACKOFF_DEFAULT; - de_digtable.backoff_val_range_max = DM_DIG_BACKOFF_MAX; - de_digtable.backoff_val_range_min = DM_DIG_BACKOFF_MIN; - de_digtable.pre_cck_pd_state = CCK_PD_STAGE_LOWRSSI; - de_digtable.cur_cck_pd_state = CCK_PD_STAGE_MAX; - de_digtable.large_fa_hit = 0; - de_digtable.recover_cnt = 0; - de_digtable.forbidden_igi = DM_DIG_FA_LOWER; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct dig_t *de_digtable = &rtlpriv->dm_digtable; + + de_digtable->dig_enable_flag = true; + de_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; + de_digtable->cur_igvalue = 0x20; + de_digtable->pre_igvalue = 0x0; + de_digtable->cursta_connectctate = DIG_STA_DISCONNECT; + de_digtable->presta_connectstate = DIG_STA_DISCONNECT; + de_digtable->curmultista_connectstate = DIG_MULTISTA_DISCONNECT; + de_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW; + de_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH; + de_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW; + de_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH; + de_digtable->rx_gain_range_max = DM_DIG_FA_UPPER; + de_digtable->rx_gain_range_min = DM_DIG_FA_LOWER; + de_digtable->backoff_val = DM_DIG_BACKOFF_DEFAULT; + de_digtable->backoff_val_range_max = DM_DIG_BACKOFF_MAX; + de_digtable->backoff_val_range_min = DM_DIG_BACKOFF_MIN; + de_digtable->pre_cck_pd_state = CCK_PD_STAGE_LOWRSSI; + de_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX; + de_digtable->large_fa_hit = 0; + de_digtable->recover_cnt = 0; + de_digtable->forbidden_igi = DM_DIG_FA_LOWER; } static void rtl92d_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw) @@ -266,68 +267,70 @@ static void rtl92d_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw) static void rtl92d_dm_find_minimum_rssi(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct dig_t *de_digtable = &rtlpriv->dm_digtable; struct rtl_mac *mac = rtl_mac(rtlpriv); /* Determine the minimum RSSI */ if ((mac->link_state < MAC80211_LINKED) && (rtlpriv->dm.UNDEC_SM_PWDB == 0)) { - de_digtable.min_undecorated_pwdb_for_dm = 0; + de_digtable->min_undecorated_pwdb_for_dm = 0; RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD, "Not connected to any\n"); } if (mac->link_state >= MAC80211_LINKED) { if (mac->opmode == NL80211_IFTYPE_AP || mac->opmode == NL80211_IFTYPE_ADHOC) { - de_digtable.min_undecorated_pwdb_for_dm = + de_digtable->min_undecorated_pwdb_for_dm = rtlpriv->dm.UNDEC_SM_PWDB; RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD, "AP Client PWDB = 0x%lx\n", rtlpriv->dm.UNDEC_SM_PWDB); } else { - de_digtable.min_undecorated_pwdb_for_dm = + de_digtable->min_undecorated_pwdb_for_dm = rtlpriv->dm.undecorated_smoothed_pwdb; RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD, "STA Default Port PWDB = 0x%x\n", - de_digtable.min_undecorated_pwdb_for_dm); + de_digtable->min_undecorated_pwdb_for_dm); } } else { - de_digtable.min_undecorated_pwdb_for_dm = + de_digtable->min_undecorated_pwdb_for_dm = rtlpriv->dm.UNDEC_SM_PWDB; RT_TRACE(rtlpriv, COMP_BB_POWERSAVING, DBG_LOUD, "AP Ext Port or disconnect PWDB = 0x%x\n", - de_digtable.min_undecorated_pwdb_for_dm); + de_digtable->min_undecorated_pwdb_for_dm); } RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "MinUndecoratedPWDBForDM =%d\n", - de_digtable.min_undecorated_pwdb_for_dm); + de_digtable->min_undecorated_pwdb_for_dm); } static void rtl92d_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct dig_t *de_digtable = &rtlpriv->dm_digtable; unsigned long flag = 0; - if (de_digtable.cursta_connectctate == DIG_STA_CONNECT) { - if (de_digtable.pre_cck_pd_state == CCK_PD_STAGE_LOWRSSI) { - if (de_digtable.min_undecorated_pwdb_for_dm <= 25) - de_digtable.cur_cck_pd_state = + if (de_digtable->cursta_connectctate == DIG_STA_CONNECT) { + if (de_digtable->pre_cck_pd_state == CCK_PD_STAGE_LOWRSSI) { + if (de_digtable->min_undecorated_pwdb_for_dm <= 25) + de_digtable->cur_cck_pd_state = CCK_PD_STAGE_LOWRSSI; else - de_digtable.cur_cck_pd_state = + de_digtable->cur_cck_pd_state = CCK_PD_STAGE_HIGHRSSI; } else { - if (de_digtable.min_undecorated_pwdb_for_dm <= 20) - de_digtable.cur_cck_pd_state = + if (de_digtable->min_undecorated_pwdb_for_dm <= 20) + de_digtable->cur_cck_pd_state = CCK_PD_STAGE_LOWRSSI; else - de_digtable.cur_cck_pd_state = + de_digtable->cur_cck_pd_state = CCK_PD_STAGE_HIGHRSSI; } } else { - de_digtable.cur_cck_pd_state = CCK_PD_STAGE_LOWRSSI; + de_digtable->cur_cck_pd_state = CCK_PD_STAGE_LOWRSSI; } - if (de_digtable.pre_cck_pd_state != de_digtable.cur_cck_pd_state) { - if (de_digtable.cur_cck_pd_state == CCK_PD_STAGE_LOWRSSI) { + if (de_digtable->pre_cck_pd_state != de_digtable->cur_cck_pd_state) { + if (de_digtable->cur_cck_pd_state == CCK_PD_STAGE_LOWRSSI) { rtl92d_acquire_cckandrw_pagea_ctl(hw, &flag); rtl_set_bbreg(hw, RCCK0_CCA, BMASKBYTE2, 0x83); rtl92d_release_cckandrw_pagea_ctl(hw, &flag); @@ -336,13 +339,13 @@ static void rtl92d_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw) rtl_set_bbreg(hw, RCCK0_CCA, BMASKBYTE2, 0xcd); rtl92d_release_cckandrw_pagea_ctl(hw, &flag); } - de_digtable.pre_cck_pd_state = de_digtable.cur_cck_pd_state; + de_digtable->pre_cck_pd_state = de_digtable->cur_cck_pd_state; } RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "CurSTAConnectState=%s\n", - de_digtable.cursta_connectctate == DIG_STA_CONNECT ? + de_digtable->cursta_connectctate == DIG_STA_CONNECT ? "DIG_STA_CONNECT " : "DIG_STA_DISCONNECT"); RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "CCKPDStage=%s\n", - de_digtable.cur_cck_pd_state == CCK_PD_STAGE_LOWRSSI ? + de_digtable->cur_cck_pd_state == CCK_PD_STAGE_LOWRSSI ? "Low RSSI " : "High RSSI "); RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "is92d single phy =%x\n", IS_92D_SINGLEPHY(rtlpriv->rtlhal.version)); @@ -352,37 +355,40 @@ static void rtl92d_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw) void rtl92d_dm_write_dig(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct dig_t *de_digtable = &rtlpriv->dm_digtable; RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "cur_igvalue = 0x%x, pre_igvalue = 0x%x, backoff_val = %d\n", - de_digtable.cur_igvalue, de_digtable.pre_igvalue, - de_digtable.backoff_val); - if (de_digtable.dig_enable_flag == false) { + de_digtable->cur_igvalue, de_digtable->pre_igvalue, + de_digtable->backoff_val); + if (de_digtable->dig_enable_flag == false) { RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "DIG is disabled\n"); - de_digtable.pre_igvalue = 0x17; + de_digtable->pre_igvalue = 0x17; return; } - if (de_digtable.pre_igvalue != de_digtable.cur_igvalue) { + if (de_digtable->pre_igvalue != de_digtable->cur_igvalue) { rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f, - de_digtable.cur_igvalue); + de_digtable->cur_igvalue); rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, 0x7f, - de_digtable.cur_igvalue); - de_digtable.pre_igvalue = de_digtable.cur_igvalue; + de_digtable->cur_igvalue); + de_digtable->pre_igvalue = de_digtable->cur_igvalue; } } static void rtl92d_early_mode_enabled(struct rtl_priv *rtlpriv) { + struct dig_t *de_digtable = &rtlpriv->dm_digtable; + if ((rtlpriv->mac80211.link_state >= MAC80211_LINKED) && (rtlpriv->mac80211.vendor == PEER_CISCO)) { RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "IOT_PEER = CISCO\n"); - if (de_digtable.last_min_undecorated_pwdb_for_dm >= 50 - && de_digtable.min_undecorated_pwdb_for_dm < 50) { + if (de_digtable->last_min_undecorated_pwdb_for_dm >= 50 + && de_digtable->min_undecorated_pwdb_for_dm < 50) { rtl_write_byte(rtlpriv, REG_EARLY_MODE_CONTROL, 0x00); RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "Early Mode Off\n"); - } else if (de_digtable.last_min_undecorated_pwdb_for_dm <= 55 && - de_digtable.min_undecorated_pwdb_for_dm > 55) { + } else if (de_digtable->last_min_undecorated_pwdb_for_dm <= 55 && + de_digtable->min_undecorated_pwdb_for_dm > 55) { rtl_write_byte(rtlpriv, REG_EARLY_MODE_CONTROL, 0x0f); RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "Early Mode On\n"); @@ -396,14 +402,15 @@ static void rtl92d_early_mode_enabled(struct rtl_priv *rtlpriv) static void rtl92d_dm_dig(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); - u8 value_igi = de_digtable.cur_igvalue; + struct dig_t *de_digtable = &rtlpriv->dm_digtable; + u8 value_igi = de_digtable->cur_igvalue; struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt); RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "==>\n"); if (rtlpriv->rtlhal.earlymode_enable) { rtl92d_early_mode_enabled(rtlpriv); - de_digtable.last_min_undecorated_pwdb_for_dm = - de_digtable.min_undecorated_pwdb_for_dm; + de_digtable->last_min_undecorated_pwdb_for_dm = + de_digtable->min_undecorated_pwdb_for_dm; } if (!rtlpriv->dm.dm_initialgain_enable) return; @@ -421,9 +428,9 @@ static void rtl92d_dm_dig(struct ieee80211_hw *hw) RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "progress\n"); /* Decide the current status and if modify initial gain or not */ if (rtlpriv->mac80211.link_state >= MAC80211_LINKED) - de_digtable.cursta_connectctate = DIG_STA_CONNECT; + de_digtable->cursta_connectctate = DIG_STA_CONNECT; else - de_digtable.cursta_connectctate = DIG_STA_DISCONNECT; + de_digtable->cursta_connectctate = DIG_STA_DISCONNECT; /* adjust initial gain according to false alarm counter */ if (falsealm_cnt->cnt_all < DM_DIG_FA_TH0) @@ -436,64 +443,64 @@ static void rtl92d_dm_dig(struct ieee80211_hw *hw) value_igi += 2; RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "dm_DIG() Before: large_fa_hit=%d, forbidden_igi=%x\n", - de_digtable.large_fa_hit, de_digtable.forbidden_igi); + de_digtable->large_fa_hit, de_digtable->forbidden_igi); RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "dm_DIG() Before: Recover_cnt=%d, rx_gain_range_min=%x\n", - de_digtable.recover_cnt, de_digtable.rx_gain_range_min); + de_digtable->recover_cnt, de_digtable->rx_gain_range_min); /* deal with abnorally large false alarm */ if (falsealm_cnt->cnt_all > 10000) { RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "dm_DIG(): Abnormally false alarm case\n"); - de_digtable.large_fa_hit++; - if (de_digtable.forbidden_igi < de_digtable.cur_igvalue) { - de_digtable.forbidden_igi = de_digtable.cur_igvalue; - de_digtable.large_fa_hit = 1; + de_digtable->large_fa_hit++; + if (de_digtable->forbidden_igi < de_digtable->cur_igvalue) { + de_digtable->forbidden_igi = de_digtable->cur_igvalue; + de_digtable->large_fa_hit = 1; } - if (de_digtable.large_fa_hit >= 3) { - if ((de_digtable.forbidden_igi + 1) > DM_DIG_MAX) - de_digtable.rx_gain_range_min = DM_DIG_MAX; + if (de_digtable->large_fa_hit >= 3) { + if ((de_digtable->forbidden_igi + 1) > DM_DIG_MAX) + de_digtable->rx_gain_range_min = DM_DIG_MAX; else - de_digtable.rx_gain_range_min = - (de_digtable.forbidden_igi + 1); - de_digtable.recover_cnt = 3600; /* 3600=2hr */ + de_digtable->rx_gain_range_min = + (de_digtable->forbidden_igi + 1); + de_digtable->recover_cnt = 3600; /* 3600=2hr */ } } else { /* Recovery mechanism for IGI lower bound */ - if (de_digtable.recover_cnt != 0) { - de_digtable.recover_cnt--; + if (de_digtable->recover_cnt != 0) { + de_digtable->recover_cnt--; } else { - if (de_digtable.large_fa_hit == 0) { - if ((de_digtable.forbidden_igi - 1) < + if (de_digtable->large_fa_hit == 0) { + if ((de_digtable->forbidden_igi - 1) < DM_DIG_FA_LOWER) { - de_digtable.forbidden_igi = + de_digtable->forbidden_igi = DM_DIG_FA_LOWER; - de_digtable.rx_gain_range_min = + de_digtable->rx_gain_range_min = DM_DIG_FA_LOWER; } else { - de_digtable.forbidden_igi--; - de_digtable.rx_gain_range_min = - (de_digtable.forbidden_igi + 1); + de_digtable->forbidden_igi--; + de_digtable->rx_gain_range_min = + (de_digtable->forbidden_igi + 1); } - } else if (de_digtable.large_fa_hit == 3) { - de_digtable.large_fa_hit = 0; + } else if (de_digtable->large_fa_hit == 3) { + de_digtable->large_fa_hit = 0; } } } RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "dm_DIG() After: large_fa_hit=%d, forbidden_igi=%x\n", - de_digtable.large_fa_hit, de_digtable.forbidden_igi); + de_digtable->large_fa_hit, de_digtable->forbidden_igi); RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "dm_DIG() After: recover_cnt=%d, rx_gain_range_min=%x\n", - de_digtable.recover_cnt, de_digtable.rx_gain_range_min); + de_digtable->recover_cnt, de_digtable->rx_gain_range_min); if (value_igi > DM_DIG_MAX) value_igi = DM_DIG_MAX; - else if (value_igi < de_digtable.rx_gain_range_min) - value_igi = de_digtable.rx_gain_range_min; - de_digtable.cur_igvalue = value_igi; + else if (value_igi < de_digtable->rx_gain_range_min) + value_igi = de_digtable->rx_gain_range_min; + de_digtable->cur_igvalue = value_igi; rtl92d_dm_write_dig(hw); if (rtlpriv->rtlhal.current_bandtype != BAND_ON_5G) rtl92d_dm_cck_packet_detection_thresh(hw); diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192de/dm.h b/trunk/drivers/net/wireless/rtlwifi/rtl8192de/dm.h index 91030ec8ac3e..3fea0c11c24a 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192de/dm.h +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192de/dm.h @@ -87,55 +87,6 @@ #define TX_POWER_NEAR_FIELD_THRESH_LVL1 67 #define INDEX_MAPPING_NUM 13 -struct ps_t { - u8 pre_ccastate; - u8 cur_ccasate; - - u8 pre_rfstate; - u8 cur_rfstate; - - long rssi_val_min; -}; - -struct dig_t { - u8 dig_enable_flag; - u8 dig_ext_port_stage; - - u32 rssi_lowthresh; - u32 rssi_highthresh; - - u32 fa_lowthresh; - u32 fa_highthresh; - - u8 cursta_connectctate; - u8 presta_connectstate; - u8 curmultista_connectstate; - - u8 pre_igvalue; - u8 cur_igvalue; - - char backoff_val; - char backoff_val_range_max; - char backoff_val_range_min; - u8 rx_gain_range_max; - u8 rx_gain_range_min; - u8 min_undecorated_pwdb_for_dm; - long last_min_undecorated_pwdb_for_dm; - - u8 pre_cck_pd_state; - u8 cur_cck_pd_state; - - u8 pre_cck_fa_state; - u8 cur_cck_fa_state; - - u8 pre_ccastate; - u8 cur_ccasate; - - u8 large_fa_hit; - u8 forbidden_igi; - u32 recover_cnt; -}; - struct swat { u8 failure_cnt; u8 try_flag; @@ -200,8 +151,6 @@ enum dm_dig_connect { DIG_CONNECT_MAX }; -extern struct dig_t de_digtable; - void rtl92d_dm_init(struct ieee80211_hw *hw); void rtl92d_dm_watchdog(struct ieee80211_hw *hw); void rtl92d_dm_init_edca_turbo(struct ieee80211_hw *hw); diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192de/hw.c b/trunk/drivers/net/wireless/rtlwifi/rtl8192de/hw.c index 509f5af38adf..b338d526c422 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192de/hw.c +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192de/hw.c @@ -1743,9 +1743,13 @@ static void _rtl92de_efuse_update_chip_version(struct ieee80211_hw *hw) chipver |= CHIP_92D_D_CUT; RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "D-CUT!!!\n"); break; + case 0xCC33: + chipver |= CHIP_92D_E_CUT; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "E-CUT!!!\n"); + break; default: chipver |= CHIP_92D_D_CUT; - RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, "Unkown CUT!\n"); + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, "Unknown CUT!\n"); break; } rtlpriv->rtlhal.version = chipver; diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192de/phy.c b/trunk/drivers/net/wireless/rtlwifi/rtl8192de/phy.c index 28fc5fb8057b..18380a7829f1 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192de/phy.c +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192de/phy.c @@ -3064,6 +3064,7 @@ u8 rtl92d_phy_sw_chnl(struct ieee80211_hw *hw) static void rtl92d_phy_set_io(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct dig_t *de_digtable = &rtlpriv->dm_digtable; struct rtl_phy *rtlphy = &(rtlpriv->phy); RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, @@ -3071,13 +3072,13 @@ static void rtl92d_phy_set_io(struct ieee80211_hw *hw) rtlphy->current_io_type, rtlphy->set_io_inprogress); switch (rtlphy->current_io_type) { case IO_CMD_RESUME_DM_BY_SCAN: - de_digtable.cur_igvalue = rtlphy->initgain_backup.xaagccore1; + de_digtable->cur_igvalue = rtlphy->initgain_backup.xaagccore1; rtl92d_dm_write_dig(hw); rtl92d_phy_set_txpower_level(hw, rtlphy->current_channel); break; case IO_CMD_PAUSE_DM_BY_SCAN: - rtlphy->initgain_backup.xaagccore1 = de_digtable.cur_igvalue; - de_digtable.cur_igvalue = 0x37; + rtlphy->initgain_backup.xaagccore1 = de_digtable->cur_igvalue; + de_digtable->cur_igvalue = 0x37; rtl92d_dm_write_dig(hw); break; default: diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192de/trx.c b/trunk/drivers/net/wireless/rtlwifi/rtl8192de/trx.c index a7f6126e2f86..1666ef7fd87b 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192de/trx.c +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192de/trx.c @@ -466,12 +466,13 @@ static void _rtl92de_translate_rx_signal_stuff(struct ieee80211_hw *hw, type = WLAN_FC_GET_TYPE(fc); praddr = hdr->addr1; packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) && - (!compare_ether_addr(mac->bssid, (cfc & IEEE80211_FCTL_TODS) ? - hdr->addr1 : (cfc & IEEE80211_FCTL_FROMDS) ? - hdr->addr2 : hdr->addr3)) && (!pstats->hwerror) && - (!pstats->crc) && (!pstats->icv)); + ether_addr_equal(mac->bssid, + (cfc & IEEE80211_FCTL_TODS) ? hdr->addr1 : + (cfc & IEEE80211_FCTL_FROMDS) ? hdr->addr2 : + hdr->addr3) && + (!pstats->hwerror) && (!pstats->crc) && (!pstats->icv)); packet_toself = packet_matchbssid && - (!compare_ether_addr(praddr, rtlefuse->dev_addr)); + ether_addr_equal(praddr, rtlefuse->dev_addr); if (ieee80211_is_beacon(fc)) packet_beacon = true; _rtl92de_query_rxphystatus(hw, pstats, pdesc, p_drvinfo, diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192de/trx.h b/trunk/drivers/net/wireless/rtlwifi/rtl8192de/trx.h index 0dc736c2723b..057a52431b00 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192de/trx.h +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192de/trx.h @@ -530,12 +530,8 @@ SET_BITS_OFFSET_LE(__pdesc+28, 0, 32, __val) #define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size) \ -do { \ - if (_size > TX_DESC_NEXT_DESC_OFFSET) \ - memset((void *)__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \ - else \ - memset((void *)__pdesc, 0, _size); \ -} while (0); + memset((void *)__pdesc, 0, \ + min_t(size_t, _size, TX_DESC_NEXT_DESC_OFFSET)) /* For 92D early mode */ #define SET_EARLYMODE_PKTNUM(__paddr, __value) \ diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192se/def.h b/trunk/drivers/net/wireless/rtlwifi/rtl8192se/def.h index d1b0a1e14971..20afec62ce05 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192se/def.h +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192se/def.h @@ -252,12 +252,7 @@ * the desc is cleared. */ #define TX_DESC_NEXT_DESC_OFFSET 36 #define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size) \ -do { \ - if (_size > TX_DESC_NEXT_DESC_OFFSET) \ - memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \ - else \ - memset(__pdesc, 0, _size); \ -} while (0); + memset(__pdesc, 0, min_t(size_t, _size, TX_DESC_NEXT_DESC_OFFSET)) /* Rx Desc */ #define RX_STATUS_DESC_SIZE 24 diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192se/dm.c b/trunk/drivers/net/wireless/rtlwifi/rtl8192se/dm.c index fbabae17259e..2e1158026fb7 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192se/dm.c +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192se/dm.c @@ -35,7 +35,6 @@ #include "dm.h" #include "fw.h" -struct dig_t digtable; static const u32 edca_setting_dl[PEER_MAX] = { 0xa44f, /* 0 UNKNOWN */ 0x5ea44f, /* 1 REALTEK_90 */ @@ -421,62 +420,64 @@ static void _rtl92s_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw) static void rtl92s_backoff_enable_flag(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct dig_t *digtable = &rtlpriv->dm_digtable; struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt); - if (falsealm_cnt->cnt_all > digtable.fa_highthresh) { - if ((digtable.backoff_val - 6) < - digtable.backoffval_range_min) - digtable.backoff_val = digtable.backoffval_range_min; + if (falsealm_cnt->cnt_all > digtable->fa_highthresh) { + if ((digtable->backoff_val - 6) < + digtable->backoffval_range_min) + digtable->backoff_val = digtable->backoffval_range_min; else - digtable.backoff_val -= 6; - } else if (falsealm_cnt->cnt_all < digtable.fa_lowthresh) { - if ((digtable.backoff_val + 6) > - digtable.backoffval_range_max) - digtable.backoff_val = - digtable.backoffval_range_max; + digtable->backoff_val -= 6; + } else if (falsealm_cnt->cnt_all < digtable->fa_lowthresh) { + if ((digtable->backoff_val + 6) > + digtable->backoffval_range_max) + digtable->backoff_val = + digtable->backoffval_range_max; else - digtable.backoff_val += 6; + digtable->backoff_val += 6; } } static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct dig_t *digtable = &rtlpriv->dm_digtable; struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt); static u8 initialized, force_write; u8 initial_gain = 0; - if ((digtable.pre_sta_connectstate == digtable.cur_sta_connectstate) || - (digtable.cur_sta_connectstate == DIG_STA_BEFORE_CONNECT)) { - if (digtable.cur_sta_connectstate == DIG_STA_BEFORE_CONNECT) { + if ((digtable->pre_sta_connectstate == digtable->cur_sta_connectstate) || + (digtable->cur_sta_connectstate == DIG_STA_BEFORE_CONNECT)) { + if (digtable->cur_sta_connectstate == DIG_STA_BEFORE_CONNECT) { if (rtlpriv->psc.rfpwr_state != ERFON) return; - if (digtable.backoff_enable_flag) + if (digtable->backoff_enable_flag) rtl92s_backoff_enable_flag(hw); else - digtable.backoff_val = DM_DIG_BACKOFF; - - if ((digtable.rssi_val + 10 - digtable.backoff_val) > - digtable.rx_gain_range_max) - digtable.cur_igvalue = - digtable.rx_gain_range_max; - else if ((digtable.rssi_val + 10 - digtable.backoff_val) - < digtable.rx_gain_range_min) - digtable.cur_igvalue = - digtable.rx_gain_range_min; + digtable->backoff_val = DM_DIG_BACKOFF; + + if ((digtable->rssi_val + 10 - digtable->backoff_val) > + digtable->rx_gain_range_max) + digtable->cur_igvalue = + digtable->rx_gain_range_max; + else if ((digtable->rssi_val + 10 - digtable->backoff_val) + < digtable->rx_gain_range_min) + digtable->cur_igvalue = + digtable->rx_gain_range_min; else - digtable.cur_igvalue = digtable.rssi_val + 10 - - digtable.backoff_val; + digtable->cur_igvalue = digtable->rssi_val + 10 - + digtable->backoff_val; if (falsealm_cnt->cnt_all > 10000) - digtable.cur_igvalue = - (digtable.cur_igvalue > 0x33) ? - digtable.cur_igvalue : 0x33; + digtable->cur_igvalue = + (digtable->cur_igvalue > 0x33) ? + digtable->cur_igvalue : 0x33; if (falsealm_cnt->cnt_all > 16000) - digtable.cur_igvalue = - digtable.rx_gain_range_max; + digtable->cur_igvalue = + digtable->rx_gain_range_max; /* connected -> connected or disconnected -> disconnected */ } else { /* Firmware control DIG, do nothing in driver dm */ @@ -486,31 +487,31 @@ static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw) * disconnected or beforeconnect->(dis)connected */ } else { /* Enable FW DIG */ - digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; + digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_ENABLE); - digtable.backoff_val = DM_DIG_BACKOFF; - digtable.cur_igvalue = rtlpriv->phy.default_initialgain[0]; - digtable.pre_igvalue = 0; + digtable->backoff_val = DM_DIG_BACKOFF; + digtable->cur_igvalue = rtlpriv->phy.default_initialgain[0]; + digtable->pre_igvalue = 0; return; } /* Forced writing to prevent from fw-dig overwriting. */ - if (digtable.pre_igvalue != rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, + if (digtable->pre_igvalue != rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0)) force_write = 1; - if ((digtable.pre_igvalue != digtable.cur_igvalue) || + if ((digtable->pre_igvalue != digtable->cur_igvalue) || !initialized || force_write) { /* Disable FW DIG */ rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_DISABLE); - initial_gain = (u8)digtable.cur_igvalue; + initial_gain = (u8)digtable->cur_igvalue; /* Set initial gain. */ rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0, initial_gain); rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0, initial_gain); - digtable.pre_igvalue = digtable.cur_igvalue; + digtable->pre_igvalue = digtable->cur_igvalue; initialized = 1; force_write = 0; } @@ -519,6 +520,7 @@ static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw) static void _rtl92s_dm_ctrl_initgain_bytwoport(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct dig_t *digtable = &rtlpriv->dm_digtable; if (rtlpriv->mac80211.act_scanning) return; @@ -526,17 +528,17 @@ static void _rtl92s_dm_ctrl_initgain_bytwoport(struct ieee80211_hw *hw) /* Decide the current status and if modify initial gain or not */ if (rtlpriv->mac80211.link_state >= MAC80211_LINKED || rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC) - digtable.cur_sta_connectstate = DIG_STA_CONNECT; + digtable->cur_sta_connectstate = DIG_STA_CONNECT; else - digtable.cur_sta_connectstate = DIG_STA_DISCONNECT; + digtable->cur_sta_connectstate = DIG_STA_DISCONNECT; - digtable.rssi_val = rtlpriv->dm.undecorated_smoothed_pwdb; + digtable->rssi_val = rtlpriv->dm.undecorated_smoothed_pwdb; /* Change dig mode to rssi */ - if (digtable.cur_sta_connectstate != DIG_STA_DISCONNECT) { - if (digtable.dig_twoport_algorithm == + if (digtable->cur_sta_connectstate != DIG_STA_DISCONNECT) { + if (digtable->dig_twoport_algorithm == DIG_TWO_PORT_ALGO_FALSE_ALARM) { - digtable.dig_twoport_algorithm = DIG_TWO_PORT_ALGO_RSSI; + digtable->dig_twoport_algorithm = DIG_TWO_PORT_ALGO_RSSI; rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_MODE_SS); } } @@ -544,13 +546,14 @@ static void _rtl92s_dm_ctrl_initgain_bytwoport(struct ieee80211_hw *hw) _rtl92s_dm_false_alarm_counter_statistics(hw); _rtl92s_dm_initial_gain_sta_beforeconnect(hw); - digtable.pre_sta_connectstate = digtable.cur_sta_connectstate; + digtable->pre_sta_connectstate = digtable->cur_sta_connectstate; } static void _rtl92s_dm_ctrl_initgain_byrssi(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct dig_t *digtable = &rtlpriv->dm_digtable; /* 2T2R TP issue */ if (rtlphy->rf_type == RF_2T2R) @@ -559,7 +562,7 @@ static void _rtl92s_dm_ctrl_initgain_byrssi(struct ieee80211_hw *hw) if (!rtlpriv->dm.dm_initialgain_enable) return; - if (digtable.dig_enable_flag == false) + if (digtable->dig_enable_flag == false) return; _rtl92s_dm_ctrl_initgain_bytwoport(hw); @@ -639,51 +642,52 @@ static void _rtl92s_dm_dynamic_txpower(struct ieee80211_hw *hw) static void _rtl92s_dm_init_dig(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct dig_t *digtable = &rtlpriv->dm_digtable; /* Disable DIG scheme now.*/ - digtable.dig_enable_flag = true; - digtable.backoff_enable_flag = true; + digtable->dig_enable_flag = true; + digtable->backoff_enable_flag = true; if ((rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER) && (hal_get_firmwareversion(rtlpriv) >= 0x3c)) - digtable.dig_algorithm = DIG_ALGO_BY_TOW_PORT; + digtable->dig_algorithm = DIG_ALGO_BY_TOW_PORT; else - digtable.dig_algorithm = + digtable->dig_algorithm = DIG_ALGO_BEFORE_CONNECT_BY_RSSI_AND_ALARM; - digtable.dig_twoport_algorithm = DIG_TWO_PORT_ALGO_RSSI; - digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; - /* off=by real rssi value, on=by digtable.rssi_val for new dig */ - digtable.dig_dbgmode = DM_DBG_OFF; - digtable.dig_slgorithm_switch = 0; + digtable->dig_twoport_algorithm = DIG_TWO_PORT_ALGO_RSSI; + digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; + /* off=by real rssi value, on=by digtable->rssi_val for new dig */ + digtable->dig_dbgmode = DM_DBG_OFF; + digtable->dig_slgorithm_switch = 0; /* 2007/10/04 MH Define init gain threshol. */ - digtable.dig_state = DM_STA_DIG_MAX; - digtable.dig_highpwrstate = DM_STA_DIG_MAX; + digtable->dig_state = DM_STA_DIG_MAX; + digtable->dig_highpwrstate = DM_STA_DIG_MAX; - digtable.cur_sta_connectstate = DIG_STA_DISCONNECT; - digtable.pre_sta_connectstate = DIG_STA_DISCONNECT; - digtable.cur_ap_connectstate = DIG_AP_DISCONNECT; - digtable.pre_ap_connectstate = DIG_AP_DISCONNECT; + digtable->cur_sta_connectstate = DIG_STA_DISCONNECT; + digtable->pre_sta_connectstate = DIG_STA_DISCONNECT; + digtable->cur_ap_connectstate = DIG_AP_DISCONNECT; + digtable->pre_ap_connectstate = DIG_AP_DISCONNECT; - digtable.rssi_lowthresh = DM_DIG_THRESH_LOW; - digtable.rssi_highthresh = DM_DIG_THRESH_HIGH; + digtable->rssi_lowthresh = DM_DIG_THRESH_LOW; + digtable->rssi_highthresh = DM_DIG_THRESH_HIGH; - digtable.fa_lowthresh = DM_FALSEALARM_THRESH_LOW; - digtable.fa_highthresh = DM_FALSEALARM_THRESH_HIGH; + digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW; + digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH; - digtable.rssi_highpower_lowthresh = DM_DIG_HIGH_PWR_THRESH_LOW; - digtable.rssi_highpower_highthresh = DM_DIG_HIGH_PWR_THRESH_HIGH; + digtable->rssi_highpower_lowthresh = DM_DIG_HIGH_PWR_THRESH_LOW; + digtable->rssi_highpower_highthresh = DM_DIG_HIGH_PWR_THRESH_HIGH; /* for dig debug rssi value */ - digtable.rssi_val = 50; - digtable.backoff_val = DM_DIG_BACKOFF; - digtable.rx_gain_range_max = DM_DIG_MAX; + digtable->rssi_val = 50; + digtable->backoff_val = DM_DIG_BACKOFF; + digtable->rx_gain_range_max = DM_DIG_MAX; - digtable.rx_gain_range_min = DM_DIG_MIN; + digtable->rx_gain_range_min = DM_DIG_MIN; - digtable.backoffval_range_max = DM_DIG_BACKOFF_MAX; - digtable.backoffval_range_min = DM_DIG_BACKOFF_MIN; + digtable->backoffval_range_max = DM_DIG_BACKOFF_MAX; + digtable->backoffval_range_min = DM_DIG_BACKOFF_MIN; } static void _rtl92s_dm_init_dynamic_txpower(struct ieee80211_hw *hw) diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192se/dm.h b/trunk/drivers/net/wireless/rtlwifi/rtl8192se/dm.h index e1b19a641765..2e9052c8fe4b 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192se/dm.h +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192se/dm.h @@ -29,48 +29,6 @@ #ifndef __RTL_92S_DM_H__ #define __RTL_92S_DM_H__ -struct dig_t { - u8 dig_enable_flag; - u8 dig_algorithm; - u8 dig_twoport_algorithm; - u8 dig_ext_port_stage; - u8 dig_dbgmode; - u8 dig_slgorithm_switch; - - long rssi_lowthresh; - long rssi_highthresh; - - u32 fa_lowthresh; - u32 fa_highthresh; - - long rssi_highpower_lowthresh; - long rssi_highpower_highthresh; - - u8 dig_state; - u8 dig_highpwrstate; - u8 cur_sta_connectstate; - u8 pre_sta_connectstate; - u8 cur_ap_connectstate; - u8 pre_ap_connectstate; - - u8 cur_pd_thstate; - u8 pre_pd_thstate; - u8 cur_cs_ratiostate; - u8 pre_cs_ratiostate; - - u32 pre_igvalue; - u32 cur_igvalue; - - u8 backoff_enable_flag; - char backoff_val; - char backoffval_range_max; - char backoffval_range_min; - u8 rx_gain_range_max; - u8 rx_gain_range_min; - - long rssi_val; -}; - enum dm_dig_alg { DIG_ALGO_BY_FALSE_ALARM = 0, DIG_ALGO_BY_RSSI = 1, @@ -154,8 +112,6 @@ enum dm_ratr_sta { #define DM_DIG_BACKOFF_MAX 12 #define DM_DIG_BACKOFF_MIN -4 -extern struct dig_t digtable; - void rtl92s_dm_watchdog(struct ieee80211_hw *hw); void rtl92s_dm_init(struct ieee80211_hw *hw); void rtl92s_dm_init_edca_turbo(struct ieee80211_hw *hw); diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192se/fw.h b/trunk/drivers/net/wireless/rtlwifi/rtl8192se/fw.h index b4afff626437..d53f4332464d 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192se/fw.h +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192se/fw.h @@ -345,7 +345,7 @@ enum fw_h2c_cmd { do { \ udelay(1000); \ rtlpriv->rtlhal.fwcmd_iomap &= (~_Bit); \ - } while (0); + } while (0) #define FW_CMD_IO_UPDATE(rtlpriv, _val) \ rtlpriv->rtlhal.fwcmd_iomap = _val; @@ -354,13 +354,13 @@ enum fw_h2c_cmd { do { \ rtl_write_word(rtlpriv, LBUS_MON_ADDR, (u16)_val); \ FW_CMD_IO_UPDATE(rtlpriv, _val); \ - } while (0); + } while (0) #define FW_CMD_PARA_SET(rtlpriv, _val) \ do { \ rtl_write_dword(rtlpriv, LBUS_ADDR_MASK, _val); \ rtlpriv->rtlhal.fwcmd_ioparam = _val; \ - } while (0); + } while (0) #define FW_CMD_IO_QUERY(rtlpriv) \ (u16)(rtlpriv->rtlhal.fwcmd_iomap) diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192se/phy.c b/trunk/drivers/net/wireless/rtlwifi/rtl8192se/phy.c index 4a499928e4c6..8d7099bc472c 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192se/phy.c +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192se/phy.c @@ -1450,6 +1450,7 @@ static void _rtl92s_phy_set_fwcmd_io(struct ieee80211_hw *hw) bool rtl92s_phy_set_fw_cmd(struct ieee80211_hw *hw, enum fwcmd_iotype fw_cmdio) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct dig_t *digtable = &rtlpriv->dm_digtable; struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); u32 fw_param = FW_CMD_IO_PARA_QUERY(rtlpriv); @@ -1588,16 +1589,16 @@ bool rtl92s_phy_set_fw_cmd(struct ieee80211_hw *hw, enum fwcmd_iotype fw_cmdio) FW_SS_CTL); if (rtlpriv->dm.dm_flag & HAL_DM_DIG_DISABLE || - !digtable.dig_enable_flag) + !digtable->dig_enable_flag) fw_cmdmap &= ~FW_DIG_ENABLE_CTL; if ((rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) || rtlpriv->dm.dynamic_txpower_enable) fw_cmdmap &= ~FW_HIGH_PWR_ENABLE_CTL; - if ((digtable.dig_ext_port_stage == + if ((digtable->dig_ext_port_stage == DIG_EXT_PORT_STAGE_0) || - (digtable.dig_ext_port_stage == + (digtable->dig_ext_port_stage == DIG_EXT_PORT_STAGE_1)) fw_cmdmap &= ~FW_DIG_ENABLE_CTL; diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192se/sw.c b/trunk/drivers/net/wireless/rtlwifi/rtl8192se/sw.c index f1b36005c6a2..730bcc919529 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192se/sw.c +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192se/sw.c @@ -450,21 +450,4 @@ static struct pci_driver rtl92se_driver = { .driver.pm = &rtlwifi_pm_ops, }; -static int __init rtl92se_module_init(void) -{ - int ret = 0; - - ret = pci_register_driver(&rtl92se_driver); - if (ret) - RT_ASSERT(false, "No device found\n"); - - return ret; -} - -static void __exit rtl92se_module_exit(void) -{ - pci_unregister_driver(&rtl92se_driver); -} - -module_init(rtl92se_module_init); -module_exit(rtl92se_module_exit); +module_pci_driver(rtl92se_driver); diff --git a/trunk/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/trunk/drivers/net/wireless/rtlwifi/rtl8192se/trx.c index 2fd3d13b7ced..812b5858f14a 100644 --- a/trunk/drivers/net/wireless/rtlwifi/rtl8192se/trx.c +++ b/trunk/drivers/net/wireless/rtlwifi/rtl8192se/trx.c @@ -492,13 +492,14 @@ static void _rtl92se_translate_rx_signal_stuff(struct ieee80211_hw *hw, praddr = hdr->addr1; packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) && - (!compare_ether_addr(mac->bssid, (cfc & IEEE80211_FCTL_TODS) ? - hdr->addr1 : (cfc & IEEE80211_FCTL_FROMDS) ? - hdr->addr2 : hdr->addr3)) && (!pstats->hwerror) && - (!pstats->crc) && (!pstats->icv)); + ether_addr_equal(mac->bssid, + (cfc & IEEE80211_FCTL_TODS) ? hdr->addr1 : + (cfc & IEEE80211_FCTL_FROMDS) ? hdr->addr2 : + hdr->addr3) && + (!pstats->hwerror) && (!pstats->crc) && (!pstats->icv)); packet_toself = packet_matchbssid && - (!compare_ether_addr(praddr, rtlefuse->dev_addr)); + ether_addr_equal(praddr, rtlefuse->dev_addr); if (ieee80211_is_beacon(fc)) packet_beacon = true; diff --git a/trunk/drivers/net/wireless/rtlwifi/wifi.h b/trunk/drivers/net/wireless/rtlwifi/wifi.h index 28ebc69218a3..bd816aef26dc 100644 --- a/trunk/drivers/net/wireless/rtlwifi/wifi.h +++ b/trunk/drivers/net/wireless/rtlwifi/wifi.h @@ -1592,6 +1592,65 @@ struct rtl_debug { char proc_name[20]; }; +struct ps_t { + u8 pre_ccastate; + u8 cur_ccasate; + u8 pre_rfstate; + u8 cur_rfstate; + long rssi_val_min; +}; + +struct dig_t { + u32 rssi_lowthresh; + u32 rssi_highthresh; + u32 fa_lowthresh; + u32 fa_highthresh; + long last_min_undecorated_pwdb_for_dm; + long rssi_highpower_lowthresh; + long rssi_highpower_highthresh; + u32 recover_cnt; + u32 pre_igvalue; + u32 cur_igvalue; + long rssi_val; + u8 dig_enable_flag; + u8 dig_ext_port_stage; + u8 dig_algorithm; + u8 dig_twoport_algorithm; + u8 dig_dbgmode; + u8 dig_slgorithm_switch; + u8 cursta_connectctate; + u8 presta_connectstate; + u8 curmultista_connectstate; + char backoff_val; + char backoff_val_range_max; + char backoff_val_range_min; + u8 rx_gain_range_max; + u8 rx_gain_range_min; + u8 min_undecorated_pwdb_for_dm; + u8 rssi_val_min; + u8 pre_cck_pd_state; + u8 cur_cck_pd_state; + u8 pre_cck_fa_state; + u8 cur_cck_fa_state; + u8 pre_ccastate; + u8 cur_ccasate; + u8 large_fa_hit; + u8 forbidden_igi; + u8 dig_state; + u8 dig_highpwrstate; + u8 cur_sta_connectstate; + u8 pre_sta_connectstate; + u8 cur_ap_connectstate; + u8 pre_ap_connectstate; + u8 cur_pd_thstate; + u8 pre_pd_thstate; + u8 cur_cs_ratiostate; + u8 pre_cs_ratiostate; + u8 backoff_enable_flag; + char backoffval_range_max; + char backoffval_range_min; +}; + struct rtl_priv { struct completion firmware_loading_complete; struct rtl_locks locks; @@ -1629,6 +1688,10 @@ struct rtl_priv { interface or hardware */ unsigned long status; + /* tables for dm */ + struct dig_t dm_digtable; + struct ps_t dm_pstable; + /* data buffer pointer for USB reads */ __le32 *usb_data; int usb_data_index; @@ -1958,37 +2021,35 @@ static inline void rtl_write_dword(struct rtl_priv *rtlpriv, static inline u32 rtl_get_bbreg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask) { - return ((struct rtl_priv *)(hw)->priv)->cfg->ops->get_bbreg(hw, - regaddr, - bitmask); + struct rtl_priv *rtlpriv = hw->priv; + + return rtlpriv->cfg->ops->get_bbreg(hw, regaddr, bitmask); } static inline void rtl_set_bbreg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask, u32 data) { - ((struct rtl_priv *)(hw)->priv)->cfg->ops->set_bbreg(hw, - regaddr, bitmask, - data); + struct rtl_priv *rtlpriv = hw->priv; + rtlpriv->cfg->ops->set_bbreg(hw, regaddr, bitmask, data); } static inline u32 rtl_get_rfreg(struct ieee80211_hw *hw, enum radio_path rfpath, u32 regaddr, u32 bitmask) { - return ((struct rtl_priv *)(hw)->priv)->cfg->ops->get_rfreg(hw, - rfpath, - regaddr, - bitmask); + struct rtl_priv *rtlpriv = hw->priv; + + return rtlpriv->cfg->ops->get_rfreg(hw, rfpath, regaddr, bitmask); } static inline void rtl_set_rfreg(struct ieee80211_hw *hw, enum radio_path rfpath, u32 regaddr, u32 bitmask, u32 data) { - ((struct rtl_priv *)(hw)->priv)->cfg->ops->set_rfreg(hw, - rfpath, regaddr, - bitmask, data); + struct rtl_priv *rtlpriv = hw->priv; + + rtlpriv->cfg->ops->set_rfreg(hw, rfpath, regaddr, bitmask, data); } static inline bool is_hal_stop(struct rtl_hal *rtlhal) diff --git a/trunk/drivers/net/wireless/ti/Kconfig b/trunk/drivers/net/wireless/ti/Kconfig new file mode 100644 index 000000000000..1a72932e2213 --- /dev/null +++ b/trunk/drivers/net/wireless/ti/Kconfig @@ -0,0 +1,14 @@ +menuconfig WL_TI + bool "TI Wireless LAN support" + ---help--- + This section contains support for all the wireless drivers + for Texas Instruments WLAN chips, such as wl1251 and the wl12xx + family. + +if WL_TI +source "drivers/net/wireless/ti/wl1251/Kconfig" +source "drivers/net/wireless/ti/wl12xx/Kconfig" + +# keep last for automatic dependencies +source "drivers/net/wireless/ti/wlcore/Kconfig" +endif # WL_TI diff --git a/trunk/drivers/net/wireless/ti/Makefile b/trunk/drivers/net/wireless/ti/Makefile new file mode 100644 index 000000000000..0a565622d4a4 --- /dev/null +++ b/trunk/drivers/net/wireless/ti/Makefile @@ -0,0 +1,4 @@ +obj-$(CONFIG_WLCORE) += wlcore/ +obj-$(CONFIG_WL12XX) += wl12xx/ +obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wlcore/ +obj-$(CONFIG_WL1251) += wl1251/ diff --git a/trunk/drivers/net/wireless/wl1251/Kconfig b/trunk/drivers/net/wireless/ti/wl1251/Kconfig similarity index 100% rename from trunk/drivers/net/wireless/wl1251/Kconfig rename to trunk/drivers/net/wireless/ti/wl1251/Kconfig diff --git a/trunk/drivers/net/wireless/wl1251/Makefile b/trunk/drivers/net/wireless/ti/wl1251/Makefile similarity index 100% rename from trunk/drivers/net/wireless/wl1251/Makefile rename to trunk/drivers/net/wireless/ti/wl1251/Makefile diff --git a/trunk/drivers/net/wireless/wl1251/acx.c b/trunk/drivers/net/wireless/ti/wl1251/acx.c similarity index 100% rename from trunk/drivers/net/wireless/wl1251/acx.c rename to trunk/drivers/net/wireless/ti/wl1251/acx.c diff --git a/trunk/drivers/net/wireless/wl1251/acx.h b/trunk/drivers/net/wireless/ti/wl1251/acx.h similarity index 100% rename from trunk/drivers/net/wireless/wl1251/acx.h rename to trunk/drivers/net/wireless/ti/wl1251/acx.h diff --git a/trunk/drivers/net/wireless/wl1251/boot.c b/trunk/drivers/net/wireless/ti/wl1251/boot.c similarity index 100% rename from trunk/drivers/net/wireless/wl1251/boot.c rename to trunk/drivers/net/wireless/ti/wl1251/boot.c diff --git a/trunk/drivers/net/wireless/wl1251/boot.h b/trunk/drivers/net/wireless/ti/wl1251/boot.h similarity index 100% rename from trunk/drivers/net/wireless/wl1251/boot.h rename to trunk/drivers/net/wireless/ti/wl1251/boot.h diff --git a/trunk/drivers/net/wireless/wl1251/cmd.c b/trunk/drivers/net/wireless/ti/wl1251/cmd.c similarity index 100% rename from trunk/drivers/net/wireless/wl1251/cmd.c rename to trunk/drivers/net/wireless/ti/wl1251/cmd.c diff --git a/trunk/drivers/net/wireless/wl1251/cmd.h b/trunk/drivers/net/wireless/ti/wl1251/cmd.h similarity index 100% rename from trunk/drivers/net/wireless/wl1251/cmd.h rename to trunk/drivers/net/wireless/ti/wl1251/cmd.h diff --git a/trunk/drivers/net/wireless/wl1251/debugfs.c b/trunk/drivers/net/wireless/ti/wl1251/debugfs.c similarity index 100% rename from trunk/drivers/net/wireless/wl1251/debugfs.c rename to trunk/drivers/net/wireless/ti/wl1251/debugfs.c diff --git a/trunk/drivers/net/wireless/wl1251/debugfs.h b/trunk/drivers/net/wireless/ti/wl1251/debugfs.h similarity index 100% rename from trunk/drivers/net/wireless/wl1251/debugfs.h rename to trunk/drivers/net/wireless/ti/wl1251/debugfs.h diff --git a/trunk/drivers/net/wireless/wl1251/event.c b/trunk/drivers/net/wireless/ti/wl1251/event.c similarity index 100% rename from trunk/drivers/net/wireless/wl1251/event.c rename to trunk/drivers/net/wireless/ti/wl1251/event.c diff --git a/trunk/drivers/net/wireless/wl1251/event.h b/trunk/drivers/net/wireless/ti/wl1251/event.h similarity index 100% rename from trunk/drivers/net/wireless/wl1251/event.h rename to trunk/drivers/net/wireless/ti/wl1251/event.h diff --git a/trunk/drivers/net/wireless/wl1251/init.c b/trunk/drivers/net/wireless/ti/wl1251/init.c similarity index 100% rename from trunk/drivers/net/wireless/wl1251/init.c rename to trunk/drivers/net/wireless/ti/wl1251/init.c diff --git a/trunk/drivers/net/wireless/wl1251/init.h b/trunk/drivers/net/wireless/ti/wl1251/init.h similarity index 100% rename from trunk/drivers/net/wireless/wl1251/init.h rename to trunk/drivers/net/wireless/ti/wl1251/init.h diff --git a/trunk/drivers/net/wireless/wl1251/io.c b/trunk/drivers/net/wireless/ti/wl1251/io.c similarity index 100% rename from trunk/drivers/net/wireless/wl1251/io.c rename to trunk/drivers/net/wireless/ti/wl1251/io.c diff --git a/trunk/drivers/net/wireless/wl1251/io.h b/trunk/drivers/net/wireless/ti/wl1251/io.h similarity index 100% rename from trunk/drivers/net/wireless/wl1251/io.h rename to trunk/drivers/net/wireless/ti/wl1251/io.h diff --git a/trunk/drivers/net/wireless/wl1251/main.c b/trunk/drivers/net/wireless/ti/wl1251/main.c similarity index 100% rename from trunk/drivers/net/wireless/wl1251/main.c rename to trunk/drivers/net/wireless/ti/wl1251/main.c diff --git a/trunk/drivers/net/wireless/wl1251/ps.c b/trunk/drivers/net/wireless/ti/wl1251/ps.c similarity index 100% rename from trunk/drivers/net/wireless/wl1251/ps.c rename to trunk/drivers/net/wireless/ti/wl1251/ps.c diff --git a/trunk/drivers/net/wireless/wl1251/ps.h b/trunk/drivers/net/wireless/ti/wl1251/ps.h similarity index 100% rename from trunk/drivers/net/wireless/wl1251/ps.h rename to trunk/drivers/net/wireless/ti/wl1251/ps.h diff --git a/trunk/drivers/net/wireless/wl1251/reg.h b/trunk/drivers/net/wireless/ti/wl1251/reg.h similarity index 100% rename from trunk/drivers/net/wireless/wl1251/reg.h rename to trunk/drivers/net/wireless/ti/wl1251/reg.h diff --git a/trunk/drivers/net/wireless/wl1251/rx.c b/trunk/drivers/net/wireless/ti/wl1251/rx.c similarity index 100% rename from trunk/drivers/net/wireless/wl1251/rx.c rename to trunk/drivers/net/wireless/ti/wl1251/rx.c diff --git a/trunk/drivers/net/wireless/wl1251/rx.h b/trunk/drivers/net/wireless/ti/wl1251/rx.h similarity index 100% rename from trunk/drivers/net/wireless/wl1251/rx.h rename to trunk/drivers/net/wireless/ti/wl1251/rx.h diff --git a/trunk/drivers/net/wireless/wl1251/sdio.c b/trunk/drivers/net/wireless/ti/wl1251/sdio.c similarity index 100% rename from trunk/drivers/net/wireless/wl1251/sdio.c rename to trunk/drivers/net/wireless/ti/wl1251/sdio.c diff --git a/trunk/drivers/net/wireless/wl1251/spi.c b/trunk/drivers/net/wireless/ti/wl1251/spi.c similarity index 100% rename from trunk/drivers/net/wireless/wl1251/spi.c rename to trunk/drivers/net/wireless/ti/wl1251/spi.c diff --git a/trunk/drivers/net/wireless/wl1251/spi.h b/trunk/drivers/net/wireless/ti/wl1251/spi.h similarity index 100% rename from trunk/drivers/net/wireless/wl1251/spi.h rename to trunk/drivers/net/wireless/ti/wl1251/spi.h diff --git a/trunk/drivers/net/wireless/wl1251/tx.c b/trunk/drivers/net/wireless/ti/wl1251/tx.c similarity index 100% rename from trunk/drivers/net/wireless/wl1251/tx.c rename to trunk/drivers/net/wireless/ti/wl1251/tx.c diff --git a/trunk/drivers/net/wireless/wl1251/tx.h b/trunk/drivers/net/wireless/ti/wl1251/tx.h similarity index 100% rename from trunk/drivers/net/wireless/wl1251/tx.h rename to trunk/drivers/net/wireless/ti/wl1251/tx.h diff --git a/trunk/drivers/net/wireless/wl1251/wl1251.h b/trunk/drivers/net/wireless/ti/wl1251/wl1251.h similarity index 100% rename from trunk/drivers/net/wireless/wl1251/wl1251.h rename to trunk/drivers/net/wireless/ti/wl1251/wl1251.h diff --git a/trunk/drivers/net/wireless/wl1251/wl12xx_80211.h b/trunk/drivers/net/wireless/ti/wl1251/wl12xx_80211.h similarity index 100% rename from trunk/drivers/net/wireless/wl1251/wl12xx_80211.h rename to trunk/drivers/net/wireless/ti/wl1251/wl12xx_80211.h diff --git a/trunk/drivers/net/wireless/ti/wl12xx/Kconfig b/trunk/drivers/net/wireless/ti/wl12xx/Kconfig new file mode 100644 index 000000000000..5b92329122c4 --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wl12xx/Kconfig @@ -0,0 +1,8 @@ +config WL12XX + tristate "TI wl12xx support" + select WLCORE + ---help--- + This module adds support for wireless adapters based on TI wl1271, + wl1273, wl1281 and wl1283 chipsets. This module does *not* include + support for wl1251. For wl1251 support, use the separate homonymous + driver instead. diff --git a/trunk/drivers/net/wireless/ti/wl12xx/Makefile b/trunk/drivers/net/wireless/ti/wl12xx/Makefile new file mode 100644 index 000000000000..87f64b14db35 --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wl12xx/Makefile @@ -0,0 +1,3 @@ +wl12xx-objs = main.o cmd.o acx.o + +obj-$(CONFIG_WL12XX) += wl12xx.o diff --git a/trunk/drivers/net/wireless/ti/wl12xx/acx.c b/trunk/drivers/net/wireless/ti/wl12xx/acx.c new file mode 100644 index 000000000000..bea06b2d7bf4 --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wl12xx/acx.c @@ -0,0 +1,53 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2008-2009 Nokia Corporation + * Copyright (C) 2011 Texas Instruments 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. + * + * 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 "../wlcore/cmd.h" +#include "../wlcore/debug.h" +#include "../wlcore/acx.h" + +#include "acx.h" + +int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap) +{ + struct wl1271_acx_host_config_bitmap *bitmap_conf; + int ret; + + bitmap_conf = kzalloc(sizeof(*bitmap_conf), GFP_KERNEL); + if (!bitmap_conf) { + ret = -ENOMEM; + goto out; + } + + bitmap_conf->host_cfg_bitmap = cpu_to_le32(host_cfg_bitmap); + + ret = wl1271_cmd_configure(wl, ACX_HOST_IF_CFG_BITMAP, + bitmap_conf, sizeof(*bitmap_conf)); + if (ret < 0) { + wl1271_warning("wl1271 bitmap config opt failed: %d", ret); + goto out; + } + +out: + kfree(bitmap_conf); + + return ret; +} diff --git a/trunk/drivers/net/wireless/ti/wl12xx/acx.h b/trunk/drivers/net/wireless/ti/wl12xx/acx.h new file mode 100644 index 000000000000..d1f5aba0afce --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wl12xx/acx.h @@ -0,0 +1,36 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 1998-2009, 2011 Texas Instruments. All rights reserved. + * Copyright (C) 2008-2010 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_ACX_H__ +#define __WL12XX_ACX_H__ + +#include "../wlcore/wlcore.h" + +struct wl1271_acx_host_config_bitmap { + struct acx_header header; + + __le32 host_cfg_bitmap; +} __packed; + +int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap); + +#endif /* __WL12XX_ACX_H__ */ diff --git a/trunk/drivers/net/wireless/ti/wl12xx/cmd.c b/trunk/drivers/net/wireless/ti/wl12xx/cmd.c new file mode 100644 index 000000000000..8ffaeb5f2147 --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wl12xx/cmd.c @@ -0,0 +1,254 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2009-2010 Nokia Corporation + * Copyright (C) 2011 Texas Instruments 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. + * + * 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 "../wlcore/cmd.h" +#include "../wlcore/debug.h" + +#include "wl12xx.h" +#include "cmd.h" + +int wl1271_cmd_ext_radio_parms(struct wl1271 *wl) +{ + struct wl1271_ext_radio_parms_cmd *ext_radio_parms; + struct wl12xx_priv *priv = wl->priv; + struct wl12xx_conf_rf *rf = &priv->conf.rf; + int ret; + + if (!wl->nvs) + return -ENODEV; + + ext_radio_parms = kzalloc(sizeof(*ext_radio_parms), GFP_KERNEL); + if (!ext_radio_parms) + return -ENOMEM; + + ext_radio_parms->test.id = TEST_CMD_INI_FILE_RF_EXTENDED_PARAM; + + memcpy(ext_radio_parms->tx_per_channel_power_compensation_2, + rf->tx_per_channel_power_compensation_2, + CONF_TX_PWR_COMPENSATION_LEN_2); + memcpy(ext_radio_parms->tx_per_channel_power_compensation_5, + rf->tx_per_channel_power_compensation_5, + CONF_TX_PWR_COMPENSATION_LEN_5); + + wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_EXT_RADIO_PARAM: ", + ext_radio_parms, sizeof(*ext_radio_parms)); + + ret = wl1271_cmd_test(wl, ext_radio_parms, sizeof(*ext_radio_parms), 0); + if (ret < 0) + wl1271_warning("TEST_CMD_INI_FILE_RF_EXTENDED_PARAM failed"); + + kfree(ext_radio_parms); + return ret; +} + +int wl1271_cmd_general_parms(struct wl1271 *wl) +{ + struct wl1271_general_parms_cmd *gen_parms; + struct wl1271_ini_general_params *gp = + &((struct wl1271_nvs_file *)wl->nvs)->general_params; + bool answer = false; + int ret; + + if (!wl->nvs) + return -ENODEV; + + if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { + wl1271_warning("FEM index from INI out of bounds"); + return -EINVAL; + } + + gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); + if (!gen_parms) + return -ENOMEM; + + gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; + + memcpy(&gen_parms->general_params, gp, sizeof(*gp)); + + if (gp->tx_bip_fem_auto_detect) + answer = true; + + /* Override the REF CLK from the NVS with the one from platform data */ + gen_parms->general_params.ref_clock = wl->ref_clock; + + ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); + if (ret < 0) { + wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); + goto out; + } + + gp->tx_bip_fem_manufacturer = + gen_parms->general_params.tx_bip_fem_manufacturer; + + if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { + wl1271_warning("FEM index from FW out of bounds"); + ret = -EINVAL; + goto out; + } + + wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", + answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer); + +out: + kfree(gen_parms); + return ret; +} + +int wl128x_cmd_general_parms(struct wl1271 *wl) +{ + struct wl128x_general_parms_cmd *gen_parms; + struct wl128x_ini_general_params *gp = + &((struct wl128x_nvs_file *)wl->nvs)->general_params; + bool answer = false; + int ret; + + if (!wl->nvs) + return -ENODEV; + + if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { + wl1271_warning("FEM index from ini out of bounds"); + return -EINVAL; + } + + gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); + if (!gen_parms) + return -ENOMEM; + + gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; + + memcpy(&gen_parms->general_params, gp, sizeof(*gp)); + + if (gp->tx_bip_fem_auto_detect) + answer = true; + + /* Replace REF and TCXO CLKs with the ones from platform data */ + gen_parms->general_params.ref_clock = wl->ref_clock; + gen_parms->general_params.tcxo_ref_clock = wl->tcxo_clock; + + ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); + if (ret < 0) { + wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); + goto out; + } + + gp->tx_bip_fem_manufacturer = + gen_parms->general_params.tx_bip_fem_manufacturer; + + if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { + wl1271_warning("FEM index from FW out of bounds"); + ret = -EINVAL; + goto out; + } + + wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", + answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer); + +out: + kfree(gen_parms); + return ret; +} + +int wl1271_cmd_radio_parms(struct wl1271 *wl) +{ + struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs; + struct wl1271_radio_parms_cmd *radio_parms; + struct wl1271_ini_general_params *gp = &nvs->general_params; + int ret; + + if (!wl->nvs) + return -ENODEV; + + radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); + if (!radio_parms) + return -ENOMEM; + + radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; + + /* 2.4GHz parameters */ + memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, + sizeof(struct wl1271_ini_band_params_2)); + memcpy(&radio_parms->dyn_params_2, + &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, + sizeof(struct wl1271_ini_fem_params_2)); + + /* 5GHz parameters */ + memcpy(&radio_parms->static_params_5, + &nvs->stat_radio_params_5, + sizeof(struct wl1271_ini_band_params_5)); + memcpy(&radio_parms->dyn_params_5, + &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, + sizeof(struct wl1271_ini_fem_params_5)); + + wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", + radio_parms, sizeof(*radio_parms)); + + ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); + if (ret < 0) + wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); + + kfree(radio_parms); + return ret; +} + +int wl128x_cmd_radio_parms(struct wl1271 *wl) +{ + struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs; + struct wl128x_radio_parms_cmd *radio_parms; + struct wl128x_ini_general_params *gp = &nvs->general_params; + int ret; + + if (!wl->nvs) + return -ENODEV; + + radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); + if (!radio_parms) + return -ENOMEM; + + radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; + + /* 2.4GHz parameters */ + memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, + sizeof(struct wl128x_ini_band_params_2)); + memcpy(&radio_parms->dyn_params_2, + &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, + sizeof(struct wl128x_ini_fem_params_2)); + + /* 5GHz parameters */ + memcpy(&radio_parms->static_params_5, + &nvs->stat_radio_params_5, + sizeof(struct wl128x_ini_band_params_5)); + memcpy(&radio_parms->dyn_params_5, + &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, + sizeof(struct wl128x_ini_fem_params_5)); + + radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options; + + wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", + radio_parms, sizeof(*radio_parms)); + + ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); + if (ret < 0) + wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); + + kfree(radio_parms); + return ret; +} diff --git a/trunk/drivers/net/wireless/ti/wl12xx/cmd.h b/trunk/drivers/net/wireless/ti/wl12xx/cmd.h new file mode 100644 index 000000000000..140a0e8829d5 --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wl12xx/cmd.h @@ -0,0 +1,112 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 1998-2009, 2011 Texas Instruments. All rights reserved. + * Copyright (C) 2009 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_CMD_H__ +#define __WL12XX_CMD_H__ + +#include "conf.h" + +#define TEST_CMD_INI_FILE_RADIO_PARAM 0x19 +#define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E + +struct wl1271_general_parms_cmd { + struct wl1271_cmd_header header; + + struct wl1271_cmd_test_header test; + + struct wl1271_ini_general_params general_params; + + u8 sr_debug_table[WL1271_INI_MAX_SMART_REFLEX_PARAM]; + u8 sr_sen_n_p; + u8 sr_sen_n_p_gain; + u8 sr_sen_nrn; + u8 sr_sen_prn; + u8 padding[3]; +} __packed; + +struct wl128x_general_parms_cmd { + struct wl1271_cmd_header header; + + struct wl1271_cmd_test_header test; + + struct wl128x_ini_general_params general_params; + + u8 sr_debug_table[WL1271_INI_MAX_SMART_REFLEX_PARAM]; + u8 sr_sen_n_p; + u8 sr_sen_n_p_gain; + u8 sr_sen_nrn; + u8 sr_sen_prn; + u8 padding[3]; +} __packed; + +struct wl1271_radio_parms_cmd { + struct wl1271_cmd_header header; + + struct wl1271_cmd_test_header test; + + /* Static radio parameters */ + struct wl1271_ini_band_params_2 static_params_2; + struct wl1271_ini_band_params_5 static_params_5; + + /* Dynamic radio parameters */ + struct wl1271_ini_fem_params_2 dyn_params_2; + u8 padding2; + struct wl1271_ini_fem_params_5 dyn_params_5; + u8 padding3[2]; +} __packed; + +struct wl128x_radio_parms_cmd { + struct wl1271_cmd_header header; + + struct wl1271_cmd_test_header test; + + /* Static radio parameters */ + struct wl128x_ini_band_params_2 static_params_2; + struct wl128x_ini_band_params_5 static_params_5; + + u8 fem_vendor_and_options; + + /* Dynamic radio parameters */ + struct wl128x_ini_fem_params_2 dyn_params_2; + u8 padding2; + struct wl128x_ini_fem_params_5 dyn_params_5; +} __packed; + +#define TEST_CMD_INI_FILE_RF_EXTENDED_PARAM 0x26 + +struct wl1271_ext_radio_parms_cmd { + struct wl1271_cmd_header header; + + struct wl1271_cmd_test_header test; + + u8 tx_per_channel_power_compensation_2[CONF_TX_PWR_COMPENSATION_LEN_2]; + u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5]; + u8 padding[3]; +} __packed; + +int wl1271_cmd_general_parms(struct wl1271 *wl); +int wl128x_cmd_general_parms(struct wl1271 *wl); +int wl1271_cmd_radio_parms(struct wl1271 *wl); +int wl128x_cmd_radio_parms(struct wl1271 *wl); +int wl1271_cmd_ext_radio_parms(struct wl1271 *wl); + +#endif /* __WL12XX_CMD_H__ */ diff --git a/trunk/drivers/net/wireless/ti/wl12xx/conf.h b/trunk/drivers/net/wireless/ti/wl12xx/conf.h new file mode 100644 index 000000000000..75e29897a0f5 --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wl12xx/conf.h @@ -0,0 +1,50 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2011 Texas Instruments 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_CONF_H__ +#define __WL12XX_CONF_H__ + +/* these are number of channels on the band divided by two, rounded up */ +#define CONF_TX_PWR_COMPENSATION_LEN_2 7 +#define CONF_TX_PWR_COMPENSATION_LEN_5 18 + +struct wl12xx_conf_rf { + /* + * Per channel power compensation for 2.4GHz + * + * Range: s8 + */ + u8 tx_per_channel_power_compensation_2[CONF_TX_PWR_COMPENSATION_LEN_2]; + + /* + * Per channel power compensation for 5GHz + * + * Range: s8 + */ + u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5]; +}; + +struct wl12xx_priv_conf { + struct wl12xx_conf_rf rf; + struct conf_memory_settings mem_wl127x; +}; + +#endif /* __WL12XX_CONF_H__ */ diff --git a/trunk/drivers/net/wireless/ti/wl12xx/main.c b/trunk/drivers/net/wireless/ti/wl12xx/main.c new file mode 100644 index 000000000000..d7dd3def07b5 --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wl12xx/main.c @@ -0,0 +1,1388 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2010 Nokia Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include + +#include + +#include + +#include "../wlcore/wlcore.h" +#include "../wlcore/debug.h" +#include "../wlcore/io.h" +#include "../wlcore/acx.h" +#include "../wlcore/tx.h" +#include "../wlcore/rx.h" +#include "../wlcore/io.h" +#include "../wlcore/boot.h" + +#include "wl12xx.h" +#include "reg.h" +#include "cmd.h" +#include "acx.h" + +static struct wlcore_conf wl12xx_conf = { + .sg = { + .params = { + [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10, + [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180, + [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10, + [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180, + [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10, + [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80, + [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10, + [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80, + [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8, + [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8, + [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20, + [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20, + [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20, + [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35, + [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16, + [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35, + [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32, + [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50, + [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28, + [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50, + [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10, + [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20, + [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75, + [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15, + [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27, + [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17, + /* active scan params */ + [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170, + [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50, + [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100, + /* passive scan params */ + [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800, + [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200, + [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200, + /* passive scan in dual antenna params */ + [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0, + [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0, + [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0, + /* general params */ + [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1, + [CONF_SG_ANTENNA_CONFIGURATION] = 0, + [CONF_SG_BEACON_MISS_PERCENT] = 60, + [CONF_SG_DHCP_TIME] = 5000, + [CONF_SG_RXT] = 1200, + [CONF_SG_TXT] = 1000, + [CONF_SG_ADAPTIVE_RXT_TXT] = 1, + [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3, + [CONF_SG_HV3_MAX_SERVED] = 6, + [CONF_SG_PS_POLL_TIMEOUT] = 10, + [CONF_SG_UPSD_TIMEOUT] = 10, + [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2, + [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5, + [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30, + /* AP params */ + [CONF_AP_BEACON_MISS_TX] = 3, + [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10, + [CONF_AP_BEACON_WINDOW_INTERVAL] = 2, + [CONF_AP_CONNECTION_PROTECTION_TIME] = 0, + [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25, + [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25, + /* CTS Diluting params */ + [CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0, + [CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0, + }, + .state = CONF_SG_PROTECTIVE, + }, + .rx = { + .rx_msdu_life_time = 512000, + .packet_detection_threshold = 0, + .ps_poll_timeout = 15, + .upsd_timeout = 15, + .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD, + .rx_cca_threshold = 0, + .irq_blk_threshold = 0xFFFF, + .irq_pkt_threshold = 0, + .irq_timeout = 600, + .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY, + }, + .tx = { + .tx_energy_detection = 0, + .sta_rc_conf = { + .enabled_rates = 0, + .short_retry_limit = 10, + .long_retry_limit = 10, + .aflags = 0, + }, + .ac_conf_count = 4, + .ac_conf = { + [CONF_TX_AC_BE] = { + .ac = CONF_TX_AC_BE, + .cw_min = 15, + .cw_max = 63, + .aifsn = 3, + .tx_op_limit = 0, + }, + [CONF_TX_AC_BK] = { + .ac = CONF_TX_AC_BK, + .cw_min = 15, + .cw_max = 63, + .aifsn = 7, + .tx_op_limit = 0, + }, + [CONF_TX_AC_VI] = { + .ac = CONF_TX_AC_VI, + .cw_min = 15, + .cw_max = 63, + .aifsn = CONF_TX_AIFS_PIFS, + .tx_op_limit = 3008, + }, + [CONF_TX_AC_VO] = { + .ac = CONF_TX_AC_VO, + .cw_min = 15, + .cw_max = 63, + .aifsn = CONF_TX_AIFS_PIFS, + .tx_op_limit = 1504, + }, + }, + .max_tx_retries = 100, + .ap_aging_period = 300, + .tid_conf_count = 4, + .tid_conf = { + [CONF_TX_AC_BE] = { + .queue_id = CONF_TX_AC_BE, + .channel_type = CONF_CHANNEL_TYPE_EDCF, + .tsid = CONF_TX_AC_BE, + .ps_scheme = CONF_PS_SCHEME_LEGACY, + .ack_policy = CONF_ACK_POLICY_LEGACY, + .apsd_conf = {0, 0}, + }, + [CONF_TX_AC_BK] = { + .queue_id = CONF_TX_AC_BK, + .channel_type = CONF_CHANNEL_TYPE_EDCF, + .tsid = CONF_TX_AC_BK, + .ps_scheme = CONF_PS_SCHEME_LEGACY, + .ack_policy = CONF_ACK_POLICY_LEGACY, + .apsd_conf = {0, 0}, + }, + [CONF_TX_AC_VI] = { + .queue_id = CONF_TX_AC_VI, + .channel_type = CONF_CHANNEL_TYPE_EDCF, + .tsid = CONF_TX_AC_VI, + .ps_scheme = CONF_PS_SCHEME_LEGACY, + .ack_policy = CONF_ACK_POLICY_LEGACY, + .apsd_conf = {0, 0}, + }, + [CONF_TX_AC_VO] = { + .queue_id = CONF_TX_AC_VO, + .channel_type = CONF_CHANNEL_TYPE_EDCF, + .tsid = CONF_TX_AC_VO, + .ps_scheme = CONF_PS_SCHEME_LEGACY, + .ack_policy = CONF_ACK_POLICY_LEGACY, + .apsd_conf = {0, 0}, + }, + }, + .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD, + .tx_compl_timeout = 700, + .tx_compl_threshold = 4, + .basic_rate = CONF_HW_BIT_RATE_1MBPS, + .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS, + .tmpl_short_retry_limit = 10, + .tmpl_long_retry_limit = 10, + .tx_watchdog_timeout = 5000, + }, + .conn = { + .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, + .listen_interval = 1, + .suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM, + .suspend_listen_interval = 3, + .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED, + .bcn_filt_ie_count = 2, + .bcn_filt_ie = { + [0] = { + .ie = WLAN_EID_CHANNEL_SWITCH, + .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE, + }, + [1] = { + .ie = WLAN_EID_HT_OPERATION, + .rule = CONF_BCN_RULE_PASS_ON_CHANGE, + }, + }, + .synch_fail_thold = 10, + .bss_lose_timeout = 100, + .beacon_rx_timeout = 10000, + .broadcast_timeout = 20000, + .rx_broadcast_in_ps = 1, + .ps_poll_threshold = 10, + .bet_enable = CONF_BET_MODE_ENABLE, + .bet_max_consecutive = 50, + .psm_entry_retries = 8, + .psm_exit_retries = 16, + .psm_entry_nullfunc_retries = 3, + .dynamic_ps_timeout = 40, + .forced_ps = false, + .keep_alive_interval = 55000, + .max_listen_interval = 20, + }, + .itrim = { + .enable = false, + .timeout = 50000, + }, + .pm_config = { + .host_clk_settling_time = 5000, + .host_fast_wakeup_support = false + }, + .roam_trigger = { + .trigger_pacing = 1, + .avg_weight_rssi_beacon = 20, + .avg_weight_rssi_data = 10, + .avg_weight_snr_beacon = 20, + .avg_weight_snr_data = 10, + }, + .scan = { + .min_dwell_time_active = 7500, + .max_dwell_time_active = 30000, + .min_dwell_time_passive = 100000, + .max_dwell_time_passive = 100000, + .num_probe_reqs = 2, + .split_scan_timeout = 50000, + }, + .sched_scan = { + /* + * Values are in TU/1000 but since sched scan FW command + * params are in TUs rounding up may occur. + */ + .base_dwell_time = 7500, + .max_dwell_time_delta = 22500, + /* based on 250bits per probe @1Mbps */ + .dwell_time_delta_per_probe = 2000, + /* based on 250bits per probe @6Mbps (plus a bit more) */ + .dwell_time_delta_per_probe_5 = 350, + .dwell_time_passive = 100000, + .dwell_time_dfs = 150000, + .num_probe_reqs = 2, + .rssi_threshold = -90, + .snr_threshold = 0, + }, + .ht = { + .rx_ba_win_size = 8, + .tx_ba_win_size = 64, + .inactivity_timeout = 10000, + .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP, + }, + /* + * Memory config for wl127x chips is given in the + * wl12xx_default_priv_conf struct. The below configuration is + * for wl128x chips. + */ + .mem = { + .num_stations = 1, + .ssid_profiles = 1, + .rx_block_num = 40, + .tx_min_block_num = 40, + .dynamic_memory = 1, + .min_req_tx_blocks = 45, + .min_req_rx_blocks = 22, + .tx_min = 27, + }, + .fm_coex = { + .enable = true, + .swallow_period = 5, + .n_divider_fref_set_1 = 0xff, /* default */ + .n_divider_fref_set_2 = 12, + .m_divider_fref_set_1 = 148, + .m_divider_fref_set_2 = 0xffff, /* default */ + .coex_pll_stabilization_time = 0xffffffff, /* default */ + .ldo_stabilization_time = 0xffff, /* default */ + .fm_disturbed_band_margin = 0xff, /* default */ + .swallow_clk_diff = 0xff, /* default */ + }, + .rx_streaming = { + .duration = 150, + .queues = 0x1, + .interval = 20, + .always = 0, + }, + .fwlog = { + .mode = WL12XX_FWLOG_ON_DEMAND, + .mem_blocks = 2, + .severity = 0, + .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED, + .output = WL12XX_FWLOG_OUTPUT_HOST, + .threshold = 0, + }, + .rate = { + .rate_retry_score = 32000, + .per_add = 8192, + .per_th1 = 2048, + .per_th2 = 4096, + .max_per = 8100, + .inverse_curiosity_factor = 5, + .tx_fail_low_th = 4, + .tx_fail_high_th = 10, + .per_alpha_shift = 4, + .per_add_shift = 13, + .per_beta1_shift = 10, + .per_beta2_shift = 8, + .rate_check_up = 2, + .rate_check_down = 12, + .rate_retry_policy = { + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + }, + }, + .hangover = { + .recover_time = 0, + .hangover_period = 20, + .dynamic_mode = 1, + .early_termination_mode = 1, + .max_period = 20, + .min_period = 1, + .increase_delta = 1, + .decrease_delta = 2, + .quiet_time = 4, + .increase_time = 1, + .window_size = 16, + }, +}; + +static struct wl12xx_priv_conf wl12xx_default_priv_conf = { + .rf = { + .tx_per_channel_power_compensation_2 = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .tx_per_channel_power_compensation_5 = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + }, + .mem_wl127x = { + .num_stations = 1, + .ssid_profiles = 1, + .rx_block_num = 70, + .tx_min_block_num = 40, + .dynamic_memory = 1, + .min_req_tx_blocks = 100, + .min_req_rx_blocks = 22, + .tx_min = 27, + }, + +}; + +#define WL12XX_TX_HW_BLOCK_SPARE_DEFAULT 1 +#define WL12XX_TX_HW_BLOCK_GEM_SPARE 2 +#define WL12XX_TX_HW_BLOCK_SIZE 252 + +static const u8 wl12xx_rate_to_idx_2ghz[] = { + /* MCS rates are used only with 11n */ + 7, /* WL12XX_CONF_HW_RXTX_RATE_MCS7_SGI */ + 7, /* WL12XX_CONF_HW_RXTX_RATE_MCS7 */ + 6, /* WL12XX_CONF_HW_RXTX_RATE_MCS6 */ + 5, /* WL12XX_CONF_HW_RXTX_RATE_MCS5 */ + 4, /* WL12XX_CONF_HW_RXTX_RATE_MCS4 */ + 3, /* WL12XX_CONF_HW_RXTX_RATE_MCS3 */ + 2, /* WL12XX_CONF_HW_RXTX_RATE_MCS2 */ + 1, /* WL12XX_CONF_HW_RXTX_RATE_MCS1 */ + 0, /* WL12XX_CONF_HW_RXTX_RATE_MCS0 */ + + 11, /* WL12XX_CONF_HW_RXTX_RATE_54 */ + 10, /* WL12XX_CONF_HW_RXTX_RATE_48 */ + 9, /* WL12XX_CONF_HW_RXTX_RATE_36 */ + 8, /* WL12XX_CONF_HW_RXTX_RATE_24 */ + + /* TI-specific rate */ + CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_22 */ + + 7, /* WL12XX_CONF_HW_RXTX_RATE_18 */ + 6, /* WL12XX_CONF_HW_RXTX_RATE_12 */ + 3, /* WL12XX_CONF_HW_RXTX_RATE_11 */ + 5, /* WL12XX_CONF_HW_RXTX_RATE_9 */ + 4, /* WL12XX_CONF_HW_RXTX_RATE_6 */ + 2, /* WL12XX_CONF_HW_RXTX_RATE_5_5 */ + 1, /* WL12XX_CONF_HW_RXTX_RATE_2 */ + 0 /* WL12XX_CONF_HW_RXTX_RATE_1 */ +}; + +static const u8 wl12xx_rate_to_idx_5ghz[] = { + /* MCS rates are used only with 11n */ + 7, /* WL12XX_CONF_HW_RXTX_RATE_MCS7_SGI */ + 7, /* WL12XX_CONF_HW_RXTX_RATE_MCS7 */ + 6, /* WL12XX_CONF_HW_RXTX_RATE_MCS6 */ + 5, /* WL12XX_CONF_HW_RXTX_RATE_MCS5 */ + 4, /* WL12XX_CONF_HW_RXTX_RATE_MCS4 */ + 3, /* WL12XX_CONF_HW_RXTX_RATE_MCS3 */ + 2, /* WL12XX_CONF_HW_RXTX_RATE_MCS2 */ + 1, /* WL12XX_CONF_HW_RXTX_RATE_MCS1 */ + 0, /* WL12XX_CONF_HW_RXTX_RATE_MCS0 */ + + 7, /* WL12XX_CONF_HW_RXTX_RATE_54 */ + 6, /* WL12XX_CONF_HW_RXTX_RATE_48 */ + 5, /* WL12XX_CONF_HW_RXTX_RATE_36 */ + 4, /* WL12XX_CONF_HW_RXTX_RATE_24 */ + + /* TI-specific rate */ + CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_22 */ + + 3, /* WL12XX_CONF_HW_RXTX_RATE_18 */ + 2, /* WL12XX_CONF_HW_RXTX_RATE_12 */ + CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_11 */ + 1, /* WL12XX_CONF_HW_RXTX_RATE_9 */ + 0, /* WL12XX_CONF_HW_RXTX_RATE_6 */ + CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_5_5 */ + CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_2 */ + CONF_HW_RXTX_RATE_UNSUPPORTED /* WL12XX_CONF_HW_RXTX_RATE_1 */ +}; + +static const u8 *wl12xx_band_rate_to_idx[] = { + [IEEE80211_BAND_2GHZ] = wl12xx_rate_to_idx_2ghz, + [IEEE80211_BAND_5GHZ] = wl12xx_rate_to_idx_5ghz +}; + +enum wl12xx_hw_rates { + WL12XX_CONF_HW_RXTX_RATE_MCS7_SGI = 0, + WL12XX_CONF_HW_RXTX_RATE_MCS7, + WL12XX_CONF_HW_RXTX_RATE_MCS6, + WL12XX_CONF_HW_RXTX_RATE_MCS5, + WL12XX_CONF_HW_RXTX_RATE_MCS4, + WL12XX_CONF_HW_RXTX_RATE_MCS3, + WL12XX_CONF_HW_RXTX_RATE_MCS2, + WL12XX_CONF_HW_RXTX_RATE_MCS1, + WL12XX_CONF_HW_RXTX_RATE_MCS0, + WL12XX_CONF_HW_RXTX_RATE_54, + WL12XX_CONF_HW_RXTX_RATE_48, + WL12XX_CONF_HW_RXTX_RATE_36, + WL12XX_CONF_HW_RXTX_RATE_24, + WL12XX_CONF_HW_RXTX_RATE_22, + WL12XX_CONF_HW_RXTX_RATE_18, + WL12XX_CONF_HW_RXTX_RATE_12, + WL12XX_CONF_HW_RXTX_RATE_11, + WL12XX_CONF_HW_RXTX_RATE_9, + WL12XX_CONF_HW_RXTX_RATE_6, + WL12XX_CONF_HW_RXTX_RATE_5_5, + WL12XX_CONF_HW_RXTX_RATE_2, + WL12XX_CONF_HW_RXTX_RATE_1, + WL12XX_CONF_HW_RXTX_RATE_MAX, +}; + +static struct wlcore_partition_set wl12xx_ptable[PART_TABLE_LEN] = { + [PART_DOWN] = { + .mem = { + .start = 0x00000000, + .size = 0x000177c0 + }, + .reg = { + .start = REGISTERS_BASE, + .size = 0x00008800 + }, + .mem2 = { + .start = 0x00000000, + .size = 0x00000000 + }, + .mem3 = { + .start = 0x00000000, + .size = 0x00000000 + }, + }, + + [PART_BOOT] = { /* in wl12xx we can use a mix of work and down + * partition here */ + .mem = { + .start = 0x00040000, + .size = 0x00014fc0 + }, + .reg = { + .start = REGISTERS_BASE, + .size = 0x00008800 + }, + .mem2 = { + .start = 0x00000000, + .size = 0x00000000 + }, + .mem3 = { + .start = 0x00000000, + .size = 0x00000000 + }, + }, + + [PART_WORK] = { + .mem = { + .start = 0x00040000, + .size = 0x00014fc0 + }, + .reg = { + .start = REGISTERS_BASE, + .size = 0x0000a000 + }, + .mem2 = { + .start = 0x003004f8, + .size = 0x00000004 + }, + .mem3 = { + .start = 0x00040404, + .size = 0x00000000 + }, + }, + + [PART_DRPW] = { + .mem = { + .start = 0x00040000, + .size = 0x00014fc0 + }, + .reg = { + .start = DRPW_BASE, + .size = 0x00006000 + }, + .mem2 = { + .start = 0x00000000, + .size = 0x00000000 + }, + .mem3 = { + .start = 0x00000000, + .size = 0x00000000 + } + } +}; + +static const int wl12xx_rtable[REG_TABLE_LEN] = { + [REG_ECPU_CONTROL] = WL12XX_REG_ECPU_CONTROL, + [REG_INTERRUPT_NO_CLEAR] = WL12XX_REG_INTERRUPT_NO_CLEAR, + [REG_INTERRUPT_ACK] = WL12XX_REG_INTERRUPT_ACK, + [REG_COMMAND_MAILBOX_PTR] = WL12XX_REG_COMMAND_MAILBOX_PTR, + [REG_EVENT_MAILBOX_PTR] = WL12XX_REG_EVENT_MAILBOX_PTR, + [REG_INTERRUPT_TRIG] = WL12XX_REG_INTERRUPT_TRIG, + [REG_INTERRUPT_MASK] = WL12XX_REG_INTERRUPT_MASK, + [REG_PC_ON_RECOVERY] = WL12XX_SCR_PAD4, + [REG_CHIP_ID_B] = WL12XX_CHIP_ID_B, + [REG_CMD_MBOX_ADDRESS] = WL12XX_CMD_MBOX_ADDRESS, + + /* data access memory addresses, used with partition translation */ + [REG_SLV_MEM_DATA] = WL1271_SLV_MEM_DATA, + [REG_SLV_REG_DATA] = WL1271_SLV_REG_DATA, + + /* raw data access memory addresses */ + [REG_RAW_FW_STATUS_ADDR] = FW_STATUS_ADDR, +}; + +/* TODO: maybe move to a new header file? */ +#define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-4-mr.bin" +#define WL127X_FW_NAME_SINGLE "ti-connectivity/wl127x-fw-4-sr.bin" +#define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-4-plt.bin" + +#define WL128X_FW_NAME_MULTI "ti-connectivity/wl128x-fw-4-mr.bin" +#define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-4-sr.bin" +#define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-4-plt.bin" + +static void wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len) +{ + if (wl->chip.id != CHIP_ID_1283_PG20) { + struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map; + struct wl1271_rx_mem_pool_addr rx_mem_addr; + + /* + * Choose the block we want to read + * For aggregated packets, only the first memory block + * should be retrieved. The FW takes care of the rest. + */ + u32 mem_block = rx_desc & RX_MEM_BLOCK_MASK; + + rx_mem_addr.addr = (mem_block << 8) + + le32_to_cpu(wl_mem_map->packet_memory_pool_start); + + rx_mem_addr.addr_extra = rx_mem_addr.addr + 4; + + wl1271_write(wl, WL1271_SLV_REG_DATA, + &rx_mem_addr, sizeof(rx_mem_addr), false); + } +} + +static int wl12xx_identify_chip(struct wl1271 *wl) +{ + int ret = 0; + + switch (wl->chip.id) { + case CHIP_ID_1271_PG10: + wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete", + wl->chip.id); + + /* clear the alignment quirk, since we don't support it */ + wl->quirks &= ~WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN; + + wl->quirks |= WLCORE_QUIRK_LEGACY_NVS; + wl->sr_fw_name = WL127X_FW_NAME_SINGLE; + wl->mr_fw_name = WL127X_FW_NAME_MULTI; + memcpy(&wl->conf.mem, &wl12xx_default_priv_conf.mem_wl127x, + sizeof(wl->conf.mem)); + + /* read data preparation is only needed by wl127x */ + wl->ops->prepare_read = wl127x_prepare_read; + + break; + + case CHIP_ID_1271_PG20: + wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", + wl->chip.id); + + /* clear the alignment quirk, since we don't support it */ + wl->quirks &= ~WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN; + + wl->quirks |= WLCORE_QUIRK_LEGACY_NVS; + wl->plt_fw_name = WL127X_PLT_FW_NAME; + wl->sr_fw_name = WL127X_FW_NAME_SINGLE; + wl->mr_fw_name = WL127X_FW_NAME_MULTI; + memcpy(&wl->conf.mem, &wl12xx_default_priv_conf.mem_wl127x, + sizeof(wl->conf.mem)); + + /* read data preparation is only needed by wl127x */ + wl->ops->prepare_read = wl127x_prepare_read; + + break; + + case CHIP_ID_1283_PG20: + wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)", + wl->chip.id); + wl->plt_fw_name = WL128X_PLT_FW_NAME; + wl->sr_fw_name = WL128X_FW_NAME_SINGLE; + wl->mr_fw_name = WL128X_FW_NAME_MULTI; + break; + case CHIP_ID_1283_PG10: + default: + wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); + ret = -ENODEV; + goto out; + } + +out: + return ret; +} + +static void wl12xx_top_reg_write(struct wl1271 *wl, int addr, u16 val) +{ + /* write address >> 1 + 0x30000 to OCP_POR_CTR */ + addr = (addr >> 1) + 0x30000; + wl1271_write32(wl, WL12XX_OCP_POR_CTR, addr); + + /* write value to OCP_POR_WDATA */ + wl1271_write32(wl, WL12XX_OCP_DATA_WRITE, val); + + /* write 1 to OCP_CMD */ + wl1271_write32(wl, WL12XX_OCP_CMD, OCP_CMD_WRITE); +} + +static u16 wl12xx_top_reg_read(struct wl1271 *wl, int addr) +{ + u32 val; + int timeout = OCP_CMD_LOOP; + + /* write address >> 1 + 0x30000 to OCP_POR_CTR */ + addr = (addr >> 1) + 0x30000; + wl1271_write32(wl, WL12XX_OCP_POR_CTR, addr); + + /* write 2 to OCP_CMD */ + wl1271_write32(wl, WL12XX_OCP_CMD, OCP_CMD_READ); + + /* poll for data ready */ + do { + val = wl1271_read32(wl, WL12XX_OCP_DATA_READ); + } while (!(val & OCP_READY_MASK) && --timeout); + + if (!timeout) { + wl1271_warning("Top register access timed out."); + return 0xffff; + } + + /* check data status and return if OK */ + if ((val & OCP_STATUS_MASK) == OCP_STATUS_OK) + return val & 0xffff; + else { + wl1271_warning("Top register access returned error."); + return 0xffff; + } +} + +static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl) +{ + u16 spare_reg; + + /* Mask bits [2] & [8:4] in the sys_clk_cfg register */ + spare_reg = wl12xx_top_reg_read(wl, WL_SPARE_REG); + if (spare_reg == 0xFFFF) + return -EFAULT; + spare_reg |= (BIT(3) | BIT(5) | BIT(6)); + wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg); + + /* Enable FREF_CLK_REQ & mux MCS and coex PLLs to FREF */ + wl12xx_top_reg_write(wl, SYS_CLK_CFG_REG, + WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF); + + /* Delay execution for 15msec, to let the HW settle */ + mdelay(15); + + return 0; +} + +static bool wl128x_is_tcxo_valid(struct wl1271 *wl) +{ + u16 tcxo_detection; + + tcxo_detection = wl12xx_top_reg_read(wl, TCXO_CLK_DETECT_REG); + if (tcxo_detection & TCXO_DET_FAILED) + return false; + + return true; +} + +static bool wl128x_is_fref_valid(struct wl1271 *wl) +{ + u16 fref_detection; + + fref_detection = wl12xx_top_reg_read(wl, FREF_CLK_DETECT_REG); + if (fref_detection & FREF_CLK_DETECT_FAIL) + return false; + + return true; +} + +static int wl128x_manually_configure_mcs_pll(struct wl1271 *wl) +{ + wl12xx_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL); + wl12xx_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL); + wl12xx_top_reg_write(wl, MCS_PLL_CONFIG_REG, MCS_PLL_CONFIG_REG_VAL); + + return 0; +} + +static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk) +{ + u16 spare_reg; + u16 pll_config; + u8 input_freq; + + /* Mask bits [3:1] in the sys_clk_cfg register */ + spare_reg = wl12xx_top_reg_read(wl, WL_SPARE_REG); + if (spare_reg == 0xFFFF) + return -EFAULT; + spare_reg |= BIT(2); + wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg); + + /* Handle special cases of the TCXO clock */ + if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_8 || + wl->tcxo_clock == WL12XX_TCXOCLOCK_33_6) + return wl128x_manually_configure_mcs_pll(wl); + + /* Set the input frequency according to the selected clock source */ + input_freq = (clk & 1) + 1; + + pll_config = wl12xx_top_reg_read(wl, MCS_PLL_CONFIG_REG); + if (pll_config == 0xFFFF) + return -EFAULT; + pll_config |= (input_freq << MCS_SEL_IN_FREQ_SHIFT); + pll_config |= MCS_PLL_ENABLE_HP; + wl12xx_top_reg_write(wl, MCS_PLL_CONFIG_REG, pll_config); + + return 0; +} + +/* + * WL128x has two clocks input - TCXO and FREF. + * TCXO is the main clock of the device, while FREF is used to sync + * between the GPS and the cellular modem. + * In cases where TCXO is 32.736MHz or 16.368MHz, the FREF will be used + * as the WLAN/BT main clock. + */ +static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock) +{ + u16 sys_clk_cfg; + + /* For XTAL-only modes, FREF will be used after switching from TCXO */ + if (wl->ref_clock == WL12XX_REFCLOCK_26_XTAL || + wl->ref_clock == WL12XX_REFCLOCK_38_XTAL) { + if (!wl128x_switch_tcxo_to_fref(wl)) + return -EINVAL; + goto fref_clk; + } + + /* Query the HW, to determine which clock source we should use */ + sys_clk_cfg = wl12xx_top_reg_read(wl, SYS_CLK_CFG_REG); + if (sys_clk_cfg == 0xFFFF) + return -EINVAL; + if (sys_clk_cfg & PRCM_CM_EN_MUX_WLAN_FREF) + goto fref_clk; + + /* If TCXO is either 32.736MHz or 16.368MHz, switch to FREF */ + if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_368 || + wl->tcxo_clock == WL12XX_TCXOCLOCK_32_736) { + if (!wl128x_switch_tcxo_to_fref(wl)) + return -EINVAL; + goto fref_clk; + } + + /* TCXO clock is selected */ + if (!wl128x_is_tcxo_valid(wl)) + return -EINVAL; + *selected_clock = wl->tcxo_clock; + goto config_mcs_pll; + +fref_clk: + /* FREF clock is selected */ + if (!wl128x_is_fref_valid(wl)) + return -EINVAL; + *selected_clock = wl->ref_clock; + +config_mcs_pll: + return wl128x_configure_mcs_pll(wl, *selected_clock); +} + +static int wl127x_boot_clk(struct wl1271 *wl) +{ + u32 pause; + u32 clk; + + if (WL127X_PG_GET_MAJOR(wl->hw_pg_ver) < 3) + wl->quirks |= WLCORE_QUIRK_END_OF_TRANSACTION; + + if (wl->ref_clock == CONF_REF_CLK_19_2_E || + wl->ref_clock == CONF_REF_CLK_38_4_E || + wl->ref_clock == CONF_REF_CLK_38_4_M_XTAL) + /* ref clk: 19.2/38.4/38.4-XTAL */ + clk = 0x3; + else if (wl->ref_clock == CONF_REF_CLK_26_E || + wl->ref_clock == CONF_REF_CLK_52_E) + /* ref clk: 26/52 */ + clk = 0x5; + else + return -EINVAL; + + if (wl->ref_clock != CONF_REF_CLK_19_2_E) { + u16 val; + /* Set clock type (open drain) */ + val = wl12xx_top_reg_read(wl, OCP_REG_CLK_TYPE); + val &= FREF_CLK_TYPE_BITS; + wl12xx_top_reg_write(wl, OCP_REG_CLK_TYPE, val); + + /* Set clock pull mode (no pull) */ + val = wl12xx_top_reg_read(wl, OCP_REG_CLK_PULL); + val |= NO_PULL; + wl12xx_top_reg_write(wl, OCP_REG_CLK_PULL, val); + } else { + u16 val; + /* Set clock polarity */ + val = wl12xx_top_reg_read(wl, OCP_REG_CLK_POLARITY); + val &= FREF_CLK_POLARITY_BITS; + val |= CLK_REQ_OUTN_SEL; + wl12xx_top_reg_write(wl, OCP_REG_CLK_POLARITY, val); + } + + wl1271_write32(wl, WL12XX_PLL_PARAMETERS, clk); + + pause = wl1271_read32(wl, WL12XX_PLL_PARAMETERS); + + wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause); + + pause &= ~(WU_COUNTER_PAUSE_VAL); + pause |= WU_COUNTER_PAUSE_VAL; + wl1271_write32(wl, WL12XX_WU_COUNTER_PAUSE, pause); + + return 0; +} + +static int wl1271_boot_soft_reset(struct wl1271 *wl) +{ + unsigned long timeout; + u32 boot_data; + + /* perform soft reset */ + wl1271_write32(wl, WL12XX_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); + + /* SOFT_RESET is self clearing */ + timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); + while (1) { + boot_data = wl1271_read32(wl, WL12XX_SLV_SOFT_RESET); + wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); + if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) + break; + + if (time_after(jiffies, timeout)) { + /* 1.2 check pWhalBus->uSelfClearTime if the + * timeout was reached */ + wl1271_error("soft reset timeout"); + return -1; + } + + udelay(SOFT_RESET_STALL_TIME); + } + + /* disable Rx/Tx */ + wl1271_write32(wl, WL12XX_ENABLE, 0x0); + + /* disable auto calibration on start*/ + wl1271_write32(wl, WL12XX_SPARE_A2, 0xffff); + + return 0; +} + +static int wl12xx_pre_boot(struct wl1271 *wl) +{ + int ret = 0; + u32 clk; + int selected_clock = -1; + + if (wl->chip.id == CHIP_ID_1283_PG20) { + ret = wl128x_boot_clk(wl, &selected_clock); + if (ret < 0) + goto out; + } else { + ret = wl127x_boot_clk(wl); + if (ret < 0) + goto out; + } + + /* Continue the ELP wake up sequence */ + wl1271_write32(wl, WL12XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); + udelay(500); + + wlcore_set_partition(wl, &wl->ptable[PART_DRPW]); + + /* Read-modify-write DRPW_SCRATCH_START register (see next state) + to be used by DRPw FW. The RTRIM value will be added by the FW + before taking DRPw out of reset */ + + clk = wl1271_read32(wl, WL12XX_DRPW_SCRATCH_START); + + wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); + + if (wl->chip.id == CHIP_ID_1283_PG20) + clk |= ((selected_clock & 0x3) << 1) << 4; + else + clk |= (wl->ref_clock << 1) << 4; + + wl1271_write32(wl, WL12XX_DRPW_SCRATCH_START, clk); + + wlcore_set_partition(wl, &wl->ptable[PART_WORK]); + + /* Disable interrupts */ + wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); + + ret = wl1271_boot_soft_reset(wl); + if (ret < 0) + goto out; + +out: + return ret; +} + +static void wl12xx_pre_upload(struct wl1271 *wl) +{ + u32 tmp; + + /* write firmware's last address (ie. it's length) to + * ACX_EEPROMLESS_IND_REG */ + wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG"); + + wl1271_write32(wl, WL12XX_EEPROMLESS_IND, WL12XX_EEPROMLESS_IND); + + tmp = wlcore_read_reg(wl, REG_CHIP_ID_B); + + wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp); + + /* 6. read the EEPROM parameters */ + tmp = wl1271_read32(wl, WL12XX_SCR_PAD2); + + /* WL1271: The reference driver skips steps 7 to 10 (jumps directly + * to upload_fw) */ + + if (wl->chip.id == CHIP_ID_1283_PG20) + wl12xx_top_reg_write(wl, SDIO_IO_DS, HCI_IO_DS_6MA); +} + +static void wl12xx_enable_interrupts(struct wl1271 *wl) +{ + u32 polarity; + + polarity = wl12xx_top_reg_read(wl, OCP_REG_POLARITY); + + /* We use HIGH polarity, so unset the LOW bit */ + polarity &= ~POLARITY_LOW; + wl12xx_top_reg_write(wl, OCP_REG_POLARITY, polarity); + + wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_ALL_EVENTS_VECTOR); + + wlcore_enable_interrupts(wl); + wlcore_write_reg(wl, REG_INTERRUPT_MASK, + WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK)); + + wl1271_write32(wl, WL12XX_HI_CFG, HI_CFG_DEF_VAL); +} + +static int wl12xx_boot(struct wl1271 *wl) +{ + int ret; + + ret = wl12xx_pre_boot(wl); + if (ret < 0) + goto out; + + ret = wlcore_boot_upload_nvs(wl); + if (ret < 0) + goto out; + + wl12xx_pre_upload(wl); + + ret = wlcore_boot_upload_firmware(wl); + if (ret < 0) + goto out; + + ret = wlcore_boot_run_firmware(wl); + if (ret < 0) + goto out; + + wl12xx_enable_interrupts(wl); + +out: + return ret; +} + +static void wl12xx_trigger_cmd(struct wl1271 *wl, int cmd_box_addr, + void *buf, size_t len) +{ + wl1271_write(wl, cmd_box_addr, buf, len, false); + wlcore_write_reg(wl, REG_INTERRUPT_TRIG, WL12XX_INTR_TRIG_CMD); +} + +static void wl12xx_ack_event(struct wl1271 *wl) +{ + wlcore_write_reg(wl, REG_INTERRUPT_TRIG, WL12XX_INTR_TRIG_EVENT_ACK); +} + +static u32 wl12xx_calc_tx_blocks(struct wl1271 *wl, u32 len, u32 spare_blks) +{ + u32 blk_size = WL12XX_TX_HW_BLOCK_SIZE; + u32 align_len = wlcore_calc_packet_alignment(wl, len); + + return (align_len + blk_size - 1) / blk_size + spare_blks; +} + +static void +wl12xx_set_tx_desc_blocks(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc, + u32 blks, u32 spare_blks) +{ + if (wl->chip.id == CHIP_ID_1283_PG20) { + desc->wl128x_mem.total_mem_blocks = blks; + } else { + desc->wl127x_mem.extra_blocks = spare_blks; + desc->wl127x_mem.total_mem_blocks = blks; + } +} + +static void +wl12xx_set_tx_desc_data_len(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc, + struct sk_buff *skb) +{ + u32 aligned_len = wlcore_calc_packet_alignment(wl, skb->len); + + if (wl->chip.id == CHIP_ID_1283_PG20) { + desc->wl128x_mem.extra_bytes = aligned_len - skb->len; + desc->length = cpu_to_le16(aligned_len >> 2); + + wl1271_debug(DEBUG_TX, + "tx_fill_hdr: hlid: %d len: %d life: %d mem: %d extra: %d", + desc->hlid, + le16_to_cpu(desc->length), + le16_to_cpu(desc->life_time), + desc->wl128x_mem.total_mem_blocks, + desc->wl128x_mem.extra_bytes); + } else { + /* calculate number of padding bytes */ + int pad = aligned_len - skb->len; + desc->tx_attr |= + cpu_to_le16(pad << TX_HW_ATTR_OFST_LAST_WORD_PAD); + + /* Store the aligned length in terms of words */ + desc->length = cpu_to_le16(aligned_len >> 2); + + wl1271_debug(DEBUG_TX, + "tx_fill_hdr: pad: %d hlid: %d len: %d life: %d mem: %d", + pad, desc->hlid, + le16_to_cpu(desc->length), + le16_to_cpu(desc->life_time), + desc->wl127x_mem.total_mem_blocks); + } +} + +static enum wl_rx_buf_align +wl12xx_get_rx_buf_align(struct wl1271 *wl, u32 rx_desc) +{ + if (rx_desc & RX_BUF_UNALIGNED_PAYLOAD) + return WLCORE_RX_BUF_UNALIGNED; + + return WLCORE_RX_BUF_ALIGNED; +} + +static u32 wl12xx_get_rx_packet_len(struct wl1271 *wl, void *rx_data, + u32 data_len) +{ + struct wl1271_rx_descriptor *desc = rx_data; + + /* invalid packet */ + if (data_len < sizeof(*desc) || + data_len < sizeof(*desc) + desc->pad_len) + return 0; + + return data_len - sizeof(*desc) - desc->pad_len; +} + +static void wl12xx_tx_delayed_compl(struct wl1271 *wl) +{ + if (wl->fw_status->tx_results_counter == (wl->tx_results_count & 0xff)) + return; + + wl1271_tx_complete(wl); +} + +static int wl12xx_hw_init(struct wl1271 *wl) +{ + int ret; + + if (wl->chip.id == CHIP_ID_1283_PG20) { + u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE; + + ret = wl128x_cmd_general_parms(wl); + if (ret < 0) + goto out; + ret = wl128x_cmd_radio_parms(wl); + if (ret < 0) + goto out; + + if (wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN) + /* Enable SDIO padding */ + host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK; + + /* Must be before wl1271_acx_init_mem_config() */ + ret = wl1271_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap); + if (ret < 0) + goto out; + } else { + ret = wl1271_cmd_general_parms(wl); + if (ret < 0) + goto out; + ret = wl1271_cmd_radio_parms(wl); + if (ret < 0) + goto out; + ret = wl1271_cmd_ext_radio_parms(wl); + if (ret < 0) + goto out; + } +out: + return ret; +} + +static u32 wl12xx_sta_get_ap_rate_mask(struct wl1271 *wl, + struct wl12xx_vif *wlvif) +{ + return wlvif->rate_set; +} + +static int wl12xx_identify_fw(struct wl1271 *wl) +{ + unsigned int *fw_ver = wl->chip.fw_ver; + + /* Only new station firmwares support routing fw logs to the host */ + if ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) && + (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_FWLOG_STA_MIN)) + wl->quirks |= WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED; + + /* This feature is not yet supported for AP mode */ + if (fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) + wl->quirks |= WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED; + + return 0; +} + +static void wl12xx_conf_init(struct wl1271 *wl) +{ + struct wl12xx_priv *priv = wl->priv; + + /* apply driver default configuration */ + memcpy(&wl->conf, &wl12xx_conf, sizeof(wl12xx_conf)); + + /* apply default private configuration */ + memcpy(&priv->conf, &wl12xx_default_priv_conf, sizeof(priv->conf)); +} + +static bool wl12xx_mac_in_fuse(struct wl1271 *wl) +{ + bool supported = false; + u8 major, minor; + + if (wl->chip.id == CHIP_ID_1283_PG20) { + major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver); + minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver); + + /* in wl128x we have the MAC address if the PG is >= (2, 1) */ + if (major > 2 || (major == 2 && minor >= 1)) + supported = true; + } else { + major = WL127X_PG_GET_MAJOR(wl->hw_pg_ver); + minor = WL127X_PG_GET_MINOR(wl->hw_pg_ver); + + /* in wl127x we have the MAC address if the PG is >= (3, 1) */ + if (major == 3 && minor >= 1) + supported = true; + } + + wl1271_debug(DEBUG_PROBE, + "PG Ver major = %d minor = %d, MAC %s present", + major, minor, supported ? "is" : "is not"); + + return supported; +} + +static void wl12xx_get_fuse_mac(struct wl1271 *wl) +{ + u32 mac1, mac2; + + wlcore_set_partition(wl, &wl->ptable[PART_DRPW]); + + mac1 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1); + mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2); + + /* these are the two parts of the BD_ADDR */ + wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) + + ((mac1 & 0xff000000) >> 24); + wl->fuse_nic_addr = mac1 & 0xffffff; + + wlcore_set_partition(wl, &wl->ptable[PART_DOWN]); +} + +static s8 wl12xx_get_pg_ver(struct wl1271 *wl) +{ + u32 die_info; + + if (wl->chip.id == CHIP_ID_1283_PG20) + die_info = wl12xx_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1); + else + die_info = wl12xx_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1); + + return (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET; +} + +static void wl12xx_get_mac(struct wl1271 *wl) +{ + if (wl12xx_mac_in_fuse(wl)) + wl12xx_get_fuse_mac(wl); +} + +static struct wlcore_ops wl12xx_ops = { + .identify_chip = wl12xx_identify_chip, + .identify_fw = wl12xx_identify_fw, + .boot = wl12xx_boot, + .trigger_cmd = wl12xx_trigger_cmd, + .ack_event = wl12xx_ack_event, + .calc_tx_blocks = wl12xx_calc_tx_blocks, + .set_tx_desc_blocks = wl12xx_set_tx_desc_blocks, + .set_tx_desc_data_len = wl12xx_set_tx_desc_data_len, + .get_rx_buf_align = wl12xx_get_rx_buf_align, + .get_rx_packet_len = wl12xx_get_rx_packet_len, + .tx_immediate_compl = NULL, + .tx_delayed_compl = wl12xx_tx_delayed_compl, + .hw_init = wl12xx_hw_init, + .init_vif = NULL, + .sta_get_ap_rate_mask = wl12xx_sta_get_ap_rate_mask, + .get_pg_ver = wl12xx_get_pg_ver, + .get_mac = wl12xx_get_mac, +}; + +static struct ieee80211_sta_ht_cap wl12xx_ht_cap = { + .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | + (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), + .ht_supported = true, + .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, + .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, + .mcs = { + .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + .rx_highest = cpu_to_le16(72), + .tx_params = IEEE80211_HT_MCS_TX_DEFINED, + }, +}; + +static int __devinit wl12xx_probe(struct platform_device *pdev) +{ + struct wl1271 *wl; + struct ieee80211_hw *hw; + struct wl12xx_priv *priv; + + hw = wlcore_alloc_hw(sizeof(*priv)); + if (IS_ERR(hw)) { + wl1271_error("can't allocate hw"); + return PTR_ERR(hw); + } + + wl = hw->priv; + wl->ops = &wl12xx_ops; + wl->ptable = wl12xx_ptable; + wl->rtable = wl12xx_rtable; + wl->num_tx_desc = 16; + wl->normal_tx_spare = WL12XX_TX_HW_BLOCK_SPARE_DEFAULT; + wl->gem_tx_spare = WL12XX_TX_HW_BLOCK_GEM_SPARE; + wl->band_rate_to_idx = wl12xx_band_rate_to_idx; + wl->hw_tx_rate_tbl_size = WL12XX_CONF_HW_RXTX_RATE_MAX; + wl->hw_min_ht_rate = WL12XX_CONF_HW_RXTX_RATE_MCS0; + wl->fw_status_priv_len = 0; + memcpy(&wl->ht_cap, &wl12xx_ht_cap, sizeof(wl12xx_ht_cap)); + wl12xx_conf_init(wl); + + return wlcore_probe(wl, pdev); +} + +static const struct platform_device_id wl12xx_id_table[] __devinitconst = { + { "wl12xx", 0 }, + { } /* Terminating Entry */ +}; +MODULE_DEVICE_TABLE(platform, wl12xx_id_table); + +static struct platform_driver wl12xx_driver = { + .probe = wl12xx_probe, + .remove = __devexit_p(wlcore_remove), + .id_table = wl12xx_id_table, + .driver = { + .name = "wl12xx_driver", + .owner = THIS_MODULE, + } +}; + +static int __init wl12xx_init(void) +{ + return platform_driver_register(&wl12xx_driver); +} +module_init(wl12xx_init); + +static void __exit wl12xx_exit(void) +{ + platform_driver_unregister(&wl12xx_driver); +} +module_exit(wl12xx_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Luciano Coelho "); +MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE); +MODULE_FIRMWARE(WL127X_FW_NAME_MULTI); +MODULE_FIRMWARE(WL127X_PLT_FW_NAME); +MODULE_FIRMWARE(WL128X_FW_NAME_SINGLE); +MODULE_FIRMWARE(WL128X_FW_NAME_MULTI); +MODULE_FIRMWARE(WL128X_PLT_FW_NAME); diff --git a/trunk/drivers/net/wireless/ti/wl12xx/reg.h b/trunk/drivers/net/wireless/ti/wl12xx/reg.h new file mode 100644 index 000000000000..79ede02e2587 --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wl12xx/reg.h @@ -0,0 +1,556 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __REG_H__ +#define __REG_H__ + +#include + +#define REGISTERS_BASE 0x00300000 +#define DRPW_BASE 0x00310000 + +#define REGISTERS_DOWN_SIZE 0x00008800 +#define REGISTERS_WORK_SIZE 0x0000b000 + +#define FW_STATUS_ADDR (0x14FC0 + 0xA000) + +/*=============================================== + Host Software Reset - 32bit RW + ------------------------------------------ + [31:1] Reserved + 0 SOFT_RESET Soft Reset - When this bit is set, + it holds the Wlan hardware in a soft reset state. + This reset disables all MAC and baseband processor + clocks except the CardBus/PCI interface clock. + It also initializes all MAC state machines except + the host interface. It does not reload the + contents of the EEPROM. When this bit is cleared + (not self-clearing), the Wlan hardware + exits the software reset state. +===============================================*/ +#define WL12XX_SLV_SOFT_RESET (REGISTERS_BASE + 0x0000) + +#define WL1271_SLV_REG_DATA (REGISTERS_BASE + 0x0008) +#define WL1271_SLV_REG_ADATA (REGISTERS_BASE + 0x000c) +#define WL1271_SLV_MEM_DATA (REGISTERS_BASE + 0x0018) + +#define WL12XX_REG_INTERRUPT_TRIG (REGISTERS_BASE + 0x0474) +#define WL12XX_REG_INTERRUPT_TRIG_H (REGISTERS_BASE + 0x0478) + +/*============================================= + Host Interrupt Mask Register - 32bit (RW) + ------------------------------------------ + Setting a bit in this register masks the + corresponding interrupt to the host. + 0 - RX0 - Rx first dubble buffer Data Interrupt + 1 - TXD - Tx Data Interrupt + 2 - TXXFR - Tx Transfer Interrupt + 3 - RX1 - Rx second dubble buffer Data Interrupt + 4 - RXXFR - Rx Transfer Interrupt + 5 - EVENT_A - Event Mailbox interrupt + 6 - EVENT_B - Event Mailbox interrupt + 7 - WNONHST - Wake On Host Interrupt + 8 - TRACE_A - Debug Trace interrupt + 9 - TRACE_B - Debug Trace interrupt + 10 - CDCMP - Command Complete Interrupt + 11 - + 12 - + 13 - + 14 - ICOMP - Initialization Complete Interrupt + 16 - SG SE - Soft Gemini - Sense enable interrupt + 17 - SG SD - Soft Gemini - Sense disable interrupt + 18 - - + 19 - - + 20 - - + 21- - + Default: 0x0001 +*==============================================*/ +#define WL12XX_REG_INTERRUPT_MASK (REGISTERS_BASE + 0x04DC) + +/*============================================= + Host Interrupt Mask Set 16bit, (Write only) + ------------------------------------------ + Setting a bit in this register sets + the corresponding bin in ACX_HINT_MASK register + without effecting the mask + state of other bits (0 = no effect). +==============================================*/ +#define ACX_REG_HINT_MASK_SET (REGISTERS_BASE + 0x04E0) + +/*============================================= + Host Interrupt Mask Clear 16bit,(Write only) + ------------------------------------------ + Setting a bit in this register clears + the corresponding bin in ACX_HINT_MASK register + without effecting the mask + state of other bits (0 = no effect). +=============================================*/ +#define ACX_REG_HINT_MASK_CLR (REGISTERS_BASE + 0x04E4) + +/*============================================= + Host Interrupt Status Nondestructive Read + 16bit,(Read only) + ------------------------------------------ + The host can read this register to determine + which interrupts are active. + Reading this register doesn't + effect its content. +=============================================*/ +#define WL12XX_REG_INTERRUPT_NO_CLEAR (REGISTERS_BASE + 0x04E8) + +/*============================================= + Host Interrupt Status Clear on Read Register + 16bit,(Read only) + ------------------------------------------ + The host can read this register to determine + which interrupts are active. + Reading this register clears it, + thus making all interrupts inactive. +==============================================*/ +#define ACX_REG_INTERRUPT_CLEAR (REGISTERS_BASE + 0x04F8) + +/*============================================= + Host Interrupt Acknowledge Register + 16bit,(Write only) + ------------------------------------------ + The host can set individual bits in this + register to clear (acknowledge) the corresp. + interrupt status bits in the HINT_STS_CLR and + HINT_STS_ND registers, thus making the + assotiated interrupt inactive. (0-no effect) +==============================================*/ +#define WL12XX_REG_INTERRUPT_ACK (REGISTERS_BASE + 0x04F0) + +#define WL12XX_REG_RX_DRIVER_COUNTER (REGISTERS_BASE + 0x0538) + +/* Device Configuration registers*/ +#define SOR_CFG (REGISTERS_BASE + 0x0800) + +/* Embedded ARM CPU Control */ + +/*=============================================== + Halt eCPU - 32bit RW + ------------------------------------------ + 0 HALT_ECPU Halt Embedded CPU - This bit is the + compliment of bit 1 (MDATA2) in the SOR_CFG register. + During a hardware reset, this bit holds + the inverse of MDATA2. + When downloading firmware from the host, + set this bit (pull down MDATA2). + The host clears this bit after downloading the firmware into + zero-wait-state SSRAM. + When loading firmware from Flash, clear this bit (pull up MDATA2) + so that the eCPU can run the bootloader code in Flash + HALT_ECPU eCPU State + -------------------- + 1 halt eCPU + 0 enable eCPU + ===============================================*/ +#define WL12XX_REG_ECPU_CONTROL (REGISTERS_BASE + 0x0804) + +#define WL12XX_HI_CFG (REGISTERS_BASE + 0x0808) + +/*=============================================== + EEPROM Burst Read Start - 32bit RW + ------------------------------------------ + [31:1] Reserved + 0 ACX_EE_START - EEPROM Burst Read Start 0 + Setting this bit starts a burst read from + the external EEPROM. + If this bit is set (after reset) before an EEPROM read/write, + the burst read starts at EEPROM address 0. + Otherwise, it starts at the address + following the address of the previous access. + TheWlan hardware hardware clears this bit automatically. + + Default: 0x00000000 +*================================================*/ +#define ACX_REG_EE_START (REGISTERS_BASE + 0x080C) + +#define WL12XX_OCP_POR_CTR (REGISTERS_BASE + 0x09B4) +#define WL12XX_OCP_DATA_WRITE (REGISTERS_BASE + 0x09B8) +#define WL12XX_OCP_DATA_READ (REGISTERS_BASE + 0x09BC) +#define WL12XX_OCP_CMD (REGISTERS_BASE + 0x09C0) + +#define WL12XX_HOST_WR_ACCESS (REGISTERS_BASE + 0x09F8) + +#define WL12XX_CHIP_ID_B (REGISTERS_BASE + 0x5674) + +#define WL12XX_ENABLE (REGISTERS_BASE + 0x5450) + +/* Power Management registers */ +#define WL12XX_ELP_CFG_MODE (REGISTERS_BASE + 0x5804) +#define WL12XX_ELP_CMD (REGISTERS_BASE + 0x5808) +#define WL12XX_PLL_CAL_TIME (REGISTERS_BASE + 0x5810) +#define WL12XX_CLK_REQ_TIME (REGISTERS_BASE + 0x5814) +#define WL12XX_CLK_BUF_TIME (REGISTERS_BASE + 0x5818) + +#define WL12XX_CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820) + +/* Scratch Pad registers*/ +#define WL12XX_SCR_PAD0 (REGISTERS_BASE + 0x5608) +#define WL12XX_SCR_PAD1 (REGISTERS_BASE + 0x560C) +#define WL12XX_SCR_PAD2 (REGISTERS_BASE + 0x5610) +#define WL12XX_SCR_PAD3 (REGISTERS_BASE + 0x5614) +#define WL12XX_SCR_PAD4 (REGISTERS_BASE + 0x5618) +#define WL12XX_SCR_PAD4_SET (REGISTERS_BASE + 0x561C) +#define WL12XX_SCR_PAD4_CLR (REGISTERS_BASE + 0x5620) +#define WL12XX_SCR_PAD5 (REGISTERS_BASE + 0x5624) +#define WL12XX_SCR_PAD5_SET (REGISTERS_BASE + 0x5628) +#define WL12XX_SCR_PAD5_CLR (REGISTERS_BASE + 0x562C) +#define WL12XX_SCR_PAD6 (REGISTERS_BASE + 0x5630) +#define WL12XX_SCR_PAD7 (REGISTERS_BASE + 0x5634) +#define WL12XX_SCR_PAD8 (REGISTERS_BASE + 0x5638) +#define WL12XX_SCR_PAD9 (REGISTERS_BASE + 0x563C) + +/* Spare registers*/ +#define WL12XX_SPARE_A1 (REGISTERS_BASE + 0x0994) +#define WL12XX_SPARE_A2 (REGISTERS_BASE + 0x0998) +#define WL12XX_SPARE_A3 (REGISTERS_BASE + 0x099C) +#define WL12XX_SPARE_A4 (REGISTERS_BASE + 0x09A0) +#define WL12XX_SPARE_A5 (REGISTERS_BASE + 0x09A4) +#define WL12XX_SPARE_A6 (REGISTERS_BASE + 0x09A8) +#define WL12XX_SPARE_A7 (REGISTERS_BASE + 0x09AC) +#define WL12XX_SPARE_A8 (REGISTERS_BASE + 0x09B0) +#define WL12XX_SPARE_B1 (REGISTERS_BASE + 0x5420) +#define WL12XX_SPARE_B2 (REGISTERS_BASE + 0x5424) +#define WL12XX_SPARE_B3 (REGISTERS_BASE + 0x5428) +#define WL12XX_SPARE_B4 (REGISTERS_BASE + 0x542C) +#define WL12XX_SPARE_B5 (REGISTERS_BASE + 0x5430) +#define WL12XX_SPARE_B6 (REGISTERS_BASE + 0x5434) +#define WL12XX_SPARE_B7 (REGISTERS_BASE + 0x5438) +#define WL12XX_SPARE_B8 (REGISTERS_BASE + 0x543C) + +#define WL12XX_PLL_PARAMETERS (REGISTERS_BASE + 0x6040) +#define WL12XX_WU_COUNTER_PAUSE (REGISTERS_BASE + 0x6008) +#define WL12XX_WELP_ARM_COMMAND (REGISTERS_BASE + 0x6100) +#define WL12XX_DRPW_SCRATCH_START (DRPW_BASE + 0x002C) + +#define WL12XX_CMD_MBOX_ADDRESS 0x407B4 + +#define ACX_REG_EEPROM_START_BIT BIT(1) + +/* Command/Information Mailbox Pointers */ + +/*=============================================== + Command Mailbox Pointer - 32bit RW + ------------------------------------------ + This register holds the start address of + the command mailbox located in the Wlan hardware memory. + The host must read this pointer after a reset to + find the location of the command mailbox. + The Wlan hardware initializes the command mailbox + pointer with the default address of the command mailbox. + The command mailbox pointer is not valid until after + the host receives the Init Complete interrupt from + the Wlan hardware. + ===============================================*/ +#define WL12XX_REG_COMMAND_MAILBOX_PTR (WL12XX_SCR_PAD0) + +/*=============================================== + Information Mailbox Pointer - 32bit RW + ------------------------------------------ + This register holds the start address of + the information mailbox located in the Wlan hardware memory. + The host must read this pointer after a reset to find + the location of the information mailbox. + The Wlan hardware initializes the information mailbox pointer + with the default address of the information mailbox. + The information mailbox pointer is not valid + until after the host receives the Init Complete interrupt from + the Wlan hardware. + ===============================================*/ +#define WL12XX_REG_EVENT_MAILBOX_PTR (WL12XX_SCR_PAD1) + +/*=============================================== + EEPROM Read/Write Request 32bit RW + ------------------------------------------ + 1 EE_READ - EEPROM Read Request 1 - Setting this bit + loads a single byte of data into the EE_DATA + register from the EEPROM location specified in + the EE_ADDR register. + The Wlan hardware hardware clears this bit automatically. + EE_DATA is valid when this bit is cleared. + + 0 EE_WRITE - EEPROM Write Request - Setting this bit + writes a single byte of data from the EE_DATA register into the + EEPROM location specified in the EE_ADDR register. + The Wlan hardware hardware clears this bit automatically. +*===============================================*/ +#define ACX_EE_CTL_REG EE_CTL +#define EE_WRITE 0x00000001ul +#define EE_READ 0x00000002ul + +/*=============================================== + EEPROM Address - 32bit RW + ------------------------------------------ + This register specifies the address + within the EEPROM from/to which to read/write data. + ===============================================*/ +#define ACX_EE_ADDR_REG EE_ADDR + +/*=============================================== + EEPROM Data - 32bit RW + ------------------------------------------ + This register either holds the read 8 bits of + data from the EEPROM or the write data + to be written to the EEPROM. + ===============================================*/ +#define ACX_EE_DATA_REG EE_DATA + +/*=============================================== + EEPROM Base Address - 32bit RW + ------------------------------------------ + This register holds the upper nine bits + [23:15] of the 24-bit Wlan hardware memory + address for burst reads from EEPROM accesses. + The EEPROM provides the lower 15 bits of this address. + The MSB of the address from the EEPROM is ignored. + ===============================================*/ +#define ACX_EE_CFG EE_CFG + +/*=============================================== + GPIO Output Values -32bit, RW + ------------------------------------------ + [31:16] Reserved + [15: 0] Specify the output values (at the output driver inputs) for + GPIO[15:0], respectively. + ===============================================*/ +#define ACX_GPIO_OUT_REG GPIO_OUT +#define ACX_MAX_GPIO_LINES 15 + +/*=============================================== + Contention window -32bit, RW + ------------------------------------------ + [31:26] Reserved + [25:16] Max (0x3ff) + [15:07] Reserved + [06:00] Current contention window value - default is 0x1F + ===============================================*/ +#define ACX_CONT_WIND_CFG_REG CONT_WIND_CFG +#define ACX_CONT_WIND_MIN_MASK 0x0000007f +#define ACX_CONT_WIND_MAX 0x03ff0000 + +#define REF_FREQ_19_2 0 +#define REF_FREQ_26_0 1 +#define REF_FREQ_38_4 2 +#define REF_FREQ_40_0 3 +#define REF_FREQ_33_6 4 +#define REF_FREQ_NUM 5 + +#define LUT_PARAM_INTEGER_DIVIDER 0 +#define LUT_PARAM_FRACTIONAL_DIVIDER 1 +#define LUT_PARAM_ATTN_BB 2 +#define LUT_PARAM_ALPHA_BB 3 +#define LUT_PARAM_STOP_TIME_BB 4 +#define LUT_PARAM_BB_PLL_LOOP_FILTER 5 +#define LUT_PARAM_NUM 6 + +#define WL12XX_EEPROMLESS_IND (WL12XX_SCR_PAD4) +#define USE_EEPROM 0 +#define NVS_DATA_BUNDARY_ALIGNMENT 4 + +/* Firmware image header size */ +#define FW_HDR_SIZE 8 + +/****************************************************************************** + + CHANNELS, BAND & REG DOMAINS definitions + +******************************************************************************/ + +#define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */ +#define OFDM_RATE_BIT BIT(6) +#define PBCC_RATE_BIT BIT(7) + +enum { + CCK_LONG = 0, + CCK_SHORT = SHORT_PREAMBLE_BIT, + PBCC_LONG = PBCC_RATE_BIT, + PBCC_SHORT = PBCC_RATE_BIT | SHORT_PREAMBLE_BIT, + OFDM = OFDM_RATE_BIT +}; + +/****************************************************************************** + +Transmit-Descriptor RATE-SET field definitions... + +Define a new "Rate-Set" for TX path that incorporates the +Rate & Modulation info into a single 16-bit field. + +TxdRateSet_t: +b15 - Indicates Preamble type (1=SHORT, 0=LONG). + Notes: + Must be LONG (0) for 1Mbps rate. + Does not apply (set to 0) for RevG-OFDM rates. +b14 - Indicates PBCC encoding (1=PBCC, 0=not). + Notes: + Does not apply (set to 0) for rates 1 and 2 Mbps. + Does not apply (set to 0) for RevG-OFDM rates. +b13 - Unused (set to 0). +b12-b0 - Supported Rate indicator bits as defined below. + +******************************************************************************/ + +#define OCP_CMD_LOOP 32 +#define OCP_CMD_WRITE 0x1 +#define OCP_CMD_READ 0x2 +#define OCP_READY_MASK BIT(18) +#define OCP_STATUS_MASK (BIT(16) | BIT(17)) +#define OCP_STATUS_NO_RESP 0x00000 +#define OCP_STATUS_OK 0x10000 +#define OCP_STATUS_REQ_FAILED 0x20000 +#define OCP_STATUS_RESP_ERROR 0x30000 + +#define OCP_REG_POLARITY 0x0064 +#define OCP_REG_CLK_TYPE 0x0448 +#define OCP_REG_CLK_POLARITY 0x0cb2 +#define OCP_REG_CLK_PULL 0x0cb4 + +#define POLARITY_LOW BIT(1) +#define NO_PULL (BIT(14) | BIT(15)) + +#define FREF_CLK_TYPE_BITS 0xfffffe7f +#define CLK_REQ_PRCM 0x100 +#define FREF_CLK_POLARITY_BITS 0xfffff8ff +#define CLK_REQ_OUTN_SEL 0x700 + +#define WU_COUNTER_PAUSE_VAL 0x3FF + +/* PLL configuration algorithm for wl128x */ +#define SYS_CLK_CFG_REG 0x2200 +/* Bit[0] - 0-TCXO, 1-FREF */ +#define MCS_PLL_CLK_SEL_FREF BIT(0) +/* Bit[3:2] - 01-TCXO, 10-FREF */ +#define WL_CLK_REQ_TYPE_FREF BIT(3) +#define WL_CLK_REQ_TYPE_PG2 (BIT(3) | BIT(2)) +/* Bit[4] - 0-TCXO, 1-FREF */ +#define PRCM_CM_EN_MUX_WLAN_FREF BIT(4) + +#define TCXO_ILOAD_INT_REG 0x2264 +#define TCXO_CLK_DETECT_REG 0x2266 + +#define TCXO_DET_FAILED BIT(4) + +#define FREF_ILOAD_INT_REG 0x2084 +#define FREF_CLK_DETECT_REG 0x2086 +#define FREF_CLK_DETECT_FAIL BIT(4) + +/* Use this reg for masking during driver access */ +#define WL_SPARE_REG 0x2320 +#define WL_SPARE_VAL BIT(2) +/* Bit[6:5:3] - mask wl write SYS_CLK_CFG[8:5:2:4] */ +#define WL_SPARE_MASK_8526 (BIT(6) | BIT(5) | BIT(3)) + +#define PLL_LOCK_COUNTERS_REG 0xD8C +#define PLL_LOCK_COUNTERS_COEX 0x0F +#define PLL_LOCK_COUNTERS_MCS 0xF0 +#define MCS_PLL_OVERRIDE_REG 0xD90 +#define MCS_PLL_CONFIG_REG 0xD92 +#define MCS_SEL_IN_FREQ_MASK 0x0070 +#define MCS_SEL_IN_FREQ_SHIFT 4 +#define MCS_PLL_CONFIG_REG_VAL 0x73 +#define MCS_PLL_ENABLE_HP (BIT(0) | BIT(1)) + +#define MCS_PLL_M_REG 0xD94 +#define MCS_PLL_N_REG 0xD96 +#define MCS_PLL_M_REG_VAL 0xC8 +#define MCS_PLL_N_REG_VAL 0x07 + +#define SDIO_IO_DS 0xd14 + +/* SDIO/wSPI DS configuration values */ +enum { + HCI_IO_DS_8MA = 0, + HCI_IO_DS_4MA = 1, /* default */ + HCI_IO_DS_6MA = 2, + HCI_IO_DS_2MA = 3, +}; + +/* end PLL configuration algorithm for wl128x */ + +/* + * Host Command Interrupt. Setting this bit masks + * the interrupt that the host issues to inform + * the FW that it has sent a command + * to the Wlan hardware Command Mailbox. + */ +#define WL12XX_INTR_TRIG_CMD BIT(0) + +/* + * Host Event Acknowlegde Interrupt. The host + * sets this bit to acknowledge that it received + * the unsolicited information from the event + * mailbox. + */ +#define WL12XX_INTR_TRIG_EVENT_ACK BIT(1) + +/*=============================================== + HI_CFG Interface Configuration Register Values + ------------------------------------------ + ===============================================*/ +#define HI_CFG_UART_ENABLE 0x00000004 +#define HI_CFG_RST232_ENABLE 0x00000008 +#define HI_CFG_CLOCK_REQ_SELECT 0x00000010 +#define HI_CFG_HOST_INT_ENABLE 0x00000020 +#define HI_CFG_VLYNQ_OUTPUT_ENABLE 0x00000040 +#define HI_CFG_HOST_INT_ACTIVE_LOW 0x00000080 +#define HI_CFG_UART_TX_OUT_GPIO_15 0x00000100 +#define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200 +#define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400 + +#define HI_CFG_DEF_VAL \ + (HI_CFG_UART_ENABLE | \ + HI_CFG_RST232_ENABLE | \ + HI_CFG_CLOCK_REQ_SELECT | \ + HI_CFG_HOST_INT_ENABLE) + +#define WL127X_REG_FUSE_DATA_2_1 0x050a +#define WL128X_REG_FUSE_DATA_2_1 0x2152 +#define PG_VER_MASK 0x3c +#define PG_VER_OFFSET 2 + +#define WL127X_PG_MAJOR_VER_MASK 0x3 +#define WL127X_PG_MAJOR_VER_OFFSET 0x0 +#define WL127X_PG_MINOR_VER_MASK 0xc +#define WL127X_PG_MINOR_VER_OFFSET 0x2 + +#define WL128X_PG_MAJOR_VER_MASK 0xc +#define WL128X_PG_MAJOR_VER_OFFSET 0x2 +#define WL128X_PG_MINOR_VER_MASK 0x3 +#define WL128X_PG_MINOR_VER_OFFSET 0x0 + +#define WL127X_PG_GET_MAJOR(pg_ver) ((pg_ver & WL127X_PG_MAJOR_VER_MASK) >> \ + WL127X_PG_MAJOR_VER_OFFSET) +#define WL127X_PG_GET_MINOR(pg_ver) ((pg_ver & WL127X_PG_MINOR_VER_MASK) >> \ + WL127X_PG_MINOR_VER_OFFSET) +#define WL128X_PG_GET_MAJOR(pg_ver) ((pg_ver & WL128X_PG_MAJOR_VER_MASK) >> \ + WL128X_PG_MAJOR_VER_OFFSET) +#define WL128X_PG_GET_MINOR(pg_ver) ((pg_ver & WL128X_PG_MINOR_VER_MASK) >> \ + WL128X_PG_MINOR_VER_OFFSET) + +#define WL12XX_REG_FUSE_BD_ADDR_1 0x00310eb4 +#define WL12XX_REG_FUSE_BD_ADDR_2 0x00310eb8 + +#endif diff --git a/trunk/drivers/net/wireless/ti/wl12xx/wl12xx.h b/trunk/drivers/net/wireless/ti/wl12xx/wl12xx.h new file mode 100644 index 000000000000..74cd332e23ef --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wl12xx/wl12xx.h @@ -0,0 +1,31 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2011 Texas Instruments 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_PRIV_H__ +#define __WL12XX_PRIV_H__ + +#include "conf.h" + +struct wl12xx_priv { + struct wl12xx_priv_conf conf; +}; + +#endif /* __WL12XX_PRIV_H__ */ diff --git a/trunk/drivers/net/wireless/ti/wlcore/Kconfig b/trunk/drivers/net/wireless/ti/wlcore/Kconfig new file mode 100644 index 000000000000..9d04c38938bc --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wlcore/Kconfig @@ -0,0 +1,41 @@ +config WLCORE + tristate "TI wlcore support" + depends on WL_TI && GENERIC_HARDIRQS + depends on INET + select FW_LOADER + ---help--- + This module contains the main code for TI WLAN chips. It abstracts + hardware-specific differences among different chipset families. + Each chipset family needs to implement its own lower-level module + that will depend on this module for the common code. + + If you choose to build a module, it will be called wlcore. Say N if + unsure. + +config WLCORE_SPI + tristate "TI wlcore SPI support" + depends on WLCORE && SPI_MASTER + select CRC7 + ---help--- + This module adds support for the SPI interface of adapters using + TI WLAN chipsets. Select this if your platform is using + the SPI bus. + + If you choose to build a module, it'll be called wlcore_spi. + Say N if unsure. + +config WLCORE_SDIO + tristate "TI wlcore SDIO support" + depends on WLCORE && MMC + ---help--- + This module adds support for the SDIO interface of adapters using + TI WLAN chipsets. Select this if your platform is using + the SDIO bus. + + If you choose to build a module, it'll be called wlcore_sdio. + Say N if unsure. + +config WL12XX_PLATFORM_DATA + bool + depends on WLCORE_SDIO != n || WL1251_SDIO != n + default y diff --git a/trunk/drivers/net/wireless/ti/wlcore/Makefile b/trunk/drivers/net/wireless/ti/wlcore/Makefile new file mode 100644 index 000000000000..d9fba9e32130 --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wlcore/Makefile @@ -0,0 +1,15 @@ +wlcore-objs = main.o cmd.o io.o event.o tx.o rx.o ps.o acx.o \ + boot.o init.o debugfs.o scan.o + +wlcore_spi-objs = spi.o +wlcore_sdio-objs = sdio.o + +wlcore-$(CONFIG_NL80211_TESTMODE) += testmode.o +obj-$(CONFIG_WLCORE) += wlcore.o +obj-$(CONFIG_WLCORE_SPI) += wlcore_spi.o +obj-$(CONFIG_WLCORE_SDIO) += wlcore_sdio.o + +# small builtin driver bit +obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o + +ccflags-y += -D__CHECK_ENDIAN__ diff --git a/trunk/drivers/net/wireless/ti/wlcore/acx.c b/trunk/drivers/net/wireless/ti/wlcore/acx.c new file mode 100644 index 000000000000..5912541a925e --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wlcore/acx.c @@ -0,0 +1,1716 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "acx.h" + +#include +#include +#include +#include + +#include "wlcore.h" +#include "debug.h" +#include "wl12xx_80211.h" +#include "ps.h" +#include "hw_ops.h" + +int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 wake_up_event, u8 listen_interval) +{ + struct acx_wake_up_condition *wake_up; + int ret; + + wl1271_debug(DEBUG_ACX, "acx wake up conditions (wake_up_event %d listen_interval %d)", + wake_up_event, listen_interval); + + wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); + if (!wake_up) { + ret = -ENOMEM; + goto out; + } + + wake_up->role_id = wlvif->role_id; + wake_up->wake_up_event = wake_up_event; + wake_up->listen_interval = listen_interval; + + ret = wl1271_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, + wake_up, sizeof(*wake_up)); + if (ret < 0) { + wl1271_warning("could not set wake up conditions: %d", ret); + goto out; + } + +out: + kfree(wake_up); + return ret; +} + +int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth) +{ + struct acx_sleep_auth *auth; + int ret; + + wl1271_debug(DEBUG_ACX, "acx sleep auth"); + + auth = kzalloc(sizeof(*auth), GFP_KERNEL); + if (!auth) { + ret = -ENOMEM; + goto out; + } + + auth->sleep_auth = sleep_auth; + + ret = wl1271_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); + +out: + kfree(auth); + return ret; +} + +int wl1271_acx_tx_power(struct wl1271 *wl, struct wl12xx_vif *wlvif, + int power) +{ + struct acx_current_tx_power *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr %d", power); + + if (power < 0 || power > 25) + return -EINVAL; + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->role_id = wlvif->role_id; + acx->current_tx_power = power * 10; + + ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("configure of tx power failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_feature_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + struct acx_feature_config *feature; + int ret; + + wl1271_debug(DEBUG_ACX, "acx feature cfg"); + + feature = kzalloc(sizeof(*feature), GFP_KERNEL); + if (!feature) { + ret = -ENOMEM; + goto out; + } + + /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ + feature->role_id = wlvif->role_id; + feature->data_flow_options = 0; + feature->options = 0; + + ret = wl1271_cmd_configure(wl, ACX_FEATURE_CFG, + feature, sizeof(*feature)); + if (ret < 0) { + wl1271_error("Couldnt set HW encryption"); + goto out; + } + +out: + kfree(feature); + return ret; +} + +int wl1271_acx_mem_map(struct wl1271 *wl, struct acx_header *mem_map, + size_t len) +{ + int ret; + + wl1271_debug(DEBUG_ACX, "acx mem map"); + + ret = wl1271_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); + if (ret < 0) + return ret; + + return 0; +} + +int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl) +{ + struct acx_rx_msdu_lifetime *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx rx msdu life time"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->lifetime = cpu_to_le32(wl->conf.rx.rx_msdu_life_time); + ret = wl1271_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, + acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("failed to set rx msdu life time: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_slot(struct wl1271 *wl, struct wl12xx_vif *wlvif, + enum acx_slot_type slot_time) +{ + struct acx_slot *slot; + int ret; + + wl1271_debug(DEBUG_ACX, "acx slot"); + + slot = kzalloc(sizeof(*slot), GFP_KERNEL); + if (!slot) { + ret = -ENOMEM; + goto out; + } + + slot->role_id = wlvif->role_id; + slot->wone_index = STATION_WONE_INDEX; + slot->slot_time = slot_time; + + ret = wl1271_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); + if (ret < 0) { + wl1271_warning("failed to set slot time: %d", ret); + goto out; + } + +out: + kfree(slot); + return ret; +} + +int wl1271_acx_group_address_tbl(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable, void *mc_list, u32 mc_list_len) +{ + struct acx_dot11_grp_addr_tbl *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx group address tbl"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + /* MAC filtering */ + acx->role_id = wlvif->role_id; + acx->enabled = enable; + acx->num_groups = mc_list_len; + memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN); + + ret = wl1271_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, + acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("failed to set group addr table: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_service_period_timeout(struct wl1271 *wl, + struct wl12xx_vif *wlvif) +{ + struct acx_rx_timeout *rx_timeout; + int ret; + + rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL); + if (!rx_timeout) { + ret = -ENOMEM; + goto out; + } + + wl1271_debug(DEBUG_ACX, "acx service period timeout"); + + rx_timeout->role_id = wlvif->role_id; + rx_timeout->ps_poll_timeout = cpu_to_le16(wl->conf.rx.ps_poll_timeout); + rx_timeout->upsd_timeout = cpu_to_le16(wl->conf.rx.upsd_timeout); + + ret = wl1271_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, + rx_timeout, sizeof(*rx_timeout)); + if (ret < 0) { + wl1271_warning("failed to set service period timeout: %d", + ret); + goto out; + } + +out: + kfree(rx_timeout); + return ret; +} + +int wl1271_acx_rts_threshold(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u32 rts_threshold) +{ + struct acx_rts_threshold *rts; + int ret; + + /* + * If the RTS threshold is not configured or out of range, use the + * default value. + */ + if (rts_threshold > IEEE80211_MAX_RTS_THRESHOLD) + rts_threshold = wl->conf.rx.rts_threshold; + + wl1271_debug(DEBUG_ACX, "acx rts threshold: %d", rts_threshold); + + rts = kzalloc(sizeof(*rts), GFP_KERNEL); + if (!rts) { + ret = -ENOMEM; + goto out; + } + + rts->role_id = wlvif->role_id; + rts->threshold = cpu_to_le16((u16)rts_threshold); + + ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); + if (ret < 0) { + wl1271_warning("failed to set rts threshold: %d", ret); + goto out; + } + +out: + kfree(rts); + return ret; +} + +int wl1271_acx_dco_itrim_params(struct wl1271 *wl) +{ + struct acx_dco_itrim_params *dco; + struct conf_itrim_settings *c = &wl->conf.itrim; + int ret; + + wl1271_debug(DEBUG_ACX, "acx dco itrim parameters"); + + dco = kzalloc(sizeof(*dco), GFP_KERNEL); + if (!dco) { + ret = -ENOMEM; + goto out; + } + + dco->enable = c->enable; + dco->timeout = cpu_to_le32(c->timeout); + + ret = wl1271_cmd_configure(wl, ACX_SET_DCO_ITRIM_PARAMS, + dco, sizeof(*dco)); + if (ret < 0) { + wl1271_warning("failed to set dco itrim parameters: %d", ret); + goto out; + } + +out: + kfree(dco); + return ret; +} + +int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable_filter) +{ + struct acx_beacon_filter_option *beacon_filter = NULL; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx beacon filter opt"); + + if (enable_filter && + wl->conf.conn.bcn_filt_mode == CONF_BCN_FILT_MODE_DISABLED) + goto out; + + beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); + if (!beacon_filter) { + ret = -ENOMEM; + goto out; + } + + beacon_filter->role_id = wlvif->role_id; + beacon_filter->enable = enable_filter; + + /* + * When set to zero, and the filter is enabled, beacons + * without the unicast TIM bit set are dropped. + */ + beacon_filter->max_num_beacons = 0; + + ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_OPT, + beacon_filter, sizeof(*beacon_filter)); + if (ret < 0) { + wl1271_warning("failed to set beacon filter opt: %d", ret); + goto out; + } + +out: + kfree(beacon_filter); + return ret; +} + +int wl1271_acx_beacon_filter_table(struct wl1271 *wl, + struct wl12xx_vif *wlvif) +{ + struct acx_beacon_filter_ie_table *ie_table; + int i, idx = 0; + int ret; + bool vendor_spec = false; + + wl1271_debug(DEBUG_ACX, "acx beacon filter table"); + + ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL); + if (!ie_table) { + ret = -ENOMEM; + goto out; + } + + /* configure default beacon pass-through rules */ + ie_table->role_id = wlvif->role_id; + ie_table->num_ie = 0; + for (i = 0; i < wl->conf.conn.bcn_filt_ie_count; i++) { + struct conf_bcn_filt_rule *r = &(wl->conf.conn.bcn_filt_ie[i]); + ie_table->table[idx++] = r->ie; + ie_table->table[idx++] = r->rule; + + if (r->ie == WLAN_EID_VENDOR_SPECIFIC) { + /* only one vendor specific ie allowed */ + if (vendor_spec) + continue; + + /* for vendor specific rules configure the + additional fields */ + memcpy(&(ie_table->table[idx]), r->oui, + CONF_BCN_IE_OUI_LEN); + idx += CONF_BCN_IE_OUI_LEN; + ie_table->table[idx++] = r->type; + memcpy(&(ie_table->table[idx]), r->version, + CONF_BCN_IE_VER_LEN); + idx += CONF_BCN_IE_VER_LEN; + vendor_spec = true; + } + + ie_table->num_ie++; + } + + ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, + ie_table, sizeof(*ie_table)); + if (ret < 0) { + wl1271_warning("failed to set beacon filter table: %d", ret); + goto out; + } + +out: + kfree(ie_table); + return ret; +} + +#define ACX_CONN_MONIT_DISABLE_VALUE 0xffffffff + +int wl1271_acx_conn_monit_params(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable) +{ + struct acx_conn_monit_params *acx; + u32 threshold = ACX_CONN_MONIT_DISABLE_VALUE; + u32 timeout = ACX_CONN_MONIT_DISABLE_VALUE; + int ret; + + wl1271_debug(DEBUG_ACX, "acx connection monitor parameters: %s", + enable ? "enabled" : "disabled"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + if (enable) { + threshold = wl->conf.conn.synch_fail_thold; + timeout = wl->conf.conn.bss_lose_timeout; + } + + acx->role_id = wlvif->role_id; + acx->synch_fail_thold = cpu_to_le32(threshold); + acx->bss_lose_timeout = cpu_to_le32(timeout); + + ret = wl1271_cmd_configure(wl, ACX_CONN_MONIT_PARAMS, + acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("failed to set connection monitor " + "parameters: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + + +int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable) +{ + struct acx_bt_wlan_coex *pta; + int ret; + + wl1271_debug(DEBUG_ACX, "acx sg enable"); + + pta = kzalloc(sizeof(*pta), GFP_KERNEL); + if (!pta) { + ret = -ENOMEM; + goto out; + } + + if (enable) + pta->enable = wl->conf.sg.state; + else + pta->enable = CONF_SG_DISABLE; + + ret = wl1271_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); + if (ret < 0) { + wl1271_warning("failed to set softgemini enable: %d", ret); + goto out; + } + +out: + kfree(pta); + return ret; +} + +int wl12xx_acx_sg_cfg(struct wl1271 *wl) +{ + struct acx_bt_wlan_coex_param *param; + struct conf_sg_settings *c = &wl->conf.sg; + int i, ret; + + wl1271_debug(DEBUG_ACX, "acx sg cfg"); + + param = kzalloc(sizeof(*param), GFP_KERNEL); + if (!param) { + ret = -ENOMEM; + goto out; + } + + /* BT-WLAN coext parameters */ + for (i = 0; i < CONF_SG_PARAMS_MAX; i++) + param->params[i] = cpu_to_le32(c->params[i]); + param->param_idx = CONF_SG_PARAMS_ALL; + + ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); + if (ret < 0) { + wl1271_warning("failed to set sg config: %d", ret); + goto out; + } + +out: + kfree(param); + return ret; +} + +int wl1271_acx_cca_threshold(struct wl1271 *wl) +{ + struct acx_energy_detection *detection; + int ret; + + wl1271_debug(DEBUG_ACX, "acx cca threshold"); + + detection = kzalloc(sizeof(*detection), GFP_KERNEL); + if (!detection) { + ret = -ENOMEM; + goto out; + } + + detection->rx_cca_threshold = cpu_to_le16(wl->conf.rx.rx_cca_threshold); + detection->tx_energy_detection = wl->conf.tx.tx_energy_detection; + + ret = wl1271_cmd_configure(wl, ACX_CCA_THRESHOLD, + detection, sizeof(*detection)); + if (ret < 0) + wl1271_warning("failed to set cca threshold: %d", ret); + +out: + kfree(detection); + return ret; +} + +int wl1271_acx_bcn_dtim_options(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + struct acx_beacon_broadcast *bb; + int ret; + + wl1271_debug(DEBUG_ACX, "acx bcn dtim options"); + + bb = kzalloc(sizeof(*bb), GFP_KERNEL); + if (!bb) { + ret = -ENOMEM; + goto out; + } + + bb->role_id = wlvif->role_id; + bb->beacon_rx_timeout = cpu_to_le16(wl->conf.conn.beacon_rx_timeout); + bb->broadcast_timeout = cpu_to_le16(wl->conf.conn.broadcast_timeout); + bb->rx_broadcast_in_ps = wl->conf.conn.rx_broadcast_in_ps; + bb->ps_poll_threshold = wl->conf.conn.ps_poll_threshold; + + ret = wl1271_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); + if (ret < 0) { + wl1271_warning("failed to set rx config: %d", ret); + goto out; + } + +out: + kfree(bb); + return ret; +} + +int wl1271_acx_aid(struct wl1271 *wl, struct wl12xx_vif *wlvif, u16 aid) +{ + struct acx_aid *acx_aid; + int ret; + + wl1271_debug(DEBUG_ACX, "acx aid"); + + acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); + if (!acx_aid) { + ret = -ENOMEM; + goto out; + } + + acx_aid->role_id = wlvif->role_id; + acx_aid->aid = cpu_to_le16(aid); + + ret = wl1271_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); + if (ret < 0) { + wl1271_warning("failed to set aid: %d", ret); + goto out; + } + +out: + kfree(acx_aid); + return ret; +} + +int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask) +{ + struct acx_event_mask *mask; + int ret; + + wl1271_debug(DEBUG_ACX, "acx event mbox mask"); + + mask = kzalloc(sizeof(*mask), GFP_KERNEL); + if (!mask) { + ret = -ENOMEM; + goto out; + } + + /* high event mask is unused */ + mask->high_event_mask = cpu_to_le32(0xffffffff); + mask->event_mask = cpu_to_le32(event_mask); + + ret = wl1271_cmd_configure(wl, ACX_EVENT_MBOX_MASK, + mask, sizeof(*mask)); + if (ret < 0) { + wl1271_warning("failed to set acx_event_mbox_mask: %d", ret); + goto out; + } + +out: + kfree(mask); + return ret; +} + +int wl1271_acx_set_preamble(struct wl1271 *wl, struct wl12xx_vif *wlvif, + enum acx_preamble_type preamble) +{ + struct acx_preamble *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx_set_preamble"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->role_id = wlvif->role_id; + acx->preamble = preamble; + + ret = wl1271_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of preamble failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_cts_protect(struct wl1271 *wl, struct wl12xx_vif *wlvif, + enum acx_ctsprotect_type ctsprotect) +{ + struct acx_ctsprotect *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx_set_ctsprotect"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->role_id = wlvif->role_id; + acx->ctsprotect = ctsprotect; + + ret = wl1271_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of ctsprotect failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats) +{ + int ret; + + wl1271_debug(DEBUG_ACX, "acx statistics"); + + ret = wl1271_cmd_interrogate(wl, ACX_STATISTICS, stats, + sizeof(*stats)); + if (ret < 0) { + wl1271_warning("acx statistics failed: %d", ret); + return -ENOMEM; + } + + return 0; +} + +int wl1271_acx_sta_rate_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + struct acx_rate_policy *acx; + struct conf_tx_rate_class *c = &wl->conf.tx.sta_rc_conf; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx rate policies"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + wl1271_debug(DEBUG_ACX, "basic_rate: 0x%x, full_rate: 0x%x", + wlvif->basic_rate, wlvif->rate_set); + + /* configure one basic rate class */ + acx->rate_policy_idx = cpu_to_le32(wlvif->sta.basic_rate_idx); + acx->rate_policy.enabled_rates = cpu_to_le32(wlvif->basic_rate); + acx->rate_policy.short_retry_limit = c->short_retry_limit; + acx->rate_policy.long_retry_limit = c->long_retry_limit; + acx->rate_policy.aflags = c->aflags; + + ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of rate policies failed: %d", ret); + goto out; + } + + /* configure one AP supported rate class */ + acx->rate_policy_idx = cpu_to_le32(wlvif->sta.ap_rate_idx); + + /* the AP policy is HW specific */ + acx->rate_policy.enabled_rates = + cpu_to_le32(wlcore_hw_sta_get_ap_rate_mask(wl, wlvif)); + acx->rate_policy.short_retry_limit = c->short_retry_limit; + acx->rate_policy.long_retry_limit = c->long_retry_limit; + acx->rate_policy.aflags = c->aflags; + + ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of rate policies failed: %d", ret); + goto out; + } + + /* + * configure one rate class for basic p2p operations. + * (p2p packets should always go out with OFDM rates, even + * if we are currently connected to 11b AP) + */ + acx->rate_policy_idx = cpu_to_le32(wlvif->sta.p2p_rate_idx); + acx->rate_policy.enabled_rates = + cpu_to_le32(CONF_TX_RATE_MASK_BASIC_P2P); + acx->rate_policy.short_retry_limit = c->short_retry_limit; + acx->rate_policy.long_retry_limit = c->long_retry_limit; + acx->rate_policy.aflags = c->aflags; + + ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of rate policies failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c, + u8 idx) +{ + struct acx_rate_policy *acx; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx ap rate policy %d rates 0x%x", + idx, c->enabled_rates); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->rate_policy.enabled_rates = cpu_to_le32(c->enabled_rates); + acx->rate_policy.short_retry_limit = c->short_retry_limit; + acx->rate_policy.long_retry_limit = c->long_retry_limit; + acx->rate_policy.aflags = c->aflags; + + acx->rate_policy_idx = cpu_to_le32(idx); + + ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of ap rate policy failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_ac_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 ac, u8 cw_min, u16 cw_max, u8 aifsn, u16 txop) +{ + struct acx_ac_cfg *acx; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d " + "aifs %d txop %d", ac, cw_min, cw_max, aifsn, txop); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->role_id = wlvif->role_id; + acx->ac = ac; + acx->cw_min = cw_min; + acx->cw_max = cpu_to_le16(cw_max); + acx->aifsn = aifsn; + acx->tx_op_limit = cpu_to_le16(txop); + + ret = wl1271_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx ac cfg failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_tid_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 queue_id, u8 channel_type, + u8 tsid, u8 ps_scheme, u8 ack_policy, + u32 apsd_conf0, u32 apsd_conf1) +{ + struct acx_tid_config *acx; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx tid config"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->role_id = wlvif->role_id; + acx->queue_id = queue_id; + acx->channel_type = channel_type; + acx->tsid = tsid; + acx->ps_scheme = ps_scheme; + acx->ack_policy = ack_policy; + acx->apsd_conf[0] = cpu_to_le32(apsd_conf0); + acx->apsd_conf[1] = cpu_to_le32(apsd_conf1); + + ret = wl1271_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of tid config failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold) +{ + struct acx_frag_threshold *acx; + int ret = 0; + + /* + * If the fragmentation is not configured or out of range, use the + * default value. + */ + if (frag_threshold > IEEE80211_MAX_FRAG_THRESHOLD) + frag_threshold = wl->conf.tx.frag_threshold; + + wl1271_debug(DEBUG_ACX, "acx frag threshold: %d", frag_threshold); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->frag_threshold = cpu_to_le16((u16)frag_threshold); + ret = wl1271_cmd_configure(wl, ACX_FRAG_CFG, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of frag threshold failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_tx_config_options(struct wl1271 *wl) +{ + struct acx_tx_config_options *acx; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx tx config options"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->tx_compl_timeout = cpu_to_le16(wl->conf.tx.tx_compl_timeout); + acx->tx_compl_threshold = cpu_to_le16(wl->conf.tx.tx_compl_threshold); + ret = wl1271_cmd_configure(wl, ACX_TX_CONFIG_OPT, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of tx options failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl12xx_acx_mem_cfg(struct wl1271 *wl) +{ + struct wl12xx_acx_config_memory *mem_conf; + struct conf_memory_settings *mem; + int ret; + + wl1271_debug(DEBUG_ACX, "wl1271 mem cfg"); + + mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); + if (!mem_conf) { + ret = -ENOMEM; + goto out; + } + + mem = &wl->conf.mem; + + /* memory config */ + mem_conf->num_stations = mem->num_stations; + mem_conf->rx_mem_block_num = mem->rx_block_num; + mem_conf->tx_min_mem_block_num = mem->tx_min_block_num; + mem_conf->num_ssid_profiles = mem->ssid_profiles; + mem_conf->total_tx_descriptors = cpu_to_le32(wl->num_tx_desc); + mem_conf->dyn_mem_enable = mem->dynamic_memory; + mem_conf->tx_free_req = mem->min_req_tx_blocks; + mem_conf->rx_free_req = mem->min_req_rx_blocks; + mem_conf->tx_min = mem->tx_min; + mem_conf->fwlog_blocks = wl->conf.fwlog.mem_blocks; + + ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf, + sizeof(*mem_conf)); + if (ret < 0) { + wl1271_warning("wl1271 mem config failed: %d", ret); + goto out; + } + +out: + kfree(mem_conf); + return ret; +} + +int wl1271_acx_init_mem_config(struct wl1271 *wl) +{ + int ret; + + wl->target_mem_map = kzalloc(sizeof(struct wl1271_acx_mem_map), + GFP_KERNEL); + if (!wl->target_mem_map) { + wl1271_error("couldn't allocate target memory map"); + return -ENOMEM; + } + + /* we now ask for the firmware built memory map */ + ret = wl1271_acx_mem_map(wl, (void *)wl->target_mem_map, + sizeof(struct wl1271_acx_mem_map)); + if (ret < 0) { + wl1271_error("couldn't retrieve firmware memory map"); + kfree(wl->target_mem_map); + wl->target_mem_map = NULL; + return ret; + } + + /* initialize TX block book keeping */ + wl->tx_blocks_available = + le32_to_cpu(wl->target_mem_map->num_tx_mem_blocks); + wl1271_debug(DEBUG_TX, "available tx blocks: %d", + wl->tx_blocks_available); + + return 0; +} + +int wl1271_acx_init_rx_interrupt(struct wl1271 *wl) +{ + struct wl1271_acx_rx_config_opt *rx_conf; + int ret; + + wl1271_debug(DEBUG_ACX, "wl1271 rx interrupt config"); + + rx_conf = kzalloc(sizeof(*rx_conf), GFP_KERNEL); + if (!rx_conf) { + ret = -ENOMEM; + goto out; + } + + rx_conf->threshold = cpu_to_le16(wl->conf.rx.irq_pkt_threshold); + rx_conf->timeout = cpu_to_le16(wl->conf.rx.irq_timeout); + rx_conf->mblk_threshold = cpu_to_le16(wl->conf.rx.irq_blk_threshold); + rx_conf->queue_type = wl->conf.rx.queue_type; + + ret = wl1271_cmd_configure(wl, ACX_RX_CONFIG_OPT, rx_conf, + sizeof(*rx_conf)); + if (ret < 0) { + wl1271_warning("wl1271 rx config opt failed: %d", ret); + goto out; + } + +out: + kfree(rx_conf); + return ret; +} + +int wl1271_acx_bet_enable(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable) +{ + struct wl1271_acx_bet_enable *acx = NULL; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx bet enable"); + + if (enable && wl->conf.conn.bet_enable == CONF_BET_MODE_DISABLE) + goto out; + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->role_id = wlvif->role_id; + acx->enable = enable ? CONF_BET_MODE_ENABLE : CONF_BET_MODE_DISABLE; + acx->max_consecutive = wl->conf.conn.bet_max_consecutive; + + ret = wl1271_cmd_configure(wl, ACX_BET_ENABLE, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx bet enable failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_arp_ip_filter(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 enable, __be32 address) +{ + struct wl1271_acx_arp_filter *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx arp ip filter, enable: %d", enable); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->role_id = wlvif->role_id; + acx->version = ACX_IPV4_VERSION; + acx->enable = enable; + + if (enable) + memcpy(acx->address, &address, ACX_IPV4_ADDR_SIZE); + + ret = wl1271_cmd_configure(wl, ACX_ARP_IP_FILTER, + acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("failed to set arp ip filter: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_pm_config(struct wl1271 *wl) +{ + struct wl1271_acx_pm_config *acx = NULL; + struct conf_pm_config_settings *c = &wl->conf.pm_config; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx pm config"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->host_clk_settling_time = cpu_to_le32(c->host_clk_settling_time); + acx->host_fast_wakeup_support = c->host_fast_wakeup_support; + + ret = wl1271_cmd_configure(wl, ACX_PM_CONFIG, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx pm config failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_keep_alive_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable) +{ + struct wl1271_acx_keep_alive_mode *acx = NULL; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx keep alive mode: %d", enable); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->role_id = wlvif->role_id; + acx->enabled = enable; + + ret = wl1271_cmd_configure(wl, ACX_KEEP_ALIVE_MODE, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx keep alive mode failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_keep_alive_config(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 index, u8 tpl_valid) +{ + struct wl1271_acx_keep_alive_config *acx = NULL; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx keep alive config"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->role_id = wlvif->role_id; + acx->period = cpu_to_le32(wl->conf.conn.keep_alive_interval); + acx->index = index; + acx->tpl_validation = tpl_valid; + acx->trigger = ACX_KEEP_ALIVE_NO_TX; + + ret = wl1271_cmd_configure(wl, ACX_SET_KEEP_ALIVE_CONFIG, + acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx keep alive config failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable, s16 thold, u8 hyst) +{ + struct wl1271_acx_rssi_snr_trigger *acx = NULL; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx rssi snr trigger"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + wlvif->last_rssi_event = -1; + + acx->role_id = wlvif->role_id; + acx->pacing = cpu_to_le16(wl->conf.roam_trigger.trigger_pacing); + acx->metric = WL1271_ACX_TRIG_METRIC_RSSI_BEACON; + acx->type = WL1271_ACX_TRIG_TYPE_EDGE; + if (enable) + acx->enable = WL1271_ACX_TRIG_ENABLE; + else + acx->enable = WL1271_ACX_TRIG_DISABLE; + + acx->index = WL1271_ACX_TRIG_IDX_RSSI; + acx->dir = WL1271_ACX_TRIG_DIR_BIDIR; + acx->threshold = cpu_to_le16(thold); + acx->hysteresis = hyst; + + ret = wl1271_cmd_configure(wl, ACX_RSSI_SNR_TRIGGER, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx rssi snr trigger setting failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl, + struct wl12xx_vif *wlvif) +{ + struct wl1271_acx_rssi_snr_avg_weights *acx = NULL; + struct conf_roam_trigger_settings *c = &wl->conf.roam_trigger; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx rssi snr avg weights"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->role_id = wlvif->role_id; + acx->rssi_beacon = c->avg_weight_rssi_beacon; + acx->rssi_data = c->avg_weight_rssi_data; + acx->snr_beacon = c->avg_weight_snr_beacon; + acx->snr_data = c->avg_weight_snr_data; + + ret = wl1271_cmd_configure(wl, ACX_RSSI_SNR_WEIGHTS, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx rssi snr trigger weights failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, + struct ieee80211_sta_ht_cap *ht_cap, + bool allow_ht_operation, u8 hlid) +{ + struct wl1271_acx_ht_capabilities *acx; + int ret = 0; + u32 ht_capabilites = 0; + + wl1271_debug(DEBUG_ACX, "acx ht capabilities setting " + "sta supp: %d sta cap: %d", ht_cap->ht_supported, + ht_cap->cap); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + if (allow_ht_operation && ht_cap->ht_supported) { + /* no need to translate capabilities - use the spec values */ + ht_capabilites = ht_cap->cap; + + /* + * this bit is not employed by the spec but only by FW to + * indicate peer HT support + */ + ht_capabilites |= WL12XX_HT_CAP_HT_OPERATION; + + /* get data from A-MPDU parameters field */ + acx->ampdu_max_length = ht_cap->ampdu_factor; + acx->ampdu_min_spacing = ht_cap->ampdu_density; + } + + acx->hlid = hlid; + acx->ht_capabilites = cpu_to_le32(ht_capabilites); + + ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx ht capabilities setting failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_set_ht_information(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + u16 ht_operation_mode) +{ + struct wl1271_acx_ht_information *acx; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx ht information setting"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->role_id = wlvif->role_id; + acx->ht_protection = + (u8)(ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION); + acx->rifs_mode = 0; + acx->gf_protection = + !!(ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); + acx->ht_tx_burst_limit = 0; + acx->dual_cts_protection = 0; + + ret = wl1271_cmd_configure(wl, ACX_HT_BSS_OPERATION, acx, sizeof(*acx)); + + if (ret < 0) { + wl1271_warning("acx ht information setting failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +/* Configure BA session initiator/receiver parameters setting in the FW. */ +int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl, + struct wl12xx_vif *wlvif) +{ + struct wl1271_acx_ba_initiator_policy *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx ba initiator policy"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + /* set for the current role */ + acx->role_id = wlvif->role_id; + acx->tid_bitmap = wl->conf.ht.tx_ba_tid_bitmap; + acx->win_size = wl->conf.ht.tx_ba_win_size; + acx->inactivity_timeout = wl->conf.ht.inactivity_timeout; + + ret = wl1271_cmd_configure(wl, + ACX_BA_SESSION_INIT_POLICY, + acx, + sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx ba initiator policy failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +/* setup BA session receiver setting in the FW. */ +int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, + u16 ssn, bool enable, u8 peer_hlid) +{ + struct wl1271_acx_ba_receiver_setup *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx ba receiver session setting"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->hlid = peer_hlid; + acx->tid = tid_index; + acx->enable = enable; + acx->win_size = wl->conf.ht.rx_ba_win_size; + acx->ssn = ssn; + + ret = wl1271_cmd_configure(wl, ACX_BA_SESSION_RX_SETUP, acx, + sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx ba receiver session failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl12xx_acx_tsf_info(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u64 *mactime) +{ + struct wl12xx_acx_fw_tsf_information *tsf_info; + int ret; + + tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL); + if (!tsf_info) { + ret = -ENOMEM; + goto out; + } + + tsf_info->role_id = wlvif->role_id; + + ret = wl1271_cmd_interrogate(wl, ACX_TSF_INFO, + tsf_info, sizeof(*tsf_info)); + if (ret < 0) { + wl1271_warning("acx tsf info interrogate failed"); + goto out; + } + + *mactime = le32_to_cpu(tsf_info->current_tsf_low) | + ((u64) le32_to_cpu(tsf_info->current_tsf_high) << 32); + +out: + kfree(tsf_info); + return ret; +} + +int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable) +{ + struct wl1271_acx_ps_rx_streaming *rx_streaming; + u32 conf_queues, enable_queues; + int i, ret = 0; + + wl1271_debug(DEBUG_ACX, "acx ps rx streaming"); + + rx_streaming = kzalloc(sizeof(*rx_streaming), GFP_KERNEL); + if (!rx_streaming) { + ret = -ENOMEM; + goto out; + } + + conf_queues = wl->conf.rx_streaming.queues; + if (enable) + enable_queues = conf_queues; + else + enable_queues = 0; + + for (i = 0; i < 8; i++) { + /* + * Skip non-changed queues, to avoid redundant acxs. + * this check assumes conf.rx_streaming.queues can't + * be changed while rx_streaming is enabled. + */ + if (!(conf_queues & BIT(i))) + continue; + + rx_streaming->role_id = wlvif->role_id; + rx_streaming->tid = i; + rx_streaming->enable = enable_queues & BIT(i); + rx_streaming->period = wl->conf.rx_streaming.interval; + rx_streaming->timeout = wl->conf.rx_streaming.interval; + + ret = wl1271_cmd_configure(wl, ACX_PS_RX_STREAMING, + rx_streaming, + sizeof(*rx_streaming)); + if (ret < 0) { + wl1271_warning("acx ps rx streaming failed: %d", ret); + goto out; + } + } +out: + kfree(rx_streaming); + return ret; +} + +int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + struct wl1271_acx_ap_max_tx_retry *acx = NULL; + int ret; + + wl1271_debug(DEBUG_ACX, "acx ap max tx retry"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) + return -ENOMEM; + + acx->role_id = wlvif->role_id; + acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries); + + ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx ap max tx retry failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl12xx_acx_config_ps(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + struct wl1271_acx_config_ps *config_ps; + int ret; + + wl1271_debug(DEBUG_ACX, "acx config ps"); + + config_ps = kzalloc(sizeof(*config_ps), GFP_KERNEL); + if (!config_ps) { + ret = -ENOMEM; + goto out; + } + + config_ps->exit_retries = wl->conf.conn.psm_exit_retries; + config_ps->enter_retries = wl->conf.conn.psm_entry_retries; + config_ps->null_data_rate = cpu_to_le32(wlvif->basic_rate); + + ret = wl1271_cmd_configure(wl, ACX_CONFIG_PS, config_ps, + sizeof(*config_ps)); + + if (ret < 0) { + wl1271_warning("acx config ps failed: %d", ret); + goto out; + } + +out: + kfree(config_ps); + return ret; +} + +int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr) +{ + struct wl1271_acx_inconnection_sta *acx = NULL; + int ret; + + wl1271_debug(DEBUG_ACX, "acx set inconnaction sta %pM", addr); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) + return -ENOMEM; + + memcpy(acx->addr, addr, ETH_ALEN); + + ret = wl1271_cmd_configure(wl, ACX_UPDATE_INCONNECTION_STA_LIST, + acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx set inconnaction sta failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_fm_coex(struct wl1271 *wl) +{ + struct wl1271_acx_fm_coex *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx fm coex setting"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->enable = wl->conf.fm_coex.enable; + acx->swallow_period = wl->conf.fm_coex.swallow_period; + acx->n_divider_fref_set_1 = wl->conf.fm_coex.n_divider_fref_set_1; + acx->n_divider_fref_set_2 = wl->conf.fm_coex.n_divider_fref_set_2; + acx->m_divider_fref_set_1 = + cpu_to_le16(wl->conf.fm_coex.m_divider_fref_set_1); + acx->m_divider_fref_set_2 = + cpu_to_le16(wl->conf.fm_coex.m_divider_fref_set_2); + acx->coex_pll_stabilization_time = + cpu_to_le32(wl->conf.fm_coex.coex_pll_stabilization_time); + acx->ldo_stabilization_time = + cpu_to_le16(wl->conf.fm_coex.ldo_stabilization_time); + acx->fm_disturbed_band_margin = + wl->conf.fm_coex.fm_disturbed_band_margin; + acx->swallow_clk_diff = wl->conf.fm_coex.swallow_clk_diff; + + ret = wl1271_cmd_configure(wl, ACX_FM_COEX_CFG, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx fm coex setting failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl) +{ + struct wl12xx_acx_set_rate_mgmt_params *acx = NULL; + struct conf_rate_policy_settings *conf = &wl->conf.rate; + int ret; + + wl1271_debug(DEBUG_ACX, "acx set rate mgmt params"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) + return -ENOMEM; + + acx->index = ACX_RATE_MGMT_ALL_PARAMS; + acx->rate_retry_score = cpu_to_le16(conf->rate_retry_score); + acx->per_add = cpu_to_le16(conf->per_add); + acx->per_th1 = cpu_to_le16(conf->per_th1); + acx->per_th2 = cpu_to_le16(conf->per_th2); + acx->max_per = cpu_to_le16(conf->max_per); + acx->inverse_curiosity_factor = conf->inverse_curiosity_factor; + acx->tx_fail_low_th = conf->tx_fail_low_th; + acx->tx_fail_high_th = conf->tx_fail_high_th; + acx->per_alpha_shift = conf->per_alpha_shift; + acx->per_add_shift = conf->per_add_shift; + acx->per_beta1_shift = conf->per_beta1_shift; + acx->per_beta2_shift = conf->per_beta2_shift; + acx->rate_check_up = conf->rate_check_up; + acx->rate_check_down = conf->rate_check_down; + memcpy(acx->rate_retry_policy, conf->rate_retry_policy, + sizeof(acx->rate_retry_policy)); + + ret = wl1271_cmd_configure(wl, ACX_SET_RATE_MGMT_PARAMS, + acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx set rate mgmt params failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl12xx_acx_config_hangover(struct wl1271 *wl) +{ + struct wl12xx_acx_config_hangover *acx; + struct conf_hangover_settings *conf = &wl->conf.hangover; + int ret; + + wl1271_debug(DEBUG_ACX, "acx config hangover"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->recover_time = cpu_to_le32(conf->recover_time); + acx->hangover_period = conf->hangover_period; + acx->dynamic_mode = conf->dynamic_mode; + acx->early_termination_mode = conf->early_termination_mode; + acx->max_period = conf->max_period; + acx->min_period = conf->min_period; + acx->increase_delta = conf->increase_delta; + acx->decrease_delta = conf->decrease_delta; + acx->quiet_time = conf->quiet_time; + acx->increase_time = conf->increase_time; + acx->window_size = acx->window_size; + + ret = wl1271_cmd_configure(wl, ACX_CONFIG_HANGOVER, acx, + sizeof(*acx)); + + if (ret < 0) { + wl1271_warning("acx config hangover failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; + +} diff --git a/trunk/drivers/net/wireless/ti/wlcore/acx.h b/trunk/drivers/net/wireless/ti/wlcore/acx.h new file mode 100644 index 000000000000..b2f88831b7a9 --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wlcore/acx.h @@ -0,0 +1,1308 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2008-2010 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __ACX_H__ +#define __ACX_H__ + +#include "wlcore.h" +#include "cmd.h" + +/************************************************************************* + + Host Interrupt Register (WiLink -> Host) + +**************************************************************************/ +/* HW Initiated interrupt Watchdog timer expiration */ +#define WL1271_ACX_INTR_WATCHDOG BIT(0) +/* Init sequence is done (masked interrupt, detection through polling only ) */ +#define WL1271_ACX_INTR_INIT_COMPLETE BIT(1) +/* Event was entered to Event MBOX #A*/ +#define WL1271_ACX_INTR_EVENT_A BIT(2) +/* Event was entered to Event MBOX #B*/ +#define WL1271_ACX_INTR_EVENT_B BIT(3) +/* Command processing completion*/ +#define WL1271_ACX_INTR_CMD_COMPLETE BIT(4) +/* Signaling the host on HW wakeup */ +#define WL1271_ACX_INTR_HW_AVAILABLE BIT(5) +/* The MISC bit is used for aggregation of RX, TxComplete and TX rate update */ +#define WL1271_ACX_INTR_DATA BIT(6) +/* Trace message on MBOX #A */ +#define WL1271_ACX_INTR_TRACE_A BIT(7) +/* Trace message on MBOX #B */ +#define WL1271_ACX_INTR_TRACE_B BIT(8) + +#define WL1271_ACX_INTR_ALL 0xFFFFFFFF +#define WL1271_ACX_ALL_EVENTS_VECTOR (WL1271_ACX_INTR_WATCHDOG | \ + WL1271_ACX_INTR_INIT_COMPLETE | \ + WL1271_ACX_INTR_EVENT_A | \ + WL1271_ACX_INTR_EVENT_B | \ + WL1271_ACX_INTR_CMD_COMPLETE | \ + WL1271_ACX_INTR_HW_AVAILABLE | \ + WL1271_ACX_INTR_DATA) + +#define WL1271_INTR_MASK (WL1271_ACX_INTR_WATCHDOG | \ + WL1271_ACX_INTR_EVENT_A | \ + WL1271_ACX_INTR_EVENT_B | \ + WL1271_ACX_INTR_HW_AVAILABLE | \ + WL1271_ACX_INTR_DATA) + +/* Target's information element */ +struct acx_header { + struct wl1271_cmd_header cmd; + + /* acx (or information element) header */ + __le16 id; + + /* payload length (not including headers */ + __le16 len; +} __packed; + +struct acx_error_counter { + struct acx_header header; + + /* The number of PLCP errors since the last time this */ + /* information element was interrogated. This field is */ + /* automatically cleared when it is interrogated.*/ + __le32 PLCP_error; + + /* The number of FCS errors since the last time this */ + /* information element was interrogated. This field is */ + /* automatically cleared when it is interrogated.*/ + __le32 FCS_error; + + /* The number of MPDUs without PLCP header errors received*/ + /* since the last time this information element was interrogated. */ + /* This field is automatically cleared when it is interrogated.*/ + __le32 valid_frame; + + /* the number of missed sequence numbers in the squentially */ + /* values of frames seq numbers */ + __le32 seq_num_miss; +} __packed; + +enum wl12xx_role { + WL1271_ROLE_STA = 0, + WL1271_ROLE_IBSS, + WL1271_ROLE_AP, + WL1271_ROLE_DEVICE, + WL1271_ROLE_P2P_CL, + WL1271_ROLE_P2P_GO, + + WL12XX_INVALID_ROLE_TYPE = 0xff +}; + +enum wl1271_psm_mode { + /* Active mode */ + WL1271_PSM_CAM = 0, + + /* Power save mode */ + WL1271_PSM_PS = 1, + + /* Extreme low power */ + WL1271_PSM_ELP = 2, +}; + +struct acx_sleep_auth { + struct acx_header header; + + /* The sleep level authorization of the device. */ + /* 0 - Always active*/ + /* 1 - Power down mode: light / fast sleep*/ + /* 2 - ELP mode: Deep / Max sleep*/ + u8 sleep_auth; + u8 padding[3]; +} __packed; + +enum { + HOSTIF_PCI_MASTER_HOST_INDIRECT, + HOSTIF_PCI_MASTER_HOST_DIRECT, + HOSTIF_SLAVE, + HOSTIF_PKT_RING, + HOSTIF_DONTCARE = 0xFF +}; + +#define DEFAULT_UCAST_PRIORITY 0 +#define DEFAULT_RX_Q_PRIORITY 0 +#define DEFAULT_RXQ_PRIORITY 0 /* low 0 .. 15 high */ +#define DEFAULT_RXQ_TYPE 0x07 /* All frames, Data/Ctrl/Mgmt */ +#define TRACE_BUFFER_MAX_SIZE 256 + +#define DP_RX_PACKET_RING_CHUNK_SIZE 1600 +#define DP_TX_PACKET_RING_CHUNK_SIZE 1600 +#define DP_RX_PACKET_RING_CHUNK_NUM 2 +#define DP_TX_PACKET_RING_CHUNK_NUM 2 +#define DP_TX_COMPLETE_TIME_OUT 20 + +#define TX_MSDU_LIFETIME_MIN 0 +#define TX_MSDU_LIFETIME_MAX 3000 +#define TX_MSDU_LIFETIME_DEF 512 +#define RX_MSDU_LIFETIME_MIN 0 +#define RX_MSDU_LIFETIME_MAX 0xFFFFFFFF +#define RX_MSDU_LIFETIME_DEF 512000 + +struct acx_rx_msdu_lifetime { + struct acx_header header; + + /* + * The maximum amount of time, in TU, before the + * firmware discards the MSDU. + */ + __le32 lifetime; +} __packed; + +enum acx_slot_type { + SLOT_TIME_LONG = 0, + SLOT_TIME_SHORT = 1, + DEFAULT_SLOT_TIME = SLOT_TIME_SHORT, + MAX_SLOT_TIMES = 0xFF +}; + +#define STATION_WONE_INDEX 0 + +struct acx_slot { + struct acx_header header; + + u8 role_id; + u8 wone_index; /* Reserved */ + u8 slot_time; + u8 reserved[5]; +} __packed; + + +#define ACX_MC_ADDRESS_GROUP_MAX (8) +#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ACX_MC_ADDRESS_GROUP_MAX) + +struct acx_dot11_grp_addr_tbl { + struct acx_header header; + + u8 role_id; + u8 enabled; + u8 num_groups; + u8 pad[1]; + u8 mac_table[ADDRESS_GROUP_MAX_LEN]; +} __packed; + +struct acx_rx_timeout { + struct acx_header header; + + u8 role_id; + u8 reserved; + __le16 ps_poll_timeout; + __le16 upsd_timeout; + u8 padding[2]; +} __packed; + +struct acx_rts_threshold { + struct acx_header header; + + u8 role_id; + u8 reserved; + __le16 threshold; +} __packed; + +struct acx_beacon_filter_option { + struct acx_header header; + + u8 role_id; + u8 enable; + /* + * The number of beacons without the unicast TIM + * bit set that the firmware buffers before + * signaling the host about ready frames. + * When set to 0 and the filter is enabled, beacons + * without the unicast TIM bit set are dropped. + */ + u8 max_num_beacons; + u8 pad[1]; +} __packed; + +/* + * ACXBeaconFilterEntry (not 221) + * Byte Offset Size (Bytes) Definition + * =========== ============ ========== + * 0 1 IE identifier + * 1 1 Treatment bit mask + * + * ACXBeaconFilterEntry (221) + * Byte Offset Size (Bytes) Definition + * =========== ============ ========== + * 0 1 IE identifier + * 1 1 Treatment bit mask + * 2 3 OUI + * 5 1 Type + * 6 2 Version + * + * + * Treatment bit mask - The information element handling: + * bit 0 - The information element is compared and transferred + * in case of change. + * bit 1 - The information element is transferred to the host + * with each appearance or disappearance. + * Note that both bits can be set at the same time. + */ +#define BEACON_FILTER_TABLE_MAX_IE_NUM (32) +#define BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM (6) +#define BEACON_FILTER_TABLE_IE_ENTRY_SIZE (2) +#define BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE (6) +#define BEACON_FILTER_TABLE_MAX_SIZE ((BEACON_FILTER_TABLE_MAX_IE_NUM * \ + BEACON_FILTER_TABLE_IE_ENTRY_SIZE) + \ + (BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \ + BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE)) + +struct acx_beacon_filter_ie_table { + struct acx_header header; + + u8 role_id; + u8 num_ie; + u8 pad[2]; + u8 table[BEACON_FILTER_TABLE_MAX_SIZE]; +} __packed; + +struct acx_conn_monit_params { + struct acx_header header; + + u8 role_id; + u8 padding[3]; + __le32 synch_fail_thold; /* number of beacons missed */ + __le32 bss_lose_timeout; /* number of TU's from synch fail */ +} __packed; + +struct acx_bt_wlan_coex { + struct acx_header header; + + u8 enable; + u8 pad[3]; +} __packed; + +struct acx_bt_wlan_coex_param { + struct acx_header header; + + __le32 params[CONF_SG_PARAMS_MAX]; + u8 param_idx; + u8 padding[3]; +} __packed; + +struct acx_dco_itrim_params { + struct acx_header header; + + u8 enable; + u8 padding[3]; + __le32 timeout; +} __packed; + +struct acx_energy_detection { + struct acx_header header; + + /* The RX Clear Channel Assessment threshold in the PHY */ + __le16 rx_cca_threshold; + u8 tx_energy_detection; + u8 pad; +} __packed; + +struct acx_beacon_broadcast { + struct acx_header header; + + u8 role_id; + /* Enables receiving of broadcast packets in PS mode */ + u8 rx_broadcast_in_ps; + + __le16 beacon_rx_timeout; + __le16 broadcast_timeout; + + /* Consecutive PS Poll failures before updating the host */ + u8 ps_poll_threshold; + u8 pad[1]; +} __packed; + +struct acx_event_mask { + struct acx_header header; + + __le32 event_mask; + __le32 high_event_mask; /* Unused */ +} __packed; + +#define SCAN_PASSIVE BIT(0) +#define SCAN_5GHZ_BAND BIT(1) +#define SCAN_TRIGGERED BIT(2) +#define SCAN_PRIORITY_HIGH BIT(3) + +/* When set, disable HW encryption */ +#define DF_ENCRYPTION_DISABLE 0x01 +#define DF_SNIFF_MODE_ENABLE 0x80 + +struct acx_feature_config { + struct acx_header header; + + u8 role_id; + u8 padding[3]; + __le32 options; + __le32 data_flow_options; +} __packed; + +struct acx_current_tx_power { + struct acx_header header; + + u8 role_id; + u8 current_tx_power; + u8 padding[2]; +} __packed; + +struct acx_wake_up_condition { + struct acx_header header; + + u8 role_id; + u8 wake_up_event; /* Only one bit can be set */ + u8 listen_interval; + u8 pad[1]; +} __packed; + +struct acx_aid { + struct acx_header header; + + /* + * To be set when associated with an AP. + */ + u8 role_id; + u8 reserved; + __le16 aid; +} __packed; + +enum acx_preamble_type { + ACX_PREAMBLE_LONG = 0, + ACX_PREAMBLE_SHORT = 1 +}; + +struct acx_preamble { + struct acx_header header; + + /* + * When set, the WiLink transmits the frames with a short preamble and + * when cleared, the WiLink transmits the frames with a long preamble. + */ + u8 role_id; + u8 preamble; + u8 padding[2]; +} __packed; + +enum acx_ctsprotect_type { + CTSPROTECT_DISABLE = 0, + CTSPROTECT_ENABLE = 1 +}; + +struct acx_ctsprotect { + struct acx_header header; + u8 role_id; + u8 ctsprotect; + u8 padding[2]; +} __packed; + +struct acx_tx_statistics { + __le32 internal_desc_overflow; +} __packed; + +struct acx_rx_statistics { + __le32 out_of_mem; + __le32 hdr_overflow; + __le32 hw_stuck; + __le32 dropped; + __le32 fcs_err; + __le32 xfr_hint_trig; + __le32 path_reset; + __le32 reset_counter; +} __packed; + +struct acx_dma_statistics { + __le32 rx_requested; + __le32 rx_errors; + __le32 tx_requested; + __le32 tx_errors; +} __packed; + +struct acx_isr_statistics { + /* host command complete */ + __le32 cmd_cmplt; + + /* fiqisr() */ + __le32 fiqs; + + /* (INT_STS_ND & INT_TRIG_RX_HEADER) */ + __le32 rx_headers; + + /* (INT_STS_ND & INT_TRIG_RX_CMPLT) */ + __le32 rx_completes; + + /* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */ + __le32 rx_mem_overflow; + + /* (INT_STS_ND & INT_TRIG_S_RX_RDY) */ + __le32 rx_rdys; + + /* irqisr() */ + __le32 irqs; + + /* (INT_STS_ND & INT_TRIG_TX_PROC) */ + __le32 tx_procs; + + /* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */ + __le32 decrypt_done; + + /* (INT_STS_ND & INT_TRIG_DMA0) */ + __le32 dma0_done; + + /* (INT_STS_ND & INT_TRIG_DMA1) */ + __le32 dma1_done; + + /* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */ + __le32 tx_exch_complete; + + /* (INT_STS_ND & INT_TRIG_COMMAND) */ + __le32 commands; + + /* (INT_STS_ND & INT_TRIG_RX_PROC) */ + __le32 rx_procs; + + /* (INT_STS_ND & INT_TRIG_PM_802) */ + __le32 hw_pm_mode_changes; + + /* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */ + __le32 host_acknowledges; + + /* (INT_STS_ND & INT_TRIG_PM_PCI) */ + __le32 pci_pm; + + /* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */ + __le32 wakeups; + + /* (INT_STS_ND & INT_TRIG_LOW_RSSI) */ + __le32 low_rssi; +} __packed; + +struct acx_wep_statistics { + /* WEP address keys configured */ + __le32 addr_key_count; + + /* default keys configured */ + __le32 default_key_count; + + __le32 reserved; + + /* number of times that WEP key not found on lookup */ + __le32 key_not_found; + + /* number of times that WEP key decryption failed */ + __le32 decrypt_fail; + + /* WEP packets decrypted */ + __le32 packets; + + /* WEP decrypt interrupts */ + __le32 interrupt; +} __packed; + +#define ACX_MISSED_BEACONS_SPREAD 10 + +struct acx_pwr_statistics { + /* the amount of enters into power save mode (both PD & ELP) */ + __le32 ps_enter; + + /* the amount of enters into ELP mode */ + __le32 elp_enter; + + /* the amount of missing beacon interrupts to the host */ + __le32 missing_bcns; + + /* the amount of wake on host-access times */ + __le32 wake_on_host; + + /* the amount of wake on timer-expire */ + __le32 wake_on_timer_exp; + + /* the number of packets that were transmitted with PS bit set */ + __le32 tx_with_ps; + + /* the number of packets that were transmitted with PS bit clear */ + __le32 tx_without_ps; + + /* the number of received beacons */ + __le32 rcvd_beacons; + + /* the number of entering into PowerOn (power save off) */ + __le32 power_save_off; + + /* the number of entries into power save mode */ + __le16 enable_ps; + + /* + * the number of exits from power save, not including failed PS + * transitions + */ + __le16 disable_ps; + + /* + * the number of times the TSF counter was adjusted because + * of drift + */ + __le32 fix_tsf_ps; + + /* Gives statistics about the spread continuous missed beacons. + * The 16 LSB are dedicated for the PS mode. + * The 16 MSB are dedicated for the PS mode. + * cont_miss_bcns_spread[0] - single missed beacon. + * cont_miss_bcns_spread[1] - two continuous missed beacons. + * cont_miss_bcns_spread[2] - three continuous missed beacons. + * ... + * cont_miss_bcns_spread[9] - ten and more continuous missed beacons. + */ + __le32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD]; + + /* the number of beacons in awake mode */ + __le32 rcvd_awake_beacons; +} __packed; + +struct acx_mic_statistics { + __le32 rx_pkts; + __le32 calc_failure; +} __packed; + +struct acx_aes_statistics { + __le32 encrypt_fail; + __le32 decrypt_fail; + __le32 encrypt_packets; + __le32 decrypt_packets; + __le32 encrypt_interrupt; + __le32 decrypt_interrupt; +} __packed; + +struct acx_event_statistics { + __le32 heart_beat; + __le32 calibration; + __le32 rx_mismatch; + __le32 rx_mem_empty; + __le32 rx_pool; + __le32 oom_late; + __le32 phy_transmit_error; + __le32 tx_stuck; +} __packed; + +struct acx_ps_statistics { + __le32 pspoll_timeouts; + __le32 upsd_timeouts; + __le32 upsd_max_sptime; + __le32 upsd_max_apturn; + __le32 pspoll_max_apturn; + __le32 pspoll_utilization; + __le32 upsd_utilization; +} __packed; + +struct acx_rxpipe_statistics { + __le32 rx_prep_beacon_drop; + __le32 descr_host_int_trig_rx_data; + __le32 beacon_buffer_thres_host_int_trig_rx_data; + __le32 missed_beacon_host_int_trig_rx_data; + __le32 tx_xfr_host_int_trig_rx_data; +} __packed; + +struct acx_statistics { + struct acx_header header; + + struct acx_tx_statistics tx; + struct acx_rx_statistics rx; + struct acx_dma_statistics dma; + struct acx_isr_statistics isr; + struct acx_wep_statistics wep; + struct acx_pwr_statistics pwr; + struct acx_aes_statistics aes; + struct acx_mic_statistics mic; + struct acx_event_statistics event; + struct acx_ps_statistics ps; + struct acx_rxpipe_statistics rxpipe; +} __packed; + +struct acx_rate_class { + __le32 enabled_rates; + u8 short_retry_limit; + u8 long_retry_limit; + u8 aflags; + u8 reserved; +}; + +struct acx_rate_policy { + struct acx_header header; + + __le32 rate_policy_idx; + struct acx_rate_class rate_policy; +} __packed; + +struct acx_ac_cfg { + struct acx_header header; + u8 role_id; + u8 ac; + u8 aifsn; + u8 cw_min; + __le16 cw_max; + __le16 tx_op_limit; +} __packed; + +struct acx_tid_config { + struct acx_header header; + u8 role_id; + u8 queue_id; + u8 channel_type; + u8 tsid; + u8 ps_scheme; + u8 ack_policy; + u8 padding[2]; + __le32 apsd_conf[2]; +} __packed; + +struct acx_frag_threshold { + struct acx_header header; + __le16 frag_threshold; + u8 padding[2]; +} __packed; + +struct acx_tx_config_options { + struct acx_header header; + __le16 tx_compl_timeout; /* msec */ + __le16 tx_compl_threshold; /* number of packets */ +} __packed; + +struct wl12xx_acx_config_memory { + struct acx_header header; + + u8 rx_mem_block_num; + u8 tx_min_mem_block_num; + u8 num_stations; + u8 num_ssid_profiles; + __le32 total_tx_descriptors; + u8 dyn_mem_enable; + u8 tx_free_req; + u8 rx_free_req; + u8 tx_min; + u8 fwlog_blocks; + u8 padding[3]; +} __packed; + +struct wl1271_acx_mem_map { + struct acx_header header; + + __le32 code_start; + __le32 code_end; + + __le32 wep_defkey_start; + __le32 wep_defkey_end; + + __le32 sta_table_start; + __le32 sta_table_end; + + __le32 packet_template_start; + __le32 packet_template_end; + + /* Address of the TX result interface (control block) */ + __le32 tx_result; + __le32 tx_result_queue_start; + + __le32 queue_memory_start; + __le32 queue_memory_end; + + __le32 packet_memory_pool_start; + __le32 packet_memory_pool_end; + + __le32 debug_buffer1_start; + __le32 debug_buffer1_end; + + __le32 debug_buffer2_start; + __le32 debug_buffer2_end; + + /* Number of blocks FW allocated for TX packets */ + __le32 num_tx_mem_blocks; + + /* Number of blocks FW allocated for RX packets */ + __le32 num_rx_mem_blocks; + + /* the following 4 fields are valid in SLAVE mode only */ + u8 *tx_cbuf; + u8 *rx_cbuf; + __le32 rx_ctrl; + __le32 tx_ctrl; +} __packed; + +struct wl1271_acx_rx_config_opt { + struct acx_header header; + + __le16 mblk_threshold; + __le16 threshold; + __le16 timeout; + u8 queue_type; + u8 reserved; +} __packed; + + +struct wl1271_acx_bet_enable { + struct acx_header header; + + u8 role_id; + u8 enable; + u8 max_consecutive; + u8 padding[1]; +} __packed; + +#define ACX_IPV4_VERSION 4 +#define ACX_IPV6_VERSION 6 +#define ACX_IPV4_ADDR_SIZE 4 + +/* bitmap of enabled arp_filter features */ +#define ACX_ARP_FILTER_ARP_FILTERING BIT(0) +#define ACX_ARP_FILTER_AUTO_ARP BIT(1) + +struct wl1271_acx_arp_filter { + struct acx_header header; + u8 role_id; + u8 version; /* ACX_IPV4_VERSION, ACX_IPV6_VERSION */ + u8 enable; /* bitmap of enabled ARP filtering features */ + u8 padding[1]; + u8 address[16]; /* The configured device IP address - all ARP + requests directed to this IP address will pass + through. For IPv4, the first four bytes are + used. */ +} __packed; + +struct wl1271_acx_pm_config { + struct acx_header header; + + __le32 host_clk_settling_time; + u8 host_fast_wakeup_support; + u8 padding[3]; +} __packed; + +struct wl1271_acx_keep_alive_mode { + struct acx_header header; + + u8 role_id; + u8 enabled; + u8 padding[2]; +} __packed; + +enum { + ACX_KEEP_ALIVE_NO_TX = 0, + ACX_KEEP_ALIVE_PERIOD_ONLY +}; + +enum { + ACX_KEEP_ALIVE_TPL_INVALID = 0, + ACX_KEEP_ALIVE_TPL_VALID +}; + +struct wl1271_acx_keep_alive_config { + struct acx_header header; + + u8 role_id; + u8 index; + u8 tpl_validation; + u8 trigger; + __le32 period; +} __packed; + +/* TODO: maybe this needs to be moved somewhere else? */ +#define HOST_IF_CFG_RX_FIFO_ENABLE BIT(0) +#define HOST_IF_CFG_TX_EXTRA_BLKS_SWAP BIT(1) +#define HOST_IF_CFG_TX_PAD_TO_SDIO_BLK BIT(3) + +enum { + WL1271_ACX_TRIG_TYPE_LEVEL = 0, + WL1271_ACX_TRIG_TYPE_EDGE, +}; + +enum { + WL1271_ACX_TRIG_DIR_LOW = 0, + WL1271_ACX_TRIG_DIR_HIGH, + WL1271_ACX_TRIG_DIR_BIDIR, +}; + +enum { + WL1271_ACX_TRIG_ENABLE = 1, + WL1271_ACX_TRIG_DISABLE, +}; + +enum { + WL1271_ACX_TRIG_METRIC_RSSI_BEACON = 0, + WL1271_ACX_TRIG_METRIC_RSSI_DATA, + WL1271_ACX_TRIG_METRIC_SNR_BEACON, + WL1271_ACX_TRIG_METRIC_SNR_DATA, +}; + +enum { + WL1271_ACX_TRIG_IDX_RSSI = 0, + WL1271_ACX_TRIG_COUNT = 8, +}; + +struct wl1271_acx_rssi_snr_trigger { + struct acx_header header; + + u8 role_id; + u8 metric; + u8 type; + u8 dir; + __le16 threshold; + __le16 pacing; /* 0 - 60000 ms */ + u8 hysteresis; + u8 index; + u8 enable; + u8 padding[1]; +}; + +struct wl1271_acx_rssi_snr_avg_weights { + struct acx_header header; + + u8 role_id; + u8 padding[3]; + u8 rssi_beacon; + u8 rssi_data; + u8 snr_beacon; + u8 snr_data; +}; + + +/* special capability bit (not employed by the 802.11n spec) */ +#define WL12XX_HT_CAP_HT_OPERATION BIT(16) + +/* + * ACX_PEER_HT_CAP + * Configure HT capabilities - declare the capabilities of the peer + * we are connected to. + */ +struct wl1271_acx_ht_capabilities { + struct acx_header header; + + /* bitmask of capability bits supported by the peer */ + __le32 ht_capabilites; + + /* Indicates to which link these capabilities apply. */ + u8 hlid; + + /* + * This the maximum A-MPDU length supported by the AP. The FW may not + * exceed this length when sending A-MPDUs + */ + u8 ampdu_max_length; + + /* This is the minimal spacing required when sending A-MPDUs to the AP*/ + u8 ampdu_min_spacing; + + u8 padding; +} __packed; + +/* + * ACX_HT_BSS_OPERATION + * Configure HT capabilities - AP rules for behavior in the BSS. + */ +struct wl1271_acx_ht_information { + struct acx_header header; + + u8 role_id; + + /* Values: 0 - RIFS not allowed, 1 - RIFS allowed */ + u8 rifs_mode; + + /* Values: 0 - 3 like in spec */ + u8 ht_protection; + + /* Values: 0 - GF protection not required, 1 - GF protection required */ + u8 gf_protection; + + /*Values: 0 - TX Burst limit not required, 1 - TX Burst Limit required*/ + u8 ht_tx_burst_limit; + + /* + * Values: 0 - Dual CTS protection not required, + * 1 - Dual CTS Protection required + * Note: When this value is set to 1 FW will protect all TXOP with RTS + * frame and will not use CTS-to-self regardless of the value of the + * ACX_CTS_PROTECTION information element + */ + u8 dual_cts_protection; + + u8 padding[2]; +} __packed; + +#define RX_BA_MAX_SESSIONS 2 + +struct wl1271_acx_ba_initiator_policy { + struct acx_header header; + + /* Specifies role Id, Range 0-7, 0xFF means ANY role. */ + u8 role_id; + + /* + * Per TID setting for allowing TX BA. Set a bit to 1 to allow + * TX BA sessions for the corresponding TID. + */ + u8 tid_bitmap; + + /* Windows size in number of packets */ + u8 win_size; + + u8 padding1[1]; + + /* As initiator inactivity timeout in time units(TU) of 1024us */ + u16 inactivity_timeout; + + u8 padding[2]; +} __packed; + +struct wl1271_acx_ba_receiver_setup { + struct acx_header header; + + /* Specifies link id, range 0-31 */ + u8 hlid; + + u8 tid; + + u8 enable; + + /* Windows size in number of packets */ + u8 win_size; + + /* BA session starting sequence number. RANGE 0-FFF */ + u16 ssn; + + u8 padding[2]; +} __packed; + +struct wl12xx_acx_fw_tsf_information { + struct acx_header header; + + u8 role_id; + u8 padding1[3]; + __le32 current_tsf_high; + __le32 current_tsf_low; + __le32 last_bttt_high; + __le32 last_tbtt_low; + u8 last_dtim_count; + u8 padding2[3]; +} __packed; + +struct wl1271_acx_ps_rx_streaming { + struct acx_header header; + + u8 role_id; + u8 tid; + u8 enable; + + /* interval between triggers (10-100 msec) */ + u8 period; + + /* timeout before first trigger (0-200 msec) */ + u8 timeout; + u8 padding[3]; +} __packed; + +struct wl1271_acx_ap_max_tx_retry { + struct acx_header header; + + u8 role_id; + u8 padding_1; + + /* + * the number of frames transmission failures before + * issuing the aging event. + */ + __le16 max_tx_retry; +} __packed; + +struct wl1271_acx_config_ps { + struct acx_header header; + + u8 exit_retries; + u8 enter_retries; + u8 padding[2]; + __le32 null_data_rate; +} __packed; + +struct wl1271_acx_inconnection_sta { + struct acx_header header; + + u8 addr[ETH_ALEN]; + u8 padding1[2]; +} __packed; + +/* + * ACX_FM_COEX_CFG + * set the FM co-existence parameters. + */ +struct wl1271_acx_fm_coex { + struct acx_header header; + /* enable(1) / disable(0) the FM Coex feature */ + u8 enable; + /* + * Swallow period used in COEX PLL swallowing mechanism. + * 0xFF = use FW default + */ + u8 swallow_period; + /* + * The N divider used in COEX PLL swallowing mechanism for Fref of + * 38.4/19.2 Mhz. 0xFF = use FW default + */ + u8 n_divider_fref_set_1; + /* + * The N divider used in COEX PLL swallowing mechanism for Fref of + * 26/52 Mhz. 0xFF = use FW default + */ + u8 n_divider_fref_set_2; + /* + * The M divider used in COEX PLL swallowing mechanism for Fref of + * 38.4/19.2 Mhz. 0xFFFF = use FW default + */ + __le16 m_divider_fref_set_1; + /* + * The M divider used in COEX PLL swallowing mechanism for Fref of + * 26/52 Mhz. 0xFFFF = use FW default + */ + __le16 m_divider_fref_set_2; + /* + * The time duration in uSec required for COEX PLL to stabilize. + * 0xFFFFFFFF = use FW default + */ + __le32 coex_pll_stabilization_time; + /* + * The time duration in uSec required for LDO to stabilize. + * 0xFFFFFFFF = use FW default + */ + __le16 ldo_stabilization_time; + /* + * The disturbed frequency band margin around the disturbed frequency + * center (single sided). + * For example, if 2 is configured, the following channels will be + * considered disturbed channel: + * 80 +- 0.1 MHz, 91 +- 0.1 MHz, 98 +- 0.1 MHz, 102 +- 0.1 MH + * 0xFF = use FW default + */ + u8 fm_disturbed_band_margin; + /* + * The swallow clock difference of the swallowing mechanism. + * 0xFF = use FW default + */ + u8 swallow_clk_diff; +} __packed; + +#define ACX_RATE_MGMT_ALL_PARAMS 0xff +struct wl12xx_acx_set_rate_mgmt_params { + struct acx_header header; + + u8 index; /* 0xff to configure all params */ + u8 padding1; + __le16 rate_retry_score; + __le16 per_add; + __le16 per_th1; + __le16 per_th2; + __le16 max_per; + u8 inverse_curiosity_factor; + u8 tx_fail_low_th; + u8 tx_fail_high_th; + u8 per_alpha_shift; + u8 per_add_shift; + u8 per_beta1_shift; + u8 per_beta2_shift; + u8 rate_check_up; + u8 rate_check_down; + u8 rate_retry_policy[ACX_RATE_MGMT_NUM_OF_RATES]; + u8 padding2[2]; +} __packed; + +struct wl12xx_acx_config_hangover { + struct acx_header header; + + __le32 recover_time; + u8 hangover_period; + u8 dynamic_mode; + u8 early_termination_mode; + u8 max_period; + u8 min_period; + u8 increase_delta; + u8 decrease_delta; + u8 quiet_time; + u8 increase_time; + u8 window_size; + u8 padding[2]; +} __packed; + +enum { + ACX_WAKE_UP_CONDITIONS = 0x0000, + ACX_MEM_CFG = 0x0001, + ACX_SLOT = 0x0002, + ACX_AC_CFG = 0x0003, + ACX_MEM_MAP = 0x0004, + ACX_AID = 0x0005, + ACX_MEDIUM_USAGE = 0x0006, + ACX_STATISTICS = 0x0007, + ACX_PWR_CONSUMPTION_STATISTICS = 0x0008, + ACX_TID_CFG = 0x0009, + ACX_PS_RX_STREAMING = 0x000A, + ACX_BEACON_FILTER_OPT = 0x000B, + ACX_NOISE_HIST = 0x000C, + ACX_HDK_VERSION = 0x000D, + ACX_PD_THRESHOLD = 0x000E, + ACX_TX_CONFIG_OPT = 0x000F, + ACX_CCA_THRESHOLD = 0x0010, + ACX_EVENT_MBOX_MASK = 0x0011, + ACX_CONN_MONIT_PARAMS = 0x0012, + ACX_DISABLE_BROADCASTS = 0x0013, + ACX_BCN_DTIM_OPTIONS = 0x0014, + ACX_SG_ENABLE = 0x0015, + ACX_SG_CFG = 0x0016, + ACX_FM_COEX_CFG = 0x0017, + ACX_BEACON_FILTER_TABLE = 0x0018, + ACX_ARP_IP_FILTER = 0x0019, + ACX_ROAMING_STATISTICS_TBL = 0x001A, + ACX_RATE_POLICY = 0x001B, + ACX_CTS_PROTECTION = 0x001C, + ACX_SLEEP_AUTH = 0x001D, + ACX_PREAMBLE_TYPE = 0x001E, + ACX_ERROR_CNT = 0x001F, + ACX_IBSS_FILTER = 0x0020, + ACX_SERVICE_PERIOD_TIMEOUT = 0x0021, + ACX_TSF_INFO = 0x0022, + ACX_CONFIG_PS_WMM = 0x0023, + ACX_ENABLE_RX_DATA_FILTER = 0x0024, + ACX_SET_RX_DATA_FILTER = 0x0025, + ACX_GET_DATA_FILTER_STATISTICS = 0x0026, + ACX_RX_CONFIG_OPT = 0x0027, + ACX_FRAG_CFG = 0x0028, + ACX_BET_ENABLE = 0x0029, + ACX_RSSI_SNR_TRIGGER = 0x002A, + ACX_RSSI_SNR_WEIGHTS = 0x002B, + ACX_KEEP_ALIVE_MODE = 0x002C, + ACX_SET_KEEP_ALIVE_CONFIG = 0x002D, + ACX_BA_SESSION_INIT_POLICY = 0x002E, + ACX_BA_SESSION_RX_SETUP = 0x002F, + ACX_PEER_HT_CAP = 0x0030, + ACX_HT_BSS_OPERATION = 0x0031, + ACX_COEX_ACTIVITY = 0x0032, + ACX_BURST_MODE = 0x0033, + ACX_SET_RATE_MGMT_PARAMS = 0x0034, + ACX_GET_RATE_MGMT_PARAMS = 0x0035, + ACX_SET_RATE_ADAPT_PARAMS = 0x0036, + ACX_SET_DCO_ITRIM_PARAMS = 0x0037, + ACX_GEN_FW_CMD = 0x0038, + ACX_HOST_IF_CFG_BITMAP = 0x0039, + ACX_MAX_TX_FAILURE = 0x003A, + ACX_UPDATE_INCONNECTION_STA_LIST = 0x003B, + DOT11_RX_MSDU_LIFE_TIME = 0x003C, + DOT11_CUR_TX_PWR = 0x003D, + DOT11_RTS_THRESHOLD = 0x003E, + DOT11_GROUP_ADDRESS_TBL = 0x003F, + ACX_PM_CONFIG = 0x0040, + ACX_CONFIG_PS = 0x0041, + ACX_CONFIG_HANGOVER = 0x0042, + ACX_FEATURE_CFG = 0x0043, + ACX_PROTECTION_CFG = 0x0044, +}; + + +int wl1271_acx_wake_up_conditions(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + u8 wake_up_event, u8 listen_interval); +int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth); +int wl1271_acx_tx_power(struct wl1271 *wl, struct wl12xx_vif *wlvif, + int power); +int wl1271_acx_feature_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif); +int wl1271_acx_mem_map(struct wl1271 *wl, + struct acx_header *mem_map, size_t len); +int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl); +int wl1271_acx_slot(struct wl1271 *wl, struct wl12xx_vif *wlvif, + enum acx_slot_type slot_time); +int wl1271_acx_group_address_tbl(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable, void *mc_list, u32 mc_list_len); +int wl1271_acx_service_period_timeout(struct wl1271 *wl, + struct wl12xx_vif *wlvif); +int wl1271_acx_rts_threshold(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u32 rts_threshold); +int wl1271_acx_dco_itrim_params(struct wl1271 *wl); +int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable_filter); +int wl1271_acx_beacon_filter_table(struct wl1271 *wl, + struct wl12xx_vif *wlvif); +int wl1271_acx_conn_monit_params(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable); +int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable); +int wl12xx_acx_sg_cfg(struct wl1271 *wl); +int wl1271_acx_cca_threshold(struct wl1271 *wl); +int wl1271_acx_bcn_dtim_options(struct wl1271 *wl, struct wl12xx_vif *wlvif); +int wl1271_acx_aid(struct wl1271 *wl, struct wl12xx_vif *wlvif, u16 aid); +int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask); +int wl1271_acx_set_preamble(struct wl1271 *wl, struct wl12xx_vif *wlvif, + enum acx_preamble_type preamble); +int wl1271_acx_cts_protect(struct wl1271 *wl, struct wl12xx_vif *wlvif, + enum acx_ctsprotect_type ctsprotect); +int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats); +int wl1271_acx_sta_rate_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif); +int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c, + u8 idx); +int wl1271_acx_ac_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 ac, u8 cw_min, u16 cw_max, u8 aifsn, u16 txop); +int wl1271_acx_tid_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 queue_id, u8 channel_type, + u8 tsid, u8 ps_scheme, u8 ack_policy, + u32 apsd_conf0, u32 apsd_conf1); +int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold); +int wl1271_acx_tx_config_options(struct wl1271 *wl); +int wl12xx_acx_mem_cfg(struct wl1271 *wl); +int wl1271_acx_init_mem_config(struct wl1271 *wl); +int wl1271_acx_init_rx_interrupt(struct wl1271 *wl); +int wl1271_acx_smart_reflex(struct wl1271 *wl); +int wl1271_acx_bet_enable(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable); +int wl1271_acx_arp_ip_filter(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 enable, __be32 address); +int wl1271_acx_pm_config(struct wl1271 *wl); +int wl1271_acx_keep_alive_mode(struct wl1271 *wl, struct wl12xx_vif *vif, + bool enable); +int wl1271_acx_keep_alive_config(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 index, u8 tpl_valid); +int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable, s16 thold, u8 hyst); +int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl, + struct wl12xx_vif *wlvif); +int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, + struct ieee80211_sta_ht_cap *ht_cap, + bool allow_ht_operation, u8 hlid); +int wl1271_acx_set_ht_information(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + u16 ht_operation_mode); +int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl, + struct wl12xx_vif *wlvif); +int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, + u16 ssn, bool enable, u8 peer_hlid); +int wl12xx_acx_tsf_info(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u64 *mactime); +int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable); +int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl, struct wl12xx_vif *wlvif); +int wl12xx_acx_config_ps(struct wl1271 *wl, struct wl12xx_vif *wlvif); +int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr); +int wl1271_acx_fm_coex(struct wl1271 *wl); +int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl); +int wl12xx_acx_config_hangover(struct wl1271 *wl); + +#endif /* __WL1271_ACX_H__ */ diff --git a/trunk/drivers/net/wireless/ti/wlcore/boot.c b/trunk/drivers/net/wireless/ti/wlcore/boot.c new file mode 100644 index 000000000000..3a2207db5405 --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wlcore/boot.c @@ -0,0 +1,443 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2010 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include + +#include "debug.h" +#include "acx.h" +#include "boot.h" +#include "io.h" +#include "event.h" +#include "rx.h" +#include "hw_ops.h" + +static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag) +{ + u32 cpu_ctrl; + + /* 10.5.0 run the firmware (I) */ + cpu_ctrl = wlcore_read_reg(wl, REG_ECPU_CONTROL); + + /* 10.5.1 run the firmware (II) */ + cpu_ctrl |= flag; + wlcore_write_reg(wl, REG_ECPU_CONTROL, cpu_ctrl); +} + +static int wlcore_parse_fw_ver(struct wl1271 *wl) +{ + int ret; + + ret = sscanf(wl->chip.fw_ver_str + 4, "%u.%u.%u.%u.%u", + &wl->chip.fw_ver[0], &wl->chip.fw_ver[1], + &wl->chip.fw_ver[2], &wl->chip.fw_ver[3], + &wl->chip.fw_ver[4]); + + if (ret != 5) { + wl1271_warning("fw version incorrect value"); + memset(wl->chip.fw_ver, 0, sizeof(wl->chip.fw_ver)); + return -EINVAL; + } + + ret = wlcore_identify_fw(wl); + if (ret < 0) + return ret; + + return 0; +} + +static int wlcore_boot_fw_version(struct wl1271 *wl) +{ + struct wl1271_static_data *static_data; + int ret; + + static_data = kmalloc(sizeof(*static_data), GFP_DMA); + if (!static_data) { + wl1271_error("Couldn't allocate memory for static data!"); + return -ENOMEM; + } + + wl1271_read(wl, wl->cmd_box_addr, static_data, sizeof(*static_data), + false); + + strncpy(wl->chip.fw_ver_str, static_data->fw_version, + sizeof(wl->chip.fw_ver_str)); + + kfree(static_data); + + /* make sure the string is NULL-terminated */ + wl->chip.fw_ver_str[sizeof(wl->chip.fw_ver_str) - 1] = '\0'; + + ret = wlcore_parse_fw_ver(wl); + if (ret < 0) + return ret; + + return 0; +} + +static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, + size_t fw_data_len, u32 dest) +{ + struct wlcore_partition_set partition; + int addr, chunk_num, partition_limit; + u8 *p, *chunk; + + /* whal_FwCtrl_LoadFwImageSm() */ + + wl1271_debug(DEBUG_BOOT, "starting firmware upload"); + + wl1271_debug(DEBUG_BOOT, "fw_data_len %zd chunk_size %d", + fw_data_len, CHUNK_SIZE); + + if ((fw_data_len % 4) != 0) { + wl1271_error("firmware length not multiple of four"); + return -EIO; + } + + chunk = kmalloc(CHUNK_SIZE, GFP_KERNEL); + if (!chunk) { + wl1271_error("allocation for firmware upload chunk failed"); + return -ENOMEM; + } + + memcpy(&partition, &wl->ptable[PART_DOWN], sizeof(partition)); + partition.mem.start = dest; + wlcore_set_partition(wl, &partition); + + /* 10.1 set partition limit and chunk num */ + chunk_num = 0; + partition_limit = wl->ptable[PART_DOWN].mem.size; + + while (chunk_num < fw_data_len / CHUNK_SIZE) { + /* 10.2 update partition, if needed */ + addr = dest + (chunk_num + 2) * CHUNK_SIZE; + if (addr > partition_limit) { + addr = dest + chunk_num * CHUNK_SIZE; + partition_limit = chunk_num * CHUNK_SIZE + + wl->ptable[PART_DOWN].mem.size; + partition.mem.start = addr; + wlcore_set_partition(wl, &partition); + } + + /* 10.3 upload the chunk */ + addr = dest + chunk_num * CHUNK_SIZE; + p = buf + chunk_num * CHUNK_SIZE; + memcpy(chunk, p, CHUNK_SIZE); + wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", + p, addr); + wl1271_write(wl, addr, chunk, CHUNK_SIZE, false); + + chunk_num++; + } + + /* 10.4 upload the last chunk */ + addr = dest + chunk_num * CHUNK_SIZE; + p = buf + chunk_num * CHUNK_SIZE; + memcpy(chunk, p, fw_data_len % CHUNK_SIZE); + wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x", + fw_data_len % CHUNK_SIZE, p, addr); + wl1271_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false); + + kfree(chunk); + return 0; +} + +int wlcore_boot_upload_firmware(struct wl1271 *wl) +{ + u32 chunks, addr, len; + int ret = 0; + u8 *fw; + + fw = wl->fw; + chunks = be32_to_cpup((__be32 *) fw); + fw += sizeof(u32); + + wl1271_debug(DEBUG_BOOT, "firmware chunks to be uploaded: %u", chunks); + + while (chunks--) { + addr = be32_to_cpup((__be32 *) fw); + fw += sizeof(u32); + len = be32_to_cpup((__be32 *) fw); + fw += sizeof(u32); + + if (len > 300000) { + wl1271_info("firmware chunk too long: %u", len); + return -EINVAL; + } + wl1271_debug(DEBUG_BOOT, "chunk %d addr 0x%x len %u", + chunks, addr, len); + ret = wl1271_boot_upload_firmware_chunk(wl, fw, len, addr); + if (ret != 0) + break; + fw += len; + } + + return ret; +} +EXPORT_SYMBOL_GPL(wlcore_boot_upload_firmware); + +int wlcore_boot_upload_nvs(struct wl1271 *wl) +{ + size_t nvs_len, burst_len; + int i; + u32 dest_addr, val; + u8 *nvs_ptr, *nvs_aligned; + + if (wl->nvs == NULL) + return -ENODEV; + + if (wl->quirks & WLCORE_QUIRK_LEGACY_NVS) { + struct wl1271_nvs_file *nvs = + (struct wl1271_nvs_file *)wl->nvs; + /* + * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz + * band configurations) can be removed when those NVS files stop + * floating around. + */ + if (wl->nvs_len == sizeof(struct wl1271_nvs_file) || + wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) { + if (nvs->general_params.dual_mode_select) + wl->enable_11a = true; + } + + if (wl->nvs_len != sizeof(struct wl1271_nvs_file) && + (wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE || + wl->enable_11a)) { + wl1271_error("nvs size is not as expected: %zu != %zu", + wl->nvs_len, sizeof(struct wl1271_nvs_file)); + kfree(wl->nvs); + wl->nvs = NULL; + wl->nvs_len = 0; + return -EILSEQ; + } + + /* only the first part of the NVS needs to be uploaded */ + nvs_len = sizeof(nvs->nvs); + nvs_ptr = (u8 *) nvs->nvs; + } else { + struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs; + + if (wl->nvs_len == sizeof(struct wl128x_nvs_file)) { + if (nvs->general_params.dual_mode_select) + wl->enable_11a = true; + } else { + wl1271_error("nvs size is not as expected: %zu != %zu", + wl->nvs_len, + sizeof(struct wl128x_nvs_file)); + kfree(wl->nvs); + wl->nvs = NULL; + wl->nvs_len = 0; + return -EILSEQ; + } + + /* only the first part of the NVS needs to be uploaded */ + nvs_len = sizeof(nvs->nvs); + nvs_ptr = (u8 *)nvs->nvs; + } + + /* update current MAC address to NVS */ + nvs_ptr[11] = wl->addresses[0].addr[0]; + nvs_ptr[10] = wl->addresses[0].addr[1]; + nvs_ptr[6] = wl->addresses[0].addr[2]; + nvs_ptr[5] = wl->addresses[0].addr[3]; + nvs_ptr[4] = wl->addresses[0].addr[4]; + nvs_ptr[3] = wl->addresses[0].addr[5]; + + /* + * Layout before the actual NVS tables: + * 1 byte : burst length. + * 2 bytes: destination address. + * n bytes: data to burst copy. + * + * This is ended by a 0 length, then the NVS tables. + */ + + /* FIXME: Do we need to check here whether the LSB is 1? */ + while (nvs_ptr[0]) { + burst_len = nvs_ptr[0]; + dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); + + /* + * Due to our new wl1271_translate_reg_addr function, + * we need to add the register partition start address + * to the destination + */ + dest_addr += wl->curr_part.reg.start; + + /* We move our pointer to the data */ + nvs_ptr += 3; + + for (i = 0; i < burst_len; i++) { + if (nvs_ptr + 3 >= (u8 *) wl->nvs + nvs_len) + goto out_badnvs; + + val = (nvs_ptr[0] | (nvs_ptr[1] << 8) + | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); + + wl1271_debug(DEBUG_BOOT, + "nvs burst write 0x%x: 0x%x", + dest_addr, val); + wl1271_write32(wl, dest_addr, val); + + nvs_ptr += 4; + dest_addr += 4; + } + + if (nvs_ptr >= (u8 *) wl->nvs + nvs_len) + goto out_badnvs; + } + + /* + * We've reached the first zero length, the first NVS table + * is located at an aligned offset which is at least 7 bytes further. + * NOTE: The wl->nvs->nvs element must be first, in order to + * simplify the casting, we assume it is at the beginning of + * the wl->nvs structure. + */ + nvs_ptr = (u8 *)wl->nvs + + ALIGN(nvs_ptr - (u8 *)wl->nvs + 7, 4); + + if (nvs_ptr >= (u8 *) wl->nvs + nvs_len) + goto out_badnvs; + + nvs_len -= nvs_ptr - (u8 *)wl->nvs; + + /* Now we must set the partition correctly */ + wlcore_set_partition(wl, &wl->ptable[PART_WORK]); + + /* Copy the NVS tables to a new block to ensure alignment */ + nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); + if (!nvs_aligned) + return -ENOMEM; + + /* And finally we upload the NVS tables */ + wlcore_write_data(wl, REG_CMD_MBOX_ADDRESS, + nvs_aligned, nvs_len, false); + + kfree(nvs_aligned); + return 0; + +out_badnvs: + wl1271_error("nvs data is malformed"); + return -EILSEQ; +} +EXPORT_SYMBOL_GPL(wlcore_boot_upload_nvs); + +int wlcore_boot_run_firmware(struct wl1271 *wl) +{ + int loop, ret; + u32 chip_id, intr; + + /* Make sure we have the boot partition */ + wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); + + wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); + + chip_id = wlcore_read_reg(wl, REG_CHIP_ID_B); + + wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); + + if (chip_id != wl->chip.id) { + wl1271_error("chip id doesn't match after firmware boot"); + return -EIO; + } + + /* wait for init to complete */ + loop = 0; + while (loop++ < INIT_LOOP) { + udelay(INIT_LOOP_DELAY); + intr = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR); + + if (intr == 0xffffffff) { + wl1271_error("error reading hardware complete " + "init indication"); + return -EIO; + } + /* check that ACX_INTR_INIT_COMPLETE is enabled */ + else if (intr & WL1271_ACX_INTR_INIT_COMPLETE) { + wlcore_write_reg(wl, REG_INTERRUPT_ACK, + WL1271_ACX_INTR_INIT_COMPLETE); + break; + } + } + + if (loop > INIT_LOOP) { + wl1271_error("timeout waiting for the hardware to " + "complete initialization"); + return -EIO; + } + + /* get hardware config command mail box */ + wl->cmd_box_addr = wlcore_read_reg(wl, REG_COMMAND_MAILBOX_PTR); + + wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x", wl->cmd_box_addr); + + /* get hardware config event mail box */ + wl->mbox_ptr[0] = wlcore_read_reg(wl, REG_EVENT_MAILBOX_PTR); + wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); + + wl1271_debug(DEBUG_MAILBOX, "MBOX ptrs: 0x%x 0x%x", + wl->mbox_ptr[0], wl->mbox_ptr[1]); + + ret = wlcore_boot_fw_version(wl); + if (ret < 0) { + wl1271_error("couldn't boot firmware"); + return ret; + } + + /* + * in case of full asynchronous mode the firmware event must be + * ready to receive event from the command mailbox + */ + + /* unmask required mbox events */ + wl->event_mask = BSS_LOSE_EVENT_ID | + SCAN_COMPLETE_EVENT_ID | + ROLE_STOP_COMPLETE_EVENT_ID | + RSSI_SNR_TRIGGER_0_EVENT_ID | + PSPOLL_DELIVERY_FAILURE_EVENT_ID | + SOFT_GEMINI_SENSE_EVENT_ID | + PERIODIC_SCAN_REPORT_EVENT_ID | + PERIODIC_SCAN_COMPLETE_EVENT_ID | + DUMMY_PACKET_EVENT_ID | + PEER_REMOVE_COMPLETE_EVENT_ID | + BA_SESSION_RX_CONSTRAINT_EVENT_ID | + REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID | + INACTIVE_STA_EVENT_ID | + MAX_TX_RETRY_EVENT_ID | + CHANNEL_SWITCH_COMPLETE_EVENT_ID; + + ret = wl1271_event_unmask(wl); + if (ret < 0) { + wl1271_error("EVENT mask setting failed"); + return ret; + } + + /* set the working partition to its "running" mode offset */ + wlcore_set_partition(wl, &wl->ptable[PART_WORK]); + + /* firmware startup completed */ + return 0; +} +EXPORT_SYMBOL_GPL(wlcore_boot_run_firmware); diff --git a/trunk/drivers/net/wireless/ti/wlcore/boot.h b/trunk/drivers/net/wireless/ti/wlcore/boot.h new file mode 100644 index 000000000000..094981dd2227 --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wlcore/boot.h @@ -0,0 +1,54 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __BOOT_H__ +#define __BOOT_H__ + +#include "wlcore.h" + +int wlcore_boot_upload_firmware(struct wl1271 *wl); +int wlcore_boot_upload_nvs(struct wl1271 *wl); +int wlcore_boot_run_firmware(struct wl1271 *wl); + +#define WL1271_NO_SUBBANDS 8 +#define WL1271_NO_POWER_LEVELS 4 +#define WL1271_FW_VERSION_MAX_LEN 20 + +struct wl1271_static_data { + u8 mac_address[ETH_ALEN]; + u8 padding[2]; + u8 fw_version[WL1271_FW_VERSION_MAX_LEN]; + u32 hw_version; + u8 tx_power_table[WL1271_NO_SUBBANDS][WL1271_NO_POWER_LEVELS]; +}; + +/* number of times we try to read the INIT interrupt */ +#define INIT_LOOP 20000 + +/* delay between retries */ +#define INIT_LOOP_DELAY 50 + +#define WU_COUNTER_PAUSE_VAL 0x3FF +#define WELP_ARM_COMMAND_VAL 0x4 + +#endif diff --git a/trunk/drivers/net/wireless/ti/wlcore/cmd.c b/trunk/drivers/net/wireless/ti/wlcore/cmd.c new file mode 100644 index 000000000000..5c4716c6f040 --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wlcore/cmd.c @@ -0,0 +1,1728 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009-2010 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include + +#include "wlcore.h" +#include "debug.h" +#include "io.h" +#include "acx.h" +#include "wl12xx_80211.h" +#include "cmd.h" +#include "event.h" +#include "tx.h" + +#define WL1271_CMD_FAST_POLL_COUNT 50 + +/* + * send command to firmware + * + * @wl: wl struct + * @id: command id + * @buf: buffer containing the command, must work with dma + * @len: length of the buffer + */ +int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, + size_t res_len) +{ + struct wl1271_cmd_header *cmd; + unsigned long timeout; + u32 intr; + int ret = 0; + u16 status; + u16 poll_count = 0; + + cmd = buf; + cmd->id = cpu_to_le16(id); + cmd->status = 0; + + WARN_ON(len % 4 != 0); + WARN_ON(test_bit(WL1271_FLAG_IN_ELP, &wl->flags)); + + wl1271_write(wl, wl->cmd_box_addr, buf, len, false); + + /* + * TODO: we just need this because one bit is in a different + * place. Is there any better way? + */ + wl->ops->trigger_cmd(wl, wl->cmd_box_addr, buf, len); + + timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); + + intr = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR); + while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { + if (time_after(jiffies, timeout)) { + wl1271_error("command complete timeout"); + ret = -ETIMEDOUT; + goto fail; + } + + poll_count++; + if (poll_count < WL1271_CMD_FAST_POLL_COUNT) + udelay(10); + else + msleep(1); + + intr = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR); + } + + /* read back the status code of the command */ + if (res_len == 0) + res_len = sizeof(struct wl1271_cmd_header); + wl1271_read(wl, wl->cmd_box_addr, cmd, res_len, false); + + status = le16_to_cpu(cmd->status); + if (status != CMD_STATUS_SUCCESS) { + wl1271_error("command execute failure %d", status); + ret = -EIO; + goto fail; + } + + wlcore_write_reg(wl, REG_INTERRUPT_ACK, WL1271_ACX_INTR_CMD_COMPLETE); + return 0; + +fail: + WARN_ON(1); + wl12xx_queue_recovery_work(wl); + return ret; +} + +/* + * Poll the mailbox event field until any of the bits in the mask is set or a + * timeout occurs (WL1271_EVENT_TIMEOUT in msecs) + */ +static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask) +{ + u32 *events_vector; + u32 event; + unsigned long timeout; + int ret = 0; + + events_vector = kmalloc(sizeof(*events_vector), GFP_DMA); + + timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT); + + do { + if (time_after(jiffies, timeout)) { + wl1271_debug(DEBUG_CMD, "timeout waiting for event %d", + (int)mask); + ret = -ETIMEDOUT; + goto out; + } + + msleep(1); + + /* read from both event fields */ + wl1271_read(wl, wl->mbox_ptr[0], events_vector, + sizeof(*events_vector), false); + event = *events_vector & mask; + wl1271_read(wl, wl->mbox_ptr[1], events_vector, + sizeof(*events_vector), false); + event |= *events_vector & mask; + } while (!event); + +out: + kfree(events_vector); + return ret; +} + +static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) +{ + int ret; + + ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask); + if (ret != 0) { + wl12xx_queue_recovery_work(wl); + return ret; + } + + return 0; +} + +int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type, + u8 *role_id) +{ + struct wl12xx_cmd_role_enable *cmd; + int ret; + + wl1271_debug(DEBUG_CMD, "cmd role enable"); + + if (WARN_ON(*role_id != WL12XX_INVALID_ROLE_ID)) + return -EBUSY; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + /* get role id */ + cmd->role_id = find_first_zero_bit(wl->roles_map, WL12XX_MAX_ROLES); + if (cmd->role_id >= WL12XX_MAX_ROLES) { + ret = -EBUSY; + goto out_free; + } + + memcpy(cmd->mac_address, addr, ETH_ALEN); + cmd->role_type = role_type; + + ret = wl1271_cmd_send(wl, CMD_ROLE_ENABLE, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role enable"); + goto out_free; + } + + __set_bit(cmd->role_id, wl->roles_map); + *role_id = cmd->role_id; + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id) +{ + struct wl12xx_cmd_role_disable *cmd; + int ret; + + wl1271_debug(DEBUG_CMD, "cmd role disable"); + + if (WARN_ON(*role_id == WL12XX_INVALID_ROLE_ID)) + return -ENOENT; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + cmd->role_id = *role_id; + + ret = wl1271_cmd_send(wl, CMD_ROLE_DISABLE, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role disable"); + goto out_free; + } + + __clear_bit(*role_id, wl->roles_map); + *role_id = WL12XX_INVALID_ROLE_ID; + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) +{ + unsigned long flags; + u8 link = find_first_zero_bit(wl->links_map, WL12XX_MAX_LINKS); + if (link >= WL12XX_MAX_LINKS) + return -EBUSY; + + /* these bits are used by op_tx */ + spin_lock_irqsave(&wl->wl_lock, flags); + __set_bit(link, wl->links_map); + __set_bit(link, wlvif->links_map); + spin_unlock_irqrestore(&wl->wl_lock, flags); + *hlid = link; + return 0; +} + +void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) +{ + unsigned long flags; + + if (*hlid == WL12XX_INVALID_LINK_ID) + return; + + /* these bits are used by op_tx */ + spin_lock_irqsave(&wl->wl_lock, flags); + __clear_bit(*hlid, wl->links_map); + __clear_bit(*hlid, wlvif->links_map); + spin_unlock_irqrestore(&wl->wl_lock, flags); + + /* + * At this point op_tx() will not add more packets to the queues. We + * can purge them. + */ + wl1271_tx_reset_link_queues(wl, *hlid); + + *hlid = WL12XX_INVALID_LINK_ID; +} + +static int wl12xx_get_new_session_id(struct wl1271 *wl, + struct wl12xx_vif *wlvif) +{ + if (wlvif->session_counter >= SESSION_COUNTER_MAX) + wlvif->session_counter = 0; + + wlvif->session_counter++; + + return wlvif->session_counter; +} + +static int wl12xx_cmd_role_start_dev(struct wl1271 *wl, + struct wl12xx_vif *wlvif) +{ + struct wl12xx_cmd_role_start *cmd; + int ret; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + wl1271_debug(DEBUG_CMD, "cmd role start dev %d", wlvif->dev_role_id); + + cmd->role_id = wlvif->dev_role_id; + if (wlvif->band == IEEE80211_BAND_5GHZ) + cmd->band = WLCORE_BAND_5GHZ; + cmd->channel = wlvif->channel; + + if (wlvif->dev_hlid == WL12XX_INVALID_LINK_ID) { + ret = wl12xx_allocate_link(wl, wlvif, &wlvif->dev_hlid); + if (ret) + goto out_free; + } + cmd->device.hlid = wlvif->dev_hlid; + cmd->device.session = wl12xx_get_new_session_id(wl, wlvif); + + wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d", + cmd->role_id, cmd->device.hlid, cmd->device.session); + + ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role enable"); + goto err_hlid; + } + + goto out_free; + +err_hlid: + /* clear links on error */ + wl12xx_free_link(wl, wlvif, &wlvif->dev_hlid); + +out_free: + kfree(cmd); + +out: + return ret; +} + +static int wl12xx_cmd_role_stop_dev(struct wl1271 *wl, + struct wl12xx_vif *wlvif) +{ + struct wl12xx_cmd_role_stop *cmd; + int ret; + + if (WARN_ON(wlvif->dev_hlid == WL12XX_INVALID_LINK_ID)) + return -EINVAL; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + wl1271_debug(DEBUG_CMD, "cmd role stop dev"); + + cmd->role_id = wlvif->dev_role_id; + cmd->disc_type = DISCONNECT_IMMEDIATE; + cmd->reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED); + + ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role stop"); + goto out_free; + } + + ret = wl1271_cmd_wait_for_event(wl, ROLE_STOP_COMPLETE_EVENT_ID); + if (ret < 0) { + wl1271_error("cmd role stop dev event completion error"); + goto out_free; + } + + wl12xx_free_link(wl, wlvif, &wlvif->dev_hlid); + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); + struct wl12xx_cmd_role_start *cmd; + int ret; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + wl1271_debug(DEBUG_CMD, "cmd role start sta %d", wlvif->role_id); + + cmd->role_id = wlvif->role_id; + if (wlvif->band == IEEE80211_BAND_5GHZ) + cmd->band = WLCORE_BAND_5GHZ; + cmd->channel = wlvif->channel; + cmd->sta.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); + cmd->sta.beacon_interval = cpu_to_le16(wlvif->beacon_int); + cmd->sta.ssid_type = WL12XX_SSID_TYPE_ANY; + cmd->sta.ssid_len = wlvif->ssid_len; + memcpy(cmd->sta.ssid, wlvif->ssid, wlvif->ssid_len); + memcpy(cmd->sta.bssid, vif->bss_conf.bssid, ETH_ALEN); + cmd->sta.local_rates = cpu_to_le32(wlvif->rate_set); + + if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) { + ret = wl12xx_allocate_link(wl, wlvif, &wlvif->sta.hlid); + if (ret) + goto out_free; + } + cmd->sta.hlid = wlvif->sta.hlid; + cmd->sta.session = wl12xx_get_new_session_id(wl, wlvif); + cmd->sta.remote_rates = cpu_to_le32(wlvif->rate_set); + + wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d " + "basic_rate_set: 0x%x, remote_rates: 0x%x", + wlvif->role_id, cmd->sta.hlid, cmd->sta.session, + wlvif->basic_rate_set, wlvif->rate_set); + + ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role start sta"); + goto err_hlid; + } + + goto out_free; + +err_hlid: + /* clear links on error. */ + wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid); + +out_free: + kfree(cmd); + +out: + return ret; +} + +/* use this function to stop ibss as well */ +int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + struct wl12xx_cmd_role_stop *cmd; + int ret; + + if (WARN_ON(wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)) + return -EINVAL; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + wl1271_debug(DEBUG_CMD, "cmd role stop sta %d", wlvif->role_id); + + cmd->role_id = wlvif->role_id; + cmd->disc_type = DISCONNECT_IMMEDIATE; + cmd->reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED); + + ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role stop sta"); + goto out_free; + } + + wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid); + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + struct wl12xx_cmd_role_start *cmd; + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + int ret; + + wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wlvif->role_id); + + /* trying to use hidden SSID with an old hostapd version */ + if (wlvif->ssid_len == 0 && !bss_conf->hidden_ssid) { + wl1271_error("got a null SSID from beacon/bss"); + ret = -EINVAL; + goto out; + } + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + ret = wl12xx_allocate_link(wl, wlvif, &wlvif->ap.global_hlid); + if (ret < 0) + goto out_free; + + ret = wl12xx_allocate_link(wl, wlvif, &wlvif->ap.bcast_hlid); + if (ret < 0) + goto out_free_global; + + cmd->role_id = wlvif->role_id; + cmd->ap.aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period); + cmd->ap.bss_index = WL1271_AP_BSS_INDEX; + cmd->ap.global_hlid = wlvif->ap.global_hlid; + cmd->ap.broadcast_hlid = wlvif->ap.bcast_hlid; + cmd->ap.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); + cmd->ap.beacon_interval = cpu_to_le16(wlvif->beacon_int); + cmd->ap.dtim_interval = bss_conf->dtim_period; + cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP; + /* FIXME: Change when adding DFS */ + cmd->ap.reset_tsf = 1; /* By default reset AP TSF */ + cmd->channel = wlvif->channel; + + if (!bss_conf->hidden_ssid) { + /* take the SSID from the beacon for backward compatibility */ + cmd->ap.ssid_type = WL12XX_SSID_TYPE_PUBLIC; + cmd->ap.ssid_len = wlvif->ssid_len; + memcpy(cmd->ap.ssid, wlvif->ssid, wlvif->ssid_len); + } else { + cmd->ap.ssid_type = WL12XX_SSID_TYPE_HIDDEN; + cmd->ap.ssid_len = bss_conf->ssid_len; + memcpy(cmd->ap.ssid, bss_conf->ssid, bss_conf->ssid_len); + } + + cmd->ap.local_rates = cpu_to_le32(0xffffffff); + + switch (wlvif->band) { + case IEEE80211_BAND_2GHZ: + cmd->band = WLCORE_BAND_2_4GHZ; + break; + case IEEE80211_BAND_5GHZ: + cmd->band = WLCORE_BAND_5GHZ; + break; + default: + wl1271_warning("ap start - unknown band: %d", (int)wlvif->band); + cmd->band = WLCORE_BAND_2_4GHZ; + break; + } + + ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role start ap"); + goto out_free_bcast; + } + + goto out_free; + +out_free_bcast: + wl12xx_free_link(wl, wlvif, &wlvif->ap.bcast_hlid); + +out_free_global: + wl12xx_free_link(wl, wlvif, &wlvif->ap.global_hlid); + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_cmd_role_stop_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + struct wl12xx_cmd_role_stop *cmd; + int ret; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + wl1271_debug(DEBUG_CMD, "cmd role stop ap %d", wlvif->role_id); + + cmd->role_id = wlvif->role_id; + + ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role stop ap"); + goto out_free; + } + + wl12xx_free_link(wl, wlvif, &wlvif->ap.bcast_hlid); + wl12xx_free_link(wl, wlvif, &wlvif->ap.global_hlid); + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_cmd_role_start_ibss(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); + struct wl12xx_cmd_role_start *cmd; + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + int ret; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + wl1271_debug(DEBUG_CMD, "cmd role start ibss %d", wlvif->role_id); + + cmd->role_id = wlvif->role_id; + if (wlvif->band == IEEE80211_BAND_5GHZ) + cmd->band = WLCORE_BAND_5GHZ; + cmd->channel = wlvif->channel; + cmd->ibss.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); + cmd->ibss.beacon_interval = cpu_to_le16(wlvif->beacon_int); + cmd->ibss.dtim_interval = bss_conf->dtim_period; + cmd->ibss.ssid_type = WL12XX_SSID_TYPE_ANY; + cmd->ibss.ssid_len = wlvif->ssid_len; + memcpy(cmd->ibss.ssid, wlvif->ssid, wlvif->ssid_len); + memcpy(cmd->ibss.bssid, vif->bss_conf.bssid, ETH_ALEN); + cmd->sta.local_rates = cpu_to_le32(wlvif->rate_set); + + if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) { + ret = wl12xx_allocate_link(wl, wlvif, &wlvif->sta.hlid); + if (ret) + goto out_free; + } + cmd->ibss.hlid = wlvif->sta.hlid; + cmd->ibss.remote_rates = cpu_to_le32(wlvif->rate_set); + + wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d " + "basic_rate_set: 0x%x, remote_rates: 0x%x", + wlvif->role_id, cmd->sta.hlid, cmd->sta.session, + wlvif->basic_rate_set, wlvif->rate_set); + + wl1271_debug(DEBUG_CMD, "vif->bss_conf.bssid = %pM", + vif->bss_conf.bssid); + + ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role enable"); + goto err_hlid; + } + + goto out_free; + +err_hlid: + /* clear links on error. */ + wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid); + +out_free: + kfree(cmd); + +out: + return ret; +} + + +/** + * send test command to firmware + * + * @wl: wl struct + * @buf: buffer containing the command, with all headers, must work with dma + * @len: length of the buffer + * @answer: is answer needed + */ +int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer) +{ + int ret; + size_t res_len = 0; + + wl1271_debug(DEBUG_CMD, "cmd test"); + + if (answer) + res_len = buf_len; + + ret = wl1271_cmd_send(wl, CMD_TEST, buf, buf_len, res_len); + + if (ret < 0) { + wl1271_warning("TEST command failed"); + return ret; + } + + return ret; +} +EXPORT_SYMBOL_GPL(wl1271_cmd_test); + +/** + * read acx from firmware + * + * @wl: wl struct + * @id: acx id + * @buf: buffer for the response, including all headers, must work with dma + * @len: length of buf + */ +int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len) +{ + struct acx_header *acx = buf; + int ret; + + wl1271_debug(DEBUG_CMD, "cmd interrogate"); + + acx->id = cpu_to_le16(id); + + /* payload length, does not include any headers */ + acx->len = cpu_to_le16(len - sizeof(*acx)); + + ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx), len); + if (ret < 0) + wl1271_error("INTERROGATE command failed"); + + return ret; +} + +/** + * write acx value to firmware + * + * @wl: wl struct + * @id: acx id + * @buf: buffer containing acx, including all headers, must work with dma + * @len: length of buf + */ +int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) +{ + struct acx_header *acx = buf; + int ret; + + wl1271_debug(DEBUG_CMD, "cmd configure (%d)", id); + + acx->id = cpu_to_le16(id); + + /* payload length, does not include any headers */ + acx->len = cpu_to_le16(len - sizeof(*acx)); + + ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len, 0); + if (ret < 0) { + wl1271_warning("CONFIGURE command NOK"); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(wl1271_cmd_configure); + +int wl1271_cmd_data_path(struct wl1271 *wl, bool enable) +{ + struct cmd_enabledisable_path *cmd; + int ret; + u16 cmd_rx, cmd_tx; + + wl1271_debug(DEBUG_CMD, "cmd data path"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + /* the channel here is only used for calibration, so hardcoded to 1 */ + cmd->channel = 1; + + if (enable) { + cmd_rx = CMD_ENABLE_RX; + cmd_tx = CMD_ENABLE_TX; + } else { + cmd_rx = CMD_DISABLE_RX; + cmd_tx = CMD_DISABLE_TX; + } + + ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("rx %s cmd for channel %d failed", + enable ? "start" : "stop", cmd->channel); + goto out; + } + + wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d", + enable ? "start" : "stop", cmd->channel); + + ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("tx %s cmd for channel %d failed", + enable ? "start" : "stop", cmd->channel); + goto out; + } + + wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d", + enable ? "start" : "stop", cmd->channel); + +out: + kfree(cmd); + return ret; +} + +int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 ps_mode, u16 auto_ps_timeout) +{ + struct wl1271_cmd_ps_params *ps_params = NULL; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd set ps mode"); + + ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); + if (!ps_params) { + ret = -ENOMEM; + goto out; + } + + ps_params->role_id = wlvif->role_id; + ps_params->ps_mode = ps_mode; + ps_params->auto_ps_timeout = auto_ps_timeout; + + ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, + sizeof(*ps_params), 0); + if (ret < 0) { + wl1271_error("cmd set_ps_mode failed"); + goto out; + } + +out: + kfree(ps_params); + return ret; +} + +int wl1271_cmd_template_set(struct wl1271 *wl, u8 role_id, + u16 template_id, void *buf, size_t buf_len, + int index, u32 rates) +{ + struct wl1271_cmd_template_set *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd template_set %d (role %d)", + template_id, role_id); + + WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE); + buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + /* during initialization wlvif is NULL */ + cmd->role_id = role_id; + cmd->len = cpu_to_le16(buf_len); + cmd->template_type = template_id; + cmd->enabled_rates = cpu_to_le32(rates); + cmd->short_retry_limit = wl->conf.tx.tmpl_short_retry_limit; + cmd->long_retry_limit = wl->conf.tx.tmpl_long_retry_limit; + cmd->index = index; + + if (buf) + memcpy(cmd->template_data, buf, buf_len); + + ret = wl1271_cmd_send(wl, CMD_SET_TEMPLATE, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_warning("cmd set_template failed: %d", ret); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + struct sk_buff *skb = NULL; + int size; + void *ptr; + int ret = -ENOMEM; + + + if (wlvif->bss_type == BSS_TYPE_IBSS) { + size = sizeof(struct wl12xx_null_data_template); + ptr = NULL; + } else { + skb = ieee80211_nullfunc_get(wl->hw, + wl12xx_wlvif_to_vif(wlvif)); + if (!skb) + goto out; + size = skb->len; + ptr = skb->data; + } + + ret = wl1271_cmd_template_set(wl, wlvif->role_id, + CMD_TEMPL_NULL_DATA, ptr, size, 0, + wlvif->basic_rate); + +out: + dev_kfree_skb(skb); + if (ret) + wl1271_warning("cmd buld null data failed %d", ret); + + return ret; + +} + +int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl, + struct wl12xx_vif *wlvif) +{ + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); + struct sk_buff *skb = NULL; + int ret = -ENOMEM; + + skb = ieee80211_nullfunc_get(wl->hw, vif); + if (!skb) + goto out; + + ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_KLV, + skb->data, skb->len, + CMD_TEMPL_KLV_IDX_NULL_DATA, + wlvif->basic_rate); + +out: + dev_kfree_skb(skb); + if (ret) + wl1271_warning("cmd build klv null data failed %d", ret); + + return ret; + +} + +int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u16 aid) +{ + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); + struct sk_buff *skb; + int ret = 0; + + skb = ieee80211_pspoll_get(wl->hw, vif); + if (!skb) + goto out; + + ret = wl1271_cmd_template_set(wl, wlvif->role_id, + CMD_TEMPL_PS_POLL, skb->data, + skb->len, 0, wlvif->basic_rate_set); + +out: + dev_kfree_skb(skb); + return ret; +} + +int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 role_id, u8 band, + const u8 *ssid, size_t ssid_len, + const u8 *ie, size_t ie_len) +{ + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); + struct sk_buff *skb; + int ret; + u32 rate; + + skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len, + ie, ie_len); + if (!skb) { + ret = -ENOMEM; + goto out; + } + + wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len); + + rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); + if (band == IEEE80211_BAND_2GHZ) + ret = wl1271_cmd_template_set(wl, role_id, + CMD_TEMPL_CFG_PROBE_REQ_2_4, + skb->data, skb->len, 0, rate); + else + ret = wl1271_cmd_template_set(wl, role_id, + CMD_TEMPL_CFG_PROBE_REQ_5, + skb->data, skb->len, 0, rate); + +out: + dev_kfree_skb(skb); + return ret; +} + +struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + struct sk_buff *skb) +{ + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); + int ret; + u32 rate; + + if (!skb) + skb = ieee80211_ap_probereq_get(wl->hw, vif); + if (!skb) + goto out; + + wl1271_dump(DEBUG_SCAN, "AP PROBE REQ: ", skb->data, skb->len); + + rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[wlvif->band]); + if (wlvif->band == IEEE80211_BAND_2GHZ) + ret = wl1271_cmd_template_set(wl, wlvif->role_id, + CMD_TEMPL_CFG_PROBE_REQ_2_4, + skb->data, skb->len, 0, rate); + else + ret = wl1271_cmd_template_set(wl, wlvif->role_id, + CMD_TEMPL_CFG_PROBE_REQ_5, + skb->data, skb->len, 0, rate); + + if (ret < 0) + wl1271_error("Unable to set ap probe request template."); + +out: + return skb; +} + +int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + int ret, extra; + u16 fc; + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); + struct sk_buff *skb; + struct wl12xx_arp_rsp_template *tmpl; + struct ieee80211_hdr_3addr *hdr; + struct arphdr *arp_hdr; + + skb = dev_alloc_skb(sizeof(*hdr) + sizeof(__le16) + sizeof(*tmpl) + + WL1271_EXTRA_SPACE_MAX); + if (!skb) { + wl1271_error("failed to allocate buffer for arp rsp template"); + return -ENOMEM; + } + + skb_reserve(skb, sizeof(*hdr) + WL1271_EXTRA_SPACE_MAX); + + tmpl = (struct wl12xx_arp_rsp_template *)skb_put(skb, sizeof(*tmpl)); + memset(tmpl, 0, sizeof(tmpl)); + + /* llc layer */ + memcpy(tmpl->llc_hdr, rfc1042_header, sizeof(rfc1042_header)); + tmpl->llc_type = cpu_to_be16(ETH_P_ARP); + + /* arp header */ + arp_hdr = &tmpl->arp_hdr; + arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER); + arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP); + arp_hdr->ar_hln = ETH_ALEN; + arp_hdr->ar_pln = 4; + arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY); + + /* arp payload */ + memcpy(tmpl->sender_hw, vif->addr, ETH_ALEN); + tmpl->sender_ip = wlvif->ip_addr; + + /* encryption space */ + switch (wlvif->encryption_type) { + case KEY_TKIP: + extra = WL1271_EXTRA_SPACE_TKIP; + break; + case KEY_AES: + extra = WL1271_EXTRA_SPACE_AES; + break; + case KEY_NONE: + case KEY_WEP: + case KEY_GEM: + extra = 0; + break; + default: + wl1271_warning("Unknown encryption type: %d", + wlvif->encryption_type); + ret = -EINVAL; + goto out; + } + + if (extra) { + u8 *space = skb_push(skb, extra); + memset(space, 0, extra); + } + + /* QoS header - BE */ + if (wlvif->sta.qos) + memset(skb_push(skb, sizeof(__le16)), 0, sizeof(__le16)); + + /* mac80211 header */ + hdr = (struct ieee80211_hdr_3addr *)skb_push(skb, sizeof(*hdr)); + memset(hdr, 0, sizeof(hdr)); + fc = IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS; + if (wlvif->sta.qos) + fc |= IEEE80211_STYPE_QOS_DATA; + else + fc |= IEEE80211_STYPE_DATA; + if (wlvif->encryption_type != KEY_NONE) + fc |= IEEE80211_FCTL_PROTECTED; + + hdr->frame_control = cpu_to_le16(fc); + memcpy(hdr->addr1, vif->bss_conf.bssid, ETH_ALEN); + memcpy(hdr->addr2, vif->addr, ETH_ALEN); + memset(hdr->addr3, 0xff, ETH_ALEN); + + ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_ARP_RSP, + skb->data, skb->len, 0, + wlvif->basic_rate); +out: + dev_kfree_skb(skb); + return ret; +} + +int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif) +{ + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + struct ieee80211_qos_hdr template; + + memset(&template, 0, sizeof(template)); + + memcpy(template.addr1, vif->bss_conf.bssid, ETH_ALEN); + memcpy(template.addr2, vif->addr, ETH_ALEN); + memcpy(template.addr3, vif->bss_conf.bssid, ETH_ALEN); + + template.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_STYPE_QOS_NULLFUNC | + IEEE80211_FCTL_TODS); + + /* FIXME: not sure what priority to use here */ + template.qos_ctrl = cpu_to_le16(0); + + return wl1271_cmd_template_set(wl, wlvif->role_id, + CMD_TEMPL_QOS_NULL_DATA, &template, + sizeof(template), 0, + wlvif->basic_rate); +} + +int wl12xx_cmd_set_default_wep_key(struct wl1271 *wl, u8 id, u8 hlid) +{ + struct wl1271_cmd_set_keys *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->hlid = hlid; + cmd->key_id = id; + cmd->lid_key_type = WEP_DEFAULT_LID_TYPE; + cmd->key_action = cpu_to_le16(KEY_SET_ID); + cmd->key_type = KEY_WEP; + + ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_warning("cmd set_default_wep_key failed: %d", ret); + goto out; + } + +out: + kfree(cmd); + + return ret; +} + +int wl1271_cmd_set_sta_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u16 action, u8 id, u8 key_type, + u8 key_size, const u8 *key, const u8 *addr, + u32 tx_seq_32, u16 tx_seq_16) +{ + struct wl1271_cmd_set_keys *cmd; + int ret = 0; + + /* hlid might have already been deleted */ + if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) + return 0; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->hlid = wlvif->sta.hlid; + + if (key_type == KEY_WEP) + cmd->lid_key_type = WEP_DEFAULT_LID_TYPE; + else if (is_broadcast_ether_addr(addr)) + cmd->lid_key_type = BROADCAST_LID_TYPE; + else + cmd->lid_key_type = UNICAST_LID_TYPE; + + cmd->key_action = cpu_to_le16(action); + cmd->key_size = key_size; + cmd->key_type = key_type; + + cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16); + cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32); + + cmd->key_id = id; + + if (key_type == KEY_TKIP) { + /* + * We get the key in the following form: + * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) + * but the target is expecting: + * TKIP - RX MIC - TX MIC + */ + memcpy(cmd->key, key, 16); + memcpy(cmd->key + 16, key + 24, 8); + memcpy(cmd->key + 24, key + 16, 8); + + } else { + memcpy(cmd->key, key, key_size); + } + + wl1271_dump(DEBUG_CRYPT, "TARGET KEY: ", cmd, sizeof(*cmd)); + + ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_warning("could not set keys"); + goto out; + } + +out: + kfree(cmd); + + return ret; +} + +/* + * TODO: merge with sta/ibss into 1 set_key function. + * note there are slight diffs + */ +int wl1271_cmd_set_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u16 action, u8 id, u8 key_type, + u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, + u16 tx_seq_16) +{ + struct wl1271_cmd_set_keys *cmd; + int ret = 0; + u8 lid_type; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + if (hlid == wlvif->ap.bcast_hlid) { + if (key_type == KEY_WEP) + lid_type = WEP_DEFAULT_LID_TYPE; + else + lid_type = BROADCAST_LID_TYPE; + } else { + lid_type = UNICAST_LID_TYPE; + } + + wl1271_debug(DEBUG_CRYPT, "ap key action: %d id: %d lid: %d type: %d" + " hlid: %d", (int)action, (int)id, (int)lid_type, + (int)key_type, (int)hlid); + + cmd->lid_key_type = lid_type; + cmd->hlid = hlid; + cmd->key_action = cpu_to_le16(action); + cmd->key_size = key_size; + cmd->key_type = key_type; + cmd->key_id = id; + cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16); + cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32); + + if (key_type == KEY_TKIP) { + /* + * We get the key in the following form: + * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) + * but the target is expecting: + * TKIP - RX MIC - TX MIC + */ + memcpy(cmd->key, key, 16); + memcpy(cmd->key + 16, key + 24, 8); + memcpy(cmd->key + 24, key + 16, 8); + } else { + memcpy(cmd->key, key, key_size); + } + + wl1271_dump(DEBUG_CRYPT, "TARGET AP KEY: ", cmd, sizeof(*cmd)); + + ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_warning("could not set ap keys"); + goto out; + } + +out: + kfree(cmd); + return ret; +} + +int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid) +{ + struct wl12xx_cmd_set_peer_state *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd set peer state (hlid=%d)", hlid); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->hlid = hlid; + cmd->state = WL1271_CMD_STA_STATE_CONNECTED; + + ret = wl1271_cmd_send(wl, CMD_SET_PEER_STATE, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send set peer state command"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif, + struct ieee80211_sta *sta, u8 hlid) +{ + struct wl12xx_cmd_add_peer *cmd; + int i, ret; + u32 sta_rates; + + wl1271_debug(DEBUG_CMD, "cmd add peer %d", (int)hlid); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + memcpy(cmd->addr, sta->addr, ETH_ALEN); + cmd->bss_index = WL1271_AP_BSS_INDEX; + cmd->aid = sta->aid; + cmd->hlid = hlid; + cmd->sp_len = sta->max_sp; + cmd->wmm = sta->wme ? 1 : 0; + + for (i = 0; i < NUM_ACCESS_CATEGORIES_COPY; i++) + if (sta->wme && (sta->uapsd_queues & BIT(i))) + cmd->psd_type[i] = WL1271_PSD_UPSD_TRIGGER; + else + cmd->psd_type[i] = WL1271_PSD_LEGACY; + + sta_rates = sta->supp_rates[wlvif->band]; + if (sta->ht_cap.ht_supported) + sta_rates |= sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET; + + cmd->supported_rates = + cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates, + wlvif->band)); + + wl1271_debug(DEBUG_CMD, "new peer rates=0x%x queues=0x%x", + cmd->supported_rates, sta->uapsd_queues); + + ret = wl1271_cmd_send(wl, CMD_ADD_PEER, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd add peer"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid) +{ + struct wl12xx_cmd_remove_peer *cmd; + int ret; + + wl1271_debug(DEBUG_CMD, "cmd remove peer %d", (int)hlid); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->hlid = hlid; + /* We never send a deauth, mac80211 is in charge of this */ + cmd->reason_opcode = 0; + cmd->send_deauth_flag = 0; + + ret = wl1271_cmd_send(wl, CMD_REMOVE_PEER, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd remove peer"); + goto out_free; + } + + /* + * We are ok with a timeout here. The event is sometimes not sent + * due to a firmware bug. + */ + wl1271_cmd_wait_for_event_or_timeout(wl, + PEER_REMOVE_COMPLETE_EVENT_ID); + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_cmd_config_fwlog(struct wl1271 *wl) +{ + struct wl12xx_cmd_config_fwlog *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd config firmware logger"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->logger_mode = wl->conf.fwlog.mode; + cmd->log_severity = wl->conf.fwlog.severity; + cmd->timestamp = wl->conf.fwlog.timestamp; + cmd->output = wl->conf.fwlog.output; + cmd->threshold = wl->conf.fwlog.threshold; + + ret = wl1271_cmd_send(wl, CMD_CONFIG_FWLOGGER, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send config firmware logger command"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_cmd_start_fwlog(struct wl1271 *wl) +{ + struct wl12xx_cmd_start_fwlog *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd start firmware logger"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + ret = wl1271_cmd_send(wl, CMD_START_FWLOGGER, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send start firmware logger command"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_cmd_stop_fwlog(struct wl1271 *wl) +{ + struct wl12xx_cmd_stop_fwlog *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd stop firmware logger"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + ret = wl1271_cmd_send(wl, CMD_STOP_FWLOGGER, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send stop firmware logger command"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +static int wl12xx_cmd_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 role_id) +{ + struct wl12xx_cmd_roc *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", wlvif->channel, role_id); + + if (WARN_ON(role_id == WL12XX_INVALID_ROLE_ID)) + return -EINVAL; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->role_id = role_id; + cmd->channel = wlvif->channel; + switch (wlvif->band) { + case IEEE80211_BAND_2GHZ: + cmd->band = WLCORE_BAND_2_4GHZ; + break; + case IEEE80211_BAND_5GHZ: + cmd->band = WLCORE_BAND_5GHZ; + break; + default: + wl1271_error("roc - unknown band: %d", (int)wlvif->band); + ret = -EINVAL; + goto out_free; + } + + + ret = wl1271_cmd_send(wl, CMD_REMAIN_ON_CHANNEL, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send ROC command"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +static int wl12xx_cmd_croc(struct wl1271 *wl, u8 role_id) +{ + struct wl12xx_cmd_croc *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd croc (%d)", role_id); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + cmd->role_id = role_id; + + ret = wl1271_cmd_send(wl, CMD_CANCEL_REMAIN_ON_CHANNEL, cmd, + sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send ROC command"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id) +{ + int ret = 0; + + if (WARN_ON(test_bit(role_id, wl->roc_map))) + return 0; + + ret = wl12xx_cmd_roc(wl, wlvif, role_id); + if (ret < 0) + goto out; + + ret = wl1271_cmd_wait_for_event(wl, + REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID); + if (ret < 0) { + wl1271_error("cmd roc event completion error"); + goto out; + } + + __set_bit(role_id, wl->roc_map); +out: + return ret; +} + +int wl12xx_croc(struct wl1271 *wl, u8 role_id) +{ + int ret = 0; + + if (WARN_ON(!test_bit(role_id, wl->roc_map))) + return 0; + + ret = wl12xx_cmd_croc(wl, role_id); + if (ret < 0) + goto out; + + __clear_bit(role_id, wl->roc_map); + + /* + * Rearm the tx watchdog when removing the last ROC. This prevents + * recoveries due to just finished ROCs - when Tx hasn't yet had + * a chance to get out. + */ + if (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) >= WL12XX_MAX_ROLES) + wl12xx_rearm_tx_watchdog_locked(wl); +out: + return ret; +} + +int wl12xx_cmd_channel_switch(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + struct ieee80211_channel_switch *ch_switch) +{ + struct wl12xx_cmd_channel_switch *cmd; + int ret; + + wl1271_debug(DEBUG_ACX, "cmd channel switch"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->role_id = wlvif->role_id; + cmd->channel = ch_switch->channel->hw_value; + cmd->switch_time = ch_switch->count; + cmd->stop_tx = ch_switch->block_tx; + + /* FIXME: control from mac80211 in the future */ + cmd->post_switch_tx_disable = 0; /* Enable TX on the target channel */ + + ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send channel switch command"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl) +{ + struct wl12xx_cmd_stop_channel_switch *cmd; + int ret; + + wl1271_debug(DEBUG_ACX, "cmd stop channel switch"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + ret = wl1271_cmd_send(wl, CMD_STOP_CHANNEL_SWICTH, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to stop channel switch command"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} + +/* start dev role and roc on its channel */ +int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + int ret; + + if (WARN_ON(!(wlvif->bss_type == BSS_TYPE_STA_BSS || + wlvif->bss_type == BSS_TYPE_IBSS))) + return -EINVAL; + + ret = wl12xx_cmd_role_start_dev(wl, wlvif); + if (ret < 0) + goto out; + + ret = wl12xx_roc(wl, wlvif, wlvif->dev_role_id); + if (ret < 0) + goto out_stop; + + return 0; + +out_stop: + wl12xx_cmd_role_stop_dev(wl, wlvif); +out: + return ret; +} + +/* croc dev hlid, and stop the role */ +int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + int ret; + + if (WARN_ON(!(wlvif->bss_type == BSS_TYPE_STA_BSS || + wlvif->bss_type == BSS_TYPE_IBSS))) + return -EINVAL; + + /* flush all pending packets */ + wl1271_tx_work_locked(wl); + + if (test_bit(wlvif->dev_role_id, wl->roc_map)) { + ret = wl12xx_croc(wl, wlvif->dev_role_id); + if (ret < 0) + goto out; + } + + ret = wl12xx_cmd_role_stop_dev(wl, wlvif); + if (ret < 0) + goto out; +out: + return ret; +} diff --git a/trunk/drivers/net/wireless/ti/wlcore/cmd.h b/trunk/drivers/net/wireless/ti/wlcore/cmd.h new file mode 100644 index 000000000000..a46ae07cb77e --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wlcore/cmd.h @@ -0,0 +1,646 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __CMD_H__ +#define __CMD_H__ + +#include "wlcore.h" + +struct acx_header; + +int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, + size_t res_len); +int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type, + u8 *role_id); +int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id); +int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif); +int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif); +int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif); +int wl12xx_cmd_role_stop_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif); +int wl12xx_cmd_role_start_ibss(struct wl1271 *wl, struct wl12xx_vif *wlvif); +int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif); +int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif); +int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); +int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); +int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len); +int wl1271_cmd_data_path(struct wl1271 *wl, bool enable); +int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 ps_mode, u16 auto_ps_timeout); +int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, + size_t len); +int wl1271_cmd_template_set(struct wl1271 *wl, u8 role_id, + u16 template_id, void *buf, size_t buf_len, + int index, u32 rates); +int wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif); +int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u16 aid); +int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 role_id, u8 band, + const u8 *ssid, size_t ssid_len, + const u8 *ie, size_t ie_len); +struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + struct sk_buff *skb); +int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif); +int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif); +int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl, + struct wl12xx_vif *wlvif); +int wl12xx_cmd_set_default_wep_key(struct wl1271 *wl, u8 id, u8 hlid); +int wl1271_cmd_set_sta_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u16 action, u8 id, u8 key_type, + u8 key_size, const u8 *key, const u8 *addr, + u32 tx_seq_32, u16 tx_seq_16); +int wl1271_cmd_set_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u16 action, u8 id, u8 key_type, + u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, + u16 tx_seq_16); +int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid); +int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id); +int wl12xx_croc(struct wl1271 *wl, u8 role_id); +int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif, + struct ieee80211_sta *sta, u8 hlid); +int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid); +int wl12xx_cmd_config_fwlog(struct wl1271 *wl); +int wl12xx_cmd_start_fwlog(struct wl1271 *wl); +int wl12xx_cmd_stop_fwlog(struct wl1271 *wl); +int wl12xx_cmd_channel_switch(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + struct ieee80211_channel_switch *ch_switch); +int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl); +int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 *hlid); +void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid); + +enum wl1271_commands { + CMD_INTERROGATE = 1, /* use this to read information elements */ + CMD_CONFIGURE = 2, /* use this to write information elements */ + CMD_ENABLE_RX = 3, + CMD_ENABLE_TX = 4, + CMD_DISABLE_RX = 5, + CMD_DISABLE_TX = 6, + CMD_SCAN = 7, + CMD_STOP_SCAN = 8, + CMD_SET_KEYS = 9, + CMD_READ_MEMORY = 10, + CMD_WRITE_MEMORY = 11, + CMD_SET_TEMPLATE = 12, + CMD_TEST = 13, + CMD_NOISE_HIST = 14, + CMD_QUIET_ELEMENT_SET_STATE = 15, + CMD_SET_BCN_MODE = 16, + + CMD_MEASUREMENT = 17, + CMD_STOP_MEASUREMENT = 18, + CMD_SET_PS_MODE = 19, + CMD_CHANNEL_SWITCH = 20, + CMD_STOP_CHANNEL_SWICTH = 21, + CMD_AP_DISCOVERY = 22, + CMD_STOP_AP_DISCOVERY = 23, + CMD_HEALTH_CHECK = 24, + CMD_DEBUG = 25, + CMD_TRIGGER_SCAN_TO = 26, + CMD_CONNECTION_SCAN_CFG = 27, + CMD_CONNECTION_SCAN_SSID_CFG = 28, + CMD_START_PERIODIC_SCAN = 29, + CMD_STOP_PERIODIC_SCAN = 30, + CMD_SET_PEER_STATE = 31, + CMD_REMAIN_ON_CHANNEL = 32, + CMD_CANCEL_REMAIN_ON_CHANNEL = 33, + CMD_CONFIG_FWLOGGER = 34, + CMD_START_FWLOGGER = 35, + CMD_STOP_FWLOGGER = 36, + + /* Access point commands */ + CMD_ADD_PEER = 37, + CMD_REMOVE_PEER = 38, + + /* Role API */ + CMD_ROLE_ENABLE = 39, + CMD_ROLE_DISABLE = 40, + CMD_ROLE_START = 41, + CMD_ROLE_STOP = 42, + + /* DFS */ + CMD_START_RADAR_DETECTION = 43, + CMD_STOP_RADAR_DETECTION = 44, + + /* WIFI Direct */ + CMD_WFD_START_DISCOVERY = 45, + CMD_WFD_STOP_DISCOVERY = 46, + CMD_WFD_ATTRIBUTE_CONFIG = 47, + CMD_NOP = 48, + CMD_LAST_COMMAND, + + MAX_COMMAND_ID = 0xFFFF, +}; + +#define MAX_CMD_PARAMS 572 + +enum { + CMD_TEMPL_KLV_IDX_NULL_DATA = 0, + CMD_TEMPL_KLV_IDX_MAX = 4 +}; + +enum cmd_templ { + CMD_TEMPL_NULL_DATA = 0, + CMD_TEMPL_BEACON, + CMD_TEMPL_CFG_PROBE_REQ_2_4, + CMD_TEMPL_CFG_PROBE_REQ_5, + CMD_TEMPL_PROBE_RESPONSE, + CMD_TEMPL_QOS_NULL_DATA, + CMD_TEMPL_PS_POLL, + CMD_TEMPL_KLV, + CMD_TEMPL_DISCONNECT, + CMD_TEMPL_PROBE_REQ_2_4, /* for firmware internal use only */ + CMD_TEMPL_PROBE_REQ_5, /* for firmware internal use only */ + CMD_TEMPL_BAR, /* for firmware internal use only */ + CMD_TEMPL_CTS, /* + * For CTS-to-self (FastCTS) mechanism + * for BT/WLAN coexistence (SoftGemini). */ + CMD_TEMPL_AP_BEACON, + CMD_TEMPL_AP_PROBE_RESPONSE, + CMD_TEMPL_ARP_RSP, + CMD_TEMPL_DEAUTH_AP, + CMD_TEMPL_TEMPORARY, + CMD_TEMPL_LINK_MEASUREMENT_REPORT, + + CMD_TEMPL_MAX = 0xff +}; + +/* unit ms */ +#define WL1271_COMMAND_TIMEOUT 2000 +#define WL1271_CMD_TEMPL_DFLT_SIZE 252 +#define WL1271_CMD_TEMPL_MAX_SIZE 512 +#define WL1271_EVENT_TIMEOUT 750 + +struct wl1271_cmd_header { + __le16 id; + __le16 status; + /* payload */ + u8 data[0]; +} __packed; + +#define WL1271_CMD_MAX_PARAMS 572 + +struct wl1271_command { + struct wl1271_cmd_header header; + u8 parameters[WL1271_CMD_MAX_PARAMS]; +} __packed; + +enum { + CMD_MAILBOX_IDLE = 0, + CMD_STATUS_SUCCESS = 1, + CMD_STATUS_UNKNOWN_CMD = 2, + CMD_STATUS_UNKNOWN_IE = 3, + CMD_STATUS_REJECT_MEAS_SG_ACTIVE = 11, + CMD_STATUS_RX_BUSY = 13, + CMD_STATUS_INVALID_PARAM = 14, + CMD_STATUS_TEMPLATE_TOO_LARGE = 15, + CMD_STATUS_OUT_OF_MEMORY = 16, + CMD_STATUS_STA_TABLE_FULL = 17, + CMD_STATUS_RADIO_ERROR = 18, + CMD_STATUS_WRONG_NESTING = 19, + CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/ + CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ + CMD_STATUS_TEMPLATE_OOM = 23, + CMD_STATUS_NO_RX_BA_SESSION = 24, + MAX_COMMAND_STATUS = 0xff +}; + +#define CMDMBOX_HEADER_LEN 4 +#define CMDMBOX_INFO_ELEM_HEADER_LEN 4 + +enum { + BSS_TYPE_IBSS = 0, + BSS_TYPE_STA_BSS = 2, + BSS_TYPE_AP_BSS = 3, + MAX_BSS_TYPE = 0xFF +}; + +#define WL1271_JOIN_CMD_CTRL_TX_FLUSH 0x80 /* Firmware flushes all Tx */ +#define WL1271_JOIN_CMD_TX_SESSION_OFFSET 1 +#define WL1271_JOIN_CMD_BSS_TYPE_5GHZ 0x10 + +struct wl12xx_cmd_role_enable { + struct wl1271_cmd_header header; + + u8 role_id; + u8 role_type; + u8 mac_address[ETH_ALEN]; +} __packed; + +struct wl12xx_cmd_role_disable { + struct wl1271_cmd_header header; + + u8 role_id; + u8 padding[3]; +} __packed; + +enum wlcore_band { + WLCORE_BAND_2_4GHZ = 0, + WLCORE_BAND_5GHZ = 1, + WLCORE_BAND_JAPAN_4_9_GHZ = 2, + WLCORE_BAND_DEFAULT = WLCORE_BAND_2_4GHZ, + WLCORE_BAND_INVALID = 0x7E, + WLCORE_BAND_MAX_RADIO = 0x7F, +}; + +struct wl12xx_cmd_role_start { + struct wl1271_cmd_header header; + + u8 role_id; + u8 band; + u8 channel; + u8 padding; + + union { + struct { + u8 hlid; + u8 session; + u8 padding_1[54]; + } __packed device; + /* sta & p2p_cli use the same struct */ + struct { + u8 bssid[ETH_ALEN]; + u8 hlid; /* data hlid */ + u8 session; + __le32 remote_rates; /* remote supported rates */ + + /* + * The target uses this field to determine the rate at + * which to transmit control frame responses (such as + * ACK or CTS frames). + */ + __le32 basic_rate_set; + __le32 local_rates; /* local supported rates */ + + u8 ssid_type; + u8 ssid_len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + + __le16 beacon_interval; /* in TBTTs */ + } __packed sta; + struct { + u8 bssid[ETH_ALEN]; + u8 hlid; /* data hlid */ + u8 dtim_interval; + __le32 remote_rates; /* remote supported rates */ + + __le32 basic_rate_set; + __le32 local_rates; /* local supported rates */ + + u8 ssid_type; + u8 ssid_len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + + __le16 beacon_interval; /* in TBTTs */ + + u8 padding_1[4]; + } __packed ibss; + /* ap & p2p_go use the same struct */ + struct { + __le16 aging_period; /* in secs */ + u8 beacon_expiry; /* in ms */ + u8 bss_index; + /* The host link id for the AP's global queue */ + u8 global_hlid; + /* The host link id for the AP's broadcast queue */ + u8 broadcast_hlid; + + __le16 beacon_interval; /* in TBTTs */ + + __le32 basic_rate_set; + __le32 local_rates; /* local supported rates */ + + u8 dtim_interval; + + u8 ssid_type; + u8 ssid_len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + + u8 reset_tsf; + + u8 padding_1[4]; + } __packed ap; + }; +} __packed; + +struct wl12xx_cmd_role_stop { + struct wl1271_cmd_header header; + + u8 role_id; + u8 disc_type; /* only STA and P2P_CLI */ + __le16 reason; /* only STA and P2P_CLI */ +} __packed; + +struct cmd_enabledisable_path { + struct wl1271_cmd_header header; + + u8 channel; + u8 padding[3]; +} __packed; + +#define WL1271_RATE_AUTOMATIC 0 + +struct wl1271_cmd_template_set { + struct wl1271_cmd_header header; + + u8 role_id; + u8 template_type; + __le16 len; + u8 index; /* relevant only for KLV_TEMPLATE type */ + u8 padding[3]; + + __le32 enabled_rates; + u8 short_retry_limit; + u8 long_retry_limit; + u8 aflags; + u8 reserved; + + u8 template_data[WL1271_CMD_TEMPL_MAX_SIZE]; +} __packed; + +#define TIM_ELE_ID 5 +#define PARTIAL_VBM_MAX 251 + +struct wl1271_tim { + u8 identity; + u8 length; + u8 dtim_count; + u8 dtim_period; + u8 bitmap_ctrl; + u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */ +} __packed; + +enum wl1271_cmd_ps_mode { + STATION_AUTO_PS_MODE, /* Dynamic Power Save */ + STATION_ACTIVE_MODE, + STATION_POWER_SAVE_MODE +}; + +struct wl1271_cmd_ps_params { + struct wl1271_cmd_header header; + + u8 role_id; + u8 ps_mode; /* STATION_* */ + u16 auto_ps_timeout; +} __packed; + +/* HW encryption keys */ +#define NUM_ACCESS_CATEGORIES_COPY 4 + +enum wl1271_cmd_key_action { + KEY_ADD_OR_REPLACE = 1, + KEY_REMOVE = 2, + KEY_SET_ID = 3, + MAX_KEY_ACTION = 0xffff, +}; + +enum wl1271_cmd_lid_key_type { + UNICAST_LID_TYPE = 0, + BROADCAST_LID_TYPE = 1, + WEP_DEFAULT_LID_TYPE = 2 +}; + +enum wl1271_cmd_key_type { + KEY_NONE = 0, + KEY_WEP = 1, + KEY_TKIP = 2, + KEY_AES = 3, + KEY_GEM = 4, +}; + +struct wl1271_cmd_set_keys { + struct wl1271_cmd_header header; + + /* + * Indicates whether the HLID is a unicast key set + * or broadcast key set. A special value 0xFF is + * used to indicate that the HLID is on WEP-default + * (multi-hlids). of type wl1271_cmd_lid_key_type. + */ + u8 hlid; + + /* + * In WEP-default network (hlid == 0xFF) used to + * indicate which network STA/IBSS/AP role should be + * changed + */ + u8 lid_key_type; + + /* + * Key ID - For TKIP and AES key types, this field + * indicates the value that should be inserted into + * the KeyID field of frames transmitted using this + * key entry. For broadcast keys the index use as a + * marker for TX/RX key. + * For WEP default network (HLID=0xFF), this field + * indicates the ID of the key to add or remove. + */ + u8 key_id; + u8 reserved_1; + + /* key_action_e */ + __le16 key_action; + + /* key size in bytes */ + u8 key_size; + + /* key_type_e */ + u8 key_type; + + /* This field holds the security key data to add to the STA table */ + u8 key[MAX_KEY_SIZE]; + __le16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; + __le32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; +} __packed; + +struct wl1271_cmd_test_header { + u8 id; + u8 padding[3]; +} __packed; + +enum wl1271_channel_tune_bands { + WL1271_CHANNEL_TUNE_BAND_2_4, + WL1271_CHANNEL_TUNE_BAND_5, + WL1271_CHANNEL_TUNE_BAND_4_9 +}; + +#define WL1271_PD_REFERENCE_POINT_BAND_B_G 0 + +/* + * There are three types of disconnections: + * + * DISCONNECT_IMMEDIATE: the fw doesn't send any frames + * DISCONNECT_DEAUTH: the fw generates a DEAUTH request with the reason + * we have passed + * DISCONNECT_DISASSOC: the fw generates a DESASSOC request with the reason + * we have passed + */ +enum wl1271_disconnect_type { + DISCONNECT_IMMEDIATE, + DISCONNECT_DEAUTH, + DISCONNECT_DISASSOC +}; + +#define WL1271_CMD_STA_STATE_CONNECTED 1 + +struct wl12xx_cmd_set_peer_state { + struct wl1271_cmd_header header; + + u8 hlid; + u8 state; + u8 padding[2]; +} __packed; + +struct wl12xx_cmd_roc { + struct wl1271_cmd_header header; + + u8 role_id; + u8 channel; + u8 band; + u8 padding; +}; + +struct wl12xx_cmd_croc { + struct wl1271_cmd_header header; + + u8 role_id; + u8 padding[3]; +}; + +enum wl12xx_ssid_type { + WL12XX_SSID_TYPE_PUBLIC = 0, + WL12XX_SSID_TYPE_HIDDEN = 1, + WL12XX_SSID_TYPE_ANY = 2, +}; + +enum wl1271_psd_type { + WL1271_PSD_LEGACY = 0, + WL1271_PSD_UPSD_TRIGGER = 1, + WL1271_PSD_LEGACY_PSPOLL = 2, + WL1271_PSD_SAPSD = 3 +}; + +struct wl12xx_cmd_add_peer { + struct wl1271_cmd_header header; + + u8 addr[ETH_ALEN]; + u8 hlid; + u8 aid; + u8 psd_type[NUM_ACCESS_CATEGORIES_COPY]; + __le32 supported_rates; + u8 bss_index; + u8 sp_len; + u8 wmm; + u8 padding1; +} __packed; + +struct wl12xx_cmd_remove_peer { + struct wl1271_cmd_header header; + + u8 hlid; + u8 reason_opcode; + u8 send_deauth_flag; + u8 padding1; +} __packed; + +/* + * Continuous mode - packets are transferred to the host periodically + * via the data path. + * On demand - Log messages are stored in a cyclic buffer in the + * firmware, and only transferred to the host when explicitly requested + */ +enum wl12xx_fwlogger_log_mode { + WL12XX_FWLOG_CONTINUOUS, + WL12XX_FWLOG_ON_DEMAND +}; + +/* Include/exclude timestamps from the log messages */ +enum wl12xx_fwlogger_timestamp { + WL12XX_FWLOG_TIMESTAMP_DISABLED, + WL12XX_FWLOG_TIMESTAMP_ENABLED +}; + +/* + * Logs can be routed to the debug pinouts (where available), to the host bus + * (SDIO/SPI), or dropped + */ +enum wl12xx_fwlogger_output { + WL12XX_FWLOG_OUTPUT_NONE, + WL12XX_FWLOG_OUTPUT_DBG_PINS, + WL12XX_FWLOG_OUTPUT_HOST, +}; + +struct wl12xx_cmd_config_fwlog { + struct wl1271_cmd_header header; + + /* See enum wl12xx_fwlogger_log_mode */ + u8 logger_mode; + + /* Minimum log level threshold */ + u8 log_severity; + + /* Include/exclude timestamps from the log messages */ + u8 timestamp; + + /* See enum wl1271_fwlogger_output */ + u8 output; + + /* Regulates the frequency of log messages */ + u8 threshold; + + u8 padding[3]; +} __packed; + +struct wl12xx_cmd_start_fwlog { + struct wl1271_cmd_header header; +} __packed; + +struct wl12xx_cmd_stop_fwlog { + struct wl1271_cmd_header header; +} __packed; + +struct wl12xx_cmd_channel_switch { + struct wl1271_cmd_header header; + + u8 role_id; + + /* The new serving channel */ + u8 channel; + /* Relative time of the serving channel switch in TBTT units */ + u8 switch_time; + /* Stop the role TX, should expect it after radar detection */ + u8 stop_tx; + /* The target channel tx status 1-stopped 0-open*/ + u8 post_switch_tx_disable; + + u8 padding[3]; +} __packed; + +struct wl12xx_cmd_stop_channel_switch { + struct wl1271_cmd_header header; +} __packed; + +#endif /* __WL1271_CMD_H__ */ diff --git a/trunk/drivers/net/wireless/ti/wlcore/conf.h b/trunk/drivers/net/wireless/ti/wlcore/conf.h new file mode 100644 index 000000000000..fef0db4213bc --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wlcore/conf.h @@ -0,0 +1,1274 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __CONF_H__ +#define __CONF_H__ + +enum { + CONF_HW_BIT_RATE_1MBPS = BIT(0), + CONF_HW_BIT_RATE_2MBPS = BIT(1), + CONF_HW_BIT_RATE_5_5MBPS = BIT(2), + CONF_HW_BIT_RATE_6MBPS = BIT(3), + CONF_HW_BIT_RATE_9MBPS = BIT(4), + CONF_HW_BIT_RATE_11MBPS = BIT(5), + CONF_HW_BIT_RATE_12MBPS = BIT(6), + CONF_HW_BIT_RATE_18MBPS = BIT(7), + CONF_HW_BIT_RATE_22MBPS = BIT(8), + CONF_HW_BIT_RATE_24MBPS = BIT(9), + CONF_HW_BIT_RATE_36MBPS = BIT(10), + CONF_HW_BIT_RATE_48MBPS = BIT(11), + CONF_HW_BIT_RATE_54MBPS = BIT(12), + CONF_HW_BIT_RATE_MCS_0 = BIT(13), + CONF_HW_BIT_RATE_MCS_1 = BIT(14), + CONF_HW_BIT_RATE_MCS_2 = BIT(15), + CONF_HW_BIT_RATE_MCS_3 = BIT(16), + CONF_HW_BIT_RATE_MCS_4 = BIT(17), + CONF_HW_BIT_RATE_MCS_5 = BIT(18), + CONF_HW_BIT_RATE_MCS_6 = BIT(19), + CONF_HW_BIT_RATE_MCS_7 = BIT(20) +}; + +enum { + CONF_HW_RATE_INDEX_1MBPS = 0, + CONF_HW_RATE_INDEX_2MBPS = 1, + CONF_HW_RATE_INDEX_5_5MBPS = 2, + CONF_HW_RATE_INDEX_6MBPS = 3, + CONF_HW_RATE_INDEX_9MBPS = 4, + CONF_HW_RATE_INDEX_11MBPS = 5, + CONF_HW_RATE_INDEX_12MBPS = 6, + CONF_HW_RATE_INDEX_18MBPS = 7, + CONF_HW_RATE_INDEX_22MBPS = 8, + CONF_HW_RATE_INDEX_24MBPS = 9, + CONF_HW_RATE_INDEX_36MBPS = 10, + CONF_HW_RATE_INDEX_48MBPS = 11, + CONF_HW_RATE_INDEX_54MBPS = 12, + CONF_HW_RATE_INDEX_MAX = CONF_HW_RATE_INDEX_54MBPS, +}; + +#define CONF_HW_RXTX_RATE_UNSUPPORTED 0xff + +enum { + CONF_SG_DISABLE = 0, + CONF_SG_PROTECTIVE, + CONF_SG_OPPORTUNISTIC +}; + +enum { + /* + * Configure the min and max time BT gains the antenna + * in WLAN / BT master basic rate + * + * Range: 0 - 255 (ms) + */ + CONF_SG_ACL_BT_MASTER_MIN_BR = 0, + CONF_SG_ACL_BT_MASTER_MAX_BR, + + /* + * Configure the min and max time BT gains the antenna + * in WLAN / BT slave basic rate + * + * Range: 0 - 255 (ms) + */ + CONF_SG_ACL_BT_SLAVE_MIN_BR, + CONF_SG_ACL_BT_SLAVE_MAX_BR, + + /* + * Configure the min and max time BT gains the antenna + * in WLAN / BT master EDR + * + * Range: 0 - 255 (ms) + */ + CONF_SG_ACL_BT_MASTER_MIN_EDR, + CONF_SG_ACL_BT_MASTER_MAX_EDR, + + /* + * Configure the min and max time BT gains the antenna + * in WLAN / BT slave EDR + * + * Range: 0 - 255 (ms) + */ + CONF_SG_ACL_BT_SLAVE_MIN_EDR, + CONF_SG_ACL_BT_SLAVE_MAX_EDR, + + /* + * The maximum time WLAN can gain the antenna + * in WLAN PSM / BT master/slave BR + * + * Range: 0 - 255 (ms) + */ + CONF_SG_ACL_WLAN_PS_MASTER_BR, + CONF_SG_ACL_WLAN_PS_SLAVE_BR, + + /* + * The maximum time WLAN can gain the antenna + * in WLAN PSM / BT master/slave EDR + * + * Range: 0 - 255 (ms) + */ + CONF_SG_ACL_WLAN_PS_MASTER_EDR, + CONF_SG_ACL_WLAN_PS_SLAVE_EDR, + + /* TODO: explain these values */ + CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR, + CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR, + CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR, + CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR, + CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR, + CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR, + CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR, + CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR, + + CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR, + CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR, + CONF_SG_ACL_PASSIVE_SCAN_BT_BR, + CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR, + CONF_SG_ACL_PASSIVE_SCAN_BT_EDR, + CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR, + + /* + * Compensation percentage of probe requests when scan initiated + * during BT voice/ACL link. + * + * Range: 0 - 255 (%) + */ + CONF_SG_AUTO_SCAN_PROBE_REQ, + + /* + * Compensation percentage of probe requests when active scan initiated + * during BT voice + * + * Range: 0 - 255 (%) + */ + CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3, + + /* + * Compensation percentage of WLAN active scan window if initiated + * during BT A2DP + * + * Range: 0 - 1000 (%) + */ + CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP, + + /* + * Compensation percentage of WLAN passive scan window if initiated + * during BT A2DP BR + * + * Range: 0 - 1000 (%) + */ + CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR, + + /* + * Compensation percentage of WLAN passive scan window if initiated + * during BT A2DP EDR + * + * Range: 0 - 1000 (%) + */ + CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR, + + /* + * Compensation percentage of WLAN passive scan window if initiated + * during BT voice + * + * Range: 0 - 1000 (%) + */ + CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3, + + /* TODO: explain these values */ + CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN, + CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN, + CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN, + + /* + * Defines whether the SG will force WLAN host to enter/exit PSM + * + * Range: 1 - SG can force, 0 - host handles PSM + */ + CONF_SG_STA_FORCE_PS_IN_BT_SCO, + + /* + * Defines antenna configuration (single/dual antenna) + * + * Range: 0 - single antenna, 1 - dual antenna + */ + CONF_SG_ANTENNA_CONFIGURATION, + + /* + * The threshold (percent) of max consecutive beacon misses before + * increasing priority of beacon reception. + * + * Range: 0 - 100 (%) + */ + CONF_SG_BEACON_MISS_PERCENT, + + /* + * Protection time of the DHCP procedure. + * + * Range: 0 - 100000 (ms) + */ + CONF_SG_DHCP_TIME, + + /* + * RX guard time before the beginning of a new BT voice frame during + * which no new WLAN trigger frame is transmitted. + * + * Range: 0 - 100000 (us) + */ + CONF_SG_RXT, + + /* + * TX guard time before the beginning of a new BT voice frame during + * which no new WLAN frame is transmitted. + * + * Range: 0 - 100000 (us) + */ + + CONF_SG_TXT, + + /* + * Enable adaptive RXT/TXT algorithm. If disabled, the host values + * will be utilized. + * + * Range: 0 - disable, 1 - enable + */ + CONF_SG_ADAPTIVE_RXT_TXT, + + /* TODO: explain this value */ + CONF_SG_GENERAL_USAGE_BIT_MAP, + + /* + * Number of consecutive BT voice frames not interrupted by WLAN + * + * Range: 0 - 100 + */ + CONF_SG_HV3_MAX_SERVED, + + /* + * The used WLAN legacy service period during active BT ACL link + * + * Range: 0 - 255 (ms) + */ + CONF_SG_PS_POLL_TIMEOUT, + + /* + * The used WLAN UPSD service period during active BT ACL link + * + * Range: 0 - 255 (ms) + */ + CONF_SG_UPSD_TIMEOUT, + + CONF_SG_CONSECUTIVE_CTS_THRESHOLD, + CONF_SG_STA_RX_WINDOW_AFTER_DTIM, + CONF_SG_STA_CONNECTION_PROTECTION_TIME, + + /* AP params */ + CONF_AP_BEACON_MISS_TX, + CONF_AP_RX_WINDOW_AFTER_BEACON, + CONF_AP_BEACON_WINDOW_INTERVAL, + CONF_AP_CONNECTION_PROTECTION_TIME, + CONF_AP_BT_ACL_VAL_BT_SERVE_TIME, + CONF_AP_BT_ACL_VAL_WL_SERVE_TIME, + + /* CTS Diluting params */ + CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH, + CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER, + + CONF_SG_TEMP_PARAM_1, + CONF_SG_TEMP_PARAM_2, + CONF_SG_TEMP_PARAM_3, + CONF_SG_TEMP_PARAM_4, + CONF_SG_TEMP_PARAM_5, + CONF_SG_TEMP_PARAM_6, + CONF_SG_TEMP_PARAM_7, + CONF_SG_TEMP_PARAM_8, + CONF_SG_TEMP_PARAM_9, + CONF_SG_TEMP_PARAM_10, + + CONF_SG_PARAMS_MAX, + CONF_SG_PARAMS_ALL = 0xff +}; + +struct conf_sg_settings { + u32 params[CONF_SG_PARAMS_MAX]; + u8 state; +}; + +enum conf_rx_queue_type { + CONF_RX_QUEUE_TYPE_LOW_PRIORITY, /* All except the high priority */ + CONF_RX_QUEUE_TYPE_HIGH_PRIORITY, /* Management and voice packets */ +}; + +struct conf_rx_settings { + /* + * The maximum amount of time, in TU, before the + * firmware discards the MSDU. + * + * Range: 0 - 0xFFFFFFFF + */ + u32 rx_msdu_life_time; + + /* + * Packet detection threshold in the PHY. + * + * FIXME: details unknown. + */ + u32 packet_detection_threshold; + + /* + * The longest time the STA will wait to receive traffic from the AP + * after a PS-poll has been transmitted. + * + * Range: 0 - 200000 + */ + u16 ps_poll_timeout; + /* + * The longest time the STA will wait to receive traffic from the AP + * after a frame has been sent from an UPSD enabled queue. + * + * Range: 0 - 200000 + */ + u16 upsd_timeout; + + /* + * The number of octets in an MPDU, below which an RTS/CTS + * handshake is not performed. + * + * Range: 0 - 4096 + */ + u16 rts_threshold; + + /* + * The RX Clear Channel Assessment threshold in the PHY + * (the energy threshold). + * + * Range: ENABLE_ENERGY_D == 0x140A + * DISABLE_ENERGY_D == 0xFFEF + */ + u16 rx_cca_threshold; + + /* + * Occupied Rx mem-blocks number which requires interrupting the host + * (0 = no buffering, 0xffff = disabled). + * + * Range: u16 + */ + u16 irq_blk_threshold; + + /* + * Rx packets number which requires interrupting the host + * (0 = no buffering). + * + * Range: u16 + */ + u16 irq_pkt_threshold; + + /* + * Max time in msec the FW may delay RX-Complete interrupt. + * + * Range: 1 - 100 + */ + u16 irq_timeout; + + /* + * The RX queue type. + * + * Range: RX_QUEUE_TYPE_RX_LOW_PRIORITY, RX_QUEUE_TYPE_RX_HIGH_PRIORITY, + */ + u8 queue_type; +}; + +#define CONF_TX_MAX_RATE_CLASSES 10 + +#define CONF_TX_RATE_MASK_UNSPECIFIED 0 +#define CONF_TX_RATE_MASK_BASIC (CONF_HW_BIT_RATE_1MBPS | \ + CONF_HW_BIT_RATE_2MBPS) +#define CONF_TX_RATE_RETRY_LIMIT 10 + +/* basic rates for p2p operations (probe req/resp, etc.) */ +#define CONF_TX_RATE_MASK_BASIC_P2P (CONF_HW_BIT_RATE_6MBPS | \ + CONF_HW_BIT_RATE_12MBPS | CONF_HW_BIT_RATE_24MBPS) + +/* + * Rates supported for data packets when operating as AP. Note the absence + * of the 22Mbps rate. There is a FW limitation on 12 rates so we must drop + * one. The rate dropped is not mandatory under any operating mode. + */ +#define CONF_TX_AP_ENABLED_RATES (CONF_HW_BIT_RATE_1MBPS | \ + CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \ + CONF_HW_BIT_RATE_6MBPS | CONF_HW_BIT_RATE_9MBPS | \ + CONF_HW_BIT_RATE_11MBPS | CONF_HW_BIT_RATE_12MBPS | \ + CONF_HW_BIT_RATE_18MBPS | CONF_HW_BIT_RATE_24MBPS | \ + CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \ + CONF_HW_BIT_RATE_54MBPS) + +#define CONF_TX_CCK_RATES (CONF_HW_BIT_RATE_1MBPS | \ + CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \ + CONF_HW_BIT_RATE_11MBPS) + +#define CONF_TX_OFDM_RATES (CONF_HW_BIT_RATE_6MBPS | \ + CONF_HW_BIT_RATE_12MBPS | CONF_HW_BIT_RATE_24MBPS | \ + CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \ + CONF_HW_BIT_RATE_54MBPS) + +#define CONF_TX_MCS_RATES (CONF_HW_BIT_RATE_MCS_0 | \ + CONF_HW_BIT_RATE_MCS_1 | CONF_HW_BIT_RATE_MCS_2 | \ + CONF_HW_BIT_RATE_MCS_3 | CONF_HW_BIT_RATE_MCS_4 | \ + CONF_HW_BIT_RATE_MCS_5 | CONF_HW_BIT_RATE_MCS_6 | \ + CONF_HW_BIT_RATE_MCS_7) + +/* + * Default rates for management traffic when operating in AP mode. This + * should be configured according to the basic rate set of the AP + */ +#define CONF_TX_AP_DEFAULT_MGMT_RATES (CONF_HW_BIT_RATE_1MBPS | \ + CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS) + +/* default rates for working as IBSS (11b and OFDM) */ +#define CONF_TX_IBSS_DEFAULT_RATES (CONF_HW_BIT_RATE_1MBPS | \ + CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \ + CONF_HW_BIT_RATE_11MBPS | CONF_TX_OFDM_RATES); + +struct conf_tx_rate_class { + + /* + * The rates enabled for this rate class. + * + * Range: CONF_HW_BIT_RATE_* bit mask + */ + u32 enabled_rates; + + /* + * The dot11 short retry limit used for TX retries. + * + * Range: u8 + */ + u8 short_retry_limit; + + /* + * The dot11 long retry limit used for TX retries. + * + * Range: u8 + */ + u8 long_retry_limit; + + /* + * Flags controlling the attributes of TX transmission. + * + * Range: bit 0: Truncate - when set, FW attempts to send a frame stop + * when the total valid per-rate attempts have + * been exhausted; otherwise transmissions + * will continue at the lowest available rate + * until the appropriate one of the + * short_retry_limit, long_retry_limit, + * dot11_max_transmit_msdu_life_time, or + * max_tx_life_time, is exhausted. + * 1: Preamble Override - indicates if the preamble type + * should be used in TX. + * 2: Preamble Type - the type of the preamble to be used by + * the policy (0 - long preamble, 1 - short preamble. + */ + u8 aflags; +}; + +#define CONF_TX_MAX_AC_COUNT 4 + +/* Slot number setting to start transmission at PIFS interval */ +#define CONF_TX_AIFS_PIFS 1 +/* Slot number setting to start transmission at DIFS interval normal + * DCF access */ +#define CONF_TX_AIFS_DIFS 2 + + +enum conf_tx_ac { + CONF_TX_AC_BE = 0, /* best effort / legacy */ + CONF_TX_AC_BK = 1, /* background */ + CONF_TX_AC_VI = 2, /* video */ + CONF_TX_AC_VO = 3, /* voice */ + CONF_TX_AC_CTS2SELF = 4, /* fictitious AC, follows AC_VO */ + CONF_TX_AC_ANY_TID = 0x1f +}; + +struct conf_tx_ac_category { + /* + * The AC class identifier. + * + * Range: enum conf_tx_ac + */ + u8 ac; + + /* + * The contention window minimum size (in slots) for the access + * class. + * + * Range: u8 + */ + u8 cw_min; + + /* + * The contention window maximum size (in slots) for the access + * class. + * + * Range: u8 + */ + u16 cw_max; + + /* + * The AIF value (in slots) for the access class. + * + * Range: u8 + */ + u8 aifsn; + + /* + * The TX Op Limit (in microseconds) for the access class. + * + * Range: u16 + */ + u16 tx_op_limit; +}; + +#define CONF_TX_MAX_TID_COUNT 8 + +/* Allow TX BA on all TIDs but 6,7. These are currently reserved in the FW */ +#define CONF_TX_BA_ENABLED_TID_BITMAP 0x3F + +enum { + CONF_CHANNEL_TYPE_DCF = 0, /* DC/LEGACY*/ + CONF_CHANNEL_TYPE_EDCF = 1, /* EDCA*/ + CONF_CHANNEL_TYPE_HCCA = 2, /* HCCA*/ +}; + +enum { + CONF_PS_SCHEME_LEGACY = 0, + CONF_PS_SCHEME_UPSD_TRIGGER = 1, + CONF_PS_SCHEME_LEGACY_PSPOLL = 2, + CONF_PS_SCHEME_SAPSD = 3, +}; + +enum { + CONF_ACK_POLICY_LEGACY = 0, + CONF_ACK_POLICY_NO_ACK = 1, + CONF_ACK_POLICY_BLOCK = 2, +}; + + +struct conf_tx_tid { + u8 queue_id; + u8 channel_type; + u8 tsid; + u8 ps_scheme; + u8 ack_policy; + u32 apsd_conf[2]; +}; + +struct conf_tx_settings { + /* + * The TX ED value for TELEC Enable/Disable. + * + * Range: 0, 1 + */ + u8 tx_energy_detection; + + /* + * Configuration for rate classes for TX (currently only one + * rate class supported). Used in non-AP mode. + */ + struct conf_tx_rate_class sta_rc_conf; + + /* + * Configuration for access categories for TX rate control. + */ + u8 ac_conf_count; + struct conf_tx_ac_category ac_conf[CONF_TX_MAX_AC_COUNT]; + + /* + * AP-mode - allow this number of TX retries to a station before an + * event is triggered from FW. + * In AP-mode the hlids of unreachable stations are given in the + * "sta_tx_retry_exceeded" member in the event mailbox. + */ + u8 max_tx_retries; + + /* + * AP-mode - after this number of seconds a connected station is + * considered inactive. + */ + u16 ap_aging_period; + + /* + * Configuration for TID parameters. + */ + u8 tid_conf_count; + struct conf_tx_tid tid_conf[CONF_TX_MAX_TID_COUNT]; + + /* + * The TX fragmentation threshold. + * + * Range: u16 + */ + u16 frag_threshold; + + /* + * Max time in msec the FW may delay frame TX-Complete interrupt. + * + * Range: u16 + */ + u16 tx_compl_timeout; + + /* + * Completed TX packet count which requires to issue the TX-Complete + * interrupt. + * + * Range: u16 + */ + u16 tx_compl_threshold; + + /* + * The rate used for control messages and scanning on the 2.4GHz band + * + * Range: CONF_HW_BIT_RATE_* bit mask + */ + u32 basic_rate; + + /* + * The rate used for control messages and scanning on the 5GHz band + * + * Range: CONF_HW_BIT_RATE_* bit mask + */ + u32 basic_rate_5; + + /* + * TX retry limits for templates + */ + u8 tmpl_short_retry_limit; + u8 tmpl_long_retry_limit; + + /* Time in ms for Tx watchdog timer to expire */ + u32 tx_watchdog_timeout; +}; + +enum { + CONF_WAKE_UP_EVENT_BEACON = 0x01, /* Wake on every Beacon*/ + CONF_WAKE_UP_EVENT_DTIM = 0x02, /* Wake on every DTIM*/ + CONF_WAKE_UP_EVENT_N_DTIM = 0x04, /* Wake every Nth DTIM */ + CONF_WAKE_UP_EVENT_N_BEACONS = 0x08, /* Wake every Nth beacon */ + CONF_WAKE_UP_EVENT_BITS_MASK = 0x0F +}; + +#define CONF_MAX_BCN_FILT_IE_COUNT 32 + +#define CONF_BCN_RULE_PASS_ON_CHANGE BIT(0) +#define CONF_BCN_RULE_PASS_ON_APPEARANCE BIT(1) + +#define CONF_BCN_IE_OUI_LEN 3 +#define CONF_BCN_IE_VER_LEN 2 + +struct conf_bcn_filt_rule { + /* + * IE number to which to associate a rule. + * + * Range: u8 + */ + u8 ie; + + /* + * Rule to associate with the specific ie. + * + * Range: CONF_BCN_RULE_PASS_ON_* + */ + u8 rule; + + /* + * OUI for the vendor specifie IE (221) + */ + u8 oui[CONF_BCN_IE_OUI_LEN]; + + /* + * Type for the vendor specifie IE (221) + */ + u8 type; + + /* + * Version for the vendor specifie IE (221) + */ + u8 version[CONF_BCN_IE_VER_LEN]; +}; + +#define CONF_MAX_RSSI_SNR_TRIGGERS 8 + +enum { + CONF_TRIG_METRIC_RSSI_BEACON = 0, + CONF_TRIG_METRIC_RSSI_DATA, + CONF_TRIG_METRIC_SNR_BEACON, + CONF_TRIG_METRIC_SNR_DATA +}; + +enum { + CONF_TRIG_EVENT_TYPE_LEVEL = 0, + CONF_TRIG_EVENT_TYPE_EDGE +}; + +enum { + CONF_TRIG_EVENT_DIR_LOW = 0, + CONF_TRIG_EVENT_DIR_HIGH, + CONF_TRIG_EVENT_DIR_BIDIR +}; + +struct conf_sig_weights { + + /* + * RSSI from beacons average weight. + * + * Range: u8 + */ + u8 rssi_bcn_avg_weight; + + /* + * RSSI from data average weight. + * + * Range: u8 + */ + u8 rssi_pkt_avg_weight; + + /* + * SNR from beacons average weight. + * + * Range: u8 + */ + u8 snr_bcn_avg_weight; + + /* + * SNR from data average weight. + * + * Range: u8 + */ + u8 snr_pkt_avg_weight; +}; + +enum conf_bcn_filt_mode { + CONF_BCN_FILT_MODE_DISABLED = 0, + CONF_BCN_FILT_MODE_ENABLED = 1 +}; + +enum conf_bet_mode { + CONF_BET_MODE_DISABLE = 0, + CONF_BET_MODE_ENABLE = 1, +}; + +struct conf_conn_settings { + /* + * Firmware wakeup conditions configuration. The host may set only + * one bit. + * + * Range: CONF_WAKE_UP_EVENT_* + */ + u8 wake_up_event; + + /* + * Listen interval for beacons or Dtims. + * + * Range: 0 for beacon and Dtim wakeup + * 1-10 for x Dtims + * 1-255 for x beacons + */ + u8 listen_interval; + + /* + * Firmware wakeup conditions during suspend + * Range: CONF_WAKE_UP_EVENT_* + */ + u8 suspend_wake_up_event; + + /* + * Listen interval during suspend. + * Currently will be in DTIMs (1-10) + * + */ + u8 suspend_listen_interval; + + /* + * Enable or disable the beacon filtering. + * + * Range: CONF_BCN_FILT_MODE_* + */ + enum conf_bcn_filt_mode bcn_filt_mode; + + /* + * Configure Beacon filter pass-thru rules. + */ + u8 bcn_filt_ie_count; + struct conf_bcn_filt_rule bcn_filt_ie[CONF_MAX_BCN_FILT_IE_COUNT]; + + /* + * The number of consecutive beacons to lose, before the firmware + * becomes out of synch. + * + * Range: u32 + */ + u32 synch_fail_thold; + + /* + * After out-of-synch, the number of TU's to wait without a further + * received beacon (or probe response) before issuing the BSS_EVENT_LOSE + * event. + * + * Range: u32 + */ + u32 bss_lose_timeout; + + /* + * Beacon receive timeout. + * + * Range: u32 + */ + u32 beacon_rx_timeout; + + /* + * Broadcast receive timeout. + * + * Range: u32 + */ + u32 broadcast_timeout; + + /* + * Enable/disable reception of broadcast packets in power save mode + * + * Range: 1 - enable, 0 - disable + */ + u8 rx_broadcast_in_ps; + + /* + * Consecutive PS Poll failures before sending event to driver + * + * Range: u8 + */ + u8 ps_poll_threshold; + + /* + * Configuration of signal average weights. + */ + struct conf_sig_weights sig_weights; + + /* + * Specifies if beacon early termination procedure is enabled or + * disabled. + * + * Range: CONF_BET_MODE_* + */ + u8 bet_enable; + + /* + * Specifies the maximum number of consecutive beacons that may be + * early terminated. After this number is reached at least one full + * beacon must be correctly received in FW before beacon ET + * resumes. + * + * Range 0 - 255 + */ + u8 bet_max_consecutive; + + /* + * Specifies the maximum number of times to try PSM entry if it fails + * (if sending the appropriate null-func message fails.) + * + * Range 0 - 255 + */ + u8 psm_entry_retries; + + /* + * Specifies the maximum number of times to try PSM exit if it fails + * (if sending the appropriate null-func message fails.) + * + * Range 0 - 255 + */ + u8 psm_exit_retries; + + /* + * Specifies the maximum number of times to try transmit the PSM entry + * null-func frame for each PSM entry attempt + * + * Range 0 - 255 + */ + u8 psm_entry_nullfunc_retries; + + /* + * Specifies the dynamic PS timeout in ms that will be used + * by the FW when in AUTO_PS mode + */ + u16 dynamic_ps_timeout; + + /* + * Specifies whether dynamic PS should be disabled and PSM forced. + * This is required for certain WiFi certification tests. + */ + u8 forced_ps; + + /* + * + * Specifies the interval of the connection keep-alive null-func + * frame in ms. + * + * Range: 1000 - 3600000 + */ + u32 keep_alive_interval; + + /* + * Maximum listen interval supported by the driver in units of beacons. + * + * Range: u16 + */ + u8 max_listen_interval; +}; + +enum { + CONF_REF_CLK_19_2_E, + CONF_REF_CLK_26_E, + CONF_REF_CLK_38_4_E, + CONF_REF_CLK_52_E, + CONF_REF_CLK_38_4_M_XTAL, + CONF_REF_CLK_26_M_XTAL, +}; + +enum single_dual_band_enum { + CONF_SINGLE_BAND, + CONF_DUAL_BAND +}; + +#define CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE 15 +#define CONF_NUMBER_OF_SUB_BANDS_5 7 +#define CONF_NUMBER_OF_RATE_GROUPS 6 +#define CONF_NUMBER_OF_CHANNELS_2_4 14 +#define CONF_NUMBER_OF_CHANNELS_5 35 + +struct conf_itrim_settings { + /* enable dco itrim */ + u8 enable; + + /* moderation timeout in microsecs from the last TX */ + u32 timeout; +}; + +struct conf_pm_config_settings { + /* + * Host clock settling time + * + * Range: 0 - 30000 us + */ + u32 host_clk_settling_time; + + /* + * Host fast wakeup support + * + * Range: true, false + */ + bool host_fast_wakeup_support; +}; + +struct conf_roam_trigger_settings { + /* + * The minimum interval between two trigger events. + * + * Range: 0 - 60000 ms + */ + u16 trigger_pacing; + + /* + * The weight for rssi/beacon average calculation + * + * Range: 0 - 255 + */ + u8 avg_weight_rssi_beacon; + + /* + * The weight for rssi/data frame average calculation + * + * Range: 0 - 255 + */ + u8 avg_weight_rssi_data; + + /* + * The weight for snr/beacon average calculation + * + * Range: 0 - 255 + */ + u8 avg_weight_snr_beacon; + + /* + * The weight for snr/data frame average calculation + * + * Range: 0 - 255 + */ + u8 avg_weight_snr_data; +}; + +struct conf_scan_settings { + /* + * The minimum time to wait on each channel for active scans + * + * Range: u32 tu/1000 + */ + u32 min_dwell_time_active; + + /* + * The maximum time to wait on each channel for active scans + * + * Range: u32 tu/1000 + */ + u32 max_dwell_time_active; + + /* + * The minimum time to wait on each channel for passive scans + * + * Range: u32 tu/1000 + */ + u32 min_dwell_time_passive; + + /* + * The maximum time to wait on each channel for passive scans + * + * Range: u32 tu/1000 + */ + u32 max_dwell_time_passive; + + /* + * Number of probe requests to transmit on each active scan channel + * + * Range: u8 + */ + u16 num_probe_reqs; + + /* + * Scan trigger (split scan) timeout. The FW will split the scan + * operation into slices of the given time and allow the FW to schedule + * other tasks in between. + * + * Range: u32 Microsecs + */ + u32 split_scan_timeout; +}; + +struct conf_sched_scan_settings { + /* + * The base time to wait on the channel for active scans (in TU/1000). + * The minimum dwell time is calculated according to this: + * min_dwell_time = base + num_of_probes_to_be_sent * delta_per_probe + * The maximum dwell time is calculated according to this: + * max_dwell_time = min_dwell_time + max_dwell_time_delta + */ + u32 base_dwell_time; + + /* The delta between the min dwell time and max dwell time for + * active scans (in TU/1000s). The max dwell time is used by the FW once + * traffic is detected on the channel. + */ + u32 max_dwell_time_delta; + + /* Delta added to min dwell time per each probe in 2.4 GHz (TU/1000) */ + u32 dwell_time_delta_per_probe; + + /* Delta added to min dwell time per each probe in 5 GHz (TU/1000) */ + u32 dwell_time_delta_per_probe_5; + + /* time to wait on the channel for passive scans (in TU/1000) */ + u32 dwell_time_passive; + + /* time to wait on the channel for DFS scans (in TU/1000) */ + u32 dwell_time_dfs; + + /* number of probe requests to send on each channel in active scans */ + u8 num_probe_reqs; + + /* RSSI threshold to be used for filtering */ + s8 rssi_threshold; + + /* SNR threshold to be used for filtering */ + s8 snr_threshold; +}; + +struct conf_ht_setting { + u8 rx_ba_win_size; + u8 tx_ba_win_size; + u16 inactivity_timeout; + + /* bitmap of enabled TIDs for TX BA sessions */ + u8 tx_ba_tid_bitmap; +}; + +struct conf_memory_settings { + /* Number of stations supported in IBSS mode */ + u8 num_stations; + + /* Number of ssid profiles used in IBSS mode */ + u8 ssid_profiles; + + /* Number of memory buffers allocated to rx pool */ + u8 rx_block_num; + + /* Minimum number of blocks allocated to tx pool */ + u8 tx_min_block_num; + + /* Disable/Enable dynamic memory */ + u8 dynamic_memory; + + /* + * Minimum required free tx memory blocks in order to assure optimum + * performance + * + * Range: 0-120 + */ + u8 min_req_tx_blocks; + + /* + * Minimum required free rx memory blocks in order to assure optimum + * performance + * + * Range: 0-120 + */ + u8 min_req_rx_blocks; + + /* + * Minimum number of mem blocks (free+used) guaranteed for TX + * + * Range: 0-120 + */ + u8 tx_min; +}; + +struct conf_fm_coex { + u8 enable; + u8 swallow_period; + u8 n_divider_fref_set_1; + u8 n_divider_fref_set_2; + u16 m_divider_fref_set_1; + u16 m_divider_fref_set_2; + u32 coex_pll_stabilization_time; + u16 ldo_stabilization_time; + u8 fm_disturbed_band_margin; + u8 swallow_clk_diff; +}; + +struct conf_rx_streaming_settings { + /* + * RX Streaming duration (in msec) from last tx/rx + * + * Range: u32 + */ + u32 duration; + + /* + * Bitmap of tids to be polled during RX streaming. + * (Note: it doesn't look like it really matters) + * + * Range: 0x1-0xff + */ + u8 queues; + + /* + * RX Streaming interval. + * (Note:this value is also used as the rx streaming timeout) + * Range: 0 (disabled), 10 - 100 + */ + u8 interval; + + /* + * enable rx streaming also when there is no coex activity + */ + u8 always; +}; + +struct conf_fwlog { + /* Continuous or on-demand */ + u8 mode; + + /* + * Number of memory blocks dedicated for the FW logger + * + * Range: 1-3, or 0 to disable the FW logger + */ + u8 mem_blocks; + + /* Minimum log level threshold */ + u8 severity; + + /* Include/exclude timestamps from the log messages */ + u8 timestamp; + + /* See enum wl1271_fwlogger_output */ + u8 output; + + /* Regulates the frequency of log messages */ + u8 threshold; +}; + +#define ACX_RATE_MGMT_NUM_OF_RATES 13 +struct conf_rate_policy_settings { + u16 rate_retry_score; + u16 per_add; + u16 per_th1; + u16 per_th2; + u16 max_per; + u8 inverse_curiosity_factor; + u8 tx_fail_low_th; + u8 tx_fail_high_th; + u8 per_alpha_shift; + u8 per_add_shift; + u8 per_beta1_shift; + u8 per_beta2_shift; + u8 rate_check_up; + u8 rate_check_down; + u8 rate_retry_policy[ACX_RATE_MGMT_NUM_OF_RATES]; +}; + +struct conf_hangover_settings { + u32 recover_time; + u8 hangover_period; + u8 dynamic_mode; + u8 early_termination_mode; + u8 max_period; + u8 min_period; + u8 increase_delta; + u8 decrease_delta; + u8 quiet_time; + u8 increase_time; + u8 window_size; +}; + +struct wlcore_conf { + struct conf_sg_settings sg; + struct conf_rx_settings rx; + struct conf_tx_settings tx; + struct conf_conn_settings conn; + struct conf_itrim_settings itrim; + struct conf_pm_config_settings pm_config; + struct conf_roam_trigger_settings roam_trigger; + struct conf_scan_settings scan; + struct conf_sched_scan_settings sched_scan; + struct conf_ht_setting ht; + struct conf_memory_settings mem; + struct conf_fm_coex fm_coex; + struct conf_rx_streaming_settings rx_streaming; + struct conf_fwlog fwlog; + struct conf_rate_policy_settings rate; + struct conf_hangover_settings hangover; +}; + +#endif diff --git a/trunk/drivers/net/wireless/ti/wlcore/debug.h b/trunk/drivers/net/wireless/ti/wlcore/debug.h new file mode 100644 index 000000000000..6b800b3cbea5 --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wlcore/debug.h @@ -0,0 +1,103 @@ +/* + * This file is part of wl12xx + * + * Copyright (C) 2011 Texas Instruments. All rights reserved. + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +#include +#include + +#define DRIVER_NAME "wl12xx" +#define DRIVER_PREFIX DRIVER_NAME ": " + +enum { + DEBUG_NONE = 0, + DEBUG_IRQ = BIT(0), + DEBUG_SPI = BIT(1), + DEBUG_BOOT = BIT(2), + DEBUG_MAILBOX = BIT(3), + DEBUG_TESTMODE = BIT(4), + DEBUG_EVENT = BIT(5), + DEBUG_TX = BIT(6), + DEBUG_RX = BIT(7), + DEBUG_SCAN = BIT(8), + DEBUG_CRYPT = BIT(9), + DEBUG_PSM = BIT(10), + DEBUG_MAC80211 = BIT(11), + DEBUG_CMD = BIT(12), + DEBUG_ACX = BIT(13), + DEBUG_SDIO = BIT(14), + DEBUG_FILTERS = BIT(15), + DEBUG_ADHOC = BIT(16), + DEBUG_AP = BIT(17), + DEBUG_PROBE = BIT(18), + DEBUG_IO = BIT(19), + DEBUG_MASTER = (DEBUG_ADHOC | DEBUG_AP), + DEBUG_ALL = ~0, +}; + +extern u32 wl12xx_debug_level; + +#define DEBUG_DUMP_LIMIT 1024 + +#define wl1271_error(fmt, arg...) \ + pr_err(DRIVER_PREFIX "ERROR " fmt "\n", ##arg) + +#define wl1271_warning(fmt, arg...) \ + pr_warning(DRIVER_PREFIX "WARNING " fmt "\n", ##arg) + +#define wl1271_notice(fmt, arg...) \ + pr_info(DRIVER_PREFIX fmt "\n", ##arg) + +#define wl1271_info(fmt, arg...) \ + pr_info(DRIVER_PREFIX fmt "\n", ##arg) + +#define wl1271_debug(level, fmt, arg...) \ + do { \ + if (level & wl12xx_debug_level) \ + pr_debug(DRIVER_PREFIX fmt "\n", ##arg); \ + } while (0) + +/* TODO: use pr_debug_hex_dump when it becomes available */ +#define wl1271_dump(level, prefix, buf, len) \ + do { \ + if (level & wl12xx_debug_level) \ + print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ + DUMP_PREFIX_OFFSET, 16, 1, \ + buf, \ + min_t(size_t, len, DEBUG_DUMP_LIMIT), \ + 0); \ + } while (0) + +#define wl1271_dump_ascii(level, prefix, buf, len) \ + do { \ + if (level & wl12xx_debug_level) \ + print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ + DUMP_PREFIX_OFFSET, 16, 1, \ + buf, \ + min_t(size_t, len, DEBUG_DUMP_LIMIT), \ + true); \ + } while (0) + +#endif /* __DEBUG_H__ */ diff --git a/trunk/drivers/net/wireless/wl12xx/debugfs.c b/trunk/drivers/net/wireless/ti/wlcore/debugfs.c similarity index 99% rename from trunk/drivers/net/wireless/wl12xx/debugfs.c rename to trunk/drivers/net/wireless/ti/wlcore/debugfs.c index 564d49575c94..d5aea1ff5ad1 100644 --- a/trunk/drivers/net/wireless/wl12xx/debugfs.c +++ b/trunk/drivers/net/wireless/ti/wlcore/debugfs.c @@ -26,7 +26,7 @@ #include #include -#include "wl12xx.h" +#include "wlcore.h" #include "debug.h" #include "acx.h" #include "ps.h" @@ -647,6 +647,7 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf, VIF_STATE_PRINT_INT(last_rssi_event); VIF_STATE_PRINT_INT(ba_support); VIF_STATE_PRINT_INT(ba_allowed); + VIF_STATE_PRINT_INT(is_gem); VIF_STATE_PRINT_LLHEX(tx_security_seq); VIF_STATE_PRINT_INT(tx_security_last_seq_lsb); } diff --git a/trunk/drivers/net/wireless/wl12xx/debugfs.h b/trunk/drivers/net/wireless/ti/wlcore/debugfs.h similarity index 98% rename from trunk/drivers/net/wireless/wl12xx/debugfs.h rename to trunk/drivers/net/wireless/ti/wlcore/debugfs.h index 254c5b292cf6..a8d3aef011ff 100644 --- a/trunk/drivers/net/wireless/wl12xx/debugfs.h +++ b/trunk/drivers/net/wireless/ti/wlcore/debugfs.h @@ -24,7 +24,7 @@ #ifndef __DEBUGFS_H__ #define __DEBUGFS_H__ -#include "wl12xx.h" +#include "wlcore.h" int wl1271_debugfs_init(struct wl1271 *wl); void wl1271_debugfs_exit(struct wl1271 *wl); diff --git a/trunk/drivers/net/wireless/wl12xx/event.c b/trunk/drivers/net/wireless/ti/wlcore/event.c similarity index 91% rename from trunk/drivers/net/wireless/wl12xx/event.c rename to trunk/drivers/net/wireless/ti/wlcore/event.c index c953717f38eb..292632ddf890 100644 --- a/trunk/drivers/net/wireless/wl12xx/event.c +++ b/trunk/drivers/net/wireless/ti/wlcore/event.c @@ -21,9 +21,8 @@ * */ -#include "wl12xx.h" +#include "wlcore.h" #include "debug.h" -#include "reg.h" #include "io.h" #include "event.h" #include "ps.h" @@ -98,8 +97,9 @@ static void wl1271_event_mbox_dump(struct event_mailbox *mbox) wl1271_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask); } -static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) +static int wl1271_event_process(struct wl1271 *wl) { + struct event_mailbox *mbox = wl->mbox; struct ieee80211_vif *vif; struct wl12xx_vif *wlvif; u32 vector; @@ -196,7 +196,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) bool success; if (!test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, - &wl->flags)) + &wlvif->flags)) continue; success = mbox->channel_switch_status ? false : true; @@ -278,18 +278,8 @@ int wl1271_event_unmask(struct wl1271 *wl) return 0; } -void wl1271_event_mbox_config(struct wl1271 *wl) -{ - wl->mbox_ptr[0] = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR); - wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); - - wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", - wl->mbox_ptr[0], wl->mbox_ptr[1]); -} - int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) { - struct event_mailbox mbox; int ret; wl1271_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num); @@ -298,16 +288,19 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) return -EINVAL; /* first we read the mbox descriptor */ - wl1271_read(wl, wl->mbox_ptr[mbox_num], &mbox, - sizeof(struct event_mailbox), false); + wl1271_read(wl, wl->mbox_ptr[mbox_num], wl->mbox, + sizeof(*wl->mbox), false); /* process the descriptor */ - ret = wl1271_event_process(wl, &mbox); + ret = wl1271_event_process(wl); if (ret < 0) return ret; - /* then we let the firmware know it can go on...*/ - wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); + /* + * TODO: we just need this because one bit is in a different + * place. Is there any better way? + */ + wl->ops->ack_event(wl); return 0; } diff --git a/trunk/drivers/net/wireless/wl12xx/event.h b/trunk/drivers/net/wireless/ti/wlcore/event.h similarity index 98% rename from trunk/drivers/net/wireless/wl12xx/event.h rename to trunk/drivers/net/wireless/ti/wlcore/event.h index 057d193d3525..8adf18d6c58f 100644 --- a/trunk/drivers/net/wireless/wl12xx/event.h +++ b/trunk/drivers/net/wireless/ti/wlcore/event.h @@ -132,8 +132,9 @@ struct event_mailbox { u8 reserved_8[9]; } __packed; +struct wl1271; + int wl1271_event_unmask(struct wl1271 *wl); -void wl1271_event_mbox_config(struct wl1271 *wl); int wl1271_event_handle(struct wl1271 *wl, u8 mbox); #endif diff --git a/trunk/drivers/net/wireless/ti/wlcore/hw_ops.h b/trunk/drivers/net/wireless/ti/wlcore/hw_ops.h new file mode 100644 index 000000000000..9384b4d56c24 --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wlcore/hw_ops.h @@ -0,0 +1,122 @@ +/* + * This file is part of wlcore + * + * Copyright (C) 2011 Texas Instruments 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WLCORE_HW_OPS_H__ +#define __WLCORE_HW_OPS_H__ + +#include "wlcore.h" +#include "rx.h" + +static inline u32 +wlcore_hw_calc_tx_blocks(struct wl1271 *wl, u32 len, u32 spare_blks) +{ + if (!wl->ops->calc_tx_blocks) + BUG_ON(1); + + return wl->ops->calc_tx_blocks(wl, len, spare_blks); +} + +static inline void +wlcore_hw_set_tx_desc_blocks(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc, + u32 blks, u32 spare_blks) +{ + if (!wl->ops->set_tx_desc_blocks) + BUG_ON(1); + + return wl->ops->set_tx_desc_blocks(wl, desc, blks, spare_blks); +} + +static inline void +wlcore_hw_set_tx_desc_data_len(struct wl1271 *wl, + struct wl1271_tx_hw_descr *desc, + struct sk_buff *skb) +{ + if (!wl->ops->set_tx_desc_data_len) + BUG_ON(1); + + wl->ops->set_tx_desc_data_len(wl, desc, skb); +} + +static inline enum wl_rx_buf_align +wlcore_hw_get_rx_buf_align(struct wl1271 *wl, u32 rx_desc) +{ + + if (!wl->ops->get_rx_buf_align) + BUG_ON(1); + + return wl->ops->get_rx_buf_align(wl, rx_desc); +} + +static inline void +wlcore_hw_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len) +{ + if (wl->ops->prepare_read) + wl->ops->prepare_read(wl, rx_desc, len); +} + +static inline u32 +wlcore_hw_get_rx_packet_len(struct wl1271 *wl, void *rx_data, u32 data_len) +{ + if (!wl->ops->get_rx_packet_len) + BUG_ON(1); + + return wl->ops->get_rx_packet_len(wl, rx_data, data_len); +} + +static inline void wlcore_hw_tx_delayed_compl(struct wl1271 *wl) +{ + if (wl->ops->tx_delayed_compl) + wl->ops->tx_delayed_compl(wl); +} + +static inline void wlcore_hw_tx_immediate_compl(struct wl1271 *wl) +{ + if (wl->ops->tx_immediate_compl) + wl->ops->tx_immediate_compl(wl); +} + +static inline int +wlcore_hw_init_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + if (wl->ops->init_vif) + return wl->ops->init_vif(wl, wlvif); + + return 0; +} + +static inline u32 +wlcore_hw_sta_get_ap_rate_mask(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + if (!wl->ops->sta_get_ap_rate_mask) + BUG_ON(1); + + return wl->ops->sta_get_ap_rate_mask(wl, wlvif); +} + +static inline int wlcore_identify_fw(struct wl1271 *wl) +{ + if (wl->ops->identify_fw) + return wl->ops->identify_fw(wl); + + return 0; +} + +#endif diff --git a/trunk/drivers/net/wireless/wl12xx/ini.h b/trunk/drivers/net/wireless/ti/wlcore/ini.h similarity index 100% rename from trunk/drivers/net/wireless/wl12xx/ini.h rename to trunk/drivers/net/wireless/ti/wlcore/ini.h diff --git a/trunk/drivers/net/wireless/ti/wlcore/init.c b/trunk/drivers/net/wireless/ti/wlcore/init.c new file mode 100644 index 000000000000..9f89255eb6e6 --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wlcore/init.c @@ -0,0 +1,737 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include + +#include "debug.h" +#include "init.h" +#include "wl12xx_80211.h" +#include "acx.h" +#include "cmd.h" +#include "tx.h" +#include "io.h" +#include "hw_ops.h" + +int wl1271_init_templates_config(struct wl1271 *wl) +{ + int ret, i; + size_t max_size; + + /* send empty templates for fw memory reservation */ + ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, + CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, + WL1271_CMD_TEMPL_MAX_SIZE, + 0, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, + CMD_TEMPL_CFG_PROBE_REQ_5, + NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0, + WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, + CMD_TEMPL_NULL_DATA, NULL, + sizeof(struct wl12xx_null_data_template), + 0, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, + CMD_TEMPL_PS_POLL, NULL, + sizeof(struct wl12xx_ps_poll_template), + 0, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, + CMD_TEMPL_QOS_NULL_DATA, NULL, + sizeof + (struct ieee80211_qos_hdr), + 0, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, + CMD_TEMPL_PROBE_RESPONSE, NULL, + WL1271_CMD_TEMPL_DFLT_SIZE, + 0, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, + CMD_TEMPL_BEACON, NULL, + WL1271_CMD_TEMPL_DFLT_SIZE, + 0, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + + max_size = sizeof(struct wl12xx_arp_rsp_template) + + WL1271_EXTRA_SPACE_MAX; + ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, + CMD_TEMPL_ARP_RSP, NULL, + max_size, + 0, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + + /* + * Put very large empty placeholders for all templates. These + * reserve memory for later. + */ + ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, + CMD_TEMPL_AP_PROBE_RESPONSE, NULL, + WL1271_CMD_TEMPL_MAX_SIZE, + 0, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, + CMD_TEMPL_AP_BEACON, NULL, + WL1271_CMD_TEMPL_MAX_SIZE, + 0, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, + CMD_TEMPL_DEAUTH_AP, NULL, + sizeof + (struct wl12xx_disconn_template), + 0, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + + for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { + ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, + CMD_TEMPL_KLV, NULL, + sizeof(struct ieee80211_qos_hdr), + i, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + } + + return 0; +} + +static int wl1271_ap_init_deauth_template(struct wl1271 *wl, + struct wl12xx_vif *wlvif) +{ + struct wl12xx_disconn_template *tmpl; + int ret; + u32 rate; + + tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL); + if (!tmpl) { + ret = -ENOMEM; + goto out; + } + + tmpl->header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_DEAUTH); + + rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); + ret = wl1271_cmd_template_set(wl, wlvif->role_id, + CMD_TEMPL_DEAUTH_AP, + tmpl, sizeof(*tmpl), 0, rate); + +out: + kfree(tmpl); + return ret; +} + +static int wl1271_ap_init_null_template(struct wl1271 *wl, + struct ieee80211_vif *vif) +{ + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + struct ieee80211_hdr_3addr *nullfunc; + int ret; + u32 rate; + + nullfunc = kzalloc(sizeof(*nullfunc), GFP_KERNEL); + if (!nullfunc) { + ret = -ENOMEM; + goto out; + } + + nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_STYPE_NULLFUNC | + IEEE80211_FCTL_FROMDS); + + /* nullfunc->addr1 is filled by FW */ + + memcpy(nullfunc->addr2, vif->addr, ETH_ALEN); + memcpy(nullfunc->addr3, vif->addr, ETH_ALEN); + + rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); + ret = wl1271_cmd_template_set(wl, wlvif->role_id, + CMD_TEMPL_NULL_DATA, nullfunc, + sizeof(*nullfunc), 0, rate); + +out: + kfree(nullfunc); + return ret; +} + +static int wl1271_ap_init_qos_null_template(struct wl1271 *wl, + struct ieee80211_vif *vif) +{ + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + struct ieee80211_qos_hdr *qosnull; + int ret; + u32 rate; + + qosnull = kzalloc(sizeof(*qosnull), GFP_KERNEL); + if (!qosnull) { + ret = -ENOMEM; + goto out; + } + + qosnull->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_STYPE_QOS_NULLFUNC | + IEEE80211_FCTL_FROMDS); + + /* qosnull->addr1 is filled by FW */ + + memcpy(qosnull->addr2, vif->addr, ETH_ALEN); + memcpy(qosnull->addr3, vif->addr, ETH_ALEN); + + rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); + ret = wl1271_cmd_template_set(wl, wlvif->role_id, + CMD_TEMPL_QOS_NULL_DATA, qosnull, + sizeof(*qosnull), 0, rate); + +out: + kfree(qosnull); + return ret; +} + +static int wl12xx_init_rx_config(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_rx_msdu_life_time(wl); + if (ret < 0) + return ret; + + return 0; +} + +static int wl12xx_init_phy_vif_config(struct wl1271 *wl, + struct wl12xx_vif *wlvif) +{ + int ret; + + ret = wl1271_acx_slot(wl, wlvif, DEFAULT_SLOT_TIME); + if (ret < 0) + return ret; + + ret = wl1271_acx_service_period_timeout(wl, wlvif); + if (ret < 0) + return ret; + + ret = wl1271_acx_rts_threshold(wl, wlvif, wl->hw->wiphy->rts_threshold); + if (ret < 0) + return ret; + + return 0; +} + +static int wl1271_init_sta_beacon_filter(struct wl1271 *wl, + struct wl12xx_vif *wlvif) +{ + int ret; + + ret = wl1271_acx_beacon_filter_table(wl, wlvif); + if (ret < 0) + return ret; + + /* enable beacon filtering */ + ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true); + if (ret < 0) + return ret; + + return 0; +} + +int wl1271_init_pta(struct wl1271 *wl) +{ + int ret; + + ret = wl12xx_acx_sg_cfg(wl); + if (ret < 0) + return ret; + + ret = wl1271_acx_sg_enable(wl, wl->sg_enabled); + if (ret < 0) + return ret; + + return 0; +} + +int wl1271_init_energy_detection(struct wl1271 *wl) +{ + int ret; + + ret = wl1271_acx_cca_threshold(wl); + if (ret < 0) + return ret; + + return 0; +} + +static int wl1271_init_beacon_broadcast(struct wl1271 *wl, + struct wl12xx_vif *wlvif) +{ + int ret; + + ret = wl1271_acx_bcn_dtim_options(wl, wlvif); + if (ret < 0) + return ret; + + return 0; +} + +static int wl12xx_init_fwlog(struct wl1271 *wl) +{ + int ret; + + if (wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED) + return 0; + + ret = wl12xx_cmd_config_fwlog(wl); + if (ret < 0) + return ret; + + return 0; +} + +/* generic sta initialization (non vif-specific) */ +static int wl1271_sta_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + int ret; + + /* PS config */ + ret = wl12xx_acx_config_ps(wl, wlvif); + if (ret < 0) + return ret; + + /* FM WLAN coexistence */ + ret = wl1271_acx_fm_coex(wl); + if (ret < 0) + return ret; + + ret = wl1271_acx_sta_rate_policies(wl, wlvif); + if (ret < 0) + return ret; + + return 0; +} + +static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl, + struct ieee80211_vif *vif) +{ + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + int ret, i; + + /* disable all keep-alive templates */ + for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { + ret = wl1271_acx_keep_alive_config(wl, wlvif, i, + ACX_KEEP_ALIVE_TPL_INVALID); + if (ret < 0) + return ret; + } + + /* disable the keep-alive feature */ + ret = wl1271_acx_keep_alive_mode(wl, wlvif, false); + if (ret < 0) + return ret; + + return 0; +} + +/* generic ap initialization (non vif-specific) */ +static int wl1271_ap_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + int ret; + + ret = wl1271_init_ap_rates(wl, wlvif); + if (ret < 0) + return ret; + + return 0; +} + +int wl1271_ap_init_templates(struct wl1271 *wl, struct ieee80211_vif *vif) +{ + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + int ret; + + ret = wl1271_ap_init_deauth_template(wl, wlvif); + if (ret < 0) + return ret; + + ret = wl1271_ap_init_null_template(wl, vif); + if (ret < 0) + return ret; + + ret = wl1271_ap_init_qos_null_template(wl, vif); + if (ret < 0) + return ret; + + /* + * when operating as AP we want to receive external beacons for + * configuring ERP protection. + */ + ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false); + if (ret < 0) + return ret; + + return 0; +} + +static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl, + struct ieee80211_vif *vif) +{ + return wl1271_ap_init_templates(wl, vif); +} + +int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + int i, ret; + struct conf_tx_rate_class rc; + u32 supported_rates; + + wl1271_debug(DEBUG_AP, "AP basic rate set: 0x%x", + wlvif->basic_rate_set); + + if (wlvif->basic_rate_set == 0) + return -EINVAL; + + rc.enabled_rates = wlvif->basic_rate_set; + rc.long_retry_limit = 10; + rc.short_retry_limit = 10; + rc.aflags = 0; + ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.mgmt_rate_idx); + if (ret < 0) + return ret; + + /* use the min basic rate for AP broadcast/multicast */ + rc.enabled_rates = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); + rc.short_retry_limit = 10; + rc.long_retry_limit = 10; + rc.aflags = 0; + ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.bcast_rate_idx); + if (ret < 0) + return ret; + + /* + * If the basic rates contain OFDM rates, use OFDM only + * rates for unicast TX as well. Else use all supported rates. + */ + if ((wlvif->basic_rate_set & CONF_TX_OFDM_RATES)) + supported_rates = CONF_TX_OFDM_RATES; + else + supported_rates = CONF_TX_AP_ENABLED_RATES; + + /* unconditionally enable HT rates */ + supported_rates |= CONF_TX_MCS_RATES; + + /* configure unicast TX rate classes */ + for (i = 0; i < wl->conf.tx.ac_conf_count; i++) { + rc.enabled_rates = supported_rates; + rc.short_retry_limit = 10; + rc.long_retry_limit = 10; + rc.aflags = 0; + ret = wl1271_acx_ap_rate_policy(wl, &rc, + wlvif->ap.ucast_rate_idx[i]); + if (ret < 0) + return ret; + } + + return 0; +} + +static int wl1271_set_ba_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + /* Reset the BA RX indicators */ + wlvif->ba_allowed = true; + wl->ba_rx_session_count = 0; + + /* BA is supported in STA/AP modes */ + if (wlvif->bss_type != BSS_TYPE_AP_BSS && + wlvif->bss_type != BSS_TYPE_STA_BSS) { + wlvif->ba_support = false; + return 0; + } + + wlvif->ba_support = true; + + /* 802.11n initiator BA session setting */ + return wl12xx_acx_set_ba_initiator_policy(wl, wlvif); +} + +/* vif-specifc initialization */ +static int wl12xx_init_sta_role(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + int ret; + + ret = wl1271_acx_group_address_tbl(wl, wlvif, true, NULL, 0); + if (ret < 0) + return ret; + + /* Initialize connection monitoring thresholds */ + ret = wl1271_acx_conn_monit_params(wl, wlvif, false); + if (ret < 0) + return ret; + + /* Beacon filtering */ + ret = wl1271_init_sta_beacon_filter(wl, wlvif); + if (ret < 0) + return ret; + + /* Beacons and broadcast settings */ + ret = wl1271_init_beacon_broadcast(wl, wlvif); + if (ret < 0) + return ret; + + /* Configure rssi/snr averaging weights */ + ret = wl1271_acx_rssi_snr_avg_weights(wl, wlvif); + if (ret < 0) + return ret; + + return 0; +} + +/* vif-specific intialization */ +static int wl12xx_init_ap_role(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + int ret; + + ret = wl1271_acx_ap_max_tx_retry(wl, wlvif); + if (ret < 0) + return ret; + + /* initialize Tx power */ + ret = wl1271_acx_tx_power(wl, wlvif, wlvif->power_level); + if (ret < 0) + return ret; + + return 0; +} + +int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif) +{ + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + struct conf_tx_ac_category *conf_ac; + struct conf_tx_tid *conf_tid; + bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); + int ret, i; + + /* + * consider all existing roles before configuring psm. + * TODO: reconfigure on interface removal. + */ + if (!wl->ap_count) { + if (is_ap) { + /* Configure for power always on */ + ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); + if (ret < 0) + return ret; + } else if (!wl->sta_count) { + if (wl->quirks & WLCORE_QUIRK_NO_ELP) { + /* Configure for power always on */ + ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); + if (ret < 0) + return ret; + } else { + /* Configure for ELP power saving */ + ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); + if (ret < 0) + return ret; + } + } + } + + /* Mode specific init */ + if (is_ap) { + ret = wl1271_ap_hw_init(wl, wlvif); + if (ret < 0) + return ret; + + ret = wl12xx_init_ap_role(wl, wlvif); + if (ret < 0) + return ret; + } else { + ret = wl1271_sta_hw_init(wl, wlvif); + if (ret < 0) + return ret; + + ret = wl12xx_init_sta_role(wl, wlvif); + if (ret < 0) + return ret; + } + + wl12xx_init_phy_vif_config(wl, wlvif); + + /* Default TID/AC configuration */ + BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count); + for (i = 0; i < wl->conf.tx.tid_conf_count; i++) { + conf_ac = &wl->conf.tx.ac_conf[i]; + ret = wl1271_acx_ac_cfg(wl, wlvif, conf_ac->ac, + conf_ac->cw_min, conf_ac->cw_max, + conf_ac->aifsn, conf_ac->tx_op_limit); + if (ret < 0) + return ret; + + conf_tid = &wl->conf.tx.tid_conf[i]; + ret = wl1271_acx_tid_cfg(wl, wlvif, + conf_tid->queue_id, + conf_tid->channel_type, + conf_tid->tsid, + conf_tid->ps_scheme, + conf_tid->ack_policy, + conf_tid->apsd_conf[0], + conf_tid->apsd_conf[1]); + if (ret < 0) + return ret; + } + + /* Configure HW encryption */ + ret = wl1271_acx_feature_cfg(wl, wlvif); + if (ret < 0) + return ret; + + /* Mode specific init - post mem init */ + if (is_ap) + ret = wl1271_ap_hw_init_post_mem(wl, vif); + else + ret = wl1271_sta_hw_init_post_mem(wl, vif); + + if (ret < 0) + return ret; + + /* Configure initiator BA sessions policies */ + ret = wl1271_set_ba_policies(wl, wlvif); + if (ret < 0) + return ret; + + ret = wlcore_hw_init_vif(wl, wlvif); + if (ret < 0) + return ret; + + return 0; +} + +int wl1271_hw_init(struct wl1271 *wl) +{ + int ret; + + /* Chip-specific hw init */ + ret = wl->ops->hw_init(wl); + if (ret < 0) + return ret; + + /* Init templates */ + ret = wl1271_init_templates_config(wl); + if (ret < 0) + return ret; + + ret = wl12xx_acx_mem_cfg(wl); + if (ret < 0) + return ret; + + /* Configure the FW logger */ + ret = wl12xx_init_fwlog(wl); + if (ret < 0) + return ret; + + /* Bluetooth WLAN coexistence */ + ret = wl1271_init_pta(wl); + if (ret < 0) + return ret; + + /* Default memory configuration */ + ret = wl1271_acx_init_mem_config(wl); + if (ret < 0) + return ret; + + /* RX config */ + ret = wl12xx_init_rx_config(wl); + if (ret < 0) + goto out_free_memmap; + + ret = wl1271_acx_dco_itrim_params(wl); + if (ret < 0) + goto out_free_memmap; + + /* Configure TX patch complete interrupt behavior */ + ret = wl1271_acx_tx_config_options(wl); + if (ret < 0) + goto out_free_memmap; + + /* RX complete interrupt pacing */ + ret = wl1271_acx_init_rx_interrupt(wl); + if (ret < 0) + goto out_free_memmap; + + /* Energy detection */ + ret = wl1271_init_energy_detection(wl); + if (ret < 0) + goto out_free_memmap; + + /* Default fragmentation threshold */ + ret = wl1271_acx_frag_threshold(wl, wl->hw->wiphy->frag_threshold); + if (ret < 0) + goto out_free_memmap; + + /* Enable data path */ + ret = wl1271_cmd_data_path(wl, 1); + if (ret < 0) + goto out_free_memmap; + + /* configure PM */ + ret = wl1271_acx_pm_config(wl); + if (ret < 0) + goto out_free_memmap; + + ret = wl12xx_acx_set_rate_mgmt_params(wl); + if (ret < 0) + goto out_free_memmap; + + /* configure hangover */ + ret = wl12xx_acx_config_hangover(wl); + if (ret < 0) + goto out_free_memmap; + + return 0; + + out_free_memmap: + kfree(wl->target_mem_map); + wl->target_mem_map = NULL; + + return ret; +} diff --git a/trunk/drivers/net/wireless/wl12xx/init.h b/trunk/drivers/net/wireless/ti/wlcore/init.h similarity index 98% rename from trunk/drivers/net/wireless/wl12xx/init.h rename to trunk/drivers/net/wireless/ti/wlcore/init.h index 2da0f404ef6e..a45fbfddec19 100644 --- a/trunk/drivers/net/wireless/wl12xx/init.h +++ b/trunk/drivers/net/wireless/ti/wlcore/init.h @@ -24,7 +24,7 @@ #ifndef __INIT_H__ #define __INIT_H__ -#include "wl12xx.h" +#include "wlcore.h" int wl1271_hw_init_power_auth(struct wl1271 *wl); int wl1271_init_templates_config(struct wl1271 *wl); diff --git a/trunk/drivers/net/wireless/ti/wlcore/io.c b/trunk/drivers/net/wireless/ti/wlcore/io.c new file mode 100644 index 000000000000..7cd0081aede5 --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wlcore/io.c @@ -0,0 +1,173 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2010 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include + +#include "wlcore.h" +#include "debug.h" +#include "wl12xx_80211.h" +#include "io.h" +#include "tx.h" + +bool wl1271_set_block_size(struct wl1271 *wl) +{ + if (wl->if_ops->set_block_size) { + wl->if_ops->set_block_size(wl->dev, WL12XX_BUS_BLOCK_SIZE); + return true; + } + + return false; +} + +void wlcore_disable_interrupts(struct wl1271 *wl) +{ + disable_irq(wl->irq); +} +EXPORT_SYMBOL_GPL(wlcore_disable_interrupts); + +void wlcore_enable_interrupts(struct wl1271 *wl) +{ + enable_irq(wl->irq); +} +EXPORT_SYMBOL_GPL(wlcore_enable_interrupts); + +int wlcore_translate_addr(struct wl1271 *wl, int addr) +{ + struct wlcore_partition_set *part = &wl->curr_part; + + /* + * To translate, first check to which window of addresses the + * particular address belongs. Then subtract the starting address + * of that window from the address. Then, add offset of the + * translated region. + * + * The translated regions occur next to each other in physical device + * memory, so just add the sizes of the preceding address regions to + * get the offset to the new region. + */ + if ((addr >= part->mem.start) && + (addr < part->mem.start + part->mem.size)) + return addr - part->mem.start; + else if ((addr >= part->reg.start) && + (addr < part->reg.start + part->reg.size)) + return addr - part->reg.start + part->mem.size; + else if ((addr >= part->mem2.start) && + (addr < part->mem2.start + part->mem2.size)) + return addr - part->mem2.start + part->mem.size + + part->reg.size; + else if ((addr >= part->mem3.start) && + (addr < part->mem3.start + part->mem3.size)) + return addr - part->mem3.start + part->mem.size + + part->reg.size + part->mem2.size; + + WARN(1, "HW address 0x%x out of range", addr); + return 0; +} +EXPORT_SYMBOL_GPL(wlcore_translate_addr); + +/* Set the partitions to access the chip addresses + * + * To simplify driver code, a fixed (virtual) memory map is defined for + * register and memory addresses. Because in the chipset, in different stages + * of operation, those addresses will move around, an address translation + * mechanism is required. + * + * There are four partitions (three memory and one register partition), + * which are mapped to two different areas of the hardware memory. + * + * Virtual address + * space + * + * | | + * ...+----+--> mem.start + * Physical address ... | | + * space ... | | [PART_0] + * ... | | + * 00000000 <--+----+... ...+----+--> mem.start + mem.size + * | | ... | | + * |MEM | ... | | + * | | ... | | + * mem.size <--+----+... | | {unused area) + * | | ... | | + * |REG | ... | | + * mem.size | | ... | | + * + <--+----+... ...+----+--> reg.start + * reg.size | | ... | | + * |MEM2| ... | | [PART_1] + * | | ... | | + * ...+----+--> reg.start + reg.size + * | | + * + */ +void wlcore_set_partition(struct wl1271 *wl, + const struct wlcore_partition_set *p) +{ + /* copy partition info */ + memcpy(&wl->curr_part, p, sizeof(*p)); + + wl1271_debug(DEBUG_IO, "mem_start %08X mem_size %08X", + p->mem.start, p->mem.size); + wl1271_debug(DEBUG_IO, "reg_start %08X reg_size %08X", + p->reg.start, p->reg.size); + wl1271_debug(DEBUG_IO, "mem2_start %08X mem2_size %08X", + p->mem2.start, p->mem2.size); + wl1271_debug(DEBUG_IO, "mem3_start %08X mem3_size %08X", + p->mem3.start, p->mem3.size); + + wl1271_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start); + wl1271_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size); + wl1271_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start); + wl1271_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size); + wl1271_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start); + wl1271_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size); + /* + * We don't need the size of the last partition, as it is + * automatically calculated based on the total memory size and + * the sizes of the previous partitions. + */ + wl1271_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start); +} +EXPORT_SYMBOL_GPL(wlcore_set_partition); + +void wlcore_select_partition(struct wl1271 *wl, u8 part) +{ + wl1271_debug(DEBUG_IO, "setting partition %d", part); + + wlcore_set_partition(wl, &wl->ptable[part]); +} +EXPORT_SYMBOL_GPL(wlcore_select_partition); + +void wl1271_io_reset(struct wl1271 *wl) +{ + if (wl->if_ops->reset) + wl->if_ops->reset(wl->dev); +} + +void wl1271_io_init(struct wl1271 *wl) +{ + if (wl->if_ops->init) + wl->if_ops->init(wl->dev); +} diff --git a/trunk/drivers/net/wireless/ti/wlcore/io.h b/trunk/drivers/net/wireless/ti/wlcore/io.h new file mode 100644 index 000000000000..8942954b56a0 --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wlcore/io.h @@ -0,0 +1,187 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2008-2010 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __IO_H__ +#define __IO_H__ + +#include + +#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 + +#define HW_PARTITION_REGISTERS_ADDR 0x1FFC0 +#define HW_PART0_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR) +#define HW_PART0_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 4) +#define HW_PART1_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR + 8) +#define HW_PART1_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 12) +#define HW_PART2_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR + 16) +#define HW_PART2_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 20) +#define HW_PART3_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 24) + +#define HW_ACCESS_REGISTER_SIZE 4 + +#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 + +struct wl1271; + +void wlcore_disable_interrupts(struct wl1271 *wl); +void wlcore_enable_interrupts(struct wl1271 *wl); + +void wl1271_io_reset(struct wl1271 *wl); +void wl1271_io_init(struct wl1271 *wl); +int wlcore_translate_addr(struct wl1271 *wl, int addr); + +/* Raw target IO, address is not translated */ +static inline void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf, + size_t len, bool fixed) +{ + wl->if_ops->write(wl->dev, addr, buf, len, fixed); +} + +static inline void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf, + size_t len, bool fixed) +{ + wl->if_ops->read(wl->dev, addr, buf, len, fixed); +} + +static inline void wlcore_raw_read_data(struct wl1271 *wl, int reg, void *buf, + size_t len, bool fixed) +{ + wl1271_raw_read(wl, wl->rtable[reg], buf, len, fixed); +} + +static inline void wlcore_raw_write_data(struct wl1271 *wl, int reg, void *buf, + size_t len, bool fixed) +{ + wl1271_raw_write(wl, wl->rtable[reg], buf, len, fixed); +} + +static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr) +{ + wl1271_raw_read(wl, addr, &wl->buffer_32, + sizeof(wl->buffer_32), false); + + return le32_to_cpu(wl->buffer_32); +} + +static inline void wl1271_raw_write32(struct wl1271 *wl, int addr, u32 val) +{ + wl->buffer_32 = cpu_to_le32(val); + wl1271_raw_write(wl, addr, &wl->buffer_32, + sizeof(wl->buffer_32), false); +} + +static inline void wl1271_read(struct wl1271 *wl, int addr, void *buf, + size_t len, bool fixed) +{ + int physical; + + physical = wlcore_translate_addr(wl, addr); + + wl1271_raw_read(wl, physical, buf, len, fixed); +} + +static inline void wl1271_write(struct wl1271 *wl, int addr, void *buf, + size_t len, bool fixed) +{ + int physical; + + physical = wlcore_translate_addr(wl, addr); + + wl1271_raw_write(wl, physical, buf, len, fixed); +} + +static inline void wlcore_write_data(struct wl1271 *wl, int reg, void *buf, + size_t len, bool fixed) +{ + wl1271_write(wl, wl->rtable[reg], buf, len, fixed); +} + +static inline void wlcore_read_data(struct wl1271 *wl, int reg, void *buf, + size_t len, bool fixed) +{ + wl1271_read(wl, wl->rtable[reg], buf, len, fixed); +} + +static inline void wl1271_read_hwaddr(struct wl1271 *wl, int hwaddr, + void *buf, size_t len, bool fixed) +{ + int physical; + int addr; + + /* Addresses are stored internally as addresses to 32 bytes blocks */ + addr = hwaddr << 5; + + physical = wlcore_translate_addr(wl, addr); + + wl1271_raw_read(wl, physical, buf, len, fixed); +} + +static inline u32 wl1271_read32(struct wl1271 *wl, int addr) +{ + return wl1271_raw_read32(wl, wlcore_translate_addr(wl, addr)); +} + +static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val) +{ + wl1271_raw_write32(wl, wlcore_translate_addr(wl, addr), val); +} + +static inline u32 wlcore_read_reg(struct wl1271 *wl, int reg) +{ + return wl1271_raw_read32(wl, + wlcore_translate_addr(wl, wl->rtable[reg])); +} + +static inline void wlcore_write_reg(struct wl1271 *wl, int reg, u32 val) +{ + wl1271_raw_write32(wl, wlcore_translate_addr(wl, wl->rtable[reg]), val); +} + +static inline void wl1271_power_off(struct wl1271 *wl) +{ + wl->if_ops->power(wl->dev, false); + clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); +} + +static inline int wl1271_power_on(struct wl1271 *wl) +{ + int ret = wl->if_ops->power(wl->dev, true); + if (ret == 0) + set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); + + return ret; +} + +void wlcore_set_partition(struct wl1271 *wl, + const struct wlcore_partition_set *p); + +bool wl1271_set_block_size(struct wl1271 *wl); + +/* Functions from wl1271_main.c */ + +int wl1271_tx_dummy_packet(struct wl1271 *wl); + +void wlcore_select_partition(struct wl1271 *wl, u8 part); + +#endif diff --git a/trunk/drivers/net/wireless/ti/wlcore/main.c b/trunk/drivers/net/wireless/ti/wlcore/main.c new file mode 100644 index 000000000000..2b0f987660c6 --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wlcore/main.c @@ -0,0 +1,5093 @@ + +/* + * This file is part of wl1271 + * + * Copyright (C) 2008-2010 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wlcore.h" +#include "debug.h" +#include "wl12xx_80211.h" +#include "io.h" +#include "event.h" +#include "tx.h" +#include "rx.h" +#include "ps.h" +#include "init.h" +#include "debugfs.h" +#include "cmd.h" +#include "boot.h" +#include "testmode.h" +#include "scan.h" +#include "hw_ops.h" + +#define WL1271_BOOT_RETRIES 3 + +#define WL1271_BOOT_RETRIES 3 + +static char *fwlog_param; +static bool bug_on_recovery; +static bool no_recovery; + +static void __wl1271_op_remove_interface(struct wl1271 *wl, + struct ieee80211_vif *vif, + bool reset_tx_queues); +static void wl1271_op_stop(struct ieee80211_hw *hw); +static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif); + +static int wl12xx_set_authorized(struct wl1271 *wl, + struct wl12xx_vif *wlvif) +{ + int ret; + + if (WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS)) + return -EINVAL; + + if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + return 0; + + if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags)) + return 0; + + ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid); + if (ret < 0) + return ret; + + wl12xx_croc(wl, wlvif->role_id); + + wl1271_info("Association completed."); + return 0; +} + +static int wl1271_reg_notify(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct ieee80211_supported_band *band; + struct ieee80211_channel *ch; + int i; + + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + for (i = 0; i < band->n_channels; i++) { + ch = &band->channels[i]; + if (ch->flags & IEEE80211_CHAN_DISABLED) + continue; + + if (ch->flags & IEEE80211_CHAN_RADAR) + ch->flags |= IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN; + + } + + return 0; +} + +static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool enable) +{ + int ret = 0; + + /* we should hold wl->mutex */ + ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable); + if (ret < 0) + goto out; + + if (enable) + set_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags); + else + clear_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags); +out: + return ret; +} + +/* + * this function is being called when the rx_streaming interval + * has beed changed or rx_streaming should be disabled + */ +int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + int ret = 0; + int period = wl->conf.rx_streaming.interval; + + /* don't reconfigure if rx_streaming is disabled */ + if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags)) + goto out; + + /* reconfigure/disable according to new streaming_period */ + if (period && + test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) && + (wl->conf.rx_streaming.always || + test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))) + ret = wl1271_set_rx_streaming(wl, wlvif, true); + else { + ret = wl1271_set_rx_streaming(wl, wlvif, false); + /* don't cancel_work_sync since we might deadlock */ + del_timer_sync(&wlvif->rx_streaming_timer); + } +out: + return ret; +} + +static void wl1271_rx_streaming_enable_work(struct work_struct *work) +{ + int ret; + struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif, + rx_streaming_enable_work); + struct wl1271 *wl = wlvif->wl; + + mutex_lock(&wl->mutex); + + if (test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags) || + !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) || + (!wl->conf.rx_streaming.always && + !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))) + goto out; + + if (!wl->conf.rx_streaming.interval) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl1271_set_rx_streaming(wl, wlvif, true); + if (ret < 0) + goto out_sleep; + + /* stop it after some time of inactivity */ + mod_timer(&wlvif->rx_streaming_timer, + jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration)); + +out_sleep: + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); +} + +static void wl1271_rx_streaming_disable_work(struct work_struct *work) +{ + int ret; + struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif, + rx_streaming_disable_work); + struct wl1271 *wl = wlvif->wl; + + mutex_lock(&wl->mutex); + + if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags)) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl1271_set_rx_streaming(wl, wlvif, false); + if (ret) + goto out_sleep; + +out_sleep: + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); +} + +static void wl1271_rx_streaming_timer(unsigned long data) +{ + struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data; + struct wl1271 *wl = wlvif->wl; + ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work); +} + +/* wl->mutex must be taken */ +void wl12xx_rearm_tx_watchdog_locked(struct wl1271 *wl) +{ + /* if the watchdog is not armed, don't do anything */ + if (wl->tx_allocated_blocks == 0) + return; + + cancel_delayed_work(&wl->tx_watchdog_work); + ieee80211_queue_delayed_work(wl->hw, &wl->tx_watchdog_work, + msecs_to_jiffies(wl->conf.tx.tx_watchdog_timeout)); +} + +static void wl12xx_tx_watchdog_work(struct work_struct *work) +{ + struct delayed_work *dwork; + struct wl1271 *wl; + + dwork = container_of(work, struct delayed_work, work); + wl = container_of(dwork, struct wl1271, tx_watchdog_work); + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + + /* Tx went out in the meantime - everything is ok */ + if (unlikely(wl->tx_allocated_blocks == 0)) + goto out; + + /* + * if a ROC is in progress, we might not have any Tx for a long + * time (e.g. pending Tx on the non-ROC channels) + */ + if (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES) { + wl1271_debug(DEBUG_TX, "No Tx (in FW) for %d ms due to ROC", + wl->conf.tx.tx_watchdog_timeout); + wl12xx_rearm_tx_watchdog_locked(wl); + goto out; + } + + /* + * if a scan is in progress, we might not have any Tx for a long + * time + */ + if (wl->scan.state != WL1271_SCAN_STATE_IDLE) { + wl1271_debug(DEBUG_TX, "No Tx (in FW) for %d ms due to scan", + wl->conf.tx.tx_watchdog_timeout); + wl12xx_rearm_tx_watchdog_locked(wl); + goto out; + } + + /* + * AP might cache a frame for a long time for a sleeping station, + * so rearm the timer if there's an AP interface with stations. If + * Tx is genuinely stuck we will most hopefully discover it when all + * stations are removed due to inactivity. + */ + if (wl->active_sta_count) { + wl1271_debug(DEBUG_TX, "No Tx (in FW) for %d ms. AP has " + " %d stations", + wl->conf.tx.tx_watchdog_timeout, + wl->active_sta_count); + wl12xx_rearm_tx_watchdog_locked(wl); + goto out; + } + + wl1271_error("Tx stuck (in FW) for %d ms. Starting recovery", + wl->conf.tx.tx_watchdog_timeout); + wl12xx_queue_recovery_work(wl); + +out: + mutex_unlock(&wl->mutex); +} + +static void wlcore_adjust_conf(struct wl1271 *wl) +{ + /* Adjust settings according to optional module parameters */ + if (fwlog_param) { + if (!strcmp(fwlog_param, "continuous")) { + wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS; + } else if (!strcmp(fwlog_param, "ondemand")) { + wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND; + } else if (!strcmp(fwlog_param, "dbgpins")) { + wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS; + wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS; + } else if (!strcmp(fwlog_param, "disable")) { + wl->conf.fwlog.mem_blocks = 0; + wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE; + } else { + wl1271_error("Unknown fwlog parameter %s", fwlog_param); + } + } +} + +static int wl1271_plt_init(struct wl1271 *wl) +{ + int ret; + + ret = wl->ops->hw_init(wl); + if (ret < 0) + return ret; + + ret = wl1271_acx_init_mem_config(wl); + if (ret < 0) + return ret; + + ret = wl12xx_acx_mem_cfg(wl); + if (ret < 0) + goto out_free_memmap; + + /* Enable data path */ + ret = wl1271_cmd_data_path(wl, 1); + if (ret < 0) + goto out_free_memmap; + + /* Configure for CAM power saving (ie. always active) */ + ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); + if (ret < 0) + goto out_free_memmap; + + /* configure PM */ + ret = wl1271_acx_pm_config(wl); + if (ret < 0) + goto out_free_memmap; + + return 0; + + out_free_memmap: + kfree(wl->target_mem_map); + wl->target_mem_map = NULL; + + return ret; +} + +static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + u8 hlid, u8 tx_pkts) +{ + bool fw_ps, single_sta; + + fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); + single_sta = (wl->active_sta_count == 1); + + /* + * Wake up from high level PS if the STA is asleep with too little + * packets in FW or if the STA is awake. + */ + if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS) + wl12xx_ps_link_end(wl, wlvif, hlid); + + /* + * Start high-level PS if the STA is asleep with enough blocks in FW. + * Make an exception if this is the only connected station. In this + * case FW-memory congestion is not a problem. + */ + else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) + wl12xx_ps_link_start(wl, wlvif, hlid, true); +} + +static void wl12xx_irq_update_links_status(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + struct wl_fw_status *status) +{ + struct wl1271_link *lnk; + u32 cur_fw_ps_map; + u8 hlid, cnt; + + /* TODO: also use link_fast_bitmap here */ + + cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap); + if (wl->ap_fw_ps_map != cur_fw_ps_map) { + wl1271_debug(DEBUG_PSM, + "link ps prev 0x%x cur 0x%x changed 0x%x", + wl->ap_fw_ps_map, cur_fw_ps_map, + wl->ap_fw_ps_map ^ cur_fw_ps_map); + + wl->ap_fw_ps_map = cur_fw_ps_map; + } + + for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) { + lnk = &wl->links[hlid]; + cnt = status->counters.tx_lnk_free_pkts[hlid] - + lnk->prev_freed_pkts; + + lnk->prev_freed_pkts = status->counters.tx_lnk_free_pkts[hlid]; + lnk->allocated_pkts -= cnt; + + wl12xx_irq_ps_regulate_link(wl, wlvif, hlid, + lnk->allocated_pkts); + } +} + +static void wl12xx_fw_status(struct wl1271 *wl, + struct wl_fw_status *status) +{ + struct wl12xx_vif *wlvif; + struct timespec ts; + u32 old_tx_blk_count = wl->tx_blocks_available; + int avail, freed_blocks; + int i; + size_t status_len; + + status_len = sizeof(*status) + wl->fw_status_priv_len; + + wlcore_raw_read_data(wl, REG_RAW_FW_STATUS_ADDR, status, + status_len, false); + + wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, " + "drv_rx_counter = %d, tx_results_counter = %d)", + status->intr, + status->fw_rx_counter, + status->drv_rx_counter, + status->tx_results_counter); + + for (i = 0; i < NUM_TX_QUEUES; i++) { + /* prevent wrap-around in freed-packets counter */ + wl->tx_allocated_pkts[i] -= + (status->counters.tx_released_pkts[i] - + wl->tx_pkts_freed[i]) & 0xff; + + wl->tx_pkts_freed[i] = status->counters.tx_released_pkts[i]; + } + + /* prevent wrap-around in total blocks counter */ + if (likely(wl->tx_blocks_freed <= + le32_to_cpu(status->total_released_blks))) + freed_blocks = le32_to_cpu(status->total_released_blks) - + wl->tx_blocks_freed; + else + freed_blocks = 0x100000000LL - wl->tx_blocks_freed + + le32_to_cpu(status->total_released_blks); + + wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks); + + wl->tx_allocated_blocks -= freed_blocks; + + /* + * If the FW freed some blocks: + * If we still have allocated blocks - re-arm the timer, Tx is + * not stuck. Otherwise, cancel the timer (no Tx currently). + */ + if (freed_blocks) { + if (wl->tx_allocated_blocks) + wl12xx_rearm_tx_watchdog_locked(wl); + else + cancel_delayed_work(&wl->tx_watchdog_work); + } + + avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks; + + /* + * The FW might change the total number of TX memblocks before + * we get a notification about blocks being released. Thus, the + * available blocks calculation might yield a temporary result + * which is lower than the actual available blocks. Keeping in + * mind that only blocks that were allocated can be moved from + * TX to RX, tx_blocks_available should never decrease here. + */ + wl->tx_blocks_available = max((int)wl->tx_blocks_available, + avail); + + /* if more blocks are available now, tx work can be scheduled */ + if (wl->tx_blocks_available > old_tx_blk_count) + clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); + + /* for AP update num of allocated TX blocks per link and ps status */ + wl12xx_for_each_wlvif_ap(wl, wlvif) { + wl12xx_irq_update_links_status(wl, wlvif, status); + } + + /* update the host-chipset time offset */ + getnstimeofday(&ts); + wl->time_offset = (timespec_to_ns(&ts) >> 10) - + (s64)le32_to_cpu(status->fw_localtime); +} + +static void wl1271_flush_deferred_work(struct wl1271 *wl) +{ + struct sk_buff *skb; + + /* Pass all received frames to the network stack */ + while ((skb = skb_dequeue(&wl->deferred_rx_queue))) + ieee80211_rx_ni(wl->hw, skb); + + /* Return sent skbs to the network stack */ + while ((skb = skb_dequeue(&wl->deferred_tx_queue))) + ieee80211_tx_status_ni(wl->hw, skb); +} + +static void wl1271_netstack_work(struct work_struct *work) +{ + struct wl1271 *wl = + container_of(work, struct wl1271, netstack_work); + + do { + wl1271_flush_deferred_work(wl); + } while (skb_queue_len(&wl->deferred_rx_queue)); +} + +#define WL1271_IRQ_MAX_LOOPS 256 + +static irqreturn_t wl1271_irq(int irq, void *cookie) +{ + int ret; + u32 intr; + int loopcount = WL1271_IRQ_MAX_LOOPS; + struct wl1271 *wl = (struct wl1271 *)cookie; + bool done = false; + unsigned int defer_count; + unsigned long flags; + + /* TX might be handled here, avoid redundant work */ + set_bit(WL1271_FLAG_TX_PENDING, &wl->flags); + cancel_work_sync(&wl->tx_work); + + /* + * In case edge triggered interrupt must be used, we cannot iterate + * more than once without introducing race conditions with the hardirq. + */ + if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) + loopcount = 1; + + mutex_lock(&wl->mutex); + + wl1271_debug(DEBUG_IRQ, "IRQ work"); + + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + while (!done && loopcount--) { + /* + * In order to avoid a race with the hardirq, clear the flag + * before acknowledging the chip. Since the mutex is held, + * wl1271_ps_elp_wakeup cannot be called concurrently. + */ + clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); + smp_mb__after_clear_bit(); + + wl12xx_fw_status(wl, wl->fw_status); + + wlcore_hw_tx_immediate_compl(wl); + + intr = le32_to_cpu(wl->fw_status->intr); + intr &= WL1271_INTR_MASK; + if (!intr) { + done = true; + continue; + } + + if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) { + wl1271_error("watchdog interrupt received! " + "starting recovery."); + wl12xx_queue_recovery_work(wl); + + /* restarting the chip. ignore any other interrupt. */ + goto out; + } + + if (likely(intr & WL1271_ACX_INTR_DATA)) { + wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA"); + + wl12xx_rx(wl, wl->fw_status); + + /* Check if any tx blocks were freed */ + spin_lock_irqsave(&wl->wl_lock, flags); + if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) && + wl1271_tx_total_queue_count(wl) > 0) { + spin_unlock_irqrestore(&wl->wl_lock, flags); + /* + * In order to avoid starvation of the TX path, + * call the work function directly. + */ + wl1271_tx_work_locked(wl); + } else { + spin_unlock_irqrestore(&wl->wl_lock, flags); + } + + /* check for tx results */ + wlcore_hw_tx_delayed_compl(wl); + + /* Make sure the deferred queues don't get too long */ + defer_count = skb_queue_len(&wl->deferred_tx_queue) + + skb_queue_len(&wl->deferred_rx_queue); + if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT) + wl1271_flush_deferred_work(wl); + } + + if (intr & WL1271_ACX_INTR_EVENT_A) { + wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A"); + wl1271_event_handle(wl, 0); + } + + if (intr & WL1271_ACX_INTR_EVENT_B) { + wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B"); + wl1271_event_handle(wl, 1); + } + + if (intr & WL1271_ACX_INTR_INIT_COMPLETE) + wl1271_debug(DEBUG_IRQ, + "WL1271_ACX_INTR_INIT_COMPLETE"); + + if (intr & WL1271_ACX_INTR_HW_AVAILABLE) + wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE"); + } + + wl1271_ps_elp_sleep(wl); + +out: + spin_lock_irqsave(&wl->wl_lock, flags); + /* In case TX was not handled here, queue TX work */ + clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags); + if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) && + wl1271_tx_total_queue_count(wl) > 0) + ieee80211_queue_work(wl->hw, &wl->tx_work); + spin_unlock_irqrestore(&wl->wl_lock, flags); + + mutex_unlock(&wl->mutex); + + return IRQ_HANDLED; +} + +struct vif_counter_data { + u8 counter; + + struct ieee80211_vif *cur_vif; + bool cur_vif_running; +}; + +static void wl12xx_vif_count_iter(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct vif_counter_data *counter = data; + + counter->counter++; + if (counter->cur_vif == vif) + counter->cur_vif_running = true; +} + +/* caller must not hold wl->mutex, as it might deadlock */ +static void wl12xx_get_vif_count(struct ieee80211_hw *hw, + struct ieee80211_vif *cur_vif, + struct vif_counter_data *data) +{ + memset(data, 0, sizeof(*data)); + data->cur_vif = cur_vif; + + ieee80211_iterate_active_interfaces(hw, + wl12xx_vif_count_iter, data); +} + +static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt) +{ + const struct firmware *fw; + const char *fw_name; + enum wl12xx_fw_type fw_type; + int ret; + + if (plt) { + fw_type = WL12XX_FW_TYPE_PLT; + fw_name = wl->plt_fw_name; + } else { + /* + * we can't call wl12xx_get_vif_count() here because + * wl->mutex is taken, so use the cached last_vif_count value + */ + if (wl->last_vif_count > 1) { + fw_type = WL12XX_FW_TYPE_MULTI; + fw_name = wl->mr_fw_name; + } else { + fw_type = WL12XX_FW_TYPE_NORMAL; + fw_name = wl->sr_fw_name; + } + } + + if (wl->fw_type == fw_type) + return 0; + + wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name); + + ret = request_firmware(&fw, fw_name, wl->dev); + + if (ret < 0) { + wl1271_error("could not get firmware %s: %d", fw_name, ret); + return ret; + } + + if (fw->size % 4) { + wl1271_error("firmware size is not multiple of 32 bits: %zu", + fw->size); + ret = -EILSEQ; + goto out; + } + + vfree(wl->fw); + wl->fw_type = WL12XX_FW_TYPE_NONE; + wl->fw_len = fw->size; + wl->fw = vmalloc(wl->fw_len); + + if (!wl->fw) { + wl1271_error("could not allocate memory for the firmware"); + ret = -ENOMEM; + goto out; + } + + memcpy(wl->fw, fw->data, wl->fw_len); + ret = 0; + wl->fw_type = fw_type; +out: + release_firmware(fw); + + return ret; +} + +static int wl1271_fetch_nvs(struct wl1271 *wl) +{ + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev); + + if (ret < 0) { + wl1271_error("could not get nvs file %s: %d", WL12XX_NVS_NAME, + ret); + return ret; + } + + wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL); + + if (!wl->nvs) { + wl1271_error("could not allocate memory for the nvs file"); + ret = -ENOMEM; + goto out; + } + + wl->nvs_len = fw->size; + +out: + release_firmware(fw); + + return ret; +} + +void wl12xx_queue_recovery_work(struct wl1271 *wl) +{ + if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) + ieee80211_queue_work(wl->hw, &wl->recovery_work); +} + +size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen) +{ + size_t len = 0; + + /* The FW log is a length-value list, find where the log end */ + while (len < maxlen) { + if (memblock[len] == 0) + break; + if (len + memblock[len] + 1 > maxlen) + break; + len += memblock[len] + 1; + } + + /* Make sure we have enough room */ + len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size)); + + /* Fill the FW log file, consumed by the sysfs fwlog entry */ + memcpy(wl->fwlog + wl->fwlog_size, memblock, len); + wl->fwlog_size += len; + + return len; +} + +static void wl12xx_read_fwlog_panic(struct wl1271 *wl) +{ + u32 addr; + u32 first_addr; + u8 *block; + + if ((wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED) || + (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) || + (wl->conf.fwlog.mem_blocks == 0)) + return; + + wl1271_info("Reading FW panic log"); + + block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL); + if (!block) + return; + + /* + * Make sure the chip is awake and the logger isn't active. + * This might fail if the firmware hanged. + */ + if (!wl1271_ps_elp_wakeup(wl)) + wl12xx_cmd_stop_fwlog(wl); + + /* Read the first memory block address */ + wl12xx_fw_status(wl, wl->fw_status); + first_addr = le32_to_cpu(wl->fw_status->log_start_addr); + if (!first_addr) + goto out; + + /* Traverse the memory blocks linked list */ + addr = first_addr; + do { + memset(block, 0, WL12XX_HW_BLOCK_SIZE); + wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE, + false); + + /* + * Memory blocks are linked to one another. The first 4 bytes + * of each memory block hold the hardware address of the next + * one. The last memory block points to the first one. + */ + addr = le32_to_cpup((__le32 *)block); + if (!wl12xx_copy_fwlog(wl, block + sizeof(addr), + WL12XX_HW_BLOCK_SIZE - sizeof(addr))) + break; + } while (addr && (addr != first_addr)); + + wake_up_interruptible(&wl->fwlog_waitq); + +out: + kfree(block); +} + +static void wl1271_recovery_work(struct work_struct *work) +{ + struct wl1271 *wl = + container_of(work, struct wl1271, recovery_work); + struct wl12xx_vif *wlvif; + struct ieee80211_vif *vif; + + mutex_lock(&wl->mutex); + + if (wl->state != WL1271_STATE_ON || wl->plt) + goto out_unlock; + + /* Avoid a recursive recovery */ + set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags); + + wl12xx_read_fwlog_panic(wl); + + wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x", + wl->chip.fw_ver_str, + wlcore_read_reg(wl, REG_PC_ON_RECOVERY)); + + BUG_ON(bug_on_recovery && + !test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)); + + if (no_recovery) { + wl1271_info("No recovery (chosen on module load). Fw will remain stuck."); + clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags); + goto out_unlock; + } + + BUG_ON(bug_on_recovery); + + /* + * Advance security sequence number to overcome potential progress + * in the firmware during recovery. This doens't hurt if the network is + * not encrypted. + */ + wl12xx_for_each_wlvif(wl, wlvif) { + if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) || + test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) + wlvif->tx_security_seq += + WL1271_TX_SQN_POST_RECOVERY_PADDING; + } + + /* Prevent spurious TX during FW restart */ + ieee80211_stop_queues(wl->hw); + + if (wl->sched_scanning) { + ieee80211_sched_scan_stopped(wl->hw); + wl->sched_scanning = false; + } + + /* reboot the chipset */ + while (!list_empty(&wl->wlvif_list)) { + wlvif = list_first_entry(&wl->wlvif_list, + struct wl12xx_vif, list); + vif = wl12xx_wlvif_to_vif(wlvif); + __wl1271_op_remove_interface(wl, vif, false); + } + mutex_unlock(&wl->mutex); + wl1271_op_stop(wl->hw); + + clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags); + + ieee80211_restart_hw(wl->hw); + + /* + * Its safe to enable TX now - the queues are stopped after a request + * to restart the HW. + */ + ieee80211_wake_queues(wl->hw); + return; +out_unlock: + mutex_unlock(&wl->mutex); +} + +static void wl1271_fw_wakeup(struct wl1271 *wl) +{ + wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP); +} + +static int wl1271_setup(struct wl1271 *wl) +{ + wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL); + if (!wl->fw_status) + return -ENOMEM; + + wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL); + if (!wl->tx_res_if) { + kfree(wl->fw_status); + return -ENOMEM; + } + + return 0; +} + +static int wl12xx_set_power_on(struct wl1271 *wl) +{ + int ret; + + msleep(WL1271_PRE_POWER_ON_SLEEP); + ret = wl1271_power_on(wl); + if (ret < 0) + goto out; + msleep(WL1271_POWER_ON_SLEEP); + wl1271_io_reset(wl); + wl1271_io_init(wl); + + wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); + + /* ELP module wake up */ + wl1271_fw_wakeup(wl); + +out: + return ret; +} + +static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt) +{ + int ret = 0; + + ret = wl12xx_set_power_on(wl); + if (ret < 0) + goto out; + + /* + * For wl127x based devices we could use the default block + * size (512 bytes), but due to a bug in the sdio driver, we + * need to set it explicitly after the chip is powered on. To + * simplify the code and since the performance impact is + * negligible, we use the same block size for all different + * chip types. + */ + if (wl1271_set_block_size(wl)) + wl->quirks |= WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN; + + ret = wl->ops->identify_chip(wl); + if (ret < 0) + goto out; + + /* TODO: make sure the lower driver has set things up correctly */ + + ret = wl1271_setup(wl); + if (ret < 0) + goto out; + + ret = wl12xx_fetch_firmware(wl, plt); + if (ret < 0) + goto out; + + /* No NVS from netlink, try to get it from the filesystem */ + if (wl->nvs == NULL) { + ret = wl1271_fetch_nvs(wl); + if (ret < 0) + goto out; + } + +out: + return ret; +} + +int wl1271_plt_start(struct wl1271 *wl) +{ + int retries = WL1271_BOOT_RETRIES; + struct wiphy *wiphy = wl->hw->wiphy; + int ret; + + mutex_lock(&wl->mutex); + + wl1271_notice("power up"); + + if (wl->state != WL1271_STATE_OFF) { + wl1271_error("cannot go into PLT state because not " + "in off state: %d", wl->state); + ret = -EBUSY; + goto out; + } + + while (retries) { + retries--; + ret = wl12xx_chip_wakeup(wl, true); + if (ret < 0) + goto power_off; + + ret = wl->ops->boot(wl); + if (ret < 0) + goto power_off; + + ret = wl1271_plt_init(wl); + if (ret < 0) + goto irq_disable; + + wl->plt = true; + wl->state = WL1271_STATE_ON; + wl1271_notice("firmware booted in PLT mode (%s)", + wl->chip.fw_ver_str); + + /* update hw/fw version info in wiphy struct */ + wiphy->hw_version = wl->chip.id; + strncpy(wiphy->fw_version, wl->chip.fw_ver_str, + sizeof(wiphy->fw_version)); + + goto out; + +irq_disable: + mutex_unlock(&wl->mutex); + /* Unlocking the mutex in the middle of handling is + inherently unsafe. In this case we deem it safe to do, + because we need to let any possibly pending IRQ out of + the system (and while we are WL1271_STATE_OFF the IRQ + work function will not do anything.) Also, any other + possible concurrent operations will fail due to the + current state, hence the wl1271 struct should be safe. */ + wlcore_disable_interrupts(wl); + wl1271_flush_deferred_work(wl); + cancel_work_sync(&wl->netstack_work); + mutex_lock(&wl->mutex); +power_off: + wl1271_power_off(wl); + } + + wl1271_error("firmware boot in PLT mode failed despite %d retries", + WL1271_BOOT_RETRIES); +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +int wl1271_plt_stop(struct wl1271 *wl) +{ + int ret = 0; + + wl1271_notice("power down"); + + /* + * Interrupts must be disabled before setting the state to OFF. + * Otherwise, the interrupt handler might be called and exit without + * reading the interrupt status. + */ + wlcore_disable_interrupts(wl); + mutex_lock(&wl->mutex); + if (!wl->plt) { + mutex_unlock(&wl->mutex); + + /* + * This will not necessarily enable interrupts as interrupts + * may have been disabled when op_stop was called. It will, + * however, balance the above call to disable_interrupts(). + */ + wlcore_enable_interrupts(wl); + + wl1271_error("cannot power down because not in PLT " + "state: %d", wl->state); + ret = -EBUSY; + goto out; + } + + mutex_unlock(&wl->mutex); + + wl1271_flush_deferred_work(wl); + cancel_work_sync(&wl->netstack_work); + cancel_work_sync(&wl->recovery_work); + cancel_delayed_work_sync(&wl->elp_work); + cancel_delayed_work_sync(&wl->tx_watchdog_work); + + mutex_lock(&wl->mutex); + wl1271_power_off(wl); + wl->flags = 0; + wl->state = WL1271_STATE_OFF; + wl->plt = false; + wl->rx_counter = 0; + mutex_unlock(&wl->mutex); + +out: + return ret; +} + +static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct wl1271 *wl = hw->priv; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_vif *vif = info->control.vif; + struct wl12xx_vif *wlvif = NULL; + unsigned long flags; + int q, mapping; + u8 hlid; + + if (vif) + wlvif = wl12xx_vif_to_data(vif); + + mapping = skb_get_queue_mapping(skb); + q = wl1271_tx_get_queue(mapping); + + hlid = wl12xx_tx_get_hlid(wl, wlvif, skb); + + spin_lock_irqsave(&wl->wl_lock, flags); + + /* queue the packet */ + if (hlid == WL12XX_INVALID_LINK_ID || + (wlvif && !test_bit(hlid, wlvif->links_map))) { + wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q); + ieee80211_free_txskb(hw, skb); + goto out; + } + + wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d len %d", + hlid, q, skb->len); + skb_queue_tail(&wl->links[hlid].tx_queue[q], skb); + + wl->tx_queue_count[q]++; + + /* + * The workqueue is slow to process the tx_queue and we need stop + * the queue here, otherwise the queue will get too long. + */ + if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) { + wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q); + ieee80211_stop_queue(wl->hw, mapping); + set_bit(q, &wl->stopped_queues_map); + } + + /* + * The chip specific setup must run before the first TX packet - + * before that, the tx_work will not be initialized! + */ + + if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) && + !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags)) + ieee80211_queue_work(wl->hw, &wl->tx_work); + +out: + spin_unlock_irqrestore(&wl->wl_lock, flags); +} + +int wl1271_tx_dummy_packet(struct wl1271 *wl) +{ + unsigned long flags; + int q; + + /* no need to queue a new dummy packet if one is already pending */ + if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) + return 0; + + q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet)); + + spin_lock_irqsave(&wl->wl_lock, flags); + set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); + wl->tx_queue_count[q]++; + spin_unlock_irqrestore(&wl->wl_lock, flags); + + /* The FW is low on RX memory blocks, so send the dummy packet asap */ + if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags)) + wl1271_tx_work_locked(wl); + + /* + * If the FW TX is busy, TX work will be scheduled by the threaded + * interrupt handler function + */ + return 0; +} + +/* + * The size of the dummy packet should be at least 1400 bytes. However, in + * order to minimize the number of bus transactions, aligning it to 512 bytes + * boundaries could be beneficial, performance wise + */ +#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512)) + +static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl) +{ + struct sk_buff *skb; + struct ieee80211_hdr_3addr *hdr; + unsigned int dummy_packet_size; + + dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE - + sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr); + + skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE); + if (!skb) { + wl1271_warning("Failed to allocate a dummy packet skb"); + return NULL; + } + + skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr)); + + hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr)); + memset(hdr, 0, sizeof(*hdr)); + hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_STYPE_NULLFUNC | + IEEE80211_FCTL_TODS); + + memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size); + + /* Dummy packets require the TID to be management */ + skb->priority = WL1271_TID_MGMT; + + /* Initialize all fields that might be used */ + skb_set_queue_mapping(skb, 0); + memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info)); + + return skb; +} + + +#ifdef CONFIG_PM +static int wl1271_configure_suspend_sta(struct wl1271 *wl, + struct wl12xx_vif *wlvif) +{ + int ret = 0; + + if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl1271_acx_wake_up_conditions(wl, wlvif, + wl->conf.conn.suspend_wake_up_event, + wl->conf.conn.suspend_listen_interval); + + if (ret < 0) + wl1271_error("suspend: set wake up conditions failed: %d", ret); + + wl1271_ps_elp_sleep(wl); + +out: + return ret; + +} + +static int wl1271_configure_suspend_ap(struct wl1271 *wl, + struct wl12xx_vif *wlvif) +{ + int ret = 0; + + if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true); + + wl1271_ps_elp_sleep(wl); +out: + return ret; + +} + +static int wl1271_configure_suspend(struct wl1271 *wl, + struct wl12xx_vif *wlvif) +{ + if (wlvif->bss_type == BSS_TYPE_STA_BSS) + return wl1271_configure_suspend_sta(wl, wlvif); + if (wlvif->bss_type == BSS_TYPE_AP_BSS) + return wl1271_configure_suspend_ap(wl, wlvif); + return 0; +} + +static void wl1271_configure_resume(struct wl1271 *wl, + struct wl12xx_vif *wlvif) +{ + int ret = 0; + bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS; + bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS; + + if ((!is_ap) && (!is_sta)) + return; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + return; + + if (is_sta) { + ret = wl1271_acx_wake_up_conditions(wl, wlvif, + wl->conf.conn.wake_up_event, + wl->conf.conn.listen_interval); + + if (ret < 0) + wl1271_error("resume: wake up conditions failed: %d", + ret); + + } else if (is_ap) { + ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false); + } + + wl1271_ps_elp_sleep(wl); +} + +static int wl1271_op_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wow) +{ + struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif; + int ret; + + wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow); + WARN_ON(!wow || !wow->any); + + wl1271_tx_flush(wl); + + mutex_lock(&wl->mutex); + wl->wow_enabled = true; + wl12xx_for_each_wlvif(wl, wlvif) { + ret = wl1271_configure_suspend(wl, wlvif); + if (ret < 0) { + wl1271_warning("couldn't prepare device to suspend"); + return ret; + } + } + mutex_unlock(&wl->mutex); + /* flush any remaining work */ + wl1271_debug(DEBUG_MAC80211, "flushing remaining works"); + + /* + * disable and re-enable interrupts in order to flush + * the threaded_irq + */ + wlcore_disable_interrupts(wl); + + /* + * set suspended flag to avoid triggering a new threaded_irq + * work. no need for spinlock as interrupts are disabled. + */ + set_bit(WL1271_FLAG_SUSPENDED, &wl->flags); + + wlcore_enable_interrupts(wl); + flush_work(&wl->tx_work); + flush_delayed_work(&wl->elp_work); + + return 0; +} + +static int wl1271_op_resume(struct ieee80211_hw *hw) +{ + struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif; + unsigned long flags; + bool run_irq_work = false; + + wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d", + wl->wow_enabled); + WARN_ON(!wl->wow_enabled); + + /* + * re-enable irq_work enqueuing, and call irq_work directly if + * there is a pending work. + */ + spin_lock_irqsave(&wl->wl_lock, flags); + clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags); + if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags)) + run_irq_work = true; + spin_unlock_irqrestore(&wl->wl_lock, flags); + + if (run_irq_work) { + wl1271_debug(DEBUG_MAC80211, + "run postponed irq_work directly"); + wl1271_irq(0, wl); + wlcore_enable_interrupts(wl); + } + + mutex_lock(&wl->mutex); + wl12xx_for_each_wlvif(wl, wlvif) { + wl1271_configure_resume(wl, wlvif); + } + wl->wow_enabled = false; + mutex_unlock(&wl->mutex); + + return 0; +} +#endif + +static int wl1271_op_start(struct ieee80211_hw *hw) +{ + wl1271_debug(DEBUG_MAC80211, "mac80211 start"); + + /* + * We have to delay the booting of the hardware because + * we need to know the local MAC address before downloading and + * initializing the firmware. The MAC address cannot be changed + * after boot, and without the proper MAC address, the firmware + * will not function properly. + * + * The MAC address is first known when the corresponding interface + * is added. That is where we will initialize the hardware. + */ + + return 0; +} + +static void wl1271_op_stop(struct ieee80211_hw *hw) +{ + struct wl1271 *wl = hw->priv; + int i; + + wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); + + /* + * Interrupts must be disabled before setting the state to OFF. + * Otherwise, the interrupt handler might be called and exit without + * reading the interrupt status. + */ + wlcore_disable_interrupts(wl); + mutex_lock(&wl->mutex); + if (wl->state == WL1271_STATE_OFF) { + mutex_unlock(&wl->mutex); + + /* + * This will not necessarily enable interrupts as interrupts + * may have been disabled when op_stop was called. It will, + * however, balance the above call to disable_interrupts(). + */ + wlcore_enable_interrupts(wl); + return; + } + + /* + * this must be before the cancel_work calls below, so that the work + * functions don't perform further work. + */ + wl->state = WL1271_STATE_OFF; + mutex_unlock(&wl->mutex); + + wl1271_flush_deferred_work(wl); + cancel_delayed_work_sync(&wl->scan_complete_work); + cancel_work_sync(&wl->netstack_work); + cancel_work_sync(&wl->tx_work); + cancel_delayed_work_sync(&wl->elp_work); + cancel_delayed_work_sync(&wl->tx_watchdog_work); + + /* let's notify MAC80211 about the remaining pending TX frames */ + wl12xx_tx_reset(wl, true); + mutex_lock(&wl->mutex); + + wl1271_power_off(wl); + + wl->band = IEEE80211_BAND_2GHZ; + + wl->rx_counter = 0; + wl->power_level = WL1271_DEFAULT_POWER_LEVEL; + wl->tx_blocks_available = 0; + wl->tx_allocated_blocks = 0; + wl->tx_results_count = 0; + wl->tx_packets_count = 0; + wl->time_offset = 0; + wl->ap_fw_ps_map = 0; + wl->ap_ps_map = 0; + wl->sched_scanning = false; + memset(wl->roles_map, 0, sizeof(wl->roles_map)); + memset(wl->links_map, 0, sizeof(wl->links_map)); + memset(wl->roc_map, 0, sizeof(wl->roc_map)); + wl->active_sta_count = 0; + + /* The system link is always allocated */ + __set_bit(WL12XX_SYSTEM_HLID, wl->links_map); + + /* + * this is performed after the cancel_work calls and the associated + * mutex_lock, so that wl1271_op_add_interface does not accidentally + * get executed before all these vars have been reset. + */ + wl->flags = 0; + + wl->tx_blocks_freed = 0; + + for (i = 0; i < NUM_TX_QUEUES; i++) { + wl->tx_pkts_freed[i] = 0; + wl->tx_allocated_pkts[i] = 0; + } + + wl1271_debugfs_reset(wl); + + kfree(wl->fw_status); + wl->fw_status = NULL; + kfree(wl->tx_res_if); + wl->tx_res_if = NULL; + kfree(wl->target_mem_map); + wl->target_mem_map = NULL; + + mutex_unlock(&wl->mutex); +} + +static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx) +{ + u8 policy = find_first_zero_bit(wl->rate_policies_map, + WL12XX_MAX_RATE_POLICIES); + if (policy >= WL12XX_MAX_RATE_POLICIES) + return -EBUSY; + + __set_bit(policy, wl->rate_policies_map); + *idx = policy; + return 0; +} + +static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx) +{ + if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES)) + return; + + __clear_bit(*idx, wl->rate_policies_map); + *idx = WL12XX_MAX_RATE_POLICIES; +} + +static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + switch (wlvif->bss_type) { + case BSS_TYPE_AP_BSS: + if (wlvif->p2p) + return WL1271_ROLE_P2P_GO; + else + return WL1271_ROLE_AP; + + case BSS_TYPE_STA_BSS: + if (wlvif->p2p) + return WL1271_ROLE_P2P_CL; + else + return WL1271_ROLE_STA; + + case BSS_TYPE_IBSS: + return WL1271_ROLE_IBSS; + + default: + wl1271_error("invalid bss_type: %d", wlvif->bss_type); + } + return WL12XX_INVALID_ROLE_TYPE; +} + +static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif) +{ + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + int i; + + /* clear everything but the persistent data */ + memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent)); + + switch (ieee80211_vif_type_p2p(vif)) { + case NL80211_IFTYPE_P2P_CLIENT: + wlvif->p2p = 1; + /* fall-through */ + case NL80211_IFTYPE_STATION: + wlvif->bss_type = BSS_TYPE_STA_BSS; + break; + case NL80211_IFTYPE_ADHOC: + wlvif->bss_type = BSS_TYPE_IBSS; + break; + case NL80211_IFTYPE_P2P_GO: + wlvif->p2p = 1; + /* fall-through */ + case NL80211_IFTYPE_AP: + wlvif->bss_type = BSS_TYPE_AP_BSS; + break; + default: + wlvif->bss_type = MAX_BSS_TYPE; + return -EOPNOTSUPP; + } + + wlvif->role_id = WL12XX_INVALID_ROLE_ID; + wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID; + wlvif->dev_hlid = WL12XX_INVALID_LINK_ID; + + if (wlvif->bss_type == BSS_TYPE_STA_BSS || + wlvif->bss_type == BSS_TYPE_IBSS) { + /* init sta/ibss data */ + wlvif->sta.hlid = WL12XX_INVALID_LINK_ID; + wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx); + wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx); + wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx); + } else { + /* init ap data */ + wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID; + wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID; + wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx); + wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx); + for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++) + wl12xx_allocate_rate_policy(wl, + &wlvif->ap.ucast_rate_idx[i]); + } + + wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate; + wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5; + wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC; + wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC; + wlvif->rate_set = CONF_TX_RATE_MASK_BASIC; + wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT; + + /* + * mac80211 configures some values globally, while we treat them + * per-interface. thus, on init, we have to copy them from wl + */ + wlvif->band = wl->band; + wlvif->channel = wl->channel; + wlvif->power_level = wl->power_level; + + INIT_WORK(&wlvif->rx_streaming_enable_work, + wl1271_rx_streaming_enable_work); + INIT_WORK(&wlvif->rx_streaming_disable_work, + wl1271_rx_streaming_disable_work); + INIT_LIST_HEAD(&wlvif->list); + + setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer, + (unsigned long) wlvif); + return 0; +} + +static bool wl12xx_init_fw(struct wl1271 *wl) +{ + int retries = WL1271_BOOT_RETRIES; + bool booted = false; + struct wiphy *wiphy = wl->hw->wiphy; + int ret; + + while (retries) { + retries--; + ret = wl12xx_chip_wakeup(wl, false); + if (ret < 0) + goto power_off; + + ret = wl->ops->boot(wl); + if (ret < 0) + goto power_off; + + ret = wl1271_hw_init(wl); + if (ret < 0) + goto irq_disable; + + booted = true; + break; + +irq_disable: + mutex_unlock(&wl->mutex); + /* Unlocking the mutex in the middle of handling is + inherently unsafe. In this case we deem it safe to do, + because we need to let any possibly pending IRQ out of + the system (and while we are WL1271_STATE_OFF the IRQ + work function will not do anything.) Also, any other + possible concurrent operations will fail due to the + current state, hence the wl1271 struct should be safe. */ + wlcore_disable_interrupts(wl); + wl1271_flush_deferred_work(wl); + cancel_work_sync(&wl->netstack_work); + mutex_lock(&wl->mutex); +power_off: + wl1271_power_off(wl); + } + + if (!booted) { + wl1271_error("firmware boot failed despite %d retries", + WL1271_BOOT_RETRIES); + goto out; + } + + wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str); + + /* update hw/fw version info in wiphy struct */ + wiphy->hw_version = wl->chip.id; + strncpy(wiphy->fw_version, wl->chip.fw_ver_str, + sizeof(wiphy->fw_version)); + + /* + * Now we know if 11a is supported (info from the NVS), so disable + * 11a channels if not supported + */ + if (!wl->enable_11a) + wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0; + + wl1271_debug(DEBUG_MAC80211, "11a is %ssupported", + wl->enable_11a ? "" : "not "); + + wl->state = WL1271_STATE_ON; +out: + return booted; +} + +static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif) +{ + return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID; +} + +/* + * Check whether a fw switch (i.e. moving from one loaded + * fw to another) is needed. This function is also responsible + * for updating wl->last_vif_count, so it must be called before + * loading a non-plt fw (so the correct fw (single-role/multi-role) + * will be used). + */ +static bool wl12xx_need_fw_change(struct wl1271 *wl, + struct vif_counter_data vif_counter_data, + bool add) +{ + enum wl12xx_fw_type current_fw = wl->fw_type; + u8 vif_count = vif_counter_data.counter; + + if (test_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags)) + return false; + + /* increase the vif count if this is a new vif */ + if (add && !vif_counter_data.cur_vif_running) + vif_count++; + + wl->last_vif_count = vif_count; + + /* no need for fw change if the device is OFF */ + if (wl->state == WL1271_STATE_OFF) + return false; + + if (vif_count > 1 && current_fw == WL12XX_FW_TYPE_NORMAL) + return true; + if (vif_count <= 1 && current_fw == WL12XX_FW_TYPE_MULTI) + return true; + + return false; +} + +/* + * Enter "forced psm". Make sure the sta is in psm against the ap, + * to make the fw switch a bit more disconnection-persistent. + */ +static void wl12xx_force_active_psm(struct wl1271 *wl) +{ + struct wl12xx_vif *wlvif; + + wl12xx_for_each_wlvif_sta(wl, wlvif) { + wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE); + } +} + +static int wl1271_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + struct vif_counter_data vif_count; + int ret = 0; + u8 role_type; + bool booted = false; + + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | + IEEE80211_VIF_SUPPORTS_CQM_RSSI; + + wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", + ieee80211_vif_type_p2p(vif), vif->addr); + + wl12xx_get_vif_count(hw, vif, &vif_count); + + mutex_lock(&wl->mutex); + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out_unlock; + + /* + * in some very corner case HW recovery scenarios its possible to + * get here before __wl1271_op_remove_interface is complete, so + * opt out if that is the case. + */ + if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) || + test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) { + ret = -EBUSY; + goto out; + } + + + ret = wl12xx_init_vif_data(wl, vif); + if (ret < 0) + goto out; + + wlvif->wl = wl; + role_type = wl12xx_get_role_type(wl, wlvif); + if (role_type == WL12XX_INVALID_ROLE_TYPE) { + ret = -EINVAL; + goto out; + } + + if (wl12xx_need_fw_change(wl, vif_count, true)) { + wl12xx_force_active_psm(wl); + set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags); + mutex_unlock(&wl->mutex); + wl1271_recovery_work(&wl->recovery_work); + return 0; + } + + /* + * TODO: after the nvs issue will be solved, move this block + * to start(), and make sure here the driver is ON. + */ + if (wl->state == WL1271_STATE_OFF) { + /* + * we still need this in order to configure the fw + * while uploading the nvs + */ + memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN); + + booted = wl12xx_init_fw(wl); + if (!booted) { + ret = -EINVAL; + goto out; + } + } + + if (wlvif->bss_type == BSS_TYPE_STA_BSS || + wlvif->bss_type == BSS_TYPE_IBSS) { + /* + * The device role is a special role used for + * rx and tx frames prior to association (as + * the STA role can get packets only from + * its associated bssid) + */ + ret = wl12xx_cmd_role_enable(wl, vif->addr, + WL1271_ROLE_DEVICE, + &wlvif->dev_role_id); + if (ret < 0) + goto out; + } + + ret = wl12xx_cmd_role_enable(wl, vif->addr, + role_type, &wlvif->role_id); + if (ret < 0) + goto out; + + ret = wl1271_init_vif_specific(wl, vif); + if (ret < 0) + goto out; + + list_add(&wlvif->list, &wl->wlvif_list); + set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags); + + if (wlvif->bss_type == BSS_TYPE_AP_BSS) + wl->ap_count++; + else + wl->sta_count++; +out: + wl1271_ps_elp_sleep(wl); +out_unlock: + mutex_unlock(&wl->mutex); + + return ret; +} + +static void __wl1271_op_remove_interface(struct wl1271 *wl, + struct ieee80211_vif *vif, + bool reset_tx_queues) +{ + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + int i, ret; + + wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); + + if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) + return; + + /* because of hardware recovery, we may get here twice */ + if (wl->state != WL1271_STATE_ON) + return; + + wl1271_info("down"); + + if (wl->scan.state != WL1271_SCAN_STATE_IDLE && + wl->scan_vif == vif) { + /* + * Rearm the tx watchdog just before idling scan. This + * prevents just-finished scans from triggering the watchdog + */ + wl12xx_rearm_tx_watchdog_locked(wl); + + wl->scan.state = WL1271_SCAN_STATE_IDLE; + memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); + wl->scan_vif = NULL; + wl->scan.req = NULL; + ieee80211_scan_completed(wl->hw, true); + } + + if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) { + /* disable active roles */ + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto deinit; + + if (wlvif->bss_type == BSS_TYPE_STA_BSS || + wlvif->bss_type == BSS_TYPE_IBSS) { + if (wl12xx_dev_role_started(wlvif)) + wl12xx_stop_dev(wl, wlvif); + + ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id); + if (ret < 0) + goto deinit; + } + + ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id); + if (ret < 0) + goto deinit; + + wl1271_ps_elp_sleep(wl); + } +deinit: + /* clear all hlids (except system_hlid) */ + wlvif->dev_hlid = WL12XX_INVALID_LINK_ID; + + if (wlvif->bss_type == BSS_TYPE_STA_BSS || + wlvif->bss_type == BSS_TYPE_IBSS) { + wlvif->sta.hlid = WL12XX_INVALID_LINK_ID; + wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx); + wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx); + wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx); + } else { + wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID; + wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID; + wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx); + wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx); + for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++) + wl12xx_free_rate_policy(wl, + &wlvif->ap.ucast_rate_idx[i]); + wl1271_free_ap_keys(wl, wlvif); + } + + dev_kfree_skb(wlvif->probereq); + wlvif->probereq = NULL; + wl12xx_tx_reset_wlvif(wl, wlvif); + if (wl->last_wlvif == wlvif) + wl->last_wlvif = NULL; + list_del(&wlvif->list); + memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map)); + wlvif->role_id = WL12XX_INVALID_ROLE_ID; + wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID; + + if (wlvif->bss_type == BSS_TYPE_AP_BSS) + wl->ap_count--; + else + wl->sta_count--; + + mutex_unlock(&wl->mutex); + + del_timer_sync(&wlvif->rx_streaming_timer); + cancel_work_sync(&wlvif->rx_streaming_enable_work); + cancel_work_sync(&wlvif->rx_streaming_disable_work); + + mutex_lock(&wl->mutex); +} + +static void wl1271_op_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + struct wl12xx_vif *iter; + struct vif_counter_data vif_count; + bool cancel_recovery = true; + + wl12xx_get_vif_count(hw, vif, &vif_count); + mutex_lock(&wl->mutex); + + if (wl->state == WL1271_STATE_OFF || + !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) + goto out; + + /* + * wl->vif can be null here if someone shuts down the interface + * just when hardware recovery has been started. + */ + wl12xx_for_each_wlvif(wl, iter) { + if (iter != wlvif) + continue; + + __wl1271_op_remove_interface(wl, vif, true); + break; + } + WARN_ON(iter != wlvif); + if (wl12xx_need_fw_change(wl, vif_count, false)) { + wl12xx_force_active_psm(wl); + set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags); + wl12xx_queue_recovery_work(wl); + cancel_recovery = false; + } +out: + mutex_unlock(&wl->mutex); + if (cancel_recovery) + cancel_work_sync(&wl->recovery_work); +} + +static int wl12xx_op_change_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum nl80211_iftype new_type, bool p2p) +{ + struct wl1271 *wl = hw->priv; + int ret; + + set_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags); + wl1271_op_remove_interface(hw, vif); + + vif->type = new_type; + vif->p2p = p2p; + ret = wl1271_op_add_interface(hw, vif); + + clear_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags); + return ret; +} + +static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool set_assoc) +{ + int ret; + bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS); + + /* + * One of the side effects of the JOIN command is that is clears + * WPA/WPA2 keys from the chipset. Performing a JOIN while associated + * to a WPA/WPA2 access point will therefore kill the data-path. + * Currently the only valid scenario for JOIN during association + * is on roaming, in which case we will also be given new keys. + * Keep the below message for now, unless it starts bothering + * users who really like to roam a lot :) + */ + if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + wl1271_info("JOIN while associated."); + + /* clear encryption type */ + wlvif->encryption_type = KEY_NONE; + + if (set_assoc) + set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags); + + if (is_ibss) + ret = wl12xx_cmd_role_start_ibss(wl, wlvif); + else + ret = wl12xx_cmd_role_start_sta(wl, wlvif); + if (ret < 0) + goto out; + + if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + goto out; + + /* + * The join command disable the keep-alive mode, shut down its process, + * and also clear the template config, so we need to reset it all after + * the join. The acx_aid starts the keep-alive process, and the order + * of the commands below is relevant. + */ + ret = wl1271_acx_keep_alive_mode(wl, wlvif, true); + if (ret < 0) + goto out; + + ret = wl1271_acx_aid(wl, wlvif, wlvif->aid); + if (ret < 0) + goto out; + + ret = wl12xx_cmd_build_klv_null_data(wl, wlvif); + if (ret < 0) + goto out; + + ret = wl1271_acx_keep_alive_config(wl, wlvif, + CMD_TEMPL_KLV_IDX_NULL_DATA, + ACX_KEEP_ALIVE_TPL_VALID); + if (ret < 0) + goto out; + +out: + return ret; +} + +static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + int ret; + + if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) { + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); + + wl12xx_cmd_stop_channel_switch(wl); + ieee80211_chswitch_done(vif, false); + } + + /* to stop listening to a channel, we disconnect */ + ret = wl12xx_cmd_role_stop_sta(wl, wlvif); + if (ret < 0) + goto out; + + /* reset TX security counters on a clean disconnect */ + wlvif->tx_security_last_seq_lsb = 0; + wlvif->tx_security_seq = 0; + +out: + return ret; +} + +static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band]; + wlvif->rate_set = wlvif->basic_rate_set; +} + +static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif, + bool idle) +{ + int ret; + bool cur_idle = !test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags); + + if (idle == cur_idle) + return 0; + + if (idle) { + /* no need to croc if we weren't busy (e.g. during boot) */ + if (wl12xx_dev_role_started(wlvif)) { + ret = wl12xx_stop_dev(wl, wlvif); + if (ret < 0) + goto out; + } + wlvif->rate_set = + wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); + ret = wl1271_acx_sta_rate_policies(wl, wlvif); + if (ret < 0) + goto out; + ret = wl1271_acx_keep_alive_config( + wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA, + ACX_KEEP_ALIVE_TPL_INVALID); + if (ret < 0) + goto out; + clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags); + } else { + /* The current firmware only supports sched_scan in idle */ + if (wl->sched_scanning) { + wl1271_scan_sched_scan_stop(wl); + ieee80211_sched_scan_stopped(wl->hw); + } + + ret = wl12xx_start_dev(wl, wlvif); + if (ret < 0) + goto out; + set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags); + } + +out: + return ret; +} + +static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif, + struct ieee80211_conf *conf, u32 changed) +{ + bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); + int channel, ret; + + channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + + /* if the channel changes while joined, join again */ + if (changed & IEEE80211_CONF_CHANGE_CHANNEL && + ((wlvif->band != conf->channel->band) || + (wlvif->channel != channel))) { + /* send all pending packets */ + wl1271_tx_work_locked(wl); + wlvif->band = conf->channel->band; + wlvif->channel = channel; + + if (!is_ap) { + /* + * FIXME: the mac80211 should really provide a fixed + * rate to use here. for now, just use the smallest + * possible rate for the band as a fixed rate for + * association frames and other control messages. + */ + if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + wl1271_set_band_rate(wl, wlvif); + + wlvif->basic_rate = + wl1271_tx_min_rate_get(wl, + wlvif->basic_rate_set); + ret = wl1271_acx_sta_rate_policies(wl, wlvif); + if (ret < 0) + wl1271_warning("rate policy for channel " + "failed %d", ret); + + /* + * change the ROC channel. do it only if we are + * not idle. otherwise, CROC will be called + * anyway. + */ + if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, + &wlvif->flags) && + wl12xx_dev_role_started(wlvif) && + !(conf->flags & IEEE80211_CONF_IDLE)) { + ret = wl12xx_stop_dev(wl, wlvif); + if (ret < 0) + return ret; + + ret = wl12xx_start_dev(wl, wlvif); + if (ret < 0) + return ret; + } + } + } + + if ((changed & IEEE80211_CONF_CHANGE_PS) && !is_ap) { + + if ((conf->flags & IEEE80211_CONF_PS) && + test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) && + !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) { + + int ps_mode; + char *ps_mode_str; + + if (wl->conf.conn.forced_ps) { + ps_mode = STATION_POWER_SAVE_MODE; + ps_mode_str = "forced"; + } else { + ps_mode = STATION_AUTO_PS_MODE; + ps_mode_str = "auto"; + } + + wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str); + + ret = wl1271_ps_set_mode(wl, wlvif, ps_mode); + + if (ret < 0) + wl1271_warning("enter %s ps failed %d", + ps_mode_str, ret); + + } else if (!(conf->flags & IEEE80211_CONF_PS) && + test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) { + + wl1271_debug(DEBUG_PSM, "auto ps disabled"); + + ret = wl1271_ps_set_mode(wl, wlvif, + STATION_ACTIVE_MODE); + if (ret < 0) + wl1271_warning("exit auto ps failed %d", ret); + } + } + + if (conf->power_level != wlvif->power_level) { + ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level); + if (ret < 0) + return ret; + + wlvif->power_level = conf->power_level; + } + + return 0; +} + +static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) +{ + struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif; + struct ieee80211_conf *conf = &hw->conf; + int channel, ret = 0; + + channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + + wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s" + " changed 0x%x", + channel, + conf->flags & IEEE80211_CONF_PS ? "on" : "off", + conf->power_level, + conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use", + changed); + + /* + * mac80211 will go to idle nearly immediately after transmitting some + * frames, such as the deauth. To make sure those frames reach the air, + * wait here until the TX queue is fully flushed. + */ + if ((changed & IEEE80211_CONF_CHANGE_IDLE) && + (conf->flags & IEEE80211_CONF_IDLE)) + wl1271_tx_flush(wl); + + mutex_lock(&wl->mutex); + + /* we support configuring the channel and band even while off */ + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + wl->band = conf->channel->band; + wl->channel = channel; + } + + if (changed & IEEE80211_CONF_CHANGE_POWER) + wl->power_level = conf->power_level; + + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + /* configure each interface */ + wl12xx_for_each_wlvif(wl, wlvif) { + ret = wl12xx_config_vif(wl, wlvif, conf, changed); + if (ret < 0) + goto out_sleep; + } + +out_sleep: + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +struct wl1271_filter_params { + bool enabled; + int mc_list_length; + u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN]; +}; + +static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, + struct netdev_hw_addr_list *mc_list) +{ + struct wl1271_filter_params *fp; + struct netdev_hw_addr *ha; + struct wl1271 *wl = hw->priv; + + if (unlikely(wl->state == WL1271_STATE_OFF)) + return 0; + + fp = kzalloc(sizeof(*fp), GFP_ATOMIC); + if (!fp) { + wl1271_error("Out of memory setting filters."); + return 0; + } + + /* update multicast filtering parameters */ + fp->mc_list_length = 0; + if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) { + fp->enabled = false; + } else { + fp->enabled = true; + netdev_hw_addr_list_for_each(ha, mc_list) { + memcpy(fp->mc_list[fp->mc_list_length], + ha->addr, ETH_ALEN); + fp->mc_list_length++; + } + } + + return (u64)(unsigned long)fp; +} + +#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ + FIF_ALLMULTI | \ + FIF_FCSFAIL | \ + FIF_BCN_PRBRESP_PROMISC | \ + FIF_CONTROL | \ + FIF_OTHER_BSS) + +static void wl1271_op_configure_filter(struct ieee80211_hw *hw, + unsigned int changed, + unsigned int *total, u64 multicast) +{ + struct wl1271_filter_params *fp = (void *)(unsigned long)multicast; + struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif; + + int ret; + + wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x" + " total %x", changed, *total); + + mutex_lock(&wl->mutex); + + *total &= WL1271_SUPPORTED_FILTERS; + changed &= WL1271_SUPPORTED_FILTERS; + + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + wl12xx_for_each_wlvif(wl, wlvif) { + if (wlvif->bss_type != BSS_TYPE_AP_BSS) { + if (*total & FIF_ALLMULTI) + ret = wl1271_acx_group_address_tbl(wl, wlvif, + false, + NULL, 0); + else if (fp) + ret = wl1271_acx_group_address_tbl(wl, wlvif, + fp->enabled, + fp->mc_list, + fp->mc_list_length); + if (ret < 0) + goto out_sleep; + } + } + + /* + * the fw doesn't provide an api to configure the filters. instead, + * the filters configuration is based on the active roles / ROC + * state. + */ + +out_sleep: + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + kfree(fp); +} + +static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 id, u8 key_type, u8 key_size, + const u8 *key, u8 hlid, u32 tx_seq_32, + u16 tx_seq_16) +{ + struct wl1271_ap_key *ap_key; + int i; + + wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id); + + if (key_size > MAX_KEY_SIZE) + return -EINVAL; + + /* + * Find next free entry in ap_keys. Also check we are not replacing + * an existing key. + */ + for (i = 0; i < MAX_NUM_KEYS; i++) { + if (wlvif->ap.recorded_keys[i] == NULL) + break; + + if (wlvif->ap.recorded_keys[i]->id == id) { + wl1271_warning("trying to record key replacement"); + return -EINVAL; + } + } + + if (i == MAX_NUM_KEYS) + return -EBUSY; + + ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL); + if (!ap_key) + return -ENOMEM; + + ap_key->id = id; + ap_key->key_type = key_type; + ap_key->key_size = key_size; + memcpy(ap_key->key, key, key_size); + ap_key->hlid = hlid; + ap_key->tx_seq_32 = tx_seq_32; + ap_key->tx_seq_16 = tx_seq_16; + + wlvif->ap.recorded_keys[i] = ap_key; + return 0; +} + +static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + int i; + + for (i = 0; i < MAX_NUM_KEYS; i++) { + kfree(wlvif->ap.recorded_keys[i]); + wlvif->ap.recorded_keys[i] = NULL; + } +} + +static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + int i, ret = 0; + struct wl1271_ap_key *key; + bool wep_key_added = false; + + for (i = 0; i < MAX_NUM_KEYS; i++) { + u8 hlid; + if (wlvif->ap.recorded_keys[i] == NULL) + break; + + key = wlvif->ap.recorded_keys[i]; + hlid = key->hlid; + if (hlid == WL12XX_INVALID_LINK_ID) + hlid = wlvif->ap.bcast_hlid; + + ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE, + key->id, key->key_type, + key->key_size, key->key, + hlid, key->tx_seq_32, + key->tx_seq_16); + if (ret < 0) + goto out; + + if (key->key_type == KEY_WEP) + wep_key_added = true; + } + + if (wep_key_added) { + ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key, + wlvif->ap.bcast_hlid); + if (ret < 0) + goto out; + } + +out: + wl1271_free_ap_keys(wl, wlvif); + return ret; +} + +static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u16 action, u8 id, u8 key_type, + u8 key_size, const u8 *key, u32 tx_seq_32, + u16 tx_seq_16, struct ieee80211_sta *sta) +{ + int ret; + bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); + + /* + * A role set to GEM cipher requires different Tx settings (namely + * spare blocks). Note when we are in this mode so the HW can adjust. + */ + if (key_type == KEY_GEM) { + if (action == KEY_ADD_OR_REPLACE) + wlvif->is_gem = true; + else if (action == KEY_REMOVE) + wlvif->is_gem = false; + } + + if (is_ap) { + struct wl1271_station *wl_sta; + u8 hlid; + + if (sta) { + wl_sta = (struct wl1271_station *)sta->drv_priv; + hlid = wl_sta->hlid; + } else { + hlid = wlvif->ap.bcast_hlid; + } + + if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) { + /* + * We do not support removing keys after AP shutdown. + * Pretend we do to make mac80211 happy. + */ + if (action != KEY_ADD_OR_REPLACE) + return 0; + + ret = wl1271_record_ap_key(wl, wlvif, id, + key_type, key_size, + key, hlid, tx_seq_32, + tx_seq_16); + } else { + ret = wl1271_cmd_set_ap_key(wl, wlvif, action, + id, key_type, key_size, + key, hlid, tx_seq_32, + tx_seq_16); + } + + if (ret < 0) + return ret; + } else { + const u8 *addr; + static const u8 bcast_addr[ETH_ALEN] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + + addr = sta ? sta->addr : bcast_addr; + + if (is_zero_ether_addr(addr)) { + /* We dont support TX only encryption */ + return -EOPNOTSUPP; + } + + /* The wl1271 does not allow to remove unicast keys - they + will be cleared automatically on next CMD_JOIN. Ignore the + request silently, as we dont want the mac80211 to emit + an error message. */ + if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr)) + return 0; + + /* don't remove key if hlid was already deleted */ + if (action == KEY_REMOVE && + wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) + return 0; + + ret = wl1271_cmd_set_sta_key(wl, wlvif, action, + id, key_type, key_size, + key, addr, tx_seq_32, + tx_seq_16); + if (ret < 0) + return ret; + + /* the default WEP key needs to be configured at least once */ + if (key_type == KEY_WEP) { + ret = wl12xx_cmd_set_default_wep_key(wl, + wlvif->default_key, + wlvif->sta.hlid); + if (ret < 0) + return ret; + } + } + + return 0; +} + +static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key_conf) +{ + struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + int ret; + u32 tx_seq_32 = 0; + u16 tx_seq_16 = 0; + u8 key_type; + + wl1271_debug(DEBUG_MAC80211, "mac80211 set key"); + + wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta); + wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", + key_conf->cipher, key_conf->keyidx, + key_conf->keylen, key_conf->flags); + wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen); + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) { + ret = -EAGAIN; + goto out_unlock; + } + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out_unlock; + + switch (key_conf->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + key_type = KEY_WEP; + + key_conf->hw_key_idx = key_conf->keyidx; + break; + case WLAN_CIPHER_SUITE_TKIP: + key_type = KEY_TKIP; + + key_conf->hw_key_idx = key_conf->keyidx; + tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq); + tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq); + break; + case WLAN_CIPHER_SUITE_CCMP: + key_type = KEY_AES; + + key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; + tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq); + tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq); + break; + case WL1271_CIPHER_SUITE_GEM: + key_type = KEY_GEM; + tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq); + tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq); + break; + default: + wl1271_error("Unknown key algo 0x%x", key_conf->cipher); + + ret = -EOPNOTSUPP; + goto out_sleep; + } + + switch (cmd) { + case SET_KEY: + ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE, + key_conf->keyidx, key_type, + key_conf->keylen, key_conf->key, + tx_seq_32, tx_seq_16, sta); + if (ret < 0) { + wl1271_error("Could not add or replace key"); + goto out_sleep; + } + + /* + * reconfiguring arp response if the unicast (or common) + * encryption key type was changed + */ + if (wlvif->bss_type == BSS_TYPE_STA_BSS && + (sta || key_type == KEY_WEP) && + wlvif->encryption_type != key_type) { + wlvif->encryption_type = key_type; + ret = wl1271_cmd_build_arp_rsp(wl, wlvif); + if (ret < 0) { + wl1271_warning("build arp rsp failed: %d", ret); + goto out_sleep; + } + } + break; + + case DISABLE_KEY: + ret = wl1271_set_key(wl, wlvif, KEY_REMOVE, + key_conf->keyidx, key_type, + key_conf->keylen, key_conf->key, + 0, 0, sta); + if (ret < 0) { + wl1271_error("Could not remove key"); + goto out_sleep; + } + break; + + default: + wl1271_error("Unsupported key cmd 0x%x", cmd); + ret = -EOPNOTSUPP; + break; + } + +out_sleep: + wl1271_ps_elp_sleep(wl); + +out_unlock: + mutex_unlock(&wl->mutex); + + return ret; +} + +static int wl1271_op_hw_scan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_scan_request *req) +{ + struct wl1271 *wl = hw->priv; + int ret; + u8 *ssid = NULL; + size_t len = 0; + + wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan"); + + if (req->n_ssids) { + ssid = req->ssids[0].ssid; + len = req->ssids[0].ssid_len; + } + + mutex_lock(&wl->mutex); + + if (wl->state == WL1271_STATE_OFF) { + /* + * We cannot return -EBUSY here because cfg80211 will expect + * a call to ieee80211_scan_completed if we do - in this case + * there won't be any call. + */ + ret = -EAGAIN; + goto out; + } + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + /* fail if there is any role in ROC */ + if (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES) { + /* don't allow scanning right now */ + ret = -EBUSY; + goto out_sleep; + } + + ret = wl1271_scan(hw->priv, vif, ssid, len, req); +out_sleep: + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct wl1271 *wl = hw->priv; + int ret; + + wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan"); + + mutex_lock(&wl->mutex); + + if (wl->state == WL1271_STATE_OFF) + goto out; + + if (wl->scan.state == WL1271_SCAN_STATE_IDLE) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + if (wl->scan.state != WL1271_SCAN_STATE_DONE) { + ret = wl1271_scan_stop(wl); + if (ret < 0) + goto out_sleep; + } + + /* + * Rearm the tx watchdog just before idling scan. This + * prevents just-finished scans from triggering the watchdog + */ + wl12xx_rearm_tx_watchdog_locked(wl); + + wl->scan.state = WL1271_SCAN_STATE_IDLE; + memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); + wl->scan_vif = NULL; + wl->scan.req = NULL; + ieee80211_scan_completed(wl->hw, true); + +out_sleep: + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); + + cancel_delayed_work_sync(&wl->scan_complete_work); +} + +static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_sched_scan_request *req, + struct ieee80211_sched_scan_ies *ies) +{ + struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + int ret; + + wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start"); + + mutex_lock(&wl->mutex); + + if (wl->state == WL1271_STATE_OFF) { + ret = -EAGAIN; + goto out; + } + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies); + if (ret < 0) + goto out_sleep; + + ret = wl1271_scan_sched_scan_start(wl, wlvif); + if (ret < 0) + goto out_sleep; + + wl->sched_scanning = true; + +out_sleep: + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); + return ret; +} + +static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct wl1271 *wl = hw->priv; + int ret; + + wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop"); + + mutex_lock(&wl->mutex); + + if (wl->state == WL1271_STATE_OFF) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + wl1271_scan_sched_scan_stop(wl); + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); +} + +static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) +{ + struct wl1271 *wl = hw->priv; + int ret = 0; + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) { + ret = -EAGAIN; + goto out; + } + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl1271_acx_frag_threshold(wl, value); + if (ret < 0) + wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret); + + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +{ + struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif; + int ret = 0; + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) { + ret = -EAGAIN; + goto out; + } + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + wl12xx_for_each_wlvif(wl, wlvif) { + ret = wl1271_acx_rts_threshold(wl, wlvif, value); + if (ret < 0) + wl1271_warning("set rts threshold failed: %d", ret); + } + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb, + int offset) +{ + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + u8 ssid_len; + const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset, + skb->len - offset); + + if (!ptr) { + wl1271_error("No SSID in IEs!"); + return -ENOENT; + } + + ssid_len = ptr[1]; + if (ssid_len > IEEE80211_MAX_SSID_LEN) { + wl1271_error("SSID is too long!"); + return -EINVAL; + } + + wlvif->ssid_len = ssid_len; + memcpy(wlvif->ssid, ptr+2, ssid_len); + return 0; +} + +static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset) +{ + int len; + const u8 *next, *end = skb->data + skb->len; + u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset, + skb->len - ieoffset); + if (!ie) + return; + len = ie[1] + 2; + next = ie + len; + memmove(ie, next, end - next); + skb_trim(skb, skb->len - len); +} + +static void wl12xx_remove_vendor_ie(struct sk_buff *skb, + unsigned int oui, u8 oui_type, + int ieoffset) +{ + int len; + const u8 *next, *end = skb->data + skb->len; + u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type, + skb->data + ieoffset, + skb->len - ieoffset); + if (!ie) + return; + len = ie[1] + 2; + next = ie + len; + memmove(ie, next, end - next); + skb_trim(skb, skb->len - len); +} + +static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates, + struct ieee80211_vif *vif) +{ + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + struct sk_buff *skb; + int ret; + + skb = ieee80211_proberesp_get(wl->hw, vif); + if (!skb) + return -EOPNOTSUPP; + + ret = wl1271_cmd_template_set(wl, wlvif->role_id, + CMD_TEMPL_AP_PROBE_RESPONSE, + skb->data, + skb->len, 0, + rates); + + dev_kfree_skb(skb); + return ret; +} + +static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl, + struct ieee80211_vif *vif, + u8 *probe_rsp_data, + size_t probe_rsp_len, + u32 rates) +{ + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE]; + int ssid_ie_offset, ie_offset, templ_len; + const u8 *ptr; + + /* no need to change probe response if the SSID is set correctly */ + if (wlvif->ssid_len > 0) + return wl1271_cmd_template_set(wl, wlvif->role_id, + CMD_TEMPL_AP_PROBE_RESPONSE, + probe_rsp_data, + probe_rsp_len, 0, + rates); + + if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) { + wl1271_error("probe_rsp template too big"); + return -EINVAL; + } + + /* start searching from IE offset */ + ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); + + ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset, + probe_rsp_len - ie_offset); + if (!ptr) { + wl1271_error("No SSID in beacon!"); + return -EINVAL; + } + + ssid_ie_offset = ptr - probe_rsp_data; + ptr += (ptr[1] + 2); + + memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset); + + /* insert SSID from bss_conf */ + probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID; + probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len; + memcpy(probe_rsp_templ + ssid_ie_offset + 2, + bss_conf->ssid, bss_conf->ssid_len); + templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len; + + memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len, + ptr, probe_rsp_len - (ptr - probe_rsp_data)); + templ_len += probe_rsp_len - (ptr - probe_rsp_data); + + return wl1271_cmd_template_set(wl, wlvif->role_id, + CMD_TEMPL_AP_PROBE_RESPONSE, + probe_rsp_templ, + templ_len, 0, + rates); +} + +static int wl1271_bss_erp_info_changed(struct wl1271 *wl, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changed) +{ + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + int ret = 0; + + if (changed & BSS_CHANGED_ERP_SLOT) { + if (bss_conf->use_short_slot) + ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT); + else + ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG); + if (ret < 0) { + wl1271_warning("Set slot time failed %d", ret); + goto out; + } + } + + if (changed & BSS_CHANGED_ERP_PREAMBLE) { + if (bss_conf->use_short_preamble) + wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT); + else + wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG); + } + + if (changed & BSS_CHANGED_ERP_CTS_PROT) { + if (bss_conf->use_cts_prot) + ret = wl1271_acx_cts_protect(wl, wlvif, + CTSPROTECT_ENABLE); + else + ret = wl1271_acx_cts_protect(wl, wlvif, + CTSPROTECT_DISABLE); + if (ret < 0) { + wl1271_warning("Set ctsprotect failed %d", ret); + goto out; + } + } + +out: + return ret; +} + +static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changed) +{ + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); + int ret = 0; + + if ((changed & BSS_CHANGED_BEACON_INT)) { + wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d", + bss_conf->beacon_int); + + wlvif->beacon_int = bss_conf->beacon_int; + } + + if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) { + u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); + if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) { + wl1271_debug(DEBUG_AP, "probe response updated"); + set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags); + } + } + + if ((changed & BSS_CHANGED_BEACON)) { + struct ieee80211_hdr *hdr; + u32 min_rate; + int ieoffset = offsetof(struct ieee80211_mgmt, + u.beacon.variable); + struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif); + u16 tmpl_id; + + if (!beacon) { + ret = -EINVAL; + goto out; + } + + wl1271_debug(DEBUG_MASTER, "beacon updated"); + + ret = wl1271_ssid_set(vif, beacon, ieoffset); + if (ret < 0) { + dev_kfree_skb(beacon); + goto out; + } + min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); + tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON : + CMD_TEMPL_BEACON; + ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id, + beacon->data, + beacon->len, 0, + min_rate); + if (ret < 0) { + dev_kfree_skb(beacon); + goto out; + } + + /* + * In case we already have a probe-resp beacon set explicitly + * by usermode, don't use the beacon data. + */ + if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags)) + goto end_bcn; + + /* remove TIM ie from probe response */ + wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset); + + /* + * remove p2p ie from probe response. + * the fw reponds to probe requests that don't include + * the p2p ie. probe requests with p2p ie will be passed, + * and will be responded by the supplicant (the spec + * forbids including the p2p ie when responding to probe + * requests that didn't include it). + */ + wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA, + WLAN_OUI_TYPE_WFA_P2P, ieoffset); + + hdr = (struct ieee80211_hdr *) beacon->data; + hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_PROBE_RESP); + if (is_ap) + ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif, + beacon->data, + beacon->len, + min_rate); + else + ret = wl1271_cmd_template_set(wl, wlvif->role_id, + CMD_TEMPL_PROBE_RESPONSE, + beacon->data, + beacon->len, 0, + min_rate); +end_bcn: + dev_kfree_skb(beacon); + if (ret < 0) + goto out; + } + +out: + if (ret != 0) + wl1271_error("beacon info change failed: %d", ret); + return ret; +} + +/* AP mode changes */ +static void wl1271_bss_info_changed_ap(struct wl1271 *wl, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changed) +{ + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + int ret = 0; + + if ((changed & BSS_CHANGED_BASIC_RATES)) { + u32 rates = bss_conf->basic_rates; + + wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates, + wlvif->band); + wlvif->basic_rate = wl1271_tx_min_rate_get(wl, + wlvif->basic_rate_set); + + ret = wl1271_init_ap_rates(wl, wlvif); + if (ret < 0) { + wl1271_error("AP rate policy change failed %d", ret); + goto out; + } + + ret = wl1271_ap_init_templates(wl, vif); + if (ret < 0) + goto out; + } + + ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed); + if (ret < 0) + goto out; + + if ((changed & BSS_CHANGED_BEACON_ENABLED)) { + if (bss_conf->enable_beacon) { + if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) { + ret = wl12xx_cmd_role_start_ap(wl, wlvif); + if (ret < 0) + goto out; + + ret = wl1271_ap_init_hwenc(wl, wlvif); + if (ret < 0) + goto out; + + set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags); + wl1271_debug(DEBUG_AP, "started AP"); + } + } else { + if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) { + ret = wl12xx_cmd_role_stop_ap(wl, wlvif); + if (ret < 0) + goto out; + + clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags); + clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, + &wlvif->flags); + wl1271_debug(DEBUG_AP, "stopped AP"); + } + } + } + + ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed); + if (ret < 0) + goto out; + + /* Handle HT information change */ + if ((changed & BSS_CHANGED_HT) && + (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { + ret = wl1271_acx_set_ht_information(wl, wlvif, + bss_conf->ht_operation_mode); + if (ret < 0) { + wl1271_warning("Set ht information failed %d", ret); + goto out; + } + } + +out: + return; +} + +/* STA/IBSS mode changes */ +static void wl1271_bss_info_changed_sta(struct wl1271 *wl, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changed) +{ + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + bool do_join = false, set_assoc = false; + bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS); + bool ibss_joined = false; + u32 sta_rate_set = 0; + int ret; + struct ieee80211_sta *sta; + bool sta_exists = false; + struct ieee80211_sta_ht_cap sta_ht_cap; + + if (is_ibss) { + ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, + changed); + if (ret < 0) + goto out; + } + + if (changed & BSS_CHANGED_IBSS) { + if (bss_conf->ibss_joined) { + set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags); + ibss_joined = true; + } else { + if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED, + &wlvif->flags)) + wl1271_unjoin(wl, wlvif); + } + } + + if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined) + do_join = true; + + /* Need to update the SSID (for filtering etc) */ + if ((changed & BSS_CHANGED_BEACON) && ibss_joined) + do_join = true; + + if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) { + wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s", + bss_conf->enable_beacon ? "enabled" : "disabled"); + + do_join = true; + } + + if (changed & BSS_CHANGED_IDLE && !is_ibss) { + ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle); + if (ret < 0) + wl1271_warning("idle mode change failed %d", ret); + } + + if ((changed & BSS_CHANGED_CQM)) { + bool enable = false; + if (bss_conf->cqm_rssi_thold) + enable = true; + ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable, + bss_conf->cqm_rssi_thold, + bss_conf->cqm_rssi_hyst); + if (ret < 0) + goto out; + wlvif->rssi_thold = bss_conf->cqm_rssi_thold; + } + + if (changed & BSS_CHANGED_BSSID) + if (!is_zero_ether_addr(bss_conf->bssid)) { + ret = wl12xx_cmd_build_null_data(wl, wlvif); + if (ret < 0) + goto out; + + ret = wl1271_build_qos_null_data(wl, vif); + if (ret < 0) + goto out; + } + + if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) { + rcu_read_lock(); + sta = ieee80211_find_sta(vif, bss_conf->bssid); + if (!sta) + goto sta_not_found; + + /* save the supp_rates of the ap */ + sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band]; + if (sta->ht_cap.ht_supported) + sta_rate_set |= + (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET); + sta_ht_cap = sta->ht_cap; + sta_exists = true; + +sta_not_found: + rcu_read_unlock(); + } + + if ((changed & BSS_CHANGED_ASSOC)) { + if (bss_conf->assoc) { + u32 rates; + int ieoffset; + wlvif->aid = bss_conf->aid; + wlvif->beacon_int = bss_conf->beacon_int; + do_join = true; + set_assoc = true; + + /* + * use basic rates from AP, and determine lowest rate + * to use with control frames. + */ + rates = bss_conf->basic_rates; + wlvif->basic_rate_set = + wl1271_tx_enabled_rates_get(wl, rates, + wlvif->band); + wlvif->basic_rate = + wl1271_tx_min_rate_get(wl, + wlvif->basic_rate_set); + if (sta_rate_set) + wlvif->rate_set = + wl1271_tx_enabled_rates_get(wl, + sta_rate_set, + wlvif->band); + ret = wl1271_acx_sta_rate_policies(wl, wlvif); + if (ret < 0) + goto out; + + /* + * with wl1271, we don't need to update the + * beacon_int and dtim_period, because the firmware + * updates it by itself when the first beacon is + * received after a join. + */ + ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid); + if (ret < 0) + goto out; + + /* + * Get a template for hardware connection maintenance + */ + dev_kfree_skb(wlvif->probereq); + wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl, + wlvif, + NULL); + ieoffset = offsetof(struct ieee80211_mgmt, + u.probe_req.variable); + wl1271_ssid_set(vif, wlvif->probereq, ieoffset); + + /* enable the connection monitoring feature */ + ret = wl1271_acx_conn_monit_params(wl, wlvif, true); + if (ret < 0) + goto out; + } else { + /* use defaults when not associated */ + bool was_assoc = + !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED, + &wlvif->flags); + bool was_ifup = + !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT, + &wlvif->flags); + wlvif->aid = 0; + + /* free probe-request template */ + dev_kfree_skb(wlvif->probereq); + wlvif->probereq = NULL; + + /* revert back to minimum rates for the current band */ + wl1271_set_band_rate(wl, wlvif); + wlvif->basic_rate = + wl1271_tx_min_rate_get(wl, + wlvif->basic_rate_set); + ret = wl1271_acx_sta_rate_policies(wl, wlvif); + if (ret < 0) + goto out; + + /* disable connection monitor features */ + ret = wl1271_acx_conn_monit_params(wl, wlvif, false); + + /* Disable the keep-alive feature */ + ret = wl1271_acx_keep_alive_mode(wl, wlvif, false); + if (ret < 0) + goto out; + + /* restore the bssid filter and go to dummy bssid */ + if (was_assoc) { + /* + * we might have to disable roc, if there was + * no IF_OPER_UP notification. + */ + if (!was_ifup) { + ret = wl12xx_croc(wl, wlvif->role_id); + if (ret < 0) + goto out; + } + /* + * (we also need to disable roc in case of + * roaming on the same channel. until we will + * have a better flow...) + */ + if (test_bit(wlvif->dev_role_id, wl->roc_map)) { + ret = wl12xx_croc(wl, + wlvif->dev_role_id); + if (ret < 0) + goto out; + } + + wl1271_unjoin(wl, wlvif); + if (!bss_conf->idle) + wl12xx_start_dev(wl, wlvif); + } + } + } + + if (changed & BSS_CHANGED_IBSS) { + wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d", + bss_conf->ibss_joined); + + if (bss_conf->ibss_joined) { + u32 rates = bss_conf->basic_rates; + wlvif->basic_rate_set = + wl1271_tx_enabled_rates_get(wl, rates, + wlvif->band); + wlvif->basic_rate = + wl1271_tx_min_rate_get(wl, + wlvif->basic_rate_set); + + /* by default, use 11b + OFDM rates */ + wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES; + ret = wl1271_acx_sta_rate_policies(wl, wlvif); + if (ret < 0) + goto out; + } + } + + ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed); + if (ret < 0) + goto out; + + if (do_join) { + ret = wl1271_join(wl, wlvif, set_assoc); + if (ret < 0) { + wl1271_warning("cmd join failed %d", ret); + goto out; + } + + /* ROC until connected (after EAPOL exchange) */ + if (!is_ibss) { + ret = wl12xx_roc(wl, wlvif, wlvif->role_id); + if (ret < 0) + goto out; + + if (test_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags)) + wl12xx_set_authorized(wl, wlvif); + } + /* + * stop device role if started (we might already be in + * STA/IBSS role). + */ + if (wl12xx_dev_role_started(wlvif)) { + ret = wl12xx_stop_dev(wl, wlvif); + if (ret < 0) + goto out; + } + } + + /* Handle new association with HT. Do this after join. */ + if (sta_exists) { + if ((changed & BSS_CHANGED_HT) && + (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { + ret = wl1271_acx_set_ht_capabilities(wl, + &sta_ht_cap, + true, + wlvif->sta.hlid); + if (ret < 0) { + wl1271_warning("Set ht cap true failed %d", + ret); + goto out; + } + } + /* handle new association without HT and disassociation */ + else if (changed & BSS_CHANGED_ASSOC) { + ret = wl1271_acx_set_ht_capabilities(wl, + &sta_ht_cap, + false, + wlvif->sta.hlid); + if (ret < 0) { + wl1271_warning("Set ht cap false failed %d", + ret); + goto out; + } + } + } + + /* Handle HT information change. Done after join. */ + if ((changed & BSS_CHANGED_HT) && + (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { + ret = wl1271_acx_set_ht_information(wl, wlvif, + bss_conf->ht_operation_mode); + if (ret < 0) { + wl1271_warning("Set ht information failed %d", ret); + goto out; + } + } + + /* Handle arp filtering. Done after join. */ + if ((changed & BSS_CHANGED_ARP_FILTER) || + (!is_ibss && (changed & BSS_CHANGED_QOS))) { + __be32 addr = bss_conf->arp_addr_list[0]; + wlvif->sta.qos = bss_conf->qos; + WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS); + + if (bss_conf->arp_addr_cnt == 1 && + bss_conf->arp_filter_enabled) { + wlvif->ip_addr = addr; + /* + * The template should have been configured only upon + * association. however, it seems that the correct ip + * isn't being set (when sending), so we have to + * reconfigure the template upon every ip change. + */ + ret = wl1271_cmd_build_arp_rsp(wl, wlvif); + if (ret < 0) { + wl1271_warning("build arp rsp failed: %d", ret); + goto out; + } + + ret = wl1271_acx_arp_ip_filter(wl, wlvif, + (ACX_ARP_FILTER_ARP_FILTERING | + ACX_ARP_FILTER_AUTO_ARP), + addr); + } else { + wlvif->ip_addr = 0; + ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr); + } + + if (ret < 0) + goto out; + } + +out: + return; +} + +static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changed) +{ + struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); + int ret; + + wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x", + (int)changed); + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + + if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + if (is_ap) + wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed); + else + wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed); + + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + +static int wl1271_op_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + u8 ps_scheme; + int ret = 0; + + mutex_lock(&wl->mutex); + + wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue); + + if (params->uapsd) + ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER; + else + ps_scheme = CONF_PS_SCHEME_LEGACY; + + if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + /* + * the txop is confed in units of 32us by the mac80211, + * we need us + */ + ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue), + params->cw_min, params->cw_max, + params->aifs, params->txop << 5); + if (ret < 0) + goto out_sleep; + + ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue), + CONF_CHANNEL_TYPE_EDCF, + wl1271_tx_get_queue(queue), + ps_scheme, CONF_ACK_POLICY_LEGACY, + 0, 0); + +out_sleep: + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + + struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + u64 mactime = ULLONG_MAX; + int ret; + + wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf"); + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl12xx_acx_tsf_info(wl, wlvif, &mactime); + if (ret < 0) + goto out_sleep; + +out_sleep: + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + return mactime; +} + +static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx, + struct survey_info *survey) +{ + struct wl1271 *wl = hw->priv; + struct ieee80211_conf *conf = &hw->conf; + + if (idx != 0) + return -ENOENT; + + survey->channel = conf->channel; + survey->filled = SURVEY_INFO_NOISE_DBM; + survey->noise = wl->noise; + + return 0; +} + +static int wl1271_allocate_sta(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + struct ieee80211_sta *sta) +{ + struct wl1271_station *wl_sta; + int ret; + + + if (wl->active_sta_count >= AP_MAX_STATIONS) { + wl1271_warning("could not allocate HLID - too much stations"); + return -EBUSY; + } + + wl_sta = (struct wl1271_station *)sta->drv_priv; + ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid); + if (ret < 0) { + wl1271_warning("could not allocate HLID - too many links"); + return -EBUSY; + } + + set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map); + memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN); + wl->active_sta_count++; + return 0; +} + +void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid) +{ + if (!test_bit(hlid, wlvif->ap.sta_hlid_map)) + return; + + clear_bit(hlid, wlvif->ap.sta_hlid_map); + memset(wl->links[hlid].addr, 0, ETH_ALEN); + wl->links[hlid].ba_bitmap = 0; + __clear_bit(hlid, &wl->ap_ps_map); + __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); + wl12xx_free_link(wl, wlvif, &hlid); + wl->active_sta_count--; + + /* + * rearm the tx watchdog when the last STA is freed - give the FW a + * chance to return STA-buffered packets before complaining. + */ + if (wl->active_sta_count == 0) + wl12xx_rearm_tx_watchdog_locked(wl); +} + +static int wl12xx_sta_add(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + struct ieee80211_sta *sta) +{ + struct wl1271_station *wl_sta; + int ret = 0; + u8 hlid; + + wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid); + + ret = wl1271_allocate_sta(wl, wlvif, sta); + if (ret < 0) + return ret; + + wl_sta = (struct wl1271_station *)sta->drv_priv; + hlid = wl_sta->hlid; + + ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid); + if (ret < 0) + wl1271_free_sta(wl, wlvif, hlid); + + return ret; +} + +static int wl12xx_sta_remove(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + struct ieee80211_sta *sta) +{ + struct wl1271_station *wl_sta; + int ret = 0, id; + + wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid); + + wl_sta = (struct wl1271_station *)sta->drv_priv; + id = wl_sta->hlid; + if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map))) + return -EINVAL; + + ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid); + if (ret < 0) + return ret; + + wl1271_free_sta(wl, wlvif, wl_sta->hlid); + return ret; +} + +static int wl12xx_update_sta_state(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + struct ieee80211_sta *sta, + enum ieee80211_sta_state old_state, + enum ieee80211_sta_state new_state) +{ + struct wl1271_station *wl_sta; + u8 hlid; + bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS; + bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS; + int ret; + + wl_sta = (struct wl1271_station *)sta->drv_priv; + hlid = wl_sta->hlid; + + /* Add station (AP mode) */ + if (is_ap && + old_state == IEEE80211_STA_NOTEXIST && + new_state == IEEE80211_STA_NONE) + return wl12xx_sta_add(wl, wlvif, sta); + + /* Remove station (AP mode) */ + if (is_ap && + old_state == IEEE80211_STA_NONE && + new_state == IEEE80211_STA_NOTEXIST) { + /* must not fail */ + wl12xx_sta_remove(wl, wlvif, sta); + return 0; + } + + /* Authorize station (AP mode) */ + if (is_ap && + new_state == IEEE80211_STA_AUTHORIZED) { + ret = wl12xx_cmd_set_peer_state(wl, hlid); + if (ret < 0) + return ret; + + ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, + hlid); + return ret; + } + + /* Authorize station */ + if (is_sta && + new_state == IEEE80211_STA_AUTHORIZED) { + set_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags); + return wl12xx_set_authorized(wl, wlvif); + } + + if (is_sta && + old_state == IEEE80211_STA_AUTHORIZED && + new_state == IEEE80211_STA_ASSOC) { + clear_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags); + return 0; + } + + return 0; +} + +static int wl12xx_op_sta_state(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + enum ieee80211_sta_state old_state, + enum ieee80211_sta_state new_state) +{ + struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + int ret; + + wl1271_debug(DEBUG_MAC80211, "mac80211 sta %d state=%d->%d", + sta->aid, old_state, new_state); + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) { + ret = -EBUSY; + goto out; + } + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl12xx_update_sta_state(wl, wlvif, sta, old_state, new_state); + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); + if (new_state < old_state) + return 0; + return ret; +} + +static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, u16 tid, u16 *ssn, + u8 buf_size) +{ + struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + int ret; + u8 hlid, *ba_bitmap; + + wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action, + tid); + + /* sanity check - the fields in FW are only 8bits wide */ + if (WARN_ON(tid > 0xFF)) + return -ENOTSUPP; + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) { + ret = -EAGAIN; + goto out; + } + + if (wlvif->bss_type == BSS_TYPE_STA_BSS) { + hlid = wlvif->sta.hlid; + ba_bitmap = &wlvif->sta.ba_rx_bitmap; + } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) { + struct wl1271_station *wl_sta; + + wl_sta = (struct wl1271_station *)sta->drv_priv; + hlid = wl_sta->hlid; + ba_bitmap = &wl->links[hlid].ba_bitmap; + } else { + ret = -EINVAL; + goto out; + } + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d", + tid, action); + + switch (action) { + case IEEE80211_AMPDU_RX_START: + if (!wlvif->ba_support || !wlvif->ba_allowed) { + ret = -ENOTSUPP; + break; + } + + if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) { + ret = -EBUSY; + wl1271_error("exceeded max RX BA sessions"); + break; + } + + if (*ba_bitmap & BIT(tid)) { + ret = -EINVAL; + wl1271_error("cannot enable RX BA session on active " + "tid: %d", tid); + break; + } + + ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true, + hlid); + if (!ret) { + *ba_bitmap |= BIT(tid); + wl->ba_rx_session_count++; + } + break; + + case IEEE80211_AMPDU_RX_STOP: + if (!(*ba_bitmap & BIT(tid))) { + ret = -EINVAL; + wl1271_error("no active RX BA session on tid: %d", + tid); + break; + } + + ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false, + hlid); + if (!ret) { + *ba_bitmap &= ~BIT(tid); + wl->ba_rx_session_count--; + } + break; + + /* + * The BA initiator session management in FW independently. + * Falling break here on purpose for all TX APDU commands. + */ + case IEEE80211_AMPDU_TX_START: + case IEEE80211_AMPDU_TX_STOP: + case IEEE80211_AMPDU_TX_OPERATIONAL: + ret = -EINVAL; + break; + + default: + wl1271_error("Incorrect ampdu action id=%x\n", action); + ret = -EINVAL; + } + + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const struct cfg80211_bitrate_mask *mask) +{ + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + struct wl1271 *wl = hw->priv; + int i, ret = 0; + + wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x", + mask->control[NL80211_BAND_2GHZ].legacy, + mask->control[NL80211_BAND_5GHZ].legacy); + + mutex_lock(&wl->mutex); + + for (i = 0; i < IEEE80211_NUM_BANDS; i++) + wlvif->bitrate_masks[i] = + wl1271_tx_enabled_rates_get(wl, + mask->control[i].legacy, + i); + + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + + if (wlvif->bss_type == BSS_TYPE_STA_BSS && + !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + wl1271_set_band_rate(wl, wlvif); + wlvif->basic_rate = + wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); + ret = wl1271_acx_sta_rate_policies(wl, wlvif); + + wl1271_ps_elp_sleep(wl); + } +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static void wl12xx_op_channel_switch(struct ieee80211_hw *hw, + struct ieee80211_channel_switch *ch_switch) +{ + struct wl1271 *wl = hw->priv; + struct wl12xx_vif *wlvif; + int ret; + + wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch"); + + wl1271_tx_flush(wl); + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) { + wl12xx_for_each_wlvif_sta(wl, wlvif) { + struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); + ieee80211_chswitch_done(vif, false); + } + goto out; + } + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + /* TODO: change mac80211 to pass vif as param */ + wl12xx_for_each_wlvif_sta(wl, wlvif) { + ret = wl12xx_cmd_channel_switch(wl, wlvif, ch_switch); + + if (!ret) + set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags); + } + + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + +static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) +{ + struct wl1271 *wl = hw->priv; + bool ret = false; + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + + /* packets are considered pending if in the TX queue or the FW */ + ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0); +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_rate wl1271_rates[] = { + { .bitrate = 10, + .hw_value = CONF_HW_BIT_RATE_1MBPS, + .hw_value_short = CONF_HW_BIT_RATE_1MBPS, }, + { .bitrate = 20, + .hw_value = CONF_HW_BIT_RATE_2MBPS, + .hw_value_short = CONF_HW_BIT_RATE_2MBPS, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, + .hw_value = CONF_HW_BIT_RATE_5_5MBPS, + .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, + .hw_value = CONF_HW_BIT_RATE_11MBPS, + .hw_value_short = CONF_HW_BIT_RATE_11MBPS, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 60, + .hw_value = CONF_HW_BIT_RATE_6MBPS, + .hw_value_short = CONF_HW_BIT_RATE_6MBPS, }, + { .bitrate = 90, + .hw_value = CONF_HW_BIT_RATE_9MBPS, + .hw_value_short = CONF_HW_BIT_RATE_9MBPS, }, + { .bitrate = 120, + .hw_value = CONF_HW_BIT_RATE_12MBPS, + .hw_value_short = CONF_HW_BIT_RATE_12MBPS, }, + { .bitrate = 180, + .hw_value = CONF_HW_BIT_RATE_18MBPS, + .hw_value_short = CONF_HW_BIT_RATE_18MBPS, }, + { .bitrate = 240, + .hw_value = CONF_HW_BIT_RATE_24MBPS, + .hw_value_short = CONF_HW_BIT_RATE_24MBPS, }, + { .bitrate = 360, + .hw_value = CONF_HW_BIT_RATE_36MBPS, + .hw_value_short = CONF_HW_BIT_RATE_36MBPS, }, + { .bitrate = 480, + .hw_value = CONF_HW_BIT_RATE_48MBPS, + .hw_value_short = CONF_HW_BIT_RATE_48MBPS, }, + { .bitrate = 540, + .hw_value = CONF_HW_BIT_RATE_54MBPS, + .hw_value_short = CONF_HW_BIT_RATE_54MBPS, }, +}; + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_channel wl1271_channels[] = { + { .hw_value = 1, .center_freq = 2412, .max_power = 25 }, + { .hw_value = 2, .center_freq = 2417, .max_power = 25 }, + { .hw_value = 3, .center_freq = 2422, .max_power = 25 }, + { .hw_value = 4, .center_freq = 2427, .max_power = 25 }, + { .hw_value = 5, .center_freq = 2432, .max_power = 25 }, + { .hw_value = 6, .center_freq = 2437, .max_power = 25 }, + { .hw_value = 7, .center_freq = 2442, .max_power = 25 }, + { .hw_value = 8, .center_freq = 2447, .max_power = 25 }, + { .hw_value = 9, .center_freq = 2452, .max_power = 25 }, + { .hw_value = 10, .center_freq = 2457, .max_power = 25 }, + { .hw_value = 11, .center_freq = 2462, .max_power = 25 }, + { .hw_value = 12, .center_freq = 2467, .max_power = 25 }, + { .hw_value = 13, .center_freq = 2472, .max_power = 25 }, + { .hw_value = 14, .center_freq = 2484, .max_power = 25 }, +}; + +/* can't be const, mac80211 writes to this */ +static struct ieee80211_supported_band wl1271_band_2ghz = { + .channels = wl1271_channels, + .n_channels = ARRAY_SIZE(wl1271_channels), + .bitrates = wl1271_rates, + .n_bitrates = ARRAY_SIZE(wl1271_rates), +}; + +/* 5 GHz data rates for WL1273 */ +static struct ieee80211_rate wl1271_rates_5ghz[] = { + { .bitrate = 60, + .hw_value = CONF_HW_BIT_RATE_6MBPS, + .hw_value_short = CONF_HW_BIT_RATE_6MBPS, }, + { .bitrate = 90, + .hw_value = CONF_HW_BIT_RATE_9MBPS, + .hw_value_short = CONF_HW_BIT_RATE_9MBPS, }, + { .bitrate = 120, + .hw_value = CONF_HW_BIT_RATE_12MBPS, + .hw_value_short = CONF_HW_BIT_RATE_12MBPS, }, + { .bitrate = 180, + .hw_value = CONF_HW_BIT_RATE_18MBPS, + .hw_value_short = CONF_HW_BIT_RATE_18MBPS, }, + { .bitrate = 240, + .hw_value = CONF_HW_BIT_RATE_24MBPS, + .hw_value_short = CONF_HW_BIT_RATE_24MBPS, }, + { .bitrate = 360, + .hw_value = CONF_HW_BIT_RATE_36MBPS, + .hw_value_short = CONF_HW_BIT_RATE_36MBPS, }, + { .bitrate = 480, + .hw_value = CONF_HW_BIT_RATE_48MBPS, + .hw_value_short = CONF_HW_BIT_RATE_48MBPS, }, + { .bitrate = 540, + .hw_value = CONF_HW_BIT_RATE_54MBPS, + .hw_value_short = CONF_HW_BIT_RATE_54MBPS, }, +}; + +/* 5 GHz band channels for WL1273 */ +static struct ieee80211_channel wl1271_channels_5ghz[] = { + { .hw_value = 7, .center_freq = 5035, .max_power = 25 }, + { .hw_value = 8, .center_freq = 5040, .max_power = 25 }, + { .hw_value = 9, .center_freq = 5045, .max_power = 25 }, + { .hw_value = 11, .center_freq = 5055, .max_power = 25 }, + { .hw_value = 12, .center_freq = 5060, .max_power = 25 }, + { .hw_value = 16, .center_freq = 5080, .max_power = 25 }, + { .hw_value = 34, .center_freq = 5170, .max_power = 25 }, + { .hw_value = 36, .center_freq = 5180, .max_power = 25 }, + { .hw_value = 38, .center_freq = 5190, .max_power = 25 }, + { .hw_value = 40, .center_freq = 5200, .max_power = 25 }, + { .hw_value = 42, .center_freq = 5210, .max_power = 25 }, + { .hw_value = 44, .center_freq = 5220, .max_power = 25 }, + { .hw_value = 46, .center_freq = 5230, .max_power = 25 }, + { .hw_value = 48, .center_freq = 5240, .max_power = 25 }, + { .hw_value = 52, .center_freq = 5260, .max_power = 25 }, + { .hw_value = 56, .center_freq = 5280, .max_power = 25 }, + { .hw_value = 60, .center_freq = 5300, .max_power = 25 }, + { .hw_value = 64, .center_freq = 5320, .max_power = 25 }, + { .hw_value = 100, .center_freq = 5500, .max_power = 25 }, + { .hw_value = 104, .center_freq = 5520, .max_power = 25 }, + { .hw_value = 108, .center_freq = 5540, .max_power = 25 }, + { .hw_value = 112, .center_freq = 5560, .max_power = 25 }, + { .hw_value = 116, .center_freq = 5580, .max_power = 25 }, + { .hw_value = 120, .center_freq = 5600, .max_power = 25 }, + { .hw_value = 124, .center_freq = 5620, .max_power = 25 }, + { .hw_value = 128, .center_freq = 5640, .max_power = 25 }, + { .hw_value = 132, .center_freq = 5660, .max_power = 25 }, + { .hw_value = 136, .center_freq = 5680, .max_power = 25 }, + { .hw_value = 140, .center_freq = 5700, .max_power = 25 }, + { .hw_value = 149, .center_freq = 5745, .max_power = 25 }, + { .hw_value = 153, .center_freq = 5765, .max_power = 25 }, + { .hw_value = 157, .center_freq = 5785, .max_power = 25 }, + { .hw_value = 161, .center_freq = 5805, .max_power = 25 }, + { .hw_value = 165, .center_freq = 5825, .max_power = 25 }, +}; + +static struct ieee80211_supported_band wl1271_band_5ghz = { + .channels = wl1271_channels_5ghz, + .n_channels = ARRAY_SIZE(wl1271_channels_5ghz), + .bitrates = wl1271_rates_5ghz, + .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz), +}; + +static const struct ieee80211_ops wl1271_ops = { + .start = wl1271_op_start, + .stop = wl1271_op_stop, + .add_interface = wl1271_op_add_interface, + .remove_interface = wl1271_op_remove_interface, + .change_interface = wl12xx_op_change_interface, +#ifdef CONFIG_PM + .suspend = wl1271_op_suspend, + .resume = wl1271_op_resume, +#endif + .config = wl1271_op_config, + .prepare_multicast = wl1271_op_prepare_multicast, + .configure_filter = wl1271_op_configure_filter, + .tx = wl1271_op_tx, + .set_key = wl1271_op_set_key, + .hw_scan = wl1271_op_hw_scan, + .cancel_hw_scan = wl1271_op_cancel_hw_scan, + .sched_scan_start = wl1271_op_sched_scan_start, + .sched_scan_stop = wl1271_op_sched_scan_stop, + .bss_info_changed = wl1271_op_bss_info_changed, + .set_frag_threshold = wl1271_op_set_frag_threshold, + .set_rts_threshold = wl1271_op_set_rts_threshold, + .conf_tx = wl1271_op_conf_tx, + .get_tsf = wl1271_op_get_tsf, + .get_survey = wl1271_op_get_survey, + .sta_state = wl12xx_op_sta_state, + .ampdu_action = wl1271_op_ampdu_action, + .tx_frames_pending = wl1271_tx_frames_pending, + .set_bitrate_mask = wl12xx_set_bitrate_mask, + .channel_switch = wl12xx_op_channel_switch, + CFG80211_TESTMODE_CMD(wl1271_tm_cmd) +}; + + +u8 wlcore_rate_to_idx(struct wl1271 *wl, u8 rate, enum ieee80211_band band) +{ + u8 idx; + + BUG_ON(band >= 2); + + if (unlikely(rate >= wl->hw_tx_rate_tbl_size)) { + wl1271_error("Illegal RX rate from HW: %d", rate); + return 0; + } + + idx = wl->band_rate_to_idx[band][rate]; + if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) { + wl1271_error("Unsupported RX rate from HW: %d", rate); + return 0; + } + + return idx; +} + +static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct wl1271 *wl = dev_get_drvdata(dev); + ssize_t len; + + len = PAGE_SIZE; + + mutex_lock(&wl->mutex); + len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n", + wl->sg_enabled); + mutex_unlock(&wl->mutex); + + return len; + +} + +static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct wl1271 *wl = dev_get_drvdata(dev); + unsigned long res; + int ret; + + ret = kstrtoul(buf, 10, &res); + if (ret < 0) { + wl1271_warning("incorrect value written to bt_coex_mode"); + return count; + } + + mutex_lock(&wl->mutex); + + res = !!res; + + if (res == wl->sg_enabled) + goto out; + + wl->sg_enabled = res; + + if (wl->state == WL1271_STATE_OFF) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + wl1271_acx_sg_enable(wl, wl->sg_enabled); + wl1271_ps_elp_sleep(wl); + + out: + mutex_unlock(&wl->mutex); + return count; +} + +static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR, + wl1271_sysfs_show_bt_coex_state, + wl1271_sysfs_store_bt_coex_state); + +static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct wl1271 *wl = dev_get_drvdata(dev); + ssize_t len; + + len = PAGE_SIZE; + + mutex_lock(&wl->mutex); + if (wl->hw_pg_ver >= 0) + len = snprintf(buf, len, "%d\n", wl->hw_pg_ver); + else + len = snprintf(buf, len, "n/a\n"); + mutex_unlock(&wl->mutex); + + return len; +} + +static DEVICE_ATTR(hw_pg_ver, S_IRUGO, + wl1271_sysfs_show_hw_pg_ver, NULL); + +static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buffer, loff_t pos, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct wl1271 *wl = dev_get_drvdata(dev); + ssize_t len; + int ret; + + ret = mutex_lock_interruptible(&wl->mutex); + if (ret < 0) + return -ERESTARTSYS; + + /* Let only one thread read the log at a time, blocking others */ + while (wl->fwlog_size == 0) { + DEFINE_WAIT(wait); + + prepare_to_wait_exclusive(&wl->fwlog_waitq, + &wait, + TASK_INTERRUPTIBLE); + + if (wl->fwlog_size != 0) { + finish_wait(&wl->fwlog_waitq, &wait); + break; + } + + mutex_unlock(&wl->mutex); + + schedule(); + finish_wait(&wl->fwlog_waitq, &wait); + + if (signal_pending(current)) + return -ERESTARTSYS; + + ret = mutex_lock_interruptible(&wl->mutex); + if (ret < 0) + return -ERESTARTSYS; + } + + /* Check if the fwlog is still valid */ + if (wl->fwlog_size < 0) { + mutex_unlock(&wl->mutex); + return 0; + } + + /* Seeking is not supported - old logs are not kept. Disregard pos. */ + len = min(count, (size_t)wl->fwlog_size); + wl->fwlog_size -= len; + memcpy(buffer, wl->fwlog, len); + + /* Make room for new messages */ + memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size); + + mutex_unlock(&wl->mutex); + + return len; +} + +static struct bin_attribute fwlog_attr = { + .attr = {.name = "fwlog", .mode = S_IRUSR}, + .read = wl1271_sysfs_read_fwlog, +}; + +static void wl12xx_derive_mac_addresses(struct wl1271 *wl, + u32 oui, u32 nic, int n) +{ + int i; + + wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x, n %d", + oui, nic, n); + + if (nic + n - 1 > 0xffffff) + wl1271_warning("NIC part of the MAC address wraps around!"); + + for (i = 0; i < n; i++) { + wl->addresses[i].addr[0] = (u8)(oui >> 16); + wl->addresses[i].addr[1] = (u8)(oui >> 8); + wl->addresses[i].addr[2] = (u8) oui; + wl->addresses[i].addr[3] = (u8)(nic >> 16); + wl->addresses[i].addr[4] = (u8)(nic >> 8); + wl->addresses[i].addr[5] = (u8) nic; + nic++; + } + + wl->hw->wiphy->n_addresses = n; + wl->hw->wiphy->addresses = wl->addresses; +} + +static int wl12xx_get_hw_info(struct wl1271 *wl) +{ + int ret; + + ret = wl12xx_set_power_on(wl); + if (ret < 0) + goto out; + + wl->chip.id = wlcore_read_reg(wl, REG_CHIP_ID_B); + + wl->fuse_oui_addr = 0; + wl->fuse_nic_addr = 0; + + wl->hw_pg_ver = wl->ops->get_pg_ver(wl); + + if (wl->ops->get_mac) + wl->ops->get_mac(wl); + + wl1271_power_off(wl); +out: + return ret; +} + +static int wl1271_register_hw(struct wl1271 *wl) +{ + int ret; + u32 oui_addr = 0, nic_addr = 0; + + if (wl->mac80211_registered) + return 0; + + ret = wl12xx_get_hw_info(wl); + if (ret < 0) { + wl1271_error("couldn't get hw info"); + goto out; + } + + ret = wl1271_fetch_nvs(wl); + if (ret == 0) { + /* NOTE: The wl->nvs->nvs element must be first, in + * order to simplify the casting, we assume it is at + * the beginning of the wl->nvs structure. + */ + u8 *nvs_ptr = (u8 *)wl->nvs; + + oui_addr = + (nvs_ptr[11] << 16) + (nvs_ptr[10] << 8) + nvs_ptr[6]; + nic_addr = + (nvs_ptr[5] << 16) + (nvs_ptr[4] << 8) + nvs_ptr[3]; + } + + /* if the MAC address is zeroed in the NVS derive from fuse */ + if (oui_addr == 0 && nic_addr == 0) { + oui_addr = wl->fuse_oui_addr; + /* fuse has the BD_ADDR, the WLAN addresses are the next two */ + nic_addr = wl->fuse_nic_addr + 1; + } + + wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr, 2); + + ret = ieee80211_register_hw(wl->hw); + if (ret < 0) { + wl1271_error("unable to register mac80211 hw: %d", ret); + goto out; + } + + wl->mac80211_registered = true; + + wl1271_debugfs_init(wl); + + wl1271_notice("loaded"); + +out: + return ret; +} + +static void wl1271_unregister_hw(struct wl1271 *wl) +{ + if (wl->plt) + wl1271_plt_stop(wl); + + ieee80211_unregister_hw(wl->hw); + wl->mac80211_registered = false; + +} + +static int wl1271_init_ieee80211(struct wl1271 *wl) +{ + static const u32 cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, + WL1271_CIPHER_SUITE_GEM, + }; + + /* The tx descriptor buffer and the TKIP space. */ + wl->hw->extra_tx_headroom = WL1271_EXTRA_SPACE_TKIP + + sizeof(struct wl1271_tx_hw_descr); + + /* unit us */ + /* FIXME: find a proper value */ + wl->hw->channel_change_time = 10000; + wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval; + + wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_SUPPORTS_DYNAMIC_PS | + IEEE80211_HW_SUPPORTS_UAPSD | + IEEE80211_HW_HAS_RATE_CONTROL | + IEEE80211_HW_CONNECTION_MONITOR | + IEEE80211_HW_REPORTS_TX_ACK_STATUS | + IEEE80211_HW_SPECTRUM_MGMT | + IEEE80211_HW_AP_LINK_PS | + IEEE80211_HW_AMPDU_AGGREGATION | + IEEE80211_HW_TX_AMPDU_SETUP_IN_HW | + IEEE80211_HW_SCAN_WHILE_IDLE; + + wl->hw->wiphy->cipher_suites = cipher_suites; + wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + + wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); + wl->hw->wiphy->max_scan_ssids = 1; + wl->hw->wiphy->max_sched_scan_ssids = 16; + wl->hw->wiphy->max_match_sets = 16; + /* + * Maximum length of elements in scanning probe request templates + * should be the maximum length possible for a template, without + * the IEEE80211 header of the template + */ + wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE - + sizeof(struct ieee80211_header); + + wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE - + sizeof(struct ieee80211_header); + + wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD | + WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + + /* make sure all our channels fit in the scanned_ch bitmask */ + BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) + + ARRAY_SIZE(wl1271_channels_5ghz) > + WL1271_MAX_CHANNELS); + /* + * We keep local copies of the band structs because we need to + * modify them on a per-device basis. + */ + memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz, + sizeof(wl1271_band_2ghz)); + memcpy(&wl->bands[IEEE80211_BAND_2GHZ].ht_cap, &wl->ht_cap, + sizeof(wl->ht_cap)); + memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz, + sizeof(wl1271_band_5ghz)); + memcpy(&wl->bands[IEEE80211_BAND_5GHZ].ht_cap, &wl->ht_cap, + sizeof(wl->ht_cap)); + + wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = + &wl->bands[IEEE80211_BAND_2GHZ]; + wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = + &wl->bands[IEEE80211_BAND_5GHZ]; + + wl->hw->queues = 4; + wl->hw->max_rates = 1; + + wl->hw->wiphy->reg_notifier = wl1271_reg_notify; + + /* the FW answers probe-requests in AP-mode */ + wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; + wl->hw->wiphy->probe_resp_offload = + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; + + SET_IEEE80211_DEV(wl->hw, wl->dev); + + wl->hw->sta_data_size = sizeof(struct wl1271_station); + wl->hw->vif_data_size = sizeof(struct wl12xx_vif); + + wl->hw->max_rx_aggregation_subframes = wl->conf.ht.rx_ba_win_size; + + return 0; +} + +#define WL1271_DEFAULT_CHANNEL 0 + +struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size) +{ + struct ieee80211_hw *hw; + struct wl1271 *wl; + int i, j, ret; + unsigned int order; + + BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS); + + hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); + if (!hw) { + wl1271_error("could not alloc ieee80211_hw"); + ret = -ENOMEM; + goto err_hw_alloc; + } + + wl = hw->priv; + memset(wl, 0, sizeof(*wl)); + + wl->priv = kzalloc(priv_size, GFP_KERNEL); + if (!wl->priv) { + wl1271_error("could not alloc wl priv"); + ret = -ENOMEM; + goto err_priv_alloc; + } + + INIT_LIST_HEAD(&wl->wlvif_list); + + wl->hw = hw; + + for (i = 0; i < NUM_TX_QUEUES; i++) + for (j = 0; j < WL12XX_MAX_LINKS; j++) + skb_queue_head_init(&wl->links[j].tx_queue[i]); + + skb_queue_head_init(&wl->deferred_rx_queue); + skb_queue_head_init(&wl->deferred_tx_queue); + + INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work); + INIT_WORK(&wl->netstack_work, wl1271_netstack_work); + INIT_WORK(&wl->tx_work, wl1271_tx_work); + INIT_WORK(&wl->recovery_work, wl1271_recovery_work); + INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work); + INIT_DELAYED_WORK(&wl->tx_watchdog_work, wl12xx_tx_watchdog_work); + + wl->freezable_wq = create_freezable_workqueue("wl12xx_wq"); + if (!wl->freezable_wq) { + ret = -ENOMEM; + goto err_hw; + } + + wl->channel = WL1271_DEFAULT_CHANNEL; + wl->rx_counter = 0; + wl->power_level = WL1271_DEFAULT_POWER_LEVEL; + wl->band = IEEE80211_BAND_2GHZ; + wl->flags = 0; + wl->sg_enabled = true; + wl->hw_pg_ver = -1; + wl->ap_ps_map = 0; + wl->ap_fw_ps_map = 0; + wl->quirks = 0; + wl->platform_quirks = 0; + wl->sched_scanning = false; + wl->system_hlid = WL12XX_SYSTEM_HLID; + wl->active_sta_count = 0; + wl->fwlog_size = 0; + init_waitqueue_head(&wl->fwlog_waitq); + + /* The system link is always allocated */ + __set_bit(WL12XX_SYSTEM_HLID, wl->links_map); + + memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); + for (i = 0; i < wl->num_tx_desc; i++) + wl->tx_frames[i] = NULL; + + spin_lock_init(&wl->wl_lock); + + wl->state = WL1271_STATE_OFF; + wl->fw_type = WL12XX_FW_TYPE_NONE; + mutex_init(&wl->mutex); + + order = get_order(WL1271_AGGR_BUFFER_SIZE); + wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order); + if (!wl->aggr_buf) { + ret = -ENOMEM; + goto err_wq; + } + + wl->dummy_packet = wl12xx_alloc_dummy_packet(wl); + if (!wl->dummy_packet) { + ret = -ENOMEM; + goto err_aggr; + } + + /* Allocate one page for the FW log */ + wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL); + if (!wl->fwlog) { + ret = -ENOMEM; + goto err_dummy_packet; + } + + wl->mbox = kmalloc(sizeof(*wl->mbox), GFP_DMA); + if (!wl->mbox) { + ret = -ENOMEM; + goto err_fwlog; + } + + return hw; + +err_fwlog: + free_page((unsigned long)wl->fwlog); + +err_dummy_packet: + dev_kfree_skb(wl->dummy_packet); + +err_aggr: + free_pages((unsigned long)wl->aggr_buf, order); + +err_wq: + destroy_workqueue(wl->freezable_wq); + +err_hw: + wl1271_debugfs_exit(wl); + kfree(wl->priv); + +err_priv_alloc: + ieee80211_free_hw(hw); + +err_hw_alloc: + + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(wlcore_alloc_hw); + +int wlcore_free_hw(struct wl1271 *wl) +{ + /* Unblock any fwlog readers */ + mutex_lock(&wl->mutex); + wl->fwlog_size = -1; + wake_up_interruptible_all(&wl->fwlog_waitq); + mutex_unlock(&wl->mutex); + + device_remove_bin_file(wl->dev, &fwlog_attr); + + device_remove_file(wl->dev, &dev_attr_hw_pg_ver); + + device_remove_file(wl->dev, &dev_attr_bt_coex_state); + free_page((unsigned long)wl->fwlog); + dev_kfree_skb(wl->dummy_packet); + free_pages((unsigned long)wl->aggr_buf, + get_order(WL1271_AGGR_BUFFER_SIZE)); + + wl1271_debugfs_exit(wl); + + vfree(wl->fw); + wl->fw = NULL; + wl->fw_type = WL12XX_FW_TYPE_NONE; + kfree(wl->nvs); + wl->nvs = NULL; + + kfree(wl->fw_status); + kfree(wl->tx_res_if); + destroy_workqueue(wl->freezable_wq); + + kfree(wl->priv); + ieee80211_free_hw(wl->hw); + + return 0; +} +EXPORT_SYMBOL_GPL(wlcore_free_hw); + +static irqreturn_t wl12xx_hardirq(int irq, void *cookie) +{ + struct wl1271 *wl = cookie; + unsigned long flags; + + wl1271_debug(DEBUG_IRQ, "IRQ"); + + /* complete the ELP completion */ + spin_lock_irqsave(&wl->wl_lock, flags); + set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); + if (wl->elp_compl) { + complete(wl->elp_compl); + wl->elp_compl = NULL; + } + + if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) { + /* don't enqueue a work right now. mark it as pending */ + set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags); + wl1271_debug(DEBUG_IRQ, "should not enqueue work"); + disable_irq_nosync(wl->irq); + pm_wakeup_event(wl->dev, 0); + spin_unlock_irqrestore(&wl->wl_lock, flags); + return IRQ_HANDLED; + } + spin_unlock_irqrestore(&wl->wl_lock, flags); + + return IRQ_WAKE_THREAD; +} + +int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev) +{ + struct wl12xx_platform_data *pdata = pdev->dev.platform_data; + unsigned long irqflags; + int ret; + + if (!wl->ops || !wl->ptable) { + ret = -EINVAL; + goto out_free_hw; + } + + BUG_ON(wl->num_tx_desc > WLCORE_MAX_TX_DESCRIPTORS); + + /* adjust some runtime configuration parameters */ + wlcore_adjust_conf(wl); + + wl->irq = platform_get_irq(pdev, 0); + wl->ref_clock = pdata->board_ref_clock; + wl->tcxo_clock = pdata->board_tcxo_clock; + wl->platform_quirks = pdata->platform_quirks; + wl->set_power = pdata->set_power; + wl->dev = &pdev->dev; + wl->if_ops = pdata->ops; + + platform_set_drvdata(pdev, wl); + + if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) + irqflags = IRQF_TRIGGER_RISING; + else + irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; + + ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq, + irqflags, + pdev->name, wl); + if (ret < 0) { + wl1271_error("request_irq() failed: %d", ret); + goto out_free_hw; + } + + ret = enable_irq_wake(wl->irq); + if (!ret) { + wl->irq_wake_enabled = true; + device_init_wakeup(wl->dev, 1); + if (pdata->pwr_in_suspend) + wl->hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY; + + } + disable_irq(wl->irq); + + ret = wl1271_init_ieee80211(wl); + if (ret) + goto out_irq; + + ret = wl1271_register_hw(wl); + if (ret) + goto out_irq; + + /* Create sysfs file to control bt coex state */ + ret = device_create_file(wl->dev, &dev_attr_bt_coex_state); + if (ret < 0) { + wl1271_error("failed to create sysfs file bt_coex_state"); + goto out_irq; + } + + /* Create sysfs file to get HW PG version */ + ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver); + if (ret < 0) { + wl1271_error("failed to create sysfs file hw_pg_ver"); + goto out_bt_coex_state; + } + + /* Create sysfs file for the FW log */ + ret = device_create_bin_file(wl->dev, &fwlog_attr); + if (ret < 0) { + wl1271_error("failed to create sysfs file fwlog"); + goto out_hw_pg_ver; + } + + goto out; + +out_hw_pg_ver: + device_remove_file(wl->dev, &dev_attr_hw_pg_ver); + +out_bt_coex_state: + device_remove_file(wl->dev, &dev_attr_bt_coex_state); + +out_irq: + free_irq(wl->irq, wl); + +out_free_hw: + wlcore_free_hw(wl); + +out: + return ret; +} +EXPORT_SYMBOL_GPL(wlcore_probe); + +int __devexit wlcore_remove(struct platform_device *pdev) +{ + struct wl1271 *wl = platform_get_drvdata(pdev); + + if (wl->irq_wake_enabled) { + device_init_wakeup(wl->dev, 0); + disable_irq_wake(wl->irq); + } + wl1271_unregister_hw(wl); + free_irq(wl->irq, wl); + wlcore_free_hw(wl); + + return 0; +} +EXPORT_SYMBOL_GPL(wlcore_remove); + +u32 wl12xx_debug_level = DEBUG_NONE; +EXPORT_SYMBOL_GPL(wl12xx_debug_level); +module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR); +MODULE_PARM_DESC(debug_level, "wl12xx debugging level"); + +module_param_named(fwlog, fwlog_param, charp, 0); +MODULE_PARM_DESC(fwlog, + "FW logger options: continuous, ondemand, dbgpins or disable"); + +module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR); +MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery"); + +module_param(no_recovery, bool, S_IRUSR | S_IWUSR); +MODULE_PARM_DESC(no_recovery, "Prevent HW recovery. FW will remain stuck."); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Luciano Coelho "); +MODULE_AUTHOR("Juuso Oikarinen "); diff --git a/trunk/drivers/net/wireless/wl12xx/ps.c b/trunk/drivers/net/wireless/ti/wlcore/ps.c similarity index 97% rename from trunk/drivers/net/wireless/wl12xx/ps.c rename to trunk/drivers/net/wireless/ti/wlcore/ps.c index 78f598b4f97b..756eee2257b4 100644 --- a/trunk/drivers/net/wireless/wl12xx/ps.c +++ b/trunk/drivers/net/wireless/ti/wlcore/ps.c @@ -21,7 +21,6 @@ * */ -#include "reg.h" #include "ps.h" #include "io.h" #include "tx.h" @@ -62,7 +61,7 @@ void wl1271_elp_work(struct work_struct *work) } wl1271_debug(DEBUG_PSM, "chip to elp"); - wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); + wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_SLEEP); set_bit(WL1271_FLAG_IN_ELP, &wl->flags); out: @@ -74,6 +73,9 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl) { struct wl12xx_vif *wlvif; + if (wl->quirks & WLCORE_QUIRK_NO_ELP) + return; + /* we shouldn't get consecutive sleep requests */ if (WARN_ON(test_and_set_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags))) return; @@ -125,7 +127,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl) wl->elp_compl = &compl; spin_unlock_irqrestore(&wl->wl_lock, flags); - wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); + wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP); if (!pending) { ret = wait_for_completion_timeout( diff --git a/trunk/drivers/net/wireless/wl12xx/ps.h b/trunk/drivers/net/wireless/ti/wlcore/ps.h similarity index 98% rename from trunk/drivers/net/wireless/wl12xx/ps.h rename to trunk/drivers/net/wireless/ti/wlcore/ps.h index 5f19d4fbbf27..de4f9da8ed26 100644 --- a/trunk/drivers/net/wireless/wl12xx/ps.h +++ b/trunk/drivers/net/wireless/ti/wlcore/ps.h @@ -24,7 +24,7 @@ #ifndef __PS_H__ #define __PS_H__ -#include "wl12xx.h" +#include "wlcore.h" #include "acx.h" int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, diff --git a/trunk/drivers/net/wireless/ti/wlcore/rx.c b/trunk/drivers/net/wireless/ti/wlcore/rx.c new file mode 100644 index 000000000000..89bd9385e90b --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wlcore/rx.c @@ -0,0 +1,280 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include + +#include "wlcore.h" +#include "debug.h" +#include "acx.h" +#include "rx.h" +#include "tx.h" +#include "io.h" +#include "hw_ops.h" + +/* + * TODO: this is here just for now, it must be removed when the data + * operations are in place. + */ +#include "../wl12xx/reg.h" + +static u32 wlcore_rx_get_buf_size(struct wl1271 *wl, + u32 rx_pkt_desc) +{ + if (wl->quirks & WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN) + return (rx_pkt_desc & ALIGNED_RX_BUF_SIZE_MASK) >> + ALIGNED_RX_BUF_SIZE_SHIFT; + + return (rx_pkt_desc & RX_BUF_SIZE_MASK) >> RX_BUF_SIZE_SHIFT_DIV; +} + +static u32 wlcore_rx_get_align_buf_size(struct wl1271 *wl, u32 pkt_len) +{ + if (wl->quirks & WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN) + return ALIGN(pkt_len, WL12XX_BUS_BLOCK_SIZE); + + return pkt_len; +} + +static void wl1271_rx_status(struct wl1271 *wl, + struct wl1271_rx_descriptor *desc, + struct ieee80211_rx_status *status, + u8 beacon) +{ + memset(status, 0, sizeof(struct ieee80211_rx_status)); + + if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG) + status->band = IEEE80211_BAND_2GHZ; + else + status->band = IEEE80211_BAND_5GHZ; + + status->rate_idx = wlcore_rate_to_idx(wl, desc->rate, status->band); + + /* 11n support */ + if (desc->rate <= wl->hw_min_ht_rate) + status->flag |= RX_FLAG_HT; + + status->signal = desc->rssi; + + /* + * FIXME: In wl1251, the SNR should be divided by two. In wl1271 we + * need to divide by two for now, but TI has been discussing about + * changing it. This needs to be rechecked. + */ + wl->noise = desc->rssi - (desc->snr >> 1); + + status->freq = ieee80211_channel_to_frequency(desc->channel, + status->band); + + if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) { + u8 desc_err_code = desc->status & WL1271_RX_DESC_STATUS_MASK; + + status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED | + RX_FLAG_DECRYPTED; + + if (unlikely(desc_err_code == WL1271_RX_DESC_MIC_FAIL)) { + status->flag |= RX_FLAG_MMIC_ERROR; + wl1271_warning("Michael MIC error"); + } + } +} + +static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, + enum wl_rx_buf_align rx_align, u8 *hlid) +{ + struct wl1271_rx_descriptor *desc; + struct sk_buff *skb; + struct ieee80211_hdr *hdr; + u8 *buf; + u8 beacon = 0; + u8 is_data = 0; + u8 reserved = 0; + u16 seq_num; + u32 pkt_data_len; + + /* + * In PLT mode we seem to get frames and mac80211 warns about them, + * workaround this by not retrieving them at all. + */ + if (unlikely(wl->plt)) + return -EINVAL; + + pkt_data_len = wlcore_hw_get_rx_packet_len(wl, data, length); + if (!pkt_data_len) { + wl1271_error("Invalid packet arrived from HW. length %d", + length); + return -EINVAL; + } + + if (rx_align == WLCORE_RX_BUF_UNALIGNED) + reserved = NET_IP_ALIGN; + + /* the data read starts with the descriptor */ + desc = (struct wl1271_rx_descriptor *) data; + + if (desc->packet_class == WL12XX_RX_CLASS_LOGGER) { + size_t len = length - sizeof(*desc); + wl12xx_copy_fwlog(wl, data + sizeof(*desc), len); + wake_up_interruptible(&wl->fwlog_waitq); + return 0; + } + + switch (desc->status & WL1271_RX_DESC_STATUS_MASK) { + /* discard corrupted packets */ + case WL1271_RX_DESC_DRIVER_RX_Q_FAIL: + case WL1271_RX_DESC_DECRYPT_FAIL: + wl1271_warning("corrupted packet in RX with status: 0x%x", + desc->status & WL1271_RX_DESC_STATUS_MASK); + return -EINVAL; + case WL1271_RX_DESC_SUCCESS: + case WL1271_RX_DESC_MIC_FAIL: + break; + default: + wl1271_error("invalid RX descriptor status: 0x%x", + desc->status & WL1271_RX_DESC_STATUS_MASK); + return -EINVAL; + } + + /* skb length not including rx descriptor */ + skb = __dev_alloc_skb(pkt_data_len + reserved, GFP_KERNEL); + if (!skb) { + wl1271_error("Couldn't allocate RX frame"); + return -ENOMEM; + } + + /* reserve the unaligned payload(if any) */ + skb_reserve(skb, reserved); + + buf = skb_put(skb, pkt_data_len); + + /* + * Copy packets from aggregation buffer to the skbs without rx + * descriptor and with packet payload aligned care. In case of unaligned + * packets copy the packets in offset of 2 bytes guarantee IP header + * payload aligned to 4 bytes. + */ + memcpy(buf, data + sizeof(*desc), pkt_data_len); + if (rx_align == WLCORE_RX_BUF_PADDED) + skb_pull(skb, NET_IP_ALIGN); + + *hlid = desc->hlid; + + hdr = (struct ieee80211_hdr *)skb->data; + if (ieee80211_is_beacon(hdr->frame_control)) + beacon = 1; + if (ieee80211_is_data_present(hdr->frame_control)) + is_data = 1; + + wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); + + seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; + wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d hlid %d", skb, + skb->len - desc->pad_len, + beacon ? "beacon" : "", + seq_num, *hlid); + + skb_queue_tail(&wl->deferred_rx_queue, skb); + queue_work(wl->freezable_wq, &wl->netstack_work); + + return is_data; +} + +void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status) +{ + unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0}; + u32 buf_size; + u32 fw_rx_counter = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK; + u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK; + u32 rx_counter; + u32 pkt_len, align_pkt_len; + u32 pkt_offset, des; + u8 hlid; + enum wl_rx_buf_align rx_align; + + while (drv_rx_counter != fw_rx_counter) { + buf_size = 0; + rx_counter = drv_rx_counter; + while (rx_counter != fw_rx_counter) { + des = le32_to_cpu(status->rx_pkt_descs[rx_counter]); + pkt_len = wlcore_rx_get_buf_size(wl, des); + align_pkt_len = wlcore_rx_get_align_buf_size(wl, + pkt_len); + if (buf_size + align_pkt_len > WL1271_AGGR_BUFFER_SIZE) + break; + buf_size += align_pkt_len; + rx_counter++; + rx_counter &= NUM_RX_PKT_DESC_MOD_MASK; + } + + if (buf_size == 0) { + wl1271_warning("received empty data"); + break; + } + + /* Read all available packets at once */ + des = le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]); + wlcore_hw_prepare_read(wl, des, buf_size); + wlcore_read_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf, + buf_size, true); + + /* Split data into separate packets */ + pkt_offset = 0; + while (pkt_offset < buf_size) { + des = le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]); + pkt_len = wlcore_rx_get_buf_size(wl, des); + rx_align = wlcore_hw_get_rx_buf_align(wl, des); + + /* + * the handle data call can only fail in memory-outage + * conditions, in that case the received frame will just + * be dropped. + */ + if (wl1271_rx_handle_data(wl, + wl->aggr_buf + pkt_offset, + pkt_len, rx_align, + &hlid) == 1) { + if (hlid < WL12XX_MAX_LINKS) + __set_bit(hlid, active_hlids); + else + WARN(1, + "hlid exceeded WL12XX_MAX_LINKS " + "(%d)\n", hlid); + } + + wl->rx_counter++; + drv_rx_counter++; + drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK; + pkt_offset += wlcore_rx_get_align_buf_size(wl, pkt_len); + } + } + + /* + * Write the driver's packet counter to the FW. This is only required + * for older hardware revisions + */ + if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION) + wl1271_write32(wl, WL12XX_REG_RX_DRIVER_COUNTER, + wl->rx_counter); + + wl12xx_rearm_rx_streaming(wl, active_hlids); +} diff --git a/trunk/drivers/net/wireless/wl12xx/rx.h b/trunk/drivers/net/wireless/ti/wlcore/rx.h similarity index 92% rename from trunk/drivers/net/wireless/wl12xx/rx.h rename to trunk/drivers/net/wireless/ti/wlcore/rx.h index 86ba6b1d0cdc..6e129e2a8546 100644 --- a/trunk/drivers/net/wireless/wl12xx/rx.h +++ b/trunk/drivers/net/wireless/ti/wlcore/rx.h @@ -96,9 +96,19 @@ #define RX_MEM_BLOCK_MASK 0xFF #define RX_BUF_SIZE_MASK 0xFFF00 #define RX_BUF_SIZE_SHIFT_DIV 6 +#define ALIGNED_RX_BUF_SIZE_MASK 0xFFFF00 +#define ALIGNED_RX_BUF_SIZE_SHIFT 8 + /* If set, the start of IP payload is not 4 bytes aligned */ #define RX_BUF_UNALIGNED_PAYLOAD BIT(20) +/* Describes the alignment state of a Rx buffer */ +enum wl_rx_buf_align { + WLCORE_RX_BUF_ALIGNED, + WLCORE_RX_BUF_UNALIGNED, + WLCORE_RX_BUF_PADDED, +}; + enum { WL12XX_RX_CLASS_UNKNOWN, WL12XX_RX_CLASS_MANAGEMENT, @@ -126,7 +136,7 @@ struct wl1271_rx_descriptor { u8 reserved; } __packed; -void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status); +void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status); u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); #endif diff --git a/trunk/drivers/net/wireless/ti/wlcore/scan.c b/trunk/drivers/net/wireless/ti/wlcore/scan.c new file mode 100644 index 000000000000..ade21a011c45 --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wlcore/scan.c @@ -0,0 +1,790 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009-2010 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include + +#include "wlcore.h" +#include "debug.h" +#include "cmd.h" +#include "scan.h" +#include "acx.h" +#include "ps.h" +#include "tx.h" + +void wl1271_scan_complete_work(struct work_struct *work) +{ + struct delayed_work *dwork; + struct wl1271 *wl; + struct ieee80211_vif *vif; + struct wl12xx_vif *wlvif; + int ret; + + dwork = container_of(work, struct delayed_work, work); + wl = container_of(dwork, struct wl1271, scan_complete_work); + + wl1271_debug(DEBUG_SCAN, "Scanning complete"); + + mutex_lock(&wl->mutex); + + if (wl->state == WL1271_STATE_OFF) + goto out; + + if (wl->scan.state == WL1271_SCAN_STATE_IDLE) + goto out; + + vif = wl->scan_vif; + wlvif = wl12xx_vif_to_data(vif); + + /* + * Rearm the tx watchdog just before idling scan. This + * prevents just-finished scans from triggering the watchdog + */ + wl12xx_rearm_tx_watchdog_locked(wl); + + wl->scan.state = WL1271_SCAN_STATE_IDLE; + memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); + wl->scan.req = NULL; + wl->scan_vif = NULL; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { + /* restore hardware connection monitoring template */ + wl1271_cmd_build_ap_probe_req(wl, wlvif, wlvif->probereq); + } + + wl1271_ps_elp_sleep(wl); + + if (wl->scan.failed) { + wl1271_info("Scan completed due to error."); + wl12xx_queue_recovery_work(wl); + } + + ieee80211_scan_completed(wl->hw, false); + +out: + mutex_unlock(&wl->mutex); + +} + + +static int wl1271_get_scan_channels(struct wl1271 *wl, + struct cfg80211_scan_request *req, + struct basic_scan_channel_params *channels, + enum ieee80211_band band, bool passive) +{ + struct conf_scan_settings *c = &wl->conf.scan; + int i, j; + u32 flags; + + for (i = 0, j = 0; + i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS; + i++) { + flags = req->channels[i]->flags; + + if (!test_bit(i, wl->scan.scanned_ch) && + !(flags & IEEE80211_CHAN_DISABLED) && + (req->channels[i]->band == band) && + /* + * In passive scans, we scan all remaining + * channels, even if not marked as such. + * In active scans, we only scan channels not + * marked as passive. + */ + (passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) { + wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ", + req->channels[i]->band, + req->channels[i]->center_freq); + wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X", + req->channels[i]->hw_value, + req->channels[i]->flags); + wl1271_debug(DEBUG_SCAN, + "max_antenna_gain %d, max_power %d", + req->channels[i]->max_antenna_gain, + req->channels[i]->max_power); + wl1271_debug(DEBUG_SCAN, "beacon_found %d", + req->channels[i]->beacon_found); + + if (!passive) { + channels[j].min_duration = + cpu_to_le32(c->min_dwell_time_active); + channels[j].max_duration = + cpu_to_le32(c->max_dwell_time_active); + } else { + channels[j].min_duration = + cpu_to_le32(c->min_dwell_time_passive); + channels[j].max_duration = + cpu_to_le32(c->max_dwell_time_passive); + } + channels[j].early_termination = 0; + channels[j].tx_power_att = req->channels[i]->max_power; + channels[j].channel = req->channels[i]->hw_value; + + memset(&channels[j].bssid_lsb, 0xff, 4); + memset(&channels[j].bssid_msb, 0xff, 2); + + /* Mark the channels we already used */ + set_bit(i, wl->scan.scanned_ch); + + j++; + } + } + + return j; +} + +#define WL1271_NOTHING_TO_SCAN 1 + +static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif, + enum ieee80211_band band, + bool passive, u32 basic_rate) +{ + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + struct wl1271_cmd_scan *cmd; + struct wl1271_cmd_trigger_scan_to *trigger; + int ret; + u16 scan_options = 0; + + /* skip active scans if we don't have SSIDs */ + if (!passive && wl->scan.req->n_ssids == 0) + return WL1271_NOTHING_TO_SCAN; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); + if (!cmd || !trigger) { + ret = -ENOMEM; + goto out; + } + + if (wl->conf.scan.split_scan_timeout) + scan_options |= WL1271_SCAN_OPT_SPLIT_SCAN; + + if (passive) + scan_options |= WL1271_SCAN_OPT_PASSIVE; + + if (wlvif->bss_type == BSS_TYPE_AP_BSS || + test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + cmd->params.role_id = wlvif->role_id; + else + cmd->params.role_id = wlvif->dev_role_id; + + if (WARN_ON(cmd->params.role_id == WL12XX_INVALID_ROLE_ID)) { + ret = -EINVAL; + goto out; + } + + cmd->params.scan_options = cpu_to_le16(scan_options); + + cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req, + cmd->channels, + band, passive); + if (cmd->params.n_ch == 0) { + ret = WL1271_NOTHING_TO_SCAN; + goto out; + } + + cmd->params.tx_rate = cpu_to_le32(basic_rate); + cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs; + cmd->params.tid_trigger = CONF_TX_AC_ANY_TID; + cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; + + if (band == IEEE80211_BAND_2GHZ) + cmd->params.band = WL1271_SCAN_BAND_2_4_GHZ; + else + cmd->params.band = WL1271_SCAN_BAND_5_GHZ; + + if (wl->scan.ssid_len && wl->scan.ssid) { + cmd->params.ssid_len = wl->scan.ssid_len; + memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len); + } + + memcpy(cmd->addr, vif->addr, ETH_ALEN); + + ret = wl12xx_cmd_build_probe_req(wl, wlvif, + cmd->params.role_id, band, + wl->scan.ssid, wl->scan.ssid_len, + wl->scan.req->ie, + wl->scan.req->ie_len); + if (ret < 0) { + wl1271_error("PROBE request template failed"); + goto out; + } + + trigger->timeout = cpu_to_le32(wl->conf.scan.split_scan_timeout); + ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, + sizeof(*trigger), 0); + if (ret < 0) { + wl1271_error("trigger scan to failed for hw scan"); + goto out; + } + + wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd)); + + ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("SCAN failed"); + goto out; + } + +out: + kfree(cmd); + kfree(trigger); + return ret; +} + +void wl1271_scan_stm(struct wl1271 *wl, struct ieee80211_vif *vif) +{ + struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); + int ret = 0; + enum ieee80211_band band; + u32 rate, mask; + + switch (wl->scan.state) { + case WL1271_SCAN_STATE_IDLE: + break; + + case WL1271_SCAN_STATE_2GHZ_ACTIVE: + band = IEEE80211_BAND_2GHZ; + mask = wlvif->bitrate_masks[band]; + if (wl->scan.req->no_cck) { + mask &= ~CONF_TX_CCK_RATES; + if (!mask) + mask = CONF_TX_RATE_MASK_BASIC_P2P; + } + rate = wl1271_tx_min_rate_get(wl, mask); + ret = wl1271_scan_send(wl, vif, band, false, rate); + if (ret == WL1271_NOTHING_TO_SCAN) { + wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE; + wl1271_scan_stm(wl, vif); + } + + break; + + case WL1271_SCAN_STATE_2GHZ_PASSIVE: + band = IEEE80211_BAND_2GHZ; + mask = wlvif->bitrate_masks[band]; + if (wl->scan.req->no_cck) { + mask &= ~CONF_TX_CCK_RATES; + if (!mask) + mask = CONF_TX_RATE_MASK_BASIC_P2P; + } + rate = wl1271_tx_min_rate_get(wl, mask); + ret = wl1271_scan_send(wl, vif, band, true, rate); + if (ret == WL1271_NOTHING_TO_SCAN) { + if (wl->enable_11a) + wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE; + else + wl->scan.state = WL1271_SCAN_STATE_DONE; + wl1271_scan_stm(wl, vif); + } + + break; + + case WL1271_SCAN_STATE_5GHZ_ACTIVE: + band = IEEE80211_BAND_5GHZ; + rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); + ret = wl1271_scan_send(wl, vif, band, false, rate); + if (ret == WL1271_NOTHING_TO_SCAN) { + wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE; + wl1271_scan_stm(wl, vif); + } + + break; + + case WL1271_SCAN_STATE_5GHZ_PASSIVE: + band = IEEE80211_BAND_5GHZ; + rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); + ret = wl1271_scan_send(wl, vif, band, true, rate); + if (ret == WL1271_NOTHING_TO_SCAN) { + wl->scan.state = WL1271_SCAN_STATE_DONE; + wl1271_scan_stm(wl, vif); + } + + break; + + case WL1271_SCAN_STATE_DONE: + wl->scan.failed = false; + cancel_delayed_work(&wl->scan_complete_work); + ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, + msecs_to_jiffies(0)); + break; + + default: + wl1271_error("invalid scan state"); + break; + } + + if (ret < 0) { + cancel_delayed_work(&wl->scan_complete_work); + ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, + msecs_to_jiffies(0)); + } +} + +int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif, + const u8 *ssid, size_t ssid_len, + struct cfg80211_scan_request *req) +{ + /* + * cfg80211 should guarantee that we don't get more channels + * than what we have registered. + */ + BUG_ON(req->n_channels > WL1271_MAX_CHANNELS); + + if (wl->scan.state != WL1271_SCAN_STATE_IDLE) + return -EBUSY; + + wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE; + + if (ssid_len && ssid) { + wl->scan.ssid_len = ssid_len; + memcpy(wl->scan.ssid, ssid, ssid_len); + } else { + wl->scan.ssid_len = 0; + } + + wl->scan_vif = vif; + wl->scan.req = req; + memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); + + /* we assume failure so that timeout scenarios are handled correctly */ + wl->scan.failed = true; + ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, + msecs_to_jiffies(WL1271_SCAN_TIMEOUT)); + + wl1271_scan_stm(wl, vif); + + return 0; +} + +int wl1271_scan_stop(struct wl1271 *wl) +{ + struct wl1271_cmd_header *cmd = NULL; + int ret = 0; + + if (WARN_ON(wl->scan.state == WL1271_SCAN_STATE_IDLE)) + return -EINVAL; + + wl1271_debug(DEBUG_CMD, "cmd scan stop"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, cmd, + sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("cmd stop_scan failed"); + goto out; + } +out: + kfree(cmd); + return ret; +} + +static int +wl1271_scan_get_sched_scan_channels(struct wl1271 *wl, + struct cfg80211_sched_scan_request *req, + struct conn_scan_ch_params *channels, + u32 band, bool radar, bool passive, + int start, int max_channels) +{ + struct conf_sched_scan_settings *c = &wl->conf.sched_scan; + int i, j; + u32 flags; + bool force_passive = !req->n_ssids; + u32 min_dwell_time_active, max_dwell_time_active, delta_per_probe; + u32 dwell_time_passive, dwell_time_dfs; + + if (band == IEEE80211_BAND_5GHZ) + delta_per_probe = c->dwell_time_delta_per_probe_5; + else + delta_per_probe = c->dwell_time_delta_per_probe; + + min_dwell_time_active = c->base_dwell_time + + req->n_ssids * c->num_probe_reqs * delta_per_probe; + + max_dwell_time_active = min_dwell_time_active + c->max_dwell_time_delta; + + min_dwell_time_active = DIV_ROUND_UP(min_dwell_time_active, 1000); + max_dwell_time_active = DIV_ROUND_UP(max_dwell_time_active, 1000); + dwell_time_passive = DIV_ROUND_UP(c->dwell_time_passive, 1000); + dwell_time_dfs = DIV_ROUND_UP(c->dwell_time_dfs, 1000); + + for (i = 0, j = start; + i < req->n_channels && j < max_channels; + i++) { + flags = req->channels[i]->flags; + + if (force_passive) + flags |= IEEE80211_CHAN_PASSIVE_SCAN; + + if ((req->channels[i]->band == band) && + !(flags & IEEE80211_CHAN_DISABLED) && + (!!(flags & IEEE80211_CHAN_RADAR) == radar) && + /* if radar is set, we ignore the passive flag */ + (radar || + !!(flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive)) { + wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ", + req->channels[i]->band, + req->channels[i]->center_freq); + wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X", + req->channels[i]->hw_value, + req->channels[i]->flags); + wl1271_debug(DEBUG_SCAN, "max_power %d", + req->channels[i]->max_power); + wl1271_debug(DEBUG_SCAN, "min_dwell_time %d max dwell time %d", + min_dwell_time_active, + max_dwell_time_active); + + if (flags & IEEE80211_CHAN_RADAR) { + channels[j].flags |= SCAN_CHANNEL_FLAGS_DFS; + + channels[j].passive_duration = + cpu_to_le16(dwell_time_dfs); + } else { + channels[j].passive_duration = + cpu_to_le16(dwell_time_passive); + } + + channels[j].min_duration = + cpu_to_le16(min_dwell_time_active); + channels[j].max_duration = + cpu_to_le16(max_dwell_time_active); + + channels[j].tx_power_att = req->channels[i]->max_power; + channels[j].channel = req->channels[i]->hw_value; + + j++; + } + } + + return j - start; +} + +static bool +wl1271_scan_sched_scan_channels(struct wl1271 *wl, + struct cfg80211_sched_scan_request *req, + struct wl1271_cmd_sched_scan_config *cfg) +{ + cfg->passive[0] = + wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_2, + IEEE80211_BAND_2GHZ, + false, true, 0, + MAX_CHANNELS_2GHZ); + cfg->active[0] = + wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_2, + IEEE80211_BAND_2GHZ, + false, false, + cfg->passive[0], + MAX_CHANNELS_2GHZ); + cfg->passive[1] = + wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5, + IEEE80211_BAND_5GHZ, + false, true, 0, + MAX_CHANNELS_5GHZ); + cfg->dfs = + wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5, + IEEE80211_BAND_5GHZ, + true, true, + cfg->passive[1], + MAX_CHANNELS_5GHZ); + cfg->active[1] = + wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5, + IEEE80211_BAND_5GHZ, + false, false, + cfg->passive[1] + cfg->dfs, + MAX_CHANNELS_5GHZ); + /* 802.11j channels are not supported yet */ + cfg->passive[2] = 0; + cfg->active[2] = 0; + + wl1271_debug(DEBUG_SCAN, " 2.4GHz: active %d passive %d", + cfg->active[0], cfg->passive[0]); + wl1271_debug(DEBUG_SCAN, " 5GHz: active %d passive %d", + cfg->active[1], cfg->passive[1]); + wl1271_debug(DEBUG_SCAN, " DFS: %d", cfg->dfs); + + return cfg->passive[0] || cfg->active[0] || + cfg->passive[1] || cfg->active[1] || cfg->dfs || + cfg->passive[2] || cfg->active[2]; +} + +/* Returns the scan type to be used or a negative value on error */ +static int +wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, + struct cfg80211_sched_scan_request *req) +{ + struct wl1271_cmd_sched_scan_ssid_list *cmd = NULL; + struct cfg80211_match_set *sets = req->match_sets; + struct cfg80211_ssid *ssids = req->ssids; + int ret = 0, type, i, j, n_match_ssids = 0; + + wl1271_debug(DEBUG_CMD, "cmd sched scan ssid list"); + + /* count the match sets that contain SSIDs */ + for (i = 0; i < req->n_match_sets; i++) + if (sets[i].ssid.ssid_len > 0) + n_match_ssids++; + + /* No filter, no ssids or only bcast ssid */ + if (!n_match_ssids && + (!req->n_ssids || + (req->n_ssids == 1 && req->ssids[0].ssid_len == 0))) { + type = SCAN_SSID_FILTER_ANY; + goto out; + } + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + if (!n_match_ssids) { + /* No filter, with ssids */ + type = SCAN_SSID_FILTER_DISABLED; + + for (i = 0; i < req->n_ssids; i++) { + cmd->ssids[cmd->n_ssids].type = (ssids[i].ssid_len) ? + SCAN_SSID_TYPE_HIDDEN : SCAN_SSID_TYPE_PUBLIC; + cmd->ssids[cmd->n_ssids].len = ssids[i].ssid_len; + memcpy(cmd->ssids[cmd->n_ssids].ssid, ssids[i].ssid, + ssids[i].ssid_len); + cmd->n_ssids++; + } + } else { + type = SCAN_SSID_FILTER_LIST; + + /* Add all SSIDs from the filters */ + for (i = 0; i < req->n_match_sets; i++) { + /* ignore sets without SSIDs */ + if (!sets[i].ssid.ssid_len) + continue; + + cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_PUBLIC; + cmd->ssids[cmd->n_ssids].len = sets[i].ssid.ssid_len; + memcpy(cmd->ssids[cmd->n_ssids].ssid, + sets[i].ssid.ssid, sets[i].ssid.ssid_len); + cmd->n_ssids++; + } + if ((req->n_ssids > 1) || + (req->n_ssids == 1 && req->ssids[0].ssid_len > 0)) { + /* + * Mark all the SSIDs passed in the SSID list as HIDDEN, + * so they're used in probe requests. + */ + for (i = 0; i < req->n_ssids; i++) { + if (!req->ssids[i].ssid_len) + continue; + + for (j = 0; j < cmd->n_ssids; j++) + if (!memcmp(req->ssids[i].ssid, + cmd->ssids[j].ssid, + req->ssids[i].ssid_len)) { + cmd->ssids[j].type = + SCAN_SSID_TYPE_HIDDEN; + break; + } + /* Fail if SSID isn't present in the filters */ + if (j == cmd->n_ssids) { + ret = -EINVAL; + goto out_free; + } + } + } + } + + wl1271_dump(DEBUG_SCAN, "SSID_LIST: ", cmd, sizeof(*cmd)); + + ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_SSID_CFG, cmd, + sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("cmd sched scan ssid list failed"); + goto out_free; + } + +out_free: + kfree(cmd); +out: + if (ret < 0) + return ret; + return type; +} + +int wl1271_scan_sched_scan_config(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + struct cfg80211_sched_scan_request *req, + struct ieee80211_sched_scan_ies *ies) +{ + struct wl1271_cmd_sched_scan_config *cfg = NULL; + struct conf_sched_scan_settings *c = &wl->conf.sched_scan; + int i, ret; + bool force_passive = !req->n_ssids; + + wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config"); + + cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); + if (!cfg) + return -ENOMEM; + + cfg->rssi_threshold = c->rssi_threshold; + cfg->snr_threshold = c->snr_threshold; + cfg->n_probe_reqs = c->num_probe_reqs; + /* cycles set to 0 it means infinite (until manually stopped) */ + cfg->cycles = 0; + /* report APs when at least 1 is found */ + cfg->report_after = 1; + /* don't stop scanning automatically when something is found */ + cfg->terminate = 0; + cfg->tag = WL1271_SCAN_DEFAULT_TAG; + /* don't filter on BSS type */ + cfg->bss_type = SCAN_BSS_TYPE_ANY; + /* currently NL80211 supports only a single interval */ + for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++) + cfg->intervals[i] = cpu_to_le32(req->interval); + + cfg->ssid_len = 0; + ret = wl12xx_scan_sched_scan_ssid_list(wl, req); + if (ret < 0) + goto out; + + cfg->filter_type = ret; + + wl1271_debug(DEBUG_SCAN, "filter_type = %d", cfg->filter_type); + + if (!wl1271_scan_sched_scan_channels(wl, req, cfg)) { + wl1271_error("scan channel list is empty"); + ret = -EINVAL; + goto out; + } + + if (!force_passive && cfg->active[0]) { + u8 band = IEEE80211_BAND_2GHZ; + ret = wl12xx_cmd_build_probe_req(wl, wlvif, + wlvif->dev_role_id, band, + req->ssids[0].ssid, + req->ssids[0].ssid_len, + ies->ie[band], + ies->len[band]); + if (ret < 0) { + wl1271_error("2.4GHz PROBE request template failed"); + goto out; + } + } + + if (!force_passive && cfg->active[1]) { + u8 band = IEEE80211_BAND_5GHZ; + ret = wl12xx_cmd_build_probe_req(wl, wlvif, + wlvif->dev_role_id, band, + req->ssids[0].ssid, + req->ssids[0].ssid_len, + ies->ie[band], + ies->len[band]); + if (ret < 0) { + wl1271_error("5GHz PROBE request template failed"); + goto out; + } + } + + wl1271_dump(DEBUG_SCAN, "SCAN_CFG: ", cfg, sizeof(*cfg)); + + ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_CFG, cfg, + sizeof(*cfg), 0); + if (ret < 0) { + wl1271_error("SCAN configuration failed"); + goto out; + } +out: + kfree(cfg); + return ret; +} + +int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + struct wl1271_cmd_sched_scan_start *start; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd periodic scan start"); + + if (wlvif->bss_type != BSS_TYPE_STA_BSS) + return -EOPNOTSUPP; + + if (test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) + return -EBUSY; + + start = kzalloc(sizeof(*start), GFP_KERNEL); + if (!start) + return -ENOMEM; + + start->tag = WL1271_SCAN_DEFAULT_TAG; + + ret = wl1271_cmd_send(wl, CMD_START_PERIODIC_SCAN, start, + sizeof(*start), 0); + if (ret < 0) { + wl1271_error("failed to send scan start command"); + goto out_free; + } + +out_free: + kfree(start); + return ret; +} + +void wl1271_scan_sched_scan_results(struct wl1271 *wl) +{ + wl1271_debug(DEBUG_SCAN, "got periodic scan results"); + + ieee80211_sched_scan_results(wl->hw); +} + +void wl1271_scan_sched_scan_stop(struct wl1271 *wl) +{ + struct wl1271_cmd_sched_scan_stop *stop; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd periodic scan stop"); + + /* FIXME: what to do if alloc'ing to stop fails? */ + stop = kzalloc(sizeof(*stop), GFP_KERNEL); + if (!stop) { + wl1271_error("failed to alloc memory to send sched scan stop"); + return; + } + + stop->tag = WL1271_SCAN_DEFAULT_TAG; + + ret = wl1271_cmd_send(wl, CMD_STOP_PERIODIC_SCAN, stop, + sizeof(*stop), 0); + if (ret < 0) { + wl1271_error("failed to send sched scan stop command"); + goto out_free; + } + +out_free: + kfree(stop); +} diff --git a/trunk/drivers/net/wireless/ti/wlcore/scan.h b/trunk/drivers/net/wireless/ti/wlcore/scan.h new file mode 100644 index 000000000000..81ee36ac2078 --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wlcore/scan.h @@ -0,0 +1,233 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009-2010 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __SCAN_H__ +#define __SCAN_H__ + +#include "wlcore.h" + +int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif, + const u8 *ssid, size_t ssid_len, + struct cfg80211_scan_request *req); +int wl1271_scan_stop(struct wl1271 *wl); +int wl1271_scan_build_probe_req(struct wl1271 *wl, + const u8 *ssid, size_t ssid_len, + const u8 *ie, size_t ie_len, u8 band); +void wl1271_scan_stm(struct wl1271 *wl, struct ieee80211_vif *vif); +void wl1271_scan_complete_work(struct work_struct *work); +int wl1271_scan_sched_scan_config(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + struct cfg80211_sched_scan_request *req, + struct ieee80211_sched_scan_ies *ies); +int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif); +void wl1271_scan_sched_scan_stop(struct wl1271 *wl); +void wl1271_scan_sched_scan_results(struct wl1271 *wl); + +#define WL1271_SCAN_MAX_CHANNELS 24 +#define WL1271_SCAN_DEFAULT_TAG 1 +#define WL1271_SCAN_CURRENT_TX_PWR 0 +#define WL1271_SCAN_OPT_ACTIVE 0 +#define WL1271_SCAN_OPT_PASSIVE 1 +#define WL1271_SCAN_OPT_SPLIT_SCAN 2 +#define WL1271_SCAN_OPT_PRIORITY_HIGH 4 +/* scan even if we fail to enter psm */ +#define WL1271_SCAN_OPT_FORCE 8 +#define WL1271_SCAN_BAND_2_4_GHZ 0 +#define WL1271_SCAN_BAND_5_GHZ 1 + +#define WL1271_SCAN_TIMEOUT 30000 /* msec */ + +enum { + WL1271_SCAN_STATE_IDLE, + WL1271_SCAN_STATE_2GHZ_ACTIVE, + WL1271_SCAN_STATE_2GHZ_PASSIVE, + WL1271_SCAN_STATE_5GHZ_ACTIVE, + WL1271_SCAN_STATE_5GHZ_PASSIVE, + WL1271_SCAN_STATE_DONE +}; + +struct basic_scan_params { + /* Scan option flags (WL1271_SCAN_OPT_*) */ + __le16 scan_options; + u8 role_id; + /* Number of scan channels in the list (maximum 30) */ + u8 n_ch; + /* This field indicates the number of probe requests to send + per channel for an active scan */ + u8 n_probe_reqs; + u8 tid_trigger; + u8 ssid_len; + u8 use_ssid_list; + + /* Rate bit field for sending the probes */ + __le32 tx_rate; + + u8 ssid[IEEE80211_MAX_SSID_LEN]; + /* Band to scan */ + u8 band; + + u8 scan_tag; + u8 padding2[2]; +} __packed; + +struct basic_scan_channel_params { + /* Duration in TU to wait for frames on a channel for active scan */ + __le32 min_duration; + __le32 max_duration; + __le32 bssid_lsb; + __le16 bssid_msb; + u8 early_termination; + u8 tx_power_att; + u8 channel; + /* FW internal use only! */ + u8 dfs_candidate; + u8 activity_detected; + u8 pad; +} __packed; + +struct wl1271_cmd_scan { + struct wl1271_cmd_header header; + + struct basic_scan_params params; + struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS]; + + /* src mac address */ + u8 addr[ETH_ALEN]; + u8 padding[2]; +} __packed; + +struct wl1271_cmd_trigger_scan_to { + struct wl1271_cmd_header header; + + __le32 timeout; +} __packed; + +#define MAX_CHANNELS_2GHZ 14 +#define MAX_CHANNELS_5GHZ 23 +#define MAX_CHANNELS_4GHZ 4 + +#define SCAN_MAX_CYCLE_INTERVALS 16 +#define SCAN_MAX_BANDS 3 + +enum { + SCAN_SSID_FILTER_ANY = 0, + SCAN_SSID_FILTER_SPECIFIC = 1, + SCAN_SSID_FILTER_LIST = 2, + SCAN_SSID_FILTER_DISABLED = 3 +}; + +enum { + SCAN_BSS_TYPE_INDEPENDENT, + SCAN_BSS_TYPE_INFRASTRUCTURE, + SCAN_BSS_TYPE_ANY, +}; + +#define SCAN_CHANNEL_FLAGS_DFS BIT(0) +#define SCAN_CHANNEL_FLAGS_DFS_ENABLED BIT(1) + +struct conn_scan_ch_params { + __le16 min_duration; + __le16 max_duration; + __le16 passive_duration; + + u8 channel; + u8 tx_power_att; + + /* bit 0: DFS channel; bit 1: DFS enabled */ + u8 flags; + + u8 padding[3]; +} __packed; + +struct wl1271_cmd_sched_scan_config { + struct wl1271_cmd_header header; + + __le32 intervals[SCAN_MAX_CYCLE_INTERVALS]; + + s8 rssi_threshold; /* for filtering (in dBm) */ + s8 snr_threshold; /* for filtering (in dB) */ + + u8 cycles; /* maximum number of scan cycles */ + u8 report_after; /* report when this number of results are received */ + u8 terminate; /* stop scanning after reporting */ + + u8 tag; + u8 bss_type; /* for filtering */ + u8 filter_type; + + u8 ssid_len; /* For SCAN_SSID_FILTER_SPECIFIC */ + u8 ssid[IEEE80211_MAX_SSID_LEN]; + + u8 n_probe_reqs; /* Number of probes requests per channel */ + + u8 passive[SCAN_MAX_BANDS]; + u8 active[SCAN_MAX_BANDS]; + + u8 dfs; + + u8 padding[3]; + + struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ]; + struct conn_scan_ch_params channels_5[MAX_CHANNELS_5GHZ]; + struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ]; +} __packed; + + +#define SCHED_SCAN_MAX_SSIDS 16 + +enum { + SCAN_SSID_TYPE_PUBLIC = 0, + SCAN_SSID_TYPE_HIDDEN = 1, +}; + +struct wl1271_ssid { + u8 type; + u8 len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + /* u8 padding[2]; */ +} __packed; + +struct wl1271_cmd_sched_scan_ssid_list { + struct wl1271_cmd_header header; + + u8 n_ssids; + struct wl1271_ssid ssids[SCHED_SCAN_MAX_SSIDS]; + u8 padding[3]; +} __packed; + +struct wl1271_cmd_sched_scan_start { + struct wl1271_cmd_header header; + + u8 tag; + u8 padding[3]; +} __packed; + +struct wl1271_cmd_sched_scan_stop { + struct wl1271_cmd_header header; + + u8 tag; + u8 padding[3]; +} __packed; + + +#endif /* __WL1271_SCAN_H__ */ diff --git a/trunk/drivers/net/wireless/wl12xx/sdio.c b/trunk/drivers/net/wireless/ti/wlcore/sdio.c similarity index 98% rename from trunk/drivers/net/wireless/wl12xx/sdio.c rename to trunk/drivers/net/wireless/ti/wlcore/sdio.c index 4b3c32774bae..0a72347cfc4c 100644 --- a/trunk/drivers/net/wireless/wl12xx/sdio.c +++ b/trunk/drivers/net/wireless/ti/wlcore/sdio.c @@ -33,7 +33,7 @@ #include #include -#include "wl12xx.h" +#include "wlcore.h" #include "wl12xx_80211.h" #include "io.h" @@ -76,7 +76,7 @@ static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf, sdio_claim_host(func); - if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { + if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG)) { ((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret); dev_dbg(child->parent, "sdio read 52 addr 0x%x, byte 0x%02x\n", addr, ((u8 *)buf)[0]); @@ -105,7 +105,7 @@ static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf, sdio_claim_host(func); - if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { + if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG)) { sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret); dev_dbg(child->parent, "sdio write 52 addr 0x%x, byte 0x%02x\n", addr, ((u8 *)buf)[0]); diff --git a/trunk/drivers/net/wireless/wl12xx/spi.c b/trunk/drivers/net/wireless/ti/wlcore/spi.c similarity index 99% rename from trunk/drivers/net/wireless/wl12xx/spi.c rename to trunk/drivers/net/wireless/ti/wlcore/spi.c index 2fc18a8dcce8..553cd3cbb98c 100644 --- a/trunk/drivers/net/wireless/wl12xx/spi.c +++ b/trunk/drivers/net/wireless/ti/wlcore/spi.c @@ -30,12 +30,10 @@ #include #include -#include "wl12xx.h" +#include "wlcore.h" #include "wl12xx_80211.h" #include "io.h" -#include "reg.h" - #define WSPI_CMD_READ 0x40000000 #define WSPI_CMD_WRITE 0x00000000 #define WSPI_CMD_FIXED 0x20000000 diff --git a/trunk/drivers/net/wireless/wl12xx/testmode.c b/trunk/drivers/net/wireless/ti/wlcore/testmode.c similarity index 96% rename from trunk/drivers/net/wireless/wl12xx/testmode.c rename to trunk/drivers/net/wireless/ti/wlcore/testmode.c index 1e93bb9c0246..0e59ea2cdd39 100644 --- a/trunk/drivers/net/wireless/wl12xx/testmode.c +++ b/trunk/drivers/net/wireless/ti/wlcore/testmode.c @@ -25,10 +25,9 @@ #include #include -#include "wl12xx.h" +#include "wlcore.h" #include "debug.h" #include "acx.h" -#include "reg.h" #include "ps.h" #include "io.h" @@ -116,7 +115,8 @@ static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[]) goto out_sleep; } - NLA_PUT(skb, WL1271_TM_ATTR_DATA, buf_len, buf); + if (nla_put(skb, WL1271_TM_ATTR_DATA, buf_len, buf)) + goto nla_put_failure; ret = cfg80211_testmode_reply(skb); if (ret < 0) goto out_sleep; @@ -178,7 +178,8 @@ static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[]) goto out_free; } - NLA_PUT(skb, WL1271_TM_ATTR_DATA, sizeof(*cmd), cmd); + if (nla_put(skb, WL1271_TM_ATTR_DATA, sizeof(*cmd), cmd)) + goto nla_put_failure; ret = cfg80211_testmode_reply(skb); if (ret < 0) goto out_free; @@ -297,7 +298,8 @@ static int wl12xx_tm_cmd_get_mac(struct wl1271 *wl, struct nlattr *tb[]) goto out; } - NLA_PUT(skb, WL1271_TM_ATTR_DATA, ETH_ALEN, mac_addr); + if (nla_put(skb, WL1271_TM_ATTR_DATA, ETH_ALEN, mac_addr)) + goto nla_put_failure; ret = cfg80211_testmode_reply(skb); if (ret < 0) goto out; diff --git a/trunk/drivers/net/wireless/wl12xx/testmode.h b/trunk/drivers/net/wireless/ti/wlcore/testmode.h similarity index 100% rename from trunk/drivers/net/wireless/wl12xx/testmode.h rename to trunk/drivers/net/wireless/ti/wlcore/testmode.h diff --git a/trunk/drivers/net/wireless/ti/wlcore/tx.c b/trunk/drivers/net/wireless/ti/wlcore/tx.c new file mode 100644 index 000000000000..6893bc207994 --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wlcore/tx.c @@ -0,0 +1,1056 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include + +#include "wlcore.h" +#include "debug.h" +#include "io.h" +#include "ps.h" +#include "tx.h" +#include "event.h" +#include "hw_ops.h" + +/* + * TODO: this is here just for now, it must be removed when the data + * operations are in place. + */ +#include "../wl12xx/reg.h" + +static int wl1271_set_default_wep_key(struct wl1271 *wl, + struct wl12xx_vif *wlvif, u8 id) +{ + int ret; + bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); + + if (is_ap) + ret = wl12xx_cmd_set_default_wep_key(wl, id, + wlvif->ap.bcast_hlid); + else + ret = wl12xx_cmd_set_default_wep_key(wl, id, wlvif->sta.hlid); + + if (ret < 0) + return ret; + + wl1271_debug(DEBUG_CRYPT, "default wep key idx: %d", (int)id); + return 0; +} + +static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb) +{ + int id; + + id = find_first_zero_bit(wl->tx_frames_map, wl->num_tx_desc); + if (id >= wl->num_tx_desc) + return -EBUSY; + + __set_bit(id, wl->tx_frames_map); + wl->tx_frames[id] = skb; + wl->tx_frames_cnt++; + return id; +} + +static void wl1271_free_tx_id(struct wl1271 *wl, int id) +{ + if (__test_and_clear_bit(id, wl->tx_frames_map)) { + if (unlikely(wl->tx_frames_cnt == wl->num_tx_desc)) + clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); + + wl->tx_frames[id] = NULL; + wl->tx_frames_cnt--; + } +} + +static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, + struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr; + + /* + * add the station to the known list before transmitting the + * authentication response. this way it won't get de-authed by FW + * when transmitting too soon. + */ + hdr = (struct ieee80211_hdr *)(skb->data + + sizeof(struct wl1271_tx_hw_descr)); + if (ieee80211_is_auth(hdr->frame_control)) + wl1271_acx_set_inconnection_sta(wl, hdr->addr1); +} + +static void wl1271_tx_regulate_link(struct wl1271 *wl, + struct wl12xx_vif *wlvif, + u8 hlid) +{ + bool fw_ps, single_sta; + u8 tx_pkts; + + if (WARN_ON(!test_bit(hlid, wlvif->links_map))) + return; + + fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); + tx_pkts = wl->links[hlid].allocated_pkts; + single_sta = (wl->active_sta_count == 1); + + /* + * if in FW PS and there is enough data in FW we can put the link + * into high-level PS and clean out its TX queues. + * Make an exception if this is the only connected station. In this + * case FW-memory congestion is not a problem. + */ + if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) + wl12xx_ps_link_start(wl, wlvif, hlid, true); +} + +bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) +{ + return wl->dummy_packet == skb; +} + +u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif, + struct sk_buff *skb) +{ + struct ieee80211_tx_info *control = IEEE80211_SKB_CB(skb); + + if (control->control.sta) { + struct wl1271_station *wl_sta; + + wl_sta = (struct wl1271_station *) + control->control.sta->drv_priv; + return wl_sta->hlid; + } else { + struct ieee80211_hdr *hdr; + + if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) + return wl->system_hlid; + + hdr = (struct ieee80211_hdr *)skb->data; + if (ieee80211_is_mgmt(hdr->frame_control)) + return wlvif->ap.global_hlid; + else + return wlvif->ap.bcast_hlid; + } +} + +u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif, + struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + if (!wlvif || wl12xx_is_dummy_packet(wl, skb)) + return wl->system_hlid; + + if (wlvif->bss_type == BSS_TYPE_AP_BSS) + return wl12xx_tx_get_hlid_ap(wl, wlvif, skb); + + if ((test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) || + test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags)) && + !ieee80211_is_auth(hdr->frame_control) && + !ieee80211_is_assoc_req(hdr->frame_control)) + return wlvif->sta.hlid; + else + return wlvif->dev_hlid; +} + +unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl, + unsigned int packet_length) +{ + if (wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN) + return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE); + else + return ALIGN(packet_length, WL1271_TX_ALIGN_TO); +} +EXPORT_SYMBOL(wlcore_calc_packet_alignment); + +static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif, + struct sk_buff *skb, u32 extra, u32 buf_offset, + u8 hlid) +{ + struct wl1271_tx_hw_descr *desc; + u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; + u32 total_blocks; + int id, ret = -EBUSY, ac; + u32 spare_blocks = wl->normal_tx_spare; + bool is_dummy = false; + + if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) + return -EAGAIN; + + /* allocate free identifier for the packet */ + id = wl1271_alloc_tx_id(wl, skb); + if (id < 0) + return id; + + if (unlikely(wl12xx_is_dummy_packet(wl, skb))) + is_dummy = true; + else if (wlvif->is_gem) + spare_blocks = wl->gem_tx_spare; + + total_blocks = wlcore_hw_calc_tx_blocks(wl, total_len, spare_blocks); + + if (total_blocks <= wl->tx_blocks_available) { + desc = (struct wl1271_tx_hw_descr *)skb_push( + skb, total_len - skb->len); + + wlcore_hw_set_tx_desc_blocks(wl, desc, total_blocks, + spare_blocks); + + desc->id = id; + + wl->tx_blocks_available -= total_blocks; + wl->tx_allocated_blocks += total_blocks; + + /* If the FW was empty before, arm the Tx watchdog */ + if (wl->tx_allocated_blocks == total_blocks) + wl12xx_rearm_tx_watchdog_locked(wl); + + ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); + wl->tx_allocated_pkts[ac]++; + + if (!is_dummy && wlvif && + wlvif->bss_type == BSS_TYPE_AP_BSS && + test_bit(hlid, wlvif->ap.sta_hlid_map)) + wl->links[hlid].allocated_pkts++; + + ret = 0; + + wl1271_debug(DEBUG_TX, + "tx_allocate: size: %d, blocks: %d, id: %d", + total_len, total_blocks, id); + } else { + wl1271_free_tx_id(wl, id); + } + + return ret; +} + +static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif, + struct sk_buff *skb, u32 extra, + struct ieee80211_tx_info *control, u8 hlid) +{ + struct timespec ts; + struct wl1271_tx_hw_descr *desc; + int ac, rate_idx; + s64 hosttime; + u16 tx_attr = 0; + __le16 frame_control; + struct ieee80211_hdr *hdr; + u8 *frame_start; + bool is_dummy; + + desc = (struct wl1271_tx_hw_descr *) skb->data; + frame_start = (u8 *)(desc + 1); + hdr = (struct ieee80211_hdr *)(frame_start + extra); + frame_control = hdr->frame_control; + + /* relocate space for security header */ + if (extra) { + int hdrlen = ieee80211_hdrlen(frame_control); + memmove(frame_start, hdr, hdrlen); + } + + /* configure packet life time */ + getnstimeofday(&ts); + hosttime = (timespec_to_ns(&ts) >> 10); + desc->start_time = cpu_to_le32(hosttime - wl->time_offset); + + is_dummy = wl12xx_is_dummy_packet(wl, skb); + if (is_dummy || !wlvif || wlvif->bss_type != BSS_TYPE_AP_BSS) + desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU); + else + desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU); + + /* queue */ + ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); + desc->tid = skb->priority; + + if (is_dummy) { + /* + * FW expects the dummy packet to have an invalid session id - + * any session id that is different than the one set in the join + */ + tx_attr = (SESSION_COUNTER_INVALID << + TX_HW_ATTR_OFST_SESSION_COUNTER) & + TX_HW_ATTR_SESSION_COUNTER; + + tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ; + } else if (wlvif) { + /* configure the tx attributes */ + tx_attr = wlvif->session_counter << + TX_HW_ATTR_OFST_SESSION_COUNTER; + } + + desc->hlid = hlid; + if (is_dummy || !wlvif) + rate_idx = 0; + else if (wlvif->bss_type != BSS_TYPE_AP_BSS) { + /* if the packets are destined for AP (have a STA entry) + send them with AP rate policies, otherwise use default + basic rates */ + if (control->flags & IEEE80211_TX_CTL_NO_CCK_RATE) + rate_idx = wlvif->sta.p2p_rate_idx; + else if (control->control.sta) + rate_idx = wlvif->sta.ap_rate_idx; + else + rate_idx = wlvif->sta.basic_rate_idx; + } else { + if (hlid == wlvif->ap.global_hlid) + rate_idx = wlvif->ap.mgmt_rate_idx; + else if (hlid == wlvif->ap.bcast_hlid) + rate_idx = wlvif->ap.bcast_rate_idx; + else + rate_idx = wlvif->ap.ucast_rate_idx[ac]; + } + + tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY; + + /* for WEP shared auth - no fw encryption is needed */ + if (ieee80211_is_auth(frame_control) && + ieee80211_has_protected(frame_control)) + tx_attr |= TX_HW_ATTR_HOST_ENCRYPT; + + desc->reserved = 0; + desc->tx_attr = cpu_to_le16(tx_attr); + + wlcore_hw_set_tx_desc_data_len(wl, desc, skb); +} + +/* caller must hold wl->mutex */ +static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif, + struct sk_buff *skb, u32 buf_offset) +{ + struct ieee80211_tx_info *info; + u32 extra = 0; + int ret = 0; + u32 total_len; + u8 hlid; + bool is_dummy; + + if (!skb) + return -EINVAL; + + info = IEEE80211_SKB_CB(skb); + + /* TODO: handle dummy packets on multi-vifs */ + is_dummy = wl12xx_is_dummy_packet(wl, skb); + + if (info->control.hw_key && + info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) + extra = WL1271_EXTRA_SPACE_TKIP; + + if (info->control.hw_key) { + bool is_wep; + u8 idx = info->control.hw_key->hw_key_idx; + u32 cipher = info->control.hw_key->cipher; + + is_wep = (cipher == WLAN_CIPHER_SUITE_WEP40) || + (cipher == WLAN_CIPHER_SUITE_WEP104); + + if (unlikely(is_wep && wlvif->default_key != idx)) { + ret = wl1271_set_default_wep_key(wl, wlvif, idx); + if (ret < 0) + return ret; + wlvif->default_key = idx; + } + } + hlid = wl12xx_tx_get_hlid(wl, wlvif, skb); + if (hlid == WL12XX_INVALID_LINK_ID) { + wl1271_error("invalid hlid. dropping skb 0x%p", skb); + return -EINVAL; + } + + ret = wl1271_tx_allocate(wl, wlvif, skb, extra, buf_offset, hlid); + if (ret < 0) + return ret; + + wl1271_tx_fill_hdr(wl, wlvif, skb, extra, info, hlid); + + if (!is_dummy && wlvif && wlvif->bss_type == BSS_TYPE_AP_BSS) { + wl1271_tx_ap_update_inconnection_sta(wl, skb); + wl1271_tx_regulate_link(wl, wlvif, hlid); + } + + /* + * The length of each packet is stored in terms of + * words. Thus, we must pad the skb data to make sure its + * length is aligned. The number of padding bytes is computed + * and set in wl1271_tx_fill_hdr. + * In special cases, we want to align to a specific block size + * (eg. for wl128x with SDIO we align to 256). + */ + total_len = wlcore_calc_packet_alignment(wl, skb->len); + + memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len); + memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len); + + /* Revert side effects in the dummy packet skb, so it can be reused */ + if (is_dummy) + skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); + + return total_len; +} + +u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set, + enum ieee80211_band rate_band) +{ + struct ieee80211_supported_band *band; + u32 enabled_rates = 0; + int bit; + + band = wl->hw->wiphy->bands[rate_band]; + for (bit = 0; bit < band->n_bitrates; bit++) { + if (rate_set & 0x1) + enabled_rates |= band->bitrates[bit].hw_value; + rate_set >>= 1; + } + + /* MCS rates indication are on bits 16 - 23 */ + rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates; + + for (bit = 0; bit < 8; bit++) { + if (rate_set & 0x1) + enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit); + rate_set >>= 1; + } + + return enabled_rates; +} + +void wl1271_handle_tx_low_watermark(struct wl1271 *wl) +{ + unsigned long flags; + int i; + + for (i = 0; i < NUM_TX_QUEUES; i++) { + if (test_bit(i, &wl->stopped_queues_map) && + wl->tx_queue_count[i] <= WL1271_TX_QUEUE_LOW_WATERMARK) { + /* firmware buffer has space, restart queues */ + spin_lock_irqsave(&wl->wl_lock, flags); + ieee80211_wake_queue(wl->hw, + wl1271_tx_get_mac80211_queue(i)); + clear_bit(i, &wl->stopped_queues_map); + spin_unlock_irqrestore(&wl->wl_lock, flags); + } + } +} + +static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl, + struct sk_buff_head *queues) +{ + int i, q = -1, ac; + u32 min_pkts = 0xffffffff; + + /* + * Find a non-empty ac where: + * 1. There are packets to transmit + * 2. The FW has the least allocated blocks + * + * We prioritize the ACs according to VO>VI>BE>BK + */ + for (i = 0; i < NUM_TX_QUEUES; i++) { + ac = wl1271_tx_get_queue(i); + if (!skb_queue_empty(&queues[ac]) && + (wl->tx_allocated_pkts[ac] < min_pkts)) { + q = ac; + min_pkts = wl->tx_allocated_pkts[q]; + } + } + + if (q == -1) + return NULL; + + return &queues[q]; +} + +static struct sk_buff *wl12xx_lnk_skb_dequeue(struct wl1271 *wl, + struct wl1271_link *lnk) +{ + struct sk_buff *skb; + unsigned long flags; + struct sk_buff_head *queue; + + queue = wl1271_select_queue(wl, lnk->tx_queue); + if (!queue) + return NULL; + + skb = skb_dequeue(queue); + if (skb) { + int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); + spin_lock_irqsave(&wl->wl_lock, flags); + WARN_ON_ONCE(wl->tx_queue_count[q] <= 0); + wl->tx_queue_count[q]--; + spin_unlock_irqrestore(&wl->wl_lock, flags); + } + + return skb; +} + +static struct sk_buff *wl12xx_vif_skb_dequeue(struct wl1271 *wl, + struct wl12xx_vif *wlvif) +{ + struct sk_buff *skb = NULL; + int i, h, start_hlid; + + /* start from the link after the last one */ + start_hlid = (wlvif->last_tx_hlid + 1) % WL12XX_MAX_LINKS; + + /* dequeue according to AC, round robin on each link */ + for (i = 0; i < WL12XX_MAX_LINKS; i++) { + h = (start_hlid + i) % WL12XX_MAX_LINKS; + + /* only consider connected stations */ + if (!test_bit(h, wlvif->links_map)) + continue; + + skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[h]); + if (!skb) + continue; + + wlvif->last_tx_hlid = h; + break; + } + + if (!skb) + wlvif->last_tx_hlid = 0; + + return skb; +} + +static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) +{ + unsigned long flags; + struct wl12xx_vif *wlvif = wl->last_wlvif; + struct sk_buff *skb = NULL; + + /* continue from last wlvif (round robin) */ + if (wlvif) { + wl12xx_for_each_wlvif_continue(wl, wlvif) { + skb = wl12xx_vif_skb_dequeue(wl, wlvif); + if (skb) { + wl->last_wlvif = wlvif; + break; + } + } + } + + /* dequeue from the system HLID before the restarting wlvif list */ + if (!skb) + skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[wl->system_hlid]); + + /* do a new pass over the wlvif list */ + if (!skb) { + wl12xx_for_each_wlvif(wl, wlvif) { + skb = wl12xx_vif_skb_dequeue(wl, wlvif); + if (skb) { + wl->last_wlvif = wlvif; + break; + } + + /* + * No need to continue after last_wlvif. The previous + * pass should have found it. + */ + if (wlvif == wl->last_wlvif) + break; + } + } + + if (!skb && + test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) { + int q; + + skb = wl->dummy_packet; + q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); + spin_lock_irqsave(&wl->wl_lock, flags); + WARN_ON_ONCE(wl->tx_queue_count[q] <= 0); + wl->tx_queue_count[q]--; + spin_unlock_irqrestore(&wl->wl_lock, flags); + } + + return skb; +} + +static void wl1271_skb_queue_head(struct wl1271 *wl, struct wl12xx_vif *wlvif, + struct sk_buff *skb) +{ + unsigned long flags; + int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); + + if (wl12xx_is_dummy_packet(wl, skb)) { + set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); + } else { + u8 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb); + skb_queue_head(&wl->links[hlid].tx_queue[q], skb); + + /* make sure we dequeue the same packet next time */ + wlvif->last_tx_hlid = (hlid + WL12XX_MAX_LINKS - 1) % + WL12XX_MAX_LINKS; + } + + spin_lock_irqsave(&wl->wl_lock, flags); + wl->tx_queue_count[q]++; + spin_unlock_irqrestore(&wl->wl_lock, flags); +} + +static bool wl1271_tx_is_data_present(struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); + + return ieee80211_is_data_present(hdr->frame_control); +} + +void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids) +{ + struct wl12xx_vif *wlvif; + u32 timeout; + u8 hlid; + + if (!wl->conf.rx_streaming.interval) + return; + + if (!wl->conf.rx_streaming.always && + !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)) + return; + + timeout = wl->conf.rx_streaming.duration; + wl12xx_for_each_wlvif_sta(wl, wlvif) { + bool found = false; + for_each_set_bit(hlid, active_hlids, WL12XX_MAX_LINKS) { + if (test_bit(hlid, wlvif->links_map)) { + found = true; + break; + } + } + + if (!found) + continue; + + /* enable rx streaming */ + if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags)) + ieee80211_queue_work(wl->hw, + &wlvif->rx_streaming_enable_work); + + mod_timer(&wlvif->rx_streaming_timer, + jiffies + msecs_to_jiffies(timeout)); + } +} + +void wl1271_tx_work_locked(struct wl1271 *wl) +{ + struct wl12xx_vif *wlvif; + struct sk_buff *skb; + struct wl1271_tx_hw_descr *desc; + u32 buf_offset = 0; + bool sent_packets = false; + unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0}; + int ret; + + if (unlikely(wl->state == WL1271_STATE_OFF)) + return; + + while ((skb = wl1271_skb_dequeue(wl))) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + bool has_data = false; + + wlvif = NULL; + if (!wl12xx_is_dummy_packet(wl, skb) && info->control.vif) + wlvif = wl12xx_vif_to_data(info->control.vif); + + has_data = wlvif && wl1271_tx_is_data_present(skb); + ret = wl1271_prepare_tx_frame(wl, wlvif, skb, buf_offset); + if (ret == -EAGAIN) { + /* + * Aggregation buffer is full. + * Flush buffer and try again. + */ + wl1271_skb_queue_head(wl, wlvif, skb); + wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf, + buf_offset, true); + sent_packets = true; + buf_offset = 0; + continue; + } else if (ret == -EBUSY) { + /* + * Firmware buffer is full. + * Queue back last skb, and stop aggregating. + */ + wl1271_skb_queue_head(wl, wlvif, skb); + /* No work left, avoid scheduling redundant tx work */ + set_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); + goto out_ack; + } else if (ret < 0) { + if (wl12xx_is_dummy_packet(wl, skb)) + /* + * fw still expects dummy packet, + * so re-enqueue it + */ + wl1271_skb_queue_head(wl, wlvif, skb); + else + ieee80211_free_txskb(wl->hw, skb); + goto out_ack; + } + buf_offset += ret; + wl->tx_packets_count++; + if (has_data) { + desc = (struct wl1271_tx_hw_descr *) skb->data; + __set_bit(desc->hlid, active_hlids); + } + } + +out_ack: + if (buf_offset) { + wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf, + buf_offset, true); + sent_packets = true; + } + if (sent_packets) { + /* + * Interrupt the firmware with the new packets. This is only + * required for older hardware revisions + */ + if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION) + wl1271_write32(wl, WL12XX_HOST_WR_ACCESS, + wl->tx_packets_count); + + wl1271_handle_tx_low_watermark(wl); + } + wl12xx_rearm_rx_streaming(wl, active_hlids); +} + +void wl1271_tx_work(struct work_struct *work) +{ + struct wl1271 *wl = container_of(work, struct wl1271, tx_work); + int ret; + + mutex_lock(&wl->mutex); + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + wl1271_tx_work_locked(wl); + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); +} + +static u8 wl1271_tx_get_rate_flags(u8 rate_class_index) +{ + u8 flags = 0; + + /* + * TODO: use wl12xx constants when this code is moved to wl12xx, as + * only it uses Tx-completion. + */ + if (rate_class_index <= 8) + flags |= IEEE80211_TX_RC_MCS; + + /* + * TODO: use wl12xx constants when this code is moved to wl12xx, as + * only it uses Tx-completion. + */ + if (rate_class_index == 0) + flags |= IEEE80211_TX_RC_SHORT_GI; + + return flags; +} + +static void wl1271_tx_complete_packet(struct wl1271 *wl, + struct wl1271_tx_hw_res_descr *result) +{ + struct ieee80211_tx_info *info; + struct ieee80211_vif *vif; + struct wl12xx_vif *wlvif; + struct sk_buff *skb; + int id = result->id; + int rate = -1; + u8 rate_flags = 0; + u8 retries = 0; + + /* check for id legality */ + if (unlikely(id >= wl->num_tx_desc || wl->tx_frames[id] == NULL)) { + wl1271_warning("TX result illegal id: %d", id); + return; + } + + skb = wl->tx_frames[id]; + info = IEEE80211_SKB_CB(skb); + + if (wl12xx_is_dummy_packet(wl, skb)) { + wl1271_free_tx_id(wl, id); + return; + } + + /* info->control is valid as long as we don't update info->status */ + vif = info->control.vif; + wlvif = wl12xx_vif_to_data(vif); + + /* update the TX status info */ + if (result->status == TX_SUCCESS) { + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) + info->flags |= IEEE80211_TX_STAT_ACK; + rate = wlcore_rate_to_idx(wl, result->rate_class_index, + wlvif->band); + rate_flags = wl1271_tx_get_rate_flags(result->rate_class_index); + retries = result->ack_failures; + } else if (result->status == TX_RETRY_EXCEEDED) { + wl->stats.excessive_retries++; + retries = result->ack_failures; + } + + info->status.rates[0].idx = rate; + info->status.rates[0].count = retries; + info->status.rates[0].flags = rate_flags; + info->status.ack_signal = -1; + + wl->stats.retry_count += result->ack_failures; + + /* + * update sequence number only when relevant, i.e. only in + * sessions of TKIP, AES and GEM (not in open or WEP sessions) + */ + if (info->control.hw_key && + (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP || + info->control.hw_key->cipher == WLAN_CIPHER_SUITE_CCMP || + info->control.hw_key->cipher == WL1271_CIPHER_SUITE_GEM)) { + u8 fw_lsb = result->tx_security_sequence_number_lsb; + u8 cur_lsb = wlvif->tx_security_last_seq_lsb; + + /* + * update security sequence number, taking care of potential + * wrap-around + */ + wlvif->tx_security_seq += (fw_lsb - cur_lsb) & 0xff; + wlvif->tx_security_last_seq_lsb = fw_lsb; + } + + /* remove private header from packet */ + skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); + + /* remove TKIP header space if present */ + if (info->control.hw_key && + info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { + int hdrlen = ieee80211_get_hdrlen_from_skb(skb); + memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, skb->data, + hdrlen); + skb_pull(skb, WL1271_EXTRA_SPACE_TKIP); + } + + wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" + " status 0x%x", + result->id, skb, result->ack_failures, + result->rate_class_index, result->status); + + /* return the packet to the stack */ + skb_queue_tail(&wl->deferred_tx_queue, skb); + queue_work(wl->freezable_wq, &wl->netstack_work); + wl1271_free_tx_id(wl, result->id); +} + +/* Called upon reception of a TX complete interrupt */ +void wl1271_tx_complete(struct wl1271 *wl) +{ + struct wl1271_acx_mem_map *memmap = + (struct wl1271_acx_mem_map *)wl->target_mem_map; + u32 count, fw_counter; + u32 i; + + /* read the tx results from the chipset */ + wl1271_read(wl, le32_to_cpu(memmap->tx_result), + wl->tx_res_if, sizeof(*wl->tx_res_if), false); + fw_counter = le32_to_cpu(wl->tx_res_if->tx_result_fw_counter); + + /* write host counter to chipset (to ack) */ + wl1271_write32(wl, le32_to_cpu(memmap->tx_result) + + offsetof(struct wl1271_tx_hw_res_if, + tx_result_host_counter), fw_counter); + + count = fw_counter - wl->tx_results_count; + wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); + + /* verify that the result buffer is not getting overrun */ + if (unlikely(count > TX_HW_RESULT_QUEUE_LEN)) + wl1271_warning("TX result overflow from chipset: %d", count); + + /* process the results */ + for (i = 0; i < count; i++) { + struct wl1271_tx_hw_res_descr *result; + u8 offset = wl->tx_results_count & TX_HW_RESULT_QUEUE_LEN_MASK; + + /* process the packet */ + result = &(wl->tx_res_if->tx_results_queue[offset]); + wl1271_tx_complete_packet(wl, result); + + wl->tx_results_count++; + } +} +EXPORT_SYMBOL(wl1271_tx_complete); + +void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) +{ + struct sk_buff *skb; + int i; + unsigned long flags; + struct ieee80211_tx_info *info; + int total[NUM_TX_QUEUES]; + + for (i = 0; i < NUM_TX_QUEUES; i++) { + total[i] = 0; + while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { + wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb); + + if (!wl12xx_is_dummy_packet(wl, skb)) { + info = IEEE80211_SKB_CB(skb); + info->status.rates[0].idx = -1; + info->status.rates[0].count = 0; + ieee80211_tx_status_ni(wl->hw, skb); + } + + total[i]++; + } + } + + spin_lock_irqsave(&wl->wl_lock, flags); + for (i = 0; i < NUM_TX_QUEUES; i++) + wl->tx_queue_count[i] -= total[i]; + spin_unlock_irqrestore(&wl->wl_lock, flags); + + wl1271_handle_tx_low_watermark(wl); +} + +/* caller must hold wl->mutex and TX must be stopped */ +void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif) +{ + int i; + + /* TX failure */ + for_each_set_bit(i, wlvif->links_map, WL12XX_MAX_LINKS) { + if (wlvif->bss_type == BSS_TYPE_AP_BSS) + wl1271_free_sta(wl, wlvif, i); + else + wlvif->sta.ba_rx_bitmap = 0; + + wl->links[i].allocated_pkts = 0; + wl->links[i].prev_freed_pkts = 0; + } + wlvif->last_tx_hlid = 0; + +} +/* caller must hold wl->mutex and TX must be stopped */ +void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues) +{ + int i; + struct sk_buff *skb; + struct ieee80211_tx_info *info; + + /* only reset the queues if something bad happened */ + if (WARN_ON_ONCE(wl1271_tx_total_queue_count(wl) != 0)) { + for (i = 0; i < WL12XX_MAX_LINKS; i++) + wl1271_tx_reset_link_queues(wl, i); + + for (i = 0; i < NUM_TX_QUEUES; i++) + wl->tx_queue_count[i] = 0; + } + + wl->stopped_queues_map = 0; + + /* + * Make sure the driver is at a consistent state, in case this + * function is called from a context other than interface removal. + * This call will always wake the TX queues. + */ + if (reset_tx_queues) + wl1271_handle_tx_low_watermark(wl); + + for (i = 0; i < wl->num_tx_desc; i++) { + if (wl->tx_frames[i] == NULL) + continue; + + skb = wl->tx_frames[i]; + wl1271_free_tx_id(wl, i); + wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); + + if (!wl12xx_is_dummy_packet(wl, skb)) { + /* + * Remove private headers before passing the skb to + * mac80211 + */ + info = IEEE80211_SKB_CB(skb); + skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); + if (info->control.hw_key && + info->control.hw_key->cipher == + WLAN_CIPHER_SUITE_TKIP) { + int hdrlen = ieee80211_get_hdrlen_from_skb(skb); + memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, + skb->data, hdrlen); + skb_pull(skb, WL1271_EXTRA_SPACE_TKIP); + } + + info->status.rates[0].idx = -1; + info->status.rates[0].count = 0; + + ieee80211_tx_status_ni(wl->hw, skb); + } + } +} + +#define WL1271_TX_FLUSH_TIMEOUT 500000 + +/* caller must *NOT* hold wl->mutex */ +void wl1271_tx_flush(struct wl1271 *wl) +{ + unsigned long timeout; + int i; + timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT); + + while (!time_after(jiffies, timeout)) { + mutex_lock(&wl->mutex); + wl1271_debug(DEBUG_TX, "flushing tx buffer: %d %d", + wl->tx_frames_cnt, + wl1271_tx_total_queue_count(wl)); + if ((wl->tx_frames_cnt == 0) && + (wl1271_tx_total_queue_count(wl) == 0)) { + mutex_unlock(&wl->mutex); + return; + } + mutex_unlock(&wl->mutex); + msleep(1); + } + + wl1271_warning("Unable to flush all TX buffers, timed out."); + + /* forcibly flush all Tx buffers on our queues */ + mutex_lock(&wl->mutex); + for (i = 0; i < WL12XX_MAX_LINKS; i++) + wl1271_tx_reset_link_queues(wl, i); + mutex_unlock(&wl->mutex); +} + +u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set) +{ + if (WARN_ON(!rate_set)) + return 0; + + return BIT(__ffs(rate_set)); +} diff --git a/trunk/drivers/net/wireless/wl12xx/tx.h b/trunk/drivers/net/wireless/ti/wlcore/tx.h similarity index 97% rename from trunk/drivers/net/wireless/wl12xx/tx.h rename to trunk/drivers/net/wireless/ti/wlcore/tx.h index 5cf8c32d40d1..2fd6e5dc6f75 100644 --- a/trunk/drivers/net/wireless/wl12xx/tx.h +++ b/trunk/drivers/net/wireless/ti/wlcore/tx.h @@ -25,9 +25,6 @@ #ifndef __TX_H__ #define __TX_H__ -#define TX_HW_BLOCK_SPARE_DEFAULT 1 -#define TX_HW_BLOCK_SIZE 252 - #define TX_HW_MGMT_PKT_LIFETIME_TU 2000 #define TX_HW_AP_MODE_PKT_LIFETIME_TU 8000 @@ -212,7 +209,7 @@ void wl1271_tx_complete(struct wl1271 *wl); void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif); void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues); void wl1271_tx_flush(struct wl1271 *wl); -u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); +u8 wlcore_rate_to_idx(struct wl1271 *wl, u8 rate, enum ieee80211_band band); u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set, enum ieee80211_band rate_band); u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set); @@ -224,6 +221,8 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid); void wl1271_handle_tx_low_watermark(struct wl1271 *wl); bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb); void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids); +unsigned int wlcore_calc_packet_alignment(struct wl1271 *wl, + unsigned int packet_length); /* from main.c */ void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid); diff --git a/trunk/drivers/net/wireless/ti/wlcore/wl12xx.h b/trunk/drivers/net/wireless/ti/wlcore/wl12xx.h new file mode 100644 index 000000000000..a9b220c43e54 --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wlcore/wl12xx.h @@ -0,0 +1,466 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. + * Copyright (C) 2008-2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL12XX_H__ +#define __WL12XX_H__ + +#include +#include +#include +#include +#include +#include + +#include "conf.h" +#include "ini.h" + +#define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-4-mr.bin" +#define WL127X_FW_NAME_SINGLE "ti-connectivity/wl127x-fw-4-sr.bin" + +#define WL128X_FW_NAME_MULTI "ti-connectivity/wl128x-fw-4-mr.bin" +#define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-4-sr.bin" + +#define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-4-plt.bin" +#define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-4-plt.bin" + +/* + * wl127x and wl128x are using the same NVS file name. However, the + * ini parameters between them are different. The driver validates + * the correct NVS size in wl1271_boot_upload_nvs(). + */ +#define WL12XX_NVS_NAME "ti-connectivity/wl1271-nvs.bin" + +#define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff)) +#define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff)) +#define WL1271_TX_SQN_POST_RECOVERY_PADDING 0xff + +#define WL1271_CIPHER_SUITE_GEM 0x00147201 + +#define WL1271_BUSY_WORD_CNT 1 +#define WL1271_BUSY_WORD_LEN (WL1271_BUSY_WORD_CNT * sizeof(u32)) + +#define WL1271_ELP_HW_STATE_ASLEEP 0 +#define WL1271_ELP_HW_STATE_IRQ 1 + +#define WL1271_DEFAULT_BEACON_INT 100 +#define WL1271_DEFAULT_DTIM_PERIOD 1 + +#define WL12XX_MAX_ROLES 4 +#define WL12XX_MAX_LINKS 12 +#define WL12XX_INVALID_ROLE_ID 0xff +#define WL12XX_INVALID_LINK_ID 0xff + +#define WL12XX_MAX_RATE_POLICIES 16 + +/* Defined by FW as 0. Will not be freed or allocated. */ +#define WL12XX_SYSTEM_HLID 0 + +/* + * When in AP-mode, we allow (at least) this number of packets + * to be transmitted to FW for a STA in PS-mode. Only when packets are + * present in the FW buffers it will wake the sleeping STA. We want to put + * enough packets for the driver to transmit all of its buffered data before + * the STA goes to sleep again. But we don't want to take too much memory + * as it might hurt the throughput of active STAs. + */ +#define WL1271_PS_STA_MAX_PACKETS 2 + +#define WL1271_AP_BSS_INDEX 0 +#define WL1271_AP_DEF_BEACON_EXP 20 + +#define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE) + +enum wl1271_state { + WL1271_STATE_OFF, + WL1271_STATE_ON, +}; + +enum wl12xx_fw_type { + WL12XX_FW_TYPE_NONE, + WL12XX_FW_TYPE_NORMAL, + WL12XX_FW_TYPE_MULTI, + WL12XX_FW_TYPE_PLT, +}; + +struct wl1271; + +enum { + FW_VER_CHIP, + FW_VER_IF_TYPE, + FW_VER_MAJOR, + FW_VER_SUBTYPE, + FW_VER_MINOR, + + NUM_FW_VER +}; + +#define FW_VER_CHIP_WL127X 6 +#define FW_VER_CHIP_WL128X 7 + +#define FW_VER_IF_TYPE_STA 1 +#define FW_VER_IF_TYPE_AP 2 + +#define FW_VER_MINOR_1_SPARE_STA_MIN 58 +#define FW_VER_MINOR_1_SPARE_AP_MIN 47 + +#define FW_VER_MINOR_FWLOG_STA_MIN 70 + +struct wl1271_chip { + u32 id; + char fw_ver_str[ETHTOOL_BUSINFO_LEN]; + unsigned int fw_ver[NUM_FW_VER]; +}; + +struct wl1271_stats { + struct acx_statistics *fw_stats; + unsigned long fw_stats_update; + + unsigned int retry_count; + unsigned int excessive_retries; +}; + +#define NUM_TX_QUEUES 4 +#define NUM_RX_PKT_DESC 8 + +#define AP_MAX_STATIONS 8 + +struct wl_fw_packet_counters { + /* Cumulative counter of released packets per AC */ + u8 tx_released_pkts[NUM_TX_QUEUES]; + + /* Cumulative counter of freed packets per HLID */ + u8 tx_lnk_free_pkts[WL12XX_MAX_LINKS]; + + /* Cumulative counter of released Voice memory blocks */ + u8 tx_voice_released_blks; + + u8 padding[3]; +} __packed; + +/* FW status registers */ +struct wl_fw_status { + __le32 intr; + u8 fw_rx_counter; + u8 drv_rx_counter; + u8 reserved; + u8 tx_results_counter; + __le32 rx_pkt_descs[NUM_RX_PKT_DESC]; + __le32 fw_localtime; + + /* + * A bitmap (where each bit represents a single HLID) + * to indicate if the station is in PS mode. + */ + __le32 link_ps_bitmap; + + /* + * A bitmap (where each bit represents a single HLID) to indicate + * if the station is in Fast mode + */ + __le32 link_fast_bitmap; + + /* Cumulative counter of total released mem blocks since FW-reset */ + __le32 total_released_blks; + + /* Size (in Memory Blocks) of TX pool */ + __le32 tx_total; + + struct wl_fw_packet_counters counters; + + __le32 log_start_addr; + + /* Private status to be used by the lower drivers */ + u8 priv[0]; +} __packed; + +struct wl1271_rx_mem_pool_addr { + u32 addr; + u32 addr_extra; +}; + +#define WL1271_MAX_CHANNELS 64 +struct wl1271_scan { + struct cfg80211_scan_request *req; + unsigned long scanned_ch[BITS_TO_LONGS(WL1271_MAX_CHANNELS)]; + bool failed; + u8 state; + u8 ssid[IEEE80211_MAX_SSID_LEN+1]; + size_t ssid_len; +}; + +struct wl1271_if_operations { + void (*read)(struct device *child, int addr, void *buf, size_t len, + bool fixed); + void (*write)(struct device *child, int addr, void *buf, size_t len, + bool fixed); + void (*reset)(struct device *child); + void (*init)(struct device *child); + int (*power)(struct device *child, bool enable); + void (*set_block_size) (struct device *child, unsigned int blksz); +}; + +#define MAX_NUM_KEYS 14 +#define MAX_KEY_SIZE 32 + +struct wl1271_ap_key { + u8 id; + u8 key_type; + u8 key_size; + u8 key[MAX_KEY_SIZE]; + u8 hlid; + u32 tx_seq_32; + u16 tx_seq_16; +}; + +enum wl12xx_flags { + WL1271_FLAG_GPIO_POWER, + WL1271_FLAG_TX_QUEUE_STOPPED, + WL1271_FLAG_TX_PENDING, + WL1271_FLAG_IN_ELP, + WL1271_FLAG_ELP_REQUESTED, + WL1271_FLAG_IRQ_RUNNING, + WL1271_FLAG_FW_TX_BUSY, + WL1271_FLAG_DUMMY_PACKET_PENDING, + WL1271_FLAG_SUSPENDED, + WL1271_FLAG_PENDING_WORK, + WL1271_FLAG_SOFT_GEMINI, + WL1271_FLAG_RECOVERY_IN_PROGRESS, + WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, + WL1271_FLAG_INTENDED_FW_RECOVERY, +}; + +enum wl12xx_vif_flags { + WLVIF_FLAG_INITIALIZED, + WLVIF_FLAG_STA_ASSOCIATED, + WLVIF_FLAG_STA_AUTHORIZED, + WLVIF_FLAG_IBSS_JOINED, + WLVIF_FLAG_AP_STARTED, + WLVIF_FLAG_IN_PS, + WLVIF_FLAG_STA_STATE_SENT, + WLVIF_FLAG_RX_STREAMING_STARTED, + WLVIF_FLAG_PSPOLL_FAILURE, + WLVIF_FLAG_CS_PROGRESS, + WLVIF_FLAG_AP_PROBE_RESP_SET, + WLVIF_FLAG_IN_USE, +}; + +struct wl1271_link { + /* AP-mode - TX queue per AC in link */ + struct sk_buff_head tx_queue[NUM_TX_QUEUES]; + + /* accounting for allocated / freed packets in FW */ + u8 allocated_pkts; + u8 prev_freed_pkts; + + u8 addr[ETH_ALEN]; + + /* bitmap of TIDs where RX BA sessions are active for this link */ + u8 ba_bitmap; +}; + +struct wl1271_station { + u8 hlid; +}; + +struct wl12xx_vif { + struct wl1271 *wl; + struct list_head list; + unsigned long flags; + u8 bss_type; + u8 p2p; /* we are using p2p role */ + u8 role_id; + + /* sta/ibss specific */ + u8 dev_role_id; + u8 dev_hlid; + + union { + struct { + u8 hlid; + u8 ba_rx_bitmap; + + u8 basic_rate_idx; + u8 ap_rate_idx; + u8 p2p_rate_idx; + + bool qos; + } sta; + struct { + u8 global_hlid; + u8 bcast_hlid; + + /* HLIDs bitmap of associated stations */ + unsigned long sta_hlid_map[BITS_TO_LONGS( + WL12XX_MAX_LINKS)]; + + /* recoreded keys - set here before AP startup */ + struct wl1271_ap_key *recorded_keys[MAX_NUM_KEYS]; + + u8 mgmt_rate_idx; + u8 bcast_rate_idx; + u8 ucast_rate_idx[CONF_TX_MAX_AC_COUNT]; + } ap; + }; + + /* the hlid of the last transmitted skb */ + int last_tx_hlid; + + unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)]; + + u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; + u8 ssid_len; + + /* The current band */ + enum ieee80211_band band; + int channel; + + u32 bitrate_masks[IEEE80211_NUM_BANDS]; + u32 basic_rate_set; + + /* + * currently configured rate set: + * bits 0-15 - 802.11abg rates + * bits 16-23 - 802.11n MCS index mask + * support only 1 stream, thus only 8 bits for the MCS rates (0-7). + */ + u32 basic_rate; + u32 rate_set; + + /* probe-req template for the current AP */ + struct sk_buff *probereq; + + /* Beaconing interval (needed for ad-hoc) */ + u32 beacon_int; + + /* Default key (for WEP) */ + u32 default_key; + + /* Our association ID */ + u16 aid; + + /* Session counter for the chipset */ + int session_counter; + + /* retry counter for PSM entries */ + u8 psm_entry_retry; + + /* in dBm */ + int power_level; + + int rssi_thold; + int last_rssi_event; + + /* save the current encryption type for auto-arp config */ + u8 encryption_type; + __be32 ip_addr; + + /* RX BA constraint value */ + bool ba_support; + bool ba_allowed; + + /* Rx Streaming */ + struct work_struct rx_streaming_enable_work; + struct work_struct rx_streaming_disable_work; + struct timer_list rx_streaming_timer; + + /* does the current role use GEM for encryption (AP or STA) */ + bool is_gem; + + /* + * This struct must be last! + * data that has to be saved acrossed reconfigs (e.g. recovery) + * should be declared in this struct. + */ + struct { + u8 persistent[0]; + /* + * Security sequence number + * bits 0-15: lower 16 bits part of sequence number + * bits 16-47: higher 32 bits part of sequence number + * bits 48-63: not in use + */ + u64 tx_security_seq; + + /* 8 bits of the last sequence number in use */ + u8 tx_security_last_seq_lsb; + }; +}; + +static inline struct wl12xx_vif *wl12xx_vif_to_data(struct ieee80211_vif *vif) +{ + return (struct wl12xx_vif *)vif->drv_priv; +} + +static inline +struct ieee80211_vif *wl12xx_wlvif_to_vif(struct wl12xx_vif *wlvif) +{ + return container_of((void *)wlvif, struct ieee80211_vif, drv_priv); +} + +#define wl12xx_for_each_wlvif(wl, wlvif) \ + list_for_each_entry(wlvif, &wl->wlvif_list, list) + +#define wl12xx_for_each_wlvif_continue(wl, wlvif) \ + list_for_each_entry_continue(wlvif, &wl->wlvif_list, list) + +#define wl12xx_for_each_wlvif_bss_type(wl, wlvif, _bss_type) \ + wl12xx_for_each_wlvif(wl, wlvif) \ + if (wlvif->bss_type == _bss_type) + +#define wl12xx_for_each_wlvif_sta(wl, wlvif) \ + wl12xx_for_each_wlvif_bss_type(wl, wlvif, BSS_TYPE_STA_BSS) + +#define wl12xx_for_each_wlvif_ap(wl, wlvif) \ + wl12xx_for_each_wlvif_bss_type(wl, wlvif, BSS_TYPE_AP_BSS) + +int wl1271_plt_start(struct wl1271 *wl); +int wl1271_plt_stop(struct wl1271 *wl); +int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif); +void wl12xx_queue_recovery_work(struct wl1271 *wl); +size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen); + +#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ + +#define SESSION_COUNTER_MAX 6 /* maximum value for the session counter */ +#define SESSION_COUNTER_INVALID 7 /* used with dummy_packet */ + +#define WL1271_DEFAULT_POWER_LEVEL 0 + +#define WL1271_TX_QUEUE_LOW_WATERMARK 32 +#define WL1271_TX_QUEUE_HIGH_WATERMARK 256 + +#define WL1271_DEFERRED_QUEUE_LIMIT 64 + +/* WL1271 needs a 200ms sleep after power on, and a 20ms sleep before power + on in case is has been shut down shortly before */ +#define WL1271_PRE_POWER_ON_SLEEP 20 /* in milliseconds */ +#define WL1271_POWER_ON_SLEEP 200 /* in milliseconds */ + +/* Macros to handle wl1271.sta_rate_set */ +#define HW_BG_RATES_MASK 0xffff +#define HW_HT_RATES_OFFSET 16 + +#define WL12XX_HW_BLOCK_SIZE 256 + +#endif diff --git a/trunk/drivers/net/wireless/wl12xx/wl12xx_80211.h b/trunk/drivers/net/wireless/ti/wlcore/wl12xx_80211.h similarity index 100% rename from trunk/drivers/net/wireless/wl12xx/wl12xx_80211.h rename to trunk/drivers/net/wireless/ti/wlcore/wl12xx_80211.h diff --git a/trunk/drivers/net/wireless/wl12xx/wl12xx_platform_data.c b/trunk/drivers/net/wireless/ti/wlcore/wl12xx_platform_data.c similarity index 100% rename from trunk/drivers/net/wireless/wl12xx/wl12xx_platform_data.c rename to trunk/drivers/net/wireless/ti/wlcore/wl12xx_platform_data.c diff --git a/trunk/drivers/net/wireless/ti/wlcore/wlcore.h b/trunk/drivers/net/wireless/ti/wlcore/wlcore.h new file mode 100644 index 000000000000..39f9fadfebd9 --- /dev/null +++ b/trunk/drivers/net/wireless/ti/wlcore/wlcore.h @@ -0,0 +1,448 @@ +/* + * This file is part of wlcore + * + * Copyright (C) 2011 Texas Instruments 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WLCORE_H__ +#define __WLCORE_H__ + +#include + +#include "wl12xx.h" +#include "event.h" + +/* The maximum number of Tx descriptors in all chip families */ +#define WLCORE_MAX_TX_DESCRIPTORS 32 + +/* forward declaration */ +struct wl1271_tx_hw_descr; +enum wl_rx_buf_align; + +struct wlcore_ops { + int (*identify_chip)(struct wl1271 *wl); + int (*identify_fw)(struct wl1271 *wl); + int (*boot)(struct wl1271 *wl); + void (*trigger_cmd)(struct wl1271 *wl, int cmd_box_addr, + void *buf, size_t len); + void (*ack_event)(struct wl1271 *wl); + u32 (*calc_tx_blocks)(struct wl1271 *wl, u32 len, u32 spare_blks); + void (*set_tx_desc_blocks)(struct wl1271 *wl, + struct wl1271_tx_hw_descr *desc, + u32 blks, u32 spare_blks); + void (*set_tx_desc_data_len)(struct wl1271 *wl, + struct wl1271_tx_hw_descr *desc, + struct sk_buff *skb); + enum wl_rx_buf_align (*get_rx_buf_align)(struct wl1271 *wl, + u32 rx_desc); + void (*prepare_read)(struct wl1271 *wl, u32 rx_desc, u32 len); + u32 (*get_rx_packet_len)(struct wl1271 *wl, void *rx_data, + u32 data_len); + void (*tx_delayed_compl)(struct wl1271 *wl); + void (*tx_immediate_compl)(struct wl1271 *wl); + int (*hw_init)(struct wl1271 *wl); + int (*init_vif)(struct wl1271 *wl, struct wl12xx_vif *wlvif); + u32 (*sta_get_ap_rate_mask)(struct wl1271 *wl, + struct wl12xx_vif *wlvif); + s8 (*get_pg_ver)(struct wl1271 *wl); + void (*get_mac)(struct wl1271 *wl); +}; + +enum wlcore_partitions { + PART_DOWN, + PART_WORK, + PART_BOOT, + PART_DRPW, + PART_TOP_PRCM_ELP_SOC, + PART_PHY_INIT, + + PART_TABLE_LEN, +}; + +struct wlcore_partition { + u32 size; + u32 start; +}; + +struct wlcore_partition_set { + struct wlcore_partition mem; + struct wlcore_partition reg; + struct wlcore_partition mem2; + struct wlcore_partition mem3; +}; + +enum wlcore_registers { + /* register addresses, used with partition translation */ + REG_ECPU_CONTROL, + REG_INTERRUPT_NO_CLEAR, + REG_INTERRUPT_ACK, + REG_COMMAND_MAILBOX_PTR, + REG_EVENT_MAILBOX_PTR, + REG_INTERRUPT_TRIG, + REG_INTERRUPT_MASK, + REG_PC_ON_RECOVERY, + REG_CHIP_ID_B, + REG_CMD_MBOX_ADDRESS, + + /* data access memory addresses, used with partition translation */ + REG_SLV_MEM_DATA, + REG_SLV_REG_DATA, + + /* raw data access memory addresses */ + REG_RAW_FW_STATUS_ADDR, + + REG_TABLE_LEN, +}; + +struct wl1271 { + struct ieee80211_hw *hw; + bool mac80211_registered; + + struct device *dev; + + void *if_priv; + + struct wl1271_if_operations *if_ops; + + void (*set_power)(bool enable); + int irq; + int ref_clock; + + spinlock_t wl_lock; + + enum wl1271_state state; + enum wl12xx_fw_type fw_type; + bool plt; + u8 last_vif_count; + struct mutex mutex; + + unsigned long flags; + + struct wlcore_partition_set curr_part; + + struct wl1271_chip chip; + + int cmd_box_addr; + + u8 *fw; + size_t fw_len; + void *nvs; + size_t nvs_len; + + s8 hw_pg_ver; + + /* address read from the fuse ROM */ + u32 fuse_oui_addr; + u32 fuse_nic_addr; + + /* we have up to 2 MAC addresses */ + struct mac_address addresses[2]; + int channel; + u8 system_hlid; + + unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)]; + unsigned long roles_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)]; + unsigned long roc_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)]; + unsigned long rate_policies_map[ + BITS_TO_LONGS(WL12XX_MAX_RATE_POLICIES)]; + + struct list_head wlvif_list; + + u8 sta_count; + u8 ap_count; + + struct wl1271_acx_mem_map *target_mem_map; + + /* Accounting for allocated / available TX blocks on HW */ + u32 tx_blocks_freed; + u32 tx_blocks_available; + u32 tx_allocated_blocks; + u32 tx_results_count; + + /* Accounting for allocated / available Tx packets in HW */ + u32 tx_pkts_freed[NUM_TX_QUEUES]; + u32 tx_allocated_pkts[NUM_TX_QUEUES]; + + /* Transmitted TX packets counter for chipset interface */ + u32 tx_packets_count; + + /* Time-offset between host and chipset clocks */ + s64 time_offset; + + /* Frames scheduled for transmission, not handled yet */ + int tx_queue_count[NUM_TX_QUEUES]; + long stopped_queues_map; + + /* Frames received, not handled yet by mac80211 */ + struct sk_buff_head deferred_rx_queue; + + /* Frames sent, not returned yet to mac80211 */ + struct sk_buff_head deferred_tx_queue; + + struct work_struct tx_work; + struct workqueue_struct *freezable_wq; + + /* Pending TX frames */ + unsigned long tx_frames_map[BITS_TO_LONGS(WLCORE_MAX_TX_DESCRIPTORS)]; + struct sk_buff *tx_frames[WLCORE_MAX_TX_DESCRIPTORS]; + int tx_frames_cnt; + + /* FW Rx counter */ + u32 rx_counter; + + /* Rx memory pool address */ + struct wl1271_rx_mem_pool_addr rx_mem_pool_addr; + + /* Intermediate buffer, used for packet aggregation */ + u8 *aggr_buf; + + /* Reusable dummy packet template */ + struct sk_buff *dummy_packet; + + /* Network stack work */ + struct work_struct netstack_work; + + /* FW log buffer */ + u8 *fwlog; + + /* Number of valid bytes in the FW log buffer */ + ssize_t fwlog_size; + + /* Sysfs FW log entry readers wait queue */ + wait_queue_head_t fwlog_waitq; + + /* Hardware recovery work */ + struct work_struct recovery_work; + + /* Pointer that holds DMA-friendly block for the mailbox */ + struct event_mailbox *mbox; + + /* The mbox event mask */ + u32 event_mask; + + /* Mailbox pointers */ + u32 mbox_ptr[2]; + + /* Are we currently scanning */ + struct ieee80211_vif *scan_vif; + struct wl1271_scan scan; + struct delayed_work scan_complete_work; + + bool sched_scanning; + + /* The current band */ + enum ieee80211_band band; + + struct completion *elp_compl; + struct delayed_work elp_work; + + /* in dBm */ + int power_level; + + struct wl1271_stats stats; + + __le32 buffer_32; + u32 buffer_cmd; + u32 buffer_busyword[WL1271_BUSY_WORD_CNT]; + + struct wl_fw_status *fw_status; + struct wl1271_tx_hw_res_if *tx_res_if; + + /* Current chipset configuration */ + struct wlcore_conf conf; + + bool sg_enabled; + + bool enable_11a; + + /* Most recently reported noise in dBm */ + s8 noise; + + /* bands supported by this instance of wl12xx */ + struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; + + int tcxo_clock; + + /* + * wowlan trigger was configured during suspend. + * (currently, only "ANY" trigger is supported) + */ + bool wow_enabled; + bool irq_wake_enabled; + + /* + * AP-mode - links indexed by HLID. The global and broadcast links + * are always active. + */ + struct wl1271_link links[WL12XX_MAX_LINKS]; + + /* AP-mode - a bitmap of links currently in PS mode according to FW */ + u32 ap_fw_ps_map; + + /* AP-mode - a bitmap of links currently in PS mode in mac80211 */ + unsigned long ap_ps_map; + + /* Quirks of specific hardware revisions */ + unsigned int quirks; + + /* Platform limitations */ + unsigned int platform_quirks; + + /* number of currently active RX BA sessions */ + int ba_rx_session_count; + + /* AP-mode - number of currently connected stations */ + int active_sta_count; + + /* last wlvif we transmitted from */ + struct wl12xx_vif *last_wlvif; + + /* work to fire when Tx is stuck */ + struct delayed_work tx_watchdog_work; + + struct wlcore_ops *ops; + /* pointer to the lower driver partition table */ + const struct wlcore_partition_set *ptable; + /* pointer to the lower driver register table */ + const int *rtable; + /* name of the firmwares to load - for PLT, single role, multi-role */ + const char *plt_fw_name; + const char *sr_fw_name; + const char *mr_fw_name; + + /* per-chip-family private structure */ + void *priv; + + /* number of TX descriptors the HW supports. */ + u32 num_tx_desc; + + /* spare Tx blocks for normal/GEM operating modes */ + u32 normal_tx_spare; + u32 gem_tx_spare; + + /* translate HW Tx rates to standard rate-indices */ + const u8 **band_rate_to_idx; + + /* size of table for HW rates that can be received from chip */ + u8 hw_tx_rate_tbl_size; + + /* this HW rate and below are considered HT rates for this chip */ + u8 hw_min_ht_rate; + + /* HW HT (11n) capabilities */ + struct ieee80211_sta_ht_cap ht_cap; + + /* size of the private FW status data */ + size_t fw_status_priv_len; +}; + +int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev); +int __devexit wlcore_remove(struct platform_device *pdev); +struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size); +int wlcore_free_hw(struct wl1271 *wl); + +/* Firmware image load chunk size */ +#define CHUNK_SIZE 16384 + +/* Quirks */ + +/* Each RX/TX transaction requires an end-of-transaction transfer */ +#define WLCORE_QUIRK_END_OF_TRANSACTION BIT(0) + +/* wl127x and SPI don't support SDIO block size alignment */ +#define WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN BIT(2) + +/* means aggregated Rx packets are aligned to a SDIO block */ +#define WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN BIT(3) + +/* Older firmwares did not implement the FW logger over bus feature */ +#define WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED BIT(4) + +/* Older firmwares use an old NVS format */ +#define WLCORE_QUIRK_LEGACY_NVS BIT(5) + +/* Some firmwares may not support ELP */ +#define WLCORE_QUIRK_NO_ELP BIT(6) + +/* TODO: move to the lower drivers when all usages are abstracted */ +#define CHIP_ID_1271_PG10 (0x4030101) +#define CHIP_ID_1271_PG20 (0x4030111) +#define CHIP_ID_1283_PG10 (0x05030101) +#define CHIP_ID_1283_PG20 (0x05030111) + +/* TODO: move all these common registers and values elsewhere */ +#define HW_ACCESS_ELP_CTRL_REG 0x1FFFC + +/* ELP register commands */ +#define ELPCTRL_WAKE_UP 0x1 +#define ELPCTRL_WAKE_UP_WLAN_READY 0x5 +#define ELPCTRL_SLEEP 0x0 +/* ELP WLAN_READY bit */ +#define ELPCTRL_WLAN_READY 0x2 + +/************************************************************************* + + Interrupt Trigger Register (Host -> WiLink) + +**************************************************************************/ + +/* Hardware to Embedded CPU Interrupts - first 32-bit register set */ + +/* + * The host sets this bit to inform the Wlan + * FW that a TX packet is in the XFER + * Buffer #0. + */ +#define INTR_TRIG_TX_PROC0 BIT(2) + +/* + * The host sets this bit to inform the FW + * that it read a packet from RX XFER + * Buffer #0. + */ +#define INTR_TRIG_RX_PROC0 BIT(3) + +#define INTR_TRIG_DEBUG_ACK BIT(4) + +#define INTR_TRIG_STATE_CHANGED BIT(5) + +/* Hardware to Embedded CPU Interrupts - second 32-bit register set */ + +/* + * The host sets this bit to inform the FW + * that it read a packet from RX XFER + * Buffer #1. + */ +#define INTR_TRIG_RX_PROC1 BIT(17) + +/* + * The host sets this bit to inform the Wlan + * hardware that a TX packet is in the XFER + * Buffer #1. + */ +#define INTR_TRIG_TX_PROC1 BIT(18) + +#define ACX_SLV_SOFT_RESET_BIT BIT(1) +#define SOFT_RESET_MAX_TIME 1000000 +#define SOFT_RESET_STALL_TIME 1000 + +#define ECPU_CONTROL_HALT 0x00000101 + +#define WELP_ARM_COMMAND_VAL 0x4 + +#endif /* __WLCORE_H__ */ diff --git a/trunk/drivers/net/wireless/wl12xx/Kconfig b/trunk/drivers/net/wireless/wl12xx/Kconfig deleted file mode 100644 index af08c8609c63..000000000000 --- a/trunk/drivers/net/wireless/wl12xx/Kconfig +++ /dev/null @@ -1,48 +0,0 @@ -menuconfig WL12XX_MENU - tristate "TI wl12xx driver support" - depends on MAC80211 && EXPERIMENTAL - ---help--- - This will enable TI wl12xx driver support for the following chips: - wl1271, wl1273, wl1281 and wl1283. - The drivers make use of the mac80211 stack. - -config WL12XX - tristate "TI wl12xx support" - depends on WL12XX_MENU && GENERIC_HARDIRQS - depends on INET - select FW_LOADER - ---help--- - This module adds support for wireless adapters based on TI wl1271 and - TI wl1273 chipsets. This module does *not* include support for wl1251. - For wl1251 support, use the separate homonymous driver instead. - - If you choose to build a module, it will be called wl12xx. Say N if - unsure. - -config WL12XX_SPI - tristate "TI wl12xx SPI support" - depends on WL12XX && SPI_MASTER - select CRC7 - ---help--- - This module adds support for the SPI interface of adapters using - TI wl12xx chipsets. Select this if your platform is using - the SPI bus. - - If you choose to build a module, it'll be called wl12xx_spi. - Say N if unsure. - -config WL12XX_SDIO - tristate "TI wl12xx SDIO support" - depends on WL12XX && MMC - ---help--- - This module adds support for the SDIO interface of adapters using - TI wl12xx chipsets. Select this if your platform is using - the SDIO bus. - - If you choose to build a module, it'll be called wl12xx_sdio. - Say N if unsure. - -config WL12XX_PLATFORM_DATA - bool - depends on WL12XX_SDIO != n || WL1251_SDIO != n - default y diff --git a/trunk/drivers/net/wireless/wl12xx/Makefile b/trunk/drivers/net/wireless/wl12xx/Makefile deleted file mode 100644 index 98f289c907a9..000000000000 --- a/trunk/drivers/net/wireless/wl12xx/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -wl12xx-objs = main.o cmd.o io.o event.o tx.o rx.o ps.o acx.o \ - boot.o init.o debugfs.o scan.o - -wl12xx_spi-objs = spi.o -wl12xx_sdio-objs = sdio.o - -wl12xx-$(CONFIG_NL80211_TESTMODE) += testmode.o -obj-$(CONFIG_WL12XX) += wl12xx.o -obj-$(CONFIG_WL12XX_SPI) += wl12xx_spi.o -obj-$(CONFIG_WL12XX_SDIO) += wl12xx_sdio.o - -# small builtin driver bit -obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o - -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/trunk/drivers/net/wireless/wl12xx/acx.c b/trunk/drivers/net/wireless/wl12xx/acx.c deleted file mode 100644 index bc96db0683a5..000000000000 --- a/trunk/drivers/net/wireless/wl12xx/acx.c +++ /dev/null @@ -1,1742 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2008-2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include "acx.h" - -#include -#include -#include -#include - -#include "wl12xx.h" -#include "debug.h" -#include "wl12xx_80211.h" -#include "reg.h" -#include "ps.h" - -int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 wake_up_event, u8 listen_interval) -{ - struct acx_wake_up_condition *wake_up; - int ret; - - wl1271_debug(DEBUG_ACX, "acx wake up conditions (wake_up_event %d listen_interval %d)", - wake_up_event, listen_interval); - - wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL); - if (!wake_up) { - ret = -ENOMEM; - goto out; - } - - wake_up->role_id = wlvif->role_id; - wake_up->wake_up_event = wake_up_event; - wake_up->listen_interval = listen_interval; - - ret = wl1271_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, - wake_up, sizeof(*wake_up)); - if (ret < 0) { - wl1271_warning("could not set wake up conditions: %d", ret); - goto out; - } - -out: - kfree(wake_up); - return ret; -} - -int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth) -{ - struct acx_sleep_auth *auth; - int ret; - - wl1271_debug(DEBUG_ACX, "acx sleep auth"); - - auth = kzalloc(sizeof(*auth), GFP_KERNEL); - if (!auth) { - ret = -ENOMEM; - goto out; - } - - auth->sleep_auth = sleep_auth; - - ret = wl1271_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); - -out: - kfree(auth); - return ret; -} - -int wl1271_acx_tx_power(struct wl1271 *wl, struct wl12xx_vif *wlvif, - int power) -{ - struct acx_current_tx_power *acx; - int ret; - - wl1271_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr %d", power); - - if (power < 0 || power > 25) - return -EINVAL; - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->role_id = wlvif->role_id; - acx->current_tx_power = power * 10; - - ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("configure of tx power failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_feature_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - struct acx_feature_config *feature; - int ret; - - wl1271_debug(DEBUG_ACX, "acx feature cfg"); - - feature = kzalloc(sizeof(*feature), GFP_KERNEL); - if (!feature) { - ret = -ENOMEM; - goto out; - } - - /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ - feature->role_id = wlvif->role_id; - feature->data_flow_options = 0; - feature->options = 0; - - ret = wl1271_cmd_configure(wl, ACX_FEATURE_CFG, - feature, sizeof(*feature)); - if (ret < 0) { - wl1271_error("Couldnt set HW encryption"); - goto out; - } - -out: - kfree(feature); - return ret; -} - -int wl1271_acx_mem_map(struct wl1271 *wl, struct acx_header *mem_map, - size_t len) -{ - int ret; - - wl1271_debug(DEBUG_ACX, "acx mem map"); - - ret = wl1271_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len); - if (ret < 0) - return ret; - - return 0; -} - -int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl) -{ - struct acx_rx_msdu_lifetime *acx; - int ret; - - wl1271_debug(DEBUG_ACX, "acx rx msdu life time"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->lifetime = cpu_to_le32(wl->conf.rx.rx_msdu_life_time); - ret = wl1271_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, - acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("failed to set rx msdu life time: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_slot(struct wl1271 *wl, struct wl12xx_vif *wlvif, - enum acx_slot_type slot_time) -{ - struct acx_slot *slot; - int ret; - - wl1271_debug(DEBUG_ACX, "acx slot"); - - slot = kzalloc(sizeof(*slot), GFP_KERNEL); - if (!slot) { - ret = -ENOMEM; - goto out; - } - - slot->role_id = wlvif->role_id; - slot->wone_index = STATION_WONE_INDEX; - slot->slot_time = slot_time; - - ret = wl1271_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot)); - if (ret < 0) { - wl1271_warning("failed to set slot time: %d", ret); - goto out; - } - -out: - kfree(slot); - return ret; -} - -int wl1271_acx_group_address_tbl(struct wl1271 *wl, struct wl12xx_vif *wlvif, - bool enable, void *mc_list, u32 mc_list_len) -{ - struct acx_dot11_grp_addr_tbl *acx; - int ret; - - wl1271_debug(DEBUG_ACX, "acx group address tbl"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - /* MAC filtering */ - acx->role_id = wlvif->role_id; - acx->enabled = enable; - acx->num_groups = mc_list_len; - memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN); - - ret = wl1271_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, - acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("failed to set group addr table: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_service_period_timeout(struct wl1271 *wl, - struct wl12xx_vif *wlvif) -{ - struct acx_rx_timeout *rx_timeout; - int ret; - - rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL); - if (!rx_timeout) { - ret = -ENOMEM; - goto out; - } - - wl1271_debug(DEBUG_ACX, "acx service period timeout"); - - rx_timeout->role_id = wlvif->role_id; - rx_timeout->ps_poll_timeout = cpu_to_le16(wl->conf.rx.ps_poll_timeout); - rx_timeout->upsd_timeout = cpu_to_le16(wl->conf.rx.upsd_timeout); - - ret = wl1271_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, - rx_timeout, sizeof(*rx_timeout)); - if (ret < 0) { - wl1271_warning("failed to set service period timeout: %d", - ret); - goto out; - } - -out: - kfree(rx_timeout); - return ret; -} - -int wl1271_acx_rts_threshold(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u32 rts_threshold) -{ - struct acx_rts_threshold *rts; - int ret; - - /* - * If the RTS threshold is not configured or out of range, use the - * default value. - */ - if (rts_threshold > IEEE80211_MAX_RTS_THRESHOLD) - rts_threshold = wl->conf.rx.rts_threshold; - - wl1271_debug(DEBUG_ACX, "acx rts threshold: %d", rts_threshold); - - rts = kzalloc(sizeof(*rts), GFP_KERNEL); - if (!rts) { - ret = -ENOMEM; - goto out; - } - - rts->role_id = wlvif->role_id; - rts->threshold = cpu_to_le16((u16)rts_threshold); - - ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); - if (ret < 0) { - wl1271_warning("failed to set rts threshold: %d", ret); - goto out; - } - -out: - kfree(rts); - return ret; -} - -int wl1271_acx_dco_itrim_params(struct wl1271 *wl) -{ - struct acx_dco_itrim_params *dco; - struct conf_itrim_settings *c = &wl->conf.itrim; - int ret; - - wl1271_debug(DEBUG_ACX, "acx dco itrim parameters"); - - dco = kzalloc(sizeof(*dco), GFP_KERNEL); - if (!dco) { - ret = -ENOMEM; - goto out; - } - - dco->enable = c->enable; - dco->timeout = cpu_to_le32(c->timeout); - - ret = wl1271_cmd_configure(wl, ACX_SET_DCO_ITRIM_PARAMS, - dco, sizeof(*dco)); - if (ret < 0) { - wl1271_warning("failed to set dco itrim parameters: %d", ret); - goto out; - } - -out: - kfree(dco); - return ret; -} - -int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, struct wl12xx_vif *wlvif, - bool enable_filter) -{ - struct acx_beacon_filter_option *beacon_filter = NULL; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx beacon filter opt"); - - if (enable_filter && - wl->conf.conn.bcn_filt_mode == CONF_BCN_FILT_MODE_DISABLED) - goto out; - - beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); - if (!beacon_filter) { - ret = -ENOMEM; - goto out; - } - - beacon_filter->role_id = wlvif->role_id; - beacon_filter->enable = enable_filter; - - /* - * When set to zero, and the filter is enabled, beacons - * without the unicast TIM bit set are dropped. - */ - beacon_filter->max_num_beacons = 0; - - ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_OPT, - beacon_filter, sizeof(*beacon_filter)); - if (ret < 0) { - wl1271_warning("failed to set beacon filter opt: %d", ret); - goto out; - } - -out: - kfree(beacon_filter); - return ret; -} - -int wl1271_acx_beacon_filter_table(struct wl1271 *wl, - struct wl12xx_vif *wlvif) -{ - struct acx_beacon_filter_ie_table *ie_table; - int i, idx = 0; - int ret; - bool vendor_spec = false; - - wl1271_debug(DEBUG_ACX, "acx beacon filter table"); - - ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL); - if (!ie_table) { - ret = -ENOMEM; - goto out; - } - - /* configure default beacon pass-through rules */ - ie_table->role_id = wlvif->role_id; - ie_table->num_ie = 0; - for (i = 0; i < wl->conf.conn.bcn_filt_ie_count; i++) { - struct conf_bcn_filt_rule *r = &(wl->conf.conn.bcn_filt_ie[i]); - ie_table->table[idx++] = r->ie; - ie_table->table[idx++] = r->rule; - - if (r->ie == WLAN_EID_VENDOR_SPECIFIC) { - /* only one vendor specific ie allowed */ - if (vendor_spec) - continue; - - /* for vendor specific rules configure the - additional fields */ - memcpy(&(ie_table->table[idx]), r->oui, - CONF_BCN_IE_OUI_LEN); - idx += CONF_BCN_IE_OUI_LEN; - ie_table->table[idx++] = r->type; - memcpy(&(ie_table->table[idx]), r->version, - CONF_BCN_IE_VER_LEN); - idx += CONF_BCN_IE_VER_LEN; - vendor_spec = true; - } - - ie_table->num_ie++; - } - - ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, - ie_table, sizeof(*ie_table)); - if (ret < 0) { - wl1271_warning("failed to set beacon filter table: %d", ret); - goto out; - } - -out: - kfree(ie_table); - return ret; -} - -#define ACX_CONN_MONIT_DISABLE_VALUE 0xffffffff - -int wl1271_acx_conn_monit_params(struct wl1271 *wl, struct wl12xx_vif *wlvif, - bool enable) -{ - struct acx_conn_monit_params *acx; - u32 threshold = ACX_CONN_MONIT_DISABLE_VALUE; - u32 timeout = ACX_CONN_MONIT_DISABLE_VALUE; - int ret; - - wl1271_debug(DEBUG_ACX, "acx connection monitor parameters: %s", - enable ? "enabled" : "disabled"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - if (enable) { - threshold = wl->conf.conn.synch_fail_thold; - timeout = wl->conf.conn.bss_lose_timeout; - } - - acx->role_id = wlvif->role_id; - acx->synch_fail_thold = cpu_to_le32(threshold); - acx->bss_lose_timeout = cpu_to_le32(timeout); - - ret = wl1271_cmd_configure(wl, ACX_CONN_MONIT_PARAMS, - acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("failed to set connection monitor " - "parameters: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - - -int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable) -{ - struct acx_bt_wlan_coex *pta; - int ret; - - wl1271_debug(DEBUG_ACX, "acx sg enable"); - - pta = kzalloc(sizeof(*pta), GFP_KERNEL); - if (!pta) { - ret = -ENOMEM; - goto out; - } - - if (enable) - pta->enable = wl->conf.sg.state; - else - pta->enable = CONF_SG_DISABLE; - - ret = wl1271_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); - if (ret < 0) { - wl1271_warning("failed to set softgemini enable: %d", ret); - goto out; - } - -out: - kfree(pta); - return ret; -} - -int wl12xx_acx_sg_cfg(struct wl1271 *wl) -{ - struct acx_bt_wlan_coex_param *param; - struct conf_sg_settings *c = &wl->conf.sg; - int i, ret; - - wl1271_debug(DEBUG_ACX, "acx sg cfg"); - - param = kzalloc(sizeof(*param), GFP_KERNEL); - if (!param) { - ret = -ENOMEM; - goto out; - } - - /* BT-WLAN coext parameters */ - for (i = 0; i < CONF_SG_PARAMS_MAX; i++) - param->params[i] = cpu_to_le32(c->params[i]); - param->param_idx = CONF_SG_PARAMS_ALL; - - ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); - if (ret < 0) { - wl1271_warning("failed to set sg config: %d", ret); - goto out; - } - -out: - kfree(param); - return ret; -} - -int wl1271_acx_cca_threshold(struct wl1271 *wl) -{ - struct acx_energy_detection *detection; - int ret; - - wl1271_debug(DEBUG_ACX, "acx cca threshold"); - - detection = kzalloc(sizeof(*detection), GFP_KERNEL); - if (!detection) { - ret = -ENOMEM; - goto out; - } - - detection->rx_cca_threshold = cpu_to_le16(wl->conf.rx.rx_cca_threshold); - detection->tx_energy_detection = wl->conf.tx.tx_energy_detection; - - ret = wl1271_cmd_configure(wl, ACX_CCA_THRESHOLD, - detection, sizeof(*detection)); - if (ret < 0) - wl1271_warning("failed to set cca threshold: %d", ret); - -out: - kfree(detection); - return ret; -} - -int wl1271_acx_bcn_dtim_options(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - struct acx_beacon_broadcast *bb; - int ret; - - wl1271_debug(DEBUG_ACX, "acx bcn dtim options"); - - bb = kzalloc(sizeof(*bb), GFP_KERNEL); - if (!bb) { - ret = -ENOMEM; - goto out; - } - - bb->role_id = wlvif->role_id; - bb->beacon_rx_timeout = cpu_to_le16(wl->conf.conn.beacon_rx_timeout); - bb->broadcast_timeout = cpu_to_le16(wl->conf.conn.broadcast_timeout); - bb->rx_broadcast_in_ps = wl->conf.conn.rx_broadcast_in_ps; - bb->ps_poll_threshold = wl->conf.conn.ps_poll_threshold; - - ret = wl1271_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); - if (ret < 0) { - wl1271_warning("failed to set rx config: %d", ret); - goto out; - } - -out: - kfree(bb); - return ret; -} - -int wl1271_acx_aid(struct wl1271 *wl, struct wl12xx_vif *wlvif, u16 aid) -{ - struct acx_aid *acx_aid; - int ret; - - wl1271_debug(DEBUG_ACX, "acx aid"); - - acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL); - if (!acx_aid) { - ret = -ENOMEM; - goto out; - } - - acx_aid->role_id = wlvif->role_id; - acx_aid->aid = cpu_to_le16(aid); - - ret = wl1271_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); - if (ret < 0) { - wl1271_warning("failed to set aid: %d", ret); - goto out; - } - -out: - kfree(acx_aid); - return ret; -} - -int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask) -{ - struct acx_event_mask *mask; - int ret; - - wl1271_debug(DEBUG_ACX, "acx event mbox mask"); - - mask = kzalloc(sizeof(*mask), GFP_KERNEL); - if (!mask) { - ret = -ENOMEM; - goto out; - } - - /* high event mask is unused */ - mask->high_event_mask = cpu_to_le32(0xffffffff); - mask->event_mask = cpu_to_le32(event_mask); - - ret = wl1271_cmd_configure(wl, ACX_EVENT_MBOX_MASK, - mask, sizeof(*mask)); - if (ret < 0) { - wl1271_warning("failed to set acx_event_mbox_mask: %d", ret); - goto out; - } - -out: - kfree(mask); - return ret; -} - -int wl1271_acx_set_preamble(struct wl1271 *wl, struct wl12xx_vif *wlvif, - enum acx_preamble_type preamble) -{ - struct acx_preamble *acx; - int ret; - - wl1271_debug(DEBUG_ACX, "acx_set_preamble"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->role_id = wlvif->role_id; - acx->preamble = preamble; - - ret = wl1271_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("Setting of preamble failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_cts_protect(struct wl1271 *wl, struct wl12xx_vif *wlvif, - enum acx_ctsprotect_type ctsprotect) -{ - struct acx_ctsprotect *acx; - int ret; - - wl1271_debug(DEBUG_ACX, "acx_set_ctsprotect"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->role_id = wlvif->role_id; - acx->ctsprotect = ctsprotect; - - ret = wl1271_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("Setting of ctsprotect failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats) -{ - int ret; - - wl1271_debug(DEBUG_ACX, "acx statistics"); - - ret = wl1271_cmd_interrogate(wl, ACX_STATISTICS, stats, - sizeof(*stats)); - if (ret < 0) { - wl1271_warning("acx statistics failed: %d", ret); - return -ENOMEM; - } - - return 0; -} - -int wl1271_acx_sta_rate_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - struct acx_rate_policy *acx; - struct conf_tx_rate_class *c = &wl->conf.tx.sta_rc_conf; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx rate policies"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - - if (!acx) { - ret = -ENOMEM; - goto out; - } - - wl1271_debug(DEBUG_ACX, "basic_rate: 0x%x, full_rate: 0x%x", - wlvif->basic_rate, wlvif->rate_set); - - /* configure one basic rate class */ - acx->rate_policy_idx = cpu_to_le32(wlvif->sta.basic_rate_idx); - acx->rate_policy.enabled_rates = cpu_to_le32(wlvif->basic_rate); - acx->rate_policy.short_retry_limit = c->short_retry_limit; - acx->rate_policy.long_retry_limit = c->long_retry_limit; - acx->rate_policy.aflags = c->aflags; - - ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("Setting of rate policies failed: %d", ret); - goto out; - } - - /* configure one AP supported rate class */ - acx->rate_policy_idx = cpu_to_le32(wlvif->sta.ap_rate_idx); - acx->rate_policy.enabled_rates = cpu_to_le32(wlvif->rate_set); - acx->rate_policy.short_retry_limit = c->short_retry_limit; - acx->rate_policy.long_retry_limit = c->long_retry_limit; - acx->rate_policy.aflags = c->aflags; - - ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("Setting of rate policies failed: %d", ret); - goto out; - } - - /* - * configure one rate class for basic p2p operations. - * (p2p packets should always go out with OFDM rates, even - * if we are currently connected to 11b AP) - */ - acx->rate_policy_idx = cpu_to_le32(wlvif->sta.p2p_rate_idx); - acx->rate_policy.enabled_rates = - cpu_to_le32(CONF_TX_RATE_MASK_BASIC_P2P); - acx->rate_policy.short_retry_limit = c->short_retry_limit; - acx->rate_policy.long_retry_limit = c->long_retry_limit; - acx->rate_policy.aflags = c->aflags; - - ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("Setting of rate policies failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c, - u8 idx) -{ - struct acx_rate_policy *acx; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx ap rate policy %d rates 0x%x", - idx, c->enabled_rates); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->rate_policy.enabled_rates = cpu_to_le32(c->enabled_rates); - acx->rate_policy.short_retry_limit = c->short_retry_limit; - acx->rate_policy.long_retry_limit = c->long_retry_limit; - acx->rate_policy.aflags = c->aflags; - - acx->rate_policy_idx = cpu_to_le32(idx); - - ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("Setting of ap rate policy failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_ac_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 ac, u8 cw_min, u16 cw_max, u8 aifsn, u16 txop) -{ - struct acx_ac_cfg *acx; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d " - "aifs %d txop %d", ac, cw_min, cw_max, aifsn, txop); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->role_id = wlvif->role_id; - acx->ac = ac; - acx->cw_min = cw_min; - acx->cw_max = cpu_to_le16(cw_max); - acx->aifsn = aifsn; - acx->tx_op_limit = cpu_to_le16(txop); - - ret = wl1271_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx ac cfg failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_tid_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 queue_id, u8 channel_type, - u8 tsid, u8 ps_scheme, u8 ack_policy, - u32 apsd_conf0, u32 apsd_conf1) -{ - struct acx_tid_config *acx; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx tid config"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->role_id = wlvif->role_id; - acx->queue_id = queue_id; - acx->channel_type = channel_type; - acx->tsid = tsid; - acx->ps_scheme = ps_scheme; - acx->ack_policy = ack_policy; - acx->apsd_conf[0] = cpu_to_le32(apsd_conf0); - acx->apsd_conf[1] = cpu_to_le32(apsd_conf1); - - ret = wl1271_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("Setting of tid config failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold) -{ - struct acx_frag_threshold *acx; - int ret = 0; - - /* - * If the fragmentation is not configured or out of range, use the - * default value. - */ - if (frag_threshold > IEEE80211_MAX_FRAG_THRESHOLD) - frag_threshold = wl->conf.tx.frag_threshold; - - wl1271_debug(DEBUG_ACX, "acx frag threshold: %d", frag_threshold); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->frag_threshold = cpu_to_le16((u16)frag_threshold); - ret = wl1271_cmd_configure(wl, ACX_FRAG_CFG, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("Setting of frag threshold failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_tx_config_options(struct wl1271 *wl) -{ - struct acx_tx_config_options *acx; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx tx config options"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->tx_compl_timeout = cpu_to_le16(wl->conf.tx.tx_compl_timeout); - acx->tx_compl_threshold = cpu_to_le16(wl->conf.tx.tx_compl_threshold); - ret = wl1271_cmd_configure(wl, ACX_TX_CONFIG_OPT, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("Setting of tx options failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl12xx_acx_mem_cfg(struct wl1271 *wl) -{ - struct wl12xx_acx_config_memory *mem_conf; - struct conf_memory_settings *mem; - int ret; - - wl1271_debug(DEBUG_ACX, "wl1271 mem cfg"); - - mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); - if (!mem_conf) { - ret = -ENOMEM; - goto out; - } - - if (wl->chip.id == CHIP_ID_1283_PG20) - mem = &wl->conf.mem_wl128x; - else - mem = &wl->conf.mem_wl127x; - - /* memory config */ - mem_conf->num_stations = mem->num_stations; - mem_conf->rx_mem_block_num = mem->rx_block_num; - mem_conf->tx_min_mem_block_num = mem->tx_min_block_num; - mem_conf->num_ssid_profiles = mem->ssid_profiles; - mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS); - mem_conf->dyn_mem_enable = mem->dynamic_memory; - mem_conf->tx_free_req = mem->min_req_tx_blocks; - mem_conf->rx_free_req = mem->min_req_rx_blocks; - mem_conf->tx_min = mem->tx_min; - mem_conf->fwlog_blocks = wl->conf.fwlog.mem_blocks; - - ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf, - sizeof(*mem_conf)); - if (ret < 0) { - wl1271_warning("wl1271 mem config failed: %d", ret); - goto out; - } - -out: - kfree(mem_conf); - return ret; -} - -int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap) -{ - struct wl1271_acx_host_config_bitmap *bitmap_conf; - int ret; - - bitmap_conf = kzalloc(sizeof(*bitmap_conf), GFP_KERNEL); - if (!bitmap_conf) { - ret = -ENOMEM; - goto out; - } - - bitmap_conf->host_cfg_bitmap = cpu_to_le32(host_cfg_bitmap); - - ret = wl1271_cmd_configure(wl, ACX_HOST_IF_CFG_BITMAP, - bitmap_conf, sizeof(*bitmap_conf)); - if (ret < 0) { - wl1271_warning("wl1271 bitmap config opt failed: %d", ret); - goto out; - } - -out: - kfree(bitmap_conf); - - return ret; -} - -int wl1271_acx_init_mem_config(struct wl1271 *wl) -{ - int ret; - - wl->target_mem_map = kzalloc(sizeof(struct wl1271_acx_mem_map), - GFP_KERNEL); - if (!wl->target_mem_map) { - wl1271_error("couldn't allocate target memory map"); - return -ENOMEM; - } - - /* we now ask for the firmware built memory map */ - ret = wl1271_acx_mem_map(wl, (void *)wl->target_mem_map, - sizeof(struct wl1271_acx_mem_map)); - if (ret < 0) { - wl1271_error("couldn't retrieve firmware memory map"); - kfree(wl->target_mem_map); - wl->target_mem_map = NULL; - return ret; - } - - /* initialize TX block book keeping */ - wl->tx_blocks_available = - le32_to_cpu(wl->target_mem_map->num_tx_mem_blocks); - wl1271_debug(DEBUG_TX, "available tx blocks: %d", - wl->tx_blocks_available); - - return 0; -} - -int wl1271_acx_init_rx_interrupt(struct wl1271 *wl) -{ - struct wl1271_acx_rx_config_opt *rx_conf; - int ret; - - wl1271_debug(DEBUG_ACX, "wl1271 rx interrupt config"); - - rx_conf = kzalloc(sizeof(*rx_conf), GFP_KERNEL); - if (!rx_conf) { - ret = -ENOMEM; - goto out; - } - - rx_conf->threshold = cpu_to_le16(wl->conf.rx.irq_pkt_threshold); - rx_conf->timeout = cpu_to_le16(wl->conf.rx.irq_timeout); - rx_conf->mblk_threshold = cpu_to_le16(wl->conf.rx.irq_blk_threshold); - rx_conf->queue_type = wl->conf.rx.queue_type; - - ret = wl1271_cmd_configure(wl, ACX_RX_CONFIG_OPT, rx_conf, - sizeof(*rx_conf)); - if (ret < 0) { - wl1271_warning("wl1271 rx config opt failed: %d", ret); - goto out; - } - -out: - kfree(rx_conf); - return ret; -} - -int wl1271_acx_bet_enable(struct wl1271 *wl, struct wl12xx_vif *wlvif, - bool enable) -{ - struct wl1271_acx_bet_enable *acx = NULL; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx bet enable"); - - if (enable && wl->conf.conn.bet_enable == CONF_BET_MODE_DISABLE) - goto out; - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->role_id = wlvif->role_id; - acx->enable = enable ? CONF_BET_MODE_ENABLE : CONF_BET_MODE_DISABLE; - acx->max_consecutive = wl->conf.conn.bet_max_consecutive; - - ret = wl1271_cmd_configure(wl, ACX_BET_ENABLE, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx bet enable failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_arp_ip_filter(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 enable, __be32 address) -{ - struct wl1271_acx_arp_filter *acx; - int ret; - - wl1271_debug(DEBUG_ACX, "acx arp ip filter, enable: %d", enable); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->role_id = wlvif->role_id; - acx->version = ACX_IPV4_VERSION; - acx->enable = enable; - - if (enable) - memcpy(acx->address, &address, ACX_IPV4_ADDR_SIZE); - - ret = wl1271_cmd_configure(wl, ACX_ARP_IP_FILTER, - acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("failed to set arp ip filter: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_pm_config(struct wl1271 *wl) -{ - struct wl1271_acx_pm_config *acx = NULL; - struct conf_pm_config_settings *c = &wl->conf.pm_config; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx pm config"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->host_clk_settling_time = cpu_to_le32(c->host_clk_settling_time); - acx->host_fast_wakeup_support = c->host_fast_wakeup_support; - - ret = wl1271_cmd_configure(wl, ACX_PM_CONFIG, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx pm config failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_keep_alive_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, - bool enable) -{ - struct wl1271_acx_keep_alive_mode *acx = NULL; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx keep alive mode: %d", enable); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->role_id = wlvif->role_id; - acx->enabled = enable; - - ret = wl1271_cmd_configure(wl, ACX_KEEP_ALIVE_MODE, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx keep alive mode failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_keep_alive_config(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 index, u8 tpl_valid) -{ - struct wl1271_acx_keep_alive_config *acx = NULL; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx keep alive config"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->role_id = wlvif->role_id; - acx->period = cpu_to_le32(wl->conf.conn.keep_alive_interval); - acx->index = index; - acx->tpl_validation = tpl_valid; - acx->trigger = ACX_KEEP_ALIVE_NO_TX; - - ret = wl1271_cmd_configure(wl, ACX_SET_KEEP_ALIVE_CONFIG, - acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx keep alive config failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, struct wl12xx_vif *wlvif, - bool enable, s16 thold, u8 hyst) -{ - struct wl1271_acx_rssi_snr_trigger *acx = NULL; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx rssi snr trigger"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - wlvif->last_rssi_event = -1; - - acx->role_id = wlvif->role_id; - acx->pacing = cpu_to_le16(wl->conf.roam_trigger.trigger_pacing); - acx->metric = WL1271_ACX_TRIG_METRIC_RSSI_BEACON; - acx->type = WL1271_ACX_TRIG_TYPE_EDGE; - if (enable) - acx->enable = WL1271_ACX_TRIG_ENABLE; - else - acx->enable = WL1271_ACX_TRIG_DISABLE; - - acx->index = WL1271_ACX_TRIG_IDX_RSSI; - acx->dir = WL1271_ACX_TRIG_DIR_BIDIR; - acx->threshold = cpu_to_le16(thold); - acx->hysteresis = hyst; - - ret = wl1271_cmd_configure(wl, ACX_RSSI_SNR_TRIGGER, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx rssi snr trigger setting failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl, - struct wl12xx_vif *wlvif) -{ - struct wl1271_acx_rssi_snr_avg_weights *acx = NULL; - struct conf_roam_trigger_settings *c = &wl->conf.roam_trigger; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx rssi snr avg weights"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->role_id = wlvif->role_id; - acx->rssi_beacon = c->avg_weight_rssi_beacon; - acx->rssi_data = c->avg_weight_rssi_data; - acx->snr_beacon = c->avg_weight_snr_beacon; - acx->snr_data = c->avg_weight_snr_data; - - ret = wl1271_cmd_configure(wl, ACX_RSSI_SNR_WEIGHTS, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx rssi snr trigger weights failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, - struct ieee80211_sta_ht_cap *ht_cap, - bool allow_ht_operation, u8 hlid) -{ - struct wl1271_acx_ht_capabilities *acx; - int ret = 0; - u32 ht_capabilites = 0; - - wl1271_debug(DEBUG_ACX, "acx ht capabilities setting " - "sta supp: %d sta cap: %d", ht_cap->ht_supported, - ht_cap->cap); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - if (allow_ht_operation && ht_cap->ht_supported) { - /* no need to translate capabilities - use the spec values */ - ht_capabilites = ht_cap->cap; - - /* - * this bit is not employed by the spec but only by FW to - * indicate peer HT support - */ - ht_capabilites |= WL12XX_HT_CAP_HT_OPERATION; - - /* get data from A-MPDU parameters field */ - acx->ampdu_max_length = ht_cap->ampdu_factor; - acx->ampdu_min_spacing = ht_cap->ampdu_density; - } - - acx->hlid = hlid; - acx->ht_capabilites = cpu_to_le32(ht_capabilites); - - ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx ht capabilities setting failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_set_ht_information(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - u16 ht_operation_mode) -{ - struct wl1271_acx_ht_information *acx; - int ret = 0; - - wl1271_debug(DEBUG_ACX, "acx ht information setting"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->role_id = wlvif->role_id; - acx->ht_protection = - (u8)(ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION); - acx->rifs_mode = 0; - acx->gf_protection = - !!(ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); - acx->ht_tx_burst_limit = 0; - acx->dual_cts_protection = 0; - - ret = wl1271_cmd_configure(wl, ACX_HT_BSS_OPERATION, acx, sizeof(*acx)); - - if (ret < 0) { - wl1271_warning("acx ht information setting failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -/* Configure BA session initiator/receiver parameters setting in the FW. */ -int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl, - struct wl12xx_vif *wlvif) -{ - struct wl1271_acx_ba_initiator_policy *acx; - int ret; - - wl1271_debug(DEBUG_ACX, "acx ba initiator policy"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - /* set for the current role */ - acx->role_id = wlvif->role_id; - acx->tid_bitmap = wl->conf.ht.tx_ba_tid_bitmap; - acx->win_size = wl->conf.ht.tx_ba_win_size; - acx->inactivity_timeout = wl->conf.ht.inactivity_timeout; - - ret = wl1271_cmd_configure(wl, - ACX_BA_SESSION_INIT_POLICY, - acx, - sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx ba initiator policy failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -/* setup BA session receiver setting in the FW. */ -int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, - u16 ssn, bool enable, u8 peer_hlid) -{ - struct wl1271_acx_ba_receiver_setup *acx; - int ret; - - wl1271_debug(DEBUG_ACX, "acx ba receiver session setting"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->hlid = peer_hlid; - acx->tid = tid_index; - acx->enable = enable; - acx->win_size = wl->conf.ht.rx_ba_win_size; - acx->ssn = ssn; - - ret = wl1271_cmd_configure(wl, ACX_BA_SESSION_RX_SETUP, acx, - sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx ba receiver session failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl12xx_acx_tsf_info(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u64 *mactime) -{ - struct wl12xx_acx_fw_tsf_information *tsf_info; - int ret; - - tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL); - if (!tsf_info) { - ret = -ENOMEM; - goto out; - } - - tsf_info->role_id = wlvif->role_id; - - ret = wl1271_cmd_interrogate(wl, ACX_TSF_INFO, - tsf_info, sizeof(*tsf_info)); - if (ret < 0) { - wl1271_warning("acx tsf info interrogate failed"); - goto out; - } - - *mactime = le32_to_cpu(tsf_info->current_tsf_low) | - ((u64) le32_to_cpu(tsf_info->current_tsf_high) << 32); - -out: - kfree(tsf_info); - return ret; -} - -int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif, - bool enable) -{ - struct wl1271_acx_ps_rx_streaming *rx_streaming; - u32 conf_queues, enable_queues; - int i, ret = 0; - - wl1271_debug(DEBUG_ACX, "acx ps rx streaming"); - - rx_streaming = kzalloc(sizeof(*rx_streaming), GFP_KERNEL); - if (!rx_streaming) { - ret = -ENOMEM; - goto out; - } - - conf_queues = wl->conf.rx_streaming.queues; - if (enable) - enable_queues = conf_queues; - else - enable_queues = 0; - - for (i = 0; i < 8; i++) { - /* - * Skip non-changed queues, to avoid redundant acxs. - * this check assumes conf.rx_streaming.queues can't - * be changed while rx_streaming is enabled. - */ - if (!(conf_queues & BIT(i))) - continue; - - rx_streaming->role_id = wlvif->role_id; - rx_streaming->tid = i; - rx_streaming->enable = enable_queues & BIT(i); - rx_streaming->period = wl->conf.rx_streaming.interval; - rx_streaming->timeout = wl->conf.rx_streaming.interval; - - ret = wl1271_cmd_configure(wl, ACX_PS_RX_STREAMING, - rx_streaming, - sizeof(*rx_streaming)); - if (ret < 0) { - wl1271_warning("acx ps rx streaming failed: %d", ret); - goto out; - } - } -out: - kfree(rx_streaming); - return ret; -} - -int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - struct wl1271_acx_ap_max_tx_retry *acx = NULL; - int ret; - - wl1271_debug(DEBUG_ACX, "acx ap max tx retry"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) - return -ENOMEM; - - acx->role_id = wlvif->role_id; - acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries); - - ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx ap max tx retry failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl12xx_acx_config_ps(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - struct wl1271_acx_config_ps *config_ps; - int ret; - - wl1271_debug(DEBUG_ACX, "acx config ps"); - - config_ps = kzalloc(sizeof(*config_ps), GFP_KERNEL); - if (!config_ps) { - ret = -ENOMEM; - goto out; - } - - config_ps->exit_retries = wl->conf.conn.psm_exit_retries; - config_ps->enter_retries = wl->conf.conn.psm_entry_retries; - config_ps->null_data_rate = cpu_to_le32(wlvif->basic_rate); - - ret = wl1271_cmd_configure(wl, ACX_CONFIG_PS, config_ps, - sizeof(*config_ps)); - - if (ret < 0) { - wl1271_warning("acx config ps failed: %d", ret); - goto out; - } - -out: - kfree(config_ps); - return ret; -} - -int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr) -{ - struct wl1271_acx_inconnection_sta *acx = NULL; - int ret; - - wl1271_debug(DEBUG_ACX, "acx set inconnaction sta %pM", addr); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) - return -ENOMEM; - - memcpy(acx->addr, addr, ETH_ALEN); - - ret = wl1271_cmd_configure(wl, ACX_UPDATE_INCONNECTION_STA_LIST, - acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx set inconnaction sta failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl1271_acx_fm_coex(struct wl1271 *wl) -{ - struct wl1271_acx_fm_coex *acx; - int ret; - - wl1271_debug(DEBUG_ACX, "acx fm coex setting"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->enable = wl->conf.fm_coex.enable; - acx->swallow_period = wl->conf.fm_coex.swallow_period; - acx->n_divider_fref_set_1 = wl->conf.fm_coex.n_divider_fref_set_1; - acx->n_divider_fref_set_2 = wl->conf.fm_coex.n_divider_fref_set_2; - acx->m_divider_fref_set_1 = - cpu_to_le16(wl->conf.fm_coex.m_divider_fref_set_1); - acx->m_divider_fref_set_2 = - cpu_to_le16(wl->conf.fm_coex.m_divider_fref_set_2); - acx->coex_pll_stabilization_time = - cpu_to_le32(wl->conf.fm_coex.coex_pll_stabilization_time); - acx->ldo_stabilization_time = - cpu_to_le16(wl->conf.fm_coex.ldo_stabilization_time); - acx->fm_disturbed_band_margin = - wl->conf.fm_coex.fm_disturbed_band_margin; - acx->swallow_clk_diff = wl->conf.fm_coex.swallow_clk_diff; - - ret = wl1271_cmd_configure(wl, ACX_FM_COEX_CFG, acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx fm coex setting failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl) -{ - struct wl12xx_acx_set_rate_mgmt_params *acx = NULL; - struct conf_rate_policy_settings *conf = &wl->conf.rate; - int ret; - - wl1271_debug(DEBUG_ACX, "acx set rate mgmt params"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) - return -ENOMEM; - - acx->index = ACX_RATE_MGMT_ALL_PARAMS; - acx->rate_retry_score = cpu_to_le16(conf->rate_retry_score); - acx->per_add = cpu_to_le16(conf->per_add); - acx->per_th1 = cpu_to_le16(conf->per_th1); - acx->per_th2 = cpu_to_le16(conf->per_th2); - acx->max_per = cpu_to_le16(conf->max_per); - acx->inverse_curiosity_factor = conf->inverse_curiosity_factor; - acx->tx_fail_low_th = conf->tx_fail_low_th; - acx->tx_fail_high_th = conf->tx_fail_high_th; - acx->per_alpha_shift = conf->per_alpha_shift; - acx->per_add_shift = conf->per_add_shift; - acx->per_beta1_shift = conf->per_beta1_shift; - acx->per_beta2_shift = conf->per_beta2_shift; - acx->rate_check_up = conf->rate_check_up; - acx->rate_check_down = conf->rate_check_down; - memcpy(acx->rate_retry_policy, conf->rate_retry_policy, - sizeof(acx->rate_retry_policy)); - - ret = wl1271_cmd_configure(wl, ACX_SET_RATE_MGMT_PARAMS, - acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx set rate mgmt params failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - -int wl12xx_acx_config_hangover(struct wl1271 *wl) -{ - struct wl12xx_acx_config_hangover *acx; - struct conf_hangover_settings *conf = &wl->conf.hangover; - int ret; - - wl1271_debug(DEBUG_ACX, "acx config hangover"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) { - ret = -ENOMEM; - goto out; - } - - acx->recover_time = cpu_to_le32(conf->recover_time); - acx->hangover_period = conf->hangover_period; - acx->dynamic_mode = conf->dynamic_mode; - acx->early_termination_mode = conf->early_termination_mode; - acx->max_period = conf->max_period; - acx->min_period = conf->min_period; - acx->increase_delta = conf->increase_delta; - acx->decrease_delta = conf->decrease_delta; - acx->quiet_time = conf->quiet_time; - acx->increase_time = conf->increase_time; - acx->window_size = acx->window_size; - - ret = wl1271_cmd_configure(wl, ACX_CONFIG_HANGOVER, acx, - sizeof(*acx)); - - if (ret < 0) { - wl1271_warning("acx config hangover failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; - -} diff --git a/trunk/drivers/net/wireless/wl12xx/acx.h b/trunk/drivers/net/wireless/wl12xx/acx.h deleted file mode 100644 index a28fc044034c..000000000000 --- a/trunk/drivers/net/wireless/wl12xx/acx.h +++ /dev/null @@ -1,1314 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. - * Copyright (C) 2008-2010 Nokia Corporation - * - * Contact: Luciano Coelho - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __ACX_H__ -#define __ACX_H__ - -#include "wl12xx.h" -#include "cmd.h" - -/************************************************************************* - - Host Interrupt Register (WiLink -> Host) - -**************************************************************************/ -/* HW Initiated interrupt Watchdog timer expiration */ -#define WL1271_ACX_INTR_WATCHDOG BIT(0) -/* Init sequence is done (masked interrupt, detection through polling only ) */ -#define WL1271_ACX_INTR_INIT_COMPLETE BIT(1) -/* Event was entered to Event MBOX #A*/ -#define WL1271_ACX_INTR_EVENT_A BIT(2) -/* Event was entered to Event MBOX #B*/ -#define WL1271_ACX_INTR_EVENT_B BIT(3) -/* Command processing completion*/ -#define WL1271_ACX_INTR_CMD_COMPLETE BIT(4) -/* Signaling the host on HW wakeup */ -#define WL1271_ACX_INTR_HW_AVAILABLE BIT(5) -/* The MISC bit is used for aggregation of RX, TxComplete and TX rate update */ -#define WL1271_ACX_INTR_DATA BIT(6) -/* Trace message on MBOX #A */ -#define WL1271_ACX_INTR_TRACE_A BIT(7) -/* Trace message on MBOX #B */ -#define WL1271_ACX_INTR_TRACE_B BIT(8) - -#define WL1271_ACX_INTR_ALL 0xFFFFFFFF -#define WL1271_ACX_ALL_EVENTS_VECTOR (WL1271_ACX_INTR_WATCHDOG | \ - WL1271_ACX_INTR_INIT_COMPLETE | \ - WL1271_ACX_INTR_EVENT_A | \ - WL1271_ACX_INTR_EVENT_B | \ - WL1271_ACX_INTR_CMD_COMPLETE | \ - WL1271_ACX_INTR_HW_AVAILABLE | \ - WL1271_ACX_INTR_DATA) - -#define WL1271_INTR_MASK (WL1271_ACX_INTR_WATCHDOG | \ - WL1271_ACX_INTR_EVENT_A | \ - WL1271_ACX_INTR_EVENT_B | \ - WL1271_ACX_INTR_HW_AVAILABLE | \ - WL1271_ACX_INTR_DATA) - -/* Target's information element */ -struct acx_header { - struct wl1271_cmd_header cmd; - - /* acx (or information element) header */ - __le16 id; - - /* payload length (not including headers */ - __le16 len; -} __packed; - -struct acx_error_counter { - struct acx_header header; - - /* The number of PLCP errors since the last time this */ - /* information element was interrogated. This field is */ - /* automatically cleared when it is interrogated.*/ - __le32 PLCP_error; - - /* The number of FCS errors since the last time this */ - /* information element was interrogated. This field is */ - /* automatically cleared when it is interrogated.*/ - __le32 FCS_error; - - /* The number of MPDUs without PLCP header errors received*/ - /* since the last time this information element was interrogated. */ - /* This field is automatically cleared when it is interrogated.*/ - __le32 valid_frame; - - /* the number of missed sequence numbers in the squentially */ - /* values of frames seq numbers */ - __le32 seq_num_miss; -} __packed; - -enum wl12xx_role { - WL1271_ROLE_STA = 0, - WL1271_ROLE_IBSS, - WL1271_ROLE_AP, - WL1271_ROLE_DEVICE, - WL1271_ROLE_P2P_CL, - WL1271_ROLE_P2P_GO, - - WL12XX_INVALID_ROLE_TYPE = 0xff -}; - -enum wl1271_psm_mode { - /* Active mode */ - WL1271_PSM_CAM = 0, - - /* Power save mode */ - WL1271_PSM_PS = 1, - - /* Extreme low power */ - WL1271_PSM_ELP = 2, -}; - -struct acx_sleep_auth { - struct acx_header header; - - /* The sleep level authorization of the device. */ - /* 0 - Always active*/ - /* 1 - Power down mode: light / fast sleep*/ - /* 2 - ELP mode: Deep / Max sleep*/ - u8 sleep_auth; - u8 padding[3]; -} __packed; - -enum { - HOSTIF_PCI_MASTER_HOST_INDIRECT, - HOSTIF_PCI_MASTER_HOST_DIRECT, - HOSTIF_SLAVE, - HOSTIF_PKT_RING, - HOSTIF_DONTCARE = 0xFF -}; - -#define DEFAULT_UCAST_PRIORITY 0 -#define DEFAULT_RX_Q_PRIORITY 0 -#define DEFAULT_RXQ_PRIORITY 0 /* low 0 .. 15 high */ -#define DEFAULT_RXQ_TYPE 0x07 /* All frames, Data/Ctrl/Mgmt */ -#define TRACE_BUFFER_MAX_SIZE 256 - -#define DP_RX_PACKET_RING_CHUNK_SIZE 1600 -#define DP_TX_PACKET_RING_CHUNK_SIZE 1600 -#define DP_RX_PACKET_RING_CHUNK_NUM 2 -#define DP_TX_PACKET_RING_CHUNK_NUM 2 -#define DP_TX_COMPLETE_TIME_OUT 20 - -#define TX_MSDU_LIFETIME_MIN 0 -#define TX_MSDU_LIFETIME_MAX 3000 -#define TX_MSDU_LIFETIME_DEF 512 -#define RX_MSDU_LIFETIME_MIN 0 -#define RX_MSDU_LIFETIME_MAX 0xFFFFFFFF -#define RX_MSDU_LIFETIME_DEF 512000 - -struct acx_rx_msdu_lifetime { - struct acx_header header; - - /* - * The maximum amount of time, in TU, before the - * firmware discards the MSDU. - */ - __le32 lifetime; -} __packed; - -enum acx_slot_type { - SLOT_TIME_LONG = 0, - SLOT_TIME_SHORT = 1, - DEFAULT_SLOT_TIME = SLOT_TIME_SHORT, - MAX_SLOT_TIMES = 0xFF -}; - -#define STATION_WONE_INDEX 0 - -struct acx_slot { - struct acx_header header; - - u8 role_id; - u8 wone_index; /* Reserved */ - u8 slot_time; - u8 reserved[5]; -} __packed; - - -#define ACX_MC_ADDRESS_GROUP_MAX (8) -#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ACX_MC_ADDRESS_GROUP_MAX) - -struct acx_dot11_grp_addr_tbl { - struct acx_header header; - - u8 role_id; - u8 enabled; - u8 num_groups; - u8 pad[1]; - u8 mac_table[ADDRESS_GROUP_MAX_LEN]; -} __packed; - -struct acx_rx_timeout { - struct acx_header header; - - u8 role_id; - u8 reserved; - __le16 ps_poll_timeout; - __le16 upsd_timeout; - u8 padding[2]; -} __packed; - -struct acx_rts_threshold { - struct acx_header header; - - u8 role_id; - u8 reserved; - __le16 threshold; -} __packed; - -struct acx_beacon_filter_option { - struct acx_header header; - - u8 role_id; - u8 enable; - /* - * The number of beacons without the unicast TIM - * bit set that the firmware buffers before - * signaling the host about ready frames. - * When set to 0 and the filter is enabled, beacons - * without the unicast TIM bit set are dropped. - */ - u8 max_num_beacons; - u8 pad[1]; -} __packed; - -/* - * ACXBeaconFilterEntry (not 221) - * Byte Offset Size (Bytes) Definition - * =========== ============ ========== - * 0 1 IE identifier - * 1 1 Treatment bit mask - * - * ACXBeaconFilterEntry (221) - * Byte Offset Size (Bytes) Definition - * =========== ============ ========== - * 0 1 IE identifier - * 1 1 Treatment bit mask - * 2 3 OUI - * 5 1 Type - * 6 2 Version - * - * - * Treatment bit mask - The information element handling: - * bit 0 - The information element is compared and transferred - * in case of change. - * bit 1 - The information element is transferred to the host - * with each appearance or disappearance. - * Note that both bits can be set at the same time. - */ -#define BEACON_FILTER_TABLE_MAX_IE_NUM (32) -#define BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM (6) -#define BEACON_FILTER_TABLE_IE_ENTRY_SIZE (2) -#define BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE (6) -#define BEACON_FILTER_TABLE_MAX_SIZE ((BEACON_FILTER_TABLE_MAX_IE_NUM * \ - BEACON_FILTER_TABLE_IE_ENTRY_SIZE) + \ - (BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \ - BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE)) - -struct acx_beacon_filter_ie_table { - struct acx_header header; - - u8 role_id; - u8 num_ie; - u8 pad[2]; - u8 table[BEACON_FILTER_TABLE_MAX_SIZE]; -} __packed; - -struct acx_conn_monit_params { - struct acx_header header; - - u8 role_id; - u8 padding[3]; - __le32 synch_fail_thold; /* number of beacons missed */ - __le32 bss_lose_timeout; /* number of TU's from synch fail */ -} __packed; - -struct acx_bt_wlan_coex { - struct acx_header header; - - u8 enable; - u8 pad[3]; -} __packed; - -struct acx_bt_wlan_coex_param { - struct acx_header header; - - __le32 params[CONF_SG_PARAMS_MAX]; - u8 param_idx; - u8 padding[3]; -} __packed; - -struct acx_dco_itrim_params { - struct acx_header header; - - u8 enable; - u8 padding[3]; - __le32 timeout; -} __packed; - -struct acx_energy_detection { - struct acx_header header; - - /* The RX Clear Channel Assessment threshold in the PHY */ - __le16 rx_cca_threshold; - u8 tx_energy_detection; - u8 pad; -} __packed; - -struct acx_beacon_broadcast { - struct acx_header header; - - u8 role_id; - /* Enables receiving of broadcast packets in PS mode */ - u8 rx_broadcast_in_ps; - - __le16 beacon_rx_timeout; - __le16 broadcast_timeout; - - /* Consecutive PS Poll failures before updating the host */ - u8 ps_poll_threshold; - u8 pad[1]; -} __packed; - -struct acx_event_mask { - struct acx_header header; - - __le32 event_mask; - __le32 high_event_mask; /* Unused */ -} __packed; - -#define SCAN_PASSIVE BIT(0) -#define SCAN_5GHZ_BAND BIT(1) -#define SCAN_TRIGGERED BIT(2) -#define SCAN_PRIORITY_HIGH BIT(3) - -/* When set, disable HW encryption */ -#define DF_ENCRYPTION_DISABLE 0x01 -#define DF_SNIFF_MODE_ENABLE 0x80 - -struct acx_feature_config { - struct acx_header header; - - u8 role_id; - u8 padding[3]; - __le32 options; - __le32 data_flow_options; -} __packed; - -struct acx_current_tx_power { - struct acx_header header; - - u8 role_id; - u8 current_tx_power; - u8 padding[2]; -} __packed; - -struct acx_wake_up_condition { - struct acx_header header; - - u8 role_id; - u8 wake_up_event; /* Only one bit can be set */ - u8 listen_interval; - u8 pad[1]; -} __packed; - -struct acx_aid { - struct acx_header header; - - /* - * To be set when associated with an AP. - */ - u8 role_id; - u8 reserved; - __le16 aid; -} __packed; - -enum acx_preamble_type { - ACX_PREAMBLE_LONG = 0, - ACX_PREAMBLE_SHORT = 1 -}; - -struct acx_preamble { - struct acx_header header; - - /* - * When set, the WiLink transmits the frames with a short preamble and - * when cleared, the WiLink transmits the frames with a long preamble. - */ - u8 role_id; - u8 preamble; - u8 padding[2]; -} __packed; - -enum acx_ctsprotect_type { - CTSPROTECT_DISABLE = 0, - CTSPROTECT_ENABLE = 1 -}; - -struct acx_ctsprotect { - struct acx_header header; - u8 role_id; - u8 ctsprotect; - u8 padding[2]; -} __packed; - -struct acx_tx_statistics { - __le32 internal_desc_overflow; -} __packed; - -struct acx_rx_statistics { - __le32 out_of_mem; - __le32 hdr_overflow; - __le32 hw_stuck; - __le32 dropped; - __le32 fcs_err; - __le32 xfr_hint_trig; - __le32 path_reset; - __le32 reset_counter; -} __packed; - -struct acx_dma_statistics { - __le32 rx_requested; - __le32 rx_errors; - __le32 tx_requested; - __le32 tx_errors; -} __packed; - -struct acx_isr_statistics { - /* host command complete */ - __le32 cmd_cmplt; - - /* fiqisr() */ - __le32 fiqs; - - /* (INT_STS_ND & INT_TRIG_RX_HEADER) */ - __le32 rx_headers; - - /* (INT_STS_ND & INT_TRIG_RX_CMPLT) */ - __le32 rx_completes; - - /* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */ - __le32 rx_mem_overflow; - - /* (INT_STS_ND & INT_TRIG_S_RX_RDY) */ - __le32 rx_rdys; - - /* irqisr() */ - __le32 irqs; - - /* (INT_STS_ND & INT_TRIG_TX_PROC) */ - __le32 tx_procs; - - /* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */ - __le32 decrypt_done; - - /* (INT_STS_ND & INT_TRIG_DMA0) */ - __le32 dma0_done; - - /* (INT_STS_ND & INT_TRIG_DMA1) */ - __le32 dma1_done; - - /* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */ - __le32 tx_exch_complete; - - /* (INT_STS_ND & INT_TRIG_COMMAND) */ - __le32 commands; - - /* (INT_STS_ND & INT_TRIG_RX_PROC) */ - __le32 rx_procs; - - /* (INT_STS_ND & INT_TRIG_PM_802) */ - __le32 hw_pm_mode_changes; - - /* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */ - __le32 host_acknowledges; - - /* (INT_STS_ND & INT_TRIG_PM_PCI) */ - __le32 pci_pm; - - /* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */ - __le32 wakeups; - - /* (INT_STS_ND & INT_TRIG_LOW_RSSI) */ - __le32 low_rssi; -} __packed; - -struct acx_wep_statistics { - /* WEP address keys configured */ - __le32 addr_key_count; - - /* default keys configured */ - __le32 default_key_count; - - __le32 reserved; - - /* number of times that WEP key not found on lookup */ - __le32 key_not_found; - - /* number of times that WEP key decryption failed */ - __le32 decrypt_fail; - - /* WEP packets decrypted */ - __le32 packets; - - /* WEP decrypt interrupts */ - __le32 interrupt; -} __packed; - -#define ACX_MISSED_BEACONS_SPREAD 10 - -struct acx_pwr_statistics { - /* the amount of enters into power save mode (both PD & ELP) */ - __le32 ps_enter; - - /* the amount of enters into ELP mode */ - __le32 elp_enter; - - /* the amount of missing beacon interrupts to the host */ - __le32 missing_bcns; - - /* the amount of wake on host-access times */ - __le32 wake_on_host; - - /* the amount of wake on timer-expire */ - __le32 wake_on_timer_exp; - - /* the number of packets that were transmitted with PS bit set */ - __le32 tx_with_ps; - - /* the number of packets that were transmitted with PS bit clear */ - __le32 tx_without_ps; - - /* the number of received beacons */ - __le32 rcvd_beacons; - - /* the number of entering into PowerOn (power save off) */ - __le32 power_save_off; - - /* the number of entries into power save mode */ - __le16 enable_ps; - - /* - * the number of exits from power save, not including failed PS - * transitions - */ - __le16 disable_ps; - - /* - * the number of times the TSF counter was adjusted because - * of drift - */ - __le32 fix_tsf_ps; - - /* Gives statistics about the spread continuous missed beacons. - * The 16 LSB are dedicated for the PS mode. - * The 16 MSB are dedicated for the PS mode. - * cont_miss_bcns_spread[0] - single missed beacon. - * cont_miss_bcns_spread[1] - two continuous missed beacons. - * cont_miss_bcns_spread[2] - three continuous missed beacons. - * ... - * cont_miss_bcns_spread[9] - ten and more continuous missed beacons. - */ - __le32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD]; - - /* the number of beacons in awake mode */ - __le32 rcvd_awake_beacons; -} __packed; - -struct acx_mic_statistics { - __le32 rx_pkts; - __le32 calc_failure; -} __packed; - -struct acx_aes_statistics { - __le32 encrypt_fail; - __le32 decrypt_fail; - __le32 encrypt_packets; - __le32 decrypt_packets; - __le32 encrypt_interrupt; - __le32 decrypt_interrupt; -} __packed; - -struct acx_event_statistics { - __le32 heart_beat; - __le32 calibration; - __le32 rx_mismatch; - __le32 rx_mem_empty; - __le32 rx_pool; - __le32 oom_late; - __le32 phy_transmit_error; - __le32 tx_stuck; -} __packed; - -struct acx_ps_statistics { - __le32 pspoll_timeouts; - __le32 upsd_timeouts; - __le32 upsd_max_sptime; - __le32 upsd_max_apturn; - __le32 pspoll_max_apturn; - __le32 pspoll_utilization; - __le32 upsd_utilization; -} __packed; - -struct acx_rxpipe_statistics { - __le32 rx_prep_beacon_drop; - __le32 descr_host_int_trig_rx_data; - __le32 beacon_buffer_thres_host_int_trig_rx_data; - __le32 missed_beacon_host_int_trig_rx_data; - __le32 tx_xfr_host_int_trig_rx_data; -} __packed; - -struct acx_statistics { - struct acx_header header; - - struct acx_tx_statistics tx; - struct acx_rx_statistics rx; - struct acx_dma_statistics dma; - struct acx_isr_statistics isr; - struct acx_wep_statistics wep; - struct acx_pwr_statistics pwr; - struct acx_aes_statistics aes; - struct acx_mic_statistics mic; - struct acx_event_statistics event; - struct acx_ps_statistics ps; - struct acx_rxpipe_statistics rxpipe; -} __packed; - -struct acx_rate_class { - __le32 enabled_rates; - u8 short_retry_limit; - u8 long_retry_limit; - u8 aflags; - u8 reserved; -}; - -struct acx_rate_policy { - struct acx_header header; - - __le32 rate_policy_idx; - struct acx_rate_class rate_policy; -} __packed; - -struct acx_ac_cfg { - struct acx_header header; - u8 role_id; - u8 ac; - u8 aifsn; - u8 cw_min; - __le16 cw_max; - __le16 tx_op_limit; -} __packed; - -struct acx_tid_config { - struct acx_header header; - u8 role_id; - u8 queue_id; - u8 channel_type; - u8 tsid; - u8 ps_scheme; - u8 ack_policy; - u8 padding[2]; - __le32 apsd_conf[2]; -} __packed; - -struct acx_frag_threshold { - struct acx_header header; - __le16 frag_threshold; - u8 padding[2]; -} __packed; - -struct acx_tx_config_options { - struct acx_header header; - __le16 tx_compl_timeout; /* msec */ - __le16 tx_compl_threshold; /* number of packets */ -} __packed; - -struct wl12xx_acx_config_memory { - struct acx_header header; - - u8 rx_mem_block_num; - u8 tx_min_mem_block_num; - u8 num_stations; - u8 num_ssid_profiles; - __le32 total_tx_descriptors; - u8 dyn_mem_enable; - u8 tx_free_req; - u8 rx_free_req; - u8 tx_min; - u8 fwlog_blocks; - u8 padding[3]; -} __packed; - -struct wl1271_acx_mem_map { - struct acx_header header; - - __le32 code_start; - __le32 code_end; - - __le32 wep_defkey_start; - __le32 wep_defkey_end; - - __le32 sta_table_start; - __le32 sta_table_end; - - __le32 packet_template_start; - __le32 packet_template_end; - - /* Address of the TX result interface (control block) */ - __le32 tx_result; - __le32 tx_result_queue_start; - - __le32 queue_memory_start; - __le32 queue_memory_end; - - __le32 packet_memory_pool_start; - __le32 packet_memory_pool_end; - - __le32 debug_buffer1_start; - __le32 debug_buffer1_end; - - __le32 debug_buffer2_start; - __le32 debug_buffer2_end; - - /* Number of blocks FW allocated for TX packets */ - __le32 num_tx_mem_blocks; - - /* Number of blocks FW allocated for RX packets */ - __le32 num_rx_mem_blocks; - - /* the following 4 fields are valid in SLAVE mode only */ - u8 *tx_cbuf; - u8 *rx_cbuf; - __le32 rx_ctrl; - __le32 tx_ctrl; -} __packed; - -struct wl1271_acx_rx_config_opt { - struct acx_header header; - - __le16 mblk_threshold; - __le16 threshold; - __le16 timeout; - u8 queue_type; - u8 reserved; -} __packed; - - -struct wl1271_acx_bet_enable { - struct acx_header header; - - u8 role_id; - u8 enable; - u8 max_consecutive; - u8 padding[1]; -} __packed; - -#define ACX_IPV4_VERSION 4 -#define ACX_IPV6_VERSION 6 -#define ACX_IPV4_ADDR_SIZE 4 - -/* bitmap of enabled arp_filter features */ -#define ACX_ARP_FILTER_ARP_FILTERING BIT(0) -#define ACX_ARP_FILTER_AUTO_ARP BIT(1) - -struct wl1271_acx_arp_filter { - struct acx_header header; - u8 role_id; - u8 version; /* ACX_IPV4_VERSION, ACX_IPV6_VERSION */ - u8 enable; /* bitmap of enabled ARP filtering features */ - u8 padding[1]; - u8 address[16]; /* The configured device IP address - all ARP - requests directed to this IP address will pass - through. For IPv4, the first four bytes are - used. */ -} __packed; - -struct wl1271_acx_pm_config { - struct acx_header header; - - __le32 host_clk_settling_time; - u8 host_fast_wakeup_support; - u8 padding[3]; -} __packed; - -struct wl1271_acx_keep_alive_mode { - struct acx_header header; - - u8 role_id; - u8 enabled; - u8 padding[2]; -} __packed; - -enum { - ACX_KEEP_ALIVE_NO_TX = 0, - ACX_KEEP_ALIVE_PERIOD_ONLY -}; - -enum { - ACX_KEEP_ALIVE_TPL_INVALID = 0, - ACX_KEEP_ALIVE_TPL_VALID -}; - -struct wl1271_acx_keep_alive_config { - struct acx_header header; - - u8 role_id; - u8 index; - u8 tpl_validation; - u8 trigger; - __le32 period; -} __packed; - -#define HOST_IF_CFG_RX_FIFO_ENABLE BIT(0) -#define HOST_IF_CFG_TX_EXTRA_BLKS_SWAP BIT(1) -#define HOST_IF_CFG_TX_PAD_TO_SDIO_BLK BIT(3) - -struct wl1271_acx_host_config_bitmap { - struct acx_header header; - - __le32 host_cfg_bitmap; -} __packed; - -enum { - WL1271_ACX_TRIG_TYPE_LEVEL = 0, - WL1271_ACX_TRIG_TYPE_EDGE, -}; - -enum { - WL1271_ACX_TRIG_DIR_LOW = 0, - WL1271_ACX_TRIG_DIR_HIGH, - WL1271_ACX_TRIG_DIR_BIDIR, -}; - -enum { - WL1271_ACX_TRIG_ENABLE = 1, - WL1271_ACX_TRIG_DISABLE, -}; - -enum { - WL1271_ACX_TRIG_METRIC_RSSI_BEACON = 0, - WL1271_ACX_TRIG_METRIC_RSSI_DATA, - WL1271_ACX_TRIG_METRIC_SNR_BEACON, - WL1271_ACX_TRIG_METRIC_SNR_DATA, -}; - -enum { - WL1271_ACX_TRIG_IDX_RSSI = 0, - WL1271_ACX_TRIG_COUNT = 8, -}; - -struct wl1271_acx_rssi_snr_trigger { - struct acx_header header; - - u8 role_id; - u8 metric; - u8 type; - u8 dir; - __le16 threshold; - __le16 pacing; /* 0 - 60000 ms */ - u8 hysteresis; - u8 index; - u8 enable; - u8 padding[1]; -}; - -struct wl1271_acx_rssi_snr_avg_weights { - struct acx_header header; - - u8 role_id; - u8 padding[3]; - u8 rssi_beacon; - u8 rssi_data; - u8 snr_beacon; - u8 snr_data; -}; - - -/* special capability bit (not employed by the 802.11n spec) */ -#define WL12XX_HT_CAP_HT_OPERATION BIT(16) - -/* - * ACX_PEER_HT_CAP - * Configure HT capabilities - declare the capabilities of the peer - * we are connected to. - */ -struct wl1271_acx_ht_capabilities { - struct acx_header header; - - /* bitmask of capability bits supported by the peer */ - __le32 ht_capabilites; - - /* Indicates to which link these capabilities apply. */ - u8 hlid; - - /* - * This the maximum A-MPDU length supported by the AP. The FW may not - * exceed this length when sending A-MPDUs - */ - u8 ampdu_max_length; - - /* This is the minimal spacing required when sending A-MPDUs to the AP*/ - u8 ampdu_min_spacing; - - u8 padding; -} __packed; - -/* - * ACX_HT_BSS_OPERATION - * Configure HT capabilities - AP rules for behavior in the BSS. - */ -struct wl1271_acx_ht_information { - struct acx_header header; - - u8 role_id; - - /* Values: 0 - RIFS not allowed, 1 - RIFS allowed */ - u8 rifs_mode; - - /* Values: 0 - 3 like in spec */ - u8 ht_protection; - - /* Values: 0 - GF protection not required, 1 - GF protection required */ - u8 gf_protection; - - /*Values: 0 - TX Burst limit not required, 1 - TX Burst Limit required*/ - u8 ht_tx_burst_limit; - - /* - * Values: 0 - Dual CTS protection not required, - * 1 - Dual CTS Protection required - * Note: When this value is set to 1 FW will protect all TXOP with RTS - * frame and will not use CTS-to-self regardless of the value of the - * ACX_CTS_PROTECTION information element - */ - u8 dual_cts_protection; - - u8 padding[2]; -} __packed; - -#define RX_BA_MAX_SESSIONS 2 - -struct wl1271_acx_ba_initiator_policy { - struct acx_header header; - - /* Specifies role Id, Range 0-7, 0xFF means ANY role. */ - u8 role_id; - - /* - * Per TID setting for allowing TX BA. Set a bit to 1 to allow - * TX BA sessions for the corresponding TID. - */ - u8 tid_bitmap; - - /* Windows size in number of packets */ - u8 win_size; - - u8 padding1[1]; - - /* As initiator inactivity timeout in time units(TU) of 1024us */ - u16 inactivity_timeout; - - u8 padding[2]; -} __packed; - -struct wl1271_acx_ba_receiver_setup { - struct acx_header header; - - /* Specifies link id, range 0-31 */ - u8 hlid; - - u8 tid; - - u8 enable; - - /* Windows size in number of packets */ - u8 win_size; - - /* BA session starting sequence number. RANGE 0-FFF */ - u16 ssn; - - u8 padding[2]; -} __packed; - -struct wl12xx_acx_fw_tsf_information { - struct acx_header header; - - u8 role_id; - u8 padding1[3]; - __le32 current_tsf_high; - __le32 current_tsf_low; - __le32 last_bttt_high; - __le32 last_tbtt_low; - u8 last_dtim_count; - u8 padding2[3]; -} __packed; - -struct wl1271_acx_ps_rx_streaming { - struct acx_header header; - - u8 role_id; - u8 tid; - u8 enable; - - /* interval between triggers (10-100 msec) */ - u8 period; - - /* timeout before first trigger (0-200 msec) */ - u8 timeout; - u8 padding[3]; -} __packed; - -struct wl1271_acx_ap_max_tx_retry { - struct acx_header header; - - u8 role_id; - u8 padding_1; - - /* - * the number of frames transmission failures before - * issuing the aging event. - */ - __le16 max_tx_retry; -} __packed; - -struct wl1271_acx_config_ps { - struct acx_header header; - - u8 exit_retries; - u8 enter_retries; - u8 padding[2]; - __le32 null_data_rate; -} __packed; - -struct wl1271_acx_inconnection_sta { - struct acx_header header; - - u8 addr[ETH_ALEN]; - u8 padding1[2]; -} __packed; - -/* - * ACX_FM_COEX_CFG - * set the FM co-existence parameters. - */ -struct wl1271_acx_fm_coex { - struct acx_header header; - /* enable(1) / disable(0) the FM Coex feature */ - u8 enable; - /* - * Swallow period used in COEX PLL swallowing mechanism. - * 0xFF = use FW default - */ - u8 swallow_period; - /* - * The N divider used in COEX PLL swallowing mechanism for Fref of - * 38.4/19.2 Mhz. 0xFF = use FW default - */ - u8 n_divider_fref_set_1; - /* - * The N divider used in COEX PLL swallowing mechanism for Fref of - * 26/52 Mhz. 0xFF = use FW default - */ - u8 n_divider_fref_set_2; - /* - * The M divider used in COEX PLL swallowing mechanism for Fref of - * 38.4/19.2 Mhz. 0xFFFF = use FW default - */ - __le16 m_divider_fref_set_1; - /* - * The M divider used in COEX PLL swallowing mechanism for Fref of - * 26/52 Mhz. 0xFFFF = use FW default - */ - __le16 m_divider_fref_set_2; - /* - * The time duration in uSec required for COEX PLL to stabilize. - * 0xFFFFFFFF = use FW default - */ - __le32 coex_pll_stabilization_time; - /* - * The time duration in uSec required for LDO to stabilize. - * 0xFFFFFFFF = use FW default - */ - __le16 ldo_stabilization_time; - /* - * The disturbed frequency band margin around the disturbed frequency - * center (single sided). - * For example, if 2 is configured, the following channels will be - * considered disturbed channel: - * 80 +- 0.1 MHz, 91 +- 0.1 MHz, 98 +- 0.1 MHz, 102 +- 0.1 MH - * 0xFF = use FW default - */ - u8 fm_disturbed_band_margin; - /* - * The swallow clock difference of the swallowing mechanism. - * 0xFF = use FW default - */ - u8 swallow_clk_diff; -} __packed; - -#define ACX_RATE_MGMT_ALL_PARAMS 0xff -struct wl12xx_acx_set_rate_mgmt_params { - struct acx_header header; - - u8 index; /* 0xff to configure all params */ - u8 padding1; - __le16 rate_retry_score; - __le16 per_add; - __le16 per_th1; - __le16 per_th2; - __le16 max_per; - u8 inverse_curiosity_factor; - u8 tx_fail_low_th; - u8 tx_fail_high_th; - u8 per_alpha_shift; - u8 per_add_shift; - u8 per_beta1_shift; - u8 per_beta2_shift; - u8 rate_check_up; - u8 rate_check_down; - u8 rate_retry_policy[ACX_RATE_MGMT_NUM_OF_RATES]; - u8 padding2[2]; -} __packed; - -struct wl12xx_acx_config_hangover { - struct acx_header header; - - __le32 recover_time; - u8 hangover_period; - u8 dynamic_mode; - u8 early_termination_mode; - u8 max_period; - u8 min_period; - u8 increase_delta; - u8 decrease_delta; - u8 quiet_time; - u8 increase_time; - u8 window_size; - u8 padding[2]; -} __packed; - -enum { - ACX_WAKE_UP_CONDITIONS = 0x0000, - ACX_MEM_CFG = 0x0001, - ACX_SLOT = 0x0002, - ACX_AC_CFG = 0x0003, - ACX_MEM_MAP = 0x0004, - ACX_AID = 0x0005, - ACX_MEDIUM_USAGE = 0x0006, - ACX_STATISTICS = 0x0007, - ACX_PWR_CONSUMPTION_STATISTICS = 0x0008, - ACX_TID_CFG = 0x0009, - ACX_PS_RX_STREAMING = 0x000A, - ACX_BEACON_FILTER_OPT = 0x000B, - ACX_NOISE_HIST = 0x000C, - ACX_HDK_VERSION = 0x000D, - ACX_PD_THRESHOLD = 0x000E, - ACX_TX_CONFIG_OPT = 0x000F, - ACX_CCA_THRESHOLD = 0x0010, - ACX_EVENT_MBOX_MASK = 0x0011, - ACX_CONN_MONIT_PARAMS = 0x0012, - ACX_DISABLE_BROADCASTS = 0x0013, - ACX_BCN_DTIM_OPTIONS = 0x0014, - ACX_SG_ENABLE = 0x0015, - ACX_SG_CFG = 0x0016, - ACX_FM_COEX_CFG = 0x0017, - ACX_BEACON_FILTER_TABLE = 0x0018, - ACX_ARP_IP_FILTER = 0x0019, - ACX_ROAMING_STATISTICS_TBL = 0x001A, - ACX_RATE_POLICY = 0x001B, - ACX_CTS_PROTECTION = 0x001C, - ACX_SLEEP_AUTH = 0x001D, - ACX_PREAMBLE_TYPE = 0x001E, - ACX_ERROR_CNT = 0x001F, - ACX_IBSS_FILTER = 0x0020, - ACX_SERVICE_PERIOD_TIMEOUT = 0x0021, - ACX_TSF_INFO = 0x0022, - ACX_CONFIG_PS_WMM = 0x0023, - ACX_ENABLE_RX_DATA_FILTER = 0x0024, - ACX_SET_RX_DATA_FILTER = 0x0025, - ACX_GET_DATA_FILTER_STATISTICS = 0x0026, - ACX_RX_CONFIG_OPT = 0x0027, - ACX_FRAG_CFG = 0x0028, - ACX_BET_ENABLE = 0x0029, - ACX_RSSI_SNR_TRIGGER = 0x002A, - ACX_RSSI_SNR_WEIGHTS = 0x002B, - ACX_KEEP_ALIVE_MODE = 0x002C, - ACX_SET_KEEP_ALIVE_CONFIG = 0x002D, - ACX_BA_SESSION_INIT_POLICY = 0x002E, - ACX_BA_SESSION_RX_SETUP = 0x002F, - ACX_PEER_HT_CAP = 0x0030, - ACX_HT_BSS_OPERATION = 0x0031, - ACX_COEX_ACTIVITY = 0x0032, - ACX_BURST_MODE = 0x0033, - ACX_SET_RATE_MGMT_PARAMS = 0x0034, - ACX_GET_RATE_MGMT_PARAMS = 0x0035, - ACX_SET_RATE_ADAPT_PARAMS = 0x0036, - ACX_SET_DCO_ITRIM_PARAMS = 0x0037, - ACX_GEN_FW_CMD = 0x0038, - ACX_HOST_IF_CFG_BITMAP = 0x0039, - ACX_MAX_TX_FAILURE = 0x003A, - ACX_UPDATE_INCONNECTION_STA_LIST = 0x003B, - DOT11_RX_MSDU_LIFE_TIME = 0x003C, - DOT11_CUR_TX_PWR = 0x003D, - DOT11_RTS_THRESHOLD = 0x003E, - DOT11_GROUP_ADDRESS_TBL = 0x003F, - ACX_PM_CONFIG = 0x0040, - ACX_CONFIG_PS = 0x0041, - ACX_CONFIG_HANGOVER = 0x0042, - ACX_FEATURE_CFG = 0x0043, - ACX_PROTECTION_CFG = 0x0044, -}; - - -int wl1271_acx_wake_up_conditions(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - u8 wake_up_event, u8 listen_interval); -int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth); -int wl1271_acx_tx_power(struct wl1271 *wl, struct wl12xx_vif *wlvif, - int power); -int wl1271_acx_feature_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif); -int wl1271_acx_mem_map(struct wl1271 *wl, - struct acx_header *mem_map, size_t len); -int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl); -int wl1271_acx_slot(struct wl1271 *wl, struct wl12xx_vif *wlvif, - enum acx_slot_type slot_time); -int wl1271_acx_group_address_tbl(struct wl1271 *wl, struct wl12xx_vif *wlvif, - bool enable, void *mc_list, u32 mc_list_len); -int wl1271_acx_service_period_timeout(struct wl1271 *wl, - struct wl12xx_vif *wlvif); -int wl1271_acx_rts_threshold(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u32 rts_threshold); -int wl1271_acx_dco_itrim_params(struct wl1271 *wl); -int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, struct wl12xx_vif *wlvif, - bool enable_filter); -int wl1271_acx_beacon_filter_table(struct wl1271 *wl, - struct wl12xx_vif *wlvif); -int wl1271_acx_conn_monit_params(struct wl1271 *wl, struct wl12xx_vif *wlvif, - bool enable); -int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable); -int wl12xx_acx_sg_cfg(struct wl1271 *wl); -int wl1271_acx_cca_threshold(struct wl1271 *wl); -int wl1271_acx_bcn_dtim_options(struct wl1271 *wl, struct wl12xx_vif *wlvif); -int wl1271_acx_aid(struct wl1271 *wl, struct wl12xx_vif *wlvif, u16 aid); -int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask); -int wl1271_acx_set_preamble(struct wl1271 *wl, struct wl12xx_vif *wlvif, - enum acx_preamble_type preamble); -int wl1271_acx_cts_protect(struct wl1271 *wl, struct wl12xx_vif *wlvif, - enum acx_ctsprotect_type ctsprotect); -int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats); -int wl1271_acx_sta_rate_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif); -int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c, - u8 idx); -int wl1271_acx_ac_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 ac, u8 cw_min, u16 cw_max, u8 aifsn, u16 txop); -int wl1271_acx_tid_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 queue_id, u8 channel_type, - u8 tsid, u8 ps_scheme, u8 ack_policy, - u32 apsd_conf0, u32 apsd_conf1); -int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold); -int wl1271_acx_tx_config_options(struct wl1271 *wl); -int wl12xx_acx_mem_cfg(struct wl1271 *wl); -int wl1271_acx_init_mem_config(struct wl1271 *wl); -int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap); -int wl1271_acx_init_rx_interrupt(struct wl1271 *wl); -int wl1271_acx_smart_reflex(struct wl1271 *wl); -int wl1271_acx_bet_enable(struct wl1271 *wl, struct wl12xx_vif *wlvif, - bool enable); -int wl1271_acx_arp_ip_filter(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 enable, __be32 address); -int wl1271_acx_pm_config(struct wl1271 *wl); -int wl1271_acx_keep_alive_mode(struct wl1271 *wl, struct wl12xx_vif *vif, - bool enable); -int wl1271_acx_keep_alive_config(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 index, u8 tpl_valid); -int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, struct wl12xx_vif *wlvif, - bool enable, s16 thold, u8 hyst); -int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl, - struct wl12xx_vif *wlvif); -int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, - struct ieee80211_sta_ht_cap *ht_cap, - bool allow_ht_operation, u8 hlid); -int wl1271_acx_set_ht_information(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - u16 ht_operation_mode); -int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl, - struct wl12xx_vif *wlvif); -int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, - u16 ssn, bool enable, u8 peer_hlid); -int wl12xx_acx_tsf_info(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u64 *mactime); -int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif, - bool enable); -int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl, struct wl12xx_vif *wlvif); -int wl12xx_acx_config_ps(struct wl1271 *wl, struct wl12xx_vif *wlvif); -int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr); -int wl1271_acx_fm_coex(struct wl1271 *wl); -int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl); -int wl12xx_acx_config_hangover(struct wl1271 *wl); - -#endif /* __WL1271_ACX_H__ */ diff --git a/trunk/drivers/net/wireless/wl12xx/boot.c b/trunk/drivers/net/wireless/wl12xx/boot.c deleted file mode 100644 index 954101d03f06..000000000000 --- a/trunk/drivers/net/wireless/wl12xx/boot.c +++ /dev/null @@ -1,786 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2008-2010 Nokia Corporation - * - * Contact: Luciano Coelho - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include -#include - -#include "debug.h" -#include "acx.h" -#include "reg.h" -#include "boot.h" -#include "io.h" -#include "event.h" -#include "rx.h" - -static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag) -{ - u32 cpu_ctrl; - - /* 10.5.0 run the firmware (I) */ - cpu_ctrl = wl1271_read32(wl, ACX_REG_ECPU_CONTROL); - - /* 10.5.1 run the firmware (II) */ - cpu_ctrl |= flag; - wl1271_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); -} - -static unsigned int wl12xx_get_fw_ver_quirks(struct wl1271 *wl) -{ - unsigned int quirks = 0; - unsigned int *fw_ver = wl->chip.fw_ver; - - /* Only new station firmwares support routing fw logs to the host */ - if ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) && - (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_FWLOG_STA_MIN)) - quirks |= WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED; - - /* This feature is not yet supported for AP mode */ - if (fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) - quirks |= WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED; - - return quirks; -} - -static void wl1271_parse_fw_ver(struct wl1271 *wl) -{ - int ret; - - ret = sscanf(wl->chip.fw_ver_str + 4, "%u.%u.%u.%u.%u", - &wl->chip.fw_ver[0], &wl->chip.fw_ver[1], - &wl->chip.fw_ver[2], &wl->chip.fw_ver[3], - &wl->chip.fw_ver[4]); - - if (ret != 5) { - wl1271_warning("fw version incorrect value"); - memset(wl->chip.fw_ver, 0, sizeof(wl->chip.fw_ver)); - return; - } - - /* Check if any quirks are needed with older fw versions */ - wl->quirks |= wl12xx_get_fw_ver_quirks(wl); -} - -static void wl1271_boot_fw_version(struct wl1271 *wl) -{ - struct wl1271_static_data static_data; - - wl1271_read(wl, wl->cmd_box_addr, &static_data, sizeof(static_data), - false); - - strncpy(wl->chip.fw_ver_str, static_data.fw_version, - sizeof(wl->chip.fw_ver_str)); - - /* make sure the string is NULL-terminated */ - wl->chip.fw_ver_str[sizeof(wl->chip.fw_ver_str) - 1] = '\0'; - - wl1271_parse_fw_ver(wl); -} - -static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, - size_t fw_data_len, u32 dest) -{ - struct wl1271_partition_set partition; - int addr, chunk_num, partition_limit; - u8 *p, *chunk; - - /* whal_FwCtrl_LoadFwImageSm() */ - - wl1271_debug(DEBUG_BOOT, "starting firmware upload"); - - wl1271_debug(DEBUG_BOOT, "fw_data_len %zd chunk_size %d", - fw_data_len, CHUNK_SIZE); - - if ((fw_data_len % 4) != 0) { - wl1271_error("firmware length not multiple of four"); - return -EIO; - } - - chunk = kmalloc(CHUNK_SIZE, GFP_KERNEL); - if (!chunk) { - wl1271_error("allocation for firmware upload chunk failed"); - return -ENOMEM; - } - - memcpy(&partition, &wl12xx_part_table[PART_DOWN], sizeof(partition)); - partition.mem.start = dest; - wl1271_set_partition(wl, &partition); - - /* 10.1 set partition limit and chunk num */ - chunk_num = 0; - partition_limit = wl12xx_part_table[PART_DOWN].mem.size; - - while (chunk_num < fw_data_len / CHUNK_SIZE) { - /* 10.2 update partition, if needed */ - addr = dest + (chunk_num + 2) * CHUNK_SIZE; - if (addr > partition_limit) { - addr = dest + chunk_num * CHUNK_SIZE; - partition_limit = chunk_num * CHUNK_SIZE + - wl12xx_part_table[PART_DOWN].mem.size; - partition.mem.start = addr; - wl1271_set_partition(wl, &partition); - } - - /* 10.3 upload the chunk */ - addr = dest + chunk_num * CHUNK_SIZE; - p = buf + chunk_num * CHUNK_SIZE; - memcpy(chunk, p, CHUNK_SIZE); - wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", - p, addr); - wl1271_write(wl, addr, chunk, CHUNK_SIZE, false); - - chunk_num++; - } - - /* 10.4 upload the last chunk */ - addr = dest + chunk_num * CHUNK_SIZE; - p = buf + chunk_num * CHUNK_SIZE; - memcpy(chunk, p, fw_data_len % CHUNK_SIZE); - wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x", - fw_data_len % CHUNK_SIZE, p, addr); - wl1271_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false); - - kfree(chunk); - return 0; -} - -static int wl1271_boot_upload_firmware(struct wl1271 *wl) -{ - u32 chunks, addr, len; - int ret = 0; - u8 *fw; - - fw = wl->fw; - chunks = be32_to_cpup((__be32 *) fw); - fw += sizeof(u32); - - wl1271_debug(DEBUG_BOOT, "firmware chunks to be uploaded: %u", chunks); - - while (chunks--) { - addr = be32_to_cpup((__be32 *) fw); - fw += sizeof(u32); - len = be32_to_cpup((__be32 *) fw); - fw += sizeof(u32); - - if (len > 300000) { - wl1271_info("firmware chunk too long: %u", len); - return -EINVAL; - } - wl1271_debug(DEBUG_BOOT, "chunk %d addr 0x%x len %u", - chunks, addr, len); - ret = wl1271_boot_upload_firmware_chunk(wl, fw, len, addr); - if (ret != 0) - break; - fw += len; - } - - return ret; -} - -static int wl1271_boot_upload_nvs(struct wl1271 *wl) -{ - size_t nvs_len, burst_len; - int i; - u32 dest_addr, val; - u8 *nvs_ptr, *nvs_aligned; - - if (wl->nvs == NULL) - return -ENODEV; - - if (wl->chip.id == CHIP_ID_1283_PG20) { - struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs; - - if (wl->nvs_len == sizeof(struct wl128x_nvs_file)) { - if (nvs->general_params.dual_mode_select) - wl->enable_11a = true; - } else { - wl1271_error("nvs size is not as expected: %zu != %zu", - wl->nvs_len, - sizeof(struct wl128x_nvs_file)); - kfree(wl->nvs); - wl->nvs = NULL; - wl->nvs_len = 0; - return -EILSEQ; - } - - /* only the first part of the NVS needs to be uploaded */ - nvs_len = sizeof(nvs->nvs); - nvs_ptr = (u8 *)nvs->nvs; - - } else { - struct wl1271_nvs_file *nvs = - (struct wl1271_nvs_file *)wl->nvs; - /* - * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz - * band configurations) can be removed when those NVS files stop - * floating around. - */ - if (wl->nvs_len == sizeof(struct wl1271_nvs_file) || - wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) { - if (nvs->general_params.dual_mode_select) - wl->enable_11a = true; - } - - if (wl->nvs_len != sizeof(struct wl1271_nvs_file) && - (wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE || - wl->enable_11a)) { - wl1271_error("nvs size is not as expected: %zu != %zu", - wl->nvs_len, sizeof(struct wl1271_nvs_file)); - kfree(wl->nvs); - wl->nvs = NULL; - wl->nvs_len = 0; - return -EILSEQ; - } - - /* only the first part of the NVS needs to be uploaded */ - nvs_len = sizeof(nvs->nvs); - nvs_ptr = (u8 *) nvs->nvs; - } - - /* update current MAC address to NVS */ - nvs_ptr[11] = wl->addresses[0].addr[0]; - nvs_ptr[10] = wl->addresses[0].addr[1]; - nvs_ptr[6] = wl->addresses[0].addr[2]; - nvs_ptr[5] = wl->addresses[0].addr[3]; - nvs_ptr[4] = wl->addresses[0].addr[4]; - nvs_ptr[3] = wl->addresses[0].addr[5]; - - /* - * Layout before the actual NVS tables: - * 1 byte : burst length. - * 2 bytes: destination address. - * n bytes: data to burst copy. - * - * This is ended by a 0 length, then the NVS tables. - */ - - /* FIXME: Do we need to check here whether the LSB is 1? */ - while (nvs_ptr[0]) { - burst_len = nvs_ptr[0]; - dest_addr = (nvs_ptr[1] & 0xfe) | ((u32)(nvs_ptr[2] << 8)); - - /* - * Due to our new wl1271_translate_reg_addr function, - * we need to add the REGISTER_BASE to the destination - */ - dest_addr += REGISTERS_BASE; - - /* We move our pointer to the data */ - nvs_ptr += 3; - - for (i = 0; i < burst_len; i++) { - if (nvs_ptr + 3 >= (u8 *) wl->nvs + nvs_len) - goto out_badnvs; - - val = (nvs_ptr[0] | (nvs_ptr[1] << 8) - | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); - - wl1271_debug(DEBUG_BOOT, - "nvs burst write 0x%x: 0x%x", - dest_addr, val); - wl1271_write32(wl, dest_addr, val); - - nvs_ptr += 4; - dest_addr += 4; - } - - if (nvs_ptr >= (u8 *) wl->nvs + nvs_len) - goto out_badnvs; - } - - /* - * We've reached the first zero length, the first NVS table - * is located at an aligned offset which is at least 7 bytes further. - * NOTE: The wl->nvs->nvs element must be first, in order to - * simplify the casting, we assume it is at the beginning of - * the wl->nvs structure. - */ - nvs_ptr = (u8 *)wl->nvs + - ALIGN(nvs_ptr - (u8 *)wl->nvs + 7, 4); - - if (nvs_ptr >= (u8 *) wl->nvs + nvs_len) - goto out_badnvs; - - nvs_len -= nvs_ptr - (u8 *)wl->nvs; - - /* Now we must set the partition correctly */ - wl1271_set_partition(wl, &wl12xx_part_table[PART_WORK]); - - /* Copy the NVS tables to a new block to ensure alignment */ - nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); - if (!nvs_aligned) - return -ENOMEM; - - /* And finally we upload the NVS tables */ - wl1271_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false); - - kfree(nvs_aligned); - return 0; - -out_badnvs: - wl1271_error("nvs data is malformed"); - return -EILSEQ; -} - -static void wl1271_boot_enable_interrupts(struct wl1271 *wl) -{ - wl1271_enable_interrupts(wl); - wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, - WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK)); - wl1271_write32(wl, HI_CFG, HI_CFG_DEF_VAL); -} - -static int wl1271_boot_soft_reset(struct wl1271 *wl) -{ - unsigned long timeout; - u32 boot_data; - - /* perform soft reset */ - wl1271_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); - - /* SOFT_RESET is self clearing */ - timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); - while (1) { - boot_data = wl1271_read32(wl, ACX_REG_SLV_SOFT_RESET); - wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); - if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) - break; - - if (time_after(jiffies, timeout)) { - /* 1.2 check pWhalBus->uSelfClearTime if the - * timeout was reached */ - wl1271_error("soft reset timeout"); - return -1; - } - - udelay(SOFT_RESET_STALL_TIME); - } - - /* disable Rx/Tx */ - wl1271_write32(wl, ENABLE, 0x0); - - /* disable auto calibration on start*/ - wl1271_write32(wl, SPARE_A2, 0xffff); - - return 0; -} - -static int wl1271_boot_run_firmware(struct wl1271 *wl) -{ - int loop, ret; - u32 chip_id, intr; - - wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); - - chip_id = wl1271_read32(wl, CHIP_ID_B); - - wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); - - if (chip_id != wl->chip.id) { - wl1271_error("chip id doesn't match after firmware boot"); - return -EIO; - } - - /* wait for init to complete */ - loop = 0; - while (loop++ < INIT_LOOP) { - udelay(INIT_LOOP_DELAY); - intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); - - if (intr == 0xffffffff) { - wl1271_error("error reading hardware complete " - "init indication"); - return -EIO; - } - /* check that ACX_INTR_INIT_COMPLETE is enabled */ - else if (intr & WL1271_ACX_INTR_INIT_COMPLETE) { - wl1271_write32(wl, ACX_REG_INTERRUPT_ACK, - WL1271_ACX_INTR_INIT_COMPLETE); - break; - } - } - - if (loop > INIT_LOOP) { - wl1271_error("timeout waiting for the hardware to " - "complete initialization"); - return -EIO; - } - - /* get hardware config command mail box */ - wl->cmd_box_addr = wl1271_read32(wl, REG_COMMAND_MAILBOX_PTR); - - /* get hardware config event mail box */ - wl->event_box_addr = wl1271_read32(wl, REG_EVENT_MAILBOX_PTR); - - /* set the working partition to its "running" mode offset */ - wl1271_set_partition(wl, &wl12xx_part_table[PART_WORK]); - - wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", - wl->cmd_box_addr, wl->event_box_addr); - - wl1271_boot_fw_version(wl); - - /* - * in case of full asynchronous mode the firmware event must be - * ready to receive event from the command mailbox - */ - - /* unmask required mbox events */ - wl->event_mask = BSS_LOSE_EVENT_ID | - SCAN_COMPLETE_EVENT_ID | - ROLE_STOP_COMPLETE_EVENT_ID | - RSSI_SNR_TRIGGER_0_EVENT_ID | - PSPOLL_DELIVERY_FAILURE_EVENT_ID | - SOFT_GEMINI_SENSE_EVENT_ID | - PERIODIC_SCAN_REPORT_EVENT_ID | - PERIODIC_SCAN_COMPLETE_EVENT_ID | - DUMMY_PACKET_EVENT_ID | - PEER_REMOVE_COMPLETE_EVENT_ID | - BA_SESSION_RX_CONSTRAINT_EVENT_ID | - REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID | - INACTIVE_STA_EVENT_ID | - MAX_TX_RETRY_EVENT_ID | - CHANNEL_SWITCH_COMPLETE_EVENT_ID; - - ret = wl1271_event_unmask(wl); - if (ret < 0) { - wl1271_error("EVENT mask setting failed"); - return ret; - } - - wl1271_event_mbox_config(wl); - - /* firmware startup completed */ - return 0; -} - -static int wl1271_boot_write_irq_polarity(struct wl1271 *wl) -{ - u32 polarity; - - polarity = wl1271_top_reg_read(wl, OCP_REG_POLARITY); - - /* We use HIGH polarity, so unset the LOW bit */ - polarity &= ~POLARITY_LOW; - wl1271_top_reg_write(wl, OCP_REG_POLARITY, polarity); - - return 0; -} - -static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl) -{ - u16 spare_reg; - - /* Mask bits [2] & [8:4] in the sys_clk_cfg register */ - spare_reg = wl1271_top_reg_read(wl, WL_SPARE_REG); - if (spare_reg == 0xFFFF) - return -EFAULT; - spare_reg |= (BIT(3) | BIT(5) | BIT(6)); - wl1271_top_reg_write(wl, WL_SPARE_REG, spare_reg); - - /* Enable FREF_CLK_REQ & mux MCS and coex PLLs to FREF */ - wl1271_top_reg_write(wl, SYS_CLK_CFG_REG, - WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF); - - /* Delay execution for 15msec, to let the HW settle */ - mdelay(15); - - return 0; -} - -static bool wl128x_is_tcxo_valid(struct wl1271 *wl) -{ - u16 tcxo_detection; - - tcxo_detection = wl1271_top_reg_read(wl, TCXO_CLK_DETECT_REG); - if (tcxo_detection & TCXO_DET_FAILED) - return false; - - return true; -} - -static bool wl128x_is_fref_valid(struct wl1271 *wl) -{ - u16 fref_detection; - - fref_detection = wl1271_top_reg_read(wl, FREF_CLK_DETECT_REG); - if (fref_detection & FREF_CLK_DETECT_FAIL) - return false; - - return true; -} - -static int wl128x_manually_configure_mcs_pll(struct wl1271 *wl) -{ - wl1271_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL); - wl1271_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL); - wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, MCS_PLL_CONFIG_REG_VAL); - - return 0; -} - -static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk) -{ - u16 spare_reg; - u16 pll_config; - u8 input_freq; - - /* Mask bits [3:1] in the sys_clk_cfg register */ - spare_reg = wl1271_top_reg_read(wl, WL_SPARE_REG); - if (spare_reg == 0xFFFF) - return -EFAULT; - spare_reg |= BIT(2); - wl1271_top_reg_write(wl, WL_SPARE_REG, spare_reg); - - /* Handle special cases of the TCXO clock */ - if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_8 || - wl->tcxo_clock == WL12XX_TCXOCLOCK_33_6) - return wl128x_manually_configure_mcs_pll(wl); - - /* Set the input frequency according to the selected clock source */ - input_freq = (clk & 1) + 1; - - pll_config = wl1271_top_reg_read(wl, MCS_PLL_CONFIG_REG); - if (pll_config == 0xFFFF) - return -EFAULT; - pll_config |= (input_freq << MCS_SEL_IN_FREQ_SHIFT); - pll_config |= MCS_PLL_ENABLE_HP; - wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, pll_config); - - return 0; -} - -/* - * WL128x has two clocks input - TCXO and FREF. - * TCXO is the main clock of the device, while FREF is used to sync - * between the GPS and the cellular modem. - * In cases where TCXO is 32.736MHz or 16.368MHz, the FREF will be used - * as the WLAN/BT main clock. - */ -static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock) -{ - u16 sys_clk_cfg; - - /* For XTAL-only modes, FREF will be used after switching from TCXO */ - if (wl->ref_clock == WL12XX_REFCLOCK_26_XTAL || - wl->ref_clock == WL12XX_REFCLOCK_38_XTAL) { - if (!wl128x_switch_tcxo_to_fref(wl)) - return -EINVAL; - goto fref_clk; - } - - /* Query the HW, to determine which clock source we should use */ - sys_clk_cfg = wl1271_top_reg_read(wl, SYS_CLK_CFG_REG); - if (sys_clk_cfg == 0xFFFF) - return -EINVAL; - if (sys_clk_cfg & PRCM_CM_EN_MUX_WLAN_FREF) - goto fref_clk; - - /* If TCXO is either 32.736MHz or 16.368MHz, switch to FREF */ - if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_368 || - wl->tcxo_clock == WL12XX_TCXOCLOCK_32_736) { - if (!wl128x_switch_tcxo_to_fref(wl)) - return -EINVAL; - goto fref_clk; - } - - /* TCXO clock is selected */ - if (!wl128x_is_tcxo_valid(wl)) - return -EINVAL; - *selected_clock = wl->tcxo_clock; - goto config_mcs_pll; - -fref_clk: - /* FREF clock is selected */ - if (!wl128x_is_fref_valid(wl)) - return -EINVAL; - *selected_clock = wl->ref_clock; - -config_mcs_pll: - return wl128x_configure_mcs_pll(wl, *selected_clock); -} - -static int wl127x_boot_clk(struct wl1271 *wl) -{ - u32 pause; - u32 clk; - - if (WL127X_PG_GET_MAJOR(wl->hw_pg_ver) < 3) - wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION; - - if (wl->ref_clock == CONF_REF_CLK_19_2_E || - wl->ref_clock == CONF_REF_CLK_38_4_E || - wl->ref_clock == CONF_REF_CLK_38_4_M_XTAL) - /* ref clk: 19.2/38.4/38.4-XTAL */ - clk = 0x3; - else if (wl->ref_clock == CONF_REF_CLK_26_E || - wl->ref_clock == CONF_REF_CLK_52_E) - /* ref clk: 26/52 */ - clk = 0x5; - else - return -EINVAL; - - if (wl->ref_clock != CONF_REF_CLK_19_2_E) { - u16 val; - /* Set clock type (open drain) */ - val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE); - val &= FREF_CLK_TYPE_BITS; - wl1271_top_reg_write(wl, OCP_REG_CLK_TYPE, val); - - /* Set clock pull mode (no pull) */ - val = wl1271_top_reg_read(wl, OCP_REG_CLK_PULL); - val |= NO_PULL; - wl1271_top_reg_write(wl, OCP_REG_CLK_PULL, val); - } else { - u16 val; - /* Set clock polarity */ - val = wl1271_top_reg_read(wl, OCP_REG_CLK_POLARITY); - val &= FREF_CLK_POLARITY_BITS; - val |= CLK_REQ_OUTN_SEL; - wl1271_top_reg_write(wl, OCP_REG_CLK_POLARITY, val); - } - - wl1271_write32(wl, PLL_PARAMETERS, clk); - - pause = wl1271_read32(wl, PLL_PARAMETERS); - - wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause); - - pause &= ~(WU_COUNTER_PAUSE_VAL); - pause |= WU_COUNTER_PAUSE_VAL; - wl1271_write32(wl, WU_COUNTER_PAUSE, pause); - - return 0; -} - -/* uploads NVS and firmware */ -int wl1271_load_firmware(struct wl1271 *wl) -{ - int ret = 0; - u32 tmp, clk; - int selected_clock = -1; - - if (wl->chip.id == CHIP_ID_1283_PG20) { - ret = wl128x_boot_clk(wl, &selected_clock); - if (ret < 0) - goto out; - } else { - ret = wl127x_boot_clk(wl); - if (ret < 0) - goto out; - } - - /* Continue the ELP wake up sequence */ - wl1271_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); - udelay(500); - - wl1271_set_partition(wl, &wl12xx_part_table[PART_DRPW]); - - /* Read-modify-write DRPW_SCRATCH_START register (see next state) - to be used by DRPw FW. The RTRIM value will be added by the FW - before taking DRPw out of reset */ - - wl1271_debug(DEBUG_BOOT, "DRPW_SCRATCH_START %08x", DRPW_SCRATCH_START); - clk = wl1271_read32(wl, DRPW_SCRATCH_START); - - wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); - - if (wl->chip.id == CHIP_ID_1283_PG20) { - clk |= ((selected_clock & 0x3) << 1) << 4; - } else { - clk |= (wl->ref_clock << 1) << 4; - } - - wl1271_write32(wl, DRPW_SCRATCH_START, clk); - - wl1271_set_partition(wl, &wl12xx_part_table[PART_WORK]); - - /* Disable interrupts */ - wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); - - ret = wl1271_boot_soft_reset(wl); - if (ret < 0) - goto out; - - /* 2. start processing NVS file */ - ret = wl1271_boot_upload_nvs(wl); - if (ret < 0) - goto out; - - /* write firmware's last address (ie. it's length) to - * ACX_EEPROMLESS_IND_REG */ - wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG"); - - wl1271_write32(wl, ACX_EEPROMLESS_IND_REG, ACX_EEPROMLESS_IND_REG); - - tmp = wl1271_read32(wl, CHIP_ID_B); - - wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp); - - /* 6. read the EEPROM parameters */ - tmp = wl1271_read32(wl, SCR_PAD2); - - /* WL1271: The reference driver skips steps 7 to 10 (jumps directly - * to upload_fw) */ - - if (wl->chip.id == CHIP_ID_1283_PG20) - wl1271_top_reg_write(wl, SDIO_IO_DS, wl->conf.hci_io_ds); - - ret = wl1271_boot_upload_firmware(wl); - if (ret < 0) - goto out; - -out: - return ret; -} -EXPORT_SYMBOL_GPL(wl1271_load_firmware); - -int wl1271_boot(struct wl1271 *wl) -{ - int ret; - - /* upload NVS and firmware */ - ret = wl1271_load_firmware(wl); - if (ret) - return ret; - - /* 10.5 start firmware */ - ret = wl1271_boot_run_firmware(wl); - if (ret < 0) - goto out; - - ret = wl1271_boot_write_irq_polarity(wl); - if (ret < 0) - goto out; - - wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, - WL1271_ACX_ALL_EVENTS_VECTOR); - - /* Enable firmware interrupts now */ - wl1271_boot_enable_interrupts(wl); - - wl1271_event_mbox_config(wl); - -out: - return ret; -} diff --git a/trunk/drivers/net/wireless/wl12xx/boot.h b/trunk/drivers/net/wireless/wl12xx/boot.h deleted file mode 100644 index c3adc09f403d..000000000000 --- a/trunk/drivers/net/wireless/wl12xx/boot.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2008-2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __BOOT_H__ -#define __BOOT_H__ - -#include "wl12xx.h" - -int wl1271_boot(struct wl1271 *wl); -int wl1271_load_firmware(struct wl1271 *wl); - -#define WL1271_NO_SUBBANDS 8 -#define WL1271_NO_POWER_LEVELS 4 -#define WL1271_FW_VERSION_MAX_LEN 20 - -struct wl1271_static_data { - u8 mac_address[ETH_ALEN]; - u8 padding[2]; - u8 fw_version[WL1271_FW_VERSION_MAX_LEN]; - u32 hw_version; - u8 tx_power_table[WL1271_NO_SUBBANDS][WL1271_NO_POWER_LEVELS]; -}; - -/* number of times we try to read the INIT interrupt */ -#define INIT_LOOP 20000 - -/* delay between retries */ -#define INIT_LOOP_DELAY 50 - -#define WU_COUNTER_PAUSE_VAL 0x3FF -#define WELP_ARM_COMMAND_VAL 0x4 - -#define OCP_REG_POLARITY 0x0064 -#define OCP_REG_CLK_TYPE 0x0448 -#define OCP_REG_CLK_POLARITY 0x0cb2 -#define OCP_REG_CLK_PULL 0x0cb4 - -#define CMD_MBOX_ADDRESS 0x407B4 - -#define POLARITY_LOW BIT(1) -#define NO_PULL (BIT(14) | BIT(15)) - -#define FREF_CLK_TYPE_BITS 0xfffffe7f -#define CLK_REQ_PRCM 0x100 -#define FREF_CLK_POLARITY_BITS 0xfffff8ff -#define CLK_REQ_OUTN_SEL 0x700 - -/* PLL configuration algorithm for wl128x */ -#define SYS_CLK_CFG_REG 0x2200 -/* Bit[0] - 0-TCXO, 1-FREF */ -#define MCS_PLL_CLK_SEL_FREF BIT(0) -/* Bit[3:2] - 01-TCXO, 10-FREF */ -#define WL_CLK_REQ_TYPE_FREF BIT(3) -#define WL_CLK_REQ_TYPE_PG2 (BIT(3) | BIT(2)) -/* Bit[4] - 0-TCXO, 1-FREF */ -#define PRCM_CM_EN_MUX_WLAN_FREF BIT(4) - -#define TCXO_ILOAD_INT_REG 0x2264 -#define TCXO_CLK_DETECT_REG 0x2266 - -#define TCXO_DET_FAILED BIT(4) - -#define FREF_ILOAD_INT_REG 0x2084 -#define FREF_CLK_DETECT_REG 0x2086 -#define FREF_CLK_DETECT_FAIL BIT(4) - -/* Use this reg for masking during driver access */ -#define WL_SPARE_REG 0x2320 -#define WL_SPARE_VAL BIT(2) -/* Bit[6:5:3] - mask wl write SYS_CLK_CFG[8:5:2:4] */ -#define WL_SPARE_MASK_8526 (BIT(6) | BIT(5) | BIT(3)) - -#define PLL_LOCK_COUNTERS_REG 0xD8C -#define PLL_LOCK_COUNTERS_COEX 0x0F -#define PLL_LOCK_COUNTERS_MCS 0xF0 -#define MCS_PLL_OVERRIDE_REG 0xD90 -#define MCS_PLL_CONFIG_REG 0xD92 -#define MCS_SEL_IN_FREQ_MASK 0x0070 -#define MCS_SEL_IN_FREQ_SHIFT 4 -#define MCS_PLL_CONFIG_REG_VAL 0x73 -#define MCS_PLL_ENABLE_HP (BIT(0) | BIT(1)) - -#define MCS_PLL_M_REG 0xD94 -#define MCS_PLL_N_REG 0xD96 -#define MCS_PLL_M_REG_VAL 0xC8 -#define MCS_PLL_N_REG_VAL 0x07 - -#define SDIO_IO_DS 0xd14 - -/* SDIO/wSPI DS configuration values */ -enum { - HCI_IO_DS_8MA = 0, - HCI_IO_DS_4MA = 1, /* default */ - HCI_IO_DS_6MA = 2, - HCI_IO_DS_2MA = 3, -}; - -/* end PLL configuration algorithm for wl128x */ - -#endif diff --git a/trunk/drivers/net/wireless/wl12xx/cmd.c b/trunk/drivers/net/wireless/wl12xx/cmd.c deleted file mode 100644 index 3414fc11e9ba..000000000000 --- a/trunk/drivers/net/wireless/wl12xx/cmd.c +++ /dev/null @@ -1,1943 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2009-2010 Nokia Corporation - * - * Contact: Luciano Coelho - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include -#include -#include -#include -#include - -#include "wl12xx.h" -#include "debug.h" -#include "reg.h" -#include "io.h" -#include "acx.h" -#include "wl12xx_80211.h" -#include "cmd.h" -#include "event.h" -#include "tx.h" - -#define WL1271_CMD_FAST_POLL_COUNT 50 - -/* - * send command to firmware - * - * @wl: wl struct - * @id: command id - * @buf: buffer containing the command, must work with dma - * @len: length of the buffer - */ -int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, - size_t res_len) -{ - struct wl1271_cmd_header *cmd; - unsigned long timeout; - u32 intr; - int ret = 0; - u16 status; - u16 poll_count = 0; - - cmd = buf; - cmd->id = cpu_to_le16(id); - cmd->status = 0; - - WARN_ON(len % 4 != 0); - WARN_ON(test_bit(WL1271_FLAG_IN_ELP, &wl->flags)); - - wl1271_write(wl, wl->cmd_box_addr, buf, len, false); - - wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); - - timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); - - intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); - while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { - if (time_after(jiffies, timeout)) { - wl1271_error("command complete timeout"); - ret = -ETIMEDOUT; - goto fail; - } - - poll_count++; - if (poll_count < WL1271_CMD_FAST_POLL_COUNT) - udelay(10); - else - msleep(1); - - intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); - } - - /* read back the status code of the command */ - if (res_len == 0) - res_len = sizeof(struct wl1271_cmd_header); - wl1271_read(wl, wl->cmd_box_addr, cmd, res_len, false); - - status = le16_to_cpu(cmd->status); - if (status != CMD_STATUS_SUCCESS) { - wl1271_error("command execute failure %d", status); - ret = -EIO; - goto fail; - } - - wl1271_write32(wl, ACX_REG_INTERRUPT_ACK, - WL1271_ACX_INTR_CMD_COMPLETE); - return 0; - -fail: - WARN_ON(1); - wl12xx_queue_recovery_work(wl); - return ret; -} - -int wl1271_cmd_general_parms(struct wl1271 *wl) -{ - struct wl1271_general_parms_cmd *gen_parms; - struct wl1271_ini_general_params *gp = - &((struct wl1271_nvs_file *)wl->nvs)->general_params; - bool answer = false; - int ret; - - if (!wl->nvs) - return -ENODEV; - - if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { - wl1271_warning("FEM index from INI out of bounds"); - return -EINVAL; - } - - gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); - if (!gen_parms) - return -ENOMEM; - - gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; - - memcpy(&gen_parms->general_params, gp, sizeof(*gp)); - - if (gp->tx_bip_fem_auto_detect) - answer = true; - - /* Override the REF CLK from the NVS with the one from platform data */ - gen_parms->general_params.ref_clock = wl->ref_clock; - - ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); - if (ret < 0) { - wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); - goto out; - } - - gp->tx_bip_fem_manufacturer = - gen_parms->general_params.tx_bip_fem_manufacturer; - - if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { - wl1271_warning("FEM index from FW out of bounds"); - ret = -EINVAL; - goto out; - } - - wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", - answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer); - -out: - kfree(gen_parms); - return ret; -} - -int wl128x_cmd_general_parms(struct wl1271 *wl) -{ - struct wl128x_general_parms_cmd *gen_parms; - struct wl128x_ini_general_params *gp = - &((struct wl128x_nvs_file *)wl->nvs)->general_params; - bool answer = false; - int ret; - - if (!wl->nvs) - return -ENODEV; - - if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { - wl1271_warning("FEM index from ini out of bounds"); - return -EINVAL; - } - - gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); - if (!gen_parms) - return -ENOMEM; - - gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; - - memcpy(&gen_parms->general_params, gp, sizeof(*gp)); - - if (gp->tx_bip_fem_auto_detect) - answer = true; - - /* Replace REF and TCXO CLKs with the ones from platform data */ - gen_parms->general_params.ref_clock = wl->ref_clock; - gen_parms->general_params.tcxo_ref_clock = wl->tcxo_clock; - - ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); - if (ret < 0) { - wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); - goto out; - } - - gp->tx_bip_fem_manufacturer = - gen_parms->general_params.tx_bip_fem_manufacturer; - - if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { - wl1271_warning("FEM index from FW out of bounds"); - ret = -EINVAL; - goto out; - } - - wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", - answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer); - -out: - kfree(gen_parms); - return ret; -} - -int wl1271_cmd_radio_parms(struct wl1271 *wl) -{ - struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs; - struct wl1271_radio_parms_cmd *radio_parms; - struct wl1271_ini_general_params *gp = &nvs->general_params; - int ret; - - if (!wl->nvs) - return -ENODEV; - - radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); - if (!radio_parms) - return -ENOMEM; - - radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; - - /* 2.4GHz parameters */ - memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, - sizeof(struct wl1271_ini_band_params_2)); - memcpy(&radio_parms->dyn_params_2, - &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, - sizeof(struct wl1271_ini_fem_params_2)); - - /* 5GHz parameters */ - memcpy(&radio_parms->static_params_5, - &nvs->stat_radio_params_5, - sizeof(struct wl1271_ini_band_params_5)); - memcpy(&radio_parms->dyn_params_5, - &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, - sizeof(struct wl1271_ini_fem_params_5)); - - wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", - radio_parms, sizeof(*radio_parms)); - - ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); - if (ret < 0) - wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); - - kfree(radio_parms); - return ret; -} - -int wl128x_cmd_radio_parms(struct wl1271 *wl) -{ - struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs; - struct wl128x_radio_parms_cmd *radio_parms; - struct wl128x_ini_general_params *gp = &nvs->general_params; - int ret; - - if (!wl->nvs) - return -ENODEV; - - radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); - if (!radio_parms) - return -ENOMEM; - - radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; - - /* 2.4GHz parameters */ - memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, - sizeof(struct wl128x_ini_band_params_2)); - memcpy(&radio_parms->dyn_params_2, - &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, - sizeof(struct wl128x_ini_fem_params_2)); - - /* 5GHz parameters */ - memcpy(&radio_parms->static_params_5, - &nvs->stat_radio_params_5, - sizeof(struct wl128x_ini_band_params_5)); - memcpy(&radio_parms->dyn_params_5, - &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, - sizeof(struct wl128x_ini_fem_params_5)); - - radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options; - - wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", - radio_parms, sizeof(*radio_parms)); - - ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); - if (ret < 0) - wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); - - kfree(radio_parms); - return ret; -} - -int wl1271_cmd_ext_radio_parms(struct wl1271 *wl) -{ - struct wl1271_ext_radio_parms_cmd *ext_radio_parms; - struct conf_rf_settings *rf = &wl->conf.rf; - int ret; - - if (!wl->nvs) - return -ENODEV; - - ext_radio_parms = kzalloc(sizeof(*ext_radio_parms), GFP_KERNEL); - if (!ext_radio_parms) - return -ENOMEM; - - ext_radio_parms->test.id = TEST_CMD_INI_FILE_RF_EXTENDED_PARAM; - - memcpy(ext_radio_parms->tx_per_channel_power_compensation_2, - rf->tx_per_channel_power_compensation_2, - CONF_TX_PWR_COMPENSATION_LEN_2); - memcpy(ext_radio_parms->tx_per_channel_power_compensation_5, - rf->tx_per_channel_power_compensation_5, - CONF_TX_PWR_COMPENSATION_LEN_5); - - wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_EXT_RADIO_PARAM: ", - ext_radio_parms, sizeof(*ext_radio_parms)); - - ret = wl1271_cmd_test(wl, ext_radio_parms, sizeof(*ext_radio_parms), 0); - if (ret < 0) - wl1271_warning("TEST_CMD_INI_FILE_RF_EXTENDED_PARAM failed"); - - kfree(ext_radio_parms); - return ret; -} - -/* - * Poll the mailbox event field until any of the bits in the mask is set or a - * timeout occurs (WL1271_EVENT_TIMEOUT in msecs) - */ -static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask) -{ - u32 events_vector, event; - unsigned long timeout; - - timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT); - - do { - if (time_after(jiffies, timeout)) { - wl1271_debug(DEBUG_CMD, "timeout waiting for event %d", - (int)mask); - return -ETIMEDOUT; - } - - msleep(1); - - /* read from both event fields */ - wl1271_read(wl, wl->mbox_ptr[0], &events_vector, - sizeof(events_vector), false); - event = events_vector & mask; - wl1271_read(wl, wl->mbox_ptr[1], &events_vector, - sizeof(events_vector), false); - event |= events_vector & mask; - } while (!event); - - return 0; -} - -static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) -{ - int ret; - - ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask); - if (ret != 0) { - wl12xx_queue_recovery_work(wl); - return ret; - } - - return 0; -} - -int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type, - u8 *role_id) -{ - struct wl12xx_cmd_role_enable *cmd; - int ret; - - wl1271_debug(DEBUG_CMD, "cmd role enable"); - - if (WARN_ON(*role_id != WL12XX_INVALID_ROLE_ID)) - return -EBUSY; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - /* get role id */ - cmd->role_id = find_first_zero_bit(wl->roles_map, WL12XX_MAX_ROLES); - if (cmd->role_id >= WL12XX_MAX_ROLES) { - ret = -EBUSY; - goto out_free; - } - - memcpy(cmd->mac_address, addr, ETH_ALEN); - cmd->role_type = role_type; - - ret = wl1271_cmd_send(wl, CMD_ROLE_ENABLE, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to initiate cmd role enable"); - goto out_free; - } - - __set_bit(cmd->role_id, wl->roles_map); - *role_id = cmd->role_id; - -out_free: - kfree(cmd); - -out: - return ret; -} - -int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id) -{ - struct wl12xx_cmd_role_disable *cmd; - int ret; - - wl1271_debug(DEBUG_CMD, "cmd role disable"); - - if (WARN_ON(*role_id == WL12XX_INVALID_ROLE_ID)) - return -ENOENT; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - cmd->role_id = *role_id; - - ret = wl1271_cmd_send(wl, CMD_ROLE_DISABLE, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to initiate cmd role disable"); - goto out_free; - } - - __clear_bit(*role_id, wl->roles_map); - *role_id = WL12XX_INVALID_ROLE_ID; - -out_free: - kfree(cmd); - -out: - return ret; -} - -int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) -{ - unsigned long flags; - u8 link = find_first_zero_bit(wl->links_map, WL12XX_MAX_LINKS); - if (link >= WL12XX_MAX_LINKS) - return -EBUSY; - - /* these bits are used by op_tx */ - spin_lock_irqsave(&wl->wl_lock, flags); - __set_bit(link, wl->links_map); - __set_bit(link, wlvif->links_map); - spin_unlock_irqrestore(&wl->wl_lock, flags); - *hlid = link; - return 0; -} - -void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid) -{ - unsigned long flags; - - if (*hlid == WL12XX_INVALID_LINK_ID) - return; - - /* these bits are used by op_tx */ - spin_lock_irqsave(&wl->wl_lock, flags); - __clear_bit(*hlid, wl->links_map); - __clear_bit(*hlid, wlvif->links_map); - spin_unlock_irqrestore(&wl->wl_lock, flags); - - /* - * At this point op_tx() will not add more packets to the queues. We - * can purge them. - */ - wl1271_tx_reset_link_queues(wl, *hlid); - - *hlid = WL12XX_INVALID_LINK_ID; -} - -static int wl12xx_get_new_session_id(struct wl1271 *wl, - struct wl12xx_vif *wlvif) -{ - if (wlvif->session_counter >= SESSION_COUNTER_MAX) - wlvif->session_counter = 0; - - wlvif->session_counter++; - - return wlvif->session_counter; -} - -static int wl12xx_cmd_role_start_dev(struct wl1271 *wl, - struct wl12xx_vif *wlvif) -{ - struct wl12xx_cmd_role_start *cmd; - int ret; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - wl1271_debug(DEBUG_CMD, "cmd role start dev %d", wlvif->dev_role_id); - - cmd->role_id = wlvif->dev_role_id; - if (wlvif->band == IEEE80211_BAND_5GHZ) - cmd->band = WL12XX_BAND_5GHZ; - cmd->channel = wlvif->channel; - - if (wlvif->dev_hlid == WL12XX_INVALID_LINK_ID) { - ret = wl12xx_allocate_link(wl, wlvif, &wlvif->dev_hlid); - if (ret) - goto out_free; - } - cmd->device.hlid = wlvif->dev_hlid; - cmd->device.session = wl12xx_get_new_session_id(wl, wlvif); - - wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d", - cmd->role_id, cmd->device.hlid, cmd->device.session); - - ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to initiate cmd role enable"); - goto err_hlid; - } - - goto out_free; - -err_hlid: - /* clear links on error */ - wl12xx_free_link(wl, wlvif, &wlvif->dev_hlid); - -out_free: - kfree(cmd); - -out: - return ret; -} - -static int wl12xx_cmd_role_stop_dev(struct wl1271 *wl, - struct wl12xx_vif *wlvif) -{ - struct wl12xx_cmd_role_stop *cmd; - int ret; - - if (WARN_ON(wlvif->dev_hlid == WL12XX_INVALID_LINK_ID)) - return -EINVAL; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - wl1271_debug(DEBUG_CMD, "cmd role stop dev"); - - cmd->role_id = wlvif->dev_role_id; - cmd->disc_type = DISCONNECT_IMMEDIATE; - cmd->reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED); - - ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to initiate cmd role stop"); - goto out_free; - } - - ret = wl1271_cmd_wait_for_event(wl, ROLE_STOP_COMPLETE_EVENT_ID); - if (ret < 0) { - wl1271_error("cmd role stop dev event completion error"); - goto out_free; - } - - wl12xx_free_link(wl, wlvif, &wlvif->dev_hlid); - -out_free: - kfree(cmd); - -out: - return ret; -} - -int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); - struct wl12xx_cmd_role_start *cmd; - int ret; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - wl1271_debug(DEBUG_CMD, "cmd role start sta %d", wlvif->role_id); - - cmd->role_id = wlvif->role_id; - if (wlvif->band == IEEE80211_BAND_5GHZ) - cmd->band = WL12XX_BAND_5GHZ; - cmd->channel = wlvif->channel; - cmd->sta.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); - cmd->sta.beacon_interval = cpu_to_le16(wlvif->beacon_int); - cmd->sta.ssid_type = WL12XX_SSID_TYPE_ANY; - cmd->sta.ssid_len = wlvif->ssid_len; - memcpy(cmd->sta.ssid, wlvif->ssid, wlvif->ssid_len); - memcpy(cmd->sta.bssid, vif->bss_conf.bssid, ETH_ALEN); - cmd->sta.local_rates = cpu_to_le32(wlvif->rate_set); - - if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) { - ret = wl12xx_allocate_link(wl, wlvif, &wlvif->sta.hlid); - if (ret) - goto out_free; - } - cmd->sta.hlid = wlvif->sta.hlid; - cmd->sta.session = wl12xx_get_new_session_id(wl, wlvif); - cmd->sta.remote_rates = cpu_to_le32(wlvif->rate_set); - - wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d " - "basic_rate_set: 0x%x, remote_rates: 0x%x", - wlvif->role_id, cmd->sta.hlid, cmd->sta.session, - wlvif->basic_rate_set, wlvif->rate_set); - - ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to initiate cmd role start sta"); - goto err_hlid; - } - - goto out_free; - -err_hlid: - /* clear links on error. */ - wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid); - -out_free: - kfree(cmd); - -out: - return ret; -} - -/* use this function to stop ibss as well */ -int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - struct wl12xx_cmd_role_stop *cmd; - int ret; - - if (WARN_ON(wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)) - return -EINVAL; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - wl1271_debug(DEBUG_CMD, "cmd role stop sta %d", wlvif->role_id); - - cmd->role_id = wlvif->role_id; - cmd->disc_type = DISCONNECT_IMMEDIATE; - cmd->reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED); - - ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to initiate cmd role stop sta"); - goto out_free; - } - - wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid); - -out_free: - kfree(cmd); - -out: - return ret; -} - -int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - struct wl12xx_cmd_role_start *cmd; - struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; - int ret; - - wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wlvif->role_id); - - /* trying to use hidden SSID with an old hostapd version */ - if (wlvif->ssid_len == 0 && !bss_conf->hidden_ssid) { - wl1271_error("got a null SSID from beacon/bss"); - ret = -EINVAL; - goto out; - } - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - ret = wl12xx_allocate_link(wl, wlvif, &wlvif->ap.global_hlid); - if (ret < 0) - goto out_free; - - ret = wl12xx_allocate_link(wl, wlvif, &wlvif->ap.bcast_hlid); - if (ret < 0) - goto out_free_global; - - cmd->role_id = wlvif->role_id; - cmd->ap.aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period); - cmd->ap.bss_index = WL1271_AP_BSS_INDEX; - cmd->ap.global_hlid = wlvif->ap.global_hlid; - cmd->ap.broadcast_hlid = wlvif->ap.bcast_hlid; - cmd->ap.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); - cmd->ap.beacon_interval = cpu_to_le16(wlvif->beacon_int); - cmd->ap.dtim_interval = bss_conf->dtim_period; - cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP; - /* FIXME: Change when adding DFS */ - cmd->ap.reset_tsf = 1; /* By default reset AP TSF */ - cmd->channel = wlvif->channel; - - if (!bss_conf->hidden_ssid) { - /* take the SSID from the beacon for backward compatibility */ - cmd->ap.ssid_type = WL12XX_SSID_TYPE_PUBLIC; - cmd->ap.ssid_len = wlvif->ssid_len; - memcpy(cmd->ap.ssid, wlvif->ssid, wlvif->ssid_len); - } else { - cmd->ap.ssid_type = WL12XX_SSID_TYPE_HIDDEN; - cmd->ap.ssid_len = bss_conf->ssid_len; - memcpy(cmd->ap.ssid, bss_conf->ssid, bss_conf->ssid_len); - } - - cmd->ap.local_rates = cpu_to_le32(0xffffffff); - - switch (wlvif->band) { - case IEEE80211_BAND_2GHZ: - cmd->band = RADIO_BAND_2_4GHZ; - break; - case IEEE80211_BAND_5GHZ: - cmd->band = RADIO_BAND_5GHZ; - break; - default: - wl1271_warning("ap start - unknown band: %d", (int)wlvif->band); - cmd->band = RADIO_BAND_2_4GHZ; - break; - } - - ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to initiate cmd role start ap"); - goto out_free_bcast; - } - - goto out_free; - -out_free_bcast: - wl12xx_free_link(wl, wlvif, &wlvif->ap.bcast_hlid); - -out_free_global: - wl12xx_free_link(wl, wlvif, &wlvif->ap.global_hlid); - -out_free: - kfree(cmd); - -out: - return ret; -} - -int wl12xx_cmd_role_stop_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - struct wl12xx_cmd_role_stop *cmd; - int ret; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - wl1271_debug(DEBUG_CMD, "cmd role stop ap %d", wlvif->role_id); - - cmd->role_id = wlvif->role_id; - - ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to initiate cmd role stop ap"); - goto out_free; - } - - wl12xx_free_link(wl, wlvif, &wlvif->ap.bcast_hlid); - wl12xx_free_link(wl, wlvif, &wlvif->ap.global_hlid); - -out_free: - kfree(cmd); - -out: - return ret; -} - -int wl12xx_cmd_role_start_ibss(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); - struct wl12xx_cmd_role_start *cmd; - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; - int ret; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - wl1271_debug(DEBUG_CMD, "cmd role start ibss %d", wlvif->role_id); - - cmd->role_id = wlvif->role_id; - if (wlvif->band == IEEE80211_BAND_5GHZ) - cmd->band = WL12XX_BAND_5GHZ; - cmd->channel = wlvif->channel; - cmd->ibss.basic_rate_set = cpu_to_le32(wlvif->basic_rate_set); - cmd->ibss.beacon_interval = cpu_to_le16(wlvif->beacon_int); - cmd->ibss.dtim_interval = bss_conf->dtim_period; - cmd->ibss.ssid_type = WL12XX_SSID_TYPE_ANY; - cmd->ibss.ssid_len = wlvif->ssid_len; - memcpy(cmd->ibss.ssid, wlvif->ssid, wlvif->ssid_len); - memcpy(cmd->ibss.bssid, vif->bss_conf.bssid, ETH_ALEN); - cmd->sta.local_rates = cpu_to_le32(wlvif->rate_set); - - if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) { - ret = wl12xx_allocate_link(wl, wlvif, &wlvif->sta.hlid); - if (ret) - goto out_free; - } - cmd->ibss.hlid = wlvif->sta.hlid; - cmd->ibss.remote_rates = cpu_to_le32(wlvif->rate_set); - - wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d " - "basic_rate_set: 0x%x, remote_rates: 0x%x", - wlvif->role_id, cmd->sta.hlid, cmd->sta.session, - wlvif->basic_rate_set, wlvif->rate_set); - - wl1271_debug(DEBUG_CMD, "vif->bss_conf.bssid = %pM", - vif->bss_conf.bssid); - - ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to initiate cmd role enable"); - goto err_hlid; - } - - goto out_free; - -err_hlid: - /* clear links on error. */ - wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid); - -out_free: - kfree(cmd); - -out: - return ret; -} - - -/** - * send test command to firmware - * - * @wl: wl struct - * @buf: buffer containing the command, with all headers, must work with dma - * @len: length of the buffer - * @answer: is answer needed - */ -int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer) -{ - int ret; - size_t res_len = 0; - - wl1271_debug(DEBUG_CMD, "cmd test"); - - if (answer) - res_len = buf_len; - - ret = wl1271_cmd_send(wl, CMD_TEST, buf, buf_len, res_len); - - if (ret < 0) { - wl1271_warning("TEST command failed"); - return ret; - } - - return ret; -} - -/** - * read acx from firmware - * - * @wl: wl struct - * @id: acx id - * @buf: buffer for the response, including all headers, must work with dma - * @len: length of buf - */ -int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len) -{ - struct acx_header *acx = buf; - int ret; - - wl1271_debug(DEBUG_CMD, "cmd interrogate"); - - acx->id = cpu_to_le16(id); - - /* payload length, does not include any headers */ - acx->len = cpu_to_le16(len - sizeof(*acx)); - - ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx), len); - if (ret < 0) - wl1271_error("INTERROGATE command failed"); - - return ret; -} - -/** - * write acx value to firmware - * - * @wl: wl struct - * @id: acx id - * @buf: buffer containing acx, including all headers, must work with dma - * @len: length of buf - */ -int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) -{ - struct acx_header *acx = buf; - int ret; - - wl1271_debug(DEBUG_CMD, "cmd configure (%d)", id); - - acx->id = cpu_to_le16(id); - - /* payload length, does not include any headers */ - acx->len = cpu_to_le16(len - sizeof(*acx)); - - ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len, 0); - if (ret < 0) { - wl1271_warning("CONFIGURE command NOK"); - return ret; - } - - return 0; -} - -int wl1271_cmd_data_path(struct wl1271 *wl, bool enable) -{ - struct cmd_enabledisable_path *cmd; - int ret; - u16 cmd_rx, cmd_tx; - - wl1271_debug(DEBUG_CMD, "cmd data path"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - /* the channel here is only used for calibration, so hardcoded to 1 */ - cmd->channel = 1; - - if (enable) { - cmd_rx = CMD_ENABLE_RX; - cmd_tx = CMD_ENABLE_TX; - } else { - cmd_rx = CMD_DISABLE_RX; - cmd_tx = CMD_DISABLE_TX; - } - - ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("rx %s cmd for channel %d failed", - enable ? "start" : "stop", cmd->channel); - goto out; - } - - wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d", - enable ? "start" : "stop", cmd->channel); - - ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("tx %s cmd for channel %d failed", - enable ? "start" : "stop", cmd->channel); - goto out; - } - - wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d", - enable ? "start" : "stop", cmd->channel); - -out: - kfree(cmd); - return ret; -} - -int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 ps_mode, u16 auto_ps_timeout) -{ - struct wl1271_cmd_ps_params *ps_params = NULL; - int ret = 0; - - wl1271_debug(DEBUG_CMD, "cmd set ps mode"); - - ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); - if (!ps_params) { - ret = -ENOMEM; - goto out; - } - - ps_params->role_id = wlvif->role_id; - ps_params->ps_mode = ps_mode; - ps_params->auto_ps_timeout = auto_ps_timeout; - - ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, - sizeof(*ps_params), 0); - if (ret < 0) { - wl1271_error("cmd set_ps_mode failed"); - goto out; - } - -out: - kfree(ps_params); - return ret; -} - -int wl1271_cmd_template_set(struct wl1271 *wl, u8 role_id, - u16 template_id, void *buf, size_t buf_len, - int index, u32 rates) -{ - struct wl1271_cmd_template_set *cmd; - int ret = 0; - - wl1271_debug(DEBUG_CMD, "cmd template_set %d (role %d)", - template_id, role_id); - - WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE); - buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - /* during initialization wlvif is NULL */ - cmd->role_id = role_id; - cmd->len = cpu_to_le16(buf_len); - cmd->template_type = template_id; - cmd->enabled_rates = cpu_to_le32(rates); - cmd->short_retry_limit = wl->conf.tx.tmpl_short_retry_limit; - cmd->long_retry_limit = wl->conf.tx.tmpl_long_retry_limit; - cmd->index = index; - - if (buf) - memcpy(cmd->template_data, buf, buf_len); - - ret = wl1271_cmd_send(wl, CMD_SET_TEMPLATE, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_warning("cmd set_template failed: %d", ret); - goto out_free; - } - -out_free: - kfree(cmd); - -out: - return ret; -} - -int wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - struct sk_buff *skb = NULL; - int size; - void *ptr; - int ret = -ENOMEM; - - - if (wlvif->bss_type == BSS_TYPE_IBSS) { - size = sizeof(struct wl12xx_null_data_template); - ptr = NULL; - } else { - skb = ieee80211_nullfunc_get(wl->hw, - wl12xx_wlvif_to_vif(wlvif)); - if (!skb) - goto out; - size = skb->len; - ptr = skb->data; - } - - ret = wl1271_cmd_template_set(wl, wlvif->role_id, - CMD_TEMPL_NULL_DATA, ptr, size, 0, - wlvif->basic_rate); - -out: - dev_kfree_skb(skb); - if (ret) - wl1271_warning("cmd buld null data failed %d", ret); - - return ret; - -} - -int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl, - struct wl12xx_vif *wlvif) -{ - struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); - struct sk_buff *skb = NULL; - int ret = -ENOMEM; - - skb = ieee80211_nullfunc_get(wl->hw, vif); - if (!skb) - goto out; - - ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_KLV, - skb->data, skb->len, - CMD_TEMPL_KLV_IDX_NULL_DATA, - wlvif->basic_rate); - -out: - dev_kfree_skb(skb); - if (ret) - wl1271_warning("cmd build klv null data failed %d", ret); - - return ret; - -} - -int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u16 aid) -{ - struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); - struct sk_buff *skb; - int ret = 0; - - skb = ieee80211_pspoll_get(wl->hw, vif); - if (!skb) - goto out; - - ret = wl1271_cmd_template_set(wl, wlvif->role_id, - CMD_TEMPL_PS_POLL, skb->data, - skb->len, 0, wlvif->basic_rate_set); - -out: - dev_kfree_skb(skb); - return ret; -} - -int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 role_id, u8 band, - const u8 *ssid, size_t ssid_len, - const u8 *ie, size_t ie_len) -{ - struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); - struct sk_buff *skb; - int ret; - u32 rate; - - skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len, - ie, ie_len); - if (!skb) { - ret = -ENOMEM; - goto out; - } - - wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len); - - rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); - if (band == IEEE80211_BAND_2GHZ) - ret = wl1271_cmd_template_set(wl, role_id, - CMD_TEMPL_CFG_PROBE_REQ_2_4, - skb->data, skb->len, 0, rate); - else - ret = wl1271_cmd_template_set(wl, role_id, - CMD_TEMPL_CFG_PROBE_REQ_5, - skb->data, skb->len, 0, rate); - -out: - dev_kfree_skb(skb); - return ret; -} - -struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - struct sk_buff *skb) -{ - struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); - int ret; - u32 rate; - - if (!skb) - skb = ieee80211_ap_probereq_get(wl->hw, vif); - if (!skb) - goto out; - - wl1271_dump(DEBUG_SCAN, "AP PROBE REQ: ", skb->data, skb->len); - - rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[wlvif->band]); - if (wlvif->band == IEEE80211_BAND_2GHZ) - ret = wl1271_cmd_template_set(wl, wlvif->role_id, - CMD_TEMPL_CFG_PROBE_REQ_2_4, - skb->data, skb->len, 0, rate); - else - ret = wl1271_cmd_template_set(wl, wlvif->role_id, - CMD_TEMPL_CFG_PROBE_REQ_5, - skb->data, skb->len, 0, rate); - - if (ret < 0) - wl1271_error("Unable to set ap probe request template."); - -out: - return skb; -} - -int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - int ret, extra; - u16 fc; - struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); - struct sk_buff *skb; - struct wl12xx_arp_rsp_template *tmpl; - struct ieee80211_hdr_3addr *hdr; - struct arphdr *arp_hdr; - - skb = dev_alloc_skb(sizeof(*hdr) + sizeof(__le16) + sizeof(*tmpl) + - WL1271_EXTRA_SPACE_MAX); - if (!skb) { - wl1271_error("failed to allocate buffer for arp rsp template"); - return -ENOMEM; - } - - skb_reserve(skb, sizeof(*hdr) + WL1271_EXTRA_SPACE_MAX); - - tmpl = (struct wl12xx_arp_rsp_template *)skb_put(skb, sizeof(*tmpl)); - memset(tmpl, 0, sizeof(tmpl)); - - /* llc layer */ - memcpy(tmpl->llc_hdr, rfc1042_header, sizeof(rfc1042_header)); - tmpl->llc_type = cpu_to_be16(ETH_P_ARP); - - /* arp header */ - arp_hdr = &tmpl->arp_hdr; - arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER); - arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP); - arp_hdr->ar_hln = ETH_ALEN; - arp_hdr->ar_pln = 4; - arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY); - - /* arp payload */ - memcpy(tmpl->sender_hw, vif->addr, ETH_ALEN); - tmpl->sender_ip = wlvif->ip_addr; - - /* encryption space */ - switch (wlvif->encryption_type) { - case KEY_TKIP: - extra = WL1271_EXTRA_SPACE_TKIP; - break; - case KEY_AES: - extra = WL1271_EXTRA_SPACE_AES; - break; - case KEY_NONE: - case KEY_WEP: - case KEY_GEM: - extra = 0; - break; - default: - wl1271_warning("Unknown encryption type: %d", - wlvif->encryption_type); - ret = -EINVAL; - goto out; - } - - if (extra) { - u8 *space = skb_push(skb, extra); - memset(space, 0, extra); - } - - /* QoS header - BE */ - if (wlvif->sta.qos) - memset(skb_push(skb, sizeof(__le16)), 0, sizeof(__le16)); - - /* mac80211 header */ - hdr = (struct ieee80211_hdr_3addr *)skb_push(skb, sizeof(*hdr)); - memset(hdr, 0, sizeof(hdr)); - fc = IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS; - if (wlvif->sta.qos) - fc |= IEEE80211_STYPE_QOS_DATA; - else - fc |= IEEE80211_STYPE_DATA; - if (wlvif->encryption_type != KEY_NONE) - fc |= IEEE80211_FCTL_PROTECTED; - - hdr->frame_control = cpu_to_le16(fc); - memcpy(hdr->addr1, vif->bss_conf.bssid, ETH_ALEN); - memcpy(hdr->addr2, vif->addr, ETH_ALEN); - memset(hdr->addr3, 0xff, ETH_ALEN); - - ret = wl1271_cmd_template_set(wl, wlvif->role_id, CMD_TEMPL_ARP_RSP, - skb->data, skb->len, 0, - wlvif->basic_rate); -out: - dev_kfree_skb(skb); - return ret; -} - -int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif) -{ - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - struct ieee80211_qos_hdr template; - - memset(&template, 0, sizeof(template)); - - memcpy(template.addr1, vif->bss_conf.bssid, ETH_ALEN); - memcpy(template.addr2, vif->addr, ETH_ALEN); - memcpy(template.addr3, vif->bss_conf.bssid, ETH_ALEN); - - template.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | - IEEE80211_STYPE_QOS_NULLFUNC | - IEEE80211_FCTL_TODS); - - /* FIXME: not sure what priority to use here */ - template.qos_ctrl = cpu_to_le16(0); - - return wl1271_cmd_template_set(wl, wlvif->role_id, - CMD_TEMPL_QOS_NULL_DATA, &template, - sizeof(template), 0, - wlvif->basic_rate); -} - -int wl12xx_cmd_set_default_wep_key(struct wl1271 *wl, u8 id, u8 hlid) -{ - struct wl1271_cmd_set_keys *cmd; - int ret = 0; - - wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->hlid = hlid; - cmd->key_id = id; - cmd->lid_key_type = WEP_DEFAULT_LID_TYPE; - cmd->key_action = cpu_to_le16(KEY_SET_ID); - cmd->key_type = KEY_WEP; - - ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_warning("cmd set_default_wep_key failed: %d", ret); - goto out; - } - -out: - kfree(cmd); - - return ret; -} - -int wl1271_cmd_set_sta_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u16 action, u8 id, u8 key_type, - u8 key_size, const u8 *key, const u8 *addr, - u32 tx_seq_32, u16 tx_seq_16) -{ - struct wl1271_cmd_set_keys *cmd; - int ret = 0; - - /* hlid might have already been deleted */ - if (wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) - return 0; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->hlid = wlvif->sta.hlid; - - if (key_type == KEY_WEP) - cmd->lid_key_type = WEP_DEFAULT_LID_TYPE; - else if (is_broadcast_ether_addr(addr)) - cmd->lid_key_type = BROADCAST_LID_TYPE; - else - cmd->lid_key_type = UNICAST_LID_TYPE; - - cmd->key_action = cpu_to_le16(action); - cmd->key_size = key_size; - cmd->key_type = key_type; - - cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16); - cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32); - - cmd->key_id = id; - - if (key_type == KEY_TKIP) { - /* - * We get the key in the following form: - * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) - * but the target is expecting: - * TKIP - RX MIC - TX MIC - */ - memcpy(cmd->key, key, 16); - memcpy(cmd->key + 16, key + 24, 8); - memcpy(cmd->key + 24, key + 16, 8); - - } else { - memcpy(cmd->key, key, key_size); - } - - wl1271_dump(DEBUG_CRYPT, "TARGET KEY: ", cmd, sizeof(*cmd)); - - ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_warning("could not set keys"); - goto out; - } - -out: - kfree(cmd); - - return ret; -} - -/* - * TODO: merge with sta/ibss into 1 set_key function. - * note there are slight diffs - */ -int wl1271_cmd_set_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u16 action, u8 id, u8 key_type, - u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, - u16 tx_seq_16) -{ - struct wl1271_cmd_set_keys *cmd; - int ret = 0; - u8 lid_type; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - if (hlid == wlvif->ap.bcast_hlid) { - if (key_type == KEY_WEP) - lid_type = WEP_DEFAULT_LID_TYPE; - else - lid_type = BROADCAST_LID_TYPE; - } else { - lid_type = UNICAST_LID_TYPE; - } - - wl1271_debug(DEBUG_CRYPT, "ap key action: %d id: %d lid: %d type: %d" - " hlid: %d", (int)action, (int)id, (int)lid_type, - (int)key_type, (int)hlid); - - cmd->lid_key_type = lid_type; - cmd->hlid = hlid; - cmd->key_action = cpu_to_le16(action); - cmd->key_size = key_size; - cmd->key_type = key_type; - cmd->key_id = id; - cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16); - cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32); - - if (key_type == KEY_TKIP) { - /* - * We get the key in the following form: - * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) - * but the target is expecting: - * TKIP - RX MIC - TX MIC - */ - memcpy(cmd->key, key, 16); - memcpy(cmd->key + 16, key + 24, 8); - memcpy(cmd->key + 24, key + 16, 8); - } else { - memcpy(cmd->key, key, key_size); - } - - wl1271_dump(DEBUG_CRYPT, "TARGET AP KEY: ", cmd, sizeof(*cmd)); - - ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_warning("could not set ap keys"); - goto out; - } - -out: - kfree(cmd); - return ret; -} - -int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid) -{ - struct wl12xx_cmd_set_peer_state *cmd; - int ret = 0; - - wl1271_debug(DEBUG_CMD, "cmd set peer state (hlid=%d)", hlid); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->hlid = hlid; - cmd->state = WL1271_CMD_STA_STATE_CONNECTED; - - ret = wl1271_cmd_send(wl, CMD_SET_PEER_STATE, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to send set peer state command"); - goto out_free; - } - -out_free: - kfree(cmd); - -out: - return ret; -} - -int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct ieee80211_sta *sta, u8 hlid) -{ - struct wl12xx_cmd_add_peer *cmd; - int i, ret; - u32 sta_rates; - - wl1271_debug(DEBUG_CMD, "cmd add peer %d", (int)hlid); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - memcpy(cmd->addr, sta->addr, ETH_ALEN); - cmd->bss_index = WL1271_AP_BSS_INDEX; - cmd->aid = sta->aid; - cmd->hlid = hlid; - cmd->sp_len = sta->max_sp; - cmd->wmm = sta->wme ? 1 : 0; - - for (i = 0; i < NUM_ACCESS_CATEGORIES_COPY; i++) - if (sta->wme && (sta->uapsd_queues & BIT(i))) - cmd->psd_type[i] = WL1271_PSD_UPSD_TRIGGER; - else - cmd->psd_type[i] = WL1271_PSD_LEGACY; - - sta_rates = sta->supp_rates[wlvif->band]; - if (sta->ht_cap.ht_supported) - sta_rates |= sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET; - - cmd->supported_rates = - cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates, - wlvif->band)); - - wl1271_debug(DEBUG_CMD, "new peer rates=0x%x queues=0x%x", - cmd->supported_rates, sta->uapsd_queues); - - ret = wl1271_cmd_send(wl, CMD_ADD_PEER, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to initiate cmd add peer"); - goto out_free; - } - -out_free: - kfree(cmd); - -out: - return ret; -} - -int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid) -{ - struct wl12xx_cmd_remove_peer *cmd; - int ret; - - wl1271_debug(DEBUG_CMD, "cmd remove peer %d", (int)hlid); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->hlid = hlid; - /* We never send a deauth, mac80211 is in charge of this */ - cmd->reason_opcode = 0; - cmd->send_deauth_flag = 0; - - ret = wl1271_cmd_send(wl, CMD_REMOVE_PEER, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to initiate cmd remove peer"); - goto out_free; - } - - /* - * We are ok with a timeout here. The event is sometimes not sent - * due to a firmware bug. - */ - wl1271_cmd_wait_for_event_or_timeout(wl, - PEER_REMOVE_COMPLETE_EVENT_ID); - -out_free: - kfree(cmd); - -out: - return ret; -} - -int wl12xx_cmd_config_fwlog(struct wl1271 *wl) -{ - struct wl12xx_cmd_config_fwlog *cmd; - int ret = 0; - - wl1271_debug(DEBUG_CMD, "cmd config firmware logger"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->logger_mode = wl->conf.fwlog.mode; - cmd->log_severity = wl->conf.fwlog.severity; - cmd->timestamp = wl->conf.fwlog.timestamp; - cmd->output = wl->conf.fwlog.output; - cmd->threshold = wl->conf.fwlog.threshold; - - ret = wl1271_cmd_send(wl, CMD_CONFIG_FWLOGGER, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to send config firmware logger command"); - goto out_free; - } - -out_free: - kfree(cmd); - -out: - return ret; -} - -int wl12xx_cmd_start_fwlog(struct wl1271 *wl) -{ - struct wl12xx_cmd_start_fwlog *cmd; - int ret = 0; - - wl1271_debug(DEBUG_CMD, "cmd start firmware logger"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - ret = wl1271_cmd_send(wl, CMD_START_FWLOGGER, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to send start firmware logger command"); - goto out_free; - } - -out_free: - kfree(cmd); - -out: - return ret; -} - -int wl12xx_cmd_stop_fwlog(struct wl1271 *wl) -{ - struct wl12xx_cmd_stop_fwlog *cmd; - int ret = 0; - - wl1271_debug(DEBUG_CMD, "cmd stop firmware logger"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - ret = wl1271_cmd_send(wl, CMD_STOP_FWLOGGER, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to send stop firmware logger command"); - goto out_free; - } - -out_free: - kfree(cmd); - -out: - return ret; -} - -static int wl12xx_cmd_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 role_id) -{ - struct wl12xx_cmd_roc *cmd; - int ret = 0; - - wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", wlvif->channel, role_id); - - if (WARN_ON(role_id == WL12XX_INVALID_ROLE_ID)) - return -EINVAL; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->role_id = role_id; - cmd->channel = wlvif->channel; - switch (wlvif->band) { - case IEEE80211_BAND_2GHZ: - cmd->band = RADIO_BAND_2_4GHZ; - break; - case IEEE80211_BAND_5GHZ: - cmd->band = RADIO_BAND_5GHZ; - break; - default: - wl1271_error("roc - unknown band: %d", (int)wlvif->band); - ret = -EINVAL; - goto out_free; - } - - - ret = wl1271_cmd_send(wl, CMD_REMAIN_ON_CHANNEL, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to send ROC command"); - goto out_free; - } - -out_free: - kfree(cmd); - -out: - return ret; -} - -static int wl12xx_cmd_croc(struct wl1271 *wl, u8 role_id) -{ - struct wl12xx_cmd_croc *cmd; - int ret = 0; - - wl1271_debug(DEBUG_CMD, "cmd croc (%d)", role_id); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - cmd->role_id = role_id; - - ret = wl1271_cmd_send(wl, CMD_CANCEL_REMAIN_ON_CHANNEL, cmd, - sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to send ROC command"); - goto out_free; - } - -out_free: - kfree(cmd); - -out: - return ret; -} - -int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id) -{ - int ret = 0; - - if (WARN_ON(test_bit(role_id, wl->roc_map))) - return 0; - - ret = wl12xx_cmd_roc(wl, wlvif, role_id); - if (ret < 0) - goto out; - - ret = wl1271_cmd_wait_for_event(wl, - REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID); - if (ret < 0) { - wl1271_error("cmd roc event completion error"); - goto out; - } - - __set_bit(role_id, wl->roc_map); -out: - return ret; -} - -int wl12xx_croc(struct wl1271 *wl, u8 role_id) -{ - int ret = 0; - - if (WARN_ON(!test_bit(role_id, wl->roc_map))) - return 0; - - ret = wl12xx_cmd_croc(wl, role_id); - if (ret < 0) - goto out; - - __clear_bit(role_id, wl->roc_map); - - /* - * Rearm the tx watchdog when removing the last ROC. This prevents - * recoveries due to just finished ROCs - when Tx hasn't yet had - * a chance to get out. - */ - if (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) >= WL12XX_MAX_ROLES) - wl12xx_rearm_tx_watchdog_locked(wl); -out: - return ret; -} - -int wl12xx_cmd_channel_switch(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - struct ieee80211_channel_switch *ch_switch) -{ - struct wl12xx_cmd_channel_switch *cmd; - int ret; - - wl1271_debug(DEBUG_ACX, "cmd channel switch"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->role_id = wlvif->role_id; - cmd->channel = ch_switch->channel->hw_value; - cmd->switch_time = ch_switch->count; - cmd->stop_tx = ch_switch->block_tx; - - /* FIXME: control from mac80211 in the future */ - cmd->post_switch_tx_disable = 0; /* Enable TX on the target channel */ - - ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to send channel switch command"); - goto out_free; - } - -out_free: - kfree(cmd); - -out: - return ret; -} - -int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl) -{ - struct wl12xx_cmd_stop_channel_switch *cmd; - int ret; - - wl1271_debug(DEBUG_ACX, "cmd stop channel switch"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - ret = wl1271_cmd_send(wl, CMD_STOP_CHANNEL_SWICTH, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to stop channel switch command"); - goto out_free; - } - -out_free: - kfree(cmd); - -out: - return ret; -} - -/* start dev role and roc on its channel */ -int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - int ret; - - if (WARN_ON(!(wlvif->bss_type == BSS_TYPE_STA_BSS || - wlvif->bss_type == BSS_TYPE_IBSS))) - return -EINVAL; - - ret = wl12xx_cmd_role_start_dev(wl, wlvif); - if (ret < 0) - goto out; - - ret = wl12xx_roc(wl, wlvif, wlvif->dev_role_id); - if (ret < 0) - goto out_stop; - - return 0; - -out_stop: - wl12xx_cmd_role_stop_dev(wl, wlvif); -out: - return ret; -} - -/* croc dev hlid, and stop the role */ -int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - int ret; - - if (WARN_ON(!(wlvif->bss_type == BSS_TYPE_STA_BSS || - wlvif->bss_type == BSS_TYPE_IBSS))) - return -EINVAL; - - /* flush all pending packets */ - wl1271_tx_work_locked(wl); - - if (test_bit(wlvif->dev_role_id, wl->roc_map)) { - ret = wl12xx_croc(wl, wlvif->dev_role_id); - if (ret < 0) - goto out; - } - - ret = wl12xx_cmd_role_stop_dev(wl, wlvif); - if (ret < 0) - goto out; -out: - return ret; -} diff --git a/trunk/drivers/net/wireless/wl12xx/cmd.h b/trunk/drivers/net/wireless/wl12xx/cmd.h deleted file mode 100644 index de217d92516b..000000000000 --- a/trunk/drivers/net/wireless/wl12xx/cmd.h +++ /dev/null @@ -1,728 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __CMD_H__ -#define __CMD_H__ - -#include "wl12xx.h" - -struct acx_header; - -int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, - size_t res_len); -int wl1271_cmd_general_parms(struct wl1271 *wl); -int wl128x_cmd_general_parms(struct wl1271 *wl); -int wl1271_cmd_radio_parms(struct wl1271 *wl); -int wl128x_cmd_radio_parms(struct wl1271 *wl); -int wl1271_cmd_ext_radio_parms(struct wl1271 *wl); -int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 *addr, u8 role_type, - u8 *role_id); -int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id); -int wl12xx_cmd_role_start_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif); -int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif); -int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif); -int wl12xx_cmd_role_stop_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif); -int wl12xx_cmd_role_start_ibss(struct wl1271 *wl, struct wl12xx_vif *wlvif); -int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif); -int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif); -int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); -int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); -int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len); -int wl1271_cmd_data_path(struct wl1271 *wl, bool enable); -int wl1271_cmd_ps_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 ps_mode, u16 auto_ps_timeout); -int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, - size_t len); -int wl1271_cmd_template_set(struct wl1271 *wl, u8 role_id, - u16 template_id, void *buf, size_t buf_len, - int index, u32 rates); -int wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif); -int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u16 aid); -int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 role_id, u8 band, - const u8 *ssid, size_t ssid_len, - const u8 *ie, size_t ie_len); -struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - struct sk_buff *skb); -int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif); -int wl1271_build_qos_null_data(struct wl1271 *wl, struct ieee80211_vif *vif); -int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl, - struct wl12xx_vif *wlvif); -int wl12xx_cmd_set_default_wep_key(struct wl1271 *wl, u8 id, u8 hlid); -int wl1271_cmd_set_sta_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u16 action, u8 id, u8 key_type, - u8 key_size, const u8 *key, const u8 *addr, - u32 tx_seq_32, u16 tx_seq_16); -int wl1271_cmd_set_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u16 action, u8 id, u8 key_type, - u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, - u16 tx_seq_16); -int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid); -int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id); -int wl12xx_croc(struct wl1271 *wl, u8 role_id); -int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct ieee80211_sta *sta, u8 hlid); -int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid); -int wl12xx_cmd_config_fwlog(struct wl1271 *wl); -int wl12xx_cmd_start_fwlog(struct wl1271 *wl); -int wl12xx_cmd_stop_fwlog(struct wl1271 *wl); -int wl12xx_cmd_channel_switch(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - struct ieee80211_channel_switch *ch_switch); -int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl); -int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 *hlid); -void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid); - -enum wl1271_commands { - CMD_INTERROGATE = 1, /* use this to read information elements */ - CMD_CONFIGURE = 2, /* use this to write information elements */ - CMD_ENABLE_RX = 3, - CMD_ENABLE_TX = 4, - CMD_DISABLE_RX = 5, - CMD_DISABLE_TX = 6, - CMD_SCAN = 7, - CMD_STOP_SCAN = 8, - CMD_SET_KEYS = 9, - CMD_READ_MEMORY = 10, - CMD_WRITE_MEMORY = 11, - CMD_SET_TEMPLATE = 12, - CMD_TEST = 13, - CMD_NOISE_HIST = 14, - CMD_QUIET_ELEMENT_SET_STATE = 15, - CMD_SET_BCN_MODE = 16, - - CMD_MEASUREMENT = 17, - CMD_STOP_MEASUREMENT = 18, - CMD_SET_PS_MODE = 19, - CMD_CHANNEL_SWITCH = 20, - CMD_STOP_CHANNEL_SWICTH = 21, - CMD_AP_DISCOVERY = 22, - CMD_STOP_AP_DISCOVERY = 23, - CMD_HEALTH_CHECK = 24, - CMD_DEBUG = 25, - CMD_TRIGGER_SCAN_TO = 26, - CMD_CONNECTION_SCAN_CFG = 27, - CMD_CONNECTION_SCAN_SSID_CFG = 28, - CMD_START_PERIODIC_SCAN = 29, - CMD_STOP_PERIODIC_SCAN = 30, - CMD_SET_PEER_STATE = 31, - CMD_REMAIN_ON_CHANNEL = 32, - CMD_CANCEL_REMAIN_ON_CHANNEL = 33, - CMD_CONFIG_FWLOGGER = 34, - CMD_START_FWLOGGER = 35, - CMD_STOP_FWLOGGER = 36, - - /* Access point commands */ - CMD_ADD_PEER = 37, - CMD_REMOVE_PEER = 38, - - /* Role API */ - CMD_ROLE_ENABLE = 39, - CMD_ROLE_DISABLE = 40, - CMD_ROLE_START = 41, - CMD_ROLE_STOP = 42, - - /* DFS */ - CMD_START_RADAR_DETECTION = 43, - CMD_STOP_RADAR_DETECTION = 44, - - /* WIFI Direct */ - CMD_WFD_START_DISCOVERY = 45, - CMD_WFD_STOP_DISCOVERY = 46, - CMD_WFD_ATTRIBUTE_CONFIG = 47, - CMD_NOP = 48, - CMD_LAST_COMMAND, - - MAX_COMMAND_ID = 0xFFFF, -}; - -#define MAX_CMD_PARAMS 572 - -enum { - CMD_TEMPL_KLV_IDX_NULL_DATA = 0, - CMD_TEMPL_KLV_IDX_MAX = 4 -}; - -enum cmd_templ { - CMD_TEMPL_NULL_DATA = 0, - CMD_TEMPL_BEACON, - CMD_TEMPL_CFG_PROBE_REQ_2_4, - CMD_TEMPL_CFG_PROBE_REQ_5, - CMD_TEMPL_PROBE_RESPONSE, - CMD_TEMPL_QOS_NULL_DATA, - CMD_TEMPL_PS_POLL, - CMD_TEMPL_KLV, - CMD_TEMPL_DISCONNECT, - CMD_TEMPL_PROBE_REQ_2_4, /* for firmware internal use only */ - CMD_TEMPL_PROBE_REQ_5, /* for firmware internal use only */ - CMD_TEMPL_BAR, /* for firmware internal use only */ - CMD_TEMPL_CTS, /* - * For CTS-to-self (FastCTS) mechanism - * for BT/WLAN coexistence (SoftGemini). */ - CMD_TEMPL_AP_BEACON, - CMD_TEMPL_AP_PROBE_RESPONSE, - CMD_TEMPL_ARP_RSP, - CMD_TEMPL_DEAUTH_AP, - CMD_TEMPL_TEMPORARY, - CMD_TEMPL_LINK_MEASUREMENT_REPORT, - - CMD_TEMPL_MAX = 0xff -}; - -/* unit ms */ -#define WL1271_COMMAND_TIMEOUT 2000 -#define WL1271_CMD_TEMPL_DFLT_SIZE 252 -#define WL1271_CMD_TEMPL_MAX_SIZE 512 -#define WL1271_EVENT_TIMEOUT 750 - -struct wl1271_cmd_header { - __le16 id; - __le16 status; - /* payload */ - u8 data[0]; -} __packed; - -#define WL1271_CMD_MAX_PARAMS 572 - -struct wl1271_command { - struct wl1271_cmd_header header; - u8 parameters[WL1271_CMD_MAX_PARAMS]; -} __packed; - -enum { - CMD_MAILBOX_IDLE = 0, - CMD_STATUS_SUCCESS = 1, - CMD_STATUS_UNKNOWN_CMD = 2, - CMD_STATUS_UNKNOWN_IE = 3, - CMD_STATUS_REJECT_MEAS_SG_ACTIVE = 11, - CMD_STATUS_RX_BUSY = 13, - CMD_STATUS_INVALID_PARAM = 14, - CMD_STATUS_TEMPLATE_TOO_LARGE = 15, - CMD_STATUS_OUT_OF_MEMORY = 16, - CMD_STATUS_STA_TABLE_FULL = 17, - CMD_STATUS_RADIO_ERROR = 18, - CMD_STATUS_WRONG_NESTING = 19, - CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/ - CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ - CMD_STATUS_TEMPLATE_OOM = 23, - CMD_STATUS_NO_RX_BA_SESSION = 24, - MAX_COMMAND_STATUS = 0xff -}; - -#define CMDMBOX_HEADER_LEN 4 -#define CMDMBOX_INFO_ELEM_HEADER_LEN 4 - -enum { - BSS_TYPE_IBSS = 0, - BSS_TYPE_STA_BSS = 2, - BSS_TYPE_AP_BSS = 3, - MAX_BSS_TYPE = 0xFF -}; - -#define WL1271_JOIN_CMD_CTRL_TX_FLUSH 0x80 /* Firmware flushes all Tx */ -#define WL1271_JOIN_CMD_TX_SESSION_OFFSET 1 -#define WL1271_JOIN_CMD_BSS_TYPE_5GHZ 0x10 - -struct wl12xx_cmd_role_enable { - struct wl1271_cmd_header header; - - u8 role_id; - u8 role_type; - u8 mac_address[ETH_ALEN]; -} __packed; - -struct wl12xx_cmd_role_disable { - struct wl1271_cmd_header header; - - u8 role_id; - u8 padding[3]; -} __packed; - -enum wl12xx_band { - WL12XX_BAND_2_4GHZ = 0, - WL12XX_BAND_5GHZ = 1, - WL12XX_BAND_JAPAN_4_9_GHZ = 2, - WL12XX_BAND_DEFAULT = WL12XX_BAND_2_4GHZ, - WL12XX_BAND_INVALID = 0x7E, - WL12XX_BAND_MAX_RADIO = 0x7F, -}; - -struct wl12xx_cmd_role_start { - struct wl1271_cmd_header header; - - u8 role_id; - u8 band; - u8 channel; - u8 padding; - - union { - struct { - u8 hlid; - u8 session; - u8 padding_1[54]; - } __packed device; - /* sta & p2p_cli use the same struct */ - struct { - u8 bssid[ETH_ALEN]; - u8 hlid; /* data hlid */ - u8 session; - __le32 remote_rates; /* remote supported rates */ - - /* - * The target uses this field to determine the rate at - * which to transmit control frame responses (such as - * ACK or CTS frames). - */ - __le32 basic_rate_set; - __le32 local_rates; /* local supported rates */ - - u8 ssid_type; - u8 ssid_len; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - - __le16 beacon_interval; /* in TBTTs */ - } __packed sta; - struct { - u8 bssid[ETH_ALEN]; - u8 hlid; /* data hlid */ - u8 dtim_interval; - __le32 remote_rates; /* remote supported rates */ - - __le32 basic_rate_set; - __le32 local_rates; /* local supported rates */ - - u8 ssid_type; - u8 ssid_len; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - - __le16 beacon_interval; /* in TBTTs */ - - u8 padding_1[4]; - } __packed ibss; - /* ap & p2p_go use the same struct */ - struct { - __le16 aging_period; /* in secs */ - u8 beacon_expiry; /* in ms */ - u8 bss_index; - /* The host link id for the AP's global queue */ - u8 global_hlid; - /* The host link id for the AP's broadcast queue */ - u8 broadcast_hlid; - - __le16 beacon_interval; /* in TBTTs */ - - __le32 basic_rate_set; - __le32 local_rates; /* local supported rates */ - - u8 dtim_interval; - - u8 ssid_type; - u8 ssid_len; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - - u8 reset_tsf; - - u8 padding_1[4]; - } __packed ap; - }; -} __packed; - -struct wl12xx_cmd_role_stop { - struct wl1271_cmd_header header; - - u8 role_id; - u8 disc_type; /* only STA and P2P_CLI */ - __le16 reason; /* only STA and P2P_CLI */ -} __packed; - -struct cmd_enabledisable_path { - struct wl1271_cmd_header header; - - u8 channel; - u8 padding[3]; -} __packed; - -#define WL1271_RATE_AUTOMATIC 0 - -struct wl1271_cmd_template_set { - struct wl1271_cmd_header header; - - u8 role_id; - u8 template_type; - __le16 len; - u8 index; /* relevant only for KLV_TEMPLATE type */ - u8 padding[3]; - - __le32 enabled_rates; - u8 short_retry_limit; - u8 long_retry_limit; - u8 aflags; - u8 reserved; - - u8 template_data[WL1271_CMD_TEMPL_MAX_SIZE]; -} __packed; - -#define TIM_ELE_ID 5 -#define PARTIAL_VBM_MAX 251 - -struct wl1271_tim { - u8 identity; - u8 length; - u8 dtim_count; - u8 dtim_period; - u8 bitmap_ctrl; - u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */ -} __packed; - -enum wl1271_cmd_ps_mode { - STATION_AUTO_PS_MODE, /* Dynamic Power Save */ - STATION_ACTIVE_MODE, - STATION_POWER_SAVE_MODE -}; - -struct wl1271_cmd_ps_params { - struct wl1271_cmd_header header; - - u8 role_id; - u8 ps_mode; /* STATION_* */ - u16 auto_ps_timeout; -} __packed; - -/* HW encryption keys */ -#define NUM_ACCESS_CATEGORIES_COPY 4 - -enum wl1271_cmd_key_action { - KEY_ADD_OR_REPLACE = 1, - KEY_REMOVE = 2, - KEY_SET_ID = 3, - MAX_KEY_ACTION = 0xffff, -}; - -enum wl1271_cmd_lid_key_type { - UNICAST_LID_TYPE = 0, - BROADCAST_LID_TYPE = 1, - WEP_DEFAULT_LID_TYPE = 2 -}; - -enum wl1271_cmd_key_type { - KEY_NONE = 0, - KEY_WEP = 1, - KEY_TKIP = 2, - KEY_AES = 3, - KEY_GEM = 4, -}; - -struct wl1271_cmd_set_keys { - struct wl1271_cmd_header header; - - /* - * Indicates whether the HLID is a unicast key set - * or broadcast key set. A special value 0xFF is - * used to indicate that the HLID is on WEP-default - * (multi-hlids). of type wl1271_cmd_lid_key_type. - */ - u8 hlid; - - /* - * In WEP-default network (hlid == 0xFF) used to - * indicate which network STA/IBSS/AP role should be - * changed - */ - u8 lid_key_type; - - /* - * Key ID - For TKIP and AES key types, this field - * indicates the value that should be inserted into - * the KeyID field of frames transmitted using this - * key entry. For broadcast keys the index use as a - * marker for TX/RX key. - * For WEP default network (HLID=0xFF), this field - * indicates the ID of the key to add or remove. - */ - u8 key_id; - u8 reserved_1; - - /* key_action_e */ - __le16 key_action; - - /* key size in bytes */ - u8 key_size; - - /* key_type_e */ - u8 key_type; - - /* This field holds the security key data to add to the STA table */ - u8 key[MAX_KEY_SIZE]; - __le16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; - __le32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; -} __packed; - -struct wl1271_cmd_test_header { - u8 id; - u8 padding[3]; -} __packed; - -enum wl1271_channel_tune_bands { - WL1271_CHANNEL_TUNE_BAND_2_4, - WL1271_CHANNEL_TUNE_BAND_5, - WL1271_CHANNEL_TUNE_BAND_4_9 -}; - -#define WL1271_PD_REFERENCE_POINT_BAND_B_G 0 - -#define TEST_CMD_INI_FILE_RADIO_PARAM 0x19 -#define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E -#define TEST_CMD_INI_FILE_RF_EXTENDED_PARAM 0x26 - -struct wl1271_general_parms_cmd { - struct wl1271_cmd_header header; - - struct wl1271_cmd_test_header test; - - struct wl1271_ini_general_params general_params; - - u8 sr_debug_table[WL1271_INI_MAX_SMART_REFLEX_PARAM]; - u8 sr_sen_n_p; - u8 sr_sen_n_p_gain; - u8 sr_sen_nrn; - u8 sr_sen_prn; - u8 padding[3]; -} __packed; - -struct wl128x_general_parms_cmd { - struct wl1271_cmd_header header; - - struct wl1271_cmd_test_header test; - - struct wl128x_ini_general_params general_params; - - u8 sr_debug_table[WL1271_INI_MAX_SMART_REFLEX_PARAM]; - u8 sr_sen_n_p; - u8 sr_sen_n_p_gain; - u8 sr_sen_nrn; - u8 sr_sen_prn; - u8 padding[3]; -} __packed; - -struct wl1271_radio_parms_cmd { - struct wl1271_cmd_header header; - - struct wl1271_cmd_test_header test; - - /* Static radio parameters */ - struct wl1271_ini_band_params_2 static_params_2; - struct wl1271_ini_band_params_5 static_params_5; - - /* Dynamic radio parameters */ - struct wl1271_ini_fem_params_2 dyn_params_2; - u8 padding2; - struct wl1271_ini_fem_params_5 dyn_params_5; - u8 padding3[2]; -} __packed; - -struct wl128x_radio_parms_cmd { - struct wl1271_cmd_header header; - - struct wl1271_cmd_test_header test; - - /* Static radio parameters */ - struct wl128x_ini_band_params_2 static_params_2; - struct wl128x_ini_band_params_5 static_params_5; - - u8 fem_vendor_and_options; - - /* Dynamic radio parameters */ - struct wl128x_ini_fem_params_2 dyn_params_2; - u8 padding2; - struct wl128x_ini_fem_params_5 dyn_params_5; -} __packed; - -struct wl1271_ext_radio_parms_cmd { - struct wl1271_cmd_header header; - - struct wl1271_cmd_test_header test; - - u8 tx_per_channel_power_compensation_2[CONF_TX_PWR_COMPENSATION_LEN_2]; - u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5]; - u8 padding[3]; -} __packed; - -/* - * There are three types of disconnections: - * - * DISCONNECT_IMMEDIATE: the fw doesn't send any frames - * DISCONNECT_DEAUTH: the fw generates a DEAUTH request with the reason - * we have passed - * DISCONNECT_DISASSOC: the fw generates a DESASSOC request with the reason - * we have passed - */ -enum wl1271_disconnect_type { - DISCONNECT_IMMEDIATE, - DISCONNECT_DEAUTH, - DISCONNECT_DISASSOC -}; - -#define WL1271_CMD_STA_STATE_CONNECTED 1 - -struct wl12xx_cmd_set_peer_state { - struct wl1271_cmd_header header; - - u8 hlid; - u8 state; - u8 padding[2]; -} __packed; - -struct wl12xx_cmd_roc { - struct wl1271_cmd_header header; - - u8 role_id; - u8 channel; - u8 band; - u8 padding; -}; - -struct wl12xx_cmd_croc { - struct wl1271_cmd_header header; - - u8 role_id; - u8 padding[3]; -}; - -enum wl12xx_ssid_type { - WL12XX_SSID_TYPE_PUBLIC = 0, - WL12XX_SSID_TYPE_HIDDEN = 1, - WL12XX_SSID_TYPE_ANY = 2, -}; - -enum wl1271_psd_type { - WL1271_PSD_LEGACY = 0, - WL1271_PSD_UPSD_TRIGGER = 1, - WL1271_PSD_LEGACY_PSPOLL = 2, - WL1271_PSD_SAPSD = 3 -}; - -struct wl12xx_cmd_add_peer { - struct wl1271_cmd_header header; - - u8 addr[ETH_ALEN]; - u8 hlid; - u8 aid; - u8 psd_type[NUM_ACCESS_CATEGORIES_COPY]; - __le32 supported_rates; - u8 bss_index; - u8 sp_len; - u8 wmm; - u8 padding1; -} __packed; - -struct wl12xx_cmd_remove_peer { - struct wl1271_cmd_header header; - - u8 hlid; - u8 reason_opcode; - u8 send_deauth_flag; - u8 padding1; -} __packed; - -/* - * Continuous mode - packets are transferred to the host periodically - * via the data path. - * On demand - Log messages are stored in a cyclic buffer in the - * firmware, and only transferred to the host when explicitly requested - */ -enum wl12xx_fwlogger_log_mode { - WL12XX_FWLOG_CONTINUOUS, - WL12XX_FWLOG_ON_DEMAND -}; - -/* Include/exclude timestamps from the log messages */ -enum wl12xx_fwlogger_timestamp { - WL12XX_FWLOG_TIMESTAMP_DISABLED, - WL12XX_FWLOG_TIMESTAMP_ENABLED -}; - -/* - * Logs can be routed to the debug pinouts (where available), to the host bus - * (SDIO/SPI), or dropped - */ -enum wl12xx_fwlogger_output { - WL12XX_FWLOG_OUTPUT_NONE, - WL12XX_FWLOG_OUTPUT_DBG_PINS, - WL12XX_FWLOG_OUTPUT_HOST, -}; - -struct wl12xx_cmd_config_fwlog { - struct wl1271_cmd_header header; - - /* See enum wl12xx_fwlogger_log_mode */ - u8 logger_mode; - - /* Minimum log level threshold */ - u8 log_severity; - - /* Include/exclude timestamps from the log messages */ - u8 timestamp; - - /* See enum wl1271_fwlogger_output */ - u8 output; - - /* Regulates the frequency of log messages */ - u8 threshold; - - u8 padding[3]; -} __packed; - -struct wl12xx_cmd_start_fwlog { - struct wl1271_cmd_header header; -} __packed; - -struct wl12xx_cmd_stop_fwlog { - struct wl1271_cmd_header header; -} __packed; - -struct wl12xx_cmd_channel_switch { - struct wl1271_cmd_header header; - - u8 role_id; - - /* The new serving channel */ - u8 channel; - /* Relative time of the serving channel switch in TBTT units */ - u8 switch_time; - /* Stop the role TX, should expect it after radar detection */ - u8 stop_tx; - /* The target channel tx status 1-stopped 0-open*/ - u8 post_switch_tx_disable; - - u8 padding[3]; -} __packed; - -struct wl12xx_cmd_stop_channel_switch { - struct wl1271_cmd_header header; -} __packed; - -#endif /* __WL1271_CMD_H__ */ diff --git a/trunk/drivers/net/wireless/wl12xx/conf.h b/trunk/drivers/net/wireless/wl12xx/conf.h deleted file mode 100644 index 3e581e19424c..000000000000 --- a/trunk/drivers/net/wireless/wl12xx/conf.h +++ /dev/null @@ -1,1311 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __CONF_H__ -#define __CONF_H__ - -enum { - CONF_HW_BIT_RATE_1MBPS = BIT(0), - CONF_HW_BIT_RATE_2MBPS = BIT(1), - CONF_HW_BIT_RATE_5_5MBPS = BIT(2), - CONF_HW_BIT_RATE_6MBPS = BIT(3), - CONF_HW_BIT_RATE_9MBPS = BIT(4), - CONF_HW_BIT_RATE_11MBPS = BIT(5), - CONF_HW_BIT_RATE_12MBPS = BIT(6), - CONF_HW_BIT_RATE_18MBPS = BIT(7), - CONF_HW_BIT_RATE_22MBPS = BIT(8), - CONF_HW_BIT_RATE_24MBPS = BIT(9), - CONF_HW_BIT_RATE_36MBPS = BIT(10), - CONF_HW_BIT_RATE_48MBPS = BIT(11), - CONF_HW_BIT_RATE_54MBPS = BIT(12), - CONF_HW_BIT_RATE_MCS_0 = BIT(13), - CONF_HW_BIT_RATE_MCS_1 = BIT(14), - CONF_HW_BIT_RATE_MCS_2 = BIT(15), - CONF_HW_BIT_RATE_MCS_3 = BIT(16), - CONF_HW_BIT_RATE_MCS_4 = BIT(17), - CONF_HW_BIT_RATE_MCS_5 = BIT(18), - CONF_HW_BIT_RATE_MCS_6 = BIT(19), - CONF_HW_BIT_RATE_MCS_7 = BIT(20) -}; - -enum { - CONF_HW_RATE_INDEX_1MBPS = 0, - CONF_HW_RATE_INDEX_2MBPS = 1, - CONF_HW_RATE_INDEX_5_5MBPS = 2, - CONF_HW_RATE_INDEX_6MBPS = 3, - CONF_HW_RATE_INDEX_9MBPS = 4, - CONF_HW_RATE_INDEX_11MBPS = 5, - CONF_HW_RATE_INDEX_12MBPS = 6, - CONF_HW_RATE_INDEX_18MBPS = 7, - CONF_HW_RATE_INDEX_22MBPS = 8, - CONF_HW_RATE_INDEX_24MBPS = 9, - CONF_HW_RATE_INDEX_36MBPS = 10, - CONF_HW_RATE_INDEX_48MBPS = 11, - CONF_HW_RATE_INDEX_54MBPS = 12, - CONF_HW_RATE_INDEX_MAX = CONF_HW_RATE_INDEX_54MBPS, -}; - -enum { - CONF_HW_RXTX_RATE_MCS7_SGI = 0, - CONF_HW_RXTX_RATE_MCS7, - CONF_HW_RXTX_RATE_MCS6, - CONF_HW_RXTX_RATE_MCS5, - CONF_HW_RXTX_RATE_MCS4, - CONF_HW_RXTX_RATE_MCS3, - CONF_HW_RXTX_RATE_MCS2, - CONF_HW_RXTX_RATE_MCS1, - CONF_HW_RXTX_RATE_MCS0, - CONF_HW_RXTX_RATE_54, - CONF_HW_RXTX_RATE_48, - CONF_HW_RXTX_RATE_36, - CONF_HW_RXTX_RATE_24, - CONF_HW_RXTX_RATE_22, - CONF_HW_RXTX_RATE_18, - CONF_HW_RXTX_RATE_12, - CONF_HW_RXTX_RATE_11, - CONF_HW_RXTX_RATE_9, - CONF_HW_RXTX_RATE_6, - CONF_HW_RXTX_RATE_5_5, - CONF_HW_RXTX_RATE_2, - CONF_HW_RXTX_RATE_1, - CONF_HW_RXTX_RATE_MAX, - CONF_HW_RXTX_RATE_UNSUPPORTED = 0xff -}; - -/* Rates between and including these are MCS rates */ -#define CONF_HW_RXTX_RATE_MCS_MIN CONF_HW_RXTX_RATE_MCS7_SGI -#define CONF_HW_RXTX_RATE_MCS_MAX CONF_HW_RXTX_RATE_MCS0 - -enum { - CONF_SG_DISABLE = 0, - CONF_SG_PROTECTIVE, - CONF_SG_OPPORTUNISTIC -}; - -enum { - /* - * Configure the min and max time BT gains the antenna - * in WLAN / BT master basic rate - * - * Range: 0 - 255 (ms) - */ - CONF_SG_ACL_BT_MASTER_MIN_BR = 0, - CONF_SG_ACL_BT_MASTER_MAX_BR, - - /* - * Configure the min and max time BT gains the antenna - * in WLAN / BT slave basic rate - * - * Range: 0 - 255 (ms) - */ - CONF_SG_ACL_BT_SLAVE_MIN_BR, - CONF_SG_ACL_BT_SLAVE_MAX_BR, - - /* - * Configure the min and max time BT gains the antenna - * in WLAN / BT master EDR - * - * Range: 0 - 255 (ms) - */ - CONF_SG_ACL_BT_MASTER_MIN_EDR, - CONF_SG_ACL_BT_MASTER_MAX_EDR, - - /* - * Configure the min and max time BT gains the antenna - * in WLAN / BT slave EDR - * - * Range: 0 - 255 (ms) - */ - CONF_SG_ACL_BT_SLAVE_MIN_EDR, - CONF_SG_ACL_BT_SLAVE_MAX_EDR, - - /* - * The maximum time WLAN can gain the antenna - * in WLAN PSM / BT master/slave BR - * - * Range: 0 - 255 (ms) - */ - CONF_SG_ACL_WLAN_PS_MASTER_BR, - CONF_SG_ACL_WLAN_PS_SLAVE_BR, - - /* - * The maximum time WLAN can gain the antenna - * in WLAN PSM / BT master/slave EDR - * - * Range: 0 - 255 (ms) - */ - CONF_SG_ACL_WLAN_PS_MASTER_EDR, - CONF_SG_ACL_WLAN_PS_SLAVE_EDR, - - /* TODO: explain these values */ - CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR, - CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR, - CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR, - CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR, - CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR, - CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR, - CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR, - CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR, - - CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR, - CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR, - CONF_SG_ACL_PASSIVE_SCAN_BT_BR, - CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR, - CONF_SG_ACL_PASSIVE_SCAN_BT_EDR, - CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR, - - /* - * Compensation percentage of probe requests when scan initiated - * during BT voice/ACL link. - * - * Range: 0 - 255 (%) - */ - CONF_SG_AUTO_SCAN_PROBE_REQ, - - /* - * Compensation percentage of probe requests when active scan initiated - * during BT voice - * - * Range: 0 - 255 (%) - */ - CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3, - - /* - * Compensation percentage of WLAN active scan window if initiated - * during BT A2DP - * - * Range: 0 - 1000 (%) - */ - CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP, - - /* - * Compensation percentage of WLAN passive scan window if initiated - * during BT A2DP BR - * - * Range: 0 - 1000 (%) - */ - CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR, - - /* - * Compensation percentage of WLAN passive scan window if initiated - * during BT A2DP EDR - * - * Range: 0 - 1000 (%) - */ - CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR, - - /* - * Compensation percentage of WLAN passive scan window if initiated - * during BT voice - * - * Range: 0 - 1000 (%) - */ - CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3, - - /* TODO: explain these values */ - CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN, - CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN, - CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN, - - /* - * Defines whether the SG will force WLAN host to enter/exit PSM - * - * Range: 1 - SG can force, 0 - host handles PSM - */ - CONF_SG_STA_FORCE_PS_IN_BT_SCO, - - /* - * Defines antenna configuration (single/dual antenna) - * - * Range: 0 - single antenna, 1 - dual antenna - */ - CONF_SG_ANTENNA_CONFIGURATION, - - /* - * The threshold (percent) of max consecutive beacon misses before - * increasing priority of beacon reception. - * - * Range: 0 - 100 (%) - */ - CONF_SG_BEACON_MISS_PERCENT, - - /* - * Protection time of the DHCP procedure. - * - * Range: 0 - 100000 (ms) - */ - CONF_SG_DHCP_TIME, - - /* - * RX guard time before the beginning of a new BT voice frame during - * which no new WLAN trigger frame is transmitted. - * - * Range: 0 - 100000 (us) - */ - CONF_SG_RXT, - - /* - * TX guard time before the beginning of a new BT voice frame during - * which no new WLAN frame is transmitted. - * - * Range: 0 - 100000 (us) - */ - - CONF_SG_TXT, - - /* - * Enable adaptive RXT/TXT algorithm. If disabled, the host values - * will be utilized. - * - * Range: 0 - disable, 1 - enable - */ - CONF_SG_ADAPTIVE_RXT_TXT, - - /* TODO: explain this value */ - CONF_SG_GENERAL_USAGE_BIT_MAP, - - /* - * Number of consecutive BT voice frames not interrupted by WLAN - * - * Range: 0 - 100 - */ - CONF_SG_HV3_MAX_SERVED, - - /* - * The used WLAN legacy service period during active BT ACL link - * - * Range: 0 - 255 (ms) - */ - CONF_SG_PS_POLL_TIMEOUT, - - /* - * The used WLAN UPSD service period during active BT ACL link - * - * Range: 0 - 255 (ms) - */ - CONF_SG_UPSD_TIMEOUT, - - CONF_SG_CONSECUTIVE_CTS_THRESHOLD, - CONF_SG_STA_RX_WINDOW_AFTER_DTIM, - CONF_SG_STA_CONNECTION_PROTECTION_TIME, - - /* AP params */ - CONF_AP_BEACON_MISS_TX, - CONF_AP_RX_WINDOW_AFTER_BEACON, - CONF_AP_BEACON_WINDOW_INTERVAL, - CONF_AP_CONNECTION_PROTECTION_TIME, - CONF_AP_BT_ACL_VAL_BT_SERVE_TIME, - CONF_AP_BT_ACL_VAL_WL_SERVE_TIME, - - /* CTS Diluting params */ - CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH, - CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER, - - CONF_SG_TEMP_PARAM_1, - CONF_SG_TEMP_PARAM_2, - CONF_SG_TEMP_PARAM_3, - CONF_SG_TEMP_PARAM_4, - CONF_SG_TEMP_PARAM_5, - CONF_SG_TEMP_PARAM_6, - CONF_SG_TEMP_PARAM_7, - CONF_SG_TEMP_PARAM_8, - CONF_SG_TEMP_PARAM_9, - CONF_SG_TEMP_PARAM_10, - - CONF_SG_PARAMS_MAX, - CONF_SG_PARAMS_ALL = 0xff -}; - -struct conf_sg_settings { - u32 params[CONF_SG_PARAMS_MAX]; - u8 state; -}; - -enum conf_rx_queue_type { - CONF_RX_QUEUE_TYPE_LOW_PRIORITY, /* All except the high priority */ - CONF_RX_QUEUE_TYPE_HIGH_PRIORITY, /* Management and voice packets */ -}; - -struct conf_rx_settings { - /* - * The maximum amount of time, in TU, before the - * firmware discards the MSDU. - * - * Range: 0 - 0xFFFFFFFF - */ - u32 rx_msdu_life_time; - - /* - * Packet detection threshold in the PHY. - * - * FIXME: details unknown. - */ - u32 packet_detection_threshold; - - /* - * The longest time the STA will wait to receive traffic from the AP - * after a PS-poll has been transmitted. - * - * Range: 0 - 200000 - */ - u16 ps_poll_timeout; - /* - * The longest time the STA will wait to receive traffic from the AP - * after a frame has been sent from an UPSD enabled queue. - * - * Range: 0 - 200000 - */ - u16 upsd_timeout; - - /* - * The number of octets in an MPDU, below which an RTS/CTS - * handshake is not performed. - * - * Range: 0 - 4096 - */ - u16 rts_threshold; - - /* - * The RX Clear Channel Assessment threshold in the PHY - * (the energy threshold). - * - * Range: ENABLE_ENERGY_D == 0x140A - * DISABLE_ENERGY_D == 0xFFEF - */ - u16 rx_cca_threshold; - - /* - * Occupied Rx mem-blocks number which requires interrupting the host - * (0 = no buffering, 0xffff = disabled). - * - * Range: u16 - */ - u16 irq_blk_threshold; - - /* - * Rx packets number which requires interrupting the host - * (0 = no buffering). - * - * Range: u16 - */ - u16 irq_pkt_threshold; - - /* - * Max time in msec the FW may delay RX-Complete interrupt. - * - * Range: 1 - 100 - */ - u16 irq_timeout; - - /* - * The RX queue type. - * - * Range: RX_QUEUE_TYPE_RX_LOW_PRIORITY, RX_QUEUE_TYPE_RX_HIGH_PRIORITY, - */ - u8 queue_type; -}; - -#define CONF_TX_MAX_RATE_CLASSES 10 - -#define CONF_TX_RATE_MASK_UNSPECIFIED 0 -#define CONF_TX_RATE_MASK_BASIC (CONF_HW_BIT_RATE_1MBPS | \ - CONF_HW_BIT_RATE_2MBPS) -#define CONF_TX_RATE_RETRY_LIMIT 10 - -/* basic rates for p2p operations (probe req/resp, etc.) */ -#define CONF_TX_RATE_MASK_BASIC_P2P (CONF_HW_BIT_RATE_6MBPS | \ - CONF_HW_BIT_RATE_12MBPS | CONF_HW_BIT_RATE_24MBPS) - -/* - * Rates supported for data packets when operating as AP. Note the absence - * of the 22Mbps rate. There is a FW limitation on 12 rates so we must drop - * one. The rate dropped is not mandatory under any operating mode. - */ -#define CONF_TX_AP_ENABLED_RATES (CONF_HW_BIT_RATE_1MBPS | \ - CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \ - CONF_HW_BIT_RATE_6MBPS | CONF_HW_BIT_RATE_9MBPS | \ - CONF_HW_BIT_RATE_11MBPS | CONF_HW_BIT_RATE_12MBPS | \ - CONF_HW_BIT_RATE_18MBPS | CONF_HW_BIT_RATE_24MBPS | \ - CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \ - CONF_HW_BIT_RATE_54MBPS) - -#define CONF_TX_CCK_RATES (CONF_HW_BIT_RATE_1MBPS | \ - CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \ - CONF_HW_BIT_RATE_11MBPS) - -#define CONF_TX_OFDM_RATES (CONF_HW_BIT_RATE_6MBPS | \ - CONF_HW_BIT_RATE_12MBPS | CONF_HW_BIT_RATE_24MBPS | \ - CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \ - CONF_HW_BIT_RATE_54MBPS) - -#define CONF_TX_MCS_RATES (CONF_HW_BIT_RATE_MCS_0 | \ - CONF_HW_BIT_RATE_MCS_1 | CONF_HW_BIT_RATE_MCS_2 | \ - CONF_HW_BIT_RATE_MCS_3 | CONF_HW_BIT_RATE_MCS_4 | \ - CONF_HW_BIT_RATE_MCS_5 | CONF_HW_BIT_RATE_MCS_6 | \ - CONF_HW_BIT_RATE_MCS_7) - -/* - * Default rates for management traffic when operating in AP mode. This - * should be configured according to the basic rate set of the AP - */ -#define CONF_TX_AP_DEFAULT_MGMT_RATES (CONF_HW_BIT_RATE_1MBPS | \ - CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS) - -/* default rates for working as IBSS (11b and OFDM) */ -#define CONF_TX_IBSS_DEFAULT_RATES (CONF_HW_BIT_RATE_1MBPS | \ - CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \ - CONF_HW_BIT_RATE_11MBPS | CONF_TX_OFDM_RATES); - -struct conf_tx_rate_class { - - /* - * The rates enabled for this rate class. - * - * Range: CONF_HW_BIT_RATE_* bit mask - */ - u32 enabled_rates; - - /* - * The dot11 short retry limit used for TX retries. - * - * Range: u8 - */ - u8 short_retry_limit; - - /* - * The dot11 long retry limit used for TX retries. - * - * Range: u8 - */ - u8 long_retry_limit; - - /* - * Flags controlling the attributes of TX transmission. - * - * Range: bit 0: Truncate - when set, FW attempts to send a frame stop - * when the total valid per-rate attempts have - * been exhausted; otherwise transmissions - * will continue at the lowest available rate - * until the appropriate one of the - * short_retry_limit, long_retry_limit, - * dot11_max_transmit_msdu_life_time, or - * max_tx_life_time, is exhausted. - * 1: Preamble Override - indicates if the preamble type - * should be used in TX. - * 2: Preamble Type - the type of the preamble to be used by - * the policy (0 - long preamble, 1 - short preamble. - */ - u8 aflags; -}; - -#define CONF_TX_MAX_AC_COUNT 4 - -/* Slot number setting to start transmission at PIFS interval */ -#define CONF_TX_AIFS_PIFS 1 -/* Slot number setting to start transmission at DIFS interval normal - * DCF access */ -#define CONF_TX_AIFS_DIFS 2 - - -enum conf_tx_ac { - CONF_TX_AC_BE = 0, /* best effort / legacy */ - CONF_TX_AC_BK = 1, /* background */ - CONF_TX_AC_VI = 2, /* video */ - CONF_TX_AC_VO = 3, /* voice */ - CONF_TX_AC_CTS2SELF = 4, /* fictitious AC, follows AC_VO */ - CONF_TX_AC_ANY_TID = 0x1f -}; - -struct conf_tx_ac_category { - /* - * The AC class identifier. - * - * Range: enum conf_tx_ac - */ - u8 ac; - - /* - * The contention window minimum size (in slots) for the access - * class. - * - * Range: u8 - */ - u8 cw_min; - - /* - * The contention window maximum size (in slots) for the access - * class. - * - * Range: u8 - */ - u16 cw_max; - - /* - * The AIF value (in slots) for the access class. - * - * Range: u8 - */ - u8 aifsn; - - /* - * The TX Op Limit (in microseconds) for the access class. - * - * Range: u16 - */ - u16 tx_op_limit; -}; - -#define CONF_TX_MAX_TID_COUNT 8 - -/* Allow TX BA on all TIDs but 6,7. These are currently reserved in the FW */ -#define CONF_TX_BA_ENABLED_TID_BITMAP 0x3F - -enum { - CONF_CHANNEL_TYPE_DCF = 0, /* DC/LEGACY*/ - CONF_CHANNEL_TYPE_EDCF = 1, /* EDCA*/ - CONF_CHANNEL_TYPE_HCCA = 2, /* HCCA*/ -}; - -enum { - CONF_PS_SCHEME_LEGACY = 0, - CONF_PS_SCHEME_UPSD_TRIGGER = 1, - CONF_PS_SCHEME_LEGACY_PSPOLL = 2, - CONF_PS_SCHEME_SAPSD = 3, -}; - -enum { - CONF_ACK_POLICY_LEGACY = 0, - CONF_ACK_POLICY_NO_ACK = 1, - CONF_ACK_POLICY_BLOCK = 2, -}; - - -struct conf_tx_tid { - u8 queue_id; - u8 channel_type; - u8 tsid; - u8 ps_scheme; - u8 ack_policy; - u32 apsd_conf[2]; -}; - -struct conf_tx_settings { - /* - * The TX ED value for TELEC Enable/Disable. - * - * Range: 0, 1 - */ - u8 tx_energy_detection; - - /* - * Configuration for rate classes for TX (currently only one - * rate class supported). Used in non-AP mode. - */ - struct conf_tx_rate_class sta_rc_conf; - - /* - * Configuration for access categories for TX rate control. - */ - u8 ac_conf_count; - struct conf_tx_ac_category ac_conf[CONF_TX_MAX_AC_COUNT]; - - /* - * AP-mode - allow this number of TX retries to a station before an - * event is triggered from FW. - * In AP-mode the hlids of unreachable stations are given in the - * "sta_tx_retry_exceeded" member in the event mailbox. - */ - u8 max_tx_retries; - - /* - * AP-mode - after this number of seconds a connected station is - * considered inactive. - */ - u16 ap_aging_period; - - /* - * Configuration for TID parameters. - */ - u8 tid_conf_count; - struct conf_tx_tid tid_conf[CONF_TX_MAX_TID_COUNT]; - - /* - * The TX fragmentation threshold. - * - * Range: u16 - */ - u16 frag_threshold; - - /* - * Max time in msec the FW may delay frame TX-Complete interrupt. - * - * Range: u16 - */ - u16 tx_compl_timeout; - - /* - * Completed TX packet count which requires to issue the TX-Complete - * interrupt. - * - * Range: u16 - */ - u16 tx_compl_threshold; - - /* - * The rate used for control messages and scanning on the 2.4GHz band - * - * Range: CONF_HW_BIT_RATE_* bit mask - */ - u32 basic_rate; - - /* - * The rate used for control messages and scanning on the 5GHz band - * - * Range: CONF_HW_BIT_RATE_* bit mask - */ - u32 basic_rate_5; - - /* - * TX retry limits for templates - */ - u8 tmpl_short_retry_limit; - u8 tmpl_long_retry_limit; - - /* Time in ms for Tx watchdog timer to expire */ - u32 tx_watchdog_timeout; -}; - -enum { - CONF_WAKE_UP_EVENT_BEACON = 0x01, /* Wake on every Beacon*/ - CONF_WAKE_UP_EVENT_DTIM = 0x02, /* Wake on every DTIM*/ - CONF_WAKE_UP_EVENT_N_DTIM = 0x04, /* Wake every Nth DTIM */ - CONF_WAKE_UP_EVENT_N_BEACONS = 0x08, /* Wake every Nth beacon */ - CONF_WAKE_UP_EVENT_BITS_MASK = 0x0F -}; - -#define CONF_MAX_BCN_FILT_IE_COUNT 32 - -#define CONF_BCN_RULE_PASS_ON_CHANGE BIT(0) -#define CONF_BCN_RULE_PASS_ON_APPEARANCE BIT(1) - -#define CONF_BCN_IE_OUI_LEN 3 -#define CONF_BCN_IE_VER_LEN 2 - -struct conf_bcn_filt_rule { - /* - * IE number to which to associate a rule. - * - * Range: u8 - */ - u8 ie; - - /* - * Rule to associate with the specific ie. - * - * Range: CONF_BCN_RULE_PASS_ON_* - */ - u8 rule; - - /* - * OUI for the vendor specifie IE (221) - */ - u8 oui[CONF_BCN_IE_OUI_LEN]; - - /* - * Type for the vendor specifie IE (221) - */ - u8 type; - - /* - * Version for the vendor specifie IE (221) - */ - u8 version[CONF_BCN_IE_VER_LEN]; -}; - -#define CONF_MAX_RSSI_SNR_TRIGGERS 8 - -enum { - CONF_TRIG_METRIC_RSSI_BEACON = 0, - CONF_TRIG_METRIC_RSSI_DATA, - CONF_TRIG_METRIC_SNR_BEACON, - CONF_TRIG_METRIC_SNR_DATA -}; - -enum { - CONF_TRIG_EVENT_TYPE_LEVEL = 0, - CONF_TRIG_EVENT_TYPE_EDGE -}; - -enum { - CONF_TRIG_EVENT_DIR_LOW = 0, - CONF_TRIG_EVENT_DIR_HIGH, - CONF_TRIG_EVENT_DIR_BIDIR -}; - -struct conf_sig_weights { - - /* - * RSSI from beacons average weight. - * - * Range: u8 - */ - u8 rssi_bcn_avg_weight; - - /* - * RSSI from data average weight. - * - * Range: u8 - */ - u8 rssi_pkt_avg_weight; - - /* - * SNR from beacons average weight. - * - * Range: u8 - */ - u8 snr_bcn_avg_weight; - - /* - * SNR from data average weight. - * - * Range: u8 - */ - u8 snr_pkt_avg_weight; -}; - -enum conf_bcn_filt_mode { - CONF_BCN_FILT_MODE_DISABLED = 0, - CONF_BCN_FILT_MODE_ENABLED = 1 -}; - -enum conf_bet_mode { - CONF_BET_MODE_DISABLE = 0, - CONF_BET_MODE_ENABLE = 1, -}; - -struct conf_conn_settings { - /* - * Firmware wakeup conditions configuration. The host may set only - * one bit. - * - * Range: CONF_WAKE_UP_EVENT_* - */ - u8 wake_up_event; - - /* - * Listen interval for beacons or Dtims. - * - * Range: 0 for beacon and Dtim wakeup - * 1-10 for x Dtims - * 1-255 for x beacons - */ - u8 listen_interval; - - /* - * Firmware wakeup conditions during suspend - * Range: CONF_WAKE_UP_EVENT_* - */ - u8 suspend_wake_up_event; - - /* - * Listen interval during suspend. - * Currently will be in DTIMs (1-10) - * - */ - u8 suspend_listen_interval; - - /* - * Enable or disable the beacon filtering. - * - * Range: CONF_BCN_FILT_MODE_* - */ - enum conf_bcn_filt_mode bcn_filt_mode; - - /* - * Configure Beacon filter pass-thru rules. - */ - u8 bcn_filt_ie_count; - struct conf_bcn_filt_rule bcn_filt_ie[CONF_MAX_BCN_FILT_IE_COUNT]; - - /* - * The number of consecutive beacons to lose, before the firmware - * becomes out of synch. - * - * Range: u32 - */ - u32 synch_fail_thold; - - /* - * After out-of-synch, the number of TU's to wait without a further - * received beacon (or probe response) before issuing the BSS_EVENT_LOSE - * event. - * - * Range: u32 - */ - u32 bss_lose_timeout; - - /* - * Beacon receive timeout. - * - * Range: u32 - */ - u32 beacon_rx_timeout; - - /* - * Broadcast receive timeout. - * - * Range: u32 - */ - u32 broadcast_timeout; - - /* - * Enable/disable reception of broadcast packets in power save mode - * - * Range: 1 - enable, 0 - disable - */ - u8 rx_broadcast_in_ps; - - /* - * Consecutive PS Poll failures before sending event to driver - * - * Range: u8 - */ - u8 ps_poll_threshold; - - /* - * Configuration of signal average weights. - */ - struct conf_sig_weights sig_weights; - - /* - * Specifies if beacon early termination procedure is enabled or - * disabled. - * - * Range: CONF_BET_MODE_* - */ - u8 bet_enable; - - /* - * Specifies the maximum number of consecutive beacons that may be - * early terminated. After this number is reached at least one full - * beacon must be correctly received in FW before beacon ET - * resumes. - * - * Range 0 - 255 - */ - u8 bet_max_consecutive; - - /* - * Specifies the maximum number of times to try PSM entry if it fails - * (if sending the appropriate null-func message fails.) - * - * Range 0 - 255 - */ - u8 psm_entry_retries; - - /* - * Specifies the maximum number of times to try PSM exit if it fails - * (if sending the appropriate null-func message fails.) - * - * Range 0 - 255 - */ - u8 psm_exit_retries; - - /* - * Specifies the maximum number of times to try transmit the PSM entry - * null-func frame for each PSM entry attempt - * - * Range 0 - 255 - */ - u8 psm_entry_nullfunc_retries; - - /* - * Specifies the dynamic PS timeout in ms that will be used - * by the FW when in AUTO_PS mode - */ - u16 dynamic_ps_timeout; - - /* - * Specifies whether dynamic PS should be disabled and PSM forced. - * This is required for certain WiFi certification tests. - */ - u8 forced_ps; - - /* - * - * Specifies the interval of the connection keep-alive null-func - * frame in ms. - * - * Range: 1000 - 3600000 - */ - u32 keep_alive_interval; - - /* - * Maximum listen interval supported by the driver in units of beacons. - * - * Range: u16 - */ - u8 max_listen_interval; -}; - -enum { - CONF_REF_CLK_19_2_E, - CONF_REF_CLK_26_E, - CONF_REF_CLK_38_4_E, - CONF_REF_CLK_52_E, - CONF_REF_CLK_38_4_M_XTAL, - CONF_REF_CLK_26_M_XTAL, -}; - -enum single_dual_band_enum { - CONF_SINGLE_BAND, - CONF_DUAL_BAND -}; - -#define CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE 15 -#define CONF_NUMBER_OF_SUB_BANDS_5 7 -#define CONF_NUMBER_OF_RATE_GROUPS 6 -#define CONF_NUMBER_OF_CHANNELS_2_4 14 -#define CONF_NUMBER_OF_CHANNELS_5 35 - -struct conf_itrim_settings { - /* enable dco itrim */ - u8 enable; - - /* moderation timeout in microsecs from the last TX */ - u32 timeout; -}; - -struct conf_pm_config_settings { - /* - * Host clock settling time - * - * Range: 0 - 30000 us - */ - u32 host_clk_settling_time; - - /* - * Host fast wakeup support - * - * Range: true, false - */ - bool host_fast_wakeup_support; -}; - -struct conf_roam_trigger_settings { - /* - * The minimum interval between two trigger events. - * - * Range: 0 - 60000 ms - */ - u16 trigger_pacing; - - /* - * The weight for rssi/beacon average calculation - * - * Range: 0 - 255 - */ - u8 avg_weight_rssi_beacon; - - /* - * The weight for rssi/data frame average calculation - * - * Range: 0 - 255 - */ - u8 avg_weight_rssi_data; - - /* - * The weight for snr/beacon average calculation - * - * Range: 0 - 255 - */ - u8 avg_weight_snr_beacon; - - /* - * The weight for snr/data frame average calculation - * - * Range: 0 - 255 - */ - u8 avg_weight_snr_data; -}; - -struct conf_scan_settings { - /* - * The minimum time to wait on each channel for active scans - * - * Range: u32 tu/1000 - */ - u32 min_dwell_time_active; - - /* - * The maximum time to wait on each channel for active scans - * - * Range: u32 tu/1000 - */ - u32 max_dwell_time_active; - - /* - * The minimum time to wait on each channel for passive scans - * - * Range: u32 tu/1000 - */ - u32 min_dwell_time_passive; - - /* - * The maximum time to wait on each channel for passive scans - * - * Range: u32 tu/1000 - */ - u32 max_dwell_time_passive; - - /* - * Number of probe requests to transmit on each active scan channel - * - * Range: u8 - */ - u16 num_probe_reqs; - - /* - * Scan trigger (split scan) timeout. The FW will split the scan - * operation into slices of the given time and allow the FW to schedule - * other tasks in between. - * - * Range: u32 Microsecs - */ - u32 split_scan_timeout; -}; - -struct conf_sched_scan_settings { - /* minimum time to wait on the channel for active scans (in TUs) */ - u16 min_dwell_time_active; - - /* maximum time to wait on the channel for active scans (in TUs) */ - u16 max_dwell_time_active; - - /* time to wait on the channel for passive scans (in TUs) */ - u32 dwell_time_passive; - - /* time to wait on the channel for DFS scans (in TUs) */ - u32 dwell_time_dfs; - - /* number of probe requests to send on each channel in active scans */ - u8 num_probe_reqs; - - /* RSSI threshold to be used for filtering */ - s8 rssi_threshold; - - /* SNR threshold to be used for filtering */ - s8 snr_threshold; -}; - -/* these are number of channels on the band divided by two, rounded up */ -#define CONF_TX_PWR_COMPENSATION_LEN_2 7 -#define CONF_TX_PWR_COMPENSATION_LEN_5 18 - -struct conf_rf_settings { - /* - * Per channel power compensation for 2.4GHz - * - * Range: s8 - */ - u8 tx_per_channel_power_compensation_2[CONF_TX_PWR_COMPENSATION_LEN_2]; - - /* - * Per channel power compensation for 5GHz - * - * Range: s8 - */ - u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5]; -}; - -struct conf_ht_setting { - u8 rx_ba_win_size; - u8 tx_ba_win_size; - u16 inactivity_timeout; - - /* bitmap of enabled TIDs for TX BA sessions */ - u8 tx_ba_tid_bitmap; -}; - -struct conf_memory_settings { - /* Number of stations supported in IBSS mode */ - u8 num_stations; - - /* Number of ssid profiles used in IBSS mode */ - u8 ssid_profiles; - - /* Number of memory buffers allocated to rx pool */ - u8 rx_block_num; - - /* Minimum number of blocks allocated to tx pool */ - u8 tx_min_block_num; - - /* Disable/Enable dynamic memory */ - u8 dynamic_memory; - - /* - * Minimum required free tx memory blocks in order to assure optimum - * performance - * - * Range: 0-120 - */ - u8 min_req_tx_blocks; - - /* - * Minimum required free rx memory blocks in order to assure optimum - * performance - * - * Range: 0-120 - */ - u8 min_req_rx_blocks; - - /* - * Minimum number of mem blocks (free+used) guaranteed for TX - * - * Range: 0-120 - */ - u8 tx_min; -}; - -struct conf_fm_coex { - u8 enable; - u8 swallow_period; - u8 n_divider_fref_set_1; - u8 n_divider_fref_set_2; - u16 m_divider_fref_set_1; - u16 m_divider_fref_set_2; - u32 coex_pll_stabilization_time; - u16 ldo_stabilization_time; - u8 fm_disturbed_band_margin; - u8 swallow_clk_diff; -}; - -struct conf_rx_streaming_settings { - /* - * RX Streaming duration (in msec) from last tx/rx - * - * Range: u32 - */ - u32 duration; - - /* - * Bitmap of tids to be polled during RX streaming. - * (Note: it doesn't look like it really matters) - * - * Range: 0x1-0xff - */ - u8 queues; - - /* - * RX Streaming interval. - * (Note:this value is also used as the rx streaming timeout) - * Range: 0 (disabled), 10 - 100 - */ - u8 interval; - - /* - * enable rx streaming also when there is no coex activity - */ - u8 always; -}; - -struct conf_fwlog { - /* Continuous or on-demand */ - u8 mode; - - /* - * Number of memory blocks dedicated for the FW logger - * - * Range: 1-3, or 0 to disable the FW logger - */ - u8 mem_blocks; - - /* Minimum log level threshold */ - u8 severity; - - /* Include/exclude timestamps from the log messages */ - u8 timestamp; - - /* See enum wl1271_fwlogger_output */ - u8 output; - - /* Regulates the frequency of log messages */ - u8 threshold; -}; - -#define ACX_RATE_MGMT_NUM_OF_RATES 13 -struct conf_rate_policy_settings { - u16 rate_retry_score; - u16 per_add; - u16 per_th1; - u16 per_th2; - u16 max_per; - u8 inverse_curiosity_factor; - u8 tx_fail_low_th; - u8 tx_fail_high_th; - u8 per_alpha_shift; - u8 per_add_shift; - u8 per_beta1_shift; - u8 per_beta2_shift; - u8 rate_check_up; - u8 rate_check_down; - u8 rate_retry_policy[ACX_RATE_MGMT_NUM_OF_RATES]; -}; - -struct conf_hangover_settings { - u32 recover_time; - u8 hangover_period; - u8 dynamic_mode; - u8 early_termination_mode; - u8 max_period; - u8 min_period; - u8 increase_delta; - u8 decrease_delta; - u8 quiet_time; - u8 increase_time; - u8 window_size; -}; - -struct conf_drv_settings { - struct conf_sg_settings sg; - struct conf_rx_settings rx; - struct conf_tx_settings tx; - struct conf_conn_settings conn; - struct conf_itrim_settings itrim; - struct conf_pm_config_settings pm_config; - struct conf_roam_trigger_settings roam_trigger; - struct conf_scan_settings scan; - struct conf_sched_scan_settings sched_scan; - struct conf_rf_settings rf; - struct conf_ht_setting ht; - struct conf_memory_settings mem_wl127x; - struct conf_memory_settings mem_wl128x; - struct conf_fm_coex fm_coex; - struct conf_rx_streaming_settings rx_streaming; - struct conf_fwlog fwlog; - struct conf_rate_policy_settings rate; - struct conf_hangover_settings hangover; - u8 hci_io_ds; -}; - -#endif diff --git a/trunk/drivers/net/wireless/wl12xx/debug.h b/trunk/drivers/net/wireless/wl12xx/debug.h deleted file mode 100644 index ec0fdc25b280..000000000000 --- a/trunk/drivers/net/wireless/wl12xx/debug.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 2011 Texas Instruments. All rights reserved. - * Copyright (C) 2008-2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __DEBUG_H__ -#define __DEBUG_H__ - -#include -#include - -#define DRIVER_NAME "wl12xx" -#define DRIVER_PREFIX DRIVER_NAME ": " - -enum { - DEBUG_NONE = 0, - DEBUG_IRQ = BIT(0), - DEBUG_SPI = BIT(1), - DEBUG_BOOT = BIT(2), - DEBUG_MAILBOX = BIT(3), - DEBUG_TESTMODE = BIT(4), - DEBUG_EVENT = BIT(5), - DEBUG_TX = BIT(6), - DEBUG_RX = BIT(7), - DEBUG_SCAN = BIT(8), - DEBUG_CRYPT = BIT(9), - DEBUG_PSM = BIT(10), - DEBUG_MAC80211 = BIT(11), - DEBUG_CMD = BIT(12), - DEBUG_ACX = BIT(13), - DEBUG_SDIO = BIT(14), - DEBUG_FILTERS = BIT(15), - DEBUG_ADHOC = BIT(16), - DEBUG_AP = BIT(17), - DEBUG_PROBE = BIT(18), - DEBUG_MASTER = (DEBUG_ADHOC | DEBUG_AP), - DEBUG_ALL = ~0, -}; - -extern u32 wl12xx_debug_level; - -#define DEBUG_DUMP_LIMIT 1024 - -#define wl1271_error(fmt, arg...) \ - pr_err(DRIVER_PREFIX "ERROR " fmt "\n", ##arg) - -#define wl1271_warning(fmt, arg...) \ - pr_warning(DRIVER_PREFIX "WARNING " fmt "\n", ##arg) - -#define wl1271_notice(fmt, arg...) \ - pr_info(DRIVER_PREFIX fmt "\n", ##arg) - -#define wl1271_info(fmt, arg...) \ - pr_info(DRIVER_PREFIX fmt "\n", ##arg) - -#define wl1271_debug(level, fmt, arg...) \ - do { \ - if (level & wl12xx_debug_level) \ - pr_debug(DRIVER_PREFIX fmt "\n", ##arg); \ - } while (0) - -/* TODO: use pr_debug_hex_dump when it becomes available */ -#define wl1271_dump(level, prefix, buf, len) \ - do { \ - if (level & wl12xx_debug_level) \ - print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ - DUMP_PREFIX_OFFSET, 16, 1, \ - buf, \ - min_t(size_t, len, DEBUG_DUMP_LIMIT), \ - 0); \ - } while (0) - -#define wl1271_dump_ascii(level, prefix, buf, len) \ - do { \ - if (level & wl12xx_debug_level) \ - print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ - DUMP_PREFIX_OFFSET, 16, 1, \ - buf, \ - min_t(size_t, len, DEBUG_DUMP_LIMIT), \ - true); \ - } while (0) - -#endif /* __DEBUG_H__ */ diff --git a/trunk/drivers/net/wireless/wl12xx/init.c b/trunk/drivers/net/wireless/wl12xx/init.c deleted file mode 100644 index 203fbebf09eb..000000000000 --- a/trunk/drivers/net/wireless/wl12xx/init.c +++ /dev/null @@ -1,765 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include -#include - -#include "debug.h" -#include "init.h" -#include "wl12xx_80211.h" -#include "acx.h" -#include "cmd.h" -#include "reg.h" -#include "tx.h" -#include "io.h" - -int wl1271_init_templates_config(struct wl1271 *wl) -{ - int ret, i; - size_t max_size; - - /* send empty templates for fw memory reservation */ - ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, - CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, - WL1271_CMD_TEMPL_MAX_SIZE, - 0, WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - - ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, - CMD_TEMPL_CFG_PROBE_REQ_5, - NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0, - WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - - ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, - CMD_TEMPL_NULL_DATA, NULL, - sizeof(struct wl12xx_null_data_template), - 0, WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - - ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, - CMD_TEMPL_PS_POLL, NULL, - sizeof(struct wl12xx_ps_poll_template), - 0, WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - - ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, - CMD_TEMPL_QOS_NULL_DATA, NULL, - sizeof - (struct ieee80211_qos_hdr), - 0, WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - - ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, - CMD_TEMPL_PROBE_RESPONSE, NULL, - WL1271_CMD_TEMPL_DFLT_SIZE, - 0, WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - - ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, - CMD_TEMPL_BEACON, NULL, - WL1271_CMD_TEMPL_DFLT_SIZE, - 0, WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - - max_size = sizeof(struct wl12xx_arp_rsp_template) + - WL1271_EXTRA_SPACE_MAX; - ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, - CMD_TEMPL_ARP_RSP, NULL, - max_size, - 0, WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - - /* - * Put very large empty placeholders for all templates. These - * reserve memory for later. - */ - ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, - CMD_TEMPL_AP_PROBE_RESPONSE, NULL, - WL1271_CMD_TEMPL_MAX_SIZE, - 0, WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - - ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, - CMD_TEMPL_AP_BEACON, NULL, - WL1271_CMD_TEMPL_MAX_SIZE, - 0, WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - - ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, - CMD_TEMPL_DEAUTH_AP, NULL, - sizeof - (struct wl12xx_disconn_template), - 0, WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - - for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { - ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, - CMD_TEMPL_KLV, NULL, - sizeof(struct ieee80211_qos_hdr), - i, WL1271_RATE_AUTOMATIC); - if (ret < 0) - return ret; - } - - return 0; -} - -static int wl1271_ap_init_deauth_template(struct wl1271 *wl, - struct wl12xx_vif *wlvif) -{ - struct wl12xx_disconn_template *tmpl; - int ret; - u32 rate; - - tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL); - if (!tmpl) { - ret = -ENOMEM; - goto out; - } - - tmpl->header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_DEAUTH); - - rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); - ret = wl1271_cmd_template_set(wl, wlvif->role_id, - CMD_TEMPL_DEAUTH_AP, - tmpl, sizeof(*tmpl), 0, rate); - -out: - kfree(tmpl); - return ret; -} - -static int wl1271_ap_init_null_template(struct wl1271 *wl, - struct ieee80211_vif *vif) -{ - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - struct ieee80211_hdr_3addr *nullfunc; - int ret; - u32 rate; - - nullfunc = kzalloc(sizeof(*nullfunc), GFP_KERNEL); - if (!nullfunc) { - ret = -ENOMEM; - goto out; - } - - nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | - IEEE80211_STYPE_NULLFUNC | - IEEE80211_FCTL_FROMDS); - - /* nullfunc->addr1 is filled by FW */ - - memcpy(nullfunc->addr2, vif->addr, ETH_ALEN); - memcpy(nullfunc->addr3, vif->addr, ETH_ALEN); - - rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); - ret = wl1271_cmd_template_set(wl, wlvif->role_id, - CMD_TEMPL_NULL_DATA, nullfunc, - sizeof(*nullfunc), 0, rate); - -out: - kfree(nullfunc); - return ret; -} - -static int wl1271_ap_init_qos_null_template(struct wl1271 *wl, - struct ieee80211_vif *vif) -{ - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - struct ieee80211_qos_hdr *qosnull; - int ret; - u32 rate; - - qosnull = kzalloc(sizeof(*qosnull), GFP_KERNEL); - if (!qosnull) { - ret = -ENOMEM; - goto out; - } - - qosnull->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | - IEEE80211_STYPE_QOS_NULLFUNC | - IEEE80211_FCTL_FROMDS); - - /* qosnull->addr1 is filled by FW */ - - memcpy(qosnull->addr2, vif->addr, ETH_ALEN); - memcpy(qosnull->addr3, vif->addr, ETH_ALEN); - - rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); - ret = wl1271_cmd_template_set(wl, wlvif->role_id, - CMD_TEMPL_QOS_NULL_DATA, qosnull, - sizeof(*qosnull), 0, rate); - -out: - kfree(qosnull); - return ret; -} - -static int wl12xx_init_rx_config(struct wl1271 *wl) -{ - int ret; - - ret = wl1271_acx_rx_msdu_life_time(wl); - if (ret < 0) - return ret; - - return 0; -} - -static int wl12xx_init_phy_vif_config(struct wl1271 *wl, - struct wl12xx_vif *wlvif) -{ - int ret; - - ret = wl1271_acx_slot(wl, wlvif, DEFAULT_SLOT_TIME); - if (ret < 0) - return ret; - - ret = wl1271_acx_service_period_timeout(wl, wlvif); - if (ret < 0) - return ret; - - ret = wl1271_acx_rts_threshold(wl, wlvif, wl->hw->wiphy->rts_threshold); - if (ret < 0) - return ret; - - return 0; -} - -static int wl1271_init_sta_beacon_filter(struct wl1271 *wl, - struct wl12xx_vif *wlvif) -{ - int ret; - - ret = wl1271_acx_beacon_filter_table(wl, wlvif); - if (ret < 0) - return ret; - - /* enable beacon filtering */ - ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true); - if (ret < 0) - return ret; - - return 0; -} - -int wl1271_init_pta(struct wl1271 *wl) -{ - int ret; - - ret = wl12xx_acx_sg_cfg(wl); - if (ret < 0) - return ret; - - ret = wl1271_acx_sg_enable(wl, wl->sg_enabled); - if (ret < 0) - return ret; - - return 0; -} - -int wl1271_init_energy_detection(struct wl1271 *wl) -{ - int ret; - - ret = wl1271_acx_cca_threshold(wl); - if (ret < 0) - return ret; - - return 0; -} - -static int wl1271_init_beacon_broadcast(struct wl1271 *wl, - struct wl12xx_vif *wlvif) -{ - int ret; - - ret = wl1271_acx_bcn_dtim_options(wl, wlvif); - if (ret < 0) - return ret; - - return 0; -} - -static int wl12xx_init_fwlog(struct wl1271 *wl) -{ - int ret; - - if (wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) - return 0; - - ret = wl12xx_cmd_config_fwlog(wl); - if (ret < 0) - return ret; - - return 0; -} - -/* generic sta initialization (non vif-specific) */ -static int wl1271_sta_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - int ret; - - /* PS config */ - ret = wl12xx_acx_config_ps(wl, wlvif); - if (ret < 0) - return ret; - - /* FM WLAN coexistence */ - ret = wl1271_acx_fm_coex(wl); - if (ret < 0) - return ret; - - ret = wl1271_acx_sta_rate_policies(wl, wlvif); - if (ret < 0) - return ret; - - return 0; -} - -static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl, - struct ieee80211_vif *vif) -{ - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - int ret, i; - - /* disable all keep-alive templates */ - for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { - ret = wl1271_acx_keep_alive_config(wl, wlvif, i, - ACX_KEEP_ALIVE_TPL_INVALID); - if (ret < 0) - return ret; - } - - /* disable the keep-alive feature */ - ret = wl1271_acx_keep_alive_mode(wl, wlvif, false); - if (ret < 0) - return ret; - - return 0; -} - -/* generic ap initialization (non vif-specific) */ -static int wl1271_ap_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - int ret; - - ret = wl1271_init_ap_rates(wl, wlvif); - if (ret < 0) - return ret; - - return 0; -} - -int wl1271_ap_init_templates(struct wl1271 *wl, struct ieee80211_vif *vif) -{ - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - int ret; - - ret = wl1271_ap_init_deauth_template(wl, wlvif); - if (ret < 0) - return ret; - - ret = wl1271_ap_init_null_template(wl, vif); - if (ret < 0) - return ret; - - ret = wl1271_ap_init_qos_null_template(wl, vif); - if (ret < 0) - return ret; - - /* - * when operating as AP we want to receive external beacons for - * configuring ERP protection. - */ - ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false); - if (ret < 0) - return ret; - - return 0; -} - -static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl, - struct ieee80211_vif *vif) -{ - return wl1271_ap_init_templates(wl, vif); -} - -int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - int i, ret; - struct conf_tx_rate_class rc; - u32 supported_rates; - - wl1271_debug(DEBUG_AP, "AP basic rate set: 0x%x", - wlvif->basic_rate_set); - - if (wlvif->basic_rate_set == 0) - return -EINVAL; - - rc.enabled_rates = wlvif->basic_rate_set; - rc.long_retry_limit = 10; - rc.short_retry_limit = 10; - rc.aflags = 0; - ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.mgmt_rate_idx); - if (ret < 0) - return ret; - - /* use the min basic rate for AP broadcast/multicast */ - rc.enabled_rates = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); - rc.short_retry_limit = 10; - rc.long_retry_limit = 10; - rc.aflags = 0; - ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.bcast_rate_idx); - if (ret < 0) - return ret; - - /* - * If the basic rates contain OFDM rates, use OFDM only - * rates for unicast TX as well. Else use all supported rates. - */ - if ((wlvif->basic_rate_set & CONF_TX_OFDM_RATES)) - supported_rates = CONF_TX_OFDM_RATES; - else - supported_rates = CONF_TX_AP_ENABLED_RATES; - - /* unconditionally enable HT rates */ - supported_rates |= CONF_TX_MCS_RATES; - - /* configure unicast TX rate classes */ - for (i = 0; i < wl->conf.tx.ac_conf_count; i++) { - rc.enabled_rates = supported_rates; - rc.short_retry_limit = 10; - rc.long_retry_limit = 10; - rc.aflags = 0; - ret = wl1271_acx_ap_rate_policy(wl, &rc, - wlvif->ap.ucast_rate_idx[i]); - if (ret < 0) - return ret; - } - - return 0; -} - -static int wl1271_set_ba_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - /* Reset the BA RX indicators */ - wlvif->ba_allowed = true; - wl->ba_rx_session_count = 0; - - /* BA is supported in STA/AP modes */ - if (wlvif->bss_type != BSS_TYPE_AP_BSS && - wlvif->bss_type != BSS_TYPE_STA_BSS) { - wlvif->ba_support = false; - return 0; - } - - wlvif->ba_support = true; - - /* 802.11n initiator BA session setting */ - return wl12xx_acx_set_ba_initiator_policy(wl, wlvif); -} - -int wl1271_chip_specific_init(struct wl1271 *wl) -{ - int ret = 0; - - if (wl->chip.id == CHIP_ID_1283_PG20) { - u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE; - - if (!(wl->quirks & WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT)) - /* Enable SDIO padding */ - host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK; - - /* Must be before wl1271_acx_init_mem_config() */ - ret = wl1271_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap); - if (ret < 0) - goto out; - } -out: - return ret; -} - -/* vif-specifc initialization */ -static int wl12xx_init_sta_role(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - int ret; - - ret = wl1271_acx_group_address_tbl(wl, wlvif, true, NULL, 0); - if (ret < 0) - return ret; - - /* Initialize connection monitoring thresholds */ - ret = wl1271_acx_conn_monit_params(wl, wlvif, false); - if (ret < 0) - return ret; - - /* Beacon filtering */ - ret = wl1271_init_sta_beacon_filter(wl, wlvif); - if (ret < 0) - return ret; - - /* Beacons and broadcast settings */ - ret = wl1271_init_beacon_broadcast(wl, wlvif); - if (ret < 0) - return ret; - - /* Configure rssi/snr averaging weights */ - ret = wl1271_acx_rssi_snr_avg_weights(wl, wlvif); - if (ret < 0) - return ret; - - return 0; -} - -/* vif-specific intialization */ -static int wl12xx_init_ap_role(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - int ret; - - ret = wl1271_acx_ap_max_tx_retry(wl, wlvif); - if (ret < 0) - return ret; - - /* initialize Tx power */ - ret = wl1271_acx_tx_power(wl, wlvif, wlvif->power_level); - if (ret < 0) - return ret; - - return 0; -} - -int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif) -{ - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - struct conf_tx_ac_category *conf_ac; - struct conf_tx_tid *conf_tid; - bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); - int ret, i; - - /* - * consider all existing roles before configuring psm. - * TODO: reconfigure on interface removal. - */ - if (!wl->ap_count) { - if (is_ap) { - /* Configure for power always on */ - ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); - if (ret < 0) - return ret; - } else if (!wl->sta_count) { - /* Configure for ELP power saving */ - ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); - if (ret < 0) - return ret; - } - } - - /* Mode specific init */ - if (is_ap) { - ret = wl1271_ap_hw_init(wl, wlvif); - if (ret < 0) - return ret; - - ret = wl12xx_init_ap_role(wl, wlvif); - if (ret < 0) - return ret; - } else { - ret = wl1271_sta_hw_init(wl, wlvif); - if (ret < 0) - return ret; - - ret = wl12xx_init_sta_role(wl, wlvif); - if (ret < 0) - return ret; - } - - wl12xx_init_phy_vif_config(wl, wlvif); - - /* Default TID/AC configuration */ - BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count); - for (i = 0; i < wl->conf.tx.tid_conf_count; i++) { - conf_ac = &wl->conf.tx.ac_conf[i]; - ret = wl1271_acx_ac_cfg(wl, wlvif, conf_ac->ac, - conf_ac->cw_min, conf_ac->cw_max, - conf_ac->aifsn, conf_ac->tx_op_limit); - if (ret < 0) - return ret; - - conf_tid = &wl->conf.tx.tid_conf[i]; - ret = wl1271_acx_tid_cfg(wl, wlvif, - conf_tid->queue_id, - conf_tid->channel_type, - conf_tid->tsid, - conf_tid->ps_scheme, - conf_tid->ack_policy, - conf_tid->apsd_conf[0], - conf_tid->apsd_conf[1]); - if (ret < 0) - return ret; - } - - /* Configure HW encryption */ - ret = wl1271_acx_feature_cfg(wl, wlvif); - if (ret < 0) - return ret; - - /* Mode specific init - post mem init */ - if (is_ap) - ret = wl1271_ap_hw_init_post_mem(wl, vif); - else - ret = wl1271_sta_hw_init_post_mem(wl, vif); - - if (ret < 0) - return ret; - - /* Configure initiator BA sessions policies */ - ret = wl1271_set_ba_policies(wl, wlvif); - if (ret < 0) - return ret; - - return 0; -} - -int wl1271_hw_init(struct wl1271 *wl) -{ - int ret; - - if (wl->chip.id == CHIP_ID_1283_PG20) { - ret = wl128x_cmd_general_parms(wl); - if (ret < 0) - return ret; - ret = wl128x_cmd_radio_parms(wl); - if (ret < 0) - return ret; - } else { - ret = wl1271_cmd_general_parms(wl); - if (ret < 0) - return ret; - ret = wl1271_cmd_radio_parms(wl); - if (ret < 0) - return ret; - ret = wl1271_cmd_ext_radio_parms(wl); - if (ret < 0) - return ret; - } - - /* Chip-specific init */ - ret = wl1271_chip_specific_init(wl); - if (ret < 0) - return ret; - - /* Init templates */ - ret = wl1271_init_templates_config(wl); - if (ret < 0) - return ret; - - ret = wl12xx_acx_mem_cfg(wl); - if (ret < 0) - return ret; - - /* Configure the FW logger */ - ret = wl12xx_init_fwlog(wl); - if (ret < 0) - return ret; - - /* Bluetooth WLAN coexistence */ - ret = wl1271_init_pta(wl); - if (ret < 0) - return ret; - - /* Default memory configuration */ - ret = wl1271_acx_init_mem_config(wl); - if (ret < 0) - return ret; - - /* RX config */ - ret = wl12xx_init_rx_config(wl); - if (ret < 0) - goto out_free_memmap; - - ret = wl1271_acx_dco_itrim_params(wl); - if (ret < 0) - goto out_free_memmap; - - /* Configure TX patch complete interrupt behavior */ - ret = wl1271_acx_tx_config_options(wl); - if (ret < 0) - goto out_free_memmap; - - /* RX complete interrupt pacing */ - ret = wl1271_acx_init_rx_interrupt(wl); - if (ret < 0) - goto out_free_memmap; - - /* Energy detection */ - ret = wl1271_init_energy_detection(wl); - if (ret < 0) - goto out_free_memmap; - - /* Default fragmentation threshold */ - ret = wl1271_acx_frag_threshold(wl, wl->hw->wiphy->frag_threshold); - if (ret < 0) - goto out_free_memmap; - - /* Enable data path */ - ret = wl1271_cmd_data_path(wl, 1); - if (ret < 0) - goto out_free_memmap; - - /* configure PM */ - ret = wl1271_acx_pm_config(wl); - if (ret < 0) - goto out_free_memmap; - - ret = wl12xx_acx_set_rate_mgmt_params(wl); - if (ret < 0) - goto out_free_memmap; - - /* configure hangover */ - ret = wl12xx_acx_config_hangover(wl); - if (ret < 0) - goto out_free_memmap; - - return 0; - - out_free_memmap: - kfree(wl->target_mem_map); - wl->target_mem_map = NULL; - - return ret; -} diff --git a/trunk/drivers/net/wireless/wl12xx/io.c b/trunk/drivers/net/wireless/wl12xx/io.c deleted file mode 100644 index c574a3b31e31..000000000000 --- a/trunk/drivers/net/wireless/wl12xx/io.c +++ /dev/null @@ -1,244 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2008-2010 Nokia Corporation - * - * Contact: Luciano Coelho - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include -#include -#include - -#include "wl12xx.h" -#include "debug.h" -#include "wl12xx_80211.h" -#include "io.h" -#include "tx.h" - -#define OCP_CMD_LOOP 32 - -#define OCP_CMD_WRITE 0x1 -#define OCP_CMD_READ 0x2 - -#define OCP_READY_MASK BIT(18) -#define OCP_STATUS_MASK (BIT(16) | BIT(17)) - -#define OCP_STATUS_NO_RESP 0x00000 -#define OCP_STATUS_OK 0x10000 -#define OCP_STATUS_REQ_FAILED 0x20000 -#define OCP_STATUS_RESP_ERROR 0x30000 - -struct wl1271_partition_set wl12xx_part_table[PART_TABLE_LEN] = { - [PART_DOWN] = { - .mem = { - .start = 0x00000000, - .size = 0x000177c0 - }, - .reg = { - .start = REGISTERS_BASE, - .size = 0x00008800 - }, - .mem2 = { - .start = 0x00000000, - .size = 0x00000000 - }, - .mem3 = { - .start = 0x00000000, - .size = 0x00000000 - }, - }, - - [PART_WORK] = { - .mem = { - .start = 0x00040000, - .size = 0x00014fc0 - }, - .reg = { - .start = REGISTERS_BASE, - .size = 0x0000a000 - }, - .mem2 = { - .start = 0x003004f8, - .size = 0x00000004 - }, - .mem3 = { - .start = 0x00040404, - .size = 0x00000000 - }, - }, - - [PART_DRPW] = { - .mem = { - .start = 0x00040000, - .size = 0x00014fc0 - }, - .reg = { - .start = DRPW_BASE, - .size = 0x00006000 - }, - .mem2 = { - .start = 0x00000000, - .size = 0x00000000 - }, - .mem3 = { - .start = 0x00000000, - .size = 0x00000000 - } - } -}; - -bool wl1271_set_block_size(struct wl1271 *wl) -{ - if (wl->if_ops->set_block_size) { - wl->if_ops->set_block_size(wl->dev, WL12XX_BUS_BLOCK_SIZE); - return true; - } - - return false; -} - -void wl1271_disable_interrupts(struct wl1271 *wl) -{ - disable_irq(wl->irq); -} - -void wl1271_enable_interrupts(struct wl1271 *wl) -{ - enable_irq(wl->irq); -} - -/* Set the SPI partitions to access the chip addresses - * - * To simplify driver code, a fixed (virtual) memory map is defined for - * register and memory addresses. Because in the chipset, in different stages - * of operation, those addresses will move around, an address translation - * mechanism is required. - * - * There are four partitions (three memory and one register partition), - * which are mapped to two different areas of the hardware memory. - * - * Virtual address - * space - * - * | | - * ...+----+--> mem.start - * Physical address ... | | - * space ... | | [PART_0] - * ... | | - * 00000000 <--+----+... ...+----+--> mem.start + mem.size - * | | ... | | - * |MEM | ... | | - * | | ... | | - * mem.size <--+----+... | | {unused area) - * | | ... | | - * |REG | ... | | - * mem.size | | ... | | - * + <--+----+... ...+----+--> reg.start - * reg.size | | ... | | - * |MEM2| ... | | [PART_1] - * | | ... | | - * ...+----+--> reg.start + reg.size - * | | - * - */ -int wl1271_set_partition(struct wl1271 *wl, - struct wl1271_partition_set *p) -{ - /* copy partition info */ - memcpy(&wl->part, p, sizeof(*p)); - - wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - p->mem.start, p->mem.size); - wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - p->reg.start, p->reg.size); - wl1271_debug(DEBUG_SPI, "mem2_start %08X mem2_size %08X", - p->mem2.start, p->mem2.size); - wl1271_debug(DEBUG_SPI, "mem3_start %08X mem3_size %08X", - p->mem3.start, p->mem3.size); - - /* write partition info to the chipset */ - wl1271_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start); - wl1271_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size); - wl1271_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start); - wl1271_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size); - wl1271_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start); - wl1271_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size); - wl1271_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start); - - return 0; -} -EXPORT_SYMBOL_GPL(wl1271_set_partition); - -void wl1271_io_reset(struct wl1271 *wl) -{ - if (wl->if_ops->reset) - wl->if_ops->reset(wl->dev); -} - -void wl1271_io_init(struct wl1271 *wl) -{ - if (wl->if_ops->init) - wl->if_ops->init(wl->dev); -} - -void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val) -{ - /* write address >> 1 + 0x30000 to OCP_POR_CTR */ - addr = (addr >> 1) + 0x30000; - wl1271_write32(wl, OCP_POR_CTR, addr); - - /* write value to OCP_POR_WDATA */ - wl1271_write32(wl, OCP_DATA_WRITE, val); - - /* write 1 to OCP_CMD */ - wl1271_write32(wl, OCP_CMD, OCP_CMD_WRITE); -} - -u16 wl1271_top_reg_read(struct wl1271 *wl, int addr) -{ - u32 val; - int timeout = OCP_CMD_LOOP; - - /* write address >> 1 + 0x30000 to OCP_POR_CTR */ - addr = (addr >> 1) + 0x30000; - wl1271_write32(wl, OCP_POR_CTR, addr); - - /* write 2 to OCP_CMD */ - wl1271_write32(wl, OCP_CMD, OCP_CMD_READ); - - /* poll for data ready */ - do { - val = wl1271_read32(wl, OCP_DATA_READ); - } while (!(val & OCP_READY_MASK) && --timeout); - - if (!timeout) { - wl1271_warning("Top register access timed out."); - return 0xffff; - } - - /* check data status and return if OK */ - if ((val & OCP_STATUS_MASK) == OCP_STATUS_OK) - return val & 0xffff; - else { - wl1271_warning("Top register access returned error."); - return 0xffff; - } -} - diff --git a/trunk/drivers/net/wireless/wl12xx/io.h b/trunk/drivers/net/wireless/wl12xx/io.h deleted file mode 100644 index 4fb3dab8c3b2..000000000000 --- a/trunk/drivers/net/wireless/wl12xx/io.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. - * Copyright (C) 2008-2010 Nokia Corporation - * - * Contact: Luciano Coelho - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __IO_H__ -#define __IO_H__ - -#include -#include "reg.h" - -#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 - -#define HW_PARTITION_REGISTERS_ADDR 0x1FFC0 -#define HW_PART0_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR) -#define HW_PART0_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 4) -#define HW_PART1_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR + 8) -#define HW_PART1_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 12) -#define HW_PART2_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR + 16) -#define HW_PART2_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 20) -#define HW_PART3_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 24) - -#define HW_ACCESS_REGISTER_SIZE 4 - -#define HW_ACCESS_PRAM_MAX_RANGE 0x3c000 - -extern struct wl1271_partition_set wl12xx_part_table[PART_TABLE_LEN]; - -struct wl1271; - -void wl1271_disable_interrupts(struct wl1271 *wl); -void wl1271_enable_interrupts(struct wl1271 *wl); - -void wl1271_io_reset(struct wl1271 *wl); -void wl1271_io_init(struct wl1271 *wl); - -/* Raw target IO, address is not translated */ -static inline void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf, - size_t len, bool fixed) -{ - wl->if_ops->write(wl->dev, addr, buf, len, fixed); -} - -static inline void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf, - size_t len, bool fixed) -{ - wl->if_ops->read(wl->dev, addr, buf, len, fixed); -} - -static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr) -{ - wl1271_raw_read(wl, addr, &wl->buffer_32, - sizeof(wl->buffer_32), false); - - return le32_to_cpu(wl->buffer_32); -} - -static inline void wl1271_raw_write32(struct wl1271 *wl, int addr, u32 val) -{ - wl->buffer_32 = cpu_to_le32(val); - wl1271_raw_write(wl, addr, &wl->buffer_32, - sizeof(wl->buffer_32), false); -} - -/* Translated target IO */ -static inline int wl1271_translate_addr(struct wl1271 *wl, int addr) -{ - /* - * To translate, first check to which window of addresses the - * particular address belongs. Then subtract the starting address - * of that window from the address. Then, add offset of the - * translated region. - * - * The translated regions occur next to each other in physical device - * memory, so just add the sizes of the preceding address regions to - * get the offset to the new region. - * - * Currently, only the two first regions are addressed, and the - * assumption is that all addresses will fall into either of those - * two. - */ - if ((addr >= wl->part.reg.start) && - (addr < wl->part.reg.start + wl->part.reg.size)) - return addr - wl->part.reg.start + wl->part.mem.size; - else - return addr - wl->part.mem.start; -} - -static inline void wl1271_read(struct wl1271 *wl, int addr, void *buf, - size_t len, bool fixed) -{ - int physical; - - physical = wl1271_translate_addr(wl, addr); - - wl1271_raw_read(wl, physical, buf, len, fixed); -} - -static inline void wl1271_write(struct wl1271 *wl, int addr, void *buf, - size_t len, bool fixed) -{ - int physical; - - physical = wl1271_translate_addr(wl, addr); - - wl1271_raw_write(wl, physical, buf, len, fixed); -} - -static inline void wl1271_read_hwaddr(struct wl1271 *wl, int hwaddr, - void *buf, size_t len, bool fixed) -{ - int physical; - int addr; - - /* Addresses are stored internally as addresses to 32 bytes blocks */ - addr = hwaddr << 5; - - physical = wl1271_translate_addr(wl, addr); - - wl1271_raw_read(wl, physical, buf, len, fixed); -} - -static inline u32 wl1271_read32(struct wl1271 *wl, int addr) -{ - return wl1271_raw_read32(wl, wl1271_translate_addr(wl, addr)); -} - -static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val) -{ - wl1271_raw_write32(wl, wl1271_translate_addr(wl, addr), val); -} - -static inline void wl1271_power_off(struct wl1271 *wl) -{ - wl->if_ops->power(wl->dev, false); - clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); -} - -static inline int wl1271_power_on(struct wl1271 *wl) -{ - int ret = wl->if_ops->power(wl->dev, true); - if (ret == 0) - set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); - - return ret; -} - - -/* Top Register IO */ -void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val); -u16 wl1271_top_reg_read(struct wl1271 *wl, int addr); - -int wl1271_set_partition(struct wl1271 *wl, - struct wl1271_partition_set *p); - -bool wl1271_set_block_size(struct wl1271 *wl); - -/* Functions from wl1271_main.c */ - -int wl1271_tx_dummy_packet(struct wl1271 *wl); - -#endif diff --git a/trunk/drivers/net/wireless/wl12xx/main.c b/trunk/drivers/net/wireless/wl12xx/main.c deleted file mode 100644 index 39002363611e..000000000000 --- a/trunk/drivers/net/wireless/wl12xx/main.c +++ /dev/null @@ -1,5623 +0,0 @@ - -/* - * This file is part of wl1271 - * - * Copyright (C) 2008-2010 Nokia Corporation - * - * Contact: Luciano Coelho - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "wl12xx.h" -#include "debug.h" -#include "wl12xx_80211.h" -#include "reg.h" -#include "io.h" -#include "event.h" -#include "tx.h" -#include "rx.h" -#include "ps.h" -#include "init.h" -#include "debugfs.h" -#include "cmd.h" -#include "boot.h" -#include "testmode.h" -#include "scan.h" - -#define WL1271_BOOT_RETRIES 3 - -static struct conf_drv_settings default_conf = { - .sg = { - .params = { - [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10, - [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180, - [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10, - [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180, - [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10, - [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80, - [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10, - [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80, - [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8, - [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8, - [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20, - [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20, - [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20, - [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35, - [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16, - [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35, - [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32, - [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50, - [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28, - [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50, - [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10, - [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20, - [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75, - [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15, - [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27, - [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17, - /* active scan params */ - [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170, - [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50, - [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100, - /* passive scan params */ - [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800, - [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200, - [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200, - /* passive scan in dual antenna params */ - [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0, - [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0, - [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0, - /* general params */ - [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1, - [CONF_SG_ANTENNA_CONFIGURATION] = 0, - [CONF_SG_BEACON_MISS_PERCENT] = 60, - [CONF_SG_DHCP_TIME] = 5000, - [CONF_SG_RXT] = 1200, - [CONF_SG_TXT] = 1000, - [CONF_SG_ADAPTIVE_RXT_TXT] = 1, - [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3, - [CONF_SG_HV3_MAX_SERVED] = 6, - [CONF_SG_PS_POLL_TIMEOUT] = 10, - [CONF_SG_UPSD_TIMEOUT] = 10, - [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2, - [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5, - [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30, - /* AP params */ - [CONF_AP_BEACON_MISS_TX] = 3, - [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10, - [CONF_AP_BEACON_WINDOW_INTERVAL] = 2, - [CONF_AP_CONNECTION_PROTECTION_TIME] = 0, - [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25, - [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25, - /* CTS Diluting params */ - [CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0, - [CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0, - }, - .state = CONF_SG_PROTECTIVE, - }, - .rx = { - .rx_msdu_life_time = 512000, - .packet_detection_threshold = 0, - .ps_poll_timeout = 15, - .upsd_timeout = 15, - .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD, - .rx_cca_threshold = 0, - .irq_blk_threshold = 0xFFFF, - .irq_pkt_threshold = 0, - .irq_timeout = 600, - .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY, - }, - .tx = { - .tx_energy_detection = 0, - .sta_rc_conf = { - .enabled_rates = 0, - .short_retry_limit = 10, - .long_retry_limit = 10, - .aflags = 0, - }, - .ac_conf_count = 4, - .ac_conf = { - [CONF_TX_AC_BE] = { - .ac = CONF_TX_AC_BE, - .cw_min = 15, - .cw_max = 63, - .aifsn = 3, - .tx_op_limit = 0, - }, - [CONF_TX_AC_BK] = { - .ac = CONF_TX_AC_BK, - .cw_min = 15, - .cw_max = 63, - .aifsn = 7, - .tx_op_limit = 0, - }, - [CONF_TX_AC_VI] = { - .ac = CONF_TX_AC_VI, - .cw_min = 15, - .cw_max = 63, - .aifsn = CONF_TX_AIFS_PIFS, - .tx_op_limit = 3008, - }, - [CONF_TX_AC_VO] = { - .ac = CONF_TX_AC_VO, - .cw_min = 15, - .cw_max = 63, - .aifsn = CONF_TX_AIFS_PIFS, - .tx_op_limit = 1504, - }, - }, - .max_tx_retries = 100, - .ap_aging_period = 300, - .tid_conf_count = 4, - .tid_conf = { - [CONF_TX_AC_BE] = { - .queue_id = CONF_TX_AC_BE, - .channel_type = CONF_CHANNEL_TYPE_EDCF, - .tsid = CONF_TX_AC_BE, - .ps_scheme = CONF_PS_SCHEME_LEGACY, - .ack_policy = CONF_ACK_POLICY_LEGACY, - .apsd_conf = {0, 0}, - }, - [CONF_TX_AC_BK] = { - .queue_id = CONF_TX_AC_BK, - .channel_type = CONF_CHANNEL_TYPE_EDCF, - .tsid = CONF_TX_AC_BK, - .ps_scheme = CONF_PS_SCHEME_LEGACY, - .ack_policy = CONF_ACK_POLICY_LEGACY, - .apsd_conf = {0, 0}, - }, - [CONF_TX_AC_VI] = { - .queue_id = CONF_TX_AC_VI, - .channel_type = CONF_CHANNEL_TYPE_EDCF, - .tsid = CONF_TX_AC_VI, - .ps_scheme = CONF_PS_SCHEME_LEGACY, - .ack_policy = CONF_ACK_POLICY_LEGACY, - .apsd_conf = {0, 0}, - }, - [CONF_TX_AC_VO] = { - .queue_id = CONF_TX_AC_VO, - .channel_type = CONF_CHANNEL_TYPE_EDCF, - .tsid = CONF_TX_AC_VO, - .ps_scheme = CONF_PS_SCHEME_LEGACY, - .ack_policy = CONF_ACK_POLICY_LEGACY, - .apsd_conf = {0, 0}, - }, - }, - .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD, - .tx_compl_timeout = 700, - .tx_compl_threshold = 4, - .basic_rate = CONF_HW_BIT_RATE_1MBPS, - .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS, - .tmpl_short_retry_limit = 10, - .tmpl_long_retry_limit = 10, - .tx_watchdog_timeout = 5000, - }, - .conn = { - .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, - .listen_interval = 1, - .suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM, - .suspend_listen_interval = 3, - .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED, - .bcn_filt_ie_count = 2, - .bcn_filt_ie = { - [0] = { - .ie = WLAN_EID_CHANNEL_SWITCH, - .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE, - }, - [1] = { - .ie = WLAN_EID_HT_INFORMATION, - .rule = CONF_BCN_RULE_PASS_ON_CHANGE, - }, - }, - .synch_fail_thold = 10, - .bss_lose_timeout = 100, - .beacon_rx_timeout = 10000, - .broadcast_timeout = 20000, - .rx_broadcast_in_ps = 1, - .ps_poll_threshold = 10, - .bet_enable = CONF_BET_MODE_ENABLE, - .bet_max_consecutive = 50, - .psm_entry_retries = 8, - .psm_exit_retries = 16, - .psm_entry_nullfunc_retries = 3, - .dynamic_ps_timeout = 200, - .forced_ps = false, - .keep_alive_interval = 55000, - .max_listen_interval = 20, - }, - .itrim = { - .enable = false, - .timeout = 50000, - }, - .pm_config = { - .host_clk_settling_time = 5000, - .host_fast_wakeup_support = false - }, - .roam_trigger = { - .trigger_pacing = 1, - .avg_weight_rssi_beacon = 20, - .avg_weight_rssi_data = 10, - .avg_weight_snr_beacon = 20, - .avg_weight_snr_data = 10, - }, - .scan = { - .min_dwell_time_active = 7500, - .max_dwell_time_active = 30000, - .min_dwell_time_passive = 100000, - .max_dwell_time_passive = 100000, - .num_probe_reqs = 2, - .split_scan_timeout = 50000, - }, - .sched_scan = { - /* sched_scan requires dwell times in TU instead of TU/1000 */ - .min_dwell_time_active = 30, - .max_dwell_time_active = 60, - .dwell_time_passive = 100, - .dwell_time_dfs = 150, - .num_probe_reqs = 2, - .rssi_threshold = -90, - .snr_threshold = 0, - }, - .rf = { - .tx_per_channel_power_compensation_2 = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - .tx_per_channel_power_compensation_5 = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - }, - .ht = { - .rx_ba_win_size = 8, - .tx_ba_win_size = 64, - .inactivity_timeout = 10000, - .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP, - }, - .mem_wl127x = { - .num_stations = 1, - .ssid_profiles = 1, - .rx_block_num = 70, - .tx_min_block_num = 40, - .dynamic_memory = 1, - .min_req_tx_blocks = 100, - .min_req_rx_blocks = 22, - .tx_min = 27, - }, - .mem_wl128x = { - .num_stations = 1, - .ssid_profiles = 1, - .rx_block_num = 40, - .tx_min_block_num = 40, - .dynamic_memory = 1, - .min_req_tx_blocks = 45, - .min_req_rx_blocks = 22, - .tx_min = 27, - }, - .fm_coex = { - .enable = true, - .swallow_period = 5, - .n_divider_fref_set_1 = 0xff, /* default */ - .n_divider_fref_set_2 = 12, - .m_divider_fref_set_1 = 148, - .m_divider_fref_set_2 = 0xffff, /* default */ - .coex_pll_stabilization_time = 0xffffffff, /* default */ - .ldo_stabilization_time = 0xffff, /* default */ - .fm_disturbed_band_margin = 0xff, /* default */ - .swallow_clk_diff = 0xff, /* default */ - }, - .rx_streaming = { - .duration = 150, - .queues = 0x1, - .interval = 20, - .always = 0, - }, - .fwlog = { - .mode = WL12XX_FWLOG_ON_DEMAND, - .mem_blocks = 2, - .severity = 0, - .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED, - .output = WL12XX_FWLOG_OUTPUT_HOST, - .threshold = 0, - }, - .hci_io_ds = HCI_IO_DS_6MA, - .rate = { - .rate_retry_score = 32000, - .per_add = 8192, - .per_th1 = 2048, - .per_th2 = 4096, - .max_per = 8100, - .inverse_curiosity_factor = 5, - .tx_fail_low_th = 4, - .tx_fail_high_th = 10, - .per_alpha_shift = 4, - .per_add_shift = 13, - .per_beta1_shift = 10, - .per_beta2_shift = 8, - .rate_check_up = 2, - .rate_check_down = 12, - .rate_retry_policy = { - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - }, - }, - .hangover = { - .recover_time = 0, - .hangover_period = 20, - .dynamic_mode = 1, - .early_termination_mode = 1, - .max_period = 20, - .min_period = 1, - .increase_delta = 1, - .decrease_delta = 2, - .quiet_time = 4, - .increase_time = 1, - .window_size = 16, - }, -}; - -static char *fwlog_param; -static bool bug_on_recovery; - -static void __wl1271_op_remove_interface(struct wl1271 *wl, - struct ieee80211_vif *vif, - bool reset_tx_queues); -static void wl1271_op_stop(struct ieee80211_hw *hw); -static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif); - -static int wl12xx_set_authorized(struct wl1271 *wl, - struct wl12xx_vif *wlvif) -{ - int ret; - - if (WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS)) - return -EINVAL; - - if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) - return 0; - - if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags)) - return 0; - - ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid); - if (ret < 0) - return ret; - - wl12xx_croc(wl, wlvif->role_id); - - wl1271_info("Association completed."); - return 0; -} - -static int wl1271_reg_notify(struct wiphy *wiphy, - struct regulatory_request *request) -{ - struct ieee80211_supported_band *band; - struct ieee80211_channel *ch; - int i; - - band = wiphy->bands[IEEE80211_BAND_5GHZ]; - for (i = 0; i < band->n_channels; i++) { - ch = &band->channels[i]; - if (ch->flags & IEEE80211_CHAN_DISABLED) - continue; - - if (ch->flags & IEEE80211_CHAN_RADAR) - ch->flags |= IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN; - - } - - return 0; -} - -static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif, - bool enable) -{ - int ret = 0; - - /* we should hold wl->mutex */ - ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable); - if (ret < 0) - goto out; - - if (enable) - set_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags); - else - clear_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags); -out: - return ret; -} - -/* - * this function is being called when the rx_streaming interval - * has beed changed or rx_streaming should be disabled - */ -int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - int ret = 0; - int period = wl->conf.rx_streaming.interval; - - /* don't reconfigure if rx_streaming is disabled */ - if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags)) - goto out; - - /* reconfigure/disable according to new streaming_period */ - if (period && - test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) && - (wl->conf.rx_streaming.always || - test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))) - ret = wl1271_set_rx_streaming(wl, wlvif, true); - else { - ret = wl1271_set_rx_streaming(wl, wlvif, false); - /* don't cancel_work_sync since we might deadlock */ - del_timer_sync(&wlvif->rx_streaming_timer); - } -out: - return ret; -} - -static void wl1271_rx_streaming_enable_work(struct work_struct *work) -{ - int ret; - struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif, - rx_streaming_enable_work); - struct wl1271 *wl = wlvif->wl; - - mutex_lock(&wl->mutex); - - if (test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags) || - !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) || - (!wl->conf.rx_streaming.always && - !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))) - goto out; - - if (!wl->conf.rx_streaming.interval) - goto out; - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - ret = wl1271_set_rx_streaming(wl, wlvif, true); - if (ret < 0) - goto out_sleep; - - /* stop it after some time of inactivity */ - mod_timer(&wlvif->rx_streaming_timer, - jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration)); - -out_sleep: - wl1271_ps_elp_sleep(wl); -out: - mutex_unlock(&wl->mutex); -} - -static void wl1271_rx_streaming_disable_work(struct work_struct *work) -{ - int ret; - struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif, - rx_streaming_disable_work); - struct wl1271 *wl = wlvif->wl; - - mutex_lock(&wl->mutex); - - if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags)) - goto out; - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - ret = wl1271_set_rx_streaming(wl, wlvif, false); - if (ret) - goto out_sleep; - -out_sleep: - wl1271_ps_elp_sleep(wl); -out: - mutex_unlock(&wl->mutex); -} - -static void wl1271_rx_streaming_timer(unsigned long data) -{ - struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data; - struct wl1271 *wl = wlvif->wl; - ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work); -} - -/* wl->mutex must be taken */ -void wl12xx_rearm_tx_watchdog_locked(struct wl1271 *wl) -{ - /* if the watchdog is not armed, don't do anything */ - if (wl->tx_allocated_blocks == 0) - return; - - cancel_delayed_work(&wl->tx_watchdog_work); - ieee80211_queue_delayed_work(wl->hw, &wl->tx_watchdog_work, - msecs_to_jiffies(wl->conf.tx.tx_watchdog_timeout)); -} - -static void wl12xx_tx_watchdog_work(struct work_struct *work) -{ - struct delayed_work *dwork; - struct wl1271 *wl; - - dwork = container_of(work, struct delayed_work, work); - wl = container_of(dwork, struct wl1271, tx_watchdog_work); - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state == WL1271_STATE_OFF)) - goto out; - - /* Tx went out in the meantime - everything is ok */ - if (unlikely(wl->tx_allocated_blocks == 0)) - goto out; - - /* - * if a ROC is in progress, we might not have any Tx for a long - * time (e.g. pending Tx on the non-ROC channels) - */ - if (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES) { - wl1271_debug(DEBUG_TX, "No Tx (in FW) for %d ms due to ROC", - wl->conf.tx.tx_watchdog_timeout); - wl12xx_rearm_tx_watchdog_locked(wl); - goto out; - } - - /* - * if a scan is in progress, we might not have any Tx for a long - * time - */ - if (wl->scan.state != WL1271_SCAN_STATE_IDLE) { - wl1271_debug(DEBUG_TX, "No Tx (in FW) for %d ms due to scan", - wl->conf.tx.tx_watchdog_timeout); - wl12xx_rearm_tx_watchdog_locked(wl); - goto out; - } - - /* - * AP might cache a frame for a long time for a sleeping station, - * so rearm the timer if there's an AP interface with stations. If - * Tx is genuinely stuck we will most hopefully discover it when all - * stations are removed due to inactivity. - */ - if (wl->active_sta_count) { - wl1271_debug(DEBUG_TX, "No Tx (in FW) for %d ms. AP has " - " %d stations", - wl->conf.tx.tx_watchdog_timeout, - wl->active_sta_count); - wl12xx_rearm_tx_watchdog_locked(wl); - goto out; - } - - wl1271_error("Tx stuck (in FW) for %d ms. Starting recovery", - wl->conf.tx.tx_watchdog_timeout); - wl12xx_queue_recovery_work(wl); - -out: - mutex_unlock(&wl->mutex); -} - -static void wl1271_conf_init(struct wl1271 *wl) -{ - - /* - * This function applies the default configuration to the driver. This - * function is invoked upon driver load (spi probe.) - * - * The configuration is stored in a run-time structure in order to - * facilitate for run-time adjustment of any of the parameters. Making - * changes to the configuration structure will apply the new values on - * the next interface up (wl1271_op_start.) - */ - - /* apply driver default configuration */ - memcpy(&wl->conf, &default_conf, sizeof(default_conf)); - - /* Adjust settings according to optional module parameters */ - if (fwlog_param) { - if (!strcmp(fwlog_param, "continuous")) { - wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS; - } else if (!strcmp(fwlog_param, "ondemand")) { - wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND; - } else if (!strcmp(fwlog_param, "dbgpins")) { - wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS; - wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS; - } else if (!strcmp(fwlog_param, "disable")) { - wl->conf.fwlog.mem_blocks = 0; - wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE; - } else { - wl1271_error("Unknown fwlog parameter %s", fwlog_param); - } - } -} - -static int wl1271_plt_init(struct wl1271 *wl) -{ - int ret; - - if (wl->chip.id == CHIP_ID_1283_PG20) - ret = wl128x_cmd_general_parms(wl); - else - ret = wl1271_cmd_general_parms(wl); - if (ret < 0) - return ret; - - if (wl->chip.id == CHIP_ID_1283_PG20) - ret = wl128x_cmd_radio_parms(wl); - else - ret = wl1271_cmd_radio_parms(wl); - if (ret < 0) - return ret; - - if (wl->chip.id != CHIP_ID_1283_PG20) { - ret = wl1271_cmd_ext_radio_parms(wl); - if (ret < 0) - return ret; - } - - /* Chip-specific initializations */ - ret = wl1271_chip_specific_init(wl); - if (ret < 0) - return ret; - - ret = wl1271_acx_init_mem_config(wl); - if (ret < 0) - return ret; - - ret = wl12xx_acx_mem_cfg(wl); - if (ret < 0) - goto out_free_memmap; - - /* Enable data path */ - ret = wl1271_cmd_data_path(wl, 1); - if (ret < 0) - goto out_free_memmap; - - /* Configure for CAM power saving (ie. always active) */ - ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); - if (ret < 0) - goto out_free_memmap; - - /* configure PM */ - ret = wl1271_acx_pm_config(wl); - if (ret < 0) - goto out_free_memmap; - - return 0; - - out_free_memmap: - kfree(wl->target_mem_map); - wl->target_mem_map = NULL; - - return ret; -} - -static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - u8 hlid, u8 tx_pkts) -{ - bool fw_ps, single_sta; - - fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); - single_sta = (wl->active_sta_count == 1); - - /* - * Wake up from high level PS if the STA is asleep with too little - * packets in FW or if the STA is awake. - */ - if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS) - wl12xx_ps_link_end(wl, wlvif, hlid); - - /* - * Start high-level PS if the STA is asleep with enough blocks in FW. - * Make an exception if this is the only connected station. In this - * case FW-memory congestion is not a problem. - */ - else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) - wl12xx_ps_link_start(wl, wlvif, hlid, true); -} - -static void wl12xx_irq_update_links_status(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - struct wl12xx_fw_status *status) -{ - struct wl1271_link *lnk; - u32 cur_fw_ps_map; - u8 hlid, cnt; - - /* TODO: also use link_fast_bitmap here */ - - cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap); - if (wl->ap_fw_ps_map != cur_fw_ps_map) { - wl1271_debug(DEBUG_PSM, - "link ps prev 0x%x cur 0x%x changed 0x%x", - wl->ap_fw_ps_map, cur_fw_ps_map, - wl->ap_fw_ps_map ^ cur_fw_ps_map); - - wl->ap_fw_ps_map = cur_fw_ps_map; - } - - for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) { - lnk = &wl->links[hlid]; - cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts; - - lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid]; - lnk->allocated_pkts -= cnt; - - wl12xx_irq_ps_regulate_link(wl, wlvif, hlid, - lnk->allocated_pkts); - } -} - -static void wl12xx_fw_status(struct wl1271 *wl, - struct wl12xx_fw_status *status) -{ - struct wl12xx_vif *wlvif; - struct timespec ts; - u32 old_tx_blk_count = wl->tx_blocks_available; - int avail, freed_blocks; - int i; - - wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false); - - wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, " - "drv_rx_counter = %d, tx_results_counter = %d)", - status->intr, - status->fw_rx_counter, - status->drv_rx_counter, - status->tx_results_counter); - - for (i = 0; i < NUM_TX_QUEUES; i++) { - /* prevent wrap-around in freed-packets counter */ - wl->tx_allocated_pkts[i] -= - (status->tx_released_pkts[i] - - wl->tx_pkts_freed[i]) & 0xff; - - wl->tx_pkts_freed[i] = status->tx_released_pkts[i]; - } - - /* prevent wrap-around in total blocks counter */ - if (likely(wl->tx_blocks_freed <= - le32_to_cpu(status->total_released_blks))) - freed_blocks = le32_to_cpu(status->total_released_blks) - - wl->tx_blocks_freed; - else - freed_blocks = 0x100000000LL - wl->tx_blocks_freed + - le32_to_cpu(status->total_released_blks); - - wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks); - - wl->tx_allocated_blocks -= freed_blocks; - - /* - * If the FW freed some blocks: - * If we still have allocated blocks - re-arm the timer, Tx is - * not stuck. Otherwise, cancel the timer (no Tx currently). - */ - if (freed_blocks) { - if (wl->tx_allocated_blocks) - wl12xx_rearm_tx_watchdog_locked(wl); - else - cancel_delayed_work(&wl->tx_watchdog_work); - } - - avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks; - - /* - * The FW might change the total number of TX memblocks before - * we get a notification about blocks being released. Thus, the - * available blocks calculation might yield a temporary result - * which is lower than the actual available blocks. Keeping in - * mind that only blocks that were allocated can be moved from - * TX to RX, tx_blocks_available should never decrease here. - */ - wl->tx_blocks_available = max((int)wl->tx_blocks_available, - avail); - - /* if more blocks are available now, tx work can be scheduled */ - if (wl->tx_blocks_available > old_tx_blk_count) - clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); - - /* for AP update num of allocated TX blocks per link and ps status */ - wl12xx_for_each_wlvif_ap(wl, wlvif) { - wl12xx_irq_update_links_status(wl, wlvif, status); - } - - /* update the host-chipset time offset */ - getnstimeofday(&ts); - wl->time_offset = (timespec_to_ns(&ts) >> 10) - - (s64)le32_to_cpu(status->fw_localtime); -} - -static void wl1271_flush_deferred_work(struct wl1271 *wl) -{ - struct sk_buff *skb; - - /* Pass all received frames to the network stack */ - while ((skb = skb_dequeue(&wl->deferred_rx_queue))) - ieee80211_rx_ni(wl->hw, skb); - - /* Return sent skbs to the network stack */ - while ((skb = skb_dequeue(&wl->deferred_tx_queue))) - ieee80211_tx_status_ni(wl->hw, skb); -} - -static void wl1271_netstack_work(struct work_struct *work) -{ - struct wl1271 *wl = - container_of(work, struct wl1271, netstack_work); - - do { - wl1271_flush_deferred_work(wl); - } while (skb_queue_len(&wl->deferred_rx_queue)); -} - -#define WL1271_IRQ_MAX_LOOPS 256 - -static irqreturn_t wl1271_irq(int irq, void *cookie) -{ - int ret; - u32 intr; - int loopcount = WL1271_IRQ_MAX_LOOPS; - struct wl1271 *wl = (struct wl1271 *)cookie; - bool done = false; - unsigned int defer_count; - unsigned long flags; - - /* TX might be handled here, avoid redundant work */ - set_bit(WL1271_FLAG_TX_PENDING, &wl->flags); - cancel_work_sync(&wl->tx_work); - - /* - * In case edge triggered interrupt must be used, we cannot iterate - * more than once without introducing race conditions with the hardirq. - */ - if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) - loopcount = 1; - - mutex_lock(&wl->mutex); - - wl1271_debug(DEBUG_IRQ, "IRQ work"); - - if (unlikely(wl->state == WL1271_STATE_OFF)) - goto out; - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - while (!done && loopcount--) { - /* - * In order to avoid a race with the hardirq, clear the flag - * before acknowledging the chip. Since the mutex is held, - * wl1271_ps_elp_wakeup cannot be called concurrently. - */ - clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); - smp_mb__after_clear_bit(); - - wl12xx_fw_status(wl, wl->fw_status); - intr = le32_to_cpu(wl->fw_status->intr); - intr &= WL1271_INTR_MASK; - if (!intr) { - done = true; - continue; - } - - if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) { - wl1271_error("watchdog interrupt received! " - "starting recovery."); - wl12xx_queue_recovery_work(wl); - - /* restarting the chip. ignore any other interrupt. */ - goto out; - } - - if (likely(intr & WL1271_ACX_INTR_DATA)) { - wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA"); - - wl12xx_rx(wl, wl->fw_status); - - /* Check if any tx blocks were freed */ - spin_lock_irqsave(&wl->wl_lock, flags); - if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) && - wl1271_tx_total_queue_count(wl) > 0) { - spin_unlock_irqrestore(&wl->wl_lock, flags); - /* - * In order to avoid starvation of the TX path, - * call the work function directly. - */ - wl1271_tx_work_locked(wl); - } else { - spin_unlock_irqrestore(&wl->wl_lock, flags); - } - - /* check for tx results */ - if (wl->fw_status->tx_results_counter != - (wl->tx_results_count & 0xff)) - wl1271_tx_complete(wl); - - /* Make sure the deferred queues don't get too long */ - defer_count = skb_queue_len(&wl->deferred_tx_queue) + - skb_queue_len(&wl->deferred_rx_queue); - if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT) - wl1271_flush_deferred_work(wl); - } - - if (intr & WL1271_ACX_INTR_EVENT_A) { - wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A"); - wl1271_event_handle(wl, 0); - } - - if (intr & WL1271_ACX_INTR_EVENT_B) { - wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B"); - wl1271_event_handle(wl, 1); - } - - if (intr & WL1271_ACX_INTR_INIT_COMPLETE) - wl1271_debug(DEBUG_IRQ, - "WL1271_ACX_INTR_INIT_COMPLETE"); - - if (intr & WL1271_ACX_INTR_HW_AVAILABLE) - wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE"); - } - - wl1271_ps_elp_sleep(wl); - -out: - spin_lock_irqsave(&wl->wl_lock, flags); - /* In case TX was not handled here, queue TX work */ - clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags); - if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) && - wl1271_tx_total_queue_count(wl) > 0) - ieee80211_queue_work(wl->hw, &wl->tx_work); - spin_unlock_irqrestore(&wl->wl_lock, flags); - - mutex_unlock(&wl->mutex); - - return IRQ_HANDLED; -} - -struct vif_counter_data { - u8 counter; - - struct ieee80211_vif *cur_vif; - bool cur_vif_running; -}; - -static void wl12xx_vif_count_iter(void *data, u8 *mac, - struct ieee80211_vif *vif) -{ - struct vif_counter_data *counter = data; - - counter->counter++; - if (counter->cur_vif == vif) - counter->cur_vif_running = true; -} - -/* caller must not hold wl->mutex, as it might deadlock */ -static void wl12xx_get_vif_count(struct ieee80211_hw *hw, - struct ieee80211_vif *cur_vif, - struct vif_counter_data *data) -{ - memset(data, 0, sizeof(*data)); - data->cur_vif = cur_vif; - - ieee80211_iterate_active_interfaces(hw, - wl12xx_vif_count_iter, data); -} - -static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt) -{ - const struct firmware *fw; - const char *fw_name; - enum wl12xx_fw_type fw_type; - int ret; - - if (plt) { - fw_type = WL12XX_FW_TYPE_PLT; - if (wl->chip.id == CHIP_ID_1283_PG20) - fw_name = WL128X_PLT_FW_NAME; - else - fw_name = WL127X_PLT_FW_NAME; - } else { - /* - * we can't call wl12xx_get_vif_count() here because - * wl->mutex is taken, so use the cached last_vif_count value - */ - if (wl->last_vif_count > 1) { - fw_type = WL12XX_FW_TYPE_MULTI; - if (wl->chip.id == CHIP_ID_1283_PG20) - fw_name = WL128X_FW_NAME_MULTI; - else - fw_name = WL127X_FW_NAME_MULTI; - } else { - fw_type = WL12XX_FW_TYPE_NORMAL; - if (wl->chip.id == CHIP_ID_1283_PG20) - fw_name = WL128X_FW_NAME_SINGLE; - else - fw_name = WL127X_FW_NAME_SINGLE; - } - } - - if (wl->fw_type == fw_type) - return 0; - - wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name); - - ret = request_firmware(&fw, fw_name, wl->dev); - - if (ret < 0) { - wl1271_error("could not get firmware %s: %d", fw_name, ret); - return ret; - } - - if (fw->size % 4) { - wl1271_error("firmware size is not multiple of 32 bits: %zu", - fw->size); - ret = -EILSEQ; - goto out; - } - - vfree(wl->fw); - wl->fw_type = WL12XX_FW_TYPE_NONE; - wl->fw_len = fw->size; - wl->fw = vmalloc(wl->fw_len); - - if (!wl->fw) { - wl1271_error("could not allocate memory for the firmware"); - ret = -ENOMEM; - goto out; - } - - memcpy(wl->fw, fw->data, wl->fw_len); - ret = 0; - wl->fw_type = fw_type; -out: - release_firmware(fw); - - return ret; -} - -static int wl1271_fetch_nvs(struct wl1271 *wl) -{ - const struct firmware *fw; - int ret; - - ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev); - - if (ret < 0) { - wl1271_error("could not get nvs file %s: %d", WL12XX_NVS_NAME, - ret); - return ret; - } - - wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL); - - if (!wl->nvs) { - wl1271_error("could not allocate memory for the nvs file"); - ret = -ENOMEM; - goto out; - } - - wl->nvs_len = fw->size; - -out: - release_firmware(fw); - - return ret; -} - -void wl12xx_queue_recovery_work(struct wl1271 *wl) -{ - if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) - ieee80211_queue_work(wl->hw, &wl->recovery_work); -} - -size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen) -{ - size_t len = 0; - - /* The FW log is a length-value list, find where the log end */ - while (len < maxlen) { - if (memblock[len] == 0) - break; - if (len + memblock[len] + 1 > maxlen) - break; - len += memblock[len] + 1; - } - - /* Make sure we have enough room */ - len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size)); - - /* Fill the FW log file, consumed by the sysfs fwlog entry */ - memcpy(wl->fwlog + wl->fwlog_size, memblock, len); - wl->fwlog_size += len; - - return len; -} - -static void wl12xx_read_fwlog_panic(struct wl1271 *wl) -{ - u32 addr; - u32 first_addr; - u8 *block; - - if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) || - (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) || - (wl->conf.fwlog.mem_blocks == 0)) - return; - - wl1271_info("Reading FW panic log"); - - block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL); - if (!block) - return; - - /* - * Make sure the chip is awake and the logger isn't active. - * This might fail if the firmware hanged. - */ - if (!wl1271_ps_elp_wakeup(wl)) - wl12xx_cmd_stop_fwlog(wl); - - /* Read the first memory block address */ - wl12xx_fw_status(wl, wl->fw_status); - first_addr = le32_to_cpu(wl->fw_status->log_start_addr); - if (!first_addr) - goto out; - - /* Traverse the memory blocks linked list */ - addr = first_addr; - do { - memset(block, 0, WL12XX_HW_BLOCK_SIZE); - wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE, - false); - - /* - * Memory blocks are linked to one another. The first 4 bytes - * of each memory block hold the hardware address of the next - * one. The last memory block points to the first one. - */ - addr = le32_to_cpup((__le32 *)block); - if (!wl12xx_copy_fwlog(wl, block + sizeof(addr), - WL12XX_HW_BLOCK_SIZE - sizeof(addr))) - break; - } while (addr && (addr != first_addr)); - - wake_up_interruptible(&wl->fwlog_waitq); - -out: - kfree(block); -} - -static void wl1271_recovery_work(struct work_struct *work) -{ - struct wl1271 *wl = - container_of(work, struct wl1271, recovery_work); - struct wl12xx_vif *wlvif; - struct ieee80211_vif *vif; - - mutex_lock(&wl->mutex); - - if (wl->state != WL1271_STATE_ON || wl->plt) - goto out_unlock; - - /* Avoid a recursive recovery */ - set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags); - - wl12xx_read_fwlog_panic(wl); - - wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x", - wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4)); - - BUG_ON(bug_on_recovery && - !test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)); - - /* - * Advance security sequence number to overcome potential progress - * in the firmware during recovery. This doens't hurt if the network is - * not encrypted. - */ - wl12xx_for_each_wlvif(wl, wlvif) { - if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) || - test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) - wlvif->tx_security_seq += - WL1271_TX_SQN_POST_RECOVERY_PADDING; - } - - /* Prevent spurious TX during FW restart */ - ieee80211_stop_queues(wl->hw); - - if (wl->sched_scanning) { - ieee80211_sched_scan_stopped(wl->hw); - wl->sched_scanning = false; - } - - /* reboot the chipset */ - while (!list_empty(&wl->wlvif_list)) { - wlvif = list_first_entry(&wl->wlvif_list, - struct wl12xx_vif, list); - vif = wl12xx_wlvif_to_vif(wlvif); - __wl1271_op_remove_interface(wl, vif, false); - } - mutex_unlock(&wl->mutex); - wl1271_op_stop(wl->hw); - - clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags); - - ieee80211_restart_hw(wl->hw); - - /* - * Its safe to enable TX now - the queues are stopped after a request - * to restart the HW. - */ - ieee80211_wake_queues(wl->hw); - return; -out_unlock: - mutex_unlock(&wl->mutex); -} - -static void wl1271_fw_wakeup(struct wl1271 *wl) -{ - u32 elp_reg; - - elp_reg = ELPCTRL_WAKE_UP; - wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); -} - -static int wl1271_setup(struct wl1271 *wl) -{ - wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL); - if (!wl->fw_status) - return -ENOMEM; - - wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL); - if (!wl->tx_res_if) { - kfree(wl->fw_status); - return -ENOMEM; - } - - return 0; -} - -static int wl12xx_set_power_on(struct wl1271 *wl) -{ - int ret; - - msleep(WL1271_PRE_POWER_ON_SLEEP); - ret = wl1271_power_on(wl); - if (ret < 0) - goto out; - msleep(WL1271_POWER_ON_SLEEP); - wl1271_io_reset(wl); - wl1271_io_init(wl); - - wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]); - - /* ELP module wake up */ - wl1271_fw_wakeup(wl); - -out: - return ret; -} - -static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt) -{ - int ret = 0; - - ret = wl12xx_set_power_on(wl); - if (ret < 0) - goto out; - - /* - * For wl127x based devices we could use the default block - * size (512 bytes), but due to a bug in the sdio driver, we - * need to set it explicitly after the chip is powered on. To - * simplify the code and since the performance impact is - * negligible, we use the same block size for all different - * chip types. - */ - if (!wl1271_set_block_size(wl)) - wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT; - - switch (wl->chip.id) { - case CHIP_ID_1271_PG10: - wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete", - wl->chip.id); - - ret = wl1271_setup(wl); - if (ret < 0) - goto out; - wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT; - break; - - case CHIP_ID_1271_PG20: - wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", - wl->chip.id); - - ret = wl1271_setup(wl); - if (ret < 0) - goto out; - wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT; - break; - - case CHIP_ID_1283_PG20: - wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)", - wl->chip.id); - - ret = wl1271_setup(wl); - if (ret < 0) - goto out; - break; - case CHIP_ID_1283_PG10: - default: - wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); - ret = -ENODEV; - goto out; - } - - ret = wl12xx_fetch_firmware(wl, plt); - if (ret < 0) - goto out; - - /* No NVS from netlink, try to get it from the filesystem */ - if (wl->nvs == NULL) { - ret = wl1271_fetch_nvs(wl); - if (ret < 0) - goto out; - } - -out: - return ret; -} - -int wl1271_plt_start(struct wl1271 *wl) -{ - int retries = WL1271_BOOT_RETRIES; - struct wiphy *wiphy = wl->hw->wiphy; - int ret; - - mutex_lock(&wl->mutex); - - wl1271_notice("power up"); - - if (wl->state != WL1271_STATE_OFF) { - wl1271_error("cannot go into PLT state because not " - "in off state: %d", wl->state); - ret = -EBUSY; - goto out; - } - - while (retries) { - retries--; - ret = wl12xx_chip_wakeup(wl, true); - if (ret < 0) - goto power_off; - - ret = wl1271_boot(wl); - if (ret < 0) - goto power_off; - - ret = wl1271_plt_init(wl); - if (ret < 0) - goto irq_disable; - - wl->plt = true; - wl->state = WL1271_STATE_ON; - wl1271_notice("firmware booted in PLT mode (%s)", - wl->chip.fw_ver_str); - - /* update hw/fw version info in wiphy struct */ - wiphy->hw_version = wl->chip.id; - strncpy(wiphy->fw_version, wl->chip.fw_ver_str, - sizeof(wiphy->fw_version)); - - goto out; - -irq_disable: - mutex_unlock(&wl->mutex); - /* Unlocking the mutex in the middle of handling is - inherently unsafe. In this case we deem it safe to do, - because we need to let any possibly pending IRQ out of - the system (and while we are WL1271_STATE_OFF the IRQ - work function will not do anything.) Also, any other - possible concurrent operations will fail due to the - current state, hence the wl1271 struct should be safe. */ - wl1271_disable_interrupts(wl); - wl1271_flush_deferred_work(wl); - cancel_work_sync(&wl->netstack_work); - mutex_lock(&wl->mutex); -power_off: - wl1271_power_off(wl); - } - - wl1271_error("firmware boot in PLT mode failed despite %d retries", - WL1271_BOOT_RETRIES); -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -int wl1271_plt_stop(struct wl1271 *wl) -{ - int ret = 0; - - wl1271_notice("power down"); - - /* - * Interrupts must be disabled before setting the state to OFF. - * Otherwise, the interrupt handler might be called and exit without - * reading the interrupt status. - */ - wl1271_disable_interrupts(wl); - mutex_lock(&wl->mutex); - if (!wl->plt) { - mutex_unlock(&wl->mutex); - - /* - * This will not necessarily enable interrupts as interrupts - * may have been disabled when op_stop was called. It will, - * however, balance the above call to disable_interrupts(). - */ - wl1271_enable_interrupts(wl); - - wl1271_error("cannot power down because not in PLT " - "state: %d", wl->state); - ret = -EBUSY; - goto out; - } - - mutex_unlock(&wl->mutex); - - wl1271_flush_deferred_work(wl); - cancel_work_sync(&wl->netstack_work); - cancel_work_sync(&wl->recovery_work); - cancel_delayed_work_sync(&wl->elp_work); - cancel_delayed_work_sync(&wl->tx_watchdog_work); - - mutex_lock(&wl->mutex); - wl1271_power_off(wl); - wl->flags = 0; - wl->state = WL1271_STATE_OFF; - wl->plt = false; - wl->rx_counter = 0; - mutex_unlock(&wl->mutex); - -out: - return ret; -} - -static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct wl1271 *wl = hw->priv; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_vif *vif = info->control.vif; - struct wl12xx_vif *wlvif = NULL; - unsigned long flags; - int q, mapping; - u8 hlid; - - if (vif) - wlvif = wl12xx_vif_to_data(vif); - - mapping = skb_get_queue_mapping(skb); - q = wl1271_tx_get_queue(mapping); - - hlid = wl12xx_tx_get_hlid(wl, wlvif, skb); - - spin_lock_irqsave(&wl->wl_lock, flags); - - /* queue the packet */ - if (hlid == WL12XX_INVALID_LINK_ID || - (wlvif && !test_bit(hlid, wlvif->links_map))) { - wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q); - ieee80211_free_txskb(hw, skb); - goto out; - } - - wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d len %d", - hlid, q, skb->len); - skb_queue_tail(&wl->links[hlid].tx_queue[q], skb); - - wl->tx_queue_count[q]++; - - /* - * The workqueue is slow to process the tx_queue and we need stop - * the queue here, otherwise the queue will get too long. - */ - if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) { - wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q); - ieee80211_stop_queue(wl->hw, mapping); - set_bit(q, &wl->stopped_queues_map); - } - - /* - * The chip specific setup must run before the first TX packet - - * before that, the tx_work will not be initialized! - */ - - if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) && - !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags)) - ieee80211_queue_work(wl->hw, &wl->tx_work); - -out: - spin_unlock_irqrestore(&wl->wl_lock, flags); -} - -int wl1271_tx_dummy_packet(struct wl1271 *wl) -{ - unsigned long flags; - int q; - - /* no need to queue a new dummy packet if one is already pending */ - if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) - return 0; - - q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet)); - - spin_lock_irqsave(&wl->wl_lock, flags); - set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); - wl->tx_queue_count[q]++; - spin_unlock_irqrestore(&wl->wl_lock, flags); - - /* The FW is low on RX memory blocks, so send the dummy packet asap */ - if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags)) - wl1271_tx_work_locked(wl); - - /* - * If the FW TX is busy, TX work will be scheduled by the threaded - * interrupt handler function - */ - return 0; -} - -/* - * The size of the dummy packet should be at least 1400 bytes. However, in - * order to minimize the number of bus transactions, aligning it to 512 bytes - * boundaries could be beneficial, performance wise - */ -#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512)) - -static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl) -{ - struct sk_buff *skb; - struct ieee80211_hdr_3addr *hdr; - unsigned int dummy_packet_size; - - dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE - - sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr); - - skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE); - if (!skb) { - wl1271_warning("Failed to allocate a dummy packet skb"); - return NULL; - } - - skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr)); - - hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr)); - memset(hdr, 0, sizeof(*hdr)); - hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | - IEEE80211_STYPE_NULLFUNC | - IEEE80211_FCTL_TODS); - - memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size); - - /* Dummy packets require the TID to be management */ - skb->priority = WL1271_TID_MGMT; - - /* Initialize all fields that might be used */ - skb_set_queue_mapping(skb, 0); - memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info)); - - return skb; -} - - -#ifdef CONFIG_PM -static int wl1271_configure_suspend_sta(struct wl1271 *wl, - struct wl12xx_vif *wlvif) -{ - int ret = 0; - - mutex_lock(&wl->mutex); - - if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) - goto out_unlock; - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out_unlock; - - ret = wl1271_acx_wake_up_conditions(wl, wlvif, - wl->conf.conn.suspend_wake_up_event, - wl->conf.conn.suspend_listen_interval); - - if (ret < 0) - wl1271_error("suspend: set wake up conditions failed: %d", ret); - - - wl1271_ps_elp_sleep(wl); - -out_unlock: - mutex_unlock(&wl->mutex); - return ret; - -} - -static int wl1271_configure_suspend_ap(struct wl1271 *wl, - struct wl12xx_vif *wlvif) -{ - int ret = 0; - - mutex_lock(&wl->mutex); - - if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) - goto out_unlock; - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out_unlock; - - ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true); - - wl1271_ps_elp_sleep(wl); -out_unlock: - mutex_unlock(&wl->mutex); - return ret; - -} - -static int wl1271_configure_suspend(struct wl1271 *wl, - struct wl12xx_vif *wlvif) -{ - if (wlvif->bss_type == BSS_TYPE_STA_BSS) - return wl1271_configure_suspend_sta(wl, wlvif); - if (wlvif->bss_type == BSS_TYPE_AP_BSS) - return wl1271_configure_suspend_ap(wl, wlvif); - return 0; -} - -static void wl1271_configure_resume(struct wl1271 *wl, - struct wl12xx_vif *wlvif) -{ - int ret = 0; - bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS; - bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS; - - if ((!is_ap) && (!is_sta)) - return; - - mutex_lock(&wl->mutex); - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - if (is_sta) { - ret = wl1271_acx_wake_up_conditions(wl, wlvif, - wl->conf.conn.wake_up_event, - wl->conf.conn.listen_interval); - - if (ret < 0) - wl1271_error("resume: wake up conditions failed: %d", - ret); - - } else if (is_ap) { - ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false); - } - - wl1271_ps_elp_sleep(wl); -out: - mutex_unlock(&wl->mutex); -} - -static int wl1271_op_suspend(struct ieee80211_hw *hw, - struct cfg80211_wowlan *wow) -{ - struct wl1271 *wl = hw->priv; - struct wl12xx_vif *wlvif; - int ret; - - wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow); - WARN_ON(!wow || !wow->any); - - wl1271_tx_flush(wl); - - wl->wow_enabled = true; - wl12xx_for_each_wlvif(wl, wlvif) { - ret = wl1271_configure_suspend(wl, wlvif); - if (ret < 0) { - wl1271_warning("couldn't prepare device to suspend"); - return ret; - } - } - /* flush any remaining work */ - wl1271_debug(DEBUG_MAC80211, "flushing remaining works"); - - /* - * disable and re-enable interrupts in order to flush - * the threaded_irq - */ - wl1271_disable_interrupts(wl); - - /* - * set suspended flag to avoid triggering a new threaded_irq - * work. no need for spinlock as interrupts are disabled. - */ - set_bit(WL1271_FLAG_SUSPENDED, &wl->flags); - - wl1271_enable_interrupts(wl); - flush_work(&wl->tx_work); - flush_delayed_work(&wl->elp_work); - - return 0; -} - -static int wl1271_op_resume(struct ieee80211_hw *hw) -{ - struct wl1271 *wl = hw->priv; - struct wl12xx_vif *wlvif; - unsigned long flags; - bool run_irq_work = false; - - wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d", - wl->wow_enabled); - WARN_ON(!wl->wow_enabled); - - /* - * re-enable irq_work enqueuing, and call irq_work directly if - * there is a pending work. - */ - spin_lock_irqsave(&wl->wl_lock, flags); - clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags); - if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags)) - run_irq_work = true; - spin_unlock_irqrestore(&wl->wl_lock, flags); - - if (run_irq_work) { - wl1271_debug(DEBUG_MAC80211, - "run postponed irq_work directly"); - wl1271_irq(0, wl); - wl1271_enable_interrupts(wl); - } - wl12xx_for_each_wlvif(wl, wlvif) { - wl1271_configure_resume(wl, wlvif); - } - wl->wow_enabled = false; - - return 0; -} -#endif - -static int wl1271_op_start(struct ieee80211_hw *hw) -{ - wl1271_debug(DEBUG_MAC80211, "mac80211 start"); - - /* - * We have to delay the booting of the hardware because - * we need to know the local MAC address before downloading and - * initializing the firmware. The MAC address cannot be changed - * after boot, and without the proper MAC address, the firmware - * will not function properly. - * - * The MAC address is first known when the corresponding interface - * is added. That is where we will initialize the hardware. - */ - - return 0; -} - -static void wl1271_op_stop(struct ieee80211_hw *hw) -{ - struct wl1271 *wl = hw->priv; - int i; - - wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); - - /* - * Interrupts must be disabled before setting the state to OFF. - * Otherwise, the interrupt handler might be called and exit without - * reading the interrupt status. - */ - wl1271_disable_interrupts(wl); - mutex_lock(&wl->mutex); - if (wl->state == WL1271_STATE_OFF) { - mutex_unlock(&wl->mutex); - - /* - * This will not necessarily enable interrupts as interrupts - * may have been disabled when op_stop was called. It will, - * however, balance the above call to disable_interrupts(). - */ - wl1271_enable_interrupts(wl); - return; - } - - /* - * this must be before the cancel_work calls below, so that the work - * functions don't perform further work. - */ - wl->state = WL1271_STATE_OFF; - mutex_unlock(&wl->mutex); - - wl1271_flush_deferred_work(wl); - cancel_delayed_work_sync(&wl->scan_complete_work); - cancel_work_sync(&wl->netstack_work); - cancel_work_sync(&wl->tx_work); - cancel_delayed_work_sync(&wl->elp_work); - cancel_delayed_work_sync(&wl->tx_watchdog_work); - - /* let's notify MAC80211 about the remaining pending TX frames */ - wl12xx_tx_reset(wl, true); - mutex_lock(&wl->mutex); - - wl1271_power_off(wl); - - wl->band = IEEE80211_BAND_2GHZ; - - wl->rx_counter = 0; - wl->power_level = WL1271_DEFAULT_POWER_LEVEL; - wl->tx_blocks_available = 0; - wl->tx_allocated_blocks = 0; - wl->tx_results_count = 0; - wl->tx_packets_count = 0; - wl->time_offset = 0; - wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; - wl->ap_fw_ps_map = 0; - wl->ap_ps_map = 0; - wl->sched_scanning = false; - memset(wl->roles_map, 0, sizeof(wl->roles_map)); - memset(wl->links_map, 0, sizeof(wl->links_map)); - memset(wl->roc_map, 0, sizeof(wl->roc_map)); - wl->active_sta_count = 0; - - /* The system link is always allocated */ - __set_bit(WL12XX_SYSTEM_HLID, wl->links_map); - - /* - * this is performed after the cancel_work calls and the associated - * mutex_lock, so that wl1271_op_add_interface does not accidentally - * get executed before all these vars have been reset. - */ - wl->flags = 0; - - wl->tx_blocks_freed = 0; - - for (i = 0; i < NUM_TX_QUEUES; i++) { - wl->tx_pkts_freed[i] = 0; - wl->tx_allocated_pkts[i] = 0; - } - - wl1271_debugfs_reset(wl); - - kfree(wl->fw_status); - wl->fw_status = NULL; - kfree(wl->tx_res_if); - wl->tx_res_if = NULL; - kfree(wl->target_mem_map); - wl->target_mem_map = NULL; - - mutex_unlock(&wl->mutex); -} - -static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx) -{ - u8 policy = find_first_zero_bit(wl->rate_policies_map, - WL12XX_MAX_RATE_POLICIES); - if (policy >= WL12XX_MAX_RATE_POLICIES) - return -EBUSY; - - __set_bit(policy, wl->rate_policies_map); - *idx = policy; - return 0; -} - -static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx) -{ - if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES)) - return; - - __clear_bit(*idx, wl->rate_policies_map); - *idx = WL12XX_MAX_RATE_POLICIES; -} - -static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - switch (wlvif->bss_type) { - case BSS_TYPE_AP_BSS: - if (wlvif->p2p) - return WL1271_ROLE_P2P_GO; - else - return WL1271_ROLE_AP; - - case BSS_TYPE_STA_BSS: - if (wlvif->p2p) - return WL1271_ROLE_P2P_CL; - else - return WL1271_ROLE_STA; - - case BSS_TYPE_IBSS: - return WL1271_ROLE_IBSS; - - default: - wl1271_error("invalid bss_type: %d", wlvif->bss_type); - } - return WL12XX_INVALID_ROLE_TYPE; -} - -static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif) -{ - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - int i; - - /* clear everything but the persistent data */ - memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent)); - - switch (ieee80211_vif_type_p2p(vif)) { - case NL80211_IFTYPE_P2P_CLIENT: - wlvif->p2p = 1; - /* fall-through */ - case NL80211_IFTYPE_STATION: - wlvif->bss_type = BSS_TYPE_STA_BSS; - break; - case NL80211_IFTYPE_ADHOC: - wlvif->bss_type = BSS_TYPE_IBSS; - break; - case NL80211_IFTYPE_P2P_GO: - wlvif->p2p = 1; - /* fall-through */ - case NL80211_IFTYPE_AP: - wlvif->bss_type = BSS_TYPE_AP_BSS; - break; - default: - wlvif->bss_type = MAX_BSS_TYPE; - return -EOPNOTSUPP; - } - - wlvif->role_id = WL12XX_INVALID_ROLE_ID; - wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID; - wlvif->dev_hlid = WL12XX_INVALID_LINK_ID; - - if (wlvif->bss_type == BSS_TYPE_STA_BSS || - wlvif->bss_type == BSS_TYPE_IBSS) { - /* init sta/ibss data */ - wlvif->sta.hlid = WL12XX_INVALID_LINK_ID; - wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx); - wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx); - wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx); - } else { - /* init ap data */ - wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID; - wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID; - wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx); - wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx); - for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++) - wl12xx_allocate_rate_policy(wl, - &wlvif->ap.ucast_rate_idx[i]); - } - - wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate; - wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5; - wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC; - wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC; - wlvif->rate_set = CONF_TX_RATE_MASK_BASIC; - wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT; - - /* - * mac80211 configures some values globally, while we treat them - * per-interface. thus, on init, we have to copy them from wl - */ - wlvif->band = wl->band; - wlvif->channel = wl->channel; - wlvif->power_level = wl->power_level; - - INIT_WORK(&wlvif->rx_streaming_enable_work, - wl1271_rx_streaming_enable_work); - INIT_WORK(&wlvif->rx_streaming_disable_work, - wl1271_rx_streaming_disable_work); - INIT_LIST_HEAD(&wlvif->list); - - setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer, - (unsigned long) wlvif); - return 0; -} - -static bool wl12xx_init_fw(struct wl1271 *wl) -{ - int retries = WL1271_BOOT_RETRIES; - bool booted = false; - struct wiphy *wiphy = wl->hw->wiphy; - int ret; - - while (retries) { - retries--; - ret = wl12xx_chip_wakeup(wl, false); - if (ret < 0) - goto power_off; - - ret = wl1271_boot(wl); - if (ret < 0) - goto power_off; - - ret = wl1271_hw_init(wl); - if (ret < 0) - goto irq_disable; - - booted = true; - break; - -irq_disable: - mutex_unlock(&wl->mutex); - /* Unlocking the mutex in the middle of handling is - inherently unsafe. In this case we deem it safe to do, - because we need to let any possibly pending IRQ out of - the system (and while we are WL1271_STATE_OFF the IRQ - work function will not do anything.) Also, any other - possible concurrent operations will fail due to the - current state, hence the wl1271 struct should be safe. */ - wl1271_disable_interrupts(wl); - wl1271_flush_deferred_work(wl); - cancel_work_sync(&wl->netstack_work); - mutex_lock(&wl->mutex); -power_off: - wl1271_power_off(wl); - } - - if (!booted) { - wl1271_error("firmware boot failed despite %d retries", - WL1271_BOOT_RETRIES); - goto out; - } - - wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str); - - /* update hw/fw version info in wiphy struct */ - wiphy->hw_version = wl->chip.id; - strncpy(wiphy->fw_version, wl->chip.fw_ver_str, - sizeof(wiphy->fw_version)); - - /* - * Now we know if 11a is supported (info from the NVS), so disable - * 11a channels if not supported - */ - if (!wl->enable_11a) - wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0; - - wl1271_debug(DEBUG_MAC80211, "11a is %ssupported", - wl->enable_11a ? "" : "not "); - - wl->state = WL1271_STATE_ON; -out: - return booted; -} - -static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif) -{ - return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID; -} - -/* - * Check whether a fw switch (i.e. moving from one loaded - * fw to another) is needed. This function is also responsible - * for updating wl->last_vif_count, so it must be called before - * loading a non-plt fw (so the correct fw (single-role/multi-role) - * will be used). - */ -static bool wl12xx_need_fw_change(struct wl1271 *wl, - struct vif_counter_data vif_counter_data, - bool add) -{ - enum wl12xx_fw_type current_fw = wl->fw_type; - u8 vif_count = vif_counter_data.counter; - - if (test_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags)) - return false; - - /* increase the vif count if this is a new vif */ - if (add && !vif_counter_data.cur_vif_running) - vif_count++; - - wl->last_vif_count = vif_count; - - /* no need for fw change if the device is OFF */ - if (wl->state == WL1271_STATE_OFF) - return false; - - if (vif_count > 1 && current_fw == WL12XX_FW_TYPE_NORMAL) - return true; - if (vif_count <= 1 && current_fw == WL12XX_FW_TYPE_MULTI) - return true; - - return false; -} - -/* - * Enter "forced psm". Make sure the sta is in psm against the ap, - * to make the fw switch a bit more disconnection-persistent. - */ -static void wl12xx_force_active_psm(struct wl1271 *wl) -{ - struct wl12xx_vif *wlvif; - - wl12xx_for_each_wlvif_sta(wl, wlvif) { - wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE); - } -} - -static int wl1271_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct wl1271 *wl = hw->priv; - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - struct vif_counter_data vif_count; - int ret = 0; - u8 role_type; - bool booted = false; - - vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | - IEEE80211_VIF_SUPPORTS_CQM_RSSI; - - wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", - ieee80211_vif_type_p2p(vif), vif->addr); - - wl12xx_get_vif_count(hw, vif, &vif_count); - - mutex_lock(&wl->mutex); - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out_unlock; - - /* - * in some very corner case HW recovery scenarios its possible to - * get here before __wl1271_op_remove_interface is complete, so - * opt out if that is the case. - */ - if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) || - test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) { - ret = -EBUSY; - goto out; - } - - - ret = wl12xx_init_vif_data(wl, vif); - if (ret < 0) - goto out; - - wlvif->wl = wl; - role_type = wl12xx_get_role_type(wl, wlvif); - if (role_type == WL12XX_INVALID_ROLE_TYPE) { - ret = -EINVAL; - goto out; - } - - if (wl12xx_need_fw_change(wl, vif_count, true)) { - wl12xx_force_active_psm(wl); - set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags); - mutex_unlock(&wl->mutex); - wl1271_recovery_work(&wl->recovery_work); - return 0; - } - - /* - * TODO: after the nvs issue will be solved, move this block - * to start(), and make sure here the driver is ON. - */ - if (wl->state == WL1271_STATE_OFF) { - /* - * we still need this in order to configure the fw - * while uploading the nvs - */ - memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN); - - booted = wl12xx_init_fw(wl); - if (!booted) { - ret = -EINVAL; - goto out; - } - } - - if (wlvif->bss_type == BSS_TYPE_STA_BSS || - wlvif->bss_type == BSS_TYPE_IBSS) { - /* - * The device role is a special role used for - * rx and tx frames prior to association (as - * the STA role can get packets only from - * its associated bssid) - */ - ret = wl12xx_cmd_role_enable(wl, vif->addr, - WL1271_ROLE_DEVICE, - &wlvif->dev_role_id); - if (ret < 0) - goto out; - } - - ret = wl12xx_cmd_role_enable(wl, vif->addr, - role_type, &wlvif->role_id); - if (ret < 0) - goto out; - - ret = wl1271_init_vif_specific(wl, vif); - if (ret < 0) - goto out; - - list_add(&wlvif->list, &wl->wlvif_list); - set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags); - - if (wlvif->bss_type == BSS_TYPE_AP_BSS) - wl->ap_count++; - else - wl->sta_count++; -out: - wl1271_ps_elp_sleep(wl); -out_unlock: - mutex_unlock(&wl->mutex); - - return ret; -} - -static void __wl1271_op_remove_interface(struct wl1271 *wl, - struct ieee80211_vif *vif, - bool reset_tx_queues) -{ - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - int i, ret; - - wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); - - if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) - return; - - /* because of hardware recovery, we may get here twice */ - if (wl->state != WL1271_STATE_ON) - return; - - wl1271_info("down"); - - if (wl->scan.state != WL1271_SCAN_STATE_IDLE && - wl->scan_vif == vif) { - /* - * Rearm the tx watchdog just before idling scan. This - * prevents just-finished scans from triggering the watchdog - */ - wl12xx_rearm_tx_watchdog_locked(wl); - - wl->scan.state = WL1271_SCAN_STATE_IDLE; - memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); - wl->scan_vif = NULL; - wl->scan.req = NULL; - ieee80211_scan_completed(wl->hw, true); - } - - if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) { - /* disable active roles */ - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto deinit; - - if (wlvif->bss_type == BSS_TYPE_STA_BSS || - wlvif->bss_type == BSS_TYPE_IBSS) { - if (wl12xx_dev_role_started(wlvif)) - wl12xx_stop_dev(wl, wlvif); - - ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id); - if (ret < 0) - goto deinit; - } - - ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id); - if (ret < 0) - goto deinit; - - wl1271_ps_elp_sleep(wl); - } -deinit: - /* clear all hlids (except system_hlid) */ - wlvif->dev_hlid = WL12XX_INVALID_LINK_ID; - - if (wlvif->bss_type == BSS_TYPE_STA_BSS || - wlvif->bss_type == BSS_TYPE_IBSS) { - wlvif->sta.hlid = WL12XX_INVALID_LINK_ID; - wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx); - wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx); - wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx); - } else { - wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID; - wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID; - wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx); - wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx); - for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++) - wl12xx_free_rate_policy(wl, - &wlvif->ap.ucast_rate_idx[i]); - } - - wl12xx_tx_reset_wlvif(wl, wlvif); - wl1271_free_ap_keys(wl, wlvif); - if (wl->last_wlvif == wlvif) - wl->last_wlvif = NULL; - list_del(&wlvif->list); - memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map)); - wlvif->role_id = WL12XX_INVALID_ROLE_ID; - wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID; - - if (wlvif->bss_type == BSS_TYPE_AP_BSS) - wl->ap_count--; - else - wl->sta_count--; - - mutex_unlock(&wl->mutex); - - del_timer_sync(&wlvif->rx_streaming_timer); - cancel_work_sync(&wlvif->rx_streaming_enable_work); - cancel_work_sync(&wlvif->rx_streaming_disable_work); - - mutex_lock(&wl->mutex); -} - -static void wl1271_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct wl1271 *wl = hw->priv; - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - struct wl12xx_vif *iter; - struct vif_counter_data vif_count; - bool cancel_recovery = true; - - wl12xx_get_vif_count(hw, vif, &vif_count); - mutex_lock(&wl->mutex); - - if (wl->state == WL1271_STATE_OFF || - !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) - goto out; - - /* - * wl->vif can be null here if someone shuts down the interface - * just when hardware recovery has been started. - */ - wl12xx_for_each_wlvif(wl, iter) { - if (iter != wlvif) - continue; - - __wl1271_op_remove_interface(wl, vif, true); - break; - } - WARN_ON(iter != wlvif); - if (wl12xx_need_fw_change(wl, vif_count, false)) { - wl12xx_force_active_psm(wl); - set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags); - wl12xx_queue_recovery_work(wl); - cancel_recovery = false; - } -out: - mutex_unlock(&wl->mutex); - if (cancel_recovery) - cancel_work_sync(&wl->recovery_work); -} - -static int wl12xx_op_change_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum nl80211_iftype new_type, bool p2p) -{ - struct wl1271 *wl = hw->priv; - int ret; - - set_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags); - wl1271_op_remove_interface(hw, vif); - - vif->type = new_type; - vif->p2p = p2p; - ret = wl1271_op_add_interface(hw, vif); - - clear_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags); - return ret; -} - -static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif, - bool set_assoc) -{ - int ret; - bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS); - - /* - * One of the side effects of the JOIN command is that is clears - * WPA/WPA2 keys from the chipset. Performing a JOIN while associated - * to a WPA/WPA2 access point will therefore kill the data-path. - * Currently the only valid scenario for JOIN during association - * is on roaming, in which case we will also be given new keys. - * Keep the below message for now, unless it starts bothering - * users who really like to roam a lot :) - */ - if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) - wl1271_info("JOIN while associated."); - - /* clear encryption type */ - wlvif->encryption_type = KEY_NONE; - - if (set_assoc) - set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags); - - if (is_ibss) - ret = wl12xx_cmd_role_start_ibss(wl, wlvif); - else - ret = wl12xx_cmd_role_start_sta(wl, wlvif); - if (ret < 0) - goto out; - - if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) - goto out; - - /* - * The join command disable the keep-alive mode, shut down its process, - * and also clear the template config, so we need to reset it all after - * the join. The acx_aid starts the keep-alive process, and the order - * of the commands below is relevant. - */ - ret = wl1271_acx_keep_alive_mode(wl, wlvif, true); - if (ret < 0) - goto out; - - ret = wl1271_acx_aid(wl, wlvif, wlvif->aid); - if (ret < 0) - goto out; - - ret = wl12xx_cmd_build_klv_null_data(wl, wlvif); - if (ret < 0) - goto out; - - ret = wl1271_acx_keep_alive_config(wl, wlvif, - CMD_TEMPL_KLV_IDX_NULL_DATA, - ACX_KEEP_ALIVE_TPL_VALID); - if (ret < 0) - goto out; - -out: - return ret; -} - -static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - int ret; - - if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) { - struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); - - wl12xx_cmd_stop_channel_switch(wl); - ieee80211_chswitch_done(vif, false); - } - - /* to stop listening to a channel, we disconnect */ - ret = wl12xx_cmd_role_stop_sta(wl, wlvif); - if (ret < 0) - goto out; - - /* reset TX security counters on a clean disconnect */ - wlvif->tx_security_last_seq_lsb = 0; - wlvif->tx_security_seq = 0; - -out: - return ret; -} - -static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band]; - wlvif->rate_set = wlvif->basic_rate_set; -} - -static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif, - bool idle) -{ - int ret; - bool cur_idle = !test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags); - - if (idle == cur_idle) - return 0; - - if (idle) { - /* no need to croc if we weren't busy (e.g. during boot) */ - if (wl12xx_dev_role_started(wlvif)) { - ret = wl12xx_stop_dev(wl, wlvif); - if (ret < 0) - goto out; - } - wlvif->rate_set = - wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); - ret = wl1271_acx_sta_rate_policies(wl, wlvif); - if (ret < 0) - goto out; - ret = wl1271_acx_keep_alive_config( - wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA, - ACX_KEEP_ALIVE_TPL_INVALID); - if (ret < 0) - goto out; - clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags); - } else { - /* The current firmware only supports sched_scan in idle */ - if (wl->sched_scanning) { - wl1271_scan_sched_scan_stop(wl); - ieee80211_sched_scan_stopped(wl->hw); - } - - ret = wl12xx_start_dev(wl, wlvif); - if (ret < 0) - goto out; - set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags); - } - -out: - return ret; -} - -static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct ieee80211_conf *conf, u32 changed) -{ - bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); - int channel, ret; - - channel = ieee80211_frequency_to_channel(conf->channel->center_freq); - - /* if the channel changes while joined, join again */ - if (changed & IEEE80211_CONF_CHANGE_CHANNEL && - ((wlvif->band != conf->channel->band) || - (wlvif->channel != channel))) { - /* send all pending packets */ - wl1271_tx_work_locked(wl); - wlvif->band = conf->channel->band; - wlvif->channel = channel; - - if (!is_ap) { - /* - * FIXME: the mac80211 should really provide a fixed - * rate to use here. for now, just use the smallest - * possible rate for the band as a fixed rate for - * association frames and other control messages. - */ - if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) - wl1271_set_band_rate(wl, wlvif); - - wlvif->basic_rate = - wl1271_tx_min_rate_get(wl, - wlvif->basic_rate_set); - ret = wl1271_acx_sta_rate_policies(wl, wlvif); - if (ret < 0) - wl1271_warning("rate policy for channel " - "failed %d", ret); - - /* - * change the ROC channel. do it only if we are - * not idle. otherwise, CROC will be called - * anyway. - */ - if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, - &wlvif->flags) && - wl12xx_dev_role_started(wlvif) && - !(conf->flags & IEEE80211_CONF_IDLE)) { - ret = wl12xx_stop_dev(wl, wlvif); - if (ret < 0) - return ret; - - ret = wl12xx_start_dev(wl, wlvif); - if (ret < 0) - return ret; - } - } - } - - if ((changed & IEEE80211_CONF_CHANGE_PS) && !is_ap) { - - if ((conf->flags & IEEE80211_CONF_PS) && - test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) && - !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) { - - int ps_mode; - char *ps_mode_str; - - if (wl->conf.conn.forced_ps) { - ps_mode = STATION_POWER_SAVE_MODE; - ps_mode_str = "forced"; - } else { - ps_mode = STATION_AUTO_PS_MODE; - ps_mode_str = "auto"; - } - - wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str); - - ret = wl1271_ps_set_mode(wl, wlvif, ps_mode); - - if (ret < 0) - wl1271_warning("enter %s ps failed %d", - ps_mode_str, ret); - - } else if (!(conf->flags & IEEE80211_CONF_PS) && - test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) { - - wl1271_debug(DEBUG_PSM, "auto ps disabled"); - - ret = wl1271_ps_set_mode(wl, wlvif, - STATION_ACTIVE_MODE); - if (ret < 0) - wl1271_warning("exit auto ps failed %d", ret); - } - } - - if (conf->power_level != wlvif->power_level) { - ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level); - if (ret < 0) - return ret; - - wlvif->power_level = conf->power_level; - } - - return 0; -} - -static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) -{ - struct wl1271 *wl = hw->priv; - struct wl12xx_vif *wlvif; - struct ieee80211_conf *conf = &hw->conf; - int channel, ret = 0; - - channel = ieee80211_frequency_to_channel(conf->channel->center_freq); - - wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s" - " changed 0x%x", - channel, - conf->flags & IEEE80211_CONF_PS ? "on" : "off", - conf->power_level, - conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use", - changed); - - /* - * mac80211 will go to idle nearly immediately after transmitting some - * frames, such as the deauth. To make sure those frames reach the air, - * wait here until the TX queue is fully flushed. - */ - if ((changed & IEEE80211_CONF_CHANGE_IDLE) && - (conf->flags & IEEE80211_CONF_IDLE)) - wl1271_tx_flush(wl); - - mutex_lock(&wl->mutex); - - /* we support configuring the channel and band even while off */ - if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { - wl->band = conf->channel->band; - wl->channel = channel; - } - - if (changed & IEEE80211_CONF_CHANGE_POWER) - wl->power_level = conf->power_level; - - if (unlikely(wl->state == WL1271_STATE_OFF)) - goto out; - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - /* configure each interface */ - wl12xx_for_each_wlvif(wl, wlvif) { - ret = wl12xx_config_vif(wl, wlvif, conf, changed); - if (ret < 0) - goto out_sleep; - } - -out_sleep: - wl1271_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -struct wl1271_filter_params { - bool enabled; - int mc_list_length; - u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN]; -}; - -static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, - struct netdev_hw_addr_list *mc_list) -{ - struct wl1271_filter_params *fp; - struct netdev_hw_addr *ha; - struct wl1271 *wl = hw->priv; - - if (unlikely(wl->state == WL1271_STATE_OFF)) - return 0; - - fp = kzalloc(sizeof(*fp), GFP_ATOMIC); - if (!fp) { - wl1271_error("Out of memory setting filters."); - return 0; - } - - /* update multicast filtering parameters */ - fp->mc_list_length = 0; - if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) { - fp->enabled = false; - } else { - fp->enabled = true; - netdev_hw_addr_list_for_each(ha, mc_list) { - memcpy(fp->mc_list[fp->mc_list_length], - ha->addr, ETH_ALEN); - fp->mc_list_length++; - } - } - - return (u64)(unsigned long)fp; -} - -#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ - FIF_ALLMULTI | \ - FIF_FCSFAIL | \ - FIF_BCN_PRBRESP_PROMISC | \ - FIF_CONTROL | \ - FIF_OTHER_BSS) - -static void wl1271_op_configure_filter(struct ieee80211_hw *hw, - unsigned int changed, - unsigned int *total, u64 multicast) -{ - struct wl1271_filter_params *fp = (void *)(unsigned long)multicast; - struct wl1271 *wl = hw->priv; - struct wl12xx_vif *wlvif; - - int ret; - - wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x" - " total %x", changed, *total); - - mutex_lock(&wl->mutex); - - *total &= WL1271_SUPPORTED_FILTERS; - changed &= WL1271_SUPPORTED_FILTERS; - - if (unlikely(wl->state == WL1271_STATE_OFF)) - goto out; - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - wl12xx_for_each_wlvif(wl, wlvif) { - if (wlvif->bss_type != BSS_TYPE_AP_BSS) { - if (*total & FIF_ALLMULTI) - ret = wl1271_acx_group_address_tbl(wl, wlvif, - false, - NULL, 0); - else if (fp) - ret = wl1271_acx_group_address_tbl(wl, wlvif, - fp->enabled, - fp->mc_list, - fp->mc_list_length); - if (ret < 0) - goto out_sleep; - } - } - - /* - * the fw doesn't provide an api to configure the filters. instead, - * the filters configuration is based on the active roles / ROC - * state. - */ - -out_sleep: - wl1271_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - kfree(fp); -} - -static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 id, u8 key_type, u8 key_size, - const u8 *key, u8 hlid, u32 tx_seq_32, - u16 tx_seq_16) -{ - struct wl1271_ap_key *ap_key; - int i; - - wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id); - - if (key_size > MAX_KEY_SIZE) - return -EINVAL; - - /* - * Find next free entry in ap_keys. Also check we are not replacing - * an existing key. - */ - for (i = 0; i < MAX_NUM_KEYS; i++) { - if (wlvif->ap.recorded_keys[i] == NULL) - break; - - if (wlvif->ap.recorded_keys[i]->id == id) { - wl1271_warning("trying to record key replacement"); - return -EINVAL; - } - } - - if (i == MAX_NUM_KEYS) - return -EBUSY; - - ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL); - if (!ap_key) - return -ENOMEM; - - ap_key->id = id; - ap_key->key_type = key_type; - ap_key->key_size = key_size; - memcpy(ap_key->key, key, key_size); - ap_key->hlid = hlid; - ap_key->tx_seq_32 = tx_seq_32; - ap_key->tx_seq_16 = tx_seq_16; - - wlvif->ap.recorded_keys[i] = ap_key; - return 0; -} - -static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - int i; - - for (i = 0; i < MAX_NUM_KEYS; i++) { - kfree(wlvif->ap.recorded_keys[i]); - wlvif->ap.recorded_keys[i] = NULL; - } -} - -static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - int i, ret = 0; - struct wl1271_ap_key *key; - bool wep_key_added = false; - - for (i = 0; i < MAX_NUM_KEYS; i++) { - u8 hlid; - if (wlvif->ap.recorded_keys[i] == NULL) - break; - - key = wlvif->ap.recorded_keys[i]; - hlid = key->hlid; - if (hlid == WL12XX_INVALID_LINK_ID) - hlid = wlvif->ap.bcast_hlid; - - ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE, - key->id, key->key_type, - key->key_size, key->key, - hlid, key->tx_seq_32, - key->tx_seq_16); - if (ret < 0) - goto out; - - if (key->key_type == KEY_WEP) - wep_key_added = true; - } - - if (wep_key_added) { - ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key, - wlvif->ap.bcast_hlid); - if (ret < 0) - goto out; - } - -out: - wl1271_free_ap_keys(wl, wlvif); - return ret; -} - -static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u16 action, u8 id, u8 key_type, - u8 key_size, const u8 *key, u32 tx_seq_32, - u16 tx_seq_16, struct ieee80211_sta *sta) -{ - int ret; - bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); - - if (is_ap) { - struct wl1271_station *wl_sta; - u8 hlid; - - if (sta) { - wl_sta = (struct wl1271_station *)sta->drv_priv; - hlid = wl_sta->hlid; - } else { - hlid = wlvif->ap.bcast_hlid; - } - - if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) { - /* - * We do not support removing keys after AP shutdown. - * Pretend we do to make mac80211 happy. - */ - if (action != KEY_ADD_OR_REPLACE) - return 0; - - ret = wl1271_record_ap_key(wl, wlvif, id, - key_type, key_size, - key, hlid, tx_seq_32, - tx_seq_16); - } else { - ret = wl1271_cmd_set_ap_key(wl, wlvif, action, - id, key_type, key_size, - key, hlid, tx_seq_32, - tx_seq_16); - } - - if (ret < 0) - return ret; - } else { - const u8 *addr; - static const u8 bcast_addr[ETH_ALEN] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff - }; - - /* - * A STA set to GEM cipher requires 2 tx spare blocks. - * Return to default value when GEM cipher key is removed - */ - if (key_type == KEY_GEM) { - if (action == KEY_ADD_OR_REPLACE) - wl->tx_spare_blocks = 2; - else if (action == KEY_REMOVE) - wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; - } - - addr = sta ? sta->addr : bcast_addr; - - if (is_zero_ether_addr(addr)) { - /* We dont support TX only encryption */ - return -EOPNOTSUPP; - } - - /* The wl1271 does not allow to remove unicast keys - they - will be cleared automatically on next CMD_JOIN. Ignore the - request silently, as we dont want the mac80211 to emit - an error message. */ - if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr)) - return 0; - - /* don't remove key if hlid was already deleted */ - if (action == KEY_REMOVE && - wlvif->sta.hlid == WL12XX_INVALID_LINK_ID) - return 0; - - ret = wl1271_cmd_set_sta_key(wl, wlvif, action, - id, key_type, key_size, - key, addr, tx_seq_32, - tx_seq_16); - if (ret < 0) - return ret; - - /* the default WEP key needs to be configured at least once */ - if (key_type == KEY_WEP) { - ret = wl12xx_cmd_set_default_wep_key(wl, - wlvif->default_key, - wlvif->sta.hlid); - if (ret < 0) - return ret; - } - } - - return 0; -} - -static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *key_conf) -{ - struct wl1271 *wl = hw->priv; - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - int ret; - u32 tx_seq_32 = 0; - u16 tx_seq_16 = 0; - u8 key_type; - - wl1271_debug(DEBUG_MAC80211, "mac80211 set key"); - - wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta); - wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x", - key_conf->cipher, key_conf->keyidx, - key_conf->keylen, key_conf->flags); - wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen); - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state == WL1271_STATE_OFF)) { - ret = -EAGAIN; - goto out_unlock; - } - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out_unlock; - - switch (key_conf->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - key_type = KEY_WEP; - - key_conf->hw_key_idx = key_conf->keyidx; - break; - case WLAN_CIPHER_SUITE_TKIP: - key_type = KEY_TKIP; - - key_conf->hw_key_idx = key_conf->keyidx; - tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq); - tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq); - break; - case WLAN_CIPHER_SUITE_CCMP: - key_type = KEY_AES; - - key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; - tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq); - tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq); - break; - case WL1271_CIPHER_SUITE_GEM: - key_type = KEY_GEM; - tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq); - tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq); - break; - default: - wl1271_error("Unknown key algo 0x%x", key_conf->cipher); - - ret = -EOPNOTSUPP; - goto out_sleep; - } - - switch (cmd) { - case SET_KEY: - ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE, - key_conf->keyidx, key_type, - key_conf->keylen, key_conf->key, - tx_seq_32, tx_seq_16, sta); - if (ret < 0) { - wl1271_error("Could not add or replace key"); - goto out_sleep; - } - - /* - * reconfiguring arp response if the unicast (or common) - * encryption key type was changed - */ - if (wlvif->bss_type == BSS_TYPE_STA_BSS && - (sta || key_type == KEY_WEP) && - wlvif->encryption_type != key_type) { - wlvif->encryption_type = key_type; - ret = wl1271_cmd_build_arp_rsp(wl, wlvif); - if (ret < 0) { - wl1271_warning("build arp rsp failed: %d", ret); - goto out_sleep; - } - } - break; - - case DISABLE_KEY: - ret = wl1271_set_key(wl, wlvif, KEY_REMOVE, - key_conf->keyidx, key_type, - key_conf->keylen, key_conf->key, - 0, 0, sta); - if (ret < 0) { - wl1271_error("Could not remove key"); - goto out_sleep; - } - break; - - default: - wl1271_error("Unsupported key cmd 0x%x", cmd); - ret = -EOPNOTSUPP; - break; - } - -out_sleep: - wl1271_ps_elp_sleep(wl); - -out_unlock: - mutex_unlock(&wl->mutex); - - return ret; -} - -static int wl1271_op_hw_scan(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct cfg80211_scan_request *req) -{ - struct wl1271 *wl = hw->priv; - int ret; - u8 *ssid = NULL; - size_t len = 0; - - wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan"); - - if (req->n_ssids) { - ssid = req->ssids[0].ssid; - len = req->ssids[0].ssid_len; - } - - mutex_lock(&wl->mutex); - - if (wl->state == WL1271_STATE_OFF) { - /* - * We cannot return -EBUSY here because cfg80211 will expect - * a call to ieee80211_scan_completed if we do - in this case - * there won't be any call. - */ - ret = -EAGAIN; - goto out; - } - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - /* fail if there is any role in ROC */ - if (find_first_bit(wl->roc_map, WL12XX_MAX_ROLES) < WL12XX_MAX_ROLES) { - /* don't allow scanning right now */ - ret = -EBUSY; - goto out_sleep; - } - - ret = wl1271_scan(hw->priv, vif, ssid, len, req); -out_sleep: - wl1271_ps_elp_sleep(wl); -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct wl1271 *wl = hw->priv; - int ret; - - wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan"); - - mutex_lock(&wl->mutex); - - if (wl->state == WL1271_STATE_OFF) - goto out; - - if (wl->scan.state == WL1271_SCAN_STATE_IDLE) - goto out; - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - if (wl->scan.state != WL1271_SCAN_STATE_DONE) { - ret = wl1271_scan_stop(wl); - if (ret < 0) - goto out_sleep; - } - - /* - * Rearm the tx watchdog just before idling scan. This - * prevents just-finished scans from triggering the watchdog - */ - wl12xx_rearm_tx_watchdog_locked(wl); - - wl->scan.state = WL1271_SCAN_STATE_IDLE; - memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); - wl->scan_vif = NULL; - wl->scan.req = NULL; - ieee80211_scan_completed(wl->hw, true); - -out_sleep: - wl1271_ps_elp_sleep(wl); -out: - mutex_unlock(&wl->mutex); - - cancel_delayed_work_sync(&wl->scan_complete_work); -} - -static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct cfg80211_sched_scan_request *req, - struct ieee80211_sched_scan_ies *ies) -{ - struct wl1271 *wl = hw->priv; - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - int ret; - - wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start"); - - mutex_lock(&wl->mutex); - - if (wl->state == WL1271_STATE_OFF) { - ret = -EAGAIN; - goto out; - } - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies); - if (ret < 0) - goto out_sleep; - - ret = wl1271_scan_sched_scan_start(wl, wlvif); - if (ret < 0) - goto out_sleep; - - wl->sched_scanning = true; - -out_sleep: - wl1271_ps_elp_sleep(wl); -out: - mutex_unlock(&wl->mutex); - return ret; -} - -static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct wl1271 *wl = hw->priv; - int ret; - - wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop"); - - mutex_lock(&wl->mutex); - - if (wl->state == WL1271_STATE_OFF) - goto out; - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - wl1271_scan_sched_scan_stop(wl); - - wl1271_ps_elp_sleep(wl); -out: - mutex_unlock(&wl->mutex); -} - -static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) -{ - struct wl1271 *wl = hw->priv; - int ret = 0; - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state == WL1271_STATE_OFF)) { - ret = -EAGAIN; - goto out; - } - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - ret = wl1271_acx_frag_threshold(wl, value); - if (ret < 0) - wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret); - - wl1271_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) -{ - struct wl1271 *wl = hw->priv; - struct wl12xx_vif *wlvif; - int ret = 0; - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state == WL1271_STATE_OFF)) { - ret = -EAGAIN; - goto out; - } - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - wl12xx_for_each_wlvif(wl, wlvif) { - ret = wl1271_acx_rts_threshold(wl, wlvif, value); - if (ret < 0) - wl1271_warning("set rts threshold failed: %d", ret); - } - wl1271_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb, - int offset) -{ - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - u8 ssid_len; - const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset, - skb->len - offset); - - if (!ptr) { - wl1271_error("No SSID in IEs!"); - return -ENOENT; - } - - ssid_len = ptr[1]; - if (ssid_len > IEEE80211_MAX_SSID_LEN) { - wl1271_error("SSID is too long!"); - return -EINVAL; - } - - wlvif->ssid_len = ssid_len; - memcpy(wlvif->ssid, ptr+2, ssid_len); - return 0; -} - -static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset) -{ - int len; - const u8 *next, *end = skb->data + skb->len; - u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset, - skb->len - ieoffset); - if (!ie) - return; - len = ie[1] + 2; - next = ie + len; - memmove(ie, next, end - next); - skb_trim(skb, skb->len - len); -} - -static void wl12xx_remove_vendor_ie(struct sk_buff *skb, - unsigned int oui, u8 oui_type, - int ieoffset) -{ - int len; - const u8 *next, *end = skb->data + skb->len; - u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type, - skb->data + ieoffset, - skb->len - ieoffset); - if (!ie) - return; - len = ie[1] + 2; - next = ie + len; - memmove(ie, next, end - next); - skb_trim(skb, skb->len - len); -} - -static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates, - struct ieee80211_vif *vif) -{ - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - struct sk_buff *skb; - int ret; - - skb = ieee80211_proberesp_get(wl->hw, vif); - if (!skb) - return -EOPNOTSUPP; - - ret = wl1271_cmd_template_set(wl, wlvif->role_id, - CMD_TEMPL_AP_PROBE_RESPONSE, - skb->data, - skb->len, 0, - rates); - - dev_kfree_skb(skb); - return ret; -} - -static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl, - struct ieee80211_vif *vif, - u8 *probe_rsp_data, - size_t probe_rsp_len, - u32 rates) -{ - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; - u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE]; - int ssid_ie_offset, ie_offset, templ_len; - const u8 *ptr; - - /* no need to change probe response if the SSID is set correctly */ - if (wlvif->ssid_len > 0) - return wl1271_cmd_template_set(wl, wlvif->role_id, - CMD_TEMPL_AP_PROBE_RESPONSE, - probe_rsp_data, - probe_rsp_len, 0, - rates); - - if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) { - wl1271_error("probe_rsp template too big"); - return -EINVAL; - } - - /* start searching from IE offset */ - ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); - - ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset, - probe_rsp_len - ie_offset); - if (!ptr) { - wl1271_error("No SSID in beacon!"); - return -EINVAL; - } - - ssid_ie_offset = ptr - probe_rsp_data; - ptr += (ptr[1] + 2); - - memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset); - - /* insert SSID from bss_conf */ - probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID; - probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len; - memcpy(probe_rsp_templ + ssid_ie_offset + 2, - bss_conf->ssid, bss_conf->ssid_len); - templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len; - - memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len, - ptr, probe_rsp_len - (ptr - probe_rsp_data)); - templ_len += probe_rsp_len - (ptr - probe_rsp_data); - - return wl1271_cmd_template_set(wl, wlvif->role_id, - CMD_TEMPL_AP_PROBE_RESPONSE, - probe_rsp_templ, - templ_len, 0, - rates); -} - -static int wl1271_bss_erp_info_changed(struct wl1271 *wl, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changed) -{ - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - int ret = 0; - - if (changed & BSS_CHANGED_ERP_SLOT) { - if (bss_conf->use_short_slot) - ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT); - else - ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG); - if (ret < 0) { - wl1271_warning("Set slot time failed %d", ret); - goto out; - } - } - - if (changed & BSS_CHANGED_ERP_PREAMBLE) { - if (bss_conf->use_short_preamble) - wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT); - else - wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG); - } - - if (changed & BSS_CHANGED_ERP_CTS_PROT) { - if (bss_conf->use_cts_prot) - ret = wl1271_acx_cts_protect(wl, wlvif, - CTSPROTECT_ENABLE); - else - ret = wl1271_acx_cts_protect(wl, wlvif, - CTSPROTECT_DISABLE); - if (ret < 0) { - wl1271_warning("Set ctsprotect failed %d", ret); - goto out; - } - } - -out: - return ret; -} - -static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changed) -{ - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); - int ret = 0; - - if ((changed & BSS_CHANGED_BEACON_INT)) { - wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d", - bss_conf->beacon_int); - - wlvif->beacon_int = bss_conf->beacon_int; - } - - if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) { - u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); - if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) { - wl1271_debug(DEBUG_AP, "probe response updated"); - set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags); - } - } - - if ((changed & BSS_CHANGED_BEACON)) { - struct ieee80211_hdr *hdr; - u32 min_rate; - int ieoffset = offsetof(struct ieee80211_mgmt, - u.beacon.variable); - struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif); - u16 tmpl_id; - - if (!beacon) { - ret = -EINVAL; - goto out; - } - - wl1271_debug(DEBUG_MASTER, "beacon updated"); - - ret = wl1271_ssid_set(vif, beacon, ieoffset); - if (ret < 0) { - dev_kfree_skb(beacon); - goto out; - } - min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); - tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON : - CMD_TEMPL_BEACON; - ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id, - beacon->data, - beacon->len, 0, - min_rate); - if (ret < 0) { - dev_kfree_skb(beacon); - goto out; - } - - /* - * In case we already have a probe-resp beacon set explicitly - * by usermode, don't use the beacon data. - */ - if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags)) - goto end_bcn; - - /* remove TIM ie from probe response */ - wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset); - - /* - * remove p2p ie from probe response. - * the fw reponds to probe requests that don't include - * the p2p ie. probe requests with p2p ie will be passed, - * and will be responded by the supplicant (the spec - * forbids including the p2p ie when responding to probe - * requests that didn't include it). - */ - wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA, - WLAN_OUI_TYPE_WFA_P2P, ieoffset); - - hdr = (struct ieee80211_hdr *) beacon->data; - hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_PROBE_RESP); - if (is_ap) - ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif, - beacon->data, - beacon->len, - min_rate); - else - ret = wl1271_cmd_template_set(wl, wlvif->role_id, - CMD_TEMPL_PROBE_RESPONSE, - beacon->data, - beacon->len, 0, - min_rate); -end_bcn: - dev_kfree_skb(beacon); - if (ret < 0) - goto out; - } - -out: - if (ret != 0) - wl1271_error("beacon info change failed: %d", ret); - return ret; -} - -/* AP mode changes */ -static void wl1271_bss_info_changed_ap(struct wl1271 *wl, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changed) -{ - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - int ret = 0; - - if ((changed & BSS_CHANGED_BASIC_RATES)) { - u32 rates = bss_conf->basic_rates; - - wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates, - wlvif->band); - wlvif->basic_rate = wl1271_tx_min_rate_get(wl, - wlvif->basic_rate_set); - - ret = wl1271_init_ap_rates(wl, wlvif); - if (ret < 0) { - wl1271_error("AP rate policy change failed %d", ret); - goto out; - } - - ret = wl1271_ap_init_templates(wl, vif); - if (ret < 0) - goto out; - } - - ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed); - if (ret < 0) - goto out; - - if ((changed & BSS_CHANGED_BEACON_ENABLED)) { - if (bss_conf->enable_beacon) { - if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) { - ret = wl12xx_cmd_role_start_ap(wl, wlvif); - if (ret < 0) - goto out; - - ret = wl1271_ap_init_hwenc(wl, wlvif); - if (ret < 0) - goto out; - - set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags); - wl1271_debug(DEBUG_AP, "started AP"); - } - } else { - if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) { - ret = wl12xx_cmd_role_stop_ap(wl, wlvif); - if (ret < 0) - goto out; - - clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags); - clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, - &wlvif->flags); - wl1271_debug(DEBUG_AP, "stopped AP"); - } - } - } - - ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed); - if (ret < 0) - goto out; - - /* Handle HT information change */ - if ((changed & BSS_CHANGED_HT) && - (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { - ret = wl1271_acx_set_ht_information(wl, wlvif, - bss_conf->ht_operation_mode); - if (ret < 0) { - wl1271_warning("Set ht information failed %d", ret); - goto out; - } - } - -out: - return; -} - -/* STA/IBSS mode changes */ -static void wl1271_bss_info_changed_sta(struct wl1271 *wl, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changed) -{ - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - bool do_join = false, set_assoc = false; - bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS); - bool ibss_joined = false; - u32 sta_rate_set = 0; - int ret; - struct ieee80211_sta *sta; - bool sta_exists = false; - struct ieee80211_sta_ht_cap sta_ht_cap; - - if (is_ibss) { - ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, - changed); - if (ret < 0) - goto out; - } - - if (changed & BSS_CHANGED_IBSS) { - if (bss_conf->ibss_joined) { - set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags); - ibss_joined = true; - } else { - if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED, - &wlvif->flags)) - wl1271_unjoin(wl, wlvif); - } - } - - if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined) - do_join = true; - - /* Need to update the SSID (for filtering etc) */ - if ((changed & BSS_CHANGED_BEACON) && ibss_joined) - do_join = true; - - if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) { - wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s", - bss_conf->enable_beacon ? "enabled" : "disabled"); - - do_join = true; - } - - if (changed & BSS_CHANGED_IDLE && !is_ibss) { - ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle); - if (ret < 0) - wl1271_warning("idle mode change failed %d", ret); - } - - if ((changed & BSS_CHANGED_CQM)) { - bool enable = false; - if (bss_conf->cqm_rssi_thold) - enable = true; - ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable, - bss_conf->cqm_rssi_thold, - bss_conf->cqm_rssi_hyst); - if (ret < 0) - goto out; - wlvif->rssi_thold = bss_conf->cqm_rssi_thold; - } - - if (changed & BSS_CHANGED_BSSID && - (is_ibss || bss_conf->assoc)) - if (!is_zero_ether_addr(bss_conf->bssid)) { - ret = wl12xx_cmd_build_null_data(wl, wlvif); - if (ret < 0) - goto out; - - ret = wl1271_build_qos_null_data(wl, vif); - if (ret < 0) - goto out; - - /* Need to update the BSSID (for filtering etc) */ - do_join = true; - } - - if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) { - rcu_read_lock(); - sta = ieee80211_find_sta(vif, bss_conf->bssid); - if (!sta) - goto sta_not_found; - - /* save the supp_rates of the ap */ - sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band]; - if (sta->ht_cap.ht_supported) - sta_rate_set |= - (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET); - sta_ht_cap = sta->ht_cap; - sta_exists = true; - -sta_not_found: - rcu_read_unlock(); - } - - if ((changed & BSS_CHANGED_ASSOC)) { - if (bss_conf->assoc) { - u32 rates; - int ieoffset; - wlvif->aid = bss_conf->aid; - wlvif->beacon_int = bss_conf->beacon_int; - set_assoc = true; - - /* - * use basic rates from AP, and determine lowest rate - * to use with control frames. - */ - rates = bss_conf->basic_rates; - wlvif->basic_rate_set = - wl1271_tx_enabled_rates_get(wl, rates, - wlvif->band); - wlvif->basic_rate = - wl1271_tx_min_rate_get(wl, - wlvif->basic_rate_set); - if (sta_rate_set) - wlvif->rate_set = - wl1271_tx_enabled_rates_get(wl, - sta_rate_set, - wlvif->band); - ret = wl1271_acx_sta_rate_policies(wl, wlvif); - if (ret < 0) - goto out; - - /* - * with wl1271, we don't need to update the - * beacon_int and dtim_period, because the firmware - * updates it by itself when the first beacon is - * received after a join. - */ - ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid); - if (ret < 0) - goto out; - - /* - * Get a template for hardware connection maintenance - */ - dev_kfree_skb(wlvif->probereq); - wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl, - wlvif, - NULL); - ieoffset = offsetof(struct ieee80211_mgmt, - u.probe_req.variable); - wl1271_ssid_set(vif, wlvif->probereq, ieoffset); - - /* enable the connection monitoring feature */ - ret = wl1271_acx_conn_monit_params(wl, wlvif, true); - if (ret < 0) - goto out; - } else { - /* use defaults when not associated */ - bool was_assoc = - !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED, - &wlvif->flags); - bool was_ifup = - !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT, - &wlvif->flags); - wlvif->aid = 0; - - /* free probe-request template */ - dev_kfree_skb(wlvif->probereq); - wlvif->probereq = NULL; - - /* revert back to minimum rates for the current band */ - wl1271_set_band_rate(wl, wlvif); - wlvif->basic_rate = - wl1271_tx_min_rate_get(wl, - wlvif->basic_rate_set); - ret = wl1271_acx_sta_rate_policies(wl, wlvif); - if (ret < 0) - goto out; - - /* disable connection monitor features */ - ret = wl1271_acx_conn_monit_params(wl, wlvif, false); - - /* Disable the keep-alive feature */ - ret = wl1271_acx_keep_alive_mode(wl, wlvif, false); - if (ret < 0) - goto out; - - /* restore the bssid filter and go to dummy bssid */ - if (was_assoc) { - /* - * we might have to disable roc, if there was - * no IF_OPER_UP notification. - */ - if (!was_ifup) { - ret = wl12xx_croc(wl, wlvif->role_id); - if (ret < 0) - goto out; - } - /* - * (we also need to disable roc in case of - * roaming on the same channel. until we will - * have a better flow...) - */ - if (test_bit(wlvif->dev_role_id, wl->roc_map)) { - ret = wl12xx_croc(wl, - wlvif->dev_role_id); - if (ret < 0) - goto out; - } - - wl1271_unjoin(wl, wlvif); - if (!bss_conf->idle) - wl12xx_start_dev(wl, wlvif); - } - } - } - - if (changed & BSS_CHANGED_IBSS) { - wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d", - bss_conf->ibss_joined); - - if (bss_conf->ibss_joined) { - u32 rates = bss_conf->basic_rates; - wlvif->basic_rate_set = - wl1271_tx_enabled_rates_get(wl, rates, - wlvif->band); - wlvif->basic_rate = - wl1271_tx_min_rate_get(wl, - wlvif->basic_rate_set); - - /* by default, use 11b + OFDM rates */ - wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES; - ret = wl1271_acx_sta_rate_policies(wl, wlvif); - if (ret < 0) - goto out; - } - } - - ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed); - if (ret < 0) - goto out; - - if (do_join) { - ret = wl1271_join(wl, wlvif, set_assoc); - if (ret < 0) { - wl1271_warning("cmd join failed %d", ret); - goto out; - } - - /* ROC until connected (after EAPOL exchange) */ - if (!is_ibss) { - ret = wl12xx_roc(wl, wlvif, wlvif->role_id); - if (ret < 0) - goto out; - - if (test_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags)) - wl12xx_set_authorized(wl, wlvif); - } - /* - * stop device role if started (we might already be in - * STA/IBSS role). - */ - if (wl12xx_dev_role_started(wlvif)) { - ret = wl12xx_stop_dev(wl, wlvif); - if (ret < 0) - goto out; - } - } - - /* Handle new association with HT. Do this after join. */ - if (sta_exists) { - if ((changed & BSS_CHANGED_HT) && - (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { - ret = wl1271_acx_set_ht_capabilities(wl, - &sta_ht_cap, - true, - wlvif->sta.hlid); - if (ret < 0) { - wl1271_warning("Set ht cap true failed %d", - ret); - goto out; - } - } - /* handle new association without HT and disassociation */ - else if (changed & BSS_CHANGED_ASSOC) { - ret = wl1271_acx_set_ht_capabilities(wl, - &sta_ht_cap, - false, - wlvif->sta.hlid); - if (ret < 0) { - wl1271_warning("Set ht cap false failed %d", - ret); - goto out; - } - } - } - - /* Handle HT information change. Done after join. */ - if ((changed & BSS_CHANGED_HT) && - (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { - ret = wl1271_acx_set_ht_information(wl, wlvif, - bss_conf->ht_operation_mode); - if (ret < 0) { - wl1271_warning("Set ht information failed %d", ret); - goto out; - } - } - - /* Handle arp filtering. Done after join. */ - if ((changed & BSS_CHANGED_ARP_FILTER) || - (!is_ibss && (changed & BSS_CHANGED_QOS))) { - __be32 addr = bss_conf->arp_addr_list[0]; - wlvif->sta.qos = bss_conf->qos; - WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS); - - if (bss_conf->arp_addr_cnt == 1 && - bss_conf->arp_filter_enabled) { - wlvif->ip_addr = addr; - /* - * The template should have been configured only upon - * association. however, it seems that the correct ip - * isn't being set (when sending), so we have to - * reconfigure the template upon every ip change. - */ - ret = wl1271_cmd_build_arp_rsp(wl, wlvif); - if (ret < 0) { - wl1271_warning("build arp rsp failed: %d", ret); - goto out; - } - - ret = wl1271_acx_arp_ip_filter(wl, wlvif, - (ACX_ARP_FILTER_ARP_FILTERING | - ACX_ARP_FILTER_AUTO_ARP), - addr); - } else { - wlvif->ip_addr = 0; - ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr); - } - - if (ret < 0) - goto out; - } - -out: - return; -} - -static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changed) -{ - struct wl1271 *wl = hw->priv; - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); - int ret; - - wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x", - (int)changed); - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state == WL1271_STATE_OFF)) - goto out; - - if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))) - goto out; - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - if (is_ap) - wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed); - else - wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed); - - wl1271_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); -} - -static int wl1271_op_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 queue, - const struct ieee80211_tx_queue_params *params) -{ - struct wl1271 *wl = hw->priv; - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - u8 ps_scheme; - int ret = 0; - - mutex_lock(&wl->mutex); - - wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue); - - if (params->uapsd) - ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER; - else - ps_scheme = CONF_PS_SCHEME_LEGACY; - - if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) - goto out; - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - /* - * the txop is confed in units of 32us by the mac80211, - * we need us - */ - ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue), - params->cw_min, params->cw_max, - params->aifs, params->txop << 5); - if (ret < 0) - goto out_sleep; - - ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue), - CONF_CHANNEL_TYPE_EDCF, - wl1271_tx_get_queue(queue), - ps_scheme, CONF_ACK_POLICY_LEGACY, - 0, 0); - -out_sleep: - wl1271_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - - struct wl1271 *wl = hw->priv; - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - u64 mactime = ULLONG_MAX; - int ret; - - wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf"); - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state == WL1271_STATE_OFF)) - goto out; - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - ret = wl12xx_acx_tsf_info(wl, wlvif, &mactime); - if (ret < 0) - goto out_sleep; - -out_sleep: - wl1271_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - return mactime; -} - -static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx, - struct survey_info *survey) -{ - struct wl1271 *wl = hw->priv; - struct ieee80211_conf *conf = &hw->conf; - - if (idx != 0) - return -ENOENT; - - survey->channel = conf->channel; - survey->filled = SURVEY_INFO_NOISE_DBM; - survey->noise = wl->noise; - - return 0; -} - -static int wl1271_allocate_sta(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - struct ieee80211_sta *sta) -{ - struct wl1271_station *wl_sta; - int ret; - - - if (wl->active_sta_count >= AP_MAX_STATIONS) { - wl1271_warning("could not allocate HLID - too much stations"); - return -EBUSY; - } - - wl_sta = (struct wl1271_station *)sta->drv_priv; - ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid); - if (ret < 0) { - wl1271_warning("could not allocate HLID - too many links"); - return -EBUSY; - } - - set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map); - memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN); - wl->active_sta_count++; - return 0; -} - -void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid) -{ - if (!test_bit(hlid, wlvif->ap.sta_hlid_map)) - return; - - clear_bit(hlid, wlvif->ap.sta_hlid_map); - memset(wl->links[hlid].addr, 0, ETH_ALEN); - wl->links[hlid].ba_bitmap = 0; - __clear_bit(hlid, &wl->ap_ps_map); - __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); - wl12xx_free_link(wl, wlvif, &hlid); - wl->active_sta_count--; - - /* - * rearm the tx watchdog when the last STA is freed - give the FW a - * chance to return STA-buffered packets before complaining. - */ - if (wl->active_sta_count == 0) - wl12xx_rearm_tx_watchdog_locked(wl); -} - -static int wl12xx_sta_add(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - struct ieee80211_sta *sta) -{ - struct wl1271_station *wl_sta; - int ret = 0; - u8 hlid; - - wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid); - - ret = wl1271_allocate_sta(wl, wlvif, sta); - if (ret < 0) - return ret; - - wl_sta = (struct wl1271_station *)sta->drv_priv; - hlid = wl_sta->hlid; - - ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid); - if (ret < 0) - wl1271_free_sta(wl, wlvif, hlid); - - return ret; -} - -static int wl12xx_sta_remove(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - struct ieee80211_sta *sta) -{ - struct wl1271_station *wl_sta; - int ret = 0, id; - - wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid); - - wl_sta = (struct wl1271_station *)sta->drv_priv; - id = wl_sta->hlid; - if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map))) - return -EINVAL; - - ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid); - if (ret < 0) - return ret; - - wl1271_free_sta(wl, wlvif, wl_sta->hlid); - return ret; -} - -static int wl12xx_update_sta_state(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - struct ieee80211_sta *sta, - enum ieee80211_sta_state old_state, - enum ieee80211_sta_state new_state) -{ - struct wl1271_station *wl_sta; - u8 hlid; - bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS; - bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS; - int ret; - - wl_sta = (struct wl1271_station *)sta->drv_priv; - hlid = wl_sta->hlid; - - /* Add station (AP mode) */ - if (is_ap && - old_state == IEEE80211_STA_NOTEXIST && - new_state == IEEE80211_STA_NONE) - return wl12xx_sta_add(wl, wlvif, sta); - - /* Remove station (AP mode) */ - if (is_ap && - old_state == IEEE80211_STA_NONE && - new_state == IEEE80211_STA_NOTEXIST) { - /* must not fail */ - wl12xx_sta_remove(wl, wlvif, sta); - return 0; - } - - /* Authorize station (AP mode) */ - if (is_ap && - new_state == IEEE80211_STA_AUTHORIZED) { - ret = wl12xx_cmd_set_peer_state(wl, hlid); - if (ret < 0) - return ret; - - ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, - hlid); - return ret; - } - - /* Authorize station */ - if (is_sta && - new_state == IEEE80211_STA_AUTHORIZED) { - set_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags); - return wl12xx_set_authorized(wl, wlvif); - } - - if (is_sta && - old_state == IEEE80211_STA_AUTHORIZED && - new_state == IEEE80211_STA_ASSOC) { - clear_bit(WLVIF_FLAG_STA_AUTHORIZED, &wlvif->flags); - return 0; - } - - return 0; -} - -static int wl12xx_op_sta_state(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - enum ieee80211_sta_state old_state, - enum ieee80211_sta_state new_state) -{ - struct wl1271 *wl = hw->priv; - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - int ret; - - wl1271_debug(DEBUG_MAC80211, "mac80211 sta %d state=%d->%d", - sta->aid, old_state, new_state); - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state == WL1271_STATE_OFF)) { - ret = -EBUSY; - goto out; - } - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - ret = wl12xx_update_sta_state(wl, wlvif, sta, old_state, new_state); - - wl1271_ps_elp_sleep(wl); -out: - mutex_unlock(&wl->mutex); - if (new_state < old_state) - return 0; - return ret; -} - -static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size) -{ - struct wl1271 *wl = hw->priv; - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - int ret; - u8 hlid, *ba_bitmap; - - wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action, - tid); - - /* sanity check - the fields in FW are only 8bits wide */ - if (WARN_ON(tid > 0xFF)) - return -ENOTSUPP; - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state == WL1271_STATE_OFF)) { - ret = -EAGAIN; - goto out; - } - - if (wlvif->bss_type == BSS_TYPE_STA_BSS) { - hlid = wlvif->sta.hlid; - ba_bitmap = &wlvif->sta.ba_rx_bitmap; - } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) { - struct wl1271_station *wl_sta; - - wl_sta = (struct wl1271_station *)sta->drv_priv; - hlid = wl_sta->hlid; - ba_bitmap = &wl->links[hlid].ba_bitmap; - } else { - ret = -EINVAL; - goto out; - } - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d", - tid, action); - - switch (action) { - case IEEE80211_AMPDU_RX_START: - if (!wlvif->ba_support || !wlvif->ba_allowed) { - ret = -ENOTSUPP; - break; - } - - if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) { - ret = -EBUSY; - wl1271_error("exceeded max RX BA sessions"); - break; - } - - if (*ba_bitmap & BIT(tid)) { - ret = -EINVAL; - wl1271_error("cannot enable RX BA session on active " - "tid: %d", tid); - break; - } - - ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true, - hlid); - if (!ret) { - *ba_bitmap |= BIT(tid); - wl->ba_rx_session_count++; - } - break; - - case IEEE80211_AMPDU_RX_STOP: - if (!(*ba_bitmap & BIT(tid))) { - ret = -EINVAL; - wl1271_error("no active RX BA session on tid: %d", - tid); - break; - } - - ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false, - hlid); - if (!ret) { - *ba_bitmap &= ~BIT(tid); - wl->ba_rx_session_count--; - } - break; - - /* - * The BA initiator session management in FW independently. - * Falling break here on purpose for all TX APDU commands. - */ - case IEEE80211_AMPDU_TX_START: - case IEEE80211_AMPDU_TX_STOP: - case IEEE80211_AMPDU_TX_OPERATIONAL: - ret = -EINVAL; - break; - - default: - wl1271_error("Incorrect ampdu action id=%x\n", action); - ret = -EINVAL; - } - - wl1271_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - const struct cfg80211_bitrate_mask *mask) -{ - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - struct wl1271 *wl = hw->priv; - int i, ret = 0; - - wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x", - mask->control[NL80211_BAND_2GHZ].legacy, - mask->control[NL80211_BAND_5GHZ].legacy); - - mutex_lock(&wl->mutex); - - for (i = 0; i < IEEE80211_NUM_BANDS; i++) - wlvif->bitrate_masks[i] = - wl1271_tx_enabled_rates_get(wl, - mask->control[i].legacy, - i); - - if (unlikely(wl->state == WL1271_STATE_OFF)) - goto out; - - if (wlvif->bss_type == BSS_TYPE_STA_BSS && - !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - wl1271_set_band_rate(wl, wlvif); - wlvif->basic_rate = - wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set); - ret = wl1271_acx_sta_rate_policies(wl, wlvif); - - wl1271_ps_elp_sleep(wl); - } -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -static void wl12xx_op_channel_switch(struct ieee80211_hw *hw, - struct ieee80211_channel_switch *ch_switch) -{ - struct wl1271 *wl = hw->priv; - struct wl12xx_vif *wlvif; - int ret; - - wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch"); - - wl1271_tx_flush(wl); - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state == WL1271_STATE_OFF)) { - wl12xx_for_each_wlvif_sta(wl, wlvif) { - struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); - ieee80211_chswitch_done(vif, false); - } - goto out; - } - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - /* TODO: change mac80211 to pass vif as param */ - wl12xx_for_each_wlvif_sta(wl, wlvif) { - ret = wl12xx_cmd_channel_switch(wl, wlvif, ch_switch); - - if (!ret) - set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags); - } - - wl1271_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); -} - -static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) -{ - struct wl1271 *wl = hw->priv; - bool ret = false; - - mutex_lock(&wl->mutex); - - if (unlikely(wl->state == WL1271_STATE_OFF)) - goto out; - - /* packets are considered pending if in the TX queue or the FW */ - ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0); -out: - mutex_unlock(&wl->mutex); - - return ret; -} - -/* can't be const, mac80211 writes to this */ -static struct ieee80211_rate wl1271_rates[] = { - { .bitrate = 10, - .hw_value = CONF_HW_BIT_RATE_1MBPS, - .hw_value_short = CONF_HW_BIT_RATE_1MBPS, }, - { .bitrate = 20, - .hw_value = CONF_HW_BIT_RATE_2MBPS, - .hw_value_short = CONF_HW_BIT_RATE_2MBPS, - .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 55, - .hw_value = CONF_HW_BIT_RATE_5_5MBPS, - .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS, - .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 110, - .hw_value = CONF_HW_BIT_RATE_11MBPS, - .hw_value_short = CONF_HW_BIT_RATE_11MBPS, - .flags = IEEE80211_RATE_SHORT_PREAMBLE }, - { .bitrate = 60, - .hw_value = CONF_HW_BIT_RATE_6MBPS, - .hw_value_short = CONF_HW_BIT_RATE_6MBPS, }, - { .bitrate = 90, - .hw_value = CONF_HW_BIT_RATE_9MBPS, - .hw_value_short = CONF_HW_BIT_RATE_9MBPS, }, - { .bitrate = 120, - .hw_value = CONF_HW_BIT_RATE_12MBPS, - .hw_value_short = CONF_HW_BIT_RATE_12MBPS, }, - { .bitrate = 180, - .hw_value = CONF_HW_BIT_RATE_18MBPS, - .hw_value_short = CONF_HW_BIT_RATE_18MBPS, }, - { .bitrate = 240, - .hw_value = CONF_HW_BIT_RATE_24MBPS, - .hw_value_short = CONF_HW_BIT_RATE_24MBPS, }, - { .bitrate = 360, - .hw_value = CONF_HW_BIT_RATE_36MBPS, - .hw_value_short = CONF_HW_BIT_RATE_36MBPS, }, - { .bitrate = 480, - .hw_value = CONF_HW_BIT_RATE_48MBPS, - .hw_value_short = CONF_HW_BIT_RATE_48MBPS, }, - { .bitrate = 540, - .hw_value = CONF_HW_BIT_RATE_54MBPS, - .hw_value_short = CONF_HW_BIT_RATE_54MBPS, }, -}; - -/* can't be const, mac80211 writes to this */ -static struct ieee80211_channel wl1271_channels[] = { - { .hw_value = 1, .center_freq = 2412, .max_power = 25 }, - { .hw_value = 2, .center_freq = 2417, .max_power = 25 }, - { .hw_value = 3, .center_freq = 2422, .max_power = 25 }, - { .hw_value = 4, .center_freq = 2427, .max_power = 25 }, - { .hw_value = 5, .center_freq = 2432, .max_power = 25 }, - { .hw_value = 6, .center_freq = 2437, .max_power = 25 }, - { .hw_value = 7, .center_freq = 2442, .max_power = 25 }, - { .hw_value = 8, .center_freq = 2447, .max_power = 25 }, - { .hw_value = 9, .center_freq = 2452, .max_power = 25 }, - { .hw_value = 10, .center_freq = 2457, .max_power = 25 }, - { .hw_value = 11, .center_freq = 2462, .max_power = 25 }, - { .hw_value = 12, .center_freq = 2467, .max_power = 25 }, - { .hw_value = 13, .center_freq = 2472, .max_power = 25 }, - { .hw_value = 14, .center_freq = 2484, .max_power = 25 }, -}; - -/* mapping to indexes for wl1271_rates */ -static const u8 wl1271_rate_to_idx_2ghz[] = { - /* MCS rates are used only with 11n */ - 7, /* CONF_HW_RXTX_RATE_MCS7_SGI */ - 7, /* CONF_HW_RXTX_RATE_MCS7 */ - 6, /* CONF_HW_RXTX_RATE_MCS6 */ - 5, /* CONF_HW_RXTX_RATE_MCS5 */ - 4, /* CONF_HW_RXTX_RATE_MCS4 */ - 3, /* CONF_HW_RXTX_RATE_MCS3 */ - 2, /* CONF_HW_RXTX_RATE_MCS2 */ - 1, /* CONF_HW_RXTX_RATE_MCS1 */ - 0, /* CONF_HW_RXTX_RATE_MCS0 */ - - 11, /* CONF_HW_RXTX_RATE_54 */ - 10, /* CONF_HW_RXTX_RATE_48 */ - 9, /* CONF_HW_RXTX_RATE_36 */ - 8, /* CONF_HW_RXTX_RATE_24 */ - - /* TI-specific rate */ - CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */ - - 7, /* CONF_HW_RXTX_RATE_18 */ - 6, /* CONF_HW_RXTX_RATE_12 */ - 3, /* CONF_HW_RXTX_RATE_11 */ - 5, /* CONF_HW_RXTX_RATE_9 */ - 4, /* CONF_HW_RXTX_RATE_6 */ - 2, /* CONF_HW_RXTX_RATE_5_5 */ - 1, /* CONF_HW_RXTX_RATE_2 */ - 0 /* CONF_HW_RXTX_RATE_1 */ -}; - -/* 11n STA capabilities */ -#define HW_RX_HIGHEST_RATE 72 - -#define WL12XX_HT_CAP { \ - .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \ - (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \ - .ht_supported = true, \ - .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \ - .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \ - .mcs = { \ - .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \ - .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \ - .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \ - }, \ -} - -/* can't be const, mac80211 writes to this */ -static struct ieee80211_supported_band wl1271_band_2ghz = { - .channels = wl1271_channels, - .n_channels = ARRAY_SIZE(wl1271_channels), - .bitrates = wl1271_rates, - .n_bitrates = ARRAY_SIZE(wl1271_rates), - .ht_cap = WL12XX_HT_CAP, -}; - -/* 5 GHz data rates for WL1273 */ -static struct ieee80211_rate wl1271_rates_5ghz[] = { - { .bitrate = 60, - .hw_value = CONF_HW_BIT_RATE_6MBPS, - .hw_value_short = CONF_HW_BIT_RATE_6MBPS, }, - { .bitrate = 90, - .hw_value = CONF_HW_BIT_RATE_9MBPS, - .hw_value_short = CONF_HW_BIT_RATE_9MBPS, }, - { .bitrate = 120, - .hw_value = CONF_HW_BIT_RATE_12MBPS, - .hw_value_short = CONF_HW_BIT_RATE_12MBPS, }, - { .bitrate = 180, - .hw_value = CONF_HW_BIT_RATE_18MBPS, - .hw_value_short = CONF_HW_BIT_RATE_18MBPS, }, - { .bitrate = 240, - .hw_value = CONF_HW_BIT_RATE_24MBPS, - .hw_value_short = CONF_HW_BIT_RATE_24MBPS, }, - { .bitrate = 360, - .hw_value = CONF_HW_BIT_RATE_36MBPS, - .hw_value_short = CONF_HW_BIT_RATE_36MBPS, }, - { .bitrate = 480, - .hw_value = CONF_HW_BIT_RATE_48MBPS, - .hw_value_short = CONF_HW_BIT_RATE_48MBPS, }, - { .bitrate = 540, - .hw_value = CONF_HW_BIT_RATE_54MBPS, - .hw_value_short = CONF_HW_BIT_RATE_54MBPS, }, -}; - -/* 5 GHz band channels for WL1273 */ -static struct ieee80211_channel wl1271_channels_5ghz[] = { - { .hw_value = 7, .center_freq = 5035, .max_power = 25 }, - { .hw_value = 8, .center_freq = 5040, .max_power = 25 }, - { .hw_value = 9, .center_freq = 5045, .max_power = 25 }, - { .hw_value = 11, .center_freq = 5055, .max_power = 25 }, - { .hw_value = 12, .center_freq = 5060, .max_power = 25 }, - { .hw_value = 16, .center_freq = 5080, .max_power = 25 }, - { .hw_value = 34, .center_freq = 5170, .max_power = 25 }, - { .hw_value = 36, .center_freq = 5180, .max_power = 25 }, - { .hw_value = 38, .center_freq = 5190, .max_power = 25 }, - { .hw_value = 40, .center_freq = 5200, .max_power = 25 }, - { .hw_value = 42, .center_freq = 5210, .max_power = 25 }, - { .hw_value = 44, .center_freq = 5220, .max_power = 25 }, - { .hw_value = 46, .center_freq = 5230, .max_power = 25 }, - { .hw_value = 48, .center_freq = 5240, .max_power = 25 }, - { .hw_value = 52, .center_freq = 5260, .max_power = 25 }, - { .hw_value = 56, .center_freq = 5280, .max_power = 25 }, - { .hw_value = 60, .center_freq = 5300, .max_power = 25 }, - { .hw_value = 64, .center_freq = 5320, .max_power = 25 }, - { .hw_value = 100, .center_freq = 5500, .max_power = 25 }, - { .hw_value = 104, .center_freq = 5520, .max_power = 25 }, - { .hw_value = 108, .center_freq = 5540, .max_power = 25 }, - { .hw_value = 112, .center_freq = 5560, .max_power = 25 }, - { .hw_value = 116, .center_freq = 5580, .max_power = 25 }, - { .hw_value = 120, .center_freq = 5600, .max_power = 25 }, - { .hw_value = 124, .center_freq = 5620, .max_power = 25 }, - { .hw_value = 128, .center_freq = 5640, .max_power = 25 }, - { .hw_value = 132, .center_freq = 5660, .max_power = 25 }, - { .hw_value = 136, .center_freq = 5680, .max_power = 25 }, - { .hw_value = 140, .center_freq = 5700, .max_power = 25 }, - { .hw_value = 149, .center_freq = 5745, .max_power = 25 }, - { .hw_value = 153, .center_freq = 5765, .max_power = 25 }, - { .hw_value = 157, .center_freq = 5785, .max_power = 25 }, - { .hw_value = 161, .center_freq = 5805, .max_power = 25 }, - { .hw_value = 165, .center_freq = 5825, .max_power = 25 }, -}; - -/* mapping to indexes for wl1271_rates_5ghz */ -static const u8 wl1271_rate_to_idx_5ghz[] = { - /* MCS rates are used only with 11n */ - 7, /* CONF_HW_RXTX_RATE_MCS7_SGI */ - 7, /* CONF_HW_RXTX_RATE_MCS7 */ - 6, /* CONF_HW_RXTX_RATE_MCS6 */ - 5, /* CONF_HW_RXTX_RATE_MCS5 */ - 4, /* CONF_HW_RXTX_RATE_MCS4 */ - 3, /* CONF_HW_RXTX_RATE_MCS3 */ - 2, /* CONF_HW_RXTX_RATE_MCS2 */ - 1, /* CONF_HW_RXTX_RATE_MCS1 */ - 0, /* CONF_HW_RXTX_RATE_MCS0 */ - - 7, /* CONF_HW_RXTX_RATE_54 */ - 6, /* CONF_HW_RXTX_RATE_48 */ - 5, /* CONF_HW_RXTX_RATE_36 */ - 4, /* CONF_HW_RXTX_RATE_24 */ - - /* TI-specific rate */ - CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */ - - 3, /* CONF_HW_RXTX_RATE_18 */ - 2, /* CONF_HW_RXTX_RATE_12 */ - CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */ - 1, /* CONF_HW_RXTX_RATE_9 */ - 0, /* CONF_HW_RXTX_RATE_6 */ - CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */ - CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */ - CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */ -}; - -static struct ieee80211_supported_band wl1271_band_5ghz = { - .channels = wl1271_channels_5ghz, - .n_channels = ARRAY_SIZE(wl1271_channels_5ghz), - .bitrates = wl1271_rates_5ghz, - .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz), - .ht_cap = WL12XX_HT_CAP, -}; - -static const u8 *wl1271_band_rate_to_idx[] = { - [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz, - [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz -}; - -static const struct ieee80211_ops wl1271_ops = { - .start = wl1271_op_start, - .stop = wl1271_op_stop, - .add_interface = wl1271_op_add_interface, - .remove_interface = wl1271_op_remove_interface, - .change_interface = wl12xx_op_change_interface, -#ifdef CONFIG_PM - .suspend = wl1271_op_suspend, - .resume = wl1271_op_resume, -#endif - .config = wl1271_op_config, - .prepare_multicast = wl1271_op_prepare_multicast, - .configure_filter = wl1271_op_configure_filter, - .tx = wl1271_op_tx, - .set_key = wl1271_op_set_key, - .hw_scan = wl1271_op_hw_scan, - .cancel_hw_scan = wl1271_op_cancel_hw_scan, - .sched_scan_start = wl1271_op_sched_scan_start, - .sched_scan_stop = wl1271_op_sched_scan_stop, - .bss_info_changed = wl1271_op_bss_info_changed, - .set_frag_threshold = wl1271_op_set_frag_threshold, - .set_rts_threshold = wl1271_op_set_rts_threshold, - .conf_tx = wl1271_op_conf_tx, - .get_tsf = wl1271_op_get_tsf, - .get_survey = wl1271_op_get_survey, - .sta_state = wl12xx_op_sta_state, - .ampdu_action = wl1271_op_ampdu_action, - .tx_frames_pending = wl1271_tx_frames_pending, - .set_bitrate_mask = wl12xx_set_bitrate_mask, - .channel_switch = wl12xx_op_channel_switch, - CFG80211_TESTMODE_CMD(wl1271_tm_cmd) -}; - - -u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band) -{ - u8 idx; - - BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *)); - - if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) { - wl1271_error("Illegal RX rate from HW: %d", rate); - return 0; - } - - idx = wl1271_band_rate_to_idx[band][rate]; - if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) { - wl1271_error("Unsupported RX rate from HW: %d", rate); - return 0; - } - - return idx; -} - -static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct wl1271 *wl = dev_get_drvdata(dev); - ssize_t len; - - len = PAGE_SIZE; - - mutex_lock(&wl->mutex); - len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n", - wl->sg_enabled); - mutex_unlock(&wl->mutex); - - return len; - -} - -static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct wl1271 *wl = dev_get_drvdata(dev); - unsigned long res; - int ret; - - ret = kstrtoul(buf, 10, &res); - if (ret < 0) { - wl1271_warning("incorrect value written to bt_coex_mode"); - return count; - } - - mutex_lock(&wl->mutex); - - res = !!res; - - if (res == wl->sg_enabled) - goto out; - - wl->sg_enabled = res; - - if (wl->state == WL1271_STATE_OFF) - goto out; - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - wl1271_acx_sg_enable(wl, wl->sg_enabled); - wl1271_ps_elp_sleep(wl); - - out: - mutex_unlock(&wl->mutex); - return count; -} - -static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR, - wl1271_sysfs_show_bt_coex_state, - wl1271_sysfs_store_bt_coex_state); - -static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct wl1271 *wl = dev_get_drvdata(dev); - ssize_t len; - - len = PAGE_SIZE; - - mutex_lock(&wl->mutex); - if (wl->hw_pg_ver >= 0) - len = snprintf(buf, len, "%d\n", wl->hw_pg_ver); - else - len = snprintf(buf, len, "n/a\n"); - mutex_unlock(&wl->mutex); - - return len; -} - -static DEVICE_ATTR(hw_pg_ver, S_IRUGO, - wl1271_sysfs_show_hw_pg_ver, NULL); - -static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buffer, loff_t pos, size_t count) -{ - struct device *dev = container_of(kobj, struct device, kobj); - struct wl1271 *wl = dev_get_drvdata(dev); - ssize_t len; - int ret; - - ret = mutex_lock_interruptible(&wl->mutex); - if (ret < 0) - return -ERESTARTSYS; - - /* Let only one thread read the log at a time, blocking others */ - while (wl->fwlog_size == 0) { - DEFINE_WAIT(wait); - - prepare_to_wait_exclusive(&wl->fwlog_waitq, - &wait, - TASK_INTERRUPTIBLE); - - if (wl->fwlog_size != 0) { - finish_wait(&wl->fwlog_waitq, &wait); - break; - } - - mutex_unlock(&wl->mutex); - - schedule(); - finish_wait(&wl->fwlog_waitq, &wait); - - if (signal_pending(current)) - return -ERESTARTSYS; - - ret = mutex_lock_interruptible(&wl->mutex); - if (ret < 0) - return -ERESTARTSYS; - } - - /* Check if the fwlog is still valid */ - if (wl->fwlog_size < 0) { - mutex_unlock(&wl->mutex); - return 0; - } - - /* Seeking is not supported - old logs are not kept. Disregard pos. */ - len = min(count, (size_t)wl->fwlog_size); - wl->fwlog_size -= len; - memcpy(buffer, wl->fwlog, len); - - /* Make room for new messages */ - memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size); - - mutex_unlock(&wl->mutex); - - return len; -} - -static struct bin_attribute fwlog_attr = { - .attr = {.name = "fwlog", .mode = S_IRUSR}, - .read = wl1271_sysfs_read_fwlog, -}; - -static bool wl12xx_mac_in_fuse(struct wl1271 *wl) -{ - bool supported = false; - u8 major, minor; - - if (wl->chip.id == CHIP_ID_1283_PG20) { - major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver); - minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver); - - /* in wl128x we have the MAC address if the PG is >= (2, 1) */ - if (major > 2 || (major == 2 && minor >= 1)) - supported = true; - } else { - major = WL127X_PG_GET_MAJOR(wl->hw_pg_ver); - minor = WL127X_PG_GET_MINOR(wl->hw_pg_ver); - - /* in wl127x we have the MAC address if the PG is >= (3, 1) */ - if (major == 3 && minor >= 1) - supported = true; - } - - wl1271_debug(DEBUG_PROBE, - "PG Ver major = %d minor = %d, MAC %s present", - major, minor, supported ? "is" : "is not"); - - return supported; -} - -static void wl12xx_derive_mac_addresses(struct wl1271 *wl, - u32 oui, u32 nic, int n) -{ - int i; - - wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x, n %d", - oui, nic, n); - - if (nic + n - 1 > 0xffffff) - wl1271_warning("NIC part of the MAC address wraps around!"); - - for (i = 0; i < n; i++) { - wl->addresses[i].addr[0] = (u8)(oui >> 16); - wl->addresses[i].addr[1] = (u8)(oui >> 8); - wl->addresses[i].addr[2] = (u8) oui; - wl->addresses[i].addr[3] = (u8)(nic >> 16); - wl->addresses[i].addr[4] = (u8)(nic >> 8); - wl->addresses[i].addr[5] = (u8) nic; - nic++; - } - - wl->hw->wiphy->n_addresses = n; - wl->hw->wiphy->addresses = wl->addresses; -} - -static void wl12xx_get_fuse_mac(struct wl1271 *wl) -{ - u32 mac1, mac2; - - wl1271_set_partition(wl, &wl12xx_part_table[PART_DRPW]); - - mac1 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1); - mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2); - - /* these are the two parts of the BD_ADDR */ - wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) + - ((mac1 & 0xff000000) >> 24); - wl->fuse_nic_addr = mac1 & 0xffffff; - - wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]); -} - -static int wl12xx_get_hw_info(struct wl1271 *wl) -{ - int ret; - u32 die_info; - - ret = wl12xx_set_power_on(wl); - if (ret < 0) - goto out; - - wl->chip.id = wl1271_read32(wl, CHIP_ID_B); - - if (wl->chip.id == CHIP_ID_1283_PG20) - die_info = wl1271_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1); - else - die_info = wl1271_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1); - - wl->hw_pg_ver = (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET; - - if (!wl12xx_mac_in_fuse(wl)) { - wl->fuse_oui_addr = 0; - wl->fuse_nic_addr = 0; - } else { - wl12xx_get_fuse_mac(wl); - } - - wl1271_power_off(wl); -out: - return ret; -} - -static int wl1271_register_hw(struct wl1271 *wl) -{ - int ret; - u32 oui_addr = 0, nic_addr = 0; - - if (wl->mac80211_registered) - return 0; - - ret = wl12xx_get_hw_info(wl); - if (ret < 0) { - wl1271_error("couldn't get hw info"); - goto out; - } - - ret = wl1271_fetch_nvs(wl); - if (ret == 0) { - /* NOTE: The wl->nvs->nvs element must be first, in - * order to simplify the casting, we assume it is at - * the beginning of the wl->nvs structure. - */ - u8 *nvs_ptr = (u8 *)wl->nvs; - - oui_addr = - (nvs_ptr[11] << 16) + (nvs_ptr[10] << 8) + nvs_ptr[6]; - nic_addr = - (nvs_ptr[5] << 16) + (nvs_ptr[4] << 8) + nvs_ptr[3]; - } - - /* if the MAC address is zeroed in the NVS derive from fuse */ - if (oui_addr == 0 && nic_addr == 0) { - oui_addr = wl->fuse_oui_addr; - /* fuse has the BD_ADDR, the WLAN addresses are the next two */ - nic_addr = wl->fuse_nic_addr + 1; - } - - wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr, 2); - - ret = ieee80211_register_hw(wl->hw); - if (ret < 0) { - wl1271_error("unable to register mac80211 hw: %d", ret); - goto out; - } - - wl->mac80211_registered = true; - - wl1271_debugfs_init(wl); - - wl1271_notice("loaded"); - -out: - return ret; -} - -static void wl1271_unregister_hw(struct wl1271 *wl) -{ - if (wl->plt) - wl1271_plt_stop(wl); - - ieee80211_unregister_hw(wl->hw); - wl->mac80211_registered = false; - -} - -static int wl1271_init_ieee80211(struct wl1271 *wl) -{ - static const u32 cipher_suites[] = { - WLAN_CIPHER_SUITE_WEP40, - WLAN_CIPHER_SUITE_WEP104, - WLAN_CIPHER_SUITE_TKIP, - WLAN_CIPHER_SUITE_CCMP, - WL1271_CIPHER_SUITE_GEM, - }; - - /* The tx descriptor buffer and the TKIP space. */ - wl->hw->extra_tx_headroom = WL1271_EXTRA_SPACE_TKIP + - sizeof(struct wl1271_tx_hw_descr); - - /* unit us */ - /* FIXME: find a proper value */ - wl->hw->channel_change_time = 10000; - wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval; - - wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_SUPPORTS_DYNAMIC_PS | - IEEE80211_HW_SUPPORTS_UAPSD | - IEEE80211_HW_HAS_RATE_CONTROL | - IEEE80211_HW_CONNECTION_MONITOR | - IEEE80211_HW_REPORTS_TX_ACK_STATUS | - IEEE80211_HW_SPECTRUM_MGMT | - IEEE80211_HW_AP_LINK_PS | - IEEE80211_HW_AMPDU_AGGREGATION | - IEEE80211_HW_TX_AMPDU_SETUP_IN_HW | - IEEE80211_HW_SCAN_WHILE_IDLE; - - wl->hw->wiphy->cipher_suites = cipher_suites; - wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); - - wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); - wl->hw->wiphy->max_scan_ssids = 1; - wl->hw->wiphy->max_sched_scan_ssids = 16; - wl->hw->wiphy->max_match_sets = 16; - /* - * Maximum length of elements in scanning probe request templates - * should be the maximum length possible for a template, without - * the IEEE80211 header of the template - */ - wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE - - sizeof(struct ieee80211_header); - - wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE - - sizeof(struct ieee80211_header); - - wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; - - /* make sure all our channels fit in the scanned_ch bitmask */ - BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) + - ARRAY_SIZE(wl1271_channels_5ghz) > - WL1271_MAX_CHANNELS); - /* - * We keep local copies of the band structs because we need to - * modify them on a per-device basis. - */ - memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz, - sizeof(wl1271_band_2ghz)); - memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz, - sizeof(wl1271_band_5ghz)); - - wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &wl->bands[IEEE80211_BAND_2GHZ]; - wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &wl->bands[IEEE80211_BAND_5GHZ]; - - wl->hw->queues = 4; - wl->hw->max_rates = 1; - - wl->hw->wiphy->reg_notifier = wl1271_reg_notify; - - /* the FW answers probe-requests in AP-mode */ - wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; - wl->hw->wiphy->probe_resp_offload = - NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | - NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | - NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; - - SET_IEEE80211_DEV(wl->hw, wl->dev); - - wl->hw->sta_data_size = sizeof(struct wl1271_station); - wl->hw->vif_data_size = sizeof(struct wl12xx_vif); - - wl->hw->max_rx_aggregation_subframes = 8; - - return 0; -} - -#define WL1271_DEFAULT_CHANNEL 0 - -static struct ieee80211_hw *wl1271_alloc_hw(void) -{ - struct ieee80211_hw *hw; - struct wl1271 *wl; - int i, j, ret; - unsigned int order; - - BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS); - - hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); - if (!hw) { - wl1271_error("could not alloc ieee80211_hw"); - ret = -ENOMEM; - goto err_hw_alloc; - } - - wl = hw->priv; - memset(wl, 0, sizeof(*wl)); - - INIT_LIST_HEAD(&wl->wlvif_list); - - wl->hw = hw; - - for (i = 0; i < NUM_TX_QUEUES; i++) - for (j = 0; j < WL12XX_MAX_LINKS; j++) - skb_queue_head_init(&wl->links[j].tx_queue[i]); - - skb_queue_head_init(&wl->deferred_rx_queue); - skb_queue_head_init(&wl->deferred_tx_queue); - - INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work); - INIT_WORK(&wl->netstack_work, wl1271_netstack_work); - INIT_WORK(&wl->tx_work, wl1271_tx_work); - INIT_WORK(&wl->recovery_work, wl1271_recovery_work); - INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work); - INIT_DELAYED_WORK(&wl->tx_watchdog_work, wl12xx_tx_watchdog_work); - - wl->freezable_wq = create_freezable_workqueue("wl12xx_wq"); - if (!wl->freezable_wq) { - ret = -ENOMEM; - goto err_hw; - } - - wl->channel = WL1271_DEFAULT_CHANNEL; - wl->rx_counter = 0; - wl->power_level = WL1271_DEFAULT_POWER_LEVEL; - wl->band = IEEE80211_BAND_2GHZ; - wl->flags = 0; - wl->sg_enabled = true; - wl->hw_pg_ver = -1; - wl->ap_ps_map = 0; - wl->ap_fw_ps_map = 0; - wl->quirks = 0; - wl->platform_quirks = 0; - wl->sched_scanning = false; - wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; - wl->system_hlid = WL12XX_SYSTEM_HLID; - wl->active_sta_count = 0; - wl->fwlog_size = 0; - init_waitqueue_head(&wl->fwlog_waitq); - - /* The system link is always allocated */ - __set_bit(WL12XX_SYSTEM_HLID, wl->links_map); - - memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); - for (i = 0; i < ACX_TX_DESCRIPTORS; i++) - wl->tx_frames[i] = NULL; - - spin_lock_init(&wl->wl_lock); - - wl->state = WL1271_STATE_OFF; - wl->fw_type = WL12XX_FW_TYPE_NONE; - mutex_init(&wl->mutex); - - /* Apply default driver configuration. */ - wl1271_conf_init(wl); - - order = get_order(WL1271_AGGR_BUFFER_SIZE); - wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order); - if (!wl->aggr_buf) { - ret = -ENOMEM; - goto err_wq; - } - - wl->dummy_packet = wl12xx_alloc_dummy_packet(wl); - if (!wl->dummy_packet) { - ret = -ENOMEM; - goto err_aggr; - } - - /* Allocate one page for the FW log */ - wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL); - if (!wl->fwlog) { - ret = -ENOMEM; - goto err_dummy_packet; - } - - return hw; - -err_dummy_packet: - dev_kfree_skb(wl->dummy_packet); - -err_aggr: - free_pages((unsigned long)wl->aggr_buf, order); - -err_wq: - destroy_workqueue(wl->freezable_wq); - -err_hw: - wl1271_debugfs_exit(wl); - ieee80211_free_hw(hw); - -err_hw_alloc: - - return ERR_PTR(ret); -} - -static int wl1271_free_hw(struct wl1271 *wl) -{ - /* Unblock any fwlog readers */ - mutex_lock(&wl->mutex); - wl->fwlog_size = -1; - wake_up_interruptible_all(&wl->fwlog_waitq); - mutex_unlock(&wl->mutex); - - device_remove_bin_file(wl->dev, &fwlog_attr); - - device_remove_file(wl->dev, &dev_attr_hw_pg_ver); - - device_remove_file(wl->dev, &dev_attr_bt_coex_state); - free_page((unsigned long)wl->fwlog); - dev_kfree_skb(wl->dummy_packet); - free_pages((unsigned long)wl->aggr_buf, - get_order(WL1271_AGGR_BUFFER_SIZE)); - - wl1271_debugfs_exit(wl); - - vfree(wl->fw); - wl->fw = NULL; - wl->fw_type = WL12XX_FW_TYPE_NONE; - kfree(wl->nvs); - wl->nvs = NULL; - - kfree(wl->fw_status); - kfree(wl->tx_res_if); - destroy_workqueue(wl->freezable_wq); - - ieee80211_free_hw(wl->hw); - - return 0; -} - -static irqreturn_t wl12xx_hardirq(int irq, void *cookie) -{ - struct wl1271 *wl = cookie; - unsigned long flags; - - wl1271_debug(DEBUG_IRQ, "IRQ"); - - /* complete the ELP completion */ - spin_lock_irqsave(&wl->wl_lock, flags); - set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); - if (wl->elp_compl) { - complete(wl->elp_compl); - wl->elp_compl = NULL; - } - - if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) { - /* don't enqueue a work right now. mark it as pending */ - set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags); - wl1271_debug(DEBUG_IRQ, "should not enqueue work"); - disable_irq_nosync(wl->irq); - pm_wakeup_event(wl->dev, 0); - spin_unlock_irqrestore(&wl->wl_lock, flags); - return IRQ_HANDLED; - } - spin_unlock_irqrestore(&wl->wl_lock, flags); - - return IRQ_WAKE_THREAD; -} - -static int __devinit wl12xx_probe(struct platform_device *pdev) -{ - struct wl12xx_platform_data *pdata = pdev->dev.platform_data; - struct ieee80211_hw *hw; - struct wl1271 *wl; - unsigned long irqflags; - int ret = -ENODEV; - - hw = wl1271_alloc_hw(); - if (IS_ERR(hw)) { - wl1271_error("can't allocate hw"); - ret = PTR_ERR(hw); - goto out; - } - - wl = hw->priv; - wl->irq = platform_get_irq(pdev, 0); - wl->ref_clock = pdata->board_ref_clock; - wl->tcxo_clock = pdata->board_tcxo_clock; - wl->platform_quirks = pdata->platform_quirks; - wl->set_power = pdata->set_power; - wl->dev = &pdev->dev; - wl->if_ops = pdata->ops; - - platform_set_drvdata(pdev, wl); - - if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) - irqflags = IRQF_TRIGGER_RISING; - else - irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; - - ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq, - irqflags, - pdev->name, wl); - if (ret < 0) { - wl1271_error("request_irq() failed: %d", ret); - goto out_free_hw; - } - - ret = enable_irq_wake(wl->irq); - if (!ret) { - wl->irq_wake_enabled = true; - device_init_wakeup(wl->dev, 1); - if (pdata->pwr_in_suspend) - hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY; - - } - disable_irq(wl->irq); - - ret = wl1271_init_ieee80211(wl); - if (ret) - goto out_irq; - - ret = wl1271_register_hw(wl); - if (ret) - goto out_irq; - - /* Create sysfs file to control bt coex state */ - ret = device_create_file(wl->dev, &dev_attr_bt_coex_state); - if (ret < 0) { - wl1271_error("failed to create sysfs file bt_coex_state"); - goto out_irq; - } - - /* Create sysfs file to get HW PG version */ - ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver); - if (ret < 0) { - wl1271_error("failed to create sysfs file hw_pg_ver"); - goto out_bt_coex_state; - } - - /* Create sysfs file for the FW log */ - ret = device_create_bin_file(wl->dev, &fwlog_attr); - if (ret < 0) { - wl1271_error("failed to create sysfs file fwlog"); - goto out_hw_pg_ver; - } - - return 0; - -out_hw_pg_ver: - device_remove_file(wl->dev, &dev_attr_hw_pg_ver); - -out_bt_coex_state: - device_remove_file(wl->dev, &dev_attr_bt_coex_state); - -out_irq: - free_irq(wl->irq, wl); - -out_free_hw: - wl1271_free_hw(wl); - -out: - return ret; -} - -static int __devexit wl12xx_remove(struct platform_device *pdev) -{ - struct wl1271 *wl = platform_get_drvdata(pdev); - - if (wl->irq_wake_enabled) { - device_init_wakeup(wl->dev, 0); - disable_irq_wake(wl->irq); - } - wl1271_unregister_hw(wl); - free_irq(wl->irq, wl); - wl1271_free_hw(wl); - - return 0; -} - -static const struct platform_device_id wl12xx_id_table[] __devinitconst = { - { "wl12xx", 0 }, - { } /* Terminating Entry */ -}; -MODULE_DEVICE_TABLE(platform, wl12xx_id_table); - -static struct platform_driver wl12xx_driver = { - .probe = wl12xx_probe, - .remove = __devexit_p(wl12xx_remove), - .id_table = wl12xx_id_table, - .driver = { - .name = "wl12xx_driver", - .owner = THIS_MODULE, - } -}; - -static int __init wl12xx_init(void) -{ - return platform_driver_register(&wl12xx_driver); -} -module_init(wl12xx_init); - -static void __exit wl12xx_exit(void) -{ - platform_driver_unregister(&wl12xx_driver); -} -module_exit(wl12xx_exit); - -u32 wl12xx_debug_level = DEBUG_NONE; -EXPORT_SYMBOL_GPL(wl12xx_debug_level); -module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR); -MODULE_PARM_DESC(debug_level, "wl12xx debugging level"); - -module_param_named(fwlog, fwlog_param, charp, 0); -MODULE_PARM_DESC(fwlog, - "FW logger options: continuous, ondemand, dbgpins or disable"); - -module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR); -MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery"); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Luciano Coelho "); -MODULE_AUTHOR("Juuso Oikarinen "); diff --git a/trunk/drivers/net/wireless/wl12xx/reg.h b/trunk/drivers/net/wireless/wl12xx/reg.h deleted file mode 100644 index 340db324bc26..000000000000 --- a/trunk/drivers/net/wireless/wl12xx/reg.h +++ /dev/null @@ -1,555 +0,0 @@ -/* - * This file is part of wl12xx - * - * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __REG_H__ -#define __REG_H__ - -#include - -#define REGISTERS_BASE 0x00300000 -#define DRPW_BASE 0x00310000 - -#define REGISTERS_DOWN_SIZE 0x00008800 -#define REGISTERS_WORK_SIZE 0x0000b000 - -#define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC -#define FW_STATUS_ADDR (0x14FC0 + 0xA000) - -/* ELP register commands */ -#define ELPCTRL_WAKE_UP 0x1 -#define ELPCTRL_WAKE_UP_WLAN_READY 0x5 -#define ELPCTRL_SLEEP 0x0 -/* ELP WLAN_READY bit */ -#define ELPCTRL_WLAN_READY 0x2 - -/*=============================================== - Host Software Reset - 32bit RW - ------------------------------------------ - [31:1] Reserved - 0 SOFT_RESET Soft Reset - When this bit is set, - it holds the Wlan hardware in a soft reset state. - This reset disables all MAC and baseband processor - clocks except the CardBus/PCI interface clock. - It also initializes all MAC state machines except - the host interface. It does not reload the - contents of the EEPROM. When this bit is cleared - (not self-clearing), the Wlan hardware - exits the software reset state. -===============================================*/ -#define ACX_REG_SLV_SOFT_RESET (REGISTERS_BASE + 0x0000) - -#define WL1271_SLV_REG_DATA (REGISTERS_BASE + 0x0008) -#define WL1271_SLV_REG_ADATA (REGISTERS_BASE + 0x000c) -#define WL1271_SLV_MEM_DATA (REGISTERS_BASE + 0x0018) - -#define ACX_REG_INTERRUPT_TRIG (REGISTERS_BASE + 0x0474) -#define ACX_REG_INTERRUPT_TRIG_H (REGISTERS_BASE + 0x0478) - -/*============================================= - Host Interrupt Mask Register - 32bit (RW) - ------------------------------------------ - Setting a bit in this register masks the - corresponding interrupt to the host. - 0 - RX0 - Rx first dubble buffer Data Interrupt - 1 - TXD - Tx Data Interrupt - 2 - TXXFR - Tx Transfer Interrupt - 3 - RX1 - Rx second dubble buffer Data Interrupt - 4 - RXXFR - Rx Transfer Interrupt - 5 - EVENT_A - Event Mailbox interrupt - 6 - EVENT_B - Event Mailbox interrupt - 7 - WNONHST - Wake On Host Interrupt - 8 - TRACE_A - Debug Trace interrupt - 9 - TRACE_B - Debug Trace interrupt - 10 - CDCMP - Command Complete Interrupt - 11 - - 12 - - 13 - - 14 - ICOMP - Initialization Complete Interrupt - 16 - SG SE - Soft Gemini - Sense enable interrupt - 17 - SG SD - Soft Gemini - Sense disable interrupt - 18 - - - 19 - - - 20 - - - 21- - - Default: 0x0001 -*==============================================*/ -#define ACX_REG_INTERRUPT_MASK (REGISTERS_BASE + 0x04DC) - -/*============================================= - Host Interrupt Mask Set 16bit, (Write only) - ------------------------------------------ - Setting a bit in this register sets - the corresponding bin in ACX_HINT_MASK register - without effecting the mask - state of other bits (0 = no effect). -==============================================*/ -#define ACX_REG_HINT_MASK_SET (REGISTERS_BASE + 0x04E0) - -/*============================================= - Host Interrupt Mask Clear 16bit,(Write only) - ------------------------------------------ - Setting a bit in this register clears - the corresponding bin in ACX_HINT_MASK register - without effecting the mask - state of other bits (0 = no effect). -=============================================*/ -#define ACX_REG_HINT_MASK_CLR (REGISTERS_BASE + 0x04E4) - -/*============================================= - Host Interrupt Status Nondestructive Read - 16bit,(Read only) - ------------------------------------------ - The host can read this register to determine - which interrupts are active. - Reading this register doesn't - effect its content. -=============================================*/ -#define ACX_REG_INTERRUPT_NO_CLEAR (REGISTERS_BASE + 0x04E8) - -/*============================================= - Host Interrupt Status Clear on Read Register - 16bit,(Read only) - ------------------------------------------ - The host can read this register to determine - which interrupts are active. - Reading this register clears it, - thus making all interrupts inactive. -==============================================*/ -#define ACX_REG_INTERRUPT_CLEAR (REGISTERS_BASE + 0x04F8) - -/*============================================= - Host Interrupt Acknowledge Register - 16bit,(Write only) - ------------------------------------------ - The host can set individual bits in this - register to clear (acknowledge) the corresp. - interrupt status bits in the HINT_STS_CLR and - HINT_STS_ND registers, thus making the - assotiated interrupt inactive. (0-no effect) -==============================================*/ -#define ACX_REG_INTERRUPT_ACK (REGISTERS_BASE + 0x04F0) - -#define RX_DRIVER_COUNTER_ADDRESS (REGISTERS_BASE + 0x0538) - -/* Device Configuration registers*/ -#define SOR_CFG (REGISTERS_BASE + 0x0800) - -/* Embedded ARM CPU Control */ - -/*=============================================== - Halt eCPU - 32bit RW - ------------------------------------------ - 0 HALT_ECPU Halt Embedded CPU - This bit is the - compliment of bit 1 (MDATA2) in the SOR_CFG register. - During a hardware reset, this bit holds - the inverse of MDATA2. - When downloading firmware from the host, - set this bit (pull down MDATA2). - The host clears this bit after downloading the firmware into - zero-wait-state SSRAM. - When loading firmware from Flash, clear this bit (pull up MDATA2) - so that the eCPU can run the bootloader code in Flash - HALT_ECPU eCPU State - -------------------- - 1 halt eCPU - 0 enable eCPU - ===============================================*/ -#define ACX_REG_ECPU_CONTROL (REGISTERS_BASE + 0x0804) - -#define HI_CFG (REGISTERS_BASE + 0x0808) - -/*=============================================== - EEPROM Burst Read Start - 32bit RW - ------------------------------------------ - [31:1] Reserved - 0 ACX_EE_START - EEPROM Burst Read Start 0 - Setting this bit starts a burst read from - the external EEPROM. - If this bit is set (after reset) before an EEPROM read/write, - the burst read starts at EEPROM address 0. - Otherwise, it starts at the address - following the address of the previous access. - TheWlan hardware hardware clears this bit automatically. - - Default: 0x00000000 -*================================================*/ -#define ACX_REG_EE_START (REGISTERS_BASE + 0x080C) - -#define OCP_POR_CTR (REGISTERS_BASE + 0x09B4) -#define OCP_DATA_WRITE (REGISTERS_BASE + 0x09B8) -#define OCP_DATA_READ (REGISTERS_BASE + 0x09BC) -#define OCP_CMD (REGISTERS_BASE + 0x09C0) - -#define WL1271_HOST_WR_ACCESS (REGISTERS_BASE + 0x09F8) - -#define CHIP_ID_B (REGISTERS_BASE + 0x5674) - -#define CHIP_ID_1271_PG10 (0x4030101) -#define CHIP_ID_1271_PG20 (0x4030111) -#define CHIP_ID_1283_PG10 (0x05030101) -#define CHIP_ID_1283_PG20 (0x05030111) - -#define ENABLE (REGISTERS_BASE + 0x5450) - -/* Power Management registers */ -#define ELP_CFG_MODE (REGISTERS_BASE + 0x5804) -#define ELP_CMD (REGISTERS_BASE + 0x5808) -#define PLL_CAL_TIME (REGISTERS_BASE + 0x5810) -#define CLK_REQ_TIME (REGISTERS_BASE + 0x5814) -#define CLK_BUF_TIME (REGISTERS_BASE + 0x5818) - -#define CFG_PLL_SYNC_CNT (REGISTERS_BASE + 0x5820) - -/* Scratch Pad registers*/ -#define SCR_PAD0 (REGISTERS_BASE + 0x5608) -#define SCR_PAD1 (REGISTERS_BASE + 0x560C) -#define SCR_PAD2 (REGISTERS_BASE + 0x5610) -#define SCR_PAD3 (REGISTERS_BASE + 0x5614) -#define SCR_PAD4 (REGISTERS_BASE + 0x5618) -#define SCR_PAD4_SET (REGISTERS_BASE + 0x561C) -#define SCR_PAD4_CLR (REGISTERS_BASE + 0x5620) -#define SCR_PAD5 (REGISTERS_BASE + 0x5624) -#define SCR_PAD5_SET (REGISTERS_BASE + 0x5628) -#define SCR_PAD5_CLR (REGISTERS_BASE + 0x562C) -#define SCR_PAD6 (REGISTERS_BASE + 0x5630) -#define SCR_PAD7 (REGISTERS_BASE + 0x5634) -#define SCR_PAD8 (REGISTERS_BASE + 0x5638) -#define SCR_PAD9 (REGISTERS_BASE + 0x563C) - -/* Spare registers*/ -#define SPARE_A1 (REGISTERS_BASE + 0x0994) -#define SPARE_A2 (REGISTERS_BASE + 0x0998) -#define SPARE_A3 (REGISTERS_BASE + 0x099C) -#define SPARE_A4 (REGISTERS_BASE + 0x09A0) -#define SPARE_A5 (REGISTERS_BASE + 0x09A4) -#define SPARE_A6 (REGISTERS_BASE + 0x09A8) -#define SPARE_A7 (REGISTERS_BASE + 0x09AC) -#define SPARE_A8 (REGISTERS_BASE + 0x09B0) -#define SPARE_B1 (REGISTERS_BASE + 0x5420) -#define SPARE_B2 (REGISTERS_BASE + 0x5424) -#define SPARE_B3 (REGISTERS_BASE + 0x5428) -#define SPARE_B4 (REGISTERS_BASE + 0x542C) -#define SPARE_B5 (REGISTERS_BASE + 0x5430) -#define SPARE_B6 (REGISTERS_BASE + 0x5434) -#define SPARE_B7 (REGISTERS_BASE + 0x5438) -#define SPARE_B8 (REGISTERS_BASE + 0x543C) - -#define PLL_PARAMETERS (REGISTERS_BASE + 0x6040) -#define WU_COUNTER_PAUSE (REGISTERS_BASE + 0x6008) -#define WELP_ARM_COMMAND (REGISTERS_BASE + 0x6100) -#define DRPW_SCRATCH_START (DRPW_BASE + 0x002C) - - -#define ACX_SLV_SOFT_RESET_BIT BIT(1) -#define ACX_REG_EEPROM_START_BIT BIT(1) - -/* Command/Information Mailbox Pointers */ - -/*=============================================== - Command Mailbox Pointer - 32bit RW - ------------------------------------------ - This register holds the start address of - the command mailbox located in the Wlan hardware memory. - The host must read this pointer after a reset to - find the location of the command mailbox. - The Wlan hardware initializes the command mailbox - pointer with the default address of the command mailbox. - The command mailbox pointer is not valid until after - the host receives the Init Complete interrupt from - the Wlan hardware. - ===============================================*/ -#define REG_COMMAND_MAILBOX_PTR (SCR_PAD0) - -/*=============================================== - Information Mailbox Pointer - 32bit RW - ------------------------------------------ - This register holds the start address of - the information mailbox located in the Wlan hardware memory. - The host must read this pointer after a reset to find - the location of the information mailbox. - The Wlan hardware initializes the information mailbox pointer - with the default address of the information mailbox. - The information mailbox pointer is not valid - until after the host receives the Init Complete interrupt from - the Wlan hardware. - ===============================================*/ -#define REG_EVENT_MAILBOX_PTR (SCR_PAD1) - -/*=============================================== - EEPROM Read/Write Request 32bit RW - ------------------------------------------ - 1 EE_READ - EEPROM Read Request 1 - Setting this bit - loads a single byte of data into the EE_DATA - register from the EEPROM location specified in - the EE_ADDR register. - The Wlan hardware hardware clears this bit automatically. - EE_DATA is valid when this bit is cleared. - - 0 EE_WRITE - EEPROM Write Request - Setting this bit - writes a single byte of data from the EE_DATA register into the - EEPROM location specified in the EE_ADDR register. - The Wlan hardware hardware clears this bit automatically. -*===============================================*/ -#define ACX_EE_CTL_REG EE_CTL -#define EE_WRITE 0x00000001ul -#define EE_READ 0x00000002ul - -/*=============================================== - EEPROM Address - 32bit RW - ------------------------------------------ - This register specifies the address - within the EEPROM from/to which to read/write data. - ===============================================*/ -#define ACX_EE_ADDR_REG EE_ADDR - -/*=============================================== - EEPROM Data - 32bit RW - ------------------------------------------ - This register either holds the read 8 bits of - data from the EEPROM or the write data - to be written to the EEPROM. - ===============================================*/ -#define ACX_EE_DATA_REG EE_DATA - -/*=============================================== - EEPROM Base Address - 32bit RW - ------------------------------------------ - This register holds the upper nine bits - [23:15] of the 24-bit Wlan hardware memory - address for burst reads from EEPROM accesses. - The EEPROM provides the lower 15 bits of this address. - The MSB of the address from the EEPROM is ignored. - ===============================================*/ -#define ACX_EE_CFG EE_CFG - -/*=============================================== - GPIO Output Values -32bit, RW - ------------------------------------------ - [31:16] Reserved - [15: 0] Specify the output values (at the output driver inputs) for - GPIO[15:0], respectively. - ===============================================*/ -#define ACX_GPIO_OUT_REG GPIO_OUT -#define ACX_MAX_GPIO_LINES 15 - -/*=============================================== - Contention window -32bit, RW - ------------------------------------------ - [31:26] Reserved - [25:16] Max (0x3ff) - [15:07] Reserved - [06:00] Current contention window value - default is 0x1F - ===============================================*/ -#define ACX_CONT_WIND_CFG_REG CONT_WIND_CFG -#define ACX_CONT_WIND_MIN_MASK 0x0000007f -#define ACX_CONT_WIND_MAX 0x03ff0000 - -/*=============================================== - HI_CFG Interface Configuration Register Values - ------------------------------------------ - ===============================================*/ -#define HI_CFG_UART_ENABLE 0x00000004 -#define HI_CFG_RST232_ENABLE 0x00000008 -#define HI_CFG_CLOCK_REQ_SELECT 0x00000010 -#define HI_CFG_HOST_INT_ENABLE 0x00000020 -#define HI_CFG_VLYNQ_OUTPUT_ENABLE 0x00000040 -#define HI_CFG_HOST_INT_ACTIVE_LOW 0x00000080 -#define HI_CFG_UART_TX_OUT_GPIO_15 0x00000100 -#define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200 -#define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400 - -#define HI_CFG_DEF_VAL \ - (HI_CFG_UART_ENABLE | \ - HI_CFG_RST232_ENABLE | \ - HI_CFG_CLOCK_REQ_SELECT | \ - HI_CFG_HOST_INT_ENABLE) - -#define REF_FREQ_19_2 0 -#define REF_FREQ_26_0 1 -#define REF_FREQ_38_4 2 -#define REF_FREQ_40_0 3 -#define REF_FREQ_33_6 4 -#define REF_FREQ_NUM 5 - -#define LUT_PARAM_INTEGER_DIVIDER 0 -#define LUT_PARAM_FRACTIONAL_DIVIDER 1 -#define LUT_PARAM_ATTN_BB 2 -#define LUT_PARAM_ALPHA_BB 3 -#define LUT_PARAM_STOP_TIME_BB 4 -#define LUT_PARAM_BB_PLL_LOOP_FILTER 5 -#define LUT_PARAM_NUM 6 - -#define ACX_EEPROMLESS_IND_REG (SCR_PAD4) -#define USE_EEPROM 0 -#define SOFT_RESET_MAX_TIME 1000000 -#define SOFT_RESET_STALL_TIME 1000 -#define NVS_DATA_BUNDARY_ALIGNMENT 4 - - -/* Firmware image load chunk size */ -#define CHUNK_SIZE 16384 - -/* Firmware image header size */ -#define FW_HDR_SIZE 8 - -#define ECPU_CONTROL_HALT 0x00000101 - - -/****************************************************************************** - - CHANNELS, BAND & REG DOMAINS definitions - -******************************************************************************/ - - -enum { - RADIO_BAND_2_4GHZ = 0, /* 2.4 Ghz band */ - RADIO_BAND_5GHZ = 1, /* 5 Ghz band */ - RADIO_BAND_JAPAN_4_9_GHZ = 2, - DEFAULT_BAND = RADIO_BAND_2_4GHZ, - INVALID_BAND = 0xFE, - MAX_RADIO_BANDS = 0xFF -}; - -#define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */ -#define OFDM_RATE_BIT BIT(6) -#define PBCC_RATE_BIT BIT(7) - -enum { - CCK_LONG = 0, - CCK_SHORT = SHORT_PREAMBLE_BIT, - PBCC_LONG = PBCC_RATE_BIT, - PBCC_SHORT = PBCC_RATE_BIT | SHORT_PREAMBLE_BIT, - OFDM = OFDM_RATE_BIT -}; - -/****************************************************************************** - -Transmit-Descriptor RATE-SET field definitions... - -Define a new "Rate-Set" for TX path that incorporates the -Rate & Modulation info into a single 16-bit field. - -TxdRateSet_t: -b15 - Indicates Preamble type (1=SHORT, 0=LONG). - Notes: - Must be LONG (0) for 1Mbps rate. - Does not apply (set to 0) for RevG-OFDM rates. -b14 - Indicates PBCC encoding (1=PBCC, 0=not). - Notes: - Does not apply (set to 0) for rates 1 and 2 Mbps. - Does not apply (set to 0) for RevG-OFDM rates. -b13 - Unused (set to 0). -b12-b0 - Supported Rate indicator bits as defined below. - -******************************************************************************/ - - -/************************************************************************* - - Interrupt Trigger Register (Host -> WiLink) - -**************************************************************************/ - -/* Hardware to Embedded CPU Interrupts - first 32-bit register set */ - -/* - * Host Command Interrupt. Setting this bit masks - * the interrupt that the host issues to inform - * the FW that it has sent a command - * to the Wlan hardware Command Mailbox. - */ -#define INTR_TRIG_CMD BIT(0) - -/* - * Host Event Acknowlegde Interrupt. The host - * sets this bit to acknowledge that it received - * the unsolicited information from the event - * mailbox. - */ -#define INTR_TRIG_EVENT_ACK BIT(1) - -/* - * The host sets this bit to inform the Wlan - * FW that a TX packet is in the XFER - * Buffer #0. - */ -#define INTR_TRIG_TX_PROC0 BIT(2) - -/* - * The host sets this bit to inform the FW - * that it read a packet from RX XFER - * Buffer #0. - */ -#define INTR_TRIG_RX_PROC0 BIT(3) - -#define INTR_TRIG_DEBUG_ACK BIT(4) - -#define INTR_TRIG_STATE_CHANGED BIT(5) - - -/* Hardware to Embedded CPU Interrupts - second 32-bit register set */ - -/* - * The host sets this bit to inform the FW - * that it read a packet from RX XFER - * Buffer #1. - */ -#define INTR_TRIG_RX_PROC1 BIT(17) - -/* - * The host sets this bit to inform the Wlan - * hardware that a TX packet is in the XFER - * Buffer #1. - */ -#define INTR_TRIG_TX_PROC1 BIT(18) - -#define WL127X_REG_FUSE_DATA_2_1 0x050a -#define WL128X_REG_FUSE_DATA_2_1 0x2152 -#define PG_VER_MASK 0x3c -#define PG_VER_OFFSET 2 - -#define WL127X_PG_MAJOR_VER_MASK 0x3 -#define WL127X_PG_MAJOR_VER_OFFSET 0x0 -#define WL127X_PG_MINOR_VER_MASK 0xc -#define WL127X_PG_MINOR_VER_OFFSET 0x2 - -#define WL128X_PG_MAJOR_VER_MASK 0xc -#define WL128X_PG_MAJOR_VER_OFFSET 0x2 -#define WL128X_PG_MINOR_VER_MASK 0x3 -#define WL128X_PG_MINOR_VER_OFFSET 0x0 - -#define WL127X_PG_GET_MAJOR(pg_ver) ((pg_ver & WL127X_PG_MAJOR_VER_MASK) >> \ - WL127X_PG_MAJOR_VER_OFFSET) -#define WL127X_PG_GET_MINOR(pg_ver) ((pg_ver & WL127X_PG_MINOR_VER_MASK) >> \ - WL127X_PG_MINOR_VER_OFFSET) -#define WL128X_PG_GET_MAJOR(pg_ver) ((pg_ver & WL128X_PG_MAJOR_VER_MASK) >> \ - WL128X_PG_MAJOR_VER_OFFSET) -#define WL128X_PG_GET_MINOR(pg_ver) ((pg_ver & WL128X_PG_MINOR_VER_MASK) >> \ - WL128X_PG_MINOR_VER_OFFSET) - -#define WL12XX_REG_FUSE_BD_ADDR_1 0x00310eb4 -#define WL12XX_REG_FUSE_BD_ADDR_2 0x00310eb8 - -#endif diff --git a/trunk/drivers/net/wireless/wl12xx/rx.c b/trunk/drivers/net/wireless/wl12xx/rx.c deleted file mode 100644 index cfa6071704c5..000000000000 --- a/trunk/drivers/net/wireless/wl12xx/rx.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include - -#include "wl12xx.h" -#include "debug.h" -#include "acx.h" -#include "reg.h" -#include "rx.h" -#include "tx.h" -#include "io.h" - -static u8 wl12xx_rx_get_mem_block(struct wl12xx_fw_status *status, - u32 drv_rx_counter) -{ - return le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) & - RX_MEM_BLOCK_MASK; -} - -static u32 wl12xx_rx_get_buf_size(struct wl12xx_fw_status *status, - u32 drv_rx_counter) -{ - return (le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) & - RX_BUF_SIZE_MASK) >> RX_BUF_SIZE_SHIFT_DIV; -} - -static bool wl12xx_rx_get_unaligned(struct wl12xx_fw_status *status, - u32 drv_rx_counter) -{ - /* Convert the value to bool */ - return !!(le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) & - RX_BUF_UNALIGNED_PAYLOAD); -} - -static void wl1271_rx_status(struct wl1271 *wl, - struct wl1271_rx_descriptor *desc, - struct ieee80211_rx_status *status, - u8 beacon) -{ - memset(status, 0, sizeof(struct ieee80211_rx_status)); - - if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG) - status->band = IEEE80211_BAND_2GHZ; - else - status->band = IEEE80211_BAND_5GHZ; - - status->rate_idx = wl1271_rate_to_idx(desc->rate, status->band); - - /* 11n support */ - if (desc->rate <= CONF_HW_RXTX_RATE_MCS0) - status->flag |= RX_FLAG_HT; - - status->signal = desc->rssi; - - /* - * FIXME: In wl1251, the SNR should be divided by two. In wl1271 we - * need to divide by two for now, but TI has been discussing about - * changing it. This needs to be rechecked. - */ - wl->noise = desc->rssi - (desc->snr >> 1); - - status->freq = ieee80211_channel_to_frequency(desc->channel, - status->band); - - if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) { - u8 desc_err_code = desc->status & WL1271_RX_DESC_STATUS_MASK; - - status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED | - RX_FLAG_DECRYPTED; - - if (unlikely(desc_err_code == WL1271_RX_DESC_MIC_FAIL)) { - status->flag |= RX_FLAG_MMIC_ERROR; - wl1271_warning("Michael MIC error"); - } - } -} - -static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, - bool unaligned, u8 *hlid) -{ - struct wl1271_rx_descriptor *desc; - struct sk_buff *skb; - struct ieee80211_hdr *hdr; - u8 *buf; - u8 beacon = 0; - u8 is_data = 0; - u8 reserved = unaligned ? NET_IP_ALIGN : 0; - u16 seq_num; - - /* - * In PLT mode we seem to get frames and mac80211 warns about them, - * workaround this by not retrieving them at all. - */ - if (unlikely(wl->plt)) - return -EINVAL; - - /* the data read starts with the descriptor */ - desc = (struct wl1271_rx_descriptor *) data; - - if (desc->packet_class == WL12XX_RX_CLASS_LOGGER) { - size_t len = length - sizeof(*desc); - wl12xx_copy_fwlog(wl, data + sizeof(*desc), len); - wake_up_interruptible(&wl->fwlog_waitq); - return 0; - } - - switch (desc->status & WL1271_RX_DESC_STATUS_MASK) { - /* discard corrupted packets */ - case WL1271_RX_DESC_DRIVER_RX_Q_FAIL: - case WL1271_RX_DESC_DECRYPT_FAIL: - wl1271_warning("corrupted packet in RX with status: 0x%x", - desc->status & WL1271_RX_DESC_STATUS_MASK); - return -EINVAL; - case WL1271_RX_DESC_SUCCESS: - case WL1271_RX_DESC_MIC_FAIL: - break; - default: - wl1271_error("invalid RX descriptor status: 0x%x", - desc->status & WL1271_RX_DESC_STATUS_MASK); - return -EINVAL; - } - - /* skb length not included rx descriptor */ - skb = __dev_alloc_skb(length + reserved - sizeof(*desc), GFP_KERNEL); - if (!skb) { - wl1271_error("Couldn't allocate RX frame"); - return -ENOMEM; - } - - /* reserve the unaligned payload(if any) */ - skb_reserve(skb, reserved); - - buf = skb_put(skb, length - sizeof(*desc)); - - /* - * Copy packets from aggregation buffer to the skbs without rx - * descriptor and with packet payload aligned care. In case of unaligned - * packets copy the packets in offset of 2 bytes guarantee IP header - * payload aligned to 4 bytes. - */ - memcpy(buf, data + sizeof(*desc), length - sizeof(*desc)); - *hlid = desc->hlid; - - hdr = (struct ieee80211_hdr *)skb->data; - if (ieee80211_is_beacon(hdr->frame_control)) - beacon = 1; - if (ieee80211_is_data_present(hdr->frame_control)) - is_data = 1; - - wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); - - seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; - wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d hlid %d", skb, - skb->len - desc->pad_len, - beacon ? "beacon" : "", - seq_num, *hlid); - - skb_trim(skb, skb->len - desc->pad_len); - - skb_queue_tail(&wl->deferred_rx_queue, skb); - queue_work(wl->freezable_wq, &wl->netstack_work); - - return is_data; -} - -void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status) -{ - struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map; - unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0}; - u32 buf_size; - u32 fw_rx_counter = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK; - u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK; - u32 rx_counter; - u32 mem_block; - u32 pkt_length; - u32 pkt_offset; - u8 hlid; - bool unaligned = false; - - while (drv_rx_counter != fw_rx_counter) { - buf_size = 0; - rx_counter = drv_rx_counter; - while (rx_counter != fw_rx_counter) { - pkt_length = wl12xx_rx_get_buf_size(status, rx_counter); - if (buf_size + pkt_length > WL1271_AGGR_BUFFER_SIZE) - break; - buf_size += pkt_length; - rx_counter++; - rx_counter &= NUM_RX_PKT_DESC_MOD_MASK; - } - - if (buf_size == 0) { - wl1271_warning("received empty data"); - break; - } - - if (wl->chip.id != CHIP_ID_1283_PG20) { - /* - * Choose the block we want to read - * For aggregated packets, only the first memory block - * should be retrieved. The FW takes care of the rest. - */ - mem_block = wl12xx_rx_get_mem_block(status, - drv_rx_counter); - - wl->rx_mem_pool_addr.addr = (mem_block << 8) + - le32_to_cpu(wl_mem_map->packet_memory_pool_start); - - wl->rx_mem_pool_addr.addr_extra = - wl->rx_mem_pool_addr.addr + 4; - - wl1271_write(wl, WL1271_SLV_REG_DATA, - &wl->rx_mem_pool_addr, - sizeof(wl->rx_mem_pool_addr), false); - } - - /* Read all available packets at once */ - wl1271_read(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, - buf_size, true); - - /* Split data into separate packets */ - pkt_offset = 0; - while (pkt_offset < buf_size) { - pkt_length = wl12xx_rx_get_buf_size(status, - drv_rx_counter); - - unaligned = wl12xx_rx_get_unaligned(status, - drv_rx_counter); - - /* - * the handle data call can only fail in memory-outage - * conditions, in that case the received frame will just - * be dropped. - */ - if (wl1271_rx_handle_data(wl, - wl->aggr_buf + pkt_offset, - pkt_length, unaligned, - &hlid) == 1) { - if (hlid < WL12XX_MAX_LINKS) - __set_bit(hlid, active_hlids); - else - WARN(1, - "hlid exceeded WL12XX_MAX_LINKS " - "(%d)\n", hlid); - } - - wl->rx_counter++; - drv_rx_counter++; - drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK; - pkt_offset += pkt_length; - } - } - - /* - * Write the driver's packet counter to the FW. This is only required - * for older hardware revisions - */ - if (wl->quirks & WL12XX_QUIRK_END_OF_TRANSACTION) - wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter); - - wl12xx_rearm_rx_streaming(wl, active_hlids); -} diff --git a/trunk/drivers/net/wireless/wl12xx/scan.c b/trunk/drivers/net/wireless/wl12xx/scan.c deleted file mode 100644 index fcba055ef196..000000000000 --- a/trunk/drivers/net/wireless/wl12xx/scan.c +++ /dev/null @@ -1,770 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2009-2010 Nokia Corporation - * - * Contact: Luciano Coelho - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include - -#include "wl12xx.h" -#include "debug.h" -#include "cmd.h" -#include "scan.h" -#include "acx.h" -#include "ps.h" -#include "tx.h" - -void wl1271_scan_complete_work(struct work_struct *work) -{ - struct delayed_work *dwork; - struct wl1271 *wl; - struct ieee80211_vif *vif; - struct wl12xx_vif *wlvif; - int ret; - - dwork = container_of(work, struct delayed_work, work); - wl = container_of(dwork, struct wl1271, scan_complete_work); - - wl1271_debug(DEBUG_SCAN, "Scanning complete"); - - mutex_lock(&wl->mutex); - - if (wl->state == WL1271_STATE_OFF) - goto out; - - if (wl->scan.state == WL1271_SCAN_STATE_IDLE) - goto out; - - vif = wl->scan_vif; - wlvif = wl12xx_vif_to_data(vif); - - /* - * Rearm the tx watchdog just before idling scan. This - * prevents just-finished scans from triggering the watchdog - */ - wl12xx_rearm_tx_watchdog_locked(wl); - - wl->scan.state = WL1271_SCAN_STATE_IDLE; - memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); - wl->scan.req = NULL; - wl->scan_vif = NULL; - - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { - /* restore hardware connection monitoring template */ - wl1271_cmd_build_ap_probe_req(wl, wlvif, wlvif->probereq); - } - - wl1271_ps_elp_sleep(wl); - - if (wl->scan.failed) { - wl1271_info("Scan completed due to error."); - wl12xx_queue_recovery_work(wl); - } - - ieee80211_scan_completed(wl->hw, false); - -out: - mutex_unlock(&wl->mutex); - -} - - -static int wl1271_get_scan_channels(struct wl1271 *wl, - struct cfg80211_scan_request *req, - struct basic_scan_channel_params *channels, - enum ieee80211_band band, bool passive) -{ - struct conf_scan_settings *c = &wl->conf.scan; - int i, j; - u32 flags; - - for (i = 0, j = 0; - i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS; - i++) { - flags = req->channels[i]->flags; - - if (!test_bit(i, wl->scan.scanned_ch) && - !(flags & IEEE80211_CHAN_DISABLED) && - (req->channels[i]->band == band) && - /* - * In passive scans, we scan all remaining - * channels, even if not marked as such. - * In active scans, we only scan channels not - * marked as passive. - */ - (passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) { - wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ", - req->channels[i]->band, - req->channels[i]->center_freq); - wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X", - req->channels[i]->hw_value, - req->channels[i]->flags); - wl1271_debug(DEBUG_SCAN, - "max_antenna_gain %d, max_power %d", - req->channels[i]->max_antenna_gain, - req->channels[i]->max_power); - wl1271_debug(DEBUG_SCAN, "beacon_found %d", - req->channels[i]->beacon_found); - - if (!passive) { - channels[j].min_duration = - cpu_to_le32(c->min_dwell_time_active); - channels[j].max_duration = - cpu_to_le32(c->max_dwell_time_active); - } else { - channels[j].min_duration = - cpu_to_le32(c->min_dwell_time_passive); - channels[j].max_duration = - cpu_to_le32(c->max_dwell_time_passive); - } - channels[j].early_termination = 0; - channels[j].tx_power_att = req->channels[i]->max_power; - channels[j].channel = req->channels[i]->hw_value; - - memset(&channels[j].bssid_lsb, 0xff, 4); - memset(&channels[j].bssid_msb, 0xff, 2); - - /* Mark the channels we already used */ - set_bit(i, wl->scan.scanned_ch); - - j++; - } - } - - return j; -} - -#define WL1271_NOTHING_TO_SCAN 1 - -static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif, - enum ieee80211_band band, - bool passive, u32 basic_rate) -{ - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - struct wl1271_cmd_scan *cmd; - struct wl1271_cmd_trigger_scan_to *trigger; - int ret; - u16 scan_options = 0; - - /* skip active scans if we don't have SSIDs */ - if (!passive && wl->scan.req->n_ssids == 0) - return WL1271_NOTHING_TO_SCAN; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); - if (!cmd || !trigger) { - ret = -ENOMEM; - goto out; - } - - if (wl->conf.scan.split_scan_timeout) - scan_options |= WL1271_SCAN_OPT_SPLIT_SCAN; - - if (passive) - scan_options |= WL1271_SCAN_OPT_PASSIVE; - - if (wlvif->bss_type == BSS_TYPE_AP_BSS || - test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) - cmd->params.role_id = wlvif->role_id; - else - cmd->params.role_id = wlvif->dev_role_id; - - if (WARN_ON(cmd->params.role_id == WL12XX_INVALID_ROLE_ID)) { - ret = -EINVAL; - goto out; - } - - cmd->params.scan_options = cpu_to_le16(scan_options); - - cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req, - cmd->channels, - band, passive); - if (cmd->params.n_ch == 0) { - ret = WL1271_NOTHING_TO_SCAN; - goto out; - } - - cmd->params.tx_rate = cpu_to_le32(basic_rate); - cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs; - cmd->params.tid_trigger = CONF_TX_AC_ANY_TID; - cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; - - if (band == IEEE80211_BAND_2GHZ) - cmd->params.band = WL1271_SCAN_BAND_2_4_GHZ; - else - cmd->params.band = WL1271_SCAN_BAND_5_GHZ; - - if (wl->scan.ssid_len && wl->scan.ssid) { - cmd->params.ssid_len = wl->scan.ssid_len; - memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len); - } - - memcpy(cmd->addr, vif->addr, ETH_ALEN); - - ret = wl12xx_cmd_build_probe_req(wl, wlvif, - cmd->params.role_id, band, - wl->scan.ssid, wl->scan.ssid_len, - wl->scan.req->ie, - wl->scan.req->ie_len); - if (ret < 0) { - wl1271_error("PROBE request template failed"); - goto out; - } - - trigger->timeout = cpu_to_le32(wl->conf.scan.split_scan_timeout); - ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, - sizeof(*trigger), 0); - if (ret < 0) { - wl1271_error("trigger scan to failed for hw scan"); - goto out; - } - - wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd)); - - ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("SCAN failed"); - goto out; - } - -out: - kfree(cmd); - kfree(trigger); - return ret; -} - -void wl1271_scan_stm(struct wl1271 *wl, struct ieee80211_vif *vif) -{ - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - int ret = 0; - enum ieee80211_band band; - u32 rate, mask; - - switch (wl->scan.state) { - case WL1271_SCAN_STATE_IDLE: - break; - - case WL1271_SCAN_STATE_2GHZ_ACTIVE: - band = IEEE80211_BAND_2GHZ; - mask = wlvif->bitrate_masks[band]; - if (wl->scan.req->no_cck) { - mask &= ~CONF_TX_CCK_RATES; - if (!mask) - mask = CONF_TX_RATE_MASK_BASIC_P2P; - } - rate = wl1271_tx_min_rate_get(wl, mask); - ret = wl1271_scan_send(wl, vif, band, false, rate); - if (ret == WL1271_NOTHING_TO_SCAN) { - wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE; - wl1271_scan_stm(wl, vif); - } - - break; - - case WL1271_SCAN_STATE_2GHZ_PASSIVE: - band = IEEE80211_BAND_2GHZ; - mask = wlvif->bitrate_masks[band]; - if (wl->scan.req->no_cck) { - mask &= ~CONF_TX_CCK_RATES; - if (!mask) - mask = CONF_TX_RATE_MASK_BASIC_P2P; - } - rate = wl1271_tx_min_rate_get(wl, mask); - ret = wl1271_scan_send(wl, vif, band, true, rate); - if (ret == WL1271_NOTHING_TO_SCAN) { - if (wl->enable_11a) - wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE; - else - wl->scan.state = WL1271_SCAN_STATE_DONE; - wl1271_scan_stm(wl, vif); - } - - break; - - case WL1271_SCAN_STATE_5GHZ_ACTIVE: - band = IEEE80211_BAND_5GHZ; - rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); - ret = wl1271_scan_send(wl, vif, band, false, rate); - if (ret == WL1271_NOTHING_TO_SCAN) { - wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE; - wl1271_scan_stm(wl, vif); - } - - break; - - case WL1271_SCAN_STATE_5GHZ_PASSIVE: - band = IEEE80211_BAND_5GHZ; - rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); - ret = wl1271_scan_send(wl, vif, band, true, rate); - if (ret == WL1271_NOTHING_TO_SCAN) { - wl->scan.state = WL1271_SCAN_STATE_DONE; - wl1271_scan_stm(wl, vif); - } - - break; - - case WL1271_SCAN_STATE_DONE: - wl->scan.failed = false; - cancel_delayed_work(&wl->scan_complete_work); - ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, - msecs_to_jiffies(0)); - break; - - default: - wl1271_error("invalid scan state"); - break; - } - - if (ret < 0) { - cancel_delayed_work(&wl->scan_complete_work); - ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, - msecs_to_jiffies(0)); - } -} - -int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif, - const u8 *ssid, size_t ssid_len, - struct cfg80211_scan_request *req) -{ - /* - * cfg80211 should guarantee that we don't get more channels - * than what we have registered. - */ - BUG_ON(req->n_channels > WL1271_MAX_CHANNELS); - - if (wl->scan.state != WL1271_SCAN_STATE_IDLE) - return -EBUSY; - - wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE; - - if (ssid_len && ssid) { - wl->scan.ssid_len = ssid_len; - memcpy(wl->scan.ssid, ssid, ssid_len); - } else { - wl->scan.ssid_len = 0; - } - - wl->scan_vif = vif; - wl->scan.req = req; - memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); - - /* we assume failure so that timeout scenarios are handled correctly */ - wl->scan.failed = true; - ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, - msecs_to_jiffies(WL1271_SCAN_TIMEOUT)); - - wl1271_scan_stm(wl, vif); - - return 0; -} - -int wl1271_scan_stop(struct wl1271 *wl) -{ - struct wl1271_cmd_header *cmd = NULL; - int ret = 0; - - if (WARN_ON(wl->scan.state == WL1271_SCAN_STATE_IDLE)) - return -EINVAL; - - wl1271_debug(DEBUG_CMD, "cmd scan stop"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, cmd, - sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("cmd stop_scan failed"); - goto out; - } -out: - kfree(cmd); - return ret; -} - -static int -wl1271_scan_get_sched_scan_channels(struct wl1271 *wl, - struct cfg80211_sched_scan_request *req, - struct conn_scan_ch_params *channels, - u32 band, bool radar, bool passive, - int start, int max_channels) -{ - struct conf_sched_scan_settings *c = &wl->conf.sched_scan; - int i, j; - u32 flags; - bool force_passive = !req->n_ssids; - - for (i = 0, j = start; - i < req->n_channels && j < max_channels; - i++) { - flags = req->channels[i]->flags; - - if (force_passive) - flags |= IEEE80211_CHAN_PASSIVE_SCAN; - - if ((req->channels[i]->band == band) && - !(flags & IEEE80211_CHAN_DISABLED) && - (!!(flags & IEEE80211_CHAN_RADAR) == radar) && - /* if radar is set, we ignore the passive flag */ - (radar || - !!(flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive)) { - wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ", - req->channels[i]->band, - req->channels[i]->center_freq); - wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X", - req->channels[i]->hw_value, - req->channels[i]->flags); - wl1271_debug(DEBUG_SCAN, "max_power %d", - req->channels[i]->max_power); - - if (flags & IEEE80211_CHAN_RADAR) { - channels[j].flags |= SCAN_CHANNEL_FLAGS_DFS; - - channels[j].passive_duration = - cpu_to_le16(c->dwell_time_dfs); - } else { - channels[j].passive_duration = - cpu_to_le16(c->dwell_time_passive); - } - - channels[j].min_duration = - cpu_to_le16(c->min_dwell_time_active); - channels[j].max_duration = - cpu_to_le16(c->max_dwell_time_active); - - channels[j].tx_power_att = req->channels[i]->max_power; - channels[j].channel = req->channels[i]->hw_value; - - j++; - } - } - - return j - start; -} - -static bool -wl1271_scan_sched_scan_channels(struct wl1271 *wl, - struct cfg80211_sched_scan_request *req, - struct wl1271_cmd_sched_scan_config *cfg) -{ - cfg->passive[0] = - wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_2, - IEEE80211_BAND_2GHZ, - false, true, 0, - MAX_CHANNELS_2GHZ); - cfg->active[0] = - wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_2, - IEEE80211_BAND_2GHZ, - false, false, - cfg->passive[0], - MAX_CHANNELS_2GHZ); - cfg->passive[1] = - wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5, - IEEE80211_BAND_5GHZ, - false, true, 0, - MAX_CHANNELS_5GHZ); - cfg->dfs = - wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5, - IEEE80211_BAND_5GHZ, - true, true, - cfg->passive[1], - MAX_CHANNELS_5GHZ); - cfg->active[1] = - wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels_5, - IEEE80211_BAND_5GHZ, - false, false, - cfg->passive[1] + cfg->dfs, - MAX_CHANNELS_5GHZ); - /* 802.11j channels are not supported yet */ - cfg->passive[2] = 0; - cfg->active[2] = 0; - - wl1271_debug(DEBUG_SCAN, " 2.4GHz: active %d passive %d", - cfg->active[0], cfg->passive[0]); - wl1271_debug(DEBUG_SCAN, " 5GHz: active %d passive %d", - cfg->active[1], cfg->passive[1]); - wl1271_debug(DEBUG_SCAN, " DFS: %d", cfg->dfs); - - return cfg->passive[0] || cfg->active[0] || - cfg->passive[1] || cfg->active[1] || cfg->dfs || - cfg->passive[2] || cfg->active[2]; -} - -/* Returns the scan type to be used or a negative value on error */ -static int -wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, - struct cfg80211_sched_scan_request *req) -{ - struct wl1271_cmd_sched_scan_ssid_list *cmd = NULL; - struct cfg80211_match_set *sets = req->match_sets; - struct cfg80211_ssid *ssids = req->ssids; - int ret = 0, type, i, j, n_match_ssids = 0; - - wl1271_debug(DEBUG_CMD, "cmd sched scan ssid list"); - - /* count the match sets that contain SSIDs */ - for (i = 0; i < req->n_match_sets; i++) - if (sets[i].ssid.ssid_len > 0) - n_match_ssids++; - - /* No filter, no ssids or only bcast ssid */ - if (!n_match_ssids && - (!req->n_ssids || - (req->n_ssids == 1 && req->ssids[0].ssid_len == 0))) { - type = SCAN_SSID_FILTER_ANY; - goto out; - } - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - if (!n_match_ssids) { - /* No filter, with ssids */ - type = SCAN_SSID_FILTER_DISABLED; - - for (i = 0; i < req->n_ssids; i++) { - cmd->ssids[cmd->n_ssids].type = (ssids[i].ssid_len) ? - SCAN_SSID_TYPE_HIDDEN : SCAN_SSID_TYPE_PUBLIC; - cmd->ssids[cmd->n_ssids].len = ssids[i].ssid_len; - memcpy(cmd->ssids[cmd->n_ssids].ssid, ssids[i].ssid, - ssids[i].ssid_len); - cmd->n_ssids++; - } - } else { - type = SCAN_SSID_FILTER_LIST; - - /* Add all SSIDs from the filters */ - for (i = 0; i < req->n_match_sets; i++) { - /* ignore sets without SSIDs */ - if (!sets[i].ssid.ssid_len) - continue; - - cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_PUBLIC; - cmd->ssids[cmd->n_ssids].len = sets[i].ssid.ssid_len; - memcpy(cmd->ssids[cmd->n_ssids].ssid, - sets[i].ssid.ssid, sets[i].ssid.ssid_len); - cmd->n_ssids++; - } - if ((req->n_ssids > 1) || - (req->n_ssids == 1 && req->ssids[0].ssid_len > 0)) { - /* - * Mark all the SSIDs passed in the SSID list as HIDDEN, - * so they're used in probe requests. - */ - for (i = 0; i < req->n_ssids; i++) { - if (!req->ssids[i].ssid_len) - continue; - - for (j = 0; j < cmd->n_ssids; j++) - if (!memcmp(req->ssids[i].ssid, - cmd->ssids[j].ssid, - req->ssids[i].ssid_len)) { - cmd->ssids[j].type = - SCAN_SSID_TYPE_HIDDEN; - break; - } - /* Fail if SSID isn't present in the filters */ - if (j == cmd->n_ssids) { - ret = -EINVAL; - goto out_free; - } - } - } - } - - wl1271_dump(DEBUG_SCAN, "SSID_LIST: ", cmd, sizeof(*cmd)); - - ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_SSID_CFG, cmd, - sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("cmd sched scan ssid list failed"); - goto out_free; - } - -out_free: - kfree(cmd); -out: - if (ret < 0) - return ret; - return type; -} - -int wl1271_scan_sched_scan_config(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - struct cfg80211_sched_scan_request *req, - struct ieee80211_sched_scan_ies *ies) -{ - struct wl1271_cmd_sched_scan_config *cfg = NULL; - struct conf_sched_scan_settings *c = &wl->conf.sched_scan; - int i, ret; - bool force_passive = !req->n_ssids; - - wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config"); - - cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); - if (!cfg) - return -ENOMEM; - - cfg->rssi_threshold = c->rssi_threshold; - cfg->snr_threshold = c->snr_threshold; - cfg->n_probe_reqs = c->num_probe_reqs; - /* cycles set to 0 it means infinite (until manually stopped) */ - cfg->cycles = 0; - /* report APs when at least 1 is found */ - cfg->report_after = 1; - /* don't stop scanning automatically when something is found */ - cfg->terminate = 0; - cfg->tag = WL1271_SCAN_DEFAULT_TAG; - /* don't filter on BSS type */ - cfg->bss_type = SCAN_BSS_TYPE_ANY; - /* currently NL80211 supports only a single interval */ - for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++) - cfg->intervals[i] = cpu_to_le32(req->interval); - - cfg->ssid_len = 0; - ret = wl12xx_scan_sched_scan_ssid_list(wl, req); - if (ret < 0) - goto out; - - cfg->filter_type = ret; - - wl1271_debug(DEBUG_SCAN, "filter_type = %d", cfg->filter_type); - - if (!wl1271_scan_sched_scan_channels(wl, req, cfg)) { - wl1271_error("scan channel list is empty"); - ret = -EINVAL; - goto out; - } - - if (!force_passive && cfg->active[0]) { - u8 band = IEEE80211_BAND_2GHZ; - ret = wl12xx_cmd_build_probe_req(wl, wlvif, - wlvif->dev_role_id, band, - req->ssids[0].ssid, - req->ssids[0].ssid_len, - ies->ie[band], - ies->len[band]); - if (ret < 0) { - wl1271_error("2.4GHz PROBE request template failed"); - goto out; - } - } - - if (!force_passive && cfg->active[1]) { - u8 band = IEEE80211_BAND_5GHZ; - ret = wl12xx_cmd_build_probe_req(wl, wlvif, - wlvif->dev_role_id, band, - req->ssids[0].ssid, - req->ssids[0].ssid_len, - ies->ie[band], - ies->len[band]); - if (ret < 0) { - wl1271_error("5GHz PROBE request template failed"); - goto out; - } - } - - wl1271_dump(DEBUG_SCAN, "SCAN_CFG: ", cfg, sizeof(*cfg)); - - ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_CFG, cfg, - sizeof(*cfg), 0); - if (ret < 0) { - wl1271_error("SCAN configuration failed"); - goto out; - } -out: - kfree(cfg); - return ret; -} - -int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - struct wl1271_cmd_sched_scan_start *start; - int ret = 0; - - wl1271_debug(DEBUG_CMD, "cmd periodic scan start"); - - if (wlvif->bss_type != BSS_TYPE_STA_BSS) - return -EOPNOTSUPP; - - if (test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) - return -EBUSY; - - start = kzalloc(sizeof(*start), GFP_KERNEL); - if (!start) - return -ENOMEM; - - start->tag = WL1271_SCAN_DEFAULT_TAG; - - ret = wl1271_cmd_send(wl, CMD_START_PERIODIC_SCAN, start, - sizeof(*start), 0); - if (ret < 0) { - wl1271_error("failed to send scan start command"); - goto out_free; - } - -out_free: - kfree(start); - return ret; -} - -void wl1271_scan_sched_scan_results(struct wl1271 *wl) -{ - wl1271_debug(DEBUG_SCAN, "got periodic scan results"); - - ieee80211_sched_scan_results(wl->hw); -} - -void wl1271_scan_sched_scan_stop(struct wl1271 *wl) -{ - struct wl1271_cmd_sched_scan_stop *stop; - int ret = 0; - - wl1271_debug(DEBUG_CMD, "cmd periodic scan stop"); - - /* FIXME: what to do if alloc'ing to stop fails? */ - stop = kzalloc(sizeof(*stop), GFP_KERNEL); - if (!stop) { - wl1271_error("failed to alloc memory to send sched scan stop"); - return; - } - - stop->tag = WL1271_SCAN_DEFAULT_TAG; - - ret = wl1271_cmd_send(wl, CMD_STOP_PERIODIC_SCAN, stop, - sizeof(*stop), 0); - if (ret < 0) { - wl1271_error("failed to send sched scan stop command"); - goto out_free; - } - -out_free: - kfree(stop); -} diff --git a/trunk/drivers/net/wireless/wl12xx/scan.h b/trunk/drivers/net/wireless/wl12xx/scan.h deleted file mode 100644 index 96ff457a3a0b..000000000000 --- a/trunk/drivers/net/wireless/wl12xx/scan.h +++ /dev/null @@ -1,233 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2009-2010 Nokia Corporation - * - * Contact: Luciano Coelho - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __SCAN_H__ -#define __SCAN_H__ - -#include "wl12xx.h" - -int wl1271_scan(struct wl1271 *wl, struct ieee80211_vif *vif, - const u8 *ssid, size_t ssid_len, - struct cfg80211_scan_request *req); -int wl1271_scan_stop(struct wl1271 *wl); -int wl1271_scan_build_probe_req(struct wl1271 *wl, - const u8 *ssid, size_t ssid_len, - const u8 *ie, size_t ie_len, u8 band); -void wl1271_scan_stm(struct wl1271 *wl, struct ieee80211_vif *vif); -void wl1271_scan_complete_work(struct work_struct *work); -int wl1271_scan_sched_scan_config(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - struct cfg80211_sched_scan_request *req, - struct ieee80211_sched_scan_ies *ies); -int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif); -void wl1271_scan_sched_scan_stop(struct wl1271 *wl); -void wl1271_scan_sched_scan_results(struct wl1271 *wl); - -#define WL1271_SCAN_MAX_CHANNELS 24 -#define WL1271_SCAN_DEFAULT_TAG 1 -#define WL1271_SCAN_CURRENT_TX_PWR 0 -#define WL1271_SCAN_OPT_ACTIVE 0 -#define WL1271_SCAN_OPT_PASSIVE 1 -#define WL1271_SCAN_OPT_SPLIT_SCAN 2 -#define WL1271_SCAN_OPT_PRIORITY_HIGH 4 -/* scan even if we fail to enter psm */ -#define WL1271_SCAN_OPT_FORCE 8 -#define WL1271_SCAN_BAND_2_4_GHZ 0 -#define WL1271_SCAN_BAND_5_GHZ 1 - -#define WL1271_SCAN_TIMEOUT 10000 /* msec */ - -enum { - WL1271_SCAN_STATE_IDLE, - WL1271_SCAN_STATE_2GHZ_ACTIVE, - WL1271_SCAN_STATE_2GHZ_PASSIVE, - WL1271_SCAN_STATE_5GHZ_ACTIVE, - WL1271_SCAN_STATE_5GHZ_PASSIVE, - WL1271_SCAN_STATE_DONE -}; - -struct basic_scan_params { - /* Scan option flags (WL1271_SCAN_OPT_*) */ - __le16 scan_options; - u8 role_id; - /* Number of scan channels in the list (maximum 30) */ - u8 n_ch; - /* This field indicates the number of probe requests to send - per channel for an active scan */ - u8 n_probe_reqs; - u8 tid_trigger; - u8 ssid_len; - u8 use_ssid_list; - - /* Rate bit field for sending the probes */ - __le32 tx_rate; - - u8 ssid[IEEE80211_MAX_SSID_LEN]; - /* Band to scan */ - u8 band; - - u8 scan_tag; - u8 padding2[2]; -} __packed; - -struct basic_scan_channel_params { - /* Duration in TU to wait for frames on a channel for active scan */ - __le32 min_duration; - __le32 max_duration; - __le32 bssid_lsb; - __le16 bssid_msb; - u8 early_termination; - u8 tx_power_att; - u8 channel; - /* FW internal use only! */ - u8 dfs_candidate; - u8 activity_detected; - u8 pad; -} __packed; - -struct wl1271_cmd_scan { - struct wl1271_cmd_header header; - - struct basic_scan_params params; - struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS]; - - /* src mac address */ - u8 addr[ETH_ALEN]; - u8 padding[2]; -} __packed; - -struct wl1271_cmd_trigger_scan_to { - struct wl1271_cmd_header header; - - __le32 timeout; -} __packed; - -#define MAX_CHANNELS_2GHZ 14 -#define MAX_CHANNELS_5GHZ 23 -#define MAX_CHANNELS_4GHZ 4 - -#define SCAN_MAX_CYCLE_INTERVALS 16 -#define SCAN_MAX_BANDS 3 - -enum { - SCAN_SSID_FILTER_ANY = 0, - SCAN_SSID_FILTER_SPECIFIC = 1, - SCAN_SSID_FILTER_LIST = 2, - SCAN_SSID_FILTER_DISABLED = 3 -}; - -enum { - SCAN_BSS_TYPE_INDEPENDENT, - SCAN_BSS_TYPE_INFRASTRUCTURE, - SCAN_BSS_TYPE_ANY, -}; - -#define SCAN_CHANNEL_FLAGS_DFS BIT(0) -#define SCAN_CHANNEL_FLAGS_DFS_ENABLED BIT(1) - -struct conn_scan_ch_params { - __le16 min_duration; - __le16 max_duration; - __le16 passive_duration; - - u8 channel; - u8 tx_power_att; - - /* bit 0: DFS channel; bit 1: DFS enabled */ - u8 flags; - - u8 padding[3]; -} __packed; - -struct wl1271_cmd_sched_scan_config { - struct wl1271_cmd_header header; - - __le32 intervals[SCAN_MAX_CYCLE_INTERVALS]; - - s8 rssi_threshold; /* for filtering (in dBm) */ - s8 snr_threshold; /* for filtering (in dB) */ - - u8 cycles; /* maximum number of scan cycles */ - u8 report_after; /* report when this number of results are received */ - u8 terminate; /* stop scanning after reporting */ - - u8 tag; - u8 bss_type; /* for filtering */ - u8 filter_type; - - u8 ssid_len; /* For SCAN_SSID_FILTER_SPECIFIC */ - u8 ssid[IEEE80211_MAX_SSID_LEN]; - - u8 n_probe_reqs; /* Number of probes requests per channel */ - - u8 passive[SCAN_MAX_BANDS]; - u8 active[SCAN_MAX_BANDS]; - - u8 dfs; - - u8 padding[3]; - - struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ]; - struct conn_scan_ch_params channels_5[MAX_CHANNELS_5GHZ]; - struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ]; -} __packed; - - -#define SCHED_SCAN_MAX_SSIDS 16 - -enum { - SCAN_SSID_TYPE_PUBLIC = 0, - SCAN_SSID_TYPE_HIDDEN = 1, -}; - -struct wl1271_ssid { - u8 type; - u8 len; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - /* u8 padding[2]; */ -} __packed; - -struct wl1271_cmd_sched_scan_ssid_list { - struct wl1271_cmd_header header; - - u8 n_ssids; - struct wl1271_ssid ssids[SCHED_SCAN_MAX_SSIDS]; - u8 padding[3]; -} __packed; - -struct wl1271_cmd_sched_scan_start { - struct wl1271_cmd_header header; - - u8 tag; - u8 padding[3]; -} __packed; - -struct wl1271_cmd_sched_scan_stop { - struct wl1271_cmd_header header; - - u8 tag; - u8 padding[3]; -} __packed; - - -#endif /* __WL1271_SCAN_H__ */ diff --git a/trunk/drivers/net/wireless/wl12xx/tx.c b/trunk/drivers/net/wireless/wl12xx/tx.c deleted file mode 100644 index 43ae49143d68..000000000000 --- a/trunk/drivers/net/wireless/wl12xx/tx.c +++ /dev/null @@ -1,1079 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include -#include -#include - -#include "wl12xx.h" -#include "debug.h" -#include "io.h" -#include "reg.h" -#include "ps.h" -#include "tx.h" -#include "event.h" - -static int wl1271_set_default_wep_key(struct wl1271 *wl, - struct wl12xx_vif *wlvif, u8 id) -{ - int ret; - bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); - - if (is_ap) - ret = wl12xx_cmd_set_default_wep_key(wl, id, - wlvif->ap.bcast_hlid); - else - ret = wl12xx_cmd_set_default_wep_key(wl, id, wlvif->sta.hlid); - - if (ret < 0) - return ret; - - wl1271_debug(DEBUG_CRYPT, "default wep key idx: %d", (int)id); - return 0; -} - -static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb) -{ - int id; - - id = find_first_zero_bit(wl->tx_frames_map, ACX_TX_DESCRIPTORS); - if (id >= ACX_TX_DESCRIPTORS) - return -EBUSY; - - __set_bit(id, wl->tx_frames_map); - wl->tx_frames[id] = skb; - wl->tx_frames_cnt++; - return id; -} - -static void wl1271_free_tx_id(struct wl1271 *wl, int id) -{ - if (__test_and_clear_bit(id, wl->tx_frames_map)) { - if (unlikely(wl->tx_frames_cnt == ACX_TX_DESCRIPTORS)) - clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); - - wl->tx_frames[id] = NULL; - wl->tx_frames_cnt--; - } -} - -static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, - struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr; - - /* - * add the station to the known list before transmitting the - * authentication response. this way it won't get de-authed by FW - * when transmitting too soon. - */ - hdr = (struct ieee80211_hdr *)(skb->data + - sizeof(struct wl1271_tx_hw_descr)); - if (ieee80211_is_auth(hdr->frame_control)) - wl1271_acx_set_inconnection_sta(wl, hdr->addr1); -} - -static void wl1271_tx_regulate_link(struct wl1271 *wl, - struct wl12xx_vif *wlvif, - u8 hlid) -{ - bool fw_ps, single_sta; - u8 tx_pkts; - - if (WARN_ON(!test_bit(hlid, wlvif->links_map))) - return; - - fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); - tx_pkts = wl->links[hlid].allocated_pkts; - single_sta = (wl->active_sta_count == 1); - - /* - * if in FW PS and there is enough data in FW we can put the link - * into high-level PS and clean out its TX queues. - * Make an exception if this is the only connected station. In this - * case FW-memory congestion is not a problem. - */ - if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) - wl12xx_ps_link_start(wl, wlvif, hlid, true); -} - -bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) -{ - return wl->dummy_packet == skb; -} - -u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct sk_buff *skb) -{ - struct ieee80211_tx_info *control = IEEE80211_SKB_CB(skb); - - if (control->control.sta) { - struct wl1271_station *wl_sta; - - wl_sta = (struct wl1271_station *) - control->control.sta->drv_priv; - return wl_sta->hlid; - } else { - struct ieee80211_hdr *hdr; - - if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) - return wl->system_hlid; - - hdr = (struct ieee80211_hdr *)skb->data; - if (ieee80211_is_mgmt(hdr->frame_control)) - return wlvif->ap.global_hlid; - else - return wlvif->ap.bcast_hlid; - } -} - -u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - - if (!wlvif || wl12xx_is_dummy_packet(wl, skb)) - return wl->system_hlid; - - if (wlvif->bss_type == BSS_TYPE_AP_BSS) - return wl12xx_tx_get_hlid_ap(wl, wlvif, skb); - - if ((test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) || - test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags)) && - !ieee80211_is_auth(hdr->frame_control) && - !ieee80211_is_assoc_req(hdr->frame_control)) - return wlvif->sta.hlid; - else - return wlvif->dev_hlid; -} - -static unsigned int wl12xx_calc_packet_alignment(struct wl1271 *wl, - unsigned int packet_length) -{ - if (wl->quirks & WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT) - return ALIGN(packet_length, WL1271_TX_ALIGN_TO); - else - return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE); -} - -static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct sk_buff *skb, u32 extra, u32 buf_offset, - u8 hlid) -{ - struct wl1271_tx_hw_descr *desc; - u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; - u32 len; - u32 total_blocks; - int id, ret = -EBUSY, ac; - u32 spare_blocks = wl->tx_spare_blocks; - bool is_dummy = false; - - if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) - return -EAGAIN; - - /* allocate free identifier for the packet */ - id = wl1271_alloc_tx_id(wl, skb); - if (id < 0) - return id; - - /* approximate the number of blocks required for this packet - in the firmware */ - len = wl12xx_calc_packet_alignment(wl, total_len); - - /* in case of a dummy packet, use default amount of spare mem blocks */ - if (unlikely(wl12xx_is_dummy_packet(wl, skb))) { - is_dummy = true; - spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; - } - - total_blocks = (len + TX_HW_BLOCK_SIZE - 1) / TX_HW_BLOCK_SIZE + - spare_blocks; - - if (total_blocks <= wl->tx_blocks_available) { - desc = (struct wl1271_tx_hw_descr *)skb_push( - skb, total_len - skb->len); - - /* HW descriptor fields change between wl127x and wl128x */ - if (wl->chip.id == CHIP_ID_1283_PG20) { - desc->wl128x_mem.total_mem_blocks = total_blocks; - } else { - desc->wl127x_mem.extra_blocks = spare_blocks; - desc->wl127x_mem.total_mem_blocks = total_blocks; - } - - desc->id = id; - - wl->tx_blocks_available -= total_blocks; - wl->tx_allocated_blocks += total_blocks; - - /* If the FW was empty before, arm the Tx watchdog */ - if (wl->tx_allocated_blocks == total_blocks) - wl12xx_rearm_tx_watchdog_locked(wl); - - ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); - wl->tx_allocated_pkts[ac]++; - - if (!is_dummy && wlvif && - wlvif->bss_type == BSS_TYPE_AP_BSS && - test_bit(hlid, wlvif->ap.sta_hlid_map)) - wl->links[hlid].allocated_pkts++; - - ret = 0; - - wl1271_debug(DEBUG_TX, - "tx_allocate: size: %d, blocks: %d, id: %d", - total_len, total_blocks, id); - } else { - wl1271_free_tx_id(wl, id); - } - - return ret; -} - -static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct sk_buff *skb, u32 extra, - struct ieee80211_tx_info *control, u8 hlid) -{ - struct timespec ts; - struct wl1271_tx_hw_descr *desc; - int aligned_len, ac, rate_idx; - s64 hosttime; - u16 tx_attr = 0; - __le16 frame_control; - struct ieee80211_hdr *hdr; - u8 *frame_start; - bool is_dummy; - - desc = (struct wl1271_tx_hw_descr *) skb->data; - frame_start = (u8 *)(desc + 1); - hdr = (struct ieee80211_hdr *)(frame_start + extra); - frame_control = hdr->frame_control; - - /* relocate space for security header */ - if (extra) { - int hdrlen = ieee80211_hdrlen(frame_control); - memmove(frame_start, hdr, hdrlen); - } - - /* configure packet life time */ - getnstimeofday(&ts); - hosttime = (timespec_to_ns(&ts) >> 10); - desc->start_time = cpu_to_le32(hosttime - wl->time_offset); - - is_dummy = wl12xx_is_dummy_packet(wl, skb); - if (is_dummy || !wlvif || wlvif->bss_type != BSS_TYPE_AP_BSS) - desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU); - else - desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU); - - /* queue */ - ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); - desc->tid = skb->priority; - - if (is_dummy) { - /* - * FW expects the dummy packet to have an invalid session id - - * any session id that is different than the one set in the join - */ - tx_attr = (SESSION_COUNTER_INVALID << - TX_HW_ATTR_OFST_SESSION_COUNTER) & - TX_HW_ATTR_SESSION_COUNTER; - - tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ; - } else if (wlvif) { - /* configure the tx attributes */ - tx_attr = wlvif->session_counter << - TX_HW_ATTR_OFST_SESSION_COUNTER; - } - - desc->hlid = hlid; - if (is_dummy || !wlvif) - rate_idx = 0; - else if (wlvif->bss_type != BSS_TYPE_AP_BSS) { - /* if the packets are destined for AP (have a STA entry) - send them with AP rate policies, otherwise use default - basic rates */ - if (control->flags & IEEE80211_TX_CTL_NO_CCK_RATE) - rate_idx = wlvif->sta.p2p_rate_idx; - else if (control->control.sta) - rate_idx = wlvif->sta.ap_rate_idx; - else - rate_idx = wlvif->sta.basic_rate_idx; - } else { - if (hlid == wlvif->ap.global_hlid) - rate_idx = wlvif->ap.mgmt_rate_idx; - else if (hlid == wlvif->ap.bcast_hlid) - rate_idx = wlvif->ap.bcast_rate_idx; - else - rate_idx = wlvif->ap.ucast_rate_idx[ac]; - } - - tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY; - desc->reserved = 0; - - aligned_len = wl12xx_calc_packet_alignment(wl, skb->len); - - if (wl->chip.id == CHIP_ID_1283_PG20) { - desc->wl128x_mem.extra_bytes = aligned_len - skb->len; - desc->length = cpu_to_le16(aligned_len >> 2); - - wl1271_debug(DEBUG_TX, "tx_fill_hdr: hlid: %d " - "tx_attr: 0x%x len: %d life: %d mem: %d", - desc->hlid, tx_attr, - le16_to_cpu(desc->length), - le16_to_cpu(desc->life_time), - desc->wl128x_mem.total_mem_blocks); - } else { - int pad; - - /* Store the aligned length in terms of words */ - desc->length = cpu_to_le16(aligned_len >> 2); - - /* calculate number of padding bytes */ - pad = aligned_len - skb->len; - tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; - - wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d hlid: %d " - "tx_attr: 0x%x len: %d life: %d mem: %d", pad, - desc->hlid, tx_attr, - le16_to_cpu(desc->length), - le16_to_cpu(desc->life_time), - desc->wl127x_mem.total_mem_blocks); - } - - /* for WEP shared auth - no fw encryption is needed */ - if (ieee80211_is_auth(frame_control) && - ieee80211_has_protected(frame_control)) - tx_attr |= TX_HW_ATTR_HOST_ENCRYPT; - - desc->tx_attr = cpu_to_le16(tx_attr); -} - -/* caller must hold wl->mutex */ -static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct sk_buff *skb, u32 buf_offset) -{ - struct ieee80211_tx_info *info; - u32 extra = 0; - int ret = 0; - u32 total_len; - u8 hlid; - bool is_dummy; - - if (!skb) - return -EINVAL; - - info = IEEE80211_SKB_CB(skb); - - /* TODO: handle dummy packets on multi-vifs */ - is_dummy = wl12xx_is_dummy_packet(wl, skb); - - if (info->control.hw_key && - info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) - extra = WL1271_EXTRA_SPACE_TKIP; - - if (info->control.hw_key) { - bool is_wep; - u8 idx = info->control.hw_key->hw_key_idx; - u32 cipher = info->control.hw_key->cipher; - - is_wep = (cipher == WLAN_CIPHER_SUITE_WEP40) || - (cipher == WLAN_CIPHER_SUITE_WEP104); - - if (unlikely(is_wep && wlvif->default_key != idx)) { - ret = wl1271_set_default_wep_key(wl, wlvif, idx); - if (ret < 0) - return ret; - wlvif->default_key = idx; - } - } - hlid = wl12xx_tx_get_hlid(wl, wlvif, skb); - if (hlid == WL12XX_INVALID_LINK_ID) { - wl1271_error("invalid hlid. dropping skb 0x%p", skb); - return -EINVAL; - } - - ret = wl1271_tx_allocate(wl, wlvif, skb, extra, buf_offset, hlid); - if (ret < 0) - return ret; - - wl1271_tx_fill_hdr(wl, wlvif, skb, extra, info, hlid); - - if (!is_dummy && wlvif && wlvif->bss_type == BSS_TYPE_AP_BSS) { - wl1271_tx_ap_update_inconnection_sta(wl, skb); - wl1271_tx_regulate_link(wl, wlvif, hlid); - } - - /* - * The length of each packet is stored in terms of - * words. Thus, we must pad the skb data to make sure its - * length is aligned. The number of padding bytes is computed - * and set in wl1271_tx_fill_hdr. - * In special cases, we want to align to a specific block size - * (eg. for wl128x with SDIO we align to 256). - */ - total_len = wl12xx_calc_packet_alignment(wl, skb->len); - - memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len); - memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len); - - /* Revert side effects in the dummy packet skb, so it can be reused */ - if (is_dummy) - skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); - - return total_len; -} - -u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set, - enum ieee80211_band rate_band) -{ - struct ieee80211_supported_band *band; - u32 enabled_rates = 0; - int bit; - - band = wl->hw->wiphy->bands[rate_band]; - for (bit = 0; bit < band->n_bitrates; bit++) { - if (rate_set & 0x1) - enabled_rates |= band->bitrates[bit].hw_value; - rate_set >>= 1; - } - - /* MCS rates indication are on bits 16 - 23 */ - rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates; - - for (bit = 0; bit < 8; bit++) { - if (rate_set & 0x1) - enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit); - rate_set >>= 1; - } - - return enabled_rates; -} - -void wl1271_handle_tx_low_watermark(struct wl1271 *wl) -{ - unsigned long flags; - int i; - - for (i = 0; i < NUM_TX_QUEUES; i++) { - if (test_bit(i, &wl->stopped_queues_map) && - wl->tx_queue_count[i] <= WL1271_TX_QUEUE_LOW_WATERMARK) { - /* firmware buffer has space, restart queues */ - spin_lock_irqsave(&wl->wl_lock, flags); - ieee80211_wake_queue(wl->hw, - wl1271_tx_get_mac80211_queue(i)); - clear_bit(i, &wl->stopped_queues_map); - spin_unlock_irqrestore(&wl->wl_lock, flags); - } - } -} - -static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl, - struct sk_buff_head *queues) -{ - int i, q = -1, ac; - u32 min_pkts = 0xffffffff; - - /* - * Find a non-empty ac where: - * 1. There are packets to transmit - * 2. The FW has the least allocated blocks - * - * We prioritize the ACs according to VO>VI>BE>BK - */ - for (i = 0; i < NUM_TX_QUEUES; i++) { - ac = wl1271_tx_get_queue(i); - if (!skb_queue_empty(&queues[ac]) && - (wl->tx_allocated_pkts[ac] < min_pkts)) { - q = ac; - min_pkts = wl->tx_allocated_pkts[q]; - } - } - - if (q == -1) - return NULL; - - return &queues[q]; -} - -static struct sk_buff *wl12xx_lnk_skb_dequeue(struct wl1271 *wl, - struct wl1271_link *lnk) -{ - struct sk_buff *skb; - unsigned long flags; - struct sk_buff_head *queue; - - queue = wl1271_select_queue(wl, lnk->tx_queue); - if (!queue) - return NULL; - - skb = skb_dequeue(queue); - if (skb) { - int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); - spin_lock_irqsave(&wl->wl_lock, flags); - WARN_ON_ONCE(wl->tx_queue_count[q] <= 0); - wl->tx_queue_count[q]--; - spin_unlock_irqrestore(&wl->wl_lock, flags); - } - - return skb; -} - -static struct sk_buff *wl12xx_vif_skb_dequeue(struct wl1271 *wl, - struct wl12xx_vif *wlvif) -{ - struct sk_buff *skb = NULL; - int i, h, start_hlid; - - /* start from the link after the last one */ - start_hlid = (wlvif->last_tx_hlid + 1) % WL12XX_MAX_LINKS; - - /* dequeue according to AC, round robin on each link */ - for (i = 0; i < WL12XX_MAX_LINKS; i++) { - h = (start_hlid + i) % WL12XX_MAX_LINKS; - - /* only consider connected stations */ - if (!test_bit(h, wlvif->links_map)) - continue; - - skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[h]); - if (!skb) - continue; - - wlvif->last_tx_hlid = h; - break; - } - - if (!skb) - wlvif->last_tx_hlid = 0; - - return skb; -} - -static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) -{ - unsigned long flags; - struct wl12xx_vif *wlvif = wl->last_wlvif; - struct sk_buff *skb = NULL; - - /* continue from last wlvif (round robin) */ - if (wlvif) { - wl12xx_for_each_wlvif_continue(wl, wlvif) { - skb = wl12xx_vif_skb_dequeue(wl, wlvif); - if (skb) { - wl->last_wlvif = wlvif; - break; - } - } - } - - /* dequeue from the system HLID before the restarting wlvif list */ - if (!skb) - skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[wl->system_hlid]); - - /* do a new pass over the wlvif list */ - if (!skb) { - wl12xx_for_each_wlvif(wl, wlvif) { - skb = wl12xx_vif_skb_dequeue(wl, wlvif); - if (skb) { - wl->last_wlvif = wlvif; - break; - } - - /* - * No need to continue after last_wlvif. The previous - * pass should have found it. - */ - if (wlvif == wl->last_wlvif) - break; - } - } - - if (!skb && - test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) { - int q; - - skb = wl->dummy_packet; - q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); - spin_lock_irqsave(&wl->wl_lock, flags); - WARN_ON_ONCE(wl->tx_queue_count[q] <= 0); - wl->tx_queue_count[q]--; - spin_unlock_irqrestore(&wl->wl_lock, flags); - } - - return skb; -} - -static void wl1271_skb_queue_head(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct sk_buff *skb) -{ - unsigned long flags; - int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); - - if (wl12xx_is_dummy_packet(wl, skb)) { - set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); - } else { - u8 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb); - skb_queue_head(&wl->links[hlid].tx_queue[q], skb); - - /* make sure we dequeue the same packet next time */ - wlvif->last_tx_hlid = (hlid + WL12XX_MAX_LINKS - 1) % - WL12XX_MAX_LINKS; - } - - spin_lock_irqsave(&wl->wl_lock, flags); - wl->tx_queue_count[q]++; - spin_unlock_irqrestore(&wl->wl_lock, flags); -} - -static bool wl1271_tx_is_data_present(struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); - - return ieee80211_is_data_present(hdr->frame_control); -} - -void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids) -{ - struct wl12xx_vif *wlvif; - u32 timeout; - u8 hlid; - - if (!wl->conf.rx_streaming.interval) - return; - - if (!wl->conf.rx_streaming.always && - !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)) - return; - - timeout = wl->conf.rx_streaming.duration; - wl12xx_for_each_wlvif_sta(wl, wlvif) { - bool found = false; - for_each_set_bit(hlid, active_hlids, WL12XX_MAX_LINKS) { - if (test_bit(hlid, wlvif->links_map)) { - found = true; - break; - } - } - - if (!found) - continue; - - /* enable rx streaming */ - if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags)) - ieee80211_queue_work(wl->hw, - &wlvif->rx_streaming_enable_work); - - mod_timer(&wlvif->rx_streaming_timer, - jiffies + msecs_to_jiffies(timeout)); - } -} - -void wl1271_tx_work_locked(struct wl1271 *wl) -{ - struct wl12xx_vif *wlvif; - struct sk_buff *skb; - struct wl1271_tx_hw_descr *desc; - u32 buf_offset = 0; - bool sent_packets = false; - unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0}; - int ret; - - if (unlikely(wl->state == WL1271_STATE_OFF)) - return; - - while ((skb = wl1271_skb_dequeue(wl))) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - bool has_data = false; - - wlvif = NULL; - if (!wl12xx_is_dummy_packet(wl, skb) && info->control.vif) - wlvif = wl12xx_vif_to_data(info->control.vif); - - has_data = wlvif && wl1271_tx_is_data_present(skb); - ret = wl1271_prepare_tx_frame(wl, wlvif, skb, buf_offset); - if (ret == -EAGAIN) { - /* - * Aggregation buffer is full. - * Flush buffer and try again. - */ - wl1271_skb_queue_head(wl, wlvif, skb); - wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, - buf_offset, true); - sent_packets = true; - buf_offset = 0; - continue; - } else if (ret == -EBUSY) { - /* - * Firmware buffer is full. - * Queue back last skb, and stop aggregating. - */ - wl1271_skb_queue_head(wl, wlvif, skb); - /* No work left, avoid scheduling redundant tx work */ - set_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); - goto out_ack; - } else if (ret < 0) { - if (wl12xx_is_dummy_packet(wl, skb)) - /* - * fw still expects dummy packet, - * so re-enqueue it - */ - wl1271_skb_queue_head(wl, wlvif, skb); - else - ieee80211_free_txskb(wl->hw, skb); - goto out_ack; - } - buf_offset += ret; - wl->tx_packets_count++; - if (has_data) { - desc = (struct wl1271_tx_hw_descr *) skb->data; - __set_bit(desc->hlid, active_hlids); - } - } - -out_ack: - if (buf_offset) { - wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, - buf_offset, true); - sent_packets = true; - } - if (sent_packets) { - /* - * Interrupt the firmware with the new packets. This is only - * required for older hardware revisions - */ - if (wl->quirks & WL12XX_QUIRK_END_OF_TRANSACTION) - wl1271_write32(wl, WL1271_HOST_WR_ACCESS, - wl->tx_packets_count); - - wl1271_handle_tx_low_watermark(wl); - } - wl12xx_rearm_rx_streaming(wl, active_hlids); -} - -void wl1271_tx_work(struct work_struct *work) -{ - struct wl1271 *wl = container_of(work, struct wl1271, tx_work); - int ret; - - mutex_lock(&wl->mutex); - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - wl1271_tx_work_locked(wl); - - wl1271_ps_elp_sleep(wl); -out: - mutex_unlock(&wl->mutex); -} - -static u8 wl1271_tx_get_rate_flags(u8 rate_class_index) -{ - u8 flags = 0; - - if (rate_class_index >= CONF_HW_RXTX_RATE_MCS_MIN && - rate_class_index <= CONF_HW_RXTX_RATE_MCS_MAX) - flags |= IEEE80211_TX_RC_MCS; - if (rate_class_index == CONF_HW_RXTX_RATE_MCS7_SGI) - flags |= IEEE80211_TX_RC_SHORT_GI; - return flags; -} - -static void wl1271_tx_complete_packet(struct wl1271 *wl, - struct wl1271_tx_hw_res_descr *result) -{ - struct ieee80211_tx_info *info; - struct ieee80211_vif *vif; - struct wl12xx_vif *wlvif; - struct sk_buff *skb; - int id = result->id; - int rate = -1; - u8 rate_flags = 0; - u8 retries = 0; - - /* check for id legality */ - if (unlikely(id >= ACX_TX_DESCRIPTORS || wl->tx_frames[id] == NULL)) { - wl1271_warning("TX result illegal id: %d", id); - return; - } - - skb = wl->tx_frames[id]; - info = IEEE80211_SKB_CB(skb); - - if (wl12xx_is_dummy_packet(wl, skb)) { - wl1271_free_tx_id(wl, id); - return; - } - - /* info->control is valid as long as we don't update info->status */ - vif = info->control.vif; - wlvif = wl12xx_vif_to_data(vif); - - /* update the TX status info */ - if (result->status == TX_SUCCESS) { - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) - info->flags |= IEEE80211_TX_STAT_ACK; - rate = wl1271_rate_to_idx(result->rate_class_index, - wlvif->band); - rate_flags = wl1271_tx_get_rate_flags(result->rate_class_index); - retries = result->ack_failures; - } else if (result->status == TX_RETRY_EXCEEDED) { - wl->stats.excessive_retries++; - retries = result->ack_failures; - } - - info->status.rates[0].idx = rate; - info->status.rates[0].count = retries; - info->status.rates[0].flags = rate_flags; - info->status.ack_signal = -1; - - wl->stats.retry_count += result->ack_failures; - - /* - * update sequence number only when relevant, i.e. only in - * sessions of TKIP, AES and GEM (not in open or WEP sessions) - */ - if (info->control.hw_key && - (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP || - info->control.hw_key->cipher == WLAN_CIPHER_SUITE_CCMP || - info->control.hw_key->cipher == WL1271_CIPHER_SUITE_GEM)) { - u8 fw_lsb = result->tx_security_sequence_number_lsb; - u8 cur_lsb = wlvif->tx_security_last_seq_lsb; - - /* - * update security sequence number, taking care of potential - * wrap-around - */ - wlvif->tx_security_seq += (fw_lsb - cur_lsb) & 0xff; - wlvif->tx_security_last_seq_lsb = fw_lsb; - } - - /* remove private header from packet */ - skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); - - /* remove TKIP header space if present */ - if (info->control.hw_key && - info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { - int hdrlen = ieee80211_get_hdrlen_from_skb(skb); - memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, skb->data, - hdrlen); - skb_pull(skb, WL1271_EXTRA_SPACE_TKIP); - } - - wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" - " status 0x%x", - result->id, skb, result->ack_failures, - result->rate_class_index, result->status); - - /* return the packet to the stack */ - skb_queue_tail(&wl->deferred_tx_queue, skb); - queue_work(wl->freezable_wq, &wl->netstack_work); - wl1271_free_tx_id(wl, result->id); -} - -/* Called upon reception of a TX complete interrupt */ -void wl1271_tx_complete(struct wl1271 *wl) -{ - struct wl1271_acx_mem_map *memmap = - (struct wl1271_acx_mem_map *)wl->target_mem_map; - u32 count, fw_counter; - u32 i; - - /* read the tx results from the chipset */ - wl1271_read(wl, le32_to_cpu(memmap->tx_result), - wl->tx_res_if, sizeof(*wl->tx_res_if), false); - fw_counter = le32_to_cpu(wl->tx_res_if->tx_result_fw_counter); - - /* write host counter to chipset (to ack) */ - wl1271_write32(wl, le32_to_cpu(memmap->tx_result) + - offsetof(struct wl1271_tx_hw_res_if, - tx_result_host_counter), fw_counter); - - count = fw_counter - wl->tx_results_count; - wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); - - /* verify that the result buffer is not getting overrun */ - if (unlikely(count > TX_HW_RESULT_QUEUE_LEN)) - wl1271_warning("TX result overflow from chipset: %d", count); - - /* process the results */ - for (i = 0; i < count; i++) { - struct wl1271_tx_hw_res_descr *result; - u8 offset = wl->tx_results_count & TX_HW_RESULT_QUEUE_LEN_MASK; - - /* process the packet */ - result = &(wl->tx_res_if->tx_results_queue[offset]); - wl1271_tx_complete_packet(wl, result); - - wl->tx_results_count++; - } -} - -void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) -{ - struct sk_buff *skb; - int i; - unsigned long flags; - struct ieee80211_tx_info *info; - int total[NUM_TX_QUEUES]; - - for (i = 0; i < NUM_TX_QUEUES; i++) { - total[i] = 0; - while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { - wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb); - - if (!wl12xx_is_dummy_packet(wl, skb)) { - info = IEEE80211_SKB_CB(skb); - info->status.rates[0].idx = -1; - info->status.rates[0].count = 0; - ieee80211_tx_status_ni(wl->hw, skb); - } - - total[i]++; - } - } - - spin_lock_irqsave(&wl->wl_lock, flags); - for (i = 0; i < NUM_TX_QUEUES; i++) - wl->tx_queue_count[i] -= total[i]; - spin_unlock_irqrestore(&wl->wl_lock, flags); - - wl1271_handle_tx_low_watermark(wl); -} - -/* caller must hold wl->mutex and TX must be stopped */ -void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif) -{ - int i; - - /* TX failure */ - for_each_set_bit(i, wlvif->links_map, WL12XX_MAX_LINKS) { - if (wlvif->bss_type == BSS_TYPE_AP_BSS) - wl1271_free_sta(wl, wlvif, i); - else - wlvif->sta.ba_rx_bitmap = 0; - - wl->links[i].allocated_pkts = 0; - wl->links[i].prev_freed_pkts = 0; - } - wlvif->last_tx_hlid = 0; - -} -/* caller must hold wl->mutex and TX must be stopped */ -void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues) -{ - int i; - struct sk_buff *skb; - struct ieee80211_tx_info *info; - - /* only reset the queues if something bad happened */ - if (WARN_ON_ONCE(wl1271_tx_total_queue_count(wl) != 0)) { - for (i = 0; i < WL12XX_MAX_LINKS; i++) - wl1271_tx_reset_link_queues(wl, i); - - for (i = 0; i < NUM_TX_QUEUES; i++) - wl->tx_queue_count[i] = 0; - } - - wl->stopped_queues_map = 0; - - /* - * Make sure the driver is at a consistent state, in case this - * function is called from a context other than interface removal. - * This call will always wake the TX queues. - */ - if (reset_tx_queues) - wl1271_handle_tx_low_watermark(wl); - - for (i = 0; i < ACX_TX_DESCRIPTORS; i++) { - if (wl->tx_frames[i] == NULL) - continue; - - skb = wl->tx_frames[i]; - wl1271_free_tx_id(wl, i); - wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); - - if (!wl12xx_is_dummy_packet(wl, skb)) { - /* - * Remove private headers before passing the skb to - * mac80211 - */ - info = IEEE80211_SKB_CB(skb); - skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); - if (info->control.hw_key && - info->control.hw_key->cipher == - WLAN_CIPHER_SUITE_TKIP) { - int hdrlen = ieee80211_get_hdrlen_from_skb(skb); - memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, - skb->data, hdrlen); - skb_pull(skb, WL1271_EXTRA_SPACE_TKIP); - } - - info->status.rates[0].idx = -1; - info->status.rates[0].count = 0; - - ieee80211_tx_status_ni(wl->hw, skb); - } - } -} - -#define WL1271_TX_FLUSH_TIMEOUT 500000 - -/* caller must *NOT* hold wl->mutex */ -void wl1271_tx_flush(struct wl1271 *wl) -{ - unsigned long timeout; - int i; - timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT); - - while (!time_after(jiffies, timeout)) { - mutex_lock(&wl->mutex); - wl1271_debug(DEBUG_TX, "flushing tx buffer: %d %d", - wl->tx_frames_cnt, - wl1271_tx_total_queue_count(wl)); - if ((wl->tx_frames_cnt == 0) && - (wl1271_tx_total_queue_count(wl) == 0)) { - mutex_unlock(&wl->mutex); - return; - } - mutex_unlock(&wl->mutex); - msleep(1); - } - - wl1271_warning("Unable to flush all TX buffers, timed out."); - - /* forcibly flush all Tx buffers on our queues */ - mutex_lock(&wl->mutex); - for (i = 0; i < WL12XX_MAX_LINKS; i++) - wl1271_tx_reset_link_queues(wl, i); - mutex_unlock(&wl->mutex); -} - -u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set) -{ - if (WARN_ON(!rate_set)) - return 0; - - return BIT(__ffs(rate_set)); -} diff --git a/trunk/drivers/net/wireless/wl12xx/wl12xx.h b/trunk/drivers/net/wireless/wl12xx/wl12xx.h deleted file mode 100644 index 749a15a75d38..000000000000 --- a/trunk/drivers/net/wireless/wl12xx/wl12xx.h +++ /dev/null @@ -1,695 +0,0 @@ -/* - * This file is part of wl1271 - * - * Copyright (C) 1998-2009 Texas Instruments. All rights reserved. - * Copyright (C) 2008-2009 Nokia Corporation - * - * Contact: Luciano Coelho - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL12XX_H__ -#define __WL12XX_H__ - -#include -#include -#include -#include -#include -#include - -#include "conf.h" -#include "ini.h" - -#define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-4-mr.bin" -#define WL127X_FW_NAME_SINGLE "ti-connectivity/wl127x-fw-4-sr.bin" - -#define WL128X_FW_NAME_MULTI "ti-connectivity/wl128x-fw-4-mr.bin" -#define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-4-sr.bin" - -#define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-4-plt.bin" -#define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-4-plt.bin" - -/* - * wl127x and wl128x are using the same NVS file name. However, the - * ini parameters between them are different. The driver validates - * the correct NVS size in wl1271_boot_upload_nvs(). - */ -#define WL12XX_NVS_NAME "ti-connectivity/wl1271-nvs.bin" - -#define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff)) -#define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff)) -#define WL1271_TX_SQN_POST_RECOVERY_PADDING 0xff - -#define WL1271_CIPHER_SUITE_GEM 0x00147201 - -#define WL1271_BUSY_WORD_CNT 1 -#define WL1271_BUSY_WORD_LEN (WL1271_BUSY_WORD_CNT * sizeof(u32)) - -#define WL1271_ELP_HW_STATE_ASLEEP 0 -#define WL1271_ELP_HW_STATE_IRQ 1 - -#define WL1271_DEFAULT_BEACON_INT 100 -#define WL1271_DEFAULT_DTIM_PERIOD 1 - -#define WL12XX_MAX_ROLES 4 -#define WL12XX_MAX_LINKS 12 -#define WL12XX_INVALID_ROLE_ID 0xff -#define WL12XX_INVALID_LINK_ID 0xff - -#define WL12XX_MAX_RATE_POLICIES 16 - -/* Defined by FW as 0. Will not be freed or allocated. */ -#define WL12XX_SYSTEM_HLID 0 - -/* - * When in AP-mode, we allow (at least) this number of packets - * to be transmitted to FW for a STA in PS-mode. Only when packets are - * present in the FW buffers it will wake the sleeping STA. We want to put - * enough packets for the driver to transmit all of its buffered data before - * the STA goes to sleep again. But we don't want to take too much memory - * as it might hurt the throughput of active STAs. - */ -#define WL1271_PS_STA_MAX_PACKETS 2 - -#define WL1271_AP_BSS_INDEX 0 -#define WL1271_AP_DEF_BEACON_EXP 20 - -#define ACX_TX_DESCRIPTORS 16 - -#define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE) - -enum wl1271_state { - WL1271_STATE_OFF, - WL1271_STATE_ON, -}; - -enum wl12xx_fw_type { - WL12XX_FW_TYPE_NONE, - WL12XX_FW_TYPE_NORMAL, - WL12XX_FW_TYPE_MULTI, - WL12XX_FW_TYPE_PLT, -}; - -enum wl1271_partition_type { - PART_DOWN, - PART_WORK, - PART_DRPW, - - PART_TABLE_LEN -}; - -struct wl1271_partition { - u32 size; - u32 start; -}; - -struct wl1271_partition_set { - struct wl1271_partition mem; - struct wl1271_partition reg; - struct wl1271_partition mem2; - struct wl1271_partition mem3; -}; - -struct wl1271; - -enum { - FW_VER_CHIP, - FW_VER_IF_TYPE, - FW_VER_MAJOR, - FW_VER_SUBTYPE, - FW_VER_MINOR, - - NUM_FW_VER -}; - -#define FW_VER_CHIP_WL127X 6 -#define FW_VER_CHIP_WL128X 7 - -#define FW_VER_IF_TYPE_STA 1 -#define FW_VER_IF_TYPE_AP 2 - -#define FW_VER_MINOR_1_SPARE_STA_MIN 58 -#define FW_VER_MINOR_1_SPARE_AP_MIN 47 - -#define FW_VER_MINOR_FWLOG_STA_MIN 70 - -struct wl1271_chip { - u32 id; - char fw_ver_str[ETHTOOL_BUSINFO_LEN]; - unsigned int fw_ver[NUM_FW_VER]; -}; - -struct wl1271_stats { - struct acx_statistics *fw_stats; - unsigned long fw_stats_update; - - unsigned int retry_count; - unsigned int excessive_retries; -}; - -#define NUM_TX_QUEUES 4 -#define NUM_RX_PKT_DESC 8 - -#define AP_MAX_STATIONS 8 - -/* FW status registers */ -struct wl12xx_fw_status { - __le32 intr; - u8 fw_rx_counter; - u8 drv_rx_counter; - u8 reserved; - u8 tx_results_counter; - __le32 rx_pkt_descs[NUM_RX_PKT_DESC]; - __le32 fw_localtime; - - /* - * A bitmap (where each bit represents a single HLID) - * to indicate if the station is in PS mode. - */ - __le32 link_ps_bitmap; - - /* - * A bitmap (where each bit represents a single HLID) to indicate - * if the station is in Fast mode - */ - __le32 link_fast_bitmap; - - /* Cumulative counter of total released mem blocks since FW-reset */ - __le32 total_released_blks; - - /* Size (in Memory Blocks) of TX pool */ - __le32 tx_total; - - /* Cumulative counter of released packets per AC */ - u8 tx_released_pkts[NUM_TX_QUEUES]; - - /* Cumulative counter of freed packets per HLID */ - u8 tx_lnk_free_pkts[WL12XX_MAX_LINKS]; - - /* Cumulative counter of released Voice memory blocks */ - u8 tx_voice_released_blks; - u8 padding_1[3]; - __le32 log_start_addr; -} __packed; - -struct wl1271_rx_mem_pool_addr { - u32 addr; - u32 addr_extra; -}; - -#define WL1271_MAX_CHANNELS 64 -struct wl1271_scan { - struct cfg80211_scan_request *req; - unsigned long scanned_ch[BITS_TO_LONGS(WL1271_MAX_CHANNELS)]; - bool failed; - u8 state; - u8 ssid[IEEE80211_MAX_SSID_LEN+1]; - size_t ssid_len; -}; - -struct wl1271_if_operations { - void (*read)(struct device *child, int addr, void *buf, size_t len, - bool fixed); - void (*write)(struct device *child, int addr, void *buf, size_t len, - bool fixed); - void (*reset)(struct device *child); - void (*init)(struct device *child); - int (*power)(struct device *child, bool enable); - void (*set_block_size) (struct device *child, unsigned int blksz); -}; - -#define MAX_NUM_KEYS 14 -#define MAX_KEY_SIZE 32 - -struct wl1271_ap_key { - u8 id; - u8 key_type; - u8 key_size; - u8 key[MAX_KEY_SIZE]; - u8 hlid; - u32 tx_seq_32; - u16 tx_seq_16; -}; - -enum wl12xx_flags { - WL1271_FLAG_GPIO_POWER, - WL1271_FLAG_TX_QUEUE_STOPPED, - WL1271_FLAG_TX_PENDING, - WL1271_FLAG_IN_ELP, - WL1271_FLAG_ELP_REQUESTED, - WL1271_FLAG_IRQ_RUNNING, - WL1271_FLAG_FW_TX_BUSY, - WL1271_FLAG_DUMMY_PACKET_PENDING, - WL1271_FLAG_SUSPENDED, - WL1271_FLAG_PENDING_WORK, - WL1271_FLAG_SOFT_GEMINI, - WL1271_FLAG_RECOVERY_IN_PROGRESS, - WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, - WL1271_FLAG_INTENDED_FW_RECOVERY, -}; - -enum wl12xx_vif_flags { - WLVIF_FLAG_INITIALIZED, - WLVIF_FLAG_STA_ASSOCIATED, - WLVIF_FLAG_STA_AUTHORIZED, - WLVIF_FLAG_IBSS_JOINED, - WLVIF_FLAG_AP_STARTED, - WLVIF_FLAG_IN_PS, - WLVIF_FLAG_STA_STATE_SENT, - WLVIF_FLAG_RX_STREAMING_STARTED, - WLVIF_FLAG_PSPOLL_FAILURE, - WLVIF_FLAG_CS_PROGRESS, - WLVIF_FLAG_AP_PROBE_RESP_SET, - WLVIF_FLAG_IN_USE, -}; - -struct wl1271_link { - /* AP-mode - TX queue per AC in link */ - struct sk_buff_head tx_queue[NUM_TX_QUEUES]; - - /* accounting for allocated / freed packets in FW */ - u8 allocated_pkts; - u8 prev_freed_pkts; - - u8 addr[ETH_ALEN]; - - /* bitmap of TIDs where RX BA sessions are active for this link */ - u8 ba_bitmap; -}; - -struct wl1271 { - struct ieee80211_hw *hw; - bool mac80211_registered; - - struct device *dev; - - void *if_priv; - - struct wl1271_if_operations *if_ops; - - void (*set_power)(bool enable); - int irq; - int ref_clock; - - spinlock_t wl_lock; - - enum wl1271_state state; - enum wl12xx_fw_type fw_type; - bool plt; - u8 last_vif_count; - struct mutex mutex; - - unsigned long flags; - - struct wl1271_partition_set part; - - struct wl1271_chip chip; - - int cmd_box_addr; - int event_box_addr; - - u8 *fw; - size_t fw_len; - void *nvs; - size_t nvs_len; - - s8 hw_pg_ver; - - /* address read from the fuse ROM */ - u32 fuse_oui_addr; - u32 fuse_nic_addr; - - /* we have up to 2 MAC addresses */ - struct mac_address addresses[2]; - int channel; - u8 system_hlid; - - unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)]; - unsigned long roles_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)]; - unsigned long roc_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)]; - unsigned long rate_policies_map[ - BITS_TO_LONGS(WL12XX_MAX_RATE_POLICIES)]; - - struct list_head wlvif_list; - - u8 sta_count; - u8 ap_count; - - struct wl1271_acx_mem_map *target_mem_map; - - /* Accounting for allocated / available TX blocks on HW */ - u32 tx_blocks_freed; - u32 tx_blocks_available; - u32 tx_allocated_blocks; - u32 tx_results_count; - - /* amount of spare TX blocks to use */ - u32 tx_spare_blocks; - - /* Accounting for allocated / available Tx packets in HW */ - u32 tx_pkts_freed[NUM_TX_QUEUES]; - u32 tx_allocated_pkts[NUM_TX_QUEUES]; - - /* Transmitted TX packets counter for chipset interface */ - u32 tx_packets_count; - - /* Time-offset between host and chipset clocks */ - s64 time_offset; - - /* Frames scheduled for transmission, not handled yet */ - int tx_queue_count[NUM_TX_QUEUES]; - long stopped_queues_map; - - /* Frames received, not handled yet by mac80211 */ - struct sk_buff_head deferred_rx_queue; - - /* Frames sent, not returned yet to mac80211 */ - struct sk_buff_head deferred_tx_queue; - - struct work_struct tx_work; - struct workqueue_struct *freezable_wq; - - /* Pending TX frames */ - unsigned long tx_frames_map[BITS_TO_LONGS(ACX_TX_DESCRIPTORS)]; - struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS]; - int tx_frames_cnt; - - /* FW Rx counter */ - u32 rx_counter; - - /* Rx memory pool address */ - struct wl1271_rx_mem_pool_addr rx_mem_pool_addr; - - /* Intermediate buffer, used for packet aggregation */ - u8 *aggr_buf; - - /* Reusable dummy packet template */ - struct sk_buff *dummy_packet; - - /* Network stack work */ - struct work_struct netstack_work; - - /* FW log buffer */ - u8 *fwlog; - - /* Number of valid bytes in the FW log buffer */ - ssize_t fwlog_size; - - /* Sysfs FW log entry readers wait queue */ - wait_queue_head_t fwlog_waitq; - - /* Hardware recovery work */ - struct work_struct recovery_work; - - /* The mbox event mask */ - u32 event_mask; - - /* Mailbox pointers */ - u32 mbox_ptr[2]; - - /* Are we currently scanning */ - struct ieee80211_vif *scan_vif; - struct wl1271_scan scan; - struct delayed_work scan_complete_work; - - bool sched_scanning; - - /* The current band */ - enum ieee80211_band band; - - struct completion *elp_compl; - struct delayed_work elp_work; - - /* in dBm */ - int power_level; - - struct wl1271_stats stats; - - __le32 buffer_32; - u32 buffer_cmd; - u32 buffer_busyword[WL1271_BUSY_WORD_CNT]; - - struct wl12xx_fw_status *fw_status; - struct wl1271_tx_hw_res_if *tx_res_if; - - /* Current chipset configuration */ - struct conf_drv_settings conf; - - bool sg_enabled; - - bool enable_11a; - - /* Most recently reported noise in dBm */ - s8 noise; - - /* bands supported by this instance of wl12xx */ - struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; - - int tcxo_clock; - - /* - * wowlan trigger was configured during suspend. - * (currently, only "ANY" trigger is supported) - */ - bool wow_enabled; - bool irq_wake_enabled; - - /* - * AP-mode - links indexed by HLID. The global and broadcast links - * are always active. - */ - struct wl1271_link links[WL12XX_MAX_LINKS]; - - /* AP-mode - a bitmap of links currently in PS mode according to FW */ - u32 ap_fw_ps_map; - - /* AP-mode - a bitmap of links currently in PS mode in mac80211 */ - unsigned long ap_ps_map; - - /* Quirks of specific hardware revisions */ - unsigned int quirks; - - /* Platform limitations */ - unsigned int platform_quirks; - - /* number of currently active RX BA sessions */ - int ba_rx_session_count; - - /* AP-mode - number of currently connected stations */ - int active_sta_count; - - /* last wlvif we transmitted from */ - struct wl12xx_vif *last_wlvif; - - /* work to fire when Tx is stuck */ - struct delayed_work tx_watchdog_work; -}; - -struct wl1271_station { - u8 hlid; -}; - -struct wl12xx_vif { - struct wl1271 *wl; - struct list_head list; - unsigned long flags; - u8 bss_type; - u8 p2p; /* we are using p2p role */ - u8 role_id; - - /* sta/ibss specific */ - u8 dev_role_id; - u8 dev_hlid; - - union { - struct { - u8 hlid; - u8 ba_rx_bitmap; - - u8 basic_rate_idx; - u8 ap_rate_idx; - u8 p2p_rate_idx; - - bool qos; - } sta; - struct { - u8 global_hlid; - u8 bcast_hlid; - - /* HLIDs bitmap of associated stations */ - unsigned long sta_hlid_map[BITS_TO_LONGS( - WL12XX_MAX_LINKS)]; - - /* recoreded keys - set here before AP startup */ - struct wl1271_ap_key *recorded_keys[MAX_NUM_KEYS]; - - u8 mgmt_rate_idx; - u8 bcast_rate_idx; - u8 ucast_rate_idx[CONF_TX_MAX_AC_COUNT]; - } ap; - }; - - /* the hlid of the last transmitted skb */ - int last_tx_hlid; - - unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)]; - - u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; - u8 ssid_len; - - /* The current band */ - enum ieee80211_band band; - int channel; - - u32 bitrate_masks[IEEE80211_NUM_BANDS]; - u32 basic_rate_set; - - /* - * currently configured rate set: - * bits 0-15 - 802.11abg rates - * bits 16-23 - 802.11n MCS index mask - * support only 1 stream, thus only 8 bits for the MCS rates (0-7). - */ - u32 basic_rate; - u32 rate_set; - - /* probe-req template for the current AP */ - struct sk_buff *probereq; - - /* Beaconing interval (needed for ad-hoc) */ - u32 beacon_int; - - /* Default key (for WEP) */ - u32 default_key; - - /* Our association ID */ - u16 aid; - - /* Session counter for the chipset */ - int session_counter; - - /* retry counter for PSM entries */ - u8 psm_entry_retry; - - /* in dBm */ - int power_level; - - int rssi_thold; - int last_rssi_event; - - /* save the current encryption type for auto-arp config */ - u8 encryption_type; - __be32 ip_addr; - - /* RX BA constraint value */ - bool ba_support; - bool ba_allowed; - - /* Rx Streaming */ - struct work_struct rx_streaming_enable_work; - struct work_struct rx_streaming_disable_work; - struct timer_list rx_streaming_timer; - - /* - * This struct must be last! - * data that has to be saved acrossed reconfigs (e.g. recovery) - * should be declared in this struct. - */ - struct { - u8 persistent[0]; - /* - * Security sequence number - * bits 0-15: lower 16 bits part of sequence number - * bits 16-47: higher 32 bits part of sequence number - * bits 48-63: not in use - */ - u64 tx_security_seq; - - /* 8 bits of the last sequence number in use */ - u8 tx_security_last_seq_lsb; - }; -}; - -static inline struct wl12xx_vif *wl12xx_vif_to_data(struct ieee80211_vif *vif) -{ - return (struct wl12xx_vif *)vif->drv_priv; -} - -static inline -struct ieee80211_vif *wl12xx_wlvif_to_vif(struct wl12xx_vif *wlvif) -{ - return container_of((void *)wlvif, struct ieee80211_vif, drv_priv); -} - -#define wl12xx_for_each_wlvif(wl, wlvif) \ - list_for_each_entry(wlvif, &wl->wlvif_list, list) - -#define wl12xx_for_each_wlvif_continue(wl, wlvif) \ - list_for_each_entry_continue(wlvif, &wl->wlvif_list, list) - -#define wl12xx_for_each_wlvif_bss_type(wl, wlvif, _bss_type) \ - wl12xx_for_each_wlvif(wl, wlvif) \ - if (wlvif->bss_type == _bss_type) - -#define wl12xx_for_each_wlvif_sta(wl, wlvif) \ - wl12xx_for_each_wlvif_bss_type(wl, wlvif, BSS_TYPE_STA_BSS) - -#define wl12xx_for_each_wlvif_ap(wl, wlvif) \ - wl12xx_for_each_wlvif_bss_type(wl, wlvif, BSS_TYPE_AP_BSS) - -int wl1271_plt_start(struct wl1271 *wl); -int wl1271_plt_stop(struct wl1271 *wl); -int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif); -void wl12xx_queue_recovery_work(struct wl1271 *wl); -size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen); - -#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ - -#define SESSION_COUNTER_MAX 6 /* maximum value for the session counter */ -#define SESSION_COUNTER_INVALID 7 /* used with dummy_packet */ - -#define WL1271_DEFAULT_POWER_LEVEL 0 - -#define WL1271_TX_QUEUE_LOW_WATERMARK 32 -#define WL1271_TX_QUEUE_HIGH_WATERMARK 256 - -#define WL1271_DEFERRED_QUEUE_LIMIT 64 - -/* WL1271 needs a 200ms sleep after power on, and a 20ms sleep before power - on in case is has been shut down shortly before */ -#define WL1271_PRE_POWER_ON_SLEEP 20 /* in milliseconds */ -#define WL1271_POWER_ON_SLEEP 200 /* in milliseconds */ - -/* Macros to handle wl1271.sta_rate_set */ -#define HW_BG_RATES_MASK 0xffff -#define HW_HT_RATES_OFFSET 16 - -/* Quirks */ - -/* Each RX/TX transaction requires an end-of-transaction transfer */ -#define WL12XX_QUIRK_END_OF_TRANSACTION BIT(0) - -/* wl127x and SPI don't support SDIO block size alignment */ -#define WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT BIT(2) - -/* Older firmwares did not implement the FW logger over bus feature */ -#define WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED BIT(4) - -#define WL12XX_HW_BLOCK_SIZE 256 - -#endif diff --git a/trunk/drivers/net/wireless/zd1201.c b/trunk/drivers/net/wireless/zd1201.c index a66b93b7ff9a..48273dd05b63 100644 --- a/trunk/drivers/net/wireless/zd1201.c +++ b/trunk/drivers/net/wireless/zd1201.c @@ -1905,6 +1905,7 @@ static struct usb_driver zd1201_usb = { .id_table = zd1201_table, .suspend = zd1201_suspend, .resume = zd1201_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(zd1201_usb); diff --git a/trunk/drivers/net/wireless/zd1211rw/zd_usb.c b/trunk/drivers/net/wireless/zd1211rw/zd_usb.c index f766b3e67c6d..af83c43bcdb1 100644 --- a/trunk/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/trunk/drivers/net/wireless/zd1211rw/zd_usb.c @@ -1542,6 +1542,7 @@ static struct usb_driver driver = { .disconnect = disconnect, .pre_reset = pre_reset, .post_reset = post_reset, + .disable_hub_initiated_lpm = 1, }; struct workqueue_struct *zd_workqueue; diff --git a/trunk/drivers/nfc/pn533.c b/trunk/drivers/nfc/pn533.c index cb6204f78300..e6ec16d92e65 100644 --- a/trunk/drivers/nfc/pn533.c +++ b/trunk/drivers/nfc/pn533.c @@ -266,9 +266,13 @@ struct pn533 { int in_maxlen; struct pn533_frame *in_frame; - struct tasklet_struct tasklet; - struct pn533_frame *tklt_in_frame; - int tklt_in_error; + struct sk_buff_head resp_q; + + struct workqueue_struct *wq; + struct work_struct cmd_work; + struct work_struct mi_work; + struct pn533_frame *wq_in_frame; + int wq_in_error; pn533_cmd_complete_t cmd_complete; void *cmd_complete_arg; @@ -383,15 +387,21 @@ static bool pn533_rx_frame_is_cmd_response(struct pn533_frame *frame, u8 cmd) return (PN533_FRAME_CMD(frame) == PN533_CMD_RESPONSE(cmd)); } -static void pn533_tasklet_cmd_complete(unsigned long arg) + +static void pn533_wq_cmd_complete(struct work_struct *work) { - struct pn533 *dev = (struct pn533 *) arg; - struct pn533_frame *in_frame = dev->tklt_in_frame; + struct pn533 *dev = container_of(work, struct pn533, cmd_work); + struct pn533_frame *in_frame; int rc; - if (dev->tklt_in_error) + if (dev == NULL) + return; + + in_frame = dev->wq_in_frame; + + if (dev->wq_in_error) rc = dev->cmd_complete(dev, dev->cmd_complete_arg, NULL, - dev->tklt_in_error); + dev->wq_in_error); else rc = dev->cmd_complete(dev, dev->cmd_complete_arg, PN533_FRAME_CMD_PARAMS_PTR(in_frame), @@ -406,7 +416,7 @@ static void pn533_recv_response(struct urb *urb) struct pn533 *dev = urb->context; struct pn533_frame *in_frame; - dev->tklt_in_frame = NULL; + dev->wq_in_frame = NULL; switch (urb->status) { case 0: @@ -417,36 +427,36 @@ static void pn533_recv_response(struct urb *urb) case -ESHUTDOWN: nfc_dev_dbg(&dev->interface->dev, "Urb shutting down with" " status: %d", urb->status); - dev->tklt_in_error = urb->status; - goto sched_tasklet; + dev->wq_in_error = urb->status; + goto sched_wq; default: nfc_dev_err(&dev->interface->dev, "Nonzero urb status received:" " %d", urb->status); - dev->tklt_in_error = urb->status; - goto sched_tasklet; + dev->wq_in_error = urb->status; + goto sched_wq; } in_frame = dev->in_urb->transfer_buffer; if (!pn533_rx_frame_is_valid(in_frame)) { nfc_dev_err(&dev->interface->dev, "Received an invalid frame"); - dev->tklt_in_error = -EIO; - goto sched_tasklet; + dev->wq_in_error = -EIO; + goto sched_wq; } if (!pn533_rx_frame_is_cmd_response(in_frame, dev->cmd)) { nfc_dev_err(&dev->interface->dev, "The received frame is not " "response to the last command"); - dev->tklt_in_error = -EIO; - goto sched_tasklet; + dev->wq_in_error = -EIO; + goto sched_wq; } nfc_dev_dbg(&dev->interface->dev, "Received a valid frame"); - dev->tklt_in_error = 0; - dev->tklt_in_frame = in_frame; + dev->wq_in_error = 0; + dev->wq_in_frame = in_frame; -sched_tasklet: - tasklet_schedule(&dev->tasklet); +sched_wq: + queue_work(dev->wq, &dev->cmd_work); } static int pn533_submit_urb_for_response(struct pn533 *dev, gfp_t flags) @@ -471,21 +481,21 @@ static void pn533_recv_ack(struct urb *urb) case -ESHUTDOWN: nfc_dev_dbg(&dev->interface->dev, "Urb shutting down with" " status: %d", urb->status); - dev->tklt_in_error = urb->status; - goto sched_tasklet; + dev->wq_in_error = urb->status; + goto sched_wq; default: nfc_dev_err(&dev->interface->dev, "Nonzero urb status received:" " %d", urb->status); - dev->tklt_in_error = urb->status; - goto sched_tasklet; + dev->wq_in_error = urb->status; + goto sched_wq; } in_frame = dev->in_urb->transfer_buffer; if (!pn533_rx_frame_is_ack(in_frame)) { nfc_dev_err(&dev->interface->dev, "Received an invalid ack"); - dev->tklt_in_error = -EIO; - goto sched_tasklet; + dev->wq_in_error = -EIO; + goto sched_wq; } nfc_dev_dbg(&dev->interface->dev, "Received a valid ack"); @@ -494,15 +504,15 @@ static void pn533_recv_ack(struct urb *urb) if (rc) { nfc_dev_err(&dev->interface->dev, "usb_submit_urb failed with" " result %d", rc); - dev->tklt_in_error = rc; - goto sched_tasklet; + dev->wq_in_error = rc; + goto sched_wq; } return; -sched_tasklet: - dev->tklt_in_frame = NULL; - tasklet_schedule(&dev->tasklet); +sched_wq: + dev->wq_in_frame = NULL; + queue_work(dev->wq, &dev->cmd_work); } static int pn533_submit_urb_for_ack(struct pn533 *dev, gfp_t flags) @@ -1249,6 +1259,8 @@ static void pn533_deactivate_target(struct nfc_dev *nfc_dev, u32 target_idx) dev->tgt_active_prot = 0; + skb_queue_purge(&dev->resp_q); + pn533_tx_frame_init(dev->out_frame, PN533_CMD_IN_RELEASE); tg = 1; @@ -1447,11 +1459,49 @@ struct pn533_data_exchange_arg { void *cb_context; }; +static struct sk_buff *pn533_build_response(struct pn533 *dev) +{ + struct sk_buff *skb, *tmp, *t; + unsigned int skb_len = 0, tmp_len = 0; + + nfc_dev_dbg(&dev->interface->dev, "%s\n", __func__); + + if (skb_queue_empty(&dev->resp_q)) + return NULL; + + if (skb_queue_len(&dev->resp_q) == 1) { + skb = skb_dequeue(&dev->resp_q); + goto out; + } + + skb_queue_walk_safe(&dev->resp_q, tmp, t) + skb_len += tmp->len; + + nfc_dev_dbg(&dev->interface->dev, "%s total length %d\n", + __func__, skb_len); + + skb = alloc_skb(skb_len, GFP_KERNEL); + if (skb == NULL) + goto out; + + skb_put(skb, skb_len); + + skb_queue_walk_safe(&dev->resp_q, tmp, t) { + memcpy(skb->data + tmp_len, tmp->data, tmp->len); + tmp_len += tmp->len; + } + +out: + skb_queue_purge(&dev->resp_q); + + return skb; +} + static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg, u8 *params, int params_len) { struct pn533_data_exchange_arg *arg = _arg; - struct sk_buff *skb_resp = arg->skb_resp; + struct sk_buff *skb = NULL, *skb_resp = arg->skb_resp; struct pn533_frame *in_frame = (struct pn533_frame *) skb_resp->data; int err = 0; u8 status; @@ -1459,15 +1509,13 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg, nfc_dev_dbg(&dev->interface->dev, "%s", __func__); - dev_kfree_skb_irq(arg->skb_out); + dev_kfree_skb(arg->skb_out); if (params_len < 0) { /* error */ err = params_len; goto error; } - skb_put(skb_resp, PN533_FRAME_SIZE(in_frame)); - status = params[0]; cmd_ret = status & PN533_CMD_RET_MASK; @@ -1478,25 +1526,27 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg, goto error; } + skb_put(skb_resp, PN533_FRAME_SIZE(in_frame)); + skb_pull(skb_resp, PN533_CMD_DATAEXCH_HEAD_LEN); + skb_trim(skb_resp, skb_resp->len - PN533_FRAME_TAIL_SIZE); + skb_queue_tail(&dev->resp_q, skb_resp); + if (status & PN533_CMD_MI_MASK) { - /* TODO: Implement support to multi-part data exchange */ - nfc_dev_err(&dev->interface->dev, "Multi-part message not yet" - " supported"); - /* Prevent the other messages from controller */ - pn533_send_ack(dev, GFP_ATOMIC); - err = -ENOSYS; - goto error; + queue_work(dev->wq, &dev->mi_work); + return -EINPROGRESS; } - skb_pull(skb_resp, PN533_CMD_DATAEXCH_HEAD_LEN); - skb_trim(skb_resp, skb_resp->len - PN533_FRAME_TAIL_SIZE); + skb = pn533_build_response(dev); + if (skb == NULL) + goto error; - arg->cb(arg->cb_context, skb_resp, 0); + arg->cb(arg->cb_context, skb, 0); kfree(arg); return 0; error: - dev_kfree_skb_irq(skb_resp); + skb_queue_purge(&dev->resp_q); + dev_kfree_skb(skb_resp); arg->cb(arg->cb_context, NULL, err); kfree(arg); return 0; @@ -1571,6 +1621,68 @@ static int pn533_data_exchange(struct nfc_dev *nfc_dev, u32 target_idx, return rc; } +static void pn533_wq_mi_recv(struct work_struct *work) +{ + struct pn533 *dev = container_of(work, struct pn533, mi_work); + struct sk_buff *skb_cmd; + struct pn533_data_exchange_arg *arg = dev->cmd_complete_arg; + struct pn533_frame *out_frame, *in_frame; + struct sk_buff *skb_resp; + int skb_resp_len; + int rc; + + nfc_dev_dbg(&dev->interface->dev, "%s", __func__); + + /* This is a zero payload size skb */ + skb_cmd = alloc_skb(PN533_CMD_DATAEXCH_HEAD_LEN + PN533_FRAME_TAIL_SIZE, + GFP_KERNEL); + if (skb_cmd == NULL) + goto error_cmd; + + skb_reserve(skb_cmd, PN533_CMD_DATAEXCH_HEAD_LEN); + + rc = pn533_data_exchange_tx_frame(dev, skb_cmd); + if (rc) + goto error_frame; + + skb_resp_len = PN533_CMD_DATAEXCH_HEAD_LEN + + PN533_CMD_DATAEXCH_DATA_MAXLEN + + PN533_FRAME_TAIL_SIZE; + skb_resp = alloc_skb(skb_resp_len, GFP_KERNEL); + if (!skb_resp) { + rc = -ENOMEM; + goto error_frame; + } + + in_frame = (struct pn533_frame *) skb_resp->data; + out_frame = (struct pn533_frame *) skb_cmd->data; + + arg->skb_resp = skb_resp; + arg->skb_out = skb_cmd; + + rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame, + skb_resp_len, + pn533_data_exchange_complete, + dev->cmd_complete_arg, GFP_KERNEL); + if (!rc) + return; + + nfc_dev_err(&dev->interface->dev, "Error %d when trying to" + " perform data_exchange", rc); + + kfree_skb(skb_resp); + +error_frame: + kfree_skb(skb_cmd); + +error_cmd: + pn533_send_ack(dev, GFP_KERNEL); + + kfree(arg); + + up(&dev->cmd_lock); +} + static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata, u8 cfgdata_len) { @@ -1668,7 +1780,15 @@ static int pn533_probe(struct usb_interface *interface, NULL, 0, pn533_send_complete, dev); - tasklet_init(&dev->tasklet, pn533_tasklet_cmd_complete, (ulong)dev); + INIT_WORK(&dev->cmd_work, pn533_wq_cmd_complete); + INIT_WORK(&dev->mi_work, pn533_wq_mi_recv); + dev->wq = alloc_workqueue("pn533", + WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM, + 1); + if (dev->wq == NULL) + goto error; + + skb_queue_head_init(&dev->resp_q); usb_set_intfdata(interface, dev); @@ -1678,7 +1798,7 @@ static int pn533_probe(struct usb_interface *interface, rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame, dev->in_maxlen); if (rc) - goto kill_tasklet; + goto destroy_wq; fw_ver = (struct pn533_fw_version *) PN533_FRAME_CMD_PARAMS_PTR(dev->in_frame); @@ -1694,7 +1814,7 @@ static int pn533_probe(struct usb_interface *interface, PN533_CMD_DATAEXCH_HEAD_LEN, PN533_FRAME_TAIL_SIZE); if (!dev->nfc_dev) - goto kill_tasklet; + goto destroy_wq; nfc_set_parent_dev(dev->nfc_dev, &interface->dev); nfc_set_drvdata(dev->nfc_dev, dev); @@ -1720,8 +1840,8 @@ static int pn533_probe(struct usb_interface *interface, free_nfc_dev: nfc_free_device(dev->nfc_dev); -kill_tasklet: - tasklet_kill(&dev->tasklet); +destroy_wq: + destroy_workqueue(dev->wq); error: kfree(dev->in_frame); usb_free_urb(dev->in_urb); @@ -1744,7 +1864,9 @@ static void pn533_disconnect(struct usb_interface *interface) usb_kill_urb(dev->in_urb); usb_kill_urb(dev->out_urb); - tasklet_kill(&dev->tasklet); + destroy_workqueue(dev->wq); + + skb_queue_purge(&dev->resp_q); kfree(dev->in_frame); usb_free_urb(dev->in_urb); diff --git a/trunk/drivers/of/address.c b/trunk/drivers/of/address.c index 66d96f14c274..7e262a6124c5 100644 --- a/trunk/drivers/of/address.c +++ b/trunk/drivers/of/address.c @@ -1,4 +1,5 @@ +#include #include #include #include diff --git a/trunk/drivers/of/base.c b/trunk/drivers/of/base.c index 580644986945..d9bfd49b1935 100644 --- a/trunk/drivers/of/base.c +++ b/trunk/drivers/of/base.c @@ -1260,3 +1260,44 @@ int of_alias_get_id(struct device_node *np, const char *stem) return id; } EXPORT_SYMBOL_GPL(of_alias_get_id); + +const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur, + u32 *pu) +{ + const void *curv = cur; + + if (!prop) + return NULL; + + if (!cur) { + curv = prop->value; + goto out_val; + } + + curv += sizeof(*cur); + if (curv >= prop->value + prop->length) + return NULL; + +out_val: + *pu = be32_to_cpup(curv); + return curv; +} +EXPORT_SYMBOL_GPL(of_prop_next_u32); + +const char *of_prop_next_string(struct property *prop, const char *cur) +{ + const void *curv = cur; + + if (!prop) + return NULL; + + if (!cur) + return prop->value; + + curv += strlen(cur) + 1; + if (curv >= prop->value + prop->length) + return NULL; + + return curv; +} +EXPORT_SYMBOL_GPL(of_prop_next_string); diff --git a/trunk/drivers/of/of_mdio.c b/trunk/drivers/of/of_mdio.c index 483c0adcad87..2574abde8d99 100644 --- a/trunk/drivers/of/of_mdio.c +++ b/trunk/drivers/of/of_mdio.c @@ -45,6 +45,8 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) for (i=0; iirq[i] = PHY_POLL; + mdio->dev.of_node = np; + /* Register the MDIO bus */ rc = mdiobus_register(mdio); if (rc) diff --git a/trunk/drivers/parisc/superio.c b/trunk/drivers/parisc/superio.c index e3b76d409dee..5003458980d3 100644 --- a/trunk/drivers/parisc/superio.c +++ b/trunk/drivers/parisc/superio.c @@ -348,7 +348,7 @@ int superio_fixup_irq(struct pci_dev *pcidev) BUG(); return -1; } - printk("superio_fixup_irq(%s) ven 0x%x dev 0x%x from %p\n", + printk("superio_fixup_irq(%s) ven 0x%x dev 0x%x from %pf\n", pci_name(pcidev), pcidev->vendor, pcidev->device, __builtin_return_address(0)); diff --git a/trunk/drivers/parport/parport_amiga.c b/trunk/drivers/parport/parport_amiga.c index 8bef6d60f88b..ee78e0ee6e05 100644 --- a/trunk/drivers/parport/parport_amiga.c +++ b/trunk/drivers/parport/parport_amiga.c @@ -48,23 +48,6 @@ static unsigned char amiga_read_data(struct parport *p) return ciaa.prb; } -#if 0 -static unsigned char control_pc_to_amiga(unsigned char control) -{ - unsigned char ret = 0; - - if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */ - ; - if (control & PARPORT_CONTROL_INIT) /* INITP */ - /* reset connected to cpu reset pin */; - if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */ - /* Not connected */; - if (control & PARPORT_CONTROL_STROBE) /* Strobe */ - /* Handled only directly by hardware */; - return ret; -} -#endif - static unsigned char control_amiga_to_pc(unsigned char control) { return PARPORT_CONTROL_SELECT | @@ -95,25 +78,6 @@ static unsigned char amiga_frob_control( struct parport *p, unsigned char mask, return old; } -#if 0 /* currently unused */ -static unsigned char status_pc_to_amiga(unsigned char status) -{ - unsigned char ret = 1; - - if (status & PARPORT_STATUS_BUSY) /* Busy */ - ret &= ~1; - if (status & PARPORT_STATUS_ACK) /* Ack */ - /* handled in hardware */; - if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */ - ret |= 2; - if (status & PARPORT_STATUS_SELECT) /* select */ - ret |= 4; - if (status & PARPORT_STATUS_ERROR) /* error */ - /* not connected */; - return ret; -} -#endif - static unsigned char status_amiga_to_pc(unsigned char status) { unsigned char ret = PARPORT_STATUS_BUSY | PARPORT_STATUS_ACK | PARPORT_STATUS_ERROR; diff --git a/trunk/drivers/parport/parport_atari.c b/trunk/drivers/parport/parport_atari.c index 0b28fccec03f..7ad59ac68cf6 100644 --- a/trunk/drivers/parport/parport_atari.c +++ b/trunk/drivers/parport/parport_atari.c @@ -130,15 +130,6 @@ parport_atari_data_forward(struct parport *p) static void parport_atari_data_reverse(struct parport *p) { -#if 0 /* too dangerous, can kill sound chip */ - unsigned long flags; - - local_irq_save(flags); - /* Soundchip port B as input. */ - sound_ym.rd_data_reg_sel = 7; - sound_ym.wd_data = sound_ym.rd_data_reg_sel & ~0x40; - local_irq_restore(flags); -#endif } static struct parport_operations parport_atari_ops = { diff --git a/trunk/drivers/parport/parport_mfc3.c b/trunk/drivers/parport/parport_mfc3.c index 1c0c642b3e23..7578d79b3688 100644 --- a/trunk/drivers/parport/parport_mfc3.c +++ b/trunk/drivers/parport/parport_mfc3.c @@ -147,25 +147,6 @@ DPRINTK(KERN_DEBUG "frob_control mask %02x, value %02x\n",mask,val); return old; } -#if 0 /* currently unused */ -static unsigned char status_pc_to_mfc3(unsigned char status) -{ - unsigned char ret = 1; - - if (status & PARPORT_STATUS_BUSY) /* Busy */ - ret &= ~1; - if (status & PARPORT_STATUS_ACK) /* Ack */ - ret |= 8; - if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */ - ret |= 2; - if (status & PARPORT_STATUS_SELECT) /* select */ - ret |= 4; - if (status & PARPORT_STATUS_ERROR) /* error */ - ret |= 16; - return ret; -} -#endif - static unsigned char status_mfc3_to_pc(unsigned char status) { unsigned char ret = PARPORT_STATUS_BUSY; @@ -184,14 +165,6 @@ static unsigned char status_mfc3_to_pc(unsigned char status) return ret; } -#if 0 /* currently unused */ -static void mfc3_write_status( struct parport *p, unsigned char status) -{ -DPRINTK(KERN_DEBUG "write_status %02x\n",status); - pia(p)->ppra = (pia(p)->ppra & 0xe0) | status_pc_to_mfc3(status); -} -#endif - static unsigned char mfc3_read_status(struct parport *p) { unsigned char status; @@ -201,14 +174,6 @@ DPRINTK(KERN_DEBUG "read_status %02x\n", status); return status; } -#if 0 /* currently unused */ -static void mfc3_change_mode( struct parport *p, int m) -{ - /* XXX: This port only has one mode, and I am - not sure about the corresponding PC-style mode*/ -} -#endif - static int use_cnt = 0; static irqreturn_t mfc3_interrupt(int irq, void *dev_id) diff --git a/trunk/drivers/parport/parport_pc.c b/trunk/drivers/parport/parport_pc.c index 0cb64f50cecd..5abffe58a9d2 100644 --- a/trunk/drivers/parport/parport_pc.c +++ b/trunk/drivers/parport/parport_pc.c @@ -197,54 +197,6 @@ static int change_mode(struct parport *p, int m) ECR_WRITE(p, oecr); return 0; } - -#ifdef CONFIG_PARPORT_1284 -/* Find FIFO lossage; FIFO is reset */ -#if 0 -static int get_fifo_residue(struct parport *p) -{ - int residue; - int cnfga; - const struct parport_pc_private *priv = p->physport->private_data; - - /* Adjust for the contents of the FIFO. */ - for (residue = priv->fifo_depth; ; residue--) { - if (inb(ECONTROL(p)) & 0x2) - /* Full up. */ - break; - - outb(0, FIFO(p)); - } - - printk(KERN_DEBUG "%s: %d PWords were left in FIFO\n", p->name, - residue); - - /* Reset the FIFO. */ - frob_set_mode(p, ECR_PS2); - - /* Now change to config mode and clean up. FIXME */ - frob_set_mode(p, ECR_CNF); - cnfga = inb(CONFIGA(p)); - printk(KERN_DEBUG "%s: cnfgA contains 0x%02x\n", p->name, cnfga); - - if (!(cnfga & (1<<2))) { - printk(KERN_DEBUG "%s: Accounting for extra byte\n", p->name); - residue++; - } - - /* Don't care about partial PWords until support is added for - * PWord != 1 byte. */ - - /* Back to PS2 mode. */ - frob_set_mode(p, ECR_PS2); - - DPRINTK(KERN_DEBUG - "*** get_fifo_residue: done residue collecting (ecr = 0x%2.2x)\n", - inb(ECONTROL(p))); - return residue; -} -#endif /* 0 */ -#endif /* IEEE 1284 support */ #endif /* FIFO support */ /* @@ -940,234 +892,6 @@ static size_t parport_pc_ecp_write_block_pio(struct parport *port, return written; } - -#if 0 -static size_t parport_pc_ecp_read_block_pio(struct parport *port, - void *buf, size_t length, - int flags) -{ - size_t left = length; - size_t fifofull; - int r; - const int fifo = FIFO(port); - const struct parport_pc_private *priv = port->physport->private_data; - const int fifo_depth = priv->fifo_depth; - char *bufp = buf; - - port = port->physport; - DPRINTK(KERN_DEBUG "parport_pc: parport_pc_ecp_read_block_pio\n"); - dump_parport_state("enter fcn", port); - - /* Special case: a timeout of zero means we cannot call schedule(). - * Also if O_NONBLOCK is set then use the default implementation. */ - if (port->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK) - return parport_ieee1284_ecp_read_data(port, buf, - length, flags); - - if (port->ieee1284.mode == IEEE1284_MODE_ECPRLE) { - /* If the peripheral is allowed to send RLE compressed - * data, it is possible for a byte to expand to 128 - * bytes in the FIFO. */ - fifofull = 128; - } else { - fifofull = fifo_depth; - } - - /* If the caller wants less than a full FIFO's worth of data, - * go through software emulation. Otherwise we may have to throw - * away data. */ - if (length < fifofull) - return parport_ieee1284_ecp_read_data(port, buf, - length, flags); - - if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE) { - /* change to reverse-idle phase (must be in forward-idle) */ - - /* Event 38: Set nAutoFd low (also make sure nStrobe is high) */ - parport_frob_control(port, - PARPORT_CONTROL_AUTOFD - | PARPORT_CONTROL_STROBE, - PARPORT_CONTROL_AUTOFD); - parport_pc_data_reverse(port); /* Must be in PS2 mode */ - udelay(5); - /* Event 39: Set nInit low to initiate bus reversal */ - parport_frob_control(port, - PARPORT_CONTROL_INIT, - 0); - /* Event 40: Wait for nAckReverse (PError) to go low */ - r = parport_wait_peripheral(port, PARPORT_STATUS_PAPEROUT, 0); - if (r) { - printk(KERN_DEBUG "%s: PE timeout Event 40 (%d) " - "in ecp_read_block_pio\n", port->name, r); - return 0; - } - } - - /* Set up ECP FIFO mode.*/ -/* parport_pc_frob_control(port, - PARPORT_CONTROL_STROBE | - PARPORT_CONTROL_AUTOFD, - PARPORT_CONTROL_AUTOFD); */ - r = change_mode(port, ECR_ECP); /* ECP FIFO */ - if (r) - printk(KERN_DEBUG "%s: Warning change_mode ECR_ECP failed\n", - port->name); - - port->ieee1284.phase = IEEE1284_PH_REV_DATA; - - /* the first byte must be collected manually */ - dump_parport_state("pre 43", port); - /* Event 43: Wait for nAck to go low */ - r = parport_wait_peripheral(port, PARPORT_STATUS_ACK, 0); - if (r) { - /* timed out while reading -- no data */ - printk(KERN_DEBUG "PIO read timed out (initial byte)\n"); - goto out_no_data; - } - /* read byte */ - *bufp++ = inb(DATA(port)); - left--; - dump_parport_state("43-44", port); - /* Event 44: nAutoFd (HostAck) goes high to acknowledge */ - parport_pc_frob_control(port, - PARPORT_CONTROL_AUTOFD, - 0); - dump_parport_state("pre 45", port); - /* Event 45: Wait for nAck to go high */ - /* r = parport_wait_peripheral(port, PARPORT_STATUS_ACK, - PARPORT_STATUS_ACK); */ - dump_parport_state("post 45", port); - r = 0; - if (r) { - /* timed out while waiting for peripheral to respond to ack */ - printk(KERN_DEBUG "ECP PIO read timed out (waiting for nAck)\n"); - - /* keep hold of the byte we've got already */ - goto out_no_data; - } - /* Event 46: nAutoFd (HostAck) goes low to accept more data */ - parport_pc_frob_control(port, - PARPORT_CONTROL_AUTOFD, - PARPORT_CONTROL_AUTOFD); - - - dump_parport_state("rev idle", port); - /* Do the transfer. */ - while (left > fifofull) { - int ret; - unsigned long expire = jiffies + port->cad->timeout; - unsigned char ecrval = inb(ECONTROL(port)); - - if (need_resched() && time_before(jiffies, expire)) - /* Can't yield the port. */ - schedule(); - - /* At this point, the FIFO may already be full. In - * that case ECP is already holding back the - * peripheral (assuming proper design) with a delayed - * handshake. Work fast to avoid a peripheral - * timeout. */ - - if (ecrval & 0x01) { - /* FIFO is empty. Wait for interrupt. */ - dump_parport_state("FIFO empty", port); - - /* Anyone else waiting for the port? */ - if (port->waithead) { - printk(KERN_DEBUG "Somebody wants the port\n"); - break; - } - - /* Clear serviceIntr */ - ECR_WRITE(port, ecrval & ~(1<<2)); -false_alarm: - dump_parport_state("waiting", port); - ret = parport_wait_event(port, HZ); - DPRINTK(KERN_DEBUG "parport_wait_event returned %d\n", - ret); - if (ret < 0) - break; - ret = 0; - if (!time_before(jiffies, expire)) { - /* Timed out. */ - dump_parport_state("timeout", port); - printk(KERN_DEBUG "PIO read timed out\n"); - break; - } - ecrval = inb(ECONTROL(port)); - if (!(ecrval & (1<<2))) { - if (need_resched() && - time_before(jiffies, expire)) { - schedule(); - } - goto false_alarm; - } - - /* Depending on how the FIFO threshold was - * set, how long interrupt service took, and - * how fast the peripheral is, we might be - * lucky and have a just filled FIFO. */ - continue; - } - - if (ecrval & 0x02) { - /* FIFO is full. */ - dump_parport_state("FIFO full", port); - insb(fifo, bufp, fifo_depth); - bufp += fifo_depth; - left -= fifo_depth; - continue; - } - - DPRINTK(KERN_DEBUG - "*** ecp_read_block_pio: reading one byte from the FIFO\n"); - - /* FIFO not filled. We will cycle this loop for a while - * and either the peripheral will fill it faster, - * tripping a fast empty with insb, or we empty it. */ - *bufp++ = inb(fifo); - left--; - } - - /* scoop up anything left in the FIFO */ - while (left && !(inb(ECONTROL(port) & 0x01))) { - *bufp++ = inb(fifo); - left--; - } - - port->ieee1284.phase = IEEE1284_PH_REV_IDLE; - dump_parport_state("rev idle2", port); - -out_no_data: - - /* Go to forward idle mode to shut the peripheral up (event 47). */ - parport_frob_control(port, PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT); - - /* event 49: PError goes high */ - r = parport_wait_peripheral(port, - PARPORT_STATUS_PAPEROUT, - PARPORT_STATUS_PAPEROUT); - if (r) { - printk(KERN_DEBUG - "%s: PE timeout FWDIDLE (%d) in ecp_read_block_pio\n", - port->name, r); - } - - port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; - - /* Finish up. */ - { - int lost = get_fifo_residue(port); - if (lost) - /* Shouldn't happen with compliant peripherals. */ - printk(KERN_DEBUG "%s: DATA LOSS (%d bytes)!\n", - port->name, lost); - } - - dump_parport_state("fwd idle", port); - return length - left; -} -#endif /* 0 */ #endif /* IEEE 1284 support */ #endif /* Allowed to use FIFO/DMA */ @@ -2351,7 +2075,7 @@ struct parport *parport_pc_probe_port(unsigned long int base, printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base); if (p->base_hi && priv->ecr) - printk(" (0x%lx)", p->base_hi); + printk(KERN_CONT " (0x%lx)", p->base_hi); if (p->irq == PARPORT_IRQ_AUTO) { p->irq = PARPORT_IRQ_NONE; parport_irq_probe(p); @@ -2362,7 +2086,7 @@ struct parport *parport_pc_probe_port(unsigned long int base, p->irq = PARPORT_IRQ_NONE; } if (p->irq != PARPORT_IRQ_NONE) { - printk(", irq %d", p->irq); + printk(KERN_CONT ", irq %d", p->irq); priv->ctr_writable |= 0x10; if (p->dma == PARPORT_DMA_AUTO) { @@ -2386,21 +2110,21 @@ struct parport *parport_pc_probe_port(unsigned long int base, /* p->ops->ecp_read_data = parport_pc_ecp_read_block_pio; */ #endif /* IEEE 1284 support */ if (p->dma != PARPORT_DMA_NONE) { - printk(", dma %d", p->dma); + printk(KERN_CONT ", dma %d", p->dma); p->modes |= PARPORT_MODE_DMA; } else - printk(", using FIFO"); + printk(KERN_CONT ", using FIFO"); } else /* We can't use the DMA channel after all. */ p->dma = PARPORT_DMA_NONE; #endif /* Allowed to use FIFO/DMA */ - printk(" ["); + printk(KERN_CONT " ["); #define printmode(x) \ {\ if (p->modes & PARPORT_MODE_##x) {\ - printk("%s%s", f ? "," : "", #x);\ + printk(KERN_CONT "%s%s", f ? "," : "", #x);\ f++;\ } \ } @@ -2416,9 +2140,9 @@ struct parport *parport_pc_probe_port(unsigned long int base, } #undef printmode #ifndef CONFIG_PARPORT_1284 - printk("(,...)"); + printk(KERN_CONT "(,...)"); #endif /* CONFIG_PARPORT_1284 */ - printk("]\n"); + printk(KERN_CONT "]\n"); if (probedirq != PARPORT_IRQ_NONE) printk(KERN_INFO "%s: irq %d detected\n", p->name, probedirq); diff --git a/trunk/drivers/parport/parport_sunbpp.c b/trunk/drivers/parport/parport_sunbpp.c index 9390a534a2b2..983a2d2df659 100644 --- a/trunk/drivers/parport/parport_sunbpp.c +++ b/trunk/drivers/parport/parport_sunbpp.c @@ -82,27 +82,6 @@ static unsigned char parport_sunbpp_read_data(struct parport *p) return sbus_readb(®s->p_dr); } -#if 0 -static void control_pc_to_sunbpp(struct parport *p, unsigned char status) -{ - struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base; - unsigned char value_tcr = sbus_readb(®s->p_tcr); - unsigned char value_or = sbus_readb(®s->p_or); - - if (status & PARPORT_CONTROL_STROBE) - value_tcr |= P_TCR_DS; - if (status & PARPORT_CONTROL_AUTOFD) - value_or |= P_OR_AFXN; - if (status & PARPORT_CONTROL_INIT) - value_or |= P_OR_INIT; - if (status & PARPORT_CONTROL_SELECT) - value_or |= P_OR_SLCT_IN; - - sbus_writeb(value_or, ®s->p_or); - sbus_writeb(value_tcr, ®s->p_tcr); -} -#endif - static unsigned char status_sunbpp_to_pc(struct parport *p) { struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base; diff --git a/trunk/drivers/pci/Makefile b/trunk/drivers/pci/Makefile index 165274c064bc..01c001f3b766 100644 --- a/trunk/drivers/pci/Makefile +++ b/trunk/drivers/pci/Makefile @@ -2,7 +2,7 @@ # Makefile for the PCI bus specific drivers. # -obj-y += access.o bus.o probe.o remove.o pci.o \ +obj-y += access.o bus.o probe.o host-bridge.o remove.o pci.o \ pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \ irq.o vpd.o obj-$(CONFIG_PROC_FS) += proc.o diff --git a/trunk/drivers/pci/host-bridge.c b/trunk/drivers/pci/host-bridge.c new file mode 100644 index 000000000000..a68dc613a5be --- /dev/null +++ b/trunk/drivers/pci/host-bridge.c @@ -0,0 +1,96 @@ +/* + * host bridge related code + */ + +#include +#include +#include +#include + +#include "pci.h" + +static struct pci_bus *find_pci_root_bus(struct pci_dev *dev) +{ + struct pci_bus *bus; + + bus = dev->bus; + while (bus->parent) + bus = bus->parent; + + return bus; +} + +static struct pci_host_bridge *find_pci_host_bridge(struct pci_dev *dev) +{ + struct pci_bus *bus = find_pci_root_bus(dev); + + return to_pci_host_bridge(bus->bridge); +} + +void pci_set_host_bridge_release(struct pci_host_bridge *bridge, + void (*release_fn)(struct pci_host_bridge *), + void *release_data) +{ + bridge->release_fn = release_fn; + bridge->release_data = release_data; +} + +static bool resource_contains(struct resource *res1, struct resource *res2) +{ + return res1->start <= res2->start && res1->end >= res2->end; +} + +void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, + struct resource *res) +{ + struct pci_host_bridge *bridge = find_pci_host_bridge(dev); + struct pci_host_bridge_window *window; + resource_size_t offset = 0; + + list_for_each_entry(window, &bridge->windows, list) { + if (resource_type(res) != resource_type(window->res)) + continue; + + if (resource_contains(window->res, res)) { + offset = window->offset; + break; + } + } + + region->start = res->start - offset; + region->end = res->end - offset; +} +EXPORT_SYMBOL(pcibios_resource_to_bus); + +static bool region_contains(struct pci_bus_region *region1, + struct pci_bus_region *region2) +{ + return region1->start <= region2->start && region1->end >= region2->end; +} + +void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, + struct pci_bus_region *region) +{ + struct pci_host_bridge *bridge = find_pci_host_bridge(dev); + struct pci_host_bridge_window *window; + resource_size_t offset = 0; + + list_for_each_entry(window, &bridge->windows, list) { + struct pci_bus_region bus_region; + + if (resource_type(res) != resource_type(window->res)) + continue; + + bus_region.start = window->res->start - window->offset; + bus_region.end = window->res->end - window->offset; + + if (region_contains(&bus_region, region)) { + offset = window->offset; + break; + } + } + + res->start = region->start + offset; + res->end = region->end + offset; +} +EXPORT_SYMBOL(pcibios_bus_to_resource); diff --git a/trunk/drivers/pci/pci-driver.c b/trunk/drivers/pci/pci-driver.c index 6b54b23b990b..bf0cee629b60 100644 --- a/trunk/drivers/pci/pci-driver.c +++ b/trunk/drivers/pci/pci-driver.c @@ -420,6 +420,12 @@ static void pci_device_shutdown(struct device *dev) pci_msi_shutdown(pci_dev); pci_msix_shutdown(pci_dev); + /* + * Turn off Bus Master bit on the device to tell it to not + * continue to do DMA + */ + pci_disable_device(pci_dev); + /* * Devices may be enabled to wake up by runtime PM, but they need not * be supposed to wake up the system from its "power off" state (e.g. diff --git a/trunk/drivers/pci/pci.c b/trunk/drivers/pci/pci.c index 111569ccab43..8f169002dc7e 100644 --- a/trunk/drivers/pci/pci.c +++ b/trunk/drivers/pci/pci.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "pci.h" @@ -3164,18 +3165,12 @@ static int pci_parent_bus_reset(struct pci_dev *dev, int probe) return 0; } -static int pci_dev_reset(struct pci_dev *dev, int probe) +static int __pci_dev_reset(struct pci_dev *dev, int probe) { int rc; might_sleep(); - if (!probe) { - pci_cfg_access_lock(dev); - /* block PM suspend, driver probe, etc. */ - device_lock(&dev->dev); - } - rc = pci_dev_specific_reset(dev, probe); if (rc != -ENOTTY) goto done; @@ -3194,14 +3189,27 @@ static int pci_dev_reset(struct pci_dev *dev, int probe) rc = pci_parent_bus_reset(dev, probe); done: + return rc; +} + +static int pci_dev_reset(struct pci_dev *dev, int probe) +{ + int rc; + + if (!probe) { + pci_cfg_access_lock(dev); + /* block PM suspend, driver probe, etc. */ + device_lock(&dev->dev); + } + + rc = __pci_dev_reset(dev, probe); + if (!probe) { device_unlock(&dev->dev); pci_cfg_access_unlock(dev); } - return rc; } - /** * __pci_reset_function - reset a PCI device function * @dev: PCI device to reset @@ -3246,7 +3254,7 @@ EXPORT_SYMBOL_GPL(__pci_reset_function); */ int __pci_reset_function_locked(struct pci_dev *dev) { - return pci_dev_reset(dev, 1); + return __pci_dev_reset(dev, 0); } EXPORT_SYMBOL_GPL(__pci_reset_function_locked); @@ -3893,6 +3901,8 @@ static int __init pci_setup(char *str) pcie_bus_config = PCIE_BUS_PERFORMANCE; } else if (!strncmp(str, "pcie_bus_peer2peer", 18)) { pcie_bus_config = PCIE_BUS_PEER2PEER; + } else if (!strncmp(str, "pcie_scan_all", 13)) { + pci_add_flags(PCI_SCAN_ALL_PCIE_DEVS); } else { printk(KERN_ERR "PCI: Unknown option `%s'\n", str); diff --git a/trunk/drivers/pci/pcie/portdrv_core.c b/trunk/drivers/pci/pcie/portdrv_core.c index 2f589a54f9bd..75915b30ad19 100644 --- a/trunk/drivers/pci/pcie/portdrv_core.c +++ b/trunk/drivers/pci/pcie/portdrv_core.c @@ -249,7 +249,7 @@ static int get_port_device_capability(struct pci_dev *dev) int services = 0, pos; u16 reg16; u32 reg32; - int cap_mask; + int cap_mask = 0; int err; if (pcie_ports_disabled) diff --git a/trunk/drivers/pci/probe.c b/trunk/drivers/pci/probe.c index 5e1ca3c58a7d..658ac977cb56 100644 --- a/trunk/drivers/pci/probe.c +++ b/trunk/drivers/pci/probe.c @@ -10,18 +10,16 @@ #include #include #include +#include #include "pci.h" #define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ #define CARDBUS_RESERVE_BUSNR 3 -static LIST_HEAD(pci_host_bridges); - /* Ugh. Need to stop exporting this to modules. */ LIST_HEAD(pci_root_buses); EXPORT_SYMBOL(pci_root_buses); - static int find_anything(struct device *dev, void *data) { return 1; @@ -44,82 +42,6 @@ int no_pci_devices(void) } EXPORT_SYMBOL(no_pci_devices); -static struct pci_host_bridge *pci_host_bridge(struct pci_dev *dev) -{ - struct pci_bus *bus; - struct pci_host_bridge *bridge; - - bus = dev->bus; - while (bus->parent) - bus = bus->parent; - - list_for_each_entry(bridge, &pci_host_bridges, list) { - if (bridge->bus == bus) - return bridge; - } - - return NULL; -} - -static bool resource_contains(struct resource *res1, struct resource *res2) -{ - return res1->start <= res2->start && res1->end >= res2->end; -} - -void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, - struct resource *res) -{ - struct pci_host_bridge *bridge = pci_host_bridge(dev); - struct pci_host_bridge_window *window; - resource_size_t offset = 0; - - list_for_each_entry(window, &bridge->windows, list) { - if (resource_type(res) != resource_type(window->res)) - continue; - - if (resource_contains(window->res, res)) { - offset = window->offset; - break; - } - } - - region->start = res->start - offset; - region->end = res->end - offset; -} -EXPORT_SYMBOL(pcibios_resource_to_bus); - -static bool region_contains(struct pci_bus_region *region1, - struct pci_bus_region *region2) -{ - return region1->start <= region2->start && region1->end >= region2->end; -} - -void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, - struct pci_bus_region *region) -{ - struct pci_host_bridge *bridge = pci_host_bridge(dev); - struct pci_host_bridge_window *window; - struct pci_bus_region bus_region; - resource_size_t offset = 0; - - list_for_each_entry(window, &bridge->windows, list) { - if (resource_type(res) != resource_type(window->res)) - continue; - - bus_region.start = window->res->start - window->offset; - bus_region.end = window->res->end - window->offset; - - if (region_contains(&bus_region, region)) { - offset = window->offset; - break; - } - } - - res->start = region->start + offset; - res->end = region->end + offset; -} -EXPORT_SYMBOL(pcibios_bus_to_resource); - /* * PCI Bus Class */ @@ -501,6 +423,19 @@ static struct pci_bus * pci_alloc_bus(void) return b; } +static struct pci_host_bridge *pci_alloc_host_bridge(struct pci_bus *b) +{ + struct pci_host_bridge *bridge; + + bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); + if (bridge) { + INIT_LIST_HEAD(&bridge->windows); + bridge->bus = b; + } + + return bridge; +} + static unsigned char pcix_bus_speed[] = { PCI_SPEED_UNKNOWN, /* 0 */ PCI_SPEED_66MHz_PCIX, /* 1 */ @@ -1201,7 +1136,14 @@ int pci_cfg_space_size(struct pci_dev *dev) static void pci_release_bus_bridge_dev(struct device *dev) { - kfree(dev); + struct pci_host_bridge *bridge = to_pci_host_bridge(dev); + + if (bridge->release_fn) + bridge->release_fn(bridge); + + pci_free_resource_list(&bridge->windows); + + kfree(bridge); } struct pci_dev *alloc_pci_dev(void) @@ -1395,10 +1337,13 @@ static unsigned no_next_fn(struct pci_dev *dev, unsigned fn) static int only_one_child(struct pci_bus *bus) { struct pci_dev *parent = bus->self; + if (!parent || !pci_is_pcie(parent)) return 0; - if (parent->pcie_type == PCI_EXP_TYPE_ROOT_PORT || - parent->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) + if (parent->pcie_type == PCI_EXP_TYPE_ROOT_PORT) + return 1; + if (parent->pcie_type == PCI_EXP_TYPE_DOWNSTREAM && + !pci_has_flag(PCI_SCAN_ALL_PCIE_DEVS)) return 1; return 0; } @@ -1650,28 +1595,19 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, int error; struct pci_host_bridge *bridge; struct pci_bus *b, *b2; - struct device *dev; struct pci_host_bridge_window *window, *n; struct resource *res; resource_size_t offset; char bus_addr[64]; char *fmt; - bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); - if (!bridge) - return NULL; b = pci_alloc_bus(); if (!b) - goto err_bus; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - goto err_dev; + return NULL; b->sysdata = sysdata; b->ops = ops; - b2 = pci_find_bus(pci_domain_nr(b), bus); if (b2) { /* If we already got to this bus through a different bridge, ignore it */ @@ -1679,13 +1615,17 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, goto err_out; } - dev->parent = parent; - dev->release = pci_release_bus_bridge_dev; - dev_set_name(dev, "pci%04x:%02x", pci_domain_nr(b), bus); - error = device_register(dev); + bridge = pci_alloc_host_bridge(b); + if (!bridge) + goto err_out; + + bridge->dev.parent = parent; + bridge->dev.release = pci_release_bus_bridge_dev; + dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus); + error = device_register(&bridge->dev); if (error) - goto dev_reg_err; - b->bridge = get_device(dev); + goto bridge_dev_reg_err; + b->bridge = get_device(&bridge->dev); device_enable_async_suspend(b->bridge); pci_set_bus_of_node(b); @@ -1704,9 +1644,6 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, b->number = b->secondary = bus; - bridge->bus = b; - INIT_LIST_HEAD(&bridge->windows); - if (parent) dev_info(parent, "PCI host bridge to bus %s\n", dev_name(&b->dev)); else @@ -1732,25 +1669,18 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, } down_write(&pci_bus_sem); - list_add_tail(&bridge->list, &pci_host_bridges); list_add_tail(&b->node, &pci_root_buses); up_write(&pci_bus_sem); return b; class_dev_reg_err: - device_unregister(dev); -dev_reg_err: - down_write(&pci_bus_sem); - list_del(&bridge->list); - list_del(&b->node); - up_write(&pci_bus_sem); + put_device(&bridge->dev); + device_unregister(&bridge->dev); +bridge_dev_reg_err: + kfree(bridge); err_out: - kfree(dev); -err_dev: kfree(b); -err_bus: - kfree(bridge); return NULL; } diff --git a/trunk/drivers/pci/quirks.c b/trunk/drivers/pci/quirks.c index 4bf71028556b..2a7521677541 100644 --- a/trunk/drivers/pci/quirks.c +++ b/trunk/drivers/pci/quirks.c @@ -2626,6 +2626,18 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4374, DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4375, quirk_msi_intx_disable_bug); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x1062, + quirk_msi_intx_disable_bug); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x1063, + quirk_msi_intx_disable_bug); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x2060, + quirk_msi_intx_disable_bug); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x2062, + quirk_msi_intx_disable_bug); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x1073, + quirk_msi_intx_disable_bug); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x1083, + quirk_msi_intx_disable_bug); #endif /* CONFIG_PCI_MSI */ /* Allow manual resource allocation for PCI hotplug bridges @@ -3085,16 +3097,74 @@ static int reset_intel_82599_sfp_virtfn(struct pci_dev *dev, int probe) return 0; } +#include "../gpu/drm/i915/i915_reg.h" +#define MSG_CTL 0x45010 +#define NSDE_PWR_STATE 0xd0100 +#define IGD_OPERATION_TIMEOUT 10000 /* set timeout 10 seconds */ + +static int reset_ivb_igd(struct pci_dev *dev, int probe) +{ + void __iomem *mmio_base; + unsigned long timeout; + u32 val; + + if (probe) + return 0; + + mmio_base = pci_iomap(dev, 0, 0); + if (!mmio_base) + return -ENOMEM; + + iowrite32(0x00000002, mmio_base + MSG_CTL); + + /* + * Clobbering SOUTH_CHICKEN2 register is fine only if the next + * driver loaded sets the right bits. However, this's a reset and + * the bits have been set by i915 previously, so we clobber + * SOUTH_CHICKEN2 register directly here. + */ + iowrite32(0x00000005, mmio_base + SOUTH_CHICKEN2); + + val = ioread32(mmio_base + PCH_PP_CONTROL) & 0xfffffffe; + iowrite32(val, mmio_base + PCH_PP_CONTROL); + + timeout = jiffies + msecs_to_jiffies(IGD_OPERATION_TIMEOUT); + do { + val = ioread32(mmio_base + PCH_PP_STATUS); + if ((val & 0xb0000000) == 0) + goto reset_complete; + msleep(10); + } while (time_before(jiffies, timeout)); + dev_warn(&dev->dev, "timeout during reset\n"); + +reset_complete: + iowrite32(0x00000002, mmio_base + NSDE_PWR_STATE); + + pci_iounmap(dev, mmio_base); + return 0; +} + #define PCI_DEVICE_ID_INTEL_82599_SFP_VF 0x10ed +#define PCI_DEVICE_ID_INTEL_IVB_M_VGA 0x0156 +#define PCI_DEVICE_ID_INTEL_IVB_M2_VGA 0x0166 static const struct pci_dev_reset_methods pci_dev_reset_methods[] = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82599_SFP_VF, reset_intel_82599_sfp_virtfn }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IVB_M_VGA, + reset_ivb_igd }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IVB_M2_VGA, + reset_ivb_igd }, { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, reset_intel_generic_dev }, { 0 } }; +/* + * These device-specific reset methods are here rather than in a driver + * because when a host assigns a device to a guest VM, the host may need + * to reset the device but probably doesn't have a driver for it. + */ int pci_dev_specific_reset(struct pci_dev *dev, int probe) { const struct pci_dev_reset_methods *i; diff --git a/trunk/drivers/pcmcia/Kconfig b/trunk/drivers/pcmcia/Kconfig index bba3ab2066ee..8fd255f7ee40 100644 --- a/trunk/drivers/pcmcia/Kconfig +++ b/trunk/drivers/pcmcia/Kconfig @@ -217,7 +217,7 @@ config PCMCIA_PXA2XX || MACH_ARMCORE || ARCH_PXA_PALM || TRIZEPS_PCMCIA \ || ARCOM_PCMCIA || ARCH_PXA_ESERIES || MACH_STARGATE2 \ || MACH_VPAC270 || MACH_BALLOON3 || MACH_COLIBRI \ - || MACH_COLIBRI320) + || MACH_COLIBRI320 || MACH_H4700) select PCMCIA_SA1111 if ARCH_LUBBOCK && SA1111 select PCMCIA_SOC_COMMON help diff --git a/trunk/drivers/pcmcia/Makefile b/trunk/drivers/pcmcia/Makefile index 47525de6a631..7745b512a87c 100644 --- a/trunk/drivers/pcmcia/Makefile +++ b/trunk/drivers/pcmcia/Makefile @@ -69,6 +69,7 @@ pxa2xx-obj-$(CONFIG_MACH_VPAC270) += pxa2xx_vpac270.o pxa2xx-obj-$(CONFIG_MACH_BALLOON3) += pxa2xx_balloon3.o pxa2xx-obj-$(CONFIG_MACH_COLIBRI) += pxa2xx_colibri.o pxa2xx-obj-$(CONFIG_MACH_COLIBRI320) += pxa2xx_colibri.o +pxa2xx-obj-$(CONFIG_MACH_H4700) += pxa2xx_hx4700.o obj-$(CONFIG_PCMCIA_PXA2XX) += pxa2xx_base.o $(pxa2xx-obj-y) diff --git a/trunk/drivers/pcmcia/pxa2xx_hx4700.c b/trunk/drivers/pcmcia/pxa2xx_hx4700.c new file mode 100644 index 000000000000..7dfef3ee5b53 --- /dev/null +++ b/trunk/drivers/pcmcia/pxa2xx_hx4700.c @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2012 Paul Parsons + * + * 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 "soc_common.h" + +static struct gpio gpios[] = { + { GPIO114_HX4700_CF_RESET, GPIOF_OUT_INIT_LOW, "CF reset" }, + { EGPIO4_CF_3V3_ON, GPIOF_OUT_INIT_LOW, "CF 3.3V enable" }, +}; + +static int hx4700_pcmcia_hw_init(struct soc_pcmcia_socket *skt) +{ + int ret; + + ret = gpio_request_array(gpios, ARRAY_SIZE(gpios)); + if (ret) + goto out; + + /* + * IRQ type must be set before soc_pcmcia_hw_init() calls request_irq(). + * The asic3 default IRQ type is level trigger low level detect, exactly + * the the signal present on GPIOD4_CF_nCD when a CF card is inserted. + * If the IRQ type is not changed, the asic3 interrupt handler will loop + * repeatedly because it is unable to clear the level trigger interrupt. + */ + irq_set_irq_type(gpio_to_irq(GPIOD4_CF_nCD), IRQ_TYPE_EDGE_BOTH); + + skt->stat[SOC_STAT_CD].gpio = GPIOD4_CF_nCD; + skt->stat[SOC_STAT_CD].name = "PCMCIA CD"; + skt->stat[SOC_STAT_RDY].gpio = GPIO60_HX4700_CF_RNB; + skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready"; + +out: + return ret; +} + +static void hx4700_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) +{ + gpio_free_array(gpios, ARRAY_SIZE(gpios)); +} + +static void hx4700_pcmcia_socket_state(struct soc_pcmcia_socket *skt, + struct pcmcia_state *state) +{ + state->vs_3v = 1; + state->vs_Xv = 0; +} + +static int hx4700_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, + const socket_state_t *state) +{ + switch (state->Vcc) { + case 0: + gpio_set_value(EGPIO4_CF_3V3_ON, 0); + break; + case 33: + gpio_set_value(EGPIO4_CF_3V3_ON, 1); + break; + default: + printk(KERN_ERR "pcmcia: Unsupported Vcc: %d\n", state->Vcc); + return -EINVAL; + } + + gpio_set_value(GPIO114_HX4700_CF_RESET, (state->flags & SS_RESET) != 0); + + return 0; +} + +static struct pcmcia_low_level hx4700_pcmcia_ops = { + .owner = THIS_MODULE, + .nr = 1, + .hw_init = hx4700_pcmcia_hw_init, + .hw_shutdown = hx4700_pcmcia_hw_shutdown, + .socket_state = hx4700_pcmcia_socket_state, + .configure_socket = hx4700_pcmcia_configure_socket, +}; + +static struct platform_device *hx4700_pcmcia_device; + +static int __init hx4700_pcmcia_init(void) +{ + struct platform_device *pdev; + + if (!machine_is_h4700()) + return -ENODEV; + + pdev = platform_device_register_data(NULL, "pxa2xx-pcmcia", -1, + &hx4700_pcmcia_ops, sizeof(hx4700_pcmcia_ops)); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + hx4700_pcmcia_device = pdev; + + return 0; +} + +static void __exit hx4700_pcmcia_exit(void) +{ + platform_device_unregister(hx4700_pcmcia_device); +} + +module_init(hx4700_pcmcia_init); +module_exit(hx4700_pcmcia_exit); + +MODULE_AUTHOR("Paul Parsons "); +MODULE_DESCRIPTION("HP iPAQ hx4700 PCMCIA driver"); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/pinctrl/Kconfig b/trunk/drivers/pinctrl/Kconfig index abfb96408779..c6e6ae0aa3b1 100644 --- a/trunk/drivers/pinctrl/Kconfig +++ b/trunk/drivers/pinctrl/Kconfig @@ -4,7 +4,6 @@ config PINCTRL bool - depends on EXPERIMENTAL if PINCTRL @@ -27,6 +26,35 @@ config DEBUG_PINCTRL help Say Y here to add some extra checks and diagnostics to PINCTRL calls. +config PINCTRL_IMX + bool + select PINMUX + select PINCONF + +config PINCTRL_IMX51 + bool "IMX51 pinctrl driver" + depends on OF + depends on SOC_IMX51 + select PINCTRL_IMX + help + Say Y here to enable the imx51 pinctrl driver + +config PINCTRL_IMX53 + bool "IMX53 pinctrl driver" + depends on OF + depends on SOC_IMX53 + select PINCTRL_IMX + help + Say Y here to enable the imx53 pinctrl driver + +config PINCTRL_IMX6Q + bool "IMX6Q pinctrl driver" + depends on OF + depends on SOC_IMX6Q + select PINCTRL_IMX + help + Say Y here to enable the imx6q pinctrl driver + config PINCTRL_PXA3xx bool select PINMUX @@ -37,6 +65,31 @@ config PINCTRL_MMP2 select PINCTRL_PXA3xx select PINCONF +config PINCTRL_MXS + bool + +config PINCTRL_IMX23 + bool + select PINMUX + select PINCONF + select PINCTRL_MXS + +config PINCTRL_IMX28 + bool + select PINMUX + select PINCONF + select PINCTRL_MXS + +config PINCTRL_NOMADIK + bool "Nomadik pin controller driver" + depends on ARCH_U8500 || ARCH_NOMADIK + select PINMUX + select PINCONF + +config PINCTRL_DB8500 + bool "DB8500 pin controller driver" + depends on PINCTRL_NOMADIK && ARCH_U8500 + config PINCTRL_PXA168 bool "PXA168 pin controller driver" depends on ARCH_MMP @@ -84,6 +137,8 @@ config PINCTRL_COH901 COH 901 335 and COH 901 571/3. They contain 3, 5 or 7 ports of 8 GPIO pins each. +source "drivers/pinctrl/spear/Kconfig" + endmenu endif diff --git a/trunk/drivers/pinctrl/Makefile b/trunk/drivers/pinctrl/Makefile index 6d4150b4eced..8c074376cdea 100644 --- a/trunk/drivers/pinctrl/Makefile +++ b/trunk/drivers/pinctrl/Makefile @@ -5,9 +5,21 @@ ccflags-$(CONFIG_DEBUG_PINCTRL) += -DDEBUG obj-$(CONFIG_PINCTRL) += core.o obj-$(CONFIG_PINMUX) += pinmux.o obj-$(CONFIG_PINCONF) += pinconf.o +ifeq ($(CONFIG_OF),y) +obj-$(CONFIG_PINCTRL) += devicetree.o +endif obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o +obj-$(CONFIG_PINCTRL_IMX) += pinctrl-imx.o +obj-$(CONFIG_PINCTRL_IMX51) += pinctrl-imx51.o +obj-$(CONFIG_PINCTRL_IMX53) += pinctrl-imx53.o +obj-$(CONFIG_PINCTRL_IMX6Q) += pinctrl-imx6q.o obj-$(CONFIG_PINCTRL_PXA3xx) += pinctrl-pxa3xx.o obj-$(CONFIG_PINCTRL_MMP2) += pinctrl-mmp2.o +obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o +obj-$(CONFIG_PINCTRL_IMX23) += pinctrl-imx23.o +obj-$(CONFIG_PINCTRL_IMX28) += pinctrl-imx28.o +obj-$(CONFIG_PINCTRL_NOMADIK) += pinctrl-nomadik.o +obj-$(CONFIG_PINCTRL_DB8500) += pinctrl-nomadik-db8500.o obj-$(CONFIG_PINCTRL_PXA168) += pinctrl-pxa168.o obj-$(CONFIG_PINCTRL_PXA910) += pinctrl-pxa910.o obj-$(CONFIG_PINCTRL_SIRF) += pinctrl-sirf.o @@ -16,3 +28,5 @@ obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o + +obj-$(CONFIG_PLAT_SPEAR) += spear/ diff --git a/trunk/drivers/pinctrl/core.c b/trunk/drivers/pinctrl/core.c index df6296c5f47b..c3b331b74fa0 100644 --- a/trunk/drivers/pinctrl/core.c +++ b/trunk/drivers/pinctrl/core.c @@ -23,9 +23,11 @@ #include #include #include +#include #include #include #include "core.h" +#include "devicetree.h" #include "pinmux.h" #include "pinconf.h" @@ -41,11 +43,13 @@ struct pinctrl_maps { unsigned num_maps; }; +static bool pinctrl_dummy_state; + /* Mutex taken by all entry points */ DEFINE_MUTEX(pinctrl_mutex); /* Global list of pin control devices (struct pinctrl_dev) */ -static LIST_HEAD(pinctrldev_list); +LIST_HEAD(pinctrldev_list); /* List of pin controller handles (struct pinctrl) */ static LIST_HEAD(pinctrl_list); @@ -59,6 +63,19 @@ static LIST_HEAD(pinctrl_maps); _i_ < _maps_node_->num_maps; \ i++, _map_ = &_maps_node_->maps[_i_]) +/** + * pinctrl_provide_dummies() - indicate if pinctrl provides dummy state support + * + * Usually this function is called by platforms without pinctrl driver support + * but run with some shared drivers using pinctrl APIs. + * After calling this function, the pinctrl core will return successfully + * with creating a dummy state for the driver to keep going smoothly. + */ +void pinctrl_provide_dummies(void) +{ + pinctrl_dummy_state = true; +} + const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev) { /* We're not allowed to register devices without name */ @@ -123,6 +140,25 @@ int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name) return -EINVAL; } +/** + * pin_get_name_from_id() - look up a pin name from a pin id + * @pctldev: the pin control device to lookup the pin on + * @name: the name of the pin to look up + */ +const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin) +{ + const struct pin_desc *desc; + + desc = pin_desc_get(pctldev, pin); + if (desc == NULL) { + dev_err(pctldev->dev, "failed to get pin(%d) name\n", + pin); + return NULL; + } + + return desc->name; +} + /** * pin_is_valid() - check if pin exists on controller * @pctldev: the pin control device to check the pin on @@ -255,7 +291,8 @@ pinctrl_match_gpio_range(struct pinctrl_dev *pctldev, unsigned gpio) * * Find the pin controller handling a certain GPIO pin from the pinspace of * the GPIO subsystem, return the device and the matching GPIO range. Returns - * negative if the GPIO range could not be found in any device. + * -EPROBE_DEFER if the GPIO range could not be found in any device since it + * may still have not been registered. */ static int pinctrl_get_device_gpio_range(unsigned gpio, struct pinctrl_dev **outdev, @@ -275,7 +312,7 @@ static int pinctrl_get_device_gpio_range(unsigned gpio, } } - return -EINVAL; + return -EPROBE_DEFER; } /** @@ -318,9 +355,10 @@ int pinctrl_get_group_selector(struct pinctrl_dev *pctldev, const char *pin_group) { const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; + unsigned ngroups = pctlops->get_groups_count(pctldev); unsigned group_selector = 0; - while (pctlops->list_groups(pctldev, group_selector) >= 0) { + while (group_selector < ngroups) { const char *gname = pctlops->get_group_name(pctldev, group_selector); if (!strcmp(gname, pin_group)) { @@ -360,7 +398,7 @@ int pinctrl_request_gpio(unsigned gpio) ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range); if (ret) { mutex_unlock(&pinctrl_mutex); - return -EINVAL; + return ret; } /* Convert to the pin controllers number space */ @@ -516,11 +554,14 @@ static int add_setting(struct pinctrl *p, struct pinctrl_map const *map) setting->pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name); if (setting->pctldev == NULL) { - dev_err(p->dev, "unknown pinctrl device %s in map entry", + dev_info(p->dev, "unknown pinctrl device %s in map entry, deferring probe", map->ctrl_dev_name); kfree(setting); - /* Eventually, this should trigger deferred probe */ - return -ENODEV; + /* + * OK let us guess that the driver is not there yet, and + * let's defer obtaining this pinctrl handle to later... + */ + return -EPROBE_DEFER; } switch (map->type) { @@ -579,6 +620,13 @@ static struct pinctrl *create_pinctrl(struct device *dev) } p->dev = dev; INIT_LIST_HEAD(&p->states); + INIT_LIST_HEAD(&p->dt_maps); + + ret = pinctrl_dt_to_map(p); + if (ret < 0) { + kfree(p); + return ERR_PTR(ret); + } devname = dev_name(dev); @@ -662,6 +710,8 @@ static void pinctrl_put_locked(struct pinctrl *p, bool inlist) kfree(state); } + pinctrl_dt_free_maps(p); + if (inlist) list_del(&p->node); kfree(p); @@ -685,8 +735,18 @@ static struct pinctrl_state *pinctrl_lookup_state_locked(struct pinctrl *p, struct pinctrl_state *state; state = find_state(p, name); - if (!state) - return ERR_PTR(-ENODEV); + if (!state) { + if (pinctrl_dummy_state) { + /* create dummy state */ + dev_dbg(p->dev, "using pinctrl dummy state (%s)\n", + name); + state = create_state(p, name); + if (IS_ERR(state)) + return state; + } else { + return ERR_PTR(-ENODEV); + } + } return state; } @@ -787,15 +847,63 @@ int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state) } EXPORT_SYMBOL_GPL(pinctrl_select_state); +static void devm_pinctrl_release(struct device *dev, void *res) +{ + pinctrl_put(*(struct pinctrl **)res); +} + /** - * pinctrl_register_mappings() - register a set of pin controller mappings - * @maps: the pincontrol mappings table to register. This should probably be - * marked with __initdata so it can be discarded after boot. This - * function will perform a shallow copy for the mapping entries. - * @num_maps: the number of maps in the mapping table + * struct devm_pinctrl_get() - Resource managed pinctrl_get() + * @dev: the device to obtain the handle for + * + * If there is a need to explicitly destroy the returned struct pinctrl, + * devm_pinctrl_put() should be used, rather than plain pinctrl_put(). */ -int pinctrl_register_mappings(struct pinctrl_map const *maps, - unsigned num_maps) +struct pinctrl *devm_pinctrl_get(struct device *dev) +{ + struct pinctrl **ptr, *p; + + ptr = devres_alloc(devm_pinctrl_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + p = pinctrl_get(dev); + if (!IS_ERR(p)) { + *ptr = p; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return p; +} +EXPORT_SYMBOL_GPL(devm_pinctrl_get); + +static int devm_pinctrl_match(struct device *dev, void *res, void *data) +{ + struct pinctrl **p = res; + + return *p == data; +} + +/** + * devm_pinctrl_put() - Resource managed pinctrl_put() + * @p: the pinctrl handle to release + * + * Deallocate a struct pinctrl obtained via devm_pinctrl_get(). Normally + * this function will not need to be called and the resource management + * code will ensure that the resource is freed. + */ +void devm_pinctrl_put(struct pinctrl *p) +{ + WARN_ON(devres_destroy(p->dev, devm_pinctrl_release, + devm_pinctrl_match, p)); + pinctrl_put(p); +} +EXPORT_SYMBOL_GPL(devm_pinctrl_put); + +int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps, + bool dup, bool locked) { int i, ret; struct pinctrl_maps *maps_node; @@ -829,13 +937,13 @@ int pinctrl_register_mappings(struct pinctrl_map const *maps, case PIN_MAP_TYPE_MUX_GROUP: ret = pinmux_validate_map(&maps[i], i); if (ret < 0) - return 0; + return ret; break; case PIN_MAP_TYPE_CONFIGS_PIN: case PIN_MAP_TYPE_CONFIGS_GROUP: ret = pinconf_validate_map(&maps[i], i); if (ret < 0) - return 0; + return ret; break; default: pr_err("failed to register map %s (%d): invalid type given\n", @@ -851,20 +959,52 @@ int pinctrl_register_mappings(struct pinctrl_map const *maps, } maps_node->num_maps = num_maps; - maps_node->maps = kmemdup(maps, sizeof(*maps) * num_maps, GFP_KERNEL); - if (!maps_node->maps) { - pr_err("failed to duplicate mapping table\n"); - kfree(maps_node); - return -ENOMEM; + if (dup) { + maps_node->maps = kmemdup(maps, sizeof(*maps) * num_maps, + GFP_KERNEL); + if (!maps_node->maps) { + pr_err("failed to duplicate mapping table\n"); + kfree(maps_node); + return -ENOMEM; + } + } else { + maps_node->maps = maps; } - mutex_lock(&pinctrl_mutex); + if (!locked) + mutex_lock(&pinctrl_mutex); list_add_tail(&maps_node->node, &pinctrl_maps); - mutex_unlock(&pinctrl_mutex); + if (!locked) + mutex_unlock(&pinctrl_mutex); return 0; } +/** + * pinctrl_register_mappings() - register a set of pin controller mappings + * @maps: the pincontrol mappings table to register. This should probably be + * marked with __initdata so it can be discarded after boot. This + * function will perform a shallow copy for the mapping entries. + * @num_maps: the number of maps in the mapping table + */ +int pinctrl_register_mappings(struct pinctrl_map const *maps, + unsigned num_maps) +{ + return pinctrl_register_map(maps, num_maps, true, false); +} + +void pinctrl_unregister_map(struct pinctrl_map const *map) +{ + struct pinctrl_maps *maps_node; + + list_for_each_entry(maps_node, &pinctrl_maps, node) { + if (maps_node->maps == map) { + list_del(&maps_node->node); + return; + } + } +} + #ifdef CONFIG_DEBUG_FS static int pinctrl_pins_show(struct seq_file *s, void *what) @@ -906,15 +1046,17 @@ static int pinctrl_groups_show(struct seq_file *s, void *what) { struct pinctrl_dev *pctldev = s->private; const struct pinctrl_ops *ops = pctldev->desc->pctlops; - unsigned selector = 0; + unsigned ngroups, selector = 0; + ngroups = ops->get_groups_count(pctldev); mutex_lock(&pinctrl_mutex); seq_puts(s, "registered pin groups:\n"); - while (ops->list_groups(pctldev, selector) >= 0) { + while (selector < ngroups) { const unsigned *pins; unsigned num_pins; const char *gname = ops->get_group_name(pctldev, selector); + const char *pname; int ret; int i; @@ -924,10 +1066,14 @@ static int pinctrl_groups_show(struct seq_file *s, void *what) seq_printf(s, "%s [ERROR GETTING PINS]\n", gname); else { - seq_printf(s, "group: %s, pins = [ ", gname); - for (i = 0; i < num_pins; i++) - seq_printf(s, "%d ", pins[i]); - seq_puts(s, "]\n"); + seq_printf(s, "group: %s\n", gname); + for (i = 0; i < num_pins; i++) { + pname = pin_get_name(pctldev, pins[i]); + if (WARN_ON(!pname)) + return -EINVAL; + seq_printf(s, "pin %d (%s)\n", pins[i], pname); + } + seq_puts(s, "\n"); } selector++; } @@ -1226,11 +1372,14 @@ static int pinctrl_check_ops(struct pinctrl_dev *pctldev) const struct pinctrl_ops *ops = pctldev->desc->pctlops; if (!ops || - !ops->list_groups || + !ops->get_groups_count || !ops->get_group_name || !ops->get_group_pins) return -EINVAL; + if (ops->dt_node_to_map && !ops->dt_free_map) + return -EINVAL; + return 0; } @@ -1268,37 +1417,29 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, /* check core ops for sanity */ ret = pinctrl_check_ops(pctldev); if (ret) { - pr_err("%s pinctrl ops lacks necessary functions\n", - pctldesc->name); + dev_err(dev, "pinctrl ops lacks necessary functions\n"); goto out_err; } /* If we're implementing pinmuxing, check the ops for sanity */ if (pctldesc->pmxops) { ret = pinmux_check_ops(pctldev); - if (ret) { - pr_err("%s pinmux ops lacks necessary functions\n", - pctldesc->name); + if (ret) goto out_err; - } } /* If we're implementing pinconfig, check the ops for sanity */ if (pctldesc->confops) { ret = pinconf_check_ops(pctldev); - if (ret) { - pr_err("%s pin config ops lacks necessary functions\n", - pctldesc->name); + if (ret) goto out_err; - } } /* Register all the pins */ - pr_debug("try to register %d pins on %s...\n", - pctldesc->npins, pctldesc->name); + dev_dbg(dev, "try to register %d pins ...\n", pctldesc->npins); ret = pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins); if (ret) { - pr_err("error during pin registration\n"); + dev_err(dev, "error during pin registration\n"); pinctrl_free_pindescs(pctldev, pctldesc->pins, pctldesc->npins); goto out_err; @@ -1313,8 +1454,15 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, struct pinctrl_state *s = pinctrl_lookup_state_locked(pctldev->p, PINCTRL_STATE_DEFAULT); - if (!IS_ERR(s)) - pinctrl_select_state_locked(pctldev->p, s); + if (IS_ERR(s)) { + dev_dbg(dev, "failed to lookup the default state\n"); + } else { + ret = pinctrl_select_state_locked(pctldev->p, s); + if (ret) { + dev_err(dev, + "failed to select default state\n"); + } + } } mutex_unlock(&pinctrl_mutex); diff --git a/trunk/drivers/pinctrl/core.h b/trunk/drivers/pinctrl/core.h index 17ecf651b123..1f40ff68a8c4 100644 --- a/trunk/drivers/pinctrl/core.h +++ b/trunk/drivers/pinctrl/core.h @@ -52,12 +52,15 @@ struct pinctrl_dev { * @dev: the device using this pin control handle * @states: a list of states for this device * @state: the current state + * @dt_maps: the mapping table chunks dynamically parsed from device tree for + * this device, if any */ struct pinctrl { struct list_head node; struct device *dev; struct list_head states; struct pinctrl_state *state; + struct list_head dt_maps; }; /** @@ -100,7 +103,8 @@ struct pinctrl_setting_configs { * struct pinctrl_setting - an individual mux or config setting * @node: list node for struct pinctrl_settings's @settings field * @type: the type of setting - * @pctldev: pin control device handling to be programmed + * @pctldev: pin control device handling to be programmed. Not used for + * PIN_MAP_TYPE_DUMMY_STATE. * @data: Data specific to the setting type */ struct pinctrl_setting { @@ -144,6 +148,7 @@ struct pin_desc { struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name); int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name); +const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin); int pinctrl_get_group_selector(struct pinctrl_dev *pctldev, const char *pin_group); @@ -153,4 +158,9 @@ static inline struct pin_desc *pin_desc_get(struct pinctrl_dev *pctldev, return radix_tree_lookup(&pctldev->pin_desc_tree, pin); } +int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps, + bool dup, bool locked); +void pinctrl_unregister_map(struct pinctrl_map const *map); + extern struct mutex pinctrl_mutex; +extern struct list_head pinctrldev_list; diff --git a/trunk/drivers/pinctrl/devicetree.c b/trunk/drivers/pinctrl/devicetree.c new file mode 100644 index 000000000000..fcb1de45473c --- /dev/null +++ b/trunk/drivers/pinctrl/devicetree.c @@ -0,0 +1,249 @@ +/* + * Device tree integration for the pin control subsystem + * + * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * 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 . + */ + +#include +#include +#include +#include + +#include "core.h" +#include "devicetree.h" + +/** + * struct pinctrl_dt_map - mapping table chunk parsed from device tree + * @node: list node for struct pinctrl's @dt_maps field + * @pctldev: the pin controller that allocated this struct, and will free it + * @maps: the mapping table entries + */ +struct pinctrl_dt_map { + struct list_head node; + struct pinctrl_dev *pctldev; + struct pinctrl_map *map; + unsigned num_maps; +}; + +static void dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) +{ + if (pctldev) { + struct pinctrl_ops *ops = pctldev->desc->pctlops; + ops->dt_free_map(pctldev, map, num_maps); + } else { + /* There is no pctldev for PIN_MAP_TYPE_DUMMY_STATE */ + kfree(map); + } +} + +void pinctrl_dt_free_maps(struct pinctrl *p) +{ + struct pinctrl_dt_map *dt_map, *n1; + + list_for_each_entry_safe(dt_map, n1, &p->dt_maps, node) { + pinctrl_unregister_map(dt_map->map); + list_del(&dt_map->node); + dt_free_map(dt_map->pctldev, dt_map->map, + dt_map->num_maps); + kfree(dt_map); + } + + of_node_put(p->dev->of_node); +} + +static int dt_remember_or_free_map(struct pinctrl *p, const char *statename, + struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) +{ + int i; + struct pinctrl_dt_map *dt_map; + + /* Initialize common mapping table entry fields */ + for (i = 0; i < num_maps; i++) { + map[i].dev_name = dev_name(p->dev); + map[i].name = statename; + if (pctldev) + map[i].ctrl_dev_name = dev_name(pctldev->dev); + } + + /* Remember the converted mapping table entries */ + dt_map = kzalloc(sizeof(*dt_map), GFP_KERNEL); + if (!dt_map) { + dev_err(p->dev, "failed to alloc struct pinctrl_dt_map\n"); + dt_free_map(pctldev, map, num_maps); + return -ENOMEM; + } + + dt_map->pctldev = pctldev; + dt_map->map = map; + dt_map->num_maps = num_maps; + list_add_tail(&dt_map->node, &p->dt_maps); + + return pinctrl_register_map(map, num_maps, false, true); +} + +static struct pinctrl_dev *find_pinctrl_by_of_node(struct device_node *np) +{ + struct pinctrl_dev *pctldev; + + list_for_each_entry(pctldev, &pinctrldev_list, node) + if (pctldev->dev->of_node == np) + return pctldev; + + return NULL; +} + +static int dt_to_map_one_config(struct pinctrl *p, const char *statename, + struct device_node *np_config) +{ + struct device_node *np_pctldev; + struct pinctrl_dev *pctldev; + struct pinctrl_ops *ops; + int ret; + struct pinctrl_map *map; + unsigned num_maps; + + /* Find the pin controller containing np_config */ + np_pctldev = of_node_get(np_config); + for (;;) { + np_pctldev = of_get_next_parent(np_pctldev); + if (!np_pctldev || of_node_is_root(np_pctldev)) { + dev_info(p->dev, "could not find pctldev for node %s, deferring probe\n", + np_config->full_name); + of_node_put(np_pctldev); + /* OK let's just assume this will appear later then */ + return -EPROBE_DEFER; + } + pctldev = find_pinctrl_by_of_node(np_pctldev); + if (pctldev) + break; + } + of_node_put(np_pctldev); + + /* + * Call pinctrl driver to parse device tree node, and + * generate mapping table entries + */ + ops = pctldev->desc->pctlops; + if (!ops->dt_node_to_map) { + dev_err(p->dev, "pctldev %s doesn't support DT\n", + dev_name(pctldev->dev)); + return -ENODEV; + } + ret = ops->dt_node_to_map(pctldev, np_config, &map, &num_maps); + if (ret < 0) + return ret; + + /* Stash the mapping table chunk away for later use */ + return dt_remember_or_free_map(p, statename, pctldev, map, num_maps); +} + +static int dt_remember_dummy_state(struct pinctrl *p, const char *statename) +{ + struct pinctrl_map *map; + + map = kzalloc(sizeof(*map), GFP_KERNEL); + if (!map) { + dev_err(p->dev, "failed to alloc struct pinctrl_map\n"); + return -ENOMEM; + } + + /* There is no pctldev for PIN_MAP_TYPE_DUMMY_STATE */ + map->type = PIN_MAP_TYPE_DUMMY_STATE; + + return dt_remember_or_free_map(p, statename, NULL, map, 1); +} + +int pinctrl_dt_to_map(struct pinctrl *p) +{ + struct device_node *np = p->dev->of_node; + int state, ret; + char *propname; + struct property *prop; + const char *statename; + const __be32 *list; + int size, config; + phandle phandle; + struct device_node *np_config; + + /* CONFIG_OF enabled, p->dev not instantiated from DT */ + if (!np) { + dev_dbg(p->dev, "no of_node; not parsing pinctrl DT\n"); + return 0; + } + + /* We may store pointers to property names within the node */ + of_node_get(np); + + /* For each defined state ID */ + for (state = 0; ; state++) { + /* Retrieve the pinctrl-* property */ + propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state); + prop = of_find_property(np, propname, &size); + kfree(propname); + if (!prop) + break; + list = prop->value; + size /= sizeof(*list); + + /* Determine whether pinctrl-names property names the state */ + ret = of_property_read_string_index(np, "pinctrl-names", + state, &statename); + /* + * If not, statename is just the integer state ID. But rather + * than dynamically allocate it and have to free it later, + * just point part way into the property name for the string. + */ + if (ret < 0) { + /* strlen("pinctrl-") == 8 */ + statename = prop->name + 8; + } + + /* For every referenced pin configuration node in it */ + for (config = 0; config < size; config++) { + phandle = be32_to_cpup(list++); + + /* Look up the pin configuration node */ + np_config = of_find_node_by_phandle(phandle); + if (!np_config) { + dev_err(p->dev, + "prop %s index %i invalid phandle\n", + prop->name, config); + ret = -EINVAL; + goto err; + } + + /* Parse the node */ + ret = dt_to_map_one_config(p, statename, np_config); + of_node_put(np_config); + if (ret < 0) + goto err; + } + + /* No entries in DT? Generate a dummy state table entry */ + if (!size) { + ret = dt_remember_dummy_state(p, statename); + if (ret < 0) + goto err; + } + } + + return 0; + +err: + pinctrl_dt_free_maps(p); + return ret; +} diff --git a/trunk/drivers/pinctrl/devicetree.h b/trunk/drivers/pinctrl/devicetree.h new file mode 100644 index 000000000000..760bc4960f58 --- /dev/null +++ b/trunk/drivers/pinctrl/devicetree.h @@ -0,0 +1,35 @@ +/* + * Internal interface to pinctrl device tree integration + * + * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * 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 . + */ + +#ifdef CONFIG_OF + +void pinctrl_dt_free_maps(struct pinctrl *p); +int pinctrl_dt_to_map(struct pinctrl *p); + +#else + +static inline int pinctrl_dt_to_map(struct pinctrl *p) +{ + return 0; +} + +static inline void pinctrl_dt_free_maps(struct pinctrl *p) +{ +} + +#endif diff --git a/trunk/drivers/pinctrl/pinconf.c b/trunk/drivers/pinctrl/pinconf.c index 7321e8601294..43f474cdc110 100644 --- a/trunk/drivers/pinctrl/pinconf.c +++ b/trunk/drivers/pinctrl/pinconf.c @@ -28,11 +28,17 @@ int pinconf_check_ops(struct pinctrl_dev *pctldev) const struct pinconf_ops *ops = pctldev->desc->confops; /* We must be able to read out pin status */ - if (!ops->pin_config_get && !ops->pin_config_group_get) + if (!ops->pin_config_get && !ops->pin_config_group_get) { + dev_err(pctldev->dev, + "pinconf must be able to read out pin status\n"); return -EINVAL; + } /* We have to be able to config the pins in SOME way */ - if (!ops->pin_config_set && !ops->pin_config_group_set) + if (!ops->pin_config_set && !ops->pin_config_group_set) { + dev_err(pctldev->dev, + "pinconf has to be able to set a pins config\n"); return -EINVAL; + } return 0; } @@ -44,9 +50,9 @@ int pinconf_validate_map(struct pinctrl_map const *map, int i) return -EINVAL; } - if (map->data.configs.num_configs && + if (!map->data.configs.num_configs || !map->data.configs.configs) { - pr_err("failed to register map %s (%d): no configs ptr given\n", + pr_err("failed to register map %s (%d): no configs given\n", map->name, i); return -EINVAL; } @@ -379,8 +385,16 @@ int pinconf_apply_setting(struct pinctrl_setting const *setting) void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map) { + struct pinctrl_dev *pctldev; + const struct pinconf_ops *confops; int i; + pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name); + if (pctldev) + confops = pctldev->desc->confops; + else + confops = NULL; + switch (map->type) { case PIN_MAP_TYPE_CONFIGS_PIN: seq_printf(s, "pin "); @@ -394,8 +408,15 @@ void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map) seq_printf(s, "%s\n", map->data.configs.group_or_pin); - for (i = 0; i < map->data.configs.num_configs; i++) - seq_printf(s, "config %08lx\n", map->data.configs.configs[i]); + for (i = 0; i < map->data.configs.num_configs; i++) { + seq_printf(s, "config "); + if (confops && confops->pin_config_config_dbg_show) + confops->pin_config_config_dbg_show(pctldev, s, + map->data.configs.configs[i]); + else + seq_printf(s, "%08lx", map->data.configs.configs[i]); + seq_printf(s, "\n"); + } } void pinconf_show_setting(struct seq_file *s, @@ -403,6 +424,7 @@ void pinconf_show_setting(struct seq_file *s, { struct pinctrl_dev *pctldev = setting->pctldev; const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; + const struct pinconf_ops *confops = pctldev->desc->confops; struct pin_desc *desc; int i; @@ -428,8 +450,15 @@ void pinconf_show_setting(struct seq_file *s, * FIXME: We should really get the pin controler to dump the config * values, so they can be decoded to something meaningful. */ - for (i = 0; i < setting->data.configs.num_configs; i++) - seq_printf(s, " %08lx", setting->data.configs.configs[i]); + for (i = 0; i < setting->data.configs.num_configs; i++) { + seq_printf(s, " "); + if (confops && confops->pin_config_config_dbg_show) + confops->pin_config_config_dbg_show(pctldev, s, + setting->data.configs.configs[i]); + else + seq_printf(s, "%08lx", + setting->data.configs.configs[i]); + } seq_printf(s, "\n"); } @@ -448,10 +477,14 @@ static void pinconf_dump_pin(struct pinctrl_dev *pctldev, static int pinconf_pins_show(struct seq_file *s, void *what) { struct pinctrl_dev *pctldev = s->private; + const struct pinconf_ops *ops = pctldev->desc->confops; unsigned i, pin; + if (!ops || !ops->pin_config_get) + return 0; + seq_puts(s, "Pin config settings per pin\n"); - seq_puts(s, "Format: pin (name): pinmux setting array\n"); + seq_puts(s, "Format: pin (name): configs\n"); mutex_lock(&pinctrl_mutex); @@ -495,17 +528,18 @@ static int pinconf_groups_show(struct seq_file *s, void *what) struct pinctrl_dev *pctldev = s->private; const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; const struct pinconf_ops *ops = pctldev->desc->confops; + unsigned ngroups = pctlops->get_groups_count(pctldev); unsigned selector = 0; if (!ops || !ops->pin_config_group_get) return 0; seq_puts(s, "Pin config settings per pin group\n"); - seq_puts(s, "Format: group (name): pinmux setting array\n"); + seq_puts(s, "Format: group (name): configs\n"); mutex_lock(&pinctrl_mutex); - while (pctlops->list_groups(pctldev, selector) >= 0) { + while (selector < ngroups) { const char *gname = pctlops->get_group_name(pctldev, selector); seq_printf(s, "%u (%s):", selector, gname); diff --git a/trunk/drivers/pinctrl/pinconf.h b/trunk/drivers/pinctrl/pinconf.h index 54510de5e8c6..e3ed8cb072a5 100644 --- a/trunk/drivers/pinctrl/pinconf.h +++ b/trunk/drivers/pinctrl/pinconf.h @@ -19,11 +19,6 @@ int pinconf_map_to_setting(struct pinctrl_map const *map, struct pinctrl_setting *setting); void pinconf_free_setting(struct pinctrl_setting const *setting); int pinconf_apply_setting(struct pinctrl_setting const *setting); -void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map); -void pinconf_show_setting(struct seq_file *s, - struct pinctrl_setting const *setting); -void pinconf_init_device_debugfs(struct dentry *devroot, - struct pinctrl_dev *pctldev); /* * You will only be interested in these if you're using PINCONF @@ -61,6 +56,18 @@ static inline int pinconf_apply_setting(struct pinctrl_setting const *setting) return 0; } +#endif + +#if defined(CONFIG_PINCONF) && defined(CONFIG_DEBUG_FS) + +void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map); +void pinconf_show_setting(struct seq_file *s, + struct pinctrl_setting const *setting); +void pinconf_init_device_debugfs(struct dentry *devroot, + struct pinctrl_dev *pctldev); + +#else + static inline void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map) { diff --git a/trunk/drivers/pinctrl/pinctrl-coh901.c b/trunk/drivers/pinctrl/pinctrl-coh901.c index 0797eba3e33a..55697a5d7482 100644 --- a/trunk/drivers/pinctrl/pinctrl-coh901.c +++ b/trunk/drivers/pinctrl/pinctrl-coh901.c @@ -174,7 +174,7 @@ struct u300_gpio_confdata { /* Initial configuration */ -static const struct __initdata u300_gpio_confdata +static const struct __initconst u300_gpio_confdata bs335_gpio_config[BS335_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = { /* Port 0, pins 0-7 */ { @@ -255,7 +255,7 @@ bs335_gpio_config[BS335_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = { } }; -static const struct __initdata u300_gpio_confdata +static const struct __initconst u300_gpio_confdata bs365_gpio_config[BS365_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = { /* Port 0, pins 0-7 */ { diff --git a/trunk/drivers/pinctrl/pinctrl-imx.c b/trunk/drivers/pinctrl/pinctrl-imx.c new file mode 100644 index 000000000000..f6e7c670906c --- /dev/null +++ b/trunk/drivers/pinctrl/pinctrl-imx.c @@ -0,0 +1,620 @@ +/* + * Core driver for the imx pin controller + * + * Copyright (C) 2012 Freescale Semiconductor, Inc. + * Copyright (C) 2012 Linaro Ltd. + * + * Author: Dong Aisheng + * + * 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 "core.h" +#include "pinctrl-imx.h" + +#define IMX_PMX_DUMP(info, p, m, c, n) \ +{ \ + int i, j; \ + printk("Format: Pin Mux Config\n"); \ + for (i = 0; i < n; i++) { \ + j = p[i]; \ + printk("%s %d 0x%lx\n", \ + info->pins[j].name, \ + m[i], c[i]); \ + } \ +} + +/* The bits in CONFIG cell defined in binding doc*/ +#define IMX_NO_PAD_CTL 0x80000000 /* no pin config need */ +#define IMX_PAD_SION 0x40000000 /* set SION */ + +/** + * @dev: a pointer back to containing device + * @base: the offset to the controller in virtual memory + */ +struct imx_pinctrl { + struct device *dev; + struct pinctrl_dev *pctl; + void __iomem *base; + const struct imx_pinctrl_soc_info *info; +}; + +static const struct imx_pin_reg *imx_find_pin_reg( + const struct imx_pinctrl_soc_info *info, + unsigned pin, bool is_mux, unsigned mux) +{ + const struct imx_pin_reg *pin_reg = NULL; + int i; + + for (i = 0; i < info->npin_regs; i++) { + pin_reg = &info->pin_regs[i]; + if (pin_reg->pid != pin) + continue; + if (!is_mux) + break; + else if (pin_reg->mux_mode == (mux & IMX_MUX_MASK)) + break; + } + + if (!pin_reg) { + dev_err(info->dev, "Pin(%s): unable to find pin reg map\n", + info->pins[pin].name); + return NULL; + } + + return pin_reg; +} + +static const inline struct imx_pin_group *imx_pinctrl_find_group_by_name( + const struct imx_pinctrl_soc_info *info, + const char *name) +{ + const struct imx_pin_group *grp = NULL; + int i; + + for (i = 0; i < info->ngroups; i++) { + if (!strcmp(info->groups[i].name, name)) { + grp = &info->groups[i]; + break; + } + } + + return grp; +} + +static int imx_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct imx_pinctrl_soc_info *info = ipctl->info; + + return info->ngroups; +} + +static const char *imx_get_group_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct imx_pinctrl_soc_info *info = ipctl->info; + + return info->groups[selector].name; +} + +static int imx_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, + const unsigned **pins, + unsigned *npins) +{ + struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct imx_pinctrl_soc_info *info = ipctl->info; + + if (selector >= info->ngroups) + return -EINVAL; + + *pins = info->groups[selector].pins; + *npins = info->groups[selector].npins; + + return 0; +} + +static void imx_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, + unsigned offset) +{ + seq_printf(s, "%s", dev_name(pctldev->dev)); +} + +static int imx_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, unsigned *num_maps) +{ + struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct imx_pinctrl_soc_info *info = ipctl->info; + const struct imx_pin_group *grp; + struct pinctrl_map *new_map; + struct device_node *parent; + int map_num = 1; + int i; + + /* + * first find the group of this node and check if we need create + * config maps for pins + */ + grp = imx_pinctrl_find_group_by_name(info, np->name); + if (!grp) { + dev_err(info->dev, "unable to find group for node %s\n", + np->name); + return -EINVAL; + } + + for (i = 0; i < grp->npins; i++) { + if (!(grp->configs[i] & IMX_NO_PAD_CTL)) + map_num++; + } + + new_map = kmalloc(sizeof(struct pinctrl_map) * map_num, GFP_KERNEL); + if (!new_map) + return -ENOMEM; + + *map = new_map; + *num_maps = map_num; + + /* create mux map */ + parent = of_get_parent(np); + if (!parent) + return -EINVAL; + new_map[0].type = PIN_MAP_TYPE_MUX_GROUP; + new_map[0].data.mux.function = parent->name; + new_map[0].data.mux.group = np->name; + of_node_put(parent); + + /* create config map */ + new_map++; + for (i = 0; i < grp->npins; i++) { + if (!(grp->configs[i] & IMX_NO_PAD_CTL)) { + new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN; + new_map[i].data.configs.group_or_pin = + pin_get_name(pctldev, grp->pins[i]); + new_map[i].data.configs.configs = &grp->configs[i]; + new_map[i].data.configs.num_configs = 1; + } + } + + dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n", + new_map->data.mux.function, new_map->data.mux.group, map_num); + + return 0; +} + +static void imx_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) +{ + int i; + + for (i = 0; i < num_maps; i++) + kfree(map); +} + +static struct pinctrl_ops imx_pctrl_ops = { + .get_groups_count = imx_get_groups_count, + .get_group_name = imx_get_group_name, + .get_group_pins = imx_get_group_pins, + .pin_dbg_show = imx_pin_dbg_show, + .dt_node_to_map = imx_dt_node_to_map, + .dt_free_map = imx_dt_free_map, + +}; + +static int imx_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group) +{ + struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct imx_pinctrl_soc_info *info = ipctl->info; + const struct imx_pin_reg *pin_reg; + const unsigned *pins, *mux; + unsigned int npins, pin_id; + int i; + + /* + * Configure the mux mode for each pin in the group for a specific + * function. + */ + pins = info->groups[group].pins; + npins = info->groups[group].npins; + mux = info->groups[group].mux_mode; + + WARN_ON(!pins || !npins || !mux); + + dev_dbg(ipctl->dev, "enable function %s group %s\n", + info->functions[selector].name, info->groups[group].name); + + for (i = 0; i < npins; i++) { + pin_id = pins[i]; + + pin_reg = imx_find_pin_reg(info, pin_id, 1, mux[i]); + if (!pin_reg) + return -EINVAL; + + if (!pin_reg->mux_reg) { + dev_err(ipctl->dev, "Pin(%s) does not support mux function\n", + info->pins[pin_id].name); + return -EINVAL; + } + + writel(mux[i], ipctl->base + pin_reg->mux_reg); + dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n", + pin_reg->mux_reg, mux[i]); + + /* some pins also need select input setting, set it if found */ + if (pin_reg->input_reg) { + writel(pin_reg->input_val, ipctl->base + pin_reg->input_reg); + dev_dbg(ipctl->dev, + "==>select_input: offset 0x%x val 0x%x\n", + pin_reg->input_reg, pin_reg->input_val); + } + } + + return 0; +} + +static int imx_pmx_get_funcs_count(struct pinctrl_dev *pctldev) +{ + struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct imx_pinctrl_soc_info *info = ipctl->info; + + return info->nfunctions; +} + +static const char *imx_pmx_get_func_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct imx_pinctrl_soc_info *info = ipctl->info; + + return info->functions[selector].name; +} + +static int imx_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector, + const char * const **groups, + unsigned * const num_groups) +{ + struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct imx_pinctrl_soc_info *info = ipctl->info; + + *groups = info->functions[selector].groups; + *num_groups = info->functions[selector].num_groups; + + return 0; +} + +static struct pinmux_ops imx_pmx_ops = { + .get_functions_count = imx_pmx_get_funcs_count, + .get_function_name = imx_pmx_get_func_name, + .get_function_groups = imx_pmx_get_groups, + .enable = imx_pmx_enable, +}; + +static int imx_pinconf_get(struct pinctrl_dev *pctldev, + unsigned pin_id, unsigned long *config) +{ + struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct imx_pinctrl_soc_info *info = ipctl->info; + const struct imx_pin_reg *pin_reg; + + pin_reg = imx_find_pin_reg(info, pin_id, 0, 0); + if (!pin_reg) + return -EINVAL; + + if (!pin_reg->conf_reg) { + dev_err(info->dev, "Pin(%s) does not support config function\n", + info->pins[pin_id].name); + return -EINVAL; + } + + *config = readl(ipctl->base + pin_reg->conf_reg); + + return 0; +} + +static int imx_pinconf_set(struct pinctrl_dev *pctldev, + unsigned pin_id, unsigned long config) +{ + struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct imx_pinctrl_soc_info *info = ipctl->info; + const struct imx_pin_reg *pin_reg; + + pin_reg = imx_find_pin_reg(info, pin_id, 0, 0); + if (!pin_reg) + return -EINVAL; + + if (!pin_reg->conf_reg) { + dev_err(info->dev, "Pin(%s) does not support config function\n", + info->pins[pin_id].name); + return -EINVAL; + } + + dev_dbg(ipctl->dev, "pinconf set pin %s\n", + info->pins[pin_id].name); + + writel(config, ipctl->base + pin_reg->conf_reg); + dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%lx\n", + pin_reg->conf_reg, config); + + return 0; +} + +static void imx_pinconf_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned pin_id) +{ + struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct imx_pinctrl_soc_info *info = ipctl->info; + const struct imx_pin_reg *pin_reg; + unsigned long config; + + pin_reg = imx_find_pin_reg(info, pin_id, 0, 0); + if (!pin_reg || !pin_reg->conf_reg) { + seq_printf(s, "N/A"); + return; + } + + config = readl(ipctl->base + pin_reg->conf_reg); + seq_printf(s, "0x%lx", config); +} + +static void imx_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned group) +{ + struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pin_group *grp; + unsigned long config; + const char *name; + int i, ret; + + if (group > info->ngroups) + return; + + seq_printf(s, "\n"); + grp = &info->groups[group]; + for (i = 0; i < grp->npins; i++) { + name = pin_get_name(pctldev, grp->pins[i]); + ret = imx_pinconf_get(pctldev, grp->pins[i], &config); + if (ret) + return; + seq_printf(s, "%s: 0x%lx", name, config); + } +} + +struct pinconf_ops imx_pinconf_ops = { + .pin_config_get = imx_pinconf_get, + .pin_config_set = imx_pinconf_set, + .pin_config_dbg_show = imx_pinconf_dbg_show, + .pin_config_group_dbg_show = imx_pinconf_group_dbg_show, +}; + +static struct pinctrl_desc imx_pinctrl_desc = { + .pctlops = &imx_pctrl_ops, + .pmxops = &imx_pmx_ops, + .confops = &imx_pinconf_ops, + .owner = THIS_MODULE, +}; + +/* decode pin id and mux from pin function id got from device tree*/ +static int imx_pinctrl_get_pin_id_and_mux(const struct imx_pinctrl_soc_info *info, + unsigned int pin_func_id, unsigned int *pin_id, + unsigned int *mux) +{ + if (pin_func_id > info->npin_regs) + return -EINVAL; + + *pin_id = info->pin_regs[pin_func_id].pid; + *mux = info->pin_regs[pin_func_id].mux_mode; + + return 0; +} + +static int __devinit imx_pinctrl_parse_groups(struct device_node *np, + struct imx_pin_group *grp, + struct imx_pinctrl_soc_info *info, + u32 index) +{ + unsigned int pin_func_id; + int ret, size; + const const __be32 *list; + int i, j; + u32 config; + + dev_dbg(info->dev, "group(%d): %s\n", index, np->name); + + /* Initialise group */ + grp->name = np->name; + + /* + * the binding format is fsl,pins = , + * do sanity check and calculate pins number + */ + list = of_get_property(np, "fsl,pins", &size); + /* we do not check return since it's safe node passed down */ + size /= sizeof(*list); + if (!size || size % 2) { + dev_err(info->dev, "wrong pins number or pins and configs should be pairs\n"); + return -EINVAL; + } + + grp->npins = size / 2; + grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int), + GFP_KERNEL); + grp->mux_mode = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int), + GFP_KERNEL); + grp->configs = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned long), + GFP_KERNEL); + for (i = 0, j = 0; i < size; i += 2, j++) { + pin_func_id = be32_to_cpu(*list++); + ret = imx_pinctrl_get_pin_id_and_mux(info, pin_func_id, + &grp->pins[j], &grp->mux_mode[j]); + if (ret) { + dev_err(info->dev, "get invalid pin function id\n"); + return -EINVAL; + } + /* SION bit is in mux register */ + config = be32_to_cpu(*list++); + if (config & IMX_PAD_SION) + grp->mux_mode[j] |= IOMUXC_CONFIG_SION; + grp->configs[j] = config & ~IMX_PAD_SION; + } + +#ifdef DEBUG + IMX_PMX_DUMP(info, grp->pins, grp->mux_mode, grp->configs, grp->npins); +#endif + return 0; +} + +static int __devinit imx_pinctrl_parse_functions(struct device_node *np, + struct imx_pinctrl_soc_info *info, u32 index) +{ + struct device_node *child; + struct imx_pmx_func *func; + struct imx_pin_group *grp; + int ret; + static u32 grp_index; + u32 i = 0; + + dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name); + + func = &info->functions[index]; + + /* Initialise function */ + func->name = np->name; + func->num_groups = of_get_child_count(np); + if (func->num_groups <= 0) { + dev_err(info->dev, "no groups defined\n"); + return -EINVAL; + } + func->groups = devm_kzalloc(info->dev, + func->num_groups * sizeof(char *), GFP_KERNEL); + + for_each_child_of_node(np, child) { + func->groups[i] = child->name; + grp = &info->groups[grp_index++]; + ret = imx_pinctrl_parse_groups(child, grp, info, i++); + if (ret) + return ret; + } + + return 0; +} + +static int __devinit imx_pinctrl_probe_dt(struct platform_device *pdev, + struct imx_pinctrl_soc_info *info) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *child; + int ret; + u32 nfuncs = 0; + u32 i = 0; + + if (!np) + return -ENODEV; + + nfuncs = of_get_child_count(np); + if (nfuncs <= 0) { + dev_err(&pdev->dev, "no functions defined\n"); + return -EINVAL; + } + + info->nfunctions = nfuncs; + info->functions = devm_kzalloc(&pdev->dev, nfuncs * sizeof(struct imx_pmx_func), + GFP_KERNEL); + if (!info->functions) + return -ENOMEM; + + info->ngroups = 0; + for_each_child_of_node(np, child) + info->ngroups += of_get_child_count(child); + info->groups = devm_kzalloc(&pdev->dev, info->ngroups * sizeof(struct imx_pin_group), + GFP_KERNEL); + if (!info->groups) + return -ENOMEM; + + for_each_child_of_node(np, child) { + ret = imx_pinctrl_parse_functions(child, info, i++); + if (ret) { + dev_err(&pdev->dev, "failed to parse function\n"); + return ret; + } + } + + return 0; +} + +int __devinit imx_pinctrl_probe(struct platform_device *pdev, + struct imx_pinctrl_soc_info *info) +{ + struct imx_pinctrl *ipctl; + struct resource *res; + int ret; + + if (!info || !info->pins || !info->npins + || !info->pin_regs || !info->npin_regs) { + dev_err(&pdev->dev, "wrong pinctrl info\n"); + return -EINVAL; + } + info->dev = &pdev->dev; + + /* Create state holders etc for this driver */ + ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL); + if (!ipctl) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENOENT; + + ipctl->base = devm_request_and_ioremap(&pdev->dev, res); + if (!ipctl->base) + return -EBUSY; + + imx_pinctrl_desc.name = dev_name(&pdev->dev); + imx_pinctrl_desc.pins = info->pins; + imx_pinctrl_desc.npins = info->npins; + + ret = imx_pinctrl_probe_dt(pdev, info); + if (ret) { + dev_err(&pdev->dev, "fail to probe dt properties\n"); + return ret; + } + + ipctl->info = info; + ipctl->dev = info->dev; + platform_set_drvdata(pdev, ipctl); + ipctl->pctl = pinctrl_register(&imx_pinctrl_desc, &pdev->dev, ipctl); + if (!ipctl->pctl) { + dev_err(&pdev->dev, "could not register IMX pinctrl driver\n"); + return -EINVAL; + } + + dev_info(&pdev->dev, "initialized IMX pinctrl driver\n"); + + return 0; +} + +int __devexit imx_pinctrl_remove(struct platform_device *pdev) +{ + struct imx_pinctrl *ipctl = platform_get_drvdata(pdev); + + pinctrl_unregister(ipctl->pctl); + + return 0; +} diff --git a/trunk/drivers/pinctrl/pinctrl-imx.h b/trunk/drivers/pinctrl/pinctrl-imx.h new file mode 100644 index 000000000000..9b65e7828f1d --- /dev/null +++ b/trunk/drivers/pinctrl/pinctrl-imx.h @@ -0,0 +1,106 @@ +/* + * IMX pinmux core definitions + * + * Copyright (C) 2012 Freescale Semiconductor, Inc. + * Copyright (C) 2012 Linaro Ltd. + * + * Author: Dong Aisheng + * + * 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 __DRIVERS_PINCTRL_IMX_H +#define __DRIVERS_PINCTRL_IMX_H + +struct platform_device; + +/** + * struct imx_pin_group - describes an IMX pin group + * @name: the name of this specific pin group + * @pins: an array of discrete physical pins used in this group, taken + * from the driver-local pin enumeration space + * @npins: the number of pins in this group array, i.e. the number of + * elements in .pins so we can iterate over that array + * @mux_mode: the mux mode for each pin in this group. The size of this + * array is the same as pins. + * @configs: the config for each pin in this group. The size of this + * array is the same as pins. + */ +struct imx_pin_group { + const char *name; + unsigned int *pins; + unsigned npins; + unsigned int *mux_mode; + unsigned long *configs; +}; + +/** + * struct imx_pmx_func - describes IMX pinmux functions + * @name: the name of this specific function + * @groups: corresponding pin groups + * @num_groups: the number of groups + */ +struct imx_pmx_func { + const char *name; + const char **groups; + unsigned num_groups; +}; + +/** + * struct imx_pin_reg - describe a pin reg map + * The last 3 members are used for select input setting + * @pid: pin id + * @mux_reg: mux register offset + * @conf_reg: config register offset + * @mux_mode: mux mode + * @input_reg: select input register offset for this mux if any + * 0 if no select input setting needed. + * @input_val: the value set to select input register + */ +struct imx_pin_reg { + u16 pid; + u16 mux_reg; + u16 conf_reg; + u8 mux_mode; + u16 input_reg; + u8 input_val; +}; + +struct imx_pinctrl_soc_info { + struct device *dev; + const struct pinctrl_pin_desc *pins; + unsigned int npins; + const struct imx_pin_reg *pin_regs; + unsigned int npin_regs; + struct imx_pin_group *groups; + unsigned int ngroups; + struct imx_pmx_func *functions; + unsigned int nfunctions; +}; + +#define NO_MUX 0x0 +#define NO_PAD 0x0 + +#define IMX_PIN_REG(id, conf, mux, mode, input, val) \ + { \ + .pid = id, \ + .conf_reg = conf, \ + .mux_reg = mux, \ + .mux_mode = mode, \ + .input_reg = input, \ + .input_val = val, \ + } + +#define IMX_PINCTRL_PIN(pin) PINCTRL_PIN(pin, #pin) + +#define PAD_CTL_MASK(len) ((1 << len) - 1) +#define IMX_MUX_MASK 0x7 +#define IOMUXC_CONFIG_SION (0x1 << 4) + +int imx_pinctrl_probe(struct platform_device *pdev, + struct imx_pinctrl_soc_info *info); +int imx_pinctrl_remove(struct platform_device *pdev); +#endif /* __DRIVERS_PINCTRL_IMX_H */ diff --git a/trunk/drivers/pinctrl/pinctrl-imx23.c b/trunk/drivers/pinctrl/pinctrl-imx23.c new file mode 100644 index 000000000000..75d3eff94296 --- /dev/null +++ b/trunk/drivers/pinctrl/pinctrl-imx23.c @@ -0,0 +1,305 @@ +/* + * Copyright 2012 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 + */ + +#include +#include +#include +#include +#include "pinctrl-mxs.h" + +enum imx23_pin_enum { + GPMI_D00 = PINID(0, 0), + GPMI_D01 = PINID(0, 1), + GPMI_D02 = PINID(0, 2), + GPMI_D03 = PINID(0, 3), + GPMI_D04 = PINID(0, 4), + GPMI_D05 = PINID(0, 5), + GPMI_D06 = PINID(0, 6), + GPMI_D07 = PINID(0, 7), + GPMI_D08 = PINID(0, 8), + GPMI_D09 = PINID(0, 9), + GPMI_D10 = PINID(0, 10), + GPMI_D11 = PINID(0, 11), + GPMI_D12 = PINID(0, 12), + GPMI_D13 = PINID(0, 13), + GPMI_D14 = PINID(0, 14), + GPMI_D15 = PINID(0, 15), + GPMI_CLE = PINID(0, 16), + GPMI_ALE = PINID(0, 17), + GPMI_CE2N = PINID(0, 18), + GPMI_RDY0 = PINID(0, 19), + GPMI_RDY1 = PINID(0, 20), + GPMI_RDY2 = PINID(0, 21), + GPMI_RDY3 = PINID(0, 22), + GPMI_WPN = PINID(0, 23), + GPMI_WRN = PINID(0, 24), + GPMI_RDN = PINID(0, 25), + AUART1_CTS = PINID(0, 26), + AUART1_RTS = PINID(0, 27), + AUART1_RX = PINID(0, 28), + AUART1_TX = PINID(0, 29), + I2C_SCL = PINID(0, 30), + I2C_SDA = PINID(0, 31), + LCD_D00 = PINID(1, 0), + LCD_D01 = PINID(1, 1), + LCD_D02 = PINID(1, 2), + LCD_D03 = PINID(1, 3), + LCD_D04 = PINID(1, 4), + LCD_D05 = PINID(1, 5), + LCD_D06 = PINID(1, 6), + LCD_D07 = PINID(1, 7), + LCD_D08 = PINID(1, 8), + LCD_D09 = PINID(1, 9), + LCD_D10 = PINID(1, 10), + LCD_D11 = PINID(1, 11), + LCD_D12 = PINID(1, 12), + LCD_D13 = PINID(1, 13), + LCD_D14 = PINID(1, 14), + LCD_D15 = PINID(1, 15), + LCD_D16 = PINID(1, 16), + LCD_D17 = PINID(1, 17), + LCD_RESET = PINID(1, 18), + LCD_RS = PINID(1, 19), + LCD_WR = PINID(1, 20), + LCD_CS = PINID(1, 21), + LCD_DOTCK = PINID(1, 22), + LCD_ENABLE = PINID(1, 23), + LCD_HSYNC = PINID(1, 24), + LCD_VSYNC = PINID(1, 25), + PWM0 = PINID(1, 26), + PWM1 = PINID(1, 27), + PWM2 = PINID(1, 28), + PWM3 = PINID(1, 29), + PWM4 = PINID(1, 30), + SSP1_CMD = PINID(2, 0), + SSP1_DETECT = PINID(2, 1), + SSP1_DATA0 = PINID(2, 2), + SSP1_DATA1 = PINID(2, 3), + SSP1_DATA2 = PINID(2, 4), + SSP1_DATA3 = PINID(2, 5), + SSP1_SCK = PINID(2, 6), + ROTARYA = PINID(2, 7), + ROTARYB = PINID(2, 8), + EMI_A00 = PINID(2, 9), + EMI_A01 = PINID(2, 10), + EMI_A02 = PINID(2, 11), + EMI_A03 = PINID(2, 12), + EMI_A04 = PINID(2, 13), + EMI_A05 = PINID(2, 14), + EMI_A06 = PINID(2, 15), + EMI_A07 = PINID(2, 16), + EMI_A08 = PINID(2, 17), + EMI_A09 = PINID(2, 18), + EMI_A10 = PINID(2, 19), + EMI_A11 = PINID(2, 20), + EMI_A12 = PINID(2, 21), + EMI_BA0 = PINID(2, 22), + EMI_BA1 = PINID(2, 23), + EMI_CASN = PINID(2, 24), + EMI_CE0N = PINID(2, 25), + EMI_CE1N = PINID(2, 26), + GPMI_CE1N = PINID(2, 27), + GPMI_CE0N = PINID(2, 28), + EMI_CKE = PINID(2, 29), + EMI_RASN = PINID(2, 30), + EMI_WEN = PINID(2, 31), + EMI_D00 = PINID(3, 0), + EMI_D01 = PINID(3, 1), + EMI_D02 = PINID(3, 2), + EMI_D03 = PINID(3, 3), + EMI_D04 = PINID(3, 4), + EMI_D05 = PINID(3, 5), + EMI_D06 = PINID(3, 6), + EMI_D07 = PINID(3, 7), + EMI_D08 = PINID(3, 8), + EMI_D09 = PINID(3, 9), + EMI_D10 = PINID(3, 10), + EMI_D11 = PINID(3, 11), + EMI_D12 = PINID(3, 12), + EMI_D13 = PINID(3, 13), + EMI_D14 = PINID(3, 14), + EMI_D15 = PINID(3, 15), + EMI_DQM0 = PINID(3, 16), + EMI_DQM1 = PINID(3, 17), + EMI_DQS0 = PINID(3, 18), + EMI_DQS1 = PINID(3, 19), + EMI_CLK = PINID(3, 20), + EMI_CLKN = PINID(3, 21), +}; + +static const struct pinctrl_pin_desc imx23_pins[] = { + MXS_PINCTRL_PIN(GPMI_D00), + MXS_PINCTRL_PIN(GPMI_D01), + MXS_PINCTRL_PIN(GPMI_D02), + MXS_PINCTRL_PIN(GPMI_D03), + MXS_PINCTRL_PIN(GPMI_D04), + MXS_PINCTRL_PIN(GPMI_D05), + MXS_PINCTRL_PIN(GPMI_D06), + MXS_PINCTRL_PIN(GPMI_D07), + MXS_PINCTRL_PIN(GPMI_D08), + MXS_PINCTRL_PIN(GPMI_D09), + MXS_PINCTRL_PIN(GPMI_D10), + MXS_PINCTRL_PIN(GPMI_D11), + MXS_PINCTRL_PIN(GPMI_D12), + MXS_PINCTRL_PIN(GPMI_D13), + MXS_PINCTRL_PIN(GPMI_D14), + MXS_PINCTRL_PIN(GPMI_D15), + MXS_PINCTRL_PIN(GPMI_CLE), + MXS_PINCTRL_PIN(GPMI_ALE), + MXS_PINCTRL_PIN(GPMI_CE2N), + MXS_PINCTRL_PIN(GPMI_RDY0), + MXS_PINCTRL_PIN(GPMI_RDY1), + MXS_PINCTRL_PIN(GPMI_RDY2), + MXS_PINCTRL_PIN(GPMI_RDY3), + MXS_PINCTRL_PIN(GPMI_WPN), + MXS_PINCTRL_PIN(GPMI_WRN), + MXS_PINCTRL_PIN(GPMI_RDN), + MXS_PINCTRL_PIN(AUART1_CTS), + MXS_PINCTRL_PIN(AUART1_RTS), + MXS_PINCTRL_PIN(AUART1_RX), + MXS_PINCTRL_PIN(AUART1_TX), + MXS_PINCTRL_PIN(I2C_SCL), + MXS_PINCTRL_PIN(I2C_SDA), + MXS_PINCTRL_PIN(LCD_D00), + MXS_PINCTRL_PIN(LCD_D01), + MXS_PINCTRL_PIN(LCD_D02), + MXS_PINCTRL_PIN(LCD_D03), + MXS_PINCTRL_PIN(LCD_D04), + MXS_PINCTRL_PIN(LCD_D05), + MXS_PINCTRL_PIN(LCD_D06), + MXS_PINCTRL_PIN(LCD_D07), + MXS_PINCTRL_PIN(LCD_D08), + MXS_PINCTRL_PIN(LCD_D09), + MXS_PINCTRL_PIN(LCD_D10), + MXS_PINCTRL_PIN(LCD_D11), + MXS_PINCTRL_PIN(LCD_D12), + MXS_PINCTRL_PIN(LCD_D13), + MXS_PINCTRL_PIN(LCD_D14), + MXS_PINCTRL_PIN(LCD_D15), + MXS_PINCTRL_PIN(LCD_D16), + MXS_PINCTRL_PIN(LCD_D17), + MXS_PINCTRL_PIN(LCD_RESET), + MXS_PINCTRL_PIN(LCD_RS), + MXS_PINCTRL_PIN(LCD_WR), + MXS_PINCTRL_PIN(LCD_CS), + MXS_PINCTRL_PIN(LCD_DOTCK), + MXS_PINCTRL_PIN(LCD_ENABLE), + MXS_PINCTRL_PIN(LCD_HSYNC), + MXS_PINCTRL_PIN(LCD_VSYNC), + MXS_PINCTRL_PIN(PWM0), + MXS_PINCTRL_PIN(PWM1), + MXS_PINCTRL_PIN(PWM2), + MXS_PINCTRL_PIN(PWM3), + MXS_PINCTRL_PIN(PWM4), + MXS_PINCTRL_PIN(SSP1_CMD), + MXS_PINCTRL_PIN(SSP1_DETECT), + MXS_PINCTRL_PIN(SSP1_DATA0), + MXS_PINCTRL_PIN(SSP1_DATA1), + MXS_PINCTRL_PIN(SSP1_DATA2), + MXS_PINCTRL_PIN(SSP1_DATA3), + MXS_PINCTRL_PIN(SSP1_SCK), + MXS_PINCTRL_PIN(ROTARYA), + MXS_PINCTRL_PIN(ROTARYB), + MXS_PINCTRL_PIN(EMI_A00), + MXS_PINCTRL_PIN(EMI_A01), + MXS_PINCTRL_PIN(EMI_A02), + MXS_PINCTRL_PIN(EMI_A03), + MXS_PINCTRL_PIN(EMI_A04), + MXS_PINCTRL_PIN(EMI_A05), + MXS_PINCTRL_PIN(EMI_A06), + MXS_PINCTRL_PIN(EMI_A07), + MXS_PINCTRL_PIN(EMI_A08), + MXS_PINCTRL_PIN(EMI_A09), + MXS_PINCTRL_PIN(EMI_A10), + MXS_PINCTRL_PIN(EMI_A11), + MXS_PINCTRL_PIN(EMI_A12), + MXS_PINCTRL_PIN(EMI_BA0), + MXS_PINCTRL_PIN(EMI_BA1), + MXS_PINCTRL_PIN(EMI_CASN), + MXS_PINCTRL_PIN(EMI_CE0N), + MXS_PINCTRL_PIN(EMI_CE1N), + MXS_PINCTRL_PIN(GPMI_CE1N), + MXS_PINCTRL_PIN(GPMI_CE0N), + MXS_PINCTRL_PIN(EMI_CKE), + MXS_PINCTRL_PIN(EMI_RASN), + MXS_PINCTRL_PIN(EMI_WEN), + MXS_PINCTRL_PIN(EMI_D00), + MXS_PINCTRL_PIN(EMI_D01), + MXS_PINCTRL_PIN(EMI_D02), + MXS_PINCTRL_PIN(EMI_D03), + MXS_PINCTRL_PIN(EMI_D04), + MXS_PINCTRL_PIN(EMI_D05), + MXS_PINCTRL_PIN(EMI_D06), + MXS_PINCTRL_PIN(EMI_D07), + MXS_PINCTRL_PIN(EMI_D08), + MXS_PINCTRL_PIN(EMI_D09), + MXS_PINCTRL_PIN(EMI_D10), + MXS_PINCTRL_PIN(EMI_D11), + MXS_PINCTRL_PIN(EMI_D12), + MXS_PINCTRL_PIN(EMI_D13), + MXS_PINCTRL_PIN(EMI_D14), + MXS_PINCTRL_PIN(EMI_D15), + MXS_PINCTRL_PIN(EMI_DQM0), + MXS_PINCTRL_PIN(EMI_DQM1), + MXS_PINCTRL_PIN(EMI_DQS0), + MXS_PINCTRL_PIN(EMI_DQS1), + MXS_PINCTRL_PIN(EMI_CLK), + MXS_PINCTRL_PIN(EMI_CLKN), +}; + +static struct mxs_regs imx23_regs = { + .muxsel = 0x100, + .drive = 0x200, + .pull = 0x400, +}; + +static struct mxs_pinctrl_soc_data imx23_pinctrl_data = { + .regs = &imx23_regs, + .pins = imx23_pins, + .npins = ARRAY_SIZE(imx23_pins), +}; + +static int __devinit imx23_pinctrl_probe(struct platform_device *pdev) +{ + return mxs_pinctrl_probe(pdev, &imx23_pinctrl_data); +} + +static struct of_device_id imx23_pinctrl_of_match[] __devinitdata = { + { .compatible = "fsl,imx23-pinctrl", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, imx23_pinctrl_of_match); + +static struct platform_driver imx23_pinctrl_driver = { + .driver = { + .name = "imx23-pinctrl", + .owner = THIS_MODULE, + .of_match_table = imx23_pinctrl_of_match, + }, + .probe = imx23_pinctrl_probe, + .remove = __devexit_p(mxs_pinctrl_remove), +}; + +static int __init imx23_pinctrl_init(void) +{ + return platform_driver_register(&imx23_pinctrl_driver); +} +arch_initcall(imx23_pinctrl_init); + +static void __exit imx23_pinctrl_exit(void) +{ + platform_driver_unregister(&imx23_pinctrl_driver); +} +module_exit(imx23_pinctrl_exit); + +MODULE_AUTHOR("Shawn Guo "); +MODULE_DESCRIPTION("Freescale i.MX23 pinctrl driver"); +MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/pinctrl/pinctrl-imx28.c b/trunk/drivers/pinctrl/pinctrl-imx28.c new file mode 100644 index 000000000000..b973026811a2 --- /dev/null +++ b/trunk/drivers/pinctrl/pinctrl-imx28.c @@ -0,0 +1,421 @@ +/* + * Copyright 2012 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 + */ + +#include +#include +#include +#include +#include "pinctrl-mxs.h" + +enum imx28_pin_enum { + GPMI_D00 = PINID(0, 0), + GPMI_D01 = PINID(0, 1), + GPMI_D02 = PINID(0, 2), + GPMI_D03 = PINID(0, 3), + GPMI_D04 = PINID(0, 4), + GPMI_D05 = PINID(0, 5), + GPMI_D06 = PINID(0, 6), + GPMI_D07 = PINID(0, 7), + GPMI_CE0N = PINID(0, 16), + GPMI_CE1N = PINID(0, 17), + GPMI_CE2N = PINID(0, 18), + GPMI_CE3N = PINID(0, 19), + GPMI_RDY0 = PINID(0, 20), + GPMI_RDY1 = PINID(0, 21), + GPMI_RDY2 = PINID(0, 22), + GPMI_RDY3 = PINID(0, 23), + GPMI_RDN = PINID(0, 24), + GPMI_WRN = PINID(0, 25), + GPMI_ALE = PINID(0, 26), + GPMI_CLE = PINID(0, 27), + GPMI_RESETN = PINID(0, 28), + LCD_D00 = PINID(1, 0), + LCD_D01 = PINID(1, 1), + LCD_D02 = PINID(1, 2), + LCD_D03 = PINID(1, 3), + LCD_D04 = PINID(1, 4), + LCD_D05 = PINID(1, 5), + LCD_D06 = PINID(1, 6), + LCD_D07 = PINID(1, 7), + LCD_D08 = PINID(1, 8), + LCD_D09 = PINID(1, 9), + LCD_D10 = PINID(1, 10), + LCD_D11 = PINID(1, 11), + LCD_D12 = PINID(1, 12), + LCD_D13 = PINID(1, 13), + LCD_D14 = PINID(1, 14), + LCD_D15 = PINID(1, 15), + LCD_D16 = PINID(1, 16), + LCD_D17 = PINID(1, 17), + LCD_D18 = PINID(1, 18), + LCD_D19 = PINID(1, 19), + LCD_D20 = PINID(1, 20), + LCD_D21 = PINID(1, 21), + LCD_D22 = PINID(1, 22), + LCD_D23 = PINID(1, 23), + LCD_RD_E = PINID(1, 24), + LCD_WR_RWN = PINID(1, 25), + LCD_RS = PINID(1, 26), + LCD_CS = PINID(1, 27), + LCD_VSYNC = PINID(1, 28), + LCD_HSYNC = PINID(1, 29), + LCD_DOTCLK = PINID(1, 30), + LCD_ENABLE = PINID(1, 31), + SSP0_DATA0 = PINID(2, 0), + SSP0_DATA1 = PINID(2, 1), + SSP0_DATA2 = PINID(2, 2), + SSP0_DATA3 = PINID(2, 3), + SSP0_DATA4 = PINID(2, 4), + SSP0_DATA5 = PINID(2, 5), + SSP0_DATA6 = PINID(2, 6), + SSP0_DATA7 = PINID(2, 7), + SSP0_CMD = PINID(2, 8), + SSP0_DETECT = PINID(2, 9), + SSP0_SCK = PINID(2, 10), + SSP1_SCK = PINID(2, 12), + SSP1_CMD = PINID(2, 13), + SSP1_DATA0 = PINID(2, 14), + SSP1_DATA3 = PINID(2, 15), + SSP2_SCK = PINID(2, 16), + SSP2_MOSI = PINID(2, 17), + SSP2_MISO = PINID(2, 18), + SSP2_SS0 = PINID(2, 19), + SSP2_SS1 = PINID(2, 20), + SSP2_SS2 = PINID(2, 21), + SSP3_SCK = PINID(2, 24), + SSP3_MOSI = PINID(2, 25), + SSP3_MISO = PINID(2, 26), + SSP3_SS0 = PINID(2, 27), + AUART0_RX = PINID(3, 0), + AUART0_TX = PINID(3, 1), + AUART0_CTS = PINID(3, 2), + AUART0_RTS = PINID(3, 3), + AUART1_RX = PINID(3, 4), + AUART1_TX = PINID(3, 5), + AUART1_CTS = PINID(3, 6), + AUART1_RTS = PINID(3, 7), + AUART2_RX = PINID(3, 8), + AUART2_TX = PINID(3, 9), + AUART2_CTS = PINID(3, 10), + AUART2_RTS = PINID(3, 11), + AUART3_RX = PINID(3, 12), + AUART3_TX = PINID(3, 13), + AUART3_CTS = PINID(3, 14), + AUART3_RTS = PINID(3, 15), + PWM0 = PINID(3, 16), + PWM1 = PINID(3, 17), + PWM2 = PINID(3, 18), + SAIF0_MCLK = PINID(3, 20), + SAIF0_LRCLK = PINID(3, 21), + SAIF0_BITCLK = PINID(3, 22), + SAIF0_SDATA0 = PINID(3, 23), + I2C0_SCL = PINID(3, 24), + I2C0_SDA = PINID(3, 25), + SAIF1_SDATA0 = PINID(3, 26), + SPDIF = PINID(3, 27), + PWM3 = PINID(3, 28), + PWM4 = PINID(3, 29), + LCD_RESET = PINID(3, 30), + ENET0_MDC = PINID(4, 0), + ENET0_MDIO = PINID(4, 1), + ENET0_RX_EN = PINID(4, 2), + ENET0_RXD0 = PINID(4, 3), + ENET0_RXD1 = PINID(4, 4), + ENET0_TX_CLK = PINID(4, 5), + ENET0_TX_EN = PINID(4, 6), + ENET0_TXD0 = PINID(4, 7), + ENET0_TXD1 = PINID(4, 8), + ENET0_RXD2 = PINID(4, 9), + ENET0_RXD3 = PINID(4, 10), + ENET0_TXD2 = PINID(4, 11), + ENET0_TXD3 = PINID(4, 12), + ENET0_RX_CLK = PINID(4, 13), + ENET0_COL = PINID(4, 14), + ENET0_CRS = PINID(4, 15), + ENET_CLK = PINID(4, 16), + JTAG_RTCK = PINID(4, 20), + EMI_D00 = PINID(5, 0), + EMI_D01 = PINID(5, 1), + EMI_D02 = PINID(5, 2), + EMI_D03 = PINID(5, 3), + EMI_D04 = PINID(5, 4), + EMI_D05 = PINID(5, 5), + EMI_D06 = PINID(5, 6), + EMI_D07 = PINID(5, 7), + EMI_D08 = PINID(5, 8), + EMI_D09 = PINID(5, 9), + EMI_D10 = PINID(5, 10), + EMI_D11 = PINID(5, 11), + EMI_D12 = PINID(5, 12), + EMI_D13 = PINID(5, 13), + EMI_D14 = PINID(5, 14), + EMI_D15 = PINID(5, 15), + EMI_ODT0 = PINID(5, 16), + EMI_DQM0 = PINID(5, 17), + EMI_ODT1 = PINID(5, 18), + EMI_DQM1 = PINID(5, 19), + EMI_DDR_OPEN_FB = PINID(5, 20), + EMI_CLK = PINID(5, 21), + EMI_DQS0 = PINID(5, 22), + EMI_DQS1 = PINID(5, 23), + EMI_DDR_OPEN = PINID(5, 26), + EMI_A00 = PINID(6, 0), + EMI_A01 = PINID(6, 1), + EMI_A02 = PINID(6, 2), + EMI_A03 = PINID(6, 3), + EMI_A04 = PINID(6, 4), + EMI_A05 = PINID(6, 5), + EMI_A06 = PINID(6, 6), + EMI_A07 = PINID(6, 7), + EMI_A08 = PINID(6, 8), + EMI_A09 = PINID(6, 9), + EMI_A10 = PINID(6, 10), + EMI_A11 = PINID(6, 11), + EMI_A12 = PINID(6, 12), + EMI_A13 = PINID(6, 13), + EMI_A14 = PINID(6, 14), + EMI_BA0 = PINID(6, 16), + EMI_BA1 = PINID(6, 17), + EMI_BA2 = PINID(6, 18), + EMI_CASN = PINID(6, 19), + EMI_RASN = PINID(6, 20), + EMI_WEN = PINID(6, 21), + EMI_CE0N = PINID(6, 22), + EMI_CE1N = PINID(6, 23), + EMI_CKE = PINID(6, 24), +}; + +static const struct pinctrl_pin_desc imx28_pins[] = { + MXS_PINCTRL_PIN(GPMI_D00), + MXS_PINCTRL_PIN(GPMI_D01), + MXS_PINCTRL_PIN(GPMI_D02), + MXS_PINCTRL_PIN(GPMI_D03), + MXS_PINCTRL_PIN(GPMI_D04), + MXS_PINCTRL_PIN(GPMI_D05), + MXS_PINCTRL_PIN(GPMI_D06), + MXS_PINCTRL_PIN(GPMI_D07), + MXS_PINCTRL_PIN(GPMI_CE0N), + MXS_PINCTRL_PIN(GPMI_CE1N), + MXS_PINCTRL_PIN(GPMI_CE2N), + MXS_PINCTRL_PIN(GPMI_CE3N), + MXS_PINCTRL_PIN(GPMI_RDY0), + MXS_PINCTRL_PIN(GPMI_RDY1), + MXS_PINCTRL_PIN(GPMI_RDY2), + MXS_PINCTRL_PIN(GPMI_RDY3), + MXS_PINCTRL_PIN(GPMI_RDN), + MXS_PINCTRL_PIN(GPMI_WRN), + MXS_PINCTRL_PIN(GPMI_ALE), + MXS_PINCTRL_PIN(GPMI_CLE), + MXS_PINCTRL_PIN(GPMI_RESETN), + MXS_PINCTRL_PIN(LCD_D00), + MXS_PINCTRL_PIN(LCD_D01), + MXS_PINCTRL_PIN(LCD_D02), + MXS_PINCTRL_PIN(LCD_D03), + MXS_PINCTRL_PIN(LCD_D04), + MXS_PINCTRL_PIN(LCD_D05), + MXS_PINCTRL_PIN(LCD_D06), + MXS_PINCTRL_PIN(LCD_D07), + MXS_PINCTRL_PIN(LCD_D08), + MXS_PINCTRL_PIN(LCD_D09), + MXS_PINCTRL_PIN(LCD_D10), + MXS_PINCTRL_PIN(LCD_D11), + MXS_PINCTRL_PIN(LCD_D12), + MXS_PINCTRL_PIN(LCD_D13), + MXS_PINCTRL_PIN(LCD_D14), + MXS_PINCTRL_PIN(LCD_D15), + MXS_PINCTRL_PIN(LCD_D16), + MXS_PINCTRL_PIN(LCD_D17), + MXS_PINCTRL_PIN(LCD_D18), + MXS_PINCTRL_PIN(LCD_D19), + MXS_PINCTRL_PIN(LCD_D20), + MXS_PINCTRL_PIN(LCD_D21), + MXS_PINCTRL_PIN(LCD_D22), + MXS_PINCTRL_PIN(LCD_D23), + MXS_PINCTRL_PIN(LCD_RD_E), + MXS_PINCTRL_PIN(LCD_WR_RWN), + MXS_PINCTRL_PIN(LCD_RS), + MXS_PINCTRL_PIN(LCD_CS), + MXS_PINCTRL_PIN(LCD_VSYNC), + MXS_PINCTRL_PIN(LCD_HSYNC), + MXS_PINCTRL_PIN(LCD_DOTCLK), + MXS_PINCTRL_PIN(LCD_ENABLE), + MXS_PINCTRL_PIN(SSP0_DATA0), + MXS_PINCTRL_PIN(SSP0_DATA1), + MXS_PINCTRL_PIN(SSP0_DATA2), + MXS_PINCTRL_PIN(SSP0_DATA3), + MXS_PINCTRL_PIN(SSP0_DATA4), + MXS_PINCTRL_PIN(SSP0_DATA5), + MXS_PINCTRL_PIN(SSP0_DATA6), + MXS_PINCTRL_PIN(SSP0_DATA7), + MXS_PINCTRL_PIN(SSP0_CMD), + MXS_PINCTRL_PIN(SSP0_DETECT), + MXS_PINCTRL_PIN(SSP0_SCK), + MXS_PINCTRL_PIN(SSP1_SCK), + MXS_PINCTRL_PIN(SSP1_CMD), + MXS_PINCTRL_PIN(SSP1_DATA0), + MXS_PINCTRL_PIN(SSP1_DATA3), + MXS_PINCTRL_PIN(SSP2_SCK), + MXS_PINCTRL_PIN(SSP2_MOSI), + MXS_PINCTRL_PIN(SSP2_MISO), + MXS_PINCTRL_PIN(SSP2_SS0), + MXS_PINCTRL_PIN(SSP2_SS1), + MXS_PINCTRL_PIN(SSP2_SS2), + MXS_PINCTRL_PIN(SSP3_SCK), + MXS_PINCTRL_PIN(SSP3_MOSI), + MXS_PINCTRL_PIN(SSP3_MISO), + MXS_PINCTRL_PIN(SSP3_SS0), + MXS_PINCTRL_PIN(AUART0_RX), + MXS_PINCTRL_PIN(AUART0_TX), + MXS_PINCTRL_PIN(AUART0_CTS), + MXS_PINCTRL_PIN(AUART0_RTS), + MXS_PINCTRL_PIN(AUART1_RX), + MXS_PINCTRL_PIN(AUART1_TX), + MXS_PINCTRL_PIN(AUART1_CTS), + MXS_PINCTRL_PIN(AUART1_RTS), + MXS_PINCTRL_PIN(AUART2_RX), + MXS_PINCTRL_PIN(AUART2_TX), + MXS_PINCTRL_PIN(AUART2_CTS), + MXS_PINCTRL_PIN(AUART2_RTS), + MXS_PINCTRL_PIN(AUART3_RX), + MXS_PINCTRL_PIN(AUART3_TX), + MXS_PINCTRL_PIN(AUART3_CTS), + MXS_PINCTRL_PIN(AUART3_RTS), + MXS_PINCTRL_PIN(PWM0), + MXS_PINCTRL_PIN(PWM1), + MXS_PINCTRL_PIN(PWM2), + MXS_PINCTRL_PIN(SAIF0_MCLK), + MXS_PINCTRL_PIN(SAIF0_LRCLK), + MXS_PINCTRL_PIN(SAIF0_BITCLK), + MXS_PINCTRL_PIN(SAIF0_SDATA0), + MXS_PINCTRL_PIN(I2C0_SCL), + MXS_PINCTRL_PIN(I2C0_SDA), + MXS_PINCTRL_PIN(SAIF1_SDATA0), + MXS_PINCTRL_PIN(SPDIF), + MXS_PINCTRL_PIN(PWM3), + MXS_PINCTRL_PIN(PWM4), + MXS_PINCTRL_PIN(LCD_RESET), + MXS_PINCTRL_PIN(ENET0_MDC), + MXS_PINCTRL_PIN(ENET0_MDIO), + MXS_PINCTRL_PIN(ENET0_RX_EN), + MXS_PINCTRL_PIN(ENET0_RXD0), + MXS_PINCTRL_PIN(ENET0_RXD1), + MXS_PINCTRL_PIN(ENET0_TX_CLK), + MXS_PINCTRL_PIN(ENET0_TX_EN), + MXS_PINCTRL_PIN(ENET0_TXD0), + MXS_PINCTRL_PIN(ENET0_TXD1), + MXS_PINCTRL_PIN(ENET0_RXD2), + MXS_PINCTRL_PIN(ENET0_RXD3), + MXS_PINCTRL_PIN(ENET0_TXD2), + MXS_PINCTRL_PIN(ENET0_TXD3), + MXS_PINCTRL_PIN(ENET0_RX_CLK), + MXS_PINCTRL_PIN(ENET0_COL), + MXS_PINCTRL_PIN(ENET0_CRS), + MXS_PINCTRL_PIN(ENET_CLK), + MXS_PINCTRL_PIN(JTAG_RTCK), + MXS_PINCTRL_PIN(EMI_D00), + MXS_PINCTRL_PIN(EMI_D01), + MXS_PINCTRL_PIN(EMI_D02), + MXS_PINCTRL_PIN(EMI_D03), + MXS_PINCTRL_PIN(EMI_D04), + MXS_PINCTRL_PIN(EMI_D05), + MXS_PINCTRL_PIN(EMI_D06), + MXS_PINCTRL_PIN(EMI_D07), + MXS_PINCTRL_PIN(EMI_D08), + MXS_PINCTRL_PIN(EMI_D09), + MXS_PINCTRL_PIN(EMI_D10), + MXS_PINCTRL_PIN(EMI_D11), + MXS_PINCTRL_PIN(EMI_D12), + MXS_PINCTRL_PIN(EMI_D13), + MXS_PINCTRL_PIN(EMI_D14), + MXS_PINCTRL_PIN(EMI_D15), + MXS_PINCTRL_PIN(EMI_ODT0), + MXS_PINCTRL_PIN(EMI_DQM0), + MXS_PINCTRL_PIN(EMI_ODT1), + MXS_PINCTRL_PIN(EMI_DQM1), + MXS_PINCTRL_PIN(EMI_DDR_OPEN_FB), + MXS_PINCTRL_PIN(EMI_CLK), + MXS_PINCTRL_PIN(EMI_DQS0), + MXS_PINCTRL_PIN(EMI_DQS1), + MXS_PINCTRL_PIN(EMI_DDR_OPEN), + MXS_PINCTRL_PIN(EMI_A00), + MXS_PINCTRL_PIN(EMI_A01), + MXS_PINCTRL_PIN(EMI_A02), + MXS_PINCTRL_PIN(EMI_A03), + MXS_PINCTRL_PIN(EMI_A04), + MXS_PINCTRL_PIN(EMI_A05), + MXS_PINCTRL_PIN(EMI_A06), + MXS_PINCTRL_PIN(EMI_A07), + MXS_PINCTRL_PIN(EMI_A08), + MXS_PINCTRL_PIN(EMI_A09), + MXS_PINCTRL_PIN(EMI_A10), + MXS_PINCTRL_PIN(EMI_A11), + MXS_PINCTRL_PIN(EMI_A12), + MXS_PINCTRL_PIN(EMI_A13), + MXS_PINCTRL_PIN(EMI_A14), + MXS_PINCTRL_PIN(EMI_BA0), + MXS_PINCTRL_PIN(EMI_BA1), + MXS_PINCTRL_PIN(EMI_BA2), + MXS_PINCTRL_PIN(EMI_CASN), + MXS_PINCTRL_PIN(EMI_RASN), + MXS_PINCTRL_PIN(EMI_WEN), + MXS_PINCTRL_PIN(EMI_CE0N), + MXS_PINCTRL_PIN(EMI_CE1N), + MXS_PINCTRL_PIN(EMI_CKE), +}; + +static struct mxs_regs imx28_regs = { + .muxsel = 0x100, + .drive = 0x300, + .pull = 0x600, +}; + +static struct mxs_pinctrl_soc_data imx28_pinctrl_data = { + .regs = &imx28_regs, + .pins = imx28_pins, + .npins = ARRAY_SIZE(imx28_pins), +}; + +static int __devinit imx28_pinctrl_probe(struct platform_device *pdev) +{ + return mxs_pinctrl_probe(pdev, &imx28_pinctrl_data); +} + +static struct of_device_id imx28_pinctrl_of_match[] __devinitdata = { + { .compatible = "fsl,imx28-pinctrl", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, imx28_pinctrl_of_match); + +static struct platform_driver imx28_pinctrl_driver = { + .driver = { + .name = "imx28-pinctrl", + .owner = THIS_MODULE, + .of_match_table = imx28_pinctrl_of_match, + }, + .probe = imx28_pinctrl_probe, + .remove = __devexit_p(mxs_pinctrl_remove), +}; + +static int __init imx28_pinctrl_init(void) +{ + return platform_driver_register(&imx28_pinctrl_driver); +} +arch_initcall(imx28_pinctrl_init); + +static void __exit imx28_pinctrl_exit(void) +{ + platform_driver_unregister(&imx28_pinctrl_driver); +} +module_exit(imx28_pinctrl_exit); + +MODULE_AUTHOR("Shawn Guo "); +MODULE_DESCRIPTION("Freescale i.MX28 pinctrl driver"); +MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/pinctrl/pinctrl-imx51.c b/trunk/drivers/pinctrl/pinctrl-imx51.c new file mode 100644 index 000000000000..689b3c88dd2e --- /dev/null +++ b/trunk/drivers/pinctrl/pinctrl-imx51.c @@ -0,0 +1,1322 @@ +/* + * imx51 pinctrl driver based on imx pinmux core + * + * Copyright (C) 2012 Freescale Semiconductor, Inc. + * Copyright (C) 2012 Linaro, Inc. + * + * Author: Dong Aisheng + * + * 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 "pinctrl-imx.h" + +enum imx51_pads { + MX51_PAD_EIM_D16 = 1, + MX51_PAD_EIM_D17 = 2, + MX51_PAD_EIM_D18 = 3, + MX51_PAD_EIM_D19 = 4, + MX51_PAD_EIM_D20 = 5, + MX51_PAD_EIM_D21 = 6, + MX51_PAD_EIM_D22 = 7, + MX51_PAD_EIM_D23 = 8, + MX51_PAD_EIM_D24 = 9, + MX51_PAD_EIM_D25 = 10, + MX51_PAD_EIM_D26 = 11, + MX51_PAD_EIM_D27 = 12, + MX51_PAD_EIM_D28 = 13, + MX51_PAD_EIM_D29 = 14, + MX51_PAD_EIM_D30 = 15, + MX51_PAD_EIM_D31 = 16, + MX51_PAD_EIM_A16 = 17, + MX51_PAD_EIM_A17 = 18, + MX51_PAD_EIM_A18 = 19, + MX51_PAD_EIM_A19 = 20, + MX51_PAD_EIM_A20 = 21, + MX51_PAD_EIM_A21 = 22, + MX51_PAD_EIM_A22 = 23, + MX51_PAD_EIM_A23 = 24, + MX51_PAD_EIM_A24 = 25, + MX51_PAD_EIM_A25 = 26, + MX51_PAD_EIM_A26 = 27, + MX51_PAD_EIM_A27 = 28, + MX51_PAD_EIM_EB0 = 29, + MX51_PAD_EIM_EB1 = 30, + MX51_PAD_EIM_EB2 = 31, + MX51_PAD_EIM_EB3 = 32, + MX51_PAD_EIM_OE = 33, + MX51_PAD_EIM_CS0 = 34, + MX51_PAD_EIM_CS1 = 35, + MX51_PAD_EIM_CS2 = 36, + MX51_PAD_EIM_CS3 = 37, + MX51_PAD_EIM_CS4 = 38, + MX51_PAD_EIM_CS5 = 39, + MX51_PAD_EIM_DTACK = 40, + MX51_PAD_EIM_LBA = 41, + MX51_PAD_EIM_CRE = 42, + MX51_PAD_DRAM_CS1 = 43, + MX51_PAD_NANDF_WE_B = 44, + MX51_PAD_NANDF_RE_B = 45, + MX51_PAD_NANDF_ALE = 46, + MX51_PAD_NANDF_CLE = 47, + MX51_PAD_NANDF_WP_B = 48, + MX51_PAD_NANDF_RB0 = 49, + MX51_PAD_NANDF_RB1 = 50, + MX51_PAD_NANDF_RB2 = 51, + MX51_PAD_NANDF_RB3 = 52, + MX51_PAD_GPIO_NAND = 53, + MX51_PAD_NANDF_CS0 = 54, + MX51_PAD_NANDF_CS1 = 55, + MX51_PAD_NANDF_CS2 = 56, + MX51_PAD_NANDF_CS3 = 57, + MX51_PAD_NANDF_CS4 = 58, + MX51_PAD_NANDF_CS5 = 59, + MX51_PAD_NANDF_CS6 = 60, + MX51_PAD_NANDF_CS7 = 61, + MX51_PAD_NANDF_RDY_INT = 62, + MX51_PAD_NANDF_D15 = 63, + MX51_PAD_NANDF_D14 = 64, + MX51_PAD_NANDF_D13 = 65, + MX51_PAD_NANDF_D12 = 66, + MX51_PAD_NANDF_D11 = 67, + MX51_PAD_NANDF_D10 = 68, + MX51_PAD_NANDF_D9 = 69, + MX51_PAD_NANDF_D8 = 70, + MX51_PAD_NANDF_D7 = 71, + MX51_PAD_NANDF_D6 = 72, + MX51_PAD_NANDF_D5 = 73, + MX51_PAD_NANDF_D4 = 74, + MX51_PAD_NANDF_D3 = 75, + MX51_PAD_NANDF_D2 = 76, + MX51_PAD_NANDF_D1 = 77, + MX51_PAD_NANDF_D0 = 78, + MX51_PAD_CSI1_D8 = 79, + MX51_PAD_CSI1_D9 = 80, + MX51_PAD_CSI1_D10 = 81, + MX51_PAD_CSI1_D11 = 82, + MX51_PAD_CSI1_D12 = 83, + MX51_PAD_CSI1_D13 = 84, + MX51_PAD_CSI1_D14 = 85, + MX51_PAD_CSI1_D15 = 86, + MX51_PAD_CSI1_D16 = 87, + MX51_PAD_CSI1_D17 = 88, + MX51_PAD_CSI1_D18 = 89, + MX51_PAD_CSI1_D19 = 90, + MX51_PAD_CSI1_VSYNC = 91, + MX51_PAD_CSI1_HSYNC = 92, + MX51_PAD_CSI1_PIXCLK = 93, + MX51_PAD_CSI1_MCLK = 94, + MX51_PAD_CSI2_D12 = 95, + MX51_PAD_CSI2_D13 = 96, + MX51_PAD_CSI2_D14 = 97, + MX51_PAD_CSI2_D15 = 98, + MX51_PAD_CSI2_D16 = 99, + MX51_PAD_CSI2_D17 = 100, + MX51_PAD_CSI2_D18 = 101, + MX51_PAD_CSI2_D19 = 102, + MX51_PAD_CSI2_VSYNC = 103, + MX51_PAD_CSI2_HSYNC = 104, + MX51_PAD_CSI2_PIXCLK = 105, + MX51_PAD_I2C1_CLK = 106, + MX51_PAD_I2C1_DAT = 107, + MX51_PAD_AUD3_BB_TXD = 108, + MX51_PAD_AUD3_BB_RXD = 109, + MX51_PAD_AUD3_BB_CK = 110, + MX51_PAD_AUD3_BB_FS = 111, + MX51_PAD_CSPI1_MOSI = 112, + MX51_PAD_CSPI1_MISO = 113, + MX51_PAD_CSPI1_SS0 = 114, + MX51_PAD_CSPI1_SS1 = 115, + MX51_PAD_CSPI1_RDY = 116, + MX51_PAD_CSPI1_SCLK = 117, + MX51_PAD_UART1_RXD = 118, + MX51_PAD_UART1_TXD = 119, + MX51_PAD_UART1_RTS = 120, + MX51_PAD_UART1_CTS = 121, + MX51_PAD_UART2_RXD = 122, + MX51_PAD_UART2_TXD = 123, + MX51_PAD_UART3_RXD = 124, + MX51_PAD_UART3_TXD = 125, + MX51_PAD_OWIRE_LINE = 126, + MX51_PAD_KEY_ROW0 = 127, + MX51_PAD_KEY_ROW1 = 128, + MX51_PAD_KEY_ROW2 = 129, + MX51_PAD_KEY_ROW3 = 130, + MX51_PAD_KEY_COL0 = 131, + MX51_PAD_KEY_COL1 = 132, + MX51_PAD_KEY_COL2 = 133, + MX51_PAD_KEY_COL3 = 134, + MX51_PAD_KEY_COL4 = 135, + MX51_PAD_KEY_COL5 = 136, + MX51_PAD_USBH1_CLK = 137, + MX51_PAD_USBH1_DIR = 138, + MX51_PAD_USBH1_STP = 139, + MX51_PAD_USBH1_NXT = 140, + MX51_PAD_USBH1_DATA0 = 141, + MX51_PAD_USBH1_DATA1 = 142, + MX51_PAD_USBH1_DATA2 = 143, + MX51_PAD_USBH1_DATA3 = 144, + MX51_PAD_USBH1_DATA4 = 145, + MX51_PAD_USBH1_DATA5 = 146, + MX51_PAD_USBH1_DATA6 = 147, + MX51_PAD_USBH1_DATA7 = 148, + MX51_PAD_DI1_PIN11 = 149, + MX51_PAD_DI1_PIN12 = 150, + MX51_PAD_DI1_PIN13 = 151, + MX51_PAD_DI1_D0_CS = 152, + MX51_PAD_DI1_D1_CS = 153, + MX51_PAD_DISPB2_SER_DIN = 154, + MX51_PAD_DISPB2_SER_DIO = 155, + MX51_PAD_DISPB2_SER_CLK = 156, + MX51_PAD_DISPB2_SER_RS = 157, + MX51_PAD_DISP1_DAT0 = 158, + MX51_PAD_DISP1_DAT1 = 159, + MX51_PAD_DISP1_DAT2 = 160, + MX51_PAD_DISP1_DAT3 = 161, + MX51_PAD_DISP1_DAT4 = 162, + MX51_PAD_DISP1_DAT5 = 163, + MX51_PAD_DISP1_DAT6 = 164, + MX51_PAD_DISP1_DAT7 = 165, + MX51_PAD_DISP1_DAT8 = 166, + MX51_PAD_DISP1_DAT9 = 167, + MX51_PAD_DISP1_DAT10 = 168, + MX51_PAD_DISP1_DAT11 = 169, + MX51_PAD_DISP1_DAT12 = 170, + MX51_PAD_DISP1_DAT13 = 171, + MX51_PAD_DISP1_DAT14 = 172, + MX51_PAD_DISP1_DAT15 = 173, + MX51_PAD_DISP1_DAT16 = 174, + MX51_PAD_DISP1_DAT17 = 175, + MX51_PAD_DISP1_DAT18 = 176, + MX51_PAD_DISP1_DAT19 = 177, + MX51_PAD_DISP1_DAT20 = 178, + MX51_PAD_DISP1_DAT21 = 179, + MX51_PAD_DISP1_DAT22 = 180, + MX51_PAD_DISP1_DAT23 = 181, + MX51_PAD_DI1_PIN3 = 182, + MX51_PAD_DI1_PIN2 = 183, + MX51_PAD_DI_GP2 = 184, + MX51_PAD_DI_GP3 = 185, + MX51_PAD_DI2_PIN4 = 186, + MX51_PAD_DI2_PIN2 = 187, + MX51_PAD_DI2_PIN3 = 188, + MX51_PAD_DI2_DISP_CLK = 189, + MX51_PAD_DI_GP4 = 190, + MX51_PAD_DISP2_DAT0 = 191, + MX51_PAD_DISP2_DAT1 = 192, + MX51_PAD_DISP2_DAT2 = 193, + MX51_PAD_DISP2_DAT3 = 194, + MX51_PAD_DISP2_DAT4 = 195, + MX51_PAD_DISP2_DAT5 = 196, + MX51_PAD_DISP2_DAT6 = 197, + MX51_PAD_DISP2_DAT7 = 198, + MX51_PAD_DISP2_DAT8 = 199, + MX51_PAD_DISP2_DAT9 = 200, + MX51_PAD_DISP2_DAT10 = 201, + MX51_PAD_DISP2_DAT11 = 202, + MX51_PAD_DISP2_DAT12 = 203, + MX51_PAD_DISP2_DAT13 = 204, + MX51_PAD_DISP2_DAT14 = 205, + MX51_PAD_DISP2_DAT15 = 206, + MX51_PAD_SD1_CMD = 207, + MX51_PAD_SD1_CLK = 208, + MX51_PAD_SD1_DATA0 = 209, + MX51_PAD_EIM_DA0 = 210, + MX51_PAD_EIM_DA1 = 211, + MX51_PAD_EIM_DA2 = 212, + MX51_PAD_EIM_DA3 = 213, + MX51_PAD_SD1_DATA1 = 214, + MX51_PAD_EIM_DA4 = 215, + MX51_PAD_EIM_DA5 = 216, + MX51_PAD_EIM_DA6 = 217, + MX51_PAD_EIM_DA7 = 218, + MX51_PAD_SD1_DATA2 = 219, + MX51_PAD_EIM_DA10 = 220, + MX51_PAD_EIM_DA11 = 221, + MX51_PAD_EIM_DA8 = 222, + MX51_PAD_EIM_DA9 = 223, + MX51_PAD_SD1_DATA3 = 224, + MX51_PAD_GPIO1_0 = 225, + MX51_PAD_GPIO1_1 = 226, + MX51_PAD_EIM_DA12 = 227, + MX51_PAD_EIM_DA13 = 228, + MX51_PAD_EIM_DA14 = 229, + MX51_PAD_EIM_DA15 = 230, + MX51_PAD_SD2_CMD = 231, + MX51_PAD_SD2_CLK = 232, + MX51_PAD_SD2_DATA0 = 233, + MX51_PAD_SD2_DATA1 = 234, + MX51_PAD_SD2_DATA2 = 235, + MX51_PAD_SD2_DATA3 = 236, + MX51_PAD_GPIO1_2 = 237, + MX51_PAD_GPIO1_3 = 238, + MX51_PAD_PMIC_INT_REQ = 239, + MX51_PAD_GPIO1_4 = 240, + MX51_PAD_GPIO1_5 = 241, + MX51_PAD_GPIO1_6 = 242, + MX51_PAD_GPIO1_7 = 243, + MX51_PAD_GPIO1_8 = 244, + MX51_PAD_GPIO1_9 = 245, +}; + +/* imx51 register maps */ +static struct imx_pin_reg imx51_pin_regs[] = { + IMX_PIN_REG(MX51_PAD_EIM_D16, 0x3f0, 0x05c, 5, 0x000, 0), /* MX51_PAD_EIM_D16__AUD4_RXFS */ + IMX_PIN_REG(MX51_PAD_EIM_D16, 0x3f0, 0x05c, 7, 0x8d8, 0), /* MX51_PAD_EIM_D16__AUD5_TXD */ + IMX_PIN_REG(MX51_PAD_EIM_D16, 0x3f0, 0x05c, 0, 0x000, 0), /* MX51_PAD_EIM_D16__EIM_D16 */ + IMX_PIN_REG(MX51_PAD_EIM_D16, 0x3f0, 0x05c, 1, 0x000, 0), /* MX51_PAD_EIM_D16__GPIO2_0 */ + IMX_PIN_REG(MX51_PAD_EIM_D16, 0x3f0, 0x05c, 4, 0x9b4, 0), /* MX51_PAD_EIM_D16__I2C1_SDA */ + IMX_PIN_REG(MX51_PAD_EIM_D16, 0x3f0, 0x05c, 3, 0x000, 0), /* MX51_PAD_EIM_D16__UART2_CTS */ + IMX_PIN_REG(MX51_PAD_EIM_D16, 0x3f0, 0x05c, 2, 0x000, 0), /* MX51_PAD_EIM_D16__USBH2_DATA0 */ + IMX_PIN_REG(MX51_PAD_EIM_D17, 0x3f4, 0x060, 7, 0x8d4, 0), /* MX51_PAD_EIM_D17__AUD5_RXD */ + IMX_PIN_REG(MX51_PAD_EIM_D17, 0x3f4, 0x060, 0, 0x000, 0), /* MX51_PAD_EIM_D17__EIM_D17 */ + IMX_PIN_REG(MX51_PAD_EIM_D17, 0x3f4, 0x060, 1, 0x000, 0), /* MX51_PAD_EIM_D17__GPIO2_1 */ + IMX_PIN_REG(MX51_PAD_EIM_D17, 0x3f4, 0x060, 3, 0x9ec, 0), /* MX51_PAD_EIM_D17__UART2_RXD */ + IMX_PIN_REG(MX51_PAD_EIM_D17, 0x3f4, 0x060, 4, 0x000, 0), /* MX51_PAD_EIM_D17__UART3_CTS */ + IMX_PIN_REG(MX51_PAD_EIM_D17, 0x3f4, 0x060, 2, 0x000, 0), /* MX51_PAD_EIM_D17__USBH2_DATA1 */ + IMX_PIN_REG(MX51_PAD_EIM_D18, 0x3f8, 0x064, 7, 0x8e4, 0), /* MX51_PAD_EIM_D18__AUD5_TXC */ + IMX_PIN_REG(MX51_PAD_EIM_D18, 0x3f8, 0x064, 0, 0x000, 0), /* MX51_PAD_EIM_D18__EIM_D18 */ + IMX_PIN_REG(MX51_PAD_EIM_D18, 0x3f8, 0x064, 1, 0x000, 0), /* MX51_PAD_EIM_D18__GPIO2_2 */ + IMX_PIN_REG(MX51_PAD_EIM_D18, 0x3f8, 0x064, 3, 0x000, 0), /* MX51_PAD_EIM_D18__UART2_TXD */ + IMX_PIN_REG(MX51_PAD_EIM_D18, 0x3f8, 0x064, 4, 0x9f0, 1), /* MX51_PAD_EIM_D18__UART3_RTS */ + IMX_PIN_REG(MX51_PAD_EIM_D18, 0x3f8, 0x064, 2, 0x000, 0), /* MX51_PAD_EIM_D18__USBH2_DATA2 */ + IMX_PIN_REG(MX51_PAD_EIM_D19, 0x3fc, 0x068, 5, 0x000, 0), /* MX51_PAD_EIM_D19__AUD4_RXC */ + IMX_PIN_REG(MX51_PAD_EIM_D19, 0x3fc, 0x068, 7, 0x8e8, 0), /* MX51_PAD_EIM_D19__AUD5_TXFS */ + IMX_PIN_REG(MX51_PAD_EIM_D19, 0x3fc, 0x068, 0, 0x000, 0), /* MX51_PAD_EIM_D19__EIM_D19 */ + IMX_PIN_REG(MX51_PAD_EIM_D19, 0x3fc, 0x068, 1, 0x000, 0), /* MX51_PAD_EIM_D19__GPIO2_3 */ + IMX_PIN_REG(MX51_PAD_EIM_D19, 0x3fc, 0x068, 4, 0x9b0, 0), /* MX51_PAD_EIM_D19__I2C1_SCL */ + IMX_PIN_REG(MX51_PAD_EIM_D19, 0x3fc, 0x068, 3, 0x9e8, 1), /* MX51_PAD_EIM_D19__UART2_RTS */ + IMX_PIN_REG(MX51_PAD_EIM_D19, 0x3fc, 0x068, 2, 0x000, 0), /* MX51_PAD_EIM_D19__USBH2_DATA3 */ + IMX_PIN_REG(MX51_PAD_EIM_D20, 0x400, 0x06c, 5, 0x8c8, 0), /* MX51_PAD_EIM_D20__AUD4_TXD */ + IMX_PIN_REG(MX51_PAD_EIM_D20, 0x400, 0x06c, 0, 0x000, 0), /* MX51_PAD_EIM_D20__EIM_D20 */ + IMX_PIN_REG(MX51_PAD_EIM_D20, 0x400, 0x06c, 1, 0x000, 0), /* MX51_PAD_EIM_D20__GPIO2_4 */ + IMX_PIN_REG(MX51_PAD_EIM_D20, 0x400, 0x06c, 4, 0x000, 0), /* MX51_PAD_EIM_D20__SRTC_ALARM_DEB */ + IMX_PIN_REG(MX51_PAD_EIM_D20, 0x400, 0x06c, 2, 0x000, 0), /* MX51_PAD_EIM_D20__USBH2_DATA4 */ + IMX_PIN_REG(MX51_PAD_EIM_D21, 0x404, 0x070, 5, 0x8c4, 0), /* MX51_PAD_EIM_D21__AUD4_RXD */ + IMX_PIN_REG(MX51_PAD_EIM_D21, 0x404, 0x070, 0, 0x000, 0), /* MX51_PAD_EIM_D21__EIM_D21 */ + IMX_PIN_REG(MX51_PAD_EIM_D21, 0x404, 0x070, 1, 0x000, 0), /* MX51_PAD_EIM_D21__GPIO2_5 */ + IMX_PIN_REG(MX51_PAD_EIM_D21, 0x404, 0x070, 3, 0x000, 0), /* MX51_PAD_EIM_D21__SRTC_ALARM_DEB */ + IMX_PIN_REG(MX51_PAD_EIM_D21, 0x404, 0x070, 2, 0x000, 0), /* MX51_PAD_EIM_D21__USBH2_DATA5 */ + IMX_PIN_REG(MX51_PAD_EIM_D22, 0x408, 0x074, 5, 0x8cc, 0), /* MX51_PAD_EIM_D22__AUD4_TXC */ + IMX_PIN_REG(MX51_PAD_EIM_D22, 0x408, 0x074, 0, 0x000, 0), /* MX51_PAD_EIM_D22__EIM_D22 */ + IMX_PIN_REG(MX51_PAD_EIM_D22, 0x408, 0x074, 1, 0x000, 0), /* MX51_PAD_EIM_D22__GPIO2_6 */ + IMX_PIN_REG(MX51_PAD_EIM_D22, 0x408, 0x074, 2, 0x000, 0), /* MX51_PAD_EIM_D22__USBH2_DATA6 */ + IMX_PIN_REG(MX51_PAD_EIM_D23, 0x40c, 0x078, 5, 0x8d0, 0), /* MX51_PAD_EIM_D23__AUD4_TXFS */ + IMX_PIN_REG(MX51_PAD_EIM_D23, 0x40c, 0x078, 0, 0x000, 0), /* MX51_PAD_EIM_D23__EIM_D23 */ + IMX_PIN_REG(MX51_PAD_EIM_D23, 0x40c, 0x078, 1, 0x000, 0), /* MX51_PAD_EIM_D23__GPIO2_7 */ + IMX_PIN_REG(MX51_PAD_EIM_D23, 0x40c, 0x078, 4, 0x000, 0), /* MX51_PAD_EIM_D23__SPDIF_OUT1 */ + IMX_PIN_REG(MX51_PAD_EIM_D23, 0x40c, 0x078, 2, 0x000, 0), /* MX51_PAD_EIM_D23__USBH2_DATA7 */ + IMX_PIN_REG(MX51_PAD_EIM_D24, 0x410, 0x07c, 5, 0x8f8, 0), /* MX51_PAD_EIM_D24__AUD6_RXFS */ + IMX_PIN_REG(MX51_PAD_EIM_D24, 0x410, 0x07c, 0, 0x000, 0), /* MX51_PAD_EIM_D24__EIM_D24 */ + IMX_PIN_REG(MX51_PAD_EIM_D24, 0x410, 0x07c, 1, 0x000, 0), /* MX51_PAD_EIM_D24__GPIO2_8 */ + IMX_PIN_REG(MX51_PAD_EIM_D24, 0x410, 0x07c, 4, 0x9bc, 0), /* MX51_PAD_EIM_D24__I2C2_SDA */ + IMX_PIN_REG(MX51_PAD_EIM_D24, 0x410, 0x07c, 3, 0x000, 0), /* MX51_PAD_EIM_D24__UART3_CTS */ + IMX_PIN_REG(MX51_PAD_EIM_D24, 0x410, 0x07c, 2, 0x000, 0), /* MX51_PAD_EIM_D24__USBOTG_DATA0 */ + IMX_PIN_REG(MX51_PAD_EIM_D25, 0x414, 0x080, 0, 0x000, 0), /* MX51_PAD_EIM_D25__EIM_D25 */ + IMX_PIN_REG(MX51_PAD_EIM_D25, 0x414, 0x080, 1, 0x9c8, 0), /* MX51_PAD_EIM_D25__KEY_COL6 */ + IMX_PIN_REG(MX51_PAD_EIM_D25, 0x414, 0x080, 4, 0x000, 0), /* MX51_PAD_EIM_D25__UART2_CTS */ + IMX_PIN_REG(MX51_PAD_EIM_D25, 0x414, 0x080, 3, 0x9f4, 0), /* MX51_PAD_EIM_D25__UART3_RXD */ + IMX_PIN_REG(MX51_PAD_EIM_D25, 0x414, 0x080, 2, 0x000, 0), /* MX51_PAD_EIM_D25__USBOTG_DATA1 */ + IMX_PIN_REG(MX51_PAD_EIM_D26, 0x418, 0x084, 0, 0x000, 0), /* MX51_PAD_EIM_D26__EIM_D26 */ + IMX_PIN_REG(MX51_PAD_EIM_D26, 0x418, 0x084, 1, 0x9cc, 0), /* MX51_PAD_EIM_D26__KEY_COL7 */ + IMX_PIN_REG(MX51_PAD_EIM_D26, 0x418, 0x084, 4, 0x9e8, 3), /* MX51_PAD_EIM_D26__UART2_RTS */ + IMX_PIN_REG(MX51_PAD_EIM_D26, 0x418, 0x084, 3, 0x000, 0), /* MX51_PAD_EIM_D26__UART3_TXD */ + IMX_PIN_REG(MX51_PAD_EIM_D26, 0x418, 0x084, 2, 0x000, 0), /* MX51_PAD_EIM_D26__USBOTG_DATA2 */ + IMX_PIN_REG(MX51_PAD_EIM_D27, 0x41c, 0x088, 5, 0x8f4, 0), /* MX51_PAD_EIM_D27__AUD6_RXC */ + IMX_PIN_REG(MX51_PAD_EIM_D27, 0x41c, 0x088, 0, 0x000, 0), /* MX51_PAD_EIM_D27__EIM_D27 */ + IMX_PIN_REG(MX51_PAD_EIM_D27, 0x41c, 0x088, 1, 0x000, 0), /* MX51_PAD_EIM_D27__GPIO2_9 */ + IMX_PIN_REG(MX51_PAD_EIM_D27, 0x41c, 0x088, 4, 0x9b8, 0), /* MX51_PAD_EIM_D27__I2C2_SCL */ + IMX_PIN_REG(MX51_PAD_EIM_D27, 0x41c, 0x088, 3, 0x9f0, 3), /* MX51_PAD_EIM_D27__UART3_RTS */ + IMX_PIN_REG(MX51_PAD_EIM_D27, 0x41c, 0x088, 2, 0x000, 0), /* MX51_PAD_EIM_D27__USBOTG_DATA3 */ + IMX_PIN_REG(MX51_PAD_EIM_D28, 0x420, 0x08c, 5, 0x8f0, 0), /* MX51_PAD_EIM_D28__AUD6_TXD */ + IMX_PIN_REG(MX51_PAD_EIM_D28, 0x420, 0x08c, 0, 0x000, 0), /* MX51_PAD_EIM_D28__EIM_D28 */ + IMX_PIN_REG(MX51_PAD_EIM_D28, 0x420, 0x08c, 1, 0x9d0, 0), /* MX51_PAD_EIM_D28__KEY_ROW4 */ + IMX_PIN_REG(MX51_PAD_EIM_D28, 0x420, 0x08c, 2, 0x000, 0), /* MX51_PAD_EIM_D28__USBOTG_DATA4 */ + IMX_PIN_REG(MX51_PAD_EIM_D29, 0x424, 0x090, 5, 0x8ec, 0), /* MX51_PAD_EIM_D29__AUD6_RXD */ + IMX_PIN_REG(MX51_PAD_EIM_D29, 0x424, 0x090, 0, 0x000, 0), /* MX51_PAD_EIM_D29__EIM_D29 */ + IMX_PIN_REG(MX51_PAD_EIM_D29, 0x424, 0x090, 1, 0x9d4, 0), /* MX51_PAD_EIM_D29__KEY_ROW5 */ + IMX_PIN_REG(MX51_PAD_EIM_D29, 0x424, 0x090, 2, 0x000, 0), /* MX51_PAD_EIM_D29__USBOTG_DATA5 */ + IMX_PIN_REG(MX51_PAD_EIM_D30, 0x428, 0x094, 5, 0x8fc, 0), /* MX51_PAD_EIM_D30__AUD6_TXC */ + IMX_PIN_REG(MX51_PAD_EIM_D30, 0x428, 0x094, 0, 0x000, 0), /* MX51_PAD_EIM_D30__EIM_D30 */ + IMX_PIN_REG(MX51_PAD_EIM_D30, 0x428, 0x094, 1, 0x9d8, 0), /* MX51_PAD_EIM_D30__KEY_ROW6 */ + IMX_PIN_REG(MX51_PAD_EIM_D30, 0x428, 0x094, 2, 0x000, 0), /* MX51_PAD_EIM_D30__USBOTG_DATA6 */ + IMX_PIN_REG(MX51_PAD_EIM_D31, 0x42c, 0x098, 5, 0x900, 0), /* MX51_PAD_EIM_D31__AUD6_TXFS */ + IMX_PIN_REG(MX51_PAD_EIM_D31, 0x42c, 0x098, 0, 0x000, 0), /* MX51_PAD_EIM_D31__EIM_D31 */ + IMX_PIN_REG(MX51_PAD_EIM_D31, 0x42c, 0x098, 1, 0x9dc, 0), /* MX51_PAD_EIM_D31__KEY_ROW7 */ + IMX_PIN_REG(MX51_PAD_EIM_D31, 0x42c, 0x098, 2, 0x000, 0), /* MX51_PAD_EIM_D31__USBOTG_DATA7 */ + IMX_PIN_REG(MX51_PAD_EIM_A16, 0x430, 0x09c, 0, 0x000, 0), /* MX51_PAD_EIM_A16__EIM_A16 */ + IMX_PIN_REG(MX51_PAD_EIM_A16, 0x430, 0x09c, 1, 0x000, 0), /* MX51_PAD_EIM_A16__GPIO2_10 */ + IMX_PIN_REG(MX51_PAD_EIM_A16, 0x430, 0x09c, 7, 0x000, 0), /* MX51_PAD_EIM_A16__OSC_FREQ_SEL0 */ + IMX_PIN_REG(MX51_PAD_EIM_A17, 0x434, 0x0a0, 0, 0x000, 0), /* MX51_PAD_EIM_A17__EIM_A17 */ + IMX_PIN_REG(MX51_PAD_EIM_A17, 0x434, 0x0a0, 1, 0x000, 0), /* MX51_PAD_EIM_A17__GPIO2_11 */ + IMX_PIN_REG(MX51_PAD_EIM_A17, 0x434, 0x0a0, 7, 0x000, 0), /* MX51_PAD_EIM_A17__OSC_FREQ_SEL1 */ + IMX_PIN_REG(MX51_PAD_EIM_A18, 0x438, 0x0a4, 7, 0x000, 0), /* MX51_PAD_EIM_A18__BOOT_LPB0 */ + IMX_PIN_REG(MX51_PAD_EIM_A18, 0x438, 0x0a4, 0, 0x000, 0), /* MX51_PAD_EIM_A18__EIM_A18 */ + IMX_PIN_REG(MX51_PAD_EIM_A18, 0x438, 0x0a4, 1, 0x000, 0), /* MX51_PAD_EIM_A18__GPIO2_12 */ + IMX_PIN_REG(MX51_PAD_EIM_A19, 0x43c, 0x0a8, 7, 0x000, 0), /* MX51_PAD_EIM_A19__BOOT_LPB1 */ + IMX_PIN_REG(MX51_PAD_EIM_A19, 0x43c, 0x0a8, 0, 0x000, 0), /* MX51_PAD_EIM_A19__EIM_A19 */ + IMX_PIN_REG(MX51_PAD_EIM_A19, 0x43c, 0x0a8, 1, 0x000, 0), /* MX51_PAD_EIM_A19__GPIO2_13 */ + IMX_PIN_REG(MX51_PAD_EIM_A20, 0x440, 0x0ac, 7, 0x000, 0), /* MX51_PAD_EIM_A20__BOOT_UART_SRC0 */ + IMX_PIN_REG(MX51_PAD_EIM_A20, 0x440, 0x0ac, 0, 0x000, 0), /* MX51_PAD_EIM_A20__EIM_A20 */ + IMX_PIN_REG(MX51_PAD_EIM_A20, 0x440, 0x0ac, 1, 0x000, 0), /* MX51_PAD_EIM_A20__GPIO2_14 */ + IMX_PIN_REG(MX51_PAD_EIM_A21, 0x444, 0x0b0, 7, 0x000, 0), /* MX51_PAD_EIM_A21__BOOT_UART_SRC1 */ + IMX_PIN_REG(MX51_PAD_EIM_A21, 0x444, 0x0b0, 0, 0x000, 0), /* MX51_PAD_EIM_A21__EIM_A21 */ + IMX_PIN_REG(MX51_PAD_EIM_A21, 0x444, 0x0b0, 1, 0x000, 0), /* MX51_PAD_EIM_A21__GPIO2_15 */ + IMX_PIN_REG(MX51_PAD_EIM_A22, 0x448, 0x0b4, 0, 0x000, 0), /* MX51_PAD_EIM_A22__EIM_A22 */ + IMX_PIN_REG(MX51_PAD_EIM_A22, 0x448, 0x0b4, 1, 0x000, 0), /* MX51_PAD_EIM_A22__GPIO2_16 */ + IMX_PIN_REG(MX51_PAD_EIM_A23, 0x44c, 0x0b8, 7, 0x000, 0), /* MX51_PAD_EIM_A23__BOOT_HPN_EN */ + IMX_PIN_REG(MX51_PAD_EIM_A23, 0x44c, 0x0b8, 0, 0x000, 0), /* MX51_PAD_EIM_A23__EIM_A23 */ + IMX_PIN_REG(MX51_PAD_EIM_A23, 0x44c, 0x0b8, 1, 0x000, 0), /* MX51_PAD_EIM_A23__GPIO2_17 */ + IMX_PIN_REG(MX51_PAD_EIM_A24, 0x450, 0x0bc, 0, 0x000, 0), /* MX51_PAD_EIM_A24__EIM_A24 */ + IMX_PIN_REG(MX51_PAD_EIM_A24, 0x450, 0x0bc, 1, 0x000, 0), /* MX51_PAD_EIM_A24__GPIO2_18 */ + IMX_PIN_REG(MX51_PAD_EIM_A24, 0x450, 0x0bc, 2, 0x000, 0), /* MX51_PAD_EIM_A24__USBH2_CLK */ + IMX_PIN_REG(MX51_PAD_EIM_A25, 0x454, 0x0c0, 6, 0x000, 0), /* MX51_PAD_EIM_A25__DISP1_PIN4 */ + IMX_PIN_REG(MX51_PAD_EIM_A25, 0x454, 0x0c0, 0, 0x000, 0), /* MX51_PAD_EIM_A25__EIM_A25 */ + IMX_PIN_REG(MX51_PAD_EIM_A25, 0x454, 0x0c0, 1, 0x000, 0), /* MX51_PAD_EIM_A25__GPIO2_19 */ + IMX_PIN_REG(MX51_PAD_EIM_A25, 0x454, 0x0c0, 2, 0x000, 0), /* MX51_PAD_EIM_A25__USBH2_DIR */ + IMX_PIN_REG(MX51_PAD_EIM_A26, 0x458, 0x0c4, 5, 0x9a0, 0), /* MX51_PAD_EIM_A26__CSI1_DATA_EN */ + IMX_PIN_REG(MX51_PAD_EIM_A26, 0x458, 0x0c4, 6, 0x908, 0), /* MX51_PAD_EIM_A26__DISP2_EXT_CLK */ + IMX_PIN_REG(MX51_PAD_EIM_A26, 0x458, 0x0c4, 0, 0x000, 0), /* MX51_PAD_EIM_A26__EIM_A26 */ + IMX_PIN_REG(MX51_PAD_EIM_A26, 0x458, 0x0c4, 1, 0x000, 0), /* MX51_PAD_EIM_A26__GPIO2_20 */ + IMX_PIN_REG(MX51_PAD_EIM_A26, 0x458, 0x0c4, 2, 0x000, 0), /* MX51_PAD_EIM_A26__USBH2_STP */ + IMX_PIN_REG(MX51_PAD_EIM_A27, 0x45c, 0x0c8, 5, 0x99c, 0), /* MX51_PAD_EIM_A27__CSI2_DATA_EN */ + IMX_PIN_REG(MX51_PAD_EIM_A27, 0x45c, 0x0c8, 6, 0x9a4, 0), /* MX51_PAD_EIM_A27__DISP1_PIN1 */ + IMX_PIN_REG(MX51_PAD_EIM_A27, 0x45c, 0x0c8, 0, 0x000, 0), /* MX51_PAD_EIM_A27__EIM_A27 */ + IMX_PIN_REG(MX51_PAD_EIM_A27, 0x45c, 0x0c8, 1, 0x000, 0), /* MX51_PAD_EIM_A27__GPIO2_21 */ + IMX_PIN_REG(MX51_PAD_EIM_A27, 0x45c, 0x0c8, 2, 0x000, 0), /* MX51_PAD_EIM_A27__USBH2_NXT */ + IMX_PIN_REG(MX51_PAD_EIM_EB0, 0x460, 0x0cc, 0, 0x000, 0), /* MX51_PAD_EIM_EB0__EIM_EB0 */ + IMX_PIN_REG(MX51_PAD_EIM_EB1, 0x464, 0x0d0, 0, 0x000, 0), /* MX51_PAD_EIM_EB1__EIM_EB1 */ + IMX_PIN_REG(MX51_PAD_EIM_EB2, 0x468, 0x0d4, 6, 0x8e0, 0), /* MX51_PAD_EIM_EB2__AUD5_RXFS */ + IMX_PIN_REG(MX51_PAD_EIM_EB2, 0x468, 0x0d4, 5, 0x000, 0), /* MX51_PAD_EIM_EB2__CSI1_D2 */ + IMX_PIN_REG(MX51_PAD_EIM_EB2, 0x468, 0x0d4, 0, 0x000, 0), /* MX51_PAD_EIM_EB2__EIM_EB2 */ + IMX_PIN_REG(MX51_PAD_EIM_EB2, 0x468, 0x0d4, 3, 0x954, 0), /* MX51_PAD_EIM_EB2__FEC_MDIO */ + IMX_PIN_REG(MX51_PAD_EIM_EB2, 0x468, 0x0d4, 1, 0x000, 0), /* MX51_PAD_EIM_EB2__GPIO2_22 */ + IMX_PIN_REG(MX51_PAD_EIM_EB2, 0x468, 0x0d4, 7, 0x000, 0), /* MX51_PAD_EIM_EB2__GPT_CMPOUT1 */ + IMX_PIN_REG(MX51_PAD_EIM_EB3, 0x46c, 0x0d8, 6, 0x8dc, 0), /* MX51_PAD_EIM_EB3__AUD5_RXC */ + IMX_PIN_REG(MX51_PAD_EIM_EB3, 0x46c, 0x0d8, 5, 0x000, 0), /* MX51_PAD_EIM_EB3__CSI1_D3 */ + IMX_PIN_REG(MX51_PAD_EIM_EB3, 0x46c, 0x0d8, 0, 0x000, 0), /* MX51_PAD_EIM_EB3__EIM_EB3 */ + IMX_PIN_REG(MX51_PAD_EIM_EB3, 0x46c, 0x0d8, 3, 0x95c, 0), /* MX51_PAD_EIM_EB3__FEC_RDATA1 */ + IMX_PIN_REG(MX51_PAD_EIM_EB3, 0x46c, 0x0d8, 1, 0x000, 0), /* MX51_PAD_EIM_EB3__GPIO2_23 */ + IMX_PIN_REG(MX51_PAD_EIM_EB3, 0x46c, 0x0d8, 7, 0x000, 0), /* MX51_PAD_EIM_EB3__GPT_CMPOUT2 */ + IMX_PIN_REG(MX51_PAD_EIM_OE, 0x470, 0x0dc, 0, 0x000, 0), /* MX51_PAD_EIM_OE__EIM_OE */ + IMX_PIN_REG(MX51_PAD_EIM_OE, 0x470, 0x0dc, 1, 0x000, 0), /* MX51_PAD_EIM_OE__GPIO2_24 */ + IMX_PIN_REG(MX51_PAD_EIM_CS0, 0x474, 0x0e0, 0, 0x000, 0), /* MX51_PAD_EIM_CS0__EIM_CS0 */ + IMX_PIN_REG(MX51_PAD_EIM_CS0, 0x474, 0x0e0, 1, 0x000, 0), /* MX51_PAD_EIM_CS0__GPIO2_25 */ + IMX_PIN_REG(MX51_PAD_EIM_CS1, 0x478, 0x0e4, 0, 0x000, 0), /* MX51_PAD_EIM_CS1__EIM_CS1 */ + IMX_PIN_REG(MX51_PAD_EIM_CS1, 0x478, 0x0e4, 1, 0x000, 0), /* MX51_PAD_EIM_CS1__GPIO2_26 */ + IMX_PIN_REG(MX51_PAD_EIM_CS2, 0x47c, 0x0e8, 6, 0x8d8, 1), /* MX51_PAD_EIM_CS2__AUD5_TXD */ + IMX_PIN_REG(MX51_PAD_EIM_CS2, 0x47c, 0x0e8, 5, 0x000, 0), /* MX51_PAD_EIM_CS2__CSI1_D4 */ + IMX_PIN_REG(MX51_PAD_EIM_CS2, 0x47c, 0x0e8, 0, 0x000, 0), /* MX51_PAD_EIM_CS2__EIM_CS2 */ + IMX_PIN_REG(MX51_PAD_EIM_CS2, 0x47c, 0x0e8, 3, 0x960, 0), /* MX51_PAD_EIM_CS2__FEC_RDATA2 */ + IMX_PIN_REG(MX51_PAD_EIM_CS2, 0x47c, 0x0e8, 1, 0x000, 0), /* MX51_PAD_EIM_CS2__GPIO2_27 */ + IMX_PIN_REG(MX51_PAD_EIM_CS2, 0x47c, 0x0e8, 2, 0x000, 0), /* MX51_PAD_EIM_CS2__USBOTG_STP */ + IMX_PIN_REG(MX51_PAD_EIM_CS3, 0x480, 0x0ec, 6, 0x8d4, 1), /* MX51_PAD_EIM_CS3__AUD5_RXD */ + IMX_PIN_REG(MX51_PAD_EIM_CS3, 0x480, 0x0ec, 5, 0x000, 0), /* MX51_PAD_EIM_CS3__CSI1_D5 */ + IMX_PIN_REG(MX51_PAD_EIM_CS3, 0x480, 0x0ec, 0, 0x000, 0), /* MX51_PAD_EIM_CS3__EIM_CS3 */ + IMX_PIN_REG(MX51_PAD_EIM_CS3, 0x480, 0x0ec, 3, 0x964, 0), /* MX51_PAD_EIM_CS3__FEC_RDATA3 */ + IMX_PIN_REG(MX51_PAD_EIM_CS3, 0x480, 0x0ec, 1, 0x000, 0), /* MX51_PAD_EIM_CS3__GPIO2_28 */ + IMX_PIN_REG(MX51_PAD_EIM_CS3, 0x480, 0x0ec, 2, 0x000, 0), /* MX51_PAD_EIM_CS3__USBOTG_NXT */ + IMX_PIN_REG(MX51_PAD_EIM_CS4, 0x484, 0x0f0, 6, 0x8e4, 1), /* MX51_PAD_EIM_CS4__AUD5_TXC */ + IMX_PIN_REG(MX51_PAD_EIM_CS4, 0x484, 0x0f0, 5, 0x000, 0), /* MX51_PAD_EIM_CS4__CSI1_D6 */ + IMX_PIN_REG(MX51_PAD_EIM_CS4, 0x484, 0x0f0, 0, 0x000, 0), /* MX51_PAD_EIM_CS4__EIM_CS4 */ + IMX_PIN_REG(MX51_PAD_EIM_CS4, 0x484, 0x0f0, 3, 0x970, 0), /* MX51_PAD_EIM_CS4__FEC_RX_ER */ + IMX_PIN_REG(MX51_PAD_EIM_CS4, 0x484, 0x0f0, 1, 0x000, 0), /* MX51_PAD_EIM_CS4__GPIO2_29 */ + IMX_PIN_REG(MX51_PAD_EIM_CS4, 0x484, 0x0f0, 2, 0x000, 0), /* MX51_PAD_EIM_CS4__USBOTG_CLK */ + IMX_PIN_REG(MX51_PAD_EIM_CS5, 0x488, 0x0f4, 6, 0x8e8, 1), /* MX51_PAD_EIM_CS5__AUD5_TXFS */ + IMX_PIN_REG(MX51_PAD_EIM_CS5, 0x488, 0x0f4, 5, 0x000, 0), /* MX51_PAD_EIM_CS5__CSI1_D7 */ + IMX_PIN_REG(MX51_PAD_EIM_CS5, 0x488, 0x0f4, 4, 0x904, 0), /* MX51_PAD_EIM_CS5__DISP1_EXT_CLK */ + IMX_PIN_REG(MX51_PAD_EIM_CS5, 0x488, 0x0f4, 0, 0x000, 0), /* MX51_PAD_EIM_CS5__EIM_CS5 */ + IMX_PIN_REG(MX51_PAD_EIM_CS5, 0x488, 0x0f4, 3, 0x950, 0), /* MX51_PAD_EIM_CS5__FEC_CRS */ + IMX_PIN_REG(MX51_PAD_EIM_CS5, 0x488, 0x0f4, 1, 0x000, 0), /* MX51_PAD_EIM_CS5__GPIO2_30 */ + IMX_PIN_REG(MX51_PAD_EIM_CS5, 0x488, 0x0f4, 2, 0x000, 0), /* MX51_PAD_EIM_CS5__USBOTG_DIR */ + IMX_PIN_REG(MX51_PAD_EIM_DTACK, 0x48c, 0x0f8, 0, 0x000, 0), /* MX51_PAD_EIM_DTACK__EIM_DTACK */ + IMX_PIN_REG(MX51_PAD_EIM_DTACK, 0x48c, 0x0f8, 1, 0x000, 0), /* MX51_PAD_EIM_DTACK__GPIO2_31 */ + IMX_PIN_REG(MX51_PAD_EIM_LBA, 0x494, 0x0fc, 0, 0x000, 0), /* MX51_PAD_EIM_LBA__EIM_LBA */ + IMX_PIN_REG(MX51_PAD_EIM_LBA, 0x494, 0x0fc, 1, 0x978, 0), /* MX51_PAD_EIM_LBA__GPIO3_1 */ + IMX_PIN_REG(MX51_PAD_EIM_CRE, 0x4a0, 0x100, 0, 0x000, 0), /* MX51_PAD_EIM_CRE__EIM_CRE */ + IMX_PIN_REG(MX51_PAD_EIM_CRE, 0x4a0, 0x100, 1, 0x97c, 0), /* MX51_PAD_EIM_CRE__GPIO3_2 */ + IMX_PIN_REG(MX51_PAD_DRAM_CS1, 0x4d0, 0x104, 0, 0x000, 0), /* MX51_PAD_DRAM_CS1__DRAM_CS1 */ + IMX_PIN_REG(MX51_PAD_NANDF_WE_B, 0x4e4, 0x108, 3, 0x980, 0), /* MX51_PAD_NANDF_WE_B__GPIO3_3 */ + IMX_PIN_REG(MX51_PAD_NANDF_WE_B, 0x4e4, 0x108, 0, 0x000, 0), /* MX51_PAD_NANDF_WE_B__NANDF_WE_B */ + IMX_PIN_REG(MX51_PAD_NANDF_WE_B, 0x4e4, 0x108, 1, 0x000, 0), /* MX51_PAD_NANDF_WE_B__PATA_DIOW */ + IMX_PIN_REG(MX51_PAD_NANDF_WE_B, 0x4e4, 0x108, 2, 0x93c, 0), /* MX51_PAD_NANDF_WE_B__SD3_DATA0 */ + IMX_PIN_REG(MX51_PAD_NANDF_RE_B, 0x4e8, 0x10c, 3, 0x984, 0), /* MX51_PAD_NANDF_RE_B__GPIO3_4 */ + IMX_PIN_REG(MX51_PAD_NANDF_RE_B, 0x4e8, 0x10c, 0, 0x000, 0), /* MX51_PAD_NANDF_RE_B__NANDF_RE_B */ + IMX_PIN_REG(MX51_PAD_NANDF_RE_B, 0x4e8, 0x10c, 1, 0x000, 0), /* MX51_PAD_NANDF_RE_B__PATA_DIOR */ + IMX_PIN_REG(MX51_PAD_NANDF_RE_B, 0x4e8, 0x10c, 2, 0x940, 0), /* MX51_PAD_NANDF_RE_B__SD3_DATA1 */ + IMX_PIN_REG(MX51_PAD_NANDF_ALE, 0x4ec, 0x110, 3, 0x988, 0), /* MX51_PAD_NANDF_ALE__GPIO3_5 */ + IMX_PIN_REG(MX51_PAD_NANDF_ALE, 0x4ec, 0x110, 0, 0x000, 0), /* MX51_PAD_NANDF_ALE__NANDF_ALE */ + IMX_PIN_REG(MX51_PAD_NANDF_ALE, 0x4ec, 0x110, 1, 0x000, 0), /* MX51_PAD_NANDF_ALE__PATA_BUFFER_EN */ + IMX_PIN_REG(MX51_PAD_NANDF_CLE, 0x4f0, 0x114, 3, 0x98c, 0), /* MX51_PAD_NANDF_CLE__GPIO3_6 */ + IMX_PIN_REG(MX51_PAD_NANDF_CLE, 0x4f0, 0x114, 0, 0x000, 0), /* MX51_PAD_NANDF_CLE__NANDF_CLE */ + IMX_PIN_REG(MX51_PAD_NANDF_CLE, 0x4f0, 0x114, 1, 0x000, 0), /* MX51_PAD_NANDF_CLE__PATA_RESET_B */ + IMX_PIN_REG(MX51_PAD_NANDF_WP_B, 0x4f4, 0x118, 3, 0x990, 0), /* MX51_PAD_NANDF_WP_B__GPIO3_7 */ + IMX_PIN_REG(MX51_PAD_NANDF_WP_B, 0x4f4, 0x118, 0, 0x000, 0), /* MX51_PAD_NANDF_WP_B__NANDF_WP_B */ + IMX_PIN_REG(MX51_PAD_NANDF_WP_B, 0x4f4, 0x118, 1, 0x000, 0), /* MX51_PAD_NANDF_WP_B__PATA_DMACK */ + IMX_PIN_REG(MX51_PAD_NANDF_WP_B, 0x4f4, 0x118, 2, 0x944, 0), /* MX51_PAD_NANDF_WP_B__SD3_DATA2 */ + IMX_PIN_REG(MX51_PAD_NANDF_RB0, 0x4f8, 0x11c, 5, 0x930, 0), /* MX51_PAD_NANDF_RB0__ECSPI2_SS1 */ + IMX_PIN_REG(MX51_PAD_NANDF_RB0, 0x4f8, 0x11c, 3, 0x994, 0), /* MX51_PAD_NANDF_RB0__GPIO3_8 */ + IMX_PIN_REG(MX51_PAD_NANDF_RB0, 0x4f8, 0x11c, 0, 0x000, 0), /* MX51_PAD_NANDF_RB0__NANDF_RB0 */ + IMX_PIN_REG(MX51_PAD_NANDF_RB0, 0x4f8, 0x11c, 1, 0x000, 0), /* MX51_PAD_NANDF_RB0__PATA_DMARQ */ + IMX_PIN_REG(MX51_PAD_NANDF_RB0, 0x4f8, 0x11c, 2, 0x948, 0), /* MX51_PAD_NANDF_RB0__SD3_DATA3 */ + IMX_PIN_REG(MX51_PAD_NANDF_RB1, 0x4fc, 0x120, 6, 0x91c, 0), /* MX51_PAD_NANDF_RB1__CSPI_MOSI */ + IMX_PIN_REG(MX51_PAD_NANDF_RB1, 0x4fc, 0x120, 2, 0x000, 0), /* MX51_PAD_NANDF_RB1__ECSPI2_RDY */ + IMX_PIN_REG(MX51_PAD_NANDF_RB1, 0x4fc, 0x120, 3, 0x000, 0), /* MX51_PAD_NANDF_RB1__GPIO3_9 */ + IMX_PIN_REG(MX51_PAD_NANDF_RB1, 0x4fc, 0x120, 0, 0x000, 0), /* MX51_PAD_NANDF_RB1__NANDF_RB1 */ + IMX_PIN_REG(MX51_PAD_NANDF_RB1, 0x4fc, 0x120, 1, 0x000, 0), /* MX51_PAD_NANDF_RB1__PATA_IORDY */ + IMX_PIN_REG(MX51_PAD_NANDF_RB1, 0x4fc, 0x120, 5, 0x000, 0), /* MX51_PAD_NANDF_RB1__SD4_CMD */ + IMX_PIN_REG(MX51_PAD_NANDF_RB2, 0x500, 0x124, 5, 0x9a8, 0), /* MX51_PAD_NANDF_RB2__DISP2_WAIT */ + IMX_PIN_REG(MX51_PAD_NANDF_RB2, 0x500, 0x124, 2, 0x000, 0), /* MX51_PAD_NANDF_RB2__ECSPI2_SCLK */ + IMX_PIN_REG(MX51_PAD_NANDF_RB2, 0x500, 0x124, 1, 0x94c, 0), /* MX51_PAD_NANDF_RB2__FEC_COL */ + IMX_PIN_REG(MX51_PAD_NANDF_RB2, 0x500, 0x124, 3, 0x000, 0), /* MX51_PAD_NANDF_RB2__GPIO3_10 */ + IMX_PIN_REG(MX51_PAD_NANDF_RB2, 0x500, 0x124, 0, 0x000, 0), /* MX51_PAD_NANDF_RB2__NANDF_RB2 */ + IMX_PIN_REG(MX51_PAD_NANDF_RB2, 0x500, 0x124, 7, 0x000, 0), /* MX51_PAD_NANDF_RB2__USBH3_H3_DP */ + IMX_PIN_REG(MX51_PAD_NANDF_RB2, 0x500, 0x124, 6, 0xa20, 0), /* MX51_PAD_NANDF_RB2__USBH3_NXT */ + IMX_PIN_REG(MX51_PAD_NANDF_RB3, 0x504, 0x128, 5, 0x000, 0), /* MX51_PAD_NANDF_RB3__DISP1_WAIT */ + IMX_PIN_REG(MX51_PAD_NANDF_RB3, 0x504, 0x128, 2, 0x000, 0), /* MX51_PAD_NANDF_RB3__ECSPI2_MISO */ + IMX_PIN_REG(MX51_PAD_NANDF_RB3, 0x504, 0x128, 1, 0x968, 0), /* MX51_PAD_NANDF_RB3__FEC_RX_CLK */ + IMX_PIN_REG(MX51_PAD_NANDF_RB3, 0x504, 0x128, 3, 0x000, 0), /* MX51_PAD_NANDF_RB3__GPIO3_11 */ + IMX_PIN_REG(MX51_PAD_NANDF_RB3, 0x504, 0x128, 0, 0x000, 0), /* MX51_PAD_NANDF_RB3__NANDF_RB3 */ + IMX_PIN_REG(MX51_PAD_NANDF_RB3, 0x504, 0x128, 6, 0x9f8, 0), /* MX51_PAD_NANDF_RB3__USBH3_CLK */ + IMX_PIN_REG(MX51_PAD_NANDF_RB3, 0x504, 0x128, 7, 0x000, 0), /* MX51_PAD_NANDF_RB3__USBH3_H3_DM */ + IMX_PIN_REG(MX51_PAD_GPIO_NAND, 0x514, 0x12c, 0, 0x998, 0), /* MX51_PAD_GPIO_NAND__GPIO_NAND */ + IMX_PIN_REG(MX51_PAD_GPIO_NAND, 0x514, 0x12c, 1, 0x000, 0), /* MX51_PAD_GPIO_NAND__PATA_INTRQ */ + IMX_PIN_REG(MX51_PAD_NANDF_CS0, 0x518, 0x130, 3, 0x000, 0), /* MX51_PAD_NANDF_CS0__GPIO3_16 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS0, 0x518, 0x130, 0, 0x000, 0), /* MX51_PAD_NANDF_CS0__NANDF_CS0 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS1, 0x51c, 0x134, 3, 0x000, 0), /* MX51_PAD_NANDF_CS1__GPIO3_17 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS1, 0x51c, 0x134, 0, 0x000, 0), /* MX51_PAD_NANDF_CS1__NANDF_CS1 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS2, 0x520, 0x138, 6, 0x914, 0), /* MX51_PAD_NANDF_CS2__CSPI_SCLK */ + IMX_PIN_REG(MX51_PAD_NANDF_CS2, 0x520, 0x138, 2, 0x000, 0), /* MX51_PAD_NANDF_CS2__FEC_TX_ER */ + IMX_PIN_REG(MX51_PAD_NANDF_CS2, 0x520, 0x138, 3, 0x000, 0), /* MX51_PAD_NANDF_CS2__GPIO3_18 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS2, 0x520, 0x138, 0, 0x000, 0), /* MX51_PAD_NANDF_CS2__NANDF_CS2 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS2, 0x520, 0x138, 1, 0x000, 0), /* MX51_PAD_NANDF_CS2__PATA_CS_0 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS2, 0x520, 0x138, 5, 0x000, 0), /* MX51_PAD_NANDF_CS2__SD4_CLK */ + IMX_PIN_REG(MX51_PAD_NANDF_CS2, 0x520, 0x138, 7, 0x000, 0), /* MX51_PAD_NANDF_CS2__USBH3_H1_DP */ + IMX_PIN_REG(MX51_PAD_NANDF_CS3, 0x524, 0x13c, 2, 0x000, 0), /* MX51_PAD_NANDF_CS3__FEC_MDC */ + IMX_PIN_REG(MX51_PAD_NANDF_CS3, 0x524, 0x13c, 3, 0x000, 0), /* MX51_PAD_NANDF_CS3__GPIO3_19 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS3, 0x524, 0x13c, 0, 0x000, 0), /* MX51_PAD_NANDF_CS3__NANDF_CS3 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS3, 0x524, 0x13c, 1, 0x000, 0), /* MX51_PAD_NANDF_CS3__PATA_CS_1 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS3, 0x524, 0x13c, 5, 0x000, 0), /* MX51_PAD_NANDF_CS3__SD4_DAT0 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS3, 0x524, 0x13c, 7, 0x000, 0), /* MX51_PAD_NANDF_CS3__USBH3_H1_DM */ + IMX_PIN_REG(MX51_PAD_NANDF_CS4, 0x528, 0x140, 2, 0x000, 0), /* MX51_PAD_NANDF_CS4__FEC_TDATA1 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS4, 0x528, 0x140, 3, 0x000, 0), /* MX51_PAD_NANDF_CS4__GPIO3_20 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS4, 0x528, 0x140, 0, 0x000, 0), /* MX51_PAD_NANDF_CS4__NANDF_CS4 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS4, 0x528, 0x140, 1, 0x000, 0), /* MX51_PAD_NANDF_CS4__PATA_DA_0 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS4, 0x528, 0x140, 5, 0x000, 0), /* MX51_PAD_NANDF_CS4__SD4_DAT1 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS4, 0x528, 0x140, 7, 0xa24, 0), /* MX51_PAD_NANDF_CS4__USBH3_STP */ + IMX_PIN_REG(MX51_PAD_NANDF_CS5, 0x52c, 0x144, 2, 0x000, 0), /* MX51_PAD_NANDF_CS5__FEC_TDATA2 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS5, 0x52c, 0x144, 3, 0x000, 0), /* MX51_PAD_NANDF_CS5__GPIO3_21 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS5, 0x52c, 0x144, 0, 0x000, 0), /* MX51_PAD_NANDF_CS5__NANDF_CS5 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS5, 0x52c, 0x144, 1, 0x000, 0), /* MX51_PAD_NANDF_CS5__PATA_DA_1 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS5, 0x52c, 0x144, 5, 0x000, 0), /* MX51_PAD_NANDF_CS5__SD4_DAT2 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS5, 0x52c, 0x144, 7, 0xa1c, 0), /* MX51_PAD_NANDF_CS5__USBH3_DIR */ + IMX_PIN_REG(MX51_PAD_NANDF_CS6, 0x530, 0x148, 7, 0x928, 0), /* MX51_PAD_NANDF_CS6__CSPI_SS3 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS6, 0x530, 0x148, 2, 0x000, 0), /* MX51_PAD_NANDF_CS6__FEC_TDATA3 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS6, 0x530, 0x148, 3, 0x000, 0), /* MX51_PAD_NANDF_CS6__GPIO3_22 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS6, 0x530, 0x148, 0, 0x000, 0), /* MX51_PAD_NANDF_CS6__NANDF_CS6 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS6, 0x530, 0x148, 1, 0x000, 0), /* MX51_PAD_NANDF_CS6__PATA_DA_2 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS6, 0x530, 0x148, 5, 0x000, 0), /* MX51_PAD_NANDF_CS6__SD4_DAT3 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS7, 0x534, 0x14c, 1, 0x000, 0), /* MX51_PAD_NANDF_CS7__FEC_TX_EN */ + IMX_PIN_REG(MX51_PAD_NANDF_CS7, 0x534, 0x14c, 3, 0x000, 0), /* MX51_PAD_NANDF_CS7__GPIO3_23 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS7, 0x534, 0x14c, 0, 0x000, 0), /* MX51_PAD_NANDF_CS7__NANDF_CS7 */ + IMX_PIN_REG(MX51_PAD_NANDF_CS7, 0x534, 0x14c, 5, 0x000, 0), /* MX51_PAD_NANDF_CS7__SD3_CLK */ + IMX_PIN_REG(MX51_PAD_NANDF_RDY_INT, 0x538, 0x150, 2, 0x000, 0), /* MX51_PAD_NANDF_RDY_INT__ECSPI2_SS0 */ + IMX_PIN_REG(MX51_PAD_NANDF_RDY_INT, 0x538, 0x150, 1, 0x974, 0), /* MX51_PAD_NANDF_RDY_INT__FEC_TX_CLK */ + IMX_PIN_REG(MX51_PAD_NANDF_RDY_INT, 0x538, 0x150, 3, 0x000, 0), /* MX51_PAD_NANDF_RDY_INT__GPIO3_24 */ + IMX_PIN_REG(MX51_PAD_NANDF_RDY_INT, 0x538, 0x150, 0, 0x938, 0), /* MX51_PAD_NANDF_RDY_INT__NANDF_RDY_INT */ + IMX_PIN_REG(MX51_PAD_NANDF_RDY_INT, 0x538, 0x150, 5, 0x000, 0), /* MX51_PAD_NANDF_RDY_INT__SD3_CMD */ + IMX_PIN_REG(MX51_PAD_NANDF_D15, 0x53c, 0x154, 2, 0x000, 0), /* MX51_PAD_NANDF_D15__ECSPI2_MOSI */ + IMX_PIN_REG(MX51_PAD_NANDF_D15, 0x53c, 0x154, 3, 0x000, 0), /* MX51_PAD_NANDF_D15__GPIO3_25 */ + IMX_PIN_REG(MX51_PAD_NANDF_D15, 0x53c, 0x154, 0, 0x000, 0), /* MX51_PAD_NANDF_D15__NANDF_D15 */ + IMX_PIN_REG(MX51_PAD_NANDF_D15, 0x53c, 0x154, 1, 0x000, 0), /* MX51_PAD_NANDF_D15__PATA_DATA15 */ + IMX_PIN_REG(MX51_PAD_NANDF_D15, 0x53c, 0x154, 5, 0x000, 0), /* MX51_PAD_NANDF_D15__SD3_DAT7 */ + IMX_PIN_REG(MX51_PAD_NANDF_D14, 0x540, 0x158, 2, 0x934, 0), /* MX51_PAD_NANDF_D14__ECSPI2_SS3 */ + IMX_PIN_REG(MX51_PAD_NANDF_D14, 0x540, 0x158, 3, 0x000, 0), /* MX51_PAD_NANDF_D14__GPIO3_26 */ + IMX_PIN_REG(MX51_PAD_NANDF_D14, 0x540, 0x158, 0, 0x000, 0), /* MX51_PAD_NANDF_D14__NANDF_D14 */ + IMX_PIN_REG(MX51_PAD_NANDF_D14, 0x540, 0x158, 1, 0x000, 0), /* MX51_PAD_NANDF_D14__PATA_DATA14 */ + IMX_PIN_REG(MX51_PAD_NANDF_D14, 0x540, 0x158, 5, 0x000, 0), /* MX51_PAD_NANDF_D14__SD3_DAT6 */ + IMX_PIN_REG(MX51_PAD_NANDF_D13, 0x544, 0x15c, 2, 0x000, 0), /* MX51_PAD_NANDF_D13__ECSPI2_SS2 */ + IMX_PIN_REG(MX51_PAD_NANDF_D13, 0x544, 0x15c, 3, 0x000, 0), /* MX51_PAD_NANDF_D13__GPIO3_27 */ + IMX_PIN_REG(MX51_PAD_NANDF_D13, 0x544, 0x15c, 0, 0x000, 0), /* MX51_PAD_NANDF_D13__NANDF_D13 */ + IMX_PIN_REG(MX51_PAD_NANDF_D13, 0x544, 0x15c, 1, 0x000, 0), /* MX51_PAD_NANDF_D13__PATA_DATA13 */ + IMX_PIN_REG(MX51_PAD_NANDF_D13, 0x544, 0x15c, 5, 0x000, 0), /* MX51_PAD_NANDF_D13__SD3_DAT5 */ + IMX_PIN_REG(MX51_PAD_NANDF_D12, 0x548, 0x160, 2, 0x930, 1), /* MX51_PAD_NANDF_D12__ECSPI2_SS1 */ + IMX_PIN_REG(MX51_PAD_NANDF_D12, 0x548, 0x160, 3, 0x000, 0), /* MX51_PAD_NANDF_D12__GPIO3_28 */ + IMX_PIN_REG(MX51_PAD_NANDF_D12, 0x548, 0x160, 0, 0x000, 0), /* MX51_PAD_NANDF_D12__NANDF_D12 */ + IMX_PIN_REG(MX51_PAD_NANDF_D12, 0x548, 0x160, 1, 0x000, 0), /* MX51_PAD_NANDF_D12__PATA_DATA12 */ + IMX_PIN_REG(MX51_PAD_NANDF_D12, 0x548, 0x160, 5, 0x000, 0), /* MX51_PAD_NANDF_D12__SD3_DAT4 */ + IMX_PIN_REG(MX51_PAD_NANDF_D11, 0x54c, 0x164, 2, 0x96c, 0), /* MX51_PAD_NANDF_D11__FEC_RX_DV */ + IMX_PIN_REG(MX51_PAD_NANDF_D11, 0x54c, 0x164, 3, 0x000, 0), /* MX51_PAD_NANDF_D11__GPIO3_29 */ + IMX_PIN_REG(MX51_PAD_NANDF_D11, 0x54c, 0x164, 0, 0x000, 0), /* MX51_PAD_NANDF_D11__NANDF_D11 */ + IMX_PIN_REG(MX51_PAD_NANDF_D11, 0x54c, 0x164, 1, 0x000, 0), /* MX51_PAD_NANDF_D11__PATA_DATA11 */ + IMX_PIN_REG(MX51_PAD_NANDF_D11, 0x54c, 0x164, 5, 0x948, 1), /* MX51_PAD_NANDF_D11__SD3_DATA3 */ + IMX_PIN_REG(MX51_PAD_NANDF_D10, 0x550, 0x168, 3, 0x000, 0), /* MX51_PAD_NANDF_D10__GPIO3_30 */ + IMX_PIN_REG(MX51_PAD_NANDF_D10, 0x550, 0x168, 0, 0x000, 0), /* MX51_PAD_NANDF_D10__NANDF_D10 */ + IMX_PIN_REG(MX51_PAD_NANDF_D10, 0x550, 0x168, 1, 0x000, 0), /* MX51_PAD_NANDF_D10__PATA_DATA10 */ + IMX_PIN_REG(MX51_PAD_NANDF_D10, 0x550, 0x168, 5, 0x944, 1), /* MX51_PAD_NANDF_D10__SD3_DATA2 */ + IMX_PIN_REG(MX51_PAD_NANDF_D9, 0x554, 0x16c, 2, 0x958, 0), /* MX51_PAD_NANDF_D9__FEC_RDATA0 */ + IMX_PIN_REG(MX51_PAD_NANDF_D9, 0x554, 0x16c, 3, 0x000, 0), /* MX51_PAD_NANDF_D9__GPIO3_31 */ + IMX_PIN_REG(MX51_PAD_NANDF_D9, 0x554, 0x16c, 0, 0x000, 0), /* MX51_PAD_NANDF_D9__NANDF_D9 */ + IMX_PIN_REG(MX51_PAD_NANDF_D9, 0x554, 0x16c, 1, 0x000, 0), /* MX51_PAD_NANDF_D9__PATA_DATA9 */ + IMX_PIN_REG(MX51_PAD_NANDF_D9, 0x554, 0x16c, 5, 0x940, 1), /* MX51_PAD_NANDF_D9__SD3_DATA1 */ + IMX_PIN_REG(MX51_PAD_NANDF_D8, 0x558, 0x170, 2, 0x000, 0), /* MX51_PAD_NANDF_D8__FEC_TDATA0 */ + IMX_PIN_REG(MX51_PAD_NANDF_D8, 0x558, 0x170, 3, 0x000, 0), /* MX51_PAD_NANDF_D8__GPIO4_0 */ + IMX_PIN_REG(MX51_PAD_NANDF_D8, 0x558, 0x170, 0, 0x000, 0), /* MX51_PAD_NANDF_D8__NANDF_D8 */ + IMX_PIN_REG(MX51_PAD_NANDF_D8, 0x558, 0x170, 1, 0x000, 0), /* MX51_PAD_NANDF_D8__PATA_DATA8 */ + IMX_PIN_REG(MX51_PAD_NANDF_D8, 0x558, 0x170, 5, 0x93c, 1), /* MX51_PAD_NANDF_D8__SD3_DATA0 */ + IMX_PIN_REG(MX51_PAD_NANDF_D7, 0x55c, 0x174, 3, 0x000, 0), /* MX51_PAD_NANDF_D7__GPIO4_1 */ + IMX_PIN_REG(MX51_PAD_NANDF_D7, 0x55c, 0x174, 0, 0x000, 0), /* MX51_PAD_NANDF_D7__NANDF_D7 */ + IMX_PIN_REG(MX51_PAD_NANDF_D7, 0x55c, 0x174, 1, 0x000, 0), /* MX51_PAD_NANDF_D7__PATA_DATA7 */ + IMX_PIN_REG(MX51_PAD_NANDF_D7, 0x55c, 0x174, 5, 0x9fc, 0), /* MX51_PAD_NANDF_D7__USBH3_DATA0 */ + IMX_PIN_REG(MX51_PAD_NANDF_D6, 0x560, 0x178, 3, 0x000, 0), /* MX51_PAD_NANDF_D6__GPIO4_2 */ + IMX_PIN_REG(MX51_PAD_NANDF_D6, 0x560, 0x178, 0, 0x000, 0), /* MX51_PAD_NANDF_D6__NANDF_D6 */ + IMX_PIN_REG(MX51_PAD_NANDF_D6, 0x560, 0x178, 1, 0x000, 0), /* MX51_PAD_NANDF_D6__PATA_DATA6 */ + IMX_PIN_REG(MX51_PAD_NANDF_D6, 0x560, 0x178, 2, 0x000, 0), /* MX51_PAD_NANDF_D6__SD4_LCTL */ + IMX_PIN_REG(MX51_PAD_NANDF_D6, 0x560, 0x178, 5, 0xa00, 0), /* MX51_PAD_NANDF_D6__USBH3_DATA1 */ + IMX_PIN_REG(MX51_PAD_NANDF_D5, 0x564, 0x17c, 3, 0x000, 0), /* MX51_PAD_NANDF_D5__GPIO4_3 */ + IMX_PIN_REG(MX51_PAD_NANDF_D5, 0x564, 0x17c, 0, 0x000, 0), /* MX51_PAD_NANDF_D5__NANDF_D5 */ + IMX_PIN_REG(MX51_PAD_NANDF_D5, 0x564, 0x17c, 1, 0x000, 0), /* MX51_PAD_NANDF_D5__PATA_DATA5 */ + IMX_PIN_REG(MX51_PAD_NANDF_D5, 0x564, 0x17c, 2, 0x000, 0), /* MX51_PAD_NANDF_D5__SD4_WP */ + IMX_PIN_REG(MX51_PAD_NANDF_D5, 0x564, 0x17c, 5, 0xa04, 0), /* MX51_PAD_NANDF_D5__USBH3_DATA2 */ + IMX_PIN_REG(MX51_PAD_NANDF_D4, 0x568, 0x180, 3, 0x000, 0), /* MX51_PAD_NANDF_D4__GPIO4_4 */ + IMX_PIN_REG(MX51_PAD_NANDF_D4, 0x568, 0x180, 0, 0x000, 0), /* MX51_PAD_NANDF_D4__NANDF_D4 */ + IMX_PIN_REG(MX51_PAD_NANDF_D4, 0x568, 0x180, 1, 0x000, 0), /* MX51_PAD_NANDF_D4__PATA_DATA4 */ + IMX_PIN_REG(MX51_PAD_NANDF_D4, 0x568, 0x180, 2, 0x000, 0), /* MX51_PAD_NANDF_D4__SD4_CD */ + IMX_PIN_REG(MX51_PAD_NANDF_D4, 0x568, 0x180, 5, 0xa08, 0), /* MX51_PAD_NANDF_D4__USBH3_DATA3 */ + IMX_PIN_REG(MX51_PAD_NANDF_D3, 0x56c, 0x184, 3, 0x000, 0), /* MX51_PAD_NANDF_D3__GPIO4_5 */ + IMX_PIN_REG(MX51_PAD_NANDF_D3, 0x56c, 0x184, 0, 0x000, 0), /* MX51_PAD_NANDF_D3__NANDF_D3 */ + IMX_PIN_REG(MX51_PAD_NANDF_D3, 0x56c, 0x184, 1, 0x000, 0), /* MX51_PAD_NANDF_D3__PATA_DATA3 */ + IMX_PIN_REG(MX51_PAD_NANDF_D3, 0x56c, 0x184, 2, 0x000, 0), /* MX51_PAD_NANDF_D3__SD4_DAT4 */ + IMX_PIN_REG(MX51_PAD_NANDF_D3, 0x56c, 0x184, 5, 0xa0c, 0), /* MX51_PAD_NANDF_D3__USBH3_DATA4 */ + IMX_PIN_REG(MX51_PAD_NANDF_D2, 0x570, 0x188, 3, 0x000, 0), /* MX51_PAD_NANDF_D2__GPIO4_6 */ + IMX_PIN_REG(MX51_PAD_NANDF_D2, 0x570, 0x188, 0, 0x000, 0), /* MX51_PAD_NANDF_D2__NANDF_D2 */ + IMX_PIN_REG(MX51_PAD_NANDF_D2, 0x570, 0x188, 1, 0x000, 0), /* MX51_PAD_NANDF_D2__PATA_DATA2 */ + IMX_PIN_REG(MX51_PAD_NANDF_D2, 0x570, 0x188, 2, 0x000, 0), /* MX51_PAD_NANDF_D2__SD4_DAT5 */ + IMX_PIN_REG(MX51_PAD_NANDF_D2, 0x570, 0x188, 5, 0xa10, 0), /* MX51_PAD_NANDF_D2__USBH3_DATA5 */ + IMX_PIN_REG(MX51_PAD_NANDF_D1, 0x574, 0x18c, 3, 0x000, 0), /* MX51_PAD_NANDF_D1__GPIO4_7 */ + IMX_PIN_REG(MX51_PAD_NANDF_D1, 0x574, 0x18c, 0, 0x000, 0), /* MX51_PAD_NANDF_D1__NANDF_D1 */ + IMX_PIN_REG(MX51_PAD_NANDF_D1, 0x574, 0x18c, 1, 0x000, 0), /* MX51_PAD_NANDF_D1__PATA_DATA1 */ + IMX_PIN_REG(MX51_PAD_NANDF_D1, 0x574, 0x18c, 2, 0x000, 0), /* MX51_PAD_NANDF_D1__SD4_DAT6 */ + IMX_PIN_REG(MX51_PAD_NANDF_D1, 0x574, 0x18c, 5, 0xa14, 0), /* MX51_PAD_NANDF_D1__USBH3_DATA6 */ + IMX_PIN_REG(MX51_PAD_NANDF_D0, 0x578, 0x190, 3, 0x000, 0), /* MX51_PAD_NANDF_D0__GPIO4_8 */ + IMX_PIN_REG(MX51_PAD_NANDF_D0, 0x578, 0x190, 0, 0x000, 0), /* MX51_PAD_NANDF_D0__NANDF_D0 */ + IMX_PIN_REG(MX51_PAD_NANDF_D0, 0x578, 0x190, 1, 0x000, 0), /* MX51_PAD_NANDF_D0__PATA_DATA0 */ + IMX_PIN_REG(MX51_PAD_NANDF_D0, 0x578, 0x190, 2, 0x000, 0), /* MX51_PAD_NANDF_D0__SD4_DAT7 */ + IMX_PIN_REG(MX51_PAD_NANDF_D0, 0x578, 0x190, 5, 0xa18, 0), /* MX51_PAD_NANDF_D0__USBH3_DATA7 */ + IMX_PIN_REG(MX51_PAD_CSI1_D8, 0x57c, 0x194, 0, 0x000, 0), /* MX51_PAD_CSI1_D8__CSI1_D8 */ + IMX_PIN_REG(MX51_PAD_CSI1_D8, 0x57c, 0x194, 3, 0x998, 1), /* MX51_PAD_CSI1_D8__GPIO3_12 */ + IMX_PIN_REG(MX51_PAD_CSI1_D9, 0x580, 0x198, 0, 0x000, 0), /* MX51_PAD_CSI1_D9__CSI1_D9 */ + IMX_PIN_REG(MX51_PAD_CSI1_D9, 0x580, 0x198, 3, 0x000, 0), /* MX51_PAD_CSI1_D9__GPIO3_13 */ + IMX_PIN_REG(MX51_PAD_CSI1_D10, 0x584, 0x19c, 0, 0x000, 0), /* MX51_PAD_CSI1_D10__CSI1_D10 */ + IMX_PIN_REG(MX51_PAD_CSI1_D11, 0x588, 0x1a0, 0, 0x000, 0), /* MX51_PAD_CSI1_D11__CSI1_D11 */ + IMX_PIN_REG(MX51_PAD_CSI1_D12, 0x58c, 0x1a4, 0, 0x000, 0), /* MX51_PAD_CSI1_D12__CSI1_D12 */ + IMX_PIN_REG(MX51_PAD_CSI1_D13, 0x590, 0x1a8, 0, 0x000, 0), /* MX51_PAD_CSI1_D13__CSI1_D13 */ + IMX_PIN_REG(MX51_PAD_CSI1_D14, 0x594, 0x1ac, 0, 0x000, 0), /* MX51_PAD_CSI1_D14__CSI1_D14 */ + IMX_PIN_REG(MX51_PAD_CSI1_D15, 0x598, 0x1b0, 0, 0x000, 0), /* MX51_PAD_CSI1_D15__CSI1_D15 */ + IMX_PIN_REG(MX51_PAD_CSI1_D16, 0x59c, 0x1b4, 0, 0x000, 0), /* MX51_PAD_CSI1_D16__CSI1_D16 */ + IMX_PIN_REG(MX51_PAD_CSI1_D17, 0x5a0, 0x1b8, 0, 0x000, 0), /* MX51_PAD_CSI1_D17__CSI1_D17 */ + IMX_PIN_REG(MX51_PAD_CSI1_D18, 0x5a4, 0x1bc, 0, 0x000, 0), /* MX51_PAD_CSI1_D18__CSI1_D18 */ + IMX_PIN_REG(MX51_PAD_CSI1_D19, 0x5a8, 0x1c0, 0, 0x000, 0), /* MX51_PAD_CSI1_D19__CSI1_D19 */ + IMX_PIN_REG(MX51_PAD_CSI1_VSYNC, 0x5ac, 0x1c4, 0, 0x000, 0), /* MX51_PAD_CSI1_VSYNC__CSI1_VSYNC */ + IMX_PIN_REG(MX51_PAD_CSI1_VSYNC, 0x5ac, 0x1c4, 3, 0x000, 0), /* MX51_PAD_CSI1_VSYNC__GPIO3_14 */ + IMX_PIN_REG(MX51_PAD_CSI1_HSYNC, 0x5b0, 0x1c8, 0, 0x000, 0), /* MX51_PAD_CSI1_HSYNC__CSI1_HSYNC */ + IMX_PIN_REG(MX51_PAD_CSI1_HSYNC, 0x5b0, 0x1c8, 3, 0x000, 0), /* MX51_PAD_CSI1_HSYNC__GPIO3_15 */ + IMX_PIN_REG(MX51_PAD_CSI1_PIXCLK, 0x5b4, NO_MUX, 0, 0x000, 0), /* MX51_PAD_CSI1_PIXCLK__CSI1_PIXCLK */ + IMX_PIN_REG(MX51_PAD_CSI1_MCLK, 0x5b8, NO_MUX, 0, 0x000, 0), /* MX51_PAD_CSI1_MCLK__CSI1_MCLK */ + IMX_PIN_REG(MX51_PAD_CSI2_D12, 0x5bc, 0x1cc, 0, 0x000, 0), /* MX51_PAD_CSI2_D12__CSI2_D12 */ + IMX_PIN_REG(MX51_PAD_CSI2_D12, 0x5bc, 0x1cc, 3, 0x000, 0), /* MX51_PAD_CSI2_D12__GPIO4_9 */ + IMX_PIN_REG(MX51_PAD_CSI2_D13, 0x5c0, 0x1d0, 0, 0x000, 0), /* MX51_PAD_CSI2_D13__CSI2_D13 */ + IMX_PIN_REG(MX51_PAD_CSI2_D13, 0x5c0, 0x1d0, 3, 0x000, 0), /* MX51_PAD_CSI2_D13__GPIO4_10 */ + IMX_PIN_REG(MX51_PAD_CSI2_D14, 0x5c4, 0x1d4, 0, 0x000, 0), /* MX51_PAD_CSI2_D14__CSI2_D14 */ + IMX_PIN_REG(MX51_PAD_CSI2_D15, 0x5c8, 0x1d8, 0, 0x000, 0), /* MX51_PAD_CSI2_D15__CSI2_D15 */ + IMX_PIN_REG(MX51_PAD_CSI2_D16, 0x5cc, 0x1dc, 0, 0x000, 0), /* MX51_PAD_CSI2_D16__CSI2_D16 */ + IMX_PIN_REG(MX51_PAD_CSI2_D17, 0x5d0, 0x1e0, 0, 0x000, 0), /* MX51_PAD_CSI2_D17__CSI2_D17 */ + IMX_PIN_REG(MX51_PAD_CSI2_D18, 0x5d4, 0x1e4, 0, 0x000, 0), /* MX51_PAD_CSI2_D18__CSI2_D18 */ + IMX_PIN_REG(MX51_PAD_CSI2_D18, 0x5d4, 0x1e4, 3, 0x000, 0), /* MX51_PAD_CSI2_D18__GPIO4_11 */ + IMX_PIN_REG(MX51_PAD_CSI2_D19, 0x5d8, 0x1e8, 0, 0x000, 0), /* MX51_PAD_CSI2_D19__CSI2_D19 */ + IMX_PIN_REG(MX51_PAD_CSI2_D19, 0x5d8, 0x1e8, 3, 0x000, 0), /* MX51_PAD_CSI2_D19__GPIO4_12 */ + IMX_PIN_REG(MX51_PAD_CSI2_VSYNC, 0x5dc, 0x1ec, 0, 0x000, 0), /* MX51_PAD_CSI2_VSYNC__CSI2_VSYNC */ + IMX_PIN_REG(MX51_PAD_CSI2_VSYNC, 0x5dc, 0x1ec, 3, 0x000, 0), /* MX51_PAD_CSI2_VSYNC__GPIO4_13 */ + IMX_PIN_REG(MX51_PAD_CSI2_HSYNC, 0x5e0, 0x1f0, 0, 0x000, 0), /* MX51_PAD_CSI2_HSYNC__CSI2_HSYNC */ + IMX_PIN_REG(MX51_PAD_CSI2_HSYNC, 0x5e0, 0x1f0, 3, 0x000, 0), /* MX51_PAD_CSI2_HSYNC__GPIO4_14 */ + IMX_PIN_REG(MX51_PAD_CSI2_PIXCLK, 0x5e4, 0x1f4, 0, 0x000, 0), /* MX51_PAD_CSI2_PIXCLK__CSI2_PIXCLK */ + IMX_PIN_REG(MX51_PAD_CSI2_PIXCLK, 0x5e4, 0x1f4, 3, 0x000, 0), /* MX51_PAD_CSI2_PIXCLK__GPIO4_15 */ + IMX_PIN_REG(MX51_PAD_I2C1_CLK, 0x5e8, 0x1f8, 3, 0x000, 0), /* MX51_PAD_I2C1_CLK__GPIO4_16 */ + IMX_PIN_REG(MX51_PAD_I2C1_CLK, 0x5e8, 0x1f8, 0, 0x000, 0), /* MX51_PAD_I2C1_CLK__I2C1_CLK */ + IMX_PIN_REG(MX51_PAD_I2C1_DAT, 0x5ec, 0x1fc, 3, 0x000, 0), /* MX51_PAD_I2C1_DAT__GPIO4_17 */ + IMX_PIN_REG(MX51_PAD_I2C1_DAT, 0x5ec, 0x1fc, 0, 0x000, 0), /* MX51_PAD_I2C1_DAT__I2C1_DAT */ + IMX_PIN_REG(MX51_PAD_AUD3_BB_TXD, 0x5f0, 0x200, 0, 0x000, 0), /* MX51_PAD_AUD3_BB_TXD__AUD3_TXD */ + IMX_PIN_REG(MX51_PAD_AUD3_BB_TXD, 0x5f0, 0x200, 3, 0x000, 0), /* MX51_PAD_AUD3_BB_TXD__GPIO4_18 */ + IMX_PIN_REG(MX51_PAD_AUD3_BB_RXD, 0x5f4, 0x204, 0, 0x000, 0), /* MX51_PAD_AUD3_BB_RXD__AUD3_RXD */ + IMX_PIN_REG(MX51_PAD_AUD3_BB_RXD, 0x5f4, 0x204, 3, 0x000, 0), /* MX51_PAD_AUD3_BB_RXD__GPIO4_19 */ + IMX_PIN_REG(MX51_PAD_AUD3_BB_RXD, 0x5f4, 0x204, 1, 0x9f4, 2), /* MX51_PAD_AUD3_BB_RXD__UART3_RXD */ + IMX_PIN_REG(MX51_PAD_AUD3_BB_CK, 0x5f8, 0x208, 0, 0x000, 0), /* MX51_PAD_AUD3_BB_CK__AUD3_TXC */ + IMX_PIN_REG(MX51_PAD_AUD3_BB_CK, 0x5f8, 0x208, 3, 0x000, 0), /* MX51_PAD_AUD3_BB_CK__GPIO4_20 */ + IMX_PIN_REG(MX51_PAD_AUD3_BB_FS, 0x5fc, 0x20c, 0, 0x000, 0), /* MX51_PAD_AUD3_BB_FS__AUD3_TXFS */ + IMX_PIN_REG(MX51_PAD_AUD3_BB_FS, 0x5fc, 0x20c, 3, 0x000, 0), /* MX51_PAD_AUD3_BB_FS__GPIO4_21 */ + IMX_PIN_REG(MX51_PAD_AUD3_BB_FS, 0x5fc, 0x20c, 1, 0x000, 0), /* MX51_PAD_AUD3_BB_FS__UART3_TXD */ + IMX_PIN_REG(MX51_PAD_CSPI1_MOSI, 0x600, 0x210, 0, 0x000, 0), /* MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI */ + IMX_PIN_REG(MX51_PAD_CSPI1_MOSI, 0x600, 0x210, 3, 0x000, 0), /* MX51_PAD_CSPI1_MOSI__GPIO4_22 */ + IMX_PIN_REG(MX51_PAD_CSPI1_MOSI, 0x600, 0x210, 1, 0x9b4, 1), /* MX51_PAD_CSPI1_MOSI__I2C1_SDA */ + IMX_PIN_REG(MX51_PAD_CSPI1_MISO, 0x604, 0x214, 1, 0x8c4, 1), /* MX51_PAD_CSPI1_MISO__AUD4_RXD */ + IMX_PIN_REG(MX51_PAD_CSPI1_MISO, 0x604, 0x214, 0, 0x000, 0), /* MX51_PAD_CSPI1_MISO__ECSPI1_MISO */ + IMX_PIN_REG(MX51_PAD_CSPI1_MISO, 0x604, 0x214, 3, 0x000, 0), /* MX51_PAD_CSPI1_MISO__GPIO4_23 */ + IMX_PIN_REG(MX51_PAD_CSPI1_SS0, 0x608, 0x218, 1, 0x8cc, 1), /* MX51_PAD_CSPI1_SS0__AUD4_TXC */ + IMX_PIN_REG(MX51_PAD_CSPI1_SS0, 0x608, 0x218, 0, 0x000, 0), /* MX51_PAD_CSPI1_SS0__ECSPI1_SS0 */ + IMX_PIN_REG(MX51_PAD_CSPI1_SS0, 0x608, 0x218, 3, 0x000, 0), /* MX51_PAD_CSPI1_SS0__GPIO4_24 */ + IMX_PIN_REG(MX51_PAD_CSPI1_SS1, 0x60c, 0x21c, 1, 0x8c8, 1), /* MX51_PAD_CSPI1_SS1__AUD4_TXD */ + IMX_PIN_REG(MX51_PAD_CSPI1_SS1, 0x60c, 0x21c, 0, 0x000, 0), /* MX51_PAD_CSPI1_SS1__ECSPI1_SS1 */ + IMX_PIN_REG(MX51_PAD_CSPI1_SS1, 0x60c, 0x21c, 3, 0x000, 0), /* MX51_PAD_CSPI1_SS1__GPIO4_25 */ + IMX_PIN_REG(MX51_PAD_CSPI1_RDY, 0x610, 0x220, 1, 0x8d0, 1), /* MX51_PAD_CSPI1_RDY__AUD4_TXFS */ + IMX_PIN_REG(MX51_PAD_CSPI1_RDY, 0x610, 0x220, 0, 0x000, 0), /* MX51_PAD_CSPI1_RDY__ECSPI1_RDY */ + IMX_PIN_REG(MX51_PAD_CSPI1_RDY, 0x610, 0x220, 3, 0x000, 0), /* MX51_PAD_CSPI1_RDY__GPIO4_26 */ + IMX_PIN_REG(MX51_PAD_CSPI1_SCLK, 0x614, 0x224, 0, 0x000, 0), /* MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK */ + IMX_PIN_REG(MX51_PAD_CSPI1_SCLK, 0x614, 0x224, 3, 0x000, 0), /* MX51_PAD_CSPI1_SCLK__GPIO4_27 */ + IMX_PIN_REG(MX51_PAD_CSPI1_SCLK, 0x614, 0x224, 1, 0x9b0, 1), /* MX51_PAD_CSPI1_SCLK__I2C1_SCL */ + IMX_PIN_REG(MX51_PAD_UART1_RXD, 0x618, 0x228, 3, 0x000, 0), /* MX51_PAD_UART1_RXD__GPIO4_28 */ + IMX_PIN_REG(MX51_PAD_UART1_RXD, 0x618, 0x228, 0, 0x9e4, 0), /* MX51_PAD_UART1_RXD__UART1_RXD */ + IMX_PIN_REG(MX51_PAD_UART1_TXD, 0x61c, 0x22c, 3, 0x000, 0), /* MX51_PAD_UART1_TXD__GPIO4_29 */ + IMX_PIN_REG(MX51_PAD_UART1_TXD, 0x61c, 0x22c, 1, 0x000, 0), /* MX51_PAD_UART1_TXD__PWM2_PWMO */ + IMX_PIN_REG(MX51_PAD_UART1_TXD, 0x61c, 0x22c, 0, 0x000, 0), /* MX51_PAD_UART1_TXD__UART1_TXD */ + IMX_PIN_REG(MX51_PAD_UART1_RTS, 0x620, 0x230, 3, 0x000, 0), /* MX51_PAD_UART1_RTS__GPIO4_30 */ + IMX_PIN_REG(MX51_PAD_UART1_RTS, 0x620, 0x230, 0, 0x9e0, 0), /* MX51_PAD_UART1_RTS__UART1_RTS */ + IMX_PIN_REG(MX51_PAD_UART1_CTS, 0x624, 0x234, 3, 0x000, 0), /* MX51_PAD_UART1_CTS__GPIO4_31 */ + IMX_PIN_REG(MX51_PAD_UART1_CTS, 0x624, 0x234, 0, 0x000, 0), /* MX51_PAD_UART1_CTS__UART1_CTS */ + IMX_PIN_REG(MX51_PAD_UART2_RXD, 0x628, 0x238, 1, 0x000, 0), /* MX51_PAD_UART2_RXD__FIRI_TXD */ + IMX_PIN_REG(MX51_PAD_UART2_RXD, 0x628, 0x238, 3, 0x000, 0), /* MX51_PAD_UART2_RXD__GPIO1_20 */ + IMX_PIN_REG(MX51_PAD_UART2_RXD, 0x628, 0x238, 0, 0x9ec, 2), /* MX51_PAD_UART2_RXD__UART2_RXD */ + IMX_PIN_REG(MX51_PAD_UART2_TXD, 0x62c, 0x23c, 1, 0x000, 0), /* MX51_PAD_UART2_TXD__FIRI_RXD */ + IMX_PIN_REG(MX51_PAD_UART2_TXD, 0x62c, 0x23c, 3, 0x000, 0), /* MX51_PAD_UART2_TXD__GPIO1_21 */ + IMX_PIN_REG(MX51_PAD_UART2_TXD, 0x62c, 0x23c, 0, 0x000, 0), /* MX51_PAD_UART2_TXD__UART2_TXD */ + IMX_PIN_REG(MX51_PAD_UART3_RXD, 0x630, 0x240, 2, 0x000, 0), /* MX51_PAD_UART3_RXD__CSI1_D0 */ + IMX_PIN_REG(MX51_PAD_UART3_RXD, 0x630, 0x240, 3, 0x000, 0), /* MX51_PAD_UART3_RXD__GPIO1_22 */ + IMX_PIN_REG(MX51_PAD_UART3_RXD, 0x630, 0x240, 0, 0x000, 0), /* MX51_PAD_UART3_RXD__UART1_DTR */ + IMX_PIN_REG(MX51_PAD_UART3_RXD, 0x630, 0x240, 1, 0x9f4, 4), /* MX51_PAD_UART3_RXD__UART3_RXD */ + IMX_PIN_REG(MX51_PAD_UART3_TXD, 0x634, 0x244, 2, 0x000, 0), /* MX51_PAD_UART3_TXD__CSI1_D1 */ + IMX_PIN_REG(MX51_PAD_UART3_TXD, 0x634, 0x244, 3, 0x000, 0), /* MX51_PAD_UART3_TXD__GPIO1_23 */ + IMX_PIN_REG(MX51_PAD_UART3_TXD, 0x634, 0x244, 0, 0x000, 0), /* MX51_PAD_UART3_TXD__UART1_DSR */ + IMX_PIN_REG(MX51_PAD_UART3_TXD, 0x634, 0x244, 1, 0x000, 0), /* MX51_PAD_UART3_TXD__UART3_TXD */ + IMX_PIN_REG(MX51_PAD_OWIRE_LINE, 0x638, 0x248, 3, 0x000, 0), /* MX51_PAD_OWIRE_LINE__GPIO1_24 */ + IMX_PIN_REG(MX51_PAD_OWIRE_LINE, 0x638, 0x248, 0, 0x000, 0), /* MX51_PAD_OWIRE_LINE__OWIRE_LINE */ + IMX_PIN_REG(MX51_PAD_OWIRE_LINE, 0x638, 0x248, 6, 0x000, 0), /* MX51_PAD_OWIRE_LINE__SPDIF_OUT */ + IMX_PIN_REG(MX51_PAD_KEY_ROW0, 0x63c, 0x24c, 0, 0x000, 0), /* MX51_PAD_KEY_ROW0__KEY_ROW0 */ + IMX_PIN_REG(MX51_PAD_KEY_ROW1, 0x640, 0x250, 0, 0x000, 0), /* MX51_PAD_KEY_ROW1__KEY_ROW1 */ + IMX_PIN_REG(MX51_PAD_KEY_ROW2, 0x644, 0x254, 0, 0x000, 0), /* MX51_PAD_KEY_ROW2__KEY_ROW2 */ + IMX_PIN_REG(MX51_PAD_KEY_ROW3, 0x648, 0x258, 0, 0x000, 0), /* MX51_PAD_KEY_ROW3__KEY_ROW3 */ + IMX_PIN_REG(MX51_PAD_KEY_COL0, 0x64c, 0x25c, 0, 0x000, 0), /* MX51_PAD_KEY_COL0__KEY_COL0 */ + IMX_PIN_REG(MX51_PAD_KEY_COL0, 0x64c, 0x25c, 7, 0x90c, 0), /* MX51_PAD_KEY_COL0__PLL1_BYP */ + IMX_PIN_REG(MX51_PAD_KEY_COL1, 0x650, 0x260, 0, 0x000, 0), /* MX51_PAD_KEY_COL1__KEY_COL1 */ + IMX_PIN_REG(MX51_PAD_KEY_COL1, 0x650, 0x260, 7, 0x910, 0), /* MX51_PAD_KEY_COL1__PLL2_BYP */ + IMX_PIN_REG(MX51_PAD_KEY_COL2, 0x654, 0x264, 0, 0x000, 0), /* MX51_PAD_KEY_COL2__KEY_COL2 */ + IMX_PIN_REG(MX51_PAD_KEY_COL2, 0x654, 0x264, 7, 0x000, 0), /* MX51_PAD_KEY_COL2__PLL3_BYP */ + IMX_PIN_REG(MX51_PAD_KEY_COL3, 0x658, 0x268, 0, 0x000, 0), /* MX51_PAD_KEY_COL3__KEY_COL3 */ + IMX_PIN_REG(MX51_PAD_KEY_COL4, 0x65c, 0x26c, 3, 0x9b8, 1), /* MX51_PAD_KEY_COL4__I2C2_SCL */ + IMX_PIN_REG(MX51_PAD_KEY_COL4, 0x65c, 0x26c, 0, 0x000, 0), /* MX51_PAD_KEY_COL4__KEY_COL4 */ + IMX_PIN_REG(MX51_PAD_KEY_COL4, 0x65c, 0x26c, 6, 0x000, 0), /* MX51_PAD_KEY_COL4__SPDIF_OUT1 */ + IMX_PIN_REG(MX51_PAD_KEY_COL4, 0x65c, 0x26c, 1, 0x000, 0), /* MX51_PAD_KEY_COL4__UART1_RI */ + IMX_PIN_REG(MX51_PAD_KEY_COL4, 0x65c, 0x26c, 2, 0x9f0, 4), /* MX51_PAD_KEY_COL4__UART3_RTS */ + IMX_PIN_REG(MX51_PAD_KEY_COL5, 0x660, 0x270, 3, 0x9bc, 1), /* MX51_PAD_KEY_COL5__I2C2_SDA */ + IMX_PIN_REG(MX51_PAD_KEY_COL5, 0x660, 0x270, 0, 0x000, 0), /* MX51_PAD_KEY_COL5__KEY_COL5 */ + IMX_PIN_REG(MX51_PAD_KEY_COL5, 0x660, 0x270, 1, 0x000, 0), /* MX51_PAD_KEY_COL5__UART1_DCD */ + IMX_PIN_REG(MX51_PAD_KEY_COL5, 0x660, 0x270, 2, 0x000, 0), /* MX51_PAD_KEY_COL5__UART3_CTS */ + IMX_PIN_REG(MX51_PAD_USBH1_CLK, 0x678, 0x278, 1, 0x914, 1), /* MX51_PAD_USBH1_CLK__CSPI_SCLK */ + IMX_PIN_REG(MX51_PAD_USBH1_CLK, 0x678, 0x278, 2, 0x000, 0), /* MX51_PAD_USBH1_CLK__GPIO1_25 */ + IMX_PIN_REG(MX51_PAD_USBH1_CLK, 0x678, 0x278, 5, 0x9b8, 2), /* MX51_PAD_USBH1_CLK__I2C2_SCL */ + IMX_PIN_REG(MX51_PAD_USBH1_CLK, 0x678, 0x278, 0, 0x000, 0), /* MX51_PAD_USBH1_CLK__USBH1_CLK */ + IMX_PIN_REG(MX51_PAD_USBH1_DIR, 0x67c, 0x27c, 1, 0x91c, 1), /* MX51_PAD_USBH1_DIR__CSPI_MOSI */ + IMX_PIN_REG(MX51_PAD_USBH1_DIR, 0x67c, 0x27c, 2, 0x000, 0), /* MX51_PAD_USBH1_DIR__GPIO1_26 */ + IMX_PIN_REG(MX51_PAD_USBH1_DIR, 0x67c, 0x27c, 5, 0x9bc, 2), /* MX51_PAD_USBH1_DIR__I2C2_SDA */ + IMX_PIN_REG(MX51_PAD_USBH1_DIR, 0x67c, 0x27c, 0, 0x000, 0), /* MX51_PAD_USBH1_DIR__USBH1_DIR */ + IMX_PIN_REG(MX51_PAD_USBH1_STP, 0x680, 0x280, 1, 0x000, 0), /* MX51_PAD_USBH1_STP__CSPI_RDY */ + IMX_PIN_REG(MX51_PAD_USBH1_STP, 0x680, 0x280, 2, 0x000, 0), /* MX51_PAD_USBH1_STP__GPIO1_27 */ + IMX_PIN_REG(MX51_PAD_USBH1_STP, 0x680, 0x280, 5, 0x9f4, 6), /* MX51_PAD_USBH1_STP__UART3_RXD */ + IMX_PIN_REG(MX51_PAD_USBH1_STP, 0x680, 0x280, 0, 0x000, 0), /* MX51_PAD_USBH1_STP__USBH1_STP */ + IMX_PIN_REG(MX51_PAD_USBH1_NXT, 0x684, 0x284, 1, 0x918, 0), /* MX51_PAD_USBH1_NXT__CSPI_MISO */ + IMX_PIN_REG(MX51_PAD_USBH1_NXT, 0x684, 0x284, 2, 0x000, 0), /* MX51_PAD_USBH1_NXT__GPIO1_28 */ + IMX_PIN_REG(MX51_PAD_USBH1_NXT, 0x684, 0x284, 5, 0x000, 0), /* MX51_PAD_USBH1_NXT__UART3_TXD */ + IMX_PIN_REG(MX51_PAD_USBH1_NXT, 0x684, 0x284, 0, 0x000, 0), /* MX51_PAD_USBH1_NXT__USBH1_NXT */ + IMX_PIN_REG(MX51_PAD_USBH1_DATA0, 0x688, 0x288, 2, 0x000, 0), /* MX51_PAD_USBH1_DATA0__GPIO1_11 */ + IMX_PIN_REG(MX51_PAD_USBH1_DATA0, 0x688, 0x288, 1, 0x000, 0), /* MX51_PAD_USBH1_DATA0__UART2_CTS */ + IMX_PIN_REG(MX51_PAD_USBH1_DATA0, 0x688, 0x288, 0, 0x000, 0), /* MX51_PAD_USBH1_DATA0__USBH1_DATA0 */ + IMX_PIN_REG(MX51_PAD_USBH1_DATA1, 0x68c, 0x28c, 2, 0x000, 0), /* MX51_PAD_USBH1_DATA1__GPIO1_12 */ + IMX_PIN_REG(MX51_PAD_USBH1_DATA1, 0x68c, 0x28c, 1, 0x9ec, 4), /* MX51_PAD_USBH1_DATA1__UART2_RXD */ + IMX_PIN_REG(MX51_PAD_USBH1_DATA1, 0x68c, 0x28c, 0, 0x000, 0), /* MX51_PAD_USBH1_DATA1__USBH1_DATA1 */ + IMX_PIN_REG(MX51_PAD_USBH1_DATA2, 0x690, 0x290, 2, 0x000, 0), /* MX51_PAD_USBH1_DATA2__GPIO1_13 */ + IMX_PIN_REG(MX51_PAD_USBH1_DATA2, 0x690, 0x290, 1, 0x000, 0), /* MX51_PAD_USBH1_DATA2__UART2_TXD */ + IMX_PIN_REG(MX51_PAD_USBH1_DATA2, 0x690, 0x290, 0, 0x000, 0), /* MX51_PAD_USBH1_DATA2__USBH1_DATA2 */ + IMX_PIN_REG(MX51_PAD_USBH1_DATA3, 0x694, 0x294, 2, 0x000, 0), /* MX51_PAD_USBH1_DATA3__GPIO1_14 */ + IMX_PIN_REG(MX51_PAD_USBH1_DATA3, 0x694, 0x294, 1, 0x9e8, 5), /* MX51_PAD_USBH1_DATA3__UART2_RTS */ + IMX_PIN_REG(MX51_PAD_USBH1_DATA3, 0x694, 0x294, 0, 0x000, 0), /* MX51_PAD_USBH1_DATA3__USBH1_DATA3 */ + IMX_PIN_REG(MX51_PAD_USBH1_DATA4, 0x698, 0x298, 1, 0x000, 0), /* MX51_PAD_USBH1_DATA4__CSPI_SS0 */ + IMX_PIN_REG(MX51_PAD_USBH1_DATA4, 0x698, 0x298, 2, 0x000, 0), /* MX51_PAD_USBH1_DATA4__GPIO1_15 */ + IMX_PIN_REG(MX51_PAD_USBH1_DATA4, 0x698, 0x298, 0, 0x000, 0), /* MX51_PAD_USBH1_DATA4__USBH1_DATA4 */ + IMX_PIN_REG(MX51_PAD_USBH1_DATA5, 0x69c, 0x29c, 1, 0x920, 0), /* MX51_PAD_USBH1_DATA5__CSPI_SS1 */ + IMX_PIN_REG(MX51_PAD_USBH1_DATA5, 0x69c, 0x29c, 2, 0x000, 0), /* MX51_PAD_USBH1_DATA5__GPIO1_16 */ + IMX_PIN_REG(MX51_PAD_USBH1_DATA5, 0x69c, 0x29c, 0, 0x000, 0), /* MX51_PAD_USBH1_DATA5__USBH1_DATA5 */ + IMX_PIN_REG(MX51_PAD_USBH1_DATA6, 0x6a0, 0x2a0, 1, 0x928, 1), /* MX51_PAD_USBH1_DATA6__CSPI_SS3 */ + IMX_PIN_REG(MX51_PAD_USBH1_DATA6, 0x6a0, 0x2a0, 2, 0x000, 0), /* MX51_PAD_USBH1_DATA6__GPIO1_17 */ + IMX_PIN_REG(MX51_PAD_USBH1_DATA6, 0x6a0, 0x2a0, 0, 0x000, 0), /* MX51_PAD_USBH1_DATA6__USBH1_DATA6 */ + IMX_PIN_REG(MX51_PAD_USBH1_DATA7, 0x6a4, 0x2a4, 1, 0x000, 0), /* MX51_PAD_USBH1_DATA7__ECSPI1_SS3 */ + IMX_PIN_REG(MX51_PAD_USBH1_DATA7, 0x6a4, 0x2a4, 5, 0x934, 1), /* MX51_PAD_USBH1_DATA7__ECSPI2_SS3 */ + IMX_PIN_REG(MX51_PAD_USBH1_DATA7, 0x6a4, 0x2a4, 2, 0x000, 0), /* MX51_PAD_USBH1_DATA7__GPIO1_18 */ + IMX_PIN_REG(MX51_PAD_USBH1_DATA7, 0x6a4, 0x2a4, 0, 0x000, 0), /* MX51_PAD_USBH1_DATA7__USBH1_DATA7 */ + IMX_PIN_REG(MX51_PAD_DI1_PIN11, 0x6a8, 0x2a8, 0, 0x000, 0), /* MX51_PAD_DI1_PIN11__DI1_PIN11 */ + IMX_PIN_REG(MX51_PAD_DI1_PIN11, 0x6a8, 0x2a8, 7, 0x000, 0), /* MX51_PAD_DI1_PIN11__ECSPI1_SS2 */ + IMX_PIN_REG(MX51_PAD_DI1_PIN11, 0x6a8, 0x2a8, 4, 0x000, 0), /* MX51_PAD_DI1_PIN11__GPIO3_0 */ + IMX_PIN_REG(MX51_PAD_DI1_PIN12, 0x6ac, 0x2ac, 0, 0x000, 0), /* MX51_PAD_DI1_PIN12__DI1_PIN12 */ + IMX_PIN_REG(MX51_PAD_DI1_PIN12, 0x6ac, 0x2ac, 4, 0x978, 1), /* MX51_PAD_DI1_PIN12__GPIO3_1 */ + IMX_PIN_REG(MX51_PAD_DI1_PIN13, 0x6b0, 0x2b0, 0, 0x000, 0), /* MX51_PAD_DI1_PIN13__DI1_PIN13 */ + IMX_PIN_REG(MX51_PAD_DI1_PIN13, 0x6b0, 0x2b0, 4, 0x97c, 1), /* MX51_PAD_DI1_PIN13__GPIO3_2 */ + IMX_PIN_REG(MX51_PAD_DI1_D0_CS, 0x6b4, 0x2b4, 0, 0x000, 0), /* MX51_PAD_DI1_D0_CS__DI1_D0_CS */ + IMX_PIN_REG(MX51_PAD_DI1_D0_CS, 0x6b4, 0x2b4, 4, 0x980, 1), /* MX51_PAD_DI1_D0_CS__GPIO3_3 */ + IMX_PIN_REG(MX51_PAD_DI1_D1_CS, 0x6b8, 0x2b8, 0, 0x000, 0), /* MX51_PAD_DI1_D1_CS__DI1_D1_CS */ + IMX_PIN_REG(MX51_PAD_DI1_D1_CS, 0x6b8, 0x2b8, 2, 0x000, 0), /* MX51_PAD_DI1_D1_CS__DISP1_PIN14 */ + IMX_PIN_REG(MX51_PAD_DI1_D1_CS, 0x6b8, 0x2b8, 3, 0x000, 0), /* MX51_PAD_DI1_D1_CS__DISP1_PIN5 */ + IMX_PIN_REG(MX51_PAD_DI1_D1_CS, 0x6b8, 0x2b8, 4, 0x984, 1), /* MX51_PAD_DI1_D1_CS__GPIO3_4 */ + IMX_PIN_REG(MX51_PAD_DISPB2_SER_DIN, 0x6bc, 0x2bc, 2, 0x9a4, 1), /* MX51_PAD_DISPB2_SER_DIN__DISP1_PIN1 */ + IMX_PIN_REG(MX51_PAD_DISPB2_SER_DIN, 0x6bc, 0x2bc, 0, 0x9c4, 0), /* MX51_PAD_DISPB2_SER_DIN__DISPB2_SER_DIN */ + IMX_PIN_REG(MX51_PAD_DISPB2_SER_DIN, 0x6bc, 0x2bc, 4, 0x988, 1), /* MX51_PAD_DISPB2_SER_DIN__GPIO3_5 */ + IMX_PIN_REG(MX51_PAD_DISPB2_SER_DIO, 0x6c0, 0x2c0, 3, 0x000, 0), /* MX51_PAD_DISPB2_SER_DIO__DISP1_PIN6 */ + IMX_PIN_REG(MX51_PAD_DISPB2_SER_DIO, 0x6c0, 0x2c0, 0, 0x9c4, 1), /* MX51_PAD_DISPB2_SER_DIO__DISPB2_SER_DIO */ + IMX_PIN_REG(MX51_PAD_DISPB2_SER_DIO, 0x6c0, 0x2c0, 4, 0x98c, 1), /* MX51_PAD_DISPB2_SER_DIO__GPIO3_6 */ + IMX_PIN_REG(MX51_PAD_DISPB2_SER_CLK, 0x6c4, 0x2c4, 2, 0x000, 0), /* MX51_PAD_DISPB2_SER_CLK__DISP1_PIN17 */ + IMX_PIN_REG(MX51_PAD_DISPB2_SER_CLK, 0x6c4, 0x2c4, 3, 0x000, 0), /* MX51_PAD_DISPB2_SER_CLK__DISP1_PIN7 */ + IMX_PIN_REG(MX51_PAD_DISPB2_SER_CLK, 0x6c4, 0x2c4, 0, 0x000, 0), /* MX51_PAD_DISPB2_SER_CLK__DISPB2_SER_CLK */ + IMX_PIN_REG(MX51_PAD_DISPB2_SER_CLK, 0x6c4, 0x2c4, 4, 0x990, 1), /* MX51_PAD_DISPB2_SER_CLK__GPIO3_7 */ + IMX_PIN_REG(MX51_PAD_DISPB2_SER_RS, 0x6c8, 0x2c8, 2, 0x000, 0), /* MX51_PAD_DISPB2_SER_RS__DISP1_EXT_CLK */ + IMX_PIN_REG(MX51_PAD_DISPB2_SER_RS, 0x6c8, 0x2c8, 2, 0x000, 0), /* MX51_PAD_DISPB2_SER_RS__DISP1_PIN16 */ + IMX_PIN_REG(MX51_PAD_DISPB2_SER_RS, 0x6c8, 0x2c8, 3, 0x000, 0), /* MX51_PAD_DISPB2_SER_RS__DISP1_PIN8 */ + IMX_PIN_REG(MX51_PAD_DISPB2_SER_RS, 0x6c8, 0x2c8, 0, 0x000, 0), /* MX51_PAD_DISPB2_SER_RS__DISPB2_SER_RS */ + IMX_PIN_REG(MX51_PAD_DISPB2_SER_RS, 0x6c8, 0x2c8, 0, 0x000, 0), /* MX51_PAD_DISPB2_SER_RS__DISPB2_SER_RS */ + IMX_PIN_REG(MX51_PAD_DISPB2_SER_RS, 0x6c8, 0x2c8, 4, 0x994, 1), /* MX51_PAD_DISPB2_SER_RS__GPIO3_8 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT0, 0x6cc, 0x2cc, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT0__DISP1_DAT0 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT1, 0x6d0, 0x2d0, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT1__DISP1_DAT1 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT2, 0x6d4, 0x2d4, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT2__DISP1_DAT2 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT3, 0x6d8, 0x2d8, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT3__DISP1_DAT3 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT4, 0x6dc, 0x2dc, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT4__DISP1_DAT4 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT5, 0x6e0, 0x2e0, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT5__DISP1_DAT5 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT6, 0x6e4, 0x2e4, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT6__BOOT_USB_SRC */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT6, 0x6e4, 0x2e4, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT6__DISP1_DAT6 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT7, 0x6e8, 0x2e8, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT7__BOOT_EEPROM_CFG */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT7, 0x6e8, 0x2e8, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT7__DISP1_DAT7 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT8, 0x6ec, 0x2ec, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT8__BOOT_SRC0 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT8, 0x6ec, 0x2ec, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT8__DISP1_DAT8 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT9, 0x6f0, 0x2f0, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT9__BOOT_SRC1 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT9, 0x6f0, 0x2f0, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT9__DISP1_DAT9 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT10, 0x6f4, 0x2f4, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT10__BOOT_SPARE_SIZE */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT10, 0x6f4, 0x2f4, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT10__DISP1_DAT10 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT11, 0x6f8, 0x2f8, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT11__BOOT_LPB_FREQ2 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT11, 0x6f8, 0x2f8, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT11__DISP1_DAT11 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT12, 0x6fc, 0x2fc, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT12__BOOT_MLC_SEL */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT12, 0x6fc, 0x2fc, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT12__DISP1_DAT12 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT13, 0x700, 0x300, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT13__BOOT_MEM_CTL0 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT13, 0x700, 0x300, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT13__DISP1_DAT13 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT14, 0x704, 0x304, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT14__BOOT_MEM_CTL1 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT14, 0x704, 0x304, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT14__DISP1_DAT14 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT15, 0x708, 0x308, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT15__BOOT_BUS_WIDTH */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT15, 0x708, 0x308, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT15__DISP1_DAT15 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT16, 0x70c, 0x30c, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT16__BOOT_PAGE_SIZE0 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT16, 0x70c, 0x30c, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT16__DISP1_DAT16 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT17, 0x710, 0x310, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT17__BOOT_PAGE_SIZE1 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT17, 0x710, 0x310, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT17__DISP1_DAT17 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT18, 0x714, 0x314, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT18__BOOT_WEIM_MUXED0 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT18, 0x714, 0x314, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT18__DISP1_DAT18 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT18, 0x714, 0x314, 5, 0x000, 0), /* MX51_PAD_DISP1_DAT18__DISP2_PIN11 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT18, 0x714, 0x314, 4, 0x000, 0), /* MX51_PAD_DISP1_DAT18__DISP2_PIN5 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT19, 0x718, 0x318, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT19__BOOT_WEIM_MUXED1 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT19, 0x718, 0x318, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT19__DISP1_DAT19 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT19, 0x718, 0x318, 5, 0x000, 0), /* MX51_PAD_DISP1_DAT19__DISP2_PIN12 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT19, 0x718, 0x318, 4, 0x000, 0), /* MX51_PAD_DISP1_DAT19__DISP2_PIN6 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT20, 0x71c, 0x31c, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT20__BOOT_MEM_TYPE0 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT20, 0x71c, 0x31c, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT20__DISP1_DAT20 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT20, 0x71c, 0x31c, 5, 0x000, 0), /* MX51_PAD_DISP1_DAT20__DISP2_PIN13 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT20, 0x71c, 0x31c, 4, 0x000, 0), /* MX51_PAD_DISP1_DAT20__DISP2_PIN7 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT21, 0x720, 0x320, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT21__BOOT_MEM_TYPE1 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT21, 0x720, 0x320, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT21__DISP1_DAT21 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT21, 0x720, 0x320, 5, 0x000, 0), /* MX51_PAD_DISP1_DAT21__DISP2_PIN14 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT21, 0x720, 0x320, 4, 0x000, 0), /* MX51_PAD_DISP1_DAT21__DISP2_PIN8 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT22, 0x724, 0x324, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT22__BOOT_LPB_FREQ0 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT22, 0x724, 0x324, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT22__DISP1_DAT22 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT22, 0x724, 0x324, 6, 0x000, 0), /* MX51_PAD_DISP1_DAT22__DISP2_D0_CS */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT22, 0x724, 0x324, 5, 0x000, 0), /* MX51_PAD_DISP1_DAT22__DISP2_DAT16 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT23, 0x728, 0x328, 7, 0x000, 0), /* MX51_PAD_DISP1_DAT23__BOOT_LPB_FREQ1 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT23, 0x728, 0x328, 0, 0x000, 0), /* MX51_PAD_DISP1_DAT23__DISP1_DAT23 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT23, 0x728, 0x328, 6, 0x000, 0), /* MX51_PAD_DISP1_DAT23__DISP2_D1_CS */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT23, 0x728, 0x328, 5, 0x000, 0), /* MX51_PAD_DISP1_DAT23__DISP2_DAT17 */ + IMX_PIN_REG(MX51_PAD_DISP1_DAT23, 0x728, 0x328, 4, 0x000, 0), /* MX51_PAD_DISP1_DAT23__DISP2_SER_CS */ + IMX_PIN_REG(MX51_PAD_DI1_PIN3, 0x72c, 0x32c, 0, 0x000, 0), /* MX51_PAD_DI1_PIN3__DI1_PIN3 */ + IMX_PIN_REG(MX51_PAD_DI1_PIN2, 0x734, 0x330, 0, 0x000, 0), /* MX51_PAD_DI1_PIN2__DI1_PIN2 */ + IMX_PIN_REG(MX51_PAD_DI_GP2, 0x740, 0x338, 0, 0x000, 0), /* MX51_PAD_DI_GP2__DISP1_SER_CLK */ + IMX_PIN_REG(MX51_PAD_DI_GP2, 0x740, 0x338, 2, 0x9a8, 1), /* MX51_PAD_DI_GP2__DISP2_WAIT */ + IMX_PIN_REG(MX51_PAD_DI_GP3, 0x744, 0x33c, 3, 0x9a0, 1), /* MX51_PAD_DI_GP3__CSI1_DATA_EN */ + IMX_PIN_REG(MX51_PAD_DI_GP3, 0x744, 0x33c, 0, 0x9c0, 0), /* MX51_PAD_DI_GP3__DISP1_SER_DIO */ + IMX_PIN_REG(MX51_PAD_DI_GP3, 0x744, 0x33c, 2, 0x000, 0), /* MX51_PAD_DI_GP3__FEC_TX_ER */ + IMX_PIN_REG(MX51_PAD_DI2_PIN4, 0x748, 0x340, 3, 0x99c, 1), /* MX51_PAD_DI2_PIN4__CSI2_DATA_EN */ + IMX_PIN_REG(MX51_PAD_DI2_PIN4, 0x748, 0x340, 0, 0x000, 0), /* MX51_PAD_DI2_PIN4__DI2_PIN4 */ + IMX_PIN_REG(MX51_PAD_DI2_PIN4, 0x748, 0x340, 2, 0x950, 1), /* MX51_PAD_DI2_PIN4__FEC_CRS */ + IMX_PIN_REG(MX51_PAD_DI2_PIN2, 0x74c, 0x344, 0, 0x000, 0), /* MX51_PAD_DI2_PIN2__DI2_PIN2 */ + IMX_PIN_REG(MX51_PAD_DI2_PIN2, 0x74c, 0x344, 2, 0x000, 0), /* MX51_PAD_DI2_PIN2__FEC_MDC */ + IMX_PIN_REG(MX51_PAD_DI2_PIN3, 0x750, 0x348, 0, 0x000, 0), /* MX51_PAD_DI2_PIN3__DI2_PIN3 */ + IMX_PIN_REG(MX51_PAD_DI2_PIN3, 0x750, 0x348, 2, 0x954, 1), /* MX51_PAD_DI2_PIN3__FEC_MDIO */ + IMX_PIN_REG(MX51_PAD_DI2_DISP_CLK, 0x754, 0x34c, 0, 0x000, 0), /* MX51_PAD_DI2_DISP_CLK__DI2_DISP_CLK */ + IMX_PIN_REG(MX51_PAD_DI2_DISP_CLK, 0x754, 0x34c, 2, 0x95c, 1), /* MX51_PAD_DI2_DISP_CLK__FEC_RDATA1 */ + IMX_PIN_REG(MX51_PAD_DI_GP4, 0x758, 0x350, 4, 0x000, 0), /* MX51_PAD_DI_GP4__DI2_PIN15 */ + IMX_PIN_REG(MX51_PAD_DI_GP4, 0x758, 0x350, 0, 0x9c0, 1), /* MX51_PAD_DI_GP4__DISP1_SER_DIN */ + IMX_PIN_REG(MX51_PAD_DI_GP4, 0x758, 0x350, 3, 0x000, 0), /* MX51_PAD_DI_GP4__DISP2_PIN1 */ + IMX_PIN_REG(MX51_PAD_DI_GP4, 0x758, 0x350, 2, 0x960, 1), /* MX51_PAD_DI_GP4__FEC_RDATA2 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT0, 0x75c, 0x354, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT0__DISP2_DAT0 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT0, 0x75c, 0x354, 2, 0x964, 1), /* MX51_PAD_DISP2_DAT0__FEC_RDATA3 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT0, 0x75c, 0x354, 4, 0x9c8, 1), /* MX51_PAD_DISP2_DAT0__KEY_COL6 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT0, 0x75c, 0x354, 5, 0x9f4, 8), /* MX51_PAD_DISP2_DAT0__UART3_RXD */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT0, 0x75c, 0x354, 3, 0x9f8, 1), /* MX51_PAD_DISP2_DAT0__USBH3_CLK */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT1, 0x760, 0x358, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT1__DISP2_DAT1 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT1, 0x760, 0x358, 2, 0x970, 1), /* MX51_PAD_DISP2_DAT1__FEC_RX_ER */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT1, 0x760, 0x358, 4, 0x9cc, 1), /* MX51_PAD_DISP2_DAT1__KEY_COL7 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT1, 0x760, 0x358, 5, 0x000, 0), /* MX51_PAD_DISP2_DAT1__UART3_TXD */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT1, 0x760, 0x358, 3, 0xa1c, 1), /* MX51_PAD_DISP2_DAT1__USBH3_DIR */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT2, 0x764, 0x35c, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT2__DISP2_DAT2 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT3, 0x768, 0x360, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT3__DISP2_DAT3 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT4, 0x76c, 0x364, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT4__DISP2_DAT4 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT5, 0x770, 0x368, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT5__DISP2_DAT5 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT6, 0x774, 0x36c, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT6__DISP2_DAT6 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT6, 0x774, 0x36c, 2, 0x000, 0), /* MX51_PAD_DISP2_DAT6__FEC_TDATA1 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT6, 0x774, 0x36c, 5, 0x000, 0), /* MX51_PAD_DISP2_DAT6__GPIO1_19 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT6, 0x774, 0x36c, 4, 0x9d0, 1), /* MX51_PAD_DISP2_DAT6__KEY_ROW4 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT6, 0x774, 0x36c, 3, 0xa24, 1), /* MX51_PAD_DISP2_DAT6__USBH3_STP */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT7, 0x778, 0x370, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT7__DISP2_DAT7 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT7, 0x778, 0x370, 2, 0x000, 0), /* MX51_PAD_DISP2_DAT7__FEC_TDATA2 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT7, 0x778, 0x370, 5, 0x000, 0), /* MX51_PAD_DISP2_DAT7__GPIO1_29 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT7, 0x778, 0x370, 4, 0x9d4, 1), /* MX51_PAD_DISP2_DAT7__KEY_ROW5 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT7, 0x778, 0x370, 3, 0xa20, 1), /* MX51_PAD_DISP2_DAT7__USBH3_NXT */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT8, 0x77c, 0x374, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT8__DISP2_DAT8 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT8, 0x77c, 0x374, 2, 0x000, 0), /* MX51_PAD_DISP2_DAT8__FEC_TDATA3 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT8, 0x77c, 0x374, 5, 0x000, 0), /* MX51_PAD_DISP2_DAT8__GPIO1_30 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT8, 0x77c, 0x374, 4, 0x9d8, 1), /* MX51_PAD_DISP2_DAT8__KEY_ROW6 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT8, 0x77c, 0x374, 3, 0x9fc, 1), /* MX51_PAD_DISP2_DAT8__USBH3_DATA0 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT9, 0x780, 0x378, 4, 0x8f4, 1), /* MX51_PAD_DISP2_DAT9__AUD6_RXC */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT9, 0x780, 0x378, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT9__DISP2_DAT9 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT9, 0x780, 0x378, 2, 0x000, 0), /* MX51_PAD_DISP2_DAT9__FEC_TX_EN */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT9, 0x780, 0x378, 5, 0x000, 0), /* MX51_PAD_DISP2_DAT9__GPIO1_31 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT9, 0x780, 0x378, 3, 0xa00, 1), /* MX51_PAD_DISP2_DAT9__USBH3_DATA1 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT10, 0x784, 0x37c, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT10__DISP2_DAT10 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT10, 0x784, 0x37c, 5, 0x000, 0), /* MX51_PAD_DISP2_DAT10__DISP2_SER_CS */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT10, 0x784, 0x37c, 2, 0x94c, 1), /* MX51_PAD_DISP2_DAT10__FEC_COL */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT10, 0x784, 0x37c, 4, 0x9dc, 1), /* MX51_PAD_DISP2_DAT10__KEY_ROW7 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT10, 0x784, 0x37c, 3, 0xa04, 1), /* MX51_PAD_DISP2_DAT10__USBH3_DATA2 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT11, 0x788, 0x380, 4, 0x8f0, 1), /* MX51_PAD_DISP2_DAT11__AUD6_TXD */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT11, 0x788, 0x380, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT11__DISP2_DAT11 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT11, 0x788, 0x380, 2, 0x968, 1), /* MX51_PAD_DISP2_DAT11__FEC_RX_CLK */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT11, 0x788, 0x380, 7, 0x000, 0), /* MX51_PAD_DISP2_DAT11__GPIO1_10 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT11, 0x788, 0x380, 3, 0xa08, 1), /* MX51_PAD_DISP2_DAT11__USBH3_DATA3 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT12, 0x78c, 0x384, 4, 0x8ec, 1), /* MX51_PAD_DISP2_DAT12__AUD6_RXD */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT12, 0x78c, 0x384, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT12__DISP2_DAT12 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT12, 0x78c, 0x384, 2, 0x96c, 1), /* MX51_PAD_DISP2_DAT12__FEC_RX_DV */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT12, 0x78c, 0x384, 3, 0xa0c, 1), /* MX51_PAD_DISP2_DAT12__USBH3_DATA4 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT13, 0x790, 0x388, 4, 0x8fc, 1), /* MX51_PAD_DISP2_DAT13__AUD6_TXC */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT13, 0x790, 0x388, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT13__DISP2_DAT13 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT13, 0x790, 0x388, 2, 0x974, 1), /* MX51_PAD_DISP2_DAT13__FEC_TX_CLK */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT13, 0x790, 0x388, 3, 0xa10, 1), /* MX51_PAD_DISP2_DAT13__USBH3_DATA5 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT14, 0x794, 0x38c, 4, 0x900, 1), /* MX51_PAD_DISP2_DAT14__AUD6_TXFS */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT14, 0x794, 0x38c, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT14__DISP2_DAT14 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT14, 0x794, 0x38c, 2, 0x958, 1), /* MX51_PAD_DISP2_DAT14__FEC_RDATA0 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT14, 0x794, 0x38c, 3, 0xa14, 1), /* MX51_PAD_DISP2_DAT14__USBH3_DATA6 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT15, 0x798, 0x390, 4, 0x8f8, 1), /* MX51_PAD_DISP2_DAT15__AUD6_RXFS */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT15, 0x798, 0x390, 5, 0x000, 0), /* MX51_PAD_DISP2_DAT15__DISP1_SER_CS */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT15, 0x798, 0x390, 0, 0x000, 0), /* MX51_PAD_DISP2_DAT15__DISP2_DAT15 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT15, 0x798, 0x390, 2, 0x000, 0), /* MX51_PAD_DISP2_DAT15__FEC_TDATA0 */ + IMX_PIN_REG(MX51_PAD_DISP2_DAT15, 0x798, 0x390, 3, 0xa18, 1), /* MX51_PAD_DISP2_DAT15__USBH3_DATA7 */ + IMX_PIN_REG(MX51_PAD_SD1_CMD, 0x79c, 0x394, 1, 0x8e0, 1), /* MX51_PAD_SD1_CMD__AUD5_RXFS */ + IMX_PIN_REG(MX51_PAD_SD1_CMD, 0x79c, 0x394, 2, 0x91c, 2), /* MX51_PAD_SD1_CMD__CSPI_MOSI */ + IMX_PIN_REG(MX51_PAD_SD1_CMD, 0x79c, 0x394, 0, 0x000, 0), /* MX51_PAD_SD1_CMD__SD1_CMD */ + IMX_PIN_REG(MX51_PAD_SD1_CLK, 0x7a0, 0x398, 1, 0x8dc, 1), /* MX51_PAD_SD1_CLK__AUD5_RXC */ + IMX_PIN_REG(MX51_PAD_SD1_CLK, 0x7a0, 0x398, 2, 0x914, 2), /* MX51_PAD_SD1_CLK__CSPI_SCLK */ + IMX_PIN_REG(MX51_PAD_SD1_CLK, 0x7a0, 0x398, 0, 0x000, 0), /* MX51_PAD_SD1_CLK__SD1_CLK */ + IMX_PIN_REG(MX51_PAD_SD1_DATA0, 0x7a4, 0x39c, 1, 0x8d8, 2), /* MX51_PAD_SD1_DATA0__AUD5_TXD */ + IMX_PIN_REG(MX51_PAD_SD1_DATA0, 0x7a4, 0x39c, 2, 0x918, 1), /* MX51_PAD_SD1_DATA0__CSPI_MISO */ + IMX_PIN_REG(MX51_PAD_SD1_DATA0, 0x7a4, 0x39c, 0, 0x000, 0), /* MX51_PAD_SD1_DATA0__SD1_DATA0 */ + IMX_PIN_REG(MX51_PAD_EIM_DA0, NO_PAD, 0x01c, 0, 0x000, 0), /* MX51_PAD_EIM_DA0__EIM_DA0 */ + IMX_PIN_REG(MX51_PAD_EIM_DA1, NO_PAD, 0x020, 0, 0x000, 0), /* MX51_PAD_EIM_DA1__EIM_DA1 */ + IMX_PIN_REG(MX51_PAD_EIM_DA2, NO_PAD, 0x024, 0, 0x000, 0), /* MX51_PAD_EIM_DA2__EIM_DA2 */ + IMX_PIN_REG(MX51_PAD_EIM_DA3, NO_PAD, 0x028, 0, 0x000, 0), /* MX51_PAD_EIM_DA3__EIM_DA3 */ + IMX_PIN_REG(MX51_PAD_SD1_DATA1, 0x7a8, 0x3a0, 1, 0x8d4, 2), /* MX51_PAD_SD1_DATA1__AUD5_RXD */ + IMX_PIN_REG(MX51_PAD_SD1_DATA1, 0x7a8, 0x3a0, 0, 0x000, 0), /* MX51_PAD_SD1_DATA1__SD1_DATA1 */ + IMX_PIN_REG(MX51_PAD_EIM_DA4, NO_PAD, 0x02c, 0, 0x000, 0), /* MX51_PAD_EIM_DA4__EIM_DA4 */ + IMX_PIN_REG(MX51_PAD_EIM_DA5, NO_PAD, 0x030, 0, 0x000, 0), /* MX51_PAD_EIM_DA5__EIM_DA5 */ + IMX_PIN_REG(MX51_PAD_EIM_DA6, NO_PAD, 0x034, 0, 0x000, 0), /* MX51_PAD_EIM_DA6__EIM_DA6 */ + IMX_PIN_REG(MX51_PAD_EIM_DA7, NO_PAD, 0x038, 0, 0x000, 0), /* MX51_PAD_EIM_DA7__EIM_DA7 */ + IMX_PIN_REG(MX51_PAD_SD1_DATA2, 0x7ac, 0x3a4, 1, 0x8e4, 2), /* MX51_PAD_SD1_DATA2__AUD5_TXC */ + IMX_PIN_REG(MX51_PAD_SD1_DATA2, 0x7ac, 0x3a4, 0, 0x000, 0), /* MX51_PAD_SD1_DATA2__SD1_DATA2 */ + IMX_PIN_REG(MX51_PAD_EIM_DA10, NO_PAD, 0x044, 0, 0x000, 0), /* MX51_PAD_EIM_DA10__EIM_DA10 */ + IMX_PIN_REG(MX51_PAD_EIM_DA11, NO_PAD, 0x048, 0, 0x000, 0), /* MX51_PAD_EIM_DA11__EIM_DA11 */ + IMX_PIN_REG(MX51_PAD_EIM_DA8, NO_PAD, 0x03c, 0, 0x000, 0), /* MX51_PAD_EIM_DA8__EIM_DA8 */ + IMX_PIN_REG(MX51_PAD_EIM_DA9, NO_PAD, 0x040, 0, 0x000, 0), /* MX51_PAD_EIM_DA9__EIM_DA9 */ + IMX_PIN_REG(MX51_PAD_SD1_DATA3, 0x7b0, 0x3a8, 1, 0x8e8, 2), /* MX51_PAD_SD1_DATA3__AUD5_TXFS */ + IMX_PIN_REG(MX51_PAD_SD1_DATA3, 0x7b0, 0x3a8, 2, 0x920, 1), /* MX51_PAD_SD1_DATA3__CSPI_SS1 */ + IMX_PIN_REG(MX51_PAD_SD1_DATA3, 0x7b0, 0x3a8, 0, 0x000, 0), /* MX51_PAD_SD1_DATA3__SD1_DATA3 */ + IMX_PIN_REG(MX51_PAD_GPIO1_0, 0x7b4, 0x3ac, 2, 0x924, 0), /* MX51_PAD_GPIO1_0__CSPI_SS2 */ + IMX_PIN_REG(MX51_PAD_GPIO1_0, 0x7b4, 0x3ac, 1, 0x000, 0), /* MX51_PAD_GPIO1_0__GPIO1_0 */ + IMX_PIN_REG(MX51_PAD_GPIO1_0, 0x7b4, 0x3ac, 0, 0x000, 0), /* MX51_PAD_GPIO1_0__SD1_CD */ + IMX_PIN_REG(MX51_PAD_GPIO1_1, 0x7b8, 0x3b0, 2, 0x918, 2), /* MX51_PAD_GPIO1_1__CSPI_MISO */ + IMX_PIN_REG(MX51_PAD_GPIO1_1, 0x7b8, 0x3b0, 1, 0x000, 0), /* MX51_PAD_GPIO1_1__GPIO1_1 */ + IMX_PIN_REG(MX51_PAD_GPIO1_1, 0x7b8, 0x3b0, 0, 0x000, 0), /* MX51_PAD_GPIO1_1__SD1_WP */ + IMX_PIN_REG(MX51_PAD_EIM_DA12, NO_PAD, 0x04c, 0, 0x000, 0), /* MX51_PAD_EIM_DA12__EIM_DA12 */ + IMX_PIN_REG(MX51_PAD_EIM_DA13, NO_PAD, 0x050, 0, 0x000, 0), /* MX51_PAD_EIM_DA13__EIM_DA13 */ + IMX_PIN_REG(MX51_PAD_EIM_DA14, NO_PAD, 0x054, 0, 0x000, 0), /* MX51_PAD_EIM_DA14__EIM_DA14 */ + IMX_PIN_REG(MX51_PAD_EIM_DA15, NO_PAD, 0x058, 0, 0x000, 0), /* MX51_PAD_EIM_DA15__EIM_DA15 */ + IMX_PIN_REG(MX51_PAD_SD2_CMD, NO_PAD, 0x3b4, 2, 0x91c, 3), /* MX51_PAD_SD2_CMD__CSPI_MOSI */ + IMX_PIN_REG(MX51_PAD_SD2_CMD, 0x7bc, 0x3b4, 1, 0x9b0, 2), /* MX51_PAD_SD2_CMD__I2C1_SCL */ + IMX_PIN_REG(MX51_PAD_SD2_CMD, 0x7bc, 0x3b4, 0, 0x000, 0), /* MX51_PAD_SD2_CMD__SD2_CMD */ + IMX_PIN_REG(MX51_PAD_SD2_CLK, 0x7c0, 0x3b8, 2, 0x914, 3), /* MX51_PAD_SD2_CLK__CSPI_SCLK */ + IMX_PIN_REG(MX51_PAD_SD2_CLK, 0x7c0, 0x3b8, 1, 0x9b4, 2), /* MX51_PAD_SD2_CLK__I2C1_SDA */ + IMX_PIN_REG(MX51_PAD_SD2_CLK, 0x7c0, 0x3b8, 0, 0x000, 0), /* MX51_PAD_SD2_CLK__SD2_CLK */ + IMX_PIN_REG(MX51_PAD_SD2_DATA0, 0x7c4, 0x3bc, 2, 0x918, 3), /* MX51_PAD_SD2_DATA0__CSPI_MISO */ + IMX_PIN_REG(MX51_PAD_SD2_DATA0, 0x7c4, 0x3bc, 1, 0x000, 0), /* MX51_PAD_SD2_DATA0__SD1_DAT4 */ + IMX_PIN_REG(MX51_PAD_SD2_DATA0, 0x7c4, 0x3bc, 0, 0x000, 0), /* MX51_PAD_SD2_DATA0__SD2_DATA0 */ + IMX_PIN_REG(MX51_PAD_SD2_DATA1, 0x7c8, 0x3c0, 1, 0x000, 0), /* MX51_PAD_SD2_DATA1__SD1_DAT5 */ + IMX_PIN_REG(MX51_PAD_SD2_DATA1, 0x7c8, 0x3c0, 0, 0x000, 0), /* MX51_PAD_SD2_DATA1__SD2_DATA1 */ + IMX_PIN_REG(MX51_PAD_SD2_DATA1, 0x7c8, 0x3c0, 2, 0x000, 0), /* MX51_PAD_SD2_DATA1__USBH3_H2_DP */ + IMX_PIN_REG(MX51_PAD_SD2_DATA2, 0x7cc, 0x3c4, 1, 0x000, 0), /* MX51_PAD_SD2_DATA2__SD1_DAT6 */ + IMX_PIN_REG(MX51_PAD_SD2_DATA2, 0x7cc, 0x3c4, 0, 0x000, 0), /* MX51_PAD_SD2_DATA2__SD2_DATA2 */ + IMX_PIN_REG(MX51_PAD_SD2_DATA2, 0x7cc, 0x3c4, 2, 0x000, 0), /* MX51_PAD_SD2_DATA2__USBH3_H2_DM */ + IMX_PIN_REG(MX51_PAD_SD2_DATA3, 0x7d0, 0x3c8, 2, 0x924, 1), /* MX51_PAD_SD2_DATA3__CSPI_SS2 */ + IMX_PIN_REG(MX51_PAD_SD2_DATA3, 0x7d0, 0x3c8, 1, 0x000, 0), /* MX51_PAD_SD2_DATA3__SD1_DAT7 */ + IMX_PIN_REG(MX51_PAD_SD2_DATA3, 0x7d0, 0x3c8, 0, 0x000, 0), /* MX51_PAD_SD2_DATA3__SD2_DATA3 */ + IMX_PIN_REG(MX51_PAD_GPIO1_2, 0x7d4, 0x3cc, 5, 0x000, 0), /* MX51_PAD_GPIO1_2__CCM_OUT_2 */ + IMX_PIN_REG(MX51_PAD_GPIO1_2, 0x7d4, 0x3cc, 0, 0x000, 0), /* MX51_PAD_GPIO1_2__GPIO1_2 */ + IMX_PIN_REG(MX51_PAD_GPIO1_2, 0x7d4, 0x3cc, 2, 0x9b8, 3), /* MX51_PAD_GPIO1_2__I2C2_SCL */ + IMX_PIN_REG(MX51_PAD_GPIO1_2, 0x7d4, 0x3cc, 7, 0x90c, 1), /* MX51_PAD_GPIO1_2__PLL1_BYP */ + IMX_PIN_REG(MX51_PAD_GPIO1_2, 0x7d4, 0x3cc, 1, 0x000, 0), /* MX51_PAD_GPIO1_2__PWM1_PWMO */ + IMX_PIN_REG(MX51_PAD_GPIO1_3, 0x7d8, 0x3d0, 0, 0x000, 0), /* MX51_PAD_GPIO1_3__GPIO1_3 */ + IMX_PIN_REG(MX51_PAD_GPIO1_3, 0x7d8, 0x3d0, 2, 0x9bc, 3), /* MX51_PAD_GPIO1_3__I2C2_SDA */ + IMX_PIN_REG(MX51_PAD_GPIO1_3, 0x7d8, 0x3d0, 7, 0x910, 1), /* MX51_PAD_GPIO1_3__PLL2_BYP */ + IMX_PIN_REG(MX51_PAD_GPIO1_3, 0x7d8, 0x3d0, 1, 0x000, 0), /* MX51_PAD_GPIO1_3__PWM2_PWMO */ + IMX_PIN_REG(MX51_PAD_PMIC_INT_REQ, 0x7fc, 0x3d4, 0, 0x000, 0), /* MX51_PAD_PMIC_INT_REQ__PMIC_INT_REQ */ + IMX_PIN_REG(MX51_PAD_PMIC_INT_REQ, 0x7fc, 0x3d4, 1, 0x000, 0), /* MX51_PAD_PMIC_INT_REQ__PMIC_PMU_IRQ_B */ + IMX_PIN_REG(MX51_PAD_GPIO1_4, 0x804, 0x3d8, 4, 0x908, 1), /* MX51_PAD_GPIO1_4__DISP2_EXT_CLK */ + IMX_PIN_REG(MX51_PAD_GPIO1_4, 0x804, 0x3d8, 3, 0x938, 1), /* MX51_PAD_GPIO1_4__EIM_RDY */ + IMX_PIN_REG(MX51_PAD_GPIO1_4, 0x804, 0x3d8, 0, 0x000, 0), /* MX51_PAD_GPIO1_4__GPIO1_4 */ + IMX_PIN_REG(MX51_PAD_GPIO1_4, 0x804, 0x3d8, 2, 0x000, 0), /* MX51_PAD_GPIO1_4__WDOG1_WDOG_B */ + IMX_PIN_REG(MX51_PAD_GPIO1_5, 0x808, 0x3dc, 6, 0x000, 0), /* MX51_PAD_GPIO1_5__CSI2_MCLK */ + IMX_PIN_REG(MX51_PAD_GPIO1_5, 0x808, 0x3dc, 3, 0x000, 0), /* MX51_PAD_GPIO1_5__DISP2_PIN16 */ + IMX_PIN_REG(MX51_PAD_GPIO1_5, 0x808, 0x3dc, 0, 0x000, 0), /* MX51_PAD_GPIO1_5__GPIO1_5 */ + IMX_PIN_REG(MX51_PAD_GPIO1_5, 0x808, 0x3dc, 2, 0x000, 0), /* MX51_PAD_GPIO1_5__WDOG2_WDOG_B */ + IMX_PIN_REG(MX51_PAD_GPIO1_6, 0x80c, 0x3e0, 4, 0x000, 0), /* MX51_PAD_GPIO1_6__DISP2_PIN17 */ + IMX_PIN_REG(MX51_PAD_GPIO1_6, 0x80c, 0x3e0, 0, 0x000, 0), /* MX51_PAD_GPIO1_6__GPIO1_6 */ + IMX_PIN_REG(MX51_PAD_GPIO1_6, 0x80c, 0x3e0, 3, 0x000, 0), /* MX51_PAD_GPIO1_6__REF_EN_B */ + IMX_PIN_REG(MX51_PAD_GPIO1_7, 0x810, 0x3e4, 3, 0x000, 0), /* MX51_PAD_GPIO1_7__CCM_OUT_0 */ + IMX_PIN_REG(MX51_PAD_GPIO1_7, 0x810, 0x3e4, 0, 0x000, 0), /* MX51_PAD_GPIO1_7__GPIO1_7 */ + IMX_PIN_REG(MX51_PAD_GPIO1_7, 0x810, 0x3e4, 6, 0x000, 0), /* MX51_PAD_GPIO1_7__SD2_WP */ + IMX_PIN_REG(MX51_PAD_GPIO1_7, 0x810, 0x3e4, 2, 0x000, 0), /* MX51_PAD_GPIO1_7__SPDIF_OUT1 */ + IMX_PIN_REG(MX51_PAD_GPIO1_8, 0x814, 0x3e8, 2, 0x99c, 2), /* MX51_PAD_GPIO1_8__CSI2_DATA_EN */ + IMX_PIN_REG(MX51_PAD_GPIO1_8, 0x814, 0x3e8, 0, 0x000, 0), /* MX51_PAD_GPIO1_8__GPIO1_8 */ + IMX_PIN_REG(MX51_PAD_GPIO1_8, 0x814, 0x3e8, 6, 0x000, 0), /* MX51_PAD_GPIO1_8__SD2_CD */ + IMX_PIN_REG(MX51_PAD_GPIO1_8, 0x814, 0x3e8, 1, 0x000, 0), /* MX51_PAD_GPIO1_8__USBH3_PWR */ + IMX_PIN_REG(MX51_PAD_GPIO1_9, 0x818, 0x3ec, 3, 0x000, 0), /* MX51_PAD_GPIO1_9__CCM_OUT_1 */ + IMX_PIN_REG(MX51_PAD_GPIO1_9, 0x818, 0x3ec, 2, 0x000, 0), /* MX51_PAD_GPIO1_9__DISP2_D1_CS */ + IMX_PIN_REG(MX51_PAD_GPIO1_9, 0x818, 0x3ec, 7, 0x000, 0), /* MX51_PAD_GPIO1_9__DISP2_SER_CS */ + IMX_PIN_REG(MX51_PAD_GPIO1_9, 0x818, 0x3ec, 0, 0x000, 0), /* MX51_PAD_GPIO1_9__GPIO1_9 */ + IMX_PIN_REG(MX51_PAD_GPIO1_9, 0x818, 0x3ec, 6, 0x000, 0), /* MX51_PAD_GPIO1_9__SD2_LCTL */ + IMX_PIN_REG(MX51_PAD_GPIO1_9, 0x818, 0x3ec, 1, 0x000, 0), /* MX51_PAD_GPIO1_9__USBH3_OC */ +}; + +/* Pad names for the pinmux subsystem */ +static const struct pinctrl_pin_desc imx51_pinctrl_pads[] = { + IMX_PINCTRL_PIN(MX51_PAD_EIM_D16), + IMX_PINCTRL_PIN(MX51_PAD_EIM_D17), + IMX_PINCTRL_PIN(MX51_PAD_EIM_D18), + IMX_PINCTRL_PIN(MX51_PAD_EIM_D19), + IMX_PINCTRL_PIN(MX51_PAD_EIM_D20), + IMX_PINCTRL_PIN(MX51_PAD_EIM_D21), + IMX_PINCTRL_PIN(MX51_PAD_EIM_D22), + IMX_PINCTRL_PIN(MX51_PAD_EIM_D23), + IMX_PINCTRL_PIN(MX51_PAD_EIM_D24), + IMX_PINCTRL_PIN(MX51_PAD_EIM_D25), + IMX_PINCTRL_PIN(MX51_PAD_EIM_D26), + IMX_PINCTRL_PIN(MX51_PAD_EIM_D27), + IMX_PINCTRL_PIN(MX51_PAD_EIM_D28), + IMX_PINCTRL_PIN(MX51_PAD_EIM_D29), + IMX_PINCTRL_PIN(MX51_PAD_EIM_D30), + IMX_PINCTRL_PIN(MX51_PAD_EIM_D31), + IMX_PINCTRL_PIN(MX51_PAD_EIM_A16), + IMX_PINCTRL_PIN(MX51_PAD_EIM_A17), + IMX_PINCTRL_PIN(MX51_PAD_EIM_A18), + IMX_PINCTRL_PIN(MX51_PAD_EIM_A19), + IMX_PINCTRL_PIN(MX51_PAD_EIM_A20), + IMX_PINCTRL_PIN(MX51_PAD_EIM_A21), + IMX_PINCTRL_PIN(MX51_PAD_EIM_A22), + IMX_PINCTRL_PIN(MX51_PAD_EIM_A23), + IMX_PINCTRL_PIN(MX51_PAD_EIM_A24), + IMX_PINCTRL_PIN(MX51_PAD_EIM_A25), + IMX_PINCTRL_PIN(MX51_PAD_EIM_A26), + IMX_PINCTRL_PIN(MX51_PAD_EIM_A27), + IMX_PINCTRL_PIN(MX51_PAD_EIM_EB0), + IMX_PINCTRL_PIN(MX51_PAD_EIM_EB1), + IMX_PINCTRL_PIN(MX51_PAD_EIM_EB2), + IMX_PINCTRL_PIN(MX51_PAD_EIM_EB3), + IMX_PINCTRL_PIN(MX51_PAD_EIM_OE), + IMX_PINCTRL_PIN(MX51_PAD_EIM_CS0), + IMX_PINCTRL_PIN(MX51_PAD_EIM_CS1), + IMX_PINCTRL_PIN(MX51_PAD_EIM_CS2), + IMX_PINCTRL_PIN(MX51_PAD_EIM_CS3), + IMX_PINCTRL_PIN(MX51_PAD_EIM_CS4), + IMX_PINCTRL_PIN(MX51_PAD_EIM_CS5), + IMX_PINCTRL_PIN(MX51_PAD_EIM_DTACK), + IMX_PINCTRL_PIN(MX51_PAD_EIM_LBA), + IMX_PINCTRL_PIN(MX51_PAD_EIM_CRE), + IMX_PINCTRL_PIN(MX51_PAD_DRAM_CS1), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_WE_B), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_RE_B), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_ALE), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_CLE), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_WP_B), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_RB0), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_RB1), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_RB2), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_RB3), + IMX_PINCTRL_PIN(MX51_PAD_GPIO_NAND), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_CS0), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_CS1), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_CS2), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_CS3), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_CS4), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_CS5), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_CS6), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_CS7), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_RDY_INT), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_D15), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_D14), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_D13), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_D12), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_D11), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_D10), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_D9), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_D8), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_D7), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_D6), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_D5), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_D4), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_D3), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_D2), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_D1), + IMX_PINCTRL_PIN(MX51_PAD_NANDF_D0), + IMX_PINCTRL_PIN(MX51_PAD_CSI1_D8), + IMX_PINCTRL_PIN(MX51_PAD_CSI1_D9), + IMX_PINCTRL_PIN(MX51_PAD_CSI1_D10), + IMX_PINCTRL_PIN(MX51_PAD_CSI1_D11), + IMX_PINCTRL_PIN(MX51_PAD_CSI1_D12), + IMX_PINCTRL_PIN(MX51_PAD_CSI1_D13), + IMX_PINCTRL_PIN(MX51_PAD_CSI1_D14), + IMX_PINCTRL_PIN(MX51_PAD_CSI1_D15), + IMX_PINCTRL_PIN(MX51_PAD_CSI1_D16), + IMX_PINCTRL_PIN(MX51_PAD_CSI1_D17), + IMX_PINCTRL_PIN(MX51_PAD_CSI1_D18), + IMX_PINCTRL_PIN(MX51_PAD_CSI1_D19), + IMX_PINCTRL_PIN(MX51_PAD_CSI1_VSYNC), + IMX_PINCTRL_PIN(MX51_PAD_CSI1_HSYNC), + IMX_PINCTRL_PIN(MX51_PAD_CSI1_PIXCLK), + IMX_PINCTRL_PIN(MX51_PAD_CSI1_MCLK), + IMX_PINCTRL_PIN(MX51_PAD_CSI2_D12), + IMX_PINCTRL_PIN(MX51_PAD_CSI2_D13), + IMX_PINCTRL_PIN(MX51_PAD_CSI2_D14), + IMX_PINCTRL_PIN(MX51_PAD_CSI2_D15), + IMX_PINCTRL_PIN(MX51_PAD_CSI2_D16), + IMX_PINCTRL_PIN(MX51_PAD_CSI2_D17), + IMX_PINCTRL_PIN(MX51_PAD_CSI2_D18), + IMX_PINCTRL_PIN(MX51_PAD_CSI2_D19), + IMX_PINCTRL_PIN(MX51_PAD_CSI2_VSYNC), + IMX_PINCTRL_PIN(MX51_PAD_CSI2_HSYNC), + IMX_PINCTRL_PIN(MX51_PAD_CSI2_PIXCLK), + IMX_PINCTRL_PIN(MX51_PAD_I2C1_CLK), + IMX_PINCTRL_PIN(MX51_PAD_I2C1_DAT), + IMX_PINCTRL_PIN(MX51_PAD_AUD3_BB_TXD), + IMX_PINCTRL_PIN(MX51_PAD_AUD3_BB_RXD), + IMX_PINCTRL_PIN(MX51_PAD_AUD3_BB_CK), + IMX_PINCTRL_PIN(MX51_PAD_AUD3_BB_FS), + IMX_PINCTRL_PIN(MX51_PAD_CSPI1_MOSI), + IMX_PINCTRL_PIN(MX51_PAD_CSPI1_MISO), + IMX_PINCTRL_PIN(MX51_PAD_CSPI1_SS0), + IMX_PINCTRL_PIN(MX51_PAD_CSPI1_SS1), + IMX_PINCTRL_PIN(MX51_PAD_CSPI1_RDY), + IMX_PINCTRL_PIN(MX51_PAD_CSPI1_SCLK), + IMX_PINCTRL_PIN(MX51_PAD_UART1_RXD), + IMX_PINCTRL_PIN(MX51_PAD_UART1_TXD), + IMX_PINCTRL_PIN(MX51_PAD_UART1_RTS), + IMX_PINCTRL_PIN(MX51_PAD_UART1_CTS), + IMX_PINCTRL_PIN(MX51_PAD_UART2_RXD), + IMX_PINCTRL_PIN(MX51_PAD_UART2_TXD), + IMX_PINCTRL_PIN(MX51_PAD_UART3_RXD), + IMX_PINCTRL_PIN(MX51_PAD_UART3_TXD), + IMX_PINCTRL_PIN(MX51_PAD_OWIRE_LINE), + IMX_PINCTRL_PIN(MX51_PAD_KEY_ROW0), + IMX_PINCTRL_PIN(MX51_PAD_KEY_ROW1), + IMX_PINCTRL_PIN(MX51_PAD_KEY_ROW2), + IMX_PINCTRL_PIN(MX51_PAD_KEY_ROW3), + IMX_PINCTRL_PIN(MX51_PAD_KEY_COL0), + IMX_PINCTRL_PIN(MX51_PAD_KEY_COL1), + IMX_PINCTRL_PIN(MX51_PAD_KEY_COL2), + IMX_PINCTRL_PIN(MX51_PAD_KEY_COL3), + IMX_PINCTRL_PIN(MX51_PAD_KEY_COL4), + IMX_PINCTRL_PIN(MX51_PAD_KEY_COL5), + IMX_PINCTRL_PIN(MX51_PAD_USBH1_CLK), + IMX_PINCTRL_PIN(MX51_PAD_USBH1_DIR), + IMX_PINCTRL_PIN(MX51_PAD_USBH1_STP), + IMX_PINCTRL_PIN(MX51_PAD_USBH1_NXT), + IMX_PINCTRL_PIN(MX51_PAD_USBH1_DATA0), + IMX_PINCTRL_PIN(MX51_PAD_USBH1_DATA1), + IMX_PINCTRL_PIN(MX51_PAD_USBH1_DATA2), + IMX_PINCTRL_PIN(MX51_PAD_USBH1_DATA3), + IMX_PINCTRL_PIN(MX51_PAD_USBH1_DATA4), + IMX_PINCTRL_PIN(MX51_PAD_USBH1_DATA5), + IMX_PINCTRL_PIN(MX51_PAD_USBH1_DATA6), + IMX_PINCTRL_PIN(MX51_PAD_USBH1_DATA7), + IMX_PINCTRL_PIN(MX51_PAD_DI1_PIN11), + IMX_PINCTRL_PIN(MX51_PAD_DI1_PIN12), + IMX_PINCTRL_PIN(MX51_PAD_DI1_PIN13), + IMX_PINCTRL_PIN(MX51_PAD_DI1_D0_CS), + IMX_PINCTRL_PIN(MX51_PAD_DI1_D1_CS), + IMX_PINCTRL_PIN(MX51_PAD_DISPB2_SER_DIN), + IMX_PINCTRL_PIN(MX51_PAD_DISPB2_SER_DIO), + IMX_PINCTRL_PIN(MX51_PAD_DISPB2_SER_CLK), + IMX_PINCTRL_PIN(MX51_PAD_DISPB2_SER_RS), + IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT0), + IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT1), + IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT2), + IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT3), + IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT4), + IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT5), + IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT6), + IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT7), + IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT8), + IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT9), + IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT10), + IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT11), + IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT12), + IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT13), + IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT14), + IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT15), + IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT16), + IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT17), + IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT18), + IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT19), + IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT20), + IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT21), + IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT22), + IMX_PINCTRL_PIN(MX51_PAD_DISP1_DAT23), + IMX_PINCTRL_PIN(MX51_PAD_DI1_PIN3), + IMX_PINCTRL_PIN(MX51_PAD_DI1_PIN2), + IMX_PINCTRL_PIN(MX51_PAD_DI_GP2), + IMX_PINCTRL_PIN(MX51_PAD_DI_GP3), + IMX_PINCTRL_PIN(MX51_PAD_DI2_PIN4), + IMX_PINCTRL_PIN(MX51_PAD_DI2_PIN2), + IMX_PINCTRL_PIN(MX51_PAD_DI2_PIN3), + IMX_PINCTRL_PIN(MX51_PAD_DI2_DISP_CLK), + IMX_PINCTRL_PIN(MX51_PAD_DI_GP4), + IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT0), + IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT1), + IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT2), + IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT3), + IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT4), + IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT5), + IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT6), + IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT7), + IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT8), + IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT9), + IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT10), + IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT11), + IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT12), + IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT13), + IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT14), + IMX_PINCTRL_PIN(MX51_PAD_DISP2_DAT15), + IMX_PINCTRL_PIN(MX51_PAD_SD1_CMD), + IMX_PINCTRL_PIN(MX51_PAD_SD1_CLK), + IMX_PINCTRL_PIN(MX51_PAD_SD1_DATA0), + IMX_PINCTRL_PIN(MX51_PAD_EIM_DA0), + IMX_PINCTRL_PIN(MX51_PAD_EIM_DA1), + IMX_PINCTRL_PIN(MX51_PAD_EIM_DA2), + IMX_PINCTRL_PIN(MX51_PAD_EIM_DA3), + IMX_PINCTRL_PIN(MX51_PAD_SD1_DATA1), + IMX_PINCTRL_PIN(MX51_PAD_EIM_DA4), + IMX_PINCTRL_PIN(MX51_PAD_EIM_DA5), + IMX_PINCTRL_PIN(MX51_PAD_EIM_DA6), + IMX_PINCTRL_PIN(MX51_PAD_EIM_DA7), + IMX_PINCTRL_PIN(MX51_PAD_SD1_DATA2), + IMX_PINCTRL_PIN(MX51_PAD_EIM_DA10), + IMX_PINCTRL_PIN(MX51_PAD_EIM_DA11), + IMX_PINCTRL_PIN(MX51_PAD_EIM_DA8), + IMX_PINCTRL_PIN(MX51_PAD_EIM_DA9), + IMX_PINCTRL_PIN(MX51_PAD_SD1_DATA3), + IMX_PINCTRL_PIN(MX51_PAD_GPIO1_0), + IMX_PINCTRL_PIN(MX51_PAD_GPIO1_1), + IMX_PINCTRL_PIN(MX51_PAD_EIM_DA12), + IMX_PINCTRL_PIN(MX51_PAD_EIM_DA13), + IMX_PINCTRL_PIN(MX51_PAD_EIM_DA14), + IMX_PINCTRL_PIN(MX51_PAD_EIM_DA15), + IMX_PINCTRL_PIN(MX51_PAD_SD2_CMD), + IMX_PINCTRL_PIN(MX51_PAD_SD2_CLK), + IMX_PINCTRL_PIN(MX51_PAD_SD2_DATA0), + IMX_PINCTRL_PIN(MX51_PAD_SD2_DATA1), + IMX_PINCTRL_PIN(MX51_PAD_SD2_DATA2), + IMX_PINCTRL_PIN(MX51_PAD_SD2_DATA3), + IMX_PINCTRL_PIN(MX51_PAD_GPIO1_2), + IMX_PINCTRL_PIN(MX51_PAD_GPIO1_3), + IMX_PINCTRL_PIN(MX51_PAD_PMIC_INT_REQ), + IMX_PINCTRL_PIN(MX51_PAD_GPIO1_4), + IMX_PINCTRL_PIN(MX51_PAD_GPIO1_5), + IMX_PINCTRL_PIN(MX51_PAD_GPIO1_6), + IMX_PINCTRL_PIN(MX51_PAD_GPIO1_7), + IMX_PINCTRL_PIN(MX51_PAD_GPIO1_8), + IMX_PINCTRL_PIN(MX51_PAD_GPIO1_9), +}; + +static struct imx_pinctrl_soc_info imx51_pinctrl_info = { + .pins = imx51_pinctrl_pads, + .npins = ARRAY_SIZE(imx51_pinctrl_pads), + .pin_regs = imx51_pin_regs, + .npin_regs = ARRAY_SIZE(imx51_pin_regs), +}; + +static struct of_device_id imx51_pinctrl_of_match[] __devinitdata = { + { .compatible = "fsl,imx51-iomuxc", }, + { /* sentinel */ } +}; + +static int __devinit imx51_pinctrl_probe(struct platform_device *pdev) +{ + return imx_pinctrl_probe(pdev, &imx51_pinctrl_info); +} + +static struct platform_driver imx51_pinctrl_driver = { + .driver = { + .name = "imx51-pinctrl", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(imx51_pinctrl_of_match), + }, + .probe = imx51_pinctrl_probe, + .remove = __devexit_p(imx_pinctrl_remove), +}; + +static int __init imx51_pinctrl_init(void) +{ + return platform_driver_register(&imx51_pinctrl_driver); +} +arch_initcall(imx51_pinctrl_init); + +static void __exit imx51_pinctrl_exit(void) +{ + platform_driver_unregister(&imx51_pinctrl_driver); +} +module_exit(imx51_pinctrl_exit); +MODULE_AUTHOR("Dong Aisheng "); +MODULE_DESCRIPTION("Freescale IMX51 pinctrl driver"); +MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/pinctrl/pinctrl-imx53.c b/trunk/drivers/pinctrl/pinctrl-imx53.c new file mode 100644 index 000000000000..1f49e16a9bcd --- /dev/null +++ b/trunk/drivers/pinctrl/pinctrl-imx53.c @@ -0,0 +1,1649 @@ +/* + * imx53 pinctrl driver based on imx pinmux core + * + * Copyright (C) 2012 Freescale Semiconductor, Inc. + * Copyright (C) 2012 Linaro, Inc. + * + * Author: Dong Aisheng + * + * 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 "pinctrl-imx.h" + +enum imx53_pads { + MX53_PAD_GPIO_19 = 1, + MX53_PAD_KEY_COL0 = 2, + MX53_PAD_KEY_ROW0 = 3, + MX53_PAD_KEY_COL1 = 4, + MX53_PAD_KEY_ROW1 = 5, + MX53_PAD_KEY_COL2 = 6, + MX53_PAD_KEY_ROW2 = 7, + MX53_PAD_KEY_COL3 = 8, + MX53_PAD_KEY_ROW3 = 9, + MX53_PAD_KEY_COL4 = 10, + MX53_PAD_KEY_ROW4 = 11, + MX53_PAD_DI0_DISP_CLK = 12, + MX53_PAD_DI0_PIN15 = 13, + MX53_PAD_DI0_PIN2 = 14, + MX53_PAD_DI0_PIN3 = 15, + MX53_PAD_DI0_PIN4 = 16, + MX53_PAD_DISP0_DAT0 = 17, + MX53_PAD_DISP0_DAT1 = 18, + MX53_PAD_DISP0_DAT2 = 19, + MX53_PAD_DISP0_DAT3 = 20, + MX53_PAD_DISP0_DAT4 = 21, + MX53_PAD_DISP0_DAT5 = 22, + MX53_PAD_DISP0_DAT6 = 23, + MX53_PAD_DISP0_DAT7 = 24, + MX53_PAD_DISP0_DAT8 = 25, + MX53_PAD_DISP0_DAT9 = 26, + MX53_PAD_DISP0_DAT10 = 27, + MX53_PAD_DISP0_DAT11 = 28, + MX53_PAD_DISP0_DAT12 = 29, + MX53_PAD_DISP0_DAT13 = 30, + MX53_PAD_DISP0_DAT14 = 31, + MX53_PAD_DISP0_DAT15 = 32, + MX53_PAD_DISP0_DAT16 = 33, + MX53_PAD_DISP0_DAT17 = 34, + MX53_PAD_DISP0_DAT18 = 35, + MX53_PAD_DISP0_DAT19 = 36, + MX53_PAD_DISP0_DAT20 = 37, + MX53_PAD_DISP0_DAT21 = 38, + MX53_PAD_DISP0_DAT22 = 39, + MX53_PAD_DISP0_DAT23 = 40, + MX53_PAD_CSI0_PIXCLK = 41, + MX53_PAD_CSI0_MCLK = 42, + MX53_PAD_CSI0_DATA_EN = 43, + MX53_PAD_CSI0_VSYNC = 44, + MX53_PAD_CSI0_DAT4 = 45, + MX53_PAD_CSI0_DAT5 = 46, + MX53_PAD_CSI0_DAT6 = 47, + MX53_PAD_CSI0_DAT7 = 48, + MX53_PAD_CSI0_DAT8 = 49, + MX53_PAD_CSI0_DAT9 = 50, + MX53_PAD_CSI0_DAT10 = 51, + MX53_PAD_CSI0_DAT11 = 52, + MX53_PAD_CSI0_DAT12 = 53, + MX53_PAD_CSI0_DAT13 = 54, + MX53_PAD_CSI0_DAT14 = 55, + MX53_PAD_CSI0_DAT15 = 56, + MX53_PAD_CSI0_DAT16 = 57, + MX53_PAD_CSI0_DAT17 = 58, + MX53_PAD_CSI0_DAT18 = 59, + MX53_PAD_CSI0_DAT19 = 60, + MX53_PAD_EIM_A25 = 61, + MX53_PAD_EIM_EB2 = 62, + MX53_PAD_EIM_D16 = 63, + MX53_PAD_EIM_D17 = 64, + MX53_PAD_EIM_D18 = 65, + MX53_PAD_EIM_D19 = 66, + MX53_PAD_EIM_D20 = 67, + MX53_PAD_EIM_D21 = 68, + MX53_PAD_EIM_D22 = 69, + MX53_PAD_EIM_D23 = 70, + MX53_PAD_EIM_EB3 = 71, + MX53_PAD_EIM_D24 = 72, + MX53_PAD_EIM_D25 = 73, + MX53_PAD_EIM_D26 = 74, + MX53_PAD_EIM_D27 = 75, + MX53_PAD_EIM_D28 = 76, + MX53_PAD_EIM_D29 = 77, + MX53_PAD_EIM_D30 = 78, + MX53_PAD_EIM_D31 = 79, + MX53_PAD_EIM_A24 = 80, + MX53_PAD_EIM_A23 = 81, + MX53_PAD_EIM_A22 = 82, + MX53_PAD_EIM_A21 = 83, + MX53_PAD_EIM_A20 = 84, + MX53_PAD_EIM_A19 = 85, + MX53_PAD_EIM_A18 = 86, + MX53_PAD_EIM_A17 = 87, + MX53_PAD_EIM_A16 = 88, + MX53_PAD_EIM_CS0 = 89, + MX53_PAD_EIM_CS1 = 90, + MX53_PAD_EIM_OE = 91, + MX53_PAD_EIM_RW = 92, + MX53_PAD_EIM_LBA = 93, + MX53_PAD_EIM_EB0 = 94, + MX53_PAD_EIM_EB1 = 95, + MX53_PAD_EIM_DA0 = 96, + MX53_PAD_EIM_DA1 = 97, + MX53_PAD_EIM_DA2 = 98, + MX53_PAD_EIM_DA3 = 99, + MX53_PAD_EIM_DA4 = 100, + MX53_PAD_EIM_DA5 = 101, + MX53_PAD_EIM_DA6 = 102, + MX53_PAD_EIM_DA7 = 103, + MX53_PAD_EIM_DA8 = 104, + MX53_PAD_EIM_DA9 = 105, + MX53_PAD_EIM_DA10 = 106, + MX53_PAD_EIM_DA11 = 107, + MX53_PAD_EIM_DA12 = 108, + MX53_PAD_EIM_DA13 = 109, + MX53_PAD_EIM_DA14 = 110, + MX53_PAD_EIM_DA15 = 111, + MX53_PAD_NANDF_WE_B = 112, + MX53_PAD_NANDF_RE_B = 113, + MX53_PAD_EIM_WAIT = 114, + MX53_PAD_LVDS1_TX3_P = 115, + MX53_PAD_LVDS1_TX2_P = 116, + MX53_PAD_LVDS1_CLK_P = 117, + MX53_PAD_LVDS1_TX1_P = 118, + MX53_PAD_LVDS1_TX0_P = 119, + MX53_PAD_LVDS0_TX3_P = 120, + MX53_PAD_LVDS0_CLK_P = 121, + MX53_PAD_LVDS0_TX2_P = 122, + MX53_PAD_LVDS0_TX1_P = 123, + MX53_PAD_LVDS0_TX0_P = 124, + MX53_PAD_GPIO_10 = 125, + MX53_PAD_GPIO_11 = 126, + MX53_PAD_GPIO_12 = 127, + MX53_PAD_GPIO_13 = 128, + MX53_PAD_GPIO_14 = 129, + MX53_PAD_NANDF_CLE = 130, + MX53_PAD_NANDF_ALE = 131, + MX53_PAD_NANDF_WP_B = 132, + MX53_PAD_NANDF_RB0 = 133, + MX53_PAD_NANDF_CS0 = 134, + MX53_PAD_NANDF_CS1 = 135, + MX53_PAD_NANDF_CS2 = 136, + MX53_PAD_NANDF_CS3 = 137, + MX53_PAD_FEC_MDIO = 138, + MX53_PAD_FEC_REF_CLK = 139, + MX53_PAD_FEC_RX_ER = 140, + MX53_PAD_FEC_CRS_DV = 141, + MX53_PAD_FEC_RXD1 = 142, + MX53_PAD_FEC_RXD0 = 143, + MX53_PAD_FEC_TX_EN = 144, + MX53_PAD_FEC_TXD1 = 145, + MX53_PAD_FEC_TXD0 = 146, + MX53_PAD_FEC_MDC = 147, + MX53_PAD_PATA_DIOW = 148, + MX53_PAD_PATA_DMACK = 149, + MX53_PAD_PATA_DMARQ = 150, + MX53_PAD_PATA_BUFFER_EN = 151, + MX53_PAD_PATA_INTRQ = 152, + MX53_PAD_PATA_DIOR = 153, + MX53_PAD_PATA_RESET_B = 154, + MX53_PAD_PATA_IORDY = 155, + MX53_PAD_PATA_DA_0 = 156, + MX53_PAD_PATA_DA_1 = 157, + MX53_PAD_PATA_DA_2 = 158, + MX53_PAD_PATA_CS_0 = 159, + MX53_PAD_PATA_CS_1 = 160, + MX53_PAD_PATA_DATA0 = 161, + MX53_PAD_PATA_DATA1 = 162, + MX53_PAD_PATA_DATA2 = 163, + MX53_PAD_PATA_DATA3 = 164, + MX53_PAD_PATA_DATA4 = 165, + MX53_PAD_PATA_DATA5 = 166, + MX53_PAD_PATA_DATA6 = 167, + MX53_PAD_PATA_DATA7 = 168, + MX53_PAD_PATA_DATA8 = 169, + MX53_PAD_PATA_DATA9 = 170, + MX53_PAD_PATA_DATA10 = 171, + MX53_PAD_PATA_DATA11 = 172, + MX53_PAD_PATA_DATA12 = 173, + MX53_PAD_PATA_DATA13 = 174, + MX53_PAD_PATA_DATA14 = 175, + MX53_PAD_PATA_DATA15 = 176, + MX53_PAD_SD1_DATA0 = 177, + MX53_PAD_SD1_DATA1 = 178, + MX53_PAD_SD1_CMD = 179, + MX53_PAD_SD1_DATA2 = 180, + MX53_PAD_SD1_CLK = 181, + MX53_PAD_SD1_DATA3 = 182, + MX53_PAD_SD2_CLK = 183, + MX53_PAD_SD2_CMD = 184, + MX53_PAD_SD2_DATA3 = 185, + MX53_PAD_SD2_DATA2 = 186, + MX53_PAD_SD2_DATA1 = 187, + MX53_PAD_SD2_DATA0 = 188, + MX53_PAD_GPIO_0 = 189, + MX53_PAD_GPIO_1 = 190, + MX53_PAD_GPIO_9 = 191, + MX53_PAD_GPIO_3 = 192, + MX53_PAD_GPIO_6 = 193, + MX53_PAD_GPIO_2 = 194, + MX53_PAD_GPIO_4 = 195, + MX53_PAD_GPIO_5 = 196, + MX53_PAD_GPIO_7 = 197, + MX53_PAD_GPIO_8 = 198, + MX53_PAD_GPIO_16 = 199, + MX53_PAD_GPIO_17 = 200, + MX53_PAD_GPIO_18 = 201, +}; + +/* imx53 register maps */ +static struct imx_pin_reg imx53_pin_regs[] = { + IMX_PIN_REG(MX53_PAD_GPIO_19, 0x348, 0x020, 0, 0x840, 0), /* MX53_PAD_GPIO_19__KPP_COL_5 */ + IMX_PIN_REG(MX53_PAD_GPIO_19, 0x348, 0x020, 1, 0x000, 0), /* MX53_PAD_GPIO_19__GPIO4_5 */ + IMX_PIN_REG(MX53_PAD_GPIO_19, 0x348, 0x020, 2, 0x000, 0), /* MX53_PAD_GPIO_19__CCM_CLKO */ + IMX_PIN_REG(MX53_PAD_GPIO_19, 0x348, 0x020, 3, 0x000, 0), /* MX53_PAD_GPIO_19__SPDIF_OUT1 */ + IMX_PIN_REG(MX53_PAD_GPIO_19, 0x348, 0x020, 4, 0x000, 0), /* MX53_PAD_GPIO_19__RTC_CE_RTC_EXT_TRIG2 */ + IMX_PIN_REG(MX53_PAD_GPIO_19, 0x348, 0x020, 5, 0x000, 0), /* MX53_PAD_GPIO_19__ECSPI1_RDY */ + IMX_PIN_REG(MX53_PAD_GPIO_19, 0x348, 0x020, 6, 0x000, 0), /* MX53_PAD_GPIO_19__FEC_TDATA_3 */ + IMX_PIN_REG(MX53_PAD_GPIO_19, 0x348, 0x020, 7, 0x000, 0), /* MX53_PAD_GPIO_19__SRC_INT_BOOT */ + IMX_PIN_REG(MX53_PAD_KEY_COL0, 0x34C, 0x024, 0, 0x000, 0), /* MX53_PAD_KEY_COL0__KPP_COL_0 */ + IMX_PIN_REG(MX53_PAD_KEY_COL0, 0x34C, 0x024, 1, 0x000, 0), /* MX53_PAD_KEY_COL0__GPIO4_6 */ + IMX_PIN_REG(MX53_PAD_KEY_COL0, 0x34C, 0x024, 2, 0x758, 0), /* MX53_PAD_KEY_COL0__AUDMUX_AUD5_TXC */ + IMX_PIN_REG(MX53_PAD_KEY_COL0, 0x34C, 0x024, 4, 0x000, 0), /* MX53_PAD_KEY_COL0__UART4_TXD_MUX */ + IMX_PIN_REG(MX53_PAD_KEY_COL0, 0x34C, 0x024, 5, 0x79C, 0), /* MX53_PAD_KEY_COL0__ECSPI1_SCLK */ + IMX_PIN_REG(MX53_PAD_KEY_COL0, 0x34C, 0x024, 6, 0x000, 0), /* MX53_PAD_KEY_COL0__FEC_RDATA_3 */ + IMX_PIN_REG(MX53_PAD_KEY_COL0, 0x34C, 0x024, 7, 0x000, 0), /* MX53_PAD_KEY_COL0__SRC_ANY_PU_RST */ + IMX_PIN_REG(MX53_PAD_KEY_ROW0, 0x350, 0x028, 0, 0x000, 0), /* MX53_PAD_KEY_ROW0__KPP_ROW_0 */ + IMX_PIN_REG(MX53_PAD_KEY_ROW0, 0x350, 0x028, 1, 0x000, 0), /* MX53_PAD_KEY_ROW0__GPIO4_7 */ + IMX_PIN_REG(MX53_PAD_KEY_ROW0, 0x350, 0x028, 2, 0x74C, 0), /* MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD */ + IMX_PIN_REG(MX53_PAD_KEY_ROW0, 0x350, 0x028, 4, 0x890, 1), /* MX53_PAD_KEY_ROW0__UART4_RXD_MUX */ + IMX_PIN_REG(MX53_PAD_KEY_ROW0, 0x350, 0x028, 5, 0x7A4, 0), /* MX53_PAD_KEY_ROW0__ECSPI1_MOSI */ + IMX_PIN_REG(MX53_PAD_KEY_ROW0, 0x350, 0x028, 6, 0x000, 0), /* MX53_PAD_KEY_ROW0__FEC_TX_ER */ + IMX_PIN_REG(MX53_PAD_KEY_COL1, 0x354, 0x02C, 0, 0x000, 0), /* MX53_PAD_KEY_COL1__KPP_COL_1 */ + IMX_PIN_REG(MX53_PAD_KEY_COL1, 0x354, 0x02C, 1, 0x000, 0), /* MX53_PAD_KEY_COL1__GPIO4_8 */ + IMX_PIN_REG(MX53_PAD_KEY_COL1, 0x354, 0x02C, 2, 0x75C, 0), /* MX53_PAD_KEY_COL1__AUDMUX_AUD5_TXFS */ + IMX_PIN_REG(MX53_PAD_KEY_COL1, 0x354, 0x02C, 4, 0x000, 0), /* MX53_PAD_KEY_COL1__UART5_TXD_MUX */ + IMX_PIN_REG(MX53_PAD_KEY_COL1, 0x354, 0x02C, 5, 0x7A0, 0), /* MX53_PAD_KEY_COL1__ECSPI1_MISO */ + IMX_PIN_REG(MX53_PAD_KEY_COL1, 0x354, 0x02C, 6, 0x808, 0), /* MX53_PAD_KEY_COL1__FEC_RX_CLK */ + IMX_PIN_REG(MX53_PAD_KEY_COL1, 0x354, 0x02C, 7, 0x000, 0), /* MX53_PAD_KEY_COL1__USBPHY1_TXREADY */ + IMX_PIN_REG(MX53_PAD_KEY_ROW1, 0x358, 0x030, 0, 0x000, 0), /* MX53_PAD_KEY_ROW1__KPP_ROW_1 */ + IMX_PIN_REG(MX53_PAD_KEY_ROW1, 0x358, 0x030, 1, 0x000, 0), /* MX53_PAD_KEY_ROW1__GPIO4_9 */ + IMX_PIN_REG(MX53_PAD_KEY_ROW1, 0x358, 0x030, 2, 0x748, 0), /* MX53_PAD_KEY_ROW1__AUDMUX_AUD5_RXD */ + IMX_PIN_REG(MX53_PAD_KEY_ROW1, 0x358, 0x030, 4, 0x898, 1), /* MX53_PAD_KEY_ROW1__UART5_RXD_MUX */ + IMX_PIN_REG(MX53_PAD_KEY_ROW1, 0x358, 0x030, 5, 0x7A8, 0), /* MX53_PAD_KEY_ROW1__ECSPI1_SS0 */ + IMX_PIN_REG(MX53_PAD_KEY_ROW1, 0x358, 0x030, 6, 0x800, 0), /* MX53_PAD_KEY_ROW1__FEC_COL */ + IMX_PIN_REG(MX53_PAD_KEY_ROW1, 0x358, 0x030, 7, 0x000, 0), /* MX53_PAD_KEY_ROW1__USBPHY1_RXVALID */ + IMX_PIN_REG(MX53_PAD_KEY_COL2, 0x35C, 0x034, 0, 0x000, 0), /* MX53_PAD_KEY_COL2__KPP_COL_2 */ + IMX_PIN_REG(MX53_PAD_KEY_COL2, 0x35C, 0x034, 1, 0x000, 0), /* MX53_PAD_KEY_COL2__GPIO4_10 */ + IMX_PIN_REG(MX53_PAD_KEY_COL2, 0x35C, 0x034, 2, 0x000, 0), /* MX53_PAD_KEY_COL2__CAN1_TXCAN */ + IMX_PIN_REG(MX53_PAD_KEY_COL2, 0x35C, 0x034, 4, 0x804, 0), /* MX53_PAD_KEY_COL2__FEC_MDIO */ + IMX_PIN_REG(MX53_PAD_KEY_COL2, 0x35C, 0x034, 5, 0x7AC, 0), /* MX53_PAD_KEY_COL2__ECSPI1_SS1 */ + IMX_PIN_REG(MX53_PAD_KEY_COL2, 0x35C, 0x034, 6, 0x000, 0), /* MX53_PAD_KEY_COL2__FEC_RDATA_2 */ + IMX_PIN_REG(MX53_PAD_KEY_COL2, 0x35C, 0x034, 7, 0x000, 0), /* MX53_PAD_KEY_COL2__USBPHY1_RXACTIVE */ + IMX_PIN_REG(MX53_PAD_KEY_ROW2, 0x360, 0x038, 0, 0x000, 0), /* MX53_PAD_KEY_ROW2__KPP_ROW_2 */ + IMX_PIN_REG(MX53_PAD_KEY_ROW2, 0x360, 0x038, 1, 0x000, 0), /* MX53_PAD_KEY_ROW2__GPIO4_11 */ + IMX_PIN_REG(MX53_PAD_KEY_ROW2, 0x360, 0x038, 2, 0x760, 0), /* MX53_PAD_KEY_ROW2__CAN1_RXCAN */ + IMX_PIN_REG(MX53_PAD_KEY_ROW2, 0x360, 0x038, 4, 0x000, 0), /* MX53_PAD_KEY_ROW2__FEC_MDC */ + IMX_PIN_REG(MX53_PAD_KEY_ROW2, 0x360, 0x038, 5, 0x7B0, 0), /* MX53_PAD_KEY_ROW2__ECSPI1_SS2 */ + IMX_PIN_REG(MX53_PAD_KEY_ROW2, 0x360, 0x038, 6, 0x000, 0), /* MX53_PAD_KEY_ROW2__FEC_TDATA_2 */ + IMX_PIN_REG(MX53_PAD_KEY_ROW2, 0x360, 0x038, 7, 0x000, 0), /* MX53_PAD_KEY_ROW2__USBPHY1_RXERROR */ + IMX_PIN_REG(MX53_PAD_KEY_COL3, 0x364, 0x03C, 0, 0x000, 0), /* MX53_PAD_KEY_COL3__KPP_COL_3 */ + IMX_PIN_REG(MX53_PAD_KEY_COL3, 0x364, 0x03C, 1, 0x000, 0), /* MX53_PAD_KEY_COL3__GPIO4_12 */ + IMX_PIN_REG(MX53_PAD_KEY_COL3, 0x364, 0x03C, 2, 0x000, 0), /* MX53_PAD_KEY_COL3__USBOH3_H2_DP */ + IMX_PIN_REG(MX53_PAD_KEY_COL3, 0x364, 0x03C, 3, 0x870, 0), /* MX53_PAD_KEY_COL3__SPDIF_IN1 */ + IMX_PIN_REG(MX53_PAD_KEY_COL3, 0x364, 0x03C, 4, 0x81C, 0), /* MX53_PAD_KEY_COL3__I2C2_SCL */ + IMX_PIN_REG(MX53_PAD_KEY_COL3, 0x364, 0x03C, 5, 0x7B4, 0), /* MX53_PAD_KEY_COL3__ECSPI1_SS3 */ + IMX_PIN_REG(MX53_PAD_KEY_COL3, 0x364, 0x03C, 6, 0x000, 0), /* MX53_PAD_KEY_COL3__FEC_CRS */ + IMX_PIN_REG(MX53_PAD_KEY_COL3, 0x364, 0x03C, 7, 0x000, 0), /* MX53_PAD_KEY_COL3__USBPHY1_SIECLOCK */ + IMX_PIN_REG(MX53_PAD_KEY_ROW3, 0x368, 0x040, 0, 0x000, 0), /* MX53_PAD_KEY_ROW3__KPP_ROW_3 */ + IMX_PIN_REG(MX53_PAD_KEY_ROW3, 0x368, 0x040, 1, 0x000, 0), /* MX53_PAD_KEY_ROW3__GPIO4_13 */ + IMX_PIN_REG(MX53_PAD_KEY_ROW3, 0x368, 0x040, 2, 0x000, 0), /* MX53_PAD_KEY_ROW3__USBOH3_H2_DM */ + IMX_PIN_REG(MX53_PAD_KEY_ROW3, 0x368, 0x040, 3, 0x768, 0), /* MX53_PAD_KEY_ROW3__CCM_ASRC_EXT_CLK */ + IMX_PIN_REG(MX53_PAD_KEY_ROW3, 0x368, 0x040, 4, 0x820, 0), /* MX53_PAD_KEY_ROW3__I2C2_SDA */ + IMX_PIN_REG(MX53_PAD_KEY_ROW3, 0x368, 0x040, 5, 0x000, 0), /* MX53_PAD_KEY_ROW3__OSC32K_32K_OUT */ + IMX_PIN_REG(MX53_PAD_KEY_ROW3, 0x368, 0x040, 6, 0x77C, 0), /* MX53_PAD_KEY_ROW3__CCM_PLL4_BYP */ + IMX_PIN_REG(MX53_PAD_KEY_ROW3, 0x368, 0x040, 7, 0x000, 0), /* MX53_PAD_KEY_ROW3__USBPHY1_LINESTATE_0 */ + IMX_PIN_REG(MX53_PAD_KEY_COL4, 0x36C, 0x044, 0, 0x000, 0), /* MX53_PAD_KEY_COL4__KPP_COL_4 */ + IMX_PIN_REG(MX53_PAD_KEY_COL4, 0x36C, 0x044, 1, 0x000, 0), /* MX53_PAD_KEY_COL4__GPIO4_14 */ + IMX_PIN_REG(MX53_PAD_KEY_COL4, 0x36C, 0x044, 2, 0x000, 0), /* MX53_PAD_KEY_COL4__CAN2_TXCAN */ + IMX_PIN_REG(MX53_PAD_KEY_COL4, 0x36C, 0x044, 3, 0x000, 0), /* MX53_PAD_KEY_COL4__IPU_SISG_4 */ + IMX_PIN_REG(MX53_PAD_KEY_COL4, 0x36C, 0x044, 4, 0x894, 0), /* MX53_PAD_KEY_COL4__UART5_RTS */ + IMX_PIN_REG(MX53_PAD_KEY_COL4, 0x36C, 0x044, 5, 0x89C, 0), /* MX53_PAD_KEY_COL4__USBOH3_USBOTG_OC */ + IMX_PIN_REG(MX53_PAD_KEY_COL4, 0x36C, 0x044, 7, 0x000, 0), /* MX53_PAD_KEY_COL4__USBPHY1_LINESTATE_1 */ + IMX_PIN_REG(MX53_PAD_KEY_ROW4, 0x370, 0x048, 0, 0x000, 0), /* MX53_PAD_KEY_ROW4__KPP_ROW_4 */ + IMX_PIN_REG(MX53_PAD_KEY_ROW4, 0x370, 0x048, 1, 0x000, 0), /* MX53_PAD_KEY_ROW4__GPIO4_15 */ + IMX_PIN_REG(MX53_PAD_KEY_ROW4, 0x370, 0x048, 2, 0x764, 0), /* MX53_PAD_KEY_ROW4__CAN2_RXCAN */ + IMX_PIN_REG(MX53_PAD_KEY_ROW4, 0x370, 0x048, 3, 0x000, 0), /* MX53_PAD_KEY_ROW4__IPU_SISG_5 */ + IMX_PIN_REG(MX53_PAD_KEY_ROW4, 0x370, 0x048, 4, 0x000, 0), /* MX53_PAD_KEY_ROW4__UART5_CTS */ + IMX_PIN_REG(MX53_PAD_KEY_ROW4, 0x370, 0x048, 5, 0x000, 0), /* MX53_PAD_KEY_ROW4__USBOH3_USBOTG_PWR */ + IMX_PIN_REG(MX53_PAD_KEY_ROW4, 0x370, 0x048, 7, 0x000, 0), /* MX53_PAD_KEY_ROW4__USBPHY1_VBUSVALID */ + IMX_PIN_REG(MX53_PAD_DI0_DISP_CLK, 0x378, 0x04C, 0, 0x000, 0), /* MX53_PAD_DI0_DISP_CLK__IPU_DI0_DISP_CLK */ + IMX_PIN_REG(MX53_PAD_DI0_DISP_CLK, 0x378, 0x04C, 1, 0x000, 0), /* MX53_PAD_DI0_DISP_CLK__GPIO4_16 */ + IMX_PIN_REG(MX53_PAD_DI0_DISP_CLK, 0x378, 0x04C, 2, 0x000, 0), /* MX53_PAD_DI0_DISP_CLK__USBOH3_USBH2_DIR */ + IMX_PIN_REG(MX53_PAD_DI0_DISP_CLK, 0x378, 0x04C, 5, 0x000, 0), /* MX53_PAD_DI0_DISP_CLK__SDMA_DEBUG_CORE_STATE_0 */ + IMX_PIN_REG(MX53_PAD_DI0_DISP_CLK, 0x378, 0x04C, 6, 0x000, 0), /* MX53_PAD_DI0_DISP_CLK__EMI_EMI_DEBUG_0 */ + IMX_PIN_REG(MX53_PAD_DI0_DISP_CLK, 0x378, 0x04C, 7, 0x000, 0), /* MX53_PAD_DI0_DISP_CLK__USBPHY1_AVALID */ + IMX_PIN_REG(MX53_PAD_DI0_PIN15, 0x37C, 0x050, 0, 0x000, 0), /* MX53_PAD_DI0_PIN15__IPU_DI0_PIN15 */ + IMX_PIN_REG(MX53_PAD_DI0_PIN15, 0x37C, 0x050, 1, 0x000, 0), /* MX53_PAD_DI0_PIN15__GPIO4_17 */ + IMX_PIN_REG(MX53_PAD_DI0_PIN15, 0x37C, 0x050, 2, 0x000, 0), /* MX53_PAD_DI0_PIN15__AUDMUX_AUD6_TXC */ + IMX_PIN_REG(MX53_PAD_DI0_PIN15, 0x37C, 0x050, 5, 0x000, 0), /* MX53_PAD_DI0_PIN15__SDMA_DEBUG_CORE_STATE_1 */ + IMX_PIN_REG(MX53_PAD_DI0_PIN15, 0x37C, 0x050, 6, 0x000, 0), /* MX53_PAD_DI0_PIN15__EMI_EMI_DEBUG_1 */ + IMX_PIN_REG(MX53_PAD_DI0_PIN15, 0x37C, 0x050, 7, 0x000, 0), /* MX53_PAD_DI0_PIN15__USBPHY1_BVALID */ + IMX_PIN_REG(MX53_PAD_DI0_PIN2, 0x380, 0x054, 0, 0x000, 0), /* MX53_PAD_DI0_PIN2__IPU_DI0_PIN2 */ + IMX_PIN_REG(MX53_PAD_DI0_PIN2, 0x380, 0x054, 1, 0x000, 0), /* MX53_PAD_DI0_PIN2__GPIO4_18 */ + IMX_PIN_REG(MX53_PAD_DI0_PIN2, 0x380, 0x054, 2, 0x000, 0), /* MX53_PAD_DI0_PIN2__AUDMUX_AUD6_TXD */ + IMX_PIN_REG(MX53_PAD_DI0_PIN2, 0x380, 0x054, 5, 0x000, 0), /* MX53_PAD_DI0_PIN2__SDMA_DEBUG_CORE_STATE_2 */ + IMX_PIN_REG(MX53_PAD_DI0_PIN2, 0x380, 0x054, 6, 0x000, 0), /* MX53_PAD_DI0_PIN2__EMI_EMI_DEBUG_2 */ + IMX_PIN_REG(MX53_PAD_DI0_PIN2, 0x380, 0x054, 7, 0x000, 0), /* MX53_PAD_DI0_PIN2__USBPHY1_ENDSESSION */ + IMX_PIN_REG(MX53_PAD_DI0_PIN3, 0x384, 0x058, 0, 0x000, 0), /* MX53_PAD_DI0_PIN3__IPU_DI0_PIN3 */ + IMX_PIN_REG(MX53_PAD_DI0_PIN3, 0x384, 0x058, 1, 0x000, 0), /* MX53_PAD_DI0_PIN3__GPIO4_19 */ + IMX_PIN_REG(MX53_PAD_DI0_PIN3, 0x384, 0x058, 2, 0x000, 0), /* MX53_PAD_DI0_PIN3__AUDMUX_AUD6_TXFS */ + IMX_PIN_REG(MX53_PAD_DI0_PIN3, 0x384, 0x058, 5, 0x000, 0), /* MX53_PAD_DI0_PIN3__SDMA_DEBUG_CORE_STATE_3 */ + IMX_PIN_REG(MX53_PAD_DI0_PIN3, 0x384, 0x058, 6, 0x000, 0), /* MX53_PAD_DI0_PIN3__EMI_EMI_DEBUG_3 */ + IMX_PIN_REG(MX53_PAD_DI0_PIN3, 0x384, 0x058, 7, 0x000, 0), /* MX53_PAD_DI0_PIN3__USBPHY1_IDDIG */ + IMX_PIN_REG(MX53_PAD_DI0_PIN4, 0x388, 0x05C, 0, 0x000, 0), /* MX53_PAD_DI0_PIN4__IPU_DI0_PIN4 */ + IMX_PIN_REG(MX53_PAD_DI0_PIN4, 0x388, 0x05C, 1, 0x000, 0), /* MX53_PAD_DI0_PIN4__GPIO4_20 */ + IMX_PIN_REG(MX53_PAD_DI0_PIN4, 0x388, 0x05C, 2, 0x000, 0), /* MX53_PAD_DI0_PIN4__AUDMUX_AUD6_RXD */ + IMX_PIN_REG(MX53_PAD_DI0_PIN4, 0x388, 0x05C, 3, 0x7FC, 0), /* MX53_PAD_DI0_PIN4__ESDHC1_WP */ + IMX_PIN_REG(MX53_PAD_DI0_PIN4, 0x388, 0x05C, 5, 0x000, 0), /* MX53_PAD_DI0_PIN4__SDMA_DEBUG_YIELD */ + IMX_PIN_REG(MX53_PAD_DI0_PIN4, 0x388, 0x05C, 6, 0x000, 0), /* MX53_PAD_DI0_PIN4__EMI_EMI_DEBUG_4 */ + IMX_PIN_REG(MX53_PAD_DI0_PIN4, 0x388, 0x05C, 7, 0x000, 0), /* MX53_PAD_DI0_PIN4__USBPHY1_HOSTDISCONNECT */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT0, 0x38C, 0x060, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT0__IPU_DISP0_DAT_0 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT0, 0x38C, 0x060, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT0__GPIO4_21 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT0, 0x38C, 0x060, 2, 0x780, 0), /* MX53_PAD_DISP0_DAT0__CSPI_SCLK */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT0, 0x38C, 0x060, 3, 0x000, 0), /* MX53_PAD_DISP0_DAT0__USBOH3_USBH2_DATA_0 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT0, 0x38C, 0x060, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT0__SDMA_DEBUG_CORE_RUN */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT0, 0x38C, 0x060, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT0__EMI_EMI_DEBUG_5 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT0, 0x38C, 0x060, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT0__USBPHY2_TXREADY */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT1, 0x390, 0x064, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT1__IPU_DISP0_DAT_1 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT1, 0x390, 0x064, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT1__GPIO4_22 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT1, 0x390, 0x064, 2, 0x788, 0), /* MX53_PAD_DISP0_DAT1__CSPI_MOSI */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT1, 0x390, 0x064, 3, 0x000, 0), /* MX53_PAD_DISP0_DAT1__USBOH3_USBH2_DATA_1 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT1, 0x390, 0x064, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT1__SDMA_DEBUG_EVENT_CHANNEL_SEL */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT1, 0x390, 0x064, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT1__EMI_EMI_DEBUG_6 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT1, 0x390, 0x064, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT1__USBPHY2_RXVALID */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT2, 0x394, 0x068, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT2__IPU_DISP0_DAT_2 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT2, 0x394, 0x068, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT2__GPIO4_23 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT2, 0x394, 0x068, 2, 0x784, 0), /* MX53_PAD_DISP0_DAT2__CSPI_MISO */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT2, 0x394, 0x068, 3, 0x000, 0), /* MX53_PAD_DISP0_DAT2__USBOH3_USBH2_DATA_2 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT2, 0x394, 0x068, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT2__SDMA_DEBUG_MODE */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT2, 0x394, 0x068, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT2__EMI_EMI_DEBUG_7 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT2, 0x394, 0x068, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT2__USBPHY2_RXACTIVE */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT3, 0x398, 0x06C, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT3__IPU_DISP0_DAT_3 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT3, 0x398, 0x06C, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT3__GPIO4_24 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT3, 0x398, 0x06C, 2, 0x78C, 0), /* MX53_PAD_DISP0_DAT3__CSPI_SS0 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT3, 0x398, 0x06C, 3, 0x000, 0), /* MX53_PAD_DISP0_DAT3__USBOH3_USBH2_DATA_3 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT3, 0x398, 0x06C, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT3__SDMA_DEBUG_BUS_ERROR */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT3, 0x398, 0x06C, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT3__EMI_EMI_DEBUG_8 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT3, 0x398, 0x06C, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT3__USBPHY2_RXERROR */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT4, 0x39C, 0x070, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT4__IPU_DISP0_DAT_4 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT4, 0x39C, 0x070, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT4__GPIO4_25 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT4, 0x39C, 0x070, 2, 0x790, 0), /* MX53_PAD_DISP0_DAT4__CSPI_SS1 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT4, 0x39C, 0x070, 3, 0x000, 0), /* MX53_PAD_DISP0_DAT4__USBOH3_USBH2_DATA_4 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT4, 0x39C, 0x070, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT4__SDMA_DEBUG_BUS_RWB */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT4, 0x39C, 0x070, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT4__EMI_EMI_DEBUG_9 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT4, 0x39C, 0x070, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT4__USBPHY2_SIECLOCK */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT5, 0x3A0, 0x074, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT5__IPU_DISP0_DAT_5 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT5, 0x3A0, 0x074, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT5__GPIO4_26 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT5, 0x3A0, 0x074, 2, 0x794, 0), /* MX53_PAD_DISP0_DAT5__CSPI_SS2 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT5, 0x3A0, 0x074, 3, 0x000, 0), /* MX53_PAD_DISP0_DAT5__USBOH3_USBH2_DATA_5 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT5, 0x3A0, 0x074, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT5__SDMA_DEBUG_MATCHED_DMBUS */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT5, 0x3A0, 0x074, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT5__EMI_EMI_DEBUG_10 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT5, 0x3A0, 0x074, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT5__USBPHY2_LINESTATE_0 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT6, 0x3A4, 0x078, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT6__IPU_DISP0_DAT_6 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT6, 0x3A4, 0x078, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT6__GPIO4_27 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT6, 0x3A4, 0x078, 2, 0x798, 0), /* MX53_PAD_DISP0_DAT6__CSPI_SS3 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT6, 0x3A4, 0x078, 3, 0x000, 0), /* MX53_PAD_DISP0_DAT6__USBOH3_USBH2_DATA_6 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT6, 0x3A4, 0x078, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT6__SDMA_DEBUG_RTBUFFER_WRITE */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT6, 0x3A4, 0x078, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT6__EMI_EMI_DEBUG_11 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT6, 0x3A4, 0x078, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT6__USBPHY2_LINESTATE_1 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT7, 0x3A8, 0x07C, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT7__IPU_DISP0_DAT_7 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT7, 0x3A8, 0x07C, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT7__GPIO4_28 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT7, 0x3A8, 0x07C, 2, 0x000, 0), /* MX53_PAD_DISP0_DAT7__CSPI_RDY */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT7, 0x3A8, 0x07C, 3, 0x000, 0), /* MX53_PAD_DISP0_DAT7__USBOH3_USBH2_DATA_7 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT7, 0x3A8, 0x07C, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT7__SDMA_DEBUG_EVENT_CHANNEL_0 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT7, 0x3A8, 0x07C, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT7__EMI_EMI_DEBUG_12 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT7, 0x3A8, 0x07C, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT7__USBPHY2_VBUSVALID */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT8, 0x3AC, 0x080, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT8__IPU_DISP0_DAT_8 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT8, 0x3AC, 0x080, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT8__GPIO4_29 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT8, 0x3AC, 0x080, 2, 0x000, 0), /* MX53_PAD_DISP0_DAT8__PWM1_PWMO */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT8, 0x3AC, 0x080, 3, 0x000, 0), /* MX53_PAD_DISP0_DAT8__WDOG1_WDOG_B */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT8, 0x3AC, 0x080, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT8__SDMA_DEBUG_EVENT_CHANNEL_1 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT8, 0x3AC, 0x080, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT8__EMI_EMI_DEBUG_13 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT8, 0x3AC, 0x080, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT8__USBPHY2_AVALID */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT9, 0x3B0, 0x084, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT9__IPU_DISP0_DAT_9 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT9, 0x3B0, 0x084, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT9__GPIO4_30 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT9, 0x3B0, 0x084, 2, 0x000, 0), /* MX53_PAD_DISP0_DAT9__PWM2_PWMO */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT9, 0x3B0, 0x084, 3, 0x000, 0), /* MX53_PAD_DISP0_DAT9__WDOG2_WDOG_B */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT9, 0x3B0, 0x084, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT9__SDMA_DEBUG_EVENT_CHANNEL_2 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT9, 0x3B0, 0x084, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT9__EMI_EMI_DEBUG_14 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT9, 0x3B0, 0x084, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT9__USBPHY2_VSTATUS_0 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT10, 0x3B4, 0x088, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT10__IPU_DISP0_DAT_10 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT10, 0x3B4, 0x088, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT10__GPIO4_31 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT10, 0x3B4, 0x088, 2, 0x000, 0), /* MX53_PAD_DISP0_DAT10__USBOH3_USBH2_STP */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT10, 0x3B4, 0x088, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT10__SDMA_DEBUG_EVENT_CHANNEL_3 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT10, 0x3B4, 0x088, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT10__EMI_EMI_DEBUG_15 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT10, 0x3B4, 0x088, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT10__USBPHY2_VSTATUS_1 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT11, 0x3B8, 0x08C, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT11__IPU_DISP0_DAT_11 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT11, 0x3B8, 0x08C, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT11__GPIO5_5 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT11, 0x3B8, 0x08C, 2, 0x000, 0), /* MX53_PAD_DISP0_DAT11__USBOH3_USBH2_NXT */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT11, 0x3B8, 0x08C, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT11__SDMA_DEBUG_EVENT_CHANNEL_4 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT11, 0x3B8, 0x08C, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT11__EMI_EMI_DEBUG_16 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT11, 0x3B8, 0x08C, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT11__USBPHY2_VSTATUS_2 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT12, 0x3BC, 0x090, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT12__IPU_DISP0_DAT_12 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT12, 0x3BC, 0x090, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT12__GPIO5_6 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT12, 0x3BC, 0x090, 2, 0x000, 0), /* MX53_PAD_DISP0_DAT12__USBOH3_USBH2_CLK */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT12, 0x3BC, 0x090, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT12__SDMA_DEBUG_EVENT_CHANNEL_5 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT12, 0x3BC, 0x090, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT12__EMI_EMI_DEBUG_17 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT12, 0x3BC, 0x090, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT12__USBPHY2_VSTATUS_3 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT13, 0x3C0, 0x094, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT13__IPU_DISP0_DAT_13 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT13, 0x3C0, 0x094, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT13__GPIO5_7 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT13, 0x3C0, 0x094, 3, 0x754, 0), /* MX53_PAD_DISP0_DAT13__AUDMUX_AUD5_RXFS */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT13, 0x3C0, 0x094, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT13__SDMA_DEBUG_EVT_CHN_LINES_0 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT13, 0x3C0, 0x094, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT13__EMI_EMI_DEBUG_18 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT13, 0x3C0, 0x094, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT13__USBPHY2_VSTATUS_4 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT14, 0x3C4, 0x098, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT14__IPU_DISP0_DAT_14 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT14, 0x3C4, 0x098, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT14__GPIO5_8 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT14, 0x3C4, 0x098, 3, 0x750, 0), /* MX53_PAD_DISP0_DAT14__AUDMUX_AUD5_RXC */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT14, 0x3C4, 0x098, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT14__SDMA_DEBUG_EVT_CHN_LINES_1 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT14, 0x3C4, 0x098, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT14__EMI_EMI_DEBUG_19 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT14, 0x3C4, 0x098, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT14__USBPHY2_VSTATUS_5 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT15, 0x3C8, 0x09C, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT15__IPU_DISP0_DAT_15 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT15, 0x3C8, 0x09C, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT15__GPIO5_9 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT15, 0x3C8, 0x09C, 2, 0x7AC, 1), /* MX53_PAD_DISP0_DAT15__ECSPI1_SS1 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT15, 0x3C8, 0x09C, 3, 0x7C8, 0), /* MX53_PAD_DISP0_DAT15__ECSPI2_SS1 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT15, 0x3C8, 0x09C, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT15__SDMA_DEBUG_EVT_CHN_LINES_2 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT15, 0x3C8, 0x09C, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT15__EMI_EMI_DEBUG_20 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT15, 0x3C8, 0x09C, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT15__USBPHY2_VSTATUS_6 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT16, 0x3CC, 0x0A0, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT16__IPU_DISP0_DAT_16 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT16, 0x3CC, 0x0A0, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT16__GPIO5_10 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT16, 0x3CC, 0x0A0, 2, 0x7C0, 0), /* MX53_PAD_DISP0_DAT16__ECSPI2_MOSI */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT16, 0x3CC, 0x0A0, 3, 0x758, 1), /* MX53_PAD_DISP0_DAT16__AUDMUX_AUD5_TXC */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT16, 0x3CC, 0x0A0, 4, 0x868, 0), /* MX53_PAD_DISP0_DAT16__SDMA_EXT_EVENT_0 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT16, 0x3CC, 0x0A0, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT16__SDMA_DEBUG_EVT_CHN_LINES_3 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT16, 0x3CC, 0x0A0, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT16__EMI_EMI_DEBUG_21 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT16, 0x3CC, 0x0A0, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT16__USBPHY2_VSTATUS_7 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT17, 0x3D0, 0x0A4, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT17__IPU_DISP0_DAT_17 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT17, 0x3D0, 0x0A4, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT17__GPIO5_11 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT17, 0x3D0, 0x0A4, 2, 0x7BC, 0), /* MX53_PAD_DISP0_DAT17__ECSPI2_MISO */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT17, 0x3D0, 0x0A4, 3, 0x74C, 1), /* MX53_PAD_DISP0_DAT17__AUDMUX_AUD5_TXD */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT17, 0x3D0, 0x0A4, 4, 0x86C, 0), /* MX53_PAD_DISP0_DAT17__SDMA_EXT_EVENT_1 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT17, 0x3D0, 0x0A4, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT17__SDMA_DEBUG_EVT_CHN_LINES_4 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT17, 0x3D0, 0x0A4, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT17__EMI_EMI_DEBUG_22 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT18, 0x3D4, 0x0A8, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT18__IPU_DISP0_DAT_18 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT18, 0x3D4, 0x0A8, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT18__GPIO5_12 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT18, 0x3D4, 0x0A8, 2, 0x7C4, 0), /* MX53_PAD_DISP0_DAT18__ECSPI2_SS0 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT18, 0x3D4, 0x0A8, 3, 0x75C, 1), /* MX53_PAD_DISP0_DAT18__AUDMUX_AUD5_TXFS */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT18, 0x3D4, 0x0A8, 4, 0x73C, 0), /* MX53_PAD_DISP0_DAT18__AUDMUX_AUD4_RXFS */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT18, 0x3D4, 0x0A8, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT18__SDMA_DEBUG_EVT_CHN_LINES_5 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT18, 0x3D4, 0x0A8, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT18__EMI_EMI_DEBUG_23 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT18, 0x3D4, 0x0A8, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT18__EMI_WEIM_CS_2 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT19, 0x3D8, 0x0AC, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT19__IPU_DISP0_DAT_19 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT19, 0x3D8, 0x0AC, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT19__GPIO5_13 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT19, 0x3D8, 0x0AC, 2, 0x7B8, 0), /* MX53_PAD_DISP0_DAT19__ECSPI2_SCLK */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT19, 0x3D8, 0x0AC, 3, 0x748, 1), /* MX53_PAD_DISP0_DAT19__AUDMUX_AUD5_RXD */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT19, 0x3D8, 0x0AC, 4, 0x738, 0), /* MX53_PAD_DISP0_DAT19__AUDMUX_AUD4_RXC */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT19, 0x3D8, 0x0AC, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT19__SDMA_DEBUG_EVT_CHN_LINES_6 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT19, 0x3D8, 0x0AC, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT19__EMI_EMI_DEBUG_24 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT19, 0x3D8, 0x0AC, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT19__EMI_WEIM_CS_3 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT20, 0x3DC, 0x0B0, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT20__IPU_DISP0_DAT_20 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT20, 0x3DC, 0x0B0, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT20__GPIO5_14 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT20, 0x3DC, 0x0B0, 2, 0x79C, 1), /* MX53_PAD_DISP0_DAT20__ECSPI1_SCLK */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT20, 0x3DC, 0x0B0, 3, 0x740, 0), /* MX53_PAD_DISP0_DAT20__AUDMUX_AUD4_TXC */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT20, 0x3DC, 0x0B0, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT20__SDMA_DEBUG_EVT_CHN_LINES_7 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT20, 0x3DC, 0x0B0, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT20__EMI_EMI_DEBUG_25 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT20, 0x3DC, 0x0B0, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT20__SATA_PHY_TDI */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT21, 0x3E0, 0x0B4, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT21__IPU_DISP0_DAT_21 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT21, 0x3E0, 0x0B4, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT21__GPIO5_15 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT21, 0x3E0, 0x0B4, 2, 0x7A4, 1), /* MX53_PAD_DISP0_DAT21__ECSPI1_MOSI */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT21, 0x3E0, 0x0B4, 3, 0x734, 0), /* MX53_PAD_DISP0_DAT21__AUDMUX_AUD4_TXD */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT21, 0x3E0, 0x0B4, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT21__SDMA_DEBUG_BUS_DEVICE_0 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT21, 0x3E0, 0x0B4, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT21__EMI_EMI_DEBUG_26 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT21, 0x3E0, 0x0B4, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT21__SATA_PHY_TDO */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT22, 0x3E4, 0x0B8, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT22__IPU_DISP0_DAT_22 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT22, 0x3E4, 0x0B8, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT22__GPIO5_16 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT22, 0x3E4, 0x0B8, 2, 0x7A0, 1), /* MX53_PAD_DISP0_DAT22__ECSPI1_MISO */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT22, 0x3E4, 0x0B8, 3, 0x744, 0), /* MX53_PAD_DISP0_DAT22__AUDMUX_AUD4_TXFS */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT22, 0x3E4, 0x0B8, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT22__SDMA_DEBUG_BUS_DEVICE_1 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT22, 0x3E4, 0x0B8, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT22__EMI_EMI_DEBUG_27 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT22, 0x3E4, 0x0B8, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT22__SATA_PHY_TCK */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT23, 0x3E8, 0x0BC, 0, 0x000, 0), /* MX53_PAD_DISP0_DAT23__IPU_DISP0_DAT_23 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT23, 0x3E8, 0x0BC, 1, 0x000, 0), /* MX53_PAD_DISP0_DAT23__GPIO5_17 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT23, 0x3E8, 0x0BC, 2, 0x7A8, 1), /* MX53_PAD_DISP0_DAT23__ECSPI1_SS0 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT23, 0x3E8, 0x0BC, 3, 0x730, 0), /* MX53_PAD_DISP0_DAT23__AUDMUX_AUD4_RXD */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT23, 0x3E8, 0x0BC, 5, 0x000, 0), /* MX53_PAD_DISP0_DAT23__SDMA_DEBUG_BUS_DEVICE_2 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT23, 0x3E8, 0x0BC, 6, 0x000, 0), /* MX53_PAD_DISP0_DAT23__EMI_EMI_DEBUG_28 */ + IMX_PIN_REG(MX53_PAD_DISP0_DAT23, 0x3E8, 0x0BC, 7, 0x000, 0), /* MX53_PAD_DISP0_DAT23__SATA_PHY_TMS */ + IMX_PIN_REG(MX53_PAD_CSI0_PIXCLK, 0x3EC, 0x0C0, 0, 0x000, 0), /* MX53_PAD_CSI0_PIXCLK__IPU_CSI0_PIXCLK */ + IMX_PIN_REG(MX53_PAD_CSI0_PIXCLK, 0x3EC, 0x0C0, 1, 0x000, 0), /* MX53_PAD_CSI0_PIXCLK__GPIO5_18 */ + IMX_PIN_REG(MX53_PAD_CSI0_PIXCLK, 0x3EC, 0x0C0, 5, 0x000, 0), /* MX53_PAD_CSI0_PIXCLK__SDMA_DEBUG_PC_0 */ + IMX_PIN_REG(MX53_PAD_CSI0_PIXCLK, 0x3EC, 0x0C0, 6, 0x000, 0), /* MX53_PAD_CSI0_PIXCLK__EMI_EMI_DEBUG_29 */ + IMX_PIN_REG(MX53_PAD_CSI0_MCLK, 0x3F0, 0x0C4, 0, 0x000, 0), /* MX53_PAD_CSI0_MCLK__IPU_CSI0_HSYNC */ + IMX_PIN_REG(MX53_PAD_CSI0_MCLK, 0x3F0, 0x0C4, 1, 0x000, 0), /* MX53_PAD_CSI0_MCLK__GPIO5_19 */ + IMX_PIN_REG(MX53_PAD_CSI0_MCLK, 0x3F0, 0x0C4, 2, 0x000, 0), /* MX53_PAD_CSI0_MCLK__CCM_CSI0_MCLK */ + IMX_PIN_REG(MX53_PAD_CSI0_MCLK, 0x3F0, 0x0C4, 5, 0x000, 0), /* MX53_PAD_CSI0_MCLK__SDMA_DEBUG_PC_1 */ + IMX_PIN_REG(MX53_PAD_CSI0_MCLK, 0x3F0, 0x0C4, 6, 0x000, 0), /* MX53_PAD_CSI0_MCLK__EMI_EMI_DEBUG_30 */ + IMX_PIN_REG(MX53_PAD_CSI0_MCLK, 0x3F0, 0x0C4, 7, 0x000, 0), /* MX53_PAD_CSI0_MCLK__TPIU_TRCTL */ + IMX_PIN_REG(MX53_PAD_CSI0_DATA_EN, 0x3F4, 0x0C8, 0, 0x000, 0), /* MX53_PAD_CSI0_DATA_EN__IPU_CSI0_DATA_EN */ + IMX_PIN_REG(MX53_PAD_CSI0_DATA_EN, 0x3F4, 0x0C8, 1, 0x000, 0), /* MX53_PAD_CSI0_DATA_EN__GPIO5_20 */ + IMX_PIN_REG(MX53_PAD_CSI0_DATA_EN, 0x3F4, 0x0C8, 5, 0x000, 0), /* MX53_PAD_CSI0_DATA_EN__SDMA_DEBUG_PC_2 */ + IMX_PIN_REG(MX53_PAD_CSI0_DATA_EN, 0x3F4, 0x0C8, 6, 0x000, 0), /* MX53_PAD_CSI0_DATA_EN__EMI_EMI_DEBUG_31 */ + IMX_PIN_REG(MX53_PAD_CSI0_DATA_EN, 0x3F4, 0x0C8, 7, 0x000, 0), /* MX53_PAD_CSI0_DATA_EN__TPIU_TRCLK */ + IMX_PIN_REG(MX53_PAD_CSI0_VSYNC, 0x3F8, 0x0CC, 0, 0x000, 0), /* MX53_PAD_CSI0_VSYNC__IPU_CSI0_VSYNC */ + IMX_PIN_REG(MX53_PAD_CSI0_VSYNC, 0x3F8, 0x0CC, 1, 0x000, 0), /* MX53_PAD_CSI0_VSYNC__GPIO5_21 */ + IMX_PIN_REG(MX53_PAD_CSI0_VSYNC, 0x3F8, 0x0CC, 5, 0x000, 0), /* MX53_PAD_CSI0_VSYNC__SDMA_DEBUG_PC_3 */ + IMX_PIN_REG(MX53_PAD_CSI0_VSYNC, 0x3F8, 0x0CC, 6, 0x000, 0), /* MX53_PAD_CSI0_VSYNC__EMI_EMI_DEBUG_32 */ + IMX_PIN_REG(MX53_PAD_CSI0_VSYNC, 0x3F8, 0x0CC, 7, 0x000, 0), /* MX53_PAD_CSI0_VSYNC__TPIU_TRACE_0 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT4, 0x3FC, 0x0D0, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT4__IPU_CSI0_D_4 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT4, 0x3FC, 0x0D0, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT4__GPIO5_22 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT4, 0x3FC, 0x0D0, 2, 0x840, 1), /* MX53_PAD_CSI0_DAT4__KPP_COL_5 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT4, 0x3FC, 0x0D0, 3, 0x79C, 2), /* MX53_PAD_CSI0_DAT4__ECSPI1_SCLK */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT4, 0x3FC, 0x0D0, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT4__USBOH3_USBH3_STP */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT4, 0x3FC, 0x0D0, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT4__AUDMUX_AUD3_TXC */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT4, 0x3FC, 0x0D0, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT4__EMI_EMI_DEBUG_33 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT4, 0x3FC, 0x0D0, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT4__TPIU_TRACE_1 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT5, 0x400, 0x0D4, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT5__IPU_CSI0_D_5 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT5, 0x400, 0x0D4, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT5__GPIO5_23 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT5, 0x400, 0x0D4, 2, 0x84C, 0), /* MX53_PAD_CSI0_DAT5__KPP_ROW_5 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT5, 0x400, 0x0D4, 3, 0x7A4, 2), /* MX53_PAD_CSI0_DAT5__ECSPI1_MOSI */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT5, 0x400, 0x0D4, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT5__USBOH3_USBH3_NXT */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT5, 0x400, 0x0D4, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT5__AUDMUX_AUD3_TXD */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT5, 0x400, 0x0D4, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT5__EMI_EMI_DEBUG_34 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT5, 0x400, 0x0D4, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT5__TPIU_TRACE_2 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT6, 0x404, 0x0D8, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT6__IPU_CSI0_D_6 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT6, 0x404, 0x0D8, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT6__GPIO5_24 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT6, 0x404, 0x0D8, 2, 0x844, 0), /* MX53_PAD_CSI0_DAT6__KPP_COL_6 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT6, 0x404, 0x0D8, 3, 0x7A0, 2), /* MX53_PAD_CSI0_DAT6__ECSPI1_MISO */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT6, 0x404, 0x0D8, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT6__USBOH3_USBH3_CLK */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT6, 0x404, 0x0D8, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT6__AUDMUX_AUD3_TXFS */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT6, 0x404, 0x0D8, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT6__EMI_EMI_DEBUG_35 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT6, 0x404, 0x0D8, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT6__TPIU_TRACE_3 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT7, 0x408, 0x0DC, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT7__IPU_CSI0_D_7 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT7, 0x408, 0x0DC, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT7__GPIO5_25 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT7, 0x408, 0x0DC, 2, 0x850, 0), /* MX53_PAD_CSI0_DAT7__KPP_ROW_6 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT7, 0x408, 0x0DC, 3, 0x7A8, 2), /* MX53_PAD_CSI0_DAT7__ECSPI1_SS0 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT7, 0x408, 0x0DC, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT7__USBOH3_USBH3_DIR */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT7, 0x408, 0x0DC, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT7__AUDMUX_AUD3_RXD */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT7, 0x408, 0x0DC, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT7__EMI_EMI_DEBUG_36 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT7, 0x408, 0x0DC, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT7__TPIU_TRACE_4 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT8, 0x40C, 0x0E0, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT8__IPU_CSI0_D_8 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT8, 0x40C, 0x0E0, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT8__GPIO5_26 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT8, 0x40C, 0x0E0, 2, 0x848, 0), /* MX53_PAD_CSI0_DAT8__KPP_COL_7 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT8, 0x40C, 0x0E0, 3, 0x7B8, 1), /* MX53_PAD_CSI0_DAT8__ECSPI2_SCLK */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT8, 0x40C, 0x0E0, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT8__USBOH3_USBH3_OC */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT8, 0x40C, 0x0E0, 5, 0x818, 0), /* MX53_PAD_CSI0_DAT8__I2C1_SDA */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT8, 0x40C, 0x0E0, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT8__EMI_EMI_DEBUG_37 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT8, 0x40C, 0x0E0, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT8__TPIU_TRACE_5 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT9, 0x410, 0x0E4, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT9__IPU_CSI0_D_9 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT9, 0x410, 0x0E4, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT9__GPIO5_27 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT9, 0x410, 0x0E4, 2, 0x854, 0), /* MX53_PAD_CSI0_DAT9__KPP_ROW_7 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT9, 0x410, 0x0E4, 3, 0x7C0, 1), /* MX53_PAD_CSI0_DAT9__ECSPI2_MOSI */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT9, 0x410, 0x0E4, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT9__USBOH3_USBH3_PWR */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT9, 0x410, 0x0E4, 5, 0x814, 0), /* MX53_PAD_CSI0_DAT9__I2C1_SCL */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT9, 0x410, 0x0E4, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT9__EMI_EMI_DEBUG_38 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT9, 0x410, 0x0E4, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT9__TPIU_TRACE_6 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT10, 0x414, 0x0E8, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT10__IPU_CSI0_D_10 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT10, 0x414, 0x0E8, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT10__GPIO5_28 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT10, 0x414, 0x0E8, 2, 0x000, 0), /* MX53_PAD_CSI0_DAT10__UART1_TXD_MUX */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT10, 0x414, 0x0E8, 3, 0x7BC, 1), /* MX53_PAD_CSI0_DAT10__ECSPI2_MISO */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT10, 0x414, 0x0E8, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT10__AUDMUX_AUD3_RXC */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT10, 0x414, 0x0E8, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT10__SDMA_DEBUG_PC_4 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT10, 0x414, 0x0E8, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT10__EMI_EMI_DEBUG_39 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT10, 0x414, 0x0E8, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT10__TPIU_TRACE_7 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT11, 0x418, 0x0EC, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT11__IPU_CSI0_D_11 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT11, 0x418, 0x0EC, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT11__GPIO5_29 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT11, 0x418, 0x0EC, 2, 0x878, 1), /* MX53_PAD_CSI0_DAT11__UART1_RXD_MUX */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT11, 0x418, 0x0EC, 3, 0x7C4, 1), /* MX53_PAD_CSI0_DAT11__ECSPI2_SS0 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT11, 0x418, 0x0EC, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT11__AUDMUX_AUD3_RXFS */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT11, 0x418, 0x0EC, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT11__SDMA_DEBUG_PC_5 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT11, 0x418, 0x0EC, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT11__EMI_EMI_DEBUG_40 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT11, 0x418, 0x0EC, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT11__TPIU_TRACE_8 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT12, 0x41C, 0x0F0, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT12__IPU_CSI0_D_12 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT12, 0x41C, 0x0F0, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT12__GPIO5_30 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT12, 0x41C, 0x0F0, 2, 0x000, 0), /* MX53_PAD_CSI0_DAT12__UART4_TXD_MUX */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT12, 0x41C, 0x0F0, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT12__USBOH3_USBH3_DATA_0 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT12, 0x41C, 0x0F0, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT12__SDMA_DEBUG_PC_6 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT12, 0x41C, 0x0F0, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT12__EMI_EMI_DEBUG_41 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT12, 0x41C, 0x0F0, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT12__TPIU_TRACE_9 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT13, 0x420, 0x0F4, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT13__IPU_CSI0_D_13 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT13, 0x420, 0x0F4, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT13__GPIO5_31 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT13, 0x420, 0x0F4, 2, 0x890, 3), /* MX53_PAD_CSI0_DAT13__UART4_RXD_MUX */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT13, 0x420, 0x0F4, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT13__USBOH3_USBH3_DATA_1 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT13, 0x420, 0x0F4, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT13__SDMA_DEBUG_PC_7 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT13, 0x420, 0x0F4, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT13__EMI_EMI_DEBUG_42 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT13, 0x420, 0x0F4, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT13__TPIU_TRACE_10 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT14, 0x424, 0x0F8, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT14__IPU_CSI0_D_14 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT14, 0x424, 0x0F8, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT14__GPIO6_0 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT14, 0x424, 0x0F8, 2, 0x000, 0), /* MX53_PAD_CSI0_DAT14__UART5_TXD_MUX */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT14, 0x424, 0x0F8, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT14__USBOH3_USBH3_DATA_2 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT14, 0x424, 0x0F8, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT14__SDMA_DEBUG_PC_8 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT14, 0x424, 0x0F8, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT14__EMI_EMI_DEBUG_43 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT14, 0x424, 0x0F8, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT14__TPIU_TRACE_11 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT15, 0x428, 0x0FC, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT15__IPU_CSI0_D_15 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT15, 0x428, 0x0FC, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT15__GPIO6_1 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT15, 0x428, 0x0FC, 2, 0x898, 3), /* MX53_PAD_CSI0_DAT15__UART5_RXD_MUX */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT15, 0x428, 0x0FC, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT15__USBOH3_USBH3_DATA_3 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT15, 0x428, 0x0FC, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT15__SDMA_DEBUG_PC_9 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT15, 0x428, 0x0FC, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT15__EMI_EMI_DEBUG_44 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT15, 0x428, 0x0FC, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT15__TPIU_TRACE_12 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT16, 0x42C, 0x100, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT16__IPU_CSI0_D_16 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT16, 0x42C, 0x100, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT16__GPIO6_2 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT16, 0x42C, 0x100, 2, 0x88C, 0), /* MX53_PAD_CSI0_DAT16__UART4_RTS */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT16, 0x42C, 0x100, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT16__USBOH3_USBH3_DATA_4 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT16, 0x42C, 0x100, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT16__SDMA_DEBUG_PC_10 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT16, 0x42C, 0x100, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT16__EMI_EMI_DEBUG_45 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT16, 0x42C, 0x100, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT16__TPIU_TRACE_13 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT17, 0x430, 0x104, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT17__IPU_CSI0_D_17 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT17, 0x430, 0x104, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT17__GPIO6_3 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT17, 0x430, 0x104, 2, 0x000, 0), /* MX53_PAD_CSI0_DAT17__UART4_CTS */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT17, 0x430, 0x104, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT17__USBOH3_USBH3_DATA_5 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT17, 0x430, 0x104, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT17__SDMA_DEBUG_PC_11 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT17, 0x430, 0x104, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT17__EMI_EMI_DEBUG_46 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT17, 0x430, 0x104, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT17__TPIU_TRACE_14 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT18, 0x434, 0x108, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT18__IPU_CSI0_D_18 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT18, 0x434, 0x108, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT18__GPIO6_4 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT18, 0x434, 0x108, 2, 0x894, 2), /* MX53_PAD_CSI0_DAT18__UART5_RTS */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT18, 0x434, 0x108, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT18__USBOH3_USBH3_DATA_6 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT18, 0x434, 0x108, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT18__SDMA_DEBUG_PC_12 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT18, 0x434, 0x108, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT18__EMI_EMI_DEBUG_47 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT18, 0x434, 0x108, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT18__TPIU_TRACE_15 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT19, 0x438, 0x10C, 0, 0x000, 0), /* MX53_PAD_CSI0_DAT19__IPU_CSI0_D_19 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT19, 0x438, 0x10C, 1, 0x000, 0), /* MX53_PAD_CSI0_DAT19__GPIO6_5 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT19, 0x438, 0x10C, 2, 0x000, 0), /* MX53_PAD_CSI0_DAT19__UART5_CTS */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT19, 0x438, 0x10C, 4, 0x000, 0), /* MX53_PAD_CSI0_DAT19__USBOH3_USBH3_DATA_7 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT19, 0x438, 0x10C, 5, 0x000, 0), /* MX53_PAD_CSI0_DAT19__SDMA_DEBUG_PC_13 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT19, 0x438, 0x10C, 6, 0x000, 0), /* MX53_PAD_CSI0_DAT19__EMI_EMI_DEBUG_48 */ + IMX_PIN_REG(MX53_PAD_CSI0_DAT19, 0x438, 0x10C, 7, 0x000, 0), /* MX53_PAD_CSI0_DAT19__USBPHY2_BISTOK */ + IMX_PIN_REG(MX53_PAD_EIM_A25, 0x458, 0x110, 0, 0x000, 0), /* MX53_PAD_EIM_A25__EMI_WEIM_A_25 */ + IMX_PIN_REG(MX53_PAD_EIM_A25, 0x458, 0x110, 1, 0x000, 0), /* MX53_PAD_EIM_A25__GPIO5_2 */ + IMX_PIN_REG(MX53_PAD_EIM_A25, 0x458, 0x110, 2, 0x000, 0), /* MX53_PAD_EIM_A25__ECSPI2_RDY */ + IMX_PIN_REG(MX53_PAD_EIM_A25, 0x458, 0x110, 3, 0x000, 0), /* MX53_PAD_EIM_A25__IPU_DI1_PIN12 */ + IMX_PIN_REG(MX53_PAD_EIM_A25, 0x458, 0x110, 4, 0x790, 1), /* MX53_PAD_EIM_A25__CSPI_SS1 */ + IMX_PIN_REG(MX53_PAD_EIM_A25, 0x458, 0x110, 6, 0x000, 0), /* MX53_PAD_EIM_A25__IPU_DI0_D1_CS */ + IMX_PIN_REG(MX53_PAD_EIM_A25, 0x458, 0x110, 7, 0x000, 0), /* MX53_PAD_EIM_A25__USBPHY1_BISTOK */ + IMX_PIN_REG(MX53_PAD_EIM_EB2, 0x45C, 0x114, 0, 0x000, 0), /* MX53_PAD_EIM_EB2__EMI_WEIM_EB_2 */ + IMX_PIN_REG(MX53_PAD_EIM_EB2, 0x45C, 0x114, 1, 0x000, 0), /* MX53_PAD_EIM_EB2__GPIO2_30 */ + IMX_PIN_REG(MX53_PAD_EIM_EB2, 0x45C, 0x114, 2, 0x76C, 0), /* MX53_PAD_EIM_EB2__CCM_DI1_EXT_CLK */ + IMX_PIN_REG(MX53_PAD_EIM_EB2, 0x45C, 0x114, 3, 0x000, 0), /* MX53_PAD_EIM_EB2__IPU_SER_DISP1_CS */ + IMX_PIN_REG(MX53_PAD_EIM_EB2, 0x45C, 0x114, 4, 0x7A8, 3), /* MX53_PAD_EIM_EB2__ECSPI1_SS0 */ + IMX_PIN_REG(MX53_PAD_EIM_EB2, 0x45C, 0x114, 5, 0x81C, 1), /* MX53_PAD_EIM_EB2__I2C2_SCL */ + IMX_PIN_REG(MX53_PAD_EIM_D16, 0x460, 0x118, 0, 0x000, 0), /* MX53_PAD_EIM_D16__EMI_WEIM_D_16 */ + IMX_PIN_REG(MX53_PAD_EIM_D16, 0x460, 0x118, 1, 0x000, 0), /* MX53_PAD_EIM_D16__GPIO3_16 */ + IMX_PIN_REG(MX53_PAD_EIM_D16, 0x460, 0x118, 2, 0x000, 0), /* MX53_PAD_EIM_D16__IPU_DI0_PIN5 */ + IMX_PIN_REG(MX53_PAD_EIM_D16, 0x460, 0x118, 3, 0x000, 0), /* MX53_PAD_EIM_D16__IPU_DISPB1_SER_CLK */ + IMX_PIN_REG(MX53_PAD_EIM_D16, 0x460, 0x118, 4, 0x79C, 3), /* MX53_PAD_EIM_D16__ECSPI1_SCLK */ + IMX_PIN_REG(MX53_PAD_EIM_D16, 0x460, 0x118, 5, 0x820, 1), /* MX53_PAD_EIM_D16__I2C2_SDA */ + IMX_PIN_REG(MX53_PAD_EIM_D17, 0x464, 0x11C, 0, 0x000, 0), /* MX53_PAD_EIM_D17__EMI_WEIM_D_17 */ + IMX_PIN_REG(MX53_PAD_EIM_D17, 0x464, 0x11C, 1, 0x000, 0), /* MX53_PAD_EIM_D17__GPIO3_17 */ + IMX_PIN_REG(MX53_PAD_EIM_D17, 0x464, 0x11C, 2, 0x000, 0), /* MX53_PAD_EIM_D17__IPU_DI0_PIN6 */ + IMX_PIN_REG(MX53_PAD_EIM_D17, 0x464, 0x11C, 3, 0x830, 0), /* MX53_PAD_EIM_D17__IPU_DISPB1_SER_DIN */ + IMX_PIN_REG(MX53_PAD_EIM_D17, 0x464, 0x11C, 4, 0x7A0, 3), /* MX53_PAD_EIM_D17__ECSPI1_MISO */ + IMX_PIN_REG(MX53_PAD_EIM_D17, 0x464, 0x11C, 5, 0x824, 0), /* MX53_PAD_EIM_D17__I2C3_SCL */ + IMX_PIN_REG(MX53_PAD_EIM_D18, 0x468, 0x120, 0, 0x000, 0), /* MX53_PAD_EIM_D18__EMI_WEIM_D_18 */ + IMX_PIN_REG(MX53_PAD_EIM_D18, 0x468, 0x120, 1, 0x000, 0), /* MX53_PAD_EIM_D18__GPIO3_18 */ + IMX_PIN_REG(MX53_PAD_EIM_D18, 0x468, 0x120, 2, 0x000, 0), /* MX53_PAD_EIM_D18__IPU_DI0_PIN7 */ + IMX_PIN_REG(MX53_PAD_EIM_D18, 0x468, 0x120, 3, 0x830, 1), /* MX53_PAD_EIM_D18__IPU_DISPB1_SER_DIO */ + IMX_PIN_REG(MX53_PAD_EIM_D18, 0x468, 0x120, 4, 0x7A4, 3), /* MX53_PAD_EIM_D18__ECSPI1_MOSI */ + IMX_PIN_REG(MX53_PAD_EIM_D18, 0x468, 0x120, 5, 0x828, 0), /* MX53_PAD_EIM_D18__I2C3_SDA */ + IMX_PIN_REG(MX53_PAD_EIM_D18, 0x468, 0x120, 6, 0x000, 0), /* MX53_PAD_EIM_D18__IPU_DI1_D0_CS */ + IMX_PIN_REG(MX53_PAD_EIM_D19, 0x46C, 0x124, 0, 0x000, 0), /* MX53_PAD_EIM_D19__EMI_WEIM_D_19 */ + IMX_PIN_REG(MX53_PAD_EIM_D19, 0x46C, 0x124, 1, 0x000, 0), /* MX53_PAD_EIM_D19__GPIO3_19 */ + IMX_PIN_REG(MX53_PAD_EIM_D19, 0x46C, 0x124, 2, 0x000, 0), /* MX53_PAD_EIM_D19__IPU_DI0_PIN8 */ + IMX_PIN_REG(MX53_PAD_EIM_D19, 0x46C, 0x124, 3, 0x000, 0), /* MX53_PAD_EIM_D19__IPU_DISPB1_SER_RS */ + IMX_PIN_REG(MX53_PAD_EIM_D19, 0x46C, 0x124, 4, 0x7AC, 2), /* MX53_PAD_EIM_D19__ECSPI1_SS1 */ + IMX_PIN_REG(MX53_PAD_EIM_D19, 0x46C, 0x124, 5, 0x000, 0), /* MX53_PAD_EIM_D19__EPIT1_EPITO */ + IMX_PIN_REG(MX53_PAD_EIM_D19, 0x46C, 0x124, 6, 0x000, 0), /* MX53_PAD_EIM_D19__UART1_CTS */ + IMX_PIN_REG(MX53_PAD_EIM_D19, 0x46C, 0x124, 7, 0x8A4, 0), /* MX53_PAD_EIM_D19__USBOH3_USBH2_OC */ + IMX_PIN_REG(MX53_PAD_EIM_D20, 0x470, 0x128, 0, 0x000, 0), /* MX53_PAD_EIM_D20__EMI_WEIM_D_20 */ + IMX_PIN_REG(MX53_PAD_EIM_D20, 0x470, 0x128, 1, 0x000, 0), /* MX53_PAD_EIM_D20__GPIO3_20 */ + IMX_PIN_REG(MX53_PAD_EIM_D20, 0x470, 0x128, 2, 0x000, 0), /* MX53_PAD_EIM_D20__IPU_DI0_PIN16 */ + IMX_PIN_REG(MX53_PAD_EIM_D20, 0x470, 0x128, 3, 0x000, 0), /* MX53_PAD_EIM_D20__IPU_SER_DISP0_CS */ + IMX_PIN_REG(MX53_PAD_EIM_D20, 0x470, 0x128, 4, 0x78C, 1), /* MX53_PAD_EIM_D20__CSPI_SS0 */ + IMX_PIN_REG(MX53_PAD_EIM_D20, 0x470, 0x128, 5, 0x000, 0), /* MX53_PAD_EIM_D20__EPIT2_EPITO */ + IMX_PIN_REG(MX53_PAD_EIM_D20, 0x470, 0x128, 6, 0x874, 1), /* MX53_PAD_EIM_D20__UART1_RTS */ + IMX_PIN_REG(MX53_PAD_EIM_D20, 0x470, 0x128, 7, 0x000, 0), /* MX53_PAD_EIM_D20__USBOH3_USBH2_PWR */ + IMX_PIN_REG(MX53_PAD_EIM_D21, 0x474, 0x12C, 0, 0x000, 0), /* MX53_PAD_EIM_D21__EMI_WEIM_D_21 */ + IMX_PIN_REG(MX53_PAD_EIM_D21, 0x474, 0x12C, 1, 0x000, 0), /* MX53_PAD_EIM_D21__GPIO3_21 */ + IMX_PIN_REG(MX53_PAD_EIM_D21, 0x474, 0x12C, 2, 0x000, 0), /* MX53_PAD_EIM_D21__IPU_DI0_PIN17 */ + IMX_PIN_REG(MX53_PAD_EIM_D21, 0x474, 0x12C, 3, 0x000, 0), /* MX53_PAD_EIM_D21__IPU_DISPB0_SER_CLK */ + IMX_PIN_REG(MX53_PAD_EIM_D21, 0x474, 0x12C, 4, 0x780, 1), /* MX53_PAD_EIM_D21__CSPI_SCLK */ + IMX_PIN_REG(MX53_PAD_EIM_D21, 0x474, 0x12C, 5, 0x814, 1), /* MX53_PAD_EIM_D21__I2C1_SCL */ + IMX_PIN_REG(MX53_PAD_EIM_D21, 0x474, 0x12C, 6, 0x89C, 1), /* MX53_PAD_EIM_D21__USBOH3_USBOTG_OC */ + IMX_PIN_REG(MX53_PAD_EIM_D22, 0x478, 0x130, 0, 0x000, 0), /* MX53_PAD_EIM_D22__EMI_WEIM_D_22 */ + IMX_PIN_REG(MX53_PAD_EIM_D22, 0x478, 0x130, 1, 0x000, 0), /* MX53_PAD_EIM_D22__GPIO3_22 */ + IMX_PIN_REG(MX53_PAD_EIM_D22, 0x478, 0x130, 2, 0x000, 0), /* MX53_PAD_EIM_D22__IPU_DI0_PIN1 */ + IMX_PIN_REG(MX53_PAD_EIM_D22, 0x478, 0x130, 3, 0x82C, 0), /* MX53_PAD_EIM_D22__IPU_DISPB0_SER_DIN */ + IMX_PIN_REG(MX53_PAD_EIM_D22, 0x478, 0x130, 4, 0x784, 1), /* MX53_PAD_EIM_D22__CSPI_MISO */ + IMX_PIN_REG(MX53_PAD_EIM_D22, 0x478, 0x130, 6, 0x000, 0), /* MX53_PAD_EIM_D22__USBOH3_USBOTG_PWR */ + IMX_PIN_REG(MX53_PAD_EIM_D23, 0x47C, 0x134, 0, 0x000, 0), /* MX53_PAD_EIM_D23__EMI_WEIM_D_23 */ + IMX_PIN_REG(MX53_PAD_EIM_D23, 0x47C, 0x134, 1, 0x000, 0), /* MX53_PAD_EIM_D23__GPIO3_23 */ + IMX_PIN_REG(MX53_PAD_EIM_D23, 0x47C, 0x134, 2, 0x000, 0), /* MX53_PAD_EIM_D23__UART3_CTS */ + IMX_PIN_REG(MX53_PAD_EIM_D23, 0x47C, 0x134, 3, 0x000, 0), /* MX53_PAD_EIM_D23__UART1_DCD */ + IMX_PIN_REG(MX53_PAD_EIM_D23, 0x47C, 0x134, 4, 0x000, 0), /* MX53_PAD_EIM_D23__IPU_DI0_D0_CS */ + IMX_PIN_REG(MX53_PAD_EIM_D23, 0x47C, 0x134, 5, 0x000, 0), /* MX53_PAD_EIM_D23__IPU_DI1_PIN2 */ + IMX_PIN_REG(MX53_PAD_EIM_D23, 0x47C, 0x134, 6, 0x834, 0), /* MX53_PAD_EIM_D23__IPU_CSI1_DATA_EN */ + IMX_PIN_REG(MX53_PAD_EIM_D23, 0x47C, 0x134, 7, 0x000, 0), /* MX53_PAD_EIM_D23__IPU_DI1_PIN14 */ + IMX_PIN_REG(MX53_PAD_EIM_EB3, 0x480, 0x138, 0, 0x000, 0), /* MX53_PAD_EIM_EB3__EMI_WEIM_EB_3 */ + IMX_PIN_REG(MX53_PAD_EIM_EB3, 0x480, 0x138, 1, 0x000, 0), /* MX53_PAD_EIM_EB3__GPIO2_31 */ + IMX_PIN_REG(MX53_PAD_EIM_EB3, 0x480, 0x138, 2, 0x884, 1), /* MX53_PAD_EIM_EB3__UART3_RTS */ + IMX_PIN_REG(MX53_PAD_EIM_EB3, 0x480, 0x138, 3, 0x000, 0), /* MX53_PAD_EIM_EB3__UART1_RI */ + IMX_PIN_REG(MX53_PAD_EIM_EB3, 0x480, 0x138, 5, 0x000, 0), /* MX53_PAD_EIM_EB3__IPU_DI1_PIN3 */ + IMX_PIN_REG(MX53_PAD_EIM_EB3, 0x480, 0x138, 6, 0x838, 0), /* MX53_PAD_EIM_EB3__IPU_CSI1_HSYNC */ + IMX_PIN_REG(MX53_PAD_EIM_EB3, 0x480, 0x138, 7, 0x000, 0), /* MX53_PAD_EIM_EB3__IPU_DI1_PIN16 */ + IMX_PIN_REG(MX53_PAD_EIM_D24, 0x484, 0x13C, 0, 0x000, 0), /* MX53_PAD_EIM_D24__EMI_WEIM_D_24 */ + IMX_PIN_REG(MX53_PAD_EIM_D24, 0x484, 0x13C, 1, 0x000, 0), /* MX53_PAD_EIM_D24__GPIO3_24 */ + IMX_PIN_REG(MX53_PAD_EIM_D24, 0x484, 0x13C, 2, 0x000, 0), /* MX53_PAD_EIM_D24__UART3_TXD_MUX */ + IMX_PIN_REG(MX53_PAD_EIM_D24, 0x484, 0x13C, 3, 0x7B0, 1), /* MX53_PAD_EIM_D24__ECSPI1_SS2 */ + IMX_PIN_REG(MX53_PAD_EIM_D24, 0x484, 0x13C, 4, 0x794, 1), /* MX53_PAD_EIM_D24__CSPI_SS2 */ + IMX_PIN_REG(MX53_PAD_EIM_D24, 0x484, 0x13C, 5, 0x754, 1), /* MX53_PAD_EIM_D24__AUDMUX_AUD5_RXFS */ + IMX_PIN_REG(MX53_PAD_EIM_D24, 0x484, 0x13C, 6, 0x000, 0), /* MX53_PAD_EIM_D24__ECSPI2_SS2 */ + IMX_PIN_REG(MX53_PAD_EIM_D24, 0x484, 0x13C, 7, 0x000, 0), /* MX53_PAD_EIM_D24__UART1_DTR */ + IMX_PIN_REG(MX53_PAD_EIM_D25, 0x488, 0x140, 0, 0x000, 0), /* MX53_PAD_EIM_D25__EMI_WEIM_D_25 */ + IMX_PIN_REG(MX53_PAD_EIM_D25, 0x488, 0x140, 1, 0x000, 0), /* MX53_PAD_EIM_D25__GPIO3_25 */ + IMX_PIN_REG(MX53_PAD_EIM_D25, 0x488, 0x140, 2, 0x888, 1), /* MX53_PAD_EIM_D25__UART3_RXD_MUX */ + IMX_PIN_REG(MX53_PAD_EIM_D25, 0x488, 0x140, 3, 0x7B4, 1), /* MX53_PAD_EIM_D25__ECSPI1_SS3 */ + IMX_PIN_REG(MX53_PAD_EIM_D25, 0x488, 0x140, 4, 0x798, 1), /* MX53_PAD_EIM_D25__CSPI_SS3 */ + IMX_PIN_REG(MX53_PAD_EIM_D25, 0x488, 0x140, 5, 0x750, 1), /* MX53_PAD_EIM_D25__AUDMUX_AUD5_RXC */ + IMX_PIN_REG(MX53_PAD_EIM_D25, 0x488, 0x140, 6, 0x000, 0), /* MX53_PAD_EIM_D25__ECSPI2_SS3 */ + IMX_PIN_REG(MX53_PAD_EIM_D25, 0x488, 0x140, 7, 0x000, 0), /* MX53_PAD_EIM_D25__UART1_DSR */ + IMX_PIN_REG(MX53_PAD_EIM_D26, 0x48C, 0x144, 0, 0x000, 0), /* MX53_PAD_EIM_D26__EMI_WEIM_D_26 */ + IMX_PIN_REG(MX53_PAD_EIM_D26, 0x48C, 0x144, 1, 0x000, 0), /* MX53_PAD_EIM_D26__GPIO3_26 */ + IMX_PIN_REG(MX53_PAD_EIM_D26, 0x48C, 0x144, 2, 0x000, 0), /* MX53_PAD_EIM_D26__UART2_TXD_MUX */ + IMX_PIN_REG(MX53_PAD_EIM_D26, 0x48C, 0x144, 3, 0x80C, 0), /* MX53_PAD_EIM_D26__FIRI_RXD */ + IMX_PIN_REG(MX53_PAD_EIM_D26, 0x48C, 0x144, 4, 0x000, 0), /* MX53_PAD_EIM_D26__IPU_CSI0_D_1 */ + IMX_PIN_REG(MX53_PAD_EIM_D26, 0x48C, 0x144, 5, 0x000, 0), /* MX53_PAD_EIM_D26__IPU_DI1_PIN11 */ + IMX_PIN_REG(MX53_PAD_EIM_D26, 0x48C, 0x144, 6, 0x000, 0), /* MX53_PAD_EIM_D26__IPU_SISG_2 */ + IMX_PIN_REG(MX53_PAD_EIM_D26, 0x48C, 0x144, 7, 0x000, 0), /* MX53_PAD_EIM_D26__IPU_DISP1_DAT_22 */ + IMX_PIN_REG(MX53_PAD_EIM_D27, 0x490, 0x148, 0, 0x000, 0), /* MX53_PAD_EIM_D27__EMI_WEIM_D_27 */ + IMX_PIN_REG(MX53_PAD_EIM_D27, 0x490, 0x148, 1, 0x000, 0), /* MX53_PAD_EIM_D27__GPIO3_27 */ + IMX_PIN_REG(MX53_PAD_EIM_D27, 0x490, 0x148, 2, 0x880, 1), /* MX53_PAD_EIM_D27__UART2_RXD_MUX */ + IMX_PIN_REG(MX53_PAD_EIM_D27, 0x490, 0x148, 3, 0x000, 0), /* MX53_PAD_EIM_D27__FIRI_TXD */ + IMX_PIN_REG(MX53_PAD_EIM_D27, 0x490, 0x148, 4, 0x000, 0), /* MX53_PAD_EIM_D27__IPU_CSI0_D_0 */ + IMX_PIN_REG(MX53_PAD_EIM_D27, 0x490, 0x148, 5, 0x000, 0), /* MX53_PAD_EIM_D27__IPU_DI1_PIN13 */ + IMX_PIN_REG(MX53_PAD_EIM_D27, 0x490, 0x148, 6, 0x000, 0), /* MX53_PAD_EIM_D27__IPU_SISG_3 */ + IMX_PIN_REG(MX53_PAD_EIM_D27, 0x490, 0x148, 7, 0x000, 0), /* MX53_PAD_EIM_D27__IPU_DISP1_DAT_23 */ + IMX_PIN_REG(MX53_PAD_EIM_D28, 0x494, 0x14C, 0, 0x000, 0), /* MX53_PAD_EIM_D28__EMI_WEIM_D_28 */ + IMX_PIN_REG(MX53_PAD_EIM_D28, 0x494, 0x14C, 1, 0x000, 0), /* MX53_PAD_EIM_D28__GPIO3_28 */ + IMX_PIN_REG(MX53_PAD_EIM_D28, 0x494, 0x14C, 2, 0x000, 0), /* MX53_PAD_EIM_D28__UART2_CTS */ + IMX_PIN_REG(MX53_PAD_EIM_D28, 0x494, 0x14C, 3, 0x82C, 1), /* MX53_PAD_EIM_D28__IPU_DISPB0_SER_DIO */ + IMX_PIN_REG(MX53_PAD_EIM_D28, 0x494, 0x14C, 4, 0x788, 1), /* MX53_PAD_EIM_D28__CSPI_MOSI */ + IMX_PIN_REG(MX53_PAD_EIM_D28, 0x494, 0x14C, 5, 0x818, 1), /* MX53_PAD_EIM_D28__I2C1_SDA */ + IMX_PIN_REG(MX53_PAD_EIM_D28, 0x494, 0x14C, 6, 0x000, 0), /* MX53_PAD_EIM_D28__IPU_EXT_TRIG */ + IMX_PIN_REG(MX53_PAD_EIM_D28, 0x494, 0x14C, 7, 0x000, 0), /* MX53_PAD_EIM_D28__IPU_DI0_PIN13 */ + IMX_PIN_REG(MX53_PAD_EIM_D29, 0x498, 0x150, 0, 0x000, 0), /* MX53_PAD_EIM_D29__EMI_WEIM_D_29 */ + IMX_PIN_REG(MX53_PAD_EIM_D29, 0x498, 0x150, 1, 0x000, 0), /* MX53_PAD_EIM_D29__GPIO3_29 */ + IMX_PIN_REG(MX53_PAD_EIM_D29, 0x498, 0x150, 2, 0x87C, 1), /* MX53_PAD_EIM_D29__UART2_RTS */ + IMX_PIN_REG(MX53_PAD_EIM_D29, 0x498, 0x150, 3, 0x000, 0), /* MX53_PAD_EIM_D29__IPU_DISPB0_SER_RS */ + IMX_PIN_REG(MX53_PAD_EIM_D29, 0x498, 0x150, 4, 0x78C, 2), /* MX53_PAD_EIM_D29__CSPI_SS0 */ + IMX_PIN_REG(MX53_PAD_EIM_D29, 0x498, 0x150, 5, 0x000, 0), /* MX53_PAD_EIM_D29__IPU_DI1_PIN15 */ + IMX_PIN_REG(MX53_PAD_EIM_D29, 0x498, 0x150, 6, 0x83C, 0), /* MX53_PAD_EIM_D29__IPU_CSI1_VSYNC */ + IMX_PIN_REG(MX53_PAD_EIM_D29, 0x498, 0x150, 7, 0x000, 0), /* MX53_PAD_EIM_D29__IPU_DI0_PIN14 */ + IMX_PIN_REG(MX53_PAD_EIM_D30, 0x49C, 0x154, 0, 0x000, 0), /* MX53_PAD_EIM_D30__EMI_WEIM_D_30 */ + IMX_PIN_REG(MX53_PAD_EIM_D30, 0x49C, 0x154, 1, 0x000, 0), /* MX53_PAD_EIM_D30__GPIO3_30 */ + IMX_PIN_REG(MX53_PAD_EIM_D30, 0x49C, 0x154, 2, 0x000, 0), /* MX53_PAD_EIM_D30__UART3_CTS */ + IMX_PIN_REG(MX53_PAD_EIM_D30, 0x49C, 0x154, 3, 0x000, 0), /* MX53_PAD_EIM_D30__IPU_CSI0_D_3 */ + IMX_PIN_REG(MX53_PAD_EIM_D30, 0x49C, 0x154, 4, 0x000, 0), /* MX53_PAD_EIM_D30__IPU_DI0_PIN11 */ + IMX_PIN_REG(MX53_PAD_EIM_D30, 0x49C, 0x154, 5, 0x000, 0), /* MX53_PAD_EIM_D30__IPU_DISP1_DAT_21 */ + IMX_PIN_REG(MX53_PAD_EIM_D30, 0x49C, 0x154, 6, 0x8A0, 0), /* MX53_PAD_EIM_D30__USBOH3_USBH1_OC */ + IMX_PIN_REG(MX53_PAD_EIM_D30, 0x49C, 0x154, 7, 0x8A4, 1), /* MX53_PAD_EIM_D30__USBOH3_USBH2_OC */ + IMX_PIN_REG(MX53_PAD_EIM_D31, 0x4A0, 0x158, 0, 0x000, 0), /* MX53_PAD_EIM_D31__EMI_WEIM_D_31 */ + IMX_PIN_REG(MX53_PAD_EIM_D31, 0x4A0, 0x158, 1, 0x000, 0), /* MX53_PAD_EIM_D31__GPIO3_31 */ + IMX_PIN_REG(MX53_PAD_EIM_D31, 0x4A0, 0x158, 2, 0x884, 3), /* MX53_PAD_EIM_D31__UART3_RTS */ + IMX_PIN_REG(MX53_PAD_EIM_D31, 0x4A0, 0x158, 3, 0x000, 0), /* MX53_PAD_EIM_D31__IPU_CSI0_D_2 */ + IMX_PIN_REG(MX53_PAD_EIM_D31, 0x4A0, 0x158, 4, 0x000, 0), /* MX53_PAD_EIM_D31__IPU_DI0_PIN12 */ + IMX_PIN_REG(MX53_PAD_EIM_D31, 0x4A0, 0x158, 5, 0x000, 0), /* MX53_PAD_EIM_D31__IPU_DISP1_DAT_20 */ + IMX_PIN_REG(MX53_PAD_EIM_D31, 0x4A0, 0x158, 6, 0x000, 0), /* MX53_PAD_EIM_D31__USBOH3_USBH1_PWR */ + IMX_PIN_REG(MX53_PAD_EIM_D31, 0x4A0, 0x158, 7, 0x000, 0), /* MX53_PAD_EIM_D31__USBOH3_USBH2_PWR */ + IMX_PIN_REG(MX53_PAD_EIM_A24, 0x4A8, 0x15C, 0, 0x000, 0), /* MX53_PAD_EIM_A24__EMI_WEIM_A_24 */ + IMX_PIN_REG(MX53_PAD_EIM_A24, 0x4A8, 0x15C, 1, 0x000, 0), /* MX53_PAD_EIM_A24__GPIO5_4 */ + IMX_PIN_REG(MX53_PAD_EIM_A24, 0x4A8, 0x15C, 2, 0x000, 0), /* MX53_PAD_EIM_A24__IPU_DISP1_DAT_19 */ + IMX_PIN_REG(MX53_PAD_EIM_A24, 0x4A8, 0x15C, 3, 0x000, 0), /* MX53_PAD_EIM_A24__IPU_CSI1_D_19 */ + IMX_PIN_REG(MX53_PAD_EIM_A24, 0x4A8, 0x15C, 6, 0x000, 0), /* MX53_PAD_EIM_A24__IPU_SISG_2 */ + IMX_PIN_REG(MX53_PAD_EIM_A24, 0x4A8, 0x15C, 7, 0x000, 0), /* MX53_PAD_EIM_A24__USBPHY2_BVALID */ + IMX_PIN_REG(MX53_PAD_EIM_A23, 0x4AC, 0x160, 0, 0x000, 0), /* MX53_PAD_EIM_A23__EMI_WEIM_A_23 */ + IMX_PIN_REG(MX53_PAD_EIM_A23, 0x4AC, 0x160, 1, 0x000, 0), /* MX53_PAD_EIM_A23__GPIO6_6 */ + IMX_PIN_REG(MX53_PAD_EIM_A23, 0x4AC, 0x160, 2, 0x000, 0), /* MX53_PAD_EIM_A23__IPU_DISP1_DAT_18 */ + IMX_PIN_REG(MX53_PAD_EIM_A23, 0x4AC, 0x160, 3, 0x000, 0), /* MX53_PAD_EIM_A23__IPU_CSI1_D_18 */ + IMX_PIN_REG(MX53_PAD_EIM_A23, 0x4AC, 0x160, 6, 0x000, 0), /* MX53_PAD_EIM_A23__IPU_SISG_3 */ + IMX_PIN_REG(MX53_PAD_EIM_A23, 0x4AC, 0x160, 7, 0x000, 0), /* MX53_PAD_EIM_A23__USBPHY2_ENDSESSION */ + IMX_PIN_REG(MX53_PAD_EIM_A22, 0x4B0, 0x164, 0, 0x000, 0), /* MX53_PAD_EIM_A22__EMI_WEIM_A_22 */ + IMX_PIN_REG(MX53_PAD_EIM_A22, 0x4B0, 0x164, 1, 0x000, 0), /* MX53_PAD_EIM_A22__GPIO2_16 */ + IMX_PIN_REG(MX53_PAD_EIM_A22, 0x4B0, 0x164, 2, 0x000, 0), /* MX53_PAD_EIM_A22__IPU_DISP1_DAT_17 */ + IMX_PIN_REG(MX53_PAD_EIM_A22, 0x4B0, 0x164, 3, 0x000, 0), /* MX53_PAD_EIM_A22__IPU_CSI1_D_17 */ + IMX_PIN_REG(MX53_PAD_EIM_A22, 0x4B0, 0x164, 7, 0x000, 0), /* MX53_PAD_EIM_A22__SRC_BT_CFG1_7 */ + IMX_PIN_REG(MX53_PAD_EIM_A21, 0x4B4, 0x168, 0, 0x000, 0), /* MX53_PAD_EIM_A21__EMI_WEIM_A_21 */ + IMX_PIN_REG(MX53_PAD_EIM_A21, 0x4B4, 0x168, 1, 0x000, 0), /* MX53_PAD_EIM_A21__GPIO2_17 */ + IMX_PIN_REG(MX53_PAD_EIM_A21, 0x4B4, 0x168, 2, 0x000, 0), /* MX53_PAD_EIM_A21__IPU_DISP1_DAT_16 */ + IMX_PIN_REG(MX53_PAD_EIM_A21, 0x4B4, 0x168, 3, 0x000, 0), /* MX53_PAD_EIM_A21__IPU_CSI1_D_16 */ + IMX_PIN_REG(MX53_PAD_EIM_A21, 0x4B4, 0x168, 7, 0x000, 0), /* MX53_PAD_EIM_A21__SRC_BT_CFG1_6 */ + IMX_PIN_REG(MX53_PAD_EIM_A20, 0x4B8, 0x16C, 0, 0x000, 0), /* MX53_PAD_EIM_A20__EMI_WEIM_A_20 */ + IMX_PIN_REG(MX53_PAD_EIM_A20, 0x4B8, 0x16C, 1, 0x000, 0), /* MX53_PAD_EIM_A20__GPIO2_18 */ + IMX_PIN_REG(MX53_PAD_EIM_A20, 0x4B8, 0x16C, 2, 0x000, 0), /* MX53_PAD_EIM_A20__IPU_DISP1_DAT_15 */ + IMX_PIN_REG(MX53_PAD_EIM_A20, 0x4B8, 0x16C, 3, 0x000, 0), /* MX53_PAD_EIM_A20__IPU_CSI1_D_15 */ + IMX_PIN_REG(MX53_PAD_EIM_A20, 0x4B8, 0x16C, 7, 0x000, 0), /* MX53_PAD_EIM_A20__SRC_BT_CFG1_5 */ + IMX_PIN_REG(MX53_PAD_EIM_A19, 0x4BC, 0x170, 0, 0x000, 0), /* MX53_PAD_EIM_A19__EMI_WEIM_A_19 */ + IMX_PIN_REG(MX53_PAD_EIM_A19, 0x4BC, 0x170, 1, 0x000, 0), /* MX53_PAD_EIM_A19__GPIO2_19 */ + IMX_PIN_REG(MX53_PAD_EIM_A19, 0x4BC, 0x170, 2, 0x000, 0), /* MX53_PAD_EIM_A19__IPU_DISP1_DAT_14 */ + IMX_PIN_REG(MX53_PAD_EIM_A19, 0x4BC, 0x170, 3, 0x000, 0), /* MX53_PAD_EIM_A19__IPU_CSI1_D_14 */ + IMX_PIN_REG(MX53_PAD_EIM_A19, 0x4BC, 0x170, 7, 0x000, 0), /* MX53_PAD_EIM_A19__SRC_BT_CFG1_4 */ + IMX_PIN_REG(MX53_PAD_EIM_A18, 0x4C0, 0x174, 0, 0x000, 0), /* MX53_PAD_EIM_A18__EMI_WEIM_A_18 */ + IMX_PIN_REG(MX53_PAD_EIM_A18, 0x4C0, 0x174, 1, 0x000, 0), /* MX53_PAD_EIM_A18__GPIO2_20 */ + IMX_PIN_REG(MX53_PAD_EIM_A18, 0x4C0, 0x174, 2, 0x000, 0), /* MX53_PAD_EIM_A18__IPU_DISP1_DAT_13 */ + IMX_PIN_REG(MX53_PAD_EIM_A18, 0x4C0, 0x174, 3, 0x000, 0), /* MX53_PAD_EIM_A18__IPU_CSI1_D_13 */ + IMX_PIN_REG(MX53_PAD_EIM_A18, 0x4C0, 0x174, 7, 0x000, 0), /* MX53_PAD_EIM_A18__SRC_BT_CFG1_3 */ + IMX_PIN_REG(MX53_PAD_EIM_A17, 0x4C4, 0x178, 0, 0x000, 0), /* MX53_PAD_EIM_A17__EMI_WEIM_A_17 */ + IMX_PIN_REG(MX53_PAD_EIM_A17, 0x4C4, 0x178, 1, 0x000, 0), /* MX53_PAD_EIM_A17__GPIO2_21 */ + IMX_PIN_REG(MX53_PAD_EIM_A17, 0x4C4, 0x178, 2, 0x000, 0), /* MX53_PAD_EIM_A17__IPU_DISP1_DAT_12 */ + IMX_PIN_REG(MX53_PAD_EIM_A17, 0x4C4, 0x178, 3, 0x000, 0), /* MX53_PAD_EIM_A17__IPU_CSI1_D_12 */ + IMX_PIN_REG(MX53_PAD_EIM_A17, 0x4C4, 0x178, 7, 0x000, 0), /* MX53_PAD_EIM_A17__SRC_BT_CFG1_2 */ + IMX_PIN_REG(MX53_PAD_EIM_A16, 0x4C8, 0x17C, 0, 0x000, 0), /* MX53_PAD_EIM_A16__EMI_WEIM_A_16 */ + IMX_PIN_REG(MX53_PAD_EIM_A16, 0x4C8, 0x17C, 1, 0x000, 0), /* MX53_PAD_EIM_A16__GPIO2_22 */ + IMX_PIN_REG(MX53_PAD_EIM_A16, 0x4C8, 0x17C, 2, 0x000, 0), /* MX53_PAD_EIM_A16__IPU_DI1_DISP_CLK */ + IMX_PIN_REG(MX53_PAD_EIM_A16, 0x4C8, 0x17C, 3, 0x000, 0), /* MX53_PAD_EIM_A16__IPU_CSI1_PIXCLK */ + IMX_PIN_REG(MX53_PAD_EIM_A16, 0x4C8, 0x17C, 7, 0x000, 0), /* MX53_PAD_EIM_A16__SRC_BT_CFG1_1 */ + IMX_PIN_REG(MX53_PAD_EIM_CS0, 0x4CC, 0x180, 0, 0x000, 0), /* MX53_PAD_EIM_CS0__EMI_WEIM_CS_0 */ + IMX_PIN_REG(MX53_PAD_EIM_CS0, 0x4CC, 0x180, 1, 0x000, 0), /* MX53_PAD_EIM_CS0__GPIO2_23 */ + IMX_PIN_REG(MX53_PAD_EIM_CS0, 0x4CC, 0x180, 2, 0x7B8, 2), /* MX53_PAD_EIM_CS0__ECSPI2_SCLK */ + IMX_PIN_REG(MX53_PAD_EIM_CS0, 0x4CC, 0x180, 3, 0x000, 0), /* MX53_PAD_EIM_CS0__IPU_DI1_PIN5 */ + IMX_PIN_REG(MX53_PAD_EIM_CS1, 0x4D0, 0x184, 0, 0x000, 0), /* MX53_PAD_EIM_CS1__EMI_WEIM_CS_1 */ + IMX_PIN_REG(MX53_PAD_EIM_CS1, 0x4D0, 0x184, 1, 0x000, 0), /* MX53_PAD_EIM_CS1__GPIO2_24 */ + IMX_PIN_REG(MX53_PAD_EIM_CS1, 0x4D0, 0x184, 2, 0x7C0, 2), /* MX53_PAD_EIM_CS1__ECSPI2_MOSI */ + IMX_PIN_REG(MX53_PAD_EIM_CS1, 0x4D0, 0x184, 3, 0x000, 0), /* MX53_PAD_EIM_CS1__IPU_DI1_PIN6 */ + IMX_PIN_REG(MX53_PAD_EIM_OE, 0x4D4, 0x188, 0, 0x000, 0), /* MX53_PAD_EIM_OE__EMI_WEIM_OE */ + IMX_PIN_REG(MX53_PAD_EIM_OE, 0x4D4, 0x188, 1, 0x000, 0), /* MX53_PAD_EIM_OE__GPIO2_25 */ + IMX_PIN_REG(MX53_PAD_EIM_OE, 0x4D4, 0x188, 2, 0x7BC, 2), /* MX53_PAD_EIM_OE__ECSPI2_MISO */ + IMX_PIN_REG(MX53_PAD_EIM_OE, 0x4D4, 0x188, 3, 0x000, 0), /* MX53_PAD_EIM_OE__IPU_DI1_PIN7 */ + IMX_PIN_REG(MX53_PAD_EIM_OE, 0x4D4, 0x188, 7, 0x000, 0), /* MX53_PAD_EIM_OE__USBPHY2_IDDIG */ + IMX_PIN_REG(MX53_PAD_EIM_RW, 0x4D8, 0x18C, 0, 0x000, 0), /* MX53_PAD_EIM_RW__EMI_WEIM_RW */ + IMX_PIN_REG(MX53_PAD_EIM_RW, 0x4D8, 0x18C, 1, 0x000, 0), /* MX53_PAD_EIM_RW__GPIO2_26 */ + IMX_PIN_REG(MX53_PAD_EIM_RW, 0x4D8, 0x18C, 2, 0x7C4, 2), /* MX53_PAD_EIM_RW__ECSPI2_SS0 */ + IMX_PIN_REG(MX53_PAD_EIM_RW, 0x4D8, 0x18C, 3, 0x000, 0), /* MX53_PAD_EIM_RW__IPU_DI1_PIN8 */ + IMX_PIN_REG(MX53_PAD_EIM_RW, 0x4D8, 0x18C, 7, 0x000, 0), /* MX53_PAD_EIM_RW__USBPHY2_HOSTDISCONNECT */ + IMX_PIN_REG(MX53_PAD_EIM_LBA, 0x4DC, 0x190, 0, 0x000, 0), /* MX53_PAD_EIM_LBA__EMI_WEIM_LBA */ + IMX_PIN_REG(MX53_PAD_EIM_LBA, 0x4DC, 0x190, 1, 0x000, 0), /* MX53_PAD_EIM_LBA__GPIO2_27 */ + IMX_PIN_REG(MX53_PAD_EIM_LBA, 0x4DC, 0x190, 2, 0x7C8, 1), /* MX53_PAD_EIM_LBA__ECSPI2_SS1 */ + IMX_PIN_REG(MX53_PAD_EIM_LBA, 0x4DC, 0x190, 3, 0x000, 0), /* MX53_PAD_EIM_LBA__IPU_DI1_PIN17 */ + IMX_PIN_REG(MX53_PAD_EIM_LBA, 0x4DC, 0x190, 7, 0x000, 0), /* MX53_PAD_EIM_LBA__SRC_BT_CFG1_0 */ + IMX_PIN_REG(MX53_PAD_EIM_EB0, 0x4E4, 0x194, 0, 0x000, 0), /* MX53_PAD_EIM_EB0__EMI_WEIM_EB_0 */ + IMX_PIN_REG(MX53_PAD_EIM_EB0, 0x4E4, 0x194, 1, 0x000, 0), /* MX53_PAD_EIM_EB0__GPIO2_28 */ + IMX_PIN_REG(MX53_PAD_EIM_EB0, 0x4E4, 0x194, 3, 0x000, 0), /* MX53_PAD_EIM_EB0__IPU_DISP1_DAT_11 */ + IMX_PIN_REG(MX53_PAD_EIM_EB0, 0x4E4, 0x194, 4, 0x000, 0), /* MX53_PAD_EIM_EB0__IPU_CSI1_D_11 */ + IMX_PIN_REG(MX53_PAD_EIM_EB0, 0x4E4, 0x194, 5, 0x810, 0), /* MX53_PAD_EIM_EB0__GPC_PMIC_RDY */ + IMX_PIN_REG(MX53_PAD_EIM_EB0, 0x4E4, 0x194, 7, 0x000, 0), /* MX53_PAD_EIM_EB0__SRC_BT_CFG2_7 */ + IMX_PIN_REG(MX53_PAD_EIM_EB1, 0x4E8, 0x198, 0, 0x000, 0), /* MX53_PAD_EIM_EB1__EMI_WEIM_EB_1 */ + IMX_PIN_REG(MX53_PAD_EIM_EB1, 0x4E8, 0x198, 1, 0x000, 0), /* MX53_PAD_EIM_EB1__GPIO2_29 */ + IMX_PIN_REG(MX53_PAD_EIM_EB1, 0x4E8, 0x198, 3, 0x000, 0), /* MX53_PAD_EIM_EB1__IPU_DISP1_DAT_10 */ + IMX_PIN_REG(MX53_PAD_EIM_EB1, 0x4E8, 0x198, 4, 0x000, 0), /* MX53_PAD_EIM_EB1__IPU_CSI1_D_10 */ + IMX_PIN_REG(MX53_PAD_EIM_EB1, 0x4E8, 0x198, 7, 0x000, 0), /* MX53_PAD_EIM_EB1__SRC_BT_CFG2_6 */ + IMX_PIN_REG(MX53_PAD_EIM_DA0, 0x4EC, 0x19C, 0, 0x000, 0), /* MX53_PAD_EIM_DA0__EMI_NAND_WEIM_DA_0 */ + IMX_PIN_REG(MX53_PAD_EIM_DA0, 0x4EC, 0x19C, 1, 0x000, 0), /* MX53_PAD_EIM_DA0__GPIO3_0 */ + IMX_PIN_REG(MX53_PAD_EIM_DA0, 0x4EC, 0x19C, 3, 0x000, 0), /* MX53_PAD_EIM_DA0__IPU_DISP1_DAT_9 */ + IMX_PIN_REG(MX53_PAD_EIM_DA0, 0x4EC, 0x19C, 4, 0x000, 0), /* MX53_PAD_EIM_DA0__IPU_CSI1_D_9 */ + IMX_PIN_REG(MX53_PAD_EIM_DA0, 0x4EC, 0x19C, 7, 0x000, 0), /* MX53_PAD_EIM_DA0__SRC_BT_CFG2_5 */ + IMX_PIN_REG(MX53_PAD_EIM_DA1, 0x4F0, 0x1A0, 0, 0x000, 0), /* MX53_PAD_EIM_DA1__EMI_NAND_WEIM_DA_1 */ + IMX_PIN_REG(MX53_PAD_EIM_DA1, 0x4F0, 0x1A0, 1, 0x000, 0), /* MX53_PAD_EIM_DA1__GPIO3_1 */ + IMX_PIN_REG(MX53_PAD_EIM_DA1, 0x4F0, 0x1A0, 3, 0x000, 0), /* MX53_PAD_EIM_DA1__IPU_DISP1_DAT_8 */ + IMX_PIN_REG(MX53_PAD_EIM_DA1, 0x4F0, 0x1A0, 4, 0x000, 0), /* MX53_PAD_EIM_DA1__IPU_CSI1_D_8 */ + IMX_PIN_REG(MX53_PAD_EIM_DA1, 0x4F0, 0x1A0, 7, 0x000, 0), /* MX53_PAD_EIM_DA1__SRC_BT_CFG2_4 */ + IMX_PIN_REG(MX53_PAD_EIM_DA2, 0x4F4, 0x1A4, 0, 0x000, 0), /* MX53_PAD_EIM_DA2__EMI_NAND_WEIM_DA_2 */ + IMX_PIN_REG(MX53_PAD_EIM_DA2, 0x4F4, 0x1A4, 1, 0x000, 0), /* MX53_PAD_EIM_DA2__GPIO3_2 */ + IMX_PIN_REG(MX53_PAD_EIM_DA2, 0x4F4, 0x1A4, 3, 0x000, 0), /* MX53_PAD_EIM_DA2__IPU_DISP1_DAT_7 */ + IMX_PIN_REG(MX53_PAD_EIM_DA2, 0x4F4, 0x1A4, 4, 0x000, 0), /* MX53_PAD_EIM_DA2__IPU_CSI1_D_7 */ + IMX_PIN_REG(MX53_PAD_EIM_DA2, 0x4F4, 0x1A4, 7, 0x000, 0), /* MX53_PAD_EIM_DA2__SRC_BT_CFG2_3 */ + IMX_PIN_REG(MX53_PAD_EIM_DA3, 0x4F8, 0x1A8, 0, 0x000, 0), /* MX53_PAD_EIM_DA3__EMI_NAND_WEIM_DA_3 */ + IMX_PIN_REG(MX53_PAD_EIM_DA3, 0x4F8, 0x1A8, 1, 0x000, 0), /* MX53_PAD_EIM_DA3__GPIO3_3 */ + IMX_PIN_REG(MX53_PAD_EIM_DA3, 0x4F8, 0x1A8, 3, 0x000, 0), /* MX53_PAD_EIM_DA3__IPU_DISP1_DAT_6 */ + IMX_PIN_REG(MX53_PAD_EIM_DA3, 0x4F8, 0x1A8, 4, 0x000, 0), /* MX53_PAD_EIM_DA3__IPU_CSI1_D_6 */ + IMX_PIN_REG(MX53_PAD_EIM_DA3, 0x4F8, 0x1A8, 7, 0x000, 0), /* MX53_PAD_EIM_DA3__SRC_BT_CFG2_2 */ + IMX_PIN_REG(MX53_PAD_EIM_DA4, 0x4FC, 0x1AC, 0, 0x000, 0), /* MX53_PAD_EIM_DA4__EMI_NAND_WEIM_DA_4 */ + IMX_PIN_REG(MX53_PAD_EIM_DA4, 0x4FC, 0x1AC, 1, 0x000, 0), /* MX53_PAD_EIM_DA4__GPIO3_4 */ + IMX_PIN_REG(MX53_PAD_EIM_DA4, 0x4FC, 0x1AC, 3, 0x000, 0), /* MX53_PAD_EIM_DA4__IPU_DISP1_DAT_5 */ + IMX_PIN_REG(MX53_PAD_EIM_DA4, 0x4FC, 0x1AC, 4, 0x000, 0), /* MX53_PAD_EIM_DA4__IPU_CSI1_D_5 */ + IMX_PIN_REG(MX53_PAD_EIM_DA4, 0x4FC, 0x1AC, 7, 0x000, 0), /* MX53_PAD_EIM_DA4__SRC_BT_CFG3_7 */ + IMX_PIN_REG(MX53_PAD_EIM_DA5, 0x500, 0x1B0, 0, 0x000, 0), /* MX53_PAD_EIM_DA5__EMI_NAND_WEIM_DA_5 */ + IMX_PIN_REG(MX53_PAD_EIM_DA5, 0x500, 0x1B0, 1, 0x000, 0), /* MX53_PAD_EIM_DA5__GPIO3_5 */ + IMX_PIN_REG(MX53_PAD_EIM_DA5, 0x500, 0x1B0, 3, 0x000, 0), /* MX53_PAD_EIM_DA5__IPU_DISP1_DAT_4 */ + IMX_PIN_REG(MX53_PAD_EIM_DA5, 0x500, 0x1B0, 4, 0x000, 0), /* MX53_PAD_EIM_DA5__IPU_CSI1_D_4 */ + IMX_PIN_REG(MX53_PAD_EIM_DA5, 0x500, 0x1B0, 7, 0x000, 0), /* MX53_PAD_EIM_DA5__SRC_BT_CFG3_6 */ + IMX_PIN_REG(MX53_PAD_EIM_DA6, 0x504, 0x1B4, 0, 0x000, 0), /* MX53_PAD_EIM_DA6__EMI_NAND_WEIM_DA_6 */ + IMX_PIN_REG(MX53_PAD_EIM_DA6, 0x504, 0x1B4, 1, 0x000, 0), /* MX53_PAD_EIM_DA6__GPIO3_6 */ + IMX_PIN_REG(MX53_PAD_EIM_DA6, 0x504, 0x1B4, 3, 0x000, 0), /* MX53_PAD_EIM_DA6__IPU_DISP1_DAT_3 */ + IMX_PIN_REG(MX53_PAD_EIM_DA6, 0x504, 0x1B4, 4, 0x000, 0), /* MX53_PAD_EIM_DA6__IPU_CSI1_D_3 */ + IMX_PIN_REG(MX53_PAD_EIM_DA6, 0x504, 0x1B4, 7, 0x000, 0), /* MX53_PAD_EIM_DA6__SRC_BT_CFG3_5 */ + IMX_PIN_REG(MX53_PAD_EIM_DA7, 0x508, 0x1B8, 0, 0x000, 0), /* MX53_PAD_EIM_DA7__EMI_NAND_WEIM_DA_7 */ + IMX_PIN_REG(MX53_PAD_EIM_DA7, 0x508, 0x1B8, 1, 0x000, 0), /* MX53_PAD_EIM_DA7__GPIO3_7 */ + IMX_PIN_REG(MX53_PAD_EIM_DA7, 0x508, 0x1B8, 3, 0x000, 0), /* MX53_PAD_EIM_DA7__IPU_DISP1_DAT_2 */ + IMX_PIN_REG(MX53_PAD_EIM_DA7, 0x508, 0x1B8, 4, 0x000, 0), /* MX53_PAD_EIM_DA7__IPU_CSI1_D_2 */ + IMX_PIN_REG(MX53_PAD_EIM_DA7, 0x508, 0x1B8, 7, 0x000, 0), /* MX53_PAD_EIM_DA7__SRC_BT_CFG3_4 */ + IMX_PIN_REG(MX53_PAD_EIM_DA8, 0x50C, 0x1BC, 0, 0x000, 0), /* MX53_PAD_EIM_DA8__EMI_NAND_WEIM_DA_8 */ + IMX_PIN_REG(MX53_PAD_EIM_DA8, 0x50C, 0x1BC, 1, 0x000, 0), /* MX53_PAD_EIM_DA8__GPIO3_8 */ + IMX_PIN_REG(MX53_PAD_EIM_DA8, 0x50C, 0x1BC, 3, 0x000, 0), /* MX53_PAD_EIM_DA8__IPU_DISP1_DAT_1 */ + IMX_PIN_REG(MX53_PAD_EIM_DA8, 0x50C, 0x1BC, 4, 0x000, 0), /* MX53_PAD_EIM_DA8__IPU_CSI1_D_1 */ + IMX_PIN_REG(MX53_PAD_EIM_DA8, 0x50C, 0x1BC, 7, 0x000, 0), /* MX53_PAD_EIM_DA8__SRC_BT_CFG3_3 */ + IMX_PIN_REG(MX53_PAD_EIM_DA9, 0x510, 0x1C0, 0, 0x000, 0), /* MX53_PAD_EIM_DA9__EMI_NAND_WEIM_DA_9 */ + IMX_PIN_REG(MX53_PAD_EIM_DA9, 0x510, 0x1C0, 1, 0x000, 0), /* MX53_PAD_EIM_DA9__GPIO3_9 */ + IMX_PIN_REG(MX53_PAD_EIM_DA9, 0x510, 0x1C0, 3, 0x000, 0), /* MX53_PAD_EIM_DA9__IPU_DISP1_DAT_0 */ + IMX_PIN_REG(MX53_PAD_EIM_DA9, 0x510, 0x1C0, 4, 0x000, 0), /* MX53_PAD_EIM_DA9__IPU_CSI1_D_0 */ + IMX_PIN_REG(MX53_PAD_EIM_DA9, 0x510, 0x1C0, 7, 0x000, 0), /* MX53_PAD_EIM_DA9__SRC_BT_CFG3_2 */ + IMX_PIN_REG(MX53_PAD_EIM_DA10, 0x514, 0x1C4, 0, 0x000, 0), /* MX53_PAD_EIM_DA10__EMI_NAND_WEIM_DA_10 */ + IMX_PIN_REG(MX53_PAD_EIM_DA10, 0x514, 0x1C4, 1, 0x000, 0), /* MX53_PAD_EIM_DA10__GPIO3_10 */ + IMX_PIN_REG(MX53_PAD_EIM_DA10, 0x514, 0x1C4, 3, 0x000, 0), /* MX53_PAD_EIM_DA10__IPU_DI1_PIN15 */ + IMX_PIN_REG(MX53_PAD_EIM_DA10, 0x514, 0x1C4, 4, 0x834, 1), /* MX53_PAD_EIM_DA10__IPU_CSI1_DATA_EN */ + IMX_PIN_REG(MX53_PAD_EIM_DA10, 0x514, 0x1C4, 7, 0x000, 0), /* MX53_PAD_EIM_DA10__SRC_BT_CFG3_1 */ + IMX_PIN_REG(MX53_PAD_EIM_DA11, 0x518, 0x1C8, 0, 0x000, 0), /* MX53_PAD_EIM_DA11__EMI_NAND_WEIM_DA_11 */ + IMX_PIN_REG(MX53_PAD_EIM_DA11, 0x518, 0x1C8, 1, 0x000, 0), /* MX53_PAD_EIM_DA11__GPIO3_11 */ + IMX_PIN_REG(MX53_PAD_EIM_DA11, 0x518, 0x1C8, 3, 0x000, 0), /* MX53_PAD_EIM_DA11__IPU_DI1_PIN2 */ + IMX_PIN_REG(MX53_PAD_EIM_DA11, 0x518, 0x1C8, 4, 0x838, 1), /* MX53_PAD_EIM_DA11__IPU_CSI1_HSYNC */ + IMX_PIN_REG(MX53_PAD_EIM_DA12, 0x51C, 0x1CC, 0, 0x000, 0), /* MX53_PAD_EIM_DA12__EMI_NAND_WEIM_DA_12 */ + IMX_PIN_REG(MX53_PAD_EIM_DA12, 0x51C, 0x1CC, 1, 0x000, 0), /* MX53_PAD_EIM_DA12__GPIO3_12 */ + IMX_PIN_REG(MX53_PAD_EIM_DA12, 0x51C, 0x1CC, 3, 0x000, 0), /* MX53_PAD_EIM_DA12__IPU_DI1_PIN3 */ + IMX_PIN_REG(MX53_PAD_EIM_DA12, 0x51C, 0x1CC, 4, 0x83C, 1), /* MX53_PAD_EIM_DA12__IPU_CSI1_VSYNC */ + IMX_PIN_REG(MX53_PAD_EIM_DA13, 0x520, 0x1D0, 0, 0x000, 0), /* MX53_PAD_EIM_DA13__EMI_NAND_WEIM_DA_13 */ + IMX_PIN_REG(MX53_PAD_EIM_DA13, 0x520, 0x1D0, 1, 0x000, 0), /* MX53_PAD_EIM_DA13__GPIO3_13 */ + IMX_PIN_REG(MX53_PAD_EIM_DA13, 0x520, 0x1D0, 3, 0x000, 0), /* MX53_PAD_EIM_DA13__IPU_DI1_D0_CS */ + IMX_PIN_REG(MX53_PAD_EIM_DA13, 0x520, 0x1D0, 4, 0x76C, 1), /* MX53_PAD_EIM_DA13__CCM_DI1_EXT_CLK */ + IMX_PIN_REG(MX53_PAD_EIM_DA14, 0x524, 0x1D4, 0, 0x000, 0), /* MX53_PAD_EIM_DA14__EMI_NAND_WEIM_DA_14 */ + IMX_PIN_REG(MX53_PAD_EIM_DA14, 0x524, 0x1D4, 1, 0x000, 0), /* MX53_PAD_EIM_DA14__GPIO3_14 */ + IMX_PIN_REG(MX53_PAD_EIM_DA14, 0x524, 0x1D4, 3, 0x000, 0), /* MX53_PAD_EIM_DA14__IPU_DI1_D1_CS */ + IMX_PIN_REG(MX53_PAD_EIM_DA14, 0x524, 0x1D4, 4, 0x000, 0), /* MX53_PAD_EIM_DA14__CCM_DI0_EXT_CLK */ + IMX_PIN_REG(MX53_PAD_EIM_DA15, 0x528, 0x1D8, 0, 0x000, 0), /* MX53_PAD_EIM_DA15__EMI_NAND_WEIM_DA_15 */ + IMX_PIN_REG(MX53_PAD_EIM_DA15, 0x528, 0x1D8, 1, 0x000, 0), /* MX53_PAD_EIM_DA15__GPIO3_15 */ + IMX_PIN_REG(MX53_PAD_EIM_DA15, 0x528, 0x1D8, 3, 0x000, 0), /* MX53_PAD_EIM_DA15__IPU_DI1_PIN1 */ + IMX_PIN_REG(MX53_PAD_EIM_DA15, 0x528, 0x1D8, 4, 0x000, 0), /* MX53_PAD_EIM_DA15__IPU_DI1_PIN4 */ + IMX_PIN_REG(MX53_PAD_NANDF_WE_B, 0x52C, 0x1DC, 0, 0x000, 0), /* MX53_PAD_NANDF_WE_B__EMI_NANDF_WE_B */ + IMX_PIN_REG(MX53_PAD_NANDF_WE_B, 0x52C, 0x1DC, 1, 0x000, 0), /* MX53_PAD_NANDF_WE_B__GPIO6_12 */ + IMX_PIN_REG(MX53_PAD_NANDF_RE_B, 0x530, 0x1E0, 0, 0x000, 0), /* MX53_PAD_NANDF_RE_B__EMI_NANDF_RE_B */ + IMX_PIN_REG(MX53_PAD_NANDF_RE_B, 0x530, 0x1E0, 1, 0x000, 0), /* MX53_PAD_NANDF_RE_B__GPIO6_13 */ + IMX_PIN_REG(MX53_PAD_EIM_WAIT, 0x534, 0x1E4, 0, 0x000, 0), /* MX53_PAD_EIM_WAIT__EMI_WEIM_WAIT */ + IMX_PIN_REG(MX53_PAD_EIM_WAIT, 0x534, 0x1E4, 1, 0x000, 0), /* MX53_PAD_EIM_WAIT__GPIO5_0 */ + IMX_PIN_REG(MX53_PAD_EIM_WAIT, 0x534, 0x1E4, 2, 0x000, 0), /* MX53_PAD_EIM_WAIT__EMI_WEIM_DTACK_B */ + IMX_PIN_REG(MX53_PAD_LVDS1_TX3_P, NO_PAD, 0x1EC, 0, 0x000, 0), /* MX53_PAD_LVDS1_TX3_P__GPIO6_22 */ + IMX_PIN_REG(MX53_PAD_LVDS1_TX3_P, NO_PAD, 0x1EC, 1, 0x000, 0), /* MX53_PAD_LVDS1_TX3_P__LDB_LVDS1_TX3 */ + IMX_PIN_REG(MX53_PAD_LVDS1_TX2_P, NO_PAD, 0x1F0, 0, 0x000, 0), /* MX53_PAD_LVDS1_TX2_P__GPIO6_24 */ + IMX_PIN_REG(MX53_PAD_LVDS1_TX2_P, NO_PAD, 0x1F0, 1, 0x000, 0), /* MX53_PAD_LVDS1_TX2_P__LDB_LVDS1_TX2 */ + IMX_PIN_REG(MX53_PAD_LVDS1_CLK_P, NO_PAD, 0x1F4, 0, 0x000, 0), /* MX53_PAD_LVDS1_CLK_P__GPIO6_26 */ + IMX_PIN_REG(MX53_PAD_LVDS1_CLK_P, NO_PAD, 0x1F4, 1, 0x000, 0), /* MX53_PAD_LVDS1_CLK_P__LDB_LVDS1_CLK */ + IMX_PIN_REG(MX53_PAD_LVDS1_TX1_P, NO_PAD, 0x1F8, 0, 0x000, 0), /* MX53_PAD_LVDS1_TX1_P__GPIO6_28 */ + IMX_PIN_REG(MX53_PAD_LVDS1_TX1_P, NO_PAD, 0x1F8, 1, 0x000, 0), /* MX53_PAD_LVDS1_TX1_P__LDB_LVDS1_TX1 */ + IMX_PIN_REG(MX53_PAD_LVDS1_TX0_P, NO_PAD, 0x1FC, 0, 0x000, 0), /* MX53_PAD_LVDS1_TX0_P__GPIO6_30 */ + IMX_PIN_REG(MX53_PAD_LVDS1_TX0_P, NO_PAD, 0x1FC, 1, 0x000, 0), /* MX53_PAD_LVDS1_TX0_P__LDB_LVDS1_TX0 */ + IMX_PIN_REG(MX53_PAD_LVDS0_TX3_P, NO_PAD, 0x200, 0, 0x000, 0), /* MX53_PAD_LVDS0_TX3_P__GPIO7_22 */ + IMX_PIN_REG(MX53_PAD_LVDS0_TX3_P, NO_PAD, 0x200, 1, 0x000, 0), /* MX53_PAD_LVDS0_TX3_P__LDB_LVDS0_TX3 */ + IMX_PIN_REG(MX53_PAD_LVDS0_CLK_P, NO_PAD, 0x204, 0, 0x000, 0), /* MX53_PAD_LVDS0_CLK_P__GPIO7_24 */ + IMX_PIN_REG(MX53_PAD_LVDS0_CLK_P, NO_PAD, 0x204, 1, 0x000, 0), /* MX53_PAD_LVDS0_CLK_P__LDB_LVDS0_CLK */ + IMX_PIN_REG(MX53_PAD_LVDS0_TX2_P, NO_PAD, 0x208, 0, 0x000, 0), /* MX53_PAD_LVDS0_TX2_P__GPIO7_26 */ + IMX_PIN_REG(MX53_PAD_LVDS0_TX2_P, NO_PAD, 0x208, 1, 0x000, 0), /* MX53_PAD_LVDS0_TX2_P__LDB_LVDS0_TX2 */ + IMX_PIN_REG(MX53_PAD_LVDS0_TX1_P, NO_PAD, 0x20C, 0, 0x000, 0), /* MX53_PAD_LVDS0_TX1_P__GPIO7_28 */ + IMX_PIN_REG(MX53_PAD_LVDS0_TX1_P, NO_PAD, 0x20C, 1, 0x000, 0), /* MX53_PAD_LVDS0_TX1_P__LDB_LVDS0_TX1 */ + IMX_PIN_REG(MX53_PAD_LVDS0_TX0_P, NO_PAD, 0x210, 0, 0x000, 0), /* MX53_PAD_LVDS0_TX0_P__GPIO7_30 */ + IMX_PIN_REG(MX53_PAD_LVDS0_TX0_P, NO_PAD, 0x210, 1, 0x000, 0), /* MX53_PAD_LVDS0_TX0_P__LDB_LVDS0_TX0 */ + IMX_PIN_REG(MX53_PAD_GPIO_10, 0x540, 0x214, 0, 0x000, 0), /* MX53_PAD_GPIO_10__GPIO4_0 */ + IMX_PIN_REG(MX53_PAD_GPIO_10, 0x540, 0x214, 1, 0x000, 0), /* MX53_PAD_GPIO_10__OSC32k_32K_OUT */ + IMX_PIN_REG(MX53_PAD_GPIO_11, 0x544, 0x218, 0, 0x000, 0), /* MX53_PAD_GPIO_11__GPIO4_1 */ + IMX_PIN_REG(MX53_PAD_GPIO_12, 0x548, 0x21C, 0, 0x000, 0), /* MX53_PAD_GPIO_12__GPIO4_2 */ + IMX_PIN_REG(MX53_PAD_GPIO_13, 0x54C, 0x220, 0, 0x000, 0), /* MX53_PAD_GPIO_13__GPIO4_3 */ + IMX_PIN_REG(MX53_PAD_GPIO_14, 0x550, 0x224, 0, 0x000, 0), /* MX53_PAD_GPIO_14__GPIO4_4 */ + IMX_PIN_REG(MX53_PAD_NANDF_CLE, 0x5A0, 0x228, 0, 0x000, 0), /* MX53_PAD_NANDF_CLE__EMI_NANDF_CLE */ + IMX_PIN_REG(MX53_PAD_NANDF_CLE, 0x5A0, 0x228, 1, 0x000, 0), /* MX53_PAD_NANDF_CLE__GPIO6_7 */ + IMX_PIN_REG(MX53_PAD_NANDF_CLE, 0x5A0, 0x228, 7, 0x000, 0), /* MX53_PAD_NANDF_CLE__USBPHY1_VSTATUS_0 */ + IMX_PIN_REG(MX53_PAD_NANDF_ALE, 0x5A4, 0x22C, 0, 0x000, 0), /* MX53_PAD_NANDF_ALE__EMI_NANDF_ALE */ + IMX_PIN_REG(MX53_PAD_NANDF_ALE, 0x5A4, 0x22C, 1, 0x000, 0), /* MX53_PAD_NANDF_ALE__GPIO6_8 */ + IMX_PIN_REG(MX53_PAD_NANDF_ALE, 0x5A4, 0x22C, 7, 0x000, 0), /* MX53_PAD_NANDF_ALE__USBPHY1_VSTATUS_1 */ + IMX_PIN_REG(MX53_PAD_NANDF_WP_B, 0x5A8, 0x230, 0, 0x000, 0), /* MX53_PAD_NANDF_WP_B__EMI_NANDF_WP_B */ + IMX_PIN_REG(MX53_PAD_NANDF_WP_B, 0x5A8, 0x230, 1, 0x000, 0), /* MX53_PAD_NANDF_WP_B__GPIO6_9 */ + IMX_PIN_REG(MX53_PAD_NANDF_WP_B, 0x5A8, 0x230, 7, 0x000, 0), /* MX53_PAD_NANDF_WP_B__USBPHY1_VSTATUS_2 */ + IMX_PIN_REG(MX53_PAD_NANDF_RB0, 0x5AC, 0x234, 0, 0x000, 0), /* MX53_PAD_NANDF_RB0__EMI_NANDF_RB_0 */ + IMX_PIN_REG(MX53_PAD_NANDF_RB0, 0x5AC, 0x234, 1, 0x000, 0), /* MX53_PAD_NANDF_RB0__GPIO6_10 */ + IMX_PIN_REG(MX53_PAD_NANDF_RB0, 0x5AC, 0x234, 7, 0x000, 0), /* MX53_PAD_NANDF_RB0__USBPHY1_VSTATUS_3 */ + IMX_PIN_REG(MX53_PAD_NANDF_CS0, 0x5B0, 0x238, 0, 0x000, 0), /* MX53_PAD_NANDF_CS0__EMI_NANDF_CS_0 */ + IMX_PIN_REG(MX53_PAD_NANDF_CS0, 0x5B0, 0x238, 1, 0x000, 0), /* MX53_PAD_NANDF_CS0__GPIO6_11 */ + IMX_PIN_REG(MX53_PAD_NANDF_CS0, 0x5B0, 0x238, 7, 0x000, 0), /* MX53_PAD_NANDF_CS0__USBPHY1_VSTATUS_4 */ + IMX_PIN_REG(MX53_PAD_NANDF_CS1, 0x5B4, 0x23C, 0, 0x000, 0), /* MX53_PAD_NANDF_CS1__EMI_NANDF_CS_1 */ + IMX_PIN_REG(MX53_PAD_NANDF_CS1, 0x5B4, 0x23C, 1, 0x000, 0), /* MX53_PAD_NANDF_CS1__GPIO6_14 */ + IMX_PIN_REG(MX53_PAD_NANDF_CS1, 0x5B4, 0x23C, 6, 0x858, 0), /* MX53_PAD_NANDF_CS1__MLB_MLBCLK */ + IMX_PIN_REG(MX53_PAD_NANDF_CS1, 0x5B4, 0x23C, 7, 0x000, 0), /* MX53_PAD_NANDF_CS1__USBPHY1_VSTATUS_5 */ + IMX_PIN_REG(MX53_PAD_NANDF_CS2, 0x5B8, 0x240, 0, 0x000, 0), /* MX53_PAD_NANDF_CS2__EMI_NANDF_CS_2 */ + IMX_PIN_REG(MX53_PAD_NANDF_CS2, 0x5B8, 0x240, 1, 0x000, 0), /* MX53_PAD_NANDF_CS2__GPIO6_15 */ + IMX_PIN_REG(MX53_PAD_NANDF_CS2, 0x5B8, 0x240, 2, 0x000, 0), /* MX53_PAD_NANDF_CS2__IPU_SISG_0 */ + IMX_PIN_REG(MX53_PAD_NANDF_CS2, 0x5B8, 0x240, 3, 0x7E4, 0), /* MX53_PAD_NANDF_CS2__ESAI1_TX0 */ + IMX_PIN_REG(MX53_PAD_NANDF_CS2, 0x5B8, 0x240, 4, 0x000, 0), /* MX53_PAD_NANDF_CS2__EMI_WEIM_CRE */ + IMX_PIN_REG(MX53_PAD_NANDF_CS2, 0x5B8, 0x240, 5, 0x000, 0), /* MX53_PAD_NANDF_CS2__CCM_CSI0_MCLK */ + IMX_PIN_REG(MX53_PAD_NANDF_CS2, 0x5B8, 0x240, 6, 0x860, 0), /* MX53_PAD_NANDF_CS2__MLB_MLBSIG */ + IMX_PIN_REG(MX53_PAD_NANDF_CS2, 0x5B8, 0x240, 7, 0x000, 0), /* MX53_PAD_NANDF_CS2__USBPHY1_VSTATUS_6 */ + IMX_PIN_REG(MX53_PAD_NANDF_CS3, 0x5BC, 0x244, 0, 0x000, 0), /* MX53_PAD_NANDF_CS3__EMI_NANDF_CS_3 */ + IMX_PIN_REG(MX53_PAD_NANDF_CS3, 0x5BC, 0x244, 1, 0x000, 0), /* MX53_PAD_NANDF_CS3__GPIO6_16 */ + IMX_PIN_REG(MX53_PAD_NANDF_CS3, 0x5BC, 0x244, 2, 0x000, 0), /* MX53_PAD_NANDF_CS3__IPU_SISG_1 */ + IMX_PIN_REG(MX53_PAD_NANDF_CS3, 0x5BC, 0x244, 3, 0x7E8, 0), /* MX53_PAD_NANDF_CS3__ESAI1_TX1 */ + IMX_PIN_REG(MX53_PAD_NANDF_CS3, 0x5BC, 0x244, 4, 0x000, 0), /* MX53_PAD_NANDF_CS3__EMI_WEIM_A_26 */ + IMX_PIN_REG(MX53_PAD_NANDF_CS3, 0x5BC, 0x244, 6, 0x85C, 0), /* MX53_PAD_NANDF_CS3__MLB_MLBDAT */ + IMX_PIN_REG(MX53_PAD_NANDF_CS3, 0x5BC, 0x244, 7, 0x000, 0), /* MX53_PAD_NANDF_CS3__USBPHY1_VSTATUS_7 */ + IMX_PIN_REG(MX53_PAD_FEC_MDIO, 0x5C4, 0x248, 0, 0x804, 1), /* MX53_PAD_FEC_MDIO__FEC_MDIO */ + IMX_PIN_REG(MX53_PAD_FEC_MDIO, 0x5C4, 0x248, 1, 0x000, 0), /* MX53_PAD_FEC_MDIO__GPIO1_22 */ + IMX_PIN_REG(MX53_PAD_FEC_MDIO, 0x5C4, 0x248, 2, 0x7DC, 0), /* MX53_PAD_FEC_MDIO__ESAI1_SCKR */ + IMX_PIN_REG(MX53_PAD_FEC_MDIO, 0x5C4, 0x248, 3, 0x800, 1), /* MX53_PAD_FEC_MDIO__FEC_COL */ + IMX_PIN_REG(MX53_PAD_FEC_MDIO, 0x5C4, 0x248, 4, 0x000, 0), /* MX53_PAD_FEC_MDIO__RTC_CE_RTC_PS2 */ + IMX_PIN_REG(MX53_PAD_FEC_MDIO, 0x5C4, 0x248, 5, 0x000, 0), /* MX53_PAD_FEC_MDIO__SDMA_DEBUG_BUS_DEVICE_3 */ + IMX_PIN_REG(MX53_PAD_FEC_MDIO, 0x5C4, 0x248, 6, 0x000, 0), /* MX53_PAD_FEC_MDIO__EMI_EMI_DEBUG_49 */ + IMX_PIN_REG(MX53_PAD_FEC_REF_CLK, 0x5C8, 0x24C, 0, 0x000, 0), /* MX53_PAD_FEC_REF_CLK__FEC_TX_CLK */ + IMX_PIN_REG(MX53_PAD_FEC_REF_CLK, 0x5C8, 0x24C, 1, 0x000, 0), /* MX53_PAD_FEC_REF_CLK__GPIO1_23 */ + IMX_PIN_REG(MX53_PAD_FEC_REF_CLK, 0x5C8, 0x24C, 2, 0x7CC, 0), /* MX53_PAD_FEC_REF_CLK__ESAI1_FSR */ + IMX_PIN_REG(MX53_PAD_FEC_REF_CLK, 0x5C8, 0x24C, 5, 0x000, 0), /* MX53_PAD_FEC_REF_CLK__SDMA_DEBUG_BUS_DEVICE_4 */ + IMX_PIN_REG(MX53_PAD_FEC_REF_CLK, 0x5C8, 0x24C, 6, 0x000, 0), /* MX53_PAD_FEC_REF_CLK__EMI_EMI_DEBUG_50 */ + IMX_PIN_REG(MX53_PAD_FEC_RX_ER, 0x5CC, 0x250, 0, 0x000, 0), /* MX53_PAD_FEC_RX_ER__FEC_RX_ER */ + IMX_PIN_REG(MX53_PAD_FEC_RX_ER, 0x5CC, 0x250, 1, 0x000, 0), /* MX53_PAD_FEC_RX_ER__GPIO1_24 */ + IMX_PIN_REG(MX53_PAD_FEC_RX_ER, 0x5CC, 0x250, 2, 0x7D4, 0), /* MX53_PAD_FEC_RX_ER__ESAI1_HCKR */ + IMX_PIN_REG(MX53_PAD_FEC_RX_ER, 0x5CC, 0x250, 3, 0x808, 1), /* MX53_PAD_FEC_RX_ER__FEC_RX_CLK */ + IMX_PIN_REG(MX53_PAD_FEC_RX_ER, 0x5CC, 0x250, 4, 0x000, 0), /* MX53_PAD_FEC_RX_ER__RTC_CE_RTC_PS3 */ + IMX_PIN_REG(MX53_PAD_FEC_CRS_DV, 0x5D0, 0x254, 0, 0x000, 0), /* MX53_PAD_FEC_CRS_DV__FEC_RX_DV */ + IMX_PIN_REG(MX53_PAD_FEC_CRS_DV, 0x5D0, 0x254, 1, 0x000, 0), /* MX53_PAD_FEC_CRS_DV__GPIO1_25 */ + IMX_PIN_REG(MX53_PAD_FEC_CRS_DV, 0x5D0, 0x254, 2, 0x7E0, 0), /* MX53_PAD_FEC_CRS_DV__ESAI1_SCKT */ + IMX_PIN_REG(MX53_PAD_FEC_RXD1, 0x5D4, 0x258, 0, 0x000, 0), /* MX53_PAD_FEC_RXD1__FEC_RDATA_1 */ + IMX_PIN_REG(MX53_PAD_FEC_RXD1, 0x5D4, 0x258, 1, 0x000, 0), /* MX53_PAD_FEC_RXD1__GPIO1_26 */ + IMX_PIN_REG(MX53_PAD_FEC_RXD1, 0x5D4, 0x258, 2, 0x7D0, 0), /* MX53_PAD_FEC_RXD1__ESAI1_FST */ + IMX_PIN_REG(MX53_PAD_FEC_RXD1, 0x5D4, 0x258, 3, 0x860, 1), /* MX53_PAD_FEC_RXD1__MLB_MLBSIG */ + IMX_PIN_REG(MX53_PAD_FEC_RXD1, 0x5D4, 0x258, 4, 0x000, 0), /* MX53_PAD_FEC_RXD1__RTC_CE_RTC_PS1 */ + IMX_PIN_REG(MX53_PAD_FEC_RXD0, 0x5D8, 0x25C, 0, 0x000, 0), /* MX53_PAD_FEC_RXD0__FEC_RDATA_0 */ + IMX_PIN_REG(MX53_PAD_FEC_RXD0, 0x5D8, 0x25C, 1, 0x000, 0), /* MX53_PAD_FEC_RXD0__GPIO1_27 */ + IMX_PIN_REG(MX53_PAD_FEC_RXD0, 0x5D8, 0x25C, 2, 0x7D8, 0), /* MX53_PAD_FEC_RXD0__ESAI1_HCKT */ + IMX_PIN_REG(MX53_PAD_FEC_RXD0, 0x5D8, 0x25C, 3, 0x000, 0), /* MX53_PAD_FEC_RXD0__OSC32k_32K_OUT */ + IMX_PIN_REG(MX53_PAD_FEC_TX_EN, 0x5DC, 0x260, 0, 0x000, 0), /* MX53_PAD_FEC_TX_EN__FEC_TX_EN */ + IMX_PIN_REG(MX53_PAD_FEC_TX_EN, 0x5DC, 0x260, 1, 0x000, 0), /* MX53_PAD_FEC_TX_EN__GPIO1_28 */ + IMX_PIN_REG(MX53_PAD_FEC_TX_EN, 0x5DC, 0x260, 2, 0x7F0, 0), /* MX53_PAD_FEC_TX_EN__ESAI1_TX3_RX2 */ + IMX_PIN_REG(MX53_PAD_FEC_TXD1, 0x5E0, 0x264, 0, 0x000, 0), /* MX53_PAD_FEC_TXD1__FEC_TDATA_1 */ + IMX_PIN_REG(MX53_PAD_FEC_TXD1, 0x5E0, 0x264, 1, 0x000, 0), /* MX53_PAD_FEC_TXD1__GPIO1_29 */ + IMX_PIN_REG(MX53_PAD_FEC_TXD1, 0x5E0, 0x264, 2, 0x7EC, 0), /* MX53_PAD_FEC_TXD1__ESAI1_TX2_RX3 */ + IMX_PIN_REG(MX53_PAD_FEC_TXD1, 0x5E0, 0x264, 3, 0x858, 1), /* MX53_PAD_FEC_TXD1__MLB_MLBCLK */ + IMX_PIN_REG(MX53_PAD_FEC_TXD1, 0x5E0, 0x264, 4, 0x000, 0), /* MX53_PAD_FEC_TXD1__RTC_CE_RTC_PRSC_CLK */ + IMX_PIN_REG(MX53_PAD_FEC_TXD0, 0x5E4, 0x268, 0, 0x000, 0), /* MX53_PAD_FEC_TXD0__FEC_TDATA_0 */ + IMX_PIN_REG(MX53_PAD_FEC_TXD0, 0x5E4, 0x268, 1, 0x000, 0), /* MX53_PAD_FEC_TXD0__GPIO1_30 */ + IMX_PIN_REG(MX53_PAD_FEC_TXD0, 0x5E4, 0x268, 2, 0x7F4, 0), /* MX53_PAD_FEC_TXD0__ESAI1_TX4_RX1 */ + IMX_PIN_REG(MX53_PAD_FEC_TXD0, 0x5E4, 0x268, 7, 0x000, 0), /* MX53_PAD_FEC_TXD0__USBPHY2_DATAOUT_0 */ + IMX_PIN_REG(MX53_PAD_FEC_MDC, 0x5E8, 0x26C, 0, 0x000, 0), /* MX53_PAD_FEC_MDC__FEC_MDC */ + IMX_PIN_REG(MX53_PAD_FEC_MDC, 0x5E8, 0x26C, 1, 0x000, 0), /* MX53_PAD_FEC_MDC__GPIO1_31 */ + IMX_PIN_REG(MX53_PAD_FEC_MDC, 0x5E8, 0x26C, 2, 0x7F8, 0), /* MX53_PAD_FEC_MDC__ESAI1_TX5_RX0 */ + IMX_PIN_REG(MX53_PAD_FEC_MDC, 0x5E8, 0x26C, 3, 0x85C, 1), /* MX53_PAD_FEC_MDC__MLB_MLBDAT */ + IMX_PIN_REG(MX53_PAD_FEC_MDC, 0x5E8, 0x26C, 4, 0x000, 0), /* MX53_PAD_FEC_MDC__RTC_CE_RTC_ALARM1_TRIG */ + IMX_PIN_REG(MX53_PAD_FEC_MDC, 0x5E8, 0x26C, 7, 0x000, 0), /* MX53_PAD_FEC_MDC__USBPHY2_DATAOUT_1 */ + IMX_PIN_REG(MX53_PAD_PATA_DIOW, 0x5F0, 0x270, 0, 0x000, 0), /* MX53_PAD_PATA_DIOW__PATA_DIOW */ + IMX_PIN_REG(MX53_PAD_PATA_DIOW, 0x5F0, 0x270, 1, 0x000, 0), /* MX53_PAD_PATA_DIOW__GPIO6_17 */ + IMX_PIN_REG(MX53_PAD_PATA_DIOW, 0x5F0, 0x270, 3, 0x000, 0), /* MX53_PAD_PATA_DIOW__UART1_TXD_MUX */ + IMX_PIN_REG(MX53_PAD_PATA_DIOW, 0x5F0, 0x270, 7, 0x000, 0), /* MX53_PAD_PATA_DIOW__USBPHY2_DATAOUT_2 */ + IMX_PIN_REG(MX53_PAD_PATA_DMACK, 0x5F4, 0x274, 0, 0x000, 0), /* MX53_PAD_PATA_DMACK__PATA_DMACK */ + IMX_PIN_REG(MX53_PAD_PATA_DMACK, 0x5F4, 0x274, 1, 0x000, 0), /* MX53_PAD_PATA_DMACK__GPIO6_18 */ + IMX_PIN_REG(MX53_PAD_PATA_DMACK, 0x5F4, 0x274, 3, 0x878, 3), /* MX53_PAD_PATA_DMACK__UART1_RXD_MUX */ + IMX_PIN_REG(MX53_PAD_PATA_DMACK, 0x5F4, 0x274, 7, 0x000, 0), /* MX53_PAD_PATA_DMACK__USBPHY2_DATAOUT_3 */ + IMX_PIN_REG(MX53_PAD_PATA_DMARQ, 0x5F8, 0x278, 0, 0x000, 0), /* MX53_PAD_PATA_DMARQ__PATA_DMARQ */ + IMX_PIN_REG(MX53_PAD_PATA_DMARQ, 0x5F8, 0x278, 1, 0x000, 0), /* MX53_PAD_PATA_DMARQ__GPIO7_0 */ + IMX_PIN_REG(MX53_PAD_PATA_DMARQ, 0x5F8, 0x278, 3, 0x000, 0), /* MX53_PAD_PATA_DMARQ__UART2_TXD_MUX */ + IMX_PIN_REG(MX53_PAD_PATA_DMARQ, 0x5F8, 0x278, 5, 0x000, 0), /* MX53_PAD_PATA_DMARQ__CCM_CCM_OUT_0 */ + IMX_PIN_REG(MX53_PAD_PATA_DMARQ, 0x5F8, 0x278, 7, 0x000, 0), /* MX53_PAD_PATA_DMARQ__USBPHY2_DATAOUT_4 */ + IMX_PIN_REG(MX53_PAD_PATA_BUFFER_EN, 0x5FC, 0x27C, 0, 0x000, 0), /* MX53_PAD_PATA_BUFFER_EN__PATA_BUFFER_EN */ + IMX_PIN_REG(MX53_PAD_PATA_BUFFER_EN, 0x5FC, 0x27C, 1, 0x000, 0), /* MX53_PAD_PATA_BUFFER_EN__GPIO7_1 */ + IMX_PIN_REG(MX53_PAD_PATA_BUFFER_EN, 0x5FC, 0x27C, 3, 0x880, 3), /* MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX */ + IMX_PIN_REG(MX53_PAD_PATA_BUFFER_EN, 0x5FC, 0x27C, 5, 0x000, 0), /* MX53_PAD_PATA_BUFFER_EN__CCM_CCM_OUT_1 */ + IMX_PIN_REG(MX53_PAD_PATA_BUFFER_EN, 0x5FC, 0x27C, 7, 0x000, 0), /* MX53_PAD_PATA_BUFFER_EN__USBPHY2_DATAOUT_5 */ + IMX_PIN_REG(MX53_PAD_PATA_INTRQ, 0x600, 0x280, 0, 0x000, 0), /* MX53_PAD_PATA_INTRQ__PATA_INTRQ */ + IMX_PIN_REG(MX53_PAD_PATA_INTRQ, 0x600, 0x280, 1, 0x000, 0), /* MX53_PAD_PATA_INTRQ__GPIO7_2 */ + IMX_PIN_REG(MX53_PAD_PATA_INTRQ, 0x600, 0x280, 3, 0x000, 0), /* MX53_PAD_PATA_INTRQ__UART2_CTS */ + IMX_PIN_REG(MX53_PAD_PATA_INTRQ, 0x600, 0x280, 4, 0x000, 0), /* MX53_PAD_PATA_INTRQ__CAN1_TXCAN */ + IMX_PIN_REG(MX53_PAD_PATA_INTRQ, 0x600, 0x280, 5, 0x000, 0), /* MX53_PAD_PATA_INTRQ__CCM_CCM_OUT_2 */ + IMX_PIN_REG(MX53_PAD_PATA_INTRQ, 0x600, 0x280, 7, 0x000, 0), /* MX53_PAD_PATA_INTRQ__USBPHY2_DATAOUT_6 */ + IMX_PIN_REG(MX53_PAD_PATA_DIOR, 0x604, 0x284, 0, 0x000, 0), /* MX53_PAD_PATA_DIOR__PATA_DIOR */ + IMX_PIN_REG(MX53_PAD_PATA_DIOR, 0x604, 0x284, 1, 0x000, 0), /* MX53_PAD_PATA_DIOR__GPIO7_3 */ + IMX_PIN_REG(MX53_PAD_PATA_DIOR, 0x604, 0x284, 3, 0x87C, 3), /* MX53_PAD_PATA_DIOR__UART2_RTS */ + IMX_PIN_REG(MX53_PAD_PATA_DIOR, 0x604, 0x284, 4, 0x760, 1), /* MX53_PAD_PATA_DIOR__CAN1_RXCAN */ + IMX_PIN_REG(MX53_PAD_PATA_DIOR, 0x604, 0x284, 7, 0x000, 0), /* MX53_PAD_PATA_DIOR__USBPHY2_DATAOUT_7 */ + IMX_PIN_REG(MX53_PAD_PATA_RESET_B, 0x608, 0x288, 0, 0x000, 0), /* MX53_PAD_PATA_RESET_B__PATA_PATA_RESET_B */ + IMX_PIN_REG(MX53_PAD_PATA_RESET_B, 0x608, 0x288, 1, 0x000, 0), /* MX53_PAD_PATA_RESET_B__GPIO7_4 */ + IMX_PIN_REG(MX53_PAD_PATA_RESET_B, 0x608, 0x288, 2, 0x000, 0), /* MX53_PAD_PATA_RESET_B__ESDHC3_CMD */ + IMX_PIN_REG(MX53_PAD_PATA_RESET_B, 0x608, 0x288, 3, 0x000, 0), /* MX53_PAD_PATA_RESET_B__UART1_CTS */ + IMX_PIN_REG(MX53_PAD_PATA_RESET_B, 0x608, 0x288, 4, 0x000, 0), /* MX53_PAD_PATA_RESET_B__CAN2_TXCAN */ + IMX_PIN_REG(MX53_PAD_PATA_RESET_B, 0x608, 0x288, 7, 0x000, 0), /* MX53_PAD_PATA_RESET_B__USBPHY1_DATAOUT_0 */ + IMX_PIN_REG(MX53_PAD_PATA_IORDY, 0x60C, 0x28C, 0, 0x000, 0), /* MX53_PAD_PATA_IORDY__PATA_IORDY */ + IMX_PIN_REG(MX53_PAD_PATA_IORDY, 0x60C, 0x28C, 1, 0x000, 0), /* MX53_PAD_PATA_IORDY__GPIO7_5 */ + IMX_PIN_REG(MX53_PAD_PATA_IORDY, 0x60C, 0x28C, 2, 0x000, 0), /* MX53_PAD_PATA_IORDY__ESDHC3_CLK */ + IMX_PIN_REG(MX53_PAD_PATA_IORDY, 0x60C, 0x28C, 3, 0x874, 3), /* MX53_PAD_PATA_IORDY__UART1_RTS */ + IMX_PIN_REG(MX53_PAD_PATA_IORDY, 0x60C, 0x28C, 4, 0x764, 1), /* MX53_PAD_PATA_IORDY__CAN2_RXCAN */ + IMX_PIN_REG(MX53_PAD_PATA_IORDY, 0x60C, 0x28C, 7, 0x000, 0), /* MX53_PAD_PATA_IORDY__USBPHY1_DATAOUT_1 */ + IMX_PIN_REG(MX53_PAD_PATA_DA_0, 0x610, 0x290, 0, 0x000, 0), /* MX53_PAD_PATA_DA_0__PATA_DA_0 */ + IMX_PIN_REG(MX53_PAD_PATA_DA_0, 0x610, 0x290, 1, 0x000, 0), /* MX53_PAD_PATA_DA_0__GPIO7_6 */ + IMX_PIN_REG(MX53_PAD_PATA_DA_0, 0x610, 0x290, 2, 0x000, 0), /* MX53_PAD_PATA_DA_0__ESDHC3_RST */ + IMX_PIN_REG(MX53_PAD_PATA_DA_0, 0x610, 0x290, 4, 0x864, 0), /* MX53_PAD_PATA_DA_0__OWIRE_LINE */ + IMX_PIN_REG(MX53_PAD_PATA_DA_0, 0x610, 0x290, 7, 0x000, 0), /* MX53_PAD_PATA_DA_0__USBPHY1_DATAOUT_2 */ + IMX_PIN_REG(MX53_PAD_PATA_DA_1, 0x614, 0x294, 0, 0x000, 0), /* MX53_PAD_PATA_DA_1__PATA_DA_1 */ + IMX_PIN_REG(MX53_PAD_PATA_DA_1, 0x614, 0x294, 1, 0x000, 0), /* MX53_PAD_PATA_DA_1__GPIO7_7 */ + IMX_PIN_REG(MX53_PAD_PATA_DA_1, 0x614, 0x294, 2, 0x000, 0), /* MX53_PAD_PATA_DA_1__ESDHC4_CMD */ + IMX_PIN_REG(MX53_PAD_PATA_DA_1, 0x614, 0x294, 4, 0x000, 0), /* MX53_PAD_PATA_DA_1__UART3_CTS */ + IMX_PIN_REG(MX53_PAD_PATA_DA_1, 0x614, 0x294, 7, 0x000, 0), /* MX53_PAD_PATA_DA_1__USBPHY1_DATAOUT_3 */ + IMX_PIN_REG(MX53_PAD_PATA_DA_2, 0x618, 0x298, 0, 0x000, 0), /* MX53_PAD_PATA_DA_2__PATA_DA_2 */ + IMX_PIN_REG(MX53_PAD_PATA_DA_2, 0x618, 0x298, 1, 0x000, 0), /* MX53_PAD_PATA_DA_2__GPIO7_8 */ + IMX_PIN_REG(MX53_PAD_PATA_DA_2, 0x618, 0x298, 2, 0x000, 0), /* MX53_PAD_PATA_DA_2__ESDHC4_CLK */ + IMX_PIN_REG(MX53_PAD_PATA_DA_2, 0x618, 0x298, 4, 0x884, 5), /* MX53_PAD_PATA_DA_2__UART3_RTS */ + IMX_PIN_REG(MX53_PAD_PATA_DA_2, 0x618, 0x298, 7, 0x000, 0), /* MX53_PAD_PATA_DA_2__USBPHY1_DATAOUT_4 */ + IMX_PIN_REG(MX53_PAD_PATA_CS_0, 0x61C, 0x29C, 0, 0x000, 0), /* MX53_PAD_PATA_CS_0__PATA_CS_0 */ + IMX_PIN_REG(MX53_PAD_PATA_CS_0, 0x61C, 0x29C, 1, 0x000, 0), /* MX53_PAD_PATA_CS_0__GPIO7_9 */ + IMX_PIN_REG(MX53_PAD_PATA_CS_0, 0x61C, 0x29C, 4, 0x000, 0), /* MX53_PAD_PATA_CS_0__UART3_TXD_MUX */ + IMX_PIN_REG(MX53_PAD_PATA_CS_0, 0x61C, 0x29C, 7, 0x000, 0), /* MX53_PAD_PATA_CS_0__USBPHY1_DATAOUT_5 */ + IMX_PIN_REG(MX53_PAD_PATA_CS_1, 0x620, 0x2A0, 0, 0x000, 0), /* MX53_PAD_PATA_CS_1__PATA_CS_1 */ + IMX_PIN_REG(MX53_PAD_PATA_CS_1, 0x620, 0x2A0, 1, 0x000, 0), /* MX53_PAD_PATA_CS_1__GPIO7_10 */ + IMX_PIN_REG(MX53_PAD_PATA_CS_1, 0x620, 0x2A0, 4, 0x888, 3), /* MX53_PAD_PATA_CS_1__UART3_RXD_MUX */ + IMX_PIN_REG(MX53_PAD_PATA_CS_1, 0x620, 0x2A0, 7, 0x000, 0), /* MX53_PAD_PATA_CS_1__USBPHY1_DATAOUT_6 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA0, 0x628, 0x2A4, 0, 0x000, 0), /* MX53_PAD_PATA_DATA0__PATA_DATA_0 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA0, 0x628, 0x2A4, 1, 0x000, 0), /* MX53_PAD_PATA_DATA0__GPIO2_0 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA0, 0x628, 0x2A4, 3, 0x000, 0), /* MX53_PAD_PATA_DATA0__EMI_NANDF_D_0 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA0, 0x628, 0x2A4, 4, 0x000, 0), /* MX53_PAD_PATA_DATA0__ESDHC3_DAT4 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA0, 0x628, 0x2A4, 5, 0x000, 0), /* MX53_PAD_PATA_DATA0__GPU3d_GPU_DEBUG_OUT_0 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA0, 0x628, 0x2A4, 6, 0x000, 0), /* MX53_PAD_PATA_DATA0__IPU_DIAG_BUS_0 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA0, 0x628, 0x2A4, 7, 0x000, 0), /* MX53_PAD_PATA_DATA0__USBPHY1_DATAOUT_7 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA1, 0x62C, 0x2A8, 0, 0x000, 0), /* MX53_PAD_PATA_DATA1__PATA_DATA_1 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA1, 0x62C, 0x2A8, 1, 0x000, 0), /* MX53_PAD_PATA_DATA1__GPIO2_1 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA1, 0x62C, 0x2A8, 3, 0x000, 0), /* MX53_PAD_PATA_DATA1__EMI_NANDF_D_1 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA1, 0x62C, 0x2A8, 4, 0x000, 0), /* MX53_PAD_PATA_DATA1__ESDHC3_DAT5 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA1, 0x62C, 0x2A8, 5, 0x000, 0), /* MX53_PAD_PATA_DATA1__GPU3d_GPU_DEBUG_OUT_1 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA1, 0x62C, 0x2A8, 6, 0x000, 0), /* MX53_PAD_PATA_DATA1__IPU_DIAG_BUS_1 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA2, 0x630, 0x2AC, 0, 0x000, 0), /* MX53_PAD_PATA_DATA2__PATA_DATA_2 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA2, 0x630, 0x2AC, 1, 0x000, 0), /* MX53_PAD_PATA_DATA2__GPIO2_2 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA2, 0x630, 0x2AC, 3, 0x000, 0), /* MX53_PAD_PATA_DATA2__EMI_NANDF_D_2 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA2, 0x630, 0x2AC, 4, 0x000, 0), /* MX53_PAD_PATA_DATA2__ESDHC3_DAT6 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA2, 0x630, 0x2AC, 5, 0x000, 0), /* MX53_PAD_PATA_DATA2__GPU3d_GPU_DEBUG_OUT_2 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA2, 0x630, 0x2AC, 6, 0x000, 0), /* MX53_PAD_PATA_DATA2__IPU_DIAG_BUS_2 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA3, 0x634, 0x2B0, 0, 0x000, 0), /* MX53_PAD_PATA_DATA3__PATA_DATA_3 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA3, 0x634, 0x2B0, 1, 0x000, 0), /* MX53_PAD_PATA_DATA3__GPIO2_3 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA3, 0x634, 0x2B0, 3, 0x000, 0), /* MX53_PAD_PATA_DATA3__EMI_NANDF_D_3 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA3, 0x634, 0x2B0, 4, 0x000, 0), /* MX53_PAD_PATA_DATA3__ESDHC3_DAT7 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA3, 0x634, 0x2B0, 5, 0x000, 0), /* MX53_PAD_PATA_DATA3__GPU3d_GPU_DEBUG_OUT_3 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA3, 0x634, 0x2B0, 6, 0x000, 0), /* MX53_PAD_PATA_DATA3__IPU_DIAG_BUS_3 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA4, 0x638, 0x2B4, 0, 0x000, 0), /* MX53_PAD_PATA_DATA4__PATA_DATA_4 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA4, 0x638, 0x2B4, 1, 0x000, 0), /* MX53_PAD_PATA_DATA4__GPIO2_4 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA4, 0x638, 0x2B4, 3, 0x000, 0), /* MX53_PAD_PATA_DATA4__EMI_NANDF_D_4 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA4, 0x638, 0x2B4, 4, 0x000, 0), /* MX53_PAD_PATA_DATA4__ESDHC4_DAT4 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA4, 0x638, 0x2B4, 5, 0x000, 0), /* MX53_PAD_PATA_DATA4__GPU3d_GPU_DEBUG_OUT_4 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA4, 0x638, 0x2B4, 6, 0x000, 0), /* MX53_PAD_PATA_DATA4__IPU_DIAG_BUS_4 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA5, 0x63C, 0x2B8, 0, 0x000, 0), /* MX53_PAD_PATA_DATA5__PATA_DATA_5 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA5, 0x63C, 0x2B8, 1, 0x000, 0), /* MX53_PAD_PATA_DATA5__GPIO2_5 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA5, 0x63C, 0x2B8, 3, 0x000, 0), /* MX53_PAD_PATA_DATA5__EMI_NANDF_D_5 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA5, 0x63C, 0x2B8, 4, 0x000, 0), /* MX53_PAD_PATA_DATA5__ESDHC4_DAT5 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA5, 0x63C, 0x2B8, 5, 0x000, 0), /* MX53_PAD_PATA_DATA5__GPU3d_GPU_DEBUG_OUT_5 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA5, 0x63C, 0x2B8, 6, 0x000, 0), /* MX53_PAD_PATA_DATA5__IPU_DIAG_BUS_5 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA6, 0x640, 0x2BC, 0, 0x000, 0), /* MX53_PAD_PATA_DATA6__PATA_DATA_6 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA6, 0x640, 0x2BC, 1, 0x000, 0), /* MX53_PAD_PATA_DATA6__GPIO2_6 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA6, 0x640, 0x2BC, 3, 0x000, 0), /* MX53_PAD_PATA_DATA6__EMI_NANDF_D_6 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA6, 0x640, 0x2BC, 4, 0x000, 0), /* MX53_PAD_PATA_DATA6__ESDHC4_DAT6 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA6, 0x640, 0x2BC, 5, 0x000, 0), /* MX53_PAD_PATA_DATA6__GPU3d_GPU_DEBUG_OUT_6 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA6, 0x640, 0x2BC, 6, 0x000, 0), /* MX53_PAD_PATA_DATA6__IPU_DIAG_BUS_6 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA7, 0x644, 0x2C0, 0, 0x000, 0), /* MX53_PAD_PATA_DATA7__PATA_DATA_7 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA7, 0x644, 0x2C0, 1, 0x000, 0), /* MX53_PAD_PATA_DATA7__GPIO2_7 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA7, 0x644, 0x2C0, 3, 0x000, 0), /* MX53_PAD_PATA_DATA7__EMI_NANDF_D_7 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA7, 0x644, 0x2C0, 4, 0x000, 0), /* MX53_PAD_PATA_DATA7__ESDHC4_DAT7 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA7, 0x644, 0x2C0, 5, 0x000, 0), /* MX53_PAD_PATA_DATA7__GPU3d_GPU_DEBUG_OUT_7 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA7, 0x644, 0x2C0, 6, 0x000, 0), /* MX53_PAD_PATA_DATA7__IPU_DIAG_BUS_7 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA8, 0x648, 0x2C4, 0, 0x000, 0), /* MX53_PAD_PATA_DATA8__PATA_DATA_8 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA8, 0x648, 0x2C4, 1, 0x000, 0), /* MX53_PAD_PATA_DATA8__GPIO2_8 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA8, 0x648, 0x2C4, 2, 0x000, 0), /* MX53_PAD_PATA_DATA8__ESDHC1_DAT4 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA8, 0x648, 0x2C4, 3, 0x000, 0), /* MX53_PAD_PATA_DATA8__EMI_NANDF_D_8 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA8, 0x648, 0x2C4, 4, 0x000, 0), /* MX53_PAD_PATA_DATA8__ESDHC3_DAT0 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA8, 0x648, 0x2C4, 5, 0x000, 0), /* MX53_PAD_PATA_DATA8__GPU3d_GPU_DEBUG_OUT_8 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA8, 0x648, 0x2C4, 6, 0x000, 0), /* MX53_PAD_PATA_DATA8__IPU_DIAG_BUS_8 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA9, 0x64C, 0x2C8, 0, 0x000, 0), /* MX53_PAD_PATA_DATA9__PATA_DATA_9 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA9, 0x64C, 0x2C8, 1, 0x000, 0), /* MX53_PAD_PATA_DATA9__GPIO2_9 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA9, 0x64C, 0x2C8, 2, 0x000, 0), /* MX53_PAD_PATA_DATA9__ESDHC1_DAT5 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA9, 0x64C, 0x2C8, 3, 0x000, 0), /* MX53_PAD_PATA_DATA9__EMI_NANDF_D_9 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA9, 0x64C, 0x2C8, 4, 0x000, 0), /* MX53_PAD_PATA_DATA9__ESDHC3_DAT1 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA9, 0x64C, 0x2C8, 5, 0x000, 0), /* MX53_PAD_PATA_DATA9__GPU3d_GPU_DEBUG_OUT_9 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA9, 0x64C, 0x2C8, 6, 0x000, 0), /* MX53_PAD_PATA_DATA9__IPU_DIAG_BUS_9 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA10, 0x650, 0x2CC, 0, 0x000, 0), /* MX53_PAD_PATA_DATA10__PATA_DATA_10 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA10, 0x650, 0x2CC, 1, 0x000, 0), /* MX53_PAD_PATA_DATA10__GPIO2_10 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA10, 0x650, 0x2CC, 2, 0x000, 0), /* MX53_PAD_PATA_DATA10__ESDHC1_DAT6 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA10, 0x650, 0x2CC, 3, 0x000, 0), /* MX53_PAD_PATA_DATA10__EMI_NANDF_D_10 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA10, 0x650, 0x2CC, 4, 0x000, 0), /* MX53_PAD_PATA_DATA10__ESDHC3_DAT2 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA10, 0x650, 0x2CC, 5, 0x000, 0), /* MX53_PAD_PATA_DATA10__GPU3d_GPU_DEBUG_OUT_10 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA10, 0x650, 0x2CC, 6, 0x000, 0), /* MX53_PAD_PATA_DATA10__IPU_DIAG_BUS_10 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA11, 0x654, 0x2D0, 0, 0x000, 0), /* MX53_PAD_PATA_DATA11__PATA_DATA_11 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA11, 0x654, 0x2D0, 1, 0x000, 0), /* MX53_PAD_PATA_DATA11__GPIO2_11 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA11, 0x654, 0x2D0, 2, 0x000, 0), /* MX53_PAD_PATA_DATA11__ESDHC1_DAT7 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA11, 0x654, 0x2D0, 3, 0x000, 0), /* MX53_PAD_PATA_DATA11__EMI_NANDF_D_11 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA11, 0x654, 0x2D0, 4, 0x000, 0), /* MX53_PAD_PATA_DATA11__ESDHC3_DAT3 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA11, 0x654, 0x2D0, 5, 0x000, 0), /* MX53_PAD_PATA_DATA11__GPU3d_GPU_DEBUG_OUT_11 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA11, 0x654, 0x2D0, 6, 0x000, 0), /* MX53_PAD_PATA_DATA11__IPU_DIAG_BUS_11 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA12, 0x658, 0x2D4, 0, 0x000, 0), /* MX53_PAD_PATA_DATA12__PATA_DATA_12 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA12, 0x658, 0x2D4, 1, 0x000, 0), /* MX53_PAD_PATA_DATA12__GPIO2_12 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA12, 0x658, 0x2D4, 2, 0x000, 0), /* MX53_PAD_PATA_DATA12__ESDHC2_DAT4 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA12, 0x658, 0x2D4, 3, 0x000, 0), /* MX53_PAD_PATA_DATA12__EMI_NANDF_D_12 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA12, 0x658, 0x2D4, 4, 0x000, 0), /* MX53_PAD_PATA_DATA12__ESDHC4_DAT0 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA12, 0x658, 0x2D4, 5, 0x000, 0), /* MX53_PAD_PATA_DATA12__GPU3d_GPU_DEBUG_OUT_12 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA12, 0x658, 0x2D4, 6, 0x000, 0), /* MX53_PAD_PATA_DATA12__IPU_DIAG_BUS_12 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA13, 0x65C, 0x2D8, 0, 0x000, 0), /* MX53_PAD_PATA_DATA13__PATA_DATA_13 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA13, 0x65C, 0x2D8, 1, 0x000, 0), /* MX53_PAD_PATA_DATA13__GPIO2_13 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA13, 0x65C, 0x2D8, 2, 0x000, 0), /* MX53_PAD_PATA_DATA13__ESDHC2_DAT5 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA13, 0x65C, 0x2D8, 3, 0x000, 0), /* MX53_PAD_PATA_DATA13__EMI_NANDF_D_13 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA13, 0x65C, 0x2D8, 4, 0x000, 0), /* MX53_PAD_PATA_DATA13__ESDHC4_DAT1 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA13, 0x65C, 0x2D8, 5, 0x000, 0), /* MX53_PAD_PATA_DATA13__GPU3d_GPU_DEBUG_OUT_13 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA13, 0x65C, 0x2D8, 6, 0x000, 0), /* MX53_PAD_PATA_DATA13__IPU_DIAG_BUS_13 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA14, 0x660, 0x2DC, 0, 0x000, 0), /* MX53_PAD_PATA_DATA14__PATA_DATA_14 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA14, 0x660, 0x2DC, 1, 0x000, 0), /* MX53_PAD_PATA_DATA14__GPIO2_14 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA14, 0x660, 0x2DC, 2, 0x000, 0), /* MX53_PAD_PATA_DATA14__ESDHC2_DAT6 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA14, 0x660, 0x2DC, 3, 0x000, 0), /* MX53_PAD_PATA_DATA14__EMI_NANDF_D_14 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA14, 0x660, 0x2DC, 4, 0x000, 0), /* MX53_PAD_PATA_DATA14__ESDHC4_DAT2 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA14, 0x660, 0x2DC, 5, 0x000, 0), /* MX53_PAD_PATA_DATA14__GPU3d_GPU_DEBUG_OUT_14 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA14, 0x660, 0x2DC, 6, 0x000, 0), /* MX53_PAD_PATA_DATA14__IPU_DIAG_BUS_14 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA15, 0x664, 0x2E0, 0, 0x000, 0), /* MX53_PAD_PATA_DATA15__PATA_DATA_15 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA15, 0x664, 0x2E0, 1, 0x000, 0), /* MX53_PAD_PATA_DATA15__GPIO2_15 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA15, 0x664, 0x2E0, 2, 0x000, 0), /* MX53_PAD_PATA_DATA15__ESDHC2_DAT7 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA15, 0x664, 0x2E0, 3, 0x000, 0), /* MX53_PAD_PATA_DATA15__EMI_NANDF_D_15 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA15, 0x664, 0x2E0, 4, 0x000, 0), /* MX53_PAD_PATA_DATA15__ESDHC4_DAT3 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA15, 0x664, 0x2E0, 5, 0x000, 0), /* MX53_PAD_PATA_DATA15__GPU3d_GPU_DEBUG_OUT_15 */ + IMX_PIN_REG(MX53_PAD_PATA_DATA15, 0x664, 0x2E0, 6, 0x000, 0), /* MX53_PAD_PATA_DATA15__IPU_DIAG_BUS_15 */ + IMX_PIN_REG(MX53_PAD_SD1_DATA0, 0x66C, 0x2E4, 0, 0x000, 0), /* MX53_PAD_SD1_DATA0__ESDHC1_DAT0 */ + IMX_PIN_REG(MX53_PAD_SD1_DATA0, 0x66C, 0x2E4, 1, 0x000, 0), /* MX53_PAD_SD1_DATA0__GPIO1_16 */ + IMX_PIN_REG(MX53_PAD_SD1_DATA0, 0x66C, 0x2E4, 3, 0x000, 0), /* MX53_PAD_SD1_DATA0__GPT_CAPIN1 */ + IMX_PIN_REG(MX53_PAD_SD1_DATA0, 0x66C, 0x2E4, 5, 0x784, 2), /* MX53_PAD_SD1_DATA0__CSPI_MISO */ + IMX_PIN_REG(MX53_PAD_SD1_DATA0, 0x66C, 0x2E4, 7, 0x778, 0), /* MX53_PAD_SD1_DATA0__CCM_PLL3_BYP */ + IMX_PIN_REG(MX53_PAD_SD1_DATA1, 0x670, 0x2E8, 0, 0x000, 0), /* MX53_PAD_SD1_DATA1__ESDHC1_DAT1 */ + IMX_PIN_REG(MX53_PAD_SD1_DATA1, 0x670, 0x2E8, 1, 0x000, 0), /* MX53_PAD_SD1_DATA1__GPIO1_17 */ + IMX_PIN_REG(MX53_PAD_SD1_DATA1, 0x670, 0x2E8, 3, 0x000, 0), /* MX53_PAD_SD1_DATA1__GPT_CAPIN2 */ + IMX_PIN_REG(MX53_PAD_SD1_DATA1, 0x670, 0x2E8, 5, 0x78C, 3), /* MX53_PAD_SD1_DATA1__CSPI_SS0 */ + IMX_PIN_REG(MX53_PAD_SD1_DATA1, 0x670, 0x2E8, 7, 0x77C, 1), /* MX53_PAD_SD1_DATA1__CCM_PLL4_BYP */ + IMX_PIN_REG(MX53_PAD_SD1_CMD, 0x674, 0x2EC, 0, 0x000, 0), /* MX53_PAD_SD1_CMD__ESDHC1_CMD */ + IMX_PIN_REG(MX53_PAD_SD1_CMD, 0x674, 0x2EC, 1, 0x000, 0), /* MX53_PAD_SD1_CMD__GPIO1_18 */ + IMX_PIN_REG(MX53_PAD_SD1_CMD, 0x674, 0x2EC, 3, 0x000, 0), /* MX53_PAD_SD1_CMD__GPT_CMPOUT1 */ + IMX_PIN_REG(MX53_PAD_SD1_CMD, 0x674, 0x2EC, 5, 0x788, 2), /* MX53_PAD_SD1_CMD__CSPI_MOSI */ + IMX_PIN_REG(MX53_PAD_SD1_CMD, 0x674, 0x2EC, 7, 0x770, 0), /* MX53_PAD_SD1_CMD__CCM_PLL1_BYP */ + IMX_PIN_REG(MX53_PAD_SD1_DATA2, 0x678, 0x2F0, 0, 0x000, 0), /* MX53_PAD_SD1_DATA2__ESDHC1_DAT2 */ + IMX_PIN_REG(MX53_PAD_SD1_DATA2, 0x678, 0x2F0, 1, 0x000, 0), /* MX53_PAD_SD1_DATA2__GPIO1_19 */ + IMX_PIN_REG(MX53_PAD_SD1_DATA2, 0x678, 0x2F0, 2, 0x000, 0), /* MX53_PAD_SD1_DATA2__GPT_CMPOUT2 */ + IMX_PIN_REG(MX53_PAD_SD1_DATA2, 0x678, 0x2F0, 3, 0x000, 0), /* MX53_PAD_SD1_DATA2__PWM2_PWMO */ + IMX_PIN_REG(MX53_PAD_SD1_DATA2, 0x678, 0x2F0, 4, 0x000, 0), /* MX53_PAD_SD1_DATA2__WDOG1_WDOG_B */ + IMX_PIN_REG(MX53_PAD_SD1_DATA2, 0x678, 0x2F0, 5, 0x790, 2), /* MX53_PAD_SD1_DATA2__CSPI_SS1 */ + IMX_PIN_REG(MX53_PAD_SD1_DATA2, 0x678, 0x2F0, 6, 0x000, 0), /* MX53_PAD_SD1_DATA2__WDOG1_WDOG_RST_B_DEB */ + IMX_PIN_REG(MX53_PAD_SD1_DATA2, 0x678, 0x2F0, 7, 0x774, 0), /* MX53_PAD_SD1_DATA2__CCM_PLL2_BYP */ + IMX_PIN_REG(MX53_PAD_SD1_CLK, 0x67C, 0x2F4, 0, 0x000, 0), /* MX53_PAD_SD1_CLK__ESDHC1_CLK */ + IMX_PIN_REG(MX53_PAD_SD1_CLK, 0x67C, 0x2F4, 1, 0x000, 0), /* MX53_PAD_SD1_CLK__GPIO1_20 */ + IMX_PIN_REG(MX53_PAD_SD1_CLK, 0x67C, 0x2F4, 2, 0x000, 0), /* MX53_PAD_SD1_CLK__OSC32k_32K_OUT */ + IMX_PIN_REG(MX53_PAD_SD1_CLK, 0x67C, 0x2F4, 3, 0x000, 0), /* MX53_PAD_SD1_CLK__GPT_CLKIN */ + IMX_PIN_REG(MX53_PAD_SD1_CLK, 0x67C, 0x2F4, 5, 0x780, 2), /* MX53_PAD_SD1_CLK__CSPI_SCLK */ + IMX_PIN_REG(MX53_PAD_SD1_CLK, 0x67C, 0x2F4, 7, 0x000, 0), /* MX53_PAD_SD1_CLK__SATA_PHY_DTB_0 */ + IMX_PIN_REG(MX53_PAD_SD1_DATA3, 0x680, 0x2F8, 0, 0x000, 0), /* MX53_PAD_SD1_DATA3__ESDHC1_DAT3 */ + IMX_PIN_REG(MX53_PAD_SD1_DATA3, 0x680, 0x2F8, 1, 0x000, 0), /* MX53_PAD_SD1_DATA3__GPIO1_21 */ + IMX_PIN_REG(MX53_PAD_SD1_DATA3, 0x680, 0x2F8, 2, 0x000, 0), /* MX53_PAD_SD1_DATA3__GPT_CMPOUT3 */ + IMX_PIN_REG(MX53_PAD_SD1_DATA3, 0x680, 0x2F8, 3, 0x000, 0), /* MX53_PAD_SD1_DATA3__PWM1_PWMO */ + IMX_PIN_REG(MX53_PAD_SD1_DATA3, 0x680, 0x2F8, 4, 0x000, 0), /* MX53_PAD_SD1_DATA3__WDOG2_WDOG_B */ + IMX_PIN_REG(MX53_PAD_SD1_DATA3, 0x680, 0x2F8, 5, 0x794, 2), /* MX53_PAD_SD1_DATA3__CSPI_SS2 */ + IMX_PIN_REG(MX53_PAD_SD1_DATA3, 0x680, 0x2F8, 6, 0x000, 0), /* MX53_PAD_SD1_DATA3__WDOG2_WDOG_RST_B_DEB */ + IMX_PIN_REG(MX53_PAD_SD1_DATA3, 0x680, 0x2F8, 7, 0x000, 0), /* MX53_PAD_SD1_DATA3__SATA_PHY_DTB_1 */ + IMX_PIN_REG(MX53_PAD_SD2_CLK, 0x688, 0x2FC, 0, 0x000, 0), /* MX53_PAD_SD2_CLK__ESDHC2_CLK */ + IMX_PIN_REG(MX53_PAD_SD2_CLK, 0x688, 0x2FC, 1, 0x000, 0), /* MX53_PAD_SD2_CLK__GPIO1_10 */ + IMX_PIN_REG(MX53_PAD_SD2_CLK, 0x688, 0x2FC, 2, 0x840, 2), /* MX53_PAD_SD2_CLK__KPP_COL_5 */ + IMX_PIN_REG(MX53_PAD_SD2_CLK, 0x688, 0x2FC, 3, 0x73C, 1), /* MX53_PAD_SD2_CLK__AUDMUX_AUD4_RXFS */ + IMX_PIN_REG(MX53_PAD_SD2_CLK, 0x688, 0x2FC, 5, 0x780, 3), /* MX53_PAD_SD2_CLK__CSPI_SCLK */ + IMX_PIN_REG(MX53_PAD_SD2_CLK, 0x688, 0x2FC, 7, 0x000, 0), /* MX53_PAD_SD2_CLK__SCC_RANDOM_V */ + IMX_PIN_REG(MX53_PAD_SD2_CMD, 0x68C, 0x300, 0, 0x000, 0), /* MX53_PAD_SD2_CMD__ESDHC2_CMD */ + IMX_PIN_REG(MX53_PAD_SD2_CMD, 0x68C, 0x300, 1, 0x000, 0), /* MX53_PAD_SD2_CMD__GPIO1_11 */ + IMX_PIN_REG(MX53_PAD_SD2_CMD, 0x68C, 0x300, 2, 0x84C, 1), /* MX53_PAD_SD2_CMD__KPP_ROW_5 */ + IMX_PIN_REG(MX53_PAD_SD2_CMD, 0x68C, 0x300, 3, 0x738, 1), /* MX53_PAD_SD2_CMD__AUDMUX_AUD4_RXC */ + IMX_PIN_REG(MX53_PAD_SD2_CMD, 0x68C, 0x300, 5, 0x788, 3), /* MX53_PAD_SD2_CMD__CSPI_MOSI */ + IMX_PIN_REG(MX53_PAD_SD2_CMD, 0x68C, 0x300, 7, 0x000, 0), /* MX53_PAD_SD2_CMD__SCC_RANDOM */ + IMX_PIN_REG(MX53_PAD_SD2_DATA3, 0x690, 0x304, 0, 0x000, 0), /* MX53_PAD_SD2_DATA3__ESDHC2_DAT3 */ + IMX_PIN_REG(MX53_PAD_SD2_DATA3, 0x690, 0x304, 1, 0x000, 0), /* MX53_PAD_SD2_DATA3__GPIO1_12 */ + IMX_PIN_REG(MX53_PAD_SD2_DATA3, 0x690, 0x304, 2, 0x844, 1), /* MX53_PAD_SD2_DATA3__KPP_COL_6 */ + IMX_PIN_REG(MX53_PAD_SD2_DATA3, 0x690, 0x304, 3, 0x740, 1), /* MX53_PAD_SD2_DATA3__AUDMUX_AUD4_TXC */ + IMX_PIN_REG(MX53_PAD_SD2_DATA3, 0x690, 0x304, 5, 0x794, 3), /* MX53_PAD_SD2_DATA3__CSPI_SS2 */ + IMX_PIN_REG(MX53_PAD_SD2_DATA3, 0x690, 0x304, 7, 0x000, 0), /* MX53_PAD_SD2_DATA3__SJC_DONE */ + IMX_PIN_REG(MX53_PAD_SD2_DATA2, 0x694, 0x308, 0, 0x000, 0), /* MX53_PAD_SD2_DATA2__ESDHC2_DAT2 */ + IMX_PIN_REG(MX53_PAD_SD2_DATA2, 0x694, 0x308, 1, 0x000, 0), /* MX53_PAD_SD2_DATA2__GPIO1_13 */ + IMX_PIN_REG(MX53_PAD_SD2_DATA2, 0x694, 0x308, 2, 0x850, 1), /* MX53_PAD_SD2_DATA2__KPP_ROW_6 */ + IMX_PIN_REG(MX53_PAD_SD2_DATA2, 0x694, 0x308, 3, 0x734, 1), /* MX53_PAD_SD2_DATA2__AUDMUX_AUD4_TXD */ + IMX_PIN_REG(MX53_PAD_SD2_DATA2, 0x694, 0x308, 5, 0x790, 3), /* MX53_PAD_SD2_DATA2__CSPI_SS1 */ + IMX_PIN_REG(MX53_PAD_SD2_DATA2, 0x694, 0x308, 7, 0x000, 0), /* MX53_PAD_SD2_DATA2__SJC_FAIL */ + IMX_PIN_REG(MX53_PAD_SD2_DATA1, 0x698, 0x30C, 0, 0x000, 0), /* MX53_PAD_SD2_DATA1__ESDHC2_DAT1 */ + IMX_PIN_REG(MX53_PAD_SD2_DATA1, 0x698, 0x30C, 1, 0x000, 0), /* MX53_PAD_SD2_DATA1__GPIO1_14 */ + IMX_PIN_REG(MX53_PAD_SD2_DATA1, 0x698, 0x30C, 2, 0x848, 1), /* MX53_PAD_SD2_DATA1__KPP_COL_7 */ + IMX_PIN_REG(MX53_PAD_SD2_DATA1, 0x698, 0x30C, 3, 0x744, 0), /* MX53_PAD_SD2_DATA1__AUDMUX_AUD4_TXFS */ + IMX_PIN_REG(MX53_PAD_SD2_DATA1, 0x698, 0x30C, 5, 0x78C, 4), /* MX53_PAD_SD2_DATA1__CSPI_SS0 */ + IMX_PIN_REG(MX53_PAD_SD2_DATA1, 0x698, 0x30C, 7, 0x000, 0), /* MX53_PAD_SD2_DATA1__RTIC_SEC_VIO */ + IMX_PIN_REG(MX53_PAD_SD2_DATA0, 0x69C, 0x310, 0, 0x000, 0), /* MX53_PAD_SD2_DATA0__ESDHC2_DAT0 */ + IMX_PIN_REG(MX53_PAD_SD2_DATA0, 0x69C, 0x310, 1, 0x000, 0), /* MX53_PAD_SD2_DATA0__GPIO1_15 */ + IMX_PIN_REG(MX53_PAD_SD2_DATA0, 0x69C, 0x310, 2, 0x854, 1), /* MX53_PAD_SD2_DATA0__KPP_ROW_7 */ + IMX_PIN_REG(MX53_PAD_SD2_DATA0, 0x69C, 0x310, 3, 0x730, 1), /* MX53_PAD_SD2_DATA0__AUDMUX_AUD4_RXD */ + IMX_PIN_REG(MX53_PAD_SD2_DATA0, 0x69C, 0x310, 5, 0x784, 3), /* MX53_PAD_SD2_DATA0__CSPI_MISO */ + IMX_PIN_REG(MX53_PAD_SD2_DATA0, 0x69C, 0x310, 7, 0x000, 0), /* MX53_PAD_SD2_DATA0__RTIC_DONE_INT */ + IMX_PIN_REG(MX53_PAD_GPIO_0, 0x6A4, 0x314, 0, 0x000, 0), /* MX53_PAD_GPIO_0__CCM_CLKO */ + IMX_PIN_REG(MX53_PAD_GPIO_0, 0x6A4, 0x314, 1, 0x000, 0), /* MX53_PAD_GPIO_0__GPIO1_0 */ + IMX_PIN_REG(MX53_PAD_GPIO_0, 0x6A4, 0x314, 2, 0x840, 3), /* MX53_PAD_GPIO_0__KPP_COL_5 */ + IMX_PIN_REG(MX53_PAD_GPIO_0, 0x6A4, 0x314, 3, 0x000, 0), /* MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK */ + IMX_PIN_REG(MX53_PAD_GPIO_0, 0x6A4, 0x314, 4, 0x000, 0), /* MX53_PAD_GPIO_0__EPIT1_EPITO */ + IMX_PIN_REG(MX53_PAD_GPIO_0, 0x6A4, 0x314, 5, 0x000, 0), /* MX53_PAD_GPIO_0__SRTC_ALARM_DEB */ + IMX_PIN_REG(MX53_PAD_GPIO_0, 0x6A4, 0x314, 6, 0x000, 0), /* MX53_PAD_GPIO_0__USBOH3_USBH1_PWR */ + IMX_PIN_REG(MX53_PAD_GPIO_0, 0x6A4, 0x314, 7, 0x000, 0), /* MX53_PAD_GPIO_0__CSU_TD */ + IMX_PIN_REG(MX53_PAD_GPIO_1, 0x6A8, 0x318, 0, 0x7DC, 1), /* MX53_PAD_GPIO_1__ESAI1_SCKR */ + IMX_PIN_REG(MX53_PAD_GPIO_1, 0x6A8, 0x318, 1, 0x000, 0), /* MX53_PAD_GPIO_1__GPIO1_1 */ + IMX_PIN_REG(MX53_PAD_GPIO_1, 0x6A8, 0x318, 2, 0x84C, 2), /* MX53_PAD_GPIO_1__KPP_ROW_5 */ + IMX_PIN_REG(MX53_PAD_GPIO_1, 0x6A8, 0x318, 3, 0x000, 0), /* MX53_PAD_GPIO_1__CCM_SSI_EXT2_CLK */ + IMX_PIN_REG(MX53_PAD_GPIO_1, 0x6A8, 0x318, 4, 0x000, 0), /* MX53_PAD_GPIO_1__PWM2_PWMO */ + IMX_PIN_REG(MX53_PAD_GPIO_1, 0x6A8, 0x318, 5, 0x000, 0), /* MX53_PAD_GPIO_1__WDOG2_WDOG_B */ + IMX_PIN_REG(MX53_PAD_GPIO_1, 0x6A8, 0x318, 6, 0x000, 0), /* MX53_PAD_GPIO_1__ESDHC1_CD */ + IMX_PIN_REG(MX53_PAD_GPIO_1, 0x6A8, 0x318, 7, 0x000, 0), /* MX53_PAD_GPIO_1__SRC_TESTER_ACK */ + IMX_PIN_REG(MX53_PAD_GPIO_9, 0x6AC, 0x31C, 0, 0x7CC, 1), /* MX53_PAD_GPIO_9__ESAI1_FSR */ + IMX_PIN_REG(MX53_PAD_GPIO_9, 0x6AC, 0x31C, 1, 0x000, 0), /* MX53_PAD_GPIO_9__GPIO1_9 */ + IMX_PIN_REG(MX53_PAD_GPIO_9, 0x6AC, 0x31C, 2, 0x844, 2), /* MX53_PAD_GPIO_9__KPP_COL_6 */ + IMX_PIN_REG(MX53_PAD_GPIO_9, 0x6AC, 0x31C, 3, 0x000, 0), /* MX53_PAD_GPIO_9__CCM_REF_EN_B */ + IMX_PIN_REG(MX53_PAD_GPIO_9, 0x6AC, 0x31C, 4, 0x000, 0), /* MX53_PAD_GPIO_9__PWM1_PWMO */ + IMX_PIN_REG(MX53_PAD_GPIO_9, 0x6AC, 0x31C, 5, 0x000, 0), /* MX53_PAD_GPIO_9__WDOG1_WDOG_B */ + IMX_PIN_REG(MX53_PAD_GPIO_9, 0x6AC, 0x31C, 6, 0x7FC, 1), /* MX53_PAD_GPIO_9__ESDHC1_WP */ + IMX_PIN_REG(MX53_PAD_GPIO_9, 0x6AC, 0x31C, 7, 0x000, 0), /* MX53_PAD_GPIO_9__SCC_FAIL_STATE */ + IMX_PIN_REG(MX53_PAD_GPIO_3, 0x6B0, 0x320, 0, 0x7D4, 1), /* MX53_PAD_GPIO_3__ESAI1_HCKR */ + IMX_PIN_REG(MX53_PAD_GPIO_3, 0x6B0, 0x320, 1, 0x000, 0), /* MX53_PAD_GPIO_3__GPIO1_3 */ + IMX_PIN_REG(MX53_PAD_GPIO_3, 0x6B0, 0x320, 2, 0x824, 1), /* MX53_PAD_GPIO_3__I2C3_SCL */ + IMX_PIN_REG(MX53_PAD_GPIO_3, 0x6B0, 0x320, 3, 0x000, 0), /* MX53_PAD_GPIO_3__DPLLIP1_TOG_EN */ + IMX_PIN_REG(MX53_PAD_GPIO_3, 0x6B0, 0x320, 4, 0x000, 0), /* MX53_PAD_GPIO_3__CCM_CLKO2 */ + IMX_PIN_REG(MX53_PAD_GPIO_3, 0x6B0, 0x320, 5, 0x000, 0), /* MX53_PAD_GPIO_3__OBSERVE_MUX_OBSRV_INT_OUT0 */ + IMX_PIN_REG(MX53_PAD_GPIO_3, 0x6B0, 0x320, 6, 0x8A0, 1), /* MX53_PAD_GPIO_3__USBOH3_USBH1_OC */ + IMX_PIN_REG(MX53_PAD_GPIO_3, 0x6B0, 0x320, 7, 0x858, 2), /* MX53_PAD_GPIO_3__MLB_MLBCLK */ + IMX_PIN_REG(MX53_PAD_GPIO_6, 0x6B4, 0x324, 0, 0x7E0, 1), /* MX53_PAD_GPIO_6__ESAI1_SCKT */ + IMX_PIN_REG(MX53_PAD_GPIO_6, 0x6B4, 0x324, 1, 0x000, 0), /* MX53_PAD_GPIO_6__GPIO1_6 */ + IMX_PIN_REG(MX53_PAD_GPIO_6, 0x6B4, 0x324, 2, 0x828, 1), /* MX53_PAD_GPIO_6__I2C3_SDA */ + IMX_PIN_REG(MX53_PAD_GPIO_6, 0x6B4, 0x324, 3, 0x000, 0), /* MX53_PAD_GPIO_6__CCM_CCM_OUT_0 */ + IMX_PIN_REG(MX53_PAD_GPIO_6, 0x6B4, 0x324, 4, 0x000, 0), /* MX53_PAD_GPIO_6__CSU_CSU_INT_DEB */ + IMX_PIN_REG(MX53_PAD_GPIO_6, 0x6B4, 0x324, 5, 0x000, 0), /* MX53_PAD_GPIO_6__OBSERVE_MUX_OBSRV_INT_OUT1 */ + IMX_PIN_REG(MX53_PAD_GPIO_6, 0x6B4, 0x324, 6, 0x000, 0), /* MX53_PAD_GPIO_6__ESDHC2_LCTL */ + IMX_PIN_REG(MX53_PAD_GPIO_6, 0x6B4, 0x324, 7, 0x860, 2), /* MX53_PAD_GPIO_6__MLB_MLBSIG */ + IMX_PIN_REG(MX53_PAD_GPIO_2, 0x6B8, 0x328, 0, 0x7D0, 1), /* MX53_PAD_GPIO_2__ESAI1_FST */ + IMX_PIN_REG(MX53_PAD_GPIO_2, 0x6B8, 0x328, 1, 0x000, 0), /* MX53_PAD_GPIO_2__GPIO1_2 */ + IMX_PIN_REG(MX53_PAD_GPIO_2, 0x6B8, 0x328, 2, 0x850, 2), /* MX53_PAD_GPIO_2__KPP_ROW_6 */ + IMX_PIN_REG(MX53_PAD_GPIO_2, 0x6B8, 0x328, 3, 0x000, 0), /* MX53_PAD_GPIO_2__CCM_CCM_OUT_1 */ + IMX_PIN_REG(MX53_PAD_GPIO_2, 0x6B8, 0x328, 4, 0x000, 0), /* MX53_PAD_GPIO_2__CSU_CSU_ALARM_AUT_0 */ + IMX_PIN_REG(MX53_PAD_GPIO_2, 0x6B8, 0x328, 5, 0x000, 0), /* MX53_PAD_GPIO_2__OBSERVE_MUX_OBSRV_INT_OUT2 */ + IMX_PIN_REG(MX53_PAD_GPIO_2, 0x6B8, 0x328, 6, 0x000, 0), /* MX53_PAD_GPIO_2__ESDHC2_WP */ + IMX_PIN_REG(MX53_PAD_GPIO_2, 0x6B8, 0x328, 7, 0x85C, 2), /* MX53_PAD_GPIO_2__MLB_MLBDAT */ + IMX_PIN_REG(MX53_PAD_GPIO_4, 0x6BC, 0x32C, 0, 0x7D8, 1), /* MX53_PAD_GPIO_4__ESAI1_HCKT */ + IMX_PIN_REG(MX53_PAD_GPIO_4, 0x6BC, 0x32C, 1, 0x000, 0), /* MX53_PAD_GPIO_4__GPIO1_4 */ + IMX_PIN_REG(MX53_PAD_GPIO_4, 0x6BC, 0x32C, 2, 0x848, 2), /* MX53_PAD_GPIO_4__KPP_COL_7 */ + IMX_PIN_REG(MX53_PAD_GPIO_4, 0x6BC, 0x32C, 3, 0x000, 0), /* MX53_PAD_GPIO_4__CCM_CCM_OUT_2 */ + IMX_PIN_REG(MX53_PAD_GPIO_4, 0x6BC, 0x32C, 4, 0x000, 0), /* MX53_PAD_GPIO_4__CSU_CSU_ALARM_AUT_1 */ + IMX_PIN_REG(MX53_PAD_GPIO_4, 0x6BC, 0x32C, 5, 0x000, 0), /* MX53_PAD_GPIO_4__OBSERVE_MUX_OBSRV_INT_OUT3 */ + IMX_PIN_REG(MX53_PAD_GPIO_4, 0x6BC, 0x32C, 6, 0x000, 0), /* MX53_PAD_GPIO_4__ESDHC2_CD */ + IMX_PIN_REG(MX53_PAD_GPIO_4, 0x6BC, 0x32C, 7, 0x000, 0), /* MX53_PAD_GPIO_4__SCC_SEC_STATE */ + IMX_PIN_REG(MX53_PAD_GPIO_5, 0x6C0, 0x330, 0, 0x7EC, 1), /* MX53_PAD_GPIO_5__ESAI1_TX2_RX3 */ + IMX_PIN_REG(MX53_PAD_GPIO_5, 0x6C0, 0x330, 1, 0x000, 0), /* MX53_PAD_GPIO_5__GPIO1_5 */ + IMX_PIN_REG(MX53_PAD_GPIO_5, 0x6C0, 0x330, 2, 0x854, 2), /* MX53_PAD_GPIO_5__KPP_ROW_7 */ + IMX_PIN_REG(MX53_PAD_GPIO_5, 0x6C0, 0x330, 3, 0x000, 0), /* MX53_PAD_GPIO_5__CCM_CLKO */ + IMX_PIN_REG(MX53_PAD_GPIO_5, 0x6C0, 0x330, 4, 0x000, 0), /* MX53_PAD_GPIO_5__CSU_CSU_ALARM_AUT_2 */ + IMX_PIN_REG(MX53_PAD_GPIO_5, 0x6C0, 0x330, 5, 0x000, 0), /* MX53_PAD_GPIO_5__OBSERVE_MUX_OBSRV_INT_OUT4 */ + IMX_PIN_REG(MX53_PAD_GPIO_5, 0x6C0, 0x330, 6, 0x824, 2), /* MX53_PAD_GPIO_5__I2C3_SCL */ + IMX_PIN_REG(MX53_PAD_GPIO_5, 0x6C0, 0x330, 7, 0x770, 1), /* MX53_PAD_GPIO_5__CCM_PLL1_BYP */ + IMX_PIN_REG(MX53_PAD_GPIO_7, 0x6C4, 0x334, 0, 0x7F4, 1), /* MX53_PAD_GPIO_7__ESAI1_TX4_RX1 */ + IMX_PIN_REG(MX53_PAD_GPIO_7, 0x6C4, 0x334, 1, 0x000, 0), /* MX53_PAD_GPIO_7__GPIO1_7 */ + IMX_PIN_REG(MX53_PAD_GPIO_7, 0x6C4, 0x334, 2, 0x000, 0), /* MX53_PAD_GPIO_7__EPIT1_EPITO */ + IMX_PIN_REG(MX53_PAD_GPIO_7, 0x6C4, 0x334, 3, 0x000, 0), /* MX53_PAD_GPIO_7__CAN1_TXCAN */ + IMX_PIN_REG(MX53_PAD_GPIO_7, 0x6C4, 0x334, 4, 0x000, 0), /* MX53_PAD_GPIO_7__UART2_TXD_MUX */ + IMX_PIN_REG(MX53_PAD_GPIO_7, 0x6C4, 0x334, 5, 0x80C, 1), /* MX53_PAD_GPIO_7__FIRI_RXD */ + IMX_PIN_REG(MX53_PAD_GPIO_7, 0x6C4, 0x334, 6, 0x000, 0), /* MX53_PAD_GPIO_7__SPDIF_PLOCK */ + IMX_PIN_REG(MX53_PAD_GPIO_7, 0x6C4, 0x334, 7, 0x774, 1), /* MX53_PAD_GPIO_7__CCM_PLL2_BYP */ + IMX_PIN_REG(MX53_PAD_GPIO_8, 0x6C8, 0x338, 0, 0x7F8, 1), /* MX53_PAD_GPIO_8__ESAI1_TX5_RX0 */ + IMX_PIN_REG(MX53_PAD_GPIO_8, 0x6C8, 0x338, 1, 0x000, 0), /* MX53_PAD_GPIO_8__GPIO1_8 */ + IMX_PIN_REG(MX53_PAD_GPIO_8, 0x6C8, 0x338, 2, 0x000, 0), /* MX53_PAD_GPIO_8__EPIT2_EPITO */ + IMX_PIN_REG(MX53_PAD_GPIO_8, 0x6C8, 0x338, 3, 0x760, 3), /* MX53_PAD_GPIO_8__CAN1_RXCAN */ + IMX_PIN_REG(MX53_PAD_GPIO_8, 0x6C8, 0x338, 4, 0x880, 5), /* MX53_PAD_GPIO_8__UART2_RXD_MUX */ + IMX_PIN_REG(MX53_PAD_GPIO_8, 0x6C8, 0x338, 5, 0x000, 0), /* MX53_PAD_GPIO_8__FIRI_TXD */ + IMX_PIN_REG(MX53_PAD_GPIO_8, 0x6C8, 0x338, 6, 0x000, 0), /* MX53_PAD_GPIO_8__SPDIF_SRCLK */ + IMX_PIN_REG(MX53_PAD_GPIO_8, 0x6C8, 0x338, 7, 0x778, 1), /* MX53_PAD_GPIO_8__CCM_PLL3_BYP */ + IMX_PIN_REG(MX53_PAD_GPIO_16, 0x6CC, 0x33C, 0, 0x7F0, 1), /* MX53_PAD_GPIO_16__ESAI1_TX3_RX2 */ + IMX_PIN_REG(MX53_PAD_GPIO_16, 0x6CC, 0x33C, 1, 0x000, 0), /* MX53_PAD_GPIO_16__GPIO7_11 */ + IMX_PIN_REG(MX53_PAD_GPIO_16, 0x6CC, 0x33C, 2, 0x000, 0), /* MX53_PAD_GPIO_16__TZIC_PWRFAIL_INT */ + IMX_PIN_REG(MX53_PAD_GPIO_16, 0x6CC, 0x33C, 4, 0x000, 0), /* MX53_PAD_GPIO_16__RTC_CE_RTC_EXT_TRIG1 */ + IMX_PIN_REG(MX53_PAD_GPIO_16, 0x6CC, 0x33C, 5, 0x870, 1), /* MX53_PAD_GPIO_16__SPDIF_IN1 */ + IMX_PIN_REG(MX53_PAD_GPIO_16, 0x6CC, 0x33C, 6, 0x828, 2), /* MX53_PAD_GPIO_16__I2C3_SDA */ + IMX_PIN_REG(MX53_PAD_GPIO_16, 0x6CC, 0x33C, 7, 0x000, 0), /* MX53_PAD_GPIO_16__SJC_DE_B */ + IMX_PIN_REG(MX53_PAD_GPIO_17, 0x6D0, 0x340, 0, 0x7E4, 1), /* MX53_PAD_GPIO_17__ESAI1_TX0 */ + IMX_PIN_REG(MX53_PAD_GPIO_17, 0x6D0, 0x340, 1, 0x000, 0), /* MX53_PAD_GPIO_17__GPIO7_12 */ + IMX_PIN_REG(MX53_PAD_GPIO_17, 0x6D0, 0x340, 2, 0x868, 1), /* MX53_PAD_GPIO_17__SDMA_EXT_EVENT_0 */ + IMX_PIN_REG(MX53_PAD_GPIO_17, 0x6D0, 0x340, 3, 0x810, 1), /* MX53_PAD_GPIO_17__GPC_PMIC_RDY */ + IMX_PIN_REG(MX53_PAD_GPIO_17, 0x6D0, 0x340, 4, 0x000, 0), /* MX53_PAD_GPIO_17__RTC_CE_RTC_FSV_TRIG */ + IMX_PIN_REG(MX53_PAD_GPIO_17, 0x6D0, 0x340, 5, 0x000, 0), /* MX53_PAD_GPIO_17__SPDIF_OUT1 */ + IMX_PIN_REG(MX53_PAD_GPIO_17, 0x6D0, 0x340, 6, 0x000, 0), /* MX53_PAD_GPIO_17__IPU_SNOOP2 */ + IMX_PIN_REG(MX53_PAD_GPIO_17, 0x6D0, 0x340, 7, 0x000, 0), /* MX53_PAD_GPIO_17__SJC_JTAG_ACT */ + IMX_PIN_REG(MX53_PAD_GPIO_18, 0x6D4, 0x344, 0, 0x7E8, 1), /* MX53_PAD_GPIO_18__ESAI1_TX1 */ + IMX_PIN_REG(MX53_PAD_GPIO_18, 0x6D4, 0x344, 1, 0x000, 0), /* MX53_PAD_GPIO_18__GPIO7_13 */ + IMX_PIN_REG(MX53_PAD_GPIO_18, 0x6D4, 0x344, 2, 0x86C, 1), /* MX53_PAD_GPIO_18__SDMA_EXT_EVENT_1 */ + IMX_PIN_REG(MX53_PAD_GPIO_18, 0x6D4, 0x344, 3, 0x864, 1), /* MX53_PAD_GPIO_18__OWIRE_LINE */ + IMX_PIN_REG(MX53_PAD_GPIO_18, 0x6D4, 0x344, 4, 0x000, 0), /* MX53_PAD_GPIO_18__RTC_CE_RTC_ALARM2_TRIG */ + IMX_PIN_REG(MX53_PAD_GPIO_18, 0x6D4, 0x344, 5, 0x768, 1), /* MX53_PAD_GPIO_18__CCM_ASRC_EXT_CLK */ + IMX_PIN_REG(MX53_PAD_GPIO_18, 0x6D4, 0x344, 6, 0x000, 0), /* MX53_PAD_GPIO_18__ESDHC1_LCTL */ + IMX_PIN_REG(MX53_PAD_GPIO_18, 0x6D4, 0x344, 7, 0x000, 0), /* MX53_PAD_GPIO_18__SRC_SYSTEM_RST */ +}; + +/* Pad names for the pinmux subsystem */ +static const struct pinctrl_pin_desc imx53_pinctrl_pads[] = { + IMX_PINCTRL_PIN(MX53_PAD_GPIO_19), + IMX_PINCTRL_PIN(MX53_PAD_KEY_COL0), + IMX_PINCTRL_PIN(MX53_PAD_KEY_ROW0), + IMX_PINCTRL_PIN(MX53_PAD_KEY_COL1), + IMX_PINCTRL_PIN(MX53_PAD_KEY_ROW1), + IMX_PINCTRL_PIN(MX53_PAD_KEY_COL2), + IMX_PINCTRL_PIN(MX53_PAD_KEY_ROW2), + IMX_PINCTRL_PIN(MX53_PAD_KEY_COL3), + IMX_PINCTRL_PIN(MX53_PAD_KEY_ROW3), + IMX_PINCTRL_PIN(MX53_PAD_KEY_COL4), + IMX_PINCTRL_PIN(MX53_PAD_KEY_ROW4), + IMX_PINCTRL_PIN(MX53_PAD_DI0_DISP_CLK), + IMX_PINCTRL_PIN(MX53_PAD_DI0_PIN15), + IMX_PINCTRL_PIN(MX53_PAD_DI0_PIN2), + IMX_PINCTRL_PIN(MX53_PAD_DI0_PIN3), + IMX_PINCTRL_PIN(MX53_PAD_DI0_PIN4), + IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT0), + IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT1), + IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT2), + IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT3), + IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT4), + IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT5), + IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT6), + IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT7), + IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT8), + IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT9), + IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT10), + IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT11), + IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT12), + IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT13), + IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT14), + IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT15), + IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT16), + IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT17), + IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT18), + IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT19), + IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT20), + IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT21), + IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT22), + IMX_PINCTRL_PIN(MX53_PAD_DISP0_DAT23), + IMX_PINCTRL_PIN(MX53_PAD_CSI0_PIXCLK), + IMX_PINCTRL_PIN(MX53_PAD_CSI0_MCLK), + IMX_PINCTRL_PIN(MX53_PAD_CSI0_DATA_EN), + IMX_PINCTRL_PIN(MX53_PAD_CSI0_VSYNC), + IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT4), + IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT5), + IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT6), + IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT7), + IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT8), + IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT9), + IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT10), + IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT11), + IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT12), + IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT13), + IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT14), + IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT15), + IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT16), + IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT17), + IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT18), + IMX_PINCTRL_PIN(MX53_PAD_CSI0_DAT19), + IMX_PINCTRL_PIN(MX53_PAD_EIM_A25), + IMX_PINCTRL_PIN(MX53_PAD_EIM_EB2), + IMX_PINCTRL_PIN(MX53_PAD_EIM_D16), + IMX_PINCTRL_PIN(MX53_PAD_EIM_D17), + IMX_PINCTRL_PIN(MX53_PAD_EIM_D18), + IMX_PINCTRL_PIN(MX53_PAD_EIM_D19), + IMX_PINCTRL_PIN(MX53_PAD_EIM_D20), + IMX_PINCTRL_PIN(MX53_PAD_EIM_D21), + IMX_PINCTRL_PIN(MX53_PAD_EIM_D22), + IMX_PINCTRL_PIN(MX53_PAD_EIM_D23), + IMX_PINCTRL_PIN(MX53_PAD_EIM_EB3), + IMX_PINCTRL_PIN(MX53_PAD_EIM_D24), + IMX_PINCTRL_PIN(MX53_PAD_EIM_D25), + IMX_PINCTRL_PIN(MX53_PAD_EIM_D26), + IMX_PINCTRL_PIN(MX53_PAD_EIM_D27), + IMX_PINCTRL_PIN(MX53_PAD_EIM_D28), + IMX_PINCTRL_PIN(MX53_PAD_EIM_D29), + IMX_PINCTRL_PIN(MX53_PAD_EIM_D30), + IMX_PINCTRL_PIN(MX53_PAD_EIM_D31), + IMX_PINCTRL_PIN(MX53_PAD_EIM_A24), + IMX_PINCTRL_PIN(MX53_PAD_EIM_A23), + IMX_PINCTRL_PIN(MX53_PAD_EIM_A22), + IMX_PINCTRL_PIN(MX53_PAD_EIM_A21), + IMX_PINCTRL_PIN(MX53_PAD_EIM_A20), + IMX_PINCTRL_PIN(MX53_PAD_EIM_A19), + IMX_PINCTRL_PIN(MX53_PAD_EIM_A18), + IMX_PINCTRL_PIN(MX53_PAD_EIM_A17), + IMX_PINCTRL_PIN(MX53_PAD_EIM_A16), + IMX_PINCTRL_PIN(MX53_PAD_EIM_CS0), + IMX_PINCTRL_PIN(MX53_PAD_EIM_CS1), + IMX_PINCTRL_PIN(MX53_PAD_EIM_OE), + IMX_PINCTRL_PIN(MX53_PAD_EIM_RW), + IMX_PINCTRL_PIN(MX53_PAD_EIM_LBA), + IMX_PINCTRL_PIN(MX53_PAD_EIM_EB0), + IMX_PINCTRL_PIN(MX53_PAD_EIM_EB1), + IMX_PINCTRL_PIN(MX53_PAD_EIM_DA0), + IMX_PINCTRL_PIN(MX53_PAD_EIM_DA1), + IMX_PINCTRL_PIN(MX53_PAD_EIM_DA2), + IMX_PINCTRL_PIN(MX53_PAD_EIM_DA3), + IMX_PINCTRL_PIN(MX53_PAD_EIM_DA4), + IMX_PINCTRL_PIN(MX53_PAD_EIM_DA5), + IMX_PINCTRL_PIN(MX53_PAD_EIM_DA6), + IMX_PINCTRL_PIN(MX53_PAD_EIM_DA7), + IMX_PINCTRL_PIN(MX53_PAD_EIM_DA8), + IMX_PINCTRL_PIN(MX53_PAD_EIM_DA9), + IMX_PINCTRL_PIN(MX53_PAD_EIM_DA10), + IMX_PINCTRL_PIN(MX53_PAD_EIM_DA11), + IMX_PINCTRL_PIN(MX53_PAD_EIM_DA12), + IMX_PINCTRL_PIN(MX53_PAD_EIM_DA13), + IMX_PINCTRL_PIN(MX53_PAD_EIM_DA14), + IMX_PINCTRL_PIN(MX53_PAD_EIM_DA15), + IMX_PINCTRL_PIN(MX53_PAD_NANDF_WE_B), + IMX_PINCTRL_PIN(MX53_PAD_NANDF_RE_B), + IMX_PINCTRL_PIN(MX53_PAD_EIM_WAIT), + IMX_PINCTRL_PIN(MX53_PAD_LVDS1_TX3_P), + IMX_PINCTRL_PIN(MX53_PAD_LVDS1_TX2_P), + IMX_PINCTRL_PIN(MX53_PAD_LVDS1_CLK_P), + IMX_PINCTRL_PIN(MX53_PAD_LVDS1_TX1_P), + IMX_PINCTRL_PIN(MX53_PAD_LVDS1_TX0_P), + IMX_PINCTRL_PIN(MX53_PAD_LVDS0_TX3_P), + IMX_PINCTRL_PIN(MX53_PAD_LVDS0_CLK_P), + IMX_PINCTRL_PIN(MX53_PAD_LVDS0_TX2_P), + IMX_PINCTRL_PIN(MX53_PAD_LVDS0_TX1_P), + IMX_PINCTRL_PIN(MX53_PAD_LVDS0_TX0_P), + IMX_PINCTRL_PIN(MX53_PAD_GPIO_10), + IMX_PINCTRL_PIN(MX53_PAD_GPIO_11), + IMX_PINCTRL_PIN(MX53_PAD_GPIO_12), + IMX_PINCTRL_PIN(MX53_PAD_GPIO_13), + IMX_PINCTRL_PIN(MX53_PAD_GPIO_14), + IMX_PINCTRL_PIN(MX53_PAD_NANDF_CLE), + IMX_PINCTRL_PIN(MX53_PAD_NANDF_ALE), + IMX_PINCTRL_PIN(MX53_PAD_NANDF_WP_B), + IMX_PINCTRL_PIN(MX53_PAD_NANDF_RB0), + IMX_PINCTRL_PIN(MX53_PAD_NANDF_CS0), + IMX_PINCTRL_PIN(MX53_PAD_NANDF_CS1), + IMX_PINCTRL_PIN(MX53_PAD_NANDF_CS2), + IMX_PINCTRL_PIN(MX53_PAD_NANDF_CS3), + IMX_PINCTRL_PIN(MX53_PAD_FEC_MDIO), + IMX_PINCTRL_PIN(MX53_PAD_FEC_REF_CLK), + IMX_PINCTRL_PIN(MX53_PAD_FEC_RX_ER), + IMX_PINCTRL_PIN(MX53_PAD_FEC_CRS_DV), + IMX_PINCTRL_PIN(MX53_PAD_FEC_RXD1), + IMX_PINCTRL_PIN(MX53_PAD_FEC_RXD0), + IMX_PINCTRL_PIN(MX53_PAD_FEC_TX_EN), + IMX_PINCTRL_PIN(MX53_PAD_FEC_TXD1), + IMX_PINCTRL_PIN(MX53_PAD_FEC_TXD0), + IMX_PINCTRL_PIN(MX53_PAD_FEC_MDC), + IMX_PINCTRL_PIN(MX53_PAD_PATA_DIOW), + IMX_PINCTRL_PIN(MX53_PAD_PATA_DMACK), + IMX_PINCTRL_PIN(MX53_PAD_PATA_DMARQ), + IMX_PINCTRL_PIN(MX53_PAD_PATA_BUFFER_EN), + IMX_PINCTRL_PIN(MX53_PAD_PATA_INTRQ), + IMX_PINCTRL_PIN(MX53_PAD_PATA_DIOR), + IMX_PINCTRL_PIN(MX53_PAD_PATA_RESET_B), + IMX_PINCTRL_PIN(MX53_PAD_PATA_IORDY), + IMX_PINCTRL_PIN(MX53_PAD_PATA_DA_0), + IMX_PINCTRL_PIN(MX53_PAD_PATA_DA_1), + IMX_PINCTRL_PIN(MX53_PAD_PATA_DA_2), + IMX_PINCTRL_PIN(MX53_PAD_PATA_CS_0), + IMX_PINCTRL_PIN(MX53_PAD_PATA_CS_1), + IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA0), + IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA1), + IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA2), + IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA3), + IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA4), + IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA5), + IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA6), + IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA7), + IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA8), + IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA9), + IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA10), + IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA11), + IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA12), + IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA13), + IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA14), + IMX_PINCTRL_PIN(MX53_PAD_PATA_DATA15), + IMX_PINCTRL_PIN(MX53_PAD_SD1_DATA0), + IMX_PINCTRL_PIN(MX53_PAD_SD1_DATA1), + IMX_PINCTRL_PIN(MX53_PAD_SD1_CMD), + IMX_PINCTRL_PIN(MX53_PAD_SD1_DATA2), + IMX_PINCTRL_PIN(MX53_PAD_SD1_CLK), + IMX_PINCTRL_PIN(MX53_PAD_SD1_DATA3), + IMX_PINCTRL_PIN(MX53_PAD_SD2_CLK), + IMX_PINCTRL_PIN(MX53_PAD_SD2_CMD), + IMX_PINCTRL_PIN(MX53_PAD_SD2_DATA3), + IMX_PINCTRL_PIN(MX53_PAD_SD2_DATA2), + IMX_PINCTRL_PIN(MX53_PAD_SD2_DATA1), + IMX_PINCTRL_PIN(MX53_PAD_SD2_DATA0), + IMX_PINCTRL_PIN(MX53_PAD_GPIO_0), + IMX_PINCTRL_PIN(MX53_PAD_GPIO_1), + IMX_PINCTRL_PIN(MX53_PAD_GPIO_9), + IMX_PINCTRL_PIN(MX53_PAD_GPIO_3), + IMX_PINCTRL_PIN(MX53_PAD_GPIO_6), + IMX_PINCTRL_PIN(MX53_PAD_GPIO_2), + IMX_PINCTRL_PIN(MX53_PAD_GPIO_4), + IMX_PINCTRL_PIN(MX53_PAD_GPIO_5), + IMX_PINCTRL_PIN(MX53_PAD_GPIO_7), + IMX_PINCTRL_PIN(MX53_PAD_GPIO_8), + IMX_PINCTRL_PIN(MX53_PAD_GPIO_16), + IMX_PINCTRL_PIN(MX53_PAD_GPIO_17), + IMX_PINCTRL_PIN(MX53_PAD_GPIO_18), +}; + +static struct imx_pinctrl_soc_info imx53_pinctrl_info = { + .pins = imx53_pinctrl_pads, + .npins = ARRAY_SIZE(imx53_pinctrl_pads), + .pin_regs = imx53_pin_regs, + .npin_regs = ARRAY_SIZE(imx53_pin_regs), +}; + +static struct of_device_id imx53_pinctrl_of_match[] __devinitdata = { + { .compatible = "fsl,imx53-iomuxc", }, + { /* sentinel */ } +}; + +static int __devinit imx53_pinctrl_probe(struct platform_device *pdev) +{ + return imx_pinctrl_probe(pdev, &imx53_pinctrl_info); +} + +static struct platform_driver imx53_pinctrl_driver = { + .driver = { + .name = "imx53-pinctrl", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(imx53_pinctrl_of_match), + }, + .probe = imx53_pinctrl_probe, + .remove = __devexit_p(imx_pinctrl_remove), +}; + +static int __init imx53_pinctrl_init(void) +{ + return platform_driver_register(&imx53_pinctrl_driver); +} +arch_initcall(imx53_pinctrl_init); + +static void __exit imx53_pinctrl_exit(void) +{ + platform_driver_unregister(&imx53_pinctrl_driver); +} +module_exit(imx53_pinctrl_exit); +MODULE_AUTHOR("Dong Aisheng "); +MODULE_DESCRIPTION("Freescale IMX53 pinctrl driver"); +MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/pinctrl/pinctrl-imx6q.c b/trunk/drivers/pinctrl/pinctrl-imx6q.c new file mode 100644 index 000000000000..7737d4d71a3c --- /dev/null +++ b/trunk/drivers/pinctrl/pinctrl-imx6q.c @@ -0,0 +1,2331 @@ +/* + * imx6q pinctrl driver based on imx pinmux core + * + * Copyright (C) 2012 Freescale Semiconductor, Inc. + * Copyright (C) 2012 Linaro, Inc. + * + * Author: Dong Aisheng + * + * 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 "pinctrl-imx.h" + +enum imx6q_pads { + MX6Q_PAD_SD2_DAT1 = 0, + MX6Q_PAD_SD2_DAT2 = 1, + MX6Q_PAD_SD2_DAT0 = 2, + MX6Q_PAD_RGMII_TXC = 3, + MX6Q_PAD_RGMII_TD0 = 4, + MX6Q_PAD_RGMII_TD1 = 5, + MX6Q_PAD_RGMII_TD2 = 6, + MX6Q_PAD_RGMII_TD3 = 7, + MX6Q_PAD_RGMII_RX_CTL = 8, + MX6Q_PAD_RGMII_RD0 = 9, + MX6Q_PAD_RGMII_TX_CTL = 10, + MX6Q_PAD_RGMII_RD1 = 11, + MX6Q_PAD_RGMII_RD2 = 12, + MX6Q_PAD_RGMII_RD3 = 13, + MX6Q_PAD_RGMII_RXC = 14, + MX6Q_PAD_EIM_A25 = 15, + MX6Q_PAD_EIM_EB2 = 16, + MX6Q_PAD_EIM_D16 = 17, + MX6Q_PAD_EIM_D17 = 18, + MX6Q_PAD_EIM_D18 = 19, + MX6Q_PAD_EIM_D19 = 20, + MX6Q_PAD_EIM_D20 = 21, + MX6Q_PAD_EIM_D21 = 22, + MX6Q_PAD_EIM_D22 = 23, + MX6Q_PAD_EIM_D23 = 24, + MX6Q_PAD_EIM_EB3 = 25, + MX6Q_PAD_EIM_D24 = 26, + MX6Q_PAD_EIM_D25 = 27, + MX6Q_PAD_EIM_D26 = 28, + MX6Q_PAD_EIM_D27 = 29, + MX6Q_PAD_EIM_D28 = 30, + MX6Q_PAD_EIM_D29 = 31, + MX6Q_PAD_EIM_D30 = 32, + MX6Q_PAD_EIM_D31 = 33, + MX6Q_PAD_EIM_A24 = 34, + MX6Q_PAD_EIM_A23 = 35, + MX6Q_PAD_EIM_A22 = 36, + MX6Q_PAD_EIM_A21 = 37, + MX6Q_PAD_EIM_A20 = 38, + MX6Q_PAD_EIM_A19 = 39, + MX6Q_PAD_EIM_A18 = 40, + MX6Q_PAD_EIM_A17 = 41, + MX6Q_PAD_EIM_A16 = 42, + MX6Q_PAD_EIM_CS0 = 43, + MX6Q_PAD_EIM_CS1 = 44, + MX6Q_PAD_EIM_OE = 45, + MX6Q_PAD_EIM_RW = 46, + MX6Q_PAD_EIM_LBA = 47, + MX6Q_PAD_EIM_EB0 = 48, + MX6Q_PAD_EIM_EB1 = 49, + MX6Q_PAD_EIM_DA0 = 50, + MX6Q_PAD_EIM_DA1 = 51, + MX6Q_PAD_EIM_DA2 = 52, + MX6Q_PAD_EIM_DA3 = 53, + MX6Q_PAD_EIM_DA4 = 54, + MX6Q_PAD_EIM_DA5 = 55, + MX6Q_PAD_EIM_DA6 = 56, + MX6Q_PAD_EIM_DA7 = 57, + MX6Q_PAD_EIM_DA8 = 58, + MX6Q_PAD_EIM_DA9 = 59, + MX6Q_PAD_EIM_DA10 = 60, + MX6Q_PAD_EIM_DA11 = 61, + MX6Q_PAD_EIM_DA12 = 62, + MX6Q_PAD_EIM_DA13 = 63, + MX6Q_PAD_EIM_DA14 = 64, + MX6Q_PAD_EIM_DA15 = 65, + MX6Q_PAD_EIM_WAIT = 66, + MX6Q_PAD_EIM_BCLK = 67, + MX6Q_PAD_DI0_DISP_CLK = 68, + MX6Q_PAD_DI0_PIN15 = 69, + MX6Q_PAD_DI0_PIN2 = 70, + MX6Q_PAD_DI0_PIN3 = 71, + MX6Q_PAD_DI0_PIN4 = 72, + MX6Q_PAD_DISP0_DAT0 = 73, + MX6Q_PAD_DISP0_DAT1 = 74, + MX6Q_PAD_DISP0_DAT2 = 75, + MX6Q_PAD_DISP0_DAT3 = 76, + MX6Q_PAD_DISP0_DAT4 = 77, + MX6Q_PAD_DISP0_DAT5 = 78, + MX6Q_PAD_DISP0_DAT6 = 79, + MX6Q_PAD_DISP0_DAT7 = 80, + MX6Q_PAD_DISP0_DAT8 = 81, + MX6Q_PAD_DISP0_DAT9 = 82, + MX6Q_PAD_DISP0_DAT10 = 83, + MX6Q_PAD_DISP0_DAT11 = 84, + MX6Q_PAD_DISP0_DAT12 = 85, + MX6Q_PAD_DISP0_DAT13 = 86, + MX6Q_PAD_DISP0_DAT14 = 87, + MX6Q_PAD_DISP0_DAT15 = 88, + MX6Q_PAD_DISP0_DAT16 = 89, + MX6Q_PAD_DISP0_DAT17 = 90, + MX6Q_PAD_DISP0_DAT18 = 91, + MX6Q_PAD_DISP0_DAT19 = 92, + MX6Q_PAD_DISP0_DAT20 = 93, + MX6Q_PAD_DISP0_DAT21 = 94, + MX6Q_PAD_DISP0_DAT22 = 95, + MX6Q_PAD_DISP0_DAT23 = 96, + MX6Q_PAD_ENET_MDIO = 97, + MX6Q_PAD_ENET_REF_CLK = 98, + MX6Q_PAD_ENET_RX_ER = 99, + MX6Q_PAD_ENET_CRS_DV = 100, + MX6Q_PAD_ENET_RXD1 = 101, + MX6Q_PAD_ENET_RXD0 = 102, + MX6Q_PAD_ENET_TX_EN = 103, + MX6Q_PAD_ENET_TXD1 = 104, + MX6Q_PAD_ENET_TXD0 = 105, + MX6Q_PAD_ENET_MDC = 106, + MX6Q_PAD_DRAM_D40 = 107, + MX6Q_PAD_DRAM_D41 = 108, + MX6Q_PAD_DRAM_D42 = 109, + MX6Q_PAD_DRAM_D43 = 110, + MX6Q_PAD_DRAM_D44 = 111, + MX6Q_PAD_DRAM_D45 = 112, + MX6Q_PAD_DRAM_D46 = 113, + MX6Q_PAD_DRAM_D47 = 114, + MX6Q_PAD_DRAM_SDQS5 = 115, + MX6Q_PAD_DRAM_DQM5 = 116, + MX6Q_PAD_DRAM_D32 = 117, + MX6Q_PAD_DRAM_D33 = 118, + MX6Q_PAD_DRAM_D34 = 119, + MX6Q_PAD_DRAM_D35 = 120, + MX6Q_PAD_DRAM_D36 = 121, + MX6Q_PAD_DRAM_D37 = 122, + MX6Q_PAD_DRAM_D38 = 123, + MX6Q_PAD_DRAM_D39 = 124, + MX6Q_PAD_DRAM_DQM4 = 125, + MX6Q_PAD_DRAM_SDQS4 = 126, + MX6Q_PAD_DRAM_D24 = 127, + MX6Q_PAD_DRAM_D25 = 128, + MX6Q_PAD_DRAM_D26 = 129, + MX6Q_PAD_DRAM_D27 = 130, + MX6Q_PAD_DRAM_D28 = 131, + MX6Q_PAD_DRAM_D29 = 132, + MX6Q_PAD_DRAM_SDQS3 = 133, + MX6Q_PAD_DRAM_D30 = 134, + MX6Q_PAD_DRAM_D31 = 135, + MX6Q_PAD_DRAM_DQM3 = 136, + MX6Q_PAD_DRAM_D16 = 137, + MX6Q_PAD_DRAM_D17 = 138, + MX6Q_PAD_DRAM_D18 = 139, + MX6Q_PAD_DRAM_D19 = 140, + MX6Q_PAD_DRAM_D20 = 141, + MX6Q_PAD_DRAM_D21 = 142, + MX6Q_PAD_DRAM_D22 = 143, + MX6Q_PAD_DRAM_SDQS2 = 144, + MX6Q_PAD_DRAM_D23 = 145, + MX6Q_PAD_DRAM_DQM2 = 146, + MX6Q_PAD_DRAM_A0 = 147, + MX6Q_PAD_DRAM_A1 = 148, + MX6Q_PAD_DRAM_A2 = 149, + MX6Q_PAD_DRAM_A3 = 150, + MX6Q_PAD_DRAM_A4 = 151, + MX6Q_PAD_DRAM_A5 = 152, + MX6Q_PAD_DRAM_A6 = 153, + MX6Q_PAD_DRAM_A7 = 154, + MX6Q_PAD_DRAM_A8 = 155, + MX6Q_PAD_DRAM_A9 = 156, + MX6Q_PAD_DRAM_A10 = 157, + MX6Q_PAD_DRAM_A11 = 158, + MX6Q_PAD_DRAM_A12 = 159, + MX6Q_PAD_DRAM_A13 = 160, + MX6Q_PAD_DRAM_A14 = 161, + MX6Q_PAD_DRAM_A15 = 162, + MX6Q_PAD_DRAM_CAS = 163, + MX6Q_PAD_DRAM_CS0 = 164, + MX6Q_PAD_DRAM_CS1 = 165, + MX6Q_PAD_DRAM_RAS = 166, + MX6Q_PAD_DRAM_RESET = 167, + MX6Q_PAD_DRAM_SDBA0 = 168, + MX6Q_PAD_DRAM_SDBA1 = 169, + MX6Q_PAD_DRAM_SDCLK_0 = 170, + MX6Q_PAD_DRAM_SDBA2 = 171, + MX6Q_PAD_DRAM_SDCKE0 = 172, + MX6Q_PAD_DRAM_SDCLK_1 = 173, + MX6Q_PAD_DRAM_SDCKE1 = 174, + MX6Q_PAD_DRAM_SDODT0 = 175, + MX6Q_PAD_DRAM_SDODT1 = 176, + MX6Q_PAD_DRAM_SDWE = 177, + MX6Q_PAD_DRAM_D0 = 178, + MX6Q_PAD_DRAM_D1 = 179, + MX6Q_PAD_DRAM_D2 = 180, + MX6Q_PAD_DRAM_D3 = 181, + MX6Q_PAD_DRAM_D4 = 182, + MX6Q_PAD_DRAM_D5 = 183, + MX6Q_PAD_DRAM_SDQS0 = 184, + MX6Q_PAD_DRAM_D6 = 185, + MX6Q_PAD_DRAM_D7 = 186, + MX6Q_PAD_DRAM_DQM0 = 187, + MX6Q_PAD_DRAM_D8 = 188, + MX6Q_PAD_DRAM_D9 = 189, + MX6Q_PAD_DRAM_D10 = 190, + MX6Q_PAD_DRAM_D11 = 191, + MX6Q_PAD_DRAM_D12 = 192, + MX6Q_PAD_DRAM_D13 = 193, + MX6Q_PAD_DRAM_D14 = 194, + MX6Q_PAD_DRAM_SDQS1 = 195, + MX6Q_PAD_DRAM_D15 = 196, + MX6Q_PAD_DRAM_DQM1 = 197, + MX6Q_PAD_DRAM_D48 = 198, + MX6Q_PAD_DRAM_D49 = 199, + MX6Q_PAD_DRAM_D50 = 200, + MX6Q_PAD_DRAM_D51 = 201, + MX6Q_PAD_DRAM_D52 = 202, + MX6Q_PAD_DRAM_D53 = 203, + MX6Q_PAD_DRAM_D54 = 204, + MX6Q_PAD_DRAM_D55 = 205, + MX6Q_PAD_DRAM_SDQS6 = 206, + MX6Q_PAD_DRAM_DQM6 = 207, + MX6Q_PAD_DRAM_D56 = 208, + MX6Q_PAD_DRAM_SDQS7 = 209, + MX6Q_PAD_DRAM_D57 = 210, + MX6Q_PAD_DRAM_D58 = 211, + MX6Q_PAD_DRAM_D59 = 212, + MX6Q_PAD_DRAM_D60 = 213, + MX6Q_PAD_DRAM_DQM7 = 214, + MX6Q_PAD_DRAM_D61 = 215, + MX6Q_PAD_DRAM_D62 = 216, + MX6Q_PAD_DRAM_D63 = 217, + MX6Q_PAD_KEY_COL0 = 218, + MX6Q_PAD_KEY_ROW0 = 219, + MX6Q_PAD_KEY_COL1 = 220, + MX6Q_PAD_KEY_ROW1 = 221, + MX6Q_PAD_KEY_COL2 = 222, + MX6Q_PAD_KEY_ROW2 = 223, + MX6Q_PAD_KEY_COL3 = 224, + MX6Q_PAD_KEY_ROW3 = 225, + MX6Q_PAD_KEY_COL4 = 226, + MX6Q_PAD_KEY_ROW4 = 227, + MX6Q_PAD_GPIO_0 = 228, + MX6Q_PAD_GPIO_1 = 229, + MX6Q_PAD_GPIO_9 = 230, + MX6Q_PAD_GPIO_3 = 231, + MX6Q_PAD_GPIO_6 = 232, + MX6Q_PAD_GPIO_2 = 233, + MX6Q_PAD_GPIO_4 = 234, + MX6Q_PAD_GPIO_5 = 235, + MX6Q_PAD_GPIO_7 = 236, + MX6Q_PAD_GPIO_8 = 237, + MX6Q_PAD_GPIO_16 = 238, + MX6Q_PAD_GPIO_17 = 239, + MX6Q_PAD_GPIO_18 = 240, + MX6Q_PAD_GPIO_19 = 241, + MX6Q_PAD_CSI0_PIXCLK = 242, + MX6Q_PAD_CSI0_MCLK = 243, + MX6Q_PAD_CSI0_DATA_EN = 244, + MX6Q_PAD_CSI0_VSYNC = 245, + MX6Q_PAD_CSI0_DAT4 = 246, + MX6Q_PAD_CSI0_DAT5 = 247, + MX6Q_PAD_CSI0_DAT6 = 248, + MX6Q_PAD_CSI0_DAT7 = 249, + MX6Q_PAD_CSI0_DAT8 = 250, + MX6Q_PAD_CSI0_DAT9 = 251, + MX6Q_PAD_CSI0_DAT10 = 252, + MX6Q_PAD_CSI0_DAT11 = 253, + MX6Q_PAD_CSI0_DAT12 = 254, + MX6Q_PAD_CSI0_DAT13 = 255, + MX6Q_PAD_CSI0_DAT14 = 256, + MX6Q_PAD_CSI0_DAT15 = 257, + MX6Q_PAD_CSI0_DAT16 = 258, + MX6Q_PAD_CSI0_DAT17 = 259, + MX6Q_PAD_CSI0_DAT18 = 260, + MX6Q_PAD_CSI0_DAT19 = 261, + MX6Q_PAD_JTAG_TMS = 262, + MX6Q_PAD_JTAG_MOD = 263, + MX6Q_PAD_JTAG_TRSTB = 264, + MX6Q_PAD_JTAG_TDI = 265, + MX6Q_PAD_JTAG_TCK = 266, + MX6Q_PAD_JTAG_TDO = 267, + MX6Q_PAD_LVDS1_TX3_P = 268, + MX6Q_PAD_LVDS1_TX2_P = 269, + MX6Q_PAD_LVDS1_CLK_P = 270, + MX6Q_PAD_LVDS1_TX1_P = 271, + MX6Q_PAD_LVDS1_TX0_P = 272, + MX6Q_PAD_LVDS0_TX3_P = 273, + MX6Q_PAD_LVDS0_CLK_P = 274, + MX6Q_PAD_LVDS0_TX2_P = 275, + MX6Q_PAD_LVDS0_TX1_P = 276, + MX6Q_PAD_LVDS0_TX0_P = 277, + MX6Q_PAD_TAMPER = 278, + MX6Q_PAD_PMIC_ON_REQ = 279, + MX6Q_PAD_PMIC_STBY_REQ = 280, + MX6Q_PAD_POR_B = 281, + MX6Q_PAD_BOOT_MODE1 = 282, + MX6Q_PAD_RESET_IN_B = 283, + MX6Q_PAD_BOOT_MODE0 = 284, + MX6Q_PAD_TEST_MODE = 285, + MX6Q_PAD_SD3_DAT7 = 286, + MX6Q_PAD_SD3_DAT6 = 287, + MX6Q_PAD_SD3_DAT5 = 288, + MX6Q_PAD_SD3_DAT4 = 289, + MX6Q_PAD_SD3_CMD = 290, + MX6Q_PAD_SD3_CLK = 291, + MX6Q_PAD_SD3_DAT0 = 292, + MX6Q_PAD_SD3_DAT1 = 293, + MX6Q_PAD_SD3_DAT2 = 294, + MX6Q_PAD_SD3_DAT3 = 295, + MX6Q_PAD_SD3_RST = 296, + MX6Q_PAD_NANDF_CLE = 297, + MX6Q_PAD_NANDF_ALE = 298, + MX6Q_PAD_NANDF_WP_B = 299, + MX6Q_PAD_NANDF_RB0 = 300, + MX6Q_PAD_NANDF_CS0 = 301, + MX6Q_PAD_NANDF_CS1 = 302, + MX6Q_PAD_NANDF_CS2 = 303, + MX6Q_PAD_NANDF_CS3 = 304, + MX6Q_PAD_SD4_CMD = 305, + MX6Q_PAD_SD4_CLK = 306, + MX6Q_PAD_NANDF_D0 = 307, + MX6Q_PAD_NANDF_D1 = 308, + MX6Q_PAD_NANDF_D2 = 309, + MX6Q_PAD_NANDF_D3 = 310, + MX6Q_PAD_NANDF_D4 = 311, + MX6Q_PAD_NANDF_D5 = 312, + MX6Q_PAD_NANDF_D6 = 313, + MX6Q_PAD_NANDF_D7 = 314, + MX6Q_PAD_SD4_DAT0 = 315, + MX6Q_PAD_SD4_DAT1 = 316, + MX6Q_PAD_SD4_DAT2 = 317, + MX6Q_PAD_SD4_DAT3 = 318, + MX6Q_PAD_SD4_DAT4 = 319, + MX6Q_PAD_SD4_DAT5 = 320, + MX6Q_PAD_SD4_DAT6 = 321, + MX6Q_PAD_SD4_DAT7 = 322, + MX6Q_PAD_SD1_DAT1 = 323, + MX6Q_PAD_SD1_DAT0 = 324, + MX6Q_PAD_SD1_DAT3 = 325, + MX6Q_PAD_SD1_CMD = 326, + MX6Q_PAD_SD1_DAT2 = 327, + MX6Q_PAD_SD1_CLK = 328, + MX6Q_PAD_SD2_CLK = 329, + MX6Q_PAD_SD2_CMD = 330, + MX6Q_PAD_SD2_DAT3 = 331, +}; + +/* imx6q register maps */ +static struct imx_pin_reg imx6q_pin_regs[] = { + IMX_PIN_REG(MX6Q_PAD_SD2_DAT1, 0x0360, 0x004C, 0, 0x0000, 0), /* MX6Q_PAD_SD2_DAT1__USDHC2_DAT1 */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT1, 0x0360, 0x004C, 1, 0x0834, 0), /* MX6Q_PAD_SD2_DAT1__ECSPI5_SS0 */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT1, 0x0360, 0x004C, 2, 0x0000, 0), /* MX6Q_PAD_SD2_DAT1__WEIM_WEIM_CS_2 */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT1, 0x0360, 0x004C, 3, 0x07C8, 0), /* MX6Q_PAD_SD2_DAT1__AUDMUX_AUD4_TXFS */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT1, 0x0360, 0x004C, 4, 0x08F0, 0), /* MX6Q_PAD_SD2_DAT1__KPP_COL_7 */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT1, 0x0360, 0x004C, 5, 0x0000, 0), /* MX6Q_PAD_SD2_DAT1__GPIO_1_14 */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT1, 0x0360, 0x004C, 6, 0x0000, 0), /* MX6Q_PAD_SD2_DAT1__CCM_WAIT */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT1, 0x0360, 0x004C, 7, 0x0000, 0), /* MX6Q_PAD_SD2_DAT1__ANATOP_TESTO_0 */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT2, 0x0364, 0x0050, 0, 0x0000, 0), /* MX6Q_PAD_SD2_DAT2__USDHC2_DAT2 */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT2, 0x0364, 0x0050, 1, 0x0838, 0), /* MX6Q_PAD_SD2_DAT2__ECSPI5_SS1 */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT2, 0x0364, 0x0050, 2, 0x0000, 0), /* MX6Q_PAD_SD2_DAT2__WEIM_WEIM_CS_3 */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT2, 0x0364, 0x0050, 3, 0x07B8, 0), /* MX6Q_PAD_SD2_DAT2__AUDMUX_AUD4_TXD */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT2, 0x0364, 0x0050, 4, 0x08F8, 0), /* MX6Q_PAD_SD2_DAT2__KPP_ROW_6 */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT2, 0x0364, 0x0050, 5, 0x0000, 0), /* MX6Q_PAD_SD2_DAT2__GPIO_1_13 */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT2, 0x0364, 0x0050, 6, 0x0000, 0), /* MX6Q_PAD_SD2_DAT2__CCM_STOP */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT2, 0x0364, 0x0050, 7, 0x0000, 0), /* MX6Q_PAD_SD2_DAT2__ANATOP_TESTO_1 */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT0, 0x0368, 0x0054, 0, 0x0000, 0), /* MX6Q_PAD_SD2_DAT0__USDHC2_DAT0 */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT0, 0x0368, 0x0054, 1, 0x082C, 0), /* MX6Q_PAD_SD2_DAT0__ECSPI5_MISO */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT0, 0x0368, 0x0054, 3, 0x07B4, 0), /* MX6Q_PAD_SD2_DAT0__AUDMUX_AUD4_RXD */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT0, 0x0368, 0x0054, 4, 0x08FC, 0), /* MX6Q_PAD_SD2_DAT0__KPP_ROW_7 */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT0, 0x0368, 0x0054, 5, 0x0000, 0), /* MX6Q_PAD_SD2_DAT0__GPIO_1_15 */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT0, 0x0368, 0x0054, 6, 0x0000, 0), /* MX6Q_PAD_SD2_DAT0__DCIC2_DCIC_OUT */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT0, 0x0368, 0x0054, 7, 0x0000, 0), /* MX6Q_PAD_SD2_DAT0__TESTO_2 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TXC, 0x036C, 0x0058, 0, 0x0000, 0), /* MX6Q_PAD_RGMII_TXC__USBOH3_H2_DATA */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TXC, 0x036C, 0x0058, 1, 0x0000, 0), /* MX6Q_PAD_RGMII_TXC__ENET_RGMII_TXC */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TXC, 0x036C, 0x0058, 2, 0x0918, 0), /* MX6Q_PAD_RGMII_TXC__SPDIF_SPDIF_EXTCLK */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TXC, 0x036C, 0x0058, 5, 0x0000, 0), /* MX6Q_PAD_RGMII_TXC__GPIO_6_19 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TXC, 0x036C, 0x0058, 6, 0x0000, 0), /* MX6Q_PAD_RGMII_TXC__MIPI_CORE_DPHY_IN_0 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TXC, 0x036C, 0x0058, 7, 0x0000, 0), /* MX6Q_PAD_RGMII_TXC__ANATOP_24M_OUT */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TD0, 0x0370, 0x005C, 0, 0x0000, 0), /* MX6Q_PAD_RGMII_TD0__MIPI_HSI_CRL_TX_RDY */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TD0, 0x0370, 0x005C, 1, 0x0000, 0), /* MX6Q_PAD_RGMII_TD0__ENET_RGMII_TD0 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TD0, 0x0370, 0x005C, 5, 0x0000, 0), /* MX6Q_PAD_RGMII_TD0__GPIO_6_20 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TD0, 0x0370, 0x005C, 6, 0x0000, 0), /* MX6Q_PAD_RGMII_TD0__MIPI_CORE_DPHY_IN_1 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TD1, 0x0374, 0x0060, 0, 0x0000, 0), /* MX6Q_PAD_RGMII_TD1__MIPI_HSI_CRL_RX_FLG */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TD1, 0x0374, 0x0060, 1, 0x0000, 0), /* MX6Q_PAD_RGMII_TD1__ENET_RGMII_TD1 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TD1, 0x0374, 0x0060, 5, 0x0000, 0), /* MX6Q_PAD_RGMII_TD1__GPIO_6_21 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TD1, 0x0374, 0x0060, 6, 0x0000, 0), /* MX6Q_PAD_RGMII_TD1__MIPI_CORE_DPHY_IN_2 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TD1, 0x0374, 0x0060, 7, 0x0000, 0), /* MX6Q_PAD_RGMII_TD1__CCM_PLL3_BYP */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TD2, 0x0378, 0x0064, 0, 0x0000, 0), /* MX6Q_PAD_RGMII_TD2__MIPI_HSI_CRL_RX_DTA */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TD2, 0x0378, 0x0064, 1, 0x0000, 0), /* MX6Q_PAD_RGMII_TD2__ENET_RGMII_TD2 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TD2, 0x0378, 0x0064, 5, 0x0000, 0), /* MX6Q_PAD_RGMII_TD2__GPIO_6_22 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TD2, 0x0378, 0x0064, 6, 0x0000, 0), /* MX6Q_PAD_RGMII_TD2__MIPI_CORE_DPHY_IN_3 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TD2, 0x0378, 0x0064, 7, 0x0000, 0), /* MX6Q_PAD_RGMII_TD2__CCM_PLL2_BYP */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TD3, 0x037C, 0x0068, 0, 0x0000, 0), /* MX6Q_PAD_RGMII_TD3__MIPI_HSI_CRL_RX_WAK */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TD3, 0x037C, 0x0068, 1, 0x0000, 0), /* MX6Q_PAD_RGMII_TD3__ENET_RGMII_TD3 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TD3, 0x037C, 0x0068, 5, 0x0000, 0), /* MX6Q_PAD_RGMII_TD3__GPIO_6_23 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TD3, 0x037C, 0x0068, 6, 0x0000, 0), /* MX6Q_PAD_RGMII_TD3__MIPI_CORE_DPHY_IN_4 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_RX_CTL, 0x0380, 0x006C, 0, 0x0000, 0), /* MX6Q_PAD_RGMII_RX_CTL__USBOH3_H3_DATA */ + IMX_PIN_REG(MX6Q_PAD_RGMII_RX_CTL, 0x0380, 0x006C, 1, 0x0858, 0), /* MX6Q_PAD_RGMII_RX_CTL__RGMII_RX_CTL */ + IMX_PIN_REG(MX6Q_PAD_RGMII_RX_CTL, 0x0380, 0x006C, 5, 0x0000, 0), /* MX6Q_PAD_RGMII_RX_CTL__GPIO_6_24 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_RX_CTL, 0x0380, 0x006C, 6, 0x0000, 0), /* MX6Q_PAD_RGMII_RX_CTL__MIPI_DPHY_IN_5 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_RD0, 0x0384, 0x0070, 0, 0x0000, 0), /* MX6Q_PAD_RGMII_RD0__MIPI_HSI_CRL_RX_RDY */ + IMX_PIN_REG(MX6Q_PAD_RGMII_RD0, 0x0384, 0x0070, 1, 0x0848, 0), /* MX6Q_PAD_RGMII_RD0__ENET_RGMII_RD0 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_RD0, 0x0384, 0x0070, 5, 0x0000, 0), /* MX6Q_PAD_RGMII_RD0__GPIO_6_25 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_RD0, 0x0384, 0x0070, 6, 0x0000, 0), /* MX6Q_PAD_RGMII_RD0__MIPI_CORE_DPHY_IN_6 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TX_CTL, 0x0388, 0x0074, 0, 0x0000, 0), /* MX6Q_PAD_RGMII_TX_CTL__USBOH3_H2_STROBE */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TX_CTL, 0x0388, 0x0074, 1, 0x0000, 0), /* MX6Q_PAD_RGMII_TX_CTL__RGMII_TX_CTL */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TX_CTL, 0x0388, 0x0074, 5, 0x0000, 0), /* MX6Q_PAD_RGMII_TX_CTL__GPIO_6_26 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TX_CTL, 0x0388, 0x0074, 6, 0x0000, 0), /* MX6Q_PAD_RGMII_TX_CTL__CORE_DPHY_IN_7 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_TX_CTL, 0x0388, 0x0074, 7, 0x083C, 0), /* MX6Q_PAD_RGMII_TX_CTL__ANATOP_REF_OUT */ + IMX_PIN_REG(MX6Q_PAD_RGMII_RD1, 0x038C, 0x0078, 0, 0x0000, 0), /* MX6Q_PAD_RGMII_RD1__MIPI_HSI_CTRL_TX_FL */ + IMX_PIN_REG(MX6Q_PAD_RGMII_RD1, 0x038C, 0x0078, 1, 0x084C, 0), /* MX6Q_PAD_RGMII_RD1__ENET_RGMII_RD1 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_RD1, 0x038C, 0x0078, 5, 0x0000, 0), /* MX6Q_PAD_RGMII_RD1__GPIO_6_27 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_RD1, 0x038C, 0x0078, 6, 0x0000, 0), /* MX6Q_PAD_RGMII_RD1__CORE_DPHY_TEST_IN_8 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_RD1, 0x038C, 0x0078, 7, 0x0000, 0), /* MX6Q_PAD_RGMII_RD1__SJC_FAIL */ + IMX_PIN_REG(MX6Q_PAD_RGMII_RD2, 0x0390, 0x007C, 0, 0x0000, 0), /* MX6Q_PAD_RGMII_RD2__MIPI_HSI_CRL_TX_DTA */ + IMX_PIN_REG(MX6Q_PAD_RGMII_RD2, 0x0390, 0x007C, 1, 0x0850, 0), /* MX6Q_PAD_RGMII_RD2__ENET_RGMII_RD2 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_RD2, 0x0390, 0x007C, 5, 0x0000, 0), /* MX6Q_PAD_RGMII_RD2__GPIO_6_28 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_RD2, 0x0390, 0x007C, 6, 0x0000, 0), /* MX6Q_PAD_RGMII_RD2__MIPI_CORE_DPHY_IN_9 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_RD3, 0x0394, 0x0080, 0, 0x0000, 0), /* MX6Q_PAD_RGMII_RD3__MIPI_HSI_CRL_TX_WAK */ + IMX_PIN_REG(MX6Q_PAD_RGMII_RD3, 0x0394, 0x0080, 1, 0x0854, 0), /* MX6Q_PAD_RGMII_RD3__ENET_RGMII_RD3 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_RD3, 0x0394, 0x0080, 5, 0x0000, 0), /* MX6Q_PAD_RGMII_RD3__GPIO_6_29 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_RD3, 0x0394, 0x0080, 6, 0x0000, 0), /* MX6Q_PAD_RGMII_RD3__MIPI_CORE_DPHY_IN10 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_RXC, 0x0398, 0x0084, 0, 0x0000, 0), /* MX6Q_PAD_RGMII_RXC__USBOH3_H3_STROBE */ + IMX_PIN_REG(MX6Q_PAD_RGMII_RXC, 0x0398, 0x0084, 1, 0x0844, 0), /* MX6Q_PAD_RGMII_RXC__ENET_RGMII_RXC */ + IMX_PIN_REG(MX6Q_PAD_RGMII_RXC, 0x0398, 0x0084, 5, 0x0000, 0), /* MX6Q_PAD_RGMII_RXC__GPIO_6_30 */ + IMX_PIN_REG(MX6Q_PAD_RGMII_RXC, 0x0398, 0x0084, 6, 0x0000, 0), /* MX6Q_PAD_RGMII_RXC__MIPI_CORE_DPHY_IN11 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A25, 0x039C, 0x0088, 0, 0x0000, 0), /* MX6Q_PAD_EIM_A25__WEIM_WEIM_A_25 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A25, 0x039C, 0x0088, 1, 0x0000, 0), /* MX6Q_PAD_EIM_A25__ECSPI4_SS1 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A25, 0x039C, 0x0088, 2, 0x0000, 0), /* MX6Q_PAD_EIM_A25__ECSPI2_RDY */ + IMX_PIN_REG(MX6Q_PAD_EIM_A25, 0x039C, 0x0088, 3, 0x0000, 0), /* MX6Q_PAD_EIM_A25__IPU1_DI1_PIN12 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A25, 0x039C, 0x0088, 4, 0x0000, 0), /* MX6Q_PAD_EIM_A25__IPU1_DI0_D1_CS */ + IMX_PIN_REG(MX6Q_PAD_EIM_A25, 0x039C, 0x0088, 5, 0x0000, 0), /* MX6Q_PAD_EIM_A25__GPIO_5_2 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A25, 0x039C, 0x0088, 6, 0x088C, 0), /* MX6Q_PAD_EIM_A25__HDMI_TX_CEC_LINE */ + IMX_PIN_REG(MX6Q_PAD_EIM_A25, 0x039C, 0x0088, 7, 0x0000, 0), /* MX6Q_PAD_EIM_A25__PL301_PER1_HBURST_0 */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB2, 0x03A0, 0x008C, 0, 0x0000, 0), /* MX6Q_PAD_EIM_EB2__WEIM_WEIM_EB_2 */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB2, 0x03A0, 0x008C, 1, 0x0800, 0), /* MX6Q_PAD_EIM_EB2__ECSPI1_SS0 */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB2, 0x03A0, 0x008C, 2, 0x07EC, 0), /* MX6Q_PAD_EIM_EB2__CCM_DI1_EXT_CLK */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB2, 0x03A0, 0x008C, 3, 0x08D4, 0), /* MX6Q_PAD_EIM_EB2__IPU2_CSI1_D_19 */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB2, 0x03A0, 0x008C, 4, 0x0890, 0), /* MX6Q_PAD_EIM_EB2__HDMI_TX_DDC_SCL */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB2, 0x03A0, 0x008C, 5, 0x0000, 0), /* MX6Q_PAD_EIM_EB2__GPIO_2_30 */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB2, 0x03A0, 0x008C, 6, 0x08A0, 0), /* MX6Q_PAD_EIM_EB2__I2C2_SCL */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB2, 0x03A0, 0x008C, 7, 0x0000, 0), /* MX6Q_PAD_EIM_EB2__SRC_BT_CFG_30 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D16, 0x03A4, 0x0090, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D16__WEIM_WEIM_D_16 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D16, 0x03A4, 0x0090, 1, 0x07F4, 0), /* MX6Q_PAD_EIM_D16__ECSPI1_SCLK */ + IMX_PIN_REG(MX6Q_PAD_EIM_D16, 0x03A4, 0x0090, 2, 0x0000, 0), /* MX6Q_PAD_EIM_D16__IPU1_DI0_PIN5 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D16, 0x03A4, 0x0090, 3, 0x08D0, 0), /* MX6Q_PAD_EIM_D16__IPU2_CSI1_D_18 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D16, 0x03A4, 0x0090, 4, 0x0894, 0), /* MX6Q_PAD_EIM_D16__HDMI_TX_DDC_SDA */ + IMX_PIN_REG(MX6Q_PAD_EIM_D16, 0x03A4, 0x0090, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D16__GPIO_3_16 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D16, 0x03A4, 0x0090, 6, 0x08A4, 0), /* MX6Q_PAD_EIM_D16__I2C2_SDA */ + IMX_PIN_REG(MX6Q_PAD_EIM_D17, 0x03A8, 0x0094, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D17__WEIM_WEIM_D_17 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D17, 0x03A8, 0x0094, 1, 0x07F8, 0), /* MX6Q_PAD_EIM_D17__ECSPI1_MISO */ + IMX_PIN_REG(MX6Q_PAD_EIM_D17, 0x03A8, 0x0094, 2, 0x0000, 0), /* MX6Q_PAD_EIM_D17__IPU1_DI0_PIN6 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D17, 0x03A8, 0x0094, 3, 0x08E0, 0), /* MX6Q_PAD_EIM_D17__IPU2_CSI1_PIXCLK */ + IMX_PIN_REG(MX6Q_PAD_EIM_D17, 0x03A8, 0x0094, 4, 0x0000, 0), /* MX6Q_PAD_EIM_D17__DCIC1_DCIC_OUT */ + IMX_PIN_REG(MX6Q_PAD_EIM_D17, 0x03A8, 0x0094, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D17__GPIO_3_17 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D17, 0x03A8, 0x0094, 6, 0x08A8, 0), /* MX6Q_PAD_EIM_D17__I2C3_SCL */ + IMX_PIN_REG(MX6Q_PAD_EIM_D17, 0x03A8, 0x0094, 7, 0x0000, 0), /* MX6Q_PAD_EIM_D17__PL301_PER1_HBURST_1 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D18, 0x03AC, 0x0098, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D18__WEIM_WEIM_D_18 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D18, 0x03AC, 0x0098, 1, 0x07FC, 0), /* MX6Q_PAD_EIM_D18__ECSPI1_MOSI */ + IMX_PIN_REG(MX6Q_PAD_EIM_D18, 0x03AC, 0x0098, 2, 0x0000, 0), /* MX6Q_PAD_EIM_D18__IPU1_DI0_PIN7 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D18, 0x03AC, 0x0098, 3, 0x08CC, 0), /* MX6Q_PAD_EIM_D18__IPU2_CSI1_D_17 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D18, 0x03AC, 0x0098, 4, 0x0000, 0), /* MX6Q_PAD_EIM_D18__IPU1_DI1_D0_CS */ + IMX_PIN_REG(MX6Q_PAD_EIM_D18, 0x03AC, 0x0098, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D18__GPIO_3_18 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D18, 0x03AC, 0x0098, 6, 0x08AC, 0), /* MX6Q_PAD_EIM_D18__I2C3_SDA */ + IMX_PIN_REG(MX6Q_PAD_EIM_D18, 0x03AC, 0x0098, 7, 0x0000, 0), /* MX6Q_PAD_EIM_D18__PL301_PER1_HBURST_2 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D19, 0x03B0, 0x009C, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D19__WEIM_WEIM_D_19 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D19, 0x03B0, 0x009C, 1, 0x0804, 0), /* MX6Q_PAD_EIM_D19__ECSPI1_SS1 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D19, 0x03B0, 0x009C, 2, 0x0000, 0), /* MX6Q_PAD_EIM_D19__IPU1_DI0_PIN8 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D19, 0x03B0, 0x009C, 3, 0x08C8, 0), /* MX6Q_PAD_EIM_D19__IPU2_CSI1_D_16 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D19, 0x03B0, 0x009C, 4, 0x091C, 0), /* MX6Q_PAD_EIM_D19__UART1_CTS */ + IMX_PIN_REG(MX6Q_PAD_EIM_D19, 0x03B0, 0x009C, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D19__GPIO_3_19 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D19, 0x03B0, 0x009C, 6, 0x0000, 0), /* MX6Q_PAD_EIM_D19__EPIT1_EPITO */ + IMX_PIN_REG(MX6Q_PAD_EIM_D19, 0x03B0, 0x009C, 7, 0x0000, 0), /* MX6Q_PAD_EIM_D19__PL301_PER1_HRESP */ + IMX_PIN_REG(MX6Q_PAD_EIM_D20, 0x03B4, 0x00A0, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D20__WEIM_WEIM_D_20 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D20, 0x03B4, 0x00A0, 1, 0x0824, 0), /* MX6Q_PAD_EIM_D20__ECSPI4_SS0 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D20, 0x03B4, 0x00A0, 2, 0x0000, 0), /* MX6Q_PAD_EIM_D20__IPU1_DI0_PIN16 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D20, 0x03B4, 0x00A0, 3, 0x08C4, 0), /* MX6Q_PAD_EIM_D20__IPU2_CSI1_D_15 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D20, 0x03B4, 0x00A0, 4, 0x091C, 1), /* MX6Q_PAD_EIM_D20__UART1_RTS */ + IMX_PIN_REG(MX6Q_PAD_EIM_D20, 0x03B4, 0x00A0, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D20__GPIO_3_20 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D20, 0x03B4, 0x00A0, 6, 0x0000, 0), /* MX6Q_PAD_EIM_D20__EPIT2_EPITO */ + IMX_PIN_REG(MX6Q_PAD_EIM_D21, 0x03B8, 0x00A4, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D21__WEIM_WEIM_D_21 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D21, 0x03B8, 0x00A4, 1, 0x0000, 0), /* MX6Q_PAD_EIM_D21__ECSPI4_SCLK */ + IMX_PIN_REG(MX6Q_PAD_EIM_D21, 0x03B8, 0x00A4, 2, 0x0000, 0), /* MX6Q_PAD_EIM_D21__IPU1_DI0_PIN17 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D21, 0x03B8, 0x00A4, 3, 0x08B4, 0), /* MX6Q_PAD_EIM_D21__IPU2_CSI1_D_11 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D21, 0x03B8, 0x00A4, 4, 0x0944, 0), /* MX6Q_PAD_EIM_D21__USBOH3_USBOTG_OC */ + IMX_PIN_REG(MX6Q_PAD_EIM_D21, 0x03B8, 0x00A4, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D21__GPIO_3_21 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D21, 0x03B8, 0x00A4, 6, 0x0898, 0), /* MX6Q_PAD_EIM_D21__I2C1_SCL */ + IMX_PIN_REG(MX6Q_PAD_EIM_D21, 0x03B8, 0x00A4, 7, 0x0914, 0), /* MX6Q_PAD_EIM_D21__SPDIF_IN1 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D22, 0x03BC, 0x00A8, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D22__WEIM_WEIM_D_22 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D22, 0x03BC, 0x00A8, 1, 0x0000, 0), /* MX6Q_PAD_EIM_D22__ECSPI4_MISO */ + IMX_PIN_REG(MX6Q_PAD_EIM_D22, 0x03BC, 0x00A8, 2, 0x0000, 0), /* MX6Q_PAD_EIM_D22__IPU1_DI0_PIN1 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D22, 0x03BC, 0x00A8, 3, 0x08B0, 0), /* MX6Q_PAD_EIM_D22__IPU2_CSI1_D_10 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D22, 0x03BC, 0x00A8, 4, 0x0000, 0), /* MX6Q_PAD_EIM_D22__USBOH3_USBOTG_PWR */ + IMX_PIN_REG(MX6Q_PAD_EIM_D22, 0x03BC, 0x00A8, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D22__GPIO_3_22 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D22, 0x03BC, 0x00A8, 6, 0x0000, 0), /* MX6Q_PAD_EIM_D22__SPDIF_OUT1 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D22, 0x03BC, 0x00A8, 7, 0x0000, 0), /* MX6Q_PAD_EIM_D22__PL301_PER1_HWRITE */ + IMX_PIN_REG(MX6Q_PAD_EIM_D23, 0x03C0, 0x00AC, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D23__WEIM_WEIM_D_23 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D23, 0x03C0, 0x00AC, 1, 0x0000, 0), /* MX6Q_PAD_EIM_D23__IPU1_DI0_D0_CS */ + IMX_PIN_REG(MX6Q_PAD_EIM_D23, 0x03C0, 0x00AC, 2, 0x092C, 0), /* MX6Q_PAD_EIM_D23__UART3_CTS */ + IMX_PIN_REG(MX6Q_PAD_EIM_D23, 0x03C0, 0x00AC, 3, 0x0000, 0), /* MX6Q_PAD_EIM_D23__UART1_DCD */ + IMX_PIN_REG(MX6Q_PAD_EIM_D23, 0x03C0, 0x00AC, 4, 0x08D8, 0), /* MX6Q_PAD_EIM_D23__IPU2_CSI1_DATA_EN */ + IMX_PIN_REG(MX6Q_PAD_EIM_D23, 0x03C0, 0x00AC, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D23__GPIO_3_23 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D23, 0x03C0, 0x00AC, 6, 0x0000, 0), /* MX6Q_PAD_EIM_D23__IPU1_DI1_PIN2 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D23, 0x03C0, 0x00AC, 7, 0x0000, 0), /* MX6Q_PAD_EIM_D23__IPU1_DI1_PIN14 */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB3, 0x03C4, 0x00B0, 0, 0x0000, 0), /* MX6Q_PAD_EIM_EB3__WEIM_WEIM_EB_3 */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB3, 0x03C4, 0x00B0, 1, 0x0000, 0), /* MX6Q_PAD_EIM_EB3__ECSPI4_RDY */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB3, 0x03C4, 0x00B0, 2, 0x092C, 1), /* MX6Q_PAD_EIM_EB3__UART3_RTS */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB3, 0x03C4, 0x00B0, 3, 0x0000, 0), /* MX6Q_PAD_EIM_EB3__UART1_RI */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB3, 0x03C4, 0x00B0, 4, 0x08DC, 0), /* MX6Q_PAD_EIM_EB3__IPU2_CSI1_HSYNC */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB3, 0x03C4, 0x00B0, 5, 0x0000, 0), /* MX6Q_PAD_EIM_EB3__GPIO_2_31 */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB3, 0x03C4, 0x00B0, 6, 0x0000, 0), /* MX6Q_PAD_EIM_EB3__IPU1_DI1_PIN3 */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB3, 0x03C4, 0x00B0, 7, 0x0000, 0), /* MX6Q_PAD_EIM_EB3__SRC_BT_CFG_31 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D24, 0x03C8, 0x00B4, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D24__WEIM_WEIM_D_24 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D24, 0x03C8, 0x00B4, 1, 0x0000, 0), /* MX6Q_PAD_EIM_D24__ECSPI4_SS2 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D24, 0x03C8, 0x00B4, 2, 0x0000, 0), /* MX6Q_PAD_EIM_D24__UART3_TXD */ + IMX_PIN_REG(MX6Q_PAD_EIM_D24, 0x03C8, 0x00B4, 3, 0x0808, 0), /* MX6Q_PAD_EIM_D24__ECSPI1_SS2 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D24, 0x03C8, 0x00B4, 4, 0x0000, 0), /* MX6Q_PAD_EIM_D24__ECSPI2_SS2 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D24, 0x03C8, 0x00B4, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D24__GPIO_3_24 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D24, 0x03C8, 0x00B4, 6, 0x07D8, 0), /* MX6Q_PAD_EIM_D24__AUDMUX_AUD5_RXFS */ + IMX_PIN_REG(MX6Q_PAD_EIM_D24, 0x03C8, 0x00B4, 7, 0x0000, 0), /* MX6Q_PAD_EIM_D24__UART1_DTR */ + IMX_PIN_REG(MX6Q_PAD_EIM_D25, 0x03CC, 0x00B8, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D25__WEIM_WEIM_D_25 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D25, 0x03CC, 0x00B8, 1, 0x0000, 0), /* MX6Q_PAD_EIM_D25__ECSPI4_SS3 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D25, 0x03CC, 0x00B8, 2, 0x0930, 1), /* MX6Q_PAD_EIM_D25__UART3_RXD */ + IMX_PIN_REG(MX6Q_PAD_EIM_D25, 0x03CC, 0x00B8, 3, 0x080C, 0), /* MX6Q_PAD_EIM_D25__ECSPI1_SS3 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D25, 0x03CC, 0x00B8, 4, 0x0000, 0), /* MX6Q_PAD_EIM_D25__ECSPI2_SS3 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D25, 0x03CC, 0x00B8, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D25__GPIO_3_25 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D25, 0x03CC, 0x00B8, 6, 0x07D4, 0), /* MX6Q_PAD_EIM_D25__AUDMUX_AUD5_RXC */ + IMX_PIN_REG(MX6Q_PAD_EIM_D25, 0x03CC, 0x00B8, 7, 0x0000, 0), /* MX6Q_PAD_EIM_D25__UART1_DSR */ + IMX_PIN_REG(MX6Q_PAD_EIM_D26, 0x03D0, 0x00BC, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D26__WEIM_WEIM_D_26 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D26, 0x03D0, 0x00BC, 1, 0x0000, 0), /* MX6Q_PAD_EIM_D26__IPU1_DI1_PIN11 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D26, 0x03D0, 0x00BC, 2, 0x0000, 0), /* MX6Q_PAD_EIM_D26__IPU1_CSI0_D_1 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D26, 0x03D0, 0x00BC, 3, 0x08C0, 0), /* MX6Q_PAD_EIM_D26__IPU2_CSI1_D_14 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D26, 0x03D0, 0x00BC, 4, 0x0000, 0), /* MX6Q_PAD_EIM_D26__UART2_TXD */ + IMX_PIN_REG(MX6Q_PAD_EIM_D26, 0x03D0, 0x00BC, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D26__GPIO_3_26 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D26, 0x03D0, 0x00BC, 6, 0x0000, 0), /* MX6Q_PAD_EIM_D26__IPU1_SISG_2 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D26, 0x03D0, 0x00BC, 7, 0x0000, 0), /* MX6Q_PAD_EIM_D26__IPU1_DISP1_DAT_22 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D27, 0x03D4, 0x00C0, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D27__WEIM_WEIM_D_27 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D27, 0x03D4, 0x00C0, 1, 0x0000, 0), /* MX6Q_PAD_EIM_D27__IPU1_DI1_PIN13 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D27, 0x03D4, 0x00C0, 2, 0x0000, 0), /* MX6Q_PAD_EIM_D27__IPU1_CSI0_D_0 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D27, 0x03D4, 0x00C0, 3, 0x08BC, 0), /* MX6Q_PAD_EIM_D27__IPU2_CSI1_D_13 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D27, 0x03D4, 0x00C0, 4, 0x0928, 1), /* MX6Q_PAD_EIM_D27__UART2_RXD */ + IMX_PIN_REG(MX6Q_PAD_EIM_D27, 0x03D4, 0x00C0, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D27__GPIO_3_27 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D27, 0x03D4, 0x00C0, 6, 0x0000, 0), /* MX6Q_PAD_EIM_D27__IPU1_SISG_3 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D27, 0x03D4, 0x00C0, 7, 0x0000, 0), /* MX6Q_PAD_EIM_D27__IPU1_DISP1_DAT_23 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D28, 0x03D8, 0x00C4, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D28__WEIM_WEIM_D_28 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D28, 0x03D8, 0x00C4, 1, 0x089C, 0), /* MX6Q_PAD_EIM_D28__I2C1_SDA */ + IMX_PIN_REG(MX6Q_PAD_EIM_D28, 0x03D8, 0x00C4, 2, 0x0000, 0), /* MX6Q_PAD_EIM_D28__ECSPI4_MOSI */ + IMX_PIN_REG(MX6Q_PAD_EIM_D28, 0x03D8, 0x00C4, 3, 0x08B8, 0), /* MX6Q_PAD_EIM_D28__IPU2_CSI1_D_12 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D28, 0x03D8, 0x00C4, 4, 0x0924, 0), /* MX6Q_PAD_EIM_D28__UART2_CTS */ + IMX_PIN_REG(MX6Q_PAD_EIM_D28, 0x03D8, 0x00C4, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D28__GPIO_3_28 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D28, 0x03D8, 0x00C4, 6, 0x0000, 0), /* MX6Q_PAD_EIM_D28__IPU1_EXT_TRIG */ + IMX_PIN_REG(MX6Q_PAD_EIM_D28, 0x03D8, 0x00C4, 7, 0x0000, 0), /* MX6Q_PAD_EIM_D28__IPU1_DI0_PIN13 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D29, 0x03DC, 0x00C8, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D29__WEIM_WEIM_D_29 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D29, 0x03DC, 0x00C8, 1, 0x0000, 0), /* MX6Q_PAD_EIM_D29__IPU1_DI1_PIN15 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D29, 0x03DC, 0x00C8, 2, 0x0824, 1), /* MX6Q_PAD_EIM_D29__ECSPI4_SS0 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D29, 0x03DC, 0x00C8, 4, 0x0924, 1), /* MX6Q_PAD_EIM_D29__UART2_RTS */ + IMX_PIN_REG(MX6Q_PAD_EIM_D29, 0x03DC, 0x00C8, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D29__GPIO_3_29 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D29, 0x03DC, 0x00C8, 6, 0x08E4, 0), /* MX6Q_PAD_EIM_D29__IPU2_CSI1_VSYNC */ + IMX_PIN_REG(MX6Q_PAD_EIM_D29, 0x03DC, 0x00C8, 7, 0x0000, 0), /* MX6Q_PAD_EIM_D29__IPU1_DI0_PIN14 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D30, 0x03E0, 0x00CC, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D30__WEIM_WEIM_D_30 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D30, 0x03E0, 0x00CC, 1, 0x0000, 0), /* MX6Q_PAD_EIM_D30__IPU1_DISP1_DAT_21 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D30, 0x03E0, 0x00CC, 2, 0x0000, 0), /* MX6Q_PAD_EIM_D30__IPU1_DI0_PIN11 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D30, 0x03E0, 0x00CC, 3, 0x0000, 0), /* MX6Q_PAD_EIM_D30__IPU1_CSI0_D_3 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D30, 0x03E0, 0x00CC, 4, 0x092C, 2), /* MX6Q_PAD_EIM_D30__UART3_CTS */ + IMX_PIN_REG(MX6Q_PAD_EIM_D30, 0x03E0, 0x00CC, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D30__GPIO_3_30 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D30, 0x03E0, 0x00CC, 6, 0x0948, 0), /* MX6Q_PAD_EIM_D30__USBOH3_USBH1_OC */ + IMX_PIN_REG(MX6Q_PAD_EIM_D30, 0x03E0, 0x00CC, 7, 0x0000, 0), /* MX6Q_PAD_EIM_D30__PL301_PER1_HPROT_0 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D31, 0x03E4, 0x00D0, 0, 0x0000, 0), /* MX6Q_PAD_EIM_D31__WEIM_WEIM_D_31 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D31, 0x03E4, 0x00D0, 1, 0x0000, 0), /* MX6Q_PAD_EIM_D31__IPU1_DISP1_DAT_20 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D31, 0x03E4, 0x00D0, 2, 0x0000, 0), /* MX6Q_PAD_EIM_D31__IPU1_DI0_PIN12 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D31, 0x03E4, 0x00D0, 3, 0x0000, 0), /* MX6Q_PAD_EIM_D31__IPU1_CSI0_D_2 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D31, 0x03E4, 0x00D0, 4, 0x092C, 3), /* MX6Q_PAD_EIM_D31__UART3_RTS */ + IMX_PIN_REG(MX6Q_PAD_EIM_D31, 0x03E4, 0x00D0, 5, 0x0000, 0), /* MX6Q_PAD_EIM_D31__GPIO_3_31 */ + IMX_PIN_REG(MX6Q_PAD_EIM_D31, 0x03E4, 0x00D0, 6, 0x0000, 0), /* MX6Q_PAD_EIM_D31__USBOH3_USBH1_PWR */ + IMX_PIN_REG(MX6Q_PAD_EIM_D31, 0x03E4, 0x00D0, 7, 0x0000, 0), /* MX6Q_PAD_EIM_D31__PL301_PER1_HPROT_1 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A24, 0x03E8, 0x00D4, 0, 0x0000, 0), /* MX6Q_PAD_EIM_A24__WEIM_WEIM_A_24 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A24, 0x03E8, 0x00D4, 1, 0x0000, 0), /* MX6Q_PAD_EIM_A24__IPU1_DISP1_DAT_19 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A24, 0x03E8, 0x00D4, 2, 0x08D4, 1), /* MX6Q_PAD_EIM_A24__IPU2_CSI1_D_19 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A24, 0x03E8, 0x00D4, 3, 0x0000, 0), /* MX6Q_PAD_EIM_A24__IPU2_SISG_2 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A24, 0x03E8, 0x00D4, 4, 0x0000, 0), /* MX6Q_PAD_EIM_A24__IPU1_SISG_2 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A24, 0x03E8, 0x00D4, 5, 0x0000, 0), /* MX6Q_PAD_EIM_A24__GPIO_5_4 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A24, 0x03E8, 0x00D4, 6, 0x0000, 0), /* MX6Q_PAD_EIM_A24__PL301_PER1_HPROT_2 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A24, 0x03E8, 0x00D4, 7, 0x0000, 0), /* MX6Q_PAD_EIM_A24__SRC_BT_CFG_24 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A23, 0x03EC, 0x00D8, 0, 0x0000, 0), /* MX6Q_PAD_EIM_A23__WEIM_WEIM_A_23 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A23, 0x03EC, 0x00D8, 1, 0x0000, 0), /* MX6Q_PAD_EIM_A23__IPU1_DISP1_DAT_18 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A23, 0x03EC, 0x00D8, 2, 0x08D0, 1), /* MX6Q_PAD_EIM_A23__IPU2_CSI1_D_18 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A23, 0x03EC, 0x00D8, 3, 0x0000, 0), /* MX6Q_PAD_EIM_A23__IPU2_SISG_3 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A23, 0x03EC, 0x00D8, 4, 0x0000, 0), /* MX6Q_PAD_EIM_A23__IPU1_SISG_3 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A23, 0x03EC, 0x00D8, 5, 0x0000, 0), /* MX6Q_PAD_EIM_A23__GPIO_6_6 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A23, 0x03EC, 0x00D8, 6, 0x0000, 0), /* MX6Q_PAD_EIM_A23__PL301_PER1_HPROT_3 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A23, 0x03EC, 0x00D8, 7, 0x0000, 0), /* MX6Q_PAD_EIM_A23__SRC_BT_CFG_23 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A22, 0x03F0, 0x00DC, 0, 0x0000, 0), /* MX6Q_PAD_EIM_A22__WEIM_WEIM_A_22 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A22, 0x03F0, 0x00DC, 1, 0x0000, 0), /* MX6Q_PAD_EIM_A22__IPU1_DISP1_DAT_17 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A22, 0x03F0, 0x00DC, 2, 0x08CC, 1), /* MX6Q_PAD_EIM_A22__IPU2_CSI1_D_17 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A22, 0x03F0, 0x00DC, 5, 0x0000, 0), /* MX6Q_PAD_EIM_A22__GPIO_2_16 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A22, 0x03F0, 0x00DC, 6, 0x0000, 0), /* MX6Q_PAD_EIM_A22__TPSMP_HDATA_0 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A22, 0x03F0, 0x00DC, 7, 0x0000, 0), /* MX6Q_PAD_EIM_A22__SRC_BT_CFG_22 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A21, 0x03F4, 0x00E0, 0, 0x0000, 0), /* MX6Q_PAD_EIM_A21__WEIM_WEIM_A_21 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A21, 0x03F4, 0x00E0, 1, 0x0000, 0), /* MX6Q_PAD_EIM_A21__IPU1_DISP1_DAT_16 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A21, 0x03F4, 0x00E0, 2, 0x08C8, 1), /* MX6Q_PAD_EIM_A21__IPU2_CSI1_D_16 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A21, 0x03F4, 0x00E0, 3, 0x0000, 0), /* MX6Q_PAD_EIM_A21__RESERVED_RESERVED */ + IMX_PIN_REG(MX6Q_PAD_EIM_A21, 0x03F4, 0x00E0, 4, 0x0000, 0), /* MX6Q_PAD_EIM_A21__MIPI_CORE_DPHY_OUT_18 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A21, 0x03F4, 0x00E0, 5, 0x0000, 0), /* MX6Q_PAD_EIM_A21__GPIO_2_17 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A21, 0x03F4, 0x00E0, 6, 0x0000, 0), /* MX6Q_PAD_EIM_A21__TPSMP_HDATA_1 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A21, 0x03F4, 0x00E0, 7, 0x0000, 0), /* MX6Q_PAD_EIM_A21__SRC_BT_CFG_21 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A20, 0x03F8, 0x00E4, 0, 0x0000, 0), /* MX6Q_PAD_EIM_A20__WEIM_WEIM_A_20 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A20, 0x03F8, 0x00E4, 1, 0x0000, 0), /* MX6Q_PAD_EIM_A20__IPU1_DISP1_DAT_15 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A20, 0x03F8, 0x00E4, 2, 0x08C4, 1), /* MX6Q_PAD_EIM_A20__IPU2_CSI1_D_15 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A20, 0x03F8, 0x00E4, 3, 0x0000, 0), /* MX6Q_PAD_EIM_A20__RESERVED_RESERVED */ + IMX_PIN_REG(MX6Q_PAD_EIM_A20, 0x03F8, 0x00E4, 4, 0x0000, 0), /* MX6Q_PAD_EIM_A20__MIPI_CORE_DPHY_OUT_19 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A20, 0x03F8, 0x00E4, 5, 0x0000, 0), /* MX6Q_PAD_EIM_A20__GPIO_2_18 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A20, 0x03F8, 0x00E4, 6, 0x0000, 0), /* MX6Q_PAD_EIM_A20__TPSMP_HDATA_2 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A20, 0x03F8, 0x00E4, 7, 0x0000, 0), /* MX6Q_PAD_EIM_A20__SRC_BT_CFG_20 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A19, 0x03FC, 0x00E8, 0, 0x0000, 0), /* MX6Q_PAD_EIM_A19__WEIM_WEIM_A_19 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A19, 0x03FC, 0x00E8, 1, 0x0000, 0), /* MX6Q_PAD_EIM_A19__IPU1_DISP1_DAT_14 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A19, 0x03FC, 0x00E8, 2, 0x08C0, 1), /* MX6Q_PAD_EIM_A19__IPU2_CSI1_D_14 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A19, 0x03FC, 0x00E8, 3, 0x0000, 0), /* MX6Q_PAD_EIM_A19__RESERVED_RESERVED */ + IMX_PIN_REG(MX6Q_PAD_EIM_A19, 0x03FC, 0x00E8, 4, 0x0000, 0), /* MX6Q_PAD_EIM_A19__MIPI_CORE_DPHY_OUT_20 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A19, 0x03FC, 0x00E8, 5, 0x0000, 0), /* MX6Q_PAD_EIM_A19__GPIO_2_19 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A19, 0x03FC, 0x00E8, 6, 0x0000, 0), /* MX6Q_PAD_EIM_A19__TPSMP_HDATA_3 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A19, 0x03FC, 0x00E8, 7, 0x0000, 0), /* MX6Q_PAD_EIM_A19__SRC_BT_CFG_19 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A18, 0x0400, 0x00EC, 0, 0x0000, 0), /* MX6Q_PAD_EIM_A18__WEIM_WEIM_A_18 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A18, 0x0400, 0x00EC, 1, 0x0000, 0), /* MX6Q_PAD_EIM_A18__IPU1_DISP1_DAT_13 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A18, 0x0400, 0x00EC, 2, 0x08BC, 1), /* MX6Q_PAD_EIM_A18__IPU2_CSI1_D_13 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A18, 0x0400, 0x00EC, 3, 0x0000, 0), /* MX6Q_PAD_EIM_A18__RESERVED_RESERVED */ + IMX_PIN_REG(MX6Q_PAD_EIM_A18, 0x0400, 0x00EC, 4, 0x0000, 0), /* MX6Q_PAD_EIM_A18__MIPI_CORE_DPHY_OUT_21 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A18, 0x0400, 0x00EC, 5, 0x0000, 0), /* MX6Q_PAD_EIM_A18__GPIO_2_20 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A18, 0x0400, 0x00EC, 6, 0x0000, 0), /* MX6Q_PAD_EIM_A18__TPSMP_HDATA_4 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A18, 0x0400, 0x00EC, 7, 0x0000, 0), /* MX6Q_PAD_EIM_A18__SRC_BT_CFG_18 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A17, 0x0404, 0x00F0, 0, 0x0000, 0), /* MX6Q_PAD_EIM_A17__WEIM_WEIM_A_17 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A17, 0x0404, 0x00F0, 1, 0x0000, 0), /* MX6Q_PAD_EIM_A17__IPU1_DISP1_DAT_12 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A17, 0x0404, 0x00F0, 2, 0x08B8, 1), /* MX6Q_PAD_EIM_A17__IPU2_CSI1_D_12 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A17, 0x0404, 0x00F0, 3, 0x0000, 0), /* MX6Q_PAD_EIM_A17__RESERVED_RESERVED */ + IMX_PIN_REG(MX6Q_PAD_EIM_A17, 0x0404, 0x00F0, 4, 0x0000, 0), /* MX6Q_PAD_EIM_A17__MIPI_CORE_DPHY_OUT_22 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A17, 0x0404, 0x00F0, 5, 0x0000, 0), /* MX6Q_PAD_EIM_A17__GPIO_2_21 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A17, 0x0404, 0x00F0, 6, 0x0000, 0), /* MX6Q_PAD_EIM_A17__TPSMP_HDATA_5 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A17, 0x0404, 0x00F0, 7, 0x0000, 0), /* MX6Q_PAD_EIM_A17__SRC_BT_CFG_17 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A16, 0x0408, 0x00F4, 0, 0x0000, 0), /* MX6Q_PAD_EIM_A16__WEIM_WEIM_A_16 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A16, 0x0408, 0x00F4, 1, 0x0000, 0), /* MX6Q_PAD_EIM_A16__IPU1_DI1_DISP_CLK */ + IMX_PIN_REG(MX6Q_PAD_EIM_A16, 0x0408, 0x00F4, 2, 0x08E0, 1), /* MX6Q_PAD_EIM_A16__IPU2_CSI1_PIXCLK */ + IMX_PIN_REG(MX6Q_PAD_EIM_A16, 0x0408, 0x00F4, 4, 0x0000, 0), /* MX6Q_PAD_EIM_A16__MIPI_CORE_DPHY_OUT_23 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A16, 0x0408, 0x00F4, 5, 0x0000, 0), /* MX6Q_PAD_EIM_A16__GPIO_2_22 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A16, 0x0408, 0x00F4, 6, 0x0000, 0), /* MX6Q_PAD_EIM_A16__TPSMP_HDATA_6 */ + IMX_PIN_REG(MX6Q_PAD_EIM_A16, 0x0408, 0x00F4, 7, 0x0000, 0), /* MX6Q_PAD_EIM_A16__SRC_BT_CFG_16 */ + IMX_PIN_REG(MX6Q_PAD_EIM_CS0, 0x040C, 0x00F8, 0, 0x0000, 0), /* MX6Q_PAD_EIM_CS0__WEIM_WEIM_CS_0 */ + IMX_PIN_REG(MX6Q_PAD_EIM_CS0, 0x040C, 0x00F8, 1, 0x0000, 0), /* MX6Q_PAD_EIM_CS0__IPU1_DI1_PIN5 */ + IMX_PIN_REG(MX6Q_PAD_EIM_CS0, 0x040C, 0x00F8, 2, 0x0810, 0), /* MX6Q_PAD_EIM_CS0__ECSPI2_SCLK */ + IMX_PIN_REG(MX6Q_PAD_EIM_CS0, 0x040C, 0x00F8, 4, 0x0000, 0), /* MX6Q_PAD_EIM_CS0__MIPI_CORE_DPHY_OUT_24 */ + IMX_PIN_REG(MX6Q_PAD_EIM_CS0, 0x040C, 0x00F8, 5, 0x0000, 0), /* MX6Q_PAD_EIM_CS0__GPIO_2_23 */ + IMX_PIN_REG(MX6Q_PAD_EIM_CS0, 0x040C, 0x00F8, 6, 0x0000, 0), /* MX6Q_PAD_EIM_CS0__TPSMP_HDATA_7 */ + IMX_PIN_REG(MX6Q_PAD_EIM_CS1, 0x0410, 0x00FC, 0, 0x0000, 0), /* MX6Q_PAD_EIM_CS1__WEIM_WEIM_CS_1 */ + IMX_PIN_REG(MX6Q_PAD_EIM_CS1, 0x0410, 0x00FC, 1, 0x0000, 0), /* MX6Q_PAD_EIM_CS1__IPU1_DI1_PIN6 */ + IMX_PIN_REG(MX6Q_PAD_EIM_CS1, 0x0410, 0x00FC, 2, 0x0818, 0), /* MX6Q_PAD_EIM_CS1__ECSPI2_MOSI */ + IMX_PIN_REG(MX6Q_PAD_EIM_CS1, 0x0410, 0x00FC, 4, 0x0000, 0), /* MX6Q_PAD_EIM_CS1__MIPI_CORE_DPHY_OUT_25 */ + IMX_PIN_REG(MX6Q_PAD_EIM_CS1, 0x0410, 0x00FC, 5, 0x0000, 0), /* MX6Q_PAD_EIM_CS1__GPIO_2_24 */ + IMX_PIN_REG(MX6Q_PAD_EIM_CS1, 0x0410, 0x00FC, 6, 0x0000, 0), /* MX6Q_PAD_EIM_CS1__TPSMP_HDATA_8 */ + IMX_PIN_REG(MX6Q_PAD_EIM_OE, 0x0414, 0x0100, 0, 0x0000, 0), /* MX6Q_PAD_EIM_OE__WEIM_WEIM_OE */ + IMX_PIN_REG(MX6Q_PAD_EIM_OE, 0x0414, 0x0100, 1, 0x0000, 0), /* MX6Q_PAD_EIM_OE__IPU1_DI1_PIN7 */ + IMX_PIN_REG(MX6Q_PAD_EIM_OE, 0x0414, 0x0100, 2, 0x0814, 0), /* MX6Q_PAD_EIM_OE__ECSPI2_MISO */ + IMX_PIN_REG(MX6Q_PAD_EIM_OE, 0x0414, 0x0100, 4, 0x0000, 0), /* MX6Q_PAD_EIM_OE__MIPI_CORE_DPHY_OUT_26 */ + IMX_PIN_REG(MX6Q_PAD_EIM_OE, 0x0414, 0x0100, 5, 0x0000, 0), /* MX6Q_PAD_EIM_OE__GPIO_2_25 */ + IMX_PIN_REG(MX6Q_PAD_EIM_OE, 0x0414, 0x0100, 6, 0x0000, 0), /* MX6Q_PAD_EIM_OE__TPSMP_HDATA_9 */ + IMX_PIN_REG(MX6Q_PAD_EIM_RW, 0x0418, 0x0104, 0, 0x0000, 0), /* MX6Q_PAD_EIM_RW__WEIM_WEIM_RW */ + IMX_PIN_REG(MX6Q_PAD_EIM_RW, 0x0418, 0x0104, 1, 0x0000, 0), /* MX6Q_PAD_EIM_RW__IPU1_DI1_PIN8 */ + IMX_PIN_REG(MX6Q_PAD_EIM_RW, 0x0418, 0x0104, 2, 0x081C, 0), /* MX6Q_PAD_EIM_RW__ECSPI2_SS0 */ + IMX_PIN_REG(MX6Q_PAD_EIM_RW, 0x0418, 0x0104, 4, 0x0000, 0), /* MX6Q_PAD_EIM_RW__MIPI_CORE_DPHY_OUT_27 */ + IMX_PIN_REG(MX6Q_PAD_EIM_RW, 0x0418, 0x0104, 5, 0x0000, 0), /* MX6Q_PAD_EIM_RW__GPIO_2_26 */ + IMX_PIN_REG(MX6Q_PAD_EIM_RW, 0x0418, 0x0104, 6, 0x0000, 0), /* MX6Q_PAD_EIM_RW__TPSMP_HDATA_10 */ + IMX_PIN_REG(MX6Q_PAD_EIM_RW, 0x0418, 0x0104, 7, 0x0000, 0), /* MX6Q_PAD_EIM_RW__SRC_BT_CFG_29 */ + IMX_PIN_REG(MX6Q_PAD_EIM_LBA, 0x041C, 0x0108, 0, 0x0000, 0), /* MX6Q_PAD_EIM_LBA__WEIM_WEIM_LBA */ + IMX_PIN_REG(MX6Q_PAD_EIM_LBA, 0x041C, 0x0108, 1, 0x0000, 0), /* MX6Q_PAD_EIM_LBA__IPU1_DI1_PIN17 */ + IMX_PIN_REG(MX6Q_PAD_EIM_LBA, 0x041C, 0x0108, 2, 0x0820, 0), /* MX6Q_PAD_EIM_LBA__ECSPI2_SS1 */ + IMX_PIN_REG(MX6Q_PAD_EIM_LBA, 0x041C, 0x0108, 5, 0x0000, 0), /* MX6Q_PAD_EIM_LBA__GPIO_2_27 */ + IMX_PIN_REG(MX6Q_PAD_EIM_LBA, 0x041C, 0x0108, 6, 0x0000, 0), /* MX6Q_PAD_EIM_LBA__TPSMP_HDATA_11 */ + IMX_PIN_REG(MX6Q_PAD_EIM_LBA, 0x041C, 0x0108, 7, 0x0000, 0), /* MX6Q_PAD_EIM_LBA__SRC_BT_CFG_26 */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB0, 0x0420, 0x010C, 0, 0x0000, 0), /* MX6Q_PAD_EIM_EB0__WEIM_WEIM_EB_0 */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB0, 0x0420, 0x010C, 1, 0x0000, 0), /* MX6Q_PAD_EIM_EB0__IPU1_DISP1_DAT_11 */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB0, 0x0420, 0x010C, 2, 0x08B4, 1), /* MX6Q_PAD_EIM_EB0__IPU2_CSI1_D_11 */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB0, 0x0420, 0x010C, 3, 0x0000, 0), /* MX6Q_PAD_EIM_EB0__MIPI_CORE_DPHY_OUT_0 */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB0, 0x0420, 0x010C, 4, 0x07F0, 0), /* MX6Q_PAD_EIM_EB0__CCM_PMIC_RDY */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB0, 0x0420, 0x010C, 5, 0x0000, 0), /* MX6Q_PAD_EIM_EB0__GPIO_2_28 */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB0, 0x0420, 0x010C, 6, 0x0000, 0), /* MX6Q_PAD_EIM_EB0__TPSMP_HDATA_12 */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB0, 0x0420, 0x010C, 7, 0x0000, 0), /* MX6Q_PAD_EIM_EB0__SRC_BT_CFG_27 */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB1, 0x0424, 0x0110, 0, 0x0000, 0), /* MX6Q_PAD_EIM_EB1__WEIM_WEIM_EB_1 */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB1, 0x0424, 0x0110, 1, 0x0000, 0), /* MX6Q_PAD_EIM_EB1__IPU1_DISP1_DAT_10 */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB1, 0x0424, 0x0110, 2, 0x08B0, 1), /* MX6Q_PAD_EIM_EB1__IPU2_CSI1_D_10 */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB1, 0x0424, 0x0110, 3, 0x0000, 0), /* MX6Q_PAD_EIM_EB1__MIPI_CORE_DPHY__OUT_1 */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB1, 0x0424, 0x0110, 5, 0x0000, 0), /* MX6Q_PAD_EIM_EB1__GPIO_2_29 */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB1, 0x0424, 0x0110, 6, 0x0000, 0), /* MX6Q_PAD_EIM_EB1__TPSMP_HDATA_13 */ + IMX_PIN_REG(MX6Q_PAD_EIM_EB1, 0x0424, 0x0110, 7, 0x0000, 0), /* MX6Q_PAD_EIM_EB1__SRC_BT_CFG_28 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA0, 0x0428, 0x0114, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA0__WEIM_WEIM_DA_A_0 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA0, 0x0428, 0x0114, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA0__IPU1_DISP1_DAT_9 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA0, 0x0428, 0x0114, 2, 0x0000, 0), /* MX6Q_PAD_EIM_DA0__IPU2_CSI1_D_9 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA0, 0x0428, 0x0114, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA0__MIPI_CORE_DPHY__OUT_2 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA0, 0x0428, 0x0114, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA0__GPIO_3_0 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA0, 0x0428, 0x0114, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA0__TPSMP_HDATA_14 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA0, 0x0428, 0x0114, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA0__SRC_BT_CFG_0 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA1, 0x042C, 0x0118, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA1__WEIM_WEIM_DA_A_1 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA1, 0x042C, 0x0118, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA1__IPU1_DISP1_DAT_8 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA1, 0x042C, 0x0118, 2, 0x0000, 0), /* MX6Q_PAD_EIM_DA1__IPU2_CSI1_D_8 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA1, 0x042C, 0x0118, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA1__MIPI_CORE_DPHY_OUT_3 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA1, 0x042C, 0x0118, 4, 0x0000, 0), /* MX6Q_PAD_EIM_DA1__USBPHY1_TX_LS_MODE */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA1, 0x042C, 0x0118, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA1__GPIO_3_1 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA1, 0x042C, 0x0118, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA1__TPSMP_HDATA_15 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA1, 0x042C, 0x0118, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA1__SRC_BT_CFG_1 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA2, 0x0430, 0x011C, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA2__WEIM_WEIM_DA_A_2 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA2, 0x0430, 0x011C, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA2__IPU1_DISP1_DAT_7 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA2, 0x0430, 0x011C, 2, 0x0000, 0), /* MX6Q_PAD_EIM_DA2__IPU2_CSI1_D_7 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA2, 0x0430, 0x011C, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA2__MIPI_CORE_DPHY_OUT_4 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA2, 0x0430, 0x011C, 4, 0x0000, 0), /* MX6Q_PAD_EIM_DA2__USBPHY1_TX_HS_MODE */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA2, 0x0430, 0x011C, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA2__GPIO_3_2 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA2, 0x0430, 0x011C, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA2__TPSMP_HDATA_16 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA2, 0x0430, 0x011C, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA2__SRC_BT_CFG_2 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA3, 0x0434, 0x0120, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA3__WEIM_WEIM_DA_A_3 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA3, 0x0434, 0x0120, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA3__IPU1_DISP1_DAT_6 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA3, 0x0434, 0x0120, 2, 0x0000, 0), /* MX6Q_PAD_EIM_DA3__IPU2_CSI1_D_6 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA3, 0x0434, 0x0120, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA3__MIPI_CORE_DPHY_OUT_5 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA3, 0x0434, 0x0120, 4, 0x0000, 0), /* MX6Q_PAD_EIM_DA3__USBPHY1_TX_HIZ */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA3, 0x0434, 0x0120, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA3__GPIO_3_3 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA3, 0x0434, 0x0120, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA3__TPSMP_HDATA_17 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA3, 0x0434, 0x0120, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA3__SRC_BT_CFG_3 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA4, 0x0438, 0x0124, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA4__WEIM_WEIM_DA_A_4 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA4, 0x0438, 0x0124, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA4__IPU1_DISP1_DAT_5 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA4, 0x0438, 0x0124, 2, 0x0000, 0), /* MX6Q_PAD_EIM_DA4__IPU2_CSI1_D_5 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA4, 0x0438, 0x0124, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA4__MIPI_CORE_DPHY_OUT_6 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA4, 0x0438, 0x0124, 4, 0x0000, 0), /* MX6Q_PAD_EIM_DA4__ANATOP_USBPHY1_TX_EN */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA4, 0x0438, 0x0124, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA4__GPIO_3_4 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA4, 0x0438, 0x0124, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA4__TPSMP_HDATA_18 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA4, 0x0438, 0x0124, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA4__SRC_BT_CFG_4 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA5, 0x043C, 0x0128, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA5__WEIM_WEIM_DA_A_5 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA5, 0x043C, 0x0128, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA5__IPU1_DISP1_DAT_4 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA5, 0x043C, 0x0128, 2, 0x0000, 0), /* MX6Q_PAD_EIM_DA5__IPU2_CSI1_D_4 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA5, 0x043C, 0x0128, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA5__MIPI_CORE_DPHY_OUT_7 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA5, 0x043C, 0x0128, 4, 0x0000, 0), /* MX6Q_PAD_EIM_DA5__ANATOP_USBPHY1_TX_DP */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA5, 0x043C, 0x0128, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA5__GPIO_3_5 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA5, 0x043C, 0x0128, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA5__TPSMP_HDATA_19 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA5, 0x043C, 0x0128, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA5__SRC_BT_CFG_5 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA6, 0x0440, 0x012C, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA6__WEIM_WEIM_DA_A_6 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA6, 0x0440, 0x012C, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA6__IPU1_DISP1_DAT_3 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA6, 0x0440, 0x012C, 2, 0x0000, 0), /* MX6Q_PAD_EIM_DA6__IPU2_CSI1_D_3 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA6, 0x0440, 0x012C, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA6__MIPI_CORE_DPHY_OUT_8 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA6, 0x0440, 0x012C, 4, 0x0000, 0), /* MX6Q_PAD_EIM_DA6__ANATOP_USBPHY1_TX_DN */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA6, 0x0440, 0x012C, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA6__GPIO_3_6 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA6, 0x0440, 0x012C, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA6__TPSMP_HDATA_20 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA6, 0x0440, 0x012C, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA6__SRC_BT_CFG_6 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA7, 0x0444, 0x0130, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA7__WEIM_WEIM_DA_A_7 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA7, 0x0444, 0x0130, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA7__IPU1_DISP1_DAT_2 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA7, 0x0444, 0x0130, 2, 0x0000, 0), /* MX6Q_PAD_EIM_DA7__IPU2_CSI1_D_2 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA7, 0x0444, 0x0130, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA7__MIPI_CORE_DPHY_OUT_9 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA7, 0x0444, 0x0130, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA7__GPIO_3_7 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA7, 0x0444, 0x0130, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA7__TPSMP_HDATA_21 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA7, 0x0444, 0x0130, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA7__SRC_BT_CFG_7 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA8, 0x0448, 0x0134, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA8__WEIM_WEIM_DA_A_8 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA8, 0x0448, 0x0134, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA8__IPU1_DISP1_DAT_1 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA8, 0x0448, 0x0134, 2, 0x0000, 0), /* MX6Q_PAD_EIM_DA8__IPU2_CSI1_D_1 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA8, 0x0448, 0x0134, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA8__MIPI_CORE_DPHY_OUT_10 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA8, 0x0448, 0x0134, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA8__GPIO_3_8 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA8, 0x0448, 0x0134, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA8__TPSMP_HDATA_22 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA8, 0x0448, 0x0134, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA8__SRC_BT_CFG_8 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA9, 0x044C, 0x0138, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA9__WEIM_WEIM_DA_A_9 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA9, 0x044C, 0x0138, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA9__IPU1_DISP1_DAT_0 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA9, 0x044C, 0x0138, 2, 0x0000, 0), /* MX6Q_PAD_EIM_DA9__IPU2_CSI1_D_0 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA9, 0x044C, 0x0138, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA9__MIPI_CORE_DPHY_OUT_11 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA9, 0x044C, 0x0138, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA9__GPIO_3_9 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA9, 0x044C, 0x0138, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA9__TPSMP_HDATA_23 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA9, 0x044C, 0x0138, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA9__SRC_BT_CFG_9 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA10, 0x0450, 0x013C, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA10__WEIM_WEIM_DA_A_10 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA10, 0x0450, 0x013C, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA10__IPU1_DI1_PIN15 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA10, 0x0450, 0x013C, 2, 0x08D8, 1), /* MX6Q_PAD_EIM_DA10__IPU2_CSI1_DATA_EN */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA10, 0x0450, 0x013C, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA10__MIPI_CORE_DPHY_OUT12 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA10, 0x0450, 0x013C, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA10__GPIO_3_10 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA10, 0x0450, 0x013C, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA10__TPSMP_HDATA_24 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA10, 0x0450, 0x013C, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA10__SRC_BT_CFG_10 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA11, 0x0454, 0x0140, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA11__WEIM_WEIM_DA_A_11 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA11, 0x0454, 0x0140, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA11__IPU1_DI1_PIN2 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA11, 0x0454, 0x0140, 2, 0x08DC, 1), /* MX6Q_PAD_EIM_DA11__IPU2_CSI1_HSYNC */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA11, 0x0454, 0x0140, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA11__MIPI_CORE_DPHY_OUT13 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA11, 0x0454, 0x0140, 4, 0x0000, 0), /* MX6Q_PAD_EIM_DA11__SDMA_DBG_EVT_CHN_6 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA11, 0x0454, 0x0140, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA11__GPIO_3_11 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA11, 0x0454, 0x0140, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA11__TPSMP_HDATA_25 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA11, 0x0454, 0x0140, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA11__SRC_BT_CFG_11 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA12, 0x0458, 0x0144, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA12__WEIM_WEIM_DA_A_12 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA12, 0x0458, 0x0144, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA12__IPU1_DI1_PIN3 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA12, 0x0458, 0x0144, 2, 0x08E4, 1), /* MX6Q_PAD_EIM_DA12__IPU2_CSI1_VSYNC */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA12, 0x0458, 0x0144, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA12__MIPI_CORE_DPHY_OUT14 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA12, 0x0458, 0x0144, 4, 0x0000, 0), /* MX6Q_PAD_EIM_DA12__SDMA_DEBUG_EVT_CHN_3 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA12, 0x0458, 0x0144, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA12__GPIO_3_12 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA12, 0x0458, 0x0144, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA12__TPSMP_HDATA_26 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA12, 0x0458, 0x0144, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA12__SRC_BT_CFG_12 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA13, 0x045C, 0x0148, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA13__WEIM_WEIM_DA_A_13 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA13, 0x045C, 0x0148, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA13__IPU1_DI1_D0_CS */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA13, 0x045C, 0x0148, 2, 0x07EC, 1), /* MX6Q_PAD_EIM_DA13__CCM_DI1_EXT_CLK */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA13, 0x045C, 0x0148, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA13__MIPI_CORE_DPHY_OUT15 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA13, 0x045C, 0x0148, 4, 0x0000, 0), /* MX6Q_PAD_EIM_DA13__SDMA_DEBUG_EVT_CHN_4 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA13, 0x045C, 0x0148, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA13__GPIO_3_13 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA13, 0x045C, 0x0148, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA13__TPSMP_HDATA_27 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA13, 0x045C, 0x0148, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA13__SRC_BT_CFG_13 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA14, 0x0460, 0x014C, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA14__WEIM_WEIM_DA_A_14 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA14, 0x0460, 0x014C, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA14__IPU1_DI1_D1_CS */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA14, 0x0460, 0x014C, 2, 0x0000, 0), /* MX6Q_PAD_EIM_DA14__CCM_DI0_EXT_CLK */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA14, 0x0460, 0x014C, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA14__MIPI_CORE_DPHY_OUT16 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA14, 0x0460, 0x014C, 4, 0x0000, 0), /* MX6Q_PAD_EIM_DA14__SDMA_DEBUG_EVT_CHN_5 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA14, 0x0460, 0x014C, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA14__GPIO_3_14 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA14, 0x0460, 0x014C, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA14__TPSMP_HDATA_28 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA14, 0x0460, 0x014C, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA14__SRC_BT_CFG_14 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA15, 0x0464, 0x0150, 0, 0x0000, 0), /* MX6Q_PAD_EIM_DA15__WEIM_WEIM_DA_A_15 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA15, 0x0464, 0x0150, 1, 0x0000, 0), /* MX6Q_PAD_EIM_DA15__IPU1_DI1_PIN1 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA15, 0x0464, 0x0150, 2, 0x0000, 0), /* MX6Q_PAD_EIM_DA15__IPU1_DI1_PIN4 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA15, 0x0464, 0x0150, 3, 0x0000, 0), /* MX6Q_PAD_EIM_DA15__MIPI_CORE_DPHY_OUT17 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA15, 0x0464, 0x0150, 5, 0x0000, 0), /* MX6Q_PAD_EIM_DA15__GPIO_3_15 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA15, 0x0464, 0x0150, 6, 0x0000, 0), /* MX6Q_PAD_EIM_DA15__TPSMP_HDATA_29 */ + IMX_PIN_REG(MX6Q_PAD_EIM_DA15, 0x0464, 0x0150, 7, 0x0000, 0), /* MX6Q_PAD_EIM_DA15__SRC_BT_CFG_15 */ + IMX_PIN_REG(MX6Q_PAD_EIM_WAIT, 0x0468, 0x0154, 0, 0x0000, 0), /* MX6Q_PAD_EIM_WAIT__WEIM_WEIM_WAIT */ + IMX_PIN_REG(MX6Q_PAD_EIM_WAIT, 0x0468, 0x0154, 1, 0x0000, 0), /* MX6Q_PAD_EIM_WAIT__WEIM_WEIM_DTACK_B */ + IMX_PIN_REG(MX6Q_PAD_EIM_WAIT, 0x0468, 0x0154, 5, 0x0000, 0), /* MX6Q_PAD_EIM_WAIT__GPIO_5_0 */ + IMX_PIN_REG(MX6Q_PAD_EIM_WAIT, 0x0468, 0x0154, 6, 0x0000, 0), /* MX6Q_PAD_EIM_WAIT__TPSMP_HDATA_30 */ + IMX_PIN_REG(MX6Q_PAD_EIM_WAIT, 0x0468, 0x0154, 7, 0x0000, 0), /* MX6Q_PAD_EIM_WAIT__SRC_BT_CFG_25 */ + IMX_PIN_REG(MX6Q_PAD_EIM_BCLK, 0x046C, 0x0158, 0, 0x0000, 0), /* MX6Q_PAD_EIM_BCLK__WEIM_WEIM_BCLK */ + IMX_PIN_REG(MX6Q_PAD_EIM_BCLK, 0x046C, 0x0158, 1, 0x0000, 0), /* MX6Q_PAD_EIM_BCLK__IPU1_DI1_PIN16 */ + IMX_PIN_REG(MX6Q_PAD_EIM_BCLK, 0x046C, 0x0158, 5, 0x0000, 0), /* MX6Q_PAD_EIM_BCLK__GPIO_6_31 */ + IMX_PIN_REG(MX6Q_PAD_EIM_BCLK, 0x046C, 0x0158, 6, 0x0000, 0), /* MX6Q_PAD_EIM_BCLK__TPSMP_HDATA_31 */ + IMX_PIN_REG(MX6Q_PAD_DI0_DISP_CLK, 0x0470, 0x015C, 0, 0x0000, 0), /* MX6Q_PAD_DI0_DISP_CLK__IPU1_DI0_DSP_CLK */ + IMX_PIN_REG(MX6Q_PAD_DI0_DISP_CLK, 0x0470, 0x015C, 1, 0x0000, 0), /* MX6Q_PAD_DI0_DISP_CLK__IPU2_DI0_DSP_CLK */ + IMX_PIN_REG(MX6Q_PAD_DI0_DISP_CLK, 0x0470, 0x015C, 3, 0x0000, 0), /* MX6Q_PAD_DI0_DISP_CLK__MIPI_CR_DPY_OT28 */ + IMX_PIN_REG(MX6Q_PAD_DI0_DISP_CLK, 0x0470, 0x015C, 4, 0x0000, 0), /* MX6Q_PAD_DI0_DISP_CLK__SDMA_DBG_CR_STA0 */ + IMX_PIN_REG(MX6Q_PAD_DI0_DISP_CLK, 0x0470, 0x015C, 5, 0x0000, 0), /* MX6Q_PAD_DI0_DISP_CLK__GPIO_4_16 */ + IMX_PIN_REG(MX6Q_PAD_DI0_DISP_CLK, 0x0470, 0x015C, 6, 0x0000, 0), /* MX6Q_PAD_DI0_DISP_CLK__MMDC_DEBUG_0 */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN15, 0x0474, 0x0160, 0, 0x0000, 0), /* MX6Q_PAD_DI0_PIN15__IPU1_DI0_PIN15 */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN15, 0x0474, 0x0160, 1, 0x0000, 0), /* MX6Q_PAD_DI0_PIN15__IPU2_DI0_PIN15 */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN15, 0x0474, 0x0160, 2, 0x0000, 0), /* MX6Q_PAD_DI0_PIN15__AUDMUX_AUD6_TXC */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN15, 0x0474, 0x0160, 3, 0x0000, 0), /* MX6Q_PAD_DI0_PIN15__MIPI_CR_DPHY_OUT_29 */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN15, 0x0474, 0x0160, 4, 0x0000, 0), /* MX6Q_PAD_DI0_PIN15__SDMA_DBG_CORE_STA_1 */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN15, 0x0474, 0x0160, 5, 0x0000, 0), /* MX6Q_PAD_DI0_PIN15__GPIO_4_17 */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN15, 0x0474, 0x0160, 6, 0x0000, 0), /* MX6Q_PAD_DI0_PIN15__MMDC_MMDC_DEBUG_1 */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN2, 0x0478, 0x0164, 0, 0x0000, 0), /* MX6Q_PAD_DI0_PIN2__IPU1_DI0_PIN2 */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN2, 0x0478, 0x0164, 1, 0x0000, 0), /* MX6Q_PAD_DI0_PIN2__IPU2_DI0_PIN2 */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN2, 0x0478, 0x0164, 2, 0x0000, 0), /* MX6Q_PAD_DI0_PIN2__AUDMUX_AUD6_TXD */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN2, 0x0478, 0x0164, 3, 0x0000, 0), /* MX6Q_PAD_DI0_PIN2__MIPI_CR_DPHY_OUT_30 */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN2, 0x0478, 0x0164, 4, 0x0000, 0), /* MX6Q_PAD_DI0_PIN2__SDMA_DBG_CORE_STA_2 */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN2, 0x0478, 0x0164, 5, 0x0000, 0), /* MX6Q_PAD_DI0_PIN2__GPIO_4_18 */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN2, 0x0478, 0x0164, 6, 0x0000, 0), /* MX6Q_PAD_DI0_PIN2__MMDC_DEBUG_2 */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN2, 0x0478, 0x0164, 7, 0x0000, 0), /* MX6Q_PAD_DI0_PIN2__PL301_PER1_HADDR_9 */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN3, 0x047C, 0x0168, 0, 0x0000, 0), /* MX6Q_PAD_DI0_PIN3__IPU1_DI0_PIN3 */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN3, 0x047C, 0x0168, 1, 0x0000, 0), /* MX6Q_PAD_DI0_PIN3__IPU2_DI0_PIN3 */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN3, 0x047C, 0x0168, 2, 0x0000, 0), /* MX6Q_PAD_DI0_PIN3__AUDMUX_AUD6_TXFS */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN3, 0x047C, 0x0168, 3, 0x0000, 0), /* MX6Q_PAD_DI0_PIN3__MIPI_CORE_DPHY_OUT31 */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN3, 0x047C, 0x0168, 4, 0x0000, 0), /* MX6Q_PAD_DI0_PIN3__SDMA_DBG_CORE_STA_3 */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN3, 0x047C, 0x0168, 5, 0x0000, 0), /* MX6Q_PAD_DI0_PIN3__GPIO_4_19 */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN3, 0x047C, 0x0168, 6, 0x0000, 0), /* MX6Q_PAD_DI0_PIN3__MMDC_MMDC_DEBUG_3 */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN3, 0x047C, 0x0168, 7, 0x0000, 0), /* MX6Q_PAD_DI0_PIN3__PL301_PER1_HADDR_10 */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN4, 0x0480, 0x016C, 0, 0x0000, 0), /* MX6Q_PAD_DI0_PIN4__IPU1_DI0_PIN4 */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN4, 0x0480, 0x016C, 1, 0x0000, 0), /* MX6Q_PAD_DI0_PIN4__IPU2_DI0_PIN4 */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN4, 0x0480, 0x016C, 2, 0x0000, 0), /* MX6Q_PAD_DI0_PIN4__AUDMUX_AUD6_RXD */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN4, 0x0480, 0x016C, 3, 0x094C, 0), /* MX6Q_PAD_DI0_PIN4__USDHC1_WP */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN4, 0x0480, 0x016C, 4, 0x0000, 0), /* MX6Q_PAD_DI0_PIN4__SDMA_DEBUG_YIELD */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN4, 0x0480, 0x016C, 5, 0x0000, 0), /* MX6Q_PAD_DI0_PIN4__GPIO_4_20 */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN4, 0x0480, 0x016C, 6, 0x0000, 0), /* MX6Q_PAD_DI0_PIN4__MMDC_MMDC_DEBUG_4 */ + IMX_PIN_REG(MX6Q_PAD_DI0_PIN4, 0x0480, 0x016C, 7, 0x0000, 0), /* MX6Q_PAD_DI0_PIN4__PL301_PER1_HADDR_11 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT0, 0x0484, 0x0170, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT0__IPU1_DISP0_DAT_0 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT0, 0x0484, 0x0170, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT0__IPU2_DISP0_DAT_0 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT0, 0x0484, 0x0170, 2, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT0__ECSPI3_SCLK */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT0, 0x0484, 0x0170, 3, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT0__USDHC1_USDHC_DBG_0 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT0, 0x0484, 0x0170, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT0__SDMA_DBG_CORE_RUN */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT0, 0x0484, 0x0170, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT0__GPIO_4_21 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT0, 0x0484, 0x0170, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT0__MMDC_MMDC_DEBUG_5 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT1, 0x0488, 0x0174, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT1__IPU1_DISP0_DAT_1 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT1, 0x0488, 0x0174, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT1__IPU2_DISP0_DAT_1 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT1, 0x0488, 0x0174, 2, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT1__ECSPI3_MOSI */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT1, 0x0488, 0x0174, 3, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT1__USDHC1_USDHC_DBG_1 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT1, 0x0488, 0x0174, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT1__SDMA_DBG_EVT_CHNSL */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT1, 0x0488, 0x0174, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT1__GPIO_4_22 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT1, 0x0488, 0x0174, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT1__MMDC_DEBUG_6 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT1, 0x0488, 0x0174, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT1__PL301_PER1_HADR_12 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT2, 0x048C, 0x0178, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT2__IPU1_DISP0_DAT_2 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT2, 0x048C, 0x0178, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT2__IPU2_DISP0_DAT_2 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT2, 0x048C, 0x0178, 2, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT2__ECSPI3_MISO */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT2, 0x048C, 0x0178, 3, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT2__USDHC1_USDHC_DBG_2 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT2, 0x048C, 0x0178, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT2__SDMA_DEBUG_MODE */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT2, 0x048C, 0x0178, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT2__GPIO_4_23 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT2, 0x048C, 0x0178, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT2__MMDC_DEBUG_7 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT2, 0x048C, 0x0178, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT2__PL301_PER1_HADR_13 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT3, 0x0490, 0x017C, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT3__IPU1_DISP0_DAT_3 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT3, 0x0490, 0x017C, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT3__IPU2_DISP0_DAT_3 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT3, 0x0490, 0x017C, 2, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT3__ECSPI3_SS0 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT3, 0x0490, 0x017C, 3, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT3__USDHC1_USDHC_DBG_3 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT3, 0x0490, 0x017C, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT3__SDMA_DBG_BUS_ERROR */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT3, 0x0490, 0x017C, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT3__GPIO_4_24 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT3, 0x0490, 0x017C, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT3__MMDC_MMDC_DBG_8 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT3, 0x0490, 0x017C, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT3__PL301_PER1_HADR_14 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT4, 0x0494, 0x0180, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT4__IPU1_DISP0_DAT_4 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT4, 0x0494, 0x0180, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT4__IPU2_DISP0_DAT_4 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT4, 0x0494, 0x0180, 2, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT4__ECSPI3_SS1 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT4, 0x0494, 0x0180, 3, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT4__USDHC1_USDHC_DBG_4 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT4, 0x0494, 0x0180, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT4__SDMA_DEBUG_BUS_RWB */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT4, 0x0494, 0x0180, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT4__GPIO_4_25 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT4, 0x0494, 0x0180, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT4__MMDC_MMDC_DEBUG_9 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT4, 0x0494, 0x0180, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT4__PL301_PER1_HADR_15 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT5, 0x0498, 0x0184, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT5__IPU1_DISP0_DAT_5 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT5, 0x0498, 0x0184, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT5__IPU2_DISP0_DAT_5 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT5, 0x0498, 0x0184, 2, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT5__ECSPI3_SS2 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT5, 0x0498, 0x0184, 3, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT5__AUDMUX_AUD6_RXFS */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT5, 0x0498, 0x0184, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT5__SDMA_DBG_MCH_DMBUS */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT5, 0x0498, 0x0184, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT5__GPIO_4_26 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT5, 0x0498, 0x0184, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT5__MMDC_DEBUG_10 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT5, 0x0498, 0x0184, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT5__PL301_PER1_HADR_16 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT6, 0x049C, 0x0188, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT6__IPU1_DISP0_DAT_6 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT6, 0x049C, 0x0188, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT6__IPU2_DISP0_DAT_6 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT6, 0x049C, 0x0188, 2, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT6__ECSPI3_SS3 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT6, 0x049C, 0x0188, 3, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT6__AUDMUX_AUD6_RXC */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT6, 0x049C, 0x0188, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT6__SDMA_DBG_RTBUF_WRT */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT6, 0x049C, 0x0188, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT6__GPIO_4_27 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT6, 0x049C, 0x0188, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT6__MMDC_DEBUG_11 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT6, 0x049C, 0x0188, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT6__PL301_PER1_HADR_17 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT7, 0x04A0, 0x018C, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT7__IPU1_DISP0_DAT_7 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT7, 0x04A0, 0x018C, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT7__IPU2_DISP0_DAT_7 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT7, 0x04A0, 0x018C, 2, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT7__ECSPI3_RDY */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT7, 0x04A0, 0x018C, 3, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT7__USDHC1_USDHC_DBG_5 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT7, 0x04A0, 0x018C, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT7__SDMA_DBG_EVT_CHN_0 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT7, 0x04A0, 0x018C, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT7__GPIO_4_28 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT7, 0x04A0, 0x018C, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT7__MMDC_DEBUG_12 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT7, 0x04A0, 0x018C, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT7__PL301_PER1_HADR_18 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT8, 0x04A4, 0x0190, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT8__IPU1_DISP0_DAT_8 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT8, 0x04A4, 0x0190, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT8__IPU2_DISP0_DAT_8 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT8, 0x04A4, 0x0190, 2, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT8__PWM1_PWMO */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT8, 0x04A4, 0x0190, 3, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT8__WDOG1_WDOG_B */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT8, 0x04A4, 0x0190, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT8__SDMA_DBG_EVT_CHN_1 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT8, 0x04A4, 0x0190, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT8__GPIO_4_29 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT8, 0x04A4, 0x0190, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT8__MMDC_DEBUG_13 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT8, 0x04A4, 0x0190, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT8__PL301_PER1_HADR_19 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT9, 0x04A8, 0x0194, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT9__IPU1_DISP0_DAT_9 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT9, 0x04A8, 0x0194, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT9__IPU2_DISP0_DAT_9 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT9, 0x04A8, 0x0194, 2, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT9__PWM2_PWMO */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT9, 0x04A8, 0x0194, 3, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT9__WDOG2_WDOG_B */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT9, 0x04A8, 0x0194, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT9__SDMA_DBG_EVT_CHN_2 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT9, 0x04A8, 0x0194, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT9__GPIO_4_30 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT9, 0x04A8, 0x0194, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT9__MMDC_DEBUG_14 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT9, 0x04A8, 0x0194, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT9__PL301_PER1_HADR_20 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT10, 0x04AC, 0x0198, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT10__IPU1_DISP0_DAT_10 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT10, 0x04AC, 0x0198, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT10__IPU2_DISP0_DAT_10 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT10, 0x04AC, 0x0198, 3, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT10__USDHC1_DBG_6 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT10, 0x04AC, 0x0198, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT10__SDMA_DBG_EVT_CHN3 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT10, 0x04AC, 0x0198, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT10__GPIO_4_31 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT10, 0x04AC, 0x0198, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT10__MMDC_DEBUG_15 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT10, 0x04AC, 0x0198, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT10__PL301_PER1_HADR21 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT11, 0x04B0, 0x019C, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT11__IPU1_DISP0_DAT_11 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT11, 0x04B0, 0x019C, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT11__IPU2_DISP0_DAT_11 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT11, 0x04B0, 0x019C, 3, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT11__USDHC1_USDHC_DBG7 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT11, 0x04B0, 0x019C, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT11__SDMA_DBG_EVT_CHN4 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT11, 0x04B0, 0x019C, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT11__GPIO_5_5 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT11, 0x04B0, 0x019C, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT11__MMDC_DEBUG_16 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT11, 0x04B0, 0x019C, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT11__PL301_PER1_HADR22 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT12, 0x04B4, 0x01A0, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT12__IPU1_DISP0_DAT_12 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT12, 0x04B4, 0x01A0, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT12__IPU2_DISP0_DAT_12 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT12, 0x04B4, 0x01A0, 3, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT12__RESERVED_RESERVED */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT12, 0x04B4, 0x01A0, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT12__SDMA_DBG_EVT_CHN5 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT12, 0x04B4, 0x01A0, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT12__GPIO_5_6 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT12, 0x04B4, 0x01A0, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT12__MMDC_DEBUG_17 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT12, 0x04B4, 0x01A0, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT12__PL301_PER1_HADR23 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT13, 0x04B8, 0x01A4, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT13__IPU1_DISP0_DAT_13 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT13, 0x04B8, 0x01A4, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT13__IPU2_DISP0_DAT_13 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT13, 0x04B8, 0x01A4, 3, 0x07D8, 1), /* MX6Q_PAD_DISP0_DAT13__AUDMUX_AUD5_RXFS */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT13, 0x04B8, 0x01A4, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT13__SDMA_DBG_EVT_CHN0 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT13, 0x04B8, 0x01A4, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT13__GPIO_5_7 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT13, 0x04B8, 0x01A4, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT13__MMDC_DEBUG_18 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT13, 0x04B8, 0x01A4, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT13__PL301_PER1_HADR24 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT14, 0x04BC, 0x01A8, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT14__IPU1_DISP0_DAT_14 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT14, 0x04BC, 0x01A8, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT14__IPU2_DISP0_DAT_14 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT14, 0x04BC, 0x01A8, 3, 0x07D4, 1), /* MX6Q_PAD_DISP0_DAT14__AUDMUX_AUD5_RXC */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT14, 0x04BC, 0x01A8, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT14__SDMA_DBG_EVT_CHN1 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT14, 0x04BC, 0x01A8, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT14__GPIO_5_8 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT14, 0x04BC, 0x01A8, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT14__MMDC_DEBUG_19 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT15, 0x04C0, 0x01AC, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT15__IPU1_DISP0_DAT_15 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT15, 0x04C0, 0x01AC, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT15__IPU2_DISP0_DAT_15 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT15, 0x04C0, 0x01AC, 2, 0x0804, 1), /* MX6Q_PAD_DISP0_DAT15__ECSPI1_SS1 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT15, 0x04C0, 0x01AC, 3, 0x0820, 1), /* MX6Q_PAD_DISP0_DAT15__ECSPI2_SS1 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT15, 0x04C0, 0x01AC, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT15__SDMA_DBG_EVT_CHN2 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT15, 0x04C0, 0x01AC, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT15__GPIO_5_9 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT15, 0x04C0, 0x01AC, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT15__MMDC_DEBUG_20 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT15, 0x04C0, 0x01AC, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT15__PL301_PER1_HADR25 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT16, 0x04C4, 0x01B0, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT16__IPU1_DISP0_DAT_16 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT16, 0x04C4, 0x01B0, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT16__IPU2_DISP0_DAT_16 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT16, 0x04C4, 0x01B0, 2, 0x0818, 1), /* MX6Q_PAD_DISP0_DAT16__ECSPI2_MOSI */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT16, 0x04C4, 0x01B0, 3, 0x07DC, 0), /* MX6Q_PAD_DISP0_DAT16__AUDMUX_AUD5_TXC */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT16, 0x04C4, 0x01B0, 4, 0x090C, 0), /* MX6Q_PAD_DISP0_DAT16__SDMA_EXT_EVENT_0 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT16, 0x04C4, 0x01B0, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT16__GPIO_5_10 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT16, 0x04C4, 0x01B0, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT16__MMDC_DEBUG_21 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT16, 0x04C4, 0x01B0, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT16__PL301_PER1_HADR26 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT17, 0x04C8, 0x01B4, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT17__IPU1_DISP0_DAT_17 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT17, 0x04C8, 0x01B4, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT17__IPU2_DISP0_DAT_17 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT17, 0x04C8, 0x01B4, 2, 0x0814, 1), /* MX6Q_PAD_DISP0_DAT17__ECSPI2_MISO */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT17, 0x04C8, 0x01B4, 3, 0x07D0, 0), /* MX6Q_PAD_DISP0_DAT17__AUDMUX_AUD5_TXD */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT17, 0x04C8, 0x01B4, 4, 0x0910, 0), /* MX6Q_PAD_DISP0_DAT17__SDMA_EXT_EVENT_1 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT17, 0x04C8, 0x01B4, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT17__GPIO_5_11 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT17, 0x04C8, 0x01B4, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT17__MMDC_DEBUG_22 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT17, 0x04C8, 0x01B4, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT17__PL301_PER1_HADR27 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT18, 0x04CC, 0x01B8, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT18__IPU1_DISP0_DAT_18 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT18, 0x04CC, 0x01B8, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT18__IPU2_DISP0_DAT_18 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT18, 0x04CC, 0x01B8, 2, 0x081C, 1), /* MX6Q_PAD_DISP0_DAT18__ECSPI2_SS0 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT18, 0x04CC, 0x01B8, 3, 0x07E0, 0), /* MX6Q_PAD_DISP0_DAT18__AUDMUX_AUD5_TXFS */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT18, 0x04CC, 0x01B8, 4, 0x07C0, 0), /* MX6Q_PAD_DISP0_DAT18__AUDMUX_AUD4_RXFS */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT18, 0x04CC, 0x01B8, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT18__GPIO_5_12 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT18, 0x04CC, 0x01B8, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT18__MMDC_DEBUG_23 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT18, 0x04CC, 0x01B8, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT18__WEIM_WEIM_CS_2 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT19, 0x04D0, 0x01BC, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT19__IPU1_DISP0_DAT_19 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT19, 0x04D0, 0x01BC, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT19__IPU2_DISP0_DAT_19 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT19, 0x04D0, 0x01BC, 2, 0x0810, 1), /* MX6Q_PAD_DISP0_DAT19__ECSPI2_SCLK */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT19, 0x04D0, 0x01BC, 3, 0x07CC, 0), /* MX6Q_PAD_DISP0_DAT19__AUDMUX_AUD5_RXD */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT19, 0x04D0, 0x01BC, 4, 0x07BC, 0), /* MX6Q_PAD_DISP0_DAT19__AUDMUX_AUD4_RXC */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT19, 0x04D0, 0x01BC, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT19__GPIO_5_13 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT19, 0x04D0, 0x01BC, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT19__MMDC_DEBUG_24 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT19, 0x04D0, 0x01BC, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT19__WEIM_WEIM_CS_3 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT20, 0x04D4, 0x01C0, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT20__IPU1_DISP0_DAT_20 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT20, 0x04D4, 0x01C0, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT20__IPU2_DISP0_DAT_20 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT20, 0x04D4, 0x01C0, 2, 0x07F4, 1), /* MX6Q_PAD_DISP0_DAT20__ECSPI1_SCLK */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT20, 0x04D4, 0x01C0, 3, 0x07C4, 0), /* MX6Q_PAD_DISP0_DAT20__AUDMUX_AUD4_TXC */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT20, 0x04D4, 0x01C0, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT20__SDMA_DBG_EVT_CHN7 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT20, 0x04D4, 0x01C0, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT20__GPIO_5_14 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT20, 0x04D4, 0x01C0, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT20__MMDC_DEBUG_25 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT20, 0x04D4, 0x01C0, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT20__PL301_PER1_HADR28 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT21, 0x04D8, 0x01C4, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT21__IPU1_DISP0_DAT_21 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT21, 0x04D8, 0x01C4, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT21__IPU2_DISP0_DAT_21 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT21, 0x04D8, 0x01C4, 2, 0x07FC, 1), /* MX6Q_PAD_DISP0_DAT21__ECSPI1_MOSI */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT21, 0x04D8, 0x01C4, 3, 0x07B8, 1), /* MX6Q_PAD_DISP0_DAT21__AUDMUX_AUD4_TXD */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT21, 0x04D8, 0x01C4, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT21__SDMA_DBG_BUS_DEV0 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT21, 0x04D8, 0x01C4, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT21__GPIO_5_15 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT21, 0x04D8, 0x01C4, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT21__MMDC_DEBUG_26 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT21, 0x04D8, 0x01C4, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT21__PL301_PER1_HADR29 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT22, 0x04DC, 0x01C8, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT22__IPU1_DISP0_DAT_22 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT22, 0x04DC, 0x01C8, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT22__IPU2_DISP0_DAT_22 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT22, 0x04DC, 0x01C8, 2, 0x07F8, 1), /* MX6Q_PAD_DISP0_DAT22__ECSPI1_MISO */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT22, 0x04DC, 0x01C8, 3, 0x07C8, 1), /* MX6Q_PAD_DISP0_DAT22__AUDMUX_AUD4_TXFS */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT22, 0x04DC, 0x01C8, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT22__SDMA_DBG_BUS_DEV1 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT22, 0x04DC, 0x01C8, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT22__GPIO_5_16 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT22, 0x04DC, 0x01C8, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT22__MMDC_DEBUG_27 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT22, 0x04DC, 0x01C8, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT22__PL301_PER1_HADR30 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT23, 0x04E0, 0x01CC, 0, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT23__IPU1_DISP0_DAT_23 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT23, 0x04E0, 0x01CC, 1, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT23__IPU2_DISP0_DAT_23 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT23, 0x04E0, 0x01CC, 2, 0x0800, 1), /* MX6Q_PAD_DISP0_DAT23__ECSPI1_SS0 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT23, 0x04E0, 0x01CC, 3, 0x07B4, 1), /* MX6Q_PAD_DISP0_DAT23__AUDMUX_AUD4_RXD */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT23, 0x04E0, 0x01CC, 4, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT23__SDMA_DBG_BUS_DEV2 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT23, 0x04E0, 0x01CC, 5, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT23__GPIO_5_17 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT23, 0x04E0, 0x01CC, 6, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT23__MMDC_DEBUG_28 */ + IMX_PIN_REG(MX6Q_PAD_DISP0_DAT23, 0x04E0, 0x01CC, 7, 0x0000, 0), /* MX6Q_PAD_DISP0_DAT23__PL301_PER1_HADR31 */ + IMX_PIN_REG(MX6Q_PAD_ENET_MDIO, 0x04E4, 0x01D0, 0, 0x0000, 0), /* MX6Q_PAD_ENET_MDIO__RESERVED_RESERVED */ + IMX_PIN_REG(MX6Q_PAD_ENET_MDIO, 0x04E4, 0x01D0, 1, 0x0840, 0), /* MX6Q_PAD_ENET_MDIO__ENET_MDIO */ + IMX_PIN_REG(MX6Q_PAD_ENET_MDIO, 0x04E4, 0x01D0, 2, 0x086C, 0), /* MX6Q_PAD_ENET_MDIO__ESAI1_SCKR */ + IMX_PIN_REG(MX6Q_PAD_ENET_MDIO, 0x04E4, 0x01D0, 3, 0x0000, 0), /* MX6Q_PAD_ENET_MDIO__SDMA_DEBUG_BUS_DEV3 */ + IMX_PIN_REG(MX6Q_PAD_ENET_MDIO, 0x04E4, 0x01D0, 4, 0x0000, 0), /* MX6Q_PAD_ENET_MDIO__ENET_1588_EVT1_OUT */ + IMX_PIN_REG(MX6Q_PAD_ENET_MDIO, 0x04E4, 0x01D0, 5, 0x0000, 0), /* MX6Q_PAD_ENET_MDIO__GPIO_1_22 */ + IMX_PIN_REG(MX6Q_PAD_ENET_MDIO, 0x04E4, 0x01D0, 6, 0x0000, 0), /* MX6Q_PAD_ENET_MDIO__SPDIF_PLOCK */ + IMX_PIN_REG(MX6Q_PAD_ENET_REF_CLK, 0x04E8, 0x01D4, 0, 0x0000, 0), /* MX6Q_PAD_ENET_REF_CLK__RESERVED_RSRVED */ + IMX_PIN_REG(MX6Q_PAD_ENET_REF_CLK, 0x04E8, 0x01D4, 1, 0x0000, 0), /* MX6Q_PAD_ENET_REF_CLK__ENET_TX_CLK */ + IMX_PIN_REG(MX6Q_PAD_ENET_REF_CLK, 0x04E8, 0x01D4, 2, 0x085C, 0), /* MX6Q_PAD_ENET_REF_CLK__ESAI1_FSR */ + IMX_PIN_REG(MX6Q_PAD_ENET_REF_CLK, 0x04E8, 0x01D4, 3, 0x0000, 0), /* MX6Q_PAD_ENET_REF_CLK__SDMA_DBGBUS_DEV4 */ + IMX_PIN_REG(MX6Q_PAD_ENET_REF_CLK, 0x04E8, 0x01D4, 5, 0x0000, 0), /* MX6Q_PAD_ENET_REF_CLK__GPIO_1_23 */ + IMX_PIN_REG(MX6Q_PAD_ENET_REF_CLK, 0x04E8, 0x01D4, 6, 0x0000, 0), /* MX6Q_PAD_ENET_REF_CLK__SPDIF_SRCLK */ + IMX_PIN_REG(MX6Q_PAD_ENET_REF_CLK, 0x04E8, 0x01D4, 7, 0x0000, 0), /* MX6Q_PAD_ENET_REF_CLK__USBPHY1_RX_SQH */ + IMX_PIN_REG(MX6Q_PAD_ENET_RX_ER, 0x04EC, 0x01D8, 1, 0x0000, 0), /* MX6Q_PAD_ENET_RX_ER__ENET_RX_ER */ + IMX_PIN_REG(MX6Q_PAD_ENET_RX_ER, 0x04EC, 0x01D8, 2, 0x0864, 0), /* MX6Q_PAD_ENET_RX_ER__ESAI1_HCKR */ + IMX_PIN_REG(MX6Q_PAD_ENET_RX_ER, 0x04EC, 0x01D8, 3, 0x0914, 1), /* MX6Q_PAD_ENET_RX_ER__SPDIF_IN1 */ + IMX_PIN_REG(MX6Q_PAD_ENET_RX_ER, 0x04EC, 0x01D8, 4, 0x0000, 0), /* MX6Q_PAD_ENET_RX_ER__ENET_1588_EVT2_OUT */ + IMX_PIN_REG(MX6Q_PAD_ENET_RX_ER, 0x04EC, 0x01D8, 5, 0x0000, 0), /* MX6Q_PAD_ENET_RX_ER__GPIO_1_24 */ + IMX_PIN_REG(MX6Q_PAD_ENET_RX_ER, 0x04EC, 0x01D8, 6, 0x0000, 0), /* MX6Q_PAD_ENET_RX_ER__PHY_TDI */ + IMX_PIN_REG(MX6Q_PAD_ENET_RX_ER, 0x04EC, 0x01D8, 7, 0x0000, 0), /* MX6Q_PAD_ENET_RX_ER__USBPHY1_RX_HS_RXD */ + IMX_PIN_REG(MX6Q_PAD_ENET_CRS_DV, 0x04F0, 0x01DC, 0, 0x0000, 0), /* MX6Q_PAD_ENET_CRS_DV__RESERVED_RSRVED */ + IMX_PIN_REG(MX6Q_PAD_ENET_CRS_DV, 0x04F0, 0x01DC, 1, 0x0858, 1), /* MX6Q_PAD_ENET_CRS_DV__ENET_RX_EN */ + IMX_PIN_REG(MX6Q_PAD_ENET_CRS_DV, 0x04F0, 0x01DC, 2, 0x0870, 0), /* MX6Q_PAD_ENET_CRS_DV__ESAI1_SCKT */ + IMX_PIN_REG(MX6Q_PAD_ENET_CRS_DV, 0x04F0, 0x01DC, 3, 0x0918, 1), /* MX6Q_PAD_ENET_CRS_DV__SPDIF_EXTCLK */ + IMX_PIN_REG(MX6Q_PAD_ENET_CRS_DV, 0x04F0, 0x01DC, 5, 0x0000, 0), /* MX6Q_PAD_ENET_CRS_DV__GPIO_1_25 */ + IMX_PIN_REG(MX6Q_PAD_ENET_CRS_DV, 0x04F0, 0x01DC, 6, 0x0000, 0), /* MX6Q_PAD_ENET_CRS_DV__PHY_TDO */ + IMX_PIN_REG(MX6Q_PAD_ENET_CRS_DV, 0x04F0, 0x01DC, 7, 0x0000, 0), /* MX6Q_PAD_ENET_CRS_DV__USBPHY1_RX_FS_RXD */ + IMX_PIN_REG(MX6Q_PAD_ENET_RXD1, 0x04F4, 0x01E0, 0, 0x0908, 0), /* MX6Q_PAD_ENET_RXD1__MLB_MLBSIG */ + IMX_PIN_REG(MX6Q_PAD_ENET_RXD1, 0x04F4, 0x01E0, 1, 0x084C, 1), /* MX6Q_PAD_ENET_RXD1__ENET_RDATA_1 */ + IMX_PIN_REG(MX6Q_PAD_ENET_RXD1, 0x04F4, 0x01E0, 2, 0x0860, 0), /* MX6Q_PAD_ENET_RXD1__ESAI1_FST */ + IMX_PIN_REG(MX6Q_PAD_ENET_RXD1, 0x04F4, 0x01E0, 4, 0x0000, 0), /* MX6Q_PAD_ENET_RXD1__ENET_1588_EVT3_OUT */ + IMX_PIN_REG(MX6Q_PAD_ENET_RXD1, 0x04F4, 0x01E0, 5, 0x0000, 0), /* MX6Q_PAD_ENET_RXD1__GPIO_1_26 */ + IMX_PIN_REG(MX6Q_PAD_ENET_RXD1, 0x04F4, 0x01E0, 6, 0x0000, 0), /* MX6Q_PAD_ENET_RXD1__PHY_TCK */ + IMX_PIN_REG(MX6Q_PAD_ENET_RXD1, 0x04F4, 0x01E0, 7, 0x0000, 0), /* MX6Q_PAD_ENET_RXD1__USBPHY1_RX_DISCON */ + IMX_PIN_REG(MX6Q_PAD_ENET_RXD0, 0x04F8, 0x01E4, 0, 0x0000, 0), /* MX6Q_PAD_ENET_RXD0__OSC32K_32K_OUT */ + IMX_PIN_REG(MX6Q_PAD_ENET_RXD0, 0x04F8, 0x01E4, 1, 0x0848, 1), /* MX6Q_PAD_ENET_RXD0__ENET_RDATA_0 */ + IMX_PIN_REG(MX6Q_PAD_ENET_RXD0, 0x04F8, 0x01E4, 2, 0x0868, 0), /* MX6Q_PAD_ENET_RXD0__ESAI1_HCKT */ + IMX_PIN_REG(MX6Q_PAD_ENET_RXD0, 0x04F8, 0x01E4, 3, 0x0000, 0), /* MX6Q_PAD_ENET_RXD0__SPDIF_OUT1 */ + IMX_PIN_REG(MX6Q_PAD_ENET_RXD0, 0x04F8, 0x01E4, 5, 0x0000, 0), /* MX6Q_PAD_ENET_RXD0__GPIO_1_27 */ + IMX_PIN_REG(MX6Q_PAD_ENET_RXD0, 0x04F8, 0x01E4, 6, 0x0000, 0), /* MX6Q_PAD_ENET_RXD0__PHY_TMS */ + IMX_PIN_REG(MX6Q_PAD_ENET_RXD0, 0x04F8, 0x01E4, 7, 0x0000, 0), /* MX6Q_PAD_ENET_RXD0__USBPHY1_PLL_CK20DIV */ + IMX_PIN_REG(MX6Q_PAD_ENET_TX_EN, 0x04FC, 0x01E8, 0, 0x0000, 0), /* MX6Q_PAD_ENET_TX_EN__RESERVED_RSRVED */ + IMX_PIN_REG(MX6Q_PAD_ENET_TX_EN, 0x04FC, 0x01E8, 1, 0x0000, 0), /* MX6Q_PAD_ENET_TX_EN__ENET_TX_EN */ + IMX_PIN_REG(MX6Q_PAD_ENET_TX_EN, 0x04FC, 0x01E8, 2, 0x0880, 0), /* MX6Q_PAD_ENET_TX_EN__ESAI1_TX3_RX2 */ + IMX_PIN_REG(MX6Q_PAD_ENET_TX_EN, 0x04FC, 0x01E8, 5, 0x0000, 0), /* MX6Q_PAD_ENET_TX_EN__GPIO_1_28 */ + IMX_PIN_REG(MX6Q_PAD_ENET_TX_EN, 0x04FC, 0x01E8, 6, 0x0000, 0), /* MX6Q_PAD_ENET_TX_EN__SATA_PHY_TDI */ + IMX_PIN_REG(MX6Q_PAD_ENET_TX_EN, 0x04FC, 0x01E8, 7, 0x0000, 0), /* MX6Q_PAD_ENET_TX_EN__USBPHY2_RX_SQH */ + IMX_PIN_REG(MX6Q_PAD_ENET_TXD1, 0x0500, 0x01EC, 0, 0x0900, 0), /* MX6Q_PAD_ENET_TXD1__MLB_MLBCLK */ + IMX_PIN_REG(MX6Q_PAD_ENET_TXD1, 0x0500, 0x01EC, 1, 0x0000, 0), /* MX6Q_PAD_ENET_TXD1__ENET_TDATA_1 */ + IMX_PIN_REG(MX6Q_PAD_ENET_TXD1, 0x0500, 0x01EC, 2, 0x087C, 0), /* MX6Q_PAD_ENET_TXD1__ESAI1_TX2_RX3 */ + IMX_PIN_REG(MX6Q_PAD_ENET_TXD1, 0x0500, 0x01EC, 4, 0x0000, 0), /* MX6Q_PAD_ENET_TXD1__ENET_1588_EVENT0_IN */ + IMX_PIN_REG(MX6Q_PAD_ENET_TXD1, 0x0500, 0x01EC, 5, 0x0000, 0), /* MX6Q_PAD_ENET_TXD1__GPIO_1_29 */ + IMX_PIN_REG(MX6Q_PAD_ENET_TXD1, 0x0500, 0x01EC, 6, 0x0000, 0), /* MX6Q_PAD_ENET_TXD1__SATA_PHY_TDO */ + IMX_PIN_REG(MX6Q_PAD_ENET_TXD1, 0x0500, 0x01EC, 7, 0x0000, 0), /* MX6Q_PAD_ENET_TXD1__USBPHY2_RX_HS_RXD */ + IMX_PIN_REG(MX6Q_PAD_ENET_TXD0, 0x0504, 0x01F0, 0, 0x0000, 0), /* MX6Q_PAD_ENET_TXD0__RESERVED_RSRVED */ + IMX_PIN_REG(MX6Q_PAD_ENET_TXD0, 0x0504, 0x01F0, 1, 0x0000, 0), /* MX6Q_PAD_ENET_TXD0__ENET_TDATA_0 */ + IMX_PIN_REG(MX6Q_PAD_ENET_TXD0, 0x0504, 0x01F0, 2, 0x0884, 0), /* MX6Q_PAD_ENET_TXD0__ESAI1_TX4_RX1 */ + IMX_PIN_REG(MX6Q_PAD_ENET_TXD0, 0x0504, 0x01F0, 5, 0x0000, 0), /* MX6Q_PAD_ENET_TXD0__GPIO_1_30 */ + IMX_PIN_REG(MX6Q_PAD_ENET_TXD0, 0x0504, 0x01F0, 6, 0x0000, 0), /* MX6Q_PAD_ENET_TXD0__SATA_PHY_TCK */ + IMX_PIN_REG(MX6Q_PAD_ENET_TXD0, 0x0504, 0x01F0, 7, 0x0000, 0), /* MX6Q_PAD_ENET_TXD0__USBPHY2_RX_FS_RXD */ + IMX_PIN_REG(MX6Q_PAD_ENET_MDC, 0x0508, 0x01F4, 0, 0x0904, 0), /* MX6Q_PAD_ENET_MDC__MLB_MLBDAT */ + IMX_PIN_REG(MX6Q_PAD_ENET_MDC, 0x0508, 0x01F4, 1, 0x0000, 0), /* MX6Q_PAD_ENET_MDC__ENET_MDC */ + IMX_PIN_REG(MX6Q_PAD_ENET_MDC, 0x0508, 0x01F4, 2, 0x0888, 0), /* MX6Q_PAD_ENET_MDC__ESAI1_TX5_RX0 */ + IMX_PIN_REG(MX6Q_PAD_ENET_MDC, 0x0508, 0x01F4, 4, 0x0000, 0), /* MX6Q_PAD_ENET_MDC__ENET_1588_EVENT1_IN */ + IMX_PIN_REG(MX6Q_PAD_ENET_MDC, 0x0508, 0x01F4, 5, 0x0000, 0), /* MX6Q_PAD_ENET_MDC__GPIO_1_31 */ + IMX_PIN_REG(MX6Q_PAD_ENET_MDC, 0x0508, 0x01F4, 6, 0x0000, 0), /* MX6Q_PAD_ENET_MDC__SATA_PHY_TMS */ + IMX_PIN_REG(MX6Q_PAD_ENET_MDC, 0x0508, 0x01F4, 7, 0x0000, 0), /* MX6Q_PAD_ENET_MDC__USBPHY2_RX_DISCON */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D40, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D40__MMDC_DRAM_D_40 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D41, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D41__MMDC_DRAM_D_41 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D42, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D42__MMDC_DRAM_D_42 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D43, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D43__MMDC_DRAM_D_43 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D44, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D44__MMDC_DRAM_D_44 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D45, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D45__MMDC_DRAM_D_45 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D46, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D46__MMDC_DRAM_D_46 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D47, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D47__MMDC_DRAM_D_47 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_SDQS5, 0x050C, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDQS5__MMDC_DRAM_SDQS_5 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_DQM5, 0x0510, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_DQM5__MMDC_DRAM_DQM_5 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D32, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D32__MMDC_DRAM_D_32 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D33, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D33__MMDC_DRAM_D_33 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D34, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D34__MMDC_DRAM_D_34 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D35, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D35__MMDC_DRAM_D_35 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D36, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D36__MMDC_DRAM_D_36 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D37, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D37__MMDC_DRAM_D_37 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D38, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D38__MMDC_DRAM_D_38 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D39, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D39__MMDC_DRAM_D_39 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_DQM4, 0x0514, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_DQM4__MMDC_DRAM_DQM_4 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_SDQS4, 0x0518, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDQS4__MMDC_DRAM_SDQS_4 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D24, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D24__MMDC_DRAM_D_24 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D25, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D25__MMDC_DRAM_D_25 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D26, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D26__MMDC_DRAM_D_26 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D27, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D27__MMDC_DRAM_D_27 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D28, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D28__MMDC_DRAM_D_28 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D29, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D29__MMDC_DRAM_D_29 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_SDQS3, 0x051C, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDQS3__MMDC_DRAM_SDQS_3 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D30, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D30__MMDC_DRAM_D_30 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D31, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D31__MMDC_DRAM_D_31 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_DQM3, 0x0520, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_DQM3__MMDC_DRAM_DQM_3 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D16, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D16__MMDC_DRAM_D_16 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D17, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D17__MMDC_DRAM_D_17 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D18, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D18__MMDC_DRAM_D_18 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D19, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D19__MMDC_DRAM_D_19 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D20, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D20__MMDC_DRAM_D_20 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D21, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D21__MMDC_DRAM_D_21 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D22, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D22__MMDC_DRAM_D_22 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_SDQS2, 0x0524, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDQS2__MMDC_DRAM_SDQS_2 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D23, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D23__MMDC_DRAM_D_23 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_DQM2, 0x0528, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_DQM2__MMDC_DRAM_DQM_2 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_A0, 0x052C, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A0__MMDC_DRAM_A_0 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_A1, 0x0530, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A1__MMDC_DRAM_A_1 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_A2, 0x0534, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A2__MMDC_DRAM_A_2 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_A3, 0x0538, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A3__MMDC_DRAM_A_3 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_A4, 0x053C, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A4__MMDC_DRAM_A_4 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_A5, 0x0540, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A5__MMDC_DRAM_A_5 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_A6, 0x0544, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A6__MMDC_DRAM_A_6 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_A7, 0x0548, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A7__MMDC_DRAM_A_7 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_A8, 0x054C, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A8__MMDC_DRAM_A_8 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_A9, 0x0550, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A9__MMDC_DRAM_A_9 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_A10, 0x0554, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A10__MMDC_DRAM_A_10 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_A11, 0x0558, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A11__MMDC_DRAM_A_11 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_A12, 0x055C, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A12__MMDC_DRAM_A_12 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_A13, 0x0560, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A13__MMDC_DRAM_A_13 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_A14, 0x0564, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A14__MMDC_DRAM_A_14 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_A15, 0x0568, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_A15__MMDC_DRAM_A_15 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_CAS, 0x056C, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_CAS__MMDC_DRAM_CAS */ + IMX_PIN_REG(MX6Q_PAD_DRAM_CS0, 0x0570, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_CS0__MMDC_DRAM_CS_0 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_CS1, 0x0574, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_CS1__MMDC_DRAM_CS_1 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_RAS, 0x0578, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_RAS__MMDC_DRAM_RAS */ + IMX_PIN_REG(MX6Q_PAD_DRAM_RESET, 0x057C, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_RESET__MMDC_DRAM_RESET */ + IMX_PIN_REG(MX6Q_PAD_DRAM_SDBA0, 0x0580, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDBA0__MMDC_DRAM_SDBA_0 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_SDBA1, 0x0584, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDBA1__MMDC_DRAM_SDBA_1 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_SDCLK_0, 0x0588, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDCLK_0__MMDC_DRAM_SDCLK0 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_SDBA2, 0x058C, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDBA2__MMDC_DRAM_SDBA_2 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_SDCKE0, 0x0590, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDCKE0__MMDC_DRAM_SDCKE_0 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_SDCLK_1, 0x0594, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDCLK_1__MMDC_DRAM_SDCLK1 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_SDCKE1, 0x0598, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDCKE1__MMDC_DRAM_SDCKE_1 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_SDODT0, 0x059C, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDODT0__MMDC_DRAM_ODT_0 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_SDODT1, 0x05A0, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDODT1__MMDC_DRAM_ODT_1 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_SDWE, 0x05A4, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDWE__MMDC_DRAM_SDWE */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D0, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D0__MMDC_DRAM_D_0 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D1, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D1__MMDC_DRAM_D_1 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D2, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D2__MMDC_DRAM_D_2 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D3, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D3__MMDC_DRAM_D_3 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D4, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D4__MMDC_DRAM_D_4 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D5, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D5__MMDC_DRAM_D_5 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_SDQS0, 0x05A8, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDQS0__MMDC_DRAM_SDQS_0 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D6, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D6__MMDC_DRAM_D_6 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D7, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D7__MMDC_DRAM_D_7 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_DQM0, 0x05AC, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_DQM0__MMDC_DRAM_DQM_0 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D8, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D8__MMDC_DRAM_D_8 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D9, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D9__MMDC_DRAM_D_9 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D10, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D10__MMDC_DRAM_D_10 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D11, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D11__MMDC_DRAM_D_11 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D12, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D12__MMDC_DRAM_D_12 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D13, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D13__MMDC_DRAM_D_13 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D14, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D14__MMDC_DRAM_D_14 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_SDQS1, 0x05B0, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDQS1__MMDC_DRAM_SDQS_1 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D15, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D15__MMDC_DRAM_D_15 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_DQM1, 0x05B4, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_DQM1__MMDC_DRAM_DQM_1 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D48, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D48__MMDC_DRAM_D_48 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D49, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D49__MMDC_DRAM_D_49 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D50, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D50__MMDC_DRAM_D_50 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D51, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D51__MMDC_DRAM_D_51 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D52, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D52__MMDC_DRAM_D_52 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D53, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D53__MMDC_DRAM_D_53 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D54, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D54__MMDC_DRAM_D_54 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D55, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D55__MMDC_DRAM_D_55 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_SDQS6, 0x05B8, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDQS6__MMDC_DRAM_SDQS_6 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_DQM6, 0x05BC, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_DQM6__MMDC_DRAM_DQM_6 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D56, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D56__MMDC_DRAM_D_56 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_SDQS7, 0x05C0, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_SDQS7__MMDC_DRAM_SDQS_7 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D57, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D57__MMDC_DRAM_D_57 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D58, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D58__MMDC_DRAM_D_58 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D59, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D59__MMDC_DRAM_D_59 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D60, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D60__MMDC_DRAM_D_60 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_DQM7, 0x05C4, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_DQM7__MMDC_DRAM_DQM_7 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D61, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D61__MMDC_DRAM_D_61 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D62, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D62__MMDC_DRAM_D_62 */ + IMX_PIN_REG(MX6Q_PAD_DRAM_D63, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_DRAM_D63__MMDC_DRAM_D_63 */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL0, 0x05C8, 0x01F8, 0, 0x07F4, 2), /* MX6Q_PAD_KEY_COL0__ECSPI1_SCLK */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL0, 0x05C8, 0x01F8, 1, 0x0854, 1), /* MX6Q_PAD_KEY_COL0__ENET_RDATA_3 */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL0, 0x05C8, 0x01F8, 2, 0x07DC, 1), /* MX6Q_PAD_KEY_COL0__AUDMUX_AUD5_TXC */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL0, 0x05C8, 0x01F8, 3, 0x0000, 0), /* MX6Q_PAD_KEY_COL0__KPP_COL_0 */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL0, 0x05C8, 0x01F8, 4, 0x0000, 0), /* MX6Q_PAD_KEY_COL0__UART4_TXD */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL0, 0x05C8, 0x01F8, 5, 0x0000, 0), /* MX6Q_PAD_KEY_COL0__GPIO_4_6 */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL0, 0x05C8, 0x01F8, 6, 0x0000, 0), /* MX6Q_PAD_KEY_COL0__DCIC1_DCIC_OUT */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL0, 0x05C8, 0x01F8, 7, 0x0000, 0), /* MX6Q_PAD_KEY_COL0__SRC_ANY_PU_RST */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW0, 0x05CC, 0x01FC, 0, 0x07FC, 2), /* MX6Q_PAD_KEY_ROW0__ECSPI1_MOSI */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW0, 0x05CC, 0x01FC, 1, 0x0000, 0), /* MX6Q_PAD_KEY_ROW0__ENET_TDATA_3 */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW0, 0x05CC, 0x01FC, 2, 0x07D0, 1), /* MX6Q_PAD_KEY_ROW0__AUDMUX_AUD5_TXD */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW0, 0x05CC, 0x01FC, 3, 0x0000, 0), /* MX6Q_PAD_KEY_ROW0__KPP_ROW_0 */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW0, 0x05CC, 0x01FC, 4, 0x0938, 1), /* MX6Q_PAD_KEY_ROW0__UART4_RXD */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW0, 0x05CC, 0x01FC, 5, 0x0000, 0), /* MX6Q_PAD_KEY_ROW0__GPIO_4_7 */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW0, 0x05CC, 0x01FC, 6, 0x0000, 0), /* MX6Q_PAD_KEY_ROW0__DCIC2_DCIC_OUT */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW0, 0x05CC, 0x01FC, 7, 0x0000, 0), /* MX6Q_PAD_KEY_ROW0__PL301_PER1_HADR_0 */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL1, 0x05D0, 0x0200, 0, 0x07F8, 2), /* MX6Q_PAD_KEY_COL1__ECSPI1_MISO */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL1, 0x05D0, 0x0200, 1, 0x0840, 1), /* MX6Q_PAD_KEY_COL1__ENET_MDIO */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL1, 0x05D0, 0x0200, 2, 0x07E0, 1), /* MX6Q_PAD_KEY_COL1__AUDMUX_AUD5_TXFS */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL1, 0x05D0, 0x0200, 3, 0x0000, 0), /* MX6Q_PAD_KEY_COL1__KPP_COL_1 */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL1, 0x05D0, 0x0200, 4, 0x0000, 0), /* MX6Q_PAD_KEY_COL1__UART5_TXD */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL1, 0x05D0, 0x0200, 5, 0x0000, 0), /* MX6Q_PAD_KEY_COL1__GPIO_4_8 */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL1, 0x05D0, 0x0200, 6, 0x0000, 0), /* MX6Q_PAD_KEY_COL1__USDHC1_VSELECT */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL1, 0x05D0, 0x0200, 7, 0x0000, 0), /* MX6Q_PAD_KEY_COL1__PL301MX_PER1_HADR_1 */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW1, 0x05D4, 0x0204, 0, 0x0800, 2), /* MX6Q_PAD_KEY_ROW1__ECSPI1_SS0 */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW1, 0x05D4, 0x0204, 1, 0x0000, 0), /* MX6Q_PAD_KEY_ROW1__ENET_COL */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW1, 0x05D4, 0x0204, 2, 0x07CC, 1), /* MX6Q_PAD_KEY_ROW1__AUDMUX_AUD5_RXD */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW1, 0x05D4, 0x0204, 3, 0x0000, 0), /* MX6Q_PAD_KEY_ROW1__KPP_ROW_1 */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW1, 0x05D4, 0x0204, 4, 0x0940, 1), /* MX6Q_PAD_KEY_ROW1__UART5_RXD */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW1, 0x05D4, 0x0204, 5, 0x0000, 0), /* MX6Q_PAD_KEY_ROW1__GPIO_4_9 */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW1, 0x05D4, 0x0204, 6, 0x0000, 0), /* MX6Q_PAD_KEY_ROW1__USDHC2_VSELECT */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW1, 0x05D4, 0x0204, 7, 0x0000, 0), /* MX6Q_PAD_KEY_ROW1__PL301_PER1_HADDR_2 */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL2, 0x05D8, 0x0208, 0, 0x0804, 2), /* MX6Q_PAD_KEY_COL2__ECSPI1_SS1 */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL2, 0x05D8, 0x0208, 1, 0x0850, 1), /* MX6Q_PAD_KEY_COL2__ENET_RDATA_2 */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL2, 0x05D8, 0x0208, 2, 0x0000, 0), /* MX6Q_PAD_KEY_COL2__CAN1_TXCAN */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL2, 0x05D8, 0x0208, 3, 0x0000, 0), /* MX6Q_PAD_KEY_COL2__KPP_COL_2 */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL2, 0x05D8, 0x0208, 4, 0x0000, 0), /* MX6Q_PAD_KEY_COL2__ENET_MDC */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL2, 0x05D8, 0x0208, 5, 0x0000, 0), /* MX6Q_PAD_KEY_COL2__GPIO_4_10 */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL2, 0x05D8, 0x0208, 6, 0x0000, 0), /* MX6Q_PAD_KEY_COL2__USBOH3_H1_PWRCTL_WKP */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL2, 0x05D8, 0x0208, 7, 0x0000, 0), /* MX6Q_PAD_KEY_COL2__PL301_PER1_HADDR_3 */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW2, 0x05DC, 0x020C, 0, 0x0808, 1), /* MX6Q_PAD_KEY_ROW2__ECSPI1_SS2 */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW2, 0x05DC, 0x020C, 1, 0x0000, 0), /* MX6Q_PAD_KEY_ROW2__ENET_TDATA_2 */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW2, 0x05DC, 0x020C, 2, 0x07E4, 0), /* MX6Q_PAD_KEY_ROW2__CAN1_RXCAN */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW2, 0x05DC, 0x020C, 3, 0x0000, 0), /* MX6Q_PAD_KEY_ROW2__KPP_ROW_2 */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW2, 0x05DC, 0x020C, 4, 0x0000, 0), /* MX6Q_PAD_KEY_ROW2__USDHC2_VSELECT */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW2, 0x05DC, 0x020C, 5, 0x0000, 0), /* MX6Q_PAD_KEY_ROW2__GPIO_4_11 */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW2, 0x05DC, 0x020C, 6, 0x088C, 1), /* MX6Q_PAD_KEY_ROW2__HDMI_TX_CEC_LINE */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW2, 0x05DC, 0x020C, 7, 0x0000, 0), /* MX6Q_PAD_KEY_ROW2__PL301_PER1_HADR_4 */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL3, 0x05E0, 0x0210, 0, 0x080C, 1), /* MX6Q_PAD_KEY_COL3__ECSPI1_SS3 */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL3, 0x05E0, 0x0210, 1, 0x0000, 0), /* MX6Q_PAD_KEY_COL3__ENET_CRS */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL3, 0x05E0, 0x0210, 2, 0x0890, 1), /* MX6Q_PAD_KEY_COL3__HDMI_TX_DDC_SCL */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL3, 0x05E0, 0x0210, 3, 0x0000, 0), /* MX6Q_PAD_KEY_COL3__KPP_COL_3 */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL3, 0x05E0, 0x0210, 4, 0x08A0, 1), /* MX6Q_PAD_KEY_COL3__I2C2_SCL */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL3, 0x05E0, 0x0210, 5, 0x0000, 0), /* MX6Q_PAD_KEY_COL3__GPIO_4_12 */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL3, 0x05E0, 0x0210, 6, 0x0914, 2), /* MX6Q_PAD_KEY_COL3__SPDIF_IN1 */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL3, 0x05E0, 0x0210, 7, 0x0000, 0), /* MX6Q_PAD_KEY_COL3__PL301_PER1_HADR_5 */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW3, 0x05E4, 0x0214, 0, 0x0000, 0), /* MX6Q_PAD_KEY_ROW3__OSC32K_32K_OUT */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW3, 0x05E4, 0x0214, 1, 0x07B0, 0), /* MX6Q_PAD_KEY_ROW3__ASRC_ASRC_EXT_CLK */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW3, 0x05E4, 0x0214, 2, 0x0894, 1), /* MX6Q_PAD_KEY_ROW3__HDMI_TX_DDC_SDA */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW3, 0x05E4, 0x0214, 3, 0x0000, 0), /* MX6Q_PAD_KEY_ROW3__KPP_ROW_3 */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW3, 0x05E4, 0x0214, 4, 0x08A4, 1), /* MX6Q_PAD_KEY_ROW3__I2C2_SDA */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW3, 0x05E4, 0x0214, 5, 0x0000, 0), /* MX6Q_PAD_KEY_ROW3__GPIO_4_13 */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW3, 0x05E4, 0x0214, 6, 0x0000, 0), /* MX6Q_PAD_KEY_ROW3__USDHC1_VSELECT */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW3, 0x05E4, 0x0214, 7, 0x0000, 0), /* MX6Q_PAD_KEY_ROW3__PL301_PER1_HADR_6 */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL4, 0x05E8, 0x0218, 0, 0x0000, 0), /* MX6Q_PAD_KEY_COL4__CAN2_TXCAN */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL4, 0x05E8, 0x0218, 1, 0x0000, 0), /* MX6Q_PAD_KEY_COL4__IPU1_SISG_4 */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL4, 0x05E8, 0x0218, 2, 0x0944, 1), /* MX6Q_PAD_KEY_COL4__USBOH3_USBOTG_OC */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL4, 0x05E8, 0x0218, 3, 0x0000, 0), /* MX6Q_PAD_KEY_COL4__KPP_COL_4 */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL4, 0x05E8, 0x0218, 4, 0x093C, 0), /* MX6Q_PAD_KEY_COL4__UART5_RTS */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL4, 0x05E8, 0x0218, 5, 0x0000, 0), /* MX6Q_PAD_KEY_COL4__GPIO_4_14 */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL4, 0x05E8, 0x0218, 6, 0x0000, 0), /* MX6Q_PAD_KEY_COL4__MMDC_DEBUG_49 */ + IMX_PIN_REG(MX6Q_PAD_KEY_COL4, 0x05E8, 0x0218, 7, 0x0000, 0), /* MX6Q_PAD_KEY_COL4__PL301_PER1_HADDR_7 */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW4, 0x05EC, 0x021C, 0, 0x07E8, 0), /* MX6Q_PAD_KEY_ROW4__CAN2_RXCAN */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW4, 0x05EC, 0x021C, 1, 0x0000, 0), /* MX6Q_PAD_KEY_ROW4__IPU1_SISG_5 */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW4, 0x05EC, 0x021C, 2, 0x0000, 0), /* MX6Q_PAD_KEY_ROW4__USBOH3_USBOTG_PWR */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW4, 0x05EC, 0x021C, 3, 0x0000, 0), /* MX6Q_PAD_KEY_ROW4__KPP_ROW_4 */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW4, 0x05EC, 0x021C, 4, 0x093C, 1), /* MX6Q_PAD_KEY_ROW4__UART5_CTS */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW4, 0x05EC, 0x021C, 5, 0x0000, 0), /* MX6Q_PAD_KEY_ROW4__GPIO_4_15 */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW4, 0x05EC, 0x021C, 6, 0x0000, 0), /* MX6Q_PAD_KEY_ROW4__MMDC_DEBUG_50 */ + IMX_PIN_REG(MX6Q_PAD_KEY_ROW4, 0x05EC, 0x021C, 7, 0x0000, 0), /* MX6Q_PAD_KEY_ROW4__PL301_PER1_HADR_8 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_0, 0x05F0, 0x0220, 0, 0x0000, 0), /* MX6Q_PAD_GPIO_0__CCM_CLKO */ + IMX_PIN_REG(MX6Q_PAD_GPIO_0, 0x05F0, 0x0220, 2, 0x08E8, 0), /* MX6Q_PAD_GPIO_0__KPP_COL_5 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_0, 0x05F0, 0x0220, 3, 0x07B0, 1), /* MX6Q_PAD_GPIO_0__ASRC_ASRC_EXT_CLK */ + IMX_PIN_REG(MX6Q_PAD_GPIO_0, 0x05F0, 0x0220, 4, 0x0000, 0), /* MX6Q_PAD_GPIO_0__EPIT1_EPITO */ + IMX_PIN_REG(MX6Q_PAD_GPIO_0, 0x05F0, 0x0220, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_0__GPIO_1_0 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_0, 0x05F0, 0x0220, 6, 0x0000, 0), /* MX6Q_PAD_GPIO_0__USBOH3_USBH1_PWR */ + IMX_PIN_REG(MX6Q_PAD_GPIO_0, 0x05F0, 0x0220, 7, 0x0000, 0), /* MX6Q_PAD_GPIO_0__SNVS_HP_WRAP_SNVS_VIO5 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_1, 0x05F4, 0x0224, 0, 0x086C, 1), /* MX6Q_PAD_GPIO_1__ESAI1_SCKR */ + IMX_PIN_REG(MX6Q_PAD_GPIO_1, 0x05F4, 0x0224, 1, 0x0000, 0), /* MX6Q_PAD_GPIO_1__WDOG2_WDOG_B */ + IMX_PIN_REG(MX6Q_PAD_GPIO_1, 0x05F4, 0x0224, 2, 0x08F4, 0), /* MX6Q_PAD_GPIO_1__KPP_ROW_5 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_1, 0x05F4, 0x0224, 4, 0x0000, 0), /* MX6Q_PAD_GPIO_1__PWM2_PWMO */ + IMX_PIN_REG(MX6Q_PAD_GPIO_1, 0x05F4, 0x0224, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_1__GPIO_1_1 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_1, 0x05F4, 0x0224, 6, 0x0000, 0), /* MX6Q_PAD_GPIO_1__USDHC1_CD */ + IMX_PIN_REG(MX6Q_PAD_GPIO_1, 0x05F4, 0x0224, 7, 0x0000, 0), /* MX6Q_PAD_GPIO_1__SRC_TESTER_ACK */ + IMX_PIN_REG(MX6Q_PAD_GPIO_9, 0x05F8, 0x0228, 0, 0x085C, 1), /* MX6Q_PAD_GPIO_9__ESAI1_FSR */ + IMX_PIN_REG(MX6Q_PAD_GPIO_9, 0x05F8, 0x0228, 1, 0x0000, 0), /* MX6Q_PAD_GPIO_9__WDOG1_WDOG_B */ + IMX_PIN_REG(MX6Q_PAD_GPIO_9, 0x05F8, 0x0228, 2, 0x08EC, 0), /* MX6Q_PAD_GPIO_9__KPP_COL_6 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_9, 0x05F8, 0x0228, 3, 0x0000, 0), /* MX6Q_PAD_GPIO_9__CCM_REF_EN_B */ + IMX_PIN_REG(MX6Q_PAD_GPIO_9, 0x05F8, 0x0228, 4, 0x0000, 0), /* MX6Q_PAD_GPIO_9__PWM1_PWMO */ + IMX_PIN_REG(MX6Q_PAD_GPIO_9, 0x05F8, 0x0228, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_9__GPIO_1_9 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_9, 0x05F8, 0x0228, 6, 0x094C, 1), /* MX6Q_PAD_GPIO_9__USDHC1_WP */ + IMX_PIN_REG(MX6Q_PAD_GPIO_9, 0x05F8, 0x0228, 7, 0x0000, 0), /* MX6Q_PAD_GPIO_9__SRC_EARLY_RST */ + IMX_PIN_REG(MX6Q_PAD_GPIO_3, 0x05FC, 0x022C, 0, 0x0864, 1), /* MX6Q_PAD_GPIO_3__ESAI1_HCKR */ + IMX_PIN_REG(MX6Q_PAD_GPIO_3, 0x05FC, 0x022C, 1, 0x0000, 0), /* MX6Q_PAD_GPIO_3__OBSERVE_MUX_INT_OUT0 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_3, 0x05FC, 0x022C, 2, 0x08A8, 1), /* MX6Q_PAD_GPIO_3__I2C3_SCL */ + IMX_PIN_REG(MX6Q_PAD_GPIO_3, 0x05FC, 0x022C, 3, 0x0000, 0), /* MX6Q_PAD_GPIO_3__ANATOP_24M_OUT */ + IMX_PIN_REG(MX6Q_PAD_GPIO_3, 0x05FC, 0x022C, 4, 0x0000, 0), /* MX6Q_PAD_GPIO_3__CCM_CLKO2 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_3, 0x05FC, 0x022C, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_3__GPIO_1_3 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_3, 0x05FC, 0x022C, 6, 0x0948, 1), /* MX6Q_PAD_GPIO_3__USBOH3_USBH1_OC */ + IMX_PIN_REG(MX6Q_PAD_GPIO_3, 0x05FC, 0x022C, 7, 0x0900, 1), /* MX6Q_PAD_GPIO_3__MLB_MLBCLK */ + IMX_PIN_REG(MX6Q_PAD_GPIO_6, 0x0600, 0x0230, 0, 0x0870, 1), /* MX6Q_PAD_GPIO_6__ESAI1_SCKT */ + IMX_PIN_REG(MX6Q_PAD_GPIO_6, 0x0600, 0x0230, 1, 0x0000, 0), /* MX6Q_PAD_GPIO_6__OBSERVE_MUX_INT_OUT1 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_6, 0x0600, 0x0230, 2, 0x08AC, 1), /* MX6Q_PAD_GPIO_6__I2C3_SDA */ + IMX_PIN_REG(MX6Q_PAD_GPIO_6, 0x0600, 0x0230, 3, 0x0000, 0), /* MX6Q_PAD_GPIO_6__CCM_CCM_OUT_0 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_6, 0x0600, 0x0230, 4, 0x0000, 0), /* MX6Q_PAD_GPIO_6__CSU_CSU_INT_DEB */ + IMX_PIN_REG(MX6Q_PAD_GPIO_6, 0x0600, 0x0230, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_6__GPIO_1_6 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_6, 0x0600, 0x0230, 6, 0x0000, 0), /* MX6Q_PAD_GPIO_6__USDHC2_LCTL */ + IMX_PIN_REG(MX6Q_PAD_GPIO_6, 0x0600, 0x0230, 7, 0x0908, 1), /* MX6Q_PAD_GPIO_6__MLB_MLBSIG */ + IMX_PIN_REG(MX6Q_PAD_GPIO_2, 0x0604, 0x0234, 0, 0x0860, 1), /* MX6Q_PAD_GPIO_2__ESAI1_FST */ + IMX_PIN_REG(MX6Q_PAD_GPIO_2, 0x0604, 0x0234, 1, 0x0000, 0), /* MX6Q_PAD_GPIO_2__OBSERVE_MUX_INT_OUT2 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_2, 0x0604, 0x0234, 2, 0x08F8, 1), /* MX6Q_PAD_GPIO_2__KPP_ROW_6 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_2, 0x0604, 0x0234, 3, 0x0000, 0), /* MX6Q_PAD_GPIO_2__CCM_CCM_OUT_1 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_2, 0x0604, 0x0234, 4, 0x0000, 0), /* MX6Q_PAD_GPIO_2__CSU_CSU_ALARM_AUT_0 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_2, 0x0604, 0x0234, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_2__GPIO_1_2 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_2, 0x0604, 0x0234, 6, 0x0000, 0), /* MX6Q_PAD_GPIO_2__USDHC2_WP */ + IMX_PIN_REG(MX6Q_PAD_GPIO_2, 0x0604, 0x0234, 7, 0x0904, 1), /* MX6Q_PAD_GPIO_2__MLB_MLBDAT */ + IMX_PIN_REG(MX6Q_PAD_GPIO_4, 0x0608, 0x0238, 0, 0x0868, 1), /* MX6Q_PAD_GPIO_4__ESAI1_HCKT */ + IMX_PIN_REG(MX6Q_PAD_GPIO_4, 0x0608, 0x0238, 1, 0x0000, 0), /* MX6Q_PAD_GPIO_4__OBSERVE_MUX_INT_OUT3 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_4, 0x0608, 0x0238, 2, 0x08F0, 1), /* MX6Q_PAD_GPIO_4__KPP_COL_7 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_4, 0x0608, 0x0238, 3, 0x0000, 0), /* MX6Q_PAD_GPIO_4__CCM_CCM_OUT_2 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_4, 0x0608, 0x0238, 4, 0x0000, 0), /* MX6Q_PAD_GPIO_4__CSU_CSU_ALARM_AUT_1 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_4, 0x0608, 0x0238, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_4__GPIO_1_4 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_4, 0x0608, 0x0238, 6, 0x0000, 0), /* MX6Q_PAD_GPIO_4__USDHC2_CD */ + IMX_PIN_REG(MX6Q_PAD_GPIO_4, 0x0608, 0x0238, 7, 0x0000, 0), /* MX6Q_PAD_GPIO_4__OCOTP_CRL_WRAR_FUSE_LA */ + IMX_PIN_REG(MX6Q_PAD_GPIO_5, 0x060C, 0x023C, 0, 0x087C, 1), /* MX6Q_PAD_GPIO_5__ESAI1_TX2_RX3 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_5, 0x060C, 0x023C, 1, 0x0000, 0), /* MX6Q_PAD_GPIO_5__OBSERVE_MUX_INT_OUT4 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_5, 0x060C, 0x023C, 2, 0x08FC, 1), /* MX6Q_PAD_GPIO_5__KPP_ROW_7 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_5, 0x060C, 0x023C, 3, 0x0000, 0), /* MX6Q_PAD_GPIO_5__CCM_CLKO */ + IMX_PIN_REG(MX6Q_PAD_GPIO_5, 0x060C, 0x023C, 4, 0x0000, 0), /* MX6Q_PAD_GPIO_5__CSU_CSU_ALARM_AUT_2 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_5, 0x060C, 0x023C, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_5__GPIO_1_5 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_5, 0x060C, 0x023C, 6, 0x08A8, 2), /* MX6Q_PAD_GPIO_5__I2C3_SCL */ + IMX_PIN_REG(MX6Q_PAD_GPIO_5, 0x060C, 0x023C, 7, 0x0000, 0), /* MX6Q_PAD_GPIO_5__CHEETAH_EVENTI */ + IMX_PIN_REG(MX6Q_PAD_GPIO_7, 0x0610, 0x0240, 0, 0x0884, 1), /* MX6Q_PAD_GPIO_7__ESAI1_TX4_RX1 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_7, 0x0610, 0x0240, 1, 0x0000, 0), /* MX6Q_PAD_GPIO_7__ECSPI5_RDY */ + IMX_PIN_REG(MX6Q_PAD_GPIO_7, 0x0610, 0x0240, 2, 0x0000, 0), /* MX6Q_PAD_GPIO_7__EPIT1_EPITO */ + IMX_PIN_REG(MX6Q_PAD_GPIO_7, 0x0610, 0x0240, 3, 0x0000, 0), /* MX6Q_PAD_GPIO_7__CAN1_TXCAN */ + IMX_PIN_REG(MX6Q_PAD_GPIO_7, 0x0610, 0x0240, 4, 0x0000, 0), /* MX6Q_PAD_GPIO_7__UART2_TXD */ + IMX_PIN_REG(MX6Q_PAD_GPIO_7, 0x0610, 0x0240, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_7__GPIO_1_7 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_7, 0x0610, 0x0240, 6, 0x0000, 0), /* MX6Q_PAD_GPIO_7__SPDIF_PLOCK */ + IMX_PIN_REG(MX6Q_PAD_GPIO_7, 0x0610, 0x0240, 7, 0x0000, 0), /* MX6Q_PAD_GPIO_7__USBOH3_OTGUSB_HST_MODE */ + IMX_PIN_REG(MX6Q_PAD_GPIO_8, 0x0614, 0x0244, 0, 0x0888, 1), /* MX6Q_PAD_GPIO_8__ESAI1_TX5_RX0 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_8, 0x0614, 0x0244, 1, 0x0000, 0), /* MX6Q_PAD_GPIO_8__ANATOP_ANATOP_32K_OUT */ + IMX_PIN_REG(MX6Q_PAD_GPIO_8, 0x0614, 0x0244, 2, 0x0000, 0), /* MX6Q_PAD_GPIO_8__EPIT2_EPITO */ + IMX_PIN_REG(MX6Q_PAD_GPIO_8, 0x0614, 0x0244, 3, 0x07E4, 1), /* MX6Q_PAD_GPIO_8__CAN1_RXCAN */ + IMX_PIN_REG(MX6Q_PAD_GPIO_8, 0x0614, 0x0244, 4, 0x0928, 3), /* MX6Q_PAD_GPIO_8__UART2_RXD */ + IMX_PIN_REG(MX6Q_PAD_GPIO_8, 0x0614, 0x0244, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_8__GPIO_1_8 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_8, 0x0614, 0x0244, 6, 0x0000, 0), /* MX6Q_PAD_GPIO_8__SPDIF_SRCLK */ + IMX_PIN_REG(MX6Q_PAD_GPIO_8, 0x0614, 0x0244, 7, 0x0000, 0), /* MX6Q_PAD_GPIO_8__USBOH3_OTG_PWRCTL_WAK */ + IMX_PIN_REG(MX6Q_PAD_GPIO_16, 0x0618, 0x0248, 0, 0x0880, 1), /* MX6Q_PAD_GPIO_16__ESAI1_TX3_RX2 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_16, 0x0618, 0x0248, 1, 0x0000, 0), /* MX6Q_PAD_GPIO_16__ENET_1588_EVENT2_IN */ + IMX_PIN_REG(MX6Q_PAD_GPIO_16, 0x0618, 0x0248, 2, 0x083C, 1), /* MX6Q_PAD_GPIO_16__ENET_ETHERNET_REF_OUT */ + IMX_PIN_REG(MX6Q_PAD_GPIO_16, 0x0618, 0x0248, 3, 0x0000, 0), /* MX6Q_PAD_GPIO_16__USDHC1_LCTL */ + IMX_PIN_REG(MX6Q_PAD_GPIO_16, 0x0618, 0x0248, 4, 0x0914, 3), /* MX6Q_PAD_GPIO_16__SPDIF_IN1 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_16, 0x0618, 0x0248, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_16__GPIO_7_11 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_16, 0x0618, 0x0248, 6, 0x08AC, 2), /* MX6Q_PAD_GPIO_16__I2C3_SDA */ + IMX_PIN_REG(MX6Q_PAD_GPIO_16, 0x0618, 0x0248, 7, 0x0000, 0), /* MX6Q_PAD_GPIO_16__SJC_DE_B */ + IMX_PIN_REG(MX6Q_PAD_GPIO_17, 0x061C, 0x024C, 0, 0x0874, 0), /* MX6Q_PAD_GPIO_17__ESAI1_TX0 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_17, 0x061C, 0x024C, 1, 0x0000, 0), /* MX6Q_PAD_GPIO_17__ENET_1588_EVENT3_IN */ + IMX_PIN_REG(MX6Q_PAD_GPIO_17, 0x061C, 0x024C, 2, 0x07F0, 1), /* MX6Q_PAD_GPIO_17__CCM_PMIC_RDY */ + IMX_PIN_REG(MX6Q_PAD_GPIO_17, 0x061C, 0x024C, 3, 0x090C, 1), /* MX6Q_PAD_GPIO_17__SDMA_SDMA_EXT_EVENT_0 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_17, 0x061C, 0x024C, 4, 0x0000, 0), /* MX6Q_PAD_GPIO_17__SPDIF_OUT1 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_17, 0x061C, 0x024C, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_17__GPIO_7_12 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_17, 0x061C, 0x024C, 7, 0x0000, 0), /* MX6Q_PAD_GPIO_17__SJC_JTAG_ACT */ + IMX_PIN_REG(MX6Q_PAD_GPIO_18, 0x0620, 0x0250, 0, 0x0878, 0), /* MX6Q_PAD_GPIO_18__ESAI1_TX1 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_18, 0x0620, 0x0250, 1, 0x0844, 1), /* MX6Q_PAD_GPIO_18__ENET_RX_CLK */ + IMX_PIN_REG(MX6Q_PAD_GPIO_18, 0x0620, 0x0250, 2, 0x0000, 0), /* MX6Q_PAD_GPIO_18__USDHC3_VSELECT */ + IMX_PIN_REG(MX6Q_PAD_GPIO_18, 0x0620, 0x0250, 3, 0x0910, 1), /* MX6Q_PAD_GPIO_18__SDMA_SDMA_EXT_EVENT_1 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_18, 0x0620, 0x0250, 4, 0x07B0, 2), /* MX6Q_PAD_GPIO_18__ASRC_ASRC_EXT_CLK */ + IMX_PIN_REG(MX6Q_PAD_GPIO_18, 0x0620, 0x0250, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_18__GPIO_7_13 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_18, 0x0620, 0x0250, 6, 0x0000, 0), /* MX6Q_PAD_GPIO_18__SNVS_HP_WRA_SNVS_VIO5 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_18, 0x0620, 0x0250, 7, 0x0000, 0), /* MX6Q_PAD_GPIO_18__SRC_SYSTEM_RST */ + IMX_PIN_REG(MX6Q_PAD_GPIO_19, 0x0624, 0x0254, 0, 0x08E8, 1), /* MX6Q_PAD_GPIO_19__KPP_COL_5 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_19, 0x0624, 0x0254, 1, 0x0000, 0), /* MX6Q_PAD_GPIO_19__ENET_1588_EVENT0_OUT */ + IMX_PIN_REG(MX6Q_PAD_GPIO_19, 0x0624, 0x0254, 2, 0x0000, 0), /* MX6Q_PAD_GPIO_19__SPDIF_OUT1 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_19, 0x0624, 0x0254, 3, 0x0000, 0), /* MX6Q_PAD_GPIO_19__CCM_CLKO */ + IMX_PIN_REG(MX6Q_PAD_GPIO_19, 0x0624, 0x0254, 4, 0x0000, 0), /* MX6Q_PAD_GPIO_19__ECSPI1_RDY */ + IMX_PIN_REG(MX6Q_PAD_GPIO_19, 0x0624, 0x0254, 5, 0x0000, 0), /* MX6Q_PAD_GPIO_19__GPIO_4_5 */ + IMX_PIN_REG(MX6Q_PAD_GPIO_19, 0x0624, 0x0254, 6, 0x0000, 0), /* MX6Q_PAD_GPIO_19__ENET_TX_ER */ + IMX_PIN_REG(MX6Q_PAD_GPIO_19, 0x0624, 0x0254, 7, 0x0000, 0), /* MX6Q_PAD_GPIO_19__SRC_INT_BOOT */ + IMX_PIN_REG(MX6Q_PAD_CSI0_PIXCLK, 0x0628, 0x0258, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK */ + IMX_PIN_REG(MX6Q_PAD_CSI0_PIXCLK, 0x0628, 0x0258, 2, 0x0000, 0), /* MX6Q_PAD_CSI0_PIXCLK__PCIE_CTRL_MUX_12 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_PIXCLK, 0x0628, 0x0258, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_PIXCLK__SDMA_DEBUG_PC_0 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_PIXCLK, 0x0628, 0x0258, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_PIXCLK__GPIO_5_18 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_PIXCLK, 0x0628, 0x0258, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_PIXCLK___MMDC_DEBUG_29 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_PIXCLK, 0x0628, 0x0258, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_PIXCLK__CHEETAH_EVENTO */ + IMX_PIN_REG(MX6Q_PAD_CSI0_MCLK, 0x062C, 0x025C, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC */ + IMX_PIN_REG(MX6Q_PAD_CSI0_MCLK, 0x062C, 0x025C, 2, 0x0000, 0), /* MX6Q_PAD_CSI0_MCLK__PCIE_CTRL_MUX_13 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_MCLK, 0x062C, 0x025C, 3, 0x0000, 0), /* MX6Q_PAD_CSI0_MCLK__CCM_CLKO */ + IMX_PIN_REG(MX6Q_PAD_CSI0_MCLK, 0x062C, 0x025C, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_MCLK__SDMA_DEBUG_PC_1 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_MCLK, 0x062C, 0x025C, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_MCLK__GPIO_5_19 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_MCLK, 0x062C, 0x025C, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_MCLK__MMDC_MMDC_DEBUG_30 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_MCLK, 0x062C, 0x025C, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_MCLK__CHEETAH_TRCTL */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DATA_EN, 0x0630, 0x0260, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DATA_EN__IPU1_CSI0_DA_EN */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DATA_EN, 0x0630, 0x0260, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DATA_EN__WEIM_WEIM_D_0 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DATA_EN, 0x0630, 0x0260, 2, 0x0000, 0), /* MX6Q_PAD_CSI0_DATA_EN__PCIE_CTRL_MUX_14 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DATA_EN, 0x0630, 0x0260, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DATA_EN__SDMA_DEBUG_PC_2 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DATA_EN, 0x0630, 0x0260, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DATA_EN__GPIO_5_20 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DATA_EN, 0x0630, 0x0260, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DATA_EN__MMDC_DEBUG_31 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DATA_EN, 0x0630, 0x0260, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DATA_EN__CHEETAH_TRCLK */ + IMX_PIN_REG(MX6Q_PAD_CSI0_VSYNC, 0x0634, 0x0264, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC */ + IMX_PIN_REG(MX6Q_PAD_CSI0_VSYNC, 0x0634, 0x0264, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_VSYNC__WEIM_WEIM_D_1 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_VSYNC, 0x0634, 0x0264, 2, 0x0000, 0), /* MX6Q_PAD_CSI0_VSYNC__PCIE_CTRL_MUX_15 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_VSYNC, 0x0634, 0x0264, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_VSYNC__SDMA_DEBUG_PC_3 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_VSYNC, 0x0634, 0x0264, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_VSYNC__GPIO_5_21 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_VSYNC, 0x0634, 0x0264, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_VSYNC__MMDC_DEBUG_32 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_VSYNC, 0x0634, 0x0264, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_VSYNC__CHEETAH_TRACE_0 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT4, 0x0638, 0x0268, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT4__IPU1_CSI0_D_4 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT4, 0x0638, 0x0268, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT4__WEIM_WEIM_D_2 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT4, 0x0638, 0x0268, 2, 0x07F4, 3), /* MX6Q_PAD_CSI0_DAT4__ECSPI1_SCLK */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT4, 0x0638, 0x0268, 3, 0x08E8, 2), /* MX6Q_PAD_CSI0_DAT4__KPP_COL_5 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT4, 0x0638, 0x0268, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT4__AUDMUX_AUD3_TXC */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT4, 0x0638, 0x0268, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT4__GPIO_5_22 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT4, 0x0638, 0x0268, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT4__MMDC_DEBUG_43 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT4, 0x0638, 0x0268, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT4__CHEETAH_TRACE_1 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT5, 0x063C, 0x026C, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT5__IPU1_CSI0_D_5 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT5, 0x063C, 0x026C, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT5__WEIM_WEIM_D_3 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT5, 0x063C, 0x026C, 2, 0x07FC, 3), /* MX6Q_PAD_CSI0_DAT5__ECSPI1_MOSI */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT5, 0x063C, 0x026C, 3, 0x08F4, 1), /* MX6Q_PAD_CSI0_DAT5__KPP_ROW_5 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT5, 0x063C, 0x026C, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT5__AUDMUX_AUD3_TXD */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT5, 0x063C, 0x026C, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT5__GPIO_5_23 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT5, 0x063C, 0x026C, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT5__MMDC_MMDC_DEBUG_44 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT5, 0x063C, 0x026C, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT5__CHEETAH_TRACE_2 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT6, 0x0640, 0x0270, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT6__IPU1_CSI0_D_6 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT6, 0x0640, 0x0270, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT6__WEIM_WEIM_D_4 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT6, 0x0640, 0x0270, 2, 0x07F8, 3), /* MX6Q_PAD_CSI0_DAT6__ECSPI1_MISO */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT6, 0x0640, 0x0270, 3, 0x08EC, 1), /* MX6Q_PAD_CSI0_DAT6__KPP_COL_6 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT6, 0x0640, 0x0270, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT6__AUDMUX_AUD3_TXFS */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT6, 0x0640, 0x0270, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT6__GPIO_5_24 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT6, 0x0640, 0x0270, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT6__MMDC_MMDC_DEBUG_45 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT6, 0x0640, 0x0270, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT6__CHEETAH_TRACE_3 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT7, 0x0644, 0x0274, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT7__IPU1_CSI0_D_7 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT7, 0x0644, 0x0274, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT7__WEIM_WEIM_D_5 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT7, 0x0644, 0x0274, 2, 0x0800, 3), /* MX6Q_PAD_CSI0_DAT7__ECSPI1_SS0 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT7, 0x0644, 0x0274, 3, 0x08F8, 2), /* MX6Q_PAD_CSI0_DAT7__KPP_ROW_6 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT7, 0x0644, 0x0274, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT7__AUDMUX_AUD3_RXD */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT7, 0x0644, 0x0274, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT7__GPIO_5_25 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT7, 0x0644, 0x0274, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT7__MMDC_MMDC_DEBUG_46 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT7, 0x0644, 0x0274, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT7__CHEETAH_TRACE_4 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT8, 0x0648, 0x0278, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT8__IPU1_CSI0_D_8 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT8, 0x0648, 0x0278, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT8__WEIM_WEIM_D_6 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT8, 0x0648, 0x0278, 2, 0x0810, 2), /* MX6Q_PAD_CSI0_DAT8__ECSPI2_SCLK */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT8, 0x0648, 0x0278, 3, 0x08F0, 2), /* MX6Q_PAD_CSI0_DAT8__KPP_COL_7 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT8, 0x0648, 0x0278, 4, 0x089C, 1), /* MX6Q_PAD_CSI0_DAT8__I2C1_SDA */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT8, 0x0648, 0x0278, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT8__GPIO_5_26 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT8, 0x0648, 0x0278, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT8__MMDC_MMDC_DEBUG_47 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT8, 0x0648, 0x0278, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT8__CHEETAH_TRACE_5 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT9, 0x064C, 0x027C, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT9__IPU1_CSI0_D_9 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT9, 0x064C, 0x027C, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT9__WEIM_WEIM_D_7 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT9, 0x064C, 0x027C, 2, 0x0818, 2), /* MX6Q_PAD_CSI0_DAT9__ECSPI2_MOSI */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT9, 0x064C, 0x027C, 3, 0x08FC, 2), /* MX6Q_PAD_CSI0_DAT9__KPP_ROW_7 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT9, 0x064C, 0x027C, 4, 0x0898, 1), /* MX6Q_PAD_CSI0_DAT9__I2C1_SCL */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT9, 0x064C, 0x027C, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT9__GPIO_5_27 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT9, 0x064C, 0x027C, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT9__MMDC_MMDC_DEBUG_48 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT9, 0x064C, 0x027C, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT9__CHEETAH_TRACE_6 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT10, 0x0650, 0x0280, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT10__IPU1_CSI0_D_10 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT10, 0x0650, 0x0280, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT10__AUDMUX_AUD3_RXC */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT10, 0x0650, 0x0280, 2, 0x0814, 2), /* MX6Q_PAD_CSI0_DAT10__ECSPI2_MISO */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT10, 0x0650, 0x0280, 3, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT10__UART1_TXD */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT10, 0x0650, 0x0280, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT10__SDMA_DEBUG_PC_4 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT10, 0x0650, 0x0280, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT10__GPIO_5_28 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT10, 0x0650, 0x0280, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT10__MMDC_MMDC_DEBUG_33 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT10, 0x0650, 0x0280, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT10__CHEETAH_TRACE_7 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT11, 0x0654, 0x0284, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT11__IPU1_CSI0_D_11 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT11, 0x0654, 0x0284, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT11__AUDMUX_AUD3_RXFS */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT11, 0x0654, 0x0284, 2, 0x081C, 2), /* MX6Q_PAD_CSI0_DAT11__ECSPI2_SS0 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT11, 0x0654, 0x0284, 3, 0x0920, 1), /* MX6Q_PAD_CSI0_DAT11__UART1_RXD */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT11, 0x0654, 0x0284, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT11__SDMA_DEBUG_PC_5 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT11, 0x0654, 0x0284, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT11__GPIO_5_29 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT11, 0x0654, 0x0284, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT11__MMDC_MMDC_DEBUG_34 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT11, 0x0654, 0x0284, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT11__CHEETAH_TRACE_8 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT12, 0x0658, 0x0288, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT12__IPU1_CSI0_D_12 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT12, 0x0658, 0x0288, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT12__WEIM_WEIM_D_8 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT12, 0x0658, 0x0288, 2, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT12__PCIE_CTRL_MUX_16 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT12, 0x0658, 0x0288, 3, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT12__UART4_TXD */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT12, 0x0658, 0x0288, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT12__SDMA_DEBUG_PC_6 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT12, 0x0658, 0x0288, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT12__GPIO_5_30 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT12, 0x0658, 0x0288, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT12__MMDC_MMDC_DEBUG_35 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT12, 0x0658, 0x0288, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT12__CHEETAH_TRACE_9 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT13, 0x065C, 0x028C, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT13__IPU1_CSI0_D_13 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT13, 0x065C, 0x028C, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT13__WEIM_WEIM_D_9 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT13, 0x065C, 0x028C, 2, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT13__PCIE_CTRL_MUX_17 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT13, 0x065C, 0x028C, 3, 0x0938, 3), /* MX6Q_PAD_CSI0_DAT13__UART4_RXD */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT13, 0x065C, 0x028C, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT13__SDMA_DEBUG_PC_7 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT13, 0x065C, 0x028C, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT13__GPIO_5_31 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT13, 0x065C, 0x028C, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT13__MMDC_MMDC_DEBUG_36 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT13, 0x065C, 0x028C, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT13__CHEETAH_TRACE_10 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT14, 0x0660, 0x0290, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT14__IPU1_CSI0_D_14 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT14, 0x0660, 0x0290, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT14__WEIM_WEIM_D_10 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT14, 0x0660, 0x0290, 2, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT14__PCIE_CTRL_MUX_18 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT14, 0x0660, 0x0290, 3, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT14__UART5_TXD */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT14, 0x0660, 0x0290, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT14__SDMA_DEBUG_PC_8 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT14, 0x0660, 0x0290, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT14__GPIO_6_0 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT14, 0x0660, 0x0290, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT14__MMDC_MMDC_DEBUG_37 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT14, 0x0660, 0x0290, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT14__CHEETAH_TRACE_11 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT15, 0x0664, 0x0294, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT15__IPU1_CSI0_D_15 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT15, 0x0664, 0x0294, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT15__WEIM_WEIM_D_11 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT15, 0x0664, 0x0294, 2, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT15__PCIE_CTRL_MUX_19 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT15, 0x0664, 0x0294, 3, 0x0940, 3), /* MX6Q_PAD_CSI0_DAT15__UART5_RXD */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT15, 0x0664, 0x0294, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT15__SDMA_DEBUG_PC_9 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT15, 0x0664, 0x0294, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT15__GPIO_6_1 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT15, 0x0664, 0x0294, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT15__MMDC_MMDC_DEBUG_38 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT15, 0x0664, 0x0294, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT15__CHEETAH_TRACE_12 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT16, 0x0668, 0x0298, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT16__IPU1_CSI0_D_16 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT16, 0x0668, 0x0298, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT16__WEIM_WEIM_D_12 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT16, 0x0668, 0x0298, 2, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT16__PCIE_CTRL_MUX_20 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT16, 0x0668, 0x0298, 3, 0x0934, 0), /* MX6Q_PAD_CSI0_DAT16__UART4_RTS */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT16, 0x0668, 0x0298, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT16__SDMA_DEBUG_PC_10 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT16, 0x0668, 0x0298, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT16__GPIO_6_2 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT16, 0x0668, 0x0298, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT16__MMDC_MMDC_DEBUG_39 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT16, 0x0668, 0x0298, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT16__CHEETAH_TRACE_13 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT17, 0x066C, 0x029C, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT17__IPU1_CSI0_D_17 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT17, 0x066C, 0x029C, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT17__WEIM_WEIM_D_13 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT17, 0x066C, 0x029C, 2, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT17__PCIE_CTRL_MUX_21 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT17, 0x066C, 0x029C, 3, 0x0934, 1), /* MX6Q_PAD_CSI0_DAT17__UART4_CTS */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT17, 0x066C, 0x029C, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT17__SDMA_DEBUG_PC_11 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT17, 0x066C, 0x029C, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT17__GPIO_6_3 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT17, 0x066C, 0x029C, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT17__MMDC_MMDC_DEBUG_40 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT17, 0x066C, 0x029C, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT17__CHEETAH_TRACE_14 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT18, 0x0670, 0x02A0, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT18__IPU1_CSI0_D_18 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT18, 0x0670, 0x02A0, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT18__WEIM_WEIM_D_14 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT18, 0x0670, 0x02A0, 2, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT18__PCIE_CTRL_MUX_22 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT18, 0x0670, 0x02A0, 3, 0x093C, 2), /* MX6Q_PAD_CSI0_DAT18__UART5_RTS */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT18, 0x0670, 0x02A0, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT18__SDMA_DEBUG_PC_12 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT18, 0x0670, 0x02A0, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT18__GPIO_6_4 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT18, 0x0670, 0x02A0, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT18__MMDC_MMDC_DEBUG_41 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT18, 0x0670, 0x02A0, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT18__CHEETAH_TRACE_15 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT19, 0x0674, 0x02A4, 0, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT19__IPU1_CSI0_D_19 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT19, 0x0674, 0x02A4, 1, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT19__WEIM_WEIM_D_15 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT19, 0x0674, 0x02A4, 2, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT19__PCIE_CTRL_MUX_23 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT19, 0x0674, 0x02A4, 3, 0x093C, 3), /* MX6Q_PAD_CSI0_DAT19__UART5_CTS */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT19, 0x0674, 0x02A4, 4, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT19__SDMA_DEBUG_PC_13 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT19, 0x0674, 0x02A4, 5, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT19__GPIO_6_5 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT19, 0x0674, 0x02A4, 6, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT19__MMDC_MMDC_DEBUG_42 */ + IMX_PIN_REG(MX6Q_PAD_CSI0_DAT19, 0x0674, 0x02A4, 7, 0x0000, 0), /* MX6Q_PAD_CSI0_DAT19__ANATOP_TESTO_9 */ + IMX_PIN_REG(MX6Q_PAD_JTAG_TMS, 0x0678, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_JTAG_TMS__SJC_TMS */ + IMX_PIN_REG(MX6Q_PAD_JTAG_MOD, 0x067C, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_JTAG_MOD__SJC_MOD */ + IMX_PIN_REG(MX6Q_PAD_JTAG_TRSTB, 0x0680, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_JTAG_TRSTB__SJC_TRSTB */ + IMX_PIN_REG(MX6Q_PAD_JTAG_TDI, 0x0684, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_JTAG_TDI__SJC_TDI */ + IMX_PIN_REG(MX6Q_PAD_JTAG_TCK, 0x0688, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_JTAG_TCK__SJC_TCK */ + IMX_PIN_REG(MX6Q_PAD_JTAG_TDO, 0x068C, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_JTAG_TDO__SJC_TDO */ + IMX_PIN_REG(MX6Q_PAD_LVDS1_TX3_P, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_LVDS1_TX3_P__LDB_LVDS1_TX3 */ + IMX_PIN_REG(MX6Q_PAD_LVDS1_TX2_P, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_LVDS1_TX2_P__LDB_LVDS1_TX2 */ + IMX_PIN_REG(MX6Q_PAD_LVDS1_CLK_P, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_LVDS1_CLK_P__LDB_LVDS1_CLK */ + IMX_PIN_REG(MX6Q_PAD_LVDS1_TX1_P, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_LVDS1_TX1_P__LDB_LVDS1_TX1 */ + IMX_PIN_REG(MX6Q_PAD_LVDS1_TX0_P, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_LVDS1_TX0_P__LDB_LVDS1_TX0 */ + IMX_PIN_REG(MX6Q_PAD_LVDS0_TX3_P, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_LVDS0_TX3_P__LDB_LVDS0_TX3 */ + IMX_PIN_REG(MX6Q_PAD_LVDS0_CLK_P, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_LVDS0_CLK_P__LDB_LVDS0_CLK */ + IMX_PIN_REG(MX6Q_PAD_LVDS0_TX2_P, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_LVDS0_TX2_P__LDB_LVDS0_TX2 */ + IMX_PIN_REG(MX6Q_PAD_LVDS0_TX1_P, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_LVDS0_TX1_P__LDB_LVDS0_TX1 */ + IMX_PIN_REG(MX6Q_PAD_LVDS0_TX0_P, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_LVDS0_TX0_P__LDB_LVDS0_TX0 */ + IMX_PIN_REG(MX6Q_PAD_TAMPER, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_TAMPER__SNVS_LP_WRAP_SNVS_TD1 */ + IMX_PIN_REG(MX6Q_PAD_PMIC_ON_REQ, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_PMIC_ON_REQ__SNVS_LPWRAP_WKALM */ + IMX_PIN_REG(MX6Q_PAD_PMIC_STBY_REQ, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_PMIC_STBY_REQ__CCM_PMIC_STBYRQ */ + IMX_PIN_REG(MX6Q_PAD_POR_B, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_POR_B__SRC_POR_B */ + IMX_PIN_REG(MX6Q_PAD_BOOT_MODE1, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_BOOT_MODE1__SRC_BOOT_MODE_1 */ + IMX_PIN_REG(MX6Q_PAD_RESET_IN_B, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_RESET_IN_B__SRC_RESET_B */ + IMX_PIN_REG(MX6Q_PAD_BOOT_MODE0, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_BOOT_MODE0__SRC_BOOT_MODE_0 */ + IMX_PIN_REG(MX6Q_PAD_TEST_MODE, NO_PAD, NO_MUX, 0, 0x0000, 0), /* MX6Q_PAD_TEST_MODE__TCU_TEST_MODE */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT7, 0x0690, 0x02A8, 0, 0x0000, 0), /* MX6Q_PAD_SD3_DAT7__USDHC3_DAT7 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT7, 0x0690, 0x02A8, 1, 0x0000, 0), /* MX6Q_PAD_SD3_DAT7__UART1_TXD */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT7, 0x0690, 0x02A8, 2, 0x0000, 0), /* MX6Q_PAD_SD3_DAT7__PCIE_CTRL_MUX_24 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT7, 0x0690, 0x02A8, 3, 0x0000, 0), /* MX6Q_PAD_SD3_DAT7__USBOH3_UH3_DFD_OUT_0 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT7, 0x0690, 0x02A8, 4, 0x0000, 0), /* MX6Q_PAD_SD3_DAT7__USBOH3_UH2_DFD_OUT_0 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT7, 0x0690, 0x02A8, 5, 0x0000, 0), /* MX6Q_PAD_SD3_DAT7__GPIO_6_17 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT7, 0x0690, 0x02A8, 6, 0x0000, 0), /* MX6Q_PAD_SD3_DAT7__MIPI_CORE_DPHY_IN_12 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT7, 0x0690, 0x02A8, 7, 0x0000, 0), /* MX6Q_PAD_SD3_DAT7__USBPHY2_CLK20DIV */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT6, 0x0694, 0x02AC, 0, 0x0000, 0), /* MX6Q_PAD_SD3_DAT6__USDHC3_DAT6 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT6, 0x0694, 0x02AC, 1, 0x0920, 3), /* MX6Q_PAD_SD3_DAT6__UART1_RXD */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT6, 0x0694, 0x02AC, 2, 0x0000, 0), /* MX6Q_PAD_SD3_DAT6__PCIE_CTRL_MUX_25 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT6, 0x0694, 0x02AC, 3, 0x0000, 0), /* MX6Q_PAD_SD3_DAT6__USBOH3_UH3_DFD_OUT_1 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT6, 0x0694, 0x02AC, 4, 0x0000, 0), /* MX6Q_PAD_SD3_DAT6__USBOH3_UH2_DFD_OUT_1 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT6, 0x0694, 0x02AC, 5, 0x0000, 0), /* MX6Q_PAD_SD3_DAT6__GPIO_6_18 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT6, 0x0694, 0x02AC, 6, 0x0000, 0), /* MX6Q_PAD_SD3_DAT6__MIPI_CORE_DPHY_IN_13 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT6, 0x0694, 0x02AC, 7, 0x0000, 0), /* MX6Q_PAD_SD3_DAT6__ANATOP_TESTO_10 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT5, 0x0698, 0x02B0, 0, 0x0000, 0), /* MX6Q_PAD_SD3_DAT5__USDHC3_DAT5 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT5, 0x0698, 0x02B0, 1, 0x0000, 0), /* MX6Q_PAD_SD3_DAT5__UART2_TXD */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT5, 0x0698, 0x02B0, 2, 0x0000, 0), /* MX6Q_PAD_SD3_DAT5__PCIE_CTRL_MUX_26 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT5, 0x0698, 0x02B0, 3, 0x0000, 0), /* MX6Q_PAD_SD3_DAT5__USBOH3_UH3_DFD_OUT_2 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT5, 0x0698, 0x02B0, 4, 0x0000, 0), /* MX6Q_PAD_SD3_DAT5__USBOH3_UH2_DFD_OUT_2 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT5, 0x0698, 0x02B0, 5, 0x0000, 0), /* MX6Q_PAD_SD3_DAT5__GPIO_7_0 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT5, 0x0698, 0x02B0, 6, 0x0000, 0), /* MX6Q_PAD_SD3_DAT5__MIPI_CORE_DPHY_IN_14 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT5, 0x0698, 0x02B0, 7, 0x0000, 0), /* MX6Q_PAD_SD3_DAT5__ANATOP_TESTO_11 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT4, 0x069C, 0x02B4, 0, 0x0000, 0), /* MX6Q_PAD_SD3_DAT4__USDHC3_DAT4 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT4, 0x069C, 0x02B4, 1, 0x0928, 5), /* MX6Q_PAD_SD3_DAT4__UART2_RXD */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT4, 0x069C, 0x02B4, 2, 0x0000, 0), /* MX6Q_PAD_SD3_DAT4__PCIE_CTRL_MUX_27 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT4, 0x069C, 0x02B4, 3, 0x0000, 0), /* MX6Q_PAD_SD3_DAT4__USBOH3_UH3_DFD_OUT_3 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT4, 0x069C, 0x02B4, 4, 0x0000, 0), /* MX6Q_PAD_SD3_DAT4__USBOH3_UH2_DFD_OUT_3 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT4, 0x069C, 0x02B4, 5, 0x0000, 0), /* MX6Q_PAD_SD3_DAT4__GPIO_7_1 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT4, 0x069C, 0x02B4, 6, 0x0000, 0), /* MX6Q_PAD_SD3_DAT4__MIPI_CORE_DPHY_IN_15 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT4, 0x069C, 0x02B4, 7, 0x0000, 0), /* MX6Q_PAD_SD3_DAT4__ANATOP_TESTO_12 */ + IMX_PIN_REG(MX6Q_PAD_SD3_CMD, 0x06A0, 0x02B8, 0, 0x0000, 0), /* MX6Q_PAD_SD3_CMD__USDHC3_CMD */ + IMX_PIN_REG(MX6Q_PAD_SD3_CMD, 0x06A0, 0x02B8, 1, 0x0924, 2), /* MX6Q_PAD_SD3_CMD__UART2_CTS */ + IMX_PIN_REG(MX6Q_PAD_SD3_CMD, 0x06A0, 0x02B8, 2, 0x0000, 0), /* MX6Q_PAD_SD3_CMD__CAN1_TXCAN */ + IMX_PIN_REG(MX6Q_PAD_SD3_CMD, 0x06A0, 0x02B8, 3, 0x0000, 0), /* MX6Q_PAD_SD3_CMD__USBOH3_UH3_DFD_OUT_4 */ + IMX_PIN_REG(MX6Q_PAD_SD3_CMD, 0x06A0, 0x02B8, 4, 0x0000, 0), /* MX6Q_PAD_SD3_CMD__USBOH3_UH2_DFD_OUT_4 */ + IMX_PIN_REG(MX6Q_PAD_SD3_CMD, 0x06A0, 0x02B8, 5, 0x0000, 0), /* MX6Q_PAD_SD3_CMD__GPIO_7_2 */ + IMX_PIN_REG(MX6Q_PAD_SD3_CMD, 0x06A0, 0x02B8, 6, 0x0000, 0), /* MX6Q_PAD_SD3_CMD__MIPI_CORE_DPHY_IN_16 */ + IMX_PIN_REG(MX6Q_PAD_SD3_CMD, 0x06A0, 0x02B8, 7, 0x0000, 0), /* MX6Q_PAD_SD3_CMD__ANATOP_TESTO_13 */ + IMX_PIN_REG(MX6Q_PAD_SD3_CLK, 0x06A4, 0x02BC, 0, 0x0000, 0), /* MX6Q_PAD_SD3_CLK__USDHC3_CLK */ + IMX_PIN_REG(MX6Q_PAD_SD3_CLK, 0x06A4, 0x02BC, 1, 0x0924, 3), /* MX6Q_PAD_SD3_CLK__UART2_RTS */ + IMX_PIN_REG(MX6Q_PAD_SD3_CLK, 0x06A4, 0x02BC, 2, 0x07E4, 2), /* MX6Q_PAD_SD3_CLK__CAN1_RXCAN */ + IMX_PIN_REG(MX6Q_PAD_SD3_CLK, 0x06A4, 0x02BC, 3, 0x0000, 0), /* MX6Q_PAD_SD3_CLK__USBOH3_UH3_DFD_OUT_5 */ + IMX_PIN_REG(MX6Q_PAD_SD3_CLK, 0x06A4, 0x02BC, 4, 0x0000, 0), /* MX6Q_PAD_SD3_CLK__USBOH3_UH2_DFD_OUT_5 */ + IMX_PIN_REG(MX6Q_PAD_SD3_CLK, 0x06A4, 0x02BC, 5, 0x0000, 0), /* MX6Q_PAD_SD3_CLK__GPIO_7_3 */ + IMX_PIN_REG(MX6Q_PAD_SD3_CLK, 0x06A4, 0x02BC, 6, 0x0000, 0), /* MX6Q_PAD_SD3_CLK__MIPI_CORE_DPHY_IN_17 */ + IMX_PIN_REG(MX6Q_PAD_SD3_CLK, 0x06A4, 0x02BC, 7, 0x0000, 0), /* MX6Q_PAD_SD3_CLK__ANATOP_TESTO_14 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT0, 0x06A8, 0x02C0, 0, 0x0000, 0), /* MX6Q_PAD_SD3_DAT0__USDHC3_DAT0 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT0, 0x06A8, 0x02C0, 1, 0x091C, 2), /* MX6Q_PAD_SD3_DAT0__UART1_CTS */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT0, 0x06A8, 0x02C0, 2, 0x0000, 0), /* MX6Q_PAD_SD3_DAT0__CAN2_TXCAN */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT0, 0x06A8, 0x02C0, 3, 0x0000, 0), /* MX6Q_PAD_SD3_DAT0__USBOH3_UH3_DFD_OUT_6 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT0, 0x06A8, 0x02C0, 4, 0x0000, 0), /* MX6Q_PAD_SD3_DAT0__USBOH3_UH2_DFD_OUT_6 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT0, 0x06A8, 0x02C0, 5, 0x0000, 0), /* MX6Q_PAD_SD3_DAT0__GPIO_7_4 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT0, 0x06A8, 0x02C0, 6, 0x0000, 0), /* MX6Q_PAD_SD3_DAT0__MIPI_CORE_DPHY_IN_18 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT0, 0x06A8, 0x02C0, 7, 0x0000, 0), /* MX6Q_PAD_SD3_DAT0__ANATOP_TESTO_15 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT1, 0x06AC, 0x02C4, 0, 0x0000, 0), /* MX6Q_PAD_SD3_DAT1__USDHC3_DAT1 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT1, 0x06AC, 0x02C4, 1, 0x091C, 3), /* MX6Q_PAD_SD3_DAT1__UART1_RTS */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT1, 0x06AC, 0x02C4, 2, 0x07E8, 1), /* MX6Q_PAD_SD3_DAT1__CAN2_RXCAN */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT1, 0x06AC, 0x02C4, 3, 0x0000, 0), /* MX6Q_PAD_SD3_DAT1__USBOH3_UH3_DFD_OUT_7 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT1, 0x06AC, 0x02C4, 4, 0x0000, 0), /* MX6Q_PAD_SD3_DAT1__USBOH3_UH2_DFD_OUT_7 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT1, 0x06AC, 0x02C4, 5, 0x0000, 0), /* MX6Q_PAD_SD3_DAT1__GPIO_7_5 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT1, 0x06AC, 0x02C4, 6, 0x0000, 0), /* MX6Q_PAD_SD3_DAT1__MIPI_CORE_DPHY_IN_19 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT1, 0x06AC, 0x02C4, 7, 0x0000, 0), /* MX6Q_PAD_SD3_DAT1__ANATOP_TESTI_0 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT2, 0x06B0, 0x02C8, 0, 0x0000, 0), /* MX6Q_PAD_SD3_DAT2__USDHC3_DAT2 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT2, 0x06B0, 0x02C8, 2, 0x0000, 0), /* MX6Q_PAD_SD3_DAT2__PCIE_CTRL_MUX_28 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT2, 0x06B0, 0x02C8, 3, 0x0000, 0), /* MX6Q_PAD_SD3_DAT2__USBOH3_UH3_DFD_OUT_8 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT2, 0x06B0, 0x02C8, 4, 0x0000, 0), /* MX6Q_PAD_SD3_DAT2__USBOH3_UH2_DFD_OUT_8 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT2, 0x06B0, 0x02C8, 5, 0x0000, 0), /* MX6Q_PAD_SD3_DAT2__GPIO_7_6 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT2, 0x06B0, 0x02C8, 6, 0x0000, 0), /* MX6Q_PAD_SD3_DAT2__MIPI_CORE_DPHY_IN_20 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT2, 0x06B0, 0x02C8, 7, 0x0000, 0), /* MX6Q_PAD_SD3_DAT2__ANATOP_TESTI_1 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT3, 0x06B4, 0x02CC, 0, 0x0000, 0), /* MX6Q_PAD_SD3_DAT3__USDHC3_DAT3 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT3, 0x06B4, 0x02CC, 1, 0x092C, 4), /* MX6Q_PAD_SD3_DAT3__UART3_CTS */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT3, 0x06B4, 0x02CC, 2, 0x0000, 0), /* MX6Q_PAD_SD3_DAT3__PCIE_CTRL_MUX_29 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT3, 0x06B4, 0x02CC, 3, 0x0000, 0), /* MX6Q_PAD_SD3_DAT3__USBOH3_UH3_DFD_OUT_9 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT3, 0x06B4, 0x02CC, 4, 0x0000, 0), /* MX6Q_PAD_SD3_DAT3__USBOH3_UH2_DFD_OUT_9 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT3, 0x06B4, 0x02CC, 5, 0x0000, 0), /* MX6Q_PAD_SD3_DAT3__GPIO_7_7 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT3, 0x06B4, 0x02CC, 6, 0x0000, 0), /* MX6Q_PAD_SD3_DAT3__MIPI_CORE_DPHY_IN_21 */ + IMX_PIN_REG(MX6Q_PAD_SD3_DAT3, 0x06B4, 0x02CC, 7, 0x0000, 0), /* MX6Q_PAD_SD3_DAT3__ANATOP_TESTI_2 */ + IMX_PIN_REG(MX6Q_PAD_SD3_RST, 0x06B8, 0x02D0, 0, 0x0000, 0), /* MX6Q_PAD_SD3_RST__USDHC3_RST */ + IMX_PIN_REG(MX6Q_PAD_SD3_RST, 0x06B8, 0x02D0, 1, 0x092C, 5), /* MX6Q_PAD_SD3_RST__UART3_RTS */ + IMX_PIN_REG(MX6Q_PAD_SD3_RST, 0x06B8, 0x02D0, 2, 0x0000, 0), /* MX6Q_PAD_SD3_RST__PCIE_CTRL_MUX_30 */ + IMX_PIN_REG(MX6Q_PAD_SD3_RST, 0x06B8, 0x02D0, 3, 0x0000, 0), /* MX6Q_PAD_SD3_RST__USBOH3_UH3_DFD_OUT_10 */ + IMX_PIN_REG(MX6Q_PAD_SD3_RST, 0x06B8, 0x02D0, 4, 0x0000, 0), /* MX6Q_PAD_SD3_RST__USBOH3_UH2_DFD_OUT_10 */ + IMX_PIN_REG(MX6Q_PAD_SD3_RST, 0x06B8, 0x02D0, 5, 0x0000, 0), /* MX6Q_PAD_SD3_RST__GPIO_7_8 */ + IMX_PIN_REG(MX6Q_PAD_SD3_RST, 0x06B8, 0x02D0, 6, 0x0000, 0), /* MX6Q_PAD_SD3_RST__MIPI_CORE_DPHY_IN_22 */ + IMX_PIN_REG(MX6Q_PAD_SD3_RST, 0x06B8, 0x02D0, 7, 0x0000, 0), /* MX6Q_PAD_SD3_RST__ANATOP_ANATOP_TESTI_3 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CLE, 0x06BC, 0x02D4, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_CLE__RAWNAND_CLE */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CLE, 0x06BC, 0x02D4, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_CLE__IPU2_SISG_4 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CLE, 0x06BC, 0x02D4, 2, 0x0000, 0), /* MX6Q_PAD_NANDF_CLE__PCIE_CTRL_MUX_31 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CLE, 0x06BC, 0x02D4, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_CLE__USBOH3_UH3_DFD_OT11 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CLE, 0x06BC, 0x02D4, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_CLE__USBOH3_UH2_DFD_OT11 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CLE, 0x06BC, 0x02D4, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_CLE__GPIO_6_7 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CLE, 0x06BC, 0x02D4, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_CLE__MIPI_CORE_DPHY_IN23 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CLE, 0x06BC, 0x02D4, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_CLE__TPSMP_HTRANS_0 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_ALE, 0x06C0, 0x02D8, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_ALE__RAWNAND_ALE */ + IMX_PIN_REG(MX6Q_PAD_NANDF_ALE, 0x06C0, 0x02D8, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_ALE__USDHC4_RST */ + IMX_PIN_REG(MX6Q_PAD_NANDF_ALE, 0x06C0, 0x02D8, 2, 0x0000, 0), /* MX6Q_PAD_NANDF_ALE__PCIE_CTRL_MUX_0 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_ALE, 0x06C0, 0x02D8, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_ALE__USBOH3_UH3_DFD_OT12 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_ALE, 0x06C0, 0x02D8, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_ALE__USBOH3_UH2_DFD_OT12 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_ALE, 0x06C0, 0x02D8, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_ALE__GPIO_6_8 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_ALE, 0x06C0, 0x02D8, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_ALE__MIPI_CR_DPHY_IN_24 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_ALE, 0x06C0, 0x02D8, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_ALE__TPSMP_HTRANS_1 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_WP_B, 0x06C4, 0x02DC, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_WP_B__RAWNAND_RESETN */ + IMX_PIN_REG(MX6Q_PAD_NANDF_WP_B, 0x06C4, 0x02DC, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_WP_B__IPU2_SISG_5 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_WP_B, 0x06C4, 0x02DC, 2, 0x0000, 0), /* MX6Q_PAD_NANDF_WP_B__PCIE_CTRL__MUX_1 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_WP_B, 0x06C4, 0x02DC, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_WP_B__USBOH3_UH3_DFDOT13 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_WP_B, 0x06C4, 0x02DC, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_WP_B__USBOH3_UH2_DFDOT13 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_WP_B, 0x06C4, 0x02DC, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_WP_B__GPIO_6_9 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_WP_B, 0x06C4, 0x02DC, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_WP_B__MIPI_CR_DPHY_OUT32 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_WP_B, 0x06C4, 0x02DC, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_WP_B__PL301_PER1_HSIZE_0 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_RB0, 0x06C8, 0x02E0, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_RB0__RAWNAND_READY0 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_RB0, 0x06C8, 0x02E0, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_RB0__IPU2_DI0_PIN1 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_RB0, 0x06C8, 0x02E0, 2, 0x0000, 0), /* MX6Q_PAD_NANDF_RB0__PCIE_CTRL_MUX_2 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_RB0, 0x06C8, 0x02E0, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_RB0__USBOH3_UH3_DFD_OT14 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_RB0, 0x06C8, 0x02E0, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_RB0__USBOH3_UH2_DFD_OT14 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_RB0, 0x06C8, 0x02E0, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_RB0__GPIO_6_10 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_RB0, 0x06C8, 0x02E0, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_RB0__MIPI_CR_DPHY_OUT_33 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_RB0, 0x06C8, 0x02E0, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_RB0__PL301_PER1_HSIZE_1 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CS0, 0x06CC, 0x02E4, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_CS0__RAWNAND_CE0N */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CS0, 0x06CC, 0x02E4, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_CS0__USBOH3_UH3_DFD_OT15 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CS0, 0x06CC, 0x02E4, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_CS0__USBOH3_UH2_DFD_OT15 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CS0, 0x06CC, 0x02E4, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_CS0__GPIO_6_11 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CS0, 0x06CC, 0x02E4, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_CS0__PL301_PER1_HSIZE_2 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CS1, 0x06D0, 0x02E8, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_CS1__RAWNAND_CE1N */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CS1, 0x06D0, 0x02E8, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_CS1__USDHC4_VSELECT */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CS1, 0x06D0, 0x02E8, 2, 0x0000, 0), /* MX6Q_PAD_NANDF_CS1__USDHC3_VSELECT */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CS1, 0x06D0, 0x02E8, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_CS1__PCIE_CTRL_MUX_3 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CS1, 0x06D0, 0x02E8, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_CS1__GPIO_6_14 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CS1, 0x06D0, 0x02E8, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_CS1__PL301_PER1_HRDYOUT */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CS2, 0x06D4, 0x02EC, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_CS2__RAWNAND_CE2N */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CS2, 0x06D4, 0x02EC, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_CS2__IPU1_SISG_0 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CS2, 0x06D4, 0x02EC, 2, 0x0874, 1), /* MX6Q_PAD_NANDF_CS2__ESAI1_TX0 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CS2, 0x06D4, 0x02EC, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_CS2__WEIM_WEIM_CRE */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CS2, 0x06D4, 0x02EC, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_CS2__CCM_CLKO2 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CS2, 0x06D4, 0x02EC, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_CS2__GPIO_6_15 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CS2, 0x06D4, 0x02EC, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_CS2__IPU2_SISG_0 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CS3, 0x06D8, 0x02F0, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_CS3__RAWNAND_CE3N */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CS3, 0x06D8, 0x02F0, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_CS3__IPU1_SISG_1 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CS3, 0x06D8, 0x02F0, 2, 0x0878, 1), /* MX6Q_PAD_NANDF_CS3__ESAI1_TX1 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CS3, 0x06D8, 0x02F0, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_CS3__WEIM_WEIM_A_26 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CS3, 0x06D8, 0x02F0, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_CS3__PCIE_CTRL_MUX_4 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CS3, 0x06D8, 0x02F0, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_CS3__GPIO_6_16 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CS3, 0x06D8, 0x02F0, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_CS3__IPU2_SISG_1 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_CS3, 0x06D8, 0x02F0, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_CS3__TPSMP_CLK */ + IMX_PIN_REG(MX6Q_PAD_SD4_CMD, 0x06DC, 0x02F4, 0, 0x0000, 0), /* MX6Q_PAD_SD4_CMD__USDHC4_CMD */ + IMX_PIN_REG(MX6Q_PAD_SD4_CMD, 0x06DC, 0x02F4, 1, 0x0000, 0), /* MX6Q_PAD_SD4_CMD__RAWNAND_RDN */ + IMX_PIN_REG(MX6Q_PAD_SD4_CMD, 0x06DC, 0x02F4, 2, 0x0000, 0), /* MX6Q_PAD_SD4_CMD__UART3_TXD */ + IMX_PIN_REG(MX6Q_PAD_SD4_CMD, 0x06DC, 0x02F4, 4, 0x0000, 0), /* MX6Q_PAD_SD4_CMD__PCIE_CTRL_MUX_5 */ + IMX_PIN_REG(MX6Q_PAD_SD4_CMD, 0x06DC, 0x02F4, 5, 0x0000, 0), /* MX6Q_PAD_SD4_CMD__GPIO_7_9 */ + IMX_PIN_REG(MX6Q_PAD_SD4_CMD, 0x06DC, 0x02F4, 7, 0x0000, 0), /* MX6Q_PAD_SD4_CMD__TPSMP_HDATA_DIR */ + IMX_PIN_REG(MX6Q_PAD_SD4_CLK, 0x06E0, 0x02F8, 0, 0x0000, 0), /* MX6Q_PAD_SD4_CLK__USDHC4_CLK */ + IMX_PIN_REG(MX6Q_PAD_SD4_CLK, 0x06E0, 0x02F8, 1, 0x0000, 0), /* MX6Q_PAD_SD4_CLK__RAWNAND_WRN */ + IMX_PIN_REG(MX6Q_PAD_SD4_CLK, 0x06E0, 0x02F8, 2, 0x0930, 3), /* MX6Q_PAD_SD4_CLK__UART3_RXD */ + IMX_PIN_REG(MX6Q_PAD_SD4_CLK, 0x06E0, 0x02F8, 4, 0x0000, 0), /* MX6Q_PAD_SD4_CLK__PCIE_CTRL_MUX_6 */ + IMX_PIN_REG(MX6Q_PAD_SD4_CLK, 0x06E0, 0x02F8, 5, 0x0000, 0), /* MX6Q_PAD_SD4_CLK__GPIO_7_10 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D0, 0x06E4, 0x02FC, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_D0__RAWNAND_D0 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D0, 0x06E4, 0x02FC, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_D0__USDHC1_DAT4 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D0, 0x06E4, 0x02FC, 2, 0x0000, 0), /* MX6Q_PAD_NANDF_D0__GPU3D_GPU_DBG_OUT_0 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D0, 0x06E4, 0x02FC, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_D0__USBOH3_UH2_DFD_OUT16 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D0, 0x06E4, 0x02FC, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_D0__USBOH3_UH3_DFD_OUT16 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D0, 0x06E4, 0x02FC, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_D0__GPIO_2_0 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D0, 0x06E4, 0x02FC, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_D0__IPU1_IPU_DIAG_BUS_0 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D0, 0x06E4, 0x02FC, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_D0__IPU2_IPU_DIAG_BUS_0 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D1, 0x06E8, 0x0300, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_D1__RAWNAND_D1 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D1, 0x06E8, 0x0300, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_D1__USDHC1_DAT5 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D1, 0x06E8, 0x0300, 2, 0x0000, 0), /* MX6Q_PAD_NANDF_D1__GPU3D_GPU_DEBUG_OUT1 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D1, 0x06E8, 0x0300, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_D1__USBOH3_UH2_DFD_OUT17 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D1, 0x06E8, 0x0300, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_D1__USBOH3_UH3_DFD_OUT17 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D1, 0x06E8, 0x0300, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_D1__GPIO_2_1 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D1, 0x06E8, 0x0300, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_D1__IPU1_IPU_DIAG_BUS_1 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D1, 0x06E8, 0x0300, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_D1__IPU2_IPU_DIAG_BUS_1 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D2, 0x06EC, 0x0304, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_D2__RAWNAND_D2 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D2, 0x06EC, 0x0304, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_D2__USDHC1_DAT6 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D2, 0x06EC, 0x0304, 2, 0x0000, 0), /* MX6Q_PAD_NANDF_D2__GPU3D_GPU_DBG_OUT_2 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D2, 0x06EC, 0x0304, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_D2__USBOH3_UH2_DFD_OUT18 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D2, 0x06EC, 0x0304, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_D2__USBOH3_UH3_DFD_OUT18 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D2, 0x06EC, 0x0304, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_D2__GPIO_2_2 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D2, 0x06EC, 0x0304, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_D2__IPU1_IPU_DIAG_BUS_2 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D2, 0x06EC, 0x0304, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_D2__IPU2_IPU_DIAG_BUS_2 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D3, 0x06F0, 0x0308, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_D3__RAWNAND_D3 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D3, 0x06F0, 0x0308, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_D3__USDHC1_DAT7 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D3, 0x06F0, 0x0308, 2, 0x0000, 0), /* MX6Q_PAD_NANDF_D3__GPU3D_GPU_DBG_OUT_3 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D3, 0x06F0, 0x0308, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_D3__USBOH3_UH2_DFD_OUT19 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D3, 0x06F0, 0x0308, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_D3__USBOH3_UH3_DFD_OUT19 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D3, 0x06F0, 0x0308, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_D3__GPIO_2_3 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D3, 0x06F0, 0x0308, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_D3__IPU1_IPU_DIAG_BUS_3 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D3, 0x06F0, 0x0308, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_D3__IPU2_IPU_DIAG_BUS_3 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D4, 0x06F4, 0x030C, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_D4__RAWNAND_D4 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D4, 0x06F4, 0x030C, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_D4__USDHC2_DAT4 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D4, 0x06F4, 0x030C, 2, 0x0000, 0), /* MX6Q_PAD_NANDF_D4__GPU3D_GPU_DBG_OUT_4 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D4, 0x06F4, 0x030C, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_D4__USBOH3_UH2_DFD_OUT20 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D4, 0x06F4, 0x030C, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_D4__USBOH3_UH3_DFD_OUT20 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D4, 0x06F4, 0x030C, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_D4__GPIO_2_4 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D4, 0x06F4, 0x030C, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_D4__IPU1_IPU_DIAG_BUS_4 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D4, 0x06F4, 0x030C, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_D4__IPU2_IPU_DIAG_BUS_4 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D5, 0x06F8, 0x0310, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_D5__RAWNAND_D5 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D5, 0x06F8, 0x0310, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_D5__USDHC2_DAT5 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D5, 0x06F8, 0x0310, 2, 0x0000, 0), /* MX6Q_PAD_NANDF_D5__GPU3D_GPU_DBG_OUT_5 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D5, 0x06F8, 0x0310, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_D5__USBOH3_UH2_DFD_OUT21 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D5, 0x06F8, 0x0310, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_D5__USBOH3_UH3_DFD_OUT21 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D5, 0x06F8, 0x0310, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_D5__GPIO_2_5 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D5, 0x06F8, 0x0310, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_D5__IPU1_IPU_DIAG_BUS_5 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D5, 0x06F8, 0x0310, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_D5__IPU2_IPU_DIAG_BUS_5 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D6, 0x06FC, 0x0314, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_D6__RAWNAND_D6 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D6, 0x06FC, 0x0314, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_D6__USDHC2_DAT6 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D6, 0x06FC, 0x0314, 2, 0x0000, 0), /* MX6Q_PAD_NANDF_D6__GPU3D_GPU_DBG_OUT_6 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D6, 0x06FC, 0x0314, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_D6__USBOH3_UH2_DFD_OUT22 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D6, 0x06FC, 0x0314, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_D6__USBOH3_UH3_DFD_OUT22 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D6, 0x06FC, 0x0314, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_D6__GPIO_2_6 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D6, 0x06FC, 0x0314, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_D6__IPU1_IPU_DIAG_BUS_6 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D6, 0x06FC, 0x0314, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_D6__IPU2_IPU_DIAG_BUS_6 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D7, 0x0700, 0x0318, 0, 0x0000, 0), /* MX6Q_PAD_NANDF_D7__RAWNAND_D7 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D7, 0x0700, 0x0318, 1, 0x0000, 0), /* MX6Q_PAD_NANDF_D7__USDHC2_DAT7 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D7, 0x0700, 0x0318, 2, 0x0000, 0), /* MX6Q_PAD_NANDF_D7__GPU3D_GPU_DBG_OUT_7 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D7, 0x0700, 0x0318, 3, 0x0000, 0), /* MX6Q_PAD_NANDF_D7__USBOH3_UH2_DFD_OUT23 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D7, 0x0700, 0x0318, 4, 0x0000, 0), /* MX6Q_PAD_NANDF_D7__USBOH3_UH3_DFD_OUT23 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D7, 0x0700, 0x0318, 5, 0x0000, 0), /* MX6Q_PAD_NANDF_D7__GPIO_2_7 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D7, 0x0700, 0x0318, 6, 0x0000, 0), /* MX6Q_PAD_NANDF_D7__IPU1_IPU_DIAG_BUS_7 */ + IMX_PIN_REG(MX6Q_PAD_NANDF_D7, 0x0700, 0x0318, 7, 0x0000, 0), /* MX6Q_PAD_NANDF_D7__IPU2_IPU_DIAG_BUS_7 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT0, 0x0704, 0x031C, 0, 0x0000, 0), /* MX6Q_PAD_SD4_DAT0__RAWNAND_D8 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT0, 0x0704, 0x031C, 1, 0x0000, 0), /* MX6Q_PAD_SD4_DAT0__USDHC4_DAT0 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT0, 0x0704, 0x031C, 2, 0x0000, 0), /* MX6Q_PAD_SD4_DAT0__RAWNAND_DQS */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT0, 0x0704, 0x031C, 3, 0x0000, 0), /* MX6Q_PAD_SD4_DAT0__USBOH3_UH2_DFD_OUT24 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT0, 0x0704, 0x031C, 4, 0x0000, 0), /* MX6Q_PAD_SD4_DAT0__USBOH3_UH3_DFD_OUT24 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT0, 0x0704, 0x031C, 5, 0x0000, 0), /* MX6Q_PAD_SD4_DAT0__GPIO_2_8 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT0, 0x0704, 0x031C, 6, 0x0000, 0), /* MX6Q_PAD_SD4_DAT0__IPU1_IPU_DIAG_BUS_8 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT0, 0x0704, 0x031C, 7, 0x0000, 0), /* MX6Q_PAD_SD4_DAT0__IPU2_IPU_DIAG_BUS_8 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT1, 0x0708, 0x0320, 0, 0x0000, 0), /* MX6Q_PAD_SD4_DAT1__RAWNAND_D9 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT1, 0x0708, 0x0320, 1, 0x0000, 0), /* MX6Q_PAD_SD4_DAT1__USDHC4_DAT1 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT1, 0x0708, 0x0320, 2, 0x0000, 0), /* MX6Q_PAD_SD4_DAT1__PWM3_PWMO */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT1, 0x0708, 0x0320, 3, 0x0000, 0), /* MX6Q_PAD_SD4_DAT1__USBOH3_UH2_DFD_OUT25 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT1, 0x0708, 0x0320, 4, 0x0000, 0), /* MX6Q_PAD_SD4_DAT1__USBOH3_UH3_DFD_OUT25 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT1, 0x0708, 0x0320, 5, 0x0000, 0), /* MX6Q_PAD_SD4_DAT1__GPIO_2_9 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT1, 0x0708, 0x0320, 6, 0x0000, 0), /* MX6Q_PAD_SD4_DAT1__IPU1_IPU_DIAG_BUS_9 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT1, 0x0708, 0x0320, 7, 0x0000, 0), /* MX6Q_PAD_SD4_DAT1__IPU2_IPU_DIAG_BUS_9 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT2, 0x070C, 0x0324, 0, 0x0000, 0), /* MX6Q_PAD_SD4_DAT2__RAWNAND_D10 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT2, 0x070C, 0x0324, 1, 0x0000, 0), /* MX6Q_PAD_SD4_DAT2__USDHC4_DAT2 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT2, 0x070C, 0x0324, 2, 0x0000, 0), /* MX6Q_PAD_SD4_DAT2__PWM4_PWMO */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT2, 0x070C, 0x0324, 3, 0x0000, 0), /* MX6Q_PAD_SD4_DAT2__USBOH3_UH2_DFD_OUT26 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT2, 0x070C, 0x0324, 4, 0x0000, 0), /* MX6Q_PAD_SD4_DAT2__USBOH3_UH3_DFD_OUT26 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT2, 0x070C, 0x0324, 5, 0x0000, 0), /* MX6Q_PAD_SD4_DAT2__GPIO_2_10 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT2, 0x070C, 0x0324, 6, 0x0000, 0), /* MX6Q_PAD_SD4_DAT2__IPU1_IPU_DIAG_BUS_10 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT2, 0x070C, 0x0324, 7, 0x0000, 0), /* MX6Q_PAD_SD4_DAT2__IPU2_IPU_DIAG_BUS_10 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT3, 0x0710, 0x0328, 0, 0x0000, 0), /* MX6Q_PAD_SD4_DAT3__RAWNAND_D11 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT3, 0x0710, 0x0328, 1, 0x0000, 0), /* MX6Q_PAD_SD4_DAT3__USDHC4_DAT3 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT3, 0x0710, 0x0328, 3, 0x0000, 0), /* MX6Q_PAD_SD4_DAT3__USBOH3_UH2_DFD_OUT27 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT3, 0x0710, 0x0328, 4, 0x0000, 0), /* MX6Q_PAD_SD4_DAT3__USBOH3_UH3_DFD_OUT27 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT3, 0x0710, 0x0328, 5, 0x0000, 0), /* MX6Q_PAD_SD4_DAT3__GPIO_2_11 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT3, 0x0710, 0x0328, 6, 0x0000, 0), /* MX6Q_PAD_SD4_DAT3__IPU1_IPU_DIAG_BUS_11 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT3, 0x0710, 0x0328, 7, 0x0000, 0), /* MX6Q_PAD_SD4_DAT3__IPU2_IPU_DIAG_BUS_11 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT4, 0x0714, 0x032C, 0, 0x0000, 0), /* MX6Q_PAD_SD4_DAT4__RAWNAND_D12 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT4, 0x0714, 0x032C, 1, 0x0000, 0), /* MX6Q_PAD_SD4_DAT4__USDHC4_DAT4 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT4, 0x0714, 0x032C, 2, 0x0928, 6), /* MX6Q_PAD_SD4_DAT4__UART2_RXD */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT4, 0x0714, 0x032C, 3, 0x0000, 0), /* MX6Q_PAD_SD4_DAT4__USBOH3_UH2_DFD_OUT28 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT4, 0x0714, 0x032C, 4, 0x0000, 0), /* MX6Q_PAD_SD4_DAT4__USBOH3_UH3_DFD_OUT28 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT4, 0x0714, 0x032C, 5, 0x0000, 0), /* MX6Q_PAD_SD4_DAT4__GPIO_2_12 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT4, 0x0714, 0x032C, 6, 0x0000, 0), /* MX6Q_PAD_SD4_DAT4__IPU1_IPU_DIAG_BUS_12 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT4, 0x0714, 0x032C, 7, 0x0000, 0), /* MX6Q_PAD_SD4_DAT4__IPU2_IPU_DIAG_BUS_12 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT5, 0x0718, 0x0330, 0, 0x0000, 0), /* MX6Q_PAD_SD4_DAT5__RAWNAND_D13 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT5, 0x0718, 0x0330, 1, 0x0000, 0), /* MX6Q_PAD_SD4_DAT5__USDHC4_DAT5 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT5, 0x0718, 0x0330, 2, 0x0924, 4), /* MX6Q_PAD_SD4_DAT5__UART2_RTS */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT5, 0x0718, 0x0330, 3, 0x0000, 0), /* MX6Q_PAD_SD4_DAT5__USBOH3_UH2_DFD_OUT29 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT5, 0x0718, 0x0330, 4, 0x0000, 0), /* MX6Q_PAD_SD4_DAT5__USBOH3_UH3_DFD_OUT29 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT5, 0x0718, 0x0330, 5, 0x0000, 0), /* MX6Q_PAD_SD4_DAT5__GPIO_2_13 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT5, 0x0718, 0x0330, 6, 0x0000, 0), /* MX6Q_PAD_SD4_DAT5__IPU1_IPU_DIAG_BUS_13 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT5, 0x0718, 0x0330, 7, 0x0000, 0), /* MX6Q_PAD_SD4_DAT5__IPU2_IPU_DIAG_BUS_13 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT6, 0x071C, 0x0334, 0, 0x0000, 0), /* MX6Q_PAD_SD4_DAT6__RAWNAND_D14 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT6, 0x071C, 0x0334, 1, 0x0000, 0), /* MX6Q_PAD_SD4_DAT6__USDHC4_DAT6 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT6, 0x071C, 0x0334, 2, 0x0924, 5), /* MX6Q_PAD_SD4_DAT6__UART2_CTS */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT6, 0x071C, 0x0334, 3, 0x0000, 0), /* MX6Q_PAD_SD4_DAT6__USBOH3_UH2_DFD_OUT30 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT6, 0x071C, 0x0334, 4, 0x0000, 0), /* MX6Q_PAD_SD4_DAT6__USBOH3_UH3_DFD_OUT30 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT6, 0x071C, 0x0334, 5, 0x0000, 0), /* MX6Q_PAD_SD4_DAT6__GPIO_2_14 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT6, 0x071C, 0x0334, 6, 0x0000, 0), /* MX6Q_PAD_SD4_DAT6__IPU1_IPU_DIAG_BUS_14 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT6, 0x071C, 0x0334, 7, 0x0000, 0), /* MX6Q_PAD_SD4_DAT6__IPU2_IPU_DIAG_BUS_14 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT7, 0x0720, 0x0338, 0, 0x0000, 0), /* MX6Q_PAD_SD4_DAT7__RAWNAND_D15 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT7, 0x0720, 0x0338, 1, 0x0000, 0), /* MX6Q_PAD_SD4_DAT7__USDHC4_DAT7 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT7, 0x0720, 0x0338, 2, 0x0000, 0), /* MX6Q_PAD_SD4_DAT7__UART2_TXD */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT7, 0x0720, 0x0338, 3, 0x0000, 0), /* MX6Q_PAD_SD4_DAT7__USBOH3_UH2_DFD_OUT31 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT7, 0x0720, 0x0338, 4, 0x0000, 0), /* MX6Q_PAD_SD4_DAT7__USBOH3_UH3_DFD_OUT31 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT7, 0x0720, 0x0338, 5, 0x0000, 0), /* MX6Q_PAD_SD4_DAT7__GPIO_2_15 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT7, 0x0720, 0x0338, 6, 0x0000, 0), /* MX6Q_PAD_SD4_DAT7__IPU1_IPU_DIAG_BUS_15 */ + IMX_PIN_REG(MX6Q_PAD_SD4_DAT7, 0x0720, 0x0338, 7, 0x0000, 0), /* MX6Q_PAD_SD4_DAT7__IPU2_IPU_DIAG_BUS_15 */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT1, 0x0724, 0x033C, 0, 0x0000, 0), /* MX6Q_PAD_SD1_DAT1__USDHC1_DAT1 */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT1, 0x0724, 0x033C, 1, 0x0834, 1), /* MX6Q_PAD_SD1_DAT1__ECSPI5_SS0 */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT1, 0x0724, 0x033C, 2, 0x0000, 0), /* MX6Q_PAD_SD1_DAT1__PWM3_PWMO */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT1, 0x0724, 0x033C, 3, 0x0000, 0), /* MX6Q_PAD_SD1_DAT1__GPT_CAPIN2 */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT1, 0x0724, 0x033C, 4, 0x0000, 0), /* MX6Q_PAD_SD1_DAT1__PCIE_CTRL_MUX_7 */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT1, 0x0724, 0x033C, 5, 0x0000, 0), /* MX6Q_PAD_SD1_DAT1__GPIO_1_17 */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT1, 0x0724, 0x033C, 6, 0x0000, 0), /* MX6Q_PAD_SD1_DAT1__HDMI_TX_OPHYDTB_0 */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT1, 0x0724, 0x033C, 7, 0x0000, 0), /* MX6Q_PAD_SD1_DAT1__ANATOP_TESTO_8 */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT0, 0x0728, 0x0340, 0, 0x0000, 0), /* MX6Q_PAD_SD1_DAT0__USDHC1_DAT0 */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT0, 0x0728, 0x0340, 1, 0x082C, 1), /* MX6Q_PAD_SD1_DAT0__ECSPI5_MISO */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT0, 0x0728, 0x0340, 2, 0x0000, 0), /* MX6Q_PAD_SD1_DAT0__CAAM_WRAP_RNG_OSCOBS */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT0, 0x0728, 0x0340, 3, 0x0000, 0), /* MX6Q_PAD_SD1_DAT0__GPT_CAPIN1 */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT0, 0x0728, 0x0340, 4, 0x0000, 0), /* MX6Q_PAD_SD1_DAT0__PCIE_CTRL_MUX_8 */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT0, 0x0728, 0x0340, 5, 0x0000, 0), /* MX6Q_PAD_SD1_DAT0__GPIO_1_16 */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT0, 0x0728, 0x0340, 6, 0x0000, 0), /* MX6Q_PAD_SD1_DAT0__HDMI_TX_OPHYDTB_1 */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT0, 0x0728, 0x0340, 7, 0x0000, 0), /* MX6Q_PAD_SD1_DAT0__ANATOP_TESTO_7 */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT3, 0x072C, 0x0344, 0, 0x0000, 0), /* MX6Q_PAD_SD1_DAT3__USDHC1_DAT3 */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT3, 0x072C, 0x0344, 1, 0x0000, 0), /* MX6Q_PAD_SD1_DAT3__ECSPI5_SS2 */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT3, 0x072C, 0x0344, 2, 0x0000, 0), /* MX6Q_PAD_SD1_DAT3__GPT_CMPOUT3 */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT3, 0x072C, 0x0344, 3, 0x0000, 0), /* MX6Q_PAD_SD1_DAT3__PWM1_PWMO */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT3, 0x072C, 0x0344, 4, 0x0000, 0), /* MX6Q_PAD_SD1_DAT3__WDOG2_WDOG_B */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT3, 0x072C, 0x0344, 5, 0x0000, 0), /* MX6Q_PAD_SD1_DAT3__GPIO_1_21 */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT3, 0x072C, 0x0344, 6, 0x0000, 0), /* MX6Q_PAD_SD1_DAT3__WDOG2_WDOG_RST_B_DEB */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT3, 0x072C, 0x0344, 7, 0x0000, 0), /* MX6Q_PAD_SD1_DAT3__ANATOP_TESTO_6 */ + IMX_PIN_REG(MX6Q_PAD_SD1_CMD, 0x0730, 0x0348, 0, 0x0000, 0), /* MX6Q_PAD_SD1_CMD__USDHC1_CMD */ + IMX_PIN_REG(MX6Q_PAD_SD1_CMD, 0x0730, 0x0348, 1, 0x0830, 0), /* MX6Q_PAD_SD1_CMD__ECSPI5_MOSI */ + IMX_PIN_REG(MX6Q_PAD_SD1_CMD, 0x0730, 0x0348, 2, 0x0000, 0), /* MX6Q_PAD_SD1_CMD__PWM4_PWMO */ + IMX_PIN_REG(MX6Q_PAD_SD1_CMD, 0x0730, 0x0348, 3, 0x0000, 0), /* MX6Q_PAD_SD1_CMD__GPT_CMPOUT1 */ + IMX_PIN_REG(MX6Q_PAD_SD1_CMD, 0x0730, 0x0348, 5, 0x0000, 0), /* MX6Q_PAD_SD1_CMD__GPIO_1_18 */ + IMX_PIN_REG(MX6Q_PAD_SD1_CMD, 0x0730, 0x0348, 7, 0x0000, 0), /* MX6Q_PAD_SD1_CMD__ANATOP_TESTO_5 */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT2, 0x0734, 0x034C, 0, 0x0000, 0), /* MX6Q_PAD_SD1_DAT2__USDHC1_DAT2 */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT2, 0x0734, 0x034C, 1, 0x0838, 1), /* MX6Q_PAD_SD1_DAT2__ECSPI5_SS1 */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT2, 0x0734, 0x034C, 2, 0x0000, 0), /* MX6Q_PAD_SD1_DAT2__GPT_CMPOUT2 */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT2, 0x0734, 0x034C, 3, 0x0000, 0), /* MX6Q_PAD_SD1_DAT2__PWM2_PWMO */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT2, 0x0734, 0x034C, 4, 0x0000, 0), /* MX6Q_PAD_SD1_DAT2__WDOG1_WDOG_B */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT2, 0x0734, 0x034C, 5, 0x0000, 0), /* MX6Q_PAD_SD1_DAT2__GPIO_1_19 */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT2, 0x0734, 0x034C, 6, 0x0000, 0), /* MX6Q_PAD_SD1_DAT2__WDOG1_WDOG_RST_B_DEB */ + IMX_PIN_REG(MX6Q_PAD_SD1_DAT2, 0x0734, 0x034C, 7, 0x0000, 0), /* MX6Q_PAD_SD1_DAT2__ANATOP_TESTO_4 */ + IMX_PIN_REG(MX6Q_PAD_SD1_CLK, 0x0738, 0x0350, 0, 0x0000, 0), /* MX6Q_PAD_SD1_CLK__USDHC1_CLK */ + IMX_PIN_REG(MX6Q_PAD_SD1_CLK, 0x0738, 0x0350, 1, 0x0828, 0), /* MX6Q_PAD_SD1_CLK__ECSPI5_SCLK */ + IMX_PIN_REG(MX6Q_PAD_SD1_CLK, 0x0738, 0x0350, 2, 0x0000, 0), /* MX6Q_PAD_SD1_CLK__OSC32K_32K_OUT */ + IMX_PIN_REG(MX6Q_PAD_SD1_CLK, 0x0738, 0x0350, 3, 0x0000, 0), /* MX6Q_PAD_SD1_CLK__GPT_CLKIN */ + IMX_PIN_REG(MX6Q_PAD_SD1_CLK, 0x0738, 0x0350, 5, 0x0000, 0), /* MX6Q_PAD_SD1_CLK__GPIO_1_20 */ + IMX_PIN_REG(MX6Q_PAD_SD1_CLK, 0x0738, 0x0350, 6, 0x0000, 0), /* MX6Q_PAD_SD1_CLK__PHY_DTB_0 */ + IMX_PIN_REG(MX6Q_PAD_SD1_CLK, 0x0738, 0x0350, 7, 0x0000, 0), /* MX6Q_PAD_SD1_CLK__SATA_PHY_DTB_0 */ + IMX_PIN_REG(MX6Q_PAD_SD2_CLK, 0x073C, 0x0354, 0, 0x0000, 0), /* MX6Q_PAD_SD2_CLK__USDHC2_CLK */ + IMX_PIN_REG(MX6Q_PAD_SD2_CLK, 0x073C, 0x0354, 1, 0x0828, 1), /* MX6Q_PAD_SD2_CLK__ECSPI5_SCLK */ + IMX_PIN_REG(MX6Q_PAD_SD2_CLK, 0x073C, 0x0354, 2, 0x08E8, 3), /* MX6Q_PAD_SD2_CLK__KPP_COL_5 */ + IMX_PIN_REG(MX6Q_PAD_SD2_CLK, 0x073C, 0x0354, 3, 0x07C0, 1), /* MX6Q_PAD_SD2_CLK__AUDMUX_AUD4_RXFS */ + IMX_PIN_REG(MX6Q_PAD_SD2_CLK, 0x073C, 0x0354, 4, 0x0000, 0), /* MX6Q_PAD_SD2_CLK__PCIE_CTRL_MUX_9 */ + IMX_PIN_REG(MX6Q_PAD_SD2_CLK, 0x073C, 0x0354, 5, 0x0000, 0), /* MX6Q_PAD_SD2_CLK__GPIO_1_10 */ + IMX_PIN_REG(MX6Q_PAD_SD2_CLK, 0x073C, 0x0354, 6, 0x0000, 0), /* MX6Q_PAD_SD2_CLK__PHY_DTB_1 */ + IMX_PIN_REG(MX6Q_PAD_SD2_CLK, 0x073C, 0x0354, 7, 0x0000, 0), /* MX6Q_PAD_SD2_CLK__SATA_PHY_DTB_1 */ + IMX_PIN_REG(MX6Q_PAD_SD2_CMD, 0x0740, 0x0358, 0, 0x0000, 0), /* MX6Q_PAD_SD2_CMD__USDHC2_CMD */ + IMX_PIN_REG(MX6Q_PAD_SD2_CMD, 0x0740, 0x0358, 1, 0x0830, 1), /* MX6Q_PAD_SD2_CMD__ECSPI5_MOSI */ + IMX_PIN_REG(MX6Q_PAD_SD2_CMD, 0x0740, 0x0358, 2, 0x08F4, 2), /* MX6Q_PAD_SD2_CMD__KPP_ROW_5 */ + IMX_PIN_REG(MX6Q_PAD_SD2_CMD, 0x0740, 0x0358, 3, 0x07BC, 1), /* MX6Q_PAD_SD2_CMD__AUDMUX_AUD4_RXC */ + IMX_PIN_REG(MX6Q_PAD_SD2_CMD, 0x0740, 0x0358, 4, 0x0000, 0), /* MX6Q_PAD_SD2_CMD__PCIE_CTRL_MUX_10 */ + IMX_PIN_REG(MX6Q_PAD_SD2_CMD, 0x0740, 0x0358, 5, 0x0000, 0), /* MX6Q_PAD_SD2_CMD__GPIO_1_11 */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT3, 0x0744, 0x035C, 0, 0x0000, 0), /* MX6Q_PAD_SD2_DAT3__USDHC2_DAT3 */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT3, 0x0744, 0x035C, 1, 0x0000, 0), /* MX6Q_PAD_SD2_DAT3__ECSPI5_SS3 */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT3, 0x0744, 0x035C, 2, 0x08EC, 2), /* MX6Q_PAD_SD2_DAT3__KPP_COL_6 */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT3, 0x0744, 0x035C, 3, 0x07C4, 1), /* MX6Q_PAD_SD2_DAT3__AUDMUX_AUD4_TXC */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT3, 0x0744, 0x035C, 4, 0x0000, 0), /* MX6Q_PAD_SD2_DAT3__PCIE_CTRL_MUX_11 */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT3, 0x0744, 0x035C, 5, 0x0000, 0), /* MX6Q_PAD_SD2_DAT3__GPIO_1_12 */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT3, 0x0744, 0x035C, 6, 0x0000, 0), /* MX6Q_PAD_SD2_DAT3__SJC_DONE */ + IMX_PIN_REG(MX6Q_PAD_SD2_DAT3, 0x0744, 0x035C, 7, 0x0000, 0), /* MX6Q_PAD_SD2_DAT3__ANATOP_TESTO_3 */ +}; + +/* Pad names for the pinmux subsystem */ +static const struct pinctrl_pin_desc imx6q_pinctrl_pads[] = { + IMX_PINCTRL_PIN(MX6Q_PAD_SD2_DAT1), + IMX_PINCTRL_PIN(MX6Q_PAD_SD2_DAT2), + IMX_PINCTRL_PIN(MX6Q_PAD_SD2_DAT0), + IMX_PINCTRL_PIN(MX6Q_PAD_RGMII_TXC), + IMX_PINCTRL_PIN(MX6Q_PAD_RGMII_TD0), + IMX_PINCTRL_PIN(MX6Q_PAD_RGMII_TD1), + IMX_PINCTRL_PIN(MX6Q_PAD_RGMII_TD2), + IMX_PINCTRL_PIN(MX6Q_PAD_RGMII_TD3), + IMX_PINCTRL_PIN(MX6Q_PAD_RGMII_RX_CTL), + IMX_PINCTRL_PIN(MX6Q_PAD_RGMII_RD0), + IMX_PINCTRL_PIN(MX6Q_PAD_RGMII_TX_CTL), + IMX_PINCTRL_PIN(MX6Q_PAD_RGMII_RD1), + IMX_PINCTRL_PIN(MX6Q_PAD_RGMII_RD2), + IMX_PINCTRL_PIN(MX6Q_PAD_RGMII_RD3), + IMX_PINCTRL_PIN(MX6Q_PAD_RGMII_RXC), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_A25), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_EB2), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D16), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D17), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D18), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D19), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D20), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D21), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D22), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D23), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_EB3), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D24), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D25), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D26), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D27), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D28), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D29), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D30), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_D31), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_A24), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_A23), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_A22), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_A21), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_A20), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_A19), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_A18), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_A17), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_A16), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_CS0), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_CS1), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_OE), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_RW), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_LBA), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_EB0), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_EB1), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA0), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA1), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA2), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA3), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA4), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA5), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA6), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA7), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA8), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA9), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA10), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA11), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA12), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA13), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA14), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_DA15), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_WAIT), + IMX_PINCTRL_PIN(MX6Q_PAD_EIM_BCLK), + IMX_PINCTRL_PIN(MX6Q_PAD_DI0_DISP_CLK), + IMX_PINCTRL_PIN(MX6Q_PAD_DI0_PIN15), + IMX_PINCTRL_PIN(MX6Q_PAD_DI0_PIN2), + IMX_PINCTRL_PIN(MX6Q_PAD_DI0_PIN3), + IMX_PINCTRL_PIN(MX6Q_PAD_DI0_PIN4), + IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT0), + IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT1), + IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT2), + IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT3), + IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT4), + IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT5), + IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT6), + IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT7), + IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT8), + IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT9), + IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT10), + IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT11), + IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT12), + IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT13), + IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT14), + IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT15), + IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT16), + IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT17), + IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT18), + IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT19), + IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT20), + IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT21), + IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT22), + IMX_PINCTRL_PIN(MX6Q_PAD_DISP0_DAT23), + IMX_PINCTRL_PIN(MX6Q_PAD_ENET_MDIO), + IMX_PINCTRL_PIN(MX6Q_PAD_ENET_REF_CLK), + IMX_PINCTRL_PIN(MX6Q_PAD_ENET_RX_ER), + IMX_PINCTRL_PIN(MX6Q_PAD_ENET_CRS_DV), + IMX_PINCTRL_PIN(MX6Q_PAD_ENET_RXD1), + IMX_PINCTRL_PIN(MX6Q_PAD_ENET_RXD0), + IMX_PINCTRL_PIN(MX6Q_PAD_ENET_TX_EN), + IMX_PINCTRL_PIN(MX6Q_PAD_ENET_TXD1), + IMX_PINCTRL_PIN(MX6Q_PAD_ENET_TXD0), + IMX_PINCTRL_PIN(MX6Q_PAD_ENET_MDC), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D40), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D41), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D42), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D43), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D44), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D45), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D46), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D47), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDQS5), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_DQM5), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D32), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D33), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D34), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D35), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D36), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D37), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D38), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D39), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_DQM4), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDQS4), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D24), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D25), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D26), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D27), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D28), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D29), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDQS3), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D30), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D31), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_DQM3), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D16), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D17), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D18), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D19), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D20), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D21), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D22), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDQS2), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D23), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_DQM2), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A0), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A1), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A2), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A3), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A4), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A5), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A6), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A7), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A8), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A9), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A10), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A11), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A12), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A13), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A14), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_A15), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_CAS), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_CS0), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_CS1), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_RAS), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_RESET), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDBA0), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDBA1), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDCLK_0), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDBA2), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDCKE0), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDCLK_1), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDCKE1), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDODT0), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDODT1), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDWE), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D0), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D1), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D2), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D3), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D4), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D5), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDQS0), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D6), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D7), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_DQM0), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D8), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D9), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D10), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D11), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D12), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D13), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D14), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDQS1), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D15), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_DQM1), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D48), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D49), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D50), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D51), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D52), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D53), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D54), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D55), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDQS6), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_DQM6), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D56), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_SDQS7), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D57), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D58), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D59), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D60), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_DQM7), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D61), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D62), + IMX_PINCTRL_PIN(MX6Q_PAD_DRAM_D63), + IMX_PINCTRL_PIN(MX6Q_PAD_KEY_COL0), + IMX_PINCTRL_PIN(MX6Q_PAD_KEY_ROW0), + IMX_PINCTRL_PIN(MX6Q_PAD_KEY_COL1), + IMX_PINCTRL_PIN(MX6Q_PAD_KEY_ROW1), + IMX_PINCTRL_PIN(MX6Q_PAD_KEY_COL2), + IMX_PINCTRL_PIN(MX6Q_PAD_KEY_ROW2), + IMX_PINCTRL_PIN(MX6Q_PAD_KEY_COL3), + IMX_PINCTRL_PIN(MX6Q_PAD_KEY_ROW3), + IMX_PINCTRL_PIN(MX6Q_PAD_KEY_COL4), + IMX_PINCTRL_PIN(MX6Q_PAD_KEY_ROW4), + IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_0), + IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_1), + IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_9), + IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_3), + IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_6), + IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_2), + IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_4), + IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_5), + IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_7), + IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_8), + IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_16), + IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_17), + IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_18), + IMX_PINCTRL_PIN(MX6Q_PAD_GPIO_19), + IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_PIXCLK), + IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_MCLK), + IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DATA_EN), + IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_VSYNC), + IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT4), + IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT5), + IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT6), + IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT7), + IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT8), + IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT9), + IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT10), + IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT11), + IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT12), + IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT13), + IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT14), + IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT15), + IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT16), + IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT17), + IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT18), + IMX_PINCTRL_PIN(MX6Q_PAD_CSI0_DAT19), + IMX_PINCTRL_PIN(MX6Q_PAD_JTAG_TMS), + IMX_PINCTRL_PIN(MX6Q_PAD_JTAG_MOD), + IMX_PINCTRL_PIN(MX6Q_PAD_JTAG_TRSTB), + IMX_PINCTRL_PIN(MX6Q_PAD_JTAG_TDI), + IMX_PINCTRL_PIN(MX6Q_PAD_JTAG_TCK), + IMX_PINCTRL_PIN(MX6Q_PAD_JTAG_TDO), + IMX_PINCTRL_PIN(MX6Q_PAD_LVDS1_TX3_P), + IMX_PINCTRL_PIN(MX6Q_PAD_LVDS1_TX2_P), + IMX_PINCTRL_PIN(MX6Q_PAD_LVDS1_CLK_P), + IMX_PINCTRL_PIN(MX6Q_PAD_LVDS1_TX1_P), + IMX_PINCTRL_PIN(MX6Q_PAD_LVDS1_TX0_P), + IMX_PINCTRL_PIN(MX6Q_PAD_LVDS0_TX3_P), + IMX_PINCTRL_PIN(MX6Q_PAD_LVDS0_CLK_P), + IMX_PINCTRL_PIN(MX6Q_PAD_LVDS0_TX2_P), + IMX_PINCTRL_PIN(MX6Q_PAD_LVDS0_TX1_P), + IMX_PINCTRL_PIN(MX6Q_PAD_LVDS0_TX0_P), + IMX_PINCTRL_PIN(MX6Q_PAD_TAMPER), + IMX_PINCTRL_PIN(MX6Q_PAD_PMIC_ON_REQ), + IMX_PINCTRL_PIN(MX6Q_PAD_PMIC_STBY_REQ), + IMX_PINCTRL_PIN(MX6Q_PAD_POR_B), + IMX_PINCTRL_PIN(MX6Q_PAD_BOOT_MODE1), + IMX_PINCTRL_PIN(MX6Q_PAD_RESET_IN_B), + IMX_PINCTRL_PIN(MX6Q_PAD_BOOT_MODE0), + IMX_PINCTRL_PIN(MX6Q_PAD_TEST_MODE), + IMX_PINCTRL_PIN(MX6Q_PAD_SD3_DAT7), + IMX_PINCTRL_PIN(MX6Q_PAD_SD3_DAT6), + IMX_PINCTRL_PIN(MX6Q_PAD_SD3_DAT5), + IMX_PINCTRL_PIN(MX6Q_PAD_SD3_DAT4), + IMX_PINCTRL_PIN(MX6Q_PAD_SD3_CMD), + IMX_PINCTRL_PIN(MX6Q_PAD_SD3_CLK), + IMX_PINCTRL_PIN(MX6Q_PAD_SD3_DAT0), + IMX_PINCTRL_PIN(MX6Q_PAD_SD3_DAT1), + IMX_PINCTRL_PIN(MX6Q_PAD_SD3_DAT2), + IMX_PINCTRL_PIN(MX6Q_PAD_SD3_DAT3), + IMX_PINCTRL_PIN(MX6Q_PAD_SD3_RST), + IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_CLE), + IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_ALE), + IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_WP_B), + IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_RB0), + IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_CS0), + IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_CS1), + IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_CS2), + IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_CS3), + IMX_PINCTRL_PIN(MX6Q_PAD_SD4_CMD), + IMX_PINCTRL_PIN(MX6Q_PAD_SD4_CLK), + IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_D0), + IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_D1), + IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_D2), + IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_D3), + IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_D4), + IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_D5), + IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_D6), + IMX_PINCTRL_PIN(MX6Q_PAD_NANDF_D7), + IMX_PINCTRL_PIN(MX6Q_PAD_SD4_DAT0), + IMX_PINCTRL_PIN(MX6Q_PAD_SD4_DAT1), + IMX_PINCTRL_PIN(MX6Q_PAD_SD4_DAT2), + IMX_PINCTRL_PIN(MX6Q_PAD_SD4_DAT3), + IMX_PINCTRL_PIN(MX6Q_PAD_SD4_DAT4), + IMX_PINCTRL_PIN(MX6Q_PAD_SD4_DAT5), + IMX_PINCTRL_PIN(MX6Q_PAD_SD4_DAT6), + IMX_PINCTRL_PIN(MX6Q_PAD_SD4_DAT7), + IMX_PINCTRL_PIN(MX6Q_PAD_SD1_DAT1), + IMX_PINCTRL_PIN(MX6Q_PAD_SD1_DAT0), + IMX_PINCTRL_PIN(MX6Q_PAD_SD1_DAT3), + IMX_PINCTRL_PIN(MX6Q_PAD_SD1_CMD), + IMX_PINCTRL_PIN(MX6Q_PAD_SD1_DAT2), + IMX_PINCTRL_PIN(MX6Q_PAD_SD1_CLK), + IMX_PINCTRL_PIN(MX6Q_PAD_SD2_CLK), + IMX_PINCTRL_PIN(MX6Q_PAD_SD2_CMD), + IMX_PINCTRL_PIN(MX6Q_PAD_SD2_DAT3), +}; + +static struct imx_pinctrl_soc_info imx6q_pinctrl_info = { + .pins = imx6q_pinctrl_pads, + .npins = ARRAY_SIZE(imx6q_pinctrl_pads), + .pin_regs = imx6q_pin_regs, + .npin_regs = ARRAY_SIZE(imx6q_pin_regs), +}; + +static struct of_device_id imx6q_pinctrl_of_match[] __devinitdata = { + { .compatible = "fsl,imx6q-iomuxc", }, + { /* sentinel */ } +}; + +static int __devinit imx6q_pinctrl_probe(struct platform_device *pdev) +{ + return imx_pinctrl_probe(pdev, &imx6q_pinctrl_info); +} + +static struct platform_driver imx6q_pinctrl_driver = { + .driver = { + .name = "imx6q-pinctrl", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(imx6q_pinctrl_of_match), + }, + .probe = imx6q_pinctrl_probe, + .remove = __devexit_p(imx_pinctrl_remove), +}; + +static int __init imx6q_pinctrl_init(void) +{ + return platform_driver_register(&imx6q_pinctrl_driver); +} +arch_initcall(imx6q_pinctrl_init); + +static void __exit imx6q_pinctrl_exit(void) +{ + platform_driver_unregister(&imx6q_pinctrl_driver); +} +module_exit(imx6q_pinctrl_exit); +MODULE_AUTHOR("Dong Aisheng "); +MODULE_DESCRIPTION("Freescale IMX6Q pinctrl driver"); +MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/pinctrl/pinctrl-mxs.c b/trunk/drivers/pinctrl/pinctrl-mxs.c new file mode 100644 index 000000000000..556e45a213eb --- /dev/null +++ b/trunk/drivers/pinctrl/pinctrl-mxs.c @@ -0,0 +1,528 @@ +/* + * Copyright 2012 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "core.h" +#include "pinctrl-mxs.h" + +#define SUFFIX_LEN 4 + +struct mxs_pinctrl_data { + struct device *dev; + struct pinctrl_dev *pctl; + void __iomem *base; + struct mxs_pinctrl_soc_data *soc; +}; + +static int mxs_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct mxs_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev); + + return d->soc->ngroups; +} + +static const char *mxs_get_group_name(struct pinctrl_dev *pctldev, + unsigned group) +{ + struct mxs_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev); + + return d->soc->groups[group].name; +} + +static int mxs_get_group_pins(struct pinctrl_dev *pctldev, unsigned group, + const unsigned **pins, unsigned *num_pins) +{ + struct mxs_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev); + + *pins = d->soc->groups[group].pins; + *num_pins = d->soc->groups[group].npins; + + return 0; +} + +static void mxs_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, + unsigned offset) +{ + seq_printf(s, " %s", dev_name(pctldev->dev)); +} + +static int mxs_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, unsigned *num_maps) +{ + struct pinctrl_map *new_map; + char *group = NULL; + unsigned new_num = 1; + unsigned long config = 0; + unsigned long *pconfig; + int length = strlen(np->name) + SUFFIX_LEN; + bool purecfg = false; + u32 val, reg; + int ret, i = 0; + + /* Check for pin config node which has no 'reg' property */ + if (of_property_read_u32(np, "reg", ®)) + purecfg = true; + + ret = of_property_read_u32(np, "fsl,drive-strength", &val); + if (!ret) + config = val | MA_PRESENT; + ret = of_property_read_u32(np, "fsl,voltage", &val); + if (!ret) + config |= val << VOL_SHIFT | VOL_PRESENT; + ret = of_property_read_u32(np, "fsl,pull-up", &val); + if (!ret) + config |= val << PULL_SHIFT | PULL_PRESENT; + + /* Check for group node which has both mux and config settings */ + if (!purecfg && config) + new_num = 2; + + new_map = kzalloc(sizeof(*new_map) * new_num, GFP_KERNEL); + if (!new_map) + return -ENOMEM; + + if (!purecfg) { + new_map[i].type = PIN_MAP_TYPE_MUX_GROUP; + new_map[i].data.mux.function = np->name; + + /* Compose group name */ + group = kzalloc(length, GFP_KERNEL); + if (!group) + return -ENOMEM; + snprintf(group, length, "%s.%d", np->name, reg); + new_map[i].data.mux.group = group; + i++; + } + + if (config) { + pconfig = kmemdup(&config, sizeof(config), GFP_KERNEL); + if (!pconfig) { + ret = -ENOMEM; + goto free; + } + + new_map[i].type = PIN_MAP_TYPE_CONFIGS_GROUP; + new_map[i].data.configs.group_or_pin = purecfg ? np->name : + group; + new_map[i].data.configs.configs = pconfig; + new_map[i].data.configs.num_configs = 1; + } + + *map = new_map; + *num_maps = new_num; + + return 0; + +free: + kfree(new_map); + return ret; +} + +static void mxs_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) +{ + int i; + + for (i = 0; i < num_maps; i++) { + if (map[i].type == PIN_MAP_TYPE_MUX_GROUP) + kfree(map[i].data.mux.group); + if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP) + kfree(map[i].data.configs.configs); + } + + kfree(map); +} + +static struct pinctrl_ops mxs_pinctrl_ops = { + .get_groups_count = mxs_get_groups_count, + .get_group_name = mxs_get_group_name, + .get_group_pins = mxs_get_group_pins, + .pin_dbg_show = mxs_pin_dbg_show, + .dt_node_to_map = mxs_dt_node_to_map, + .dt_free_map = mxs_dt_free_map, +}; + +static int mxs_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev) +{ + struct mxs_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev); + + return d->soc->nfunctions; +} + +static const char *mxs_pinctrl_get_func_name(struct pinctrl_dev *pctldev, + unsigned function) +{ + struct mxs_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev); + + return d->soc->functions[function].name; +} + +static int mxs_pinctrl_get_func_groups(struct pinctrl_dev *pctldev, + unsigned group, + const char * const **groups, + unsigned * const num_groups) +{ + struct mxs_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev); + + *groups = d->soc->functions[group].groups; + *num_groups = d->soc->functions[group].ngroups; + + return 0; +} + +static int mxs_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group) +{ + struct mxs_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev); + struct mxs_group *g = &d->soc->groups[group]; + void __iomem *reg; + u8 bank, shift; + u16 pin; + int i; + + for (i = 0; i < g->npins; i++) { + bank = PINID_TO_BANK(g->pins[i]); + pin = PINID_TO_PIN(g->pins[i]); + reg = d->base + d->soc->regs->muxsel; + reg += bank * 0x20 + pin / 16 * 0x10; + shift = pin % 16 * 2; + + writel(0x3 << shift, reg + CLR); + writel(g->muxsel[i] << shift, reg + SET); + } + + return 0; +} + +static struct pinmux_ops mxs_pinmux_ops = { + .get_functions_count = mxs_pinctrl_get_funcs_count, + .get_function_name = mxs_pinctrl_get_func_name, + .get_function_groups = mxs_pinctrl_get_func_groups, + .enable = mxs_pinctrl_enable, +}; + +static int mxs_pinconf_get(struct pinctrl_dev *pctldev, + unsigned pin, unsigned long *config) +{ + return -ENOTSUPP; +} + +static int mxs_pinconf_set(struct pinctrl_dev *pctldev, + unsigned pin, unsigned long config) +{ + return -ENOTSUPP; +} + +static int mxs_pinconf_group_get(struct pinctrl_dev *pctldev, + unsigned group, unsigned long *config) +{ + struct mxs_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev); + + *config = d->soc->groups[group].config; + + return 0; +} + +static int mxs_pinconf_group_set(struct pinctrl_dev *pctldev, + unsigned group, unsigned long config) +{ + struct mxs_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev); + struct mxs_group *g = &d->soc->groups[group]; + void __iomem *reg; + u8 ma, vol, pull, bank, shift; + u16 pin; + int i; + + ma = CONFIG_TO_MA(config); + vol = CONFIG_TO_VOL(config); + pull = CONFIG_TO_PULL(config); + + for (i = 0; i < g->npins; i++) { + bank = PINID_TO_BANK(g->pins[i]); + pin = PINID_TO_PIN(g->pins[i]); + + /* drive */ + reg = d->base + d->soc->regs->drive; + reg += bank * 0x40 + pin / 8 * 0x10; + + /* mA */ + if (config & MA_PRESENT) { + shift = pin % 8 * 4; + writel(0x3 << shift, reg + CLR); + writel(ma << shift, reg + SET); + } + + /* vol */ + if (config & VOL_PRESENT) { + shift = pin % 8 * 4 + 2; + if (vol) + writel(1 << shift, reg + SET); + else + writel(1 << shift, reg + CLR); + } + + /* pull */ + if (config & PULL_PRESENT) { + reg = d->base + d->soc->regs->pull; + reg += bank * 0x10; + shift = pin; + if (pull) + writel(1 << shift, reg + SET); + else + writel(1 << shift, reg + CLR); + } + } + + /* cache the config value for mxs_pinconf_group_get() */ + g->config = config; + + return 0; +} + +static void mxs_pinconf_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned pin) +{ + /* Not support */ +} + +static void mxs_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned group) +{ + unsigned long config; + + if (!mxs_pinconf_group_get(pctldev, group, &config)) + seq_printf(s, "0x%lx", config); +} + +struct pinconf_ops mxs_pinconf_ops = { + .pin_config_get = mxs_pinconf_get, + .pin_config_set = mxs_pinconf_set, + .pin_config_group_get = mxs_pinconf_group_get, + .pin_config_group_set = mxs_pinconf_group_set, + .pin_config_dbg_show = mxs_pinconf_dbg_show, + .pin_config_group_dbg_show = mxs_pinconf_group_dbg_show, +}; + +static struct pinctrl_desc mxs_pinctrl_desc = { + .pctlops = &mxs_pinctrl_ops, + .pmxops = &mxs_pinmux_ops, + .confops = &mxs_pinconf_ops, + .owner = THIS_MODULE, +}; + +static int __devinit mxs_pinctrl_parse_group(struct platform_device *pdev, + struct device_node *np, int idx, + const char **out_name) +{ + struct mxs_pinctrl_data *d = platform_get_drvdata(pdev); + struct mxs_group *g = &d->soc->groups[idx]; + struct property *prop; + const char *propname = "fsl,pinmux-ids"; + char *group; + int length = strlen(np->name) + SUFFIX_LEN; + int i; + u32 val; + + group = devm_kzalloc(&pdev->dev, length, GFP_KERNEL); + if (!group) + return -ENOMEM; + if (of_property_read_u32(np, "reg", &val)) + snprintf(group, length, "%s", np->name); + else + snprintf(group, length, "%s.%d", np->name, val); + g->name = group; + + prop = of_find_property(np, propname, &length); + if (!prop) + return -EINVAL; + g->npins = length / sizeof(u32); + + g->pins = devm_kzalloc(&pdev->dev, g->npins * sizeof(*g->pins), + GFP_KERNEL); + if (!g->pins) + return -ENOMEM; + + g->muxsel = devm_kzalloc(&pdev->dev, g->npins * sizeof(*g->muxsel), + GFP_KERNEL); + if (!g->muxsel) + return -ENOMEM; + + of_property_read_u32_array(np, propname, g->pins, g->npins); + for (i = 0; i < g->npins; i++) { + g->muxsel[i] = MUXID_TO_MUXSEL(g->pins[i]); + g->pins[i] = MUXID_TO_PINID(g->pins[i]); + } + + if (out_name) + *out_name = g->name; + + return 0; +} + +static int __devinit mxs_pinctrl_probe_dt(struct platform_device *pdev, + struct mxs_pinctrl_data *d) +{ + struct mxs_pinctrl_soc_data *soc = d->soc; + struct device_node *np = pdev->dev.of_node; + struct device_node *child; + struct mxs_function *f; + const char *gpio_compat = "fsl,mxs-gpio"; + const char *fn, *fnull = ""; + int i = 0, idxf = 0, idxg = 0; + int ret; + u32 val; + + child = of_get_next_child(np, NULL); + if (!child) { + dev_err(&pdev->dev, "no group is defined\n"); + return -ENOENT; + } + + /* Count total functions and groups */ + fn = fnull; + for_each_child_of_node(np, child) { + if (of_device_is_compatible(child, gpio_compat)) + continue; + soc->ngroups++; + /* Skip pure pinconf node */ + if (of_property_read_u32(child, "reg", &val)) + continue; + if (strcmp(fn, child->name)) { + fn = child->name; + soc->nfunctions++; + } + } + + soc->functions = devm_kzalloc(&pdev->dev, soc->nfunctions * + sizeof(*soc->functions), GFP_KERNEL); + if (!soc->functions) + return -ENOMEM; + + soc->groups = devm_kzalloc(&pdev->dev, soc->ngroups * + sizeof(*soc->groups), GFP_KERNEL); + if (!soc->groups) + return -ENOMEM; + + /* Count groups for each function */ + fn = fnull; + f = &soc->functions[idxf]; + for_each_child_of_node(np, child) { + if (of_device_is_compatible(child, gpio_compat)) + continue; + if (of_property_read_u32(child, "reg", &val)) + continue; + if (strcmp(fn, child->name)) { + f = &soc->functions[idxf++]; + f->name = fn = child->name; + } + f->ngroups++; + }; + + /* Get groups for each function */ + idxf = 0; + fn = fnull; + for_each_child_of_node(np, child) { + if (of_device_is_compatible(child, gpio_compat)) + continue; + if (of_property_read_u32(child, "reg", &val)) { + ret = mxs_pinctrl_parse_group(pdev, child, + idxg++, NULL); + if (ret) + return ret; + continue; + } + + if (strcmp(fn, child->name)) { + f = &soc->functions[idxf++]; + f->groups = devm_kzalloc(&pdev->dev, f->ngroups * + sizeof(*f->groups), + GFP_KERNEL); + if (!f->groups) + return -ENOMEM; + fn = child->name; + i = 0; + } + ret = mxs_pinctrl_parse_group(pdev, child, idxg++, + &f->groups[i++]); + if (ret) + return ret; + } + + return 0; +} + +int __devinit mxs_pinctrl_probe(struct platform_device *pdev, + struct mxs_pinctrl_soc_data *soc) +{ + struct device_node *np = pdev->dev.of_node; + struct mxs_pinctrl_data *d; + int ret; + + d = devm_kzalloc(&pdev->dev, sizeof(*d), GFP_KERNEL); + if (!d) + return -ENOMEM; + + d->dev = &pdev->dev; + d->soc = soc; + + d->base = of_iomap(np, 0); + if (!d->base) + return -EADDRNOTAVAIL; + + mxs_pinctrl_desc.pins = d->soc->pins; + mxs_pinctrl_desc.npins = d->soc->npins; + mxs_pinctrl_desc.name = dev_name(&pdev->dev); + + platform_set_drvdata(pdev, d); + + ret = mxs_pinctrl_probe_dt(pdev, d); + if (ret) { + dev_err(&pdev->dev, "dt probe failed: %d\n", ret); + goto err; + } + + d->pctl = pinctrl_register(&mxs_pinctrl_desc, &pdev->dev, d); + if (!d->pctl) { + dev_err(&pdev->dev, "Couldn't register MXS pinctrl driver\n"); + ret = -EINVAL; + goto err; + } + + return 0; + +err: + iounmap(d->base); + return ret; +} +EXPORT_SYMBOL_GPL(mxs_pinctrl_probe); + +int __devexit mxs_pinctrl_remove(struct platform_device *pdev) +{ + struct mxs_pinctrl_data *d = platform_get_drvdata(pdev); + + pinctrl_unregister(d->pctl); + iounmap(d->base); + + return 0; +} +EXPORT_SYMBOL_GPL(mxs_pinctrl_remove); diff --git a/trunk/drivers/pinctrl/pinctrl-mxs.h b/trunk/drivers/pinctrl/pinctrl-mxs.h new file mode 100644 index 000000000000..fdd88d0bae22 --- /dev/null +++ b/trunk/drivers/pinctrl/pinctrl-mxs.h @@ -0,0 +1,91 @@ +/* + * Copyright 2012 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 + */ + +#ifndef __PINCTRL_MXS_H +#define __PINCTRL_MXS_H + +#include +#include + +#define SET 0x4 +#define CLR 0x8 +#define TOG 0xc + +#define MXS_PINCTRL_PIN(pin) PINCTRL_PIN(pin, #pin) +#define PINID(bank, pin) ((bank) * 32 + (pin)) + +/* + * pinmux-id bit field definitions + * + * bank: 15..12 (4) + * pin: 11..4 (8) + * muxsel: 3..0 (4) + */ +#define MUXID_TO_PINID(m) PINID((m) >> 12 & 0xf, (m) >> 4 & 0xff) +#define MUXID_TO_MUXSEL(m) ((m) & 0xf) + +#define PINID_TO_BANK(p) ((p) >> 5) +#define PINID_TO_PIN(p) ((p) % 32) + +/* + * pin config bit field definitions + * + * pull-up: 6..5 (2) + * voltage: 4..3 (2) + * mA: 2..0 (3) + * + * MSB of each field is presence bit for the config. + */ +#define PULL_PRESENT (1 << 6) +#define PULL_SHIFT 5 +#define VOL_PRESENT (1 << 4) +#define VOL_SHIFT 3 +#define MA_PRESENT (1 << 2) +#define MA_SHIFT 0 +#define CONFIG_TO_PULL(c) ((c) >> PULL_SHIFT & 0x1) +#define CONFIG_TO_VOL(c) ((c) >> VOL_SHIFT & 0x1) +#define CONFIG_TO_MA(c) ((c) >> MA_SHIFT & 0x3) + +struct mxs_function { + const char *name; + const char **groups; + unsigned ngroups; +}; + +struct mxs_group { + const char *name; + unsigned int *pins; + unsigned npins; + u8 *muxsel; + u8 config; +}; + +struct mxs_regs { + u16 muxsel; + u16 drive; + u16 pull; +}; + +struct mxs_pinctrl_soc_data { + const struct mxs_regs *regs; + const struct pinctrl_pin_desc *pins; + unsigned npins; + struct mxs_function *functions; + unsigned nfunctions; + struct mxs_group *groups; + unsigned ngroups; +}; + +int mxs_pinctrl_probe(struct platform_device *pdev, + struct mxs_pinctrl_soc_data *soc); +int mxs_pinctrl_remove(struct platform_device *pdev); + +#endif /* __PINCTRL_MXS_H */ diff --git a/trunk/drivers/pinctrl/pinctrl-nomadik-db8500.c b/trunk/drivers/pinctrl/pinctrl-nomadik-db8500.c new file mode 100644 index 000000000000..8b2022276f71 --- /dev/null +++ b/trunk/drivers/pinctrl/pinctrl-nomadik-db8500.c @@ -0,0 +1,857 @@ +#include +#include +#include "pinctrl-nomadik.h" + +/* All the pins that can be used for GPIO and some other functions */ +#define _GPIO(offset) (offset) + +#define DB8500_PIN_AJ5 _GPIO(0) +#define DB8500_PIN_AJ3 _GPIO(1) +#define DB8500_PIN_AH4 _GPIO(2) +#define DB8500_PIN_AH3 _GPIO(3) +#define DB8500_PIN_AH6 _GPIO(4) +#define DB8500_PIN_AG6 _GPIO(5) +#define DB8500_PIN_AF6 _GPIO(6) +#define DB8500_PIN_AG5 _GPIO(7) +#define DB8500_PIN_AD5 _GPIO(8) +#define DB8500_PIN_AE4 _GPIO(9) +#define DB8500_PIN_AF5 _GPIO(10) +#define DB8500_PIN_AG4 _GPIO(11) +#define DB8500_PIN_AC4 _GPIO(12) +#define DB8500_PIN_AF3 _GPIO(13) +#define DB8500_PIN_AE3 _GPIO(14) +#define DB8500_PIN_AC3 _GPIO(15) +#define DB8500_PIN_AD3 _GPIO(16) +#define DB8500_PIN_AD4 _GPIO(17) +#define DB8500_PIN_AC2 _GPIO(18) +#define DB8500_PIN_AC1 _GPIO(19) +#define DB8500_PIN_AB4 _GPIO(20) +#define DB8500_PIN_AB3 _GPIO(21) +#define DB8500_PIN_AA3 _GPIO(22) +#define DB8500_PIN_AA4 _GPIO(23) +#define DB8500_PIN_AB2 _GPIO(24) +#define DB8500_PIN_Y4 _GPIO(25) +#define DB8500_PIN_Y2 _GPIO(26) +#define DB8500_PIN_AA2 _GPIO(27) +#define DB8500_PIN_AA1 _GPIO(28) +#define DB8500_PIN_W2 _GPIO(29) +#define DB8500_PIN_W3 _GPIO(30) +#define DB8500_PIN_V3 _GPIO(31) +#define DB8500_PIN_V2 _GPIO(32) +#define DB8500_PIN_AF2 _GPIO(33) +#define DB8500_PIN_AE1 _GPIO(34) +#define DB8500_PIN_AE2 _GPIO(35) +#define DB8500_PIN_AG2 _GPIO(36) +/* Hole */ +#define DB8500_PIN_F3 _GPIO(64) +#define DB8500_PIN_F1 _GPIO(65) +#define DB8500_PIN_G3 _GPIO(66) +#define DB8500_PIN_G2 _GPIO(67) +#define DB8500_PIN_E1 _GPIO(68) +#define DB8500_PIN_E2 _GPIO(69) +#define DB8500_PIN_G5 _GPIO(70) +#define DB8500_PIN_G4 _GPIO(71) +#define DB8500_PIN_H4 _GPIO(72) +#define DB8500_PIN_H3 _GPIO(73) +#define DB8500_PIN_J3 _GPIO(74) +#define DB8500_PIN_H2 _GPIO(75) +#define DB8500_PIN_J2 _GPIO(76) +#define DB8500_PIN_H1 _GPIO(77) +#define DB8500_PIN_F4 _GPIO(78) +#define DB8500_PIN_E3 _GPIO(79) +#define DB8500_PIN_E4 _GPIO(80) +#define DB8500_PIN_D2 _GPIO(81) +#define DB8500_PIN_C1 _GPIO(82) +#define DB8500_PIN_D3 _GPIO(83) +#define DB8500_PIN_C2 _GPIO(84) +#define DB8500_PIN_D5 _GPIO(85) +#define DB8500_PIN_C6 _GPIO(86) +#define DB8500_PIN_B3 _GPIO(87) +#define DB8500_PIN_C4 _GPIO(88) +#define DB8500_PIN_E6 _GPIO(89) +#define DB8500_PIN_A3 _GPIO(90) +#define DB8500_PIN_B6 _GPIO(91) +#define DB8500_PIN_D6 _GPIO(92) +#define DB8500_PIN_B7 _GPIO(93) +#define DB8500_PIN_D7 _GPIO(94) +#define DB8500_PIN_E8 _GPIO(95) +#define DB8500_PIN_D8 _GPIO(96) +#define DB8500_PIN_D9 _GPIO(97) +/* Hole */ +#define DB8500_PIN_A5 _GPIO(128) +#define DB8500_PIN_B4 _GPIO(129) +#define DB8500_PIN_C8 _GPIO(130) +#define DB8500_PIN_A12 _GPIO(131) +#define DB8500_PIN_C10 _GPIO(132) +#define DB8500_PIN_B10 _GPIO(133) +#define DB8500_PIN_B9 _GPIO(134) +#define DB8500_PIN_A9 _GPIO(135) +#define DB8500_PIN_C7 _GPIO(136) +#define DB8500_PIN_A7 _GPIO(137) +#define DB8500_PIN_C5 _GPIO(138) +#define DB8500_PIN_C9 _GPIO(139) +#define DB8500_PIN_B11 _GPIO(140) +#define DB8500_PIN_C12 _GPIO(141) +#define DB8500_PIN_C11 _GPIO(142) +#define DB8500_PIN_D12 _GPIO(143) +#define DB8500_PIN_B13 _GPIO(144) +#define DB8500_PIN_C13 _GPIO(145) +#define DB8500_PIN_D13 _GPIO(146) +#define DB8500_PIN_C15 _GPIO(147) +#define DB8500_PIN_B16 _GPIO(148) +#define DB8500_PIN_B14 _GPIO(149) +#define DB8500_PIN_C14 _GPIO(150) +#define DB8500_PIN_D17 _GPIO(151) +#define DB8500_PIN_D16 _GPIO(152) +#define DB8500_PIN_B17 _GPIO(153) +#define DB8500_PIN_C16 _GPIO(154) +#define DB8500_PIN_C19 _GPIO(155) +#define DB8500_PIN_C17 _GPIO(156) +#define DB8500_PIN_A18 _GPIO(157) +#define DB8500_PIN_C18 _GPIO(158) +#define DB8500_PIN_B19 _GPIO(159) +#define DB8500_PIN_B20 _GPIO(160) +#define DB8500_PIN_D21 _GPIO(161) +#define DB8500_PIN_D20 _GPIO(162) +#define DB8500_PIN_C20 _GPIO(163) +#define DB8500_PIN_B21 _GPIO(164) +#define DB8500_PIN_C21 _GPIO(165) +#define DB8500_PIN_A22 _GPIO(166) +#define DB8500_PIN_B24 _GPIO(167) +#define DB8500_PIN_C22 _GPIO(168) +#define DB8500_PIN_D22 _GPIO(169) +#define DB8500_PIN_C23 _GPIO(170) +#define DB8500_PIN_D23 _GPIO(171) +/* Hole */ +#define DB8500_PIN_AJ27 _GPIO(192) +#define DB8500_PIN_AH27 _GPIO(193) +#define DB8500_PIN_AF27 _GPIO(194) +#define DB8500_PIN_AG28 _GPIO(195) +#define DB8500_PIN_AG26 _GPIO(196) +#define DB8500_PIN_AH24 _GPIO(197) +#define DB8500_PIN_AG25 _GPIO(198) +#define DB8500_PIN_AH23 _GPIO(199) +#define DB8500_PIN_AH26 _GPIO(200) +#define DB8500_PIN_AF24 _GPIO(201) +#define DB8500_PIN_AF25 _GPIO(202) +#define DB8500_PIN_AE23 _GPIO(203) +#define DB8500_PIN_AF23 _GPIO(204) +#define DB8500_PIN_AG23 _GPIO(205) +#define DB8500_PIN_AG24 _GPIO(206) +#define DB8500_PIN_AJ23 _GPIO(207) +#define DB8500_PIN_AH16 _GPIO(208) +#define DB8500_PIN_AG15 _GPIO(209) +#define DB8500_PIN_AJ15 _GPIO(210) +#define DB8500_PIN_AG14 _GPIO(211) +#define DB8500_PIN_AF13 _GPIO(212) +#define DB8500_PIN_AG13 _GPIO(213) +#define DB8500_PIN_AH15 _GPIO(214) +#define DB8500_PIN_AH13 _GPIO(215) +#define DB8500_PIN_AG12 _GPIO(216) +#define DB8500_PIN_AH12 _GPIO(217) +#define DB8500_PIN_AH11 _GPIO(218) +#define DB8500_PIN_AG10 _GPIO(219) +#define DB8500_PIN_AH10 _GPIO(220) +#define DB8500_PIN_AJ11 _GPIO(221) +#define DB8500_PIN_AJ9 _GPIO(222) +#define DB8500_PIN_AH9 _GPIO(223) +#define DB8500_PIN_AG9 _GPIO(224) +#define DB8500_PIN_AG8 _GPIO(225) +#define DB8500_PIN_AF8 _GPIO(226) +#define DB8500_PIN_AH7 _GPIO(227) +#define DB8500_PIN_AJ6 _GPIO(228) +#define DB8500_PIN_AG7 _GPIO(229) +#define DB8500_PIN_AF7 _GPIO(230) +/* Hole */ +#define DB8500_PIN_AF28 _GPIO(256) +#define DB8500_PIN_AE29 _GPIO(257) +#define DB8500_PIN_AD29 _GPIO(258) +#define DB8500_PIN_AC29 _GPIO(259) +#define DB8500_PIN_AD28 _GPIO(260) +#define DB8500_PIN_AD26 _GPIO(261) +#define DB8500_PIN_AE26 _GPIO(262) +#define DB8500_PIN_AG29 _GPIO(263) +#define DB8500_PIN_AE27 _GPIO(264) +#define DB8500_PIN_AD27 _GPIO(265) +#define DB8500_PIN_AC28 _GPIO(266) +#define DB8500_PIN_AC27 _GPIO(267) + +/* + * The names of the pins are denoted by GPIO number and ball name, even + * though they can be used for other things than GPIO, this is the first + * column in the table of the data sheet and often used on schematics and + * such. + */ +static const struct pinctrl_pin_desc nmk_db8500_pins[] = { + PINCTRL_PIN(DB8500_PIN_AJ5, "GPIO0_AJ5"), + PINCTRL_PIN(DB8500_PIN_AJ3, "GPIO1_AJ3"), + PINCTRL_PIN(DB8500_PIN_AH4, "GPIO2_AH4"), + PINCTRL_PIN(DB8500_PIN_AH3, "GPIO3_AH3"), + PINCTRL_PIN(DB8500_PIN_AH6, "GPIO4_AH6"), + PINCTRL_PIN(DB8500_PIN_AG6, "GPIO5_AG6"), + PINCTRL_PIN(DB8500_PIN_AF6, "GPIO6_AF6"), + PINCTRL_PIN(DB8500_PIN_AG5, "GPIO7_AG5"), + PINCTRL_PIN(DB8500_PIN_AD5, "GPIO8_AD5"), + PINCTRL_PIN(DB8500_PIN_AE4, "GPIO9_AE4"), + PINCTRL_PIN(DB8500_PIN_AF5, "GPIO10_AF5"), + PINCTRL_PIN(DB8500_PIN_AG4, "GPIO11_AG4"), + PINCTRL_PIN(DB8500_PIN_AC4, "GPIO12_AC4"), + PINCTRL_PIN(DB8500_PIN_AF3, "GPIO13_AF3"), + PINCTRL_PIN(DB8500_PIN_AE3, "GPIO14_AE3"), + PINCTRL_PIN(DB8500_PIN_AC3, "GPIO15_AC3"), + PINCTRL_PIN(DB8500_PIN_AD3, "GPIO16_AD3"), + PINCTRL_PIN(DB8500_PIN_AD4, "GPIO17_AD4"), + PINCTRL_PIN(DB8500_PIN_AC2, "GPIO18_AC2"), + PINCTRL_PIN(DB8500_PIN_AC1, "GPIO19_AC1"), + PINCTRL_PIN(DB8500_PIN_AB4, "GPIO20_AB4"), + PINCTRL_PIN(DB8500_PIN_AB3, "GPIO21_AB3"), + PINCTRL_PIN(DB8500_PIN_AA3, "GPIO22_AA3"), + PINCTRL_PIN(DB8500_PIN_AA4, "GPIO23_AA4"), + PINCTRL_PIN(DB8500_PIN_AB2, "GPIO24_AB2"), + PINCTRL_PIN(DB8500_PIN_Y4, "GPIO25_Y4"), + PINCTRL_PIN(DB8500_PIN_Y2, "GPIO26_Y2"), + PINCTRL_PIN(DB8500_PIN_AA2, "GPIO27_AA2"), + PINCTRL_PIN(DB8500_PIN_AA1, "GPIO28_AA1"), + PINCTRL_PIN(DB8500_PIN_W2, "GPIO29_W2"), + PINCTRL_PIN(DB8500_PIN_W3, "GPIO30_W3"), + PINCTRL_PIN(DB8500_PIN_V3, "GPIO31_V3"), + PINCTRL_PIN(DB8500_PIN_V2, "GPIO32_V2"), + PINCTRL_PIN(DB8500_PIN_AF2, "GPIO33_AF2"), + PINCTRL_PIN(DB8500_PIN_AE1, "GPIO34_AE1"), + PINCTRL_PIN(DB8500_PIN_AE2, "GPIO35_AE2"), + PINCTRL_PIN(DB8500_PIN_AG2, "GPIO36_AG2"), + /* Hole */ + PINCTRL_PIN(DB8500_PIN_F3, "GPIO64_F3"), + PINCTRL_PIN(DB8500_PIN_F1, "GPIO65_F1"), + PINCTRL_PIN(DB8500_PIN_G3, "GPIO66_G3"), + PINCTRL_PIN(DB8500_PIN_G2, "GPIO67_G2"), + PINCTRL_PIN(DB8500_PIN_E1, "GPIO68_E1"), + PINCTRL_PIN(DB8500_PIN_E2, "GPIO69_E2"), + PINCTRL_PIN(DB8500_PIN_G5, "GPIO70_G5"), + PINCTRL_PIN(DB8500_PIN_G4, "GPIO71_G4"), + PINCTRL_PIN(DB8500_PIN_H4, "GPIO72_H4"), + PINCTRL_PIN(DB8500_PIN_H3, "GPIO73_H3"), + PINCTRL_PIN(DB8500_PIN_J3, "GPIO74_J3"), + PINCTRL_PIN(DB8500_PIN_H2, "GPIO75_H2"), + PINCTRL_PIN(DB8500_PIN_J2, "GPIO76_J2"), + PINCTRL_PIN(DB8500_PIN_H1, "GPIO77_H1"), + PINCTRL_PIN(DB8500_PIN_F4, "GPIO78_F4"), + PINCTRL_PIN(DB8500_PIN_E3, "GPIO79_E3"), + PINCTRL_PIN(DB8500_PIN_E4, "GPIO80_E4"), + PINCTRL_PIN(DB8500_PIN_D2, "GPIO81_D2"), + PINCTRL_PIN(DB8500_PIN_C1, "GPIO82_C1"), + PINCTRL_PIN(DB8500_PIN_D3, "GPIO83_D3"), + PINCTRL_PIN(DB8500_PIN_C2, "GPIO84_C2"), + PINCTRL_PIN(DB8500_PIN_D5, "GPIO85_D5"), + PINCTRL_PIN(DB8500_PIN_C6, "GPIO86_C6"), + PINCTRL_PIN(DB8500_PIN_B3, "GPIO87_B3"), + PINCTRL_PIN(DB8500_PIN_C4, "GPIO88_C4"), + PINCTRL_PIN(DB8500_PIN_E6, "GPIO89_E6"), + PINCTRL_PIN(DB8500_PIN_A3, "GPIO90_A3"), + PINCTRL_PIN(DB8500_PIN_B6, "GPIO91_B6"), + PINCTRL_PIN(DB8500_PIN_D6, "GPIO92_D6"), + PINCTRL_PIN(DB8500_PIN_B7, "GPIO93_B7"), + PINCTRL_PIN(DB8500_PIN_D7, "GPIO94_D7"), + PINCTRL_PIN(DB8500_PIN_E8, "GPIO95_E8"), + PINCTRL_PIN(DB8500_PIN_D8, "GPIO96_D8"), + PINCTRL_PIN(DB8500_PIN_D9, "GPIO97_D9"), + /* Hole */ + PINCTRL_PIN(DB8500_PIN_A5, "GPIO128_A5"), + PINCTRL_PIN(DB8500_PIN_B4, "GPIO129_B4"), + PINCTRL_PIN(DB8500_PIN_C8, "GPIO130_C8"), + PINCTRL_PIN(DB8500_PIN_A12, "GPIO131_A12"), + PINCTRL_PIN(DB8500_PIN_C10, "GPIO132_C10"), + PINCTRL_PIN(DB8500_PIN_B10, "GPIO133_B10"), + PINCTRL_PIN(DB8500_PIN_B9, "GPIO134_B9"), + PINCTRL_PIN(DB8500_PIN_A9, "GPIO135_A9"), + PINCTRL_PIN(DB8500_PIN_C7, "GPIO136_C7"), + PINCTRL_PIN(DB8500_PIN_A7, "GPIO137_A7"), + PINCTRL_PIN(DB8500_PIN_C5, "GPIO138_C5"), + PINCTRL_PIN(DB8500_PIN_C9, "GPIO139_C9"), + PINCTRL_PIN(DB8500_PIN_B11, "GPIO140_B11"), + PINCTRL_PIN(DB8500_PIN_C12, "GPIO141_C12"), + PINCTRL_PIN(DB8500_PIN_C11, "GPIO142_C11"), + PINCTRL_PIN(DB8500_PIN_D12, "GPIO143_D12"), + PINCTRL_PIN(DB8500_PIN_B13, "GPIO144_B13"), + PINCTRL_PIN(DB8500_PIN_C13, "GPIO145_C13"), + PINCTRL_PIN(DB8500_PIN_D13, "GPIO146_D13"), + PINCTRL_PIN(DB8500_PIN_C15, "GPIO147_C15"), + PINCTRL_PIN(DB8500_PIN_B16, "GPIO148_B16"), + PINCTRL_PIN(DB8500_PIN_B14, "GPIO149_B14"), + PINCTRL_PIN(DB8500_PIN_C14, "GPIO150_C14"), + PINCTRL_PIN(DB8500_PIN_D17, "GPIO151_D17"), + PINCTRL_PIN(DB8500_PIN_D16, "GPIO152_D16"), + PINCTRL_PIN(DB8500_PIN_B17, "GPIO153_B17"), + PINCTRL_PIN(DB8500_PIN_C16, "GPIO154_C16"), + PINCTRL_PIN(DB8500_PIN_C19, "GPIO155_C19"), + PINCTRL_PIN(DB8500_PIN_C17, "GPIO156_C17"), + PINCTRL_PIN(DB8500_PIN_A18, "GPIO157_A18"), + PINCTRL_PIN(DB8500_PIN_C18, "GPIO158_C18"), + PINCTRL_PIN(DB8500_PIN_B19, "GPIO159_B19"), + PINCTRL_PIN(DB8500_PIN_B20, "GPIO160_B20"), + PINCTRL_PIN(DB8500_PIN_D21, "GPIO161_D21"), + PINCTRL_PIN(DB8500_PIN_D20, "GPIO162_D20"), + PINCTRL_PIN(DB8500_PIN_C20, "GPIO163_C20"), + PINCTRL_PIN(DB8500_PIN_B21, "GPIO164_B21"), + PINCTRL_PIN(DB8500_PIN_C21, "GPIO165_C21"), + PINCTRL_PIN(DB8500_PIN_A22, "GPIO166_A22"), + PINCTRL_PIN(DB8500_PIN_B24, "GPIO167_B24"), + PINCTRL_PIN(DB8500_PIN_C22, "GPIO168_C22"), + PINCTRL_PIN(DB8500_PIN_D22, "GPIO169_D22"), + PINCTRL_PIN(DB8500_PIN_C23, "GPIO170_C23"), + PINCTRL_PIN(DB8500_PIN_D23, "GPIO171_D23"), + /* Hole */ + PINCTRL_PIN(DB8500_PIN_AJ27, "GPIO192_AJ27"), + PINCTRL_PIN(DB8500_PIN_AH27, "GPIO193_AH27"), + PINCTRL_PIN(DB8500_PIN_AF27, "GPIO194_AF27"), + PINCTRL_PIN(DB8500_PIN_AG28, "GPIO195_AG28"), + PINCTRL_PIN(DB8500_PIN_AG26, "GPIO196_AG26"), + PINCTRL_PIN(DB8500_PIN_AH24, "GPIO197_AH24"), + PINCTRL_PIN(DB8500_PIN_AG25, "GPIO198_AG25"), + PINCTRL_PIN(DB8500_PIN_AH23, "GPIO199_AH23"), + PINCTRL_PIN(DB8500_PIN_AH26, "GPIO200_AH26"), + PINCTRL_PIN(DB8500_PIN_AF24, "GPIO201_AF24"), + PINCTRL_PIN(DB8500_PIN_AF25, "GPIO202_AF25"), + PINCTRL_PIN(DB8500_PIN_AE23, "GPIO203_AE23"), + PINCTRL_PIN(DB8500_PIN_AF23, "GPIO204_AF23"), + PINCTRL_PIN(DB8500_PIN_AG23, "GPIO205_AG23"), + PINCTRL_PIN(DB8500_PIN_AG24, "GPIO206_AG24"), + PINCTRL_PIN(DB8500_PIN_AJ23, "GPIO207_AJ23"), + PINCTRL_PIN(DB8500_PIN_AH16, "GPIO208_AH16"), + PINCTRL_PIN(DB8500_PIN_AG15, "GPIO209_AG15"), + PINCTRL_PIN(DB8500_PIN_AJ15, "GPIO210_AJ15"), + PINCTRL_PIN(DB8500_PIN_AG14, "GPIO211_AG14"), + PINCTRL_PIN(DB8500_PIN_AF13, "GPIO212_AF13"), + PINCTRL_PIN(DB8500_PIN_AG13, "GPIO213_AG13"), + PINCTRL_PIN(DB8500_PIN_AH15, "GPIO214_AH15"), + PINCTRL_PIN(DB8500_PIN_AH13, "GPIO215_AH13"), + PINCTRL_PIN(DB8500_PIN_AG12, "GPIO216_AG12"), + PINCTRL_PIN(DB8500_PIN_AH12, "GPIO217_AH12"), + PINCTRL_PIN(DB8500_PIN_AH11, "GPIO218_AH11"), + PINCTRL_PIN(DB8500_PIN_AG10, "GPIO219_AG10"), + PINCTRL_PIN(DB8500_PIN_AH10, "GPIO220_AH10"), + PINCTRL_PIN(DB8500_PIN_AJ11, "GPIO221_AJ11"), + PINCTRL_PIN(DB8500_PIN_AJ9, "GPIO222_AJ9"), + PINCTRL_PIN(DB8500_PIN_AH9, "GPIO223_AH9"), + PINCTRL_PIN(DB8500_PIN_AG9, "GPIO224_AG9"), + PINCTRL_PIN(DB8500_PIN_AG8, "GPIO225_AG8"), + PINCTRL_PIN(DB8500_PIN_AF8, "GPIO226_AF8"), + PINCTRL_PIN(DB8500_PIN_AH7, "GPIO227_AH7"), + PINCTRL_PIN(DB8500_PIN_AJ6, "GPIO228_AJ6"), + PINCTRL_PIN(DB8500_PIN_AG7, "GPIO229_AG7"), + PINCTRL_PIN(DB8500_PIN_AF7, "GPIO230_AF7"), + /* Hole */ + PINCTRL_PIN(DB8500_PIN_AF28, "GPIO256_AF28"), + PINCTRL_PIN(DB8500_PIN_AE29, "GPIO257_AE29"), + PINCTRL_PIN(DB8500_PIN_AD29, "GPIO258_AD29"), + PINCTRL_PIN(DB8500_PIN_AC29, "GPIO259_AC29"), + PINCTRL_PIN(DB8500_PIN_AD28, "GPIO260_AD28"), + PINCTRL_PIN(DB8500_PIN_AD26, "GPIO261_AD26"), + PINCTRL_PIN(DB8500_PIN_AE26, "GPIO262_AE26"), + PINCTRL_PIN(DB8500_PIN_AG29, "GPIO263_AG29"), + PINCTRL_PIN(DB8500_PIN_AE27, "GPIO264_AE27"), + PINCTRL_PIN(DB8500_PIN_AD27, "GPIO265_AD27"), + PINCTRL_PIN(DB8500_PIN_AC28, "GPIO266_AC28"), + PINCTRL_PIN(DB8500_PIN_AC27, "GPIO267_AC27"), +}; + +#define DB8500_GPIO_RANGE(a, b, c) { .name = "DB8500", .id = a, .base = b, \ + .pin_base = b, .npins = c } + +/* + * This matches the 32-pin gpio chips registered by the GPIO portion. This + * cannot be const since we assign the struct gpio_chip * pointer at runtime. + */ +static struct pinctrl_gpio_range nmk_db8500_ranges[] = { + DB8500_GPIO_RANGE(0, 0, 32), + DB8500_GPIO_RANGE(1, 32, 5), + DB8500_GPIO_RANGE(2, 64, 32), + DB8500_GPIO_RANGE(3, 96, 2), + DB8500_GPIO_RANGE(4, 128, 32), + DB8500_GPIO_RANGE(5, 160, 12), + DB8500_GPIO_RANGE(6, 192, 32), + DB8500_GPIO_RANGE(7, 224, 7), + DB8500_GPIO_RANGE(8, 256, 12), +}; + +/* + * Read the pin group names like this: + * u0_a_1 = first groups of pins for uart0 on alt function a + * i2c2_b_2 = second group of pins for i2c2 on alt function b + * + * The groups are arranged as sets per altfunction column, so we can + * mux in one group at a time by selecting the same altfunction for them + * all. When functions require pins on different altfunctions, you need + * to combine several groups. + */ + +/* Altfunction A column */ +static const unsigned u0_a_1_pins[] = { DB8500_PIN_AJ5, DB8500_PIN_AJ3, + DB8500_PIN_AH4, DB8500_PIN_AH3 }; +static const unsigned u1rxtx_a_1_pins[] = { DB8500_PIN_AH6, DB8500_PIN_AG6 }; +static const unsigned u1ctsrts_a_1_pins[] = { DB8500_PIN_AF6, DB8500_PIN_AG5 }; +/* Image processor I2C line, this is driven by image processor firmware */ +static const unsigned ipi2c_a_1_pins[] = { DB8500_PIN_AD5, DB8500_PIN_AE4 }; +static const unsigned ipi2c_a_2_pins[] = { DB8500_PIN_AF5, DB8500_PIN_AG4 }; +/* MSP0 can only be on these pins, but TXD and RXD can be flipped */ +static const unsigned msp0txrx_a_1_pins[] = { DB8500_PIN_AC4, DB8500_PIN_AC3 }; +static const unsigned msp0tfstck_a_1_pins[] = { DB8500_PIN_AF3, DB8500_PIN_AE3 }; +static const unsigned msp0rfsrck_a_1_pins[] = { DB8500_PIN_AD3, DB8500_PIN_AD4 }; +/* Basic pins of the MMC/SD card 0 interface */ +static const unsigned mc0_a_1_pins[] = { DB8500_PIN_AC2, DB8500_PIN_AC1, + DB8500_PIN_AB4, DB8500_PIN_AA3, DB8500_PIN_AA4, DB8500_PIN_AB2, + DB8500_PIN_Y4, DB8500_PIN_Y2, DB8500_PIN_AA2, DB8500_PIN_AA1 }; +/* Often only 4 bits are used, then these are not needed (only used for MMC) */ +static const unsigned mc0_dat47_a_1_pins[] = { DB8500_PIN_W2, DB8500_PIN_W3, + DB8500_PIN_V3, DB8500_PIN_V2}; +static const unsigned mc0dat31dir_a_1_pins[] = { DB8500_PIN_AB3 }; +/* MSP1 can only be on these pins, but TXD and RXD can be flipped */ +static const unsigned msp1txrx_a_1_pins[] = { DB8500_PIN_AF2, DB8500_PIN_AG2 }; +static const unsigned msp1_a_1_pins[] = { DB8500_PIN_AE1, DB8500_PIN_AE2 }; +/* LCD interface */ +static const unsigned lcdb_a_1_pins[] = { DB8500_PIN_F3, DB8500_PIN_F1, + DB8500_PIN_G3, DB8500_PIN_G2 }; +static const unsigned lcdvsi0_a_1_pins[] = { DB8500_PIN_E1 }; +static const unsigned lcdvsi1_a_1_pins[] = { DB8500_PIN_E2 }; +static const unsigned lcd_d0_d7_a_1_pins[] = { + DB8500_PIN_G5, DB8500_PIN_G4, DB8500_PIN_H4, DB8500_PIN_H3, + DB8500_PIN_J3, DB8500_PIN_H2, DB8500_PIN_J2, DB8500_PIN_H1 }; +/* D8 thru D11 often used as TVOUT lines */ +static const unsigned lcd_d8_d11_a_1_pins[] = { DB8500_PIN_F4, + DB8500_PIN_E3, DB8500_PIN_E4, DB8500_PIN_D2 }; +static const unsigned lcd_d12_d23_a_1_pins[] = { + DB8500_PIN_C1, DB8500_PIN_D3, DB8500_PIN_C2, DB8500_PIN_D5, + DB8500_PIN_C6, DB8500_PIN_B3, DB8500_PIN_C4, DB8500_PIN_E6, + DB8500_PIN_A3, DB8500_PIN_B6, DB8500_PIN_D6, DB8500_PIN_B7 }; +static const unsigned kp_a_1_pins[] = { DB8500_PIN_D7, DB8500_PIN_E8, + DB8500_PIN_D8, DB8500_PIN_D9 }; +static const unsigned kpskaskb_a_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16 }; +static const unsigned kp_a_2_pins[] = { + DB8500_PIN_B17, DB8500_PIN_C16, DB8500_PIN_C19, DB8500_PIN_C17, + DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19, DB8500_PIN_B20, + DB8500_PIN_D21, DB8500_PIN_D20, DB8500_PIN_C20, DB8500_PIN_B21, + DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24, DB8500_PIN_C22 }; +/* MC2 has 8 data lines and no direction control, so only for (e)MMC */ +static const unsigned mc2_a_1_pins[] = { DB8500_PIN_A5, DB8500_PIN_B4, + DB8500_PIN_C8, DB8500_PIN_A12, DB8500_PIN_C10, DB8500_PIN_B10, + DB8500_PIN_B9, DB8500_PIN_A9, DB8500_PIN_C7, DB8500_PIN_A7, + DB8500_PIN_C5 }; +static const unsigned ssp1_a_1_pins[] = { DB8500_PIN_C9, DB8500_PIN_B11, + DB8500_PIN_C12, DB8500_PIN_C11 }; +static const unsigned ssp0_a_1_pins[] = { DB8500_PIN_D12, DB8500_PIN_B13, + DB8500_PIN_C13, DB8500_PIN_D13 }; +static const unsigned i2c0_a_1_pins[] = { DB8500_PIN_C15, DB8500_PIN_B16 }; +/* + * Image processor GPIO pins are named "ipgpio" and have their own + * numberspace + */ +static const unsigned ipgpio0_a_1_pins[] = { DB8500_PIN_B14 }; +static const unsigned ipgpio1_a_1_pins[] = { DB8500_PIN_C14 }; +/* Three modem pins named RF_PURn, MODEM_STATE and MODEM_PWREN */ +static const unsigned modem_a_1_pins[] = { DB8500_PIN_D22, DB8500_PIN_C23, + DB8500_PIN_D23 }; +/* + * This MSP cannot switch RX and TX, SCK in a separate group since this + * seems to be optional. + */ +static const unsigned msp2sck_a_1_pins[] = { DB8500_PIN_AJ27 }; +static const unsigned msp2_a_1_pins[] = { DB8500_PIN_AH27, DB8500_PIN_AF27, + DB8500_PIN_AG28, DB8500_PIN_AG26 }; +static const unsigned mc4_a_1_pins[] = { DB8500_PIN_AH24, DB8500_PIN_AG25, + DB8500_PIN_AH23, DB8500_PIN_AH26, DB8500_PIN_AF24, DB8500_PIN_AF25, + DB8500_PIN_AE23, DB8500_PIN_AF23, DB8500_PIN_AG23, DB8500_PIN_AG24, + DB8500_PIN_AJ23 }; +/* MC1 has only 4 data pins, designed for SD or SDIO exclusively */ +static const unsigned mc1_a_1_pins[] = { DB8500_PIN_AH16, DB8500_PIN_AG15, + DB8500_PIN_AJ15, DB8500_PIN_AG14, DB8500_PIN_AF13, DB8500_PIN_AG13, + DB8500_PIN_AH15 }; +static const unsigned mc1dir_a_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AG12, + DB8500_PIN_AH12, DB8500_PIN_AH11 }; +static const unsigned hsir_a_1_pins[] = { DB8500_PIN_AG10, DB8500_PIN_AH10 }; +static const unsigned hsit_a_1_pins[] = { DB8500_PIN_AJ11, DB8500_PIN_AJ9, + DB8500_PIN_AH9, DB8500_PIN_AG9, DB8500_PIN_AG8, DB8500_PIN_AF8 }; +static const unsigned clkout_a_1_pins[] = { DB8500_PIN_AH7, DB8500_PIN_AJ6 }; +static const unsigned clkout_a_2_pins[] = { DB8500_PIN_AG7, DB8500_PIN_AF7 }; +static const unsigned usb_a_1_pins[] = { DB8500_PIN_AF28, DB8500_PIN_AE29, + DB8500_PIN_AD29, DB8500_PIN_AC29, DB8500_PIN_AD28, DB8500_PIN_AD26, + DB8500_PIN_AE26, DB8500_PIN_AG29, DB8500_PIN_AE27, DB8500_PIN_AD27, + DB8500_PIN_AC28, DB8500_PIN_AC27 }; + +/* Altfunction B column */ +static const unsigned trig_b_1_pins[] = { DB8500_PIN_AJ5, DB8500_PIN_AJ3 }; +static const unsigned i2c4_b_1_pins[] = { DB8500_PIN_AH6, DB8500_PIN_AG6 }; +static const unsigned i2c1_b_1_pins[] = { DB8500_PIN_AF6, DB8500_PIN_AG5 }; +static const unsigned i2c2_b_1_pins[] = { DB8500_PIN_AD5, DB8500_PIN_AE4 }; +static const unsigned i2c2_b_2_pins[] = { DB8500_PIN_AF5, DB8500_PIN_AG4 }; +static const unsigned msp0txrx_b_1_pins[] = { DB8500_PIN_AC4, DB8500_PIN_AC3 }; +static const unsigned i2c1_b_2_pins[] = { DB8500_PIN_AD3, DB8500_PIN_AD4 }; +/* Just RX and TX for UART2 */ +static const unsigned u2rxtx_b_1_pins[] = { DB8500_PIN_AC2, DB8500_PIN_AC1 }; +static const unsigned uartmodtx_b_1_pins[] = { DB8500_PIN_AB4 }; +static const unsigned msp0sck_b_1_pins[] = { DB8500_PIN_AB3 }; +static const unsigned uartmodrx_b_1_pins[] = { DB8500_PIN_AA3 }; +static const unsigned stmmod_b_1_pins[] = { DB8500_PIN_AA4, DB8500_PIN_Y4, + DB8500_PIN_Y2, DB8500_PIN_AA2, DB8500_PIN_AA1 }; +static const unsigned uartmodrx_b_2_pins[] = { DB8500_PIN_AB2 }; +static const unsigned spi3_b_1_pins[] = { DB8500_PIN_W2, DB8500_PIN_W3, + DB8500_PIN_V3, DB8500_PIN_V2 }; +static const unsigned msp1txrx_b_1_pins[] = { DB8500_PIN_AF2, DB8500_PIN_AG2 }; +static const unsigned kp_b_1_pins[] = { DB8500_PIN_F3, DB8500_PIN_F1, + DB8500_PIN_G3, DB8500_PIN_G2, DB8500_PIN_E1, DB8500_PIN_E2, + DB8500_PIN_G5, DB8500_PIN_G4, DB8500_PIN_H4, DB8500_PIN_H3, + DB8500_PIN_J3, DB8500_PIN_H2, DB8500_PIN_J2, DB8500_PIN_H1, + DB8500_PIN_F4, DB8500_PIN_E3, DB8500_PIN_E4, DB8500_PIN_D2, + DB8500_PIN_C1, DB8500_PIN_D3, DB8500_PIN_C2, DB8500_PIN_D5 }; +static const unsigned sm_b_1_pins[] = { DB8500_PIN_C6, DB8500_PIN_B3, + DB8500_PIN_C4, DB8500_PIN_E6, DB8500_PIN_A3, DB8500_PIN_B6, + DB8500_PIN_D6, DB8500_PIN_B7, DB8500_PIN_D7, DB8500_PIN_D8, + DB8500_PIN_D9, DB8500_PIN_A5, DB8500_PIN_B4, DB8500_PIN_C8, + DB8500_PIN_A12, DB8500_PIN_C10, DB8500_PIN_B10, DB8500_PIN_B9, + DB8500_PIN_A9, DB8500_PIN_C7, DB8500_PIN_A7, DB8500_PIN_C5, + DB8500_PIN_C9, DB8500_PIN_B14 }; +/* This chip select pin can be "ps0" in alt B so have it separately */ +static const unsigned smcs0_b_1_pins[] = { DB8500_PIN_E8 }; +static const unsigned ipgpio7_b_1_pins[] = { DB8500_PIN_B11 }; +static const unsigned ipgpio2_b_1_pins[] = { DB8500_PIN_C12 }; +static const unsigned ipgpio3_b_1_pins[] = { DB8500_PIN_C11 }; +static const unsigned lcdaclk_b_1_pins[] = { DB8500_PIN_C14 }; +static const unsigned lcda_b_1_pins[] = { DB8500_PIN_D22, + DB8500_PIN_C23, DB8500_PIN_D23 }; +static const unsigned lcd_b_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16, + DB8500_PIN_B17, DB8500_PIN_C16, DB8500_PIN_C19, DB8500_PIN_C17, + DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19, DB8500_PIN_B20, + DB8500_PIN_D21, DB8500_PIN_D20, DB8500_PIN_C20, DB8500_PIN_B21, + DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24, DB8500_PIN_C22 }; +static const unsigned ddrtrig_b_1_pins[] = { DB8500_PIN_AJ27 }; +static const unsigned pwl_b_1_pins[] = { DB8500_PIN_AF25 }; +static const unsigned spi1_b_1_pins[] = { DB8500_PIN_AG15, DB8500_PIN_AF13, + DB8500_PIN_AG13, DB8500_PIN_AH15 }; +static const unsigned mc3_b_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AG12, + DB8500_PIN_AH12, DB8500_PIN_AH11, DB8500_PIN_AG10, DB8500_PIN_AH10, + DB8500_PIN_AJ11, DB8500_PIN_AJ9, DB8500_PIN_AH9, DB8500_PIN_AG9, + DB8500_PIN_AG8 }; +static const unsigned pwl_b_2_pins[] = { DB8500_PIN_AF8 }; +static const unsigned pwl_b_3_pins[] = { DB8500_PIN_AG7 }; +static const unsigned pwl_b_4_pins[] = { DB8500_PIN_AF7 }; + +/* Altfunction C column */ +static const unsigned ipjtag_c_1_pins[] = { DB8500_PIN_AJ5, DB8500_PIN_AJ3, + DB8500_PIN_AH4, DB8500_PIN_AH3, DB8500_PIN_AH6 }; +static const unsigned ipgpio6_c_1_pins[] = { DB8500_PIN_AG6 }; +static const unsigned ipgpio0_c_1_pins[] = { DB8500_PIN_AF6 }; +static const unsigned ipgpio1_c_1_pins[] = { DB8500_PIN_AG5 }; +static const unsigned ipgpio3_c_1_pins[] = { DB8500_PIN_AF5 }; +static const unsigned ipgpio2_c_1_pins[] = { DB8500_PIN_AG4 }; +static const unsigned slim0_c_1_pins[] = { DB8500_PIN_AD3, DB8500_PIN_AD4 }; +/* Optional 4-bit Memory Stick interface */ +static const unsigned ms_c_1_pins[] = { DB8500_PIN_AC2, DB8500_PIN_AC1, + DB8500_PIN_AB3, DB8500_PIN_AA3, DB8500_PIN_AA4, DB8500_PIN_AB2, + DB8500_PIN_Y4, DB8500_PIN_Y2, DB8500_PIN_AA2, DB8500_PIN_AA1 }; +static const unsigned iptrigout_c_1_pins[] = { DB8500_PIN_AB4 }; +static const unsigned u2rxtx_c_1_pins[] = { DB8500_PIN_W2, DB8500_PIN_W3 }; +static const unsigned u2ctsrts_c_1_pins[] = { DB8500_PIN_V3, DB8500_PIN_V2 }; +static const unsigned u0_c_1_pins[] = { DB8500_PIN_AF2, DB8500_PIN_AE1, + DB8500_PIN_AE2, DB8500_PIN_AG2 }; +static const unsigned ipgpio4_c_1_pins[] = { DB8500_PIN_F3 }; +static const unsigned ipgpio5_c_1_pins[] = { DB8500_PIN_F1 }; +static const unsigned ipgpio6_c_2_pins[] = { DB8500_PIN_G3 }; +static const unsigned ipgpio7_c_1_pins[] = { DB8500_PIN_G2 }; +static const unsigned smcleale_c_1_pins[] = { DB8500_PIN_E1, DB8500_PIN_E2 }; +static const unsigned stmape_c_1_pins[] = { DB8500_PIN_G5, DB8500_PIN_G4, + DB8500_PIN_H4, DB8500_PIN_H3, DB8500_PIN_J3 }; +static const unsigned u2rxtx_c_2_pins[] = { DB8500_PIN_H2, DB8500_PIN_J2 }; +static const unsigned ipgpio2_c_2_pins[] = { DB8500_PIN_F4 }; +static const unsigned ipgpio3_c_2_pins[] = { DB8500_PIN_E3 }; +static const unsigned ipgpio4_c_2_pins[] = { DB8500_PIN_E4 }; +static const unsigned ipgpio5_c_2_pins[] = { DB8500_PIN_D2 }; +static const unsigned mc5_c_1_pins[] = { DB8500_PIN_C6, DB8500_PIN_B3, + DB8500_PIN_C4, DB8500_PIN_E6, DB8500_PIN_A3, DB8500_PIN_B6, + DB8500_PIN_D6, DB8500_PIN_B7, DB8500_PIN_D7, DB8500_PIN_D8, + DB8500_PIN_D9 }; +static const unsigned mc2rstn_c_1_pins[] = { DB8500_PIN_C8 }; +static const unsigned kp_c_1_pins[] = { DB8500_PIN_C9, DB8500_PIN_B11, + DB8500_PIN_C12, DB8500_PIN_C11, DB8500_PIN_D17, DB8500_PIN_D16, + DB8500_PIN_C23, DB8500_PIN_D23 }; +static const unsigned smps1_c_1_pins[] = { DB8500_PIN_B14 }; +static const unsigned u2rxtx_c_3_pins[] = { DB8500_PIN_B17, DB8500_PIN_C16 }; +static const unsigned stmape_c_2_pins[] = { DB8500_PIN_C19, DB8500_PIN_C17, + DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19 }; +static const unsigned uartmodrx_c_1_pins[] = { DB8500_PIN_D21 }; +static const unsigned uartmodtx_c_1_pins[] = { DB8500_PIN_D20 }; +static const unsigned stmmod_c_1_pins[] = { DB8500_PIN_C20, DB8500_PIN_B21, + DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24 }; +static const unsigned usbsim_c_1_pins[] = { DB8500_PIN_D22 }; +static const unsigned mc4rstn_c_1_pins[] = { DB8500_PIN_AF25 }; +static const unsigned clkout_c_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AH12 }; +static const unsigned i2c3_c_1_pins[] = { DB8500_PIN_AG12, DB8500_PIN_AH11 }; +static const unsigned spi0_c_1_pins[] = { DB8500_PIN_AH10, DB8500_PIN_AH9, + DB8500_PIN_AG9, DB8500_PIN_AG8 }; +static const unsigned usbsim_c_2_pins[] = { DB8500_PIN_AF8 }; +static const unsigned i2c3_c_2_pins[] = { DB8500_PIN_AG7, DB8500_PIN_AF7 }; + +/* Other C1 column */ +static const unsigned kp_oc1_1_pins[] = { DB8500_PIN_C6, DB8500_PIN_B3, + DB8500_PIN_C4, DB8500_PIN_E6, DB8500_PIN_A3, DB8500_PIN_B6, + DB8500_PIN_D6, DB8500_PIN_B7 }; +static const unsigned spi2_oc1_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AG12, + DB8500_PIN_AH12, DB8500_PIN_AH11 }; + +#define DB8500_PIN_GROUP(a,b) { .name = #a, .pins = a##_pins, \ + .npins = ARRAY_SIZE(a##_pins), .altsetting = b } + +static const struct nmk_pingroup nmk_db8500_groups[] = { + /* Altfunction A column */ + DB8500_PIN_GROUP(u0_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(u1rxtx_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(u1ctsrts_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(ipi2c_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(ipi2c_a_2, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(msp0txrx_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(msp0tfstck_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(msp0rfsrck_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(mc0_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(msp1txrx_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(msp1_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(lcdb_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(lcdvsi0_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(lcdvsi1_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(lcd_d0_d7_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(lcd_d8_d11_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(lcd_d12_d23_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(kp_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(mc2_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(ssp1_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(ssp0_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(i2c0_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(ipgpio0_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(ipgpio1_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(msp2sck_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(msp2_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(mc4_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(mc1_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(hsir_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(hsit_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(clkout_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(clkout_a_2, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(usb_a_1, NMK_GPIO_ALT_A), + /* Altfunction B column */ + DB8500_PIN_GROUP(trig_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(i2c4_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(i2c1_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(i2c2_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(i2c2_b_2, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(msp0txrx_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(i2c1_b_2, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(u2rxtx_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(uartmodtx_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(msp0sck_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(uartmodrx_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(stmmod_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(uartmodrx_b_2, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(spi3_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(msp1txrx_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(kp_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(sm_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(smcs0_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(ipgpio7_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(ipgpio2_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(ipgpio3_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(lcdaclk_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(lcda_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(lcd_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(ddrtrig_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(pwl_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(spi1_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(mc3_b_1, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(pwl_b_2, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(pwl_b_3, NMK_GPIO_ALT_B), + DB8500_PIN_GROUP(pwl_b_4, NMK_GPIO_ALT_B), + /* Altfunction C column */ + DB8500_PIN_GROUP(ipjtag_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ipgpio6_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ipgpio0_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ipgpio1_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ipgpio3_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ipgpio2_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(slim0_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ms_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(iptrigout_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(u2rxtx_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(u2ctsrts_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(u0_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ipgpio4_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ipgpio5_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ipgpio6_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ipgpio7_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(smcleale_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(stmape_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(u2rxtx_c_2, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ipgpio2_c_2, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ipgpio3_c_2, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ipgpio4_c_2, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(ipgpio5_c_2, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(mc5_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(mc2rstn_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(kp_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(smps1_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(u2rxtx_c_3, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(stmape_c_2, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(uartmodrx_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(uartmodtx_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(stmmod_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(usbsim_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(mc4rstn_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(clkout_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(i2c3_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(spi0_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(usbsim_c_2, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(i2c3_c_2, NMK_GPIO_ALT_C), + /* Other alt C1 column, these are still configured as alt C */ + DB8500_PIN_GROUP(kp_oc1_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(spi2_oc1_1, NMK_GPIO_ALT_C), +}; + +/* We use this macro to define the groups applicable to a function */ +#define DB8500_FUNC_GROUPS(a, b...) \ +static const char * const a##_groups[] = { b }; + +DB8500_FUNC_GROUPS(u0, "u0_a_1", "u0_c_1"); +DB8500_FUNC_GROUPS(u1, "u1rxtx_a_1", "u1ctsrts_a_1"); +/* + * UART2 can be muxed out with just RX/TX in four places, CTS+RTS is however + * only available on two pins in alternative function C + */ +DB8500_FUNC_GROUPS(u2, "u2rxtx_b_1", "u2rxtx_c_1", "u2ctsrts_c_1", + "u2rxtx_c_2", "u2rxtx_c_3"); +DB8500_FUNC_GROUPS(ipi2c, "ipi2c_a_1", "ipi2c_a_2"); +/* + * MSP0 can only be on a certain set of pins, but the TX/RX pins can be + * switched around by selecting the altfunction A or B. The SCK pin is + * only available on the altfunction B. + */ +DB8500_FUNC_GROUPS(msp0, "msp0txrx_a_1", "msp0tfstck_a_1", "msp0rfstck_a_1", + "msp0txrx_b_1", "msp0sck_b_1"); +DB8500_FUNC_GROUPS(mc0, "mc0_a_1"); +/* MSP0 can swap RX/TX like MSP0 but has no SCK pin available */ +DB8500_FUNC_GROUPS(msp1, "msp1txrx_a_1", "msp1_a_1", "msp1txrx_b_1"); +DB8500_FUNC_GROUPS(lcdb, "lcdb_a_1"); +DB8500_FUNC_GROUPS(lcd, "lcdvsi0_a_1", "lcdvsi1_a_1", "lcd_d0_d7_a_1", + "lcd_d8_d11_a_1", "lcd_d12_d23_a_1", "lcd_b_1"); +DB8500_FUNC_GROUPS(kp, "kp_a_1", "kp_b_1", "kp_c_1", "kp_oc1_1"); +DB8500_FUNC_GROUPS(mc2, "mc2_a_1", "mc2rstn_c_1"); +DB8500_FUNC_GROUPS(ssp1, "ssp1_a_1"); +DB8500_FUNC_GROUPS(ssp0, "ssp0_a_1"); +DB8500_FUNC_GROUPS(i2c0, "i2c0_a_1"); +/* The image processor has 8 GPIO pins that can be muxed out */ +DB8500_FUNC_GROUPS(ipgpio, "ipgpio0_a_1", "ipgpio1_a_1", "ipgpio7_b_1", + "ipgpio2_b_1", "ipgpio3_b_1", "ipgpio6_c_1", "ipgpio0_c_1", + "ipgpio1_c_1", "ipgpio3_c_1", "ipgpio2_c_1", "ipgpio4_c_1", + "ipgpio5_c_1", "ipgpio6_c_2", "ipgpio7_c_1", "ipgpio2_c_2", + "ipgpio3_c_2", "ipgpio4_c_2", "ipgpio5_c_2"); +/* MSP2 can not invert the RX/TX pins but has the optional SCK pin */ +DB8500_FUNC_GROUPS(msp2, "msp2sck_a_1", "msp2_a_1"); +DB8500_FUNC_GROUPS(mc4, "mc4_a_1", "mc4rstn_c_1"); +DB8500_FUNC_GROUPS(mc1, "mc1_a_1", "mc1dir_a_1"); +DB8500_FUNC_GROUPS(hsi, "hsir1_a_1", "hsit1_a_1"); +DB8500_FUNC_GROUPS(clkout, "clkout_a_1", "clkout_a_2", "clkout_c_1"); +DB8500_FUNC_GROUPS(usb, "usb_a_1"); +DB8500_FUNC_GROUPS(trig, "trig_b_1"); +DB8500_FUNC_GROUPS(i2c4, "i2c4_b_1"); +DB8500_FUNC_GROUPS(i2c1, "i2c1_b_1", "i2c1_b_2"); +DB8500_FUNC_GROUPS(i2c2, "i2c2_b_1", "i2c2_b_2"); +/* + * The modem UART can output its RX and TX pins in some different places, + * so select one of each. + */ +DB8500_FUNC_GROUPS(uartmod, "uartmodtx_b_1", "uartmodrx_b_1", "uartmodrx_b_2", + "uartmodrx_c_1", "uartmod_tx_c_1"); +DB8500_FUNC_GROUPS(stmmod, "stmmod_b_1", "stmmod_c_1"); +DB8500_FUNC_GROUPS(spi3, "spi3_b_1"); +/* Select between CS0 on alt B or PS1 on alt C */ +DB8500_FUNC_GROUPS(sm, "sm_b_1", "smcs0_b_1", "smcleale_c_1", "smps1_c_1"); +DB8500_FUNC_GROUPS(lcda, "lcdaclk_b_1", "lcda_b_1"); +DB8500_FUNC_GROUPS(ddrtrig, "ddrtrig_b_1"); +DB8500_FUNC_GROUPS(pwl, "pwl_b_1", "pwl_b_2", "pwl_b_3", "pwl_b_4"); +DB8500_FUNC_GROUPS(spi1, "spi1_b_1"); +DB8500_FUNC_GROUPS(mc3, "mc3_b_1"); +DB8500_FUNC_GROUPS(ipjtag, "ipjtag_c_1"); +DB8500_FUNC_GROUPS(slim0, "slim0_c_1"); +DB8500_FUNC_GROUPS(ms, "ms_c_1"); +DB8500_FUNC_GROUPS(iptrigout, "iptrigout_c_1"); +DB8500_FUNC_GROUPS(stmape, "stmape_c_1", "stmape_c_2"); +DB8500_FUNC_GROUPS(mc5, "mc5_c_1"); +DB8500_FUNC_GROUPS(usbsim, "usbsim_c_1", "usbsim_c_2"); +DB8500_FUNC_GROUPS(i2c3, "i2c3_c_1", "i2c3_c_2"); +DB8500_FUNC_GROUPS(spi0, "spi0_c_1"); +DB8500_FUNC_GROUPS(spi2, "spi2_oc1_1"); + +#define FUNCTION(fname) \ + { \ + .name = #fname, \ + .groups = fname##_groups, \ + .ngroups = ARRAY_SIZE(fname##_groups), \ + } + +static const struct nmk_function nmk_db8500_functions[] = { + FUNCTION(u0), + FUNCTION(u1), + FUNCTION(u2), + FUNCTION(ipi2c), + FUNCTION(msp0), + FUNCTION(mc0), + FUNCTION(msp1), + FUNCTION(lcdb), + FUNCTION(lcd), + FUNCTION(kp), + FUNCTION(mc2), + FUNCTION(ssp1), + FUNCTION(ssp0), + FUNCTION(i2c0), + FUNCTION(ipgpio), + FUNCTION(msp2), + FUNCTION(mc4), + FUNCTION(mc1), + FUNCTION(hsi), + FUNCTION(clkout), + FUNCTION(usb), + FUNCTION(trig), + FUNCTION(i2c4), + FUNCTION(i2c1), + FUNCTION(i2c2), + FUNCTION(uartmod), + FUNCTION(stmmod), + FUNCTION(spi3), + FUNCTION(sm), + FUNCTION(lcda), + FUNCTION(ddrtrig), + FUNCTION(pwl), + FUNCTION(spi1), + FUNCTION(mc3), + FUNCTION(ipjtag), + FUNCTION(slim0), + FUNCTION(ms), + FUNCTION(iptrigout), + FUNCTION(stmape), + FUNCTION(mc5), + FUNCTION(usbsim), + FUNCTION(i2c3), + FUNCTION(spi0), + FUNCTION(spi2), +}; + +static const struct nmk_pinctrl_soc_data nmk_db8500_soc = { + .gpio_ranges = nmk_db8500_ranges, + .gpio_num_ranges = ARRAY_SIZE(nmk_db8500_ranges), + .pins = nmk_db8500_pins, + .npins = ARRAY_SIZE(nmk_db8500_pins), + .functions = nmk_db8500_functions, + .nfunctions = ARRAY_SIZE(nmk_db8500_functions), + .groups = nmk_db8500_groups, + .ngroups = ARRAY_SIZE(nmk_db8500_groups), +}; + +void __devinit +nmk_pinctrl_db8500_init(const struct nmk_pinctrl_soc_data **soc) +{ + *soc = &nmk_db8500_soc; +} diff --git a/trunk/drivers/pinctrl/pinctrl-nomadik.c b/trunk/drivers/pinctrl/pinctrl-nomadik.c new file mode 100644 index 000000000000..b8e01c3eaa95 --- /dev/null +++ b/trunk/drivers/pinctrl/pinctrl-nomadik.c @@ -0,0 +1,1780 @@ +/* + * Generic GPIO driver for logic cells found in the Nomadik SoC + * + * Copyright (C) 2008,2009 STMicroelectronics + * Copyright (C) 2009 Alessandro Rubini + * Rewritten based on work by Prafulla WADASKAR + * Copyright (C) 2011 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 +#include +#include +/* Since we request GPIOs from ourself */ +#include + +#include + +#include +#include + +#include "pinctrl-nomadik.h" + +/* + * The GPIO module in the Nomadik family of Systems-on-Chip is an + * AMBA device, managing 32 pins and alternate functions. The logic block + * is currently used in the Nomadik and ux500. + * + * Symbols in this file are called "nmk_gpio" for "nomadik gpio" + */ + +#define NMK_GPIO_PER_CHIP 32 + +struct nmk_gpio_chip { + struct gpio_chip chip; + struct irq_domain *domain; + void __iomem *addr; + struct clk *clk; + unsigned int bank; + unsigned int parent_irq; + int secondary_parent_irq; + u32 (*get_secondary_status)(unsigned int bank); + void (*set_ioforce)(bool enable); + spinlock_t lock; + bool sleepmode; + /* Keep track of configured edges */ + u32 edge_rising; + u32 edge_falling; + u32 real_wake; + u32 rwimsc; + u32 fwimsc; + u32 rimsc; + u32 fimsc; + u32 pull_up; + u32 lowemi; +}; + +struct nmk_pinctrl { + struct device *dev; + struct pinctrl_dev *pctl; + const struct nmk_pinctrl_soc_data *soc; +}; + +static struct nmk_gpio_chip * +nmk_gpio_chips[DIV_ROUND_UP(ARCH_NR_GPIOS, NMK_GPIO_PER_CHIP)]; + +static DEFINE_SPINLOCK(nmk_gpio_slpm_lock); + +#define NUM_BANKS ARRAY_SIZE(nmk_gpio_chips) + +static void __nmk_gpio_set_mode(struct nmk_gpio_chip *nmk_chip, + unsigned offset, int gpio_mode) +{ + u32 bit = 1 << offset; + u32 afunc, bfunc; + + afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & ~bit; + bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & ~bit; + if (gpio_mode & NMK_GPIO_ALT_A) + afunc |= bit; + if (gpio_mode & NMK_GPIO_ALT_B) + bfunc |= bit; + writel(afunc, nmk_chip->addr + NMK_GPIO_AFSLA); + writel(bfunc, nmk_chip->addr + NMK_GPIO_AFSLB); +} + +static void __nmk_gpio_set_slpm(struct nmk_gpio_chip *nmk_chip, + unsigned offset, enum nmk_gpio_slpm mode) +{ + u32 bit = 1 << offset; + u32 slpm; + + slpm = readl(nmk_chip->addr + NMK_GPIO_SLPC); + if (mode == NMK_GPIO_SLPM_NOCHANGE) + slpm |= bit; + else + slpm &= ~bit; + writel(slpm, nmk_chip->addr + NMK_GPIO_SLPC); +} + +static void __nmk_gpio_set_pull(struct nmk_gpio_chip *nmk_chip, + unsigned offset, enum nmk_gpio_pull pull) +{ + u32 bit = 1 << offset; + u32 pdis; + + pdis = readl(nmk_chip->addr + NMK_GPIO_PDIS); + if (pull == NMK_GPIO_PULL_NONE) { + pdis |= bit; + nmk_chip->pull_up &= ~bit; + } else { + pdis &= ~bit; + } + + writel(pdis, nmk_chip->addr + NMK_GPIO_PDIS); + + if (pull == NMK_GPIO_PULL_UP) { + nmk_chip->pull_up |= bit; + writel(bit, nmk_chip->addr + NMK_GPIO_DATS); + } else if (pull == NMK_GPIO_PULL_DOWN) { + nmk_chip->pull_up &= ~bit; + writel(bit, nmk_chip->addr + NMK_GPIO_DATC); + } +} + +static void __nmk_gpio_set_lowemi(struct nmk_gpio_chip *nmk_chip, + unsigned offset, bool lowemi) +{ + u32 bit = BIT(offset); + bool enabled = nmk_chip->lowemi & bit; + + if (lowemi == enabled) + return; + + if (lowemi) + nmk_chip->lowemi |= bit; + else + nmk_chip->lowemi &= ~bit; + + writel_relaxed(nmk_chip->lowemi, + nmk_chip->addr + NMK_GPIO_LOWEMI); +} + +static void __nmk_gpio_make_input(struct nmk_gpio_chip *nmk_chip, + unsigned offset) +{ + writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRC); +} + +static void __nmk_gpio_set_output(struct nmk_gpio_chip *nmk_chip, + unsigned offset, int val) +{ + if (val) + writel(1 << offset, nmk_chip->addr + NMK_GPIO_DATS); + else + writel(1 << offset, nmk_chip->addr + NMK_GPIO_DATC); +} + +static void __nmk_gpio_make_output(struct nmk_gpio_chip *nmk_chip, + unsigned offset, int val) +{ + writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRS); + __nmk_gpio_set_output(nmk_chip, offset, val); +} + +static void __nmk_gpio_set_mode_safe(struct nmk_gpio_chip *nmk_chip, + unsigned offset, int gpio_mode, + bool glitch) +{ + u32 rwimsc = nmk_chip->rwimsc; + u32 fwimsc = nmk_chip->fwimsc; + + if (glitch && nmk_chip->set_ioforce) { + u32 bit = BIT(offset); + + /* Prevent spurious wakeups */ + writel(rwimsc & ~bit, nmk_chip->addr + NMK_GPIO_RWIMSC); + writel(fwimsc & ~bit, nmk_chip->addr + NMK_GPIO_FWIMSC); + + nmk_chip->set_ioforce(true); + } + + __nmk_gpio_set_mode(nmk_chip, offset, gpio_mode); + + if (glitch && nmk_chip->set_ioforce) { + nmk_chip->set_ioforce(false); + + writel(rwimsc, nmk_chip->addr + NMK_GPIO_RWIMSC); + writel(fwimsc, nmk_chip->addr + NMK_GPIO_FWIMSC); + } +} + +static void +nmk_gpio_disable_lazy_irq(struct nmk_gpio_chip *nmk_chip, unsigned offset) +{ + u32 falling = nmk_chip->fimsc & BIT(offset); + u32 rising = nmk_chip->rimsc & BIT(offset); + int gpio = nmk_chip->chip.base + offset; + int irq = NOMADIK_GPIO_TO_IRQ(gpio); + struct irq_data *d = irq_get_irq_data(irq); + + if (!rising && !falling) + return; + + if (!d || !irqd_irq_disabled(d)) + return; + + if (rising) { + nmk_chip->rimsc &= ~BIT(offset); + writel_relaxed(nmk_chip->rimsc, + nmk_chip->addr + NMK_GPIO_RIMSC); + } + + if (falling) { + nmk_chip->fimsc &= ~BIT(offset); + writel_relaxed(nmk_chip->fimsc, + nmk_chip->addr + NMK_GPIO_FIMSC); + } + + dev_dbg(nmk_chip->chip.dev, "%d: clearing interrupt mask\n", gpio); +} + +static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset, + pin_cfg_t cfg, bool sleep, unsigned int *slpmregs) +{ + static const char *afnames[] = { + [NMK_GPIO_ALT_GPIO] = "GPIO", + [NMK_GPIO_ALT_A] = "A", + [NMK_GPIO_ALT_B] = "B", + [NMK_GPIO_ALT_C] = "C" + }; + static const char *pullnames[] = { + [NMK_GPIO_PULL_NONE] = "none", + [NMK_GPIO_PULL_UP] = "up", + [NMK_GPIO_PULL_DOWN] = "down", + [3] /* illegal */ = "??" + }; + static const char *slpmnames[] = { + [NMK_GPIO_SLPM_INPUT] = "input/wakeup", + [NMK_GPIO_SLPM_NOCHANGE] = "no-change/no-wakeup", + }; + + int pin = PIN_NUM(cfg); + int pull = PIN_PULL(cfg); + int af = PIN_ALT(cfg); + int slpm = PIN_SLPM(cfg); + int output = PIN_DIR(cfg); + int val = PIN_VAL(cfg); + bool glitch = af == NMK_GPIO_ALT_C; + + dev_dbg(nmk_chip->chip.dev, "pin %d [%#lx]: af %s, pull %s, slpm %s (%s%s)\n", + pin, cfg, afnames[af], pullnames[pull], slpmnames[slpm], + output ? "output " : "input", + output ? (val ? "high" : "low") : ""); + + if (sleep) { + int slpm_pull = PIN_SLPM_PULL(cfg); + int slpm_output = PIN_SLPM_DIR(cfg); + int slpm_val = PIN_SLPM_VAL(cfg); + + af = NMK_GPIO_ALT_GPIO; + + /* + * The SLPM_* values are normal values + 1 to allow zero to + * mean "same as normal". + */ + if (slpm_pull) + pull = slpm_pull - 1; + if (slpm_output) + output = slpm_output - 1; + if (slpm_val) + val = slpm_val - 1; + + dev_dbg(nmk_chip->chip.dev, "pin %d: sleep pull %s, dir %s, val %s\n", + pin, + slpm_pull ? pullnames[pull] : "same", + slpm_output ? (output ? "output" : "input") : "same", + slpm_val ? (val ? "high" : "low") : "same"); + } + + if (output) + __nmk_gpio_make_output(nmk_chip, offset, val); + else { + __nmk_gpio_make_input(nmk_chip, offset); + __nmk_gpio_set_pull(nmk_chip, offset, pull); + } + + __nmk_gpio_set_lowemi(nmk_chip, offset, PIN_LOWEMI(cfg)); + + /* + * If the pin is switching to altfunc, and there was an interrupt + * installed on it which has been lazy disabled, actually mask the + * interrupt to prevent spurious interrupts that would occur while the + * pin is under control of the peripheral. Only SKE does this. + */ + if (af != NMK_GPIO_ALT_GPIO) + nmk_gpio_disable_lazy_irq(nmk_chip, offset); + + /* + * If we've backed up the SLPM registers (glitch workaround), modify + * the backups since they will be restored. + */ + if (slpmregs) { + if (slpm == NMK_GPIO_SLPM_NOCHANGE) + slpmregs[nmk_chip->bank] |= BIT(offset); + else + slpmregs[nmk_chip->bank] &= ~BIT(offset); + } else + __nmk_gpio_set_slpm(nmk_chip, offset, slpm); + + __nmk_gpio_set_mode_safe(nmk_chip, offset, af, glitch); +} + +/* + * Safe sequence used to switch IOs between GPIO and Alternate-C mode: + * - Save SLPM registers + * - Set SLPM=0 for the IOs you want to switch and others to 1 + * - Configure the GPIO registers for the IOs that are being switched + * - Set IOFORCE=1 + * - Modify the AFLSA/B registers for the IOs that are being switched + * - Set IOFORCE=0 + * - Restore SLPM registers + * - Any spurious wake up event during switch sequence to be ignored and + * cleared + */ +static void nmk_gpio_glitch_slpm_init(unsigned int *slpm) +{ + int i; + + for (i = 0; i < NUM_BANKS; i++) { + struct nmk_gpio_chip *chip = nmk_gpio_chips[i]; + unsigned int temp = slpm[i]; + + if (!chip) + break; + + clk_enable(chip->clk); + + slpm[i] = readl(chip->addr + NMK_GPIO_SLPC); + writel(temp, chip->addr + NMK_GPIO_SLPC); + } +} + +static void nmk_gpio_glitch_slpm_restore(unsigned int *slpm) +{ + int i; + + for (i = 0; i < NUM_BANKS; i++) { + struct nmk_gpio_chip *chip = nmk_gpio_chips[i]; + + if (!chip) + break; + + writel(slpm[i], chip->addr + NMK_GPIO_SLPC); + + clk_disable(chip->clk); + } +} + +static int __nmk_config_pins(pin_cfg_t *cfgs, int num, bool sleep) +{ + static unsigned int slpm[NUM_BANKS]; + unsigned long flags; + bool glitch = false; + int ret = 0; + int i; + + for (i = 0; i < num; i++) { + if (PIN_ALT(cfgs[i]) == NMK_GPIO_ALT_C) { + glitch = true; + break; + } + } + + spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); + + if (glitch) { + memset(slpm, 0xff, sizeof(slpm)); + + for (i = 0; i < num; i++) { + int pin = PIN_NUM(cfgs[i]); + int offset = pin % NMK_GPIO_PER_CHIP; + + if (PIN_ALT(cfgs[i]) == NMK_GPIO_ALT_C) + slpm[pin / NMK_GPIO_PER_CHIP] &= ~BIT(offset); + } + + nmk_gpio_glitch_slpm_init(slpm); + } + + for (i = 0; i < num; i++) { + struct nmk_gpio_chip *nmk_chip; + int pin = PIN_NUM(cfgs[i]); + + nmk_chip = nmk_gpio_chips[pin / NMK_GPIO_PER_CHIP]; + if (!nmk_chip) { + ret = -EINVAL; + break; + } + + clk_enable(nmk_chip->clk); + spin_lock(&nmk_chip->lock); + __nmk_config_pin(nmk_chip, pin % NMK_GPIO_PER_CHIP, + cfgs[i], sleep, glitch ? slpm : NULL); + spin_unlock(&nmk_chip->lock); + clk_disable(nmk_chip->clk); + } + + if (glitch) + nmk_gpio_glitch_slpm_restore(slpm); + + spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags); + + return ret; +} + +/** + * nmk_config_pin - configure a pin's mux attributes + * @cfg: pin confguration + * + * Configures a pin's mode (alternate function or GPIO), its pull up status, + * and its sleep mode based on the specified configuration. The @cfg is + * usually one of the SoC specific macros defined in mach/-pins.h. These + * are constructed using, and can be further enhanced with, the macros in + * plat/pincfg.h. + * + * If a pin's mode is set to GPIO, it is configured as an input to avoid + * side-effects. The gpio can be manipulated later using standard GPIO API + * calls. + */ +int nmk_config_pin(pin_cfg_t cfg, bool sleep) +{ + return __nmk_config_pins(&cfg, 1, sleep); +} +EXPORT_SYMBOL(nmk_config_pin); + +/** + * nmk_config_pins - configure several pins at once + * @cfgs: array of pin configurations + * @num: number of elments in the array + * + * Configures several pins using nmk_config_pin(). Refer to that function for + * further information. + */ +int nmk_config_pins(pin_cfg_t *cfgs, int num) +{ + return __nmk_config_pins(cfgs, num, false); +} +EXPORT_SYMBOL(nmk_config_pins); + +int nmk_config_pins_sleep(pin_cfg_t *cfgs, int num) +{ + return __nmk_config_pins(cfgs, num, true); +} +EXPORT_SYMBOL(nmk_config_pins_sleep); + +/** + * nmk_gpio_set_slpm() - configure the sleep mode of a pin + * @gpio: pin number + * @mode: NMK_GPIO_SLPM_INPUT or NMK_GPIO_SLPM_NOCHANGE, + * + * This register is actually in the pinmux layer, not the GPIO block itself. + * The GPIO1B_SLPM register defines the GPIO mode when SLEEP/DEEP-SLEEP + * mode is entered (i.e. when signal IOFORCE is HIGH by the platform code). + * Each GPIO can be configured to be forced into GPIO mode when IOFORCE is + * HIGH, overriding the normal setting defined by GPIO_AFSELx registers. + * When IOFORCE returns LOW (by software, after SLEEP/DEEP-SLEEP exit), + * the GPIOs return to the normal setting defined by GPIO_AFSELx registers. + * + * If @mode is NMK_GPIO_SLPM_INPUT, the corresponding GPIO is switched to GPIO + * mode when signal IOFORCE is HIGH (i.e. when SLEEP/DEEP-SLEEP mode is + * entered) regardless of the altfunction selected. Also wake-up detection is + * ENABLED. + * + * If @mode is NMK_GPIO_SLPM_NOCHANGE, the corresponding GPIO remains + * controlled by NMK_GPIO_DATC, NMK_GPIO_DATS, NMK_GPIO_DIR, NMK_GPIO_PDIS + * (for altfunction GPIO) or respective on-chip peripherals (for other + * altfuncs) when IOFORCE is HIGH. Also wake-up detection DISABLED. + * + * Note that enable_irq_wake() will automatically enable wakeup detection. + */ +int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode) +{ + struct nmk_gpio_chip *nmk_chip; + unsigned long flags; + + nmk_chip = nmk_gpio_chips[gpio / NMK_GPIO_PER_CHIP]; + if (!nmk_chip) + return -EINVAL; + + clk_enable(nmk_chip->clk); + spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); + spin_lock(&nmk_chip->lock); + + __nmk_gpio_set_slpm(nmk_chip, gpio % NMK_GPIO_PER_CHIP, mode); + + spin_unlock(&nmk_chip->lock); + spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags); + clk_disable(nmk_chip->clk); + + return 0; +} + +/** + * nmk_gpio_set_pull() - enable/disable pull up/down on a gpio + * @gpio: pin number + * @pull: one of NMK_GPIO_PULL_DOWN, NMK_GPIO_PULL_UP, and NMK_GPIO_PULL_NONE + * + * Enables/disables pull up/down on a specified pin. This only takes effect if + * the pin is configured as an input (either explicitly or by the alternate + * function). + * + * NOTE: If enabling the pull up/down, the caller must ensure that the GPIO is + * configured as an input. Otherwise, due to the way the controller registers + * work, this function will change the value output on the pin. + */ +int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull) +{ + struct nmk_gpio_chip *nmk_chip; + unsigned long flags; + + nmk_chip = nmk_gpio_chips[gpio / NMK_GPIO_PER_CHIP]; + if (!nmk_chip) + return -EINVAL; + + clk_enable(nmk_chip->clk); + spin_lock_irqsave(&nmk_chip->lock, flags); + __nmk_gpio_set_pull(nmk_chip, gpio % NMK_GPIO_PER_CHIP, pull); + spin_unlock_irqrestore(&nmk_chip->lock, flags); + clk_disable(nmk_chip->clk); + + return 0; +} + +/* Mode functions */ +/** + * nmk_gpio_set_mode() - set the mux mode of a gpio pin + * @gpio: pin number + * @gpio_mode: one of NMK_GPIO_ALT_GPIO, NMK_GPIO_ALT_A, + * NMK_GPIO_ALT_B, and NMK_GPIO_ALT_C + * + * Sets the mode of the specified pin to one of the alternate functions or + * plain GPIO. + */ +int nmk_gpio_set_mode(int gpio, int gpio_mode) +{ + struct nmk_gpio_chip *nmk_chip; + unsigned long flags; + + nmk_chip = nmk_gpio_chips[gpio / NMK_GPIO_PER_CHIP]; + if (!nmk_chip) + return -EINVAL; + + clk_enable(nmk_chip->clk); + spin_lock_irqsave(&nmk_chip->lock, flags); + __nmk_gpio_set_mode(nmk_chip, gpio % NMK_GPIO_PER_CHIP, gpio_mode); + spin_unlock_irqrestore(&nmk_chip->lock, flags); + clk_disable(nmk_chip->clk); + + return 0; +} +EXPORT_SYMBOL(nmk_gpio_set_mode); + +int nmk_gpio_get_mode(int gpio) +{ + struct nmk_gpio_chip *nmk_chip; + u32 afunc, bfunc, bit; + + nmk_chip = nmk_gpio_chips[gpio / NMK_GPIO_PER_CHIP]; + if (!nmk_chip) + return -EINVAL; + + bit = 1 << (gpio % NMK_GPIO_PER_CHIP); + + clk_enable(nmk_chip->clk); + + afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & bit; + bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & bit; + + clk_disable(nmk_chip->clk); + + return (afunc ? NMK_GPIO_ALT_A : 0) | (bfunc ? NMK_GPIO_ALT_B : 0); +} +EXPORT_SYMBOL(nmk_gpio_get_mode); + + +/* IRQ functions */ +static inline int nmk_gpio_get_bitmask(int gpio) +{ + return 1 << (gpio % NMK_GPIO_PER_CHIP); +} + +static void nmk_gpio_irq_ack(struct irq_data *d) +{ + struct nmk_gpio_chip *nmk_chip; + + nmk_chip = irq_data_get_irq_chip_data(d); + if (!nmk_chip) + return; + + clk_enable(nmk_chip->clk); + writel(nmk_gpio_get_bitmask(d->hwirq), nmk_chip->addr + NMK_GPIO_IC); + clk_disable(nmk_chip->clk); +} + +enum nmk_gpio_irq_type { + NORMAL, + WAKE, +}; + +static void __nmk_gpio_irq_modify(struct nmk_gpio_chip *nmk_chip, + int gpio, enum nmk_gpio_irq_type which, + bool enable) +{ + u32 bitmask = nmk_gpio_get_bitmask(gpio); + u32 *rimscval; + u32 *fimscval; + u32 rimscreg; + u32 fimscreg; + + if (which == NORMAL) { + rimscreg = NMK_GPIO_RIMSC; + fimscreg = NMK_GPIO_FIMSC; + rimscval = &nmk_chip->rimsc; + fimscval = &nmk_chip->fimsc; + } else { + rimscreg = NMK_GPIO_RWIMSC; + fimscreg = NMK_GPIO_FWIMSC; + rimscval = &nmk_chip->rwimsc; + fimscval = &nmk_chip->fwimsc; + } + + /* we must individually set/clear the two edges */ + if (nmk_chip->edge_rising & bitmask) { + if (enable) + *rimscval |= bitmask; + else + *rimscval &= ~bitmask; + writel(*rimscval, nmk_chip->addr + rimscreg); + } + if (nmk_chip->edge_falling & bitmask) { + if (enable) + *fimscval |= bitmask; + else + *fimscval &= ~bitmask; + writel(*fimscval, nmk_chip->addr + fimscreg); + } +} + +static void __nmk_gpio_set_wake(struct nmk_gpio_chip *nmk_chip, + int gpio, bool on) +{ + /* + * Ensure WAKEUP_ENABLE is on. No need to disable it if wakeup is + * disabled, since setting SLPM to 1 increases power consumption, and + * wakeup is anyhow controlled by the RIMSC and FIMSC registers. + */ + if (nmk_chip->sleepmode && on) { + __nmk_gpio_set_slpm(nmk_chip, gpio % nmk_chip->chip.base, + NMK_GPIO_SLPM_WAKEUP_ENABLE); + } + + __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, on); +} + +static int nmk_gpio_irq_maskunmask(struct irq_data *d, bool enable) +{ + struct nmk_gpio_chip *nmk_chip; + unsigned long flags; + u32 bitmask; + + nmk_chip = irq_data_get_irq_chip_data(d); + bitmask = nmk_gpio_get_bitmask(d->hwirq); + if (!nmk_chip) + return -EINVAL; + + clk_enable(nmk_chip->clk); + spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); + spin_lock(&nmk_chip->lock); + + __nmk_gpio_irq_modify(nmk_chip, d->hwirq, NORMAL, enable); + + if (!(nmk_chip->real_wake & bitmask)) + __nmk_gpio_set_wake(nmk_chip, d->hwirq, enable); + + spin_unlock(&nmk_chip->lock); + spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags); + clk_disable(nmk_chip->clk); + + return 0; +} + +static void nmk_gpio_irq_mask(struct irq_data *d) +{ + nmk_gpio_irq_maskunmask(d, false); +} + +static void nmk_gpio_irq_unmask(struct irq_data *d) +{ + nmk_gpio_irq_maskunmask(d, true); +} + +static int nmk_gpio_irq_set_wake(struct irq_data *d, unsigned int on) +{ + struct nmk_gpio_chip *nmk_chip; + unsigned long flags; + u32 bitmask; + + nmk_chip = irq_data_get_irq_chip_data(d); + if (!nmk_chip) + return -EINVAL; + bitmask = nmk_gpio_get_bitmask(d->hwirq); + + clk_enable(nmk_chip->clk); + spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); + spin_lock(&nmk_chip->lock); + + if (irqd_irq_disabled(d)) + __nmk_gpio_set_wake(nmk_chip, d->hwirq, on); + + if (on) + nmk_chip->real_wake |= bitmask; + else + nmk_chip->real_wake &= ~bitmask; + + spin_unlock(&nmk_chip->lock); + spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags); + clk_disable(nmk_chip->clk); + + return 0; +} + +static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type) +{ + bool enabled = !irqd_irq_disabled(d); + bool wake = irqd_is_wakeup_set(d); + struct nmk_gpio_chip *nmk_chip; + unsigned long flags; + u32 bitmask; + + nmk_chip = irq_data_get_irq_chip_data(d); + bitmask = nmk_gpio_get_bitmask(d->hwirq); + if (!nmk_chip) + return -EINVAL; + if (type & IRQ_TYPE_LEVEL_HIGH) + return -EINVAL; + if (type & IRQ_TYPE_LEVEL_LOW) + return -EINVAL; + + clk_enable(nmk_chip->clk); + spin_lock_irqsave(&nmk_chip->lock, flags); + + if (enabled) + __nmk_gpio_irq_modify(nmk_chip, d->hwirq, NORMAL, false); + + if (enabled || wake) + __nmk_gpio_irq_modify(nmk_chip, d->hwirq, WAKE, false); + + nmk_chip->edge_rising &= ~bitmask; + if (type & IRQ_TYPE_EDGE_RISING) + nmk_chip->edge_rising |= bitmask; + + nmk_chip->edge_falling &= ~bitmask; + if (type & IRQ_TYPE_EDGE_FALLING) + nmk_chip->edge_falling |= bitmask; + + if (enabled) + __nmk_gpio_irq_modify(nmk_chip, d->hwirq, NORMAL, true); + + if (enabled || wake) + __nmk_gpio_irq_modify(nmk_chip, d->hwirq, WAKE, true); + + spin_unlock_irqrestore(&nmk_chip->lock, flags); + clk_disable(nmk_chip->clk); + + return 0; +} + +static unsigned int nmk_gpio_irq_startup(struct irq_data *d) +{ + struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d); + + clk_enable(nmk_chip->clk); + nmk_gpio_irq_unmask(d); + return 0; +} + +static void nmk_gpio_irq_shutdown(struct irq_data *d) +{ + struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d); + + nmk_gpio_irq_mask(d); + clk_disable(nmk_chip->clk); +} + +static struct irq_chip nmk_gpio_irq_chip = { + .name = "Nomadik-GPIO", + .irq_ack = nmk_gpio_irq_ack, + .irq_mask = nmk_gpio_irq_mask, + .irq_unmask = nmk_gpio_irq_unmask, + .irq_set_type = nmk_gpio_irq_set_type, + .irq_set_wake = nmk_gpio_irq_set_wake, + .irq_startup = nmk_gpio_irq_startup, + .irq_shutdown = nmk_gpio_irq_shutdown, +}; + +static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc, + u32 status) +{ + struct nmk_gpio_chip *nmk_chip; + struct irq_chip *host_chip = irq_get_chip(irq); + unsigned int first_irq; + + chained_irq_enter(host_chip, desc); + + nmk_chip = irq_get_handler_data(irq); + first_irq = nmk_chip->domain->revmap_data.legacy.first_irq; + while (status) { + int bit = __ffs(status); + + generic_handle_irq(first_irq + bit); + status &= ~BIT(bit); + } + + chained_irq_exit(host_chip, desc); +} + +static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + struct nmk_gpio_chip *nmk_chip = irq_get_handler_data(irq); + u32 status; + + clk_enable(nmk_chip->clk); + status = readl(nmk_chip->addr + NMK_GPIO_IS); + clk_disable(nmk_chip->clk); + + __nmk_gpio_irq_handler(irq, desc, status); +} + +static void nmk_gpio_secondary_irq_handler(unsigned int irq, + struct irq_desc *desc) +{ + struct nmk_gpio_chip *nmk_chip = irq_get_handler_data(irq); + u32 status = nmk_chip->get_secondary_status(nmk_chip->bank); + + __nmk_gpio_irq_handler(irq, desc, status); +} + +static int nmk_gpio_init_irq(struct nmk_gpio_chip *nmk_chip) +{ + irq_set_chained_handler(nmk_chip->parent_irq, nmk_gpio_irq_handler); + irq_set_handler_data(nmk_chip->parent_irq, nmk_chip); + + if (nmk_chip->secondary_parent_irq >= 0) { + irq_set_chained_handler(nmk_chip->secondary_parent_irq, + nmk_gpio_secondary_irq_handler); + irq_set_handler_data(nmk_chip->secondary_parent_irq, nmk_chip); + } + + return 0; +} + +/* I/O Functions */ + +static int nmk_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + /* + * Map back to global GPIO space and request muxing, the direction + * parameter does not matter for this controller. + */ + int gpio = chip->base + offset; + + return pinctrl_request_gpio(gpio); +} + +static void nmk_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + int gpio = chip->base + offset; + + pinctrl_free_gpio(gpio); +} + +static int nmk_gpio_make_input(struct gpio_chip *chip, unsigned offset) +{ + struct nmk_gpio_chip *nmk_chip = + container_of(chip, struct nmk_gpio_chip, chip); + + clk_enable(nmk_chip->clk); + + writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRC); + + clk_disable(nmk_chip->clk); + + return 0; +} + +static int nmk_gpio_get_input(struct gpio_chip *chip, unsigned offset) +{ + struct nmk_gpio_chip *nmk_chip = + container_of(chip, struct nmk_gpio_chip, chip); + u32 bit = 1 << offset; + int value; + + clk_enable(nmk_chip->clk); + + value = (readl(nmk_chip->addr + NMK_GPIO_DAT) & bit) != 0; + + clk_disable(nmk_chip->clk); + + return value; +} + +static void nmk_gpio_set_output(struct gpio_chip *chip, unsigned offset, + int val) +{ + struct nmk_gpio_chip *nmk_chip = + container_of(chip, struct nmk_gpio_chip, chip); + + clk_enable(nmk_chip->clk); + + __nmk_gpio_set_output(nmk_chip, offset, val); + + clk_disable(nmk_chip->clk); +} + +static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset, + int val) +{ + struct nmk_gpio_chip *nmk_chip = + container_of(chip, struct nmk_gpio_chip, chip); + + clk_enable(nmk_chip->clk); + + __nmk_gpio_make_output(nmk_chip, offset, val); + + clk_disable(nmk_chip->clk); + + return 0; +} + +static int nmk_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct nmk_gpio_chip *nmk_chip = + container_of(chip, struct nmk_gpio_chip, chip); + + return irq_find_mapping(nmk_chip->domain, offset); +} + +#ifdef CONFIG_DEBUG_FS + +#include + +static void nmk_gpio_dbg_show_one(struct seq_file *s, struct gpio_chip *chip, + unsigned offset, unsigned gpio) +{ + const char *label = gpiochip_is_requested(chip, offset); + struct nmk_gpio_chip *nmk_chip = + container_of(chip, struct nmk_gpio_chip, chip); + int mode; + bool is_out; + bool pull; + u32 bit = 1 << offset; + const char *modes[] = { + [NMK_GPIO_ALT_GPIO] = "gpio", + [NMK_GPIO_ALT_A] = "altA", + [NMK_GPIO_ALT_B] = "altB", + [NMK_GPIO_ALT_C] = "altC", + }; + + clk_enable(nmk_chip->clk); + is_out = !!(readl(nmk_chip->addr + NMK_GPIO_DIR) & bit); + pull = !(readl(nmk_chip->addr + NMK_GPIO_PDIS) & bit); + mode = nmk_gpio_get_mode(gpio); + + seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s %s", + gpio, label ?: "(none)", + is_out ? "out" : "in ", + chip->get + ? (chip->get(chip, offset) ? "hi" : "lo") + : "? ", + (mode < 0) ? "unknown" : modes[mode], + pull ? "pull" : "none"); + + if (label && !is_out) { + int irq = gpio_to_irq(gpio); + struct irq_desc *desc = irq_to_desc(irq); + + /* This races with request_irq(), set_irq_type(), + * and set_irq_wake() ... but those are "rare". + */ + if (irq >= 0 && desc->action) { + char *trigger; + u32 bitmask = nmk_gpio_get_bitmask(gpio); + + if (nmk_chip->edge_rising & bitmask) + trigger = "edge-rising"; + else if (nmk_chip->edge_falling & bitmask) + trigger = "edge-falling"; + else + trigger = "edge-undefined"; + + seq_printf(s, " irq-%d %s%s", + irq, trigger, + irqd_is_wakeup_set(&desc->irq_data) + ? " wakeup" : ""); + } + } + clk_disable(nmk_chip->clk); +} + +static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ + unsigned i; + unsigned gpio = chip->base; + + for (i = 0; i < chip->ngpio; i++, gpio++) { + nmk_gpio_dbg_show_one(s, chip, i, gpio); + seq_printf(s, "\n"); + } +} + +#else +static inline void nmk_gpio_dbg_show_one(struct seq_file *s, + struct gpio_chip *chip, + unsigned offset, unsigned gpio) +{ +} +#define nmk_gpio_dbg_show NULL +#endif + +/* This structure is replicated for each GPIO block allocated at probe time */ +static struct gpio_chip nmk_gpio_template = { + .request = nmk_gpio_request, + .free = nmk_gpio_free, + .direction_input = nmk_gpio_make_input, + .get = nmk_gpio_get_input, + .direction_output = nmk_gpio_make_output, + .set = nmk_gpio_set_output, + .to_irq = nmk_gpio_to_irq, + .dbg_show = nmk_gpio_dbg_show, + .can_sleep = 0, +}; + +void nmk_gpio_clocks_enable(void) +{ + int i; + + for (i = 0; i < NUM_BANKS; i++) { + struct nmk_gpio_chip *chip = nmk_gpio_chips[i]; + + if (!chip) + continue; + + clk_enable(chip->clk); + } +} + +void nmk_gpio_clocks_disable(void) +{ + int i; + + for (i = 0; i < NUM_BANKS; i++) { + struct nmk_gpio_chip *chip = nmk_gpio_chips[i]; + + if (!chip) + continue; + + clk_disable(chip->clk); + } +} + +/* + * Called from the suspend/resume path to only keep the real wakeup interrupts + * (those that have had set_irq_wake() called on them) as wakeup interrupts, + * and not the rest of the interrupts which we needed to have as wakeups for + * cpuidle. + * + * PM ops are not used since this needs to be done at the end, after all the + * other drivers are done with their suspend callbacks. + */ +void nmk_gpio_wakeups_suspend(void) +{ + int i; + + for (i = 0; i < NUM_BANKS; i++) { + struct nmk_gpio_chip *chip = nmk_gpio_chips[i]; + + if (!chip) + break; + + clk_enable(chip->clk); + + writel(chip->rwimsc & chip->real_wake, + chip->addr + NMK_GPIO_RWIMSC); + writel(chip->fwimsc & chip->real_wake, + chip->addr + NMK_GPIO_FWIMSC); + + clk_disable(chip->clk); + } +} + +void nmk_gpio_wakeups_resume(void) +{ + int i; + + for (i = 0; i < NUM_BANKS; i++) { + struct nmk_gpio_chip *chip = nmk_gpio_chips[i]; + + if (!chip) + break; + + clk_enable(chip->clk); + + writel(chip->rwimsc, chip->addr + NMK_GPIO_RWIMSC); + writel(chip->fwimsc, chip->addr + NMK_GPIO_FWIMSC); + + clk_disable(chip->clk); + } +} + +/* + * Read the pull up/pull down status. + * A bit set in 'pull_up' means that pull up + * is selected if pull is enabled in PDIS register. + * Note: only pull up/down set via this driver can + * be detected due to HW limitations. + */ +void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up) +{ + if (gpio_bank < NUM_BANKS) { + struct nmk_gpio_chip *chip = nmk_gpio_chips[gpio_bank]; + + if (!chip) + return; + + *pull_up = chip->pull_up; + } +} + +int nmk_gpio_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + struct nmk_gpio_chip *nmk_chip = d->host_data; + + if (!nmk_chip) + return -EINVAL; + + irq_set_chip_and_handler(irq, &nmk_gpio_irq_chip, handle_edge_irq); + set_irq_flags(irq, IRQF_VALID); + irq_set_chip_data(irq, nmk_chip); + irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING); + + return 0; +} + +const struct irq_domain_ops nmk_gpio_irq_simple_ops = { + .map = nmk_gpio_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + +static int __devinit nmk_gpio_probe(struct platform_device *dev) +{ + struct nmk_gpio_platform_data *pdata = dev->dev.platform_data; + struct device_node *np = dev->dev.of_node; + struct nmk_gpio_chip *nmk_chip; + struct gpio_chip *chip; + struct resource *res; + struct clk *clk; + int secondary_irq; + void __iomem *base; + int irq; + int ret; + + if (!pdata && !np) { + dev_err(&dev->dev, "No platform data or device tree found\n"); + return -ENODEV; + } + + if (np) { + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + if (of_get_property(np, "supports-sleepmode", NULL)) + pdata->supports_sleepmode = true; + + if (of_property_read_u32(np, "gpio-bank", &dev->id)) { + dev_err(&dev->dev, "gpio-bank property not found\n"); + ret = -EINVAL; + goto out; + } + + pdata->first_gpio = dev->id * NMK_GPIO_PER_CHIP; + pdata->num_gpio = NMK_GPIO_PER_CHIP; + } + + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!res) { + ret = -ENOENT; + goto out; + } + + irq = platform_get_irq(dev, 0); + if (irq < 0) { + ret = irq; + goto out; + } + + secondary_irq = platform_get_irq(dev, 1); + if (secondary_irq >= 0 && !pdata->get_secondary_status) { + ret = -EINVAL; + goto out; + } + + if (request_mem_region(res->start, resource_size(res), + dev_name(&dev->dev)) == NULL) { + ret = -EBUSY; + goto out; + } + + base = ioremap(res->start, resource_size(res)); + if (!base) { + ret = -ENOMEM; + goto out_release; + } + + clk = clk_get(&dev->dev, NULL); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto out_unmap; + } + + nmk_chip = kzalloc(sizeof(*nmk_chip), GFP_KERNEL); + if (!nmk_chip) { + ret = -ENOMEM; + goto out_clk; + } + + /* + * The virt address in nmk_chip->addr is in the nomadik register space, + * so we can simply convert the resource address, without remapping + */ + nmk_chip->bank = dev->id; + nmk_chip->clk = clk; + nmk_chip->addr = base; + nmk_chip->chip = nmk_gpio_template; + nmk_chip->parent_irq = irq; + nmk_chip->secondary_parent_irq = secondary_irq; + nmk_chip->get_secondary_status = pdata->get_secondary_status; + nmk_chip->set_ioforce = pdata->set_ioforce; + nmk_chip->sleepmode = pdata->supports_sleepmode; + spin_lock_init(&nmk_chip->lock); + + chip = &nmk_chip->chip; + chip->base = pdata->first_gpio; + chip->ngpio = pdata->num_gpio; + chip->label = pdata->name ?: dev_name(&dev->dev); + chip->dev = &dev->dev; + chip->owner = THIS_MODULE; + + clk_enable(nmk_chip->clk); + nmk_chip->lowemi = readl_relaxed(nmk_chip->addr + NMK_GPIO_LOWEMI); + clk_disable(nmk_chip->clk); + +#ifdef CONFIG_OF_GPIO + chip->of_node = np; +#endif + + ret = gpiochip_add(&nmk_chip->chip); + if (ret) + goto out_free; + + BUG_ON(nmk_chip->bank >= ARRAY_SIZE(nmk_gpio_chips)); + + nmk_gpio_chips[nmk_chip->bank] = nmk_chip; + + platform_set_drvdata(dev, nmk_chip); + + nmk_chip->domain = irq_domain_add_legacy(np, NMK_GPIO_PER_CHIP, + NOMADIK_GPIO_TO_IRQ(pdata->first_gpio), + 0, &nmk_gpio_irq_simple_ops, nmk_chip); + if (!nmk_chip->domain) { + pr_err("%s: Failed to create irqdomain\n", np->full_name); + ret = -ENOSYS; + goto out_free; + } + + nmk_gpio_init_irq(nmk_chip); + + dev_info(&dev->dev, "at address %p\n", nmk_chip->addr); + + return 0; + +out_free: + kfree(nmk_chip); +out_clk: + clk_disable(clk); + clk_put(clk); +out_unmap: + iounmap(base); +out_release: + release_mem_region(res->start, resource_size(res)); +out: + dev_err(&dev->dev, "Failure %i for GPIO %i-%i\n", ret, + pdata->first_gpio, pdata->first_gpio+31); + if (np) + kfree(pdata); + + return ret; +} + +static int nmk_get_groups_cnt(struct pinctrl_dev *pctldev) +{ + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + + return npct->soc->ngroups; +} + +static const char *nmk_get_group_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + + return npct->soc->groups[selector].name; +} + +static int nmk_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, + const unsigned **pins, + unsigned *num_pins) +{ + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + + *pins = npct->soc->groups[selector].pins; + *num_pins = npct->soc->groups[selector].npins; + return 0; +} + +static struct pinctrl_gpio_range * +nmk_match_gpio_range(struct pinctrl_dev *pctldev, unsigned offset) +{ + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + int i; + + for (i = 0; i < npct->soc->gpio_num_ranges; i++) { + struct pinctrl_gpio_range *range; + + range = &npct->soc->gpio_ranges[i]; + if (offset >= range->pin_base && + offset <= (range->pin_base + range->npins - 1)) + return range; + } + return NULL; +} + +static void nmk_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, + unsigned offset) +{ + struct pinctrl_gpio_range *range; + struct gpio_chip *chip; + + range = nmk_match_gpio_range(pctldev, offset); + if (!range || !range->gc) { + seq_printf(s, "invalid pin offset"); + return; + } + chip = range->gc; + nmk_gpio_dbg_show_one(s, chip, offset - chip->base, offset); +} + +static struct pinctrl_ops nmk_pinctrl_ops = { + .get_groups_count = nmk_get_groups_cnt, + .get_group_name = nmk_get_group_name, + .get_group_pins = nmk_get_group_pins, + .pin_dbg_show = nmk_pin_dbg_show, +}; + +static int nmk_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev) +{ + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + + return npct->soc->nfunctions; +} + +static const char *nmk_pmx_get_func_name(struct pinctrl_dev *pctldev, + unsigned function) +{ + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + + return npct->soc->functions[function].name; +} + +static int nmk_pmx_get_func_groups(struct pinctrl_dev *pctldev, + unsigned function, + const char * const **groups, + unsigned * const num_groups) +{ + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + + *groups = npct->soc->functions[function].groups; + *num_groups = npct->soc->functions[function].ngroups; + + return 0; +} + +static int nmk_pmx_enable(struct pinctrl_dev *pctldev, unsigned function, + unsigned group) +{ + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + const struct nmk_pingroup *g; + static unsigned int slpm[NUM_BANKS]; + unsigned long flags; + bool glitch; + int ret = -EINVAL; + int i; + + g = &npct->soc->groups[group]; + + if (g->altsetting < 0) + return -EINVAL; + + dev_dbg(npct->dev, "enable group %s, %u pins\n", g->name, g->npins); + + /* Handle this special glitch on altfunction C */ + glitch = (g->altsetting == NMK_GPIO_ALT_C); + + if (glitch) { + spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); + + /* Initially don't put any pins to sleep when switching */ + memset(slpm, 0xff, sizeof(slpm)); + + /* + * Then mask the pins that need to be sleeping now when we're + * switching to the ALT C function. + */ + for (i = 0; i < g->npins; i++) + slpm[g->pins[i] / NMK_GPIO_PER_CHIP] &= ~BIT(g->pins[i]); + nmk_gpio_glitch_slpm_init(slpm); + } + + for (i = 0; i < g->npins; i++) { + struct pinctrl_gpio_range *range; + struct nmk_gpio_chip *nmk_chip; + struct gpio_chip *chip; + unsigned bit; + + range = nmk_match_gpio_range(pctldev, g->pins[i]); + if (!range) { + dev_err(npct->dev, + "invalid pin offset %d in group %s at index %d\n", + g->pins[i], g->name, i); + goto out_glitch; + } + if (!range->gc) { + dev_err(npct->dev, "GPIO chip missing in range for pin offset %d in group %s at index %d\n", + g->pins[i], g->name, i); + goto out_glitch; + } + chip = range->gc; + nmk_chip = container_of(chip, struct nmk_gpio_chip, chip); + dev_dbg(npct->dev, "setting pin %d to altsetting %d\n", g->pins[i], g->altsetting); + + clk_enable(nmk_chip->clk); + bit = g->pins[i] % NMK_GPIO_PER_CHIP; + /* + * If the pin is switching to altfunc, and there was an + * interrupt installed on it which has been lazy disabled, + * actually mask the interrupt to prevent spurious interrupts + * that would occur while the pin is under control of the + * peripheral. Only SKE does this. + */ + nmk_gpio_disable_lazy_irq(nmk_chip, bit); + + __nmk_gpio_set_mode_safe(nmk_chip, bit, g->altsetting, glitch); + clk_disable(nmk_chip->clk); + } + + /* When all pins are successfully reconfigured we get here */ + ret = 0; + +out_glitch: + if (glitch) { + nmk_gpio_glitch_slpm_restore(slpm); + spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags); + } + + return ret; +} + +static void nmk_pmx_disable(struct pinctrl_dev *pctldev, + unsigned function, unsigned group) +{ + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + const struct nmk_pingroup *g; + + g = &npct->soc->groups[group]; + + if (g->altsetting < 0) + return; + + /* Poke out the mux, set the pin to some default state? */ + dev_dbg(npct->dev, "disable group %s, %u pins\n", g->name, g->npins); +} + +int nmk_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + struct nmk_gpio_chip *nmk_chip; + struct gpio_chip *chip; + unsigned bit; + + if (!range) { + dev_err(npct->dev, "invalid range\n"); + return -EINVAL; + } + if (!range->gc) { + dev_err(npct->dev, "missing GPIO chip in range\n"); + return -EINVAL; + } + chip = range->gc; + nmk_chip = container_of(chip, struct nmk_gpio_chip, chip); + + dev_dbg(npct->dev, "enable pin %u as GPIO\n", offset); + + clk_enable(nmk_chip->clk); + bit = offset % NMK_GPIO_PER_CHIP; + /* There is no glitch when converting any pin to GPIO */ + __nmk_gpio_set_mode(nmk_chip, bit, NMK_GPIO_ALT_GPIO); + clk_disable(nmk_chip->clk); + + return 0; +} + +void nmk_gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + + dev_dbg(npct->dev, "disable pin %u as GPIO\n", offset); + /* Set the pin to some default state, GPIO is usually default */ +} + +static struct pinmux_ops nmk_pinmux_ops = { + .get_functions_count = nmk_pmx_get_funcs_cnt, + .get_function_name = nmk_pmx_get_func_name, + .get_function_groups = nmk_pmx_get_func_groups, + .enable = nmk_pmx_enable, + .disable = nmk_pmx_disable, + .gpio_request_enable = nmk_gpio_request_enable, + .gpio_disable_free = nmk_gpio_disable_free, +}; + +int nmk_pin_config_get(struct pinctrl_dev *pctldev, + unsigned pin, + unsigned long *config) +{ + /* Not implemented */ + return -EINVAL; +} + +int nmk_pin_config_set(struct pinctrl_dev *pctldev, + unsigned pin, + unsigned long config) +{ + static const char *pullnames[] = { + [NMK_GPIO_PULL_NONE] = "none", + [NMK_GPIO_PULL_UP] = "up", + [NMK_GPIO_PULL_DOWN] = "down", + [3] /* illegal */ = "??" + }; + static const char *slpmnames[] = { + [NMK_GPIO_SLPM_INPUT] = "input/wakeup", + [NMK_GPIO_SLPM_NOCHANGE] = "no-change/no-wakeup", + }; + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + struct nmk_gpio_chip *nmk_chip; + struct pinctrl_gpio_range *range; + struct gpio_chip *chip; + unsigned bit; + + /* + * The pin config contains pin number and altfunction fields, here + * we just ignore that part. It's being handled by the framework and + * pinmux callback respectively. + */ + pin_cfg_t cfg = (pin_cfg_t) config; + int pull = PIN_PULL(cfg); + int slpm = PIN_SLPM(cfg); + int output = PIN_DIR(cfg); + int val = PIN_VAL(cfg); + bool lowemi = PIN_LOWEMI(cfg); + bool gpiomode = PIN_GPIOMODE(cfg); + bool sleep = PIN_SLEEPMODE(cfg); + + range = nmk_match_gpio_range(pctldev, pin); + if (!range) { + dev_err(npct->dev, "invalid pin offset %d\n", pin); + return -EINVAL; + } + if (!range->gc) { + dev_err(npct->dev, "GPIO chip missing in range for pin %d\n", + pin); + return -EINVAL; + } + chip = range->gc; + nmk_chip = container_of(chip, struct nmk_gpio_chip, chip); + + if (sleep) { + int slpm_pull = PIN_SLPM_PULL(cfg); + int slpm_output = PIN_SLPM_DIR(cfg); + int slpm_val = PIN_SLPM_VAL(cfg); + + /* All pins go into GPIO mode at sleep */ + gpiomode = true; + + /* + * The SLPM_* values are normal values + 1 to allow zero to + * mean "same as normal". + */ + if (slpm_pull) + pull = slpm_pull - 1; + if (slpm_output) + output = slpm_output - 1; + if (slpm_val) + val = slpm_val - 1; + + dev_dbg(nmk_chip->chip.dev, "pin %d: sleep pull %s, dir %s, val %s\n", + pin, + slpm_pull ? pullnames[pull] : "same", + slpm_output ? (output ? "output" : "input") : "same", + slpm_val ? (val ? "high" : "low") : "same"); + } + + dev_dbg(nmk_chip->chip.dev, "pin %d [%#lx]: pull %s, slpm %s (%s%s), lowemi %s\n", + pin, cfg, pullnames[pull], slpmnames[slpm], + output ? "output " : "input", + output ? (val ? "high" : "low") : "", + lowemi ? "on" : "off" ); + + clk_enable(nmk_chip->clk); + bit = pin % NMK_GPIO_PER_CHIP; + if (gpiomode) + /* No glitch when going to GPIO mode */ + __nmk_gpio_set_mode(nmk_chip, bit, NMK_GPIO_ALT_GPIO); + if (output) + __nmk_gpio_make_output(nmk_chip, bit, val); + else { + __nmk_gpio_make_input(nmk_chip, bit); + __nmk_gpio_set_pull(nmk_chip, bit, pull); + } + /* TODO: isn't this only applicable on output pins? */ + __nmk_gpio_set_lowemi(nmk_chip, bit, lowemi); + + __nmk_gpio_set_slpm(nmk_chip, bit, slpm); + clk_disable(nmk_chip->clk); + return 0; +} + +static struct pinconf_ops nmk_pinconf_ops = { + .pin_config_get = nmk_pin_config_get, + .pin_config_set = nmk_pin_config_set, +}; + +static struct pinctrl_desc nmk_pinctrl_desc = { + .name = "pinctrl-nomadik", + .pctlops = &nmk_pinctrl_ops, + .pmxops = &nmk_pinmux_ops, + .confops = &nmk_pinconf_ops, + .owner = THIS_MODULE, +}; + +static int __devinit nmk_pinctrl_probe(struct platform_device *pdev) +{ + const struct platform_device_id *platid = platform_get_device_id(pdev); + struct nmk_pinctrl *npct; + int i; + + npct = devm_kzalloc(&pdev->dev, sizeof(*npct), GFP_KERNEL); + if (!npct) + return -ENOMEM; + + /* Poke in other ASIC variants here */ + if (platid->driver_data == PINCTRL_NMK_DB8500) + nmk_pinctrl_db8500_init(&npct->soc); + + /* + * We need all the GPIO drivers to probe FIRST, or we will not be able + * to obtain references to the struct gpio_chip * for them, and we + * need this to proceed. + */ + for (i = 0; i < npct->soc->gpio_num_ranges; i++) { + if (!nmk_gpio_chips[i]) { + dev_warn(&pdev->dev, "GPIO chip %d not registered yet\n", i); + devm_kfree(&pdev->dev, npct); + return -EPROBE_DEFER; + } + npct->soc->gpio_ranges[i].gc = &nmk_gpio_chips[i]->chip; + } + + nmk_pinctrl_desc.pins = npct->soc->pins; + nmk_pinctrl_desc.npins = npct->soc->npins; + npct->dev = &pdev->dev; + npct->pctl = pinctrl_register(&nmk_pinctrl_desc, &pdev->dev, npct); + if (!npct->pctl) { + dev_err(&pdev->dev, "could not register Nomadik pinctrl driver\n"); + return -EINVAL; + } + + /* We will handle a range of GPIO pins */ + for (i = 0; i < npct->soc->gpio_num_ranges; i++) + pinctrl_add_gpio_range(npct->pctl, &npct->soc->gpio_ranges[i]); + + platform_set_drvdata(pdev, npct); + dev_info(&pdev->dev, "initialized Nomadik pin control driver\n"); + + return 0; +} + +static const struct of_device_id nmk_gpio_match[] = { + { .compatible = "st,nomadik-gpio", }, + {} +}; + +static struct platform_driver nmk_gpio_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "gpio", + .of_match_table = nmk_gpio_match, + }, + .probe = nmk_gpio_probe, +}; + +static const struct platform_device_id nmk_pinctrl_id[] = { + { "pinctrl-stn8815", PINCTRL_NMK_STN8815 }, + { "pinctrl-db8500", PINCTRL_NMK_DB8500 }, +}; + +static struct platform_driver nmk_pinctrl_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "pinctrl-nomadik", + }, + .probe = nmk_pinctrl_probe, + .id_table = nmk_pinctrl_id, +}; + +static int __init nmk_gpio_init(void) +{ + int ret; + + ret = platform_driver_register(&nmk_gpio_driver); + if (ret) + return ret; + return platform_driver_register(&nmk_pinctrl_driver); +} + +core_initcall(nmk_gpio_init); + +MODULE_AUTHOR("Prafulla WADASKAR and Alessandro Rubini"); +MODULE_DESCRIPTION("Nomadik GPIO Driver"); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/pinctrl/pinctrl-nomadik.h b/trunk/drivers/pinctrl/pinctrl-nomadik.h new file mode 100644 index 000000000000..bc91aed7185d --- /dev/null +++ b/trunk/drivers/pinctrl/pinctrl-nomadik.h @@ -0,0 +1,77 @@ +#ifndef PINCTRL_PINCTRL_NOMADIK_H +#define PINCTRL_PINCTRL_NOMADIK_H + +#include + +/* Package definitions */ +#define PINCTRL_NMK_STN8815 0 +#define PINCTRL_NMK_DB8500 1 + +/** + * struct nmk_function - Nomadik pinctrl mux function + * @name: The name of the function, exported to pinctrl core. + * @groups: An array of pin groups that may select this function. + * @ngroups: The number of entries in @groups. + */ +struct nmk_function { + const char *name; + const char * const *groups; + unsigned ngroups; +}; + +/** + * struct nmk_pingroup - describes a Nomadik pin group + * @name: the name of this specific pin group + * @pins: an array of discrete physical pins used in this group, taken + * from the driver-local pin enumeration space + * @num_pins: the number of pins in this group array, i.e. the number of + * elements in .pins so we can iterate over that array + * @altsetting: the altsetting to apply to all pins in this group to + * configure them to be used by a function + */ +struct nmk_pingroup { + const char *name; + const unsigned int *pins; + const unsigned npins; + int altsetting; +}; + +/** + * struct nmk_pinctrl_soc_data - Nomadik pin controller per-SoC configuration + * @gpio_ranges: An array of GPIO ranges for this SoC + * @gpio_num_ranges: The number of GPIO ranges for this SoC + * @pins: An array describing all pins the pin controller affects. + * All pins which are also GPIOs must be listed first within the + * array, and be numbered identically to the GPIO controller's + * numbering. + * @npins: The number of entries in @pins. + * @functions: The functions supported on this SoC. + * @nfunction: The number of entries in @functions. + * @groups: An array describing all pin groups the pin SoC supports. + * @ngroups: The number of entries in @groups. + */ +struct nmk_pinctrl_soc_data { + struct pinctrl_gpio_range *gpio_ranges; + unsigned gpio_num_ranges; + const struct pinctrl_pin_desc *pins; + unsigned npins; + const struct nmk_function *functions; + unsigned nfunctions; + const struct nmk_pingroup *groups; + unsigned ngroups; +}; + +#ifdef CONFIG_PINCTRL_DB8500 + +void nmk_pinctrl_db8500_init(const struct nmk_pinctrl_soc_data **soc); + +#else + +static inline void +nmk_pinctrl_db8500_init(const struct nmk_pinctrl_soc_data **soc) +{ +} + +#endif + +#endif /* PINCTRL_PINCTRL_NOMADIK_H */ diff --git a/trunk/drivers/pinctrl/pinctrl-pxa3xx.c b/trunk/drivers/pinctrl/pinctrl-pxa3xx.c index 079dce0e93e9..f14cd6ba4c0b 100644 --- a/trunk/drivers/pinctrl/pinctrl-pxa3xx.c +++ b/trunk/drivers/pinctrl/pinctrl-pxa3xx.c @@ -25,20 +25,18 @@ static struct pinctrl_gpio_range pxa3xx_pinctrl_gpio_range = { .pin_base = 0, }; -static int pxa3xx_list_groups(struct pinctrl_dev *pctrldev, unsigned selector) +static int pxa3xx_get_groups_count(struct pinctrl_dev *pctrldev) { struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); - if (selector >= info->num_grps) - return -EINVAL; - return 0; + + return info->num_grps; } static const char *pxa3xx_get_group_name(struct pinctrl_dev *pctrldev, unsigned selector) { struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); - if (selector >= info->num_grps) - return NULL; + return info->grps[selector].name; } @@ -48,25 +46,23 @@ static int pxa3xx_get_group_pins(struct pinctrl_dev *pctrldev, unsigned *num_pins) { struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); - if (selector >= info->num_grps) - return -EINVAL; + *pins = info->grps[selector].pins; *num_pins = info->grps[selector].npins; return 0; } static struct pinctrl_ops pxa3xx_pctrl_ops = { - .list_groups = pxa3xx_list_groups, + .get_groups_count = pxa3xx_get_groups_count, .get_group_name = pxa3xx_get_group_name, .get_group_pins = pxa3xx_get_group_pins, }; -static int pxa3xx_pmx_list_func(struct pinctrl_dev *pctrldev, unsigned func) +static int pxa3xx_pmx_get_funcs_count(struct pinctrl_dev *pctrldev) { struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); - if (func >= info->num_funcs) - return -EINVAL; - return 0; + + return info->num_funcs; } static const char *pxa3xx_pmx_get_func_name(struct pinctrl_dev *pctrldev, @@ -142,11 +138,6 @@ static int pxa3xx_pmx_enable(struct pinctrl_dev *pctrldev, unsigned func, return 0; } -static void pxa3xx_pmx_disable(struct pinctrl_dev *pctrldev, unsigned func, - unsigned group) -{ -} - static int pxa3xx_pmx_request_gpio(struct pinctrl_dev *pctrldev, struct pinctrl_gpio_range *range, unsigned pin) @@ -170,11 +161,10 @@ static int pxa3xx_pmx_request_gpio(struct pinctrl_dev *pctrldev, } static struct pinmux_ops pxa3xx_pmx_ops = { - .list_functions = pxa3xx_pmx_list_func, + .get_functions_count = pxa3xx_pmx_get_funcs_count, .get_function_name = pxa3xx_pmx_get_func_name, .get_function_groups = pxa3xx_pmx_get_groups, .enable = pxa3xx_pmx_enable, - .disable = pxa3xx_pmx_disable, .gpio_request_enable = pxa3xx_pmx_request_gpio, }; diff --git a/trunk/drivers/pinctrl/pinctrl-sirf.c b/trunk/drivers/pinctrl/pinctrl-sirf.c index 6b3534cc051a..ba15b1a29e52 100644 --- a/trunk/drivers/pinctrl/pinctrl-sirf.c +++ b/trunk/drivers/pinctrl/pinctrl-sirf.c @@ -853,18 +853,14 @@ static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = { SIRFSOC_PIN_GROUP("gpsgrp", gps_pins), }; -static int sirfsoc_list_groups(struct pinctrl_dev *pctldev, unsigned selector) +static int sirfsoc_get_groups_count(struct pinctrl_dev *pctldev) { - if (selector >= ARRAY_SIZE(sirfsoc_pin_groups)) - return -EINVAL; - return 0; + return ARRAY_SIZE(sirfsoc_pin_groups); } static const char *sirfsoc_get_group_name(struct pinctrl_dev *pctldev, unsigned selector) { - if (selector >= ARRAY_SIZE(sirfsoc_pin_groups)) - return NULL; return sirfsoc_pin_groups[selector].name; } @@ -872,8 +868,6 @@ static int sirfsoc_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector const unsigned **pins, unsigned *num_pins) { - if (selector >= ARRAY_SIZE(sirfsoc_pin_groups)) - return -EINVAL; *pins = sirfsoc_pin_groups[selector].pins; *num_pins = sirfsoc_pin_groups[selector].num_pins; return 0; @@ -886,7 +880,7 @@ static void sirfsoc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s } static struct pinctrl_ops sirfsoc_pctrl_ops = { - .list_groups = sirfsoc_list_groups, + .get_groups_count = sirfsoc_get_groups_count, .get_group_name = sirfsoc_get_group_name, .get_group_pins = sirfsoc_get_group_pins, .pin_dbg_show = sirfsoc_pin_dbg_show, @@ -1033,11 +1027,9 @@ static void sirfsoc_pinmux_disable(struct pinctrl_dev *pmxdev, unsigned selector sirfsoc_pinmux_endisable(spmx, selector, false); } -static int sirfsoc_pinmux_list_funcs(struct pinctrl_dev *pmxdev, unsigned selector) +static int sirfsoc_pinmux_get_funcs_count(struct pinctrl_dev *pmxdev) { - if (selector >= ARRAY_SIZE(sirfsoc_pmx_functions)) - return -EINVAL; - return 0; + return ARRAY_SIZE(sirfsoc_pmx_functions); } static const char *sirfsoc_pinmux_get_func_name(struct pinctrl_dev *pctldev, @@ -1074,9 +1066,9 @@ static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev, } static struct pinmux_ops sirfsoc_pinmux_ops = { - .list_functions = sirfsoc_pinmux_list_funcs, .enable = sirfsoc_pinmux_enable, .disable = sirfsoc_pinmux_disable, + .get_functions_count = sirfsoc_pinmux_get_funcs_count, .get_function_name = sirfsoc_pinmux_get_func_name, .get_function_groups = sirfsoc_pinmux_get_groups, .gpio_request_enable = sirfsoc_pinmux_request_gpio, diff --git a/trunk/drivers/pinctrl/pinctrl-tegra.c b/trunk/drivers/pinctrl/pinctrl-tegra.c index 9b329688120c..b6934867d8d3 100644 --- a/trunk/drivers/pinctrl/pinctrl-tegra.c +++ b/trunk/drivers/pinctrl/pinctrl-tegra.c @@ -1,7 +1,7 @@ /* * Driver for the NVIDIA Tegra pinmux * - * Copyright (c) 2011, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved. * * Derived from code: * Copyright (C) 2010 Google, Inc. @@ -22,17 +22,19 @@ #include #include #include -#include +#include +#include +#include #include #include #include +#include #include +#include "core.h" #include "pinctrl-tegra.h" -#define DRIVER_NAME "tegra-pinmux-disabled" - struct tegra_pmx { struct device *dev; struct pinctrl_dev *pctl; @@ -53,15 +55,11 @@ static inline void pmx_writel(struct tegra_pmx *pmx, u32 val, u32 bank, u32 reg) writel(val, pmx->regs[bank] + reg); } -static int tegra_pinctrl_list_groups(struct pinctrl_dev *pctldev, - unsigned group) +static int tegra_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) { struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); - if (group >= pmx->soc->ngroups) - return -EINVAL; - - return 0; + return pmx->soc->ngroups; } static const char *tegra_pinctrl_get_group_name(struct pinctrl_dev *pctldev, @@ -69,9 +67,6 @@ static const char *tegra_pinctrl_get_group_name(struct pinctrl_dev *pctldev, { struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); - if (group >= pmx->soc->ngroups) - return NULL; - return pmx->soc->groups[group].name; } @@ -82,38 +77,259 @@ static int tegra_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, { struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); - if (group >= pmx->soc->ngroups) - return -EINVAL; - *pins = pmx->soc->groups[group].pins; *num_pins = pmx->soc->groups[group].npins; return 0; } +#ifdef CONFIG_DEBUG_FS static void tegra_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned offset) { - seq_printf(s, " " DRIVER_NAME); + seq_printf(s, " %s", dev_name(pctldev->dev)); +} +#endif + +static int reserve_map(struct device *dev, struct pinctrl_map **map, + unsigned *reserved_maps, unsigned *num_maps, + unsigned reserve) +{ + unsigned old_num = *reserved_maps; + unsigned new_num = *num_maps + reserve; + struct pinctrl_map *new_map; + + if (old_num >= new_num) + return 0; + + new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL); + if (!new_map) { + dev_err(dev, "krealloc(map) failed\n"); + return -ENOMEM; + } + + memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map)); + + *map = new_map; + *reserved_maps = new_num; + + return 0; +} + +static int add_map_mux(struct pinctrl_map **map, unsigned *reserved_maps, + unsigned *num_maps, const char *group, + const char *function) +{ + if (WARN_ON(*num_maps == *reserved_maps)) + return -ENOSPC; + + (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; + (*map)[*num_maps].data.mux.group = group; + (*map)[*num_maps].data.mux.function = function; + (*num_maps)++; + + return 0; +} + +static int add_map_configs(struct device *dev, struct pinctrl_map **map, + unsigned *reserved_maps, unsigned *num_maps, + const char *group, unsigned long *configs, + unsigned num_configs) +{ + unsigned long *dup_configs; + + if (WARN_ON(*num_maps == *reserved_maps)) + return -ENOSPC; + + dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs), + GFP_KERNEL); + if (!dup_configs) { + dev_err(dev, "kmemdup(configs) failed\n"); + return -ENOMEM; + } + + (*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_GROUP; + (*map)[*num_maps].data.configs.group_or_pin = group; + (*map)[*num_maps].data.configs.configs = dup_configs; + (*map)[*num_maps].data.configs.num_configs = num_configs; + (*num_maps)++; + + return 0; +} + +static int add_config(struct device *dev, unsigned long **configs, + unsigned *num_configs, unsigned long config) +{ + unsigned old_num = *num_configs; + unsigned new_num = old_num + 1; + unsigned long *new_configs; + + new_configs = krealloc(*configs, sizeof(*new_configs) * new_num, + GFP_KERNEL); + if (!new_configs) { + dev_err(dev, "krealloc(configs) failed\n"); + return -ENOMEM; + } + + new_configs[old_num] = config; + + *configs = new_configs; + *num_configs = new_num; + + return 0; +} + +void tegra_pinctrl_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) +{ + int i; + + for (i = 0; i < num_maps; i++) + if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP) + kfree(map[i].data.configs.configs); + + kfree(map); +} + +static const struct cfg_param { + const char *property; + enum tegra_pinconf_param param; +} cfg_params[] = { + {"nvidia,pull", TEGRA_PINCONF_PARAM_PULL}, + {"nvidia,tristate", TEGRA_PINCONF_PARAM_TRISTATE}, + {"nvidia,enable-input", TEGRA_PINCONF_PARAM_ENABLE_INPUT}, + {"nvidia,open-drain", TEGRA_PINCONF_PARAM_OPEN_DRAIN}, + {"nvidia,lock", TEGRA_PINCONF_PARAM_LOCK}, + {"nvidia,io-reset", TEGRA_PINCONF_PARAM_IORESET}, + {"nvidia,high-speed-mode", TEGRA_PINCONF_PARAM_HIGH_SPEED_MODE}, + {"nvidia,schmitt", TEGRA_PINCONF_PARAM_SCHMITT}, + {"nvidia,low-power-mode", TEGRA_PINCONF_PARAM_LOW_POWER_MODE}, + {"nvidia,pull-down-strength", TEGRA_PINCONF_PARAM_DRIVE_DOWN_STRENGTH}, + {"nvidia,pull-up-strength", TEGRA_PINCONF_PARAM_DRIVE_UP_STRENGTH}, + {"nvidia,slew-rate-falling", TEGRA_PINCONF_PARAM_SLEW_RATE_FALLING}, + {"nvidia,slew-rate-rising", TEGRA_PINCONF_PARAM_SLEW_RATE_RISING}, +}; + +int tegra_pinctrl_dt_subnode_to_map(struct device *dev, + struct device_node *np, + struct pinctrl_map **map, + unsigned *reserved_maps, + unsigned *num_maps) +{ + int ret, i; + const char *function; + u32 val; + unsigned long config; + unsigned long *configs = NULL; + unsigned num_configs = 0; + unsigned reserve; + struct property *prop; + const char *group; + + ret = of_property_read_string(np, "nvidia,function", &function); + if (ret < 0) { + /* EINVAL=missing, which is fine since it's optional */ + if (ret != -EINVAL) + dev_err(dev, + "could not parse property nvidia,function\n"); + function = NULL; + } + + for (i = 0; i < ARRAY_SIZE(cfg_params); i++) { + ret = of_property_read_u32(np, cfg_params[i].property, &val); + if (!ret) { + config = TEGRA_PINCONF_PACK(cfg_params[i].param, val); + ret = add_config(dev, &configs, &num_configs, config); + if (ret < 0) + goto exit; + /* EINVAL=missing, which is fine since it's optional */ + } else if (ret != -EINVAL) { + dev_err(dev, "could not parse property %s\n", + cfg_params[i].property); + } + } + + reserve = 0; + if (function != NULL) + reserve++; + if (num_configs) + reserve++; + ret = of_property_count_strings(np, "nvidia,pins"); + if (ret < 0) { + dev_err(dev, "could not parse property nvidia,pins\n"); + goto exit; + } + reserve *= ret; + + ret = reserve_map(dev, map, reserved_maps, num_maps, reserve); + if (ret < 0) + goto exit; + + of_property_for_each_string(np, "nvidia,pins", prop, group) { + if (function) { + ret = add_map_mux(map, reserved_maps, num_maps, + group, function); + if (ret < 0) + goto exit; + } + + if (num_configs) { + ret = add_map_configs(dev, map, reserved_maps, + num_maps, group, configs, + num_configs); + if (ret < 0) + goto exit; + } + } + + ret = 0; + +exit: + kfree(configs); + return ret; +} + +int tegra_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, unsigned *num_maps) +{ + unsigned reserved_maps; + struct device_node *np; + int ret; + + reserved_maps = 0; + *map = NULL; + *num_maps = 0; + + for_each_child_of_node(np_config, np) { + ret = tegra_pinctrl_dt_subnode_to_map(pctldev->dev, np, map, + &reserved_maps, num_maps); + if (ret < 0) { + tegra_pinctrl_dt_free_map(pctldev, *map, *num_maps); + return ret; + } + } + + return 0; } static struct pinctrl_ops tegra_pinctrl_ops = { - .list_groups = tegra_pinctrl_list_groups, + .get_groups_count = tegra_pinctrl_get_groups_count, .get_group_name = tegra_pinctrl_get_group_name, .get_group_pins = tegra_pinctrl_get_group_pins, +#ifdef CONFIG_DEBUG_FS .pin_dbg_show = tegra_pinctrl_pin_dbg_show, +#endif + .dt_node_to_map = tegra_pinctrl_dt_node_to_map, + .dt_free_map = tegra_pinctrl_dt_free_map, }; -static int tegra_pinctrl_list_funcs(struct pinctrl_dev *pctldev, - unsigned function) +static int tegra_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev) { struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); - if (function >= pmx->soc->nfunctions) - return -EINVAL; - - return 0; + return pmx->soc->nfunctions; } static const char *tegra_pinctrl_get_func_name(struct pinctrl_dev *pctldev, @@ -121,9 +337,6 @@ static const char *tegra_pinctrl_get_func_name(struct pinctrl_dev *pctldev, { struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); - if (function >= pmx->soc->nfunctions) - return NULL; - return pmx->soc->functions[function].name; } @@ -134,9 +347,6 @@ static int tegra_pinctrl_get_func_groups(struct pinctrl_dev *pctldev, { struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); - if (function >= pmx->soc->nfunctions) - return -EINVAL; - *groups = pmx->soc->functions[function].groups; *num_groups = pmx->soc->functions[function].ngroups; @@ -151,18 +361,16 @@ static int tegra_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned function, int i; u32 val; - if (group >= pmx->soc->ngroups) - return -EINVAL; g = &pmx->soc->groups[group]; - if (g->mux_reg < 0) + if (WARN_ON(g->mux_reg < 0)) return -EINVAL; for (i = 0; i < ARRAY_SIZE(g->funcs); i++) { if (g->funcs[i] == function) break; } - if (i == ARRAY_SIZE(g->funcs)) + if (WARN_ON(i == ARRAY_SIZE(g->funcs))) return -EINVAL; val = pmx_readl(pmx, g->mux_bank, g->mux_reg); @@ -180,11 +388,9 @@ static void tegra_pinctrl_disable(struct pinctrl_dev *pctldev, const struct tegra_pingroup *g; u32 val; - if (group >= pmx->soc->ngroups) - return; g = &pmx->soc->groups[group]; - if (g->mux_reg < 0) + if (WARN_ON(g->mux_reg < 0)) return; val = pmx_readl(pmx, g->mux_bank, g->mux_reg); @@ -194,7 +400,7 @@ static void tegra_pinctrl_disable(struct pinctrl_dev *pctldev, } static struct pinmux_ops tegra_pinmux_ops = { - .list_functions = tegra_pinctrl_list_funcs, + .get_functions_count = tegra_pinctrl_get_funcs_count, .get_function_name = tegra_pinctrl_get_func_name, .get_function_groups = tegra_pinctrl_get_func_groups, .enable = tegra_pinctrl_enable, @@ -204,6 +410,7 @@ static struct pinmux_ops tegra_pinmux_ops = { static int tegra_pinconf_reg(struct tegra_pmx *pmx, const struct tegra_pingroup *g, enum tegra_pinconf_param param, + bool report_err, s8 *bank, s16 *reg, s8 *bit, s8 *width) { switch (param) { @@ -291,9 +498,10 @@ static int tegra_pinconf_reg(struct tegra_pmx *pmx, } if (*reg < 0) { - dev_err(pmx->dev, - "Config param %04x not supported on group %s\n", - param, g->name); + if (report_err) + dev_err(pmx->dev, + "Config param %04x not supported on group %s\n", + param, g->name); return -ENOTSUPP; } @@ -303,12 +511,14 @@ static int tegra_pinconf_reg(struct tegra_pmx *pmx, static int tegra_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin, unsigned long *config) { + dev_err(pctldev->dev, "pin_config_get op not supported\n"); return -ENOTSUPP; } static int tegra_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin, unsigned long config) { + dev_err(pctldev->dev, "pin_config_set op not supported\n"); return -ENOTSUPP; } @@ -324,11 +534,10 @@ static int tegra_pinconf_group_get(struct pinctrl_dev *pctldev, s16 reg; u32 val, mask; - if (group >= pmx->soc->ngroups) - return -EINVAL; g = &pmx->soc->groups[group]; - ret = tegra_pinconf_reg(pmx, g, param, &bank, ®, &bit, &width); + ret = tegra_pinconf_reg(pmx, g, param, true, &bank, ®, &bit, + &width); if (ret < 0) return ret; @@ -353,11 +562,10 @@ static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev, s16 reg; u32 val, mask; - if (group >= pmx->soc->ngroups) - return -EINVAL; g = &pmx->soc->groups[group]; - ret = tegra_pinconf_reg(pmx, g, param, &bank, ®, &bit, &width); + ret = tegra_pinconf_reg(pmx, g, param, true, &bank, ®, &bit, + &width); if (ret < 0) return ret; @@ -365,8 +573,10 @@ static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev, /* LOCK can't be cleared */ if (param == TEGRA_PINCONF_PARAM_LOCK) { - if ((val & BIT(bit)) && !arg) + if ((val & BIT(bit)) && !arg) { + dev_err(pctldev->dev, "LOCK bit cannot be cleared\n"); return -EINVAL; + } } /* Special-case Boolean values; allow any non-zero as true */ @@ -375,8 +585,12 @@ static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev, /* Range-check user-supplied value */ mask = (1 << width) - 1; - if (arg & ~mask) + if (arg & ~mask) { + dev_err(pctldev->dev, + "config %lx: %x too big for %d bit register\n", + config, arg, width); return -EINVAL; + } /* Update register */ val &= ~(mask << bit); @@ -386,23 +600,78 @@ static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev, return 0; } +#ifdef CONFIG_DEBUG_FS static void tegra_pinconf_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned offset) { } +static const char *strip_prefix(const char *s) +{ + const char *comma = strchr(s, ','); + if (!comma) + return s; + + return comma + 1; +} + static void tegra_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, - struct seq_file *s, unsigned selector) + struct seq_file *s, unsigned group) { + struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + const struct tegra_pingroup *g; + int i, ret; + s8 bank, bit, width; + s16 reg; + u32 val; + + g = &pmx->soc->groups[group]; + + for (i = 0; i < ARRAY_SIZE(cfg_params); i++) { + ret = tegra_pinconf_reg(pmx, g, cfg_params[i].param, false, + &bank, ®, &bit, &width); + if (ret < 0) + continue; + + val = pmx_readl(pmx, bank, reg); + val >>= bit; + val &= (1 << width) - 1; + + seq_printf(s, "\n\t%s=%u", + strip_prefix(cfg_params[i].property), val); + } } +static void tegra_pinconf_config_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, + unsigned long config) +{ + enum tegra_pinconf_param param = TEGRA_PINCONF_UNPACK_PARAM(config); + u16 arg = TEGRA_PINCONF_UNPACK_ARG(config); + const char *pname = "unknown"; + int i; + + for (i = 0; i < ARRAY_SIZE(cfg_params); i++) { + if (cfg_params[i].param == param) { + pname = cfg_params[i].property; + break; + } + } + + seq_printf(s, "%s=%d", strip_prefix(pname), arg); +} +#endif + struct pinconf_ops tegra_pinconf_ops = { .pin_config_get = tegra_pinconf_get, .pin_config_set = tegra_pinconf_set, .pin_config_group_get = tegra_pinconf_group_get, .pin_config_group_set = tegra_pinconf_group_set, +#ifdef CONFIG_DEBUG_FS .pin_config_dbg_show = tegra_pinconf_dbg_show, .pin_config_group_dbg_show = tegra_pinconf_group_dbg_show, + .pin_config_config_dbg_show = tegra_pinconf_config_dbg_show, +#endif }; static struct pinctrl_gpio_range tegra_pinctrl_gpio_range = { @@ -412,60 +681,29 @@ static struct pinctrl_gpio_range tegra_pinctrl_gpio_range = { }; static struct pinctrl_desc tegra_pinctrl_desc = { - .name = DRIVER_NAME, .pctlops = &tegra_pinctrl_ops, .pmxops = &tegra_pinmux_ops, .confops = &tegra_pinconf_ops, .owner = THIS_MODULE, }; -static struct of_device_id tegra_pinctrl_of_match[] __devinitdata = { -#ifdef CONFIG_PINCTRL_TEGRA20 - { - .compatible = "nvidia,tegra20-pinmux-disabled", - .data = tegra20_pinctrl_init, - }, -#endif -#ifdef CONFIG_PINCTRL_TEGRA30 - { - .compatible = "nvidia,tegra30-pinmux-disabled", - .data = tegra30_pinctrl_init, - }, -#endif - {}, -}; - -static int __devinit tegra_pinctrl_probe(struct platform_device *pdev) +int __devinit tegra_pinctrl_probe(struct platform_device *pdev, + const struct tegra_pinctrl_soc_data *soc_data) { - const struct of_device_id *match; - tegra_pinctrl_soc_initf initf = NULL; struct tegra_pmx *pmx; struct resource *res; int i; - match = of_match_device(tegra_pinctrl_of_match, &pdev->dev); - if (match) - initf = (tegra_pinctrl_soc_initf)match->data; -#ifdef CONFIG_PINCTRL_TEGRA20 - if (!initf) - initf = tegra20_pinctrl_init; -#endif - if (!initf) { - dev_err(&pdev->dev, - "Could not determine SoC-specific init func\n"); - return -EINVAL; - } - pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL); if (!pmx) { dev_err(&pdev->dev, "Can't alloc tegra_pmx\n"); return -ENOMEM; } pmx->dev = &pdev->dev; - - (*initf)(&pmx->soc); + pmx->soc = soc_data; tegra_pinctrl_gpio_range.npins = pmx->soc->ngpios; + tegra_pinctrl_desc.name = dev_name(&pdev->dev); tegra_pinctrl_desc.pins = pmx->soc->pins; tegra_pinctrl_desc.npins = pmx->soc->npins; @@ -520,8 +758,9 @@ static int __devinit tegra_pinctrl_probe(struct platform_device *pdev) return 0; } +EXPORT_SYMBOL_GPL(tegra_pinctrl_probe); -static int __devexit tegra_pinctrl_remove(struct platform_device *pdev) +int __devexit tegra_pinctrl_remove(struct platform_device *pdev) { struct tegra_pmx *pmx = platform_get_drvdata(pdev); @@ -530,30 +769,4 @@ static int __devexit tegra_pinctrl_remove(struct platform_device *pdev) return 0; } - -static struct platform_driver tegra_pinctrl_driver = { - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - .of_match_table = tegra_pinctrl_of_match, - }, - .probe = tegra_pinctrl_probe, - .remove = __devexit_p(tegra_pinctrl_remove), -}; - -static int __init tegra_pinctrl_init(void) -{ - return platform_driver_register(&tegra_pinctrl_driver); -} -arch_initcall(tegra_pinctrl_init); - -static void __exit tegra_pinctrl_exit(void) -{ - platform_driver_unregister(&tegra_pinctrl_driver); -} -module_exit(tegra_pinctrl_exit); - -MODULE_AUTHOR("Stephen Warren "); -MODULE_DESCRIPTION("NVIDIA Tegra pinctrl driver"); -MODULE_LICENSE("GPL v2"); -MODULE_DEVICE_TABLE(of, tegra_pinctrl_of_match); +EXPORT_SYMBOL_GPL(tegra_pinctrl_remove); diff --git a/trunk/drivers/pinctrl/pinctrl-tegra.h b/trunk/drivers/pinctrl/pinctrl-tegra.h index 782c795326ef..705c007a38cc 100644 --- a/trunk/drivers/pinctrl/pinctrl-tegra.h +++ b/trunk/drivers/pinctrl/pinctrl-tegra.h @@ -139,25 +139,8 @@ struct tegra_pinctrl_soc_data { unsigned ngroups; }; -/** - * tegra_pinctrl_soc_initf() - Retrieve pin controller details for a SoC. - * @soc_data: This pointer must be updated to point at a struct containing - * details of the SoC. - */ -typedef void (*tegra_pinctrl_soc_initf)( - const struct tegra_pinctrl_soc_data **soc_data); - -/** - * tegra20_pinctrl_init() - Retrieve pin controller details for Tegra20 - * @soc_data: This pointer will be updated to point at a struct containing - * details of Tegra20's pin controller. - */ -void tegra20_pinctrl_init(const struct tegra_pinctrl_soc_data **soc_data); -/** - * tegra30_pinctrl_init() - Retrieve pin controller details for Tegra20 - * @soc_data: This pointer will be updated to point at a struct containing - * details of Tegra30's pin controller. - */ -void tegra30_pinctrl_init(const struct tegra_pinctrl_soc_data **soc_data); +int tegra_pinctrl_probe(struct platform_device *pdev, + const struct tegra_pinctrl_soc_data *soc_data); +int tegra_pinctrl_remove(struct platform_device *pdev); #endif diff --git a/trunk/drivers/pinctrl/pinctrl-tegra20.c b/trunk/drivers/pinctrl/pinctrl-tegra20.c index f69ff96aa292..a74f9a568536 100644 --- a/trunk/drivers/pinctrl/pinctrl-tegra20.c +++ b/trunk/drivers/pinctrl/pinctrl-tegra20.c @@ -1,7 +1,7 @@ /* * Pinctrl data for the NVIDIA Tegra20 pinmux * - * Copyright (c) 2011, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved. * * Derived from code: * Copyright (C) 2010 Google, Inc. @@ -17,6 +17,8 @@ * more details. */ +#include +#include #include #include #include @@ -2854,7 +2856,39 @@ static const struct tegra_pinctrl_soc_data tegra20_pinctrl = { .ngroups = ARRAY_SIZE(tegra20_groups), }; -void __devinit tegra20_pinctrl_init(const struct tegra_pinctrl_soc_data **soc) +static int __devinit tegra20_pinctrl_probe(struct platform_device *pdev) { - *soc = &tegra20_pinctrl; + return tegra_pinctrl_probe(pdev, &tegra20_pinctrl); } + +static struct of_device_id tegra20_pinctrl_of_match[] __devinitdata = { + { .compatible = "nvidia,tegra20-pinmux", }, + { }, +}; + +static struct platform_driver tegra20_pinctrl_driver = { + .driver = { + .name = "tegra20-pinctrl", + .owner = THIS_MODULE, + .of_match_table = tegra20_pinctrl_of_match, + }, + .probe = tegra20_pinctrl_probe, + .remove = __devexit_p(tegra_pinctrl_remove), +}; + +static int __init tegra20_pinctrl_init(void) +{ + return platform_driver_register(&tegra20_pinctrl_driver); +} +arch_initcall(tegra20_pinctrl_init); + +static void __exit tegra20_pinctrl_exit(void) +{ + platform_driver_unregister(&tegra20_pinctrl_driver); +} +module_exit(tegra20_pinctrl_exit); + +MODULE_AUTHOR("Stephen Warren "); +MODULE_DESCRIPTION("NVIDIA Tegra20 pinctrl driver"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, tegra20_pinctrl_of_match); diff --git a/trunk/drivers/pinctrl/pinctrl-tegra30.c b/trunk/drivers/pinctrl/pinctrl-tegra30.c index 4d7571d4a431..0386fdf0da16 100644 --- a/trunk/drivers/pinctrl/pinctrl-tegra30.c +++ b/trunk/drivers/pinctrl/pinctrl-tegra30.c @@ -1,7 +1,7 @@ /* * Pinctrl data for the NVIDIA Tegra30 pinmux * - * Copyright (c) 2011, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -13,6 +13,8 @@ * more details. */ +#include +#include #include #include #include @@ -3720,7 +3722,39 @@ static const struct tegra_pinctrl_soc_data tegra30_pinctrl = { .ngroups = ARRAY_SIZE(tegra30_groups), }; -void __devinit tegra30_pinctrl_init(const struct tegra_pinctrl_soc_data **soc) +static int __devinit tegra30_pinctrl_probe(struct platform_device *pdev) { - *soc = &tegra30_pinctrl; + return tegra_pinctrl_probe(pdev, &tegra30_pinctrl); } + +static struct of_device_id tegra30_pinctrl_of_match[] __devinitdata = { + { .compatible = "nvidia,tegra30-pinmux", }, + { }, +}; + +static struct platform_driver tegra30_pinctrl_driver = { + .driver = { + .name = "tegra30-pinctrl", + .owner = THIS_MODULE, + .of_match_table = tegra30_pinctrl_of_match, + }, + .probe = tegra30_pinctrl_probe, + .remove = __devexit_p(tegra_pinctrl_remove), +}; + +static int __init tegra30_pinctrl_init(void) +{ + return platform_driver_register(&tegra30_pinctrl_driver); +} +arch_initcall(tegra30_pinctrl_init); + +static void __exit tegra30_pinctrl_exit(void) +{ + platform_driver_unregister(&tegra30_pinctrl_driver); +} +module_exit(tegra30_pinctrl_exit); + +MODULE_AUTHOR("Stephen Warren "); +MODULE_DESCRIPTION("NVIDIA Tegra30 pinctrl driver"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, tegra30_pinctrl_of_match); diff --git a/trunk/drivers/pinctrl/pinctrl-u300.c b/trunk/drivers/pinctrl/pinctrl-u300.c index 26eb8ccd72d5..05d029911be6 100644 --- a/trunk/drivers/pinctrl/pinctrl-u300.c +++ b/trunk/drivers/pinctrl/pinctrl-u300.c @@ -836,18 +836,14 @@ static const struct u300_pin_group u300_pin_groups[] = { }, }; -static int u300_list_groups(struct pinctrl_dev *pctldev, unsigned selector) +static int u300_get_groups_count(struct pinctrl_dev *pctldev) { - if (selector >= ARRAY_SIZE(u300_pin_groups)) - return -EINVAL; - return 0; + return ARRAY_SIZE(u300_pin_groups); } static const char *u300_get_group_name(struct pinctrl_dev *pctldev, unsigned selector) { - if (selector >= ARRAY_SIZE(u300_pin_groups)) - return NULL; return u300_pin_groups[selector].name; } @@ -855,8 +851,6 @@ static int u300_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, const unsigned **pins, unsigned *num_pins) { - if (selector >= ARRAY_SIZE(u300_pin_groups)) - return -EINVAL; *pins = u300_pin_groups[selector].pins; *num_pins = u300_pin_groups[selector].num_pins; return 0; @@ -869,7 +863,7 @@ static void u300_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, } static struct pinctrl_ops u300_pctrl_ops = { - .list_groups = u300_list_groups, + .get_groups_count = u300_get_groups_count, .get_group_name = u300_get_group_name, .get_group_pins = u300_get_group_pins, .pin_dbg_show = u300_pin_dbg_show, @@ -991,11 +985,9 @@ static void u300_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector, u300_pmx_endisable(upmx, selector, false); } -static int u300_pmx_list_funcs(struct pinctrl_dev *pctldev, unsigned selector) +static int u300_pmx_get_funcs_count(struct pinctrl_dev *pctldev) { - if (selector >= ARRAY_SIZE(u300_pmx_functions)) - return -EINVAL; - return 0; + return ARRAY_SIZE(u300_pmx_functions); } static const char *u300_pmx_get_func_name(struct pinctrl_dev *pctldev, @@ -1014,7 +1006,7 @@ static int u300_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector, } static struct pinmux_ops u300_pmx_ops = { - .list_functions = u300_pmx_list_funcs, + .get_functions_count = u300_pmx_get_funcs_count, .get_function_name = u300_pmx_get_func_name, .get_function_groups = u300_pmx_get_groups, .enable = u300_pmx_enable, diff --git a/trunk/drivers/pinctrl/pinmux.c b/trunk/drivers/pinctrl/pinmux.c index 4e62783a573a..3d5ac73bd5a7 100644 --- a/trunk/drivers/pinctrl/pinmux.c +++ b/trunk/drivers/pinctrl/pinmux.c @@ -33,22 +33,25 @@ int pinmux_check_ops(struct pinctrl_dev *pctldev) { const struct pinmux_ops *ops = pctldev->desc->pmxops; + unsigned nfuncs; unsigned selector = 0; /* Check that we implement required operations */ - if (!ops->list_functions || + if (!ops || + !ops->get_functions_count || !ops->get_function_name || !ops->get_function_groups || - !ops->enable || - !ops->disable) + !ops->enable) { + dev_err(pctldev->dev, "pinmux ops lacks necessary functions\n"); return -EINVAL; - + } /* Check that all functions registered have names */ - while (ops->list_functions(pctldev, selector) >= 0) { + nfuncs = ops->get_functions_count(pctldev); + while (selector < nfuncs) { const char *fname = ops->get_function_name(pctldev, selector); if (!fname) { - pr_err("pinmux ops has no name for function%u\n", + dev_err(pctldev->dev, "pinmux ops has no name for function%u\n", selector); return -EINVAL; } @@ -85,20 +88,23 @@ static int pin_request(struct pinctrl_dev *pctldev, const struct pinmux_ops *ops = pctldev->desc->pmxops; int status = -EINVAL; - dev_dbg(pctldev->dev, "request pin %d for %s\n", pin, owner); - desc = pin_desc_get(pctldev, pin); if (desc == NULL) { dev_err(pctldev->dev, - "pin is not registered so it cannot be requested\n"); + "pin %d is not registered so it cannot be requested\n", + pin); goto out; } + dev_dbg(pctldev->dev, "request pin %d (%s) for %s\n", + pin, desc->name, owner); + if (gpio_range) { /* There's no need to support multiple GPIO requests */ if (desc->gpio_owner) { dev_err(pctldev->dev, - "pin already requested\n"); + "pin %s already requested by %s; cannot claim for %s\n", + desc->name, desc->gpio_owner, owner); goto out; } @@ -106,7 +112,8 @@ static int pin_request(struct pinctrl_dev *pctldev, } else { if (desc->mux_usecount && strcmp(desc->mux_owner, owner)) { dev_err(pctldev->dev, - "pin already requested\n"); + "pin %s already requested by %s; cannot claim for %s\n", + desc->name, desc->mux_owner, owner); goto out; } @@ -139,8 +146,7 @@ static int pin_request(struct pinctrl_dev *pctldev, status = 0; if (status) { - dev_err(pctldev->dev, "->request on device %s failed for pin %d\n", - pctldev->desc->name, pin); + dev_err(pctldev->dev, "request() failed for pin %d\n", pin); module_put(pctldev->owner); } @@ -157,7 +163,7 @@ static int pin_request(struct pinctrl_dev *pctldev, out: if (status) dev_err(pctldev->dev, "pin-%d (%s) status %d\n", - pin, owner, status); + pin, owner, status); return status; } @@ -287,10 +293,11 @@ static int pinmux_func_name_to_selector(struct pinctrl_dev *pctldev, const char *function) { const struct pinmux_ops *ops = pctldev->desc->pmxops; + unsigned nfuncs = ops->get_functions_count(pctldev); unsigned selector = 0; /* See if this pctldev has this function */ - while (ops->list_functions(pctldev, selector) >= 0) { + while (selector < nfuncs) { const char *fname = ops->get_function_name(pctldev, selector); @@ -319,18 +326,32 @@ int pinmux_map_to_setting(struct pinctrl_map const *map, const unsigned *pins; unsigned num_pins; - setting->data.mux.func = - pinmux_func_name_to_selector(pctldev, map->data.mux.function); - if (setting->data.mux.func < 0) - return setting->data.mux.func; + if (!pmxops) { + dev_err(pctldev->dev, "does not support mux function\n"); + return -EINVAL; + } + + ret = pinmux_func_name_to_selector(pctldev, map->data.mux.function); + if (ret < 0) { + dev_err(pctldev->dev, "invalid function %s in map table\n", + map->data.mux.function); + return ret; + } + setting->data.mux.func = ret; ret = pmxops->get_function_groups(pctldev, setting->data.mux.func, &groups, &num_groups); - if (ret < 0) + if (ret < 0) { + dev_err(pctldev->dev, "can't query groups for function %s\n", + map->data.mux.function); return ret; - if (!num_groups) + } + if (!num_groups) { + dev_err(pctldev->dev, + "function %s can't be selected on any group\n", + map->data.mux.function); return -EINVAL; - + } if (map->data.mux.group) { bool found = false; group = map->data.mux.group; @@ -340,15 +361,23 @@ int pinmux_map_to_setting(struct pinctrl_map const *map, break; } } - if (!found) + if (!found) { + dev_err(pctldev->dev, + "invalid group \"%s\" for function \"%s\"\n", + group, map->data.mux.function); return -EINVAL; + } } else { group = groups[0]; } - setting->data.mux.group = pinctrl_get_group_selector(pctldev, group); - if (setting->data.mux.group < 0) - return setting->data.mux.group; + ret = pinctrl_get_group_selector(pctldev, group); + if (ret < 0) { + dev_err(pctldev->dev, "invalid group %s in map table\n", + map->data.mux.group); + return ret; + } + setting->data.mux.group = ret; ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, &pins, &num_pins); @@ -364,7 +393,7 @@ int pinmux_map_to_setting(struct pinctrl_map const *map, ret = pin_request(pctldev, pins[i], map->dev_name, NULL); if (ret) { dev_err(pctldev->dev, - "could not get request pin %d on device %s\n", + "could not request pin %d on device %s\n", pins[i], pinctrl_dev_get_name(pctldev)); /* On error release all taken pins */ i--; /* this pin just failed */ @@ -467,7 +496,8 @@ void pinmux_disable_setting(struct pinctrl_setting const *setting) desc->mux_setting = NULL; } - ops->disable(pctldev, setting->data.mux.func, setting->data.mux.group); + if (ops->disable) + ops->disable(pctldev, setting->data.mux.func, setting->data.mux.group); } #ifdef CONFIG_DEBUG_FS @@ -477,11 +507,15 @@ static int pinmux_functions_show(struct seq_file *s, void *what) { struct pinctrl_dev *pctldev = s->private; const struct pinmux_ops *pmxops = pctldev->desc->pmxops; + unsigned nfuncs; unsigned func_selector = 0; - mutex_lock(&pinctrl_mutex); + if (!pmxops) + return 0; - while (pmxops->list_functions(pctldev, func_selector) >= 0) { + mutex_lock(&pinctrl_mutex); + nfuncs = pmxops->get_functions_count(pctldev); + while (func_selector < nfuncs) { const char *func = pmxops->get_function_name(pctldev, func_selector); const char * const *groups; @@ -515,6 +549,9 @@ static int pinmux_pins_show(struct seq_file *s, void *what) const struct pinmux_ops *pmxops = pctldev->desc->pmxops; unsigned i, pin; + if (!pmxops) + return 0; + seq_puts(s, "Pinmux settings per pin\n"); seq_puts(s, "Format: pin (name): mux_owner gpio_owner hog?\n"); diff --git a/trunk/drivers/pinctrl/pinmux.h b/trunk/drivers/pinctrl/pinmux.h index 6fc47003e95d..d1a98b1c9fce 100644 --- a/trunk/drivers/pinctrl/pinmux.h +++ b/trunk/drivers/pinctrl/pinmux.h @@ -31,12 +31,6 @@ void pinmux_free_setting(struct pinctrl_setting const *setting); int pinmux_enable_setting(struct pinctrl_setting const *setting); void pinmux_disable_setting(struct pinctrl_setting const *setting); -void pinmux_show_map(struct seq_file *s, struct pinctrl_map const *map); -void pinmux_show_setting(struct seq_file *s, - struct pinctrl_setting const *setting); -void pinmux_init_device_debugfs(struct dentry *devroot, - struct pinctrl_dev *pctldev); - #else static inline int pinmux_check_ops(struct pinctrl_dev *pctldev) @@ -89,6 +83,18 @@ static inline void pinmux_disable_setting( { } +#endif + +#if defined(CONFIG_PINMUX) && defined(CONFIG_DEBUG_FS) + +void pinmux_show_map(struct seq_file *s, struct pinctrl_map const *map); +void pinmux_show_setting(struct seq_file *s, + struct pinctrl_setting const *setting); +void pinmux_init_device_debugfs(struct dentry *devroot, + struct pinctrl_dev *pctldev); + +#else + static inline void pinmux_show_map(struct seq_file *s, struct pinctrl_map const *map) { diff --git a/trunk/drivers/pinctrl/spear/Kconfig b/trunk/drivers/pinctrl/spear/Kconfig new file mode 100644 index 000000000000..6a2596b4f359 --- /dev/null +++ b/trunk/drivers/pinctrl/spear/Kconfig @@ -0,0 +1,34 @@ +# +# ST Microelectronics SPEAr PINCTRL drivers +# + +if PLAT_SPEAR + +config PINCTRL_SPEAR + bool + depends on OF + select PINMUX + help + This enables pin control drivers for SPEAr Platform + +config PINCTRL_SPEAR3XX + bool + depends on ARCH_SPEAR3XX + select PINCTRL_SPEAR + +config PINCTRL_SPEAR300 + bool "ST Microelectronics SPEAr300 SoC pin controller driver" + depends on MACH_SPEAR300 + select PINCTRL_SPEAR3XX + +config PINCTRL_SPEAR310 + bool "ST Microelectronics SPEAr310 SoC pin controller driver" + depends on MACH_SPEAR310 + select PINCTRL_SPEAR3XX + +config PINCTRL_SPEAR320 + bool "ST Microelectronics SPEAr320 SoC pin controller driver" + depends on MACH_SPEAR320 + select PINCTRL_SPEAR3XX + +endif diff --git a/trunk/drivers/pinctrl/spear/Makefile b/trunk/drivers/pinctrl/spear/Makefile new file mode 100644 index 000000000000..15dcb85da22d --- /dev/null +++ b/trunk/drivers/pinctrl/spear/Makefile @@ -0,0 +1,7 @@ +# SPEAr pinmux support + +obj-$(CONFIG_PINCTRL_SPEAR) += pinctrl-spear.o +obj-$(CONFIG_PINCTRL_SPEAR3XX) += pinctrl-spear3xx.o +obj-$(CONFIG_PINCTRL_SPEAR300) += pinctrl-spear300.o +obj-$(CONFIG_PINCTRL_SPEAR310) += pinctrl-spear310.o +obj-$(CONFIG_PINCTRL_SPEAR320) += pinctrl-spear320.o diff --git a/trunk/drivers/pinctrl/spear/pinctrl-spear.c b/trunk/drivers/pinctrl/spear/pinctrl-spear.c new file mode 100644 index 000000000000..5ae50aadf885 --- /dev/null +++ b/trunk/drivers/pinctrl/spear/pinctrl-spear.c @@ -0,0 +1,354 @@ +/* + * Driver for the ST Microelectronics SPEAr pinmux + * + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar + * + * Inspired from: + * - U300 Pinctl drivers + * - Tegra Pinctl drivers + * + * 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 "pinctrl-spear.h" + +#define DRIVER_NAME "spear-pinmux" + +static inline u32 pmx_readl(struct spear_pmx *pmx, u32 reg) +{ + return readl_relaxed(pmx->vbase + reg); +} + +static inline void pmx_writel(struct spear_pmx *pmx, u32 val, u32 reg) +{ + writel_relaxed(val, pmx->vbase + reg); +} + +static int set_mode(struct spear_pmx *pmx, int mode) +{ + struct spear_pmx_mode *pmx_mode = NULL; + int i; + u32 val; + + if (!pmx->machdata->pmx_modes || !pmx->machdata->npmx_modes) + return -EINVAL; + + for (i = 0; i < pmx->machdata->npmx_modes; i++) { + if (pmx->machdata->pmx_modes[i]->mode == (1 << mode)) { + pmx_mode = pmx->machdata->pmx_modes[i]; + break; + } + } + + if (!pmx_mode) + return -EINVAL; + + val = pmx_readl(pmx, pmx_mode->reg); + val &= ~pmx_mode->mask; + val |= pmx_mode->val; + pmx_writel(pmx, val, pmx_mode->reg); + + pmx->machdata->mode = pmx_mode->mode; + dev_info(pmx->dev, "Configured Mode: %s with id: %x\n\n", + pmx_mode->name ? pmx_mode->name : "no_name", + pmx_mode->reg); + + return 0; +} + +void __devinit pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg) +{ + struct spear_pingroup *pgroup; + struct spear_modemux *modemux; + int i, j, group; + + for (group = 0; group < machdata->ngroups; group++) { + pgroup = machdata->groups[group]; + + for (i = 0; i < pgroup->nmodemuxs; i++) { + modemux = &pgroup->modemuxs[i]; + + for (j = 0; j < modemux->nmuxregs; j++) + if (modemux->muxregs[j].reg == 0xFFFF) + modemux->muxregs[j].reg = reg; + } + } +} + +static int spear_pinctrl_get_groups_cnt(struct pinctrl_dev *pctldev) +{ + struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + + return pmx->machdata->ngroups; +} + +static const char *spear_pinctrl_get_group_name(struct pinctrl_dev *pctldev, + unsigned group) +{ + struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + + return pmx->machdata->groups[group]->name; +} + +static int spear_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned group, const unsigned **pins, unsigned *num_pins) +{ + struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + + *pins = pmx->machdata->groups[group]->pins; + *num_pins = pmx->machdata->groups[group]->npins; + + return 0; +} + +static void spear_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned offset) +{ + seq_printf(s, " " DRIVER_NAME); +} + +int spear_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, unsigned *num_maps) +{ + struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + struct device_node *np; + struct property *prop; + const char *function, *group; + int ret, index = 0, count = 0; + + /* calculate number of maps required */ + for_each_child_of_node(np_config, np) { + ret = of_property_read_string(np, "st,function", &function); + if (ret < 0) + return ret; + + ret = of_property_count_strings(np, "st,pins"); + if (ret < 0) + return ret; + + count += ret; + } + + if (!count) { + dev_err(pmx->dev, "No child nodes passed via DT\n"); + return -ENODEV; + } + + *map = kzalloc(sizeof(**map) * count, GFP_KERNEL); + if (!*map) + return -ENOMEM; + + for_each_child_of_node(np_config, np) { + of_property_read_string(np, "st,function", &function); + of_property_for_each_string(np, "st,pins", prop, group) { + (*map)[index].type = PIN_MAP_TYPE_MUX_GROUP; + (*map)[index].data.mux.group = group; + (*map)[index].data.mux.function = function; + index++; + } + } + + *num_maps = count; + + return 0; +} + +void spear_pinctrl_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) +{ + kfree(map); +} + +static struct pinctrl_ops spear_pinctrl_ops = { + .get_groups_count = spear_pinctrl_get_groups_cnt, + .get_group_name = spear_pinctrl_get_group_name, + .get_group_pins = spear_pinctrl_get_group_pins, + .pin_dbg_show = spear_pinctrl_pin_dbg_show, + .dt_node_to_map = spear_pinctrl_dt_node_to_map, + .dt_free_map = spear_pinctrl_dt_free_map, +}; + +static int spear_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev) +{ + struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + + return pmx->machdata->nfunctions; +} + +static const char *spear_pinctrl_get_func_name(struct pinctrl_dev *pctldev, + unsigned function) +{ + struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + + return pmx->machdata->functions[function]->name; +} + +static int spear_pinctrl_get_func_groups(struct pinctrl_dev *pctldev, + unsigned function, const char *const **groups, + unsigned * const ngroups) +{ + struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + + *groups = pmx->machdata->functions[function]->groups; + *ngroups = pmx->machdata->functions[function]->ngroups; + + return 0; +} + +static int spear_pinctrl_endisable(struct pinctrl_dev *pctldev, + unsigned function, unsigned group, bool enable) +{ + struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + const struct spear_pingroup *pgroup; + const struct spear_modemux *modemux; + struct spear_muxreg *muxreg; + u32 val, temp; + int i, j; + bool found = false; + + pgroup = pmx->machdata->groups[group]; + + for (i = 0; i < pgroup->nmodemuxs; i++) { + modemux = &pgroup->modemuxs[i]; + + /* SoC have any modes */ + if (pmx->machdata->modes_supported) { + if (!(pmx->machdata->mode & modemux->modes)) + continue; + } + + found = true; + for (j = 0; j < modemux->nmuxregs; j++) { + muxreg = &modemux->muxregs[j]; + + val = pmx_readl(pmx, muxreg->reg); + val &= ~muxreg->mask; + + if (enable) + temp = muxreg->val; + else + temp = ~muxreg->val; + + val |= temp; + pmx_writel(pmx, val, muxreg->reg); + } + } + + if (!found) { + dev_err(pmx->dev, "pinmux group: %s not supported\n", + pgroup->name); + return -ENODEV; + } + + return 0; +} + +static int spear_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned function, + unsigned group) +{ + return spear_pinctrl_endisable(pctldev, function, group, true); +} + +static void spear_pinctrl_disable(struct pinctrl_dev *pctldev, + unsigned function, unsigned group) +{ + spear_pinctrl_endisable(pctldev, function, group, false); +} + +static struct pinmux_ops spear_pinmux_ops = { + .get_functions_count = spear_pinctrl_get_funcs_count, + .get_function_name = spear_pinctrl_get_func_name, + .get_function_groups = spear_pinctrl_get_func_groups, + .enable = spear_pinctrl_enable, + .disable = spear_pinctrl_disable, +}; + +static struct pinctrl_desc spear_pinctrl_desc = { + .name = DRIVER_NAME, + .pctlops = &spear_pinctrl_ops, + .pmxops = &spear_pinmux_ops, + .owner = THIS_MODULE, +}; + +int __devinit spear_pinctrl_probe(struct platform_device *pdev, + struct spear_pinctrl_machdata *machdata) +{ + struct device_node *np = pdev->dev.of_node; + struct resource *res; + struct spear_pmx *pmx; + + if (!machdata) + return -ENODEV; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; + + pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL); + if (!pmx) { + dev_err(&pdev->dev, "Can't alloc spear_pmx\n"); + return -ENOMEM; + } + + pmx->vbase = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!pmx->vbase) { + dev_err(&pdev->dev, "Couldn't ioremap at index 0\n"); + return -ENODEV; + } + + pmx->dev = &pdev->dev; + pmx->machdata = machdata; + + /* configure mode, if supported by SoC */ + if (machdata->modes_supported) { + int mode = 0; + + if (of_property_read_u32(np, "st,pinmux-mode", &mode)) { + dev_err(&pdev->dev, "OF: pinmux mode not passed\n"); + return -EINVAL; + } + + if (set_mode(pmx, mode)) { + dev_err(&pdev->dev, "OF: Couldn't configure mode: %x\n", + mode); + return -EINVAL; + } + } + + platform_set_drvdata(pdev, pmx); + + spear_pinctrl_desc.pins = machdata->pins; + spear_pinctrl_desc.npins = machdata->npins; + + pmx->pctl = pinctrl_register(&spear_pinctrl_desc, &pdev->dev, pmx); + if (IS_ERR(pmx->pctl)) { + dev_err(&pdev->dev, "Couldn't register pinctrl driver\n"); + return PTR_ERR(pmx->pctl); + } + + return 0; +} + +int __devexit spear_pinctrl_remove(struct platform_device *pdev) +{ + struct spear_pmx *pmx = platform_get_drvdata(pdev); + + pinctrl_unregister(pmx->pctl); + + return 0; +} diff --git a/trunk/drivers/pinctrl/spear/pinctrl-spear.h b/trunk/drivers/pinctrl/spear/pinctrl-spear.h new file mode 100644 index 000000000000..47a6b5b72f90 --- /dev/null +++ b/trunk/drivers/pinctrl/spear/pinctrl-spear.h @@ -0,0 +1,142 @@ +/* + * Driver header file for the ST Microelectronics SPEAr pinmux + * + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar + * + * 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. + */ + +#ifndef __PINMUX_SPEAR_H__ +#define __PINMUX_SPEAR_H__ + +#include +#include + +struct platform_device; +struct device; + +/** + * struct spear_pmx_mode - SPEAr pmx mode + * @name: name of pmx mode + * @mode: mode id + * @reg: register for configuring this mode + * @mask: mask of this mode in reg + * @val: val to be configured at reg after doing (val & mask) + */ +struct spear_pmx_mode { + const char *const name; + u16 mode; + u16 reg; + u16 mask; + u32 val; +}; + +/** + * struct spear_muxreg - SPEAr mux reg configuration + * @reg: register offset + * @mask: mask bits + * @val: val to be written on mask bits + */ +struct spear_muxreg { + u16 reg; + u32 mask; + u32 val; +}; + +/** + * struct spear_modemux - SPEAr mode mux configuration + * @modes: mode ids supported by this group of muxregs + * @nmuxregs: number of muxreg configurations to be done for modes + * @muxregs: array of muxreg configurations to be done for modes + */ +struct spear_modemux { + u16 modes; + u8 nmuxregs; + struct spear_muxreg *muxregs; +}; + +/** + * struct spear_pingroup - SPEAr pin group configurations + * @name: name of pin group + * @pins: array containing pin numbers + * @npins: size of pins array + * @modemuxs: array of modemux configurations for this pin group + * @nmodemuxs: size of array modemuxs + * + * A representation of a group of pins in the SPEAr pin controller. Each group + * allows some parameter or parameters to be configured. + */ +struct spear_pingroup { + const char *name; + const unsigned *pins; + unsigned npins; + struct spear_modemux *modemuxs; + unsigned nmodemuxs; +}; + +/** + * struct spear_function - SPEAr pinctrl mux function + * @name: The name of the function, exported to pinctrl core. + * @groups: An array of pin groups that may select this function. + * @ngroups: The number of entries in @groups. + */ +struct spear_function { + const char *name; + const char *const *groups; + unsigned ngroups; +}; + +/** + * struct spear_pinctrl_machdata - SPEAr pin controller machine driver + * configuration + * @pins: An array describing all pins the pin controller affects. + * All pins which are also GPIOs must be listed first within the *array, + * and be numbered identically to the GPIO controller's *numbering. + * @npins: The numbmer of entries in @pins. + * @functions: An array describing all mux functions the SoC supports. + * @nfunctions: The numbmer of entries in @functions. + * @groups: An array describing all pin groups the pin SoC supports. + * @ngroups: The numbmer of entries in @groups. + * + * @modes_supported: Does SoC support modes + * @mode: mode configured from probe + * @pmx_modes: array of modes supported by SoC + * @npmx_modes: number of entries in pmx_modes. + */ +struct spear_pinctrl_machdata { + const struct pinctrl_pin_desc *pins; + unsigned npins; + struct spear_function **functions; + unsigned nfunctions; + struct spear_pingroup **groups; + unsigned ngroups; + + bool modes_supported; + u16 mode; + struct spear_pmx_mode **pmx_modes; + unsigned npmx_modes; +}; + +/** + * struct spear_pmx - SPEAr pinctrl mux + * @dev: pointer to struct dev of platform_device registered + * @pctl: pointer to struct pinctrl_dev + * @machdata: pointer to SoC or machine specific structure + * @vbase: virtual base address of pinmux controller + */ +struct spear_pmx { + struct device *dev; + struct pinctrl_dev *pctl; + struct spear_pinctrl_machdata *machdata; + void __iomem *vbase; +}; + +/* exported routines */ +void __devinit pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg); +int __devinit spear_pinctrl_probe(struct platform_device *pdev, + struct spear_pinctrl_machdata *machdata); +int __devexit spear_pinctrl_remove(struct platform_device *pdev); +#endif /* __PINMUX_SPEAR_H__ */ diff --git a/trunk/drivers/pinctrl/spear/pinctrl-spear300.c b/trunk/drivers/pinctrl/spear/pinctrl-spear300.c new file mode 100644 index 000000000000..9c82a35e4e78 --- /dev/null +++ b/trunk/drivers/pinctrl/spear/pinctrl-spear300.c @@ -0,0 +1,708 @@ +/* + * Driver for the ST Microelectronics SPEAr300 pinmux + * + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar + * + * 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 "pinctrl-spear3xx.h" + +#define DRIVER_NAME "spear300-pinmux" + +/* addresses */ +#define PMX_CONFIG_REG 0x00 +#define MODE_CONFIG_REG 0x04 + +/* modes */ +#define NAND_MODE (1 << 0) +#define NOR_MODE (1 << 1) +#define PHOTO_FRAME_MODE (1 << 2) +#define LEND_IP_PHONE_MODE (1 << 3) +#define HEND_IP_PHONE_MODE (1 << 4) +#define LEND_WIFI_PHONE_MODE (1 << 5) +#define HEND_WIFI_PHONE_MODE (1 << 6) +#define ATA_PABX_WI2S_MODE (1 << 7) +#define ATA_PABX_I2S_MODE (1 << 8) +#define CAML_LCDW_MODE (1 << 9) +#define CAMU_LCD_MODE (1 << 10) +#define CAMU_WLCD_MODE (1 << 11) +#define CAML_LCD_MODE (1 << 12) + +static struct spear_pmx_mode pmx_mode_nand = { + .name = "nand", + .mode = NAND_MODE, + .reg = MODE_CONFIG_REG, + .mask = 0x0000000F, + .val = 0x00, +}; + +static struct spear_pmx_mode pmx_mode_nor = { + .name = "nor", + .mode = NOR_MODE, + .reg = MODE_CONFIG_REG, + .mask = 0x0000000F, + .val = 0x01, +}; + +static struct spear_pmx_mode pmx_mode_photo_frame = { + .name = "photo frame mode", + .mode = PHOTO_FRAME_MODE, + .reg = MODE_CONFIG_REG, + .mask = 0x0000000F, + .val = 0x02, +}; + +static struct spear_pmx_mode pmx_mode_lend_ip_phone = { + .name = "lend ip phone mode", + .mode = LEND_IP_PHONE_MODE, + .reg = MODE_CONFIG_REG, + .mask = 0x0000000F, + .val = 0x03, +}; + +static struct spear_pmx_mode pmx_mode_hend_ip_phone = { + .name = "hend ip phone mode", + .mode = HEND_IP_PHONE_MODE, + .reg = MODE_CONFIG_REG, + .mask = 0x0000000F, + .val = 0x04, +}; + +static struct spear_pmx_mode pmx_mode_lend_wifi_phone = { + .name = "lend wifi phone mode", + .mode = LEND_WIFI_PHONE_MODE, + .reg = MODE_CONFIG_REG, + .mask = 0x0000000F, + .val = 0x05, +}; + +static struct spear_pmx_mode pmx_mode_hend_wifi_phone = { + .name = "hend wifi phone mode", + .mode = HEND_WIFI_PHONE_MODE, + .reg = MODE_CONFIG_REG, + .mask = 0x0000000F, + .val = 0x06, +}; + +static struct spear_pmx_mode pmx_mode_ata_pabx_wi2s = { + .name = "ata pabx wi2s mode", + .mode = ATA_PABX_WI2S_MODE, + .reg = MODE_CONFIG_REG, + .mask = 0x0000000F, + .val = 0x07, +}; + +static struct spear_pmx_mode pmx_mode_ata_pabx_i2s = { + .name = "ata pabx i2s mode", + .mode = ATA_PABX_I2S_MODE, + .reg = MODE_CONFIG_REG, + .mask = 0x0000000F, + .val = 0x08, +}; + +static struct spear_pmx_mode pmx_mode_caml_lcdw = { + .name = "caml lcdw mode", + .mode = CAML_LCDW_MODE, + .reg = MODE_CONFIG_REG, + .mask = 0x0000000F, + .val = 0x0C, +}; + +static struct spear_pmx_mode pmx_mode_camu_lcd = { + .name = "camu lcd mode", + .mode = CAMU_LCD_MODE, + .reg = MODE_CONFIG_REG, + .mask = 0x0000000F, + .val = 0x0D, +}; + +static struct spear_pmx_mode pmx_mode_camu_wlcd = { + .name = "camu wlcd mode", + .mode = CAMU_WLCD_MODE, + .reg = MODE_CONFIG_REG, + .mask = 0x0000000F, + .val = 0xE, +}; + +static struct spear_pmx_mode pmx_mode_caml_lcd = { + .name = "caml lcd mode", + .mode = CAML_LCD_MODE, + .reg = MODE_CONFIG_REG, + .mask = 0x0000000F, + .val = 0x0F, +}; + +static struct spear_pmx_mode *spear300_pmx_modes[] = { + &pmx_mode_nand, + &pmx_mode_nor, + &pmx_mode_photo_frame, + &pmx_mode_lend_ip_phone, + &pmx_mode_hend_ip_phone, + &pmx_mode_lend_wifi_phone, + &pmx_mode_hend_wifi_phone, + &pmx_mode_ata_pabx_wi2s, + &pmx_mode_ata_pabx_i2s, + &pmx_mode_caml_lcdw, + &pmx_mode_camu_lcd, + &pmx_mode_camu_wlcd, + &pmx_mode_caml_lcd, +}; + +/* fsmc_2chips_pins */ +static const unsigned fsmc_2chips_pins[] = { 1, 97 }; +static struct spear_muxreg fsmc_2chips_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_FIRDA_MASK, + .val = 0, + }, +}; + +static struct spear_modemux fsmc_2chips_modemux[] = { + { + .modes = NAND_MODE | NOR_MODE | PHOTO_FRAME_MODE | + ATA_PABX_WI2S_MODE | ATA_PABX_I2S_MODE, + .muxregs = fsmc_2chips_muxreg, + .nmuxregs = ARRAY_SIZE(fsmc_2chips_muxreg), + }, +}; + +static struct spear_pingroup fsmc_2chips_pingroup = { + .name = "fsmc_2chips_grp", + .pins = fsmc_2chips_pins, + .npins = ARRAY_SIZE(fsmc_2chips_pins), + .modemuxs = fsmc_2chips_modemux, + .nmodemuxs = ARRAY_SIZE(fsmc_2chips_modemux), +}; + +/* fsmc_4chips_pins */ +static const unsigned fsmc_4chips_pins[] = { 1, 2, 3, 97 }; +static struct spear_muxreg fsmc_4chips_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_FIRDA_MASK | PMX_UART0_MASK, + .val = 0, + }, +}; + +static struct spear_modemux fsmc_4chips_modemux[] = { + { + .modes = NAND_MODE | NOR_MODE | PHOTO_FRAME_MODE | + ATA_PABX_WI2S_MODE | ATA_PABX_I2S_MODE, + .muxregs = fsmc_4chips_muxreg, + .nmuxregs = ARRAY_SIZE(fsmc_4chips_muxreg), + }, +}; + +static struct spear_pingroup fsmc_4chips_pingroup = { + .name = "fsmc_4chips_grp", + .pins = fsmc_4chips_pins, + .npins = ARRAY_SIZE(fsmc_4chips_pins), + .modemuxs = fsmc_4chips_modemux, + .nmodemuxs = ARRAY_SIZE(fsmc_4chips_modemux), +}; + +static const char *const fsmc_grps[] = { "fsmc_2chips_grp", "fsmc_4chips_grp" +}; +static struct spear_function fsmc_function = { + .name = "fsmc", + .groups = fsmc_grps, + .ngroups = ARRAY_SIZE(fsmc_grps), +}; + +/* clcd_lcdmode_pins */ +static const unsigned clcd_lcdmode_pins[] = { 49, 50 }; +static struct spear_muxreg clcd_lcdmode_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK, + .val = 0, + }, +}; + +static struct spear_modemux clcd_lcdmode_modemux[] = { + { + .modes = HEND_IP_PHONE_MODE | HEND_WIFI_PHONE_MODE | + CAMU_LCD_MODE | CAML_LCD_MODE, + .muxregs = clcd_lcdmode_muxreg, + .nmuxregs = ARRAY_SIZE(clcd_lcdmode_muxreg), + }, +}; + +static struct spear_pingroup clcd_lcdmode_pingroup = { + .name = "clcd_lcdmode_grp", + .pins = clcd_lcdmode_pins, + .npins = ARRAY_SIZE(clcd_lcdmode_pins), + .modemuxs = clcd_lcdmode_modemux, + .nmodemuxs = ARRAY_SIZE(clcd_lcdmode_modemux), +}; + +/* clcd_pfmode_pins */ +static const unsigned clcd_pfmode_pins[] = { 47, 48, 49, 50 }; +static struct spear_muxreg clcd_pfmode_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_TIMER_2_3_MASK, + .val = 0, + }, +}; + +static struct spear_modemux clcd_pfmode_modemux[] = { + { + .modes = PHOTO_FRAME_MODE, + .muxregs = clcd_pfmode_muxreg, + .nmuxregs = ARRAY_SIZE(clcd_pfmode_muxreg), + }, +}; + +static struct spear_pingroup clcd_pfmode_pingroup = { + .name = "clcd_pfmode_grp", + .pins = clcd_pfmode_pins, + .npins = ARRAY_SIZE(clcd_pfmode_pins), + .modemuxs = clcd_pfmode_modemux, + .nmodemuxs = ARRAY_SIZE(clcd_pfmode_modemux), +}; + +static const char *const clcd_grps[] = { "clcd_lcdmode_grp", "clcd_pfmode_grp" +}; +static struct spear_function clcd_function = { + .name = "clcd", + .groups = clcd_grps, + .ngroups = ARRAY_SIZE(clcd_grps), +}; + +/* tdm_pins */ +static const unsigned tdm_pins[] = { 34, 35, 36, 37, 38 }; +static struct spear_muxreg tdm_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_UART0_MODEM_MASK | PMX_SSP_CS_MASK, + .val = 0, + }, +}; + +static struct spear_modemux tdm_modemux[] = { + { + .modes = PHOTO_FRAME_MODE | LEND_IP_PHONE_MODE | + HEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE + | HEND_WIFI_PHONE_MODE | ATA_PABX_WI2S_MODE + | ATA_PABX_I2S_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE + | CAMU_WLCD_MODE | CAML_LCD_MODE, + .muxregs = tdm_muxreg, + .nmuxregs = ARRAY_SIZE(tdm_muxreg), + }, +}; + +static struct spear_pingroup tdm_pingroup = { + .name = "tdm_grp", + .pins = tdm_pins, + .npins = ARRAY_SIZE(tdm_pins), + .modemuxs = tdm_modemux, + .nmodemuxs = ARRAY_SIZE(tdm_modemux), +}; + +static const char *const tdm_grps[] = { "tdm_grp" }; +static struct spear_function tdm_function = { + .name = "tdm", + .groups = tdm_grps, + .ngroups = ARRAY_SIZE(tdm_grps), +}; + +/* i2c_clk_pins */ +static const unsigned i2c_clk_pins[] = { 45, 46, 47, 48 }; +static struct spear_muxreg i2c_clk_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK, + .val = 0, + }, +}; + +static struct spear_modemux i2c_clk_modemux[] = { + { + .modes = LEND_IP_PHONE_MODE | HEND_IP_PHONE_MODE | + LEND_WIFI_PHONE_MODE | HEND_WIFI_PHONE_MODE | + ATA_PABX_WI2S_MODE | ATA_PABX_I2S_MODE | CAML_LCDW_MODE + | CAML_LCD_MODE, + .muxregs = i2c_clk_muxreg, + .nmuxregs = ARRAY_SIZE(i2c_clk_muxreg), + }, +}; + +static struct spear_pingroup i2c_clk_pingroup = { + .name = "i2c_clk_grp_grp", + .pins = i2c_clk_pins, + .npins = ARRAY_SIZE(i2c_clk_pins), + .modemuxs = i2c_clk_modemux, + .nmodemuxs = ARRAY_SIZE(i2c_clk_modemux), +}; + +static const char *const i2c_grps[] = { "i2c_clk_grp" }; +static struct spear_function i2c_function = { + .name = "i2c1", + .groups = i2c_grps, + .ngroups = ARRAY_SIZE(i2c_grps), +}; + +/* caml_pins */ +static const unsigned caml_pins[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; +static struct spear_muxreg caml_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_MII_MASK, + .val = 0, + }, +}; + +static struct spear_modemux caml_modemux[] = { + { + .modes = CAML_LCDW_MODE | CAML_LCD_MODE, + .muxregs = caml_muxreg, + .nmuxregs = ARRAY_SIZE(caml_muxreg), + }, +}; + +static struct spear_pingroup caml_pingroup = { + .name = "caml_grp", + .pins = caml_pins, + .npins = ARRAY_SIZE(caml_pins), + .modemuxs = caml_modemux, + .nmodemuxs = ARRAY_SIZE(caml_modemux), +}; + +/* camu_pins */ +static const unsigned camu_pins[] = { 16, 17, 18, 19, 20, 21, 45, 46, 47, 48 }; +static struct spear_muxreg camu_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK | PMX_MII_MASK, + .val = 0, + }, +}; + +static struct spear_modemux camu_modemux[] = { + { + .modes = CAMU_LCD_MODE | CAMU_WLCD_MODE, + .muxregs = camu_muxreg, + .nmuxregs = ARRAY_SIZE(camu_muxreg), + }, +}; + +static struct spear_pingroup camu_pingroup = { + .name = "camu_grp", + .pins = camu_pins, + .npins = ARRAY_SIZE(camu_pins), + .modemuxs = camu_modemux, + .nmodemuxs = ARRAY_SIZE(camu_modemux), +}; + +static const char *const cam_grps[] = { "caml_grp", "camu_grp" }; +static struct spear_function cam_function = { + .name = "cam", + .groups = cam_grps, + .ngroups = ARRAY_SIZE(cam_grps), +}; + +/* dac_pins */ +static const unsigned dac_pins[] = { 43, 44 }; +static struct spear_muxreg dac_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_TIMER_0_1_MASK, + .val = 0, + }, +}; + +static struct spear_modemux dac_modemux[] = { + { + .modes = ATA_PABX_I2S_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE + | CAMU_WLCD_MODE | CAML_LCD_MODE, + .muxregs = dac_muxreg, + .nmuxregs = ARRAY_SIZE(dac_muxreg), + }, +}; + +static struct spear_pingroup dac_pingroup = { + .name = "dac_grp", + .pins = dac_pins, + .npins = ARRAY_SIZE(dac_pins), + .modemuxs = dac_modemux, + .nmodemuxs = ARRAY_SIZE(dac_modemux), +}; + +static const char *const dac_grps[] = { "dac_grp" }; +static struct spear_function dac_function = { + .name = "dac", + .groups = dac_grps, + .ngroups = ARRAY_SIZE(dac_grps), +}; + +/* i2s_pins */ +static const unsigned i2s_pins[] = { 39, 40, 41, 42 }; +static struct spear_muxreg i2s_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_UART0_MODEM_MASK, + .val = 0, + }, +}; + +static struct spear_modemux i2s_modemux[] = { + { + .modes = LEND_IP_PHONE_MODE | HEND_IP_PHONE_MODE + | LEND_WIFI_PHONE_MODE | HEND_WIFI_PHONE_MODE | + ATA_PABX_I2S_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE + | CAMU_WLCD_MODE | CAML_LCD_MODE, + .muxregs = i2s_muxreg, + .nmuxregs = ARRAY_SIZE(i2s_muxreg), + }, +}; + +static struct spear_pingroup i2s_pingroup = { + .name = "i2s_grp", + .pins = i2s_pins, + .npins = ARRAY_SIZE(i2s_pins), + .modemuxs = i2s_modemux, + .nmodemuxs = ARRAY_SIZE(i2s_modemux), +}; + +static const char *const i2s_grps[] = { "i2s_grp" }; +static struct spear_function i2s_function = { + .name = "i2s", + .groups = i2s_grps, + .ngroups = ARRAY_SIZE(i2s_grps), +}; + +/* sdhci_4bit_pins */ +static const unsigned sdhci_4bit_pins[] = { 28, 29, 30, 31, 32, 33 }; +static struct spear_muxreg sdhci_4bit_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_GPIO_PIN0_MASK | PMX_GPIO_PIN1_MASK | + PMX_GPIO_PIN2_MASK | PMX_GPIO_PIN3_MASK | + PMX_GPIO_PIN4_MASK | PMX_GPIO_PIN5_MASK, + .val = 0, + }, +}; + +static struct spear_modemux sdhci_4bit_modemux[] = { + { + .modes = PHOTO_FRAME_MODE | LEND_IP_PHONE_MODE | + HEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE | + HEND_WIFI_PHONE_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE | + CAMU_WLCD_MODE | CAML_LCD_MODE | ATA_PABX_WI2S_MODE, + .muxregs = sdhci_4bit_muxreg, + .nmuxregs = ARRAY_SIZE(sdhci_4bit_muxreg), + }, +}; + +static struct spear_pingroup sdhci_4bit_pingroup = { + .name = "sdhci_4bit_grp", + .pins = sdhci_4bit_pins, + .npins = ARRAY_SIZE(sdhci_4bit_pins), + .modemuxs = sdhci_4bit_modemux, + .nmodemuxs = ARRAY_SIZE(sdhci_4bit_modemux), +}; + +/* sdhci_8bit_pins */ +static const unsigned sdhci_8bit_pins[] = { 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33 }; +static struct spear_muxreg sdhci_8bit_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_GPIO_PIN0_MASK | PMX_GPIO_PIN1_MASK | + PMX_GPIO_PIN2_MASK | PMX_GPIO_PIN3_MASK | + PMX_GPIO_PIN4_MASK | PMX_GPIO_PIN5_MASK | PMX_MII_MASK, + .val = 0, + }, +}; + +static struct spear_modemux sdhci_8bit_modemux[] = { + { + .modes = PHOTO_FRAME_MODE | LEND_IP_PHONE_MODE | + HEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE | + HEND_WIFI_PHONE_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE | + CAMU_WLCD_MODE | CAML_LCD_MODE, + .muxregs = sdhci_8bit_muxreg, + .nmuxregs = ARRAY_SIZE(sdhci_8bit_muxreg), + }, +}; + +static struct spear_pingroup sdhci_8bit_pingroup = { + .name = "sdhci_8bit_grp", + .pins = sdhci_8bit_pins, + .npins = ARRAY_SIZE(sdhci_8bit_pins), + .modemuxs = sdhci_8bit_modemux, + .nmodemuxs = ARRAY_SIZE(sdhci_8bit_modemux), +}; + +static const char *const sdhci_grps[] = { "sdhci_4bit_grp", "sdhci_8bit_grp" }; +static struct spear_function sdhci_function = { + .name = "sdhci", + .groups = sdhci_grps, + .ngroups = ARRAY_SIZE(sdhci_grps), +}; + +/* gpio1_0_to_3_pins */ +static const unsigned gpio1_0_to_3_pins[] = { 39, 40, 41, 42 }; +static struct spear_muxreg gpio1_0_to_3_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_UART0_MODEM_MASK, + .val = 0, + }, +}; + +static struct spear_modemux gpio1_0_to_3_modemux[] = { + { + .modes = PHOTO_FRAME_MODE, + .muxregs = gpio1_0_to_3_muxreg, + .nmuxregs = ARRAY_SIZE(gpio1_0_to_3_muxreg), + }, +}; + +static struct spear_pingroup gpio1_0_to_3_pingroup = { + .name = "gpio1_0_to_3_grp", + .pins = gpio1_0_to_3_pins, + .npins = ARRAY_SIZE(gpio1_0_to_3_pins), + .modemuxs = gpio1_0_to_3_modemux, + .nmodemuxs = ARRAY_SIZE(gpio1_0_to_3_modemux), +}; + +/* gpio1_4_to_7_pins */ +static const unsigned gpio1_4_to_7_pins[] = { 43, 44, 45, 46 }; + +static struct spear_muxreg gpio1_4_to_7_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK, + .val = 0, + }, +}; + +static struct spear_modemux gpio1_4_to_7_modemux[] = { + { + .modes = PHOTO_FRAME_MODE, + .muxregs = gpio1_4_to_7_muxreg, + .nmuxregs = ARRAY_SIZE(gpio1_4_to_7_muxreg), + }, +}; + +static struct spear_pingroup gpio1_4_to_7_pingroup = { + .name = "gpio1_4_to_7_grp", + .pins = gpio1_4_to_7_pins, + .npins = ARRAY_SIZE(gpio1_4_to_7_pins), + .modemuxs = gpio1_4_to_7_modemux, + .nmodemuxs = ARRAY_SIZE(gpio1_4_to_7_modemux), +}; + +static const char *const gpio1_grps[] = { "gpio1_0_to_3_grp", "gpio1_4_to_7_grp" +}; +static struct spear_function gpio1_function = { + .name = "gpio1", + .groups = gpio1_grps, + .ngroups = ARRAY_SIZE(gpio1_grps), +}; + +/* pingroups */ +static struct spear_pingroup *spear300_pingroups[] = { + SPEAR3XX_COMMON_PINGROUPS, + &fsmc_2chips_pingroup, + &fsmc_4chips_pingroup, + &clcd_lcdmode_pingroup, + &clcd_pfmode_pingroup, + &tdm_pingroup, + &i2c_clk_pingroup, + &caml_pingroup, + &camu_pingroup, + &dac_pingroup, + &i2s_pingroup, + &sdhci_4bit_pingroup, + &sdhci_8bit_pingroup, + &gpio1_0_to_3_pingroup, + &gpio1_4_to_7_pingroup, +}; + +/* functions */ +static struct spear_function *spear300_functions[] = { + SPEAR3XX_COMMON_FUNCTIONS, + &fsmc_function, + &clcd_function, + &tdm_function, + &i2c_function, + &cam_function, + &dac_function, + &i2s_function, + &sdhci_function, + &gpio1_function, +}; + +static struct of_device_id spear300_pinctrl_of_match[] __devinitdata = { + { + .compatible = "st,spear300-pinmux", + }, + {}, +}; + +static int __devinit spear300_pinctrl_probe(struct platform_device *pdev) +{ + int ret; + + spear3xx_machdata.groups = spear300_pingroups; + spear3xx_machdata.ngroups = ARRAY_SIZE(spear300_pingroups); + spear3xx_machdata.functions = spear300_functions; + spear3xx_machdata.nfunctions = ARRAY_SIZE(spear300_functions); + + spear3xx_machdata.modes_supported = true; + spear3xx_machdata.pmx_modes = spear300_pmx_modes; + spear3xx_machdata.npmx_modes = ARRAY_SIZE(spear300_pmx_modes); + + pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG); + + ret = spear_pinctrl_probe(pdev, &spear3xx_machdata); + if (ret) + return ret; + + return 0; +} + +static int __devexit spear300_pinctrl_remove(struct platform_device *pdev) +{ + return spear_pinctrl_remove(pdev); +} + +static struct platform_driver spear300_pinctrl_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = spear300_pinctrl_of_match, + }, + .probe = spear300_pinctrl_probe, + .remove = __devexit_p(spear300_pinctrl_remove), +}; + +static int __init spear300_pinctrl_init(void) +{ + return platform_driver_register(&spear300_pinctrl_driver); +} +arch_initcall(spear300_pinctrl_init); + +static void __exit spear300_pinctrl_exit(void) +{ + platform_driver_unregister(&spear300_pinctrl_driver); +} +module_exit(spear300_pinctrl_exit); + +MODULE_AUTHOR("Viresh Kumar "); +MODULE_DESCRIPTION("ST Microelectronics SPEAr300 pinctrl driver"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, spear300_pinctrl_of_match); diff --git a/trunk/drivers/pinctrl/spear/pinctrl-spear310.c b/trunk/drivers/pinctrl/spear/pinctrl-spear310.c new file mode 100644 index 000000000000..1a9707605125 --- /dev/null +++ b/trunk/drivers/pinctrl/spear/pinctrl-spear310.c @@ -0,0 +1,431 @@ +/* + * Driver for the ST Microelectronics SPEAr310 pinmux + * + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar + * + * 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 "pinctrl-spear3xx.h" + +#define DRIVER_NAME "spear310-pinmux" + +/* addresses */ +#define PMX_CONFIG_REG 0x08 + +/* emi_cs_0_to_5_pins */ +static const unsigned emi_cs_0_to_5_pins[] = { 45, 46, 47, 48, 49, 50 }; +static struct spear_muxreg emi_cs_0_to_5_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK, + .val = 0, + }, +}; + +static struct spear_modemux emi_cs_0_to_5_modemux[] = { + { + .muxregs = emi_cs_0_to_5_muxreg, + .nmuxregs = ARRAY_SIZE(emi_cs_0_to_5_muxreg), + }, +}; + +static struct spear_pingroup emi_cs_0_to_5_pingroup = { + .name = "emi_cs_0_to_5_grp", + .pins = emi_cs_0_to_5_pins, + .npins = ARRAY_SIZE(emi_cs_0_to_5_pins), + .modemuxs = emi_cs_0_to_5_modemux, + .nmodemuxs = ARRAY_SIZE(emi_cs_0_to_5_modemux), +}; + +static const char *const emi_cs_0_to_5_grps[] = { "emi_cs_0_to_5_grp" }; +static struct spear_function emi_cs_0_to_5_function = { + .name = "emi", + .groups = emi_cs_0_to_5_grps, + .ngroups = ARRAY_SIZE(emi_cs_0_to_5_grps), +}; + +/* uart1_pins */ +static const unsigned uart1_pins[] = { 0, 1 }; +static struct spear_muxreg uart1_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_FIRDA_MASK, + .val = 0, + }, +}; + +static struct spear_modemux uart1_modemux[] = { + { + .muxregs = uart1_muxreg, + .nmuxregs = ARRAY_SIZE(uart1_muxreg), + }, +}; + +static struct spear_pingroup uart1_pingroup = { + .name = "uart1_grp", + .pins = uart1_pins, + .npins = ARRAY_SIZE(uart1_pins), + .modemuxs = uart1_modemux, + .nmodemuxs = ARRAY_SIZE(uart1_modemux), +}; + +static const char *const uart1_grps[] = { "uart1_grp" }; +static struct spear_function uart1_function = { + .name = "uart1", + .groups = uart1_grps, + .ngroups = ARRAY_SIZE(uart1_grps), +}; + +/* uart2_pins */ +static const unsigned uart2_pins[] = { 43, 44 }; +static struct spear_muxreg uart2_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_TIMER_0_1_MASK, + .val = 0, + }, +}; + +static struct spear_modemux uart2_modemux[] = { + { + .muxregs = uart2_muxreg, + .nmuxregs = ARRAY_SIZE(uart2_muxreg), + }, +}; + +static struct spear_pingroup uart2_pingroup = { + .name = "uart2_grp", + .pins = uart2_pins, + .npins = ARRAY_SIZE(uart2_pins), + .modemuxs = uart2_modemux, + .nmodemuxs = ARRAY_SIZE(uart2_modemux), +}; + +static const char *const uart2_grps[] = { "uart2_grp" }; +static struct spear_function uart2_function = { + .name = "uart2", + .groups = uart2_grps, + .ngroups = ARRAY_SIZE(uart2_grps), +}; + +/* uart3_pins */ +static const unsigned uart3_pins[] = { 37, 38 }; +static struct spear_muxreg uart3_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_UART0_MODEM_MASK, + .val = 0, + }, +}; + +static struct spear_modemux uart3_modemux[] = { + { + .muxregs = uart3_muxreg, + .nmuxregs = ARRAY_SIZE(uart3_muxreg), + }, +}; + +static struct spear_pingroup uart3_pingroup = { + .name = "uart3_grp", + .pins = uart3_pins, + .npins = ARRAY_SIZE(uart3_pins), + .modemuxs = uart3_modemux, + .nmodemuxs = ARRAY_SIZE(uart3_modemux), +}; + +static const char *const uart3_grps[] = { "uart3_grp" }; +static struct spear_function uart3_function = { + .name = "uart3", + .groups = uart3_grps, + .ngroups = ARRAY_SIZE(uart3_grps), +}; + +/* uart4_pins */ +static const unsigned uart4_pins[] = { 39, 40 }; +static struct spear_muxreg uart4_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_UART0_MODEM_MASK, + .val = 0, + }, +}; + +static struct spear_modemux uart4_modemux[] = { + { + .muxregs = uart4_muxreg, + .nmuxregs = ARRAY_SIZE(uart4_muxreg), + }, +}; + +static struct spear_pingroup uart4_pingroup = { + .name = "uart4_grp", + .pins = uart4_pins, + .npins = ARRAY_SIZE(uart4_pins), + .modemuxs = uart4_modemux, + .nmodemuxs = ARRAY_SIZE(uart4_modemux), +}; + +static const char *const uart4_grps[] = { "uart4_grp" }; +static struct spear_function uart4_function = { + .name = "uart4", + .groups = uart4_grps, + .ngroups = ARRAY_SIZE(uart4_grps), +}; + +/* uart5_pins */ +static const unsigned uart5_pins[] = { 41, 42 }; +static struct spear_muxreg uart5_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_UART0_MODEM_MASK, + .val = 0, + }, +}; + +static struct spear_modemux uart5_modemux[] = { + { + .muxregs = uart5_muxreg, + .nmuxregs = ARRAY_SIZE(uart5_muxreg), + }, +}; + +static struct spear_pingroup uart5_pingroup = { + .name = "uart5_grp", + .pins = uart5_pins, + .npins = ARRAY_SIZE(uart5_pins), + .modemuxs = uart5_modemux, + .nmodemuxs = ARRAY_SIZE(uart5_modemux), +}; + +static const char *const uart5_grps[] = { "uart5_grp" }; +static struct spear_function uart5_function = { + .name = "uart5", + .groups = uart5_grps, + .ngroups = ARRAY_SIZE(uart5_grps), +}; + +/* fsmc_pins */ +static const unsigned fsmc_pins[] = { 34, 35, 36 }; +static struct spear_muxreg fsmc_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_SSP_CS_MASK, + .val = 0, + }, +}; + +static struct spear_modemux fsmc_modemux[] = { + { + .muxregs = fsmc_muxreg, + .nmuxregs = ARRAY_SIZE(fsmc_muxreg), + }, +}; + +static struct spear_pingroup fsmc_pingroup = { + .name = "fsmc_grp", + .pins = fsmc_pins, + .npins = ARRAY_SIZE(fsmc_pins), + .modemuxs = fsmc_modemux, + .nmodemuxs = ARRAY_SIZE(fsmc_modemux), +}; + +static const char *const fsmc_grps[] = { "fsmc_grp" }; +static struct spear_function fsmc_function = { + .name = "fsmc", + .groups = fsmc_grps, + .ngroups = ARRAY_SIZE(fsmc_grps), +}; + +/* rs485_0_pins */ +static const unsigned rs485_0_pins[] = { 19, 20, 21, 22, 23 }; +static struct spear_muxreg rs485_0_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_MII_MASK, + .val = 0, + }, +}; + +static struct spear_modemux rs485_0_modemux[] = { + { + .muxregs = rs485_0_muxreg, + .nmuxregs = ARRAY_SIZE(rs485_0_muxreg), + }, +}; + +static struct spear_pingroup rs485_0_pingroup = { + .name = "rs485_0_grp", + .pins = rs485_0_pins, + .npins = ARRAY_SIZE(rs485_0_pins), + .modemuxs = rs485_0_modemux, + .nmodemuxs = ARRAY_SIZE(rs485_0_modemux), +}; + +static const char *const rs485_0_grps[] = { "rs485_0" }; +static struct spear_function rs485_0_function = { + .name = "rs485_0", + .groups = rs485_0_grps, + .ngroups = ARRAY_SIZE(rs485_0_grps), +}; + +/* rs485_1_pins */ +static const unsigned rs485_1_pins[] = { 14, 15, 16, 17, 18 }; +static struct spear_muxreg rs485_1_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_MII_MASK, + .val = 0, + }, +}; + +static struct spear_modemux rs485_1_modemux[] = { + { + .muxregs = rs485_1_muxreg, + .nmuxregs = ARRAY_SIZE(rs485_1_muxreg), + }, +}; + +static struct spear_pingroup rs485_1_pingroup = { + .name = "rs485_1_grp", + .pins = rs485_1_pins, + .npins = ARRAY_SIZE(rs485_1_pins), + .modemuxs = rs485_1_modemux, + .nmodemuxs = ARRAY_SIZE(rs485_1_modemux), +}; + +static const char *const rs485_1_grps[] = { "rs485_1" }; +static struct spear_function rs485_1_function = { + .name = "rs485_1", + .groups = rs485_1_grps, + .ngroups = ARRAY_SIZE(rs485_1_grps), +}; + +/* tdm_pins */ +static const unsigned tdm_pins[] = { 10, 11, 12, 13 }; +static struct spear_muxreg tdm_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_MII_MASK, + .val = 0, + }, +}; + +static struct spear_modemux tdm_modemux[] = { + { + .muxregs = tdm_muxreg, + .nmuxregs = ARRAY_SIZE(tdm_muxreg), + }, +}; + +static struct spear_pingroup tdm_pingroup = { + .name = "tdm_grp", + .pins = tdm_pins, + .npins = ARRAY_SIZE(tdm_pins), + .modemuxs = tdm_modemux, + .nmodemuxs = ARRAY_SIZE(tdm_modemux), +}; + +static const char *const tdm_grps[] = { "tdm_grp" }; +static struct spear_function tdm_function = { + .name = "tdm", + .groups = tdm_grps, + .ngroups = ARRAY_SIZE(tdm_grps), +}; + +/* pingroups */ +static struct spear_pingroup *spear310_pingroups[] = { + SPEAR3XX_COMMON_PINGROUPS, + &emi_cs_0_to_5_pingroup, + &uart1_pingroup, + &uart2_pingroup, + &uart3_pingroup, + &uart4_pingroup, + &uart5_pingroup, + &fsmc_pingroup, + &rs485_0_pingroup, + &rs485_1_pingroup, + &tdm_pingroup, +}; + +/* functions */ +static struct spear_function *spear310_functions[] = { + SPEAR3XX_COMMON_FUNCTIONS, + &emi_cs_0_to_5_function, + &uart1_function, + &uart2_function, + &uart3_function, + &uart4_function, + &uart5_function, + &fsmc_function, + &rs485_0_function, + &rs485_1_function, + &tdm_function, +}; + +static struct of_device_id spear310_pinctrl_of_match[] __devinitdata = { + { + .compatible = "st,spear310-pinmux", + }, + {}, +}; + +static int __devinit spear310_pinctrl_probe(struct platform_device *pdev) +{ + int ret; + + spear3xx_machdata.groups = spear310_pingroups; + spear3xx_machdata.ngroups = ARRAY_SIZE(spear310_pingroups); + spear3xx_machdata.functions = spear310_functions; + spear3xx_machdata.nfunctions = ARRAY_SIZE(spear310_functions); + + pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG); + + spear3xx_machdata.modes_supported = false; + + ret = spear_pinctrl_probe(pdev, &spear3xx_machdata); + if (ret) + return ret; + + return 0; +} + +static int __devexit spear310_pinctrl_remove(struct platform_device *pdev) +{ + return spear_pinctrl_remove(pdev); +} + +static struct platform_driver spear310_pinctrl_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = spear310_pinctrl_of_match, + }, + .probe = spear310_pinctrl_probe, + .remove = __devexit_p(spear310_pinctrl_remove), +}; + +static int __init spear310_pinctrl_init(void) +{ + return platform_driver_register(&spear310_pinctrl_driver); +} +arch_initcall(spear310_pinctrl_init); + +static void __exit spear310_pinctrl_exit(void) +{ + platform_driver_unregister(&spear310_pinctrl_driver); +} +module_exit(spear310_pinctrl_exit); + +MODULE_AUTHOR("Viresh Kumar "); +MODULE_DESCRIPTION("ST Microelectronics SPEAr310 pinctrl driver"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, SPEAr310_pinctrl_of_match); diff --git a/trunk/drivers/pinctrl/spear/pinctrl-spear320.c b/trunk/drivers/pinctrl/spear/pinctrl-spear320.c new file mode 100644 index 000000000000..de726e6c283a --- /dev/null +++ b/trunk/drivers/pinctrl/spear/pinctrl-spear320.c @@ -0,0 +1,3468 @@ +/* + * Driver for the ST Microelectronics SPEAr320 pinmux + * + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar + * + * 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 "pinctrl-spear3xx.h" + +#define DRIVER_NAME "spear320-pinmux" + +/* addresses */ +#define PMX_CONFIG_REG 0x0C +#define MODE_CONFIG_REG 0x10 +#define MODE_EXT_CONFIG_REG 0x18 + +/* modes */ +#define AUTO_NET_SMII_MODE (1 << 0) +#define AUTO_NET_MII_MODE (1 << 1) +#define AUTO_EXP_MODE (1 << 2) +#define SMALL_PRINTERS_MODE (1 << 3) +#define EXTENDED_MODE (1 << 4) + +static struct spear_pmx_mode pmx_mode_auto_net_smii = { + .name = "Automation Networking SMII mode", + .mode = AUTO_NET_SMII_MODE, + .reg = MODE_CONFIG_REG, + .mask = 0x00000007, + .val = 0x0, +}; + +static struct spear_pmx_mode pmx_mode_auto_net_mii = { + .name = "Automation Networking MII mode", + .mode = AUTO_NET_MII_MODE, + .reg = MODE_CONFIG_REG, + .mask = 0x00000007, + .val = 0x1, +}; + +static struct spear_pmx_mode pmx_mode_auto_exp = { + .name = "Automation Expanded mode", + .mode = AUTO_EXP_MODE, + .reg = MODE_CONFIG_REG, + .mask = 0x00000007, + .val = 0x2, +}; + +static struct spear_pmx_mode pmx_mode_small_printers = { + .name = "Small Printers mode", + .mode = SMALL_PRINTERS_MODE, + .reg = MODE_CONFIG_REG, + .mask = 0x00000007, + .val = 0x3, +}; + +static struct spear_pmx_mode pmx_mode_extended = { + .name = "extended mode", + .mode = EXTENDED_MODE, + .reg = MODE_EXT_CONFIG_REG, + .mask = 0x00000001, + .val = 0x1, +}; + +static struct spear_pmx_mode *spear320_pmx_modes[] = { + &pmx_mode_auto_net_smii, + &pmx_mode_auto_net_mii, + &pmx_mode_auto_exp, + &pmx_mode_small_printers, + &pmx_mode_extended, +}; + +/* Extended mode registers and their offsets */ +#define EXT_CTRL_REG 0x0018 + #define MII_MDIO_MASK (1 << 4) + #define MII_MDIO_10_11_VAL 0 + #define MII_MDIO_81_VAL (1 << 4) + #define EMI_FSMC_DYNAMIC_MUX_MASK (1 << 5) + #define MAC_MODE_MII 0 + #define MAC_MODE_RMII 1 + #define MAC_MODE_SMII 2 + #define MAC_MODE_SS_SMII 3 + #define MAC_MODE_MASK 0x3 + #define MAC1_MODE_SHIFT 16 + #define MAC2_MODE_SHIFT 18 + +#define IP_SEL_PAD_0_9_REG 0x00A4 + #define PMX_PL_0_1_MASK (0x3F << 0) + #define PMX_UART2_PL_0_1_VAL 0x0 + #define PMX_I2C2_PL_0_1_VAL (0x4 | (0x4 << 3)) + + #define PMX_PL_2_3_MASK (0x3F << 6) + #define PMX_I2C2_PL_2_3_VAL 0x0 + #define PMX_UART6_PL_2_3_VAL ((0x1 << 6) | (0x1 << 9)) + #define PMX_UART1_ENH_PL_2_3_VAL ((0x4 << 6) | (0x4 << 9)) + + #define PMX_PL_4_5_MASK (0x3F << 12) + #define PMX_UART5_PL_4_5_VAL ((0x1 << 12) | (0x1 << 15)) + #define PMX_UART1_ENH_PL_4_5_VAL ((0x4 << 12) | (0x4 << 15)) + #define PMX_PL_5_MASK (0x7 << 15) + #define PMX_TOUCH_Y_PL_5_VAL 0x0 + + #define PMX_PL_6_7_MASK (0x3F << 18) + #define PMX_PL_6_MASK (0x7 << 18) + #define PMX_PL_7_MASK (0x7 << 21) + #define PMX_UART4_PL_6_7_VAL ((0x1 << 18) | (0x1 << 21)) + #define PMX_PWM_3_PL_6_VAL (0x2 << 18) + #define PMX_PWM_2_PL_7_VAL (0x2 << 21) + #define PMX_UART1_ENH_PL_6_7_VAL ((0x4 << 18) | (0x4 << 21)) + + #define PMX_PL_8_9_MASK (0x3F << 24) + #define PMX_UART3_PL_8_9_VAL ((0x1 << 24) | (0x1 << 27)) + #define PMX_PWM_0_1_PL_8_9_VAL ((0x2 << 24) | (0x2 << 27)) + #define PMX_I2C1_PL_8_9_VAL ((0x4 << 24) | (0x4 << 27)) + +#define IP_SEL_PAD_10_19_REG 0x00A8 + #define PMX_PL_10_11_MASK (0x3F << 0) + #define PMX_SMII_PL_10_11_VAL 0 + #define PMX_RMII_PL_10_11_VAL ((0x4 << 0) | (0x4 << 3)) + + #define PMX_PL_12_MASK (0x7 << 6) + #define PMX_PWM3_PL_12_VAL 0 + #define PMX_SDHCI_CD_PL_12_VAL (0x4 << 6) + + #define PMX_PL_13_14_MASK (0x3F << 9) + #define PMX_PL_13_MASK (0x7 << 9) + #define PMX_PL_14_MASK (0x7 << 12) + #define PMX_SSP2_PL_13_14_15_16_VAL 0 + #define PMX_UART4_PL_13_14_VAL ((0x1 << 9) | (0x1 << 12)) + #define PMX_RMII_PL_13_14_VAL ((0x4 << 9) | (0x4 << 12)) + #define PMX_PWM2_PL_13_VAL (0x2 << 9) + #define PMX_PWM1_PL_14_VAL (0x2 << 12) + + #define PMX_PL_15_MASK (0x7 << 15) + #define PMX_PWM0_PL_15_VAL (0x2 << 15) + #define PMX_PL_15_16_MASK (0x3F << 15) + #define PMX_UART3_PL_15_16_VAL ((0x1 << 15) | (0x1 << 18)) + #define PMX_RMII_PL_15_16_VAL ((0x4 << 15) | (0x4 << 18)) + + #define PMX_PL_17_18_MASK (0x3F << 21) + #define PMX_SSP1_PL_17_18_19_20_VAL 0 + #define PMX_RMII_PL_17_18_VAL ((0x4 << 21) | (0x4 << 24)) + + #define PMX_PL_19_MASK (0x7 << 27) + #define PMX_I2C2_PL_19_VAL (0x1 << 27) + #define PMX_RMII_PL_19_VAL (0x4 << 27) + +#define IP_SEL_PAD_20_29_REG 0x00AC + #define PMX_PL_20_MASK (0x7 << 0) + #define PMX_I2C2_PL_20_VAL (0x1 << 0) + #define PMX_RMII_PL_20_VAL (0x4 << 0) + + #define PMX_PL_21_TO_27_MASK (0x1FFFFF << 3) + #define PMX_SMII_PL_21_TO_27_VAL 0 + #define PMX_RMII_PL_21_TO_27_VAL ((0x4 << 3) | (0x4 << 6) | (0x4 << 9) | (0x4 << 12) | (0x4 << 15) | (0x4 << 18) | (0x4 << 21)) + + #define PMX_PL_28_29_MASK (0x3F << 24) + #define PMX_PL_28_MASK (0x7 << 24) + #define PMX_PL_29_MASK (0x7 << 27) + #define PMX_UART1_PL_28_29_VAL 0 + #define PMX_PWM_3_PL_28_VAL (0x4 << 24) + #define PMX_PWM_2_PL_29_VAL (0x4 << 27) + +#define IP_SEL_PAD_30_39_REG 0x00B0 + #define PMX_PL_30_31_MASK (0x3F << 0) + #define PMX_CAN1_PL_30_31_VAL (0) + #define PMX_PL_30_MASK (0x7 << 0) + #define PMX_PL_31_MASK (0x7 << 3) + #define PMX_PWM1_EXT_PL_30_VAL (0x4 << 0) + #define PMX_PWM0_EXT_PL_31_VAL (0x4 << 3) + #define PMX_UART1_ENH_PL_31_VAL (0x3 << 3) + + #define PMX_PL_32_33_MASK (0x3F << 6) + #define PMX_CAN0_PL_32_33_VAL 0 + #define PMX_UART1_ENH_PL_32_33_VAL ((0x3 << 6) | (0x3 << 9)) + #define PMX_SSP2_PL_32_33_VAL ((0x4 << 6) | (0x4 << 9)) + + #define PMX_PL_34_MASK (0x7 << 12) + #define PMX_PWM2_PL_34_VAL 0 + #define PMX_UART1_ENH_PL_34_VAL (0x2 << 12) + #define PMX_SSP2_PL_34_VAL (0x4 << 12) + + #define PMX_PL_35_MASK (0x7 << 15) + #define PMX_I2S_REF_CLK_PL_35_VAL 0 + #define PMX_UART1_ENH_PL_35_VAL (0x2 << 15) + #define PMX_SSP2_PL_35_VAL (0x4 << 15) + + #define PMX_PL_36_MASK (0x7 << 18) + #define PMX_TOUCH_X_PL_36_VAL 0 + #define PMX_UART1_ENH_PL_36_VAL (0x2 << 18) + #define PMX_SSP1_PL_36_VAL (0x4 << 18) + + #define PMX_PL_37_38_MASK (0x3F << 21) + #define PMX_PWM0_1_PL_37_38_VAL 0 + #define PMX_UART5_PL_37_38_VAL ((0x2 << 21) | (0x2 << 24)) + #define PMX_SSP1_PL_37_38_VAL ((0x4 << 21) | (0x4 << 24)) + + #define PMX_PL_39_MASK (0x7 << 27) + #define PMX_I2S_PL_39_VAL 0 + #define PMX_UART4_PL_39_VAL (0x2 << 27) + #define PMX_SSP1_PL_39_VAL (0x4 << 27) + +#define IP_SEL_PAD_40_49_REG 0x00B4 + #define PMX_PL_40_MASK (0x7 << 0) + #define PMX_I2S_PL_40_VAL 0 + #define PMX_UART4_PL_40_VAL (0x2 << 0) + #define PMX_PWM3_PL_40_VAL (0x4 << 0) + + #define PMX_PL_41_42_MASK (0x3F << 3) + #define PMX_PL_41_MASK (0x7 << 3) + #define PMX_PL_42_MASK (0x7 << 6) + #define PMX_I2S_PL_41_42_VAL 0 + #define PMX_UART3_PL_41_42_VAL ((0x2 << 3) | (0x2 << 6)) + #define PMX_PWM2_PL_41_VAL (0x4 << 3) + #define PMX_PWM1_PL_42_VAL (0x4 << 6) + + #define PMX_PL_43_MASK (0x7 << 9) + #define PMX_SDHCI_PL_43_VAL 0 + #define PMX_UART1_ENH_PL_43_VAL (0x2 << 9) + #define PMX_PWM0_PL_43_VAL (0x4 << 9) + + #define PMX_PL_44_45_MASK (0x3F << 12) + #define PMX_SDHCI_PL_44_45_VAL 0 + #define PMX_UART1_ENH_PL_44_45_VAL ((0x2 << 12) | (0x2 << 15)) + #define PMX_SSP2_PL_44_45_VAL ((0x4 << 12) | (0x4 << 15)) + + #define PMX_PL_46_47_MASK (0x3F << 18) + #define PMX_SDHCI_PL_46_47_VAL 0 + #define PMX_FSMC_EMI_PL_46_47_VAL ((0x2 << 18) | (0x2 << 21)) + #define PMX_SSP2_PL_46_47_VAL ((0x4 << 18) | (0x4 << 21)) + + #define PMX_PL_48_49_MASK (0x3F << 24) + #define PMX_SDHCI_PL_48_49_VAL 0 + #define PMX_FSMC_EMI_PL_48_49_VAL ((0x2 << 24) | (0x2 << 27)) + #define PMX_SSP1_PL_48_49_VAL ((0x4 << 24) | (0x4 << 27)) + +#define IP_SEL_PAD_50_59_REG 0x00B8 + #define PMX_PL_50_51_MASK (0x3F << 0) + #define PMX_EMI_PL_50_51_VAL ((0x2 << 0) | (0x2 << 3)) + #define PMX_SSP1_PL_50_51_VAL ((0x4 << 0) | (0x4 << 3)) + #define PMX_PL_50_MASK (0x7 << 0) + #define PMX_PL_51_MASK (0x7 << 3) + #define PMX_SDHCI_PL_50_VAL 0 + #define PMX_SDHCI_CD_PL_51_VAL 0 + + #define PMX_PL_52_53_MASK (0x3F << 6) + #define PMX_FSMC_PL_52_53_VAL 0 + #define PMX_EMI_PL_52_53_VAL ((0x2 << 6) | (0x2 << 9)) + #define PMX_UART3_PL_52_53_VAL ((0x4 << 6) | (0x4 << 9)) + + #define PMX_PL_54_55_56_MASK (0x1FF << 12) + #define PMX_FSMC_EMI_PL_54_55_56_VAL ((0x2 << 12) | (0x2 << 15) | (0x2 << 18)) + + #define PMX_PL_57_MASK (0x7 << 21) + #define PMX_FSMC_PL_57_VAL 0 + #define PMX_PWM3_PL_57_VAL (0x4 << 21) + + #define PMX_PL_58_59_MASK (0x3F << 24) + #define PMX_PL_58_MASK (0x7 << 24) + #define PMX_PL_59_MASK (0x7 << 27) + #define PMX_FSMC_EMI_PL_58_59_VAL ((0x2 << 24) | (0x2 << 27)) + #define PMX_PWM2_PL_58_VAL (0x4 << 24) + #define PMX_PWM1_PL_59_VAL (0x4 << 27) + +#define IP_SEL_PAD_60_69_REG 0x00BC + #define PMX_PL_60_MASK (0x7 << 0) + #define PMX_FSMC_PL_60_VAL 0 + #define PMX_PWM0_PL_60_VAL (0x4 << 0) + + #define PMX_PL_61_TO_64_MASK (0xFFF << 3) + #define PMX_FSMC_PL_61_TO_64_VAL ((0x2 << 3) | (0x2 << 6) | (0x2 << 9) | (0x2 << 12)) + #define PMX_SSP2_PL_61_TO_64_VAL ((0x4 << 3) | (0x4 << 6) | (0x4 << 9) | (0x4 << 12)) + + #define PMX_PL_65_TO_68_MASK (0xFFF << 15) + #define PMX_FSMC_PL_65_TO_68_VAL ((0x2 << 15) | (0x2 << 18) | (0x2 << 21) | (0x2 << 24)) + #define PMX_SSP1_PL_65_TO_68_VAL ((0x4 << 15) | (0x4 << 18) | (0x4 << 21) | (0x4 << 24)) + + #define PMX_PL_69_MASK (0x7 << 27) + #define PMX_CLCD_PL_69_VAL (0) + #define PMX_EMI_PL_69_VAL (0x2 << 27) + #define PMX_SPP_PL_69_VAL (0x3 << 27) + #define PMX_UART5_PL_69_VAL (0x4 << 27) + +#define IP_SEL_PAD_70_79_REG 0x00C0 + #define PMX_PL_70_MASK (0x7 << 0) + #define PMX_CLCD_PL_70_VAL (0) + #define PMX_FSMC_EMI_PL_70_VAL (0x2 << 0) + #define PMX_SPP_PL_70_VAL (0x3 << 0) + #define PMX_UART5_PL_70_VAL (0x4 << 0) + + #define PMX_PL_71_72_MASK (0x3F << 3) + #define PMX_CLCD_PL_71_72_VAL (0) + #define PMX_FSMC_EMI_PL_71_72_VAL ((0x2 << 3) | (0x2 << 6)) + #define PMX_SPP_PL_71_72_VAL ((0x3 << 3) | (0x3 << 6)) + #define PMX_UART4_PL_71_72_VAL ((0x4 << 3) | (0x4 << 6)) + + #define PMX_PL_73_MASK (0x7 << 9) + #define PMX_CLCD_PL_73_VAL (0) + #define PMX_FSMC_EMI_PL_73_VAL (0x2 << 9) + #define PMX_SPP_PL_73_VAL (0x3 << 9) + #define PMX_UART3_PL_73_VAL (0x4 << 9) + + #define PMX_PL_74_MASK (0x7 << 12) + #define PMX_CLCD_PL_74_VAL (0) + #define PMX_EMI_PL_74_VAL (0x2 << 12) + #define PMX_SPP_PL_74_VAL (0x3 << 12) + #define PMX_UART3_PL_74_VAL (0x4 << 12) + + #define PMX_PL_75_76_MASK (0x3F << 15) + #define PMX_CLCD_PL_75_76_VAL (0) + #define PMX_EMI_PL_75_76_VAL ((0x2 << 15) | (0x2 << 18)) + #define PMX_SPP_PL_75_76_VAL ((0x3 << 15) | (0x3 << 18)) + #define PMX_I2C2_PL_75_76_VAL ((0x4 << 15) | (0x4 << 18)) + + #define PMX_PL_77_78_79_MASK (0x1FF << 21) + #define PMX_CLCD_PL_77_78_79_VAL (0) + #define PMX_EMI_PL_77_78_79_VAL ((0x2 << 21) | (0x2 << 24) | (0x2 << 27)) + #define PMX_SPP_PL_77_78_79_VAL ((0x3 << 21) | (0x3 << 24) | (0x3 << 27)) + #define PMX_RS485_PL_77_78_79_VAL ((0x4 << 21) | (0x4 << 24) | (0x4 << 27)) + +#define IP_SEL_PAD_80_89_REG 0x00C4 + #define PMX_PL_80_TO_85_MASK (0x3FFFF << 0) + #define PMX_CLCD_PL_80_TO_85_VAL 0 + #define PMX_MII2_PL_80_TO_85_VAL ((0x1 << 0) | (0x1 << 3) | (0x1 << 6) | (0x1 << 9) | (0x1 << 12) | (0x1 << 15)) + #define PMX_EMI_PL_80_TO_85_VAL ((0x2 << 0) | (0x2 << 3) | (0x2 << 6) | (0x2 << 9) | (0x2 << 12) | (0x2 << 15)) + #define PMX_SPP_PL_80_TO_85_VAL ((0x3 << 0) | (0x3 << 3) | (0x3 << 6) | (0x3 << 9) | (0x3 << 12) | (0x3 << 15)) + #define PMX_UART1_ENH_PL_80_TO_85_VAL ((0x4 << 0) | (0x4 << 3) | (0x4 << 6) | (0x4 << 9) | (0x4 << 12) | (0x4 << 15)) + + #define PMX_PL_86_87_MASK (0x3F << 18) + #define PMX_PL_86_MASK (0x7 << 18) + #define PMX_PL_87_MASK (0x7 << 21) + #define PMX_CLCD_PL_86_87_VAL 0 + #define PMX_MII2_PL_86_87_VAL ((0x1 << 18) | (0x1 << 21)) + #define PMX_EMI_PL_86_87_VAL ((0x2 << 18) | (0x2 << 21)) + #define PMX_PWM3_PL_86_VAL (0x4 << 18) + #define PMX_PWM2_PL_87_VAL (0x4 << 21) + + #define PMX_PL_88_89_MASK (0x3F << 24) + #define PMX_CLCD_PL_88_89_VAL 0 + #define PMX_MII2_PL_88_89_VAL ((0x1 << 24) | (0x1 << 27)) + #define PMX_EMI_PL_88_89_VAL ((0x2 << 24) | (0x2 << 27)) + #define PMX_UART6_PL_88_89_VAL ((0x3 << 24) | (0x3 << 27)) + #define PMX_PWM0_1_PL_88_89_VAL ((0x4 << 24) | (0x4 << 27)) + +#define IP_SEL_PAD_90_99_REG 0x00C8 + #define PMX_PL_90_91_MASK (0x3F << 0) + #define PMX_CLCD_PL_90_91_VAL 0 + #define PMX_MII2_PL_90_91_VAL ((0x1 << 0) | (0x1 << 3)) + #define PMX_EMI1_PL_90_91_VAL ((0x2 << 0) | (0x2 << 3)) + #define PMX_UART5_PL_90_91_VAL ((0x3 << 0) | (0x3 << 3)) + #define PMX_SSP2_PL_90_91_VAL ((0x4 << 0) | (0x4 << 3)) + + #define PMX_PL_92_93_MASK (0x3F << 6) + #define PMX_CLCD_PL_92_93_VAL 0 + #define PMX_MII2_PL_92_93_VAL ((0x1 << 6) | (0x1 << 9)) + #define PMX_EMI1_PL_92_93_VAL ((0x2 << 6) | (0x2 << 9)) + #define PMX_UART4_PL_92_93_VAL ((0x3 << 6) | (0x3 << 9)) + #define PMX_SSP2_PL_92_93_VAL ((0x4 << 6) | (0x4 << 9)) + + #define PMX_PL_94_95_MASK (0x3F << 12) + #define PMX_CLCD_PL_94_95_VAL 0 + #define PMX_MII2_PL_94_95_VAL ((0x1 << 12) | (0x1 << 15)) + #define PMX_EMI1_PL_94_95_VAL ((0x2 << 12) | (0x2 << 15)) + #define PMX_UART3_PL_94_95_VAL ((0x3 << 12) | (0x3 << 15)) + #define PMX_SSP1_PL_94_95_VAL ((0x4 << 12) | (0x4 << 15)) + + #define PMX_PL_96_97_MASK (0x3F << 18) + #define PMX_CLCD_PL_96_97_VAL 0 + #define PMX_MII2_PL_96_97_VAL ((0x1 << 18) | (0x1 << 21)) + #define PMX_EMI1_PL_96_97_VAL ((0x2 << 18) | (0x2 << 21)) + #define PMX_I2C2_PL_96_97_VAL ((0x3 << 18) | (0x3 << 21)) + #define PMX_SSP1_PL_96_97_VAL ((0x4 << 18) | (0x4 << 21)) + + #define PMX_PL_98_MASK (0x7 << 24) + #define PMX_CLCD_PL_98_VAL 0 + #define PMX_I2C1_PL_98_VAL (0x2 << 24) + #define PMX_UART3_PL_98_VAL (0x4 << 24) + + #define PMX_PL_99_MASK (0x7 << 27) + #define PMX_SDHCI_PL_99_VAL 0 + #define PMX_I2C1_PL_99_VAL (0x2 << 27) + #define PMX_UART3_PL_99_VAL (0x4 << 27) + +#define IP_SEL_MIX_PAD_REG 0x00CC + #define PMX_PL_100_101_MASK (0x3F << 0) + #define PMX_SDHCI_PL_100_101_VAL 0 + #define PMX_UART4_PL_100_101_VAL ((0x4 << 0) | (0x4 << 3)) + + #define PMX_SSP1_PORT_SEL_MASK (0x7 << 8) + #define PMX_SSP1_PORT_94_TO_97_VAL 0 + #define PMX_SSP1_PORT_65_TO_68_VAL (0x1 << 8) + #define PMX_SSP1_PORT_48_TO_51_VAL (0x2 << 8) + #define PMX_SSP1_PORT_36_TO_39_VAL (0x3 << 8) + #define PMX_SSP1_PORT_17_TO_20_VAL (0x4 << 8) + + #define PMX_SSP2_PORT_SEL_MASK (0x7 << 11) + #define PMX_SSP2_PORT_90_TO_93_VAL 0 + #define PMX_SSP2_PORT_61_TO_64_VAL (0x1 << 11) + #define PMX_SSP2_PORT_44_TO_47_VAL (0x2 << 11) + #define PMX_SSP2_PORT_32_TO_35_VAL (0x3 << 11) + #define PMX_SSP2_PORT_13_TO_16_VAL (0x4 << 11) + + #define PMX_UART1_ENH_PORT_SEL_MASK (0x3 << 14) + #define PMX_UART1_ENH_PORT_81_TO_85_VAL 0 + #define PMX_UART1_ENH_PORT_44_45_34_36_VAL (0x1 << 14) + #define PMX_UART1_ENH_PORT_32_TO_34_36_VAL (0x2 << 14) + #define PMX_UART1_ENH_PORT_3_TO_5_7_VAL (0x3 << 14) + + #define PMX_UART3_PORT_SEL_MASK (0x7 << 16) + #define PMX_UART3_PORT_94_VAL 0 + #define PMX_UART3_PORT_73_VAL (0x1 << 16) + #define PMX_UART3_PORT_52_VAL (0x2 << 16) + #define PMX_UART3_PORT_41_VAL (0x3 << 16) + #define PMX_UART3_PORT_15_VAL (0x4 << 16) + #define PMX_UART3_PORT_8_VAL (0x5 << 16) + #define PMX_UART3_PORT_99_VAL (0x6 << 16) + + #define PMX_UART4_PORT_SEL_MASK (0x7 << 19) + #define PMX_UART4_PORT_92_VAL 0 + #define PMX_UART4_PORT_71_VAL (0x1 << 19) + #define PMX_UART4_PORT_39_VAL (0x2 << 19) + #define PMX_UART4_PORT_13_VAL (0x3 << 19) + #define PMX_UART4_PORT_6_VAL (0x4 << 19) + #define PMX_UART4_PORT_101_VAL (0x5 << 19) + + #define PMX_UART5_PORT_SEL_MASK (0x3 << 22) + #define PMX_UART5_PORT_90_VAL 0 + #define PMX_UART5_PORT_69_VAL (0x1 << 22) + #define PMX_UART5_PORT_37_VAL (0x2 << 22) + #define PMX_UART5_PORT_4_VAL (0x3 << 22) + + #define PMX_UART6_PORT_SEL_MASK (0x1 << 24) + #define PMX_UART6_PORT_88_VAL 0 + #define PMX_UART6_PORT_2_VAL (0x1 << 24) + + #define PMX_I2C1_PORT_SEL_MASK (0x1 << 25) + #define PMX_I2C1_PORT_8_9_VAL 0 + #define PMX_I2C1_PORT_98_99_VAL (0x1 << 25) + + #define PMX_I2C2_PORT_SEL_MASK (0x3 << 26) + #define PMX_I2C2_PORT_96_97_VAL 0 + #define PMX_I2C2_PORT_75_76_VAL (0x1 << 26) + #define PMX_I2C2_PORT_19_20_VAL (0x2 << 26) + #define PMX_I2C2_PORT_2_3_VAL (0x3 << 26) + #define PMX_I2C2_PORT_0_1_VAL (0x4 << 26) + + #define PMX_SDHCI_CD_PORT_SEL_MASK (0x1 << 29) + #define PMX_SDHCI_CD_PORT_12_VAL 0 + #define PMX_SDHCI_CD_PORT_51_VAL (0x1 << 29) + +/* Pad multiplexing for CLCD device */ +static const unsigned clcd_pins[] = { 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97 }; +static struct spear_muxreg clcd_muxreg[] = { + { + .reg = IP_SEL_PAD_60_69_REG, + .mask = PMX_PL_69_MASK, + .val = PMX_CLCD_PL_69_VAL, + }, { + .reg = IP_SEL_PAD_70_79_REG, + .mask = PMX_PL_70_MASK | PMX_PL_71_72_MASK | PMX_PL_73_MASK | + PMX_PL_74_MASK | PMX_PL_75_76_MASK | + PMX_PL_77_78_79_MASK, + .val = PMX_CLCD_PL_70_VAL | PMX_CLCD_PL_71_72_VAL | + PMX_CLCD_PL_73_VAL | PMX_CLCD_PL_74_VAL | + PMX_CLCD_PL_75_76_VAL | PMX_CLCD_PL_77_78_79_VAL, + }, { + .reg = IP_SEL_PAD_80_89_REG, + .mask = PMX_PL_80_TO_85_MASK | PMX_PL_86_87_MASK | + PMX_PL_88_89_MASK, + .val = PMX_CLCD_PL_80_TO_85_VAL | PMX_CLCD_PL_86_87_VAL | + PMX_CLCD_PL_88_89_VAL, + }, { + .reg = IP_SEL_PAD_90_99_REG, + .mask = PMX_PL_90_91_MASK | PMX_PL_92_93_MASK | + PMX_PL_94_95_MASK | PMX_PL_96_97_MASK | PMX_PL_98_MASK, + .val = PMX_CLCD_PL_90_91_VAL | PMX_CLCD_PL_92_93_VAL | + PMX_CLCD_PL_94_95_VAL | PMX_CLCD_PL_96_97_VAL | + PMX_CLCD_PL_98_VAL, + }, +}; + +static struct spear_modemux clcd_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = clcd_muxreg, + .nmuxregs = ARRAY_SIZE(clcd_muxreg), + }, +}; + +static struct spear_pingroup clcd_pingroup = { + .name = "clcd_grp", + .pins = clcd_pins, + .npins = ARRAY_SIZE(clcd_pins), + .modemuxs = clcd_modemux, + .nmodemuxs = ARRAY_SIZE(clcd_modemux), +}; + +static const char *const clcd_grps[] = { "clcd_grp" }; +static struct spear_function clcd_function = { + .name = "clcd", + .groups = clcd_grps, + .ngroups = ARRAY_SIZE(clcd_grps), +}; + +/* Pad multiplexing for EMI (Parallel NOR flash) device */ +static const unsigned emi_pins[] = { 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97 }; +static struct spear_muxreg emi_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK, + .val = 0, + }, +}; + +static struct spear_muxreg emi_ext_muxreg[] = { + { + .reg = IP_SEL_PAD_40_49_REG, + .mask = PMX_PL_46_47_MASK | PMX_PL_48_49_MASK, + .val = PMX_FSMC_EMI_PL_46_47_VAL | PMX_FSMC_EMI_PL_48_49_VAL, + }, { + .reg = IP_SEL_PAD_50_59_REG, + .mask = PMX_PL_50_51_MASK | PMX_PL_52_53_MASK | + PMX_PL_54_55_56_MASK | PMX_PL_58_59_MASK, + .val = PMX_EMI_PL_50_51_VAL | PMX_EMI_PL_52_53_VAL | + PMX_FSMC_EMI_PL_54_55_56_VAL | + PMX_FSMC_EMI_PL_58_59_VAL, + }, { + .reg = IP_SEL_PAD_60_69_REG, + .mask = PMX_PL_69_MASK, + .val = PMX_EMI_PL_69_VAL, + }, { + .reg = IP_SEL_PAD_70_79_REG, + .mask = PMX_PL_70_MASK | PMX_PL_71_72_MASK | PMX_PL_73_MASK | + PMX_PL_74_MASK | PMX_PL_75_76_MASK | + PMX_PL_77_78_79_MASK, + .val = PMX_FSMC_EMI_PL_70_VAL | PMX_FSMC_EMI_PL_71_72_VAL | + PMX_FSMC_EMI_PL_73_VAL | PMX_EMI_PL_74_VAL | + PMX_EMI_PL_75_76_VAL | PMX_EMI_PL_77_78_79_VAL, + }, { + .reg = IP_SEL_PAD_80_89_REG, + .mask = PMX_PL_80_TO_85_MASK | PMX_PL_86_87_MASK | + PMX_PL_88_89_MASK, + .val = PMX_EMI_PL_80_TO_85_VAL | PMX_EMI_PL_86_87_VAL | + PMX_EMI_PL_88_89_VAL, + }, { + .reg = IP_SEL_PAD_90_99_REG, + .mask = PMX_PL_90_91_MASK | PMX_PL_92_93_MASK | + PMX_PL_94_95_MASK | PMX_PL_96_97_MASK, + .val = PMX_EMI1_PL_90_91_VAL | PMX_EMI1_PL_92_93_VAL | + PMX_EMI1_PL_94_95_VAL | PMX_EMI1_PL_96_97_VAL, + }, { + .reg = EXT_CTRL_REG, + .mask = EMI_FSMC_DYNAMIC_MUX_MASK, + .val = EMI_FSMC_DYNAMIC_MUX_MASK, + }, +}; + +static struct spear_modemux emi_modemux[] = { + { + .modes = AUTO_EXP_MODE | EXTENDED_MODE, + .muxregs = emi_muxreg, + .nmuxregs = ARRAY_SIZE(emi_muxreg), + }, { + .modes = EXTENDED_MODE, + .muxregs = emi_ext_muxreg, + .nmuxregs = ARRAY_SIZE(emi_ext_muxreg), + }, +}; + +static struct spear_pingroup emi_pingroup = { + .name = "emi_grp", + .pins = emi_pins, + .npins = ARRAY_SIZE(emi_pins), + .modemuxs = emi_modemux, + .nmodemuxs = ARRAY_SIZE(emi_modemux), +}; + +static const char *const emi_grps[] = { "emi_grp" }; +static struct spear_function emi_function = { + .name = "emi", + .groups = emi_grps, + .ngroups = ARRAY_SIZE(emi_grps), +}; + +/* Pad multiplexing for FSMC (NAND flash) device */ +static const unsigned fsmc_8bit_pins[] = { 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68 }; +static struct spear_muxreg fsmc_8bit_muxreg[] = { + { + .reg = IP_SEL_PAD_50_59_REG, + .mask = PMX_PL_52_53_MASK | PMX_PL_54_55_56_MASK | + PMX_PL_57_MASK | PMX_PL_58_59_MASK, + .val = PMX_FSMC_PL_52_53_VAL | PMX_FSMC_EMI_PL_54_55_56_VAL | + PMX_FSMC_PL_57_VAL | PMX_FSMC_EMI_PL_58_59_VAL, + }, { + .reg = IP_SEL_PAD_60_69_REG, + .mask = PMX_PL_60_MASK | PMX_PL_61_TO_64_MASK | + PMX_PL_65_TO_68_MASK, + .val = PMX_FSMC_PL_60_VAL | PMX_FSMC_PL_61_TO_64_VAL | + PMX_FSMC_PL_65_TO_68_VAL, + }, { + .reg = EXT_CTRL_REG, + .mask = EMI_FSMC_DYNAMIC_MUX_MASK, + .val = EMI_FSMC_DYNAMIC_MUX_MASK, + }, +}; + +static struct spear_modemux fsmc_8bit_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = fsmc_8bit_muxreg, + .nmuxregs = ARRAY_SIZE(fsmc_8bit_muxreg), + }, +}; + +static struct spear_pingroup fsmc_8bit_pingroup = { + .name = "fsmc_8bit_grp", + .pins = fsmc_8bit_pins, + .npins = ARRAY_SIZE(fsmc_8bit_pins), + .modemuxs = fsmc_8bit_modemux, + .nmodemuxs = ARRAY_SIZE(fsmc_8bit_modemux), +}; + +static const unsigned fsmc_16bit_pins[] = { 46, 47, 48, 49, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 70, 71, 72, 73 }; +static struct spear_muxreg fsmc_16bit_autoexp_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK, + .val = 0, + }, +}; + +static struct spear_muxreg fsmc_16bit_muxreg[] = { + { + .reg = IP_SEL_PAD_40_49_REG, + .mask = PMX_PL_46_47_MASK | PMX_PL_48_49_MASK, + .val = PMX_FSMC_EMI_PL_46_47_VAL | PMX_FSMC_EMI_PL_48_49_VAL, + }, { + .reg = IP_SEL_PAD_70_79_REG, + .mask = PMX_PL_70_MASK | PMX_PL_71_72_MASK | PMX_PL_73_MASK, + .val = PMX_FSMC_EMI_PL_70_VAL | PMX_FSMC_EMI_PL_71_72_VAL | + PMX_FSMC_EMI_PL_73_VAL, + } +}; + +static struct spear_modemux fsmc_16bit_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = fsmc_8bit_muxreg, + .nmuxregs = ARRAY_SIZE(fsmc_8bit_muxreg), + }, { + .modes = AUTO_EXP_MODE | EXTENDED_MODE, + .muxregs = fsmc_16bit_autoexp_muxreg, + .nmuxregs = ARRAY_SIZE(fsmc_16bit_autoexp_muxreg), + }, { + .modes = EXTENDED_MODE, + .muxregs = fsmc_16bit_muxreg, + .nmuxregs = ARRAY_SIZE(fsmc_16bit_muxreg), + }, +}; + +static struct spear_pingroup fsmc_16bit_pingroup = { + .name = "fsmc_16bit_grp", + .pins = fsmc_16bit_pins, + .npins = ARRAY_SIZE(fsmc_16bit_pins), + .modemuxs = fsmc_16bit_modemux, + .nmodemuxs = ARRAY_SIZE(fsmc_16bit_modemux), +}; + +static const char *const fsmc_grps[] = { "fsmc_8bit_grp", "fsmc_16bit_grp" }; +static struct spear_function fsmc_function = { + .name = "fsmc", + .groups = fsmc_grps, + .ngroups = ARRAY_SIZE(fsmc_grps), +}; + +/* Pad multiplexing for SPP device */ +static const unsigned spp_pins[] = { 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85 }; +static struct spear_muxreg spp_muxreg[] = { + { + .reg = IP_SEL_PAD_60_69_REG, + .mask = PMX_PL_69_MASK, + .val = PMX_SPP_PL_69_VAL, + }, { + .reg = IP_SEL_PAD_70_79_REG, + .mask = PMX_PL_70_MASK | PMX_PL_71_72_MASK | PMX_PL_73_MASK | + PMX_PL_74_MASK | PMX_PL_75_76_MASK | + PMX_PL_77_78_79_MASK, + .val = PMX_SPP_PL_70_VAL | PMX_SPP_PL_71_72_VAL | + PMX_SPP_PL_73_VAL | PMX_SPP_PL_74_VAL | + PMX_SPP_PL_75_76_VAL | PMX_SPP_PL_77_78_79_VAL, + }, { + .reg = IP_SEL_PAD_80_89_REG, + .mask = PMX_PL_80_TO_85_MASK, + .val = PMX_SPP_PL_80_TO_85_VAL, + }, +}; + +static struct spear_modemux spp_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = spp_muxreg, + .nmuxregs = ARRAY_SIZE(spp_muxreg), + }, +}; + +static struct spear_pingroup spp_pingroup = { + .name = "spp_grp", + .pins = spp_pins, + .npins = ARRAY_SIZE(spp_pins), + .modemuxs = spp_modemux, + .nmodemuxs = ARRAY_SIZE(spp_modemux), +}; + +static const char *const spp_grps[] = { "spp_grp" }; +static struct spear_function spp_function = { + .name = "spp", + .groups = spp_grps, + .ngroups = ARRAY_SIZE(spp_grps), +}; + +/* Pad multiplexing for SDHCI device */ +static const unsigned sdhci_led_pins[] = { 34 }; +static struct spear_muxreg sdhci_led_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_SSP_CS_MASK, + .val = 0, + }, +}; + +static struct spear_muxreg sdhci_led_ext_muxreg[] = { + { + .reg = IP_SEL_PAD_30_39_REG, + .mask = PMX_PL_34_MASK, + .val = PMX_PWM2_PL_34_VAL, + }, +}; + +static struct spear_modemux sdhci_led_modemux[] = { + { + .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | EXTENDED_MODE, + .muxregs = sdhci_led_muxreg, + .nmuxregs = ARRAY_SIZE(sdhci_led_muxreg), + }, { + .modes = EXTENDED_MODE, + .muxregs = sdhci_led_ext_muxreg, + .nmuxregs = ARRAY_SIZE(sdhci_led_ext_muxreg), + }, +}; + +static struct spear_pingroup sdhci_led_pingroup = { + .name = "sdhci_led_grp", + .pins = sdhci_led_pins, + .npins = ARRAY_SIZE(sdhci_led_pins), + .modemuxs = sdhci_led_modemux, + .nmodemuxs = ARRAY_SIZE(sdhci_led_modemux), +}; + +static const unsigned sdhci_cd_12_pins[] = { 12, 43, 44, 45, 46, 47, 48, 49, + 50}; +static const unsigned sdhci_cd_51_pins[] = { 43, 44, 45, 46, 47, 48, 49, 50, 51 +}; +static struct spear_muxreg sdhci_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK, + .val = 0, + }, +}; + +static struct spear_muxreg sdhci_ext_muxreg[] = { + { + .reg = IP_SEL_PAD_40_49_REG, + .mask = PMX_PL_43_MASK | PMX_PL_44_45_MASK | PMX_PL_46_47_MASK | + PMX_PL_48_49_MASK, + .val = PMX_SDHCI_PL_43_VAL | PMX_SDHCI_PL_44_45_VAL | + PMX_SDHCI_PL_46_47_VAL | PMX_SDHCI_PL_48_49_VAL, + }, { + .reg = IP_SEL_PAD_50_59_REG, + .mask = PMX_PL_50_MASK, + .val = PMX_SDHCI_PL_50_VAL, + }, { + .reg = IP_SEL_PAD_90_99_REG, + .mask = PMX_PL_99_MASK, + .val = PMX_SDHCI_PL_99_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_PL_100_101_MASK, + .val = PMX_SDHCI_PL_100_101_VAL, + }, +}; + +static struct spear_muxreg sdhci_cd_12_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_MII_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_10_19_REG, + .mask = PMX_PL_12_MASK, + .val = PMX_SDHCI_CD_PL_12_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_SDHCI_CD_PORT_SEL_MASK, + .val = PMX_SDHCI_CD_PORT_12_VAL, + }, +}; + +static struct spear_muxreg sdhci_cd_51_muxreg[] = { + { + .reg = IP_SEL_PAD_50_59_REG, + .mask = PMX_PL_51_MASK, + .val = PMX_SDHCI_CD_PL_51_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_SDHCI_CD_PORT_SEL_MASK, + .val = PMX_SDHCI_CD_PORT_51_VAL, + }, +}; + +#define pmx_sdhci_common_modemux \ + { \ + .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | \ + SMALL_PRINTERS_MODE | EXTENDED_MODE, \ + .muxregs = sdhci_muxreg, \ + .nmuxregs = ARRAY_SIZE(sdhci_muxreg), \ + }, { \ + .modes = EXTENDED_MODE, \ + .muxregs = sdhci_ext_muxreg, \ + .nmuxregs = ARRAY_SIZE(sdhci_ext_muxreg), \ + } + +static struct spear_modemux sdhci_modemux[][3] = { + { + /* select pin 12 for cd */ + pmx_sdhci_common_modemux, + { + .modes = EXTENDED_MODE, + .muxregs = sdhci_cd_12_muxreg, + .nmuxregs = ARRAY_SIZE(sdhci_cd_12_muxreg), + }, + }, { + /* select pin 51 for cd */ + pmx_sdhci_common_modemux, + { + .modes = EXTENDED_MODE, + .muxregs = sdhci_cd_51_muxreg, + .nmuxregs = ARRAY_SIZE(sdhci_cd_51_muxreg), + }, + } +}; + +static struct spear_pingroup sdhci_pingroup[] = { + { + .name = "sdhci_cd_12_grp", + .pins = sdhci_cd_12_pins, + .npins = ARRAY_SIZE(sdhci_cd_12_pins), + .modemuxs = sdhci_modemux[0], + .nmodemuxs = ARRAY_SIZE(sdhci_modemux[0]), + }, { + .name = "sdhci_cd_51_grp", + .pins = sdhci_cd_51_pins, + .npins = ARRAY_SIZE(sdhci_cd_51_pins), + .modemuxs = sdhci_modemux[1], + .nmodemuxs = ARRAY_SIZE(sdhci_modemux[1]), + }, +}; + +static const char *const sdhci_grps[] = { "sdhci_cd_12_grp", "sdhci_cd_51_grp", + "sdhci_led_grp" }; + +static struct spear_function sdhci_function = { + .name = "sdhci", + .groups = sdhci_grps, + .ngroups = ARRAY_SIZE(sdhci_grps), +}; + +/* Pad multiplexing for I2S device */ +static const unsigned i2s_pins[] = { 35, 39, 40, 41, 42 }; +static struct spear_muxreg i2s_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_SSP_CS_MASK, + .val = 0, + }, { + .reg = PMX_CONFIG_REG, + .mask = PMX_UART0_MODEM_MASK, + .val = 0, + }, +}; + +static struct spear_muxreg i2s_ext_muxreg[] = { + { + .reg = IP_SEL_PAD_30_39_REG, + .mask = PMX_PL_35_MASK | PMX_PL_39_MASK, + .val = PMX_I2S_REF_CLK_PL_35_VAL | PMX_I2S_PL_39_VAL, + }, { + .reg = IP_SEL_PAD_40_49_REG, + .mask = PMX_PL_40_MASK | PMX_PL_41_42_MASK, + .val = PMX_I2S_PL_40_VAL | PMX_I2S_PL_41_42_VAL, + }, +}; + +static struct spear_modemux i2s_modemux[] = { + { + .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | EXTENDED_MODE, + .muxregs = i2s_muxreg, + .nmuxregs = ARRAY_SIZE(i2s_muxreg), + }, { + .modes = EXTENDED_MODE, + .muxregs = i2s_ext_muxreg, + .nmuxregs = ARRAY_SIZE(i2s_ext_muxreg), + }, +}; + +static struct spear_pingroup i2s_pingroup = { + .name = "i2s_grp", + .pins = i2s_pins, + .npins = ARRAY_SIZE(i2s_pins), + .modemuxs = i2s_modemux, + .nmodemuxs = ARRAY_SIZE(i2s_modemux), +}; + +static const char *const i2s_grps[] = { "i2s_grp" }; +static struct spear_function i2s_function = { + .name = "i2s", + .groups = i2s_grps, + .ngroups = ARRAY_SIZE(i2s_grps), +}; + +/* Pad multiplexing for UART1 device */ +static const unsigned uart1_pins[] = { 28, 29 }; +static struct spear_muxreg uart1_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_GPIO_PIN0_MASK | PMX_GPIO_PIN1_MASK, + .val = 0, + }, +}; + +static struct spear_muxreg uart1_ext_muxreg[] = { + { + .reg = IP_SEL_PAD_20_29_REG, + .mask = PMX_PL_28_29_MASK, + .val = PMX_UART1_PL_28_29_VAL, + }, +}; + +static struct spear_modemux uart1_modemux[] = { + { + .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | AUTO_EXP_MODE + | SMALL_PRINTERS_MODE | EXTENDED_MODE, + .muxregs = uart1_muxreg, + .nmuxregs = ARRAY_SIZE(uart1_muxreg), + }, { + .modes = EXTENDED_MODE, + .muxregs = uart1_ext_muxreg, + .nmuxregs = ARRAY_SIZE(uart1_ext_muxreg), + }, +}; + +static struct spear_pingroup uart1_pingroup = { + .name = "uart1_grp", + .pins = uart1_pins, + .npins = ARRAY_SIZE(uart1_pins), + .modemuxs = uart1_modemux, + .nmodemuxs = ARRAY_SIZE(uart1_modemux), +}; + +static const char *const uart1_grps[] = { "uart1_grp" }; +static struct spear_function uart1_function = { + .name = "uart1", + .groups = uart1_grps, + .ngroups = ARRAY_SIZE(uart1_grps), +}; + +/* Pad multiplexing for UART1 Modem device */ +static const unsigned uart1_modem_2_to_7_pins[] = { 2, 3, 4, 5, 6, 7 }; +static const unsigned uart1_modem_31_to_36_pins[] = { 31, 32, 33, 34, 35, 36 }; +static const unsigned uart1_modem_34_to_45_pins[] = { 34, 35, 36, 43, 44, 45 }; +static const unsigned uart1_modem_80_to_85_pins[] = { 80, 81, 82, 83, 84, 85 }; + +static struct spear_muxreg uart1_modem_ext_2_to_7_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_UART0_MASK | PMX_I2C_MASK | PMX_SSP_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_0_9_REG, + .mask = PMX_PL_2_3_MASK | PMX_PL_6_7_MASK, + .val = PMX_UART1_ENH_PL_2_3_VAL | PMX_UART1_ENH_PL_4_5_VAL | + PMX_UART1_ENH_PL_6_7_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_UART1_ENH_PORT_SEL_MASK, + .val = PMX_UART1_ENH_PORT_3_TO_5_7_VAL, + }, +}; + +static struct spear_muxreg uart1_modem_31_to_36_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_GPIO_PIN3_MASK | PMX_GPIO_PIN4_MASK | + PMX_GPIO_PIN5_MASK | PMX_SSP_CS_MASK, + .val = 0, + }, +}; + +static struct spear_muxreg uart1_modem_ext_31_to_36_muxreg[] = { + { + .reg = IP_SEL_PAD_30_39_REG, + .mask = PMX_PL_31_MASK | PMX_PL_32_33_MASK | PMX_PL_34_MASK | + PMX_PL_35_MASK | PMX_PL_36_MASK, + .val = PMX_UART1_ENH_PL_31_VAL | PMX_UART1_ENH_PL_32_33_VAL | + PMX_UART1_ENH_PL_34_VAL | PMX_UART1_ENH_PL_35_VAL | + PMX_UART1_ENH_PL_36_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_UART1_ENH_PORT_SEL_MASK, + .val = PMX_UART1_ENH_PORT_32_TO_34_36_VAL, + }, +}; + +static struct spear_muxreg uart1_modem_34_to_45_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK | + PMX_SSP_CS_MASK, + .val = 0, + }, +}; + +static struct spear_muxreg uart1_modem_ext_34_to_45_muxreg[] = { + { + .reg = IP_SEL_PAD_30_39_REG, + .mask = PMX_PL_34_MASK | PMX_PL_35_MASK | PMX_PL_36_MASK, + .val = PMX_UART1_ENH_PL_34_VAL | PMX_UART1_ENH_PL_35_VAL | + PMX_UART1_ENH_PL_36_VAL, + }, { + .reg = IP_SEL_PAD_40_49_REG, + .mask = PMX_PL_43_MASK | PMX_PL_44_45_MASK, + .val = PMX_UART1_ENH_PL_43_VAL | PMX_UART1_ENH_PL_44_45_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_UART1_ENH_PORT_SEL_MASK, + .val = PMX_UART1_ENH_PORT_44_45_34_36_VAL, + }, +}; + +static struct spear_muxreg uart1_modem_ext_80_to_85_muxreg[] = { + { + .reg = IP_SEL_PAD_80_89_REG, + .mask = PMX_PL_80_TO_85_MASK, + .val = PMX_UART1_ENH_PL_80_TO_85_VAL, + }, { + .reg = IP_SEL_PAD_40_49_REG, + .mask = PMX_PL_43_MASK | PMX_PL_44_45_MASK, + .val = PMX_UART1_ENH_PL_43_VAL | PMX_UART1_ENH_PL_44_45_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_UART1_ENH_PORT_SEL_MASK, + .val = PMX_UART1_ENH_PORT_81_TO_85_VAL, + }, +}; + +static struct spear_modemux uart1_modem_2_to_7_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = uart1_modem_ext_2_to_7_muxreg, + .nmuxregs = ARRAY_SIZE(uart1_modem_ext_2_to_7_muxreg), + }, +}; + +static struct spear_modemux uart1_modem_31_to_36_modemux[] = { + { + .modes = SMALL_PRINTERS_MODE | EXTENDED_MODE, + .muxregs = uart1_modem_31_to_36_muxreg, + .nmuxregs = ARRAY_SIZE(uart1_modem_31_to_36_muxreg), + }, { + .modes = EXTENDED_MODE, + .muxregs = uart1_modem_ext_31_to_36_muxreg, + .nmuxregs = ARRAY_SIZE(uart1_modem_ext_31_to_36_muxreg), + }, +}; + +static struct spear_modemux uart1_modem_34_to_45_modemux[] = { + { + .modes = AUTO_EXP_MODE | EXTENDED_MODE, + .muxregs = uart1_modem_34_to_45_muxreg, + .nmuxregs = ARRAY_SIZE(uart1_modem_34_to_45_muxreg), + }, { + .modes = EXTENDED_MODE, + .muxregs = uart1_modem_ext_34_to_45_muxreg, + .nmuxregs = ARRAY_SIZE(uart1_modem_ext_34_to_45_muxreg), + }, +}; + +static struct spear_modemux uart1_modem_80_to_85_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = uart1_modem_ext_80_to_85_muxreg, + .nmuxregs = ARRAY_SIZE(uart1_modem_ext_80_to_85_muxreg), + }, +}; + +static struct spear_pingroup uart1_modem_pingroup[] = { + { + .name = "uart1_modem_2_to_7_grp", + .pins = uart1_modem_2_to_7_pins, + .npins = ARRAY_SIZE(uart1_modem_2_to_7_pins), + .modemuxs = uart1_modem_2_to_7_modemux, + .nmodemuxs = ARRAY_SIZE(uart1_modem_2_to_7_modemux), + }, { + .name = "uart1_modem_31_to_36_grp", + .pins = uart1_modem_31_to_36_pins, + .npins = ARRAY_SIZE(uart1_modem_31_to_36_pins), + .modemuxs = uart1_modem_31_to_36_modemux, + .nmodemuxs = ARRAY_SIZE(uart1_modem_31_to_36_modemux), + }, { + .name = "uart1_modem_34_to_45_grp", + .pins = uart1_modem_34_to_45_pins, + .npins = ARRAY_SIZE(uart1_modem_34_to_45_pins), + .modemuxs = uart1_modem_34_to_45_modemux, + .nmodemuxs = ARRAY_SIZE(uart1_modem_34_to_45_modemux), + }, { + .name = "uart1_modem_80_to_85_grp", + .pins = uart1_modem_80_to_85_pins, + .npins = ARRAY_SIZE(uart1_modem_80_to_85_pins), + .modemuxs = uart1_modem_80_to_85_modemux, + .nmodemuxs = ARRAY_SIZE(uart1_modem_80_to_85_modemux), + }, +}; + +static const char *const uart1_modem_grps[] = { "uart1_modem_2_to_7_grp", + "uart1_modem_31_to_36_grp", "uart1_modem_34_to_45_grp", + "uart1_modem_80_to_85_grp" }; +static struct spear_function uart1_modem_function = { + .name = "uart1_modem", + .groups = uart1_modem_grps, + .ngroups = ARRAY_SIZE(uart1_modem_grps), +}; + +/* Pad multiplexing for UART2 device */ +static const unsigned uart2_pins[] = { 0, 1 }; +static struct spear_muxreg uart2_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_FIRDA_MASK, + .val = 0, + }, +}; + +static struct spear_muxreg uart2_ext_muxreg[] = { + { + .reg = IP_SEL_PAD_0_9_REG, + .mask = PMX_PL_0_1_MASK, + .val = PMX_UART2_PL_0_1_VAL, + }, +}; + +static struct spear_modemux uart2_modemux[] = { + { + .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | AUTO_EXP_MODE + | SMALL_PRINTERS_MODE | EXTENDED_MODE, + .muxregs = uart2_muxreg, + .nmuxregs = ARRAY_SIZE(uart2_muxreg), + }, { + .modes = EXTENDED_MODE, + .muxregs = uart2_ext_muxreg, + .nmuxregs = ARRAY_SIZE(uart2_ext_muxreg), + }, +}; + +static struct spear_pingroup uart2_pingroup = { + .name = "uart2_grp", + .pins = uart2_pins, + .npins = ARRAY_SIZE(uart2_pins), + .modemuxs = uart2_modemux, + .nmodemuxs = ARRAY_SIZE(uart2_modemux), +}; + +static const char *const uart2_grps[] = { "uart2_grp" }; +static struct spear_function uart2_function = { + .name = "uart2", + .groups = uart2_grps, + .ngroups = ARRAY_SIZE(uart2_grps), +}; + +/* Pad multiplexing for uart3 device */ +static const unsigned uart3_pins[][2] = { { 8, 9 }, { 15, 16 }, { 41, 42 }, + { 52, 53 }, { 73, 74 }, { 94, 95 }, { 98, 99 } }; + +static struct spear_muxreg uart3_ext_8_9_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_SSP_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_0_9_REG, + .mask = PMX_PL_8_9_MASK, + .val = PMX_UART3_PL_8_9_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_UART3_PORT_SEL_MASK, + .val = PMX_UART3_PORT_8_VAL, + }, +}; + +static struct spear_muxreg uart3_ext_15_16_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_MII_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_10_19_REG, + .mask = PMX_PL_15_16_MASK, + .val = PMX_UART3_PL_15_16_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_UART3_PORT_SEL_MASK, + .val = PMX_UART3_PORT_15_VAL, + }, +}; + +static struct spear_muxreg uart3_ext_41_42_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_UART0_MODEM_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_40_49_REG, + .mask = PMX_PL_41_42_MASK, + .val = PMX_UART3_PL_41_42_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_UART3_PORT_SEL_MASK, + .val = PMX_UART3_PORT_41_VAL, + }, +}; + +static struct spear_muxreg uart3_ext_52_53_muxreg[] = { + { + .reg = IP_SEL_PAD_50_59_REG, + .mask = PMX_PL_52_53_MASK, + .val = PMX_UART3_PL_52_53_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_UART3_PORT_SEL_MASK, + .val = PMX_UART3_PORT_52_VAL, + }, +}; + +static struct spear_muxreg uart3_ext_73_74_muxreg[] = { + { + .reg = IP_SEL_PAD_70_79_REG, + .mask = PMX_PL_73_MASK | PMX_PL_74_MASK, + .val = PMX_UART3_PL_73_VAL | PMX_UART3_PL_74_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_UART3_PORT_SEL_MASK, + .val = PMX_UART3_PORT_73_VAL, + }, +}; + +static struct spear_muxreg uart3_ext_94_95_muxreg[] = { + { + .reg = IP_SEL_PAD_90_99_REG, + .mask = PMX_PL_94_95_MASK, + .val = PMX_UART3_PL_94_95_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_UART3_PORT_SEL_MASK, + .val = PMX_UART3_PORT_94_VAL, + }, +}; + +static struct spear_muxreg uart3_ext_98_99_muxreg[] = { + { + .reg = IP_SEL_PAD_90_99_REG, + .mask = PMX_PL_98_MASK | PMX_PL_99_MASK, + .val = PMX_UART3_PL_98_VAL | PMX_UART3_PL_99_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_UART3_PORT_SEL_MASK, + .val = PMX_UART3_PORT_99_VAL, + }, +}; + +static struct spear_modemux uart3_modemux[][1] = { + { + /* Select signals on pins 8_9 */ + { + .modes = EXTENDED_MODE, + .muxregs = uart3_ext_8_9_muxreg, + .nmuxregs = ARRAY_SIZE(uart3_ext_8_9_muxreg), + }, + }, { + /* Select signals on pins 15_16 */ + { + .modes = EXTENDED_MODE, + .muxregs = uart3_ext_15_16_muxreg, + .nmuxregs = ARRAY_SIZE(uart3_ext_15_16_muxreg), + }, + }, { + /* Select signals on pins 41_42 */ + { + .modes = EXTENDED_MODE, + .muxregs = uart3_ext_41_42_muxreg, + .nmuxregs = ARRAY_SIZE(uart3_ext_41_42_muxreg), + }, + }, { + /* Select signals on pins 52_53 */ + { + .modes = EXTENDED_MODE, + .muxregs = uart3_ext_52_53_muxreg, + .nmuxregs = ARRAY_SIZE(uart3_ext_52_53_muxreg), + }, + }, { + /* Select signals on pins 73_74 */ + { + .modes = EXTENDED_MODE, + .muxregs = uart3_ext_73_74_muxreg, + .nmuxregs = ARRAY_SIZE(uart3_ext_73_74_muxreg), + }, + }, { + /* Select signals on pins 94_95 */ + { + .modes = EXTENDED_MODE, + .muxregs = uart3_ext_94_95_muxreg, + .nmuxregs = ARRAY_SIZE(uart3_ext_94_95_muxreg), + }, + }, { + /* Select signals on pins 98_99 */ + { + .modes = EXTENDED_MODE, + .muxregs = uart3_ext_98_99_muxreg, + .nmuxregs = ARRAY_SIZE(uart3_ext_98_99_muxreg), + }, + }, +}; + +static struct spear_pingroup uart3_pingroup[] = { + { + .name = "uart3_8_9_grp", + .pins = uart3_pins[0], + .npins = ARRAY_SIZE(uart3_pins[0]), + .modemuxs = uart3_modemux[0], + .nmodemuxs = ARRAY_SIZE(uart3_modemux[0]), + }, { + .name = "uart3_15_16_grp", + .pins = uart3_pins[1], + .npins = ARRAY_SIZE(uart3_pins[1]), + .modemuxs = uart3_modemux[1], + .nmodemuxs = ARRAY_SIZE(uart3_modemux[1]), + }, { + .name = "uart3_41_42_grp", + .pins = uart3_pins[2], + .npins = ARRAY_SIZE(uart3_pins[2]), + .modemuxs = uart3_modemux[2], + .nmodemuxs = ARRAY_SIZE(uart3_modemux[2]), + }, { + .name = "uart3_52_53_grp", + .pins = uart3_pins[3], + .npins = ARRAY_SIZE(uart3_pins[3]), + .modemuxs = uart3_modemux[3], + .nmodemuxs = ARRAY_SIZE(uart3_modemux[3]), + }, { + .name = "uart3_73_74_grp", + .pins = uart3_pins[4], + .npins = ARRAY_SIZE(uart3_pins[4]), + .modemuxs = uart3_modemux[4], + .nmodemuxs = ARRAY_SIZE(uart3_modemux[4]), + }, { + .name = "uart3_94_95_grp", + .pins = uart3_pins[5], + .npins = ARRAY_SIZE(uart3_pins[5]), + .modemuxs = uart3_modemux[5], + .nmodemuxs = ARRAY_SIZE(uart3_modemux[5]), + }, { + .name = "uart3_98_99_grp", + .pins = uart3_pins[6], + .npins = ARRAY_SIZE(uart3_pins[6]), + .modemuxs = uart3_modemux[6], + .nmodemuxs = ARRAY_SIZE(uart3_modemux[6]), + }, +}; + +static const char *const uart3_grps[] = { "uart3_8_9_grp", "uart3_15_16_grp", + "uart3_41_42_grp", "uart3_52_53_grp", "uart3_73_74_grp", + "uart3_94_95_grp", "uart3_98_99_grp" }; + +static struct spear_function uart3_function = { + .name = "uart3", + .groups = uart3_grps, + .ngroups = ARRAY_SIZE(uart3_grps), +}; + +/* Pad multiplexing for uart4 device */ +static const unsigned uart4_pins[][2] = { { 6, 7 }, { 13, 14 }, { 39, 40 }, + { 71, 72 }, { 92, 93 }, { 100, 101 } }; + +static struct spear_muxreg uart4_ext_6_7_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_SSP_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_0_9_REG, + .mask = PMX_PL_6_7_MASK, + .val = PMX_UART4_PL_6_7_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_UART4_PORT_SEL_MASK, + .val = PMX_UART4_PORT_6_VAL, + }, +}; + +static struct spear_muxreg uart4_ext_13_14_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_MII_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_10_19_REG, + .mask = PMX_PL_13_14_MASK, + .val = PMX_UART4_PL_13_14_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_UART4_PORT_SEL_MASK, + .val = PMX_UART4_PORT_13_VAL, + }, +}; + +static struct spear_muxreg uart4_ext_39_40_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_UART0_MODEM_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_30_39_REG, + .mask = PMX_PL_39_MASK, + .val = PMX_UART4_PL_39_VAL, + }, { + .reg = IP_SEL_PAD_40_49_REG, + .mask = PMX_PL_40_MASK, + .val = PMX_UART4_PL_40_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_UART4_PORT_SEL_MASK, + .val = PMX_UART4_PORT_39_VAL, + }, +}; + +static struct spear_muxreg uart4_ext_71_72_muxreg[] = { + { + .reg = IP_SEL_PAD_70_79_REG, + .mask = PMX_PL_71_72_MASK, + .val = PMX_UART4_PL_71_72_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_UART4_PORT_SEL_MASK, + .val = PMX_UART4_PORT_71_VAL, + }, +}; + +static struct spear_muxreg uart4_ext_92_93_muxreg[] = { + { + .reg = IP_SEL_PAD_90_99_REG, + .mask = PMX_PL_92_93_MASK, + .val = PMX_UART4_PL_92_93_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_UART4_PORT_SEL_MASK, + .val = PMX_UART4_PORT_92_VAL, + }, +}; + +static struct spear_muxreg uart4_ext_100_101_muxreg[] = { + { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_PL_100_101_MASK | + PMX_UART4_PORT_SEL_MASK, + .val = PMX_UART4_PL_100_101_VAL | + PMX_UART4_PORT_101_VAL, + }, +}; + +static struct spear_modemux uart4_modemux[][1] = { + { + /* Select signals on pins 6_7 */ + { + .modes = EXTENDED_MODE, + .muxregs = uart4_ext_6_7_muxreg, + .nmuxregs = ARRAY_SIZE(uart4_ext_6_7_muxreg), + }, + }, { + /* Select signals on pins 13_14 */ + { + .modes = EXTENDED_MODE, + .muxregs = uart4_ext_13_14_muxreg, + .nmuxregs = ARRAY_SIZE(uart4_ext_13_14_muxreg), + }, + }, { + /* Select signals on pins 39_40 */ + { + .modes = EXTENDED_MODE, + .muxregs = uart4_ext_39_40_muxreg, + .nmuxregs = ARRAY_SIZE(uart4_ext_39_40_muxreg), + }, + }, { + /* Select signals on pins 71_72 */ + { + .modes = EXTENDED_MODE, + .muxregs = uart4_ext_71_72_muxreg, + .nmuxregs = ARRAY_SIZE(uart4_ext_71_72_muxreg), + }, + }, { + /* Select signals on pins 92_93 */ + { + .modes = EXTENDED_MODE, + .muxregs = uart4_ext_92_93_muxreg, + .nmuxregs = ARRAY_SIZE(uart4_ext_92_93_muxreg), + }, + }, { + /* Select signals on pins 100_101_ */ + { + .modes = EXTENDED_MODE, + .muxregs = uart4_ext_100_101_muxreg, + .nmuxregs = ARRAY_SIZE(uart4_ext_100_101_muxreg), + }, + }, +}; + +static struct spear_pingroup uart4_pingroup[] = { + { + .name = "uart4_6_7_grp", + .pins = uart4_pins[0], + .npins = ARRAY_SIZE(uart4_pins[0]), + .modemuxs = uart4_modemux[0], + .nmodemuxs = ARRAY_SIZE(uart4_modemux[0]), + }, { + .name = "uart4_13_14_grp", + .pins = uart4_pins[1], + .npins = ARRAY_SIZE(uart4_pins[1]), + .modemuxs = uart4_modemux[1], + .nmodemuxs = ARRAY_SIZE(uart4_modemux[1]), + }, { + .name = "uart4_39_40_grp", + .pins = uart4_pins[2], + .npins = ARRAY_SIZE(uart4_pins[2]), + .modemuxs = uart4_modemux[2], + .nmodemuxs = ARRAY_SIZE(uart4_modemux[2]), + }, { + .name = "uart4_71_72_grp", + .pins = uart4_pins[3], + .npins = ARRAY_SIZE(uart4_pins[3]), + .modemuxs = uart4_modemux[3], + .nmodemuxs = ARRAY_SIZE(uart4_modemux[3]), + }, { + .name = "uart4_92_93_grp", + .pins = uart4_pins[4], + .npins = ARRAY_SIZE(uart4_pins[4]), + .modemuxs = uart4_modemux[4], + .nmodemuxs = ARRAY_SIZE(uart4_modemux[4]), + }, { + .name = "uart4_100_101_grp", + .pins = uart4_pins[5], + .npins = ARRAY_SIZE(uart4_pins[5]), + .modemuxs = uart4_modemux[5], + .nmodemuxs = ARRAY_SIZE(uart4_modemux[5]), + }, +}; + +static const char *const uart4_grps[] = { "uart4_6_7_grp", "uart4_13_14_grp", + "uart4_39_40_grp", "uart4_71_72_grp", "uart4_92_93_grp", + "uart4_100_101_grp" }; + +static struct spear_function uart4_function = { + .name = "uart4", + .groups = uart4_grps, + .ngroups = ARRAY_SIZE(uart4_grps), +}; + +/* Pad multiplexing for uart5 device */ +static const unsigned uart5_pins[][2] = { { 4, 5 }, { 37, 38 }, { 69, 70 }, + { 90, 91 } }; + +static struct spear_muxreg uart5_ext_4_5_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_I2C_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_0_9_REG, + .mask = PMX_PL_4_5_MASK, + .val = PMX_UART5_PL_4_5_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_UART5_PORT_SEL_MASK, + .val = PMX_UART5_PORT_4_VAL, + }, +}; + +static struct spear_muxreg uart5_ext_37_38_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_UART0_MODEM_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_30_39_REG, + .mask = PMX_PL_37_38_MASK, + .val = PMX_UART5_PL_37_38_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_UART5_PORT_SEL_MASK, + .val = PMX_UART5_PORT_37_VAL, + }, +}; + +static struct spear_muxreg uart5_ext_69_70_muxreg[] = { + { + .reg = IP_SEL_PAD_60_69_REG, + .mask = PMX_PL_69_MASK, + .val = PMX_UART5_PL_69_VAL, + }, { + .reg = IP_SEL_PAD_70_79_REG, + .mask = PMX_PL_70_MASK, + .val = PMX_UART5_PL_70_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_UART5_PORT_SEL_MASK, + .val = PMX_UART5_PORT_69_VAL, + }, +}; + +static struct spear_muxreg uart5_ext_90_91_muxreg[] = { + { + .reg = IP_SEL_PAD_90_99_REG, + .mask = PMX_PL_90_91_MASK, + .val = PMX_UART5_PL_90_91_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_UART5_PORT_SEL_MASK, + .val = PMX_UART5_PORT_90_VAL, + }, +}; + +static struct spear_modemux uart5_modemux[][1] = { + { + /* Select signals on pins 4_5 */ + { + .modes = EXTENDED_MODE, + .muxregs = uart5_ext_4_5_muxreg, + .nmuxregs = ARRAY_SIZE(uart5_ext_4_5_muxreg), + }, + }, { + /* Select signals on pins 37_38 */ + { + .modes = EXTENDED_MODE, + .muxregs = uart5_ext_37_38_muxreg, + .nmuxregs = ARRAY_SIZE(uart5_ext_37_38_muxreg), + }, + }, { + /* Select signals on pins 69_70 */ + { + .modes = EXTENDED_MODE, + .muxregs = uart5_ext_69_70_muxreg, + .nmuxregs = ARRAY_SIZE(uart5_ext_69_70_muxreg), + }, + }, { + /* Select signals on pins 90_91 */ + { + .modes = EXTENDED_MODE, + .muxregs = uart5_ext_90_91_muxreg, + .nmuxregs = ARRAY_SIZE(uart5_ext_90_91_muxreg), + }, + }, +}; + +static struct spear_pingroup uart5_pingroup[] = { + { + .name = "uart5_4_5_grp", + .pins = uart5_pins[0], + .npins = ARRAY_SIZE(uart5_pins[0]), + .modemuxs = uart5_modemux[0], + .nmodemuxs = ARRAY_SIZE(uart5_modemux[0]), + }, { + .name = "uart5_37_38_grp", + .pins = uart5_pins[1], + .npins = ARRAY_SIZE(uart5_pins[1]), + .modemuxs = uart5_modemux[1], + .nmodemuxs = ARRAY_SIZE(uart5_modemux[1]), + }, { + .name = "uart5_69_70_grp", + .pins = uart5_pins[2], + .npins = ARRAY_SIZE(uart5_pins[2]), + .modemuxs = uart5_modemux[2], + .nmodemuxs = ARRAY_SIZE(uart5_modemux[2]), + }, { + .name = "uart5_90_91_grp", + .pins = uart5_pins[3], + .npins = ARRAY_SIZE(uart5_pins[3]), + .modemuxs = uart5_modemux[3], + .nmodemuxs = ARRAY_SIZE(uart5_modemux[3]), + }, +}; + +static const char *const uart5_grps[] = { "uart5_4_5_grp", "uart5_37_38_grp", + "uart5_69_70_grp", "uart5_90_91_grp" }; +static struct spear_function uart5_function = { + .name = "uart5", + .groups = uart5_grps, + .ngroups = ARRAY_SIZE(uart5_grps), +}; + +/* Pad multiplexing for uart6 device */ +static const unsigned uart6_pins[][2] = { { 2, 3 }, { 88, 89 } }; +static struct spear_muxreg uart6_ext_2_3_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_UART0_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_0_9_REG, + .mask = PMX_PL_2_3_MASK, + .val = PMX_UART6_PL_2_3_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_UART6_PORT_SEL_MASK, + .val = PMX_UART6_PORT_2_VAL, + }, +}; + +static struct spear_muxreg uart6_ext_88_89_muxreg[] = { + { + .reg = IP_SEL_PAD_80_89_REG, + .mask = PMX_PL_88_89_MASK, + .val = PMX_UART6_PL_88_89_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_UART6_PORT_SEL_MASK, + .val = PMX_UART6_PORT_88_VAL, + }, +}; + +static struct spear_modemux uart6_modemux[][1] = { + { + /* Select signals on pins 2_3 */ + { + .modes = EXTENDED_MODE, + .muxregs = uart6_ext_2_3_muxreg, + .nmuxregs = ARRAY_SIZE(uart6_ext_2_3_muxreg), + }, + }, { + /* Select signals on pins 88_89 */ + { + .modes = EXTENDED_MODE, + .muxregs = uart6_ext_88_89_muxreg, + .nmuxregs = ARRAY_SIZE(uart6_ext_88_89_muxreg), + }, + }, +}; + +static struct spear_pingroup uart6_pingroup[] = { + { + .name = "uart6_2_3_grp", + .pins = uart6_pins[0], + .npins = ARRAY_SIZE(uart6_pins[0]), + .modemuxs = uart6_modemux[0], + .nmodemuxs = ARRAY_SIZE(uart6_modemux[0]), + }, { + .name = "uart6_88_89_grp", + .pins = uart6_pins[1], + .npins = ARRAY_SIZE(uart6_pins[1]), + .modemuxs = uart6_modemux[1], + .nmodemuxs = ARRAY_SIZE(uart6_modemux[1]), + }, +}; + +static const char *const uart6_grps[] = { "uart6_2_3_grp", "uart6_88_89_grp" }; +static struct spear_function uart6_function = { + .name = "uart6", + .groups = uart6_grps, + .ngroups = ARRAY_SIZE(uart6_grps), +}; + +/* UART - RS485 pmx */ +static const unsigned rs485_pins[] = { 77, 78, 79 }; +static struct spear_muxreg rs485_muxreg[] = { + { + .reg = IP_SEL_PAD_70_79_REG, + .mask = PMX_PL_77_78_79_MASK, + .val = PMX_RS485_PL_77_78_79_VAL, + }, +}; + +static struct spear_modemux rs485_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = rs485_muxreg, + .nmuxregs = ARRAY_SIZE(rs485_muxreg), + }, +}; + +static struct spear_pingroup rs485_pingroup = { + .name = "rs485_grp", + .pins = rs485_pins, + .npins = ARRAY_SIZE(rs485_pins), + .modemuxs = rs485_modemux, + .nmodemuxs = ARRAY_SIZE(rs485_modemux), +}; + +static const char *const rs485_grps[] = { "rs485_grp" }; +static struct spear_function rs485_function = { + .name = "rs485", + .groups = rs485_grps, + .ngroups = ARRAY_SIZE(rs485_grps), +}; + +/* Pad multiplexing for Touchscreen device */ +static const unsigned touchscreen_pins[] = { 5, 36 }; +static struct spear_muxreg touchscreen_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_I2C_MASK | PMX_SSP_CS_MASK, + .val = 0, + }, +}; + +static struct spear_muxreg touchscreen_ext_muxreg[] = { + { + .reg = IP_SEL_PAD_0_9_REG, + .mask = PMX_PL_5_MASK, + .val = PMX_TOUCH_Y_PL_5_VAL, + }, { + .reg = IP_SEL_PAD_30_39_REG, + .mask = PMX_PL_36_MASK, + .val = PMX_TOUCH_X_PL_36_VAL, + }, +}; + +static struct spear_modemux touchscreen_modemux[] = { + { + .modes = AUTO_NET_SMII_MODE | EXTENDED_MODE, + .muxregs = touchscreen_muxreg, + .nmuxregs = ARRAY_SIZE(touchscreen_muxreg), + }, { + .modes = EXTENDED_MODE, + .muxregs = touchscreen_ext_muxreg, + .nmuxregs = ARRAY_SIZE(touchscreen_ext_muxreg), + }, +}; + +static struct spear_pingroup touchscreen_pingroup = { + .name = "touchscreen_grp", + .pins = touchscreen_pins, + .npins = ARRAY_SIZE(touchscreen_pins), + .modemuxs = touchscreen_modemux, + .nmodemuxs = ARRAY_SIZE(touchscreen_modemux), +}; + +static const char *const touchscreen_grps[] = { "touchscreen_grp" }; +static struct spear_function touchscreen_function = { + .name = "touchscreen", + .groups = touchscreen_grps, + .ngroups = ARRAY_SIZE(touchscreen_grps), +}; + +/* Pad multiplexing for CAN device */ +static const unsigned can0_pins[] = { 32, 33 }; +static struct spear_muxreg can0_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_GPIO_PIN4_MASK | PMX_GPIO_PIN5_MASK, + .val = 0, + }, +}; + +static struct spear_muxreg can0_ext_muxreg[] = { + { + .reg = IP_SEL_PAD_30_39_REG, + .mask = PMX_PL_32_33_MASK, + .val = PMX_CAN0_PL_32_33_VAL, + }, +}; + +static struct spear_modemux can0_modemux[] = { + { + .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | AUTO_EXP_MODE + | EXTENDED_MODE, + .muxregs = can0_muxreg, + .nmuxregs = ARRAY_SIZE(can0_muxreg), + }, { + .modes = EXTENDED_MODE, + .muxregs = can0_ext_muxreg, + .nmuxregs = ARRAY_SIZE(can0_ext_muxreg), + }, +}; + +static struct spear_pingroup can0_pingroup = { + .name = "can0_grp", + .pins = can0_pins, + .npins = ARRAY_SIZE(can0_pins), + .modemuxs = can0_modemux, + .nmodemuxs = ARRAY_SIZE(can0_modemux), +}; + +static const char *const can0_grps[] = { "can0_grp" }; +static struct spear_function can0_function = { + .name = "can0", + .groups = can0_grps, + .ngroups = ARRAY_SIZE(can0_grps), +}; + +static const unsigned can1_pins[] = { 30, 31 }; +static struct spear_muxreg can1_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_GPIO_PIN2_MASK | PMX_GPIO_PIN3_MASK, + .val = 0, + }, +}; + +static struct spear_muxreg can1_ext_muxreg[] = { + { + .reg = IP_SEL_PAD_30_39_REG, + .mask = PMX_PL_30_31_MASK, + .val = PMX_CAN1_PL_30_31_VAL, + }, +}; + +static struct spear_modemux can1_modemux[] = { + { + .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | AUTO_EXP_MODE + | EXTENDED_MODE, + .muxregs = can1_muxreg, + .nmuxregs = ARRAY_SIZE(can1_muxreg), + }, { + .modes = EXTENDED_MODE, + .muxregs = can1_ext_muxreg, + .nmuxregs = ARRAY_SIZE(can1_ext_muxreg), + }, +}; + +static struct spear_pingroup can1_pingroup = { + .name = "can1_grp", + .pins = can1_pins, + .npins = ARRAY_SIZE(can1_pins), + .modemuxs = can1_modemux, + .nmodemuxs = ARRAY_SIZE(can1_modemux), +}; + +static const char *const can1_grps[] = { "can1_grp" }; +static struct spear_function can1_function = { + .name = "can1", + .groups = can1_grps, + .ngroups = ARRAY_SIZE(can1_grps), +}; + +/* Pad multiplexing for PWM0_1 device */ +static const unsigned pwm0_1_pins[][2] = { { 37, 38 }, { 14, 15 }, { 8, 9 }, + { 30, 31 }, { 42, 43 }, { 59, 60 }, { 88, 89 } }; + +static struct spear_muxreg pwm0_1_pin_8_9_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_SSP_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_0_9_REG, + .mask = PMX_PL_8_9_MASK, + .val = PMX_PWM_0_1_PL_8_9_VAL, + }, +}; + +static struct spear_muxreg pwm0_1_autoexpsmallpri_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_MII_MASK, + .val = 0, + }, +}; + +static struct spear_muxreg pwm0_1_pin_14_15_muxreg[] = { + { + .reg = IP_SEL_PAD_10_19_REG, + .mask = PMX_PL_14_MASK | PMX_PL_15_MASK, + .val = PMX_PWM1_PL_14_VAL | PMX_PWM0_PL_15_VAL, + }, +}; + +static struct spear_muxreg pwm0_1_pin_30_31_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_GPIO_PIN2_MASK | PMX_GPIO_PIN3_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_30_39_REG, + .mask = PMX_PL_30_MASK | PMX_PL_31_MASK, + .val = PMX_PWM1_EXT_PL_30_VAL | PMX_PWM0_EXT_PL_31_VAL, + }, +}; + +static struct spear_muxreg pwm0_1_net_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_UART0_MODEM_MASK, + .val = 0, + }, +}; + +static struct spear_muxreg pwm0_1_pin_37_38_muxreg[] = { + { + .reg = IP_SEL_PAD_30_39_REG, + .mask = PMX_PL_37_38_MASK, + .val = PMX_PWM0_1_PL_37_38_VAL, + }, +}; + +static struct spear_muxreg pwm0_1_pin_42_43_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_UART0_MODEM_MASK | PMX_TIMER_0_1_MASK , + .val = 0, + }, { + .reg = IP_SEL_PAD_40_49_REG, + .mask = PMX_PL_42_MASK | PMX_PL_43_MASK, + .val = PMX_PWM1_PL_42_VAL | + PMX_PWM0_PL_43_VAL, + }, +}; + +static struct spear_muxreg pwm0_1_pin_59_60_muxreg[] = { + { + .reg = IP_SEL_PAD_50_59_REG, + .mask = PMX_PL_59_MASK, + .val = PMX_PWM1_PL_59_VAL, + }, { + .reg = IP_SEL_PAD_60_69_REG, + .mask = PMX_PL_60_MASK, + .val = PMX_PWM0_PL_60_VAL, + }, +}; + +static struct spear_muxreg pwm0_1_pin_88_89_muxreg[] = { + { + .reg = IP_SEL_PAD_80_89_REG, + .mask = PMX_PL_88_89_MASK, + .val = PMX_PWM0_1_PL_88_89_VAL, + }, +}; + +static struct spear_modemux pwm0_1_pin_8_9_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = pwm0_1_pin_8_9_muxreg, + .nmuxregs = ARRAY_SIZE(pwm0_1_pin_8_9_muxreg), + }, +}; + +static struct spear_modemux pwm0_1_pin_14_15_modemux[] = { + { + .modes = AUTO_EXP_MODE | SMALL_PRINTERS_MODE | EXTENDED_MODE, + .muxregs = pwm0_1_autoexpsmallpri_muxreg, + .nmuxregs = ARRAY_SIZE(pwm0_1_autoexpsmallpri_muxreg), + }, { + .modes = EXTENDED_MODE, + .muxregs = pwm0_1_pin_14_15_muxreg, + .nmuxregs = ARRAY_SIZE(pwm0_1_pin_14_15_muxreg), + }, +}; + +static struct spear_modemux pwm0_1_pin_30_31_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = pwm0_1_pin_30_31_muxreg, + .nmuxregs = ARRAY_SIZE(pwm0_1_pin_30_31_muxreg), + }, +}; + +static struct spear_modemux pwm0_1_pin_37_38_modemux[] = { + { + .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | EXTENDED_MODE, + .muxregs = pwm0_1_net_muxreg, + .nmuxregs = ARRAY_SIZE(pwm0_1_net_muxreg), + }, { + .modes = EXTENDED_MODE, + .muxregs = pwm0_1_pin_37_38_muxreg, + .nmuxregs = ARRAY_SIZE(pwm0_1_pin_37_38_muxreg), + }, +}; + +static struct spear_modemux pwm0_1_pin_42_43_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = pwm0_1_pin_42_43_muxreg, + .nmuxregs = ARRAY_SIZE(pwm0_1_pin_42_43_muxreg), + }, +}; + +static struct spear_modemux pwm0_1_pin_59_60_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = pwm0_1_pin_59_60_muxreg, + .nmuxregs = ARRAY_SIZE(pwm0_1_pin_59_60_muxreg), + }, +}; + +static struct spear_modemux pwm0_1_pin_88_89_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = pwm0_1_pin_88_89_muxreg, + .nmuxregs = ARRAY_SIZE(pwm0_1_pin_88_89_muxreg), + }, +}; + +static struct spear_pingroup pwm0_1_pingroup[] = { + { + .name = "pwm0_1_pin_8_9_grp", + .pins = pwm0_1_pins[0], + .npins = ARRAY_SIZE(pwm0_1_pins[0]), + .modemuxs = pwm0_1_pin_8_9_modemux, + .nmodemuxs = ARRAY_SIZE(pwm0_1_pin_8_9_modemux), + }, { + .name = "pwm0_1_pin_14_15_grp", + .pins = pwm0_1_pins[1], + .npins = ARRAY_SIZE(pwm0_1_pins[1]), + .modemuxs = pwm0_1_pin_14_15_modemux, + .nmodemuxs = ARRAY_SIZE(pwm0_1_pin_14_15_modemux), + }, { + .name = "pwm0_1_pin_30_31_grp", + .pins = pwm0_1_pins[2], + .npins = ARRAY_SIZE(pwm0_1_pins[2]), + .modemuxs = pwm0_1_pin_30_31_modemux, + .nmodemuxs = ARRAY_SIZE(pwm0_1_pin_30_31_modemux), + }, { + .name = "pwm0_1_pin_37_38_grp", + .pins = pwm0_1_pins[3], + .npins = ARRAY_SIZE(pwm0_1_pins[3]), + .modemuxs = pwm0_1_pin_37_38_modemux, + .nmodemuxs = ARRAY_SIZE(pwm0_1_pin_37_38_modemux), + }, { + .name = "pwm0_1_pin_42_43_grp", + .pins = pwm0_1_pins[4], + .npins = ARRAY_SIZE(pwm0_1_pins[4]), + .modemuxs = pwm0_1_pin_42_43_modemux, + .nmodemuxs = ARRAY_SIZE(pwm0_1_pin_42_43_modemux), + }, { + .name = "pwm0_1_pin_59_60_grp", + .pins = pwm0_1_pins[5], + .npins = ARRAY_SIZE(pwm0_1_pins[5]), + .modemuxs = pwm0_1_pin_59_60_modemux, + .nmodemuxs = ARRAY_SIZE(pwm0_1_pin_59_60_modemux), + }, { + .name = "pwm0_1_pin_88_89_grp", + .pins = pwm0_1_pins[6], + .npins = ARRAY_SIZE(pwm0_1_pins[6]), + .modemuxs = pwm0_1_pin_88_89_modemux, + .nmodemuxs = ARRAY_SIZE(pwm0_1_pin_88_89_modemux), + }, +}; + +static const char *const pwm0_1_grps[] = { "pwm0_1_pin_8_9_grp", + "pwm0_1_pin_14_15_grp", "pwm0_1_pin_30_31_grp", "pwm0_1_pin_37_38_grp", + "pwm0_1_pin_42_43_grp", "pwm0_1_pin_59_60_grp", "pwm0_1_pin_88_89_grp" +}; + +static struct spear_function pwm0_1_function = { + .name = "pwm0_1", + .groups = pwm0_1_grps, + .ngroups = ARRAY_SIZE(pwm0_1_grps), +}; + +/* Pad multiplexing for PWM2 device */ +static const unsigned pwm2_pins[][1] = { { 7 }, { 13 }, { 29 }, { 34 }, { 41 }, + { 58 }, { 87 } }; +static struct spear_muxreg pwm2_net_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_SSP_CS_MASK, + .val = 0, + }, +}; + +static struct spear_muxreg pwm2_pin_7_muxreg[] = { + { + .reg = IP_SEL_PAD_0_9_REG, + .mask = PMX_PL_7_MASK, + .val = PMX_PWM_2_PL_7_VAL, + }, +}; + +static struct spear_muxreg pwm2_autoexpsmallpri_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_MII_MASK, + .val = 0, + }, +}; + +static struct spear_muxreg pwm2_pin_13_muxreg[] = { + { + .reg = IP_SEL_PAD_10_19_REG, + .mask = PMX_PL_13_MASK, + .val = PMX_PWM2_PL_13_VAL, + }, +}; + +static struct spear_muxreg pwm2_pin_29_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_GPIO_PIN1_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_20_29_REG, + .mask = PMX_PL_29_MASK, + .val = PMX_PWM_2_PL_29_VAL, + }, +}; + +static struct spear_muxreg pwm2_pin_34_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_SSP_CS_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_30_39_REG, + .mask = PMX_PL_34_MASK, + .val = PMX_PWM2_PL_34_VAL, + }, +}; + +static struct spear_muxreg pwm2_pin_41_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_UART0_MODEM_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_40_49_REG, + .mask = PMX_PL_41_MASK, + .val = PMX_PWM2_PL_41_VAL, + }, +}; + +static struct spear_muxreg pwm2_pin_58_muxreg[] = { + { + .reg = IP_SEL_PAD_50_59_REG, + .mask = PMX_PL_58_MASK, + .val = PMX_PWM2_PL_58_VAL, + }, +}; + +static struct spear_muxreg pwm2_pin_87_muxreg[] = { + { + .reg = IP_SEL_PAD_80_89_REG, + .mask = PMX_PL_87_MASK, + .val = PMX_PWM2_PL_87_VAL, + }, +}; + +static struct spear_modemux pwm2_pin_7_modemux[] = { + { + .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | EXTENDED_MODE, + .muxregs = pwm2_net_muxreg, + .nmuxregs = ARRAY_SIZE(pwm2_net_muxreg), + }, { + .modes = EXTENDED_MODE, + .muxregs = pwm2_pin_7_muxreg, + .nmuxregs = ARRAY_SIZE(pwm2_pin_7_muxreg), + }, +}; +static struct spear_modemux pwm2_pin_13_modemux[] = { + { + .modes = AUTO_EXP_MODE | SMALL_PRINTERS_MODE | EXTENDED_MODE, + .muxregs = pwm2_autoexpsmallpri_muxreg, + .nmuxregs = ARRAY_SIZE(pwm2_autoexpsmallpri_muxreg), + }, { + .modes = EXTENDED_MODE, + .muxregs = pwm2_pin_13_muxreg, + .nmuxregs = ARRAY_SIZE(pwm2_pin_13_muxreg), + }, +}; +static struct spear_modemux pwm2_pin_29_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = pwm2_pin_29_muxreg, + .nmuxregs = ARRAY_SIZE(pwm2_pin_29_muxreg), + }, +}; +static struct spear_modemux pwm2_pin_34_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = pwm2_pin_34_muxreg, + .nmuxregs = ARRAY_SIZE(pwm2_pin_34_muxreg), + }, +}; + +static struct spear_modemux pwm2_pin_41_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = pwm2_pin_41_muxreg, + .nmuxregs = ARRAY_SIZE(pwm2_pin_41_muxreg), + }, +}; + +static struct spear_modemux pwm2_pin_58_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = pwm2_pin_58_muxreg, + .nmuxregs = ARRAY_SIZE(pwm2_pin_58_muxreg), + }, +}; + +static struct spear_modemux pwm2_pin_87_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = pwm2_pin_87_muxreg, + .nmuxregs = ARRAY_SIZE(pwm2_pin_87_muxreg), + }, +}; + +static struct spear_pingroup pwm2_pingroup[] = { + { + .name = "pwm2_pin_7_grp", + .pins = pwm2_pins[0], + .npins = ARRAY_SIZE(pwm2_pins[0]), + .modemuxs = pwm2_pin_7_modemux, + .nmodemuxs = ARRAY_SIZE(pwm2_pin_7_modemux), + }, { + .name = "pwm2_pin_13_grp", + .pins = pwm2_pins[1], + .npins = ARRAY_SIZE(pwm2_pins[1]), + .modemuxs = pwm2_pin_13_modemux, + .nmodemuxs = ARRAY_SIZE(pwm2_pin_13_modemux), + }, { + .name = "pwm2_pin_29_grp", + .pins = pwm2_pins[2], + .npins = ARRAY_SIZE(pwm2_pins[2]), + .modemuxs = pwm2_pin_29_modemux, + .nmodemuxs = ARRAY_SIZE(pwm2_pin_29_modemux), + }, { + .name = "pwm2_pin_34_grp", + .pins = pwm2_pins[3], + .npins = ARRAY_SIZE(pwm2_pins[3]), + .modemuxs = pwm2_pin_34_modemux, + .nmodemuxs = ARRAY_SIZE(pwm2_pin_34_modemux), + }, { + .name = "pwm2_pin_41_grp", + .pins = pwm2_pins[4], + .npins = ARRAY_SIZE(pwm2_pins[4]), + .modemuxs = pwm2_pin_41_modemux, + .nmodemuxs = ARRAY_SIZE(pwm2_pin_41_modemux), + }, { + .name = "pwm2_pin_58_grp", + .pins = pwm2_pins[5], + .npins = ARRAY_SIZE(pwm2_pins[5]), + .modemuxs = pwm2_pin_58_modemux, + .nmodemuxs = ARRAY_SIZE(pwm2_pin_58_modemux), + }, { + .name = "pwm2_pin_87_grp", + .pins = pwm2_pins[6], + .npins = ARRAY_SIZE(pwm2_pins[6]), + .modemuxs = pwm2_pin_87_modemux, + .nmodemuxs = ARRAY_SIZE(pwm2_pin_87_modemux), + }, +}; + +static const char *const pwm2_grps[] = { "pwm2_pin_7_grp", "pwm2_pin_13_grp", + "pwm2_pin_29_grp", "pwm2_pin_34_grp", "pwm2_pin_41_grp", + "pwm2_pin_58_grp", "pwm2_pin_87_grp" }; +static struct spear_function pwm2_function = { + .name = "pwm2", + .groups = pwm2_grps, + .ngroups = ARRAY_SIZE(pwm2_grps), +}; + +/* Pad multiplexing for PWM3 device */ +static const unsigned pwm3_pins[][1] = { { 6 }, { 12 }, { 28 }, { 40 }, { 57 }, + { 86 } }; +static struct spear_muxreg pwm3_pin_6_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_SSP_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_0_9_REG, + .mask = PMX_PL_6_MASK, + .val = PMX_PWM_3_PL_6_VAL, + }, +}; + +static struct spear_muxreg pwm3_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_MII_MASK, + .val = 0, + }, +}; + +static struct spear_muxreg pwm3_pin_12_muxreg[] = { + { + .reg = IP_SEL_PAD_10_19_REG, + .mask = PMX_PL_12_MASK, + .val = PMX_PWM3_PL_12_VAL, + }, +}; + +static struct spear_muxreg pwm3_pin_28_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_GPIO_PIN0_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_20_29_REG, + .mask = PMX_PL_28_MASK, + .val = PMX_PWM_3_PL_28_VAL, + }, +}; + +static struct spear_muxreg pwm3_pin_40_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_UART0_MODEM_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_40_49_REG, + .mask = PMX_PL_40_MASK, + .val = PMX_PWM3_PL_40_VAL, + }, +}; + +static struct spear_muxreg pwm3_pin_57_muxreg[] = { + { + .reg = IP_SEL_PAD_50_59_REG, + .mask = PMX_PL_57_MASK, + .val = PMX_PWM3_PL_57_VAL, + }, +}; + +static struct spear_muxreg pwm3_pin_86_muxreg[] = { + { + .reg = IP_SEL_PAD_80_89_REG, + .mask = PMX_PL_86_MASK, + .val = PMX_PWM3_PL_86_VAL, + }, +}; + +static struct spear_modemux pwm3_pin_6_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = pwm3_pin_6_muxreg, + .nmuxregs = ARRAY_SIZE(pwm3_pin_6_muxreg), + }, +}; + +static struct spear_modemux pwm3_pin_12_modemux[] = { + { + .modes = AUTO_EXP_MODE | SMALL_PRINTERS_MODE | + AUTO_NET_SMII_MODE | EXTENDED_MODE, + .muxregs = pwm3_muxreg, + .nmuxregs = ARRAY_SIZE(pwm3_muxreg), + }, { + .modes = EXTENDED_MODE, + .muxregs = pwm3_pin_12_muxreg, + .nmuxregs = ARRAY_SIZE(pwm3_pin_12_muxreg), + }, +}; + +static struct spear_modemux pwm3_pin_28_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = pwm3_pin_28_muxreg, + .nmuxregs = ARRAY_SIZE(pwm3_pin_28_muxreg), + }, +}; + +static struct spear_modemux pwm3_pin_40_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = pwm3_pin_40_muxreg, + .nmuxregs = ARRAY_SIZE(pwm3_pin_40_muxreg), + }, +}; + +static struct spear_modemux pwm3_pin_57_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = pwm3_pin_57_muxreg, + .nmuxregs = ARRAY_SIZE(pwm3_pin_57_muxreg), + }, +}; + +static struct spear_modemux pwm3_pin_86_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = pwm3_pin_86_muxreg, + .nmuxregs = ARRAY_SIZE(pwm3_pin_86_muxreg), + }, +}; + +static struct spear_pingroup pwm3_pingroup[] = { + { + .name = "pwm3_pin_6_grp", + .pins = pwm3_pins[0], + .npins = ARRAY_SIZE(pwm3_pins[0]), + .modemuxs = pwm3_pin_6_modemux, + .nmodemuxs = ARRAY_SIZE(pwm3_pin_6_modemux), + }, { + .name = "pwm3_pin_12_grp", + .pins = pwm3_pins[1], + .npins = ARRAY_SIZE(pwm3_pins[1]), + .modemuxs = pwm3_pin_12_modemux, + .nmodemuxs = ARRAY_SIZE(pwm3_pin_12_modemux), + }, { + .name = "pwm3_pin_28_grp", + .pins = pwm3_pins[2], + .npins = ARRAY_SIZE(pwm3_pins[2]), + .modemuxs = pwm3_pin_28_modemux, + .nmodemuxs = ARRAY_SIZE(pwm3_pin_28_modemux), + }, { + .name = "pwm3_pin_40_grp", + .pins = pwm3_pins[3], + .npins = ARRAY_SIZE(pwm3_pins[3]), + .modemuxs = pwm3_pin_40_modemux, + .nmodemuxs = ARRAY_SIZE(pwm3_pin_40_modemux), + }, { + .name = "pwm3_pin_57_grp", + .pins = pwm3_pins[4], + .npins = ARRAY_SIZE(pwm3_pins[4]), + .modemuxs = pwm3_pin_57_modemux, + .nmodemuxs = ARRAY_SIZE(pwm3_pin_57_modemux), + }, { + .name = "pwm3_pin_86_grp", + .pins = pwm3_pins[5], + .npins = ARRAY_SIZE(pwm3_pins[5]), + .modemuxs = pwm3_pin_86_modemux, + .nmodemuxs = ARRAY_SIZE(pwm3_pin_86_modemux), + }, +}; + +static const char *const pwm3_grps[] = { "pwm3_pin_6_grp", "pwm3_pin_12_grp", + "pwm3_pin_28_grp", "pwm3_pin_40_grp", "pwm3_pin_57_grp", + "pwm3_pin_86_grp" }; +static struct spear_function pwm3_function = { + .name = "pwm3", + .groups = pwm3_grps, + .ngroups = ARRAY_SIZE(pwm3_grps), +}; + +/* Pad multiplexing for SSP1 device */ +static const unsigned ssp1_pins[][2] = { { 17, 20 }, { 36, 39 }, { 48, 51 }, + { 65, 68 }, { 94, 97 } }; +static struct spear_muxreg ssp1_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_MII_MASK, + .val = 0, + }, +}; + +static struct spear_muxreg ssp1_ext_17_20_muxreg[] = { + { + .reg = IP_SEL_PAD_10_19_REG, + .mask = PMX_PL_17_18_MASK | PMX_PL_19_MASK, + .val = PMX_SSP1_PL_17_18_19_20_VAL, + }, { + .reg = IP_SEL_PAD_20_29_REG, + .mask = PMX_PL_20_MASK, + .val = PMX_SSP1_PL_17_18_19_20_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_SSP1_PORT_SEL_MASK, + .val = PMX_SSP1_PORT_17_TO_20_VAL, + }, +}; + +static struct spear_muxreg ssp1_ext_36_39_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_UART0_MODEM_MASK | PMX_SSP_CS_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_30_39_REG, + .mask = PMX_PL_36_MASK | PMX_PL_37_38_MASK | PMX_PL_39_MASK, + .val = PMX_SSP1_PL_36_VAL | PMX_SSP1_PL_37_38_VAL | + PMX_SSP1_PL_39_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_SSP1_PORT_SEL_MASK, + .val = PMX_SSP1_PORT_36_TO_39_VAL, + }, +}; + +static struct spear_muxreg ssp1_ext_48_51_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_40_49_REG, + .mask = PMX_PL_48_49_MASK, + .val = PMX_SSP1_PL_48_49_VAL, + }, { + .reg = IP_SEL_PAD_50_59_REG, + .mask = PMX_PL_50_51_MASK, + .val = PMX_SSP1_PL_50_51_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_SSP1_PORT_SEL_MASK, + .val = PMX_SSP1_PORT_48_TO_51_VAL, + }, +}; + +static struct spear_muxreg ssp1_ext_65_68_muxreg[] = { + { + .reg = IP_SEL_PAD_60_69_REG, + .mask = PMX_PL_65_TO_68_MASK, + .val = PMX_SSP1_PL_65_TO_68_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_SSP1_PORT_SEL_MASK, + .val = PMX_SSP1_PORT_65_TO_68_VAL, + }, +}; + +static struct spear_muxreg ssp1_ext_94_97_muxreg[] = { + { + .reg = IP_SEL_PAD_90_99_REG, + .mask = PMX_PL_94_95_MASK | PMX_PL_96_97_MASK, + .val = PMX_SSP1_PL_94_95_VAL | PMX_SSP1_PL_96_97_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_SSP1_PORT_SEL_MASK, + .val = PMX_SSP1_PORT_94_TO_97_VAL, + }, +}; + +static struct spear_modemux ssp1_17_20_modemux[] = { + { + .modes = SMALL_PRINTERS_MODE | AUTO_NET_SMII_MODE | + EXTENDED_MODE, + .muxregs = ssp1_muxreg, + .nmuxregs = ARRAY_SIZE(ssp1_muxreg), + }, { + .modes = EXTENDED_MODE, + .muxregs = ssp1_ext_17_20_muxreg, + .nmuxregs = ARRAY_SIZE(ssp1_ext_17_20_muxreg), + }, +}; + +static struct spear_modemux ssp1_36_39_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = ssp1_ext_36_39_muxreg, + .nmuxregs = ARRAY_SIZE(ssp1_ext_36_39_muxreg), + }, +}; + +static struct spear_modemux ssp1_48_51_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = ssp1_ext_48_51_muxreg, + .nmuxregs = ARRAY_SIZE(ssp1_ext_48_51_muxreg), + }, +}; +static struct spear_modemux ssp1_65_68_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = ssp1_ext_65_68_muxreg, + .nmuxregs = ARRAY_SIZE(ssp1_ext_65_68_muxreg), + }, +}; + +static struct spear_modemux ssp1_94_97_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = ssp1_ext_94_97_muxreg, + .nmuxregs = ARRAY_SIZE(ssp1_ext_94_97_muxreg), + }, +}; + +static struct spear_pingroup ssp1_pingroup[] = { + { + .name = "ssp1_17_20_grp", + .pins = ssp1_pins[0], + .npins = ARRAY_SIZE(ssp1_pins[0]), + .modemuxs = ssp1_17_20_modemux, + .nmodemuxs = ARRAY_SIZE(ssp1_17_20_modemux), + }, { + .name = "ssp1_36_39_grp", + .pins = ssp1_pins[1], + .npins = ARRAY_SIZE(ssp1_pins[1]), + .modemuxs = ssp1_36_39_modemux, + .nmodemuxs = ARRAY_SIZE(ssp1_36_39_modemux), + }, { + .name = "ssp1_48_51_grp", + .pins = ssp1_pins[2], + .npins = ARRAY_SIZE(ssp1_pins[2]), + .modemuxs = ssp1_48_51_modemux, + .nmodemuxs = ARRAY_SIZE(ssp1_48_51_modemux), + }, { + .name = "ssp1_65_68_grp", + .pins = ssp1_pins[3], + .npins = ARRAY_SIZE(ssp1_pins[3]), + .modemuxs = ssp1_65_68_modemux, + .nmodemuxs = ARRAY_SIZE(ssp1_65_68_modemux), + }, { + .name = "ssp1_94_97_grp", + .pins = ssp1_pins[4], + .npins = ARRAY_SIZE(ssp1_pins[4]), + .modemuxs = ssp1_94_97_modemux, + .nmodemuxs = ARRAY_SIZE(ssp1_94_97_modemux), + }, +}; + +static const char *const ssp1_grps[] = { "ssp1_17_20_grp", "ssp1_36_39_grp", + "ssp1_48_51_grp", "ssp1_65_68_grp", "ssp1_94_97_grp" +}; +static struct spear_function ssp1_function = { + .name = "ssp1", + .groups = ssp1_grps, + .ngroups = ARRAY_SIZE(ssp1_grps), +}; + +/* Pad multiplexing for SSP2 device */ +static const unsigned ssp2_pins[][2] = { { 13, 16 }, { 32, 35 }, { 44, 47 }, + { 61, 64 }, { 90, 93 } }; +static struct spear_muxreg ssp2_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_MII_MASK, + .val = 0, + }, +}; + +static struct spear_muxreg ssp2_ext_13_16_muxreg[] = { + { + .reg = IP_SEL_PAD_10_19_REG, + .mask = PMX_PL_13_14_MASK | PMX_PL_15_16_MASK, + .val = PMX_SSP2_PL_13_14_15_16_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_SSP2_PORT_SEL_MASK, + .val = PMX_SSP2_PORT_13_TO_16_VAL, + }, +}; + +static struct spear_muxreg ssp2_ext_32_35_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_SSP_CS_MASK | PMX_GPIO_PIN4_MASK | + PMX_GPIO_PIN5_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_30_39_REG, + .mask = PMX_PL_32_33_MASK | PMX_PL_34_MASK | PMX_PL_35_MASK, + .val = PMX_SSP2_PL_32_33_VAL | PMX_SSP2_PL_34_VAL | + PMX_SSP2_PL_35_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_SSP2_PORT_SEL_MASK, + .val = PMX_SSP2_PORT_32_TO_35_VAL, + }, +}; + +static struct spear_muxreg ssp2_ext_44_47_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_40_49_REG, + .mask = PMX_PL_44_45_MASK | PMX_PL_46_47_MASK, + .val = PMX_SSP2_PL_44_45_VAL | PMX_SSP2_PL_46_47_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_SSP2_PORT_SEL_MASK, + .val = PMX_SSP2_PORT_44_TO_47_VAL, + }, +}; + +static struct spear_muxreg ssp2_ext_61_64_muxreg[] = { + { + .reg = IP_SEL_PAD_60_69_REG, + .mask = PMX_PL_61_TO_64_MASK, + .val = PMX_SSP2_PL_61_TO_64_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_SSP2_PORT_SEL_MASK, + .val = PMX_SSP2_PORT_61_TO_64_VAL, + }, +}; + +static struct spear_muxreg ssp2_ext_90_93_muxreg[] = { + { + .reg = IP_SEL_PAD_90_99_REG, + .mask = PMX_PL_90_91_MASK | PMX_PL_92_93_MASK, + .val = PMX_SSP2_PL_90_91_VAL | PMX_SSP2_PL_92_93_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_SSP2_PORT_SEL_MASK, + .val = PMX_SSP2_PORT_90_TO_93_VAL, + }, +}; + +static struct spear_modemux ssp2_13_16_modemux[] = { + { + .modes = AUTO_NET_SMII_MODE | EXTENDED_MODE, + .muxregs = ssp2_muxreg, + .nmuxregs = ARRAY_SIZE(ssp2_muxreg), + }, { + .modes = EXTENDED_MODE, + .muxregs = ssp2_ext_13_16_muxreg, + .nmuxregs = ARRAY_SIZE(ssp2_ext_13_16_muxreg), + }, +}; + +static struct spear_modemux ssp2_32_35_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = ssp2_ext_32_35_muxreg, + .nmuxregs = ARRAY_SIZE(ssp2_ext_32_35_muxreg), + }, +}; + +static struct spear_modemux ssp2_44_47_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = ssp2_ext_44_47_muxreg, + .nmuxregs = ARRAY_SIZE(ssp2_ext_44_47_muxreg), + }, +}; + +static struct spear_modemux ssp2_61_64_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = ssp2_ext_61_64_muxreg, + .nmuxregs = ARRAY_SIZE(ssp2_ext_61_64_muxreg), + }, +}; + +static struct spear_modemux ssp2_90_93_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = ssp2_ext_90_93_muxreg, + .nmuxregs = ARRAY_SIZE(ssp2_ext_90_93_muxreg), + }, +}; + +static struct spear_pingroup ssp2_pingroup[] = { + { + .name = "ssp2_13_16_grp", + .pins = ssp2_pins[0], + .npins = ARRAY_SIZE(ssp2_pins[0]), + .modemuxs = ssp2_13_16_modemux, + .nmodemuxs = ARRAY_SIZE(ssp2_13_16_modemux), + }, { + .name = "ssp2_32_35_grp", + .pins = ssp2_pins[1], + .npins = ARRAY_SIZE(ssp2_pins[1]), + .modemuxs = ssp2_32_35_modemux, + .nmodemuxs = ARRAY_SIZE(ssp2_32_35_modemux), + }, { + .name = "ssp2_44_47_grp", + .pins = ssp2_pins[2], + .npins = ARRAY_SIZE(ssp2_pins[2]), + .modemuxs = ssp2_44_47_modemux, + .nmodemuxs = ARRAY_SIZE(ssp2_44_47_modemux), + }, { + .name = "ssp2_61_64_grp", + .pins = ssp2_pins[3], + .npins = ARRAY_SIZE(ssp2_pins[3]), + .modemuxs = ssp2_61_64_modemux, + .nmodemuxs = ARRAY_SIZE(ssp2_61_64_modemux), + }, { + .name = "ssp2_90_93_grp", + .pins = ssp2_pins[4], + .npins = ARRAY_SIZE(ssp2_pins[4]), + .modemuxs = ssp2_90_93_modemux, + .nmodemuxs = ARRAY_SIZE(ssp2_90_93_modemux), + }, +}; + +static const char *const ssp2_grps[] = { "ssp2_13_16_grp", "ssp2_32_35_grp", + "ssp2_44_47_grp", "ssp2_61_64_grp", "ssp2_90_93_grp" }; +static struct spear_function ssp2_function = { + .name = "ssp2", + .groups = ssp2_grps, + .ngroups = ARRAY_SIZE(ssp2_grps), +}; + +/* Pad multiplexing for cadence mii2 as mii device */ +static const unsigned mii2_pins[] = { 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97 }; +static struct spear_muxreg mii2_muxreg[] = { + { + .reg = IP_SEL_PAD_80_89_REG, + .mask = PMX_PL_80_TO_85_MASK | PMX_PL_86_87_MASK | + PMX_PL_88_89_MASK, + .val = PMX_MII2_PL_80_TO_85_VAL | PMX_MII2_PL_86_87_VAL | + PMX_MII2_PL_88_89_VAL, + }, { + .reg = IP_SEL_PAD_90_99_REG, + .mask = PMX_PL_90_91_MASK | PMX_PL_92_93_MASK | + PMX_PL_94_95_MASK | PMX_PL_96_97_MASK, + .val = PMX_MII2_PL_90_91_VAL | PMX_MII2_PL_92_93_VAL | + PMX_MII2_PL_94_95_VAL | PMX_MII2_PL_96_97_VAL, + }, { + .reg = EXT_CTRL_REG, + .mask = (MAC_MODE_MASK << MAC2_MODE_SHIFT) | + (MAC_MODE_MASK << MAC1_MODE_SHIFT) | + MII_MDIO_MASK, + .val = (MAC_MODE_MII << MAC2_MODE_SHIFT) | + (MAC_MODE_MII << MAC1_MODE_SHIFT) | + MII_MDIO_81_VAL, + }, +}; + +static struct spear_modemux mii2_modemux[] = { + { + .modes = EXTENDED_MODE, + .muxregs = mii2_muxreg, + .nmuxregs = ARRAY_SIZE(mii2_muxreg), + }, +}; + +static struct spear_pingroup mii2_pingroup = { + .name = "mii2_grp", + .pins = mii2_pins, + .npins = ARRAY_SIZE(mii2_pins), + .modemuxs = mii2_modemux, + .nmodemuxs = ARRAY_SIZE(mii2_modemux), +}; + +static const char *const mii2_grps[] = { "mii2_grp" }; +static struct spear_function mii2_function = { + .name = "mii2", + .groups = mii2_grps, + .ngroups = ARRAY_SIZE(mii2_grps), +}; + +/* Pad multiplexing for cadence mii 1_2 as smii or rmii device */ +static const unsigned smii0_1_pins[] = { 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27 }; +static const unsigned rmii0_1_pins[] = { 10, 11, 21, 22, 23, 24, 25, 26, 27 }; +static struct spear_muxreg mii0_1_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_MII_MASK, + .val = 0, + }, +}; + +static struct spear_muxreg smii0_1_ext_muxreg[] = { + { + .reg = IP_SEL_PAD_10_19_REG, + .mask = PMX_PL_10_11_MASK, + .val = PMX_SMII_PL_10_11_VAL, + }, { + .reg = IP_SEL_PAD_20_29_REG, + .mask = PMX_PL_21_TO_27_MASK, + .val = PMX_SMII_PL_21_TO_27_VAL, + }, { + .reg = EXT_CTRL_REG, + .mask = (MAC_MODE_MASK << MAC2_MODE_SHIFT) | + (MAC_MODE_MASK << MAC1_MODE_SHIFT) | + MII_MDIO_MASK, + .val = (MAC_MODE_SMII << MAC2_MODE_SHIFT) + | (MAC_MODE_SMII << MAC1_MODE_SHIFT) + | MII_MDIO_10_11_VAL, + }, +}; + +static struct spear_muxreg rmii0_1_ext_muxreg[] = { + { + .reg = IP_SEL_PAD_10_19_REG, + .mask = PMX_PL_10_11_MASK | PMX_PL_13_14_MASK | + PMX_PL_15_16_MASK | PMX_PL_17_18_MASK | PMX_PL_19_MASK, + .val = PMX_RMII_PL_10_11_VAL | PMX_RMII_PL_13_14_VAL | + PMX_RMII_PL_15_16_VAL | PMX_RMII_PL_17_18_VAL | + PMX_RMII_PL_19_VAL, + }, { + .reg = IP_SEL_PAD_20_29_REG, + .mask = PMX_PL_20_MASK | PMX_PL_21_TO_27_MASK, + .val = PMX_RMII_PL_20_VAL | PMX_RMII_PL_21_TO_27_VAL, + }, { + .reg = EXT_CTRL_REG, + .mask = (MAC_MODE_MASK << MAC2_MODE_SHIFT) | + (MAC_MODE_MASK << MAC1_MODE_SHIFT) | + MII_MDIO_MASK, + .val = (MAC_MODE_RMII << MAC2_MODE_SHIFT) + | (MAC_MODE_RMII << MAC1_MODE_SHIFT) + | MII_MDIO_10_11_VAL, + }, +}; + +static struct spear_modemux mii0_1_modemux[][2] = { + { + /* configure as smii */ + { + .modes = AUTO_NET_SMII_MODE | AUTO_EXP_MODE | + SMALL_PRINTERS_MODE | EXTENDED_MODE, + .muxregs = mii0_1_muxreg, + .nmuxregs = ARRAY_SIZE(mii0_1_muxreg), + }, { + .modes = EXTENDED_MODE, + .muxregs = smii0_1_ext_muxreg, + .nmuxregs = ARRAY_SIZE(smii0_1_ext_muxreg), + }, + }, { + /* configure as rmii */ + { + .modes = AUTO_NET_SMII_MODE | AUTO_EXP_MODE | + SMALL_PRINTERS_MODE | EXTENDED_MODE, + .muxregs = mii0_1_muxreg, + .nmuxregs = ARRAY_SIZE(mii0_1_muxreg), + }, { + .modes = EXTENDED_MODE, + .muxregs = rmii0_1_ext_muxreg, + .nmuxregs = ARRAY_SIZE(rmii0_1_ext_muxreg), + }, + }, +}; + +static struct spear_pingroup mii0_1_pingroup[] = { + { + .name = "smii0_1_grp", + .pins = smii0_1_pins, + .npins = ARRAY_SIZE(smii0_1_pins), + .modemuxs = mii0_1_modemux[0], + .nmodemuxs = ARRAY_SIZE(mii0_1_modemux[0]), + }, { + .name = "rmii0_1_grp", + .pins = rmii0_1_pins, + .npins = ARRAY_SIZE(rmii0_1_pins), + .modemuxs = mii0_1_modemux[1], + .nmodemuxs = ARRAY_SIZE(mii0_1_modemux[1]), + }, +}; + +static const char *const mii0_1_grps[] = { "smii0_1_grp", "rmii0_1_grp" }; +static struct spear_function mii0_1_function = { + .name = "mii0_1", + .groups = mii0_1_grps, + .ngroups = ARRAY_SIZE(mii0_1_grps), +}; + +/* Pad multiplexing for i2c1 device */ +static const unsigned i2c1_pins[][2] = { { 8, 9 }, { 98, 99 } }; +static struct spear_muxreg i2c1_ext_8_9_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_SSP_CS_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_0_9_REG, + .mask = PMX_PL_8_9_MASK, + .val = PMX_I2C1_PL_8_9_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_I2C1_PORT_SEL_MASK, + .val = PMX_I2C1_PORT_8_9_VAL, + }, +}; + +static struct spear_muxreg i2c1_ext_98_99_muxreg[] = { + { + .reg = IP_SEL_PAD_90_99_REG, + .mask = PMX_PL_98_MASK | PMX_PL_99_MASK, + .val = PMX_I2C1_PL_98_VAL | PMX_I2C1_PL_99_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_I2C1_PORT_SEL_MASK, + .val = PMX_I2C1_PORT_98_99_VAL, + }, +}; + +static struct spear_modemux i2c1_modemux[][1] = { + { + /* Select signals on pins 8-9 */ + { + .modes = EXTENDED_MODE, + .muxregs = i2c1_ext_8_9_muxreg, + .nmuxregs = ARRAY_SIZE(i2c1_ext_8_9_muxreg), + }, + }, { + /* Select signals on pins 98-99 */ + { + .modes = EXTENDED_MODE, + .muxregs = i2c1_ext_98_99_muxreg, + .nmuxregs = ARRAY_SIZE(i2c1_ext_98_99_muxreg), + }, + }, +}; + +static struct spear_pingroup i2c1_pingroup[] = { + { + .name = "i2c1_8_9_grp", + .pins = i2c1_pins[0], + .npins = ARRAY_SIZE(i2c1_pins[0]), + .modemuxs = i2c1_modemux[0], + .nmodemuxs = ARRAY_SIZE(i2c1_modemux[0]), + }, { + .name = "i2c1_98_99_grp", + .pins = i2c1_pins[1], + .npins = ARRAY_SIZE(i2c1_pins[1]), + .modemuxs = i2c1_modemux[1], + .nmodemuxs = ARRAY_SIZE(i2c1_modemux[1]), + }, +}; + +static const char *const i2c1_grps[] = { "i2c1_8_9_grp", "i2c1_98_99_grp" }; +static struct spear_function i2c1_function = { + .name = "i2c1", + .groups = i2c1_grps, + .ngroups = ARRAY_SIZE(i2c1_grps), +}; + +/* Pad multiplexing for i2c2 device */ +static const unsigned i2c2_pins[][2] = { { 0, 1 }, { 2, 3 }, { 19, 20 }, + { 75, 76 }, { 96, 97 } }; +static struct spear_muxreg i2c2_ext_0_1_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_FIRDA_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_0_9_REG, + .mask = PMX_PL_0_1_MASK, + .val = PMX_I2C2_PL_0_1_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_I2C2_PORT_SEL_MASK, + .val = PMX_I2C2_PORT_0_1_VAL, + }, +}; + +static struct spear_muxreg i2c2_ext_2_3_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_UART0_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_0_9_REG, + .mask = PMX_PL_2_3_MASK, + .val = PMX_I2C2_PL_2_3_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_I2C2_PORT_SEL_MASK, + .val = PMX_I2C2_PORT_2_3_VAL, + }, +}; + +static struct spear_muxreg i2c2_ext_19_20_muxreg[] = { + { + .reg = PMX_CONFIG_REG, + .mask = PMX_MII_MASK, + .val = 0, + }, { + .reg = IP_SEL_PAD_10_19_REG, + .mask = PMX_PL_19_MASK, + .val = PMX_I2C2_PL_19_VAL, + }, { + .reg = IP_SEL_PAD_20_29_REG, + .mask = PMX_PL_20_MASK, + .val = PMX_I2C2_PL_20_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_I2C2_PORT_SEL_MASK, + .val = PMX_I2C2_PORT_19_20_VAL, + }, +}; + +static struct spear_muxreg i2c2_ext_75_76_muxreg[] = { + { + .reg = IP_SEL_PAD_70_79_REG, + .mask = PMX_PL_75_76_MASK, + .val = PMX_I2C2_PL_75_76_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_I2C2_PORT_SEL_MASK, + .val = PMX_I2C2_PORT_75_76_VAL, + }, +}; + +static struct spear_muxreg i2c2_ext_96_97_muxreg[] = { + { + .reg = IP_SEL_PAD_90_99_REG, + .mask = PMX_PL_96_97_MASK, + .val = PMX_I2C2_PL_96_97_VAL, + }, { + .reg = IP_SEL_MIX_PAD_REG, + .mask = PMX_I2C2_PORT_SEL_MASK, + .val = PMX_I2C2_PORT_96_97_VAL, + }, +}; + +static struct spear_modemux i2c2_modemux[][1] = { + { + /* Select signals on pins 0_1 */ + { + .modes = EXTENDED_MODE, + .muxregs = i2c2_ext_0_1_muxreg, + .nmuxregs = ARRAY_SIZE(i2c2_ext_0_1_muxreg), + }, + }, { + /* Select signals on pins 2_3 */ + { + .modes = EXTENDED_MODE, + .muxregs = i2c2_ext_2_3_muxreg, + .nmuxregs = ARRAY_SIZE(i2c2_ext_2_3_muxreg), + }, + }, { + /* Select signals on pins 19_20 */ + { + .modes = EXTENDED_MODE, + .muxregs = i2c2_ext_19_20_muxreg, + .nmuxregs = ARRAY_SIZE(i2c2_ext_19_20_muxreg), + }, + }, { + /* Select signals on pins 75_76 */ + { + .modes = EXTENDED_MODE, + .muxregs = i2c2_ext_75_76_muxreg, + .nmuxregs = ARRAY_SIZE(i2c2_ext_75_76_muxreg), + }, + }, { + /* Select signals on pins 96_97 */ + { + .modes = EXTENDED_MODE, + .muxregs = i2c2_ext_96_97_muxreg, + .nmuxregs = ARRAY_SIZE(i2c2_ext_96_97_muxreg), + }, + }, +}; + +static struct spear_pingroup i2c2_pingroup[] = { + { + .name = "i2c2_0_1_grp", + .pins = i2c2_pins[0], + .npins = ARRAY_SIZE(i2c2_pins[0]), + .modemuxs = i2c2_modemux[0], + .nmodemuxs = ARRAY_SIZE(i2c2_modemux[0]), + }, { + .name = "i2c2_2_3_grp", + .pins = i2c2_pins[1], + .npins = ARRAY_SIZE(i2c2_pins[1]), + .modemuxs = i2c2_modemux[1], + .nmodemuxs = ARRAY_SIZE(i2c2_modemux[1]), + }, { + .name = "i2c2_19_20_grp", + .pins = i2c2_pins[2], + .npins = ARRAY_SIZE(i2c2_pins[2]), + .modemuxs = i2c2_modemux[2], + .nmodemuxs = ARRAY_SIZE(i2c2_modemux[2]), + }, { + .name = "i2c2_75_76_grp", + .pins = i2c2_pins[3], + .npins = ARRAY_SIZE(i2c2_pins[3]), + .modemuxs = i2c2_modemux[3], + .nmodemuxs = ARRAY_SIZE(i2c2_modemux[3]), + }, { + .name = "i2c2_96_97_grp", + .pins = i2c2_pins[4], + .npins = ARRAY_SIZE(i2c2_pins[4]), + .modemuxs = i2c2_modemux[4], + .nmodemuxs = ARRAY_SIZE(i2c2_modemux[4]), + }, +}; + +static const char *const i2c2_grps[] = { "i2c2_0_1_grp", "i2c2_2_3_grp", + "i2c2_19_20_grp", "i2c2_75_76_grp", "i2c2_96_97_grp" }; +static struct spear_function i2c2_function = { + .name = "i2c2", + .groups = i2c2_grps, + .ngroups = ARRAY_SIZE(i2c2_grps), +}; + +/* pingroups */ +static struct spear_pingroup *spear320_pingroups[] = { + SPEAR3XX_COMMON_PINGROUPS, + &clcd_pingroup, + &emi_pingroup, + &fsmc_8bit_pingroup, + &fsmc_16bit_pingroup, + &spp_pingroup, + &sdhci_led_pingroup, + &sdhci_pingroup[0], + &sdhci_pingroup[1], + &i2s_pingroup, + &uart1_pingroup, + &uart1_modem_pingroup[0], + &uart1_modem_pingroup[1], + &uart1_modem_pingroup[2], + &uart1_modem_pingroup[3], + &uart2_pingroup, + &uart3_pingroup[0], + &uart3_pingroup[1], + &uart3_pingroup[2], + &uart3_pingroup[3], + &uart3_pingroup[4], + &uart3_pingroup[5], + &uart3_pingroup[6], + &uart4_pingroup[0], + &uart4_pingroup[1], + &uart4_pingroup[2], + &uart4_pingroup[3], + &uart4_pingroup[4], + &uart4_pingroup[5], + &uart5_pingroup[0], + &uart5_pingroup[1], + &uart5_pingroup[2], + &uart5_pingroup[3], + &uart6_pingroup[0], + &uart6_pingroup[1], + &rs485_pingroup, + &touchscreen_pingroup, + &can0_pingroup, + &can1_pingroup, + &pwm0_1_pingroup[0], + &pwm0_1_pingroup[1], + &pwm0_1_pingroup[2], + &pwm0_1_pingroup[3], + &pwm0_1_pingroup[4], + &pwm0_1_pingroup[5], + &pwm0_1_pingroup[6], + &pwm2_pingroup[0], + &pwm2_pingroup[1], + &pwm2_pingroup[2], + &pwm2_pingroup[3], + &pwm2_pingroup[4], + &pwm2_pingroup[5], + &pwm2_pingroup[6], + &pwm3_pingroup[0], + &pwm3_pingroup[1], + &pwm3_pingroup[2], + &pwm3_pingroup[3], + &pwm3_pingroup[4], + &pwm3_pingroup[5], + &ssp1_pingroup[0], + &ssp1_pingroup[1], + &ssp1_pingroup[2], + &ssp1_pingroup[3], + &ssp1_pingroup[4], + &ssp2_pingroup[0], + &ssp2_pingroup[1], + &ssp2_pingroup[2], + &ssp2_pingroup[3], + &ssp2_pingroup[4], + &mii2_pingroup, + &mii0_1_pingroup[0], + &mii0_1_pingroup[1], + &i2c1_pingroup[0], + &i2c1_pingroup[1], + &i2c2_pingroup[0], + &i2c2_pingroup[1], + &i2c2_pingroup[2], + &i2c2_pingroup[3], + &i2c2_pingroup[4], +}; + +/* functions */ +static struct spear_function *spear320_functions[] = { + SPEAR3XX_COMMON_FUNCTIONS, + &clcd_function, + &emi_function, + &fsmc_function, + &spp_function, + &sdhci_function, + &i2s_function, + &uart1_function, + &uart1_modem_function, + &uart2_function, + &uart3_function, + &uart4_function, + &uart5_function, + &uart6_function, + &rs485_function, + &touchscreen_function, + &can0_function, + &can1_function, + &pwm0_1_function, + &pwm2_function, + &pwm3_function, + &ssp1_function, + &ssp2_function, + &mii2_function, + &mii0_1_function, + &i2c1_function, + &i2c2_function, +}; + +static struct of_device_id spear320_pinctrl_of_match[] __devinitdata = { + { + .compatible = "st,spear320-pinmux", + }, + {}, +}; + +static int __devinit spear320_pinctrl_probe(struct platform_device *pdev) +{ + int ret; + + spear3xx_machdata.groups = spear320_pingroups; + spear3xx_machdata.ngroups = ARRAY_SIZE(spear320_pingroups); + spear3xx_machdata.functions = spear320_functions; + spear3xx_machdata.nfunctions = ARRAY_SIZE(spear320_functions); + + spear3xx_machdata.modes_supported = true; + spear3xx_machdata.pmx_modes = spear320_pmx_modes; + spear3xx_machdata.npmx_modes = ARRAY_SIZE(spear320_pmx_modes); + + pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG); + + ret = spear_pinctrl_probe(pdev, &spear3xx_machdata); + if (ret) + return ret; + + return 0; +} + +static int __devexit spear320_pinctrl_remove(struct platform_device *pdev) +{ + return spear_pinctrl_remove(pdev); +} + +static struct platform_driver spear320_pinctrl_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = spear320_pinctrl_of_match, + }, + .probe = spear320_pinctrl_probe, + .remove = __devexit_p(spear320_pinctrl_remove), +}; + +static int __init spear320_pinctrl_init(void) +{ + return platform_driver_register(&spear320_pinctrl_driver); +} +arch_initcall(spear320_pinctrl_init); + +static void __exit spear320_pinctrl_exit(void) +{ + platform_driver_unregister(&spear320_pinctrl_driver); +} +module_exit(spear320_pinctrl_exit); + +MODULE_AUTHOR("Viresh Kumar "); +MODULE_DESCRIPTION("ST Microelectronics SPEAr320 pinctrl driver"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, spear320_pinctrl_of_match); diff --git a/trunk/drivers/pinctrl/spear/pinctrl-spear3xx.c b/trunk/drivers/pinctrl/spear/pinctrl-spear3xx.c new file mode 100644 index 000000000000..832049a8b1c9 --- /dev/null +++ b/trunk/drivers/pinctrl/spear/pinctrl-spear3xx.c @@ -0,0 +1,588 @@ +/* + * Driver for the ST Microelectronics SPEAr3xx pinmux + * + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar + * + * 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 "pinctrl-spear3xx.h" + +/* pins */ +static const struct pinctrl_pin_desc spear3xx_pins[] = { + PINCTRL_PIN(0, "PLGPIO0"), + PINCTRL_PIN(1, "PLGPIO1"), + PINCTRL_PIN(2, "PLGPIO2"), + PINCTRL_PIN(3, "PLGPIO3"), + PINCTRL_PIN(4, "PLGPIO4"), + PINCTRL_PIN(5, "PLGPIO5"), + PINCTRL_PIN(6, "PLGPIO6"), + PINCTRL_PIN(7, "PLGPIO7"), + PINCTRL_PIN(8, "PLGPIO8"), + PINCTRL_PIN(9, "PLGPIO9"), + PINCTRL_PIN(10, "PLGPIO10"), + PINCTRL_PIN(11, "PLGPIO11"), + PINCTRL_PIN(12, "PLGPIO12"), + PINCTRL_PIN(13, "PLGPIO13"), + PINCTRL_PIN(14, "PLGPIO14"), + PINCTRL_PIN(15, "PLGPIO15"), + PINCTRL_PIN(16, "PLGPIO16"), + PINCTRL_PIN(17, "PLGPIO17"), + PINCTRL_PIN(18, "PLGPIO18"), + PINCTRL_PIN(19, "PLGPIO19"), + PINCTRL_PIN(20, "PLGPIO20"), + PINCTRL_PIN(21, "PLGPIO21"), + PINCTRL_PIN(22, "PLGPIO22"), + PINCTRL_PIN(23, "PLGPIO23"), + PINCTRL_PIN(24, "PLGPIO24"), + PINCTRL_PIN(25, "PLGPIO25"), + PINCTRL_PIN(26, "PLGPIO26"), + PINCTRL_PIN(27, "PLGPIO27"), + PINCTRL_PIN(28, "PLGPIO28"), + PINCTRL_PIN(29, "PLGPIO29"), + PINCTRL_PIN(30, "PLGPIO30"), + PINCTRL_PIN(31, "PLGPIO31"), + PINCTRL_PIN(32, "PLGPIO32"), + PINCTRL_PIN(33, "PLGPIO33"), + PINCTRL_PIN(34, "PLGPIO34"), + PINCTRL_PIN(35, "PLGPIO35"), + PINCTRL_PIN(36, "PLGPIO36"), + PINCTRL_PIN(37, "PLGPIO37"), + PINCTRL_PIN(38, "PLGPIO38"), + PINCTRL_PIN(39, "PLGPIO39"), + PINCTRL_PIN(40, "PLGPIO40"), + PINCTRL_PIN(41, "PLGPIO41"), + PINCTRL_PIN(42, "PLGPIO42"), + PINCTRL_PIN(43, "PLGPIO43"), + PINCTRL_PIN(44, "PLGPIO44"), + PINCTRL_PIN(45, "PLGPIO45"), + PINCTRL_PIN(46, "PLGPIO46"), + PINCTRL_PIN(47, "PLGPIO47"), + PINCTRL_PIN(48, "PLGPIO48"), + PINCTRL_PIN(49, "PLGPIO49"), + PINCTRL_PIN(50, "PLGPIO50"), + PINCTRL_PIN(51, "PLGPIO51"), + PINCTRL_PIN(52, "PLGPIO52"), + PINCTRL_PIN(53, "PLGPIO53"), + PINCTRL_PIN(54, "PLGPIO54"), + PINCTRL_PIN(55, "PLGPIO55"), + PINCTRL_PIN(56, "PLGPIO56"), + PINCTRL_PIN(57, "PLGPIO57"), + PINCTRL_PIN(58, "PLGPIO58"), + PINCTRL_PIN(59, "PLGPIO59"), + PINCTRL_PIN(60, "PLGPIO60"), + PINCTRL_PIN(61, "PLGPIO61"), + PINCTRL_PIN(62, "PLGPIO62"), + PINCTRL_PIN(63, "PLGPIO63"), + PINCTRL_PIN(64, "PLGPIO64"), + PINCTRL_PIN(65, "PLGPIO65"), + PINCTRL_PIN(66, "PLGPIO66"), + PINCTRL_PIN(67, "PLGPIO67"), + PINCTRL_PIN(68, "PLGPIO68"), + PINCTRL_PIN(69, "PLGPIO69"), + PINCTRL_PIN(70, "PLGPIO70"), + PINCTRL_PIN(71, "PLGPIO71"), + PINCTRL_PIN(72, "PLGPIO72"), + PINCTRL_PIN(73, "PLGPIO73"), + PINCTRL_PIN(74, "PLGPIO74"), + PINCTRL_PIN(75, "PLGPIO75"), + PINCTRL_PIN(76, "PLGPIO76"), + PINCTRL_PIN(77, "PLGPIO77"), + PINCTRL_PIN(78, "PLGPIO78"), + PINCTRL_PIN(79, "PLGPIO79"), + PINCTRL_PIN(80, "PLGPIO80"), + PINCTRL_PIN(81, "PLGPIO81"), + PINCTRL_PIN(82, "PLGPIO82"), + PINCTRL_PIN(83, "PLGPIO83"), + PINCTRL_PIN(84, "PLGPIO84"), + PINCTRL_PIN(85, "PLGPIO85"), + PINCTRL_PIN(86, "PLGPIO86"), + PINCTRL_PIN(87, "PLGPIO87"), + PINCTRL_PIN(88, "PLGPIO88"), + PINCTRL_PIN(89, "PLGPIO89"), + PINCTRL_PIN(90, "PLGPIO90"), + PINCTRL_PIN(91, "PLGPIO91"), + PINCTRL_PIN(92, "PLGPIO92"), + PINCTRL_PIN(93, "PLGPIO93"), + PINCTRL_PIN(94, "PLGPIO94"), + PINCTRL_PIN(95, "PLGPIO95"), + PINCTRL_PIN(96, "PLGPIO96"), + PINCTRL_PIN(97, "PLGPIO97"), + PINCTRL_PIN(98, "PLGPIO98"), + PINCTRL_PIN(99, "PLGPIO99"), + PINCTRL_PIN(100, "PLGPIO100"), + PINCTRL_PIN(101, "PLGPIO101"), +}; + +/* firda_pins */ +static const unsigned firda_pins[] = { 0, 1 }; +static struct spear_muxreg firda_muxreg[] = { + { + .reg = -1, + .mask = PMX_FIRDA_MASK, + .val = PMX_FIRDA_MASK, + }, +}; + +static struct spear_modemux firda_modemux[] = { + { + .modes = ~0, + .muxregs = firda_muxreg, + .nmuxregs = ARRAY_SIZE(firda_muxreg), + }, +}; + +struct spear_pingroup spear3xx_firda_pingroup = { + .name = "firda_grp", + .pins = firda_pins, + .npins = ARRAY_SIZE(firda_pins), + .modemuxs = firda_modemux, + .nmodemuxs = ARRAY_SIZE(firda_modemux), +}; + +static const char *const firda_grps[] = { "firda_grp" }; +struct spear_function spear3xx_firda_function = { + .name = "firda", + .groups = firda_grps, + .ngroups = ARRAY_SIZE(firda_grps), +}; + +/* i2c_pins */ +static const unsigned i2c_pins[] = { 4, 5 }; +static struct spear_muxreg i2c_muxreg[] = { + { + .reg = -1, + .mask = PMX_I2C_MASK, + .val = PMX_I2C_MASK, + }, +}; + +static struct spear_modemux i2c_modemux[] = { + { + .modes = ~0, + .muxregs = i2c_muxreg, + .nmuxregs = ARRAY_SIZE(i2c_muxreg), + }, +}; + +struct spear_pingroup spear3xx_i2c_pingroup = { + .name = "i2c0_grp", + .pins = i2c_pins, + .npins = ARRAY_SIZE(i2c_pins), + .modemuxs = i2c_modemux, + .nmodemuxs = ARRAY_SIZE(i2c_modemux), +}; + +static const char *const i2c_grps[] = { "i2c0_grp" }; +struct spear_function spear3xx_i2c_function = { + .name = "i2c0", + .groups = i2c_grps, + .ngroups = ARRAY_SIZE(i2c_grps), +}; + +/* ssp_cs_pins */ +static const unsigned ssp_cs_pins[] = { 34, 35, 36 }; +static struct spear_muxreg ssp_cs_muxreg[] = { + { + .reg = -1, + .mask = PMX_SSP_CS_MASK, + .val = PMX_SSP_CS_MASK, + }, +}; + +static struct spear_modemux ssp_cs_modemux[] = { + { + .modes = ~0, + .muxregs = ssp_cs_muxreg, + .nmuxregs = ARRAY_SIZE(ssp_cs_muxreg), + }, +}; + +struct spear_pingroup spear3xx_ssp_cs_pingroup = { + .name = "ssp_cs_grp", + .pins = ssp_cs_pins, + .npins = ARRAY_SIZE(ssp_cs_pins), + .modemuxs = ssp_cs_modemux, + .nmodemuxs = ARRAY_SIZE(ssp_cs_modemux), +}; + +static const char *const ssp_cs_grps[] = { "ssp_cs_grp" }; +struct spear_function spear3xx_ssp_cs_function = { + .name = "ssp_cs", + .groups = ssp_cs_grps, + .ngroups = ARRAY_SIZE(ssp_cs_grps), +}; + +/* ssp_pins */ +static const unsigned ssp_pins[] = { 6, 7, 8, 9 }; +static struct spear_muxreg ssp_muxreg[] = { + { + .reg = -1, + .mask = PMX_SSP_MASK, + .val = PMX_SSP_MASK, + }, +}; + +static struct spear_modemux ssp_modemux[] = { + { + .modes = ~0, + .muxregs = ssp_muxreg, + .nmuxregs = ARRAY_SIZE(ssp_muxreg), + }, +}; + +struct spear_pingroup spear3xx_ssp_pingroup = { + .name = "ssp0_grp", + .pins = ssp_pins, + .npins = ARRAY_SIZE(ssp_pins), + .modemuxs = ssp_modemux, + .nmodemuxs = ARRAY_SIZE(ssp_modemux), +}; + +static const char *const ssp_grps[] = { "ssp0_grp" }; +struct spear_function spear3xx_ssp_function = { + .name = "ssp0", + .groups = ssp_grps, + .ngroups = ARRAY_SIZE(ssp_grps), +}; + +/* mii_pins */ +static const unsigned mii_pins[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27 }; +static struct spear_muxreg mii_muxreg[] = { + { + .reg = -1, + .mask = PMX_MII_MASK, + .val = PMX_MII_MASK, + }, +}; + +static struct spear_modemux mii_modemux[] = { + { + .modes = ~0, + .muxregs = mii_muxreg, + .nmuxregs = ARRAY_SIZE(mii_muxreg), + }, +}; + +struct spear_pingroup spear3xx_mii_pingroup = { + .name = "mii0_grp", + .pins = mii_pins, + .npins = ARRAY_SIZE(mii_pins), + .modemuxs = mii_modemux, + .nmodemuxs = ARRAY_SIZE(mii_modemux), +}; + +static const char *const mii_grps[] = { "mii0_grp" }; +struct spear_function spear3xx_mii_function = { + .name = "mii0", + .groups = mii_grps, + .ngroups = ARRAY_SIZE(mii_grps), +}; + +/* gpio0_pin0_pins */ +static const unsigned gpio0_pin0_pins[] = { 28 }; +static struct spear_muxreg gpio0_pin0_muxreg[] = { + { + .reg = -1, + .mask = PMX_GPIO_PIN0_MASK, + .val = PMX_GPIO_PIN0_MASK, + }, +}; + +static struct spear_modemux gpio0_pin0_modemux[] = { + { + .modes = ~0, + .muxregs = gpio0_pin0_muxreg, + .nmuxregs = ARRAY_SIZE(gpio0_pin0_muxreg), + }, +}; + +struct spear_pingroup spear3xx_gpio0_pin0_pingroup = { + .name = "gpio0_pin0_grp", + .pins = gpio0_pin0_pins, + .npins = ARRAY_SIZE(gpio0_pin0_pins), + .modemuxs = gpio0_pin0_modemux, + .nmodemuxs = ARRAY_SIZE(gpio0_pin0_modemux), +}; + +/* gpio0_pin1_pins */ +static const unsigned gpio0_pin1_pins[] = { 29 }; +static struct spear_muxreg gpio0_pin1_muxreg[] = { + { + .reg = -1, + .mask = PMX_GPIO_PIN1_MASK, + .val = PMX_GPIO_PIN1_MASK, + }, +}; + +static struct spear_modemux gpio0_pin1_modemux[] = { + { + .modes = ~0, + .muxregs = gpio0_pin1_muxreg, + .nmuxregs = ARRAY_SIZE(gpio0_pin1_muxreg), + }, +}; + +struct spear_pingroup spear3xx_gpio0_pin1_pingroup = { + .name = "gpio0_pin1_grp", + .pins = gpio0_pin1_pins, + .npins = ARRAY_SIZE(gpio0_pin1_pins), + .modemuxs = gpio0_pin1_modemux, + .nmodemuxs = ARRAY_SIZE(gpio0_pin1_modemux), +}; + +/* gpio0_pin2_pins */ +static const unsigned gpio0_pin2_pins[] = { 30 }; +static struct spear_muxreg gpio0_pin2_muxreg[] = { + { + .reg = -1, + .mask = PMX_GPIO_PIN2_MASK, + .val = PMX_GPIO_PIN2_MASK, + }, +}; + +static struct spear_modemux gpio0_pin2_modemux[] = { + { + .modes = ~0, + .muxregs = gpio0_pin2_muxreg, + .nmuxregs = ARRAY_SIZE(gpio0_pin2_muxreg), + }, +}; + +struct spear_pingroup spear3xx_gpio0_pin2_pingroup = { + .name = "gpio0_pin2_grp", + .pins = gpio0_pin2_pins, + .npins = ARRAY_SIZE(gpio0_pin2_pins), + .modemuxs = gpio0_pin2_modemux, + .nmodemuxs = ARRAY_SIZE(gpio0_pin2_modemux), +}; + +/* gpio0_pin3_pins */ +static const unsigned gpio0_pin3_pins[] = { 31 }; +static struct spear_muxreg gpio0_pin3_muxreg[] = { + { + .reg = -1, + .mask = PMX_GPIO_PIN3_MASK, + .val = PMX_GPIO_PIN3_MASK, + }, +}; + +static struct spear_modemux gpio0_pin3_modemux[] = { + { + .modes = ~0, + .muxregs = gpio0_pin3_muxreg, + .nmuxregs = ARRAY_SIZE(gpio0_pin3_muxreg), + }, +}; + +struct spear_pingroup spear3xx_gpio0_pin3_pingroup = { + .name = "gpio0_pin3_grp", + .pins = gpio0_pin3_pins, + .npins = ARRAY_SIZE(gpio0_pin3_pins), + .modemuxs = gpio0_pin3_modemux, + .nmodemuxs = ARRAY_SIZE(gpio0_pin3_modemux), +}; + +/* gpio0_pin4_pins */ +static const unsigned gpio0_pin4_pins[] = { 32 }; +static struct spear_muxreg gpio0_pin4_muxreg[] = { + { + .reg = -1, + .mask = PMX_GPIO_PIN4_MASK, + .val = PMX_GPIO_PIN4_MASK, + }, +}; + +static struct spear_modemux gpio0_pin4_modemux[] = { + { + .modes = ~0, + .muxregs = gpio0_pin4_muxreg, + .nmuxregs = ARRAY_SIZE(gpio0_pin4_muxreg), + }, +}; + +struct spear_pingroup spear3xx_gpio0_pin4_pingroup = { + .name = "gpio0_pin4_grp", + .pins = gpio0_pin4_pins, + .npins = ARRAY_SIZE(gpio0_pin4_pins), + .modemuxs = gpio0_pin4_modemux, + .nmodemuxs = ARRAY_SIZE(gpio0_pin4_modemux), +}; + +/* gpio0_pin5_pins */ +static const unsigned gpio0_pin5_pins[] = { 33 }; +static struct spear_muxreg gpio0_pin5_muxreg[] = { + { + .reg = -1, + .mask = PMX_GPIO_PIN5_MASK, + .val = PMX_GPIO_PIN5_MASK, + }, +}; + +static struct spear_modemux gpio0_pin5_modemux[] = { + { + .modes = ~0, + .muxregs = gpio0_pin5_muxreg, + .nmuxregs = ARRAY_SIZE(gpio0_pin5_muxreg), + }, +}; + +struct spear_pingroup spear3xx_gpio0_pin5_pingroup = { + .name = "gpio0_pin5_grp", + .pins = gpio0_pin5_pins, + .npins = ARRAY_SIZE(gpio0_pin5_pins), + .modemuxs = gpio0_pin5_modemux, + .nmodemuxs = ARRAY_SIZE(gpio0_pin5_modemux), +}; + +static const char *const gpio0_grps[] = { "gpio0_pin0_grp", "gpio0_pin1_grp", + "gpio0_pin2_grp", "gpio0_pin3_grp", "gpio0_pin4_grp", "gpio0_pin5_grp", +}; +struct spear_function spear3xx_gpio0_function = { + .name = "gpio0", + .groups = gpio0_grps, + .ngroups = ARRAY_SIZE(gpio0_grps), +}; + +/* uart0_ext_pins */ +static const unsigned uart0_ext_pins[] = { 37, 38, 39, 40, 41, 42 }; +static struct spear_muxreg uart0_ext_muxreg[] = { + { + .reg = -1, + .mask = PMX_UART0_MODEM_MASK, + .val = PMX_UART0_MODEM_MASK, + }, +}; + +static struct spear_modemux uart0_ext_modemux[] = { + { + .modes = ~0, + .muxregs = uart0_ext_muxreg, + .nmuxregs = ARRAY_SIZE(uart0_ext_muxreg), + }, +}; + +struct spear_pingroup spear3xx_uart0_ext_pingroup = { + .name = "uart0_ext_grp", + .pins = uart0_ext_pins, + .npins = ARRAY_SIZE(uart0_ext_pins), + .modemuxs = uart0_ext_modemux, + .nmodemuxs = ARRAY_SIZE(uart0_ext_modemux), +}; + +static const char *const uart0_ext_grps[] = { "uart0_ext_grp" }; +struct spear_function spear3xx_uart0_ext_function = { + .name = "uart0_ext", + .groups = uart0_ext_grps, + .ngroups = ARRAY_SIZE(uart0_ext_grps), +}; + +/* uart0_pins */ +static const unsigned uart0_pins[] = { 2, 3 }; +static struct spear_muxreg uart0_muxreg[] = { + { + .reg = -1, + .mask = PMX_UART0_MASK, + .val = PMX_UART0_MASK, + }, +}; + +static struct spear_modemux uart0_modemux[] = { + { + .modes = ~0, + .muxregs = uart0_muxreg, + .nmuxregs = ARRAY_SIZE(uart0_muxreg), + }, +}; + +struct spear_pingroup spear3xx_uart0_pingroup = { + .name = "uart0_grp", + .pins = uart0_pins, + .npins = ARRAY_SIZE(uart0_pins), + .modemuxs = uart0_modemux, + .nmodemuxs = ARRAY_SIZE(uart0_modemux), +}; + +static const char *const uart0_grps[] = { "uart0_grp" }; +struct spear_function spear3xx_uart0_function = { + .name = "uart0", + .groups = uart0_grps, + .ngroups = ARRAY_SIZE(uart0_grps), +}; + +/* timer_0_1_pins */ +static const unsigned timer_0_1_pins[] = { 43, 44, 47, 48 }; +static struct spear_muxreg timer_0_1_muxreg[] = { + { + .reg = -1, + .mask = PMX_TIMER_0_1_MASK, + .val = PMX_TIMER_0_1_MASK, + }, +}; + +static struct spear_modemux timer_0_1_modemux[] = { + { + .modes = ~0, + .muxregs = timer_0_1_muxreg, + .nmuxregs = ARRAY_SIZE(timer_0_1_muxreg), + }, +}; + +struct spear_pingroup spear3xx_timer_0_1_pingroup = { + .name = "timer_0_1_grp", + .pins = timer_0_1_pins, + .npins = ARRAY_SIZE(timer_0_1_pins), + .modemuxs = timer_0_1_modemux, + .nmodemuxs = ARRAY_SIZE(timer_0_1_modemux), +}; + +static const char *const timer_0_1_grps[] = { "timer_0_1_grp" }; +struct spear_function spear3xx_timer_0_1_function = { + .name = "timer_0_1", + .groups = timer_0_1_grps, + .ngroups = ARRAY_SIZE(timer_0_1_grps), +}; + +/* timer_2_3_pins */ +static const unsigned timer_2_3_pins[] = { 45, 46, 49, 50 }; +static struct spear_muxreg timer_2_3_muxreg[] = { + { + .reg = -1, + .mask = PMX_TIMER_2_3_MASK, + .val = PMX_TIMER_2_3_MASK, + }, +}; + +static struct spear_modemux timer_2_3_modemux[] = { + { + .modes = ~0, + .muxregs = timer_2_3_muxreg, + .nmuxregs = ARRAY_SIZE(timer_2_3_muxreg), + }, +}; + +struct spear_pingroup spear3xx_timer_2_3_pingroup = { + .name = "timer_2_3_grp", + .pins = timer_2_3_pins, + .npins = ARRAY_SIZE(timer_2_3_pins), + .modemuxs = timer_2_3_modemux, + .nmodemuxs = ARRAY_SIZE(timer_2_3_modemux), +}; + +static const char *const timer_2_3_grps[] = { "timer_2_3_grp" }; +struct spear_function spear3xx_timer_2_3_function = { + .name = "timer_2_3", + .groups = timer_2_3_grps, + .ngroups = ARRAY_SIZE(timer_2_3_grps), +}; + +struct spear_pinctrl_machdata spear3xx_machdata = { + .pins = spear3xx_pins, + .npins = ARRAY_SIZE(spear3xx_pins), +}; diff --git a/trunk/drivers/pinctrl/spear/pinctrl-spear3xx.h b/trunk/drivers/pinctrl/spear/pinctrl-spear3xx.h new file mode 100644 index 000000000000..5d5fdd8df7b8 --- /dev/null +++ b/trunk/drivers/pinctrl/spear/pinctrl-spear3xx.h @@ -0,0 +1,92 @@ +/* + * Header file for the ST Microelectronics SPEAr3xx pinmux + * + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar + * + * 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. + */ + +#ifndef __PINMUX_SPEAR3XX_H__ +#define __PINMUX_SPEAR3XX_H__ + +#include "pinctrl-spear.h" + +/* pad mux declarations */ +#define PMX_FIRDA_MASK (1 << 14) +#define PMX_I2C_MASK (1 << 13) +#define PMX_SSP_CS_MASK (1 << 12) +#define PMX_SSP_MASK (1 << 11) +#define PMX_MII_MASK (1 << 10) +#define PMX_GPIO_PIN0_MASK (1 << 9) +#define PMX_GPIO_PIN1_MASK (1 << 8) +#define PMX_GPIO_PIN2_MASK (1 << 7) +#define PMX_GPIO_PIN3_MASK (1 << 6) +#define PMX_GPIO_PIN4_MASK (1 << 5) +#define PMX_GPIO_PIN5_MASK (1 << 4) +#define PMX_UART0_MODEM_MASK (1 << 3) +#define PMX_UART0_MASK (1 << 2) +#define PMX_TIMER_2_3_MASK (1 << 1) +#define PMX_TIMER_0_1_MASK (1 << 0) + +extern struct spear_pingroup spear3xx_firda_pingroup; +extern struct spear_pingroup spear3xx_gpio0_pin0_pingroup; +extern struct spear_pingroup spear3xx_gpio0_pin1_pingroup; +extern struct spear_pingroup spear3xx_gpio0_pin2_pingroup; +extern struct spear_pingroup spear3xx_gpio0_pin3_pingroup; +extern struct spear_pingroup spear3xx_gpio0_pin4_pingroup; +extern struct spear_pingroup spear3xx_gpio0_pin5_pingroup; +extern struct spear_pingroup spear3xx_i2c_pingroup; +extern struct spear_pingroup spear3xx_mii_pingroup; +extern struct spear_pingroup spear3xx_ssp_cs_pingroup; +extern struct spear_pingroup spear3xx_ssp_pingroup; +extern struct spear_pingroup spear3xx_timer_0_1_pingroup; +extern struct spear_pingroup spear3xx_timer_2_3_pingroup; +extern struct spear_pingroup spear3xx_uart0_ext_pingroup; +extern struct spear_pingroup spear3xx_uart0_pingroup; + +#define SPEAR3XX_COMMON_PINGROUPS \ + &spear3xx_firda_pingroup, \ + &spear3xx_gpio0_pin0_pingroup, \ + &spear3xx_gpio0_pin1_pingroup, \ + &spear3xx_gpio0_pin2_pingroup, \ + &spear3xx_gpio0_pin3_pingroup, \ + &spear3xx_gpio0_pin4_pingroup, \ + &spear3xx_gpio0_pin5_pingroup, \ + &spear3xx_i2c_pingroup, \ + &spear3xx_mii_pingroup, \ + &spear3xx_ssp_cs_pingroup, \ + &spear3xx_ssp_pingroup, \ + &spear3xx_timer_0_1_pingroup, \ + &spear3xx_timer_2_3_pingroup, \ + &spear3xx_uart0_ext_pingroup, \ + &spear3xx_uart0_pingroup + +extern struct spear_function spear3xx_firda_function; +extern struct spear_function spear3xx_gpio0_function; +extern struct spear_function spear3xx_i2c_function; +extern struct spear_function spear3xx_mii_function; +extern struct spear_function spear3xx_ssp_cs_function; +extern struct spear_function spear3xx_ssp_function; +extern struct spear_function spear3xx_timer_0_1_function; +extern struct spear_function spear3xx_timer_2_3_function; +extern struct spear_function spear3xx_uart0_ext_function; +extern struct spear_function spear3xx_uart0_function; + +#define SPEAR3XX_COMMON_FUNCTIONS \ + &spear3xx_firda_function, \ + &spear3xx_gpio0_function, \ + &spear3xx_i2c_function, \ + &spear3xx_mii_function, \ + &spear3xx_ssp_cs_function, \ + &spear3xx_ssp_function, \ + &spear3xx_timer_0_1_function, \ + &spear3xx_timer_2_3_function, \ + &spear3xx_uart0_ext_function, \ + &spear3xx_uart0_function + +extern struct spear_pinctrl_machdata spear3xx_machdata; + +#endif /* __PINMUX_SPEAR3XX_H__ */ diff --git a/trunk/drivers/platform/x86/fujitsu-laptop.c b/trunk/drivers/platform/x86/fujitsu-laptop.c index 6b26666b37f2..c4c1a5444b38 100644 --- a/trunk/drivers/platform/x86/fujitsu-laptop.c +++ b/trunk/drivers/platform/x86/fujitsu-laptop.c @@ -1,7 +1,7 @@ /*-*-linux-c-*-*/ /* - Copyright (C) 2007,2008 Jonathan Woithe + Copyright (C) 2007,2008 Jonathan Woithe Copyright (C) 2008 Peter Gruber Copyright (C) 2008 Tony Vroon Based on earlier work: diff --git a/trunk/drivers/power/bq27x00_battery.c b/trunk/drivers/power/bq27x00_battery.c index 222ccd872ac5..f5d6d379f2fb 100644 --- a/trunk/drivers/power/bq27x00_battery.c +++ b/trunk/drivers/power/bq27x00_battery.c @@ -451,7 +451,7 @@ static int bq27x00_battery_capacity_level(struct bq27x00_device_info *di, } /* - * Return the battery Voltage in milivolts + * Return the battery Voltage in millivolts * Or < 0 if something fails. */ static int bq27x00_battery_voltage(struct bq27x00_device_info *di, diff --git a/trunk/drivers/ptp/Kconfig b/trunk/drivers/ptp/Kconfig index cd9bc3b129bc..ffdf712f9a67 100644 --- a/trunk/drivers/ptp/Kconfig +++ b/trunk/drivers/ptp/Kconfig @@ -70,7 +70,7 @@ config DP83640_PHY using the SO_TIMESTAMPING API. In order for this to work, your MAC driver must also - implement the skb_tx_timetamp() function. + implement the skb_tx_timestamp() function. config PTP_1588_CLOCK_PCH tristate "Intel PCH EG20T as PTP clock" @@ -78,9 +78,13 @@ config PTP_1588_CLOCK_PCH depends on PCH_GBE help This driver adds support for using the PCH EG20T as a PTP - clock. This clock is only useful if your PTP programs are - getting hardware time stamps on the PTP Ethernet packets - using the SO_TIMESTAMPING API. + clock. The hardware supports time stamping of PTP packets + when using the end-to-end delay (E2E) mechansim. The peer + delay mechansim (P2P) is not supported. + + This clock is only useful if your PTP programs are getting + hardware time stamps on the PTP Ethernet packets using the + SO_TIMESTAMPING API. To compile this driver as a module, choose M here: the module will be called ptp_pch. diff --git a/trunk/drivers/ptp/ptp_clock.c b/trunk/drivers/ptp/ptp_clock.c index f519a131238d..1e528b539a07 100644 --- a/trunk/drivers/ptp/ptp_clock.c +++ b/trunk/drivers/ptp/ptp_clock.c @@ -304,6 +304,12 @@ void ptp_clock_event(struct ptp_clock *ptp, struct ptp_clock_event *event) } EXPORT_SYMBOL(ptp_clock_event); +int ptp_clock_index(struct ptp_clock *ptp) +{ + return ptp->index; +} +EXPORT_SYMBOL(ptp_clock_index); + /* module operations */ static void __exit ptp_exit(void) diff --git a/trunk/drivers/ptp/ptp_ixp46x.c b/trunk/drivers/ptp/ptp_ixp46x.c index 6f2782bb5f41..e03c40692b00 100644 --- a/trunk/drivers/ptp/ptp_ixp46x.c +++ b/trunk/drivers/ptp/ptp_ixp46x.c @@ -284,6 +284,7 @@ static void __exit ptp_ixp_exit(void) { free_irq(MASTER_IRQ, &ixp_clock); free_irq(SLAVE_IRQ, &ixp_clock); + ixp46x_phc_index = -1; ptp_clock_unregister(ixp_clock.ptp_clock); } @@ -302,6 +303,8 @@ static int __init ptp_ixp_init(void) if (IS_ERR(ixp_clock.ptp_clock)) return PTR_ERR(ixp_clock.ptp_clock); + ixp46x_phc_index = ptp_clock_index(ixp_clock.ptp_clock); + __raw_writel(DEFAULT_ADDEND, &ixp_clock.regs->addend); __raw_writel(1, &ixp_clock.regs->trgt_lo); __raw_writel(0, &ixp_clock.regs->trgt_hi); diff --git a/trunk/drivers/ptp/ptp_pch.c b/trunk/drivers/ptp/ptp_pch.c index 6fff68020488..3a9c17eced10 100644 --- a/trunk/drivers/ptp/ptp_pch.c +++ b/trunk/drivers/ptp/ptp_pch.c @@ -262,6 +262,7 @@ u64 pch_rx_snap_read(struct pci_dev *pdev) ns = ((u64) hi) << 32; ns |= lo; + ns <<= TICKS_NS_SHIFT; return ns; } @@ -278,6 +279,7 @@ u64 pch_tx_snap_read(struct pci_dev *pdev) ns = ((u64) hi) << 32; ns |= lo; + ns <<= TICKS_NS_SHIFT; return ns; } @@ -307,7 +309,7 @@ static void pch_reset(struct pch_dev *chip) * traffic on the ethernet interface * @addr: dress which contain the column separated address to be used. */ -static int pch_set_station_address(u8 *addr, struct pci_dev *pdev) +int pch_set_station_address(u8 *addr, struct pci_dev *pdev) { s32 i; struct pch_dev *chip = pci_get_drvdata(pdev); @@ -351,6 +353,7 @@ static int pch_set_station_address(u8 *addr, struct pci_dev *pdev) } return 0; } +EXPORT_SYMBOL(pch_set_station_address); /* * Interrupt service routine @@ -650,8 +653,6 @@ pch_probe(struct pci_dev *pdev, const struct pci_device_id *id) iowrite32(1, &chip->regs->trgt_lo); iowrite32(0, &chip->regs->trgt_hi); iowrite32(PCH_TSE_TTIPEND, &chip->regs->event); - /* Version: IEEE1588 v1 and IEEE1588-2008, Mode: All Evwnt, Locked */ - iowrite32(0x80020000, &chip->regs->ch_control); pch_eth_enable_set(chip); diff --git a/trunk/drivers/regulator/88pm8607.c b/trunk/drivers/regulator/88pm8607.c index 28b81ae4cf7f..c3482b954cb7 100644 --- a/trunk/drivers/regulator/88pm8607.c +++ b/trunk/drivers/regulator/88pm8607.c @@ -27,13 +27,8 @@ struct pm8607_regulator_info { unsigned int *vol_table; unsigned int *vol_suspend; - int vol_reg; - int vol_shift; - int vol_nbits; int update_reg; int update_bit; - int enable_reg; - int enable_bit; int slope_double; }; @@ -216,7 +211,7 @@ static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index) struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); int ret = -EINVAL; - if (info->vol_table && (index < (1 << info->vol_nbits))) { + if (info->vol_table && (index < rdev->desc->n_voltages)) { ret = info->vol_table[index]; if (info->slope_double) ret <<= 1; @@ -224,51 +219,16 @@ static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index) return ret; } -static int choose_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) +static int pm8607_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) { struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - int i, ret = -ENOENT; - - if (info->slope_double) { - min_uV = min_uV >> 1; - max_uV = max_uV >> 1; - } - if (info->vol_table) { - for (i = 0; i < (1 << info->vol_nbits); i++) { - if (!info->vol_table[i]) - break; - if ((min_uV <= info->vol_table[i]) - && (max_uV >= info->vol_table[i])) { - ret = i; - break; - } - } - } - if (ret < 0) - pr_err("invalid voltage range (%d %d) uV\n", min_uV, max_uV); - return ret; -} - -static int pm8607_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned *selector) -{ - struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - uint8_t val, mask; + uint8_t val; int ret; - if (min_uV > max_uV) { - pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV); - return -EINVAL; - } + val = (uint8_t)(selector << (ffs(rdev->desc->vsel_mask) - 1)); - ret = choose_voltage(rdev, min_uV, max_uV); - if (ret < 0) - return -EINVAL; - *selector = ret; - val = (uint8_t)(ret << info->vol_shift); - mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; - - ret = pm860x_set_bits(info->i2c, info->vol_reg, mask, val); + ret = pm860x_set_bits(info->i2c, rdev->desc->vsel_reg, + rdev->desc->vsel_mask, val); if (ret) return ret; switch (info->desc.id) { @@ -282,60 +242,16 @@ static int pm8607_set_voltage(struct regulator_dev *rdev, return ret; } -static int pm8607_get_voltage(struct regulator_dev *rdev) -{ - struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - uint8_t val, mask; - int ret; - - ret = pm860x_reg_read(info->i2c, info->vol_reg); - if (ret < 0) - return ret; - - mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; - val = ((unsigned char)ret & mask) >> info->vol_shift; - - return pm8607_list_voltage(rdev, val); -} - -static int pm8607_enable(struct regulator_dev *rdev) -{ - struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - - return pm860x_set_bits(info->i2c, info->enable_reg, - 1 << info->enable_bit, - 1 << info->enable_bit); -} - -static int pm8607_disable(struct regulator_dev *rdev) -{ - struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - - return pm860x_set_bits(info->i2c, info->enable_reg, - 1 << info->enable_bit, 0); -} - -static int pm8607_is_enabled(struct regulator_dev *rdev) -{ - struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - int ret; - - ret = pm860x_reg_read(info->i2c, info->enable_reg); - if (ret < 0) - return ret; - - return !!((unsigned char)ret & (1 << info->enable_bit)); -} - static struct regulator_ops pm8607_regulator_ops = { - .set_voltage = pm8607_set_voltage, - .get_voltage = pm8607_get_voltage, - .enable = pm8607_enable, - .disable = pm8607_disable, - .is_enabled = pm8607_is_enabled, + .list_voltage = pm8607_list_voltage, + .set_voltage_sel = pm8607_set_voltage_sel, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, }; -#define PM8607_DVC(vreg, nbits, ureg, ubit, ereg, ebit) \ +#define PM8607_DVC(vreg, ureg, ubit, ereg, ebit) \ { \ .desc = { \ .name = #vreg, \ @@ -343,20 +259,20 @@ static struct regulator_ops pm8607_regulator_ops = { .type = REGULATOR_VOLTAGE, \ .id = PM8607_ID_##vreg, \ .owner = THIS_MODULE, \ + .n_voltages = ARRAY_SIZE(vreg##_table), \ + .vsel_reg = PM8607_##vreg, \ + .vsel_mask = ARRAY_SIZE(vreg##_table) - 1, \ + .enable_reg = PM8607_##ereg, \ + .enable_mask = 1 << (ebit), \ }, \ - .vol_reg = PM8607_##vreg, \ - .vol_shift = (0), \ - .vol_nbits = (nbits), \ .update_reg = PM8607_##ureg, \ .update_bit = (ubit), \ - .enable_reg = PM8607_##ereg, \ - .enable_bit = (ebit), \ .slope_double = (0), \ .vol_table = (unsigned int *)&vreg##_table, \ .vol_suspend = (unsigned int *)&vreg##_suspend_table, \ } -#define PM8607_LDO(_id, vreg, shift, nbits, ereg, ebit) \ +#define PM8607_LDO(_id, vreg, shift, ereg, ebit) \ { \ .desc = { \ .name = "LDO" #_id, \ @@ -364,35 +280,35 @@ static struct regulator_ops pm8607_regulator_ops = { .type = REGULATOR_VOLTAGE, \ .id = PM8607_ID_LDO##_id, \ .owner = THIS_MODULE, \ + .n_voltages = ARRAY_SIZE(LDO##_id##_table), \ + .vsel_reg = PM8607_##vreg, \ + .vsel_mask = (ARRAY_SIZE(LDO##_id##_table) - 1) << (shift), \ + .enable_reg = PM8607_##ereg, \ + .enable_mask = 1 << (ebit), \ }, \ - .vol_reg = PM8607_##vreg, \ - .vol_shift = (shift), \ - .vol_nbits = (nbits), \ - .enable_reg = PM8607_##ereg, \ - .enable_bit = (ebit), \ .slope_double = (0), \ .vol_table = (unsigned int *)&LDO##_id##_table, \ .vol_suspend = (unsigned int *)&LDO##_id##_suspend_table, \ } static struct pm8607_regulator_info pm8607_regulator_info[] = { - PM8607_DVC(BUCK1, 6, GO, 0, SUPPLIES_EN11, 0), - PM8607_DVC(BUCK2, 6, GO, 1, SUPPLIES_EN11, 1), - PM8607_DVC(BUCK3, 6, GO, 2, SUPPLIES_EN11, 2), - - PM8607_LDO( 1, LDO1, 0, 2, SUPPLIES_EN11, 3), - PM8607_LDO( 2, LDO2, 0, 3, SUPPLIES_EN11, 4), - PM8607_LDO( 3, LDO3, 0, 3, SUPPLIES_EN11, 5), - PM8607_LDO( 4, LDO4, 0, 3, SUPPLIES_EN11, 6), - PM8607_LDO( 5, LDO5, 0, 2, SUPPLIES_EN11, 7), - PM8607_LDO( 6, LDO6, 0, 3, SUPPLIES_EN12, 0), - PM8607_LDO( 7, LDO7, 0, 3, SUPPLIES_EN12, 1), - PM8607_LDO( 8, LDO8, 0, 3, SUPPLIES_EN12, 2), - PM8607_LDO( 9, LDO9, 0, 3, SUPPLIES_EN12, 3), - PM8607_LDO(10, LDO10, 0, 4, SUPPLIES_EN12, 4), - PM8607_LDO(12, LDO12, 0, 4, SUPPLIES_EN12, 5), - PM8607_LDO(13, VIBRATOR_SET, 1, 3, VIBRATOR_SET, 0), - PM8607_LDO(14, LDO14, 0, 3, SUPPLIES_EN12, 6), + PM8607_DVC(BUCK1, GO, 0, SUPPLIES_EN11, 0), + PM8607_DVC(BUCK2, GO, 1, SUPPLIES_EN11, 1), + PM8607_DVC(BUCK3, GO, 2, SUPPLIES_EN11, 2), + + PM8607_LDO(1, LDO1, 0, SUPPLIES_EN11, 3), + PM8607_LDO(2, LDO2, 0, SUPPLIES_EN11, 4), + PM8607_LDO(3, LDO3, 0, SUPPLIES_EN11, 5), + PM8607_LDO(4, LDO4, 0, SUPPLIES_EN11, 6), + PM8607_LDO(5, LDO5, 0, SUPPLIES_EN11, 7), + PM8607_LDO(6, LDO6, 0, SUPPLIES_EN12, 0), + PM8607_LDO(7, LDO7, 0, SUPPLIES_EN12, 1), + PM8607_LDO(8, LDO8, 0, SUPPLIES_EN12, 2), + PM8607_LDO(9, LDO9, 0, SUPPLIES_EN12, 3), + PM8607_LDO(10, LDO10, 0, SUPPLIES_EN12, 4), + PM8607_LDO(12, LDO12, 0, SUPPLIES_EN12, 5), + PM8607_LDO(13, VIBRATOR_SET, 1, VIBRATOR_SET, 0), + PM8607_LDO(14, LDO14, 0, SUPPLIES_EN12, 6), }; static int __devinit pm8607_regulator_probe(struct platform_device *pdev) @@ -400,6 +316,7 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev) struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); struct pm8607_regulator_info *info = NULL; struct regulator_init_data *pdata = pdev->dev.platform_data; + struct regulator_config config = { }; struct resource *res; int i; @@ -425,9 +342,17 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev) if ((i == PM8607_ID_BUCK3) && info->chip->buck3_double) info->slope_double = 1; + config.dev = &pdev->dev; + config.init_data = pdata; + config.driver_data = info; + + if (chip->id == CHIP_PM8607) + config.regmap = chip->regmap; + else + config.regmap = chip->regmap_companion; + /* replace driver_data with info */ - info->regulator = regulator_register(&info->desc, &pdev->dev, - pdata, info, NULL); + info->regulator = regulator_register(&info->desc, &config); if (IS_ERR(info->regulator)) { dev_err(&pdev->dev, "failed to register regulator %s\n", info->desc.name); diff --git a/trunk/drivers/regulator/Kconfig b/trunk/drivers/regulator/Kconfig index 36db5a441eba..c86b8864e411 100644 --- a/trunk/drivers/regulator/Kconfig +++ b/trunk/drivers/regulator/Kconfig @@ -223,6 +223,16 @@ config REGULATOR_PCF50633 Say Y here to support the voltage regulators and convertors on PCF50633 +config REGULATOR_RC5T583 + tristate "RICOH RC5T583 Power regulators" + depends on MFD_RC5T583 + help + Select this option to enable the power regulator of RICOH + PMIC RC5T583. + This driver supports the control of different power rails of device + through regulator interface. The device supports multiple DCDC/LDO + outputs which can be controlled by i2c communication. + config REGULATOR_S5M8767 tristate "Samsung S5M8767A voltage regulator" depends on MFD_S5M_CORE @@ -258,6 +268,18 @@ config REGULATOR_DB8500_PRCMU This driver supports the voltage domain regulators controlled by the DB8500 PRCMU +config REGULATOR_PALMAS + tristate "TI Palmas PMIC Regulators" + depends on MFD_PALMAS + help + If you wish to control the regulators on the Palmas series of + chips say Y here. This will enable support for all the software + controllable SMPS/LDO regulators. + + The regulators available on Palmas series chips vary depending + on the muxing. This is handled automatically in the driver by + reading the mux info from OTP. + config REGULATOR_TPS6105X tristate "TI TPS6105X Power regulators" depends on TPS6105X @@ -268,11 +290,11 @@ config REGULATOR_TPS6105X audio amplifiers. config REGULATOR_TPS62360 - tristate "TI TPS62360 Power Regulator" + tristate "TI TPS6236x Power Regulator" depends on I2C select REGMAP_I2C help - This driver supports TPS62360 voltage regulator chip. This + This driver supports TPS6236x voltage regulator chip. This regulator is meant for processor core supply. This chip is high-frequency synchronous step down dc-dc converter optimized for battery-powered portable applications. @@ -294,6 +316,13 @@ config REGULATOR_TPS6507X three step-down converters and two general-purpose LDO voltage regulators. It supports TI's software based Class-2 SmartReflex implementation. +config REGULATOR_TPS65090 + tristate "TI TPS65090 Power regulator" + depends on MFD_TPS65090 + help + This driver provides support for the voltage regulators on the + TI TPS65090 PMIC. + config REGULATOR_TPS65217 tristate "TI TPS65217 Power regulators" depends on MFD_TPS65217 diff --git a/trunk/drivers/regulator/Makefile b/trunk/drivers/regulator/Makefile index 94b52745e957..977fd46909ab 100644 --- a/trunk/drivers/regulator/Makefile +++ b/trunk/drivers/regulator/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o -obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o @@ -20,6 +19,7 @@ obj-$(CONFIG_REGULATOR_DA903X) += da903x.o obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o +obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o @@ -33,13 +33,16 @@ obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o +obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o +obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o +obj-$(CONFIG_REGULATOR_TPS65090) += tps65090-regulator.o obj-$(CONFIG_REGULATOR_TPS65217) += tps65217-regulator.o obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o diff --git a/trunk/drivers/regulator/aat2870-regulator.c b/trunk/drivers/regulator/aat2870-regulator.c index 9ed5c5d84e12..06776ca945f2 100644 --- a/trunk/drivers/regulator/aat2870-regulator.c +++ b/trunk/drivers/regulator/aat2870-regulator.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -178,6 +177,7 @@ static struct aat2870_regulator *aat2870_get_regulator(int id) static int aat2870_regulator_probe(struct platform_device *pdev) { struct aat2870_regulator *ri; + struct regulator_config config = { 0 }; struct regulator_dev *rdev; ri = aat2870_get_regulator(pdev->id); @@ -187,8 +187,11 @@ static int aat2870_regulator_probe(struct platform_device *pdev) } ri->aat2870 = dev_get_drvdata(pdev->dev.parent); - rdev = regulator_register(&ri->desc, &pdev->dev, - pdev->dev.platform_data, ri, NULL); + config.dev = &pdev->dev; + config.driver_data = ri; + config.init_data = pdev->dev.platform_data; + + rdev = regulator_register(&ri->desc, &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "Failed to register regulator %s\n", ri->desc.name); @@ -231,3 +234,4 @@ module_exit(aat2870_regulator_exit); MODULE_DESCRIPTION("AnalogicTech AAT2870 Regulator"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jin Park "); +MODULE_ALIAS("platform:aat2870-regulator"); diff --git a/trunk/drivers/regulator/ab3100.c b/trunk/drivers/regulator/ab3100.c index 042271aace6a..03f4d9c604ec 100644 --- a/trunk/drivers/regulator/ab3100.c +++ b/trunk/drivers/regulator/ab3100.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -305,53 +304,12 @@ static int ab3100_get_voltage_regulator(struct regulator_dev *reg) return abreg->typ_voltages[regval]; } -static int ab3100_get_best_voltage_index(struct regulator_dev *reg, - int min_uV, int max_uV) -{ - struct ab3100_regulator *abreg = reg->reg_data; - int i; - int bestmatch; - int bestindex; - - /* - * Locate the minimum voltage fitting the criteria on - * this regulator. The switchable voltages are not - * in strict falling order so we need to check them - * all for the best match. - */ - bestmatch = INT_MAX; - bestindex = -1; - for (i = 0; i < abreg->voltages_len; i++) { - if (abreg->typ_voltages[i] <= max_uV && - abreg->typ_voltages[i] >= min_uV && - abreg->typ_voltages[i] < bestmatch) { - bestmatch = abreg->typ_voltages[i]; - bestindex = i; - } - } - - if (bestindex < 0) { - dev_warn(®->dev, "requested %d<=x<=%d uV, out of range!\n", - min_uV, max_uV); - return -EINVAL; - } - return bestindex; -} - -static int ab3100_set_voltage_regulator(struct regulator_dev *reg, - int min_uV, int max_uV, - unsigned *selector) +static int ab3100_set_voltage_regulator_sel(struct regulator_dev *reg, + unsigned selector) { struct ab3100_regulator *abreg = reg->reg_data; u8 regval; int err; - int bestindex; - - bestindex = ab3100_get_best_voltage_index(reg, min_uV, max_uV); - if (bestindex < 0) - return bestindex; - - *selector = bestindex; err = abx500_get_register_interruptible(abreg->dev, 0, abreg->regreg, ®val); @@ -364,7 +322,7 @@ static int ab3100_set_voltage_regulator(struct regulator_dev *reg, /* The highest three bits control the variable regulators */ regval &= ~0xE0; - regval |= (bestindex << 5); + regval |= (selector << 5); err = abx500_set_register_interruptible(abreg->dev, 0, abreg->regreg, regval); @@ -392,7 +350,7 @@ static int ab3100_set_suspend_voltage_regulator(struct regulator_dev *reg, return -EINVAL; /* LDO E and BUCK have special suspend voltages you can set */ - bestindex = ab3100_get_best_voltage_index(reg, uV, uV); + bestindex = regulator_map_voltage_iterate(reg, uV, uV); err = abx500_get_register_interruptible(abreg->dev, 0, targetreg, ®val); @@ -464,7 +422,7 @@ static struct regulator_ops regulator_ops_variable = { .disable = ab3100_disable_regulator, .is_enabled = ab3100_is_enabled_regulator, .get_voltage = ab3100_get_voltage_regulator, - .set_voltage = ab3100_set_voltage_regulator, + .set_voltage_sel = ab3100_set_voltage_regulator_sel, .list_voltage = ab3100_list_voltage_regulator, .enable_time = ab3100_enable_time_regulator, }; @@ -474,7 +432,7 @@ static struct regulator_ops regulator_ops_variable_sleepable = { .disable = ab3100_disable_regulator, .is_enabled = ab3100_is_enabled_regulator, .get_voltage = ab3100_get_voltage_regulator, - .set_voltage = ab3100_set_voltage_regulator, + .set_voltage_sel = ab3100_set_voltage_regulator_sel, .set_suspend_voltage = ab3100_set_suspend_voltage_regulator, .list_voltage = ab3100_list_voltage_regulator, .enable_time = ab3100_enable_time_regulator, @@ -582,6 +540,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = { static int __devinit ab3100_regulators_probe(struct platform_device *pdev) { struct ab3100_platform_data *plfdata = pdev->dev.platform_data; + struct regulator_config config = { }; int err = 0; u8 data; int i; @@ -627,15 +586,15 @@ static int __devinit ab3100_regulators_probe(struct platform_device *pdev) reg->dev = &pdev->dev; reg->plfdata = plfdata; + config.dev = &pdev->dev; + config.driver_data = reg; + config.init_data = &plfdata->reg_constraints[i]; + /* * Register the regulator, pass around * the ab3100_regulator struct */ - rdev = regulator_register(&ab3100_regulator_desc[i], - &pdev->dev, - &plfdata->reg_constraints[i], - reg, NULL); - + rdev = regulator_register(&ab3100_regulator_desc[i], &config); if (IS_ERR(rdev)) { err = PTR_ERR(rdev); dev_err(&pdev->dev, diff --git a/trunk/drivers/regulator/ab8500.c b/trunk/drivers/regulator/ab8500.c index c7ee4c15d6f5..e1b8c54ace5a 100644 --- a/trunk/drivers/regulator/ab8500.c +++ b/trunk/drivers/regulator/ab8500.c @@ -18,9 +18,12 @@ #include #include #include +#include +#include #include #include #include +#include /** * struct ab8500_regulator_info - ab8500 regulator information @@ -234,25 +237,8 @@ static int ab8500_regulator_get_voltage_sel(struct regulator_dev *rdev) return val; } -static int ab8500_get_best_voltage_index(struct regulator_dev *rdev, - int min_uV, int max_uV) -{ - struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - int i; - - /* check the supported voltage */ - for (i = 0; i < info->voltages_len; i++) { - if ((info->voltages[i] >= min_uV) && - (info->voltages[i] <= max_uV)) - return i; - } - - return -EINVAL; -} - -static int ab8500_regulator_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, - unsigned *selector) +static int ab8500_regulator_set_voltage_sel(struct regulator_dev *rdev, + unsigned selector) { int ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); @@ -263,18 +249,8 @@ static int ab8500_regulator_set_voltage(struct regulator_dev *rdev, return -EINVAL; } - /* get the appropriate voltages within the range */ - ret = ab8500_get_best_voltage_index(rdev, min_uV, max_uV); - if (ret < 0) { - dev_err(rdev_get_dev(rdev), - "couldn't get best voltage for regulator\n"); - return ret; - } - - *selector = ret; - /* set the registers for the request */ - regval = (u8)ret; + regval = (u8)selector; ret = abx500_mask_and_set_register_interruptible(info->dev, info->voltage_bank, info->voltage_reg, info->voltage_mask, regval); @@ -319,7 +295,7 @@ static struct regulator_ops ab8500_regulator_ops = { .disable = ab8500_regulator_disable, .is_enabled = ab8500_regulator_is_enabled, .get_voltage_sel = ab8500_regulator_get_voltage_sel, - .set_voltage = ab8500_regulator_set_voltage, + .set_voltage_sel = ab8500_regulator_set_voltage_sel, .list_voltage = ab8500_list_voltage, .enable_time = ab8500_regulator_enable_time, .set_voltage_time_sel = ab8500_regulator_set_voltage_time_sel, @@ -735,12 +711,139 @@ static struct ab8500_reg_init ab8500_reg_init[] = { REG_INIT(AB8500_REGUCTRLDISCH2, 0x04, 0x44, 0x16), }; +static __devinit int +ab8500_regulator_init_registers(struct platform_device *pdev, int id, int value) +{ + int err; + + if (value & ~ab8500_reg_init[id].mask) { + dev_err(&pdev->dev, + "Configuration error: value outside mask.\n"); + return -EINVAL; + } + + err = abx500_mask_and_set_register_interruptible( + &pdev->dev, + ab8500_reg_init[id].bank, + ab8500_reg_init[id].addr, + ab8500_reg_init[id].mask, + value); + if (err < 0) { + dev_err(&pdev->dev, + "Failed to initialize 0x%02x, 0x%02x.\n", + ab8500_reg_init[id].bank, + ab8500_reg_init[id].addr); + return err; + } + + dev_vdbg(&pdev->dev, + "init: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", + ab8500_reg_init[id].bank, + ab8500_reg_init[id].addr, + ab8500_reg_init[id].mask, + value); + + return 0; +} + +static __devinit int ab8500_regulator_register(struct platform_device *pdev, + struct regulator_init_data *init_data, + int id, + struct device_node *np) +{ + struct ab8500_regulator_info *info = NULL; + struct regulator_config config = { }; + int err; + + /* assign per-regulator data */ + info = &ab8500_regulator_info[id]; + info->dev = &pdev->dev; + + config.dev = &pdev->dev; + config.init_data = init_data; + config.driver_data = info; + config.of_node = np; + + /* fix for hardware before ab8500v2.0 */ + if (abx500_get_chip_id(info->dev) < 0x20) { + if (info->desc.id == AB8500_LDO_AUX3) { + info->desc.n_voltages = + ARRAY_SIZE(ldo_vauxn_voltages); + info->voltages = ldo_vauxn_voltages; + info->voltages_len = + ARRAY_SIZE(ldo_vauxn_voltages); + info->voltage_mask = 0xf; + } + } + + /* register regulator with framework */ + info->regulator = regulator_register(&info->desc, &config); + if (IS_ERR(info->regulator)) { + err = PTR_ERR(info->regulator); + dev_err(&pdev->dev, "failed to register regulator %s\n", + info->desc.name); + /* when we fail, un-register all earlier regulators */ + while (--id >= 0) { + info = &ab8500_regulator_info[id]; + regulator_unregister(info->regulator); + } + return err; + } + + return 0; +} + +static struct of_regulator_match ab8500_regulator_matches[] = { + { .name = "LDO-AUX1", .driver_data = (void *) AB8500_LDO_AUX1, }, + { .name = "LDO-AUX2", .driver_data = (void *) AB8500_LDO_AUX2, }, + { .name = "LDO-AUX3", .driver_data = (void *) AB8500_LDO_AUX3, }, + { .name = "LDO-INTCORE", .driver_data = (void *) AB8500_LDO_INTCORE, }, + { .name = "LDO-TVOUT", .driver_data = (void *) AB8500_LDO_TVOUT, }, + { .name = "LDO-USB", .driver_data = (void *) AB8500_LDO_USB, }, + { .name = "LDO-AUDIO", .driver_data = (void *) AB8500_LDO_AUDIO, }, + { .name = "LDO-ANAMIC1", .driver_data = (void *) AB8500_LDO_ANAMIC1, }, + { .name = "LDO-ANAMIC2", .driver_data = (void *) AB8500_LDO_ANAMIC2, }, + { .name = "LDO-DMIC", .driver_data = (void *) AB8500_LDO_DMIC, }, + { .name = "LDO-ANA", .driver_data = (void *) AB8500_LDO_ANA, }, +}; + +static __devinit int +ab8500_regulator_of_probe(struct platform_device *pdev, struct device_node *np) +{ + int err, i; + + for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) { + err = ab8500_regulator_register( + pdev, ab8500_regulator_matches[i].init_data, + i, ab8500_regulator_matches[i].of_node); + if (err) + return err; + } + + return 0; +} + static __devinit int ab8500_regulator_probe(struct platform_device *pdev) { struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); struct ab8500_platform_data *pdata; + struct device_node *np = pdev->dev.of_node; int i, err; + if (np) { + err = of_regulator_match(&pdev->dev, np, + ab8500_regulator_matches, + ARRAY_SIZE(ab8500_regulator_matches)); + if (err < 0) { + dev_err(&pdev->dev, + "Error parsing regulator init data: %d\n", err); + return err; + } + + err = ab8500_regulator_of_probe(pdev, np); + return err; + } + if (!ab8500) { dev_err(&pdev->dev, "null mfd parent\n"); return -EINVAL; @@ -759,8 +862,7 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) /* initialize registers */ for (i = 0; i < pdata->num_regulator_reg_init; i++) { - int id; - u8 value; + int id, value; id = pdata->regulator_reg_init[i].id; value = pdata->regulator_reg_init[i].value; @@ -771,70 +873,17 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) "Configuration error: id outside range.\n"); return -EINVAL; } - if (value & ~ab8500_reg_init[id].mask) { - dev_err(&pdev->dev, - "Configuration error: value outside mask.\n"); - return -EINVAL; - } - /* initialize register */ - err = abx500_mask_and_set_register_interruptible(&pdev->dev, - ab8500_reg_init[id].bank, - ab8500_reg_init[id].addr, - ab8500_reg_init[id].mask, - value); - if (err < 0) { - dev_err(&pdev->dev, - "Failed to initialize 0x%02x, 0x%02x.\n", - ab8500_reg_init[id].bank, - ab8500_reg_init[id].addr); + err = ab8500_regulator_init_registers(pdev, id, value); + if (err < 0) return err; - } - dev_vdbg(&pdev->dev, - " init: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", - ab8500_reg_init[id].bank, - ab8500_reg_init[id].addr, - ab8500_reg_init[id].mask, - value); } /* register all regulators */ for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) { - struct ab8500_regulator_info *info = NULL; - - /* assign per-regulator data */ - info = &ab8500_regulator_info[i]; - info->dev = &pdev->dev; - - /* fix for hardware before ab8500v2.0 */ - if (abx500_get_chip_id(info->dev) < 0x20) { - if (info->desc.id == AB8500_LDO_AUX3) { - info->desc.n_voltages = - ARRAY_SIZE(ldo_vauxn_voltages); - info->voltages = ldo_vauxn_voltages; - info->voltages_len = - ARRAY_SIZE(ldo_vauxn_voltages); - info->voltage_mask = 0xf; - } - } - - /* register regulator with framework */ - info->regulator = regulator_register(&info->desc, &pdev->dev, - &pdata->regulator[i], info, NULL); - if (IS_ERR(info->regulator)) { - err = PTR_ERR(info->regulator); - dev_err(&pdev->dev, "failed to register regulator %s\n", - info->desc.name); - /* when we fail, un-register all earlier regulators */ - while (--i >= 0) { - info = &ab8500_regulator_info[i]; - regulator_unregister(info->regulator); - } + err = ab8500_regulator_register(pdev, &pdata->regulator[i], i, NULL); + if (err < 0) return err; - } - - dev_vdbg(rdev_get_dev(info->regulator), - "%s-probed\n", info->desc.name); } return 0; @@ -857,12 +906,18 @@ static __devexit int ab8500_regulator_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id ab8500_regulator_match[] = { + { .compatible = "stericsson,ab8500-regulator", }, + {} +}; + static struct platform_driver ab8500_regulator_driver = { .probe = ab8500_regulator_probe, .remove = __devexit_p(ab8500_regulator_remove), .driver = { .name = "ab8500-regulator", .owner = THIS_MODULE, + .of_match_table = ab8500_regulator_match, }, }; diff --git a/trunk/drivers/regulator/ad5398.c b/trunk/drivers/regulator/ad5398.c index 26d23adfc66f..46d05f38baf8 100644 --- a/trunk/drivers/regulator/ad5398.c +++ b/trunk/drivers/regulator/ad5398.c @@ -99,8 +99,8 @@ static int ad5398_set_current_limit(struct regulator_dev *rdev, int min_uA, int if (ad5398_calc_current(chip, selector) > max_uA) return -EINVAL; - dev_dbg(&client->dev, "changing current %dmA\n", - ad5398_calc_current(chip, selector) / 1000); + dev_dbg(&client->dev, "changing current %duA\n", + ad5398_calc_current(chip, selector)); /* read chip enable bit */ ret = ad5398_read_reg(client, &data); @@ -184,7 +184,7 @@ static struct regulator_ops ad5398_ops = { .is_enabled = ad5398_is_enabled, }; -static struct regulator_desc ad5398_reg = { +static const struct regulator_desc ad5398_reg = { .name = "isink", .id = 0, .ops = &ad5398_ops, @@ -212,6 +212,7 @@ static int __devinit ad5398_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct regulator_init_data *init_data = client->dev.platform_data; + struct regulator_config config = { }; struct ad5398_chip_info *chip; const struct ad5398_current_data_format *df = (struct ad5398_current_data_format *)id->driver_data; @@ -220,10 +221,14 @@ static int __devinit ad5398_probe(struct i2c_client *client, if (!init_data) return -EINVAL; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; + config.dev = &client->dev; + config.init_data = init_data; + config.driver_data = chip; + chip->client = client; chip->min_uA = df->min_uA; @@ -232,8 +237,7 @@ static int __devinit ad5398_probe(struct i2c_client *client, chip->current_offset = df->current_offset; chip->current_mask = (chip->current_level - 1) << chip->current_offset; - chip->rdev = regulator_register(&ad5398_reg, &client->dev, - init_data, chip, NULL); + chip->rdev = regulator_register(&ad5398_reg, &config); if (IS_ERR(chip->rdev)) { ret = PTR_ERR(chip->rdev); dev_err(&client->dev, "failed to register %s %s\n", @@ -246,7 +250,6 @@ static int __devinit ad5398_probe(struct i2c_client *client, return 0; err: - kfree(chip); return ret; } @@ -255,8 +258,6 @@ static int __devexit ad5398_remove(struct i2c_client *client) struct ad5398_chip_info *chip = i2c_get_clientdata(client); regulator_unregister(chip->rdev); - kfree(chip); - return 0; } diff --git a/trunk/drivers/regulator/anatop-regulator.c b/trunk/drivers/regulator/anatop-regulator.c index 81fd606e47bc..49b2112b0486 100644 --- a/trunk/drivers/regulator/anatop-regulator.c +++ b/trunk/drivers/regulator/anatop-regulator.c @@ -122,6 +122,7 @@ static int __devinit anatop_regulator_probe(struct platform_device *pdev) struct anatop_regulator *sreg; struct regulator_init_data *initdata; struct anatop *anatopmfd = dev_get_drvdata(pdev->dev.parent); + struct regulator_config config = { }; int ret = 0; initdata = of_get_regulator_init_data(dev, np); @@ -178,9 +179,13 @@ static int __devinit anatop_regulator_probe(struct platform_device *pdev) rdesc->n_voltages = (sreg->max_voltage - sreg->min_voltage) / 25000 + 1; + config.dev = &pdev->dev; + config.init_data = initdata; + config.driver_data = sreg; + config.of_node = pdev->dev.of_node; + /* register regulator */ - rdev = regulator_register(rdesc, dev, - initdata, sreg, pdev->dev.of_node); + rdev = regulator_register(rdesc, &config); if (IS_ERR(rdev)) { dev_err(dev, "failed to register %s\n", rdesc->name); diff --git a/trunk/drivers/regulator/core.c b/trunk/drivers/regulator/core.c index 046fb1bd8619..7584a74eec8a 100644 --- a/trunk/drivers/regulator/core.c +++ b/trunk/drivers/regulator/core.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -74,6 +75,7 @@ struct regulator_map { struct regulator { struct device *dev; struct list_head list; + unsigned int always_on:1; int uA_load; int min_uV; int max_uV; @@ -155,6 +157,17 @@ static struct device_node *of_get_regulator(struct device *dev, const char *supp return regnode; } +static int _regulator_can_change_status(struct regulator_dev *rdev) +{ + if (!rdev->constraints) + return 0; + + if (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_STATUS) + return 1; + else + return 0; +} + /* Platform voltage constraint check */ static int regulator_check_voltage(struct regulator_dev *rdev, int *min_uV, int *max_uV) @@ -649,7 +662,7 @@ static void drms_uA_update(struct regulator_dev *rdev) /* get input voltage */ input_uV = 0; if (rdev->supply) - input_uV = _regulator_get_voltage(rdev); + input_uV = regulator_get_voltage(rdev->supply); if (input_uV <= 0) input_uV = rdev->constraints->input_uV; if (input_uV <= 0) @@ -673,17 +686,14 @@ static int suspend_set_state(struct regulator_dev *rdev, struct regulator_state *rstate) { int ret = 0; - bool can_set_state; - - can_set_state = rdev->desc->ops->set_suspend_enable && - rdev->desc->ops->set_suspend_disable; /* If we have no suspend mode configration don't set anything; - * only warn if the driver actually makes the suspend mode - * configurable. + * only warn if the driver implements set_suspend_voltage or + * set_suspend_mode callback. */ if (!rstate->enabled && !rstate->disabled) { - if (can_set_state) + if (rdev->desc->ops->set_suspend_voltage || + rdev->desc->ops->set_suspend_mode) rdev_warn(rdev, "No configuration\n"); return 0; } @@ -693,15 +703,13 @@ static int suspend_set_state(struct regulator_dev *rdev, return -EINVAL; } - if (!can_set_state) { - rdev_err(rdev, "no way to set suspend state\n"); - return -EINVAL; - } - - if (rstate->enabled) + if (rstate->enabled && rdev->desc->ops->set_suspend_enable) ret = rdev->desc->ops->set_suspend_enable(rdev); - else + else if (rstate->disabled && rdev->desc->ops->set_suspend_disable) ret = rdev->desc->ops->set_suspend_disable(rdev); + else /* OK if set_suspend_enable or set_suspend_disable is NULL */ + ret = 0; + if (ret < 0) { rdev_err(rdev, "failed to enabled/disable\n"); return ret; @@ -1146,6 +1154,15 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, ®ulator->max_uV); } + /* + * Check now if the regulator is an always on regulator - if + * it is then we don't need to do nearly so much work for + * enable/disable calls. + */ + if (!_regulator_can_change_status(rdev) && + _regulator_is_enabled(rdev)) + regulator->always_on = true; + mutex_unlock(&rdev->mutex); return regulator; link_name_err: @@ -1169,26 +1186,52 @@ static int _regulator_get_enable_time(struct regulator_dev *rdev) } static struct regulator_dev *regulator_dev_lookup(struct device *dev, - const char *supply) + const char *supply, + int *ret) { struct regulator_dev *r; struct device_node *node; + struct regulator_map *map; + const char *devname = NULL; /* first do a dt based lookup */ if (dev && dev->of_node) { node = of_get_regulator(dev, supply); - if (node) + if (node) { list_for_each_entry(r, ®ulator_list, list) if (r->dev.parent && node == r->dev.of_node) return r; + } else { + /* + * If we couldn't even get the node then it's + * not just that the device didn't register + * yet, there's no node and we'll never + * succeed. + */ + *ret = -ENODEV; + } } /* if not found, try doing it non-dt way */ + if (dev) + devname = dev_name(dev); + list_for_each_entry(r, ®ulator_list, list) if (strcmp(rdev_get_name(r), supply) == 0) return r; + list_for_each_entry(map, ®ulator_map_list, list) { + /* If the mapping has a device set up it must match */ + if (map->dev_name && + (!devname || strcmp(map->dev_name, devname))) + continue; + + if (strcmp(map->supply, supply) == 0) + return map->regulator; + } + + return NULL; } @@ -1197,7 +1240,6 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, int exclusive) { struct regulator_dev *rdev; - struct regulator_map *map; struct regulator *regulator = ERR_PTR(-EPROBE_DEFER); const char *devname = NULL; int ret; @@ -1212,22 +1254,10 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, mutex_lock(®ulator_list_mutex); - rdev = regulator_dev_lookup(dev, id); + rdev = regulator_dev_lookup(dev, id, &ret); if (rdev) goto found; - list_for_each_entry(map, ®ulator_map_list, list) { - /* If the mapping has a device set up it must match */ - if (map->dev_name && - (!devname || strcmp(map->dev_name, devname))) - continue; - - if (strcmp(map->supply, id) == 0) { - rdev = map->regulator; - goto found; - } - } - if (board_wants_dummy_regulator) { rdev = dummy_regulator_rdev; goto found; @@ -1438,17 +1468,6 @@ void devm_regulator_put(struct regulator *regulator) } EXPORT_SYMBOL_GPL(devm_regulator_put); -static int _regulator_can_change_status(struct regulator_dev *rdev) -{ - if (!rdev->constraints) - return 0; - - if (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_STATUS) - return 1; - else - return 0; -} - /* locks held by regulator_enable() */ static int _regulator_enable(struct regulator_dev *rdev) { @@ -1528,6 +1547,9 @@ int regulator_enable(struct regulator *regulator) struct regulator_dev *rdev = regulator->rdev; int ret = 0; + if (regulator->always_on) + return 0; + if (rdev->supply) { ret = regulator_enable(rdev->supply); if (ret != 0) @@ -1606,6 +1628,9 @@ int regulator_disable(struct regulator *regulator) struct regulator_dev *rdev = regulator->rdev; int ret = 0; + if (regulator->always_on) + return 0; + mutex_lock(&rdev->mutex); ret = _regulator_disable(rdev); mutex_unlock(&rdev->mutex); @@ -1714,6 +1739,9 @@ int regulator_disable_deferred(struct regulator *regulator, int ms) struct regulator_dev *rdev = regulator->rdev; int ret; + if (regulator->always_on) + return 0; + mutex_lock(&rdev->mutex); rdev->deferred_disables++; mutex_unlock(&rdev->mutex); @@ -1727,6 +1755,61 @@ int regulator_disable_deferred(struct regulator *regulator, int ms) } EXPORT_SYMBOL_GPL(regulator_disable_deferred); +/** + * regulator_is_enabled_regmap - standard is_enabled() for regmap users + * + * @rdev: regulator to operate on + * + * Regulators that use regmap for their register I/O can set the + * enable_reg and enable_mask fields in their descriptor and then use + * this as their is_enabled operation, saving some code. + */ +int regulator_is_enabled_regmap(struct regulator_dev *rdev) +{ + unsigned int val; + int ret; + + ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val); + if (ret != 0) + return ret; + + return (val & rdev->desc->enable_mask) != 0; +} +EXPORT_SYMBOL_GPL(regulator_is_enabled_regmap); + +/** + * regulator_enable_regmap - standard enable() for regmap users + * + * @rdev: regulator to operate on + * + * Regulators that use regmap for their register I/O can set the + * enable_reg and enable_mask fields in their descriptor and then use + * this as their enable() operation, saving some code. + */ +int regulator_enable_regmap(struct regulator_dev *rdev) +{ + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, + rdev->desc->enable_mask); +} +EXPORT_SYMBOL_GPL(regulator_enable_regmap); + +/** + * regulator_disable_regmap - standard disable() for regmap users + * + * @rdev: regulator to operate on + * + * Regulators that use regmap for their register I/O can set the + * enable_reg and enable_mask fields in their descriptor and then use + * this as their disable() operation, saving some code. + */ +int regulator_disable_regmap(struct regulator_dev *rdev) +{ + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, 0); +} +EXPORT_SYMBOL_GPL(regulator_disable_regmap); + static int _regulator_is_enabled(struct regulator_dev *rdev) { /* If we don't know then assume that the regulator is always on */ @@ -1752,6 +1835,9 @@ int regulator_is_enabled(struct regulator *regulator) { int ret; + if (regulator->always_on) + return 1; + mutex_lock(®ulator->rdev->mutex); ret = _regulator_is_enabled(regulator->rdev); mutex_unlock(®ulator->rdev->mutex); @@ -1776,6 +1862,26 @@ int regulator_count_voltages(struct regulator *regulator) } EXPORT_SYMBOL_GPL(regulator_count_voltages); +/** + * regulator_list_voltage_linear - List voltages with simple calculation + * + * @rdev: Regulator device + * @selector: Selector to convert into a voltage + * + * Regulators with a simple linear mapping between voltages and + * selectors can set min_uV and uV_step in the regulator descriptor + * and then use this function as their list_voltage() operation, + */ +int regulator_list_voltage_linear(struct regulator_dev *rdev, + unsigned int selector) +{ + if (selector >= rdev->desc->n_voltages) + return -EINVAL; + + return rdev->desc->min_uV + (rdev->desc->uV_step * selector); +} +EXPORT_SYMBOL_GPL(regulator_list_voltage_linear); + /** * regulator_list_voltage - enumerate supported voltages * @regulator: regulator source @@ -1840,75 +1946,183 @@ int regulator_is_supported_voltage(struct regulator *regulator, } EXPORT_SYMBOL_GPL(regulator_is_supported_voltage); +/** + * regulator_get_voltage_sel_regmap - standard get_voltage_sel for regmap users + * + * @rdev: regulator to operate on + * + * Regulators that use regmap for their register I/O can set the + * vsel_reg and vsel_mask fields in their descriptor and then use this + * as their get_voltage_vsel operation, saving some code. + */ +int regulator_get_voltage_sel_regmap(struct regulator_dev *rdev) +{ + unsigned int val; + int ret; + + ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val); + if (ret != 0) + return ret; + + val &= rdev->desc->vsel_mask; + val >>= ffs(rdev->desc->vsel_mask) - 1; + + return val; +} +EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_regmap); + +/** + * regulator_set_voltage_sel_regmap - standard set_voltage_sel for regmap users + * + * @rdev: regulator to operate on + * @sel: Selector to set + * + * Regulators that use regmap for their register I/O can set the + * vsel_reg and vsel_mask fields in their descriptor and then use this + * as their set_voltage_vsel operation, saving some code. + */ +int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel) +{ + sel <<= ffs(rdev->desc->vsel_mask) - 1; + + return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, + rdev->desc->vsel_mask, sel); +} +EXPORT_SYMBOL_GPL(regulator_set_voltage_sel_regmap); + +/** + * regulator_map_voltage_iterate - map_voltage() based on list_voltage() + * + * @rdev: Regulator to operate on + * @min_uV: Lower bound for voltage + * @max_uV: Upper bound for voltage + * + * Drivers implementing set_voltage_sel() and list_voltage() can use + * this as their map_voltage() operation. It will find a suitable + * voltage by calling list_voltage() until it gets something in bounds + * for the requested voltages. + */ +int regulator_map_voltage_iterate(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + int best_val = INT_MAX; + int selector = 0; + int i, ret; + + /* Find the smallest voltage that falls within the specified + * range. + */ + for (i = 0; i < rdev->desc->n_voltages; i++) { + ret = rdev->desc->ops->list_voltage(rdev, i); + if (ret < 0) + continue; + + if (ret < best_val && ret >= min_uV && ret <= max_uV) { + best_val = ret; + selector = i; + } + } + + if (best_val != INT_MAX) + return selector; + else + return -EINVAL; +} +EXPORT_SYMBOL_GPL(regulator_map_voltage_iterate); + +/** + * regulator_map_voltage_linear - map_voltage() for simple linear mappings + * + * @rdev: Regulator to operate on + * @min_uV: Lower bound for voltage + * @max_uV: Upper bound for voltage + * + * Drivers providing min_uV and uV_step in their regulator_desc can + * use this as their map_voltage() operation. + */ +int regulator_map_voltage_linear(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + int ret, voltage; + + if (!rdev->desc->uV_step) { + BUG_ON(!rdev->desc->uV_step); + return -EINVAL; + } + + ret = DIV_ROUND_UP(min_uV - rdev->desc->min_uV, rdev->desc->uV_step); + if (ret < 0) + return ret; + + /* Map back into a voltage to verify we're still in bounds */ + voltage = rdev->desc->ops->list_voltage(rdev, ret); + if (voltage < min_uV || voltage > max_uV) + return -EINVAL; + + return ret; +} +EXPORT_SYMBOL_GPL(regulator_map_voltage_linear); + static int _regulator_do_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) { int ret; int delay = 0; + int best_val; unsigned int selector; + int old_selector = -1; trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV); min_uV += rdev->constraints->uV_offset; max_uV += rdev->constraints->uV_offset; + /* + * If we can't obtain the old selector there is not enough + * info to call set_voltage_time_sel(). + */ + if (rdev->desc->ops->set_voltage_time_sel && + rdev->desc->ops->get_voltage_sel) { + old_selector = rdev->desc->ops->get_voltage_sel(rdev); + if (old_selector < 0) + return old_selector; + } + if (rdev->desc->ops->set_voltage) { ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV, &selector); - - if (rdev->desc->ops->list_voltage) - selector = rdev->desc->ops->list_voltage(rdev, - selector); - else - selector = -1; } else if (rdev->desc->ops->set_voltage_sel) { - int best_val = INT_MAX; - int i; - - selector = 0; - - /* Find the smallest voltage that falls within the specified - * range. - */ - for (i = 0; i < rdev->desc->n_voltages; i++) { - ret = rdev->desc->ops->list_voltage(rdev, i); - if (ret < 0) - continue; + if (rdev->desc->ops->map_voltage) + ret = rdev->desc->ops->map_voltage(rdev, min_uV, + max_uV); + else + ret = regulator_map_voltage_iterate(rdev, min_uV, + max_uV); - if (ret < best_val && ret >= min_uV && ret <= max_uV) { - best_val = ret; - selector = i; - } + if (ret >= 0) { + selector = ret; + ret = rdev->desc->ops->set_voltage_sel(rdev, ret); } + } else { + ret = -EINVAL; + } - /* - * If we can't obtain the old selector there is not enough - * info to call set_voltage_time_sel(). - */ - if (rdev->desc->ops->set_voltage_time_sel && - rdev->desc->ops->get_voltage_sel) { - unsigned int old_selector = 0; + if (rdev->desc->ops->list_voltage) + best_val = rdev->desc->ops->list_voltage(rdev, selector); + else + best_val = -1; - ret = rdev->desc->ops->get_voltage_sel(rdev); - if (ret < 0) - return ret; - old_selector = ret; - ret = rdev->desc->ops->set_voltage_time_sel(rdev, - old_selector, selector); - if (ret < 0) - rdev_warn(rdev, "set_voltage_time_sel() failed: %d\n", ret); - else - delay = ret; - } + /* Call set_voltage_time_sel if successfully obtained old_selector */ + if (ret == 0 && old_selector >= 0 && + rdev->desc->ops->set_voltage_time_sel) { - if (best_val != INT_MAX) { - ret = rdev->desc->ops->set_voltage_sel(rdev, selector); - selector = best_val; - } else { - ret = -EINVAL; + delay = rdev->desc->ops->set_voltage_time_sel(rdev, + old_selector, selector); + if (delay < 0) { + rdev_warn(rdev, "set_voltage_time_sel() failed: %d\n", + delay); + delay = 0; } - } else { - ret = -EINVAL; } /* Insert any necessary delays */ @@ -1923,7 +2137,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, NULL); - trace_regulator_set_voltage_complete(rdev_get_name(rdev), selector); + trace_regulator_set_voltage_complete(rdev_get_name(rdev), best_val); return ret; } @@ -2327,6 +2541,9 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) */ ret = -EINVAL; + if (!rdev->desc->ops->set_mode) + goto out; + /* get output voltage */ output_uV = _regulator_get_voltage(rdev); if (output_uV <= 0) { @@ -2528,9 +2745,13 @@ int regulator_bulk_enable(int num_consumers, int i; int ret = 0; - for (i = 0; i < num_consumers; i++) - async_schedule_domain(regulator_bulk_enable_async, - &consumers[i], &async_domain); + for (i = 0; i < num_consumers; i++) { + if (consumers[i].consumer->always_on) + consumers[i].ret = 0; + else + async_schedule_domain(regulator_bulk_enable_async, + &consumers[i], &async_domain); + } async_synchronize_full_domain(&async_domain); @@ -2569,7 +2790,7 @@ int regulator_bulk_disable(int num_consumers, struct regulator_bulk_data *consumers) { int i; - int ret; + int ret, r; for (i = num_consumers - 1; i >= 0; --i) { ret = regulator_disable(consumers[i].consumer); @@ -2581,8 +2802,12 @@ int regulator_bulk_disable(int num_consumers, err: pr_err("Failed to disable %s: %d\n", consumers[i].supply, ret); - for (++i; i < num_consumers; ++i) - regulator_enable(consumers[i].consumer); + for (++i; i < num_consumers; ++i) { + r = regulator_enable(consumers[i].consumer); + if (r != 0) + pr_err("Failed to reename %s: %d\n", + consumers[i].supply, r); + } return ret; } @@ -2759,10 +2984,6 @@ static int add_regulator_attributes(struct regulator_dev *rdev) return status; } - /* suspend mode constraints need multiple supporting methods */ - if (!(ops->set_suspend_enable && ops->set_suspend_disable)) - return status; - status = device_create_file(dev, &dev_attr_suspend_standby_state); if (status < 0) return status; @@ -2823,28 +3044,29 @@ static void rdev_init_debugfs(struct regulator_dev *rdev) /** * regulator_register - register regulator * @regulator_desc: regulator to register - * @dev: struct device for the regulator - * @init_data: platform provided init data, passed through by driver - * @driver_data: private regulator data - * @of_node: OpenFirmware node to parse for device tree bindings (may be - * NULL). + * @config: runtime configuration for regulator * * Called by regulator drivers to register a regulator. * Returns 0 on success. */ -struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, - struct device *dev, const struct regulator_init_data *init_data, - void *driver_data, struct device_node *of_node) +struct regulator_dev * +regulator_register(const struct regulator_desc *regulator_desc, + const struct regulator_config *config) { const struct regulation_constraints *constraints = NULL; + const struct regulator_init_data *init_data; static atomic_t regulator_no = ATOMIC_INIT(0); struct regulator_dev *rdev; + struct device *dev; int ret, i; const char *supply = NULL; - if (regulator_desc == NULL) + if (regulator_desc == NULL || config == NULL) return ERR_PTR(-EINVAL); + dev = config->dev; + WARN_ON(!dev); + if (regulator_desc->name == NULL || regulator_desc->ops == NULL) return ERR_PTR(-EINVAL); @@ -2868,6 +3090,8 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, return ERR_PTR(-EINVAL); } + init_data = config->init_data; + rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL); if (rdev == NULL) return ERR_PTR(-ENOMEM); @@ -2875,9 +3099,10 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, mutex_lock(®ulator_list_mutex); mutex_init(&rdev->mutex); - rdev->reg_data = driver_data; + rdev->reg_data = config->driver_data; rdev->owner = regulator_desc->owner; rdev->desc = regulator_desc; + rdev->regmap = config->regmap; INIT_LIST_HEAD(&rdev->consumer_list); INIT_LIST_HEAD(&rdev->list); BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier); @@ -2892,7 +3117,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, /* register with sysfs */ rdev->dev.class = ®ulator_class; - rdev->dev.of_node = of_node; + rdev->dev.of_node = config->of_node; rdev->dev.parent = dev; dev_set_name(&rdev->dev, "regulator.%d", atomic_inc_return(®ulator_no) - 1); @@ -2925,7 +3150,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, if (supply) { struct regulator_dev *r; - r = regulator_dev_lookup(dev, supply); + r = regulator_dev_lookup(dev, supply, &ret); if (!r) { dev_err(dev, "Failed to find supply %s\n", supply); @@ -2938,8 +3163,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, goto scrub; /* Enable supply if rail is enabled */ - if (rdev->desc->ops->is_enabled && - rdev->desc->ops->is_enabled(rdev)) { + if (_regulator_is_enabled(rdev)) { ret = regulator_enable(rdev->supply); if (ret < 0) goto scrub; @@ -2971,6 +3195,8 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, unset_regulator_supplies(rdev); scrub: + if (rdev->supply) + regulator_put(rdev->supply); kfree(rdev->constraints); device_unregister(&rdev->dev); /* device core frees rdev */ @@ -3069,7 +3295,7 @@ int regulator_suspend_finish(void) goto unlock; if (!ops->disable) goto unlock; - if (ops->is_enabled && !ops->is_enabled(rdev)) + if (!_regulator_is_enabled(rdev)) goto unlock; error = ops->disable(rdev); diff --git a/trunk/drivers/regulator/da903x.c b/trunk/drivers/regulator/da903x.c index 1851f0929ef0..1005f5f7e603 100644 --- a/trunk/drivers/regulator/da903x.c +++ b/trunk/drivers/regulator/da903x.c @@ -76,9 +76,7 @@ struct da903x_regulator_info { struct regulator_desc desc; - int min_uV; int max_uV; - int step_uV; int vol_reg; int vol_shift; int vol_nbits; @@ -88,10 +86,6 @@ struct da903x_regulator_info { int enable_bit; }; -static int da9034_ldo12_data[] = { 1700, 1750, 1800, 1850, 1900, 1950, - 2000, 2050, 2700, 2750, 2800, 2850, - 2900, 2950, 3000, 3050 }; - static inline struct device *to_da903x_dev(struct regulator_dev *rdev) { return rdev_get_dev(rdev)->parent->parent; @@ -100,34 +94,26 @@ static inline struct device *to_da903x_dev(struct regulator_dev *rdev) static inline int check_range(struct da903x_regulator_info *info, int min_uV, int max_uV) { - if (min_uV < info->min_uV || min_uV > info->max_uV) + if (min_uV < info->desc.min_uV || min_uV > info->max_uV) return -EINVAL; return 0; } /* DA9030/DA9034 common operations */ -static int da903x_set_ldo_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned *selector) +static int da903x_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) { struct da903x_regulator_info *info = rdev_get_drvdata(rdev); struct device *da9034_dev = to_da903x_dev(rdev); uint8_t val, mask; - if (check_range(info, min_uV, max_uV)) { - pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV); - return -EINVAL; - } - - val = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV); - *selector = val; - val <<= info->vol_shift; + val = selector << info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; return da903x_update(da9034_dev, info->vol_reg, val, mask); } -static int da903x_get_voltage(struct regulator_dev *rdev) +static int da903x_get_voltage_sel(struct regulator_dev *rdev) { struct da903x_regulator_info *info = rdev_get_drvdata(rdev); struct device *da9034_dev = to_da903x_dev(rdev); @@ -141,7 +127,7 @@ static int da903x_get_voltage(struct regulator_dev *rdev) mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; val = (val & mask) >> info->vol_shift; - return info->min_uV + info->step_uV * val; + return val; } static int da903x_enable(struct regulator_dev *rdev) @@ -176,35 +162,16 @@ static int da903x_is_enabled(struct regulator_dev *rdev) return !!(reg_val & (1 << info->enable_bit)); } -static int da903x_list_voltage(struct regulator_dev *rdev, unsigned selector) -{ - struct da903x_regulator_info *info = rdev_get_drvdata(rdev); - int ret; - - ret = info->min_uV + info->step_uV * selector; - if (ret > info->max_uV) - return -EINVAL; - return ret; -} - /* DA9030 specific operations */ -static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, - unsigned *selector) +static int da9030_set_ldo1_15_voltage_sel(struct regulator_dev *rdev, + unsigned selector) { struct da903x_regulator_info *info = rdev_get_drvdata(rdev); struct device *da903x_dev = to_da903x_dev(rdev); uint8_t val, mask; int ret; - if (check_range(info, min_uV, max_uV)) { - pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV); - return -EINVAL; - } - - val = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV); - *selector = val; - val <<= info->vol_shift; + val = selector << info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; val |= DA9030_LDO_UNLOCK; /* have to set UNLOCK bits */ mask |= DA9030_LDO_UNLOCK_MASK; @@ -217,73 +184,57 @@ static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev, return da903x_update(da903x_dev, info->vol_reg, val, mask); } -static int da9030_set_ldo14_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, - unsigned *selector) +static int da9030_map_ldo14_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV) { struct da903x_regulator_info *info = rdev_get_drvdata(rdev); - struct device *da903x_dev = to_da903x_dev(rdev); - uint8_t val, mask; - int thresh; + int thresh, sel; if (check_range(info, min_uV, max_uV)) { pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV); return -EINVAL; } - thresh = (info->max_uV + info->min_uV) / 2; + thresh = (info->max_uV + info->desc.min_uV) / 2; if (min_uV < thresh) { - val = DIV_ROUND_UP(thresh - min_uV, info->step_uV); - val |= 0x4; + sel = DIV_ROUND_UP(thresh - min_uV, info->desc.uV_step); + sel |= 0x4; } else { - val = DIV_ROUND_UP(min_uV - thresh, info->step_uV); + sel = DIV_ROUND_UP(min_uV - thresh, info->desc.uV_step); } - *selector = val; - val <<= info->vol_shift; - mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; - - return da903x_update(da903x_dev, info->vol_reg, val, mask); + return sel; } -static int da9030_get_ldo14_voltage(struct regulator_dev *rdev) +static int da9030_list_ldo14_voltage(struct regulator_dev *rdev, + unsigned selector) { struct da903x_regulator_info *info = rdev_get_drvdata(rdev); - struct device *da903x_dev = to_da903x_dev(rdev); - uint8_t val, mask; - int ret; + int volt; - ret = da903x_read(da903x_dev, info->vol_reg, &val); - if (ret) - return ret; + if (selector & 0x4) + volt = rdev->desc->min_uV + + rdev->desc->uV_step * (3 - (selector & ~0x4)); + else + volt = (info->max_uV + rdev->desc->min_uV) / 2 + + rdev->desc->uV_step * (selector & ~0x4); - mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; - val = (val & mask) >> info->vol_shift; + if (volt > info->max_uV) + return -EINVAL; - if (val & 0x4) - return info->min_uV + info->step_uV * (3 - (val & ~0x4)); - else - return (info->max_uV + info->min_uV) / 2 + - info->step_uV * (val & ~0x4); + return volt; } /* DA9034 specific operations */ -static int da9034_set_dvc_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned *selector) +static int da9034_set_dvc_voltage_sel(struct regulator_dev *rdev, + unsigned selector) { struct da903x_regulator_info *info = rdev_get_drvdata(rdev); struct device *da9034_dev = to_da903x_dev(rdev); uint8_t val, mask; int ret; - if (check_range(info, min_uV, max_uV)) { - pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV); - return -EINVAL; - } - - val = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV); - *selector = val; - val <<= info->vol_shift; + val = selector << info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; ret = da903x_update(da9034_dev, info->vol_reg, val, mask); @@ -295,59 +246,45 @@ static int da9034_set_dvc_voltage(struct regulator_dev *rdev, return ret; } -static int da9034_set_ldo12_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned *selector) +static int da9034_map_ldo12_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV) { struct da903x_regulator_info *info = rdev_get_drvdata(rdev); - struct device *da9034_dev = to_da903x_dev(rdev); - uint8_t val, mask; + int sel; if (check_range(info, min_uV, max_uV)) { pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV); return -EINVAL; } - val = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV); - val = (val >= 20) ? val - 12 : ((val > 7) ? 8 : val); - *selector = val; - val <<= info->vol_shift; - mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; + sel = DIV_ROUND_UP(min_uV - info->desc.min_uV, info->desc.uV_step); + sel = (sel >= 20) ? sel - 12 : ((sel > 7) ? 8 : sel); - return da903x_update(da9034_dev, info->vol_reg, val, mask); + return sel; } -static int da9034_get_ldo12_voltage(struct regulator_dev *rdev) +static int da9034_list_ldo12_voltage(struct regulator_dev *rdev, + unsigned selector) { struct da903x_regulator_info *info = rdev_get_drvdata(rdev); - struct device *da9034_dev = to_da903x_dev(rdev); - uint8_t val, mask; - int ret; - - ret = da903x_read(da9034_dev, info->vol_reg, &val); - if (ret) - return ret; - - mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; - val = (val & mask) >> info->vol_shift; + int volt; - if (val >= 8) - return 2700000 + info->step_uV * (val - 8); - - return info->min_uV + info->step_uV * val; -} + if (selector >= 8) + volt = 2700000 + rdev->desc->uV_step * (selector - 8); + else + volt = rdev->desc->min_uV + rdev->desc->uV_step * selector; -static int da9034_list_ldo12_voltage(struct regulator_dev *rdev, - unsigned selector) -{ - if (selector >= ARRAY_SIZE(da9034_ldo12_data)) + if (volt > info->max_uV) return -EINVAL; - return da9034_ldo12_data[selector] * 1000; + + return volt; } static struct regulator_ops da903x_regulator_ldo_ops = { - .set_voltage = da903x_set_ldo_voltage, - .get_voltage = da903x_get_voltage, - .list_voltage = da903x_list_voltage, + .set_voltage_sel = da903x_set_voltage_sel, + .get_voltage_sel = da903x_get_voltage_sel, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, .enable = da903x_enable, .disable = da903x_disable, .is_enabled = da903x_is_enabled, @@ -355,9 +292,10 @@ static struct regulator_ops da903x_regulator_ldo_ops = { /* NOTE: this is dedicated for the insane DA9030 LDO14 */ static struct regulator_ops da9030_regulator_ldo14_ops = { - .set_voltage = da9030_set_ldo14_voltage, - .get_voltage = da9030_get_ldo14_voltage, - .list_voltage = da903x_list_voltage, + .set_voltage_sel = da903x_set_voltage_sel, + .get_voltage_sel = da903x_get_voltage_sel, + .list_voltage = da9030_list_ldo14_voltage, + .map_voltage = da9030_map_ldo14_voltage, .enable = da903x_enable, .disable = da903x_disable, .is_enabled = da903x_is_enabled, @@ -365,18 +303,20 @@ static struct regulator_ops da9030_regulator_ldo14_ops = { /* NOTE: this is dedicated for the DA9030 LDO1 and LDO15 that have locks */ static struct regulator_ops da9030_regulator_ldo1_15_ops = { - .set_voltage = da9030_set_ldo1_15_voltage, - .get_voltage = da903x_get_voltage, - .list_voltage = da903x_list_voltage, + .set_voltage_sel = da9030_set_ldo1_15_voltage_sel, + .get_voltage_sel = da903x_get_voltage_sel, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, .enable = da903x_enable, .disable = da903x_disable, .is_enabled = da903x_is_enabled, }; static struct regulator_ops da9034_regulator_dvc_ops = { - .set_voltage = da9034_set_dvc_voltage, - .get_voltage = da903x_get_voltage, - .list_voltage = da903x_list_voltage, + .set_voltage_sel = da9034_set_dvc_voltage_sel, + .get_voltage_sel = da903x_get_voltage_sel, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, .enable = da903x_enable, .disable = da903x_disable, .is_enabled = da903x_is_enabled, @@ -384,9 +324,10 @@ static struct regulator_ops da9034_regulator_dvc_ops = { /* NOTE: this is dedicated for the insane LDO12 */ static struct regulator_ops da9034_regulator_ldo12_ops = { - .set_voltage = da9034_set_ldo12_voltage, - .get_voltage = da9034_get_ldo12_voltage, + .set_voltage_sel = da903x_set_voltage_sel, + .get_voltage_sel = da903x_get_voltage_sel, .list_voltage = da9034_list_ldo12_voltage, + .map_voltage = da9034_map_ldo12_voltage, .enable = da903x_enable, .disable = da903x_disable, .is_enabled = da903x_is_enabled, @@ -401,10 +342,10 @@ static struct regulator_ops da9034_regulator_ldo12_ops = { .id = _pmic##_ID_LDO##_id, \ .n_voltages = (step) ? ((max - min) / step + 1) : 1, \ .owner = THIS_MODULE, \ + .min_uV = (min) * 1000, \ + .uV_step = (step) * 1000, \ }, \ - .min_uV = (min) * 1000, \ .max_uV = (max) * 1000, \ - .step_uV = (step) * 1000, \ .vol_reg = _pmic##_##vreg, \ .vol_shift = (shift), \ .vol_nbits = (nbits), \ @@ -421,10 +362,10 @@ static struct regulator_ops da9034_regulator_ldo12_ops = { .id = _pmic##_ID_##_id, \ .n_voltages = (step) ? ((max - min) / step + 1) : 1, \ .owner = THIS_MODULE, \ + .min_uV = (min) * 1000, \ + .uV_step = (step) * 1000, \ }, \ - .min_uV = (min) * 1000, \ .max_uV = (max) * 1000, \ - .step_uV = (step) * 1000, \ .vol_reg = _pmic##_##vreg, \ .vol_shift = (0), \ .vol_nbits = (nbits), \ @@ -517,6 +458,7 @@ static int __devinit da903x_regulator_probe(struct platform_device *pdev) { struct da903x_regulator_info *ri = NULL; struct regulator_dev *rdev; + struct regulator_config config = { }; ri = find_regulator_info(pdev->id); if (ri == NULL) { @@ -527,7 +469,7 @@ static int __devinit da903x_regulator_probe(struct platform_device *pdev) /* Workaround for the weird LDO12 voltage setting */ if (ri->desc.id == DA9034_ID_LDO12) { ri->desc.ops = &da9034_regulator_ldo12_ops; - ri->desc.n_voltages = ARRAY_SIZE(da9034_ldo12_data); + ri->desc.n_voltages = 16; } if (ri->desc.id == DA9030_ID_LDO14) @@ -536,8 +478,11 @@ static int __devinit da903x_regulator_probe(struct platform_device *pdev) if (ri->desc.id == DA9030_ID_LDO1 || ri->desc.id == DA9030_ID_LDO15) ri->desc.ops = &da9030_regulator_ldo1_15_ops; - rdev = regulator_register(&ri->desc, &pdev->dev, - pdev->dev.platform_data, ri, NULL); + config.dev = &pdev->dev; + config.init_data = pdev->dev.platform_data; + config.driver_data = ri; + + rdev = regulator_register(&ri->desc, &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register regulator %s\n", ri->desc.name); diff --git a/trunk/drivers/regulator/da9052-regulator.c b/trunk/drivers/regulator/da9052-regulator.c index 09915e89705d..88976d8d44ed 100644 --- a/trunk/drivers/regulator/da9052-regulator.c +++ b/trunk/drivers/regulator/da9052-regulator.c @@ -19,6 +19,10 @@ #include #include #include +#ifdef CONFIG_OF +#include +#include +#endif #include #include @@ -37,6 +41,22 @@ #define DA9052_BUCK_ILIM_MASK_EVEN 0x0c #define DA9052_BUCK_ILIM_MASK_ODD 0xc0 +/* DA9052 REGULATOR IDs */ +#define DA9052_ID_BUCK1 0 +#define DA9052_ID_BUCK2 1 +#define DA9052_ID_BUCK3 2 +#define DA9052_ID_BUCK4 3 +#define DA9052_ID_LDO1 4 +#define DA9052_ID_LDO2 5 +#define DA9052_ID_LDO3 6 +#define DA9052_ID_LDO4 7 +#define DA9052_ID_LDO5 8 +#define DA9052_ID_LDO6 9 +#define DA9052_ID_LDO7 10 +#define DA9052_ID_LDO8 11 +#define DA9052_ID_LDO9 12 +#define DA9052_ID_LDO10 13 + static const u32 da9052_current_limits[3][4] = { {700000, 800000, 1000000, 1200000}, /* DA9052-BC BUCKs */ {1600000, 2000000, 2400000, 3000000}, /* DA9053-AA/Bx BUCK-CORE */ @@ -50,8 +70,6 @@ struct da9052_regulator_info { int step_uV; int min_uV; int max_uV; - unsigned char volt_shift; - unsigned char en_bit; unsigned char activate_bit; }; @@ -70,42 +88,6 @@ static int verify_range(struct da9052_regulator_info *info, return 0; } -static int da9052_regulator_enable(struct regulator_dev *rdev) -{ - struct da9052_regulator *regulator = rdev_get_drvdata(rdev); - struct da9052_regulator_info *info = regulator->info; - int offset = rdev_get_id(rdev); - - return da9052_reg_update(regulator->da9052, - DA9052_BUCKCORE_REG + offset, - 1 << info->en_bit, 1 << info->en_bit); -} - -static int da9052_regulator_disable(struct regulator_dev *rdev) -{ - struct da9052_regulator *regulator = rdev_get_drvdata(rdev); - struct da9052_regulator_info *info = regulator->info; - int offset = rdev_get_id(rdev); - - return da9052_reg_update(regulator->da9052, - DA9052_BUCKCORE_REG + offset, - 1 << info->en_bit, 0); -} - -static int da9052_regulator_is_enabled(struct regulator_dev *rdev) -{ - struct da9052_regulator *regulator = rdev_get_drvdata(rdev); - struct da9052_regulator_info *info = regulator->info; - int offset = rdev_get_id(rdev); - int ret; - - ret = da9052_reg_read(regulator->da9052, DA9052_BUCKCORE_REG + offset); - if (ret < 0) - return ret; - - return ret & (1 << info->en_bit); -} - static int da9052_dcdc_get_current_limit(struct regulator_dev *rdev) { struct da9052_regulator *regulator = rdev_get_drvdata(rdev); @@ -173,36 +155,23 @@ static int da9052_dcdc_set_current_limit(struct regulator_dev *rdev, int min_uA, reg_val << 6); } -static int da9052_list_buckperi_voltage(struct regulator_dev *rdev, - unsigned int selector) -{ - struct da9052_regulator *regulator = rdev_get_drvdata(rdev); - struct da9052_regulator_info *info = regulator->info; - int volt_uV; - - if ((regulator->da9052->chip_id == DA9052) && - (selector >= DA9052_BUCK_PERI_REG_MAP_UPTO_3uV)) { - volt_uV = ((DA9052_BUCK_PERI_REG_MAP_UPTO_3uV * info->step_uV) - + info->min_uV); - volt_uV += (selector - DA9052_BUCK_PERI_REG_MAP_UPTO_3uV) - * (DA9052_BUCK_PERI_3uV_STEP); - } else - volt_uV = (selector * info->step_uV) + info->min_uV; - - if (volt_uV > info->max_uV) - return -EINVAL; - - return volt_uV; -} - static int da9052_list_voltage(struct regulator_dev *rdev, unsigned int selector) { struct da9052_regulator *regulator = rdev_get_drvdata(rdev); struct da9052_regulator_info *info = regulator->info; + int id = rdev_get_id(rdev); int volt_uV; - volt_uV = info->min_uV + info->step_uV * selector; + if ((id == DA9052_ID_BUCK4) && (regulator->da9052->chip_id == DA9052) + && (selector >= DA9052_BUCK_PERI_REG_MAP_UPTO_3uV)) { + volt_uV = ((DA9052_BUCK_PERI_REG_MAP_UPTO_3uV * info->step_uV) + + info->min_uV); + volt_uV += (selector - DA9052_BUCK_PERI_REG_MAP_UPTO_3uV) + * (DA9052_BUCK_PERI_3uV_STEP); + } else { + volt_uV = (selector * info->step_uV) + info->min_uV; + } if (volt_uV > info->max_uV) return -EINVAL; @@ -210,103 +179,13 @@ static int da9052_list_voltage(struct regulator_dev *rdev, return volt_uV; } -static int da9052_regulator_set_voltage_int(struct regulator_dev *rdev, - int min_uV, int max_uV, - unsigned int *selector) -{ - struct da9052_regulator *regulator = rdev_get_drvdata(rdev); - struct da9052_regulator_info *info = regulator->info; - int offset = rdev_get_id(rdev); - int ret; - - ret = verify_range(info, min_uV, max_uV); - if (ret < 0) - return ret; - - if (min_uV < info->min_uV) - min_uV = info->min_uV; - - *selector = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV); - - ret = da9052_list_voltage(rdev, *selector); - if (ret < 0) - return ret; - - return da9052_reg_update(regulator->da9052, - DA9052_BUCKCORE_REG + offset, - (1 << info->volt_shift) - 1, *selector); -} - -static int da9052_set_ldo_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, - unsigned int *selector) -{ - return da9052_regulator_set_voltage_int(rdev, min_uV, max_uV, selector); -} - -static int da9052_set_ldo5_6_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, - unsigned int *selector) -{ - struct da9052_regulator *regulator = rdev_get_drvdata(rdev); - struct da9052_regulator_info *info = regulator->info; - int ret; - - ret = da9052_regulator_set_voltage_int(rdev, min_uV, max_uV, selector); - if (ret < 0) - return ret; - - /* Some LDOs are DVC controlled which requires enabling of - * the LDO activate bit to implment the changes on the - * LDO output. - */ - return da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG, - info->activate_bit, info->activate_bit); -} - -static int da9052_set_dcdc_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, - unsigned int *selector) -{ - struct da9052_regulator *regulator = rdev_get_drvdata(rdev); - struct da9052_regulator_info *info = regulator->info; - int ret; - - ret = da9052_regulator_set_voltage_int(rdev, min_uV, max_uV, selector); - if (ret < 0) - return ret; - - /* Some DCDCs are DVC controlled which requires enabling of - * the DCDC activate bit to implment the changes on the - * DCDC output. - */ - return da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG, - info->activate_bit, info->activate_bit); -} - -static int da9052_get_regulator_voltage_sel(struct regulator_dev *rdev) -{ - struct da9052_regulator *regulator = rdev_get_drvdata(rdev); - struct da9052_regulator_info *info = regulator->info; - int offset = rdev_get_id(rdev); - int ret; - - ret = da9052_reg_read(regulator->da9052, DA9052_BUCKCORE_REG + offset); - if (ret < 0) - return ret; - - ret &= ((1 << info->volt_shift) - 1); - - return ret; -} - -static int da9052_set_buckperi_voltage(struct regulator_dev *rdev, int min_uV, - int max_uV, unsigned int *selector) +static int da9052_map_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV) { struct da9052_regulator *regulator = rdev_get_drvdata(rdev); struct da9052_regulator_info *info = regulator->info; - int offset = rdev_get_id(rdev); - int ret; + int id = rdev_get_id(rdev); + int ret, sel; ret = verify_range(info, min_uV, max_uV); if (ret < 0) @@ -315,192 +194,147 @@ static int da9052_set_buckperi_voltage(struct regulator_dev *rdev, int min_uV, if (min_uV < info->min_uV) min_uV = info->min_uV; - if ((regulator->da9052->chip_id == DA9052) && - (min_uV >= DA9052_CONST_3uV)) - *selector = DA9052_BUCK_PERI_REG_MAP_UPTO_3uV + - DIV_ROUND_UP(min_uV - DA9052_CONST_3uV, - DA9052_BUCK_PERI_3uV_STEP); - else - *selector = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV); + if ((id == DA9052_ID_BUCK4) && (regulator->da9052->chip_id == DA9052) + && (min_uV >= DA9052_CONST_3uV)) { + sel = DA9052_BUCK_PERI_REG_MAP_UPTO_3uV + + DIV_ROUND_UP(min_uV - DA9052_CONST_3uV, + DA9052_BUCK_PERI_3uV_STEP); + } else { + sel = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV); + } - ret = da9052_list_buckperi_voltage(rdev, *selector); + ret = da9052_list_voltage(rdev, sel); if (ret < 0) return ret; - return da9052_reg_update(regulator->da9052, - DA9052_BUCKCORE_REG + offset, - (1 << info->volt_shift) - 1, *selector); + return sel; } -static int da9052_get_buckperi_voltage_sel(struct regulator_dev *rdev) +static int da9052_regulator_set_voltage_sel(struct regulator_dev *rdev, + unsigned int selector) { struct da9052_regulator *regulator = rdev_get_drvdata(rdev); struct da9052_regulator_info *info = regulator->info; - int offset = rdev_get_id(rdev); + int id = rdev_get_id(rdev); int ret; - ret = da9052_reg_read(regulator->da9052, DA9052_BUCKCORE_REG + offset); + ret = da9052_reg_update(regulator->da9052, rdev->desc->vsel_reg, + rdev->desc->vsel_mask, selector); if (ret < 0) return ret; - ret &= ((1 << info->volt_shift) - 1); + /* Some LDOs and DCDCs are DVC controlled which requires enabling of + * the activate bit to implment the changes on the output. + */ + switch (id) { + case DA9052_ID_BUCK1: + case DA9052_ID_BUCK2: + case DA9052_ID_BUCK3: + case DA9052_ID_LDO2: + case DA9052_ID_LDO3: + ret = da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG, + info->activate_bit, info->activate_bit); + break; + } return ret; } -static struct regulator_ops da9052_buckperi_ops = { - .list_voltage = da9052_list_buckperi_voltage, - .get_voltage_sel = da9052_get_buckperi_voltage_sel, - .set_voltage = da9052_set_buckperi_voltage, - - .get_current_limit = da9052_dcdc_get_current_limit, - .set_current_limit = da9052_dcdc_set_current_limit, - - .is_enabled = da9052_regulator_is_enabled, - .enable = da9052_regulator_enable, - .disable = da9052_regulator_disable, -}; - static struct regulator_ops da9052_dcdc_ops = { - .set_voltage = da9052_set_dcdc_voltage, .get_current_limit = da9052_dcdc_get_current_limit, .set_current_limit = da9052_dcdc_set_current_limit, .list_voltage = da9052_list_voltage, - .get_voltage_sel = da9052_get_regulator_voltage_sel, - .is_enabled = da9052_regulator_is_enabled, - .enable = da9052_regulator_enable, - .disable = da9052_regulator_disable, -}; - -static struct regulator_ops da9052_ldo5_6_ops = { - .set_voltage = da9052_set_ldo5_6_voltage, - - .list_voltage = da9052_list_voltage, - .get_voltage_sel = da9052_get_regulator_voltage_sel, - .is_enabled = da9052_regulator_is_enabled, - .enable = da9052_regulator_enable, - .disable = da9052_regulator_disable, + .map_voltage = da9052_map_voltage, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = da9052_regulator_set_voltage_sel, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, }; static struct regulator_ops da9052_ldo_ops = { - .set_voltage = da9052_set_ldo_voltage, - .list_voltage = da9052_list_voltage, - .get_voltage_sel = da9052_get_regulator_voltage_sel, - .is_enabled = da9052_regulator_is_enabled, - .enable = da9052_regulator_enable, - .disable = da9052_regulator_disable, + .map_voltage = da9052_map_voltage, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = da9052_regulator_set_voltage_sel, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, }; -#define DA9052_LDO5_6(_id, step, min, max, sbits, ebits, abits) \ -{\ - .reg_desc = {\ - .name = "LDO" #_id,\ - .ops = &da9052_ldo5_6_ops,\ - .type = REGULATOR_VOLTAGE,\ - .id = _id,\ - .n_voltages = (max - min) / step + 1, \ - .owner = THIS_MODULE,\ - },\ - .min_uV = (min) * 1000,\ - .max_uV = (max) * 1000,\ - .step_uV = (step) * 1000,\ - .volt_shift = (sbits),\ - .en_bit = (ebits),\ - .activate_bit = (abits),\ -} - #define DA9052_LDO(_id, step, min, max, sbits, ebits, abits) \ {\ .reg_desc = {\ - .name = "LDO" #_id,\ + .name = #_id,\ .ops = &da9052_ldo_ops,\ .type = REGULATOR_VOLTAGE,\ - .id = _id,\ + .id = DA9052_ID_##_id,\ .n_voltages = (max - min) / step + 1, \ .owner = THIS_MODULE,\ + .vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ + .vsel_mask = (1 << (sbits)) - 1,\ + .enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ + .enable_mask = 1 << (ebits),\ },\ .min_uV = (min) * 1000,\ .max_uV = (max) * 1000,\ .step_uV = (step) * 1000,\ - .volt_shift = (sbits),\ - .en_bit = (ebits),\ .activate_bit = (abits),\ } #define DA9052_DCDC(_id, step, min, max, sbits, ebits, abits) \ {\ .reg_desc = {\ - .name = "BUCK" #_id,\ + .name = #_id,\ .ops = &da9052_dcdc_ops,\ .type = REGULATOR_VOLTAGE,\ - .id = _id,\ + .id = DA9052_ID_##_id,\ .n_voltages = (max - min) / step + 1, \ .owner = THIS_MODULE,\ + .vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ + .vsel_mask = (1 << (sbits)) - 1,\ + .enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ + .enable_mask = 1 << (ebits),\ },\ .min_uV = (min) * 1000,\ .max_uV = (max) * 1000,\ .step_uV = (step) * 1000,\ - .volt_shift = (sbits),\ - .en_bit = (ebits),\ - .activate_bit = (abits),\ -} - -#define DA9052_BUCKPERI(_id, step, min, max, sbits, ebits, abits) \ -{\ - .reg_desc = {\ - .name = "BUCK" #_id,\ - .ops = &da9052_buckperi_ops,\ - .type = REGULATOR_VOLTAGE,\ - .id = _id,\ - .n_voltages = (max - min) / step + 1, \ - .owner = THIS_MODULE,\ - },\ - .min_uV = (min) * 1000,\ - .max_uV = (max) * 1000,\ - .step_uV = (step) * 1000,\ - .volt_shift = (sbits),\ - .en_bit = (ebits),\ .activate_bit = (abits),\ } static struct da9052_regulator_info da9052_regulator_info[] = { - /* Buck1 - 4 */ - DA9052_DCDC(0, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO), - DA9052_DCDC(1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO), - DA9052_DCDC(2, 25, 925, 2500, 6, 6, DA9052_SUPPLY_VBMEMGO), - DA9052_BUCKPERI(3, 50, 1800, 3600, 5, 6, 0), - /* LD01 - LDO10 */ - DA9052_LDO(4, 50, 600, 1800, 5, 6, 0), - DA9052_LDO5_6(5, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO), - DA9052_LDO5_6(6, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO), - DA9052_LDO(7, 25, 1725, 3300, 6, 6, 0), - DA9052_LDO(8, 50, 1200, 3600, 6, 6, 0), - DA9052_LDO(9, 50, 1200, 3600, 6, 6, 0), - DA9052_LDO(10, 50, 1200, 3600, 6, 6, 0), - DA9052_LDO(11, 50, 1200, 3600, 6, 6, 0), - DA9052_LDO(12, 50, 1250, 3650, 6, 6, 0), - DA9052_LDO(13, 50, 1200, 3600, 6, 6, 0), + DA9052_DCDC(BUCK1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO), + DA9052_DCDC(BUCK2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO), + DA9052_DCDC(BUCK3, 25, 925, 2500, 6, 6, DA9052_SUPPLY_VBMEMGO), + DA9052_DCDC(BUCK4, 50, 1800, 3600, 5, 6, 0), + DA9052_LDO(LDO1, 50, 600, 1800, 5, 6, 0), + DA9052_LDO(LDO2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO), + DA9052_LDO(LDO3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO), + DA9052_LDO(LDO4, 25, 1725, 3300, 6, 6, 0), + DA9052_LDO(LDO5, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(LDO6, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(LDO7, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(LDO8, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(LDO9, 50, 1250, 3650, 6, 6, 0), + DA9052_LDO(LDO10, 50, 1200, 3600, 6, 6, 0), }; static struct da9052_regulator_info da9053_regulator_info[] = { - /* Buck1 - 4 */ - DA9052_DCDC(0, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO), - DA9052_DCDC(1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO), - DA9052_DCDC(2, 25, 925, 2500, 6, 6, DA9052_SUPPLY_VBMEMGO), - DA9052_BUCKPERI(3, 25, 925, 2500, 6, 6, 0), - /* LD01 - LDO10 */ - DA9052_LDO(4, 50, 600, 1800, 5, 6, 0), - DA9052_LDO5_6(5, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO), - DA9052_LDO5_6(6, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO), - DA9052_LDO(7, 25, 1725, 3300, 6, 6, 0), - DA9052_LDO(8, 50, 1200, 3600, 6, 6, 0), - DA9052_LDO(9, 50, 1200, 3600, 6, 6, 0), - DA9052_LDO(10, 50, 1200, 3600, 6, 6, 0), - DA9052_LDO(11, 50, 1200, 3600, 6, 6, 0), - DA9052_LDO(12, 50, 1250, 3650, 6, 6, 0), - DA9052_LDO(13, 50, 1200, 3600, 6, 6, 0), + DA9052_DCDC(BUCK1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO), + DA9052_DCDC(BUCK2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO), + DA9052_DCDC(BUCK3, 25, 925, 2500, 6, 6, DA9052_SUPPLY_VBMEMGO), + DA9052_DCDC(BUCK4, 25, 925, 2500, 6, 6, 0), + DA9052_LDO(LDO1, 50, 600, 1800, 5, 6, 0), + DA9052_LDO(LDO2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO), + DA9052_LDO(LDO3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO), + DA9052_LDO(LDO4, 25, 1725, 3300, 6, 6, 0), + DA9052_LDO(LDO5, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(LDO6, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(LDO7, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(LDO8, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(LDO9, 50, 1250, 3650, 6, 6, 0), + DA9052_LDO(LDO10, 50, 1200, 3600, 6, 6, 0), }; static inline struct da9052_regulator_info *find_regulator_info(u8 chip_id, @@ -533,10 +367,10 @@ static inline struct da9052_regulator_info *find_regulator_info(u8 chip_id, static int __devinit da9052_regulator_probe(struct platform_device *pdev) { + struct regulator_config config = { }; struct da9052_regulator *regulator; struct da9052 *da9052; struct da9052_pdata *pdata; - int ret; regulator = devm_kzalloc(&pdev->dev, sizeof(struct da9052_regulator), GFP_KERNEL); @@ -551,26 +385,49 @@ static int __devinit da9052_regulator_probe(struct platform_device *pdev) pdev->id); if (regulator->info == NULL) { dev_err(&pdev->dev, "invalid regulator ID specified\n"); - ret = -EINVAL; - goto err; + return -EINVAL; } + + config.dev = &pdev->dev; + config.driver_data = regulator; + config.regmap = da9052->regmap; + if (pdata && pdata->regulators) { + config.init_data = pdata->regulators[pdev->id]; + } else { +#ifdef CONFIG_OF + struct device_node *nproot = da9052->dev->of_node; + struct device_node *np; + + if (!nproot) + return -ENODEV; + + nproot = of_find_node_by_name(nproot, "regulators"); + if (!nproot) + return -ENODEV; + + for (np = of_get_next_child(nproot, NULL); np; + np = of_get_next_child(nproot, np)) { + if (!of_node_cmp(np->name, + regulator->info->reg_desc.name)) { + config.init_data = of_get_regulator_init_data( + &pdev->dev, np); + break; + } + } +#endif + } + regulator->rdev = regulator_register(®ulator->info->reg_desc, - &pdev->dev, - pdata->regulators[pdev->id], - regulator, NULL); + &config); if (IS_ERR(regulator->rdev)) { dev_err(&pdev->dev, "failed to register regulator %s\n", regulator->info->reg_desc.name); - ret = PTR_ERR(regulator->rdev); - goto err; + return PTR_ERR(regulator->rdev); } platform_set_drvdata(pdev, regulator); return 0; -err: - devm_kfree(&pdev->dev, regulator); - return ret; } static int __devexit da9052_regulator_remove(struct platform_device *pdev) @@ -578,8 +435,6 @@ static int __devexit da9052_regulator_remove(struct platform_device *pdev) struct da9052_regulator *regulator = platform_get_drvdata(pdev); regulator_unregister(regulator->rdev); - devm_kfree(&pdev->dev, regulator); - return 0; } diff --git a/trunk/drivers/regulator/db8500-prcmu.c b/trunk/drivers/regulator/db8500-prcmu.c index 4bd25e75efa0..968f97f3cb3d 100644 --- a/trunk/drivers/regulator/db8500-prcmu.c +++ b/trunk/drivers/regulator/db8500-prcmu.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include "dbx500-prcmu.h" @@ -410,45 +412,120 @@ dbx500_regulator_info[DB8500_NUM_REGULATORS] = { }, }; +static __devinit int db8500_regulator_register(struct platform_device *pdev, + struct regulator_init_data *init_data, + int id, + struct device_node *np) +{ + struct dbx500_regulator_info *info; + struct regulator_config config = { }; + int err; + + /* assign per-regulator data */ + info = &dbx500_regulator_info[id]; + info->dev = &pdev->dev; + + config.dev = &pdev->dev; + config.init_data = init_data; + config.driver_data = info; + config.of_node = np; + + /* register with the regulator framework */ + info->rdev = regulator_register(&info->desc, &config); + if (IS_ERR(info->rdev)) { + err = PTR_ERR(info->rdev); + dev_err(&pdev->dev, "failed to register %s: err %i\n", + info->desc.name, err); + + /* if failing, unregister all earlier regulators */ + while (--id >= 0) { + info = &dbx500_regulator_info[id]; + regulator_unregister(info->rdev); + } + return err; + } + + dev_dbg(rdev_get_dev(info->rdev), + "regulator-%s-probed\n", info->desc.name); + + return 0; +} + +static struct of_regulator_match db8500_regulator_matches[] = { + { .name = "db8500-vape", .driver_data = (void *) DB8500_REGULATOR_VAPE, }, + { .name = "db8500-varm", .driver_data = (void *) DB8500_REGULATOR_VARM, }, + { .name = "db8500-vmodem", .driver_data = (void *) DB8500_REGULATOR_VMODEM, }, + { .name = "db8500-vpll", .driver_data = (void *) DB8500_REGULATOR_VPLL, }, + { .name = "db8500-vsmps1", .driver_data = (void *) DB8500_REGULATOR_VSMPS1, }, + { .name = "db8500-vsmps2", .driver_data = (void *) DB8500_REGULATOR_VSMPS2, }, + { .name = "db8500-vsmps3", .driver_data = (void *) DB8500_REGULATOR_VSMPS3, }, + { .name = "db8500-vrf1", .driver_data = (void *) DB8500_REGULATOR_VRF1, }, + { .name = "db8500-sva-mmdsp", .driver_data = (void *) DB8500_REGULATOR_SWITCH_SVAMMDSP, }, + { .name = "db8500-sva-mmdsp-ret", .driver_data = (void *) DB8500_REGULATOR_SWITCH_SVAMMDSPRET, }, + { .name = "db8500-sva-pipe", .driver_data = (void *) DB8500_REGULATOR_SWITCH_SVAPIPE, }, + { .name = "db8500-sia-mmdsp", .driver_data = (void *) DB8500_REGULATOR_SWITCH_SIAMMDSP, }, + { .name = "db8500-sia-mmdsp-ret", .driver_data = (void *) DB8500_REGULATOR_SWITCH_SIAMMDSPRET, }, + { .name = "db8500-sia-pipe", .driver_data = (void *) DB8500_REGULATOR_SWITCH_SIAPIPE, }, + { .name = "db8500-sga", .driver_data = (void *) DB8500_REGULATOR_SWITCH_SGA, }, + { .name = "db8500-b2r2-mcde", .driver_data = (void *) DB8500_REGULATOR_SWITCH_B2R2_MCDE, }, + { .name = "db8500-esram12", .driver_data = (void *) DB8500_REGULATOR_SWITCH_ESRAM12, }, + { .name = "db8500-esram12-ret", .driver_data = (void *) DB8500_REGULATOR_SWITCH_ESRAM12RET, }, + { .name = "db8500-esram34", .driver_data = (void *) DB8500_REGULATOR_SWITCH_ESRAM34, }, + { .name = "db8500-esram34-ret", .driver_data = (void *) DB8500_REGULATOR_SWITCH_ESRAM34RET, }, +}; + +static __devinit int +db8500_regulator_of_probe(struct platform_device *pdev, + struct device_node *np) +{ + int i, err; + + for (i = 0; i < ARRAY_SIZE(dbx500_regulator_info); i++) { + err = db8500_regulator_register( + pdev, db8500_regulator_matches[i].init_data, + i, db8500_regulator_matches[i].of_node); + if (err) + return err; + } + + return 0; +} + static int __devinit db8500_regulator_probe(struct platform_device *pdev) { struct regulator_init_data *db8500_init_data = dev_get_platdata(&pdev->dev); + struct device_node *np = pdev->dev.of_node; int i, err; /* register all regulators */ - for (i = 0; i < ARRAY_SIZE(dbx500_regulator_info); i++) { - struct dbx500_regulator_info *info; - struct regulator_init_data *init_data = &db8500_init_data[i]; - - /* assign per-regulator data */ - info = &dbx500_regulator_info[i]; - info->dev = &pdev->dev; - - /* register with the regulator framework */ - info->rdev = regulator_register(&info->desc, &pdev->dev, - init_data, info, NULL); - if (IS_ERR(info->rdev)) { - err = PTR_ERR(info->rdev); - dev_err(&pdev->dev, "failed to register %s: err %i\n", - info->desc.name, err); - - /* if failing, unregister all earlier regulators */ - while (--i >= 0) { - info = &dbx500_regulator_info[i]; - regulator_unregister(info->rdev); - } + if (np) { + err = of_regulator_match(&pdev->dev, np, + db8500_regulator_matches, + ARRAY_SIZE(db8500_regulator_matches)); + if (err < 0) { + dev_err(&pdev->dev, + "Error parsing regulator init data: %d\n", err); return err; } - dev_dbg(rdev_get_dev(info->rdev), - "regulator-%s-probed\n", info->desc.name); + err = db8500_regulator_of_probe(pdev, np); + if (err) + return err; + } else { + for (i = 0; i < ARRAY_SIZE(dbx500_regulator_info); i++) { + err = db8500_regulator_register(pdev, + &db8500_init_data[i], + i, NULL); + if (err) + return err; + } } + err = ux500_regulator_debug_init(pdev, dbx500_regulator_info, ARRAY_SIZE(dbx500_regulator_info)); - - return err; + return 0; } static int __exit db8500_regulator_remove(struct platform_device *pdev) @@ -470,10 +547,16 @@ static int __exit db8500_regulator_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id db8500_prcmu_regulator_match[] = { + { .compatible = "stericsson,db8500-prcmu-regulator", }, + {} +}; + static struct platform_driver db8500_regulator_driver = { .driver = { .name = "db8500-prcmu-regulators", .owner = THIS_MODULE, + .of_match_table = db8500_prcmu_regulator_match, }, .probe = db8500_regulator_probe, .remove = __exit_p(db8500_regulator_remove), diff --git a/trunk/drivers/regulator/dummy.c b/trunk/drivers/regulator/dummy.c index 0ee00de4be72..86f655c7f7a1 100644 --- a/trunk/drivers/regulator/dummy.c +++ b/trunk/drivers/regulator/dummy.c @@ -39,10 +39,13 @@ static struct regulator_desc dummy_desc = { static int __devinit dummy_regulator_probe(struct platform_device *pdev) { + struct regulator_config config = { }; int ret; - dummy_regulator_rdev = regulator_register(&dummy_desc, NULL, - &dummy_initdata, NULL, NULL); + config.dev = &pdev->dev; + config.init_data = &dummy_initdata; + + dummy_regulator_rdev = regulator_register(&dummy_desc, &config); if (IS_ERR(dummy_regulator_rdev)) { ret = PTR_ERR(dummy_regulator_rdev); pr_err("Failed to register regulator: %d\n", ret); diff --git a/trunk/drivers/regulator/fixed.c b/trunk/drivers/regulator/fixed.c index 40f38030b394..f09fe7b20e82 100644 --- a/trunk/drivers/regulator/fixed.c +++ b/trunk/drivers/regulator/fixed.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -91,6 +90,9 @@ of_get_fixed_voltage_config(struct device *dev) if (of_find_property(np, "enable-active-high", NULL)) config->enable_high = true; + if (of_find_property(np, "gpio-open-drain", NULL)) + config->gpio_is_open_drain = true; + return config; } @@ -105,10 +107,8 @@ static int fixed_voltage_enable(struct regulator_dev *dev) { struct fixed_voltage_data *data = rdev_get_drvdata(dev); - if (gpio_is_valid(data->gpio)) { - gpio_set_value_cansleep(data->gpio, data->enable_high); - data->is_enabled = true; - } + gpio_set_value_cansleep(data->gpio, data->enable_high); + data->is_enabled = true; return 0; } @@ -117,10 +117,8 @@ static int fixed_voltage_disable(struct regulator_dev *dev) { struct fixed_voltage_data *data = rdev_get_drvdata(dev); - if (gpio_is_valid(data->gpio)) { - gpio_set_value_cansleep(data->gpio, !data->enable_high); - data->is_enabled = false; - } + gpio_set_value_cansleep(data->gpio, !data->enable_high); + data->is_enabled = false; return 0; } @@ -153,7 +151,7 @@ static int fixed_voltage_list_voltage(struct regulator_dev *dev, return data->microvolts; } -static struct regulator_ops fixed_voltage_ops = { +static struct regulator_ops fixed_voltage_gpio_ops = { .is_enabled = fixed_voltage_is_enabled, .enable = fixed_voltage_enable, .disable = fixed_voltage_disable, @@ -162,10 +160,16 @@ static struct regulator_ops fixed_voltage_ops = { .list_voltage = fixed_voltage_list_voltage, }; +static struct regulator_ops fixed_voltage_ops = { + .get_voltage = fixed_voltage_get_voltage, + .list_voltage = fixed_voltage_list_voltage, +}; + static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev) { struct fixed_voltage_config *config; struct fixed_voltage_data *drvdata; + struct regulator_config cfg = { }; int ret; if (pdev->dev.of_node) @@ -176,7 +180,8 @@ static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev) if (!config) return -ENOMEM; - drvdata = kzalloc(sizeof(struct fixed_voltage_data), GFP_KERNEL); + drvdata = devm_kzalloc(&pdev->dev, sizeof(struct fixed_voltage_data), + GFP_KERNEL); if (drvdata == NULL) { dev_err(&pdev->dev, "Failed to allocate device data\n"); ret = -ENOMEM; @@ -191,7 +196,6 @@ static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev) } drvdata->desc.type = REGULATOR_VOLTAGE; drvdata->desc.owner = THIS_MODULE; - drvdata->desc.ops = &fixed_voltage_ops; if (config->microvolts) drvdata->desc.n_voltages = 1; @@ -201,6 +205,7 @@ static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev) drvdata->startup_delay = config->startup_delay; if (gpio_is_valid(config->gpio)) { + int gpio_flag; drvdata->enable_high = config->enable_high; /* FIXME: Remove below print warning @@ -218,39 +223,39 @@ static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "using GPIO 0 for regulator enable control\n"); - ret = gpio_request(config->gpio, config->supply_name); - if (ret) { - dev_err(&pdev->dev, - "Could not obtain regulator enable GPIO %d: %d\n", - config->gpio, ret); - goto err_name; - } - - /* set output direction without changing state + /* + * set output direction without changing state * to prevent glitch */ drvdata->is_enabled = config->enabled_at_boot; ret = drvdata->is_enabled ? config->enable_high : !config->enable_high; + gpio_flag = ret ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; + + if (config->gpio_is_open_drain) + gpio_flag |= GPIOF_OPEN_DRAIN; - ret = gpio_direction_output(config->gpio, ret); + ret = gpio_request_one(config->gpio, gpio_flag, + config->supply_name); if (ret) { dev_err(&pdev->dev, - "Could not configure regulator enable GPIO %d direction: %d\n", + "Could not obtain regulator enable GPIO %d: %d\n", config->gpio, ret); - goto err_gpio; + goto err_name; } + drvdata->desc.ops = &fixed_voltage_gpio_ops; + } else { - /* Regulator without GPIO control is considered - * always enabled - */ - drvdata->is_enabled = true; + drvdata->desc.ops = &fixed_voltage_ops; } - drvdata->dev = regulator_register(&drvdata->desc, &pdev->dev, - config->init_data, drvdata, - pdev->dev.of_node); + cfg.dev = &pdev->dev; + cfg.init_data = config->init_data; + cfg.driver_data = drvdata; + cfg.of_node = pdev->dev.of_node; + + drvdata->dev = regulator_register(&drvdata->desc, &cfg); if (IS_ERR(drvdata->dev)) { ret = PTR_ERR(drvdata->dev); dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret); @@ -270,7 +275,6 @@ static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev) err_name: kfree(drvdata->desc.name); err: - kfree(drvdata); return ret; } @@ -282,7 +286,6 @@ static int __devexit reg_fixed_voltage_remove(struct platform_device *pdev) if (gpio_is_valid(drvdata->gpio)) gpio_free(drvdata->gpio); kfree(drvdata->desc.name); - kfree(drvdata); return 0; } diff --git a/trunk/drivers/regulator/gpio-regulator.c b/trunk/drivers/regulator/gpio-regulator.c index 42e1cb1835e5..9997d7aaca84 100644 --- a/trunk/drivers/regulator/gpio-regulator.c +++ b/trunk/drivers/regulator/gpio-regulator.c @@ -30,7 +30,6 @@ #include #include #include -#include #include struct gpio_regulator_data { @@ -105,15 +104,15 @@ static int gpio_regulator_set_value(struct regulator_dev *dev, int min, int max) { struct gpio_regulator_data *data = rdev_get_drvdata(dev); - int ptr, target, state; + int ptr, target, state, best_val = INT_MAX; - target = -1; for (ptr = 0; ptr < data->nr_states; ptr++) - if (data->states[ptr].value >= min && + if (data->states[ptr].value < best_val && + data->states[ptr].value >= min && data->states[ptr].value <= max) target = data->states[ptr].gpios; - if (target < 0) + if (best_val == INT_MAX) return -EINVAL; for (ptr = 0; ptr < data->nr_gpios; ptr++) { @@ -172,9 +171,11 @@ static int __devinit gpio_regulator_probe(struct platform_device *pdev) { struct gpio_regulator_config *config = pdev->dev.platform_data; struct gpio_regulator_data *drvdata; + struct regulator_config cfg = { }; int ptr, ret, state; - drvdata = kzalloc(sizeof(struct gpio_regulator_data), GFP_KERNEL); + drvdata = devm_kzalloc(&pdev->dev, sizeof(struct gpio_regulator_data), + GFP_KERNEL); if (drvdata == NULL) { dev_err(&pdev->dev, "Failed to allocate device data\n"); return -ENOMEM; @@ -283,8 +284,11 @@ static int __devinit gpio_regulator_probe(struct platform_device *pdev) } drvdata->state = state; - drvdata->dev = regulator_register(&drvdata->desc, &pdev->dev, - config->init_data, drvdata, NULL); + cfg.dev = &pdev->dev; + cfg.init_data = config->init_data; + cfg.driver_data = &drvdata; + + drvdata->dev = regulator_register(&drvdata->desc, &cfg); if (IS_ERR(drvdata->dev)) { ret = PTR_ERR(drvdata->dev); dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret); @@ -307,7 +311,6 @@ static int __devinit gpio_regulator_probe(struct platform_device *pdev) err_name: kfree(drvdata->desc.name); err: - kfree(drvdata); return ret; } @@ -326,7 +329,6 @@ static int __devexit gpio_regulator_remove(struct platform_device *pdev) gpio_free(drvdata->enable_gpio); kfree(drvdata->desc.name); - kfree(drvdata); return 0; } diff --git a/trunk/drivers/regulator/isl6271a-regulator.c b/trunk/drivers/regulator/isl6271a-regulator.c index 775f5fd208c3..56d273f25603 100644 --- a/trunk/drivers/regulator/isl6271a-regulator.c +++ b/trunk/drivers/regulator/isl6271a-regulator.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #define ISL6271A_VOLTAGE_MIN 850000 @@ -36,47 +35,30 @@ struct isl_pmic { struct mutex mtx; }; -static int isl6271a_get_voltage(struct regulator_dev *dev) +static int isl6271a_get_voltage_sel(struct regulator_dev *dev) { struct isl_pmic *pmic = rdev_get_drvdata(dev); - int idx, data; + int idx; mutex_lock(&pmic->mtx); idx = i2c_smbus_read_byte(pmic->client); - if (idx < 0) { + if (idx < 0) dev_err(&pmic->client->dev, "Error getting voltage\n"); - data = idx; - goto out; - } - - /* Convert the data from chip to microvolts */ - data = ISL6271A_VOLTAGE_MIN + (ISL6271A_VOLTAGE_STEP * (idx & 0xf)); -out: mutex_unlock(&pmic->mtx); - return data; + return idx; } -static int isl6271a_set_voltage(struct regulator_dev *dev, - int minuV, int maxuV, - unsigned *selector) +static int isl6271a_set_voltage_sel(struct regulator_dev *dev, + unsigned selector) { struct isl_pmic *pmic = rdev_get_drvdata(dev); - int err, data; - - if (minuV < ISL6271A_VOLTAGE_MIN || minuV > ISL6271A_VOLTAGE_MAX) - return -EINVAL; - if (maxuV < ISL6271A_VOLTAGE_MIN || maxuV > ISL6271A_VOLTAGE_MAX) - return -EINVAL; - - data = DIV_ROUND_UP(minuV - ISL6271A_VOLTAGE_MIN, - ISL6271A_VOLTAGE_STEP); - *selector = data; + int err; mutex_lock(&pmic->mtx); - err = i2c_smbus_write_byte(pmic->client, data); + err = i2c_smbus_write_byte(pmic->client, selector); if (err < 0) dev_err(&pmic->client->dev, "Error setting voltage\n"); @@ -84,15 +66,11 @@ static int isl6271a_set_voltage(struct regulator_dev *dev, return err; } -static int isl6271a_list_voltage(struct regulator_dev *dev, unsigned selector) -{ - return ISL6271A_VOLTAGE_MIN + (ISL6271A_VOLTAGE_STEP * selector); -} - static struct regulator_ops isl_core_ops = { - .get_voltage = isl6271a_get_voltage, - .set_voltage = isl6271a_set_voltage, - .list_voltage = isl6271a_list_voltage, + .get_voltage_sel = isl6271a_get_voltage_sel, + .set_voltage_sel = isl6271a_set_voltage_sel, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, }; static int isl6271a_get_fixed_voltage(struct regulator_dev *dev) @@ -112,7 +90,7 @@ static struct regulator_ops isl_fixed_ops = { .list_voltage = isl6271a_list_fixed_voltage, }; -static struct regulator_desc isl_rd[] = { +static const struct regulator_desc isl_rd[] = { { .name = "Core Buck", .id = 0, @@ -120,6 +98,8 @@ static struct regulator_desc isl_rd[] = { .ops = &isl_core_ops, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, + .min_uV = ISL6271A_VOLTAGE_MIN, + .uV_step = ISL6271A_VOLTAGE_STEP, }, { .name = "LDO1", .id = 1, @@ -140,6 +120,7 @@ static struct regulator_desc isl_rd[] = { static int __devinit isl6271a_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { + struct regulator_config config = { }; struct regulator_init_data *init_data = i2c->dev.platform_data; struct isl_pmic *pmic; int err, i; @@ -147,12 +128,7 @@ static int __devinit isl6271a_probe(struct i2c_client *i2c, if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO; - if (!init_data) { - dev_err(&i2c->dev, "no platform data supplied\n"); - return -EIO; - } - - pmic = kzalloc(sizeof(struct isl_pmic), GFP_KERNEL); + pmic = devm_kzalloc(&i2c->dev, sizeof(struct isl_pmic), GFP_KERNEL); if (!pmic) return -ENOMEM; @@ -161,8 +137,14 @@ static int __devinit isl6271a_probe(struct i2c_client *i2c, mutex_init(&pmic->mtx); for (i = 0; i < 3; i++) { - pmic->rdev[i] = regulator_register(&isl_rd[i], &i2c->dev, - init_data, pmic, NULL); + config.dev = &i2c->dev; + if (i == 0) + config.init_data = init_data; + else + config.init_data = 0; + config.driver_data = pmic; + + pmic->rdev[i] = regulator_register(&isl_rd[i], &config); if (IS_ERR(pmic->rdev[i])) { dev_err(&i2c->dev, "failed to register %s\n", id->name); err = PTR_ERR(pmic->rdev[i]); @@ -177,8 +159,6 @@ static int __devinit isl6271a_probe(struct i2c_client *i2c, error: while (--i >= 0) regulator_unregister(pmic->rdev[i]); - - kfree(pmic); return err; } @@ -189,9 +169,6 @@ static int __devexit isl6271a_remove(struct i2c_client *i2c) for (i = 0; i < 3; i++) regulator_unregister(pmic->rdev[i]); - - kfree(pmic); - return 0; } diff --git a/trunk/drivers/regulator/lp3971.c b/trunk/drivers/regulator/lp3971.c index 0cfabd318a59..981bea9cb9d7 100644 --- a/trunk/drivers/regulator/lp3971.c +++ b/trunk/drivers/regulator/lp3971.c @@ -124,6 +124,10 @@ static const int *ldo_voltage_map[] = { static int lp3971_ldo_list_voltage(struct regulator_dev *dev, unsigned index) { int ldo = rdev_get_id(dev) - LP3971_LDO1; + + if (index > LDO_VOL_MAX_IDX) + return -EINVAL; + return 1000 * LDO_VOL_VALUE_MAP(ldo)[index]; } @@ -168,32 +172,15 @@ static int lp3971_ldo_get_voltage(struct regulator_dev *dev) return 1000 * LDO_VOL_VALUE_MAP(ldo)[val]; } -static int lp3971_ldo_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV, - unsigned int *selector) +static int lp3971_ldo_set_voltage_sel(struct regulator_dev *dev, + unsigned int selector) { struct lp3971 *lp3971 = rdev_get_drvdata(dev); int ldo = rdev_get_id(dev) - LP3971_LDO1; - int min_vol = min_uV / 1000, max_vol = max_uV / 1000; - const int *vol_map = LDO_VOL_VALUE_MAP(ldo); - u16 val; - - if (min_vol < vol_map[LDO_VOL_MIN_IDX] || - min_vol > vol_map[LDO_VOL_MAX_IDX]) - return -EINVAL; - - for (val = LDO_VOL_MIN_IDX; val <= LDO_VOL_MAX_IDX; val++) - if (vol_map[val] >= min_vol) - break; - - if (val > LDO_VOL_MAX_IDX || vol_map[val] > max_vol) - return -EINVAL; - - *selector = val; return lp3971_set_bits(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo), LDO_VOL_CONTR_MASK << LDO_VOL_CONTR_SHIFT(ldo), - val << LDO_VOL_CONTR_SHIFT(ldo)); + selector << LDO_VOL_CONTR_SHIFT(ldo)); } static struct regulator_ops lp3971_ldo_ops = { @@ -202,11 +189,14 @@ static struct regulator_ops lp3971_ldo_ops = { .enable = lp3971_ldo_enable, .disable = lp3971_ldo_disable, .get_voltage = lp3971_ldo_get_voltage, - .set_voltage = lp3971_ldo_set_voltage, + .set_voltage_sel = lp3971_ldo_set_voltage_sel, }; static int lp3971_dcdc_list_voltage(struct regulator_dev *dev, unsigned index) { + if (index < BUCK_TARGET_VOL_MIN_IDX || index > BUCK_TARGET_VOL_MAX_IDX) + return -EINVAL; + return 1000 * buck_voltage_map[index]; } @@ -259,33 +249,15 @@ static int lp3971_dcdc_get_voltage(struct regulator_dev *dev) return val; } -static int lp3971_dcdc_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV, - unsigned int *selector) +static int lp3971_dcdc_set_voltage_sel(struct regulator_dev *dev, + unsigned int selector) { struct lp3971 *lp3971 = rdev_get_drvdata(dev); int buck = rdev_get_id(dev) - LP3971_DCDC1; - int min_vol = min_uV / 1000, max_vol = max_uV / 1000; - const int *vol_map = buck_voltage_map; - u16 val; int ret; - if (min_vol < vol_map[BUCK_TARGET_VOL_MIN_IDX] || - min_vol > vol_map[BUCK_TARGET_VOL_MAX_IDX]) - return -EINVAL; - - for (val = BUCK_TARGET_VOL_MIN_IDX; val <= BUCK_TARGET_VOL_MAX_IDX; - val++) - if (vol_map[val] >= min_vol) - break; - - if (val > BUCK_TARGET_VOL_MAX_IDX || vol_map[val] > max_vol) - return -EINVAL; - - *selector = val; - ret = lp3971_set_bits(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck), - BUCK_TARGET_VOL_MASK, val); + BUCK_TARGET_VOL_MASK, selector); if (ret) return ret; @@ -306,10 +278,10 @@ static struct regulator_ops lp3971_dcdc_ops = { .enable = lp3971_dcdc_enable, .disable = lp3971_dcdc_disable, .get_voltage = lp3971_dcdc_get_voltage, - .set_voltage = lp3971_dcdc_set_voltage, + .set_voltage_sel = lp3971_dcdc_set_voltage_sel, }; -static struct regulator_desc regulators[] = { +static const struct regulator_desc regulators[] = { { .name = "LDO1", .id = LP3971_LDO1, @@ -449,10 +421,15 @@ static int __devinit setup_regulators(struct lp3971 *lp3971, /* Instantiate the regulators */ for (i = 0; i < pdata->num_regulators; i++) { + struct regulator_config config = { }; struct lp3971_regulator_subdev *reg = &pdata->regulators[i]; - lp3971->rdev[i] = regulator_register(®ulators[reg->id], - lp3971->dev, reg->initdata, lp3971, NULL); + config.dev = lp3971->dev; + config.init_data = reg->initdata; + config.driver_data = lp3971; + + lp3971->rdev[i] = regulator_register(®ulators[reg->id], + &config); if (IS_ERR(lp3971->rdev[i])) { err = PTR_ERR(lp3971->rdev[i]); dev_err(lp3971->dev, "regulator init failed: %d\n", @@ -545,23 +522,7 @@ static struct i2c_driver lp3971_i2c_driver = { .id_table = lp3971_i2c_id, }; -static int __init lp3971_module_init(void) -{ - int ret; - - ret = i2c_add_driver(&lp3971_i2c_driver); - if (ret != 0) - pr_err("Failed to register I2C driver: %d\n", ret); - - return ret; -} -module_init(lp3971_module_init); - -static void __exit lp3971_module_exit(void) -{ - i2c_del_driver(&lp3971_i2c_driver); -} -module_exit(lp3971_module_exit); +module_i2c_driver(lp3971_i2c_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Marek Szyprowski "); diff --git a/trunk/drivers/regulator/lp3972.c b/trunk/drivers/regulator/lp3972.c index 49a15eefe5fe..de073df7d344 100644 --- a/trunk/drivers/regulator/lp3972.c +++ b/trunk/drivers/regulator/lp3972.c @@ -245,6 +245,11 @@ static int lp3972_set_bits(struct lp3972 *lp3972, u8 reg, u16 mask, u16 val) static int lp3972_ldo_list_voltage(struct regulator_dev *dev, unsigned index) { int ldo = rdev_get_id(dev) - LP3972_LDO1; + + if (index < LP3972_LDO_VOL_MIN_IDX(ldo) || + index > LP3972_LDO_VOL_MAX_IDX(ldo)) + return -EINVAL; + return 1000 * LP3972_LDO_VOL_VALUE_MAP(ldo)[index]; } @@ -292,34 +297,16 @@ static int lp3972_ldo_get_voltage(struct regulator_dev *dev) return 1000 * LP3972_LDO_VOL_VALUE_MAP(ldo)[val]; } -static int lp3972_ldo_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV, - unsigned int *selector) +static int lp3972_ldo_set_voltage_sel(struct regulator_dev *dev, + unsigned int selector) { struct lp3972 *lp3972 = rdev_get_drvdata(dev); int ldo = rdev_get_id(dev) - LP3972_LDO1; - int min_vol = min_uV / 1000, max_vol = max_uV / 1000; - const int *vol_map = LP3972_LDO_VOL_VALUE_MAP(ldo); - u16 val; int shift, ret; - if (min_vol < vol_map[LP3972_LDO_VOL_MIN_IDX(ldo)] || - min_vol > vol_map[LP3972_LDO_VOL_MAX_IDX(ldo)]) - return -EINVAL; - - for (val = LP3972_LDO_VOL_MIN_IDX(ldo); - val <= LP3972_LDO_VOL_MAX_IDX(ldo); val++) - if (vol_map[val] >= min_vol) - break; - - if (val > LP3972_LDO_VOL_MAX_IDX(ldo) || vol_map[val] > max_vol) - return -EINVAL; - - *selector = val; - shift = LP3972_LDO_VOL_CONTR_SHIFT(ldo); ret = lp3972_set_bits(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo), - LP3972_LDO_VOL_MASK(ldo) << shift, val << shift); + LP3972_LDO_VOL_MASK(ldo) << shift, selector << shift); if (ret) return ret; @@ -355,12 +342,17 @@ static struct regulator_ops lp3972_ldo_ops = { .enable = lp3972_ldo_enable, .disable = lp3972_ldo_disable, .get_voltage = lp3972_ldo_get_voltage, - .set_voltage = lp3972_ldo_set_voltage, + .set_voltage_sel = lp3972_ldo_set_voltage_sel, }; static int lp3972_dcdc_list_voltage(struct regulator_dev *dev, unsigned index) { int buck = rdev_get_id(dev) - LP3972_DCDC1; + + if (index < LP3972_BUCK_VOL_MIN_IDX(buck) || + index > LP3972_BUCK_VOL_MAX_IDX(buck)) + return -EINVAL; + return 1000 * buck_voltage_map[buck][index]; } @@ -419,34 +411,15 @@ static int lp3972_dcdc_get_voltage(struct regulator_dev *dev) return val; } -static int lp3972_dcdc_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV, - unsigned int *selector) +static int lp3972_dcdc_set_voltage_sel(struct regulator_dev *dev, + unsigned int selector) { struct lp3972 *lp3972 = rdev_get_drvdata(dev); int buck = rdev_get_id(dev) - LP3972_DCDC1; - int min_vol = min_uV / 1000, max_vol = max_uV / 1000; - const int *vol_map = buck_voltage_map[buck]; - u16 val; int ret; - if (min_vol < vol_map[LP3972_BUCK_VOL_MIN_IDX(buck)] || - min_vol > vol_map[LP3972_BUCK_VOL_MAX_IDX(buck)]) - return -EINVAL; - - for (val = LP3972_BUCK_VOL_MIN_IDX(buck); - val <= LP3972_BUCK_VOL_MAX_IDX(buck); val++) - if (vol_map[val] >= min_vol) - break; - - if (val > LP3972_BUCK_VOL_MAX_IDX(buck) || - vol_map[val] > max_vol) - return -EINVAL; - - *selector = val; - ret = lp3972_set_bits(lp3972, LP3972_BUCK_VOL1_REG(buck), - LP3972_BUCK_VOL_MASK, val); + LP3972_BUCK_VOL_MASK, selector); if (ret) return ret; @@ -468,10 +441,10 @@ static struct regulator_ops lp3972_dcdc_ops = { .enable = lp3972_dcdc_enable, .disable = lp3972_dcdc_disable, .get_voltage = lp3972_dcdc_get_voltage, - .set_voltage = lp3972_dcdc_set_voltage, + .set_voltage_sel = lp3972_dcdc_set_voltage_sel, }; -static struct regulator_desc regulators[] = { +static const struct regulator_desc regulators[] = { { .name = "LDO1", .id = LP3972_LDO1, @@ -554,9 +527,14 @@ static int __devinit setup_regulators(struct lp3972 *lp3972, /* Instantiate the regulators */ for (i = 0; i < pdata->num_regulators; i++) { struct lp3972_regulator_subdev *reg = &pdata->regulators[i]; - lp3972->rdev[i] = regulator_register(®ulators[reg->id], - lp3972->dev, reg->initdata, lp3972, NULL); + struct regulator_config config = { }; + config.dev = lp3972->dev; + config.init_data = reg->initdata; + config.driver_data = lp3972; + + lp3972->rdev[i] = regulator_register(®ulators[reg->id], + &config); if (IS_ERR(lp3972->rdev[i])) { err = PTR_ERR(lp3972->rdev[i]); dev_err(lp3972->dev, "regulator init failed: %d\n", diff --git a/trunk/drivers/regulator/max1586.c b/trunk/drivers/regulator/max1586.c index 282d2ee0604e..b9444ee08da9 100644 --- a/trunk/drivers/regulator/max1586.c +++ b/trunk/drivers/regulator/max1586.c @@ -161,7 +161,7 @@ static struct regulator_ops max1586_v6_ops = { .list_voltage = max1586_v6_list, }; -static struct regulator_desc max1586_reg[] = { +static const struct regulator_desc max1586_reg[] = { { .name = "Output_V3", .id = MAX1586_V3, @@ -185,21 +185,21 @@ static int __devinit max1586_pmic_probe(struct i2c_client *client, { struct regulator_dev **rdev; struct max1586_platform_data *pdata = client->dev.platform_data; + struct regulator_config config = { }; struct max1586_data *max1586; int i, id, ret = -ENOMEM; - max1586 = kzalloc(sizeof(struct max1586_data) + + max1586 = devm_kzalloc(&client->dev, sizeof(struct max1586_data) + sizeof(struct regulator_dev *) * (MAX1586_V6 + 1), GFP_KERNEL); if (!max1586) - goto out; + return -ENOMEM; max1586->client = client; - if (!pdata->v3_gain) { - ret = -EINVAL; - goto out_unmap; - } + if (!pdata->v3_gain) + return -EINVAL; + max1586->min_uV = MAX1586_V3_MIN_UV / 1000 * pdata->v3_gain / 1000; max1586->max_uV = MAX1586_V3_MAX_UV / 1000 * pdata->v3_gain / 1000; @@ -212,9 +212,12 @@ static int __devinit max1586_pmic_probe(struct i2c_client *client, dev_err(&client->dev, "invalid regulator id %d\n", id); goto err; } - rdev[i] = regulator_register(&max1586_reg[id], &client->dev, - pdata->subdevs[i].platform_data, - max1586, NULL); + + config.dev = &client->dev; + config.init_data = pdata->subdevs[i].platform_data; + config.driver_data = max1586; + + rdev[i] = regulator_register(&max1586_reg[id], &config); if (IS_ERR(rdev[i])) { ret = PTR_ERR(rdev[i]); dev_err(&client->dev, "failed to register %s\n", @@ -230,9 +233,6 @@ static int __devinit max1586_pmic_probe(struct i2c_client *client, err: while (--i >= 0) regulator_unregister(rdev[i]); -out_unmap: - kfree(max1586); -out: return ret; } @@ -244,8 +244,6 @@ static int __devexit max1586_pmic_remove(struct i2c_client *client) for (i = 0; i <= MAX1586_V6; i++) if (max1586->rdev[i]) regulator_unregister(max1586->rdev[i]); - kfree(max1586); - return 0; } diff --git a/trunk/drivers/regulator/max8649.c b/trunk/drivers/regulator/max8649.c index 824c650436ed..1f4bb80457b3 100644 --- a/trunk/drivers/regulator/max8649.c +++ b/trunk/drivers/regulator/max8649.c @@ -53,7 +53,6 @@ struct max8649_regulator_info { struct device *dev; struct regmap *regmap; - int vol_reg; unsigned mode:2; /* bit[1:0] = VID1, VID0 */ unsigned extclk_freq:2; unsigned extclk:1; @@ -61,53 +60,6 @@ struct max8649_regulator_info { unsigned ramp_down:1; }; -/* I2C operations */ - -static inline int check_range(int min_uV, int max_uV) -{ - if ((min_uV < MAX8649_DCDC_VMIN) || (max_uV > MAX8649_DCDC_VMAX) - || (min_uV > max_uV)) - return -EINVAL; - return 0; -} - -static int max8649_list_voltage(struct regulator_dev *rdev, unsigned index) -{ - return (MAX8649_DCDC_VMIN + index * MAX8649_DCDC_STEP); -} - -static int max8649_get_voltage(struct regulator_dev *rdev) -{ - struct max8649_regulator_info *info = rdev_get_drvdata(rdev); - unsigned int val; - unsigned char data; - int ret; - - ret = regmap_read(info->regmap, info->vol_reg, &val); - if (ret != 0) - return ret; - data = (unsigned char)val & MAX8649_VOL_MASK; - return max8649_list_voltage(rdev, data); -} - -static int max8649_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned *selector) -{ - struct max8649_regulator_info *info = rdev_get_drvdata(rdev); - unsigned char data, mask; - - if (check_range(min_uV, max_uV)) { - dev_err(info->dev, "invalid voltage range (%d, %d) uV\n", - min_uV, max_uV); - return -EINVAL; - } - data = DIV_ROUND_UP(min_uV - MAX8649_DCDC_VMIN, MAX8649_DCDC_STEP); - mask = MAX8649_VOL_MASK; - *selector = data & mask; - - return regmap_update_bits(info->regmap, info->vol_reg, mask, data); -} - /* EN_PD means pulldown on EN input */ static int max8649_enable(struct regulator_dev *rdev) { @@ -145,11 +97,11 @@ static int max8649_enable_time(struct regulator_dev *rdev) unsigned int val; /* get voltage */ - ret = regmap_read(info->regmap, info->vol_reg, &val); + ret = regmap_read(info->regmap, rdev->desc->vsel_reg, &val); if (ret != 0) return ret; val &= MAX8649_VOL_MASK; - voltage = max8649_list_voltage(rdev, (unsigned char)val); /* uV */ + voltage = regulator_list_voltage_linear(rdev, (unsigned char)val); /* get rate */ ret = regmap_read(info->regmap, MAX8649_RAMP, &val); @@ -167,11 +119,11 @@ static int max8649_set_mode(struct regulator_dev *rdev, unsigned int mode) switch (mode) { case REGULATOR_MODE_FAST: - regmap_update_bits(info->regmap, info->vol_reg, MAX8649_FORCE_PWM, - MAX8649_FORCE_PWM); + regmap_update_bits(info->regmap, rdev->desc->vsel_reg, + MAX8649_FORCE_PWM, MAX8649_FORCE_PWM); break; case REGULATOR_MODE_NORMAL: - regmap_update_bits(info->regmap, info->vol_reg, + regmap_update_bits(info->regmap, rdev->desc->vsel_reg, MAX8649_FORCE_PWM, 0); break; default: @@ -186,7 +138,7 @@ static unsigned int max8649_get_mode(struct regulator_dev *rdev) unsigned int val; int ret; - ret = regmap_read(info->regmap, info->vol_reg, &val); + ret = regmap_read(info->regmap, rdev->desc->vsel_reg, &val); if (ret != 0) return ret; if (val & MAX8649_FORCE_PWM) @@ -195,9 +147,10 @@ static unsigned int max8649_get_mode(struct regulator_dev *rdev) } static struct regulator_ops max8649_dcdc_ops = { - .set_voltage = max8649_set_voltage, - .get_voltage = max8649_get_voltage, - .list_voltage = max8649_list_voltage, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, .enable = max8649_enable, .disable = max8649_disable, .is_enabled = max8649_is_enabled, @@ -213,6 +166,9 @@ static struct regulator_desc dcdc_desc = { .type = REGULATOR_VOLTAGE, .n_voltages = 1 << 6, .owner = THIS_MODULE, + .vsel_mask = MAX8649_VOL_MASK, + .min_uV = MAX8649_DCDC_VMIN, + .uV_step = MAX8649_DCDC_STEP, }; static struct regmap_config max8649_regmap_config = { @@ -225,21 +181,23 @@ static int __devinit max8649_regulator_probe(struct i2c_client *client, { struct max8649_platform_data *pdata = client->dev.platform_data; struct max8649_regulator_info *info = NULL; + struct regulator_config config = { }; unsigned int val; unsigned char data; int ret; - info = kzalloc(sizeof(struct max8649_regulator_info), GFP_KERNEL); + info = devm_kzalloc(&client->dev, sizeof(struct max8649_regulator_info), + GFP_KERNEL); if (!info) { dev_err(&client->dev, "No enough memory\n"); return -ENOMEM; } - info->regmap = regmap_init_i2c(client, &max8649_regmap_config); + info->regmap = devm_regmap_init_i2c(client, &max8649_regmap_config); if (IS_ERR(info->regmap)) { ret = PTR_ERR(info->regmap); dev_err(&client->dev, "Failed to allocate register map: %d\n", ret); - goto fail; + return ret; } info->dev = &client->dev; @@ -248,16 +206,16 @@ static int __devinit max8649_regulator_probe(struct i2c_client *client, info->mode = pdata->mode; switch (info->mode) { case 0: - info->vol_reg = MAX8649_MODE0; + dcdc_desc.vsel_reg = MAX8649_MODE0; break; case 1: - info->vol_reg = MAX8649_MODE1; + dcdc_desc.vsel_reg = MAX8649_MODE1; break; case 2: - info->vol_reg = MAX8649_MODE2; + dcdc_desc.vsel_reg = MAX8649_MODE2; break; case 3: - info->vol_reg = MAX8649_MODE3; + dcdc_desc.vsel_reg = MAX8649_MODE3; break; default: break; @@ -267,7 +225,7 @@ static int __devinit max8649_regulator_probe(struct i2c_client *client, if (ret != 0) { dev_err(info->dev, "Failed to detect ID of MAX8649:%d\n", ret); - goto out; + return ret; } dev_info(info->dev, "Detected MAX8649 (ID:%x)\n", val); @@ -277,7 +235,8 @@ static int __devinit max8649_regulator_probe(struct i2c_client *client, /* enable/disable external clock synchronization */ info->extclk = pdata->extclk; data = (info->extclk) ? MAX8649_SYNC_EXTCLK : 0; - regmap_update_bits(info->regmap, info->vol_reg, MAX8649_SYNC_EXTCLK, data); + regmap_update_bits(info->regmap, dcdc_desc.vsel_reg, + MAX8649_SYNC_EXTCLK, data); if (info->extclk) { /* set external clock frequency */ info->extclk_freq = pdata->extclk_freq; @@ -297,22 +256,18 @@ static int __devinit max8649_regulator_probe(struct i2c_client *client, MAX8649_RAMP_DOWN); } - info->regulator = regulator_register(&dcdc_desc, &client->dev, - pdata->regulator, info, NULL); + config.dev = &client->dev; + config.init_data = pdata->regulator; + config.driver_data = info; + + info->regulator = regulator_register(&dcdc_desc, &config); if (IS_ERR(info->regulator)) { dev_err(info->dev, "failed to register regulator %s\n", dcdc_desc.name); - ret = PTR_ERR(info->regulator); - goto out; + return PTR_ERR(info->regulator); } - dev_info(info->dev, "Max8649 regulator device is detected.\n"); return 0; -out: - regmap_exit(info->regmap); -fail: - kfree(info); - return ret; } static int __devexit max8649_regulator_remove(struct i2c_client *client) @@ -322,8 +277,6 @@ static int __devexit max8649_regulator_remove(struct i2c_client *client) if (info) { if (info->regulator) regulator_unregister(info->regulator); - regmap_exit(info->regmap); - kfree(info); } return 0; @@ -360,4 +313,3 @@ module_exit(max8649_exit); MODULE_DESCRIPTION("MAXIM 8649 voltage regulator driver"); MODULE_AUTHOR("Haojian Zhuang "); MODULE_LICENSE("GPL"); - diff --git a/trunk/drivers/regulator/max8660.c b/trunk/drivers/regulator/max8660.c index 4c5b05311f47..8d531742f593 100644 --- a/trunk/drivers/regulator/max8660.c +++ b/trunk/drivers/regulator/max8660.c @@ -126,42 +126,22 @@ static int max8660_dcdc_disable(struct regulator_dev *rdev) return max8660_write(max8660, MAX8660_OVER1, mask, 0); } -static int max8660_dcdc_list(struct regulator_dev *rdev, unsigned selector) -{ - if (selector > MAX8660_DCDC_MAX_SEL) - return -EINVAL; - return MAX8660_DCDC_MIN_UV + selector * MAX8660_DCDC_STEP; -} - -static int max8660_dcdc_get(struct regulator_dev *rdev) +static int max8660_dcdc_get_voltage_sel(struct regulator_dev *rdev) { struct max8660 *max8660 = rdev_get_drvdata(rdev); + u8 reg = (rdev_get_id(rdev) == MAX8660_V3) ? MAX8660_ADTV2 : MAX8660_SDTV2; u8 selector = max8660->shadow_regs[reg]; - return MAX8660_DCDC_MIN_UV + selector * MAX8660_DCDC_STEP; + return selector; } -static int max8660_dcdc_set(struct regulator_dev *rdev, int min_uV, int max_uV, - unsigned int *s) +static int max8660_dcdc_set_voltage_sel(struct regulator_dev *rdev, + unsigned int selector) { struct max8660 *max8660 = rdev_get_drvdata(rdev); - u8 reg, selector, bits; + u8 reg, bits; int ret; - if (min_uV < MAX8660_DCDC_MIN_UV || min_uV > MAX8660_DCDC_MAX_UV) - return -EINVAL; - if (max_uV < MAX8660_DCDC_MIN_UV || max_uV > MAX8660_DCDC_MAX_UV) - return -EINVAL; - - selector = DIV_ROUND_UP(min_uV - MAX8660_DCDC_MIN_UV, - MAX8660_DCDC_STEP); - - ret = max8660_dcdc_list(rdev, selector); - if (ret < 0 || ret > max_uV) - return -EINVAL; - - *s = selector; - reg = (rdev_get_id(rdev) == MAX8660_V3) ? MAX8660_ADTV2 : MAX8660_SDTV2; ret = max8660_write(max8660, reg, 0, selector); if (ret) @@ -174,9 +154,10 @@ static int max8660_dcdc_set(struct regulator_dev *rdev, int min_uV, int max_uV, static struct regulator_ops max8660_dcdc_ops = { .is_enabled = max8660_dcdc_is_enabled, - .list_voltage = max8660_dcdc_list, - .set_voltage = max8660_dcdc_set, - .get_voltage = max8660_dcdc_get, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .set_voltage_sel = max8660_dcdc_set_voltage_sel, + .get_voltage_sel = max8660_dcdc_get_voltage_sel, }; @@ -184,42 +165,20 @@ static struct regulator_ops max8660_dcdc_ops = { * LDO5 functions */ -static int max8660_ldo5_list(struct regulator_dev *rdev, unsigned selector) -{ - if (selector > MAX8660_LDO5_MAX_SEL) - return -EINVAL; - return MAX8660_LDO5_MIN_UV + selector * MAX8660_LDO5_STEP; -} - -static int max8660_ldo5_get(struct regulator_dev *rdev) +static int max8660_ldo5_get_voltage_sel(struct regulator_dev *rdev) { struct max8660 *max8660 = rdev_get_drvdata(rdev); - u8 selector = max8660->shadow_regs[MAX8660_MDTV2]; - return MAX8660_LDO5_MIN_UV + selector * MAX8660_LDO5_STEP; + u8 selector = max8660->shadow_regs[MAX8660_MDTV2]; + return selector; } -static int max8660_ldo5_set(struct regulator_dev *rdev, int min_uV, int max_uV, - unsigned int *s) +static int max8660_ldo5_set_voltage_sel(struct regulator_dev *rdev, + unsigned int selector) { struct max8660 *max8660 = rdev_get_drvdata(rdev); - u8 selector; int ret; - if (min_uV < MAX8660_LDO5_MIN_UV || min_uV > MAX8660_LDO5_MAX_UV) - return -EINVAL; - if (max_uV < MAX8660_LDO5_MIN_UV || max_uV > MAX8660_LDO5_MAX_UV) - return -EINVAL; - - selector = DIV_ROUND_UP(min_uV - MAX8660_LDO5_MIN_UV, - MAX8660_LDO5_STEP); - - ret = max8660_ldo5_list(rdev, selector); - if (ret < 0 || ret > max_uV) - return -EINVAL; - - *s = selector; - ret = max8660_write(max8660, MAX8660_MDTV2, 0, selector); if (ret) return ret; @@ -229,9 +188,10 @@ static int max8660_ldo5_set(struct regulator_dev *rdev, int min_uV, int max_uV, } static struct regulator_ops max8660_ldo5_ops = { - .list_voltage = max8660_ldo5_list, - .set_voltage = max8660_ldo5_set, - .get_voltage = max8660_ldo5_get, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .set_voltage_sel = max8660_ldo5_set_voltage_sel, + .get_voltage_sel = max8660_ldo5_get_voltage_sel, }; @@ -261,59 +221,38 @@ static int max8660_ldo67_disable(struct regulator_dev *rdev) return max8660_write(max8660, MAX8660_OVER2, mask, 0); } -static int max8660_ldo67_list(struct regulator_dev *rdev, unsigned selector) -{ - if (selector > MAX8660_LDO67_MAX_SEL) - return -EINVAL; - return MAX8660_LDO67_MIN_UV + selector * MAX8660_LDO67_STEP; -} - -static int max8660_ldo67_get(struct regulator_dev *rdev) +static int max8660_ldo67_get_voltage_sel(struct regulator_dev *rdev) { struct max8660 *max8660 = rdev_get_drvdata(rdev); + u8 shift = (rdev_get_id(rdev) == MAX8660_V6) ? 0 : 4; u8 selector = (max8660->shadow_regs[MAX8660_L12VCR] >> shift) & 0xf; - - return MAX8660_LDO67_MIN_UV + selector * MAX8660_LDO67_STEP; + return selector; } -static int max8660_ldo67_set(struct regulator_dev *rdev, int min_uV, - int max_uV, unsigned int *s) +static int max8660_ldo67_set_voltage_sel(struct regulator_dev *rdev, + unsigned int selector) { struct max8660 *max8660 = rdev_get_drvdata(rdev); - u8 selector; - int ret; - - if (min_uV < MAX8660_LDO67_MIN_UV || min_uV > MAX8660_LDO67_MAX_UV) - return -EINVAL; - if (max_uV < MAX8660_LDO67_MIN_UV || max_uV > MAX8660_LDO67_MAX_UV) - return -EINVAL; - - selector = DIV_ROUND_UP(min_uV - MAX8660_LDO67_MIN_UV, - MAX8660_LDO67_STEP); - - ret = max8660_ldo67_list(rdev, selector); - if (ret < 0 || ret > max_uV) - return -EINVAL; - - *s = selector; if (rdev_get_id(rdev) == MAX8660_V6) return max8660_write(max8660, MAX8660_L12VCR, 0xf0, selector); else - return max8660_write(max8660, MAX8660_L12VCR, 0x0f, selector << 4); + return max8660_write(max8660, MAX8660_L12VCR, 0x0f, + selector << 4); } static struct regulator_ops max8660_ldo67_ops = { .is_enabled = max8660_ldo67_is_enabled, .enable = max8660_ldo67_enable, .disable = max8660_ldo67_disable, - .list_voltage = max8660_ldo67_list, - .get_voltage = max8660_ldo67_get, - .set_voltage = max8660_ldo67_set, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = max8660_ldo67_get_voltage_sel, + .set_voltage_sel = max8660_ldo67_set_voltage_sel, }; -static struct regulator_desc max8660_reg[] = { +static const struct regulator_desc max8660_reg[] = { { .name = "V3(DCDC)", .id = MAX8660_V3, @@ -321,6 +260,8 @@ static struct regulator_desc max8660_reg[] = { .type = REGULATOR_VOLTAGE, .n_voltages = MAX8660_DCDC_MAX_SEL + 1, .owner = THIS_MODULE, + .min_uV = MAX8660_DCDC_MIN_UV, + .uV_step = MAX8660_DCDC_STEP, }, { .name = "V4(DCDC)", @@ -329,6 +270,8 @@ static struct regulator_desc max8660_reg[] = { .type = REGULATOR_VOLTAGE, .n_voltages = MAX8660_DCDC_MAX_SEL + 1, .owner = THIS_MODULE, + .min_uV = MAX8660_DCDC_MIN_UV, + .uV_step = MAX8660_DCDC_STEP, }, { .name = "V5(LDO)", @@ -337,6 +280,8 @@ static struct regulator_desc max8660_reg[] = { .type = REGULATOR_VOLTAGE, .n_voltages = MAX8660_LDO5_MAX_SEL + 1, .owner = THIS_MODULE, + .min_uV = MAX8660_LDO5_MIN_UV, + .uV_step = MAX8660_LDO5_STEP, }, { .name = "V6(LDO)", @@ -345,6 +290,8 @@ static struct regulator_desc max8660_reg[] = { .type = REGULATOR_VOLTAGE, .n_voltages = MAX8660_LDO67_MAX_SEL + 1, .owner = THIS_MODULE, + .min_uV = MAX8660_LDO67_MIN_UV, + .uV_step = MAX8660_LDO67_STEP, }, { .name = "V7(LDO)", @@ -353,6 +300,8 @@ static struct regulator_desc max8660_reg[] = { .type = REGULATOR_VOLTAGE, .n_voltages = MAX8660_LDO67_MAX_SEL + 1, .owner = THIS_MODULE, + .min_uV = MAX8660_LDO67_MIN_UV, + .uV_step = MAX8660_LDO67_STEP, }, }; @@ -361,21 +310,20 @@ static int __devinit max8660_probe(struct i2c_client *client, { struct regulator_dev **rdev; struct max8660_platform_data *pdata = client->dev.platform_data; + struct regulator_config config = { }; struct max8660 *max8660; int boot_on, i, id, ret = -EINVAL; if (pdata->num_subdevs > MAX8660_V_END) { dev_err(&client->dev, "Too many regulators found!\n"); - goto out; + return -EINVAL; } - max8660 = kzalloc(sizeof(struct max8660) + + max8660 = devm_kzalloc(&client->dev, sizeof(struct max8660) + sizeof(struct regulator_dev *) * MAX8660_V_END, GFP_KERNEL); - if (!max8660) { - ret = -ENOMEM; - goto out; - } + if (!max8660) + return -ENOMEM; max8660->client = client; rdev = max8660->rdev; @@ -404,7 +352,7 @@ static int __devinit max8660_probe(struct i2c_client *client, for (i = 0; i < pdata->num_subdevs; i++) { if (!pdata->subdevs[i].platform_data) - goto err_free; + goto err_out; boot_on = pdata->subdevs[i].platform_data->constraints.boot_on; @@ -430,7 +378,7 @@ static int __devinit max8660_probe(struct i2c_client *client, case MAX8660_V7: if (!strcmp(i2c_id->name, "max8661")) { dev_err(&client->dev, "Regulator not on this chip!\n"); - goto err_free; + goto err_out; } if (boot_on) @@ -440,7 +388,7 @@ static int __devinit max8660_probe(struct i2c_client *client, default: dev_err(&client->dev, "invalid regulator %s\n", pdata->subdevs[i].name); - goto err_free; + goto err_out; } } @@ -449,9 +397,11 @@ static int __devinit max8660_probe(struct i2c_client *client, id = pdata->subdevs[i].id; - rdev[i] = regulator_register(&max8660_reg[id], &client->dev, - pdata->subdevs[i].platform_data, - max8660, NULL); + config.dev = &client->dev; + config.init_data = pdata->subdevs[i].platform_data; + config.driver_data = max8660; + + rdev[i] = regulator_register(&max8660_reg[id], &config); if (IS_ERR(rdev[i])) { ret = PTR_ERR(rdev[i]); dev_err(&client->dev, "failed to register %s\n", @@ -461,15 +411,12 @@ static int __devinit max8660_probe(struct i2c_client *client, } i2c_set_clientdata(client, max8660); - dev_info(&client->dev, "Maxim 8660/8661 regulator driver loaded\n"); return 0; err_unregister: while (--i >= 0) regulator_unregister(rdev[i]); -err_free: - kfree(max8660); -out: +err_out: return ret; } @@ -481,8 +428,6 @@ static int __devexit max8660_remove(struct i2c_client *client) for (i = 0; i < MAX8660_V_END; i++) if (max8660->rdev[i]) regulator_unregister(max8660->rdev[i]); - kfree(max8660); - return 0; } diff --git a/trunk/drivers/regulator/max8925-regulator.c b/trunk/drivers/regulator/max8925-regulator.c index 2f242f43096e..43dc97ec3932 100644 --- a/trunk/drivers/regulator/max8925-regulator.c +++ b/trunk/drivers/regulator/max8925-regulator.c @@ -38,50 +38,20 @@ struct max8925_regulator_info { struct i2c_client *i2c; struct max8925_chip *chip; - int min_uV; - int max_uV; - int step_uV; int vol_reg; - int vol_shift; - int vol_nbits; int enable_reg; }; -static inline int check_range(struct max8925_regulator_info *info, - int min_uV, int max_uV) -{ - if (min_uV < info->min_uV || min_uV > info->max_uV) - return -EINVAL; - - return 0; -} - -static int max8925_list_voltage(struct regulator_dev *rdev, unsigned index) -{ - struct max8925_regulator_info *info = rdev_get_drvdata(rdev); - return info->min_uV + index * info->step_uV; -} - -static int max8925_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned int *selector) +static int max8925_set_voltage_sel(struct regulator_dev *rdev, + unsigned int selector) { struct max8925_regulator_info *info = rdev_get_drvdata(rdev); - unsigned char data, mask; - - if (check_range(info, min_uV, max_uV)) { - dev_err(info->chip->dev, "invalid voltage range (%d, %d) uV\n", - min_uV, max_uV); - return -EINVAL; - } - data = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV); - *selector = data; - data <<= info->vol_shift; - mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; + unsigned char mask = rdev->desc->n_voltages - 1; - return max8925_set_bits(info->i2c, info->vol_reg, mask, data); + return max8925_set_bits(info->i2c, info->vol_reg, mask, selector); } -static int max8925_get_voltage(struct regulator_dev *rdev) +static int max8925_get_voltage_sel(struct regulator_dev *rdev) { struct max8925_regulator_info *info = rdev_get_drvdata(rdev); unsigned char data, mask; @@ -90,10 +60,10 @@ static int max8925_get_voltage(struct regulator_dev *rdev) ret = max8925_reg_read(info->i2c, info->vol_reg); if (ret < 0) return ret; - mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; - data = (ret & mask) >> info->vol_shift; + mask = rdev->desc->n_voltages - 1; + data = ret & mask; - return max8925_list_voltage(rdev, data); + return data; } static int max8925_enable(struct regulator_dev *rdev) @@ -163,8 +133,10 @@ static int max8925_set_dvm_disable(struct regulator_dev *rdev) } static struct regulator_ops max8925_regulator_sdv_ops = { - .set_voltage = max8925_set_voltage, - .get_voltage = max8925_get_voltage, + .map_voltage = regulator_map_voltage_linear, + .list_voltage = regulator_list_voltage_linear, + .set_voltage_sel = max8925_set_voltage_sel, + .get_voltage_sel = max8925_get_voltage_sel, .enable = max8925_enable, .disable = max8925_disable, .is_enabled = max8925_is_enabled, @@ -174,8 +146,10 @@ static struct regulator_ops max8925_regulator_sdv_ops = { }; static struct regulator_ops max8925_regulator_ldo_ops = { - .set_voltage = max8925_set_voltage, - .get_voltage = max8925_get_voltage, + .map_voltage = regulator_map_voltage_linear, + .list_voltage = regulator_list_voltage_linear, + .set_voltage_sel = max8925_set_voltage_sel, + .get_voltage_sel = max8925_get_voltage_sel, .enable = max8925_enable, .disable = max8925_disable, .is_enabled = max8925_is_enabled, @@ -189,13 +163,11 @@ static struct regulator_ops max8925_regulator_ldo_ops = { .type = REGULATOR_VOLTAGE, \ .id = MAX8925_ID_SD##_id, \ .owner = THIS_MODULE, \ + .n_voltages = 64, \ + .min_uV = min * 1000, \ + .uV_step = step * 1000, \ }, \ - .min_uV = min * 1000, \ - .max_uV = max * 1000, \ - .step_uV = step * 1000, \ .vol_reg = MAX8925_SDV##_id, \ - .vol_shift = 0, \ - .vol_nbits = 6, \ .enable_reg = MAX8925_SDCTL##_id, \ } @@ -207,13 +179,11 @@ static struct regulator_ops max8925_regulator_ldo_ops = { .type = REGULATOR_VOLTAGE, \ .id = MAX8925_ID_LDO##_id, \ .owner = THIS_MODULE, \ + .n_voltages = 64, \ + .min_uV = min * 1000, \ + .uV_step = step * 1000, \ }, \ - .min_uV = min * 1000, \ - .max_uV = max * 1000, \ - .step_uV = step * 1000, \ .vol_reg = MAX8925_LDOVOUT##_id, \ - .vol_shift = 0, \ - .vol_nbits = 6, \ .enable_reg = MAX8925_LDOCTL##_id, \ } @@ -261,6 +231,7 @@ static int __devinit max8925_regulator_probe(struct platform_device *pdev) { struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); struct max8925_platform_data *pdata = chip->dev->platform_data; + struct regulator_config config = { }; struct max8925_regulator_info *ri; struct regulator_dev *rdev; @@ -272,8 +243,11 @@ static int __devinit max8925_regulator_probe(struct platform_device *pdev) ri->i2c = chip->i2c; ri->chip = chip; - rdev = regulator_register(&ri->desc, &pdev->dev, - pdata->regulator[pdev->id], ri, NULL); + config.dev = &pdev->dev; + config.init_data = pdata->regulator[pdev->id]; + config.driver_data = ri; + + rdev = regulator_register(&ri->desc, &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register regulator %s\n", ri->desc.name); @@ -319,4 +293,3 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Haojian Zhuang "); MODULE_DESCRIPTION("Regulator Driver for Maxim 8925 PMIC"); MODULE_ALIAS("platform:max8925-regulator"); - diff --git a/trunk/drivers/regulator/max8952.c b/trunk/drivers/regulator/max8952.c index 75d89400c123..910c9b26d499 100644 --- a/trunk/drivers/regulator/max8952.c +++ b/trunk/drivers/regulator/max8952.c @@ -69,11 +69,6 @@ static int max8952_write_reg(struct max8952_data *max8952, return i2c_smbus_write_byte_data(max8952->client, reg, value); } -static int max8952_voltage(struct max8952_data *max8952, u8 mode) -{ - return (max8952->pdata->dvs_mode[mode] * 10 + 770) * 1000; -} - static int max8952_list_voltage(struct regulator_dev *rdev, unsigned int selector) { @@ -82,7 +77,7 @@ static int max8952_list_voltage(struct regulator_dev *rdev, if (rdev_get_id(rdev) != 0) return -EINVAL; - return max8952_voltage(max8952, selector); + return (max8952->pdata->dvs_mode[selector] * 10 + 770) * 1000; } static int max8952_is_enabled(struct regulator_dev *rdev) @@ -117,7 +112,7 @@ static int max8952_disable(struct regulator_dev *rdev) return 0; } -static int max8952_get_voltage(struct regulator_dev *rdev) +static int max8952_get_voltage_sel(struct regulator_dev *rdev) { struct max8952_data *max8952 = rdev_get_drvdata(rdev); u8 vid = 0; @@ -127,14 +122,13 @@ static int max8952_get_voltage(struct regulator_dev *rdev) if (max8952->vid1) vid += 2; - return max8952_voltage(max8952, vid); + return vid; } -static int max8952_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned *selector) +static int max8952_set_voltage_sel(struct regulator_dev *rdev, + unsigned selector) { struct max8952_data *max8952 = rdev_get_drvdata(rdev); - s8 vid = -1, i; if (!gpio_is_valid(max8952->pdata->gpio_vid0) || !gpio_is_valid(max8952->pdata->gpio_vid1)) { @@ -142,23 +136,10 @@ static int max8952_set_voltage(struct regulator_dev *rdev, return -EPERM; } - for (i = 0; i < MAX8952_NUM_DVS_MODE; i++) { - int volt = max8952_voltage(max8952, i); - - /* Set the voltage as low as possible within the range */ - if (volt <= max_uV && volt >= min_uV) - if (vid == -1 || max8952_voltage(max8952, vid) > volt) - vid = i; - } - - if (vid >= 0 && vid < MAX8952_NUM_DVS_MODE) { - max8952->vid0 = (vid % 2 == 1); - max8952->vid1 = (((vid >> 1) % 2) == 1); - *selector = vid; - gpio_set_value(max8952->pdata->gpio_vid0, max8952->vid0); - gpio_set_value(max8952->pdata->gpio_vid1, max8952->vid1); - } else - return -EINVAL; + max8952->vid0 = selector & 0x1; + max8952->vid1 = (selector >> 1) & 0x1; + gpio_set_value(max8952->pdata->gpio_vid0, max8952->vid0); + gpio_set_value(max8952->pdata->gpio_vid1, max8952->vid1); return 0; } @@ -168,12 +149,12 @@ static struct regulator_ops max8952_ops = { .is_enabled = max8952_is_enabled, .enable = max8952_enable, .disable = max8952_disable, - .get_voltage = max8952_get_voltage, - .set_voltage = max8952_set_voltage, + .get_voltage_sel = max8952_get_voltage_sel, + .set_voltage_sel = max8952_set_voltage_sel, .set_suspend_disable = max8952_disable, }; -static struct regulator_desc regulator = { +static const struct regulator_desc regulator = { .name = "MAX8952_VOUT", .id = 0, .n_voltages = MAX8952_NUM_DVS_MODE, @@ -187,6 +168,7 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client, { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); struct max8952_platform_data *pdata = client->dev.platform_data; + struct regulator_config config = { }; struct max8952_data *max8952; int ret = 0, err = 0; @@ -199,7 +181,8 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client, if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) return -EIO; - max8952 = kzalloc(sizeof(struct max8952_data), GFP_KERNEL); + max8952 = devm_kzalloc(&client->dev, sizeof(struct max8952_data), + GFP_KERNEL); if (!max8952) return -ENOMEM; @@ -207,18 +190,21 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client, max8952->dev = &client->dev; max8952->pdata = pdata; - max8952->rdev = regulator_register(®ulator, max8952->dev, - &pdata->reg_data, max8952, NULL); + config.dev = max8952->dev; + config.init_data = &pdata->reg_data; + config.driver_data = max8952; + + max8952->rdev = regulator_register(®ulator, &config); if (IS_ERR(max8952->rdev)) { ret = PTR_ERR(max8952->rdev); dev_err(max8952->dev, "regulator init failed (%d)\n", ret); - goto err_reg; + return ret; } max8952->en = !!(pdata->reg_data.constraints.boot_on); - max8952->vid0 = (pdata->default_mode % 2) == 1; - max8952->vid1 = ((pdata->default_mode >> 1) % 2) == 1; + max8952->vid0 = pdata->default_mode & 0x1; + max8952->vid1 = (pdata->default_mode >> 1) & 0x1; if (gpio_is_valid(pdata->gpio_en)) { if (!gpio_request(pdata->gpio_en, "MAX8952 EN")) @@ -241,13 +227,13 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client, gpio_is_valid(pdata->gpio_vid1)) { if (!gpio_request(pdata->gpio_vid0, "MAX8952 VID0")) gpio_direction_output(pdata->gpio_vid0, - (pdata->default_mode) % 2); + (pdata->default_mode) & 0x1); else err = 1; if (!gpio_request(pdata->gpio_vid1, "MAX8952 VID1")) gpio_direction_output(pdata->gpio_vid1, - (pdata->default_mode >> 1) % 2); + (pdata->default_mode >> 1) & 0x1); else { if (!err) gpio_free(pdata->gpio_vid0); @@ -310,10 +296,6 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client, i2c_set_clientdata(client, max8952); return 0; - -err_reg: - kfree(max8952); - return ret; } static int __devexit max8952_pmic_remove(struct i2c_client *client) @@ -327,8 +309,6 @@ static int __devexit max8952_pmic_remove(struct i2c_client *client) gpio_free(pdata->gpio_vid0); gpio_free(pdata->gpio_vid1); gpio_free(pdata->gpio_en); - - kfree(max8952); return 0; } diff --git a/trunk/drivers/regulator/max8997.c b/trunk/drivers/regulator/max8997.c index 17a58c56eebf..704cd49ef375 100644 --- a/trunk/drivers/regulator/max8997.c +++ b/trunk/drivers/regulator/max8997.c @@ -22,7 +22,6 @@ */ #include -#include #include #include #include @@ -68,29 +67,28 @@ struct voltage_map_desc { int min; int max; int step; - unsigned int n_bits; }; /* Voltage maps in mV */ static const struct voltage_map_desc ldo_voltage_map_desc = { - .min = 800, .max = 3950, .step = 50, .n_bits = 6, + .min = 800, .max = 3950, .step = 50, }; /* LDO1 ~ 18, 21 all */ static const struct voltage_map_desc buck1245_voltage_map_desc = { - .min = 650, .max = 2225, .step = 25, .n_bits = 6, + .min = 650, .max = 2225, .step = 25, }; /* Buck1, 2, 4, 5 */ static const struct voltage_map_desc buck37_voltage_map_desc = { - .min = 750, .max = 3900, .step = 50, .n_bits = 6, + .min = 750, .max = 3900, .step = 50, }; /* Buck3, 7 */ /* current map in mA */ static const struct voltage_map_desc charger_current_map_desc = { - .min = 200, .max = 950, .step = 50, .n_bits = 4, + .min = 200, .max = 950, .step = 50, }; static const struct voltage_map_desc topoff_current_map_desc = { - .min = 50, .max = 200, .step = 10, .n_bits = 4, + .min = 50, .max = 200, .step = 10, }; static const struct voltage_map_desc *reg_voltage_map[] = { @@ -279,9 +277,7 @@ static int max8997_reg_is_enabled(struct regulator_dev *rdev) u8 val; ret = max8997_get_enable_register(rdev, ®, &mask, &pattern); - if (ret == -EINVAL) - return 1; /* "not controllable" */ - else if (ret) + if (ret) return ret; ret = max8997_read_reg(i2c, reg, &val); @@ -320,6 +316,7 @@ static int max8997_reg_disable(struct regulator_dev *rdev) static int max8997_get_voltage_register(struct regulator_dev *rdev, int *_reg, int *_shift, int *_mask) { + struct max8997_data *max8997 = rdev_get_drvdata(rdev); int rid = rdev_get_id(rdev); int reg, shift = 0, mask = 0x3f; @@ -329,9 +326,13 @@ static int max8997_get_voltage_register(struct regulator_dev *rdev, break; case MAX8997_BUCK1: reg = MAX8997_REG_BUCK1DVS1; + if (max8997->buck1_gpiodvs) + reg += max8997->buck125_gpioindex; break; case MAX8997_BUCK2: reg = MAX8997_REG_BUCK2DVS1; + if (max8997->buck2_gpiodvs) + reg += max8997->buck125_gpioindex; break; case MAX8997_BUCK3: reg = MAX8997_REG_BUCK3DVS; @@ -341,6 +342,8 @@ static int max8997_get_voltage_register(struct regulator_dev *rdev, break; case MAX8997_BUCK5: reg = MAX8997_REG_BUCK5DVS1; + if (max8997->buck5_gpiodvs) + reg += max8997->buck125_gpioindex; break; case MAX8997_BUCK7: reg = MAX8997_REG_BUCK7DVS; @@ -376,23 +379,17 @@ static int max8997_get_voltage_register(struct regulator_dev *rdev, return 0; } -static int max8997_get_voltage(struct regulator_dev *rdev) +static int max8997_get_voltage_sel(struct regulator_dev *rdev) { struct max8997_data *max8997 = rdev_get_drvdata(rdev); struct i2c_client *i2c = max8997->iodev->i2c; int reg, shift, mask, ret; - int rid = rdev_get_id(rdev); u8 val; ret = max8997_get_voltage_register(rdev, ®, &shift, &mask); if (ret) return ret; - if ((rid == MAX8997_BUCK1 && max8997->buck1_gpiodvs) || - (rid == MAX8997_BUCK2 && max8997->buck2_gpiodvs) || - (rid == MAX8997_BUCK5 && max8997->buck5_gpiodvs)) - reg += max8997->buck125_gpioindex; - ret = max8997_read_reg(i2c, reg, &val); if (ret) return ret; @@ -400,22 +397,14 @@ static int max8997_get_voltage(struct regulator_dev *rdev) val >>= shift; val &= mask; - if (rdev->desc && rdev->desc->ops && rdev->desc->ops->list_voltage) - return rdev->desc->ops->list_voltage(rdev, val); - - /* - * max8997_list_voltage returns value for any rdev with voltage_map, - * which works for "CHARGER" and "CHARGER TOPOFF" that do not have - * list_voltage ops (they are current regulators). - */ - return max8997_list_voltage(rdev, val); + return val; } static inline int max8997_get_voltage_proper_val( const struct voltage_map_desc *desc, int min_vol, int max_vol) { - int i = 0; + int i; if (desc == NULL) return -EINVAL; @@ -423,14 +412,12 @@ static inline int max8997_get_voltage_proper_val( if (max_vol < desc->min || min_vol > desc->max) return -EINVAL; - while (desc->min + desc->step * i < min_vol && - desc->min + desc->step * i < desc->max) - i++; + if (min_vol < desc->min) + min_vol = desc->min; - if (desc->min + desc->step * i > max_vol) - return -EINVAL; + i = DIV_ROUND_UP(min_vol - desc->min, desc->step); - if (i >= (1 << desc->n_bits)) + if (desc->min + desc->step * i > max_vol) return -EINVAL; return i; @@ -499,9 +486,7 @@ static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev, int min_vol = min_uV / 1000, max_vol = max_uV / 1000; const struct voltage_map_desc *desc; int rid = rdev_get_id(rdev); - int reg, shift = 0, mask, ret; - int i; - u8 org; + int i, reg, shift, mask, ret; switch (rid) { case MAX8997_LDO1 ... MAX8997_LDO21: @@ -530,21 +515,50 @@ static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev, if (ret) return ret; - max8997_read_reg(i2c, reg, &org); - org = (org & mask) >> shift; - ret = max8997_update_reg(i2c, reg, i << shift, mask << shift); *selector = i; - if (rid == MAX8997_BUCK1 || rid == MAX8997_BUCK2 || - rid == MAX8997_BUCK4 || rid == MAX8997_BUCK5) { - /* If the voltage is increasing */ - if (org < i) - udelay(DIV_ROUND_UP(desc->step * (i - org), - max8997->ramp_delay)); + return ret; +} + +static int max8997_set_voltage_ldobuck_time_sel(struct regulator_dev *rdev, + unsigned int old_selector, + unsigned int new_selector) +{ + struct max8997_data *max8997 = rdev_get_drvdata(rdev); + int rid = rdev_get_id(rdev); + const struct voltage_map_desc *desc = reg_voltage_map[rid]; + + /* Delay is required only if the voltage is increasing */ + if (old_selector >= new_selector) + return 0; + + /* No need to delay if gpio_dvs_mode */ + switch (rid) { + case MAX8997_BUCK1: + if (max8997->buck1_gpiodvs) + return 0; + break; + case MAX8997_BUCK2: + if (max8997->buck2_gpiodvs) + return 0; + break; + case MAX8997_BUCK5: + if (max8997->buck5_gpiodvs) + return 0; + break; } - return ret; + switch (rid) { + case MAX8997_BUCK1: + case MAX8997_BUCK2: + case MAX8997_BUCK4: + case MAX8997_BUCK5: + return DIV_ROUND_UP(desc->step * (new_selector - old_selector), + max8997->ramp_delay); + } + + return 0; } /* @@ -751,11 +765,6 @@ static int max8997_set_voltage_safeout(struct regulator_dev *rdev, return ret; } -static int max8997_reg_enable_suspend(struct regulator_dev *rdev) -{ - return 0; -} - static int max8997_reg_disable_suspend(struct regulator_dev *rdev) { struct max8997_data *max8997 = rdev_get_drvdata(rdev); @@ -788,9 +797,9 @@ static struct regulator_ops max8997_ldo_ops = { .is_enabled = max8997_reg_is_enabled, .enable = max8997_reg_enable, .disable = max8997_reg_disable, - .get_voltage = max8997_get_voltage, + .get_voltage_sel = max8997_get_voltage_sel, .set_voltage = max8997_set_voltage_ldobuck, - .set_suspend_enable = max8997_reg_enable_suspend, + .set_voltage_time_sel = max8997_set_voltage_ldobuck_time_sel, .set_suspend_disable = max8997_reg_disable_suspend, }; @@ -799,9 +808,9 @@ static struct regulator_ops max8997_buck_ops = { .is_enabled = max8997_reg_is_enabled, .enable = max8997_reg_enable, .disable = max8997_reg_disable, - .get_voltage = max8997_get_voltage, + .get_voltage_sel = max8997_get_voltage_sel, .set_voltage = max8997_set_voltage_buck, - .set_suspend_enable = max8997_reg_enable_suspend, + .set_voltage_time_sel = max8997_set_voltage_ldobuck_time_sel, .set_suspend_disable = max8997_reg_disable_suspend, }; @@ -810,7 +819,6 @@ static struct regulator_ops max8997_fixedvolt_ops = { .is_enabled = max8997_reg_is_enabled, .enable = max8997_reg_enable, .disable = max8997_reg_disable, - .set_suspend_enable = max8997_reg_enable_suspend, .set_suspend_disable = max8997_reg_disable_suspend, }; @@ -819,144 +827,117 @@ static struct regulator_ops max8997_safeout_ops = { .is_enabled = max8997_reg_is_enabled, .enable = max8997_reg_enable, .disable = max8997_reg_disable, - .get_voltage = max8997_get_voltage, + .get_voltage_sel = max8997_get_voltage_sel, .set_voltage = max8997_set_voltage_safeout, - .set_suspend_enable = max8997_reg_enable_suspend, .set_suspend_disable = max8997_reg_disable_suspend, }; static struct regulator_ops max8997_fixedstate_ops = { .list_voltage = max8997_list_voltage_charger_cv, - .get_voltage = max8997_get_voltage, + .get_voltage_sel = max8997_get_voltage_sel, .set_voltage = max8997_set_voltage_charger_cv, }; -static int max8997_set_voltage_ldobuck_wrap(struct regulator_dev *rdev, - int min_uV, int max_uV) +static int max8997_set_current_limit(struct regulator_dev *rdev, + int min_uA, int max_uA) { unsigned dummy; + int rid = rdev_get_id(rdev); + + if (rid != MAX8997_CHARGER && rid != MAX8997_CHARGER_TOPOFF) + return -EINVAL; - return max8997_set_voltage_ldobuck(rdev, min_uV, max_uV, &dummy); + /* Reuse max8997_set_voltage_ldobuck to set current_limit. */ + return max8997_set_voltage_ldobuck(rdev, min_uA, max_uA, &dummy); } +static int max8997_get_current_limit(struct regulator_dev *rdev) +{ + int sel, rid = rdev_get_id(rdev); + + if (rid != MAX8997_CHARGER && rid != MAX8997_CHARGER_TOPOFF) + return -EINVAL; + + sel = max8997_get_voltage_sel(rdev); + if (sel < 0) + return sel; + + /* Reuse max8997_list_voltage to get current_limit. */ + return max8997_list_voltage(rdev, sel); +} static struct regulator_ops max8997_charger_ops = { .is_enabled = max8997_reg_is_enabled, .enable = max8997_reg_enable, .disable = max8997_reg_disable, - .get_current_limit = max8997_get_voltage, - .set_current_limit = max8997_set_voltage_ldobuck_wrap, + .get_current_limit = max8997_get_current_limit, + .set_current_limit = max8997_set_current_limit, }; static struct regulator_ops max8997_charger_fixedstate_ops = { - .is_enabled = max8997_reg_is_enabled, - .get_current_limit = max8997_get_voltage, - .set_current_limit = max8997_set_voltage_ldobuck_wrap, + .get_current_limit = max8997_get_current_limit, + .set_current_limit = max8997_set_current_limit, }; -#define regulator_desc_ldo(num) { \ - .name = "LDO"#num, \ - .id = MAX8997_LDO##num, \ - .ops = &max8997_ldo_ops, \ +#define MAX8997_VOLTAGE_REGULATOR(_name, _ops) {\ + .name = #_name, \ + .id = MAX8997_##_name, \ + .ops = &_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ } -#define regulator_desc_buck(num) { \ - .name = "BUCK"#num, \ - .id = MAX8997_BUCK##num, \ - .ops = &max8997_buck_ops, \ - .type = REGULATOR_VOLTAGE, \ + +#define MAX8997_CURRENT_REGULATOR(_name, _ops) {\ + .name = #_name, \ + .id = MAX8997_##_name, \ + .ops = &_ops, \ + .type = REGULATOR_CURRENT, \ .owner = THIS_MODULE, \ } static struct regulator_desc regulators[] = { - regulator_desc_ldo(1), - regulator_desc_ldo(2), - regulator_desc_ldo(3), - regulator_desc_ldo(4), - regulator_desc_ldo(5), - regulator_desc_ldo(6), - regulator_desc_ldo(7), - regulator_desc_ldo(8), - regulator_desc_ldo(9), - regulator_desc_ldo(10), - regulator_desc_ldo(11), - regulator_desc_ldo(12), - regulator_desc_ldo(13), - regulator_desc_ldo(14), - regulator_desc_ldo(15), - regulator_desc_ldo(16), - regulator_desc_ldo(17), - regulator_desc_ldo(18), - regulator_desc_ldo(21), - regulator_desc_buck(1), - regulator_desc_buck(2), - regulator_desc_buck(3), - regulator_desc_buck(4), - regulator_desc_buck(5), - { - .name = "BUCK6", - .id = MAX8997_BUCK6, - .ops = &max8997_fixedvolt_ops, - .type = REGULATOR_VOLTAGE, - .owner = THIS_MODULE, - }, - regulator_desc_buck(7), - { - .name = "EN32KHz_AP", - .id = MAX8997_EN32KHZ_AP, - .ops = &max8997_fixedvolt_ops, - .type = REGULATOR_VOLTAGE, - .owner = THIS_MODULE, - }, { - .name = "EN32KHz_CP", - .id = MAX8997_EN32KHZ_CP, - .ops = &max8997_fixedvolt_ops, - .type = REGULATOR_VOLTAGE, - .owner = THIS_MODULE, - }, { - .name = "ENVICHG", - .id = MAX8997_ENVICHG, - .ops = &max8997_fixedvolt_ops, - .type = REGULATOR_VOLTAGE, - .owner = THIS_MODULE, - }, { - .name = "ESAFEOUT1", - .id = MAX8997_ESAFEOUT1, - .ops = &max8997_safeout_ops, - .type = REGULATOR_VOLTAGE, - .owner = THIS_MODULE, - }, { - .name = "ESAFEOUT2", - .id = MAX8997_ESAFEOUT2, - .ops = &max8997_safeout_ops, - .type = REGULATOR_VOLTAGE, - .owner = THIS_MODULE, - }, { - .name = "CHARGER_CV", - .id = MAX8997_CHARGER_CV, - .ops = &max8997_fixedstate_ops, - .type = REGULATOR_VOLTAGE, - .owner = THIS_MODULE, - }, { - .name = "CHARGER", - .id = MAX8997_CHARGER, - .ops = &max8997_charger_ops, - .type = REGULATOR_CURRENT, - .owner = THIS_MODULE, - }, { - .name = "CHARGER_TOPOFF", - .id = MAX8997_CHARGER_TOPOFF, - .ops = &max8997_charger_fixedstate_ops, - .type = REGULATOR_CURRENT, - .owner = THIS_MODULE, - }, + MAX8997_VOLTAGE_REGULATOR(LDO1, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO2, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO3, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO4, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO5, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO6, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO7, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO8, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO9, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO10, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO11, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO12, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO13, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO14, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO15, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO16, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO17, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO18, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(LDO21, max8997_ldo_ops), + MAX8997_VOLTAGE_REGULATOR(BUCK1, max8997_buck_ops), + MAX8997_VOLTAGE_REGULATOR(BUCK2, max8997_buck_ops), + MAX8997_VOLTAGE_REGULATOR(BUCK3, max8997_buck_ops), + MAX8997_VOLTAGE_REGULATOR(BUCK4, max8997_buck_ops), + MAX8997_VOLTAGE_REGULATOR(BUCK5, max8997_buck_ops), + MAX8997_VOLTAGE_REGULATOR(BUCK6, max8997_fixedvolt_ops), + MAX8997_VOLTAGE_REGULATOR(BUCK7, max8997_buck_ops), + MAX8997_VOLTAGE_REGULATOR(EN32KHZ_AP, max8997_fixedvolt_ops), + MAX8997_VOLTAGE_REGULATOR(EN32KHZ_CP, max8997_fixedvolt_ops), + MAX8997_VOLTAGE_REGULATOR(ENVICHG, max8997_fixedvolt_ops), + MAX8997_VOLTAGE_REGULATOR(ESAFEOUT1, max8997_safeout_ops), + MAX8997_VOLTAGE_REGULATOR(ESAFEOUT2, max8997_safeout_ops), + MAX8997_VOLTAGE_REGULATOR(CHARGER_CV, max8997_fixedstate_ops), + MAX8997_CURRENT_REGULATOR(CHARGER, max8997_charger_ops), + MAX8997_CURRENT_REGULATOR(CHARGER_TOPOFF, + max8997_charger_fixedstate_ops), }; static __devinit int max8997_pmic_probe(struct platform_device *pdev) { struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev); + struct regulator_config config = { }; struct regulator_dev **rdev; struct max8997_data *max8997; struct i2c_client *i2c; @@ -968,16 +949,15 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev) return -ENODEV; } - max8997 = kzalloc(sizeof(struct max8997_data), GFP_KERNEL); + max8997 = devm_kzalloc(&pdev->dev, sizeof(struct max8997_data), + GFP_KERNEL); if (!max8997) return -ENOMEM; size = sizeof(struct regulator_dev *) * pdata->num_regulators; - max8997->rdev = kzalloc(size, GFP_KERNEL); - if (!max8997->rdev) { - kfree(max8997); + max8997->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); + if (!max8997->rdev) return -ENOMEM; - } rdev = max8997->rdev; max8997->dev = &pdev->dev; @@ -1001,7 +981,7 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev) pdata->buck1_voltage[i] / 1000 + buck1245_voltage_map_desc.step); if (ret < 0) - goto err_alloc; + goto err_out; max8997->buck2_vol[i] = ret = max8997_get_voltage_proper_val( @@ -1010,7 +990,7 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev) pdata->buck2_voltage[i] / 1000 + buck1245_voltage_map_desc.step); if (ret < 0) - goto err_alloc; + goto err_out; max8997->buck5_vol[i] = ret = max8997_get_voltage_proper_val( @@ -1019,7 +999,7 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev) pdata->buck5_voltage[i] / 1000 + buck1245_voltage_map_desc.step); if (ret < 0) - goto err_alloc; + goto err_out; if (max_buck1 < max8997->buck1_vol[i]) max_buck1 = max8997->buck1_vol[i]; @@ -1052,7 +1032,7 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev) !gpio_is_valid(pdata->buck125_gpios[2])) { dev_err(&pdev->dev, "GPIO NOT VALID\n"); ret = -EINVAL; - goto err_alloc; + goto err_out; } ret = gpio_request(pdata->buck125_gpios[0], @@ -1061,7 +1041,7 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "Duplicated gpio request" " on SET1\n"); else if (ret) - goto err_alloc; + goto err_out; else gpio1set = true; @@ -1073,7 +1053,7 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev) else if (ret) { if (gpio1set) gpio_free(pdata->buck125_gpios[0]); - goto err_alloc; + goto err_out; } else gpio2set = true; @@ -1087,7 +1067,7 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev) gpio_free(pdata->buck125_gpios[0]); if (gpio2set) gpio_free(pdata->buck125_gpios[1]); - goto err_alloc; + goto err_out; } gpio_direction_output(pdata->buck125_gpios[0], @@ -1140,8 +1120,11 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev) else if (id == MAX8997_CHARGER_CV) regulators[id].n_voltages = 16; - rdev[i] = regulator_register(®ulators[id], max8997->dev, - pdata->regulators[i].initdata, max8997, NULL); + config.dev = max8997->dev; + config.init_data = pdata->regulators[i].initdata; + config.driver_data = max8997; + + rdev[i] = regulator_register(®ulators[id], &config); if (IS_ERR(rdev[i])) { ret = PTR_ERR(rdev[i]); dev_err(max8997->dev, "regulator init failed for %d\n", @@ -1153,13 +1136,9 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev) return 0; err: - for (i = 0; i < max8997->num_regulators; i++) - if (rdev[i]) - regulator_unregister(rdev[i]); -err_alloc: - kfree(max8997->rdev); - kfree(max8997); - + while (--i >= 0) + regulator_unregister(rdev[i]); +err_out: return ret; } @@ -1170,12 +1149,7 @@ static int __devexit max8997_pmic_remove(struct platform_device *pdev) int i; for (i = 0; i < max8997->num_regulators; i++) - if (rdev[i]) - regulator_unregister(rdev[i]); - - kfree(max8997->rdev); - kfree(max8997); - + regulator_unregister(rdev[i]); return 0; } diff --git a/trunk/drivers/regulator/max8998.c b/trunk/drivers/regulator/max8998.c index 5890265eeacc..18bb58b9b96e 100644 --- a/trunk/drivers/regulator/max8998.c +++ b/trunk/drivers/regulator/max8998.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -277,7 +276,7 @@ static int max8998_get_voltage_register(struct regulator_dev *rdev, return 0; } -static int max8998_get_voltage(struct regulator_dev *rdev) +static int max8998_get_voltage_sel(struct regulator_dev *rdev) { struct max8998_data *max8998 = rdev_get_drvdata(rdev); struct i2c_client *i2c = max8998->iodev->i2c; @@ -295,7 +294,7 @@ static int max8998_get_voltage(struct regulator_dev *rdev) val >>= shift; val &= mask; - return max8998_list_voltage(rdev, val); + return val; } static int max8998_set_voltage_ldo(struct regulator_dev *rdev, @@ -306,8 +305,7 @@ static int max8998_set_voltage_ldo(struct regulator_dev *rdev, int min_vol = min_uV / 1000, max_vol = max_uV / 1000; const struct voltage_map_desc *desc; int ldo = rdev_get_id(rdev); - int reg, shift = 0, mask, ret; - int i = 0; + int reg, shift = 0, mask, ret, i; if (ldo >= ARRAY_SIZE(ldo_voltage_map)) return -EINVAL; @@ -319,9 +317,10 @@ static int max8998_set_voltage_ldo(struct regulator_dev *rdev, if (max_vol < desc->min || min_vol > desc->max) return -EINVAL; - while (desc->min + desc->step*i < min_vol && - desc->min + desc->step*i < desc->max) - i++; + if (min_vol < desc->min) + min_vol = desc->min; + + i = DIV_ROUND_UP(min_vol - desc->min, desc->step); if (desc->min + desc->step*i > max_vol) return -EINVAL; @@ -359,8 +358,7 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev, const struct voltage_map_desc *desc; int buck = rdev_get_id(rdev); int reg, shift = 0, mask, ret; - int difference = 0, i = 0, j = 0, previous_vol = 0; - u8 val = 0; + int i, j, previous_sel; static u8 buck1_last_val; if (buck >= ARRAY_SIZE(ldo_voltage_map)) @@ -374,9 +372,10 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev, if (max_vol < desc->min || min_vol > desc->max) return -EINVAL; - while (desc->min + desc->step*i < min_vol && - desc->min + desc->step*i < desc->max) - i++; + if (min_vol < desc->min) + min_vol = desc->min; + + i = DIV_ROUND_UP(min_vol - desc->min, desc->step); if (desc->min + desc->step*i > max_vol) return -EINVAL; @@ -387,13 +386,14 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev, if (ret) return ret; - previous_vol = max8998_get_voltage(rdev); + previous_sel = max8998_get_voltage_sel(rdev); /* Check if voltage needs to be changed */ /* if previous_voltage equal new voltage, return */ - if (previous_vol == max8998_list_voltage(rdev, i)) { + if (previous_sel == i) { dev_dbg(max8998->dev, "No voltage change, old:%d, new:%d\n", - previous_vol, max8998_list_voltage(rdev, i)); + max8998_list_voltage(rdev, previous_sel), + max8998_list_voltage(rdev, i)); return ret; } @@ -482,19 +482,40 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev, break; } + return ret; +} + +static int max8998_set_voltage_buck_time_sel(struct regulator_dev *rdev, + unsigned int old_selector, + unsigned int new_selector) +{ + struct max8998_data *max8998 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8998->iodev->i2c; + const struct voltage_map_desc *desc; + int buck = rdev_get_id(rdev); + u8 val = 0; + int difference, ret; + + if (buck < MAX8998_BUCK1 || buck > MAX8998_BUCK4) + return -EINVAL; + + desc = ldo_voltage_map[buck]; + /* Voltage stabilization */ - max8998_read_reg(i2c, MAX8998_REG_ONOFF4, &val); + ret = max8998_read_reg(i2c, MAX8998_REG_ONOFF4, &val); + if (ret) + return ret; /* lp3974 hasn't got ENRAMP bit - ramp is assumed as true */ /* MAX8998 has ENRAMP bit implemented, so test it*/ if (max8998->iodev->type == TYPE_MAX8998 && !(val & MAX8998_ENRAMP)) - return ret; + return 0; - difference = desc->min + desc->step*i - previous_vol/1000; + difference = (new_selector - old_selector) * desc->step; if (difference > 0) - udelay(difference / ((val & 0x0f) + 1)); + return difference / ((val & 0x0f) + 1); - return ret; + return 0; } static struct regulator_ops max8998_ldo_ops = { @@ -502,7 +523,7 @@ static struct regulator_ops max8998_ldo_ops = { .is_enabled = max8998_ldo_is_enabled, .enable = max8998_ldo_enable, .disable = max8998_ldo_disable, - .get_voltage = max8998_get_voltage, + .get_voltage_sel = max8998_get_voltage_sel, .set_voltage = max8998_set_voltage_ldo, .set_suspend_enable = max8998_ldo_enable, .set_suspend_disable = max8998_ldo_disable, @@ -513,8 +534,9 @@ static struct regulator_ops max8998_buck_ops = { .is_enabled = max8998_ldo_is_enabled, .enable = max8998_ldo_enable, .disable = max8998_ldo_disable, - .get_voltage = max8998_get_voltage, + .get_voltage_sel = max8998_get_voltage_sel, .set_voltage = max8998_set_voltage_buck, + .set_voltage_time_sel = max8998_set_voltage_buck_time_sel, .set_suspend_enable = max8998_ldo_enable, .set_suspend_disable = max8998_ldo_disable, }; @@ -685,6 +707,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) { struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev); + struct regulator_config config = { }; struct regulator_dev **rdev; struct max8998_data *max8998; struct i2c_client *i2c; @@ -695,16 +718,15 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) return -ENODEV; } - max8998 = kzalloc(sizeof(struct max8998_data), GFP_KERNEL); + max8998 = devm_kzalloc(&pdev->dev, sizeof(struct max8998_data), + GFP_KERNEL); if (!max8998) return -ENOMEM; size = sizeof(struct regulator_dev *) * pdata->num_regulators; - max8998->rdev = kzalloc(size, GFP_KERNEL); - if (!max8998->rdev) { - kfree(max8998); + max8998->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); + if (!max8998->rdev) return -ENOMEM; - } rdev = max8998->rdev; max8998->dev = &pdev->dev; @@ -728,14 +750,14 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) printk(KERN_ERR "MAX8998 SET1 GPIO defined as 0 !\n"); WARN_ON(!pdata->buck1_set1); ret = -EIO; - goto err_free_mem; + goto err_out; } /* Check if SET2 is not equal to 0 */ if (!pdata->buck1_set2) { printk(KERN_ERR "MAX8998 SET2 GPIO defined as 0 !\n"); WARN_ON(!pdata->buck1_set2); ret = -EIO; - goto err_free_mem; + goto err_out; } gpio_request(pdata->buck1_set1, "MAX8998 BUCK1_SET1"); @@ -755,7 +777,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) max8998->buck1_vol[0] = i; ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE1, i); if (ret) - goto err_free_mem; + goto err_out; /* Set predefined value for BUCK1 register 2 */ i = 0; @@ -767,7 +789,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) max8998->buck1_vol[1] = i; ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE2, i); if (ret) - goto err_free_mem; + goto err_out; /* Set predefined value for BUCK1 register 3 */ i = 0; @@ -779,7 +801,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) max8998->buck1_vol[2] = i; ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE3, i); if (ret) - goto err_free_mem; + goto err_out; /* Set predefined value for BUCK1 register 4 */ i = 0; @@ -791,7 +813,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) max8998->buck1_vol[3] = i; ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE4, i); if (ret) - goto err_free_mem; + goto err_out; } @@ -801,7 +823,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) printk(KERN_ERR "MAX8998 SET3 GPIO defined as 0 !\n"); WARN_ON(!pdata->buck2_set3); ret = -EIO; - goto err_free_mem; + goto err_out; } gpio_request(pdata->buck2_set3, "MAX8998 BUCK2_SET3"); gpio_direction_output(pdata->buck2_set3, @@ -816,7 +838,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) max8998->buck2_vol[0] = i; ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE1, i); if (ret) - goto err_free_mem; + goto err_out; /* BUCK2 register 2 */ i = 0; @@ -827,7 +849,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) max8998->buck2_vol[1] = i; ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE2, i); if (ret) - goto err_free_mem; + goto err_out; } for (i = 0; i < pdata->num_regulators; i++) { @@ -840,8 +862,12 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) int count = (desc->max - desc->min) / desc->step + 1; regulators[index].n_voltages = count; } - rdev[i] = regulator_register(®ulators[index], max8998->dev, - pdata->regulators[i].initdata, max8998, NULL); + + config.dev = max8998->dev; + config.init_data = pdata->regulators[i].initdata; + config.driver_data = max8998; + + rdev[i] = regulator_register(®ulators[index], &config); if (IS_ERR(rdev[i])) { ret = PTR_ERR(rdev[i]); dev_err(max8998->dev, "regulator init failed\n"); @@ -853,14 +879,9 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) return 0; err: - for (i = 0; i < max8998->num_regulators; i++) - if (rdev[i]) - regulator_unregister(rdev[i]); - -err_free_mem: - kfree(max8998->rdev); - kfree(max8998); - + while (--i >= 0) + regulator_unregister(rdev[i]); +err_out: return ret; } @@ -871,12 +892,7 @@ static int __devexit max8998_pmic_remove(struct platform_device *pdev) int i; for (i = 0; i < max8998->num_regulators; i++) - if (rdev[i]) - regulator_unregister(rdev[i]); - - kfree(max8998->rdev); - kfree(max8998); - + regulator_unregister(rdev[i]); return 0; } diff --git a/trunk/drivers/regulator/mc13783-regulator.c b/trunk/drivers/regulator/mc13783-regulator.c index 6c0face87ffe..7dcdfa283e93 100644 --- a/trunk/drivers/regulator/mc13783-regulator.c +++ b/trunk/drivers/regulator/mc13783-regulator.c @@ -340,6 +340,7 @@ static int __devinit mc13783_regulator_probe(struct platform_device *pdev) struct mc13xxx_regulator_platform_data *pdata = dev_get_platdata(&pdev->dev); struct mc13xxx_regulator_init_data *init_data; + struct regulator_config config = { }; int i, ret; dev_dbg(&pdev->dev, "%s id %d\n", __func__, pdev->id); @@ -357,11 +358,16 @@ static int __devinit mc13783_regulator_probe(struct platform_device *pdev) priv->mc13xxx = mc13783; for (i = 0; i < pdata->num_regulators; i++) { + struct regulator_desc *desc; + init_data = &pdata->regulators[i]; - priv->regulators[i] = regulator_register( - &mc13783_regulators[init_data->id].desc, - &pdev->dev, init_data->init_data, priv, NULL); + desc = &mc13783_regulators[init_data->id].desc; + + config.dev = &pdev->dev; + config.init_data = init_data->init_data; + config.driver_data = priv; + priv->regulators[i] = regulator_register(desc, &config); if (IS_ERR(priv->regulators[i])) { dev_err(&pdev->dev, "failed to register regulator %s\n", mc13783_regulators[i].desc.name); diff --git a/trunk/drivers/regulator/mc13892-regulator.c b/trunk/drivers/regulator/mc13892-regulator.c index 845aa2263b8a..970a233dbe46 100644 --- a/trunk/drivers/regulator/mc13892-regulator.c +++ b/trunk/drivers/regulator/mc13892-regulator.c @@ -428,24 +428,15 @@ static int mc13892_sw_regulator_get_voltage(struct regulator_dev *rdev) return val; } -static int mc13892_sw_regulator_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned *selector) +static int mc13892_sw_regulator_set_voltage_sel(struct regulator_dev *rdev, + unsigned selector) { struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); int hi, value, mask, id = rdev_get_id(rdev); u32 valread; int ret; - dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n", - __func__, id, min_uV, max_uV); - - /* Find the best index */ - value = mc13xxx_get_best_voltage_index(rdev, min_uV, max_uV); - dev_dbg(rdev_get_dev(rdev), "%s best value: %d\n", __func__, value); - if (value < 0) - return value; - - value = mc13892_regulators[id].voltages[value]; + value = mc13892_regulators[id].voltages[selector]; mc13xxx_lock(priv->mc13xxx); ret = mc13xxx_reg_read(priv->mc13xxx, @@ -480,7 +471,7 @@ static int mc13892_sw_regulator_set_voltage(struct regulator_dev *rdev, static struct regulator_ops mc13892_sw_regulator_ops = { .is_enabled = mc13xxx_sw_regulator_is_enabled, .list_voltage = mc13xxx_regulator_list_voltage, - .set_voltage = mc13892_sw_regulator_set_voltage, + .set_voltage_sel = mc13892_sw_regulator_set_voltage_sel, .get_voltage = mc13892_sw_regulator_get_voltage, }; @@ -528,6 +519,7 @@ static int __devinit mc13892_regulator_probe(struct platform_device *pdev) struct mc13xxx_regulator_platform_data *pdata = dev_get_platdata(&pdev->dev); struct mc13xxx_regulator_init_data *mc13xxx_data; + struct regulator_config config = { }; int i, ret; int num_regulators = 0; u32 val; @@ -597,9 +589,12 @@ static int __devinit mc13892_regulator_probe(struct platform_device *pdev) } desc = &mc13892_regulators[id].desc; - priv->regulators[i] = regulator_register( - desc, &pdev->dev, init_data, priv, node); + config.dev = &pdev->dev; + config.init_data = init_data; + config.driver_data = priv; + config.of_node = node; + priv->regulators[i] = regulator_register(desc, &config); if (IS_ERR(priv->regulators[i])) { dev_err(&pdev->dev, "failed to register regulator %s\n", mc13892_regulators[i].desc.name); diff --git a/trunk/drivers/regulator/mc13xxx-regulator-core.c b/trunk/drivers/regulator/mc13xxx-regulator-core.c index 62dcd0a432bb..4fa9704739bc 100644 --- a/trunk/drivers/regulator/mc13xxx-regulator-core.c +++ b/trunk/drivers/regulator/mc13xxx-regulator-core.c @@ -94,62 +94,18 @@ int mc13xxx_regulator_list_voltage(struct regulator_dev *rdev, } EXPORT_SYMBOL_GPL(mc13xxx_regulator_list_voltage); -int mc13xxx_get_best_voltage_index(struct regulator_dev *rdev, - int min_uV, int max_uV) +static int mc13xxx_regulator_set_voltage_sel(struct regulator_dev *rdev, + unsigned selector) { struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; - int reg_id = rdev_get_id(rdev); - int i; - int bestmatch; - int bestindex; - - /* - * Locate the minimum voltage fitting the criteria on - * this regulator. The switchable voltages are not - * in strict falling order so we need to check them - * all for the best match. - */ - bestmatch = INT_MAX; - bestindex = -1; - for (i = 0; i < mc13xxx_regulators[reg_id].desc.n_voltages; i++) { - if (mc13xxx_regulators[reg_id].voltages[i] >= min_uV && - mc13xxx_regulators[reg_id].voltages[i] < bestmatch) { - bestmatch = mc13xxx_regulators[reg_id].voltages[i]; - bestindex = i; - } - } - - if (bestindex < 0 || bestmatch > max_uV) { - dev_warn(&rdev->dev, "no possible value for %d<=x<=%d uV\n", - min_uV, max_uV); - return -EINVAL; - } - return bestindex; -} -EXPORT_SYMBOL_GPL(mc13xxx_get_best_voltage_index); - -static int mc13xxx_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, - int max_uV, unsigned *selector) -{ - struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); - struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; - int value, id = rdev_get_id(rdev); + int id = rdev_get_id(rdev); int ret; - dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n", - __func__, id, min_uV, max_uV); - - /* Find the best index */ - value = mc13xxx_get_best_voltage_index(rdev, min_uV, max_uV); - dev_dbg(rdev_get_dev(rdev), "%s best value: %d\n", __func__, value); - if (value < 0) - return value; - mc13xxx_lock(priv->mc13xxx); ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13xxx_regulators[id].vsel_reg, mc13xxx_regulators[id].vsel_mask, - value << mc13xxx_regulators[id].vsel_shift); + selector << mc13xxx_regulators[id].vsel_shift); mc13xxx_unlock(priv->mc13xxx); return ret; @@ -187,7 +143,7 @@ struct regulator_ops mc13xxx_regulator_ops = { .disable = mc13xxx_regulator_disable, .is_enabled = mc13xxx_regulator_is_enabled, .list_voltage = mc13xxx_regulator_list_voltage, - .set_voltage = mc13xxx_regulator_set_voltage, + .set_voltage_sel = mc13xxx_regulator_set_voltage_sel, .get_voltage = mc13xxx_regulator_get_voltage, }; EXPORT_SYMBOL_GPL(mc13xxx_regulator_ops); diff --git a/trunk/drivers/regulator/mc13xxx.h b/trunk/drivers/regulator/mc13xxx.h index b3961c658b05..044aba4d28ec 100644 --- a/trunk/drivers/regulator/mc13xxx.h +++ b/trunk/drivers/regulator/mc13xxx.h @@ -35,8 +35,6 @@ struct mc13xxx_regulator_priv { extern int mc13xxx_sw_regulator(struct regulator_dev *rdev); extern int mc13xxx_sw_regulator_is_enabled(struct regulator_dev *rdev); -extern int mc13xxx_get_best_voltage_index(struct regulator_dev *rdev, - int min_uV, int max_uV); extern int mc13xxx_regulator_list_voltage(struct regulator_dev *rdev, unsigned selector); extern int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, diff --git a/trunk/drivers/regulator/of_regulator.c b/trunk/drivers/regulator/of_regulator.c index 679734d26a16..56593b75168a 100644 --- a/trunk/drivers/regulator/of_regulator.c +++ b/trunk/drivers/regulator/of_regulator.c @@ -14,6 +14,7 @@ #include #include #include +#include static void of_get_regulation_constraints(struct device_node *np, struct regulator_init_data **init_data) @@ -85,3 +86,49 @@ struct regulator_init_data *of_get_regulator_init_data(struct device *dev, return init_data; } EXPORT_SYMBOL_GPL(of_get_regulator_init_data); + +/** + * of_regulator_match - extract regulator init data + * @dev: device requesting the data + * @node: parent device node of the regulators + * @matches: match table for the regulators + * @num_matches: number of entries in match table + * + * This function uses a match table specified by the regulator driver and + * looks up the corresponding init data in the device tree. Note that the + * match table is modified in place. + * + * Returns the number of matches found or a negative error code on failure. + */ +int of_regulator_match(struct device *dev, struct device_node *node, + struct of_regulator_match *matches, + unsigned int num_matches) +{ + unsigned int count = 0; + unsigned int i; + + if (!dev || !node) + return -EINVAL; + + for (i = 0; i < num_matches; i++) { + struct of_regulator_match *match = &matches[i]; + struct device_node *child; + + child = of_find_node_by_name(node, match->name); + if (!child) + continue; + + match->init_data = of_get_regulator_init_data(dev, child); + if (!match->init_data) { + dev_err(dev, "failed to parse DT for regulator %s\n", + child->name); + return -EINVAL; + } + + match->of_node = child; + count++; + } + + return count; +} +EXPORT_SYMBOL_GPL(of_regulator_match); diff --git a/trunk/drivers/regulator/palmas-regulator.c b/trunk/drivers/regulator/palmas-regulator.c new file mode 100644 index 000000000000..c4435f608df7 --- /dev/null +++ b/trunk/drivers/regulator/palmas-regulator.c @@ -0,0 +1,822 @@ +/* + * Driver for Regulator part of Palmas PMIC Chips + * + * Copyright 2011-2012 Texas Instruments Inc. + * + * Author: Graeme Gregory + * + * 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 + +struct regs_info { + char *name; + u8 vsel_addr; + u8 ctrl_addr; + u8 tstep_addr; +}; + +static const struct regs_info palmas_regs_info[] = { + { + .name = "SMPS12", + .vsel_addr = PALMAS_SMPS12_VOLTAGE, + .ctrl_addr = PALMAS_SMPS12_CTRL, + .tstep_addr = PALMAS_SMPS12_TSTEP, + }, + { + .name = "SMPS123", + .vsel_addr = PALMAS_SMPS12_VOLTAGE, + .ctrl_addr = PALMAS_SMPS12_CTRL, + .tstep_addr = PALMAS_SMPS12_TSTEP, + }, + { + .name = "SMPS3", + .vsel_addr = PALMAS_SMPS3_VOLTAGE, + .ctrl_addr = PALMAS_SMPS3_CTRL, + }, + { + .name = "SMPS45", + .vsel_addr = PALMAS_SMPS45_VOLTAGE, + .ctrl_addr = PALMAS_SMPS45_CTRL, + .tstep_addr = PALMAS_SMPS45_TSTEP, + }, + { + .name = "SMPS457", + .vsel_addr = PALMAS_SMPS45_VOLTAGE, + .ctrl_addr = PALMAS_SMPS45_CTRL, + .tstep_addr = PALMAS_SMPS45_TSTEP, + }, + { + .name = "SMPS6", + .vsel_addr = PALMAS_SMPS6_VOLTAGE, + .ctrl_addr = PALMAS_SMPS6_CTRL, + .tstep_addr = PALMAS_SMPS6_TSTEP, + }, + { + .name = "SMPS7", + .vsel_addr = PALMAS_SMPS7_VOLTAGE, + .ctrl_addr = PALMAS_SMPS7_CTRL, + }, + { + .name = "SMPS8", + .vsel_addr = PALMAS_SMPS8_VOLTAGE, + .ctrl_addr = PALMAS_SMPS8_CTRL, + .tstep_addr = PALMAS_SMPS8_TSTEP, + }, + { + .name = "SMPS9", + .vsel_addr = PALMAS_SMPS9_VOLTAGE, + .ctrl_addr = PALMAS_SMPS9_CTRL, + }, + { + .name = "SMPS10", + }, + { + .name = "LDO1", + .vsel_addr = PALMAS_LDO1_VOLTAGE, + .ctrl_addr = PALMAS_LDO1_CTRL, + }, + { + .name = "LDO2", + .vsel_addr = PALMAS_LDO2_VOLTAGE, + .ctrl_addr = PALMAS_LDO2_CTRL, + }, + { + .name = "LDO3", + .vsel_addr = PALMAS_LDO3_VOLTAGE, + .ctrl_addr = PALMAS_LDO3_CTRL, + }, + { + .name = "LDO4", + .vsel_addr = PALMAS_LDO4_VOLTAGE, + .ctrl_addr = PALMAS_LDO4_CTRL, + }, + { + .name = "LDO5", + .vsel_addr = PALMAS_LDO5_VOLTAGE, + .ctrl_addr = PALMAS_LDO5_CTRL, + }, + { + .name = "LDO6", + .vsel_addr = PALMAS_LDO6_VOLTAGE, + .ctrl_addr = PALMAS_LDO6_CTRL, + }, + { + .name = "LDO7", + .vsel_addr = PALMAS_LDO7_VOLTAGE, + .ctrl_addr = PALMAS_LDO7_CTRL, + }, + { + .name = "LDO8", + .vsel_addr = PALMAS_LDO8_VOLTAGE, + .ctrl_addr = PALMAS_LDO8_CTRL, + }, + { + .name = "LDO9", + .vsel_addr = PALMAS_LDO9_VOLTAGE, + .ctrl_addr = PALMAS_LDO9_CTRL, + }, + { + .name = "LDOLN", + .vsel_addr = PALMAS_LDOLN_VOLTAGE, + .ctrl_addr = PALMAS_LDOLN_CTRL, + }, + { + .name = "LDOUSB", + .vsel_addr = PALMAS_LDOUSB_VOLTAGE, + .ctrl_addr = PALMAS_LDOUSB_CTRL, + }, +}; + +#define SMPS_CTRL_MODE_OFF 0x00 +#define SMPS_CTRL_MODE_ON 0x01 +#define SMPS_CTRL_MODE_ECO 0x02 +#define SMPS_CTRL_MODE_PWM 0x03 + +/* These values are derived from the data sheet. And are the number of steps + * where there is a voltage change, the ranges at beginning and end of register + * max/min values where there are no change are ommitted. + * + * So they are basically (maxV-minV)/stepV + */ +#define PALMAS_SMPS_NUM_VOLTAGES 116 +#define PALMAS_SMPS10_NUM_VOLTAGES 2 +#define PALMAS_LDO_NUM_VOLTAGES 50 + +#define SMPS10_VSEL (1<<3) +#define SMPS10_BOOST_EN (1<<2) +#define SMPS10_BYPASS_EN (1<<1) +#define SMPS10_SWITCH_EN (1<<0) + +#define REGULATOR_SLAVE 0 + +static int palmas_smps_read(struct palmas *palmas, unsigned int reg, + unsigned int *dest) +{ + unsigned int addr; + + addr = PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, reg); + + return regmap_read(palmas->regmap[REGULATOR_SLAVE], addr, dest); +} + +static int palmas_smps_write(struct palmas *palmas, unsigned int reg, + unsigned int value) +{ + unsigned int addr; + + addr = PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, reg); + + return regmap_write(palmas->regmap[REGULATOR_SLAVE], addr, value); +} + +static int palmas_ldo_read(struct palmas *palmas, unsigned int reg, + unsigned int *dest) +{ + unsigned int addr; + + addr = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE, reg); + + return regmap_read(palmas->regmap[REGULATOR_SLAVE], addr, dest); +} + +static int palmas_ldo_write(struct palmas *palmas, unsigned int reg, + unsigned int value) +{ + unsigned int addr; + + addr = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE, reg); + + return regmap_write(palmas->regmap[REGULATOR_SLAVE], addr, value); +} + +static int palmas_is_enabled_smps(struct regulator_dev *dev) +{ + struct palmas_pmic *pmic = rdev_get_drvdata(dev); + int id = rdev_get_id(dev); + unsigned int reg; + + palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, ®); + + reg &= PALMAS_SMPS12_CTRL_STATUS_MASK; + reg >>= PALMAS_SMPS12_CTRL_STATUS_SHIFT; + + return !!(reg); +} + +static int palmas_enable_smps(struct regulator_dev *dev) +{ + struct palmas_pmic *pmic = rdev_get_drvdata(dev); + int id = rdev_get_id(dev); + unsigned int reg; + + palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, ®); + + reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK; + reg |= SMPS_CTRL_MODE_ON; + + palmas_smps_write(pmic->palmas, palmas_regs_info[id].ctrl_addr, reg); + + return 0; +} + +static int palmas_disable_smps(struct regulator_dev *dev) +{ + struct palmas_pmic *pmic = rdev_get_drvdata(dev); + int id = rdev_get_id(dev); + unsigned int reg; + + palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, ®); + + reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK; + + palmas_smps_write(pmic->palmas, palmas_regs_info[id].ctrl_addr, reg); + + return 0; +} + + +static int palmas_set_mode_smps(struct regulator_dev *dev, unsigned int mode) +{ + struct palmas_pmic *pmic = rdev_get_drvdata(dev); + int id = rdev_get_id(dev); + unsigned int reg; + + palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, ®); + reg &= ~PALMAS_SMPS12_CTRL_STATUS_MASK; + reg >>= PALMAS_SMPS12_CTRL_STATUS_SHIFT; + + switch (mode) { + case REGULATOR_MODE_NORMAL: + reg |= SMPS_CTRL_MODE_ON; + break; + case REGULATOR_MODE_IDLE: + reg |= SMPS_CTRL_MODE_ECO; + break; + case REGULATOR_MODE_FAST: + reg |= SMPS_CTRL_MODE_PWM; + break; + default: + return -EINVAL; + } + palmas_smps_write(pmic->palmas, palmas_regs_info[id].ctrl_addr, reg); + + return 0; +} + +static unsigned int palmas_get_mode_smps(struct regulator_dev *dev) +{ + struct palmas_pmic *pmic = rdev_get_drvdata(dev); + int id = rdev_get_id(dev); + unsigned int reg; + + palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, ®); + reg &= PALMAS_SMPS12_CTRL_STATUS_MASK; + reg >>= PALMAS_SMPS12_CTRL_STATUS_SHIFT; + + switch (reg) { + case SMPS_CTRL_MODE_ON: + return REGULATOR_MODE_NORMAL; + case SMPS_CTRL_MODE_ECO: + return REGULATOR_MODE_IDLE; + case SMPS_CTRL_MODE_PWM: + return REGULATOR_MODE_FAST; + } + + return 0; +} + +static int palmas_list_voltage_smps(struct regulator_dev *dev, + unsigned selector) +{ + struct palmas_pmic *pmic = rdev_get_drvdata(dev); + int id = rdev_get_id(dev); + int mult = 1; + + if (!selector) + return 0; + + /* Read the multiplier set in VSEL register to return + * the correct voltage. + */ + if (pmic->range[id]) + mult = 2; + + /* Voltage is (0.49V + (selector * 0.01V)) * RANGE + * as defined in data sheet. RANGE is either x1 or x2 + */ + return (490000 + (selector * 10000)) * mult; +} + +static int palmas_get_voltage_smps_sel(struct regulator_dev *dev) +{ + struct palmas_pmic *pmic = rdev_get_drvdata(dev); + int id = rdev_get_id(dev); + int selector; + unsigned int reg; + unsigned int addr; + + addr = palmas_regs_info[id].vsel_addr; + + palmas_smps_read(pmic->palmas, addr, ®); + + selector = reg & PALMAS_SMPS12_VOLTAGE_VSEL_MASK; + + /* Adjust selector to match list_voltage ranges */ + if ((selector > 0) && (selector < 6)) + selector = 6; + if (!selector) + selector = 5; + if (selector > 121) + selector = 121; + selector -= 5; + + return selector; +} + +static int palmas_set_voltage_smps_sel(struct regulator_dev *dev, + unsigned selector) +{ + struct palmas_pmic *pmic = rdev_get_drvdata(dev); + int id = rdev_get_id(dev); + unsigned int reg = 0; + unsigned int addr; + + addr = palmas_regs_info[id].vsel_addr; + + /* Make sure we don't change the value of RANGE */ + if (pmic->range[id]) + reg |= PALMAS_SMPS12_VOLTAGE_RANGE; + + /* Adjust the linux selector into range used in VSEL register */ + if (selector) + reg |= selector + 5; + + palmas_smps_write(pmic->palmas, addr, reg); + + return 0; +} + +static int palmas_map_voltage_smps(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + int ret, voltage; + + ret = ((min_uV - 500000) / 10000) + 1; + if (ret < 0) + return ret; + + /* Map back into a voltage to verify we're still in bounds */ + voltage = palmas_list_voltage_smps(rdev, ret); + if (voltage < min_uV || voltage > max_uV) + return -EINVAL; + + return ret; +} + +static struct regulator_ops palmas_ops_smps = { + .is_enabled = palmas_is_enabled_smps, + .enable = palmas_enable_smps, + .disable = palmas_disable_smps, + .set_mode = palmas_set_mode_smps, + .get_mode = palmas_get_mode_smps, + .get_voltage_sel = palmas_get_voltage_smps_sel, + .set_voltage_sel = palmas_set_voltage_smps_sel, + .list_voltage = palmas_list_voltage_smps, + .map_voltage = palmas_map_voltage_smps, +}; + +static int palmas_list_voltage_smps10(struct regulator_dev *dev, + unsigned selector) +{ + return 3750000 + (selector * 1250000); +} + +static struct regulator_ops palmas_ops_smps10 = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = palmas_list_voltage_smps10, +}; + +static int palmas_is_enabled_ldo(struct regulator_dev *dev) +{ + struct palmas_pmic *pmic = rdev_get_drvdata(dev); + int id = rdev_get_id(dev); + unsigned int reg; + + palmas_ldo_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, ®); + + reg &= PALMAS_LDO1_CTRL_STATUS; + + return !!(reg); +} + +static int palmas_list_voltage_ldo(struct regulator_dev *dev, + unsigned selector) +{ + if (!selector) + return 0; + + /* voltage is 0.85V + (selector * 0.05v) */ + return 850000 + (selector * 50000); +} + +static int palmas_get_voltage_ldo_sel(struct regulator_dev *dev) +{ + struct palmas_pmic *pmic = rdev_get_drvdata(dev); + int id = rdev_get_id(dev); + int selector; + unsigned int reg; + unsigned int addr; + + addr = palmas_regs_info[id].vsel_addr; + + palmas_ldo_read(pmic->palmas, addr, ®); + + selector = reg & PALMAS_LDO1_VOLTAGE_VSEL_MASK; + + /* Adjust selector to match list_voltage ranges */ + if (selector > 49) + selector = 49; + + return selector; +} + +static int palmas_set_voltage_ldo_sel(struct regulator_dev *dev, + unsigned selector) +{ + struct palmas_pmic *pmic = rdev_get_drvdata(dev); + int id = rdev_get_id(dev); + unsigned int reg = 0; + unsigned int addr; + + addr = palmas_regs_info[id].vsel_addr; + + reg = selector; + + palmas_ldo_write(pmic->palmas, addr, reg); + + return 0; +} + +static int palmas_map_voltage_ldo(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + int ret, voltage; + + ret = ((min_uV - 900000) / 50000) + 1; + if (ret < 0) + return ret; + + /* Map back into a voltage to verify we're still in bounds */ + voltage = palmas_list_voltage_ldo(rdev, ret); + if (voltage < min_uV || voltage > max_uV) + return -EINVAL; + + return ret; +} + +static struct regulator_ops palmas_ops_ldo = { + .is_enabled = palmas_is_enabled_ldo, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = palmas_get_voltage_ldo_sel, + .set_voltage_sel = palmas_set_voltage_ldo_sel, + .list_voltage = palmas_list_voltage_ldo, + .map_voltage = palmas_map_voltage_ldo, +}; + +/* + * setup the hardware based sleep configuration of the SMPS/LDO regulators + * from the platform data. This is different to the software based control + * supported by the regulator framework as it is controlled by toggling + * pins on the PMIC such as PREQ, SYSEN, ... + */ +static int palmas_smps_init(struct palmas *palmas, int id, + struct palmas_reg_init *reg_init) +{ + unsigned int reg; + unsigned int addr; + int ret; + + addr = palmas_regs_info[id].ctrl_addr; + + ret = palmas_smps_read(palmas, addr, ®); + if (ret) + return ret; + + if (id != PALMAS_REG_SMPS10) { + if (reg_init->warm_reset) + reg |= PALMAS_SMPS12_CTRL_WR_S; + + if (reg_init->roof_floor) + reg |= PALMAS_SMPS12_CTRL_ROOF_FLOOR_EN; + + if (reg_init->mode_sleep) { + reg &= ~PALMAS_SMPS12_CTRL_MODE_SLEEP_MASK; + reg |= reg_init->mode_sleep << + PALMAS_SMPS12_CTRL_MODE_SLEEP_SHIFT; + } + } else { + if (reg_init->mode_sleep) { + reg &= ~PALMAS_SMPS10_CTRL_MODE_SLEEP_MASK; + reg |= reg_init->mode_sleep << + PALMAS_SMPS10_CTRL_MODE_SLEEP_SHIFT; + } + + } + ret = palmas_smps_write(palmas, addr, reg); + if (ret) + return ret; + + if (palmas_regs_info[id].tstep_addr && reg_init->tstep) { + addr = palmas_regs_info[id].tstep_addr; + + reg = reg_init->tstep & PALMAS_SMPS12_TSTEP_TSTEP_MASK; + + ret = palmas_smps_write(palmas, addr, reg); + if (ret) + return ret; + } + + if (palmas_regs_info[id].vsel_addr && reg_init->vsel) { + addr = palmas_regs_info[id].vsel_addr; + + reg = reg_init->vsel; + + ret = palmas_smps_write(palmas, addr, reg); + if (ret) + return ret; + } + + + return 0; +} + +static int palmas_ldo_init(struct palmas *palmas, int id, + struct palmas_reg_init *reg_init) +{ + unsigned int reg; + unsigned int addr; + int ret; + + addr = palmas_regs_info[id].ctrl_addr; + + ret = palmas_smps_read(palmas, addr, ®); + if (ret) + return ret; + + if (reg_init->warm_reset) + reg |= PALMAS_LDO1_CTRL_WR_S; + + if (reg_init->mode_sleep) + reg |= PALMAS_LDO1_CTRL_MODE_SLEEP; + + ret = palmas_smps_write(palmas, addr, reg); + if (ret) + return ret; + + return 0; +} + +static __devinit int palmas_probe(struct platform_device *pdev) +{ + struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); + struct palmas_pmic_platform_data *pdata = pdev->dev.platform_data; + struct regulator_dev *rdev; + struct regulator_config config = { }; + struct palmas_pmic *pmic; + struct palmas_reg_init *reg_init; + int id = 0, ret; + unsigned int addr, reg; + + if (!pdata) + return -EINVAL; + if (!pdata->reg_data) + return -EINVAL; + + pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL); + if (!pmic) + return -ENOMEM; + + pmic->dev = &pdev->dev; + pmic->palmas = palmas; + palmas->pmic = pmic; + platform_set_drvdata(pdev, pmic); + + ret = palmas_smps_read(palmas, PALMAS_SMPS_CTRL, ®); + if (ret) + goto err_unregister_regulator; + + if (reg & PALMAS_SMPS_CTRL_SMPS12_SMPS123_EN) + pmic->smps123 = 1; + + if (reg & PALMAS_SMPS_CTRL_SMPS45_SMPS457_EN) + pmic->smps457 = 1; + + config.regmap = palmas->regmap[REGULATOR_SLAVE]; + config.dev = &pdev->dev; + config.driver_data = pmic; + + for (id = 0; id < PALMAS_REG_LDO1; id++) { + + /* + * Miss out regulators which are not available due + * to slaving configurations. + */ + switch (id) { + case PALMAS_REG_SMPS12: + case PALMAS_REG_SMPS3: + if (pmic->smps123) + continue; + break; + case PALMAS_REG_SMPS123: + if (!pmic->smps123) + continue; + break; + case PALMAS_REG_SMPS45: + case PALMAS_REG_SMPS7: + if (pmic->smps457) + continue; + break; + case PALMAS_REG_SMPS457: + if (!pmic->smps457) + continue; + } + + /* Register the regulators */ + pmic->desc[id].name = palmas_regs_info[id].name; + pmic->desc[id].id = id; + + if (id != PALMAS_REG_SMPS10) { + pmic->desc[id].ops = &palmas_ops_smps; + pmic->desc[id].n_voltages = PALMAS_SMPS_NUM_VOLTAGES; + } else { + pmic->desc[id].n_voltages = PALMAS_SMPS10_NUM_VOLTAGES; + pmic->desc[id].ops = &palmas_ops_smps10; + pmic->desc[id].vsel_reg = PALMAS_SMPS10_CTRL; + pmic->desc[id].vsel_mask = SMPS10_VSEL; + pmic->desc[id].enable_reg = PALMAS_SMPS10_STATUS; + pmic->desc[id].enable_mask = SMPS10_BOOST_EN; + } + + pmic->desc[id].type = REGULATOR_VOLTAGE; + pmic->desc[id].owner = THIS_MODULE; + + /* Initialise sleep/init values from platform data */ + if (pdata && pdata->reg_init) { + reg_init = pdata->reg_init[id]; + if (reg_init) { + ret = palmas_smps_init(palmas, id, reg_init); + if (ret) + goto err_unregister_regulator; + } + } + + /* + * read and store the RANGE bit for later use + * This must be done before regulator is probed otherwise + * we error in probe with unsuportable ranges. + */ + if (id != PALMAS_REG_SMPS10) { + addr = palmas_regs_info[id].vsel_addr; + + ret = palmas_smps_read(pmic->palmas, addr, ®); + if (ret) + goto err_unregister_regulator; + if (reg & PALMAS_SMPS12_VOLTAGE_RANGE) + pmic->range[id] = 1; + } + + if (pdata && pdata->reg_data) + config.init_data = pdata->reg_data[id]; + else + config.init_data = NULL; + + rdev = regulator_register(&pmic->desc[id], &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, + "failed to register %s regulator\n", + pdev->name); + ret = PTR_ERR(rdev); + goto err_unregister_regulator; + } + + /* Save regulator for cleanup */ + pmic->rdev[id] = rdev; + } + + /* Start this loop from the id left from previous loop */ + for (; id < PALMAS_NUM_REGS; id++) { + + /* Miss out regulators which are not available due + * to alternate functions. + */ + + /* Register the regulators */ + pmic->desc[id].name = palmas_regs_info[id].name; + pmic->desc[id].id = id; + pmic->desc[id].n_voltages = PALMAS_LDO_NUM_VOLTAGES; + + pmic->desc[id].ops = &palmas_ops_ldo; + + pmic->desc[id].type = REGULATOR_VOLTAGE; + pmic->desc[id].owner = THIS_MODULE; + pmic->desc[id].enable_reg = palmas_regs_info[id].ctrl_addr; + pmic->desc[id].enable_mask = PALMAS_LDO1_CTRL_MODE_ACTIVE; + + if (pdata && pdata->reg_data) + config.init_data = pdata->reg_data[id]; + else + config.init_data = NULL; + + rdev = regulator_register(&pmic->desc[id], &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, + "failed to register %s regulator\n", + pdev->name); + ret = PTR_ERR(rdev); + goto err_unregister_regulator; + } + + /* Save regulator for cleanup */ + pmic->rdev[id] = rdev; + + /* Initialise sleep/init values from platform data */ + if (pdata->reg_init) { + reg_init = pdata->reg_init[id]; + if (reg_init) { + ret = palmas_ldo_init(palmas, id, reg_init); + if (ret) + goto err_unregister_regulator; + } + } + } + + return 0; + +err_unregister_regulator: + while (--id >= 0) + regulator_unregister(pmic->rdev[id]); + kfree(pmic->rdev); + kfree(pmic->desc); + kfree(pmic); + return ret; +} + +static int __devexit palmas_remove(struct platform_device *pdev) +{ + struct palmas_pmic *pmic = platform_get_drvdata(pdev); + int id; + + for (id = 0; id < PALMAS_NUM_REGS; id++) + regulator_unregister(pmic->rdev[id]); + + kfree(pmic->rdev); + kfree(pmic->desc); + kfree(pmic); + return 0; +} + +static struct platform_driver palmas_driver = { + .driver = { + .name = "palmas-pmic", + .owner = THIS_MODULE, + }, + .probe = palmas_probe, + .remove = __devexit_p(palmas_remove), +}; + +static int __init palmas_init(void) +{ + return platform_driver_register(&palmas_driver); +} +subsys_initcall(palmas_init); + +static void __exit palmas_exit(void) +{ + platform_driver_unregister(&palmas_driver); +} +module_exit(palmas_exit); + +MODULE_AUTHOR("Graeme Gregory "); +MODULE_DESCRIPTION("Palmas voltage regulator driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:palmas-pmic"); diff --git a/trunk/drivers/regulator/pcap-regulator.c b/trunk/drivers/regulator/pcap-regulator.c index a5aab1b08bcf..8211101121f0 100644 --- a/trunk/drivers/regulator/pcap-regulator.c +++ b/trunk/drivers/regulator/pcap-regulator.c @@ -150,57 +150,33 @@ static struct pcap_regulator vreg_table[] = { VREG_INFO(SW2S, PCAP_REG_LOWPWR, NA, 20, NA, NA), */ }; -static int pcap_regulator_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, - unsigned *selector) +static int pcap_regulator_set_voltage_sel(struct regulator_dev *rdev, + unsigned selector) { struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; void *pcap = rdev_get_drvdata(rdev); - int uV; - u8 i; /* the regulator doesn't support voltage switching */ if (vreg->n_voltages == 1) return -EINVAL; - for (i = 0; i < vreg->n_voltages; i++) { - /* For V1 the first is not the best match */ - if (i == 0 && rdev_get_id(rdev) == V1) - i = 1; - else if (i + 1 == vreg->n_voltages && rdev_get_id(rdev) == V1) - i = 0; - - uV = vreg->voltage_table[i] * 1000; - if (min_uV <= uV && uV <= max_uV) { - *selector = i; - return ezx_pcap_set_bits(pcap, vreg->reg, - (vreg->n_voltages - 1) << vreg->index, - i << vreg->index); - } - - if (i == 0 && rdev_get_id(rdev) == V1) - i = vreg->n_voltages - 1; - } - - /* the requested voltage range is not supported by this regulator */ - return -EINVAL; + return ezx_pcap_set_bits(pcap, vreg->reg, + (vreg->n_voltages - 1) << vreg->index, + selector << vreg->index); } -static int pcap_regulator_get_voltage(struct regulator_dev *rdev) +static int pcap_regulator_get_voltage_sel(struct regulator_dev *rdev) { struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; void *pcap = rdev_get_drvdata(rdev); u32 tmp; - int mV; if (vreg->n_voltages == 1) - return vreg->voltage_table[0] * 1000; + return 0; ezx_pcap_read(pcap, vreg->reg, &tmp); tmp = ((tmp >> vreg->index) & (vreg->n_voltages - 1)); - mV = vreg->voltage_table[tmp]; - - return mV * 1000; + return tmp; } static int pcap_regulator_enable(struct regulator_dev *rdev) @@ -248,8 +224,8 @@ static int pcap_regulator_list_voltage(struct regulator_dev *rdev, static struct regulator_ops pcap_regulator_ops = { .list_voltage = pcap_regulator_list_voltage, - .set_voltage = pcap_regulator_set_voltage, - .get_voltage = pcap_regulator_get_voltage, + .set_voltage_sel = pcap_regulator_set_voltage_sel, + .get_voltage_sel = pcap_regulator_get_voltage_sel, .enable = pcap_regulator_enable, .disable = pcap_regulator_disable, .is_enabled = pcap_regulator_is_enabled, @@ -265,7 +241,7 @@ static struct regulator_ops pcap_regulator_ops = { .owner = THIS_MODULE, \ } -static struct regulator_desc pcap_regulators[] = { +static const struct regulator_desc pcap_regulators[] = { VREG(V1), VREG(V2), VREG(V3), VREG(V4), VREG(V5), VREG(V6), VREG(V7), VREG(V8), VREG(V9), VREG(V10), VREG(VAUX1), VREG(VAUX2), VREG(VAUX3), VREG(VAUX4), VREG(VSIM), VREG(VSIM2), VREG(VVIB), VREG(SW1), VREG(SW2), @@ -275,9 +251,13 @@ static int __devinit pcap_regulator_probe(struct platform_device *pdev) { struct regulator_dev *rdev; void *pcap = dev_get_drvdata(pdev->dev.parent); + struct regulator_config config = { }; + + config.dev = &pdev->dev; + config.init_data = pdev->dev.platform_data; + config.driver_data = pcap; - rdev = regulator_register(&pcap_regulators[pdev->id], &pdev->dev, - pdev->dev.platform_data, pcap, NULL); + rdev = regulator_register(&pcap_regulators[pdev->id], &config); if (IS_ERR(rdev)) return PTR_ERR(rdev); diff --git a/trunk/drivers/regulator/pcf50633-regulator.c b/trunk/drivers/regulator/pcf50633-regulator.c index 6db46c632f13..3c9d14c0017b 100644 --- a/trunk/drivers/regulator/pcf50633-regulator.c +++ b/trunk/drivers/regulator/pcf50633-regulator.c @@ -24,35 +24,25 @@ #include #include -#define PCF50633_REGULATOR(_name, _id, _n) \ - { \ - .name = _name, \ - .id = _id, \ - .ops = &pcf50633_regulator_ops, \ - .n_voltages = _n, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ +#define PCF50633_REGULATOR(_name, _id, _n) \ + { \ + .name = _name, \ + .id = PCF50633_REGULATOR_##_id, \ + .ops = &pcf50633_regulator_ops, \ + .n_voltages = _n, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .vsel_reg = PCF50633_REG_##_id##OUT, \ + .vsel_mask = 0xff, \ + .enable_reg = PCF50633_REG_##_id##OUT + 1, \ + .enable_mask = PCF50633_REGULATOR_ON, \ } -static const u8 pcf50633_regulator_registers[PCF50633_NUM_REGULATORS] = { - [PCF50633_REGULATOR_AUTO] = PCF50633_REG_AUTOOUT, - [PCF50633_REGULATOR_DOWN1] = PCF50633_REG_DOWN1OUT, - [PCF50633_REGULATOR_DOWN2] = PCF50633_REG_DOWN2OUT, - [PCF50633_REGULATOR_MEMLDO] = PCF50633_REG_MEMLDOOUT, - [PCF50633_REGULATOR_LDO1] = PCF50633_REG_LDO1OUT, - [PCF50633_REGULATOR_LDO2] = PCF50633_REG_LDO2OUT, - [PCF50633_REGULATOR_LDO3] = PCF50633_REG_LDO3OUT, - [PCF50633_REGULATOR_LDO4] = PCF50633_REG_LDO4OUT, - [PCF50633_REGULATOR_LDO5] = PCF50633_REG_LDO5OUT, - [PCF50633_REGULATOR_LDO6] = PCF50633_REG_LDO6OUT, - [PCF50633_REGULATOR_HCLDO] = PCF50633_REG_HCLDOOUT, -}; - /* Bits from voltage value */ static u8 auto_voltage_bits(unsigned int millivolts) { if (millivolts < 1800) - return 0; + return 0x2f; if (millivolts > 3800) return 0xff; @@ -87,6 +77,9 @@ static u8 ldo_voltage_bits(unsigned int millivolts) /* Obtain voltage value from bits */ static unsigned int auto_voltage_value(u8 bits) { + /* AUTOOUT: 00000000 to 00101110 are reserved. + * Return 0 for bits in reserved range, which means this selector code + * can't be used on this system */ if (bits < 0x2f) return 0; @@ -123,7 +116,7 @@ static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev, millivolts = min_uV / 1000; - regnr = pcf50633_regulator_registers[regulator_id]; + regnr = rdev->desc->vsel_reg; switch (regulator_id) { case PCF50633_REGULATOR_AUTO: @@ -154,20 +147,22 @@ static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev, return pcf50633_reg_write(pcf, regnr, volt_bits); } -static int pcf50633_regulator_voltage_value(enum pcf50633_regulator_id id, - u8 bits) +static int pcf50633_regulator_list_voltage(struct regulator_dev *rdev, + unsigned int index) { + int regulator_id = rdev_get_id(rdev); + int millivolts; - switch (id) { + switch (regulator_id) { case PCF50633_REGULATOR_AUTO: - millivolts = auto_voltage_value(bits); + millivolts = auto_voltage_value(index); break; case PCF50633_REGULATOR_DOWN1: - millivolts = down_voltage_value(bits); + millivolts = down_voltage_value(index); break; case PCF50633_REGULATOR_DOWN2: - millivolts = down_voltage_value(bits); + millivolts = down_voltage_value(index); break; case PCF50633_REGULATOR_LDO1: case PCF50633_REGULATOR_LDO2: @@ -177,7 +172,7 @@ static int pcf50633_regulator_voltage_value(enum pcf50633_regulator_id id, case PCF50633_REGULATOR_LDO6: case PCF50633_REGULATOR_HCLDO: case PCF50633_REGULATOR_MEMLDO: - millivolts = ldo_voltage_value(bits); + millivolts = ldo_voltage_value(index); break; default: return -EINVAL; @@ -186,140 +181,44 @@ static int pcf50633_regulator_voltage_value(enum pcf50633_regulator_id id, return millivolts * 1000; } -static int pcf50633_regulator_get_voltage(struct regulator_dev *rdev) -{ - struct pcf50633 *pcf; - int regulator_id; - u8 volt_bits, regnr; - - pcf = rdev_get_drvdata(rdev); - - regulator_id = rdev_get_id(rdev); - if (regulator_id >= PCF50633_NUM_REGULATORS) - return -EINVAL; - - regnr = pcf50633_regulator_registers[regulator_id]; - - volt_bits = pcf50633_reg_read(pcf, regnr); - - return pcf50633_regulator_voltage_value(regulator_id, volt_bits); -} - -static int pcf50633_regulator_list_voltage(struct regulator_dev *rdev, - unsigned int index) -{ - struct pcf50633 *pcf; - int regulator_id; - - pcf = rdev_get_drvdata(rdev); - - regulator_id = rdev_get_id(rdev); - - switch (regulator_id) { - case PCF50633_REGULATOR_AUTO: - index += 0x2f; - break; - default: - break; - } - - return pcf50633_regulator_voltage_value(regulator_id, index); -} - -static int pcf50633_regulator_enable(struct regulator_dev *rdev) -{ - struct pcf50633 *pcf = rdev_get_drvdata(rdev); - int regulator_id; - u8 regnr; - - regulator_id = rdev_get_id(rdev); - if (regulator_id >= PCF50633_NUM_REGULATORS) - return -EINVAL; - - /* The *ENA register is always one after the *OUT register */ - regnr = pcf50633_regulator_registers[regulator_id] + 1; - - return pcf50633_reg_set_bit_mask(pcf, regnr, PCF50633_REGULATOR_ON, - PCF50633_REGULATOR_ON); -} - -static int pcf50633_regulator_disable(struct regulator_dev *rdev) -{ - struct pcf50633 *pcf = rdev_get_drvdata(rdev); - int regulator_id; - u8 regnr; - - regulator_id = rdev_get_id(rdev); - if (regulator_id >= PCF50633_NUM_REGULATORS) - return -EINVAL; - - /* the *ENA register is always one after the *OUT register */ - regnr = pcf50633_regulator_registers[regulator_id] + 1; - - return pcf50633_reg_set_bit_mask(pcf, regnr, - PCF50633_REGULATOR_ON, 0); -} - -static int pcf50633_regulator_is_enabled(struct regulator_dev *rdev) -{ - struct pcf50633 *pcf = rdev_get_drvdata(rdev); - int regulator_id = rdev_get_id(rdev); - u8 regnr; - - regulator_id = rdev_get_id(rdev); - if (regulator_id >= PCF50633_NUM_REGULATORS) - return -EINVAL; - - /* the *ENA register is always one after the *OUT register */ - regnr = pcf50633_regulator_registers[regulator_id] + 1; - - return pcf50633_reg_read(pcf, regnr) & PCF50633_REGULATOR_ON; -} - static struct regulator_ops pcf50633_regulator_ops = { .set_voltage = pcf50633_regulator_set_voltage, - .get_voltage = pcf50633_regulator_get_voltage, + .get_voltage_sel = regulator_get_voltage_sel_regmap, .list_voltage = pcf50633_regulator_list_voltage, - .enable = pcf50633_regulator_enable, - .disable = pcf50633_regulator_disable, - .is_enabled = pcf50633_regulator_is_enabled, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, }; -static struct regulator_desc regulators[] = { - [PCF50633_REGULATOR_AUTO] = - PCF50633_REGULATOR("auto", PCF50633_REGULATOR_AUTO, 81), - [PCF50633_REGULATOR_DOWN1] = - PCF50633_REGULATOR("down1", PCF50633_REGULATOR_DOWN1, 96), - [PCF50633_REGULATOR_DOWN2] = - PCF50633_REGULATOR("down2", PCF50633_REGULATOR_DOWN2, 96), - [PCF50633_REGULATOR_LDO1] = - PCF50633_REGULATOR("ldo1", PCF50633_REGULATOR_LDO1, 28), - [PCF50633_REGULATOR_LDO2] = - PCF50633_REGULATOR("ldo2", PCF50633_REGULATOR_LDO2, 28), - [PCF50633_REGULATOR_LDO3] = - PCF50633_REGULATOR("ldo3", PCF50633_REGULATOR_LDO3, 28), - [PCF50633_REGULATOR_LDO4] = - PCF50633_REGULATOR("ldo4", PCF50633_REGULATOR_LDO4, 28), - [PCF50633_REGULATOR_LDO5] = - PCF50633_REGULATOR("ldo5", PCF50633_REGULATOR_LDO5, 28), - [PCF50633_REGULATOR_LDO6] = - PCF50633_REGULATOR("ldo6", PCF50633_REGULATOR_LDO6, 28), - [PCF50633_REGULATOR_HCLDO] = - PCF50633_REGULATOR("hcldo", PCF50633_REGULATOR_HCLDO, 28), - [PCF50633_REGULATOR_MEMLDO] = - PCF50633_REGULATOR("memldo", PCF50633_REGULATOR_MEMLDO, 28), +static const struct regulator_desc regulators[] = { + [PCF50633_REGULATOR_AUTO] = PCF50633_REGULATOR("auto", AUTO, 128), + [PCF50633_REGULATOR_DOWN1] = PCF50633_REGULATOR("down1", DOWN1, 96), + [PCF50633_REGULATOR_DOWN2] = PCF50633_REGULATOR("down2", DOWN2, 96), + [PCF50633_REGULATOR_LDO1] = PCF50633_REGULATOR("ldo1", LDO1, 28), + [PCF50633_REGULATOR_LDO2] = PCF50633_REGULATOR("ldo2", LDO2, 28), + [PCF50633_REGULATOR_LDO3] = PCF50633_REGULATOR("ldo3", LDO3, 28), + [PCF50633_REGULATOR_LDO4] = PCF50633_REGULATOR("ldo4", LDO4, 28), + [PCF50633_REGULATOR_LDO5] = PCF50633_REGULATOR("ldo5", LDO5, 28), + [PCF50633_REGULATOR_LDO6] = PCF50633_REGULATOR("ldo6", LDO6, 28), + [PCF50633_REGULATOR_HCLDO] = PCF50633_REGULATOR("hcldo", HCLDO, 28), + [PCF50633_REGULATOR_MEMLDO] = PCF50633_REGULATOR("memldo", MEMLDO, 28), }; static int __devinit pcf50633_regulator_probe(struct platform_device *pdev) { struct regulator_dev *rdev; struct pcf50633 *pcf; + struct regulator_config config = { }; /* Already set by core driver */ pcf = dev_to_pcf50633(pdev->dev.parent); - rdev = regulator_register(®ulators[pdev->id], &pdev->dev, - pdev->dev.platform_data, pcf, NULL); + config.dev = &pdev->dev; + config.init_data = pdev->dev.platform_data; + config.driver_data = pcf; + config.regmap = pcf->regmap; + + rdev = regulator_register(®ulators[pdev->id], &config); if (IS_ERR(rdev)) return PTR_ERR(rdev); diff --git a/trunk/drivers/regulator/rc5t583-regulator.c b/trunk/drivers/regulator/rc5t583-regulator.c new file mode 100644 index 000000000000..1d34e64a1307 --- /dev/null +++ b/trunk/drivers/regulator/rc5t583-regulator.c @@ -0,0 +1,255 @@ +/* + * Regulator driver for RICOH RC5T583 power management chip. + * + * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved. + * Author: Laxman dewangan + * + * based on code + * Copyright (C) 2011 RICOH COMPANY,LTD + * + * + * 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 . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct rc5t583_regulator_info { + int deepsleep_id; + + /* Regulator register address.*/ + uint8_t reg_disc_reg; + uint8_t disc_bit; + uint8_t deepsleep_reg; + + /* Regulator specific turn-on delay and voltage settling time*/ + int enable_uv_per_us; + int change_uv_per_us; + + /* Used by regulator core */ + struct regulator_desc desc; +}; + +struct rc5t583_regulator { + struct rc5t583_regulator_info *reg_info; + + /* Devices */ + struct device *dev; + struct rc5t583 *mfd; + struct regulator_dev *rdev; +}; + +static int rc5t583_regulator_enable_time(struct regulator_dev *rdev) +{ + struct rc5t583_regulator *reg = rdev_get_drvdata(rdev); + int vsel = regulator_get_voltage_sel_regmap(rdev); + int curr_uV = regulator_list_voltage_linear(rdev, vsel); + + return DIV_ROUND_UP(curr_uV, reg->reg_info->enable_uv_per_us); +} + +static int rc5t583_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int old_selector, unsigned int new_selector) +{ + struct rc5t583_regulator *reg = rdev_get_drvdata(rdev); + int old_uV, new_uV; + old_uV = regulator_list_voltage_linear(rdev, old_selector); + + if (old_uV < 0) + return old_uV; + + new_uV = regulator_list_voltage_linear(rdev, new_selector); + if (new_uV < 0) + return new_uV; + + return DIV_ROUND_UP(abs(old_uV - new_uV), + reg->reg_info->change_uv_per_us); +} + + +static struct regulator_ops rc5t583_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .enable_time = rc5t583_regulator_enable_time, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .set_voltage_time_sel = rc5t583_set_voltage_time_sel, +}; + +#define RC5T583_REG(_id, _en_reg, _en_bit, _disc_reg, _disc_bit, \ + _vout_mask, _min_mv, _max_mv, _step_uV, _enable_mv) \ +{ \ + .reg_disc_reg = RC5T583_REG_##_disc_reg, \ + .disc_bit = _disc_bit, \ + .deepsleep_reg = RC5T583_REG_##_id##DAC_DS, \ + .enable_uv_per_us = _enable_mv * 1000, \ + .change_uv_per_us = 40 * 1000, \ + .deepsleep_id = RC5T583_DS_##_id, \ + .desc = { \ + .name = "rc5t583-regulator-"#_id, \ + .id = RC5T583_REGULATOR_##_id, \ + .n_voltages = (_max_mv - _min_mv) * 1000 / _step_uV + 1, \ + .ops = &rc5t583_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .vsel_reg = RC5T583_REG_##_id##DAC, \ + .vsel_mask = _vout_mask, \ + .enable_reg = RC5T583_REG_##_en_reg, \ + .enable_mask = BIT(_en_bit), \ + .min_uV = _min_mv * 1000, \ + .uV_step = _step_uV, \ + }, \ +} + +static struct rc5t583_regulator_info rc5t583_reg_info[RC5T583_REGULATOR_MAX] = { + RC5T583_REG(DC0, DC0CTL, 0, DC0CTL, 1, 0x7F, 700, 1500, 12500, 4), + RC5T583_REG(DC1, DC1CTL, 0, DC1CTL, 1, 0x7F, 700, 1500, 12500, 14), + RC5T583_REG(DC2, DC2CTL, 0, DC2CTL, 1, 0x7F, 900, 2400, 12500, 14), + RC5T583_REG(DC3, DC3CTL, 0, DC3CTL, 1, 0x7F, 900, 2400, 12500, 14), + RC5T583_REG(LDO0, LDOEN2, 0, LDODIS2, 0, 0x7F, 900, 3400, 25000, 160), + RC5T583_REG(LDO1, LDOEN2, 1, LDODIS2, 1, 0x7F, 900, 3400, 25000, 160), + RC5T583_REG(LDO2, LDOEN2, 2, LDODIS2, 2, 0x7F, 900, 3400, 25000, 160), + RC5T583_REG(LDO3, LDOEN2, 3, LDODIS2, 3, 0x7F, 900, 3400, 25000, 160), + RC5T583_REG(LDO4, LDOEN2, 4, LDODIS2, 4, 0x3F, 750, 1500, 12500, 133), + RC5T583_REG(LDO5, LDOEN2, 5, LDODIS2, 5, 0x7F, 900, 3400, 25000, 267), + RC5T583_REG(LDO6, LDOEN2, 6, LDODIS2, 6, 0x7F, 900, 3400, 25000, 133), + RC5T583_REG(LDO7, LDOEN2, 7, LDODIS2, 7, 0x7F, 900, 3400, 25000, 233), + RC5T583_REG(LDO8, LDOEN1, 0, LDODIS1, 0, 0x7F, 900, 3400, 25000, 233), + RC5T583_REG(LDO9, LDOEN1, 1, LDODIS1, 1, 0x7F, 900, 3400, 25000, 133), +}; + +static int __devinit rc5t583_regulator_probe(struct platform_device *pdev) +{ + struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent); + struct rc5t583_platform_data *pdata = dev_get_platdata(rc5t583->dev); + struct regulator_init_data *reg_data; + struct regulator_config config = { }; + struct rc5t583_regulator *reg = NULL; + struct rc5t583_regulator *regs; + struct regulator_dev *rdev; + struct rc5t583_regulator_info *ri; + int ret; + int id; + + if (!pdata) { + dev_err(&pdev->dev, "No platform data, exiting...\n"); + return -ENODEV; + } + + regs = devm_kzalloc(&pdev->dev, RC5T583_REGULATOR_MAX * + sizeof(struct rc5t583_regulator), GFP_KERNEL); + if (!regs) { + dev_err(&pdev->dev, "Memory allocation failed exiting..\n"); + return -ENOMEM; + } + + + for (id = 0; id < RC5T583_REGULATOR_MAX; ++id) { + reg_data = pdata->reg_init_data[id]; + + /* No need to register if there is no regulator data */ + if (!reg_data) + continue; + + reg = ®s[id]; + ri = &rc5t583_reg_info[id]; + reg->reg_info = ri; + reg->mfd = rc5t583; + reg->dev = &pdev->dev; + + if (ri->deepsleep_id == RC5T583_DS_NONE) + goto skip_ext_pwr_config; + + ret = rc5t583_ext_power_req_config(rc5t583->dev, + ri->deepsleep_id, + pdata->regulator_ext_pwr_control[id], + pdata->regulator_deepsleep_slot[id]); + /* + * Configuring external control is not a major issue, + * just give warning. + */ + if (ret < 0) + dev_warn(&pdev->dev, + "Failed to configure ext control %d\n", id); + +skip_ext_pwr_config: + config.dev = &pdev->dev; + config.init_data = reg_data; + config.driver_data = reg; + config.regmap = rc5t583->regmap; + + rdev = regulator_register(&ri->desc, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "Failed to register regulator %s\n", + ri->desc.name); + ret = PTR_ERR(rdev); + goto clean_exit; + } + reg->rdev = rdev; + } + platform_set_drvdata(pdev, regs); + return 0; + +clean_exit: + while (--id >= 0) + regulator_unregister(regs[id].rdev); + + return ret; +} + +static int __devexit rc5t583_regulator_remove(struct platform_device *pdev) +{ + struct rc5t583_regulator *regs = platform_get_drvdata(pdev); + int id; + + for (id = 0; id < RC5T583_REGULATOR_MAX; ++id) + regulator_unregister(regs[id].rdev); + return 0; +} + +static struct platform_driver rc5t583_regulator_driver = { + .driver = { + .name = "rc5t583-regulator", + .owner = THIS_MODULE, + }, + .probe = rc5t583_regulator_probe, + .remove = __devexit_p(rc5t583_regulator_remove), +}; + +static int __init rc5t583_regulator_init(void) +{ + return platform_driver_register(&rc5t583_regulator_driver); +} +subsys_initcall(rc5t583_regulator_init); + +static void __exit rc5t583_regulator_exit(void) +{ + platform_driver_unregister(&rc5t583_regulator_driver); +} +module_exit(rc5t583_regulator_exit); + +MODULE_AUTHOR("Laxman Dewangan "); +MODULE_DESCRIPTION("RC5T583 regulator driver"); +MODULE_ALIAS("platform:rc5t583-regulator"); +MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/regulator/s5m8767.c b/trunk/drivers/regulator/s5m8767.c index 4ca2db059004..290d6fc01029 100644 --- a/trunk/drivers/regulator/s5m8767.c +++ b/trunk/drivers/regulator/s5m8767.c @@ -12,7 +12,6 @@ */ #include -#include #include #include #include @@ -28,6 +27,7 @@ struct s5m8767_info { struct s5m87xx_dev *iodev; int num_regulators; struct regulator_dev **rdev; + struct s5m_opmode_data *opmode; int ramp_delay; bool buck2_ramp; @@ -141,9 +141,56 @@ static int s5m8767_list_voltage(struct regulator_dev *rdev, return val; } -static int s5m8767_get_register(struct regulator_dev *rdev, int *reg) +static unsigned int s5m8767_opmode_reg[][4] = { + /* {OFF, ON, LOWPOWER, SUSPEND} */ + /* LDO1 ... LDO28 */ + {0x0, 0x3, 0x2, 0x1}, /* LDO1 */ + {0x0, 0x3, 0x2, 0x1}, + {0x0, 0x3, 0x2, 0x1}, + {0x0, 0x0, 0x0, 0x0}, + {0x0, 0x3, 0x2, 0x1}, /* LDO5 */ + {0x0, 0x3, 0x2, 0x1}, + {0x0, 0x3, 0x2, 0x1}, + {0x0, 0x3, 0x2, 0x1}, + {0x0, 0x3, 0x2, 0x1}, + {0x0, 0x3, 0x2, 0x1}, /* LDO10 */ + {0x0, 0x3, 0x2, 0x1}, + {0x0, 0x3, 0x2, 0x1}, + {0x0, 0x3, 0x2, 0x1}, + {0x0, 0x3, 0x2, 0x1}, + {0x0, 0x3, 0x2, 0x1}, /* LDO15 */ + {0x0, 0x3, 0x2, 0x1}, + {0x0, 0x3, 0x2, 0x1}, + {0x0, 0x0, 0x0, 0x0}, + {0x0, 0x3, 0x2, 0x1}, + {0x0, 0x3, 0x2, 0x1}, /* LDO20 */ + {0x0, 0x3, 0x2, 0x1}, + {0x0, 0x3, 0x2, 0x1}, + {0x0, 0x0, 0x0, 0x0}, + {0x0, 0x3, 0x2, 0x1}, + {0x0, 0x3, 0x2, 0x1}, /* LDO25 */ + {0x0, 0x3, 0x2, 0x1}, + {0x0, 0x3, 0x2, 0x1}, + {0x0, 0x3, 0x2, 0x1}, /* LDO28 */ + + /* BUCK1 ... BUCK9 */ + {0x0, 0x3, 0x1, 0x1}, /* BUCK1 */ + {0x0, 0x3, 0x1, 0x1}, + {0x0, 0x3, 0x1, 0x1}, + {0x0, 0x3, 0x1, 0x1}, + {0x0, 0x3, 0x2, 0x1}, /* BUCK5 */ + {0x0, 0x3, 0x1, 0x1}, + {0x0, 0x3, 0x1, 0x1}, + {0x0, 0x3, 0x1, 0x1}, + {0x0, 0x3, 0x1, 0x1}, /* BUCK9 */ +}; + +static int s5m8767_get_register(struct regulator_dev *rdev, int *reg, + int *enable_ctrl) { int reg_id = rdev_get_id(rdev); + unsigned int mode; + struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); switch (reg_id) { case S5M8767_LDO1 ... S5M8767_LDO2: @@ -168,6 +215,8 @@ static int s5m8767_get_register(struct regulator_dev *rdev, int *reg) return -EINVAL; } + mode = s5m8767->opmode[reg_id].mode; + *enable_ctrl = s5m8767_opmode_reg[reg_id][mode] << S5M8767_ENCTRL_SHIFT; return 0; } @@ -175,10 +224,10 @@ static int s5m8767_reg_is_enabled(struct regulator_dev *rdev) { struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); int ret, reg; - int mask = 0xc0, pattern = 0xc0; + int mask = 0xc0, enable_ctrl; u8 val; - ret = s5m8767_get_register(rdev, ®); + ret = s5m8767_get_register(rdev, ®, &enable_ctrl); if (ret == -EINVAL) return 1; else if (ret) @@ -188,33 +237,33 @@ static int s5m8767_reg_is_enabled(struct regulator_dev *rdev) if (ret) return ret; - return (val & mask) == pattern; + return (val & mask) == enable_ctrl; } static int s5m8767_reg_enable(struct regulator_dev *rdev) { struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); int ret, reg; - int mask = 0xc0, pattern = 0xc0; + int mask = 0xc0, enable_ctrl; - ret = s5m8767_get_register(rdev, ®); + ret = s5m8767_get_register(rdev, ®, &enable_ctrl); if (ret) return ret; - return s5m_reg_update(s5m8767->iodev, reg, pattern, mask); + return s5m_reg_update(s5m8767->iodev, reg, enable_ctrl, mask); } static int s5m8767_reg_disable(struct regulator_dev *rdev) { struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); int ret, reg; - int mask = 0xc0, pattern = 0xc0; + int mask = 0xc0, enable_ctrl; - ret = s5m8767_get_register(rdev, ®); + ret = s5m8767_get_register(rdev, ®, &enable_ctrl); if (ret) return ret; - return s5m_reg_update(s5m8767->iodev, reg, ~pattern, mask); + return s5m_reg_update(s5m8767->iodev, reg, ~mask, mask); } static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg) @@ -297,7 +346,10 @@ static int s5m8767_convert_voltage_to_sel( if (max_vol < desc->min || min_vol > desc->max) return -EINVAL; - selector = (min_vol - desc->min) / desc->step; + if (min_vol < desc->min) + min_vol = desc->min; + + selector = DIV_ROUND_UP(min_vol - desc->min, desc->step); if (desc->min + desc->step * selector > max_vol) return -EINVAL; @@ -305,14 +357,33 @@ static int s5m8767_convert_voltage_to_sel( return selector; } +static inline void s5m8767_set_high(struct s5m8767_info *s5m8767) +{ + int temp_index = s5m8767->buck_gpioindex; + + gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1); + gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1); + gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1); +} + +static inline void s5m8767_set_low(struct s5m8767_info *s5m8767) +{ + int temp_index = s5m8767->buck_gpioindex; + + gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1); + gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1); + gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1); +} + static int s5m8767_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, unsigned *selector) { struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); const struct s5m_voltage_desc *desc; int reg_id = rdev_get_id(rdev); - int sel, reg, mask, ret; + int sel, reg, mask, ret = 0, old_index, index = 0; u8 val; + u8 *buck234_vol = NULL; switch (reg_id) { case S5M8767_LDO1 ... S5M8767_LDO28: @@ -320,6 +391,12 @@ static int s5m8767_set_voltage(struct regulator_dev *rdev, break; case S5M8767_BUCK1 ... S5M8767_BUCK6: mask = 0xff; + if (reg_id == S5M8767_BUCK2 && s5m8767->buck2_gpiodvs) + buck234_vol = &s5m8767->buck2_vol[0]; + else if (reg_id == S5M8767_BUCK3 && s5m8767->buck3_gpiodvs) + buck234_vol = &s5m8767->buck3_vol[0]; + else if (reg_id == S5M8767_BUCK4 && s5m8767->buck4_gpiodvs) + buck234_vol = &s5m8767->buck4_vol[0]; break; case S5M8767_BUCK7 ... S5M8767_BUCK8: return -EINVAL; @@ -336,102 +413,32 @@ static int s5m8767_set_voltage(struct regulator_dev *rdev, if (sel < 0) return sel; - ret = s5m8767_get_voltage_register(rdev, ®); - if (ret) - return ret; - - s5m_reg_read(s5m8767->iodev, reg, &val); - val &= ~mask; - val |= sel; - - ret = s5m_reg_write(s5m8767->iodev, reg, val); - *selector = sel; - - return ret; -} - -static inline void s5m8767_set_high(struct s5m8767_info *s5m8767) -{ - int temp_index = s5m8767->buck_gpioindex; - - gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1); - gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1); - gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1); -} - -static inline void s5m8767_set_low(struct s5m8767_info *s5m8767) -{ - int temp_index = s5m8767->buck_gpioindex; - - gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1); - gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1); - gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1); -} - -static int s5m8767_set_voltage_buck(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned *selector) -{ - struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); - int reg_id = rdev_get_id(rdev); - const struct s5m_voltage_desc *desc; - int new_val, old_val, i = 0; - - if (reg_id < S5M8767_BUCK1 || reg_id > S5M8767_BUCK6) - return -EINVAL; - - switch (reg_id) { - case S5M8767_BUCK1: - return s5m8767_set_voltage(rdev, min_uV, max_uV, selector); - case S5M8767_BUCK2 ... S5M8767_BUCK4: - break; - case S5M8767_BUCK5 ... S5M8767_BUCK6: - return s5m8767_set_voltage(rdev, min_uV, max_uV, selector); - case S5M8767_BUCK9: - return s5m8767_set_voltage(rdev, min_uV, max_uV, selector); - } + /* buck234_vol != NULL means to control buck234 voltage via DVS GPIO */ + if (buck234_vol) { + while (*buck234_vol != sel) { + buck234_vol++; + index++; + } + old_index = s5m8767->buck_gpioindex; + s5m8767->buck_gpioindex = index; + + if (index > old_index) + s5m8767_set_high(s5m8767); + else + s5m8767_set_low(s5m8767); + } else { + ret = s5m8767_get_voltage_register(rdev, ®); + if (ret) + return ret; - desc = reg_voltage_map[reg_id]; - new_val = s5m8767_convert_voltage_to_sel(desc, min_uV, max_uV); - if (new_val < 0) - return new_val; + s5m_reg_read(s5m8767->iodev, reg, &val); + val = (val & ~mask) | sel; - switch (reg_id) { - case S5M8767_BUCK2: - if (s5m8767->buck2_gpiodvs) { - while (s5m8767->buck2_vol[i] != new_val) - i++; - } else - return s5m8767_set_voltage(rdev, min_uV, - max_uV, selector); - break; - case S5M8767_BUCK3: - if (s5m8767->buck3_gpiodvs) { - while (s5m8767->buck3_vol[i] != new_val) - i++; - } else - return s5m8767_set_voltage(rdev, min_uV, - max_uV, selector); - break; - case S5M8767_BUCK4: - if (s5m8767->buck3_gpiodvs) { - while (s5m8767->buck4_vol[i] != new_val) - i++; - } else - return s5m8767_set_voltage(rdev, min_uV, - max_uV, selector); - break; + ret = s5m_reg_write(s5m8767->iodev, reg, val); } - old_val = s5m8767->buck_gpioindex; - s5m8767->buck_gpioindex = i; - - if (i > old_val) - s5m8767_set_high(s5m8767); - else - s5m8767_set_low(s5m8767); - - *selector = new_val; - return 0; + *selector = sel; + return ret; } static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev, @@ -450,7 +457,7 @@ static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev, return 0; } -static struct regulator_ops s5m8767_ldo_ops = { +static struct regulator_ops s5m8767_ops = { .list_voltage = s5m8767_list_voltage, .is_enabled = s5m8767_reg_is_enabled, .enable = s5m8767_reg_enable, @@ -460,75 +467,59 @@ static struct regulator_ops s5m8767_ldo_ops = { .set_voltage_time_sel = s5m8767_set_voltage_time_sel, }; -static struct regulator_ops s5m8767_buck_ops = { - .list_voltage = s5m8767_list_voltage, - .is_enabled = s5m8767_reg_is_enabled, - .enable = s5m8767_reg_enable, - .disable = s5m8767_reg_disable, - .get_voltage_sel = s5m8767_get_voltage_sel, - .set_voltage = s5m8767_set_voltage_buck, - .set_voltage_time_sel = s5m8767_set_voltage_time_sel, -}; - -#define regulator_desc_ldo(num) { \ - .name = "LDO"#num, \ - .id = S5M8767_LDO##num, \ - .ops = &s5m8767_ldo_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ -} -#define regulator_desc_buck(num) { \ - .name = "BUCK"#num, \ - .id = S5M8767_BUCK##num, \ - .ops = &s5m8767_buck_ops, \ +#define s5m8767_regulator_desc(_name) { \ + .name = #_name, \ + .id = S5M8767_##_name, \ + .ops = &s5m8767_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ } static struct regulator_desc regulators[] = { - regulator_desc_ldo(1), - regulator_desc_ldo(2), - regulator_desc_ldo(3), - regulator_desc_ldo(4), - regulator_desc_ldo(5), - regulator_desc_ldo(6), - regulator_desc_ldo(7), - regulator_desc_ldo(8), - regulator_desc_ldo(9), - regulator_desc_ldo(10), - regulator_desc_ldo(11), - regulator_desc_ldo(12), - regulator_desc_ldo(13), - regulator_desc_ldo(14), - regulator_desc_ldo(15), - regulator_desc_ldo(16), - regulator_desc_ldo(17), - regulator_desc_ldo(18), - regulator_desc_ldo(19), - regulator_desc_ldo(20), - regulator_desc_ldo(21), - regulator_desc_ldo(22), - regulator_desc_ldo(23), - regulator_desc_ldo(24), - regulator_desc_ldo(25), - regulator_desc_ldo(26), - regulator_desc_ldo(27), - regulator_desc_ldo(28), - regulator_desc_buck(1), - regulator_desc_buck(2), - regulator_desc_buck(3), - regulator_desc_buck(4), - regulator_desc_buck(5), - regulator_desc_buck(6), - regulator_desc_buck(7), - regulator_desc_buck(8), - regulator_desc_buck(9), + s5m8767_regulator_desc(LDO1), + s5m8767_regulator_desc(LDO2), + s5m8767_regulator_desc(LDO3), + s5m8767_regulator_desc(LDO4), + s5m8767_regulator_desc(LDO5), + s5m8767_regulator_desc(LDO6), + s5m8767_regulator_desc(LDO7), + s5m8767_regulator_desc(LDO8), + s5m8767_regulator_desc(LDO9), + s5m8767_regulator_desc(LDO10), + s5m8767_regulator_desc(LDO11), + s5m8767_regulator_desc(LDO12), + s5m8767_regulator_desc(LDO13), + s5m8767_regulator_desc(LDO14), + s5m8767_regulator_desc(LDO15), + s5m8767_regulator_desc(LDO16), + s5m8767_regulator_desc(LDO17), + s5m8767_regulator_desc(LDO18), + s5m8767_regulator_desc(LDO19), + s5m8767_regulator_desc(LDO20), + s5m8767_regulator_desc(LDO21), + s5m8767_regulator_desc(LDO22), + s5m8767_regulator_desc(LDO23), + s5m8767_regulator_desc(LDO24), + s5m8767_regulator_desc(LDO25), + s5m8767_regulator_desc(LDO26), + s5m8767_regulator_desc(LDO27), + s5m8767_regulator_desc(LDO28), + s5m8767_regulator_desc(BUCK1), + s5m8767_regulator_desc(BUCK2), + s5m8767_regulator_desc(BUCK3), + s5m8767_regulator_desc(BUCK4), + s5m8767_regulator_desc(BUCK5), + s5m8767_regulator_desc(BUCK6), + s5m8767_regulator_desc(BUCK7), + s5m8767_regulator_desc(BUCK8), + s5m8767_regulator_desc(BUCK9), }; static __devinit int s5m8767_pmic_probe(struct platform_device *pdev) { struct s5m87xx_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct s5m_platform_data *pdata = dev_get_platdata(iodev->dev); + struct regulator_config config = { }; struct regulator_dev **rdev; struct s5m8767_info *s5m8767; int i, ret, size; @@ -586,6 +577,7 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev) s5m8767->buck2_ramp = pdata->buck2_ramp_enable; s5m8767->buck3_ramp = pdata->buck3_ramp_enable; s5m8767->buck4_ramp = pdata->buck4_ramp_enable; + s5m8767->opmode = pdata->opmode; for (i = 0; i < 8; i++) { if (s5m8767->buck2_gpiodvs) { @@ -723,8 +715,11 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev) regulators[id].n_voltages = (desc->max - desc->min) / desc->step + 1; - rdev[i] = regulator_register(®ulators[id], s5m8767->dev, - pdata->regulators[i].initdata, s5m8767, NULL); + config.dev = s5m8767->dev; + config.init_data = pdata->regulators[i].initdata; + config.driver_data = s5m8767; + + rdev[i] = regulator_register(®ulators[id], &config); if (IS_ERR(rdev[i])) { ret = PTR_ERR(rdev[i]); dev_err(s5m8767->dev, "regulator init failed for %d\n", diff --git a/trunk/drivers/regulator/tps6105x-regulator.c b/trunk/drivers/regulator/tps6105x-regulator.c index d9278da18a9e..d840d8440a91 100644 --- a/trunk/drivers/regulator/tps6105x-regulator.c +++ b/trunk/drivers/regulator/tps6105x-regulator.c @@ -123,7 +123,7 @@ static struct regulator_ops tps6105x_regulator_ops = { .list_voltage = tps6105x_regulator_list_voltage, }; -static struct regulator_desc tps6105x_regulator_desc = { +static const struct regulator_desc tps6105x_regulator_desc = { .name = "tps6105x-boost", .ops = &tps6105x_regulator_ops, .type = REGULATOR_VOLTAGE, @@ -139,6 +139,7 @@ static int __devinit tps6105x_regulator_probe(struct platform_device *pdev) { struct tps6105x *tps6105x = dev_get_platdata(&pdev->dev); struct tps6105x_platform_data *pdata = tps6105x->pdata; + struct regulator_config config = { }; int ret; /* This instance is not set for regulator mode so bail out */ @@ -148,11 +149,13 @@ static int __devinit tps6105x_regulator_probe(struct platform_device *pdev) return 0; } + config.dev = &tps6105x->client->dev; + config.init_data = pdata->regulator_data; + config.driver_data = tps6105x; + /* Register regulator with framework */ tps6105x->regulator = regulator_register(&tps6105x_regulator_desc, - &tps6105x->client->dev, - pdata->regulator_data, tps6105x, - NULL); + &config); if (IS_ERR(tps6105x->regulator)) { ret = PTR_ERR(tps6105x->regulator); dev_err(&tps6105x->client->dev, diff --git a/trunk/drivers/regulator/tps62360-regulator.c b/trunk/drivers/regulator/tps62360-regulator.c index e2ec73068ee2..e534269ed44a 100644 --- a/trunk/drivers/regulator/tps62360-regulator.c +++ b/trunk/drivers/regulator/tps62360-regulator.c @@ -1,7 +1,7 @@ /* * tps62360.c -- TI tps62360 * - * Driver for processor core supply tps62360 and tps62361B + * Driver for processor core supply tps62360, tps62361B, tps62362 and tps62363. * * Copyright (c) 2012, NVIDIA Corporation. * @@ -26,13 +26,16 @@ #include #include #include +#include +#include +#include +#include #include #include #include #include #include #include -#include #include #include @@ -46,20 +49,20 @@ #define REG_RAMPCTRL 6 #define REG_CHIPID 8 -enum chips {TPS62360, TPS62361}; +#define FORCE_PWM_ENABLE BIT(7) -#define TPS62360_BASE_VOLTAGE 770 +enum chips {TPS62360, TPS62361, TPS62362, TPS62363}; + +#define TPS62360_BASE_VOLTAGE 770000 #define TPS62360_N_VOLTAGES 64 -#define TPS62361_BASE_VOLTAGE 500 +#define TPS62361_BASE_VOLTAGE 500000 #define TPS62361_N_VOLTAGES 128 /* tps 62360 chip information */ struct tps62360_chip { - const char *name; struct device *dev; struct regulator_desc desc; - struct i2c_client *client; struct regulator_dev *rdev; struct regmap *regmap; int chip_id; @@ -68,12 +71,12 @@ struct tps62360_chip { int voltage_base; u8 voltage_reg_mask; bool en_internal_pulldn; - bool en_force_pwm; bool en_discharge; bool valid_gpios; int lru_index[4]; int curr_vset_vsel[4]; int curr_vset_id; + int change_uv_per_us; }; /* @@ -99,6 +102,7 @@ static bool find_voltage_set_register(struct tps62360_chip *tps, bool found = false; int new_vset_reg = tps->lru_index[3]; int found_index = 3; + for (i = 0; i < 4; ++i) { if (tps->curr_vset_vsel[tps->lru_index[i]] == req_vsel) { new_vset_reg = tps->lru_index[i]; @@ -117,7 +121,7 @@ static bool find_voltage_set_register(struct tps62360_chip *tps, return found; } -static int tps62360_dcdc_get_voltage(struct regulator_dev *dev) +static int tps62360_dcdc_get_voltage_sel(struct regulator_dev *dev) { struct tps62360_chip *tps = rdev_get_drvdata(dev); int vsel; @@ -126,196 +130,312 @@ static int tps62360_dcdc_get_voltage(struct regulator_dev *dev) ret = regmap_read(tps->regmap, REG_VSET0 + tps->curr_vset_id, &data); if (ret < 0) { - dev_err(tps->dev, "%s: Error in reading register %d\n", - __func__, REG_VSET0 + tps->curr_vset_id); + dev_err(tps->dev, "%s(): register %d read failed with err %d\n", + __func__, REG_VSET0 + tps->curr_vset_id, ret); return ret; } vsel = (int)data & tps->voltage_reg_mask; - return (tps->voltage_base + vsel * 10) * 1000; + return vsel; } -static int tps62360_dcdc_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV, unsigned *selector) +static int tps62360_dcdc_set_voltage_sel(struct regulator_dev *dev, + unsigned selector) { struct tps62360_chip *tps = rdev_get_drvdata(dev); - int vsel; int ret; bool found = false; int new_vset_id = tps->curr_vset_id; - if (max_uV < min_uV) - return -EINVAL; - - if (min_uV > - ((tps->voltage_base + (tps->desc.n_voltages - 1) * 10) * 1000)) - return -EINVAL; - - if (max_uV < tps->voltage_base * 1000) - return -EINVAL; - - vsel = DIV_ROUND_UP(min_uV - (tps->voltage_base * 1000), 10000); - if (selector) - *selector = (vsel & tps->voltage_reg_mask); - /* * If gpios are available to select the VSET register then least * recently used register for new configuration. */ if (tps->valid_gpios) - found = find_voltage_set_register(tps, vsel, &new_vset_id); + found = find_voltage_set_register(tps, selector, &new_vset_id); if (!found) { ret = regmap_update_bits(tps->regmap, REG_VSET0 + new_vset_id, - tps->voltage_reg_mask, vsel); + tps->voltage_reg_mask, selector); if (ret < 0) { - dev_err(tps->dev, "%s: Error in updating register %d\n", - __func__, REG_VSET0 + new_vset_id); + dev_err(tps->dev, + "%s(): register %d update failed with err %d\n", + __func__, REG_VSET0 + new_vset_id, ret); return ret; } tps->curr_vset_id = new_vset_id; - tps->curr_vset_vsel[new_vset_id] = vsel; + tps->curr_vset_vsel[new_vset_id] = selector; } /* Select proper VSET register vio gpios */ if (tps->valid_gpios) { - gpio_set_value_cansleep(tps->vsel0_gpio, - new_vset_id & 0x1); + gpio_set_value_cansleep(tps->vsel0_gpio, new_vset_id & 0x1); gpio_set_value_cansleep(tps->vsel1_gpio, (new_vset_id >> 1) & 0x1); } return 0; } -static int tps62360_dcdc_list_voltage(struct regulator_dev *dev, - unsigned selector) +static int tps62360_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int old_selector, unsigned int new_selector) { - struct tps62360_chip *tps = rdev_get_drvdata(dev); + struct tps62360_chip *tps = rdev_get_drvdata(rdev); + int old_uV, new_uV; - if (selector >= tps->desc.n_voltages) - return -EINVAL; - return (tps->voltage_base + selector * 10) * 1000; + old_uV = regulator_list_voltage_linear(rdev, old_selector); + if (old_uV < 0) + return old_uV; + + new_uV = regulator_list_voltage_linear(rdev, new_selector); + if (new_uV < 0) + return new_uV; + + return DIV_ROUND_UP(abs(old_uV - new_uV), tps->change_uv_per_us); } -static struct regulator_ops tps62360_dcdc_ops = { - .get_voltage = tps62360_dcdc_get_voltage, - .set_voltage = tps62360_dcdc_set_voltage, - .list_voltage = tps62360_dcdc_list_voltage, -}; +static int tps62360_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + struct tps62360_chip *tps = rdev_get_drvdata(rdev); + int i; + int val; + int ret; + + /* Enable force PWM mode in FAST mode only. */ + switch (mode) { + case REGULATOR_MODE_FAST: + val = FORCE_PWM_ENABLE; + break; + + case REGULATOR_MODE_NORMAL: + val = 0; + break; -static int tps62360_init_force_pwm(struct tps62360_chip *tps, - struct tps62360_regulator_platform_data *pdata, - int vset_id) + default: + return -EINVAL; + } + + if (!tps->valid_gpios) { + ret = regmap_update_bits(tps->regmap, + REG_VSET0 + tps->curr_vset_id, FORCE_PWM_ENABLE, val); + if (ret < 0) + dev_err(tps->dev, + "%s(): register %d update failed with err %d\n", + __func__, REG_VSET0 + tps->curr_vset_id, ret); + return ret; + } + + /* If gpios are valid then all register set need to be control */ + for (i = 0; i < 4; ++i) { + ret = regmap_update_bits(tps->regmap, + REG_VSET0 + i, FORCE_PWM_ENABLE, val); + if (ret < 0) { + dev_err(tps->dev, + "%s(): register %d update failed with err %d\n", + __func__, REG_VSET0 + i, ret); + return ret; + } + } + return ret; +} + +static unsigned int tps62360_get_mode(struct regulator_dev *rdev) { + struct tps62360_chip *tps = rdev_get_drvdata(rdev); unsigned int data; int ret; - ret = regmap_read(tps->regmap, REG_VSET0 + vset_id, &data); + + ret = regmap_read(tps->regmap, REG_VSET0 + tps->curr_vset_id, &data); if (ret < 0) { - dev_err(tps->dev, "%s() fails in writing reg %d\n", - __func__, REG_VSET0 + vset_id); + dev_err(tps->dev, "%s(): register %d read failed with err %d\n", + __func__, REG_VSET0 + tps->curr_vset_id, ret); return ret; } - tps->curr_vset_vsel[vset_id] = data & tps->voltage_reg_mask; - if (pdata->en_force_pwm) - data |= BIT(7); - else - data &= ~BIT(7); - ret = regmap_write(tps->regmap, REG_VSET0 + vset_id, data); - if (ret < 0) - dev_err(tps->dev, "%s() fails in writing reg %d\n", - __func__, REG_VSET0 + vset_id); - return ret; + return (data & FORCE_PWM_ENABLE) ? + REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL; } -static int tps62360_init_dcdc(struct tps62360_chip *tps, +static struct regulator_ops tps62360_dcdc_ops = { + .get_voltage_sel = tps62360_dcdc_get_voltage_sel, + .set_voltage_sel = tps62360_dcdc_set_voltage_sel, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .set_voltage_time_sel = tps62360_set_voltage_time_sel, + .set_mode = tps62360_set_mode, + .get_mode = tps62360_get_mode, +}; + +static int __devinit tps62360_init_dcdc(struct tps62360_chip *tps, struct tps62360_regulator_platform_data *pdata) { int ret; - int i; + unsigned int ramp_ctrl; - /* Initailize internal pull up/down control */ + /* Initialize internal pull up/down control */ if (tps->en_internal_pulldn) ret = regmap_write(tps->regmap, REG_CONTROL, 0xE0); else ret = regmap_write(tps->regmap, REG_CONTROL, 0x0); if (ret < 0) { - dev_err(tps->dev, "%s() fails in writing reg %d\n", - __func__, REG_CONTROL); + dev_err(tps->dev, + "%s(): register %d write failed with err %d\n", + __func__, REG_CONTROL, ret); return ret; } - /* Initailize force PWM mode */ - if (tps->valid_gpios) { - for (i = 0; i < 4; ++i) { - ret = tps62360_init_force_pwm(tps, pdata, i); - if (ret < 0) - return ret; - } - } else { - ret = tps62360_init_force_pwm(tps, pdata, tps->curr_vset_id); - if (ret < 0) - return ret; - } - /* Reset output discharge path to reduce power consumption */ ret = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), 0); - if (ret < 0) - dev_err(tps->dev, "%s() fails in updating reg %d\n", - __func__, REG_RAMPCTRL); + if (ret < 0) { + dev_err(tps->dev, + "%s(): register %d update failed with err %d\n", + __func__, REG_RAMPCTRL, ret); + return ret; + } + + /* Get ramp value from ramp control register */ + ret = regmap_read(tps->regmap, REG_RAMPCTRL, &ramp_ctrl); + if (ret < 0) { + dev_err(tps->dev, + "%s(): register %d read failed with err %d\n", + __func__, REG_RAMPCTRL, ret); + return ret; + } + ramp_ctrl = (ramp_ctrl >> 4) & 0x7; + + /* ramp mV/us = 32/(2^ramp_ctrl) */ + tps->change_uv_per_us = DIV_ROUND_UP(32000, BIT(ramp_ctrl)); return ret; } static const struct regmap_config tps62360_regmap_config = { - .reg_bits = 8, - .val_bits = 8, + .reg_bits = 8, + .val_bits = 8, + .max_register = REG_CHIPID, + .cache_type = REGCACHE_RBTREE, }; +static struct tps62360_regulator_platform_data * + of_get_tps62360_platform_data(struct device *dev) +{ + struct tps62360_regulator_platform_data *pdata; + struct device_node *np = dev->of_node; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(dev, "Memory alloc failed for platform data\n"); + return NULL; + } + + pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node); + if (!pdata->reg_init_data) { + dev_err(dev, "Not able to get OF regulator init data\n"); + return NULL; + } + + pdata->vsel0_gpio = of_get_named_gpio(np, "vsel0-gpio", 0); + pdata->vsel1_gpio = of_get_named_gpio(np, "vsel1-gpio", 0); + + if (of_find_property(np, "ti,vsel0-state-high", NULL)) + pdata->vsel0_def_state = 1; + + if (of_find_property(np, "ti,vsel1-state-high", NULL)) + pdata->vsel1_def_state = 1; + + if (of_find_property(np, "ti,enable-pull-down", NULL)) + pdata->en_internal_pulldn = true; + + if (of_find_property(np, "ti,enable-vout-discharge", NULL)) + pdata->en_discharge = true; + + return pdata; +} + +#if defined(CONFIG_OF) +static const struct of_device_id tps62360_of_match[] = { + { .compatible = "ti,tps62360", .data = (void *)TPS62360}, + { .compatible = "ti,tps62361", .data = (void *)TPS62361}, + { .compatible = "ti,tps62362", .data = (void *)TPS62362}, + { .compatible = "ti,tps62363", .data = (void *)TPS62363}, + {}, +}; +MODULE_DEVICE_TABLE(of, tps62360_of_match); +#endif + static int __devinit tps62360_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct regulator_config config = { }; struct tps62360_regulator_platform_data *pdata; struct regulator_dev *rdev; struct tps62360_chip *tps; int ret; int i; + int chip_id; pdata = client->dev.platform_data; + chip_id = id->driver_data; + + if (client->dev.of_node) { + const struct of_device_id *match; + match = of_match_device(of_match_ptr(tps62360_of_match), + &client->dev); + if (!match) { + dev_err(&client->dev, "Error: No device match found\n"); + return -ENODEV; + } + chip_id = (int)match->data; + if (!pdata) + pdata = of_get_tps62360_platform_data(&client->dev); + } + if (!pdata) { - dev_err(&client->dev, "%s() Err: Platform data not found\n", + dev_err(&client->dev, "%s(): Platform data not found\n", __func__); return -EIO; } tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); if (!tps) { - dev_err(&client->dev, "%s() Err: Memory allocation fails\n", + dev_err(&client->dev, "%s(): Memory allocation failed\n", __func__); return -ENOMEM; } - tps->en_force_pwm = pdata->en_force_pwm; tps->en_discharge = pdata->en_discharge; tps->en_internal_pulldn = pdata->en_internal_pulldn; tps->vsel0_gpio = pdata->vsel0_gpio; tps->vsel1_gpio = pdata->vsel1_gpio; - tps->client = client; tps->dev = &client->dev; - tps->name = id->name; - tps->voltage_base = (id->driver_data == TPS62360) ? - TPS62360_BASE_VOLTAGE : TPS62361_BASE_VOLTAGE; - tps->voltage_reg_mask = (id->driver_data == TPS62360) ? 0x3F : 0x7F; + + switch (chip_id) { + case TPS62360: + case TPS62362: + tps->voltage_base = TPS62360_BASE_VOLTAGE; + tps->voltage_reg_mask = 0x3F; + tps->desc.n_voltages = TPS62360_N_VOLTAGES; + break; + case TPS62361: + case TPS62363: + tps->voltage_base = TPS62361_BASE_VOLTAGE; + tps->voltage_reg_mask = 0x7F; + tps->desc.n_voltages = TPS62361_N_VOLTAGES; + break; + default: + return -ENODEV; + } tps->desc.name = id->name; tps->desc.id = 0; - tps->desc.n_voltages = (id->driver_data == TPS62360) ? - TPS62360_N_VOLTAGES : TPS62361_N_VOLTAGES; tps->desc.ops = &tps62360_dcdc_ops; tps->desc.type = REGULATOR_VOLTAGE; tps->desc.owner = THIS_MODULE; - tps->regmap = regmap_init_i2c(client, &tps62360_regmap_config); + tps->desc.min_uV = tps->voltage_base; + tps->desc.uV_step = 10000; + + tps->regmap = devm_regmap_init_i2c(client, &tps62360_regmap_config); if (IS_ERR(tps->regmap)) { ret = PTR_ERR(tps->regmap); - dev_err(&client->dev, "%s() Err: Failed to allocate register" - "map: %d\n", __func__, ret); + dev_err(&client->dev, + "%s(): regmap allocation failed with err %d\n", + __func__, ret); return ret; } i2c_set_clientdata(client, tps); @@ -326,35 +446,26 @@ static int __devinit tps62360_probe(struct i2c_client *client, tps->valid_gpios = false; if (gpio_is_valid(tps->vsel0_gpio) && gpio_is_valid(tps->vsel1_gpio)) { - ret = gpio_request(tps->vsel0_gpio, "tps62360-vsel0"); + int gpio_flags; + gpio_flags = (pdata->vsel0_def_state) ? + GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; + ret = gpio_request_one(tps->vsel0_gpio, + gpio_flags, "tps62360-vsel0"); if (ret) { dev_err(&client->dev, - "Err: Could not obtain vsel0 GPIO %d: %d\n", - tps->vsel0_gpio, ret); - goto err_gpio0; - } - ret = gpio_direction_output(tps->vsel0_gpio, - pdata->vsel0_def_state); - if (ret) { - dev_err(&client->dev, "Err: Could not set direction of" - "vsel0 GPIO %d: %d\n", tps->vsel0_gpio, ret); - gpio_free(tps->vsel0_gpio); + "%s(): Could not obtain vsel0 GPIO %d: %d\n", + __func__, tps->vsel0_gpio, ret); goto err_gpio0; } - ret = gpio_request(tps->vsel1_gpio, "tps62360-vsel1"); + gpio_flags = (pdata->vsel1_def_state) ? + GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; + ret = gpio_request_one(tps->vsel1_gpio, + gpio_flags, "tps62360-vsel1"); if (ret) { dev_err(&client->dev, - "Err: Could not obtain vsel1 GPIO %d: %d\n", - tps->vsel1_gpio, ret); - goto err_gpio1; - } - ret = gpio_direction_output(tps->vsel1_gpio, - pdata->vsel1_def_state); - if (ret) { - dev_err(&client->dev, "Err: Could not set direction of" - "vsel1 GPIO %d: %d\n", tps->vsel1_gpio, ret); - gpio_free(tps->vsel1_gpio); + "%s(): Could not obtain vsel1 GPIO %d: %d\n", + __func__, tps->vsel1_gpio, ret); goto err_gpio1; } tps->valid_gpios = true; @@ -371,17 +482,22 @@ static int __devinit tps62360_probe(struct i2c_client *client, ret = tps62360_init_dcdc(tps, pdata); if (ret < 0) { - dev_err(tps->dev, "%s() Err: Init fails with = %d\n", + dev_err(tps->dev, "%s(): Init failed with err = %d\n", __func__, ret); goto err_init; } + config.dev = &client->dev; + config.init_data = pdata->reg_init_data; + config.driver_data = tps; + config.of_node = client->dev.of_node; + /* Register the regulators */ - rdev = regulator_register(&tps->desc, &client->dev, - &pdata->reg_init_data, tps, NULL); + rdev = regulator_register(&tps->desc, &config); if (IS_ERR(rdev)) { - dev_err(tps->dev, "%s() Err: Failed to register %s\n", - __func__, id->name); + dev_err(tps->dev, + "%s(): regulator register failed with err %s\n", + __func__, id->name); ret = PTR_ERR(rdev); goto err_init; } @@ -396,7 +512,6 @@ static int __devinit tps62360_probe(struct i2c_client *client, if (gpio_is_valid(tps->vsel0_gpio)) gpio_free(tps->vsel0_gpio); err_gpio0: - regmap_exit(tps->regmap); return ret; } @@ -417,7 +532,6 @@ static int __devexit tps62360_remove(struct i2c_client *client) gpio_free(tps->vsel0_gpio); regulator_unregister(tps->rdev); - regmap_exit(tps->regmap); return 0; } @@ -432,13 +546,16 @@ static void tps62360_shutdown(struct i2c_client *client) /* Configure the output discharge path */ st = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), BIT(2)); if (st < 0) - dev_err(tps->dev, "%s() fails in updating reg %d\n", - __func__, REG_RAMPCTRL); + dev_err(tps->dev, + "%s(): register %d update failed with err %d\n", + __func__, REG_RAMPCTRL, st); } static const struct i2c_device_id tps62360_id[] = { {.name = "tps62360", .driver_data = TPS62360}, {.name = "tps62361", .driver_data = TPS62361}, + {.name = "tps62362", .driver_data = TPS62362}, + {.name = "tps62363", .driver_data = TPS62363}, {}, }; @@ -448,6 +565,7 @@ static struct i2c_driver tps62360_i2c_driver = { .driver = { .name = "tps62360", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(tps62360_of_match), }, .probe = tps62360_probe, .remove = __devexit_p(tps62360_remove), @@ -468,5 +586,5 @@ static void __exit tps62360_cleanup(void) module_exit(tps62360_cleanup); MODULE_AUTHOR("Laxman Dewangan "); -MODULE_DESCRIPTION("TPS62360 voltage regulator driver"); +MODULE_DESCRIPTION("TPS6236x voltage regulator driver"); MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/regulator/tps65023-regulator.c b/trunk/drivers/regulator/tps65023-regulator.c index 43e4902d7af8..f841bd0db6aa 100644 --- a/trunk/drivers/regulator/tps65023-regulator.c +++ b/trunk/drivers/regulator/tps65023-regulator.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -72,7 +71,7 @@ /* LDO_CTRL bitfields */ #define TPS65023_LDO_CTRL_LDOx_SHIFT(ldo_id) ((ldo_id)*4) -#define TPS65023_LDO_CTRL_LDOx_MASK(ldo_id) (0xF0 >> ((ldo_id)*4)) +#define TPS65023_LDO_CTRL_LDOx_MASK(ldo_id) (0x0F << ((ldo_id)*4)) /* Number of step-down converters available */ #define TPS65023_NUM_DCDC 3 @@ -139,7 +138,6 @@ struct tps_info { /* PMIC details */ struct tps_pmic { struct regulator_desc desc[TPS65023_NUM_REGULATOR]; - struct i2c_client *client; struct regulator_dev *rdev[TPS65023_NUM_REGULATOR]; const struct tps_info *info[TPS65023_NUM_REGULATOR]; struct regmap *regmap; @@ -152,96 +150,6 @@ struct tps_driver_data { u8 core_regulator; }; -static int tps65023_dcdc_is_enabled(struct regulator_dev *dev) -{ - struct tps_pmic *tps = rdev_get_drvdata(dev); - int data, dcdc = rdev_get_id(dev); - int ret; - u8 shift; - - if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3) - return -EINVAL; - - shift = TPS65023_NUM_REGULATOR - dcdc; - ret = regmap_read(tps->regmap, TPS65023_REG_REG_CTRL, &data); - - if (ret != 0) - return ret; - else - return (data & 1< TPS65023_LDO_2) - return -EINVAL; - - shift = (ldo == TPS65023_LDO_1 ? 1 : 2); - ret = regmap_read(tps->regmap, TPS65023_REG_REG_CTRL, &data); - - if (ret != 0) - return ret; - else - return (data & 1< TPS65023_DCDC_3) - return -EINVAL; - - shift = TPS65023_NUM_REGULATOR - dcdc; - return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 1 << shift); -} - -static int tps65023_dcdc_disable(struct regulator_dev *dev) -{ - struct tps_pmic *tps = rdev_get_drvdata(dev); - int dcdc = rdev_get_id(dev); - u8 shift; - - if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3) - return -EINVAL; - - shift = TPS65023_NUM_REGULATOR - dcdc; - return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 0); -} - -static int tps65023_ldo_enable(struct regulator_dev *dev) -{ - struct tps_pmic *tps = rdev_get_drvdata(dev); - int ldo = rdev_get_id(dev); - u8 shift; - - if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2) - return -EINVAL; - - shift = (ldo == TPS65023_LDO_1 ? 1 : 2); - return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 1 << shift); -} - -static int tps65023_ldo_disable(struct regulator_dev *dev) -{ - struct tps_pmic *tps = rdev_get_drvdata(dev); - int ldo = rdev_get_id(dev); - u8 shift; - - if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2) - return -EINVAL; - - shift = (ldo == TPS65023_LDO_1 ? 1 : 2); - return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 0); -} - static int tps65023_dcdc_get_voltage(struct regulator_dev *dev) { struct tps_pmic *tps = rdev_get_drvdata(dev); @@ -261,50 +169,28 @@ static int tps65023_dcdc_get_voltage(struct regulator_dev *dev) return tps->info[dcdc]->min_uV; } -static int tps65023_dcdc_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV, - unsigned *selector) +static int tps65023_dcdc_set_voltage_sel(struct regulator_dev *dev, + unsigned selector) { struct tps_pmic *tps = rdev_get_drvdata(dev); int dcdc = rdev_get_id(dev); - int vsel; int ret; if (dcdc != tps->core_regulator) return -EINVAL; - if (min_uV < tps->info[dcdc]->min_uV - || min_uV > tps->info[dcdc]->max_uV) - return -EINVAL; - if (max_uV < tps->info[dcdc]->min_uV - || max_uV > tps->info[dcdc]->max_uV) - return -EINVAL; - - for (vsel = 0; vsel < tps->info[dcdc]->table_len; vsel++) { - int mV = tps->info[dcdc]->table[vsel]; - int uV = mV * 1000; - - /* Break at the first in-range value */ - if (min_uV <= uV && uV <= max_uV) - break; - } - *selector = vsel; - - if (vsel == tps->info[dcdc]->table_len) - goto failed; - - ret = regmap_write(tps->regmap, TPS65023_REG_DEF_CORE, vsel); + ret = regmap_write(tps->regmap, TPS65023_REG_DEF_CORE, selector); + if (ret) + goto out; /* Tell the chip that we have changed the value in DEFCORE * and its time to update the core voltage */ - regmap_update_bits(tps->regmap, TPS65023_REG_CON_CTRL2, - TPS65023_REG_CTRL2_GO, TPS65023_REG_CTRL2_GO); + ret = regmap_update_bits(tps->regmap, TPS65023_REG_CON_CTRL2, + TPS65023_REG_CTRL2_GO, TPS65023_REG_CTRL2_GO); +out: return ret; - -failed: - return -EINVAL; } static int tps65023_ldo_get_voltage(struct regulator_dev *dev) @@ -325,42 +211,15 @@ static int tps65023_ldo_get_voltage(struct regulator_dev *dev) return tps->info[ldo]->table[data] * 1000; } -static int tps65023_ldo_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV, unsigned *selector) +static int tps65023_ldo_set_voltage_sel(struct regulator_dev *dev, + unsigned selector) { struct tps_pmic *tps = rdev_get_drvdata(dev); - int data, vsel, ldo = rdev_get_id(dev); - int ret; - - if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2) - return -EINVAL; + int ldo_index = rdev_get_id(dev) - TPS65023_LDO_1; - if (min_uV < tps->info[ldo]->min_uV || min_uV > tps->info[ldo]->max_uV) - return -EINVAL; - if (max_uV < tps->info[ldo]->min_uV || max_uV > tps->info[ldo]->max_uV) - return -EINVAL; - - for (vsel = 0; vsel < tps->info[ldo]->table_len; vsel++) { - int mV = tps->info[ldo]->table[vsel]; - int uV = mV * 1000; - - /* Break at the first in-range value */ - if (min_uV <= uV && uV <= max_uV) - break; - } - - if (vsel == tps->info[ldo]->table_len) - return -EINVAL; - - *selector = vsel; - - ret = regmap_read(tps->regmap, TPS65023_REG_LDO_CTRL, &data); - if (ret != 0) - return ret; - - data &= TPS65023_LDO_CTRL_LDOx_MASK(ldo - TPS65023_LDO_1); - data |= (vsel << (TPS65023_LDO_CTRL_LDOx_SHIFT(ldo - TPS65023_LDO_1))); - return regmap_write(tps->regmap, TPS65023_REG_LDO_CTRL, data); + return regmap_update_bits(tps->regmap, TPS65023_REG_LDO_CTRL, + TPS65023_LDO_CTRL_LDOx_MASK(ldo_index), + selector << TPS65023_LDO_CTRL_LDOx_SHIFT(ldo_index)); } static int tps65023_dcdc_list_voltage(struct regulator_dev *dev, @@ -398,21 +257,21 @@ static int tps65023_ldo_list_voltage(struct regulator_dev *dev, /* Operations permitted on VDCDCx */ static struct regulator_ops tps65023_dcdc_ops = { - .is_enabled = tps65023_dcdc_is_enabled, - .enable = tps65023_dcdc_enable, - .disable = tps65023_dcdc_disable, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, .get_voltage = tps65023_dcdc_get_voltage, - .set_voltage = tps65023_dcdc_set_voltage, + .set_voltage_sel = tps65023_dcdc_set_voltage_sel, .list_voltage = tps65023_dcdc_list_voltage, }; /* Operations permitted on LDOx */ static struct regulator_ops tps65023_ldo_ops = { - .is_enabled = tps65023_ldo_is_enabled, - .enable = tps65023_ldo_enable, - .disable = tps65023_ldo_disable, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, .get_voltage = tps65023_ldo_get_voltage, - .set_voltage = tps65023_ldo_set_voltage, + .set_voltage_sel = tps65023_ldo_set_voltage_sel, .list_voltage = tps65023_ldo_list_voltage, }; @@ -426,6 +285,7 @@ static int __devinit tps_65023_probe(struct i2c_client *client, { const struct tps_driver_data *drv_data = (void *)id->driver_data; const struct tps_info *info = drv_data->info; + struct regulator_config config = { }; struct regulator_init_data *init_data; struct regulator_dev *rdev; struct tps_pmic *tps; @@ -443,20 +303,19 @@ static int __devinit tps_65023_probe(struct i2c_client *client, if (!init_data) return -EIO; - tps = kzalloc(sizeof(*tps), GFP_KERNEL); + tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); if (!tps) return -ENOMEM; - tps->regmap = regmap_init_i2c(client, &tps65023_regmap_config); + tps->regmap = devm_regmap_init_i2c(client, &tps65023_regmap_config); if (IS_ERR(tps->regmap)) { error = PTR_ERR(tps->regmap); dev_err(&client->dev, "Failed to allocate register map: %d\n", error); - goto fail_alloc; + return error; } /* common for all regulators */ - tps->client = client; tps->core_regulator = drv_data->core_regulator; for (i = 0; i < TPS65023_NUM_REGULATOR; i++, info++, init_data++) { @@ -471,9 +330,22 @@ static int __devinit tps_65023_probe(struct i2c_client *client, tps->desc[i].type = REGULATOR_VOLTAGE; tps->desc[i].owner = THIS_MODULE; + tps->desc[i].enable_reg = TPS65023_REG_REG_CTRL; + if (i == TPS65023_LDO_1) + tps->desc[i].enable_mask = 1 << 1; + else if (i == TPS65023_LDO_2) + tps->desc[i].enable_mask = 1 << 2; + else /* DCDCx */ + tps->desc[i].enable_mask = + 1 << (TPS65023_NUM_REGULATOR - i); + + config.dev = &client->dev; + config.init_data = init_data; + config.driver_data = tps; + config.regmap = tps->regmap; + /* Register the regulators */ - rdev = regulator_register(&tps->desc[i], &client->dev, - init_data, tps, NULL); + rdev = regulator_register(&tps->desc[i], &config); if (IS_ERR(rdev)) { dev_err(&client->dev, "failed to register %s\n", id->name); @@ -496,19 +368,9 @@ static int __devinit tps_65023_probe(struct i2c_client *client, fail: while (--i >= 0) regulator_unregister(tps->rdev[i]); - - regmap_exit(tps->regmap); - fail_alloc: - kfree(tps); return error; } -/** - * tps_65023_remove - TPS65023 driver i2c remove handler - * @client: i2c driver client device structure - * - * Unregister TPS driver as an i2c client device driver - */ static int __devexit tps_65023_remove(struct i2c_client *client) { struct tps_pmic *tps = i2c_get_clientdata(client); @@ -516,10 +378,6 @@ static int __devexit tps_65023_remove(struct i2c_client *client) for (i = 0; i < TPS65023_NUM_REGULATOR; i++) regulator_unregister(tps->rdev[i]); - - regmap_exit(tps->regmap); - kfree(tps); - return 0; } @@ -638,13 +496,13 @@ static struct tps_driver_data tps65020_drv_data = { }; static struct tps_driver_data tps65021_drv_data = { - .info = tps65021_regs, - .core_regulator = TPS65023_DCDC_3, + .info = tps65021_regs, + .core_regulator = TPS65023_DCDC_3, }; static struct tps_driver_data tps65023_drv_data = { - .info = tps65023_regs, - .core_regulator = TPS65023_DCDC_1, + .info = tps65023_regs, + .core_regulator = TPS65023_DCDC_1, }; static const struct i2c_device_id tps_65023_id[] = { @@ -669,22 +527,12 @@ static struct i2c_driver tps_65023_i2c_driver = { .id_table = tps_65023_id, }; -/** - * tps_65023_init - * - * Module init function - */ static int __init tps_65023_init(void) { return i2c_add_driver(&tps_65023_i2c_driver); } subsys_initcall(tps_65023_init); -/** - * tps_65023_cleanup - * - * Module exit function - */ static void __exit tps_65023_cleanup(void) { i2c_del_driver(&tps_65023_i2c_driver); diff --git a/trunk/drivers/regulator/tps6507x-regulator.c b/trunk/drivers/regulator/tps6507x-regulator.c index 832833fe8aad..da38be1016aa 100644 --- a/trunk/drivers/regulator/tps6507x-regulator.c +++ b/trunk/drivers/regulator/tps6507x-regulator.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -283,7 +282,7 @@ static int tps6507x_pmic_disable(struct regulator_dev *dev) 1 << shift); } -static int tps6507x_pmic_get_voltage(struct regulator_dev *dev) +static int tps6507x_pmic_get_voltage_sel(struct regulator_dev *dev) { struct tps6507x_pmic *tps = rdev_get_drvdata(dev); int data, rid = rdev_get_id(dev); @@ -325,7 +324,7 @@ static int tps6507x_pmic_get_voltage(struct regulator_dev *dev) return data; data &= mask; - return tps->info[rid]->table[data] * 1000; + return data; } static int tps6507x_pmic_set_voltage_sel(struct regulator_dev *dev, @@ -395,7 +394,7 @@ static struct regulator_ops tps6507x_pmic_ops = { .is_enabled = tps6507x_pmic_is_enabled, .enable = tps6507x_pmic_enable, .disable = tps6507x_pmic_disable, - .get_voltage = tps6507x_pmic_get_voltage, + .get_voltage_sel = tps6507x_pmic_get_voltage_sel, .set_voltage_sel = tps6507x_pmic_set_voltage_sel, .list_voltage = tps6507x_pmic_list_voltage, }; @@ -404,6 +403,7 @@ static __devinit int tps6507x_pmic_probe(struct platform_device *pdev) { struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent); struct tps_info *info = &tps6507x_pmic_regs[0]; + struct regulator_config config = { }; struct regulator_init_data *init_data; struct regulator_dev *rdev; struct tps6507x_pmic *tps; @@ -428,7 +428,7 @@ static __devinit int tps6507x_pmic_probe(struct platform_device *pdev) if (!init_data) return -EINVAL; - tps = kzalloc(sizeof(*tps), GFP_KERNEL); + tps = devm_kzalloc(&pdev->dev, sizeof(*tps), GFP_KERNEL); if (!tps) return -ENOMEM; @@ -453,8 +453,11 @@ static __devinit int tps6507x_pmic_probe(struct platform_device *pdev) tps->desc[i].type = REGULATOR_VOLTAGE; tps->desc[i].owner = THIS_MODULE; - rdev = regulator_register(&tps->desc[i], - tps6507x_dev->dev, init_data, tps, NULL); + config.dev = tps6507x_dev->dev; + config.init_data = init_data; + config.driver_data = tps; + + rdev = regulator_register(&tps->desc[i], &config); if (IS_ERR(rdev)) { dev_err(tps6507x_dev->dev, "failed to register %s regulator\n", @@ -475,8 +478,6 @@ static __devinit int tps6507x_pmic_probe(struct platform_device *pdev) fail: while (--i >= 0) regulator_unregister(tps->rdev[i]); - - kfree(tps); return error; } @@ -488,9 +489,6 @@ static int __devexit tps6507x_pmic_remove(struct platform_device *pdev) for (i = 0; i < TPS6507X_NUM_REGULATOR; i++) regulator_unregister(tps->rdev[i]); - - kfree(tps); - return 0; } diff --git a/trunk/drivers/regulator/tps65090-regulator.c b/trunk/drivers/regulator/tps65090-regulator.c new file mode 100644 index 000000000000..001ad554ac62 --- /dev/null +++ b/trunk/drivers/regulator/tps65090-regulator.c @@ -0,0 +1,150 @@ +/* + * Regulator driver for tps65090 power management chip. + * + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct tps65090_regulator { + int id; + /* used by regulator core */ + struct regulator_desc desc; + + /* Device */ + struct device *dev; +}; + +static struct regulator_ops tps65090_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +#define tps65090_REG(_id) \ +{ \ + .id = TPS65090_ID_##_id, \ + .desc = { \ + .name = tps65090_rails(_id), \ + .id = TPS65090_ID_##_id, \ + .ops = &tps65090_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .enable_reg = (TPS65090_ID_##_id) + 12, \ + .enable_mask = BIT(0), \ + }, \ +} + +static struct tps65090_regulator TPS65090_regulator[] = { + tps65090_REG(DCDC1), + tps65090_REG(DCDC2), + tps65090_REG(DCDC3), + tps65090_REG(FET1), + tps65090_REG(FET2), + tps65090_REG(FET3), + tps65090_REG(FET4), + tps65090_REG(FET5), + tps65090_REG(FET6), + tps65090_REG(FET7), +}; + +static inline struct tps65090_regulator *find_regulator_info(int id) +{ + struct tps65090_regulator *ri; + int i; + + for (i = 0; i < ARRAY_SIZE(TPS65090_regulator); i++) { + ri = &TPS65090_regulator[i]; + if (ri->desc.id == id) + return ri; + } + return NULL; +} + +static int __devinit tps65090_regulator_probe(struct platform_device *pdev) +{ + struct tps65090 *tps65090_mfd = dev_get_drvdata(pdev->dev.parent); + struct tps65090_regulator *ri = NULL; + struct regulator_config config = { }; + struct regulator_dev *rdev; + struct tps65090_regulator_platform_data *tps_pdata; + int id = pdev->id; + + dev_dbg(&pdev->dev, "Probing regulator %d\n", id); + + ri = find_regulator_info(id); + if (ri == NULL) { + dev_err(&pdev->dev, "invalid regulator ID specified\n"); + return -EINVAL; + } + tps_pdata = pdev->dev.platform_data; + ri->dev = &pdev->dev; + + config.dev = &pdev->dev; + config.init_data = &tps_pdata->regulator; + config.driver_data = ri; + config.regmap = tps65090_mfd->rmap; + + rdev = regulator_register(&ri->desc, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register regulator %s\n", + ri->desc.name); + return PTR_ERR(rdev); + } + + platform_set_drvdata(pdev, rdev); + return 0; +} + +static int __devexit tps65090_regulator_remove(struct platform_device *pdev) +{ + struct regulator_dev *rdev = platform_get_drvdata(pdev); + + regulator_unregister(rdev); + return 0; +} + +static struct platform_driver tps65090_regulator_driver = { + .driver = { + .name = "tps65090-regulator", + .owner = THIS_MODULE, + }, + .probe = tps65090_regulator_probe, + .remove = __devexit_p(tps65090_regulator_remove), +}; + +static int __init tps65090_regulator_init(void) +{ + return platform_driver_register(&tps65090_regulator_driver); +} +subsys_initcall(tps65090_regulator_init); + +static void __exit tps65090_regulator_exit(void) +{ + platform_driver_unregister(&tps65090_regulator_driver); +} +module_exit(tps65090_regulator_exit); + +MODULE_DESCRIPTION("tps65090 regulator driver"); +MODULE_AUTHOR("Venu Byravarasu "); +MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/regulator/tps65217-regulator.c b/trunk/drivers/regulator/tps65217-regulator.c index e39521b42772..9d371d2cbcae 100644 --- a/trunk/drivers/regulator/tps65217-regulator.c +++ b/trunk/drivers/regulator/tps65217-regulator.c @@ -213,65 +213,56 @@ static int tps65217_pmic_get_voltage_sel(struct regulator_dev *dev) return selector; } -static int tps65217_pmic_ldo1_set_voltage_sel(struct regulator_dev *dev, - unsigned selector) +static int tps65217_pmic_set_voltage_sel(struct regulator_dev *dev, + unsigned selector) { + int ret; struct tps65217 *tps = rdev_get_drvdata(dev); - int ldo = rdev_get_id(dev); + unsigned int rid = rdev_get_id(dev); - if (ldo != TPS65217_LDO_1) - return -EINVAL; + /* Set the voltage based on vsel value and write protect level is 2 */ + ret = tps65217_set_bits(tps, tps->info[rid]->set_vout_reg, + tps->info[rid]->set_vout_mask, + selector, TPS65217_PROTECT_L2); - if (selector >= tps->info[ldo]->table_len) - return -EINVAL; + /* Set GO bit for DCDCx to initiate voltage transistion */ + switch (rid) { + case TPS65217_DCDC_1 ... TPS65217_DCDC_3: + ret = tps65217_set_bits(tps, TPS65217_REG_DEFSLEW, + TPS65217_DEFSLEW_GO, TPS65217_DEFSLEW_GO, + TPS65217_PROTECT_L2); + break; + } - /* Set the voltage based on vsel value and write protect level is 2 */ - return tps65217_set_bits(tps, tps->info[ldo]->set_vout_reg, - tps->info[ldo]->set_vout_mask, - selector, TPS65217_PROTECT_L2); + return ret; } -static int tps65217_pmic_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV, unsigned *selector) +static int tps65217_pmic_map_voltage(struct regulator_dev *dev, + int min_uV, int max_uV) { - int ret; + struct tps65217 *tps = rdev_get_drvdata(dev); - unsigned int rid = rdev_get_id(dev); + unsigned int sel, rid = rdev_get_id(dev); + int ret; - /* LDO1 implements set_voltage_sel callback */ + /* LDO1 uses regulator_map_voltage_iterate() */ if (rid == TPS65217_LDO_1) return -EINVAL; if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4) return -EINVAL; - if (min_uV < tps->info[rid]->min_uV - || min_uV > tps->info[rid]->max_uV) + if (min_uV < tps->info[rid]->min_uV || min_uV > tps->info[rid]->max_uV) return -EINVAL; - if (max_uV < tps->info[rid]->min_uV - || max_uV > tps->info[rid]->max_uV) + if (max_uV < tps->info[rid]->min_uV || max_uV > tps->info[rid]->max_uV) return -EINVAL; - ret = tps->info[rid]->uv_to_vsel(min_uV, selector); + ret = tps->info[rid]->uv_to_vsel(min_uV, &sel); if (ret) return ret; - /* Set the voltage based on vsel value and write protect level is 2 */ - ret = tps65217_set_bits(tps, tps->info[rid]->set_vout_reg, - tps->info[rid]->set_vout_mask, - *selector, TPS65217_PROTECT_L2); - - /* Set GO bit for DCDCx to initiate voltage transistion */ - switch (rid) { - case TPS65217_DCDC_1 ... TPS65217_DCDC_3: - ret = tps65217_set_bits(tps, TPS65217_REG_DEFSLEW, - TPS65217_DEFSLEW_GO, TPS65217_DEFSLEW_GO, - TPS65217_PROTECT_L2); - break; - } - - return ret; + return sel; } static int tps65217_pmic_list_voltage(struct regulator_dev *dev, @@ -298,8 +289,9 @@ static struct regulator_ops tps65217_pmic_ops = { .enable = tps65217_pmic_enable, .disable = tps65217_pmic_disable, .get_voltage_sel = tps65217_pmic_get_voltage_sel, - .set_voltage = tps65217_pmic_set_voltage, + .set_voltage_sel = tps65217_pmic_set_voltage_sel, .list_voltage = tps65217_pmic_list_voltage, + .map_voltage = tps65217_pmic_map_voltage, }; /* Operations permitted on LDO1 */ @@ -308,11 +300,11 @@ static struct regulator_ops tps65217_pmic_ldo1_ops = { .enable = tps65217_pmic_enable, .disable = tps65217_pmic_disable, .get_voltage_sel = tps65217_pmic_get_voltage_sel, - .set_voltage_sel = tps65217_pmic_ldo1_set_voltage_sel, + .set_voltage_sel = tps65217_pmic_set_voltage_sel, .list_voltage = tps65217_pmic_list_voltage, }; -static struct regulator_desc regulators[] = { +static const struct regulator_desc regulators[] = { TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, tps65217_pmic_ops, 64), TPS65217_REGULATOR("DCDC2", TPS65217_DCDC_2, tps65217_pmic_ops, 64), TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, tps65217_pmic_ops, 64), @@ -327,13 +319,17 @@ static int __devinit tps65217_regulator_probe(struct platform_device *pdev) struct regulator_dev *rdev; struct tps65217 *tps; struct tps_info *info = &tps65217_pmic_regs[pdev->id]; + struct regulator_config config = { }; /* Already set by core driver */ tps = dev_to_tps65217(pdev->dev.parent); tps->info[pdev->id] = info; - rdev = regulator_register(®ulators[pdev->id], &pdev->dev, - pdev->dev.platform_data, tps, NULL); + config.dev = &pdev->dev; + config.init_data = pdev->dev.platform_data; + config.driver_data = tps; + + rdev = regulator_register(®ulators[pdev->id], &config); if (IS_ERR(rdev)) return PTR_ERR(rdev); diff --git a/trunk/drivers/regulator/tps6524x-regulator.c b/trunk/drivers/regulator/tps6524x-regulator.c index 4a421be6d4f2..b88b3df82381 100644 --- a/trunk/drivers/regulator/tps6524x-regulator.c +++ b/trunk/drivers/regulator/tps6524x-regulator.c @@ -458,12 +458,10 @@ static int list_voltage(struct regulator_dev *rdev, unsigned selector) info->voltages[selector] : -EINVAL); } -static int set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, - unsigned *selector) +static int set_voltage_sel(struct regulator_dev *rdev, unsigned selector) { const struct supply_info *info; struct tps6524x *hw; - unsigned i; hw = rdev_get_drvdata(rdev); info = &supply_info[rdev_get_id(rdev)]; @@ -471,20 +469,10 @@ static int set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, if (info->flags & FIXED_VOLTAGE) return -EINVAL; - for (i = 0; i < info->n_voltages; i++) - if (min_uV <= info->voltages[i] && - max_uV >= info->voltages[i]) - break; - - if (i >= info->n_voltages) - i = info->n_voltages - 1; - - *selector = i; - - return write_field(hw, &info->voltage, i); + return write_field(hw, &info->voltage, selector); } -static int get_voltage(struct regulator_dev *rdev) +static int get_voltage_sel(struct regulator_dev *rdev) { const struct supply_info *info; struct tps6524x *hw; @@ -502,7 +490,7 @@ static int get_voltage(struct regulator_dev *rdev) if (WARN_ON(ret >= info->n_voltages)) return -EIO; - return info->voltages[ret]; + return ret; } static int set_current_limit(struct regulator_dev *rdev, int min_uA, @@ -587,8 +575,8 @@ static struct regulator_ops regulator_ops = { .is_enabled = is_supply_enabled, .enable = enable_supply, .disable = disable_supply, - .get_voltage = get_voltage, - .set_voltage = set_voltage, + .get_voltage_sel = get_voltage_sel, + .set_voltage_sel = set_voltage_sel, .list_voltage = list_voltage, .set_current_limit = set_current_limit, .get_current_limit = get_current_limit, @@ -607,7 +595,6 @@ static int pmic_remove(struct spi_device *spi) hw->rdev[i] = NULL; } spi_set_drvdata(spi, NULL); - kfree(hw); return 0; } @@ -617,6 +604,7 @@ static int __devinit pmic_probe(struct spi_device *spi) struct device *dev = &spi->dev; const struct supply_info *info = supply_info; struct regulator_init_data *init_data; + struct regulator_config config = { }; int ret = 0, i; init_data = dev->platform_data; @@ -625,7 +613,7 @@ static int __devinit pmic_probe(struct spi_device *spi) return -EINVAL; } - hw = kzalloc(sizeof(struct tps6524x), GFP_KERNEL); + hw = devm_kzalloc(&spi->dev, sizeof(struct tps6524x), GFP_KERNEL); if (!hw) { dev_err(dev, "cannot allocate regulator private data\n"); return -ENOMEM; @@ -648,8 +636,11 @@ static int __devinit pmic_probe(struct spi_device *spi) if (info->flags & FIXED_VOLTAGE) hw->desc[i].n_voltages = 1; - hw->rdev[i] = regulator_register(&hw->desc[i], dev, - init_data, hw, NULL); + config.dev = dev; + config.init_data = init_data; + config.driver_data = hw; + + hw->rdev[i] = regulator_register(&hw->desc[i], &config); if (IS_ERR(hw->rdev[i])) { ret = PTR_ERR(hw->rdev[i]); hw->rdev[i] = NULL; @@ -673,17 +664,7 @@ static struct spi_driver pmic_driver = { }, }; -static int __init pmic_driver_init(void) -{ - return spi_register_driver(&pmic_driver); -} -module_init(pmic_driver_init); - -static void __exit pmic_driver_exit(void) -{ - spi_unregister_driver(&pmic_driver); -} -module_exit(pmic_driver_exit); +module_spi_driver(pmic_driver); MODULE_DESCRIPTION("TPS6524X PMIC Driver"); MODULE_AUTHOR("Cyril Chemparathy"); diff --git a/trunk/drivers/regulator/tps6586x-regulator.c b/trunk/drivers/regulator/tps6586x-regulator.c index cfc1f16f7771..c0a214575380 100644 --- a/trunk/drivers/regulator/tps6586x-regulator.c +++ b/trunk/drivers/regulator/tps6586x-regulator.c @@ -75,8 +75,7 @@ static inline struct device *to_tps6586x_dev(struct regulator_dev *rdev) return rdev_get_dev(rdev)->parent->parent; } -static int tps6586x_ldo_list_voltage(struct regulator_dev *rdev, - unsigned selector) +static int tps6586x_list_voltage(struct regulator_dev *rdev, unsigned selector) { struct tps6586x_regulator *info = rdev_get_drvdata(rdev); int rid = rdev_get_id(rdev); @@ -89,47 +88,34 @@ static int tps6586x_ldo_list_voltage(struct regulator_dev *rdev, } -static int __tps6586x_ldo_set_voltage(struct device *parent, - struct tps6586x_regulator *ri, - int min_uV, int max_uV, - unsigned *selector) +static int tps6586x_set_voltage_sel(struct regulator_dev *rdev, + unsigned selector) { - int val, uV; + struct tps6586x_regulator *ri = rdev_get_drvdata(rdev); + struct device *parent = to_tps6586x_dev(rdev); + int ret, val, rid = rdev_get_id(rdev); uint8_t mask; - for (val = 0; val < ri->desc.n_voltages; val++) { - uV = ri->voltages[val] * 1000; - - /* LDO0 has minimal voltage 1.2 rather than 1.25 */ - if (ri->desc.id == TPS6586X_ID_LDO_0 && val == 0) - uV -= 50 * 1000; - - /* use the first in-range value */ - if (min_uV <= uV && uV <= max_uV) { - - *selector = val; + val = selector << ri->volt_shift; + mask = ((1 << ri->volt_nbits) - 1) << ri->volt_shift; - val <<= ri->volt_shift; - mask = ((1 << ri->volt_nbits) - 1) << ri->volt_shift; + ret = tps6586x_update(parent, ri->volt_reg, val, mask); + if (ret) + return ret; - return tps6586x_update(parent, ri->volt_reg, val, mask); - } + /* Update go bit for DVM regulators */ + switch (rid) { + case TPS6586X_ID_LDO_2: + case TPS6586X_ID_LDO_4: + case TPS6586X_ID_SM_0: + case TPS6586X_ID_SM_1: + ret = tps6586x_set_bits(parent, ri->go_reg, 1 << ri->go_bit); + break; } - - return -EINVAL; -} - -static int tps6586x_ldo_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned *selector) -{ - struct tps6586x_regulator *ri = rdev_get_drvdata(rdev); - struct device *parent = to_tps6586x_dev(rdev); - - return __tps6586x_ldo_set_voltage(parent, ri, min_uV, max_uV, - selector); + return ret; } -static int tps6586x_ldo_get_voltage(struct regulator_dev *rdev) +static int tps6586x_get_voltage_sel(struct regulator_dev *rdev) { struct tps6586x_regulator *ri = rdev_get_drvdata(rdev); struct device *parent = to_tps6586x_dev(rdev); @@ -146,22 +132,7 @@ static int tps6586x_ldo_get_voltage(struct regulator_dev *rdev) if (val >= ri->desc.n_voltages) BUG(); - return ri->voltages[val] * 1000; -} - -static int tps6586x_dvm_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned *selector) -{ - struct tps6586x_regulator *ri = rdev_get_drvdata(rdev); - struct device *parent = to_tps6586x_dev(rdev); - int ret; - - ret = __tps6586x_ldo_set_voltage(parent, ri, min_uV, max_uV, - selector); - if (ret) - return ret; - - return tps6586x_set_bits(parent, ri->go_reg, 1 << ri->go_bit); + return val; } static int tps6586x_regulator_enable(struct regulator_dev *rdev) @@ -196,20 +167,10 @@ static int tps6586x_regulator_is_enabled(struct regulator_dev *rdev) return !!(reg_val & (1 << ri->enable_bit[0])); } -static struct regulator_ops tps6586x_regulator_ldo_ops = { - .list_voltage = tps6586x_ldo_list_voltage, - .get_voltage = tps6586x_ldo_get_voltage, - .set_voltage = tps6586x_ldo_set_voltage, - - .is_enabled = tps6586x_regulator_is_enabled, - .enable = tps6586x_regulator_enable, - .disable = tps6586x_regulator_disable, -}; - -static struct regulator_ops tps6586x_regulator_dvm_ops = { - .list_voltage = tps6586x_ldo_list_voltage, - .get_voltage = tps6586x_ldo_get_voltage, - .set_voltage = tps6586x_dvm_set_voltage, +static struct regulator_ops tps6586x_regulator_ops = { + .list_voltage = tps6586x_list_voltage, + .get_voltage_sel = tps6586x_get_voltage_sel, + .set_voltage_sel = tps6586x_set_voltage_sel, .is_enabled = tps6586x_regulator_is_enabled, .enable = tps6586x_regulator_enable, @@ -241,11 +202,11 @@ static int tps6586x_dvm_voltages[] = { 1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500, }; -#define TPS6586X_REGULATOR(_id, vdata, _ops, vreg, shift, nbits, \ +#define TPS6586X_REGULATOR(_id, vdata, vreg, shift, nbits, \ ereg0, ebit0, ereg1, ebit1) \ .desc = { \ .name = "REG-" #_id, \ - .ops = &tps6586x_regulator_##_ops, \ + .ops = &tps6586x_regulator_ops, \ .type = REGULATOR_VOLTAGE, \ .id = TPS6586X_ID_##_id, \ .n_voltages = ARRAY_SIZE(tps6586x_##vdata##_voltages), \ @@ -267,14 +228,14 @@ static int tps6586x_dvm_voltages[] = { #define TPS6586X_LDO(_id, vdata, vreg, shift, nbits, \ ereg0, ebit0, ereg1, ebit1) \ { \ - TPS6586X_REGULATOR(_id, vdata, ldo_ops, vreg, shift, nbits, \ + TPS6586X_REGULATOR(_id, vdata, vreg, shift, nbits, \ ereg0, ebit0, ereg1, ebit1) \ } #define TPS6586X_DVM(_id, vdata, vreg, shift, nbits, \ ereg0, ebit0, ereg1, ebit1, goreg, gobit) \ { \ - TPS6586X_REGULATOR(_id, vdata, dvm_ops, vreg, shift, nbits, \ + TPS6586X_REGULATOR(_id, vdata, vreg, shift, nbits, \ ereg0, ebit0, ereg1, ebit1) \ TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \ } @@ -384,6 +345,7 @@ static inline struct tps6586x_regulator *find_regulator_info(int id) static int __devinit tps6586x_regulator_probe(struct platform_device *pdev) { struct tps6586x_regulator *ri = NULL; + struct regulator_config config = { }; struct regulator_dev *rdev; int id = pdev->id; int err; @@ -400,8 +362,12 @@ static int __devinit tps6586x_regulator_probe(struct platform_device *pdev) if (err) return err; - rdev = regulator_register(&ri->desc, &pdev->dev, - pdev->dev.platform_data, ri, NULL); + config.dev = &pdev->dev; + config.of_node = pdev->dev.of_node; + config.init_data = pdev->dev.platform_data; + config.driver_data = ri; + + rdev = regulator_register(&ri->desc, &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register regulator %s\n", ri->desc.name); diff --git a/trunk/drivers/regulator/tps65910-regulator.c b/trunk/drivers/regulator/tps65910-regulator.c index 4a37c2b6367f..4e01a423471b 100644 --- a/trunk/drivers/regulator/tps65910-regulator.c +++ b/trunk/drivers/regulator/tps65910-regulator.c @@ -20,10 +20,10 @@ #include #include #include -#include #include #include #include +#include #define TPS65910_SUPPLY_STATE_ENABLED 0x1 #define EXT_SLEEP_CONTROL (TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1 | \ @@ -31,54 +31,54 @@ TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3 | \ TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP) -/* supported VIO voltages in milivolts */ +/* supported VIO voltages in millivolts */ static const u16 VIO_VSEL_table[] = { 1500, 1800, 2500, 3300, }; /* VSEL tables for TPS65910 specific LDOs and dcdc's */ -/* supported VDD3 voltages in milivolts */ +/* supported VDD3 voltages in millivolts */ static const u16 VDD3_VSEL_table[] = { 5000, }; -/* supported VDIG1 voltages in milivolts */ +/* supported VDIG1 voltages in millivolts */ static const u16 VDIG1_VSEL_table[] = { 1200, 1500, 1800, 2700, }; -/* supported VDIG2 voltages in milivolts */ +/* supported VDIG2 voltages in millivolts */ static const u16 VDIG2_VSEL_table[] = { 1000, 1100, 1200, 1800, }; -/* supported VPLL voltages in milivolts */ +/* supported VPLL voltages in millivolts */ static const u16 VPLL_VSEL_table[] = { 1000, 1100, 1800, 2500, }; -/* supported VDAC voltages in milivolts */ +/* supported VDAC voltages in millivolts */ static const u16 VDAC_VSEL_table[] = { 1800, 2600, 2800, 2850, }; -/* supported VAUX1 voltages in milivolts */ +/* supported VAUX1 voltages in millivolts */ static const u16 VAUX1_VSEL_table[] = { 1800, 2500, 2800, 2850, }; -/* supported VAUX2 voltages in milivolts */ +/* supported VAUX2 voltages in millivolts */ static const u16 VAUX2_VSEL_table[] = { 1800, 2800, 2900, 3300, }; -/* supported VAUX33 voltages in milivolts */ +/* supported VAUX33 voltages in millivolts */ static const u16 VAUX33_VSEL_table[] = { 1800, 2000, 2800, 3300, }; -/* supported VMMC voltages in milivolts */ +/* supported VMMC voltages in millivolts */ static const u16 VMMC_VSEL_table[] = { 1800, 2800, 3000, 3300, }; @@ -94,11 +94,11 @@ struct tps_info { static struct tps_info tps65910_regs[] = { { - .name = "VRTC", + .name = "vrtc", .enable_time_us = 2200, }, { - .name = "VIO", + .name = "vio", .min_uV = 1500000, .max_uV = 3300000, .n_voltages = ARRAY_SIZE(VIO_VSEL_table), @@ -106,19 +106,19 @@ static struct tps_info tps65910_regs[] = { .enable_time_us = 350, }, { - .name = "VDD1", + .name = "vdd1", .min_uV = 600000, .max_uV = 4500000, .enable_time_us = 350, }, { - .name = "VDD2", + .name = "vdd2", .min_uV = 600000, .max_uV = 4500000, .enable_time_us = 350, }, { - .name = "VDD3", + .name = "vdd3", .min_uV = 5000000, .max_uV = 5000000, .n_voltages = ARRAY_SIZE(VDD3_VSEL_table), @@ -126,7 +126,7 @@ static struct tps_info tps65910_regs[] = { .enable_time_us = 200, }, { - .name = "VDIG1", + .name = "vdig1", .min_uV = 1200000, .max_uV = 2700000, .n_voltages = ARRAY_SIZE(VDIG1_VSEL_table), @@ -134,7 +134,7 @@ static struct tps_info tps65910_regs[] = { .enable_time_us = 100, }, { - .name = "VDIG2", + .name = "vdig2", .min_uV = 1000000, .max_uV = 1800000, .n_voltages = ARRAY_SIZE(VDIG2_VSEL_table), @@ -142,7 +142,7 @@ static struct tps_info tps65910_regs[] = { .enable_time_us = 100, }, { - .name = "VPLL", + .name = "vpll", .min_uV = 1000000, .max_uV = 2500000, .n_voltages = ARRAY_SIZE(VPLL_VSEL_table), @@ -150,7 +150,7 @@ static struct tps_info tps65910_regs[] = { .enable_time_us = 100, }, { - .name = "VDAC", + .name = "vdac", .min_uV = 1800000, .max_uV = 2850000, .n_voltages = ARRAY_SIZE(VDAC_VSEL_table), @@ -158,7 +158,7 @@ static struct tps_info tps65910_regs[] = { .enable_time_us = 100, }, { - .name = "VAUX1", + .name = "vaux1", .min_uV = 1800000, .max_uV = 2850000, .n_voltages = ARRAY_SIZE(VAUX1_VSEL_table), @@ -166,7 +166,7 @@ static struct tps_info tps65910_regs[] = { .enable_time_us = 100, }, { - .name = "VAUX2", + .name = "vaux2", .min_uV = 1800000, .max_uV = 3300000, .n_voltages = ARRAY_SIZE(VAUX2_VSEL_table), @@ -174,7 +174,7 @@ static struct tps_info tps65910_regs[] = { .enable_time_us = 100, }, { - .name = "VAUX33", + .name = "vaux33", .min_uV = 1800000, .max_uV = 3300000, .n_voltages = ARRAY_SIZE(VAUX33_VSEL_table), @@ -182,7 +182,7 @@ static struct tps_info tps65910_regs[] = { .enable_time_us = 100, }, { - .name = "VMMC", + .name = "vmmc", .min_uV = 1800000, .max_uV = 3300000, .n_voltages = ARRAY_SIZE(VMMC_VSEL_table), @@ -193,11 +193,11 @@ static struct tps_info tps65910_regs[] = { static struct tps_info tps65911_regs[] = { { - .name = "VRTC", + .name = "vrtc", .enable_time_us = 2200, }, { - .name = "VIO", + .name = "vio", .min_uV = 1500000, .max_uV = 3300000, .n_voltages = ARRAY_SIZE(VIO_VSEL_table), @@ -205,77 +205,77 @@ static struct tps_info tps65911_regs[] = { .enable_time_us = 350, }, { - .name = "VDD1", + .name = "vdd1", .min_uV = 600000, .max_uV = 4500000, .n_voltages = 73, .enable_time_us = 350, }, { - .name = "VDD2", + .name = "vdd2", .min_uV = 600000, .max_uV = 4500000, .n_voltages = 73, .enable_time_us = 350, }, { - .name = "VDDCTRL", + .name = "vddctrl", .min_uV = 600000, .max_uV = 1400000, .n_voltages = 65, .enable_time_us = 900, }, { - .name = "LDO1", + .name = "ldo1", .min_uV = 1000000, .max_uV = 3300000, .n_voltages = 47, .enable_time_us = 420, }, { - .name = "LDO2", + .name = "ldo2", .min_uV = 1000000, .max_uV = 3300000, .n_voltages = 47, .enable_time_us = 420, }, { - .name = "LDO3", + .name = "ldo3", .min_uV = 1000000, .max_uV = 3300000, .n_voltages = 24, .enable_time_us = 230, }, { - .name = "LDO4", + .name = "ldo4", .min_uV = 1000000, .max_uV = 3300000, .n_voltages = 47, .enable_time_us = 230, }, { - .name = "LDO5", + .name = "ldo5", .min_uV = 1000000, .max_uV = 3300000, .n_voltages = 24, .enable_time_us = 230, }, { - .name = "LDO6", + .name = "ldo6", .min_uV = 1000000, .max_uV = 3300000, .n_voltages = 24, .enable_time_us = 230, }, { - .name = "LDO7", + .name = "ldo7", .min_uV = 1000000, .max_uV = 3300000, .n_voltages = 24, .enable_time_us = 230, }, { - .name = "LDO8", + .name = "ldo8", .min_uV = 1000000, .max_uV = 3300000, .n_voltages = 24, @@ -467,48 +467,6 @@ static int tps65911_get_ctrl_register(int id) } } -static int tps65910_is_enabled(struct regulator_dev *dev) -{ - struct tps65910_reg *pmic = rdev_get_drvdata(dev); - int reg, value, id = rdev_get_id(dev); - - reg = pmic->get_ctrl_reg(id); - if (reg < 0) - return reg; - - value = tps65910_reg_read(pmic, reg); - if (value < 0) - return value; - - return value & TPS65910_SUPPLY_STATE_ENABLED; -} - -static int tps65910_enable(struct regulator_dev *dev) -{ - struct tps65910_reg *pmic = rdev_get_drvdata(dev); - struct tps65910 *mfd = pmic->mfd; - int reg, id = rdev_get_id(dev); - - reg = pmic->get_ctrl_reg(id); - if (reg < 0) - return reg; - - return tps65910_set_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED); -} - -static int tps65910_disable(struct regulator_dev *dev) -{ - struct tps65910_reg *pmic = rdev_get_drvdata(dev); - struct tps65910 *mfd = pmic->mfd; - int reg, id = rdev_get_id(dev); - - reg = pmic->get_ctrl_reg(id); - if (reg < 0) - return reg; - - return tps65910_clear_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED); -} - static int tps65910_enable_time(struct regulator_dev *dev) { struct tps65910_reg *pmic = rdev_get_drvdata(dev); @@ -621,10 +579,10 @@ static int tps65910_get_voltage_dcdc_sel(struct regulator_dev *dev) return -EINVAL; } -static int tps65910_get_voltage(struct regulator_dev *dev) +static int tps65910_get_voltage_sel(struct regulator_dev *dev) { struct tps65910_reg *pmic = rdev_get_drvdata(dev); - int reg, value, id = rdev_get_id(dev), voltage = 0; + int reg, value, id = rdev_get_id(dev); reg = pmic->get_ctrl_reg(id); if (reg < 0) @@ -651,9 +609,7 @@ static int tps65910_get_voltage(struct regulator_dev *dev) return -EINVAL; } - voltage = pmic->info[id]->voltage_table[value] * 1000; - - return voltage; + return value; } static int tps65910_get_voltage_vdd3(struct regulator_dev *dev) @@ -661,10 +617,10 @@ static int tps65910_get_voltage_vdd3(struct regulator_dev *dev) return 5 * 1000 * 1000; } -static int tps65911_get_voltage(struct regulator_dev *dev) +static int tps65911_get_voltage_sel(struct regulator_dev *dev) { struct tps65910_reg *pmic = rdev_get_drvdata(dev); - int step_mv, id = rdev_get_id(dev); + int id = rdev_get_id(dev); u8 value, reg; reg = pmic->get_ctrl_reg(id); @@ -677,13 +633,6 @@ static int tps65911_get_voltage(struct regulator_dev *dev) case TPS65911_REG_LDO4: value &= LDO1_SEL_MASK; value >>= LDO_SEL_SHIFT; - /* The first 5 values of the selector correspond to 1V */ - if (value < 5) - value = 0; - else - value -= 4; - - step_mv = 50; break; case TPS65911_REG_LDO3: case TPS65911_REG_LDO5: @@ -692,23 +641,16 @@ static int tps65911_get_voltage(struct regulator_dev *dev) case TPS65911_REG_LDO8: value &= LDO3_SEL_MASK; value >>= LDO_SEL_SHIFT; - /* The first 3 values of the selector correspond to 1V */ - if (value < 3) - value = 0; - else - value -= 2; - - step_mv = 100; break; case TPS65910_REG_VIO: value &= LDO_SEL_MASK; value >>= LDO_SEL_SHIFT; - return pmic->info[id]->voltage_table[value] * 1000; + break; default: return -EINVAL; } - return (LDO_MIN_VOLT + value * step_mv) * 1000; + return value; } static int tps65910_set_voltage_dcdc_sel(struct regulator_dev *dev, @@ -914,9 +856,9 @@ static int tps65910_set_voltage_dcdc_time_sel(struct regulator_dev *dev, /* Regulator ops (except VRTC) */ static struct regulator_ops tps65910_ops_dcdc = { - .is_enabled = tps65910_is_enabled, - .enable = tps65910_enable, - .disable = tps65910_disable, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, .enable_time = tps65910_enable_time, .set_mode = tps65910_set_mode, .get_mode = tps65910_get_mode, @@ -927,9 +869,9 @@ static struct regulator_ops tps65910_ops_dcdc = { }; static struct regulator_ops tps65910_ops_vdd3 = { - .is_enabled = tps65910_is_enabled, - .enable = tps65910_enable, - .disable = tps65910_disable, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, .enable_time = tps65910_enable_time, .set_mode = tps65910_set_mode, .get_mode = tps65910_get_mode, @@ -938,25 +880,25 @@ static struct regulator_ops tps65910_ops_vdd3 = { }; static struct regulator_ops tps65910_ops = { - .is_enabled = tps65910_is_enabled, - .enable = tps65910_enable, - .disable = tps65910_disable, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, .enable_time = tps65910_enable_time, .set_mode = tps65910_set_mode, .get_mode = tps65910_get_mode, - .get_voltage = tps65910_get_voltage, + .get_voltage_sel = tps65910_get_voltage_sel, .set_voltage_sel = tps65910_set_voltage_sel, .list_voltage = tps65910_list_voltage, }; static struct regulator_ops tps65911_ops = { - .is_enabled = tps65910_is_enabled, - .enable = tps65910_enable, - .disable = tps65910_disable, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, .enable_time = tps65910_enable_time, .set_mode = tps65910_set_mode, .get_mode = tps65910_get_mode, - .get_voltage = tps65911_get_voltage, + .get_voltage_sel = tps65911_get_voltage_sel, .set_voltage_sel = tps65911_set_voltage_sel, .list_voltage = tps65911_list_voltage, }; @@ -1094,23 +1036,141 @@ static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic, return ret; } +#ifdef CONFIG_OF + +static struct of_regulator_match tps65910_matches[] = { + { .name = "vrtc", .driver_data = (void *) &tps65910_regs[0] }, + { .name = "vio", .driver_data = (void *) &tps65910_regs[1] }, + { .name = "vdd1", .driver_data = (void *) &tps65910_regs[2] }, + { .name = "vdd2", .driver_data = (void *) &tps65910_regs[3] }, + { .name = "vdd3", .driver_data = (void *) &tps65910_regs[4] }, + { .name = "vdig1", .driver_data = (void *) &tps65910_regs[5] }, + { .name = "vdig2", .driver_data = (void *) &tps65910_regs[6] }, + { .name = "vpll", .driver_data = (void *) &tps65910_regs[7] }, + { .name = "vdac", .driver_data = (void *) &tps65910_regs[8] }, + { .name = "vaux1", .driver_data = (void *) &tps65910_regs[9] }, + { .name = "vaux2", .driver_data = (void *) &tps65910_regs[10] }, + { .name = "vaux33", .driver_data = (void *) &tps65910_regs[11] }, + { .name = "vmmc", .driver_data = (void *) &tps65910_regs[12] }, +}; + +static struct of_regulator_match tps65911_matches[] = { + { .name = "vrtc", .driver_data = (void *) &tps65911_regs[0] }, + { .name = "vio", .driver_data = (void *) &tps65911_regs[1] }, + { .name = "vdd1", .driver_data = (void *) &tps65911_regs[2] }, + { .name = "vdd2", .driver_data = (void *) &tps65911_regs[3] }, + { .name = "vddctrl", .driver_data = (void *) &tps65911_regs[4] }, + { .name = "ldo1", .driver_data = (void *) &tps65911_regs[5] }, + { .name = "ldo2", .driver_data = (void *) &tps65911_regs[6] }, + { .name = "ldo3", .driver_data = (void *) &tps65911_regs[7] }, + { .name = "ldo4", .driver_data = (void *) &tps65911_regs[8] }, + { .name = "ldo5", .driver_data = (void *) &tps65911_regs[9] }, + { .name = "ldo6", .driver_data = (void *) &tps65911_regs[10] }, + { .name = "ldo7", .driver_data = (void *) &tps65911_regs[11] }, + { .name = "ldo8", .driver_data = (void *) &tps65911_regs[12] }, +}; + +static struct tps65910_board *tps65910_parse_dt_reg_data( + struct platform_device *pdev, + struct of_regulator_match **tps65910_reg_matches) +{ + struct tps65910_board *pmic_plat_data; + struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); + struct device_node *np = pdev->dev.parent->of_node; + struct device_node *regulators; + struct of_regulator_match *matches; + unsigned int prop; + int idx = 0, ret, count; + + pmic_plat_data = devm_kzalloc(&pdev->dev, sizeof(*pmic_plat_data), + GFP_KERNEL); + + if (!pmic_plat_data) { + dev_err(&pdev->dev, "Failure to alloc pdata for regulators.\n"); + return NULL; + } + + regulators = of_find_node_by_name(np, "regulators"); + if (!regulators) { + dev_err(&pdev->dev, "regulator node not found\n"); + return NULL; + } + + switch (tps65910_chip_id(tps65910)) { + case TPS65910: + count = ARRAY_SIZE(tps65910_matches); + matches = tps65910_matches; + break; + case TPS65911: + count = ARRAY_SIZE(tps65911_matches); + matches = tps65911_matches; + break; + default: + dev_err(&pdev->dev, "Invalid tps chip version\n"); + return NULL; + } + + ret = of_regulator_match(pdev->dev.parent, regulators, matches, count); + if (ret < 0) { + dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", + ret); + return NULL; + } + + *tps65910_reg_matches = matches; + + for (idx = 0; idx < count; idx++) { + if (!matches[idx].init_data || !matches[idx].of_node) + continue; + + pmic_plat_data->tps65910_pmic_init_data[idx] = + matches[idx].init_data; + + ret = of_property_read_u32(matches[idx].of_node, + "ti,regulator-ext-sleep-control", &prop); + if (!ret) + pmic_plat_data->regulator_ext_sleep_control[idx] = prop; + } + + return pmic_plat_data; +} +#else +static inline struct tps65910_board *tps65910_parse_dt_reg_data( + struct platform_device *pdev, + struct of_regulator_match **tps65910_reg_matches) +{ + *tps65910_reg_matches = NULL; + return 0; +} +#endif + static __devinit int tps65910_probe(struct platform_device *pdev) { struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); + struct regulator_config config = { }; struct tps_info *info; struct regulator_init_data *reg_data; struct regulator_dev *rdev; struct tps65910_reg *pmic; struct tps65910_board *pmic_plat_data; + struct of_regulator_match *tps65910_reg_matches = NULL; int i, err; pmic_plat_data = dev_get_platdata(tps65910->dev); - if (!pmic_plat_data) + if (!pmic_plat_data && tps65910->dev->of_node) + pmic_plat_data = tps65910_parse_dt_reg_data(pdev, + &tps65910_reg_matches); + + if (!pmic_plat_data) { + dev_err(&pdev->dev, "Platform data not found\n"); return -EINVAL; + } - pmic = kzalloc(sizeof(*pmic), GFP_KERNEL); - if (!pmic) + pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL); + if (!pmic) { + dev_err(&pdev->dev, "Memory allocation failed for pmic\n"); return -ENOMEM; + } mutex_init(&pmic->mutex); pmic->mfd = tps65910; @@ -1134,30 +1194,29 @@ static __devinit int tps65910_probe(struct platform_device *pdev) info = tps65911_regs; break; default: - pr_err("Invalid tps chip version\n"); - kfree(pmic); + dev_err(&pdev->dev, "Invalid tps chip version\n"); return -ENODEV; } - pmic->desc = kcalloc(pmic->num_regulators, + pmic->desc = devm_kzalloc(&pdev->dev, pmic->num_regulators * sizeof(struct regulator_desc), GFP_KERNEL); if (!pmic->desc) { - err = -ENOMEM; - goto err_free_pmic; + dev_err(&pdev->dev, "Memory alloc fails for desc\n"); + return -ENOMEM; } - pmic->info = kcalloc(pmic->num_regulators, + pmic->info = devm_kzalloc(&pdev->dev, pmic->num_regulators * sizeof(struct tps_info *), GFP_KERNEL); if (!pmic->info) { - err = -ENOMEM; - goto err_free_desc; + dev_err(&pdev->dev, "Memory alloc fails for info\n"); + return -ENOMEM; } - pmic->rdev = kcalloc(pmic->num_regulators, + pmic->rdev = devm_kzalloc(&pdev->dev, pmic->num_regulators * sizeof(struct regulator_dev *), GFP_KERNEL); if (!pmic->rdev) { - err = -ENOMEM; - goto err_free_info; + dev_err(&pdev->dev, "Memory alloc fails for rdev\n"); + return -ENOMEM; } for (i = 0; i < pmic->num_regulators && i < TPS65910_NUM_REGS; @@ -1205,9 +1264,18 @@ static __devinit int tps65910_probe(struct platform_device *pdev) pmic->desc[i].type = REGULATOR_VOLTAGE; pmic->desc[i].owner = THIS_MODULE; + pmic->desc[i].enable_reg = pmic->get_ctrl_reg(i); + pmic->desc[i].enable_mask = TPS65910_SUPPLY_STATE_ENABLED; + + config.dev = tps65910->dev; + config.init_data = reg_data; + config.driver_data = pmic; + config.regmap = tps65910->regmap; + + if (tps65910_reg_matches) + config.of_node = tps65910_reg_matches[i].of_node; - rdev = regulator_register(&pmic->desc[i], - tps65910->dev, reg_data, pmic, NULL); + rdev = regulator_register(&pmic->desc[i], &config); if (IS_ERR(rdev)) { dev_err(tps65910->dev, "failed to register %s regulator\n", @@ -1224,13 +1292,6 @@ static __devinit int tps65910_probe(struct platform_device *pdev) err_unregister_regulator: while (--i >= 0) regulator_unregister(pmic->rdev[i]); - kfree(pmic->rdev); -err_free_info: - kfree(pmic->info); -err_free_desc: - kfree(pmic->desc); -err_free_pmic: - kfree(pmic); return err; } @@ -1242,10 +1303,6 @@ static int __devexit tps65910_remove(struct platform_device *pdev) for (i = 0; i < pmic->num_regulators; i++) regulator_unregister(pmic->rdev[i]); - kfree(pmic->rdev); - kfree(pmic->info); - kfree(pmic->desc); - kfree(pmic); return 0; } diff --git a/trunk/drivers/regulator/tps65912-regulator.c b/trunk/drivers/regulator/tps65912-regulator.c index b36799b1f530..18b2a1dcb4b5 100644 --- a/trunk/drivers/regulator/tps65912-regulator.c +++ b/trunk/drivers/regulator/tps65912-regulator.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -372,12 +371,14 @@ static unsigned int tps65912_get_mode(struct regulator_dev *dev) return mode; } -static int tps65912_list_voltage_dcdc(struct regulator_dev *dev, - unsigned selector) +static int tps65912_list_voltage(struct regulator_dev *dev, unsigned selector) { struct tps65912_reg *pmic = rdev_get_drvdata(dev); int range, voltage = 0, id = rdev_get_id(dev); + if (id >= TPS65912_REG_LDO1 && id <= TPS65912_REG_LDO10) + return tps65912_vsel_to_uv_ldo(selector); + if (id > TPS65912_REG_DCDC4) return -EINVAL; @@ -404,7 +405,7 @@ static int tps65912_list_voltage_dcdc(struct regulator_dev *dev, return voltage; } -static int tps65912_get_voltage_dcdc(struct regulator_dev *dev) +static int tps65912_get_voltage_sel(struct regulator_dev *dev) { struct tps65912_reg *pmic = rdev_get_drvdata(dev); struct tps65912 *mfd = pmic->mfd; @@ -418,7 +419,7 @@ static int tps65912_get_voltage_dcdc(struct regulator_dev *dev) vsel = tps65912_reg_read(mfd, reg); vsel &= 0x3F; - return tps65912_list_voltage_dcdc(dev, vsel); + return vsel; } static int tps65912_set_voltage_sel(struct regulator_dev *dev, @@ -436,32 +437,6 @@ static int tps65912_set_voltage_sel(struct regulator_dev *dev, return tps65912_reg_write(mfd, reg, selector | value); } -static int tps65912_get_voltage_ldo(struct regulator_dev *dev) -{ - struct tps65912_reg *pmic = rdev_get_drvdata(dev); - struct tps65912 *mfd = pmic->mfd; - int id = rdev_get_id(dev); - int vsel = 0; - u8 reg; - - reg = tps65912_get_sel_register(pmic, id); - vsel = tps65912_reg_read(mfd, reg); - vsel &= 0x3F; - - return tps65912_vsel_to_uv_ldo(vsel); -} - -static int tps65912_list_voltage_ldo(struct regulator_dev *dev, - unsigned selector) -{ - int ldo = rdev_get_id(dev); - - if (ldo < TPS65912_REG_LDO1 || ldo > TPS65912_REG_LDO10) - return -EINVAL; - - return tps65912_vsel_to_uv_ldo(selector); -} - /* Operations permitted on DCDCx */ static struct regulator_ops tps65912_ops_dcdc = { .is_enabled = tps65912_reg_is_enabled, @@ -469,9 +444,9 @@ static struct regulator_ops tps65912_ops_dcdc = { .disable = tps65912_reg_disable, .set_mode = tps65912_set_mode, .get_mode = tps65912_get_mode, - .get_voltage = tps65912_get_voltage_dcdc, + .get_voltage_sel = tps65912_get_voltage_sel, .set_voltage_sel = tps65912_set_voltage_sel, - .list_voltage = tps65912_list_voltage_dcdc, + .list_voltage = tps65912_list_voltage, }; /* Operations permitted on LDOx */ @@ -479,14 +454,15 @@ static struct regulator_ops tps65912_ops_ldo = { .is_enabled = tps65912_reg_is_enabled, .enable = tps65912_reg_enable, .disable = tps65912_reg_disable, - .get_voltage = tps65912_get_voltage_ldo, + .get_voltage_sel = tps65912_get_voltage_sel, .set_voltage_sel = tps65912_set_voltage_sel, - .list_voltage = tps65912_list_voltage_ldo, + .list_voltage = tps65912_list_voltage, }; static __devinit int tps65912_probe(struct platform_device *pdev) { struct tps65912 *tps65912 = dev_get_drvdata(pdev->dev.parent); + struct regulator_config config = { }; struct tps_info *info; struct regulator_init_data *reg_data; struct regulator_dev *rdev; @@ -500,7 +476,7 @@ static __devinit int tps65912_probe(struct platform_device *pdev) reg_data = pmic_plat_data->tps65912_pmic_init_data; - pmic = kzalloc(sizeof(*pmic), GFP_KERNEL); + pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL); if (!pmic) return -ENOMEM; @@ -524,8 +500,12 @@ static __devinit int tps65912_probe(struct platform_device *pdev) pmic->desc[i].type = REGULATOR_VOLTAGE; pmic->desc[i].owner = THIS_MODULE; range = tps65912_get_range(pmic, i); - rdev = regulator_register(&pmic->desc[i], - tps65912->dev, reg_data, pmic, NULL); + + config.dev = tps65912->dev; + config.init_data = reg_data; + config.driver_data = pmic; + + rdev = regulator_register(&pmic->desc[i], &config); if (IS_ERR(rdev)) { dev_err(tps65912->dev, "failed to register %s regulator\n", @@ -542,8 +522,6 @@ static __devinit int tps65912_probe(struct platform_device *pdev) err: while (--i >= 0) regulator_unregister(pmic->rdev[i]); - - kfree(pmic); return err; } @@ -554,8 +532,6 @@ static int __devexit tps65912_remove(struct platform_device *pdev) for (i = 0; i < TPS65912_NUM_REGULATOR; i++) regulator_unregister(tps65912_reg->rdev[i]); - - kfree(tps65912_reg); return 0; } diff --git a/trunk/drivers/regulator/twl-regulator.c b/trunk/drivers/regulator/twl-regulator.c index 9cdfc389ca26..c7390711d954 100644 --- a/trunk/drivers/regulator/twl-regulator.c +++ b/trunk/drivers/regulator/twl-regulator.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -175,15 +174,14 @@ static int twl6030reg_is_enabled(struct regulator_dev *rdev) struct twlreg_info *info = rdev_get_drvdata(rdev); int grp = 0, val; - if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS))) - grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP); - if (grp < 0) - return grp; - - if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS))) + if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS))) { + grp = twlreg_grp(rdev); + if (grp < 0) + return grp; grp &= P1_GRP_6030; - else + } else { grp = 1; + } val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE); val = TWL6030_CFG_STATE_APP(val); @@ -197,7 +195,7 @@ static int twl4030reg_enable(struct regulator_dev *rdev) int grp; int ret; - grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP); + grp = twlreg_grp(rdev); if (grp < 0) return grp; @@ -205,8 +203,6 @@ static int twl4030reg_enable(struct regulator_dev *rdev) ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp); - udelay(info->delay); - return ret; } @@ -217,17 +213,28 @@ static int twl6030reg_enable(struct regulator_dev *rdev) int ret; if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS))) - grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP); + grp = twlreg_grp(rdev); if (grp < 0) return grp; ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE, grp << TWL6030_CFG_STATE_GRP_SHIFT | TWL6030_CFG_STATE_ON); + return ret; +} - udelay(info->delay); +static int twl4030reg_enable_time(struct regulator_dev *rdev) +{ + struct twlreg_info *info = rdev_get_drvdata(rdev); - return ret; + return info->delay; +} + +static int twl6030reg_enable_time(struct regulator_dev *rdev) +{ + struct twlreg_info *info = rdev_get_drvdata(rdev); + + return info->delay; } static int twl4030reg_disable(struct regulator_dev *rdev) @@ -236,7 +243,7 @@ static int twl4030reg_disable(struct regulator_dev *rdev) int grp; int ret; - grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP); + grp = twlreg_grp(rdev); if (grp < 0) return grp; @@ -348,7 +355,7 @@ static int twl6030reg_set_mode(struct regulator_dev *rdev, unsigned mode) int val; if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS))) - grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP); + grp = twlreg_grp(rdev); if (grp < 0) return grp; @@ -388,14 +395,12 @@ static int twl6030reg_set_mode(struct regulator_dev *rdev, unsigned mode) * VAUX3 at 3V is incorrectly listed in some TI manuals as unsupported. * TI are revising the twl5030/tps659x0 specs to support that 3.0V setting. */ -#ifdef CONFIG_TWL4030_ALLOW_UNSUPPORTED -#define UNSUP_MASK 0x0000 -#else #define UNSUP_MASK 0x8000 -#endif #define UNSUP(x) (UNSUP_MASK | (x)) -#define IS_UNSUP(x) (UNSUP_MASK & (x)) +#define IS_UNSUP(info, x) \ + ((UNSUP_MASK & (x)) && \ + !((info)->features & TWL4030_ALLOW_UNSUPPORTED)) #define LDO_MV(x) (~UNSUP_MASK & (x)) @@ -469,35 +474,16 @@ static int twl4030ldo_list_voltage(struct regulator_dev *rdev, unsigned index) struct twlreg_info *info = rdev_get_drvdata(rdev); int mV = info->table[index]; - return IS_UNSUP(mV) ? 0 : (LDO_MV(mV) * 1000); + return IS_UNSUP(info, mV) ? 0 : (LDO_MV(mV) * 1000); } static int -twl4030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, - unsigned *selector) +twl4030ldo_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) { struct twlreg_info *info = rdev_get_drvdata(rdev); - int vsel; - for (vsel = 0; vsel < info->table_len; vsel++) { - int mV = info->table[vsel]; - int uV; - - if (IS_UNSUP(mV)) - continue; - uV = LDO_MV(mV) * 1000; - - /* REVISIT for VAUX2, first match may not be best/lowest */ - - /* use the first in-range value */ - if (min_uV <= uV && uV <= max_uV) { - *selector = vsel; - return twlreg_write(info, TWL_MODULE_PM_RECEIVER, - VREG_VOLTAGE, vsel); - } - } - - return -EDOM; + return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE, + selector); } static int twl4030ldo_get_voltage(struct regulator_dev *rdev) @@ -516,12 +502,13 @@ static int twl4030ldo_get_voltage(struct regulator_dev *rdev) static struct regulator_ops twl4030ldo_ops = { .list_voltage = twl4030ldo_list_voltage, - .set_voltage = twl4030ldo_set_voltage, + .set_voltage_sel = twl4030ldo_set_voltage_sel, .get_voltage = twl4030ldo_get_voltage, .enable = twl4030reg_enable, .disable = twl4030reg_disable, .is_enabled = twl4030reg_is_enabled, + .enable_time = twl4030reg_enable_time, .set_mode = twl4030reg_set_mode, @@ -642,6 +629,7 @@ static struct regulator_ops twl6030ldo_ops = { .enable = twl6030reg_enable, .disable = twl6030reg_disable, .is_enabled = twl6030reg_is_enabled, + .enable_time = twl6030reg_enable_time, .set_mode = twl6030reg_set_mode, @@ -675,6 +663,7 @@ static struct regulator_ops twl4030fixed_ops = { .enable = twl4030reg_enable, .disable = twl4030reg_disable, .is_enabled = twl4030reg_is_enabled, + .enable_time = twl4030reg_enable_time, .set_mode = twl4030reg_set_mode, @@ -689,6 +678,7 @@ static struct regulator_ops twl6030fixed_ops = { .enable = twl6030reg_enable, .disable = twl6030reg_disable, .is_enabled = twl6030reg_is_enabled, + .enable_time = twl6030reg_enable_time, .set_mode = twl6030reg_set_mode, @@ -699,6 +689,7 @@ static struct regulator_ops twl6030_fixed_resource = { .enable = twl6030reg_enable, .disable = twl6030reg_disable, .is_enabled = twl6030reg_is_enabled, + .enable_time = twl6030reg_enable_time, .get_status = twl6030reg_get_status, }; @@ -806,10 +797,7 @@ twl6030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, vsel = 0; else if ((min_uV >= 600000) && (min_uV <= 1300000)) { int calc_uV; - vsel = (min_uV - 600000) / 125; - if (vsel % 100) - vsel += 100; - vsel /= 100; + vsel = DIV_ROUND_UP(min_uV - 600000, 12500); vsel++; calc_uV = twl6030smps_list_voltage(rdev, vsel); if (calc_uV > max_uV) @@ -836,10 +824,7 @@ twl6030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, vsel = 0; else if ((min_uV >= 700000) && (min_uV <= 1420000)) { int calc_uV; - vsel = (min_uV - 700000) / 125; - if (vsel % 100) - vsel += 100; - vsel /= 100; + vsel = DIV_ROUND_UP(min_uV - 700000, 12500); vsel++; calc_uV = twl6030smps_list_voltage(rdev, vsel); if (calc_uV > max_uV) @@ -862,24 +847,18 @@ twl6030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, return -EINVAL; break; case SMPS_EXTENDED_EN: - if (min_uV == 0) + if (min_uV == 0) { vsel = 0; - else if ((min_uV >= 1852000) && (max_uV <= 4013600)) { - vsel = (min_uV - 1852000) / 386; - if (vsel % 100) - vsel += 100; - vsel /= 100; + } else if ((min_uV >= 1852000) && (max_uV <= 4013600)) { + vsel = DIV_ROUND_UP(min_uV - 1852000, 38600); vsel++; } break; case SMPS_OFFSET_EN|SMPS_EXTENDED_EN: - if (min_uV == 0) + if (min_uV == 0) { vsel = 0; - else if ((min_uV >= 2161000) && (max_uV <= 4321000)) { - vsel = (min_uV - 2161000) / 386; - if (vsel % 100) - vsel += 100; - vsel /= 100; + } else if ((min_uV >= 2161000) && (max_uV <= 4321000)) { + vsel = DIV_ROUND_UP(min_uV - 2161000, 38600); vsel++; } break; @@ -907,6 +886,7 @@ static struct regulator_ops twlsmps_ops = { .enable = twl6030reg_enable, .disable = twl6030reg_disable, .is_enabled = twl6030reg_is_enabled, + .enable_time = twl6030reg_enable_time, .set_mode = twl6030reg_set_mode, @@ -1194,6 +1174,7 @@ static int __devinit twlreg_probe(struct platform_device *pdev) struct regulator_dev *rdev; struct twl_regulator_driver_data *drvdata; const struct of_device_id *match; + struct regulator_config config = { }; match = of_match_device(twl_of_match, &pdev->dev); if (match) { @@ -1207,10 +1188,12 @@ static int __devinit twlreg_probe(struct platform_device *pdev) initdata = pdev->dev.platform_data; for (i = 0, info = NULL; i < ARRAY_SIZE(twl_of_match); i++) { info = twl_of_match[i].data; - if (!info || info->desc.id != id) - continue; - break; + if (info && info->desc.id == id) + break; } + if (i == ARRAY_SIZE(twl_of_match)) + return -ENODEV; + drvdata = initdata->driver_data; if (!drvdata) return -EINVAL; @@ -1273,8 +1256,12 @@ static int __devinit twlreg_probe(struct platform_device *pdev) break; } - rdev = regulator_register(&info->desc, &pdev->dev, initdata, info, - pdev->dev.of_node); + config.dev = &pdev->dev; + config.init_data = initdata; + config.driver_data = info; + config.of_node = pdev->dev.of_node; + + rdev = regulator_register(&info->desc, &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "can't register %s, %ld\n", info->desc.name, PTR_ERR(rdev)); diff --git a/trunk/drivers/regulator/userspace-consumer.c b/trunk/drivers/regulator/userspace-consumer.c index 518667ef9a0d..a7c8deb5f28f 100644 --- a/trunk/drivers/regulator/userspace-consumer.c +++ b/trunk/drivers/regulator/userspace-consumer.c @@ -115,7 +115,9 @@ static int regulator_userspace_consumer_probe(struct platform_device *pdev) if (!pdata) return -EINVAL; - drvdata = kzalloc(sizeof(struct userspace_consumer_data), GFP_KERNEL); + drvdata = devm_kzalloc(&pdev->dev, + sizeof(struct userspace_consumer_data), + GFP_KERNEL); if (drvdata == NULL) return -ENOMEM; @@ -125,16 +127,16 @@ static int regulator_userspace_consumer_probe(struct platform_device *pdev) mutex_init(&drvdata->lock); - ret = regulator_bulk_get(&pdev->dev, drvdata->num_supplies, - drvdata->supplies); + ret = devm_regulator_bulk_get(&pdev->dev, drvdata->num_supplies, + drvdata->supplies); if (ret) { dev_err(&pdev->dev, "Failed to get supplies: %d\n", ret); - goto err_alloc_supplies; + return ret; } ret = sysfs_create_group(&pdev->dev.kobj, &attr_group); if (ret != 0) - goto err_create_attrs; + return ret; if (pdata->init_on) { ret = regulator_bulk_enable(drvdata->num_supplies, @@ -154,11 +156,6 @@ static int regulator_userspace_consumer_probe(struct platform_device *pdev) err_enable: sysfs_remove_group(&pdev->dev.kobj, &attr_group); -err_create_attrs: - regulator_bulk_free(drvdata->num_supplies, drvdata->supplies); - -err_alloc_supplies: - kfree(drvdata); return ret; } @@ -171,9 +168,6 @@ static int regulator_userspace_consumer_remove(struct platform_device *pdev) if (data->enabled) regulator_bulk_disable(data->num_supplies, data->supplies); - regulator_bulk_free(data->num_supplies, data->supplies); - kfree(data); - return 0; } diff --git a/trunk/drivers/regulator/virtual.c b/trunk/drivers/regulator/virtual.c index ee0b161c998f..c038e7422538 100644 --- a/trunk/drivers/regulator/virtual.c +++ b/trunk/drivers/regulator/virtual.c @@ -121,7 +121,7 @@ static ssize_t set_min_uV(struct device *dev, struct device_attribute *attr, struct virtual_consumer_data *data = dev_get_drvdata(dev); long val; - if (strict_strtol(buf, 10, &val) != 0) + if (kstrtol(buf, 10, &val) != 0) return count; mutex_lock(&data->lock); @@ -147,7 +147,7 @@ static ssize_t set_max_uV(struct device *dev, struct device_attribute *attr, struct virtual_consumer_data *data = dev_get_drvdata(dev); long val; - if (strict_strtol(buf, 10, &val) != 0) + if (kstrtol(buf, 10, &val) != 0) return count; mutex_lock(&data->lock); @@ -173,7 +173,7 @@ static ssize_t set_min_uA(struct device *dev, struct device_attribute *attr, struct virtual_consumer_data *data = dev_get_drvdata(dev); long val; - if (strict_strtol(buf, 10, &val) != 0) + if (kstrtol(buf, 10, &val) != 0) return count; mutex_lock(&data->lock); @@ -199,7 +199,7 @@ static ssize_t set_max_uA(struct device *dev, struct device_attribute *attr, struct virtual_consumer_data *data = dev_get_drvdata(dev); long val; - if (strict_strtol(buf, 10, &val) != 0) + if (kstrtol(buf, 10, &val) != 0) return count; mutex_lock(&data->lock); @@ -291,18 +291,19 @@ static int __devinit regulator_virtual_probe(struct platform_device *pdev) struct virtual_consumer_data *drvdata; int ret; - drvdata = kzalloc(sizeof(struct virtual_consumer_data), GFP_KERNEL); + drvdata = devm_kzalloc(&pdev->dev, sizeof(struct virtual_consumer_data), + GFP_KERNEL); if (drvdata == NULL) return -ENOMEM; mutex_init(&drvdata->lock); - drvdata->regulator = regulator_get(&pdev->dev, reg_id); + drvdata->regulator = devm_regulator_get(&pdev->dev, reg_id); if (IS_ERR(drvdata->regulator)) { ret = PTR_ERR(drvdata->regulator); dev_err(&pdev->dev, "Failed to obtain supply '%s': %d\n", reg_id, ret); - goto err; + return ret; } ret = sysfs_create_group(&pdev->dev.kobj, @@ -310,7 +311,7 @@ static int __devinit regulator_virtual_probe(struct platform_device *pdev) if (ret != 0) { dev_err(&pdev->dev, "Failed to create attribute group: %d\n", ret); - goto err_regulator; + return ret; } drvdata->mode = regulator_get_mode(drvdata->regulator); @@ -318,12 +319,6 @@ static int __devinit regulator_virtual_probe(struct platform_device *pdev) platform_set_drvdata(pdev, drvdata); return 0; - -err_regulator: - regulator_put(drvdata->regulator); -err: - kfree(drvdata); - return ret; } static int __devexit regulator_virtual_remove(struct platform_device *pdev) @@ -334,9 +329,6 @@ static int __devexit regulator_virtual_remove(struct platform_device *pdev) if (drvdata->enabled) regulator_disable(drvdata->regulator); - regulator_put(drvdata->regulator); - - kfree(drvdata); platform_set_drvdata(pdev, NULL); diff --git a/trunk/drivers/regulator/wm831x-dcdc.c b/trunk/drivers/regulator/wm831x-dcdc.c index ff810e787eac..a885911bb5fc 100644 --- a/trunk/drivers/regulator/wm831x-dcdc.c +++ b/trunk/drivers/regulator/wm831x-dcdc.c @@ -35,7 +35,7 @@ #define WM831X_DCDC_MODE_IDLE 2 #define WM831X_DCDC_MODE_STANDBY 3 -#define WM831X_DCDC_MAX_NAME 6 +#define WM831X_DCDC_MAX_NAME 9 /* Register offsets in control block */ #define WM831X_DCDC_CONTROL_1 0 @@ -50,6 +50,7 @@ struct wm831x_dcdc { char name[WM831X_DCDC_MAX_NAME]; + char supply_name[WM831X_DCDC_MAX_NAME]; struct regulator_desc desc; int base; struct wm831x *wm831x; @@ -60,41 +61,6 @@ struct wm831x_dcdc { int dvs_vsel; }; -static int wm831x_dcdc_is_enabled(struct regulator_dev *rdev) -{ - struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); - struct wm831x *wm831x = dcdc->wm831x; - int mask = 1 << rdev_get_id(rdev); - int reg; - - reg = wm831x_reg_read(wm831x, WM831X_DCDC_ENABLE); - if (reg < 0) - return reg; - - if (reg & mask) - return 1; - else - return 0; -} - -static int wm831x_dcdc_enable(struct regulator_dev *rdev) -{ - struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); - struct wm831x *wm831x = dcdc->wm831x; - int mask = 1 << rdev_get_id(rdev); - - return wm831x_set_bits(wm831x, WM831X_DCDC_ENABLE, mask, mask); -} - -static int wm831x_dcdc_disable(struct regulator_dev *rdev) -{ - struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); - struct wm831x *wm831x = dcdc->wm831x; - int mask = 1 << rdev_get_id(rdev); - - return wm831x_set_bits(wm831x, WM831X_DCDC_ENABLE, mask, 0); -} - static unsigned int wm831x_dcdc_get_mode(struct regulator_dev *rdev) { @@ -414,9 +380,9 @@ static struct regulator_ops wm831x_buckv_ops = { .set_current_limit = wm831x_buckv_set_current_limit, .get_current_limit = wm831x_buckv_get_current_limit, - .is_enabled = wm831x_dcdc_is_enabled, - .enable = wm831x_dcdc_enable, - .disable = wm831x_dcdc_disable, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, .get_status = wm831x_dcdc_get_status, .get_mode = wm831x_dcdc_get_mode, .set_mode = wm831x_dcdc_set_mode, @@ -437,23 +403,17 @@ static __devinit void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc, if (!pdata || !pdata->dvs_gpio) return; - ret = gpio_request(pdata->dvs_gpio, "DCDC DVS"); - if (ret < 0) { - dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %d\n", - dcdc->name, ret); - return; - } - /* gpiolib won't let us read the GPIO status so pick the higher * of the two existing voltages so we take it as platform data. */ dcdc->dvs_gpio_state = pdata->dvs_init_state; - ret = gpio_direction_output(pdata->dvs_gpio, dcdc->dvs_gpio_state); + ret = gpio_request_one(pdata->dvs_gpio, + dcdc->dvs_gpio_state ? GPIOF_INIT_HIGH : 0, + "DCDC DVS"); if (ret < 0) { - dev_err(wm831x->dev, "Failed to enable %s DVS GPIO: %d\n", + dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %d\n", dcdc->name, ret); - gpio_free(pdata->dvs_gpio); return; } @@ -498,6 +458,7 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; + struct regulator_config config = { }; int id; struct wm831x_dcdc *dcdc; struct resource *res; @@ -511,9 +472,6 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "Probing DCDC%d\n", id + 1); - if (pdata == NULL || pdata->dcdc[id] == NULL) - return -ENODEV; - dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc), GFP_KERNEL); if (dcdc == NULL) { @@ -533,11 +491,18 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev) snprintf(dcdc->name, sizeof(dcdc->name), "DCDC%d", id + 1); dcdc->desc.name = dcdc->name; + + snprintf(dcdc->supply_name, sizeof(dcdc->supply_name), + "DC%dVDD", id + 1); + dcdc->desc.supply_name = dcdc->supply_name; + dcdc->desc.id = id; dcdc->desc.type = REGULATOR_VOLTAGE; dcdc->desc.n_voltages = WM831X_BUCKV_MAX_SELECTOR + 1; dcdc->desc.ops = &wm831x_buckv_ops; dcdc->desc.owner = THIS_MODULE; + dcdc->desc.enable_reg = WM831X_DCDC_ENABLE; + dcdc->desc.enable_mask = 1 << id; ret = wm831x_reg_read(wm831x, dcdc->base + WM831X_DCDC_ON_CONFIG); if (ret < 0) { @@ -553,11 +518,16 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev) } dcdc->dvs_vsel = ret & WM831X_DC1_DVS_VSEL_MASK; - if (pdata->dcdc[id]) + if (pdata && pdata->dcdc[id]) wm831x_buckv_dvs_init(dcdc, pdata->dcdc[id]->driver_data); - dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev, - pdata->dcdc[id], dcdc, NULL); + config.dev = pdev->dev.parent; + if (pdata) + config.init_data = pdata->dcdc[id]; + config.driver_data = dcdc; + config.regmap = wm831x->regmap; + + dcdc->regulator = regulator_register(&dcdc->desc, &config); if (IS_ERR(dcdc->regulator)) { ret = PTR_ERR(dcdc->regulator); dev_err(wm831x->dev, "Failed to register DCDC%d: %d\n", @@ -675,29 +645,15 @@ static int wm831x_buckp_set_suspend_voltage(struct regulator_dev *rdev, return wm831x_buckp_set_voltage_int(rdev, reg, uV, uV, &selector); } -static int wm831x_buckp_get_voltage_sel(struct regulator_dev *rdev) -{ - struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); - struct wm831x *wm831x = dcdc->wm831x; - u16 reg = dcdc->base + WM831X_DCDC_ON_CONFIG; - int val; - - val = wm831x_reg_read(wm831x, reg); - if (val < 0) - return val; - - return val & WM831X_DC3_ON_VSEL_MASK; -} - static struct regulator_ops wm831x_buckp_ops = { .set_voltage = wm831x_buckp_set_voltage, - .get_voltage_sel = wm831x_buckp_get_voltage_sel, + .get_voltage_sel = regulator_get_voltage_sel_regmap, .list_voltage = wm831x_buckp_list_voltage, .set_suspend_voltage = wm831x_buckp_set_suspend_voltage, - .is_enabled = wm831x_dcdc_is_enabled, - .enable = wm831x_dcdc_enable, - .disable = wm831x_dcdc_disable, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, .get_status = wm831x_dcdc_get_status, .get_mode = wm831x_dcdc_get_mode, .set_mode = wm831x_dcdc_set_mode, @@ -708,6 +664,7 @@ static __devinit int wm831x_buckp_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; + struct regulator_config config = { }; int id; struct wm831x_dcdc *dcdc; struct resource *res; @@ -721,9 +678,6 @@ static __devinit int wm831x_buckp_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "Probing DCDC%d\n", id + 1); - if (pdata == NULL || pdata->dcdc[id] == NULL) - return -ENODEV; - dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc), GFP_KERNEL); if (dcdc == NULL) { @@ -743,14 +697,28 @@ static __devinit int wm831x_buckp_probe(struct platform_device *pdev) snprintf(dcdc->name, sizeof(dcdc->name), "DCDC%d", id + 1); dcdc->desc.name = dcdc->name; + + snprintf(dcdc->supply_name, sizeof(dcdc->supply_name), + "DC%dVDD", id + 1); + dcdc->desc.supply_name = dcdc->supply_name; + dcdc->desc.id = id; dcdc->desc.type = REGULATOR_VOLTAGE; dcdc->desc.n_voltages = WM831X_BUCKP_MAX_SELECTOR + 1; dcdc->desc.ops = &wm831x_buckp_ops; dcdc->desc.owner = THIS_MODULE; - - dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev, - pdata->dcdc[id], dcdc, NULL); + dcdc->desc.vsel_reg = dcdc->base + WM831X_DCDC_ON_CONFIG; + dcdc->desc.vsel_mask = WM831X_DC3_ON_VSEL_MASK; + dcdc->desc.enable_reg = WM831X_DCDC_ENABLE; + dcdc->desc.enable_mask = 1 << id; + + config.dev = pdev->dev.parent; + if (pdata) + config.init_data = pdata->dcdc[id]; + config.driver_data = dcdc; + config.regmap = wm831x->regmap; + + dcdc->regulator = regulator_register(&dcdc->desc, &config); if (IS_ERR(dcdc->regulator)) { ret = PTR_ERR(dcdc->regulator); dev_err(wm831x->dev, "Failed to register DCDC%d: %d\n", @@ -832,15 +800,16 @@ static int wm831x_boostp_get_status(struct regulator_dev *rdev) static struct regulator_ops wm831x_boostp_ops = { .get_status = wm831x_boostp_get_status, - .is_enabled = wm831x_dcdc_is_enabled, - .enable = wm831x_dcdc_enable, - .disable = wm831x_dcdc_disable, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, }; static __devinit int wm831x_boostp_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; + struct regulator_config config = { }; int id = pdev->id % ARRAY_SIZE(pdata->dcdc); struct wm831x_dcdc *dcdc; struct resource *res; @@ -851,7 +820,7 @@ static __devinit int wm831x_boostp_probe(struct platform_device *pdev) if (pdata == NULL || pdata->dcdc[id] == NULL) return -ENODEV; - dcdc = kzalloc(sizeof(struct wm831x_dcdc), GFP_KERNEL); + dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc), GFP_KERNEL); if (dcdc == NULL) { dev_err(&pdev->dev, "Unable to allocate private data\n"); return -ENOMEM; @@ -873,9 +842,16 @@ static __devinit int wm831x_boostp_probe(struct platform_device *pdev) dcdc->desc.type = REGULATOR_VOLTAGE; dcdc->desc.ops = &wm831x_boostp_ops; dcdc->desc.owner = THIS_MODULE; + dcdc->desc.enable_reg = WM831X_DCDC_ENABLE; + dcdc->desc.enable_mask = 1 << id; - dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev, - pdata->dcdc[id], dcdc, NULL); + config.dev = pdev->dev.parent; + if (pdata) + config.init_data = pdata->dcdc[id]; + config.driver_data = dcdc; + config.regmap = wm831x->regmap; + + dcdc->regulator = regulator_register(&dcdc->desc, &config); if (IS_ERR(dcdc->regulator)) { ret = PTR_ERR(dcdc->regulator); dev_err(wm831x->dev, "Failed to register DCDC%d: %d\n", @@ -900,7 +876,6 @@ static __devinit int wm831x_boostp_probe(struct platform_device *pdev) err_regulator: regulator_unregister(dcdc->regulator); err: - kfree(dcdc); return ret; } @@ -912,7 +887,6 @@ static __devexit int wm831x_boostp_remove(struct platform_device *pdev) free_irq(platform_get_irq_byname(pdev, "UV"), dcdc); regulator_unregister(dcdc->regulator); - kfree(dcdc); return 0; } @@ -936,9 +910,9 @@ static struct platform_driver wm831x_boostp_driver = { #define WM831X_EPE_BASE 6 static struct regulator_ops wm831x_epe_ops = { - .is_enabled = wm831x_dcdc_is_enabled, - .enable = wm831x_dcdc_enable, - .disable = wm831x_dcdc_disable, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, .get_status = wm831x_dcdc_get_status, }; @@ -946,16 +920,14 @@ static __devinit int wm831x_epe_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; + struct regulator_config config = { }; int id = pdev->id % ARRAY_SIZE(pdata->epe); struct wm831x_dcdc *dcdc; int ret; dev_dbg(&pdev->dev, "Probing EPE%d\n", id + 1); - if (pdata == NULL || pdata->epe[id] == NULL) - return -ENODEV; - - dcdc = kzalloc(sizeof(struct wm831x_dcdc), GFP_KERNEL); + dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc), GFP_KERNEL); if (dcdc == NULL) { dev_err(&pdev->dev, "Unable to allocate private data\n"); return -ENOMEM; @@ -972,9 +944,16 @@ static __devinit int wm831x_epe_probe(struct platform_device *pdev) dcdc->desc.ops = &wm831x_epe_ops; dcdc->desc.type = REGULATOR_VOLTAGE; dcdc->desc.owner = THIS_MODULE; + dcdc->desc.enable_reg = WM831X_DCDC_ENABLE; + dcdc->desc.enable_mask = 1 << dcdc->desc.id; + + config.dev = pdev->dev.parent; + if (pdata) + config.init_data = pdata->epe[id]; + config.driver_data = dcdc; + config.regmap = wm831x->regmap; - dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev, - pdata->epe[id], dcdc, NULL); + dcdc->regulator = regulator_register(&dcdc->desc, &config); if (IS_ERR(dcdc->regulator)) { ret = PTR_ERR(dcdc->regulator); dev_err(wm831x->dev, "Failed to register EPE%d: %d\n", @@ -987,7 +966,6 @@ static __devinit int wm831x_epe_probe(struct platform_device *pdev) return 0; err: - kfree(dcdc); return ret; } @@ -996,9 +974,7 @@ static __devexit int wm831x_epe_remove(struct platform_device *pdev) struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev); platform_set_drvdata(pdev, NULL); - regulator_unregister(dcdc->regulator); - kfree(dcdc); return 0; } diff --git a/trunk/drivers/regulator/wm831x-isink.c b/trunk/drivers/regulator/wm831x-isink.c index b414e09c5620..b50ab778b098 100644 --- a/trunk/drivers/regulator/wm831x-isink.c +++ b/trunk/drivers/regulator/wm831x-isink.c @@ -154,6 +154,7 @@ static __devinit int wm831x_isink_probe(struct platform_device *pdev) struct wm831x_pdata *pdata = wm831x->dev->platform_data; struct wm831x_isink *isink; int id = pdev->id % ARRAY_SIZE(pdata->isink); + struct regulator_config config = { }; struct resource *res; int ret, irq; @@ -189,8 +190,11 @@ static __devinit int wm831x_isink_probe(struct platform_device *pdev) isink->desc.type = REGULATOR_CURRENT; isink->desc.owner = THIS_MODULE; - isink->regulator = regulator_register(&isink->desc, &pdev->dev, - pdata->isink[id], isink, NULL); + config.dev = pdev->dev.parent; + config.init_data = pdata->isink[id]; + config.driver_data = isink; + + isink->regulator = regulator_register(&isink->desc, &config); if (IS_ERR(isink->regulator)) { ret = PTR_ERR(isink->regulator); dev_err(wm831x->dev, "Failed to register ISINK%d: %d\n", diff --git a/trunk/drivers/regulator/wm831x-ldo.c b/trunk/drivers/regulator/wm831x-ldo.c index 641e9f6499d1..aa1f8b3fbe16 100644 --- a/trunk/drivers/regulator/wm831x-ldo.c +++ b/trunk/drivers/regulator/wm831x-ldo.c @@ -25,7 +25,7 @@ #include #include -#define WM831X_LDO_MAX_NAME 6 +#define WM831X_LDO_MAX_NAME 9 #define WM831X_LDO_CONTROL 0 #define WM831X_LDO_ON_CONTROL 1 @@ -36,6 +36,7 @@ struct wm831x_ldo { char name[WM831X_LDO_MAX_NAME]; + char supply_name[WM831X_LDO_MAX_NAME]; struct regulator_desc desc; int base; struct wm831x *wm831x; @@ -46,41 +47,6 @@ struct wm831x_ldo { * Shared */ -static int wm831x_ldo_is_enabled(struct regulator_dev *rdev) -{ - struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); - struct wm831x *wm831x = ldo->wm831x; - int mask = 1 << rdev_get_id(rdev); - int reg; - - reg = wm831x_reg_read(wm831x, WM831X_LDO_ENABLE); - if (reg < 0) - return reg; - - if (reg & mask) - return 1; - else - return 0; -} - -static int wm831x_ldo_enable(struct regulator_dev *rdev) -{ - struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); - struct wm831x *wm831x = ldo->wm831x; - int mask = 1 << rdev_get_id(rdev); - - return wm831x_set_bits(wm831x, WM831X_LDO_ENABLE, mask, mask); -} - -static int wm831x_ldo_disable(struct regulator_dev *rdev) -{ - struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); - struct wm831x *wm831x = ldo->wm831x; - int mask = 1 << rdev_get_id(rdev); - - return wm831x_set_bits(wm831x, WM831X_LDO_ENABLE, mask, 0); -} - static irqreturn_t wm831x_ldo_uv_irq(int irq, void *data) { struct wm831x_ldo *ldo = data; @@ -105,7 +71,7 @@ static int wm831x_gp_ldo_list_voltage(struct regulator_dev *rdev, /* 0.9-1.6V in 50mV steps */ if (selector <= WM831X_GP_LDO_SELECTOR_LOW) return 900000 + (selector * 50000); - /* 1.7-3.3V in 50mV steps */ + /* 1.7-3.3V in 100mV steps */ if (selector <= WM831X_GP_LDO_MAX_SELECTOR) return 1600000 + ((selector - WM831X_GP_LDO_SELECTOR_LOW) * 100000); @@ -160,22 +126,6 @@ static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev, return wm831x_gp_ldo_set_voltage_int(rdev, reg, uV, uV, &selector); } -static int wm831x_gp_ldo_get_voltage_sel(struct regulator_dev *rdev) -{ - struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); - struct wm831x *wm831x = ldo->wm831x; - int reg = ldo->base + WM831X_LDO_ON_CONTROL; - int ret; - - ret = wm831x_reg_read(wm831x, reg); - if (ret < 0) - return ret; - - ret &= WM831X_LDO1_ON_VSEL_MASK; - - return ret; -} - static unsigned int wm831x_gp_ldo_get_mode(struct regulator_dev *rdev) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); @@ -293,7 +243,7 @@ static unsigned int wm831x_gp_ldo_get_optimum_mode(struct regulator_dev *rdev, static struct regulator_ops wm831x_gp_ldo_ops = { .list_voltage = wm831x_gp_ldo_list_voltage, - .get_voltage_sel = wm831x_gp_ldo_get_voltage_sel, + .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage = wm831x_gp_ldo_set_voltage, .set_suspend_voltage = wm831x_gp_ldo_set_suspend_voltage, .get_mode = wm831x_gp_ldo_get_mode, @@ -301,15 +251,16 @@ static struct regulator_ops wm831x_gp_ldo_ops = { .get_status = wm831x_gp_ldo_get_status, .get_optimum_mode = wm831x_gp_ldo_get_optimum_mode, - .is_enabled = wm831x_ldo_is_enabled, - .enable = wm831x_ldo_enable, - .disable = wm831x_ldo_disable, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, }; static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; + struct regulator_config config = { }; int id; struct wm831x_ldo *ldo; struct resource *res; @@ -323,9 +274,6 @@ static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1); - if (pdata == NULL || pdata->ldo[id] == NULL) - return -ENODEV; - ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL); if (ldo == NULL) { dev_err(&pdev->dev, "Unable to allocate private data\n"); @@ -344,14 +292,28 @@ static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev) snprintf(ldo->name, sizeof(ldo->name), "LDO%d", id + 1); ldo->desc.name = ldo->name; + + snprintf(ldo->supply_name, sizeof(ldo->supply_name), + "LDO%dVDD", id + 1); + ldo->desc.supply_name = ldo->supply_name; + ldo->desc.id = id; ldo->desc.type = REGULATOR_VOLTAGE; ldo->desc.n_voltages = WM831X_GP_LDO_MAX_SELECTOR + 1; ldo->desc.ops = &wm831x_gp_ldo_ops; ldo->desc.owner = THIS_MODULE; - - ldo->regulator = regulator_register(&ldo->desc, &pdev->dev, - pdata->ldo[id], ldo, NULL); + ldo->desc.vsel_reg = ldo->base + WM831X_LDO_ON_CONTROL; + ldo->desc.vsel_mask = WM831X_LDO1_ON_VSEL_MASK; + ldo->desc.enable_reg = WM831X_LDO_ENABLE; + ldo->desc.enable_mask = 1 << id; + + config.dev = pdev->dev.parent; + if (pdata) + config.init_data = pdata->ldo[id]; + config.driver_data = ldo; + config.regmap = wm831x->regmap; + + ldo->regulator = regulator_register(&ldo->desc, &config); if (IS_ERR(ldo->regulator)) { ret = PTR_ERR(ldo->regulator); dev_err(wm831x->dev, "Failed to register LDO%d: %d\n", @@ -414,7 +376,7 @@ static int wm831x_aldo_list_voltage(struct regulator_dev *rdev, /* 1-1.6V in 50mV steps */ if (selector <= WM831X_ALDO_SELECTOR_LOW) return 1000000 + (selector * 50000); - /* 1.7-3.5V in 50mV steps */ + /* 1.7-3.5V in 100mV steps */ if (selector <= WM831X_ALDO_MAX_SELECTOR) return 1600000 + ((selector - WM831X_ALDO_SELECTOR_LOW) * 100000); @@ -468,22 +430,6 @@ static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev, return wm831x_aldo_set_voltage_int(rdev, reg, uV, uV, &selector); } -static int wm831x_aldo_get_voltage_sel(struct regulator_dev *rdev) -{ - struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); - struct wm831x *wm831x = ldo->wm831x; - int reg = ldo->base + WM831X_LDO_ON_CONTROL; - int ret; - - ret = wm831x_reg_read(wm831x, reg); - if (ret < 0) - return ret; - - ret &= WM831X_LDO7_ON_VSEL_MASK; - - return ret; -} - static unsigned int wm831x_aldo_get_mode(struct regulator_dev *rdev) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); @@ -559,22 +505,23 @@ static int wm831x_aldo_get_status(struct regulator_dev *rdev) static struct regulator_ops wm831x_aldo_ops = { .list_voltage = wm831x_aldo_list_voltage, - .get_voltage_sel = wm831x_aldo_get_voltage_sel, + .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage = wm831x_aldo_set_voltage, .set_suspend_voltage = wm831x_aldo_set_suspend_voltage, .get_mode = wm831x_aldo_get_mode, .set_mode = wm831x_aldo_set_mode, .get_status = wm831x_aldo_get_status, - .is_enabled = wm831x_ldo_is_enabled, - .enable = wm831x_ldo_enable, - .disable = wm831x_ldo_disable, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, }; static __devinit int wm831x_aldo_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; + struct regulator_config config = { }; int id; struct wm831x_ldo *ldo; struct resource *res; @@ -588,9 +535,6 @@ static __devinit int wm831x_aldo_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1); - if (pdata == NULL || pdata->ldo[id] == NULL) - return -ENODEV; - ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL); if (ldo == NULL) { dev_err(&pdev->dev, "Unable to allocate private data\n"); @@ -609,14 +553,28 @@ static __devinit int wm831x_aldo_probe(struct platform_device *pdev) snprintf(ldo->name, sizeof(ldo->name), "LDO%d", id + 1); ldo->desc.name = ldo->name; + + snprintf(ldo->supply_name, sizeof(ldo->supply_name), + "LDO%dVDD", id + 1); + ldo->desc.supply_name = ldo->supply_name; + ldo->desc.id = id; ldo->desc.type = REGULATOR_VOLTAGE; ldo->desc.n_voltages = WM831X_ALDO_MAX_SELECTOR + 1; ldo->desc.ops = &wm831x_aldo_ops; ldo->desc.owner = THIS_MODULE; - - ldo->regulator = regulator_register(&ldo->desc, &pdev->dev, - pdata->ldo[id], ldo, NULL); + ldo->desc.vsel_reg = ldo->base + WM831X_LDO_ON_CONTROL; + ldo->desc.vsel_mask = WM831X_LDO7_ON_VSEL_MASK; + ldo->desc.enable_reg = WM831X_LDO_ENABLE; + ldo->desc.enable_mask = 1 << id; + + config.dev = pdev->dev.parent; + if (pdata) + config.init_data = pdata->ldo[id]; + config.driver_data = ldo; + config.regmap = wm831x->regmap; + + ldo->regulator = regulator_register(&ldo->desc, &config); if (IS_ERR(ldo->regulator)) { ret = PTR_ERR(ldo->regulator); dev_err(wm831x->dev, "Failed to register LDO%d: %d\n", @@ -668,15 +626,6 @@ static struct platform_driver wm831x_aldo_driver = { #define WM831X_ALIVE_LDO_MAX_SELECTOR 0xf -static int wm831x_alive_ldo_list_voltage(struct regulator_dev *rdev, - unsigned int selector) -{ - /* 0.8-1.55V in 50mV steps */ - if (selector <= WM831X_ALIVE_LDO_MAX_SELECTOR) - return 800000 + (selector * 50000); - return -EINVAL; -} - static int wm831x_alive_ldo_set_voltage_int(struct regulator_dev *rdev, int reg, int min_uV, int max_uV, @@ -688,7 +637,7 @@ static int wm831x_alive_ldo_set_voltage_int(struct regulator_dev *rdev, vsel = (min_uV - 800000) / 50000; - ret = wm831x_alive_ldo_list_voltage(rdev, vsel); + ret = regulator_list_voltage_linear(rdev, vsel); if (ret < 0) return ret; if (ret < min_uV || ret > max_uV) @@ -720,22 +669,6 @@ static int wm831x_alive_ldo_set_suspend_voltage(struct regulator_dev *rdev, return wm831x_alive_ldo_set_voltage_int(rdev, reg, uV, uV, &selector); } -static int wm831x_alive_ldo_get_voltage_sel(struct regulator_dev *rdev) -{ - struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); - struct wm831x *wm831x = ldo->wm831x; - int reg = ldo->base + WM831X_ALIVE_LDO_ON_CONTROL; - int ret; - - ret = wm831x_reg_read(wm831x, reg); - if (ret < 0) - return ret; - - ret &= WM831X_LDO11_ON_VSEL_MASK; - - return ret; -} - static int wm831x_alive_ldo_get_status(struct regulator_dev *rdev) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); @@ -754,21 +687,22 @@ static int wm831x_alive_ldo_get_status(struct regulator_dev *rdev) } static struct regulator_ops wm831x_alive_ldo_ops = { - .list_voltage = wm831x_alive_ldo_list_voltage, - .get_voltage_sel = wm831x_alive_ldo_get_voltage_sel, + .list_voltage = regulator_list_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage = wm831x_alive_ldo_set_voltage, .set_suspend_voltage = wm831x_alive_ldo_set_suspend_voltage, .get_status = wm831x_alive_ldo_get_status, - .is_enabled = wm831x_ldo_is_enabled, - .enable = wm831x_ldo_enable, - .disable = wm831x_ldo_disable, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, }; static __devinit int wm831x_alive_ldo_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; + struct regulator_config config = { }; int id; struct wm831x_ldo *ldo; struct resource *res; @@ -783,9 +717,6 @@ static __devinit int wm831x_alive_ldo_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1); - if (pdata == NULL || pdata->ldo[id] == NULL) - return -ENODEV; - ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL); if (ldo == NULL) { dev_err(&pdev->dev, "Unable to allocate private data\n"); @@ -804,14 +735,30 @@ static __devinit int wm831x_alive_ldo_probe(struct platform_device *pdev) snprintf(ldo->name, sizeof(ldo->name), "LDO%d", id + 1); ldo->desc.name = ldo->name; + + snprintf(ldo->supply_name, sizeof(ldo->supply_name), + "LDO%dVDD", id + 1); + ldo->desc.supply_name = ldo->supply_name; + ldo->desc.id = id; ldo->desc.type = REGULATOR_VOLTAGE; ldo->desc.n_voltages = WM831X_ALIVE_LDO_MAX_SELECTOR + 1; ldo->desc.ops = &wm831x_alive_ldo_ops; ldo->desc.owner = THIS_MODULE; - - ldo->regulator = regulator_register(&ldo->desc, &pdev->dev, - pdata->ldo[id], ldo, NULL); + ldo->desc.vsel_reg = ldo->base + WM831X_ALIVE_LDO_ON_CONTROL; + ldo->desc.vsel_mask = WM831X_LDO11_ON_VSEL_MASK; + ldo->desc.enable_reg = WM831X_LDO_ENABLE; + ldo->desc.enable_mask = 1 << id; + ldo->desc.min_uV = 800000; + ldo->desc.uV_step = 50000; + + config.dev = pdev->dev.parent; + if (pdata) + config.init_data = pdata->ldo[id]; + config.driver_data = ldo; + config.regmap = wm831x->regmap; + + ldo->regulator = regulator_register(&ldo->desc, &config); if (IS_ERR(ldo->regulator)) { ret = PTR_ERR(ldo->regulator); dev_err(wm831x->dev, "Failed to register LDO%d: %d\n", diff --git a/trunk/drivers/regulator/wm8350-regulator.c b/trunk/drivers/regulator/wm8350-regulator.c index 05ecfb872319..94e550dc70b6 100644 --- a/trunk/drivers/regulator/wm8350-regulator.c +++ b/trunk/drivers/regulator/wm8350-regulator.c @@ -1269,7 +1269,7 @@ static struct regulator_ops wm8350_isink_ops = { .enable_time = wm8350_isink_enable_time, }; -static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { +static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { { .name = "DCDC1", .id = WM8350_DCDC_1, @@ -1398,6 +1398,7 @@ static irqreturn_t pmic_uv_handler(int irq, void *data) static int wm8350_regulator_probe(struct platform_device *pdev) { struct wm8350 *wm8350 = dev_get_drvdata(&pdev->dev); + struct regulator_config config = { }; struct regulator_dev *rdev; int ret; u16 val; @@ -1425,10 +1426,12 @@ static int wm8350_regulator_probe(struct platform_device *pdev) break; } + config.dev = &pdev->dev; + config.init_data = pdev->dev.platform_data; + config.driver_data = dev_get_drvdata(&pdev->dev); + /* register regulator */ - rdev = regulator_register(&wm8350_reg[pdev->id], &pdev->dev, - pdev->dev.platform_data, - dev_get_drvdata(&pdev->dev), NULL); + rdev = regulator_register(&wm8350_reg[pdev->id], &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register %s\n", wm8350_reg[pdev->id].name); diff --git a/trunk/drivers/regulator/wm8400-regulator.c b/trunk/drivers/regulator/wm8400-regulator.c index 8477153780b6..69a2b7ce5e4a 100644 --- a/trunk/drivers/regulator/wm8400-regulator.c +++ b/trunk/drivers/regulator/wm8400-regulator.c @@ -19,31 +19,6 @@ #include #include -static int wm8400_ldo_is_enabled(struct regulator_dev *dev) -{ - struct wm8400 *wm8400 = rdev_get_drvdata(dev); - u16 val; - - val = wm8400_reg_read(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev)); - return (val & WM8400_LDO1_ENA) != 0; -} - -static int wm8400_ldo_enable(struct regulator_dev *dev) -{ - struct wm8400 *wm8400 = rdev_get_drvdata(dev); - - return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev), - WM8400_LDO1_ENA, WM8400_LDO1_ENA); -} - -static int wm8400_ldo_disable(struct regulator_dev *dev) -{ - struct wm8400 *wm8400 = rdev_get_drvdata(dev); - - return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev), - WM8400_LDO1_ENA, 0); -} - static int wm8400_ldo_list_voltage(struct regulator_dev *dev, unsigned selector) { @@ -56,21 +31,9 @@ static int wm8400_ldo_list_voltage(struct regulator_dev *dev, return 1600000 + ((selector - 14) * 100000); } -static int wm8400_ldo_get_voltage_sel(struct regulator_dev *dev) +static int wm8400_ldo_map_voltage(struct regulator_dev *dev, + int min_uV, int max_uV) { - struct wm8400 *wm8400 = rdev_get_drvdata(dev); - u16 val; - - val = wm8400_reg_read(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev)); - val &= WM8400_LDO1_VSEL_MASK; - - return val; -} - -static int wm8400_ldo_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV, unsigned *selector) -{ - struct wm8400 *wm8400 = rdev_get_drvdata(dev); u16 val; if (min_uV < 900000 || min_uV > 3300000) @@ -94,92 +57,19 @@ static int wm8400_ldo_set_voltage(struct regulator_dev *dev, val += 0xf; } - *selector = val; - - return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev), - WM8400_LDO1_VSEL_MASK, val); + return val; } static struct regulator_ops wm8400_ldo_ops = { - .is_enabled = wm8400_ldo_is_enabled, - .enable = wm8400_ldo_enable, - .disable = wm8400_ldo_disable, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, .list_voltage = wm8400_ldo_list_voltage, - .get_voltage_sel = wm8400_ldo_get_voltage_sel, - .set_voltage = wm8400_ldo_set_voltage, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .map_voltage = wm8400_ldo_map_voltage, }; -static int wm8400_dcdc_is_enabled(struct regulator_dev *dev) -{ - struct wm8400 *wm8400 = rdev_get_drvdata(dev); - int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2; - u16 val; - - val = wm8400_reg_read(wm8400, WM8400_DCDC1_CONTROL_1 + offset); - return (val & WM8400_DC1_ENA) != 0; -} - -static int wm8400_dcdc_enable(struct regulator_dev *dev) -{ - struct wm8400 *wm8400 = rdev_get_drvdata(dev); - int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2; - - return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset, - WM8400_DC1_ENA, WM8400_DC1_ENA); -} - -static int wm8400_dcdc_disable(struct regulator_dev *dev) -{ - struct wm8400 *wm8400 = rdev_get_drvdata(dev); - int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2; - - return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset, - WM8400_DC1_ENA, 0); -} - -static int wm8400_dcdc_list_voltage(struct regulator_dev *dev, - unsigned selector) -{ - if (selector > WM8400_DC1_VSEL_MASK) - return -EINVAL; - - return 850000 + (selector * 25000); -} - -static int wm8400_dcdc_get_voltage_sel(struct regulator_dev *dev) -{ - struct wm8400 *wm8400 = rdev_get_drvdata(dev); - u16 val; - int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2; - - val = wm8400_reg_read(wm8400, WM8400_DCDC1_CONTROL_1 + offset); - val &= WM8400_DC1_VSEL_MASK; - - return val; -} - -static int wm8400_dcdc_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV, unsigned *selector) -{ - struct wm8400 *wm8400 = rdev_get_drvdata(dev); - u16 val; - int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2; - - if (min_uV < 850000) - return -EINVAL; - - val = DIV_ROUND_UP(min_uV - 850000, 25000); - - if (850000 + (25000 * val) > max_uV) - return -EINVAL; - BUG_ON(850000 + (25000 * val) < min_uV); - - *selector = val; - - return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset, - WM8400_DC1_VSEL_MASK, val); -} - static unsigned int wm8400_dcdc_get_mode(struct regulator_dev *dev) { struct wm8400 *wm8400 = rdev_get_drvdata(dev); @@ -258,12 +148,12 @@ static unsigned int wm8400_dcdc_get_optimum_mode(struct regulator_dev *dev, } static struct regulator_ops wm8400_dcdc_ops = { - .is_enabled = wm8400_dcdc_is_enabled, - .enable = wm8400_dcdc_enable, - .disable = wm8400_dcdc_disable, - .list_voltage = wm8400_dcdc_list_voltage, - .get_voltage_sel = wm8400_dcdc_get_voltage_sel, - .set_voltage = wm8400_dcdc_set_voltage, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .list_voltage = regulator_list_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_mode = wm8400_dcdc_get_mode, .set_mode = wm8400_dcdc_set_mode, .get_optimum_mode = wm8400_dcdc_get_optimum_mode, @@ -274,7 +164,11 @@ static struct regulator_desc regulators[] = { .name = "LDO1", .id = WM8400_LDO1, .ops = &wm8400_ldo_ops, + .enable_reg = WM8400_LDO1_CONTROL, + .enable_mask = WM8400_LDO1_ENA, .n_voltages = WM8400_LDO1_VSEL_MASK + 1, + .vsel_reg = WM8400_LDO1_CONTROL, + .vsel_mask = WM8400_LDO1_VSEL_MASK, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, @@ -282,15 +176,23 @@ static struct regulator_desc regulators[] = { .name = "LDO2", .id = WM8400_LDO2, .ops = &wm8400_ldo_ops, + .enable_reg = WM8400_LDO2_CONTROL, + .enable_mask = WM8400_LDO2_ENA, .n_voltages = WM8400_LDO2_VSEL_MASK + 1, .type = REGULATOR_VOLTAGE, + .vsel_reg = WM8400_LDO2_CONTROL, + .vsel_mask = WM8400_LDO2_VSEL_MASK, .owner = THIS_MODULE, }, { .name = "LDO3", .id = WM8400_LDO3, .ops = &wm8400_ldo_ops, + .enable_reg = WM8400_LDO3_CONTROL, + .enable_mask = WM8400_LDO3_ENA, .n_voltages = WM8400_LDO3_VSEL_MASK + 1, + .vsel_reg = WM8400_LDO3_CONTROL, + .vsel_mask = WM8400_LDO3_VSEL_MASK, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, @@ -298,7 +200,11 @@ static struct regulator_desc regulators[] = { .name = "LDO4", .id = WM8400_LDO4, .ops = &wm8400_ldo_ops, + .enable_reg = WM8400_LDO4_CONTROL, + .enable_mask = WM8400_LDO4_ENA, .n_voltages = WM8400_LDO4_VSEL_MASK + 1, + .vsel_reg = WM8400_LDO4_CONTROL, + .vsel_mask = WM8400_LDO4_VSEL_MASK, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, @@ -306,7 +212,13 @@ static struct regulator_desc regulators[] = { .name = "DCDC1", .id = WM8400_DCDC1, .ops = &wm8400_dcdc_ops, + .enable_reg = WM8400_DCDC1_CONTROL_1, + .enable_mask = WM8400_DC1_ENA_MASK, .n_voltages = WM8400_DC1_VSEL_MASK + 1, + .vsel_reg = WM8400_DCDC1_CONTROL_1, + .vsel_mask = WM8400_DC1_VSEL_MASK, + .min_uV = 850000, + .uV_step = 25000, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, @@ -314,7 +226,13 @@ static struct regulator_desc regulators[] = { .name = "DCDC2", .id = WM8400_DCDC2, .ops = &wm8400_dcdc_ops, + .enable_reg = WM8400_DCDC2_CONTROL_1, + .enable_mask = WM8400_DC1_ENA_MASK, .n_voltages = WM8400_DC2_VSEL_MASK + 1, + .vsel_reg = WM8400_DCDC2_CONTROL_1, + .vsel_mask = WM8400_DC2_VSEL_MASK, + .min_uV = 850000, + .uV_step = 25000, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, @@ -323,11 +241,15 @@ static struct regulator_desc regulators[] = { static int __devinit wm8400_regulator_probe(struct platform_device *pdev) { struct wm8400 *wm8400 = container_of(pdev, struct wm8400, regulators[pdev->id]); + struct regulator_config config = { }; struct regulator_dev *rdev; - rdev = regulator_register(®ulators[pdev->id], &pdev->dev, - pdev->dev.platform_data, wm8400, NULL); + config.dev = &pdev->dev; + config.init_data = pdev->dev.platform_data; + config.driver_data = wm8400; + config.regmap = wm8400->regmap; + rdev = regulator_register(®ulators[pdev->id], &config); if (IS_ERR(rdev)) return PTR_ERR(rdev); diff --git a/trunk/drivers/regulator/wm8994-regulator.c b/trunk/drivers/regulator/wm8994-regulator.c index 75ed402d9f43..9a994316e63c 100644 --- a/trunk/drivers/regulator/wm8994-regulator.c +++ b/trunk/drivers/regulator/wm8994-regulator.c @@ -86,36 +86,6 @@ static int wm8994_ldo1_list_voltage(struct regulator_dev *rdev, return (selector * 100000) + 2400000; } -static int wm8994_ldo1_get_voltage_sel(struct regulator_dev *rdev) -{ - struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); - int val; - - val = wm8994_reg_read(ldo->wm8994, WM8994_LDO_1); - if (val < 0) - return val; - - return (val & WM8994_LDO1_VSEL_MASK) >> WM8994_LDO1_VSEL_SHIFT; -} - -static int wm8994_ldo1_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned *s) -{ - struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); - int selector, v; - - selector = (min_uV - 2400000) / 100000; - v = wm8994_ldo1_list_voltage(rdev, selector); - if (v < 0 || v > max_uV) - return -EINVAL; - - *s = selector; - selector <<= WM8994_LDO1_VSEL_SHIFT; - - return wm8994_set_bits(ldo->wm8994, WM8994_LDO_1, - WM8994_LDO1_VSEL_MASK, selector); -} - static struct regulator_ops wm8994_ldo1_ops = { .enable = wm8994_ldo_enable, .disable = wm8994_ldo_disable, @@ -123,8 +93,8 @@ static struct regulator_ops wm8994_ldo1_ops = { .enable_time = wm8994_ldo_enable_time, .list_voltage = wm8994_ldo1_list_voltage, - .get_voltage_sel = wm8994_ldo1_get_voltage_sel, - .set_voltage = wm8994_ldo1_set_voltage, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, }; static int wm8994_ldo2_list_voltage(struct regulator_dev *rdev, @@ -153,51 +123,6 @@ static int wm8994_ldo2_list_voltage(struct regulator_dev *rdev, } } -static int wm8994_ldo2_get_voltage_sel(struct regulator_dev *rdev) -{ - struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); - int val; - - val = wm8994_reg_read(ldo->wm8994, WM8994_LDO_2); - if (val < 0) - return val; - - return (val & WM8994_LDO2_VSEL_MASK) >> WM8994_LDO2_VSEL_SHIFT; -} - -static int wm8994_ldo2_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned *s) -{ - struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); - int selector, v; - - switch (ldo->wm8994->type) { - case WM8994: - selector = (min_uV - 900000) / 100000; - break; - case WM8958: - selector = (min_uV - 1000000) / 100000; - break; - case WM1811: - selector = (min_uV - 950000) / 100000; - if (selector == 0) - selector = 1; - break; - default: - return -EINVAL; - } - - v = wm8994_ldo2_list_voltage(rdev, selector); - if (v < 0 || v > max_uV) - return -EINVAL; - - *s = selector; - selector <<= WM8994_LDO2_VSEL_SHIFT; - - return wm8994_set_bits(ldo->wm8994, WM8994_LDO_2, - WM8994_LDO2_VSEL_MASK, selector); -} - static struct regulator_ops wm8994_ldo2_ops = { .enable = wm8994_ldo_enable, .disable = wm8994_ldo_disable, @@ -205,16 +130,18 @@ static struct regulator_ops wm8994_ldo2_ops = { .enable_time = wm8994_ldo_enable_time, .list_voltage = wm8994_ldo2_list_voltage, - .get_voltage_sel = wm8994_ldo2_get_voltage_sel, - .set_voltage = wm8994_ldo2_set_voltage, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, }; -static struct regulator_desc wm8994_ldo_desc[] = { +static const struct regulator_desc wm8994_ldo_desc[] = { { .name = "LDO1", .id = 1, .type = REGULATOR_VOLTAGE, .n_voltages = WM8994_LDO1_MAX_SELECTOR + 1, + .vsel_reg = WM8994_LDO_1, + .vsel_mask = WM8994_LDO1_VSEL_MASK, .ops = &wm8994_ldo1_ops, .owner = THIS_MODULE, }, @@ -223,6 +150,8 @@ static struct regulator_desc wm8994_ldo_desc[] = { .id = 2, .type = REGULATOR_VOLTAGE, .n_voltages = WM8994_LDO2_MAX_SELECTOR + 1, + .vsel_reg = WM8994_LDO_2, + .vsel_mask = WM8994_LDO2_VSEL_MASK, .ops = &wm8994_ldo2_ops, .owner = THIS_MODULE, }, @@ -233,14 +162,12 @@ static __devinit int wm8994_ldo_probe(struct platform_device *pdev) struct wm8994 *wm8994 = dev_get_drvdata(pdev->dev.parent); struct wm8994_pdata *pdata = wm8994->dev->platform_data; int id = pdev->id % ARRAY_SIZE(pdata->ldo); + struct regulator_config config = { }; struct wm8994_ldo *ldo; int ret; dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1); - if (!pdata) - return -ENODEV; - ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm8994_ldo), GFP_KERNEL); if (ldo == NULL) { dev_err(&pdev->dev, "Unable to allocate private data\n"); @@ -252,24 +179,22 @@ static __devinit int wm8994_ldo_probe(struct platform_device *pdev) if (pdata->ldo[id].enable && gpio_is_valid(pdata->ldo[id].enable)) { ldo->enable = pdata->ldo[id].enable; - ret = gpio_request(ldo->enable, "WM8994 LDO enable"); + ret = gpio_request_one(ldo->enable, 0, "WM8994 LDO enable"); if (ret < 0) { dev_err(&pdev->dev, "Failed to get enable GPIO: %d\n", ret); goto err; } - - ret = gpio_direction_output(ldo->enable, ldo->is_enabled); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to set GPIO up: %d\n", - ret); - goto err_gpio; - } } else ldo->is_enabled = true; - ldo->regulator = regulator_register(&wm8994_ldo_desc[id], &pdev->dev, - pdata->ldo[id].init_data, ldo, NULL); + config.dev = wm8994->dev; + config.driver_data = ldo; + config.regmap = wm8994->regmap; + if (pdata) + config.init_data = pdata->ldo[id].init_data; + + ldo->regulator = regulator_register(&wm8994_ldo_desc[id], &config); if (IS_ERR(ldo->regulator)) { ret = PTR_ERR(ldo->regulator); dev_err(wm8994->dev, "Failed to register LDO%d: %d\n", diff --git a/trunk/drivers/remoteproc/remoteproc_core.c b/trunk/drivers/remoteproc/remoteproc_core.c index e756a0df3664..d6f8adaa26ef 100644 --- a/trunk/drivers/remoteproc/remoteproc_core.c +++ b/trunk/drivers/remoteproc/remoteproc_core.c @@ -1105,8 +1105,7 @@ static void rproc_fw_config_virtio(const struct firmware *fw, void *context) goto out; out: - if (fw) - release_firmware(fw); + release_firmware(fw); /* allow rproc_unregister() contexts, if any, to proceed */ complete_all(&rproc->firmware_loading_complete); } diff --git a/trunk/drivers/rtc/Kconfig b/trunk/drivers/rtc/Kconfig index 8c8377d50c4c..4161bfe462cd 100644 --- a/trunk/drivers/rtc/Kconfig +++ b/trunk/drivers/rtc/Kconfig @@ -838,7 +838,7 @@ config RTC_DRV_AT32AP700X config RTC_DRV_AT91RM9200 tristate "AT91RM9200 or some AT91SAM9 RTC" - depends on ARCH_AT91RM9200 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 + depends on ARCH_AT91 help Driver for the internal RTC (Realtime Clock) module found on Atmel AT91RM9200's and some AT91SAM9 chips. On AT91SAM9 chips diff --git a/trunk/drivers/rtc/rtc-pl031.c b/trunk/drivers/rtc/rtc-pl031.c index 684ef4bbfce4..f027c063fb20 100644 --- a/trunk/drivers/rtc/rtc-pl031.c +++ b/trunk/drivers/rtc/rtc-pl031.c @@ -312,6 +312,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id) int ret; struct pl031_local *ldata; struct rtc_class_ops *ops = id->data; + unsigned long time; ret = amba_request_regions(adev, NULL); if (ret) @@ -343,6 +344,23 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id) writel(readl(ldata->base + RTC_CR) | RTC_CR_CWEN, ldata->base + RTC_CR); + /* + * On ST PL031 variants, the RTC reset value does not provide correct + * weekday for 2000-01-01. Correct the erroneous sunday to saturday. + */ + if (ldata->hw_designer == AMBA_VENDOR_ST) { + if (readl(ldata->base + RTC_YDR) == 0x2000) { + time = readl(ldata->base + RTC_DR); + if ((time & + (RTC_MON_MASK | RTC_MDAY_MASK | RTC_WDAY_MASK)) + == 0x02120000) { + time = time | (0x7 << RTC_WDAY_SHIFT); + writel(0x2000, ldata->base + RTC_YLR); + writel(time, ldata->base + RTC_LR); + } + } + } + ldata->rtc = rtc_device_register("pl031", &adev->dev, ops, THIS_MODULE); if (IS_ERR(ldata->rtc)) { diff --git a/trunk/drivers/s390/char/con3215.c b/trunk/drivers/s390/char/con3215.c index 4f9f1dcc1551..6c0116d48c74 100644 --- a/trunk/drivers/s390/char/con3215.c +++ b/trunk/drivers/s390/char/con3215.c @@ -20,6 +20,7 @@ #include #include #include +#include /* ASYNC_* flags */ #include #include #include @@ -44,14 +45,11 @@ #define RAW3215_TIMEOUT HZ/10 /* time for delayed output */ #define RAW3215_FIXED 1 /* 3215 console device is not be freed */ -#define RAW3215_ACTIVE 2 /* set if the device is in use */ #define RAW3215_WORKING 4 /* set if a request is being worked on */ #define RAW3215_THROTTLED 8 /* set if reading is disabled */ #define RAW3215_STOPPED 16 /* set if writing is disabled */ -#define RAW3215_CLOSING 32 /* set while in close process */ #define RAW3215_TIMER_RUNS 64 /* set if the output delay timer is on */ #define RAW3215_FLUSHING 128 /* set to flush buffer (no delay) */ -#define RAW3215_FROZEN 256 /* set if 3215 is frozen for suspend */ #define TAB_STOP_SIZE 8 /* tab stop size */ @@ -76,6 +74,7 @@ struct raw3215_req { } __attribute__ ((aligned(8))); struct raw3215_info { + struct tty_port port; struct ccw_device *cdev; /* device for tty driver */ spinlock_t *lock; /* pointer to irq lock */ int flags; /* state flags */ @@ -84,7 +83,6 @@ struct raw3215_info { int head; /* first free byte in output buffer */ int count; /* number of bytes in output buffer */ int written; /* number of bytes in write requests */ - struct tty_struct *tty; /* pointer to tty structure if present */ struct raw3215_req *queued_read; /* pointer to queued read requests */ struct raw3215_req *queued_write;/* pointer to queued write requests */ struct tasklet_struct tlet; /* tasklet to invoke tty_wakeup */ @@ -293,7 +291,7 @@ static void raw3215_timeout(unsigned long __data) if (raw->flags & RAW3215_TIMER_RUNS) { del_timer(&raw->timer); raw->flags &= ~RAW3215_TIMER_RUNS; - if (!(raw->flags & RAW3215_FROZEN)) { + if (!(raw->port.flags & ASYNC_SUSPENDED)) { raw3215_mk_write_req(raw); raw3215_start_io(raw); } @@ -309,7 +307,8 @@ static void raw3215_timeout(unsigned long __data) */ static inline void raw3215_try_io(struct raw3215_info *raw) { - if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FROZEN)) + if (!(raw->port.flags & ASYNC_INITIALIZED) || + (raw->port.flags & ASYNC_SUSPENDED)) return; if (raw->queued_read != NULL) raw3215_start_io(raw); @@ -324,10 +323,7 @@ static inline void raw3215_try_io(struct raw3215_info *raw) } } else if (!(raw->flags & RAW3215_TIMER_RUNS)) { /* delay small writes */ - init_timer(&raw->timer); raw->timer.expires = RAW3215_TIMEOUT + jiffies; - raw->timer.data = (unsigned long) raw; - raw->timer.function = raw3215_timeout; add_timer(&raw->timer); raw->flags |= RAW3215_TIMER_RUNS; } @@ -340,17 +336,21 @@ static inline void raw3215_try_io(struct raw3215_info *raw) static void raw3215_wakeup(unsigned long data) { struct raw3215_info *raw = (struct raw3215_info *) data; - tty_wakeup(raw->tty); + struct tty_struct *tty; + + tty = tty_port_tty_get(&raw->port); + tty_wakeup(tty); + tty_kref_put(tty); } /* * Try to start the next IO and wake up processes waiting on the tty. */ -static void raw3215_next_io(struct raw3215_info *raw) +static void raw3215_next_io(struct raw3215_info *raw, struct tty_struct *tty) { raw3215_mk_write_req(raw); raw3215_try_io(raw); - if (raw->tty && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE) + if (tty && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE) tasklet_schedule(&raw->tlet); } @@ -368,10 +368,11 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm, raw = dev_get_drvdata(&cdev->dev); req = (struct raw3215_req *) intparm; + tty = tty_port_tty_get(&raw->port); cstat = irb->scsw.cmd.cstat; dstat = irb->scsw.cmd.dstat; if (cstat != 0) - raw3215_next_io(raw); + raw3215_next_io(raw, tty); if (dstat & 0x01) { /* we got a unit exception */ dstat &= ~0x01; /* we can ignore it */ } @@ -381,13 +382,13 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm, break; /* Attention interrupt, someone hit the enter key */ raw3215_mk_read_req(raw); - raw3215_next_io(raw); + raw3215_next_io(raw, tty); break; case 0x08: case 0x0C: /* Channel end interrupt. */ if ((raw = req->info) == NULL) - return; /* That shouldn't happen ... */ + goto put_tty; /* That shouldn't happen ... */ if (req->type == RAW3215_READ) { /* store residual count, then wait for device end */ req->residual = irb->scsw.cmd.count; @@ -397,11 +398,10 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm, case 0x04: /* Device end interrupt. */ if ((raw = req->info) == NULL) - return; /* That shouldn't happen ... */ - if (req->type == RAW3215_READ && raw->tty != NULL) { + goto put_tty; /* That shouldn't happen ... */ + if (req->type == RAW3215_READ && tty != NULL) { unsigned int cchar; - tty = raw->tty; count = 160 - req->residual; EBCASC(raw->inbuf, count); cchar = ctrlchar_handle(raw->inbuf, count, tty); @@ -411,7 +411,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm, case CTRLCHAR_CTRL: tty_insert_flip_char(tty, cchar, TTY_NORMAL); - tty_flip_buffer_push(raw->tty); + tty_flip_buffer_push(tty); break; case CTRLCHAR_NONE: @@ -424,7 +424,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm, } else count -= 2; tty_insert_flip_string(tty, raw->inbuf, count); - tty_flip_buffer_push(raw->tty); + tty_flip_buffer_push(tty); break; } } else if (req->type == RAW3215_WRITE) { @@ -439,7 +439,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm, raw->queued_read == NULL) { wake_up_interruptible(&raw->empty_wait); } - raw3215_next_io(raw); + raw3215_next_io(raw, tty); break; default: /* Strange interrupt, I'll do my best to clean up */ @@ -451,9 +451,10 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm, raw->flags &= ~RAW3215_WORKING; raw3215_free_req(req); } - raw3215_next_io(raw); + raw3215_next_io(raw, tty); } - return; +put_tty: + tty_kref_put(tty); } /* @@ -487,7 +488,7 @@ static void raw3215_make_room(struct raw3215_info *raw, unsigned int length) /* While console is frozen for suspend we have no other * choice but to drop message from the buffer to make * room for even more messages. */ - if (raw->flags & RAW3215_FROZEN) { + if (raw->port.flags & ASYNC_SUSPENDED) { raw3215_drop_line(raw); continue; } @@ -609,10 +610,10 @@ static int raw3215_startup(struct raw3215_info *raw) { unsigned long flags; - if (raw->flags & RAW3215_ACTIVE) + if (raw->port.flags & ASYNC_INITIALIZED) return 0; raw->line_pos = 0; - raw->flags |= RAW3215_ACTIVE; + raw->port.flags |= ASYNC_INITIALIZED; spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); raw3215_try_io(raw); spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); @@ -628,14 +629,15 @@ static void raw3215_shutdown(struct raw3215_info *raw) DECLARE_WAITQUEUE(wait, current); unsigned long flags; - if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FIXED)) + if (!(raw->port.flags & ASYNC_INITIALIZED) || + (raw->flags & RAW3215_FIXED)) return; /* Wait for outstanding requests, then free irq */ spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); if ((raw->flags & RAW3215_WORKING) || raw->queued_write != NULL || raw->queued_read != NULL) { - raw->flags |= RAW3215_CLOSING; + raw->port.flags |= ASYNC_CLOSING; add_wait_queue(&raw->empty_wait, &wait); set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); @@ -643,11 +645,41 @@ static void raw3215_shutdown(struct raw3215_info *raw) spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); remove_wait_queue(&raw->empty_wait, &wait); set_current_state(TASK_RUNNING); - raw->flags &= ~(RAW3215_ACTIVE | RAW3215_CLOSING); + raw->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_CLOSING); } spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); } +static struct raw3215_info *raw3215_alloc_info(void) +{ + struct raw3215_info *info; + + info = kzalloc(sizeof(struct raw3215_info), GFP_KERNEL | GFP_DMA); + if (!info) + return NULL; + + info->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA); + info->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA); + if (!info->buffer || !info->inbuf) { + kfree(info); + return NULL; + } + + setup_timer(&info->timer, raw3215_timeout, (unsigned long)info); + init_waitqueue_head(&info->empty_wait); + tasklet_init(&info->tlet, raw3215_wakeup, (unsigned long)info); + tty_port_init(&info->port); + + return info; +} + +static void raw3215_free_info(struct raw3215_info *raw) +{ + kfree(raw->inbuf); + kfree(raw->buffer); + kfree(raw); +} + static int raw3215_probe (struct ccw_device *cdev) { struct raw3215_info *raw; @@ -656,11 +688,15 @@ static int raw3215_probe (struct ccw_device *cdev) /* Console is special. */ if (raw3215[0] && (raw3215[0] == dev_get_drvdata(&cdev->dev))) return 0; - raw = kmalloc(sizeof(struct raw3215_info) + - RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA); + + raw = raw3215_alloc_info(); if (raw == NULL) return -ENOMEM; + raw->cdev = cdev; + dev_set_drvdata(&cdev->dev, raw); + cdev->handler = raw3215_irq; + spin_lock(&raw3215_device_lock); for (line = 0; line < NR_3215; line++) { if (!raw3215[line]) { @@ -670,28 +706,10 @@ static int raw3215_probe (struct ccw_device *cdev) } spin_unlock(&raw3215_device_lock); if (line == NR_3215) { - kfree(raw); + raw3215_free_info(raw); return -ENODEV; } - raw->cdev = cdev; - raw->inbuf = (char *) raw + sizeof(struct raw3215_info); - memset(raw, 0, sizeof(struct raw3215_info)); - raw->buffer = kmalloc(RAW3215_BUFFER_SIZE, - GFP_KERNEL|GFP_DMA); - if (raw->buffer == NULL) { - spin_lock(&raw3215_device_lock); - raw3215[line] = NULL; - spin_unlock(&raw3215_device_lock); - kfree(raw); - return -ENOMEM; - } - init_waitqueue_head(&raw->empty_wait); - tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw); - - dev_set_drvdata(&cdev->dev, raw); - cdev->handler = raw3215_irq; - return 0; } @@ -703,8 +721,7 @@ static void raw3215_remove (struct ccw_device *cdev) raw = dev_get_drvdata(&cdev->dev); if (raw) { dev_set_drvdata(&cdev->dev, NULL); - kfree(raw->buffer); - kfree(raw); + raw3215_free_info(raw); } } @@ -741,7 +758,7 @@ static int raw3215_pm_stop(struct ccw_device *cdev) raw = dev_get_drvdata(&cdev->dev); spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); raw3215_make_room(raw, RAW3215_BUFFER_SIZE); - raw->flags |= RAW3215_FROZEN; + raw->port.flags |= ASYNC_SUSPENDED; spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); return 0; } @@ -754,7 +771,7 @@ static int raw3215_pm_start(struct ccw_device *cdev) /* Allow I/O again and flush output buffer. */ raw = dev_get_drvdata(&cdev->dev); spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); - raw->flags &= ~RAW3215_FROZEN; + raw->port.flags &= ~ASYNC_SUSPENDED; raw->flags |= RAW3215_FLUSHING; raw3215_try_io(raw); raw->flags &= ~RAW3215_FLUSHING; @@ -827,7 +844,7 @@ static void con3215_flush(void) unsigned long flags; raw = raw3215[0]; /* console 3215 is the first one */ - if (raw->flags & RAW3215_FROZEN) + if (raw->port.flags & ASYNC_SUSPENDED) /* The console is still frozen for suspend. */ if (ccw_device_force_console()) /* Forcing didn't work, no panic message .. */ @@ -897,23 +914,16 @@ static int __init con3215_init(void) if (IS_ERR(cdev)) return -ENODEV; - raw3215[0] = raw = (struct raw3215_info *) - kzalloc(sizeof(struct raw3215_info), GFP_KERNEL | GFP_DMA); - raw->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA); - raw->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA); + raw3215[0] = raw = raw3215_alloc_info(); raw->cdev = cdev; dev_set_drvdata(&cdev->dev, raw); cdev->handler = raw3215_irq; raw->flags |= RAW3215_FIXED; - init_waitqueue_head(&raw->empty_wait); - tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw); /* Request the console irq */ if (raw3215_startup(raw) != 0) { - kfree(raw->inbuf); - kfree(raw->buffer); - kfree(raw); + raw3215_free_info(raw); raw3215[0] = NULL; return -ENODEV; } @@ -940,7 +950,7 @@ static int tty3215_open(struct tty_struct *tty, struct file * filp) return -ENODEV; tty->driver_data = raw; - raw->tty = tty; + tty_port_tty_set(&raw->port, tty); tty->low_latency = 0; /* don't use bottom half for pushing chars */ /* @@ -971,7 +981,7 @@ static void tty3215_close(struct tty_struct *tty, struct file * filp) raw3215_shutdown(raw); tasklet_kill(&raw->tlet); tty->closing = 0; - raw->tty = NULL; + tty_port_tty_set(&raw->port, NULL); } /* diff --git a/trunk/drivers/s390/char/keyboard.c b/trunk/drivers/s390/char/keyboard.c index 806588192483..7ef9cfdc17d8 100644 --- a/trunk/drivers/s390/char/keyboard.c +++ b/trunk/drivers/s390/char/keyboard.c @@ -199,7 +199,7 @@ handle_diacr(struct kbd_data *kbd, unsigned int ch) if (ch == ' ' || ch == d) return d; - kbd_put_queue(kbd->tty, d); + kbd_put_queue(kbd->port, d); return ch; } @@ -221,7 +221,7 @@ k_self(struct kbd_data *kbd, unsigned char value) { if (kbd->diacr) value = handle_diacr(kbd, value); - kbd_put_queue(kbd->tty, value); + kbd_put_queue(kbd->port, value); } /* @@ -239,7 +239,7 @@ static void k_fn(struct kbd_data *kbd, unsigned char value) { if (kbd->func_table[value]) - kbd_puts_queue(kbd->tty, kbd->func_table[value]); + kbd_puts_queue(kbd->port, kbd->func_table[value]); } static void @@ -257,20 +257,20 @@ k_spec(struct kbd_data *kbd, unsigned char value) * but we need only 16 bits here */ static void -to_utf8(struct tty_struct *tty, ushort c) +to_utf8(struct tty_port *port, ushort c) { if (c < 0x80) /* 0******* */ - kbd_put_queue(tty, c); + kbd_put_queue(port, c); else if (c < 0x800) { /* 110***** 10****** */ - kbd_put_queue(tty, 0xc0 | (c >> 6)); - kbd_put_queue(tty, 0x80 | (c & 0x3f)); + kbd_put_queue(port, 0xc0 | (c >> 6)); + kbd_put_queue(port, 0x80 | (c & 0x3f)); } else { /* 1110**** 10****** 10****** */ - kbd_put_queue(tty, 0xe0 | (c >> 12)); - kbd_put_queue(tty, 0x80 | ((c >> 6) & 0x3f)); - kbd_put_queue(tty, 0x80 | (c & 0x3f)); + kbd_put_queue(port, 0xe0 | (c >> 12)); + kbd_put_queue(port, 0x80 | ((c >> 6) & 0x3f)); + kbd_put_queue(port, 0x80 | (c & 0x3f)); } } @@ -283,7 +283,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode) unsigned short keysym; unsigned char type, value; - if (!kbd || !kbd->tty) + if (!kbd) return; if (keycode >= 384) @@ -323,7 +323,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode) #endif (*k_handler[type])(kbd, value); } else - to_utf8(kbd->tty, keysym); + to_utf8(kbd->port, keysym); } /* @@ -457,6 +457,7 @@ do_kdgkb_ioctl(struct kbd_data *kbd, struct kbsentry __user *u_kbs, int kbd_ioctl(struct kbd_data *kbd, unsigned int cmd, unsigned long arg) { + struct tty_struct *tty; void __user *argp; unsigned int ct; int perm; @@ -467,7 +468,10 @@ int kbd_ioctl(struct kbd_data *kbd, unsigned int cmd, unsigned long arg) * To have permissions to do most of the vt ioctls, we either have * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG. */ - perm = current->signal->tty == kbd->tty || capable(CAP_SYS_TTY_CONFIG); + tty = tty_port_tty_get(kbd->port); + /* FIXME this test is pretty racy */ + perm = current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG); + tty_kref_put(tty); switch (cmd) { case KDGKBTYPE: return put_user(KB_101, (char __user *)argp); diff --git a/trunk/drivers/s390/char/keyboard.h b/trunk/drivers/s390/char/keyboard.h index 7e736aaeae6e..f682f4e49680 100644 --- a/trunk/drivers/s390/char/keyboard.h +++ b/trunk/drivers/s390/char/keyboard.h @@ -21,7 +21,7 @@ typedef void (fn_handler_fn)(struct kbd_data *); */ struct kbd_data { - struct tty_struct *tty; + struct tty_port *port; unsigned short **key_maps; char **func_table; fn_handler_fn **fn_handler; @@ -42,16 +42,24 @@ int kbd_ioctl(struct kbd_data *, unsigned int, unsigned long); * Helper Functions. */ static inline void -kbd_put_queue(struct tty_struct *tty, int ch) +kbd_put_queue(struct tty_port *port, int ch) { + struct tty_struct *tty = tty_port_tty_get(port); + if (!tty) + return; tty_insert_flip_char(tty, ch, 0); tty_schedule_flip(tty); + tty_kref_put(tty); } static inline void -kbd_puts_queue(struct tty_struct *tty, char *cp) +kbd_puts_queue(struct tty_port *port, char *cp) { + struct tty_struct *tty = tty_port_tty_get(port); + if (!tty) + return; while (*cp) tty_insert_flip_char(tty, *cp++, 0); tty_schedule_flip(tty); + tty_kref_put(tty); } diff --git a/trunk/drivers/s390/char/sclp_cmd.c b/trunk/drivers/s390/char/sclp_cmd.c index 231a1d85127b..36506366158d 100644 --- a/trunk/drivers/s390/char/sclp_cmd.c +++ b/trunk/drivers/s390/char/sclp_cmd.c @@ -352,7 +352,17 @@ static int do_assign_storage(sclp_cmdw_t cmd, u16 rn) static int sclp_assign_storage(u16 rn) { - return do_assign_storage(0x000d0001, rn); + unsigned long long start, address; + int rc; + + rc = do_assign_storage(0x000d0001, rn); + if (rc) + goto out; + start = address = rn2addr(rn); + for (; address < start + rzm; address += PAGE_SIZE) + page_set_storage_key(address, PAGE_DEFAULT_KEY, 0); +out: + return rc; } static int sclp_unassign_storage(u16 rn) diff --git a/trunk/drivers/s390/char/sclp_tty.c b/trunk/drivers/s390/char/sclp_tty.c index 40a9d69c898e..e66a75b3822c 100644 --- a/trunk/drivers/s390/char/sclp_tty.c +++ b/trunk/drivers/s390/char/sclp_tty.c @@ -48,7 +48,7 @@ static struct sclp_buffer *sclp_ttybuf; /* Timer for delayed output of console messages. */ static struct timer_list sclp_tty_timer; -static struct tty_struct *sclp_tty; +static struct tty_port sclp_port; static unsigned char sclp_tty_chars[SCLP_TTY_BUF_SIZE]; static unsigned short int sclp_tty_chars_count; @@ -64,7 +64,7 @@ static int sclp_tty_columns = 80; static int sclp_tty_open(struct tty_struct *tty, struct file *filp) { - sclp_tty = tty; + tty_port_tty_set(&sclp_port, tty); tty->driver_data = NULL; tty->low_latency = 0; return 0; @@ -76,7 +76,7 @@ sclp_tty_close(struct tty_struct *tty, struct file *filp) { if (tty->count > 1) return; - sclp_tty = NULL; + tty_port_tty_set(&sclp_port, NULL); } /* @@ -108,6 +108,7 @@ sclp_tty_write_room (struct tty_struct *tty) static void sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc) { + struct tty_struct *tty; unsigned long flags; void *page; @@ -126,8 +127,10 @@ sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc) spin_unlock_irqrestore(&sclp_tty_lock, flags); } while (buffer && sclp_emit_buffer(buffer, sclp_ttybuf_callback)); /* check if the tty needs a wake up call */ - if (sclp_tty != NULL) { - tty_wakeup(sclp_tty); + tty = tty_port_tty_get(&sclp_port); + if (tty != NULL) { + tty_wakeup(tty); + tty_kref_put(tty); } } @@ -326,21 +329,22 @@ sclp_tty_flush_buffer(struct tty_struct *tty) static void sclp_tty_input(unsigned char* buf, unsigned int count) { + struct tty_struct *tty = tty_port_tty_get(&sclp_port); unsigned int cchar; /* * If this tty driver is currently closed * then throw the received input away. */ - if (sclp_tty == NULL) + if (tty == NULL) return; - cchar = ctrlchar_handle(buf, count, sclp_tty); + cchar = ctrlchar_handle(buf, count, tty); switch (cchar & CTRLCHAR_MASK) { case CTRLCHAR_SYSRQ: break; case CTRLCHAR_CTRL: - tty_insert_flip_char(sclp_tty, cchar, TTY_NORMAL); - tty_flip_buffer_push(sclp_tty); + tty_insert_flip_char(tty, cchar, TTY_NORMAL); + tty_flip_buffer_push(tty); break; case CTRLCHAR_NONE: /* send (normal) input to line discipline */ @@ -348,13 +352,14 @@ sclp_tty_input(unsigned char* buf, unsigned int count) (strncmp((const char *) buf + count - 2, "^n", 2) && strncmp((const char *) buf + count - 2, "\252n", 2))) { /* add the auto \n */ - tty_insert_flip_string(sclp_tty, buf, count); - tty_insert_flip_char(sclp_tty, '\n', TTY_NORMAL); + tty_insert_flip_string(tty, buf, count); + tty_insert_flip_char(tty, '\n', TTY_NORMAL); } else - tty_insert_flip_string(sclp_tty, buf, count - 2); - tty_flip_buffer_push(sclp_tty); + tty_insert_flip_string(tty, buf, count - 2); + tty_flip_buffer_push(tty); break; } + tty_kref_put(tty); } /* @@ -543,7 +548,7 @@ sclp_tty_init(void) sclp_tty_tolower = 1; } sclp_tty_chars_count = 0; - sclp_tty = NULL; + tty_port_init(&sclp_port); rc = sclp_register(&sclp_input_event); if (rc) { diff --git a/trunk/drivers/s390/char/sclp_vt220.c b/trunk/drivers/s390/char/sclp_vt220.c index b635472ae660..edfc0fd73dc6 100644 --- a/trunk/drivers/s390/char/sclp_vt220.c +++ b/trunk/drivers/s390/char/sclp_vt220.c @@ -34,7 +34,6 @@ #define SCLP_VT220_DEVICE_NAME "ttysclp" #define SCLP_VT220_CONSOLE_NAME "ttyS" #define SCLP_VT220_CONSOLE_INDEX 1 /* console=ttyS1 */ -#define SCLP_VT220_BUF_SIZE 80 /* Representation of a single write request */ struct sclp_vt220_request { @@ -56,8 +55,7 @@ struct sclp_vt220_sccb { /* Structures and data needed to register tty driver */ static struct tty_driver *sclp_vt220_driver; -/* The tty_struct that the kernel associated with us */ -static struct tty_struct *sclp_vt220_tty; +static struct tty_port sclp_vt220_port; /* Lock to protect internal data from concurrent access */ static spinlock_t sclp_vt220_lock; @@ -116,6 +114,7 @@ static struct sclp_register sclp_vt220_register = { static void sclp_vt220_process_queue(struct sclp_vt220_request *request) { + struct tty_struct *tty; unsigned long flags; void *page; @@ -141,8 +140,10 @@ sclp_vt220_process_queue(struct sclp_vt220_request *request) if (request == NULL && sclp_vt220_flush_later) sclp_vt220_emit_current(); /* Check if the tty needs a wake up call */ - if (sclp_vt220_tty != NULL) { - tty_wakeup(sclp_vt220_tty); + tty = tty_port_tty_get(&sclp_vt220_port); + if (tty) { + tty_wakeup(tty); + tty_kref_put(tty); } } @@ -460,11 +461,12 @@ sclp_vt220_write(struct tty_struct *tty, const unsigned char *buf, int count) static void sclp_vt220_receiver_fn(struct evbuf_header *evbuf) { + struct tty_struct *tty = tty_port_tty_get(&sclp_vt220_port); char *buffer; unsigned int count; /* Ignore input if device is not open */ - if (sclp_vt220_tty == NULL) + if (tty == NULL) return; buffer = (char *) ((addr_t) evbuf + sizeof(struct evbuf_header)); @@ -478,10 +480,11 @@ sclp_vt220_receiver_fn(struct evbuf_header *evbuf) /* Send input to line discipline */ buffer++; count--; - tty_insert_flip_string(sclp_vt220_tty, buffer, count); - tty_flip_buffer_push(sclp_vt220_tty); + tty_insert_flip_string(tty, buffer, count); + tty_flip_buffer_push(tty); break; } + tty_kref_put(tty); } /* @@ -491,10 +494,7 @@ static int sclp_vt220_open(struct tty_struct *tty, struct file *filp) { if (tty->count == 1) { - sclp_vt220_tty = tty; - tty->driver_data = kmalloc(SCLP_VT220_BUF_SIZE, GFP_KERNEL); - if (tty->driver_data == NULL) - return -ENOMEM; + tty_port_tty_set(&sclp_vt220_port, tty); tty->low_latency = 0; if (!tty->winsize.ws_row && !tty->winsize.ws_col) { tty->winsize.ws_row = 24; @@ -510,11 +510,8 @@ sclp_vt220_open(struct tty_struct *tty, struct file *filp) static void sclp_vt220_close(struct tty_struct *tty, struct file *filp) { - if (tty->count == 1) { - sclp_vt220_tty = NULL; - kfree(tty->driver_data); - tty->driver_data = NULL; - } + if (tty->count == 1) + tty_port_tty_set(&sclp_vt220_port, NULL); } /* @@ -635,9 +632,9 @@ static int __init __sclp_vt220_init(int num_pages) INIT_LIST_HEAD(&sclp_vt220_empty); INIT_LIST_HEAD(&sclp_vt220_outqueue); init_timer(&sclp_vt220_timer); + tty_port_init(&sclp_vt220_port); sclp_vt220_current_request = NULL; sclp_vt220_buffered_chars = 0; - sclp_vt220_tty = NULL; sclp_vt220_flush_later = 0; /* Allocate pages for output buffering */ diff --git a/trunk/drivers/s390/char/tape.h b/trunk/drivers/s390/char/tape.h index 267b54e8ff5a..bc6c7cfd36b6 100644 --- a/trunk/drivers/s390/char/tape.h +++ b/trunk/drivers/s390/char/tape.h @@ -154,12 +154,6 @@ struct tape_discipline { struct tape_request *(*read_block)(struct tape_device *, size_t); struct tape_request *(*write_block)(struct tape_device *, size_t); void (*process_eov)(struct tape_device*); -#ifdef CONFIG_S390_TAPE_BLOCK - /* Block device stuff. */ - struct tape_request *(*bread)(struct tape_device *, struct request *); - void (*check_locate)(struct tape_device *, struct tape_request *); - void (*free_bread)(struct tape_request *); -#endif /* ioctl function for additional ioctls. */ int (*ioctl_fn)(struct tape_device *, unsigned int, unsigned long); /* Array of tape commands with TAPE_NR_MTOPS entries */ @@ -182,26 +176,6 @@ struct tape_char_data { int block_size; /* of size block_size. */ }; -#ifdef CONFIG_S390_TAPE_BLOCK -/* Block Frontend Data */ -struct tape_blk_data -{ - struct tape_device * device; - /* Block device request queue. */ - struct request_queue * request_queue; - spinlock_t request_queue_lock; - - /* Task to move entries from block request to CCS request queue. */ - struct work_struct requeue_task; - atomic_t requeue_scheduled; - - /* Current position on the tape. */ - long block_position; - int medium_changed; - struct gendisk * disk; -}; -#endif - /* Tape Info */ struct tape_device { /* entry in tape_device_list */ @@ -248,10 +222,6 @@ struct tape_device { /* Character device frontend data */ struct tape_char_data char_data; -#ifdef CONFIG_S390_TAPE_BLOCK - /* Block dev frontend data */ - struct tape_blk_data blk_data; -#endif /* Function to start or stop the next request later. */ struct delayed_work tape_dnr; @@ -313,19 +283,6 @@ extern void tapechar_exit(void); extern int tapechar_setup_device(struct tape_device *); extern void tapechar_cleanup_device(struct tape_device *); -/* Externals from tape_block.c */ -#ifdef CONFIG_S390_TAPE_BLOCK -extern int tapeblock_init (void); -extern void tapeblock_exit(void); -extern int tapeblock_setup_device(struct tape_device *); -extern void tapeblock_cleanup_device(struct tape_device *); -#else -static inline int tapeblock_init (void) {return 0;} -static inline void tapeblock_exit (void) {;} -static inline int tapeblock_setup_device(struct tape_device *t) {return 0;} -static inline void tapeblock_cleanup_device (struct tape_device *t) {;} -#endif - /* tape initialisation functions */ #ifdef CONFIG_PROC_FS extern void tape_proc_init (void); diff --git a/trunk/drivers/s390/char/tape_34xx.c b/trunk/drivers/s390/char/tape_34xx.c index 934ef33eb9a4..b28de80b7ca4 100644 --- a/trunk/drivers/s390/char/tape_34xx.c +++ b/trunk/drivers/s390/char/tape_34xx.c @@ -323,20 +323,6 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request, inhibit_cu_recovery = (*device->modeset_byte & 0x80) ? 1 : 0; sense = irb->ecw; -#ifdef CONFIG_S390_TAPE_BLOCK - if (request->op == TO_BLOCK) { - /* - * Recovery for block device requests. Set the block_position - * to something invalid and retry. - */ - device->blk_data.block_position = -1; - if (request->retries-- <= 0) - return tape_34xx_erp_failed(request, -EIO); - else - return tape_34xx_erp_retry(request); - } -#endif - if ( sense[0] & SENSE_COMMAND_REJECT && sense[1] & SENSE_WRITE_PROTECT @@ -1129,123 +1115,6 @@ tape_34xx_mtseek(struct tape_device *device, int mt_count) return tape_do_io_free(device, request); } -#ifdef CONFIG_S390_TAPE_BLOCK -/* - * Tape block read for 34xx. - */ -static struct tape_request * -tape_34xx_bread(struct tape_device *device, struct request *req) -{ - struct tape_request *request; - struct ccw1 *ccw; - int count = 0; - unsigned off; - char *dst; - struct bio_vec *bv; - struct req_iterator iter; - struct tape_34xx_block_id * start_block; - - DBF_EVENT(6, "xBREDid:"); - - /* Count the number of blocks for the request. */ - rq_for_each_segment(bv, req, iter) - count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9); - - /* Allocate the ccw request. */ - request = tape_alloc_request(3+count+1, 8); - if (IS_ERR(request)) - return request; - - /* Setup ccws. */ - request->op = TO_BLOCK; - start_block = (struct tape_34xx_block_id *) request->cpdata; - start_block->block = blk_rq_pos(req) >> TAPEBLOCK_HSEC_S2B; - DBF_EVENT(6, "start_block = %i\n", start_block->block); - - ccw = request->cpaddr; - ccw = tape_ccw_cc(ccw, MODE_SET_DB, 1, device->modeset_byte); - - /* - * We always setup a nop after the mode set ccw. This slot is - * used in tape_std_check_locate to insert a locate ccw if the - * current tape position doesn't match the start block to be read. - * The second nop will be filled with a read block id which is in - * turn used by tape_34xx_free_bread to populate the segment bid - * table. - */ - ccw = tape_ccw_cc(ccw, NOP, 0, NULL); - ccw = tape_ccw_cc(ccw, NOP, 0, NULL); - - rq_for_each_segment(bv, req, iter) { - dst = kmap(bv->bv_page) + bv->bv_offset; - for (off = 0; off < bv->bv_len; off += TAPEBLOCK_HSEC_SIZE) { - ccw->flags = CCW_FLAG_CC; - ccw->cmd_code = READ_FORWARD; - ccw->count = TAPEBLOCK_HSEC_SIZE; - set_normalized_cda(ccw, (void*) __pa(dst)); - ccw++; - dst += TAPEBLOCK_HSEC_SIZE; - } - } - - ccw = tape_ccw_end(ccw, NOP, 0, NULL); - DBF_EVENT(6, "xBREDccwg\n"); - return request; -} - -static void -tape_34xx_free_bread (struct tape_request *request) -{ - struct ccw1* ccw; - - ccw = request->cpaddr; - if ((ccw + 2)->cmd_code == READ_BLOCK_ID) { - struct { - struct tape_34xx_block_id cbid; - struct tape_34xx_block_id dbid; - } __attribute__ ((packed)) *rbi_data; - - rbi_data = request->cpdata; - - if (request->device) - tape_34xx_add_sbid(request->device, rbi_data->cbid); - } - - /* Last ccw is a nop and doesn't need clear_normalized_cda */ - for (; ccw->flags & CCW_FLAG_CC; ccw++) - if (ccw->cmd_code == READ_FORWARD) - clear_normalized_cda(ccw); - tape_free_request(request); -} - -/* - * check_locate is called just before the tape request is passed to - * the common io layer for execution. It has to check the current - * tape position and insert a locate ccw if it doesn't match the - * start block for the request. - */ -static void -tape_34xx_check_locate(struct tape_device *device, struct tape_request *request) -{ - struct tape_34xx_block_id * start_block; - - start_block = (struct tape_34xx_block_id *) request->cpdata; - if (start_block->block == device->blk_data.block_position) - return; - - DBF_LH(4, "Block seek(%06d+%06d)\n", start_block->block, device->bof); - start_block->wrap = 0; - start_block->segment = 1; - start_block->format = (*device->modeset_byte & 0x08) ? - TAPE34XX_FMT_3480_XF : - TAPE34XX_FMT_3480; - start_block->block = start_block->block + device->bof; - tape_34xx_merge_sbid(device, start_block); - tape_ccw_cc(request->cpaddr + 1, LOCATE, 4, request->cpdata); - tape_ccw_cc(request->cpaddr + 2, READ_BLOCK_ID, 8, request->cpdata); -} -#endif - /* * List of 3480/3490 magnetic tape commands. */ @@ -1295,11 +1164,6 @@ static struct tape_discipline tape_discipline_34xx = { .irq = tape_34xx_irq, .read_block = tape_std_read_block, .write_block = tape_std_write_block, -#ifdef CONFIG_S390_TAPE_BLOCK - .bread = tape_34xx_bread, - .free_bread = tape_34xx_free_bread, - .check_locate = tape_34xx_check_locate, -#endif .ioctl_fn = tape_34xx_ioctl, .mtop_array = tape_34xx_mtop }; diff --git a/trunk/drivers/s390/char/tape_3590.c b/trunk/drivers/s390/char/tape_3590.c index 49c6aab7ad78..a5c6614b0db2 100644 --- a/trunk/drivers/s390/char/tape_3590.c +++ b/trunk/drivers/s390/char/tape_3590.c @@ -670,92 +670,6 @@ tape_3590_schedule_work(struct tape_device *device, enum tape_op op) return 0; } -#ifdef CONFIG_S390_TAPE_BLOCK -/* - * Tape Block READ - */ -static struct tape_request * -tape_3590_bread(struct tape_device *device, struct request *req) -{ - struct tape_request *request; - struct ccw1 *ccw; - int count = 0, start_block; - unsigned off; - char *dst; - struct bio_vec *bv; - struct req_iterator iter; - - DBF_EVENT(6, "xBREDid:"); - start_block = blk_rq_pos(req) >> TAPEBLOCK_HSEC_S2B; - DBF_EVENT(6, "start_block = %i\n", start_block); - - rq_for_each_segment(bv, req, iter) - count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9); - - request = tape_alloc_request(2 + count + 1, 4); - if (IS_ERR(request)) - return request; - request->op = TO_BLOCK; - *(__u32 *) request->cpdata = start_block; - ccw = request->cpaddr; - ccw = tape_ccw_cc(ccw, MODE_SET_DB, 1, device->modeset_byte); - - /* - * We always setup a nop after the mode set ccw. This slot is - * used in tape_std_check_locate to insert a locate ccw if the - * current tape position doesn't match the start block to be read. - */ - ccw = tape_ccw_cc(ccw, NOP, 0, NULL); - - rq_for_each_segment(bv, req, iter) { - dst = page_address(bv->bv_page) + bv->bv_offset; - for (off = 0; off < bv->bv_len; off += TAPEBLOCK_HSEC_SIZE) { - ccw->flags = CCW_FLAG_CC; - ccw->cmd_code = READ_FORWARD; - ccw->count = TAPEBLOCK_HSEC_SIZE; - set_normalized_cda(ccw, (void *) __pa(dst)); - ccw++; - dst += TAPEBLOCK_HSEC_SIZE; - } - BUG_ON(off > bv->bv_len); - } - ccw = tape_ccw_end(ccw, NOP, 0, NULL); - DBF_EVENT(6, "xBREDccwg\n"); - return request; -} - -static void -tape_3590_free_bread(struct tape_request *request) -{ - struct ccw1 *ccw; - - /* Last ccw is a nop and doesn't need clear_normalized_cda */ - for (ccw = request->cpaddr; ccw->flags & CCW_FLAG_CC; ccw++) - if (ccw->cmd_code == READ_FORWARD) - clear_normalized_cda(ccw); - tape_free_request(request); -} - -/* - * check_locate is called just before the tape request is passed to - * the common io layer for execution. It has to check the current - * tape position and insert a locate ccw if it doesn't match the - * start block for the request. - */ -static void -tape_3590_check_locate(struct tape_device *device, struct tape_request *request) -{ - __u32 *start_block; - - start_block = (__u32 *) request->cpdata; - if (*start_block != device->blk_data.block_position) { - /* Add the start offset of the file to get the real block. */ - *start_block += device->bof; - tape_ccw_cc(request->cpaddr + 1, LOCATE, 4, request->cpdata); - } -} -#endif - static void tape_3590_med_state_set(struct tape_device *device, struct tape_3590_med_sense *sense) { @@ -1423,20 +1337,6 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request, { struct tape_3590_sense *sense; -#ifdef CONFIG_S390_TAPE_BLOCK - if (request->op == TO_BLOCK) { - /* - * Recovery for block device requests. Set the block_position - * to something invalid and retry. - */ - device->blk_data.block_position = -1; - if (request->retries-- <= 0) - return tape_3590_erp_failed(device, request, irb, -EIO); - else - return tape_3590_erp_retry(device, request, irb); - } -#endif - sense = (struct tape_3590_sense *) irb->ecw; DBF_EVENT(6, "Unit Check: RQC = %x\n", sense->rc_rqc); @@ -1729,11 +1629,6 @@ static struct tape_discipline tape_discipline_3590 = { .irq = tape_3590_irq, .read_block = tape_std_read_block, .write_block = tape_std_write_block, -#ifdef CONFIG_S390_TAPE_BLOCK - .bread = tape_3590_bread, - .free_bread = tape_3590_free_bread, - .check_locate = tape_3590_check_locate, -#endif .ioctl_fn = tape_3590_ioctl, .mtop_array = tape_3590_mtop }; diff --git a/trunk/drivers/s390/char/tape_char.c b/trunk/drivers/s390/char/tape_char.c index 87cd0ab242de..46886a7578c6 100644 --- a/trunk/drivers/s390/char/tape_char.c +++ b/trunk/drivers/s390/char/tape_char.c @@ -161,11 +161,6 @@ tapechar_read(struct file *filp, char __user *data, size_t count, loff_t *ppos) if (rc) return rc; -#ifdef CONFIG_S390_TAPE_BLOCK - /* Changes position. */ - device->blk_data.medium_changed = 1; -#endif - DBF_EVENT(6, "TCHAR:nbytes: %lx\n", block_size); /* Let the discipline build the ccw chain. */ request = device->discipline->read_block(device, block_size); @@ -218,11 +213,6 @@ tapechar_write(struct file *filp, const char __user *data, size_t count, loff_t if (rc) return rc; -#ifdef CONFIG_S390_TAPE_BLOCK - /* Changes position. */ - device->blk_data.medium_changed = 1; -#endif - DBF_EVENT(6,"TCHAR:nbytes: %lx\n", block_size); DBF_EVENT(6, "TCHAR:nblocks: %x\n", nblocks); /* Let the discipline build the ccw chain. */ @@ -379,9 +369,6 @@ __tapechar_ioctl(struct tape_device *device, case MTBSFM: case MTFSFM: case MTSEEK: -#ifdef CONFIG_S390_TAPE_BLOCK - device->blk_data.medium_changed = 1; -#endif if (device->required_tapemarks) tape_std_terminate_write(device); default: diff --git a/trunk/drivers/s390/char/tape_core.c b/trunk/drivers/s390/char/tape_core.c index b3a3e8e8656e..585618663ba4 100644 --- a/trunk/drivers/s390/char/tape_core.c +++ b/trunk/drivers/s390/char/tape_core.c @@ -401,9 +401,6 @@ tape_generic_online(struct tape_device *device, rc = tapechar_setup_device(device); if (rc) goto out_minor; - rc = tapeblock_setup_device(device); - if (rc) - goto out_char; tape_state_set(device, TS_UNUSED); @@ -411,8 +408,6 @@ tape_generic_online(struct tape_device *device, return 0; -out_char: - tapechar_cleanup_device(device); out_minor: tape_remove_minor(device); out_discipline: @@ -426,7 +421,6 @@ tape_generic_online(struct tape_device *device, static void tape_cleanup_device(struct tape_device *device) { - tapeblock_cleanup_device(device); tapechar_cleanup_device(device); device->discipline->cleanup_device(device); module_put(device->discipline->owner); @@ -785,10 +779,6 @@ __tape_start_io(struct tape_device *device, struct tape_request *request) { int rc; -#ifdef CONFIG_S390_TAPE_BLOCK - if (request->op == TO_BLOCK) - device->discipline->check_locate(device, request); -#endif rc = ccw_device_start( device->cdev, request->cpaddr, @@ -1253,7 +1243,7 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) } /* - * Tape device open function used by tape_char & tape_block frontends. + * Tape device open function used by tape_char frontend. */ int tape_open(struct tape_device *device) @@ -1283,7 +1273,7 @@ tape_open(struct tape_device *device) } /* - * Tape device release function used by tape_char & tape_block frontends. + * Tape device release function used by tape_char frontend. */ int tape_release(struct tape_device *device) @@ -1344,7 +1334,6 @@ tape_init (void) DBF_EVENT(3, "tape init\n"); tape_proc_init(); tapechar_init (); - tapeblock_init (); return 0; } @@ -1358,7 +1347,6 @@ tape_exit(void) /* Get rid of the frontends */ tapechar_exit(); - tapeblock_exit(); tape_proc_cleanup(); debug_unregister (TAPE_DBF_AREA); } diff --git a/trunk/drivers/s390/char/tty3270.c b/trunk/drivers/s390/char/tty3270.c index b43445a55cb6..10ec690197cb 100644 --- a/trunk/drivers/s390/char/tty3270.c +++ b/trunk/drivers/s390/char/tty3270.c @@ -61,7 +61,7 @@ struct tty3270_line { */ struct tty3270 { struct raw3270_view view; - struct tty_struct *tty; /* Pointer to tty structure */ + struct tty_port port; void **freemem_pages; /* Array of pages used for freemem. */ struct list_head freemem; /* List of free memory for strings. */ @@ -324,9 +324,8 @@ tty3270_blank_line(struct tty3270 *tp) static void tty3270_write_callback(struct raw3270_request *rq, void *data) { - struct tty3270 *tp; + struct tty3270 *tp = container_of(rq->view, struct tty3270, view); - tp = (struct tty3270 *) rq->view; if (rq->rc != 0) { /* Write wasn't successful. Refresh all. */ tp->update_flags = TTY_UPDATE_ALL; @@ -450,10 +449,9 @@ tty3270_rcl_add(struct tty3270 *tp, char *input, int len) static void tty3270_rcl_backward(struct kbd_data *kbd) { - struct tty3270 *tp; + struct tty3270 *tp = container_of(kbd->port, struct tty3270, port); struct string *s; - tp = kbd->tty->driver_data; spin_lock_bh(&tp->view.lock); if (tp->inattr == TF_INPUT) { if (tp->rcl_walk && tp->rcl_walk->prev != &tp->rcl_lines) @@ -478,9 +476,8 @@ tty3270_rcl_backward(struct kbd_data *kbd) static void tty3270_exit_tty(struct kbd_data *kbd) { - struct tty3270 *tp; + struct tty3270 *tp = container_of(kbd->port, struct tty3270, port); - tp = kbd->tty->driver_data; raw3270_deactivate_view(&tp->view); } @@ -490,10 +487,9 @@ tty3270_exit_tty(struct kbd_data *kbd) static void tty3270_scroll_forward(struct kbd_data *kbd) { - struct tty3270 *tp; + struct tty3270 *tp = container_of(kbd->port, struct tty3270, port); int nr_up; - tp = kbd->tty->driver_data; spin_lock_bh(&tp->view.lock); nr_up = tp->nr_up - tp->view.rows + 2; if (nr_up < 0) @@ -513,10 +509,9 @@ tty3270_scroll_forward(struct kbd_data *kbd) static void tty3270_scroll_backward(struct kbd_data *kbd) { - struct tty3270 *tp; + struct tty3270 *tp = container_of(kbd->port, struct tty3270, port); int nr_up; - tp = kbd->tty->driver_data; spin_lock_bh(&tp->view.lock); nr_up = tp->nr_up + tp->view.rows - 2; if (nr_up + tp->view.rows - 2 > tp->nr_lines) @@ -537,11 +532,10 @@ static void tty3270_read_tasklet(struct raw3270_request *rrq) { static char kreset_data = TW_KR; - struct tty3270 *tp; + struct tty3270 *tp = container_of(rrq->view, struct tty3270, view); char *input; int len; - tp = (struct tty3270 *) rrq->view; spin_lock_bh(&tp->view.lock); /* * Two AID keys are special: For 0x7d (enter) the input line @@ -577,13 +571,10 @@ tty3270_read_tasklet(struct raw3270_request *rrq) raw3270_request_add_data(tp->kreset, &kreset_data, 1); raw3270_start(&tp->view, tp->kreset); - /* Emit input string. */ - if (tp->tty) { - while (len-- > 0) - kbd_keycode(tp->kbd, *input++); - /* Emit keycode for AID byte. */ - kbd_keycode(tp->kbd, 256 + tp->input->string[0]); - } + while (len-- > 0) + kbd_keycode(tp->kbd, *input++); + /* Emit keycode for AID byte. */ + kbd_keycode(tp->kbd, 256 + tp->input->string[0]); raw3270_request_reset(rrq); xchg(&tp->read, rrq); @@ -596,9 +587,10 @@ tty3270_read_tasklet(struct raw3270_request *rrq) static void tty3270_read_callback(struct raw3270_request *rq, void *data) { + struct tty3270 *tp = container_of(rq->view, struct tty3270, view); raw3270_get_view(rq->view); /* Schedule tasklet to pass input to tty. */ - tasklet_schedule(&((struct tty3270 *) rq->view)->readlet); + tasklet_schedule(&tp->readlet); } /* @@ -635,9 +627,8 @@ tty3270_issue_read(struct tty3270 *tp, int lock) static int tty3270_activate(struct raw3270_view *view) { - struct tty3270 *tp; + struct tty3270 *tp = container_of(view, struct tty3270, view); - tp = (struct tty3270 *) view; tp->update_flags = TTY_UPDATE_ALL; tty3270_set_timer(tp, 1); return 0; @@ -646,9 +637,8 @@ tty3270_activate(struct raw3270_view *view) static void tty3270_deactivate(struct raw3270_view *view) { - struct tty3270 *tp; + struct tty3270 *tp = container_of(view, struct tty3270, view); - tp = (struct tty3270 *) view; del_timer(&tp->timer); } @@ -690,6 +680,17 @@ tty3270_alloc_view(void) if (!tp->freemem_pages) goto out_tp; INIT_LIST_HEAD(&tp->freemem); + INIT_LIST_HEAD(&tp->lines); + INIT_LIST_HEAD(&tp->update); + INIT_LIST_HEAD(&tp->rcl_lines); + tp->rcl_max = 20; + tty_port_init(&tp->port); + setup_timer(&tp->timer, (void (*)(unsigned long)) tty3270_update, + (unsigned long) tp); + tasklet_init(&tp->readlet, + (void (*)(unsigned long)) tty3270_read_tasklet, + (unsigned long) tp->read); + for (pages = 0; pages < TTY3270_STRING_PAGES; pages++) { tp->freemem_pages[pages] = (void *) __get_free_pages(GFP_KERNEL|GFP_DMA, 0); @@ -794,16 +795,15 @@ tty3270_free_screen(struct tty3270 *tp) static void tty3270_release(struct raw3270_view *view) { - struct tty3270 *tp; - struct tty_struct *tty; + struct tty3270 *tp = container_of(view, struct tty3270, view); + struct tty_struct *tty = tty_port_tty_get(&tp->port); - tp = (struct tty3270 *) view; - tty = tp->tty; if (tty) { tty->driver_data = NULL; - tp->tty = tp->kbd->tty = NULL; + tty_port_tty_set(&tp->port, NULL); tty_hangup(tty); raw3270_put_view(&tp->view); + tty_kref_put(tty); } } @@ -813,8 +813,9 @@ tty3270_release(struct raw3270_view *view) static void tty3270_free(struct raw3270_view *view) { - tty3270_free_screen((struct tty3270 *) view); - tty3270_free_view((struct tty3270 *) view); + struct tty3270 *tp = container_of(view, struct tty3270, view); + tty3270_free_screen(tp); + tty3270_free_view(tp); } /* @@ -823,14 +824,13 @@ tty3270_free(struct raw3270_view *view) static void tty3270_del_views(void) { - struct tty3270 *tp; int i; for (i = 0; i < tty3270_max_index; i++) { - tp = (struct tty3270 *) + struct raw3270_view *view = raw3270_find_view(&tty3270_fn, i + RAW3270_FIRSTMINOR); - if (!IS_ERR(tp)) - raw3270_del_view(&tp->view); + if (!IS_ERR(view)) + raw3270_del_view(view); } } @@ -848,22 +848,23 @@ static struct raw3270_fn tty3270_fn = { static int tty3270_open(struct tty_struct *tty, struct file * filp) { + struct raw3270_view *view; struct tty3270 *tp; int i, rc; if (tty->count > 1) return 0; /* Check if the tty3270 is already there. */ - tp = (struct tty3270 *) - raw3270_find_view(&tty3270_fn, + view = raw3270_find_view(&tty3270_fn, tty->index + RAW3270_FIRSTMINOR); - if (!IS_ERR(tp)) { + if (!IS_ERR(view)) { + tp = container_of(view, struct tty3270, view); tty->driver_data = tp; tty->winsize.ws_row = tp->view.rows - 2; tty->winsize.ws_col = tp->view.cols; tty->low_latency = 0; - tp->tty = tty; - tp->kbd->tty = tty; + /* why to reassign? */ + tty_port_tty_set(&tp->port, tty); tp->inattr = TF_INPUT; return 0; } @@ -871,7 +872,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp) tty3270_max_index = tty->index + 1; /* Quick exit if there is no device for tty->index. */ - if (PTR_ERR(tp) == -ENODEV) + if (PTR_ERR(view) == -ENODEV) return -ENODEV; /* Allocate tty3270 structure on first open. */ @@ -879,16 +880,6 @@ tty3270_open(struct tty_struct *tty, struct file * filp) if (IS_ERR(tp)) return PTR_ERR(tp); - INIT_LIST_HEAD(&tp->lines); - INIT_LIST_HEAD(&tp->update); - INIT_LIST_HEAD(&tp->rcl_lines); - tp->rcl_max = 20; - setup_timer(&tp->timer, (void (*)(unsigned long)) tty3270_update, - (unsigned long) tp); - tasklet_init(&tp->readlet, - (void (*)(unsigned long)) tty3270_read_tasklet, - (unsigned long) tp->read); - rc = raw3270_add_view(&tp->view, &tty3270_fn, tty->index + RAW3270_FIRSTMINOR); if (rc) { @@ -903,7 +894,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp) return rc; } - tp->tty = tty; + tty_port_tty_set(&tp->port, tty); tty->low_latency = 0; tty->driver_data = tp; tty->winsize.ws_row = tp->view.rows - 2; @@ -917,7 +908,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp) for (i = 0; i < tp->view.rows - 2; i++) tty3270_blank_line(tp); - tp->kbd->tty = tty; + tp->kbd->port = &tp->port; tp->kbd->fn_handler[KVAL(K_INCRCONSOLE)] = tty3270_exit_tty; tp->kbd->fn_handler[KVAL(K_SCROLLBACK)] = tty3270_scroll_backward; tp->kbd->fn_handler[KVAL(K_SCROLLFORW)] = tty3270_scroll_forward; @@ -935,14 +926,13 @@ tty3270_open(struct tty_struct *tty, struct file * filp) static void tty3270_close(struct tty_struct *tty, struct file * filp) { - struct tty3270 *tp; + struct tty3270 *tp = tty->driver_data; if (tty->count > 1) return; - tp = (struct tty3270 *) tty->driver_data; if (tp) { tty->driver_data = NULL; - tp->tty = tp->kbd->tty = NULL; + tty_port_tty_set(&tp->port, NULL); raw3270_put_view(&tp->view); } } @@ -1391,7 +1381,7 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch) tty3270_lf(tp); break; case 'Z': /* Respond ID. */ - kbd_puts_queue(tp->tty, "\033[?6c"); + kbd_puts_queue(&tp->port, "\033[?6c"); break; case '7': /* Save cursor position. */ tp->saved_cx = tp->cx; @@ -1437,11 +1427,11 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch) tp->esc_state = ESnormal; if (ch == 'n' && !tp->esc_ques) { if (tp->esc_par[0] == 5) /* Status report. */ - kbd_puts_queue(tp->tty, "\033[0n"); + kbd_puts_queue(&tp->port, "\033[0n"); else if (tp->esc_par[0] == 6) { /* Cursor report. */ char buf[40]; sprintf(buf, "\033[%d;%dR", tp->cy + 1, tp->cx + 1); - kbd_puts_queue(tp->tty, buf); + kbd_puts_queue(&tp->port, buf); } return; } @@ -1513,12 +1503,13 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch) * String write routine for 3270 ttys */ static void -tty3270_do_write(struct tty3270 *tp, const unsigned char *buf, int count) +tty3270_do_write(struct tty3270 *tp, struct tty_struct *tty, + const unsigned char *buf, int count) { int i_msg, i; spin_lock_bh(&tp->view.lock); - for (i_msg = 0; !tp->tty->stopped && i_msg < count; i_msg++) { + for (i_msg = 0; !tty->stopped && i_msg < count; i_msg++) { if (tp->esc_state != 0) { /* Continue escape sequence. */ tty3270_escape_sequence(tp, buf[i_msg]); @@ -1595,10 +1586,10 @@ tty3270_write(struct tty_struct * tty, if (!tp) return 0; if (tp->char_count > 0) { - tty3270_do_write(tp, tp->char_buf, tp->char_count); + tty3270_do_write(tp, tty, tp->char_buf, tp->char_count); tp->char_count = 0; } - tty3270_do_write(tp, buf, count); + tty3270_do_write(tp, tty, buf, count); return count; } @@ -1629,7 +1620,7 @@ tty3270_flush_chars(struct tty_struct *tty) if (!tp) return; if (tp->char_count > 0) { - tty3270_do_write(tp, tp->char_buf, tp->char_count); + tty3270_do_write(tp, tty, tp->char_buf, tp->char_count); tp->char_count = 0; } } diff --git a/trunk/drivers/s390/cio/ccwgroup.c b/trunk/drivers/s390/cio/ccwgroup.c index 5f1dc6fb5708..731470e68493 100644 --- a/trunk/drivers/s390/cio/ccwgroup.c +++ b/trunk/drivers/s390/cio/ccwgroup.c @@ -1,7 +1,7 @@ /* * bus driver for ccwgroup * - * Copyright IBM Corp. 2002, 2009 + * Copyright IBM Corp. 2002, 2012 * * Author(s): Arnd Bergmann (arndb@de.ibm.com) * Cornelia Huck (cornelia.huck@de.ibm.com) @@ -15,10 +15,13 @@ #include #include +#include #include #include -#define CCW_BUS_ID_SIZE 20 +#include "device.h" + +#define CCW_BUS_ID_SIZE 10 /* In Linux 2.4, we had a channel device layer called "chandev" * that did all sorts of obscure stuff for networking devices. @@ -27,19 +30,6 @@ * to devices that use multiple subchannels. */ -/* a device matches a driver if all its slave devices match the same - * entry of the driver */ -static int ccwgroup_bus_match(struct device *dev, struct device_driver * drv) -{ - struct ccwgroup_device *gdev = to_ccwgroupdev(dev); - struct ccwgroup_driver *gdrv = to_ccwgroupdrv(drv); - - if (gdev->creator_id == gdrv->driver_id) - return 1; - - return 0; -} - static struct bus_type ccwgroup_bus_type; static void __ccwgroup_remove_symlinks(struct ccwgroup_device *gdev) @@ -254,9 +244,10 @@ static int __ccwgroup_create_symlinks(struct ccwgroup_device *gdev) return 0; } -static int __get_next_bus_id(const char **buf, char *bus_id) +static int __get_next_id(const char **buf, struct ccw_dev_id *id) { - int rc, len; + unsigned int cssid, ssid, devno; + int ret = 0, len; char *start, *end; start = (char *)*buf; @@ -271,49 +262,40 @@ static int __get_next_bus_id(const char **buf, char *bus_id) len = end - start + 1; end++; } - if (len < CCW_BUS_ID_SIZE) { - strlcpy(bus_id, start, len); - rc = 0; + if (len <= CCW_BUS_ID_SIZE) { + if (sscanf(start, "%2x.%1x.%04x", &cssid, &ssid, &devno) != 3) + ret = -EINVAL; } else - rc = -EINVAL; - *buf = end; - return rc; -} - -static int __is_valid_bus_id(char bus_id[CCW_BUS_ID_SIZE]) -{ - int cssid, ssid, devno; + ret = -EINVAL; - /* Must be of form %x.%x.%04x */ - if (sscanf(bus_id, "%x.%1x.%04x", &cssid, &ssid, &devno) != 3) - return 0; - return 1; + if (!ret) { + id->ssid = ssid; + id->devno = devno; + } + *buf = end; + return ret; } /** - * ccwgroup_create_from_string() - create and register a ccw group device - * @root: parent device for the new device - * @creator_id: identifier of creating driver - * @cdrv: ccw driver of slave devices + * ccwgroup_create_dev() - create and register a ccw group device + * @parent: parent device for the new device + * @gdrv: driver for the new group device * @num_devices: number of slave devices * @buf: buffer containing comma separated bus ids of slave devices * - * Create and register a new ccw group device as a child of @root. Slave - * devices are obtained from the list of bus ids given in @buf and must all - * belong to @cdrv. + * Create and register a new ccw group device as a child of @parent. Slave + * devices are obtained from the list of bus ids given in @buf. * Returns: * %0 on success and an error code on failure. * Context: * non-atomic */ -int ccwgroup_create_from_string(struct device *root, unsigned int creator_id, - struct ccw_driver *cdrv, int num_devices, - const char *buf) +int ccwgroup_create_dev(struct device *parent, struct ccwgroup_driver *gdrv, + int num_devices, const char *buf) { struct ccwgroup_device *gdev; + struct ccw_dev_id dev_id; int rc, i; - char tmp_bus_id[CCW_BUS_ID_SIZE]; - const char *curr_buf; gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]), GFP_KERNEL); @@ -323,29 +305,24 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id, atomic_set(&gdev->onoff, 0); mutex_init(&gdev->reg_mutex); mutex_lock(&gdev->reg_mutex); - gdev->creator_id = creator_id; gdev->count = num_devices; gdev->dev.bus = &ccwgroup_bus_type; - gdev->dev.parent = root; + gdev->dev.parent = parent; gdev->dev.release = ccwgroup_release; device_initialize(&gdev->dev); - curr_buf = buf; - for (i = 0; i < num_devices && curr_buf; i++) { - rc = __get_next_bus_id(&curr_buf, tmp_bus_id); + for (i = 0; i < num_devices && buf; i++) { + rc = __get_next_id(&buf, &dev_id); if (rc != 0) goto error; - if (!__is_valid_bus_id(tmp_bus_id)) { - rc = -EINVAL; - goto error; - } - gdev->cdev[i] = get_ccwdev_by_busid(cdrv, tmp_bus_id); + gdev->cdev[i] = get_ccwdev_by_dev_id(&dev_id); /* * All devices have to be of the same type in * order to be grouped. */ - if (!gdev->cdev[i] - || gdev->cdev[i]->id.driver_info != + if (!gdev->cdev[i] || !gdev->cdev[i]->drv || + gdev->cdev[i]->drv != gdev->cdev[0]->drv || + gdev->cdev[i]->id.driver_info != gdev->cdev[0]->id.driver_info) { rc = -EINVAL; goto error; @@ -361,18 +338,25 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id, spin_unlock_irq(gdev->cdev[i]->ccwlock); } /* Check for sufficient number of bus ids. */ - if (i < num_devices && !curr_buf) { + if (i < num_devices) { rc = -EINVAL; goto error; } /* Check for trailing stuff. */ - if (i == num_devices && strlen(curr_buf) > 0) { + if (i == num_devices && strlen(buf) > 0) { rc = -EINVAL; goto error; } dev_set_name(&gdev->dev, "%s", dev_name(&gdev->cdev[0]->dev)); gdev->dev.groups = ccwgroup_attr_groups; + + if (gdrv) { + gdev->dev.driver = &gdrv->driver; + rc = gdrv->setup ? gdrv->setup(gdev) : 0; + if (rc) + goto error; + } rc = device_add(&gdev->dev); if (rc) goto error; @@ -397,7 +381,7 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id, put_device(&gdev->dev); return rc; } -EXPORT_SYMBOL(ccwgroup_create_from_string); +EXPORT_SYMBOL(ccwgroup_create_dev); static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action, void *data) @@ -440,14 +424,6 @@ module_exit(cleanup_ccwgroup); /************************** driver stuff ******************************/ -static int ccwgroup_probe(struct device *dev) -{ - struct ccwgroup_device *gdev = to_ccwgroupdev(dev); - struct ccwgroup_driver *gdrv = to_ccwgroupdrv(dev->driver); - - return gdrv->probe ? gdrv->probe(gdev) : -ENODEV; -} - static int ccwgroup_remove(struct device *dev) { struct ccwgroup_device *gdev = to_ccwgroupdev(dev); @@ -542,8 +518,6 @@ static const struct dev_pm_ops ccwgroup_pm_ops = { static struct bus_type ccwgroup_bus_type = { .name = "ccwgroup", - .match = ccwgroup_bus_match, - .probe = ccwgroup_probe, .remove = ccwgroup_remove, .shutdown = ccwgroup_shutdown, .pm = &ccwgroup_pm_ops, diff --git a/trunk/drivers/s390/cio/cio.c b/trunk/drivers/s390/cio/cio.c index a49c46c91983..a6ddaed8793d 100644 --- a/trunk/drivers/s390/cio/cio.c +++ b/trunk/drivers/s390/cio/cio.c @@ -656,51 +656,34 @@ static struct io_subchannel_private console_priv; static int console_subchannel_in_use; /* - * Use cio_tpi to get a pending interrupt and call the interrupt handler. - * Return non-zero if an interrupt was processed, zero otherwise. + * Use cio_tsch to update the subchannel status and call the interrupt handler + * if status had been pending. Called with the console_subchannel lock. */ -static int cio_tpi(void) +static void cio_tsch(struct subchannel *sch) { - struct tpi_info *tpi_info; - struct subchannel *sch; struct irb *irb; int irq_context; - tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id; - if (tpi(NULL) != 1) - return 0; - kstat_cpu(smp_processor_id()).irqs[IO_INTERRUPT]++; - if (tpi_info->adapter_IO) { - do_adapter_IO(tpi_info->isc); - return 1; - } irb = (struct irb *)&S390_lowcore.irb; /* Store interrupt response block to lowcore. */ - if (tsch(tpi_info->schid, irb) != 0) { + if (tsch(sch->schid, irb) != 0) /* Not status pending or not operational. */ - kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; - return 1; - } - sch = (struct subchannel *)(unsigned long)tpi_info->intparm; - if (!sch) { - kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; - return 1; - } + return; + memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw)); + /* Call interrupt handler with updated status. */ irq_context = in_interrupt(); - if (!irq_context) + if (!irq_context) { local_bh_disable(); - irq_enter(); - spin_lock(sch->lock); - memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw)); + irq_enter(); + } if (sch->driver && sch->driver->irq) sch->driver->irq(sch); else kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; - spin_unlock(sch->lock); - irq_exit(); - if (!irq_context) + if (!irq_context) { + irq_exit(); _local_bh_enable(); - return 1; + } } void *cio_get_console_priv(void) @@ -712,34 +695,16 @@ void *cio_get_console_priv(void) * busy wait for the next interrupt on the console */ void wait_cons_dev(void) - __releases(console_subchannel.lock) - __acquires(console_subchannel.lock) { - unsigned long cr6 __attribute__ ((aligned (8))); - unsigned long save_cr6 __attribute__ ((aligned (8))); - - /* - * before entering the spinlock we may already have - * processed the interrupt on a different CPU... - */ if (!console_subchannel_in_use) return; - /* disable all but the console isc */ - __ctl_store (save_cr6, 6, 6); - cr6 = 1UL << (31 - CONSOLE_ISC); - __ctl_load (cr6, 6, 6); - - do { - spin_unlock(console_subchannel.lock); - if (!cio_tpi()) - cpu_relax(); - spin_lock(console_subchannel.lock); - } while (console_subchannel.schib.scsw.cmd.actl != 0); - /* - * restore previous isc value - */ - __ctl_load (save_cr6, 6, 6); + while (1) { + cio_tsch(&console_subchannel); + if (console_subchannel.schib.scsw.cmd.actl == 0) + break; + udelay_simple(100); + } } static int diff --git a/trunk/drivers/s390/cio/device.c b/trunk/drivers/s390/cio/device.c index 02d015259461..f8f952d52045 100644 --- a/trunk/drivers/s390/cio/device.c +++ b/trunk/drivers/s390/cio/device.c @@ -695,7 +695,17 @@ static int match_dev_id(struct device *dev, void *data) return ccw_dev_id_is_equal(&cdev->private->dev_id, dev_id); } -static struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id) +/** + * get_ccwdev_by_dev_id() - obtain device from a ccw device id + * @dev_id: id of the device to be searched + * + * This function searches all devices attached to the ccw bus for a device + * matching @dev_id. + * Returns: + * If a device is found its reference count is increased and returned; + * else %NULL is returned. + */ +struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id) { struct device *dev; @@ -703,6 +713,7 @@ static struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id) return dev ? to_ccwdev(dev) : NULL; } +EXPORT_SYMBOL_GPL(get_ccwdev_by_dev_id); static void ccw_device_do_unbind_bind(struct ccw_device *cdev) { diff --git a/trunk/drivers/s390/cio/device.h b/trunk/drivers/s390/cio/device.h index 179824b3082f..6bace6942396 100644 --- a/trunk/drivers/s390/cio/device.h +++ b/trunk/drivers/s390/cio/device.h @@ -101,6 +101,7 @@ int ccw_device_test_sense_data(struct ccw_device *); void ccw_device_schedule_sch_unregister(struct ccw_device *); int ccw_purge_blacklisted(void); void ccw_device_sched_todo(struct ccw_device *cdev, enum cdev_todo todo); +struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id); /* Function prototypes for device status and basic sense stuff. */ void ccw_device_accumulate_irb(struct ccw_device *, struct irb *); diff --git a/trunk/drivers/s390/cio/qdio_main.c b/trunk/drivers/s390/cio/qdio_main.c index 35c685c374e9..7493efafa0d5 100644 --- a/trunk/drivers/s390/cio/qdio_main.c +++ b/trunk/drivers/s390/cio/qdio_main.c @@ -63,7 +63,7 @@ static inline int do_siga_input(unsigned long schid, unsigned int mask, " ipm %0\n" " srl %0,28\n" : "=d" (cc) - : "d" (__fc), "d" (__schid), "d" (__mask) : "cc", "memory"); + : "d" (__fc), "d" (__schid), "d" (__mask) : "cc"); return cc; } @@ -74,7 +74,7 @@ static inline int do_siga_input(unsigned long schid, unsigned int mask, * @bb: busy bit indicator, set only if SIGA-w/wt could not access a buffer * @fc: function code to perform * - * Returns cc or QDIO_ERROR_SIGA_ACCESS_EXCEPTION. + * Returns condition code. * Note: For IQDC unicast queues only the highest priority queue is processed. */ static inline int do_siga_output(unsigned long schid, unsigned long mask, @@ -85,18 +85,16 @@ static inline int do_siga_output(unsigned long schid, unsigned long mask, register unsigned long __schid asm("1") = schid; register unsigned long __mask asm("2") = mask; register unsigned long __aob asm("3") = aob; - int cc = QDIO_ERROR_SIGA_ACCESS_EXCEPTION; + int cc; asm volatile( " siga 0\n" - "0: ipm %0\n" + " ipm %0\n" " srl %0,28\n" - "1:\n" - EX_TABLE(0b, 1b) - : "+d" (cc), "+d" (__fc), "+d" (__schid), "+d" (__mask), - "+d" (__aob) - : : "cc", "memory"); - *bb = ((unsigned int) __fc) >> 31; + : "=d" (cc), "+d" (__fc), "+d" (__aob) + : "d" (__schid), "d" (__mask) + : "cc"); + *bb = __fc >> 31; return cc; } @@ -167,7 +165,7 @@ static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state, DBF_ERROR("%4x EQBS ERROR", SCH_NO(q)); DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); - q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION, + q->handler(q->irq_ptr->cdev, QDIO_ERROR_GET_BUF_STATE, q->nr, q->first_to_kick, count, q->irq_ptr->int_parm); return 0; } @@ -215,7 +213,7 @@ static int qdio_do_sqbs(struct qdio_q *q, unsigned char state, int start, DBF_ERROR("%4x SQBS ERROR", SCH_NO(q)); DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); - q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION, + q->handler(q->irq_ptr->cdev, QDIO_ERROR_SET_BUF_STATE, q->nr, q->first_to_kick, count, q->irq_ptr->int_parm); return 0; } @@ -313,7 +311,7 @@ static inline int qdio_siga_sync(struct qdio_q *q, unsigned int output, cc = do_siga_sync(schid, output, input, fc); if (unlikely(cc)) DBF_ERROR("%4x SIGA-S:%2d", SCH_NO(q), cc); - return cc; + return (cc) ? -EIO : 0; } static inline int qdio_siga_sync_q(struct qdio_q *q) @@ -384,7 +382,7 @@ static inline int qdio_siga_input(struct qdio_q *q) cc = do_siga_input(schid, q->mask, fc); if (unlikely(cc)) DBF_ERROR("%4x SIGA-R:%2d", SCH_NO(q), cc); - return cc; + return (cc) ? -EIO : 0; } #define qdio_siga_sync_out(q) qdio_siga_sync(q, ~0U, 0) @@ -443,7 +441,7 @@ static void process_buffer_error(struct qdio_q *q, int count) unsigned char state = (q->is_input_q) ? SLSB_P_INPUT_NOT_INIT : SLSB_P_OUTPUT_NOT_INIT; - q->qdio_error |= QDIO_ERROR_SLSB_STATE; + q->qdio_error = QDIO_ERROR_SLSB_STATE; /* special handling for no target buffer empty */ if ((!q->is_input_q && @@ -519,7 +517,7 @@ static int get_inbound_buffer_frontier(struct qdio_q *q) int count, stop; unsigned char state = 0; - q->timestamp = get_clock_fast(); + q->timestamp = get_clock(); /* * Don't check 128 buffers, as otherwise qdio_inbound_q_moved @@ -575,7 +573,7 @@ static int qdio_inbound_q_moved(struct qdio_q *q) bufnr = get_inbound_buffer_frontier(q); - if ((bufnr != q->last_move) || q->qdio_error) { + if (bufnr != q->last_move) { q->last_move = bufnr; if (!is_thinint_irq(q->irq_ptr) && MACHINE_IS_LPAR) q->u.in.timestamp = get_clock(); @@ -790,7 +788,7 @@ static int get_outbound_buffer_frontier(struct qdio_q *q) int count, stop; unsigned char state = 0; - q->timestamp = get_clock_fast(); + q->timestamp = get_clock(); if (need_siga_sync(q)) if (((queue_type(q) != QDIO_IQDIO_QFMT) && @@ -863,7 +861,7 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q) bufnr = get_outbound_buffer_frontier(q); - if ((bufnr != q->last_move) || q->qdio_error) { + if (bufnr != q->last_move) { q->last_move = bufnr; DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out moved:%1d", q->nr); return 1; @@ -894,13 +892,16 @@ static int qdio_kick_outbound_q(struct qdio_q *q, unsigned long aob) goto retry; } DBF_ERROR("%4x cc2 BBC:%1d", SCH_NO(q), q->nr); - cc |= QDIO_ERROR_SIGA_BUSY; - } else + cc = -EBUSY; + } else { DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", q->nr); + cc = -ENOBUFS; + } break; case 1: case 3: DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc); + cc = -EIO; break; } if (retries) { @@ -1090,7 +1091,7 @@ static void qdio_handle_activate_check(struct ccw_device *cdev, } count = sub_buf(q->first_to_check, q->first_to_kick); - q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION, + q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE, q->nr, q->first_to_kick, count, irq_ptr->int_parm); no_handler: qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED); @@ -1691,7 +1692,7 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags, "do%02x b:%02x c:%02x", callflags, bufnr, count); if (irq_ptr->state != QDIO_IRQ_STATE_ACTIVE) - return -EBUSY; + return -EIO; if (!count) return 0; if (callflags & QDIO_FLAG_SYNC_INPUT) diff --git a/trunk/drivers/s390/crypto/ap_bus.c b/trunk/drivers/s390/crypto/ap_bus.c index 7e9a72eb2fe0..b987d4619586 100644 --- a/trunk/drivers/s390/crypto/ap_bus.c +++ b/trunk/drivers/s390/crypto/ap_bus.c @@ -215,7 +215,7 @@ ap_queue_interruption_control(ap_qid_t qid, void *ind) register struct ap_queue_status reg1_out asm ("1"); register void *reg2 asm ("2") = ind; asm volatile( - ".long 0xb2af0000" /* PQAP(RAPQ) */ + ".long 0xb2af0000" /* PQAP(AQIC) */ : "+d" (reg0), "+d" (reg1_in), "=d" (reg1_out), "+d" (reg2) : : "cc" ); @@ -232,7 +232,7 @@ __ap_query_functions(ap_qid_t qid, unsigned int *functions) register unsigned long reg2 asm ("2"); asm volatile( - ".long 0xb2af0000\n" + ".long 0xb2af0000\n" /* PQAP(TAPQ) */ "0:\n" EX_TABLE(0b, 0b) : "+d" (reg0), "+d" (reg1), "=d" (reg2) @@ -391,7 +391,7 @@ __ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length, reg0 |= 0x400000UL; asm volatile ( - "0: .long 0xb2ad0042\n" /* DQAP */ + "0: .long 0xb2ad0042\n" /* NQAP */ " brc 2,0b" : "+d" (reg0), "=d" (reg1), "+d" (reg2), "+d" (reg3) : "d" (reg4), "d" (reg5), "m" (*(msgblock *) msg) @@ -450,7 +450,7 @@ __ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length) asm volatile( - "0: .long 0xb2ae0064\n" + "0: .long 0xb2ae0064\n" /* DQAP */ " brc 6,0b\n" : "+d" (reg0), "=d" (reg1), "+d" (reg2), "+d" (reg4), "+d" (reg5), "+d" (reg6), "+d" (reg7), @@ -836,12 +836,12 @@ static void __ap_flush_queue(struct ap_device *ap_dev) list_for_each_entry_safe(ap_msg, next, &ap_dev->pendingq, list) { list_del_init(&ap_msg->list); ap_dev->pendingq_count--; - ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV)); + ap_msg->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV)); } list_for_each_entry_safe(ap_msg, next, &ap_dev->requestq, list) { list_del_init(&ap_msg->list); ap_dev->requestq_count--; - ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV)); + ap_msg->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV)); } } @@ -1329,7 +1329,7 @@ static int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags) continue; list_del_init(&ap_msg->list); ap_dev->pendingq_count--; - ap_dev->drv->receive(ap_dev, ap_msg, ap_dev->reply); + ap_msg->receive(ap_dev, ap_msg, ap_dev->reply); break; } if (ap_dev->queue_count > 0) @@ -1450,10 +1450,10 @@ static int __ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_ms return -EBUSY; case AP_RESPONSE_REQ_FAC_NOT_INST: case AP_RESPONSE_MESSAGE_TOO_BIG: - ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-EINVAL)); + ap_msg->receive(ap_dev, ap_msg, ERR_PTR(-EINVAL)); return -EINVAL; default: /* Device is gone. */ - ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV)); + ap_msg->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV)); return -ENODEV; } } else { @@ -1471,6 +1471,10 @@ void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg) unsigned long flags; int rc; + /* For asynchronous message handling a valid receive-callback + * is required. */ + BUG_ON(!ap_msg->receive); + spin_lock_bh(&ap_dev->lock); if (!ap_dev->unregistered) { /* Make room on the queue by polling for finished requests. */ @@ -1482,7 +1486,7 @@ void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg) if (rc == -ENODEV) ap_dev->unregistered = 1; } else { - ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV)); + ap_msg->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV)); rc = -ENODEV; } spin_unlock_bh(&ap_dev->lock); diff --git a/trunk/drivers/s390/crypto/ap_bus.h b/trunk/drivers/s390/crypto/ap_bus.h index d960a6309eec..726fc65809d8 100644 --- a/trunk/drivers/s390/crypto/ap_bus.h +++ b/trunk/drivers/s390/crypto/ap_bus.h @@ -136,9 +136,6 @@ struct ap_driver { int (*probe)(struct ap_device *); void (*remove)(struct ap_device *); - /* receive is called from tasklet context */ - void (*receive)(struct ap_device *, struct ap_message *, - struct ap_message *); int request_timeout; /* request timeout in jiffies */ }; @@ -183,6 +180,9 @@ struct ap_message { void *private; /* ap driver private pointer. */ unsigned int special:1; /* Used for special commands. */ + /* receive is called from tasklet context */ + void (*receive)(struct ap_device *, struct ap_message *, + struct ap_message *); }; #define AP_DEVICE(dt) \ @@ -199,6 +199,7 @@ static inline void ap_init_message(struct ap_message *ap_msg) ap_msg->psmid = 0; ap_msg->length = 0; ap_msg->special = 0; + ap_msg->receive = NULL; } /* diff --git a/trunk/drivers/s390/crypto/zcrypt_cex2a.c b/trunk/drivers/s390/crypto/zcrypt_cex2a.c index 084286728166..46812440425a 100644 --- a/trunk/drivers/s390/crypto/zcrypt_cex2a.c +++ b/trunk/drivers/s390/crypto/zcrypt_cex2a.c @@ -77,7 +77,6 @@ static void zcrypt_cex2a_receive(struct ap_device *, struct ap_message *, static struct ap_driver zcrypt_cex2a_driver = { .probe = zcrypt_cex2a_probe, .remove = zcrypt_cex2a_remove, - .receive = zcrypt_cex2a_receive, .ids = zcrypt_cex2a_ids, .request_timeout = CEX2A_CLEANUP_TIME, }; @@ -349,6 +348,7 @@ static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev, ap_msg.message = kmalloc(CEX3A_MAX_MESSAGE_SIZE, GFP_KERNEL); if (!ap_msg.message) return -ENOMEM; + ap_msg.receive = zcrypt_cex2a_receive; ap_msg.psmid = (((unsigned long long) current->pid) << 32) + atomic_inc_return(&zcrypt_step); ap_msg.private = &work; @@ -390,6 +390,7 @@ static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev, ap_msg.message = kmalloc(CEX3A_MAX_MESSAGE_SIZE, GFP_KERNEL); if (!ap_msg.message) return -ENOMEM; + ap_msg.receive = zcrypt_cex2a_receive; ap_msg.psmid = (((unsigned long long) current->pid) << 32) + atomic_inc_return(&zcrypt_step); ap_msg.private = &work; diff --git a/trunk/drivers/s390/crypto/zcrypt_pcica.c b/trunk/drivers/s390/crypto/zcrypt_pcica.c index 0effca925451..ad7951c21b79 100644 --- a/trunk/drivers/s390/crypto/zcrypt_pcica.c +++ b/trunk/drivers/s390/crypto/zcrypt_pcica.c @@ -67,7 +67,6 @@ static void zcrypt_pcica_receive(struct ap_device *, struct ap_message *, static struct ap_driver zcrypt_pcica_driver = { .probe = zcrypt_pcica_probe, .remove = zcrypt_pcica_remove, - .receive = zcrypt_pcica_receive, .ids = zcrypt_pcica_ids, .request_timeout = PCICA_CLEANUP_TIME, }; @@ -284,6 +283,7 @@ static long zcrypt_pcica_modexpo(struct zcrypt_device *zdev, ap_msg.message = kmalloc(PCICA_MAX_MESSAGE_SIZE, GFP_KERNEL); if (!ap_msg.message) return -ENOMEM; + ap_msg.receive = zcrypt_pcica_receive; ap_msg.psmid = (((unsigned long long) current->pid) << 32) + atomic_inc_return(&zcrypt_step); ap_msg.private = &work; @@ -322,6 +322,7 @@ static long zcrypt_pcica_modexpo_crt(struct zcrypt_device *zdev, ap_msg.message = kmalloc(PCICA_MAX_MESSAGE_SIZE, GFP_KERNEL); if (!ap_msg.message) return -ENOMEM; + ap_msg.receive = zcrypt_pcica_receive; ap_msg.psmid = (((unsigned long long) current->pid) << 32) + atomic_inc_return(&zcrypt_step); ap_msg.private = &work; diff --git a/trunk/drivers/s390/crypto/zcrypt_pcicc.c b/trunk/drivers/s390/crypto/zcrypt_pcicc.c index f9523c0cc8d2..e5dd335fda53 100644 --- a/trunk/drivers/s390/crypto/zcrypt_pcicc.c +++ b/trunk/drivers/s390/crypto/zcrypt_pcicc.c @@ -79,7 +79,6 @@ static void zcrypt_pcicc_receive(struct ap_device *, struct ap_message *, static struct ap_driver zcrypt_pcicc_driver = { .probe = zcrypt_pcicc_probe, .remove = zcrypt_pcicc_remove, - .receive = zcrypt_pcicc_receive, .ids = zcrypt_pcicc_ids, .request_timeout = PCICC_CLEANUP_TIME, }; @@ -488,6 +487,7 @@ static long zcrypt_pcicc_modexpo(struct zcrypt_device *zdev, ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL); if (!ap_msg.message) return -ENOMEM; + ap_msg.receive = zcrypt_pcicc_receive; ap_msg.length = PAGE_SIZE; ap_msg.psmid = (((unsigned long long) current->pid) << 32) + atomic_inc_return(&zcrypt_step); @@ -527,6 +527,7 @@ static long zcrypt_pcicc_modexpo_crt(struct zcrypt_device *zdev, ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL); if (!ap_msg.message) return -ENOMEM; + ap_msg.receive = zcrypt_pcicc_receive; ap_msg.length = PAGE_SIZE; ap_msg.psmid = (((unsigned long long) current->pid) << 32) + atomic_inc_return(&zcrypt_step); diff --git a/trunk/drivers/s390/crypto/zcrypt_pcixcc.c b/trunk/drivers/s390/crypto/zcrypt_pcixcc.c index cf1cbd4747f4..f7cc43401816 100644 --- a/trunk/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/trunk/drivers/s390/crypto/zcrypt_pcixcc.c @@ -89,7 +89,6 @@ static void zcrypt_pcixcc_receive(struct ap_device *, struct ap_message *, static struct ap_driver zcrypt_pcixcc_driver = { .probe = zcrypt_pcixcc_probe, .remove = zcrypt_pcixcc_remove, - .receive = zcrypt_pcixcc_receive, .ids = zcrypt_pcixcc_ids, .request_timeout = PCIXCC_CLEANUP_TIME, }; @@ -698,6 +697,7 @@ static long zcrypt_pcixcc_modexpo(struct zcrypt_device *zdev, ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL); if (!ap_msg.message) return -ENOMEM; + ap_msg.receive = zcrypt_pcixcc_receive; ap_msg.psmid = (((unsigned long long) current->pid) << 32) + atomic_inc_return(&zcrypt_step); ap_msg.private = &resp_type; @@ -738,6 +738,7 @@ static long zcrypt_pcixcc_modexpo_crt(struct zcrypt_device *zdev, ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL); if (!ap_msg.message) return -ENOMEM; + ap_msg.receive = zcrypt_pcixcc_receive; ap_msg.psmid = (((unsigned long long) current->pid) << 32) + atomic_inc_return(&zcrypt_step); ap_msg.private = &resp_type; @@ -778,6 +779,7 @@ static long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev, ap_msg.message = kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL); if (!ap_msg.message) return -ENOMEM; + ap_msg.receive = zcrypt_pcixcc_receive; ap_msg.psmid = (((unsigned long long) current->pid) << 32) + atomic_inc_return(&zcrypt_step); ap_msg.private = &resp_type; @@ -818,6 +820,7 @@ static long zcrypt_pcixcc_rng(struct zcrypt_device *zdev, ap_msg.message = kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL); if (!ap_msg.message) return -ENOMEM; + ap_msg.receive = zcrypt_pcixcc_receive; ap_msg.psmid = (((unsigned long long) current->pid) << 32) + atomic_inc_return(&zcrypt_step); ap_msg.private = &resp_type; diff --git a/trunk/drivers/s390/net/Kconfig b/trunk/drivers/s390/net/Kconfig index 9b66d2d1809b..dfda748c4000 100644 --- a/trunk/drivers/s390/net/Kconfig +++ b/trunk/drivers/s390/net/Kconfig @@ -4,11 +4,10 @@ menu "S/390 network device drivers" config LCS def_tristate m prompt "Lan Channel Station Interface" - depends on CCW && NETDEVICES && (ETHERNET || TR || FDDI) + depends on CCW && NETDEVICES && (ETHERNET || FDDI) help Select this option if you want to use LCS networking on IBM System z. - This device driver supports Token Ring (IEEE 802.5), - FDDI (IEEE 802.7) and Ethernet. + This device driver supports FDDI (IEEE 802.7) and Ethernet. To compile as a module, choose M. The module name is lcs. If you do not know what it is, it's safe to choose Y. diff --git a/trunk/drivers/s390/net/claw.c b/trunk/drivers/s390/net/claw.c index b41fae37d3af..6b1ff90d2f00 100644 --- a/trunk/drivers/s390/net/claw.c +++ b/trunk/drivers/s390/net/claw.c @@ -136,7 +136,6 @@ static inline void claw_set_busy(struct net_device *dev) { ((struct claw_privbk *)dev->ml_priv)->tbusy = 1; - eieio(); } static inline void @@ -144,13 +143,11 @@ claw_clear_busy(struct net_device *dev) { clear_bit(0, &(((struct claw_privbk *) dev->ml_priv)->tbusy)); netif_wake_queue(dev); - eieio(); } static inline int claw_check_busy(struct net_device *dev) { - eieio(); return ((struct claw_privbk *) dev->ml_priv)->tbusy; } @@ -233,8 +230,6 @@ static ssize_t claw_rbuff_show(struct device *dev, static ssize_t claw_rbuff_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); -static int claw_add_files(struct device *dev); -static void claw_remove_files(struct device *dev); /* Functions for System Validate */ static int claw_process_control( struct net_device *dev, struct ccwbk * p_ccw); @@ -267,12 +262,10 @@ static struct ccwgroup_driver claw_group_driver = { .owner = THIS_MODULE, .name = "claw", }, - .max_slaves = 2, - .driver_id = 0xC3D3C1E6, - .probe = claw_probe, - .remove = claw_remove_device, - .set_online = claw_new_device, - .set_offline = claw_shutdown_device, + .setup = claw_probe, + .remove = claw_remove_device, + .set_online = claw_new_device, + .set_offline = claw_shutdown_device, .prepare = claw_pm_prepare, }; @@ -293,30 +286,24 @@ static struct ccw_driver claw_ccw_driver = { .int_class = IOINT_CLW, }; -static ssize_t -claw_driver_group_store(struct device_driver *ddrv, const char *buf, - size_t count) +static ssize_t claw_driver_group_store(struct device_driver *ddrv, + const char *buf, size_t count) { int err; - err = ccwgroup_create_from_string(claw_root_dev, - claw_group_driver.driver_id, - &claw_ccw_driver, 2, buf); + err = ccwgroup_create_dev(claw_root_dev, &claw_group_driver, 2, buf); return err ? err : count; } - static DRIVER_ATTR(group, 0200, NULL, claw_driver_group_store); -static struct attribute *claw_group_attrs[] = { +static struct attribute *claw_drv_attrs[] = { &driver_attr_group.attr, NULL, }; - -static struct attribute_group claw_group_attr_group = { - .attrs = claw_group_attrs, +static struct attribute_group claw_drv_attr_group = { + .attrs = claw_drv_attrs, }; - -static const struct attribute_group *claw_group_attr_groups[] = { - &claw_group_attr_group, +static const struct attribute_group *claw_drv_attr_groups[] = { + &claw_drv_attr_group, NULL, }; @@ -324,60 +311,6 @@ static const struct attribute_group *claw_group_attr_groups[] = { * Key functions */ -/*----------------------------------------------------------------* - * claw_probe * - * this function is called for each CLAW device. * - *----------------------------------------------------------------*/ -static int -claw_probe(struct ccwgroup_device *cgdev) -{ - int rc; - struct claw_privbk *privptr=NULL; - - CLAW_DBF_TEXT(2, setup, "probe"); - if (!get_device(&cgdev->dev)) - return -ENODEV; - privptr = kzalloc(sizeof(struct claw_privbk), GFP_KERNEL); - dev_set_drvdata(&cgdev->dev, privptr); - if (privptr == NULL) { - probe_error(cgdev); - put_device(&cgdev->dev); - CLAW_DBF_TEXT_(2, setup, "probex%d", -ENOMEM); - return -ENOMEM; - } - privptr->p_mtc_envelope= kzalloc( MAX_ENVELOPE_SIZE, GFP_KERNEL); - privptr->p_env = kzalloc(sizeof(struct claw_env), GFP_KERNEL); - if ((privptr->p_mtc_envelope==NULL) || (privptr->p_env==NULL)) { - probe_error(cgdev); - put_device(&cgdev->dev); - CLAW_DBF_TEXT_(2, setup, "probex%d", -ENOMEM); - return -ENOMEM; - } - memcpy(privptr->p_env->adapter_name,WS_NAME_NOT_DEF,8); - memcpy(privptr->p_env->host_name,WS_NAME_NOT_DEF,8); - memcpy(privptr->p_env->api_type,WS_NAME_NOT_DEF,8); - privptr->p_env->packing = 0; - privptr->p_env->write_buffers = 5; - privptr->p_env->read_buffers = 5; - privptr->p_env->read_size = CLAW_FRAME_SIZE; - privptr->p_env->write_size = CLAW_FRAME_SIZE; - rc = claw_add_files(&cgdev->dev); - if (rc) { - probe_error(cgdev); - put_device(&cgdev->dev); - dev_err(&cgdev->dev, "Creating the /proc files for a new" - " CLAW device failed\n"); - CLAW_DBF_TEXT_(2, setup, "probex%d", rc); - return rc; - } - privptr->p_env->p_priv = privptr; - cgdev->cdev[0]->handler = claw_irq_handler; - cgdev->cdev[1]->handler = claw_irq_handler; - CLAW_DBF_TEXT(2, setup, "prbext 0"); - - return 0; -} /* end of claw_probe */ - /*-------------------------------------------------------------------* * claw_tx * *-------------------------------------------------------------------*/ @@ -3093,7 +3026,6 @@ claw_remove_device(struct ccwgroup_device *cgdev) dev_info(&cgdev->dev, " will be removed.\n"); if (cgdev->state == CCWGROUP_ONLINE) claw_shutdown_device(cgdev); - claw_remove_files(&cgdev->dev); kfree(priv->p_mtc_envelope); priv->p_mtc_envelope=NULL; kfree(priv->p_env); @@ -3321,7 +3253,6 @@ claw_rbuff_write(struct device *dev, struct device_attribute *attr, CLAW_DBF_TEXT_(2, setup, "RB=%d", p_env->read_buffers); return count; } - static DEVICE_ATTR(read_buffer, 0644, claw_rbuff_show, claw_rbuff_write); static struct attribute *claw_attr[] = { @@ -3332,40 +3263,73 @@ static struct attribute *claw_attr[] = { &dev_attr_host_name.attr, NULL, }; - static struct attribute_group claw_attr_group = { .attrs = claw_attr, }; +static const struct attribute_group *claw_attr_groups[] = { + &claw_attr_group, + NULL, +}; +static const struct device_type claw_devtype = { + .name = "claw", + .groups = claw_attr_groups, +}; -static int -claw_add_files(struct device *dev) +/*----------------------------------------------------------------* + * claw_probe * + * this function is called for each CLAW device. * + *----------------------------------------------------------------*/ +static int claw_probe(struct ccwgroup_device *cgdev) { - CLAW_DBF_TEXT(2, setup, "add_file"); - return sysfs_create_group(&dev->kobj, &claw_attr_group); -} + struct claw_privbk *privptr = NULL; -static void -claw_remove_files(struct device *dev) -{ - CLAW_DBF_TEXT(2, setup, "rem_file"); - sysfs_remove_group(&dev->kobj, &claw_attr_group); -} + CLAW_DBF_TEXT(2, setup, "probe"); + if (!get_device(&cgdev->dev)) + return -ENODEV; + privptr = kzalloc(sizeof(struct claw_privbk), GFP_KERNEL); + dev_set_drvdata(&cgdev->dev, privptr); + if (privptr == NULL) { + probe_error(cgdev); + put_device(&cgdev->dev); + CLAW_DBF_TEXT_(2, setup, "probex%d", -ENOMEM); + return -ENOMEM; + } + privptr->p_mtc_envelope = kzalloc(MAX_ENVELOPE_SIZE, GFP_KERNEL); + privptr->p_env = kzalloc(sizeof(struct claw_env), GFP_KERNEL); + if ((privptr->p_mtc_envelope == NULL) || (privptr->p_env == NULL)) { + probe_error(cgdev); + put_device(&cgdev->dev); + CLAW_DBF_TEXT_(2, setup, "probex%d", -ENOMEM); + return -ENOMEM; + } + memcpy(privptr->p_env->adapter_name, WS_NAME_NOT_DEF, 8); + memcpy(privptr->p_env->host_name, WS_NAME_NOT_DEF, 8); + memcpy(privptr->p_env->api_type, WS_NAME_NOT_DEF, 8); + privptr->p_env->packing = 0; + privptr->p_env->write_buffers = 5; + privptr->p_env->read_buffers = 5; + privptr->p_env->read_size = CLAW_FRAME_SIZE; + privptr->p_env->write_size = CLAW_FRAME_SIZE; + privptr->p_env->p_priv = privptr; + cgdev->cdev[0]->handler = claw_irq_handler; + cgdev->cdev[1]->handler = claw_irq_handler; + cgdev->dev.type = &claw_devtype; + CLAW_DBF_TEXT(2, setup, "prbext 0"); + + return 0; +} /* end of claw_probe */ /*--------------------------------------------------------------------* * claw_init and cleanup * *---------------------------------------------------------------------*/ -static void __exit -claw_cleanup(void) +static void __exit claw_cleanup(void) { - driver_remove_file(&claw_group_driver.driver, - &driver_attr_group); ccwgroup_driver_unregister(&claw_group_driver); ccw_driver_unregister(&claw_ccw_driver); root_device_unregister(claw_root_dev); claw_unregister_debug_facility(); pr_info("Driver unloaded\n"); - } /** @@ -3374,8 +3338,7 @@ claw_cleanup(void) * * @return 0 on success, !0 on error. */ -static int __init -claw_init(void) +static int __init claw_init(void) { int ret = 0; @@ -3394,7 +3357,7 @@ claw_init(void) ret = ccw_driver_register(&claw_ccw_driver); if (ret) goto ccw_err; - claw_group_driver.driver.groups = claw_group_attr_groups; + claw_group_driver.driver.groups = claw_drv_attr_groups; ret = ccwgroup_driver_register(&claw_group_driver); if (ret) goto ccwgroup_err; diff --git a/trunk/drivers/s390/net/ctcm_main.c b/trunk/drivers/s390/net/ctcm_main.c index 11f3b071f305..3cd25544a27a 100644 --- a/trunk/drivers/s390/net/ctcm_main.c +++ b/trunk/drivers/s390/net/ctcm_main.c @@ -1296,6 +1296,11 @@ static void ctcm_irq_handler(struct ccw_device *cdev, } +static const struct device_type ctcm_devtype = { + .name = "ctcm", + .groups = ctcm_attr_groups, +}; + /** * Add ctcm specific attributes. * Add ctcm private data. @@ -1307,7 +1312,6 @@ static void ctcm_irq_handler(struct ccw_device *cdev, static int ctcm_probe_device(struct ccwgroup_device *cgdev) { struct ctcm_priv *priv; - int rc; CTCM_DBF_TEXT_(SETUP, CTC_DBF_INFO, "%s %p", @@ -1324,17 +1328,11 @@ static int ctcm_probe_device(struct ccwgroup_device *cgdev) put_device(&cgdev->dev); return -ENOMEM; } - - rc = ctcm_add_files(&cgdev->dev); - if (rc) { - kfree(priv); - put_device(&cgdev->dev); - return rc; - } priv->buffer_size = CTCM_BUFSIZE_DEFAULT; cgdev->cdev[0]->handler = ctcm_irq_handler; cgdev->cdev[1]->handler = ctcm_irq_handler; dev_set_drvdata(&cgdev->dev, priv); + cgdev->dev.type = &ctcm_devtype; return 0; } @@ -1611,11 +1609,6 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev) goto out_dev; } - if (ctcm_add_attributes(&cgdev->dev)) { - result = -ENODEV; - goto out_unregister; - } - strlcpy(priv->fsm->name, dev->name, sizeof(priv->fsm->name)); dev_info(&dev->dev, @@ -1629,8 +1622,6 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev) priv->channel[CTCM_WRITE]->id, priv->protocol); return 0; -out_unregister: - unregister_netdev(dev); out_dev: ctcm_free_netdevice(dev); out_ccw2: @@ -1669,7 +1660,6 @@ static int ctcm_shutdown_device(struct ccwgroup_device *cgdev) /* Close the device */ ctcm_close(dev); dev->flags &= ~IFF_RUNNING; - ctcm_remove_attributes(&cgdev->dev); channel_free(priv->channel[CTCM_READ]); } else dev = NULL; @@ -1711,7 +1701,6 @@ static void ctcm_remove_device(struct ccwgroup_device *cgdev) if (cgdev->state == CCWGROUP_ONLINE) ctcm_shutdown_device(cgdev); - ctcm_remove_files(&cgdev->dev); dev_set_drvdata(&cgdev->dev, NULL); kfree(priv); put_device(&cgdev->dev); @@ -1778,9 +1767,7 @@ static struct ccwgroup_driver ctcm_group_driver = { .owner = THIS_MODULE, .name = CTC_DRIVER_NAME, }, - .max_slaves = 2, - .driver_id = 0xC3E3C3D4, /* CTCM */ - .probe = ctcm_probe_device, + .setup = ctcm_probe_device, .remove = ctcm_remove_device, .set_online = ctcm_new_device, .set_offline = ctcm_shutdown_device, @@ -1789,31 +1776,25 @@ static struct ccwgroup_driver ctcm_group_driver = { .restore = ctcm_pm_resume, }; -static ssize_t -ctcm_driver_group_store(struct device_driver *ddrv, const char *buf, - size_t count) +static ssize_t ctcm_driver_group_store(struct device_driver *ddrv, + const char *buf, size_t count) { int err; - err = ccwgroup_create_from_string(ctcm_root_dev, - ctcm_group_driver.driver_id, - &ctcm_ccw_driver, 2, buf); + err = ccwgroup_create_dev(ctcm_root_dev, &ctcm_group_driver, 2, buf); return err ? err : count; } - static DRIVER_ATTR(group, 0200, NULL, ctcm_driver_group_store); -static struct attribute *ctcm_group_attrs[] = { +static struct attribute *ctcm_drv_attrs[] = { &driver_attr_group.attr, NULL, }; - -static struct attribute_group ctcm_group_attr_group = { - .attrs = ctcm_group_attrs, +static struct attribute_group ctcm_drv_attr_group = { + .attrs = ctcm_drv_attrs, }; - -static const struct attribute_group *ctcm_group_attr_groups[] = { - &ctcm_group_attr_group, +static const struct attribute_group *ctcm_drv_attr_groups[] = { + &ctcm_drv_attr_group, NULL, }; @@ -1829,7 +1810,6 @@ static const struct attribute_group *ctcm_group_attr_groups[] = { */ static void __exit ctcm_exit(void) { - driver_remove_file(&ctcm_group_driver.driver, &driver_attr_group); ccwgroup_driver_unregister(&ctcm_group_driver); ccw_driver_unregister(&ctcm_ccw_driver); root_device_unregister(ctcm_root_dev); @@ -1867,7 +1847,7 @@ static int __init ctcm_init(void) ret = ccw_driver_register(&ctcm_ccw_driver); if (ret) goto ccw_err; - ctcm_group_driver.driver.groups = ctcm_group_attr_groups; + ctcm_group_driver.driver.groups = ctcm_drv_attr_groups; ret = ccwgroup_driver_register(&ctcm_group_driver); if (ret) goto ccwgroup_err; diff --git a/trunk/drivers/s390/net/ctcm_main.h b/trunk/drivers/s390/net/ctcm_main.h index 24d5215eb0c4..b9056a55d995 100644 --- a/trunk/drivers/s390/net/ctcm_main.h +++ b/trunk/drivers/s390/net/ctcm_main.h @@ -225,13 +225,7 @@ struct ctcm_priv { int ctcm_open(struct net_device *dev); int ctcm_close(struct net_device *dev); -/* - * prototypes for non-static sysfs functions - */ -int ctcm_add_attributes(struct device *dev); -void ctcm_remove_attributes(struct device *dev); -int ctcm_add_files(struct device *dev); -void ctcm_remove_files(struct device *dev); +extern const struct attribute_group *ctcm_attr_groups[]; /* * Compatibility macros for busy handling diff --git a/trunk/drivers/s390/net/ctcm_sysfs.c b/trunk/drivers/s390/net/ctcm_sysfs.c index 650aec1839e9..0c27ae726475 100644 --- a/trunk/drivers/s390/net/ctcm_sysfs.c +++ b/trunk/drivers/s390/net/ctcm_sysfs.c @@ -13,6 +13,7 @@ #define KMSG_COMPONENT "ctcm" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include #include #include #include "ctcm_main.h" @@ -108,10 +109,12 @@ static void ctcm_print_statistics(struct ctcm_priv *priv) } static ssize_t stats_show(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, char *buf) { + struct ccwgroup_device *gdev = to_ccwgroupdev(dev); struct ctcm_priv *priv = dev_get_drvdata(dev); - if (!priv) + + if (!priv || gdev->state != CCWGROUP_ONLINE) return -ENODEV; ctcm_print_statistics(priv); return sprintf(buf, "0\n"); @@ -190,34 +193,14 @@ static struct attribute *ctcm_attr[] = { &dev_attr_protocol.attr, &dev_attr_type.attr, &dev_attr_buffer.attr, + &dev_attr_stats.attr, NULL, }; static struct attribute_group ctcm_attr_group = { .attrs = ctcm_attr, }; - -int ctcm_add_attributes(struct device *dev) -{ - int rc; - - rc = device_create_file(dev, &dev_attr_stats); - - return rc; -} - -void ctcm_remove_attributes(struct device *dev) -{ - device_remove_file(dev, &dev_attr_stats); -} - -int ctcm_add_files(struct device *dev) -{ - return sysfs_create_group(&dev->kobj, &ctcm_attr_group); -} - -void ctcm_remove_files(struct device *dev) -{ - sysfs_remove_group(&dev->kobj, &ctcm_attr_group); -} - +const struct attribute_group *ctcm_attr_groups[] = { + &ctcm_attr_group, + NULL, +}; diff --git a/trunk/drivers/s390/net/lcs.c b/trunk/drivers/s390/net/lcs.c index 687efe4d589a..a3adf4b1c60d 100644 --- a/trunk/drivers/s390/net/lcs.c +++ b/trunk/drivers/s390/net/lcs.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -50,8 +49,7 @@ #include "lcs.h" -#if !defined(CONFIG_ETHERNET) && \ - !defined(CONFIG_TR) && !defined(CONFIG_FDDI) +#if !defined(CONFIG_ETHERNET) && !defined(CONFIG_FDDI) #error Cannot compile lcs.c without some net devices switched on. #endif @@ -1166,10 +1164,7 @@ static void lcs_get_mac_for_ipm(__be32 ipm, char *mac, struct net_device *dev) { LCS_DBF_TEXT(4,trace, "getmac"); - if (dev->type == ARPHRD_IEEE802_TR) - ip_tr_mc_map(ipm, mac); - else - ip_eth_mc_map(ipm, mac); + ip_eth_mc_map(ipm, mac); } /** @@ -1641,12 +1636,6 @@ lcs_startlan_auto(struct lcs_card *card) return 0; #endif -#ifdef CONFIG_TR - card->lan_type = LCS_FRAME_TYPE_TR; - rc = lcs_send_startlan(card, LCS_INITIATOR_TCPIP); - if (rc == 0) - return 0; -#endif #ifdef CONFIG_FDDI card->lan_type = LCS_FRAME_TYPE_FDDI; rc = lcs_send_startlan(card, LCS_INITIATOR_TCPIP); @@ -2051,10 +2040,17 @@ static struct attribute * lcs_attrs[] = { &dev_attr_recover.attr, NULL, }; - static struct attribute_group lcs_attr_group = { .attrs = lcs_attrs, }; +static const struct attribute_group *lcs_attr_groups[] = { + &lcs_attr_group, + NULL, +}; +static const struct device_type lcs_devtype = { + .name = "lcs", + .groups = lcs_attr_groups, +}; /** * lcs_probe_device is called on establishing a new ccwgroup_device. @@ -2063,7 +2059,6 @@ static int lcs_probe_device(struct ccwgroup_device *ccwgdev) { struct lcs_card *card; - int ret; if (!get_device(&ccwgdev->dev)) return -ENODEV; @@ -2075,12 +2070,6 @@ lcs_probe_device(struct ccwgroup_device *ccwgdev) put_device(&ccwgdev->dev); return -ENOMEM; } - ret = sysfs_create_group(&ccwgdev->dev.kobj, &lcs_attr_group); - if (ret) { - lcs_free_card(card); - put_device(&ccwgdev->dev); - return ret; - } dev_set_drvdata(&ccwgdev->dev, card); ccwgdev->cdev[0]->handler = lcs_irq; ccwgdev->cdev[1]->handler = lcs_irq; @@ -2089,7 +2078,9 @@ lcs_probe_device(struct ccwgroup_device *ccwgdev) card->thread_start_mask = 0; card->thread_allowed_mask = 0; card->thread_running_mask = 0; - return 0; + ccwgdev->dev.type = &lcs_devtype; + + return 0; } static int @@ -2172,12 +2163,6 @@ lcs_new_device(struct ccwgroup_device *ccwgdev) dev = alloc_etherdev(0); break; #endif -#ifdef CONFIG_TR - case LCS_FRAME_TYPE_TR: - card->lan_type_trans = tr_type_trans; - dev = alloc_trdev(0); - break; -#endif #ifdef CONFIG_FDDI case LCS_FRAME_TYPE_FDDI: card->lan_type_trans = fddi_type_trans; @@ -2323,9 +2308,9 @@ lcs_remove_device(struct ccwgroup_device *ccwgdev) } if (card->dev) unregister_netdev(card->dev); - sysfs_remove_group(&ccwgdev->dev.kobj, &lcs_attr_group); lcs_cleanup_card(card); lcs_free_card(card); + dev_set_drvdata(&ccwgdev->dev, NULL); put_device(&ccwgdev->dev); } @@ -2410,9 +2395,7 @@ static struct ccwgroup_driver lcs_group_driver = { .owner = THIS_MODULE, .name = "lcs", }, - .max_slaves = 2, - .driver_id = 0xD3C3E2, - .probe = lcs_probe_device, + .setup = lcs_probe_device, .remove = lcs_remove_device, .set_online = lcs_new_device, .set_offline = lcs_shutdown_device, @@ -2423,30 +2406,24 @@ static struct ccwgroup_driver lcs_group_driver = { .restore = lcs_restore, }; -static ssize_t -lcs_driver_group_store(struct device_driver *ddrv, const char *buf, - size_t count) +static ssize_t lcs_driver_group_store(struct device_driver *ddrv, + const char *buf, size_t count) { int err; - err = ccwgroup_create_from_string(lcs_root_dev, - lcs_group_driver.driver_id, - &lcs_ccw_driver, 2, buf); + err = ccwgroup_create_dev(lcs_root_dev, &lcs_group_driver, 2, buf); return err ? err : count; } - static DRIVER_ATTR(group, 0200, NULL, lcs_driver_group_store); -static struct attribute *lcs_group_attrs[] = { +static struct attribute *lcs_drv_attrs[] = { &driver_attr_group.attr, NULL, }; - -static struct attribute_group lcs_group_attr_group = { - .attrs = lcs_group_attrs, +static struct attribute_group lcs_drv_attr_group = { + .attrs = lcs_drv_attrs, }; - -static const struct attribute_group *lcs_group_attr_groups[] = { - &lcs_group_attr_group, +static const struct attribute_group *lcs_drv_attr_groups[] = { + &lcs_drv_attr_group, NULL, }; @@ -2470,7 +2447,7 @@ __init lcs_init_module(void) rc = ccw_driver_register(&lcs_ccw_driver); if (rc) goto ccw_err; - lcs_group_driver.driver.groups = lcs_group_attr_groups; + lcs_group_driver.driver.groups = lcs_drv_attr_groups; rc = ccwgroup_driver_register(&lcs_group_driver); if (rc) goto ccwgroup_err; @@ -2496,8 +2473,6 @@ __exit lcs_cleanup_module(void) { pr_info("Terminating lcs module.\n"); LCS_DBF_TEXT(0, trace, "cleanup"); - driver_remove_file(&lcs_group_driver.driver, - &driver_attr_group); ccwgroup_driver_unregister(&lcs_group_driver); ccw_driver_unregister(&lcs_ccw_driver); root_device_unregister(lcs_root_dev); diff --git a/trunk/drivers/s390/net/qeth_core.h b/trunk/drivers/s390/net/qeth_core.h index ec7921b5138e..06e8f31ff3dc 100644 --- a/trunk/drivers/s390/net/qeth_core.h +++ b/trunk/drivers/s390/net/qeth_core.h @@ -13,8 +13,6 @@ #include #include -#include -#include #include #include #include @@ -676,8 +674,6 @@ struct qeth_card_options { struct qeth_ipa_info adp; /*Adapter parameters*/ struct qeth_routing_info route6; struct qeth_ipa_info ipa6; - int broadcast_mode; - int macaddr_mode; int fake_broadcast; int add_hhlen; int layer2; @@ -711,7 +707,16 @@ struct qeth_discipline { qdio_handler_t *input_handler; qdio_handler_t *output_handler; int (*recover)(void *ptr); - struct ccwgroup_driver *ccwgdriver; + int (*setup) (struct ccwgroup_device *); + void (*remove) (struct ccwgroup_device *); + int (*set_online) (struct ccwgroup_device *); + int (*set_offline) (struct ccwgroup_device *); + void (*shutdown)(struct ccwgroup_device *); + int (*prepare) (struct ccwgroup_device *); + void (*complete) (struct ccwgroup_device *); + int (*freeze)(struct ccwgroup_device *); + int (*thaw) (struct ccwgroup_device *); + int (*restore)(struct ccwgroup_device *); }; struct qeth_vlan_vid { @@ -775,7 +780,7 @@ struct qeth_card { struct qeth_perf_stats perf_stats; int read_or_write_problem; struct qeth_osn_info osn_info; - struct qeth_discipline discipline; + struct qeth_discipline *discipline; atomic_t force_alloc_skb; struct service_level qeth_service_level; struct qdio_ssqd_desc ssqd; @@ -841,16 +846,15 @@ static inline int qeth_is_diagass_supported(struct qeth_card *card, return card->info.diagass_support & (__u32)cmd; } -extern struct ccwgroup_driver qeth_l2_ccwgroup_driver; -extern struct ccwgroup_driver qeth_l3_ccwgroup_driver; +extern struct qeth_discipline qeth_l2_discipline; +extern struct qeth_discipline qeth_l3_discipline; +extern const struct attribute_group *qeth_generic_attr_groups[]; +extern const struct attribute_group *qeth_osn_attr_groups[]; + const char *qeth_get_cardname_short(struct qeth_card *); int qeth_realloc_buffer_pool(struct qeth_card *, int); int qeth_core_load_discipline(struct qeth_card *, enum qeth_discipline_id); void qeth_core_free_discipline(struct qeth_card *); -int qeth_core_create_device_attributes(struct device *); -void qeth_core_remove_device_attributes(struct device *); -int qeth_core_create_osn_attributes(struct device *); -void qeth_core_remove_osn_attributes(struct device *); void qeth_buffer_reclaim_work(struct work_struct *); /* exports for qeth discipline device drivers */ diff --git a/trunk/drivers/s390/net/qeth_core_main.c b/trunk/drivers/s390/net/qeth_core_main.c index 8334dadc681d..e118e1e1e1c1 100644 --- a/trunk/drivers/s390/net/qeth_core_main.c +++ b/trunk/drivers/s390/net/qeth_core_main.c @@ -1329,8 +1329,6 @@ static void qeth_set_intial_options(struct qeth_card *card) { card->options.route4.type = NO_ROUTER; card->options.route6.type = NO_ROUTER; - card->options.broadcast_mode = QETH_TR_BROADCAST_ALLRINGS; - card->options.macaddr_mode = QETH_TR_MACADDR_NONCANONICAL; card->options.fake_broadcast = 0; card->options.add_hhlen = DEFAULT_ADD_HHLEN; card->options.performance_stats = 0; @@ -1365,7 +1363,7 @@ static void qeth_start_kernel_thread(struct work_struct *work) card->write.state != CH_STATE_UP) return; if (qeth_do_start_thread(card, QETH_RECOVER_THREAD)) { - ts = kthread_run(card->discipline.recover, (void *)card, + ts = kthread_run(card->discipline->recover, (void *)card, "qeth_recover"); if (IS_ERR(ts)) { qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD); @@ -3339,7 +3337,7 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, if (rc) { queue->card->stats.tx_errors += count; /* ignore temporary SIGA errors without busy condition */ - if (rc == QDIO_ERROR_SIGA_TARGET) + if (rc == -ENOBUFS) return; QETH_CARD_TEXT(queue->card, 2, "flushbuf"); QETH_CARD_TEXT_(queue->card, 2, " q%d", queue->queue_no); @@ -3533,7 +3531,7 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev, int i; QETH_CARD_TEXT(card, 6, "qdouhdl"); - if (qdio_error & QDIO_ERROR_ACTIVATE_CHECK_CONDITION) { + if (qdio_error & QDIO_ERROR_FATAL) { QETH_CARD_TEXT(card, 2, "achkcond"); netif_stop_queue(card->dev); qeth_schedule_recovery(card); @@ -4629,7 +4627,7 @@ static int qeth_qdio_establish(struct qeth_card *card) goto out_free_in_sbals; } for (i = 0; i < card->qdio.no_in_queues; ++i) - queue_start_poll[i] = card->discipline.start_poll; + queue_start_poll[i] = card->discipline->start_poll; qeth_qdio_establish_cq(card, in_sbal_ptrs, queue_start_poll); @@ -4653,8 +4651,8 @@ static int qeth_qdio_establish(struct qeth_card *card) init_data.qib_param_field = qib_param_field; init_data.no_input_qs = card->qdio.no_in_queues; init_data.no_output_qs = card->qdio.no_out_queues; - init_data.input_handler = card->discipline.input_handler; - init_data.output_handler = card->discipline.output_handler; + init_data.input_handler = card->discipline->input_handler; + init_data.output_handler = card->discipline->output_handler; init_data.queue_start_poll_array = queue_start_poll; init_data.int_parm = (unsigned long) card; init_data.input_sbal_addr_array = (void **) in_sbal_ptrs; @@ -4739,13 +4737,6 @@ static struct ccw_driver qeth_ccw_driver = { .remove = ccwgroup_remove_ccwdev, }; -static int qeth_core_driver_group(const char *buf, struct device *root_dev, - unsigned long driver_id) -{ - return ccwgroup_create_from_string(root_dev, driver_id, - &qeth_ccw_driver, 3, buf); -} - int qeth_core_hardsetup_card(struct qeth_card *card) { int retries = 0; @@ -4911,11 +4902,7 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card, break; case QETH_HEADER_TYPE_LAYER3: skb_len = (*hdr)->hdr.l3.length; - if ((card->info.link_type == QETH_LINK_TYPE_LANE_TR) || - (card->info.link_type == QETH_LINK_TYPE_HSTR)) - headroom = TR_HLEN; - else - headroom = ETH_HLEN; + headroom = ETH_HLEN; break; case QETH_HEADER_TYPE_OSN: skb_len = (*hdr)->hdr.osn.pdu_length; @@ -5046,17 +5033,15 @@ int qeth_core_load_discipline(struct qeth_card *card, mutex_lock(&qeth_mod_mutex); switch (discipline) { case QETH_DISCIPLINE_LAYER3: - card->discipline.ccwgdriver = try_then_request_module( - symbol_get(qeth_l3_ccwgroup_driver), - "qeth_l3"); + card->discipline = try_then_request_module( + symbol_get(qeth_l3_discipline), "qeth_l3"); break; case QETH_DISCIPLINE_LAYER2: - card->discipline.ccwgdriver = try_then_request_module( - symbol_get(qeth_l2_ccwgroup_driver), - "qeth_l2"); + card->discipline = try_then_request_module( + symbol_get(qeth_l2_discipline), "qeth_l2"); break; } - if (!card->discipline.ccwgdriver) { + if (!card->discipline) { dev_err(&card->gdev->dev, "There is no kernel module to " "support discipline %d\n", discipline); rc = -EINVAL; @@ -5068,12 +5053,21 @@ int qeth_core_load_discipline(struct qeth_card *card, void qeth_core_free_discipline(struct qeth_card *card) { if (card->options.layer2) - symbol_put(qeth_l2_ccwgroup_driver); + symbol_put(qeth_l2_discipline); else - symbol_put(qeth_l3_ccwgroup_driver); - card->discipline.ccwgdriver = NULL; + symbol_put(qeth_l3_discipline); + card->discipline = NULL; } +static const struct device_type qeth_generic_devtype = { + .name = "qeth_generic", + .groups = qeth_generic_attr_groups, +}; +static const struct device_type qeth_osn_devtype = { + .name = "qeth_osn", + .groups = qeth_osn_attr_groups, +}; + static int qeth_core_probe_device(struct ccwgroup_device *gdev) { struct qeth_card *card; @@ -5128,18 +5122,17 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) } if (card->info.type == QETH_CARD_TYPE_OSN) - rc = qeth_core_create_osn_attributes(dev); + gdev->dev.type = &qeth_osn_devtype; else - rc = qeth_core_create_device_attributes(dev); - if (rc) - goto err_dbf; + gdev->dev.type = &qeth_generic_devtype; + switch (card->info.type) { case QETH_CARD_TYPE_OSN: case QETH_CARD_TYPE_OSM: rc = qeth_core_load_discipline(card, QETH_DISCIPLINE_LAYER2); if (rc) - goto err_attr; - rc = card->discipline.ccwgdriver->probe(card->gdev); + goto err_dbf; + rc = card->discipline->setup(card->gdev); if (rc) goto err_disc; case QETH_CARD_TYPE_OSD: @@ -5157,11 +5150,6 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) err_disc: qeth_core_free_discipline(card); -err_attr: - if (card->info.type == QETH_CARD_TYPE_OSN) - qeth_core_remove_osn_attributes(dev); - else - qeth_core_remove_device_attributes(dev); err_dbf: debug_unregister(card->debug); err_card: @@ -5178,14 +5166,8 @@ static void qeth_core_remove_device(struct ccwgroup_device *gdev) QETH_DBF_TEXT(SETUP, 2, "removedv"); - if (card->info.type == QETH_CARD_TYPE_OSN) { - qeth_core_remove_osn_attributes(&gdev->dev); - } else { - qeth_core_remove_device_attributes(&gdev->dev); - } - - if (card->discipline.ccwgdriver) { - card->discipline.ccwgdriver->remove(gdev); + if (card->discipline) { + card->discipline->remove(gdev); qeth_core_free_discipline(card); } @@ -5205,7 +5187,7 @@ static int qeth_core_set_online(struct ccwgroup_device *gdev) int rc = 0; int def_discipline; - if (!card->discipline.ccwgdriver) { + if (!card->discipline) { if (card->info.type == QETH_CARD_TYPE_IQD) def_discipline = QETH_DISCIPLINE_LAYER3; else @@ -5213,11 +5195,11 @@ static int qeth_core_set_online(struct ccwgroup_device *gdev) rc = qeth_core_load_discipline(card, def_discipline); if (rc) goto err; - rc = card->discipline.ccwgdriver->probe(card->gdev); + rc = card->discipline->setup(card->gdev); if (rc) goto err; } - rc = card->discipline.ccwgdriver->set_online(gdev); + rc = card->discipline->set_online(gdev); err: return rc; } @@ -5225,58 +5207,52 @@ static int qeth_core_set_online(struct ccwgroup_device *gdev) static int qeth_core_set_offline(struct ccwgroup_device *gdev) { struct qeth_card *card = dev_get_drvdata(&gdev->dev); - return card->discipline.ccwgdriver->set_offline(gdev); + return card->discipline->set_offline(gdev); } static void qeth_core_shutdown(struct ccwgroup_device *gdev) { struct qeth_card *card = dev_get_drvdata(&gdev->dev); - if (card->discipline.ccwgdriver && - card->discipline.ccwgdriver->shutdown) - card->discipline.ccwgdriver->shutdown(gdev); + if (card->discipline && card->discipline->shutdown) + card->discipline->shutdown(gdev); } static int qeth_core_prepare(struct ccwgroup_device *gdev) { struct qeth_card *card = dev_get_drvdata(&gdev->dev); - if (card->discipline.ccwgdriver && - card->discipline.ccwgdriver->prepare) - return card->discipline.ccwgdriver->prepare(gdev); + if (card->discipline && card->discipline->prepare) + return card->discipline->prepare(gdev); return 0; } static void qeth_core_complete(struct ccwgroup_device *gdev) { struct qeth_card *card = dev_get_drvdata(&gdev->dev); - if (card->discipline.ccwgdriver && - card->discipline.ccwgdriver->complete) - card->discipline.ccwgdriver->complete(gdev); + if (card->discipline && card->discipline->complete) + card->discipline->complete(gdev); } static int qeth_core_freeze(struct ccwgroup_device *gdev) { struct qeth_card *card = dev_get_drvdata(&gdev->dev); - if (card->discipline.ccwgdriver && - card->discipline.ccwgdriver->freeze) - return card->discipline.ccwgdriver->freeze(gdev); + if (card->discipline && card->discipline->freeze) + return card->discipline->freeze(gdev); return 0; } static int qeth_core_thaw(struct ccwgroup_device *gdev) { struct qeth_card *card = dev_get_drvdata(&gdev->dev); - if (card->discipline.ccwgdriver && - card->discipline.ccwgdriver->thaw) - return card->discipline.ccwgdriver->thaw(gdev); + if (card->discipline && card->discipline->thaw) + return card->discipline->thaw(gdev); return 0; } static int qeth_core_restore(struct ccwgroup_device *gdev) { struct qeth_card *card = dev_get_drvdata(&gdev->dev); - if (card->discipline.ccwgdriver && - card->discipline.ccwgdriver->restore) - return card->discipline.ccwgdriver->restore(gdev); + if (card->discipline && card->discipline->restore) + return card->discipline->restore(gdev); return 0; } @@ -5285,8 +5261,7 @@ static struct ccwgroup_driver qeth_core_ccwgroup_driver = { .owner = THIS_MODULE, .name = "qeth", }, - .driver_id = 0xD8C5E3C8, - .probe = qeth_core_probe_device, + .setup = qeth_core_probe_device, .remove = qeth_core_remove_device, .set_online = qeth_core_set_online, .set_offline = qeth_core_set_offline, @@ -5298,21 +5273,30 @@ static struct ccwgroup_driver qeth_core_ccwgroup_driver = { .restore = qeth_core_restore, }; -static ssize_t -qeth_core_driver_group_store(struct device_driver *ddrv, const char *buf, - size_t count) +static ssize_t qeth_core_driver_group_store(struct device_driver *ddrv, + const char *buf, size_t count) { int err; - err = qeth_core_driver_group(buf, qeth_core_root_dev, - qeth_core_ccwgroup_driver.driver_id); - if (err) - return err; - else - return count; -} + err = ccwgroup_create_dev(qeth_core_root_dev, + &qeth_core_ccwgroup_driver, 3, buf); + + return err ? err : count; +} static DRIVER_ATTR(group, 0200, NULL, qeth_core_driver_group_store); +static struct attribute *qeth_drv_attrs[] = { + &driver_attr_group.attr, + NULL, +}; +static struct attribute_group qeth_drv_attr_group = { + .attrs = qeth_drv_attrs, +}; +static const struct attribute_group *qeth_drv_attr_groups[] = { + &qeth_drv_attr_group, + NULL, +}; + static struct { const char str[ETH_GSTRING_LEN]; } qeth_ethtool_stats_keys[] = { @@ -5550,49 +5534,41 @@ static int __init qeth_core_init(void) rc = qeth_register_dbf_views(); if (rc) goto out_err; - rc = ccw_driver_register(&qeth_ccw_driver); - if (rc) - goto ccw_err; - rc = ccwgroup_driver_register(&qeth_core_ccwgroup_driver); - if (rc) - goto ccwgroup_err; - rc = driver_create_file(&qeth_core_ccwgroup_driver.driver, - &driver_attr_group); - if (rc) - goto driver_err; qeth_core_root_dev = root_device_register("qeth"); rc = IS_ERR(qeth_core_root_dev) ? PTR_ERR(qeth_core_root_dev) : 0; if (rc) goto register_err; - qeth_core_header_cache = kmem_cache_create("qeth_hdr", sizeof(struct qeth_hdr) + ETH_HLEN, 64, 0, NULL); if (!qeth_core_header_cache) { rc = -ENOMEM; goto slab_err; } - qeth_qdio_outbuf_cache = kmem_cache_create("qeth_buf", sizeof(struct qeth_qdio_out_buffer), 0, 0, NULL); if (!qeth_qdio_outbuf_cache) { rc = -ENOMEM; goto cqslab_err; } + rc = ccw_driver_register(&qeth_ccw_driver); + if (rc) + goto ccw_err; + qeth_core_ccwgroup_driver.driver.groups = qeth_drv_attr_groups; + rc = ccwgroup_driver_register(&qeth_core_ccwgroup_driver); + if (rc) + goto ccwgroup_err; return 0; + +ccwgroup_err: + ccw_driver_unregister(&qeth_ccw_driver); +ccw_err: + kmem_cache_destroy(qeth_qdio_outbuf_cache); cqslab_err: kmem_cache_destroy(qeth_core_header_cache); slab_err: root_device_unregister(qeth_core_root_dev); register_err: - driver_remove_file(&qeth_core_ccwgroup_driver.driver, - &driver_attr_group); -driver_err: - ccwgroup_driver_unregister(&qeth_core_ccwgroup_driver); -ccwgroup_err: - ccw_driver_unregister(&qeth_ccw_driver); -ccw_err: - QETH_DBF_MESSAGE(2, "Initialization failed with code %d\n", rc); qeth_unregister_dbf_views(); out_err: pr_err("Initializing the qeth device driver failed\n"); @@ -5601,13 +5577,11 @@ static int __init qeth_core_init(void) static void __exit qeth_core_exit(void) { - root_device_unregister(qeth_core_root_dev); - driver_remove_file(&qeth_core_ccwgroup_driver.driver, - &driver_attr_group); ccwgroup_driver_unregister(&qeth_core_ccwgroup_driver); ccw_driver_unregister(&qeth_ccw_driver); kmem_cache_destroy(qeth_qdio_outbuf_cache); kmem_cache_destroy(qeth_core_header_cache); + root_device_unregister(qeth_core_root_dev); qeth_unregister_dbf_views(); pr_info("core functions removed\n"); } diff --git a/trunk/drivers/s390/net/qeth_core_mpc.h b/trunk/drivers/s390/net/qeth_core_mpc.h index ff41e42004ac..a11b30c38423 100644 --- a/trunk/drivers/s390/net/qeth_core_mpc.h +++ b/trunk/drivers/s390/net/qeth_core_mpc.h @@ -70,16 +70,6 @@ enum qeth_link_types { QETH_LINK_TYPE_ATM_NATIVE = 0x90, }; -enum qeth_tr_macaddr_modes { - QETH_TR_MACADDR_NONCANONICAL = 0, - QETH_TR_MACADDR_CANONICAL = 1, -}; - -enum qeth_tr_broadcast_modes { - QETH_TR_BROADCAST_ALLRINGS = 0, - QETH_TR_BROADCAST_LOCAL = 1, -}; - /* * Routing stuff */ diff --git a/trunk/drivers/s390/net/qeth_core_sys.c b/trunk/drivers/s390/net/qeth_core_sys.c index 0a8e86c1b0ea..f163af575c48 100644 --- a/trunk/drivers/s390/net/qeth_core_sys.c +++ b/trunk/drivers/s390/net/qeth_core_sys.c @@ -434,8 +434,8 @@ static ssize_t qeth_dev_layer2_store(struct device *dev, goto out; else { card->info.mac_bits = 0; - if (card->discipline.ccwgdriver) { - card->discipline.ccwgdriver->remove(card->gdev); + if (card->discipline) { + card->discipline->remove(card->gdev); qeth_core_free_discipline(card); } } @@ -444,7 +444,7 @@ static ssize_t qeth_dev_layer2_store(struct device *dev, if (rc) goto out; - rc = card->discipline.ccwgdriver->probe(card->gdev); + rc = card->discipline->setup(card->gdev); out: mutex_unlock(&card->discipline_mutex); return rc ? rc : count; @@ -693,7 +693,6 @@ static struct attribute *qeth_blkt_device_attrs[] = { &dev_attr_inter_jumbo.attr, NULL, }; - static struct attribute_group qeth_device_blkt_group = { .name = "blkt", .attrs = qeth_blkt_device_attrs, @@ -716,11 +715,16 @@ static struct attribute *qeth_device_attrs[] = { &dev_attr_hw_trap.attr, NULL, }; - static struct attribute_group qeth_device_attr_group = { .attrs = qeth_device_attrs, }; +const struct attribute_group *qeth_generic_attr_groups[] = { + &qeth_device_attr_group, + &qeth_device_blkt_group, + NULL, +}; + static struct attribute *qeth_osn_device_attrs[] = { &dev_attr_state.attr, &dev_attr_chpid.attr, @@ -730,37 +734,10 @@ static struct attribute *qeth_osn_device_attrs[] = { &dev_attr_recover.attr, NULL, }; - static struct attribute_group qeth_osn_device_attr_group = { .attrs = qeth_osn_device_attrs, }; - -int qeth_core_create_device_attributes(struct device *dev) -{ - int ret; - ret = sysfs_create_group(&dev->kobj, &qeth_device_attr_group); - if (ret) - return ret; - ret = sysfs_create_group(&dev->kobj, &qeth_device_blkt_group); - if (ret) - sysfs_remove_group(&dev->kobj, &qeth_device_attr_group); - - return 0; -} - -void qeth_core_remove_device_attributes(struct device *dev) -{ - sysfs_remove_group(&dev->kobj, &qeth_device_attr_group); - sysfs_remove_group(&dev->kobj, &qeth_device_blkt_group); -} - -int qeth_core_create_osn_attributes(struct device *dev) -{ - return sysfs_create_group(&dev->kobj, &qeth_osn_device_attr_group); -} - -void qeth_core_remove_osn_attributes(struct device *dev) -{ - sysfs_remove_group(&dev->kobj, &qeth_osn_device_attr_group); - return; -} +const struct attribute_group *qeth_osn_attr_groups[] = { + &qeth_osn_device_attr_group, + NULL, +}; diff --git a/trunk/drivers/s390/net/qeth_l2_main.c b/trunk/drivers/s390/net/qeth_l2_main.c index 0e7c29d1d7ef..426986518e96 100644 --- a/trunk/drivers/s390/net/qeth_l2_main.c +++ b/trunk/drivers/s390/net/qeth_l2_main.c @@ -882,12 +882,6 @@ static int qeth_l2_probe_device(struct ccwgroup_device *gdev) INIT_LIST_HEAD(&card->mc_list); card->options.layer2 = 1; card->info.hwtrap = 0; - card->discipline.start_poll = qeth_qdio_start_poll; - card->discipline.input_handler = (qdio_handler_t *) - qeth_qdio_input_handler; - card->discipline.output_handler = (qdio_handler_t *) - qeth_qdio_output_handler; - card->discipline.recover = qeth_l2_recover; return 0; } @@ -1227,8 +1221,12 @@ static int qeth_l2_pm_resume(struct ccwgroup_device *gdev) return rc; } -struct ccwgroup_driver qeth_l2_ccwgroup_driver = { - .probe = qeth_l2_probe_device, +struct qeth_discipline qeth_l2_discipline = { + .start_poll = qeth_qdio_start_poll, + .input_handler = (qdio_handler_t *) qeth_qdio_input_handler, + .output_handler = (qdio_handler_t *) qeth_qdio_output_handler, + .recover = qeth_l2_recover, + .setup = qeth_l2_probe_device, .remove = qeth_l2_remove_device, .set_online = qeth_l2_set_online, .set_offline = qeth_l2_set_offline, @@ -1237,7 +1235,7 @@ struct ccwgroup_driver qeth_l2_ccwgroup_driver = { .thaw = qeth_l2_pm_resume, .restore = qeth_l2_pm_resume, }; -EXPORT_SYMBOL_GPL(qeth_l2_ccwgroup_driver); +EXPORT_SYMBOL_GPL(qeth_l2_discipline); static int qeth_osn_send_control_data(struct qeth_card *card, int len, struct qeth_cmd_buffer *iob) diff --git a/trunk/drivers/s390/net/qeth_l3_main.c b/trunk/drivers/s390/net/qeth_l3_main.c index f85921607686..7be5e9775691 100644 --- a/trunk/drivers/s390/net/qeth_l3_main.c +++ b/trunk/drivers/s390/net/qeth_l3_main.c @@ -976,57 +976,6 @@ static inline u8 qeth_l3_get_qeth_hdr_flags6(int cast_type) return ct | QETH_CAST_UNICAST; } -static int qeth_l3_send_setadp_mode(struct qeth_card *card, __u32 command, - __u32 mode) -{ - int rc; - struct qeth_cmd_buffer *iob; - struct qeth_ipa_cmd *cmd; - - QETH_CARD_TEXT(card, 4, "adpmode"); - - iob = qeth_get_adapter_cmd(card, command, - sizeof(struct qeth_ipacmd_setadpparms)); - cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); - cmd->data.setadapterparms.data.mode = mode; - rc = qeth_send_ipa_cmd(card, iob, qeth_default_setadapterparms_cb, - NULL); - return rc; -} - -static int qeth_l3_setadapter_hstr(struct qeth_card *card) -{ - int rc; - - QETH_CARD_TEXT(card, 4, "adphstr"); - - if (qeth_adp_supported(card, IPA_SETADP_SET_BROADCAST_MODE)) { - rc = qeth_l3_send_setadp_mode(card, - IPA_SETADP_SET_BROADCAST_MODE, - card->options.broadcast_mode); - if (rc) - QETH_DBF_MESSAGE(2, "couldn't set broadcast mode on " - "device %s: x%x\n", - CARD_BUS_ID(card), rc); - rc = qeth_l3_send_setadp_mode(card, - IPA_SETADP_ALTER_MAC_ADDRESS, - card->options.macaddr_mode); - if (rc) - QETH_DBF_MESSAGE(2, "couldn't set macaddr mode on " - "device %s: x%x\n", CARD_BUS_ID(card), rc); - return rc; - } - if (card->options.broadcast_mode == QETH_TR_BROADCAST_LOCAL) - QETH_DBF_MESSAGE(2, "set adapter parameters not available " - "to set broadcast mode, using ALLRINGS " - "on device %s:\n", CARD_BUS_ID(card)); - if (card->options.macaddr_mode == QETH_TR_MACADDR_CANONICAL) - QETH_DBF_MESSAGE(2, "set adapter parameters not available " - "to set macaddr mode, using NONCANONICAL " - "on device %s:\n", CARD_BUS_ID(card)); - return 0; -} - static int qeth_l3_setadapter_parms(struct qeth_card *card) { int rc; @@ -1052,10 +1001,6 @@ static int qeth_l3_setadapter_parms(struct qeth_card *card) " address failed\n"); } - if ((card->info.link_type == QETH_LINK_TYPE_HSTR) || - (card->info.link_type == QETH_LINK_TYPE_LANE_TR)) - rc = qeth_l3_setadapter_hstr(card); - return rc; } @@ -1671,10 +1616,7 @@ qeth_diags_trace(struct qeth_card *card, enum qeth_diags_trace_cmds diags_cmd) static void qeth_l3_get_mac_for_ipm(__u32 ipm, char *mac, struct net_device *dev) { - if (dev->type == ARPHRD_IEEE802_TR) - ip_tr_mc_map(ipm, mac); - else - ip_eth_mc_map(ipm, mac); + ip_eth_mc_map(ipm, mac); } static void qeth_l3_add_mc(struct qeth_card *card, struct in_device *in4_dev) @@ -1922,8 +1864,6 @@ static inline int qeth_l3_rebuild_skb(struct qeth_card *card, #endif case __constant_htons(ETH_P_IP): ip_hdr = (struct iphdr *)skb->data; - (card->dev->type == ARPHRD_IEEE802_TR) ? - ip_tr_mc_map(ip_hdr->daddr, tg_addr): ip_eth_mc_map(ip_hdr->daddr, tg_addr); break; default: @@ -1959,12 +1899,7 @@ static inline int qeth_l3_rebuild_skb(struct qeth_card *card, tg_addr, "FAKELL", card->dev->addr_len); } -#ifdef CONFIG_TR - if (card->dev->type == ARPHRD_IEEE802_TR) - skb->protocol = tr_type_trans(skb, card->dev); - else -#endif - skb->protocol = eth_type_trans(skb, card->dev); + skb->protocol = eth_type_trans(skb, card->dev); if (hdr->hdr.l3.ext_flags & (QETH_HDR_EXT_VLAN_FRAME | QETH_HDR_EXT_INCLUDE_VLAN_TAG)) { @@ -2138,7 +2073,7 @@ static int qeth_l3_verify_vlan_dev(struct net_device *dev, struct net_device *netdev; rcu_read_lock(); - netdev = __vlan_find_dev_deep(dev, vid); + netdev = __vlan_find_dev_deep(card->dev, vid); rcu_read_unlock(); if (netdev == dev) { rc = QETH_VLAN_CARD; @@ -2883,13 +2818,7 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, hdr->hdr.l3.flags &= ~QETH_HDR_PASSTHRU; memcpy(hdr->hdr.l3.dest_addr, pkey, 16); } else { - /* passthrough */ - if ((skb->dev->type == ARPHRD_IEEE802_TR) && - !memcmp(skb->data + sizeof(struct qeth_hdr) + - sizeof(__u16), skb->dev->broadcast, 6)) { - hdr->hdr.l3.flags = QETH_CAST_BROADCAST | - QETH_HDR_PASSTHRU; - } else if (!memcmp(skb->data + sizeof(struct qeth_hdr), + if (!memcmp(skb->data + sizeof(struct qeth_hdr), skb->dev->broadcast, 6)) { /* broadcast? */ hdr->hdr.l3.flags = QETH_CAST_BROADCAST | @@ -3031,10 +2960,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) skb_pull(new_skb, ETH_HLEN); } else { if (ipv == 4) { - if (card->dev->type == ARPHRD_IEEE802_TR) - skb_pull(new_skb, TR_HLEN); - else - skb_pull(new_skb, ETH_HLEN); + skb_pull(new_skb, ETH_HLEN); } if (ipv != 4 && vlan_tx_tag_present(new_skb)) { @@ -3318,12 +3244,8 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) card->info.type == QETH_CARD_TYPE_OSX) { if ((card->info.link_type == QETH_LINK_TYPE_LANE_TR) || (card->info.link_type == QETH_LINK_TYPE_HSTR)) { -#ifdef CONFIG_TR - card->dev = alloc_trdev(0); -#endif - if (!card->dev) - return -ENODEV; - card->dev->netdev_ops = &qeth_l3_netdev_ops; + pr_info("qeth_l3: ignoring TR device\n"); + return -ENODEV; } else { card->dev = alloc_etherdev(0); if (!card->dev) @@ -3376,12 +3298,6 @@ static int qeth_l3_probe_device(struct ccwgroup_device *gdev) qeth_l3_create_device_attributes(&gdev->dev); card->options.layer2 = 0; card->info.hwtrap = 0; - card->discipline.start_poll = qeth_qdio_start_poll; - card->discipline.input_handler = (qdio_handler_t *) - qeth_qdio_input_handler; - card->discipline.output_handler = (qdio_handler_t *) - qeth_qdio_output_handler; - card->discipline.recover = qeth_l3_recover; return 0; } @@ -3656,8 +3572,12 @@ static int qeth_l3_pm_resume(struct ccwgroup_device *gdev) return rc; } -struct ccwgroup_driver qeth_l3_ccwgroup_driver = { - .probe = qeth_l3_probe_device, +struct qeth_discipline qeth_l3_discipline = { + .start_poll = qeth_qdio_start_poll, + .input_handler = (qdio_handler_t *) qeth_qdio_input_handler, + .output_handler = (qdio_handler_t *) qeth_qdio_output_handler, + .recover = qeth_l3_recover, + .setup = qeth_l3_probe_device, .remove = qeth_l3_remove_device, .set_online = qeth_l3_set_online, .set_offline = qeth_l3_set_offline, @@ -3666,7 +3586,7 @@ struct ccwgroup_driver qeth_l3_ccwgroup_driver = { .thaw = qeth_l3_pm_resume, .restore = qeth_l3_pm_resume, }; -EXPORT_SYMBOL_GPL(qeth_l3_ccwgroup_driver); +EXPORT_SYMBOL_GPL(qeth_l3_discipline); static int qeth_l3_ip_event(struct notifier_block *this, unsigned long event, void *ptr) @@ -3680,9 +3600,9 @@ static int qeth_l3_ip_event(struct notifier_block *this, return NOTIFY_DONE; card = qeth_l3_get_card_from_dev(dev); - QETH_CARD_TEXT(card, 3, "ipevent"); if (!card) return NOTIFY_DONE; + QETH_CARD_TEXT(card, 3, "ipevent"); addr = qeth_l3_get_addr_buffer(QETH_PROT_IPV4); if (addr != NULL) { diff --git a/trunk/drivers/s390/net/qeth_l3_sys.c b/trunk/drivers/s390/net/qeth_l3_sys.c index d979bb26522f..4cafedf950ad 100644 --- a/trunk/drivers/s390/net/qeth_l3_sys.c +++ b/trunk/drivers/s390/net/qeth_l3_sys.c @@ -175,116 +175,6 @@ static ssize_t qeth_l3_dev_fake_broadcast_store(struct device *dev, static DEVICE_ATTR(fake_broadcast, 0644, qeth_l3_dev_fake_broadcast_show, qeth_l3_dev_fake_broadcast_store); -static ssize_t qeth_l3_dev_broadcast_mode_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct qeth_card *card = dev_get_drvdata(dev); - - if (!card) - return -EINVAL; - - if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) || - (card->info.link_type == QETH_LINK_TYPE_LANE_TR))) - return sprintf(buf, "n/a\n"); - - return sprintf(buf, "%s\n", (card->options.broadcast_mode == - QETH_TR_BROADCAST_ALLRINGS)? - "all rings":"local"); -} - -static ssize_t qeth_l3_dev_broadcast_mode_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct qeth_card *card = dev_get_drvdata(dev); - char *tmp; - int rc = 0; - - if (!card) - return -EINVAL; - - mutex_lock(&card->conf_mutex); - if ((card->state != CARD_STATE_DOWN) && - (card->state != CARD_STATE_RECOVER)) { - rc = -EPERM; - goto out; - } - - if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) || - (card->info.link_type == QETH_LINK_TYPE_LANE_TR))) { - rc = -EINVAL; - goto out; - } - - tmp = strsep((char **) &buf, "\n"); - - if (!strcmp(tmp, "local")) - card->options.broadcast_mode = QETH_TR_BROADCAST_LOCAL; - else if (!strcmp(tmp, "all_rings")) - card->options.broadcast_mode = QETH_TR_BROADCAST_ALLRINGS; - else - rc = -EINVAL; -out: - mutex_unlock(&card->conf_mutex); - return rc ? rc : count; -} - -static DEVICE_ATTR(broadcast_mode, 0644, qeth_l3_dev_broadcast_mode_show, - qeth_l3_dev_broadcast_mode_store); - -static ssize_t qeth_l3_dev_canonical_macaddr_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct qeth_card *card = dev_get_drvdata(dev); - - if (!card) - return -EINVAL; - - if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) || - (card->info.link_type == QETH_LINK_TYPE_LANE_TR))) - return sprintf(buf, "n/a\n"); - - return sprintf(buf, "%i\n", (card->options.macaddr_mode == - QETH_TR_MACADDR_CANONICAL)? 1:0); -} - -static ssize_t qeth_l3_dev_canonical_macaddr_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct qeth_card *card = dev_get_drvdata(dev); - char *tmp; - int i, rc = 0; - - if (!card) - return -EINVAL; - - mutex_lock(&card->conf_mutex); - if ((card->state != CARD_STATE_DOWN) && - (card->state != CARD_STATE_RECOVER)) { - rc = -EPERM; - goto out; - } - - if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) || - (card->info.link_type == QETH_LINK_TYPE_LANE_TR))) { - rc = -EINVAL; - goto out; - } - - i = simple_strtoul(buf, &tmp, 16); - if ((i == 0) || (i == 1)) - card->options.macaddr_mode = i? - QETH_TR_MACADDR_CANONICAL : - QETH_TR_MACADDR_NONCANONICAL; - else - rc = -EINVAL; -out: - mutex_unlock(&card->conf_mutex); - return rc ? rc : count; -} - -static DEVICE_ATTR(canonical_macaddr, 0644, qeth_l3_dev_canonical_macaddr_show, - qeth_l3_dev_canonical_macaddr_store); - static ssize_t qeth_l3_dev_sniffer_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -458,8 +348,6 @@ static struct attribute *qeth_l3_device_attrs[] = { &dev_attr_route4.attr, &dev_attr_route6.attr, &dev_attr_fake_broadcast.attr, - &dev_attr_broadcast_mode.attr, - &dev_attr_canonical_macaddr.attr, &dev_attr_sniffer.attr, &dev_attr_hsuid.attr, NULL, diff --git a/trunk/drivers/scsi/Kconfig b/trunk/drivers/scsi/Kconfig index 29684c8142b0..bea04e5d3b51 100644 --- a/trunk/drivers/scsi/Kconfig +++ b/trunk/drivers/scsi/Kconfig @@ -408,6 +408,7 @@ config BLK_DEV_3W_XXXX_RAID config SCSI_HPSA tristate "HP Smart Array SCSI driver" depends on PCI && SCSI + select CHECK_SIGNATURE help This driver supports HP Smart Array Controllers (circa 2009). It is a SCSI alternative to the cciss driver, which is a block diff --git a/trunk/drivers/scsi/aacraid/src.c b/trunk/drivers/scsi/aacraid/src.c index 2bee51506a91..762820636304 100644 --- a/trunk/drivers/scsi/aacraid/src.c +++ b/trunk/drivers/scsi/aacraid/src.c @@ -424,6 +424,8 @@ static int aac_src_deliver_message(struct fib *fib) static int aac_src_ioremap(struct aac_dev *dev, u32 size) { if (!size) { + iounmap(dev->regs.src.bar1); + dev->regs.src.bar1 = NULL; iounmap(dev->regs.src.bar0); dev->base = dev->regs.src.bar0 = NULL; return 0; diff --git a/trunk/drivers/scsi/aic94xx/aic94xx_seq.c b/trunk/drivers/scsi/aic94xx/aic94xx_seq.c index 390168f62a13..5fdca93892ad 100644 --- a/trunk/drivers/scsi/aic94xx/aic94xx_seq.c +++ b/trunk/drivers/scsi/aic94xx/aic94xx_seq.c @@ -1228,8 +1228,7 @@ static int asd_seq_start_lseq(struct asd_ha_struct *asd_ha, int lseq) int asd_release_firmware(void) { - if (sequencer_fw) - release_firmware(sequencer_fw); + release_firmware(sequencer_fw); return 0; } diff --git a/trunk/drivers/scsi/atari_scsi.c b/trunk/drivers/scsi/atari_scsi.c index 04a154f87e3e..df740cbbaef4 100644 --- a/trunk/drivers/scsi/atari_scsi.c +++ b/trunk/drivers/scsi/atari_scsi.c @@ -572,7 +572,7 @@ static void falcon_get_lock(void) } -int __init atari_scsi_detect(struct scsi_host_template *host) +static int __init atari_scsi_detect(struct scsi_host_template *host) { static int called = 0; struct Scsi_Host *instance; @@ -724,7 +724,7 @@ int __init atari_scsi_detect(struct scsi_host_template *host) return 1; } -int atari_scsi_release(struct Scsi_Host *sh) +static int atari_scsi_release(struct Scsi_Host *sh) { if (IS_A_TT()) free_irq(IRQ_TT_MFP_SCSI, sh); @@ -734,17 +734,21 @@ int atari_scsi_release(struct Scsi_Host *sh) return 1; } -void __init atari_scsi_setup(char *str, int *ints) +#ifndef MODULE +static int __init atari_scsi_setup(char *str) { /* Format of atascsi parameter is: * atascsi=,,,, * Defaults depend on TT or Falcon, hostid determined at run time. * Negative values mean don't change. */ + int ints[6]; + + get_options(str, ARRAY_SIZE(ints), ints); if (ints[0] < 1) { printk("atari_scsi_setup: no arguments!\n"); - return; + return 0; } if (ints[0] >= 1) { @@ -777,9 +781,14 @@ void __init atari_scsi_setup(char *str, int *ints) setup_use_tagged_queuing = !!ints[5]; } #endif + + return 1; } -int atari_scsi_bus_reset(Scsi_Cmnd *cmd) +__setup("atascsi=", atari_scsi_setup); +#endif /* !MODULE */ + +static int atari_scsi_bus_reset(Scsi_Cmnd *cmd) { int rv; struct NCR5380_hostdata *hostdata = @@ -852,7 +861,7 @@ static void __init atari_scsi_reset_boot(void) #endif -const char *atari_scsi_info(struct Scsi_Host *host) +static const char *atari_scsi_info(struct Scsi_Host *host) { /* atari_scsi_detect() is verbose enough... */ static const char string[] = "Atari native SCSI"; @@ -862,8 +871,9 @@ const char *atari_scsi_info(struct Scsi_Host *host) #if defined(REAL_DMA) -unsigned long atari_scsi_dma_setup(struct Scsi_Host *instance, void *data, - unsigned long count, int dir) +static unsigned long atari_scsi_dma_setup(struct Scsi_Host *instance, + void *data, unsigned long count, + int dir) { unsigned long addr = virt_to_phys(data); diff --git a/trunk/drivers/scsi/atari_scsi.h b/trunk/drivers/scsi/atari_scsi.h index efadb8d567c2..bd52df78b209 100644 --- a/trunk/drivers/scsi/atari_scsi.h +++ b/trunk/drivers/scsi/atari_scsi.h @@ -18,11 +18,6 @@ /* (I_HAVE_OVERRUNS stuff removed) */ #ifndef ASM -int atari_scsi_detect (struct scsi_host_template *); -const char *atari_scsi_info (struct Scsi_Host *); -int atari_scsi_reset (Scsi_Cmnd *, unsigned int); -int atari_scsi_release (struct Scsi_Host *); - /* The values for CMD_PER_LUN and CAN_QUEUE are somehow arbitrary. Higher * values should work, too; try it! (but cmd_per_lun costs memory!) */ diff --git a/trunk/drivers/scsi/be2iscsi/be.h b/trunk/drivers/scsi/be2iscsi/be.h index 1d7b976c850f..a50b6a9030e8 100644 --- a/trunk/drivers/scsi/be2iscsi/be.h +++ b/trunk/drivers/scsi/be2iscsi/be.h @@ -132,10 +132,6 @@ struct be_ctrl_info { ((u32)((((size_t)(_address) & (PAGE_SIZE_4K - 1)) + \ (size) + (PAGE_SIZE_4K - 1)) >> PAGE_SHIFT_4K)) -/* Byte offset into the page corresponding to given address */ -#define OFFSET_IN_PAGE(addr) \ - ((size_t)(addr) & (PAGE_SIZE_4K-1)) - /* Returns bit offset within a DWORD of a bitfield */ #define AMAP_BIT_OFFSET(_struct, field) \ (((size_t)&(((_struct *)0)->field))%32) diff --git a/trunk/drivers/scsi/be2iscsi/be_cmds.c b/trunk/drivers/scsi/be2iscsi/be_cmds.c index cdb15364bc69..d2e9e933f7a3 100644 --- a/trunk/drivers/scsi/be2iscsi/be_cmds.c +++ b/trunk/drivers/scsi/be2iscsi/be_cmds.c @@ -15,6 +15,8 @@ * Costa Mesa, CA 92626 */ +#include + #include "be.h" #include "be_mgmt.h" #include "be_main.h" diff --git a/trunk/drivers/scsi/be2iscsi/be_cmds.h b/trunk/drivers/scsi/be2iscsi/be_cmds.h index 8b40a5b4366c..b0b36c6a145f 100644 --- a/trunk/drivers/scsi/be2iscsi/be_cmds.h +++ b/trunk/drivers/scsi/be2iscsi/be_cmds.h @@ -23,7 +23,7 @@ * firmware in the BE. These requests are communicated to the processor * using Work Request Blocks (WRBs) submitted to the MCC-WRB ring or via one * WRB inside a MAILBOX. - * The commands are serviced by the ARM processor in the BladeEngine's MPU. + * The commands are serviced by the ARM processor in the OneConnect's MPU. */ struct be_sge { u32 pa_lo; @@ -163,7 +163,8 @@ struct be_mcc_mailbox { #define OPCODE_COMMON_ISCSI_CFG_REMOVE_SGL_PAGES 3 #define OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG 7 #define OPCODE_COMMON_ISCSI_NTWK_SET_VLAN 14 -#define OPCODE_COMMON_ISCSI_NTWK_CONFIGURE_STATELESS_IP_ADDR 17 +#define OPCODE_COMMON_ISCSI_NTWK_CONFIG_STATELESS_IP_ADDR 17 +#define OPCODE_COMMON_ISCSI_NTWK_REL_STATELESS_IP_ADDR 18 #define OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR 21 #define OPCODE_COMMON_ISCSI_NTWK_GET_DEFAULT_GATEWAY 22 #define OPCODE_COMMON_ISCSI_NTWK_MODIFY_DEFAULT_GATEWAY 23 @@ -274,15 +275,15 @@ struct mgmt_conn_login_options { struct mgmt_auth_method_format auth_data; } __packed; -struct ip_address_format { +struct ip_addr_format { u16 size_of_structure; u8 reserved; u8 ip_type; - u8 ip_address[16]; + u8 addr[16]; u32 rsvd0; } __packed; -struct mgmt_conn_info { +struct mgmt_conn_info { u32 connection_handle; u32 connection_status; u16 src_port; @@ -290,9 +291,9 @@ struct mgmt_conn_info { u16 dest_port_redirected; u16 cid; u32 estimated_throughput; - struct ip_address_format src_ipaddr; - struct ip_address_format dest_ipaddr; - struct ip_address_format dest_ipaddr_redirected; + struct ip_addr_format src_ipaddr; + struct ip_addr_format dest_ipaddr; + struct ip_addr_format dest_ipaddr_redirected; struct mgmt_conn_login_options negotiated_login_options; } __packed; @@ -322,43 +323,115 @@ struct mgmt_session_info { struct mgmt_conn_info conn_list[1]; } __packed; -struct be_cmd_req_get_session { +struct be_cmd_get_session_req { struct be_cmd_req_hdr hdr; u32 session_handle; } __packed; -struct be_cmd_resp_get_session { +struct be_cmd_get_session_resp { struct be_cmd_resp_hdr hdr; struct mgmt_session_info session_info; } __packed; struct mac_addr { - u16 size_of_struct; + u16 size_of_structure; u8 addr[ETH_ALEN]; } __packed; -struct be_cmd_req_get_boot_target { +struct be_cmd_get_boot_target_req { struct be_cmd_req_hdr hdr; } __packed; -struct be_cmd_resp_get_boot_target { +struct be_cmd_get_boot_target_resp { struct be_cmd_resp_hdr hdr; u32 boot_session_count; int boot_session_handle; }; -struct be_cmd_req_mac_query { +struct be_cmd_mac_query_req { struct be_cmd_req_hdr hdr; u8 type; u8 permanent; u16 if_id; } __packed; -struct be_cmd_resp_mac_query { +struct be_cmd_get_mac_resp { struct be_cmd_resp_hdr hdr; struct mac_addr mac; }; +struct be_ip_addr_subnet_format { + u16 size_of_structure; + u8 ip_type; + u8 ipv6_prefix_length; + u8 addr[16]; + u8 subnet_mask[16]; + u32 rsvd0; +} __packed; + +struct be_cmd_get_if_info_req { + struct be_cmd_req_hdr hdr; + u32 interface_hndl; + u32 ip_type; +} __packed; + +struct be_cmd_get_if_info_resp { + struct be_cmd_req_hdr hdr; + u32 interface_hndl; + u32 vlan_priority; + u32 ip_addr_count; + u32 dhcp_state; + struct be_ip_addr_subnet_format ip_addr; +} __packed; + +struct be_ip_addr_record { + u32 action; + u32 interface_hndl; + struct be_ip_addr_subnet_format ip_addr; + u32 status; +} __packed; + +struct be_ip_addr_record_params { + u32 record_entry_count; + struct be_ip_addr_record ip_record; +} __packed; + +struct be_cmd_set_ip_addr_req { + struct be_cmd_req_hdr hdr; + struct be_ip_addr_record_params ip_params; +} __packed; + + +struct be_cmd_set_dhcp_req { + struct be_cmd_req_hdr hdr; + u32 interface_hndl; + u32 ip_type; + u32 flags; + u32 retry_count; +} __packed; + +struct be_cmd_rel_dhcp_req { + struct be_cmd_req_hdr hdr; + u32 interface_hndl; + u32 ip_type; +} __packed; + +struct be_cmd_set_def_gateway_req { + struct be_cmd_req_hdr hdr; + u32 action; + struct ip_addr_format ip_addr; +} __packed; + +struct be_cmd_get_def_gateway_req { + struct be_cmd_req_hdr hdr; + u32 ip_type; +} __packed; + +struct be_cmd_get_def_gateway_resp { + struct be_cmd_req_hdr hdr; + struct ip_addr_format ip_addr; +} __packed; + /******************** Create CQ ***************************/ /** * Pseudo amap definition in which each bit of the actual structure is defined @@ -489,7 +562,7 @@ struct be_cmd_req_modify_eq_delay { #define ETH_ALEN 6 -struct be_cmd_req_get_mac_addr { +struct be_cmd_get_nic_conf_req { struct be_cmd_req_hdr hdr; u32 nic_port_count; u32 speed; @@ -501,7 +574,7 @@ struct be_cmd_req_get_mac_addr { u32 rsvd[23]; }; -struct be_cmd_resp_get_mac_addr { +struct be_cmd_get_nic_conf_resp { struct be_cmd_resp_hdr hdr; u32 nic_port_count; u32 speed; @@ -513,6 +586,39 @@ struct be_cmd_resp_get_mac_addr { u32 rsvd[23]; }; +#define BEISCSI_ALIAS_LEN 32 + +struct be_cmd_hba_name { + struct be_cmd_req_hdr hdr; + u16 flags; + u16 rsvd0; + u8 initiator_name[ISCSI_NAME_LEN]; + u8 initiator_alias[BEISCSI_ALIAS_LEN]; +} __packed; + +struct be_cmd_ntwk_link_status_req { + struct be_cmd_req_hdr hdr; + u32 rsvd0; +} __packed; + +/*** Port Speed Values ***/ +#define BE2ISCSI_LINK_SPEED_ZERO 0x00 +#define BE2ISCSI_LINK_SPEED_10MBPS 0x01 +#define BE2ISCSI_LINK_SPEED_100MBPS 0x02 +#define BE2ISCSI_LINK_SPEED_1GBPS 0x03 +#define BE2ISCSI_LINK_SPEED_10GBPS 0x04 +struct be_cmd_ntwk_link_status_resp { + struct be_cmd_resp_hdr hdr; + u8 phys_port; + u8 mac_duplex; + u8 mac_speed; + u8 mac_fault; + u8 mgmt_mac_duplex; + u8 mgmt_mac_speed; + u16 qos_link_speed; + u32 logical_link_speed; +} __packed; + int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl, struct be_queue_info *eq, int eq_delay); @@ -530,11 +636,8 @@ int beiscsi_cmd_mccq_create(struct beiscsi_hba *phba, int be_poll_mcc(struct be_ctrl_info *ctrl); int mgmt_check_supported_fw(struct be_ctrl_info *ctrl, struct beiscsi_hba *phba); -unsigned int be_cmd_get_mac_addr(struct beiscsi_hba *phba); -unsigned int beiscsi_get_boot_target(struct beiscsi_hba *phba); -unsigned int beiscsi_get_session_info(struct beiscsi_hba *phba, - u32 boot_session_handle, - struct be_dma_mem *nonemb_cmd); +unsigned int be_cmd_get_initname(struct beiscsi_hba *phba); +unsigned int be_cmd_get_port_speed(struct beiscsi_hba *phba); void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag); /*ISCSI Functuions */ @@ -715,7 +818,7 @@ struct be_eq_delay_params_in { struct tcp_connect_and_offload_in { struct be_cmd_req_hdr hdr; - struct ip_address_format ip_address; + struct ip_addr_format ip_address; u16 tcp_port; u16 cid; u16 cq_id; @@ -792,13 +895,14 @@ struct be_fw_cfg { u32 function_caps; } __packed; -struct be_all_if_id { +struct be_cmd_get_all_if_id_req { struct be_cmd_req_hdr hdr; u32 if_count; u32 if_hndl_list[1]; } __packed; #define ISCSI_OPCODE_SCSI_DATA_OUT 5 +#define OPCODE_COMMON_NTWK_LINK_STATUS_QUERY 5 #define OPCODE_COMMON_MODIFY_EQ_DELAY 41 #define OPCODE_COMMON_ISCSI_CLEANUP 59 #define OPCODE_COMMON_TCP_UPLOAD 56 @@ -810,6 +914,8 @@ struct be_all_if_id { #define OPCODE_ISCSI_INI_DRIVER_OFFLOAD_SESSION 41 #define OPCODE_ISCSI_INI_DRIVER_INVALIDATE_CONNECTION 42 #define OPCODE_ISCSI_INI_BOOT_GET_BOOT_TARGET 52 +#define OPCODE_COMMON_WRITE_FLASH 96 +#define OPCODE_COMMON_READ_FLASH 97 /* --- CMD_ISCSI_INVALIDATE_CONNECTION_TYPE --- */ #define CMD_ISCSI_COMMAND_INVALIDATE 1 diff --git a/trunk/drivers/scsi/be2iscsi/be_iscsi.c b/trunk/drivers/scsi/be2iscsi/be_iscsi.c index 33c8f09c7ac1..43f35034585d 100644 --- a/trunk/drivers/scsi/be2iscsi/be_iscsi.c +++ b/trunk/drivers/scsi/be2iscsi/be_iscsi.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include #include "be_iscsi.h" @@ -207,6 +209,301 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session, return beiscsi_bindconn_cid(phba, beiscsi_conn, beiscsi_ep->ep_cid); } +static int beiscsi_create_ipv4_iface(struct beiscsi_hba *phba) +{ + if (phba->ipv4_iface) + return 0; + + phba->ipv4_iface = iscsi_create_iface(phba->shost, + &beiscsi_iscsi_transport, + ISCSI_IFACE_TYPE_IPV4, + 0, 0); + if (!phba->ipv4_iface) { + shost_printk(KERN_ERR, phba->shost, "Could not " + "create default IPv4 address.\n"); + return -ENODEV; + } + + return 0; +} + +static int beiscsi_create_ipv6_iface(struct beiscsi_hba *phba) +{ + if (phba->ipv6_iface) + return 0; + + phba->ipv6_iface = iscsi_create_iface(phba->shost, + &beiscsi_iscsi_transport, + ISCSI_IFACE_TYPE_IPV6, + 0, 0); + if (!phba->ipv6_iface) { + shost_printk(KERN_ERR, phba->shost, "Could not " + "create default IPv6 address.\n"); + return -ENODEV; + } + + return 0; +} + +void beiscsi_create_def_ifaces(struct beiscsi_hba *phba) +{ + struct be_cmd_get_if_info_resp if_info; + + if (!mgmt_get_if_info(phba, BE2_IPV4, &if_info)) + beiscsi_create_ipv4_iface(phba); + + if (!mgmt_get_if_info(phba, BE2_IPV6, &if_info)) + beiscsi_create_ipv6_iface(phba); +} + +void beiscsi_destroy_def_ifaces(struct beiscsi_hba *phba) +{ + if (phba->ipv6_iface) + iscsi_destroy_iface(phba->ipv6_iface); + if (phba->ipv4_iface) + iscsi_destroy_iface(phba->ipv4_iface); +} + +static int +beiscsi_set_static_ip(struct Scsi_Host *shost, + struct iscsi_iface_param_info *iface_param, + void *data, uint32_t dt_len) +{ + struct beiscsi_hba *phba = iscsi_host_priv(shost); + struct iscsi_iface_param_info *iface_ip = NULL; + struct iscsi_iface_param_info *iface_subnet = NULL; + struct nlattr *nla; + int ret; + + + switch (iface_param->param) { + case ISCSI_NET_PARAM_IPV4_BOOTPROTO: + nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_ADDR); + if (nla) + iface_ip = nla_data(nla); + + nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_SUBNET); + if (nla) + iface_subnet = nla_data(nla); + break; + case ISCSI_NET_PARAM_IPV4_ADDR: + iface_ip = iface_param; + nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_SUBNET); + if (nla) + iface_subnet = nla_data(nla); + break; + case ISCSI_NET_PARAM_IPV4_SUBNET: + iface_subnet = iface_param; + nla = nla_find(data, dt_len, ISCSI_NET_PARAM_IPV4_ADDR); + if (nla) + iface_ip = nla_data(nla); + break; + default: + shost_printk(KERN_ERR, shost, "Unsupported param %d\n", + iface_param->param); + } + + if (!iface_ip || !iface_subnet) { + shost_printk(KERN_ERR, shost, "IP and Subnet Mask required\n"); + return -EINVAL; + } + + ret = mgmt_set_ip(phba, iface_ip, iface_subnet, + ISCSI_BOOTPROTO_STATIC); + + return ret; +} + +static int +beiscsi_set_ipv4(struct Scsi_Host *shost, + struct iscsi_iface_param_info *iface_param, + void *data, uint32_t dt_len) +{ + struct beiscsi_hba *phba = iscsi_host_priv(shost); + int ret = 0; + + /* Check the param */ + switch (iface_param->param) { + case ISCSI_NET_PARAM_IPV4_GW: + ret = mgmt_set_gateway(phba, iface_param); + break; + case ISCSI_NET_PARAM_IPV4_BOOTPROTO: + if (iface_param->value[0] == ISCSI_BOOTPROTO_DHCP) + ret = mgmt_set_ip(phba, iface_param, + NULL, ISCSI_BOOTPROTO_DHCP); + else if (iface_param->value[0] == ISCSI_BOOTPROTO_STATIC) + ret = beiscsi_set_static_ip(shost, iface_param, + data, dt_len); + else + shost_printk(KERN_ERR, shost, "Invalid BOOTPROTO: %d\n", + iface_param->value[0]); + break; + case ISCSI_NET_PARAM_IFACE_ENABLE: + if (iface_param->value[0] == ISCSI_IFACE_ENABLE) + ret = beiscsi_create_ipv4_iface(phba); + else + iscsi_destroy_iface(phba->ipv4_iface); + break; + case ISCSI_NET_PARAM_IPV4_SUBNET: + case ISCSI_NET_PARAM_IPV4_ADDR: + ret = beiscsi_set_static_ip(shost, iface_param, + data, dt_len); + break; + default: + shost_printk(KERN_ERR, shost, "Param %d not supported\n", + iface_param->param); + } + + return ret; +} + +static int +beiscsi_set_ipv6(struct Scsi_Host *shost, + struct iscsi_iface_param_info *iface_param, + void *data, uint32_t dt_len) +{ + struct beiscsi_hba *phba = iscsi_host_priv(shost); + int ret = 0; + + switch (iface_param->param) { + case ISCSI_NET_PARAM_IFACE_ENABLE: + if (iface_param->value[0] == ISCSI_IFACE_ENABLE) + ret = beiscsi_create_ipv6_iface(phba); + else { + iscsi_destroy_iface(phba->ipv6_iface); + ret = 0; + } + break; + case ISCSI_NET_PARAM_IPV6_ADDR: + ret = mgmt_set_ip(phba, iface_param, NULL, + ISCSI_BOOTPROTO_STATIC); + break; + default: + shost_printk(KERN_ERR, shost, "Param %d not supported\n", + iface_param->param); + } + + return ret; +} + +int be2iscsi_iface_set_param(struct Scsi_Host *shost, + void *data, uint32_t dt_len) +{ + struct iscsi_iface_param_info *iface_param = NULL; + struct nlattr *attrib; + uint32_t rm_len = dt_len; + int ret = 0 ; + + nla_for_each_attr(attrib, data, dt_len, rm_len) { + iface_param = nla_data(attrib); + + if (iface_param->param_type != ISCSI_NET_PARAM) + continue; + + /* + * BE2ISCSI only supports 1 interface + */ + if (iface_param->iface_num) { + shost_printk(KERN_ERR, shost, "Invalid iface_num %d." + "Only iface_num 0 is supported.\n", + iface_param->iface_num); + return -EINVAL; + } + + switch (iface_param->iface_type) { + case ISCSI_IFACE_TYPE_IPV4: + ret = beiscsi_set_ipv4(shost, iface_param, + data, dt_len); + break; + case ISCSI_IFACE_TYPE_IPV6: + ret = beiscsi_set_ipv6(shost, iface_param, + data, dt_len); + break; + default: + shost_printk(KERN_ERR, shost, + "Invalid iface type :%d passed\n", + iface_param->iface_type); + break; + } + + if (ret) + return ret; + } + + return ret; +} + +static int be2iscsi_get_if_param(struct beiscsi_hba *phba, + struct iscsi_iface *iface, int param, + char *buf) +{ + struct be_cmd_get_if_info_resp if_info; + int len, ip_type = BE2_IPV4; + + memset(&if_info, 0, sizeof(if_info)); + + if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) + ip_type = BE2_IPV6; + + len = mgmt_get_if_info(phba, ip_type, &if_info); + if (len) + return len; + + switch (param) { + case ISCSI_NET_PARAM_IPV4_ADDR: + len = sprintf(buf, "%pI4\n", &if_info.ip_addr.addr); + break; + case ISCSI_NET_PARAM_IPV6_ADDR: + len = sprintf(buf, "%pI6\n", &if_info.ip_addr.addr); + break; + case ISCSI_NET_PARAM_IPV4_BOOTPROTO: + if (!if_info.dhcp_state) + len = sprintf(buf, "static"); + else + len = sprintf(buf, "dhcp"); + break; + case ISCSI_NET_PARAM_IPV4_SUBNET: + len = sprintf(buf, "%pI4\n", &if_info.ip_addr.subnet_mask); + break; + default: + WARN_ON(1); + } + + return len; +} + +int be2iscsi_iface_get_param(struct iscsi_iface *iface, + enum iscsi_param_type param_type, + int param, char *buf) +{ + struct Scsi_Host *shost = iscsi_iface_to_shost(iface); + struct beiscsi_hba *phba = iscsi_host_priv(shost); + struct be_cmd_get_def_gateway_resp gateway; + int len = -ENOSYS; + + switch (param) { + case ISCSI_NET_PARAM_IPV4_ADDR: + case ISCSI_NET_PARAM_IPV4_SUBNET: + case ISCSI_NET_PARAM_IPV4_BOOTPROTO: + case ISCSI_NET_PARAM_IPV6_ADDR: + len = be2iscsi_get_if_param(phba, iface, param, buf); + break; + case ISCSI_NET_PARAM_IFACE_ENABLE: + len = sprintf(buf, "enabled"); + break; + case ISCSI_NET_PARAM_IPV4_GW: + memset(&gateway, 0, sizeof(gateway)); + len = mgmt_get_gateway(phba, BE2_IPV4, &gateway); + if (!len) + len = sprintf(buf, "%pI4\n", &gateway.ip_addr.addr); + break; + default: + len = -ENOSYS; + } + + return len; +} + /** * beiscsi_ep_get_param - get the iscsi parameter * @ep: pointer to iscsi ep @@ -221,7 +518,7 @@ int beiscsi_ep_get_param(struct iscsi_endpoint *ep, struct beiscsi_endpoint *beiscsi_ep = ep->dd_data; int len = 0; - SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_get_param, param= %d\n", param); + SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_get_param, param= %d\n", param); switch (param) { case ISCSI_PARAM_CONN_PORT: @@ -278,6 +575,121 @@ int beiscsi_set_param(struct iscsi_cls_conn *cls_conn, return 0; } +/** + * beiscsi_get_initname - Read Initiator Name from flash + * @buf: buffer bointer + * @phba: The device priv structure instance + * + * returns number of bytes + */ +static int beiscsi_get_initname(char *buf, struct beiscsi_hba *phba) +{ + int rc; + unsigned int tag, wrb_num; + unsigned short status, extd_status; + struct be_mcc_wrb *wrb; + struct be_cmd_hba_name *resp; + struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; + + tag = be_cmd_get_initname(phba); + if (!tag) { + SE_DEBUG(DBG_LVL_1, "Getting Initiator Name Failed\n"); + return -EBUSY; + } else + wait_event_interruptible(phba->ctrl.mcc_wait[tag], + phba->ctrl.mcc_numtag[tag]); + + wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16; + extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8; + status = phba->ctrl.mcc_numtag[tag] & 0x000000FF; + + if (status || extd_status) { + SE_DEBUG(DBG_LVL_1, "MailBox Command Failed with " + "status = %d extd_status = %d\n", + status, extd_status); + free_mcc_tag(&phba->ctrl, tag); + return -EAGAIN; + } + wrb = queue_get_wrb(mccq, wrb_num); + free_mcc_tag(&phba->ctrl, tag); + resp = embedded_payload(wrb); + rc = sprintf(buf, "%s\n", resp->initiator_name); + return rc; +} + +/** + * beiscsi_get_port_state - Get the Port State + * @shost : pointer to scsi_host structure + * + * returns number of bytes + */ +static void beiscsi_get_port_state(struct Scsi_Host *shost) +{ + struct beiscsi_hba *phba = iscsi_host_priv(shost); + struct iscsi_cls_host *ihost = shost->shost_data; + + ihost->port_state = (phba->state == BE_ADAPTER_UP) ? + ISCSI_PORT_STATE_UP : ISCSI_PORT_STATE_DOWN; +} + +/** + * beiscsi_get_port_speed - Get the Port Speed from Adapter + * @shost : pointer to scsi_host structure + * + * returns Success/Failure + */ +static int beiscsi_get_port_speed(struct Scsi_Host *shost) +{ + unsigned int tag, wrb_num; + unsigned short status, extd_status; + struct be_mcc_wrb *wrb; + struct be_cmd_ntwk_link_status_resp *resp; + struct beiscsi_hba *phba = iscsi_host_priv(shost); + struct iscsi_cls_host *ihost = shost->shost_data; + struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; + + tag = be_cmd_get_port_speed(phba); + if (!tag) { + SE_DEBUG(DBG_LVL_1, "Getting Port Speed Failed\n"); + return -EBUSY; + } else + wait_event_interruptible(phba->ctrl.mcc_wait[tag], + phba->ctrl.mcc_numtag[tag]); + + wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16; + extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8; + status = phba->ctrl.mcc_numtag[tag] & 0x000000FF; + + if (status || extd_status) { + SE_DEBUG(DBG_LVL_1, "MailBox Command Failed with " + "status = %d extd_status = %d\n", + status, extd_status); + free_mcc_tag(&phba->ctrl, tag); + return -EAGAIN; + } + wrb = queue_get_wrb(mccq, wrb_num); + free_mcc_tag(&phba->ctrl, tag); + resp = embedded_payload(wrb); + + switch (resp->mac_speed) { + case BE2ISCSI_LINK_SPEED_10MBPS: + ihost->port_speed = ISCSI_PORT_SPEED_10MBPS; + break; + case BE2ISCSI_LINK_SPEED_100MBPS: + ihost->port_speed = BE2ISCSI_LINK_SPEED_100MBPS; + break; + case BE2ISCSI_LINK_SPEED_1GBPS: + ihost->port_speed = ISCSI_PORT_SPEED_1GBPS; + break; + case BE2ISCSI_LINK_SPEED_10GBPS: + ihost->port_speed = ISCSI_PORT_SPEED_10GBPS; + break; + default: + ihost->port_speed = ISCSI_PORT_SPEED_UNKNOWN; + } + return 0; +} + /** * beiscsi_get_host_param - get the iscsi parameter * @shost: pointer to scsi_host structure @@ -301,6 +713,27 @@ int beiscsi_get_host_param(struct Scsi_Host *shost, return status; } break; + case ISCSI_HOST_PARAM_INITIATOR_NAME: + status = beiscsi_get_initname(buf, phba); + if (status < 0) { + SE_DEBUG(DBG_LVL_1, + "Retreiving Initiator Name Failed\n"); + return status; + } + break; + case ISCSI_HOST_PARAM_PORT_STATE: + beiscsi_get_port_state(shost); + status = sprintf(buf, "%s\n", iscsi_get_port_state_name(shost)); + break; + case ISCSI_HOST_PARAM_PORT_SPEED: + status = beiscsi_get_port_speed(shost); + if (status) { + SE_DEBUG(DBG_LVL_1, + "Retreiving Port Speed Failed\n"); + return status; + } + status = sprintf(buf, "%s\n", iscsi_get_port_speed_name(shost)); + break; default: return iscsi_host_get_param(shost, param, buf); } @@ -309,46 +742,21 @@ int beiscsi_get_host_param(struct Scsi_Host *shost, int beiscsi_get_macaddr(char *buf, struct beiscsi_hba *phba) { - struct be_cmd_resp_get_mac_addr *resp; - struct be_mcc_wrb *wrb; - unsigned int tag, wrb_num; - unsigned short status, extd_status; - struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; + struct be_cmd_get_nic_conf_resp resp; int rc; - if (phba->read_mac_address) - return sysfs_format_mac(buf, phba->mac_address, - ETH_ALEN); + if (strlen(phba->mac_address)) + return strlcpy(buf, phba->mac_address, PAGE_SIZE); - tag = be_cmd_get_mac_addr(phba); - if (!tag) { - SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed\n"); - return -EBUSY; - } else - wait_event_interruptible(phba->ctrl.mcc_wait[tag], - phba->ctrl.mcc_numtag[tag]); + memset(&resp, 0, sizeof(resp)); + rc = mgmt_get_nic_conf(phba, &resp); + if (rc) + return rc; - wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16; - extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8; - status = phba->ctrl.mcc_numtag[tag] & 0x000000FF; - if (status || extd_status) { - SE_DEBUG(DBG_LVL_1, "Failed to get be_cmd_get_mac_addr" - " status = %d extd_status = %d\n", - status, extd_status); - free_mcc_tag(&phba->ctrl, tag); - return -EAGAIN; - } - wrb = queue_get_wrb(mccq, wrb_num); - free_mcc_tag(&phba->ctrl, tag); - resp = embedded_payload(wrb); - memcpy(phba->mac_address, resp->mac_address, ETH_ALEN); - rc = sysfs_format_mac(buf, phba->mac_address, - ETH_ALEN); - phba->read_mac_address = 1; - return rc; + memcpy(phba->mac_address, resp.mac_address, ETH_ALEN); + return sysfs_format_mac(buf, phba->mac_address, ETH_ALEN); } - /** * beiscsi_conn_get_stats - get the iscsi stats * @cls_conn: pointer to iscsi cls conn @@ -736,11 +1144,24 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep) umode_t be2iscsi_attr_is_visible(int param_type, int param) { switch (param_type) { + case ISCSI_NET_PARAM: + switch (param) { + case ISCSI_NET_PARAM_IFACE_ENABLE: + case ISCSI_NET_PARAM_IPV4_ADDR: + case ISCSI_NET_PARAM_IPV4_SUBNET: + case ISCSI_NET_PARAM_IPV4_BOOTPROTO: + case ISCSI_NET_PARAM_IPV4_GW: + case ISCSI_NET_PARAM_IPV6_ADDR: + return S_IRUGO; + default: + return 0; + } case ISCSI_HOST_PARAM: switch (param) { case ISCSI_HOST_PARAM_HWADDRESS: - case ISCSI_HOST_PARAM_IPADDRESS: case ISCSI_HOST_PARAM_INITIATOR_NAME: + case ISCSI_HOST_PARAM_PORT_STATE: + case ISCSI_HOST_PARAM_PORT_SPEED: return S_IRUGO; default: return 0; diff --git a/trunk/drivers/scsi/be2iscsi/be_iscsi.h b/trunk/drivers/scsi/be2iscsi/be_iscsi.h index 5c45be134501..8b826fc06bcc 100644 --- a/trunk/drivers/scsi/be2iscsi/be_iscsi.h +++ b/trunk/drivers/scsi/be2iscsi/be_iscsi.h @@ -25,6 +25,21 @@ #define BE2_IPV4 0x1 #define BE2_IPV6 0x10 +#define BE2_DHCP_V4 0x05 + +#define NON_BLOCKING 0x0 +#define BLOCKING 0x1 + +void beiscsi_create_def_ifaces(struct beiscsi_hba *phba); + +void beiscsi_destroy_def_ifaces(struct beiscsi_hba *phba); + +int be2iscsi_iface_get_param(struct iscsi_iface *iface, + enum iscsi_param_type param_type, + int param, char *buf); + +int be2iscsi_iface_set_param(struct Scsi_Host *shost, + void *data, uint32_t count); umode_t be2iscsi_attr_is_visible(int param_type, int param); diff --git a/trunk/drivers/scsi/be2iscsi/be_main.c b/trunk/drivers/scsi/be2iscsi/be_main.c index 375756fa95cf..0b1d99c99fd2 100644 --- a/trunk/drivers/scsi/be2iscsi/be_main.c +++ b/trunk/drivers/scsi/be2iscsi/be_main.c @@ -28,8 +28,11 @@ #include #include #include +#include #include +#include +#include #include #include #include @@ -48,7 +51,8 @@ static unsigned int num_hba = 0; MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table); MODULE_DESCRIPTION(DRV_DESC " " BUILD_STR); -MODULE_AUTHOR("ServerEngines Corporation"); +MODULE_VERSION(BUILD_STR); +MODULE_AUTHOR("Emulex Corporation"); MODULE_LICENSE("GPL"); module_param(be_iopoll_budget, int, 0); module_param(enable_msix, int, 0); @@ -147,15 +151,15 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc) struct invalidate_command_table *inv_tbl; struct be_dma_mem nonemb_cmd; unsigned int cid, tag, i, num_invalidate; - int rc = FAILED; /* invalidate iocbs */ cls_session = starget_to_session(scsi_target(sc->device)); session = cls_session->dd_data; spin_lock_bh(&session->lock); - if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN) - goto unlock; - + if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN) { + spin_unlock_bh(&session->lock); + return FAILED; + } conn = session->leadconn; beiscsi_conn = conn->dd_data; phba = beiscsi_conn->phba; @@ -208,9 +212,6 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc) pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, nonemb_cmd.va, nonemb_cmd.dma); return iscsi_eh_device_reset(sc); -unlock: - spin_unlock_bh(&session->lock); - return rc; } static ssize_t beiscsi_show_boot_tgt_info(void *data, int type, char *buf) @@ -230,10 +231,10 @@ static ssize_t beiscsi_show_boot_tgt_info(void *data, int type, char *buf) case ISCSI_BOOT_TGT_IP_ADDR: if (boot_conn->dest_ipaddr.ip_type == 0x1) rc = sprintf(buf, "%pI4\n", - (char *)&boot_conn->dest_ipaddr.ip_address); + (char *)&boot_conn->dest_ipaddr.addr); else rc = sprintf(str, "%pI6\n", - (char *)&boot_conn->dest_ipaddr.ip_address); + (char *)&boot_conn->dest_ipaddr.addr); break; case ISCSI_BOOT_TGT_PORT: rc = sprintf(str, "%d\n", boot_conn->dest_port); @@ -311,12 +312,8 @@ static ssize_t beiscsi_show_boot_eth_info(void *data, int type, char *buf) rc = sprintf(str, "0\n"); break; case ISCSI_BOOT_ETH_MAC: - rc = beiscsi_get_macaddr(buf, phba); - if (rc < 0) { - SE_DEBUG(DBG_LVL_1, "beiscsi_get_macaddr Failed\n"); - return rc; - } - break; + rc = beiscsi_get_macaddr(str, phba); + break; default: rc = -ENOSYS; break; @@ -394,7 +391,7 @@ MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table); static struct scsi_host_template beiscsi_sht = { .module = THIS_MODULE, - .name = "ServerEngines 10Gbe open-iscsi Initiator Driver", + .name = "Emulex 10Gbe open-iscsi Initiator Driver", .proc_name = DRV_NAME, .queuecommand = iscsi_queuecommand, .change_queue_depth = iscsi_change_queue_depth, @@ -409,6 +406,8 @@ static struct scsi_host_template beiscsi_sht = { .max_sectors = BEISCSI_MAX_SECTORS, .cmd_per_lun = BEISCSI_CMD_PER_LUN, .use_clustering = ENABLE_CLUSTERING, + .vendor_id = SCSI_NL_VID_TYPE_PCI | BE_VENDOR_ID, + }; static struct scsi_transport_template *beiscsi_scsi_transport; @@ -435,6 +434,7 @@ static struct beiscsi_hba *beiscsi_hba_alloc(struct pci_dev *pcidev) phba->shost = shost; phba->pcidev = pci_dev_get(pcidev); pci_set_drvdata(pcidev, phba); + phba->interface_handle = 0xFFFFFFFF; if (iscsi_host_add(shost, &phba->pcidev->dev)) goto free_devices; @@ -544,8 +544,7 @@ static int be_ctrl_init(struct beiscsi_hba *phba, struct pci_dev *pdev) &mbox_mem_alloc->dma); if (!mbox_mem_alloc->va) { beiscsi_unmap_pci_function(phba); - status = -ENOMEM; - return status; + return -ENOMEM; } mbox_mem_align->size = sizeof(struct be_mcc_mailbox); @@ -1252,9 +1251,9 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn, task = pwrb_handle->pio_handle; io_task = task->dd_data; - spin_lock(&phba->mgmt_sgl_lock); + spin_lock_bh(&phba->mgmt_sgl_lock); free_mgmt_sgl_handle(phba, io_task->psgl_handle); - spin_unlock(&phba->mgmt_sgl_lock); + spin_unlock_bh(&phba->mgmt_sgl_lock); spin_lock_bh(&session->lock); free_wrb_handle(phba, pwrb_context, pwrb_handle); spin_unlock_bh(&session->lock); @@ -1370,8 +1369,6 @@ hwi_get_async_handle(struct beiscsi_hba *phba, struct be_bus_address phys_addr; struct list_head *pbusy_list; struct async_pdu_handle *pasync_handle = NULL; - int buffer_len = 0; - unsigned char buffer_index = -1; unsigned char is_header = 0; phys_addr.u.a32.address_lo = @@ -1392,22 +1389,11 @@ hwi_get_async_handle(struct beiscsi_hba *phba, pbusy_list = hwi_get_async_busy_list(pasync_ctx, 1, (pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, index) / 32] & PDUCQE_INDEX_MASK)); - - buffer_len = (unsigned int)(phys_addr.u.a64.address - - pasync_ctx->async_header.pa_base.u.a64.address); - - buffer_index = buffer_len / - pasync_ctx->async_header.buffer_size; - break; case UNSOL_DATA_NOTIFY: pbusy_list = hwi_get_async_busy_list(pasync_ctx, 0, (pdpdu_cqe-> dw[offsetof(struct amap_i_t_dpdu_cqe, index) / 32] & PDUCQE_INDEX_MASK)); - buffer_len = (unsigned long)(phys_addr.u.a64.address - - pasync_ctx->async_data.pa_base.u. - a64.address); - buffer_index = buffer_len / pasync_ctx->async_data.buffer_size; break; default: pbusy_list = NULL; @@ -1418,11 +1404,9 @@ hwi_get_async_handle(struct beiscsi_hba *phba, return NULL; } - WARN_ON(!(buffer_index <= pasync_ctx->async_data.num_entries)); WARN_ON(list_empty(pbusy_list)); list_for_each_entry(pasync_handle, pbusy_list, link) { - WARN_ON(pasync_handle->consumed); - if (pasync_handle->index == buffer_index) + if (pasync_handle->pa.u.a64.address == phys_addr.u.a64.address) break; } @@ -1449,15 +1433,13 @@ hwi_update_async_writables(struct hwi_async_pdu_context *pasync_ctx, unsigned int num_entries, writables = 0; unsigned int *pep_read_ptr, *pwritables; - + num_entries = pasync_ctx->num_entries; if (is_header) { pep_read_ptr = &pasync_ctx->async_header.ep_read_ptr; pwritables = &pasync_ctx->async_header.writables; - num_entries = pasync_ctx->async_header.num_entries; } else { pep_read_ptr = &pasync_ctx->async_data.ep_read_ptr; pwritables = &pasync_ctx->async_data.writables; - num_entries = pasync_ctx->async_data.num_entries; } while ((*pep_read_ptr) != cq_index) { @@ -1491,14 +1473,13 @@ hwi_update_async_writables(struct hwi_async_pdu_context *pasync_ctx, return 0; } -static unsigned int hwi_free_async_msg(struct beiscsi_hba *phba, +static void hwi_free_async_msg(struct beiscsi_hba *phba, unsigned int cri) { struct hwi_controller *phwi_ctrlr; struct hwi_async_pdu_context *pasync_ctx; struct async_pdu_handle *pasync_handle, *tmp_handle; struct list_head *plist; - unsigned int i = 0; phwi_ctrlr = phba->phwi_ctrlr; pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr); @@ -1508,23 +1489,20 @@ static unsigned int hwi_free_async_msg(struct beiscsi_hba *phba, list_for_each_entry_safe(pasync_handle, tmp_handle, plist, link) { list_del(&pasync_handle->link); - if (i == 0) { + if (pasync_handle->is_header) { list_add_tail(&pasync_handle->link, &pasync_ctx->async_header.free_list); pasync_ctx->async_header.free_entries++; - i++; } else { list_add_tail(&pasync_handle->link, &pasync_ctx->async_data.free_list); pasync_ctx->async_data.free_entries++; - i++; } } INIT_LIST_HEAD(&pasync_ctx->async_entry[cri].wait_queue.list); pasync_ctx->async_entry[cri].wait_queue.hdr_received = 0; pasync_ctx->async_entry[cri].wait_queue.bytes_received = 0; - return 0; } static struct phys_addr * @@ -1557,16 +1535,15 @@ static void hwi_post_async_buffers(struct beiscsi_hba *phba, phwi_ctrlr = phba->phwi_ctrlr; pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr); + num_entries = pasync_ctx->num_entries; if (is_header) { - num_entries = pasync_ctx->async_header.num_entries; writables = min(pasync_ctx->async_header.writables, pasync_ctx->async_header.free_entries); pfree_link = pasync_ctx->async_header.free_list.next; host_write_num = pasync_ctx->async_header.host_write_ptr; ring_id = phwi_ctrlr->default_pdu_hdr.id; } else { - num_entries = pasync_ctx->async_data.num_entries; writables = min(pasync_ctx->async_data.writables, pasync_ctx->async_data.free_entries); pfree_link = pasync_ctx->async_data.free_list.next; @@ -1673,7 +1650,7 @@ hwi_fwd_async_msg(struct beiscsi_conn *beiscsi_conn, } memcpy(pfirst_buffer + offset, pasync_handle->pbuffer, buf_len); - offset = buf_len; + offset += buf_len; } index++; } @@ -1682,10 +1659,9 @@ hwi_fwd_async_msg(struct beiscsi_conn *beiscsi_conn, (beiscsi_conn->beiscsi_conn_cid - phba->fw_config.iscsi_cid_start), phdr, hdr_len, pfirst_buffer, - buf_len); + offset); - if (status == 0) - hwi_free_async_msg(phba, cri); + hwi_free_async_msg(phba, cri); return 0; } @@ -2229,7 +2205,7 @@ static int beiscsi_alloc_mem(struct beiscsi_hba *phba) struct mem_array *mem_arr, *mem_arr_orig; unsigned int i, j, alloc_size, curr_alloc_size; - phba->phwi_ctrlr = kmalloc(phba->params.hwi_ws_sz, GFP_KERNEL); + phba->phwi_ctrlr = kzalloc(phba->params.hwi_ws_sz, GFP_KERNEL); if (!phba->phwi_ctrlr) return -ENOMEM; @@ -2349,27 +2325,21 @@ static void iscsi_init_global_templates(struct beiscsi_hba *phba) AMAP_SET_BITS(struct amap_pdu_nop_out, i_bit, pnop_out, 0); } -static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba) +static int beiscsi_init_wrb_handle(struct beiscsi_hba *phba) { struct be_mem_descriptor *mem_descr_wrbh, *mem_descr_wrb; - struct wrb_handle *pwrb_handle; + struct wrb_handle *pwrb_handle = NULL; struct hwi_controller *phwi_ctrlr; struct hwi_wrb_context *pwrb_context; - struct iscsi_wrb *pwrb; - unsigned int num_cxn_wrbh; - unsigned int num_cxn_wrb, j, idx, index; + struct iscsi_wrb *pwrb = NULL; + unsigned int num_cxn_wrbh = 0; + unsigned int num_cxn_wrb = 0, j, idx = 0, index; mem_descr_wrbh = phba->init_mem; mem_descr_wrbh += HWI_MEM_WRBH; mem_descr_wrb = phba->init_mem; mem_descr_wrb += HWI_MEM_WRB; - - idx = 0; - pwrb_handle = mem_descr_wrbh->mem_array[idx].virtual_address; - num_cxn_wrbh = ((mem_descr_wrbh->mem_array[idx].size) / - ((sizeof(struct wrb_handle)) * - phba->params.wrbs_per_cxn)); phwi_ctrlr = phba->phwi_ctrlr; for (index = 0; index < phba->params.cxns_per_ctrl * 2; index += 2) { @@ -2377,12 +2347,32 @@ static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba) pwrb_context->pwrb_handle_base = kzalloc(sizeof(struct wrb_handle *) * phba->params.wrbs_per_cxn, GFP_KERNEL); + if (!pwrb_context->pwrb_handle_base) { + shost_printk(KERN_ERR, phba->shost, + "Mem Alloc Failed. Failing to load\n"); + goto init_wrb_hndl_failed; + } pwrb_context->pwrb_handle_basestd = kzalloc(sizeof(struct wrb_handle *) * phba->params.wrbs_per_cxn, GFP_KERNEL); + if (!pwrb_context->pwrb_handle_basestd) { + shost_printk(KERN_ERR, phba->shost, + "Mem Alloc Failed. Failing to load\n"); + goto init_wrb_hndl_failed; + } + if (!num_cxn_wrbh) { + pwrb_handle = + mem_descr_wrbh->mem_array[idx].virtual_address; + num_cxn_wrbh = ((mem_descr_wrbh->mem_array[idx].size) / + ((sizeof(struct wrb_handle)) * + phba->params.wrbs_per_cxn)); + idx++; + } + pwrb_context->alloc_index = 0; + pwrb_context->wrb_handles_available = 0; + pwrb_context->free_index = 0; + if (num_cxn_wrbh) { - pwrb_context->alloc_index = 0; - pwrb_context->wrb_handles_available = 0; for (j = 0; j < phba->params.wrbs_per_cxn; j++) { pwrb_context->pwrb_handle_base[j] = pwrb_handle; pwrb_context->pwrb_handle_basestd[j] = @@ -2391,49 +2381,21 @@ static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba) pwrb_handle->wrb_index = j; pwrb_handle++; } - pwrb_context->free_index = 0; - num_cxn_wrbh--; - } else { - idx++; - pwrb_handle = - mem_descr_wrbh->mem_array[idx].virtual_address; - num_cxn_wrbh = - ((mem_descr_wrbh->mem_array[idx].size) / - ((sizeof(struct wrb_handle)) * - phba->params.wrbs_per_cxn)); - pwrb_context->alloc_index = 0; - for (j = 0; j < phba->params.wrbs_per_cxn; j++) { - pwrb_context->pwrb_handle_base[j] = pwrb_handle; - pwrb_context->pwrb_handle_basestd[j] = - pwrb_handle; - pwrb_context->wrb_handles_available++; - pwrb_handle->wrb_index = j; - pwrb_handle++; - } - pwrb_context->free_index = 0; num_cxn_wrbh--; } } idx = 0; - pwrb = mem_descr_wrb->mem_array[idx].virtual_address; - num_cxn_wrb = (mem_descr_wrb->mem_array[idx].size) / - ((sizeof(struct iscsi_wrb) * - phba->params.wrbs_per_cxn)); for (index = 0; index < phba->params.cxns_per_ctrl * 2; index += 2) { pwrb_context = &phwi_ctrlr->wrb_context[index]; - if (num_cxn_wrb) { - for (j = 0; j < phba->params.wrbs_per_cxn; j++) { - pwrb_handle = pwrb_context->pwrb_handle_base[j]; - pwrb_handle->pwrb = pwrb; - pwrb++; - } - num_cxn_wrb--; - } else { - idx++; + if (!num_cxn_wrb) { pwrb = mem_descr_wrb->mem_array[idx].virtual_address; num_cxn_wrb = (mem_descr_wrb->mem_array[idx].size) / - ((sizeof(struct iscsi_wrb) * - phba->params.wrbs_per_cxn)); + ((sizeof(struct iscsi_wrb) * + phba->params.wrbs_per_cxn)); + idx++; + } + + if (num_cxn_wrb) { for (j = 0; j < phba->params.wrbs_per_cxn; j++) { pwrb_handle = pwrb_context->pwrb_handle_base[j]; pwrb_handle->pwrb = pwrb; @@ -2442,6 +2404,14 @@ static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba) num_cxn_wrb--; } } + return 0; +init_wrb_hndl_failed: + for (j = index; j > 0; j--) { + pwrb_context = &phwi_ctrlr->wrb_context[j]; + kfree(pwrb_context->pwrb_handle_base); + kfree(pwrb_context->pwrb_handle_basestd); + } + return -ENOMEM; } static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) @@ -2450,7 +2420,7 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) struct hba_parameters *p = &phba->params; struct hwi_async_pdu_context *pasync_ctx; struct async_pdu_handle *pasync_header_h, *pasync_data_h; - unsigned int index; + unsigned int index, idx, num_per_mem, num_async_data; struct be_mem_descriptor *mem_descr; mem_descr = (struct be_mem_descriptor *)phba->init_mem; @@ -2462,10 +2432,8 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) pasync_ctx = phwi_ctrlr->phwi_ctxt->pasync_ctx; memset(pasync_ctx, 0, sizeof(*pasync_ctx)); - pasync_ctx->async_header.num_entries = p->asyncpdus_per_ctrl; - pasync_ctx->async_header.buffer_size = p->defpdu_hdr_sz; - pasync_ctx->async_data.buffer_size = p->defpdu_data_sz; - pasync_ctx->async_data.num_entries = p->asyncpdus_per_ctrl; + pasync_ctx->num_entries = p->asyncpdus_per_ctrl; + pasync_ctx->buffer_size = p->defpdu_hdr_sz; mem_descr = (struct be_mem_descriptor *)phba->init_mem; mem_descr += HWI_MEM_ASYNC_HEADER_BUF; @@ -2510,19 +2478,6 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) pasync_ctx->async_header.writables = 0; INIT_LIST_HEAD(&pasync_ctx->async_header.free_list); - mem_descr = (struct be_mem_descriptor *)phba->init_mem; - mem_descr += HWI_MEM_ASYNC_DATA_BUF; - if (mem_descr->mem_array[0].virtual_address) { - SE_DEBUG(DBG_LVL_8, - "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_DATA_BUF" - "va=%p\n", mem_descr->mem_array[0].virtual_address); - } else - shost_printk(KERN_WARNING, phba->shost, - "No Virtual address\n"); - pasync_ctx->async_data.va_base = - mem_descr->mem_array[0].virtual_address; - pasync_ctx->async_data.pa_base.u.a64.address = - mem_descr->mem_array[0].bus_address.u.a64.address; mem_descr = (struct be_mem_descriptor *)phba->init_mem; mem_descr += HWI_MEM_ASYNC_DATA_RING; @@ -2553,6 +2508,25 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) pasync_data_h = (struct async_pdu_handle *)pasync_ctx->async_data.handle_base; + mem_descr = (struct be_mem_descriptor *)phba->init_mem; + mem_descr += HWI_MEM_ASYNC_DATA_BUF; + if (mem_descr->mem_array[0].virtual_address) { + SE_DEBUG(DBG_LVL_8, + "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_DATA_BUF" + "va=%p\n", mem_descr->mem_array[0].virtual_address); + } else + shost_printk(KERN_WARNING, phba->shost, + "No Virtual address\n"); + idx = 0; + pasync_ctx->async_data.va_base = + mem_descr->mem_array[idx].virtual_address; + pasync_ctx->async_data.pa_base.u.a64.address = + mem_descr->mem_array[idx].bus_address.u.a64.address; + + num_async_data = ((mem_descr->mem_array[idx].size) / + phba->params.defpdu_data_sz); + num_per_mem = 0; + for (index = 0; index < p->asyncpdus_per_ctrl; index++) { pasync_header_h->cri = -1; pasync_header_h->index = (char)index; @@ -2578,14 +2552,29 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) pasync_data_h->cri = -1; pasync_data_h->index = (char)index; INIT_LIST_HEAD(&pasync_data_h->link); + + if (!num_async_data) { + num_per_mem = 0; + idx++; + pasync_ctx->async_data.va_base = + mem_descr->mem_array[idx].virtual_address; + pasync_ctx->async_data.pa_base.u.a64.address = + mem_descr->mem_array[idx]. + bus_address.u.a64.address; + + num_async_data = ((mem_descr->mem_array[idx].size) / + phba->params.defpdu_data_sz); + } pasync_data_h->pbuffer = (void *)((unsigned long) (pasync_ctx->async_data.va_base) + - (p->defpdu_data_sz * index)); + (p->defpdu_data_sz * num_per_mem)); pasync_data_h->pa.u.a64.address = pasync_ctx->async_data.pa_base.u.a64.address + - (p->defpdu_data_sz * index); + (p->defpdu_data_sz * num_per_mem); + num_per_mem++; + num_async_data--; list_add_tail(&pasync_data_h->link, &pasync_ctx->async_data.free_list); @@ -2913,9 +2902,11 @@ beiscsi_post_pages(struct beiscsi_hba *phba) static void be_queue_free(struct beiscsi_hba *phba, struct be_queue_info *q) { struct be_dma_mem *mem = &q->dma_mem; - if (mem->va) + if (mem->va) { pci_free_consistent(phba->pcidev, mem->size, mem->va, mem->dma); + mem->va = NULL; + } } static int be_queue_alloc(struct beiscsi_hba *phba, struct be_queue_info *q, @@ -3215,7 +3206,7 @@ static int hwi_init_port(struct beiscsi_hba *phba) error: shost_printk(KERN_ERR, phba->shost, "hwi_init_port failed"); hwi_cleanup(phba); - return -ENOMEM; + return status; } static int hwi_init_controller(struct beiscsi_hba *phba) @@ -3236,7 +3227,9 @@ static int hwi_init_controller(struct beiscsi_hba *phba) } iscsi_init_global_templates(phba); - beiscsi_init_wrb_handle(phba); + if (beiscsi_init_wrb_handle(phba)) + return -ENOMEM; + hwi_init_async_pdu_ctx(phba); if (hwi_init_port(phba) != 0) { shost_printk(KERN_ERR, phba->shost, @@ -3288,7 +3281,7 @@ static int beiscsi_init_controller(struct beiscsi_hba *phba) free_init: beiscsi_free_mem(phba); - return -ENOMEM; + return ret; } static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba) @@ -3475,8 +3468,8 @@ static void hwi_disable_intr(struct beiscsi_hba *phba) static int beiscsi_get_boot_info(struct beiscsi_hba *phba) { - struct be_cmd_resp_get_boot_target *boot_resp; - struct be_cmd_resp_get_session *session_resp; + struct be_cmd_get_boot_target_resp *boot_resp; + struct be_cmd_get_session_resp *session_resp; struct be_mcc_wrb *wrb; struct be_dma_mem nonemb_cmd; unsigned int tag, wrb_num; @@ -3484,9 +3477,9 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba) struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; int ret = -ENOMEM; - tag = beiscsi_get_boot_target(phba); + tag = mgmt_get_boot_target(phba); if (!tag) { - SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed\n"); + SE_DEBUG(DBG_LVL_1, "beiscsi_get_boot_info Failed\n"); return -EAGAIN; } else wait_event_interruptible(phba->ctrl.mcc_wait[tag], @@ -3496,7 +3489,7 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba) extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8; status = phba->ctrl.mcc_numtag[tag] & 0x000000FF; if (status || extd_status) { - SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed" + SE_DEBUG(DBG_LVL_1, "beiscsi_get_boot_info Failed" " status = %d extd_status = %d\n", status, extd_status); free_mcc_tag(&phba->ctrl, tag); @@ -3522,8 +3515,8 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba) } memset(nonemb_cmd.va, 0, sizeof(*session_resp)); - tag = beiscsi_get_session_info(phba, - boot_resp->boot_session_handle, &nonemb_cmd); + tag = mgmt_get_session_info(phba, boot_resp->boot_session_handle, + &nonemb_cmd); if (!tag) { SE_DEBUG(DBG_LVL_1, "beiscsi_get_session_info" " Failed\n"); @@ -3696,6 +3689,57 @@ static void beiscsi_clean_port(struct beiscsi_hba *phba) kfree(phba->ep_array); } +static void beiscsi_cleanup_task(struct iscsi_task *task) +{ + struct beiscsi_io_task *io_task = task->dd_data; + struct iscsi_conn *conn = task->conn; + struct beiscsi_conn *beiscsi_conn = conn->dd_data; + struct beiscsi_hba *phba = beiscsi_conn->phba; + struct beiscsi_session *beiscsi_sess = beiscsi_conn->beiscsi_sess; + struct hwi_wrb_context *pwrb_context; + struct hwi_controller *phwi_ctrlr; + + phwi_ctrlr = phba->phwi_ctrlr; + pwrb_context = &phwi_ctrlr->wrb_context[beiscsi_conn->beiscsi_conn_cid + - phba->fw_config.iscsi_cid_start]; + + if (io_task->cmd_bhs) { + pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs, + io_task->bhs_pa.u.a64.address); + io_task->cmd_bhs = NULL; + } + + if (task->sc) { + if (io_task->pwrb_handle) { + free_wrb_handle(phba, pwrb_context, + io_task->pwrb_handle); + io_task->pwrb_handle = NULL; + } + + if (io_task->psgl_handle) { + spin_lock(&phba->io_sgl_lock); + free_io_sgl_handle(phba, io_task->psgl_handle); + spin_unlock(&phba->io_sgl_lock); + io_task->psgl_handle = NULL; + } + } else { + if (!beiscsi_conn->login_in_progress) { + if (io_task->pwrb_handle) { + free_wrb_handle(phba, pwrb_context, + io_task->pwrb_handle); + io_task->pwrb_handle = NULL; + } + if (io_task->psgl_handle) { + spin_lock(&phba->mgmt_sgl_lock); + free_mgmt_sgl_handle(phba, + io_task->psgl_handle); + spin_unlock(&phba->mgmt_sgl_lock); + io_task->psgl_handle = NULL; + } + } + } +} + void beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn, struct beiscsi_offload_params *params) @@ -3704,12 +3748,19 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn, struct iscsi_target_context_update_wrb *pwrb = NULL; struct be_mem_descriptor *mem_descr; struct beiscsi_hba *phba = beiscsi_conn->phba; + struct iscsi_task *task = beiscsi_conn->task; + struct iscsi_session *session = task->conn->session; u32 doorbell = 0; /* * We can always use 0 here because it is reserved by libiscsi for * login/startup related tasks. */ + beiscsi_conn->login_in_progress = 0; + spin_lock_bh(&session->lock); + beiscsi_cleanup_task(task); + spin_unlock_bh(&session->lock); + pwrb_handle = alloc_wrb_handle(phba, (beiscsi_conn->beiscsi_conn_cid - phba->fw_config.iscsi_cid_start)); pwrb = (struct iscsi_target_context_update_wrb *)pwrb_handle->pwrb; @@ -3823,7 +3874,7 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) task->hdr = (struct iscsi_hdr *)&io_task->cmd_bhs->iscsi_hdr; task->hdr_max = sizeof(struct be_cmd_bhs); io_task->psgl_handle = NULL; - io_task->psgl_handle = NULL; + io_task->pwrb_handle = NULL; if (task->sc) { spin_lock(&phba->io_sgl_lock); @@ -3865,6 +3916,7 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) io_task->pwrb_handle = beiscsi_conn->plogin_wrb_handle; } + beiscsi_conn->task = task; } else { spin_lock(&phba->mgmt_sgl_lock); io_task->psgl_handle = alloc_mgmt_sgl_handle(phba); @@ -3907,53 +3959,11 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) io_task->pwrb_handle = NULL; pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs, io_task->bhs_pa.u.a64.address); + io_task->cmd_bhs = NULL; SE_DEBUG(DBG_LVL_1, "Alloc of SGL_ICD Failed\n"); return -ENOMEM; } -static void beiscsi_cleanup_task(struct iscsi_task *task) -{ - struct beiscsi_io_task *io_task = task->dd_data; - struct iscsi_conn *conn = task->conn; - struct beiscsi_conn *beiscsi_conn = conn->dd_data; - struct beiscsi_hba *phba = beiscsi_conn->phba; - struct beiscsi_session *beiscsi_sess = beiscsi_conn->beiscsi_sess; - struct hwi_wrb_context *pwrb_context; - struct hwi_controller *phwi_ctrlr; - - phwi_ctrlr = phba->phwi_ctrlr; - pwrb_context = &phwi_ctrlr->wrb_context[beiscsi_conn->beiscsi_conn_cid - - phba->fw_config.iscsi_cid_start]; - if (io_task->pwrb_handle) { - free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle); - io_task->pwrb_handle = NULL; - } - - if (io_task->cmd_bhs) { - pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs, - io_task->bhs_pa.u.a64.address); - } - - if (task->sc) { - if (io_task->psgl_handle) { - spin_lock(&phba->io_sgl_lock); - free_io_sgl_handle(phba, io_task->psgl_handle); - spin_unlock(&phba->io_sgl_lock); - io_task->psgl_handle = NULL; - } - } else { - if (task->hdr && - ((task->hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN)) - return; - if (io_task->psgl_handle) { - spin_lock(&phba->mgmt_sgl_lock); - free_mgmt_sgl_handle(phba, io_task->psgl_handle); - spin_unlock(&phba->mgmt_sgl_lock); - io_task->psgl_handle = NULL; - } - } -} - static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg, unsigned int num_sg, unsigned int xferlen, unsigned int writedir) @@ -3993,7 +4003,8 @@ static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg, &io_task->cmd_bhs->iscsi_hdr.lun, sizeof(struct scsi_lun)); AMAP_SET_BITS(struct amap_iscsi_wrb, lun, pwrb, - cpu_to_be16(*(unsigned short *)&io_task->cmd_bhs->iscsi_hdr.lun)); + cpu_to_be16(*(unsigned short *) + &io_task->cmd_bhs->iscsi_hdr.lun)); AMAP_SET_BITS(struct amap_iscsi_wrb, r2t_exp_dtl, pwrb, xferlen); AMAP_SET_BITS(struct amap_iscsi_wrb, wrb_idx, pwrb, io_task->pwrb_handle->wrb_index); @@ -4126,6 +4137,76 @@ static int beiscsi_task_xmit(struct iscsi_task *task) return beiscsi_iotask(task, sg, num_sg, xferlen, writedir); } +/** + * beiscsi_bsg_request - handle bsg request from ISCSI transport + * @job: job to handle + */ +static int beiscsi_bsg_request(struct bsg_job *job) +{ + struct Scsi_Host *shost; + struct beiscsi_hba *phba; + struct iscsi_bsg_request *bsg_req = job->request; + int rc = -EINVAL; + unsigned int tag; + struct be_dma_mem nonemb_cmd; + struct be_cmd_resp_hdr *resp; + struct iscsi_bsg_reply *bsg_reply = job->reply; + unsigned short status, extd_status; + + shost = iscsi_job_to_shost(job); + phba = iscsi_host_priv(shost); + + switch (bsg_req->msgcode) { + case ISCSI_BSG_HST_VENDOR: + nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev, + job->request_payload.payload_len, + &nonemb_cmd.dma); + if (nonemb_cmd.va == NULL) { + SE_DEBUG(DBG_LVL_1, "Failed to allocate memory for " + "beiscsi_bsg_request\n"); + return -EIO; + } + tag = mgmt_vendor_specific_fw_cmd(&phba->ctrl, phba, job, + &nonemb_cmd); + if (!tag) { + SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed\n"); + pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, + nonemb_cmd.va, nonemb_cmd.dma); + return -EAGAIN; + } else + wait_event_interruptible(phba->ctrl.mcc_wait[tag], + phba->ctrl.mcc_numtag[tag]); + extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8; + status = phba->ctrl.mcc_numtag[tag] & 0x000000FF; + free_mcc_tag(&phba->ctrl, tag); + resp = (struct be_cmd_resp_hdr *)nonemb_cmd.va; + sg_copy_from_buffer(job->reply_payload.sg_list, + job->reply_payload.sg_cnt, + nonemb_cmd.va, (resp->response_length + + sizeof(*resp))); + bsg_reply->reply_payload_rcv_len = resp->response_length; + bsg_reply->result = status; + bsg_job_done(job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); + pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, + nonemb_cmd.va, nonemb_cmd.dma); + if (status || extd_status) { + SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed" + " status = %d extd_status = %d\n", + status, extd_status); + return -EIO; + } + break; + + default: + SE_DEBUG(DBG_LVL_1, "Unsupported bsg command: 0x%x\n", + bsg_req->msgcode); + break; + } + + return rc; +} + static void beiscsi_quiesce(struct beiscsi_hba *phba) { struct hwi_controller *phwi_ctrlr; @@ -4183,6 +4264,7 @@ static void beiscsi_remove(struct pci_dev *pcidev) return; } + beiscsi_destroy_def_ifaces(phba); beiscsi_quiesce(phba); iscsi_boot_destroy_kset(phba->boot_kset); iscsi_host_remove(phba->shost); @@ -4267,8 +4349,11 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, phba->num_cpus = num_cpus; SE_DEBUG(DBG_LVL_8, "num_cpus = %d\n", phba->num_cpus); - if (enable_msix) + if (enable_msix) { beiscsi_msix_enable(phba); + if (!phba->msix_enabled) + phba->num_cpus = 1; + } ret = be_ctrl_init(phba, pcidev); if (ret) { shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-" @@ -4366,8 +4451,9 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, * iscsi boot. */ shost_printk(KERN_ERR, phba->shost, "Could not set up " - "iSCSI boot info."); + "iSCSI boot info.\n"); + beiscsi_create_def_ifaces(phba); SE_DEBUG(DBG_LVL_8, "\n\n\n SUCCESS - DRIVER LOADED\n\n\n"); return 0; @@ -4418,6 +4504,8 @@ struct iscsi_transport beiscsi_iscsi_transport = { .bind_conn = beiscsi_conn_bind, .destroy_conn = iscsi_conn_teardown, .attr_is_visible = be2iscsi_attr_is_visible, + .set_iface_param = be2iscsi_iface_set_param, + .get_iface_param = be2iscsi_iface_get_param, .set_param = beiscsi_set_param, .get_conn_param = iscsi_conn_get_param, .get_session_param = iscsi_session_get_param, @@ -4435,6 +4523,7 @@ struct iscsi_transport beiscsi_iscsi_transport = { .ep_poll = beiscsi_ep_poll, .ep_disconnect = beiscsi_ep_disconnect, .session_recovery_timedout = iscsi_session_recovery_timedout, + .bsg_request = beiscsi_bsg_request, }; static struct pci_driver beiscsi_pci_driver = { diff --git a/trunk/drivers/scsi/be2iscsi/be_main.h b/trunk/drivers/scsi/be2iscsi/be_main.h index b4a06d5e5f9e..40fea6ec879c 100644 --- a/trunk/drivers/scsi/be2iscsi/be_main.h +++ b/trunk/drivers/scsi/be2iscsi/be_main.h @@ -34,9 +34,9 @@ #include "be.h" #define DRV_NAME "be2iscsi" -#define BUILD_STR "4.1.239.0" -#define BE_NAME "ServerEngines BladeEngine2" \ - "Linux iSCSI Driver version" BUILD_STR +#define BUILD_STR "4.2.162.0" +#define BE_NAME "Emulex OneConnect" \ + "Open-iSCSI Driver version" BUILD_STR #define DRV_DESC BE_NAME " " "Driver" #define BE_VENDOR_ID 0x19A2 @@ -316,6 +316,8 @@ struct beiscsi_hba { struct iscsi_endpoint **ep_array; struct iscsi_boot_kset *boot_kset; struct Scsi_Host *shost; + struct iscsi_iface *ipv4_iface; + struct iscsi_iface *ipv6_iface; struct { /** * group together since they are used most frequently @@ -345,7 +347,7 @@ struct beiscsi_hba { struct work_struct work_cqs; /* The work being queued */ struct be_ctrl_info ctrl; unsigned int generation; - unsigned int read_mac_address; + unsigned int interface_handle; struct mgmt_session_info boot_sess; struct invalidate_command_table inv_tbl[128]; @@ -525,8 +527,6 @@ struct hwi_async_pdu_context { unsigned int free_entries; unsigned int busy_entries; - unsigned int buffer_size; - unsigned int num_entries; struct list_head free_list; } async_header; @@ -543,11 +543,12 @@ struct hwi_async_pdu_context { unsigned int free_entries; unsigned int busy_entries; - unsigned int buffer_size; struct list_head free_list; - unsigned int num_entries; } async_data; + unsigned int buffer_size; + unsigned int num_entries; + /** * This is a varying size list! Do not add anything * after this entry!! diff --git a/trunk/drivers/scsi/be2iscsi/be_mgmt.c b/trunk/drivers/scsi/be2iscsi/be_mgmt.c index 44762cfa3e12..01bb04cd9e75 100644 --- a/trunk/drivers/scsi/be2iscsi/be_mgmt.c +++ b/trunk/drivers/scsi/be2iscsi/be_mgmt.c @@ -17,15 +17,17 @@ * Costa Mesa, CA 92626 */ +#include +#include +#include #include "be_mgmt.h" #include "be_iscsi.h" -#include -unsigned int beiscsi_get_boot_target(struct beiscsi_hba *phba) +unsigned int mgmt_get_boot_target(struct beiscsi_hba *phba) { struct be_ctrl_info *ctrl = &phba->ctrl; struct be_mcc_wrb *wrb; - struct be_cmd_req_get_mac_addr *req; + struct be_cmd_get_boot_target_req *req; unsigned int tag = 0; SE_DEBUG(DBG_LVL_8, "In bescsi_get_boot_target\n"); @@ -42,22 +44,22 @@ unsigned int beiscsi_get_boot_target(struct beiscsi_hba *phba) be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, OPCODE_ISCSI_INI_BOOT_GET_BOOT_TARGET, - sizeof(*req)); + sizeof(struct be_cmd_get_boot_target_resp)); be_mcc_notify(phba); spin_unlock(&ctrl->mbox_lock); return tag; } -unsigned int beiscsi_get_session_info(struct beiscsi_hba *phba, - u32 boot_session_handle, - struct be_dma_mem *nonemb_cmd) +unsigned int mgmt_get_session_info(struct beiscsi_hba *phba, + u32 boot_session_handle, + struct be_dma_mem *nonemb_cmd) { struct be_ctrl_info *ctrl = &phba->ctrl; struct be_mcc_wrb *wrb; unsigned int tag = 0; - struct be_cmd_req_get_session *req; - struct be_cmd_resp_get_session *resp; + struct be_cmd_get_session_req *req; + struct be_cmd_get_session_resp *resp; struct be_sge *sge; SE_DEBUG(DBG_LVL_8, "In beiscsi_get_session_info\n"); @@ -187,6 +189,72 @@ int mgmt_check_supported_fw(struct be_ctrl_info *ctrl, return status; } +unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl, + struct beiscsi_hba *phba, + struct bsg_job *job, + struct be_dma_mem *nonemb_cmd) +{ + struct be_cmd_resp_hdr *resp; + struct be_mcc_wrb *wrb = wrb_from_mccq(phba); + struct be_sge *mcc_sge = nonembedded_sgl(wrb); + unsigned int tag = 0; + struct iscsi_bsg_request *bsg_req = job->request; + struct be_bsg_vendor_cmd *req = nonemb_cmd->va; + unsigned short region, sector_size, sector, offset; + + nonemb_cmd->size = job->request_payload.payload_len; + memset(nonemb_cmd->va, 0, nonemb_cmd->size); + resp = nonemb_cmd->va; + region = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; + sector_size = bsg_req->rqst_data.h_vendor.vendor_cmd[2]; + sector = bsg_req->rqst_data.h_vendor.vendor_cmd[3]; + offset = bsg_req->rqst_data.h_vendor.vendor_cmd[4]; + req->region = region; + req->sector = sector; + req->offset = offset; + spin_lock(&ctrl->mbox_lock); + memset(wrb, 0, sizeof(*wrb)); + + switch (bsg_req->rqst_data.h_vendor.vendor_cmd[0]) { + case BEISCSI_WRITE_FLASH: + offset = sector * sector_size + offset; + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, + OPCODE_COMMON_WRITE_FLASH, sizeof(*req)); + sg_copy_to_buffer(job->request_payload.sg_list, + job->request_payload.sg_cnt, + nonemb_cmd->va + offset, job->request_len); + break; + case BEISCSI_READ_FLASH: + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, + OPCODE_COMMON_READ_FLASH, sizeof(*req)); + break; + default: + shost_printk(KERN_WARNING, phba->shost, + "Unsupported cmd = 0x%x\n\n", bsg_req->rqst_data. + h_vendor.vendor_cmd[0]); + spin_unlock(&ctrl->mbox_lock); + return -ENOSYS; + } + + tag = alloc_mcc_tag(phba); + if (!tag) { + spin_unlock(&ctrl->mbox_lock); + return tag; + } + + be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, + job->request_payload.sg_cnt); + mcc_sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); + mcc_sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); + mcc_sge->len = cpu_to_le32(nonemb_cmd->size); + wrb->tag0 |= tag; + + be_mcc_notify(phba); + + spin_unlock(&ctrl->mbox_lock); + return tag; +} + int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute) { struct be_ctrl_info *ctrl = &phba->ctrl; @@ -328,7 +396,6 @@ int mgmt_open_connection(struct beiscsi_hba *phba, struct sockaddr *dst_addr, struct beiscsi_endpoint *beiscsi_ep, struct be_dma_mem *nonemb_cmd) - { struct hwi_controller *phwi_ctrlr; struct hwi_context_memory *phwi_context; @@ -374,17 +441,17 @@ int mgmt_open_connection(struct beiscsi_hba *phba, if (dst_addr->sa_family == PF_INET) { __be32 s_addr = daddr_in->sin_addr.s_addr; req->ip_address.ip_type = BE2_IPV4; - req->ip_address.ip_address[0] = s_addr & 0x000000ff; - req->ip_address.ip_address[1] = (s_addr & 0x0000ff00) >> 8; - req->ip_address.ip_address[2] = (s_addr & 0x00ff0000) >> 16; - req->ip_address.ip_address[3] = (s_addr & 0xff000000) >> 24; + req->ip_address.addr[0] = s_addr & 0x000000ff; + req->ip_address.addr[1] = (s_addr & 0x0000ff00) >> 8; + req->ip_address.addr[2] = (s_addr & 0x00ff0000) >> 16; + req->ip_address.addr[3] = (s_addr & 0xff000000) >> 24; req->tcp_port = ntohs(daddr_in->sin_port); beiscsi_ep->dst_addr = daddr_in->sin_addr.s_addr; beiscsi_ep->dst_tcpport = ntohs(daddr_in->sin_port); beiscsi_ep->ip_type = BE2_IPV4; } else if (dst_addr->sa_family == PF_INET6) { req->ip_address.ip_type = BE2_IPV6; - memcpy(&req->ip_address.ip_address, + memcpy(&req->ip_address.addr, &daddr_in6->sin6_addr.in6_u.u6_addr8, 16); req->tcp_port = ntohs(daddr_in6->sin6_port); beiscsi_ep->dst_tcpport = ntohs(daddr_in6->sin6_port); @@ -419,14 +486,399 @@ int mgmt_open_connection(struct beiscsi_hba *phba, return tag; } -unsigned int be_cmd_get_mac_addr(struct beiscsi_hba *phba) +unsigned int mgmt_get_all_if_id(struct beiscsi_hba *phba) { struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb; - struct be_cmd_req_get_mac_addr *req; + struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); + struct be_cmd_get_all_if_id_req *req = embedded_payload(wrb); + struct be_cmd_get_all_if_id_req *pbe_allid = req; + int status = 0; + + memset(wrb, 0, sizeof(*wrb)); + + spin_lock(&ctrl->mbox_lock); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, + OPCODE_COMMON_ISCSI_NTWK_GET_ALL_IF_ID, + sizeof(*req)); + status = be_mbox_notify(ctrl); + if (!status) + phba->interface_handle = pbe_allid->if_hndl_list[0]; + else { + shost_printk(KERN_WARNING, phba->shost, + "Failed in mgmt_get_all_if_id\n"); + } + spin_unlock(&ctrl->mbox_lock); + + return status; +} + +static int mgmt_exec_nonemb_cmd(struct beiscsi_hba *phba, + struct be_dma_mem *nonemb_cmd, void *resp_buf, + int resp_buf_len) +{ + struct be_ctrl_info *ctrl = &phba->ctrl; + struct be_mcc_wrb *wrb = wrb_from_mccq(phba); + unsigned short status, extd_status; + struct be_sge *sge; + unsigned int tag; + int rc = 0; + + spin_lock(&ctrl->mbox_lock); + tag = alloc_mcc_tag(phba); + if (!tag) { + spin_unlock(&ctrl->mbox_lock); + rc = -ENOMEM; + goto free_cmd; + } + memset(wrb, 0, sizeof(*wrb)); + wrb->tag0 |= tag; + sge = nonembedded_sgl(wrb); + + be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, 1); + sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); + sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(nonemb_cmd->size); + + be_mcc_notify(phba); + spin_unlock(&ctrl->mbox_lock); + + wait_event_interruptible(phba->ctrl.mcc_wait[tag], + phba->ctrl.mcc_numtag[tag]); + + extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8; + status = phba->ctrl.mcc_numtag[tag] & 0x000000FF; + if (status || extd_status) { + SE_DEBUG(DBG_LVL_1, + "mgmt_exec_nonemb_cmd Failed status = %d" + "extd_status = %d\n", status, extd_status); + rc = -EIO; + goto free_tag; + } + + if (resp_buf) + memcpy(resp_buf, nonemb_cmd->va, resp_buf_len); + +free_tag: + free_mcc_tag(&phba->ctrl, tag); +free_cmd: + pci_free_consistent(ctrl->pdev, nonemb_cmd->size, + nonemb_cmd->va, nonemb_cmd->dma); + return rc; +} + +static int mgmt_alloc_cmd_data(struct beiscsi_hba *phba, struct be_dma_mem *cmd, + int iscsi_cmd, int size) +{ + cmd->va = pci_alloc_consistent(phba->ctrl.pdev, sizeof(size), + &cmd->dma); + if (!cmd->va) { + SE_DEBUG(DBG_LVL_1, "Failed to allocate memory for if info\n"); + return -ENOMEM; + } + memset(cmd->va, 0, sizeof(size)); + cmd->size = size; + be_cmd_hdr_prepare(cmd->va, CMD_SUBSYSTEM_ISCSI, iscsi_cmd, size); + return 0; +} + +static int +mgmt_static_ip_modify(struct beiscsi_hba *phba, + struct be_cmd_get_if_info_resp *if_info, + struct iscsi_iface_param_info *ip_param, + struct iscsi_iface_param_info *subnet_param, + uint32_t ip_action) +{ + struct be_cmd_set_ip_addr_req *req; + struct be_dma_mem nonemb_cmd; + uint32_t ip_type; + int rc; + + rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, + OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR, + sizeof(*req)); + if (rc) + return rc; + + ip_type = (ip_param->param == ISCSI_NET_PARAM_IPV6_ADDR) ? + BE2_IPV6 : BE2_IPV4 ; + + req = nonemb_cmd.va; + req->ip_params.record_entry_count = 1; + req->ip_params.ip_record.action = ip_action; + req->ip_params.ip_record.interface_hndl = + phba->interface_handle; + req->ip_params.ip_record.ip_addr.size_of_structure = + sizeof(struct be_ip_addr_subnet_format); + req->ip_params.ip_record.ip_addr.ip_type = ip_type; + + if (ip_action == IP_ACTION_ADD) { + memcpy(req->ip_params.ip_record.ip_addr.addr, ip_param->value, + ip_param->len); + + if (subnet_param) + memcpy(req->ip_params.ip_record.ip_addr.subnet_mask, + subnet_param->value, subnet_param->len); + } else { + memcpy(req->ip_params.ip_record.ip_addr.addr, + if_info->ip_addr.addr, ip_param->len); + + memcpy(req->ip_params.ip_record.ip_addr.subnet_mask, + if_info->ip_addr.subnet_mask, ip_param->len); + } + + rc = mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0); + if (rc < 0) + shost_printk(KERN_WARNING, phba->shost, + "Failed to Modify existing IP Address\n"); + return rc; +} + +static int mgmt_modify_gateway(struct beiscsi_hba *phba, uint8_t *gt_addr, + uint32_t gtway_action, uint32_t param_len) +{ + struct be_cmd_set_def_gateway_req *req; + struct be_dma_mem nonemb_cmd; + int rt_val; + + + rt_val = mgmt_alloc_cmd_data(phba, &nonemb_cmd, + OPCODE_COMMON_ISCSI_NTWK_MODIFY_DEFAULT_GATEWAY, + sizeof(*req)); + if (rt_val) + return rt_val; + + req = nonemb_cmd.va; + req->action = gtway_action; + req->ip_addr.ip_type = BE2_IPV4; + + memcpy(req->ip_addr.addr, gt_addr, param_len); + + return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0); +} + +int mgmt_set_ip(struct beiscsi_hba *phba, + struct iscsi_iface_param_info *ip_param, + struct iscsi_iface_param_info *subnet_param, + uint32_t boot_proto) +{ + struct be_cmd_get_def_gateway_resp gtway_addr_set; + struct be_cmd_get_if_info_resp if_info; + struct be_cmd_set_dhcp_req *dhcpreq; + struct be_cmd_rel_dhcp_req *reldhcp; + struct be_dma_mem nonemb_cmd; + uint8_t *gtway_addr; + uint32_t ip_type; + int rc; + + if (mgmt_get_all_if_id(phba)) + return -EIO; + + memset(&if_info, 0, sizeof(if_info)); + ip_type = (ip_param->param == ISCSI_NET_PARAM_IPV6_ADDR) ? + BE2_IPV6 : BE2_IPV4 ; + + rc = mgmt_get_if_info(phba, ip_type, &if_info); + if (rc) + return rc; + + if (boot_proto == ISCSI_BOOTPROTO_DHCP) { + if (if_info.dhcp_state) { + shost_printk(KERN_WARNING, phba->shost, + "DHCP Already Enabled\n"); + return 0; + } + /* The ip_param->len is 1 in DHCP case. Setting + proper IP len as this it is used while + freeing the Static IP. + */ + ip_param->len = (ip_param->param == ISCSI_NET_PARAM_IPV6_ADDR) ? + IP_V6_LEN : IP_V4_LEN; + + } else { + if (if_info.dhcp_state) { + + memset(&if_info, 0, sizeof(if_info)); + rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, + OPCODE_COMMON_ISCSI_NTWK_REL_STATELESS_IP_ADDR, + sizeof(*reldhcp)); + + if (rc) + return rc; + + reldhcp = nonemb_cmd.va; + reldhcp->interface_hndl = phba->interface_handle; + reldhcp->ip_type = ip_type; + + rc = mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0); + if (rc < 0) { + shost_printk(KERN_WARNING, phba->shost, + "Failed to Delete existing dhcp\n"); + return rc; + } + } + } + + /* Delete the Static IP Set */ + if (if_info.ip_addr.addr[0]) { + rc = mgmt_static_ip_modify(phba, &if_info, ip_param, NULL, + IP_ACTION_DEL); + if (rc) + return rc; + } + + /* Delete the Gateway settings if mode change is to DHCP */ + if (boot_proto == ISCSI_BOOTPROTO_DHCP) { + memset(>way_addr_set, 0, sizeof(gtway_addr_set)); + rc = mgmt_get_gateway(phba, BE2_IPV4, >way_addr_set); + if (rc) { + shost_printk(KERN_WARNING, phba->shost, + "Failed to Get Gateway Addr\n"); + return rc; + } + + if (gtway_addr_set.ip_addr.addr[0]) { + gtway_addr = (uint8_t *)>way_addr_set.ip_addr.addr; + rc = mgmt_modify_gateway(phba, gtway_addr, + IP_ACTION_DEL, IP_V4_LEN); + + if (rc) { + shost_printk(KERN_WARNING, phba->shost, + "Failed to clear Gateway Addr Set\n"); + return rc; + } + } + } + + /* Set Adapter to DHCP/Static Mode */ + if (boot_proto == ISCSI_BOOTPROTO_DHCP) { + rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, + OPCODE_COMMON_ISCSI_NTWK_CONFIG_STATELESS_IP_ADDR, + sizeof(*dhcpreq)); + if (rc) + return rc; + + dhcpreq = nonemb_cmd.va; + dhcpreq->flags = BLOCKING; + dhcpreq->retry_count = 1; + dhcpreq->interface_hndl = phba->interface_handle; + dhcpreq->ip_type = BE2_DHCP_V4; + + return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, NULL, 0); + } else { + return mgmt_static_ip_modify(phba, &if_info, ip_param, + subnet_param, IP_ACTION_ADD); + } + + return rc; +} + +int mgmt_set_gateway(struct beiscsi_hba *phba, + struct iscsi_iface_param_info *gateway_param) +{ + struct be_cmd_get_def_gateway_resp gtway_addr_set; + uint8_t *gtway_addr; + int rt_val; + + memset(>way_addr_set, 0, sizeof(gtway_addr_set)); + rt_val = mgmt_get_gateway(phba, BE2_IPV4, >way_addr_set); + if (rt_val) { + shost_printk(KERN_WARNING, phba->shost, + "Failed to Get Gateway Addr\n"); + return rt_val; + } + + if (gtway_addr_set.ip_addr.addr[0]) { + gtway_addr = (uint8_t *)>way_addr_set.ip_addr.addr; + rt_val = mgmt_modify_gateway(phba, gtway_addr, IP_ACTION_DEL, + gateway_param->len); + if (rt_val) { + shost_printk(KERN_WARNING, phba->shost, + "Failed to clear Gateway Addr Set\n"); + return rt_val; + } + } + + gtway_addr = (uint8_t *)&gateway_param->value; + rt_val = mgmt_modify_gateway(phba, gtway_addr, IP_ACTION_ADD, + gateway_param->len); + + if (rt_val) + shost_printk(KERN_WARNING, phba->shost, + "Failed to Set Gateway Addr\n"); + + return rt_val; +} + +int mgmt_get_gateway(struct beiscsi_hba *phba, int ip_type, + struct be_cmd_get_def_gateway_resp *gateway) +{ + struct be_cmd_get_def_gateway_req *req; + struct be_dma_mem nonemb_cmd; + int rc; + + rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, + OPCODE_COMMON_ISCSI_NTWK_GET_DEFAULT_GATEWAY, + sizeof(*gateway)); + if (rc) + return rc; + + req = nonemb_cmd.va; + req->ip_type = ip_type; + + return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, gateway, + sizeof(*gateway)); +} + +int mgmt_get_if_info(struct beiscsi_hba *phba, int ip_type, + struct be_cmd_get_if_info_resp *if_info) +{ + struct be_cmd_get_if_info_req *req; + struct be_dma_mem nonemb_cmd; + int rc; + + if (mgmt_get_all_if_id(phba)) + return -EIO; + + rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, + OPCODE_COMMON_ISCSI_NTWK_GET_IF_INFO, + sizeof(*if_info)); + if (rc) + return rc; + + req = nonemb_cmd.va; + req->interface_hndl = phba->interface_handle; + req->ip_type = ip_type; + + return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, if_info, + sizeof(*if_info)); +} + +int mgmt_get_nic_conf(struct beiscsi_hba *phba, + struct be_cmd_get_nic_conf_resp *nic) +{ + struct be_dma_mem nonemb_cmd; + int rc; + + rc = mgmt_alloc_cmd_data(phba, &nonemb_cmd, + OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG, + sizeof(*nic)); + if (rc) + return rc; + + return mgmt_exec_nonemb_cmd(phba, &nonemb_cmd, nic, sizeof(*nic)); +} + + + +unsigned int be_cmd_get_initname(struct beiscsi_hba *phba) +{ unsigned int tag = 0; + struct be_mcc_wrb *wrb; + struct be_cmd_hba_name *req; + struct be_ctrl_info *ctrl = &phba->ctrl; - SE_DEBUG(DBG_LVL_8, "In be_cmd_get_mac_addr\n"); spin_lock(&ctrl->mbox_lock); tag = alloc_mcc_tag(phba); if (!tag) { @@ -438,12 +890,38 @@ unsigned int be_cmd_get_mac_addr(struct beiscsi_hba *phba) req = embedded_payload(wrb); wrb->tag0 |= tag; be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, - OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG, - sizeof(*req)); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, + OPCODE_ISCSI_INI_CFG_GET_HBA_NAME, + sizeof(*req)); be_mcc_notify(phba); spin_unlock(&ctrl->mbox_lock); return tag; } +unsigned int be_cmd_get_port_speed(struct beiscsi_hba *phba) +{ + unsigned int tag = 0; + struct be_mcc_wrb *wrb; + struct be_cmd_ntwk_link_status_req *req; + struct be_ctrl_info *ctrl = &phba->ctrl; + + spin_lock(&ctrl->mbox_lock); + tag = alloc_mcc_tag(phba); + if (!tag) { + spin_unlock(&ctrl->mbox_lock); + return tag; + } + + wrb = wrb_from_mccq(phba); + req = embedded_payload(wrb); + wrb->tag0 |= tag; + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_NTWK_LINK_STATUS_QUERY, + sizeof(*req)); + + be_mcc_notify(phba); + spin_unlock(&ctrl->mbox_lock); + return tag; +} diff --git a/trunk/drivers/scsi/be2iscsi/be_mgmt.h b/trunk/drivers/scsi/be2iscsi/be_mgmt.h index 08428824ace2..5c2e37693ca8 100644 --- a/trunk/drivers/scsi/be2iscsi/be_mgmt.h +++ b/trunk/drivers/scsi/be2iscsi/be_mgmt.h @@ -20,11 +20,16 @@ #ifndef _BEISCSI_MGMT_ #define _BEISCSI_MGMT_ -#include -#include +#include #include "be_iscsi.h" #include "be_main.h" +#define IP_ACTION_ADD 0x01 +#define IP_ACTION_DEL 0x02 + +#define IP_V6_LEN 16 +#define IP_V4_LEN 4 + /** * Pseudo amap definition in which each bit of the actual structure is defined * as a byte: used to calculate offset/shift/mask of each field @@ -98,6 +103,10 @@ unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba, struct invalidate_command_table *inv_tbl, unsigned int num_invalidate, unsigned int cid, struct be_dma_mem *nonemb_cmd); +unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl, + struct beiscsi_hba *phba, + struct bsg_job *job, + struct be_dma_mem *nonemb_cmd); struct iscsi_invalidate_connection_params_in { struct be_cmd_req_hdr hdr; @@ -204,6 +213,13 @@ struct be_mgmt_controller_attributes_resp { struct mgmt_controller_attributes params; } __packed; +struct be_bsg_vendor_cmd { + struct be_cmd_req_hdr hdr; + unsigned short region; + unsigned short offset; + unsigned short sector; +} __packed; + /* configuration management */ #define GET_MGMT_CONTROLLER_WS(phba) (phba->pmgmt_ws) @@ -219,12 +235,15 @@ struct be_mgmt_controller_attributes_resp { /* the CMD_RESPONSE_HEADER */ #define ISCSI_GET_PDU_TEMPLATE_ADDRESS(pc, pa) {\ - pa->lo = phba->init_mem[ISCSI_MEM_GLOBAL_HEADER].mem_array[0].\ + pa->lo = phba->init_mem[ISCSI_MEM_GLOBAL_HEADER].mem_array[0].\ bus_address.u.a32.address_lo; \ - pa->hi = phba->init_mem[ISCSI_MEM_GLOBAL_HEADER].mem_array[0].\ + pa->hi = phba->init_mem[ISCSI_MEM_GLOBAL_HEADER].mem_array[0].\ bus_address.u.a32.address_hi; \ } +#define BEISCSI_WRITE_FLASH 0 +#define BEISCSI_READ_FLASH 1 + struct beiscsi_endpoint { struct beiscsi_hba *phba; struct beiscsi_sess *sess; @@ -248,4 +267,27 @@ unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba, unsigned short issue_reset, unsigned short savecfg_flag); +int mgmt_set_ip(struct beiscsi_hba *phba, + struct iscsi_iface_param_info *ip_param, + struct iscsi_iface_param_info *subnet_param, + uint32_t boot_proto); + +unsigned int mgmt_get_boot_target(struct beiscsi_hba *phba); + +unsigned int mgmt_get_session_info(struct beiscsi_hba *phba, + u32 boot_session_handle, + struct be_dma_mem *nonemb_cmd); + +int mgmt_get_nic_conf(struct beiscsi_hba *phba, + struct be_cmd_get_nic_conf_resp *mac); + +int mgmt_get_if_info(struct beiscsi_hba *phba, int ip_type, + struct be_cmd_get_if_info_resp *if_info); + +int mgmt_get_gateway(struct beiscsi_hba *phba, int ip_type, + struct be_cmd_get_def_gateway_resp *gateway); + +int mgmt_set_gateway(struct beiscsi_hba *phba, + struct iscsi_iface_param_info *gateway_param); + #endif diff --git a/trunk/drivers/scsi/bfa/bfa_fcs.h b/trunk/drivers/scsi/bfa/bfa_fcs.h index e75e07d25915..51c9e1345719 100644 --- a/trunk/drivers/scsi/bfa/bfa_fcs.h +++ b/trunk/drivers/scsi/bfa/bfa_fcs.h @@ -799,9 +799,6 @@ struct bfad_port_s *bfa_fcb_lport_new(struct bfad_s *bfad, enum bfa_lport_role roles, struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv); -void bfa_fcb_lport_delete(struct bfad_s *bfad, enum bfa_lport_role roles, - struct bfad_vf_s *vf_drv, - struct bfad_vport_s *vp_drv); /* * vport callbacks diff --git a/trunk/drivers/scsi/bfa/bfa_fcs_lport.c b/trunk/drivers/scsi/bfa/bfa_fcs_lport.c index 5d2a1307e5ce..937000db62a8 100644 --- a/trunk/drivers/scsi/bfa/bfa_fcs_lport.c +++ b/trunk/drivers/scsi/bfa/bfa_fcs_lport.c @@ -616,7 +616,7 @@ bfa_fcs_lport_online_actions(struct bfa_fcs_lport_s *port) __port_action[port->fabric->fab_type].online(port); wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port)); - BFA_LOG(KERN_INFO, bfad, bfa_log_level, + BFA_LOG(KERN_WARNING, bfad, bfa_log_level, "Logical port online: WWN = %s Role = %s\n", lpwwn_buf, "Initiator"); bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_ONLINE); @@ -639,12 +639,12 @@ bfa_fcs_lport_offline_actions(struct bfa_fcs_lport_s *port) wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port)); if (bfa_sm_cmp_state(port->fabric, bfa_fcs_fabric_sm_online) == BFA_TRUE) { - BFA_LOG(KERN_ERR, bfad, bfa_log_level, + BFA_LOG(KERN_WARNING, bfad, bfa_log_level, "Logical port lost fabric connectivity: WWN = %s Role = %s\n", lpwwn_buf, "Initiator"); bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_DISCONNECT); } else { - BFA_LOG(KERN_INFO, bfad, bfa_log_level, + BFA_LOG(KERN_WARNING, bfad, bfa_log_level, "Logical port taken offline: WWN = %s Role = %s\n", lpwwn_buf, "Initiator"); bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_OFFLINE); @@ -709,14 +709,10 @@ bfa_fcs_lport_deleted(struct bfa_fcs_lport_s *port) bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_DELETE); /* Base port will be deleted by the OS driver */ - if (port->vport) { - bfa_fcb_lport_delete(port->fcs->bfad, port->port_cfg.roles, - port->fabric->vf_drv, - port->vport ? port->vport->vport_drv : NULL); + if (port->vport) bfa_fcs_vport_delete_comp(port->vport); - } else { + else bfa_wc_down(&port->fabric->wc); - } } @@ -5714,17 +5710,23 @@ bfa_fcs_vport_free(struct bfa_fcs_vport_s *vport) (struct bfad_vport_s *)vport->vport_drv; bfa_fcs_fabric_delvport(__vport_fabric(vport), vport); + bfa_lps_delete(vport->lps); - if (vport_drv->comp_del) + if (vport_drv->comp_del) { complete(vport_drv->comp_del); - else - kfree(vport_drv); + return; + } - bfa_lps_delete(vport->lps); + /* + * We queue the vport delete work to the IM work_q from here. + * The memory for the bfad_vport_s is freed from the FC function + * template vport_delete entry point. + */ + if (vport_drv) + bfad_im_port_delete(vport_drv->drv_port.bfad, + &vport_drv->drv_port); } - - /* * fcs_vport_public FCS virtual port public interfaces */ diff --git a/trunk/drivers/scsi/bfa/bfad.c b/trunk/drivers/scsi/bfa/bfad.c index 404fd10ddb21..2e4b0be14a20 100644 --- a/trunk/drivers/scsi/bfa/bfad.c +++ b/trunk/drivers/scsi/bfa/bfad.c @@ -456,23 +456,6 @@ bfa_fcb_lport_new(struct bfad_s *bfad, struct bfa_fcs_lport_s *port, return port_drv; } -void -bfa_fcb_lport_delete(struct bfad_s *bfad, enum bfa_lport_role roles, - struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv) -{ - struct bfad_port_s *port_drv; - - /* this will be only called from rmmod context */ - if (vp_drv && !vp_drv->comp_del) { - port_drv = (vp_drv) ? (&(vp_drv)->drv_port) : - ((vf_drv) ? (&(vf_drv)->base_port) : - (&(bfad)->pport)); - bfa_trc(bfad, roles); - if (roles & BFA_LPORT_ROLE_FCP_IM) - bfad_im_port_delete(bfad, port_drv); - } -} - /* * FCS RPORT alloc callback, after successful PLOGI by FCS */ diff --git a/trunk/drivers/scsi/bfa/bfad_attr.c b/trunk/drivers/scsi/bfa/bfad_attr.c index 7b1ecd2b3ffe..8b6c6bf7837e 100644 --- a/trunk/drivers/scsi/bfa/bfad_attr.c +++ b/trunk/drivers/scsi/bfa/bfad_attr.c @@ -497,6 +497,7 @@ bfad_im_vport_delete(struct fc_vport *fc_vport) if (im_port->flags & BFAD_PORT_DELETE) { bfad_scsi_host_free(bfad, im_port); list_del(&vport->list_entry); + kfree(vport); return 0; } @@ -758,25 +759,10 @@ bfad_im_model_desc_show(struct device *dev, struct device_attribute *attr, else if (!strcmp(model, "Brocade-804")) snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, "Brocade 8Gbps FC HBA for HP Bladesystem C-class"); - else if (!strcmp(model, "Brocade-902") || - !strcmp(model, "Brocade-1741")) + else if (!strcmp(model, "Brocade-1741")) snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, "Brocade 10Gbps CNA for Dell M-Series Blade Servers"); - else if (strstr(model, "Brocade-1560")) { - if (nports == 1) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 16Gbps PCIe single port FC HBA"); - else - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 16Gbps PCIe dual port FC HBA"); - } else if (strstr(model, "Brocade-1710")) { - if (nports == 1) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 10Gbps single port CNA"); - else - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 10Gbps dual port CNA"); - } else if (strstr(model, "Brocade-1860")) { + else if (strstr(model, "Brocade-1860")) { if (nports == 1 && bfa_ioc_is_cna(&bfad->bfa.ioc)) snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, "Brocade 10Gbps single port CNA"); diff --git a/trunk/drivers/scsi/bnx2i/57xx_iscsi_constants.h b/trunk/drivers/scsi/bnx2i/57xx_iscsi_constants.h index 495a841645f9..25093a04123b 100644 --- a/trunk/drivers/scsi/bnx2i/57xx_iscsi_constants.h +++ b/trunk/drivers/scsi/bnx2i/57xx_iscsi_constants.h @@ -1,6 +1,6 @@ /* 57xx_iscsi_constants.h: Broadcom NetXtreme II iSCSI HSI * - * Copyright (c) 2006 - 2011 Broadcom Corporation + * Copyright (c) 2006 - 2012 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 diff --git a/trunk/drivers/scsi/bnx2i/57xx_iscsi_hsi.h b/trunk/drivers/scsi/bnx2i/57xx_iscsi_hsi.h index 72118db89a20..dc0a08e69c82 100644 --- a/trunk/drivers/scsi/bnx2i/57xx_iscsi_hsi.h +++ b/trunk/drivers/scsi/bnx2i/57xx_iscsi_hsi.h @@ -1,6 +1,6 @@ /* 57xx_iscsi_hsi.h: Broadcom NetXtreme II iSCSI HSI. * - * Copyright (c) 2006 - 2011 Broadcom Corporation + * Copyright (c) 2006 - 2012 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 diff --git a/trunk/drivers/scsi/bnx2i/bnx2i.h b/trunk/drivers/scsi/bnx2i/bnx2i.h index 0bd70e80efe4..0c53c28dc3d3 100644 --- a/trunk/drivers/scsi/bnx2i/bnx2i.h +++ b/trunk/drivers/scsi/bnx2i/bnx2i.h @@ -1,6 +1,6 @@ /* bnx2i.h: Broadcom NetXtreme II iSCSI driver. * - * Copyright (c) 2006 - 2011 Broadcom Corporation + * Copyright (c) 2006 - 2012 Broadcom Corporation * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. * Copyright (c) 2007, 2008 Mike Christie * diff --git a/trunk/drivers/scsi/bnx2i/bnx2i_hwi.c b/trunk/drivers/scsi/bnx2i/bnx2i_hwi.c index f9d6f4129093..ece47e502282 100644 --- a/trunk/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/trunk/drivers/scsi/bnx2i/bnx2i_hwi.c @@ -1,6 +1,6 @@ /* bnx2i_hwi.c: Broadcom NetXtreme II iSCSI driver. * - * Copyright (c) 2006 - 2011 Broadcom Corporation + * Copyright (c) 2006 - 2012 Broadcom Corporation * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. * Copyright (c) 2007, 2008 Mike Christie * diff --git a/trunk/drivers/scsi/bnx2i/bnx2i_init.c b/trunk/drivers/scsi/bnx2i/bnx2i_init.c index 4927cca733d3..8b6816706ee5 100644 --- a/trunk/drivers/scsi/bnx2i/bnx2i_init.c +++ b/trunk/drivers/scsi/bnx2i/bnx2i_init.c @@ -1,6 +1,6 @@ /* bnx2i.c: Broadcom NetXtreme II iSCSI driver. * - * Copyright (c) 2006 - 2011 Broadcom Corporation + * Copyright (c) 2006 - 2012 Broadcom Corporation * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. * Copyright (c) 2007, 2008 Mike Christie * @@ -18,8 +18,8 @@ static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list); static u32 adapter_count; #define DRV_MODULE_NAME "bnx2i" -#define DRV_MODULE_VERSION "2.7.0.3" -#define DRV_MODULE_RELDATE "Jun 15, 2011" +#define DRV_MODULE_VERSION "2.7.2.2" +#define DRV_MODULE_RELDATE "Apr 25, 2012" static char version[] __devinitdata = "Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \ diff --git a/trunk/drivers/scsi/bnx2i/bnx2i_iscsi.c b/trunk/drivers/scsi/bnx2i/bnx2i_iscsi.c index 1a44b45e7bef..f8d516b53161 100644 --- a/trunk/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/trunk/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -1,7 +1,7 @@ /* * bnx2i_iscsi.c: Broadcom NetXtreme II iSCSI driver. * - * Copyright (c) 2006 - 2011 Broadcom Corporation + * Copyright (c) 2006 - 2012 Broadcom Corporation * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. * Copyright (c) 2007, 2008 Mike Christie * @@ -2244,6 +2244,7 @@ static struct scsi_host_template bnx2i_host_template = { .eh_device_reset_handler = iscsi_eh_device_reset, .eh_target_reset_handler = iscsi_eh_recover_target, .change_queue_depth = iscsi_change_queue_depth, + .target_alloc = iscsi_target_alloc, .can_queue = 2048, .max_sectors = 127, .cmd_per_lun = 128, diff --git a/trunk/drivers/scsi/bnx2i/bnx2i_sysfs.c b/trunk/drivers/scsi/bnx2i/bnx2i_sysfs.c index 83a77f7244d2..c61cf7a43658 100644 --- a/trunk/drivers/scsi/bnx2i/bnx2i_sysfs.c +++ b/trunk/drivers/scsi/bnx2i/bnx2i_sysfs.c @@ -1,6 +1,6 @@ /* bnx2i_sysfs.c: Broadcom NetXtreme II iSCSI driver. * - * Copyright (c) 2004 - 2011 Broadcom Corporation + * Copyright (c) 2004 - 2012 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 diff --git a/trunk/drivers/scsi/device_handler/scsi_dh_alua.c b/trunk/drivers/scsi/device_handler/scsi_dh_alua.c index 04c5cea47a22..fda9cdea0e60 100644 --- a/trunk/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/trunk/drivers/scsi/device_handler/scsi_dh_alua.c @@ -55,11 +55,16 @@ #define ALUA_FAILOVER_TIMEOUT (60 * HZ) #define ALUA_FAILOVER_RETRIES 5 +/* flags passed from user level */ +#define ALUA_OPTIMIZE_STPG 1 + struct alua_dh_data { int group_id; int rel_port; int tpgs; int state; + int pref; + unsigned flags; /* used for optimizing STPG */ unsigned char inq[ALUA_INQUIRY_SIZE]; unsigned char *buff; int bufflen; @@ -554,14 +559,16 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) for (k = 4, ucp = h->buff + 4; k < len; k += off, ucp += off) { if (h->group_id == (ucp[2] << 8) + ucp[3]) { h->state = ucp[0] & 0x0f; + h->pref = ucp[0] >> 7; valid_states = ucp[1]; } off = 8 + (ucp[7] * 4); } sdev_printk(KERN_INFO, sdev, - "%s: port group %02x state %c supports %c%c%c%c%c%c%c\n", + "%s: port group %02x state %c %s supports %c%c%c%c%c%c%c\n", ALUA_DH_NAME, h->group_id, print_alua_state(h->state), + h->pref ? "preferred" : "non-preferred", valid_states&TPGS_SUPPORT_TRANSITION?'T':'t', valid_states&TPGS_SUPPORT_OFFLINE?'O':'o', valid_states&TPGS_SUPPORT_LBA_DEPENDENT?'L':'l', @@ -621,6 +628,37 @@ static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h) out: return err; } +/* + * alua_set_params - set/unset the optimize flag + * @sdev: device on the path to be activated + * params - parameters in the following format + * "no_of_params\0param1\0param2\0param3\0...\0" + * For example, to set the flag pass the following parameters + * from multipath.conf + * hardware_handler "2 alua 1" + */ +static int alua_set_params(struct scsi_device *sdev, const char *params) +{ + struct alua_dh_data *h = get_alua_data(sdev); + unsigned int optimize = 0, argc; + const char *p = params; + int result = SCSI_DH_OK; + + if ((sscanf(params, "%u", &argc) != 1) || (argc != 1)) + return -EINVAL; + + while (*p++) + ; + if ((sscanf(p, "%u", &optimize) != 1) || (optimize > 1)) + return -EINVAL; + + if (optimize) + h->flags |= ALUA_OPTIMIZE_STPG; + else + h->flags &= ~ALUA_OPTIMIZE_STPG; + + return result; +} /* * alua_activate - activate a path @@ -637,14 +675,37 @@ static int alua_activate(struct scsi_device *sdev, { struct alua_dh_data *h = get_alua_data(sdev); int err = SCSI_DH_OK; + int stpg = 0; err = alua_rtpg(sdev, h); if (err != SCSI_DH_OK) goto out; - if (h->tpgs & TPGS_MODE_EXPLICIT && - h->state != TPGS_STATE_OPTIMIZED && - h->state != TPGS_STATE_LBA_DEPENDENT) { + if (h->tpgs & TPGS_MODE_EXPLICIT) { + switch (h->state) { + case TPGS_STATE_NONOPTIMIZED: + stpg = 1; + if ((h->flags & ALUA_OPTIMIZE_STPG) && + (!h->pref) && + (h->tpgs & TPGS_MODE_IMPLICIT)) + stpg = 0; + break; + case TPGS_STATE_STANDBY: + stpg = 1; + break; + case TPGS_STATE_UNAVAILABLE: + case TPGS_STATE_OFFLINE: + err = SCSI_DH_IO; + break; + case TPGS_STATE_TRANSITIONING: + err = SCSI_DH_RETRY; + break; + default: + break; + } + } + + if (stpg) { h->callback_fn = fn; h->callback_data = data; err = submit_stpg(h); @@ -698,6 +759,7 @@ static struct scsi_device_handler alua_dh = { .prep_fn = alua_prep_fn, .check_sense = alua_check_sense, .activate = alua_activate, + .set_params = alua_set_params, .match = alua_match, }; diff --git a/trunk/drivers/scsi/esp_scsi.c b/trunk/drivers/scsi/esp_scsi.c index 394ed9e79fd4..34552bf1c023 100644 --- a/trunk/drivers/scsi/esp_scsi.c +++ b/trunk/drivers/scsi/esp_scsi.c @@ -1000,7 +1000,7 @@ static int esp_check_spur_intr(struct esp *esp) static void esp_schedule_reset(struct esp *esp) { - esp_log_reset("ESP: esp_schedule_reset() from %p\n", + esp_log_reset("ESP: esp_schedule_reset() from %pf\n", __builtin_return_address(0)); esp->flags |= ESP_FLAG_RESETTING; esp_event(esp, ESP_EVENT_RESET); diff --git a/trunk/drivers/scsi/fcoe/fcoe.c b/trunk/drivers/scsi/fcoe/fcoe.c index 335e85192807..76e3d0b5bfa6 100644 --- a/trunk/drivers/scsi/fcoe/fcoe.c +++ b/trunk/drivers/scsi/fcoe/fcoe.c @@ -411,20 +411,18 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev, } /** - * fcoe_interface_cleanup() - Clean up a FCoE interface + * fcoe_interface_remove() - remove FCoE interface from netdev * @fcoe: The FCoE interface to be cleaned up * * Caller must be holding the RTNL mutex */ -static void fcoe_interface_cleanup(struct fcoe_interface *fcoe) +static void fcoe_interface_remove(struct fcoe_interface *fcoe) { struct net_device *netdev = fcoe->netdev; struct fcoe_ctlr *fip = &fcoe->ctlr; u8 flogi_maddr[ETH_ALEN]; const struct net_device_ops *ops; - rtnl_lock(); - /* * Don't listen for Ethernet packets anymore. * synchronize_net() ensures that the packet handlers are not running @@ -453,12 +451,28 @@ static void fcoe_interface_cleanup(struct fcoe_interface *fcoe) FCOE_NETDEV_DBG(netdev, "Failed to disable FCoE" " specific feature for LLD.\n"); } + fcoe->removed = 1; +} + + +/** + * fcoe_interface_cleanup() - Clean up a FCoE interface + * @fcoe: The FCoE interface to be cleaned up + */ +static void fcoe_interface_cleanup(struct fcoe_interface *fcoe) +{ + struct net_device *netdev = fcoe->netdev; + struct fcoe_ctlr *fip = &fcoe->ctlr; + rtnl_lock(); + if (!fcoe->removed) + fcoe_interface_remove(fcoe); rtnl_unlock(); /* Release the self-reference taken during fcoe_interface_create() */ /* tear-down the FCoE controller */ fcoe_ctlr_destroy(fip); + scsi_host_put(fcoe->ctlr.lp->host); kfree(fcoe); dev_put(netdev); module_put(THIS_MODULE); @@ -522,13 +536,11 @@ static void fcoe_update_src_mac(struct fc_lport *lport, u8 *addr) struct fcoe_port *port = lport_priv(lport); struct fcoe_interface *fcoe = port->priv; - rtnl_lock(); if (!is_zero_ether_addr(port->data_src_addr)) dev_uc_del(fcoe->netdev, port->data_src_addr); if (!is_zero_ether_addr(addr)) dev_uc_add(fcoe->netdev, addr); memcpy(port->data_src_addr, addr, ETH_ALEN); - rtnl_unlock(); } /** @@ -941,6 +953,10 @@ static void fcoe_if_destroy(struct fc_lport *lport) rtnl_lock(); if (!is_zero_ether_addr(port->data_src_addr)) dev_uc_del(netdev, port->data_src_addr); + if (lport->vport) + synchronize_net(); + else + fcoe_interface_remove(fcoe); rtnl_unlock(); /* Free queued packets for the per-CPU receive threads */ @@ -959,8 +975,12 @@ static void fcoe_if_destroy(struct fc_lport *lport) /* Free memory used by statistical counters */ fc_lport_free_stats(lport); - /* Release the Scsi_Host */ - scsi_host_put(lport->host); + /* + * Release the Scsi_Host for vport but hold on to + * master lport until it fcoe interface fully cleaned-up. + */ + if (lport->vport) + scsi_host_put(lport->host); } /** @@ -2274,10 +2294,9 @@ static void fcoe_percpu_clean(struct fc_lport *lport) continue; skb = dev_alloc_skb(0); - if (!skb) { - spin_unlock_bh(&pp->fcoe_rx_list.lock); + if (!skb) continue; - } + skb->destructor = fcoe_percpu_flush_done; spin_lock_bh(&pp->fcoe_rx_list.lock); diff --git a/trunk/drivers/scsi/fcoe/fcoe.h b/trunk/drivers/scsi/fcoe/fcoe.h index 3c2733a12aa1..96ac938d39cc 100644 --- a/trunk/drivers/scsi/fcoe/fcoe.h +++ b/trunk/drivers/scsi/fcoe/fcoe.h @@ -71,7 +71,8 @@ do { \ * @ctlr: The FCoE controller (for FIP) * @oem: The offload exchange manager for all local port * instances associated with this port - * This structure is 1:1 with a net devive. + * @removed: Indicates fcoe interface removed from net device + * This structure is 1:1 with a net device. */ struct fcoe_interface { struct list_head list; @@ -81,6 +82,7 @@ struct fcoe_interface { struct packet_type fip_packet_type; struct fcoe_ctlr ctlr; struct fc_exch_mgr *oem; + u8 removed; }; #define fcoe_from_ctlr(fip) container_of(fip, struct fcoe_interface, ctlr) diff --git a/trunk/drivers/scsi/fcoe/fcoe_ctlr.c b/trunk/drivers/scsi/fcoe/fcoe_ctlr.c index 249a106888d9..5a4c7250aa77 100644 --- a/trunk/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/trunk/drivers/scsi/fcoe/fcoe_ctlr.c @@ -1883,7 +1883,13 @@ static void fcoe_ctlr_vn_send(struct fcoe_ctlr *fip, frame = (struct fip_frame *)skb->data; memset(frame, 0, len); memcpy(frame->eth.h_dest, dest, ETH_ALEN); - memcpy(frame->eth.h_source, fip->ctl_src_addr, ETH_ALEN); + + if (sub == FIP_SC_VN_BEACON) { + hton24(frame->eth.h_source, FIP_VN_FC_MAP); + hton24(frame->eth.h_source + 3, fip->port_id); + } else { + memcpy(frame->eth.h_source, fip->ctl_src_addr, ETH_ALEN); + } frame->eth.h_proto = htons(ETH_P_FIP); frame->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER); diff --git a/trunk/drivers/scsi/hpsa.c b/trunk/drivers/scsi/hpsa.c index 500e20dd56ec..796482badf13 100644 --- a/trunk/drivers/scsi/hpsa.c +++ b/trunk/drivers/scsi/hpsa.c @@ -159,6 +159,7 @@ static int hpsa_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason); static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd); +static int hpsa_eh_abort_handler(struct scsi_cmnd *scsicmd); static int hpsa_slave_alloc(struct scsi_device *sdev); static void hpsa_slave_destroy(struct scsi_device *sdev); @@ -171,7 +172,7 @@ static void check_ioctl_unit_attention(struct ctlr_info *h, static void calc_bucket_map(int *bucket, int num_buckets, int nsgs, int *bucket_map); static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h); -static inline u32 next_command(struct ctlr_info *h); +static inline u32 next_command(struct ctlr_info *h, u8 q); static int __devinit hpsa_find_cfg_addrs(struct pci_dev *pdev, void __iomem *vaddr, u32 *cfg_base_addr, u64 *cfg_base_addr_index, u64 *cfg_offset); @@ -180,6 +181,7 @@ static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev, static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id); static int __devinit hpsa_wait_for_board_state(struct pci_dev *pdev, void __iomem *vaddr, int wait_for_ready); +static inline void finish_cmd(struct CommandList *c); #define BOARD_NOT_READY 0 #define BOARD_READY 1 @@ -234,6 +236,16 @@ static int check_for_unit_attention(struct ctlr_info *h, return 1; } +static int check_for_busy(struct ctlr_info *h, struct CommandList *c) +{ + if (c->err_info->CommandStatus != CMD_TARGET_STATUS || + (c->err_info->ScsiStatus != SAM_STAT_BUSY && + c->err_info->ScsiStatus != SAM_STAT_TASK_SET_FULL)) + return 0; + dev_warn(&h->pdev->dev, HPSA "device busy"); + return 1; +} + static ssize_t host_store_rescan(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -368,7 +380,7 @@ static inline int is_logical_dev_addr_mode(unsigned char scsi3addr[]) } static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG", - "UNKNOWN" + "1(ADM)", "UNKNOWN" }; #define RAID_UNKNOWN (ARRAY_SIZE(raid_label) - 1) @@ -497,6 +509,7 @@ static struct scsi_host_template hpsa_driver_template = { .change_queue_depth = hpsa_change_queue_depth, .this_id = -1, .use_clustering = ENABLE_CLUSTERING, + .eh_abort_handler = hpsa_eh_abort_handler, .eh_device_reset_handler = hpsa_eh_device_reset_handler, .ioctl = hpsa_ioctl, .slave_alloc = hpsa_slave_alloc, @@ -516,24 +529,28 @@ static inline void addQ(struct list_head *list, struct CommandList *c) list_add_tail(&c->list, list); } -static inline u32 next_command(struct ctlr_info *h) +static inline u32 next_command(struct ctlr_info *h, u8 q) { u32 a; + struct reply_pool *rq = &h->reply_queue[q]; + unsigned long flags; if (unlikely(!(h->transMethod & CFGTBL_Trans_Performant))) - return h->access.command_completed(h); + return h->access.command_completed(h, q); - if ((*(h->reply_pool_head) & 1) == (h->reply_pool_wraparound)) { - a = *(h->reply_pool_head); /* Next cmd in ring buffer */ - (h->reply_pool_head)++; + if ((rq->head[rq->current_entry] & 1) == rq->wraparound) { + a = rq->head[rq->current_entry]; + rq->current_entry++; + spin_lock_irqsave(&h->lock, flags); h->commands_outstanding--; + spin_unlock_irqrestore(&h->lock, flags); } else { a = FIFO_EMPTY; } /* Check for wraparound */ - if (h->reply_pool_head == (h->reply_pool + h->max_commands)) { - h->reply_pool_head = h->reply_pool; - h->reply_pool_wraparound ^= 1; + if (rq->current_entry == h->max_commands) { + rq->current_entry = 0; + rq->wraparound ^= 1; } return a; } @@ -544,8 +561,41 @@ static inline u32 next_command(struct ctlr_info *h) */ static void set_performant_mode(struct ctlr_info *h, struct CommandList *c) { - if (likely(h->transMethod & CFGTBL_Trans_Performant)) + if (likely(h->transMethod & CFGTBL_Trans_Performant)) { c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1); + if (likely(h->msix_vector)) + c->Header.ReplyQueue = + smp_processor_id() % h->nreply_queues; + } +} + +static int is_firmware_flash_cmd(u8 *cdb) +{ + return cdb[0] == BMIC_WRITE && cdb[6] == BMIC_FLASH_FIRMWARE; +} + +/* + * During firmware flash, the heartbeat register may not update as frequently + * as it should. So we dial down lockup detection during firmware flash. and + * dial it back up when firmware flash completes. + */ +#define HEARTBEAT_SAMPLE_INTERVAL_DURING_FLASH (240 * HZ) +#define HEARTBEAT_SAMPLE_INTERVAL (30 * HZ) +static void dial_down_lockup_detection_during_fw_flash(struct ctlr_info *h, + struct CommandList *c) +{ + if (!is_firmware_flash_cmd(c->Request.CDB)) + return; + atomic_inc(&h->firmware_flash_in_progress); + h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL_DURING_FLASH; +} + +static void dial_up_lockup_detection_on_fw_flash_complete(struct ctlr_info *h, + struct CommandList *c) +{ + if (is_firmware_flash_cmd(c->Request.CDB) && + atomic_dec_and_test(&h->firmware_flash_in_progress)) + h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL; } static void enqueue_cmd_and_start_io(struct ctlr_info *h, @@ -554,11 +604,12 @@ static void enqueue_cmd_and_start_io(struct ctlr_info *h, unsigned long flags; set_performant_mode(h, c); + dial_down_lockup_detection_during_fw_flash(h, c); spin_lock_irqsave(&h->lock, flags); addQ(&h->reqQ, c); h->Qdepth++; - start_io(h); spin_unlock_irqrestore(&h->lock, flags); + start_io(h); } static inline void removeQ(struct CommandList *c) @@ -1193,7 +1244,7 @@ static void complete_scsi_command(struct CommandList *cp) break; } /* Must be some other type of check condition */ - dev_warn(&h->pdev->dev, "cp %p has check condition: " + dev_dbg(&h->pdev->dev, "cp %p has check condition: " "unknown type: " "Sense: 0x%x, ASC: 0x%x, ASCQ: 0x%x, " "Returning result: 0x%x, " @@ -1370,16 +1421,24 @@ static void hpsa_scsi_do_simple_cmd_core_if_no_lockup(struct ctlr_info *h, } } +#define MAX_DRIVER_CMD_RETRIES 25 static void hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h, struct CommandList *c, int data_direction) { - int retry_count = 0; + int backoff_time = 10, retry_count = 0; do { memset(c->err_info, 0, sizeof(*c->err_info)); hpsa_scsi_do_simple_cmd_core(h, c); retry_count++; - } while (check_for_unit_attention(h, c) && retry_count <= 3); + if (retry_count > 3) { + msleep(backoff_time); + if (backoff_time < 1000) + backoff_time *= 2; + } + } while ((check_for_unit_attention(h, c) || + check_for_busy(h, c)) && + retry_count <= MAX_DRIVER_CMD_RETRIES); hpsa_pci_unmap(h->pdev, c, 1, data_direction); } @@ -2065,9 +2124,8 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd, done(cmd); return 0; } - /* Need a lock as this is being allocated from the pool */ - c = cmd_alloc(h); spin_unlock_irqrestore(&h->lock, flags); + c = cmd_alloc(h); if (c == NULL) { /* trouble... */ dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n"); return SCSI_MLQUEUE_HOST_BUSY; @@ -2334,6 +2392,261 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) return FAILED; } +static void swizzle_abort_tag(u8 *tag) +{ + u8 original_tag[8]; + + memcpy(original_tag, tag, 8); + tag[0] = original_tag[3]; + tag[1] = original_tag[2]; + tag[2] = original_tag[1]; + tag[3] = original_tag[0]; + tag[4] = original_tag[7]; + tag[5] = original_tag[6]; + tag[6] = original_tag[5]; + tag[7] = original_tag[4]; +} + +static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, + struct CommandList *abort, int swizzle) +{ + int rc = IO_OK; + struct CommandList *c; + struct ErrorInfo *ei; + + c = cmd_special_alloc(h); + if (c == NULL) { /* trouble... */ + dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); + return -ENOMEM; + } + + fill_cmd(c, HPSA_ABORT_MSG, h, abort, 0, 0, scsi3addr, TYPE_MSG); + if (swizzle) + swizzle_abort_tag(&c->Request.CDB[4]); + hpsa_scsi_do_simple_cmd_core(h, c); + dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: do_simple_cmd_core completed.\n", + __func__, abort->Header.Tag.upper, abort->Header.Tag.lower); + /* no unmap needed here because no data xfer. */ + + ei = c->err_info; + switch (ei->CommandStatus) { + case CMD_SUCCESS: + break; + case CMD_UNABORTABLE: /* Very common, don't make noise. */ + rc = -1; + break; + default: + dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: interpreting error.\n", + __func__, abort->Header.Tag.upper, + abort->Header.Tag.lower); + hpsa_scsi_interpret_error(c); + rc = -1; + break; + } + cmd_special_free(h, c); + dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: Finished.\n", __func__, + abort->Header.Tag.upper, abort->Header.Tag.lower); + return rc; +} + +/* + * hpsa_find_cmd_in_queue + * + * Used to determine whether a command (find) is still present + * in queue_head. Optionally excludes the last element of queue_head. + * + * This is used to avoid unnecessary aborts. Commands in h->reqQ have + * not yet been submitted, and so can be aborted by the driver without + * sending an abort to the hardware. + * + * Returns pointer to command if found in queue, NULL otherwise. + */ +static struct CommandList *hpsa_find_cmd_in_queue(struct ctlr_info *h, + struct scsi_cmnd *find, struct list_head *queue_head) +{ + unsigned long flags; + struct CommandList *c = NULL; /* ptr into cmpQ */ + + if (!find) + return 0; + spin_lock_irqsave(&h->lock, flags); + list_for_each_entry(c, queue_head, list) { + if (c->scsi_cmd == NULL) /* e.g.: passthru ioctl */ + continue; + if (c->scsi_cmd == find) { + spin_unlock_irqrestore(&h->lock, flags); + return c; + } + } + spin_unlock_irqrestore(&h->lock, flags); + return NULL; +} + +static struct CommandList *hpsa_find_cmd_in_queue_by_tag(struct ctlr_info *h, + u8 *tag, struct list_head *queue_head) +{ + unsigned long flags; + struct CommandList *c; + + spin_lock_irqsave(&h->lock, flags); + list_for_each_entry(c, queue_head, list) { + if (memcmp(&c->Header.Tag, tag, 8) != 0) + continue; + spin_unlock_irqrestore(&h->lock, flags); + return c; + } + spin_unlock_irqrestore(&h->lock, flags); + return NULL; +} + +/* Some Smart Arrays need the abort tag swizzled, and some don't. It's hard to + * tell which kind we're dealing with, so we send the abort both ways. There + * shouldn't be any collisions between swizzled and unswizzled tags due to the + * way we construct our tags but we check anyway in case the assumptions which + * make this true someday become false. + */ +static int hpsa_send_abort_both_ways(struct ctlr_info *h, + unsigned char *scsi3addr, struct CommandList *abort) +{ + u8 swizzled_tag[8]; + struct CommandList *c; + int rc = 0, rc2 = 0; + + /* we do not expect to find the swizzled tag in our queue, but + * check anyway just to be sure the assumptions which make this + * the case haven't become wrong. + */ + memcpy(swizzled_tag, &abort->Request.CDB[4], 8); + swizzle_abort_tag(swizzled_tag); + c = hpsa_find_cmd_in_queue_by_tag(h, swizzled_tag, &h->cmpQ); + if (c != NULL) { + dev_warn(&h->pdev->dev, "Unexpectedly found byte-swapped tag in completion queue.\n"); + return hpsa_send_abort(h, scsi3addr, abort, 0); + } + rc = hpsa_send_abort(h, scsi3addr, abort, 0); + + /* if the command is still in our queue, we can't conclude that it was + * aborted (it might have just completed normally) but in any case + * we don't need to try to abort it another way. + */ + c = hpsa_find_cmd_in_queue(h, abort->scsi_cmd, &h->cmpQ); + if (c) + rc2 = hpsa_send_abort(h, scsi3addr, abort, 1); + return rc && rc2; +} + +/* Send an abort for the specified command. + * If the device and controller support it, + * send a task abort request. + */ +static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) +{ + + int i, rc; + struct ctlr_info *h; + struct hpsa_scsi_dev_t *dev; + struct CommandList *abort; /* pointer to command to be aborted */ + struct CommandList *found; + struct scsi_cmnd *as; /* ptr to scsi cmd inside aborted command. */ + char msg[256]; /* For debug messaging. */ + int ml = 0; + + /* Find the controller of the command to be aborted */ + h = sdev_to_hba(sc->device); + if (WARN(h == NULL, + "ABORT REQUEST FAILED, Controller lookup failed.\n")) + return FAILED; + + /* Check that controller supports some kind of task abort */ + if (!(HPSATMF_PHYS_TASK_ABORT & h->TMFSupportFlags) && + !(HPSATMF_LOG_TASK_ABORT & h->TMFSupportFlags)) + return FAILED; + + memset(msg, 0, sizeof(msg)); + ml += sprintf(msg+ml, "ABORT REQUEST on C%d:B%d:T%d:L%d ", + h->scsi_host->host_no, sc->device->channel, + sc->device->id, sc->device->lun); + + /* Find the device of the command to be aborted */ + dev = sc->device->hostdata; + if (!dev) { + dev_err(&h->pdev->dev, "%s FAILED, Device lookup failed.\n", + msg); + return FAILED; + } + + /* Get SCSI command to be aborted */ + abort = (struct CommandList *) sc->host_scribble; + if (abort == NULL) { + dev_err(&h->pdev->dev, "%s FAILED, Command to abort is NULL.\n", + msg); + return FAILED; + } + + ml += sprintf(msg+ml, "Tag:0x%08x:%08x ", + abort->Header.Tag.upper, abort->Header.Tag.lower); + as = (struct scsi_cmnd *) abort->scsi_cmd; + if (as != NULL) + ml += sprintf(msg+ml, "Command:0x%x SN:0x%lx ", + as->cmnd[0], as->serial_number); + dev_dbg(&h->pdev->dev, "%s\n", msg); + dev_warn(&h->pdev->dev, "Abort request on C%d:B%d:T%d:L%d\n", + h->scsi_host->host_no, dev->bus, dev->target, dev->lun); + + /* Search reqQ to See if command is queued but not submitted, + * if so, complete the command with aborted status and remove + * it from the reqQ. + */ + found = hpsa_find_cmd_in_queue(h, sc, &h->reqQ); + if (found) { + found->err_info->CommandStatus = CMD_ABORTED; + finish_cmd(found); + dev_info(&h->pdev->dev, "%s Request SUCCEEDED (driver queue).\n", + msg); + return SUCCESS; + } + + /* not in reqQ, if also not in cmpQ, must have already completed */ + found = hpsa_find_cmd_in_queue(h, sc, &h->cmpQ); + if (!found) { + dev_dbg(&h->pdev->dev, "%s Request FAILED (not known to driver).\n", + msg); + return SUCCESS; + } + + /* + * Command is in flight, or possibly already completed + * by the firmware (but not to the scsi mid layer) but we can't + * distinguish which. Send the abort down. + */ + rc = hpsa_send_abort_both_ways(h, dev->scsi3addr, abort); + if (rc != 0) { + dev_dbg(&h->pdev->dev, "%s Request FAILED.\n", msg); + dev_warn(&h->pdev->dev, "FAILED abort on device C%d:B%d:T%d:L%d\n", + h->scsi_host->host_no, + dev->bus, dev->target, dev->lun); + return FAILED; + } + dev_info(&h->pdev->dev, "%s REQUEST SUCCEEDED.\n", msg); + + /* If the abort(s) above completed and actually aborted the + * command, then the command to be aborted should already be + * completed. If not, wait around a bit more to see if they + * manage to complete normally. + */ +#define ABORT_COMPLETE_WAIT_SECS 30 + for (i = 0; i < ABORT_COMPLETE_WAIT_SECS * 10; i++) { + found = hpsa_find_cmd_in_queue(h, sc, &h->cmpQ); + if (!found) + return SUCCESS; + msleep(100); + } + dev_warn(&h->pdev->dev, "%s FAILED. Aborted command has not completed after %d seconds.\n", + msg, ABORT_COMPLETE_WAIT_SECS); + return FAILED; +} + + /* * For operations that cannot sleep, a command block is allocated at init, * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track @@ -2346,14 +2659,21 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) int i; union u64bit temp64; dma_addr_t cmd_dma_handle, err_dma_handle; + unsigned long flags; + spin_lock_irqsave(&h->lock, flags); do { i = find_first_zero_bit(h->cmd_pool_bits, h->nr_cmds); - if (i == h->nr_cmds) + if (i == h->nr_cmds) { + spin_unlock_irqrestore(&h->lock, flags); return NULL; + } } while (test_and_set_bit (i & (BITS_PER_LONG - 1), h->cmd_pool_bits + (i / BITS_PER_LONG)) != 0); + h->nr_allocs++; + spin_unlock_irqrestore(&h->lock, flags); + c = h->cmd_pool + i; memset(c, 0, sizeof(*c)); cmd_dma_handle = h->cmd_pool_dhandle @@ -2362,7 +2682,6 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) memset(c->err_info, 0, sizeof(*c->err_info)); err_dma_handle = h->errinfo_pool_dhandle + i * sizeof(*c->err_info); - h->nr_allocs++; c->cmdindex = i; @@ -2418,11 +2737,14 @@ static struct CommandList *cmd_special_alloc(struct ctlr_info *h) static void cmd_free(struct ctlr_info *h, struct CommandList *c) { int i; + unsigned long flags; i = c - h->cmd_pool; + spin_lock_irqsave(&h->lock, flags); clear_bit(i & (BITS_PER_LONG - 1), h->cmd_pool_bits + (i / BITS_PER_LONG)); h->nr_frees++; + spin_unlock_irqrestore(&h->lock, flags); } static void cmd_special_free(struct ctlr_info *h, struct CommandList *c) @@ -2866,6 +3188,7 @@ static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, int cmd_type) { int pci_dir = XFER_NONE; + struct CommandList *a; /* for commands to be aborted */ c->cmd_type = CMD_IOCTL_PEND; c->Header.ReplyQueue = 0; @@ -2949,8 +3272,35 @@ static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, c->Request.CDB[5] = 0x00; c->Request.CDB[6] = 0x00; c->Request.CDB[7] = 0x00; + break; + case HPSA_ABORT_MSG: + a = buff; /* point to command to be aborted */ + dev_dbg(&h->pdev->dev, "Abort Tag:0x%08x:%08x using request Tag:0x%08x:%08x\n", + a->Header.Tag.upper, a->Header.Tag.lower, + c->Header.Tag.upper, c->Header.Tag.lower); + c->Request.CDBLen = 16; + c->Request.Type.Type = TYPE_MSG; + c->Request.Type.Attribute = ATTR_SIMPLE; + c->Request.Type.Direction = XFER_WRITE; + c->Request.Timeout = 0; /* Don't time out */ + c->Request.CDB[0] = HPSA_TASK_MANAGEMENT; + c->Request.CDB[1] = HPSA_TMF_ABORT_TASK; + c->Request.CDB[2] = 0x00; /* reserved */ + c->Request.CDB[3] = 0x00; /* reserved */ + /* Tag to abort goes in CDB[4]-CDB[11] */ + c->Request.CDB[4] = a->Header.Tag.lower & 0xFF; + c->Request.CDB[5] = (a->Header.Tag.lower >> 8) & 0xFF; + c->Request.CDB[6] = (a->Header.Tag.lower >> 16) & 0xFF; + c->Request.CDB[7] = (a->Header.Tag.lower >> 24) & 0xFF; + c->Request.CDB[8] = a->Header.Tag.upper & 0xFF; + c->Request.CDB[9] = (a->Header.Tag.upper >> 8) & 0xFF; + c->Request.CDB[10] = (a->Header.Tag.upper >> 16) & 0xFF; + c->Request.CDB[11] = (a->Header.Tag.upper >> 24) & 0xFF; + c->Request.CDB[12] = 0x00; /* reserved */ + c->Request.CDB[13] = 0x00; /* reserved */ + c->Request.CDB[14] = 0x00; /* reserved */ + c->Request.CDB[15] = 0x00; /* reserved */ break; - default: dev_warn(&h->pdev->dev, "unknown message type %d\n", cmd); @@ -2998,7 +3348,9 @@ static void __iomem *remap_pci_mem(ulong base, ulong size) static void start_io(struct ctlr_info *h) { struct CommandList *c; + unsigned long flags; + spin_lock_irqsave(&h->lock, flags); while (!list_empty(&h->reqQ)) { c = list_entry(h->reqQ.next, struct CommandList, list); /* can't do anything if fifo is full */ @@ -3011,17 +3363,28 @@ static void start_io(struct ctlr_info *h) removeQ(c); h->Qdepth--; - /* Tell the controller execute command */ - h->access.submit_command(h, c); - /* Put job onto the completed Q */ addQ(&h->cmpQ, c); + + /* Must increment commands_outstanding before unlocking + * and submitting to avoid race checking for fifo full + * condition. + */ + h->commands_outstanding++; + if (h->commands_outstanding > h->max_outstanding) + h->max_outstanding = h->commands_outstanding; + + /* Tell the controller execute command */ + spin_unlock_irqrestore(&h->lock, flags); + h->access.submit_command(h, c); + spin_lock_irqsave(&h->lock, flags); } + spin_unlock_irqrestore(&h->lock, flags); } -static inline unsigned long get_next_completion(struct ctlr_info *h) +static inline unsigned long get_next_completion(struct ctlr_info *h, u8 q) { - return h->access.command_completed(h); + return h->access.command_completed(h, q); } static inline bool interrupt_pending(struct ctlr_info *h) @@ -3045,9 +3408,14 @@ static inline int bad_tag(struct ctlr_info *h, u32 tag_index, return 0; } -static inline void finish_cmd(struct CommandList *c, u32 raw_tag) +static inline void finish_cmd(struct CommandList *c) { + unsigned long flags; + + spin_lock_irqsave(&c->h->lock, flags); removeQ(c); + spin_unlock_irqrestore(&c->h->lock, flags); + dial_up_lockup_detection_on_fw_flash_complete(c->h, c); if (likely(c->cmd_type == CMD_SCSI)) complete_scsi_command(c); else if (c->cmd_type == CMD_IOCTL_PEND) @@ -3075,36 +3443,38 @@ static inline u32 hpsa_tag_discard_error_bits(struct ctlr_info *h, u32 tag) } /* process completion of an indexed ("direct lookup") command */ -static inline u32 process_indexed_cmd(struct ctlr_info *h, +static inline void process_indexed_cmd(struct ctlr_info *h, u32 raw_tag) { u32 tag_index; struct CommandList *c; tag_index = hpsa_tag_to_index(raw_tag); - if (bad_tag(h, tag_index, raw_tag)) - return next_command(h); - c = h->cmd_pool + tag_index; - finish_cmd(c, raw_tag); - return next_command(h); + if (!bad_tag(h, tag_index, raw_tag)) { + c = h->cmd_pool + tag_index; + finish_cmd(c); + } } /* process completion of a non-indexed command */ -static inline u32 process_nonindexed_cmd(struct ctlr_info *h, +static inline void process_nonindexed_cmd(struct ctlr_info *h, u32 raw_tag) { u32 tag; struct CommandList *c = NULL; + unsigned long flags; tag = hpsa_tag_discard_error_bits(h, raw_tag); + spin_lock_irqsave(&h->lock, flags); list_for_each_entry(c, &h->cmpQ, list) { if ((c->busaddr & 0xFFFFFFE0) == (tag & 0xFFFFFFE0)) { - finish_cmd(c, raw_tag); - return next_command(h); + spin_unlock_irqrestore(&h->lock, flags); + finish_cmd(c); + return; } } + spin_unlock_irqrestore(&h->lock, flags); bad_tag(h, h->nr_cmds + 1, raw_tag); - return next_command(h); } /* Some controllers, like p400, will give us one interrupt @@ -3126,10 +3496,20 @@ static int ignore_bogus_interrupt(struct ctlr_info *h) return 1; } -static irqreturn_t hpsa_intx_discard_completions(int irq, void *dev_id) +/* + * Convert &h->q[x] (passed to interrupt handlers) back to h. + * Relies on (h-q[x] == x) being true for x such that + * 0 <= x < MAX_REPLY_QUEUES. + */ +static struct ctlr_info *queue_to_hba(u8 *queue) { - struct ctlr_info *h = dev_id; - unsigned long flags; + return container_of((queue - *queue), struct ctlr_info, q[0]); +} + +static irqreturn_t hpsa_intx_discard_completions(int irq, void *queue) +{ + struct ctlr_info *h = queue_to_hba(queue); + u8 q = *(u8 *) queue; u32 raw_tag; if (ignore_bogus_interrupt(h)) @@ -3137,74 +3517,68 @@ static irqreturn_t hpsa_intx_discard_completions(int irq, void *dev_id) if (interrupt_not_for_us(h)) return IRQ_NONE; - spin_lock_irqsave(&h->lock, flags); h->last_intr_timestamp = get_jiffies_64(); while (interrupt_pending(h)) { - raw_tag = get_next_completion(h); + raw_tag = get_next_completion(h, q); while (raw_tag != FIFO_EMPTY) - raw_tag = next_command(h); + raw_tag = next_command(h, q); } - spin_unlock_irqrestore(&h->lock, flags); return IRQ_HANDLED; } -static irqreturn_t hpsa_msix_discard_completions(int irq, void *dev_id) +static irqreturn_t hpsa_msix_discard_completions(int irq, void *queue) { - struct ctlr_info *h = dev_id; - unsigned long flags; + struct ctlr_info *h = queue_to_hba(queue); u32 raw_tag; + u8 q = *(u8 *) queue; if (ignore_bogus_interrupt(h)) return IRQ_NONE; - spin_lock_irqsave(&h->lock, flags); h->last_intr_timestamp = get_jiffies_64(); - raw_tag = get_next_completion(h); + raw_tag = get_next_completion(h, q); while (raw_tag != FIFO_EMPTY) - raw_tag = next_command(h); - spin_unlock_irqrestore(&h->lock, flags); + raw_tag = next_command(h, q); return IRQ_HANDLED; } -static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id) +static irqreturn_t do_hpsa_intr_intx(int irq, void *queue) { - struct ctlr_info *h = dev_id; - unsigned long flags; + struct ctlr_info *h = queue_to_hba((u8 *) queue); u32 raw_tag; + u8 q = *(u8 *) queue; if (interrupt_not_for_us(h)) return IRQ_NONE; - spin_lock_irqsave(&h->lock, flags); h->last_intr_timestamp = get_jiffies_64(); while (interrupt_pending(h)) { - raw_tag = get_next_completion(h); + raw_tag = get_next_completion(h, q); while (raw_tag != FIFO_EMPTY) { - if (hpsa_tag_contains_index(raw_tag)) - raw_tag = process_indexed_cmd(h, raw_tag); + if (likely(hpsa_tag_contains_index(raw_tag))) + process_indexed_cmd(h, raw_tag); else - raw_tag = process_nonindexed_cmd(h, raw_tag); + process_nonindexed_cmd(h, raw_tag); + raw_tag = next_command(h, q); } } - spin_unlock_irqrestore(&h->lock, flags); return IRQ_HANDLED; } -static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id) +static irqreturn_t do_hpsa_intr_msi(int irq, void *queue) { - struct ctlr_info *h = dev_id; - unsigned long flags; + struct ctlr_info *h = queue_to_hba(queue); u32 raw_tag; + u8 q = *(u8 *) queue; - spin_lock_irqsave(&h->lock, flags); h->last_intr_timestamp = get_jiffies_64(); - raw_tag = get_next_completion(h); + raw_tag = get_next_completion(h, q); while (raw_tag != FIFO_EMPTY) { - if (hpsa_tag_contains_index(raw_tag)) - raw_tag = process_indexed_cmd(h, raw_tag); + if (likely(hpsa_tag_contains_index(raw_tag))) + process_indexed_cmd(h, raw_tag); else - raw_tag = process_nonindexed_cmd(h, raw_tag); + process_nonindexed_cmd(h, raw_tag); + raw_tag = next_command(h, q); } - spin_unlock_irqrestore(&h->lock, flags); return IRQ_HANDLED; } @@ -3638,10 +4012,13 @@ static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr) static void __devinit hpsa_interrupt_mode(struct ctlr_info *h) { #ifdef CONFIG_PCI_MSI - int err; - struct msix_entry hpsa_msix_entries[4] = { {0, 0}, {0, 1}, - {0, 2}, {0, 3} - }; + int err, i; + struct msix_entry hpsa_msix_entries[MAX_REPLY_QUEUES]; + + for (i = 0; i < MAX_REPLY_QUEUES; i++) { + hpsa_msix_entries[i].vector = 0; + hpsa_msix_entries[i].entry = i; + } /* Some boards advertise MSI but don't really support it */ if ((h->board_id == 0x40700E11) || (h->board_id == 0x40800E11) || @@ -3649,12 +4026,11 @@ static void __devinit hpsa_interrupt_mode(struct ctlr_info *h) goto default_int_mode; if (pci_find_capability(h->pdev, PCI_CAP_ID_MSIX)) { dev_info(&h->pdev->dev, "MSIX\n"); - err = pci_enable_msix(h->pdev, hpsa_msix_entries, 4); + err = pci_enable_msix(h->pdev, hpsa_msix_entries, + MAX_REPLY_QUEUES); if (!err) { - h->intr[0] = hpsa_msix_entries[0].vector; - h->intr[1] = hpsa_msix_entries[1].vector; - h->intr[2] = hpsa_msix_entries[2].vector; - h->intr[3] = hpsa_msix_entries[3].vector; + for (i = 0; i < MAX_REPLY_QUEUES; i++) + h->intr[i] = hpsa_msix_entries[i].vector; h->msix_vector = 1; return; } @@ -3705,14 +4081,6 @@ static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id) return ARRAY_SIZE(products) - 1; /* generic unknown smart array */ } -static inline bool hpsa_board_disabled(struct pci_dev *pdev) -{ - u16 command; - - (void) pci_read_config_word(pdev, PCI_COMMAND, &command); - return ((command & PCI_COMMAND_MEMORY) == 0); -} - static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev, unsigned long *memory_bar) { @@ -3838,14 +4206,14 @@ static void __devinit hpsa_find_board_params(struct ctlr_info *h) h->maxsgentries = 31; /* default to traditional values */ h->chainsize = 0; } + + /* Find out what task management functions are supported and cache */ + h->TMFSupportFlags = readl(&(h->cfgtable->TMFSupportFlags)); } static inline bool hpsa_CISS_signature_present(struct ctlr_info *h) { - if ((readb(&h->cfgtable->Signature[0]) != 'C') || - (readb(&h->cfgtable->Signature[1]) != 'I') || - (readb(&h->cfgtable->Signature[2]) != 'S') || - (readb(&h->cfgtable->Signature[3]) != 'S')) { + if (!check_signature(h->cfgtable->Signature, "CISS", 4)) { dev_warn(&h->pdev->dev, "not a valid CISS config table\n"); return false; } @@ -3932,11 +4300,6 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h) h->product_name = products[prod_index].product_name; h->access = *(products[prod_index].access); - if (hpsa_board_disabled(h->pdev)) { - dev_warn(&h->pdev->dev, "controller appears to be disabled\n"); - return -ENODEV; - } - pci_disable_link_state(h->pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_CLKPM); @@ -3946,6 +4309,9 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h) return err; } + /* Enable bus mastering (pci_disable_device may disable this) */ + pci_set_master(h->pdev); + err = pci_request_regions(h->pdev, HPSA); if (err) { dev_err(&h->pdev->dev, @@ -3987,10 +4353,7 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h) iounmap(h->cfgtable); if (h->vaddr) iounmap(h->vaddr); - /* - * Deliberately omit pci_disable_device(): it does something nasty to - * Smart Array controllers that pci_enable_device does not undo - */ + pci_disable_device(h->pdev); pci_release_regions(h->pdev); return err; } @@ -4081,14 +4444,33 @@ static int hpsa_request_irq(struct ctlr_info *h, irqreturn_t (*msixhandler)(int, void *), irqreturn_t (*intxhandler)(int, void *)) { - int rc; + int rc, i; - if (h->msix_vector || h->msi_vector) - rc = request_irq(h->intr[h->intr_mode], msixhandler, - 0, h->devname, h); - else - rc = request_irq(h->intr[h->intr_mode], intxhandler, - IRQF_SHARED, h->devname, h); + /* + * initialize h->q[x] = x so that interrupt handlers know which + * queue to process. + */ + for (i = 0; i < MAX_REPLY_QUEUES; i++) + h->q[i] = (u8) i; + + if (h->intr_mode == PERF_MODE_INT && h->msix_vector) { + /* If performant mode and MSI-X, use multiple reply queues */ + for (i = 0; i < MAX_REPLY_QUEUES; i++) + rc = request_irq(h->intr[i], msixhandler, + 0, h->devname, + &h->q[i]); + } else { + /* Use single reply pool */ + if (h->msix_vector || h->msi_vector) { + rc = request_irq(h->intr[h->intr_mode], + msixhandler, 0, h->devname, + &h->q[h->intr_mode]); + } else { + rc = request_irq(h->intr[h->intr_mode], + intxhandler, IRQF_SHARED, h->devname, + &h->q[h->intr_mode]); + } + } if (rc) { dev_err(&h->pdev->dev, "unable to get irq %d for %s\n", h->intr[h->intr_mode], h->devname); @@ -4121,15 +4503,38 @@ static int __devinit hpsa_kdump_soft_reset(struct ctlr_info *h) return 0; } -static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) +static void free_irqs(struct ctlr_info *h) { - free_irq(h->intr[h->intr_mode], h); + int i; + + if (!h->msix_vector || h->intr_mode != PERF_MODE_INT) { + /* Single reply queue, only one irq to free */ + i = h->intr_mode; + free_irq(h->intr[i], &h->q[i]); + return; + } + + for (i = 0; i < MAX_REPLY_QUEUES; i++) + free_irq(h->intr[i], &h->q[i]); +} + +static void hpsa_free_irqs_and_disable_msix(struct ctlr_info *h) +{ + free_irqs(h); #ifdef CONFIG_PCI_MSI - if (h->msix_vector) - pci_disable_msix(h->pdev); - else if (h->msi_vector) - pci_disable_msi(h->pdev); + if (h->msix_vector) { + if (h->pdev->msix_enabled) + pci_disable_msix(h->pdev); + } else if (h->msi_vector) { + if (h->pdev->msi_enabled) + pci_disable_msi(h->pdev); + } #endif /* CONFIG_PCI_MSI */ +} + +static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) +{ + hpsa_free_irqs_and_disable_msix(h); hpsa_free_sg_chain_blocks(h); hpsa_free_cmd_pool(h); kfree(h->blockFetchTable); @@ -4165,7 +4570,7 @@ static void fail_all_cmds_on_list(struct ctlr_info *h, struct list_head *list) while (!list_empty(list)) { c = list_entry(list->next, struct CommandList, list); c->err_info->CommandStatus = CMD_HARDWARE_ERR; - finish_cmd(c, c->Header.Tag.lower); + finish_cmd(c); } } @@ -4188,9 +4593,6 @@ static void controller_lockup_detected(struct ctlr_info *h) spin_unlock_irqrestore(&h->lock, flags); } -#define HEARTBEAT_SAMPLE_INTERVAL (10 * HZ) -#define HEARTBEAT_CHECK_MINIMUM_INTERVAL (HEARTBEAT_SAMPLE_INTERVAL / 2) - static void detect_controller_lockup(struct ctlr_info *h) { u64 now; @@ -4201,7 +4603,7 @@ static void detect_controller_lockup(struct ctlr_info *h) now = get_jiffies_64(); /* If we've received an interrupt recently, we're ok. */ if (time_after64(h->last_intr_timestamp + - (HEARTBEAT_CHECK_MINIMUM_INTERVAL), now)) + (h->heartbeat_sample_interval), now)) return; /* @@ -4210,7 +4612,7 @@ static void detect_controller_lockup(struct ctlr_info *h) * otherwise don't care about signals in this thread. */ if (time_after64(h->last_heartbeat_timestamp + - (HEARTBEAT_CHECK_MINIMUM_INTERVAL), now)) + (h->heartbeat_sample_interval), now)) return; /* If heartbeat has not changed since we last looked, we're not ok. */ @@ -4252,6 +4654,7 @@ static void add_ctlr_to_lockup_detector_list(struct ctlr_info *h) { unsigned long flags; + h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL; spin_lock_irqsave(&lockup_detector_lock, flags); list_add_tail(&h->lockup_list, &hpsa_ctlr_list); spin_unlock_irqrestore(&lockup_detector_lock, flags); @@ -4391,7 +4794,7 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev, spin_lock_irqsave(&h->lock, flags); h->access.set_intr_mask(h, HPSA_INTR_OFF); spin_unlock_irqrestore(&h->lock, flags); - free_irq(h->intr[h->intr_mode], h); + free_irqs(h); rc = hpsa_request_irq(h, hpsa_msix_discard_completions, hpsa_intx_discard_completions); if (rc) { @@ -4441,7 +4844,7 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev, clean4: hpsa_free_sg_chain_blocks(h); hpsa_free_cmd_pool(h); - free_irq(h->intr[h->intr_mode], h); + free_irqs(h); clean2: clean1: kfree(h); @@ -4484,13 +4887,7 @@ static void hpsa_shutdown(struct pci_dev *pdev) */ hpsa_flush_cache(h); h->access.set_intr_mask(h, HPSA_INTR_OFF); - free_irq(h->intr[h->intr_mode], h); -#ifdef CONFIG_PCI_MSI - if (h->msix_vector) - pci_disable_msix(h->pdev); - else if (h->msi_vector) - pci_disable_msi(h->pdev); -#endif /* CONFIG_PCI_MSI */ + hpsa_free_irqs_and_disable_msix(h); } static void __devexit hpsa_free_device_info(struct ctlr_info *h) @@ -4529,10 +4926,7 @@ static void __devexit hpsa_remove_one(struct pci_dev *pdev) kfree(h->cmd_pool_bits); kfree(h->blockFetchTable); kfree(h->hba_inquiry_data); - /* - * Deliberately omit pci_disable_device(): it does something nasty to - * Smart Array controllers that pci_enable_device does not undo - */ + pci_disable_device(pdev); pci_release_regions(pdev); pci_set_drvdata(pdev, NULL); kfree(h); @@ -4627,11 +5021,8 @@ static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h, * 10 = 6 s/g entry or 24k */ - h->reply_pool_wraparound = 1; /* spec: init to 1 */ - /* Controller spec: zero out this buffer. */ memset(h->reply_pool, 0, h->reply_pool_size); - h->reply_pool_head = h->reply_pool; bft[7] = SG_ENTRIES_IN_CMD + 4; calc_bucket_map(bft, ARRAY_SIZE(bft), @@ -4641,12 +5032,19 @@ static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h, /* size of controller ring buffer */ writel(h->max_commands, &h->transtable->RepQSize); - writel(1, &h->transtable->RepQCount); + writel(h->nreply_queues, &h->transtable->RepQCount); writel(0, &h->transtable->RepQCtrAddrLow32); writel(0, &h->transtable->RepQCtrAddrHigh32); - writel(h->reply_pool_dhandle, &h->transtable->RepQAddr0Low32); - writel(0, &h->transtable->RepQAddr0High32); - writel(CFGTBL_Trans_Performant | use_short_tags, + + for (i = 0; i < h->nreply_queues; i++) { + writel(0, &h->transtable->RepQAddr[i].upper); + writel(h->reply_pool_dhandle + + (h->max_commands * sizeof(u64) * i), + &h->transtable->RepQAddr[i].lower); + } + + writel(CFGTBL_Trans_Performant | use_short_tags | + CFGTBL_Trans_enable_directed_msix, &(h->cfgtable->HostWrite.TransportRequest)); writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); hpsa_wait_for_mode_change_ack(h); @@ -4664,6 +5062,7 @@ static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h, static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) { u32 trans_support; + int i; if (hpsa_simple_mode) return; @@ -4672,12 +5071,20 @@ static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) if (!(trans_support & PERFORMANT_MODE)) return; + h->nreply_queues = h->msix_vector ? MAX_REPLY_QUEUES : 1; hpsa_get_max_perf_mode_cmds(h); /* Performant mode ring buffer and supporting data structures */ - h->reply_pool_size = h->max_commands * sizeof(u64); + h->reply_pool_size = h->max_commands * sizeof(u64) * h->nreply_queues; h->reply_pool = pci_alloc_consistent(h->pdev, h->reply_pool_size, &(h->reply_pool_dhandle)); + for (i = 0; i < h->nreply_queues; i++) { + h->reply_queue[i].head = &h->reply_pool[h->max_commands * i]; + h->reply_queue[i].size = h->max_commands; + h->reply_queue[i].wraparound = 1; /* spec: init to 1 */ + h->reply_queue[i].current_entry = 0; + } + /* Need a block fetch table for performant mode */ h->blockFetchTable = kmalloc(((SG_ENTRIES_IN_CMD + 1) * sizeof(u32)), GFP_KERNEL); diff --git a/trunk/drivers/scsi/hpsa.h b/trunk/drivers/scsi/hpsa.h index 7b28d54fa878..981647989bfd 100644 --- a/trunk/drivers/scsi/hpsa.h +++ b/trunk/drivers/scsi/hpsa.h @@ -34,7 +34,7 @@ struct access_method { void (*set_intr_mask)(struct ctlr_info *h, unsigned long val); unsigned long (*fifo_full)(struct ctlr_info *h); bool (*intr_pending)(struct ctlr_info *h); - unsigned long (*command_completed)(struct ctlr_info *h); + unsigned long (*command_completed)(struct ctlr_info *h, u8 q); }; struct hpsa_scsi_dev_t { @@ -48,6 +48,13 @@ struct hpsa_scsi_dev_t { unsigned char raid_level; /* from inquiry page 0xC1 */ }; +struct reply_pool { + u64 *head; + size_t size; + u8 wraparound; + u32 current_entry; +}; + struct ctlr_info { int ctlr; char devname[8]; @@ -68,7 +75,7 @@ struct ctlr_info { # define DOORBELL_INT 1 # define SIMPLE_MODE_INT 2 # define MEMQ_MODE_INT 3 - unsigned int intr[4]; + unsigned int intr[MAX_REPLY_QUEUES]; unsigned int msix_vector; unsigned int msi_vector; int intr_mode; /* either PERF_MODE_INT or SIMPLE_MODE_INT */ @@ -78,7 +85,6 @@ struct ctlr_info { struct list_head reqQ; struct list_head cmpQ; unsigned int Qdepth; - unsigned int maxQsinceinit; unsigned int maxSG; spinlock_t lock; int maxsgentries; @@ -111,20 +117,45 @@ struct ctlr_info { unsigned long transMethod; /* - * Performant mode completion buffer + * Performant mode completion buffers */ u64 *reply_pool; - dma_addr_t reply_pool_dhandle; - u64 *reply_pool_head; size_t reply_pool_size; - unsigned char reply_pool_wraparound; + struct reply_pool reply_queue[MAX_REPLY_QUEUES]; + u8 nreply_queues; + dma_addr_t reply_pool_dhandle; u32 *blockFetchTable; unsigned char *hba_inquiry_data; u64 last_intr_timestamp; u32 last_heartbeat; u64 last_heartbeat_timestamp; + u32 heartbeat_sample_interval; + atomic_t firmware_flash_in_progress; u32 lockup_detected; struct list_head lockup_list; + /* Address of h->q[x] is passed to intr handler to know which queue */ + u8 q[MAX_REPLY_QUEUES]; + u32 TMFSupportFlags; /* cache what task mgmt funcs are supported. */ +#define HPSATMF_BITS_SUPPORTED (1 << 0) +#define HPSATMF_PHYS_LUN_RESET (1 << 1) +#define HPSATMF_PHYS_NEX_RESET (1 << 2) +#define HPSATMF_PHYS_TASK_ABORT (1 << 3) +#define HPSATMF_PHYS_TSET_ABORT (1 << 4) +#define HPSATMF_PHYS_CLEAR_ACA (1 << 5) +#define HPSATMF_PHYS_CLEAR_TSET (1 << 6) +#define HPSATMF_PHYS_QRY_TASK (1 << 7) +#define HPSATMF_PHYS_QRY_TSET (1 << 8) +#define HPSATMF_PHYS_QRY_ASYNC (1 << 9) +#define HPSATMF_MASK_SUPPORTED (1 << 16) +#define HPSATMF_LOG_LUN_RESET (1 << 17) +#define HPSATMF_LOG_NEX_RESET (1 << 18) +#define HPSATMF_LOG_TASK_ABORT (1 << 19) +#define HPSATMF_LOG_TSET_ABORT (1 << 20) +#define HPSATMF_LOG_CLEAR_ACA (1 << 21) +#define HPSATMF_LOG_CLEAR_TSET (1 << 22) +#define HPSATMF_LOG_QRY_TASK (1 << 23) +#define HPSATMF_LOG_QRY_TSET (1 << 24) +#define HPSATMF_LOG_QRY_ASYNC (1 << 25) }; #define HPSA_ABORT_MSG 0 #define HPSA_DEVICE_RESET_MSG 1 @@ -216,9 +247,6 @@ static void SA5_submit_command(struct ctlr_info *h, c->Header.Tag.lower); writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); (void) readl(h->vaddr + SA5_SCRATCHPAD_OFFSET); - h->commands_outstanding++; - if (h->commands_outstanding > h->max_outstanding) - h->max_outstanding = h->commands_outstanding; } /* @@ -254,16 +282,17 @@ static void SA5_performant_intr_mask(struct ctlr_info *h, unsigned long val) } } -static unsigned long SA5_performant_completed(struct ctlr_info *h) +static unsigned long SA5_performant_completed(struct ctlr_info *h, u8 q) { - unsigned long register_value = FIFO_EMPTY; + struct reply_pool *rq = &h->reply_queue[q]; + unsigned long flags, register_value = FIFO_EMPTY; - /* flush the controller write of the reply queue by reading - * outbound doorbell status register. - */ - register_value = readl(h->vaddr + SA5_OUTDB_STATUS); /* msi auto clears the interrupt pending bit. */ if (!(h->msi_vector || h->msix_vector)) { + /* flush the controller write of the reply queue by reading + * outbound doorbell status register. + */ + register_value = readl(h->vaddr + SA5_OUTDB_STATUS); writel(SA5_OUTDB_CLEAR_PERF_BIT, h->vaddr + SA5_OUTDB_CLEAR); /* Do a read in order to flush the write to the controller * (as per spec.) @@ -271,19 +300,20 @@ static unsigned long SA5_performant_completed(struct ctlr_info *h) register_value = readl(h->vaddr + SA5_OUTDB_STATUS); } - if ((*(h->reply_pool_head) & 1) == (h->reply_pool_wraparound)) { - register_value = *(h->reply_pool_head); - (h->reply_pool_head)++; + if ((rq->head[rq->current_entry] & 1) == rq->wraparound) { + register_value = rq->head[rq->current_entry]; + rq->current_entry++; + spin_lock_irqsave(&h->lock, flags); h->commands_outstanding--; + spin_unlock_irqrestore(&h->lock, flags); } else { register_value = FIFO_EMPTY; } /* Check for wraparound */ - if (h->reply_pool_head == (h->reply_pool + h->max_commands)) { - h->reply_pool_head = h->reply_pool; - h->reply_pool_wraparound ^= 1; + if (rq->current_entry == h->max_commands) { + rq->current_entry = 0; + rq->wraparound ^= 1; } - return register_value; } @@ -303,13 +333,18 @@ static unsigned long SA5_fifo_full(struct ctlr_info *h) * returns value read from hardware. * returns FIFO_EMPTY if there is nothing to read */ -static unsigned long SA5_completed(struct ctlr_info *h) +static unsigned long SA5_completed(struct ctlr_info *h, + __attribute__((unused)) u8 q) { unsigned long register_value = readl(h->vaddr + SA5_REPLY_PORT_OFFSET); + unsigned long flags; - if (register_value != FIFO_EMPTY) + if (register_value != FIFO_EMPTY) { + spin_lock_irqsave(&h->lock, flags); h->commands_outstanding--; + spin_unlock_irqrestore(&h->lock, flags); + } #ifdef HPSA_DEBUG if (register_value != FIFO_EMPTY) diff --git a/trunk/drivers/scsi/hpsa_cmd.h b/trunk/drivers/scsi/hpsa_cmd.h index 8049815d8c1e..a894f2eca7ac 100644 --- a/trunk/drivers/scsi/hpsa_cmd.h +++ b/trunk/drivers/scsi/hpsa_cmd.h @@ -82,6 +82,29 @@ #define TYPE_CMD 0x00 #define TYPE_MSG 0x01 +/* Message Types */ +#define HPSA_TASK_MANAGEMENT 0x00 +#define HPSA_RESET 0x01 +#define HPSA_SCAN 0x02 +#define HPSA_NOOP 0x03 + +#define HPSA_CTLR_RESET_TYPE 0x00 +#define HPSA_BUS_RESET_TYPE 0x01 +#define HPSA_TARGET_RESET_TYPE 0x03 +#define HPSA_LUN_RESET_TYPE 0x04 +#define HPSA_NEXUS_RESET_TYPE 0x05 + +/* Task Management Functions */ +#define HPSA_TMF_ABORT_TASK 0x00 +#define HPSA_TMF_ABORT_TASK_SET 0x01 +#define HPSA_TMF_CLEAR_ACA 0x02 +#define HPSA_TMF_CLEAR_TASK_SET 0x03 +#define HPSA_TMF_QUERY_TASK 0x04 +#define HPSA_TMF_QUERY_TASK_SET 0x05 +#define HPSA_TMF_QUERY_ASYNCEVENT 0x06 + + + /* config space register offsets */ #define CFG_VENDORID 0x00 #define CFG_DEVICEID 0x02 @@ -106,6 +129,7 @@ #define CFGTBL_Trans_Simple 0x00000002l #define CFGTBL_Trans_Performant 0x00000004l #define CFGTBL_Trans_use_short_tags 0x20000000l +#define CFGTBL_Trans_enable_directed_msix (1 << 30) #define CFGTBL_BusType_Ultra2 0x00000001l #define CFGTBL_BusType_Ultra3 0x00000002l @@ -162,6 +186,7 @@ struct SenseSubsystem_info { #define BMIC_WRITE 0x27 #define BMIC_CACHE_FLUSH 0xc2 #define HPSA_CACHE_FLUSH 0x01 /* C2 was already being used by HPSA */ +#define BMIC_FLASH_FIRMWARE 0xF7 /* Command List Structure */ union SCSI3Addr { @@ -337,11 +362,17 @@ struct CfgTable { u32 MaxPhysicalDevices; u32 MaxPhysicalDrivesPerLogicalUnit; u32 MaxPerformantModeCommands; - u8 reserved[0x78 - 0x58]; + u32 MaxBlockFetch; + u32 PowerConservationSupport; + u32 PowerConservationEnable; + u32 TMFSupportFlags; + u8 TMFTagMask[8]; + u8 reserved[0x78 - 0x70]; u32 misc_fw_support; /* offset 0x78 */ #define MISC_FW_DOORBELL_RESET (0x02) #define MISC_FW_DOORBELL_RESET2 (0x010) u8 driver_version[32]; + }; #define NUM_BLOCKFETCH_ENTRIES 8 @@ -351,8 +382,8 @@ struct TransTable_struct { u32 RepQCount; u32 RepQCtrAddrLow32; u32 RepQCtrAddrHigh32; - u32 RepQAddr0Low32; - u32 RepQAddr0High32; +#define MAX_REPLY_QUEUES 8 + struct vals32 RepQAddr[MAX_REPLY_QUEUES]; }; struct hpsa_pci_info { diff --git a/trunk/drivers/scsi/isci/host.c b/trunk/drivers/scsi/isci/host.c index d4bf9c12ecd4..45385f531649 100644 --- a/trunk/drivers/scsi/isci/host.c +++ b/trunk/drivers/scsi/isci/host.c @@ -192,22 +192,27 @@ static bool sci_controller_completion_queue_has_entries(struct isci_host *ihost) static bool sci_controller_isr(struct isci_host *ihost) { - if (sci_controller_completion_queue_has_entries(ihost)) { + if (sci_controller_completion_queue_has_entries(ihost)) return true; - } else { - /* - * we have a spurious interrupt it could be that we have already - * emptied the completion queue from a previous interrupt */ - writel(SMU_ISR_COMPLETION, &ihost->smu_registers->interrupt_status); - /* - * There is a race in the hardware that could cause us not to be notified - * of an interrupt completion if we do not take this step. We will mask - * then unmask the interrupts so if there is another interrupt pending - * the clearing of the interrupt source we get the next interrupt message. */ + /* we have a spurious interrupt it could be that we have already + * emptied the completion queue from a previous interrupt + * FIXME: really!? + */ + writel(SMU_ISR_COMPLETION, &ihost->smu_registers->interrupt_status); + + /* There is a race in the hardware that could cause us not to be + * notified of an interrupt completion if we do not take this + * step. We will mask then unmask the interrupts so if there is + * another interrupt pending the clearing of the interrupt + * source we get the next interrupt message. + */ + spin_lock(&ihost->scic_lock); + if (test_bit(IHOST_IRQ_ENABLED, &ihost->flags)) { writel(0xFF000000, &ihost->smu_registers->interrupt_mask); writel(0, &ihost->smu_registers->interrupt_mask); } + spin_unlock(&ihost->scic_lock); return false; } @@ -642,7 +647,6 @@ static void isci_host_start_complete(struct isci_host *ihost, enum sci_status co if (completion_status != SCI_SUCCESS) dev_info(&ihost->pdev->dev, "controller start timed out, continuing...\n"); - isci_host_change_state(ihost, isci_ready); clear_bit(IHOST_START_PENDING, &ihost->flags); wake_up(&ihost->eventq); } @@ -657,12 +661,7 @@ int isci_host_scan_finished(struct Scsi_Host *shost, unsigned long time) sas_drain_work(ha); - dev_dbg(&ihost->pdev->dev, - "%s: ihost->status = %d, time = %ld\n", - __func__, isci_host_get_state(ihost), time); - return 1; - } /** @@ -704,14 +703,15 @@ static u32 sci_controller_get_suggested_start_timeout(struct isci_host *ihost) static void sci_controller_enable_interrupts(struct isci_host *ihost) { - BUG_ON(ihost->smu_registers == NULL); + set_bit(IHOST_IRQ_ENABLED, &ihost->flags); writel(0, &ihost->smu_registers->interrupt_mask); } void sci_controller_disable_interrupts(struct isci_host *ihost) { - BUG_ON(ihost->smu_registers == NULL); + clear_bit(IHOST_IRQ_ENABLED, &ihost->flags); writel(0xffffffff, &ihost->smu_registers->interrupt_mask); + readl(&ihost->smu_registers->interrupt_mask); /* flush */ } static void sci_controller_enable_port_task_scheduler(struct isci_host *ihost) @@ -822,7 +822,7 @@ static void sci_controller_initialize_unsolicited_frame_queue(struct isci_host * &ihost->scu_registers->sdma.unsolicited_frame_put_pointer); } -static void sci_controller_transition_to_ready(struct isci_host *ihost, enum sci_status status) +void sci_controller_transition_to_ready(struct isci_host *ihost, enum sci_status status) { if (ihost->sm.current_state_id == SCIC_STARTING) { /* @@ -849,6 +849,7 @@ static bool is_phy_starting(struct isci_phy *iphy) case SCI_PHY_SUB_AWAIT_SATA_POWER: case SCI_PHY_SUB_AWAIT_SATA_PHY_EN: case SCI_PHY_SUB_AWAIT_SATA_SPEED_EN: + case SCI_PHY_SUB_AWAIT_OSSP_EN: case SCI_PHY_SUB_AWAIT_SIG_FIS_UF: case SCI_PHY_SUB_FINAL: return true; @@ -857,6 +858,39 @@ static bool is_phy_starting(struct isci_phy *iphy) } } +bool is_controller_start_complete(struct isci_host *ihost) +{ + int i; + + for (i = 0; i < SCI_MAX_PHYS; i++) { + struct isci_phy *iphy = &ihost->phys[i]; + u32 state = iphy->sm.current_state_id; + + /* in apc mode we need to check every phy, in + * mpc mode we only need to check phys that have + * been configured into a port + */ + if (is_port_config_apc(ihost)) + /* pass */; + else if (!phy_get_non_dummy_port(iphy)) + continue; + + /* The controller start operation is complete iff: + * - all links have been given an opportunity to start + * - have no indication of a connected device + * - have an indication of a connected device and it has + * finished the link training process. + */ + if ((iphy->is_in_link_training == false && state == SCI_PHY_INITIAL) || + (iphy->is_in_link_training == false && state == SCI_PHY_STOPPED) || + (iphy->is_in_link_training == true && is_phy_starting(iphy)) || + (ihost->port_agent.phy_ready_mask != ihost->port_agent.phy_configured_mask)) + return false; + } + + return true; +} + /** * sci_controller_start_next_phy - start phy * @scic: controller @@ -877,36 +911,7 @@ static enum sci_status sci_controller_start_next_phy(struct isci_host *ihost) return status; if (ihost->next_phy_to_start >= SCI_MAX_PHYS) { - bool is_controller_start_complete = true; - u32 state; - u8 index; - - for (index = 0; index < SCI_MAX_PHYS; index++) { - iphy = &ihost->phys[index]; - state = iphy->sm.current_state_id; - - if (!phy_get_non_dummy_port(iphy)) - continue; - - /* The controller start operation is complete iff: - * - all links have been given an opportunity to start - * - have no indication of a connected device - * - have an indication of a connected device and it has - * finished the link training process. - */ - if ((iphy->is_in_link_training == false && state == SCI_PHY_INITIAL) || - (iphy->is_in_link_training == false && state == SCI_PHY_STOPPED) || - (iphy->is_in_link_training == true && is_phy_starting(iphy)) || - (ihost->port_agent.phy_ready_mask != ihost->port_agent.phy_configured_mask)) { - is_controller_start_complete = false; - break; - } - } - - /* - * The controller has successfully finished the start process. - * Inform the SCI Core user and transition to the READY state. */ - if (is_controller_start_complete == true) { + if (is_controller_start_complete(ihost)) { sci_controller_transition_to_ready(ihost, SCI_SUCCESS); sci_del_timer(&ihost->phy_timer); ihost->phy_startup_timer_pending = false; @@ -987,9 +992,8 @@ static enum sci_status sci_controller_start(struct isci_host *ihost, u16 index; if (ihost->sm.current_state_id != SCIC_INITIALIZED) { - dev_warn(&ihost->pdev->dev, - "SCIC Controller start operation requested in " - "invalid state\n"); + dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n", + __func__, ihost->sm.current_state_id); return SCI_FAILURE_INVALID_STATE; } @@ -1053,9 +1057,8 @@ void isci_host_scan_start(struct Scsi_Host *shost) spin_unlock_irq(&ihost->scic_lock); } -static void isci_host_stop_complete(struct isci_host *ihost, enum sci_status completion_status) +static void isci_host_stop_complete(struct isci_host *ihost) { - isci_host_change_state(ihost, isci_stopped); sci_controller_disable_interrupts(ihost); clear_bit(IHOST_STOP_PENDING, &ihost->flags); wake_up(&ihost->eventq); @@ -1074,6 +1077,32 @@ static void sci_controller_completion_handler(struct isci_host *ihost) writel(0, &ihost->smu_registers->interrupt_mask); } +void ireq_done(struct isci_host *ihost, struct isci_request *ireq, struct sas_task *task) +{ + task->lldd_task = NULL; + if (!test_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags) && + !(task->task_state_flags & SAS_TASK_STATE_ABORTED)) { + if (test_bit(IREQ_COMPLETE_IN_TARGET, &ireq->flags)) { + /* Normal notification (task_done) */ + dev_dbg(&ihost->pdev->dev, + "%s: Normal - ireq/task = %p/%p\n", + __func__, ireq, task); + + task->task_done(task); + } else { + dev_dbg(&ihost->pdev->dev, + "%s: Error - ireq/task = %p/%p\n", + __func__, ireq, task); + + sas_task_abort(task); + } + } + if (test_and_clear_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags)) + wake_up_all(&ihost->eventq); + + if (!test_bit(IREQ_NO_AUTO_FREE_TAG, &ireq->flags)) + isci_free_tag(ihost, ireq->io_tag); +} /** * isci_host_completion_routine() - This function is the delayed service * routine that calls the sci core library's completion handler. It's @@ -1082,107 +1111,15 @@ static void sci_controller_completion_handler(struct isci_host *ihost) * @data: This parameter specifies the ISCI host object * */ -static void isci_host_completion_routine(unsigned long data) +void isci_host_completion_routine(unsigned long data) { struct isci_host *ihost = (struct isci_host *)data; - struct list_head completed_request_list; - struct list_head errored_request_list; - struct list_head *current_position; - struct list_head *next_position; - struct isci_request *request; - struct isci_request *next_request; - struct sas_task *task; u16 active; - INIT_LIST_HEAD(&completed_request_list); - INIT_LIST_HEAD(&errored_request_list); - spin_lock_irq(&ihost->scic_lock); - sci_controller_completion_handler(ihost); - - /* Take the lists of completed I/Os from the host. */ - - list_splice_init(&ihost->requests_to_complete, - &completed_request_list); - - /* Take the list of errored I/Os from the host. */ - list_splice_init(&ihost->requests_to_errorback, - &errored_request_list); - spin_unlock_irq(&ihost->scic_lock); - /* Process any completions in the lists. */ - list_for_each_safe(current_position, next_position, - &completed_request_list) { - - request = list_entry(current_position, struct isci_request, - completed_node); - task = isci_request_access_task(request); - - /* Normal notification (task_done) */ - dev_dbg(&ihost->pdev->dev, - "%s: Normal - request/task = %p/%p\n", - __func__, - request, - task); - - /* Return the task to libsas */ - if (task != NULL) { - - task->lldd_task = NULL; - if (!(task->task_state_flags & SAS_TASK_STATE_ABORTED)) { - - /* If the task is already in the abort path, - * the task_done callback cannot be called. - */ - task->task_done(task); - } - } - - spin_lock_irq(&ihost->scic_lock); - isci_free_tag(ihost, request->io_tag); - spin_unlock_irq(&ihost->scic_lock); - } - list_for_each_entry_safe(request, next_request, &errored_request_list, - completed_node) { - - task = isci_request_access_task(request); - - /* Use sas_task_abort */ - dev_warn(&ihost->pdev->dev, - "%s: Error - request/task = %p/%p\n", - __func__, - request, - task); - - if (task != NULL) { - - /* Put the task into the abort path if it's not there - * already. - */ - if (!(task->task_state_flags & SAS_TASK_STATE_ABORTED)) - sas_task_abort(task); - - } else { - /* This is a case where the request has completed with a - * status such that it needed further target servicing, - * but the sas_task reference has already been removed - * from the request. Since it was errored, it was not - * being aborted, so there is nothing to do except free - * it. - */ - - spin_lock_irq(&ihost->scic_lock); - /* Remove the request from the remote device's list - * of pending requests. - */ - list_del_init(&request->dev_node); - isci_free_tag(ihost, request->io_tag); - spin_unlock_irq(&ihost->scic_lock); - } - } - /* the coalesence timeout doubles at each encoding step, so * update it based on the ilog2 value of the outstanding requests */ @@ -1213,9 +1150,8 @@ static void isci_host_completion_routine(unsigned long data) static enum sci_status sci_controller_stop(struct isci_host *ihost, u32 timeout) { if (ihost->sm.current_state_id != SCIC_READY) { - dev_warn(&ihost->pdev->dev, - "SCIC Controller stop operation requested in " - "invalid state\n"); + dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n", + __func__, ihost->sm.current_state_id); return SCI_FAILURE_INVALID_STATE; } @@ -1241,7 +1177,7 @@ static enum sci_status sci_controller_reset(struct isci_host *ihost) switch (ihost->sm.current_state_id) { case SCIC_RESET: case SCIC_READY: - case SCIC_STOPPED: + case SCIC_STOPPING: case SCIC_FAILED: /* * The reset operation is not a graceful cleanup, just @@ -1250,13 +1186,50 @@ static enum sci_status sci_controller_reset(struct isci_host *ihost) sci_change_state(&ihost->sm, SCIC_RESETTING); return SCI_SUCCESS; default: - dev_warn(&ihost->pdev->dev, - "SCIC Controller reset operation requested in " - "invalid state\n"); + dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n", + __func__, ihost->sm.current_state_id); return SCI_FAILURE_INVALID_STATE; } } +static enum sci_status sci_controller_stop_phys(struct isci_host *ihost) +{ + u32 index; + enum sci_status status; + enum sci_status phy_status; + + status = SCI_SUCCESS; + + for (index = 0; index < SCI_MAX_PHYS; index++) { + phy_status = sci_phy_stop(&ihost->phys[index]); + + if (phy_status != SCI_SUCCESS && + phy_status != SCI_FAILURE_INVALID_STATE) { + status = SCI_FAILURE; + + dev_warn(&ihost->pdev->dev, + "%s: Controller stop operation failed to stop " + "phy %d because of status %d.\n", + __func__, + ihost->phys[index].phy_index, phy_status); + } + } + + return status; +} + + +/** + * isci_host_deinit - shutdown frame reception and dma + * @ihost: host to take down + * + * This is called in either the driver shutdown or the suspend path. In + * the shutdown case libsas went through port teardown and normal device + * removal (i.e. physical links stayed up to service scsi_device removal + * commands). In the suspend case we disable the hardware without + * notifying libsas of the link down events since we want libsas to + * remember the domain across the suspend/resume cycle + */ void isci_host_deinit(struct isci_host *ihost) { int i; @@ -1265,17 +1238,6 @@ void isci_host_deinit(struct isci_host *ihost) for (i = 0; i < isci_gpio_count(ihost); i++) writel(SGPIO_HW_CONTROL, &ihost->scu_registers->peg0.sgpio.output_data_select[i]); - isci_host_change_state(ihost, isci_stopping); - for (i = 0; i < SCI_MAX_PORTS; i++) { - struct isci_port *iport = &ihost->ports[i]; - struct isci_remote_device *idev, *d; - - list_for_each_entry_safe(idev, d, &iport->remote_dev_list, node) { - if (test_bit(IDEV_ALLOCATED, &idev->flags)) - isci_remote_device_stop(ihost, idev); - } - } - set_bit(IHOST_STOP_PENDING, &ihost->flags); spin_lock_irq(&ihost->scic_lock); @@ -1284,12 +1246,21 @@ void isci_host_deinit(struct isci_host *ihost) wait_for_stop(ihost); + /* phy stop is after controller stop to allow port and device to + * go idle before shutting down the phys, but the expectation is + * that i/o has been shut off well before we reach this + * function. + */ + sci_controller_stop_phys(ihost); + /* disable sgpio: where the above wait should give time for the * enclosure to sample the gpios going inactive */ writel(0, &ihost->scu_registers->peg0.sgpio.interface_control); + spin_lock_irq(&ihost->scic_lock); sci_controller_reset(ihost); + spin_unlock_irq(&ihost->scic_lock); /* Cancel any/all outstanding port timers */ for (i = 0; i < ihost->logical_port_entries; i++) { @@ -1328,29 +1299,6 @@ static void __iomem *smu_base(struct isci_host *isci_host) return pcim_iomap_table(pdev)[SCI_SMU_BAR * 2] + SCI_SMU_BAR_SIZE * id; } -static void isci_user_parameters_get(struct sci_user_parameters *u) -{ - int i; - - for (i = 0; i < SCI_MAX_PHYS; i++) { - struct sci_phy_user_params *u_phy = &u->phys[i]; - - u_phy->max_speed_generation = phy_gen; - - /* we are not exporting these for now */ - u_phy->align_insertion_frequency = 0x7f; - u_phy->in_connection_align_insertion_frequency = 0xff; - u_phy->notify_enable_spin_up_insertion_frequency = 0x33; - } - - u->stp_inactivity_timeout = stp_inactive_to; - u->ssp_inactivity_timeout = ssp_inactive_to; - u->stp_max_occupancy_timeout = stp_max_occ_to; - u->ssp_max_occupancy_timeout = ssp_max_occ_to; - u->no_outbound_task_timeout = no_outbound_task_to; - u->max_concurr_spinup = max_concurr_spinup; -} - static void sci_controller_initial_state_enter(struct sci_base_state_machine *sm) { struct isci_host *ihost = container_of(sm, typeof(*ihost), sm); @@ -1510,32 +1458,6 @@ static void sci_controller_ready_state_exit(struct sci_base_state_machine *sm) sci_controller_set_interrupt_coalescence(ihost, 0, 0); } -static enum sci_status sci_controller_stop_phys(struct isci_host *ihost) -{ - u32 index; - enum sci_status status; - enum sci_status phy_status; - - status = SCI_SUCCESS; - - for (index = 0; index < SCI_MAX_PHYS; index++) { - phy_status = sci_phy_stop(&ihost->phys[index]); - - if (phy_status != SCI_SUCCESS && - phy_status != SCI_FAILURE_INVALID_STATE) { - status = SCI_FAILURE; - - dev_warn(&ihost->pdev->dev, - "%s: Controller stop operation failed to stop " - "phy %d because of status %d.\n", - __func__, - ihost->phys[index].phy_index, phy_status); - } - } - - return status; -} - static enum sci_status sci_controller_stop_ports(struct isci_host *ihost) { u32 index; @@ -1595,10 +1517,11 @@ static void sci_controller_stopping_state_enter(struct sci_base_state_machine *s { struct isci_host *ihost = container_of(sm, typeof(*ihost), sm); - /* Stop all of the components for this controller */ - sci_controller_stop_phys(ihost); - sci_controller_stop_ports(ihost); sci_controller_stop_devices(ihost); + sci_controller_stop_ports(ihost); + + if (!sci_controller_has_remote_devices_stopping(ihost)) + isci_host_stop_complete(ihost); } static void sci_controller_stopping_state_exit(struct sci_base_state_machine *sm) @@ -1624,6 +1547,9 @@ static void sci_controller_reset_hardware(struct isci_host *ihost) /* The write to the UFQGP clears the UFQPR */ writel(0, &ihost->scu_registers->sdma.unsolicited_frame_get_pointer); + + /* clear all interrupts */ + writel(~SMU_INTERRUPT_STATUS_RESERVED_MASK, &ihost->smu_registers->interrupt_status); } static void sci_controller_resetting_state_enter(struct sci_base_state_machine *sm) @@ -1655,59 +1581,9 @@ static const struct sci_base_state sci_controller_state_table[] = { .enter_state = sci_controller_stopping_state_enter, .exit_state = sci_controller_stopping_state_exit, }, - [SCIC_STOPPED] = {}, [SCIC_FAILED] = {} }; -static void sci_controller_set_default_config_parameters(struct isci_host *ihost) -{ - /* these defaults are overridden by the platform / firmware */ - u16 index; - - /* Default to APC mode. */ - ihost->oem_parameters.controller.mode_type = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE; - - /* Default to APC mode. */ - ihost->oem_parameters.controller.max_concurr_spin_up = 1; - - /* Default to no SSC operation. */ - ihost->oem_parameters.controller.do_enable_ssc = false; - - /* Default to short cables on all phys. */ - ihost->oem_parameters.controller.cable_selection_mask = 0; - - /* Initialize all of the port parameter information to narrow ports. */ - for (index = 0; index < SCI_MAX_PORTS; index++) { - ihost->oem_parameters.ports[index].phy_mask = 0; - } - - /* Initialize all of the phy parameter information. */ - for (index = 0; index < SCI_MAX_PHYS; index++) { - /* Default to 3G (i.e. Gen 2). */ - ihost->user_parameters.phys[index].max_speed_generation = - SCIC_SDS_PARM_GEN2_SPEED; - - /* the frequencies cannot be 0 */ - ihost->user_parameters.phys[index].align_insertion_frequency = 0x7f; - ihost->user_parameters.phys[index].in_connection_align_insertion_frequency = 0xff; - ihost->user_parameters.phys[index].notify_enable_spin_up_insertion_frequency = 0x33; - - /* - * Previous Vitesse based expanders had a arbitration issue that - * is worked around by having the upper 32-bits of SAS address - * with a value greater then the Vitesse company identifier. - * Hence, usage of 0x5FCFFFFF. */ - ihost->oem_parameters.phys[index].sas_address.low = 0x1 + ihost->id; - ihost->oem_parameters.phys[index].sas_address.high = 0x5FCFFFFF; - } - - ihost->user_parameters.stp_inactivity_timeout = 5; - ihost->user_parameters.ssp_inactivity_timeout = 5; - ihost->user_parameters.stp_max_occupancy_timeout = 5; - ihost->user_parameters.ssp_max_occupancy_timeout = 20; - ihost->user_parameters.no_outbound_task_timeout = 2; -} - static void controller_timeout(unsigned long data) { struct sci_timer *tmr = (struct sci_timer *)data; @@ -1724,7 +1600,7 @@ static void controller_timeout(unsigned long data) sci_controller_transition_to_ready(ihost, SCI_FAILURE_TIMEOUT); else if (sm->current_state_id == SCIC_STOPPING) { sci_change_state(sm, SCIC_FAILED); - isci_host_stop_complete(ihost, SCI_FAILURE_TIMEOUT); + isci_host_stop_complete(ihost); } else /* / @todo Now what do we want to do in this case? */ dev_err(&ihost->pdev->dev, "%s: Controller timer fired when controller was not " @@ -1764,9 +1640,6 @@ static enum sci_status sci_controller_construct(struct isci_host *ihost, sci_init_timer(&ihost->timer, controller_timeout); - /* Initialize the User and OEM parameters to default values. */ - sci_controller_set_default_config_parameters(ihost); - return sci_controller_reset(ihost); } @@ -1846,27 +1719,6 @@ int sci_oem_parameters_validate(struct sci_oem_params *oem, u8 version) return 0; } -static enum sci_status sci_oem_parameters_set(struct isci_host *ihost) -{ - u32 state = ihost->sm.current_state_id; - struct isci_pci_info *pci_info = to_pci_info(ihost->pdev); - - if (state == SCIC_RESET || - state == SCIC_INITIALIZING || - state == SCIC_INITIALIZED) { - u8 oem_version = pci_info->orom ? pci_info->orom->hdr.version : - ISCI_ROM_VER_1_0; - - if (sci_oem_parameters_validate(&ihost->oem_parameters, - oem_version)) - return SCI_FAILURE_INVALID_PARAMETER_VALUE; - - return SCI_SUCCESS; - } - - return SCI_FAILURE_INVALID_STATE; -} - static u8 max_spin_up(struct isci_host *ihost) { if (ihost->user_parameters.max_concurr_spinup) @@ -1914,7 +1766,7 @@ static void power_control_timeout(unsigned long data) ihost->power_control.phys_granted_power++; sci_phy_consume_power_handler(iphy); - if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS) { + if (iphy->protocol == SAS_PROTOCOL_SSP) { u8 j; for (j = 0; j < SCI_MAX_PHYS; j++) { @@ -1988,7 +1840,7 @@ void sci_controller_power_control_queue_insert(struct isci_host *ihost, sizeof(current_phy->frame_rcvd.iaf.sas_addr)); if (current_phy->sm.current_state_id == SCI_PHY_READY && - current_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS && + current_phy->protocol == SAS_PROTOCOL_SSP && other == 0) { sci_phy_consume_power_handler(iphy); break; @@ -2279,9 +2131,8 @@ static enum sci_status sci_controller_initialize(struct isci_host *ihost) unsigned long i, state, val; if (ihost->sm.current_state_id != SCIC_RESET) { - dev_warn(&ihost->pdev->dev, - "SCIC Controller initialize operation requested " - "in invalid state\n"); + dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n", + __func__, ihost->sm.current_state_id); return SCI_FAILURE_INVALID_STATE; } @@ -2384,96 +2235,76 @@ static enum sci_status sci_controller_initialize(struct isci_host *ihost) return result; } -static enum sci_status sci_user_parameters_set(struct isci_host *ihost, - struct sci_user_parameters *sci_parms) -{ - u32 state = ihost->sm.current_state_id; - - if (state == SCIC_RESET || - state == SCIC_INITIALIZING || - state == SCIC_INITIALIZED) { - u16 index; - - /* - * Validate the user parameters. If they are not legal, then - * return a failure. - */ - for (index = 0; index < SCI_MAX_PHYS; index++) { - struct sci_phy_user_params *user_phy; - - user_phy = &sci_parms->phys[index]; - - if (!((user_phy->max_speed_generation <= - SCIC_SDS_PARM_MAX_SPEED) && - (user_phy->max_speed_generation > - SCIC_SDS_PARM_NO_SPEED))) - return SCI_FAILURE_INVALID_PARAMETER_VALUE; - - if (user_phy->in_connection_align_insertion_frequency < - 3) - return SCI_FAILURE_INVALID_PARAMETER_VALUE; - - if ((user_phy->in_connection_align_insertion_frequency < - 3) || - (user_phy->align_insertion_frequency == 0) || - (user_phy-> - notify_enable_spin_up_insertion_frequency == - 0)) - return SCI_FAILURE_INVALID_PARAMETER_VALUE; - } - - if ((sci_parms->stp_inactivity_timeout == 0) || - (sci_parms->ssp_inactivity_timeout == 0) || - (sci_parms->stp_max_occupancy_timeout == 0) || - (sci_parms->ssp_max_occupancy_timeout == 0) || - (sci_parms->no_outbound_task_timeout == 0)) - return SCI_FAILURE_INVALID_PARAMETER_VALUE; - - memcpy(&ihost->user_parameters, sci_parms, sizeof(*sci_parms)); - - return SCI_SUCCESS; - } - - return SCI_FAILURE_INVALID_STATE; -} - -static int sci_controller_mem_init(struct isci_host *ihost) +static int sci_controller_dma_alloc(struct isci_host *ihost) { struct device *dev = &ihost->pdev->dev; - dma_addr_t dma; size_t size; - int err; + int i; + + /* detect re-initialization */ + if (ihost->completion_queue) + return 0; size = SCU_MAX_COMPLETION_QUEUE_ENTRIES * sizeof(u32); - ihost->completion_queue = dmam_alloc_coherent(dev, size, &dma, GFP_KERNEL); + ihost->completion_queue = dmam_alloc_coherent(dev, size, &ihost->cq_dma, + GFP_KERNEL); if (!ihost->completion_queue) return -ENOMEM; - writel(lower_32_bits(dma), &ihost->smu_registers->completion_queue_lower); - writel(upper_32_bits(dma), &ihost->smu_registers->completion_queue_upper); - size = ihost->remote_node_entries * sizeof(union scu_remote_node_context); - ihost->remote_node_context_table = dmam_alloc_coherent(dev, size, &dma, + ihost->remote_node_context_table = dmam_alloc_coherent(dev, size, &ihost->rnc_dma, GFP_KERNEL); + if (!ihost->remote_node_context_table) return -ENOMEM; - writel(lower_32_bits(dma), &ihost->smu_registers->remote_node_context_lower); - writel(upper_32_bits(dma), &ihost->smu_registers->remote_node_context_upper); - size = ihost->task_context_entries * sizeof(struct scu_task_context), - ihost->task_context_table = dmam_alloc_coherent(dev, size, &dma, GFP_KERNEL); + ihost->task_context_table = dmam_alloc_coherent(dev, size, &ihost->tc_dma, + GFP_KERNEL); if (!ihost->task_context_table) return -ENOMEM; - ihost->task_context_dma = dma; - writel(lower_32_bits(dma), &ihost->smu_registers->host_task_table_lower); - writel(upper_32_bits(dma), &ihost->smu_registers->host_task_table_upper); + size = SCI_UFI_TOTAL_SIZE; + ihost->ufi_buf = dmam_alloc_coherent(dev, size, &ihost->ufi_dma, GFP_KERNEL); + if (!ihost->ufi_buf) + return -ENOMEM; + + for (i = 0; i < SCI_MAX_IO_REQUESTS; i++) { + struct isci_request *ireq; + dma_addr_t dma; + + ireq = dmam_alloc_coherent(dev, sizeof(*ireq), &dma, GFP_KERNEL); + if (!ireq) + return -ENOMEM; + + ireq->tc = &ihost->task_context_table[i]; + ireq->owning_controller = ihost; + ireq->request_daddr = dma; + ireq->isci_host = ihost; + ihost->reqs[i] = ireq; + } + + return 0; +} + +static int sci_controller_mem_init(struct isci_host *ihost) +{ + int err = sci_controller_dma_alloc(ihost); - err = sci_unsolicited_frame_control_construct(ihost); if (err) return err; + writel(lower_32_bits(ihost->cq_dma), &ihost->smu_registers->completion_queue_lower); + writel(upper_32_bits(ihost->cq_dma), &ihost->smu_registers->completion_queue_upper); + + writel(lower_32_bits(ihost->rnc_dma), &ihost->smu_registers->remote_node_context_lower); + writel(upper_32_bits(ihost->rnc_dma), &ihost->smu_registers->remote_node_context_upper); + + writel(lower_32_bits(ihost->tc_dma), &ihost->smu_registers->host_task_table_lower); + writel(upper_32_bits(ihost->tc_dma), &ihost->smu_registers->host_task_table_upper); + + sci_unsolicited_frame_control_construct(ihost); + /* * Inform the silicon as to the location of the UF headers and * address table. @@ -2491,22 +2322,22 @@ static int sci_controller_mem_init(struct isci_host *ihost) return 0; } +/** + * isci_host_init - (re-)initialize hardware and internal (private) state + * @ihost: host to init + * + * Any public facing objects (like asd_sas_port, and asd_sas_phys), or + * one-time initialization objects like locks and waitqueues, are + * not touched (they are initialized in isci_host_alloc) + */ int isci_host_init(struct isci_host *ihost) { - int err = 0, i; + int i, err; enum sci_status status; - struct sci_user_parameters sci_user_params; - struct isci_pci_info *pci_info = to_pci_info(ihost->pdev); - - spin_lock_init(&ihost->state_lock); - spin_lock_init(&ihost->scic_lock); - init_waitqueue_head(&ihost->eventq); - - isci_host_change_state(ihost, isci_starting); - - status = sci_controller_construct(ihost, scu_base(ihost), - smu_base(ihost)); + spin_lock_irq(&ihost->scic_lock); + status = sci_controller_construct(ihost, scu_base(ihost), smu_base(ihost)); + spin_unlock_irq(&ihost->scic_lock); if (status != SCI_SUCCESS) { dev_err(&ihost->pdev->dev, "%s: sci_controller_construct failed - status = %x\n", @@ -2515,48 +2346,6 @@ int isci_host_init(struct isci_host *ihost) return -ENODEV; } - ihost->sas_ha.dev = &ihost->pdev->dev; - ihost->sas_ha.lldd_ha = ihost; - - /* - * grab initial values stored in the controller object for OEM and USER - * parameters - */ - isci_user_parameters_get(&sci_user_params); - status = sci_user_parameters_set(ihost, &sci_user_params); - if (status != SCI_SUCCESS) { - dev_warn(&ihost->pdev->dev, - "%s: sci_user_parameters_set failed\n", - __func__); - return -ENODEV; - } - - /* grab any OEM parameters specified in orom */ - if (pci_info->orom) { - status = isci_parse_oem_parameters(&ihost->oem_parameters, - pci_info->orom, - ihost->id); - if (status != SCI_SUCCESS) { - dev_warn(&ihost->pdev->dev, - "parsing firmware oem parameters failed\n"); - return -EINVAL; - } - } - - status = sci_oem_parameters_set(ihost); - if (status != SCI_SUCCESS) { - dev_warn(&ihost->pdev->dev, - "%s: sci_oem_parameters_set failed\n", - __func__); - return -ENODEV; - } - - tasklet_init(&ihost->completion_tasklet, - isci_host_completion_routine, (unsigned long)ihost); - - INIT_LIST_HEAD(&ihost->requests_to_complete); - INIT_LIST_HEAD(&ihost->requests_to_errorback); - spin_lock_irq(&ihost->scic_lock); status = sci_controller_initialize(ihost); spin_unlock_irq(&ihost->scic_lock); @@ -2572,43 +2361,12 @@ int isci_host_init(struct isci_host *ihost) if (err) return err; - for (i = 0; i < SCI_MAX_PORTS; i++) - isci_port_init(&ihost->ports[i], ihost, i); - - for (i = 0; i < SCI_MAX_PHYS; i++) - isci_phy_init(&ihost->phys[i], ihost, i); - /* enable sgpio */ writel(1, &ihost->scu_registers->peg0.sgpio.interface_control); for (i = 0; i < isci_gpio_count(ihost); i++) writel(SGPIO_HW_CONTROL, &ihost->scu_registers->peg0.sgpio.output_data_select[i]); writel(0, &ihost->scu_registers->peg0.sgpio.vendor_specific_code); - for (i = 0; i < SCI_MAX_REMOTE_DEVICES; i++) { - struct isci_remote_device *idev = &ihost->devices[i]; - - INIT_LIST_HEAD(&idev->reqs_in_process); - INIT_LIST_HEAD(&idev->node); - } - - for (i = 0; i < SCI_MAX_IO_REQUESTS; i++) { - struct isci_request *ireq; - dma_addr_t dma; - - ireq = dmam_alloc_coherent(&ihost->pdev->dev, - sizeof(struct isci_request), &dma, - GFP_KERNEL); - if (!ireq) - return -ENOMEM; - - ireq->tc = &ihost->task_context_table[i]; - ireq->owning_controller = ihost; - spin_lock_init(&ireq->state_lock); - ireq->request_daddr = dma; - ireq->isci_host = ihost; - ihost->reqs[i] = ireq; - } - return 0; } @@ -2654,7 +2412,7 @@ void sci_controller_link_down(struct isci_host *ihost, struct isci_port *iport, } } -static bool sci_controller_has_remote_devices_stopping(struct isci_host *ihost) +bool sci_controller_has_remote_devices_stopping(struct isci_host *ihost) { u32 index; @@ -2680,7 +2438,7 @@ void sci_controller_remote_device_stopped(struct isci_host *ihost, } if (!sci_controller_has_remote_devices_stopping(ihost)) - sci_change_state(&ihost->sm, SCIC_STOPPED); + isci_host_stop_complete(ihost); } void sci_controller_post_request(struct isci_host *ihost, u32 request) @@ -2842,7 +2600,8 @@ enum sci_status sci_controller_start_io(struct isci_host *ihost, enum sci_status status; if (ihost->sm.current_state_id != SCIC_READY) { - dev_warn(&ihost->pdev->dev, "invalid state to start I/O"); + dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n", + __func__, ihost->sm.current_state_id); return SCI_FAILURE_INVALID_STATE; } @@ -2866,22 +2625,26 @@ enum sci_status sci_controller_terminate_request(struct isci_host *ihost, enum sci_status status; if (ihost->sm.current_state_id != SCIC_READY) { - dev_warn(&ihost->pdev->dev, - "invalid state to terminate request\n"); + dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n", + __func__, ihost->sm.current_state_id); return SCI_FAILURE_INVALID_STATE; } - status = sci_io_request_terminate(ireq); - if (status != SCI_SUCCESS) - return status; - /* - * Utilize the original post context command and or in the POST_TC_ABORT - * request sub-type. - */ - sci_controller_post_request(ihost, - ireq->post_context | SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT); - return SCI_SUCCESS; + dev_dbg(&ihost->pdev->dev, "%s: status=%d; ireq=%p; flags=%lx\n", + __func__, status, ireq, ireq->flags); + + if ((status == SCI_SUCCESS) && + !test_bit(IREQ_PENDING_ABORT, &ireq->flags) && + !test_and_set_bit(IREQ_TC_ABORT_POSTED, &ireq->flags)) { + /* Utilize the original post context command and or in the + * POST_TC_ABORT request sub-type. + */ + sci_controller_post_request( + ihost, ireq->post_context | + SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT); + } + return status; } /** @@ -2915,7 +2678,8 @@ enum sci_status sci_controller_complete_io(struct isci_host *ihost, clear_bit(IREQ_ACTIVE, &ireq->flags); return SCI_SUCCESS; default: - dev_warn(&ihost->pdev->dev, "invalid state to complete I/O"); + dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n", + __func__, ihost->sm.current_state_id); return SCI_FAILURE_INVALID_STATE; } @@ -2926,7 +2690,8 @@ enum sci_status sci_controller_continue_io(struct isci_request *ireq) struct isci_host *ihost = ireq->owning_controller; if (ihost->sm.current_state_id != SCIC_READY) { - dev_warn(&ihost->pdev->dev, "invalid state to continue I/O"); + dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n", + __func__, ihost->sm.current_state_id); return SCI_FAILURE_INVALID_STATE; } diff --git a/trunk/drivers/scsi/isci/host.h b/trunk/drivers/scsi/isci/host.h index adbad69d1069..9ab58e0540e7 100644 --- a/trunk/drivers/scsi/isci/host.h +++ b/trunk/drivers/scsi/isci/host.h @@ -55,6 +55,7 @@ #ifndef _SCI_HOST_H_ #define _SCI_HOST_H_ +#include #include "remote_device.h" #include "phy.h" #include "isci.h" @@ -108,6 +109,8 @@ struct sci_port_configuration_agent; typedef void (*port_config_fn)(struct isci_host *, struct sci_port_configuration_agent *, struct isci_port *, struct isci_phy *); +bool is_port_config_apc(struct isci_host *ihost); +bool is_controller_start_complete(struct isci_host *ihost); struct sci_port_configuration_agent { u16 phy_configured_mask; @@ -157,13 +160,17 @@ struct isci_host { struct sci_power_control power_control; u8 io_request_sequence[SCI_MAX_IO_REQUESTS]; struct scu_task_context *task_context_table; - dma_addr_t task_context_dma; + dma_addr_t tc_dma; union scu_remote_node_context *remote_node_context_table; + dma_addr_t rnc_dma; u32 *completion_queue; + dma_addr_t cq_dma; u32 completion_queue_get; u32 logical_port_entries; u32 remote_node_entries; u32 task_context_entries; + void *ufi_buf; + dma_addr_t ufi_dma; struct sci_unsolicited_frame_control uf_control; /* phy startup */ @@ -190,17 +197,13 @@ struct isci_host { struct asd_sas_port sas_ports[SCI_MAX_PORTS]; struct sas_ha_struct sas_ha; - spinlock_t state_lock; struct pci_dev *pdev; - enum isci_status status; #define IHOST_START_PENDING 0 #define IHOST_STOP_PENDING 1 + #define IHOST_IRQ_ENABLED 2 unsigned long flags; wait_queue_head_t eventq; - struct Scsi_Host *shost; struct tasklet_struct completion_tasklet; - struct list_head requests_to_complete; - struct list_head requests_to_errorback; spinlock_t scic_lock; struct isci_request *reqs[SCI_MAX_IO_REQUESTS]; struct isci_remote_device devices[SCI_MAX_REMOTE_DEVICES]; @@ -273,13 +276,6 @@ enum sci_controller_states { */ SCIC_STOPPING, - /** - * This state indicates that the controller has successfully been stopped. - * In this state no new IO operations are permitted. - * This state is entered from the STOPPING state. - */ - SCIC_STOPPED, - /** * This state indicates that the controller could not successfully be * initialized. In this state no new IO operations are permitted. @@ -309,32 +305,16 @@ static inline struct isci_pci_info *to_pci_info(struct pci_dev *pdev) return pci_get_drvdata(pdev); } +static inline struct Scsi_Host *to_shost(struct isci_host *ihost) +{ + return ihost->sas_ha.core.shost; +} + #define for_each_isci_host(id, ihost, pdev) \ for (id = 0, ihost = to_pci_info(pdev)->hosts[id]; \ id < ARRAY_SIZE(to_pci_info(pdev)->hosts) && ihost; \ ihost = to_pci_info(pdev)->hosts[++id]) -static inline enum isci_status isci_host_get_state(struct isci_host *isci_host) -{ - return isci_host->status; -} - -static inline void isci_host_change_state(struct isci_host *isci_host, - enum isci_status status) -{ - unsigned long flags; - - dev_dbg(&isci_host->pdev->dev, - "%s: isci_host = %p, state = 0x%x", - __func__, - isci_host, - status); - spin_lock_irqsave(&isci_host->state_lock, flags); - isci_host->status = status; - spin_unlock_irqrestore(&isci_host->state_lock, flags); - -} - static inline void wait_for_start(struct isci_host *ihost) { wait_event(ihost->eventq, !test_bit(IHOST_START_PENDING, &ihost->flags)); @@ -360,6 +340,11 @@ static inline struct isci_host *dev_to_ihost(struct domain_device *dev) return dev->port->ha->lldd_ha; } +static inline struct isci_host *idev_to_ihost(struct isci_remote_device *idev) +{ + return dev_to_ihost(idev->domain_dev); +} + /* we always use protocol engine group zero */ #define ISCI_PEG 0 @@ -378,8 +363,7 @@ static inline int sci_remote_device_node_count(struct isci_remote_device *idev) { struct domain_device *dev = idev->domain_dev; - if ((dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) && - !idev->is_direct_attached) + if (dev_is_sata(dev) && dev->parent) return SCU_STP_REMOTE_NODE_COUNT; return SCU_SSP_REMOTE_NODE_COUNT; } @@ -475,36 +459,17 @@ void sci_controller_free_remote_node_context( struct isci_remote_device *idev, u16 node_id); -struct isci_request *sci_request_by_tag(struct isci_host *ihost, - u16 io_tag); - -void sci_controller_power_control_queue_insert( - struct isci_host *ihost, - struct isci_phy *iphy); - -void sci_controller_power_control_queue_remove( - struct isci_host *ihost, - struct isci_phy *iphy); - -void sci_controller_link_up( - struct isci_host *ihost, - struct isci_port *iport, - struct isci_phy *iphy); - -void sci_controller_link_down( - struct isci_host *ihost, - struct isci_port *iport, - struct isci_phy *iphy); - -void sci_controller_remote_device_stopped( - struct isci_host *ihost, - struct isci_remote_device *idev); - -void sci_controller_copy_task_context( - struct isci_host *ihost, - struct isci_request *ireq); - -void sci_controller_register_setup(struct isci_host *ihost); +struct isci_request *sci_request_by_tag(struct isci_host *ihost, u16 io_tag); +void sci_controller_power_control_queue_insert(struct isci_host *ihost, + struct isci_phy *iphy); +void sci_controller_power_control_queue_remove(struct isci_host *ihost, + struct isci_phy *iphy); +void sci_controller_link_up(struct isci_host *ihost, struct isci_port *iport, + struct isci_phy *iphy); +void sci_controller_link_down(struct isci_host *ihost, struct isci_port *iport, + struct isci_phy *iphy); +void sci_controller_remote_device_stopped(struct isci_host *ihost, + struct isci_remote_device *idev); enum sci_status sci_controller_continue_io(struct isci_request *ireq); int isci_host_scan_finished(struct Scsi_Host *, unsigned long); @@ -512,29 +477,14 @@ void isci_host_scan_start(struct Scsi_Host *); u16 isci_alloc_tag(struct isci_host *ihost); enum sci_status isci_free_tag(struct isci_host *ihost, u16 io_tag); void isci_tci_free(struct isci_host *ihost, u16 tci); +void ireq_done(struct isci_host *ihost, struct isci_request *ireq, struct sas_task *task); int isci_host_init(struct isci_host *); - -void isci_host_init_controller_names( - struct isci_host *isci_host, - unsigned int controller_idx); - -void isci_host_deinit( - struct isci_host *); - -void isci_host_port_link_up( - struct isci_host *, - struct isci_port *, - struct isci_phy *); -int isci_host_dev_found(struct domain_device *); - -void isci_host_remote_device_start_complete( - struct isci_host *, - struct isci_remote_device *, - enum sci_status); - -void sci_controller_disable_interrupts( - struct isci_host *ihost); +void isci_host_completion_routine(unsigned long data); +void isci_host_deinit(struct isci_host *); +void sci_controller_disable_interrupts(struct isci_host *ihost); +bool sci_controller_has_remote_devices_stopping(struct isci_host *ihost); +void sci_controller_transition_to_ready(struct isci_host *ihost, enum sci_status status); enum sci_status sci_controller_start_io( struct isci_host *ihost, diff --git a/trunk/drivers/scsi/isci/init.c b/trunk/drivers/scsi/isci/init.c index 5137db5a5d85..47e28b555029 100644 --- a/trunk/drivers/scsi/isci/init.c +++ b/trunk/drivers/scsi/isci/init.c @@ -271,13 +271,12 @@ static void isci_unregister(struct isci_host *isci_host) if (!isci_host) return; - shost = isci_host->shost; - sas_unregister_ha(&isci_host->sas_ha); - sas_remove_host(isci_host->shost); - scsi_remove_host(isci_host->shost); - scsi_host_put(isci_host->shost); + shost = to_shost(isci_host); + sas_remove_host(shost); + scsi_remove_host(shost); + scsi_host_put(shost); } static int __devinit isci_pci_init(struct pci_dev *pdev) @@ -397,38 +396,199 @@ static int isci_setup_interrupts(struct pci_dev *pdev) return err; } +static void isci_user_parameters_get(struct sci_user_parameters *u) +{ + int i; + + for (i = 0; i < SCI_MAX_PHYS; i++) { + struct sci_phy_user_params *u_phy = &u->phys[i]; + + u_phy->max_speed_generation = phy_gen; + + /* we are not exporting these for now */ + u_phy->align_insertion_frequency = 0x7f; + u_phy->in_connection_align_insertion_frequency = 0xff; + u_phy->notify_enable_spin_up_insertion_frequency = 0x33; + } + + u->stp_inactivity_timeout = stp_inactive_to; + u->ssp_inactivity_timeout = ssp_inactive_to; + u->stp_max_occupancy_timeout = stp_max_occ_to; + u->ssp_max_occupancy_timeout = ssp_max_occ_to; + u->no_outbound_task_timeout = no_outbound_task_to; + u->max_concurr_spinup = max_concurr_spinup; +} + +static enum sci_status sci_user_parameters_set(struct isci_host *ihost, + struct sci_user_parameters *sci_parms) +{ + u16 index; + + /* + * Validate the user parameters. If they are not legal, then + * return a failure. + */ + for (index = 0; index < SCI_MAX_PHYS; index++) { + struct sci_phy_user_params *u; + + u = &sci_parms->phys[index]; + + if (!((u->max_speed_generation <= SCIC_SDS_PARM_MAX_SPEED) && + (u->max_speed_generation > SCIC_SDS_PARM_NO_SPEED))) + return SCI_FAILURE_INVALID_PARAMETER_VALUE; + + if (u->in_connection_align_insertion_frequency < 3) + return SCI_FAILURE_INVALID_PARAMETER_VALUE; + + if ((u->in_connection_align_insertion_frequency < 3) || + (u->align_insertion_frequency == 0) || + (u->notify_enable_spin_up_insertion_frequency == 0)) + return SCI_FAILURE_INVALID_PARAMETER_VALUE; + } + + if ((sci_parms->stp_inactivity_timeout == 0) || + (sci_parms->ssp_inactivity_timeout == 0) || + (sci_parms->stp_max_occupancy_timeout == 0) || + (sci_parms->ssp_max_occupancy_timeout == 0) || + (sci_parms->no_outbound_task_timeout == 0)) + return SCI_FAILURE_INVALID_PARAMETER_VALUE; + + memcpy(&ihost->user_parameters, sci_parms, sizeof(*sci_parms)); + + return SCI_SUCCESS; +} + +static void sci_oem_defaults(struct isci_host *ihost) +{ + /* these defaults are overridden by the platform / firmware */ + struct sci_user_parameters *user = &ihost->user_parameters; + struct sci_oem_params *oem = &ihost->oem_parameters; + int i; + + /* Default to APC mode. */ + oem->controller.mode_type = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE; + + /* Default to APC mode. */ + oem->controller.max_concurr_spin_up = 1; + + /* Default to no SSC operation. */ + oem->controller.do_enable_ssc = false; + + /* Default to short cables on all phys. */ + oem->controller.cable_selection_mask = 0; + + /* Initialize all of the port parameter information to narrow ports. */ + for (i = 0; i < SCI_MAX_PORTS; i++) + oem->ports[i].phy_mask = 0; + + /* Initialize all of the phy parameter information. */ + for (i = 0; i < SCI_MAX_PHYS; i++) { + /* Default to 3G (i.e. Gen 2). */ + user->phys[i].max_speed_generation = SCIC_SDS_PARM_GEN2_SPEED; + + /* the frequencies cannot be 0 */ + user->phys[i].align_insertion_frequency = 0x7f; + user->phys[i].in_connection_align_insertion_frequency = 0xff; + user->phys[i].notify_enable_spin_up_insertion_frequency = 0x33; + + /* Previous Vitesse based expanders had a arbitration issue that + * is worked around by having the upper 32-bits of SAS address + * with a value greater then the Vitesse company identifier. + * Hence, usage of 0x5FCFFFFF. + */ + oem->phys[i].sas_address.low = 0x1 + ihost->id; + oem->phys[i].sas_address.high = 0x5FCFFFFF; + } + + user->stp_inactivity_timeout = 5; + user->ssp_inactivity_timeout = 5; + user->stp_max_occupancy_timeout = 5; + user->ssp_max_occupancy_timeout = 20; + user->no_outbound_task_timeout = 2; +} + static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id) { - struct isci_host *isci_host; + struct isci_orom *orom = to_pci_info(pdev)->orom; + struct sci_user_parameters sci_user_params; + u8 oem_version = ISCI_ROM_VER_1_0; + struct isci_host *ihost; struct Scsi_Host *shost; - int err; + int err, i; - isci_host = devm_kzalloc(&pdev->dev, sizeof(*isci_host), GFP_KERNEL); - if (!isci_host) + ihost = devm_kzalloc(&pdev->dev, sizeof(*ihost), GFP_KERNEL); + if (!ihost) return NULL; - isci_host->pdev = pdev; - isci_host->id = id; + ihost->pdev = pdev; + ihost->id = id; + spin_lock_init(&ihost->scic_lock); + init_waitqueue_head(&ihost->eventq); + ihost->sas_ha.dev = &ihost->pdev->dev; + ihost->sas_ha.lldd_ha = ihost; + tasklet_init(&ihost->completion_tasklet, + isci_host_completion_routine, (unsigned long)ihost); + + /* validate module parameters */ + /* TODO: kill struct sci_user_parameters and reference directly */ + sci_oem_defaults(ihost); + isci_user_parameters_get(&sci_user_params); + if (sci_user_parameters_set(ihost, &sci_user_params)) { + dev_warn(&pdev->dev, + "%s: sci_user_parameters_set failed\n", __func__); + return NULL; + } + + /* sanity check platform (or 'firmware') oem parameters */ + if (orom) { + if (id < 0 || id >= SCI_MAX_CONTROLLERS || id > orom->hdr.num_elements) { + dev_warn(&pdev->dev, "parsing firmware oem parameters failed\n"); + return NULL; + } + ihost->oem_parameters = orom->ctrl[id]; + oem_version = orom->hdr.version; + } + + /* validate oem parameters (platform, firmware, or built-in defaults) */ + if (sci_oem_parameters_validate(&ihost->oem_parameters, oem_version)) { + dev_warn(&pdev->dev, "oem parameter validation failed\n"); + return NULL; + } + + for (i = 0; i < SCI_MAX_PORTS; i++) { + struct isci_port *iport = &ihost->ports[i]; + + INIT_LIST_HEAD(&iport->remote_dev_list); + iport->isci_host = ihost; + } + + for (i = 0; i < SCI_MAX_PHYS; i++) + isci_phy_init(&ihost->phys[i], ihost, i); + + for (i = 0; i < SCI_MAX_REMOTE_DEVICES; i++) { + struct isci_remote_device *idev = &ihost->devices[i]; + + INIT_LIST_HEAD(&idev->node); + } shost = scsi_host_alloc(&isci_sht, sizeof(void *)); if (!shost) return NULL; - isci_host->shost = shost; dev_info(&pdev->dev, "%sSCU controller %d: phy 3-0 cables: " "{%s, %s, %s, %s}\n", - (is_cable_select_overridden() ? "* " : ""), isci_host->id, - lookup_cable_names(decode_cable_selection(isci_host, 3)), - lookup_cable_names(decode_cable_selection(isci_host, 2)), - lookup_cable_names(decode_cable_selection(isci_host, 1)), - lookup_cable_names(decode_cable_selection(isci_host, 0))); + (is_cable_select_overridden() ? "* " : ""), ihost->id, + lookup_cable_names(decode_cable_selection(ihost, 3)), + lookup_cable_names(decode_cable_selection(ihost, 2)), + lookup_cable_names(decode_cable_selection(ihost, 1)), + lookup_cable_names(decode_cable_selection(ihost, 0))); - err = isci_host_init(isci_host); + err = isci_host_init(ihost); if (err) goto err_shost; - SHOST_TO_SAS_HA(shost) = &isci_host->sas_ha; - isci_host->sas_ha.core.shost = shost; + SHOST_TO_SAS_HA(shost) = &ihost->sas_ha; + ihost->sas_ha.core.shost = shost; shost->transportt = isci_transport_template; shost->max_id = ~0; @@ -439,11 +599,11 @@ static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id) if (err) goto err_shost; - err = isci_register_sas_ha(isci_host); + err = isci_register_sas_ha(ihost); if (err) goto err_shost_remove; - return isci_host; + return ihost; err_shost_remove: scsi_remove_host(shost); @@ -476,7 +636,7 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic if (!orom) orom = isci_request_oprom(pdev); - for (i = 0; orom && i < ARRAY_SIZE(orom->ctrl); i++) { + for (i = 0; orom && i < num_controllers(pdev); i++) { if (sci_oem_parameters_validate(&orom->ctrl[i], orom->hdr.version)) { dev_warn(&pdev->dev, @@ -525,11 +685,11 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic pci_info->hosts[i] = h; /* turn on DIF support */ - scsi_host_set_prot(h->shost, + scsi_host_set_prot(to_shost(h), SHOST_DIF_TYPE1_PROTECTION | SHOST_DIF_TYPE2_PROTECTION | SHOST_DIF_TYPE3_PROTECTION); - scsi_host_set_guard(h->shost, SHOST_DIX_GUARD_CRC); + scsi_host_set_guard(to_shost(h), SHOST_DIX_GUARD_CRC); } err = isci_setup_interrupts(pdev); @@ -537,7 +697,7 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic goto err_host_alloc; for_each_isci_host(i, isci_host, pdev) - scsi_scan_host(isci_host->shost); + scsi_scan_host(to_shost(isci_host)); return 0; diff --git a/trunk/drivers/scsi/isci/phy.c b/trunk/drivers/scsi/isci/phy.c index fab3586840b5..18f43d4c30ba 100644 --- a/trunk/drivers/scsi/isci/phy.c +++ b/trunk/drivers/scsi/isci/phy.c @@ -580,7 +580,7 @@ static void sci_phy_start_sas_link_training(struct isci_phy *iphy) sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SAS_SPEED_EN); - iphy->protocol = SCIC_SDS_PHY_PROTOCOL_SAS; + iphy->protocol = SAS_PROTOCOL_SSP; } static void sci_phy_start_sata_link_training(struct isci_phy *iphy) @@ -591,7 +591,7 @@ static void sci_phy_start_sata_link_training(struct isci_phy *iphy) */ sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SATA_POWER); - iphy->protocol = SCIC_SDS_PHY_PROTOCOL_SATA; + iphy->protocol = SAS_PROTOCOL_SATA; } /** @@ -668,6 +668,19 @@ static const char *phy_event_name(u32 event_code) phy_to_host(iphy)->id, iphy->phy_index, \ phy_state_name(state), phy_event_name(code), code) + +void scu_link_layer_set_txcomsas_timeout(struct isci_phy *iphy, u32 timeout) +{ + u32 val; + + /* Extend timeout */ + val = readl(&iphy->link_layer_registers->transmit_comsas_signal); + val &= ~SCU_SAS_LLTXCOMSAS_GEN_VAL(NEGTIME, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_MASK); + val |= SCU_SAS_LLTXCOMSAS_GEN_VAL(NEGTIME, timeout); + + writel(val, &iphy->link_layer_registers->transmit_comsas_signal); +} + enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code) { enum sci_phy_states state = iphy->sm.current_state_id; @@ -683,6 +696,13 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code) sci_phy_start_sata_link_training(iphy); iphy->is_in_link_training = true; break; + case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT: + /* Extend timeout value */ + scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_EXTENDED); + + /* Start the oob/sn state machine over again */ + sci_change_state(&iphy->sm, SCI_PHY_STARTING); + break; default: phy_event_dbg(iphy, state, event_code); return SCI_FAILURE; @@ -717,9 +737,19 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code) sci_phy_start_sata_link_training(iphy); break; case SCU_EVENT_LINK_FAILURE: + /* Change the timeout value to default */ + scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT); + /* Link failure change state back to the starting state */ sci_change_state(&iphy->sm, SCI_PHY_STARTING); break; + case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT: + /* Extend the timeout value */ + scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_EXTENDED); + + /* Start the oob/sn state machine over again */ + sci_change_state(&iphy->sm, SCI_PHY_STARTING); + break; default: phy_event_warn(iphy, state, event_code); return SCI_FAILURE; @@ -740,7 +770,14 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code) sci_phy_start_sata_link_training(iphy); break; case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT: + /* Extend the timeout value */ + scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_EXTENDED); + + /* Start the oob/sn state machine over again */ + sci_change_state(&iphy->sm, SCI_PHY_STARTING); + break; case SCU_EVENT_LINK_FAILURE: + scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT); case SCU_EVENT_HARD_RESET_RECEIVED: /* Start the oob/sn state machine over again */ sci_change_state(&iphy->sm, SCI_PHY_STARTING); @@ -753,6 +790,9 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code) case SCI_PHY_SUB_AWAIT_SAS_POWER: switch (scu_get_event_code(event_code)) { case SCU_EVENT_LINK_FAILURE: + /* Change the timeout value to default */ + scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT); + /* Link failure change state back to the starting state */ sci_change_state(&iphy->sm, SCI_PHY_STARTING); break; @@ -764,6 +804,9 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code) case SCI_PHY_SUB_AWAIT_SATA_POWER: switch (scu_get_event_code(event_code)) { case SCU_EVENT_LINK_FAILURE: + /* Change the timeout value to default */ + scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT); + /* Link failure change state back to the starting state */ sci_change_state(&iphy->sm, SCI_PHY_STARTING); break; @@ -788,6 +831,9 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code) case SCI_PHY_SUB_AWAIT_SATA_PHY_EN: switch (scu_get_event_code(event_code)) { case SCU_EVENT_LINK_FAILURE: + /* Change the timeout value to default */ + scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT); + /* Link failure change state back to the starting state */ sci_change_state(&iphy->sm, SCI_PHY_STARTING); break; @@ -797,7 +843,7 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code) */ break; case SCU_EVENT_SATA_PHY_DETECTED: - iphy->protocol = SCIC_SDS_PHY_PROTOCOL_SATA; + iphy->protocol = SAS_PROTOCOL_SATA; /* We have received the SATA PHY notification change state */ sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SATA_SPEED_EN); @@ -836,6 +882,9 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code) SCI_PHY_SUB_AWAIT_SIG_FIS_UF); break; case SCU_EVENT_LINK_FAILURE: + /* Change the timeout value to default */ + scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT); + /* Link failure change state back to the starting state */ sci_change_state(&iphy->sm, SCI_PHY_STARTING); break; @@ -859,6 +908,9 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code) break; case SCU_EVENT_LINK_FAILURE: + /* Change the timeout value to default */ + scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT); + /* Link failure change state back to the starting state */ sci_change_state(&iphy->sm, SCI_PHY_STARTING); break; @@ -871,16 +923,26 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code) case SCI_PHY_READY: switch (scu_get_event_code(event_code)) { case SCU_EVENT_LINK_FAILURE: + /* Set default timeout */ + scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT); + /* Link failure change state back to the starting state */ sci_change_state(&iphy->sm, SCI_PHY_STARTING); break; case SCU_EVENT_BROADCAST_CHANGE: + case SCU_EVENT_BROADCAST_SES: + case SCU_EVENT_BROADCAST_RESERVED0: + case SCU_EVENT_BROADCAST_RESERVED1: + case SCU_EVENT_BROADCAST_EXPANDER: + case SCU_EVENT_BROADCAST_AEN: /* Broadcast change received. Notify the port. */ if (phy_get_non_dummy_port(iphy) != NULL) sci_port_broadcast_change_received(iphy->owning_port, iphy); else iphy->bcn_received_while_port_unassigned = true; break; + case SCU_EVENT_BROADCAST_RESERVED3: + case SCU_EVENT_BROADCAST_RESERVED4: default: phy_event_warn(iphy, state, event_code); return SCI_FAILURE_INVALID_STATE; @@ -1215,7 +1277,7 @@ static void sci_phy_starting_state_enter(struct sci_base_state_machine *sm) scu_link_layer_start_oob(iphy); /* We don't know what kind of phy we are going to be just yet */ - iphy->protocol = SCIC_SDS_PHY_PROTOCOL_UNKNOWN; + iphy->protocol = SAS_PROTOCOL_NONE; iphy->bcn_received_while_port_unassigned = false; if (iphy->sm.previous_state_id == SCI_PHY_READY) @@ -1250,7 +1312,7 @@ static void sci_phy_resetting_state_enter(struct sci_base_state_machine *sm) */ sci_port_deactivate_phy(iphy->owning_port, iphy, false); - if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS) { + if (iphy->protocol == SAS_PROTOCOL_SSP) { scu_link_layer_tx_hard_reset(iphy); } else { /* The SCU does not need to have a discrete reset state so @@ -1316,7 +1378,7 @@ void sci_phy_construct(struct isci_phy *iphy, iphy->owning_port = iport; iphy->phy_index = phy_index; iphy->bcn_received_while_port_unassigned = false; - iphy->protocol = SCIC_SDS_PHY_PROTOCOL_UNKNOWN; + iphy->protocol = SAS_PROTOCOL_NONE; iphy->link_layer_registers = NULL; iphy->max_negotiated_speed = SAS_LINK_RATE_UNKNOWN; @@ -1380,12 +1442,14 @@ int isci_phy_control(struct asd_sas_phy *sas_phy, switch (func) { case PHY_FUNC_DISABLE: spin_lock_irqsave(&ihost->scic_lock, flags); + scu_link_layer_start_oob(iphy); sci_phy_stop(iphy); spin_unlock_irqrestore(&ihost->scic_lock, flags); break; case PHY_FUNC_LINK_RESET: spin_lock_irqsave(&ihost->scic_lock, flags); + scu_link_layer_start_oob(iphy); sci_phy_stop(iphy); sci_phy_start(iphy); spin_unlock_irqrestore(&ihost->scic_lock, flags); diff --git a/trunk/drivers/scsi/isci/phy.h b/trunk/drivers/scsi/isci/phy.h index 0e45833ba06d..45fecfa36a98 100644 --- a/trunk/drivers/scsi/isci/phy.h +++ b/trunk/drivers/scsi/isci/phy.h @@ -76,13 +76,6 @@ */ #define SCIC_SDS_SATA_LINK_TRAINING_TIMEOUT 250 -enum sci_phy_protocol { - SCIC_SDS_PHY_PROTOCOL_UNKNOWN, - SCIC_SDS_PHY_PROTOCOL_SAS, - SCIC_SDS_PHY_PROTOCOL_SATA, - SCIC_SDS_MAX_PHY_PROTOCOLS -}; - /** * isci_phy - hba local phy infrastructure * @sm: @@ -95,7 +88,7 @@ struct isci_phy { struct sci_base_state_machine sm; struct isci_port *owning_port; enum sas_linkrate max_negotiated_speed; - enum sci_phy_protocol protocol; + enum sas_protocol protocol; u8 phy_index; bool bcn_received_while_port_unassigned; bool is_in_link_training; diff --git a/trunk/drivers/scsi/isci/port.c b/trunk/drivers/scsi/isci/port.c index 5fada73b71ff..2fb85bf75449 100644 --- a/trunk/drivers/scsi/isci/port.c +++ b/trunk/drivers/scsi/isci/port.c @@ -184,7 +184,7 @@ static void isci_port_link_up(struct isci_host *isci_host, sci_port_get_properties(iport, &properties); - if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA) { + if (iphy->protocol == SAS_PROTOCOL_SATA) { u64 attached_sas_address; iphy->sas_phy.oob_mode = SATA_OOB_MODE; @@ -204,7 +204,7 @@ static void isci_port_link_up(struct isci_host *isci_host, memcpy(&iphy->sas_phy.attached_sas_addr, &attached_sas_address, sizeof(attached_sas_address)); - } else if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS) { + } else if (iphy->protocol == SAS_PROTOCOL_SSP) { iphy->sas_phy.oob_mode = SAS_OOB_MODE; iphy->sas_phy.frame_rcvd_size = sizeof(struct sas_identify_frame); @@ -251,10 +251,10 @@ static void isci_port_link_down(struct isci_host *isci_host, if (isci_phy->sas_phy.port && isci_phy->sas_phy.port->num_phys == 1) { /* change the state for all devices on this port. The - * next task sent to this device will be returned as - * SAS_TASK_UNDELIVERED, and the scsi mid layer will - * remove the target - */ + * next task sent to this device will be returned as + * SAS_TASK_UNDELIVERED, and the scsi mid layer will + * remove the target + */ list_for_each_entry(isci_device, &isci_port->remote_dev_list, node) { @@ -517,7 +517,7 @@ void sci_port_get_attached_sas_address(struct isci_port *iport, struct sci_sas_a */ iphy = sci_port_get_a_connected_phy(iport); if (iphy) { - if (iphy->protocol != SCIC_SDS_PHY_PROTOCOL_SATA) { + if (iphy->protocol != SAS_PROTOCOL_SATA) { sci_phy_get_attached_sas_address(iphy, sas); } else { sci_phy_get_sas_address(iphy, sas); @@ -624,7 +624,7 @@ static void sci_port_activate_phy(struct isci_port *iport, { struct isci_host *ihost = iport->owning_controller; - if (iphy->protocol != SCIC_SDS_PHY_PROTOCOL_SATA && (flags & PF_RESUME)) + if (iphy->protocol != SAS_PROTOCOL_SATA && (flags & PF_RESUME)) sci_phy_resume(iphy); iport->active_phy_mask |= 1 << iphy->phy_index; @@ -751,12 +751,10 @@ static bool sci_port_is_wide(struct isci_port *iport) * wide ports and direct attached phys. Since there are no wide ported SATA * devices this could become an invalid port configuration. */ -bool sci_port_link_detected( - struct isci_port *iport, - struct isci_phy *iphy) +bool sci_port_link_detected(struct isci_port *iport, struct isci_phy *iphy) { if ((iport->logical_port_index != SCIC_SDS_DUMMY_PORT) && - (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA)) { + (iphy->protocol == SAS_PROTOCOL_SATA)) { if (sci_port_is_wide(iport)) { sci_port_invalid_link_up(iport, iphy); return false; @@ -1201,6 +1199,8 @@ enum sci_status sci_port_add_phy(struct isci_port *iport, enum sci_status status; enum sci_port_states state; + sci_port_bcn_enable(iport); + state = iport->sm.current_state_id; switch (state) { case SCI_PORT_STOPPED: { @@ -1548,6 +1548,29 @@ static void sci_port_failed_state_enter(struct sci_base_state_machine *sm) isci_port_hard_reset_complete(iport, SCI_FAILURE_TIMEOUT); } +void sci_port_set_hang_detection_timeout(struct isci_port *iport, u32 timeout) +{ + int phy_index; + u32 phy_mask = iport->active_phy_mask; + + if (timeout) + ++iport->hang_detect_users; + else if (iport->hang_detect_users > 1) + --iport->hang_detect_users; + else + iport->hang_detect_users = 0; + + if (timeout || (iport->hang_detect_users == 0)) { + for (phy_index = 0; phy_index < SCI_MAX_PHYS; phy_index++) { + if ((phy_mask >> phy_index) & 1) { + writel(timeout, + &iport->phy_table[phy_index] + ->link_layer_registers + ->link_layer_hang_detection_timeout); + } + } + } +} /* --------------------------------------------------------------------------- */ static const struct sci_base_state sci_port_state_table[] = { @@ -1596,6 +1619,7 @@ void sci_port_construct(struct isci_port *iport, u8 index, iport->started_request_count = 0; iport->assigned_device_count = 0; + iport->hang_detect_users = 0; iport->reserved_rni = SCU_DUMMY_INDEX; iport->reserved_tag = SCI_CONTROLLER_INVALID_IO_TAG; @@ -1608,13 +1632,6 @@ void sci_port_construct(struct isci_port *iport, u8 index, iport->phy_table[index] = NULL; } -void isci_port_init(struct isci_port *iport, struct isci_host *ihost, int index) -{ - INIT_LIST_HEAD(&iport->remote_dev_list); - INIT_LIST_HEAD(&iport->domain_dev_list); - iport->isci_host = ihost; -} - void sci_port_broadcast_change_received(struct isci_port *iport, struct isci_phy *iphy) { struct isci_host *ihost = iport->owning_controller; @@ -1671,17 +1688,6 @@ int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *ipor __func__, iport, status); } - - /* If the hard reset for the port has failed, consider this - * the same as link failures on all phys in the port. - */ - if (ret != TMF_RESP_FUNC_COMPLETE) { - - dev_err(&ihost->pdev->dev, - "%s: iport = %p; hard reset failed " - "(0x%x) - driving explicit link fail for all phys\n", - __func__, iport, iport->hard_reset_status); - } return ret; } @@ -1740,7 +1746,7 @@ void isci_port_formed(struct asd_sas_phy *phy) struct isci_host *ihost = phy->ha->lldd_ha; struct isci_phy *iphy = to_iphy(phy); struct asd_sas_port *port = phy->port; - struct isci_port *iport; + struct isci_port *iport = NULL; unsigned long flags; int i; diff --git a/trunk/drivers/scsi/isci/port.h b/trunk/drivers/scsi/isci/port.h index 6b56240c2051..861e8f72811b 100644 --- a/trunk/drivers/scsi/isci/port.h +++ b/trunk/drivers/scsi/isci/port.h @@ -97,7 +97,6 @@ enum isci_status { struct isci_port { struct isci_host *isci_host; struct list_head remote_dev_list; - struct list_head domain_dev_list; #define IPORT_RESET_PENDING 0 unsigned long state; enum sci_status hard_reset_status; @@ -112,6 +111,7 @@ struct isci_port { u16 reserved_tag; u32 started_request_count; u32 assigned_device_count; + u32 hang_detect_users; u32 not_ready_reason; struct isci_phy *phy_table[SCI_MAX_PHYS]; struct isci_host *owning_controller; @@ -270,14 +270,13 @@ void sci_port_get_attached_sas_address( struct isci_port *iport, struct sci_sas_address *sas_address); +void sci_port_set_hang_detection_timeout( + struct isci_port *isci_port, + u32 timeout); + void isci_port_formed(struct asd_sas_phy *); void isci_port_deformed(struct asd_sas_phy *); -void isci_port_init( - struct isci_port *port, - struct isci_host *host, - int index); - int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *iport, struct isci_phy *iphy); int isci_ata_check_ready(struct domain_device *dev); diff --git a/trunk/drivers/scsi/isci/port_config.c b/trunk/drivers/scsi/isci/port_config.c index 6d1e9544cbe5..cd962da4a57a 100644 --- a/trunk/drivers/scsi/isci/port_config.c +++ b/trunk/drivers/scsi/isci/port_config.c @@ -57,7 +57,7 @@ #define SCIC_SDS_MPC_RECONFIGURATION_TIMEOUT (10) #define SCIC_SDS_APC_RECONFIGURATION_TIMEOUT (10) -#define SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION (250) +#define SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION (1000) enum SCIC_SDS_APC_ACTIVITY { SCIC_SDS_APC_SKIP_PHY, @@ -472,13 +472,9 @@ sci_apc_agent_validate_phy_configuration(struct isci_host *ihost, * down event or a link up event where we can not yet tell to which a phy * belongs. */ -static void sci_apc_agent_start_timer( - struct sci_port_configuration_agent *port_agent, - u32 timeout) +static void sci_apc_agent_start_timer(struct sci_port_configuration_agent *port_agent, + u32 timeout) { - if (port_agent->timer_pending) - sci_del_timer(&port_agent->timer); - port_agent->timer_pending = true; sci_mod_timer(&port_agent->timer, timeout); } @@ -697,6 +693,9 @@ static void apc_agent_timeout(unsigned long data) &ihost->phys[index], false); } + if (is_controller_start_complete(ihost)) + sci_controller_transition_to_ready(ihost, SCI_SUCCESS); + done: spin_unlock_irqrestore(&ihost->scic_lock, flags); } @@ -732,6 +731,11 @@ void sci_port_configuration_agent_construct( } } +bool is_port_config_apc(struct isci_host *ihost) +{ + return ihost->port_agent.link_up_handler == sci_apc_agent_link_up; +} + enum sci_status sci_port_configuration_agent_initialize( struct isci_host *ihost, struct sci_port_configuration_agent *port_agent) diff --git a/trunk/drivers/scsi/isci/probe_roms.c b/trunk/drivers/scsi/isci/probe_roms.c index 9b8117b9d756..4d95654c3fd4 100644 --- a/trunk/drivers/scsi/isci/probe_roms.c +++ b/trunk/drivers/scsi/isci/probe_roms.c @@ -112,18 +112,6 @@ struct isci_orom *isci_request_oprom(struct pci_dev *pdev) return rom; } -enum sci_status isci_parse_oem_parameters(struct sci_oem_params *oem, - struct isci_orom *orom, int scu_index) -{ - /* check for valid inputs */ - if (scu_index < 0 || scu_index >= SCI_MAX_CONTROLLERS || - scu_index > orom->hdr.num_elements || !oem) - return -EINVAL; - - *oem = orom->ctrl[scu_index]; - return 0; -} - struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmware *fw) { struct isci_orom *orom = NULL, *data; diff --git a/trunk/drivers/scsi/isci/probe_roms.h b/trunk/drivers/scsi/isci/probe_roms.h index bb0e9d4d97c9..e08b578241f8 100644 --- a/trunk/drivers/scsi/isci/probe_roms.h +++ b/trunk/drivers/scsi/isci/probe_roms.h @@ -156,8 +156,6 @@ int sci_oem_parameters_validate(struct sci_oem_params *oem, u8 version); struct isci_orom; struct isci_orom *isci_request_oprom(struct pci_dev *pdev); -enum sci_status isci_parse_oem_parameters(struct sci_oem_params *oem, - struct isci_orom *orom, int scu_index); struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmware *fw); struct isci_orom *isci_get_efi_var(struct pci_dev *pdev); diff --git a/trunk/drivers/scsi/isci/registers.h b/trunk/drivers/scsi/isci/registers.h index 7eb0ccd45fe6..97f3ceb8d724 100644 --- a/trunk/drivers/scsi/isci/registers.h +++ b/trunk/drivers/scsi/isci/registers.h @@ -1239,6 +1239,14 @@ struct scu_transport_layer_registers { #define SCU_SAS_LLCTL_GEN_BIT(name) \ SCU_GEN_BIT(SCU_SAS_LINK_LAYER_CONTROL_ ## name) +#define SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT (0xF0) +#define SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_EXTENDED (0x1FF) +#define SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_SHIFT (0) +#define SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_MASK (0x3FF) + +#define SCU_SAS_LLTXCOMSAS_GEN_VAL(name, value) \ + SCU_GEN_VALUE(SCU_SAS_LINK_LAYER_TXCOMSAS_ ## name, value) + /* #define SCU_FRXHECR_DCNT_OFFSET 0x00B0 */ #define SCU_PSZGCR_OFFSET 0x00E4 diff --git a/trunk/drivers/scsi/isci/remote_device.c b/trunk/drivers/scsi/isci/remote_device.c index 8f501b0a81d6..c3aa6c5457b9 100644 --- a/trunk/drivers/scsi/isci/remote_device.c +++ b/trunk/drivers/scsi/isci/remote_device.c @@ -72,46 +72,11 @@ const char *dev_state_name(enum sci_remote_device_states state) } #undef C -/** - * isci_remote_device_not_ready() - This function is called by the ihost when - * the remote device is not ready. We mark the isci device as ready (not - * "ready_for_io") and signal the waiting proccess. - * @isci_host: This parameter specifies the isci host object. - * @isci_device: This parameter specifies the remote device - * - * sci_lock is held on entrance to this function. - */ -static void isci_remote_device_not_ready(struct isci_host *ihost, - struct isci_remote_device *idev, u32 reason) +enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev, + enum sci_remote_node_suspension_reasons reason) { - struct isci_request *ireq; - - dev_dbg(&ihost->pdev->dev, - "%s: isci_device = %p\n", __func__, idev); - - switch (reason) { - case SCIC_REMOTE_DEVICE_NOT_READY_STOP_REQUESTED: - set_bit(IDEV_GONE, &idev->flags); - break; - case SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED: - set_bit(IDEV_IO_NCQERROR, &idev->flags); - - /* Kill all outstanding requests for the device. */ - list_for_each_entry(ireq, &idev->reqs_in_process, dev_node) { - - dev_dbg(&ihost->pdev->dev, - "%s: isci_device = %p request = %p\n", - __func__, idev, ireq); - - sci_controller_terminate_request(ihost, - idev, - ireq); - } - /* Fall through into the default case... */ - default: - clear_bit(IDEV_IO_READY, &idev->flags); - break; - } + return sci_remote_node_context_suspend(&idev->rnc, reason, + SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT); } /** @@ -133,18 +98,29 @@ static void isci_remote_device_ready(struct isci_host *ihost, struct isci_remote wake_up(&ihost->eventq); } -/* called once the remote node context is ready to be freed. - * The remote device can now report that its stop operation is complete. none - */ -static void rnc_destruct_done(void *_dev) +static enum sci_status sci_remote_device_terminate_req( + struct isci_host *ihost, + struct isci_remote_device *idev, + int check_abort, + struct isci_request *ireq) { - struct isci_remote_device *idev = _dev; + if (!test_bit(IREQ_ACTIVE, &ireq->flags) || + (ireq->target_device != idev) || + (check_abort && !test_bit(IREQ_PENDING_ABORT, &ireq->flags))) + return SCI_SUCCESS; - BUG_ON(idev->started_request_count != 0); - sci_change_state(&idev->sm, SCI_DEV_STOPPED); + dev_dbg(&ihost->pdev->dev, + "%s: idev=%p; flags=%lx; req=%p; req target=%p\n", + __func__, idev, idev->flags, ireq, ireq->target_device); + + set_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags); + + return sci_controller_terminate_request(ihost, idev, ireq); } -static enum sci_status sci_remote_device_terminate_requests(struct isci_remote_device *idev) +static enum sci_status sci_remote_device_terminate_reqs_checkabort( + struct isci_remote_device *idev, + int chk) { struct isci_host *ihost = idev->owning_port->owning_controller; enum sci_status status = SCI_SUCCESS; @@ -154,18 +130,210 @@ static enum sci_status sci_remote_device_terminate_requests(struct isci_remote_d struct isci_request *ireq = ihost->reqs[i]; enum sci_status s; - if (!test_bit(IREQ_ACTIVE, &ireq->flags) || - ireq->target_device != idev) - continue; - - s = sci_controller_terminate_request(ihost, idev, ireq); + s = sci_remote_device_terminate_req(ihost, idev, chk, ireq); if (s != SCI_SUCCESS) status = s; } + return status; +} + +static bool isci_compare_suspendcount( + struct isci_remote_device *idev, + u32 localcount) +{ + smp_rmb(); + + /* Check for a change in the suspend count, or the RNC + * being destroyed. + */ + return (localcount != idev->rnc.suspend_count) + || sci_remote_node_context_is_being_destroyed(&idev->rnc); +} + +static bool isci_check_reqterm( + struct isci_host *ihost, + struct isci_remote_device *idev, + struct isci_request *ireq, + u32 localcount) +{ + unsigned long flags; + bool res; + spin_lock_irqsave(&ihost->scic_lock, flags); + res = isci_compare_suspendcount(idev, localcount) + && !test_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags); + spin_unlock_irqrestore(&ihost->scic_lock, flags); + + return res; +} + +static bool isci_check_devempty( + struct isci_host *ihost, + struct isci_remote_device *idev, + u32 localcount) +{ + unsigned long flags; + bool res; + + spin_lock_irqsave(&ihost->scic_lock, flags); + res = isci_compare_suspendcount(idev, localcount) + && idev->started_request_count == 0; + spin_unlock_irqrestore(&ihost->scic_lock, flags); + + return res; +} + +enum sci_status isci_remote_device_terminate_requests( + struct isci_host *ihost, + struct isci_remote_device *idev, + struct isci_request *ireq) +{ + enum sci_status status = SCI_SUCCESS; + unsigned long flags; + u32 rnc_suspend_count; + + spin_lock_irqsave(&ihost->scic_lock, flags); + + if (isci_get_device(idev) == NULL) { + dev_dbg(&ihost->pdev->dev, "%s: failed isci_get_device(idev=%p)\n", + __func__, idev); + spin_unlock_irqrestore(&ihost->scic_lock, flags); + status = SCI_FAILURE; + } else { + /* If already suspended, don't wait for another suspension. */ + smp_rmb(); + rnc_suspend_count + = sci_remote_node_context_is_suspended(&idev->rnc) + ? 0 : idev->rnc.suspend_count; + + dev_dbg(&ihost->pdev->dev, + "%s: idev=%p, ireq=%p; started_request_count=%d, " + "rnc_suspend_count=%d, rnc.suspend_count=%d" + "about to wait\n", + __func__, idev, ireq, idev->started_request_count, + rnc_suspend_count, idev->rnc.suspend_count); + + #define MAX_SUSPEND_MSECS 10000 + if (ireq) { + /* Terminate a specific TC. */ + set_bit(IREQ_NO_AUTO_FREE_TAG, &ireq->flags); + sci_remote_device_terminate_req(ihost, idev, 0, ireq); + spin_unlock_irqrestore(&ihost->scic_lock, flags); + if (!wait_event_timeout(ihost->eventq, + isci_check_reqterm(ihost, idev, ireq, + rnc_suspend_count), + msecs_to_jiffies(MAX_SUSPEND_MSECS))) { + + dev_warn(&ihost->pdev->dev, "%s host%d timeout single\n", + __func__, ihost->id); + dev_dbg(&ihost->pdev->dev, + "%s: ******* Timeout waiting for " + "suspend; idev=%p, current state %s; " + "started_request_count=%d, flags=%lx\n\t" + "rnc_suspend_count=%d, rnc.suspend_count=%d " + "RNC: current state %s, current " + "suspend_type %x dest state %d;\n" + "ireq=%p, ireq->flags = %lx\n", + __func__, idev, + dev_state_name(idev->sm.current_state_id), + idev->started_request_count, idev->flags, + rnc_suspend_count, idev->rnc.suspend_count, + rnc_state_name(idev->rnc.sm.current_state_id), + idev->rnc.suspend_type, + idev->rnc.destination_state, + ireq, ireq->flags); + } + spin_lock_irqsave(&ihost->scic_lock, flags); + clear_bit(IREQ_NO_AUTO_FREE_TAG, &ireq->flags); + if (!test_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags)) + isci_free_tag(ihost, ireq->io_tag); + spin_unlock_irqrestore(&ihost->scic_lock, flags); + } else { + /* Terminate all TCs. */ + sci_remote_device_terminate_requests(idev); + spin_unlock_irqrestore(&ihost->scic_lock, flags); + if (!wait_event_timeout(ihost->eventq, + isci_check_devempty(ihost, idev, + rnc_suspend_count), + msecs_to_jiffies(MAX_SUSPEND_MSECS))) { + + dev_warn(&ihost->pdev->dev, "%s host%d timeout all\n", + __func__, ihost->id); + dev_dbg(&ihost->pdev->dev, + "%s: ******* Timeout waiting for " + "suspend; idev=%p, current state %s; " + "started_request_count=%d, flags=%lx\n\t" + "rnc_suspend_count=%d, " + "RNC: current state %s, " + "rnc.suspend_count=%d, current " + "suspend_type %x dest state %d\n", + __func__, idev, + dev_state_name(idev->sm.current_state_id), + idev->started_request_count, idev->flags, + rnc_suspend_count, + rnc_state_name(idev->rnc.sm.current_state_id), + idev->rnc.suspend_count, + idev->rnc.suspend_type, + idev->rnc.destination_state); + } + } + dev_dbg(&ihost->pdev->dev, "%s: idev=%p, wait done\n", + __func__, idev); + isci_put_device(idev); + } return status; } +/** +* isci_remote_device_not_ready() - This function is called by the ihost when +* the remote device is not ready. We mark the isci device as ready (not +* "ready_for_io") and signal the waiting proccess. +* @isci_host: This parameter specifies the isci host object. +* @isci_device: This parameter specifies the remote device +* +* sci_lock is held on entrance to this function. +*/ +static void isci_remote_device_not_ready(struct isci_host *ihost, + struct isci_remote_device *idev, + u32 reason) +{ + dev_dbg(&ihost->pdev->dev, + "%s: isci_device = %p; reason = %d\n", __func__, idev, reason); + + switch (reason) { + case SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED: + set_bit(IDEV_IO_NCQERROR, &idev->flags); + + /* Suspend the remote device so the I/O can be terminated. */ + sci_remote_device_suspend(idev, SCI_SW_SUSPEND_NORMAL); + + /* Kill all outstanding requests for the device. */ + sci_remote_device_terminate_requests(idev); + + /* Fall through into the default case... */ + default: + clear_bit(IDEV_IO_READY, &idev->flags); + break; + } +} + +/* called once the remote node context is ready to be freed. + * The remote device can now report that its stop operation is complete. none + */ +static void rnc_destruct_done(void *_dev) +{ + struct isci_remote_device *idev = _dev; + + BUG_ON(idev->started_request_count != 0); + sci_change_state(&idev->sm, SCI_DEV_STOPPED); +} + +enum sci_status sci_remote_device_terminate_requests( + struct isci_remote_device *idev) +{ + return sci_remote_device_terminate_reqs_checkabort(idev, 0); +} + enum sci_status sci_remote_device_stop(struct isci_remote_device *idev, u32 timeout) { @@ -201,13 +369,16 @@ enum sci_status sci_remote_device_stop(struct isci_remote_device *idev, case SCI_SMP_DEV_IDLE: case SCI_SMP_DEV_CMD: sci_change_state(sm, SCI_DEV_STOPPING); - if (idev->started_request_count == 0) { + if (idev->started_request_count == 0) sci_remote_node_context_destruct(&idev->rnc, - rnc_destruct_done, idev); - return SCI_SUCCESS; - } else - return sci_remote_device_terminate_requests(idev); - break; + rnc_destruct_done, + idev); + else { + sci_remote_device_suspend( + idev, SCI_SW_SUSPEND_LINKHANG_DETECT); + sci_remote_device_terminate_requests(idev); + } + return SCI_SUCCESS; case SCI_DEV_STOPPING: /* All requests should have been terminated, but if there is an * attempt to stop a device already in the stopping state, then @@ -265,22 +436,6 @@ enum sci_status sci_remote_device_reset_complete(struct isci_remote_device *idev return SCI_SUCCESS; } -enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev, - u32 suspend_type) -{ - struct sci_base_state_machine *sm = &idev->sm; - enum sci_remote_device_states state = sm->current_state_id; - - if (state != SCI_STP_DEV_CMD) { - dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n", - __func__, dev_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - } - - return sci_remote_node_context_suspend(&idev->rnc, - suspend_type, NULL, NULL); -} - enum sci_status sci_remote_device_frame_handler(struct isci_remote_device *idev, u32 frame_index) { @@ -412,9 +567,9 @@ static void atapi_remote_device_resume_done(void *_dev) enum sci_status sci_remote_device_event_handler(struct isci_remote_device *idev, u32 event_code) { + enum sci_status status; struct sci_base_state_machine *sm = &idev->sm; enum sci_remote_device_states state = sm->current_state_id; - enum sci_status status; switch (scu_get_event_type(event_code)) { case SCU_EVENT_TYPE_RNC_OPS_MISC: @@ -427,9 +582,7 @@ enum sci_status sci_remote_device_event_handler(struct isci_remote_device *idev, status = SCI_SUCCESS; /* Suspend the associated RNC */ - sci_remote_node_context_suspend(&idev->rnc, - SCI_SOFTWARE_SUSPENSION, - NULL, NULL); + sci_remote_device_suspend(idev, SCI_SW_SUSPEND_NORMAL); dev_dbg(scirdev_to_dev(idev), "%s: device: %p event code: %x: %s\n", @@ -455,6 +608,10 @@ enum sci_status sci_remote_device_event_handler(struct isci_remote_device *idev, if (status != SCI_SUCCESS) return status; + /* Decode device-specific states that may require an RNC resume during + * normal operation. When the abort path is active, these resumes are + * managed when the abort path exits. + */ if (state == SCI_STP_DEV_ATAPI_ERROR) { /* For ATAPI error state resume the RNC right away. */ if (scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX || @@ -743,10 +900,6 @@ enum sci_status sci_remote_device_start_task(struct isci_host *ihost, if (status != SCI_SUCCESS) return status; - status = sci_remote_node_context_start_task(&idev->rnc, ireq); - if (status != SCI_SUCCESS) - goto out; - status = sci_request_start(ireq); if (status != SCI_SUCCESS) goto out; @@ -765,11 +918,11 @@ enum sci_status sci_remote_device_start_task(struct isci_host *ihost, * the correct action when the remote node context is suspended * and later resumed. */ - sci_remote_node_context_suspend(&idev->rnc, - SCI_SOFTWARE_SUSPENSION, NULL, NULL); - sci_remote_node_context_resume(&idev->rnc, - sci_remote_device_continue_request, - idev); + sci_remote_device_suspend(idev, + SCI_SW_SUSPEND_LINKHANG_DETECT); + + status = sci_remote_node_context_start_task(&idev->rnc, ireq, + sci_remote_device_continue_request, idev); out: sci_remote_device_start_request(idev, ireq, status); @@ -783,7 +936,9 @@ enum sci_status sci_remote_device_start_task(struct isci_host *ihost, if (status != SCI_SUCCESS) return status; - status = sci_remote_node_context_start_task(&idev->rnc, ireq); + /* Resume the RNC as needed: */ + status = sci_remote_node_context_start_task(&idev->rnc, ireq, + NULL, NULL); if (status != SCI_SUCCESS) break; @@ -892,7 +1047,7 @@ static void isci_remote_device_deconstruct(struct isci_host *ihost, struct isci_ * here should go through isci_remote_device_nuke_requests. * If we hit this condition, we will need a way to complete * io requests in process */ - BUG_ON(!list_empty(&idev->reqs_in_process)); + BUG_ON(idev->started_request_count > 0); sci_remote_device_destruct(idev); list_del_init(&idev->node); @@ -954,14 +1109,21 @@ static void sci_remote_device_ready_state_exit(struct sci_base_state_machine *sm static void sci_remote_device_resetting_state_enter(struct sci_base_state_machine *sm) { struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm); + struct isci_host *ihost = idev->owning_port->owning_controller; - sci_remote_node_context_suspend( - &idev->rnc, SCI_SOFTWARE_SUSPENSION, NULL, NULL); + dev_dbg(&ihost->pdev->dev, + "%s: isci_device = %p\n", __func__, idev); + + sci_remote_device_suspend(idev, SCI_SW_SUSPEND_LINKHANG_DETECT); } static void sci_remote_device_resetting_state_exit(struct sci_base_state_machine *sm) { struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm); + struct isci_host *ihost = idev->owning_port->owning_controller; + + dev_dbg(&ihost->pdev->dev, + "%s: isci_device = %p\n", __func__, idev); sci_remote_node_context_resume(&idev->rnc, NULL, NULL); } @@ -1113,33 +1275,20 @@ static enum sci_status sci_remote_device_da_construct(struct isci_port *iport, { enum sci_status status; struct sci_port_properties properties; - struct domain_device *dev = idev->domain_dev; sci_remote_device_construct(iport, idev); - /* - * This information is request to determine how many remote node context - * entries will be needed to store the remote node. - */ - idev->is_direct_attached = true; - sci_port_get_properties(iport, &properties); /* Get accurate port width from port's phy mask for a DA device. */ idev->device_port_width = hweight32(properties.phy_mask); status = sci_controller_allocate_remote_node_context(iport->owning_controller, - idev, - &idev->rnc.remote_node_index); + idev, + &idev->rnc.remote_node_index); if (status != SCI_SUCCESS) return status; - if (dev->dev_type == SAS_END_DEV || dev->dev_type == SATA_DEV || - (dev->tproto & SAS_PROTOCOL_STP) || dev_is_expander(dev)) - /* pass */; - else - return SCI_FAILURE_UNSUPPORTED_PROTOCOL; - idev->connection_rate = sci_port_get_max_allowed_speed(iport); return SCI_SUCCESS; @@ -1171,19 +1320,13 @@ static enum sci_status sci_remote_device_ea_construct(struct isci_port *iport, if (status != SCI_SUCCESS) return status; - if (dev->dev_type == SAS_END_DEV || dev->dev_type == SATA_DEV || - (dev->tproto & SAS_PROTOCOL_STP) || dev_is_expander(dev)) - /* pass */; - else - return SCI_FAILURE_UNSUPPORTED_PROTOCOL; - - /* - * For SAS-2 the physical link rate is actually a logical link + /* For SAS-2 the physical link rate is actually a logical link * rate that incorporates multiplexing. The SCU doesn't * incorporate multiplexing and for the purposes of the * connection the logical link rate is that same as the * physical. Furthermore, the SAS-2 and SAS-1.1 fields overlay - * one another, so this code works for both situations. */ + * one another, so this code works for both situations. + */ idev->connection_rate = min_t(u16, sci_port_get_max_allowed_speed(iport), dev->linkrate); @@ -1193,6 +1336,105 @@ static enum sci_status sci_remote_device_ea_construct(struct isci_port *iport, return SCI_SUCCESS; } +enum sci_status sci_remote_device_resume( + struct isci_remote_device *idev, + scics_sds_remote_node_context_callback cb_fn, + void *cb_p) +{ + enum sci_status status; + + status = sci_remote_node_context_resume(&idev->rnc, cb_fn, cb_p); + if (status != SCI_SUCCESS) + dev_dbg(scirdev_to_dev(idev), "%s: failed to resume: %d\n", + __func__, status); + return status; +} + +static void isci_remote_device_resume_from_abort_complete(void *cbparam) +{ + struct isci_remote_device *idev = cbparam; + struct isci_host *ihost = idev->owning_port->owning_controller; + scics_sds_remote_node_context_callback abort_resume_cb = + idev->abort_resume_cb; + + dev_dbg(scirdev_to_dev(idev), "%s: passing-along resume: %p\n", + __func__, abort_resume_cb); + + if (abort_resume_cb != NULL) { + idev->abort_resume_cb = NULL; + abort_resume_cb(idev->abort_resume_cbparam); + } + clear_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags); + wake_up(&ihost->eventq); +} + +static bool isci_remote_device_test_resume_done( + struct isci_host *ihost, + struct isci_remote_device *idev) +{ + unsigned long flags; + bool done; + + spin_lock_irqsave(&ihost->scic_lock, flags); + done = !test_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags) + || test_bit(IDEV_STOP_PENDING, &idev->flags) + || sci_remote_node_context_is_being_destroyed(&idev->rnc); + spin_unlock_irqrestore(&ihost->scic_lock, flags); + + return done; +} + +void isci_remote_device_wait_for_resume_from_abort( + struct isci_host *ihost, + struct isci_remote_device *idev) +{ + dev_dbg(&ihost->pdev->dev, "%s: starting resume wait: %p\n", + __func__, idev); + + #define MAX_RESUME_MSECS 10000 + if (!wait_event_timeout(ihost->eventq, + isci_remote_device_test_resume_done(ihost, idev), + msecs_to_jiffies(MAX_RESUME_MSECS))) { + + dev_warn(&ihost->pdev->dev, "%s: #### Timeout waiting for " + "resume: %p\n", __func__, idev); + } + clear_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags); + + dev_dbg(&ihost->pdev->dev, "%s: resume wait done: %p\n", + __func__, idev); +} + +enum sci_status isci_remote_device_resume_from_abort( + struct isci_host *ihost, + struct isci_remote_device *idev) +{ + unsigned long flags; + enum sci_status status = SCI_SUCCESS; + int destroyed; + + spin_lock_irqsave(&ihost->scic_lock, flags); + /* Preserve any current resume callbacks, for instance from other + * resumptions. + */ + idev->abort_resume_cb = idev->rnc.user_callback; + idev->abort_resume_cbparam = idev->rnc.user_cookie; + set_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags); + clear_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags); + destroyed = sci_remote_node_context_is_being_destroyed(&idev->rnc); + if (!destroyed) + status = sci_remote_device_resume( + idev, isci_remote_device_resume_from_abort_complete, + idev); + spin_unlock_irqrestore(&ihost->scic_lock, flags); + if (!destroyed && (status == SCI_SUCCESS)) + isci_remote_device_wait_for_resume_from_abort(ihost, idev); + else + clear_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags); + + return status; +} + /** * sci_remote_device_start() - This method will start the supplied remote * device. This method enables normal IO requests to flow through to the @@ -1207,7 +1449,7 @@ static enum sci_status sci_remote_device_ea_construct(struct isci_port *iport, * the device when there have been no phys added to it. */ static enum sci_status sci_remote_device_start(struct isci_remote_device *idev, - u32 timeout) + u32 timeout) { struct sci_base_state_machine *sm = &idev->sm; enum sci_remote_device_states state = sm->current_state_id; @@ -1219,9 +1461,8 @@ static enum sci_status sci_remote_device_start(struct isci_remote_device *idev, return SCI_FAILURE_INVALID_STATE; } - status = sci_remote_node_context_resume(&idev->rnc, - remote_device_resume_done, - idev); + status = sci_remote_device_resume(idev, remote_device_resume_done, + idev); if (status != SCI_SUCCESS) return status; @@ -1259,20 +1500,6 @@ static enum sci_status isci_remote_device_construct(struct isci_port *iport, return status; } -void isci_remote_device_nuke_requests(struct isci_host *ihost, struct isci_remote_device *idev) -{ - DECLARE_COMPLETION_ONSTACK(aborted_task_completion); - - dev_dbg(&ihost->pdev->dev, - "%s: idev = %p\n", __func__, idev); - - /* Cleanup all requests pending for this device. */ - isci_terminate_pending_requests(ihost, idev); - - dev_dbg(&ihost->pdev->dev, - "%s: idev = %p, done\n", __func__, idev); -} - /** * This function builds the isci_remote_device when a libsas dev_found message * is received. @@ -1297,10 +1524,6 @@ isci_remote_device_alloc(struct isci_host *ihost, struct isci_port *iport) dev_warn(&ihost->pdev->dev, "%s: failed\n", __func__); return NULL; } - - if (WARN_ONCE(!list_empty(&idev->reqs_in_process), "found requests in process\n")) - return NULL; - if (WARN_ONCE(!list_empty(&idev->node), "found non-idle remote device\n")) return NULL; @@ -1342,14 +1565,8 @@ enum sci_status isci_remote_device_stop(struct isci_host *ihost, struct isci_rem spin_lock_irqsave(&ihost->scic_lock, flags); idev->domain_dev->lldd_dev = NULL; /* disable new lookups */ set_bit(IDEV_GONE, &idev->flags); - spin_unlock_irqrestore(&ihost->scic_lock, flags); - - /* Kill all outstanding requests. */ - isci_remote_device_nuke_requests(ihost, idev); set_bit(IDEV_STOP_PENDING, &idev->flags); - - spin_lock_irqsave(&ihost->scic_lock, flags); status = sci_remote_device_stop(idev, 50); spin_unlock_irqrestore(&ihost->scic_lock, flags); @@ -1359,6 +1576,9 @@ enum sci_status isci_remote_device_stop(struct isci_host *ihost, struct isci_rem else wait_for_device_stop(ihost, idev); + dev_dbg(&ihost->pdev->dev, + "%s: isci_device = %p, waiting done.\n", __func__, idev); + return status; } @@ -1434,3 +1654,73 @@ int isci_remote_device_found(struct domain_device *dev) return status == SCI_SUCCESS ? 0 : -ENODEV; } + +enum sci_status isci_remote_device_suspend_terminate( + struct isci_host *ihost, + struct isci_remote_device *idev, + struct isci_request *ireq) +{ + unsigned long flags; + enum sci_status status; + + /* Put the device into suspension. */ + spin_lock_irqsave(&ihost->scic_lock, flags); + set_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags); + sci_remote_device_suspend(idev, SCI_SW_SUSPEND_LINKHANG_DETECT); + spin_unlock_irqrestore(&ihost->scic_lock, flags); + + /* Terminate and wait for the completions. */ + status = isci_remote_device_terminate_requests(ihost, idev, ireq); + if (status != SCI_SUCCESS) + dev_dbg(&ihost->pdev->dev, + "%s: isci_remote_device_terminate_requests(%p) " + "returned %d!\n", + __func__, idev, status); + + /* NOTE: RNC resumption is left to the caller! */ + return status; +} + +int isci_remote_device_is_safe_to_abort( + struct isci_remote_device *idev) +{ + return sci_remote_node_context_is_safe_to_abort(&idev->rnc); +} + +enum sci_status sci_remote_device_abort_requests_pending_abort( + struct isci_remote_device *idev) +{ + return sci_remote_device_terminate_reqs_checkabort(idev, 1); +} + +enum sci_status isci_remote_device_reset_complete( + struct isci_host *ihost, + struct isci_remote_device *idev) +{ + unsigned long flags; + enum sci_status status; + + spin_lock_irqsave(&ihost->scic_lock, flags); + status = sci_remote_device_reset_complete(idev); + spin_unlock_irqrestore(&ihost->scic_lock, flags); + + return status; +} + +void isci_dev_set_hang_detection_timeout( + struct isci_remote_device *idev, + u32 timeout) +{ + if (dev_is_sata(idev->domain_dev)) { + if (timeout) { + if (test_and_set_bit(IDEV_RNC_LLHANG_ENABLED, + &idev->flags)) + return; /* Already enabled. */ + } else if (!test_and_clear_bit(IDEV_RNC_LLHANG_ENABLED, + &idev->flags)) + return; /* Not enabled. */ + + sci_port_set_hang_detection_timeout(idev->owning_port, + timeout); + } +} diff --git a/trunk/drivers/scsi/isci/remote_device.h b/trunk/drivers/scsi/isci/remote_device.h index 58637ee08f55..7674caae1d88 100644 --- a/trunk/drivers/scsi/isci/remote_device.h +++ b/trunk/drivers/scsi/isci/remote_device.h @@ -85,27 +85,38 @@ struct isci_remote_device { #define IDEV_GONE 3 #define IDEV_IO_READY 4 #define IDEV_IO_NCQERROR 5 + #define IDEV_RNC_LLHANG_ENABLED 6 + #define IDEV_ABORT_PATH_ACTIVE 7 + #define IDEV_ABORT_PATH_RESUME_PENDING 8 unsigned long flags; struct kref kref; struct isci_port *isci_port; struct domain_device *domain_dev; struct list_head node; - struct list_head reqs_in_process; struct sci_base_state_machine sm; u32 device_port_width; enum sas_linkrate connection_rate; - bool is_direct_attached; struct isci_port *owning_port; struct sci_remote_node_context rnc; /* XXX unify with device reference counting and delete */ u32 started_request_count; struct isci_request *working_request; u32 not_ready_reason; + scics_sds_remote_node_context_callback abort_resume_cb; + void *abort_resume_cbparam; }; #define ISCI_REMOTE_DEVICE_START_TIMEOUT 5000 /* device reference routines must be called under sci_lock */ +static inline struct isci_remote_device *isci_get_device( + struct isci_remote_device *idev) +{ + if (idev) + kref_get(&idev->kref); + return idev; +} + static inline struct isci_remote_device *isci_lookup_device(struct domain_device *dev) { struct isci_remote_device *idev = dev->lldd_dev; @@ -302,6 +313,8 @@ static inline void sci_remote_device_decrement_request_count(struct isci_remote_ idev->started_request_count--; } +void isci_dev_set_hang_detection_timeout(struct isci_remote_device *idev, u32 timeout); + enum sci_status sci_remote_device_frame_handler( struct isci_remote_device *idev, u32 frame_index); @@ -325,12 +338,50 @@ enum sci_status sci_remote_device_complete_io( struct isci_remote_device *idev, struct isci_request *ireq); -enum sci_status sci_remote_device_suspend( - struct isci_remote_device *idev, - u32 suspend_type); - void sci_remote_device_post_request( struct isci_remote_device *idev, u32 request); +enum sci_status sci_remote_device_terminate_requests( + struct isci_remote_device *idev); + +int isci_remote_device_is_safe_to_abort( + struct isci_remote_device *idev); + +enum sci_status +sci_remote_device_abort_requests_pending_abort( + struct isci_remote_device *idev); + +enum sci_status isci_remote_device_suspend( + struct isci_host *ihost, + struct isci_remote_device *idev); + +enum sci_status sci_remote_device_resume( + struct isci_remote_device *idev, + scics_sds_remote_node_context_callback cb_fn, + void *cb_p); + +enum sci_status isci_remote_device_resume_from_abort( + struct isci_host *ihost, + struct isci_remote_device *idev); + +enum sci_status isci_remote_device_reset( + struct isci_host *ihost, + struct isci_remote_device *idev); + +enum sci_status isci_remote_device_reset_complete( + struct isci_host *ihost, + struct isci_remote_device *idev); + +enum sci_status isci_remote_device_suspend_terminate( + struct isci_host *ihost, + struct isci_remote_device *idev, + struct isci_request *ireq); + +enum sci_status isci_remote_device_terminate_requests( + struct isci_host *ihost, + struct isci_remote_device *idev, + struct isci_request *ireq); +enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev, + enum sci_remote_node_suspension_reasons reason); #endif /* !defined(_ISCI_REMOTE_DEVICE_H_) */ diff --git a/trunk/drivers/scsi/isci/remote_node_context.c b/trunk/drivers/scsi/isci/remote_node_context.c index 3a9463481f38..1910100638a2 100644 --- a/trunk/drivers/scsi/isci/remote_node_context.c +++ b/trunk/drivers/scsi/isci/remote_node_context.c @@ -52,7 +52,7 @@ * (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 #include "host.h" #include "isci.h" #include "remote_device.h" @@ -90,6 +90,15 @@ bool sci_remote_node_context_is_ready( return false; } +bool sci_remote_node_context_is_suspended(struct sci_remote_node_context *sci_rnc) +{ + u32 current_state = sci_rnc->sm.current_state_id; + + if (current_state == SCI_RNC_TX_RX_SUSPENDED) + return true; + return false; +} + static union scu_remote_node_context *sci_rnc_by_id(struct isci_host *ihost, u16 id) { if (id < ihost->remote_node_entries && @@ -131,7 +140,7 @@ static void sci_remote_node_context_construct_buffer(struct sci_remote_node_cont rnc->ssp.arbitration_wait_time = 0; - if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) { + if (dev_is_sata(dev)) { rnc->ssp.connection_occupancy_timeout = ihost->user_parameters.stp_max_occupancy_timeout; rnc->ssp.connection_inactivity_timeout = @@ -151,7 +160,6 @@ static void sci_remote_node_context_construct_buffer(struct sci_remote_node_cont rnc->ssp.oaf_source_zone_group = 0; rnc->ssp.oaf_more_compatibility_features = 0; } - /** * * @sci_rnc: @@ -165,23 +173,30 @@ static void sci_remote_node_context_construct_buffer(struct sci_remote_node_cont static void sci_remote_node_context_setup_to_resume( struct sci_remote_node_context *sci_rnc, scics_sds_remote_node_context_callback callback, - void *callback_parameter) + void *callback_parameter, + enum sci_remote_node_context_destination_state dest_param) { - if (sci_rnc->destination_state != SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL) { - sci_rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY; - sci_rnc->user_callback = callback; - sci_rnc->user_cookie = callback_parameter; + if (sci_rnc->destination_state != RNC_DEST_FINAL) { + sci_rnc->destination_state = dest_param; + if (callback != NULL) { + sci_rnc->user_callback = callback; + sci_rnc->user_cookie = callback_parameter; + } } } -static void sci_remote_node_context_setup_to_destory( +static void sci_remote_node_context_setup_to_destroy( struct sci_remote_node_context *sci_rnc, scics_sds_remote_node_context_callback callback, void *callback_parameter) { - sci_rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL; + struct isci_host *ihost = idev_to_ihost(rnc_to_dev(sci_rnc)); + + sci_rnc->destination_state = RNC_DEST_FINAL; sci_rnc->user_callback = callback; sci_rnc->user_cookie = callback_parameter; + + wake_up(&ihost->eventq); } /** @@ -203,9 +218,19 @@ static void sci_remote_node_context_notify_user( static void sci_remote_node_context_continue_state_transitions(struct sci_remote_node_context *rnc) { - if (rnc->destination_state == SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY) + switch (rnc->destination_state) { + case RNC_DEST_READY: + case RNC_DEST_SUSPENDED_RESUME: + rnc->destination_state = RNC_DEST_READY; + /* Fall through... */ + case RNC_DEST_FINAL: sci_remote_node_context_resume(rnc, rnc->user_callback, - rnc->user_cookie); + rnc->user_cookie); + break; + default: + rnc->destination_state = RNC_DEST_UNSPECIFIED; + break; + } } static void sci_remote_node_context_validate_context_buffer(struct sci_remote_node_context *sci_rnc) @@ -219,13 +244,12 @@ static void sci_remote_node_context_validate_context_buffer(struct sci_remote_no rnc_buffer->ssp.is_valid = true; - if (!idev->is_direct_attached && - (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP))) { + if (dev_is_sata(dev) && dev->parent) { sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_96); } else { sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_32); - if (idev->is_direct_attached) + if (!dev->parent) sci_port_setup_transports(idev->owning_port, sci_rnc->remote_node_index); } @@ -248,13 +272,18 @@ static void sci_remote_node_context_invalidate_context_buffer(struct sci_remote_ static void sci_remote_node_context_initial_state_enter(struct sci_base_state_machine *sm) { struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm); + struct isci_remote_device *idev = rnc_to_dev(rnc); + struct isci_host *ihost = idev->owning_port->owning_controller; /* Check to see if we have gotten back to the initial state because * someone requested to destroy the remote node context object. */ if (sm->previous_state_id == SCI_RNC_INVALIDATING) { - rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED; + rnc->destination_state = RNC_DEST_UNSPECIFIED; sci_remote_node_context_notify_user(rnc); + + smp_wmb(); + wake_up(&ihost->eventq); } } @@ -269,6 +298,8 @@ static void sci_remote_node_context_invalidating_state_enter(struct sci_base_sta { struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm); + /* Terminate all outstanding requests. */ + sci_remote_device_terminate_requests(rnc_to_dev(rnc)); sci_remote_node_context_invalidate_context_buffer(rnc); } @@ -287,10 +318,8 @@ static void sci_remote_node_context_resuming_state_enter(struct sci_base_state_m * resume because of a target reset we also need to update * the STPTLDARNI register with the RNi of the device */ - if ((dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) && - idev->is_direct_attached) - sci_port_setup_transports(idev->owning_port, - rnc->remote_node_index); + if (dev_is_sata(dev) && !dev->parent) + sci_port_setup_transports(idev->owning_port, rnc->remote_node_index); sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_RESUME); } @@ -298,10 +327,22 @@ static void sci_remote_node_context_resuming_state_enter(struct sci_base_state_m static void sci_remote_node_context_ready_state_enter(struct sci_base_state_machine *sm) { struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm); + enum sci_remote_node_context_destination_state dest_select; + int tell_user = 1; + + dest_select = rnc->destination_state; + rnc->destination_state = RNC_DEST_UNSPECIFIED; - rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED; + if ((dest_select == RNC_DEST_SUSPENDED) || + (dest_select == RNC_DEST_SUSPENDED_RESUME)) { + sci_remote_node_context_suspend( + rnc, rnc->suspend_reason, + SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT); - if (rnc->user_callback) + if (dest_select == RNC_DEST_SUSPENDED_RESUME) + tell_user = 0; /* Wait until ready again. */ + } + if (tell_user) sci_remote_node_context_notify_user(rnc); } @@ -315,10 +356,34 @@ static void sci_remote_node_context_tx_suspended_state_enter(struct sci_base_sta static void sci_remote_node_context_tx_rx_suspended_state_enter(struct sci_base_state_machine *sm) { struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm); + struct isci_remote_device *idev = rnc_to_dev(rnc); + struct isci_host *ihost = idev->owning_port->owning_controller; + u32 new_count = rnc->suspend_count + 1; + + if (new_count == 0) + rnc->suspend_count = 1; + else + rnc->suspend_count = new_count; + smp_wmb(); + /* Terminate outstanding requests pending abort. */ + sci_remote_device_abort_requests_pending_abort(idev); + + wake_up(&ihost->eventq); sci_remote_node_context_continue_state_transitions(rnc); } +static void sci_remote_node_context_await_suspend_state_exit( + struct sci_base_state_machine *sm) +{ + struct sci_remote_node_context *rnc + = container_of(sm, typeof(*rnc), sm); + struct isci_remote_device *idev = rnc_to_dev(rnc); + + if (dev_is_sata(idev->domain_dev)) + isci_dev_set_hang_detection_timeout(idev, 0); +} + static const struct sci_base_state sci_remote_node_context_state_table[] = { [SCI_RNC_INITIAL] = { .enter_state = sci_remote_node_context_initial_state_enter, @@ -341,7 +406,9 @@ static const struct sci_base_state sci_remote_node_context_state_table[] = { [SCI_RNC_TX_RX_SUSPENDED] = { .enter_state = sci_remote_node_context_tx_rx_suspended_state_enter, }, - [SCI_RNC_AWAIT_SUSPENSION] = { }, + [SCI_RNC_AWAIT_SUSPENSION] = { + .exit_state = sci_remote_node_context_await_suspend_state_exit, + }, }; void sci_remote_node_context_construct(struct sci_remote_node_context *rnc, @@ -350,7 +417,7 @@ void sci_remote_node_context_construct(struct sci_remote_node_context *rnc, memset(rnc, 0, sizeof(struct sci_remote_node_context)); rnc->remote_node_index = remote_node_index; - rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED; + rnc->destination_state = RNC_DEST_UNSPECIFIED; sci_init_sm(&rnc->sm, sci_remote_node_context_state_table, SCI_RNC_INITIAL); } @@ -359,6 +426,7 @@ enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_con u32 event_code) { enum scis_sds_remote_node_context_states state; + u32 next_state; state = sci_rnc->sm.current_state_id; switch (state) { @@ -373,18 +441,18 @@ enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_con break; case SCI_RNC_INVALIDATING: if (scu_get_event_code(event_code) == SCU_EVENT_POST_RNC_INVALIDATE_COMPLETE) { - if (sci_rnc->destination_state == SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL) - state = SCI_RNC_INITIAL; + if (sci_rnc->destination_state == RNC_DEST_FINAL) + next_state = SCI_RNC_INITIAL; else - state = SCI_RNC_POSTING; - sci_change_state(&sci_rnc->sm, state); + next_state = SCI_RNC_POSTING; + sci_change_state(&sci_rnc->sm, next_state); } else { switch (scu_get_event_type(event_code)) { case SCU_EVENT_TYPE_RNC_SUSPEND_TX: case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX: /* We really dont care if the hardware is going to suspend * the device since it's being invalidated anyway */ - dev_dbg(scirdev_to_dev(rnc_to_dev(sci_rnc)), + dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), "%s: SCIC Remote Node Context 0x%p was " "suspeneded by hardware while being " "invalidated.\n", __func__, sci_rnc); @@ -403,7 +471,7 @@ enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_con case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX: /* We really dont care if the hardware is going to suspend * the device since it's being resumed anyway */ - dev_dbg(scirdev_to_dev(rnc_to_dev(sci_rnc)), + dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), "%s: SCIC Remote Node Context 0x%p was " "suspeneded by hardware while being resumed.\n", __func__, sci_rnc); @@ -417,11 +485,11 @@ enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_con switch (scu_get_event_type(event_code)) { case SCU_EVENT_TL_RNC_SUSPEND_TX: sci_change_state(&sci_rnc->sm, SCI_RNC_TX_SUSPENDED); - sci_rnc->suspension_code = scu_get_event_specifier(event_code); + sci_rnc->suspend_type = scu_get_event_type(event_code); break; case SCU_EVENT_TL_RNC_SUSPEND_TX_RX: sci_change_state(&sci_rnc->sm, SCI_RNC_TX_RX_SUSPENDED); - sci_rnc->suspension_code = scu_get_event_specifier(event_code); + sci_rnc->suspend_type = scu_get_event_type(event_code); break; default: goto out; @@ -430,27 +498,29 @@ enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_con case SCI_RNC_AWAIT_SUSPENSION: switch (scu_get_event_type(event_code)) { case SCU_EVENT_TL_RNC_SUSPEND_TX: - sci_change_state(&sci_rnc->sm, SCI_RNC_TX_SUSPENDED); - sci_rnc->suspension_code = scu_get_event_specifier(event_code); + next_state = SCI_RNC_TX_SUSPENDED; break; case SCU_EVENT_TL_RNC_SUSPEND_TX_RX: - sci_change_state(&sci_rnc->sm, SCI_RNC_TX_RX_SUSPENDED); - sci_rnc->suspension_code = scu_get_event_specifier(event_code); + next_state = SCI_RNC_TX_RX_SUSPENDED; break; default: goto out; } + if (sci_rnc->suspend_type == scu_get_event_type(event_code)) + sci_change_state(&sci_rnc->sm, next_state); break; default: dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), - "%s: invalid state %d\n", __func__, state); + "%s: invalid state: %s\n", __func__, + rnc_state_name(state)); return SCI_FAILURE_INVALID_STATE; } return SCI_SUCCESS; out: dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), - "%s: code: %#x state: %d\n", __func__, event_code, state); + "%s: code: %#x state: %s\n", __func__, event_code, + rnc_state_name(state)); return SCI_FAILURE; } @@ -464,20 +534,23 @@ enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context state = sci_rnc->sm.current_state_id; switch (state) { case SCI_RNC_INVALIDATING: - sci_remote_node_context_setup_to_destory(sci_rnc, cb_fn, cb_p); + sci_remote_node_context_setup_to_destroy(sci_rnc, cb_fn, cb_p); return SCI_SUCCESS; case SCI_RNC_POSTING: case SCI_RNC_RESUMING: case SCI_RNC_READY: case SCI_RNC_TX_SUSPENDED: case SCI_RNC_TX_RX_SUSPENDED: - case SCI_RNC_AWAIT_SUSPENSION: - sci_remote_node_context_setup_to_destory(sci_rnc, cb_fn, cb_p); + sci_remote_node_context_setup_to_destroy(sci_rnc, cb_fn, cb_p); sci_change_state(&sci_rnc->sm, SCI_RNC_INVALIDATING); return SCI_SUCCESS; + case SCI_RNC_AWAIT_SUSPENSION: + sci_remote_node_context_setup_to_destroy(sci_rnc, cb_fn, cb_p); + return SCI_SUCCESS; case SCI_RNC_INITIAL: dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), - "%s: invalid state %d\n", __func__, state); + "%s: invalid state: %s\n", __func__, + rnc_state_name(state)); /* We have decided that the destruct request on the remote node context * can not fail since it is either in the initial/destroyed state or is * can be destroyed. @@ -485,35 +558,101 @@ enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context return SCI_SUCCESS; default: dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), - "%s: invalid state %d\n", __func__, state); + "%s: invalid state %s\n", __func__, + rnc_state_name(state)); return SCI_FAILURE_INVALID_STATE; } } -enum sci_status sci_remote_node_context_suspend(struct sci_remote_node_context *sci_rnc, - u32 suspend_type, - scics_sds_remote_node_context_callback cb_fn, - void *cb_p) +enum sci_status sci_remote_node_context_suspend( + struct sci_remote_node_context *sci_rnc, + enum sci_remote_node_suspension_reasons suspend_reason, + u32 suspend_type) { - enum scis_sds_remote_node_context_states state; + enum scis_sds_remote_node_context_states state + = sci_rnc->sm.current_state_id; + struct isci_remote_device *idev = rnc_to_dev(sci_rnc); + enum sci_status status = SCI_FAILURE_INVALID_STATE; + enum sci_remote_node_context_destination_state dest_param = + RNC_DEST_UNSPECIFIED; + + dev_dbg(scirdev_to_dev(idev), + "%s: current state %s, current suspend_type %x dest state %d," + " arg suspend_reason %d, arg suspend_type %x", + __func__, rnc_state_name(state), sci_rnc->suspend_type, + sci_rnc->destination_state, suspend_reason, + suspend_type); + + /* Disable automatic state continuations if explicitly suspending. */ + if ((suspend_reason == SCI_HW_SUSPEND) || + (sci_rnc->destination_state == RNC_DEST_FINAL)) + dest_param = sci_rnc->destination_state; - state = sci_rnc->sm.current_state_id; - if (state != SCI_RNC_READY) { + switch (state) { + case SCI_RNC_READY: + break; + case SCI_RNC_INVALIDATING: + if (sci_rnc->destination_state == RNC_DEST_FINAL) { + dev_warn(scirdev_to_dev(idev), + "%s: already destroying %p\n", + __func__, sci_rnc); + return SCI_FAILURE_INVALID_STATE; + } + /* Fall through and handle like SCI_RNC_POSTING */ + case SCI_RNC_RESUMING: + /* Fall through and handle like SCI_RNC_POSTING */ + case SCI_RNC_POSTING: + /* Set the destination state to AWAIT - this signals the + * entry into the SCI_RNC_READY state that a suspension + * needs to be done immediately. + */ + if (sci_rnc->destination_state != RNC_DEST_FINAL) + sci_rnc->destination_state = RNC_DEST_SUSPENDED; + sci_rnc->suspend_type = suspend_type; + sci_rnc->suspend_reason = suspend_reason; + return SCI_SUCCESS; + + case SCI_RNC_TX_SUSPENDED: + if (suspend_type == SCU_EVENT_TL_RNC_SUSPEND_TX) + status = SCI_SUCCESS; + break; + case SCI_RNC_TX_RX_SUSPENDED: + if (suspend_type == SCU_EVENT_TL_RNC_SUSPEND_TX_RX) + status = SCI_SUCCESS; + break; + case SCI_RNC_AWAIT_SUSPENSION: + if ((sci_rnc->suspend_type == SCU_EVENT_TL_RNC_SUSPEND_TX_RX) + || (suspend_type == sci_rnc->suspend_type)) + return SCI_SUCCESS; + break; + default: dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), - "%s: invalid state %d\n", __func__, state); + "%s: invalid state %s\n", __func__, + rnc_state_name(state)); return SCI_FAILURE_INVALID_STATE; } + sci_rnc->destination_state = dest_param; + sci_rnc->suspend_type = suspend_type; + sci_rnc->suspend_reason = suspend_reason; + + if (status == SCI_SUCCESS) { /* Already in the destination state? */ + struct isci_host *ihost = idev->owning_port->owning_controller; + + wake_up_all(&ihost->eventq); /* Let observers look. */ + return SCI_SUCCESS; + } + if ((suspend_reason == SCI_SW_SUSPEND_NORMAL) || + (suspend_reason == SCI_SW_SUSPEND_LINKHANG_DETECT)) { - sci_rnc->user_callback = cb_fn; - sci_rnc->user_cookie = cb_p; - sci_rnc->suspension_code = suspend_type; + if (suspend_reason == SCI_SW_SUSPEND_LINKHANG_DETECT) + isci_dev_set_hang_detection_timeout(idev, 0x00000001); - if (suspend_type == SCI_SOFTWARE_SUSPENSION) { - sci_remote_device_post_request(rnc_to_dev(sci_rnc), - SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX); + sci_remote_device_post_request( + idev, SCI_SOFTWARE_SUSPEND_CMD); } + if (state != SCI_RNC_AWAIT_SUSPENSION) + sci_change_state(&sci_rnc->sm, SCI_RNC_AWAIT_SUSPENSION); - sci_change_state(&sci_rnc->sm, SCI_RNC_AWAIT_SUSPENSION); return SCI_SUCCESS; } @@ -522,56 +661,86 @@ enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *s void *cb_p) { enum scis_sds_remote_node_context_states state; + struct isci_remote_device *idev = rnc_to_dev(sci_rnc); state = sci_rnc->sm.current_state_id; + dev_dbg(scirdev_to_dev(idev), + "%s: state %s, cb_fn = %p, cb_p = %p; dest_state = %d; " + "dev resume path %s\n", + __func__, rnc_state_name(state), cb_fn, cb_p, + sci_rnc->destination_state, + test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags) + ? "" : ""); + switch (state) { case SCI_RNC_INITIAL: if (sci_rnc->remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) return SCI_FAILURE_INVALID_STATE; - sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p); - sci_remote_node_context_construct_buffer(sci_rnc); - sci_change_state(&sci_rnc->sm, SCI_RNC_POSTING); + sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p, + RNC_DEST_READY); + if (!test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags)) { + sci_remote_node_context_construct_buffer(sci_rnc); + sci_change_state(&sci_rnc->sm, SCI_RNC_POSTING); + } return SCI_SUCCESS; + case SCI_RNC_POSTING: case SCI_RNC_INVALIDATING: case SCI_RNC_RESUMING: - if (sci_rnc->destination_state != SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY) - return SCI_FAILURE_INVALID_STATE; - - sci_rnc->user_callback = cb_fn; - sci_rnc->user_cookie = cb_p; + /* We are still waiting to post when a resume was + * requested. + */ + switch (sci_rnc->destination_state) { + case RNC_DEST_SUSPENDED: + case RNC_DEST_SUSPENDED_RESUME: + /* Previously waiting to suspend after posting. + * Now continue onto resumption. + */ + sci_remote_node_context_setup_to_resume( + sci_rnc, cb_fn, cb_p, + RNC_DEST_SUSPENDED_RESUME); + break; + default: + sci_remote_node_context_setup_to_resume( + sci_rnc, cb_fn, cb_p, + RNC_DEST_READY); + break; + } return SCI_SUCCESS; - case SCI_RNC_TX_SUSPENDED: { - struct isci_remote_device *idev = rnc_to_dev(sci_rnc); - struct domain_device *dev = idev->domain_dev; - - sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p); - - /* TODO: consider adding a resume action of NONE, INVALIDATE, WRITE_TLCR */ - if (dev->dev_type == SAS_END_DEV || dev_is_expander(dev)) - sci_change_state(&sci_rnc->sm, SCI_RNC_RESUMING); - else if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) { - if (idev->is_direct_attached) { - /* @todo Fix this since I am being silly in writing to the STPTLDARNI register. */ - sci_change_state(&sci_rnc->sm, SCI_RNC_RESUMING); - } else { - sci_change_state(&sci_rnc->sm, SCI_RNC_INVALIDATING); + + case SCI_RNC_TX_SUSPENDED: + case SCI_RNC_TX_RX_SUSPENDED: + { + struct domain_device *dev = idev->domain_dev; + /* If this is an expander attached SATA device we must + * invalidate and repost the RNC since this is the only + * way to clear the TCi to NCQ tag mapping table for + * the RNi. All other device types we can just resume. + */ + sci_remote_node_context_setup_to_resume( + sci_rnc, cb_fn, cb_p, RNC_DEST_READY); + + if (!test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags)) { + if ((dev_is_sata(dev) && dev->parent) || + (sci_rnc->destination_state == RNC_DEST_FINAL)) + sci_change_state(&sci_rnc->sm, + SCI_RNC_INVALIDATING); + else + sci_change_state(&sci_rnc->sm, + SCI_RNC_RESUMING); } - } else - return SCI_FAILURE; + } return SCI_SUCCESS; - } - case SCI_RNC_TX_RX_SUSPENDED: - sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p); - sci_change_state(&sci_rnc->sm, SCI_RNC_RESUMING); - return SCI_FAILURE_INVALID_STATE; + case SCI_RNC_AWAIT_SUSPENSION: - sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p); + sci_remote_node_context_setup_to_resume( + sci_rnc, cb_fn, cb_p, RNC_DEST_SUSPENDED_RESUME); return SCI_SUCCESS; default: dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), - "%s: invalid state %d\n", __func__, state); + "%s: invalid state %s\n", __func__, + rnc_state_name(state)); return SCI_FAILURE_INVALID_STATE; } } @@ -590,35 +759,51 @@ enum sci_status sci_remote_node_context_start_io(struct sci_remote_node_context case SCI_RNC_TX_RX_SUSPENDED: case SCI_RNC_AWAIT_SUSPENSION: dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), - "%s: invalid state %d\n", __func__, state); + "%s: invalid state %s\n", __func__, + rnc_state_name(state)); return SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED; default: - break; + dev_dbg(scirdev_to_dev(rnc_to_dev(sci_rnc)), + "%s: invalid state %s\n", __func__, + rnc_state_name(state)); + return SCI_FAILURE_INVALID_STATE; } - dev_dbg(scirdev_to_dev(rnc_to_dev(sci_rnc)), - "%s: requested to start IO while still resuming, %d\n", - __func__, state); - return SCI_FAILURE_INVALID_STATE; } -enum sci_status sci_remote_node_context_start_task(struct sci_remote_node_context *sci_rnc, - struct isci_request *ireq) +enum sci_status sci_remote_node_context_start_task( + struct sci_remote_node_context *sci_rnc, + struct isci_request *ireq, + scics_sds_remote_node_context_callback cb_fn, + void *cb_p) +{ + enum sci_status status = sci_remote_node_context_resume(sci_rnc, + cb_fn, cb_p); + if (status != SCI_SUCCESS) + dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), + "%s: resume failed: %d\n", __func__, status); + return status; +} + +int sci_remote_node_context_is_safe_to_abort( + struct sci_remote_node_context *sci_rnc) { enum scis_sds_remote_node_context_states state; state = sci_rnc->sm.current_state_id; switch (state) { + case SCI_RNC_INVALIDATING: + case SCI_RNC_TX_RX_SUSPENDED: + return 1; + case SCI_RNC_POSTING: case SCI_RNC_RESUMING: case SCI_RNC_READY: - case SCI_RNC_AWAIT_SUSPENSION: - return SCI_SUCCESS; case SCI_RNC_TX_SUSPENDED: - case SCI_RNC_TX_RX_SUSPENDED: - sci_remote_node_context_resume(sci_rnc, NULL, NULL); - return SCI_SUCCESS; + case SCI_RNC_AWAIT_SUSPENSION: + case SCI_RNC_INITIAL: + return 0; default: dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), "%s: invalid state %d\n", __func__, state); - return SCI_FAILURE_INVALID_STATE; + return 0; } } diff --git a/trunk/drivers/scsi/isci/remote_node_context.h b/trunk/drivers/scsi/isci/remote_node_context.h index a241e0f4c865..a703b9ce0c2c 100644 --- a/trunk/drivers/scsi/isci/remote_node_context.h +++ b/trunk/drivers/scsi/isci/remote_node_context.h @@ -75,8 +75,13 @@ */ #define SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX 0x0FFF -#define SCU_HARDWARE_SUSPENSION (0) -#define SCI_SOFTWARE_SUSPENSION (1) +enum sci_remote_node_suspension_reasons { + SCI_HW_SUSPEND, + SCI_SW_SUSPEND_NORMAL, + SCI_SW_SUSPEND_LINKHANG_DETECT +}; +#define SCI_SOFTWARE_SUSPEND_CMD SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX_RX +#define SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT SCU_EVENT_TL_RNC_SUSPEND_TX_RX struct isci_request; struct isci_remote_device; @@ -137,9 +142,13 @@ const char *rnc_state_name(enum scis_sds_remote_node_context_states state); * node context. */ enum sci_remote_node_context_destination_state { - SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED, - SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY, - SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL + RNC_DEST_UNSPECIFIED, + RNC_DEST_READY, + RNC_DEST_FINAL, + RNC_DEST_SUSPENDED, /* Set when suspend during post/invalidate */ + RNC_DEST_SUSPENDED_RESUME /* Set when a resume was done during posting + * or invalidating and already suspending. + */ }; /** @@ -156,10 +165,12 @@ struct sci_remote_node_context { u16 remote_node_index; /** - * This field is the recored suspension code or the reason for the remote node + * This field is the recored suspension type of the remote node * context suspension. */ - u32 suspension_code; + u32 suspend_type; + enum sci_remote_node_suspension_reasons suspend_reason; + u32 suspend_count; /** * This field is true if the remote node context is resuming from its current @@ -193,6 +204,8 @@ void sci_remote_node_context_construct(struct sci_remote_node_context *rnc, bool sci_remote_node_context_is_ready( struct sci_remote_node_context *sci_rnc); +bool sci_remote_node_context_is_suspended(struct sci_remote_node_context *sci_rnc); + enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_context *sci_rnc, u32 event_code); enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context *sci_rnc, @@ -200,14 +213,24 @@ enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context void *callback_parameter); enum sci_status sci_remote_node_context_suspend(struct sci_remote_node_context *sci_rnc, u32 suspend_type, - scics_sds_remote_node_context_callback cb_fn, - void *cb_p); + u32 suspension_code); enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *sci_rnc, scics_sds_remote_node_context_callback cb_fn, void *cb_p); enum sci_status sci_remote_node_context_start_task(struct sci_remote_node_context *sci_rnc, - struct isci_request *ireq); + struct isci_request *ireq, + scics_sds_remote_node_context_callback cb_fn, + void *cb_p); enum sci_status sci_remote_node_context_start_io(struct sci_remote_node_context *sci_rnc, struct isci_request *ireq); +int sci_remote_node_context_is_safe_to_abort( + struct sci_remote_node_context *sci_rnc); +static inline bool sci_remote_node_context_is_being_destroyed( + struct sci_remote_node_context *sci_rnc) +{ + return (sci_rnc->destination_state == RNC_DEST_FINAL) + || ((sci_rnc->sm.current_state_id == SCI_RNC_INITIAL) + && (sci_rnc->destination_state == RNC_DEST_UNSPECIFIED)); +} #endif /* _SCIC_SDS_REMOTE_NODE_CONTEXT_H_ */ diff --git a/trunk/drivers/scsi/isci/request.c b/trunk/drivers/scsi/isci/request.c index 2def1e3960f6..7a0431c73493 100644 --- a/trunk/drivers/scsi/isci/request.c +++ b/trunk/drivers/scsi/isci/request.c @@ -92,11 +92,11 @@ static dma_addr_t to_sgl_element_pair_dma(struct isci_host *ihost, if (idx == 0) { offset = (void *) &ireq->tc->sgl_pair_ab - (void *) &ihost->task_context_table[0]; - return ihost->task_context_dma + offset; + return ihost->tc_dma + offset; } else if (idx == 1) { offset = (void *) &ireq->tc->sgl_pair_cd - (void *) &ihost->task_context_table[0]; - return ihost->task_context_dma + offset; + return ihost->tc_dma + offset; } return sci_io_request_get_dma_addr(ireq, &ireq->sg_table[idx - 2]); @@ -730,7 +730,7 @@ static enum sci_status sci_io_request_construct_basic_ssp(struct isci_request *i { struct sas_task *task = isci_request_access_task(ireq); - ireq->protocol = SCIC_SSP_PROTOCOL; + ireq->protocol = SAS_PROTOCOL_SSP; scu_ssp_io_request_construct_task_context(ireq, task->data_dir, @@ -763,7 +763,7 @@ static enum sci_status sci_io_request_construct_basic_sata(struct isci_request * bool copy = false; struct sas_task *task = isci_request_access_task(ireq); - ireq->protocol = SCIC_STP_PROTOCOL; + ireq->protocol = SAS_PROTOCOL_STP; copy = (task->data_dir == DMA_NONE) ? false : true; @@ -863,6 +863,8 @@ sci_io_request_terminate(struct isci_request *ireq) switch (state) { case SCI_REQ_CONSTRUCTED: + /* Set to make sure no HW terminate posting is done: */ + set_bit(IREQ_TC_ABORT_POSTED, &ireq->flags); ireq->scu_status = SCU_TASK_DONE_TASK_ABORT; ireq->sci_status = SCI_FAILURE_IO_TERMINATED; sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); @@ -883,8 +885,7 @@ sci_io_request_terminate(struct isci_request *ireq) case SCI_REQ_ATAPI_WAIT_PIO_SETUP: case SCI_REQ_ATAPI_WAIT_D2H: case SCI_REQ_ATAPI_WAIT_TC_COMP: - sci_change_state(&ireq->sm, SCI_REQ_ABORTING); - return SCI_SUCCESS; + /* Fall through and change state to ABORTING... */ case SCI_REQ_TASK_WAIT_TC_RESP: /* The task frame was already confirmed to have been * sent by the SCU HW. Since the state machine is @@ -893,20 +894,21 @@ sci_io_request_terminate(struct isci_request *ireq) * and don't wait for the task response. */ sci_change_state(&ireq->sm, SCI_REQ_ABORTING); - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - return SCI_SUCCESS; + /* Fall through and handle like ABORTING... */ case SCI_REQ_ABORTING: - /* If a request has a termination requested twice, return - * a failure indication, since HW confirmation of the first - * abort is still outstanding. + if (!isci_remote_device_is_safe_to_abort(ireq->target_device)) + set_bit(IREQ_PENDING_ABORT, &ireq->flags); + else + clear_bit(IREQ_PENDING_ABORT, &ireq->flags); + /* If the request is only waiting on the remote device + * suspension, return SUCCESS so the caller will wait too. */ + return SCI_SUCCESS; case SCI_REQ_COMPLETED: default: dev_warn(&ireq->owning_controller->pdev->dev, "%s: SCIC IO Request requested to abort while in wrong " - "state %d\n", - __func__, - ireq->sm.current_state_id); + "state %d\n", __func__, ireq->sm.current_state_id); break; } @@ -1070,7 +1072,7 @@ request_started_state_tc_event(struct isci_request *ireq, case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_SDBFIS): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_REG_ERR): case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SDB_ERR): - if (ireq->protocol == SCIC_STP_PROTOCOL) { + if (ireq->protocol == SAS_PROTOCOL_STP) { ireq->scu_status = SCU_GET_COMPLETION_TL_STATUS(completion_code) >> SCU_COMPLETION_TL_STATUS_SHIFT; ireq->sci_status = SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED; @@ -2117,7 +2119,7 @@ static enum sci_status stp_request_udma_await_tc_event(struct isci_request *ireq */ if (ireq->stp.rsp.fis_type == FIS_REGD2H) { sci_remote_device_suspend(ireq->target_device, - SCU_EVENT_SPECIFIC(SCU_NORMALIZE_COMPLETION_STATUS(completion_code))); + SCI_SW_SUSPEND_NORMAL); ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE; ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID; @@ -2138,13 +2140,6 @@ static enum sci_status stp_request_udma_await_tc_event(struct isci_request *ireq /* TODO We can retry the command for SCU_TASK_DONE_CMD_LL_R_ERR * - this comes only for B0 */ - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_INV_FIS_LEN): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_MAX_PLD_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LL_R_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_CMD_LL_R_ERR): - sci_remote_device_suspend(ireq->target_device, - SCU_EVENT_SPECIFIC(SCU_NORMALIZE_COMPLETION_STATUS(completion_code))); - /* Fall through to the default case */ default: /* All other completion status cause the IO to be complete. */ ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code); @@ -2262,15 +2257,151 @@ static enum sci_status atapi_data_tc_completion_handler(struct isci_request *ire return status; } +static int sci_request_smp_completion_status_is_tx_suspend( + unsigned int completion_status) +{ + switch (completion_status) { + case SCU_TASK_OPEN_REJECT_WRONG_DESTINATION: + case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1: + case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2: + case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3: + case SCU_TASK_OPEN_REJECT_BAD_DESTINATION: + case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION: + return 1; + } + return 0; +} + +static int sci_request_smp_completion_status_is_tx_rx_suspend( + unsigned int completion_status) +{ + return 0; /* There are no Tx/Rx SMP suspend conditions. */ +} + +static int sci_request_ssp_completion_status_is_tx_suspend( + unsigned int completion_status) +{ + switch (completion_status) { + case SCU_TASK_DONE_TX_RAW_CMD_ERR: + case SCU_TASK_DONE_LF_ERR: + case SCU_TASK_OPEN_REJECT_WRONG_DESTINATION: + case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1: + case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2: + case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3: + case SCU_TASK_OPEN_REJECT_BAD_DESTINATION: + case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION: + case SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY: + case SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED: + case SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED: + return 1; + } + return 0; +} + +static int sci_request_ssp_completion_status_is_tx_rx_suspend( + unsigned int completion_status) +{ + return 0; /* There are no Tx/Rx SSP suspend conditions. */ +} + +static int sci_request_stpsata_completion_status_is_tx_suspend( + unsigned int completion_status) +{ + switch (completion_status) { + case SCU_TASK_DONE_TX_RAW_CMD_ERR: + case SCU_TASK_DONE_LL_R_ERR: + case SCU_TASK_DONE_LL_PERR: + case SCU_TASK_DONE_REG_ERR: + case SCU_TASK_DONE_SDB_ERR: + case SCU_TASK_OPEN_REJECT_WRONG_DESTINATION: + case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1: + case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2: + case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3: + case SCU_TASK_OPEN_REJECT_BAD_DESTINATION: + case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION: + case SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY: + case SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED: + case SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED: + return 1; + } + return 0; +} + + +static int sci_request_stpsata_completion_status_is_tx_rx_suspend( + unsigned int completion_status) +{ + switch (completion_status) { + case SCU_TASK_DONE_LF_ERR: + case SCU_TASK_DONE_LL_SY_TERM: + case SCU_TASK_DONE_LL_LF_TERM: + case SCU_TASK_DONE_BREAK_RCVD: + case SCU_TASK_DONE_INV_FIS_LEN: + case SCU_TASK_DONE_UNEXP_FIS: + case SCU_TASK_DONE_UNEXP_SDBFIS: + case SCU_TASK_DONE_MAX_PLD_ERR: + return 1; + } + return 0; +} + +static void sci_request_handle_suspending_completions( + struct isci_request *ireq, + u32 completion_code) +{ + int is_tx = 0; + int is_tx_rx = 0; + + switch (ireq->protocol) { + case SAS_PROTOCOL_SMP: + is_tx = sci_request_smp_completion_status_is_tx_suspend( + completion_code); + is_tx_rx = sci_request_smp_completion_status_is_tx_rx_suspend( + completion_code); + break; + case SAS_PROTOCOL_SSP: + is_tx = sci_request_ssp_completion_status_is_tx_suspend( + completion_code); + is_tx_rx = sci_request_ssp_completion_status_is_tx_rx_suspend( + completion_code); + break; + case SAS_PROTOCOL_STP: + is_tx = sci_request_stpsata_completion_status_is_tx_suspend( + completion_code); + is_tx_rx = + sci_request_stpsata_completion_status_is_tx_rx_suspend( + completion_code); + break; + default: + dev_warn(&ireq->isci_host->pdev->dev, + "%s: request %p has no valid protocol\n", + __func__, ireq); + break; + } + if (is_tx || is_tx_rx) { + BUG_ON(is_tx && is_tx_rx); + + sci_remote_node_context_suspend( + &ireq->target_device->rnc, + SCI_HW_SUSPEND, + (is_tx_rx) ? SCU_EVENT_TL_RNC_SUSPEND_TX_RX + : SCU_EVENT_TL_RNC_SUSPEND_TX); + } +} + enum sci_status sci_io_request_tc_completion(struct isci_request *ireq, - u32 completion_code) + u32 completion_code) { enum sci_base_request_states state; struct isci_host *ihost = ireq->owning_controller; state = ireq->sm.current_state_id; + /* Decode those completions that signal upcoming suspension events. */ + sci_request_handle_suspending_completions( + ireq, SCU_GET_COMPLETION_TL_STATUS(completion_code)); + switch (state) { case SCI_REQ_STARTED: return request_started_state_tc_event(ireq, completion_code); @@ -2362,9 +2493,6 @@ static void isci_request_process_response_iu( * @request: This parameter is the completed isci_request object. * @response_ptr: This parameter specifies the service response for the I/O. * @status_ptr: This parameter specifies the exec status for the I/O. - * @complete_to_host_ptr: This parameter specifies the action to be taken by - * the LLDD with respect to completing this request or forcing an abort - * condition on the I/O. * @open_rej_reason: This parameter specifies the encoded reason for the * abandon-class reject. * @@ -2375,14 +2503,12 @@ static void isci_request_set_open_reject_status( struct sas_task *task, enum service_response *response_ptr, enum exec_status *status_ptr, - enum isci_completion_selection *complete_to_host_ptr, enum sas_open_rej_reason open_rej_reason) { /* Task in the target is done. */ set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); *response_ptr = SAS_TASK_UNDELIVERED; *status_ptr = SAS_OPEN_REJECT; - *complete_to_host_ptr = isci_perform_normal_io_completion; task->task_status.open_rej_reason = open_rej_reason; } @@ -2392,9 +2518,6 @@ static void isci_request_set_open_reject_status( * @request: This parameter is the completed isci_request object. * @response_ptr: This parameter specifies the service response for the I/O. * @status_ptr: This parameter specifies the exec status for the I/O. - * @complete_to_host_ptr: This parameter specifies the action to be taken by - * the LLDD with respect to completing this request or forcing an abort - * condition on the I/O. * * none. */ @@ -2403,8 +2526,7 @@ static void isci_request_handle_controller_specific_errors( struct isci_request *request, struct sas_task *task, enum service_response *response_ptr, - enum exec_status *status_ptr, - enum isci_completion_selection *complete_to_host_ptr) + enum exec_status *status_ptr) { unsigned int cstatus; @@ -2445,9 +2567,6 @@ static void isci_request_handle_controller_specific_errors( *status_ptr = SAS_ABORTED_TASK; set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - - *complete_to_host_ptr = - isci_perform_normal_io_completion; } else { /* Task in the target is not done. */ *response_ptr = SAS_TASK_UNDELIVERED; @@ -2458,9 +2577,6 @@ static void isci_request_handle_controller_specific_errors( *status_ptr = SAM_STAT_TASK_ABORTED; clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - - *complete_to_host_ptr = - isci_perform_error_io_completion; } break; @@ -2489,8 +2605,6 @@ static void isci_request_handle_controller_specific_errors( *status_ptr = SAS_ABORTED_TASK; set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - - *complete_to_host_ptr = isci_perform_normal_io_completion; break; @@ -2501,7 +2615,7 @@ static void isci_request_handle_controller_specific_errors( isci_request_set_open_reject_status( request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_WRONG_DEST); + SAS_OREJ_WRONG_DEST); break; case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION: @@ -2511,56 +2625,56 @@ static void isci_request_handle_controller_specific_errors( */ isci_request_set_open_reject_status( request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_RESV_AB0); + SAS_OREJ_RESV_AB0); break; case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1: isci_request_set_open_reject_status( request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_RESV_AB1); + SAS_OREJ_RESV_AB1); break; case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2: isci_request_set_open_reject_status( request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_RESV_AB2); + SAS_OREJ_RESV_AB2); break; case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3: isci_request_set_open_reject_status( request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_RESV_AB3); + SAS_OREJ_RESV_AB3); break; case SCU_TASK_OPEN_REJECT_BAD_DESTINATION: isci_request_set_open_reject_status( request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_BAD_DEST); + SAS_OREJ_BAD_DEST); break; case SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY: isci_request_set_open_reject_status( request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_STP_NORES); + SAS_OREJ_STP_NORES); break; case SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED: isci_request_set_open_reject_status( request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_EPROTO); + SAS_OREJ_EPROTO); break; case SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED: isci_request_set_open_reject_status( request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_CONN_RATE); + SAS_OREJ_CONN_RATE); break; case SCU_TASK_DONE_LL_R_ERR: @@ -2592,95 +2706,12 @@ static void isci_request_handle_controller_specific_errors( *response_ptr = SAS_TASK_UNDELIVERED; *status_ptr = SAM_STAT_TASK_ABORTED; - if (task->task_proto == SAS_PROTOCOL_SMP) { + if (task->task_proto == SAS_PROTOCOL_SMP) set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - - *complete_to_host_ptr = isci_perform_normal_io_completion; - } else { + else clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - - *complete_to_host_ptr = isci_perform_error_io_completion; - } - break; - } -} - -/** - * isci_task_save_for_upper_layer_completion() - This function saves the - * request for later completion to the upper layer driver. - * @host: This parameter is a pointer to the host on which the the request - * should be queued (either as an error or success). - * @request: This parameter is the completed request. - * @response: This parameter is the response code for the completed task. - * @status: This parameter is the status code for the completed task. - * - * none. - */ -static void isci_task_save_for_upper_layer_completion( - struct isci_host *host, - struct isci_request *request, - enum service_response response, - enum exec_status status, - enum isci_completion_selection task_notification_selection) -{ - struct sas_task *task = isci_request_access_task(request); - - task_notification_selection - = isci_task_set_completion_status(task, response, status, - task_notification_selection); - - /* Tasks aborted specifically by a call to the lldd_abort_task - * function should not be completed to the host in the regular path. - */ - switch (task_notification_selection) { - - case isci_perform_normal_io_completion: - /* Normal notification (task_done) */ - - /* Add to the completed list. */ - list_add(&request->completed_node, - &host->requests_to_complete); - - /* Take the request off the device's pending request list. */ - list_del_init(&request->dev_node); - break; - - case isci_perform_aborted_io_completion: - /* No notification to libsas because this request is - * already in the abort path. - */ - /* Wake up whatever process was waiting for this - * request to complete. - */ - WARN_ON(request->io_request_completion == NULL); - - if (request->io_request_completion != NULL) { - - /* Signal whoever is waiting that this - * request is complete. - */ - complete(request->io_request_completion); - } - break; - - case isci_perform_error_io_completion: - /* Use sas_task_abort */ - /* Add to the aborted list. */ - list_add(&request->completed_node, - &host->requests_to_errorback); - break; - - default: - /* Add to the error to libsas list. */ - list_add(&request->completed_node, - &host->requests_to_errorback); break; } - dev_dbg(&host->pdev->dev, - "%s: %d - task = %p, response=%d (%d), status=%d (%d)\n", - __func__, task_notification_selection, task, - (task) ? task->task_status.resp : 0, response, - (task) ? task->task_status.stat : 0, status); } static void isci_process_stp_response(struct sas_task *task, struct dev_to_host_fis *fis) @@ -2715,295 +2746,164 @@ static void isci_request_io_request_complete(struct isci_host *ihost, struct isci_remote_device *idev = request->target_device; enum service_response response = SAS_TASK_UNDELIVERED; enum exec_status status = SAS_ABORTED_TASK; - enum isci_request_status request_status; - enum isci_completion_selection complete_to_host - = isci_perform_normal_io_completion; dev_dbg(&ihost->pdev->dev, - "%s: request = %p, task = %p,\n" + "%s: request = %p, task = %p, " "task->data_dir = %d completion_status = 0x%x\n", - __func__, - request, - task, - task->data_dir, - completion_status); + __func__, request, task, task->data_dir, completion_status); - spin_lock(&request->state_lock); - request_status = request->status; + /* The request is done from an SCU HW perspective. */ - /* Decode the request status. Note that if the request has been - * aborted by a task management function, we don't care - * what the status is. - */ - switch (request_status) { - - case aborted: - /* "aborted" indicates that the request was aborted by a task - * management function, since once a task management request is - * perfomed by the device, the request only completes because - * of the subsequent driver terminate. - * - * Aborted also means an external thread is explicitly managing - * this request, so that we do not complete it up the stack. - * - * The target is still there (since the TMF was successful). - */ - set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - response = SAS_TASK_COMPLETE; + /* This is an active request being completed from the core. */ + switch (completion_status) { - /* See if the device has been/is being stopped. Note - * that we ignore the quiesce state, since we are - * concerned about the actual device state. - */ - if (!idev) - status = SAS_DEVICE_UNKNOWN; - else - status = SAS_ABORTED_TASK; + case SCI_IO_FAILURE_RESPONSE_VALID: + dev_dbg(&ihost->pdev->dev, + "%s: SCI_IO_FAILURE_RESPONSE_VALID (%p/%p)\n", + __func__, request, task); + + if (sas_protocol_ata(task->task_proto)) { + isci_process_stp_response(task, &request->stp.rsp); + } else if (SAS_PROTOCOL_SSP == task->task_proto) { + + /* crack the iu response buffer. */ + resp_iu = &request->ssp.rsp; + isci_request_process_response_iu(task, resp_iu, + &ihost->pdev->dev); + + } else if (SAS_PROTOCOL_SMP == task->task_proto) { + + dev_err(&ihost->pdev->dev, + "%s: SCI_IO_FAILURE_RESPONSE_VALID: " + "SAS_PROTOCOL_SMP protocol\n", + __func__); - complete_to_host = isci_perform_aborted_io_completion; - /* This was an aborted request. */ + } else + dev_err(&ihost->pdev->dev, + "%s: unknown protocol\n", __func__); - spin_unlock(&request->state_lock); + /* use the task status set in the task struct by the + * isci_request_process_response_iu call. + */ + set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); + response = task->task_status.resp; + status = task->task_status.stat; break; - case aborting: - /* aborting means that the task management function tried and - * failed to abort the request. We need to note the request - * as SAS_TASK_UNDELIVERED, so that the scsi mid layer marks the - * target as down. - * - * Aborting also means an external thread is explicitly managing - * this request, so that we do not complete it up the stack. - */ + case SCI_IO_SUCCESS: + case SCI_IO_SUCCESS_IO_DONE_EARLY: + + response = SAS_TASK_COMPLETE; + status = SAM_STAT_GOOD; set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - response = SAS_TASK_UNDELIVERED; - if (!idev) - /* The device has been /is being stopped. Note that - * we ignore the quiesce state, since we are - * concerned about the actual device state. - */ - status = SAS_DEVICE_UNKNOWN; - else - status = SAS_PHY_DOWN; + if (completion_status == SCI_IO_SUCCESS_IO_DONE_EARLY) { - complete_to_host = isci_perform_aborted_io_completion; + /* This was an SSP / STP / SATA transfer. + * There is a possibility that less data than + * the maximum was transferred. + */ + u32 transferred_length = sci_req_tx_bytes(request); - /* This was an aborted request. */ + task->task_status.residual + = task->total_xfer_len - transferred_length; + + /* If there were residual bytes, call this an + * underrun. + */ + if (task->task_status.residual != 0) + status = SAS_DATA_UNDERRUN; - spin_unlock(&request->state_lock); + dev_dbg(&ihost->pdev->dev, + "%s: SCI_IO_SUCCESS_IO_DONE_EARLY %d\n", + __func__, status); + + } else + dev_dbg(&ihost->pdev->dev, "%s: SCI_IO_SUCCESS\n", + __func__); break; - case terminating: + case SCI_IO_FAILURE_TERMINATED: - /* This was an terminated request. This happens when - * the I/O is being terminated because of an action on - * the device (reset, tear down, etc.), and the I/O needs - * to be completed up the stack. - */ + dev_dbg(&ihost->pdev->dev, + "%s: SCI_IO_FAILURE_TERMINATED (%p/%p)\n", + __func__, request, task); + + /* The request was terminated explicitly. */ set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); response = SAS_TASK_UNDELIVERED; /* See if the device has been/is being stopped. Note - * that we ignore the quiesce state, since we are - * concerned about the actual device state. - */ + * that we ignore the quiesce state, since we are + * concerned about the actual device state. + */ if (!idev) status = SAS_DEVICE_UNKNOWN; else status = SAS_ABORTED_TASK; - - complete_to_host = isci_perform_aborted_io_completion; - - /* This was a terminated request. */ - - spin_unlock(&request->state_lock); break; - case dead: - /* This was a terminated request that timed-out during the - * termination process. There is no task to complete to - * libsas. - */ - complete_to_host = isci_perform_normal_io_completion; - spin_unlock(&request->state_lock); - break; + case SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR: - default: - - /* The request is done from an SCU HW perspective. */ - request->status = completed; - - spin_unlock(&request->state_lock); - - /* This is an active request being completed from the core. */ - switch (completion_status) { - - case SCI_IO_FAILURE_RESPONSE_VALID: - dev_dbg(&ihost->pdev->dev, - "%s: SCI_IO_FAILURE_RESPONSE_VALID (%p/%p)\n", - __func__, - request, - task); - - if (sas_protocol_ata(task->task_proto)) { - isci_process_stp_response(task, &request->stp.rsp); - } else if (SAS_PROTOCOL_SSP == task->task_proto) { - - /* crack the iu response buffer. */ - resp_iu = &request->ssp.rsp; - isci_request_process_response_iu(task, resp_iu, - &ihost->pdev->dev); - - } else if (SAS_PROTOCOL_SMP == task->task_proto) { - - dev_err(&ihost->pdev->dev, - "%s: SCI_IO_FAILURE_RESPONSE_VALID: " - "SAS_PROTOCOL_SMP protocol\n", - __func__); - - } else - dev_err(&ihost->pdev->dev, - "%s: unknown protocol\n", __func__); - - /* use the task status set in the task struct by the - * isci_request_process_response_iu call. - */ - set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - response = task->task_status.resp; - status = task->task_status.stat; - break; + isci_request_handle_controller_specific_errors(idev, request, + task, &response, + &status); + break; - case SCI_IO_SUCCESS: - case SCI_IO_SUCCESS_IO_DONE_EARLY: + case SCI_IO_FAILURE_REMOTE_DEVICE_RESET_REQUIRED: + /* This is a special case, in that the I/O completion + * is telling us that the device needs a reset. + * In order for the device reset condition to be + * noticed, the I/O has to be handled in the error + * handler. Set the reset flag and cause the + * SCSI error thread to be scheduled. + */ + spin_lock_irqsave(&task->task_state_lock, task_flags); + task->task_state_flags |= SAS_TASK_NEED_DEV_RESET; + spin_unlock_irqrestore(&task->task_state_lock, task_flags); - response = SAS_TASK_COMPLETE; - status = SAM_STAT_GOOD; - set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); + /* Fail the I/O. */ + response = SAS_TASK_UNDELIVERED; + status = SAM_STAT_TASK_ABORTED; - if (completion_status == SCI_IO_SUCCESS_IO_DONE_EARLY) { + clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); + break; - /* This was an SSP / STP / SATA transfer. - * There is a possibility that less data than - * the maximum was transferred. - */ - u32 transferred_length = sci_req_tx_bytes(request); + case SCI_FAILURE_RETRY_REQUIRED: - task->task_status.residual - = task->total_xfer_len - transferred_length; + /* Fail the I/O so it can be retried. */ + response = SAS_TASK_UNDELIVERED; + if (!idev) + status = SAS_DEVICE_UNKNOWN; + else + status = SAS_ABORTED_TASK; - /* If there were residual bytes, call this an - * underrun. - */ - if (task->task_status.residual != 0) - status = SAS_DATA_UNDERRUN; + set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); + break; - dev_dbg(&ihost->pdev->dev, - "%s: SCI_IO_SUCCESS_IO_DONE_EARLY %d\n", - __func__, - status); - } else - dev_dbg(&ihost->pdev->dev, - "%s: SCI_IO_SUCCESS\n", - __func__); + default: + /* Catch any otherwise unhandled error codes here. */ + dev_dbg(&ihost->pdev->dev, + "%s: invalid completion code: 0x%x - " + "isci_request = %p\n", + __func__, completion_status, request); - break; + response = SAS_TASK_UNDELIVERED; - case SCI_IO_FAILURE_TERMINATED: - dev_dbg(&ihost->pdev->dev, - "%s: SCI_IO_FAILURE_TERMINATED (%p/%p)\n", - __func__, - request, - task); + /* See if the device has been/is being stopped. Note + * that we ignore the quiesce state, since we are + * concerned about the actual device state. + */ + if (!idev) + status = SAS_DEVICE_UNKNOWN; + else + status = SAS_ABORTED_TASK; - /* The request was terminated explicitly. No handling - * is needed in the SCSI error handler path. - */ + if (SAS_PROTOCOL_SMP == task->task_proto) set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - response = SAS_TASK_UNDELIVERED; - - /* See if the device has been/is being stopped. Note - * that we ignore the quiesce state, since we are - * concerned about the actual device state. - */ - if (!idev) - status = SAS_DEVICE_UNKNOWN; - else - status = SAS_ABORTED_TASK; - - complete_to_host = isci_perform_normal_io_completion; - break; - - case SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR: - - isci_request_handle_controller_specific_errors( - idev, request, task, &response, &status, - &complete_to_host); - - break; - - case SCI_IO_FAILURE_REMOTE_DEVICE_RESET_REQUIRED: - /* This is a special case, in that the I/O completion - * is telling us that the device needs a reset. - * In order for the device reset condition to be - * noticed, the I/O has to be handled in the error - * handler. Set the reset flag and cause the - * SCSI error thread to be scheduled. - */ - spin_lock_irqsave(&task->task_state_lock, task_flags); - task->task_state_flags |= SAS_TASK_NEED_DEV_RESET; - spin_unlock_irqrestore(&task->task_state_lock, task_flags); - - /* Fail the I/O. */ - response = SAS_TASK_UNDELIVERED; - status = SAM_STAT_TASK_ABORTED; - - complete_to_host = isci_perform_error_io_completion; + else clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - break; - - case SCI_FAILURE_RETRY_REQUIRED: - - /* Fail the I/O so it can be retried. */ - response = SAS_TASK_UNDELIVERED; - if (!idev) - status = SAS_DEVICE_UNKNOWN; - else - status = SAS_ABORTED_TASK; - - complete_to_host = isci_perform_normal_io_completion; - set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - break; - - - default: - /* Catch any otherwise unhandled error codes here. */ - dev_dbg(&ihost->pdev->dev, - "%s: invalid completion code: 0x%x - " - "isci_request = %p\n", - __func__, completion_status, request); - - response = SAS_TASK_UNDELIVERED; - - /* See if the device has been/is being stopped. Note - * that we ignore the quiesce state, since we are - * concerned about the actual device state. - */ - if (!idev) - status = SAS_DEVICE_UNKNOWN; - else - status = SAS_ABORTED_TASK; - - if (SAS_PROTOCOL_SMP == task->task_proto) { - set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - complete_to_host = isci_perform_normal_io_completion; - } else { - clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - complete_to_host = isci_perform_error_io_completion; - } - break; - } break; } @@ -3038,10 +2938,18 @@ static void isci_request_io_request_complete(struct isci_host *ihost, break; } - /* Put the completed request on the correct list */ - isci_task_save_for_upper_layer_completion(ihost, request, response, - status, complete_to_host - ); + spin_lock_irqsave(&task->task_state_lock, task_flags); + + task->task_status.resp = response; + task->task_status.stat = status; + + if (test_bit(IREQ_COMPLETE_IN_TARGET, &request->flags)) { + /* Normal notification (task_done) */ + task->task_state_flags |= SAS_TASK_STATE_DONE; + task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR | + SAS_TASK_STATE_PENDING); + } + spin_unlock_irqrestore(&task->task_state_lock, task_flags); /* complete the io request to the core. */ sci_controller_complete_io(ihost, request->target_device, request); @@ -3051,6 +2959,8 @@ static void isci_request_io_request_complete(struct isci_host *ihost, * task to recognize the already completed case. */ set_bit(IREQ_TERMINATED, &request->flags); + + ireq_done(ihost, request, task); } static void sci_request_started_state_enter(struct sci_base_state_machine *sm) @@ -3169,7 +3079,7 @@ sci_general_request_construct(struct isci_host *ihost, sci_init_sm(&ireq->sm, sci_request_state_table, SCI_REQ_INIT); ireq->target_device = idev; - ireq->protocol = SCIC_NO_PROTOCOL; + ireq->protocol = SAS_PROTOCOL_NONE; ireq->saved_rx_frame_index = SCU_INVALID_FRAME_INDEX; ireq->sci_status = SCI_SUCCESS; @@ -3193,7 +3103,7 @@ sci_io_request_construct(struct isci_host *ihost, if (dev->dev_type == SAS_END_DEV) /* pass */; - else if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) + else if (dev_is_sata(dev)) memset(&ireq->stp.cmd, 0, sizeof(ireq->stp.cmd)); else if (dev_is_expander(dev)) /* pass */; @@ -3215,10 +3125,15 @@ enum sci_status sci_task_request_construct(struct isci_host *ihost, /* Build the common part of the request */ sci_general_request_construct(ihost, idev, ireq); - if (dev->dev_type == SAS_END_DEV || - dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) { + if (dev->dev_type == SAS_END_DEV || dev_is_sata(dev)) { set_bit(IREQ_TMF, &ireq->flags); memset(ireq->tc, 0, sizeof(struct scu_task_context)); + + /* Set the protocol indicator. */ + if (dev_is_sata(dev)) + ireq->protocol = SAS_PROTOCOL_STP; + else + ireq->protocol = SAS_PROTOCOL_SSP; } else status = SCI_FAILURE_UNSUPPORTED_PROTOCOL; @@ -3311,7 +3226,7 @@ sci_io_request_construct_smp(struct device *dev, if (!dma_map_sg(dev, sg, 1, DMA_TO_DEVICE)) return SCI_FAILURE; - ireq->protocol = SCIC_SMP_PROTOCOL; + ireq->protocol = SAS_PROTOCOL_SMP; /* byte swap the smp request. */ @@ -3496,9 +3411,6 @@ static struct isci_request *isci_request_from_tag(struct isci_host *ihost, u16 t ireq->io_request_completion = NULL; ireq->flags = 0; ireq->num_sg_entries = 0; - INIT_LIST_HEAD(&ireq->completed_node); - INIT_LIST_HEAD(&ireq->dev_node); - isci_request_change_state(ireq, allocated); return ireq; } @@ -3582,26 +3494,15 @@ int isci_request_execute(struct isci_host *ihost, struct isci_remote_device *ide spin_unlock_irqrestore(&ihost->scic_lock, flags); return status; } - /* Either I/O started OK, or the core has signaled that * the device needs a target reset. - * - * In either case, hold onto the I/O for later. - * - * Update it's status and add it to the list in the - * remote device object. */ - list_add(&ireq->dev_node, &idev->reqs_in_process); - - if (status == SCI_SUCCESS) { - isci_request_change_state(ireq, started); - } else { + if (status != SCI_SUCCESS) { /* The request did not really start in the * hardware, so clear the request handle * here so no terminations will be done. */ set_bit(IREQ_TERMINATED, &ireq->flags); - isci_request_change_state(ireq, completed); } spin_unlock_irqrestore(&ihost->scic_lock, flags); diff --git a/trunk/drivers/scsi/isci/request.h b/trunk/drivers/scsi/isci/request.h index 057f2378452d..aff95317fcf4 100644 --- a/trunk/drivers/scsi/isci/request.h +++ b/trunk/drivers/scsi/isci/request.h @@ -60,30 +60,6 @@ #include "host.h" #include "scu_task_context.h" -/** - * struct isci_request_status - This enum defines the possible states of an I/O - * request. - * - * - */ -enum isci_request_status { - unallocated = 0x00, - allocated = 0x01, - started = 0x02, - completed = 0x03, - aborting = 0x04, - aborted = 0x05, - terminating = 0x06, - dead = 0x07 -}; - -enum sci_request_protocol { - SCIC_NO_PROTOCOL, - SCIC_SMP_PROTOCOL, - SCIC_SSP_PROTOCOL, - SCIC_STP_PROTOCOL -}; /* XXX remove me, use sas_task.{dev|task_proto} instead */; - /** * isci_stp_request - extra request infrastructure to handle pio/atapi protocol * @pio_len - number of bytes requested at PIO setup @@ -104,11 +80,14 @@ struct isci_stp_request { }; struct isci_request { - enum isci_request_status status; #define IREQ_COMPLETE_IN_TARGET 0 #define IREQ_TERMINATED 1 #define IREQ_TMF 2 #define IREQ_ACTIVE 3 + #define IREQ_PENDING_ABORT 4 /* Set == device was not suspended yet */ + #define IREQ_TC_ABORT_POSTED 5 + #define IREQ_ABORT_PATH_ACTIVE 6 + #define IREQ_NO_AUTO_FREE_TAG 7 /* Set when being explicitly managed */ unsigned long flags; /* XXX kill ttype and ttype_ptr, allocate full sas_task */ union ttype_ptr_union { @@ -116,11 +95,6 @@ struct isci_request { struct isci_tmf *tmf_task_ptr; /* When ttype==tmf_task */ } ttype_ptr; struct isci_host *isci_host; - /* For use in the requests_to_{complete|abort} lists: */ - struct list_head completed_node; - /* For use in the reqs_in_process list: */ - struct list_head dev_node; - spinlock_t state_lock; dma_addr_t request_daddr; dma_addr_t zero_scatter_daddr; unsigned int num_sg_entries; @@ -140,7 +114,7 @@ struct isci_request { struct isci_host *owning_controller; struct isci_remote_device *target_device; u16 io_tag; - enum sci_request_protocol protocol; + enum sas_protocol protocol; u32 scu_status; /* hardware result */ u32 sci_status; /* upper layer disposition */ u32 post_context; @@ -309,92 +283,6 @@ sci_io_request_get_dma_addr(struct isci_request *ireq, void *virt_addr) return ireq->request_daddr + (requested_addr - base_addr); } -/** - * isci_request_change_state() - This function sets the status of the request - * object. - * @request: This parameter points to the isci_request object - * @status: This Parameter is the new status of the object - * - */ -static inline enum isci_request_status -isci_request_change_state(struct isci_request *isci_request, - enum isci_request_status status) -{ - enum isci_request_status old_state; - unsigned long flags; - - dev_dbg(&isci_request->isci_host->pdev->dev, - "%s: isci_request = %p, state = 0x%x\n", - __func__, - isci_request, - status); - - BUG_ON(isci_request == NULL); - - spin_lock_irqsave(&isci_request->state_lock, flags); - old_state = isci_request->status; - isci_request->status = status; - spin_unlock_irqrestore(&isci_request->state_lock, flags); - - return old_state; -} - -/** - * isci_request_change_started_to_newstate() - This function sets the status of - * the request object. - * @request: This parameter points to the isci_request object - * @status: This Parameter is the new status of the object - * - * state previous to any change. - */ -static inline enum isci_request_status -isci_request_change_started_to_newstate(struct isci_request *isci_request, - struct completion *completion_ptr, - enum isci_request_status newstate) -{ - enum isci_request_status old_state; - unsigned long flags; - - spin_lock_irqsave(&isci_request->state_lock, flags); - - old_state = isci_request->status; - - if (old_state == started || old_state == aborting) { - BUG_ON(isci_request->io_request_completion != NULL); - - isci_request->io_request_completion = completion_ptr; - isci_request->status = newstate; - } - - spin_unlock_irqrestore(&isci_request->state_lock, flags); - - dev_dbg(&isci_request->isci_host->pdev->dev, - "%s: isci_request = %p, old_state = 0x%x\n", - __func__, - isci_request, - old_state); - - return old_state; -} - -/** - * isci_request_change_started_to_aborted() - This function sets the status of - * the request object. - * @request: This parameter points to the isci_request object - * @completion_ptr: This parameter is saved as the kernel completion structure - * signalled when the old request completes. - * - * state previous to any change. - */ -static inline enum isci_request_status -isci_request_change_started_to_aborted(struct isci_request *isci_request, - struct completion *completion_ptr) -{ - return isci_request_change_started_to_newstate(isci_request, - completion_ptr, - aborted); -} - #define isci_request_access_task(req) ((req)->ttype_ptr.io_task_ptr) #define isci_request_access_tmf(req) ((req)->ttype_ptr.tmf_task_ptr) @@ -404,8 +292,6 @@ struct isci_request *isci_tmf_request_from_tag(struct isci_host *ihost, u16 tag); int isci_request_execute(struct isci_host *ihost, struct isci_remote_device *idev, struct sas_task *task, u16 tag); -void isci_terminate_pending_requests(struct isci_host *ihost, - struct isci_remote_device *idev); enum sci_status sci_task_request_construct(struct isci_host *ihost, struct isci_remote_device *idev, @@ -421,5 +307,4 @@ static inline int isci_task_is_ncq_recovery(struct sas_task *task) task->ata_task.fis.lbal == ATA_LOG_SATA_NCQ); } - #endif /* !defined(_ISCI_REQUEST_H_) */ diff --git a/trunk/drivers/scsi/isci/scu_completion_codes.h b/trunk/drivers/scsi/isci/scu_completion_codes.h index c8b329c695f9..071cb74a211c 100644 --- a/trunk/drivers/scsi/isci/scu_completion_codes.h +++ b/trunk/drivers/scsi/isci/scu_completion_codes.h @@ -224,6 +224,7 @@ * 32-bit value like we want, each immediate value must be cast to a u32. */ #define SCU_TASK_DONE_GOOD ((u32)0x00) +#define SCU_TASK_DONE_TX_RAW_CMD_ERR ((u32)0x08) #define SCU_TASK_DONE_CRC_ERR ((u32)0x14) #define SCU_TASK_DONE_CHECK_RESPONSE ((u32)0x14) #define SCU_TASK_DONE_GEN_RESPONSE ((u32)0x15) @@ -237,6 +238,7 @@ #define SCU_TASK_DONE_LL_LF_TERM ((u32)0x1A) #define SCU_TASK_DONE_DATA_LEN_ERR ((u32)0x1A) #define SCU_TASK_DONE_LL_CL_TERM ((u32)0x1B) +#define SCU_TASK_DONE_BREAK_RCVD ((u32)0x1B) #define SCU_TASK_DONE_LL_ABORT_ERR ((u32)0x1B) #define SCU_TASK_DONE_SEQ_INV_TYPE ((u32)0x1C) #define SCU_TASK_DONE_UNEXP_XR ((u32)0x1C) diff --git a/trunk/drivers/scsi/isci/task.c b/trunk/drivers/scsi/isci/task.c index 374254ede9d4..6bc74eb012c9 100644 --- a/trunk/drivers/scsi/isci/task.c +++ b/trunk/drivers/scsi/isci/task.c @@ -78,54 +78,25 @@ static void isci_task_refuse(struct isci_host *ihost, struct sas_task *task, enum exec_status status) { - enum isci_completion_selection disposition; + unsigned long flags; - disposition = isci_perform_normal_io_completion; - disposition = isci_task_set_completion_status(task, response, status, - disposition); + /* Normal notification (task_done) */ + dev_dbg(&ihost->pdev->dev, "%s: task = %p, response=%d, status=%d\n", + __func__, task, response, status); - /* Tasks aborted specifically by a call to the lldd_abort_task - * function should not be completed to the host in the regular path. - */ - switch (disposition) { - case isci_perform_normal_io_completion: - /* Normal notification (task_done) */ - dev_dbg(&ihost->pdev->dev, - "%s: Normal - task = %p, response=%d, " - "status=%d\n", - __func__, task, response, status); - - task->lldd_task = NULL; - task->task_done(task); - break; - - case isci_perform_aborted_io_completion: - /* - * No notification because this request is already in the - * abort path. - */ - dev_dbg(&ihost->pdev->dev, - "%s: Aborted - task = %p, response=%d, " - "status=%d\n", - __func__, task, response, status); - break; + spin_lock_irqsave(&task->task_state_lock, flags); - case isci_perform_error_io_completion: - /* Use sas_task_abort */ - dev_dbg(&ihost->pdev->dev, - "%s: Error - task = %p, response=%d, " - "status=%d\n", - __func__, task, response, status); - sas_task_abort(task); - break; + task->task_status.resp = response; + task->task_status.stat = status; - default: - dev_dbg(&ihost->pdev->dev, - "%s: isci task notification default case!", - __func__); - sas_task_abort(task); - break; - } + /* Normal notification (task_done) */ + task->task_state_flags |= SAS_TASK_STATE_DONE; + task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR | + SAS_TASK_STATE_PENDING); + task->lldd_task = NULL; + spin_unlock_irqrestore(&task->task_state_lock, flags); + + task->task_done(task); } #define for_each_sas_task(num, task) \ @@ -289,60 +260,6 @@ static struct isci_request *isci_task_request_build(struct isci_host *ihost, return ireq; } -/** -* isci_request_mark_zombie() - This function must be called with scic_lock held. -*/ -static void isci_request_mark_zombie(struct isci_host *ihost, struct isci_request *ireq) -{ - struct completion *tmf_completion = NULL; - struct completion *req_completion; - - /* Set the request state to "dead". */ - ireq->status = dead; - - req_completion = ireq->io_request_completion; - ireq->io_request_completion = NULL; - - if (test_bit(IREQ_TMF, &ireq->flags)) { - /* Break links with the TMF request. */ - struct isci_tmf *tmf = isci_request_access_tmf(ireq); - - /* In the case where a task request is dying, - * the thread waiting on the complete will sit and - * timeout unless we wake it now. Since the TMF - * has a default error status, complete it here - * to wake the waiting thread. - */ - if (tmf) { - tmf_completion = tmf->complete; - tmf->complete = NULL; - } - ireq->ttype_ptr.tmf_task_ptr = NULL; - dev_dbg(&ihost->pdev->dev, "%s: tmf_code %d, managed tag %#x\n", - __func__, tmf->tmf_code, tmf->io_tag); - } else { - /* Break links with the sas_task - the callback is done - * elsewhere. - */ - struct sas_task *task = isci_request_access_task(ireq); - - if (task) - task->lldd_task = NULL; - - ireq->ttype_ptr.io_task_ptr = NULL; - } - - dev_warn(&ihost->pdev->dev, "task context unrecoverable (tag: %#x)\n", - ireq->io_tag); - - /* Don't force waiting threads to timeout. */ - if (req_completion) - complete(req_completion); - - if (tmf_completion != NULL) - complete(tmf_completion); -} - static int isci_task_execute_tmf(struct isci_host *ihost, struct isci_remote_device *idev, struct isci_tmf *tmf, unsigned long timeout_ms) @@ -400,17 +317,11 @@ static int isci_task_execute_tmf(struct isci_host *ihost, spin_unlock_irqrestore(&ihost->scic_lock, flags); goto err_tci; } - - if (tmf->cb_state_func != NULL) - tmf->cb_state_func(isci_tmf_started, tmf, tmf->cb_data); - - isci_request_change_state(ireq, started); - - /* add the request to the remote device request list. */ - list_add(&ireq->dev_node, &idev->reqs_in_process); - spin_unlock_irqrestore(&ihost->scic_lock, flags); + /* The RNC must be unsuspended before the TMF can get a response. */ + isci_remote_device_resume_from_abort(ihost, idev); + /* Wait for the TMF to complete, or a timeout. */ timeleft = wait_for_completion_timeout(&completion, msecs_to_jiffies(timeout_ms)); @@ -419,32 +330,7 @@ static int isci_task_execute_tmf(struct isci_host *ihost, /* The TMF did not complete - this could be because * of an unplug. Terminate the TMF request now. */ - spin_lock_irqsave(&ihost->scic_lock, flags); - - if (tmf->cb_state_func != NULL) - tmf->cb_state_func(isci_tmf_timed_out, tmf, - tmf->cb_data); - - sci_controller_terminate_request(ihost, idev, ireq); - - spin_unlock_irqrestore(&ihost->scic_lock, flags); - - timeleft = wait_for_completion_timeout( - &completion, - msecs_to_jiffies(ISCI_TERMINATION_TIMEOUT_MSEC)); - - if (!timeleft) { - /* Strange condition - the termination of the TMF - * request timed-out. - */ - spin_lock_irqsave(&ihost->scic_lock, flags); - - /* If the TMF status has not changed, kill it. */ - if (tmf->status == SCI_FAILURE_TIMEOUT) - isci_request_mark_zombie(ihost, ireq); - - spin_unlock_irqrestore(&ihost->scic_lock, flags); - } + isci_remote_device_suspend_terminate(ihost, idev, ireq); } isci_print_tmf(ihost, tmf); @@ -476,314 +362,20 @@ static int isci_task_execute_tmf(struct isci_host *ihost, } static void isci_task_build_tmf(struct isci_tmf *tmf, - enum isci_tmf_function_codes code, - void (*tmf_sent_cb)(enum isci_tmf_cb_state, - struct isci_tmf *, - void *), - void *cb_data) + enum isci_tmf_function_codes code) { memset(tmf, 0, sizeof(*tmf)); - - tmf->tmf_code = code; - tmf->cb_state_func = tmf_sent_cb; - tmf->cb_data = cb_data; + tmf->tmf_code = code; } static void isci_task_build_abort_task_tmf(struct isci_tmf *tmf, enum isci_tmf_function_codes code, - void (*tmf_sent_cb)(enum isci_tmf_cb_state, - struct isci_tmf *, - void *), struct isci_request *old_request) { - isci_task_build_tmf(tmf, code, tmf_sent_cb, old_request); + isci_task_build_tmf(tmf, code); tmf->io_tag = old_request->io_tag; } -/** - * isci_task_validate_request_to_abort() - This function checks the given I/O - * against the "started" state. If the request is still "started", it's - * state is changed to aborted. NOTE: isci_host->scic_lock MUST BE HELD - * BEFORE CALLING THIS FUNCTION. - * @isci_request: This parameter specifies the request object to control. - * @isci_host: This parameter specifies the ISCI host object - * @isci_device: This is the device to which the request is pending. - * @aborted_io_completion: This is a completion structure that will be added to - * the request in case it is changed to aborting; this completion is - * triggered when the request is fully completed. - * - * Either "started" on successful change of the task status to "aborted", or - * "unallocated" if the task cannot be controlled. - */ -static enum isci_request_status isci_task_validate_request_to_abort( - struct isci_request *isci_request, - struct isci_host *isci_host, - struct isci_remote_device *isci_device, - struct completion *aborted_io_completion) -{ - enum isci_request_status old_state = unallocated; - - /* Only abort the task if it's in the - * device's request_in_process list - */ - if (isci_request && !list_empty(&isci_request->dev_node)) { - old_state = isci_request_change_started_to_aborted( - isci_request, aborted_io_completion); - - } - - return old_state; -} - -static int isci_request_is_dealloc_managed(enum isci_request_status stat) -{ - switch (stat) { - case aborted: - case aborting: - case terminating: - case completed: - case dead: - return true; - default: - return false; - } -} - -/** - * isci_terminate_request_core() - This function will terminate the given - * request, and wait for it to complete. This function must only be called - * from a thread that can wait. Note that the request is terminated and - * completed (back to the host, if started there). - * @ihost: This SCU. - * @idev: The target. - * @isci_request: The I/O request to be terminated. - * - */ -static void isci_terminate_request_core(struct isci_host *ihost, - struct isci_remote_device *idev, - struct isci_request *isci_request) -{ - enum sci_status status = SCI_SUCCESS; - bool was_terminated = false; - bool needs_cleanup_handling = false; - unsigned long flags; - unsigned long termination_completed = 1; - struct completion *io_request_completion; - - dev_dbg(&ihost->pdev->dev, - "%s: device = %p; request = %p\n", - __func__, idev, isci_request); - - spin_lock_irqsave(&ihost->scic_lock, flags); - - io_request_completion = isci_request->io_request_completion; - - /* Note that we are not going to control - * the target to abort the request. - */ - set_bit(IREQ_COMPLETE_IN_TARGET, &isci_request->flags); - - /* Make sure the request wasn't just sitting around signalling - * device condition (if the request handle is NULL, then the - * request completed but needed additional handling here). - */ - if (!test_bit(IREQ_TERMINATED, &isci_request->flags)) { - was_terminated = true; - needs_cleanup_handling = true; - status = sci_controller_terminate_request(ihost, - idev, - isci_request); - } - spin_unlock_irqrestore(&ihost->scic_lock, flags); - - /* - * The only time the request to terminate will - * fail is when the io request is completed and - * being aborted. - */ - if (status != SCI_SUCCESS) { - dev_dbg(&ihost->pdev->dev, - "%s: sci_controller_terminate_request" - " returned = 0x%x\n", - __func__, status); - - isci_request->io_request_completion = NULL; - - } else { - if (was_terminated) { - dev_dbg(&ihost->pdev->dev, - "%s: before completion wait (%p/%p)\n", - __func__, isci_request, io_request_completion); - - /* Wait here for the request to complete. */ - termination_completed - = wait_for_completion_timeout( - io_request_completion, - msecs_to_jiffies(ISCI_TERMINATION_TIMEOUT_MSEC)); - - if (!termination_completed) { - - /* The request to terminate has timed out. */ - spin_lock_irqsave(&ihost->scic_lock, flags); - - /* Check for state changes. */ - if (!test_bit(IREQ_TERMINATED, - &isci_request->flags)) { - - /* The best we can do is to have the - * request die a silent death if it - * ever really completes. - */ - isci_request_mark_zombie(ihost, - isci_request); - needs_cleanup_handling = true; - } else - termination_completed = 1; - - spin_unlock_irqrestore(&ihost->scic_lock, - flags); - - if (!termination_completed) { - - dev_dbg(&ihost->pdev->dev, - "%s: *** Timeout waiting for " - "termination(%p/%p)\n", - __func__, io_request_completion, - isci_request); - - /* The request can no longer be referenced - * safely since it may go away if the - * termination every really does complete. - */ - isci_request = NULL; - } - } - if (termination_completed) - dev_dbg(&ihost->pdev->dev, - "%s: after completion wait (%p/%p)\n", - __func__, isci_request, io_request_completion); - } - - if (termination_completed) { - - isci_request->io_request_completion = NULL; - - /* Peek at the status of the request. This will tell - * us if there was special handling on the request such that it - * needs to be detached and freed here. - */ - spin_lock_irqsave(&isci_request->state_lock, flags); - - needs_cleanup_handling - = isci_request_is_dealloc_managed( - isci_request->status); - - spin_unlock_irqrestore(&isci_request->state_lock, flags); - - } - if (needs_cleanup_handling) { - - dev_dbg(&ihost->pdev->dev, - "%s: cleanup isci_device=%p, request=%p\n", - __func__, idev, isci_request); - - if (isci_request != NULL) { - spin_lock_irqsave(&ihost->scic_lock, flags); - isci_free_tag(ihost, isci_request->io_tag); - isci_request_change_state(isci_request, unallocated); - list_del_init(&isci_request->dev_node); - spin_unlock_irqrestore(&ihost->scic_lock, flags); - } - } - } -} - -/** - * isci_terminate_pending_requests() - This function will change the all of the - * requests on the given device's state to "aborting", will terminate the - * requests, and wait for them to complete. This function must only be - * called from a thread that can wait. Note that the requests are all - * terminated and completed (back to the host, if started there). - * @isci_host: This parameter specifies SCU. - * @idev: This parameter specifies the target. - * - */ -void isci_terminate_pending_requests(struct isci_host *ihost, - struct isci_remote_device *idev) -{ - struct completion request_completion; - enum isci_request_status old_state; - unsigned long flags; - LIST_HEAD(list); - - spin_lock_irqsave(&ihost->scic_lock, flags); - list_splice_init(&idev->reqs_in_process, &list); - - /* assumes that isci_terminate_request_core deletes from the list */ - while (!list_empty(&list)) { - struct isci_request *ireq = list_entry(list.next, typeof(*ireq), dev_node); - - /* Change state to "terminating" if it is currently - * "started". - */ - old_state = isci_request_change_started_to_newstate(ireq, - &request_completion, - terminating); - switch (old_state) { - case started: - case completed: - case aborting: - break; - default: - /* termination in progress, or otherwise dispositioned. - * We know the request was on 'list' so should be safe - * to move it back to reqs_in_process - */ - list_move(&ireq->dev_node, &idev->reqs_in_process); - ireq = NULL; - break; - } - - if (!ireq) - continue; - spin_unlock_irqrestore(&ihost->scic_lock, flags); - - init_completion(&request_completion); - - dev_dbg(&ihost->pdev->dev, - "%s: idev=%p request=%p; task=%p old_state=%d\n", - __func__, idev, ireq, - (!test_bit(IREQ_TMF, &ireq->flags) - ? isci_request_access_task(ireq) - : NULL), - old_state); - - /* If the old_state is started: - * This request was not already being aborted. If it had been, - * then the aborting I/O (ie. the TMF request) would not be in - * the aborting state, and thus would be terminated here. Note - * that since the TMF completion's call to the kernel function - * "complete()" does not happen until the pending I/O request - * terminate fully completes, we do not have to implement a - * special wait here for already aborting requests - the - * termination of the TMF request will force the request - * to finish it's already started terminate. - * - * If old_state == completed: - * This request completed from the SCU hardware perspective - * and now just needs cleaning up in terms of freeing the - * request and potentially calling up to libsas. - * - * If old_state == aborting: - * This request has already gone through a TMF timeout, but may - * not have been terminated; needs cleaning up at least. - */ - isci_terminate_request_core(ihost, idev, ireq); - spin_lock_irqsave(&ihost->scic_lock, flags); - } - spin_unlock_irqrestore(&ihost->scic_lock, flags); -} - /** * isci_task_send_lu_reset_sas() - This function is called by of the SAS Domain * Template functions. @@ -807,7 +399,7 @@ static int isci_task_send_lu_reset_sas( * value is "TMF_RESP_FUNC_COMPLETE", or the request timed-out (or * was otherwise unable to be executed ("TMF_RESP_FUNC_FAILED"). */ - isci_task_build_tmf(&tmf, isci_tmf_ssp_lun_reset, NULL, NULL); + isci_task_build_tmf(&tmf, isci_tmf_ssp_lun_reset); #define ISCI_LU_RESET_TIMEOUT_MS 2000 /* 2 second timeout. */ ret = isci_task_execute_tmf(isci_host, isci_device, &tmf, ISCI_LU_RESET_TIMEOUT_MS); @@ -826,42 +418,44 @@ static int isci_task_send_lu_reset_sas( int isci_task_lu_reset(struct domain_device *dev, u8 *lun) { - struct isci_host *isci_host = dev_to_ihost(dev); - struct isci_remote_device *isci_device; + struct isci_host *ihost = dev_to_ihost(dev); + struct isci_remote_device *idev; unsigned long flags; - int ret; + int ret = TMF_RESP_FUNC_COMPLETE; - spin_lock_irqsave(&isci_host->scic_lock, flags); - isci_device = isci_lookup_device(dev); - spin_unlock_irqrestore(&isci_host->scic_lock, flags); + spin_lock_irqsave(&ihost->scic_lock, flags); + idev = isci_get_device(dev->lldd_dev); + spin_unlock_irqrestore(&ihost->scic_lock, flags); - dev_dbg(&isci_host->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: domain_device=%p, isci_host=%p; isci_device=%p\n", - __func__, dev, isci_host, isci_device); + __func__, dev, ihost, idev); - if (!isci_device) { - /* If the device is gone, stop the escalations. */ - dev_dbg(&isci_host->pdev->dev, "%s: No dev\n", __func__); + if (!idev) { + /* If the device is gone, escalate to I_T_Nexus_Reset. */ + dev_dbg(&ihost->pdev->dev, "%s: No dev\n", __func__); - ret = TMF_RESP_FUNC_COMPLETE; + ret = TMF_RESP_FUNC_FAILED; goto out; } - /* Send the task management part of the reset. */ - if (dev_is_sata(dev)) { - sas_ata_schedule_reset(dev); - ret = TMF_RESP_FUNC_COMPLETE; - } else - ret = isci_task_send_lu_reset_sas(isci_host, isci_device, lun); - - /* If the LUN reset worked, all the I/O can now be terminated. */ - if (ret == TMF_RESP_FUNC_COMPLETE) - /* Terminate all I/O now. */ - isci_terminate_pending_requests(isci_host, - isci_device); - + /* Suspend the RNC, kill all TCs */ + if (isci_remote_device_suspend_terminate(ihost, idev, NULL) + != SCI_SUCCESS) { + /* The suspend/terminate only fails if isci_get_device fails */ + ret = TMF_RESP_FUNC_FAILED; + goto out; + } + /* All pending I/Os have been terminated and cleaned up. */ + if (!test_bit(IDEV_GONE, &idev->flags)) { + if (dev_is_sata(dev)) + sas_ata_schedule_reset(dev); + else + /* Send the task management part of the reset. */ + ret = isci_task_send_lu_reset_sas(ihost, idev, lun); + } out: - isci_put_device(isci_device); + isci_put_device(idev); return ret; } @@ -881,63 +475,6 @@ int isci_task_clear_nexus_ha(struct sas_ha_struct *ha) /* Task Management Functions. Must be called from process context. */ -/** - * isci_abort_task_process_cb() - This is a helper function for the abort task - * TMF command. It manages the request state with respect to the successful - * transmission / completion of the abort task request. - * @cb_state: This parameter specifies when this function was called - after - * the TMF request has been started and after it has timed-out. - * @tmf: This parameter specifies the TMF in progress. - * - * - */ -static void isci_abort_task_process_cb( - enum isci_tmf_cb_state cb_state, - struct isci_tmf *tmf, - void *cb_data) -{ - struct isci_request *old_request; - - old_request = (struct isci_request *)cb_data; - - dev_dbg(&old_request->isci_host->pdev->dev, - "%s: tmf=%p, old_request=%p\n", - __func__, tmf, old_request); - - switch (cb_state) { - - case isci_tmf_started: - /* The TMF has been started. Nothing to do here, since the - * request state was already set to "aborted" by the abort - * task function. - */ - if ((old_request->status != aborted) - && (old_request->status != completed)) - dev_dbg(&old_request->isci_host->pdev->dev, - "%s: Bad request status (%d): tmf=%p, old_request=%p\n", - __func__, old_request->status, tmf, old_request); - break; - - case isci_tmf_timed_out: - - /* Set the task's state to "aborting", since the abort task - * function thread set it to "aborted" (above) in anticipation - * of the task management request working correctly. Since the - * timeout has now fired, the TMF request failed. We set the - * state such that the request completion will indicate the - * device is no longer present. - */ - isci_request_change_state(old_request, aborting); - break; - - default: - dev_dbg(&old_request->isci_host->pdev->dev, - "%s: Bad cb_state (%d): tmf=%p, old_request=%p\n", - __func__, cb_state, tmf, old_request); - break; - } -} - /** * isci_task_abort_task() - This function is one of the SAS Domain Template * functions. This function is called by libsas to abort a specified task. @@ -947,22 +484,20 @@ static void isci_abort_task_process_cb( */ int isci_task_abort_task(struct sas_task *task) { - struct isci_host *isci_host = dev_to_ihost(task->dev); + struct isci_host *ihost = dev_to_ihost(task->dev); DECLARE_COMPLETION_ONSTACK(aborted_io_completion); struct isci_request *old_request = NULL; - enum isci_request_status old_state; - struct isci_remote_device *isci_device = NULL; + struct isci_remote_device *idev = NULL; struct isci_tmf tmf; int ret = TMF_RESP_FUNC_FAILED; unsigned long flags; - int perform_termination = 0; /* Get the isci_request reference from the task. Note that * this check does not depend on the pending request list * in the device, because tasks driving resets may land here * after completion in the core. */ - spin_lock_irqsave(&isci_host->scic_lock, flags); + spin_lock_irqsave(&ihost->scic_lock, flags); spin_lock(&task->task_state_lock); old_request = task->lldd_task; @@ -971,20 +506,29 @@ int isci_task_abort_task(struct sas_task *task) if (!(task->task_state_flags & SAS_TASK_STATE_DONE) && (task->task_state_flags & SAS_TASK_AT_INITIATOR) && old_request) - isci_device = isci_lookup_device(task->dev); + idev = isci_get_device(task->dev->lldd_dev); spin_unlock(&task->task_state_lock); - spin_unlock_irqrestore(&isci_host->scic_lock, flags); + spin_unlock_irqrestore(&ihost->scic_lock, flags); - dev_dbg(&isci_host->pdev->dev, - "%s: dev = %p, task = %p, old_request == %p\n", - __func__, isci_device, task, old_request); + dev_warn(&ihost->pdev->dev, + "%s: dev = %p (%s%s), task = %p, old_request == %p\n", + __func__, idev, + (dev_is_sata(task->dev) ? "STP/SATA" + : ((dev_is_expander(task->dev)) + ? "SMP" + : "SSP")), + ((idev) ? ((test_bit(IDEV_GONE, &idev->flags)) + ? " IDEV_GONE" + : "") + : " "), + task, old_request); /* Device reset conditions signalled in task_state_flags are the * responsbility of libsas to observe at the start of the error * handler thread. */ - if (!isci_device || !old_request) { + if (!idev || !old_request) { /* The request has already completed and there * is nothing to do here other than to set the task * done bit, and indicate that the task abort function @@ -998,108 +542,72 @@ int isci_task_abort_task(struct sas_task *task) ret = TMF_RESP_FUNC_COMPLETE; - dev_dbg(&isci_host->pdev->dev, - "%s: abort task not needed for %p\n", - __func__, task); + dev_warn(&ihost->pdev->dev, + "%s: abort task not needed for %p\n", + __func__, task); goto out; } - - spin_lock_irqsave(&isci_host->scic_lock, flags); - - /* Check the request status and change to "aborted" if currently - * "starting"; if true then set the I/O kernel completion - * struct that will be triggered when the request completes. - */ - old_state = isci_task_validate_request_to_abort( - old_request, isci_host, isci_device, - &aborted_io_completion); - if ((old_state != started) && - (old_state != completed) && - (old_state != aborting)) { - - spin_unlock_irqrestore(&isci_host->scic_lock, flags); - - /* The request was already being handled by someone else (because - * they got to set the state away from started). - */ - dev_dbg(&isci_host->pdev->dev, - "%s: device = %p; old_request %p already being aborted\n", - __func__, - isci_device, old_request); - ret = TMF_RESP_FUNC_COMPLETE; + /* Suspend the RNC, kill the TC */ + if (isci_remote_device_suspend_terminate(ihost, idev, old_request) + != SCI_SUCCESS) { + dev_warn(&ihost->pdev->dev, + "%s: isci_remote_device_reset_terminate(dev=%p, " + "req=%p, task=%p) failed\n", + __func__, idev, old_request, task); + ret = TMF_RESP_FUNC_FAILED; goto out; } + spin_lock_irqsave(&ihost->scic_lock, flags); + if (task->task_proto == SAS_PROTOCOL_SMP || sas_protocol_ata(task->task_proto) || - test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) { + test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags) || + test_bit(IDEV_GONE, &idev->flags)) { - spin_unlock_irqrestore(&isci_host->scic_lock, flags); + spin_unlock_irqrestore(&ihost->scic_lock, flags); - dev_dbg(&isci_host->pdev->dev, - "%s: %s request" - " or complete_in_target (%d), thus no TMF\n", - __func__, - ((task->task_proto == SAS_PROTOCOL_SMP) - ? "SMP" - : (sas_protocol_ata(task->task_proto) - ? "SATA/STP" - : "") - ), - test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)); - - if (test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) { - spin_lock_irqsave(&task->task_state_lock, flags); - task->task_state_flags |= SAS_TASK_STATE_DONE; - task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR | - SAS_TASK_STATE_PENDING); - spin_unlock_irqrestore(&task->task_state_lock, flags); - ret = TMF_RESP_FUNC_COMPLETE; - } else { - spin_lock_irqsave(&task->task_state_lock, flags); - task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR | - SAS_TASK_STATE_PENDING); - spin_unlock_irqrestore(&task->task_state_lock, flags); - } + /* No task to send, so explicitly resume the device here */ + isci_remote_device_resume_from_abort(ihost, idev); - /* STP and SMP devices are not sent a TMF, but the - * outstanding I/O request is terminated below. This is - * because SATA/STP and SMP discovery path timeouts directly - * call the abort task interface for cleanup. - */ - perform_termination = 1; + dev_warn(&ihost->pdev->dev, + "%s: %s request" + " or complete_in_target (%d), " + "or IDEV_GONE (%d), thus no TMF\n", + __func__, + ((task->task_proto == SAS_PROTOCOL_SMP) + ? "SMP" + : (sas_protocol_ata(task->task_proto) + ? "SATA/STP" + : "") + ), + test_bit(IREQ_COMPLETE_IN_TARGET, + &old_request->flags), + test_bit(IDEV_GONE, &idev->flags)); + + spin_lock_irqsave(&task->task_state_lock, flags); + task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR | + SAS_TASK_STATE_PENDING); + task->task_state_flags |= SAS_TASK_STATE_DONE; + spin_unlock_irqrestore(&task->task_state_lock, flags); + ret = TMF_RESP_FUNC_COMPLETE; } else { /* Fill in the tmf stucture */ isci_task_build_abort_task_tmf(&tmf, isci_tmf_ssp_task_abort, - isci_abort_task_process_cb, old_request); - spin_unlock_irqrestore(&isci_host->scic_lock, flags); + spin_unlock_irqrestore(&ihost->scic_lock, flags); + /* Send the task management request. */ #define ISCI_ABORT_TASK_TIMEOUT_MS 500 /* 1/2 second timeout */ - ret = isci_task_execute_tmf(isci_host, isci_device, &tmf, + ret = isci_task_execute_tmf(ihost, idev, &tmf, ISCI_ABORT_TASK_TIMEOUT_MS); - - if (ret == TMF_RESP_FUNC_COMPLETE) - perform_termination = 1; - else - dev_dbg(&isci_host->pdev->dev, - "%s: isci_task_send_tmf failed\n", __func__); } - if (perform_termination) { - set_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags); - - /* Clean up the request on our side, and wait for the aborted - * I/O to complete. - */ - isci_terminate_request_core(isci_host, isci_device, - old_request); - } - - /* Make sure we do not leave a reference to aborted_io_completion */ - old_request->io_request_completion = NULL; - out: - isci_put_device(isci_device); +out: + dev_warn(&ihost->pdev->dev, + "%s: Done; dev = %p, task = %p , old_request == %p\n", + __func__, idev, task, old_request); + isci_put_device(idev); return ret; } @@ -1195,14 +703,11 @@ isci_task_request_complete(struct isci_host *ihost, { struct isci_tmf *tmf = isci_request_access_tmf(ireq); struct completion *tmf_complete = NULL; - struct completion *request_complete = ireq->io_request_completion; dev_dbg(&ihost->pdev->dev, "%s: request = %p, status=%d\n", __func__, ireq, completion_status); - isci_request_change_state(ireq, completed); - set_bit(IREQ_COMPLETE_IN_TARGET, &ireq->flags); if (tmf) { @@ -1226,20 +731,11 @@ isci_task_request_complete(struct isci_host *ihost, */ set_bit(IREQ_TERMINATED, &ireq->flags); - /* As soon as something is in the terminate path, deallocation is - * managed there. Note that the final non-managed state of a task - * request is "completed". - */ - if ((ireq->status == completed) || - !isci_request_is_dealloc_managed(ireq->status)) { - isci_request_change_state(ireq, unallocated); - isci_free_tag(ihost, ireq->io_tag); - list_del_init(&ireq->dev_node); - } + if (test_and_clear_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags)) + wake_up_all(&ihost->eventq); - /* "request_complete" is set if the task was being terminated. */ - if (request_complete) - complete(request_complete); + if (!test_bit(IREQ_NO_AUTO_FREE_TAG, &ireq->flags)) + isci_free_tag(ihost, ireq->io_tag); /* The task management part completes last. */ if (tmf_complete) @@ -1250,48 +746,38 @@ static int isci_reset_device(struct isci_host *ihost, struct domain_device *dev, struct isci_remote_device *idev) { - int rc; - unsigned long flags; - enum sci_status status; + int rc = TMF_RESP_FUNC_COMPLETE, reset_stat = -1; struct sas_phy *phy = sas_get_local_phy(dev); struct isci_port *iport = dev->port->lldd_port; dev_dbg(&ihost->pdev->dev, "%s: idev %p\n", __func__, idev); - spin_lock_irqsave(&ihost->scic_lock, flags); - status = sci_remote_device_reset(idev); - spin_unlock_irqrestore(&ihost->scic_lock, flags); - - if (status != SCI_SUCCESS) { - dev_dbg(&ihost->pdev->dev, - "%s: sci_remote_device_reset(%p) returned %d!\n", - __func__, idev, status); + /* Suspend the RNC, terminate all outstanding TCs. */ + if (isci_remote_device_suspend_terminate(ihost, idev, NULL) + != SCI_SUCCESS) { rc = TMF_RESP_FUNC_FAILED; goto out; } - - if (scsi_is_sas_phy_local(phy)) { - struct isci_phy *iphy = &ihost->phys[phy->number]; - - rc = isci_port_perform_hard_reset(ihost, iport, iphy); - } else - rc = sas_phy_reset(phy, !dev_is_sata(dev)); - - /* Terminate in-progress I/O now. */ - isci_remote_device_nuke_requests(ihost, idev); - - /* Since all pending TCs have been cleaned, resume the RNC. */ - spin_lock_irqsave(&ihost->scic_lock, flags); - status = sci_remote_device_reset_complete(idev); - spin_unlock_irqrestore(&ihost->scic_lock, flags); - - if (status != SCI_SUCCESS) { - dev_dbg(&ihost->pdev->dev, - "%s: sci_remote_device_reset_complete(%p) " - "returned %d!\n", __func__, idev, status); + /* Note that since the termination for outstanding requests succeeded, + * this function will return success. This is because the resets will + * only fail if the device has been removed (ie. hotplug), and the + * primary duty of this function is to cleanup tasks, so that is the + * relevant status. + */ + if (!test_bit(IDEV_GONE, &idev->flags)) { + if (scsi_is_sas_phy_local(phy)) { + struct isci_phy *iphy = &ihost->phys[phy->number]; + + reset_stat = isci_port_perform_hard_reset(ihost, iport, + iphy); + } else + reset_stat = sas_phy_reset(phy, !dev_is_sata(dev)); } + /* Explicitly resume the RNC here, since there was no task sent. */ + isci_remote_device_resume_from_abort(ihost, idev); - dev_dbg(&ihost->pdev->dev, "%s: idev %p complete.\n", __func__, idev); + dev_dbg(&ihost->pdev->dev, "%s: idev %p complete, reset_stat=%d.\n", + __func__, idev, reset_stat); out: sas_put_local_phy(phy); return rc; @@ -1305,7 +791,7 @@ int isci_task_I_T_nexus_reset(struct domain_device *dev) int ret; spin_lock_irqsave(&ihost->scic_lock, flags); - idev = isci_lookup_device(dev); + idev = isci_get_device(dev->lldd_dev); spin_unlock_irqrestore(&ihost->scic_lock, flags); if (!idev) { diff --git a/trunk/drivers/scsi/isci/task.h b/trunk/drivers/scsi/isci/task.h index 7b6d0e32fd9b..9c06cbad1d26 100644 --- a/trunk/drivers/scsi/isci/task.h +++ b/trunk/drivers/scsi/isci/task.h @@ -62,19 +62,6 @@ struct isci_request; -/** - * enum isci_tmf_cb_state - This enum defines the possible states in which the - * TMF callback function is invoked during the TMF execution process. - * - * - */ -enum isci_tmf_cb_state { - - isci_tmf_init_state = 0, - isci_tmf_started, - isci_tmf_timed_out -}; - /** * enum isci_tmf_function_codes - This enum defines the possible preparations * of task management requests. @@ -87,6 +74,7 @@ enum isci_tmf_function_codes { isci_tmf_ssp_task_abort = TMF_ABORT_TASK, isci_tmf_ssp_lun_reset = TMF_LU_RESET, }; + /** * struct isci_tmf - This class represents the task management object which * acts as an interface to libsas for processing task management requests @@ -106,15 +94,6 @@ struct isci_tmf { u16 io_tag; enum isci_tmf_function_codes tmf_code; int status; - - /* The optional callback function allows the user process to - * track the TMF transmit / timeout conditions. - */ - void (*cb_state_func)( - enum isci_tmf_cb_state, - struct isci_tmf *, void *); - void *cb_data; - }; static inline void isci_print_tmf(struct isci_host *ihost, struct isci_tmf *tmf) @@ -208,113 +187,4 @@ int isci_queuecommand( struct scsi_cmnd *scsi_cmd, void (*donefunc)(struct scsi_cmnd *)); -/** - * enum isci_completion_selection - This enum defines the possible actions to - * take with respect to a given request's notification back to libsas. - * - * - */ -enum isci_completion_selection { - - isci_perform_normal_io_completion, /* Normal notify (task_done) */ - isci_perform_aborted_io_completion, /* No notification. */ - isci_perform_error_io_completion /* Use sas_task_abort */ -}; - -/** - * isci_task_set_completion_status() - This function sets the completion status - * for the request. - * @task: This parameter is the completed request. - * @response: This parameter is the response code for the completed task. - * @status: This parameter is the status code for the completed task. - * -* @return The new notification mode for the request. -*/ -static inline enum isci_completion_selection -isci_task_set_completion_status( - struct sas_task *task, - enum service_response response, - enum exec_status status, - enum isci_completion_selection task_notification_selection) -{ - unsigned long flags; - - spin_lock_irqsave(&task->task_state_lock, flags); - - /* If a device reset is being indicated, make sure the I/O - * is in the error path. - */ - if (task->task_state_flags & SAS_TASK_NEED_DEV_RESET) { - /* Fail the I/O to make sure it goes into the error path. */ - response = SAS_TASK_UNDELIVERED; - status = SAM_STAT_TASK_ABORTED; - - task_notification_selection = isci_perform_error_io_completion; - } - task->task_status.resp = response; - task->task_status.stat = status; - - switch (task->task_proto) { - - case SAS_PROTOCOL_SATA: - case SAS_PROTOCOL_STP: - case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: - - if (task_notification_selection - == isci_perform_error_io_completion) { - /* SATA/STP I/O has it's own means of scheduling device - * error handling on the normal path. - */ - task_notification_selection - = isci_perform_normal_io_completion; - } - break; - default: - break; - } - - switch (task_notification_selection) { - - case isci_perform_error_io_completion: - - if (task->task_proto == SAS_PROTOCOL_SMP) { - /* There is no error escalation in the SMP case. - * Convert to a normal completion to avoid the - * timeout in the discovery path and to let the - * next action take place quickly. - */ - task_notification_selection - = isci_perform_normal_io_completion; - - /* Fall through to the normal case... */ - } else { - /* Use sas_task_abort */ - /* Leave SAS_TASK_STATE_DONE clear - * Leave SAS_TASK_AT_INITIATOR set. - */ - break; - } - - case isci_perform_aborted_io_completion: - /* This path can occur with task-managed requests as well as - * requests terminated because of LUN or device resets. - */ - /* Fall through to the normal case... */ - case isci_perform_normal_io_completion: - /* Normal notification (task_done) */ - task->task_state_flags |= SAS_TASK_STATE_DONE; - task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR | - SAS_TASK_STATE_PENDING); - break; - default: - WARN_ONCE(1, "unknown task_notification_selection: %d\n", - task_notification_selection); - break; - } - - spin_unlock_irqrestore(&task->task_state_lock, flags); - - return task_notification_selection; - -} #endif /* !defined(_SCI_TASK_H_) */ diff --git a/trunk/drivers/scsi/isci/unsolicited_frame_control.c b/trunk/drivers/scsi/isci/unsolicited_frame_control.c index 16f88ab939c8..04a6d0d59a22 100644 --- a/trunk/drivers/scsi/isci/unsolicited_frame_control.c +++ b/trunk/drivers/scsi/isci/unsolicited_frame_control.c @@ -57,31 +57,19 @@ #include "unsolicited_frame_control.h" #include "registers.h" -int sci_unsolicited_frame_control_construct(struct isci_host *ihost) +void sci_unsolicited_frame_control_construct(struct isci_host *ihost) { struct sci_unsolicited_frame_control *uf_control = &ihost->uf_control; struct sci_unsolicited_frame *uf; - u32 buf_len, header_len, i; - dma_addr_t dma; - size_t size; - void *virt; - - /* - * Prepare all of the memory sizes for the UF headers, UF address - * table, and UF buffers themselves. - */ - buf_len = SCU_MAX_UNSOLICITED_FRAMES * SCU_UNSOLICITED_FRAME_BUFFER_SIZE; - header_len = SCU_MAX_UNSOLICITED_FRAMES * sizeof(struct scu_unsolicited_frame_header); - size = buf_len + header_len + SCU_MAX_UNSOLICITED_FRAMES * sizeof(uf_control->address_table.array[0]); + dma_addr_t dma = ihost->ufi_dma; + void *virt = ihost->ufi_buf; + int i; /* * The Unsolicited Frame buffers are set at the start of the UF * memory descriptor entry. The headers and address table will be * placed after the buffers. */ - virt = dmam_alloc_coherent(&ihost->pdev->dev, size, &dma, GFP_KERNEL); - if (!virt) - return -ENOMEM; /* * Program the location of the UF header table into the SCU. @@ -93,8 +81,8 @@ int sci_unsolicited_frame_control_construct(struct isci_host *ihost) * headers, since we program the UF address table pointers to * NULL. */ - uf_control->headers.physical_address = dma + buf_len; - uf_control->headers.array = virt + buf_len; + uf_control->headers.physical_address = dma + SCI_UFI_BUF_SIZE; + uf_control->headers.array = virt + SCI_UFI_BUF_SIZE; /* * Program the location of the UF address table into the SCU. @@ -103,8 +91,8 @@ int sci_unsolicited_frame_control_construct(struct isci_host *ihost) * byte boundary already due to above programming headers being on a * 64-bit boundary and headers are on a 64-bytes in size. */ - uf_control->address_table.physical_address = dma + buf_len + header_len; - uf_control->address_table.array = virt + buf_len + header_len; + uf_control->address_table.physical_address = dma + SCI_UFI_BUF_SIZE + SCI_UFI_HDR_SIZE; + uf_control->address_table.array = virt + SCI_UFI_BUF_SIZE + SCI_UFI_HDR_SIZE; uf_control->get = 0; /* @@ -135,8 +123,6 @@ int sci_unsolicited_frame_control_construct(struct isci_host *ihost) virt += SCU_UNSOLICITED_FRAME_BUFFER_SIZE; dma += SCU_UNSOLICITED_FRAME_BUFFER_SIZE; } - - return 0; } enum sci_status sci_unsolicited_frame_control_get_header(struct sci_unsolicited_frame_control *uf_control, diff --git a/trunk/drivers/scsi/isci/unsolicited_frame_control.h b/trunk/drivers/scsi/isci/unsolicited_frame_control.h index 75d896686f5a..1bc551ec611f 100644 --- a/trunk/drivers/scsi/isci/unsolicited_frame_control.h +++ b/trunk/drivers/scsi/isci/unsolicited_frame_control.h @@ -257,9 +257,13 @@ struct sci_unsolicited_frame_control { }; +#define SCI_UFI_BUF_SIZE (SCU_MAX_UNSOLICITED_FRAMES * SCU_UNSOLICITED_FRAME_BUFFER_SIZE) +#define SCI_UFI_HDR_SIZE (SCU_MAX_UNSOLICITED_FRAMES * sizeof(struct scu_unsolicited_frame_header)) +#define SCI_UFI_TOTAL_SIZE (SCI_UFI_BUF_SIZE + SCI_UFI_HDR_SIZE + SCU_MAX_UNSOLICITED_FRAMES * sizeof(u64)) + struct isci_host; -int sci_unsolicited_frame_control_construct(struct isci_host *ihost); +void sci_unsolicited_frame_control_construct(struct isci_host *ihost); enum sci_status sci_unsolicited_frame_control_get_header( struct sci_unsolicited_frame_control *uf_control, diff --git a/trunk/drivers/scsi/iscsi_tcp.c b/trunk/drivers/scsi/iscsi_tcp.c index 453a740fa68e..922086105b4b 100644 --- a/trunk/drivers/scsi/iscsi_tcp.c +++ b/trunk/drivers/scsi/iscsi_tcp.c @@ -662,7 +662,7 @@ iscsi_sw_tcp_conn_bind(struct iscsi_cls_session *cls_session, /* setup Socket parameters */ sk = sock->sk; - sk->sk_reuse = 1; + sk->sk_reuse = SK_CAN_REUSE; sk->sk_sndtimeo = 15 * HZ; /* FIXME: make it configurable */ sk->sk_allocation = GFP_ATOMIC; diff --git a/trunk/drivers/scsi/libfc/fc_lport.c b/trunk/drivers/scsi/libfc/fc_lport.c index cc83b66d45b7..c1402fb499ab 100644 --- a/trunk/drivers/scsi/libfc/fc_lport.c +++ b/trunk/drivers/scsi/libfc/fc_lport.c @@ -648,6 +648,7 @@ int fc_lport_destroy(struct fc_lport *lport) lport->tt.fcp_abort_io(lport); lport->tt.disc_stop_final(lport); lport->tt.exch_mgr_reset(lport, 0, 0); + cancel_delayed_work_sync(&lport->retry_work); fc_fc4_del_lport(lport); return 0; } @@ -1564,7 +1565,6 @@ static void fc_lport_timeout(struct work_struct *work) switch (lport->state) { case LPORT_ST_DISABLED: - WARN_ON(1); break; case LPORT_ST_READY: break; diff --git a/trunk/drivers/scsi/lpfc/lpfc.h b/trunk/drivers/scsi/lpfc/lpfc.h index 3a1ffdd6d831..e5da6da20f8a 100644 --- a/trunk/drivers/scsi/lpfc/lpfc.h +++ b/trunk/drivers/scsi/lpfc/lpfc.h @@ -93,6 +93,9 @@ struct lpfc_sli2_slim; /* lpfc wait event data ready flag */ #define LPFC_DATA_READY (1<<0) +/* queue dump line buffer size */ +#define LPFC_LBUF_SZ 128 + enum lpfc_polling_flags { ENABLE_FCP_RING_POLLING = 0x1, DISABLE_FCP_RING_INT = 0x2 @@ -620,6 +623,7 @@ struct lpfc_hba { #define HBA_AER_ENABLED 0x1000 /* AER enabled with HBA */ #define HBA_DEVLOSS_TMO 0x2000 /* HBA in devloss timeout */ #define HBA_RRQ_ACTIVE 0x4000 /* process the rrq active list */ +#define HBA_FCP_IOQ_FLUSH 0x8000 /* FCP I/O queues being flushed */ uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/ struct lpfc_dmabuf slim2p; diff --git a/trunk/drivers/scsi/lpfc/lpfc_bsg.c b/trunk/drivers/scsi/lpfc/lpfc_bsg.c index 141e4b40bb55..253d9a857346 100644 --- a/trunk/drivers/scsi/lpfc/lpfc_bsg.c +++ b/trunk/drivers/scsi/lpfc/lpfc_bsg.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2009-2011 Emulex. All rights reserved. * + * Copyright (C) 2009-2012 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -599,6 +599,7 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) cmdiocbq->iocb_cmpl = lpfc_bsg_rport_els_cmp; cmdiocbq->context1 = dd_data; + cmdiocbq->context_un.ndlp = ndlp; cmdiocbq->context2 = rspiocbq; dd_data->type = TYPE_IOCB; dd_data->context_un.iocb.cmdiocbq = cmdiocbq; @@ -3978,6 +3979,7 @@ lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, } else if (subsys == SLI_CONFIG_SUBSYS_COMN) { switch (opcode) { case COMN_OPCODE_GET_CNTL_ADDL_ATTRIBUTES: + case COMN_OPCODE_GET_CNTL_ATTRIBUTES: lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, "3106 Handled SLI_CONFIG " "subsys_comn, opcode:x%x\n", diff --git a/trunk/drivers/scsi/lpfc/lpfc_bsg.h b/trunk/drivers/scsi/lpfc/lpfc_bsg.h index edfe61fc52b1..67f7d0a160d1 100644 --- a/trunk/drivers/scsi/lpfc/lpfc_bsg.h +++ b/trunk/drivers/scsi/lpfc/lpfc_bsg.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2010 Emulex. All rights reserved. * + * Copyright (C) 2010-2012 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -249,6 +249,7 @@ struct lpfc_sli_config_emb1_subsys { #define COMN_OPCODE_READ_OBJECT_LIST 0xAD #define COMN_OPCODE_DELETE_OBJECT 0xAE #define COMN_OPCODE_GET_CNTL_ADDL_ATTRIBUTES 0x79 +#define COMN_OPCODE_GET_CNTL_ATTRIBUTES 0x20 uint32_t timeout; uint32_t request_length; uint32_t word9; diff --git a/trunk/drivers/scsi/lpfc/lpfc_crtn.h b/trunk/drivers/scsi/lpfc/lpfc_crtn.h index 330dd7192a7f..9b2a16f3bc79 100644 --- a/trunk/drivers/scsi/lpfc/lpfc_crtn.h +++ b/trunk/drivers/scsi/lpfc/lpfc_crtn.h @@ -254,6 +254,7 @@ int lpfc_sli_handle_fast_ring_event(struct lpfc_hba *, struct lpfc_sli_ring *, uint32_t); +struct lpfc_iocbq *__lpfc_sli_get_iocbq(struct lpfc_hba *); struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *); void lpfc_sli_release_iocbq(struct lpfc_hba *, struct lpfc_iocbq *); uint16_t lpfc_sli_next_iotag(struct lpfc_hba *, struct lpfc_iocbq *); @@ -460,6 +461,7 @@ int lpfc_hba_init_link_fc_topology(struct lpfc_hba *, uint32_t, uint32_t); int lpfc_issue_reg_vfi(struct lpfc_vport *); int lpfc_issue_unreg_vfi(struct lpfc_vport *); int lpfc_selective_reset(struct lpfc_hba *); -int lpfc_sli4_read_config(struct lpfc_hba *phba); -int lpfc_scsi_buf_update(struct lpfc_hba *phba); -void lpfc_sli4_node_prep(struct lpfc_hba *phba); +int lpfc_sli4_read_config(struct lpfc_hba *); +void lpfc_sli4_node_prep(struct lpfc_hba *); +int lpfc_sli4_xri_sgl_update(struct lpfc_hba *); +void lpfc_free_sgl_list(struct lpfc_hba *, struct list_head *); diff --git a/trunk/drivers/scsi/lpfc/lpfc_debugfs.c b/trunk/drivers/scsi/lpfc/lpfc_debugfs.c index af04b0d6688d..3217d63ed282 100644 --- a/trunk/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/trunk/drivers/scsi/lpfc/lpfc_debugfs.c @@ -4466,3 +4466,49 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport) #endif return; } + +/* + * Driver debug utility routines outside of debugfs. The debug utility + * routines implemented here is intended to be used in the instrumented + * debug driver for debugging host or port issues. + */ + +/** + * lpfc_debug_dump_all_queues - dump all the queues with a hba + * @phba: Pointer to HBA context object. + * + * This function dumps entries of all the queues asociated with the @phba. + **/ +void +lpfc_debug_dump_all_queues(struct lpfc_hba *phba) +{ + int fcp_wqidx; + + /* + * Dump Work Queues (WQs) + */ + lpfc_debug_dump_mbx_wq(phba); + lpfc_debug_dump_els_wq(phba); + + for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++) + lpfc_debug_dump_fcp_wq(phba, fcp_wqidx); + + lpfc_debug_dump_hdr_rq(phba); + lpfc_debug_dump_dat_rq(phba); + /* + * Dump Complete Queues (CQs) + */ + lpfc_debug_dump_mbx_cq(phba); + lpfc_debug_dump_els_cq(phba); + + for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++) + lpfc_debug_dump_fcp_cq(phba, fcp_wqidx); + + /* + * Dump Event Queues (EQs) + */ + lpfc_debug_dump_sp_eq(phba); + + for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++) + lpfc_debug_dump_fcp_eq(phba, fcp_wqidx); +} diff --git a/trunk/drivers/scsi/lpfc/lpfc_debugfs.h b/trunk/drivers/scsi/lpfc/lpfc_debugfs.h index f83bd944edd8..616c400dae14 100644 --- a/trunk/drivers/scsi/lpfc/lpfc_debugfs.h +++ b/trunk/drivers/scsi/lpfc/lpfc_debugfs.h @@ -267,3 +267,421 @@ struct lpfc_idiag { #define LPFC_DISC_TRC_DISCOVERY 0xef /* common mask for general * discovery */ #endif /* H_LPFC_DEBUG_FS */ + + +/* + * Driver debug utility routines outside of debugfs. The debug utility + * routines implemented here is intended to be used in the instrumented + * debug driver for debugging host or port issues. + */ + +/** + * lpfc_debug_dump_qe - dump an specific entry from a queue + * @q: Pointer to the queue descriptor. + * @idx: Index to the entry on the queue. + * + * This function dumps an entry indexed by @idx from a queue specified by the + * queue descriptor @q. + **/ +static inline void +lpfc_debug_dump_qe(struct lpfc_queue *q, uint32_t idx) +{ + char line_buf[LPFC_LBUF_SZ]; + int i, esize, qe_word_cnt, len; + uint32_t *pword; + + /* sanity checks */ + if (!q) + return; + if (idx >= q->entry_count) + return; + + esize = q->entry_size; + qe_word_cnt = esize / sizeof(uint32_t); + pword = q->qe[idx].address; + + len = 0; + len += snprintf(line_buf+len, LPFC_LBUF_SZ-len, "QE[%04d]: ", idx); + if (qe_word_cnt > 8) + printk(KERN_ERR "%s\n", line_buf); + + for (i = 0; i < qe_word_cnt; i++) { + if (!(i % 8)) { + if (i != 0) + printk(KERN_ERR "%s\n", line_buf); + if (qe_word_cnt > 8) { + len = 0; + memset(line_buf, 0, LPFC_LBUF_SZ); + len += snprintf(line_buf+len, LPFC_LBUF_SZ-len, + "%03d: ", i); + } + } + len += snprintf(line_buf+len, LPFC_LBUF_SZ-len, "%08x ", + ((uint32_t)*pword) & 0xffffffff); + pword++; + } + if (qe_word_cnt <= 8 || (i - 1) % 8) + printk(KERN_ERR "%s\n", line_buf); +} + +/** + * lpfc_debug_dump_q - dump all entries from an specific queue + * @q: Pointer to the queue descriptor. + * + * This function dumps all entries from a queue specified by the queue + * descriptor @q. + **/ +static inline void +lpfc_debug_dump_q(struct lpfc_queue *q) +{ + int idx, entry_count; + + /* sanity check */ + if (!q) + return; + + dev_printk(KERN_ERR, &(((q->phba))->pcidev)->dev, + "%d: [qid:%d, type:%d, subtype:%d, " + "qe_size:%d, qe_count:%d, " + "host_index:%d, port_index:%d]\n", + (q->phba)->brd_no, + q->queue_id, q->type, q->subtype, + q->entry_size, q->entry_count, + q->host_index, q->hba_index); + entry_count = q->entry_count; + for (idx = 0; idx < entry_count; idx++) + lpfc_debug_dump_qe(q, idx); + printk(KERN_ERR "\n"); +} + +/** + * lpfc_debug_dump_fcp_wq - dump all entries from a fcp work queue + * @phba: Pointer to HBA context object. + * @fcp_wqidx: Index to a FCP work queue. + * + * This function dumps all entries from a FCP work queue specified by the + * @fcp_wqidx. + **/ +static inline void +lpfc_debug_dump_fcp_wq(struct lpfc_hba *phba, int fcp_wqidx) +{ + /* sanity check */ + if (fcp_wqidx >= phba->cfg_fcp_wq_count) + return; + + printk(KERN_ERR "FCP WQ: WQ[Idx:%d|Qid:%d]\n", + fcp_wqidx, phba->sli4_hba.fcp_wq[fcp_wqidx]->queue_id); + lpfc_debug_dump_q(phba->sli4_hba.fcp_wq[fcp_wqidx]); +} + +/** + * lpfc_debug_dump_fcp_cq - dump all entries from a fcp work queue's cmpl queue + * @phba: Pointer to HBA context object. + * @fcp_wqidx: Index to a FCP work queue. + * + * This function dumps all entries from a FCP complete queue which is + * associated to the FCP work queue specified by the @fcp_wqidx. + **/ +static inline void +lpfc_debug_dump_fcp_cq(struct lpfc_hba *phba, int fcp_wqidx) +{ + int fcp_cqidx, fcp_cqid; + + /* sanity check */ + if (fcp_wqidx >= phba->cfg_fcp_wq_count) + return; + + fcp_cqid = phba->sli4_hba.fcp_wq[fcp_wqidx]->assoc_qid; + for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_eq_count; fcp_cqidx++) + if (phba->sli4_hba.fcp_cq[fcp_cqidx]->queue_id == fcp_cqid) + break; + if (fcp_cqidx >= phba->cfg_fcp_eq_count) + return; + + printk(KERN_ERR "FCP CQ: WQ[Idx:%d|Qid%d]->CQ[Idx%d|Qid%d]:\n", + fcp_wqidx, phba->sli4_hba.fcp_wq[fcp_wqidx]->queue_id, + fcp_cqidx, fcp_cqid); + lpfc_debug_dump_q(phba->sli4_hba.fcp_cq[fcp_cqidx]); +} + +/** + * lpfc_debug_dump_fcp_eq - dump all entries from a fcp work queue's evt queue + * @phba: Pointer to HBA context object. + * @fcp_wqidx: Index to a FCP work queue. + * + * This function dumps all entries from a FCP event queue which is + * associated to the FCP work queue specified by the @fcp_wqidx. + **/ +static inline void +lpfc_debug_dump_fcp_eq(struct lpfc_hba *phba, int fcp_wqidx) +{ + struct lpfc_queue *qdesc; + int fcp_eqidx, fcp_eqid; + int fcp_cqidx, fcp_cqid; + + /* sanity check */ + if (fcp_wqidx >= phba->cfg_fcp_wq_count) + return; + fcp_cqid = phba->sli4_hba.fcp_wq[fcp_wqidx]->assoc_qid; + for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_eq_count; fcp_cqidx++) + if (phba->sli4_hba.fcp_cq[fcp_cqidx]->queue_id == fcp_cqid) + break; + if (fcp_cqidx >= phba->cfg_fcp_eq_count) + return; + + if (phba->cfg_fcp_eq_count == 0) { + fcp_eqidx = -1; + fcp_eqid = phba->sli4_hba.sp_eq->queue_id; + qdesc = phba->sli4_hba.sp_eq; + } else { + fcp_eqidx = fcp_cqidx; + fcp_eqid = phba->sli4_hba.fp_eq[fcp_eqidx]->queue_id; + qdesc = phba->sli4_hba.fp_eq[fcp_eqidx]; + } + + printk(KERN_ERR "FCP EQ: WQ[Idx:%d|Qid:%d]->CQ[Idx:%d|Qid:%d]->" + "EQ[Idx:%d|Qid:%d]\n", + fcp_wqidx, phba->sli4_hba.fcp_wq[fcp_wqidx]->queue_id, + fcp_cqidx, fcp_cqid, fcp_eqidx, fcp_eqid); + lpfc_debug_dump_q(qdesc); +} + +/** + * lpfc_debug_dump_els_wq - dump all entries from the els work queue + * @phba: Pointer to HBA context object. + * + * This function dumps all entries from the ELS work queue. + **/ +static inline void +lpfc_debug_dump_els_wq(struct lpfc_hba *phba) +{ + printk(KERN_ERR "ELS WQ: WQ[Qid:%d]:\n", + phba->sli4_hba.els_wq->queue_id); + lpfc_debug_dump_q(phba->sli4_hba.els_wq); +} + +/** + * lpfc_debug_dump_mbx_wq - dump all entries from the mbox work queue + * @phba: Pointer to HBA context object. + * + * This function dumps all entries from the MBOX work queue. + **/ +static inline void +lpfc_debug_dump_mbx_wq(struct lpfc_hba *phba) +{ + printk(KERN_ERR "MBX WQ: WQ[Qid:%d]\n", + phba->sli4_hba.mbx_wq->queue_id); + lpfc_debug_dump_q(phba->sli4_hba.mbx_wq); +} + +/** + * lpfc_debug_dump_dat_rq - dump all entries from the receive data queue + * @phba: Pointer to HBA context object. + * + * This function dumps all entries from the receive data queue. + **/ +static inline void +lpfc_debug_dump_dat_rq(struct lpfc_hba *phba) +{ + printk(KERN_ERR "DAT RQ: RQ[Qid:%d]\n", + phba->sli4_hba.dat_rq->queue_id); + lpfc_debug_dump_q(phba->sli4_hba.dat_rq); +} + +/** + * lpfc_debug_dump_hdr_rq - dump all entries from the receive header queue + * @phba: Pointer to HBA context object. + * + * This function dumps all entries from the receive header queue. + **/ +static inline void +lpfc_debug_dump_hdr_rq(struct lpfc_hba *phba) +{ + printk(KERN_ERR "HDR RQ: RQ[Qid:%d]\n", + phba->sli4_hba.hdr_rq->queue_id); + lpfc_debug_dump_q(phba->sli4_hba.hdr_rq); +} + +/** + * lpfc_debug_dump_els_cq - dump all entries from the els complete queue + * @phba: Pointer to HBA context object. + * + * This function dumps all entries from the els complete queue. + **/ +static inline void +lpfc_debug_dump_els_cq(struct lpfc_hba *phba) +{ + printk(KERN_ERR "ELS CQ: WQ[Qid:%d]->CQ[Qid:%d]\n", + phba->sli4_hba.els_wq->queue_id, + phba->sli4_hba.els_cq->queue_id); + lpfc_debug_dump_q(phba->sli4_hba.els_cq); +} + +/** + * lpfc_debug_dump_mbx_cq - dump all entries from the mbox complete queue + * @phba: Pointer to HBA context object. + * + * This function dumps all entries from the mbox complete queue. + **/ +static inline void +lpfc_debug_dump_mbx_cq(struct lpfc_hba *phba) +{ + printk(KERN_ERR "MBX CQ: WQ[Qid:%d]->CQ[Qid:%d]\n", + phba->sli4_hba.mbx_wq->queue_id, + phba->sli4_hba.mbx_cq->queue_id); + lpfc_debug_dump_q(phba->sli4_hba.mbx_cq); +} + +/** + * lpfc_debug_dump_sp_eq - dump all entries from slow-path event queue + * @phba: Pointer to HBA context object. + * + * This function dumps all entries from the slow-path event queue. + **/ +static inline void +lpfc_debug_dump_sp_eq(struct lpfc_hba *phba) +{ + printk(KERN_ERR "SP EQ: WQ[Qid:%d/Qid:%d]->CQ[Qid:%d/Qid:%d]->" + "EQ[Qid:%d]:\n", + phba->sli4_hba.mbx_wq->queue_id, + phba->sli4_hba.els_wq->queue_id, + phba->sli4_hba.mbx_cq->queue_id, + phba->sli4_hba.els_cq->queue_id, + phba->sli4_hba.sp_eq->queue_id); + lpfc_debug_dump_q(phba->sli4_hba.sp_eq); +} + +/** + * lpfc_debug_dump_wq_by_id - dump all entries from a work queue by queue id + * @phba: Pointer to HBA context object. + * @qid: Work queue identifier. + * + * This function dumps all entries from a work queue identified by the queue + * identifier. + **/ +static inline void +lpfc_debug_dump_wq_by_id(struct lpfc_hba *phba, int qid) +{ + int wq_idx; + + for (wq_idx = 0; wq_idx < phba->cfg_fcp_wq_count; wq_idx++) + if (phba->sli4_hba.fcp_wq[wq_idx]->queue_id == qid) + break; + if (wq_idx < phba->cfg_fcp_wq_count) { + printk(KERN_ERR "FCP WQ[Idx:%d|Qid:%d]\n", wq_idx, qid); + lpfc_debug_dump_q(phba->sli4_hba.fcp_wq[wq_idx]); + return; + } + + if (phba->sli4_hba.els_wq->queue_id == qid) { + printk(KERN_ERR "ELS WQ[Qid:%d]\n", qid); + lpfc_debug_dump_q(phba->sli4_hba.els_wq); + } +} + +/** + * lpfc_debug_dump_mq_by_id - dump all entries from a mbox queue by queue id + * @phba: Pointer to HBA context object. + * @qid: Mbox work queue identifier. + * + * This function dumps all entries from a mbox work queue identified by the + * queue identifier. + **/ +static inline void +lpfc_debug_dump_mq_by_id(struct lpfc_hba *phba, int qid) +{ + if (phba->sli4_hba.mbx_wq->queue_id == qid) { + printk(KERN_ERR "MBX WQ[Qid:%d]\n", qid); + lpfc_debug_dump_q(phba->sli4_hba.mbx_wq); + } +} + +/** + * lpfc_debug_dump_rq_by_id - dump all entries from a receive queue by queue id + * @phba: Pointer to HBA context object. + * @qid: Receive queue identifier. + * + * This function dumps all entries from a receive queue identified by the + * queue identifier. + **/ +static inline void +lpfc_debug_dump_rq_by_id(struct lpfc_hba *phba, int qid) +{ + if (phba->sli4_hba.hdr_rq->queue_id == qid) { + printk(KERN_ERR "HDR RQ[Qid:%d]\n", qid); + lpfc_debug_dump_q(phba->sli4_hba.hdr_rq); + return; + } + if (phba->sli4_hba.dat_rq->queue_id == qid) { + printk(KERN_ERR "DAT RQ[Qid:%d]\n", qid); + lpfc_debug_dump_q(phba->sli4_hba.dat_rq); + } +} + +/** + * lpfc_debug_dump_cq_by_id - dump all entries from a cmpl queue by queue id + * @phba: Pointer to HBA context object. + * @qid: Complete queue identifier. + * + * This function dumps all entries from a complete queue identified by the + * queue identifier. + **/ +static inline void +lpfc_debug_dump_cq_by_id(struct lpfc_hba *phba, int qid) +{ + int cq_idx = 0; + + do { + if (phba->sli4_hba.fcp_cq[cq_idx]->queue_id == qid) + break; + } while (++cq_idx < phba->cfg_fcp_eq_count); + + if (cq_idx < phba->cfg_fcp_eq_count) { + printk(KERN_ERR "FCP CQ[Idx:%d|Qid:%d]\n", cq_idx, qid); + lpfc_debug_dump_q(phba->sli4_hba.fcp_cq[cq_idx]); + return; + } + + if (phba->sli4_hba.els_cq->queue_id == qid) { + printk(KERN_ERR "ELS CQ[Qid:%d]\n", qid); + lpfc_debug_dump_q(phba->sli4_hba.els_cq); + return; + } + + if (phba->sli4_hba.mbx_cq->queue_id == qid) { + printk(KERN_ERR "MBX CQ[Qid:%d]\n", qid); + lpfc_debug_dump_q(phba->sli4_hba.mbx_cq); + } +} + +/** + * lpfc_debug_dump_eq_by_id - dump all entries from an event queue by queue id + * @phba: Pointer to HBA context object. + * @qid: Complete queue identifier. + * + * This function dumps all entries from an event queue identified by the + * queue identifier. + **/ +static inline void +lpfc_debug_dump_eq_by_id(struct lpfc_hba *phba, int qid) +{ + int eq_idx; + + for (eq_idx = 0; eq_idx < phba->cfg_fcp_eq_count; eq_idx++) { + if (phba->sli4_hba.fp_eq[eq_idx]->queue_id == qid) + break; + } + + if (eq_idx < phba->cfg_fcp_eq_count) { + printk(KERN_ERR "FCP EQ[Idx:%d|Qid:%d]\n", eq_idx, qid); + lpfc_debug_dump_q(phba->sli4_hba.fp_eq[eq_idx]); + return; + } + + if (phba->sli4_hba.sp_eq->queue_id == qid) { + printk(KERN_ERR "SP EQ[|Qid:%d]\n", qid); + lpfc_debug_dump_q(phba->sli4_hba.sp_eq); + } +} + +void lpfc_debug_dump_all_queues(struct lpfc_hba *); diff --git a/trunk/drivers/scsi/lpfc/lpfc_els.c b/trunk/drivers/scsi/lpfc/lpfc_els.c index 3407b39e0a3f..d54ae1999797 100644 --- a/trunk/drivers/scsi/lpfc/lpfc_els.c +++ b/trunk/drivers/scsi/lpfc/lpfc_els.c @@ -230,27 +230,43 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, INIT_LIST_HEAD(&pbuflist->list); - icmd->un.elsreq64.bdl.addrHigh = putPaddrHigh(pbuflist->phys); - icmd->un.elsreq64.bdl.addrLow = putPaddrLow(pbuflist->phys); - icmd->un.elsreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; - icmd->un.elsreq64.remoteID = did; /* DID */ if (expectRsp) { + icmd->un.elsreq64.bdl.addrHigh = putPaddrHigh(pbuflist->phys); + icmd->un.elsreq64.bdl.addrLow = putPaddrLow(pbuflist->phys); + icmd->un.elsreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; icmd->un.elsreq64.bdl.bdeSize = (2 * sizeof(struct ulp_bde64)); + + icmd->un.elsreq64.remoteID = did; /* DID */ icmd->ulpCommand = CMD_ELS_REQUEST64_CR; icmd->ulpTimeout = phba->fc_ratov * 2; } else { - icmd->un.elsreq64.bdl.bdeSize = sizeof(struct ulp_bde64); + icmd->un.xseq64.bdl.addrHigh = putPaddrHigh(pbuflist->phys); + icmd->un.xseq64.bdl.addrLow = putPaddrLow(pbuflist->phys); + icmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; + icmd->un.xseq64.bdl.bdeSize = sizeof(struct ulp_bde64); + icmd->un.xseq64.xmit_els_remoteID = did; /* DID */ icmd->ulpCommand = CMD_XMIT_ELS_RSP64_CX; } icmd->ulpBdeCount = 1; icmd->ulpLe = 1; icmd->ulpClass = CLASS3; - if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) { - icmd->un.elsreq64.myID = vport->fc_myDID; + /* + * If we have NPIV enabled, we want to send ELS traffic by VPI. + * For SLI4, since the driver controls VPIs we also want to include + * all ELS pt2pt protocol traffic as well. + */ + if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) || + ((phba->sli_rev == LPFC_SLI_REV4) && + (vport->fc_flag & FC_PT2PT))) { + + if (expectRsp) { + icmd->un.elsreq64.myID = vport->fc_myDID; + + /* For ELS_REQUEST64_CR, use the VPI by default */ + icmd->ulpContext = phba->vpi_ids[vport->vpi]; + } - /* For ELS_REQUEST64_CR, use the VPI by default */ - icmd->ulpContext = phba->vpi_ids[vport->vpi]; icmd->ulpCt_h = 0; /* The CT field must be 0=INVALID_RPI for the ECHO cmd */ if (elscmd == ELS_CMD_ECHO) @@ -438,9 +454,10 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport) int rc = 0; sp = &phba->fc_fabparam; - /* move forward in case of SLI4 FC port loopback test */ + /* move forward in case of SLI4 FC port loopback test and pt2pt mode */ if ((phba->sli_rev == LPFC_SLI_REV4) && - !(phba->link_flag & LS_LOOPBACK_MODE)) { + !(phba->link_flag & LS_LOOPBACK_MODE) && + !(vport->fc_flag & FC_PT2PT)) { ndlp = lpfc_findnode_did(vport, Fabric_DID); if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { rc = -ENODEV; @@ -707,14 +724,17 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_sli4_unreg_all_rpis(vport); lpfc_mbx_unreg_vpi(vport); spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; - /* - * If VPI is unreged, driver need to do INIT_VPI - * before re-registering - */ vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; spin_unlock_irq(shost->host_lock); } + + /* + * For SLI3 and SLI4, the VPI needs to be reregistered in + * response to this fabric parameter change event. + */ + spin_lock_irq(shost->host_lock); + vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; + spin_unlock_irq(shost->host_lock); } else if ((phba->sli_rev == LPFC_SLI_REV4) && !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) { /* @@ -817,6 +837,17 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, mempool_free(mbox, phba->mbox_mem_pool); goto fail; } + + /* + * For SLI4, the VFI/VPI are registered AFTER the + * Nport with the higher WWPN sends the PLOGI with + * an assigned NPortId. + */ + + /* not equal */ + if ((phba->sli_rev == LPFC_SLI_REV4) && rc) + lpfc_issue_reg_vfi(vport); + /* Decrement ndlp reference count indicating that ndlp can be * safely released when other references to it are done. */ @@ -2972,7 +3003,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * ABTS we cannot generate and RRQ. */ lpfc_set_rrq_active(phba, ndlp, - cmdiocb->sli4_xritag, 0, 0); + cmdiocb->sli4_lxritag, 0, 0); } break; case IOSTAT_LOCAL_REJECT: @@ -3803,10 +3834,11 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, /* Xmit ELS ACC response tag */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0128 Xmit ELS ACC response tag x%x, XRI: x%x, " - "DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x\n", + "DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x " + "fc_flag x%x\n", elsiocb->iotag, elsiocb->iocb.ulpContext, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, - ndlp->nlp_rpi); + ndlp->nlp_rpi, vport->fc_flag); if (ndlp->nlp_flag & NLP_LOGO_ACC) { spin_lock_irq(shost->host_lock); ndlp->nlp_flag &= ~NLP_LOGO_ACC; @@ -4936,8 +4968,6 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, return 1; } - did = Fabric_DID; - if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1))) { /* For a FLOGI we accept, then if our portname is greater * then the remote portname we initiate Nport login. @@ -4976,26 +5006,82 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_PT2PT_PLOGI; spin_unlock_irq(shost->host_lock); + + /* If we have the high WWPN we can assign our own + * myDID; otherwise, we have to WAIT for a PLOGI + * from the remote NPort to find out what it + * will be. + */ + vport->fc_myDID = PT2PT_LocalID; } + + /* + * The vport state should go to LPFC_FLOGI only + * AFTER we issue a FLOGI, not receive one. + */ spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_PT2PT; vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); spin_unlock_irq(shost->host_lock); + + /* + * We temporarily set fc_myDID to make it look like we are + * a Fabric. This is done just so we end up with the right + * did / sid on the FLOGI ACC rsp. + */ + did = vport->fc_myDID; + vport->fc_myDID = Fabric_DID; + } else { /* Reject this request because invalid parameters */ stat.un.b.lsRjtRsvd0 = 0; stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS; stat.un.b.vendorUnique = 0; + + /* + * We temporarily set fc_myDID to make it look like we are + * a Fabric. This is done just so we end up with the right + * did / sid on the FLOGI LS_RJT rsp. + */ + did = vport->fc_myDID; + vport->fc_myDID = Fabric_DID; + lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); + + /* Now lets put fc_myDID back to what its supposed to be */ + vport->fc_myDID = did; + return 1; } /* Send back ACC */ lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL); + /* Now lets put fc_myDID back to what its supposed to be */ + vport->fc_myDID = did; + + if (!(vport->fc_flag & FC_PT2PT_PLOGI)) { + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + goto fail; + + lpfc_config_link(phba, mbox); + + mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + mbox->vport = vport; + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + mempool_free(mbox, phba->mbox_mem_pool); + goto fail; + } + } + return 0; +fail: + return 1; } /** @@ -5176,7 +5262,6 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) } cmdsize = sizeof(struct RLS_RSP) + sizeof(uint32_t); - mempool_free(pmb, phba->mbox_mem_pool); elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize, lpfc_max_els_tries, ndlp, ndlp->nlp_DID, ELS_CMD_ACC); @@ -5184,8 +5269,10 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) /* Decrement the ndlp reference count from previous mbox command */ lpfc_nlp_put(ndlp); - if (!elsiocb) + if (!elsiocb) { + mempool_free(pmb, phba->mbox_mem_pool); return; + } icmd = &elsiocb->iocb; icmd->ulpContext = rxid; @@ -5202,7 +5289,7 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) rls_rsp->primSeqErrCnt = cpu_to_be32(mb->un.varRdLnk.primSeqErrCnt); rls_rsp->invalidXmitWord = cpu_to_be32(mb->un.varRdLnk.invalidXmitWord); rls_rsp->crcCnt = cpu_to_be32(mb->un.varRdLnk.crcCnt); - + mempool_free(pmb, phba->mbox_mem_pool); /* Xmit ELS RLS ACC response tag */ lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS, "2874 Xmit ELS RLS ACC response tag x%x xri x%x, " @@ -5586,7 +5673,7 @@ lpfc_issue_els_rrq(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, pcmd += sizeof(uint32_t); els_rrq = (struct RRQ *) pcmd; - bf_set(rrq_oxid, els_rrq, rrq->xritag); + bf_set(rrq_oxid, els_rrq, phba->sli4_hba.xri_ids[rrq->xritag]); bf_set(rrq_rxid, els_rrq, rrq->rxid); bf_set(rrq_did, els_rrq, vport->fc_myDID); els_rrq->rrq = cpu_to_be32(els_rrq->rrq); @@ -7873,7 +7960,9 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba, sglq_entry->state = SGL_FREED; spin_unlock(&phba->sli4_hba.abts_sgl_list_lock); spin_unlock_irqrestore(&phba->hbalock, iflag); - lpfc_set_rrq_active(phba, ndlp, xri, rxid, 1); + lpfc_set_rrq_active(phba, ndlp, + sglq_entry->sli4_lxritag, + rxid, 1); /* Check if TXQ queue needs to be serviced */ if (pring->txq_cnt) diff --git a/trunk/drivers/scsi/lpfc/lpfc_hbadisc.c b/trunk/drivers/scsi/lpfc/lpfc_hbadisc.c index b507536dc5b5..5bb269e224f6 100644 --- a/trunk/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/trunk/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -713,6 +713,7 @@ lpfc_do_work(void *p) int rc; set_user_nice(current, -20); + current->flags |= PF_NOFREEZE; phba->data_flags = 0; while (!kthread_should_stop()) { @@ -1094,7 +1095,7 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) /* Start discovery by sending a FLOGI. port_state is identically * LPFC_FLOGI while waiting for FLOGI cmpl */ - if (vport->port_state != LPFC_FLOGI) + if (vport->port_state != LPFC_FLOGI || vport->fc_flag & FC_PT2PT_PLOGI) lpfc_initial_flogi(vport); return; @@ -2881,9 +2882,14 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) } if (vport->port_state == LPFC_FABRIC_CFG_LINK) { - /* For private loop just start discovery and we are done. */ - if ((phba->fc_topology == LPFC_TOPOLOGY_LOOP) && - !(vport->fc_flag & FC_PUBLIC_LOOP)) { + /* + * For private loop or for NPort pt2pt, + * just start discovery and we are done. + */ + if ((vport->fc_flag & FC_PT2PT) || + ((phba->fc_topology == LPFC_TOPOLOGY_LOOP) && + !(vport->fc_flag & FC_PUBLIC_LOOP))) { + /* Use loop map to make discovery list */ lpfc_disc_list_loopmap(vport); /* Start discovery */ @@ -5490,9 +5496,9 @@ lpfc_nlp_release(struct kref *kref) ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, - "0279 lpfc_nlp_release: ndlp:x%p " + "0279 lpfc_nlp_release: ndlp:x%p did %x " "usgmap:x%x refcnt:%d\n", - (void *)ndlp, ndlp->nlp_usg_map, + (void *)ndlp, ndlp->nlp_DID, ndlp->nlp_usg_map, atomic_read(&ndlp->kref.refcount)); /* remove ndlp from action. */ diff --git a/trunk/drivers/scsi/lpfc/lpfc_hw.h b/trunk/drivers/scsi/lpfc/lpfc_hw.h index 5f280b5ae3db..41bb1d2fb625 100644 --- a/trunk/drivers/scsi/lpfc/lpfc_hw.h +++ b/trunk/drivers/scsi/lpfc/lpfc_hw.h @@ -3374,6 +3374,9 @@ typedef struct { WORD5 w5; /* Header control/status word */ } XMT_SEQ_FIELDS64; +/* This word is remote ports D_ID for XMIT_ELS_RSP64 */ +#define xmit_els_remoteID xrsqRo + /* IOCB Command template for 64 bit RCV_SEQUENCE64 */ typedef struct { struct ulp_bde64 rcvBde; diff --git a/trunk/drivers/scsi/lpfc/lpfc_hw4.h b/trunk/drivers/scsi/lpfc/lpfc_hw4.h index 91f09761bd32..f1946dfda5b4 100644 --- a/trunk/drivers/scsi/lpfc/lpfc_hw4.h +++ b/trunk/drivers/scsi/lpfc/lpfc_hw4.h @@ -228,19 +228,15 @@ struct lpfc_sli4_flags { #define lpfc_idx_rsrc_rdy_MASK 0x00000001 #define lpfc_idx_rsrc_rdy_WORD word0 #define LPFC_IDX_RSRC_RDY 1 -#define lpfc_xri_rsrc_rdy_SHIFT 1 -#define lpfc_xri_rsrc_rdy_MASK 0x00000001 -#define lpfc_xri_rsrc_rdy_WORD word0 -#define LPFC_XRI_RSRC_RDY 1 -#define lpfc_rpi_rsrc_rdy_SHIFT 2 +#define lpfc_rpi_rsrc_rdy_SHIFT 1 #define lpfc_rpi_rsrc_rdy_MASK 0x00000001 #define lpfc_rpi_rsrc_rdy_WORD word0 #define LPFC_RPI_RSRC_RDY 1 -#define lpfc_vpi_rsrc_rdy_SHIFT 3 +#define lpfc_vpi_rsrc_rdy_SHIFT 2 #define lpfc_vpi_rsrc_rdy_MASK 0x00000001 #define lpfc_vpi_rsrc_rdy_WORD word0 #define LPFC_VPI_RSRC_RDY 1 -#define lpfc_vfi_rsrc_rdy_SHIFT 4 +#define lpfc_vfi_rsrc_rdy_SHIFT 3 #define lpfc_vfi_rsrc_rdy_MASK 0x00000001 #define lpfc_vfi_rsrc_rdy_WORD word0 #define LPFC_VFI_RSRC_RDY 1 @@ -3299,7 +3295,13 @@ struct els_request64_wqe { struct xmit_els_rsp64_wqe { struct ulp_bde64 bde; uint32_t response_payload_len; - uint32_t rsvd4; + uint32_t word4; +#define els_rsp64_sid_SHIFT 0 +#define els_rsp64_sid_MASK 0x00FFFFFF +#define els_rsp64_sid_WORD word4 +#define els_rsp64_sp_SHIFT 24 +#define els_rsp64_sp_MASK 0x00000001 +#define els_rsp64_sp_WORD word4 struct wqe_did wqe_dest; struct wqe_common wqe_com; /* words 6-11 */ uint32_t word12; diff --git a/trunk/drivers/scsi/lpfc/lpfc_init.c b/trunk/drivers/scsi/lpfc/lpfc_init.c index 9598fdcb08ab..411ed48d79da 100644 --- a/trunk/drivers/scsi/lpfc/lpfc_init.c +++ b/trunk/drivers/scsi/lpfc/lpfc_init.c @@ -64,8 +64,8 @@ static int lpfc_sli4_queue_verify(struct lpfc_hba *); static int lpfc_create_bootstrap_mbox(struct lpfc_hba *); static int lpfc_setup_endian_order(struct lpfc_hba *); static void lpfc_destroy_bootstrap_mbox(struct lpfc_hba *); -static void lpfc_free_sgl_list(struct lpfc_hba *); -static int lpfc_init_sgl_list(struct lpfc_hba *); +static void lpfc_free_els_sgl_list(struct lpfc_hba *); +static void lpfc_init_sgl_list(struct lpfc_hba *); static int lpfc_init_active_sgl_array(struct lpfc_hba *); static void lpfc_free_active_sgl(struct lpfc_hba *); static int lpfc_hba_down_post_s3(struct lpfc_hba *phba); @@ -2766,36 +2766,6 @@ lpfc_offline(struct lpfc_hba *phba) lpfc_destroy_vport_work_array(phba, vports); } -/** - * lpfc_scsi_buf_update - Update the scsi_buffers that are already allocated. - * @phba: pointer to lpfc hba data structure. - * - * This routine goes through all the scsi buffers in the system and updates the - * Physical XRIs assigned to the SCSI buffer because these may change after any - * firmware reset - * - * Return codes - * 0 - successful (for now, it always returns 0) - **/ -int -lpfc_scsi_buf_update(struct lpfc_hba *phba) -{ - struct lpfc_scsi_buf *sb, *sb_next; - - spin_lock_irq(&phba->hbalock); - spin_lock(&phba->scsi_buf_list_lock); - list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list, list) { - sb->cur_iocbq.sli4_xritag = - phba->sli4_hba.xri_ids[sb->cur_iocbq.sli4_lxritag]; - set_bit(sb->cur_iocbq.sli4_lxritag, phba->sli4_hba.xri_bmask); - phba->sli4_hba.max_cfg_param.xri_used++; - phba->sli4_hba.xri_count++; - } - spin_unlock(&phba->scsi_buf_list_lock); - spin_unlock_irq(&phba->hbalock); - return 0; -} - /** * lpfc_scsi_free - Free all the SCSI buffers and IOCBs from driver lists * @phba: pointer to lpfc hba data structure. @@ -2803,11 +2773,8 @@ lpfc_scsi_buf_update(struct lpfc_hba *phba) * This routine is to free all the SCSI buffers and IOCBs from the driver * list back to kernel. It is called from lpfc_pci_remove_one to free * the internal resources before the device is removed from the system. - * - * Return codes - * 0 - successful (for now, it always returns 0) **/ -static int +static void lpfc_scsi_free(struct lpfc_hba *phba) { struct lpfc_scsi_buf *sb, *sb_next; @@ -2833,7 +2800,178 @@ lpfc_scsi_free(struct lpfc_hba *phba) } spin_unlock_irq(&phba->hbalock); +} + +/** + * lpfc_sli4_xri_sgl_update - update xri-sgl sizing and mapping + * @phba: pointer to lpfc hba data structure. + * + * This routine first calculates the sizes of the current els and allocated + * scsi sgl lists, and then goes through all sgls to updates the physical + * XRIs assigned due to port function reset. During port initialization, the + * current els and allocated scsi sgl lists are 0s. + * + * Return codes + * 0 - successful (for now, it always returns 0) + **/ +int +lpfc_sli4_xri_sgl_update(struct lpfc_hba *phba) +{ + struct lpfc_sglq *sglq_entry = NULL, *sglq_entry_next = NULL; + struct lpfc_scsi_buf *psb = NULL, *psb_next = NULL; + uint16_t i, lxri, xri_cnt, els_xri_cnt, scsi_xri_cnt; + LIST_HEAD(els_sgl_list); + LIST_HEAD(scsi_sgl_list); + int rc; + + /* + * update on pci function's els xri-sgl list + */ + els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba); + if (els_xri_cnt > phba->sli4_hba.els_xri_cnt) { + /* els xri-sgl expanded */ + xri_cnt = els_xri_cnt - phba->sli4_hba.els_xri_cnt; + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3157 ELS xri-sgl count increased from " + "%d to %d\n", phba->sli4_hba.els_xri_cnt, + els_xri_cnt); + /* allocate the additional els sgls */ + for (i = 0; i < xri_cnt; i++) { + sglq_entry = kzalloc(sizeof(struct lpfc_sglq), + GFP_KERNEL); + if (sglq_entry == NULL) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2562 Failure to allocate an " + "ELS sgl entry:%d\n", i); + rc = -ENOMEM; + goto out_free_mem; + } + sglq_entry->buff_type = GEN_BUFF_TYPE; + sglq_entry->virt = lpfc_mbuf_alloc(phba, 0, + &sglq_entry->phys); + if (sglq_entry->virt == NULL) { + kfree(sglq_entry); + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2563 Failure to allocate an " + "ELS mbuf:%d\n", i); + rc = -ENOMEM; + goto out_free_mem; + } + sglq_entry->sgl = sglq_entry->virt; + memset(sglq_entry->sgl, 0, LPFC_BPL_SIZE); + sglq_entry->state = SGL_FREED; + list_add_tail(&sglq_entry->list, &els_sgl_list); + } + spin_lock(&phba->hbalock); + list_splice_init(&els_sgl_list, &phba->sli4_hba.lpfc_sgl_list); + spin_unlock(&phba->hbalock); + } else if (els_xri_cnt < phba->sli4_hba.els_xri_cnt) { + /* els xri-sgl shrinked */ + xri_cnt = phba->sli4_hba.els_xri_cnt - els_xri_cnt; + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3158 ELS xri-sgl count decreased from " + "%d to %d\n", phba->sli4_hba.els_xri_cnt, + els_xri_cnt); + spin_lock_irq(&phba->hbalock); + list_splice_init(&phba->sli4_hba.lpfc_sgl_list, &els_sgl_list); + spin_unlock_irq(&phba->hbalock); + /* release extra els sgls from list */ + for (i = 0; i < xri_cnt; i++) { + list_remove_head(&els_sgl_list, + sglq_entry, struct lpfc_sglq, list); + if (sglq_entry) { + lpfc_mbuf_free(phba, sglq_entry->virt, + sglq_entry->phys); + kfree(sglq_entry); + } + } + spin_lock_irq(&phba->hbalock); + list_splice_init(&els_sgl_list, &phba->sli4_hba.lpfc_sgl_list); + spin_unlock_irq(&phba->hbalock); + } else + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3163 ELS xri-sgl count unchanged: %d\n", + els_xri_cnt); + phba->sli4_hba.els_xri_cnt = els_xri_cnt; + + /* update xris to els sgls on the list */ + sglq_entry = NULL; + sglq_entry_next = NULL; + list_for_each_entry_safe(sglq_entry, sglq_entry_next, + &phba->sli4_hba.lpfc_sgl_list, list) { + lxri = lpfc_sli4_next_xritag(phba); + if (lxri == NO_XRI) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2400 Failed to allocate xri for " + "ELS sgl\n"); + rc = -ENOMEM; + goto out_free_mem; + } + sglq_entry->sli4_lxritag = lxri; + sglq_entry->sli4_xritag = phba->sli4_hba.xri_ids[lxri]; + } + + /* + * update on pci function's allocated scsi xri-sgl list + */ + phba->total_scsi_bufs = 0; + + /* maximum number of xris available for scsi buffers */ + phba->sli4_hba.scsi_xri_max = phba->sli4_hba.max_cfg_param.max_xri - + els_xri_cnt; + + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "2401 Current allocated SCSI xri-sgl count:%d, " + "maximum SCSI xri count:%d\n", + phba->sli4_hba.scsi_xri_cnt, + phba->sli4_hba.scsi_xri_max); + + spin_lock_irq(&phba->scsi_buf_list_lock); + list_splice_init(&phba->lpfc_scsi_buf_list, &scsi_sgl_list); + spin_unlock_irq(&phba->scsi_buf_list_lock); + + if (phba->sli4_hba.scsi_xri_cnt > phba->sli4_hba.scsi_xri_max) { + /* max scsi xri shrinked below the allocated scsi buffers */ + scsi_xri_cnt = phba->sli4_hba.scsi_xri_cnt - + phba->sli4_hba.scsi_xri_max; + /* release the extra allocated scsi buffers */ + for (i = 0; i < scsi_xri_cnt; i++) { + list_remove_head(&scsi_sgl_list, psb, + struct lpfc_scsi_buf, list); + pci_pool_free(phba->lpfc_scsi_dma_buf_pool, psb->data, + psb->dma_handle); + kfree(psb); + } + spin_lock_irq(&phba->scsi_buf_list_lock); + phba->sli4_hba.scsi_xri_cnt -= scsi_xri_cnt; + spin_unlock_irq(&phba->scsi_buf_list_lock); + } + + /* update xris associated to remaining allocated scsi buffers */ + psb = NULL; + psb_next = NULL; + list_for_each_entry_safe(psb, psb_next, &scsi_sgl_list, list) { + lxri = lpfc_sli4_next_xritag(phba); + if (lxri == NO_XRI) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2560 Failed to allocate xri for " + "scsi buffer\n"); + rc = -ENOMEM; + goto out_free_mem; + } + psb->cur_iocbq.sli4_lxritag = lxri; + psb->cur_iocbq.sli4_xritag = phba->sli4_hba.xri_ids[lxri]; + } + spin_lock(&phba->scsi_buf_list_lock); + list_splice_init(&scsi_sgl_list, &phba->lpfc_scsi_buf_list); + spin_unlock(&phba->scsi_buf_list_lock); + return 0; + +out_free_mem: + lpfc_free_els_sgl_list(phba); + lpfc_scsi_free(phba); + return rc; } /** @@ -4636,18 +4774,15 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) if (rc) goto out_free_bsmbx; - /* Initialize and populate the iocb list per host */ - rc = lpfc_init_sgl_list(phba); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1400 Failed to initialize sgl list.\n"); - goto out_destroy_cq_event_pool; - } + /* Initialize sgl lists per host */ + lpfc_init_sgl_list(phba); + + /* Allocate and initialize active sgl array */ rc = lpfc_init_active_sgl_array(phba); if (rc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "1430 Failed to initialize sgl list.\n"); - goto out_free_sgl_list; + goto out_destroy_cq_event_pool; } rc = lpfc_sli4_init_rpi_hdrs(phba); if (rc) { @@ -4722,8 +4857,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) lpfc_sli4_remove_rpi_hdrs(phba); out_free_active_sgl: lpfc_free_active_sgl(phba); -out_free_sgl_list: - lpfc_free_sgl_list(phba); out_destroy_cq_event_pool: lpfc_sli4_cq_event_pool_destroy(phba); out_free_bsmbx: @@ -4760,10 +4893,7 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba) /* Free the ELS sgl list */ lpfc_free_active_sgl(phba); - lpfc_free_sgl_list(phba); - - /* Free the SCSI sgl management array */ - kfree(phba->sli4_hba.lpfc_scsi_psb_array); + lpfc_free_els_sgl_list(phba); /* Free the completion queue EQ event pool */ lpfc_sli4_cq_event_release_all(phba); @@ -4990,29 +5120,42 @@ lpfc_init_iocb_list(struct lpfc_hba *phba, int iocb_count) } /** - * lpfc_free_sgl_list - Free sgl list. + * lpfc_free_sgl_list - Free a given sgl list. * @phba: pointer to lpfc hba data structure. + * @sglq_list: pointer to the head of sgl list. * - * This routine is invoked to free the driver's sgl list and memory. + * This routine is invoked to free a give sgl list and memory. **/ -static void -lpfc_free_sgl_list(struct lpfc_hba *phba) +void +lpfc_free_sgl_list(struct lpfc_hba *phba, struct list_head *sglq_list) { struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL; + + list_for_each_entry_safe(sglq_entry, sglq_next, sglq_list, list) { + list_del(&sglq_entry->list); + lpfc_mbuf_free(phba, sglq_entry->virt, sglq_entry->phys); + kfree(sglq_entry); + } +} + +/** + * lpfc_free_els_sgl_list - Free els sgl list. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to free the driver's els sgl list and memory. + **/ +static void +lpfc_free_els_sgl_list(struct lpfc_hba *phba) +{ LIST_HEAD(sglq_list); + /* Retrieve all els sgls from driver list */ spin_lock_irq(&phba->hbalock); list_splice_init(&phba->sli4_hba.lpfc_sgl_list, &sglq_list); spin_unlock_irq(&phba->hbalock); - list_for_each_entry_safe(sglq_entry, sglq_next, - &sglq_list, list) { - list_del(&sglq_entry->list); - lpfc_mbuf_free(phba, sglq_entry->virt, sglq_entry->phys); - kfree(sglq_entry); - phba->sli4_hba.total_sglq_bufs--; - } - kfree(phba->sli4_hba.lpfc_els_sgl_array); + /* Now free the sgl list */ + lpfc_free_sgl_list(phba, &sglq_list); } /** @@ -5057,99 +5200,19 @@ lpfc_free_active_sgl(struct lpfc_hba *phba) * This routine is invoked to allocate and initizlize the driver's sgl * list and set up the sgl xritag tag array accordingly. * - * Return codes - * 0 - successful - * other values - error **/ -static int +static void lpfc_init_sgl_list(struct lpfc_hba *phba) { - struct lpfc_sglq *sglq_entry = NULL; - int i; - int els_xri_cnt; - - els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba); - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "2400 ELS XRI count %d.\n", - els_xri_cnt); /* Initialize and populate the sglq list per host/VF. */ INIT_LIST_HEAD(&phba->sli4_hba.lpfc_sgl_list); INIT_LIST_HEAD(&phba->sli4_hba.lpfc_abts_els_sgl_list); - /* Sanity check on XRI management */ - if (phba->sli4_hba.max_cfg_param.max_xri <= els_xri_cnt) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2562 No room left for SCSI XRI allocation: " - "max_xri=%d, els_xri=%d\n", - phba->sli4_hba.max_cfg_param.max_xri, - els_xri_cnt); - return -ENOMEM; - } - - /* Allocate memory for the ELS XRI management array */ - phba->sli4_hba.lpfc_els_sgl_array = - kzalloc((sizeof(struct lpfc_sglq *) * els_xri_cnt), - GFP_KERNEL); - - if (!phba->sli4_hba.lpfc_els_sgl_array) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2401 Failed to allocate memory for ELS " - "XRI management array of size %d.\n", - els_xri_cnt); - return -ENOMEM; - } + /* els xri-sgl book keeping */ + phba->sli4_hba.els_xri_cnt = 0; - /* Keep the SCSI XRI into the XRI management array */ - phba->sli4_hba.scsi_xri_max = - phba->sli4_hba.max_cfg_param.max_xri - els_xri_cnt; + /* scsi xri-buffer book keeping */ phba->sli4_hba.scsi_xri_cnt = 0; - phba->sli4_hba.lpfc_scsi_psb_array = - kzalloc((sizeof(struct lpfc_scsi_buf *) * - phba->sli4_hba.scsi_xri_max), GFP_KERNEL); - - if (!phba->sli4_hba.lpfc_scsi_psb_array) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2563 Failed to allocate memory for SCSI " - "XRI management array of size %d.\n", - phba->sli4_hba.scsi_xri_max); - kfree(phba->sli4_hba.lpfc_els_sgl_array); - return -ENOMEM; - } - - for (i = 0; i < els_xri_cnt; i++) { - sglq_entry = kzalloc(sizeof(struct lpfc_sglq), GFP_KERNEL); - if (sglq_entry == NULL) { - printk(KERN_ERR "%s: only allocated %d sgls of " - "expected %d count. Unloading driver.\n", - __func__, i, els_xri_cnt); - goto out_free_mem; - } - - sglq_entry->buff_type = GEN_BUFF_TYPE; - sglq_entry->virt = lpfc_mbuf_alloc(phba, 0, &sglq_entry->phys); - if (sglq_entry->virt == NULL) { - kfree(sglq_entry); - printk(KERN_ERR "%s: failed to allocate mbuf.\n" - "Unloading driver.\n", __func__); - goto out_free_mem; - } - sglq_entry->sgl = sglq_entry->virt; - memset(sglq_entry->sgl, 0, LPFC_BPL_SIZE); - - /* The list order is used by later block SGL registraton */ - spin_lock_irq(&phba->hbalock); - sglq_entry->state = SGL_FREED; - list_add_tail(&sglq_entry->list, &phba->sli4_hba.lpfc_sgl_list); - phba->sli4_hba.lpfc_els_sgl_array[i] = sglq_entry; - phba->sli4_hba.total_sglq_bufs++; - spin_unlock_irq(&phba->hbalock); - } - return 0; - -out_free_mem: - kfree(phba->sli4_hba.lpfc_scsi_psb_array); - lpfc_free_sgl_list(phba); - return -ENOMEM; } /** @@ -7320,9 +7383,11 @@ lpfc_pci_function_reset(struct lpfc_hba *phba) phba->sli4_hba.u.if_type2.ERR2regaddr); lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "2890 Port error detected during port " - "reset(%d): port status reg 0x%x, " + "reset(%d): wait_tmo:%d ms, " + "port status reg 0x%x, " "error 1=0x%x, error 2=0x%x\n", - num_resets, reg_data.word0, + num_resets, rdy_chk*10, + reg_data.word0, phba->work_status[0], phba->work_status[1]); rc = -ENODEV; @@ -8694,8 +8759,11 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev) /* Release all the vports against this physical port */ vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for (i = 1; i <= phba->max_vports && vports[i] != NULL; i++) + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { + if (vports[i]->port_type == LPFC_PHYSICAL_PORT) + continue; fc_vport_terminate(vports[i]->fc_vport); + } lpfc_destroy_vport_work_array(phba, vports); /* Remove FC host and then SCSI host with the physical port */ @@ -9115,8 +9183,12 @@ lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *phba) return 50; else if (max_xri <= 1024) return 100; - else + else if (max_xri <= 1536) return 150; + else if (max_xri <= 2048) + return 200; + else + return 250; } else return 0; } @@ -9455,8 +9527,11 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev) /* Release all the vports against this physical port */ vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for (i = 1; i <= phba->max_vports && vports[i] != NULL; i++) + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { + if (vports[i]->port_type == LPFC_PHYSICAL_PORT) + continue; fc_vport_terminate(vports[i]->fc_vport); + } lpfc_destroy_vport_work_array(phba, vports); /* Remove FC host and then SCSI host with the physical port */ diff --git a/trunk/drivers/scsi/lpfc/lpfc_nportdisc.c b/trunk/drivers/scsi/lpfc/lpfc_nportdisc.c index 15ca2a9a0cdd..9133a97f045f 100644 --- a/trunk/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/trunk/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -367,8 +367,10 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, return 1; } + /* Check for Nport to NPort pt2pt protocol */ if ((vport->fc_flag & FC_PT2PT) && !(vport->fc_flag & FC_PT2PT_PLOGI)) { + /* rcv'ed PLOGI decides what our NPortId will be */ vport->fc_myDID = icmd->un.rcvels.parmRo; mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); @@ -382,6 +384,13 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, mempool_free(mbox, phba->mbox_mem_pool); goto out; } + /* + * For SLI4, the VFI/VPI are registered AFTER the + * Nport with the higher WWPN sends us a PLOGI with + * our assigned NPortId. + */ + if (phba->sli_rev == LPFC_SLI_REV4) + lpfc_issue_reg_vfi(vport); lpfc_can_disctmo(vport); } diff --git a/trunk/drivers/scsi/lpfc/lpfc_scsi.c b/trunk/drivers/scsi/lpfc/lpfc_scsi.c index 88f3a83dbd2e..66e09069f281 100644 --- a/trunk/drivers/scsi/lpfc/lpfc_scsi.c +++ b/trunk/drivers/scsi/lpfc/lpfc_scsi.c @@ -399,6 +399,14 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba) num_rsrc_err = atomic_read(&phba->num_rsrc_err); num_cmd_success = atomic_read(&phba->num_cmd_success); + /* + * The error and success command counters are global per + * driver instance. If another handler has already + * operated on this error event, just exit. + */ + if (num_rsrc_err == 0) + return; + vports = lpfc_create_vport_work_array(phba); if (vports != NULL) for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { @@ -688,7 +696,8 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba, rrq_empty = list_empty(&phba->active_rrq_list); spin_unlock_irqrestore(&phba->hbalock, iflag); if (ndlp) { - lpfc_set_rrq_active(phba, ndlp, xri, rxid, 1); + lpfc_set_rrq_active(phba, ndlp, + psb->cur_iocbq.sli4_lxritag, rxid, 1); lpfc_sli4_abts_err_handler(phba, ndlp, axri); } lpfc_release_scsi_buf_s4(phba, psb); @@ -718,72 +727,162 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba, } /** - * lpfc_sli4_repost_scsi_sgl_list - Repsot the Scsi buffers sgl pages as block + * lpfc_sli4_post_scsi_sgl_list - Psot blocks of scsi buffer sgls from a list * @phba: pointer to lpfc hba data structure. + * @post_sblist: pointer to the scsi buffer list. * - * This routine walks the list of scsi buffers that have been allocated and - * repost them to the HBA by using SGL block post. This is needed after a - * pci_function_reset/warm_start or start. The lpfc_hba_down_post_s4 routine - * is responsible for moving all scsi buffers on the lpfc_abts_scsi_sgl_list - * to the lpfc_scsi_buf_list. If the repost fails, reject all scsi buffers. + * This routine walks a list of scsi buffers that was passed in. It attempts + * to construct blocks of scsi buffer sgls which contains contiguous xris and + * uses the non-embedded SGL block post mailbox commands to post to the port. + * For single SCSI buffer sgl with non-contiguous xri, if any, it shall use + * embedded SGL post mailbox command for posting. The @post_sblist passed in + * must be local list, thus no lock is needed when manipulate the list. * - * Returns: 0 = success, non-zero failure. + * Returns: 0 = failure, non-zero number of successfully posted buffers. **/ int -lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba) +lpfc_sli4_post_scsi_sgl_list(struct lpfc_hba *phba, + struct list_head *post_sblist, int sb_count) { - struct lpfc_scsi_buf *psb; - int index, status, bcnt = 0, rcnt = 0, rc = 0; - LIST_HEAD(sblist); - - for (index = 0; index < phba->sli4_hba.scsi_xri_cnt; index++) { - psb = phba->sli4_hba.lpfc_scsi_psb_array[index]; - if (psb) { - /* Remove from SCSI buffer list */ - list_del(&psb->list); - /* Add it to a local SCSI buffer list */ - list_add_tail(&psb->list, &sblist); - if (++rcnt == LPFC_NEMBED_MBOX_SGL_CNT) { - bcnt = rcnt; - rcnt = 0; + struct lpfc_scsi_buf *psb, *psb_next; + int status; + int post_cnt = 0, block_cnt = 0, num_posting = 0, num_posted = 0; + dma_addr_t pdma_phys_bpl1; + int last_xritag = NO_XRI; + LIST_HEAD(prep_sblist); + LIST_HEAD(blck_sblist); + LIST_HEAD(scsi_sblist); + + /* sanity check */ + if (sb_count <= 0) + return -EINVAL; + + list_for_each_entry_safe(psb, psb_next, post_sblist, list) { + list_del_init(&psb->list); + block_cnt++; + if ((last_xritag != NO_XRI) && + (psb->cur_iocbq.sli4_xritag != last_xritag + 1)) { + /* a hole in xri block, form a sgl posting block */ + list_splice_init(&prep_sblist, &blck_sblist); + post_cnt = block_cnt - 1; + /* prepare list for next posting block */ + list_add_tail(&psb->list, &prep_sblist); + block_cnt = 1; + } else { + /* prepare list for next posting block */ + list_add_tail(&psb->list, &prep_sblist); + /* enough sgls for non-embed sgl mbox command */ + if (block_cnt == LPFC_NEMBED_MBOX_SGL_CNT) { + list_splice_init(&prep_sblist, &blck_sblist); + post_cnt = block_cnt; + block_cnt = 0; } - } else - /* A hole present in the XRI array, need to skip */ - bcnt = rcnt; + } + num_posting++; + last_xritag = psb->cur_iocbq.sli4_xritag; - if (index == phba->sli4_hba.scsi_xri_cnt - 1) - /* End of XRI array for SCSI buffer, complete */ - bcnt = rcnt; + /* end of repost sgl list condition for SCSI buffers */ + if (num_posting == sb_count) { + if (post_cnt == 0) { + /* last sgl posting block */ + list_splice_init(&prep_sblist, &blck_sblist); + post_cnt = block_cnt; + } else if (block_cnt == 1) { + /* last single sgl with non-contiguous xri */ + if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE) + pdma_phys_bpl1 = psb->dma_phys_bpl + + SGL_PAGE_SIZE; + else + pdma_phys_bpl1 = 0; + status = lpfc_sli4_post_sgl(phba, + psb->dma_phys_bpl, + pdma_phys_bpl1, + psb->cur_iocbq.sli4_xritag); + if (status) { + /* failure, put on abort scsi list */ + psb->exch_busy = 1; + } else { + /* success, put on SCSI buffer list */ + psb->exch_busy = 0; + psb->status = IOSTAT_SUCCESS; + num_posted++; + } + /* success, put on SCSI buffer sgl list */ + list_add_tail(&psb->list, &scsi_sblist); + } + } - /* Continue until collect up to a nembed page worth of sgls */ - if (bcnt == 0) + /* continue until a nembed page worth of sgls */ + if (post_cnt == 0) continue; - /* Now, post the SCSI buffer list sgls as a block */ - if (!phba->sli4_hba.extents_in_use) - status = lpfc_sli4_post_scsi_sgl_block(phba, - &sblist, - bcnt); - else - status = lpfc_sli4_post_scsi_sgl_blk_ext(phba, - &sblist, - bcnt); - /* Reset SCSI buffer count for next round of posting */ - bcnt = 0; - while (!list_empty(&sblist)) { - list_remove_head(&sblist, psb, struct lpfc_scsi_buf, - list); + + /* post block of SCSI buffer list sgls */ + status = lpfc_sli4_post_scsi_sgl_block(phba, &blck_sblist, + post_cnt); + + /* don't reset xirtag due to hole in xri block */ + if (block_cnt == 0) + last_xritag = NO_XRI; + + /* reset SCSI buffer post count for next round of posting */ + post_cnt = 0; + + /* put posted SCSI buffer-sgl posted on SCSI buffer sgl list */ + while (!list_empty(&blck_sblist)) { + list_remove_head(&blck_sblist, psb, + struct lpfc_scsi_buf, list); if (status) { - /* Put this back on the abort scsi list */ + /* failure, put on abort scsi list */ psb->exch_busy = 1; - rc++; } else { + /* success, put on SCSI buffer list */ psb->exch_busy = 0; psb->status = IOSTAT_SUCCESS; + num_posted++; } - /* Put it back into the SCSI buffer list */ - lpfc_release_scsi_buf_s4(phba, psb); + list_add_tail(&psb->list, &scsi_sblist); } } + /* Push SCSI buffers with sgl posted to the availble list */ + while (!list_empty(&scsi_sblist)) { + list_remove_head(&scsi_sblist, psb, + struct lpfc_scsi_buf, list); + lpfc_release_scsi_buf_s4(phba, psb); + } + return num_posted; +} + +/** + * lpfc_sli4_repost_scsi_sgl_list - Repsot all the allocated scsi buffer sgls + * @phba: pointer to lpfc hba data structure. + * + * This routine walks the list of scsi buffers that have been allocated and + * repost them to the port by using SGL block post. This is needed after a + * pci_function_reset/warm_start or start. The lpfc_hba_down_post_s4 routine + * is responsible for moving all scsi buffers on the lpfc_abts_scsi_sgl_list + * to the lpfc_scsi_buf_list. If the repost fails, reject all scsi buffers. + * + * Returns: 0 = success, non-zero failure. + **/ +int +lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba) +{ + LIST_HEAD(post_sblist); + int num_posted, rc = 0; + + /* get all SCSI buffers need to repost to a local list */ + spin_lock(&phba->scsi_buf_list_lock); + list_splice_init(&phba->lpfc_scsi_buf_list, &post_sblist); + spin_unlock(&phba->scsi_buf_list_lock); + + /* post the list of scsi buffer sgls to port if available */ + if (!list_empty(&post_sblist)) { + num_posted = lpfc_sli4_post_scsi_sgl_list(phba, &post_sblist, + phba->sli4_hba.scsi_xri_cnt); + /* failed to post any scsi buffer, return error */ + if (num_posted == 0) + rc = -EIO; + } return rc; } @@ -792,12 +891,13 @@ lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba) * @vport: The virtual port for which this call being executed. * @num_to_allocate: The requested number of buffers to allocate. * - * This routine allocates a scsi buffer for device with SLI-4 interface spec, + * This routine allocates scsi buffers for device with SLI-4 interface spec, * the scsi buffer contains all the necessary information needed to initiate - * a SCSI I/O. + * a SCSI I/O. After allocating up to @num_to_allocate SCSI buffers and put + * them on a list, it post them to the port by using SGL block post. * * Return codes: - * int - number of scsi buffers that were allocated. + * int - number of scsi buffers that were allocated and posted. * 0 = failure, less than num_to_alloc is a partial failure. **/ static int @@ -810,22 +910,21 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) dma_addr_t pdma_phys_fcp_cmd; dma_addr_t pdma_phys_fcp_rsp; dma_addr_t pdma_phys_bpl, pdma_phys_bpl1; - uint16_t iotag, last_xritag = NO_XRI, lxri = 0; - int status = 0, index; - int bcnt; - int non_sequential_xri = 0; - LIST_HEAD(sblist); + uint16_t iotag, lxri = 0; + int bcnt, num_posted; + LIST_HEAD(prep_sblist); + LIST_HEAD(post_sblist); + LIST_HEAD(scsi_sblist); for (bcnt = 0; bcnt < num_to_alloc; bcnt++) { psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL); if (!psb) break; - /* - * Get memory from the pci pool to map the virt space to pci bus - * space for an I/O. The DMA buffer includes space for the - * struct fcp_cmnd, struct fcp_rsp and the number of bde's - * necessary to support the sg_tablesize. + * Get memory from the pci pool to map the virt space to + * pci bus space for an I/O. The DMA buffer includes space + * for the struct fcp_cmnd, struct fcp_rsp and the number + * of bde's necessary to support the sg_tablesize. */ psb->data = pci_pool_alloc(phba->lpfc_scsi_dma_buf_pool, GFP_KERNEL, &psb->dma_handle); @@ -833,8 +932,6 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) kfree(psb); break; } - - /* Initialize virtual ptrs to dma_buf region. */ memset(psb->data, 0, phba->cfg_sg_dma_buf_size); /* Allocate iotag for psb->cur_iocbq. */ @@ -855,16 +952,7 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) } psb->cur_iocbq.sli4_lxritag = lxri; psb->cur_iocbq.sli4_xritag = phba->sli4_hba.xri_ids[lxri]; - if (last_xritag != NO_XRI - && psb->cur_iocbq.sli4_xritag != (last_xritag+1)) { - non_sequential_xri = 1; - } else - list_add_tail(&psb->list, &sblist); - last_xritag = psb->cur_iocbq.sli4_xritag; - - index = phba->sli4_hba.scsi_xri_cnt++; psb->cur_iocbq.iocb_flag |= LPFC_IO_FCP; - psb->fcp_bpl = psb->data; psb->fcp_cmnd = (psb->data + phba->cfg_sg_dma_buf_size) - (sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp)); @@ -880,9 +968,9 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) pdma_phys_fcp_rsp = pdma_phys_fcp_cmd + sizeof(struct fcp_cmnd); /* - * The first two bdes are the FCP_CMD and FCP_RSP. The balance - * are sg list bdes. Initialize the first two and leave the - * rest for queuecommand. + * The first two bdes are the FCP_CMD and FCP_RSP. + * The balance are sg list bdes. Initialize the + * first two and leave the rest for queuecommand. */ sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_fcp_cmd)); sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_fcp_cmd)); @@ -917,62 +1005,31 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) iocb->ulpBdeCount = 1; iocb->ulpLe = 1; iocb->ulpClass = CLASS3; - psb->cur_iocbq.context1 = psb; + psb->cur_iocbq.context1 = psb; if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE) pdma_phys_bpl1 = pdma_phys_bpl + SGL_PAGE_SIZE; else pdma_phys_bpl1 = 0; psb->dma_phys_bpl = pdma_phys_bpl; - phba->sli4_hba.lpfc_scsi_psb_array[index] = psb; - if (non_sequential_xri) { - status = lpfc_sli4_post_sgl(phba, pdma_phys_bpl, - pdma_phys_bpl1, - psb->cur_iocbq.sli4_xritag); - if (status) { - /* Put this back on the abort scsi list */ - psb->exch_busy = 1; - } else { - psb->exch_busy = 0; - psb->status = IOSTAT_SUCCESS; - } - /* Put it back into the SCSI buffer list */ - lpfc_release_scsi_buf_s4(phba, psb); - break; - } - } - if (bcnt) { - if (!phba->sli4_hba.extents_in_use) - status = lpfc_sli4_post_scsi_sgl_block(phba, - &sblist, - bcnt); - else - status = lpfc_sli4_post_scsi_sgl_blk_ext(phba, - &sblist, - bcnt); - - if (status) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "3021 SCSI SGL post error %d\n", - status); - bcnt = 0; - } - /* Reset SCSI buffer count for next round of posting */ - while (!list_empty(&sblist)) { - list_remove_head(&sblist, psb, struct lpfc_scsi_buf, - list); - if (status) { - /* Put this back on the abort scsi list */ - psb->exch_busy = 1; - } else { - psb->exch_busy = 0; - psb->status = IOSTAT_SUCCESS; - } - /* Put it back into the SCSI buffer list */ - lpfc_release_scsi_buf_s4(phba, psb); - } + + /* add the scsi buffer to a post list */ + list_add_tail(&psb->list, &post_sblist); + spin_lock_irq(&phba->scsi_buf_list_lock); + phba->sli4_hba.scsi_xri_cnt++; + spin_unlock_irq(&phba->scsi_buf_list_lock); } + lpfc_printf_log(phba, KERN_INFO, LOG_BG, + "3021 Allocate %d out of %d requested new SCSI " + "buffers\n", bcnt, num_to_alloc); + + /* post the list of scsi buffer sgls to port if available */ + if (!list_empty(&post_sblist)) + num_posted = lpfc_sli4_post_scsi_sgl_list(phba, + &post_sblist, bcnt); + else + num_posted = 0; - return bcnt + non_sequential_xri; + return num_posted; } /** @@ -1043,7 +1100,7 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) list_for_each_entry(lpfc_cmd, &phba->lpfc_scsi_buf_list, list) { if (lpfc_test_rrq_active(phba, ndlp, - lpfc_cmd->cur_iocbq.sli4_xritag)) + lpfc_cmd->cur_iocbq.sli4_lxritag)) continue; list_del(&lpfc_cmd->list); found = 1; @@ -1897,7 +1954,9 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc, dma_addr_t physaddr; int i = 0, num_bde = 0, status; int datadir = sc->sc_data_direction; +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS uint32_t rc; +#endif uint32_t checking = 1; uint32_t reftag; unsigned blksize; @@ -2034,7 +2093,9 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, int datadir = sc->sc_data_direction; unsigned char pgdone = 0, alldone = 0; unsigned blksize; +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS uint32_t rc; +#endif uint32_t checking = 1; uint32_t reftag; uint8_t txop, rxop; @@ -2253,7 +2314,9 @@ lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc, uint32_t reftag; unsigned blksize; uint8_t txop, rxop; +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS uint32_t rc; +#endif uint32_t checking = 1; uint32_t dma_len; uint32_t dma_offset = 0; @@ -2383,7 +2446,9 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, uint32_t reftag; uint8_t txop, rxop; uint32_t dma_len; +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS uint32_t rc; +#endif uint32_t checking = 1; uint32_t dma_offset = 0; int num_sge = 0; @@ -3604,11 +3669,16 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, logit = LOG_FCP | LOG_FCP_UNDER; lpfc_printf_vlog(vport, KERN_WARNING, logit, "9030 FCP cmd x%x failed <%d/%d> " - "status: x%x result: x%x Data: x%x x%x\n", + "status: x%x result: x%x " + "sid: x%x did: x%x oxid: x%x " + "Data: x%x x%x\n", cmd->cmnd[0], cmd->device ? cmd->device->id : 0xffff, cmd->device ? cmd->device->lun : 0xffff, lpfc_cmd->status, lpfc_cmd->result, + vport->fc_myDID, pnode->nlp_DID, + phba->sli_rev == LPFC_SLI_REV4 ? + lpfc_cmd->cur_iocbq.sli4_xritag : 0xffff, pIocbOut->iocb.ulpContext, lpfc_cmd->cur_iocbq.iocb.ulpIoTag); @@ -3689,8 +3759,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, * ABTS we cannot generate and RRQ. */ lpfc_set_rrq_active(phba, pnode, - lpfc_cmd->cur_iocbq.sli4_xritag, - 0, 0); + lpfc_cmd->cur_iocbq.sli4_lxritag, + 0, 0); } /* else: fall through */ default: @@ -4348,8 +4418,20 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) ret = fc_block_scsi_eh(cmnd); if (ret) return ret; + + spin_lock_irq(&phba->hbalock); + /* driver queued commands are in process of being flushed */ + if (phba->hba_flag & HBA_FCP_IOQ_FLUSH) { + spin_unlock_irq(&phba->hbalock); + lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, + "3168 SCSI Layer abort requested I/O has been " + "flushed by LLD.\n"); + return FAILED; + } + lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble; if (!lpfc_cmd) { + spin_unlock_irq(&phba->hbalock); lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, "2873 SCSI Layer I/O Abort Request IO CMPL Status " "x%x ID %d LUN %d\n", @@ -4357,23 +4439,34 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) return SUCCESS; } + iocb = &lpfc_cmd->cur_iocbq; + /* the command is in process of being cancelled */ + if (!(iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ)) { + spin_unlock_irq(&phba->hbalock); + lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, + "3169 SCSI Layer abort requested I/O has been " + "cancelled by LLD.\n"); + return FAILED; + } /* * If pCmd field of the corresponding lpfc_scsi_buf structure * points to a different SCSI command, then the driver has * already completed this command, but the midlayer did not - * see the completion before the eh fired. Just return - * SUCCESS. + * see the completion before the eh fired. Just return SUCCESS. */ - iocb = &lpfc_cmd->cur_iocbq; - if (lpfc_cmd->pCmd != cmnd) - goto out; + if (lpfc_cmd->pCmd != cmnd) { + lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, + "3170 SCSI Layer abort requested I/O has been " + "completed by LLD.\n"); + goto out_unlock; + } BUG_ON(iocb->context1 != lpfc_cmd); - abtsiocb = lpfc_sli_get_iocbq(phba); + abtsiocb = __lpfc_sli_get_iocbq(phba); if (abtsiocb == NULL) { ret = FAILED; - goto out; + goto out_unlock; } /* @@ -4405,6 +4498,9 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl; abtsiocb->vport = vport; + /* no longer need the lock after this point */ + spin_unlock_irq(&phba->hbalock); + if (lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, abtsiocb, 0) == IOCB_ERROR) { lpfc_sli_release_iocbq(phba, abtsiocb); @@ -4421,10 +4517,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) wait_event_timeout(waitq, (lpfc_cmd->pCmd != cmnd), (2*vport->cfg_devloss_tmo*HZ)); - - spin_lock_irq(shost->host_lock); lpfc_cmd->waitq = NULL; - spin_unlock_irq(shost->host_lock); if (lpfc_cmd->pCmd == cmnd) { ret = FAILED; @@ -4434,8 +4527,11 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) "LUN %d\n", ret, cmnd->device->id, cmnd->device->lun); } + goto out; - out: +out_unlock: + spin_unlock_irq(&phba->hbalock); +out: lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, "0749 SCSI Layer I/O Abort Request Status x%x ID %d " "LUN %d\n", ret, cmnd->device->id, @@ -4862,6 +4958,43 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) return ret; } +/** + * lpfc_host_reset_handler - scsi_host_template eh_host_reset_handler entry pt + * @cmnd: Pointer to scsi_cmnd data structure. + * + * This routine does host reset to the adaptor port. It brings the HBA + * offline, performs a board restart, and then brings the board back online. + * The lpfc_offline calls lpfc_sli_hba_down which will abort and local + * reject all outstanding SCSI commands to the host and error returned + * back to SCSI mid-level. As this will be SCSI mid-level's last resort + * of error handling, it will only return error if resetting of the adapter + * is not successful; in all other cases, will return success. + * + * Return code : + * 0x2003 - Error + * 0x2002 - Success + **/ +static int +lpfc_host_reset_handler(struct scsi_cmnd *cmnd) +{ + struct Scsi_Host *shost = cmnd->device->host; + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_hba *phba = vport->phba; + int rc, ret = SUCCESS; + + lpfc_offline_prep(phba); + lpfc_offline(phba); + rc = lpfc_sli_brdrestart(phba); + if (rc) + ret = FAILED; + lpfc_online(phba); + lpfc_unblock_mgmt_io(phba); + + lpfc_printf_log(phba, KERN_ERR, LOG_FCP, + "3172 SCSI layer issued Host Reset Data: x%x\n", ret); + return ret; +} + /** * lpfc_slave_alloc - scsi_host_template slave_alloc entry point * @sdev: Pointer to scsi_device. @@ -4994,6 +5127,7 @@ struct scsi_host_template lpfc_template = { .eh_device_reset_handler = lpfc_device_reset_handler, .eh_target_reset_handler = lpfc_target_reset_handler, .eh_bus_reset_handler = lpfc_bus_reset_handler, + .eh_host_reset_handler = lpfc_host_reset_handler, .slave_alloc = lpfc_slave_alloc, .slave_configure = lpfc_slave_configure, .slave_destroy = lpfc_slave_destroy, diff --git a/trunk/drivers/scsi/lpfc/lpfc_sli.c b/trunk/drivers/scsi/lpfc/lpfc_sli.c index dbaf5b963bff..b4720a109817 100644 --- a/trunk/drivers/scsi/lpfc/lpfc_sli.c +++ b/trunk/drivers/scsi/lpfc/lpfc_sli.c @@ -67,6 +67,8 @@ static void lpfc_sli4_send_seq_to_ulp(struct lpfc_vport *, struct hbq_dmabuf *); static int lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *, struct lpfc_queue *, struct lpfc_cqe *); +static int lpfc_sli4_post_els_sgl_list(struct lpfc_hba *, struct list_head *, + int); static IOCB_t * lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq) @@ -500,7 +502,7 @@ lpfc_resp_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) * allocation is successful, it returns pointer to the newly * allocated iocb object else it returns NULL. **/ -static struct lpfc_iocbq * +struct lpfc_iocbq * __lpfc_sli_get_iocbq(struct lpfc_hba *phba) { struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list; @@ -875,6 +877,9 @@ __lpfc_sli_get_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq) } else if ((piocbq->iocb.ulpCommand == CMD_GEN_REQUEST64_CR) && !(piocbq->iocb_flag & LPFC_IO_LIBDFC)) ndlp = piocbq->context_un.ndlp; + else if ((piocbq->iocb.ulpCommand == CMD_ELS_REQUEST64_CR) && + (piocbq->iocb_flag & LPFC_IO_LIBDFC)) + ndlp = piocbq->context_un.ndlp; else ndlp = piocbq->context1; @@ -883,7 +888,7 @@ __lpfc_sli_get_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq) while (!found) { if (!sglq) return NULL; - if (lpfc_test_rrq_active(phba, ndlp, sglq->sli4_xritag)) { + if (lpfc_test_rrq_active(phba, ndlp, sglq->sli4_lxritag)) { /* This xri has an rrq outstanding for this DID. * put it back in the list and get another xri. */ @@ -1257,7 +1262,7 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *piocb) { list_add_tail(&piocb->list, &pring->txcmplq); - piocb->iocb_flag |= LPFC_IO_ON_Q; + piocb->iocb_flag |= LPFC_IO_ON_TXCMPLQ; pring->txcmplq_cnt++; if (pring->txcmplq_cnt > pring->txcmplq_max) pring->txcmplq_max = pring->txcmplq_cnt; @@ -2556,9 +2561,9 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba, if (iotag != 0 && iotag <= phba->sli.last_iotag) { cmd_iocb = phba->sli.iocbq_lookup[iotag]; list_del_init(&cmd_iocb->list); - if (cmd_iocb->iocb_flag & LPFC_IO_ON_Q) { + if (cmd_iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ) { pring->txcmplq_cnt--; - cmd_iocb->iocb_flag &= ~LPFC_IO_ON_Q; + cmd_iocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ; } return cmd_iocb; } @@ -2591,14 +2596,14 @@ lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba, if (iotag != 0 && iotag <= phba->sli.last_iotag) { cmd_iocb = phba->sli.iocbq_lookup[iotag]; - list_del_init(&cmd_iocb->list); - if (cmd_iocb->iocb_flag & LPFC_IO_ON_Q) { - cmd_iocb->iocb_flag &= ~LPFC_IO_ON_Q; + if (cmd_iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ) { + /* remove from txcmpl queue list */ + list_del_init(&cmd_iocb->list); + cmd_iocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ; pring->txcmplq_cnt--; + return cmd_iocb; } - return cmd_iocb; } - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0372 iotag x%x is out off range: max iotag (x%x)\n", iotag, phba->sli.last_iotag); @@ -3466,6 +3471,9 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba) /* Retrieve everything on the txcmplq */ list_splice_init(&pring->txcmplq, &txcmplq); pring->txcmplq_cnt = 0; + + /* Indicate the I/O queues are flushed */ + phba->hba_flag |= HBA_FCP_IOQ_FLUSH; spin_unlock_irq(&phba->hbalock); /* Flush the txq */ @@ -3877,6 +3885,7 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) { struct lpfc_sli *psli = &phba->sli; uint16_t cfg_value; + int rc; /* Reset HBA */ lpfc_printf_log(phba, KERN_INFO, LOG_SLI, @@ -3905,12 +3914,12 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) /* Perform FCoE PCI function reset */ lpfc_sli4_queue_destroy(phba); - lpfc_pci_function_reset(phba); + rc = lpfc_pci_function_reset(phba); /* Restore PCI cmd register */ pci_write_config_word(phba->pcidev, PCI_COMMAND, cfg_value); - return 0; + return rc; } /** @@ -4002,6 +4011,7 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba) { struct lpfc_sli *psli = &phba->sli; uint32_t hba_aer_enabled; + int rc; /* Restart HBA */ lpfc_printf_log(phba, KERN_INFO, LOG_SLI, @@ -4011,7 +4021,7 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba) /* Take PCIe device Advanced Error Reporting (AER) state */ hba_aer_enabled = phba->hba_flag & HBA_AER_ENABLED; - lpfc_sli4_brdreset(phba); + rc = lpfc_sli4_brdreset(phba); spin_lock_irq(&phba->hbalock); phba->pport->stopped = 0; @@ -4028,7 +4038,7 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba) lpfc_hba_down_post(phba); - return 0; + return rc; } /** @@ -4967,7 +4977,12 @@ lpfc_sli4_get_avail_extnt_rsrc(struct lpfc_hba *phba, uint16_t type, &rsrc_info->u.rsp); *extnt_size = bf_get(lpfc_mbx_get_rsrc_extent_info_size, &rsrc_info->u.rsp); - err_exit: + + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3162 Retrieved extents type-%d from port: count:%d, " + "size:%d\n", type, *extnt_count, *extnt_size); + +err_exit: mempool_free(mbox, phba->mbox_mem_pool); return rc; } @@ -5051,7 +5066,7 @@ lpfc_sli4_chk_avail_extnt_rsrc(struct lpfc_hba *phba, uint16_t type) * 0: if successful **/ static int -lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t *extnt_cnt, +lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t extnt_cnt, uint16_t type, bool *emb, LPFC_MBOXQ_t *mbox) { int rc = 0; @@ -5060,7 +5075,7 @@ lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t *extnt_cnt, uint32_t alloc_len, mbox_tmo; /* Calculate the total requested length of the dma memory */ - req_len = *extnt_cnt * sizeof(uint16_t); + req_len = extnt_cnt * sizeof(uint16_t); /* * Calculate the size of an embedded mailbox. The uint32_t @@ -5075,7 +5090,7 @@ lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t *extnt_cnt, */ *emb = LPFC_SLI4_MBX_EMBED; if (req_len > emb_len) { - req_len = *extnt_cnt * sizeof(uint16_t) + + req_len = extnt_cnt * sizeof(uint16_t) + sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); *emb = LPFC_SLI4_MBX_NEMBED; @@ -5091,7 +5106,7 @@ lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t *extnt_cnt, "size (x%x)\n", alloc_len, req_len); return -ENOMEM; } - rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, *extnt_cnt, type, *emb); + rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, extnt_cnt, type, *emb); if (unlikely(rc)) return -EIO; @@ -5149,17 +5164,15 @@ lpfc_sli4_alloc_extent(struct lpfc_hba *phba, uint16_t type) return -ENOMEM; } - lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_INIT, - "2903 Available Resource Extents " - "for resource type 0x%x: Count: 0x%x, " - "Size 0x%x\n", type, rsrc_cnt, - rsrc_size); + lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_INIT | LOG_SLI, + "2903 Post resource extents type-0x%x: " + "count:%d, size %d\n", type, rsrc_cnt, rsrc_size); mbox = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) return -ENOMEM; - rc = lpfc_sli4_cfg_post_extnts(phba, &rsrc_cnt, type, &emb, mbox); + rc = lpfc_sli4_cfg_post_extnts(phba, rsrc_cnt, type, &emb, mbox); if (unlikely(rc)) { rc = -EIO; goto err_exit; @@ -5250,6 +5263,7 @@ lpfc_sli4_alloc_extent(struct lpfc_hba *phba, uint16_t type) rc = -ENOMEM; goto err_exit; } + phba->sli4_hba.max_cfg_param.xri_used = 0; phba->sli4_hba.xri_ids = kzalloc(rsrc_id_cnt * sizeof(uint16_t), GFP_KERNEL); @@ -5420,7 +5434,6 @@ lpfc_sli4_dealloc_extent(struct lpfc_hba *phba, uint16_t type) case LPFC_RSC_TYPE_FCOE_XRI: kfree(phba->sli4_hba.xri_bmask); kfree(phba->sli4_hba.xri_ids); - bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0); list_for_each_entry_safe(rsrc_blk, rsrc_blk_next, &phba->sli4_hba.lpfc_xri_blk_list, list) { list_del_init(&rsrc_blk->list); @@ -5612,7 +5625,6 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) goto free_vpi_ids; } phba->sli4_hba.max_cfg_param.xri_used = 0; - phba->sli4_hba.xri_count = 0; phba->sli4_hba.xri_ids = kzalloc(count * sizeof(uint16_t), GFP_KERNEL); @@ -5694,7 +5706,6 @@ lpfc_sli4_dealloc_resource_identifiers(struct lpfc_hba *phba) bf_set(lpfc_vpi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0); kfree(phba->sli4_hba.xri_bmask); kfree(phba->sli4_hba.xri_ids); - bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0); kfree(phba->sli4_hba.vfi_bmask); kfree(phba->sli4_hba.vfi_ids); bf_set(lpfc_vfi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0); @@ -5852,6 +5863,149 @@ lpfc_sli4_get_allocated_extnts(struct lpfc_hba *phba, uint16_t type, return rc; } +/** + * lpfc_sli4_repost_els_sgl_list - Repsot the els buffers sgl pages as block + * @phba: pointer to lpfc hba data structure. + * + * This routine walks the list of els buffers that have been allocated and + * repost them to the port by using SGL block post. This is needed after a + * pci_function_reset/warm_start or start. It attempts to construct blocks + * of els buffer sgls which contains contiguous xris and uses the non-embedded + * SGL block post mailbox commands to post them to the port. For single els + * buffer sgl with non-contiguous xri, if any, it shall use embedded SGL post + * mailbox command for posting. + * + * Returns: 0 = success, non-zero failure. + **/ +static int +lpfc_sli4_repost_els_sgl_list(struct lpfc_hba *phba) +{ + struct lpfc_sglq *sglq_entry = NULL; + struct lpfc_sglq *sglq_entry_next = NULL; + struct lpfc_sglq *sglq_entry_first = NULL; + int status, post_cnt = 0, num_posted = 0, block_cnt = 0; + int last_xritag = NO_XRI; + LIST_HEAD(prep_sgl_list); + LIST_HEAD(blck_sgl_list); + LIST_HEAD(allc_sgl_list); + LIST_HEAD(post_sgl_list); + LIST_HEAD(free_sgl_list); + + spin_lock(&phba->hbalock); + list_splice_init(&phba->sli4_hba.lpfc_sgl_list, &allc_sgl_list); + spin_unlock(&phba->hbalock); + + list_for_each_entry_safe(sglq_entry, sglq_entry_next, + &allc_sgl_list, list) { + list_del_init(&sglq_entry->list); + block_cnt++; + if ((last_xritag != NO_XRI) && + (sglq_entry->sli4_xritag != last_xritag + 1)) { + /* a hole in xri block, form a sgl posting block */ + list_splice_init(&prep_sgl_list, &blck_sgl_list); + post_cnt = block_cnt - 1; + /* prepare list for next posting block */ + list_add_tail(&sglq_entry->list, &prep_sgl_list); + block_cnt = 1; + } else { + /* prepare list for next posting block */ + list_add_tail(&sglq_entry->list, &prep_sgl_list); + /* enough sgls for non-embed sgl mbox command */ + if (block_cnt == LPFC_NEMBED_MBOX_SGL_CNT) { + list_splice_init(&prep_sgl_list, + &blck_sgl_list); + post_cnt = block_cnt; + block_cnt = 0; + } + } + num_posted++; + + /* keep track of last sgl's xritag */ + last_xritag = sglq_entry->sli4_xritag; + + /* end of repost sgl list condition for els buffers */ + if (num_posted == phba->sli4_hba.els_xri_cnt) { + if (post_cnt == 0) { + list_splice_init(&prep_sgl_list, + &blck_sgl_list); + post_cnt = block_cnt; + } else if (block_cnt == 1) { + status = lpfc_sli4_post_sgl(phba, + sglq_entry->phys, 0, + sglq_entry->sli4_xritag); + if (!status) { + /* successful, put sgl to posted list */ + list_add_tail(&sglq_entry->list, + &post_sgl_list); + } else { + /* Failure, put sgl to free list */ + lpfc_printf_log(phba, KERN_WARNING, + LOG_SLI, + "3159 Failed to post els " + "sgl, xritag:x%x\n", + sglq_entry->sli4_xritag); + list_add_tail(&sglq_entry->list, + &free_sgl_list); + spin_lock_irq(&phba->hbalock); + phba->sli4_hba.els_xri_cnt--; + spin_unlock_irq(&phba->hbalock); + } + } + } + + /* continue until a nembed page worth of sgls */ + if (post_cnt == 0) + continue; + + /* post the els buffer list sgls as a block */ + status = lpfc_sli4_post_els_sgl_list(phba, &blck_sgl_list, + post_cnt); + + if (!status) { + /* success, put sgl list to posted sgl list */ + list_splice_init(&blck_sgl_list, &post_sgl_list); + } else { + /* Failure, put sgl list to free sgl list */ + sglq_entry_first = list_first_entry(&blck_sgl_list, + struct lpfc_sglq, + list); + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "3160 Failed to post els sgl-list, " + "xritag:x%x-x%x\n", + sglq_entry_first->sli4_xritag, + (sglq_entry_first->sli4_xritag + + post_cnt - 1)); + list_splice_init(&blck_sgl_list, &free_sgl_list); + spin_lock_irq(&phba->hbalock); + phba->sli4_hba.els_xri_cnt -= post_cnt; + spin_unlock_irq(&phba->hbalock); + } + + /* don't reset xirtag due to hole in xri block */ + if (block_cnt == 0) + last_xritag = NO_XRI; + + /* reset els sgl post count for next round of posting */ + post_cnt = 0; + } + + /* free the els sgls failed to post */ + lpfc_free_sgl_list(phba, &free_sgl_list); + + /* push els sgls posted to the availble list */ + if (!list_empty(&post_sgl_list)) { + spin_lock(&phba->hbalock); + list_splice_init(&post_sgl_list, + &phba->sli4_hba.lpfc_sgl_list); + spin_unlock(&phba->hbalock); + } else { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "3161 Failure to post els sgl to port.\n"); + return -EIO; + } + return 0; +} + /** * lpfc_sli4_hba_setup - SLI4 device intialization PCI function * @phba: Pointer to HBA context object. @@ -5923,6 +6077,8 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) else phba->hba_flag &= ~HBA_FIP_SUPPORT; + phba->hba_flag &= ~HBA_FCP_IOQ_FLUSH; + if (phba->sli_rev != LPFC_SLI_REV4) { lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, "0376 READ_REV Error. SLI Level %d " @@ -6063,8 +6219,6 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) "rc = x%x\n", rc); goto out_free_mbox; } - /* update physical xri mappings in the scsi buffers */ - lpfc_scsi_buf_update(phba); /* Read the port's service parameters. */ rc = lpfc_read_sparam(phba, mboxq, vport->vpi); @@ -6105,28 +6259,26 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) fc_host_node_name(shost) = wwn_to_u64(vport->fc_nodename.u.wwn); fc_host_port_name(shost) = wwn_to_u64(vport->fc_portname.u.wwn); - /* Register SGL pool to the device using non-embedded mailbox command */ - if (!phba->sli4_hba.extents_in_use) { - rc = lpfc_sli4_post_els_sgl_list(phba); - if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "0582 Error %d during els sgl post " - "operation\n", rc); - rc = -ENODEV; - goto out_free_mbox; - } - } else { - rc = lpfc_sli4_post_els_sgl_list_ext(phba); - if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "2560 Error %d during els sgl post " - "operation\n", rc); - rc = -ENODEV; - goto out_free_mbox; - } + /* update host els and scsi xri-sgl sizes and mappings */ + rc = lpfc_sli4_xri_sgl_update(phba); + if (unlikely(rc)) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "1400 Failed to update xri-sgl size and " + "mapping: %d\n", rc); + goto out_free_mbox; } - /* Register SCSI SGL pool to the device */ + /* register the els sgl pool to the port */ + rc = lpfc_sli4_repost_els_sgl_list(phba); + if (unlikely(rc)) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "0582 Error %d during els sgl post " + "operation\n", rc); + rc = -ENODEV; + goto out_free_mbox; + } + + /* register the allocated scsi sgl pool to the port */ rc = lpfc_sli4_repost_scsi_sgl_list(phba); if (unlikely(rc)) { lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, @@ -7060,14 +7212,19 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, if (rc != MBX_SUCCESS) lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI, "(%d):2541 Mailbox command x%x " - "(x%x/x%x) cannot issue Data: " - "x%x x%x\n", + "(x%x/x%x) failure: " + "mqe_sta: x%x mcqe_sta: x%x/x%x " + "Data: x%x x%x\n,", mboxq->vport ? mboxq->vport->vpi : 0, mboxq->u.mb.mbxCommand, lpfc_sli_config_mbox_subsys_get(phba, mboxq), lpfc_sli_config_mbox_opcode_get(phba, mboxq), + bf_get(lpfc_mqe_status, &mboxq->u.mqe), + bf_get(lpfc_mcqe_status, &mboxq->mcqe), + bf_get(lpfc_mcqe_ext_status, + &mboxq->mcqe), psli->sli_flag, flag); return rc; } else if (flag == MBX_POLL) { @@ -7086,18 +7243,22 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, /* Successfully blocked, now issue sync mbox cmd */ rc = lpfc_sli4_post_sync_mbox(phba, mboxq); if (rc != MBX_SUCCESS) - lpfc_printf_log(phba, KERN_ERR, + lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI, - "(%d):2597 Mailbox command " - "x%x (x%x/x%x) cannot issue " - "Data: x%x x%x\n", - mboxq->vport ? - mboxq->vport->vpi : 0, + "(%d):2597 Sync Mailbox command " + "x%x (x%x/x%x) failure: " + "mqe_sta: x%x mcqe_sta: x%x/x%x " + "Data: x%x x%x\n,", + mboxq->vport ? mboxq->vport->vpi : 0, mboxq->u.mb.mbxCommand, lpfc_sli_config_mbox_subsys_get(phba, mboxq), lpfc_sli_config_mbox_opcode_get(phba, mboxq), + bf_get(lpfc_mqe_status, &mboxq->u.mqe), + bf_get(lpfc_mcqe_status, &mboxq->mcqe), + bf_get(lpfc_mcqe_ext_status, + &mboxq->mcqe), psli->sli_flag, flag); /* Unblock the async mailbox posting afterward */ lpfc_sli4_async_mbox_unblock(phba); @@ -7712,7 +7873,10 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, switch (iocbq->iocb.ulpCommand) { case CMD_ELS_REQUEST64_CR: - ndlp = (struct lpfc_nodelist *)iocbq->context1; + if (iocbq->iocb_flag & LPFC_IO_LIBDFC) + ndlp = iocbq->context_un.ndlp; + else + ndlp = (struct lpfc_nodelist *)iocbq->context1; if (!iocbq->iocb.ulpLe) { lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "2007 Only Limited Edition cmd Format" @@ -7751,9 +7915,13 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, bf_set(els_req64_sp, &wqe->els_req, 1); bf_set(els_req64_sid, &wqe->els_req, iocbq->vport->fc_myDID); + if ((*pcmd == ELS_CMD_FLOGI) && + !(phba->fc_topology == + LPFC_TOPOLOGY_LOOP)) + bf_set(els_req64_sid, &wqe->els_req, 0); bf_set(wqe_ct, &wqe->els_req.wqe_com, 1); bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com, - phba->vpi_ids[phba->pport->vpi]); + phba->vpi_ids[iocbq->vport->vpi]); } else if (pcmd && iocbq->context1) { bf_set(wqe_ct, &wqe->els_req.wqe_com, 0); bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com, @@ -7908,11 +8076,25 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, /* words0-2 BDE memcpy */ /* word3 iocb=iotag32 wqe=response_payload_len */ wqe->xmit_els_rsp.response_payload_len = xmit_len; - /* word4 iocb=did wge=rsvd. */ - wqe->xmit_els_rsp.rsvd4 = 0; + /* word4 */ + wqe->xmit_els_rsp.word4 = 0; /* word5 iocb=rsvd wge=did */ bf_set(wqe_els_did, &wqe->xmit_els_rsp.wqe_dest, - iocbq->iocb.un.elsreq64.remoteID); + iocbq->iocb.un.xseq64.xmit_els_remoteID); + + if_type = bf_get(lpfc_sli_intf_if_type, + &phba->sli4_hba.sli_intf); + if (if_type == LPFC_SLI_INTF_IF_TYPE_2) { + if (iocbq->vport->fc_flag & FC_PT2PT) { + bf_set(els_rsp64_sp, &wqe->xmit_els_rsp, 1); + bf_set(els_rsp64_sid, &wqe->xmit_els_rsp, + iocbq->vport->fc_myDID); + if (iocbq->vport->fc_myDID == Fabric_DID) { + bf_set(wqe_els_did, + &wqe->xmit_els_rsp.wqe_dest, 0); + } + } + } bf_set(wqe_ct, &wqe->xmit_els_rsp.wqe_com, ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l)); bf_set(wqe_pu, &wqe->xmit_els_rsp.wqe_com, iocbq->iocb.ulpPU); @@ -7932,11 +8114,11 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, pcmd = (uint32_t *) (((struct lpfc_dmabuf *) iocbq->context2)->virt); if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { - bf_set(els_req64_sp, &wqe->els_req, 1); - bf_set(els_req64_sid, &wqe->els_req, + bf_set(els_rsp64_sp, &wqe->xmit_els_rsp, 1); + bf_set(els_rsp64_sid, &wqe->xmit_els_rsp, iocbq->vport->fc_myDID); - bf_set(wqe_ct, &wqe->els_req.wqe_com, 1); - bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com, + bf_set(wqe_ct, &wqe->xmit_els_rsp.wqe_com, 1); + bf_set(wqe_ctxt_tag, &wqe->xmit_els_rsp.wqe_com, phba->vpi_ids[phba->pport->vpi]); } command_type = OTHER_COMMAND; @@ -13080,9 +13262,7 @@ lpfc_sli4_alloc_xri(struct lpfc_hba *phba) } else { set_bit(xri, phba->sli4_hba.xri_bmask); phba->sli4_hba.max_cfg_param.xri_used++; - phba->sli4_hba.xri_count++; } - spin_unlock_irq(&phba->hbalock); return xri; } @@ -13098,7 +13278,6 @@ void __lpfc_sli4_free_xri(struct lpfc_hba *phba, int xri) { if (test_and_clear_bit(xri, phba->sli4_hba.xri_bmask)) { - phba->sli4_hba.xri_count--; phba->sli4_hba.max_cfg_param.xri_used--; } } @@ -13134,46 +13313,45 @@ lpfc_sli4_next_xritag(struct lpfc_hba *phba) uint16_t xri_index; xri_index = lpfc_sli4_alloc_xri(phba); - if (xri_index != NO_XRI) - return xri_index; - - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2004 Failed to allocate XRI.last XRITAG is %d" - " Max XRI is %d, Used XRI is %d\n", - xri_index, - phba->sli4_hba.max_cfg_param.max_xri, - phba->sli4_hba.max_cfg_param.xri_used); - return NO_XRI; + if (xri_index == NO_XRI) + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "2004 Failed to allocate XRI.last XRITAG is %d" + " Max XRI is %d, Used XRI is %d\n", + xri_index, + phba->sli4_hba.max_cfg_param.max_xri, + phba->sli4_hba.max_cfg_param.xri_used); + return xri_index; } /** * lpfc_sli4_post_els_sgl_list - post a block of ELS sgls to the port. * @phba: pointer to lpfc hba data structure. + * @post_sgl_list: pointer to els sgl entry list. + * @count: number of els sgl entries on the list. * * This routine is invoked to post a block of driver's sgl pages to the * HBA using non-embedded mailbox command. No Lock is held. This routine * is only called when the driver is loading and after all IO has been * stopped. **/ -int -lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba) +static int +lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba, + struct list_head *post_sgl_list, + int post_cnt) { - struct lpfc_sglq *sglq_entry; + struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL; struct lpfc_mbx_post_uembed_sgl_page1 *sgl; struct sgl_page_pairs *sgl_pg_pairs; void *viraddr; LPFC_MBOXQ_t *mbox; uint32_t reqlen, alloclen, pg_pairs; uint32_t mbox_tmo; - uint16_t xritag_start = 0, lxri = 0; - int els_xri_cnt, rc = 0; + uint16_t xritag_start = 0; + int rc = 0; uint32_t shdr_status, shdr_add_status; union lpfc_sli4_cfg_shdr *shdr; - /* The number of sgls to be posted */ - els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba); - - reqlen = els_xri_cnt * sizeof(struct sgl_page_pairs) + + reqlen = phba->sli4_hba.els_xri_cnt * sizeof(struct sgl_page_pairs) + sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); if (reqlen > SLI4_PAGE_SIZE) { lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, @@ -13203,25 +13381,8 @@ lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba) sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr; sgl_pg_pairs = &sgl->sgl_pg_pairs; - for (pg_pairs = 0; pg_pairs < els_xri_cnt; pg_pairs++) { - sglq_entry = phba->sli4_hba.lpfc_els_sgl_array[pg_pairs]; - - /* - * Assign the sglq a physical xri only if the driver has not - * initialized those resources. A port reset only needs - * the sglq's posted. - */ - if (bf_get(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags) != - LPFC_XRI_RSRC_RDY) { - lxri = lpfc_sli4_next_xritag(phba); - if (lxri == NO_XRI) { - lpfc_sli4_mbox_cmd_free(phba, mbox); - return -ENOMEM; - } - sglq_entry->sli4_lxritag = lxri; - sglq_entry->sli4_xritag = phba->sli4_hba.xri_ids[lxri]; - } - + pg_pairs = 0; + list_for_each_entry_safe(sglq_entry, sglq_next, post_sgl_list, list) { /* Set up the sge entry */ sgl_pg_pairs->sgl_pg0_addr_lo = cpu_to_le32(putPaddrLow(sglq_entry->phys)); @@ -13236,11 +13397,12 @@ lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba) if (pg_pairs == 0) xritag_start = sglq_entry->sli4_xritag; sgl_pg_pairs++; + pg_pairs++; } /* Complete initialization and perform endian conversion. */ bf_set(lpfc_post_sgl_pages_xri, sgl, xritag_start); - bf_set(lpfc_post_sgl_pages_xricnt, sgl, els_xri_cnt); + bf_set(lpfc_post_sgl_pages_xricnt, sgl, phba->sli4_hba.els_xri_cnt); sgl->word0 = cpu_to_le32(sgl->word0); if (!phba->sli4_hba.intr_enable) rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); @@ -13260,183 +13422,6 @@ lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba) shdr_status, shdr_add_status, rc); rc = -ENXIO; } - - if (rc == 0) - bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags, - LPFC_XRI_RSRC_RDY); - return rc; -} - -/** - * lpfc_sli4_post_els_sgl_list_ext - post a block of ELS sgls to the port. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to post a block of driver's sgl pages to the - * HBA using non-embedded mailbox command. No Lock is held. This routine - * is only called when the driver is loading and after all IO has been - * stopped. - **/ -int -lpfc_sli4_post_els_sgl_list_ext(struct lpfc_hba *phba) -{ - struct lpfc_sglq *sglq_entry; - struct lpfc_mbx_post_uembed_sgl_page1 *sgl; - struct sgl_page_pairs *sgl_pg_pairs; - void *viraddr; - LPFC_MBOXQ_t *mbox; - uint32_t reqlen, alloclen, index; - uint32_t mbox_tmo; - uint16_t rsrc_start, rsrc_size, els_xri_cnt, post_els_xri_cnt; - uint16_t xritag_start = 0, lxri = 0; - struct lpfc_rsrc_blks *rsrc_blk; - int cnt, ttl_cnt, rc = 0; - int loop_cnt; - uint32_t shdr_status, shdr_add_status; - union lpfc_sli4_cfg_shdr *shdr; - - /* The number of sgls to be posted */ - els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba); - - reqlen = els_xri_cnt * sizeof(struct sgl_page_pairs) + - sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); - if (reqlen > SLI4_PAGE_SIZE) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "2989 Block sgl registration required DMA " - "size (%d) great than a page\n", reqlen); - return -ENOMEM; - } - - cnt = 0; - ttl_cnt = 0; - post_els_xri_cnt = els_xri_cnt; - list_for_each_entry(rsrc_blk, &phba->sli4_hba.lpfc_xri_blk_list, - list) { - rsrc_start = rsrc_blk->rsrc_start; - rsrc_size = rsrc_blk->rsrc_size; - - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "3014 Working ELS Extent start %d, cnt %d\n", - rsrc_start, rsrc_size); - - loop_cnt = min(post_els_xri_cnt, rsrc_size); - if (loop_cnt < post_els_xri_cnt) { - post_els_xri_cnt -= loop_cnt; - ttl_cnt += loop_cnt; - } else - ttl_cnt += post_els_xri_cnt; - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return -ENOMEM; - /* - * Allocate DMA memory and set up the non-embedded mailbox - * command. - */ - alloclen = lpfc_sli4_config(phba, mbox, - LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES, - reqlen, LPFC_SLI4_MBX_NEMBED); - if (alloclen < reqlen) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2987 Allocated DMA memory size (%d) " - "is less than the requested DMA memory " - "size (%d)\n", alloclen, reqlen); - lpfc_sli4_mbox_cmd_free(phba, mbox); - return -ENOMEM; - } - - /* Set up the SGL pages in the non-embedded DMA pages */ - viraddr = mbox->sge_array->addr[0]; - sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr; - sgl_pg_pairs = &sgl->sgl_pg_pairs; - - /* - * The starting resource may not begin at zero. Control - * the loop variants via the block resource parameters, - * but handle the sge pointers with a zero-based index - * that doesn't get reset per loop pass. - */ - for (index = rsrc_start; - index < rsrc_start + loop_cnt; - index++) { - sglq_entry = phba->sli4_hba.lpfc_els_sgl_array[cnt]; - - /* - * Assign the sglq a physical xri only if the driver - * has not initialized those resources. A port reset - * only needs the sglq's posted. - */ - if (bf_get(lpfc_xri_rsrc_rdy, - &phba->sli4_hba.sli4_flags) != - LPFC_XRI_RSRC_RDY) { - lxri = lpfc_sli4_next_xritag(phba); - if (lxri == NO_XRI) { - lpfc_sli4_mbox_cmd_free(phba, mbox); - rc = -ENOMEM; - goto err_exit; - } - sglq_entry->sli4_lxritag = lxri; - sglq_entry->sli4_xritag = - phba->sli4_hba.xri_ids[lxri]; - } - - /* Set up the sge entry */ - sgl_pg_pairs->sgl_pg0_addr_lo = - cpu_to_le32(putPaddrLow(sglq_entry->phys)); - sgl_pg_pairs->sgl_pg0_addr_hi = - cpu_to_le32(putPaddrHigh(sglq_entry->phys)); - sgl_pg_pairs->sgl_pg1_addr_lo = - cpu_to_le32(putPaddrLow(0)); - sgl_pg_pairs->sgl_pg1_addr_hi = - cpu_to_le32(putPaddrHigh(0)); - - /* Track the starting physical XRI for the mailbox. */ - if (index == rsrc_start) - xritag_start = sglq_entry->sli4_xritag; - sgl_pg_pairs++; - cnt++; - } - - /* Complete initialization and perform endian conversion. */ - rsrc_blk->rsrc_used += loop_cnt; - bf_set(lpfc_post_sgl_pages_xri, sgl, xritag_start); - bf_set(lpfc_post_sgl_pages_xricnt, sgl, loop_cnt); - sgl->word0 = cpu_to_le32(sgl->word0); - - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "3015 Post ELS Extent SGL, start %d, " - "cnt %d, used %d\n", - xritag_start, loop_cnt, rsrc_blk->rsrc_used); - if (!phba->sli4_hba.intr_enable) - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - else { - mbox_tmo = lpfc_mbox_tmo_val(phba, mbox); - rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); - } - shdr = (union lpfc_sli4_cfg_shdr *) &sgl->cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, - &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, - &shdr->response); - if (rc != MBX_TIMEOUT) - lpfc_sli4_mbox_cmd_free(phba, mbox); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2988 POST_SGL_BLOCK mailbox " - "command failed status x%x " - "add_status x%x mbx status x%x\n", - shdr_status, shdr_add_status, rc); - rc = -ENXIO; - goto err_exit; - } - if (ttl_cnt >= els_xri_cnt) - break; - } - - err_exit: - if (rc == 0) - bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags, - LPFC_XRI_RSRC_RDY); return rc; } @@ -13452,8 +13437,9 @@ lpfc_sli4_post_els_sgl_list_ext(struct lpfc_hba *phba) * **/ int -lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist, - int cnt) +lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, + struct list_head *sblist, + int count) { struct lpfc_scsi_buf *psb; struct lpfc_mbx_post_uembed_sgl_page1 *sgl; @@ -13469,7 +13455,7 @@ lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist, union lpfc_sli4_cfg_shdr *shdr; /* Calculate the requested length of the dma memory */ - reqlen = cnt * sizeof(struct sgl_page_pairs) + + reqlen = count * sizeof(struct sgl_page_pairs) + sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); if (reqlen > SLI4_PAGE_SIZE) { lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, @@ -13552,169 +13538,6 @@ lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist, return rc; } -/** - * lpfc_sli4_post_scsi_sgl_blk_ext - post a block of scsi sgls to the port. - * @phba: pointer to lpfc hba data structure. - * @sblist: pointer to scsi buffer list. - * @count: number of scsi buffers on the list. - * - * This routine is invoked to post a block of @count scsi sgl pages from a - * SCSI buffer list @sblist to the HBA using non-embedded mailbox command. - * No Lock is held. - * - **/ -int -lpfc_sli4_post_scsi_sgl_blk_ext(struct lpfc_hba *phba, struct list_head *sblist, - int cnt) -{ - struct lpfc_scsi_buf *psb = NULL; - struct lpfc_mbx_post_uembed_sgl_page1 *sgl; - struct sgl_page_pairs *sgl_pg_pairs; - void *viraddr; - LPFC_MBOXQ_t *mbox; - uint32_t reqlen, alloclen, pg_pairs; - uint32_t mbox_tmo; - uint16_t xri_start = 0, scsi_xri_start; - uint16_t rsrc_range; - int rc = 0, avail_cnt; - uint32_t shdr_status, shdr_add_status; - dma_addr_t pdma_phys_bpl1; - union lpfc_sli4_cfg_shdr *shdr; - struct lpfc_rsrc_blks *rsrc_blk; - uint32_t xri_cnt = 0; - - /* Calculate the total requested length of the dma memory */ - reqlen = cnt * sizeof(struct sgl_page_pairs) + - sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); - if (reqlen > SLI4_PAGE_SIZE) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "2932 Block sgl registration required DMA " - "size (%d) great than a page\n", reqlen); - return -ENOMEM; - } - - /* - * The use of extents requires the driver to post the sgl headers - * in multiple postings to meet the contiguous resource assignment. - */ - psb = list_prepare_entry(psb, sblist, list); - scsi_xri_start = phba->sli4_hba.scsi_xri_start; - list_for_each_entry(rsrc_blk, &phba->sli4_hba.lpfc_xri_blk_list, - list) { - rsrc_range = rsrc_blk->rsrc_start + rsrc_blk->rsrc_size; - if (rsrc_range < scsi_xri_start) - continue; - else if (rsrc_blk->rsrc_used >= rsrc_blk->rsrc_size) - continue; - else - avail_cnt = rsrc_blk->rsrc_size - rsrc_blk->rsrc_used; - - reqlen = (avail_cnt * sizeof(struct sgl_page_pairs)) + - sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); - /* - * Allocate DMA memory and set up the non-embedded mailbox - * command. The mbox is used to post an SGL page per loop - * but the DMA memory has a use-once semantic so the mailbox - * is used and freed per loop pass. - */ - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2933 Failed to allocate mbox cmd " - "memory\n"); - return -ENOMEM; - } - alloclen = lpfc_sli4_config(phba, mbox, - LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES, - reqlen, - LPFC_SLI4_MBX_NEMBED); - if (alloclen < reqlen) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2934 Allocated DMA memory size (%d) " - "is less than the requested DMA memory " - "size (%d)\n", alloclen, reqlen); - lpfc_sli4_mbox_cmd_free(phba, mbox); - return -ENOMEM; - } - - /* Get the first SGE entry from the non-embedded DMA memory */ - viraddr = mbox->sge_array->addr[0]; - - /* Set up the SGL pages in the non-embedded DMA pages */ - sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr; - sgl_pg_pairs = &sgl->sgl_pg_pairs; - - /* pg_pairs tracks posted SGEs per loop iteration. */ - pg_pairs = 0; - list_for_each_entry_continue(psb, sblist, list) { - /* Set up the sge entry */ - sgl_pg_pairs->sgl_pg0_addr_lo = - cpu_to_le32(putPaddrLow(psb->dma_phys_bpl)); - sgl_pg_pairs->sgl_pg0_addr_hi = - cpu_to_le32(putPaddrHigh(psb->dma_phys_bpl)); - if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE) - pdma_phys_bpl1 = psb->dma_phys_bpl + - SGL_PAGE_SIZE; - else - pdma_phys_bpl1 = 0; - sgl_pg_pairs->sgl_pg1_addr_lo = - cpu_to_le32(putPaddrLow(pdma_phys_bpl1)); - sgl_pg_pairs->sgl_pg1_addr_hi = - cpu_to_le32(putPaddrHigh(pdma_phys_bpl1)); - /* Keep the first xri for this extent. */ - if (pg_pairs == 0) - xri_start = psb->cur_iocbq.sli4_xritag; - sgl_pg_pairs++; - pg_pairs++; - xri_cnt++; - - /* - * Track two exit conditions - the loop has constructed - * all of the caller's SGE pairs or all available - * resource IDs in this extent are consumed. - */ - if ((xri_cnt == cnt) || (pg_pairs >= avail_cnt)) - break; - } - rsrc_blk->rsrc_used += pg_pairs; - bf_set(lpfc_post_sgl_pages_xri, sgl, xri_start); - bf_set(lpfc_post_sgl_pages_xricnt, sgl, pg_pairs); - - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "3016 Post SCSI Extent SGL, start %d, cnt %d " - "blk use %d\n", - xri_start, pg_pairs, rsrc_blk->rsrc_used); - /* Perform endian conversion if necessary */ - sgl->word0 = cpu_to_le32(sgl->word0); - if (!phba->sli4_hba.intr_enable) - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - else { - mbox_tmo = lpfc_mbox_tmo_val(phba, mbox); - rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); - } - shdr = (union lpfc_sli4_cfg_shdr *) &sgl->cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, - &shdr->response); - if (rc != MBX_TIMEOUT) - lpfc_sli4_mbox_cmd_free(phba, mbox); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2935 POST_SGL_BLOCK mailbox command " - "failed status x%x add_status x%x " - "mbx status x%x\n", - shdr_status, shdr_add_status, rc); - return -ENXIO; - } - - /* Post only what is requested. */ - if (xri_cnt >= cnt) - break; - } - return rc; -} - /** * lpfc_fc_frame_check - Check that this frame is a valid frame to handle * @phba: pointer to lpfc_hba struct that the frame was received on @@ -13839,8 +13662,13 @@ lpfc_fc_frame_to_vport(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr, uint32_t did = (fc_hdr->fh_d_id[0] << 16 | fc_hdr->fh_d_id[1] << 8 | fc_hdr->fh_d_id[2]); + if (did == Fabric_DID) return phba->pport; + if ((phba->pport->fc_flag & FC_PT2PT) && + !(phba->link_state == LPFC_HBA_READY)) + return phba->pport; + vports = lpfc_create_vport_work_array(phba); if (vports != NULL) for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { @@ -14133,7 +13961,6 @@ lpfc_sli4_xri_inrange(struct lpfc_hba *phba, return NO_XRI; } - /** * lpfc_sli4_seq_abort_rsp - bls rsp to sequence abort * @phba: Pointer to HBA context object. @@ -14148,7 +13975,7 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba, { struct lpfc_iocbq *ctiocb = NULL; struct lpfc_nodelist *ndlp; - uint16_t oxid, rxid; + uint16_t oxid, rxid, xri, lxri; uint32_t sid, fctl; IOCB_t *icmd; int rc; @@ -14167,8 +13994,6 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba, "SID:x%x\n", oxid, sid); return; } - if (lpfc_sli4_xri_inrange(phba, rxid)) - lpfc_set_rrq_active(phba, ndlp, rxid, oxid, 0); /* Allocate buffer for rsp iocb */ ctiocb = lpfc_sli_get_iocbq(phba); @@ -14199,13 +14024,24 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba, ctiocb->sli4_lxritag = NO_XRI; ctiocb->sli4_xritag = NO_XRI; + if (fctl & FC_FC_EX_CTX) + /* Exchange responder sent the abort so we + * own the oxid. + */ + xri = oxid; + else + xri = rxid; + lxri = lpfc_sli4_xri_inrange(phba, xri); + if (lxri != NO_XRI) + lpfc_set_rrq_active(phba, ndlp, lxri, + (xri == oxid) ? rxid : oxid, 0); /* If the oxid maps to the FCP XRI range or if it is out of range, * send a BLS_RJT. The driver no longer has that exchange. * Override the IOCB for a BA_RJT. */ - if (oxid > (phba->sli4_hba.max_cfg_param.max_xri + + if (xri > (phba->sli4_hba.max_cfg_param.max_xri + phba->sli4_hba.max_cfg_param.xri_base) || - oxid > (lpfc_sli4_get_els_iocb_cnt(phba) + + xri > (lpfc_sli4_get_els_iocb_cnt(phba) + phba->sli4_hba.max_cfg_param.xri_base)) { icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_BA_RJT; bf_set(lpfc_vndr_code, &icmd->un.bls_rsp, 0); @@ -14377,7 +14213,15 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf) /* Initialize the first IOCB. */ first_iocbq->iocb.unsli3.rcvsli3.acc_len = 0; first_iocbq->iocb.ulpStatus = IOSTAT_SUCCESS; - first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_SEQ64_CX; + + /* Check FC Header to see what TYPE of frame we are rcv'ing */ + if (sli4_type_from_fc_hdr(fc_hdr) == FC_TYPE_ELS) { + first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_ELS64_CX; + first_iocbq->iocb.un.rcvels.parmRo = + sli4_did_from_fc_hdr(fc_hdr); + first_iocbq->iocb.ulpPU = PARM_NPIV_DID; + } else + first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_SEQ64_CX; first_iocbq->iocb.ulpContext = NO_XRI; first_iocbq->iocb.unsli3.rcvsli3.ox_id = be16_to_cpu(fc_hdr->fh_ox_id); @@ -14507,6 +14351,7 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr; struct lpfc_vport *vport; uint32_t fcfi; + uint32_t did; /* Process each received buffer */ fc_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt; @@ -14522,12 +14367,32 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba, else fcfi = bf_get(lpfc_rcqe_fcf_id, &dmabuf->cq_event.cqe.rcqe_cmpl); + vport = lpfc_fc_frame_to_vport(phba, fc_hdr, fcfi); - if (!vport || !(vport->vpi_state & LPFC_VPI_REGISTERED)) { + if (!vport) { /* throw out the frame */ lpfc_in_buf_free(phba, &dmabuf->dbuf); return; } + + /* d_id this frame is directed to */ + did = sli4_did_from_fc_hdr(fc_hdr); + + /* vport is registered unless we rcv a FLOGI directed to Fabric_DID */ + if (!(vport->vpi_state & LPFC_VPI_REGISTERED) && + (did != Fabric_DID)) { + /* + * Throw out the frame if we are not pt2pt. + * The pt2pt protocol allows for discovery frames + * to be received without a registered VPI. + */ + if (!(vport->fc_flag & FC_PT2PT) || + (phba->link_state == LPFC_HBA_READY)) { + lpfc_in_buf_free(phba, &dmabuf->dbuf); + return; + } + } + /* Handle the basic abort sequence (BA_ABTS) event */ if (fc_hdr->fh_r_ctl == FC_RCTL_BA_ABTS) { lpfc_sli4_handle_unsol_abort(vport, dmabuf); diff --git a/trunk/drivers/scsi/lpfc/lpfc_sli.h b/trunk/drivers/scsi/lpfc/lpfc_sli.h index 3290b8e7ab65..2626f58c0747 100644 --- a/trunk/drivers/scsi/lpfc/lpfc_sli.h +++ b/trunk/drivers/scsi/lpfc/lpfc_sli.h @@ -68,7 +68,7 @@ struct lpfc_iocbq { #define LPFC_EXCHANGE_BUSY 0x40 /* SLI4 hba reported XB in response */ #define LPFC_USE_FCPWQIDX 0x80 /* Submit to specified FCPWQ index */ #define DSS_SECURITY_OP 0x100 /* security IO */ -#define LPFC_IO_ON_Q 0x200 /* The IO is still on the TXCMPLQ */ +#define LPFC_IO_ON_TXCMPLQ 0x200 /* The IO is still on the TXCMPLQ */ #define LPFC_IO_DIF 0x400 /* T10 DIF IO */ #define LPFC_FIP_ELS_ID_MASK 0xc000 /* ELS_ID range 0-3, non-shifted mask */ diff --git a/trunk/drivers/scsi/lpfc/lpfc_sli4.h b/trunk/drivers/scsi/lpfc/lpfc_sli4.h index c19d139618b7..a4a77080091b 100644 --- a/trunk/drivers/scsi/lpfc/lpfc_sli4.h +++ b/trunk/drivers/scsi/lpfc/lpfc_sli4.h @@ -75,11 +75,19 @@ (fc_hdr)->fh_s_id[1] << 8 | \ (fc_hdr)->fh_s_id[2]) +#define sli4_did_from_fc_hdr(fc_hdr) \ + ((fc_hdr)->fh_d_id[0] << 16 | \ + (fc_hdr)->fh_d_id[1] << 8 | \ + (fc_hdr)->fh_d_id[2]) + #define sli4_fctl_from_fc_hdr(fc_hdr) \ ((fc_hdr)->fh_f_ctl[0] << 16 | \ (fc_hdr)->fh_f_ctl[1] << 8 | \ (fc_hdr)->fh_f_ctl[2]) +#define sli4_type_from_fc_hdr(fc_hdr) \ + ((fc_hdr)->fh_type) + #define LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT 12000 enum lpfc_sli4_queue_type { @@ -493,14 +501,12 @@ struct lpfc_sli4_hba { uint16_t next_rpi; uint16_t scsi_xri_max; uint16_t scsi_xri_cnt; + uint16_t els_xri_cnt; uint16_t scsi_xri_start; struct list_head lpfc_free_sgl_list; struct list_head lpfc_sgl_list; - struct lpfc_sglq **lpfc_els_sgl_array; struct list_head lpfc_abts_els_sgl_list; - struct lpfc_scsi_buf **lpfc_scsi_psb_array; struct list_head lpfc_abts_scsi_buf_list; - uint32_t total_sglq_bufs; struct lpfc_sglq **lpfc_sglq_active_list; struct list_head lpfc_rpi_hdr_list; unsigned long *rpi_bmask; @@ -509,7 +515,6 @@ struct lpfc_sli4_hba { struct list_head lpfc_rpi_blk_list; unsigned long *xri_bmask; uint16_t *xri_ids; - uint16_t xri_count; struct list_head lpfc_xri_blk_list; unsigned long *vfi_bmask; uint16_t *vfi_ids; @@ -614,11 +619,7 @@ int lpfc_sli4_post_sgl(struct lpfc_hba *, dma_addr_t, dma_addr_t, uint16_t); int lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *); uint16_t lpfc_sli4_next_xritag(struct lpfc_hba *); int lpfc_sli4_post_async_mbox(struct lpfc_hba *); -int lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba); -int lpfc_sli4_post_els_sgl_list_ext(struct lpfc_hba *phba); int lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *, struct list_head *, int); -int lpfc_sli4_post_scsi_sgl_blk_ext(struct lpfc_hba *, struct list_head *, - int); struct lpfc_cq_event *__lpfc_sli4_cq_event_alloc(struct lpfc_hba *); struct lpfc_cq_event *lpfc_sli4_cq_event_alloc(struct lpfc_hba *); void __lpfc_sli4_cq_event_release(struct lpfc_hba *, struct lpfc_cq_event *); diff --git a/trunk/drivers/scsi/lpfc/lpfc_version.h b/trunk/drivers/scsi/lpfc/lpfc_version.h index 25cefc254b76..59c57a409981 100644 --- a/trunk/drivers/scsi/lpfc/lpfc_version.h +++ b/trunk/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.3.30" +#define LPFC_DRIVER_VERSION "8.3.31" #define LPFC_DRIVER_NAME "lpfc" #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" #define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp" diff --git a/trunk/drivers/scsi/megaraid/megaraid_sas.h b/trunk/drivers/scsi/megaraid/megaraid_sas.h index e5f416f8042d..e8f892647681 100644 --- a/trunk/drivers/scsi/megaraid/megaraid_sas.h +++ b/trunk/drivers/scsi/megaraid/megaraid_sas.h @@ -33,9 +33,9 @@ /* * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "00.00.06.14-rc1" -#define MEGASAS_RELDATE "Jan. 6, 2012" -#define MEGASAS_EXT_VERSION "Fri. Jan. 6 17:00:00 PDT 2012" +#define MEGASAS_VERSION "00.00.06.15-rc1" +#define MEGASAS_RELDATE "Mar. 19, 2012" +#define MEGASAS_EXT_VERSION "Mon. Mar. 19 17:00:00 PDT 2012" /* * Device IDs diff --git a/trunk/drivers/scsi/megaraid/megaraid_sas_base.c b/trunk/drivers/scsi/megaraid/megaraid_sas_base.c index 8b300be44284..dc27598785e5 100644 --- a/trunk/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/trunk/drivers/scsi/megaraid/megaraid_sas_base.c @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * FILE: megaraid_sas_base.c - * Version : v00.00.06.14-rc1 + * Version : v00.00.06.15-rc1 * * Authors: LSI Corporation * Sreenivas Bagalkote diff --git a/trunk/drivers/scsi/megaraid/megaraid_sas_fp.c b/trunk/drivers/scsi/megaraid/megaraid_sas_fp.c index 294abb0defa6..e3d251a2e26a 100644 --- a/trunk/drivers/scsi/megaraid/megaraid_sas_fp.c +++ b/trunk/drivers/scsi/megaraid/megaraid_sas_fp.c @@ -362,15 +362,20 @@ MR_BuildRaidContext(struct megasas_instance *instance, /* assume this IO needs the full row - we'll adjust if not true */ regSize = stripSize; - /* If IO spans more than 1 strip, fp is not possible - FP is not possible for writes on non-0 raid levels - FP is not possible if LD is not capable */ - if (num_strips > 1 || (!isRead && raid->level != 0) || - !raid->capability.fpCapable) { + /* Check if we can send this I/O via FastPath */ + if (raid->capability.fpCapable) { + if (isRead) + io_info->fpOkForIo = (raid->capability.fpReadCapable && + ((num_strips == 1) || + raid->capability. + fpReadAcrossStripe)); + else + io_info->fpOkForIo = (raid->capability.fpWriteCapable && + ((num_strips == 1) || + raid->capability. + fpWriteAcrossStripe)); + } else io_info->fpOkForIo = FALSE; - } else { - io_info->fpOkForIo = TRUE; - } if (numRows == 1) { /* single-strip IOs can always lock only the data needed */ diff --git a/trunk/drivers/scsi/megaraid/megaraid_sas_fusion.c b/trunk/drivers/scsi/megaraid/megaraid_sas_fusion.c index bfd87fab39aa..a610cf1d4847 100644 --- a/trunk/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/trunk/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -634,9 +634,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) fusion->reply_frames_desc_phys; IOCInitMessage->SystemRequestFrameBaseAddress = fusion->io_request_frames_phys; - /* Set to 0 for none or 1 MSI-X vectors */ - IOCInitMessage->HostMSIxVectors = (instance->msix_vectors > 0 ? - instance->msix_vectors : 0); + IOCInitMessage->HostMSIxVectors = instance->msix_vectors; init_frame = (struct megasas_init_frame *)cmd->frame; memset(init_frame, 0, MEGAMFI_FRAME_SIZE); diff --git a/trunk/drivers/scsi/mpt2sas/mpi/mpi2.h b/trunk/drivers/scsi/mpt2sas/mpi/mpi2.h index a01f0aa66f20..a80f3220c641 100644 --- a/trunk/drivers/scsi/mpt2sas/mpi/mpi2.h +++ b/trunk/drivers/scsi/mpt2sas/mpi/mpi2.h @@ -8,7 +8,7 @@ * scatter/gather formats. * Creation Date: June 21, 2006 * - * mpi2.h Version: 02.00.22 + * mpi2.h Version: 02.00.23 * * Version History * --------------- @@ -71,6 +71,7 @@ * 03-09-11 02.00.20 Bumped MPI2_HEADER_VERSION_UNIT. * 05-25-11 02.00.21 Bumped MPI2_HEADER_VERSION_UNIT. * 08-24-11 02.00.22 Bumped MPI2_HEADER_VERSION_UNIT. + * 11-18-11 02.00.23 Bumped MPI2_HEADER_VERSION_UNIT. * -------------------------------------------------------------------------- */ @@ -96,7 +97,7 @@ #define MPI2_VERSION_02_00 (0x0200) /* versioning for this MPI header set */ -#define MPI2_HEADER_VERSION_UNIT (0x16) +#define MPI2_HEADER_VERSION_UNIT (0x17) #define MPI2_HEADER_VERSION_DEV (0x00) #define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI2_HEADER_VERSION_UNIT_SHIFT (8) @@ -480,7 +481,7 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR RAIDAcceleratorSuccess; U64 Words; } MPI2_REPLY_DESCRIPTORS_UNION, MPI2_POINTER PTR_MPI2_REPLY_DESCRIPTORS_UNION, - Mpi2ReplyDescriptorsUnion_t, MPI2_POINTER pMpi2ReplyDescriptorsUnion_t; +Mpi2ReplyDescriptorsUnion_t, MPI2_POINTER pMpi2ReplyDescriptorsUnion_t; diff --git a/trunk/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/trunk/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h index 3a023dad77a1..737fa8cfb54a 100644 --- a/trunk/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h +++ b/trunk/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h @@ -6,7 +6,7 @@ * Title: MPI Configuration messages and pages * Creation Date: November 10, 2006 * - * mpi2_cnfg.h Version: 02.00.21 + * mpi2_cnfg.h Version: 02.00.22 * * Version History * --------------- @@ -146,7 +146,9 @@ * Added SpinupFlags field containing a Disable Spin-up * bit to the MPI2_SAS_IOUNIT4_SPINUP_GROUP fields of * SAS IO Unit Page 4. - + * 11-18-11 02.00.22 Added define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT. + * Added UEFIVersion field to BIOS Page 1 and defined new + * BiosOptions bits. * -------------------------------------------------------------------------- */ @@ -1131,9 +1133,10 @@ typedef struct _MPI2_CONFIG_PAGE_IOC_6 } MPI2_CONFIG_PAGE_IOC_6, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_6, Mpi2IOCPage6_t, MPI2_POINTER pMpi2IOCPage6_t; -#define MPI2_IOCPAGE6_PAGEVERSION (0x04) +#define MPI2_IOCPAGE6_PAGEVERSION (0x05) /* defines for IOC Page 6 CapabilitiesFlags */ +#define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT (0x00000020) #define MPI2_IOCPAGE6_CAP_FLAGS_RAID10_SUPPORT (0x00000010) #define MPI2_IOCPAGE6_CAP_FLAGS_RAID1_SUPPORT (0x00000008) #define MPI2_IOCPAGE6_CAP_FLAGS_RAID1E_SUPPORT (0x00000004) @@ -1204,24 +1207,29 @@ typedef struct _MPI2_CONFIG_PAGE_IOC_8 typedef struct _MPI2_CONFIG_PAGE_BIOS_1 { - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 BiosOptions; /* 0x04 */ - U32 IOCSettings; /* 0x08 */ - U32 Reserved1; /* 0x0C */ - U32 DeviceSettings; /* 0x10 */ - U16 NumberOfDevices; /* 0x14 */ - U16 Reserved2; /* 0x16 */ - U16 IOTimeoutBlockDevicesNonRM; /* 0x18 */ - U16 IOTimeoutSequential; /* 0x1A */ - U16 IOTimeoutOther; /* 0x1C */ - U16 IOTimeoutBlockDevicesRM; /* 0x1E */ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 BiosOptions; /* 0x04 */ + U32 IOCSettings; /* 0x08 */ + U32 Reserved1; /* 0x0C */ + U32 DeviceSettings; /* 0x10 */ + U16 NumberOfDevices; /* 0x14 */ + U16 UEFIVersion; /* 0x16 */ + U16 IOTimeoutBlockDevicesNonRM; /* 0x18 */ + U16 IOTimeoutSequential; /* 0x1A */ + U16 IOTimeoutOther; /* 0x1C */ + U16 IOTimeoutBlockDevicesRM; /* 0x1E */ } MPI2_CONFIG_PAGE_BIOS_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_1, Mpi2BiosPage1_t, MPI2_POINTER pMpi2BiosPage1_t; -#define MPI2_BIOSPAGE1_PAGEVERSION (0x04) +#define MPI2_BIOSPAGE1_PAGEVERSION (0x05) /* values for BIOS Page 1 BiosOptions field */ -#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_BIOS (0x00000001) +#define MPI2_BIOSPAGE1_OPTIONS_MASK_UEFI_HII_REGISTRATION (0x00000006) +#define MPI2_BIOSPAGE1_OPTIONS_ENABLE_UEFI_HII (0x00000000) +#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_UEFI_HII (0x00000002) +#define MPI2_BIOSPAGE1_OPTIONS_VERSION_CHECK_UEFI_HII (0x00000004) + +#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_BIOS (0x00000001) /* values for BIOS Page 1 IOCSettings field */ #define MPI2_BIOSPAGE1_IOCSET_MASK_BOOT_PREFERENCE (0x00030000) @@ -1248,6 +1256,13 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_1 #define MPI2_BIOSPAGE1_DEVSET_DISABLE_NON_RM_LUN (0x00000002) #define MPI2_BIOSPAGE1_DEVSET_DISABLE_OTHER_LUN (0x00000001) +/* defines for BIOS Page 1 UEFIVersion field */ +#define MPI2_BIOSPAGE1_UEFI_VER_MAJOR_MASK (0xFF00) +#define MPI2_BIOSPAGE1_UEFI_VER_MAJOR_SHIFT (8) +#define MPI2_BIOSPAGE1_UEFI_VER_MINOR_MASK (0x00FF) +#define MPI2_BIOSPAGE1_UEFI_VER_MINOR_SHIFT (0) + + /* BIOS Page 2 */ @@ -2216,6 +2231,27 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_8 { +/* SAS IO Unit Page 16 */ + +typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT16 { + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U64 TimeStamp; /* 0x08 */ + U32 Reserved1; /* 0x10 */ + U32 Reserved2; /* 0x14 */ + U32 FastPathPendedRequests; /* 0x18 */ + U32 FastPathUnPendedRequests; /* 0x1C */ + U32 FastPathHostRequestStarts; /* 0x20 */ + U32 FastPathFirmwareRequestStarts; /* 0x24 */ + U32 FastPathHostCompletions; /* 0x28 */ + U32 FastPathFirmwareCompletions; /* 0x2C */ + U32 NonFastPathRequestStarts; /* 0x30 */ + U32 NonFastPathHostCompletions; /* 0x30 */ +} MPI2_CONFIG_PAGE_SASIOUNIT16, +MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT16, +Mpi2SasIOUnitPage16_t, MPI2_POINTER pMpi2SasIOUnitPage16_t; + +#define MPI2_SASIOUNITPAGE16_PAGEVERSION (0x00) + /**************************************************************************** * SAS Expander Config Pages diff --git a/trunk/drivers/scsi/mpt2sas/mpt2sas_base.c b/trunk/drivers/scsi/mpt2sas/mpt2sas_base.c index 8a59a772fdf2..6102ef2cb2d8 100644 --- a/trunk/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/trunk/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -699,6 +699,11 @@ _base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u16 ioc_status; mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); + if (unlikely(!mpi_reply)) { + printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return; + } ioc_status = le16_to_cpu(mpi_reply->IOCStatus); #ifdef CONFIG_SCSI_MPT2SAS_LOGGING if ((ioc_status & MPI2_IOCSTATUS_MASK) && @@ -930,16 +935,18 @@ _base_interrupt(int irq, void *bus_id) else if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS) goto next; - if (smid) + if (smid) { cb_idx = _base_get_cb_idx(ioc, smid); - if (smid && cb_idx != 0xFF) { - rc = mpt_callbacks[cb_idx](ioc, smid, msix_index, - reply); + if ((likely(cb_idx < MPT_MAX_CALLBACKS)) + && (likely(mpt_callbacks[cb_idx] != NULL))) { + rc = mpt_callbacks[cb_idx](ioc, smid, + msix_index, reply); if (reply) - _base_display_reply_info(ioc, smid, msix_index, - reply); + _base_display_reply_info(ioc, smid, + msix_index, reply); if (rc) mpt2sas_base_free_smid(ioc, smid); + } } if (!smid) _base_async_event(ioc, msix_index, reply); @@ -3343,7 +3350,7 @@ _base_get_port_facts(struct MPT2SAS_ADAPTER *ioc, int port, int sleep_flag) } pfacts = &ioc->pfacts[port]; - memset(pfacts, 0, sizeof(Mpi2PortFactsReply_t)); + memset(pfacts, 0, sizeof(struct mpt2sas_port_facts)); pfacts->PortNumber = mpi_reply.PortNumber; pfacts->VP_ID = mpi_reply.VP_ID; pfacts->VF_ID = mpi_reply.VF_ID; @@ -3385,7 +3392,7 @@ _base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) } facts = &ioc->facts; - memset(facts, 0, sizeof(Mpi2IOCFactsReply_t)); + memset(facts, 0, sizeof(struct mpt2sas_facts)); facts->MsgVersion = le16_to_cpu(mpi_reply.MsgVersion); facts->HeaderVersion = le16_to_cpu(mpi_reply.HeaderVersion); facts->VP_ID = mpi_reply.VP_ID; @@ -4153,7 +4160,8 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) if (ioc->is_driver_loading) { if (ioc->is_warpdrive && ioc->manu_pg10.OEMIdentifier == 0x80) { - hide_flag = (u8) (ioc->manu_pg10.OEMSpecificFlags0 & + hide_flag = (u8) ( + le32_to_cpu(ioc->manu_pg10.OEMSpecificFlags0) & MFG_PAGE10_HIDE_SSDS_MASK); if (hide_flag != MFG_PAGE10_HIDE_SSDS_MASK) ioc->mfg_pg10_hide_flag = hide_flag; @@ -4262,7 +4270,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) goto out_free_resources; ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts, - sizeof(Mpi2PortFactsReply_t), GFP_KERNEL); + sizeof(struct mpt2sas_port_facts), GFP_KERNEL); if (!ioc->pfacts) { r = -ENOMEM; goto out_free_resources; @@ -4279,7 +4287,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) goto out_free_resources; init_waitqueue_head(&ioc->reset_wq); - /* allocate memory pd handle bitmask list */ ioc->pd_handles_sz = (ioc->facts.MaxDevHandle / 8); if (ioc->facts.MaxDevHandle % 8) @@ -4290,7 +4297,12 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) r = -ENOMEM; goto out_free_resources; } - + ioc->blocking_handles = kzalloc(ioc->pd_handles_sz, + GFP_KERNEL); + if (!ioc->blocking_handles) { + r = -ENOMEM; + goto out_free_resources; + } ioc->fwfault_debug = mpt2sas_fwfault_debug; /* base internal command bits */ @@ -4377,6 +4389,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) if (ioc->is_warpdrive) kfree(ioc->reply_post_host_index); kfree(ioc->pd_handles); + kfree(ioc->blocking_handles); kfree(ioc->tm_cmds.reply); kfree(ioc->transport_cmds.reply); kfree(ioc->scsih_cmds.reply); @@ -4418,6 +4431,7 @@ mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc) if (ioc->is_warpdrive) kfree(ioc->reply_post_host_index); kfree(ioc->pd_handles); + kfree(ioc->blocking_handles); kfree(ioc->pfacts); kfree(ioc->ctl_cmds.reply); kfree(ioc->ctl_cmds.sense); diff --git a/trunk/drivers/scsi/mpt2sas/mpt2sas_base.h b/trunk/drivers/scsi/mpt2sas/mpt2sas_base.h index c7459fdc06cc..b6dd3a5de7f9 100644 --- a/trunk/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/trunk/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -69,8 +69,8 @@ #define MPT2SAS_DRIVER_NAME "mpt2sas" #define MPT2SAS_AUTHOR "LSI Corporation " #define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" -#define MPT2SAS_DRIVER_VERSION "12.100.00.00" -#define MPT2SAS_MAJOR_VERSION 12 +#define MPT2SAS_DRIVER_VERSION "13.100.00.00" +#define MPT2SAS_MAJOR_VERSION 13 #define MPT2SAS_MINOR_VERSION 100 #define MPT2SAS_BUILD_VERSION 00 #define MPT2SAS_RELEASE_VERSION 00 @@ -720,6 +720,7 @@ typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct MPT2SAS_ADAPTER *ioc); * @io_missing_delay: time for IO completed by fw when PDR enabled * @device_missing_delay: time for device missing by fw when PDR enabled * @sas_id : used for setting volume target IDs + * @blocking_handles: bitmask used to identify which devices need blocking * @pd_handles : bitmask for PD handles * @pd_handles_sz : size of pd_handle bitmask * @config_page_sz: config page size @@ -889,7 +890,7 @@ struct MPT2SAS_ADAPTER { u8 io_missing_delay; u16 device_missing_delay; int sas_id; - + void *blocking_handles; void *pd_handles; u16 pd_handles_sz; @@ -1058,7 +1059,8 @@ int mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle); void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle); void mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address); -void mpt2sas_device_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address); +void mpt2sas_device_remove_by_sas_address(struct MPT2SAS_ADAPTER *ioc, + u64 sas_address); struct _sas_node *mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle); struct _sas_node *mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER diff --git a/trunk/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/trunk/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 3b9a28efea82..49bdd2dc8452 100644 --- a/trunk/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/trunk/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -620,11 +620,10 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg, * @ioc: per adapter object * @karg - (struct mpt2_ioctl_command) * @mf - pointer to mf in user space - * @state - NON_BLOCKING or BLOCKING */ static long -_ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, - struct mpt2_ioctl_command karg, void __user *mf, enum block_state state) +_ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command karg, + void __user *mf) { MPI2RequestHeader_t *mpi_request = NULL, *request; MPI2DefaultReply_t *mpi_reply; @@ -647,11 +646,6 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, issue_reset = 0; - if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex)) - return -EAGAIN; - else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) - return -ERESTARTSYS; - if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) { printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n", ioc->name, __func__); @@ -871,8 +865,16 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, if (smp_request->PassthroughFlags & MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE) data = (u8 *)&smp_request->SGL; - else + else { + if (unlikely(data_out == NULL)) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + mpt2sas_base_free_smid(ioc, smid); + ret = -EINVAL; + goto out; + } data = data_out; + } if (data[1] == 0x91 && (data[10] == 1 || data[10] == 2)) { ioc->ioc_link_reset_in_progress = 1; @@ -985,7 +987,8 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, ret = -ENODATA; if ((mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || mpi_request->Function == - MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { + MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH || + mpi_request->Function == MPI2_FUNCTION_SATA_PASSTHROUGH)) { printk(MPT2SAS_INFO_FMT "issue target reset: handle " "= (0x%04x)\n", ioc->name, le16_to_cpu(mpi_request->FunctionDependent1)); @@ -1013,27 +1016,24 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, kfree(mpi_request); ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; - mutex_unlock(&ioc->ctl_cmds.mutex); return ret; } /** * _ctl_getiocinfo - main handler for MPT2IOCINFO opcode + * @ioc: per adapter object * @arg - user space buffer containing ioctl content */ static long -_ctl_getiocinfo(void __user *arg) +_ctl_getiocinfo(struct MPT2SAS_ADAPTER *ioc, void __user *arg) { struct mpt2_ioctl_iocinfo karg; - struct MPT2SAS_ADAPTER *ioc; if (copy_from_user(&karg, arg, sizeof(karg))) { printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); return -EFAULT; } - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, __func__)); @@ -1069,21 +1069,19 @@ _ctl_getiocinfo(void __user *arg) /** * _ctl_eventquery - main handler for MPT2EVENTQUERY opcode + * @ioc: per adapter object * @arg - user space buffer containing ioctl content */ static long -_ctl_eventquery(void __user *arg) +_ctl_eventquery(struct MPT2SAS_ADAPTER *ioc, void __user *arg) { struct mpt2_ioctl_eventquery karg; - struct MPT2SAS_ADAPTER *ioc; if (copy_from_user(&karg, arg, sizeof(karg))) { printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); return -EFAULT; } - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, __func__)); @@ -1102,21 +1100,19 @@ _ctl_eventquery(void __user *arg) /** * _ctl_eventenable - main handler for MPT2EVENTENABLE opcode + * @ioc: per adapter object * @arg - user space buffer containing ioctl content */ static long -_ctl_eventenable(void __user *arg) +_ctl_eventenable(struct MPT2SAS_ADAPTER *ioc, void __user *arg) { struct mpt2_ioctl_eventenable karg; - struct MPT2SAS_ADAPTER *ioc; if (copy_from_user(&karg, arg, sizeof(karg))) { printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); return -EFAULT; } - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, __func__)); @@ -1142,13 +1138,13 @@ _ctl_eventenable(void __user *arg) /** * _ctl_eventreport - main handler for MPT2EVENTREPORT opcode + * @ioc: per adapter object * @arg - user space buffer containing ioctl content */ static long -_ctl_eventreport(void __user *arg) +_ctl_eventreport(struct MPT2SAS_ADAPTER *ioc, void __user *arg) { struct mpt2_ioctl_eventreport karg; - struct MPT2SAS_ADAPTER *ioc; u32 number_bytes, max_events, max; struct mpt2_ioctl_eventreport __user *uarg = arg; @@ -1157,8 +1153,6 @@ _ctl_eventreport(void __user *arg) __FILE__, __LINE__, __func__); return -EFAULT; } - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, __func__)); @@ -1188,13 +1182,13 @@ _ctl_eventreport(void __user *arg) /** * _ctl_do_reset - main handler for MPT2HARDRESET opcode + * @ioc: per adapter object * @arg - user space buffer containing ioctl content */ static long -_ctl_do_reset(void __user *arg) +_ctl_do_reset(struct MPT2SAS_ADAPTER *ioc, void __user *arg) { struct mpt2_ioctl_diag_reset karg; - struct MPT2SAS_ADAPTER *ioc; int retval; if (copy_from_user(&karg, arg, sizeof(karg))) { @@ -1202,8 +1196,6 @@ _ctl_do_reset(void __user *arg) __FILE__, __LINE__, __func__); return -EFAULT; } - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; if (ioc->shost_recovery || ioc->pci_error_recovery || ioc->is_driver_loading) @@ -1292,13 +1284,13 @@ _ctl_btdh_search_raid_device(struct MPT2SAS_ADAPTER *ioc, /** * _ctl_btdh_mapping - main handler for MPT2BTDHMAPPING opcode + * @ioc: per adapter object * @arg - user space buffer containing ioctl content */ static long -_ctl_btdh_mapping(void __user *arg) +_ctl_btdh_mapping(struct MPT2SAS_ADAPTER *ioc, void __user *arg) { struct mpt2_ioctl_btdh_mapping karg; - struct MPT2SAS_ADAPTER *ioc; int rc; if (copy_from_user(&karg, arg, sizeof(karg))) { @@ -1306,8 +1298,6 @@ _ctl_btdh_mapping(void __user *arg) __FILE__, __LINE__, __func__); return -EFAULT; } - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); @@ -1576,17 +1566,16 @@ mpt2sas_enable_diag_buffer(struct MPT2SAS_ADAPTER *ioc, u8 bits_to_register) /** * _ctl_diag_register - application register with driver + * @ioc: per adapter object * @arg - user space buffer containing ioctl content - * @state - NON_BLOCKING or BLOCKING * * This will allow the driver to setup any required buffers that will be * needed by firmware to communicate with the driver. */ static long -_ctl_diag_register(void __user *arg, enum block_state state) +_ctl_diag_register(struct MPT2SAS_ADAPTER *ioc, void __user *arg) { struct mpt2_diag_register karg; - struct MPT2SAS_ADAPTER *ioc; long rc; if (copy_from_user(&karg, arg, sizeof(karg))) { @@ -1594,30 +1583,23 @@ _ctl_diag_register(void __user *arg, enum block_state state) __FILE__, __LINE__, __func__); return -EFAULT; } - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; - if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex)) - return -EAGAIN; - else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) - return -ERESTARTSYS; rc = _ctl_diag_register_2(ioc, &karg); - mutex_unlock(&ioc->ctl_cmds.mutex); return rc; } /** * _ctl_diag_unregister - application unregister with driver + * @ioc: per adapter object * @arg - user space buffer containing ioctl content * * This will allow the driver to cleanup any memory allocated for diag * messages and to free up any resources. */ static long -_ctl_diag_unregister(void __user *arg) +_ctl_diag_unregister(struct MPT2SAS_ADAPTER *ioc, void __user *arg) { struct mpt2_diag_unregister karg; - struct MPT2SAS_ADAPTER *ioc; void *request_data; dma_addr_t request_data_dma; u32 request_data_sz; @@ -1628,8 +1610,6 @@ _ctl_diag_unregister(void __user *arg) __FILE__, __LINE__, __func__); return -EFAULT; } - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); @@ -1678,6 +1658,7 @@ _ctl_diag_unregister(void __user *arg) /** * _ctl_diag_query - query relevant info associated with diag buffers + * @ioc: per adapter object * @arg - user space buffer containing ioctl content * * The application will send only buffer_type and unique_id. Driver will @@ -1685,10 +1666,9 @@ _ctl_diag_unregister(void __user *arg) * 0x00, the driver will return info specified by Buffer Type. */ static long -_ctl_diag_query(void __user *arg) +_ctl_diag_query(struct MPT2SAS_ADAPTER *ioc, void __user *arg) { struct mpt2_diag_query karg; - struct MPT2SAS_ADAPTER *ioc; void *request_data; int i; u8 buffer_type; @@ -1698,8 +1678,6 @@ _ctl_diag_query(void __user *arg) __FILE__, __LINE__, __func__); return -EFAULT; } - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); @@ -1866,17 +1844,15 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset) /** * _ctl_diag_release - request to send Diag Release Message to firmware * @arg - user space buffer containing ioctl content - * @state - NON_BLOCKING or BLOCKING * * This allows ownership of the specified buffer to returned to the driver, * allowing an application to read the buffer without fear that firmware is * overwritting information in the buffer. */ static long -_ctl_diag_release(void __user *arg, enum block_state state) +_ctl_diag_release(struct MPT2SAS_ADAPTER *ioc, void __user *arg) { struct mpt2_diag_release karg; - struct MPT2SAS_ADAPTER *ioc; void *request_data; int rc; u8 buffer_type; @@ -1887,8 +1863,6 @@ _ctl_diag_release(void __user *arg, enum block_state state) __FILE__, __LINE__, __func__); return -EFAULT; } - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); @@ -1942,32 +1916,25 @@ _ctl_diag_release(void __user *arg, enum block_state state) return 0; } - if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex)) - return -EAGAIN; - else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) - return -ERESTARTSYS; - rc = _ctl_send_release(ioc, buffer_type, &issue_reset); if (issue_reset) mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER); - mutex_unlock(&ioc->ctl_cmds.mutex); return rc; } /** * _ctl_diag_read_buffer - request for copy of the diag buffer + * @ioc: per adapter object * @arg - user space buffer containing ioctl content - * @state - NON_BLOCKING or BLOCKING */ static long -_ctl_diag_read_buffer(void __user *arg, enum block_state state) +_ctl_diag_read_buffer(struct MPT2SAS_ADAPTER *ioc, void __user *arg) { struct mpt2_diag_read_buffer karg; struct mpt2_diag_read_buffer __user *uarg = arg; - struct MPT2SAS_ADAPTER *ioc; void *request_data, *diag_data; Mpi2DiagBufferPostRequest_t *mpi_request; Mpi2DiagBufferPostReply_t *mpi_reply; @@ -1983,8 +1950,6 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state) __FILE__, __LINE__, __func__); return -EFAULT; } - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); @@ -2055,10 +2020,6 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state) } /* Get a free request frame and save the message context. */ - if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex)) - return -EAGAIN; - else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) - return -ERESTARTSYS; if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) { printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n", @@ -2139,115 +2100,170 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state) out: ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; - mutex_unlock(&ioc->ctl_cmds.mutex); return rc; } + +#ifdef CONFIG_COMPAT +/** + * _ctl_compat_mpt_command - convert 32bit pointers to 64bit. + * @ioc: per adapter object + * @cmd - ioctl opcode + * @arg - (struct mpt2_ioctl_command32) + * + * MPT2COMMAND32 - Handle 32bit applications running on 64bit os. + */ +static long +_ctl_compat_mpt_command(struct MPT2SAS_ADAPTER *ioc, unsigned cmd, + void __user *arg) +{ + struct mpt2_ioctl_command32 karg32; + struct mpt2_ioctl_command32 __user *uarg; + struct mpt2_ioctl_command karg; + + if (_IOC_SIZE(cmd) != sizeof(struct mpt2_ioctl_command32)) + return -EINVAL; + + uarg = (struct mpt2_ioctl_command32 __user *) arg; + + if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32))) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + return -EFAULT; + } + + memset(&karg, 0, sizeof(struct mpt2_ioctl_command)); + karg.hdr.ioc_number = karg32.hdr.ioc_number; + karg.hdr.port_number = karg32.hdr.port_number; + karg.hdr.max_data_size = karg32.hdr.max_data_size; + karg.timeout = karg32.timeout; + karg.max_reply_bytes = karg32.max_reply_bytes; + karg.data_in_size = karg32.data_in_size; + karg.data_out_size = karg32.data_out_size; + karg.max_sense_bytes = karg32.max_sense_bytes; + karg.data_sge_offset = karg32.data_sge_offset; + karg.reply_frame_buf_ptr = compat_ptr(karg32.reply_frame_buf_ptr); + karg.data_in_buf_ptr = compat_ptr(karg32.data_in_buf_ptr); + karg.data_out_buf_ptr = compat_ptr(karg32.data_out_buf_ptr); + karg.sense_data_ptr = compat_ptr(karg32.sense_data_ptr); + return _ctl_do_mpt_command(ioc, karg, &uarg->mf); +} +#endif + /** * _ctl_ioctl_main - main ioctl entry point * @file - (struct file) * @cmd - ioctl opcode * @arg - + * compat - handles 32 bit applications in 64bit os */ static long -_ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg) +_ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg, + u8 compat) { + struct MPT2SAS_ADAPTER *ioc; + struct mpt2_ioctl_header ioctl_header; enum block_state state; long ret = -EINVAL; - state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : - BLOCKING; + /* get IOCTL header */ + if (copy_from_user(&ioctl_header, (char __user *)arg, + sizeof(struct mpt2_ioctl_header))) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + return -EFAULT; + } + + if (_ctl_verify_adapter(ioctl_header.ioc_number, &ioc) == -1 || !ioc) + return -ENODEV; + if (ioc->shost_recovery || ioc->pci_error_recovery || + ioc->is_driver_loading) + return -EAGAIN; + + state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING; + if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex)) + return -EAGAIN; + else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) + return -ERESTARTSYS; switch (cmd) { case MPT2IOCINFO: if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_iocinfo)) - ret = _ctl_getiocinfo(arg); + ret = _ctl_getiocinfo(ioc, arg); break; +#ifdef CONFIG_COMPAT + case MPT2COMMAND32: +#endif case MPT2COMMAND: { - struct mpt2_ioctl_command karg; struct mpt2_ioctl_command __user *uarg; - struct MPT2SAS_ADAPTER *ioc; - + struct mpt2_ioctl_command karg; +#ifdef CONFIG_COMPAT + if (compat) { + ret = _ctl_compat_mpt_command(ioc, cmd, arg); + break; + } +#endif if (copy_from_user(&karg, arg, sizeof(karg))) { printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); - return -EFAULT; + ret = -EFAULT; + break; } - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || - !ioc) - return -ENODEV; - - if (ioc->shost_recovery || ioc->pci_error_recovery || - ioc->is_driver_loading) - return -EAGAIN; - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_command)) { uarg = arg; - ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf, state); + ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf); } break; } case MPT2EVENTQUERY: if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_eventquery)) - ret = _ctl_eventquery(arg); + ret = _ctl_eventquery(ioc, arg); break; case MPT2EVENTENABLE: if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_eventenable)) - ret = _ctl_eventenable(arg); + ret = _ctl_eventenable(ioc, arg); break; case MPT2EVENTREPORT: - ret = _ctl_eventreport(arg); + ret = _ctl_eventreport(ioc, arg); break; case MPT2HARDRESET: if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_diag_reset)) - ret = _ctl_do_reset(arg); + ret = _ctl_do_reset(ioc, arg); break; case MPT2BTDHMAPPING: if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_btdh_mapping)) - ret = _ctl_btdh_mapping(arg); + ret = _ctl_btdh_mapping(ioc, arg); break; case MPT2DIAGREGISTER: if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_register)) - ret = _ctl_diag_register(arg, state); + ret = _ctl_diag_register(ioc, arg); break; case MPT2DIAGUNREGISTER: if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_unregister)) - ret = _ctl_diag_unregister(arg); + ret = _ctl_diag_unregister(ioc, arg); break; case MPT2DIAGQUERY: if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_query)) - ret = _ctl_diag_query(arg); + ret = _ctl_diag_query(ioc, arg); break; case MPT2DIAGRELEASE: if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_release)) - ret = _ctl_diag_release(arg, state); + ret = _ctl_diag_release(ioc, arg); break; case MPT2DIAGREADBUFFER: if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_read_buffer)) - ret = _ctl_diag_read_buffer(arg, state); + ret = _ctl_diag_read_buffer(ioc, arg); break; default: - { - struct mpt2_ioctl_command karg; - struct MPT2SAS_ADAPTER *ioc; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || - !ioc) - return -ENODEV; dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "unsupported ioctl opcode(0x%08x)\n", ioc->name, cmd)); break; } - } + + mutex_unlock(&ioc->ctl_cmds.mutex); return ret; } @@ -2262,65 +2278,10 @@ _ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret; - mutex_lock(&_ctl_mutex); - ret = _ctl_ioctl_main(file, cmd, (void __user *)arg); - mutex_unlock(&_ctl_mutex); + ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0); return ret; } - #ifdef CONFIG_COMPAT -/** - * _ctl_compat_mpt_command - convert 32bit pointers to 64bit. - * @file - (struct file) - * @cmd - ioctl opcode - * @arg - (struct mpt2_ioctl_command32) - * - * MPT2COMMAND32 - Handle 32bit applications running on 64bit os. - */ -static long -_ctl_compat_mpt_command(struct file *file, unsigned cmd, unsigned long arg) -{ - struct mpt2_ioctl_command32 karg32; - struct mpt2_ioctl_command32 __user *uarg; - struct mpt2_ioctl_command karg; - struct MPT2SAS_ADAPTER *ioc; - enum block_state state; - - if (_IOC_SIZE(cmd) != sizeof(struct mpt2_ioctl_command32)) - return -EINVAL; - - uarg = (struct mpt2_ioctl_command32 __user *) arg; - - if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - if (_ctl_verify_adapter(karg32.hdr.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; - - if (ioc->shost_recovery || ioc->pci_error_recovery || - ioc->is_driver_loading) - return -EAGAIN; - - memset(&karg, 0, sizeof(struct mpt2_ioctl_command)); - karg.hdr.ioc_number = karg32.hdr.ioc_number; - karg.hdr.port_number = karg32.hdr.port_number; - karg.hdr.max_data_size = karg32.hdr.max_data_size; - karg.timeout = karg32.timeout; - karg.max_reply_bytes = karg32.max_reply_bytes; - karg.data_in_size = karg32.data_in_size; - karg.data_out_size = karg32.data_out_size; - karg.max_sense_bytes = karg32.max_sense_bytes; - karg.data_sge_offset = karg32.data_sge_offset; - karg.reply_frame_buf_ptr = compat_ptr(karg32.reply_frame_buf_ptr); - karg.data_in_buf_ptr = compat_ptr(karg32.data_in_buf_ptr); - karg.data_out_buf_ptr = compat_ptr(karg32.data_out_buf_ptr); - karg.sense_data_ptr = compat_ptr(karg32.sense_data_ptr); - state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING; - return _ctl_do_mpt_command(ioc, karg, &uarg->mf, state); -} - /** * _ctl_ioctl_compat - main ioctl entry point (compat) * @file - @@ -2334,12 +2295,7 @@ _ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg) { long ret; - mutex_lock(&_ctl_mutex); - if (cmd == MPT2COMMAND32) - ret = _ctl_compat_mpt_command(file, cmd, arg); - else - ret = _ctl_ioctl_main(file, cmd, (void __user *)arg); - mutex_unlock(&_ctl_mutex); + ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1); return ret; } #endif @@ -2884,7 +2840,7 @@ _ctl_host_trace_buffer_enable_store(struct device *cdev, struct mpt2_diag_register diag_register; u8 issue_reset = 0; - if (sscanf(buf, "%s", str) != 1) + if (sscanf(buf, "%9s", str) != 1) return -EINVAL; if (!strcmp(str, "post")) { diff --git a/trunk/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/trunk/drivers/scsi/mpt2sas/mpt2sas_scsih.c index d953a57e779d..76973e8ca4ba 100644 --- a/trunk/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/trunk/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -579,14 +579,12 @@ _scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc, return; spin_lock_irqsave(&ioc->sas_device_lock, flags); - if (mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - sas_device->sas_address)) { - list_del(&sas_device->list); - kfree(sas_device); - } + list_del(&sas_device->list); + kfree(sas_device); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } + /** * _scsih_sas_device_add - insert sas_device to the list. * @ioc: per adapter object @@ -645,8 +643,8 @@ _scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc, spin_lock_irqsave(&ioc->sas_device_lock, flags); list_add_tail(&sas_device->list, &ioc->sas_device_init_list); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); _scsih_determine_boot_device(ioc, sas_device, 0); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } /** @@ -755,7 +753,6 @@ _scsih_raid_device_add(struct MPT2SAS_ADAPTER *ioc, * @ioc: per adapter object * @raid_device: raid_device object * - * This is removed from the raid_device_list link list. */ static void _scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc, @@ -765,7 +762,6 @@ _scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc, spin_lock_irqsave(&ioc->raid_device_lock, flags); list_del(&raid_device->list); - memset(raid_device, 0, sizeof(struct _raid_device)); kfree(raid_device); spin_unlock_irqrestore(&ioc->raid_device_lock, flags); } @@ -1199,10 +1195,10 @@ _scsih_adjust_queue_depth(struct scsi_device *sdev, int qdepth) spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, sas_device_priv_data->sas_target->sas_address); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); if (sas_device && sas_device->device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) max_depth = MPT2SAS_SATA_QUEUE_DEPTH; + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); not_sata: @@ -1299,7 +1295,8 @@ _scsih_target_alloc(struct scsi_target *starget) sas_target_priv_data->handle = raid_device->handle; sas_target_priv_data->sas_address = raid_device->wwid; sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME; - sas_target_priv_data->raid_device = raid_device; + if (ioc->is_warpdrive) + sas_target_priv_data->raid_device = raid_device; raid_device->starget = starget; } spin_unlock_irqrestore(&ioc->raid_device_lock, flags); @@ -1465,12 +1462,12 @@ _scsih_slave_destroy(struct scsi_device *sdev) /** * _scsih_display_sata_capabilities - sata capabilities * @ioc: per adapter object - * @sas_device: the sas_device object + * @handle: device handle * @sdev: scsi device struct */ static void _scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc, - struct _sas_device *sas_device, struct scsi_device *sdev) + u16 handle, struct scsi_device *sdev) { Mpi2ConfigReply_t mpi_reply; Mpi2SasDevicePage0_t sas_device_pg0; @@ -1479,7 +1476,7 @@ _scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc, u32 device_info; if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, - MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, sas_device->handle))) { + MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); return; @@ -1537,27 +1534,40 @@ _scsih_get_resync(struct device *dev) Mpi2RaidVolPage0_t vol_pg0; Mpi2ConfigReply_t mpi_reply; u32 volume_status_flags; - u8 percent_complete = 0; + u8 percent_complete; + u16 handle; + + percent_complete = 0; + handle = 0; + if (ioc->is_warpdrive) + goto out; spin_lock_irqsave(&ioc->raid_device_lock, flags); raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id, sdev->channel); + if (raid_device) { + handle = raid_device->handle; + percent_complete = raid_device->percent_complete; + } spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - if (!raid_device || ioc->is_warpdrive) + if (!handle) goto out; if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0, - MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, + MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, sizeof(Mpi2RaidVolPage0_t))) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); + percent_complete = 0; goto out; } volume_status_flags = le32_to_cpu(vol_pg0.VolumeStatusFlags); - if (volume_status_flags & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) - percent_complete = raid_device->percent_complete; + if (!(volume_status_flags & + MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS)) + percent_complete = 0; + out: raid_set_resync(mpt2sas_raid_template, dev, percent_complete); } @@ -1577,17 +1587,20 @@ _scsih_get_state(struct device *dev) Mpi2ConfigReply_t mpi_reply; u32 volstate; enum raid_state state = RAID_STATE_UNKNOWN; + u16 handle = 0; spin_lock_irqsave(&ioc->raid_device_lock, flags); raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id, sdev->channel); + if (raid_device) + handle = raid_device->handle; spin_unlock_irqrestore(&ioc->raid_device_lock, flags); if (!raid_device) goto out; if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0, - MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, + MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, sizeof(Mpi2RaidVolPage0_t))) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); @@ -1620,14 +1633,14 @@ _scsih_get_state(struct device *dev) /** * _scsih_set_level - set raid level * @sdev: scsi device struct - * @raid_device: raid_device object + * @volume_type: volume type */ static void -_scsih_set_level(struct scsi_device *sdev, struct _raid_device *raid_device) +_scsih_set_level(struct scsi_device *sdev, u8 volume_type) { enum raid_level level = RAID_LEVEL_UNKNOWN; - switch (raid_device->volume_type) { + switch (volume_type) { case MPI2_RAID_VOL_TYPE_RAID0: level = RAID_LEVEL_0; break; @@ -1722,6 +1735,7 @@ _scsih_disable_ddio(struct MPT2SAS_ADAPTER *ioc) struct _raid_device *raid_device; u16 handle; u16 ioc_status; + unsigned long flags; handle = 0xFFFF; while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, @@ -1731,9 +1745,11 @@ _scsih_disable_ddio(struct MPT2SAS_ADAPTER *ioc) if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) break; handle = le16_to_cpu(vol_pg1.DevHandle); + spin_lock_irqsave(&ioc->raid_device_lock, flags); raid_device = _scsih_raid_device_find_by_handle(ioc, handle); if (raid_device) raid_device->direct_io_enabled = 0; + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); } return; } @@ -1838,7 +1854,8 @@ _scsih_init_warpdrive_properties(struct MPT2SAS_ADAPTER *ioc, if (mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM, vol_pg0->PhysDisk[count].PhysDiskNum) || - pd_pg0.DevHandle == MPT2SAS_INVALID_DEVICE_HANDLE) { + le16_to_cpu(pd_pg0.DevHandle) == + MPT2SAS_INVALID_DEVICE_HANDLE) { printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is " "disabled for the drive with handle(0x%04x) member" "handle retrieval failed for member number=%d\n", @@ -1968,19 +1985,21 @@ _scsih_slave_configure(struct scsi_device *sdev) u8 ssp_target = 0; char *ds = ""; char *r_level = ""; + u16 handle, volume_handle = 0; + u64 volume_wwid = 0; qdepth = 1; sas_device_priv_data = sdev->hostdata; sas_device_priv_data->configured_lun = 1; sas_device_priv_data->flags &= ~MPT_DEVICE_FLAGS_INIT; sas_target_priv_data = sas_device_priv_data->sas_target; + handle = sas_target_priv_data->handle; /* raid volume handling */ if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) { spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_handle(ioc, - sas_target_priv_data->handle); + raid_device = _scsih_raid_device_find_by_handle(ioc, handle); spin_unlock_irqrestore(&ioc->raid_device_lock, flags); if (!raid_device) { dfailprintk(ioc, printk(MPT2SAS_WARN_FMT @@ -1989,8 +2008,6 @@ _scsih_slave_configure(struct scsi_device *sdev) return 1; } - _scsih_get_volume_capabilities(ioc, raid_device); - if (_scsih_get_volume_capabilities(ioc, raid_device)) { dfailprintk(ioc, printk(MPT2SAS_WARN_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, @@ -2058,68 +2075,67 @@ _scsih_slave_configure(struct scsi_device *sdev) _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT); /* raid transport support */ if (!ioc->is_warpdrive) - _scsih_set_level(sdev, raid_device); + _scsih_set_level(sdev, raid_device->volume_type); return 0; } /* non-raid handling */ - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - sas_device_priv_data->sas_target->sas_address); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (sas_device) { - if (sas_target_priv_data->flags & - MPT_TARGET_FLAGS_RAID_COMPONENT) { - if (mpt2sas_config_get_volume_handle(ioc, - sas_device->handle, &sas_device->volume_handle)) { - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__)); - return 1; - } - if (sas_device->volume_handle && - mpt2sas_config_get_volume_wwid(ioc, - sas_device->volume_handle, - &sas_device->volume_wwid)) { - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__)); - return 1; - } + if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) { + if (mpt2sas_config_get_volume_handle(ioc, handle, + &volume_handle)) { + dfailprintk(ioc, printk(MPT2SAS_WARN_FMT + "failure at %s:%d/%s()!\n", ioc->name, + __FILE__, __LINE__, __func__)); + return 1; } - if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) { - qdepth = MPT2SAS_SAS_QUEUE_DEPTH; - ssp_target = 1; - ds = "SSP"; - } else { - qdepth = MPT2SAS_SATA_QUEUE_DEPTH; - if (sas_device->device_info & - MPI2_SAS_DEVICE_INFO_STP_TARGET) - ds = "STP"; - else if (sas_device->device_info & - MPI2_SAS_DEVICE_INFO_SATA_DEVICE) - ds = "SATA"; + if (volume_handle && mpt2sas_config_get_volume_wwid(ioc, + volume_handle, &volume_wwid)) { + dfailprintk(ioc, printk(MPT2SAS_WARN_FMT + "failure at %s:%d/%s()!\n", ioc->name, + __FILE__, __LINE__, __func__)); + return 1; } + } - sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), " - "sas_addr(0x%016llx), phy(%d), device_name(0x%016llx)\n", - ds, sas_device->handle, - (unsigned long long)sas_device->sas_address, - sas_device->phy, - (unsigned long long)sas_device->device_name); - sdev_printk(KERN_INFO, sdev, "%s: " - "enclosure_logical_id(0x%016llx), slot(%d)\n", ds, - (unsigned long long) sas_device->enclosure_logical_id, - sas_device->slot); - - if (!ssp_target) - _scsih_display_sata_capabilities(ioc, sas_device, sdev); - } else { + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device_priv_data->sas_target->sas_address); + if (!sas_device) { + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, - __func__)); + "failure at %s:%d/%s()!\n", ioc->name, __FILE__, + __LINE__, __func__)); return 1; } + sas_device->volume_handle = volume_handle; + sas_device->volume_wwid = volume_wwid; + if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) { + qdepth = MPT2SAS_SAS_QUEUE_DEPTH; + ssp_target = 1; + ds = "SSP"; + } else { + qdepth = MPT2SAS_SATA_QUEUE_DEPTH; + if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) + ds = "STP"; + else if (sas_device->device_info & + MPI2_SAS_DEVICE_INFO_SATA_DEVICE) + ds = "SATA"; + } + sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), " + "sas_addr(0x%016llx), phy(%d), device_name(0x%016llx)\n", + ds, sas_device->handle, + (unsigned long long)sas_device->sas_address, + sas_device->phy, + (unsigned long long)sas_device->device_name); + sdev_printk(KERN_INFO, sdev, "%s: " + "enclosure_logical_id(0x%016llx), slot(%d)\n", ds, + (unsigned long long) sas_device->enclosure_logical_id, + sas_device->slot); + + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + if (!ssp_target) + _scsih_display_sata_capabilities(ioc, handle, sdev); + _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT); @@ -2899,7 +2915,7 @@ _scsih_ublock_io_all_device(struct MPT2SAS_ADAPTER *ioc) * During device pull we need to appropiately set the sdev state. */ static void -_scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) +_scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address) { struct MPT2SAS_DEVICE *sas_device_priv_data; struct scsi_device *sdev; @@ -2910,10 +2926,12 @@ _scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) continue; if (!sas_device_priv_data->block) continue; - if (sas_device_priv_data->sas_target->handle == handle) { + if (sas_device_priv_data->sas_target->sas_address == + sas_address) { dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, MPT2SAS_INFO_FMT "SDEV_RUNNING: " - "handle(0x%04x)\n", ioc->name, handle)); + "sas address(0x%016llx)\n", ioc->name, + (unsigned long long)sas_address)); sas_device_priv_data->block = 0; scsi_internal_device_unblock(sdev); } @@ -3006,10 +3024,10 @@ _scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc, sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, mpt2sas_port->remote_identify.sas_address); + if (sas_device) + set_bit(sas_device->handle, + ioc->blocking_handles); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (!sas_device) - continue; - _scsih_block_io_device(ioc, sas_device->handle); } } @@ -3020,12 +3038,9 @@ _scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc, SAS_EDGE_EXPANDER_DEVICE || mpt2sas_port->remote_identify.device_type == SAS_FANOUT_EXPANDER_DEVICE) { - - spin_lock_irqsave(&ioc->sas_node_lock, flags); expander_sibling = mpt2sas_scsih_expander_find_by_sas_address( ioc, mpt2sas_port->remote_identify.sas_address); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); _scsih_block_io_to_children_attached_to_ex(ioc, expander_sibling); } @@ -3124,7 +3139,7 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "setting delete flag: " "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, handle, (unsigned long long)sas_address)); - _scsih_ublock_io_device(ioc, handle); + _scsih_ublock_io_device(ioc, sas_address); sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE; } @@ -3174,16 +3189,19 @@ static u8 _scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) { -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING Mpi2SasIoUnitControlReply_t *mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -#endif - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "sc_complete:handle(0x%04x), (open) " - "smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply->DevHandle), smid, - le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo))); + if (likely(mpi_reply)) { + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT + "sc_complete:handle(0x%04x), (open) " + "smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n", + ioc->name, le16_to_cpu(mpi_reply->DevHandle), smid, + le16_to_cpu(mpi_reply->IOCStatus), + le32_to_cpu(mpi_reply->IOCLogInfo))); + } else { + printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + } return 1; } @@ -3262,7 +3280,11 @@ _scsih_tm_volume_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, "progress!\n", __func__, ioc->name)); return 1; } - + if (unlikely(!mpi_reply)) { + printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return 1; + } mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid); handle = le16_to_cpu(mpi_request_tm->DevHandle); if (handle != le16_to_cpu(mpi_reply->DevHandle)) { @@ -3325,7 +3347,11 @@ _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, "operational\n", __func__, ioc->name)); return 1; } - + if (unlikely(!mpi_reply)) { + printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return 1; + } mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid); handle = le16_to_cpu(mpi_request_tm->DevHandle); if (handle != le16_to_cpu(mpi_reply->DevHandle)) { @@ -3441,14 +3467,20 @@ _scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc, _scsih_block_io_to_children_attached_directly(ioc, event_data); return; } - - if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING - || event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) { + if (event_data->ExpStatus == + MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING) { + /* put expander attached devices into blocking state */ spin_lock_irqsave(&ioc->sas_node_lock, flags); sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, expander_handle); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); _scsih_block_io_to_children_attached_to_ex(ioc, sas_expander); + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + do { + handle = find_first_bit(ioc->blocking_handles, + ioc->facts.MaxDevHandle); + if (handle < ioc->facts.MaxDevHandle) + _scsih_block_io_device(ioc, handle); + } while (test_and_clear_bit(handle, ioc->blocking_handles)); } else if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_RESPONDING) _scsih_block_io_to_children_attached_directly(ioc, event_data); @@ -4446,8 +4478,8 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) != MPI2_IOCSTATUS_SCSI_TASK_TERMINATED)) { spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); ioc->scsi_lookup[smid - 1].scmd = scmd; - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); _scsih_scsi_direct_io_set(ioc, smid, 0); + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len); mpi_request->DevHandle = cpu_to_le16(sas_device_priv_data->sas_target->handle); @@ -5020,13 +5052,11 @@ mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address) spin_lock_irqsave(&ioc->sas_node_lock, flags); sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc, sas_address); - if (!sas_expander) { - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - return; - } - list_del(&sas_expander->list); + if (sas_expander) + list_del(&sas_expander->list); spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - _scsih_expander_node_remove(ioc, sas_expander); + if (sas_expander) + _scsih_expander_node_remove(ioc, sas_expander); } /** @@ -5106,6 +5136,7 @@ _scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) struct MPT2SAS_TARGET *sas_target_priv_data; u32 device_info; + if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) return; @@ -5139,21 +5170,24 @@ _scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) sas_target_priv_data->handle = handle; sas_device->handle = handle; } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); /* check if device is present */ if (!(le16_to_cpu(sas_device_pg0.Flags) & MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) { printk(MPT2SAS_ERR_FMT "device is not present " "handle(0x%04x), flags!!!\n", ioc->name, handle); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); return; } /* check if there were any issues with discovery */ if (_scsih_check_access_status(ioc, sas_address, handle, - sas_device_pg0.AccessStatus)) + sas_device_pg0.AccessStatus)) { + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); return; - _scsih_ublock_io_device(ioc, handle); + } + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + _scsih_ublock_io_device(ioc, sas_address); } @@ -5280,54 +5314,71 @@ static void _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device *sas_device) { - struct _sas_device sas_device_backup; struct MPT2SAS_TARGET *sas_target_priv_data; - if (!sas_device) - return; - - memcpy(&sas_device_backup, sas_device, sizeof(struct _sas_device)); - _scsih_sas_device_remove(ioc, sas_device); - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: " "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, - sas_device_backup.handle, (unsigned long long) - sas_device_backup.sas_address)); + sas_device->handle, (unsigned long long) + sas_device->sas_address)); - if (sas_device_backup.starget && sas_device_backup.starget->hostdata) { - sas_target_priv_data = sas_device_backup.starget->hostdata; + if (sas_device->starget && sas_device->starget->hostdata) { + sas_target_priv_data = sas_device->starget->hostdata; sas_target_priv_data->deleted = 1; - _scsih_ublock_io_device(ioc, sas_device_backup.handle); + _scsih_ublock_io_device(ioc, sas_device->sas_address); sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE; } - _scsih_ublock_io_device(ioc, sas_device_backup.handle); - if (!ioc->hide_drives) mpt2sas_transport_port_remove(ioc, - sas_device_backup.sas_address, - sas_device_backup.sas_address_parent); + sas_device->sas_address, + sas_device->sas_address_parent); printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr" - "(0x%016llx)\n", ioc->name, sas_device_backup.handle, - (unsigned long long) sas_device_backup.sas_address); + "(0x%016llx)\n", ioc->name, sas_device->handle, + (unsigned long long) sas_device->sas_address); dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: " "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, - sas_device_backup.handle, (unsigned long long) - sas_device_backup.sas_address)); + sas_device->handle, (unsigned long long) + sas_device->sas_address)); + kfree(sas_device); +} +/** + * _scsih_device_remove_by_handle - removing device object by handle + * @ioc: per adapter object + * @handle: device handle + * + * Return nothing. + */ +static void +_scsih_device_remove_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ + struct _sas_device *sas_device; + unsigned long flags; + + if (ioc->shost_recovery) + return; + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + if (sas_device) + list_del(&sas_device->list); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + if (sas_device) + _scsih_remove_device(ioc, sas_device); } /** - * mpt2sas_device_remove - removing device object + * mpt2sas_device_remove_by_sas_address - removing device object by sas address * @ioc: per adapter object - * @sas_address: expander sas_address + * @sas_address: device sas_address * * Return nothing. */ void -mpt2sas_device_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address) +mpt2sas_device_remove_by_sas_address(struct MPT2SAS_ADAPTER *ioc, + u64 sas_address) { struct _sas_device *sas_device; unsigned long flags; @@ -5338,14 +5389,12 @@ mpt2sas_device_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address) spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, sas_address); - if (!sas_device) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return; - } + if (sas_device) + list_del(&sas_device->list); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - _scsih_remove_device(ioc, sas_device); + if (sas_device) + _scsih_remove_device(ioc, sas_device); } - #ifdef CONFIG_SCSI_MPT2SAS_LOGGING /** * _scsih_sas_topology_change_event_debug - debug for topology event @@ -5442,7 +5491,6 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, u16 reason_code; u8 phy_number, max_phys; struct _sas_node *sas_expander; - struct _sas_device *sas_device; u64 sas_address; unsigned long flags; u8 link_rate, prev_link_rate; @@ -5477,15 +5525,17 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, spin_lock_irqsave(&ioc->sas_node_lock, flags); sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, parent_handle); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); if (sas_expander) { sas_address = sas_expander->sas_address; max_phys = sas_expander->num_phys; } else if (parent_handle < ioc->sas_hba.num_phys) { sas_address = ioc->sas_hba.sas_address; max_phys = ioc->sas_hba.num_phys; - } else + } else { + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); return; + } + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); /* handle siblings events */ for (i = 0; i < event_data->NumEntries; i++) { @@ -5540,16 +5590,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, break; case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, - handle); - if (!sas_device) { - spin_unlock_irqrestore(&ioc->sas_device_lock, - flags); - break; - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - _scsih_remove_device(ioc, sas_device); + _scsih_device_remove_by_handle(ioc, handle); break; } } @@ -5672,20 +5713,24 @@ _scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc, sas_address = le64_to_cpu(event_data->SASAddress); sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, sas_address); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (!sas_device || !sas_device->starget) + if (!sas_device || !sas_device->starget) { + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); return; + } target_priv_data = sas_device->starget->hostdata; - if (!target_priv_data) + if (!target_priv_data) { + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); return; + } if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET) target_priv_data->tm_busy = 1; else target_priv_data->tm_busy = 0; + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } #ifdef CONFIG_SCSI_MPT2SAS_LOGGING @@ -5949,30 +5994,6 @@ _scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach) rc = scsi_device_reprobe(sdev); } -/** - * _scsih_reprobe_target - reprobing target - * @starget: scsi target struct - * @no_uld_attach: sdev->no_uld_attach flag setting - * - * Note: no_uld_attach flag determines whether the disk device is attached - * to block layer. A value of `1` means to not attach. - **/ -static void -_scsih_reprobe_target(struct scsi_target *starget, int no_uld_attach) -{ - struct MPT2SAS_TARGET *sas_target_priv_data; - - if (starget == NULL) - return; - sas_target_priv_data = starget->hostdata; - if (no_uld_attach) - sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT; - else - sas_target_priv_data->flags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT; - - starget_for_each_device(starget, no_uld_attach ? (void *)1 : NULL, - _scsih_reprobe_lun); -} /** * _scsih_sas_volume_add - add new volume * @ioc: per adapter object @@ -6024,8 +6045,11 @@ _scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc, raid_device->id, 0); if (rc) _scsih_raid_device_remove(ioc, raid_device); - } else + } else { + spin_lock_irqsave(&ioc->raid_device_lock, flags); _scsih_determine_boot_device(ioc, raid_device, 1); + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); + } } /** @@ -6042,21 +6066,25 @@ _scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc, u16 handle) struct _raid_device *raid_device; unsigned long flags; struct MPT2SAS_TARGET *sas_target_priv_data; + struct scsi_target *starget = NULL; spin_lock_irqsave(&ioc->raid_device_lock, flags); raid_device = _scsih_raid_device_find_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - if (!raid_device) - return; - if (raid_device->starget) { - sas_target_priv_data = raid_device->starget->hostdata; - sas_target_priv_data->deleted = 1; - scsi_remove_target(&raid_device->starget->dev); + if (raid_device) { + if (raid_device->starget) { + starget = raid_device->starget; + sas_target_priv_data = starget->hostdata; + sas_target_priv_data->deleted = 1; + } + printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid" + "(0x%016llx)\n", ioc->name, raid_device->handle, + (unsigned long long) raid_device->wwid); + list_del(&raid_device->list); + kfree(raid_device); } - printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid" - "(0x%016llx)\n", ioc->name, raid_device->handle, - (unsigned long long) raid_device->wwid); - _scsih_raid_device_remove(ioc, raid_device); + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); + if (starget) + scsi_remove_target(&starget->dev); } /** @@ -6072,20 +6100,31 @@ _scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc, Mpi2EventIrConfigElement_t *element) { struct _sas_device *sas_device; + struct scsi_target *starget = NULL; + struct MPT2SAS_TARGET *sas_target_priv_data; unsigned long flags; u16 handle = le16_to_cpu(element->PhysDiskDevHandle); spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + if (sas_device) { + sas_device->volume_handle = 0; + sas_device->volume_wwid = 0; + clear_bit(handle, ioc->pd_handles); + if (sas_device->starget && sas_device->starget->hostdata) { + starget = sas_device->starget; + sas_target_priv_data = starget->hostdata; + sas_target_priv_data->flags &= + ~MPT_TARGET_FLAGS_RAID_COMPONENT; + } + } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); if (!sas_device) return; /* exposing raid component */ - sas_device->volume_handle = 0; - sas_device->volume_wwid = 0; - clear_bit(handle, ioc->pd_handles); - _scsih_reprobe_target(sas_device->starget, 0); + if (starget) + starget_for_each_device(starget, NULL, _scsih_reprobe_lun); } /** @@ -6101,23 +6140,38 @@ _scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc, Mpi2EventIrConfigElement_t *element) { struct _sas_device *sas_device; + struct scsi_target *starget = NULL; + struct MPT2SAS_TARGET *sas_target_priv_data; unsigned long flags; u16 handle = le16_to_cpu(element->PhysDiskDevHandle); + u16 volume_handle = 0; + u64 volume_wwid = 0; + + mpt2sas_config_get_volume_handle(ioc, handle, &volume_handle); + if (volume_handle) + mpt2sas_config_get_volume_wwid(ioc, volume_handle, + &volume_wwid); spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + if (sas_device) { + set_bit(handle, ioc->pd_handles); + if (sas_device->starget && sas_device->starget->hostdata) { + starget = sas_device->starget; + sas_target_priv_data = starget->hostdata; + sas_target_priv_data->flags |= + MPT_TARGET_FLAGS_RAID_COMPONENT; + sas_device->volume_handle = volume_handle; + sas_device->volume_wwid = volume_wwid; + } + } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); if (!sas_device) return; /* hiding raid component */ - mpt2sas_config_get_volume_handle(ioc, handle, - &sas_device->volume_handle); - mpt2sas_config_get_volume_wwid(ioc, sas_device->volume_handle, - &sas_device->volume_wwid); - set_bit(handle, ioc->pd_handles); - _scsih_reprobe_target(sas_device->starget, 1); - + if (starget) + starget_for_each_device(starget, (void *)1, _scsih_reprobe_lun); } /** @@ -6132,16 +6186,9 @@ static void _scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc, Mpi2EventIrConfigElement_t *element) { - struct _sas_device *sas_device; - unsigned long flags; u16 handle = le16_to_cpu(element->PhysDiskDevHandle); - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (!sas_device) - return; - _scsih_remove_device(ioc, sas_device); + _scsih_device_remove_by_handle(ioc, handle); } /** @@ -6583,18 +6630,13 @@ _scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc, /* code added for raid transport support */ if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) { - handle = le16_to_cpu(event_data->VolDevHandle); - spin_lock_irqsave(&ioc->raid_device_lock, flags); + handle = le16_to_cpu(event_data->VolDevHandle); raid_device = _scsih_raid_device_find_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - - if (!raid_device) - return; - - if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) + if (raid_device) raid_device->percent_complete = event_data->PercentComplete; + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); } } @@ -6761,13 +6803,18 @@ _scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid, * required data for Direct IO */ _scsih_init_warpdrive_properties(ioc, raid_device); - if (raid_device->handle == handle) + spin_lock_irqsave(&ioc->raid_device_lock, flags); + if (raid_device->handle == handle) { + spin_unlock_irqrestore(&ioc->raid_device_lock, + flags); return; + } printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n", raid_device->handle); raid_device->handle = handle; if (sas_target_priv_data) sas_target_priv_data->handle = handle; + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); return; } } @@ -6939,58 +6986,56 @@ static void _scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc) { struct _sas_device *sas_device, *sas_device_next; - struct _sas_node *sas_expander; + struct _sas_node *sas_expander, *sas_expander_next; struct _raid_device *raid_device, *raid_device_next; + struct list_head tmp_list; + unsigned long flags; printk(MPT2SAS_INFO_FMT "removing unresponding devices: start\n", ioc->name); + /* removing unresponding end devices */ + printk(MPT2SAS_INFO_FMT "removing unresponding devices: end-devices\n", + ioc->name); list_for_each_entry_safe(sas_device, sas_device_next, &ioc->sas_device_list, list) { - if (sas_device->responding) { + if (!sas_device->responding) + mpt2sas_device_remove_by_sas_address(ioc, + sas_device->sas_address); + else sas_device->responding = 0; - continue; - } - if (sas_device->starget) - starget_printk(KERN_INFO, sas_device->starget, - "removing: handle(0x%04x), sas_addr(0x%016llx), " - "enclosure logical id(0x%016llx), slot(%d)\n", - sas_device->handle, - (unsigned long long)sas_device->sas_address, - (unsigned long long) - sas_device->enclosure_logical_id, - sas_device->slot); - _scsih_remove_device(ioc, sas_device); } - if (!ioc->ir_firmware) - goto retry_expander_search; - - list_for_each_entry_safe(raid_device, raid_device_next, - &ioc->raid_device_list, list) { - if (raid_device->responding) { - raid_device->responding = 0; - continue; - } - if (raid_device->starget) { - starget_printk(KERN_INFO, raid_device->starget, - "removing: handle(0x%04x), wwid(0x%016llx)\n", - raid_device->handle, - (unsigned long long)raid_device->wwid); - scsi_remove_target(&raid_device->starget->dev); + /* removing unresponding volumes */ + if (ioc->ir_firmware) { + printk(MPT2SAS_INFO_FMT "removing unresponding devices: " + "volumes\n", ioc->name); + list_for_each_entry_safe(raid_device, raid_device_next, + &ioc->raid_device_list, list) { + if (!raid_device->responding) + _scsih_sas_volume_delete(ioc, + raid_device->handle); + else + raid_device->responding = 0; } - _scsih_raid_device_remove(ioc, raid_device); } - - retry_expander_search: - sas_expander = NULL; - list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { - if (sas_expander->responding) { + /* removing unresponding expanders */ + printk(MPT2SAS_INFO_FMT "removing unresponding devices: expanders\n", + ioc->name); + spin_lock_irqsave(&ioc->sas_node_lock, flags); + INIT_LIST_HEAD(&tmp_list); + list_for_each_entry_safe(sas_expander, sas_expander_next, + &ioc->sas_expander_list, list) { + if (!sas_expander->responding) + list_move_tail(&sas_expander->list, &tmp_list); + else sas_expander->responding = 0; - continue; - } - mpt2sas_expander_remove(ioc, sas_expander->sas_address); - goto retry_expander_search; + } + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + list_for_each_entry_safe(sas_expander, sas_expander_next, &tmp_list, + list) { + list_del(&sas_expander->list); + _scsih_expander_node_remove(ioc, sas_expander); } printk(MPT2SAS_INFO_FMT "removing unresponding devices: complete\n", ioc->name); @@ -7043,6 +7088,7 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc) struct _sas_device *sas_device; struct _sas_node *expander_device; static struct _raid_device *raid_device; + unsigned long flags; printk(MPT2SAS_INFO_FMT "scan devices: start\n", ioc->name); @@ -7057,8 +7103,10 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc) if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) break; handle = le16_to_cpu(expander_pg0.DevHandle); + spin_lock_irqsave(&ioc->sas_node_lock, flags); expander_device = mpt2sas_scsih_expander_find_by_sas_address( ioc, le64_to_cpu(expander_pg0.SASAddress)); + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); if (expander_device) _scsih_refresh_expander_links(ioc, expander_device, handle); @@ -7080,7 +7128,9 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc) break; phys_disk_num = pd_pg0.PhysDiskNum; handle = le16_to_cpu(pd_pg0.DevHandle); + spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); if (sas_device) continue; if (mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, @@ -7107,8 +7157,10 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc) if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) break; handle = le16_to_cpu(volume_pg1.DevHandle); + spin_lock_irqsave(&ioc->raid_device_lock, flags); raid_device = _scsih_raid_device_find_by_wwid(ioc, le64_to_cpu(volume_pg1.WWID)); + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); if (raid_device) continue; if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, @@ -7140,8 +7192,10 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc) if (!(_scsih_is_end_device( le32_to_cpu(sas_device_pg0.DeviceInfo)))) continue; + spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, le64_to_cpu(sas_device_pg0.SASAddress)); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); if (sas_device) continue; parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); @@ -7235,7 +7289,7 @@ _firmware_event_work(struct work_struct *work) switch (fw_event->event) { case MPT2SAS_REMOVE_UNRESPONDING_DEVICES: - while (scsi_host_in_recovery(ioc->shost)) + while (scsi_host_in_recovery(ioc->shost) || ioc->shost_recovery) ssleep(1); _scsih_remove_unresponding_sas_devices(ioc); _scsih_scan_for_devices_after_reset(ioc); @@ -7313,6 +7367,13 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, return 1; mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); + + if (unlikely(!mpi_reply)) { + printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return 1; + } + event = le16_to_cpu(mpi_reply->Event); switch (event) { @@ -7353,14 +7414,14 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, case MPI2_EVENT_LOG_ENTRY_ADDED: { Mpi2EventDataLogEntryAdded_t *log_entry; - u32 *log_code; + __le32 *log_code; if (!ioc->is_warpdrive) break; log_entry = (Mpi2EventDataLogEntryAdded_t *) mpi_reply->EventData; - log_code = (u32 *)log_entry->LogData; + log_code = (__le32 *)log_entry->LogData; if (le16_to_cpu(log_entry->LogEntryQualifier) != MPT2_WARPDRIVE_LOGENTRY) @@ -7487,7 +7548,7 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc, return; if (mpt2sas_port->remote_identify.device_type == SAS_END_DEVICE) - mpt2sas_device_remove(ioc, + mpt2sas_device_remove_by_sas_address(ioc, mpt2sas_port->remote_identify.sas_address); else if (mpt2sas_port->remote_identify.device_type == SAS_EDGE_EXPANDER_DEVICE || @@ -7661,7 +7722,7 @@ _scsih_remove(struct pci_dev *pdev) &ioc->sas_hba.sas_port_list, port_list) { if (mpt2sas_port->remote_identify.device_type == SAS_END_DEVICE) - mpt2sas_device_remove(ioc, + mpt2sas_device_remove_by_sas_address(ioc, mpt2sas_port->remote_identify.sas_address); else if (mpt2sas_port->remote_identify.device_type == SAS_EDGE_EXPANDER_DEVICE || @@ -7733,11 +7794,11 @@ _scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc) if (rc) _scsih_raid_device_remove(ioc, raid_device); } else { + spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = device; handle = sas_device->handle; sas_address_parent = sas_device->sas_address_parent; sas_address = sas_device->sas_address; - spin_lock_irqsave(&ioc->sas_device_lock, flags); list_move_tail(&sas_device->list, &ioc->sas_device_list); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); @@ -8061,8 +8122,8 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) out_thread_fail: list_del(&ioc->list); scsi_remove_host(shost); - scsi_host_put(shost); out_add_shost_fail: + scsi_host_put(shost); return -ENODEV; } diff --git a/trunk/drivers/scsi/mpt2sas/mpt2sas_transport.c b/trunk/drivers/scsi/mpt2sas/mpt2sas_transport.c index 831047466a5a..c6cf20f60720 100644 --- a/trunk/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/trunk/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -163,12 +163,15 @@ _transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle, return -EIO; } - memset(identify, 0, sizeof(*identify)); + memset(identify, 0, sizeof(struct sas_identify)); device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); /* sas_address */ identify->sas_address = le64_to_cpu(sas_device_pg0.SASAddress); + /* phy number of the parent device this device is linked to */ + identify->phy_identifier = sas_device_pg0.PhyNum; + /* device_type */ switch (device_info & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) { case MPI2_SAS_DEVICE_INFO_NO_DEVICE: @@ -484,7 +487,7 @@ _transport_delete_port(struct MPT2SAS_ADAPTER *ioc, ioc->logging_level |= MPT_DEBUG_TRANSPORT; if (device_type == SAS_END_DEVICE) - mpt2sas_device_remove(ioc, sas_address); + mpt2sas_device_remove_by_sas_address(ioc, sas_address); else if (device_type == SAS_EDGE_EXPANDER_DEVICE || device_type == SAS_FANOUT_EXPANDER_DEVICE) mpt2sas_expander_remove(ioc, sas_address); @@ -792,9 +795,10 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, spin_lock_irqsave(&ioc->sas_node_lock, flags); sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address_parent); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - if (!sas_node) + if (!sas_node) { + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); return; + } list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list, port_list) { if (mpt2sas_port->remote_identify.sas_address != sas_address) @@ -804,8 +808,10 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, goto out; } out: - if (!found) + if (!found) { + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); return; + } for (i = 0; i < sas_node->num_phys; i++) { if (sas_node->phy[i].remote_identify.sas_address == sas_address) @@ -813,6 +819,7 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, sizeof(struct sas_identify)); } + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); list_for_each_entry_safe(mpt2sas_phy, next_phy, &mpt2sas_port->phy_list, port_siblings) { if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) @@ -986,12 +993,14 @@ mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc, spin_lock_irqsave(&ioc->sas_node_lock, flags); sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - if (!sas_node) + if (!sas_node) { + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); return; + } mpt2sas_phy = &sas_node->phy[phy_number]; mpt2sas_phy->attached_handle = handle; + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) { _transport_set_identify(ioc, handle, &mpt2sas_phy->remote_identify); @@ -1310,17 +1319,20 @@ _transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy); struct _sas_device *sas_device; unsigned long flags; + int rc; spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, rphy->identify.sas_address); + if (sas_device) { + *identifier = sas_device->enclosure_logical_id; + rc = 0; + } else { + *identifier = 0; + rc = -ENXIO; + } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - if (!sas_device) - return -ENXIO; - - *identifier = sas_device->enclosure_logical_id; - return 0; + return rc; } /** @@ -1335,16 +1347,17 @@ _transport_get_bay_identifier(struct sas_rphy *rphy) struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy); struct _sas_device *sas_device; unsigned long flags; + int rc; spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, rphy->identify.sas_address); + if (sas_device) + rc = sas_device->slot; + else + rc = -ENXIO; spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - if (!sas_device) - return -ENXIO; - - return sas_device->slot; + return rc; } /* phy control request structure */ @@ -1629,11 +1642,13 @@ _transport_phy_enable(struct sas_phy *phy, int enable) { struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; + Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL; Mpi2ConfigReply_t mpi_reply; u16 ioc_status; u16 sz; int rc = 0; unsigned long flags; + int i, discovery_active; spin_lock_irqsave(&ioc->sas_node_lock, flags); if (_transport_sas_node_find_by_sas_address(ioc, @@ -1651,7 +1666,50 @@ _transport_phy_enable(struct sas_phy *phy, int enable) /* handle hba phys */ - /* sas_iounit page 1 */ + /* read sas_iounit page 0 */ + sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys * + sizeof(Mpi2SasIOUnit0PhyData_t)); + sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); + if (!sas_iounit_pg0) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -ENOMEM; + goto out; + } + if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply, + sas_iounit_pg0, sz))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -ENXIO; + goto out; + } + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -EIO; + goto out; + } + + /* unable to enable/disable phys when when discovery is active */ + for (i = 0, discovery_active = 0; i < ioc->sas_hba.num_phys ; i++) { + if (sas_iounit_pg0->PhyData[i].PortFlags & + MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS) { + printk(MPT2SAS_ERR_FMT "discovery is active on " + "port = %d, phy = %d: unable to enable/disable " + "phys, try again later!\n", ioc->name, + sas_iounit_pg0->PhyData[i].Port, i); + discovery_active = 1; + } + } + + if (discovery_active) { + rc = -EAGAIN; + goto out; + } + + /* read sas_iounit page 1 */ sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * sizeof(Mpi2SasIOUnit1PhyData_t)); sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); @@ -1676,7 +1734,18 @@ _transport_phy_enable(struct sas_phy *phy, int enable) rc = -EIO; goto out; } - + /* copy Port/PortFlags/PhyFlags from page 0 */ + for (i = 0; i < ioc->sas_hba.num_phys ; i++) { + sas_iounit_pg1->PhyData[i].Port = + sas_iounit_pg0->PhyData[i].Port; + sas_iounit_pg1->PhyData[i].PortFlags = + (sas_iounit_pg0->PhyData[i].PortFlags & + MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG); + sas_iounit_pg1->PhyData[i].PhyFlags = + (sas_iounit_pg0->PhyData[i].PhyFlags & + (MPI2_SASIOUNIT0_PHYFLAGS_ZONING_ENABLED + + MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED)); + } if (enable) sas_iounit_pg1->PhyData[phy->number].PhyFlags &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; @@ -1692,6 +1761,7 @@ _transport_phy_enable(struct sas_phy *phy, int enable) out: kfree(sas_iounit_pg1); + kfree(sas_iounit_pg0); return rc; } @@ -1828,7 +1898,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); Mpi2SmpPassthroughRequest_t *mpi_request; Mpi2SmpPassthroughReply_t *mpi_reply; - int rc; + int rc, i; u16 smid; u32 ioc_state; unsigned long timeleft; @@ -1837,24 +1907,20 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, u8 issue_reset = 0; dma_addr_t dma_addr_in = 0; dma_addr_t dma_addr_out = 0; + dma_addr_t pci_dma_in = 0; + dma_addr_t pci_dma_out = 0; + void *pci_addr_in = NULL; + void *pci_addr_out = NULL; u16 wait_state_count; struct request *rsp = req->next_rq; + struct bio_vec *bvec = NULL; if (!rsp) { printk(MPT2SAS_ERR_FMT "%s: the smp response space is " "missing\n", ioc->name, __func__); return -EINVAL; } - - /* do we need to support multiple segments? */ - if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) { - printk(MPT2SAS_ERR_FMT "%s: multiple segments req %u %u, " - "rsp %u %u\n", ioc->name, __func__, req->bio->bi_vcnt, - blk_rq_bytes(req), rsp->bio->bi_vcnt, blk_rq_bytes(rsp)); - return -EINVAL; - } - - if (ioc->shost_recovery) { + if (ioc->shost_recovery || ioc->pci_error_recovery) { printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", __func__, ioc->name); return -EFAULT; @@ -1872,6 +1938,59 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, } ioc->transport_cmds.status = MPT2_CMD_PENDING; + /* Check if the request is split across multiple segments */ + if (req->bio->bi_vcnt > 1) { + u32 offset = 0; + + /* Allocate memory and copy the request */ + pci_addr_out = pci_alloc_consistent(ioc->pdev, + blk_rq_bytes(req), &pci_dma_out); + if (!pci_addr_out) { + printk(MPT2SAS_INFO_FMT "%s(): PCI Addr out = NULL\n", + ioc->name, __func__); + rc = -ENOMEM; + goto out; + } + + bio_for_each_segment(bvec, req->bio, i) { + memcpy(pci_addr_out + offset, + page_address(bvec->bv_page) + bvec->bv_offset, + bvec->bv_len); + offset += bvec->bv_len; + } + } else { + dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio), + blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); + if (!dma_addr_out) { + printk(MPT2SAS_INFO_FMT "%s(): DMA Addr out = NULL\n", + ioc->name, __func__); + rc = -ENOMEM; + goto free_pci; + } + } + + /* Check if the response needs to be populated across + * multiple segments */ + if (rsp->bio->bi_vcnt > 1) { + pci_addr_in = pci_alloc_consistent(ioc->pdev, blk_rq_bytes(rsp), + &pci_dma_in); + if (!pci_addr_in) { + printk(MPT2SAS_INFO_FMT "%s(): PCI Addr in = NULL\n", + ioc->name, __func__); + rc = -ENOMEM; + goto unmap; + } + } else { + dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio), + blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); + if (!dma_addr_in) { + printk(MPT2SAS_INFO_FMT "%s(): DMA Addr in = NULL\n", + ioc->name, __func__); + rc = -ENOMEM; + goto unmap; + } + } + wait_state_count = 0; ioc_state = mpt2sas_base_get_iocstate(ioc, 1); while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { @@ -1880,7 +1999,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, "%s: failed due to ioc not operational\n", ioc->name, __func__); rc = -EFAULT; - goto out; + goto unmap; } ssleep(1); ioc_state = mpt2sas_base_get_iocstate(ioc, 1); @@ -1897,7 +2016,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", ioc->name, __func__); rc = -EAGAIN; - goto out; + goto unmap; } rc = 0; @@ -1919,16 +2038,14 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio), - blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); - if (!dma_addr_out) { - mpt2sas_base_free_smid(ioc, smid); - goto unmap; + if (req->bio->bi_vcnt > 1) { + ioc->base_add_sg_single(psge, sgl_flags | + (blk_rq_bytes(req) - 4), pci_dma_out); + } else { + ioc->base_add_sg_single(psge, sgl_flags | + (blk_rq_bytes(req) - 4), dma_addr_out); } - ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(req) - 4), - dma_addr_out); - /* incr sgel */ psge += ioc->sge_size; @@ -1937,16 +2054,14 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST); sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio), - blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); - if (!dma_addr_in) { - mpt2sas_base_free_smid(ioc, smid); - goto unmap; + if (rsp->bio->bi_vcnt > 1) { + ioc->base_add_sg_single(psge, sgl_flags | + (blk_rq_bytes(rsp) + 4), pci_dma_in); + } else { + ioc->base_add_sg_single(psge, sgl_flags | + (blk_rq_bytes(rsp) + 4), dma_addr_in); } - ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(rsp) + 4), - dma_addr_in); - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - " "sending smp request\n", ioc->name, __func__)); @@ -1982,6 +2097,27 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, req->resid_len = 0; rsp->resid_len -= le16_to_cpu(mpi_reply->ResponseDataLength); + /* check if the resp needs to be copied from the allocated + * pci mem */ + if (rsp->bio->bi_vcnt > 1) { + u32 offset = 0; + u32 bytes_to_copy = + le16_to_cpu(mpi_reply->ResponseDataLength); + bio_for_each_segment(bvec, rsp->bio, i) { + if (bytes_to_copy <= bvec->bv_len) { + memcpy(page_address(bvec->bv_page) + + bvec->bv_offset, pci_addr_in + + offset, bytes_to_copy); + break; + } else { + memcpy(page_address(bvec->bv_page) + + bvec->bv_offset, pci_addr_in + + offset, bvec->bv_len); + bytes_to_copy -= bvec->bv_len; + } + offset += bvec->bv_len; + } + } } else { dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - no reply\n", ioc->name, __func__)); @@ -2003,6 +2139,15 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, pci_unmap_single(ioc->pdev, dma_addr_in, blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); + free_pci: + if (pci_addr_out) + pci_free_consistent(ioc->pdev, blk_rq_bytes(req), pci_addr_out, + pci_dma_out); + + if (pci_addr_in) + pci_free_consistent(ioc->pdev, blk_rq_bytes(rsp), pci_addr_in, + pci_dma_in); + out: ioc->transport_cmds.status = MPT2_CMD_NOT_USED; mutex_unlock(&ioc->transport_cmds.mutex); diff --git a/trunk/drivers/scsi/pm8001/pm8001_defs.h b/trunk/drivers/scsi/pm8001/pm8001_defs.h index 944afada61ee..c3d20c8d4abe 100644 --- a/trunk/drivers/scsi/pm8001/pm8001_defs.h +++ b/trunk/drivers/scsi/pm8001/pm8001_defs.h @@ -66,9 +66,10 @@ enum port_type { /* driver compile-time configuration */ #define PM8001_MAX_CCB 512 /* max ccbs supported */ +#define PM8001_MPI_QUEUE 1024 /* maximum mpi queue entries */ #define PM8001_MAX_INB_NUM 1 #define PM8001_MAX_OUTB_NUM 1 -#define PM8001_CAN_QUEUE 128 /* SCSI Queue depth */ +#define PM8001_CAN_QUEUE 508 /* SCSI Queue depth */ /* unchangeable hardware details */ #define PM8001_MAX_PHYS 8 /* max. possible phys */ diff --git a/trunk/drivers/scsi/pm8001/pm8001_hwi.c b/trunk/drivers/scsi/pm8001/pm8001_hwi.c index 9d82ee5c10de..bf54aafc2d71 100644 --- a/trunk/drivers/scsi/pm8001/pm8001_hwi.c +++ b/trunk/drivers/scsi/pm8001/pm8001_hwi.c @@ -192,7 +192,7 @@ init_default_table_values(struct pm8001_hba_info *pm8001_ha) pm8001_ha->main_cfg_tbl.fatal_err_interrupt = 0x01; for (i = 0; i < qn; i++) { pm8001_ha->inbnd_q_tbl[i].element_pri_size_cnt = - 0x00000100 | (0x00000040 << 16) | (0x00<<30); + PM8001_MPI_QUEUE | (64 << 16) | (0x00<<30); pm8001_ha->inbnd_q_tbl[i].upper_base_addr = pm8001_ha->memoryMap.region[IB].phys_addr_hi; pm8001_ha->inbnd_q_tbl[i].lower_base_addr = @@ -218,7 +218,7 @@ init_default_table_values(struct pm8001_hba_info *pm8001_ha) } for (i = 0; i < qn; i++) { pm8001_ha->outbnd_q_tbl[i].element_size_cnt = - 256 | (64 << 16) | (1<<30); + PM8001_MPI_QUEUE | (64 << 16) | (0x01<<30); pm8001_ha->outbnd_q_tbl[i].upper_base_addr = pm8001_ha->memoryMap.region[OB].phys_addr_hi; pm8001_ha->outbnd_q_tbl[i].lower_base_addr = @@ -1245,7 +1245,7 @@ static int mpi_msg_free_get(struct inbound_queue_table *circularQ, /* Stores the new consumer index */ consumer_index = pm8001_read_32(circularQ->ci_virt); circularQ->consumer_index = cpu_to_le32(consumer_index); - if (((circularQ->producer_idx + bcCount) % 256) == + if (((circularQ->producer_idx + bcCount) % PM8001_MPI_QUEUE) == le32_to_cpu(circularQ->consumer_index)) { *messagePtr = NULL; return -1; @@ -1253,7 +1253,8 @@ static int mpi_msg_free_get(struct inbound_queue_table *circularQ, /* get memory IOMB buffer address */ offset = circularQ->producer_idx * 64; /* increment to next bcCount element */ - circularQ->producer_idx = (circularQ->producer_idx + bcCount) % 256; + circularQ->producer_idx = (circularQ->producer_idx + bcCount) + % PM8001_MPI_QUEUE; /* Adds that distance to the base of the region virtual address plus the message header size*/ msgHeader = (struct mpi_msg_hdr *)(circularQ->base_virt + offset); @@ -1326,7 +1327,8 @@ static u32 mpi_msg_free_set(struct pm8001_hba_info *pm8001_ha, void *pMsg, return 0; } /* free the circular queue buffer elements associated with the message*/ - circularQ->consumer_idx = (circularQ->consumer_idx + bc) % 256; + circularQ->consumer_idx = (circularQ->consumer_idx + bc) + % PM8001_MPI_QUEUE; /* update the CI of outbound queue */ pm8001_cw32(pm8001_ha, circularQ->ci_pci_bar, circularQ->ci_offset, circularQ->consumer_idx); @@ -1383,7 +1385,8 @@ static u32 mpi_msg_consume(struct pm8001_hba_info *pm8001_ha, circularQ->consumer_idx = (circularQ->consumer_idx + ((le32_to_cpu(msgHeader_tmp) - >> 24) & 0x1f)) % 256; + >> 24) & 0x1f)) + % PM8001_MPI_QUEUE; msgHeader_tmp = 0; pm8001_write_32(msgHeader, 0, 0); /* update the CI of outbound queue */ @@ -1396,7 +1399,7 @@ static u32 mpi_msg_consume(struct pm8001_hba_info *pm8001_ha, circularQ->consumer_idx = (circularQ->consumer_idx + ((le32_to_cpu(msgHeader_tmp) >> 24) & - 0x1f)) % 256; + 0x1f)) % PM8001_MPI_QUEUE; msgHeader_tmp = 0; pm8001_write_32(msgHeader, 0, 0); /* update the CI of outbound queue */ @@ -3357,7 +3360,7 @@ mpi_fw_flash_update_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) struct fw_control_ex fw_control_context; struct fw_flash_Update_resp *ppayload = (struct fw_flash_Update_resp *)(piomb + 4); - u32 tag = ppayload->tag; + u32 tag = le32_to_cpu(ppayload->tag); struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[tag]; status = le32_to_cpu(ppayload->status); memcpy(&fw_control_context, @@ -3703,8 +3706,8 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void* piomb) */ static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb) { - u32 pHeader = (u32)*(u32 *)piomb; - u8 opc = (u8)(pHeader & 0xFFF); + __le32 pHeader = *(__le32 *)piomb; + u8 opc = (u8)((le32_to_cpu(pHeader)) & 0xFFF); PM8001_MSG_DBG(pm8001_ha, pm8001_printk("process_one_iomb:")); diff --git a/trunk/drivers/scsi/pm8001/pm8001_hwi.h b/trunk/drivers/scsi/pm8001/pm8001_hwi.h index 1a4611eb0321..d437309cb1e1 100644 --- a/trunk/drivers/scsi/pm8001/pm8001_hwi.h +++ b/trunk/drivers/scsi/pm8001/pm8001_hwi.h @@ -599,7 +599,7 @@ struct fw_flash_Update_req { * */ struct fw_flash_Update_resp { - dma_addr_t tag; + __le32 tag; __le32 status; u32 reserved[13]; } __attribute__((packed, aligned(4))); diff --git a/trunk/drivers/scsi/pm8001/pm8001_init.c b/trunk/drivers/scsi/pm8001/pm8001_init.c index 36efaa7c3a54..0267c22f8741 100644 --- a/trunk/drivers/scsi/pm8001/pm8001_init.c +++ b/trunk/drivers/scsi/pm8001/pm8001_init.c @@ -235,15 +235,15 @@ static int __devinit pm8001_alloc(struct pm8001_hba_info *pm8001_ha) pm8001_ha->memoryMap.region[PI].alignment = 4; /* MPI Memory region 5 inbound queues */ - pm8001_ha->memoryMap.region[IB].num_elements = 256; + pm8001_ha->memoryMap.region[IB].num_elements = PM8001_MPI_QUEUE; pm8001_ha->memoryMap.region[IB].element_size = 64; - pm8001_ha->memoryMap.region[IB].total_len = 256 * 64; + pm8001_ha->memoryMap.region[IB].total_len = PM8001_MPI_QUEUE * 64; pm8001_ha->memoryMap.region[IB].alignment = 64; - /* MPI Memory region 6 inbound queues */ - pm8001_ha->memoryMap.region[OB].num_elements = 256; + /* MPI Memory region 6 outbound queues */ + pm8001_ha->memoryMap.region[OB].num_elements = PM8001_MPI_QUEUE; pm8001_ha->memoryMap.region[OB].element_size = 64; - pm8001_ha->memoryMap.region[OB].total_len = 256 * 64; + pm8001_ha->memoryMap.region[OB].total_len = PM8001_MPI_QUEUE * 64; pm8001_ha->memoryMap.region[OB].alignment = 64; /* Memory region write DMA*/ diff --git a/trunk/drivers/scsi/qla1280.c b/trunk/drivers/scsi/qla1280.c index 6c6486f626ee..538230be5cca 100644 --- a/trunk/drivers/scsi/qla1280.c +++ b/trunk/drivers/scsi/qla1280.c @@ -4473,17 +4473,14 @@ qla1280_exit(void) pci_unregister_driver(&qla1280_pci_driver); /* release any allocated firmware images */ for (i = 0; i < QL_NUM_FW_IMAGES; i++) { - if (qla1280_fw_tbl[i].fw) { - release_firmware(qla1280_fw_tbl[i].fw); - qla1280_fw_tbl[i].fw = NULL; - } + release_firmware(qla1280_fw_tbl[i].fw); + qla1280_fw_tbl[i].fw = NULL; } } module_init(qla1280_init); module_exit(qla1280_exit); - MODULE_AUTHOR("Qlogic & Jes Sorensen"); MODULE_DESCRIPTION("Qlogic ISP SCSI (qla1x80/qla1x160) driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/scsi/qla2xxx/qla_os.c b/trunk/drivers/scsi/qla2xxx/qla_os.c index 7db803377c64..c9c56a8427f3 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_os.c +++ b/trunk/drivers/scsi/qla2xxx/qla_os.c @@ -4122,8 +4122,7 @@ qla2x00_release_firmware(void) mutex_lock(&qla_fw_lock); for (idx = 0; idx < FW_BLOBS; idx++) - if (qla_fw_blobs[idx].fw) - release_firmware(qla_fw_blobs[idx].fw); + release_firmware(qla_fw_blobs[idx].fw); mutex_unlock(&qla_fw_lock); } diff --git a/trunk/drivers/scsi/scsi.c b/trunk/drivers/scsi/scsi.c index 07322ecff90d..61c82a345f82 100644 --- a/trunk/drivers/scsi/scsi.c +++ b/trunk/drivers/scsi/scsi.c @@ -90,6 +90,12 @@ unsigned int scsi_logging_level; EXPORT_SYMBOL(scsi_logging_level); #endif +#if IS_ENABLED(CONFIG_PM) || IS_ENABLED(CONFIG_BLK_DEV_SD) +/* sd and scsi_pm need to coordinate flushing async actions */ +LIST_HEAD(scsi_sd_probe_domain); +EXPORT_SYMBOL(scsi_sd_probe_domain); +#endif + /* NB: These are exposed through /proc/scsi/scsi and form part of the ABI. * You may not alter any existing entry (although adding new ones is * encouraged once assigned by ANSI/INCITS T10 diff --git a/trunk/drivers/scsi/scsi_error.c b/trunk/drivers/scsi/scsi_error.c index 386f0c53bea7..d0f71e5d065f 100644 --- a/trunk/drivers/scsi/scsi_error.c +++ b/trunk/drivers/scsi/scsi_error.c @@ -664,7 +664,7 @@ static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd) } /** - * scsi_eh_prep_cmnd - Save a scsi command info as part of error recory + * scsi_eh_prep_cmnd - Save a scsi command info as part of error recovery * @scmd: SCSI command structure to hijack * @ses: structure to save restore information * @cmnd: CDB to send. Can be NULL if no new cmnd is needed @@ -739,7 +739,7 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses, EXPORT_SYMBOL(scsi_eh_prep_cmnd); /** - * scsi_eh_restore_cmnd - Restore a scsi command info as part of error recory + * scsi_eh_restore_cmnd - Restore a scsi command info as part of error recovery * @scmd: SCSI command structure to restore * @ses: saved information from a coresponding call to scsi_eh_prep_cmnd * @@ -762,7 +762,7 @@ void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses) EXPORT_SYMBOL(scsi_eh_restore_cmnd); /** - * scsi_send_eh_cmnd - submit a scsi command as part of error recory + * scsi_send_eh_cmnd - submit a scsi command as part of error recovery * @scmd: SCSI command structure to hijack * @cmnd: CDB to send * @cmnd_size: size in bytes of @cmnd diff --git a/trunk/drivers/scsi/scsi_lib.c b/trunk/drivers/scsi/scsi_lib.c index 5dfd7495d1a1..62ddfd31d4ce 100644 --- a/trunk/drivers/scsi/scsi_lib.c +++ b/trunk/drivers/scsi/scsi_lib.c @@ -2348,10 +2348,14 @@ EXPORT_SYMBOL(scsi_device_quiesce); * * Must be called with user context, may sleep. */ -void -scsi_device_resume(struct scsi_device *sdev) +void scsi_device_resume(struct scsi_device *sdev) { - if(scsi_device_set_state(sdev, SDEV_RUNNING)) + /* check if the device state was mutated prior to resume, and if + * so assume the state is being managed elsewhere (for example + * device deleted during suspend) + */ + if (sdev->sdev_state != SDEV_QUIESCE || + scsi_device_set_state(sdev, SDEV_RUNNING)) return; scsi_run_queue(sdev->request_queue); } diff --git a/trunk/drivers/scsi/scsi_pm.c b/trunk/drivers/scsi/scsi_pm.c index c4670642d023..f661a41fa4c6 100644 --- a/trunk/drivers/scsi/scsi_pm.c +++ b/trunk/drivers/scsi/scsi_pm.c @@ -97,7 +97,7 @@ static int scsi_bus_prepare(struct device *dev) { if (scsi_is_sdev_device(dev)) { /* sd probing uses async_schedule. Wait until it finishes. */ - async_synchronize_full(); + async_synchronize_full_domain(&scsi_sd_probe_domain); } else if (scsi_is_host_device(dev)) { /* Wait until async scanning is finished */ diff --git a/trunk/drivers/scsi/scsi_priv.h b/trunk/drivers/scsi/scsi_priv.h index be4fa6d179b1..07ce3f51701d 100644 --- a/trunk/drivers/scsi/scsi_priv.h +++ b/trunk/drivers/scsi/scsi_priv.h @@ -163,6 +163,8 @@ static inline int scsi_autopm_get_host(struct Scsi_Host *h) { return 0; } static inline void scsi_autopm_put_host(struct Scsi_Host *h) {} #endif /* CONFIG_PM_RUNTIME */ +extern struct list_head scsi_sd_probe_domain; + /* * internal scsi timeout functions: for use by mid-layer and transport * classes. diff --git a/trunk/drivers/scsi/scsi_transport_fc.c b/trunk/drivers/scsi/scsi_transport_fc.c index 80fbe2ac0b47..579760420d53 100644 --- a/trunk/drivers/scsi/scsi_transport_fc.c +++ b/trunk/drivers/scsi/scsi_transport_fc.c @@ -2808,17 +2808,20 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, FC_RPORT_DEVLOSS_PENDING | FC_RPORT_DEVLOSS_CALLBK_DONE); + spin_unlock_irqrestore(shost->host_lock, flags); + /* if target, initiate a scan */ if (rport->scsi_target_id != -1) { + scsi_target_unblock(&rport->dev); + + spin_lock_irqsave(shost->host_lock, + flags); rport->flags |= FC_RPORT_SCAN_PENDING; scsi_queue_work(shost, &rport->scan_work); spin_unlock_irqrestore(shost->host_lock, flags); - scsi_target_unblock(&rport->dev); - } else - spin_unlock_irqrestore(shost->host_lock, - flags); + } fc_bsg_goose_queue(rport); @@ -2876,16 +2879,17 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, if (fci->f->dd_fcrport_size) memset(rport->dd_data, 0, fci->f->dd_fcrport_size); + spin_unlock_irqrestore(shost->host_lock, flags); + + if (ids->roles & FC_PORT_ROLE_FCP_TARGET) { + scsi_target_unblock(&rport->dev); - if (rport->roles & FC_PORT_ROLE_FCP_TARGET) { /* initiate a scan of the target */ + spin_lock_irqsave(shost->host_lock, flags); rport->flags |= FC_RPORT_SCAN_PENDING; scsi_queue_work(shost, &rport->scan_work); spin_unlock_irqrestore(shost->host_lock, flags); - scsi_target_unblock(&rport->dev); - } else - spin_unlock_irqrestore(shost->host_lock, flags); - + } return rport; } } @@ -3083,12 +3087,12 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) /* ensure any stgt delete functions are done */ fc_flush_work(shost); + scsi_target_unblock(&rport->dev); /* initiate a scan of the target */ spin_lock_irqsave(shost->host_lock, flags); rport->flags |= FC_RPORT_SCAN_PENDING; scsi_queue_work(shost, &rport->scan_work); spin_unlock_irqrestore(shost->host_lock, flags); - scsi_target_unblock(&rport->dev); } } EXPORT_SYMBOL(fc_remote_port_rolechg); diff --git a/trunk/drivers/scsi/scsi_transport_spi.c b/trunk/drivers/scsi/scsi_transport_spi.c index a2715c31e754..cf08071a9b6e 100644 --- a/trunk/drivers/scsi/scsi_transport_spi.c +++ b/trunk/drivers/scsi/scsi_transport_spi.c @@ -1010,10 +1010,10 @@ spi_dv_device(struct scsi_device *sdev) u8 *buffer; const int len = SPI_MAX_ECHO_BUFFER_SIZE*2; - if (unlikely(scsi_device_get(sdev))) + if (unlikely(spi_dv_in_progress(starget))) return; - if (unlikely(spi_dv_in_progress(starget))) + if (unlikely(scsi_device_get(sdev))) return; spi_dv_in_progress(starget) = 1; diff --git a/trunk/drivers/scsi/sd.c b/trunk/drivers/scsi/sd.c index 5ba5c2a9e8e9..6f0a4c612b3b 100644 --- a/trunk/drivers/scsi/sd.c +++ b/trunk/drivers/scsi/sd.c @@ -65,6 +65,7 @@ #include #include "sd.h" +#include "scsi_priv.h" #include "scsi_logging.h" MODULE_AUTHOR("Eric Youngdale"); @@ -2722,7 +2723,7 @@ static int sd_probe(struct device *dev) dev_set_drvdata(dev, sdkp); get_device(&sdkp->dev); /* prevent release before async_schedule */ - async_schedule(sd_probe_async, sdkp); + async_schedule_domain(sd_probe_async, sdkp, &scsi_sd_probe_domain); return 0; @@ -2756,7 +2757,7 @@ static int sd_remove(struct device *dev) sdkp = dev_get_drvdata(dev); scsi_autopm_get_device(sdkp->device); - async_synchronize_full(); + async_synchronize_full_domain(&scsi_sd_probe_domain); blk_queue_prep_rq(sdkp->device->request_queue, scsi_prep_fn); blk_queue_unprep_rq(sdkp->device->request_queue, NULL); device_del(&sdkp->dev); diff --git a/trunk/drivers/scsi/sg.c b/trunk/drivers/scsi/sg.c index eacd46bb36b9..9c5c5f2b3962 100644 --- a/trunk/drivers/scsi/sg.c +++ b/trunk/drivers/scsi/sg.c @@ -104,7 +104,7 @@ static int scatter_elem_sz_prev = SG_SCATTER_SZ; static int sg_add(struct device *, struct class_interface *); static void sg_remove(struct device *, struct class_interface *); -static DEFINE_MUTEX(sg_mutex); +static DEFINE_SPINLOCK(sg_open_exclusive_lock); static DEFINE_IDR(sg_index_idr); static DEFINE_RWLOCK(sg_index_lock); /* Also used to lock @@ -137,13 +137,15 @@ typedef struct sg_request { /* SG_MAX_QUEUE requests outstanding per file */ char res_used; /* 1 -> using reserve buffer, 0 -> not ... */ char orphan; /* 1 -> drop on sight, 0 -> normal */ char sg_io_owned; /* 1 -> packet belongs to SG_IO */ - volatile char done; /* 0->before bh, 1->before read, 2->read */ + /* done protected by rq_list_lock */ + char done; /* 0->before bh, 1->before read, 2->read */ struct request *rq; struct bio *bio; struct execute_work ew; } Sg_request; typedef struct sg_fd { /* holds the state of a file descriptor */ + /* sfd_siblings is protected by sg_index_lock */ struct list_head sfd_siblings; struct sg_device *parentdp; /* owning device */ wait_queue_head_t read_wait; /* queue read until command done */ @@ -157,7 +159,6 @@ typedef struct sg_fd { /* holds the state of a file descriptor */ Sg_request req_arr[SG_MAX_QUEUE]; /* used as singly-linked list */ char low_dma; /* as in parent but possibly overridden to 1 */ char force_packid; /* 1 -> pack_id input to read(), 0 -> ignored */ - volatile char closed; /* 1 -> fd closed but request(s) outstanding */ char cmd_q; /* 1 -> allow command queuing, 0 -> don't */ char next_cmd_len; /* 0 -> automatic (def), >0 -> use on next write() */ char keep_orphan; /* 0 -> drop orphan (def), 1 -> keep for read() */ @@ -171,9 +172,11 @@ typedef struct sg_device { /* holds the state of each scsi generic device */ wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */ int sg_tablesize; /* adapter's max scatter-gather table size */ u32 index; /* device index number */ + /* sfds is protected by sg_index_lock */ struct list_head sfds; volatile char detached; /* 0->attached, 1->detached pending removal */ - volatile char exclude; /* opened for exclusive access */ + /* exclude protected by sg_open_exclusive_lock */ + char exclude; /* opened for exclusive access */ char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */ struct gendisk *disk; struct cdev * cdev; /* char_dev [sysfs: /sys/cdev/major/sg] */ @@ -221,6 +224,38 @@ static int sg_allow_access(struct file *filp, unsigned char *cmd) return blk_verify_command(cmd, filp->f_mode & FMODE_WRITE); } +static int get_exclude(Sg_device *sdp) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&sg_open_exclusive_lock, flags); + ret = sdp->exclude; + spin_unlock_irqrestore(&sg_open_exclusive_lock, flags); + return ret; +} + +static int set_exclude(Sg_device *sdp, char val) +{ + unsigned long flags; + + spin_lock_irqsave(&sg_open_exclusive_lock, flags); + sdp->exclude = val; + spin_unlock_irqrestore(&sg_open_exclusive_lock, flags); + return val; +} + +static int sfds_list_empty(Sg_device *sdp) +{ + unsigned long flags; + int ret; + + read_lock_irqsave(&sg_index_lock, flags); + ret = list_empty(&sdp->sfds); + read_unlock_irqrestore(&sg_index_lock, flags); + return ret; +} + static int sg_open(struct inode *inode, struct file *filp) { @@ -232,7 +267,6 @@ sg_open(struct inode *inode, struct file *filp) int res; int retval; - mutex_lock(&sg_mutex); nonseekable_open(inode, filp); SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags)); sdp = sg_get_dev(dev); @@ -264,25 +298,22 @@ sg_open(struct inode *inode, struct file *filp) retval = -EPERM; /* Can't lock it with read only access */ goto error_out; } - if (!list_empty(&sdp->sfds) && (flags & O_NONBLOCK)) { + if (!sfds_list_empty(sdp) && (flags & O_NONBLOCK)) { retval = -EBUSY; goto error_out; } - res = 0; - __wait_event_interruptible(sdp->o_excl_wait, - ((!list_empty(&sdp->sfds) || sdp->exclude) ? 0 : (sdp->exclude = 1)), res); + res = wait_event_interruptible(sdp->o_excl_wait, + ((!sfds_list_empty(sdp) || get_exclude(sdp)) ? 0 : set_exclude(sdp, 1))); if (res) { retval = res; /* -ERESTARTSYS because signal hit process */ goto error_out; } - } else if (sdp->exclude) { /* some other fd has an exclusive lock on dev */ + } else if (get_exclude(sdp)) { /* some other fd has an exclusive lock on dev */ if (flags & O_NONBLOCK) { retval = -EBUSY; goto error_out; } - res = 0; - __wait_event_interruptible(sdp->o_excl_wait, (!sdp->exclude), - res); + res = wait_event_interruptible(sdp->o_excl_wait, !get_exclude(sdp)); if (res) { retval = res; /* -ERESTARTSYS because signal hit process */ goto error_out; @@ -292,7 +323,7 @@ sg_open(struct inode *inode, struct file *filp) retval = -ENODEV; goto error_out; } - if (list_empty(&sdp->sfds)) { /* no existing opens on this device */ + if (sfds_list_empty(sdp)) { /* no existing opens on this device */ sdp->sgdebug = 0; q = sdp->device->request_queue; sdp->sg_tablesize = queue_max_segments(q); @@ -301,7 +332,7 @@ sg_open(struct inode *inode, struct file *filp) filp->private_data = sfp; else { if (flags & O_EXCL) { - sdp->exclude = 0; /* undo if error */ + set_exclude(sdp, 0); /* undo if error */ wake_up_interruptible(&sdp->o_excl_wait); } retval = -ENOMEM; @@ -317,7 +348,6 @@ sg_open(struct inode *inode, struct file *filp) sg_put: if (sdp) sg_put_dev(sdp); - mutex_unlock(&sg_mutex); return retval; } @@ -332,9 +362,7 @@ sg_release(struct inode *inode, struct file *filp) return -ENXIO; SCSI_LOG_TIMEOUT(3, printk("sg_release: %s\n", sdp->disk->disk_name)); - sfp->closed = 1; - - sdp->exclude = 0; + set_exclude(sdp, 0); wake_up_interruptible(&sdp->o_excl_wait); scsi_autopm_put_device(sdp->device); @@ -398,19 +426,14 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) retval = -EAGAIN; goto free_old_hdr; } - while (1) { - retval = 0; /* following macro beats race condition */ - __wait_event_interruptible(sfp->read_wait, - (sdp->detached || - (srp = sg_get_rq_mark(sfp, req_pack_id))), - retval); - if (sdp->detached) { - retval = -ENODEV; - goto free_old_hdr; - } - if (0 == retval) - break; - + retval = wait_event_interruptible(sfp->read_wait, + (sdp->detached || + (srp = sg_get_rq_mark(sfp, req_pack_id)))); + if (sdp->detached) { + retval = -ENODEV; + goto free_old_hdr; + } + if (retval) { /* -ERESTARTSYS as signal hit process */ goto free_old_hdr; } @@ -771,7 +794,18 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, return 0; } -static int +static int srp_done(Sg_fd *sfp, Sg_request *srp) +{ + unsigned long flags; + int ret; + + read_lock_irqsave(&sfp->rq_list_lock, flags); + ret = srp->done; + read_unlock_irqrestore(&sfp->rq_list_lock, flags); + return ret; +} + +static long sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) { void __user *p = (void __user *)arg; @@ -791,40 +825,30 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) switch (cmd_in) { case SG_IO: - { - int blocking = 1; /* ignore O_NONBLOCK flag */ - - if (sdp->detached) - return -ENODEV; - if (!scsi_block_when_processing_errors(sdp->device)) - return -ENXIO; - if (!access_ok(VERIFY_WRITE, p, SZ_SG_IO_HDR)) - return -EFAULT; - result = - sg_new_write(sfp, filp, p, SZ_SG_IO_HDR, - blocking, read_only, 1, &srp); - if (result < 0) - return result; - while (1) { - result = 0; /* following macro to beat race condition */ - __wait_event_interruptible(sfp->read_wait, - (srp->done || sdp->detached), - result); - if (sdp->detached) - return -ENODEV; - write_lock_irq(&sfp->rq_list_lock); - if (srp->done) { - srp->done = 2; - write_unlock_irq(&sfp->rq_list_lock); - break; - } - srp->orphan = 1; - write_unlock_irq(&sfp->rq_list_lock); - return result; /* -ERESTARTSYS because signal hit process */ - } + if (sdp->detached) + return -ENODEV; + if (!scsi_block_when_processing_errors(sdp->device)) + return -ENXIO; + if (!access_ok(VERIFY_WRITE, p, SZ_SG_IO_HDR)) + return -EFAULT; + result = sg_new_write(sfp, filp, p, SZ_SG_IO_HDR, + 1, read_only, 1, &srp); + if (result < 0) + return result; + result = wait_event_interruptible(sfp->read_wait, + (srp_done(sfp, srp) || sdp->detached)); + if (sdp->detached) + return -ENODEV; + write_lock_irq(&sfp->rq_list_lock); + if (srp->done) { + srp->done = 2; + write_unlock_irq(&sfp->rq_list_lock); result = sg_new_read(sfp, p, SZ_SG_IO_HDR, srp); return (result < 0) ? result : 0; } + srp->orphan = 1; + write_unlock_irq(&sfp->rq_list_lock); + return result; /* -ERESTARTSYS because signal hit process */ case SG_SET_TIMEOUT: result = get_user(val, ip); if (result) @@ -1091,18 +1115,6 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) } } -static long -sg_unlocked_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) -{ - int ret; - - mutex_lock(&sg_mutex); - ret = sg_ioctl(filp, cmd_in, arg); - mutex_unlock(&sg_mutex); - - return ret; -} - #ifdef CONFIG_COMPAT static long sg_compat_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) { @@ -1136,8 +1148,11 @@ sg_poll(struct file *filp, poll_table * wait) int count = 0; unsigned long iflags; - if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)) - || sfp->closed) + sfp = filp->private_data; + if (!sfp) + return POLLERR; + sdp = sfp->parentdp; + if (!sdp) return POLLERR; poll_wait(filp, &sfp->read_wait, wait); read_lock_irqsave(&sfp->rq_list_lock, iflags); @@ -1347,7 +1362,7 @@ static const struct file_operations sg_fops = { .read = sg_read, .write = sg_write, .poll = sg_poll, - .unlocked_ioctl = sg_unlocked_ioctl, + .unlocked_ioctl = sg_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = sg_compat_ioctl, #endif @@ -2312,7 +2327,7 @@ struct sg_proc_leaf { const struct file_operations * fops; }; -static struct sg_proc_leaf sg_proc_leaf_arr[] = { +static const struct sg_proc_leaf sg_proc_leaf_arr[] = { {"allow_dio", &adio_fops}, {"debug", &debug_fops}, {"def_reserved_size", &dressz_fops}, @@ -2332,7 +2347,7 @@ sg_proc_init(void) if (!sg_proc_sgp) return 1; for (k = 0; k < num_leaves; ++k) { - struct sg_proc_leaf *leaf = &sg_proc_leaf_arr[k]; + const struct sg_proc_leaf *leaf = &sg_proc_leaf_arr[k]; umode_t mask = leaf->fops->write ? S_IRUGO | S_IWUSR : S_IRUGO; proc_create(leaf->name, mask, sg_proc_sgp, leaf->fops); } @@ -2533,9 +2548,9 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) fp->reserve.bufflen, (int) fp->reserve.k_use_sg, (int) fp->low_dma); - seq_printf(s, " cmd_q=%d f_packid=%d k_orphan=%d closed=%d\n", + seq_printf(s, " cmd_q=%d f_packid=%d k_orphan=%d closed=0\n", (int) fp->cmd_q, (int) fp->force_packid, - (int) fp->keep_orphan, (int) fp->closed); + (int) fp->keep_orphan); for (m = 0, srp = fp->headrp; srp != NULL; ++m, srp = srp->nextrp) { @@ -2612,7 +2627,7 @@ static int sg_proc_seq_show_debug(struct seq_file *s, void *v) scsidp->lun, scsidp->host->hostt->emulated); seq_printf(s, " sg_tablesize=%d excl=%d\n", - sdp->sg_tablesize, sdp->exclude); + sdp->sg_tablesize, get_exclude(sdp)); sg_proc_debug_helper(s, sdp); } read_unlock_irqrestore(&sg_index_lock, iflags); diff --git a/trunk/drivers/scsi/st.h b/trunk/drivers/scsi/st.h index ea35632b986c..b548923785ed 100644 --- a/trunk/drivers/scsi/st.h +++ b/trunk/drivers/scsi/st.h @@ -35,8 +35,8 @@ struct st_request { /* The tape buffer descriptor. */ struct st_buffer { unsigned char dma; /* DMA-able buffer */ - unsigned char do_dio; /* direct i/o set up? */ unsigned char cleared; /* internal buffer cleared after open? */ + unsigned short do_dio; /* direct i/o set up? */ int buffer_size; int buffer_blocks; int buffer_bytes; diff --git a/trunk/drivers/scsi/storvsc_drv.c b/trunk/drivers/scsi/storvsc_drv.c index 83a1972a1999..528d52beaa1c 100644 --- a/trunk/drivers/scsi/storvsc_drv.c +++ b/trunk/drivers/scsi/storvsc_drv.c @@ -785,12 +785,22 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request) /* * If there is an error; offline the device since all * error recovery strategies would have already been - * deployed on the host side. + * deployed on the host side. However, if the command + * were a pass-through command deal with it appropriately. */ - if (vm_srb->srb_status == SRB_STATUS_ERROR) - scmnd->result = DID_TARGET_FAILURE << 16; - else - scmnd->result = vm_srb->scsi_status; + scmnd->result = vm_srb->scsi_status; + + if (vm_srb->srb_status == SRB_STATUS_ERROR) { + switch (scmnd->cmnd[0]) { + case ATA_16: + case ATA_12: + set_host_byte(scmnd, DID_PASSTHROUGH); + break; + default: + set_host_byte(scmnd, DID_TARGET_FAILURE); + } + } + /* * If the LUN is invalid; remove the device. diff --git a/trunk/drivers/scsi/ufs/ufshcd.c b/trunk/drivers/scsi/ufs/ufshcd.c index 52b96e8bf92e..4e010b727818 100644 --- a/trunk/drivers/scsi/ufs/ufshcd.c +++ b/trunk/drivers/scsi/ufs/ufshcd.c @@ -1032,11 +1032,11 @@ static int ufshcd_initialize_hba(struct ufs_hba *hba) return -EIO; /* Configure UTRL and UTMRL base address registers */ - writel(hba->utrdl_dma_addr, - (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_L)); writel(lower_32_bits(hba->utrdl_dma_addr), + (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_L)); + writel(upper_32_bits(hba->utrdl_dma_addr), (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_H)); - writel(hba->utmrdl_dma_addr, + writel(lower_32_bits(hba->utmrdl_dma_addr), (hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_L)); writel(upper_32_bits(hba->utmrdl_dma_addr), (hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_H)); @@ -1160,7 +1160,7 @@ static int ufshcd_task_req_compl(struct ufs_hba *hba, u32 index) task_result = be32_to_cpu(task_rsp_upiup->header.dword_1); task_result = ((task_result & MASK_TASK_RESPONSE) >> 8); - if (task_result != UPIU_TASK_MANAGEMENT_FUNC_COMPL || + if (task_result != UPIU_TASK_MANAGEMENT_FUNC_COMPL && task_result != UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED) task_result = FAILED; } else { diff --git a/trunk/drivers/spi/spi-imx.c b/trunk/drivers/spi/spi-imx.c index 570f22053be8..69c9a6601f45 100644 --- a/trunk/drivers/spi/spi-imx.c +++ b/trunk/drivers/spi/spi-imx.c @@ -37,6 +37,7 @@ #include #include #include +#include #include @@ -758,6 +759,7 @@ static int __devinit spi_imx_probe(struct platform_device *pdev) struct spi_master *master; struct spi_imx_data *spi_imx; struct resource *res; + struct pinctrl *pinctrl; int i, ret, num_cs; if (!np && !mxc_platform_info) { @@ -845,6 +847,12 @@ static int __devinit spi_imx_probe(struct platform_device *pdev) goto out_iounmap; } + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(pinctrl)) { + ret = PTR_ERR(pinctrl); + goto out_free_irq; + } + spi_imx->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(spi_imx->clk)) { dev_err(&pdev->dev, "unable to get clock\n"); diff --git a/trunk/drivers/staging/Kconfig b/trunk/drivers/staging/Kconfig index 97d412d91458..05e33c700750 100644 --- a/trunk/drivers/staging/Kconfig +++ b/trunk/drivers/staging/Kconfig @@ -24,8 +24,6 @@ menuconfig STAGING if STAGING -source "drivers/staging/serial/Kconfig" - source "drivers/staging/et131x/Kconfig" source "drivers/staging/slicoss/Kconfig" @@ -68,14 +66,10 @@ source "drivers/staging/octeon/Kconfig" source "drivers/staging/serqt_usb2/Kconfig" -source "drivers/staging/quatech_usb2/Kconfig" - source "drivers/staging/vt6655/Kconfig" source "drivers/staging/vt6656/Kconfig" -source "drivers/staging/vme/Kconfig" - source "drivers/staging/sep/Kconfig" source "drivers/staging/iio/Kconfig" @@ -116,12 +110,12 @@ source "drivers/staging/cptm1217/Kconfig" source "drivers/staging/ste_rmi4/Kconfig" -source "drivers/staging/mei/Kconfig" - source "drivers/staging/nvec/Kconfig" source "drivers/staging/media/Kconfig" +source "drivers/staging/net/Kconfig" + source "drivers/staging/omapdrm/Kconfig" source "drivers/staging/android/Kconfig" @@ -132,4 +126,10 @@ source "drivers/staging/ramster/Kconfig" source "drivers/staging/ozwpan/Kconfig" +source "drivers/staging/ccg/Kconfig" + +source "drivers/staging/ipack/Kconfig" + +source "drivers/staging/gdm72xx/Kconfig" + endif # STAGING diff --git a/trunk/drivers/staging/Makefile b/trunk/drivers/staging/Makefile index ffe7d44374e6..a987b3ad380b 100644 --- a/trunk/drivers/staging/Makefile +++ b/trunk/drivers/staging/Makefile @@ -3,8 +3,8 @@ # fix for build system bug... obj-$(CONFIG_STAGING) += staging.o -obj-y += serial/ obj-y += media/ +obj-y += net/ obj-$(CONFIG_ET131X) += et131x/ obj-$(CONFIG_SLICOSS) += slicoss/ obj-$(CONFIG_USBIP_CORE) += usbip/ @@ -25,11 +25,11 @@ obj-$(CONFIG_TRANZPORT) += frontier/ obj-$(CONFIG_IDE_PHISON) += phison/ obj-$(CONFIG_LINE6_USB) += line6/ obj-$(CONFIG_USB_SERIAL_QUATECH2) += serqt_usb2/ -obj-$(CONFIG_USB_SERIAL_QUATECH_USB2) += quatech_usb2/ obj-$(CONFIG_OCTEON_ETHERNET) += octeon/ obj-$(CONFIG_VT6655) += vt6655/ obj-$(CONFIG_VT6656) += vt6656/ obj-$(CONFIG_VME_BUS) += vme/ +obj-$(CONFIG_IPACK_BUS) += ipack/ obj-$(CONFIG_DX_SEP) += sep/ obj-$(CONFIG_IIO) += iio/ obj-$(CONFIG_ZRAM) += zram/ @@ -50,10 +50,11 @@ obj-$(CONFIG_FT1000) += ft1000/ obj-$(CONFIG_SPEAKUP) += speakup/ obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_TM1217) += cptm1217/ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += ste_rmi4/ -obj-$(CONFIG_INTEL_MEI) += mei/ obj-$(CONFIG_MFD_NVEC) += nvec/ obj-$(CONFIG_DRM_OMAP) += omapdrm/ obj-$(CONFIG_ANDROID) += android/ obj-$(CONFIG_PHONE) += telephony/ obj-$(CONFIG_RAMSTER) += ramster/ obj-$(CONFIG_USB_WPAN_HCD) += ozwpan/ +obj-$(CONFIG_USB_G_CCG) += ccg/ +obj-$(CONFIG_WIMAX_GDM72XX) += gdm72xx/ diff --git a/trunk/drivers/staging/android/Kconfig b/trunk/drivers/staging/android/Kconfig index eb1dee26bda3..0e16b594460f 100644 --- a/trunk/drivers/staging/android/Kconfig +++ b/trunk/drivers/staging/android/Kconfig @@ -25,17 +25,9 @@ config ANDROID_LOGGER tristate "Android log driver" default n -config ANDROID_PERSISTENT_RAM - bool - depends on HAVE_MEMBLOCK - select REED_SOLOMON - select REED_SOLOMON_ENC8 - select REED_SOLOMON_DEC8 - config ANDROID_RAM_CONSOLE bool "Android RAM buffer console" - depends on !S390 && !UML && HAVE_MEMBLOCK - select ANDROID_PERSISTENT_RAM + depends on !S390 && !UML && HAVE_MEMBLOCK && PSTORE_RAM=y default n config ANDROID_TIMED_OUTPUT @@ -53,33 +45,14 @@ config ANDROID_LOW_MEMORY_KILLER ---help--- Register processes to be killed when memory is low -source "drivers/staging/android/switch/Kconfig" - -config ANDROID_INTF_ALARM +config ANDROID_INTF_ALARM_DEV bool "Android alarm driver" depends on RTC_CLASS default n help Provides non-wakeup and rtc backed wakeup alarms based on rtc or elapsed realtime, and a non-wakeup alarm on the monotonic clock. - Also provides an interface to set the wall time which must be used - for elapsed realtime to work. - -config ANDROID_INTF_ALARM_DEV - bool "Android alarm device" - depends on ANDROID_INTF_ALARM - default y - help - Exports the alarm interface to user-space. - -config ANDROID_ALARM_OLDDRV_COMPAT - bool "Android Alarm compatability with old drivers" - depends on ANDROID_INTF_ALARM - default n - help - Provides preprocessor alias to aid compatability with - older out-of-tree drivers that use the Android Alarm - in-kernel API. This will be removed eventually. + Also exports the alarm interface to user-space. endif # if ANDROID diff --git a/trunk/drivers/staging/android/Makefile b/trunk/drivers/staging/android/Makefile index 9b6c9ed91f69..98711e2b2afa 100644 --- a/trunk/drivers/staging/android/Makefile +++ b/trunk/drivers/staging/android/Makefile @@ -1,11 +1,8 @@ obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o obj-$(CONFIG_ASHMEM) += ashmem.o obj-$(CONFIG_ANDROID_LOGGER) += logger.o -obj-$(CONFIG_ANDROID_PERSISTENT_RAM) += persistent_ram.o obj-$(CONFIG_ANDROID_RAM_CONSOLE) += ram_console.o obj-$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o obj-$(CONFIG_ANDROID_TIMED_GPIO) += timed_gpio.o obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o -obj-$(CONFIG_ANDROID_SWITCH) += switch/ -obj-$(CONFIG_ANDROID_INTF_ALARM) += alarm.o obj-$(CONFIG_ANDROID_INTF_ALARM_DEV) += alarm-dev.o diff --git a/trunk/drivers/staging/android/alarm-dev.c b/trunk/drivers/staging/android/alarm-dev.c index 03efb34cbe2e..53ce6ecf390a 100644 --- a/trunk/drivers/staging/android/alarm-dev.c +++ b/trunk/drivers/staging/android/alarm-dev.c @@ -22,19 +22,9 @@ #include #include #include +#include #include "android_alarm.h" -/* XXX - Hack out wakelocks, while they are out of tree */ -struct wake_lock { - int i; -}; -#define wake_lock(x) -#define wake_lock_timeout(x, y) -#define wake_unlock(x) -#define WAKE_LOCK_SUSPEND 0 -#define wake_lock_init(x, y, z) ((x)->i = 1) -#define wake_lock_destroy(x) - #define ANDROID_ALARM_PRINT_INFO (1U << 0) #define ANDROID_ALARM_PRINT_IO (1U << 1) #define ANDROID_ALARM_PRINT_INT (1U << 2) @@ -54,19 +44,65 @@ module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP); ANDROID_ALARM_RTC_WAKEUP_MASK | \ ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK) -/* support old usespace code */ +/* support old userspace code */ #define ANDROID_ALARM_SET_OLD _IOW('a', 2, time_t) /* set alarm */ #define ANDROID_ALARM_SET_AND_WAIT_OLD _IOW('a', 3, time_t) static int alarm_opened; static DEFINE_SPINLOCK(alarm_slock); -static struct wake_lock alarm_wake_lock; +static struct wakeup_source alarm_wake_lock; static DECLARE_WAIT_QUEUE_HEAD(alarm_wait_queue); static uint32_t alarm_pending; static uint32_t alarm_enabled; static uint32_t wait_pending; -static struct android_alarm alarms[ANDROID_ALARM_TYPE_COUNT]; +struct devalarm { + union { + struct hrtimer hrt; + struct alarm alrm; + } u; + enum android_alarm_type type; +}; + +static struct devalarm alarms[ANDROID_ALARM_TYPE_COUNT]; + + +static int is_wakeup(enum android_alarm_type type) +{ + if (type == ANDROID_ALARM_RTC_WAKEUP || + type == ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP) + return 1; + return 0; +} + + +static void devalarm_start(struct devalarm *alrm, ktime_t exp) +{ + if (is_wakeup(alrm->type)) + alarm_start(&alrm->u.alrm, exp); + else + hrtimer_start(&alrm->u.hrt, exp, HRTIMER_MODE_ABS); +} + + +static int devalarm_try_to_cancel(struct devalarm *alrm) +{ + int ret; + if (is_wakeup(alrm->type)) + ret = alarm_try_to_cancel(&alrm->u.alrm); + else + ret = hrtimer_try_to_cancel(&alrm->u.hrt); + return ret; +} + +static void devalarm_cancel(struct devalarm *alrm) +{ + if (is_wakeup(alrm->type)) + alarm_cancel(&alrm->u.alrm); + else + hrtimer_cancel(&alrm->u.hrt); +} + static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -75,6 +111,8 @@ static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct timespec new_alarm_time; struct timespec new_rtc_time; struct timespec tmp_time; + struct rtc_time new_rtc_tm; + struct rtc_device *rtc_dev; enum android_alarm_type alarm_type = ANDROID_ALARM_IOCTL_TO_TYPE(cmd); uint32_t alarm_type_mask = 1U << alarm_type; @@ -101,11 +139,11 @@ static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case ANDROID_ALARM_CLEAR(0): spin_lock_irqsave(&alarm_slock, flags); pr_alarm(IO, "alarm %d clear\n", alarm_type); - android_alarm_try_to_cancel(&alarms[alarm_type]); + devalarm_try_to_cancel(&alarms[alarm_type]); if (alarm_pending) { alarm_pending &= ~alarm_type_mask; if (!alarm_pending && !wait_pending) - wake_unlock(&alarm_wake_lock); + __pm_relax(&alarm_wake_lock); } alarm_enabled &= ~alarm_type_mask; spin_unlock_irqrestore(&alarm_slock, flags); @@ -132,8 +170,7 @@ static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) pr_alarm(IO, "alarm %d set %ld.%09ld\n", alarm_type, new_alarm_time.tv_sec, new_alarm_time.tv_nsec); alarm_enabled |= alarm_type_mask; - android_alarm_start_range(&alarms[alarm_type], - timespec_to_ktime(new_alarm_time), + devalarm_start(&alarms[alarm_type], timespec_to_ktime(new_alarm_time)); spin_unlock_irqrestore(&alarm_slock, flags); if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_SET_AND_WAIT(0) @@ -144,7 +181,7 @@ static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) spin_lock_irqsave(&alarm_slock, flags); pr_alarm(IO, "alarm wait\n"); if (!alarm_pending && wait_pending) { - wake_unlock(&alarm_wake_lock); + __pm_relax(&alarm_wake_lock); wait_pending = 0; } spin_unlock_irqrestore(&alarm_slock, flags); @@ -163,7 +200,13 @@ static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) rv = -EFAULT; goto err1; } - rv = android_alarm_set_rtc(new_rtc_time); + rtc_time_to_tm(new_rtc_time.tv_sec, &new_rtc_tm); + rtc_dev = alarmtimer_get_rtcdev(); + rv = do_settimeofday(&new_rtc_time); + if (rv < 0) + goto err1; + if (rtc_dev) + rv = rtc_set_time(rtc_dev, &new_rtc_tm); spin_lock_irqsave(&alarm_slock, flags); alarm_pending |= ANDROID_ALARM_TIME_CHANGE_MASK; wake_up(&alarm_wait_queue); @@ -179,8 +222,7 @@ static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; case ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP: case ANDROID_ALARM_ELAPSED_REALTIME: - tmp_time = - ktime_to_timespec(alarm_get_elapsed_realtime()); + get_monotonic_boottime(&tmp_time); break; case ANDROID_ALARM_TYPE_COUNT: case ANDROID_ALARM_SYSTEMTIME: @@ -224,14 +266,14 @@ static int alarm_release(struct inode *inode, struct file *file) alarm_enabled &= ~alarm_type_mask; } spin_unlock_irqrestore(&alarm_slock, flags); - android_alarm_cancel(&alarms[i]); + devalarm_cancel(&alarms[i]); spin_lock_irqsave(&alarm_slock, flags); } if (alarm_pending | wait_pending) { if (alarm_pending) pr_alarm(INFO, "alarm_release: clear " "pending alarms %x\n", alarm_pending); - wake_unlock(&alarm_wake_lock); + __pm_relax(&alarm_wake_lock); wait_pending = 0; alarm_pending = 0; } @@ -241,15 +283,15 @@ static int alarm_release(struct inode *inode, struct file *file) return 0; } -static void alarm_triggered(struct android_alarm *alarm) +static void devalarm_triggered(struct devalarm *alarm) { unsigned long flags; uint32_t alarm_type_mask = 1U << alarm->type; - pr_alarm(INT, "alarm_triggered type %d\n", alarm->type); + pr_alarm(INT, "devalarm_triggered type %d\n", alarm->type); spin_lock_irqsave(&alarm_slock, flags); if (alarm_enabled & alarm_type_mask) { - wake_lock_timeout(&alarm_wake_lock, 5 * HZ); + __pm_wakeup_event(&alarm_wake_lock, 5000); /* 5secs */ alarm_enabled &= ~alarm_type_mask; alarm_pending |= alarm_type_mask; wake_up(&alarm_wait_queue); @@ -257,6 +299,25 @@ static void alarm_triggered(struct android_alarm *alarm) spin_unlock_irqrestore(&alarm_slock, flags); } + +static enum hrtimer_restart devalarm_hrthandler(struct hrtimer *hrt) +{ + struct devalarm *devalrm = container_of(hrt, struct devalarm, u.hrt); + + devalarm_triggered(devalrm); + return HRTIMER_NORESTART; +} + +static enum alarmtimer_restart devalarm_alarmhandler(struct alarm *alrm, + ktime_t now) +{ + struct devalarm *devalrm = container_of(alrm, struct devalarm, u.alrm); + + devalarm_triggered(devalrm); + return ALARMTIMER_NORESTART; +} + + static const struct file_operations alarm_fops = { .owner = THIS_MODULE, .unlocked_ioctl = alarm_ioctl, @@ -279,17 +340,31 @@ static int __init alarm_dev_init(void) if (err) return err; - for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) - android_alarm_init(&alarms[i], i, alarm_triggered); - wake_lock_init(&alarm_wake_lock, WAKE_LOCK_SUSPEND, "alarm"); + alarm_init(&alarms[ANDROID_ALARM_RTC_WAKEUP].u.alrm, + ALARM_REALTIME, devalarm_alarmhandler); + hrtimer_init(&alarms[ANDROID_ALARM_RTC].u.hrt, + CLOCK_REALTIME, HRTIMER_MODE_ABS); + alarm_init(&alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].u.alrm, + ALARM_BOOTTIME, devalarm_alarmhandler); + hrtimer_init(&alarms[ANDROID_ALARM_ELAPSED_REALTIME].u.hrt, + CLOCK_BOOTTIME, HRTIMER_MODE_ABS); + hrtimer_init(&alarms[ANDROID_ALARM_SYSTEMTIME].u.hrt, + CLOCK_MONOTONIC, HRTIMER_MODE_ABS); + + for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) { + alarms[i].type = i; + if (!is_wakeup(i)) + alarms[i].u.hrt.function = devalarm_hrthandler; + } + wakeup_source_init(&alarm_wake_lock, "alarm"); return 0; } static void __exit alarm_dev_exit(void) { misc_deregister(&alarm_device); - wake_lock_destroy(&alarm_wake_lock); + wakeup_source_trash(&alarm_wake_lock); } module_init(alarm_dev_init); diff --git a/trunk/drivers/staging/android/alarm.c b/trunk/drivers/staging/android/alarm.c deleted file mode 100644 index c68950b9e08f..000000000000 --- a/trunk/drivers/staging/android/alarm.c +++ /dev/null @@ -1,601 +0,0 @@ -/* drivers/rtc/alarm.c - * - * Copyright (C) 2007-2009 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "android_alarm.h" - -/* XXX - Hack out wakelocks, while they are out of tree */ -struct wake_lock { - int i; -}; -#define wake_lock(x) -#define wake_lock_timeout(x, y) -#define wake_unlock(x) -#define WAKE_LOCK_SUSPEND 0 -#define wake_lock_init(x, y, z) ((x)->i = 1) -#define wake_lock_destroy(x) - -#define ANDROID_ALARM_PRINT_ERROR (1U << 0) -#define ANDROID_ALARM_PRINT_INIT_STATUS (1U << 1) -#define ANDROID_ALARM_PRINT_TSET (1U << 2) -#define ANDROID_ALARM_PRINT_CALL (1U << 3) -#define ANDROID_ALARM_PRINT_SUSPEND (1U << 4) -#define ANDROID_ALARM_PRINT_INT (1U << 5) -#define ANDROID_ALARM_PRINT_FLOW (1U << 6) - -static int debug_mask = ANDROID_ALARM_PRINT_ERROR | \ - ANDROID_ALARM_PRINT_INIT_STATUS; -module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP); - -#define pr_alarm(debug_level_mask, args...) \ - do { \ - if (debug_mask & ANDROID_ALARM_PRINT_##debug_level_mask) { \ - pr_info(args); \ - } \ - } while (0) - -#define ANDROID_ALARM_WAKEUP_MASK ( \ - ANDROID_ALARM_RTC_WAKEUP_MASK | \ - ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK) - -/* support old usespace code */ -#define ANDROID_ALARM_SET_OLD _IOW('a', 2, time_t) /* set alarm */ -#define ANDROID_ALARM_SET_AND_WAIT_OLD _IOW('a', 3, time_t) - -struct alarm_queue { - struct rb_root alarms; - struct rb_node *first; - struct hrtimer timer; - ktime_t delta; - bool stopped; - ktime_t stopped_time; -}; - -static struct rtc_device *alarm_rtc_dev; -static DEFINE_SPINLOCK(alarm_slock); -static DEFINE_MUTEX(alarm_setrtc_mutex); -static struct wake_lock alarm_rtc_wake_lock; -static struct platform_device *alarm_platform_dev; -struct alarm_queue alarms[ANDROID_ALARM_TYPE_COUNT]; -static bool suspended; - -static void update_timer_locked(struct alarm_queue *base, bool head_removed) -{ - struct android_alarm *alarm; - bool is_wakeup = base == &alarms[ANDROID_ALARM_RTC_WAKEUP] || - base == &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP]; - - if (base->stopped) { - pr_alarm(FLOW, "changed alarm while setting the wall time\n"); - return; - } - - if (is_wakeup && !suspended && head_removed) - wake_unlock(&alarm_rtc_wake_lock); - - if (!base->first) - return; - - alarm = container_of(base->first, struct android_alarm, node); - - pr_alarm(FLOW, "selected alarm, type %d, func %pF at %lld\n", - alarm->type, alarm->function, ktime_to_ns(alarm->expires)); - - if (is_wakeup && suspended) { - pr_alarm(FLOW, "changed alarm while suspened\n"); - wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ); - return; - } - - hrtimer_try_to_cancel(&base->timer); - base->timer.node.expires = ktime_add(base->delta, alarm->expires); - base->timer._softexpires = ktime_add(base->delta, alarm->softexpires); - hrtimer_start_expires(&base->timer, HRTIMER_MODE_ABS); -} - -static void alarm_enqueue_locked(struct android_alarm *alarm) -{ - struct alarm_queue *base = &alarms[alarm->type]; - struct rb_node **link = &base->alarms.rb_node; - struct rb_node *parent = NULL; - struct android_alarm *entry; - int leftmost = 1; - bool was_first = false; - - pr_alarm(FLOW, "added alarm, type %d, func %pF at %lld\n", - alarm->type, alarm->function, ktime_to_ns(alarm->expires)); - - if (base->first == &alarm->node) { - base->first = rb_next(&alarm->node); - was_first = true; - } - if (!RB_EMPTY_NODE(&alarm->node)) { - rb_erase(&alarm->node, &base->alarms); - RB_CLEAR_NODE(&alarm->node); - } - - while (*link) { - parent = *link; - entry = rb_entry(parent, struct android_alarm, node); - /* - * We dont care about collisions. Nodes with - * the same expiry time stay together. - */ - if (alarm->expires.tv64 < entry->expires.tv64) { - link = &(*link)->rb_left; - } else { - link = &(*link)->rb_right; - leftmost = 0; - } - } - if (leftmost) - base->first = &alarm->node; - if (leftmost || was_first) - update_timer_locked(base, was_first); - - rb_link_node(&alarm->node, parent, link); - rb_insert_color(&alarm->node, &base->alarms); -} - -/** - * android_alarm_init - initialize an alarm - * @alarm: the alarm to be initialized - * @type: the alarm type to be used - * @function: alarm callback function - */ -void android_alarm_init(struct android_alarm *alarm, - enum android_alarm_type type, void (*function)(struct android_alarm *)) -{ - RB_CLEAR_NODE(&alarm->node); - alarm->type = type; - alarm->function = function; - - pr_alarm(FLOW, "created alarm, type %d, func %pF\n", type, function); -} - - -/** - * android_alarm_start_range - (re)start an alarm - * @alarm: the alarm to be added - * @start: earliest expiry time - * @end: expiry time - */ -void android_alarm_start_range(struct android_alarm *alarm, ktime_t start, - ktime_t end) -{ - unsigned long flags; - - spin_lock_irqsave(&alarm_slock, flags); - alarm->softexpires = start; - alarm->expires = end; - alarm_enqueue_locked(alarm); - spin_unlock_irqrestore(&alarm_slock, flags); -} - -/** - * android_alarm_try_to_cancel - try to deactivate an alarm - * @alarm: alarm to stop - * - * Returns: - * 0 when the alarm was not active - * 1 when the alarm was active - * -1 when the alarm may currently be excuting the callback function and - * cannot be stopped (it may also be inactive) - */ -int android_alarm_try_to_cancel(struct android_alarm *alarm) -{ - struct alarm_queue *base = &alarms[alarm->type]; - unsigned long flags; - bool first = false; - int ret = 0; - - spin_lock_irqsave(&alarm_slock, flags); - if (!RB_EMPTY_NODE(&alarm->node)) { - pr_alarm(FLOW, "canceled alarm, type %d, func %pF at %lld\n", - alarm->type, alarm->function, - ktime_to_ns(alarm->expires)); - ret = 1; - if (base->first == &alarm->node) { - base->first = rb_next(&alarm->node); - first = true; - } - rb_erase(&alarm->node, &base->alarms); - RB_CLEAR_NODE(&alarm->node); - if (first) - update_timer_locked(base, true); - } else - pr_alarm(FLOW, "tried to cancel alarm, type %d, func %pF\n", - alarm->type, alarm->function); - spin_unlock_irqrestore(&alarm_slock, flags); - if (!ret && hrtimer_callback_running(&base->timer)) - ret = -1; - return ret; -} - -/** - * android_alarm_cancel - cancel an alarm and wait for the handler to finish. - * @alarm: the alarm to be cancelled - * - * Returns: - * 0 when the alarm was not active - * 1 when the alarm was active - */ -int android_alarm_cancel(struct android_alarm *alarm) -{ - for (;;) { - int ret = android_alarm_try_to_cancel(alarm); - if (ret >= 0) - return ret; - cpu_relax(); - } -} - -/** - * alarm_set_rtc - set the kernel and rtc walltime - * @new_time: timespec value containing the new time - */ -int android_alarm_set_rtc(struct timespec new_time) -{ - int i; - int ret; - unsigned long flags; - struct rtc_time rtc_new_rtc_time; - struct timespec tmp_time; - - rtc_time_to_tm(new_time.tv_sec, &rtc_new_rtc_time); - - pr_alarm(TSET, "set rtc %ld %ld - rtc %02d:%02d:%02d %02d/%02d/%04d\n", - new_time.tv_sec, new_time.tv_nsec, - rtc_new_rtc_time.tm_hour, rtc_new_rtc_time.tm_min, - rtc_new_rtc_time.tm_sec, rtc_new_rtc_time.tm_mon + 1, - rtc_new_rtc_time.tm_mday, - rtc_new_rtc_time.tm_year + 1900); - - mutex_lock(&alarm_setrtc_mutex); - spin_lock_irqsave(&alarm_slock, flags); - wake_lock(&alarm_rtc_wake_lock); - getnstimeofday(&tmp_time); - for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) { - hrtimer_try_to_cancel(&alarms[i].timer); - alarms[i].stopped = true; - alarms[i].stopped_time = timespec_to_ktime(tmp_time); - } - alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].delta = - alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta = - ktime_sub(alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta, - timespec_to_ktime(timespec_sub(tmp_time, new_time))); - spin_unlock_irqrestore(&alarm_slock, flags); - ret = do_settimeofday(&new_time); - spin_lock_irqsave(&alarm_slock, flags); - for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) { - alarms[i].stopped = false; - update_timer_locked(&alarms[i], false); - } - spin_unlock_irqrestore(&alarm_slock, flags); - if (ret < 0) { - pr_alarm(ERROR, "alarm_set_rtc: Failed to set time\n"); - goto err; - } - if (!alarm_rtc_dev) { - pr_alarm(ERROR, - "alarm_set_rtc: no RTC, time will be lost on reboot\n"); - goto err; - } - ret = rtc_set_time(alarm_rtc_dev, &rtc_new_rtc_time); - if (ret < 0) - pr_alarm(ERROR, "alarm_set_rtc: " - "Failed to set RTC, time will be lost on reboot\n"); -err: - wake_unlock(&alarm_rtc_wake_lock); - mutex_unlock(&alarm_setrtc_mutex); - return ret; -} - -/** - * alarm_get_elapsed_realtime - get the elapsed real time in ktime_t format - * - * returns the time in ktime_t format - */ -ktime_t alarm_get_elapsed_realtime(void) -{ - ktime_t now; - unsigned long flags; - struct alarm_queue *base = &alarms[ANDROID_ALARM_ELAPSED_REALTIME]; - - spin_lock_irqsave(&alarm_slock, flags); - now = base->stopped ? base->stopped_time : ktime_get_real(); - now = ktime_sub(now, base->delta); - spin_unlock_irqrestore(&alarm_slock, flags); - return now; -} - -static enum hrtimer_restart alarm_timer_triggered(struct hrtimer *timer) -{ - struct alarm_queue *base; - struct android_alarm *alarm; - unsigned long flags; - ktime_t now; - - spin_lock_irqsave(&alarm_slock, flags); - - base = container_of(timer, struct alarm_queue, timer); - now = base->stopped ? base->stopped_time : hrtimer_cb_get_time(timer); - now = ktime_sub(now, base->delta); - - pr_alarm(INT, "alarm_timer_triggered type %ld at %lld\n", - base - alarms, ktime_to_ns(now)); - - while (base->first) { - alarm = container_of(base->first, struct android_alarm, node); - if (alarm->softexpires.tv64 > now.tv64) { - pr_alarm(FLOW, "don't call alarm, %pF, %lld (s %lld)\n", - alarm->function, ktime_to_ns(alarm->expires), - ktime_to_ns(alarm->softexpires)); - break; - } - base->first = rb_next(&alarm->node); - rb_erase(&alarm->node, &base->alarms); - RB_CLEAR_NODE(&alarm->node); - pr_alarm(CALL, "call alarm, type %d, func %pF, %lld (s %lld)\n", - alarm->type, alarm->function, - ktime_to_ns(alarm->expires), - ktime_to_ns(alarm->softexpires)); - spin_unlock_irqrestore(&alarm_slock, flags); - alarm->function(alarm); - spin_lock_irqsave(&alarm_slock, flags); - } - if (!base->first) - pr_alarm(FLOW, "no more alarms of type %ld\n", base - alarms); - update_timer_locked(base, true); - spin_unlock_irqrestore(&alarm_slock, flags); - return HRTIMER_NORESTART; -} - -static void alarm_triggered_func(void *p) -{ - struct rtc_device *rtc = alarm_rtc_dev; - if (!(rtc->irq_data & RTC_AF)) - return; - pr_alarm(INT, "rtc alarm triggered\n"); - wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ); -} - -static int alarm_suspend(struct platform_device *pdev, pm_message_t state) -{ - int err = 0; - unsigned long flags; - struct rtc_wkalrm rtc_alarm; - struct rtc_time rtc_current_rtc_time; - unsigned long rtc_current_time; - unsigned long rtc_alarm_time; - struct timespec rtc_delta; - struct timespec wall_time; - struct alarm_queue *wakeup_queue = NULL; - struct alarm_queue *tmp_queue = NULL; - - pr_alarm(SUSPEND, "alarm_suspend(%p, %d)\n", pdev, state.event); - - spin_lock_irqsave(&alarm_slock, flags); - suspended = true; - spin_unlock_irqrestore(&alarm_slock, flags); - - hrtimer_cancel(&alarms[ANDROID_ALARM_RTC_WAKEUP].timer); - hrtimer_cancel(&alarms[ - ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].timer); - - tmp_queue = &alarms[ANDROID_ALARM_RTC_WAKEUP]; - if (tmp_queue->first) - wakeup_queue = tmp_queue; - tmp_queue = &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP]; - if (tmp_queue->first && (!wakeup_queue || - hrtimer_get_expires(&tmp_queue->timer).tv64 < - hrtimer_get_expires(&wakeup_queue->timer).tv64)) - wakeup_queue = tmp_queue; - if (wakeup_queue) { - rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time); - getnstimeofday(&wall_time); - rtc_tm_to_time(&rtc_current_rtc_time, &rtc_current_time); - set_normalized_timespec(&rtc_delta, - wall_time.tv_sec - rtc_current_time, - wall_time.tv_nsec); - - rtc_alarm_time = timespec_sub(ktime_to_timespec( - hrtimer_get_expires(&wakeup_queue->timer)), - rtc_delta).tv_sec; - - rtc_time_to_tm(rtc_alarm_time, &rtc_alarm.time); - rtc_alarm.enabled = 1; - rtc_set_alarm(alarm_rtc_dev, &rtc_alarm); - rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time); - rtc_tm_to_time(&rtc_current_rtc_time, &rtc_current_time); - pr_alarm(SUSPEND, - "rtc alarm set at %ld, now %ld, rtc delta %ld.%09ld\n", - rtc_alarm_time, rtc_current_time, - rtc_delta.tv_sec, rtc_delta.tv_nsec); - if (rtc_current_time + 1 >= rtc_alarm_time) { - pr_alarm(SUSPEND, "alarm about to go off\n"); - memset(&rtc_alarm, 0, sizeof(rtc_alarm)); - rtc_alarm.enabled = 0; - rtc_set_alarm(alarm_rtc_dev, &rtc_alarm); - - spin_lock_irqsave(&alarm_slock, flags); - suspended = false; - wake_lock_timeout(&alarm_rtc_wake_lock, 2 * HZ); - update_timer_locked(&alarms[ANDROID_ALARM_RTC_WAKEUP], - false); - update_timer_locked(&alarms[ - ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP], false); - err = -EBUSY; - spin_unlock_irqrestore(&alarm_slock, flags); - } - } - return err; -} - -static int alarm_resume(struct platform_device *pdev) -{ - struct rtc_wkalrm alarm; - unsigned long flags; - - pr_alarm(SUSPEND, "alarm_resume(%p)\n", pdev); - - memset(&alarm, 0, sizeof(alarm)); - alarm.enabled = 0; - rtc_set_alarm(alarm_rtc_dev, &alarm); - - spin_lock_irqsave(&alarm_slock, flags); - suspended = false; - update_timer_locked(&alarms[ANDROID_ALARM_RTC_WAKEUP], false); - update_timer_locked(&alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP], - false); - spin_unlock_irqrestore(&alarm_slock, flags); - - return 0; -} - -static struct rtc_task alarm_rtc_task = { - .func = alarm_triggered_func -}; - -static int rtc_alarm_add_device(struct device *dev, - struct class_interface *class_intf) -{ - int err; - struct rtc_device *rtc = to_rtc_device(dev); - - mutex_lock(&alarm_setrtc_mutex); - - if (alarm_rtc_dev) { - err = -EBUSY; - goto err1; - } - - alarm_platform_dev = - platform_device_register_simple("alarm", -1, NULL, 0); - if (IS_ERR(alarm_platform_dev)) { - err = PTR_ERR(alarm_platform_dev); - goto err2; - } - err = rtc_irq_register(rtc, &alarm_rtc_task); - if (err) - goto err3; - alarm_rtc_dev = rtc; - pr_alarm(INIT_STATUS, "using rtc device, %s, for alarms", rtc->name); - mutex_unlock(&alarm_setrtc_mutex); - - return 0; - -err3: - platform_device_unregister(alarm_platform_dev); -err2: -err1: - mutex_unlock(&alarm_setrtc_mutex); - return err; -} - -static void rtc_alarm_remove_device(struct device *dev, - struct class_interface *class_intf) -{ - if (dev == &alarm_rtc_dev->dev) { - pr_alarm(INIT_STATUS, "lost rtc device for alarms"); - rtc_irq_unregister(alarm_rtc_dev, &alarm_rtc_task); - platform_device_unregister(alarm_platform_dev); - alarm_rtc_dev = NULL; - } -} - -static struct class_interface rtc_alarm_interface = { - .add_dev = &rtc_alarm_add_device, - .remove_dev = &rtc_alarm_remove_device, -}; - -static struct platform_driver alarm_driver = { - .suspend = alarm_suspend, - .resume = alarm_resume, - .driver = { - .name = "alarm" - } -}; - -static int __init alarm_late_init(void) -{ - unsigned long flags; - struct timespec tmp_time, system_time; - - /* this needs to run after the rtc is read at boot */ - spin_lock_irqsave(&alarm_slock, flags); - /* We read the current rtc and system time so we can later calulate - * elasped realtime to be (boot_systemtime + rtc - boot_rtc) == - * (rtc - (boot_rtc - boot_systemtime)) - */ - getnstimeofday(&tmp_time); - ktime_get_ts(&system_time); - alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].delta = - alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta = - timespec_to_ktime(timespec_sub(tmp_time, system_time)); - - spin_unlock_irqrestore(&alarm_slock, flags); - return 0; -} - -static int __init alarm_driver_init(void) -{ - int err; - int i; - - for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) { - hrtimer_init(&alarms[i].timer, - CLOCK_REALTIME, HRTIMER_MODE_ABS); - alarms[i].timer.function = alarm_timer_triggered; - } - hrtimer_init(&alarms[ANDROID_ALARM_SYSTEMTIME].timer, - CLOCK_MONOTONIC, HRTIMER_MODE_ABS); - alarms[ANDROID_ALARM_SYSTEMTIME].timer.function = alarm_timer_triggered; - err = platform_driver_register(&alarm_driver); - if (err < 0) - goto err1; - wake_lock_init(&alarm_rtc_wake_lock, WAKE_LOCK_SUSPEND, "alarm_rtc"); - rtc_alarm_interface.class = rtc_class; - err = class_interface_register(&rtc_alarm_interface); - if (err < 0) - goto err2; - - return 0; - -err2: - wake_lock_destroy(&alarm_rtc_wake_lock); - platform_driver_unregister(&alarm_driver); -err1: - return err; -} - -static void __exit alarm_exit(void) -{ - class_interface_unregister(&rtc_alarm_interface); - wake_lock_destroy(&alarm_rtc_wake_lock); - platform_driver_unregister(&alarm_driver); -} - -late_initcall(alarm_late_init); -module_init(alarm_driver_init); -module_exit(alarm_exit); - diff --git a/trunk/drivers/staging/android/android_alarm.h b/trunk/drivers/staging/android/android_alarm.h index 6eecbde2ef6f..d0cafd637199 100644 --- a/trunk/drivers/staging/android/android_alarm.h +++ b/trunk/drivers/staging/android/android_alarm.h @@ -33,65 +33,6 @@ enum android_alarm_type { /* ANDROID_ALARM_TIME_CHANGE = 16 */ }; -#ifdef __KERNEL__ - -#include -#include - -/* - * The alarm interface is similar to the hrtimer interface but adds support - * for wakeup from suspend. It also adds an elapsed realtime clock that can - * be used for periodic timers that need to keep runing while the system is - * suspended and not be disrupted when the wall time is set. - */ - -/** - * struct alarm - the basic alarm structure - * @node: red black tree node for time ordered insertion - * @type: alarm type. rtc/elapsed-realtime/systemtime, wakeup/non-wakeup. - * @softexpires: the absolute earliest expiry time of the alarm. - * @expires: the absolute expiry time. - * @function: alarm expiry callback function - * - * The alarm structure must be initialized by alarm_init() - * - */ - -struct android_alarm { - struct rb_node node; - enum android_alarm_type type; - ktime_t softexpires; - ktime_t expires; - void (*function)(struct android_alarm *); -}; - -void android_alarm_init(struct android_alarm *alarm, - enum android_alarm_type type, void (*function)(struct android_alarm *)); -void android_alarm_start_range(struct android_alarm *alarm, ktime_t start, - ktime_t end); -int android_alarm_try_to_cancel(struct android_alarm *alarm); -int android_alarm_cancel(struct android_alarm *alarm); -ktime_t alarm_get_elapsed_realtime(void); - -/* set rtc while preserving elapsed realtime */ -int android_alarm_set_rtc(const struct timespec ts); - -#ifdef CONFIG_ANDROID_ALARM_OLDDRV_COMPAT -/* - * Some older drivers depend on the old API, - * so provide compatability macros for now. - */ -#define alarm android_alarm -#define alarm_init(x, y, z) android_alarm_init(x, y, z) -#define alarm_start_range(x, y, z) android_alarm_start_range(x, y, z) -#define alarm_try_to_cancel(x) android_alarm_try_to_cancel(x) -#define alarm_cancel(x) android_alarm_cancel(x) -#define alarm_set_rtc(x) android_alarm_set_rtc(x) -#endif - - -#endif - enum android_alarm_return_flags { ANDROID_ALARM_RTC_WAKEUP_MASK = 1U << ANDROID_ALARM_RTC_WAKEUP, ANDROID_ALARM_RTC_MASK = 1U << ANDROID_ALARM_RTC, diff --git a/trunk/drivers/staging/android/binder.h b/trunk/drivers/staging/android/binder.h index 25ab6f2759e9..2f7d195d8b15 100644 --- a/trunk/drivers/staging/android/binder.h +++ b/trunk/drivers/staging/android/binder.h @@ -53,17 +53,17 @@ struct flat_binder_object { /* 8 bytes of data. */ union { - void *binder; /* local object */ + void __user *binder; /* local object */ signed long handle; /* remote object */ }; /* extra data associated with local object */ - void *cookie; + void __user *cookie; }; /* * On 64-bit platforms where user code may run in 32-bits the driver must - * translate the buffer (and local binder) addresses apropriately. + * translate the buffer (and local binder) addresses appropriately. */ struct binder_write_read { @@ -139,9 +139,9 @@ struct binder_transaction_data { union { struct { /* transaction data */ - const void *buffer; + const void __user *buffer; /* offsets from buffer to flat_binder_object structs */ - const void *offsets; + const void __user *offsets; } ptr; uint8_t buf[8]; } data; diff --git a/trunk/drivers/staging/android/logger.c b/trunk/drivers/staging/android/logger.c index ea69b6a77dac..b2e71c6fd175 100644 --- a/trunk/drivers/staging/android/logger.c +++ b/trunk/drivers/staging/android/logger.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "logger.h" #include @@ -45,8 +46,12 @@ struct logger_log { size_t w_off; /* current write head offset */ size_t head; /* new readers start here */ size_t size; /* size of the log */ + struct list_head logs; /* list of log channels (myself)*/ }; +static LIST_HEAD(log_list); + + /* * struct logger_reader - a logging device open for reading * @@ -60,9 +65,9 @@ struct logger_reader { }; /* logger_offset - returns index 'n' into the log via (optimized) modulus */ -size_t logger_offset(struct logger_log *log, size_t n) +static size_t logger_offset(struct logger_log *log, size_t n) { - return n & (log->size-1); + return n & (log->size - 1); } @@ -348,7 +353,7 @@ static ssize_t do_write_log_from_user(struct logger_log *log, * writev(), and aio_write(). Writes are our fast path, and we try to optimize * them above all else. */ -ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov, +static ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t ppos) { struct logger_log *log = file_get_log(iocb->ki_filp); @@ -408,7 +413,15 @@ ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov, return ret; } -static struct logger_log *get_log_from_minor(int); +static struct logger_log *get_log_from_minor(int minor) +{ + struct logger_log *log; + + list_for_each_entry(log, &log_list, logs) + if (log->misc.minor == minor) + return log; + return NULL; +} /* * logger_open - the log's open() file operation @@ -565,80 +578,84 @@ static const struct file_operations logger_fops = { }; /* - * Defines a log structure with name 'NAME' and a size of 'SIZE' bytes, which - * must be a power of two, greater than LOGGER_ENTRY_MAX_LEN, and less than - * LONG_MAX minus LOGGER_ENTRY_MAX_LEN. + * Log size must be a power of two, greater than LOGGER_ENTRY_MAX_LEN, + * and less than LONG_MAX minus LOGGER_ENTRY_MAX_LEN. */ -#define DEFINE_LOGGER_DEVICE(VAR, NAME, SIZE) \ -static unsigned char _buf_ ## VAR[SIZE]; \ -static struct logger_log VAR = { \ - .buffer = _buf_ ## VAR, \ - .misc = { \ - .minor = MISC_DYNAMIC_MINOR, \ - .name = NAME, \ - .fops = &logger_fops, \ - .parent = NULL, \ - }, \ - .wq = __WAIT_QUEUE_HEAD_INITIALIZER(VAR .wq), \ - .readers = LIST_HEAD_INIT(VAR .readers), \ - .mutex = __MUTEX_INITIALIZER(VAR .mutex), \ - .w_off = 0, \ - .head = 0, \ - .size = SIZE, \ -}; +static int __init create_log(char *log_name, int size) +{ + int ret = 0; + struct logger_log *log; + unsigned char *buffer; -DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 256*1024) -DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, 256*1024) -DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 256*1024) -DEFINE_LOGGER_DEVICE(log_system, LOGGER_LOG_SYSTEM, 256*1024) + buffer = vmalloc(size); + if (buffer == NULL) + return -ENOMEM; -static struct logger_log *get_log_from_minor(int minor) -{ - if (log_main.misc.minor == minor) - return &log_main; - if (log_events.misc.minor == minor) - return &log_events; - if (log_radio.misc.minor == minor) - return &log_radio; - if (log_system.misc.minor == minor) - return &log_system; - return NULL; -} + log = kzalloc(sizeof(struct logger_log), GFP_KERNEL); + if (log == NULL) { + ret = -ENOMEM; + goto out_free_buffer; + } + log->buffer = buffer; -static int __init init_log(struct logger_log *log) -{ - int ret; + log->misc.minor = MISC_DYNAMIC_MINOR; + log->misc.name = kstrdup(log_name, GFP_KERNEL); + if (log->misc.name == NULL) { + ret = -ENOMEM; + goto out_free_log; + } + + log->misc.fops = &logger_fops; + log->misc.parent = NULL; + init_waitqueue_head(&log->wq); + INIT_LIST_HEAD(&log->readers); + mutex_init(&log->mutex); + log->w_off = 0; + log->head = 0; + log->size = size; + + INIT_LIST_HEAD(&log->logs); + list_add_tail(&log->logs, &log_list); + + /* finally, initialize the misc device for this log */ ret = misc_register(&log->misc); if (unlikely(ret)) { printk(KERN_ERR "logger: failed to register misc " "device for log '%s'!\n", log->misc.name); - return ret; + goto out_free_log; } printk(KERN_INFO "logger: created %luK log '%s'\n", (unsigned long) log->size >> 10, log->misc.name); return 0; + +out_free_log: + kfree(log); + +out_free_buffer: + vfree(buffer); + return ret; } static int __init logger_init(void) { int ret; - ret = init_log(&log_main); + ret = create_log(LOGGER_LOG_MAIN, 256*1024); if (unlikely(ret)) goto out; - ret = init_log(&log_events); + ret = create_log(LOGGER_LOG_EVENTS, 256*1024); if (unlikely(ret)) goto out; - ret = init_log(&log_radio); + ret = create_log(LOGGER_LOG_RADIO, 256*1024); if (unlikely(ret)) goto out; - ret = init_log(&log_system); + ret = create_log(LOGGER_LOG_SYSTEM, 256*1024); if (unlikely(ret)) goto out; diff --git a/trunk/drivers/staging/android/persistent_ram.c b/trunk/drivers/staging/android/persistent_ram.c deleted file mode 100644 index 8d8c1e33e0ff..000000000000 --- a/trunk/drivers/staging/android/persistent_ram.c +++ /dev/null @@ -1,473 +0,0 @@ -/* - * Copyright (C) 2012 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "persistent_ram.h" - -struct persistent_ram_buffer { - uint32_t sig; - atomic_t start; - atomic_t size; - uint8_t data[0]; -}; - -#define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */ - -static __initdata LIST_HEAD(persistent_ram_list); - -static inline size_t buffer_size(struct persistent_ram_zone *prz) -{ - return atomic_read(&prz->buffer->size); -} - -static inline size_t buffer_start(struct persistent_ram_zone *prz) -{ - return atomic_read(&prz->buffer->start); -} - -/* increase and wrap the start pointer, returning the old value */ -static inline size_t buffer_start_add(struct persistent_ram_zone *prz, size_t a) -{ - int old; - int new; - - do { - old = atomic_read(&prz->buffer->start); - new = old + a; - while (unlikely(new > prz->buffer_size)) - new -= prz->buffer_size; - } while (atomic_cmpxchg(&prz->buffer->start, old, new) != old); - - return old; -} - -/* increase the size counter until it hits the max size */ -static inline void buffer_size_add(struct persistent_ram_zone *prz, size_t a) -{ - size_t old; - size_t new; - - if (atomic_read(&prz->buffer->size) == prz->buffer_size) - return; - - do { - old = atomic_read(&prz->buffer->size); - new = old + a; - if (new > prz->buffer_size) - new = prz->buffer_size; - } while (atomic_cmpxchg(&prz->buffer->size, old, new) != old); -} - -/* increase the size counter, retuning an error if it hits the max size */ -static inline ssize_t buffer_size_add_clamp(struct persistent_ram_zone *prz, - size_t a) -{ - size_t old; - size_t new; - - do { - old = atomic_read(&prz->buffer->size); - new = old + a; - if (new > prz->buffer_size) - return -ENOMEM; - } while (atomic_cmpxchg(&prz->buffer->size, old, new) != old); - - return 0; -} - -static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz, - uint8_t *data, size_t len, uint8_t *ecc) -{ - int i; - uint16_t par[prz->ecc_size]; - - /* Initialize the parity buffer */ - memset(par, 0, sizeof(par)); - encode_rs8(prz->rs_decoder, data, len, par, 0); - for (i = 0; i < prz->ecc_size; i++) - ecc[i] = par[i]; -} - -static int persistent_ram_decode_rs8(struct persistent_ram_zone *prz, - void *data, size_t len, uint8_t *ecc) -{ - int i; - uint16_t par[prz->ecc_size]; - - for (i = 0; i < prz->ecc_size; i++) - par[i] = ecc[i]; - return decode_rs8(prz->rs_decoder, data, par, len, - NULL, 0, NULL, 0, NULL); -} - -static void notrace persistent_ram_update_ecc(struct persistent_ram_zone *prz, - unsigned int start, unsigned int count) -{ - struct persistent_ram_buffer *buffer = prz->buffer; - uint8_t *buffer_end = buffer->data + prz->buffer_size; - uint8_t *block; - uint8_t *par; - int ecc_block_size = prz->ecc_block_size; - int ecc_size = prz->ecc_size; - int size = prz->ecc_block_size; - - if (!prz->ecc) - return; - - block = buffer->data + (start & ~(ecc_block_size - 1)); - par = prz->par_buffer + (start / ecc_block_size) * prz->ecc_size; - - do { - if (block + ecc_block_size > buffer_end) - size = buffer_end - block; - persistent_ram_encode_rs8(prz, block, size, par); - block += ecc_block_size; - par += ecc_size; - } while (block < buffer->data + start + count); -} - -static void persistent_ram_update_header_ecc(struct persistent_ram_zone *prz) -{ - struct persistent_ram_buffer *buffer = prz->buffer; - - if (!prz->ecc) - return; - - persistent_ram_encode_rs8(prz, (uint8_t *)buffer, sizeof(*buffer), - prz->par_header); -} - -static void persistent_ram_ecc_old(struct persistent_ram_zone *prz) -{ - struct persistent_ram_buffer *buffer = prz->buffer; - uint8_t *block; - uint8_t *par; - - if (!prz->ecc) - return; - - block = buffer->data; - par = prz->par_buffer; - while (block < buffer->data + buffer_size(prz)) { - int numerr; - int size = prz->ecc_block_size; - if (block + size > buffer->data + prz->buffer_size) - size = buffer->data + prz->buffer_size - block; - numerr = persistent_ram_decode_rs8(prz, block, size, par); - if (numerr > 0) { - pr_devel("persistent_ram: error in block %p, %d\n", - block, numerr); - prz->corrected_bytes += numerr; - } else if (numerr < 0) { - pr_devel("persistent_ram: uncorrectable error in block %p\n", - block); - prz->bad_blocks++; - } - block += prz->ecc_block_size; - par += prz->ecc_size; - } -} - -static int persistent_ram_init_ecc(struct persistent_ram_zone *prz, - size_t buffer_size) -{ - int numerr; - struct persistent_ram_buffer *buffer = prz->buffer; - int ecc_blocks; - - if (!prz->ecc) - return 0; - - prz->ecc_block_size = 128; - prz->ecc_size = 16; - prz->ecc_symsize = 8; - prz->ecc_poly = 0x11d; - - ecc_blocks = DIV_ROUND_UP(prz->buffer_size, prz->ecc_block_size); - prz->buffer_size -= (ecc_blocks + 1) * prz->ecc_size; - - if (prz->buffer_size > buffer_size) { - pr_err("persistent_ram: invalid size %zu, non-ecc datasize %zu\n", - buffer_size, prz->buffer_size); - return -EINVAL; - } - - prz->par_buffer = buffer->data + prz->buffer_size; - prz->par_header = prz->par_buffer + ecc_blocks * prz->ecc_size; - - /* - * first consecutive root is 0 - * primitive element to generate roots = 1 - */ - prz->rs_decoder = init_rs(prz->ecc_symsize, prz->ecc_poly, 0, 1, - prz->ecc_size); - if (prz->rs_decoder == NULL) { - pr_info("persistent_ram: init_rs failed\n"); - return -EINVAL; - } - - prz->corrected_bytes = 0; - prz->bad_blocks = 0; - - numerr = persistent_ram_decode_rs8(prz, buffer, sizeof(*buffer), - prz->par_header); - if (numerr > 0) { - pr_info("persistent_ram: error in header, %d\n", numerr); - prz->corrected_bytes += numerr; - } else if (numerr < 0) { - pr_info("persistent_ram: uncorrectable error in header\n"); - prz->bad_blocks++; - } - - return 0; -} - -ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz, - char *str, size_t len) -{ - ssize_t ret; - - if (prz->corrected_bytes || prz->bad_blocks) - ret = snprintf(str, len, "" - "\n%d Corrected bytes, %d unrecoverable blocks\n", - prz->corrected_bytes, prz->bad_blocks); - else - ret = snprintf(str, len, "\nNo errors detected\n"); - - return ret; -} - -static void notrace persistent_ram_update(struct persistent_ram_zone *prz, - const void *s, unsigned int start, unsigned int count) -{ - struct persistent_ram_buffer *buffer = prz->buffer; - memcpy(buffer->data + start, s, count); - persistent_ram_update_ecc(prz, start, count); -} - -static void __init -persistent_ram_save_old(struct persistent_ram_zone *prz) -{ - struct persistent_ram_buffer *buffer = prz->buffer; - size_t size = buffer_size(prz); - size_t start = buffer_start(prz); - char *dest; - - persistent_ram_ecc_old(prz); - - dest = kmalloc(size, GFP_KERNEL); - if (dest == NULL) { - pr_err("persistent_ram: failed to allocate buffer\n"); - return; - } - - prz->old_log = dest; - prz->old_log_size = size; - memcpy(prz->old_log, &buffer->data[start], size - start); - memcpy(prz->old_log + size - start, &buffer->data[0], start); -} - -int notrace persistent_ram_write(struct persistent_ram_zone *prz, - const void *s, unsigned int count) -{ - int rem; - int c = count; - size_t start; - - if (unlikely(c > prz->buffer_size)) { - s += c - prz->buffer_size; - c = prz->buffer_size; - } - - buffer_size_add_clamp(prz, c); - - start = buffer_start_add(prz, c); - - rem = prz->buffer_size - start; - if (unlikely(rem < c)) { - persistent_ram_update(prz, s, start, rem); - s += rem; - c -= rem; - start = 0; - } - persistent_ram_update(prz, s, start, c); - - persistent_ram_update_header_ecc(prz); - - return count; -} - -size_t persistent_ram_old_size(struct persistent_ram_zone *prz) -{ - return prz->old_log_size; -} - -void *persistent_ram_old(struct persistent_ram_zone *prz) -{ - return prz->old_log; -} - -void persistent_ram_free_old(struct persistent_ram_zone *prz) -{ - kfree(prz->old_log); - prz->old_log = NULL; - prz->old_log_size = 0; -} - -static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size, - struct persistent_ram_zone *prz) -{ - struct page **pages; - phys_addr_t page_start; - unsigned int page_count; - pgprot_t prot; - unsigned int i; - - page_start = start - offset_in_page(start); - page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE); - - prot = pgprot_noncached(PAGE_KERNEL); - - pages = kmalloc(sizeof(struct page *) * page_count, GFP_KERNEL); - if (!pages) { - pr_err("%s: Failed to allocate array for %u pages\n", __func__, - page_count); - return -ENOMEM; - } - - for (i = 0; i < page_count; i++) { - phys_addr_t addr = page_start + i * PAGE_SIZE; - pages[i] = pfn_to_page(addr >> PAGE_SHIFT); - } - prz->vaddr = vmap(pages, page_count, VM_MAP, prot); - kfree(pages); - if (!prz->vaddr) { - pr_err("%s: Failed to map %u pages\n", __func__, page_count); - return -ENOMEM; - } - - prz->buffer = prz->vaddr + offset_in_page(start); - prz->buffer_size = size - sizeof(struct persistent_ram_buffer); - - return 0; -} - -static int __init persistent_ram_buffer_init(const char *name, - struct persistent_ram_zone *prz) -{ - int i; - struct persistent_ram *ram; - struct persistent_ram_descriptor *desc; - phys_addr_t start; - - list_for_each_entry(ram, &persistent_ram_list, node) { - start = ram->start; - for (i = 0; i < ram->num_descs; i++) { - desc = &ram->descs[i]; - if (!strcmp(desc->name, name)) - return persistent_ram_buffer_map(start, - desc->size, prz); - start += desc->size; - } - } - - return -EINVAL; -} - -static __init -struct persistent_ram_zone *__persistent_ram_init(struct device *dev, bool ecc) -{ - struct persistent_ram_zone *prz; - int ret = -ENOMEM; - - prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL); - if (!prz) { - pr_err("persistent_ram: failed to allocate persistent ram zone\n"); - goto err; - } - - INIT_LIST_HEAD(&prz->node); - - ret = persistent_ram_buffer_init(dev_name(dev), prz); - if (ret) { - pr_err("persistent_ram: failed to initialize buffer\n"); - goto err; - } - - prz->ecc = ecc; - ret = persistent_ram_init_ecc(prz, prz->buffer_size); - if (ret) - goto err; - - if (prz->buffer->sig == PERSISTENT_RAM_SIG) { - if (buffer_size(prz) > prz->buffer_size || - buffer_start(prz) > buffer_size(prz)) - pr_info("persistent_ram: found existing invalid buffer," - " size %ld, start %ld\n", - buffer_size(prz), buffer_start(prz)); - else { - pr_info("persistent_ram: found existing buffer," - " size %ld, start %ld\n", - buffer_size(prz), buffer_start(prz)); - persistent_ram_save_old(prz); - } - } else { - pr_info("persistent_ram: no valid data in buffer" - " (sig = 0x%08x)\n", prz->buffer->sig); - } - - prz->buffer->sig = PERSISTENT_RAM_SIG; - atomic_set(&prz->buffer->start, 0); - atomic_set(&prz->buffer->size, 0); - - return prz; -err: - kfree(prz); - return ERR_PTR(ret); -} - -struct persistent_ram_zone * __init -persistent_ram_init_ringbuffer(struct device *dev, bool ecc) -{ - return __persistent_ram_init(dev, ecc); -} - -int __init persistent_ram_early_init(struct persistent_ram *ram) -{ - int ret; - - ret = memblock_reserve(ram->start, ram->size); - if (ret) { - pr_err("Failed to reserve persistent memory from %08lx-%08lx\n", - (long)ram->start, (long)(ram->start + ram->size - 1)); - return ret; - } - - list_add_tail(&ram->node, &persistent_ram_list); - - pr_info("Initialized persistent memory from %08lx-%08lx\n", - (long)ram->start, (long)(ram->start + ram->size - 1)); - - return 0; -} diff --git a/trunk/drivers/staging/android/persistent_ram.h b/trunk/drivers/staging/android/persistent_ram.h deleted file mode 100644 index f41e2086c645..000000000000 --- a/trunk/drivers/staging/android/persistent_ram.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2011 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 __LINUX_PERSISTENT_RAM_H__ -#define __LINUX_PERSISTENT_RAM_H__ - -#include -#include -#include -#include - -struct persistent_ram_buffer; - -struct persistent_ram_descriptor { - const char *name; - phys_addr_t size; -}; - -struct persistent_ram { - phys_addr_t start; - phys_addr_t size; - - int num_descs; - struct persistent_ram_descriptor *descs; - - struct list_head node; -}; - -struct persistent_ram_zone { - struct list_head node; - void *vaddr; - struct persistent_ram_buffer *buffer; - size_t buffer_size; - - /* ECC correction */ - bool ecc; - char *par_buffer; - char *par_header; - struct rs_control *rs_decoder; - int corrected_bytes; - int bad_blocks; - int ecc_block_size; - int ecc_size; - int ecc_symsize; - int ecc_poly; - - char *old_log; - size_t old_log_size; - size_t old_log_footer_size; - bool early; -}; - -int persistent_ram_early_init(struct persistent_ram *ram); - -struct persistent_ram_zone *persistent_ram_init_ringbuffer(struct device *dev, - bool ecc); - -int persistent_ram_write(struct persistent_ram_zone *prz, const void *s, - unsigned int count); - -size_t persistent_ram_old_size(struct persistent_ram_zone *prz); -void *persistent_ram_old(struct persistent_ram_zone *prz); -void persistent_ram_free_old(struct persistent_ram_zone *prz); -ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz, - char *str, size_t len); - -#endif diff --git a/trunk/drivers/staging/android/ram_console.c b/trunk/drivers/staging/android/ram_console.c index ce140ffc54ea..82323bb1d1a3 100644 --- a/trunk/drivers/staging/android/ram_console.c +++ b/trunk/drivers/staging/android/ram_console.c @@ -21,7 +21,7 @@ #include #include #include -#include "persistent_ram.h" +#include #include "ram_console.h" static struct persistent_ram_zone *ram_console_zone; diff --git a/trunk/drivers/staging/android/switch/Kconfig b/trunk/drivers/staging/android/switch/Kconfig deleted file mode 100644 index 36846f62f4bc..000000000000 --- a/trunk/drivers/staging/android/switch/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -menuconfig ANDROID_SWITCH - tristate "Android Switch class support" - help - Say Y here to enable Android switch class support. This allows - monitoring switches by userspace via sysfs and uevent. - -config ANDROID_SWITCH_GPIO - tristate "Android GPIO Switch support" - depends on GENERIC_GPIO && ANDROID_SWITCH - help - Say Y here to enable GPIO based switch support. diff --git a/trunk/drivers/staging/android/switch/Makefile b/trunk/drivers/staging/android/switch/Makefile deleted file mode 100644 index d76bfdcedfaf..000000000000 --- a/trunk/drivers/staging/android/switch/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -# Android Switch Class Driver -obj-$(CONFIG_ANDROID_SWITCH) += switch_class.o -obj-$(CONFIG_ANDROID_SWITCH_GPIO) += switch_gpio.o - diff --git a/trunk/drivers/staging/android/switch/switch.h b/trunk/drivers/staging/android/switch/switch.h deleted file mode 100644 index 4fcb3109875a..000000000000 --- a/trunk/drivers/staging/android/switch/switch.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Switch class driver - * - * Copyright (C) 2008 Google, Inc. - * Author: Mike Lockwood - * - * 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 __LINUX_SWITCH_H__ -#define __LINUX_SWITCH_H__ - -struct switch_dev { - const char *name; - struct device *dev; - int index; - int state; - - ssize_t (*print_name)(struct switch_dev *sdev, char *buf); - ssize_t (*print_state)(struct switch_dev *sdev, char *buf); -}; - -struct gpio_switch_platform_data { - const char *name; - unsigned gpio; - - /* if NULL, switch_dev.name will be printed */ - const char *name_on; - const char *name_off; - /* if NULL, "0" or "1" will be printed */ - const char *state_on; - const char *state_off; -}; - -extern int switch_dev_register(struct switch_dev *sdev); -extern void switch_dev_unregister(struct switch_dev *sdev); - -static inline int switch_get_state(struct switch_dev *sdev) -{ - return sdev->state; -} - -extern void switch_set_state(struct switch_dev *sdev, int state); - -#endif /* __LINUX_SWITCH_H__ */ diff --git a/trunk/drivers/staging/android/switch/switch_class.c b/trunk/drivers/staging/android/switch/switch_class.c deleted file mode 100644 index 74680446fc66..000000000000 --- a/trunk/drivers/staging/android/switch/switch_class.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * switch_class.c - * - * Copyright (C) 2008 Google, Inc. - * Author: Mike Lockwood - * - * 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 -#include "switch.h" - -struct class *switch_class; -static atomic_t device_count; - -static ssize_t state_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct switch_dev *sdev = (struct switch_dev *) - dev_get_drvdata(dev); - - if (sdev->print_state) { - int ret = sdev->print_state(sdev, buf); - if (ret >= 0) - return ret; - } - return sprintf(buf, "%d\n", sdev->state); -} - -static ssize_t name_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct switch_dev *sdev = (struct switch_dev *) - dev_get_drvdata(dev); - - if (sdev->print_name) { - int ret = sdev->print_name(sdev, buf); - if (ret >= 0) - return ret; - } - return sprintf(buf, "%s\n", sdev->name); -} - -static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, state_show, NULL); -static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, name_show, NULL); - -void switch_set_state(struct switch_dev *sdev, int state) -{ - char name_buf[120]; - char state_buf[120]; - char *prop_buf; - char *envp[3]; - int env_offset = 0; - int length; - - if (sdev->state != state) { - sdev->state = state; - - prop_buf = (char *)get_zeroed_page(GFP_KERNEL); - if (prop_buf) { - length = name_show(sdev->dev, NULL, prop_buf); - if (length > 0) { - if (prop_buf[length - 1] == '\n') - prop_buf[length - 1] = 0; - snprintf(name_buf, sizeof(name_buf), - "SWITCH_NAME=%s", prop_buf); - envp[env_offset++] = name_buf; - } - length = state_show(sdev->dev, NULL, prop_buf); - if (length > 0) { - if (prop_buf[length - 1] == '\n') - prop_buf[length - 1] = 0; - snprintf(state_buf, sizeof(state_buf), - "SWITCH_STATE=%s", prop_buf); - envp[env_offset++] = state_buf; - } - envp[env_offset] = NULL; - kobject_uevent_env(&sdev->dev->kobj, KOBJ_CHANGE, envp); - free_page((unsigned long)prop_buf); - } else { - printk(KERN_ERR "out of memory in switch_set_state\n"); - kobject_uevent(&sdev->dev->kobj, KOBJ_CHANGE); - } - } -} -EXPORT_SYMBOL_GPL(switch_set_state); - -static int create_switch_class(void) -{ - if (!switch_class) { - switch_class = class_create(THIS_MODULE, "switch"); - if (IS_ERR(switch_class)) - return PTR_ERR(switch_class); - atomic_set(&device_count, 0); - } - - return 0; -} - -int switch_dev_register(struct switch_dev *sdev) -{ - int ret; - - if (!switch_class) { - ret = create_switch_class(); - if (ret < 0) - return ret; - } - - sdev->index = atomic_inc_return(&device_count); - sdev->dev = device_create(switch_class, NULL, - MKDEV(0, sdev->index), NULL, sdev->name); - if (IS_ERR(sdev->dev)) - return PTR_ERR(sdev->dev); - - ret = device_create_file(sdev->dev, &dev_attr_state); - if (ret < 0) - goto err_create_file_1; - ret = device_create_file(sdev->dev, &dev_attr_name); - if (ret < 0) - goto err_create_file_2; - - dev_set_drvdata(sdev->dev, sdev); - sdev->state = 0; - return 0; - -err_create_file_2: - device_remove_file(sdev->dev, &dev_attr_state); -err_create_file_1: - device_destroy(switch_class, MKDEV(0, sdev->index)); - printk(KERN_ERR "switch: Failed to register driver %s\n", sdev->name); - - return ret; -} -EXPORT_SYMBOL_GPL(switch_dev_register); - -void switch_dev_unregister(struct switch_dev *sdev) -{ - device_remove_file(sdev->dev, &dev_attr_name); - device_remove_file(sdev->dev, &dev_attr_state); - device_destroy(switch_class, MKDEV(0, sdev->index)); - dev_set_drvdata(sdev->dev, NULL); -} -EXPORT_SYMBOL_GPL(switch_dev_unregister); - -static int __init switch_class_init(void) -{ - return create_switch_class(); -} - -static void __exit switch_class_exit(void) -{ - class_destroy(switch_class); -} - -module_init(switch_class_init); -module_exit(switch_class_exit); - -MODULE_AUTHOR("Mike Lockwood "); -MODULE_DESCRIPTION("Switch class driver"); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/android/switch/switch_gpio.c b/trunk/drivers/staging/android/switch/switch_gpio.c deleted file mode 100644 index 38b2c2f6004e..000000000000 --- a/trunk/drivers/staging/android/switch/switch_gpio.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * switch_gpio.c - * - * Copyright (C) 2008 Google, Inc. - * Author: Mike Lockwood - * - * 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 -#include -#include -#include "switch.h" - -struct gpio_switch_data { - struct switch_dev sdev; - unsigned gpio; - const char *name_on; - const char *name_off; - const char *state_on; - const char *state_off; - int irq; - struct work_struct work; -}; - -static void gpio_switch_work(struct work_struct *work) -{ - int state; - struct gpio_switch_data *data = - container_of(work, struct gpio_switch_data, work); - - state = gpio_get_value(data->gpio); - switch_set_state(&data->sdev, state); -} - -static irqreturn_t gpio_irq_handler(int irq, void *dev_id) -{ - struct gpio_switch_data *switch_data = - (struct gpio_switch_data *)dev_id; - - schedule_work(&switch_data->work); - return IRQ_HANDLED; -} - -static ssize_t switch_gpio_print_state(struct switch_dev *sdev, char *buf) -{ - struct gpio_switch_data *switch_data = - container_of(sdev, struct gpio_switch_data, sdev); - const char *state; - if (switch_get_state(sdev)) - state = switch_data->state_on; - else - state = switch_data->state_off; - - if (state) - return sprintf(buf, "%s\n", state); - return -1; -} - -static int gpio_switch_probe(struct platform_device *pdev) -{ - struct gpio_switch_platform_data *pdata = pdev->dev.platform_data; - struct gpio_switch_data *switch_data; - int ret = 0; - - if (!pdata) - return -EBUSY; - - switch_data = kzalloc(sizeof(struct gpio_switch_data), GFP_KERNEL); - if (!switch_data) - return -ENOMEM; - - switch_data->sdev.name = pdata->name; - switch_data->gpio = pdata->gpio; - switch_data->name_on = pdata->name_on; - switch_data->name_off = pdata->name_off; - switch_data->state_on = pdata->state_on; - switch_data->state_off = pdata->state_off; - switch_data->sdev.print_state = switch_gpio_print_state; - - ret = switch_dev_register(&switch_data->sdev); - if (ret < 0) - goto err_switch_dev_register; - - ret = gpio_request(switch_data->gpio, pdev->name); - if (ret < 0) - goto err_request_gpio; - - ret = gpio_direction_input(switch_data->gpio); - if (ret < 0) - goto err_set_gpio_input; - - INIT_WORK(&switch_data->work, gpio_switch_work); - - switch_data->irq = gpio_to_irq(switch_data->gpio); - if (switch_data->irq < 0) { - ret = switch_data->irq; - goto err_detect_irq_num_failed; - } - - ret = request_irq(switch_data->irq, gpio_irq_handler, - IRQF_TRIGGER_LOW, pdev->name, switch_data); - if (ret < 0) - goto err_request_irq; - - /* Perform initial detection */ - gpio_switch_work(&switch_data->work); - - return 0; - -err_request_irq: -err_detect_irq_num_failed: -err_set_gpio_input: - gpio_free(switch_data->gpio); -err_request_gpio: - switch_dev_unregister(&switch_data->sdev); -err_switch_dev_register: - kfree(switch_data); - - return ret; -} - -static int __devexit gpio_switch_remove(struct platform_device *pdev) -{ - struct gpio_switch_data *switch_data = platform_get_drvdata(pdev); - - cancel_work_sync(&switch_data->work); - gpio_free(switch_data->gpio); - switch_dev_unregister(&switch_data->sdev); - kfree(switch_data); - - return 0; -} - -static struct platform_driver gpio_switch_driver = { - .probe = gpio_switch_probe, - .remove = __devexit_p(gpio_switch_remove), - .driver = { - .name = "switch-gpio", - .owner = THIS_MODULE, - }, -}; - -static int __init gpio_switch_init(void) -{ - return platform_driver_register(&gpio_switch_driver); -} - -static void __exit gpio_switch_exit(void) -{ - platform_driver_unregister(&gpio_switch_driver); -} - -module_init(gpio_switch_init); -module_exit(gpio_switch_exit); - -MODULE_AUTHOR("Mike Lockwood "); -MODULE_DESCRIPTION("GPIO Switch driver"); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/android/timed_output.c b/trunk/drivers/staging/android/timed_output.c index f373422308e0..38d930cadad3 100644 --- a/trunk/drivers/staging/android/timed_output.c +++ b/trunk/drivers/staging/android/timed_output.c @@ -99,6 +99,7 @@ EXPORT_SYMBOL_GPL(timed_output_dev_register); void timed_output_dev_unregister(struct timed_output_dev *tdev) { + tdev->enable(tdev, 0); device_remove_file(tdev->dev, &dev_attr_enable); device_destroy(timed_output_class, MKDEV(0, tdev->index)); dev_set_drvdata(tdev->dev, NULL); diff --git a/trunk/drivers/staging/asus_oled/asus_oled.c b/trunk/drivers/staging/asus_oled/asus_oled.c index 83549d9cfefc..510d79639217 100644 --- a/trunk/drivers/staging/asus_oled/asus_oled.c +++ b/trunk/drivers/staging/asus_oled/asus_oled.c @@ -782,20 +782,20 @@ static int __init asus_oled_init(void) oled_class = class_create(THIS_MODULE, ASUS_OLED_UNDERSCORE_NAME); if (IS_ERR(oled_class)) { - err("Error creating " ASUS_OLED_UNDERSCORE_NAME " class"); + printk(KERN_ERR "Error creating " ASUS_OLED_UNDERSCORE_NAME " class\n"); return PTR_ERR(oled_class); } retval = class_create_file(oled_class, &class_attr_version.attr); if (retval) { - err("Error creating class version file"); + printk(KERN_ERR "Error creating class version file\n"); goto error; } retval = usb_register(&oled_driver); if (retval) { - err("usb_register failed. Error number %d", retval); + printk(KERN_ERR "usb_register failed. Error number %d\n", retval); goto error; } diff --git a/trunk/drivers/staging/bcm/Adapter.h b/trunk/drivers/staging/bcm/Adapter.h index 20cca24ff5f0..aa51d17be5a1 100644 --- a/trunk/drivers/staging/bcm/Adapter.h +++ b/trunk/drivers/staging/bcm/Adapter.h @@ -7,168 +7,145 @@ #define MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES 256 #include "Debug.h" -struct _LEADER -{ - USHORT Vcid; - USHORT PLength; - UCHAR Status; +struct _LEADER { + USHORT Vcid; + USHORT PLength; + UCHAR Status; UCHAR Unused[3]; -}__attribute__((packed)); -typedef struct _LEADER LEADER,*PLEADER; +} __packed; +typedef struct _LEADER LEADER, *PLEADER; -struct _PACKETTOSEND -{ +struct _PACKETTOSEND { LEADER Leader; UCHAR ucPayload; -}__attribute__((packed)); +} __packed; typedef struct _PACKETTOSEND PACKETTOSEND, *PPACKETTOSEND; - -struct _CONTROL_PACKET -{ +struct _CONTROL_PACKET { PVOID ControlBuff; UINT ControlBuffLen; - struct _CONTROL_PACKET* next; -}__attribute__((packed)); -typedef struct _CONTROL_PACKET CONTROL_PACKET,*PCONTROL_PACKET; - + struct _CONTROL_PACKET *next; +} __packed; +typedef struct _CONTROL_PACKET CONTROL_PACKET, *PCONTROL_PACKET; -struct link_request -{ +struct link_request { LEADER Leader; UCHAR szData[4]; -}__attribute__((packed)); +} __packed; typedef struct link_request LINK_REQUEST, *PLINK_REQUEST; - -//classification extension is added -typedef struct _ADD_CONNECTION -{ - ULONG SrcIpAddressCount; - ULONG SrcIpAddress[MAX_CONNECTIONS]; - ULONG SrcIpMask[MAX_CONNECTIONS]; - - ULONG DestIpAddressCount; - ULONG DestIpAddress[MAX_CONNECTIONS]; - ULONG DestIpMask[MAX_CONNECTIONS]; - - USHORT SrcPortBegin; - USHORT SrcPortEnd; - - USHORT DestPortBegin; - USHORT DestPortEnd; - - UCHAR SrcTOS; - UCHAR SrcProtocol; -} ADD_CONNECTION,*PADD_CONNECTION; - - -typedef struct _CLASSIFICATION_RULE -{ - UCHAR ucIPSrcAddrLen; - UCHAR ucIPSrcAddr[32]; - UCHAR ucIPDestAddrLen; - UCHAR ucIPDestAddr[32]; - UCHAR ucSrcPortRangeLen; - UCHAR ucSrcPortRange[4]; - UCHAR ucDestPortRangeLen; - UCHAR ucDestPortRange[4]; - USHORT usVcid; -} CLASSIFICATION_RULE,*PCLASSIFICATION_RULE; - -typedef struct _CLASSIFICATION_ONLY -{ - USHORT usVcid; - ULONG DestIpAddress; - ULONG DestIpMask; - USHORT usPortLo; - USHORT usPortHi; - BOOLEAN bIpVersion; - UCHAR ucDestinationAddress[16]; +/* classification extension is added */ +typedef struct _ADD_CONNECTION { + ULONG SrcIpAddressCount; + ULONG SrcIpAddress[MAX_CONNECTIONS]; + ULONG SrcIpMask[MAX_CONNECTIONS]; + + ULONG DestIpAddressCount; + ULONG DestIpAddress[MAX_CONNECTIONS]; + ULONG DestIpMask[MAX_CONNECTIONS]; + + USHORT SrcPortBegin; + USHORT SrcPortEnd; + + USHORT DestPortBegin; + USHORT DestPortEnd; + + UCHAR SrcTOS; + UCHAR SrcProtocol; +} ADD_CONNECTION, *PADD_CONNECTION; + +typedef struct _CLASSIFICATION_RULE { + UCHAR ucIPSrcAddrLen; + UCHAR ucIPSrcAddr[32]; + UCHAR ucIPDestAddrLen; + UCHAR ucIPDestAddr[32]; + UCHAR ucSrcPortRangeLen; + UCHAR ucSrcPortRange[4]; + UCHAR ucDestPortRangeLen; + UCHAR ucDestPortRange[4]; + USHORT usVcid; +} CLASSIFICATION_RULE, *PCLASSIFICATION_RULE; + +typedef struct _CLASSIFICATION_ONLY { + USHORT usVcid; + ULONG DestIpAddress; + ULONG DestIpMask; + USHORT usPortLo; + USHORT usPortHi; + BOOLEAN bIpVersion; + UCHAR ucDestinationAddress[16]; } CLASSIFICATION_ONLY, *PCLASSIFICATION_ONLY; - #define MAX_IP_RANGE_LENGTH 4 #define MAX_PORT_RANGE 4 #define MAX_PROTOCOL_LENGTH 32 #define IPV6_ADDRESS_SIZEINBYTES 0x10 -typedef union _U_IP_ADDRESS -{ - struct - { - ULONG ulIpv4Addr[MAX_IP_RANGE_LENGTH];//Source Ip Address Range - ULONG ulIpv4Mask[MAX_IP_RANGE_LENGTH];//Source Ip Mask Address Range +typedef union _U_IP_ADDRESS { + struct { + ULONG ulIpv4Addr[MAX_IP_RANGE_LENGTH]; /* Source Ip Address Range */ + ULONG ulIpv4Mask[MAX_IP_RANGE_LENGTH]; /* Source Ip Mask Address Range */ }; - struct - { - ULONG ulIpv6Addr[MAX_IP_RANGE_LENGTH * 4];//Source Ip Address Range - ULONG ulIpv6Mask[MAX_IP_RANGE_LENGTH * 4];//Source Ip Mask Address Range - + struct { + ULONG ulIpv6Addr[MAX_IP_RANGE_LENGTH * 4]; /* Source Ip Address Range */ + ULONG ulIpv6Mask[MAX_IP_RANGE_LENGTH * 4]; /* Source Ip Mask Address Range */ }; - struct - { - UCHAR ucIpv4Address[MAX_IP_RANGE_LENGTH * IP_LENGTH_OF_ADDRESS]; - UCHAR ucIpv4Mask[MAX_IP_RANGE_LENGTH * IP_LENGTH_OF_ADDRESS]; + struct { + UCHAR ucIpv4Address[MAX_IP_RANGE_LENGTH * IP_LENGTH_OF_ADDRESS]; + UCHAR ucIpv4Mask[MAX_IP_RANGE_LENGTH * IP_LENGTH_OF_ADDRESS]; }; - struct - { - UCHAR ucIpv6Address[MAX_IP_RANGE_LENGTH * IPV6_ADDRESS_SIZEINBYTES]; - UCHAR ucIpv6Mask[MAX_IP_RANGE_LENGTH * IPV6_ADDRESS_SIZEINBYTES]; + struct { + UCHAR ucIpv6Address[MAX_IP_RANGE_LENGTH * IPV6_ADDRESS_SIZEINBYTES]; + UCHAR ucIpv6Mask[MAX_IP_RANGE_LENGTH * IPV6_ADDRESS_SIZEINBYTES]; }; -}U_IP_ADDRESS; +} U_IP_ADDRESS; struct _packet_info; -typedef struct _S_HDR_SUPRESSION_CONTEXTINFO -{ +typedef struct _S_HDR_SUPRESSION_CONTEXTINFO { + UCHAR ucaHdrSupressionInBuf[MAX_PHS_LENGTHS]; /* Intermediate buffer to accumulate pkt Header for PHS */ + UCHAR ucaHdrSupressionOutBuf[MAX_PHS_LENGTHS + PHSI_LEN]; /* Intermediate buffer containing pkt Header after PHS */ +} S_HDR_SUPRESSION_CONTEXTINFO; + +typedef struct _S_CLASSIFIER_RULE { + ULONG ulSFID; + UCHAR ucReserved[2]; + B_UINT16 uiClassifierRuleIndex; + BOOLEAN bUsed; + USHORT usVCID_Value; + B_UINT8 u8ClassifierRulePriority; /* This field detemines the Classifier Priority */ + U_IP_ADDRESS stSrcIpAddress; + UCHAR ucIPSourceAddressLength; /* Ip Source Address Length */ - UCHAR ucaHdrSupressionInBuf[MAX_PHS_LENGTHS]; //Intermediate buffer to accumulate pkt Header for PHS - UCHAR ucaHdrSupressionOutBuf[MAX_PHS_LENGTHS + PHSI_LEN]; //Intermediate buffer containing pkt Header after PHS + U_IP_ADDRESS stDestIpAddress; + UCHAR ucIPDestinationAddressLength; /* Ip Destination Address Length */ + UCHAR ucIPTypeOfServiceLength; /* Type of service Length */ + UCHAR ucTosLow; /* Tos Low */ + UCHAR ucTosHigh; /* Tos High */ + UCHAR ucTosMask; /* Tos Mask */ -}S_HDR_SUPRESSION_CONTEXTINFO; + UCHAR ucProtocolLength; /* protocol Length */ + UCHAR ucProtocol[MAX_PROTOCOL_LENGTH]; /* protocol Length */ + USHORT usSrcPortRangeLo[MAX_PORT_RANGE]; + USHORT usSrcPortRangeHi[MAX_PORT_RANGE]; + UCHAR ucSrcPortRangeLength; + USHORT usDestPortRangeLo[MAX_PORT_RANGE]; + USHORT usDestPortRangeHi[MAX_PORT_RANGE]; + UCHAR ucDestPortRangeLength; -typedef struct _S_CLASSIFIER_RULE -{ - ULONG ulSFID; - UCHAR ucReserved[2]; - B_UINT16 uiClassifierRuleIndex; - BOOLEAN bUsed; - USHORT usVCID_Value; - B_UINT8 u8ClassifierRulePriority; //This field detemines the Classifier Priority - U_IP_ADDRESS stSrcIpAddress; - UCHAR ucIPSourceAddressLength;//Ip Source Address Length - - U_IP_ADDRESS stDestIpAddress; - UCHAR ucIPDestinationAddressLength;//Ip Destination Address Length - UCHAR ucIPTypeOfServiceLength;//Type of service Length - UCHAR ucTosLow;//Tos Low - UCHAR ucTosHigh;//Tos High - UCHAR ucTosMask;//Tos Mask - - UCHAR ucProtocolLength;//protocol Length - UCHAR ucProtocol[MAX_PROTOCOL_LENGTH];//protocol Length - USHORT usSrcPortRangeLo[MAX_PORT_RANGE]; - USHORT usSrcPortRangeHi[MAX_PORT_RANGE]; - UCHAR ucSrcPortRangeLength; - - USHORT usDestPortRangeLo[MAX_PORT_RANGE]; - USHORT usDestPortRangeHi[MAX_PORT_RANGE]; - UCHAR ucDestPortRangeLength; - - BOOLEAN bProtocolValid; - BOOLEAN bTOSValid; - BOOLEAN bDestIpValid; - BOOLEAN bSrcIpValid; - - //For IPv6 Addressing - UCHAR ucDirection; - BOOLEAN bIpv6Protocol; - UINT32 u32PHSRuleID; - S_PHS_RULE sPhsRule; - UCHAR u8AssociatedPHSI; - - //Classification fields for ETH CS + BOOLEAN bProtocolValid; + BOOLEAN bTOSValid; + BOOLEAN bDestIpValid; + BOOLEAN bSrcIpValid; + + /* For IPv6 Addressing */ + UCHAR ucDirection; + BOOLEAN bIpv6Protocol; + UINT32 u32PHSRuleID; + S_PHS_RULE sPhsRule; + UCHAR u8AssociatedPHSI; + + /* Classification fields for ETH CS */ UCHAR ucEthCSSrcMACLen; UCHAR au8EThCSSrcMAC[MAC_ADDRESS_SIZE]; UCHAR au8EThCSSrcMACMask[MAC_ADDRESS_SIZE]; @@ -180,71 +157,67 @@ typedef struct _S_CLASSIFIER_RULE UCHAR usUserPriority[2]; USHORT usVLANID; USHORT usValidityBitMap; -}S_CLASSIFIER_RULE; -//typedef struct _S_CLASSIFIER_RULE S_CLASSIFIER_RULE; - -typedef struct _S_FRAGMENTED_PACKET_INFO -{ - BOOLEAN bUsed; - ULONG ulSrcIpAddress; - USHORT usIpIdentification; - S_CLASSIFIER_RULE *pstMatchedClassifierEntry; - BOOLEAN bOutOfOrderFragment; -}S_FRAGMENTED_PACKET_INFO,*PS_FRAGMENTED_PACKET_INFO; - -struct _packet_info -{ - //classification extension Rule - ULONG ulSFID; - USHORT usVCID_Value; - UINT uiThreshold; - // This field determines the priority of the SF Queues - B_UINT8 u8TrafficPriority; - - BOOLEAN bValid; - BOOLEAN bActive; - BOOLEAN bActivateRequestSent; - - B_UINT8 u8QueueType;//BE or rtPS - - UINT uiMaxBucketSize;//maximum size of the bucket for the queue - UINT uiCurrentQueueDepthOnTarget; - UINT uiCurrentBytesOnHost; - UINT uiCurrentPacketsOnHost; - UINT uiDroppedCountBytes; - UINT uiDroppedCountPackets; - UINT uiSentBytes; - UINT uiSentPackets; - UINT uiCurrentDrainRate; - UINT uiThisPeriodSentBytes; +} S_CLASSIFIER_RULE; +/* typedef struct _S_CLASSIFIER_RULE S_CLASSIFIER_RULE; */ + +typedef struct _S_FRAGMENTED_PACKET_INFO { + BOOLEAN bUsed; + ULONG ulSrcIpAddress; + USHORT usIpIdentification; + S_CLASSIFIER_RULE *pstMatchedClassifierEntry; + BOOLEAN bOutOfOrderFragment; +} S_FRAGMENTED_PACKET_INFO, *PS_FRAGMENTED_PACKET_INFO; + +struct _packet_info { + /* classification extension Rule */ + ULONG ulSFID; + USHORT usVCID_Value; + UINT uiThreshold; + /* This field determines the priority of the SF Queues */ + B_UINT8 u8TrafficPriority; + + BOOLEAN bValid; + BOOLEAN bActive; + BOOLEAN bActivateRequestSent; + + B_UINT8 u8QueueType; /* BE or rtPS */ + + UINT uiMaxBucketSize; /* maximum size of the bucket for the queue */ + UINT uiCurrentQueueDepthOnTarget; + UINT uiCurrentBytesOnHost; + UINT uiCurrentPacketsOnHost; + UINT uiDroppedCountBytes; + UINT uiDroppedCountPackets; + UINT uiSentBytes; + UINT uiSentPackets; + UINT uiCurrentDrainRate; + UINT uiThisPeriodSentBytes; LARGE_INTEGER liDrainCalculated; - UINT uiCurrentTokenCount; - LARGE_INTEGER liLastUpdateTokenAt; - UINT uiMaxAllowedRate; - UINT NumOfPacketsSent; - UCHAR ucDirection; - USHORT usCID; + UINT uiCurrentTokenCount; + LARGE_INTEGER liLastUpdateTokenAt; + UINT uiMaxAllowedRate; + UINT NumOfPacketsSent; + UCHAR ucDirection; + USHORT usCID; S_MIBS_EXTSERVICEFLOW_PARAMETERS stMibsExtServiceFlowTable; - UINT uiCurrentRxRate; - UINT uiThisPeriodRxBytes; - UINT uiTotalRxBytes; - UINT uiTotalTxBytes; - UINT uiPendedLast; - UCHAR ucIpVersion; - - union - { - struct - { - struct sk_buff* FirstTxQueue; - struct sk_buff* LastTxQueue; + UINT uiCurrentRxRate; + UINT uiThisPeriodRxBytes; + UINT uiTotalRxBytes; + UINT uiTotalTxBytes; + UINT uiPendedLast; + UCHAR ucIpVersion; + + union { + struct { + struct sk_buff *FirstTxQueue; + struct sk_buff *LastTxQueue; }; - struct - { - struct sk_buff* ControlHead; - struct sk_buff* ControlTail; + struct { + struct sk_buff *ControlHead; + struct sk_buff *ControlTail; }; }; + BOOLEAN bProtocolValid; BOOLEAN bTOSValid; BOOLEAN bDestIpValid; @@ -255,226 +228,209 @@ struct _packet_info BOOLEAN bAuthorizedSet; BOOLEAN bClassifierPriority; UCHAR ucServiceClassName[MAX_CLASS_NAME_LENGTH]; - BOOLEAN bHeaderSuppressionEnabled; + BOOLEAN bHeaderSuppressionEnabled; spinlock_t SFQueueLock; - void *pstSFIndication; + void *pstSFIndication; struct timeval stLastUpdateTokenAt; - atomic_t uiPerSFTxResourceCount; + atomic_t uiPerSFTxResourceCount; UINT uiMaxLatency; - UCHAR bIPCSSupport; - UCHAR bEthCSSupport; + UCHAR bIPCSSupport; + UCHAR bEthCSSupport; }; typedef struct _packet_info PacketInfo; - -typedef struct _PER_TARANG_DATA -{ - struct _PER_TARANG_DATA * next; - struct _MINI_ADAPTER * Adapter; - struct sk_buff* RxAppControlHead; - struct sk_buff* RxAppControlTail; - volatile INT AppCtrlQueueLen; - BOOLEAN MacTracingEnabled; - BOOLEAN bApplicationToExit; - S_MIBS_DROPPED_APP_CNTRL_MESSAGES stDroppedAppCntrlMsgs; - ULONG RxCntrlMsgBitMask; +typedef struct _PER_TARANG_DATA { + struct _PER_TARANG_DATA *next; + struct _MINI_ADAPTER *Adapter; + struct sk_buff *RxAppControlHead; + struct sk_buff *RxAppControlTail; + int AppCtrlQueueLen; + BOOLEAN MacTracingEnabled; + BOOLEAN bApplicationToExit; + S_MIBS_DROPPED_APP_CNTRL_MESSAGES stDroppedAppCntrlMsgs; + ULONG RxCntrlMsgBitMask; } PER_TARANG_DATA, *PPER_TARANG_DATA; - #ifdef REL_4_1 -typedef struct _TARGET_PARAMS -{ - B_UINT32 m_u32CfgVersion; - - // Scanning Related Params - B_UINT32 m_u32CenterFrequency; - B_UINT32 m_u32BandAScan; - B_UINT32 m_u32BandBScan; - B_UINT32 m_u32BandCScan; - - // QoS Params - B_UINT32 m_u32minGrantsize; // size of minimum grant is 0 or 6 - B_UINT32 m_u32PHSEnable; - - // HO Params - B_UINT32 m_u32HoEnable; - B_UINT32 m_u32HoReserved1; - B_UINT32 m_u32HoReserved2; - - // Power Control Params - B_UINT32 m_u32MimoEnable; - B_UINT32 m_u32SecurityEnable; +typedef struct _TARGET_PARAMS { + B_UINT32 m_u32CfgVersion; + + /* Scanning Related Params */ + B_UINT32 m_u32CenterFrequency; + B_UINT32 m_u32BandAScan; + B_UINT32 m_u32BandBScan; + B_UINT32 m_u32BandCScan; + + /* QoS Params */ + B_UINT32 m_u32minGrantsize; /* size of minimum grant is 0 or 6 */ + B_UINT32 m_u32PHSEnable; + + /* HO Params */ + B_UINT32 m_u32HoEnable; + B_UINT32 m_u32HoReserved1; + B_UINT32 m_u32HoReserved2; + + /* Power Control Params */ + B_UINT32 m_u32MimoEnable; + B_UINT32 m_u32SecurityEnable; /* - * bit 1: 1 Idlemode enable; - * bit 2: 1 Sleepmode Enable - */ - B_UINT32 m_u32PowerSavingModesEnable; - /* PowerSaving Mode Options: - bit 0 = 1: CPE mode - to keep pcmcia if alive; - bit 1 = 1: CINR reporing in Idlemode Msg - bit 2 = 1: Default PSC Enable in sleepmode*/ - B_UINT32 m_u32PowerSavingModeOptions; - - B_UINT32 m_u32ArqEnable; - - // From Version #3, the HARQ section renamed as general - B_UINT32 m_u32HarqEnable; - // EEPROM Param Location - B_UINT32 m_u32EEPROMFlag; - /* BINARY TYPE - 4th MSByte: - * Interface Type - 3rd MSByte: - * Vendor Type - 2nd MSByte - */ - // Unused - LSByte - B_UINT32 m_u32Customize; - B_UINT32 m_u32ConfigBW; /* In Hz */ - B_UINT32 m_u32ShutDownTimer; - - - B_UINT32 m_u32RadioParameter; - B_UINT32 m_u32PhyParameter1; - B_UINT32 m_u32PhyParameter2; - B_UINT32 m_u32PhyParameter3; + * bit 1: 1 Idlemode enable; + * bit 2: 1 Sleepmode Enable + */ + B_UINT32 m_u32PowerSavingModesEnable; + /* PowerSaving Mode Options: + * bit 0 = 1: CPE mode - to keep pcmcia if alive; + * bit 1 = 1: CINR reporing in Idlemode Msg + * bit 2 = 1: Default PSC Enable in sleepmode + */ + B_UINT32 m_u32PowerSavingModeOptions; + + B_UINT32 m_u32ArqEnable; + + /* From Version #3, the HARQ section renamed as general */ + B_UINT32 m_u32HarqEnable; + /* EEPROM Param Location */ + B_UINT32 m_u32EEPROMFlag; + /* BINARY TYPE - 4th MSByte: + * Interface Type - 3rd MSByte: + * Vendor Type - 2nd MSByte + */ + /* Unused - LSByte */ + B_UINT32 m_u32Customize; + B_UINT32 m_u32ConfigBW; /* In Hz */ + B_UINT32 m_u32ShutDownTimer; + B_UINT32 m_u32RadioParameter; + B_UINT32 m_u32PhyParameter1; + B_UINT32 m_u32PhyParameter2; + B_UINT32 m_u32PhyParameter3; /* in eval mode only; - * lower 16bits = basic cid for testing; - * then bit 16 is test cqich, - * bit 17 test init rang; - * bit 18 test periodic rang - * bit 19 is test harq ack/nack - */ - B_UINT32 m_u32TestOptions; - + * lower 16bits = basic cid for testing; + * then bit 16 is test cqich, + * bit 17 test init rang; + * bit 18 test periodic rang + * bit 19 is test harq ack/nack + */ + B_UINT32 m_u32TestOptions; B_UINT32 m_u32MaxMACDataperDLFrame; B_UINT32 m_u32MaxMACDataperULFrame; - B_UINT32 m_u32Corr2MacFlags; - //adding driver params. - B_UINT32 HostDrvrConfig1; - B_UINT32 HostDrvrConfig2; - B_UINT32 HostDrvrConfig3; - B_UINT32 HostDrvrConfig4; - B_UINT32 HostDrvrConfig5; - B_UINT32 HostDrvrConfig6; - B_UINT32 m_u32SegmentedPUSCenable; - - // BAMC enable - but 4.x does not support this feature - // This is added just to sync 4.x and 5.x CFGs + /* adding driver params. */ + B_UINT32 HostDrvrConfig1; + B_UINT32 HostDrvrConfig2; + B_UINT32 HostDrvrConfig3; + B_UINT32 HostDrvrConfig4; + B_UINT32 HostDrvrConfig5; + B_UINT32 HostDrvrConfig6; + B_UINT32 m_u32SegmentedPUSCenable; + + /* BAMC enable - but 4.x does not support this feature + * This is added just to sync 4.x and 5.x CFGs + */ B_UINT32 m_u32BandAMCEnable; } STARGETPARAMS, *PSTARGETPARAMS; #endif -typedef struct _STTARGETDSXBUFFER -{ - ULONG ulTargetDsxBuffer; - B_UINT16 tid; - BOOLEAN valid; -}STTARGETDSXBUFFER, *PSTTARGETDSXBUFFER; +typedef struct _STTARGETDSXBUFFER { + ULONG ulTargetDsxBuffer; + B_UINT16 tid; + BOOLEAN valid; +} STTARGETDSXBUFFER, *PSTTARGETDSXBUFFER; -typedef INT (*FP_FLASH_WRITE)(struct _MINI_ADAPTER*,UINT,PVOID); +typedef int (*FP_FLASH_WRITE)(struct _MINI_ADAPTER *, UINT, PVOID); -typedef INT (*FP_FLASH_WRITE_STATUS)(struct _MINI_ADAPTER*,UINT,PVOID); +typedef int (*FP_FLASH_WRITE_STATUS)(struct _MINI_ADAPTER *, UINT, PVOID); -/** -Driver adapter data structure -*/ -struct _MINI_ADAPTER -{ - struct _MINI_ADAPTER *next; +/* + * Driver adapter data structure + */ +struct _MINI_ADAPTER { + struct _MINI_ADAPTER *next; struct net_device *dev; u32 msg_enable; - - CHAR *caDsxReqResp; + CHAR *caDsxReqResp; atomic_t ApplicationRunning; - volatile INT CtrlQueueLen; - atomic_t AppCtrlQueueLen; - BOOLEAN AppCtrlQueueOverFlow; + BOOLEAN AppCtrlQueueOverFlow; atomic_t CurrentApplicationCount; - atomic_t RegisteredApplicationCount; - BOOLEAN LinkUpStatus; - BOOLEAN TimerActive; + atomic_t RegisteredApplicationCount; + BOOLEAN LinkUpStatus; + BOOLEAN TimerActive; u32 StatisticsPointer; struct sk_buff *RxControlHead; struct sk_buff *RxControlTail; - struct semaphore RxAppControlQueuelock; struct semaphore fw_download_sema; - - PPER_TARANG_DATA pTarangs; - spinlock_t control_queue_lock; + PPER_TARANG_DATA pTarangs; + spinlock_t control_queue_lock; wait_queue_head_t process_read_wait_queue; - // the pointer to the first packet we have queued in send - // deserialized miniport support variables - atomic_t TotalPacketCount; - atomic_t TxPktAvail; - - // this to keep track of the Tx and Rx MailBox Registers. - atomic_t CurrNumFreeTxDesc; - // to keep track the no of byte received - USHORT PrevNumRecvDescs; - USHORT CurrNumRecvDescs; - UINT u32TotalDSD; - PacketInfo PackInfo[NO_OF_QUEUES]; + /* the pointer to the first packet we have queued in send + * deserialized miniport support variables + */ + atomic_t TotalPacketCount; + atomic_t TxPktAvail; + + /* this to keep track of the Tx and Rx MailBox Registers. */ + atomic_t CurrNumFreeTxDesc; + /* to keep track the no of byte received */ + USHORT PrevNumRecvDescs; + USHORT CurrNumRecvDescs; + UINT u32TotalDSD; + PacketInfo PackInfo[NO_OF_QUEUES]; S_CLASSIFIER_RULE astClassifierTable[MAX_CLASSIFIERS]; - BOOLEAN TransferMode; + BOOLEAN TransferMode; /*************** qos ******************/ - BOOLEAN bETHCSEnabled; - - ULONG BEBucketSize; - ULONG rtPSBucketSize; - UCHAR LinkStatus; - BOOLEAN AutoLinkUp; - BOOLEAN AutoSyncup; - - int major; - int minor; - wait_queue_head_t tx_packet_wait_queue; - wait_queue_head_t process_rx_cntrlpkt; - atomic_t process_waiting; - BOOLEAN fw_download_done; - - char *txctlpacket[MAX_CNTRL_PKTS]; - atomic_t cntrlpktCnt ; - atomic_t index_app_read_cntrlpkt; - atomic_t index_wr_txcntrlpkt; - atomic_t index_rd_txcntrlpkt; - UINT index_datpkt; - struct semaphore rdmwrmsync; + BOOLEAN bETHCSEnabled; + ULONG BEBucketSize; + ULONG rtPSBucketSize; + UCHAR LinkStatus; + BOOLEAN AutoLinkUp; + BOOLEAN AutoSyncup; + + int major; + int minor; + wait_queue_head_t tx_packet_wait_queue; + wait_queue_head_t process_rx_cntrlpkt; + atomic_t process_waiting; + BOOLEAN fw_download_done; + + char *txctlpacket[MAX_CNTRL_PKTS]; + atomic_t cntrlpktCnt ; + atomic_t index_app_read_cntrlpkt; + atomic_t index_wr_txcntrlpkt; + atomic_t index_rd_txcntrlpkt; + UINT index_datpkt; + struct semaphore rdmwrmsync; STTARGETDSXBUFFER astTargetDsxBuffer[MAX_TARGET_DSX_BUFFERS]; ULONG ulFreeTargetBufferCnt; - ULONG ulCurrentTargetBuffer; - ULONG ulTotalTargetBuffersAvailable; - - unsigned long chip_id; - - wait_queue_head_t lowpower_mode_wait_queue; - + ULONG ulCurrentTargetBuffer; + ULONG ulTotalTargetBuffersAvailable; + unsigned long chip_id; + wait_queue_head_t lowpower_mode_wait_queue; BOOLEAN bFlashBoot; BOOLEAN bBinDownloaded; BOOLEAN bCfgDownloaded; BOOLEAN bSyncUpRequestSent; USHORT usBestEffortQueueIndex; - - wait_queue_head_t ioctl_fw_dnld_wait_queue; - BOOLEAN waiting_to_fw_download_done; - pid_t fw_download_process_pid; + wait_queue_head_t ioctl_fw_dnld_wait_queue; + BOOLEAN waiting_to_fw_download_done; + pid_t fw_download_process_pid; PSTARGETPARAMS pstargetparams; - BOOLEAN device_removed; - BOOLEAN DeviceAccess; - BOOLEAN bIsAutoCorrectEnabled; - BOOLEAN bDDRInitDone; - INT DDRSetting; - ULONG ulPowerSaveMode; - spinlock_t txtransmitlock; - B_UINT8 txtransmit_running; + BOOLEAN device_removed; + BOOLEAN DeviceAccess; + BOOLEAN bIsAutoCorrectEnabled; + BOOLEAN bDDRInitDone; + int DDRSetting; + ULONG ulPowerSaveMode; + spinlock_t txtransmitlock; + B_UINT8 txtransmit_running; /* Thread for control packet handling */ - struct task_struct *control_packet_handler; + struct task_struct *control_packet_handler; /* thread for transmitting packets. */ - struct task_struct *transmit_packet_thread; + struct task_struct *transmit_packet_thread; /* LED Related Structures */ LED_INFO_STRUCT LEDInfo; @@ -482,39 +438,38 @@ struct _MINI_ADAPTER /* Driver State for LED Blinking */ LedEventInfo_t DriverState; /* Interface Specific */ - PVOID pvInterfaceAdapter; - int (*bcm_file_download)( PVOID, - struct file *, - unsigned int); - int (*bcm_file_readback_from_chip)( PVOID, - struct file *, - unsigned int); - INT (*interface_rdm)(PVOID, - UINT , - PVOID , - INT); - INT (*interface_wrm)(PVOID, - UINT , - PVOID , - INT); + PVOID pvInterfaceAdapter; + int (*bcm_file_download)(PVOID, + struct file *, + unsigned int); + int (*bcm_file_readback_from_chip)(PVOID, + struct file *, + unsigned int); + int (*interface_rdm)(PVOID, + UINT, + PVOID, + int); + int (*interface_wrm)(PVOID, + UINT, + PVOID, + int); int (*interface_transmit)(PVOID, PVOID , UINT); BOOLEAN IdleMode; BOOLEAN bDregRequestSentInIdleMode; BOOLEAN bTriedToWakeUpFromlowPowerMode; BOOLEAN bShutStatus; BOOLEAN bWakeUpDevice; - unsigned int usIdleModePattern; - //BOOLEAN bTriedToWakeUpFromShutdown; + unsigned int usIdleModePattern; + /* BOOLEAN bTriedToWakeUpFromShutdown; */ BOOLEAN bLinkDownRequested; - - int downloadDDR; - PHS_DEVICE_EXTENSION stBCMPhsContext; - S_HDR_SUPRESSION_CONTEXTINFO stPhsTxContextInfo; + int downloadDDR; + PHS_DEVICE_EXTENSION stBCMPhsContext; + S_HDR_SUPRESSION_CONTEXTINFO stPhsTxContextInfo; uint8_t ucaPHSPktRestoreBuf[2048]; uint8_t bPHSEnabled; BOOLEAN AutoFirmDld; - BOOLEAN bMipsConfig; - BOOLEAN bDPLLConfig; + BOOLEAN bMipsConfig; + BOOLEAN bDPLLConfig; UINT32 aTxPktSizeHist[MIBS_MAX_HIST_ENTRIES]; UINT32 aRxPktSizeHist[MIBS_MAX_HIST_ENTRIES]; S_FRAGMENTED_PACKET_INFO astFragmentedPktClassifierTable[MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES]; @@ -527,108 +482,101 @@ struct _MINI_ADAPTER BOOLEAN bStatusWrite; UINT uiNVMDSDSize; UINT uiVendorExtnFlag; - //it will always represent chosen DSD at any point of time. - // Generally it is Active DSD but in case of NVM RD/WR it might be different. + /* it will always represent chosen DSD at any point of time. + * Generally it is Active DSD but in case of NVM RD/WR it might be different. + */ UINT ulFlashCalStart; - ULONG ulFlashControlSectionStart; - ULONG ulFlashWriteSize; - ULONG ulFlashID; - FP_FLASH_WRITE fpFlashWrite; - FP_FLASH_WRITE_STATUS fpFlashWriteWithStatusCheck; - + ULONG ulFlashControlSectionStart; + ULONG ulFlashWriteSize; + ULONG ulFlashID; + FP_FLASH_WRITE fpFlashWrite; + FP_FLASH_WRITE_STATUS fpFlashWriteWithStatusCheck; struct semaphore NVMRdmWrmLock; + struct device *pstCreatedClassDevice; - struct device *pstCreatedClassDevice; - -// BOOLEAN InterfaceUpStatus; - PFLASH2X_CS_INFO psFlash2xCSInfo; - PFLASH_CS_INFO psFlashCSInfo ; + /* BOOLEAN InterfaceUpStatus; */ + PFLASH2X_CS_INFO psFlash2xCSInfo; + PFLASH_CS_INFO psFlashCSInfo; PFLASH2X_VENDORSPECIFIC_INFO psFlash2xVendorInfo; - UINT uiFlashBaseAdd; //Flash start address - UINT uiActiveISOOffset; //Active ISO offset chosen before f/w download - FLASH2X_SECTION_VAL eActiveISO; //Active ISO section val - FLASH2X_SECTION_VAL eActiveDSD; //Active DSD val chosen before f/w download - UINT uiActiveDSDOffsetAtFwDld; //For accessing Active DSD chosen before f/w download - UINT uiFlashLayoutMajorVersion ; - UINT uiFlashLayoutMinorVersion; - BOOLEAN bAllDSDWriteAllow ; - BOOLEAN bSigCorrupted ; - //this should be set who so ever want to change the Headers. after Wrtie it should be reset immediately. - BOOLEAN bHeaderChangeAllowed ; - INT SelectedChip ; - BOOLEAN bEndPointHalted; - //while bFlashRawRead will be true, Driver ignore map lay out and consider flash as of without any map. - BOOLEAN bFlashRawRead; - BOOLEAN bPreparingForLowPowerMode ; - BOOLEAN bDoSuspend ; - UINT syscfgBefFwDld ; - BOOLEAN StopAllXaction ; - UINT32 liTimeSinceLastNetEntry; //Used to Support extended CAPI requirements from + UINT uiFlashBaseAdd; /* Flash start address */ + UINT uiActiveISOOffset; /* Active ISO offset chosen before f/w download */ + FLASH2X_SECTION_VAL eActiveISO; /* Active ISO section val */ + FLASH2X_SECTION_VAL eActiveDSD; /* Active DSD val chosen before f/w download */ + UINT uiActiveDSDOffsetAtFwDld; /* For accessing Active DSD chosen before f/w download */ + UINT uiFlashLayoutMajorVersion; + UINT uiFlashLayoutMinorVersion; + BOOLEAN bAllDSDWriteAllow; + BOOLEAN bSigCorrupted; + /* this should be set who so ever want to change the Headers. after Wrtie it should be reset immediately. */ + BOOLEAN bHeaderChangeAllowed; + int SelectedChip; + BOOLEAN bEndPointHalted; + /* while bFlashRawRead will be true, Driver ignore map lay out and consider flash as of without any map. */ + BOOLEAN bFlashRawRead; + BOOLEAN bPreparingForLowPowerMode; + BOOLEAN bDoSuspend; + UINT syscfgBefFwDld; + BOOLEAN StopAllXaction; + UINT32 liTimeSinceLastNetEntry; /* Used to Support extended CAPI requirements from */ struct semaphore LowPowerModeSync; - ULONG liDrainCalculated; - UINT gpioBitMap; - - S_BCM_DEBUG_STATE stDebugState; - + ULONG liDrainCalculated; + UINT gpioBitMap; + S_BCM_DEBUG_STATE stDebugState; }; typedef struct _MINI_ADAPTER MINI_ADAPTER, *PMINI_ADAPTER; -#define GET_BCM_ADAPTER(net_dev) netdev_priv(net_dev) +#define GET_BCM_ADAPTER(net_dev) netdev_priv(net_dev) struct _ETH_HEADER_STRUC { - UCHAR au8DestinationAddress[6]; - UCHAR au8SourceAddress[6]; - USHORT u16Etype; -}__attribute__((packed)); + UCHAR au8DestinationAddress[6]; + UCHAR au8SourceAddress[6]; + USHORT u16Etype; +} __packed; typedef struct _ETH_HEADER_STRUC ETH_HEADER_STRUC, *PETH_HEADER_STRUC; +typedef struct FirmwareInfo { + void __user *pvMappedFirmwareAddress; + ULONG u32FirmwareLength; + ULONG u32StartingAddress; +} __packed FIRMWARE_INFO, *PFIRMWARE_INFO; -typedef struct FirmwareInfo -{ - void __user * pvMappedFirmwareAddress; - ULONG u32FirmwareLength; - ULONG u32StartingAddress; -}__attribute__((packed)) FIRMWARE_INFO, *PFIRMWARE_INFO; - -// holds the value of net_device structure.. +/* holds the value of net_device structure.. */ extern struct net_device *gblpnetdev; -typedef struct _cntl_pkt{ - PMINI_ADAPTER Adapter; - PLEADER PLeader; -}cntl_pkt; +typedef struct _cntl_pkt { + PMINI_ADAPTER Adapter; + PLEADER PLeader; +} cntl_pkt; typedef LINK_REQUEST CONTROL_MESSAGE; -typedef struct _DDR_SETTING -{ +typedef struct _DDR_SETTING { UINT ulRegAddress; UINT ulRegValue; -}DDR_SETTING, *PDDR_SETTING; +} DDR_SETTING, *PDDR_SETTING; typedef DDR_SETTING DDR_SET_NODE, *PDDR_SET_NODE; -INT -InitAdapter(PMINI_ADAPTER psAdapter); - -// ===================================================================== -// Beceem vendor request codes for EP0 -// ===================================================================== +int InitAdapter(PMINI_ADAPTER psAdapter); -#define BCM_REQUEST_READ 0x2 -#define BCM_REQUEST_WRITE 0x1 -#define EP2_MPS_REG 0x0F0110A0 -#define EP2_MPS 0x40 +/* ===================================================================== + * Beceem vendor request codes for EP0 + * ===================================================================== + */ -#define EP2_CFG_REG 0x0F0110A8 -#define EP2_CFG_INT 0x27 -#define EP2_CFG_BULK 0x25 +#define BCM_REQUEST_READ 0x2 +#define BCM_REQUEST_WRITE 0x1 +#define EP2_MPS_REG 0x0F0110A0 +#define EP2_MPS 0x40 -#define EP4_MPS_REG 0x0F0110F0 -#define EP4_MPS 0x8C +#define EP2_CFG_REG 0x0F0110A8 +#define EP2_CFG_INT 0x27 +#define EP2_CFG_BULK 0x25 -#define EP4_CFG_REG 0x0F0110F8 +#define EP4_MPS_REG 0x0F0110F0 +#define EP4_MPS 0x8C -#define ISO_MPS_REG 0x0F0110C8 -#define ISO_MPS 0x00000000 +#define EP4_CFG_REG 0x0F0110F8 +#define ISO_MPS_REG 0x0F0110C8 +#define ISO_MPS 0x00000000 #define EP1 0 #define EP2 1 @@ -637,12 +585,9 @@ InitAdapter(PMINI_ADAPTER psAdapter); #define EP5 4 #define EP6 5 - -typedef enum eInterface_setting -{ +typedef enum eInterface_setting { DEFAULT_SETTING_0 = 0, ALTERNATE_SETTING_1 = 1, -}INTERFACE_SETTING; - -#endif //__ADAPTER_H__ +} INTERFACE_SETTING; +#endif /* __ADAPTER_H__ */ diff --git a/trunk/drivers/staging/bcm/DDRInit.c b/trunk/drivers/staging/bcm/DDRInit.c index 1c7db81a1ee8..2b46f4d4ef0e 100644 --- a/trunk/drivers/staging/bcm/DDRInit.c +++ b/trunk/drivers/staging/bcm/DDRInit.c @@ -1115,20 +1115,20 @@ int download_ddr_settings(PMINI_ADAPTER Adapter) { case DDR_80_MHZ: psDDRSetting = asT3LP_DDRSetting80MHz; - RegCount = (sizeof(asT3LP_DDRSetting80MHz)/sizeof(DDR_SET_NODE)); + RegCount = ARRAY_SIZE(asT3LP_DDRSetting80MHz); RegCount -= T3LP_SKIP_CLOCK_PROGRAM_DUMP_80MHZ ; psDDRSetting += T3LP_SKIP_CLOCK_PROGRAM_DUMP_80MHZ; break; case DDR_100_MHZ: psDDRSetting = asT3LP_DDRSetting100MHz; - RegCount = (sizeof(asT3LP_DDRSetting100MHz)/sizeof(DDR_SET_NODE)); + RegCount = ARRAY_SIZE(asT3LP_DDRSetting100MHz); RegCount -= T3LP_SKIP_CLOCK_PROGRAM_DUMP_100MHZ ; psDDRSetting += T3LP_SKIP_CLOCK_PROGRAM_DUMP_100MHZ; break; case DDR_133_MHZ: bOverrideSelfRefresh = TRUE; psDDRSetting = asT3LP_DDRSetting133MHz; - RegCount = (sizeof(asT3LP_DDRSetting133MHz)/sizeof(DDR_SET_NODE)); + RegCount = ARRAY_SIZE(asT3LP_DDRSetting133MHz); RegCount -= T3LP_SKIP_CLOCK_PROGRAM_DUMP_133MHZ ; psDDRSetting += T3LP_SKIP_CLOCK_PROGRAM_DUMP_133MHZ; break; @@ -1146,20 +1146,20 @@ int download_ddr_settings(PMINI_ADAPTER Adapter) { case DDR_80_MHZ: psDDRSetting = asT3LPB_DDRSetting80MHz; - RegCount=(sizeof(asT3LPB_DDRSetting80MHz)/sizeof(DDR_SET_NODE)); + RegCount=ARRAY_SIZE(asT3LPB_DDRSetting80MHz); RegCount -= T3LPB_SKIP_CLOCK_PROGRAM_DUMP_80MHZ ; psDDRSetting += T3LPB_SKIP_CLOCK_PROGRAM_DUMP_80MHZ; break; case DDR_100_MHZ: psDDRSetting = asT3LPB_DDRSetting100MHz; - RegCount = (sizeof(asT3LPB_DDRSetting100MHz)/sizeof(DDR_SET_NODE)); + RegCount = ARRAY_SIZE(asT3LPB_DDRSetting100MHz); RegCount -= T3LPB_SKIP_CLOCK_PROGRAM_DUMP_100MHZ ; psDDRSetting += T3LPB_SKIP_CLOCK_PROGRAM_DUMP_100MHZ; break; case DDR_133_MHZ: bOverrideSelfRefresh = TRUE; psDDRSetting = asT3LPB_DDRSetting133MHz; - RegCount = (sizeof(asT3LPB_DDRSetting133MHz)/sizeof(DDR_SET_NODE)); + RegCount = ARRAY_SIZE(asT3LPB_DDRSetting133MHz); RegCount -= T3LPB_SKIP_CLOCK_PROGRAM_DUMP_133MHZ ; psDDRSetting += T3LPB_SKIP_CLOCK_PROGRAM_DUMP_133MHZ; break; @@ -1167,7 +1167,7 @@ int download_ddr_settings(PMINI_ADAPTER Adapter) case DDR_160_MHZ: bOverrideSelfRefresh = TRUE; psDDRSetting = asT3LPB_DDRSetting160MHz; - RegCount = sizeof(asT3LPB_DDRSetting160MHz)/sizeof(DDR_SET_NODE); + RegCount = ARRAY_SIZE(asT3LPB_DDRSetting160MHz); RegCount -= T3LPB_SKIP_CLOCK_PROGRAM_DUMP_160MHZ; psDDRSetting += T3LPB_SKIP_CLOCK_PROGRAM_DUMP_160MHZ; @@ -1181,19 +1181,19 @@ int download_ddr_settings(PMINI_ADAPTER Adapter) { case DDR_80_MHZ: psDDRSetting = asT3_DDRSetting80MHz; - RegCount = (sizeof(asT3_DDRSetting80MHz)/sizeof(DDR_SET_NODE)); + RegCount = ARRAY_SIZE(asT3_DDRSetting80MHz); RegCount-=T3_SKIP_CLOCK_PROGRAM_DUMP_80MHZ ; psDDRSetting += T3_SKIP_CLOCK_PROGRAM_DUMP_80MHZ; break; case DDR_100_MHZ: psDDRSetting = asT3_DDRSetting100MHz; - RegCount = (sizeof(asT3_DDRSetting100MHz)/sizeof(DDR_SET_NODE)); + RegCount = ARRAY_SIZE(asT3_DDRSetting100MHz); RegCount-=T3_SKIP_CLOCK_PROGRAM_DUMP_100MHZ ; psDDRSetting += T3_SKIP_CLOCK_PROGRAM_DUMP_100MHZ; break; case DDR_133_MHZ: psDDRSetting = asT3_DDRSetting133MHz; - RegCount = (sizeof(asT3_DDRSetting133MHz)/sizeof(DDR_SET_NODE)); + RegCount = ARRAY_SIZE(asT3_DDRSetting133MHz); RegCount-=T3_SKIP_CLOCK_PROGRAM_DUMP_133MHZ ; psDDRSetting += T3_SKIP_CLOCK_PROGRAM_DUMP_133MHZ ; break; @@ -1207,20 +1207,20 @@ int download_ddr_settings(PMINI_ADAPTER Adapter) { case DDR_80_MHZ: psDDRSetting = asT3B_DDRSetting80MHz; - RegCount = (sizeof(asT3B_DDRSetting80MHz)/sizeof(DDR_SET_NODE)); + RegCount = ARRAY_SIZE(asT3B_DDRSetting80MHz); RegCount -= T3B_SKIP_CLOCK_PROGRAM_DUMP_80MHZ ; psDDRSetting += T3B_SKIP_CLOCK_PROGRAM_DUMP_80MHZ; break; case DDR_100_MHZ: psDDRSetting = asT3B_DDRSetting100MHz; - RegCount = (sizeof(asT3B_DDRSetting100MHz)/sizeof(DDR_SET_NODE)); + RegCount = ARRAY_SIZE(asT3B_DDRSetting100MHz); RegCount -= T3B_SKIP_CLOCK_PROGRAM_DUMP_100MHZ ; psDDRSetting += T3B_SKIP_CLOCK_PROGRAM_DUMP_100MHZ; break; case DDR_133_MHZ: bOverrideSelfRefresh = TRUE; psDDRSetting = asT3B_DDRSetting133MHz; - RegCount = (sizeof(asT3B_DDRSetting133MHz)/sizeof(DDR_SET_NODE)); + RegCount = ARRAY_SIZE(asT3B_DDRSetting133MHz); RegCount -= T3B_SKIP_CLOCK_PROGRAM_DUMP_133MHZ ; psDDRSetting += T3B_SKIP_CLOCK_PROGRAM_DUMP_133MHZ; break; diff --git a/trunk/drivers/staging/bcm/IPv6Protocol.c b/trunk/drivers/staging/bcm/IPv6Protocol.c index 5b4fd372ec36..1da21642c18e 100644 --- a/trunk/drivers/staging/bcm/IPv6Protocol.c +++ b/trunk/drivers/staging/bcm/IPv6Protocol.c @@ -1,51 +1,52 @@ #include "headers.h" -static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header); -static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header); +static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule, + IPV6Header *pstIpv6Header); +static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule, + IPV6Header *pstIpv6Header); static VOID DumpIpv6Header(IPV6Header *pstIpv6Header); -static UCHAR * GetNextIPV6ChainedHeader(UCHAR **ppucPayload,UCHAR *pucNextHeader,BOOLEAN *bParseDone,USHORT *pusPayloadLength) +static UCHAR *GetNextIPV6ChainedHeader(UCHAR **ppucPayload, + UCHAR *pucNextHeader, BOOLEAN *bParseDone, USHORT *pusPayloadLength) { UCHAR *pucRetHeaderPtr = NULL; UCHAR *pucPayloadPtr = NULL; USHORT usNextHeaderOffset = 0 ; - PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev); + PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev); - if((NULL == ppucPayload) || (*pusPayloadLength == 0) || (*bParseDone)) - { + if ((ppucPayload == NULL) || (*pusPayloadLength == 0) || + (*bParseDone)) { *bParseDone = TRUE; return NULL; - } pucRetHeaderPtr = *ppucPayload; pucPayloadPtr = *ppucPayload; - if(!pucRetHeaderPtr || !pucPayloadPtr) - { + if (!pucRetHeaderPtr || !pucPayloadPtr) { *bParseDone = TRUE; return NULL; } - //Get the Nextt Header Type + /* Get the Nextt Header Type */ *bParseDone = FALSE; - - switch(*pucNextHeader) - { + switch (*pucNextHeader) { case IPV6HDR_TYPE_HOPBYHOP: { - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 HopByHop Header"); - usNextHeaderOffset+=sizeof(IPV6HopByHopOptionsHeader); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, "\nIPv6 HopByHop Header"); + usNextHeaderOffset += sizeof(IPV6HopByHopOptionsHeader); } break; case IPV6HDR_TYPE_ROUTING: { IPV6RoutingHeader *pstIpv6RoutingHeader; - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Routing Header"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, "\nIPv6 Routing Header"); pstIpv6RoutingHeader = (IPV6RoutingHeader *)pucPayloadPtr; usNextHeaderOffset += sizeof(IPV6RoutingHeader); usNextHeaderOffset += pstIpv6RoutingHeader->ucNumAddresses * IPV6_ADDRESS_SIZEINBYTES; @@ -54,8 +55,10 @@ static UCHAR * GetNextIPV6ChainedHeader(UCHAR **ppucPayload,UCHAR *pucNextHeader break; case IPV6HDR_TYPE_FRAGMENTATION: { - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Fragmentation Header"); - usNextHeaderOffset+= sizeof(IPV6FragmentHeader); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, + "\nIPv6 Fragmentation Header"); + usNextHeaderOffset += sizeof(IPV6FragmentHeader); } break; @@ -63,9 +66,11 @@ static UCHAR * GetNextIPV6ChainedHeader(UCHAR **ppucPayload,UCHAR *pucNextHeader { IPV6DestOptionsHeader *pstIpv6DestOptsHdr = (IPV6DestOptionsHeader *)pucPayloadPtr; int nTotalOptions = pstIpv6DestOptsHdr->ucHdrExtLen; - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 DestOpts Header Header"); - usNextHeaderOffset+= sizeof(IPV6DestOptionsHeader); - usNextHeaderOffset+= nTotalOptions * IPV6_DESTOPTS_HDR_OPTIONSIZE ; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, + "\nIPv6 DestOpts Header Header"); + usNextHeaderOffset += sizeof(IPV6DestOptionsHeader); + usNextHeaderOffset += nTotalOptions * IPV6_DESTOPTS_HDR_OPTIONSIZE ; } break; @@ -73,36 +78,43 @@ static UCHAR * GetNextIPV6ChainedHeader(UCHAR **ppucPayload,UCHAR *pucNextHeader { IPV6AuthenticationHeader *pstIpv6AuthHdr = (IPV6AuthenticationHeader *)pucPayloadPtr; int nHdrLen = pstIpv6AuthHdr->ucLength; - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Authentication Header"); - usNextHeaderOffset+= nHdrLen * 4; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, + "\nIPv6 Authentication Header"); + usNextHeaderOffset += nHdrLen * 4; } break; case IPV6HDR_TYPE_ENCRYPTEDSECURITYPAYLOAD: { - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Encrypted Security Payload Header"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, + "\nIPv6 Encrypted Security Payload Header"); *bParseDone = TRUE; } break; case IPV6_ICMP_HDR_TYPE: { - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, " ICMP Header"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, "\nICMP Header"); *bParseDone = TRUE; } break; case TCP_HEADER_TYPE: { - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, " \nTCP Header"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, "\nTCP Header"); *bParseDone = TRUE; } break; case UDP_HEADER_TYPE: { - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, " \nUDP Header"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, "\nUDP Header"); *bParseDone = TRUE; } break; - default : + default: { *bParseDone = TRUE; @@ -112,53 +124,49 @@ static UCHAR * GetNextIPV6ChainedHeader(UCHAR **ppucPayload,UCHAR *pucNextHeader } - if(*bParseDone == FALSE) - { - if(*pusPayloadLength <= usNextHeaderOffset) - { + if (*bParseDone == FALSE) { + if (*pusPayloadLength <= usNextHeaderOffset) { *bParseDone = TRUE; - } - else - { + } else { *pucNextHeader = *pucPayloadPtr; - pucPayloadPtr+=usNextHeaderOffset; - (*pusPayloadLength)-=usNextHeaderOffset; + pucPayloadPtr += usNextHeaderOffset; + (*pusPayloadLength) -= usNextHeaderOffset; } } - - *ppucPayload = pucPayloadPtr; return pucRetHeaderPtr; } -static UCHAR GetIpv6ProtocolPorts(UCHAR *pucPayload,USHORT *pusSrcPort,USHORT *pusDestPort,USHORT usPayloadLength,UCHAR ucNextHeader) +static UCHAR GetIpv6ProtocolPorts(UCHAR *pucPayload, USHORT *pusSrcPort, + USHORT *pusDestPort, USHORT usPayloadLength, UCHAR ucNextHeader) { UCHAR *pIpv6HdrScanContext = pucPayload; BOOLEAN bDone = FALSE; - UCHAR ucHeaderType =0; + UCHAR ucHeaderType = 0; UCHAR *pucNextHeader = NULL; - PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev); + PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev); - if( !pucPayload || (usPayloadLength == 0)) - { + if (!pucPayload || (usPayloadLength == 0)) return 0; - } *pusSrcPort = *pusDestPort = 0; ucHeaderType = ucNextHeader; - while(!bDone) - { - pucNextHeader = GetNextIPV6ChainedHeader(&pIpv6HdrScanContext,&ucHeaderType,&bDone,&usPayloadLength); - if(bDone) - { - if((ucHeaderType==TCP_HEADER_TYPE) || (ucHeaderType == UDP_HEADER_TYPE)) - { - *pusSrcPort=*((PUSHORT)(pucNextHeader)); - *pusDestPort=*((PUSHORT)(pucNextHeader+2)); - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, " \nProtocol Ports - Src Port :0x%x Dest Port : 0x%x",ntohs(*pusSrcPort),ntohs(*pusDestPort)); + while (!bDone) { + pucNextHeader = GetNextIPV6ChainedHeader(&pIpv6HdrScanContext, + &ucHeaderType, &bDone, &usPayloadLength); + if (bDone) { + if ((ucHeaderType == TCP_HEADER_TYPE) || + (ucHeaderType == UDP_HEADER_TYPE)) { + *pusSrcPort = *((PUSHORT)(pucNextHeader)); + *pusDestPort = *((PUSHORT)(pucNextHeader+2)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, + "\nProtocol Ports - Src Port :0x%x Dest Port : 0x%x", + ntohs(*pusSrcPort), + ntohs(*pusDestPort)); } break; @@ -168,92 +176,111 @@ static UCHAR GetIpv6ProtocolPorts(UCHAR *pucPayload,USHORT *pusSrcPort,USHORT *p } - -USHORT IpVersion6(PMINI_ADAPTER Adapter, /**< Pointer to the driver control structure */ - PVOID pcIpHeader, /**\n"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, "IpVersion6 ==========>\n"); pstIpv6Header = (IPV6Header *)pcIpHeader; DumpIpv6Header(pstIpv6Header); - //Try to get the next higher layer protocol and the Ports Nos if TCP or UDP + /* + * Try to get the next higher layer protocol + * and the Ports Nos if TCP or UDP + */ ucNextProtocolAboveIP = GetIpv6ProtocolPorts((UCHAR *)(pcIpHeader + sizeof(IPV6Header)), &ushSrcPort, &ushDestPort, pstIpv6Header->usPayloadLength, pstIpv6Header->ucNextHeader); - do - { - if(0 == pstClassifierRule->ucDirection) - { - //cannot be processed for classification. - // it is a down link connection + do { + if (pstClassifierRule->ucDirection == 0) { + /* + * cannot be processed for classification. + * it is a down link connection + */ break; } - if(!pstClassifierRule->bIpv6Protocol) - { - //We are looking for Ipv6 Classifiers . Lets ignore this classifier and try the next one. + if (!pstClassifierRule->bIpv6Protocol) { + /* + * We are looking for Ipv6 Classifiers + * Lets ignore this classifier and try the next one + */ break; } - bClassificationSucceed=MatchSrcIpv6Address(pstClassifierRule,pstIpv6Header); - if(!bClassificationSucceed) - break; + bClassificationSucceed = MatchSrcIpv6Address(pstClassifierRule, + pstIpv6Header); + if (!bClassificationSucceed) + break; - bClassificationSucceed=MatchDestIpv6Address(pstClassifierRule,pstIpv6Header); - if(!bClassificationSucceed) - break; + bClassificationSucceed = MatchDestIpv6Address(pstClassifierRule, + pstIpv6Header); + if (!bClassificationSucceed) + break; - //Match the protocol type.For IPv6 the next protocol at end of Chain of IPv6 prot headers - bClassificationSucceed=MatchProtocol(pstClassifierRule,ucNextProtocolAboveIP); - if(!bClassificationSucceed) - break; - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Protocol Matched"); + /* + * Match the protocol type. + * For IPv6 the next protocol at end of + * Chain of IPv6 prot headers + */ + bClassificationSucceed = MatchProtocol(pstClassifierRule, + ucNextProtocolAboveIP); + if (!bClassificationSucceed) + break; - if((ucNextProtocolAboveIP == TCP_HEADER_TYPE) || (ucNextProtocolAboveIP == UDP_HEADER_TYPE)) - { - //Match Src Port - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Source Port:%x\n",ntohs(ushSrcPort)); - bClassificationSucceed=MatchSrcPort(pstClassifierRule,ntohs(ushSrcPort)); - if(!bClassificationSucceed) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, "\nIPv6 Protocol Matched"); + + if ((ucNextProtocolAboveIP == TCP_HEADER_TYPE) || + (ucNextProtocolAboveIP == UDP_HEADER_TYPE)) { + /* Match Src Port */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, "\nIPv6 Source Port:%x\n", + ntohs(ushSrcPort)); + bClassificationSucceed = MatchSrcPort(pstClassifierRule, + ntohs(ushSrcPort)); + if (!bClassificationSucceed) break; - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Src Port Matched"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, "\nIPv6 Src Port Matched"); - //Match Dest Port - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Destination Port:%x\n",ntohs(ushDestPort)); - bClassificationSucceed=MatchDestPort(pstClassifierRule,ntohs(ushDestPort)); - if(!bClassificationSucceed) + /* Match Dest Port */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, "\nIPv6 Destination Port:%x\n", + ntohs(ushDestPort)); + bClassificationSucceed = MatchDestPort(pstClassifierRule, + ntohs(ushDestPort)); + if (!bClassificationSucceed) break; - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Dest Port Matched"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, "\nIPv6 Dest Port Matched"); } - }while(0); + } while (0); - if(TRUE==bClassificationSucceed) - { + if (bClassificationSucceed == TRUE) { INT iMatchedSFQueueIndex = 0; - iMatchedSFQueueIndex = SearchSfid(Adapter,pstClassifierRule->ulSFID); - if(iMatchedSFQueueIndex >= NO_OF_QUEUES) - { + iMatchedSFQueueIndex = SearchSfid(Adapter, pstClassifierRule->ulSFID); + if (iMatchedSFQueueIndex >= NO_OF_QUEUES) { bClassificationSucceed = FALSE; - } - else - { - if(FALSE == Adapter->PackInfo[iMatchedSFQueueIndex].bActive) - { + } else { + if (Adapter->PackInfo[iMatchedSFQueueIndex].bActive == FALSE) bClassificationSucceed = FALSE; - } } } @@ -261,52 +288,55 @@ USHORT IpVersion6(PMINI_ADAPTER Adapter, /**< Pointer to the driver control stru } -static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header) +static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule, + IPV6Header *pstIpv6Header) { - UINT uiLoopIndex=0; - UINT uiIpv6AddIndex=0; - UINT uiIpv6AddrNoLongWords = 4; + UINT uiLoopIndex = 0; + UINT uiIpv6AddIndex = 0; + UINT uiIpv6AddrNoLongWords = 4; ULONG aulSrcIP[4]; - PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev); + PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev); /* - //This is the no. of Src Addresses ie Range of IP Addresses contained - //in the classifier rule for which we need to match - */ + * This is the no. of Src Addresses ie Range of IP Addresses contained + * in the classifier rule for which we need to match + */ UINT uiCountIPSrcAddresses = (UINT)pstClassifierRule->ucIPSourceAddressLength; - if(0 == uiCountIPSrcAddresses) + if (uiCountIPSrcAddresses == 0) return TRUE; - //First Convert the Ip Address in the packet to Host Endian order - for(uiIpv6AddIndex=0;uiIpv6AddIndexulSrcIpAddress[uiIpv6AddIndex]); - } + /* First Convert the Ip Address in the packet to Host Endian order */ + for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++) + aulSrcIP[uiIpv6AddIndex] = ntohl(pstIpv6Header->ulSrcIpAddress[uiIpv6AddIndex]); - for(uiLoopIndex=0;uiLoopIndexstSrcIpAddress.ulIpv6Mask[uiLoopIndex]); - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\n Src Ipv6 Address In Classifier Rule : \n"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + "\n Src Ipv6 Address In Classifier Rule :\n"); DumpIpv6Address(&pstClassifierRule->stSrcIpAddress.ulIpv6Addr[uiLoopIndex]); - for(uiIpv6AddIndex=0;uiIpv6AddIndexstSrcIpAddress.ulIpv6Mask[uiLoopIndex+uiIpv6AddIndex] & aulSrcIP[uiIpv6AddIndex]) - != pstClassifierRule->stSrcIpAddress.ulIpv6Addr[uiLoopIndex+uiIpv6AddIndex]) - { - //Match failed for current Ipv6 Address.Try next Ipv6 Address + for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++) { + if ((pstClassifierRule->stSrcIpAddress.ulIpv6Mask[uiLoopIndex+uiIpv6AddIndex] & aulSrcIP[uiIpv6AddIndex]) + != pstClassifierRule->stSrcIpAddress.ulIpv6Addr[uiLoopIndex+uiIpv6AddIndex]) { + /* + * Match failed for current Ipv6 Address + * Try next Ipv6 Address + */ break; } - if(uiIpv6AddIndex == uiIpv6AddrNoLongWords-1) - { - //Match Found - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Ipv6 Src Ip Address Matched\n"); + if (uiIpv6AddIndex == uiIpv6AddrNoLongWords-1) { + /* Match Found */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, + "Ipv6 Src Ip Address Matched\n"); return TRUE; } } @@ -314,52 +344,56 @@ static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Head return FALSE; } -static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header) +static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule, + IPV6Header *pstIpv6Header) { - UINT uiLoopIndex=0; - UINT uiIpv6AddIndex=0; - UINT uiIpv6AddrNoLongWords = 4; + UINT uiLoopIndex = 0; + UINT uiIpv6AddIndex = 0; + UINT uiIpv6AddrNoLongWords = 4; ULONG aulDestIP[4]; - PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev); + PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev); /* - //This is the no. of Destination Addresses ie Range of IP Addresses contained - //in the classifier rule for which we need to match - */ + * This is the no. of Destination Addresses + * ie Range of IP Addresses contained in the classifier rule + * for which we need to match + */ UINT uiCountIPDestinationAddresses = (UINT)pstClassifierRule->ucIPDestinationAddressLength; - if(0 == uiCountIPDestinationAddresses) + if (uiCountIPDestinationAddresses == 0) return TRUE; - //First Convert the Ip Address in the packet to Host Endian order - for(uiIpv6AddIndex=0;uiIpv6AddIndexulDestIpAddress[uiIpv6AddIndex]); - } + /* First Convert the Ip Address in the packet to Host Endian order */ + for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++) + aulDestIP[uiIpv6AddIndex] = ntohl(pstIpv6Header->ulDestIpAddress[uiIpv6AddIndex]); - for(uiLoopIndex=0;uiLoopIndexstDestIpAddress.ulIpv6Mask[uiLoopIndex]); - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\n Destination Ipv6 Address In Classifier Rule : \n"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + "\n Destination Ipv6 Address In Classifier Rule :\n"); DumpIpv6Address(&pstClassifierRule->stDestIpAddress.ulIpv6Addr[uiLoopIndex]); - for(uiIpv6AddIndex=0;uiIpv6AddIndexstDestIpAddress.ulIpv6Mask[uiLoopIndex+uiIpv6AddIndex] & aulDestIP[uiIpv6AddIndex]) - != pstClassifierRule->stDestIpAddress.ulIpv6Addr[uiLoopIndex+uiIpv6AddIndex]) - { - //Match failed for current Ipv6 Address.Try next Ipv6 Address + for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++) { + if ((pstClassifierRule->stDestIpAddress.ulIpv6Mask[uiLoopIndex+uiIpv6AddIndex] & aulDestIP[uiIpv6AddIndex]) + != pstClassifierRule->stDestIpAddress.ulIpv6Addr[uiLoopIndex+uiIpv6AddIndex]) { + /* + * Match failed for current Ipv6 Address. + * Try next Ipv6 Address + */ break; } - if(uiIpv6AddIndex == uiIpv6AddrNoLongWords-1) - { - //Match Found - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Ipv6 Destination Ip Address Matched\n"); + if (uiIpv6AddIndex == uiIpv6AddrNoLongWords-1) { + /* Match Found */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, + "Ipv6 Destination Ip Address Matched\n"); return TRUE; } } @@ -371,11 +405,11 @@ static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Hea VOID DumpIpv6Address(ULONG *puIpv6Address) { UINT uiIpv6AddrNoLongWords = 4; - UINT uiIpv6AddIndex=0; - PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev); - for(uiIpv6AddIndex=0;uiIpv6AddIndexucVersionPrio & 0xf0; - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Version : %x \n",ucVersion); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + "Version : %x\n", ucVersion); ucPrio = pstIpv6Header->ucVersionPrio & 0x0f; - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Priority : %x \n",ucPrio); - //BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Flow Label : %x \n",(pstIpv6Header->ucVersionPrio &0xf0); - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Payload Length : %x \n",ntohs(pstIpv6Header->usPayloadLength)); - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Next Header : %x \n",pstIpv6Header->ucNextHeader); - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Hop Limit : %x \n",pstIpv6Header->ucHopLimit); - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Src Address :\n"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + "Priority : %x\n", ucPrio); + /* + * BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + * "Flow Label : %x\n",(pstIpv6Header->ucVersionPrio &0xf0); + */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + "Payload Length : %x\n", + ntohs(pstIpv6Header->usPayloadLength)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + "Next Header : %x\n", pstIpv6Header->ucNextHeader); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + "Hop Limit : %x\n", pstIpv6Header->ucHopLimit); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + "Src Address :\n"); DumpIpv6Address(pstIpv6Header->ulSrcIpAddress); - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Dest Address :\n"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + "Dest Address :\n"); DumpIpv6Address(pstIpv6Header->ulDestIpAddress); - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "----Ipv6 Header End---"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + "----Ipv6 Header End---"); } diff --git a/trunk/drivers/staging/bcm/Misc.c b/trunk/drivers/staging/bcm/Misc.c index c7725e141fd5..8223a6913fc5 100644 --- a/trunk/drivers/staging/bcm/Misc.c +++ b/trunk/drivers/staging/bcm/Misc.c @@ -835,7 +835,7 @@ int reset_card_proc(PMINI_ADAPTER ps_adapter) Bcm_kill_all_URBs(psIntfAdapter); /* Reset the UMA-B Device */ if (ps_adapter->chip_id >= T3LPB) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Reseting UMA-B\n"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Resetting UMA-B\n"); retval = usb_reset_device(psIntfAdapter->udev); psIntfAdapter->psAdapter->StopAllXaction = FALSE; diff --git a/trunk/drivers/staging/ccg/Kconfig b/trunk/drivers/staging/ccg/Kconfig new file mode 100644 index 000000000000..ff05e52392bf --- /dev/null +++ b/trunk/drivers/staging/ccg/Kconfig @@ -0,0 +1,20 @@ +if USB_GADGET + +config USB_G_CCG + tristate "Configurable Composite Gadget (STAGING)" + depends on STAGING && !USB_ZERO && !USB_ZERO_HNPTEST && !USB_AUDIO && !GADGET_UAC1 && !USB_ETH && !USB_ETH_RNDIS && !USB_ETH_EEM && !USB_G_NCM && !USB_GADGETFS && !USB_FUNCTIONFS && !USB_FUNCTIONFS_ETH && !USB_FUNCTIONFS_RNDIS && !USB_FUNCTIONFS_GENERIC && !USB_FILE_STORAGE && !USB_FILE_STORAGE_TEST && !USB_MASS_STORAGE && !USB_G_SERIAL && !USB_MIDI_GADGET && !USB_G_PRINTER && !USB_CDC_COMPOSITE && !USB_G_NOKIA && !USB_G_ACM_MS && !USB_G_MULTI && !USB_G_MULTI_RNDIS && !USB_G_MULTI_CDC && !USB_G_HID && !USB_G_DBGP && !USB_G_WEBCAM + help + The Configurable Composite Gadget supports multiple USB + functions: acm, mass storage, rndis and FunctionFS. + Each function can be configured and enabled/disabled + dynamically from userspace through a sysfs interface. + + In order to compile this (either as a module or built-in), + "USB Gadget Drivers" and anything under it must not be + selected compiled-in in + Device Drivers->USB Support->USB Gadget Support. + However, you can say "M" there, if you do, the + Configurable Composite Gadget can be compiled "M" only + or not at all. + +endif # USB_GADGET diff --git a/trunk/drivers/staging/ccg/Makefile b/trunk/drivers/staging/ccg/Makefile new file mode 100644 index 000000000000..693da637a6d8 --- /dev/null +++ b/trunk/drivers/staging/ccg/Makefile @@ -0,0 +1,4 @@ +g_ccg-y := ccg.o +ccflags-y += -Idrivers/usb/gadget + +obj-$(CONFIG_USB_G_CCG) += g_ccg.o diff --git a/trunk/drivers/staging/ccg/TODO b/trunk/drivers/staging/ccg/TODO new file mode 100644 index 000000000000..18612fe70171 --- /dev/null +++ b/trunk/drivers/staging/ccg/TODO @@ -0,0 +1,6 @@ +TODO: + - change configuration interface from sysfs to configfs + +Please send patches to Greg Kroah-Hartmann , +Andrzej Pietrasiewicz , and +Cc: Mike Lockwood diff --git a/trunk/drivers/staging/ccg/ccg.c b/trunk/drivers/staging/ccg/ccg.c new file mode 100644 index 000000000000..a5b36a97598d --- /dev/null +++ b/trunk/drivers/staging/ccg/ccg.c @@ -0,0 +1,1299 @@ +/* + * Configurable Composite Gadget + * + * Initially contributed as "Android Composite Gdaget" by: + * + * Copyright (C) 2008 Google, Inc. + * Author: Mike Lockwood + * Benoit Goby + * + * Tailoring it to become a generic Configurable Composite Gadget is + * + * Copyright (C) 2012 Samsung Electronics + * Author: Andrzej Pietrasiewicz + * + * 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 +#include + +#include +#include +#include + +#include "gadget_chips.h" + +/* + * Kbuild is not very cooperative with respect to linking separately + * compiled library objects into one module. So for now we won't use + * separate compilation ... ensuring init/exit sections work to shrink + * the runtime footprint, and giving us at least some parts of what + * a "gcc --combine ... part1.c part2.c part3.c ... " build would. + */ +#include "../../usb/gadget/usbstring.c" +#include "../../usb/gadget/config.c" +#include "../../usb/gadget/epautoconf.c" +#include "../../usb/gadget/composite.c" + +#include "../../usb/gadget/f_mass_storage.c" +#include "../../usb/gadget/u_serial.c" +#include "../../usb/gadget/f_acm.c" +#define USB_ETH_RNDIS y +#include "../../usb/gadget/f_rndis.c" +#include "../../usb/gadget/rndis.c" +#include "../../usb/gadget/u_ether.c" +#include "../../usb/gadget/f_fs.c" + +MODULE_AUTHOR("Mike Lockwood, Andrzej Pietrasiewicz"); +MODULE_DESCRIPTION("Configurable Composite USB Gadget"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("1.0"); + +static const char longname[] = "Configurable Composite Gadget"; + +/* Default vendor and product IDs, overridden by userspace */ +#define VENDOR_ID 0x1d6b /* Linux Foundation */ +#define PRODUCT_ID 0x0107 +#define GFS_MAX_DEVS 10 + +struct ccg_usb_function { + char *name; + void *config; + + struct device *dev; + char *dev_name; + struct device_attribute **attributes; + + /* for ccg_dev.enabled_functions */ + struct list_head enabled_list; + + /* Optional: initialization during gadget bind */ + int (*init)(struct ccg_usb_function *, struct usb_composite_dev *); + /* Optional: cleanup during gadget unbind */ + void (*cleanup)(struct ccg_usb_function *); + + int (*bind_config)(struct ccg_usb_function *, + struct usb_configuration *); + + /* Optional: called when the configuration is removed */ + void (*unbind_config)(struct ccg_usb_function *, + struct usb_configuration *); + /* Optional: handle ctrl requests before the device is configured */ + int (*ctrlrequest)(struct ccg_usb_function *, + struct usb_composite_dev *, + const struct usb_ctrlrequest *); +}; + +struct ffs_obj { + const char *name; + bool mounted; + bool desc_ready; + bool used; + struct ffs_data *ffs_data; +}; + +struct ccg_dev { + struct ccg_usb_function **functions; + struct list_head enabled_functions; + struct usb_composite_dev *cdev; + struct device *dev; + + bool enabled; + struct mutex mutex; + bool connected; + bool sw_connected; + struct work_struct work; + + unsigned int max_func_num; + unsigned int func_num; + struct ffs_obj ffs_tab[GFS_MAX_DEVS]; +}; + +static struct class *ccg_class; +static struct ccg_dev *_ccg_dev; +static int ccg_bind_config(struct usb_configuration *c); +static void ccg_unbind_config(struct usb_configuration *c); + +static char func_names_buf[256]; + +static struct usb_device_descriptor device_desc = { + .bLength = sizeof(device_desc), + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = __constant_cpu_to_le16(0x0200), + .bDeviceClass = USB_CLASS_PER_INTERFACE, + .idVendor = __constant_cpu_to_le16(VENDOR_ID), + .idProduct = __constant_cpu_to_le16(PRODUCT_ID), + .bcdDevice = __constant_cpu_to_le16(0xffff), + .bNumConfigurations = 1, +}; + +static struct usb_configuration ccg_config_driver = { + .label = "ccg", + .unbind = ccg_unbind_config, + .bConfigurationValue = 1, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = 0xFA, /* 500ma */ +}; + +static void ccg_work(struct work_struct *data) +{ + struct ccg_dev *dev = container_of(data, struct ccg_dev, work); + struct usb_composite_dev *cdev = dev->cdev; + static char *disconnected[2] = { "USB_STATE=DISCONNECTED", NULL }; + static char *connected[2] = { "USB_STATE=CONNECTED", NULL }; + static char *configured[2] = { "USB_STATE=CONFIGURED", NULL }; + char **uevent_envp = NULL; + unsigned long flags; + + spin_lock_irqsave(&cdev->lock, flags); + if (cdev->config) + uevent_envp = configured; + else if (dev->connected != dev->sw_connected) + uevent_envp = dev->connected ? connected : disconnected; + dev->sw_connected = dev->connected; + spin_unlock_irqrestore(&cdev->lock, flags); + + if (uevent_envp) { + kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE, uevent_envp); + pr_info("%s: sent uevent %s\n", __func__, uevent_envp[0]); + } else { + pr_info("%s: did not send uevent (%d %d %p)\n", __func__, + dev->connected, dev->sw_connected, cdev->config); + } +} + + +/*-------------------------------------------------------------------------*/ +/* Supported functions initialization */ + +static struct ffs_obj *functionfs_find_dev(struct ccg_dev *dev, + const char *dev_name) +{ + int i; + + for (i = 0; i < dev->max_func_num; i++) + if (strcmp(dev->ffs_tab[i].name, dev_name) == 0) + return &dev->ffs_tab[i]; + + return NULL; +} + +static bool functionfs_all_ready(struct ccg_dev *dev) +{ + int i; + + for (i = 0; i < dev->max_func_num; i++) + if (dev->ffs_tab[i].used && !dev->ffs_tab[i].desc_ready) + return false; + + return true; +} + +static int functionfs_ready_callback(struct ffs_data *ffs) +{ + struct ffs_obj *ffs_obj; + int ret; + + mutex_lock(&_ccg_dev->mutex); + + ffs_obj = ffs->private_data; + if (!ffs_obj) { + ret = -EINVAL; + goto done; + } + if (WARN_ON(ffs_obj->desc_ready)) { + ret = -EBUSY; + goto done; + } + ffs_obj->ffs_data = ffs; + + if (functionfs_all_ready(_ccg_dev)) { + ret = -EBUSY; + goto done; + } + ffs_obj->desc_ready = true; + +done: + mutex_unlock(&_ccg_dev->mutex); + return ret; +} + +static void reset_usb(struct ccg_dev *dev) +{ + /* Cancel pending control requests */ + usb_ep_dequeue(dev->cdev->gadget->ep0, dev->cdev->req); + usb_remove_config(dev->cdev, &ccg_config_driver); + dev->enabled = false; + usb_gadget_disconnect(dev->cdev->gadget); +} + +static void functionfs_closed_callback(struct ffs_data *ffs) +{ + struct ffs_obj *ffs_obj; + + mutex_lock(&_ccg_dev->mutex); + + ffs_obj = ffs->private_data; + if (!ffs_obj) + goto done; + + ffs_obj->desc_ready = false; + + if (_ccg_dev->enabled) + reset_usb(_ccg_dev); + +done: + mutex_unlock(&_ccg_dev->mutex); +} + +static void *functionfs_acquire_dev_callback(const char *dev_name) +{ + struct ffs_obj *ffs_dev; + + mutex_lock(&_ccg_dev->mutex); + + ffs_dev = functionfs_find_dev(_ccg_dev, dev_name); + if (!ffs_dev) { + ffs_dev = ERR_PTR(-ENODEV); + goto done; + } + + if (ffs_dev->mounted) { + ffs_dev = ERR_PTR(-EBUSY); + goto done; + } + ffs_dev->mounted = true; + +done: + mutex_unlock(&_ccg_dev->mutex); + return ffs_dev; +} + +static void functionfs_release_dev_callback(struct ffs_data *ffs_data) +{ + struct ffs_obj *ffs_dev; + + mutex_lock(&_ccg_dev->mutex); + + ffs_dev = ffs_data->private_data; + if (ffs_dev) + ffs_dev->mounted = false; + + mutex_unlock(&_ccg_dev->mutex); +} + +static int functionfs_function_init(struct ccg_usb_function *f, + struct usb_composite_dev *cdev) +{ + return functionfs_init(); +} + +static void functionfs_function_cleanup(struct ccg_usb_function *f) +{ + functionfs_cleanup(); +} + +static int functionfs_function_bind_config(struct ccg_usb_function *f, + struct usb_configuration *c) +{ + struct ccg_dev *dev = _ccg_dev; + int i, ret; + + for (i = dev->max_func_num; i--; ) { + if (!dev->ffs_tab[i].used) + continue; + ret = functionfs_bind(dev->ffs_tab[i].ffs_data, c->cdev); + if (unlikely(ret < 0)) { + while (++i < dev->max_func_num) + functionfs_unbind(dev->ffs_tab[i].ffs_data); + return ret; + } + } + + for (i = dev->max_func_num; i--; ) { + if (!dev->ffs_tab[i].used) + continue; + ret = functionfs_bind_config(c->cdev, c, + dev->ffs_tab[i].ffs_data); + if (unlikely(ret < 0)) + return ret; + } + + return 0; +} + +static void functionfs_function_unbind_config(struct ccg_usb_function *f, + struct usb_configuration *c) +{ + struct ccg_dev *dev = _ccg_dev; + int i; + + for (i = dev->max_func_num; i--; ) + if (dev->ffs_tab[i].ffs_data) + functionfs_unbind(dev->ffs_tab[i].ffs_data); +} + +static ssize_t functionfs_user_functions_show(struct device *_dev, + struct device_attribute *attr, + char *buf) +{ + struct ccg_dev *dev = _ccg_dev; + char *buff = buf; + int i; + + mutex_lock(&dev->mutex); + + for (i = 0; i < dev->max_func_num; i++) + buff += snprintf(buff, PAGE_SIZE + buf - buff, "%s,", + dev->ffs_tab[i].name); + + mutex_unlock(&dev->mutex); + + if (buff != buf) + *(buff - 1) = '\n'; + return buff - buf; +} + +static ssize_t functionfs_user_functions_store(struct device *_dev, + struct device_attribute *attr, + const char *buff, size_t size) +{ + struct ccg_dev *dev = _ccg_dev; + char *name, *b; + ssize_t ret = size; + int i; + + buff = skip_spaces(buff); + if (!*buff) + return -EINVAL; + + mutex_lock(&dev->mutex); + + if (dev->enabled) { + ret = -EBUSY; + goto end; + } + + for (i = 0; i < dev->max_func_num; i++) + if (dev->ffs_tab[i].mounted) { + ret = -EBUSY; + goto end; + } + + strlcpy(func_names_buf, buff, sizeof(func_names_buf)); + b = strim(func_names_buf); + + /* replace the list of functions */ + dev->max_func_num = 0; + while (b) { + name = strsep(&b, ","); + if (dev->max_func_num == GFS_MAX_DEVS) { + ret = -ENOSPC; + goto end; + } + if (functionfs_find_dev(dev, name)) { + ret = -EEXIST; + continue; + } + dev->ffs_tab[dev->max_func_num++].name = name; + } + +end: + mutex_unlock(&dev->mutex); + return ret; +} + +static DEVICE_ATTR(user_functions, S_IRUGO | S_IWUSR, + functionfs_user_functions_show, + functionfs_user_functions_store); + +static ssize_t functionfs_max_user_functions_show(struct device *_dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d", GFS_MAX_DEVS); +} + +static DEVICE_ATTR(max_user_functions, S_IRUGO, + functionfs_max_user_functions_show, NULL); + +static struct device_attribute *functionfs_function_attributes[] = { + &dev_attr_user_functions, + &dev_attr_max_user_functions, + NULL +}; + +static struct ccg_usb_function functionfs_function = { + .name = "fs", + .init = functionfs_function_init, + .cleanup = functionfs_function_cleanup, + .bind_config = functionfs_function_bind_config, + .unbind_config = functionfs_function_unbind_config, + .attributes = functionfs_function_attributes, +}; + +#define MAX_ACM_INSTANCES 4 +struct acm_function_config { + int instances; +}; + +static int +acm_function_init(struct ccg_usb_function *f, struct usb_composite_dev *cdev) +{ + f->config = kzalloc(sizeof(struct acm_function_config), GFP_KERNEL); + if (!f->config) + return -ENOMEM; + + return gserial_setup(cdev->gadget, MAX_ACM_INSTANCES); +} + +static void acm_function_cleanup(struct ccg_usb_function *f) +{ + gserial_cleanup(); + kfree(f->config); + f->config = NULL; +} + +static int +acm_function_bind_config(struct ccg_usb_function *f, + struct usb_configuration *c) +{ + int i; + int ret = 0; + struct acm_function_config *config = f->config; + + for (i = 0; i < config->instances; i++) { + ret = acm_bind_config(c, i); + if (ret) { + pr_err("Could not bind acm%u config\n", i); + break; + } + } + + return ret; +} + +static ssize_t acm_instances_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ccg_usb_function *f = dev_get_drvdata(dev); + struct acm_function_config *config = f->config; + return sprintf(buf, "%d\n", config->instances); +} + +static ssize_t acm_instances_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct ccg_usb_function *f = dev_get_drvdata(dev); + struct acm_function_config *config = f->config; + int value; + int ret = 0; + + ret = kstrtoint(buf, 10, &value); + if (ret) + return ret; + + if (value > MAX_ACM_INSTANCES) + return -EINVAL; + + config->instances = value; + + return size; +} + +static DEVICE_ATTR(instances, S_IRUGO | S_IWUSR, acm_instances_show, + acm_instances_store); +static struct device_attribute *acm_function_attributes[] = { + &dev_attr_instances, + NULL +}; + +static struct ccg_usb_function acm_function = { + .name = "acm", + .init = acm_function_init, + .cleanup = acm_function_cleanup, + .bind_config = acm_function_bind_config, + .attributes = acm_function_attributes, +}; + +struct rndis_function_config { + u8 ethaddr[ETH_ALEN]; + u32 vendorID; + char manufacturer[256]; + /* "Wireless" RNDIS; auto-detected by Windows */ + bool wceis; +}; + +static int rndis_function_init(struct ccg_usb_function *f, + struct usb_composite_dev *cdev) +{ + f->config = kzalloc(sizeof(struct rndis_function_config), GFP_KERNEL); + if (!f->config) + return -ENOMEM; + return 0; +} + +static void rndis_function_cleanup(struct ccg_usb_function *f) +{ + kfree(f->config); + f->config = NULL; +} + +static int rndis_function_bind_config(struct ccg_usb_function *f, + struct usb_configuration *c) +{ + int ret; + struct rndis_function_config *rndis = f->config; + + if (!rndis) { + pr_err("%s: rndis_pdata\n", __func__); + return -1; + } + + pr_info("%s MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", __func__, + rndis->ethaddr[0], rndis->ethaddr[1], rndis->ethaddr[2], + rndis->ethaddr[3], rndis->ethaddr[4], rndis->ethaddr[5]); + + ret = gether_setup_name(c->cdev->gadget, rndis->ethaddr, "rndis"); + if (ret) { + pr_err("%s: gether_setup failed\n", __func__); + return ret; + } + + if (rndis->wceis) { + /* "Wireless" RNDIS; auto-detected by Windows */ + rndis_iad_descriptor.bFunctionClass = + USB_CLASS_WIRELESS_CONTROLLER; + rndis_iad_descriptor.bFunctionSubClass = 0x01; + rndis_iad_descriptor.bFunctionProtocol = 0x03; + rndis_control_intf.bInterfaceClass = + USB_CLASS_WIRELESS_CONTROLLER; + rndis_control_intf.bInterfaceSubClass = 0x01; + rndis_control_intf.bInterfaceProtocol = 0x03; + } + + return rndis_bind_config_vendor(c, rndis->ethaddr, rndis->vendorID, + rndis->manufacturer); +} + +static void rndis_function_unbind_config(struct ccg_usb_function *f, + struct usb_configuration *c) +{ + gether_cleanup(); +} + +static ssize_t rndis_manufacturer_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ccg_usb_function *f = dev_get_drvdata(dev); + struct rndis_function_config *config = f->config; + return sprintf(buf, "%s\n", config->manufacturer); +} + +static ssize_t rndis_manufacturer_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct ccg_usb_function *f = dev_get_drvdata(dev); + struct rndis_function_config *config = f->config; + + if (size >= sizeof(config->manufacturer)) + return -EINVAL; + memcpy(config->manufacturer, buf, size); + config->manufacturer[size] = 0; + + return size; +} + +static DEVICE_ATTR(manufacturer, S_IRUGO | S_IWUSR, rndis_manufacturer_show, + rndis_manufacturer_store); + +static ssize_t rndis_wceis_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ccg_usb_function *f = dev_get_drvdata(dev); + struct rndis_function_config *config = f->config; + return sprintf(buf, "%d\n", config->wceis); +} + +static ssize_t rndis_wceis_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct ccg_usb_function *f = dev_get_drvdata(dev); + struct rndis_function_config *config = f->config; + int value; + int ret; + + ret = kstrtoint(buf, 10, &value); + if (ret) + return ret; + + config->wceis = value; + + return size; +} + +static DEVICE_ATTR(wceis, S_IRUGO | S_IWUSR, rndis_wceis_show, + rndis_wceis_store); + +static ssize_t rndis_ethaddr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ccg_usb_function *f = dev_get_drvdata(dev); + struct rndis_function_config *rndis = f->config; + return sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n", + rndis->ethaddr[0], rndis->ethaddr[1], rndis->ethaddr[2], + rndis->ethaddr[3], rndis->ethaddr[4], rndis->ethaddr[5]); +} + +static ssize_t rndis_ethaddr_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct ccg_usb_function *f = dev_get_drvdata(dev); + struct rndis_function_config *rndis = f->config; + unsigned char tmp[6]; + + if (sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + tmp + 0, tmp + 1, tmp + 2, tmp + 3, tmp + 4, tmp + 5) != + ETH_ALEN) + return -EINVAL; + + memcpy(rndis->ethaddr, tmp, ETH_ALEN); + + return ETH_ALEN; + +} + +static DEVICE_ATTR(ethaddr, S_IRUGO | S_IWUSR, rndis_ethaddr_show, + rndis_ethaddr_store); + +static ssize_t rndis_vendorID_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ccg_usb_function *f = dev_get_drvdata(dev); + struct rndis_function_config *config = f->config; + return sprintf(buf, "%04x\n", config->vendorID); +} + +static ssize_t rndis_vendorID_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct ccg_usb_function *f = dev_get_drvdata(dev); + struct rndis_function_config *config = f->config; + int value; + int ret; + + ret = kstrtou32(buf, 16, &value); + if (ret) + return ret; + + config->vendorID = value; + + return size; +} + +static DEVICE_ATTR(vendorID, S_IRUGO | S_IWUSR, rndis_vendorID_show, + rndis_vendorID_store); + +static struct device_attribute *rndis_function_attributes[] = { + &dev_attr_manufacturer, + &dev_attr_wceis, + &dev_attr_ethaddr, + &dev_attr_vendorID, + NULL +}; + +static struct ccg_usb_function rndis_function = { + .name = "rndis", + .init = rndis_function_init, + .cleanup = rndis_function_cleanup, + .bind_config = rndis_function_bind_config, + .unbind_config = rndis_function_unbind_config, + .attributes = rndis_function_attributes, +}; + +static int mass_storage_function_init(struct ccg_usb_function *f, + struct usb_composite_dev *cdev) +{ + struct fsg_config fsg; + struct fsg_common *common; + int err; + + memset(&fsg, 0, sizeof fsg); + fsg.nluns = 1; + fsg.luns[0].removable = 1; + fsg.vendor_name = iManufacturer; + fsg.product_name = iProduct; + + common = fsg_common_init(NULL, cdev, &fsg); + if (IS_ERR(common)) + return PTR_ERR(common); + + err = sysfs_create_link(&f->dev->kobj, + &common->luns[0].dev.kobj, + "lun"); + if (err) { + fsg_common_put(common); + return err; + } + + f->config = common; + return 0; +} + +static void mass_storage_function_cleanup(struct ccg_usb_function *f) +{ + fsg_common_put(f->config); + f->config = NULL; +} + +static int mass_storage_function_bind_config(struct ccg_usb_function *f, + struct usb_configuration *c) +{ + struct fsg_common *common = f->config; + return fsg_bind_config(c->cdev, c, common); +} + +static struct ccg_usb_function mass_storage_function = { + .name = "mass_storage", + .init = mass_storage_function_init, + .cleanup = mass_storage_function_cleanup, + .bind_config = mass_storage_function_bind_config, +}; + +static struct ccg_usb_function *supported_functions[] = { + &functionfs_function, + &acm_function, + &rndis_function, + &mass_storage_function, + NULL +}; + + +static int ccg_init_functions(struct ccg_usb_function **functions, + struct usb_composite_dev *cdev) +{ + struct ccg_dev *dev = _ccg_dev; + struct ccg_usb_function *f; + struct device_attribute **attrs; + struct device_attribute *attr; + int err; + int index = 0; + + for (; (f = *functions++); index++) { + f->dev_name = kasprintf(GFP_KERNEL, "f_%s", f->name); + if (!f->dev_name) { + pr_err("%s: Failed to alloc name %s", __func__, + f->name); + err = -ENOMEM; + goto err_alloc; + } + f->dev = device_create(ccg_class, dev->dev, + MKDEV(0, index), f, f->dev_name); + if (IS_ERR(f->dev)) { + pr_err("%s: Failed to create dev %s", __func__, + f->dev_name); + err = PTR_ERR(f->dev); + f->dev = NULL; + goto err_create; + } + + if (f->init) { + err = f->init(f, cdev); + if (err) { + pr_err("%s: Failed to init %s", __func__, + f->name); + goto err_out; + } + } + + attrs = f->attributes; + if (attrs) { + while ((attr = *attrs++) && !err) + err = device_create_file(f->dev, attr); + } + if (err) { + pr_err("%s: Failed to create function %s attributes", + __func__, f->name); + goto err_uninit; + } + } + return 0; + +err_uninit: + if (f->cleanup) + f->cleanup(f); +err_out: + device_destroy(ccg_class, f->dev->devt); + f->dev = NULL; +err_create: + kfree(f->dev_name); +err_alloc: + return err; +} + +static void ccg_cleanup_functions(struct ccg_usb_function **functions) +{ + struct ccg_usb_function *f; + + while (*functions) { + f = *functions++; + + if (f->dev) { + if (f->cleanup) + f->cleanup(f); + device_destroy(ccg_class, f->dev->devt); + kfree(f->dev_name); + } + } +} + +static int ccg_bind_enabled_functions(struct ccg_dev *dev, + struct usb_configuration *c) +{ + struct ccg_usb_function *f; + int ret; + + list_for_each_entry(f, &dev->enabled_functions, enabled_list) { + ret = f->bind_config(f, c); + if (ret) { + pr_err("%s: %s failed", __func__, f->name); + return ret; + } + } + return 0; +} + +static void ccg_unbind_enabled_functions(struct ccg_dev *dev, + struct usb_configuration *c) +{ + struct ccg_usb_function *f; + + list_for_each_entry(f, &dev->enabled_functions, enabled_list) + if (f->unbind_config) + f->unbind_config(f, c); +} + +static int ccg_enable_function(struct ccg_dev *dev, char *name) +{ + struct ccg_usb_function **functions = dev->functions; + struct ccg_usb_function *f; + while ((f = *functions++)) { + if (!strcmp(name, f->name)) { + list_add_tail(&f->enabled_list, + &dev->enabled_functions); + return 0; + } + } + return -EINVAL; +} + +/*-------------------------------------------------------------------------*/ +/* /sys/class/ccg_usb/ccg%d/ interface */ + +static ssize_t +functions_show(struct device *pdev, struct device_attribute *attr, char *buf) +{ + struct ccg_dev *dev = dev_get_drvdata(pdev); + struct ccg_usb_function *f; + char *buff = buf; + int i; + + mutex_lock(&dev->mutex); + + list_for_each_entry(f, &dev->enabled_functions, enabled_list) + buff += sprintf(buff, "%s,", f->name); + for (i = 0; i < dev->max_func_num; i++) + if (dev->ffs_tab[i].used) + buff += sprintf(buff, "%s", dev->ffs_tab[i].name); + + mutex_unlock(&dev->mutex); + + if (buff != buf) + *(buff-1) = '\n'; + return buff - buf; +} + +static ssize_t +functions_store(struct device *pdev, struct device_attribute *attr, + const char *buff, size_t size) +{ + struct ccg_dev *dev = dev_get_drvdata(pdev); + char *name; + char buf[256], *b; + int err, i; + bool functionfs_enabled; + + buff = skip_spaces(buff); + if (!*buff) + return -EINVAL; + + mutex_lock(&dev->mutex); + + if (dev->enabled) { + mutex_unlock(&dev->mutex); + return -EBUSY; + } + + INIT_LIST_HEAD(&dev->enabled_functions); + functionfs_enabled = false; + for (i = 0; i < dev->max_func_num; i++) + dev->ffs_tab[i].used = false; + + strlcpy(buf, buff, sizeof(buf)); + b = strim(buf); + + while (b) { + struct ffs_obj *user_func; + + name = strsep(&b, ","); + /* handle FunctionFS implicitly */ + if (!strcmp(name, functionfs_function.name)) { + pr_err("ccg_usb: Cannot explicitly enable '%s'", name); + continue; + } + user_func = functionfs_find_dev(dev, name); + if (user_func) + name = functionfs_function.name; + err = 0; + if (!user_func || !functionfs_enabled) + err = ccg_enable_function(dev, name); + if (err) + pr_err("ccg_usb: Cannot enable '%s'", name); + else if (user_func) { + user_func->used = true; + dev->func_num++; + functionfs_enabled = true; + } + } + + mutex_unlock(&dev->mutex); + + return size; +} + +static ssize_t enable_show(struct device *pdev, struct device_attribute *attr, + char *buf) +{ + struct ccg_dev *dev = dev_get_drvdata(pdev); + return sprintf(buf, "%d\n", dev->enabled); +} + +static ssize_t enable_store(struct device *pdev, struct device_attribute *attr, + const char *buff, size_t size) +{ + struct ccg_dev *dev = dev_get_drvdata(pdev); + struct usb_composite_dev *cdev = dev->cdev; + int enabled = 0; + + mutex_lock(&dev->mutex); + sscanf(buff, "%d", &enabled); + if (enabled && dev->func_num && !functionfs_all_ready(dev)) { + mutex_unlock(&dev->mutex); + return -ENODEV; + } + + if (enabled && !dev->enabled) { + int ret; + + cdev->next_string_id = 0; + /* + * Update values in composite driver's copy of + * device descriptor. + */ + cdev->desc.bDeviceClass = device_desc.bDeviceClass; + cdev->desc.bDeviceSubClass = device_desc.bDeviceSubClass; + cdev->desc.bDeviceProtocol = device_desc.bDeviceProtocol; + cdev->desc.idVendor = idVendor; + cdev->desc.idProduct = idProduct; + cdev->desc.bcdDevice = bcdDevice; + + usb_add_config(cdev, &ccg_config_driver, ccg_bind_config); + dev->enabled = true; + ret = usb_gadget_connect(cdev->gadget); + if (ret) { + dev->enabled = false; + usb_remove_config(cdev, &ccg_config_driver); + } + } else if (!enabled && dev->enabled) { + reset_usb(dev); + } else { + pr_err("ccg_usb: already %s\n", + dev->enabled ? "enabled" : "disabled"); + } + + mutex_unlock(&dev->mutex); + return size; +} + +static ssize_t state_show(struct device *pdev, struct device_attribute *attr, + char *buf) +{ + struct ccg_dev *dev = dev_get_drvdata(pdev); + struct usb_composite_dev *cdev = dev->cdev; + char *state = "DISCONNECTED"; + unsigned long flags; + + if (!cdev) + goto out; + + spin_lock_irqsave(&cdev->lock, flags); + if (cdev->config) + state = "CONFIGURED"; + else if (dev->connected) + state = "CONNECTED"; + spin_unlock_irqrestore(&cdev->lock, flags); +out: + return sprintf(buf, "%s\n", state); +} + +#define DESCRIPTOR_ATTR(field, format_string) \ +static ssize_t \ +field ## _show(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return sprintf(buf, format_string, device_desc.field); \ +} \ +static ssize_t \ +field ## _store(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t size) \ +{ \ + int value; \ + if (sscanf(buf, format_string, &value) == 1) { \ + device_desc.field = value; \ + return size; \ + } \ + return -1; \ +} \ +static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, field ## _show, field ## _store); + +DESCRIPTOR_ATTR(bDeviceClass, "%d\n") +DESCRIPTOR_ATTR(bDeviceSubClass, "%d\n") +DESCRIPTOR_ATTR(bDeviceProtocol, "%d\n") + +static DEVICE_ATTR(functions, S_IRUGO | S_IWUSR, functions_show, + functions_store); +static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store); +static DEVICE_ATTR(state, S_IRUGO, state_show, NULL); + +static struct device_attribute *ccg_usb_attributes[] = { + &dev_attr_bDeviceClass, + &dev_attr_bDeviceSubClass, + &dev_attr_bDeviceProtocol, + &dev_attr_functions, + &dev_attr_enable, + &dev_attr_state, + NULL +}; + +/*-------------------------------------------------------------------------*/ +/* Composite driver */ + +static int ccg_bind_config(struct usb_configuration *c) +{ + struct ccg_dev *dev = _ccg_dev; + int ret = 0; + + ret = ccg_bind_enabled_functions(dev, c); + if (ret) + return ret; + + return 0; +} + +static void ccg_unbind_config(struct usb_configuration *c) +{ + struct ccg_dev *dev = _ccg_dev; + + ccg_unbind_enabled_functions(dev, c); + + usb_ep_autoconfig_reset(dev->cdev->gadget); +} + +static int ccg_bind(struct usb_composite_dev *cdev) +{ + struct ccg_dev *dev = _ccg_dev; + struct usb_gadget *gadget = cdev->gadget; + int gcnum, ret; + + /* + * Start disconnected. Userspace will connect the gadget once + * it is done configuring the functions. + */ + usb_gadget_disconnect(gadget); + + ret = ccg_init_functions(dev->functions, cdev); + if (ret) + return ret; + + gcnum = usb_gadget_controller_number(gadget); + if (gcnum >= 0) + device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum); + else { + pr_warning("%s: controller '%s' not recognized\n", + longname, gadget->name); + device_desc.bcdDevice = __constant_cpu_to_le16(0x9999); + } + + usb_gadget_set_selfpowered(gadget); + dev->cdev = cdev; + + return 0; +} + +static int ccg_usb_unbind(struct usb_composite_dev *cdev) +{ + struct ccg_dev *dev = _ccg_dev; + + cancel_work_sync(&dev->work); + ccg_cleanup_functions(dev->functions); + return 0; +} + +static struct usb_composite_driver ccg_usb_driver = { + .name = "configurable_usb", + .dev = &device_desc, + .unbind = ccg_usb_unbind, + .needs_serial = true, + .iManufacturer = "Linux Foundation", + .iProduct = longname, + .iSerialNumber = "1234567890123456", +}; + +static int ccg_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *c) +{ + struct ccg_dev *dev = _ccg_dev; + struct usb_composite_dev *cdev = get_gadget_data(gadget); + struct usb_request *req = cdev->req; + struct ccg_usb_function *f; + int value = -EOPNOTSUPP; + unsigned long flags; + + req->zero = 0; + req->complete = composite_setup_complete; + req->length = 0; + gadget->ep0->driver_data = cdev; + + list_for_each_entry(f, &dev->enabled_functions, enabled_list) { + if (f->ctrlrequest) { + value = f->ctrlrequest(f, cdev, c); + if (value >= 0) + break; + } + } + + if (value < 0) + value = composite_setup(gadget, c); + + spin_lock_irqsave(&cdev->lock, flags); + if (!dev->connected) { + dev->connected = 1; + schedule_work(&dev->work); + } else if (c->bRequest == USB_REQ_SET_CONFIGURATION && + cdev->config) { + schedule_work(&dev->work); + } + spin_unlock_irqrestore(&cdev->lock, flags); + + return value; +} + +static void ccg_disconnect(struct usb_gadget *gadget) +{ + struct ccg_dev *dev = _ccg_dev; + struct usb_composite_dev *cdev = get_gadget_data(gadget); + unsigned long flags; + + composite_disconnect(gadget); + + spin_lock_irqsave(&cdev->lock, flags); + dev->connected = 0; + schedule_work(&dev->work); + spin_unlock_irqrestore(&cdev->lock, flags); +} + +static int ccg_create_device(struct ccg_dev *dev) +{ + struct device_attribute **attrs = ccg_usb_attributes; + struct device_attribute *attr; + int err; + + dev->dev = device_create(ccg_class, NULL, MKDEV(0, 0), NULL, "ccg0"); + if (IS_ERR(dev->dev)) + return PTR_ERR(dev->dev); + + dev_set_drvdata(dev->dev, dev); + + while ((attr = *attrs++)) { + err = device_create_file(dev->dev, attr); + if (err) { + device_destroy(ccg_class, dev->dev->devt); + return err; + } + } + return 0; +} + + +static int __init init(void) +{ + struct ccg_dev *dev; + int err; + + ccg_class = class_create(THIS_MODULE, "ccg_usb"); + if (IS_ERR(ccg_class)) + return PTR_ERR(ccg_class); + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + dev->functions = supported_functions; + INIT_LIST_HEAD(&dev->enabled_functions); + INIT_WORK(&dev->work, ccg_work); + mutex_init(&dev->mutex); + + err = ccg_create_device(dev); + if (err) { + class_destroy(ccg_class); + kfree(dev); + return err; + } + + _ccg_dev = dev; + + /* Override composite driver functions */ + composite_driver.setup = ccg_setup; + composite_driver.disconnect = ccg_disconnect; + + err = usb_composite_probe(&ccg_usb_driver, ccg_bind); + if (err) { + class_destroy(ccg_class); + kfree(dev); + } + + return err; +} +module_init(init); + +static void __exit cleanup(void) +{ + usb_composite_unregister(&ccg_usb_driver); + class_destroy(ccg_class); + kfree(_ccg_dev); + _ccg_dev = NULL; +} +module_exit(cleanup); diff --git a/trunk/drivers/staging/ccg/sysfs-class-ccg_usb b/trunk/drivers/staging/ccg/sysfs-class-ccg_usb new file mode 100644 index 000000000000..dd12a332fb00 --- /dev/null +++ b/trunk/drivers/staging/ccg/sysfs-class-ccg_usb @@ -0,0 +1,158 @@ +What: /sys/class/ccg_usb +Date: May 2012 +KernelVersion: 3.4 +Contact: linux-usb@vger.kernel.org +Description: + The ccg_usb/ class subdirectory belongs to ccg + USB gadget. + +What: /sys/class/ccg_usb/ccgX +Date: May 2012 +KernelVersion: 3.4 +Contact: linux-usb@vger.kernel.org +Description: + The /sys/class/ccg_usb/ccg{0,1,2,3...} class + subdirectories correspond to each ccg gadget device; + at the time of this writing there is only ccg0 and it + represents the ccg gadget. + +What: /sys/class/ccg_usb/ccgX/functions +Date: May 2012 +KernelVersion: 3.4 +Contact: linux-usb@vger.kernel.org +Description: + A comma-separated list of USB function names to be activated + in this ccg gadget. It includes both the functions provided + in-kernel by the ccg gadget and the functions provided from + userspace through FunctionFS. + +What: /sys/class/ccg_usb/ccgX/enable +Date: May 2012 +KernelVersion: 3.4 +Contact: linux-usb@vger.kernel.org +Description: + A flag activating/deactivating the ccg usb gadget. + +What: /sys/class/ccg_usb/ccgX/state +Date: May 2012 +KernelVersion: 3.4 +Contact: linux-usb@vger.kernel.org +Description: + Configurable usb gadget state: + + DISCONNECTED + CONNECTED + CONFIGURED + +What: /sys/class/ccg_usb/ccgX/f_acm/ +Date: May 2012 +KernelVersion: 3.4 +Contact: linux-usb@vger.kernel.org +Description: + The /sys/class/ccg_usb/ccgX/f_acm subdirectory + corresponds to the gadget's USB CDC serial (ACM) function + driver. + +What: /sys/class/ccg_usb/ccgX/f_acm/instances +Date: May 2012 +KernelVersion: 3.4 +Contact: linux-usb@vger.kernel.org +Description: + Maximum number of the /dev/ttyGS interface the driver uses. + +What: /sys/class/ccg_usb/ccgX/f_fs +Date: May 2012 +KernelVersion: 3.4 +Contact: linux-usb@vger.kernel.org +Description: + The /sys/class/ccg_usb/ccgX/f_fs subdirectory + corresponds to the gadget's FunctionFS driver. + +What: /sys/class/ccg_usb/ccgX/f_fs/user_functions +Date: May 2012 +KernelVersion: 3.4 +Contact: linux-usb@vger.kernel.org +Description: + A comma-separeted list of USB function names to be supported + from userspace. No other userspace FunctionFS functions can + be supported than listed here. However, the actual activation + of these functions is still done through + /sys/class/ccg_usb/ccgX/functions, where it is possible + to specify any subset (including maximum and empty) of + /sys/class/ccg_usb/ccgX/f_fs/user_functions. + +What: /sys/class/ccg_usb/ccgX/f_fs/max_user_functions +Date: May 2012 +KernelVersion: 3.4 +Contact: linux-usb@vger.kernel.org +Description: + Maximum number of USB functions to be supported from userspace. + +What: /sys/class/ccg_usb/ccgX/f_rndis +Date: May 2012 +KernelVersion: 3.4 +Contact: linux-usb@vger.kernel.org +Description: + The /sys/class/ccg_usb/ccgX/f_rndis subdirectory + corresponds to the gadget's RNDIS driver. + +What: /sys/class/ccg_usb/ccgX/f_rndis/manufacturer +Date: May 2012 +KernelVersion: 3.4 +Contact: linux-usb@vger.kernel.org +Description: + RNDIS Ethernet port manufacturer string. + +What: /sys/class/ccg_usb/ccgX/f_rndis/wceis +Date: May 2012 +KernelVersion: 3.4 +Contact: linux-usb@vger.kernel.org +Description: + RNDIS Ethernet port wireless flag. + +What: /sys/class/ccg_usb/ccgX/f_rndis/ethaddr +Date: May 2012 +KernelVersion: 3.4 +Contact: linux-usb@vger.kernel.org +Description: + RNDIS Ethernet port Ethernet address. + +What: /sys/class/ccg_usb/ccgX/f_rndis/vendorID +Date: May 2012 +KernelVersion: 3.4 +Contact: linux-usb@vger.kernel.org +Description: + RNDIS Ethernet port vendor ID. + +What: /sys/class/ccg_usb/ccgX/f_mass_storage +Date: May 2012 +KernelVersion: 3.4 +Contact: linux-usb@vger.kernel.org +Description: + The /sys/class/ccg_usb/ccgX/f_mass_storage subdirectory + corresponds to the gadget's USB mass storage driver. + +What: /sys/class/ccg_usb/ccgX/f_mass_storage/lun +Date: May 2012 +KernelVersion: 3.4 +Contact: linux-usb@vger.kernel.org +Description: + The /sys/class/ccg_usb/ccgX/f_mass_storage/lun + subdirectory corresponds to the gadget's USB mass storage + driver and its underlying storage. + +What: /sys/class/ccg_usb/ccgX/f_mass_storage/lun +Date: May 2012 +KernelVersion: 3.4 +Contact: linux-usb@vger.kernel.org +Description: + The /sys/class/ccg_usb/ccgX/f_mass_storage/lun + subdirectory corresponds to the gadget's USB mass storage + driver and its underlying storage. + +What: /sys/class/ccg_usb/ccgX/f_mass_storage/lun/file +Date: May 2012 +KernelVersion: 3.4 +Contact: linux-usb@vger.kernel.org +Description: + Gadget's USB mass storage underlying file. diff --git a/trunk/drivers/staging/comedi/Kconfig b/trunk/drivers/staging/comedi/Kconfig index 12c691d90900..3bbe3fd103f3 100644 --- a/trunk/drivers/staging/comedi/Kconfig +++ b/trunk/drivers/staging/comedi/Kconfig @@ -1,6 +1,5 @@ config COMEDI tristate "Data acquisition support (comedi)" - default N depends on m depends on BROKEN || FRV || M32R || MN10300 || SUPERH || TILE || X86 ---help--- @@ -14,10 +13,29 @@ config COMEDI_DEBUG This is an option for use by developers; most people should say N here. This enables comedi core and driver debugging. +config COMEDI_DEFAULT_BUF_SIZE_KB + int "Comedi default initial asynchronous buffer size in KiB" + default "2048" + depends on COMEDI != n + ---help--- + This is the default asynchronous buffer size which is used for + commands running in the background in kernel space. This + defaults to 2048 KiB of memory so that a 16 channel card + running at 10 kHz has of 2-4 seconds of buffer. + +config COMEDI_DEFAULT_BUF_MAXSIZE_KB + int "Comedi default maximum asynchronous buffer size in KiB" + default "20480" + depends on COMEDI != n + ---help--- + This is the default maximum asynchronous buffer size which can + be requested by a userspace program without root privileges. + This is set to 20480 KiB so that a fast I/O card with 16 + channels running at 100 kHz has 2-4 seconds of buffer. + menuconfig COMEDI_MISC_DRIVERS tristate "Comedi misc drivers" depends on COMEDI - default N ---help--- Enable comedi misc drivers to be built @@ -35,7 +53,6 @@ config COMEDI_KCOMEDILIB config COMEDI_BOND tristate "Device bonding support" depends on COMEDI_KCOMEDILIB - default N ---help--- Enable support for a driver to 'bond' (merge) multiple subdevices from multiple devices together as one. @@ -46,7 +63,6 @@ config COMEDI_BOND config COMEDI_TEST tristate "Fake waveform generator support" select COMEDI_FC - default N ---help--- Enable support for the fake waveform generator. This driver is mainly for testing purposes, but can also be used to @@ -58,7 +74,6 @@ config COMEDI_TEST config COMEDI_PARPORT tristate "Parallel port support" - default N ---help--- Enable support for the standard parallel port. A cheap and easy way to get a few more digital I/O lines. Steal @@ -70,7 +85,6 @@ config COMEDI_PARPORT config COMEDI_SERIAL2002 tristate "Driver for serial connected hardware" - default N ---help--- Enable support for serial connected hardware @@ -79,7 +93,6 @@ config COMEDI_SERIAL2002 config COMEDI_SKEL tristate "Comedi skeleton driver" - default N ---help--- Build the Skeleton driver, an example for driver writers @@ -91,7 +104,6 @@ endif # COMEDI_MISC_DRIVERS menuconfig COMEDI_ISA_DRIVERS tristate "Comedi ISA and PC/104 drivers" depends on COMEDI && ISA - default N ---help--- Enable comedi ISA and PC/104 drivers to be built @@ -103,7 +115,6 @@ if COMEDI_ISA_DRIVERS && ISA config COMEDI_ACL7225B tristate "ADlink NuDAQ ACL-7225b and compatibles support" - default N ---help--- Enable support for ADlink NuDAQ ACL-7225b and compatibles, ADlink ACL-7225b (acl7225b), ICP P16R16DIO (p16r16dio) @@ -113,7 +124,6 @@ config COMEDI_ACL7225B config COMEDI_PCL711 tristate "Advantech PCL-711/711b and ADlink ACL-8112 ISA card support" - default N ---help--- Enable support for Advantech PCL-711 and 711b, ADlink ACL-8112 @@ -123,7 +133,6 @@ config COMEDI_PCL711 config COMEDI_PCL724 tristate "Advantech PCL-722/724/731 and ADlink ACL-7122/7124/PET-48DIO" select COMEDI_8255 - default N ---help--- Enable support for Advantech PCL-724, PCL-722, PCL-731 and ADlink ACL-7122, ACL-7124, PET-48DIO ISA cards @@ -133,7 +142,6 @@ config COMEDI_PCL724 config COMEDI_PCL725 tristate "Advantech PCL-725 and compatible ISA card support" - default N ---help--- Enable support for Advantech PCL-725 and compatible ISA cards. @@ -142,7 +150,6 @@ config COMEDI_PCL725 config COMEDI_PCL726 tristate "Advantech PCL-726 and compatible ISA card support" - default N ---help--- Enable support for Advantech PCL-726 and compatible ISA cards. @@ -151,7 +158,6 @@ config COMEDI_PCL726 config COMEDI_PCL730 tristate "Advantech PCL-730 and ADlink ACL-7130 ISA card support" - default N ---help--- Enable support for Advantech PCL-730, ICP ISO-730 and ADlink ACL-7130 ISA cards @@ -162,7 +168,6 @@ config COMEDI_PCL730 config COMEDI_PCL812 tristate "Advantech PCL-812/813 and ADlink ACL-8112/8113/8113/8216" depends on VIRT_TO_BUS - default N ---help--- Enable support for Advantech PCL-812/PG, PCL-813/B, ADLink ACL-8112DG/HG/PG, ACL-8113, ACL-8216, ICP DAS A-821PGH/PGL/PGL-NDA, @@ -174,7 +179,6 @@ config COMEDI_PCL812 config COMEDI_PCL816 tristate "Advantech PCL-814 and PCL-816 ISA card support" depends on VIRT_TO_BUS - default N ---help--- Enable support for Advantech PCL-814 and PCL-816 ISA cards @@ -184,7 +188,6 @@ config COMEDI_PCL816 config COMEDI_PCL818 tristate "Advantech PCL-718 and PCL-818 ISA card support" depends on VIRT_TO_BUS - default N ---help--- Enable support for Advantech PCL-818 ISA cards PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818 and PCL-718 @@ -195,7 +198,6 @@ config COMEDI_PCL818 config COMEDI_PCM3724 tristate "Advantech PCM-3724 PC/104 card support" select COMEDI_8255 - default N ---help--- Enable support for Advantech PCM-3724 PC/104 cards. @@ -204,16 +206,43 @@ config COMEDI_PCM3724 config COMEDI_PCM3730 tristate "Advantech PCM-3730 and clone PC/104 board support" - default N ---help--- Enable support for Advantech PCM-3730 and clone PC/104 boards To compile this driver as a module, choose M here: the module will be called pcm3730. +config COMEDI_AMPLC_DIO200_ISA + tristate "Amplicon PC212E/PC214E/PC215E/PC218E/PC272E" + select COMEDI_AMPLC_DIO200 + depends on COMEDI_ISA_DRIVERS + ---help--- + Enable support for Amplicon PC212E, PC214E, PC215E, PC218E and + PC272E ISA DIO boards + + To compile this driver as a module, choose M here: the module will be + called amplc_dio200. + +config COMEDI_AMPLC_PC236_ISA + tristate "Amplicon PC36AT DIO board support" + select COMEDI_AMPLC_PC236 + ---help--- + Enable support for Amplicon PC36AT ISA DIO board. + + To compile this driver as a module, choose M here: the module will be + called amplc_pc236. + +config COMEDI_AMPLC_PC263_ISA + tristate "Amplicon PC263 relay board support" + select COMEDI_AMPLC_PC263 + ---help--- + Enable support for Amplicon PC263 ISA relay board. + + To compile this driver as a module, choose M here: the module will be + called amplc_pc263. + config COMEDI_RTI800 tristate "Analog Devices RTI-800/815 ISA card support" - default N ---help--- Enable support for Analog Devices RTI-800/815 ISA cards @@ -222,7 +251,6 @@ config COMEDI_RTI800 config COMEDI_RTI802 tristate "Analog Devices RTI-802 ISA card support" - default N ---help--- Enable support for Analog Devices RTI-802 ISA cards @@ -233,18 +261,29 @@ config COMEDI_DAS16M1 tristate "MeasurementComputing CIO-DAS16/M1DAS-16 ISA card support" select COMEDI_8255 select COMEDI_FC - default N ---help--- Enable support for Measurement Computing CIO-DAS16/M1 ISA cards. To compile this driver as a module, choose M here: the module will be called das16m1. +config COMEDI_DAS08_ISA + tristate "DAS-08 compatible ISA and PC/104 card support" + select COMEDI_DAS08 + ---help--- + Enable support for Keithley Metrabyte/ComputerBoards DAS08 + and compatible ISA and PC/104 cards: + Keithley Metrabyte/ComputerBoards DAS08, DAS08-PGM, DAS08-PGH, + DAS08-PGL, DAS08-AOH, DAS08-AOL, DAS08-AOM, DAS08/JR-AO, + DAS08/JR-16-AO, PC104-DAS08, DAS08/JR/16. + + To compile this driver as a module, choose M here: the module will be + called das08. + config COMEDI_DAS16 tristate "DAS-16 compatible ISA and PC/104 card support" select COMEDI_8255 select COMEDI_FC - default N ---help--- Enable support for Keithley Metrabyte/ComputerBoards DAS16 and compatible ISA and PC/104 cards: @@ -261,7 +300,6 @@ config COMEDI_DAS16 config COMEDI_DAS800 tristate "DAS800 and compatible ISA card support" select COMEDI_FC - default N ---help--- Enable support for Keithley Metrabyte DAS800 and compatible ISA cards Keithley Metrabyte DAS-800, DAS-801, DAS-802 @@ -275,7 +313,6 @@ config COMEDI_DAS1800 tristate "DAS1800 and compatible ISA card support" depends on VIRT_TO_BUS select COMEDI_FC - default N ---help--- Enable support for DAS1800 and compatible ISA cards Keithley Metrabyte DAS-1701ST, DAS-1701ST-DA, DAS-1701/AO, @@ -289,7 +326,6 @@ config COMEDI_DAS1800 config COMEDI_DAS6402 tristate "DAS6402 and compatible ISA card support" - default N ---help--- Enable support for DAS6402 and compatible ISA cards Computerboards, Keithley Metrabyte DAS6402 and compatibles @@ -299,7 +335,6 @@ config COMEDI_DAS6402 config COMEDI_DT2801 tristate "Data Translation DT2801 ISA card support" - default N ---help--- Enable support for Data Translation DT2801 ISA cards @@ -308,7 +343,6 @@ config COMEDI_DT2801 config COMEDI_DT2811 tristate "Data Translation DT2811 ISA card support" - default N ---help--- Enable support for Data Translation DT2811 ISA cards @@ -317,7 +351,6 @@ config COMEDI_DT2811 config COMEDI_DT2814 tristate "Data Translation DT2814 ISA card support" - default N ---help--- Enable support for Data Translation DT2814 ISA cards @@ -326,7 +359,6 @@ config COMEDI_DT2814 config COMEDI_DT2815 tristate "Data Translation DT2815 ISA card support" - default N ---help--- Enable support for Data Translation DT2815 ISA cards @@ -335,7 +367,6 @@ config COMEDI_DT2815 config COMEDI_DT2817 tristate "Data Translation DT2817 ISA card support" - default N ---help--- Enable support for Data Translation DT2817 ISA cards @@ -346,7 +377,6 @@ config COMEDI_DT282X tristate "Data Translation DT2821 series and DT-EZ ISA card support" select COMEDI_FC depends on VIRT_TO_BUS - default N ---help--- Enable support for Data Translation DT2821 series including DT-EZ DT2821, DT2821-F-16SE, DT2821-F-8DI, DT2821-G-16SE, DT2821-G-8DI, @@ -358,7 +388,6 @@ config COMEDI_DT282X config COMEDI_DMM32AT tristate "Diamond Systems MM-32-AT PC/104 board support" - default N ---help--- Enable support for Diamond Systems MM-32-AT PC/104 boards @@ -367,7 +396,6 @@ config COMEDI_DMM32AT config COMEDI_FL512 tristate "FL512 ISA card support" - default N ---help--- Enable support for FL512 ISA card @@ -377,7 +405,6 @@ config COMEDI_FL512 config COMEDI_AIO_AIO12_8 tristate "I/O Products PC/104 AIO12-8 Analog I/O Board support" select COMEDI_8255 - default N ---help--- Enable support for I/O Products PC/104 AIO12-8 Analog I/O Board @@ -386,7 +413,6 @@ config COMEDI_AIO_AIO12_8 config COMEDI_AIO_IIRO_16 tristate "I/O Products PC/104 IIRO16 Board support" - default N ---help--- Enable support for I/O Products PC/104 IIRO16 Relay And Isolated Input Board @@ -396,7 +422,6 @@ config COMEDI_AIO_IIRO_16 config COMEDI_C6XDIGIO tristate "Mechatronic Systems Inc. C6x_DIGIO DSP daughter card support" - default N ---help--- Enable support for Mechatronic Systems Inc. C6x_DIGIO DSP daughter card @@ -406,7 +431,6 @@ config COMEDI_C6XDIGIO config COMEDI_MPC624 tristate "Micro/sys MPC-624 PC/104 board support" - default N ---help--- Enable support for Micro/sys MPC-624 PC/104 board @@ -415,7 +439,6 @@ config COMEDI_MPC624 config COMEDI_ADQ12B tristate "MicroAxial ADQ12-B data acquisition and control card support" - default N ---help--- Enable MicroAxial ADQ12-B daq and control card support. @@ -426,7 +449,6 @@ config COMEDI_NI_AT_A2150 tristate "NI AT-A2150 ISA card support" depends on COMEDI_NI_COMMON depends on VIRT_TO_BUS - default N ---help--- Enable support for National Instruments AT-A2150 cards @@ -436,7 +458,6 @@ config COMEDI_NI_AT_A2150 config COMEDI_NI_AT_AO tristate "NI AT-AO-6/10 EISA card support" depends on COMEDI_NI_COMMON - default N ---help--- Enable support for National Instruments AT-AO-6/10 cards @@ -447,7 +468,6 @@ config COMEDI_NI_ATMIO tristate "NI AT-MIO E series ISA-PNP card support" depends on ISAPNP && COMEDI_NI_TIO && COMEDI_NI_COMMON select COMEDI_8255 - default N ---help--- Enable support for National Instruments AT-MIO E series cards National Instruments AT-MIO-16E-1 (ni_atmio), @@ -461,7 +481,6 @@ config COMEDI_NI_ATMIO16D tristate "NI AT-MIO16/AT-MIO16D series ISA-PNP card support" depends on ISAPNP && COMEDI_NI_COMMON select COMEDI_8255 - default N ---help--- Enable support for National Instruments AT-MIO16/AT-MIO16D cards. @@ -470,7 +489,6 @@ config COMEDI_NI_ATMIO16D config COMEDI_PCMAD tristate "Winsystems PCM-A/D12 and PCM-A/D16 PC/104 board support" - default N ---help--- Enable support for Winsystems PCM-A/D12 and PCM-A/D16 PC/104 boards. @@ -479,7 +497,6 @@ config COMEDI_PCMAD config COMEDI_PCMDA12 tristate "Winsystems PCM-D/A-12 8-channel AO PC/104 board support" - default N ---help--- Enable support for Winsystems PCM-D/A-12 8-channel AO PC/104 boards. Note that the board is not ISA-PNP capable and thus needs the I/O @@ -490,7 +507,6 @@ config COMEDI_PCMDA12 config COMEDI_PCMMIO tristate "Winsystems PCM-MIO PC/104 board support" - default N ---help--- Enable support for Winsystems PCM-MIO multifunction PC/104 boards. @@ -499,7 +515,6 @@ config COMEDI_PCMMIO config COMEDI_PCMUIO tristate "Winsystems PCM-UIO48A and PCM-UIO96A PC/104 board support" - default N ---help--- Enable support for PCM-UIO48A and PCM-UIO96A PC/104 boards. @@ -508,7 +523,6 @@ config COMEDI_PCMUIO config COMEDI_MULTIQ3 tristate "Quanser Consulting MultiQ-3 ISA card support" - default N ---help--- Enable support for Quanser Consulting MultiQ-3 ISA cards @@ -517,7 +531,6 @@ config COMEDI_MULTIQ3 config COMEDI_POC tristate "Generic driver for very simple devices" - default N ---help--- Enable generic support for very simple / POC (Piece of Crap) boards, Keithley Metrabyte DAC-02 (dac02), Advantech PCL-733 (pcl733) and @@ -531,7 +544,6 @@ endif # COMEDI_ISA_DRIVERS menuconfig COMEDI_PCI_DRIVERS tristate "Comedi PCI drivers" depends on COMEDI && PCI - default N ---help--- Enable comedi PCI drivers to be built @@ -544,7 +556,6 @@ if COMEDI_PCI_DRIVERS && PCI config COMEDI_ADDI_APCI_035 tristate "ADDI-DATA APCI_035 support" depends on VIRT_TO_BUS - default N ---help--- Enable support for ADDI-DATA APCI_035 cards @@ -554,7 +565,6 @@ config COMEDI_ADDI_APCI_035 config COMEDI_ADDI_APCI_1032 tristate "ADDI-DATA APCI_1032 support" depends on VIRT_TO_BUS - default N ---help--- Enable support for ADDI-DATA APCI_1032 cards @@ -564,7 +574,6 @@ config COMEDI_ADDI_APCI_1032 config COMEDI_ADDI_APCI_1500 tristate "ADDI-DATA APCI_1500 support" depends on VIRT_TO_BUS - default N ---help--- Enable support for ADDI-DATA APCI_1500 cards @@ -574,7 +583,6 @@ config COMEDI_ADDI_APCI_1500 config COMEDI_ADDI_APCI_1516 tristate "ADDI-DATA APCI_1516 support" depends on VIRT_TO_BUS - default N ---help--- Enable support for ADDI-DATA APCI_1516 cards @@ -584,7 +592,6 @@ config COMEDI_ADDI_APCI_1516 config COMEDI_ADDI_APCI_1564 tristate "ADDI-DATA APCI_1564 support" depends on VIRT_TO_BUS - default N ---help--- Enable support for ADDI-DATA APCI_1564 cards @@ -594,7 +601,6 @@ config COMEDI_ADDI_APCI_1564 config COMEDI_ADDI_APCI_16XX tristate "ADDI-DATA APCI_16xx support" depends on VIRT_TO_BUS - default N ---help--- Enable support for ADDI-DATA APCI_16xx cards @@ -604,7 +610,6 @@ config COMEDI_ADDI_APCI_16XX config COMEDI_ADDI_APCI_2016 tristate "ADDI-DATA APCI_2016 support" depends on VIRT_TO_BUS - default N ---help--- Enable support for ADDI-DATA APCI_2016 cards @@ -614,7 +619,6 @@ config COMEDI_ADDI_APCI_2016 config COMEDI_ADDI_APCI_2032 tristate "ADDI-DATA APCI_2032 support" depends on VIRT_TO_BUS - default N ---help--- Enable support for ADDI-DATA APCI_2032 cards @@ -624,7 +628,6 @@ config COMEDI_ADDI_APCI_2032 config COMEDI_ADDI_APCI_2200 tristate "ADDI-DATA APCI_2200 support" depends on VIRT_TO_BUS - default N ---help--- Enable support for ADDI-DATA APCI_2200 cards @@ -635,7 +638,6 @@ config COMEDI_ADDI_APCI_3001 tristate "ADDI-DATA APCI_3001 support" depends on VIRT_TO_BUS select COMEDI_FC - default N ---help--- Enable support for ADDI-DATA APCI_3001 cards @@ -646,7 +648,6 @@ config COMEDI_ADDI_APCI_3120 tristate "ADDI-DATA APCI_3520 support" depends on VIRT_TO_BUS select COMEDI_FC - default N ---help--- Enable support for ADDI-DATA APCI_3520 cards @@ -656,7 +657,6 @@ config COMEDI_ADDI_APCI_3120 config COMEDI_ADDI_APCI_3501 tristate "ADDI-DATA APCI_3501 support" depends on VIRT_TO_BUS - default N ---help--- Enable support for ADDI-DATA APCI_3501 cards @@ -666,7 +666,6 @@ config COMEDI_ADDI_APCI_3501 config COMEDI_ADDI_APCI_3XXX tristate "ADDI-DATA APCI_3xxx support" depends on VIRT_TO_BUS - default N ---help--- Enable support for ADDI-DATA APCI_3xxx cards @@ -676,7 +675,6 @@ config COMEDI_ADDI_APCI_3XXX config COMEDI_ADL_PCI6208 tristate "ADLink PCI-6208A support" select COMEDI_8255 - default N ---help--- Enable support for ADLink PCI-6208A cards @@ -685,7 +683,6 @@ config COMEDI_ADL_PCI6208 config COMEDI_ADL_PCI7230 tristate "ADLink PCI-7230 digital io board support" - default N ---help--- Enable support for ADlink PCI-7230 digital io board support @@ -694,7 +691,6 @@ config COMEDI_ADL_PCI7230 config COMEDI_ADL_PCI7296 tristate "ADLink PCI-7296 96 ch. digital io board support" - default N ---help--- Enable support for ADlink PCI-7296 96 ch. digital io board support @@ -703,7 +699,6 @@ config COMEDI_ADL_PCI7296 config COMEDI_ADL_PCI7432 tristate "ADLink PCI-7432 64 ch. isolated digital io board support" - default N ---help--- Enable support for ADlink PCI-7432 64 ch. isolated digital io board @@ -712,7 +707,6 @@ config COMEDI_ADL_PCI7432 config COMEDI_ADL_PCI8164 tristate "ADLink PCI-8164 4 Axes Motion Control board support" - default N ---help--- Enable support for ADlink PCI-8164 4 Axes Motion Control board @@ -722,7 +716,6 @@ config COMEDI_ADL_PCI8164 config COMEDI_ADL_PCI9111 tristate "ADLink PCI-9111HR support" select COMEDI_FC - default N ---help--- Enable support for ADlink PCI9111 cards @@ -733,7 +726,6 @@ config COMEDI_ADL_PCI9118 tristate "ADLink PCI-9118DG, PCI-9118HG, PCI-9118HR support" select COMEDI_FC depends on VIRT_TO_BUS - default N ---help--- Enable support for ADlink PCI-9118DG, PCI-9118HG, PCI-9118HR cards @@ -742,7 +734,6 @@ config COMEDI_ADL_PCI9118 config COMEDI_ADV_PCI1710 tristate "Advantech PCI-171x, PCI-1720 and PCI-1731 support" - default N ---help--- Enable support for Advantech PCI-1710, PCI-1710HG, PCI-1711, PCI-1713, PCI-1720 and PCI-1731 @@ -752,7 +743,6 @@ config COMEDI_ADV_PCI1710 config COMEDI_ADV_PCI1723 tristate "Advantech PCI-1723 support" - default N ---help--- Enable support for Advantech PCI-1723 cards @@ -762,7 +752,6 @@ config COMEDI_ADV_PCI1723 config COMEDI_ADV_PCI_DIO tristate "Advantech PCI DIO card support" select COMEDI_8255 - default N ---help--- Enable support for Advantech PCI DIO cards PCI-1730, PCI-1733, PCI-1734, PCI-1735U, PCI-1736UP, PCI-1739U, @@ -772,31 +761,29 @@ config COMEDI_ADV_PCI_DIO To compile this driver as a module, choose M here: the module will be called adv_pci_dio. -config COMEDI_AMPLC_DIO200 - tristate "Amplicon PC272E and PCI272 DIO board support" - select COMEDI_8255 - default N +config COMEDI_AMPLC_DIO200_PCI + tristate "Amplicon PCI215 and PCI272 DIO board support" + select COMEDI_AMPLC_DIO200 ---help--- - Enable support for Amplicon PC272E and PCI272 DIO boards + Enable support for Amplicon PCI215 and PCI272 DIO boards. To compile this driver as a module, choose M here: the module will be called amplc_dio200. -config COMEDI_AMPLC_PC236 - tristate "Amplicon PC36AT and PCI236 DIO board support" - select COMEDI_8255 - default N +config COMEDI_AMPLC_PC236_PCI + tristate "Amplicon PCI236 DIO board support" + select COMEDI_AMPLC_PC236 ---help--- - Enable support for Amplicon PC36AT and PCI236 DIO boards + Enable support for Amplicon PCI236 DIO board. To compile this driver as a module, choose M here: the module will be called amplc_pc236. -config COMEDI_AMPLC_PC263 - tristate "Amplicon PC263 and PCI263 relay board support" - default N +config COMEDI_AMPLC_PC263_PCI + tristate "Amplicon PCI263 relay board support" + select COMEDI_AMPLC_PC263 ---help--- - Enable support for Amplicon PC263 and PCI263 relay boards + Enable support for Amplicon PCI263 relay board. To compile this driver as a module, choose M here: the module will be called amplc_pc263. @@ -804,7 +791,6 @@ config COMEDI_AMPLC_PC263 config COMEDI_AMPLC_PCI224 tristate "Amplicon PCI224 and PCI234 support" select COMEDI_FC - default N ---help--- Enable support for Amplicon PCI224 and PCI234 AO boards @@ -814,7 +800,6 @@ config COMEDI_AMPLC_PCI224 config COMEDI_AMPLC_PCI230 tristate "Amplicon PCI230 and PCI260 support" select COMEDI_8255 - default N ---help--- Enable support for Amplicon PCI230 and PCI260 Multifunction I/O boards @@ -824,16 +809,23 @@ config COMEDI_AMPLC_PCI230 config COMEDI_CONTEC_PCI_DIO tristate "Contec PIO1616L digital I/O board support" - default N ---help--- Enable support for the Contec PIO1616L digital I/O board To compile this driver as a module, choose M here: the module will be called contec_pci_dio. +config COMEDI_DAS08_PCI + tristate "DAS-08 PCI support" + select COMEDI_DAS08 + ---help--- + Enable support for PCI DAS-08 cards. + + To compile this driver as a module, choose M here: the module will be + called das08. + config COMEDI_DT3000 tristate "Data Translation DT3000 series support" - default N ---help--- Enable support for Data Translation DT3000 series DT3001, DT3001-PGL, DT3002, DT3003, DT3003-PGL, DT3004, DT3005 and @@ -844,7 +836,6 @@ config COMEDI_DT3000 config COMEDI_DYNA_PCI10XX tristate "Dynalog PCI DAQ series support" - default N ---help--- Enable support for Dynalog PCI DAQ series PCI-1050 @@ -854,7 +845,6 @@ config COMEDI_DYNA_PCI10XX config COMEDI_UNIOXX5 tristate "Fastwel UNIOxx-5 analog and digital io board support" - default N ---help--- Enable support for Fastwel UNIOxx-5 (analog and digital i/o) boards @@ -864,7 +854,6 @@ config COMEDI_UNIOXX5 config COMEDI_GSC_HPDI tristate "General Standards PCI-HPDI32 / PMC-HPDI32 support" select COMEDI_FC - default N ---help--- Enable support for General Standards Corporation high speed parallel digital interface rs485 boards PCI-HPDI32 and PMC-HPDI32. @@ -875,7 +864,6 @@ config COMEDI_GSC_HPDI config COMEDI_ICP_MULTI tristate "Inova ICP_MULTI support" - default N ---help--- Enable support for Inova ICP_MULTI card @@ -884,7 +872,6 @@ config COMEDI_ICP_MULTI config COMEDI_II_PCI20KC tristate "Intelligent Instruments PCI-20001C carrier support" - default N ---help--- Enable support for Intelligent Instruments PCI-20001C carrier PCI-20001, PCI-20006 and PCI-20341 @@ -895,7 +882,6 @@ config COMEDI_II_PCI20KC config COMEDI_DAQBOARD2000 tristate "IOtech DAQboard/2000 support" select COMEDI_8255 - default N ---help--- Enable support for the IOtech DAQboard/2000 @@ -904,7 +890,6 @@ config COMEDI_DAQBOARD2000 config COMEDI_JR3_PCI tristate "JR3/PCI force sensor board support" - default N ---help--- Enable support for JR3/PCI force sensor boards @@ -913,7 +898,6 @@ config COMEDI_JR3_PCI config COMEDI_KE_COUNTER tristate "Kolter-Electronic PCI Counter 1 card support" - default N ---help--- Enable support for Kolter-Electronic PCI Counter 1 cards @@ -924,7 +908,6 @@ config COMEDI_CB_PCIDAS64 tristate "MeasurementComputing PCI-DAS 64xx, 60xx, and 4020 support" select COMEDI_8255 select COMEDI_FC - default N ---help--- Enable support for ComputerBoards/MeasurementComputing PCI-DAS 64xx, 60xx, and 4020 series with the PLX 9080 PCI controller @@ -936,7 +919,6 @@ config COMEDI_CB_PCIDAS tristate "MeasurementComputing PCI-DAS support" select COMEDI_8255 select COMEDI_FC - default N ---help--- Enable support for ComputerBoards/MeasurementComputing PCI-DAS with AMCC S5933 PCIcontroller: PCI-DAS1602/16, PCI-DAS1602/16jr, @@ -949,7 +931,6 @@ config COMEDI_CB_PCIDAS config COMEDI_CB_PCIDDA tristate "MeasurementComputing PCI-DDA series support" select COMEDI_8255 - default N ---help--- Enable support for ComputerBoards/MeasurementComputing PCI-DDA series: PCI-DDA08/12, PCI-DDA04/12, PCI-DDA02/12, PCI-DDA08/16, @@ -961,7 +942,6 @@ config COMEDI_CB_PCIDDA config COMEDI_CB_PCIDIO tristate "MeasurementComputing PCI-DIO series support" select COMEDI_8255 - default N ---help--- Enable support for ComputerBoards/MeasurementComputing PCI-DIO series PCI-DIO24, PCI-DIO24H and PCI-DIO48H @@ -972,7 +952,6 @@ config COMEDI_CB_PCIDIO config COMEDI_CB_PCIMDAS tristate "MeasurementComputing PCIM-DAS1602/16 support" select COMEDI_8255 - default N ---help--- Enable support for ComputerBoards/MeasurementComputing PCI Migration series PCIM-DAS1602/16 @@ -983,7 +962,6 @@ config COMEDI_CB_PCIMDAS config COMEDI_CB_PCIMDDA tristate "MeasurementComputing PCIM-DDA06-16 support" select COMEDI_8255 - default N ---help--- Enable support for ComputerBoards/MeasurementComputing PCIM-DDA06-16 @@ -992,7 +970,6 @@ config COMEDI_CB_PCIMDDA config COMEDI_ME4000 tristate "Meilhaus ME-4000 support" - default N ---help--- Enable support for Meilhaus PCI data acquisition cards ME-4650, ME-4670i, ME-4680, ME-4680i and ME-4680is @@ -1002,7 +979,6 @@ config COMEDI_ME4000 config COMEDI_ME_DAQ tristate "Meilhaus ME-2000i, ME-2600i, ME-3000vm1 support" - default N ---help--- Enable support for Meilhaus PCI data acquisition cards ME-2000i, ME-2600i and ME-3000vm1 @@ -1013,7 +989,6 @@ config COMEDI_ME_DAQ config COMEDI_NI_6527 tristate "NI 6527 support" depends on COMEDI_MITE - default N ---help--- Enable support for the National Instruments 6527 PCI card @@ -1023,7 +998,6 @@ config COMEDI_NI_6527 config COMEDI_NI_65XX tristate "NI 65xx static dio PCI card support" depends on COMEDI_MITE - default N ---help--- Enable support for National Instruments 65xx static dio boards. Supported devices: National Instruments PCI-6509 (ni_65xx), @@ -1037,7 +1011,6 @@ config COMEDI_NI_65XX config COMEDI_NI_660X tristate "NI 660x counter/timer PCI card support" depends on COMEDI_NI_TIO && COMEDI_NI_COMMON - default N ---help--- Enable support for National Instruments PCI-6601 (ni_660x), PCI-6602, PXI-6602 and PXI-6608. @@ -1048,7 +1021,6 @@ config COMEDI_NI_660X config COMEDI_NI_670X tristate "NI 670x PCI card support" depends on COMEDI_MITE - default N ---help--- Enable support for National Instruments PCI-6703 and PCI-6704 @@ -1059,7 +1031,6 @@ config COMEDI_NI_PCIDIO tristate "NI PCI-DIO32HS, PCI-DIO96, PCI-6533, PCI-6503 support" depends on COMEDI_MITE select COMEDI_8255 - default N ---help--- Enable support for National Instruments PCI-DIO-32HS, PXI-6533, PCI-DIO-96, PCI-DIO-96B, PXI-6508, PCI-6503, PCI-6503B, PCI-6503X, @@ -1075,7 +1046,6 @@ config COMEDI_NI_PCIMIO depends on COMEDI_NI_TIO && COMEDI_NI_COMMON select COMEDI_8255 select COMEDI_FC - default N ---help--- Enable support for National Instruments PCI-MIO-E series and M series (all boards): PCI-MIO-16XE-10, PXI-6030E, PCI-MIO-16E-1, @@ -1094,7 +1064,6 @@ config COMEDI_NI_PCIMIO config COMEDI_RTD520 tristate "Real Time Devices PCI4520/DM7520 support" select COMEDI_8255 - default N ---help--- Enable support for Real Time Devices PCI4520/DM7520 @@ -1103,7 +1072,6 @@ config COMEDI_RTD520 config COMEDI_S526 tristate "Sensoray s526 support" - default N ---help--- Enable support for Sensoray s526 @@ -1113,7 +1081,6 @@ config COMEDI_S526 config COMEDI_S626 tristate "Sensoray 626 support" select COMEDI_FC - default N ---help--- Enable support for Sensoray 626 @@ -1122,7 +1089,6 @@ config COMEDI_S626 config COMEDI_SSV_DNP tristate "SSV Embedded Systems DIL/Net-PC support" - default N ---help--- Enable support for SSV Embedded Systems DIL/Net-PC @@ -1134,7 +1100,6 @@ endif # COMEDI_PCI_DRIVERS menuconfig COMEDI_PCMCIA_DRIVERS tristate "Comedi PCMCIA drivers" depends on COMEDI && (PCMCIA || PCCARD) - default N ---help--- Enable comedi PCMCIA and PCCARD drivers to be built @@ -1146,7 +1111,6 @@ if COMEDI_PCMCIA_DRIVERS && PCMCIA config COMEDI_CB_DAS16_CS tristate "CB DAS16 series PCMCIA support" - default N ---help--- Enable support for the ComputerBoards/MeasurementComputing PCMCIA cards DAS16/16, PCM-DAS16D/12 and PCM-DAS16s/16 @@ -1157,7 +1121,6 @@ config COMEDI_CB_DAS16_CS config COMEDI_DAS08_CS tristate "CB DAS08 PCMCIA support" select COMEDI_DAS08 - default N ---help--- Enable support for the ComputerBoards/MeasurementComputing DAS-08 PCMCIA card @@ -1168,7 +1131,6 @@ config COMEDI_DAS08_CS config COMEDI_NI_DAQ_700_CS tristate "NI DAQCard-700 PCMCIA support" depends on COMEDI_NI_COMMON - default N ---help--- Enable support for the National Instruments PCMCIA DAQCard-700 DIO @@ -1179,7 +1141,6 @@ config COMEDI_NI_DAQ_DIO24_CS tristate "NI DAQ-Card DIO-24 PCMCIA support" depends on COMEDI_NI_COMMON select COMEDI_8255 - default N ---help--- Enable support for the National Instruments PCMCIA DAQ-Card DIO-24 @@ -1189,7 +1150,6 @@ config COMEDI_NI_DAQ_DIO24_CS config COMEDI_NI_LABPC_CS tristate "NI DAQCard-1200 PCMCIA support" depends on COMEDI_NI_LABPC - default N ---help--- Enable support for the National Instruments PCMCIA DAQCard-1200 @@ -1201,7 +1161,6 @@ config COMEDI_NI_MIO_CS depends on COMEDI_NI_TIO && COMEDI_NI_COMMON select COMEDI_8255 select COMEDI_FC - default N ---help--- Enable support for the National Instruments PCMCIA DAQCard E series DAQCard-ai-16xe-50, DAQCard-ai-16e-4, DAQCard-6062E, DAQCard-6024E @@ -1212,7 +1171,6 @@ config COMEDI_NI_MIO_CS config COMEDI_QUATECH_DAQP_CS tristate "Quatech DAQP PCMCIA data capture card support" - default N ---help--- Enable support for the Quatech DAQP PCMCIA data capture cards DAQP-208 and DAQP-308 @@ -1225,7 +1183,6 @@ endif # COMEDI_PCMCIA_DRIVERS menuconfig COMEDI_USB_DRIVERS tristate "Comedi USB drivers" depends on COMEDI && USB - default N ---help--- Enable comedi USB drivers to be built @@ -1237,7 +1194,6 @@ if COMEDI_USB_DRIVERS && USB config COMEDI_DT9812 tristate "DataTranslation DT9812 USB module support" - default N ---help--- Enable support for the Data Translation DT9812 USB module @@ -1246,7 +1202,6 @@ config COMEDI_DT9812 config COMEDI_USBDUX tristate "ITL USB-DUX-D support" - default N ---help--- Enable support for the Incite Technology Ltd USB-DUX-D Board @@ -1256,7 +1211,6 @@ config COMEDI_USBDUX config COMEDI_USBDUXFAST tristate "ITL USB-DUXfast support" select COMEDI_FC - default N ---help--- Enable support for the Incite Technology Ltd USB-DUXfast Board @@ -1266,7 +1220,6 @@ config COMEDI_USBDUXFAST config COMEDI_USBDUXSIGMA tristate "ITL USB-DUXsigma support" select COMEDI_FC - default N ---help--- Enable support for the Incite Technology Ltd USB-DUXsigma Board @@ -1275,7 +1228,6 @@ config COMEDI_USBDUXSIGMA config COMEDI_VMK80XX tristate "Velleman VM110/VM140 USB Board support" - default N ---help--- Build the Velleman USB Board Low-Level Driver supporting the K8055/K8061 aka VM110/VM140 devices @@ -1288,7 +1240,6 @@ endif # COMEDI_USB_DRIVERS menuconfig COMEDI_NI_COMMON tristate "Comedi National Instruments card support" depends on COMEDI - default N ---help--- Enable comedi support for National Instruments cards. Modules in this section are used by many comedi NI drivers. @@ -1302,7 +1253,6 @@ if COMEDI_NI_COMMON config COMEDI_MITE tristate "NI Mite PCI interface chip support" depends on PCI - default N ---help--- Enable support for National Instruments Mite PCI interface chip @@ -1312,7 +1262,6 @@ config COMEDI_MITE config COMEDI_NI_TIO tristate "NI general purpose counter support" depends on COMEDI_MITE - default N ---help--- Enable support for National Instruments general purpose counters. This module is not used directly by end-users. Rather, it @@ -1328,7 +1277,6 @@ config COMEDI_NI_LABPC select COMEDI_8255 select COMEDI_FC depends on VIRT_TO_BUS - default N ---help--- Enable support for National Instruments Lab-PC and compatibles Lab-PC-1200, Lab-PC-1200AI, Lab-PC+ and PCI-1200. @@ -1343,7 +1291,6 @@ endif # COMEDI_NI_COMMON config COMEDI_8255 tristate "Generic 8255 support" depends on COMEDI - default N ---help--- Enable generic 8255 support. @@ -1357,24 +1304,9 @@ config COMEDI_8255 To compile this driver as a module, choose M here: the module will be called 8255. -config COMEDI_DAS08 - tristate "DAS-08 compatible support" - depends on COMEDI - select COMEDI_8255 - default N - ---help--- - Enable support for DAS08 and compatible ISA, PC/104 and PCI cards. - - Note that PCMCIA DAS08 cards are not directly supported by this - driver, and need a separate driver as a wrapper. - - To compile this driver as a module, choose M here: the module will be - called das08. - config COMEDI_FC tristate "Comedi shared functions for low-level driver support" depends on COMEDI - default N ---help--- Enable support for shared functions for low-level drivers. This module is not used directly by end-users. Rather, it @@ -1382,3 +1314,22 @@ config COMEDI_FC To compile this driver as a module, choose M here: the module will be called comedi_fc. + +config COMEDI_AMPLC_DIO200 + tristate + depends on COMEDI + select COMEDI_8255 + +config COMEDI_AMPLC_PC236 + tristate + depends on COMEDI + select COMEDI_8255 + +config COMEDI_AMPLC_PC263 + tristate + depends on COMEDI + +config COMEDI_DAS08 + tristate + depends on COMEDI + select COMEDI_8255 diff --git a/trunk/drivers/staging/comedi/comedi.h b/trunk/drivers/staging/comedi/comedi.h index 14ea35ac0156..8ea55aef10a7 100644 --- a/trunk/drivers/staging/comedi/comedi.h +++ b/trunk/drivers/staging/comedi/comedi.h @@ -465,7 +465,7 @@ /* only relevant to kernel modules. */ #define COMEDI_CB_EOS 1 /* end of scan */ -#define COMEDI_CB_EOA 2 /* end of acquisition */ +#define COMEDI_CB_EOA 2 /* end of acquisition/output */ #define COMEDI_CB_BLOCK 4 /* data has arrived: * wakes up read() / write() */ #define COMEDI_CB_EOBUF 8 /* DEPRECATED: end of buffer */ diff --git a/trunk/drivers/staging/comedi/comedi_fops.c b/trunk/drivers/staging/comedi/comedi_fops.c index 9bcf87ae4c00..76776571ed91 100644 --- a/trunk/drivers/staging/comedi/comedi_fops.c +++ b/trunk/drivers/staging/comedi/comedi_fops.c @@ -58,14 +58,35 @@ MODULE_LICENSE("GPL"); #ifdef CONFIG_COMEDI_DEBUG int comedi_debug; EXPORT_SYMBOL(comedi_debug); -module_param(comedi_debug, int, 0644); +module_param(comedi_debug, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(comedi_debug, + "enable comedi core and driver debugging if non-zero (default 0)" + ); #endif bool comedi_autoconfig = 1; -module_param(comedi_autoconfig, bool, 0444); +module_param(comedi_autoconfig, bool, S_IRUGO); +MODULE_PARM_DESC(comedi_autoconfig, + "enable drivers to auto-configure comedi devices (default 1)"); static int comedi_num_legacy_minors; -module_param(comedi_num_legacy_minors, int, 0444); +module_param(comedi_num_legacy_minors, int, S_IRUGO); +MODULE_PARM_DESC(comedi_num_legacy_minors, + "number of comedi minor devices to reserve for non-auto-configured devices (default 0)" + ); + +unsigned int comedi_default_buf_size_kb = CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB; +module_param(comedi_default_buf_size_kb, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(comedi_default_buf_size_kb, + "default asynchronous buffer size in KiB (default " + __MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB) ")"); + +unsigned int comedi_default_buf_maxsize_kb + = CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB; +module_param(comedi_default_buf_maxsize_kb, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(comedi_default_buf_maxsize_kb, + "default maximum size of asynchronous buffer in KiB (default " + __MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB) ")"); static DEFINE_SPINLOCK(comedi_file_info_table_lock); static struct comedi_device_file_info @@ -108,15 +129,283 @@ static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s); static int comedi_fasync(int fd, struct file *file, int on); static int is_device_busy(struct comedi_device *dev); + static int resize_async_buffer(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_async *async, unsigned new_size); + struct comedi_async *async, unsigned new_size) +{ + int retval; + + if (new_size > async->max_bufsize) + return -EPERM; + + if (s->busy) { + DPRINTK("subdevice is busy, cannot resize buffer\n"); + return -EBUSY; + } + if (async->mmap_count) { + DPRINTK("subdevice is mmapped, cannot resize buffer\n"); + return -EBUSY; + } + + if (!async->prealloc_buf) + return -EINVAL; + + /* make sure buffer is an integral number of pages + * (we round up) */ + new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK; + + retval = comedi_buf_alloc(dev, s, new_size); + if (retval < 0) + return retval; + + if (s->buf_change) { + retval = s->buf_change(dev, s, new_size); + if (retval < 0) + return retval; + } + + DPRINTK("comedi%i subd %d buffer resized to %i bytes\n", + dev->minor, (int)(s - dev->subdevices), async->prealloc_bufsz); + return 0; +} + +/* sysfs attribute files */ + +static const unsigned bytes_per_kibi = 1024; + +static ssize_t show_max_read_buffer_kb(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t retval; + struct comedi_device_file_info *info = dev_get_drvdata(dev); + unsigned max_buffer_size_kb = 0; + struct comedi_subdevice *const read_subdevice = + comedi_get_read_subdevice(info); + + mutex_lock(&info->device->mutex); + if (read_subdevice && + (read_subdevice->subdev_flags & SDF_CMD_READ) && + read_subdevice->async) { + max_buffer_size_kb = read_subdevice->async->max_bufsize / + bytes_per_kibi; + } + retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb); + mutex_unlock(&info->device->mutex); + + return retval; +} + +static ssize_t store_max_read_buffer_kb(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct comedi_device_file_info *info = dev_get_drvdata(dev); + unsigned int new_max_size_kb; + unsigned int new_max_size; + int ret; + struct comedi_subdevice *const read_subdevice = + comedi_get_read_subdevice(info); + + ret = kstrtouint(buf, 10, &new_max_size_kb); + if (ret) + return ret; + if (new_max_size_kb > (UINT_MAX / bytes_per_kibi)) + return -EINVAL; + new_max_size = new_max_size_kb * bytes_per_kibi; + + mutex_lock(&info->device->mutex); + if (read_subdevice == NULL || + (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 || + read_subdevice->async == NULL) { + mutex_unlock(&info->device->mutex); + return -EINVAL; + } + read_subdevice->async->max_bufsize = new_max_size; + mutex_unlock(&info->device->mutex); + + return count; +} + +static ssize_t show_read_buffer_kb(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t retval; + struct comedi_device_file_info *info = dev_get_drvdata(dev); + unsigned buffer_size_kb = 0; + struct comedi_subdevice *const read_subdevice = + comedi_get_read_subdevice(info); + + mutex_lock(&info->device->mutex); + if (read_subdevice && + (read_subdevice->subdev_flags & SDF_CMD_READ) && + read_subdevice->async) { + buffer_size_kb = read_subdevice->async->prealloc_bufsz / + bytes_per_kibi; + } + retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb); + mutex_unlock(&info->device->mutex); + + return retval; +} + +static ssize_t store_read_buffer_kb(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct comedi_device_file_info *info = dev_get_drvdata(dev); + unsigned int new_size_kb; + unsigned int new_size; + int retval; + int ret; + struct comedi_subdevice *const read_subdevice = + comedi_get_read_subdevice(info); + + ret = kstrtouint(buf, 10, &new_size_kb); + if (ret) + return ret; + if (new_size_kb > (UINT_MAX / bytes_per_kibi)) + return -EINVAL; + new_size = new_size_kb * bytes_per_kibi; + + mutex_lock(&info->device->mutex); + if (read_subdevice == NULL || + (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 || + read_subdevice->async == NULL) { + mutex_unlock(&info->device->mutex); + return -EINVAL; + } + retval = resize_async_buffer(info->device, read_subdevice, + read_subdevice->async, new_size); + mutex_unlock(&info->device->mutex); + + if (retval < 0) + return retval; + return count; +} + +static ssize_t show_max_write_buffer_kb(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + ssize_t retval; + struct comedi_device_file_info *info = dev_get_drvdata(dev); + unsigned max_buffer_size_kb = 0; + struct comedi_subdevice *const write_subdevice = + comedi_get_write_subdevice(info); + + mutex_lock(&info->device->mutex); + if (write_subdevice && + (write_subdevice->subdev_flags & SDF_CMD_WRITE) && + write_subdevice->async) { + max_buffer_size_kb = write_subdevice->async->max_bufsize / + bytes_per_kibi; + } + retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb); + mutex_unlock(&info->device->mutex); + + return retval; +} + +static ssize_t store_max_write_buffer_kb(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct comedi_device_file_info *info = dev_get_drvdata(dev); + unsigned int new_max_size_kb; + unsigned int new_max_size; + int ret; + struct comedi_subdevice *const write_subdevice = + comedi_get_write_subdevice(info); + + ret = kstrtouint(buf, 10, &new_max_size_kb); + if (ret) + return ret; + if (new_max_size_kb > (UINT_MAX / bytes_per_kibi)) + return -EINVAL; + new_max_size = new_max_size_kb * bytes_per_kibi; + + mutex_lock(&info->device->mutex); + if (write_subdevice == NULL || + (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 || + write_subdevice->async == NULL) { + mutex_unlock(&info->device->mutex); + return -EINVAL; + } + write_subdevice->async->max_bufsize = new_max_size; + mutex_unlock(&info->device->mutex); + + return count; +} + +static ssize_t show_write_buffer_kb(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t retval; + struct comedi_device_file_info *info = dev_get_drvdata(dev); + unsigned buffer_size_kb = 0; + struct comedi_subdevice *const write_subdevice = + comedi_get_write_subdevice(info); + + mutex_lock(&info->device->mutex); + if (write_subdevice && + (write_subdevice->subdev_flags & SDF_CMD_WRITE) && + write_subdevice->async) { + buffer_size_kb = write_subdevice->async->prealloc_bufsz / + bytes_per_kibi; + } + retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb); + mutex_unlock(&info->device->mutex); + + return retval; +} + +static ssize_t store_write_buffer_kb(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct comedi_device_file_info *info = dev_get_drvdata(dev); + unsigned int new_size_kb; + unsigned int new_size; + int retval; + int ret; + struct comedi_subdevice *const write_subdevice = + comedi_get_write_subdevice(info); + + ret = kstrtouint(buf, 10, &new_size_kb); + if (ret) + return ret; + if (new_size_kb > (UINT_MAX / bytes_per_kibi)) + return -EINVAL; + new_size = ((uint64_t) new_size_kb) * bytes_per_kibi; -/* declarations for sysfs attribute files */ -static struct device_attribute dev_attr_max_read_buffer_kb; -static struct device_attribute dev_attr_read_buffer_kb; -static struct device_attribute dev_attr_max_write_buffer_kb; -static struct device_attribute dev_attr_write_buffer_kb; + mutex_lock(&info->device->mutex); + if (write_subdevice == NULL || + (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 || + write_subdevice->async == NULL) { + mutex_unlock(&info->device->mutex); + return -EINVAL; + } + retval = resize_async_buffer(info->device, write_subdevice, + write_subdevice->async, new_size); + mutex_unlock(&info->device->mutex); + + if (retval < 0) + return retval; + return count; +} + +static struct device_attribute comedi_dev_attrs[] = { + __ATTR(max_read_buffer_kb, S_IRUGO | S_IWUSR, + show_max_read_buffer_kb, store_max_read_buffer_kb), + __ATTR(read_buffer_kb, S_IRUGO | S_IWUSR | S_IWGRP, + show_read_buffer_kb, store_read_buffer_kb), + __ATTR(max_write_buffer_kb, S_IRUGO | S_IWUSR, + show_max_write_buffer_kb, store_max_write_buffer_kb), + __ATTR(write_buffer_kb, S_IRUGO | S_IWUSR | S_IWGRP, + show_write_buffer_kb, store_write_buffer_kb), + __ATTR_NULL +}; static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) @@ -280,7 +569,7 @@ static int do_devconfig_ioctl(struct comedi_device *dev, if (ret == 0) { if (!try_module_get(dev->driver->module)) { comedi_device_detach(dev); - return -ENOSYS; + ret = -ENOSYS; } } @@ -1545,7 +1834,7 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma) return retval; } -static unsigned int comedi_poll(struct file *file, poll_table * wait) +static unsigned int comedi_poll(struct file *file, poll_table *wait) { unsigned int mask = 0; const unsigned minor = iminor(file->f_dentry->d_inode); @@ -1880,827 +2169,473 @@ static int comedi_open(struct inode *inode, struct file *file) dev->in_request_module = 1; -#ifdef CONFIG_KMOD - mutex_unlock(&dev->mutex); - request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor); - mutex_lock(&dev->mutex); -#endif - - dev->in_request_module = 0; - - if (!dev->attached && !capable(CAP_NET_ADMIN)) { - DPRINTK("not attached and not CAP_NET_ADMIN\n"); - mutex_unlock(&dev->mutex); - return -ENODEV; - } -ok: - __module_get(THIS_MODULE); - - if (dev->attached) { - if (!try_module_get(dev->driver->module)) { - module_put(THIS_MODULE); - mutex_unlock(&dev->mutex); - return -ENOSYS; - } - } - - if (dev->attached && dev->use_count == 0 && dev->open) { - int rc = dev->open(dev); - if (rc < 0) { - module_put(dev->driver->module); - module_put(THIS_MODULE); - mutex_unlock(&dev->mutex); - return rc; - } - } - - dev->use_count++; - - mutex_unlock(&dev->mutex); - - return 0; -} - -static int comedi_close(struct inode *inode, struct file *file) -{ - const unsigned minor = iminor(inode); - struct comedi_subdevice *s = NULL; - int i; - struct comedi_device_file_info *dev_file_info; - struct comedi_device *dev; - dev_file_info = comedi_get_device_file_info(minor); - - if (dev_file_info == NULL) - return -ENODEV; - dev = dev_file_info->device; - if (dev == NULL) - return -ENODEV; - - mutex_lock(&dev->mutex); - - if (dev->subdevices) { - for (i = 0; i < dev->n_subdevices; i++) { - s = dev->subdevices + i; - - if (s->busy == file) - do_cancel(dev, s); - if (s->lock == file) - s->lock = NULL; - } - } - if (dev->attached && dev->use_count == 1 && dev->close) - dev->close(dev); - - module_put(THIS_MODULE); - if (dev->attached) - module_put(dev->driver->module); - - dev->use_count--; - - mutex_unlock(&dev->mutex); - - if (file->f_flags & FASYNC) - comedi_fasync(-1, file, 0); - - return 0; -} - -static int comedi_fasync(int fd, struct file *file, int on) -{ - const unsigned minor = iminor(file->f_dentry->d_inode); - struct comedi_device_file_info *dev_file_info; - struct comedi_device *dev; - dev_file_info = comedi_get_device_file_info(minor); - - if (dev_file_info == NULL) - return -ENODEV; - dev = dev_file_info->device; - if (dev == NULL) - return -ENODEV; - - return fasync_helper(fd, file, on, &dev->async_queue); -} - -const struct file_operations comedi_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = comedi_unlocked_ioctl, - .compat_ioctl = comedi_compat_ioctl, - .open = comedi_open, - .release = comedi_close, - .read = comedi_read, - .write = comedi_write, - .mmap = comedi_mmap, - .poll = comedi_poll, - .fasync = comedi_fasync, - .llseek = noop_llseek, -}; - -struct class *comedi_class; -static struct cdev comedi_cdev; - -static void comedi_cleanup_legacy_minors(void) -{ - unsigned i; - - for (i = 0; i < comedi_num_legacy_minors; i++) - comedi_free_board_minor(i); -} - -static int __init comedi_init(void) -{ - int i; - int retval; - - printk(KERN_INFO "comedi: version " COMEDI_RELEASE - " - http://www.comedi.org\n"); - - if (comedi_num_legacy_minors < 0 || - comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) { - printk(KERN_ERR "comedi: error: invalid value for module " - "parameter \"comedi_num_legacy_minors\". Valid values " - "are 0 through %i.\n", COMEDI_NUM_BOARD_MINORS); - return -EINVAL; - } - - /* - * comedi is unusable if both comedi_autoconfig and - * comedi_num_legacy_minors are zero, so we might as well adjust the - * defaults in that case - */ - if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0) - comedi_num_legacy_minors = 16; - - memset(comedi_file_info_table, 0, - sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS); - - retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0), - COMEDI_NUM_MINORS, "comedi"); - if (retval) - return -EIO; - cdev_init(&comedi_cdev, &comedi_fops); - comedi_cdev.owner = THIS_MODULE; - kobject_set_name(&comedi_cdev.kobj, "comedi"); - if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) { - unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), - COMEDI_NUM_MINORS); - return -EIO; - } - comedi_class = class_create(THIS_MODULE, "comedi"); - if (IS_ERR(comedi_class)) { - printk(KERN_ERR "comedi: failed to create class"); - cdev_del(&comedi_cdev); - unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), - COMEDI_NUM_MINORS); - return PTR_ERR(comedi_class); - } - - /* XXX requires /proc interface */ - comedi_proc_init(); - - /* create devices files for legacy/manual use */ - for (i = 0; i < comedi_num_legacy_minors; i++) { - int minor; - minor = comedi_alloc_board_minor(NULL); - if (minor < 0) { - comedi_cleanup_legacy_minors(); - cdev_del(&comedi_cdev); - unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), - COMEDI_NUM_MINORS); - return minor; - } - } - - return 0; -} - -static void __exit comedi_cleanup(void) -{ - int i; - - comedi_cleanup_legacy_minors(); - for (i = 0; i < COMEDI_NUM_MINORS; ++i) - BUG_ON(comedi_file_info_table[i]); - - class_destroy(comedi_class); - cdev_del(&comedi_cdev); - unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS); - - comedi_proc_cleanup(); -} - -module_init(comedi_init); -module_exit(comedi_cleanup); - -void comedi_error(const struct comedi_device *dev, const char *s) -{ - printk(KERN_ERR "comedi%d: %s: %s\n", dev->minor, - dev->driver->driver_name, s); -} -EXPORT_SYMBOL(comedi_error); - -void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s) -{ - struct comedi_async *async = s->async; - unsigned runflags = 0; - unsigned runflags_mask = 0; - - /* DPRINTK("comedi_event 0x%x\n",mask); */ +#ifdef CONFIG_KMOD + mutex_unlock(&dev->mutex); + request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor); + mutex_lock(&dev->mutex); +#endif - if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0) - return; + dev->in_request_module = 0; - if (s-> - async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | - COMEDI_CB_OVERFLOW)) { - runflags_mask |= SRF_RUNNING; - } - /* remember if an error event has occurred, so an error - * can be returned the next time the user does a read() */ - if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) { - runflags_mask |= SRF_ERROR; - runflags |= SRF_ERROR; - } - if (runflags_mask) { - /*sets SRF_ERROR and SRF_RUNNING together atomically */ - comedi_set_subdevice_runflags(s, runflags_mask, runflags); + if (!dev->attached && !capable(CAP_NET_ADMIN)) { + DPRINTK("not attached and not CAP_NET_ADMIN\n"); + mutex_unlock(&dev->mutex); + return -ENODEV; } +ok: + __module_get(THIS_MODULE); - if (async->cb_mask & s->async->events) { - if (comedi_get_subdevice_runflags(s) & SRF_USER) { - wake_up_interruptible(&async->wait_head); - if (s->subdev_flags & SDF_CMD_READ) - kill_fasync(&dev->async_queue, SIGIO, POLL_IN); - if (s->subdev_flags & SDF_CMD_WRITE) - kill_fasync(&dev->async_queue, SIGIO, POLL_OUT); - } else { - if (async->cb_func) - async->cb_func(s->async->events, async->cb_arg); + if (dev->attached) { + if (!try_module_get(dev->driver->module)) { + module_put(THIS_MODULE); + mutex_unlock(&dev->mutex); + return -ENOSYS; } } - s->async->events = 0; -} -EXPORT_SYMBOL(comedi_event); - -unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s) -{ - unsigned long flags; - unsigned runflags; - - spin_lock_irqsave(&s->spin_lock, flags); - runflags = s->runflags; - spin_unlock_irqrestore(&s->spin_lock, flags); - return runflags; -} -EXPORT_SYMBOL(comedi_get_subdevice_runflags); -static int is_device_busy(struct comedi_device *dev) -{ - struct comedi_subdevice *s; - int i; + if (dev->attached && dev->use_count == 0 && dev->open) { + int rc = dev->open(dev); + if (rc < 0) { + module_put(dev->driver->module); + module_put(THIS_MODULE); + mutex_unlock(&dev->mutex); + return rc; + } + } - if (!dev->attached) - return 0; + dev->use_count++; - for (i = 0; i < dev->n_subdevices; i++) { - s = dev->subdevices + i; - if (s->busy) - return 1; - if (s->async && s->async->mmap_count) - return 1; - } + mutex_unlock(&dev->mutex); return 0; } -static void comedi_device_init(struct comedi_device *dev) +static int comedi_close(struct inode *inode, struct file *file) { - memset(dev, 0, sizeof(struct comedi_device)); - spin_lock_init(&dev->spinlock); - mutex_init(&dev->mutex); - dev->minor = -1; -} + const unsigned minor = iminor(inode); + struct comedi_subdevice *s = NULL; + int i; + struct comedi_device_file_info *dev_file_info; + struct comedi_device *dev; + dev_file_info = comedi_get_device_file_info(minor); -static void comedi_device_cleanup(struct comedi_device *dev) -{ + if (dev_file_info == NULL) + return -ENODEV; + dev = dev_file_info->device; if (dev == NULL) - return; + return -ENODEV; + mutex_lock(&dev->mutex); - comedi_device_detach(dev); - mutex_unlock(&dev->mutex); - mutex_destroy(&dev->mutex); -} -int comedi_alloc_board_minor(struct device *hardware_device) -{ - unsigned long flags; - struct comedi_device_file_info *info; - struct device *csdev; - unsigned i; - int retval; + if (dev->subdevices) { + for (i = 0; i < dev->n_subdevices; i++) { + s = dev->subdevices + i; - info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); - if (info == NULL) - return -ENOMEM; - info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL); - if (info->device == NULL) { - kfree(info); - return -ENOMEM; - } - comedi_device_init(info->device); - spin_lock_irqsave(&comedi_file_info_table_lock, flags); - for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) { - if (comedi_file_info_table[i] == NULL) { - comedi_file_info_table[i] = info; - break; + if (s->busy == file) + do_cancel(dev, s); + if (s->lock == file) + s->lock = NULL; } } - spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); - if (i == COMEDI_NUM_BOARD_MINORS) { - comedi_device_cleanup(info->device); - kfree(info->device); - kfree(info); - printk(KERN_ERR - "comedi: error: " - "ran out of minor numbers for board device files.\n"); - return -EBUSY; - } - info->device->minor = i; - csdev = device_create(comedi_class, hardware_device, - MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i", i); - if (!IS_ERR(csdev)) - info->device->class_dev = csdev; - dev_set_drvdata(csdev, info); - retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb); - if (retval) { - printk(KERN_ERR - "comedi: " - "failed to create sysfs attribute file \"%s\".\n", - dev_attr_max_read_buffer_kb.attr.name); - comedi_free_board_minor(i); - return retval; - } - retval = device_create_file(csdev, &dev_attr_read_buffer_kb); - if (retval) { - printk(KERN_ERR - "comedi: " - "failed to create sysfs attribute file \"%s\".\n", - dev_attr_read_buffer_kb.attr.name); - comedi_free_board_minor(i); - return retval; - } - retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb); - if (retval) { - printk(KERN_ERR - "comedi: " - "failed to create sysfs attribute file \"%s\".\n", - dev_attr_max_write_buffer_kb.attr.name); - comedi_free_board_minor(i); - return retval; - } - retval = device_create_file(csdev, &dev_attr_write_buffer_kb); - if (retval) { - printk(KERN_ERR - "comedi: " - "failed to create sysfs attribute file \"%s\".\n", - dev_attr_write_buffer_kb.attr.name); - comedi_free_board_minor(i); - return retval; - } - return i; -} + if (dev->attached && dev->use_count == 1 && dev->close) + dev->close(dev); -void comedi_free_board_minor(unsigned minor) -{ - unsigned long flags; - struct comedi_device_file_info *info; + module_put(THIS_MODULE); + if (dev->attached) + module_put(dev->driver->module); - BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS); - spin_lock_irqsave(&comedi_file_info_table_lock, flags); - info = comedi_file_info_table[minor]; - comedi_file_info_table[minor] = NULL; - spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); + dev->use_count--; - if (info) { - struct comedi_device *dev = info->device; - if (dev) { - if (dev->class_dev) { - device_destroy(comedi_class, - MKDEV(COMEDI_MAJOR, dev->minor)); - } - comedi_device_cleanup(dev); - kfree(dev); - } - kfree(info); - } -} + mutex_unlock(&dev->mutex); -int comedi_alloc_subdevice_minor(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - unsigned long flags; - struct comedi_device_file_info *info; - struct device *csdev; - unsigned i; - int retval; + if (file->f_flags & FASYNC) + comedi_fasync(-1, file, 0); - info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); - if (info == NULL) - return -ENOMEM; - info->device = dev; - info->read_subdevice = s; - info->write_subdevice = s; - spin_lock_irqsave(&comedi_file_info_table_lock, flags); - for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) { - if (comedi_file_info_table[i] == NULL) { - comedi_file_info_table[i] = info; - break; - } - } - spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); - if (i == COMEDI_NUM_MINORS) { - kfree(info); - printk(KERN_ERR - "comedi: error: " - "ran out of minor numbers for board device files.\n"); - return -EBUSY; - } - s->minor = i; - csdev = device_create(comedi_class, dev->class_dev, - MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i_subd%i", - dev->minor, (int)(s - dev->subdevices)); - if (!IS_ERR(csdev)) - s->class_dev = csdev; - dev_set_drvdata(csdev, info); - retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb); - if (retval) { - printk(KERN_ERR - "comedi: " - "failed to create sysfs attribute file \"%s\".\n", - dev_attr_max_read_buffer_kb.attr.name); - comedi_free_subdevice_minor(s); - return retval; - } - retval = device_create_file(csdev, &dev_attr_read_buffer_kb); - if (retval) { - printk(KERN_ERR - "comedi: " - "failed to create sysfs attribute file \"%s\".\n", - dev_attr_read_buffer_kb.attr.name); - comedi_free_subdevice_minor(s); - return retval; - } - retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb); - if (retval) { - printk(KERN_ERR - "comedi: " - "failed to create sysfs attribute file \"%s\".\n", - dev_attr_max_write_buffer_kb.attr.name); - comedi_free_subdevice_minor(s); - return retval; - } - retval = device_create_file(csdev, &dev_attr_write_buffer_kb); - if (retval) { - printk(KERN_ERR - "comedi: " - "failed to create sysfs attribute file \"%s\".\n", - dev_attr_write_buffer_kb.attr.name); - comedi_free_subdevice_minor(s); - return retval; - } - return i; + return 0; } -void comedi_free_subdevice_minor(struct comedi_subdevice *s) +static int comedi_fasync(int fd, struct file *file, int on) { - unsigned long flags; - struct comedi_device_file_info *info; - - if (s == NULL) - return; - if (s->minor < 0) - return; - - BUG_ON(s->minor >= COMEDI_NUM_MINORS); - BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR); + const unsigned minor = iminor(file->f_dentry->d_inode); + struct comedi_device_file_info *dev_file_info; + struct comedi_device *dev; + dev_file_info = comedi_get_device_file_info(minor); - spin_lock_irqsave(&comedi_file_info_table_lock, flags); - info = comedi_file_info_table[s->minor]; - comedi_file_info_table[s->minor] = NULL; - spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); + if (dev_file_info == NULL) + return -ENODEV; + dev = dev_file_info->device; + if (dev == NULL) + return -ENODEV; - if (s->class_dev) { - device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor)); - s->class_dev = NULL; - } - kfree(info); + return fasync_helper(fd, file, on, &dev->async_queue); } -struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor) +const struct file_operations comedi_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = comedi_unlocked_ioctl, + .compat_ioctl = comedi_compat_ioctl, + .open = comedi_open, + .release = comedi_close, + .read = comedi_read, + .write = comedi_write, + .mmap = comedi_mmap, + .poll = comedi_poll, + .fasync = comedi_fasync, + .llseek = noop_llseek, +}; + +struct class *comedi_class; +static struct cdev comedi_cdev; + +static void comedi_cleanup_legacy_minors(void) { - unsigned long flags; - struct comedi_device_file_info *info; + unsigned i; - BUG_ON(minor >= COMEDI_NUM_MINORS); - spin_lock_irqsave(&comedi_file_info_table_lock, flags); - info = comedi_file_info_table[minor]; - spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); - return info; + for (i = 0; i < comedi_num_legacy_minors; i++) + comedi_free_board_minor(i); } -EXPORT_SYMBOL_GPL(comedi_get_device_file_info); -static int resize_async_buffer(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_async *async, unsigned new_size) +static int __init comedi_init(void) { + int i; int retval; - if (new_size > async->max_bufsize) - return -EPERM; + printk(KERN_INFO "comedi: version " COMEDI_RELEASE + " - http://www.comedi.org\n"); - if (s->busy) { - DPRINTK("subdevice is busy, cannot resize buffer\n"); - return -EBUSY; - } - if (async->mmap_count) { - DPRINTK("subdevice is mmapped, cannot resize buffer\n"); - return -EBUSY; + if (comedi_num_legacy_minors < 0 || + comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) { + printk(KERN_ERR "comedi: error: invalid value for module " + "parameter \"comedi_num_legacy_minors\". Valid values " + "are 0 through %i.\n", COMEDI_NUM_BOARD_MINORS); + return -EINVAL; } - if (!async->prealloc_buf) - return -EINVAL; + /* + * comedi is unusable if both comedi_autoconfig and + * comedi_num_legacy_minors are zero, so we might as well adjust the + * defaults in that case + */ + if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0) + comedi_num_legacy_minors = 16; - /* make sure buffer is an integral number of pages - * (we round up) */ - new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK; + memset(comedi_file_info_table, 0, + sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS); - retval = comedi_buf_alloc(dev, s, new_size); - if (retval < 0) - return retval; + retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0), + COMEDI_NUM_MINORS, "comedi"); + if (retval) + return -EIO; + cdev_init(&comedi_cdev, &comedi_fops); + comedi_cdev.owner = THIS_MODULE; + kobject_set_name(&comedi_cdev.kobj, "comedi"); + if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) { + unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), + COMEDI_NUM_MINORS); + return -EIO; + } + comedi_class = class_create(THIS_MODULE, "comedi"); + if (IS_ERR(comedi_class)) { + printk(KERN_ERR "comedi: failed to create class"); + cdev_del(&comedi_cdev); + unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), + COMEDI_NUM_MINORS); + return PTR_ERR(comedi_class); + } - if (s->buf_change) { - retval = s->buf_change(dev, s, new_size); - if (retval < 0) - return retval; + comedi_class->dev_attrs = comedi_dev_attrs; + + /* XXX requires /proc interface */ + comedi_proc_init(); + + /* create devices files for legacy/manual use */ + for (i = 0; i < comedi_num_legacy_minors; i++) { + int minor; + minor = comedi_alloc_board_minor(NULL); + if (minor < 0) { + comedi_cleanup_legacy_minors(); + cdev_del(&comedi_cdev); + unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), + COMEDI_NUM_MINORS); + return minor; + } } - DPRINTK("comedi%i subd %d buffer resized to %i bytes\n", - dev->minor, (int)(s - dev->subdevices), async->prealloc_bufsz); return 0; } -/* sysfs attribute files */ +static void __exit comedi_cleanup(void) +{ + int i; -static const unsigned bytes_per_kibi = 1024; + comedi_cleanup_legacy_minors(); + for (i = 0; i < COMEDI_NUM_MINORS; ++i) + BUG_ON(comedi_file_info_table[i]); -static ssize_t show_max_read_buffer_kb(struct device *dev, - struct device_attribute *attr, char *buf) -{ - ssize_t retval; - struct comedi_device_file_info *info = dev_get_drvdata(dev); - unsigned max_buffer_size_kb = 0; - struct comedi_subdevice *const read_subdevice = - comedi_get_read_subdevice(info); + class_destroy(comedi_class); + cdev_del(&comedi_cdev); + unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS); - mutex_lock(&info->device->mutex); - if (read_subdevice && - (read_subdevice->subdev_flags & SDF_CMD_READ) && - read_subdevice->async) { - max_buffer_size_kb = read_subdevice->async->max_bufsize / - bytes_per_kibi; - } - retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb); - mutex_unlock(&info->device->mutex); + comedi_proc_cleanup(); +} - return retval; +module_init(comedi_init); +module_exit(comedi_cleanup); + +void comedi_error(const struct comedi_device *dev, const char *s) +{ + printk(KERN_ERR "comedi%d: %s: %s\n", dev->minor, + dev->driver->driver_name, s); } +EXPORT_SYMBOL(comedi_error); -static ssize_t store_max_read_buffer_kb(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s) { - struct comedi_device_file_info *info = dev_get_drvdata(dev); - unsigned int new_max_size_kb; - unsigned int new_max_size; - int ret; - struct comedi_subdevice *const read_subdevice = - comedi_get_read_subdevice(info); + struct comedi_async *async = s->async; + unsigned runflags = 0; + unsigned runflags_mask = 0; - ret = kstrtouint(buf, 10, &new_max_size_kb); - if (ret) - return ret; - if (new_max_size_kb > (UINT_MAX / bytes_per_kibi)) - return -EINVAL; - new_max_size = new_max_size_kb * bytes_per_kibi; + /* DPRINTK("comedi_event 0x%x\n",mask); */ - mutex_lock(&info->device->mutex); - if (read_subdevice == NULL || - (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 || - read_subdevice->async == NULL) { - mutex_unlock(&info->device->mutex); - return -EINVAL; + if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0) + return; + + if (s-> + async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | + COMEDI_CB_OVERFLOW)) { + runflags_mask |= SRF_RUNNING; + } + /* remember if an error event has occurred, so an error + * can be returned the next time the user does a read() */ + if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) { + runflags_mask |= SRF_ERROR; + runflags |= SRF_ERROR; + } + if (runflags_mask) { + /*sets SRF_ERROR and SRF_RUNNING together atomically */ + comedi_set_subdevice_runflags(s, runflags_mask, runflags); } - read_subdevice->async->max_bufsize = new_max_size; - mutex_unlock(&info->device->mutex); - return count; + if (async->cb_mask & s->async->events) { + if (comedi_get_subdevice_runflags(s) & SRF_USER) { + wake_up_interruptible(&async->wait_head); + if (s->subdev_flags & SDF_CMD_READ) + kill_fasync(&dev->async_queue, SIGIO, POLL_IN); + if (s->subdev_flags & SDF_CMD_WRITE) + kill_fasync(&dev->async_queue, SIGIO, POLL_OUT); + } else { + if (async->cb_func) + async->cb_func(s->async->events, async->cb_arg); + } + } + s->async->events = 0; } +EXPORT_SYMBOL(comedi_event); -static struct device_attribute dev_attr_max_read_buffer_kb = { - .attr = { - .name = "max_read_buffer_kb", - .mode = S_IRUGO | S_IWUSR}, - .show = &show_max_read_buffer_kb, - .store = &store_max_read_buffer_kb -}; - -static ssize_t show_read_buffer_kb(struct device *dev, - struct device_attribute *attr, char *buf) +unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s) { - ssize_t retval; - struct comedi_device_file_info *info = dev_get_drvdata(dev); - unsigned buffer_size_kb = 0; - struct comedi_subdevice *const read_subdevice = - comedi_get_read_subdevice(info); - - mutex_lock(&info->device->mutex); - if (read_subdevice && - (read_subdevice->subdev_flags & SDF_CMD_READ) && - read_subdevice->async) { - buffer_size_kb = read_subdevice->async->prealloc_bufsz / - bytes_per_kibi; - } - retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb); - mutex_unlock(&info->device->mutex); + unsigned long flags; + unsigned runflags; - return retval; + spin_lock_irqsave(&s->spin_lock, flags); + runflags = s->runflags; + spin_unlock_irqrestore(&s->spin_lock, flags); + return runflags; } +EXPORT_SYMBOL(comedi_get_subdevice_runflags); -static ssize_t store_read_buffer_kb(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static int is_device_busy(struct comedi_device *dev) { - struct comedi_device_file_info *info = dev_get_drvdata(dev); - unsigned int new_size_kb; - unsigned int new_size; - int retval; - int ret; - struct comedi_subdevice *const read_subdevice = - comedi_get_read_subdevice(info); + struct comedi_subdevice *s; + int i; - ret = kstrtouint(buf, 10, &new_size_kb); - if (ret) - return ret; - if (new_size_kb > (UINT_MAX / bytes_per_kibi)) - return -EINVAL; - new_size = new_size_kb * bytes_per_kibi; + if (!dev->attached) + return 0; - mutex_lock(&info->device->mutex); - if (read_subdevice == NULL || - (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 || - read_subdevice->async == NULL) { - mutex_unlock(&info->device->mutex); - return -EINVAL; + for (i = 0; i < dev->n_subdevices; i++) { + s = dev->subdevices + i; + if (s->busy) + return 1; + if (s->async && s->async->mmap_count) + return 1; } - retval = resize_async_buffer(info->device, read_subdevice, - read_subdevice->async, new_size); - mutex_unlock(&info->device->mutex); - if (retval < 0) - return retval; - return count; + return 0; } -static struct device_attribute dev_attr_read_buffer_kb = { - .attr = { - .name = "read_buffer_kb", - .mode = S_IRUGO | S_IWUSR | S_IWGRP}, - .show = &show_read_buffer_kb, - .store = &store_read_buffer_kb -}; +static void comedi_device_init(struct comedi_device *dev) +{ + memset(dev, 0, sizeof(struct comedi_device)); + spin_lock_init(&dev->spinlock); + mutex_init(&dev->mutex); + dev->minor = -1; +} -static ssize_t show_max_write_buffer_kb(struct device *dev, - struct device_attribute *attr, - char *buf) +static void comedi_device_cleanup(struct comedi_device *dev) { - ssize_t retval; - struct comedi_device_file_info *info = dev_get_drvdata(dev); - unsigned max_buffer_size_kb = 0; - struct comedi_subdevice *const write_subdevice = - comedi_get_write_subdevice(info); + if (dev == NULL) + return; + mutex_lock(&dev->mutex); + comedi_device_detach(dev); + mutex_unlock(&dev->mutex); + mutex_destroy(&dev->mutex); +} - mutex_lock(&info->device->mutex); - if (write_subdevice && - (write_subdevice->subdev_flags & SDF_CMD_WRITE) && - write_subdevice->async) { - max_buffer_size_kb = write_subdevice->async->max_bufsize / - bytes_per_kibi; +int comedi_alloc_board_minor(struct device *hardware_device) +{ + struct comedi_device_file_info *info; + struct device *csdev; + unsigned i; + + info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); + if (info == NULL) + return -ENOMEM; + info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL); + if (info->device == NULL) { + kfree(info); + return -ENOMEM; } - retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb); - mutex_unlock(&info->device->mutex); + info->hardware_device = hardware_device; + comedi_device_init(info->device); + spin_lock(&comedi_file_info_table_lock); + for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) { + if (comedi_file_info_table[i] == NULL) { + comedi_file_info_table[i] = info; + break; + } + } + spin_unlock(&comedi_file_info_table_lock); + if (i == COMEDI_NUM_BOARD_MINORS) { + comedi_device_cleanup(info->device); + kfree(info->device); + kfree(info); + printk(KERN_ERR + "comedi: error: " + "ran out of minor numbers for board device files.\n"); + return -EBUSY; + } + info->device->minor = i; + csdev = device_create(comedi_class, hardware_device, + MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i", i); + if (!IS_ERR(csdev)) + info->device->class_dev = csdev; + dev_set_drvdata(csdev, info); - return retval; + return i; } -static ssize_t store_max_write_buffer_kb(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +void comedi_free_board_minor(unsigned minor) { - struct comedi_device_file_info *info = dev_get_drvdata(dev); - unsigned int new_max_size_kb; - unsigned int new_max_size; - int ret; - struct comedi_subdevice *const write_subdevice = - comedi_get_write_subdevice(info); + struct comedi_device_file_info *info; - ret = kstrtouint(buf, 10, &new_max_size_kb); - if (ret) - return ret; - if (new_max_size_kb > (UINT_MAX / bytes_per_kibi)) - return -EINVAL; - new_max_size = new_max_size_kb * bytes_per_kibi; + BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS); + spin_lock(&comedi_file_info_table_lock); + info = comedi_file_info_table[minor]; + comedi_file_info_table[minor] = NULL; + spin_unlock(&comedi_file_info_table_lock); - mutex_lock(&info->device->mutex); - if (write_subdevice == NULL || - (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 || - write_subdevice->async == NULL) { - mutex_unlock(&info->device->mutex); - return -EINVAL; + if (info) { + struct comedi_device *dev = info->device; + if (dev) { + if (dev->class_dev) { + device_destroy(comedi_class, + MKDEV(COMEDI_MAJOR, dev->minor)); + } + comedi_device_cleanup(dev); + kfree(dev); + } + kfree(info); } - write_subdevice->async->max_bufsize = new_max_size; - mutex_unlock(&info->device->mutex); - - return count; } -static struct device_attribute dev_attr_max_write_buffer_kb = { - .attr = { - .name = "max_write_buffer_kb", - .mode = S_IRUGO | S_IWUSR}, - .show = &show_max_write_buffer_kb, - .store = &store_max_write_buffer_kb -}; +int comedi_find_board_minor(struct device *hardware_device) +{ + int minor; + struct comedi_device_file_info *info; -static ssize_t show_write_buffer_kb(struct device *dev, - struct device_attribute *attr, char *buf) + for (minor = 0; minor < COMEDI_NUM_BOARD_MINORS; minor++) { + spin_lock(&comedi_file_info_table_lock); + info = comedi_file_info_table[minor]; + if (info && info->hardware_device == hardware_device) { + spin_unlock(&comedi_file_info_table_lock); + return minor; + } + spin_unlock(&comedi_file_info_table_lock); + } + return -ENODEV; +} + +int comedi_alloc_subdevice_minor(struct comedi_device *dev, + struct comedi_subdevice *s) { - ssize_t retval; - struct comedi_device_file_info *info = dev_get_drvdata(dev); - unsigned buffer_size_kb = 0; - struct comedi_subdevice *const write_subdevice = - comedi_get_write_subdevice(info); + struct comedi_device_file_info *info; + struct device *csdev; + unsigned i; - mutex_lock(&info->device->mutex); - if (write_subdevice && - (write_subdevice->subdev_flags & SDF_CMD_WRITE) && - write_subdevice->async) { - buffer_size_kb = write_subdevice->async->prealloc_bufsz / - bytes_per_kibi; + info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); + if (info == NULL) + return -ENOMEM; + info->device = dev; + info->read_subdevice = s; + info->write_subdevice = s; + spin_lock(&comedi_file_info_table_lock); + for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) { + if (comedi_file_info_table[i] == NULL) { + comedi_file_info_table[i] = info; + break; + } } - retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb); - mutex_unlock(&info->device->mutex); + spin_unlock(&comedi_file_info_table_lock); + if (i == COMEDI_NUM_MINORS) { + kfree(info); + printk(KERN_ERR + "comedi: error: " + "ran out of minor numbers for board device files.\n"); + return -EBUSY; + } + s->minor = i; + csdev = device_create(comedi_class, dev->class_dev, + MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i_subd%i", + dev->minor, (int)(s - dev->subdevices)); + if (!IS_ERR(csdev)) + s->class_dev = csdev; + dev_set_drvdata(csdev, info); - return retval; + return i; } -static ssize_t store_write_buffer_kb(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +void comedi_free_subdevice_minor(struct comedi_subdevice *s) { - struct comedi_device_file_info *info = dev_get_drvdata(dev); - unsigned int new_size_kb; - unsigned int new_size; - int retval; - int ret; - struct comedi_subdevice *const write_subdevice = - comedi_get_write_subdevice(info); + struct comedi_device_file_info *info; - ret = kstrtouint(buf, 10, &new_size_kb); - if (ret) - return ret; - if (new_size_kb > (UINT_MAX / bytes_per_kibi)) - return -EINVAL; - new_size = ((uint64_t) new_size_kb) * bytes_per_kibi; + if (s == NULL) + return; + if (s->minor < 0) + return; - mutex_lock(&info->device->mutex); - if (write_subdevice == NULL || - (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 || - write_subdevice->async == NULL) { - mutex_unlock(&info->device->mutex); - return -EINVAL; - } - retval = resize_async_buffer(info->device, write_subdevice, - write_subdevice->async, new_size); - mutex_unlock(&info->device->mutex); + BUG_ON(s->minor >= COMEDI_NUM_MINORS); + BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR); - if (retval < 0) - return retval; - return count; + spin_lock(&comedi_file_info_table_lock); + info = comedi_file_info_table[s->minor]; + comedi_file_info_table[s->minor] = NULL; + spin_unlock(&comedi_file_info_table_lock); + + if (s->class_dev) { + device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor)); + s->class_dev = NULL; + } + kfree(info); } -static struct device_attribute dev_attr_write_buffer_kb = { - .attr = { - .name = "write_buffer_kb", - .mode = S_IRUGO | S_IWUSR | S_IWGRP}, - .show = &show_write_buffer_kb, - .store = &store_write_buffer_kb -}; +struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor) +{ + struct comedi_device_file_info *info; + + BUG_ON(minor >= COMEDI_NUM_MINORS); + spin_lock(&comedi_file_info_table_lock); + info = comedi_file_info_table[minor]; + spin_unlock(&comedi_file_info_table_lock); + return info; +} +EXPORT_SYMBOL_GPL(comedi_get_device_file_info); diff --git a/trunk/drivers/staging/comedi/comedidev.h b/trunk/drivers/staging/comedi/comedidev.h index 7a0d4bcbc355..134be93eaa6d 100644 --- a/trunk/drivers/staging/comedi/comedidev.h +++ b/trunk/drivers/staging/comedi/comedidev.h @@ -180,13 +180,18 @@ struct comedi_async { unsigned int x); }; +struct pci_dev; +struct usb_interface; + struct comedi_driver { struct comedi_driver *next; const char *driver_name; struct module *module; int (*attach) (struct comedi_device *, struct comedi_devconfig *); - int (*detach) (struct comedi_device *); + void (*detach) (struct comedi_device *); + int (*attach_pci) (struct comedi_device *, struct pci_dev *); + int (*attach_usb) (struct comedi_device *, struct usb_interface *); /* number of elements in board_name and board_id arrays */ unsigned int num_names; @@ -230,10 +235,16 @@ struct comedi_device { void (*close) (struct comedi_device *dev); }; +static inline const void *comedi_board(struct comedi_device *dev) +{ + return dev->board_ptr; +} + struct comedi_device_file_info { struct comedi_device *device; struct comedi_subdevice *read_subdevice; struct comedi_subdevice *write_subdevice; + struct device *hardware_device; }; #ifdef CONFIG_COMEDI_DEBUG @@ -287,6 +298,56 @@ int comedi_device_attach(struct comedi_device *dev, int comedi_driver_register(struct comedi_driver *); int comedi_driver_unregister(struct comedi_driver *); +/** + * module_comedi_driver() - Helper macro for registering a comedi driver + * @__comedi_driver: comedi_driver struct + * + * Helper macro for comedi drivers which do not do anything special in module + * init/exit. This eliminates a lot of boilerplate. Each module may only use + * this macro once, and calling it replaces module_init() and module_exit(). + */ +#define module_comedi_driver(__comedi_driver) \ + module_driver(__comedi_driver, comedi_driver_register, \ + comedi_driver_unregister) + +struct pci_driver; + +int comedi_pci_driver_register(struct comedi_driver *, struct pci_driver *); +void comedi_pci_driver_unregister(struct comedi_driver *, struct pci_driver *); + +/** + * module_comedi_pci_driver() - Helper macro for registering a comedi PCI driver + * @__comedi_driver: comedi_driver struct + * @__pci_driver: pci_driver struct + * + * Helper macro for comedi PCI drivers which do not do anything special + * in module init/exit. This eliminates a lot of boilerplate. Each + * module may only use this macro once, and calling it replaces + * module_init() and module_exit() + */ +#define module_comedi_pci_driver(__comedi_driver, __pci_driver) \ + module_driver(__comedi_driver, comedi_pci_driver_register, \ + comedi_pci_driver_unregister, &(__pci_driver)) + +struct usb_driver; + +int comedi_usb_driver_register(struct comedi_driver *, struct usb_driver *); +void comedi_usb_driver_unregister(struct comedi_driver *, struct usb_driver *); + +/** + * module_comedi_usb_driver() - Helper macro for registering a comedi USB driver + * @__comedi_driver: comedi_driver struct + * @__usb_driver: usb_driver struct + * + * Helper macro for comedi USB drivers which do not do anything special + * in module init/exit. This eliminates a lot of boilerplate. Each + * module may only use this macro once, and calling it replaces + * module_init() and module_exit() + */ +#define module_comedi_usb_driver(__comedi_driver, __usb_driver) \ + module_driver(__comedi_driver, comedi_usb_driver_register, \ + comedi_usb_driver_unregister, &(__usb_driver)) + void init_polling(void); void cleanup_polling(void); void start_polling(struct comedi_device *); @@ -456,11 +517,12 @@ static inline void *comedi_aux_data(int options[], int n) int comedi_alloc_subdevice_minor(struct comedi_device *dev, struct comedi_subdevice *s); void comedi_free_subdevice_minor(struct comedi_subdevice *s); -int comedi_pci_auto_config(struct pci_dev *pcidev, const char *board_name); +int comedi_pci_auto_config(struct pci_dev *pcidev, + struct comedi_driver *driver); void comedi_pci_auto_unconfig(struct pci_dev *pcidev); -struct usb_device; /* forward declaration */ -int comedi_usb_auto_config(struct usb_device *usbdev, const char *board_name); -void comedi_usb_auto_unconfig(struct usb_device *usbdev); +int comedi_usb_auto_config(struct usb_interface *intf, + struct comedi_driver *driver); +void comedi_usb_auto_unconfig(struct usb_interface *intf); #ifdef CONFIG_COMEDI_PCI_DRIVERS #define CONFIG_COMEDI_PCI diff --git a/trunk/drivers/staging/comedi/drivers.c b/trunk/drivers/staging/comedi/drivers.c index bf185e2807d1..1c3d6386ea36 100644 --- a/trunk/drivers/staging/comedi/drivers.c +++ b/trunk/drivers/staging/comedi/drivers.c @@ -106,6 +106,26 @@ void comedi_device_detach(struct comedi_device *dev) __comedi_device_detach(dev); } +/* do a little post-config cleanup */ +/* called with module refcount incremented, decrements it */ +static int comedi_device_postconfig(struct comedi_device *dev) +{ + int ret = postconfig(dev); + module_put(dev->driver->module); + if (ret < 0) { + __comedi_device_detach(dev); + return ret; + } + if (!dev->board_name) { + printk(KERN_WARNING "BUG: dev->board_name=<%p>\n", + dev->board_name); + dev->board_name = "BUG"; + } + smp_wmb(); + dev->attached = 1; + return 0; +} + int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_driver *driv; @@ -121,59 +141,36 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it) } if (driv->num_names) { dev->board_ptr = comedi_recognize(driv, it->board_name); - if (dev->board_ptr == NULL) { - module_put(driv->module); - continue; - } - } else { - if (strcmp(driv->driver_name, it->board_name)) { - module_put(driv->module); + if (dev->board_ptr) + break; + } else if (strcmp(driv->driver_name, it->board_name)) + break; + module_put(driv->module); + } + if (driv == NULL) { + /* recognize has failed if we get here */ + /* report valid board names before returning error */ + for (driv = comedi_drivers; driv; driv = driv->next) { + if (!try_module_get(driv->module)) { + printk(KERN_INFO + "comedi: failed to increment module count\n"); continue; } + comedi_report_boards(driv); + module_put(driv->module); } - /* initialize dev->driver here so - * comedi_error() can be called from attach */ - dev->driver = driv; - ret = driv->attach(dev, it); - if (ret < 0) { - module_put(dev->driver->module); - __comedi_device_detach(dev); - return ret; - } - goto attached; + return -EIO; } - - /* recognize has failed if we get here */ - /* report valid board names before returning error */ - for (driv = comedi_drivers; driv; driv = driv->next) { - if (!try_module_get(driv->module)) { - printk(KERN_INFO - "comedi: failed to increment module count\n"); - continue; - } - comedi_report_boards(driv); - module_put(driv->module); - } - return -EIO; - -attached: - /* do a little post-config cleanup */ - ret = postconfig(dev); - module_put(dev->driver->module); + /* initialize dev->driver here so + * comedi_error() can be called from attach */ + dev->driver = driv; + ret = driv->attach(dev, it); if (ret < 0) { + module_put(dev->driver->module); __comedi_device_detach(dev); return ret; } - - if (!dev->board_name) { - printk(KERN_WARNING "BUG: dev->board_name=<%p>\n", - dev->board_name); - dev->board_name = "BUG"; - } - smp_wmb(); - dev->attached = 1; - - return 0; + return comedi_device_postconfig(dev); } int comedi_driver_register(struct comedi_driver *driver) @@ -242,6 +239,8 @@ static int postconfig(struct comedi_device *dev) s->len_chanlist = 1; if (s->do_cmd) { + unsigned int buf_size; + BUG_ON((s->subdev_flags & (SDF_CMD_READ | SDF_CMD_WRITE)) == 0); BUG_ON(!s->do_cmdtest); @@ -257,19 +256,20 @@ static int postconfig(struct comedi_device *dev) async->subdevice = s; s->async = async; -#define DEFAULT_BUF_MAXSIZE (64*1024) -#define DEFAULT_BUF_SIZE (64*1024) - - async->max_bufsize = DEFAULT_BUF_MAXSIZE; + async->max_bufsize = + comedi_default_buf_maxsize_kb * 1024; + buf_size = comedi_default_buf_size_kb * 1024; + if (buf_size > async->max_bufsize) + buf_size = async->max_bufsize; async->prealloc_buf = NULL; async->prealloc_bufsz = 0; - if (comedi_buf_alloc(dev, s, DEFAULT_BUF_SIZE) < 0) { + if (comedi_buf_alloc(dev, s, buf_size) < 0) { printk(KERN_INFO "Buffer allocation failed\n"); return -ENOMEM; } if (s->buf_change) { - ret = s->buf_change(dev, s, DEFAULT_BUF_SIZE); + ret = s->buf_change(dev, s, buf_size); if (ret < 0) return ret; } @@ -814,67 +814,102 @@ void comedi_reset_async_buf(struct comedi_async *async) async->events = 0; } -static int comedi_auto_config(struct device *hardware_device, - const char *board_name, const int *options, - unsigned num_options) +static int +comedi_auto_config_helper(struct device *hardware_device, + struct comedi_driver *driver, + int (*attach_wrapper) (struct comedi_device *, + void *), void *context) { - struct comedi_devconfig it; int minor; struct comedi_device_file_info *dev_file_info; - int retval; - unsigned *private_data = NULL; + struct comedi_device *comedi_dev; + int ret; - if (!comedi_autoconfig) { - dev_set_drvdata(hardware_device, NULL); + if (!comedi_autoconfig) return 0; - } minor = comedi_alloc_board_minor(hardware_device); if (minor < 0) return minor; - private_data = kmalloc(sizeof(unsigned), GFP_KERNEL); - if (private_data == NULL) { - retval = -ENOMEM; - goto cleanup; + dev_file_info = comedi_get_device_file_info(minor); + comedi_dev = dev_file_info->device; + + mutex_lock(&comedi_dev->mutex); + if (comedi_dev->attached) + ret = -EBUSY; + else if (!try_module_get(driver->module)) { + printk(KERN_INFO "comedi: failed to increment module count\n"); + ret = -EIO; + } else { + /* set comedi_dev->driver here for attach wrapper */ + comedi_dev->driver = driver; + ret = (*attach_wrapper)(comedi_dev, context); + if (ret < 0) { + module_put(driver->module); + __comedi_device_detach(comedi_dev); + } else { + ret = comedi_device_postconfig(comedi_dev); + } } - *private_data = minor; - dev_set_drvdata(hardware_device, private_data); + mutex_unlock(&comedi_dev->mutex); - dev_file_info = comedi_get_device_file_info(minor); + if (ret < 0) + comedi_free_board_minor(minor); + return ret; +} + +static int comedi_auto_config_wrapper(struct comedi_device *dev, void *context) +{ + struct comedi_devconfig *it = context; + struct comedi_driver *driv = dev->driver; + + if (driv->num_names) { + /* look for generic board entry matching driver name, which + * has already been copied to it->board_name */ + dev->board_ptr = comedi_recognize(driv, it->board_name); + if (dev->board_ptr == NULL) { + printk(KERN_WARNING + "comedi: auto config failed to find board entry" + " '%s' for driver '%s'\n", it->board_name, + driv->driver_name); + comedi_report_boards(driv); + return -EINVAL; + } + } + return driv->attach(dev, it); +} + +static int comedi_auto_config(struct device *hardware_device, + struct comedi_driver *driver, const int *options, + unsigned num_options) +{ + struct comedi_devconfig it; memset(&it, 0, sizeof(it)); - strncpy(it.board_name, board_name, COMEDI_NAMELEN); + strncpy(it.board_name, driver->driver_name, COMEDI_NAMELEN); it.board_name[COMEDI_NAMELEN - 1] = '\0'; BUG_ON(num_options > COMEDI_NDEVCONFOPTS); memcpy(it.options, options, num_options * sizeof(int)); - - mutex_lock(&dev_file_info->device->mutex); - retval = comedi_device_attach(dev_file_info->device, &it); - mutex_unlock(&dev_file_info->device->mutex); - -cleanup: - if (retval < 0) { - kfree(private_data); - comedi_free_board_minor(minor); - } - return retval; + return comedi_auto_config_helper(hardware_device, driver, + comedi_auto_config_wrapper, &it); } static void comedi_auto_unconfig(struct device *hardware_device) { - unsigned *minor = (unsigned *)dev_get_drvdata(hardware_device); - if (minor == NULL) - return; - - BUG_ON(*minor >= COMEDI_NUM_BOARD_MINORS); + int minor; - comedi_free_board_minor(*minor); - dev_set_drvdata(hardware_device, NULL); - kfree(minor); + if (hardware_device == NULL) + return; + minor = comedi_find_board_minor(hardware_device); + if (minor < 0) + return; + BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS); + comedi_free_board_minor(minor); } -int comedi_pci_auto_config(struct pci_dev *pcidev, const char *board_name) +static int comedi_old_pci_auto_config(struct pci_dev *pcidev, + struct comedi_driver *driver) { int options[2]; @@ -883,9 +918,30 @@ int comedi_pci_auto_config(struct pci_dev *pcidev, const char *board_name) /* pci slot */ options[1] = PCI_SLOT(pcidev->devfn); - return comedi_auto_config(&pcidev->dev, board_name, + return comedi_auto_config(&pcidev->dev, driver, options, ARRAY_SIZE(options)); } + +static int comedi_pci_attach_wrapper(struct comedi_device *dev, void *pcidev) +{ + return dev->driver->attach_pci(dev, pcidev); +} + +static int comedi_new_pci_auto_config(struct pci_dev *pcidev, + struct comedi_driver *driver) +{ + return comedi_auto_config_helper(&pcidev->dev, driver, + comedi_pci_attach_wrapper, pcidev); +} + +int comedi_pci_auto_config(struct pci_dev *pcidev, struct comedi_driver *driver) +{ + + if (driver->attach_pci) + return comedi_new_pci_auto_config(pcidev, driver); + else + return comedi_old_pci_auto_config(pcidev, driver); +} EXPORT_SYMBOL_GPL(comedi_pci_auto_config); void comedi_pci_auto_unconfig(struct pci_dev *pcidev) @@ -894,16 +950,96 @@ void comedi_pci_auto_unconfig(struct pci_dev *pcidev) } EXPORT_SYMBOL_GPL(comedi_pci_auto_unconfig); -int comedi_usb_auto_config(struct usb_device *usbdev, const char *board_name) +int comedi_pci_driver_register(struct comedi_driver *comedi_driver, + struct pci_driver *pci_driver) +{ + int ret; + + ret = comedi_driver_register(comedi_driver); + if (ret < 0) + return ret; + + /* FIXME: Remove this test after auditing all comedi pci drivers */ + if (!pci_driver->name) + pci_driver->name = comedi_driver->driver_name; + + ret = pci_register_driver(pci_driver); + if (ret < 0) { + comedi_driver_unregister(comedi_driver); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(comedi_pci_driver_register); + +void comedi_pci_driver_unregister(struct comedi_driver *comedi_driver, + struct pci_driver *pci_driver) +{ + pci_unregister_driver(pci_driver); + comedi_driver_unregister(comedi_driver); +} +EXPORT_SYMBOL_GPL(comedi_pci_driver_unregister); + +static int comedi_old_usb_auto_config(struct usb_interface *intf, + struct comedi_driver *driver) +{ + return comedi_auto_config(&intf->dev, driver, NULL, 0); +} + +static int comedi_usb_attach_wrapper(struct comedi_device *dev, void *intf) +{ + return dev->driver->attach_usb(dev, intf); +} + +static int comedi_new_usb_auto_config(struct usb_interface *intf, + struct comedi_driver *driver) +{ + return comedi_auto_config_helper(&intf->dev, driver, + comedi_usb_attach_wrapper, intf); +} + +int comedi_usb_auto_config(struct usb_interface *intf, + struct comedi_driver *driver) { - BUG_ON(usbdev == NULL); - return comedi_auto_config(&usbdev->dev, board_name, NULL, 0); + BUG_ON(intf == NULL); + if (driver->attach_usb) + return comedi_new_usb_auto_config(intf, driver); + else + return comedi_old_usb_auto_config(intf, driver); } EXPORT_SYMBOL_GPL(comedi_usb_auto_config); -void comedi_usb_auto_unconfig(struct usb_device *usbdev) +void comedi_usb_auto_unconfig(struct usb_interface *intf) { - BUG_ON(usbdev == NULL); - comedi_auto_unconfig(&usbdev->dev); + BUG_ON(intf == NULL); + comedi_auto_unconfig(&intf->dev); } EXPORT_SYMBOL_GPL(comedi_usb_auto_unconfig); + +int comedi_usb_driver_register(struct comedi_driver *comedi_driver, + struct usb_driver *usb_driver) +{ + int ret; + + ret = comedi_driver_register(comedi_driver); + if (ret < 0) + return ret; + + ret = usb_register(usb_driver); + if (ret < 0) { + comedi_driver_unregister(comedi_driver); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(comedi_usb_driver_register); + +void comedi_usb_driver_unregister(struct comedi_driver *comedi_driver, + struct usb_driver *usb_driver) +{ + usb_deregister(usb_driver); + comedi_driver_unregister(comedi_driver); +} +EXPORT_SYMBOL_GPL(comedi_usb_driver_unregister); diff --git a/trunk/drivers/staging/comedi/drivers/8255.c b/trunk/drivers/staging/comedi/drivers/8255.c index 6c26ac887eee..27e39e4eb6b3 100644 --- a/trunk/drivers/staging/comedi/drivers/8255.c +++ b/trunk/drivers/staging/comedi/drivers/8255.c @@ -107,31 +107,6 @@ struct subdev_8255_struct { #define CALLBACK_FUNC (((struct subdev_8255_struct *)s->private)->cb_func) #define subdevpriv ((struct subdev_8255_struct *)s->private) -static int dev_8255_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int dev_8255_detach(struct comedi_device *dev); -static struct comedi_driver driver_8255 = { - .driver_name = "8255", - .module = THIS_MODULE, - .attach = dev_8255_attach, - .detach = dev_8255_detach, -}; - -static int __init driver_8255_init_module(void) -{ - return comedi_driver_register(&driver_8255); -} - -static void __exit driver_8255_cleanup_module(void) -{ - comedi_driver_unregister(&driver_8255); -} - -module_init(driver_8255_init_module); -module_exit(driver_8255_cleanup_module); - -static void do_config(struct comedi_device *dev, struct comedi_subdevice *s); - void subdev_8255_interrupt(struct comedi_device *dev, struct comedi_subdevice *s) { @@ -185,6 +160,23 @@ static int subdev_8255_insn(struct comedi_device *dev, return 2; } +static void do_config(struct comedi_device *dev, struct comedi_subdevice *s) +{ + int config; + + config = CR_CW; + /* 1 in io_bits indicates output, 1 in config indicates input */ + if (!(s->io_bits & 0x0000ff)) + config |= CR_A_IO; + if (!(s->io_bits & 0x00ff00)) + config |= CR_B_IO; + if (!(s->io_bits & 0x0f0000)) + config |= CR_C_LO_IO; + if (!(s->io_bits & 0xf00000)) + config |= CR_C_HI_IO; + CALLBACK_FUNC(1, _8255_CR, config, CALLBACK_ARG); +} + static int subdev_8255_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -222,23 +214,6 @@ static int subdev_8255_insn_config(struct comedi_device *dev, return 1; } -static void do_config(struct comedi_device *dev, struct comedi_subdevice *s) -{ - int config; - - config = CR_CW; - /* 1 in io_bits indicates output, 1 in config indicates input */ - if (!(s->io_bits & 0x0000ff)) - config |= CR_A_IO; - if (!(s->io_bits & 0x00ff00)) - config |= CR_B_IO; - if (!(s->io_bits & 0x0f0000)) - config |= CR_C_LO_IO; - if (!(s->io_bits & 0xf00000)) - config |= CR_C_HI_IO; - CALLBACK_FUNC(1, _8255_CR, config, CALLBACK_ARG); -} - static int subdev_8255_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) @@ -442,14 +417,12 @@ static int dev_8255_attach(struct comedi_device *dev, return 0; } -static int dev_8255_detach(struct comedi_device *dev) +static void dev_8255_detach(struct comedi_device *dev) { int i; unsigned long iobase; struct comedi_subdevice *s; - printk(KERN_INFO "comedi%d: 8255: remove\n", dev->minor); - for (i = 0; i < dev->n_subdevices; i++) { s = dev->subdevices + i; if (s->type != COMEDI_SUBD_UNUSED) { @@ -458,10 +431,16 @@ static int dev_8255_detach(struct comedi_device *dev) } subdev_8255_cleanup(dev, s); } - - return 0; } +static struct comedi_driver dev_8255_driver = { + .driver_name = "8255", + .module = THIS_MODULE, + .attach = dev_8255_attach, + .detach = dev_8255_detach, +}; +module_comedi_driver(dev_8255_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/acl7225b.c b/trunk/drivers/staging/comedi/drivers/acl7225b.c index 9def2250bb80..4e4fc418655f 100644 --- a/trunk/drivers/staging/comedi/drivers/acl7225b.c +++ b/trunk/drivers/staging/comedi/drivers/acl7225b.c @@ -22,46 +22,13 @@ Devices: [Adlink] ACL-7225b (acl7225b), [ICP] P16R16DIO (p16r16dio) #define ACL7225_DI_LO 2 /* Digital input low byte (DI0-DI7) */ #define ACL7225_DI_HI 3 /* Digital input high byte (DI8-DI15) */ -static int acl7225b_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int acl7225b_detach(struct comedi_device *dev); - struct boardtype { const char *name; /* driver name */ int io_range; /* len of I/O space */ }; -static const struct boardtype boardtypes[] = { - {"acl7225b", ACL7225_SIZE,}, - {"p16r16dio", P16R16DIO_SIZE,}, -}; - -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype)) #define this_board ((const struct boardtype *)dev->board_ptr) -static struct comedi_driver driver_acl7225b = { - .driver_name = "acl7225b", - .module = THIS_MODULE, - .attach = acl7225b_attach, - .detach = acl7225b_detach, - .board_name = &boardtypes[0].name, - .num_names = n_boardtypes, - .offset = sizeof(struct boardtype), -}; - -static int __init driver_acl7225b_init_module(void) -{ - return comedi_driver_register(&driver_acl7225b); -} - -static void __exit driver_acl7225b_cleanup_module(void) -{ - comedi_driver_unregister(&driver_acl7225b); -} - -module_init(driver_acl7225b_init_module); -module_exit(driver_acl7225b_cleanup_module); - static int acl7225b_do_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -152,16 +119,28 @@ static int acl7225b_attach(struct comedi_device *dev, return 0; } -static int acl7225b_detach(struct comedi_device *dev) +static void acl7225b_detach(struct comedi_device *dev) { - printk(KERN_INFO "comedi%d: acl7225b: remove\n", dev->minor); - if (dev->iobase) release_region(dev->iobase, this_board->io_range); - - return 0; } +static const struct boardtype boardtypes[] = { + { "acl7225b", ACL7225_SIZE, }, + { "p16r16dio", P16R16DIO_SIZE, }, +}; + +static struct comedi_driver acl7225b_driver = { + .driver_name = "acl7225b", + .module = THIS_MODULE, + .attach = acl7225b_attach, + .detach = acl7225b_detach, + .board_name = &boardtypes[0].name, + .num_names = ARRAY_SIZE(boardtypes), + .offset = sizeof(struct boardtype), +}; +module_comedi_driver(acl7225b_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/addi-data/addi_common.c b/trunk/drivers/staging/comedi/drivers/addi-data/addi_common.c index ca5bd9b8704a..44aaf8351ba3 100644 --- a/trunk/drivers/staging/comedi/drivers/addi-data/addi_common.c +++ b/trunk/drivers/staging/comedi/drivers/addi-data/addi_common.c @@ -224,2318 +224,1213 @@ MODULE_DEVICE_TABLE(pci, addi_apci_tbl); static const struct addi_board boardtypes[] = { #ifdef CONFIG_APCI_3120 - {"apci3120", - APCI3120_BOARD_VENDOR_ID, - 0x818D, - AMCC_OP_REG_SIZE, - APCI3120_ADDRESS_RANGE, - 8, - 0, - ADDIDATA_NO_EEPROM, - NULL, - 16, - 8, - 16, - 8, - 0xffff, - 0x3fff, - &range_apci3120_ai, - &range_apci3120_ao, - 4, - 4, - 0x0f, - 0, - NULL, - 1, - 1, - 1, - 10000, - 100000, - v_APCI3120_Interrupt, - i_APCI3120_Reset, - i_APCI3120_InsnConfigAnalogInput, - i_APCI3120_InsnReadAnalogInput, - NULL, - NULL, - i_APCI3120_CommandTestAnalogInput, - i_APCI3120_CommandAnalogInput, - i_APCI3120_StopCyclicAcquisition, - NULL, - i_APCI3120_InsnWriteAnalogOutput, - NULL, - NULL, - i_APCI3120_InsnReadDigitalInput, - NULL, - i_APCI3120_InsnBitsDigitalInput, - i_APCI3120_InsnConfigDigitalOutput, - i_APCI3120_InsnWriteDigitalOutput, - i_APCI3120_InsnBitsDigitalOutput, - NULL, - i_APCI3120_InsnConfigTimer, - i_APCI3120_InsnWriteTimer, - i_APCI3120_InsnReadTimer, - NULL, - NULL, - NULL, - NULL, - NULL}, + { + .pc_DriverName = "apci3120", + .i_VendorId = APCI3120_BOARD_VENDOR_ID, + .i_DeviceId = 0x818D, + .i_IorangeBase0 = AMCC_OP_REG_SIZE, + .i_IorangeBase1 = APCI3120_ADDRESS_RANGE, + .i_IorangeBase2 = 8, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .i_NbrAiChannel = 16, + .i_NbrAiChannelDiff = 8, + .i_AiChannelList = 16, + .i_NbrAoChannel = 8, + .i_AiMaxdata = 0xffff, + .i_AoMaxdata = 0x3fff, + .pr_AiRangelist = &range_apci3120_ai, + .pr_AoRangelist = &range_apci3120_ao, + .i_NbrDiChannel = 4, + .i_NbrDoChannel = 4, + .i_DoMaxdata = 0x0f, + .i_Dma = 1, + .i_Timer = 1, + .b_AvailableConvertUnit = 1, + .ui_MinAcquisitiontimeNs = 10000, + .ui_MinDelaytimeNs = 100000, + .interrupt = v_APCI3120_Interrupt, + .reset = i_APCI3120_Reset, + .ai_config = i_APCI3120_InsnConfigAnalogInput, + .ai_read = i_APCI3120_InsnReadAnalogInput, + .ai_cmdtest = i_APCI3120_CommandTestAnalogInput, + .ai_cmd = i_APCI3120_CommandAnalogInput, + .ai_cancel = i_APCI3120_StopCyclicAcquisition, + .ao_write = i_APCI3120_InsnWriteAnalogOutput, + .di_read = i_APCI3120_InsnReadDigitalInput, + .di_bits = i_APCI3120_InsnBitsDigitalInput, + .do_config = i_APCI3120_InsnConfigDigitalOutput, + .do_write = i_APCI3120_InsnWriteDigitalOutput, + .do_bits = i_APCI3120_InsnBitsDigitalOutput, + .timer_config = i_APCI3120_InsnConfigTimer, + .timer_write = i_APCI3120_InsnWriteTimer, + .timer_read = i_APCI3120_InsnReadTimer, + }, #endif #ifdef CONFIG_APCI_1032 - {"apci1032", - APCI1032_BOARD_VENDOR_ID, - 0x1003, - 4, - APCI1032_ADDRESS_RANGE, - 0, - 0, - ADDIDATA_EEPROM, - ADDIDATA_93C76, - 0, - 0, - 0, - 0, - 0, - 0, - NULL, - NULL, - 32, - 0, - 0, - 0, - NULL, - 0, - 0, - 0, - 0, - 0, - v_APCI1032_Interrupt, - i_APCI1032_Reset, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI1032_ConfigDigitalInput, - i_APCI1032_Read1DigitalInput, - NULL, - i_APCI1032_ReadMoreDigitalInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL}, + { + .pc_DriverName = "apci1032", + .i_VendorId = APCI1032_BOARD_VENDOR_ID, + .i_DeviceId = 0x1003, + .i_IorangeBase0 = 4, + .i_IorangeBase1 = APCI1032_ADDRESS_RANGE, + .i_PCIEeprom = ADDIDATA_EEPROM, + .pc_EepromChip = ADDIDATA_93C76, + .i_NbrDiChannel = 32, + .interrupt = v_APCI1032_Interrupt, + .reset = i_APCI1032_Reset, + .di_config = i_APCI1032_ConfigDigitalInput, + .di_read = i_APCI1032_Read1DigitalInput, + .di_bits = i_APCI1032_ReadMoreDigitalInput, + }, #endif #ifdef CONFIG_APCI_1516 - {"apci1516", - APCI1516_BOARD_VENDOR_ID, - 0x1001, - 128, - APCI1516_ADDRESS_RANGE, - 32, - 0, - ADDIDATA_EEPROM, - ADDIDATA_S5920, - 0, - 0, - 0, - 0, - 0, - 0, - NULL, - NULL, - 8, - 8, - 0, - 0, - NULL, - 0, - 1, - 0, - 0, - 0, - NULL, - i_APCI1516_Reset, - NULL, NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI1516_Read1DigitalInput, - NULL, - i_APCI1516_ReadMoreDigitalInput, - i_APCI1516_ConfigDigitalOutput, - i_APCI1516_WriteDigitalOutput, - i_APCI1516_ReadDigitalOutput, - NULL, - i_APCI1516_ConfigWatchdog, - i_APCI1516_StartStopWriteWatchdog, - i_APCI1516_ReadWatchdog, - NULL, - NULL, - NULL, - NULL, - NULL}, + { + .pc_DriverName = "apci1516", + .i_VendorId = APCI1516_BOARD_VENDOR_ID, + .i_DeviceId = 0x1001, + .i_IorangeBase0 = 128, + .i_IorangeBase1 = APCI1516_ADDRESS_RANGE, + .i_IorangeBase2 = 32, + .i_PCIEeprom = ADDIDATA_EEPROM, + .pc_EepromChip = ADDIDATA_S5920, + .i_NbrDiChannel = 8, + .i_NbrDoChannel = 8, + .i_Timer = 1, + .reset = i_APCI1516_Reset, + .di_read = i_APCI1516_Read1DigitalInput, + .di_bits = i_APCI1516_ReadMoreDigitalInput, + .do_config = i_APCI1516_ConfigDigitalOutput, + .do_write = i_APCI1516_WriteDigitalOutput, + .do_bits = i_APCI1516_ReadDigitalOutput, + .timer_config = i_APCI1516_ConfigWatchdog, + .timer_write = i_APCI1516_StartStopWriteWatchdog, + .timer_read = i_APCI1516_ReadWatchdog, + }, #endif #ifdef CONFIG_APCI_2016 - {"apci2016", - APCI2016_BOARD_VENDOR_ID, - 0x1002, - 128, - APCI2016_ADDRESS_RANGE, - 32, - 0, - ADDIDATA_EEPROM, - ADDIDATA_S5920, - 0, - 0, - 0, - 0, - 0, - 0, - NULL, - NULL, - 0, - 16, - 0, - 0, - NULL, - 0, - 1, - 0, - 0, - 0, - NULL, - i_APCI2016_Reset, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI2016_ConfigDigitalOutput, - i_APCI2016_WriteDigitalOutput, - i_APCI2016_BitsDigitalOutput, - NULL, - i_APCI2016_ConfigWatchdog, - i_APCI2016_StartStopWriteWatchdog, - i_APCI2016_ReadWatchdog, - NULL, - NULL, - NULL, - NULL, - NULL}, + { + .pc_DriverName = "apci2016", + .i_VendorId = APCI2016_BOARD_VENDOR_ID, + .i_DeviceId = 0x1002, + .i_IorangeBase0 = 128, + .i_IorangeBase1 = APCI2016_ADDRESS_RANGE, + .i_IorangeBase2 = 32, + .i_PCIEeprom = ADDIDATA_EEPROM, + .pc_EepromChip = ADDIDATA_S5920, + .i_NbrDoChannel = 16, + .i_Timer = 1, + .reset = i_APCI2016_Reset, + .do_config = i_APCI2016_ConfigDigitalOutput, + .do_write = i_APCI2016_WriteDigitalOutput, + .do_bits = i_APCI2016_BitsDigitalOutput, + .timer_config = i_APCI2016_ConfigWatchdog, + .timer_write = i_APCI2016_StartStopWriteWatchdog, + .timer_read = i_APCI2016_ReadWatchdog, + }, #endif #ifdef CONFIG_APCI_2032 - {"apci2032", - APCI2032_BOARD_VENDOR_ID, - 0x1004, - 4, - APCI2032_ADDRESS_RANGE, - 0, - 0, - ADDIDATA_EEPROM, - ADDIDATA_93C76, - 0, - 0, - 0, - 0, - 0, - 0, - NULL, - NULL, - 0, - 32, - 0xffffffff, - 0, - NULL, - 0, - 1, - 0, - 0, - 0, - v_APCI2032_Interrupt, - i_APCI2032_Reset, - NULL, NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI2032_ConfigDigitalOutput, - i_APCI2032_WriteDigitalOutput, - i_APCI2032_ReadDigitalOutput, - i_APCI2032_ReadInterruptStatus, - i_APCI2032_ConfigWatchdog, - i_APCI2032_StartStopWriteWatchdog, - i_APCI2032_ReadWatchdog, - NULL, - NULL, - NULL, - NULL, - NULL}, + { + .pc_DriverName = "apci2032", + .i_VendorId = APCI2032_BOARD_VENDOR_ID, + .i_DeviceId = 0x1004, + .i_IorangeBase0 = 4, + .i_IorangeBase1 = APCI2032_ADDRESS_RANGE, + .i_PCIEeprom = ADDIDATA_EEPROM, + .pc_EepromChip = ADDIDATA_93C76, + .i_NbrDoChannel = 32, + .i_DoMaxdata = 0xffffffff, + .i_Timer = 1, + .interrupt = v_APCI2032_Interrupt, + .reset = i_APCI2032_Reset, + .do_config = i_APCI2032_ConfigDigitalOutput, + .do_write = i_APCI2032_WriteDigitalOutput, + .do_bits = i_APCI2032_ReadDigitalOutput, + .do_read = i_APCI2032_ReadInterruptStatus, + .timer_config = i_APCI2032_ConfigWatchdog, + .timer_write = i_APCI2032_StartStopWriteWatchdog, + .timer_read = i_APCI2032_ReadWatchdog, + }, #endif #ifdef CONFIG_APCI_2200 - {"apci2200", - APCI2200_BOARD_VENDOR_ID, - 0x1005, - 4, - APCI2200_ADDRESS_RANGE, - 0, - 0, - ADDIDATA_EEPROM, - ADDIDATA_93C76, - 0, - 0, - 0, - 0, - 0, - 0, - NULL, - NULL, - 8, - 16, - 0, - 0, - NULL, - 0, - 1, - 0, - 0, - 0, - NULL, - i_APCI2200_Reset, - NULL, NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI2200_Read1DigitalInput, - NULL, - i_APCI2200_ReadMoreDigitalInput, - i_APCI2200_ConfigDigitalOutput, - i_APCI2200_WriteDigitalOutput, - i_APCI2200_ReadDigitalOutput, - NULL, - i_APCI2200_ConfigWatchdog, - i_APCI2200_StartStopWriteWatchdog, - i_APCI2200_ReadWatchdog, - NULL, - NULL, - NULL, - NULL, - NULL}, + { + .pc_DriverName = "apci2200", + .i_VendorId = APCI2200_BOARD_VENDOR_ID, + .i_DeviceId = 0x1005, + .i_IorangeBase0 = 4, + .i_IorangeBase1 = APCI2200_ADDRESS_RANGE, + .i_PCIEeprom = ADDIDATA_EEPROM, + .pc_EepromChip = ADDIDATA_93C76, + .i_NbrDiChannel = 8, + .i_NbrDoChannel = 16, + .i_Timer = 1, + .reset = i_APCI2200_Reset, + .di_read = i_APCI2200_Read1DigitalInput, + .di_bits = i_APCI2200_ReadMoreDigitalInput, + .do_config = i_APCI2200_ConfigDigitalOutput, + .do_write = i_APCI2200_WriteDigitalOutput, + .do_bits = i_APCI2200_ReadDigitalOutput, + .timer_config = i_APCI2200_ConfigWatchdog, + .timer_write = i_APCI2200_StartStopWriteWatchdog, + .timer_read = i_APCI2200_ReadWatchdog, + }, #endif #ifdef CONFIG_APCI_1564 - {"apci1564", - APCI1564_BOARD_VENDOR_ID, - 0x1006, - 128, - APCI1564_ADDRESS_RANGE, - 0, - 0, - ADDIDATA_EEPROM, - ADDIDATA_93C76, - 0, - 0, - 0, - 0, - 0, - 0, - NULL, - NULL, - 32, - 32, - 0xffffffff, - 0, - NULL, - 0, - 1, - 0, - 0, - 0, - v_APCI1564_Interrupt, - i_APCI1564_Reset, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI1564_ConfigDigitalInput, - i_APCI1564_Read1DigitalInput, - NULL, - i_APCI1564_ReadMoreDigitalInput, - i_APCI1564_ConfigDigitalOutput, - i_APCI1564_WriteDigitalOutput, - i_APCI1564_ReadDigitalOutput, - i_APCI1564_ReadInterruptStatus, - i_APCI1564_ConfigTimerCounterWatchdog, - i_APCI1564_StartStopWriteTimerCounterWatchdog, - i_APCI1564_ReadTimerCounterWatchdog, - NULL, - NULL, - NULL, - NULL, - NULL}, + { + .pc_DriverName = "apci1564", + .i_VendorId = APCI1564_BOARD_VENDOR_ID, + .i_DeviceId = 0x1006, + .i_IorangeBase0 = 128, + .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 = v_APCI1564_Interrupt, + .reset = i_APCI1564_Reset, + .di_config = i_APCI1564_ConfigDigitalInput, + .di_read = i_APCI1564_Read1DigitalInput, + .di_bits = i_APCI1564_ReadMoreDigitalInput, + .do_config = i_APCI1564_ConfigDigitalOutput, + .do_write = i_APCI1564_WriteDigitalOutput, + .do_bits = i_APCI1564_ReadDigitalOutput, + .do_read = i_APCI1564_ReadInterruptStatus, + .timer_config = i_APCI1564_ConfigTimerCounterWatchdog, + .timer_write = i_APCI1564_StartStopWriteTimerCounterWatchdog, + .timer_read = i_APCI1564_ReadTimerCounterWatchdog, + }, #endif #ifdef CONFIG_APCI_1500 - {"apci1500", - APCI1500_BOARD_VENDOR_ID, - 0x80fc, - 128, - APCI1500_ADDRESS_RANGE, - 4, - 0, - ADDIDATA_NO_EEPROM, - NULL, - 0, - 0, - 0, - 0, - 0, - 0, - NULL, - NULL, - 16, - 16, - 0xffff, - 0, - NULL, - 0, - 1, - 0, - 0, - 0, - v_APCI1500_Interrupt, - i_APCI1500_Reset, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI1500_ConfigDigitalInputEvent, - i_APCI1500_Initialisation, - i_APCI1500_StartStopInputEvent, - i_APCI1500_ReadMoreDigitalInput, - i_APCI1500_ConfigDigitalOutputErrorInterrupt, - i_APCI1500_WriteDigitalOutput, - i_APCI1500_ConfigureInterrupt, - NULL, - i_APCI1500_ConfigCounterTimerWatchdog, - i_APCI1500_StartStopTriggerTimerCounterWatchdog, - i_APCI1500_ReadInterruptMask, - i_APCI1500_ReadCounterTimerWatchdog, - NULL, - NULL, - NULL, - NULL}, + { + .pc_DriverName = "apci1500", + .i_VendorId = APCI1500_BOARD_VENDOR_ID, + .i_DeviceId = 0x80fc, + .i_IorangeBase0 = 128, + .i_IorangeBase1 = APCI1500_ADDRESS_RANGE, + .i_IorangeBase2 = 4, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .i_NbrDiChannel = 16, + .i_NbrDoChannel = 16, + .i_DoMaxdata = 0xffff, + .i_Timer = 1, + .interrupt = v_APCI1500_Interrupt, + .reset = i_APCI1500_Reset, + .di_config = i_APCI1500_ConfigDigitalInputEvent, + .di_read = i_APCI1500_Initialisation, + .di_write = i_APCI1500_StartStopInputEvent, + .di_bits = i_APCI1500_ReadMoreDigitalInput, + .do_config = i_APCI1500_ConfigDigitalOutputErrorInterrupt, + .do_write = i_APCI1500_WriteDigitalOutput, + .do_bits = i_APCI1500_ConfigureInterrupt, + .timer_config = i_APCI1500_ConfigCounterTimerWatchdog, + .timer_write = i_APCI1500_StartStopTriggerTimerCounterWatchdog, + .timer_read = i_APCI1500_ReadInterruptMask, + .timer_bits = i_APCI1500_ReadCounterTimerWatchdog, + }, #endif #ifdef CONFIG_APCI_3001 - {"apci3001", - APCI3120_BOARD_VENDOR_ID, - 0x828D, - AMCC_OP_REG_SIZE, - APCI3120_ADDRESS_RANGE, - 8, - 0, - ADDIDATA_NO_EEPROM, - NULL, - 16, - 8, - 16, - 0, - 0xfff, - 0, - &range_apci3120_ai, - NULL, - 4, - 4, - 0x0f, - 0, - NULL, - 1, - 1, - 1, - 10000, - 100000, - v_APCI3120_Interrupt, - i_APCI3120_Reset, - i_APCI3120_InsnConfigAnalogInput, - i_APCI3120_InsnReadAnalogInput, - NULL, - NULL, - i_APCI3120_CommandTestAnalogInput, - i_APCI3120_CommandAnalogInput, - i_APCI3120_StopCyclicAcquisition, - NULL, - NULL, - NULL, - NULL, - i_APCI3120_InsnReadDigitalInput, - NULL, - i_APCI3120_InsnBitsDigitalInput, - i_APCI3120_InsnConfigDigitalOutput, - i_APCI3120_InsnWriteDigitalOutput, - i_APCI3120_InsnBitsDigitalOutput, - NULL, - i_APCI3120_InsnConfigTimer, - i_APCI3120_InsnWriteTimer, - i_APCI3120_InsnReadTimer, - NULL, - NULL, - NULL, - NULL, - NULL}, + { + .pc_DriverName = "apci3001", + .i_VendorId = APCI3120_BOARD_VENDOR_ID, + .i_DeviceId = 0x828D, + .i_IorangeBase0 = AMCC_OP_REG_SIZE, + .i_IorangeBase1 = APCI3120_ADDRESS_RANGE, + .i_IorangeBase2 = 8, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .i_NbrAiChannel = 16, + .i_NbrAiChannelDiff = 8, + .i_AiChannelList = 16, + .i_AiMaxdata = 0xfff, + .pr_AiRangelist = &range_apci3120_ai, + .i_NbrDiChannel = 4, + .i_NbrDoChannel = 4, + .i_DoMaxdata = 0x0f, + .i_Dma = 1, + .i_Timer = 1, + .b_AvailableConvertUnit = 1, + .ui_MinAcquisitiontimeNs = 10000, + .ui_MinDelaytimeNs = 100000, + .interrupt = v_APCI3120_Interrupt, + .reset = i_APCI3120_Reset, + .ai_config = i_APCI3120_InsnConfigAnalogInput, + .ai_read = i_APCI3120_InsnReadAnalogInput, + .ai_cmdtest = i_APCI3120_CommandTestAnalogInput, + .ai_cmd = i_APCI3120_CommandAnalogInput, + .ai_cancel = i_APCI3120_StopCyclicAcquisition, + .di_read = i_APCI3120_InsnReadDigitalInput, + .di_bits = i_APCI3120_InsnBitsDigitalInput, + .do_config = i_APCI3120_InsnConfigDigitalOutput, + .do_write = i_APCI3120_InsnWriteDigitalOutput, + .do_bits = i_APCI3120_InsnBitsDigitalOutput, + .timer_config = i_APCI3120_InsnConfigTimer, + .timer_write = i_APCI3120_InsnWriteTimer, + .timer_read = i_APCI3120_InsnReadTimer, + }, #endif #ifdef CONFIG_APCI_3501 - {"apci3501", - APCI3501_BOARD_VENDOR_ID, - 0x3001, - 64, - APCI3501_ADDRESS_RANGE, - 0, - 0, - ADDIDATA_EEPROM, - ADDIDATA_S5933, - 0, - 0, - 0, - 8, - 0, - 16383, - NULL, - &range_apci3501_ao, - 2, - 2, - 0x3, - 0, - NULL, - 0, - 1, - 0, - 0, - 0, - v_APCI3501_Interrupt, - i_APCI3501_Reset, - NULL, NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3501_ConfigAnalogOutput, - i_APCI3501_WriteAnalogOutput, - NULL, - NULL, - NULL, - NULL, - i_APCI3501_ReadDigitalInput, - i_APCI3501_ConfigDigitalOutput, - i_APCI3501_WriteDigitalOutput, - i_APCI3501_ReadDigitalOutput, - NULL, - i_APCI3501_ConfigTimerCounterWatchdog, - i_APCI3501_StartStopWriteTimerCounterWatchdog, - i_APCI3501_ReadTimerCounterWatchdog, - NULL, - NULL, - NULL, - NULL, - NULL}, + { + .pc_DriverName = "apci3501", + .i_VendorId = APCI3501_BOARD_VENDOR_ID, + .i_DeviceId = 0x3001, + .i_IorangeBase0 = 64, + .i_IorangeBase1 = APCI3501_ADDRESS_RANGE, + .i_PCIEeprom = ADDIDATA_EEPROM, + .pc_EepromChip = ADDIDATA_S5933, + .i_AoMaxdata = 16383, + .pr_AoRangelist = &range_apci3501_ao, + .i_NbrDiChannel = 2, + .i_NbrDoChannel = 2, + .i_DoMaxdata = 0x3, + .i_Timer = 1, + .interrupt = v_APCI3501_Interrupt, + .reset = i_APCI3501_Reset, + .ao_config = i_APCI3501_ConfigAnalogOutput, + .ao_write = i_APCI3501_WriteAnalogOutput, + .di_bits = i_APCI3501_ReadDigitalInput, + .do_config = i_APCI3501_ConfigDigitalOutput, + .do_write = i_APCI3501_WriteDigitalOutput, + .do_bits = i_APCI3501_ReadDigitalOutput, + .timer_config = i_APCI3501_ConfigTimerCounterWatchdog, + .timer_write = i_APCI3501_StartStopWriteTimerCounterWatchdog, + .timer_read = i_APCI3501_ReadTimerCounterWatchdog, + }, #endif #ifdef CONFIG_APCI_035 - {"apci035", - APCI035_BOARD_VENDOR_ID, - 0x0300, - 127, - APCI035_ADDRESS_RANGE, - 0, - 0, - 1, - ADDIDATA_S5920, - 16, - 8, - 16, - 0, - 0xff, - 0, - &range_apci035_ai, - NULL, - 0, - 0, - 0, - 0, - NULL, - 0, - 1, - 0, - 10000, - 100000, - v_APCI035_Interrupt, - i_APCI035_Reset, - i_APCI035_ConfigAnalogInput, - i_APCI035_ReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI035_ConfigTimerWatchdog, - i_APCI035_StartStopWriteTimerWatchdog, - i_APCI035_ReadTimerWatchdog, - NULL, - NULL, - NULL, - NULL, - NULL}, + { + .pc_DriverName = "apci035", + .i_VendorId = APCI035_BOARD_VENDOR_ID, + .i_DeviceId = 0x0300, + .i_IorangeBase0 = 127, + .i_IorangeBase1 = APCI035_ADDRESS_RANGE, + .i_PCIEeprom = 1, + .pc_EepromChip = ADDIDATA_S5920, + .i_NbrAiChannel = 16, + .i_NbrAiChannelDiff = 8, + .i_AiChannelList = 16, + .i_AiMaxdata = 0xff, + .pr_AiRangelist = &range_apci035_ai, + .i_Timer = 1, + .ui_MinAcquisitiontimeNs = 10000, + .ui_MinDelaytimeNs = 100000, + .interrupt = v_APCI035_Interrupt, + .reset = i_APCI035_Reset, + .ai_config = i_APCI035_ConfigAnalogInput, + .ai_read = i_APCI035_ReadAnalogInput, + .timer_config = i_APCI035_ConfigTimerWatchdog, + .timer_write = i_APCI035_StartStopWriteTimerWatchdog, + .timer_read = i_APCI035_ReadTimerWatchdog, + }, #endif #ifdef CONFIG_APCI_3200 - {"apci3200", - APCI3200_BOARD_VENDOR_ID, - 0x3000, - 128, - 256, - 4, - 4, - ADDIDATA_EEPROM, - ADDIDATA_S5920, - 16, - 8, - 16, - 0, - 0x3ffff, - 0, - &range_apci3200_ai, - NULL, - 4, - 4, - 0, - 0, - NULL, - 0, - 0, - 0, - 10000, - 100000, - v_APCI3200_Interrupt, - i_APCI3200_Reset, - i_APCI3200_ConfigAnalogInput, - i_APCI3200_ReadAnalogInput, - i_APCI3200_InsnWriteReleaseAnalogInput, - i_APCI3200_InsnBits_AnalogInput_Test, - i_APCI3200_CommandTestAnalogInput, - i_APCI3200_CommandAnalogInput, - i_APCI3200_StopCyclicAcquisition, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3200_ReadDigitalInput, - i_APCI3200_ConfigDigitalOutput, - i_APCI3200_WriteDigitalOutput, - i_APCI3200_ReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL}, + { + .pc_DriverName = "apci3200", + .i_VendorId = APCI3200_BOARD_VENDOR_ID, + .i_DeviceId = 0x3000, + .i_IorangeBase0 = 128, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 4, + .i_IorangeBase3 = 4, + .i_PCIEeprom = ADDIDATA_EEPROM, + .pc_EepromChip = ADDIDATA_S5920, + .i_NbrAiChannel = 16, + .i_NbrAiChannelDiff = 8, + .i_AiChannelList = 16, + .i_AiMaxdata = 0x3ffff, + .pr_AiRangelist = &range_apci3200_ai, + .i_NbrDiChannel = 4, + .i_NbrDoChannel = 4, + .ui_MinAcquisitiontimeNs = 10000, + .ui_MinDelaytimeNs = 100000, + .interrupt = v_APCI3200_Interrupt, + .reset = i_APCI3200_Reset, + .ai_config = i_APCI3200_ConfigAnalogInput, + .ai_read = i_APCI3200_ReadAnalogInput, + .ai_write = i_APCI3200_InsnWriteReleaseAnalogInput, + .ai_bits = i_APCI3200_InsnBits_AnalogInput_Test, + .ai_cmdtest = i_APCI3200_CommandTestAnalogInput, + .ai_cmd = i_APCI3200_CommandAnalogInput, + .ai_cancel = i_APCI3200_StopCyclicAcquisition, + .di_bits = i_APCI3200_ReadDigitalInput, + .do_config = i_APCI3200_ConfigDigitalOutput, + .do_write = i_APCI3200_WriteDigitalOutput, + .do_bits = i_APCI3200_ReadDigitalOutput, + }, #endif #ifdef CONFIG_APCI_3300 /* Begin JK .20.10.2004 = APCI-3300 integration */ - {"apci3300", - APCI3200_BOARD_VENDOR_ID, - 0x3007, - 128, - 256, - 4, - 4, - ADDIDATA_EEPROM, - ADDIDATA_S5920, - 0, - 8, - 8, - 0, - 0x3ffff, - 0, - &range_apci3300_ai, - NULL, - 4, - 4, - 0, - 0, - NULL, - 0, - 0, - 0, - 10000, - 100000, - v_APCI3200_Interrupt, - i_APCI3200_Reset, - i_APCI3200_ConfigAnalogInput, - i_APCI3200_ReadAnalogInput, - i_APCI3200_InsnWriteReleaseAnalogInput, - i_APCI3200_InsnBits_AnalogInput_Test, - i_APCI3200_CommandTestAnalogInput, - i_APCI3200_CommandAnalogInput, - i_APCI3200_StopCyclicAcquisition, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3200_ReadDigitalInput, - i_APCI3200_ConfigDigitalOutput, - i_APCI3200_WriteDigitalOutput, - i_APCI3200_ReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL}, + { + .pc_DriverName = "apci3300", + .i_VendorId = APCI3200_BOARD_VENDOR_ID, + .i_DeviceId = 0x3007, + .i_IorangeBase0 = 128, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 4, + .i_IorangeBase3 = 4, + .i_PCIEeprom = ADDIDATA_EEPROM, + .pc_EepromChip = ADDIDATA_S5920, + .i_NbrAiChannelDiff = 8, + .i_AiChannelList = 8, + .i_AiMaxdata = 0x3ffff, + .pr_AiRangelist = &range_apci3300_ai, + .i_NbrDiChannel = 4, + .i_NbrDoChannel = 4, + .ui_MinAcquisitiontimeNs = 10000, + .ui_MinDelaytimeNs = 100000, + .interrupt = v_APCI3200_Interrupt, + .reset = i_APCI3200_Reset, + .ai_config = i_APCI3200_ConfigAnalogInput, + .ai_read = i_APCI3200_ReadAnalogInput, + .ai_write = i_APCI3200_InsnWriteReleaseAnalogInput, + .ai_bits = i_APCI3200_InsnBits_AnalogInput_Test, + .ai_cmdtest = i_APCI3200_CommandTestAnalogInput, + .ai_cmd = i_APCI3200_CommandAnalogInput, + .ai_cancel = i_APCI3200_StopCyclicAcquisition, + .di_bits = i_APCI3200_ReadDigitalInput, + .do_config = i_APCI3200_ConfigDigitalOutput, + .do_write = i_APCI3200_WriteDigitalOutput, + .do_bits = i_APCI3200_ReadDigitalOutput, + }, #endif #ifdef CONFIG_APCI_1710 - {"apci1710", APCI1710_BOARD_VENDOR_ID, APCI1710_BOARD_DEVICE_ID, - 128, - 8, - 256, - 0, - ADDIDATA_NO_EEPROM, - NULL, - 0, - 0, - 0, - 0, - 0, - 0, - NULL, - NULL, - 0, - 0, - 0, - 0, - NULL, - 0, - 0, - 0, - 0, - 0, - v_APCI1710_Interrupt, - i_APCI1710_Reset, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL}, + { + .pc_DriverName = "apci1710", + .i_VendorId = APCI1710_BOARD_VENDOR_ID, + .i_DeviceId = APCI1710_BOARD_DEVICE_ID, + .i_IorangeBase0 = 128, + .i_IorangeBase1 = 8, + .i_IorangeBase2 = 256, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .interrupt = v_APCI1710_Interrupt, + .reset = i_APCI1710_Reset, + }, #endif #ifdef CONFIG_APCI_16XX - {"apci1648", - PCI_VENDOR_ID_ADDIDATA, - 0x1009, - 128, - 0, - 0, - 0, - ADDIDATA_NO_EEPROM, - NULL, - 0, - 0, - 0, - 0, - 0, - 0, - NULL, - NULL, - 0, - 0, - 0, - 48, - &range_apci16xx_ttl, - 0, - 0, - 0, - 0, - 0, - NULL, - i_APCI16XX_Reset, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI16XX_InsnConfigInitTTLIO, - i_APCI16XX_InsnBitsReadTTLIO, - i_APCI16XX_InsnReadTTLIOAllPortValue, - i_APCI16XX_InsnBitsWriteTTLIO}, - - {"apci1696", - PCI_VENDOR_ID_ADDIDATA, - 0x100A, - 128, - 0, - 0, - 0, - ADDIDATA_NO_EEPROM, - NULL, - 0, - 0, - 0, - 0, - 0, - 0, - NULL, - NULL, - 0, - 0, - 0, - 96, - &range_apci16xx_ttl, - 0, - 0, - 0, - 0, - 0, - NULL, - i_APCI16XX_Reset, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI16XX_InsnConfigInitTTLIO, - i_APCI16XX_InsnBitsReadTTLIO, - i_APCI16XX_InsnReadTTLIOAllPortValue, - i_APCI16XX_InsnBitsWriteTTLIO}, + { + .pc_DriverName = "apci1648", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x1009, + .i_IorangeBase0 = 128, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .i_NbrTTLChannel = 48, + .pr_TTLRangelist = &range_apci16xx_ttl, + .reset = i_APCI16XX_Reset, + .ttl_config = i_APCI16XX_InsnConfigInitTTLIO, + .ttl_bits = i_APCI16XX_InsnBitsReadTTLIO, + .ttl_read = i_APCI16XX_InsnReadTTLIOAllPortValue, + .ttl_write = i_APCI16XX_InsnBitsWriteTTLIO, + }, { + .pc_DriverName = "apci1696", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x100A, + .i_IorangeBase0 = 128, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .i_NbrTTLChannel = 96, + .pr_TTLRangelist = &range_apci16xx_ttl, + .reset = i_APCI16XX_Reset, + .ttl_config = i_APCI16XX_InsnConfigInitTTLIO, + .ttl_bits = i_APCI16XX_InsnBitsReadTTLIO, + .ttl_read = i_APCI16XX_InsnReadTTLIOAllPortValue, + .ttl_write = i_APCI16XX_InsnBitsWriteTTLIO, + }, #endif #ifdef CONFIG_APCI_3XXX - {"apci3000-16", - PCI_VENDOR_ID_ADDIDATA, - 0x3010, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 16, - 8, - 16, - 0, - 4095, - 0, - &range_apci3XXX_ai, - NULL, - 0, - 0, - 0, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 10000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3000-8", - PCI_VENDOR_ID_ADDIDATA, - 0x300F, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 8, - 4, - 8, - 0, - 4095, - 0, - &range_apci3XXX_ai, - NULL, - 0, - 0, - 0, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 10000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3000-4", - PCI_VENDOR_ID_ADDIDATA, - 0x300E, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 4, - 2, - 4, - 0, - 4095, - 0, - &range_apci3XXX_ai, - NULL, - 0, - 0, - 0, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 10000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3006-16", - PCI_VENDOR_ID_ADDIDATA, - 0x3013, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 16, - 8, - 16, - 0, - 65535, - 0, - &range_apci3XXX_ai, - NULL, - 0, - 0, - 0, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 10000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3006-8", - PCI_VENDOR_ID_ADDIDATA, - 0x3014, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 8, - 4, - 8, - 0, - 65535, - 0, - &range_apci3XXX_ai, - NULL, - 0, - 0, - 0, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 10000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3006-4", - PCI_VENDOR_ID_ADDIDATA, - 0x3015, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 4, - 2, - 4, - 0, - 65535, - 0, - &range_apci3XXX_ai, - NULL, - 0, - 0, - 0, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 10000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3010-16", - PCI_VENDOR_ID_ADDIDATA, - 0x3016, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 16, - 8, - 16, - 0, - 4095, - 0, - &range_apci3XXX_ai, - NULL, - 4, - 4, - 1, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 5000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3010-8", - PCI_VENDOR_ID_ADDIDATA, - 0x3017, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 8, - 4, - 8, - 0, - 4095, - 0, - &range_apci3XXX_ai, - NULL, - 4, - 4, - 1, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 5000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3010-4", - PCI_VENDOR_ID_ADDIDATA, - 0x3018, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 4, - 2, - 4, - 0, - 4095, - 0, - &range_apci3XXX_ai, - NULL, - 4, - 4, - 1, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 5000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3016-16", - PCI_VENDOR_ID_ADDIDATA, - 0x3019, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 16, - 8, - 16, - 0, - 65535, - 0, - &range_apci3XXX_ai, - NULL, - 4, - 4, - 1, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 5000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3016-8", - PCI_VENDOR_ID_ADDIDATA, - 0x301A, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 8, - 4, - 8, - 0, - 65535, - 0, - &range_apci3XXX_ai, - NULL, - 4, - 4, - 1, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 5000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3016-4", - PCI_VENDOR_ID_ADDIDATA, - 0x301B, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 4, - 2, - 4, - 0, - 65535, - 0, - &range_apci3XXX_ai, - NULL, - 4, - 4, - 1, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 5000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3100-16-4", - PCI_VENDOR_ID_ADDIDATA, - 0x301C, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 16, - 8, - 16, - 4, - 4095, - 4095, - &range_apci3XXX_ai, - &range_apci3XXX_ao, - 0, - 0, - 0, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 10000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnWriteAnalogOutput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3100-8-4", - PCI_VENDOR_ID_ADDIDATA, - 0x301D, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 8, - 4, - 8, - 4, - 4095, - 4095, - &range_apci3XXX_ai, - &range_apci3XXX_ao, - 0, - 0, - 0, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 10000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnWriteAnalogOutput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3106-16-4", - PCI_VENDOR_ID_ADDIDATA, - 0x301E, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 16, - 8, - 16, - 4, - 65535, - 4095, - &range_apci3XXX_ai, - &range_apci3XXX_ao, - 0, - 0, - 0, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 10000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnWriteAnalogOutput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3106-8-4", - PCI_VENDOR_ID_ADDIDATA, - 0x301F, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 8, - 4, - 8, - 4, - 65535, - 4095, - &range_apci3XXX_ai, - &range_apci3XXX_ao, - 0, - 0, - 0, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 10000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnWriteAnalogOutput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3110-16-4", - PCI_VENDOR_ID_ADDIDATA, - 0x3020, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 16, - 8, - 16, - 4, - 4095, - 4095, - &range_apci3XXX_ai, - &range_apci3XXX_ao, - 4, - 4, - 1, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 5000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnWriteAnalogOutput, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3110-8-4", - PCI_VENDOR_ID_ADDIDATA, - 0x3021, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 8, - 4, - 8, - 4, - 4095, - 4095, - &range_apci3XXX_ai, - &range_apci3XXX_ao, - 4, - 4, - 1, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 5000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnWriteAnalogOutput, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3116-16-4", - PCI_VENDOR_ID_ADDIDATA, - 0x3022, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 16, - 8, - 16, - 4, - 65535, - 4095, - &range_apci3XXX_ai, - &range_apci3XXX_ao, - 4, - 4, - 1, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 5000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnWriteAnalogOutput, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3116-8-4", - PCI_VENDOR_ID_ADDIDATA, - 0x3023, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 8, - 4, - 8, - 4, - 65535, - 4095, - &range_apci3XXX_ai, - &range_apci3XXX_ao, - 4, - 4, - 1, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 5000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnWriteAnalogOutput, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3003", - PCI_VENDOR_ID_ADDIDATA, - 0x300B, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 0, - 4, - 4, - 0, - 65535, - 0, - &range_apci3XXX_ai, - NULL, - 4, - 4, - 1, - 0, - NULL, - 0, - 0, - 7, - 2500, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL}, - - {"apci3002-16", - PCI_VENDOR_ID_ADDIDATA, - 0x3002, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 0, - 16, - 16, - 0, - 65535, - 0, - &range_apci3XXX_ai, - NULL, - 4, - 4, - 1, - 0, - NULL, - 0, - 0, - 6, - 5000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL}, - - {"apci3002-8", - PCI_VENDOR_ID_ADDIDATA, - 0x3003, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 0, - 8, - 8, - 0, - 65535, - 0, - &range_apci3XXX_ai, - NULL, - 4, - 4, - 1, - 0, - NULL, - 0, - 0, - 6, - 5000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL}, - - {"apci3002-4", - PCI_VENDOR_ID_ADDIDATA, - 0x3004, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 0, - 4, - 4, - 0, - 65535, - 0, - &range_apci3XXX_ai, - NULL, - 4, - 4, - 1, - 0, - NULL, - 0, - 0, - 6, - 5000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL}, - - {"apci3500", - PCI_VENDOR_ID_ADDIDATA, - 0x3024, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 0, - 0, - 0, - 4, - 0, - 4095, - NULL, - &range_apci3XXX_ao, - 0, - 0, - 0, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 0, - 0, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnWriteAnalogOutput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, + { + .pc_DriverName = "apci3000-16", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x3010, + .i_IorangeBase0 = 256, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 256, + .i_IorangeBase3 = 256, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .pc_EepromChip = ADDIDATA_9054, + .i_NbrAiChannel = 16, + .i_NbrAiChannelDiff = 8, + .i_AiChannelList = 16, + .i_AiMaxdata = 4095, + .pr_AiRangelist = &range_apci3XXX_ai, + .i_NbrTTLChannel = 24, + .pr_TTLRangelist = &range_apci3XXX_ttl, + .b_AvailableConvertUnit = 6, + .ui_MinAcquisitiontimeNs = 10000, + .interrupt = v_APCI3XXX_Interrupt, + .reset = i_APCI3XXX_Reset, + .ai_config = i_APCI3XXX_InsnConfigAnalogInput, + .ai_read = i_APCI3XXX_InsnReadAnalogInput, + .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, + .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, + .ttl_read = i_APCI3XXX_InsnReadTTLIO, + .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + }, { + .pc_DriverName = "apci3000-8", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x300F, + .i_IorangeBase0 = 256, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 256, + .i_IorangeBase3 = 256, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .pc_EepromChip = ADDIDATA_9054, + .i_NbrAiChannel = 8, + .i_NbrAiChannelDiff = 4, + .i_AiChannelList = 8, + .i_AiMaxdata = 4095, + .pr_AiRangelist = &range_apci3XXX_ai, + .i_NbrTTLChannel = 24, + .pr_TTLRangelist = &range_apci3XXX_ttl, + .b_AvailableConvertUnit = 6, + .ui_MinAcquisitiontimeNs = 10000, + .interrupt = v_APCI3XXX_Interrupt, + .reset = i_APCI3XXX_Reset, + .ai_config = i_APCI3XXX_InsnConfigAnalogInput, + .ai_read = i_APCI3XXX_InsnReadAnalogInput, + .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, + .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, + .ttl_read = i_APCI3XXX_InsnReadTTLIO, + .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + }, { + .pc_DriverName = "apci3000-4", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x300E, + .i_IorangeBase0 = 256, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 256, + .i_IorangeBase3 = 256, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .pc_EepromChip = ADDIDATA_9054, + .i_NbrAiChannel = 4, + .i_NbrAiChannelDiff = 2, + .i_AiChannelList = 4, + .i_AiMaxdata = 4095, + .pr_AiRangelist = &range_apci3XXX_ai, + .i_NbrTTLChannel = 24, + .pr_TTLRangelist = &range_apci3XXX_ttl, + .b_AvailableConvertUnit = 6, + .ui_MinAcquisitiontimeNs = 10000, + .interrupt = v_APCI3XXX_Interrupt, + .reset = i_APCI3XXX_Reset, + .ai_config = i_APCI3XXX_InsnConfigAnalogInput, + .ai_read = i_APCI3XXX_InsnReadAnalogInput, + .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, + .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, + .ttl_read = i_APCI3XXX_InsnReadTTLIO, + .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + }, { + .pc_DriverName = "apci3006-16", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x3013, + .i_IorangeBase0 = 256, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 256, + .i_IorangeBase3 = 256, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .pc_EepromChip = ADDIDATA_9054, + .i_NbrAiChannel = 16, + .i_NbrAiChannelDiff = 8, + .i_AiChannelList = 16, + .i_AiMaxdata = 65535, + .pr_AiRangelist = &range_apci3XXX_ai, + .i_NbrTTLChannel = 24, + .pr_TTLRangelist = &range_apci3XXX_ttl, + .b_AvailableConvertUnit = 6, + .ui_MinAcquisitiontimeNs = 10000, + .interrupt = v_APCI3XXX_Interrupt, + .reset = i_APCI3XXX_Reset, + .ai_config = i_APCI3XXX_InsnConfigAnalogInput, + .ai_read = i_APCI3XXX_InsnReadAnalogInput, + .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, + .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, + .ttl_read = i_APCI3XXX_InsnReadTTLIO, + .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + }, { + .pc_DriverName = "apci3006-8", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x3014, + .i_IorangeBase0 = 256, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 256, + .i_IorangeBase3 = 256, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .pc_EepromChip = ADDIDATA_9054, + .i_NbrAiChannel = 8, + .i_NbrAiChannelDiff = 4, + .i_AiChannelList = 8, + .i_AiMaxdata = 65535, + .pr_AiRangelist = &range_apci3XXX_ai, + .i_NbrTTLChannel = 24, + .pr_TTLRangelist = &range_apci3XXX_ttl, + .b_AvailableConvertUnit = 6, + .ui_MinAcquisitiontimeNs = 10000, + .interrupt = v_APCI3XXX_Interrupt, + .reset = i_APCI3XXX_Reset, + .ai_config = i_APCI3XXX_InsnConfigAnalogInput, + .ai_read = i_APCI3XXX_InsnReadAnalogInput, + .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, + .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, + .ttl_read = i_APCI3XXX_InsnReadTTLIO, + .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + }, { + .pc_DriverName = "apci3006-4", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x3015, + .i_IorangeBase0 = 256, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 256, + .i_IorangeBase3 = 256, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .pc_EepromChip = ADDIDATA_9054, + .i_NbrAiChannel = 4, + .i_NbrAiChannelDiff = 2, + .i_AiChannelList = 4, + .i_AiMaxdata = 65535, + .pr_AiRangelist = &range_apci3XXX_ai, + .i_NbrTTLChannel = 24, + .pr_TTLRangelist = &range_apci3XXX_ttl, + .b_AvailableConvertUnit = 6, + .ui_MinAcquisitiontimeNs = 10000, + .interrupt = v_APCI3XXX_Interrupt, + .reset = i_APCI3XXX_Reset, + .ai_config = i_APCI3XXX_InsnConfigAnalogInput, + .ai_read = i_APCI3XXX_InsnReadAnalogInput, + .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, + .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, + .ttl_read = i_APCI3XXX_InsnReadTTLIO, + .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + }, { + .pc_DriverName = "apci3010-16", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x3016, + .i_IorangeBase0 = 256, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 256, + .i_IorangeBase3 = 256, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .pc_EepromChip = ADDIDATA_9054, + .i_NbrAiChannel = 16, + .i_NbrAiChannelDiff = 8, + .i_AiChannelList = 16, + .i_AiMaxdata = 4095, + .pr_AiRangelist = &range_apci3XXX_ai, + .i_NbrDiChannel = 4, + .i_NbrDoChannel = 4, + .i_DoMaxdata = 1, + .i_NbrTTLChannel = 24, + .pr_TTLRangelist = &range_apci3XXX_ttl, + .b_AvailableConvertUnit = 6, + .ui_MinAcquisitiontimeNs = 5000, + .interrupt = v_APCI3XXX_Interrupt, + .reset = i_APCI3XXX_Reset, + .ai_config = i_APCI3XXX_InsnConfigAnalogInput, + .ai_read = i_APCI3XXX_InsnReadAnalogInput, + .di_read = i_APCI3XXX_InsnReadDigitalInput, + .di_bits = i_APCI3XXX_InsnBitsDigitalInput, + .do_write = i_APCI3XXX_InsnWriteDigitalOutput, + .do_bits = i_APCI3XXX_InsnBitsDigitalOutput, + .do_read = i_APCI3XXX_InsnReadDigitalOutput, + .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, + .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, + .ttl_read = i_APCI3XXX_InsnReadTTLIO, + .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + }, { + .pc_DriverName = "apci3010-8", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x3017, + .i_IorangeBase0 = 256, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 256, + .i_IorangeBase3 = 256, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .pc_EepromChip = ADDIDATA_9054, + .i_NbrAiChannel = 8, + .i_NbrAiChannelDiff = 4, + .i_AiChannelList = 8, + .i_AiMaxdata = 4095, + .pr_AiRangelist = &range_apci3XXX_ai, + .i_NbrDiChannel = 4, + .i_NbrDoChannel = 4, + .i_DoMaxdata = 1, + .i_NbrTTLChannel = 24, + .pr_TTLRangelist = &range_apci3XXX_ttl, + .b_AvailableConvertUnit = 6, + .ui_MinAcquisitiontimeNs = 5000, + .interrupt = v_APCI3XXX_Interrupt, + .reset = i_APCI3XXX_Reset, + .ai_config = i_APCI3XXX_InsnConfigAnalogInput, + .ai_read = i_APCI3XXX_InsnReadAnalogInput, + .di_read = i_APCI3XXX_InsnReadDigitalInput, + .di_bits = i_APCI3XXX_InsnBitsDigitalInput, + .do_write = i_APCI3XXX_InsnWriteDigitalOutput, + .do_bits = i_APCI3XXX_InsnBitsDigitalOutput, + .do_read = i_APCI3XXX_InsnReadDigitalOutput, + .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, + .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, + .ttl_read = i_APCI3XXX_InsnReadTTLIO, + .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + }, { + .pc_DriverName = "apci3010-4", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x3018, + .i_IorangeBase0 = 256, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 256, + .i_IorangeBase3 = 256, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .pc_EepromChip = ADDIDATA_9054, + .i_NbrAiChannel = 4, + .i_NbrAiChannelDiff = 2, + .i_AiChannelList = 4, + .i_AiMaxdata = 4095, + .pr_AiRangelist = &range_apci3XXX_ai, + .i_NbrDiChannel = 4, + .i_NbrDoChannel = 4, + .i_DoMaxdata = 1, + .i_NbrTTLChannel = 24, + .pr_TTLRangelist = &range_apci3XXX_ttl, + .b_AvailableConvertUnit = 6, + .ui_MinAcquisitiontimeNs = 5000, + .interrupt = v_APCI3XXX_Interrupt, + .reset = i_APCI3XXX_Reset, + .ai_config = i_APCI3XXX_InsnConfigAnalogInput, + .ai_read = i_APCI3XXX_InsnReadAnalogInput, + .di_read = i_APCI3XXX_InsnReadDigitalInput, + .di_bits = i_APCI3XXX_InsnBitsDigitalInput, + .do_write = i_APCI3XXX_InsnWriteDigitalOutput, + .do_bits = i_APCI3XXX_InsnBitsDigitalOutput, + .do_read = i_APCI3XXX_InsnReadDigitalOutput, + .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, + .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, + .ttl_read = i_APCI3XXX_InsnReadTTLIO, + .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + }, { + .pc_DriverName = "apci3016-16", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x3019, + .i_IorangeBase0 = 256, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 256, + .i_IorangeBase3 = 256, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .pc_EepromChip = ADDIDATA_9054, + .i_NbrAiChannel = 16, + .i_NbrAiChannelDiff = 8, + .i_AiChannelList = 16, + .i_AiMaxdata = 65535, + .pr_AiRangelist = &range_apci3XXX_ai, + .i_NbrDiChannel = 4, + .i_NbrDoChannel = 4, + .i_DoMaxdata = 1, + .i_NbrTTLChannel = 24, + .pr_TTLRangelist = &range_apci3XXX_ttl, + .b_AvailableConvertUnit = 6, + .ui_MinAcquisitiontimeNs = 5000, + .interrupt = v_APCI3XXX_Interrupt, + .reset = i_APCI3XXX_Reset, + .ai_config = i_APCI3XXX_InsnConfigAnalogInput, + .ai_read = i_APCI3XXX_InsnReadAnalogInput, + .di_read = i_APCI3XXX_InsnReadDigitalInput, + .di_bits = i_APCI3XXX_InsnBitsDigitalInput, + .do_write = i_APCI3XXX_InsnWriteDigitalOutput, + .do_bits = i_APCI3XXX_InsnBitsDigitalOutput, + .do_read = i_APCI3XXX_InsnReadDigitalOutput, + .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, + .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, + .ttl_read = i_APCI3XXX_InsnReadTTLIO, + .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + }, { + .pc_DriverName = "apci3016-8", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x301A, + .i_IorangeBase0 = 256, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 256, + .i_IorangeBase3 = 256, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .pc_EepromChip = ADDIDATA_9054, + .i_NbrAiChannel = 8, + .i_NbrAiChannelDiff = 4, + .i_AiChannelList = 8, + .i_AiMaxdata = 65535, + .pr_AiRangelist = &range_apci3XXX_ai, + .i_NbrDiChannel = 4, + .i_NbrDoChannel = 4, + .i_DoMaxdata = 1, + .i_NbrTTLChannel = 24, + .pr_TTLRangelist = &range_apci3XXX_ttl, + .b_AvailableConvertUnit = 6, + .ui_MinAcquisitiontimeNs = 5000, + .interrupt = v_APCI3XXX_Interrupt, + .reset = i_APCI3XXX_Reset, + .ai_config = i_APCI3XXX_InsnConfigAnalogInput, + .ai_read = i_APCI3XXX_InsnReadAnalogInput, + .di_read = i_APCI3XXX_InsnReadDigitalInput, + .di_bits = i_APCI3XXX_InsnBitsDigitalInput, + .do_write = i_APCI3XXX_InsnWriteDigitalOutput, + .do_bits = i_APCI3XXX_InsnBitsDigitalOutput, + .do_read = i_APCI3XXX_InsnReadDigitalOutput, + .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, + .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, + .ttl_read = i_APCI3XXX_InsnReadTTLIO, + .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + }, { + .pc_DriverName = "apci3016-4", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x301B, + .i_IorangeBase0 = 256, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 256, + .i_IorangeBase3 = 256, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .pc_EepromChip = ADDIDATA_9054, + .i_NbrAiChannel = 4, + .i_NbrAiChannelDiff = 2, + .i_AiChannelList = 4, + .i_AiMaxdata = 65535, + .pr_AiRangelist = &range_apci3XXX_ai, + .i_NbrDiChannel = 4, + .i_NbrDoChannel = 4, + .i_DoMaxdata = 1, + .i_NbrTTLChannel = 24, + .pr_TTLRangelist = &range_apci3XXX_ttl, + .b_AvailableConvertUnit = 6, + .ui_MinAcquisitiontimeNs = 5000, + .interrupt = v_APCI3XXX_Interrupt, + .reset = i_APCI3XXX_Reset, + .ai_config = i_APCI3XXX_InsnConfigAnalogInput, + .ai_read = i_APCI3XXX_InsnReadAnalogInput, + .di_read = i_APCI3XXX_InsnReadDigitalInput, + .di_bits = i_APCI3XXX_InsnBitsDigitalInput, + .do_write = i_APCI3XXX_InsnWriteDigitalOutput, + .do_bits = i_APCI3XXX_InsnBitsDigitalOutput, + .do_read = i_APCI3XXX_InsnReadDigitalOutput, + .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, + .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, + .ttl_read = i_APCI3XXX_InsnReadTTLIO, + .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + }, { + .pc_DriverName = "apci3100-16-4", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x301C, + .i_IorangeBase0 = 256, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 256, + .i_IorangeBase3 = 256, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .pc_EepromChip = ADDIDATA_9054, + .i_NbrAiChannel = 16, + .i_NbrAiChannelDiff = 8, + .i_AiChannelList = 16, + .i_NbrAoChannel = 4, + .i_AiMaxdata = 4095, + .i_AoMaxdata = 4095, + .pr_AiRangelist = &range_apci3XXX_ai, + .pr_AoRangelist = &range_apci3XXX_ao, + .i_NbrTTLChannel = 24, + .pr_TTLRangelist = &range_apci3XXX_ttl, + .b_AvailableConvertUnit = 6, + .ui_MinAcquisitiontimeNs = 10000, + .interrupt = v_APCI3XXX_Interrupt, + .reset = i_APCI3XXX_Reset, + .ai_config = i_APCI3XXX_InsnConfigAnalogInput, + .ai_read = i_APCI3XXX_InsnReadAnalogInput, + .ao_write = i_APCI3XXX_InsnWriteAnalogOutput, + .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, + .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, + .ttl_read = i_APCI3XXX_InsnReadTTLIO, + .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + }, { + .pc_DriverName = "apci3100-8-4", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x301D, + .i_IorangeBase0 = 256, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 256, + .i_IorangeBase3 = 256, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .pc_EepromChip = ADDIDATA_9054, + .i_NbrAiChannel = 8, + .i_NbrAiChannelDiff = 4, + .i_AiChannelList = 8, + .i_NbrAoChannel = 4, + .i_AiMaxdata = 4095, + .i_AoMaxdata = 4095, + .pr_AiRangelist = &range_apci3XXX_ai, + .pr_AoRangelist = &range_apci3XXX_ao, + .i_NbrTTLChannel = 24, + .pr_TTLRangelist = &range_apci3XXX_ttl, + .b_AvailableConvertUnit = 6, + .ui_MinAcquisitiontimeNs = 10000, + .interrupt = v_APCI3XXX_Interrupt, + .reset = i_APCI3XXX_Reset, + .ai_config = i_APCI3XXX_InsnConfigAnalogInput, + .ai_read = i_APCI3XXX_InsnReadAnalogInput, + .ao_write = i_APCI3XXX_InsnWriteAnalogOutput, + .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, + .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, + .ttl_read = i_APCI3XXX_InsnReadTTLIO, + .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + }, { + .pc_DriverName = "apci3106-16-4", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x301E, + .i_IorangeBase0 = 256, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 256, + .i_IorangeBase3 = 256, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .pc_EepromChip = ADDIDATA_9054, + .i_NbrAiChannel = 16, + .i_NbrAiChannelDiff = 8, + .i_AiChannelList = 16, + .i_NbrAoChannel = 4, + .i_AiMaxdata = 65535, + .i_AoMaxdata = 4095, + .pr_AiRangelist = &range_apci3XXX_ai, + .pr_AoRangelist = &range_apci3XXX_ao, + .i_NbrTTLChannel = 24, + .pr_TTLRangelist = &range_apci3XXX_ttl, + .b_AvailableConvertUnit = 6, + .ui_MinAcquisitiontimeNs = 10000, + .interrupt = v_APCI3XXX_Interrupt, + .reset = i_APCI3XXX_Reset, + .ai_config = i_APCI3XXX_InsnConfigAnalogInput, + .ai_read = i_APCI3XXX_InsnReadAnalogInput, + .ao_write = i_APCI3XXX_InsnWriteAnalogOutput, + .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, + .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, + .ttl_read = i_APCI3XXX_InsnReadTTLIO, + .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + }, { + .pc_DriverName = "apci3106-8-4", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x301F, + .i_IorangeBase0 = 256, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 256, + .i_IorangeBase3 = 256, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .pc_EepromChip = ADDIDATA_9054, + .i_NbrAiChannel = 8, + .i_NbrAiChannelDiff = 4, + .i_AiChannelList = 8, + .i_NbrAoChannel = 4, + .i_AiMaxdata = 65535, + .i_AoMaxdata = 4095, + .pr_AiRangelist = &range_apci3XXX_ai, + .pr_AoRangelist = &range_apci3XXX_ao, + .i_NbrTTLChannel = 24, + .pr_TTLRangelist = &range_apci3XXX_ttl, + .b_AvailableConvertUnit = 6, + .ui_MinAcquisitiontimeNs = 10000, + .interrupt = v_APCI3XXX_Interrupt, + .reset = i_APCI3XXX_Reset, + .ai_config = i_APCI3XXX_InsnConfigAnalogInput, + .ai_read = i_APCI3XXX_InsnReadAnalogInput, + .ao_write = i_APCI3XXX_InsnWriteAnalogOutput, + .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, + .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, + .ttl_read = i_APCI3XXX_InsnReadTTLIO, + .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + }, { + .pc_DriverName = "apci3110-16-4", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x3020, + .i_IorangeBase0 = 256, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 256, + .i_IorangeBase3 = 256, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .pc_EepromChip = ADDIDATA_9054, + .i_NbrAiChannel = 16, + .i_NbrAiChannelDiff = 8, + .i_AiChannelList = 16, + .i_NbrAoChannel = 4, + .i_AiMaxdata = 4095, + .i_AoMaxdata = 4095, + .pr_AiRangelist = &range_apci3XXX_ai, + .pr_AoRangelist = &range_apci3XXX_ao, + .i_NbrDiChannel = 4, + .i_NbrDoChannel = 4, + .i_DoMaxdata = 1, + .i_NbrTTLChannel = 24, + .pr_TTLRangelist = &range_apci3XXX_ttl, + .b_AvailableConvertUnit = 6, + .ui_MinAcquisitiontimeNs = 5000, + .interrupt = v_APCI3XXX_Interrupt, + .reset = i_APCI3XXX_Reset, + .ai_config = i_APCI3XXX_InsnConfigAnalogInput, + .ai_read = i_APCI3XXX_InsnReadAnalogInput, + .ao_write = i_APCI3XXX_InsnWriteAnalogOutput, + .di_read = i_APCI3XXX_InsnReadDigitalInput, + .di_bits = i_APCI3XXX_InsnBitsDigitalInput, + .do_write = i_APCI3XXX_InsnWriteDigitalOutput, + .do_bits = i_APCI3XXX_InsnBitsDigitalOutput, + .do_read = i_APCI3XXX_InsnReadDigitalOutput, + .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, + .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, + .ttl_read = i_APCI3XXX_InsnReadTTLIO, + .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + }, { + .pc_DriverName = "apci3110-8-4", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x3021, + .i_IorangeBase0 = 256, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 256, + .i_IorangeBase3 = 256, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .pc_EepromChip = ADDIDATA_9054, + .i_NbrAiChannel = 8, + .i_NbrAiChannelDiff = 4, + .i_AiChannelList = 8, + .i_NbrAoChannel = 4, + .i_AiMaxdata = 4095, + .i_AoMaxdata = 4095, + .pr_AiRangelist = &range_apci3XXX_ai, + .pr_AoRangelist = &range_apci3XXX_ao, + .i_NbrDiChannel = 4, + .i_NbrDoChannel = 4, + .i_DoMaxdata = 1, + .i_NbrTTLChannel = 24, + .pr_TTLRangelist = &range_apci3XXX_ttl, + .b_AvailableConvertUnit = 6, + .ui_MinAcquisitiontimeNs = 5000, + .interrupt = v_APCI3XXX_Interrupt, + .reset = i_APCI3XXX_Reset, + .ai_config = i_APCI3XXX_InsnConfigAnalogInput, + .ai_read = i_APCI3XXX_InsnReadAnalogInput, + .ao_write = i_APCI3XXX_InsnWriteAnalogOutput, + .di_read = i_APCI3XXX_InsnReadDigitalInput, + .di_bits = i_APCI3XXX_InsnBitsDigitalInput, + .do_write = i_APCI3XXX_InsnWriteDigitalOutput, + .do_bits = i_APCI3XXX_InsnBitsDigitalOutput, + .do_read = i_APCI3XXX_InsnReadDigitalOutput, + .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, + .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, + .ttl_read = i_APCI3XXX_InsnReadTTLIO, + .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + }, { + .pc_DriverName = "apci3116-16-4", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x3022, + .i_IorangeBase0 = 256, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 256, + .i_IorangeBase3 = 256, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .pc_EepromChip = ADDIDATA_9054, + .i_NbrAiChannel = 16, + .i_NbrAiChannelDiff = 8, + .i_AiChannelList = 16, + .i_NbrAoChannel = 4, + .i_AiMaxdata = 65535, + .i_AoMaxdata = 4095, + .pr_AiRangelist = &range_apci3XXX_ai, + .pr_AoRangelist = &range_apci3XXX_ao, + .i_NbrDiChannel = 4, + .i_NbrDoChannel = 4, + .i_DoMaxdata = 1, + .i_NbrTTLChannel = 24, + .pr_TTLRangelist = &range_apci3XXX_ttl, + .b_AvailableConvertUnit = 6, + .ui_MinAcquisitiontimeNs = 5000, + .interrupt = v_APCI3XXX_Interrupt, + .reset = i_APCI3XXX_Reset, + .ai_config = i_APCI3XXX_InsnConfigAnalogInput, + .ai_read = i_APCI3XXX_InsnReadAnalogInput, + .ao_write = i_APCI3XXX_InsnWriteAnalogOutput, + .di_read = i_APCI3XXX_InsnReadDigitalInput, + .di_bits = i_APCI3XXX_InsnBitsDigitalInput, + .do_write = i_APCI3XXX_InsnWriteDigitalOutput, + .do_bits = i_APCI3XXX_InsnBitsDigitalOutput, + .do_read = i_APCI3XXX_InsnReadDigitalOutput, + .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, + .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, + .ttl_read = i_APCI3XXX_InsnReadTTLIO, + .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + }, { + .pc_DriverName = "apci3116-8-4", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x3023, + .i_IorangeBase0 = 256, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 256, + .i_IorangeBase3 = 256, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .pc_EepromChip = ADDIDATA_9054, + .i_NbrAiChannel = 8, + .i_NbrAiChannelDiff = 4, + .i_AiChannelList = 8, + .i_NbrAoChannel = 4, + .i_AiMaxdata = 65535, + .i_AoMaxdata = 4095, + .pr_AiRangelist = &range_apci3XXX_ai, + .pr_AoRangelist = &range_apci3XXX_ao, + .i_NbrDiChannel = 4, + .i_NbrDoChannel = 4, + .i_DoMaxdata = 1, + .i_NbrTTLChannel = 24, + .pr_TTLRangelist = &range_apci3XXX_ttl, + .b_AvailableConvertUnit = 6, + .ui_MinAcquisitiontimeNs = 5000, + .interrupt = v_APCI3XXX_Interrupt, + .reset = i_APCI3XXX_Reset, + .ai_config = i_APCI3XXX_InsnConfigAnalogInput, + .ai_read = i_APCI3XXX_InsnReadAnalogInput, + .ao_write = i_APCI3XXX_InsnWriteAnalogOutput, + .di_read = i_APCI3XXX_InsnReadDigitalInput, + .di_bits = i_APCI3XXX_InsnBitsDigitalInput, + .do_write = i_APCI3XXX_InsnWriteDigitalOutput, + .do_bits = i_APCI3XXX_InsnBitsDigitalOutput, + .do_read = i_APCI3XXX_InsnReadDigitalOutput, + .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, + .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, + .ttl_read = i_APCI3XXX_InsnReadTTLIO, + .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + }, { + .pc_DriverName = "apci3003", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x300B, + .i_IorangeBase0 = 256, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 256, + .i_IorangeBase3 = 256, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .pc_EepromChip = ADDIDATA_9054, + .i_NbrAiChannelDiff = 4, + .i_AiChannelList = 4, + .i_AiMaxdata = 65535, + .pr_AiRangelist = &range_apci3XXX_ai, + .i_NbrDiChannel = 4, + .i_NbrDoChannel = 4, + .i_DoMaxdata = 1, + .b_AvailableConvertUnit = 7, + .ui_MinAcquisitiontimeNs = 2500, + .interrupt = v_APCI3XXX_Interrupt, + .reset = i_APCI3XXX_Reset, + .ai_config = i_APCI3XXX_InsnConfigAnalogInput, + .ai_read = i_APCI3XXX_InsnReadAnalogInput, + .di_read = i_APCI3XXX_InsnReadDigitalInput, + .di_bits = i_APCI3XXX_InsnBitsDigitalInput, + .do_write = i_APCI3XXX_InsnWriteDigitalOutput, + .do_bits = i_APCI3XXX_InsnBitsDigitalOutput, + .do_read = i_APCI3XXX_InsnReadDigitalOutput, + }, { + .pc_DriverName = "apci3002-16", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x3002, + .i_IorangeBase0 = 256, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 256, + .i_IorangeBase3 = 256, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .pc_EepromChip = ADDIDATA_9054, + .i_NbrAiChannelDiff = 16, + .i_AiChannelList = 16, + .i_AiMaxdata = 65535, + .pr_AiRangelist = &range_apci3XXX_ai, + .i_NbrDiChannel = 4, + .i_NbrDoChannel = 4, + .i_DoMaxdata = 1, + .b_AvailableConvertUnit = 6, + .ui_MinAcquisitiontimeNs = 5000, + .interrupt = v_APCI3XXX_Interrupt, + .reset = i_APCI3XXX_Reset, + .ai_config = i_APCI3XXX_InsnConfigAnalogInput, + .ai_read = i_APCI3XXX_InsnReadAnalogInput, + .di_read = i_APCI3XXX_InsnReadDigitalInput, + .di_bits = i_APCI3XXX_InsnBitsDigitalInput, + .do_write = i_APCI3XXX_InsnWriteDigitalOutput, + .do_bits = i_APCI3XXX_InsnBitsDigitalOutput, + .do_read = i_APCI3XXX_InsnReadDigitalOutput, + }, { + .pc_DriverName = "apci3002-8", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x3003, + .i_IorangeBase0 = 256, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 256, + .i_IorangeBase3 = 256, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .pc_EepromChip = ADDIDATA_9054, + .i_NbrAiChannelDiff = 8, + .i_AiChannelList = 8, + .i_AiMaxdata = 65535, + .pr_AiRangelist = &range_apci3XXX_ai, + .i_NbrDiChannel = 4, + .i_NbrDoChannel = 4, + .i_DoMaxdata = 1, + .b_AvailableConvertUnit = 6, + .ui_MinAcquisitiontimeNs = 5000, + .interrupt = v_APCI3XXX_Interrupt, + .reset = i_APCI3XXX_Reset, + .ai_config = i_APCI3XXX_InsnConfigAnalogInput, + .ai_read = i_APCI3XXX_InsnReadAnalogInput, + .di_read = i_APCI3XXX_InsnReadDigitalInput, + .di_bits = i_APCI3XXX_InsnBitsDigitalInput, + .do_write = i_APCI3XXX_InsnWriteDigitalOutput, + .do_bits = i_APCI3XXX_InsnBitsDigitalOutput, + .do_read = i_APCI3XXX_InsnReadDigitalOutput, + }, { + .pc_DriverName = "apci3002-4", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x3004, + .i_IorangeBase0 = 256, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 256, + .i_IorangeBase3 = 256, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .pc_EepromChip = ADDIDATA_9054, + .i_NbrAiChannelDiff = 4, + .i_AiChannelList = 4, + .i_AiMaxdata = 65535, + .pr_AiRangelist = &range_apci3XXX_ai, + .i_NbrDiChannel = 4, + .i_NbrDoChannel = 4, + .i_DoMaxdata = 1, + .b_AvailableConvertUnit = 6, + .ui_MinAcquisitiontimeNs = 5000, + .interrupt = v_APCI3XXX_Interrupt, + .reset = i_APCI3XXX_Reset, + .ai_config = i_APCI3XXX_InsnConfigAnalogInput, + .ai_read = i_APCI3XXX_InsnReadAnalogInput, + .di_read = i_APCI3XXX_InsnReadDigitalInput, + .di_bits = i_APCI3XXX_InsnBitsDigitalInput, + .do_write = i_APCI3XXX_InsnWriteDigitalOutput, + .do_bits = i_APCI3XXX_InsnBitsDigitalOutput, + .do_read = i_APCI3XXX_InsnReadDigitalOutput, + }, { + .pc_DriverName = "apci3500", + .i_VendorId = PCI_VENDOR_ID_ADDIDATA, + .i_DeviceId = 0x3024, + .i_IorangeBase0 = 256, + .i_IorangeBase1 = 256, + .i_IorangeBase2 = 256, + .i_IorangeBase3 = 256, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .pc_EepromChip = ADDIDATA_9054, + .i_NbrAoChannel = 4, + .i_AoMaxdata = 4095, + .pr_AoRangelist = &range_apci3XXX_ao, + .i_NbrTTLChannel = 24, + .pr_TTLRangelist = &range_apci3XXX_ttl, + .interrupt = v_APCI3XXX_Interrupt, + .reset = i_APCI3XXX_Reset, + .ao_write = i_APCI3XXX_InsnWriteAnalogOutput, + .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO, + .ttl_bits = i_APCI3XXX_InsnBitsTTLIO, + .ttl_read = i_APCI3XXX_InsnReadTTLIO, + .ttl_write = i_APCI3XXX_InsnWriteTTLIO, + }, #endif }; -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct addi_board)) - static struct comedi_driver driver_addi = { .driver_name = ADDIDATA_DRIVER_NAME, .module = THIS_MODULE, .attach = i_ADDI_Attach, .detach = i_ADDI_Detach, - .num_names = n_boardtypes, + .num_names = ARRAY_SIZE(boardtypes), .board_name = &boardtypes[0].pc_DriverName, .offset = sizeof(struct addi_board), }; @@ -2543,7 +1438,7 @@ static struct comedi_driver driver_addi = { static int __devinit driver_addi_pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, driver_addi.driver_name); + return comedi_pci_auto_config(dev, &driver_addi); } static void __devexit driver_addi_pci_remove(struct pci_dev *dev) @@ -2821,16 +1716,13 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it) /* Set the initialisation flag */ devpriv->b_AiInitialisation = 1; - s->insn_config = - this_board->i_hwdrv_InsnConfigAnalogInput; - s->insn_read = this_board->i_hwdrv_InsnReadAnalogInput; - s->insn_write = - this_board->i_hwdrv_InsnWriteAnalogInput; - s->insn_bits = this_board->i_hwdrv_InsnBitsAnalogInput; - s->do_cmdtest = - this_board->i_hwdrv_CommandTestAnalogInput; - s->do_cmd = this_board->i_hwdrv_CommandAnalogInput; - s->cancel = this_board->i_hwdrv_CancelAnalogInput; + s->insn_config = this_board->ai_config; + s->insn_read = this_board->ai_read; + s->insn_write = this_board->ai_write; + s->insn_bits = this_board->ai_bits; + s->do_cmdtest = this_board->ai_cmdtest; + s->do_cmd = this_board->ai_cmd; + s->cancel = this_board->ai_cancel; } else { s->type = COMEDI_SUBD_UNUSED; @@ -2846,10 +1738,8 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it) s->len_chanlist = devpriv->s_EeParameters.i_NbrAoChannel; s->range_table = this_board->pr_AoRangelist; - s->insn_config = - this_board->i_hwdrv_InsnConfigAnalogOutput; - s->insn_write = - this_board->i_hwdrv_InsnWriteAnalogOutput; + s->insn_config = this_board->ao_config; + s->insn_write = this_board->ao_write; } else { s->type = COMEDI_SUBD_UNUSED; } @@ -2864,12 +1754,10 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it) devpriv->s_EeParameters.i_NbrDiChannel; s->range_table = &range_digital; s->io_bits = 0; /* all bits input */ - s->insn_config = - this_board->i_hwdrv_InsnConfigDigitalInput; - s->insn_read = this_board->i_hwdrv_InsnReadDigitalInput; - s->insn_write = - this_board->i_hwdrv_InsnWriteDigitalInput; - s->insn_bits = this_board->i_hwdrv_InsnBitsDigitalInput; + s->insn_config = this_board->di_config; + s->insn_read = this_board->di_read; + s->insn_write = this_board->di_write; + s->insn_bits = this_board->di_bits; } else { s->type = COMEDI_SUBD_UNUSED; } @@ -2886,13 +1774,11 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it) s->range_table = &range_digital; s->io_bits = 0xf; /* all bits output */ - s->insn_config = this_board->i_hwdrv_InsnConfigDigitalOutput; /* for digital output memory.. */ - s->insn_write = - this_board->i_hwdrv_InsnWriteDigitalOutput; - s->insn_bits = - this_board->i_hwdrv_InsnBitsDigitalOutput; - s->insn_read = - this_board->i_hwdrv_InsnReadDigitalOutput; + /* 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; } @@ -2907,10 +1793,10 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it) s->len_chanlist = 1; s->range_table = &range_digital; - s->insn_write = this_board->i_hwdrv_InsnWriteTimer; - s->insn_read = this_board->i_hwdrv_InsnReadTimer; - s->insn_config = this_board->i_hwdrv_InsnConfigTimer; - s->insn_bits = this_board->i_hwdrv_InsnBitsTimer; + 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; } @@ -2926,10 +1812,10 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it) s->io_bits = 0; /* all bits input */ s->len_chanlist = this_board->i_NbrTTLChannel; s->range_table = &range_digital; - s->insn_config = this_board->i_hwdr_ConfigInitTTLIO; - s->insn_bits = this_board->i_hwdr_ReadTTLIOBits; - s->insn_read = this_board->i_hwdr_ReadTTLIOAllPortValue; - s->insn_write = this_board->i_hwdr_WriteTTLIOChlOnOff; + s->insn_config = this_board->ttl_config; + s->insn_bits = this_board->ttl_bits; + s->insn_read = this_board->ttl_read; + s->insn_write = this_board->ttl_write; } else { s->type = COMEDI_SUBD_UNUSED; } @@ -2953,50 +1839,22 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -/* -+----------------------------------------------------------------------------+ -| Function name : static int i_ADDI_Detach(struct comedi_device *dev) | -| | -| | -+----------------------------------------------------------------------------+ -| Task : Deallocates resources of the addi_common driver | -| Free the DMA buffers, unregister irq. | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev | -| | -| | -+----------------------------------------------------------------------------+ -| Return Value : 0 | -| | -+----------------------------------------------------------------------------+ -*/ - -static int i_ADDI_Detach(struct comedi_device *dev) +static void i_ADDI_Detach(struct comedi_device *dev) { - if (dev->private) { - if (devpriv->b_ValidDriver) { + if (devpriv->b_ValidDriver) i_ADDI_Reset(dev); - } - - if (dev->irq) { + if (dev->irq) free_irq(dev->irq, dev); - } - - if ((this_board->pc_EepromChip == NULL) - || (strcmp(this_board->pc_EepromChip, - ADDIDATA_9054) != 0)) { - if (devpriv->allocated) { + if ((this_board->pc_EepromChip == NULL) || + (strcmp(this_board->pc_EepromChip, ADDIDATA_9054) != 0)) { + if (devpriv->allocated) i_pci_card_free(devpriv->amcc); - } - if (devpriv->ul_DmaBufferVirtual[0]) { free_pages((unsigned long)devpriv-> ul_DmaBufferVirtual[0], devpriv->ui_DmaBufferPages[0]); } - if (devpriv->ul_DmaBufferVirtual[1]) { free_pages((unsigned long)devpriv-> ul_DmaBufferVirtual[1], @@ -3004,20 +1862,14 @@ static int i_ADDI_Detach(struct comedi_device *dev) } } else { iounmap(devpriv->dw_AiBase); - - if (devpriv->allocated) { + if (devpriv->allocated) i_pci_card_free(devpriv->amcc); - } } - if (pci_list_builded) { - /* v_pci_card_list_cleanup(PCI_VENDOR_ID_AMCC); */ v_pci_card_list_cleanup(this_board->i_VendorId); pci_list_builded = 0; } } - - return 0; } /* @@ -3041,7 +1893,7 @@ static int i_ADDI_Detach(struct comedi_device *dev) static int i_ADDI_Reset(struct comedi_device *dev) { - this_board->i_hwdrv_Reset(dev); + this_board->reset(dev); return 0; } @@ -3067,7 +1919,7 @@ static int i_ADDI_Reset(struct comedi_device *dev) static irqreturn_t v_ADDI_Interrupt(int irq, void *d) { struct comedi_device *dev = d; - this_board->v_hwdrv_Interrupt(irq, d); + this_board->interrupt(irq, d); return IRQ_RETVAL(1); } diff --git a/trunk/drivers/staging/comedi/drivers/addi-data/addi_common.h b/trunk/drivers/staging/comedi/drivers/addi-data/addi_common.h index c6980b7dfea0..2c3f34703dd2 100644 --- a/trunk/drivers/staging/comedi/drivers/addi-data/addi_common.h +++ b/trunk/drivers/staging/comedi/drivers/addi-data/addi_common.h @@ -94,111 +94,72 @@ struct addi_board { unsigned int ui_MinDelaytimeNs; /* Minimum Delay in Nano secs */ /* interrupt and reset */ - void (*v_hwdrv_Interrupt)(int irq, void *d); - int (*i_hwdrv_Reset)(struct comedi_device *dev); + void (*interrupt)(int irq, void *d); + int (*reset)(struct comedi_device *); /* Subdevice functions */ /* ANALOG INPUT */ - int (*i_hwdrv_InsnConfigAnalogInput)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdrv_InsnReadAnalogInput)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdrv_InsnWriteAnalogInput)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdrv_InsnBitsAnalogInput)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdrv_CommandTestAnalogInput)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); - int (*i_hwdrv_CommandAnalogInput)(struct comedi_device *dev, - struct comedi_subdevice *s); - int (*i_hwdrv_CancelAnalogInput)(struct comedi_device *dev, - struct comedi_subdevice *s); + int (*ai_config)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*ai_read)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*ai_write)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*ai_bits)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*ai_cmdtest)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_cmd *); + int (*ai_cmd)(struct comedi_device *, struct comedi_subdevice *); + int (*ai_cancel)(struct comedi_device *, struct comedi_subdevice *); /* Analog Output */ - int (*i_hwdrv_InsnConfigAnalogOutput)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdrv_InsnWriteAnalogOutput)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdrv_InsnBitsAnalogOutput)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); + int (*ao_config)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*ao_write)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*ao_bits)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); /* Digital Input */ - int (*i_hwdrv_InsnConfigDigitalInput) (struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdrv_InsnReadDigitalInput) (struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdrv_InsnWriteDigitalInput) (struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdrv_InsnBitsDigitalInput) (struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); + int (*di_config)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*di_read)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*di_write)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*di_bits)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); /* Digital Output */ - int (*i_hwdrv_InsnConfigDigitalOutput)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdrv_InsnWriteDigitalOutput)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdrv_InsnBitsDigitalOutput)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdrv_InsnReadDigitalOutput)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); + int (*do_config)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*do_write)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*do_bits)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*do_read)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); /* TIMER */ - int (*i_hwdrv_InsnConfigTimer)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - int (*i_hwdrv_InsnWriteTimer)(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdrv_InsnReadTimer)(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - int (*i_hwdrv_InsnBitsTimer)(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); + int (*timer_config)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*timer_write)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*timer_read)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*timer_bits)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); /* TTL IO */ - int (*i_hwdr_ConfigInitTTLIO)(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdr_ReadTTLIOBits)(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - int (*i_hwdr_ReadTTLIOAllPortValue)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdr_WriteTTLIOChlOnOff)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); + int (*ttl_config)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*ttl_bits)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*ttl_read)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*ttl_write)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); }; /* MODULE INFO STRUCTURE */ @@ -455,7 +416,7 @@ static unsigned short pci_list_builded; /* set to 1 when list of card is known * /* Function declarations */ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int i_ADDI_Detach(struct comedi_device *dev); +static void i_ADDI_Detach(struct comedi_device *dev); static int i_ADDI_Reset(struct comedi_device *dev); static irqreturn_t v_ADDI_Interrupt(int irq, void *d); diff --git a/trunk/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c b/trunk/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c index e886ced4978f..ffe390c6da83 100644 --- a/trunk/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c +++ b/trunk/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c @@ -156,7 +156,7 @@ int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, struct comedi_subd } else us_ConvertTiming = (unsigned short) (devpriv->ui_EocEosConversionTime / 1000); /* nano to useconds */ - /* this_board->i_hwdrv_InsnReadAnalogInput(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]); */ + /* this_board->ai_read(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]); */ /* Clear software registers */ devpriv->b_TimerSelectMode = 0; @@ -670,7 +670,7 @@ int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, struct comedi_subde /* mode 1 */ devpriv->ui_AiTimer0 = cmd->convert_arg; /* timer constant in nano seconds */ - /* return this_board->i_hwdrv_CommandAnalogInput(1,dev,s); */ + /* return this_board->ai_cmd(1,dev,s); */ return i_APCI3120_CyclicAnalogInput(1, dev, s); } @@ -680,7 +680,7 @@ int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, struct comedi_subde /* mode 2 */ devpriv->ui_AiTimer1 = cmd->scan_begin_arg; devpriv->ui_AiTimer0 = cmd->convert_arg; /* variable changed timer2 to timer0 */ - /* return this_board->i_hwdrv_CommandAnalogInput(2,dev,s); */ + /* return this_board->ai_cmd(2,dev,s); */ return i_APCI3120_CyclicAnalogInput(2, dev, s); } return -1; @@ -1922,7 +1922,7 @@ int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, struct comedi_subdevic ui_Timervalue2 = data[1] / 1000; /* convert nano seconds to u seconds */ - /* this_board->i_hwdrv_InsnConfigTimer(dev, ui_Timervalue2,(unsigned char)data[0]); */ + /* this_board->timer_config(dev, ui_Timervalue2,(unsigned char)data[0]); */ us_TmpValue = (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS); /* @@ -2092,7 +2092,7 @@ int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, struct comedi_subdevice ui_Timervalue2 = 0; } - /* this_board->i_hwdrv_InsnWriteTimer(dev,data[0],ui_Timervalue2); */ + /* this_board->timer_write(dev,data[0],ui_Timervalue2); */ switch (data[0]) { case APCI3120_START: @@ -2260,7 +2260,7 @@ int i_APCI3120_InsnReadTimer(struct comedi_device *dev, struct comedi_subdevice comedi_error(dev, "\nread:timer2 not configured "); } - /* this_board->i_hwdrv_InsnReadTimer(dev,data); */ + /* this_board->timer_read(dev,data); */ if (devpriv->b_Timer2Mode == APCI3120_TIMER) { /* Read the LOW unsigned short of Timer 2 register */ @@ -2331,7 +2331,7 @@ int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev, ui_Chan = CR_CHAN(insn->chanspec); /* channel specified */ - /* this_board->i_hwdrv_InsnReadDigitalInput(dev,ui_Chan,data); */ + /* this_board->di_read(dev,ui_Chan,data); */ if (ui_Chan <= 3) { ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI3120_RD_STATUS); @@ -2379,7 +2379,7 @@ int i_APCI3120_InsnBitsDigitalInput(struct comedi_device *dev, struct comedi_sub *****/ *data = (ui_TmpValue >> 8) & 0xf; - /* this_board->i_hwdrv_InsnBitsDigitalInput(dev,data); */ + /* this_board->di_bits(dev,data); */ return insn->n; } @@ -2595,7 +2595,7 @@ int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev, ui_Range = CR_RANGE(insn->chanspec); ui_Channel = CR_CHAN(insn->chanspec); - /* this_board->i_hwdrv_InsnWriteAnalogOutput(dev, ui_Range, ui_Channel,data[0]); */ + /* this_board->ao_write(dev, ui_Range, ui_Channel,data[0]); */ if (ui_Range) { /* if 1 then unipolar */ if (data[0] != 0) diff --git a/trunk/drivers/staging/comedi/drivers/adl_pci6208.c b/trunk/drivers/staging/comedi/drivers/adl_pci6208.c index 4fc9e8520217..de8c68af3210 100644 --- a/trunk/drivers/staging/comedi/drivers/adl_pci6208.c +++ b/trunk/drivers/staging/comedi/drivers/adl_pci6208.c @@ -54,8 +54,6 @@ Configuration Options: #include "../comedidev.h" #include "comedi_pci.h" -#define PCI6208_DRIVER_NAME "adl_pci6208" - /* Board descriptions */ struct pci6208_board { const char *name; @@ -85,17 +83,6 @@ static const struct pci6208_board pci6208_boards[] = { } }; -/* This is used by modprobe to translate PCI IDs to drivers. Should - * only be used for PCI and ISA-PnP devices */ -static DEFINE_PCI_DEVICE_TABLE(pci6208_pci_table) = { - /* { PCI_VENDOR_ID_ADLINK, 0x6208, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, */ - /* { PCI_VENDOR_ID_ADLINK, 0x6208, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, */ - { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, 0x6208) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, pci6208_pci_table); - /* Will be initialized in pci6208_find device(). */ #define thisboard ((const struct pci6208_board *)dev->board_ptr) @@ -107,157 +94,6 @@ struct pci6208_private { #define devpriv ((struct pci6208_private *)dev->private) -static int pci6208_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pci6208_detach(struct comedi_device *dev); - -static struct comedi_driver driver_pci6208 = { - .driver_name = PCI6208_DRIVER_NAME, - .module = THIS_MODULE, - .attach = pci6208_attach, - .detach = pci6208_detach, -}; - -static int __devinit driver_pci6208_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, driver_pci6208.driver_name); -} - -static void __devexit driver_pci6208_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_pci6208_pci_driver = { - .id_table = pci6208_pci_table, - .probe = &driver_pci6208_pci_probe, - .remove = __devexit_p(&driver_pci6208_pci_remove) -}; - -static int __init driver_pci6208_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_pci6208); - if (retval < 0) - return retval; - - driver_pci6208_pci_driver.name = (char *)driver_pci6208.driver_name; - return pci_register_driver(&driver_pci6208_pci_driver); -} - -static void __exit driver_pci6208_cleanup_module(void) -{ - pci_unregister_driver(&driver_pci6208_pci_driver); - comedi_driver_unregister(&driver_pci6208); -} - -module_init(driver_pci6208_init_module); -module_exit(driver_pci6208_cleanup_module); - -static int pci6208_find_device(struct comedi_device *dev, int bus, int slot); -static int -pci6208_pci_setup(struct pci_dev *pci_dev, unsigned long *io_base_ptr, - int dev_minor); - -/*read/write functions*/ -static int pci6208_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int pci6208_ao_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -/* static int pci6208_dio_insn_bits (struct comedi_device *dev, - * struct comedi_subdevice *s, */ -/* struct comedi_insn *insn,unsigned int *data); */ -/* static int pci6208_dio_insn_config(struct comedi_device *dev, - * struct comedi_subdevice *s, */ -/* struct comedi_insn *insn,unsigned int *data); */ - -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ -static int pci6208_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - int retval; - unsigned long io_base; - - printk(KERN_INFO "comedi%d: pci6208: ", dev->minor); - - retval = alloc_private(dev, sizeof(struct pci6208_private)); - if (retval < 0) - return retval; - - retval = pci6208_find_device(dev, it->options[0], it->options[1]); - if (retval < 0) - return retval; - - retval = pci6208_pci_setup(devpriv->pci_dev, &io_base, dev->minor); - if (retval < 0) - return retval; - - dev->iobase = io_base; - dev->board_name = thisboard->name; - -/* - * Allocate the subdevice structures. alloc_subdevice() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_subdevices(dev, 2) < 0) - return -ENOMEM; - - s = dev->subdevices + 0; - /* analog output subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; /* anything else to add here?? */ - s->n_chan = thisboard->ao_chans; - s->maxdata = 0xffff; /* 16-bit DAC */ - s->range_table = &range_bipolar10; /* this needs to be checked. */ - s->insn_write = pci6208_ao_winsn; - s->insn_read = pci6208_ao_rinsn; - - /* s=dev->subdevices+1; */ - /* digital i/o subdevice */ - /* s->type=COMEDI_SUBD_DIO; */ - /* s->subdev_flags=SDF_READABLE|SDF_WRITABLE; */ - /* s->n_chan=16; */ - /* s->maxdata=1; */ - /* s->range_table=&range_digital; */ - /* s->insn_bits = pci6208_dio_insn_bits; */ - /* s->insn_config = pci6208_dio_insn_config; */ - - printk(KERN_INFO "attached\n"); - - return 1; -} - -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int pci6208_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: pci6208: remove\n", dev->minor); - - if (devpriv && devpriv->pci_dev) { - if (dev->iobase) - comedi_pci_disable(devpriv->pci_dev); - pci_dev_put(devpriv->pci_dev); - } - - return 0; -} - static int pci6208_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -410,7 +246,7 @@ pci6208_pci_setup(struct pci_dev *pci_dev, unsigned long *io_base_ptr, unsigned long io_base, io_range, lcr_io_base, lcr_io_range; /* Enable PCI device and request regions */ - if (comedi_pci_enable(pci_dev, PCI6208_DRIVER_NAME) < 0) { + if (comedi_pci_enable(pci_dev, "adl_pci6208") < 0) { printk(KERN_ERR "comedi%d: Failed to enable PCI device " "and request regions\n", dev_minor); @@ -442,6 +278,103 @@ pci6208_pci_setup(struct pci_dev *pci_dev, unsigned long *io_base_ptr, return 0; } +static int pci6208_attach(struct comedi_device *dev, + struct comedi_devconfig *it) +{ + struct comedi_subdevice *s; + int retval; + unsigned long io_base; + + printk(KERN_INFO "comedi%d: pci6208: ", dev->minor); + + retval = alloc_private(dev, sizeof(struct pci6208_private)); + if (retval < 0) + return retval; + + retval = pci6208_find_device(dev, it->options[0], it->options[1]); + if (retval < 0) + return retval; + + retval = pci6208_pci_setup(devpriv->pci_dev, &io_base, dev->minor); + if (retval < 0) + return retval; + + dev->iobase = io_base; + dev->board_name = thisboard->name; + + if (alloc_subdevices(dev, 2) < 0) + return -ENOMEM; + + s = dev->subdevices + 0; + /* analog output subdevice */ + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; /* anything else to add here?? */ + s->n_chan = thisboard->ao_chans; + s->maxdata = 0xffff; /* 16-bit DAC */ + s->range_table = &range_bipolar10; /* this needs to be checked. */ + s->insn_write = pci6208_ao_winsn; + s->insn_read = pci6208_ao_rinsn; + + /* s=dev->subdevices+1; */ + /* digital i/o subdevice */ + /* s->type=COMEDI_SUBD_DIO; */ + /* s->subdev_flags=SDF_READABLE|SDF_WRITABLE; */ + /* s->n_chan=16; */ + /* s->maxdata=1; */ + /* s->range_table=&range_digital; */ + /* s->insn_bits = pci6208_dio_insn_bits; */ + /* s->insn_config = pci6208_dio_insn_config; */ + + printk(KERN_INFO "attached\n"); + + return 1; +} + +static void pci6208_detach(struct comedi_device *dev) +{ + if (devpriv && devpriv->pci_dev) { + if (dev->iobase) + comedi_pci_disable(devpriv->pci_dev); + pci_dev_put(devpriv->pci_dev); + } +} + +static struct comedi_driver adl_pci6208_driver = { + .driver_name = "adl_pci6208", + .module = THIS_MODULE, + .attach = pci6208_attach, + .detach = pci6208_detach, +}; + +static int __devinit adl_pci6208_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + return comedi_pci_auto_config(dev, &adl_pci6208_driver); +} + +static void __devexit adl_pci6208_pci_remove(struct pci_dev *dev) +{ + comedi_pci_auto_unconfig(dev); +} + +/* This is used by modprobe to translate PCI IDs to drivers. Should + * only be used for PCI and ISA-PnP devices */ +static DEFINE_PCI_DEVICE_TABLE(adl_pci6208_pci_table) = { + /* { PCI_VENDOR_ID_ADLINK, 0x6208, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, */ + /* { PCI_VENDOR_ID_ADLINK, 0x6208, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, */ + { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, 0x6208) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, adl_pci6208_pci_table); + +static struct pci_driver adl_pci6208_pci_driver = { + .name = "adl_pci6208", + .id_table = adl_pci6208_pci_table, + .probe = adl_pci6208_pci_probe, + .remove = __devexit_p(adl_pci6208_pci_remove), +}; +module_comedi_pci_driver(adl_pci6208_driver, adl_pci6208_pci_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/adl_pci7230.c b/trunk/drivers/staging/comedi/drivers/adl_pci7230.c index 20d570554fa4..e8053bc825f4 100644 --- a/trunk/drivers/staging/comedi/drivers/adl_pci7230.c +++ b/trunk/drivers/staging/comedi/drivers/adl_pci7230.c @@ -43,13 +43,6 @@ Configuration Options: #define PCI_DEVICE_ID_PCI7230 0x7230 -static DEFINE_PCI_DEVICE_TABLE(adl_pci7230_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7230) }, - {0} -}; - -MODULE_DEVICE_TABLE(pci, adl_pci7230_pci_table); - struct adl_pci7230_private { int data; struct pci_dev *pci_dev; @@ -57,27 +50,36 @@ struct adl_pci7230_private { #define devpriv ((struct adl_pci7230_private *)dev->private) -static int adl_pci7230_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int adl_pci7230_detach(struct comedi_device *dev); -static struct comedi_driver driver_adl_pci7230 = { - .driver_name = "adl_pci7230", - .module = THIS_MODULE, - .attach = adl_pci7230_attach, - .detach = adl_pci7230_detach, -}; +static int adl_pci7230_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + if (insn->n != 2) + return -EINVAL; + + if (data[0]) { + s->state &= ~data[0]; + s->state |= (data[0] & data[1]); + + outl((s->state << 16) & 0xffffffff, dev->iobase + PCI7230_DO); + } -/* Digital IO */ + return 2; +} static int adl_pci7230_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); + unsigned int *data) +{ + if (insn->n != 2) + return -EINVAL; -static int adl_pci7230_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); + data[1] = inl(dev->iobase + PCI7230_DI) & 0xffffffff; + + return 2; +} static int adl_pci7230_attach(struct comedi_device *dev, struct comedi_devconfig *it) @@ -148,89 +150,46 @@ static int adl_pci7230_attach(struct comedi_device *dev, return 1; } -static int adl_pci7230_detach(struct comedi_device *dev) +static void adl_pci7230_detach(struct comedi_device *dev) { - printk(KERN_DEBUG "comedi%d: pci7230: remove\n", dev->minor); - if (devpriv && devpriv->pci_dev) { if (dev->iobase) comedi_pci_disable(devpriv->pci_dev); pci_dev_put(devpriv->pci_dev); } - - return 0; -} - -static int adl_pci7230_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - if (insn->n != 2) - return -EINVAL; - - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - - outl((s->state << 16) & 0xffffffff, dev->iobase + PCI7230_DO); - } - - return 2; } -static int adl_pci7230_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - if (insn->n != 2) - return -EINVAL; - - data[1] = inl(dev->iobase + PCI7230_DI) & 0xffffffff; - - return 2; -} +static struct comedi_driver adl_pci7230_driver = { + .driver_name = "adl_pci7230", + .module = THIS_MODULE, + .attach = adl_pci7230_attach, + .detach = adl_pci7230_detach, +}; -static int __devinit driver_adl_pci7230_pci_probe(struct pci_dev *dev, - const struct pci_device_id - *ent) +static int __devinit adl_pci7230_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, driver_adl_pci7230.driver_name); + return comedi_pci_auto_config(dev, &adl_pci7230_driver); } -static void __devexit driver_adl_pci7230_pci_remove(struct pci_dev *dev) +static void __devexit adl_pci7230_pci_remove(struct pci_dev *dev) { comedi_pci_auto_unconfig(dev); } -static struct pci_driver driver_adl_pci7230_pci_driver = { - .id_table = adl_pci7230_pci_table, - .probe = &driver_adl_pci7230_pci_probe, - .remove = __devexit_p(&driver_adl_pci7230_pci_remove) +static DEFINE_PCI_DEVICE_TABLE(adl_pci7230_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7230) }, + { 0 } }; +MODULE_DEVICE_TABLE(pci, adl_pci7230_pci_table); -static int __init driver_adl_pci7230_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_adl_pci7230); - if (retval < 0) - return retval; - - driver_adl_pci7230_pci_driver.name = - (char *)driver_adl_pci7230.driver_name; - return pci_register_driver(&driver_adl_pci7230_pci_driver); -} - -static void __exit driver_adl_pci7230_cleanup_module(void) -{ - pci_unregister_driver(&driver_adl_pci7230_pci_driver); - comedi_driver_unregister(&driver_adl_pci7230); -} - -module_init(driver_adl_pci7230_init_module); -module_exit(driver_adl_pci7230_cleanup_module); +static struct pci_driver adl_pci7230_pci_driver = { + .name = "adl_pci7230", + .id_table = adl_pci7230_pci_table, + .probe = adl_pci7230_pci_probe, + .remove = __devexit_p(adl_pci7230_pci_remove), +}; +module_comedi_pci_driver(adl_pci7230_driver, adl_pci7230_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/adl_pci7296.c b/trunk/drivers/staging/comedi/drivers/adl_pci7296.c index 9a2320537bdb..b4dae3b7598b 100644 --- a/trunk/drivers/staging/comedi/drivers/adl_pci7296.c +++ b/trunk/drivers/staging/comedi/drivers/adl_pci7296.c @@ -48,13 +48,6 @@ Configuration Options: #define PCI_DEVICE_ID_PCI7296 0x7296 -static DEFINE_PCI_DEVICE_TABLE(adl_pci7296_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7296) }, - {0} -}; - -MODULE_DEVICE_TABLE(pci, adl_pci7296_pci_table); - struct adl_pci7296_private { int data; struct pci_dev *pci_dev; @@ -62,16 +55,6 @@ struct adl_pci7296_private { #define devpriv ((struct adl_pci7296_private *)dev->private) -static int adl_pci7296_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int adl_pci7296_detach(struct comedi_device *dev); -static struct comedi_driver driver_adl_pci7296 = { - .driver_name = "adl_pci7296", - .module = THIS_MODULE, - .attach = adl_pci7296_attach, - .detach = adl_pci7296_detach, -}; - static int adl_pci7296_attach(struct comedi_device *dev, struct comedi_devconfig *it) { @@ -151,66 +134,52 @@ static int adl_pci7296_attach(struct comedi_device *dev, return -EIO; } -static int adl_pci7296_detach(struct comedi_device *dev) +static void adl_pci7296_detach(struct comedi_device *dev) { - printk(KERN_INFO "comedi%d: pci7432: remove\n", dev->minor); - if (devpriv && devpriv->pci_dev) { if (dev->iobase) comedi_pci_disable(devpriv->pci_dev); pci_dev_put(devpriv->pci_dev); } - /* detach four 8255 digital io subdevices */ if (dev->subdevices) { subdev_8255_cleanup(dev, dev->subdevices + 0); subdev_8255_cleanup(dev, dev->subdevices + 1); subdev_8255_cleanup(dev, dev->subdevices + 2); subdev_8255_cleanup(dev, dev->subdevices + 3); - } - - return 0; } -static int __devinit driver_adl_pci7296_pci_probe(struct pci_dev *dev, - const struct pci_device_id - *ent) +static struct comedi_driver adl_pci7296_driver = { + .driver_name = "adl_pci7296", + .module = THIS_MODULE, + .attach = adl_pci7296_attach, + .detach = adl_pci7296_detach, +}; + +static int __devinit adl_pci7296_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, driver_adl_pci7296.driver_name); + return comedi_pci_auto_config(dev, &adl_pci7296_driver); } -static void __devexit driver_adl_pci7296_pci_remove(struct pci_dev *dev) +static void __devexit adl_pci7296_pci_remove(struct pci_dev *dev) { comedi_pci_auto_unconfig(dev); } -static struct pci_driver driver_adl_pci7296_pci_driver = { - .id_table = adl_pci7296_pci_table, - .probe = &driver_adl_pci7296_pci_probe, - .remove = __devexit_p(&driver_adl_pci7296_pci_remove) +static DEFINE_PCI_DEVICE_TABLE(adl_pci7296_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7296) }, + { 0 } }; +MODULE_DEVICE_TABLE(pci, adl_pci7296_pci_table); -static int __init driver_adl_pci7296_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_adl_pci7296); - if (retval < 0) - return retval; - - driver_adl_pci7296_pci_driver.name = - (char *)driver_adl_pci7296.driver_name; - return pci_register_driver(&driver_adl_pci7296_pci_driver); -} - -static void __exit driver_adl_pci7296_cleanup_module(void) -{ - pci_unregister_driver(&driver_adl_pci7296_pci_driver); - comedi_driver_unregister(&driver_adl_pci7296); -} - -module_init(driver_adl_pci7296_init_module); -module_exit(driver_adl_pci7296_cleanup_module); +static struct pci_driver adl_pci7296_pci_driver = { + .name = "adl_pci7296", + .id_table = adl_pci7296_pci_table, + .probe = adl_pci7296_pci_probe, + .remove = __devexit_p(adl_pci7296_pci_remove), +}; +module_comedi_pci_driver(adl_pci7296_driver, adl_pci7296_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/adl_pci7432.c b/trunk/drivers/staging/comedi/drivers/adl_pci7432.c index 86ee21976041..9cbfb61a4478 100644 --- a/trunk/drivers/staging/comedi/drivers/adl_pci7432.c +++ b/trunk/drivers/staging/comedi/drivers/adl_pci7432.c @@ -43,13 +43,6 @@ Configuration Options: #define PCI_DEVICE_ID_PCI7432 0x7432 -static DEFINE_PCI_DEVICE_TABLE(adl_pci7432_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7432) }, - {0} -}; - -MODULE_DEVICE_TABLE(pci, adl_pci7432_pci_table); - struct adl_pci7432_private { int data; struct pci_dev *pci_dev; @@ -57,29 +50,44 @@ struct adl_pci7432_private { #define devpriv ((struct adl_pci7432_private *)dev->private) -static int adl_pci7432_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int adl_pci7432_detach(struct comedi_device *dev); -static struct comedi_driver driver_adl_pci7432 = { - .driver_name = "adl_pci7432", - .module = THIS_MODULE, - .attach = adl_pci7432_attach, - .detach = adl_pci7432_detach, -}; +static int adl_pci7432_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + printk(KERN_DEBUG "comedi: pci7432_do_insn_bits called\n"); + printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]); + + if (insn->n != 2) + return -EINVAL; -/* Digital IO */ + if (data[0]) { + s->state &= ~data[0]; + s->state |= (data[0] & data[1]); + + printk(KERN_DEBUG "comedi: out: %8x on iobase %4lx\n", s->state, + dev->iobase + PCI7432_DO); + outl(s->state & 0xffffffff, dev->iobase + PCI7432_DO); + } + return 2; +} static int adl_pci7432_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); + unsigned int *data) +{ + printk(KERN_DEBUG "comedi: pci7432_di_insn_bits called\n"); + printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]); -static int adl_pci7432_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); + if (insn->n != 2) + return -EINVAL; + + data[1] = inl(dev->iobase + PCI7432_DI) & 0xffffffff; + printk(KERN_DEBUG "comedi: data1 %8x\n", data[1]); -/* */ + return 2; +} static int adl_pci7432_attach(struct comedi_device *dev, struct comedi_devconfig *it) @@ -153,97 +161,46 @@ static int adl_pci7432_attach(struct comedi_device *dev, return -EIO; } -static int adl_pci7432_detach(struct comedi_device *dev) +static void adl_pci7432_detach(struct comedi_device *dev) { - printk(KERN_INFO "comedi%d: pci7432: remove\n", dev->minor); - if (devpriv && devpriv->pci_dev) { if (dev->iobase) comedi_pci_disable(devpriv->pci_dev); pci_dev_put(devpriv->pci_dev); } - - return 0; } -static int adl_pci7432_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - printk(KERN_DEBUG "comedi: pci7432_do_insn_bits called\n"); - printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]); - - if (insn->n != 2) - return -EINVAL; - - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - - printk(KERN_DEBUG "comedi: out: %8x on iobase %4lx\n", s->state, - dev->iobase + PCI7432_DO); - outl(s->state & 0xffffffff, dev->iobase + PCI7432_DO); - } - return 2; -} - -static int adl_pci7432_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - printk(KERN_DEBUG "comedi: pci7432_di_insn_bits called\n"); - printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]); - - if (insn->n != 2) - return -EINVAL; - - data[1] = inl(dev->iobase + PCI7432_DI) & 0xffffffff; - printk(KERN_DEBUG "comedi: data1 %8x\n", data[1]); - - return 2; -} +static struct comedi_driver adl_pci7432_driver = { + .driver_name = "adl_pci7432", + .module = THIS_MODULE, + .attach = adl_pci7432_attach, + .detach = adl_pci7432_detach, +}; -static int __devinit driver_adl_pci7432_pci_probe(struct pci_dev *dev, - const struct pci_device_id - *ent) +static int __devinit adl_pci7432_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, driver_adl_pci7432.driver_name); + return comedi_pci_auto_config(dev, &adl_pci7432_driver); } -static void __devexit driver_adl_pci7432_pci_remove(struct pci_dev *dev) +static void __devexit adl_pci7432_pci_remove(struct pci_dev *dev) { comedi_pci_auto_unconfig(dev); } -static struct pci_driver driver_adl_pci7432_pci_driver = { - .id_table = adl_pci7432_pci_table, - .probe = &driver_adl_pci7432_pci_probe, - .remove = __devexit_p(&driver_adl_pci7432_pci_remove) +static DEFINE_PCI_DEVICE_TABLE(adl_pci7432_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7432) }, + { 0 } }; +MODULE_DEVICE_TABLE(pci, adl_pci7432_pci_table); -static int __init driver_adl_pci7432_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_adl_pci7432); - if (retval < 0) - return retval; - - driver_adl_pci7432_pci_driver.name = - (char *)driver_adl_pci7432.driver_name; - return pci_register_driver(&driver_adl_pci7432_pci_driver); -} - -static void __exit driver_adl_pci7432_cleanup_module(void) -{ - pci_unregister_driver(&driver_adl_pci7432_pci_driver); - comedi_driver_unregister(&driver_adl_pci7432); -} - -module_init(driver_adl_pci7432_init_module); -module_exit(driver_adl_pci7432_cleanup_module); +static struct pci_driver adl_pci7432_pci_driver = { + .name = "adl_pci7432", + .id_table = adl_pci7432_pci_table, + .probe = adl_pci7432_pci_probe, + .remove = __devexit_p(adl_pci7432_pci_remove), +}; +module_comedi_pci_driver(adl_pci7432_driver, adl_pci7432_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/adl_pci8164.c b/trunk/drivers/staging/comedi/drivers/adl_pci8164.c index 3b83d65bc1bc..409ef13ad090 100644 --- a/trunk/drivers/staging/comedi/drivers/adl_pci8164.c +++ b/trunk/drivers/staging/comedi/drivers/adl_pci8164.c @@ -56,13 +56,6 @@ Configuration Options: #define PCI_DEVICE_ID_PCI8164 0x8164 -static DEFINE_PCI_DEVICE_TABLE(adl_pci8164_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI8164) }, - {0} -}; - -MODULE_DEVICE_TABLE(pci, adl_pci8164_pci_table); - struct adl_pci8164_private { int data; struct pci_dev *pci_dev; @@ -70,159 +63,6 @@ struct adl_pci8164_private { #define devpriv ((struct adl_pci8164_private *)dev->private) -static int adl_pci8164_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int adl_pci8164_detach(struct comedi_device *dev); -static struct comedi_driver driver_adl_pci8164 = { - .driver_name = "adl_pci8164", - .module = THIS_MODULE, - .attach = adl_pci8164_attach, - .detach = adl_pci8164_detach, -}; - -static int adl_pci8164_insn_read_msts(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -static int adl_pci8164_insn_read_ssts(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -static int adl_pci8164_insn_read_buf0(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -static int adl_pci8164_insn_read_buf1(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -static int adl_pci8164_insn_write_cmd(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -static int adl_pci8164_insn_write_otp(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -static int adl_pci8164_insn_write_buf0(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -static int adl_pci8164_insn_write_buf1(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -static int adl_pci8164_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct pci_dev *pcidev = NULL; - struct comedi_subdevice *s; - int bus, slot; - - printk(KERN_INFO "comedi: attempt to attach...\n"); - printk(KERN_INFO "comedi%d: adl_pci8164\n", dev->minor); - - dev->board_name = "pci8164"; - bus = it->options[0]; - slot = it->options[1]; - - if (alloc_private(dev, sizeof(struct adl_pci8164_private)) < 0) - return -ENOMEM; - - if (alloc_subdevices(dev, 4) < 0) - return -ENOMEM; - - for_each_pci_dev(pcidev) { - if (pcidev->vendor == PCI_VENDOR_ID_ADLINK && - pcidev->device == PCI_DEVICE_ID_PCI8164) { - if (bus || slot) { - /* requested particular bus/slot */ - if (pcidev->bus->number != bus - || PCI_SLOT(pcidev->devfn) != slot) - continue; - } - devpriv->pci_dev = pcidev; - if (comedi_pci_enable(pcidev, "adl_pci8164") < 0) { - printk(KERN_ERR "comedi%d: Failed to enable " - "PCI device and request regions\n", dev->minor); - return -EIO; - } - dev->iobase = pci_resource_start(pcidev, 2); - printk(KERN_DEBUG "comedi: base addr %4lx\n", - dev->iobase); - - s = dev->subdevices + 0; - s->type = COMEDI_SUBD_PROC; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 4; - s->maxdata = 0xffff; - s->len_chanlist = 4; - /* s->range_table = &range_axis; */ - s->insn_read = adl_pci8164_insn_read_msts; - s->insn_write = adl_pci8164_insn_write_cmd; - - s = dev->subdevices + 1; - s->type = COMEDI_SUBD_PROC; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 4; - s->maxdata = 0xffff; - s->len_chanlist = 4; - /* s->range_table = &range_axis; */ - s->insn_read = adl_pci8164_insn_read_ssts; - s->insn_write = adl_pci8164_insn_write_otp; - - s = dev->subdevices + 2; - s->type = COMEDI_SUBD_PROC; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 4; - s->maxdata = 0xffff; - s->len_chanlist = 4; - /* s->range_table = &range_axis; */ - s->insn_read = adl_pci8164_insn_read_buf0; - s->insn_write = adl_pci8164_insn_write_buf0; - - s = dev->subdevices + 3; - s->type = COMEDI_SUBD_PROC; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 4; - s->maxdata = 0xffff; - s->len_chanlist = 4; - /* s->range_table = &range_axis; */ - s->insn_read = adl_pci8164_insn_read_buf1; - s->insn_write = adl_pci8164_insn_write_buf1; - - printk(KERN_INFO "comedi: attached\n"); - - return 1; - } - } - - printk(KERN_ERR "comedi%d: no supported board found!" - "(req. bus/slot : %d/%d)\n", dev->minor, bus, slot); - return -EIO; -} - -static int adl_pci8164_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: pci8164: remove\n", dev->minor); - - if (devpriv && devpriv->pci_dev) { - if (dev->iobase) - comedi_pci_disable(devpriv->pci_dev); - pci_dev_put(devpriv->pci_dev); - } - - return 0; -} - /* all the read commands are the same except for the addition a constant * const to the data for inw() @@ -384,45 +224,136 @@ static int adl_pci8164_insn_write_buf1(struct comedi_device *dev, return 2; } -static int __devinit driver_adl_pci8164_pci_probe(struct pci_dev *dev, - const struct pci_device_id - *ent) +static int adl_pci8164_attach(struct comedi_device *dev, + struct comedi_devconfig *it) { - return comedi_pci_auto_config(dev, driver_adl_pci8164.driver_name); + struct pci_dev *pcidev = NULL; + struct comedi_subdevice *s; + int bus, slot; + + printk(KERN_INFO "comedi: attempt to attach...\n"); + printk(KERN_INFO "comedi%d: adl_pci8164\n", dev->minor); + + dev->board_name = "pci8164"; + bus = it->options[0]; + slot = it->options[1]; + + if (alloc_private(dev, sizeof(struct adl_pci8164_private)) < 0) + return -ENOMEM; + + if (alloc_subdevices(dev, 4) < 0) + return -ENOMEM; + + for_each_pci_dev(pcidev) { + if (pcidev->vendor == PCI_VENDOR_ID_ADLINK && + pcidev->device == PCI_DEVICE_ID_PCI8164) { + if (bus || slot) { + /* requested particular bus/slot */ + if (pcidev->bus->number != bus + || PCI_SLOT(pcidev->devfn) != slot) + continue; + } + devpriv->pci_dev = pcidev; + if (comedi_pci_enable(pcidev, "adl_pci8164") < 0) { + printk(KERN_ERR "comedi%d: Failed to enable " + "PCI device and request regions\n", dev->minor); + return -EIO; + } + dev->iobase = pci_resource_start(pcidev, 2); + printk(KERN_DEBUG "comedi: base addr %4lx\n", + dev->iobase); + + s = dev->subdevices + 0; + s->type = COMEDI_SUBD_PROC; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 4; + s->maxdata = 0xffff; + s->len_chanlist = 4; + /* s->range_table = &range_axis; */ + s->insn_read = adl_pci8164_insn_read_msts; + s->insn_write = adl_pci8164_insn_write_cmd; + + s = dev->subdevices + 1; + s->type = COMEDI_SUBD_PROC; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 4; + s->maxdata = 0xffff; + s->len_chanlist = 4; + /* s->range_table = &range_axis; */ + s->insn_read = adl_pci8164_insn_read_ssts; + s->insn_write = adl_pci8164_insn_write_otp; + + s = dev->subdevices + 2; + s->type = COMEDI_SUBD_PROC; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 4; + s->maxdata = 0xffff; + s->len_chanlist = 4; + /* s->range_table = &range_axis; */ + s->insn_read = adl_pci8164_insn_read_buf0; + s->insn_write = adl_pci8164_insn_write_buf0; + + s = dev->subdevices + 3; + s->type = COMEDI_SUBD_PROC; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 4; + s->maxdata = 0xffff; + s->len_chanlist = 4; + /* s->range_table = &range_axis; */ + s->insn_read = adl_pci8164_insn_read_buf1; + s->insn_write = adl_pci8164_insn_write_buf1; + + printk(KERN_INFO "comedi: attached\n"); + + return 1; + } + } + + printk(KERN_ERR "comedi%d: no supported board found!" + "(req. bus/slot : %d/%d)\n", dev->minor, bus, slot); + return -EIO; } -static void __devexit driver_adl_pci8164_pci_remove(struct pci_dev *dev) +static void adl_pci8164_detach(struct comedi_device *dev) { - comedi_pci_auto_unconfig(dev); + if (devpriv && devpriv->pci_dev) { + if (dev->iobase) + comedi_pci_disable(devpriv->pci_dev); + pci_dev_put(devpriv->pci_dev); + } } -static struct pci_driver driver_adl_pci8164_pci_driver = { - .id_table = adl_pci8164_pci_table, - .probe = &driver_adl_pci8164_pci_probe, - .remove = __devexit_p(&driver_adl_pci8164_pci_remove) +static struct comedi_driver adl_pci8164_driver = { + .driver_name = "adl_pci8164", + .module = THIS_MODULE, + .attach = adl_pci8164_attach, + .detach = adl_pci8164_detach, }; -static int __init driver_adl_pci8164_init_module(void) +static int __devinit adl_pci8164_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) { - int retval; - - retval = comedi_driver_register(&driver_adl_pci8164); - if (retval < 0) - return retval; - - driver_adl_pci8164_pci_driver.name = - (char *)driver_adl_pci8164.driver_name; - return pci_register_driver(&driver_adl_pci8164_pci_driver); + return comedi_pci_auto_config(dev, &adl_pci8164_driver); } -static void __exit driver_adl_pci8164_cleanup_module(void) +static void __devexit adl_pci8164_pci_remove(struct pci_dev *dev) { - pci_unregister_driver(&driver_adl_pci8164_pci_driver); - comedi_driver_unregister(&driver_adl_pci8164); + comedi_pci_auto_unconfig(dev); } -module_init(driver_adl_pci8164_init_module); -module_exit(driver_adl_pci8164_cleanup_module); +static DEFINE_PCI_DEVICE_TABLE(adl_pci8164_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI8164) }, + {0} +}; +MODULE_DEVICE_TABLE(pci, adl_pci8164_pci_table); + +static struct pci_driver adl_pci8164_pci_driver = { + .name = "adl_pci8164", + .id_table = adl_pci8164_pci_table, + .probe = adl_pci8164_pci_probe, + .remove = __devexit_p(adl_pci8164_pci_remove), +}; +module_comedi_pci_driver(adl_pci8164_driver, adl_pci8164_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/adl_pci9111.c b/trunk/drivers/staging/comedi/drivers/adl_pci9111.c index 2a9bd88a4abb..ccfb1a52154e 100644 --- a/trunk/drivers/staging/comedi/drivers/adl_pci9111.c +++ b/trunk/drivers/staging/comedi/drivers/adl_pci9111.c @@ -289,16 +289,6 @@ a multiple of chanlist_len*convert_arg. PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_2); \ } while (0) -/* Function prototypes */ - -static int pci9111_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pci9111_detach(struct comedi_device *dev); -static void pci9111_ai_munge(struct comedi_device *dev, - struct comedi_subdevice *s, void *data, - unsigned int num_bytes, - unsigned int start_chan_index); - static const struct comedi_lrange pci9111_hr_ai_range = { 5, { @@ -310,14 +300,6 @@ static const struct comedi_lrange pci9111_hr_ai_range = { } }; -static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID) }, - /* { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID) }, */ - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, pci9111_pci_table); - /* */ /* Board specification structure */ /* */ @@ -354,51 +336,6 @@ static const struct pci9111_board pci9111_boards[] = { #define pci9111_board_nbr \ (sizeof(pci9111_boards)/sizeof(struct pci9111_board)) -static struct comedi_driver pci9111_driver = { - .driver_name = PCI9111_DRIVER_NAME, - .module = THIS_MODULE, - .attach = pci9111_attach, - .detach = pci9111_detach, -}; - -static int __devinit pci9111_driver_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, pci9111_driver.driver_name); -} - -static void __devexit pci9111_driver_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver pci9111_driver_pci_driver = { - .id_table = pci9111_pci_table, - .probe = &pci9111_driver_pci_probe, - .remove = __devexit_p(&pci9111_driver_pci_remove) -}; - -static int __init pci9111_driver_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&pci9111_driver); - if (retval < 0) - return retval; - - pci9111_driver_pci_driver.name = (char *)pci9111_driver.driver_name; - return pci_register_driver(&pci9111_driver_pci_driver); -} - -static void __exit pci9111_driver_cleanup_module(void) -{ - pci_unregister_driver(&pci9111_driver_pci_driver); - comedi_driver_unregister(&pci9111_driver); -} - -module_init(pci9111_driver_init_module); -module_exit(pci9111_driver_cleanup_module); - /* Private data structure */ struct pci9111_private_data { @@ -1445,31 +1382,54 @@ static int pci9111_attach(struct comedi_device *dev, return 0; } -/* Detach */ - -static int pci9111_detach(struct comedi_device *dev) +static void pci9111_detach(struct comedi_device *dev) { - /* Reset device */ - if (dev->private != NULL) { if (dev_private->is_valid) pci9111_reset(dev); - } - /* Release previously allocated irq */ - if (dev->irq != 0) free_irq(dev->irq, dev); - if (dev_private != NULL && dev_private->pci_device != NULL) { if (dev->iobase) comedi_pci_disable(dev_private->pci_device); pci_dev_put(dev_private->pci_device); } +} - return 0; +static struct comedi_driver adl_pci9111_driver = { + .driver_name = "adl_pci9111", + .module = THIS_MODULE, + .attach = pci9111_attach, + .detach = pci9111_detach, +}; + +static int __devinit pci9111_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + return comedi_pci_auto_config(dev, &adl_pci9111_driver); } +static void __devexit pci9111_pci_remove(struct pci_dev *dev) +{ + comedi_pci_auto_unconfig(dev); +} + +static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID) }, + /* { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID) }, */ + { 0 } +}; +MODULE_DEVICE_TABLE(pci, pci9111_pci_table); + +static struct pci_driver adl_pci9111_pci_driver = { + .name = "adl_pci9111", + .id_table = pci9111_pci_table, + .probe = pci9111_pci_probe, + .remove = __devexit_p(pci9111_pci_remove), +}; +module_comedi_pci_driver(adl_pci9111_driver, adl_pci9111_pci_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/adl_pci9118.c b/trunk/drivers/staging/comedi/drivers/adl_pci9118.c index f17654e44aef..78645863297b 100644 --- a/trunk/drivers/staging/comedi/drivers/adl_pci9118.c +++ b/trunk/drivers/staging/comedi/drivers/adl_pci9118.c @@ -221,10 +221,6 @@ static const struct comedi_lrange range_pci9118hg = { 8, { * of BIP/UNI ranges */ -static int pci9118_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pci9118_detach(struct comedi_device *dev); - struct boardtype { const char *name; /* board name */ int vendor_id; /* PCI vendor a device ID of card */ @@ -252,81 +248,6 @@ struct boardtype { }; -static DEFINE_PCI_DEVICE_TABLE(pci9118_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_AMCC, 0x80d9) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, pci9118_pci_table); - -static const struct boardtype boardtypes[] = { - {"pci9118dg", PCI_VENDOR_ID_AMCC, 0x80d9, - AMCC_OP_REG_SIZE, IORANGE_9118, - 16, 8, 256, PCI9118_CHANLEN, 2, 0x0fff, 0x0fff, - &range_pci9118dg_hr, &range_bipolar10, - 3000, 12, 512}, - {"pci9118hg", PCI_VENDOR_ID_AMCC, 0x80d9, - AMCC_OP_REG_SIZE, IORANGE_9118, - 16, 8, 256, PCI9118_CHANLEN, 2, 0x0fff, 0x0fff, - &range_pci9118hg, &range_bipolar10, - 3000, 12, 512}, - {"pci9118hr", PCI_VENDOR_ID_AMCC, 0x80d9, - AMCC_OP_REG_SIZE, IORANGE_9118, - 16, 8, 256, PCI9118_CHANLEN, 2, 0xffff, 0x0fff, - &range_pci9118dg_hr, &range_bipolar10, - 10000, 40, 512}, -}; - -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype)) - -static struct comedi_driver driver_pci9118 = { - .driver_name = "adl_pci9118", - .module = THIS_MODULE, - .attach = pci9118_attach, - .detach = pci9118_detach, - .num_names = n_boardtypes, - .board_name = &boardtypes[0].name, - .offset = sizeof(struct boardtype), -}; - -static int __devinit driver_pci9118_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, driver_pci9118.driver_name); -} - -static void __devexit driver_pci9118_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_pci9118_pci_driver = { - .id_table = pci9118_pci_table, - .probe = &driver_pci9118_pci_probe, - .remove = __devexit_p(&driver_pci9118_pci_remove) -}; - -static int __init driver_pci9118_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_pci9118); - if (retval < 0) - return retval; - - driver_pci9118_pci_driver.name = (char *)driver_pci9118.driver_name; - return pci_register_driver(&driver_pci9118_pci_driver); -} - -static void __exit driver_pci9118_cleanup_module(void) -{ - pci_unregister_driver(&driver_pci9118_pci_driver); - comedi_driver_unregister(&driver_pci9118); -} - -module_init(driver_pci9118_init_module); -module_exit(driver_pci9118_cleanup_module); - struct pci9118_private { unsigned long iobase_a; /* base+size for AMCC chip */ unsigned int master; /* master capable */ @@ -2190,9 +2111,6 @@ static int pci9118_reset(struct comedi_device *dev) return 0; } -/* -============================================================================== -*/ static int pci9118_attach(struct comedi_device *dev, struct comedi_devconfig *it) { @@ -2435,10 +2353,7 @@ static int pci9118_attach(struct comedi_device *dev, return 0; } -/* -============================================================================== -*/ -static int pci9118_detach(struct comedi_device *dev) +static void pci9118_detach(struct comedi_device *dev) { if (dev->private) { if (devpriv->valid) @@ -2458,13 +2373,100 @@ static int pci9118_detach(struct comedi_device *dev) free_pages((unsigned long)devpriv->dmabuf_virt[1], devpriv->dmabuf_pages[1]); } +} - return 0; +static const struct boardtype boardtypes[] = { + { + .name = "pci9118dg", + .vendor_id = PCI_VENDOR_ID_AMCC, + .device_id = 0x80d9, + .iorange_amcc = AMCC_OP_REG_SIZE, + .iorange_9118 = IORANGE_9118, + .n_aichan = 16, + .n_aichand = 8, + .mux_aichan = 256, + .n_aichanlist = PCI9118_CHANLEN, + .n_aochan = 2, + .ai_maxdata = 0x0fff, + .ao_maxdata = 0x0fff, + .rangelist_ai = &range_pci9118dg_hr, + .rangelist_ao = &range_bipolar10, + .ai_ns_min = 3000, + .ai_pacer_min = 12, + .half_fifo_size = 512, + }, { + .name = "pci9118hg", + .vendor_id = PCI_VENDOR_ID_AMCC, + .device_id = 0x80d9, + .iorange_amcc = AMCC_OP_REG_SIZE, + .iorange_9118 = IORANGE_9118, + .n_aichan = 16, + .n_aichand = 8, + .mux_aichan = 256, + .n_aichanlist = PCI9118_CHANLEN, + .n_aochan = 2, + .ai_maxdata = 0x0fff, + .ao_maxdata = 0x0fff, + .rangelist_ai = &range_pci9118hg, + .rangelist_ao = &range_bipolar10, + .ai_ns_min = 3000, + .ai_pacer_min = 12, + .half_fifo_size = 512, + }, { + .name = "pci9118hr", + .vendor_id = PCI_VENDOR_ID_AMCC, + .device_id = 0x80d9, + .iorange_amcc = AMCC_OP_REG_SIZE, + .iorange_9118 = IORANGE_9118, + .n_aichan = 16, + .n_aichand = 8, + .mux_aichan = 256, + .n_aichanlist = PCI9118_CHANLEN, + .n_aochan = 2, + .ai_maxdata = 0xffff, + .ao_maxdata = 0x0fff, + .rangelist_ai = &range_pci9118dg_hr, + .rangelist_ao = &range_bipolar10, + .ai_ns_min = 10000, + .ai_pacer_min = 40, + .half_fifo_size = 512, + }, +}; + +static struct comedi_driver adl_pci9118_driver = { + .driver_name = "adl_pci9118", + .module = THIS_MODULE, + .attach = pci9118_attach, + .detach = pci9118_detach, + .num_names = ARRAY_SIZE(boardtypes), + .board_name = &boardtypes[0].name, + .offset = sizeof(struct boardtype), +}; + +static int __devinit adl_pci9118_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + return comedi_pci_auto_config(dev, &adl_pci9118_driver); } -/* -============================================================================== -*/ +static void __devexit adl_pci9118_pci_remove(struct pci_dev *dev) +{ + comedi_pci_auto_unconfig(dev); +} + +static DEFINE_PCI_DEVICE_TABLE(adl_pci9118_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_AMCC, 0x80d9) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, adl_pci9118_pci_table); + +static struct pci_driver adl_pci9118_pci_driver = { + .name = "adl_pci9118", + .id_table = adl_pci9118_pci_table, + .probe = adl_pci9118_pci_probe, + .remove = __devexit_p(adl_pci9118_pci_remove), +}; +module_comedi_pci_driver(adl_pci9118_driver, adl_pci9118_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/adq12b.c b/trunk/drivers/staging/comedi/drivers/adq12b.c index 5361f318b010..7d585a12050f 100644 --- a/trunk/drivers/staging/comedi/drivers/adq12b.c +++ b/trunk/drivers/staging/comedi/drivers/adq12b.c @@ -125,24 +125,6 @@ struct adq12b_board { int do_chans; }; -static const struct adq12b_board adq12b_boards[] = { - { - .name = "adq12b", - .ai_se_chans = 16, - .ai_diff_chans = 8, - .ai_bits = 12, - .di_chans = 5, - .do_chans = 8} -/* potentially, more adq-based deviced will be added */ -/*, - .name = "adq12b", - .ai_chans = 16, // this is just for reference, hardcoded again later - .ai_bits = 12, - .di_chans = 8, - .do_chans = 5 - }*/ -}; - #define thisboard ((const struct adq12b_board *)dev->board_ptr) struct adq12b_private { @@ -156,41 +138,88 @@ struct adq12b_private { #define devpriv ((struct adq12b_private *)dev->private) /* - * The struct comedi_driver structure tells the Comedi core module - * which functions to call to configure/deconfigure (attach/detach) - * the board, and also about the kernel module that contains - * the device code. + * "instructions" read/write data in "one-shot" or "software-triggered" + * mode. */ -static int adq12b_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int adq12b_detach(struct comedi_device *dev); - -static struct comedi_driver driver_adq12b = { - .driver_name = "adq12b", - .module = THIS_MODULE, - .attach = adq12b_attach, - .detach = adq12b_detach, - .board_name = &adq12b_boards[0].name, - .offset = sizeof(struct adq12b_board), - .num_names = ARRAY_SIZE(adq12b_boards), -}; static int adq12b_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); + unsigned int *data) +{ + int n, i; + int range, channel; + unsigned char hi, lo, status; + + /* change channel and range only if it is different from the previous */ + range = CR_RANGE(insn->chanspec); + channel = CR_CHAN(insn->chanspec); + if (channel != devpriv->last_channel || range != devpriv->last_range) { + outb((range << 4) | channel, dev->iobase + ADQ12B_CTREG); + udelay(50); /* wait for the mux to settle */ + } + + /* trigger conversion */ + status = inb(dev->iobase + ADQ12B_ADLOW); + + /* convert n samples */ + for (n = 0; n < insn->n; n++) { + + /* wait for end of conversion */ + i = 0; + do { + /* udelay(1); */ + status = inb(dev->iobase + ADQ12B_STINR); + status = status & ADQ12B_EOC; + } while (status == 0 && ++i < TIMEOUT); + /* } while (++i < 10); */ + + /* read data */ + hi = inb(dev->iobase + ADQ12B_ADHIG); + lo = inb(dev->iobase + ADQ12B_ADLOW); + + /* printk("debug: chan=%d range=%d status=%d hi=%d lo=%d\n", + channel, range, status, hi, lo); */ + data[n] = (hi << 8) | lo; + + } + + /* return the number of samples read/written */ + return n; +} + static int adq12b_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); + struct comedi_insn *insn, unsigned int *data) +{ + + /* only bits 0-4 have information about digital inputs */ + data[1] = (inb(dev->iobase + ADQ12B_STINR) & (0x1f)); + + return 2; +} + static int adq12b_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); + struct comedi_insn *insn, unsigned int *data) +{ + int channel; + + for (channel = 0; channel < 8; channel++) + if (((data[0] >> channel) & 0x01) != 0) + outb((((data[1] >> channel) & 0x01) << 3) | channel, + dev->iobase + ADQ12B_OUTBR); + + /* store information to retrieve when asked for reading */ + if (data[0]) { + devpriv->digital_state &= ~data[0]; + devpriv->digital_state |= (data[0] & data[1]); + } + + data[1] = devpriv->digital_state; + + return 2; +} -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; @@ -295,125 +324,34 @@ static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int adq12b_detach(struct comedi_device *dev) +static void adq12b_detach(struct comedi_device *dev) { if (dev->iobase) release_region(dev->iobase, ADQ12B_SIZE); - kfree(devpriv); - - printk(KERN_INFO "comedi%d: adq12b: removed\n", dev->minor); - - return 0; -} - -/* - * "instructions" read/write data in "one-shot" or "software-triggered" - * mode. - */ - -static int adq12b_ai_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) -{ - int n, i; - int range, channel; - unsigned char hi, lo, status; - - /* change channel and range only if it is different from the previous */ - range = CR_RANGE(insn->chanspec); - channel = CR_CHAN(insn->chanspec); - if (channel != devpriv->last_channel || range != devpriv->last_range) { - outb((range << 4) | channel, dev->iobase + ADQ12B_CTREG); - udelay(50); /* wait for the mux to settle */ - } - - /* trigger conversion */ - status = inb(dev->iobase + ADQ12B_ADLOW); - - /* convert n samples */ - for (n = 0; n < insn->n; n++) { - - /* wait for end of conversion */ - i = 0; - do { - /* udelay(1); */ - status = inb(dev->iobase + ADQ12B_STINR); - status = status & ADQ12B_EOC; - } while (status == 0 && ++i < TIMEOUT); - /* } while (++i < 10); */ - - /* read data */ - hi = inb(dev->iobase + ADQ12B_ADHIG); - lo = inb(dev->iobase + ADQ12B_ADLOW); - - /* printk("debug: chan=%d range=%d status=%d hi=%d lo=%d\n", - channel, range, status, hi, lo); */ - data[n] = (hi << 8) | lo; - - } - - /* return the number of samples read/written */ - return n; -} - -static int adq12b_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - - /* only bits 0-4 have information about digital inputs */ - data[1] = (inb(dev->iobase + ADQ12B_STINR) & (0x1f)); - - return 2; } -static int adq12b_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int channel; - - for (channel = 0; channel < 8; channel++) - if (((data[0] >> channel) & 0x01) != 0) - outb((((data[1] >> channel) & 0x01) << 3) | channel, - dev->iobase + ADQ12B_OUTBR); - - /* store information to retrieve when asked for reading */ - if (data[0]) { - devpriv->digital_state &= ~data[0]; - devpriv->digital_state |= (data[0] & data[1]); - } - - data[1] = devpriv->digital_state; - - return 2; -} - -/* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. - */ -static int __init driver_adq12b_init_module(void) -{ - return comedi_driver_register(&driver_adq12b); -} - -static void __exit driver_adq12b_cleanup_module(void) -{ - comedi_driver_unregister(&driver_adq12b); -} +static const struct adq12b_board adq12b_boards[] = { + { + .name = "adq12b", + .ai_se_chans = 16, + .ai_diff_chans = 8, + .ai_bits = 12, + .di_chans = 5, + .do_chans = 8, + }, +}; -module_init(driver_adq12b_init_module); -module_exit(driver_adq12b_cleanup_module); +static struct comedi_driver adq12b_driver = { + .driver_name = "adq12b", + .module = THIS_MODULE, + .attach = adq12b_attach, + .detach = adq12b_detach, + .board_name = &adq12b_boards[0].name, + .offset = sizeof(struct adq12b_board), + .num_names = ARRAY_SIZE(adq12b_boards), +}; +module_comedi_driver(adq12b_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/adv_pci1710.c b/trunk/drivers/staging/comedi/drivers/adv_pci1710.c index 8318c82a555a..de8c98cfe367 100644 --- a/trunk/drivers/staging/comedi/drivers/adv_pci1710.c +++ b/trunk/drivers/staging/comedi/drivers/adv_pci1710.c @@ -191,10 +191,6 @@ static const struct comedi_lrange range_pci171x_da = { 2, { } }; -static int pci1710_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pci1710_detach(struct comedi_device *dev); - struct boardtype { const char *name; /* board name */ int device_id; @@ -216,17 +212,6 @@ struct boardtype { unsigned int fifo_half_size; /* size of FIFO/2 */ }; -static DEFINE_PCI_DEVICE_TABLE(pci1710_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1710) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1711) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1713) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1720) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1731) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, pci1710_pci_table); - static const struct boardtype boardtypes[] = { {"pci1710", 0x1710, IORANGE_171x, 1, TYPE_PCI171X, @@ -264,18 +249,6 @@ static const struct boardtype boardtypes[] = { {.name = DRV_NAME}, }; -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype)) - -static struct comedi_driver driver_pci1710 = { - .driver_name = DRV_NAME, - .module = THIS_MODULE, - .attach = pci1710_attach, - .detach = pci1710_detach, - .num_names = n_boardtypes, - .board_name = &boardtypes[0].name, - .offset = sizeof(struct boardtype), -}; - struct pci1710_private { struct pci_dev *pcidev; /* ptr to PCI device */ char valid; /* card is usable */ @@ -676,7 +649,9 @@ static void interrupt_pci1710_every_sample(void *d) s->async->buf_int_count, s->async->buf_int_ptr, s->async->buf_user_count, s->async->buf_user_ptr); DPRINTK("adv_pci1710 EDBG: EOS2\n"); - if ((!devpriv->neverending_ai) && (devpriv->ai_act_scan >= devpriv->ai_scans)) { /* all data sampled */ + if ((!devpriv->neverending_ai) && + (devpriv->ai_act_scan >= devpriv->ai_scans)) { + /* all data sampled */ pci171x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA; comedi_event(dev, s); @@ -804,8 +779,8 @@ static irqreturn_t interrupt_service_pci1710(int irq, void *d) irq); if (!dev->attached) /* is device attached? */ return IRQ_NONE; /* no, exit */ - - if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ)) /* is this interrupt from our board? */ + /* is this interrupt from our board? */ + if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ)) return IRQ_NONE; /* no, exit */ DPRINTK("adv_pci1710 EDBG: interrupt_service_pci1710() ST: %4x\n", @@ -814,7 +789,7 @@ static irqreturn_t interrupt_service_pci1710(int irq, void *d) if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */ devpriv->ai_et = 0; devpriv->CntrlReg &= Control_CNT0; - devpriv->CntrlReg |= Control_SW; /* set software trigger */ + devpriv->CntrlReg |= Control_SW; /* set software trigger */ outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); devpriv->CntrlReg = devpriv->ai_et_CntrlReg; outb(0, dev->iobase + PCI171x_CLRFIFO); @@ -865,7 +840,8 @@ static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev, devpriv->neverending_ai = 0; devpriv->CntrlReg &= Control_CNT0; - if ((devpriv->ai_flags & TRIG_WAKE_EOS)) { /* don't we want wake up every scan? devpriv->ai_eos=1; */ + /* don't we want wake up every scan? devpriv->ai_eos=1; */ + if ((devpriv->ai_flags & TRIG_WAKE_EOS)) { devpriv->ai_eos = 1; } else { devpriv->CntrlReg |= Control_ONEFH; @@ -982,13 +958,13 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev, #ifdef PCI171X_EXTDEBUG pci171x_cmdtest_out(1, cmd); #endif - DPRINTK - ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n", - err); + DPRINTK( + "adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n", + err); return 1; } - /* step 2: make sure trigger sources are unique and mutually compatible */ + /* step2: make sure trigger srcs are unique and mutually compatible */ if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) { cmd->start_src = TRIG_NOW; @@ -1015,9 +991,9 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev, #ifdef PCI171X_EXTDEBUG pci171x_cmdtest_out(2, cmd); #endif - DPRINTK - ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n", - err); + DPRINTK( + "adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n", + err); return 2; } @@ -1065,9 +1041,9 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev, #ifdef PCI171X_EXTDEBUG pci171x_cmdtest_out(3, cmd); #endif - DPRINTK - ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n", - err); + DPRINTK( + "adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n", + err); return 3; } @@ -1160,48 +1136,41 @@ static int check_channel_list(struct comedi_device *dev, return 0; } - if (n_chan > 1) { - chansegment[0] = chanlist[0]; /* first channel is every time ok */ - for (i = 1, seglen = 1; i < n_chan; i++, seglen++) { /* build part of chanlist */ - /* printk("%d. %d %d\n",i,CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */ - if (chanlist[0] == chanlist[i]) - break; /* we detect loop, this must by finish */ - if (CR_CHAN(chanlist[i]) & 1) /* odd channel cann't by differencial */ - if (CR_AREF(chanlist[i]) == AREF_DIFF) { - comedi_error(dev, - "Odd channel can't be differential input!\n"); - return 0; - } - 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])) { /* channel list isn't continuous :-( */ - 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; - } - chansegment[i] = chanlist[i]; /* well, this is next correct channel in list */ + if (n_chan == 1) + return 1; /* seglen=1 */ + + 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]) + 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; } + 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; + } + chansegment[i] = chanlist[i]; /* next correct channel in list */ + } - for (i = 0, segpos = 0; i < n_chan; i++) { /* check whole chanlist */ - /* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(chanlist[i]),CR_RANGE(chanlist[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; /* chan/gain list is strange */ - } + 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; } - } else { - seglen = 1; } return seglen; } @@ -1221,14 +1190,14 @@ static void setup_channel_list(struct comedi_device *dev, DPRINTK("SegLen: %d\n", seglen); 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 */ + outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */ range = this_board->rangecode_ai[CR_RANGE(chanlist[i])]; if (CR_AREF(chanlist[i]) == AREF_DIFF) range |= 0x0020; - outw(range, dev->iobase + PCI171x_RANGE); /* select gain */ + outw(range, dev->iobase + PCI171x_RANGE); /* select gain */ #ifdef PCI171x_PARANOIDCHECK devpriv->act_chanlist[i] = - (CR_CHAN(chanlist[i]) << 12) & 0xf000; + (CR_CHAN(chanlist[i]) << 12) & 0xf000; #endif DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range, devpriv->act_chanlist[i]); @@ -1236,13 +1205,14 @@ static void setup_channel_list(struct comedi_device *dev, #ifdef PCI171x_PARANOIDCHECK for ( ; i < n_chan; i++) { /* store remainder of channel list */ devpriv->act_chanlist[i] = - (CR_CHAN(chanlist[i]) << 12) & 0xf000; + (CR_CHAN(chanlist[i]) << 12) & 0xf000; } #endif devpriv->ai_et_MuxVal = - CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8); - outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); /* select channel interval to scan */ + CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8); + /* select channel interval to scan */ + outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); DPRINTK("MUX: %4x L%4x.H%4x\n", CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8), CR_CHAN(chanlist[0]), CR_CHAN(chanlist[seglen - 1])); @@ -1365,9 +1335,6 @@ static int pci1710_reset(struct comedi_device *dev) DPRINTK("adv_pci1710 EDBG: END: pci1710_reset(...)\n"); } -/* -============================================================================== -*/ static int pci1710_attach(struct comedi_device *dev, struct comedi_devconfig *it) { @@ -1398,13 +1365,13 @@ static int pci1710_attach(struct comedi_device *dev, while (NULL != (pcidev = pci_get_device(PCI_VENDOR_ID_ADVANTECH, PCI_ANY_ID, pcidev))) { if (strcmp(this_board->name, DRV_NAME) == 0) { - for (i = 0; i < n_boardtypes; ++i) { + for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) { if (pcidev->device == boardtypes[i].device_id) { board_index = i; break; } } - if (i == n_boardtypes) + if (i == ARRAY_SIZE(boardtypes)) continue; } else { if (pcidev->device != boardtypes[board_index].device_id) @@ -1584,12 +1551,8 @@ static int pci1710_attach(struct comedi_device *dev, return 0; } -/* -============================================================================== -*/ -static int pci1710_detach(struct comedi_device *dev) +static void pci1710_detach(struct comedi_device *dev) { - if (dev->private) { if (devpriv->valid) pci1710_reset(dev); @@ -1598,57 +1561,49 @@ static int pci1710_detach(struct comedi_device *dev) if (devpriv->pcidev) { if (dev->iobase) comedi_pci_disable(devpriv->pcidev); - pci_dev_put(devpriv->pcidev); } } - - return 0; } -/* -============================================================================== -*/ -static int __devinit driver_pci1710_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) +static struct comedi_driver adv_pci1710_driver = { + .driver_name = "adv_pci1710", + .module = THIS_MODULE, + .attach = pci1710_attach, + .detach = pci1710_detach, + .num_names = ARRAY_SIZE(boardtypes), + .board_name = &boardtypes[0].name, + .offset = sizeof(struct boardtype), +}; + +static int __devinit adv_pci1710_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, driver_pci1710.driver_name); + return comedi_pci_auto_config(dev, &adv_pci1710_driver); } -static void __devexit driver_pci1710_pci_remove(struct pci_dev *dev) +static void __devexit adv_pci1710_pci_remove(struct pci_dev *dev) { comedi_pci_auto_unconfig(dev); } -static struct pci_driver driver_pci1710_pci_driver = { - .id_table = pci1710_pci_table, - .probe = &driver_pci1710_pci_probe, - .remove = __devexit_p(&driver_pci1710_pci_remove) +static DEFINE_PCI_DEVICE_TABLE(adv_pci1710_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1710) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1711) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1713) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1720) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1731) }, + { 0 } }; +MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table); -static int __init driver_pci1710_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_pci1710); - if (retval < 0) - return retval; - - driver_pci1710_pci_driver.name = (char *)driver_pci1710.driver_name; - return pci_register_driver(&driver_pci1710_pci_driver); -} - -static void __exit driver_pci1710_cleanup_module(void) -{ - pci_unregister_driver(&driver_pci1710_pci_driver); - comedi_driver_unregister(&driver_pci1710); -} - -module_init(driver_pci1710_init_module); -module_exit(driver_pci1710_cleanup_module); -/* -============================================================================== -*/ +static struct pci_driver adv_pci1710_pci_driver = { + .name = "adv_pci1710", + .id_table = adv_pci1710_pci_table, + .probe = adv_pci1710_pci_probe, + .remove = __devexit_p(adv_pci1710_pci_remove), +}; +module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/adv_pci1723.c b/trunk/drivers/staging/comedi/drivers/adv_pci1723.c index 29455a8e88b4..336addcbce3a 100644 --- a/trunk/drivers/staging/comedi/drivers/adv_pci1723.c +++ b/trunk/drivers/staging/comedi/drivers/adv_pci1723.c @@ -150,36 +150,6 @@ static const struct pci1723_board boardtypes[] = { }, }; -/* - * This is used by modprobe to translate PCI IDs to drivers. - * Should only be used for PCI and ISA-PnP devices - */ -static DEFINE_PCI_DEVICE_TABLE(pci1723_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1723) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, pci1723_pci_table); - -/* - * The struct comedi_driver structure tells the Comedi core module - * which functions to call to configure/deconfigure (attach/detach) - * the board, and also about the kernel module that contains - * the device code. - */ -static int pci1723_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pci1723_detach(struct comedi_device *dev); - -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pci1723_board)) - -static struct comedi_driver driver_pci1723 = { - .driver_name = "adv_pci1723", - .module = THIS_MODULE, - .attach = pci1723_attach, - .detach = pci1723_detach, -}; - /* This structure is for data unique to this hardware driver. */ struct pci1723_private { int valid; /* card is usable; */ @@ -319,10 +289,6 @@ static int pci1723_dio_insn_bits(struct comedi_device *dev, return 2; } -/* - * Attach is called by the Comedi core to configure the driver - * for a pci1723 board. - */ static int pci1723_attach(struct comedi_device *dev, struct comedi_devconfig *it) { @@ -465,73 +431,50 @@ static int pci1723_attach(struct comedi_device *dev, return 0; } -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int pci1723_detach(struct comedi_device *dev) +static void pci1723_detach(struct comedi_device *dev) { - printk(KERN_ERR "comedi%d: pci1723: remove\n", dev->minor); - if (dev->private) { if (devpriv->valid) pci1723_reset(dev); - if (devpriv->pcidev) { if (dev->iobase) comedi_pci_disable(devpriv->pcidev); pci_dev_put(devpriv->pcidev); } } - - return 0; } -/* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. - */ -static int __devinit driver_pci1723_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) +static struct comedi_driver adv_pci1723_driver = { + .driver_name = "adv_pci1723", + .module = THIS_MODULE, + .attach = pci1723_attach, + .detach = pci1723_detach, +}; + +static int __devinit adv_pci1723_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, driver_pci1723.driver_name); + return comedi_pci_auto_config(dev, &adv_pci1723_driver); } -static void __devexit driver_pci1723_pci_remove(struct pci_dev *dev) +static void __devexit adv_pci1723_pci_remove(struct pci_dev *dev) { comedi_pci_auto_unconfig(dev); } -static struct pci_driver driver_pci1723_pci_driver = { - .id_table = pci1723_pci_table, - .probe = &driver_pci1723_pci_probe, - .remove = __devexit_p(&driver_pci1723_pci_remove) +static DEFINE_PCI_DEVICE_TABLE(adv_pci1723_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1723) }, + { 0 } }; +MODULE_DEVICE_TABLE(pci, adv_pci1723_pci_table); -static int __init driver_pci1723_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_pci1723); - if (retval < 0) - return retval; - - driver_pci1723_pci_driver.name = (char *)driver_pci1723.driver_name; - return pci_register_driver(&driver_pci1723_pci_driver); -} - -static void __exit driver_pci1723_cleanup_module(void) -{ - pci_unregister_driver(&driver_pci1723_pci_driver); - comedi_driver_unregister(&driver_pci1723); -} - -module_init(driver_pci1723_init_module); -module_exit(driver_pci1723_cleanup_module); +static struct pci_driver adv_pci1723_pci_driver = { + .name = "adv_pci1723", + .id_table = adv_pci1723_pci_table, + .probe = adv_pci1723_pci_probe, + .remove = __devexit_p(adv_pci1723_pci_remove), +}; +module_comedi_pci_driver(adv_pci1723_driver, adv_pci1723_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/adv_pci_dio.c b/trunk/drivers/staging/comedi/drivers/adv_pci_dio.c index 7af068f4a749..43a32dc12cde 100644 --- a/trunk/drivers/staging/comedi/drivers/adv_pci_dio.c +++ b/trunk/drivers/staging/comedi/drivers/adv_pci_dio.c @@ -237,10 +237,6 @@ enum hw_io_access { #define OMBCMD_RETRY 0x03 /* 3 times try request before error */ -static int pci_dio_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pci_dio_detach(struct comedi_device *dev); - struct diosubd_data { int chans; /* num of chans */ int addr; /* PCI address ofset */ @@ -263,26 +259,6 @@ struct dio_boardtype { enum hw_io_access io_access; }; -static DEFINE_PCI_DEVICE_TABLE(pci_dio_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1730) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1733) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1734) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1735) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1736) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1739) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1750) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1751) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1752) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1753) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1754) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1756) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1760) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1762) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, pci_dio_pci_table); - static const struct dio_boardtype boardtypes[] = { {"pci1730", PCI_VENDOR_ID_ADVANTECH, 0x1730, PCIDIO_MAINREG, TYPE_PCI1730, @@ -406,15 +382,6 @@ static const struct dio_boardtype boardtypes[] = { IO_16b} }; -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct dio_boardtype)) - -static struct comedi_driver driver_pci_dio = { - .driver_name = "adv_pci_dio", - .module = THIS_MODULE, - .attach = pci_dio_attach, - .detach = pci_dio_detach -}; - struct pci_dio_private { struct pci_dio_private *prev; /* previous private struct */ struct pci_dio_private *next; /* next private struct */ @@ -1116,9 +1083,6 @@ static int CheckAndAllocCard(struct comedi_device *dev, return 1; } -/* -============================================================================== -*/ static int pci_dio_attach(struct comedi_device *dev, struct comedi_devconfig *it) { @@ -1134,7 +1098,7 @@ static int pci_dio_attach(struct comedi_device *dev, for_each_pci_dev(pcidev) { /* loop through cards supported by this driver */ - for (i = 0; i < n_boardtypes; ++i) { + for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) { if (boardtypes[i].vendor_id != pcidev->vendor) continue; if (boardtypes[i].device_id != pcidev->device) @@ -1162,7 +1126,7 @@ static int pci_dio_attach(struct comedi_device *dev, return -EIO; } - if (comedi_pci_enable(pcidev, driver_pci_dio.driver_name)) { + if (comedi_pci_enable(pcidev, dev->driver->driver_name)) { dev_err(dev->hw_dev, "Error: Can't enable PCI device and request regions!\n"); return -EIO; } @@ -1246,10 +1210,7 @@ static int pci_dio_attach(struct comedi_device *dev, return 0; } -/* -============================================================================== -*/ -static int pci_dio_detach(struct comedi_device *dev) +static void pci_dio_detach(struct comedi_device *dev) { int i, j; struct comedi_subdevice *s; @@ -1258,20 +1219,14 @@ static int pci_dio_detach(struct comedi_device *dev) if (dev->private) { if (devpriv->valid) pci_dio_reset(dev); - - - /* This shows the silliness of using this kind of - * scheme for numbering subdevices. Don't do it. --ds */ subdev = 0; for (i = 0; i < MAX_DI_SUBDEVS; i++) { if (this_board->sdi[i].chans) subdev++; - } for (i = 0; i < MAX_DO_SUBDEVS; i++) { if (this_board->sdo[i].chans) subdev++; - } for (i = 0; i < MAX_DIO_SUBDEVG; i++) { for (j = 0; j < this_board->sdio[i].regs; j++) { @@ -1280,82 +1235,73 @@ static int pci_dio_detach(struct comedi_device *dev) subdev++; } } - if (this_board->boardid.chans) subdev++; - for (i = 0; i < MAX_8254_SUBDEVS; i++) if (this_board->s8254[i].chans) subdev++; - for (i = 0; i < dev->n_subdevices; i++) { s = dev->subdevices + i; s->private = NULL; } - if (devpriv->pcidev) { if (dev->iobase) comedi_pci_disable(devpriv->pcidev); - pci_dev_put(devpriv->pcidev); } - if (devpriv->prev) devpriv->prev->next = devpriv->next; else pci_priv = devpriv->next; - if (devpriv->next) devpriv->next->prev = devpriv->prev; - } - - return 0; } -/* -============================================================================== -*/ -static int __devinit driver_pci_dio_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) +static struct comedi_driver adv_pci_dio_driver = { + .driver_name = "adv_pci_dio", + .module = THIS_MODULE, + .attach = pci_dio_attach, + .detach = pci_dio_detach +}; + +static int __devinit adv_pci_dio_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, driver_pci_dio.driver_name); + return comedi_pci_auto_config(dev, &adv_pci_dio_driver); } -static void __devexit driver_pci_dio_pci_remove(struct pci_dev *dev) +static void __devexit adv_pci_dio_pci_remove(struct pci_dev *dev) { comedi_pci_auto_unconfig(dev); } -static struct pci_driver driver_pci_dio_pci_driver = { - .id_table = pci_dio_pci_table, - .probe = &driver_pci_dio_pci_probe, - .remove = __devexit_p(&driver_pci_dio_pci_remove) +static DEFINE_PCI_DEVICE_TABLE(adv_pci_dio_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1730) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1733) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1734) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1735) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1736) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1739) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1750) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1751) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1752) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1753) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1754) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1756) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1760) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1762) }, + { 0 } }; +MODULE_DEVICE_TABLE(pci, adv_pci_dio_pci_table); -static int __init driver_pci_dio_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_pci_dio); - if (retval < 0) - return retval; - - driver_pci_dio_pci_driver.name = (char *)driver_pci_dio.driver_name; - return pci_register_driver(&driver_pci_dio_pci_driver); -} - -static void __exit driver_pci_dio_cleanup_module(void) -{ - pci_unregister_driver(&driver_pci_dio_pci_driver); - comedi_driver_unregister(&driver_pci_dio); -} - -module_init(driver_pci_dio_init_module); -module_exit(driver_pci_dio_cleanup_module); -/* -============================================================================== -*/ +static struct pci_driver adv_pci_dio_pci_driver = { + .name = "adv_pci_dio", + .id_table = adv_pci_dio_pci_table, + .probe = adv_pci_dio_pci_probe, + .remove = __devexit_p(adv_pci_dio_pci_remove), +}; +module_comedi_pci_driver(adv_pci_dio_driver, adv_pci_dio_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/aio_aio12_8.c b/trunk/drivers/staging/comedi/drivers/aio_aio12_8.c index b0f98e5e4bf3..64d82bc4ffe4 100644 --- a/trunk/drivers/staging/comedi/drivers/aio_aio12_8.c +++ b/trunk/drivers/staging/comedi/drivers/aio_aio12_8.c @@ -209,36 +209,23 @@ static int aio_aio12_8_attach(struct comedi_device *dev, return 0; } -static int aio_aio12_8_detach(struct comedi_device *dev) +static void aio_aio12_8_detach(struct comedi_device *dev) { subdev_8255_cleanup(dev, &dev->subdevices[2]); if (dev->iobase) release_region(dev->iobase, 24); - return 0; } -static struct comedi_driver driver_aio_aio12_8 = { - .driver_name = "aio_aio12_8", - .module = THIS_MODULE, - .attach = aio_aio12_8_attach, - .detach = aio_aio12_8_detach, - .board_name = &board_types[0].name, - .num_names = 1, - .offset = sizeof(struct aio12_8_boardtype), +static struct comedi_driver aio_aio12_8_driver = { + .driver_name = "aio_aio12_8", + .module = THIS_MODULE, + .attach = aio_aio12_8_attach, + .detach = aio_aio12_8_detach, + .board_name = &board_types[0].name, + .num_names = ARRAY_SIZE(board_types), + .offset = sizeof(struct aio12_8_boardtype), }; - -static int __init driver_aio_aio12_8_init_module(void) -{ - return comedi_driver_register(&driver_aio_aio12_8); -} - -static void __exit driver_aio_aio12_8_cleanup_module(void) -{ - comedi_driver_unregister(&driver_aio_aio12_8); -} - -module_init(driver_aio_aio12_8_init_module); -module_exit(driver_aio_aio12_8_cleanup_module); +module_comedi_driver(aio_aio12_8_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/aio_iiro_16.c b/trunk/drivers/staging/comedi/drivers/aio_iiro_16.c index 160b0a0f4f1e..04f6f94b1f47 100644 --- a/trunk/drivers/staging/comedi/drivers/aio_iiro_16.c +++ b/trunk/drivers/staging/comedi/drivers/aio_iiro_16.c @@ -67,30 +67,41 @@ struct aio_iiro_16_private { #define devpriv ((struct aio_iiro_16_private *) dev->private) -static int aio_iiro_16_attach(struct comedi_device *dev, - struct comedi_devconfig *it); - -static int aio_iiro_16_detach(struct comedi_device *dev); - -static struct comedi_driver driver_aio_iiro_16 = { - .driver_name = "aio_iiro_16", - .module = THIS_MODULE, - .attach = aio_iiro_16_attach, - .detach = aio_iiro_16_detach, - .board_name = &aio_iiro_16_boards[0].name, - .offset = sizeof(struct aio_iiro_16_board), - .num_names = ARRAY_SIZE(aio_iiro_16_boards), -}; +static int aio_iiro_16_dio_insn_bits_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + if (insn->n != 2) + return -EINVAL; + + if (data[0]) { + s->state &= ~data[0]; + s->state |= data[0] & data[1]; + outb(s->state & 0xff, dev->iobase + AIO_IIRO_16_RELAY_0_7); + outb((s->state >> 8) & 0xff, + dev->iobase + AIO_IIRO_16_RELAY_8_15); + } + + data[1] = s->state; + + return 2; +} static int aio_iiro_16_dio_insn_bits_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); + unsigned int *data) +{ + if (insn->n != 2) + return -EINVAL; -static int aio_iiro_16_dio_insn_bits_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); + data[1] = 0; + data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_0_7); + data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_8_15) << 8; + + return 2; +} static int aio_iiro_16_attach(struct comedi_device *dev, struct comedi_devconfig *it) @@ -138,64 +149,22 @@ static int aio_iiro_16_attach(struct comedi_device *dev, return 1; } -static int aio_iiro_16_detach(struct comedi_device *dev) +static void aio_iiro_16_detach(struct comedi_device *dev) { - printk(KERN_INFO "comedi%d: aio_iiro_16: remove\n", dev->minor); - if (dev->iobase) release_region(dev->iobase, AIO_IIRO_16_SIZE); - - return 0; -} - -static int aio_iiro_16_dio_insn_bits_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - if (insn->n != 2) - return -EINVAL; - - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - outb(s->state & 0xff, dev->iobase + AIO_IIRO_16_RELAY_0_7); - outb((s->state >> 8) & 0xff, - dev->iobase + AIO_IIRO_16_RELAY_8_15); - } - - data[1] = s->state; - - return 2; -} - -static int aio_iiro_16_dio_insn_bits_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - if (insn->n != 2) - return -EINVAL; - - data[1] = 0; - data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_0_7); - data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_8_15) << 8; - - return 2; -} - -static int __init driver_aio_iiro_16_init_module(void) -{ - return comedi_driver_register(&driver_aio_iiro_16); } -static void __exit driver_aio_iiro_16_cleanup_module(void) -{ - comedi_driver_unregister(&driver_aio_iiro_16); -} - -module_init(driver_aio_iiro_16_init_module); -module_exit(driver_aio_iiro_16_cleanup_module); +static struct comedi_driver aio_iiro_16_driver = { + .driver_name = "aio_iiro_16", + .module = THIS_MODULE, + .attach = aio_iiro_16_attach, + .detach = aio_iiro_16_detach, + .board_name = &aio_iiro_16_boards[0].name, + .offset = sizeof(struct aio_iiro_16_board), + .num_names = ARRAY_SIZE(aio_iiro_16_boards), +}; +module_comedi_driver(aio_iiro_16_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/amplc_dio200.c b/trunk/drivers/staging/comedi/drivers/amplc_dio200.c index 566cc4411452..c9c5d97b3ca2 100644 --- a/trunk/drivers/staging/comedi/drivers/amplc_dio200.c +++ b/trunk/drivers/staging/comedi/drivers/amplc_dio200.c @@ -217,6 +217,14 @@ order they appear in the channel list. #define DIO200_DRIVER_NAME "amplc_dio200" +#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA_MODULE +#define CONFIG_COMEDI_AMPLC_DIO200_ISA +#endif + +#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI_MODULE +#define CONFIG_COMEDI_AMPLC_DIO200_PCI +#endif + /* PCI IDs */ #define PCI_VENDOR_ID_AMPLICON 0x14dc #define PCI_DEVICE_ID_AMPLICON_PCI272 0x000a @@ -274,10 +282,14 @@ enum dio200_model { }; enum dio200_layout { +#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA pc212_layout, pc214_layout, +#endif pc215_layout, +#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA pc218_layout, +#endif pc272_layout }; @@ -290,6 +302,7 @@ struct dio200_board { }; static const struct dio200_board dio200_boards[] = { +#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA { .name = "pc212e", .bustype = isa_bustype, @@ -308,15 +321,6 @@ static const struct dio200_board dio200_boards[] = { .model = pc215e_model, .layout = pc215_layout, }, -#ifdef CONFIG_COMEDI_PCI - { - .name = "pci215", - .devid = PCI_DEVICE_ID_AMPLICON_PCI215, - .bustype = pci_bustype, - .model = pci215_model, - .layout = pc215_layout, - }, -#endif { .name = "pc218e", .bustype = isa_bustype, @@ -329,7 +333,15 @@ static const struct dio200_board dio200_boards[] = { .model = pc272e_model, .layout = pc272_layout, }, -#ifdef CONFIG_COMEDI_PCI +#endif +#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI + { + .name = "pci215", + .devid = PCI_DEVICE_ID_AMPLICON_PCI215, + .bustype = pci_bustype, + .model = pci215_model, + .layout = pc215_layout, + }, { .name = "pci272", .devid = PCI_DEVICE_ID_AMPLICON_PCI272, @@ -337,8 +349,6 @@ static const struct dio200_board dio200_boards[] = { .model = pci272_model, .layout = pc272_layout, }, -#endif -#ifdef CONFIG_COMEDI_PCI { .name = DIO200_DRIVER_NAME, .devid = PCI_DEVICE_ID_INVALID, @@ -367,6 +377,7 @@ struct dio200_layout_struct { }; static const struct dio200_layout_struct dio200_layouts[] = { +#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA [pc212_layout] = { .n_subdevs = 6, .sdtype = {sd_8255, sd_8254, sd_8254, sd_8254, @@ -385,6 +396,7 @@ static const struct dio200_layout_struct dio200_layouts[] = { .has_int_sce = 0, .has_clk_gat_sce = 0, }, +#endif [pc215_layout] = { .n_subdevs = 5, .sdtype = {sd_8255, sd_8255, sd_8254, @@ -394,6 +406,7 @@ static const struct dio200_layout_struct dio200_layouts[] = { .has_int_sce = 1, .has_clk_gat_sce = 1, }, +#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA [pc218_layout] = { .n_subdevs = 7, .sdtype = {sd_8254, sd_8254, sd_8255, sd_8254, @@ -405,6 +418,7 @@ static const struct dio200_layout_struct dio200_layouts[] = { .has_int_sce = 1, .has_clk_gat_sce = 1, }, +#endif [pc272_layout] = { .n_subdevs = 4, .sdtype = {sd_8255, sd_8255, sd_8255, @@ -419,7 +433,7 @@ static const struct dio200_layout_struct dio200_layouts[] = { * PCI driver table. */ -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI static DEFINE_PCI_DEVICE_TABLE(dio200_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215) }, { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI272) }, @@ -427,7 +441,7 @@ static DEFINE_PCI_DEVICE_TABLE(dio200_pci_table) = { }; MODULE_DEVICE_TABLE(pci, dio200_pci_table); -#endif /* CONFIG_COMEDI_PCI */ +#endif /* CONFIG_COMEDI_AMPLC_DIO200_PCI */ /* * Useful for shorthand access to the particular board structure @@ -441,7 +455,7 @@ MODULE_DEVICE_TABLE(pci, dio200_pci_table); feel free to suggest moving the variable to the struct comedi_device struct. */ struct dio200_private { -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI struct pci_dev *pci_dev; /* PCI device */ #endif int intr_sd; @@ -479,7 +493,7 @@ struct dio200_subdev_intr { */ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int dio200_detach(struct comedi_device *dev); +static void dio200_detach(struct comedi_device *dev); static struct comedi_driver driver_amplc_dio200 = { .driver_name = DIO200_DRIVER_NAME, .module = THIS_MODULE, @@ -490,12 +504,12 @@ static struct comedi_driver driver_amplc_dio200 = { .num_names = ARRAY_SIZE(dio200_boards), }; -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI static int __devinit driver_amplc_dio200_pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, driver_amplc_dio200.driver_name); + return comedi_pci_auto_config(dev, &driver_amplc_dio200); } static void __devexit driver_amplc_dio200_pci_remove(struct pci_dev *dev) @@ -549,7 +563,7 @@ module_exit(driver_amplc_dio200_cleanup_module); * This function looks for a PCI device matching the requested board name, * bus and slot. */ -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI static int dio200_find_pci(struct comedi_device *dev, int bus, int slot, struct pci_dev **pci_dev_p) @@ -611,6 +625,7 @@ dio200_find_pci(struct comedi_device *dev, int bus, int slot, * This function checks and requests an I/O region, reporting an error * if there is a conflict. */ +#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA static int dio200_request_region(unsigned minor, unsigned long from, unsigned long extent) { @@ -621,6 +636,7 @@ dio200_request_region(unsigned minor, unsigned long from, unsigned long extent) } return 0; } +#endif /* * 'insn_bits' function for an 'INTERRUPT' subdevice. @@ -1332,7 +1348,7 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it) struct comedi_subdevice *s; unsigned long iobase = 0; unsigned int irq = 0; -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI struct pci_dev *pci_dev = NULL; int bus = 0, slot = 0; #endif @@ -1354,12 +1370,14 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* Process options. */ switch (thisboard->bustype) { +#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA case isa_bustype: iobase = it->options[0]; irq = it->options[1]; share_irq = 0; break; -#ifdef CONFIG_COMEDI_PCI +#endif +#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI case pci_bustype: bus = it->options[0]; slot = it->options[1]; @@ -1382,7 +1400,7 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it) devpriv->intr_sd = -1; /* Enable device and reserve I/O spaces. */ -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI if (pci_dev) { ret = comedi_pci_enable(pci_dev, DIO200_DRIVER_NAME); if (ret < 0) { @@ -1396,9 +1414,11 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it) } else #endif { +#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA ret = dio200_request_region(dev->minor, iobase, DIO200_IO_SIZE); if (ret < 0) return ret; +#endif } dev->iobase = iobase; @@ -1474,12 +1494,19 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it) } printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name); - if (thisboard->bustype == isa_bustype) { + switch (thisboard->bustype) { +#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA + case isa_bustype: printk("(base %#lx) ", iobase); - } else { -#ifdef CONFIG_COMEDI_PCI + break; +#endif +#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI + case pci_bustype: printk("(pci %s) ", pci_name(pci_dev)); + break; #endif + default: + break; } if (irq) printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE")); @@ -1491,22 +1518,11 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 1; } -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int dio200_detach(struct comedi_device *dev) +static void dio200_detach(struct comedi_device *dev) { const struct dio200_layout_struct *layout; unsigned n; - printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor, - DIO200_DRIVER_NAME); - if (dev->irq) free_irq(dev->irq, dev); if (dev->subdevices) { @@ -1529,7 +1545,7 @@ static int dio200_detach(struct comedi_device *dev) } } if (devpriv) { -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI if (devpriv->pci_dev) { if (dev->iobase) comedi_pci_disable(devpriv->pci_dev); @@ -1537,15 +1553,12 @@ static int dio200_detach(struct comedi_device *dev) } else #endif { +#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA if (dev->iobase) release_region(dev->iobase, DIO200_IO_SIZE); +#endif } } - if (dev->board_name) - printk(KERN_INFO "comedi%d: %s removed\n", - dev->minor, dev->board_name); - - return 0; } MODULE_AUTHOR("Comedi http://www.comedi.org"); diff --git a/trunk/drivers/staging/comedi/drivers/amplc_pc236.c b/trunk/drivers/staging/comedi/drivers/amplc_pc236.c index 7972cadd403e..57ba3228b1a9 100644 --- a/trunk/drivers/staging/comedi/drivers/amplc_pc236.c +++ b/trunk/drivers/staging/comedi/drivers/amplc_pc236.c @@ -63,6 +63,14 @@ unused. #define PC236_DRIVER_NAME "amplc_pc236" +#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA_MODULE +#define CONFIG_COMEDI_AMPLC_PC236_ISA +#endif + +#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI_MODULE +#define CONFIG_COMEDI_AMPLC_PC236_PCI +#endif + /* PCI236 PCI configuration register information */ #define PCI_VENDOR_ID_AMPLICON 0x14dc #define PCI_DEVICE_ID_AMPLICON_PCI236 0x0009 @@ -106,13 +114,15 @@ struct pc236_board { enum pc236_model model; }; static const struct pc236_board pc236_boards[] = { +#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA { .name = "pc36at", .fancy_name = "PC36AT", .bustype = isa_bustype, .model = pc36at_model, }, -#ifdef CONFIG_COMEDI_PCI +#endif +#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI { .name = "pci236", .fancy_name = "PCI236", @@ -120,8 +130,6 @@ static const struct pc236_board pc236_boards[] = { .bustype = pci_bustype, .model = pci236_model, }, -#endif -#ifdef CONFIG_COMEDI_PCI { .name = PC236_DRIVER_NAME, .fancy_name = PC236_DRIVER_NAME, @@ -132,14 +140,14 @@ static const struct pc236_board pc236_boards[] = { #endif }; -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI static DEFINE_PCI_DEVICE_TABLE(pc236_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI236) }, {0} }; MODULE_DEVICE_TABLE(pci, pc236_pci_table); -#endif /* CONFIG_COMEDI_PCI */ +#endif /* CONFIG_COMEDI_AMPLC_PC236_PCI */ /* * Useful for shorthand access to the particular board structure @@ -151,7 +159,7 @@ MODULE_DEVICE_TABLE(pci, pc236_pci_table); feel free to suggest moving the variable to the struct comedi_device struct. */ struct pc236_private { -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI /* PCI device */ struct pci_dev *pci_dev; unsigned long lcr_iobase; /* PLX PCI9052 config registers in PCIBAR1 */ @@ -168,7 +176,7 @@ struct pc236_private { * the device code. */ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int pc236_detach(struct comedi_device *dev); +static void pc236_detach(struct comedi_device *dev); static struct comedi_driver driver_amplc_pc236 = { .driver_name = PC236_DRIVER_NAME, .module = THIS_MODULE, @@ -179,12 +187,12 @@ static struct comedi_driver driver_amplc_pc236 = { .num_names = ARRAY_SIZE(pc236_boards), }; -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI static int __devinit driver_amplc_pc236_pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, driver_amplc_pc236.driver_name); + return comedi_pci_auto_config(dev, &driver_amplc_pc236); } static void __devexit driver_amplc_pc236_pci_remove(struct pci_dev *dev) @@ -234,8 +242,10 @@ module_init(driver_amplc_pc236_init_module); module_exit(driver_amplc_pc236_cleanup_module); #endif +#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA static int pc236_request_region(unsigned minor, unsigned long from, unsigned long extent); +#endif static void pc236_intr_disable(struct comedi_device *dev); static void pc236_intr_enable(struct comedi_device *dev); static int pc236_intr_check(struct comedi_device *dev); @@ -255,7 +265,7 @@ static irqreturn_t pc236_interrupt(int irq, void *d); * This function looks for a PCI device matching the requested board name, * bus and slot. */ -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI static int pc236_find_pci(struct comedi_device *dev, int bus, int slot, struct pci_dev **pci_dev_p) @@ -324,7 +334,7 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it) struct comedi_subdevice *s; unsigned long iobase = 0; unsigned int irq = 0; -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI struct pci_dev *pci_dev = NULL; int bus = 0, slot = 0; #endif @@ -345,12 +355,14 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it) } /* Process options. */ switch (thisboard->bustype) { +#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA case isa_bustype: iobase = it->options[0]; irq = it->options[1]; share_irq = 0; break; -#ifdef CONFIG_COMEDI_PCI +#endif +#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI case pci_bustype: bus = it->options[0]; slot = it->options[1]; @@ -361,7 +373,7 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it) return ret; devpriv->pci_dev = pci_dev; break; -#endif /* CONFIG_COMEDI_PCI */ +#endif default: printk(KERN_ERR "comedi%d: %s: BUG! cannot determine board type!\n", @@ -376,7 +388,7 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it) dev->board_name = thisboard->name; /* Enable device and reserve I/O spaces. */ -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI if (pci_dev) { ret = comedi_pci_enable(pci_dev, PC236_DRIVER_NAME); @@ -392,9 +404,11 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it) } else #endif { +#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA ret = pc236_request_region(dev->minor, iobase, PC236_IO_SIZE); if (ret < 0) return ret; +#endif } dev->iobase = iobase; @@ -439,12 +453,19 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it) } } printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name); - if (thisboard->bustype == isa_bustype) { + switch (thisboard->bustype) { +#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA + case isa_bustype: printk("(base %#lx) ", iobase); - } else { -#ifdef CONFIG_COMEDI_PCI + break; +#endif +#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI + case pci_bustype: printk("(pci %s) ", pci_name(pci_dev)); + break; #endif + default: + break; } if (irq) printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE")); @@ -456,27 +477,16 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 1; } -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int pc236_detach(struct comedi_device *dev) +static void pc236_detach(struct comedi_device *dev) { - printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor, - PC236_DRIVER_NAME); if (devpriv) pc236_intr_disable(dev); - if (dev->irq) free_irq(dev->irq, dev); if (dev->subdevices) subdev_8255_cleanup(dev, dev->subdevices + 0); if (devpriv) { -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI if (devpriv->pci_dev) { if (dev->iobase) comedi_pci_disable(devpriv->pci_dev); @@ -484,21 +494,19 @@ static int pc236_detach(struct comedi_device *dev) } else #endif { +#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA if (dev->iobase) release_region(dev->iobase, PC236_IO_SIZE); +#endif } } - if (dev->board_name) { - printk(KERN_INFO "comedi%d: %s removed\n", - dev->minor, dev->board_name); - } - return 0; } /* * This function checks and requests an I/O region, reporting an error * if there is a conflict. */ +#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA static int pc236_request_region(unsigned minor, unsigned long from, unsigned long extent) { @@ -509,6 +517,7 @@ static int pc236_request_region(unsigned minor, unsigned long from, } return 0; } +#endif /* * This function is called to mark the interrupt as disabled (no command @@ -521,7 +530,7 @@ static void pc236_intr_disable(struct comedi_device *dev) spin_lock_irqsave(&dev->spinlock, flags); devpriv->enable_irq = 0; -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI if (devpriv->lcr_iobase) outl(PCI236_INTR_DISABLE, devpriv->lcr_iobase + PLX9052_INTCSR); #endif @@ -539,7 +548,7 @@ static void pc236_intr_enable(struct comedi_device *dev) spin_lock_irqsave(&dev->spinlock, flags); devpriv->enable_irq = 1; -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI if (devpriv->lcr_iobase) outl(PCI236_INTR_ENABLE, devpriv->lcr_iobase + PLX9052_INTCSR); #endif @@ -561,7 +570,7 @@ static int pc236_intr_check(struct comedi_device *dev) spin_lock_irqsave(&dev->spinlock, flags); if (devpriv->enable_irq) { retval = 1; -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI if (devpriv->lcr_iobase) { if ((inl(devpriv->lcr_iobase + PLX9052_INTCSR) & PLX9052_INTCSR_LI1STAT_MASK) diff --git a/trunk/drivers/staging/comedi/drivers/amplc_pc263.c b/trunk/drivers/staging/comedi/drivers/amplc_pc263.c index 191ac0d23ce7..974d7450051e 100644 --- a/trunk/drivers/staging/comedi/drivers/amplc_pc263.c +++ b/trunk/drivers/staging/comedi/drivers/amplc_pc263.c @@ -50,6 +50,14 @@ The state of the outputs can be read. #define PC263_DRIVER_NAME "amplc_pc263" +#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA_MODULE +#define CONFIG_COMEDI_AMPLC_PC263_ISA +#endif + +#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI_MODULE +#define CONFIG_COMEDI_AMPLC_PC263_PCI +#endif + /* PCI263 PCI configuration register information */ #define PCI_VENDOR_ID_AMPLICON 0x14dc #define PCI_DEVICE_ID_AMPLICON_PCI263 0x000c @@ -73,13 +81,15 @@ struct pc263_board { enum pc263_model model; }; static const struct pc263_board pc263_boards[] = { +#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA { .name = "pc263", .fancy_name = "PC263", .bustype = isa_bustype, .model = pc263_model, }, -#ifdef CONFIG_COMEDI_PCI +#endif +#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI { .name = "pci263", .fancy_name = "PCI263", @@ -87,8 +97,6 @@ static const struct pc263_board pc263_boards[] = { .bustype = pci_bustype, .model = pci263_model, }, -#endif -#ifdef CONFIG_COMEDI_PCI { .name = PC263_DRIVER_NAME, .fancy_name = PC263_DRIVER_NAME, @@ -99,14 +107,14 @@ static const struct pc263_board pc263_boards[] = { #endif }; -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI static DEFINE_PCI_DEVICE_TABLE(pc263_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI263) }, {0} }; MODULE_DEVICE_TABLE(pci, pc263_pci_table); -#endif /* CONFIG_COMEDI_PCI */ +#endif /* CONFIG_COMEDI_AMPLC_PC263_PCI */ /* * Useful for shorthand access to the particular board structure @@ -117,14 +125,14 @@ MODULE_DEVICE_TABLE(pci, pc263_pci_table); several hardware drivers keep similar information in this structure, feel free to suggest moving the variable to the struct comedi_device struct. */ -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI struct pc263_private { /* PCI device. */ struct pci_dev *pci_dev; }; #define devpriv ((struct pc263_private *)dev->private) -#endif /* CONFIG_COMEDI_PCI */ +#endif /* CONFIG_COMEDI_AMPLC_PC263_PCI */ /* * The struct comedi_driver structure tells the Comedi core module @@ -133,7 +141,7 @@ struct pc263_private { * the device code. */ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int pc263_detach(struct comedi_device *dev); +static void pc263_detach(struct comedi_device *dev); static struct comedi_driver driver_amplc_pc263 = { .driver_name = PC263_DRIVER_NAME, .module = THIS_MODULE, @@ -144,8 +152,10 @@ static struct comedi_driver driver_amplc_pc263 = { .num_names = ARRAY_SIZE(pc263_boards), }; +#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA static int pc263_request_region(unsigned minor, unsigned long from, unsigned long extent); +#endif static int pc263_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); @@ -157,7 +167,7 @@ static int pc263_dio_insn_config(struct comedi_device *dev, * This function looks for a PCI device matching the requested board name, * bus and slot. */ -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI static int pc263_find_pci(struct comedi_device *dev, int bus, int slot, struct pci_dev **pci_dev_p) @@ -225,7 +235,7 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; unsigned long iobase = 0; -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI struct pci_dev *pci_dev = NULL; int bus = 0, slot = 0; #endif @@ -237,7 +247,7 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it) * Allocate the private structure area. alloc_private() is a * convenient macro defined in comedidev.h. */ -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI ret = alloc_private(dev, sizeof(struct pc263_private)); if (ret < 0) { printk(KERN_ERR "comedi%d: error! out of memory!\n", @@ -247,10 +257,12 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it) #endif /* Process options. */ switch (thisboard->bustype) { +#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA case isa_bustype: iobase = it->options[0]; break; -#ifdef CONFIG_COMEDI_PCI +#endif +#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI case pci_bustype: bus = it->options[0]; slot = it->options[1]; @@ -260,7 +272,7 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it) return ret; devpriv->pci_dev = pci_dev; break; -#endif /* CONFIG_COMEDI_PCI */ +#endif default: printk(KERN_ERR "comedi%d: %s: BUG! cannot determine board type!\n", @@ -275,7 +287,7 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it) dev->board_name = thisboard->name; /* Enable device and reserve I/O spaces. */ -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI if (pci_dev) { ret = comedi_pci_enable(pci_dev, PC263_DRIVER_NAME); if (ret < 0) { @@ -289,9 +301,11 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it) } else #endif { +#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA ret = pc263_request_region(dev->minor, iobase, PC263_IO_SIZE); if (ret < 0) return ret; +#endif } dev->iobase = iobase; @@ -322,12 +336,18 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->state = s->state | (inb(dev->iobase) << 8); printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name); - if (thisboard->bustype == isa_bustype) { + switch (thisboard->bustype) { +#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA + case isa_bustype: printk("(base %#lx) ", iobase); - } else { -#ifdef CONFIG_COMEDI_PCI + break; +#endif +#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI printk("(pci %s) ", pci_name(pci_dev)); + break; #endif + default: + break; } printk("attached\n"); @@ -335,23 +355,13 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 1; } -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int pc263_detach(struct comedi_device *dev) +static void pc263_detach(struct comedi_device *dev) { - printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor, - PC263_DRIVER_NAME); - -#ifdef CONFIG_COMEDI_PCI - if (devpriv) { +#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI + if (devpriv) #endif -#ifdef CONFIG_COMEDI_PCI + { +#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI if (devpriv->pci_dev) { if (dev->iobase) comedi_pci_disable(devpriv->pci_dev); @@ -359,21 +369,19 @@ static int pc263_detach(struct comedi_device *dev) } else #endif { +#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA if (dev->iobase) release_region(dev->iobase, PC263_IO_SIZE); +#endif } } - if (dev->board_name) { - printk(KERN_INFO "comedi%d: %s removed\n", - dev->minor, dev->board_name); - } - return 0; } /* * This function checks and requests an I/O region, reporting an error * if there is a conflict. */ +#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA static int pc263_request_region(unsigned minor, unsigned long from, unsigned long extent) { @@ -384,6 +392,7 @@ static int pc263_request_region(unsigned minor, unsigned long from, } return 0; } +#endif /* DIO devices are slightly special. Although it is possible to * implement the insn_read/insn_write interface, it is much more @@ -429,12 +438,12 @@ static int pc263_dio_insn_config(struct comedi_device *dev, * A convenient macro that defines init_module() and cleanup_module(), * as necessary. */ -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI static int __devinit driver_amplc_pc263_pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, driver_amplc_pc263.driver_name); + return comedi_pci_auto_config(dev, &driver_amplc_pc263); } static void __devexit driver_amplc_pc263_pci_remove(struct pci_dev *dev) diff --git a/trunk/drivers/staging/comedi/drivers/amplc_pci224.c b/trunk/drivers/staging/comedi/drivers/amplc_pci224.c index b278917cec25..fbf19cae8747 100644 --- a/trunk/drivers/staging/comedi/drivers/amplc_pci224.c +++ b/trunk/drivers/staging/comedi/drivers/amplc_pci224.c @@ -379,18 +379,6 @@ static const struct pci224_board pci224_boards[] = { }, }; -/* - * PCI driver table. - */ - -static DEFINE_PCI_DEVICE_TABLE(pci224_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI224) }, - { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI234) }, - {0} -}; - -MODULE_DEVICE_TABLE(pci, pci224_pci_table); - /* * Useful for shorthand access to the particular board structure */ @@ -421,65 +409,6 @@ struct pci224_private { #define devpriv ((struct pci224_private *)dev->private) -/* - * The struct comedi_driver structure tells the Comedi core module - * which functions to call to configure/deconfigure (attach/detach) - * the board, and also about the kernel module that contains - * the device code. - */ -static int pci224_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pci224_detach(struct comedi_device *dev); -static struct comedi_driver driver_amplc_pci224 = { - .driver_name = DRIVER_NAME, - .module = THIS_MODULE, - .attach = pci224_attach, - .detach = pci224_detach, - .board_name = &pci224_boards[0].name, - .offset = sizeof(struct pci224_board), - .num_names = ARRAY_SIZE(pci224_boards), -}; - -static int __devinit driver_amplc_pci224_pci_probe(struct pci_dev *dev, - const struct pci_device_id - *ent) -{ - return comedi_pci_auto_config(dev, driver_amplc_pci224.driver_name); -} - -static void __devexit driver_amplc_pci224_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_amplc_pci224_pci_driver = { - .id_table = pci224_pci_table, - .probe = &driver_amplc_pci224_pci_probe, - .remove = __devexit_p(&driver_amplc_pci224_pci_remove) -}; - -static int __init driver_amplc_pci224_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_amplc_pci224); - if (retval < 0) - return retval; - - driver_amplc_pci224_pci_driver.name = - (char *)driver_amplc_pci224.driver_name; - return pci_register_driver(&driver_amplc_pci224_pci_driver); -} - -static void __exit driver_amplc_pci224_cleanup_module(void) -{ - pci_unregister_driver(&driver_amplc_pci224_pci_driver); - comedi_driver_unregister(&driver_amplc_pci224); -} - -module_init(driver_amplc_pci224_init_module); -module_exit(driver_amplc_pci224_cleanup_module); - /* * Called from the 'insn_write' function to perform a single write. */ @@ -1311,6 +1240,20 @@ static irqreturn_t pci224_interrupt(int irq, void *d) return IRQ_RETVAL(retval); } +/* + * This function looks for a board matching the supplied PCI device. + */ +static const struct pci224_board +*pci224_find_pci_board(struct pci_dev *pci_dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(pci224_boards); i++) + if (pci_dev->device == pci224_boards[i].devid) + return &pci224_boards[i]; + return NULL; +} + /* * This function looks for a PCI device matching the requested board name, * bus and slot. @@ -1336,17 +1279,12 @@ pci224_find_pci(struct comedi_device *dev, int bus, int slot, } if (thisboard->model == any_model) { /* Match any supported model. */ - int i; - - for (i = 0; i < ARRAY_SIZE(pci224_boards); i++) { - if (pci_dev->device == pci224_boards[i].devid) { - /* Change board_ptr to matched board. */ - dev->board_ptr = &pci224_boards[i]; - break; - } - } - if (i == ARRAY_SIZE(pci224_boards)) + const struct pci224_board *board_ptr; + board_ptr = pci224_find_pci_board(pci_dev); + if (board_ptr == NULL) continue; + /* Change board_ptr to matched board. */ + dev->board_ptr = board_ptr; } else { /* Match specific model name. */ if (thisboard->devid != pci_dev->device) @@ -1370,35 +1308,16 @@ pci224_find_pci(struct comedi_device *dev, int bus, int slot, } /* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. + * Common part of attach and attach_pci. */ -static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int pci224_attach_common(struct comedi_device *dev, + struct pci_dev *pci_dev, int *options) { struct comedi_subdevice *s; - struct pci_dev *pci_dev; unsigned int irq; - int bus = 0, slot = 0; unsigned n; int ret; - printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor, DRIVER_NAME); - - bus = it->options[0]; - slot = it->options[1]; - ret = alloc_private(dev, sizeof(struct pci224_private)); - if (ret < 0) { - printk(KERN_ERR "comedi%d: error! out of memory!\n", - dev->minor); - return ret; - } - - ret = pci224_find_pci(dev, bus, slot, &pci_dev); - if (ret < 0) - return ret; - devpriv->pci_dev = pci_dev; ret = comedi_pci_enable(pci_dev, DRIVER_NAME); if (ret < 0) { @@ -1483,24 +1402,26 @@ static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (!s->range_table_list) return -ENOMEM; - for (n = 2; n < 3 + s->n_chan; n++) { - if (it->options[n] < 0 || it->options[n] > 1) { - printk(KERN_WARNING "comedi%d: %s: warning! " - "bad options[%u]=%d\n", - dev->minor, DRIVER_NAME, n, - it->options[n]); + if (options) { + for (n = 2; n < 3 + s->n_chan; n++) { + if (options[n] < 0 || options[n] > 1) { + printk(KERN_WARNING + "comedi%d: %s: warning! bad options[%u]=%d\n", + dev->minor, DRIVER_NAME, n, + options[n]); + } } } for (n = 0; n < s->n_chan; n++) { - if (n < COMEDI_NDEVCONFOPTS - 3 && - it->options[3 + n] == 1) { - if (it->options[2] == 1) + if (n < COMEDI_NDEVCONFOPTS - 3 && options && + options[3 + n] == 1) { + if (options[2] == 1) range_table_list[n] = &range_pci234_ext; else range_table_list[n] = &range_bipolar5; } else { - if (it->options[2] == 1) { + if (options && options[2] == 1) { range_table_list[n] = &range_pci234_ext2; } else { @@ -1511,14 +1432,14 @@ static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it) devpriv->hwrange = hwrange_pci234; } else { /* PCI224 range options. */ - if (it->options[2] == 1) { + if (options && options[2] == 1) { s->range_table = &range_pci224_external; devpriv->hwrange = hwrange_pci224_external; } else { - if (it->options[2] != 0) { + if (options && options[2] != 0) { printk(KERN_WARNING "comedi%d: %s: warning! " "bad options[2]=%d\n", - dev->minor, DRIVER_NAME, it->options[2]); + dev->minor, DRIVER_NAME, options[2]); } s->range_table = &range_pci224_internal; devpriv->hwrange = hwrange_pci224_internal; @@ -1552,21 +1473,59 @@ static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 1; } -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int pci224_detach(struct comedi_device *dev) +static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it) +{ + struct pci_dev *pci_dev; + int bus, slot; + int ret; + + printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor, DRIVER_NAME); + + bus = it->options[0]; + slot = it->options[1]; + ret = alloc_private(dev, sizeof(struct pci224_private)); + if (ret < 0) { + printk(KERN_ERR "comedi%d: error! out of memory!\n", + dev->minor); + return ret; + } + + ret = pci224_find_pci(dev, bus, slot, &pci_dev); + if (ret < 0) + return ret; + + return pci224_attach_common(dev, pci_dev, it->options); +} + +static int +pci224_attach_pci(struct comedi_device *dev, struct pci_dev *pci_dev) { - printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor, DRIVER_NAME); + int ret; + + printk(KERN_DEBUG "comedi%d: %s: attach_pci %s\n", dev->minor, + DRIVER_NAME, pci_name(pci_dev)); + + ret = alloc_private(dev, sizeof(struct pci224_private)); + if (ret < 0) { + printk(KERN_ERR "comedi%d: error! out of memory!\n", + dev->minor); + return ret; + } + dev->board_ptr = pci224_find_pci_board(pci_dev); + if (dev->board_ptr == NULL) { + printk(KERN_ERR + "comedi%d: %s: BUG! cannot determine board type!\n", + dev->minor, DRIVER_NAME); + return -EINVAL; + } + return pci224_attach_common(dev, pci_dev, NULL); +} + +static void pci224_detach(struct comedi_device *dev) +{ if (dev->irq) free_irq(dev->irq, dev); - if (dev->subdevices) { struct comedi_subdevice *s; @@ -1581,18 +1540,49 @@ static int pci224_detach(struct comedi_device *dev) if (devpriv->pci_dev) { if (dev->iobase) comedi_pci_disable(devpriv->pci_dev); - pci_dev_put(devpriv->pci_dev); } } - if (dev->board_name) { - printk(KERN_INFO "comedi%d: %s removed\n", - dev->minor, dev->board_name); - } +} - return 0; +static struct comedi_driver amplc_pci224_driver = { + .driver_name = "amplc_pci224", + .module = THIS_MODULE, + .attach = pci224_attach, + .detach = pci224_detach, + .attach_pci = pci224_attach_pci, + .board_name = &pci224_boards[0].name, + .offset = sizeof(struct pci224_board), + .num_names = ARRAY_SIZE(pci224_boards), +}; + +static int __devinit amplc_pci224_pci_probe(struct pci_dev *dev, + const struct pci_device_id + *ent) +{ + return comedi_pci_auto_config(dev, &lc_pci224_driver); } +static void __devexit amplc_pci224_pci_remove(struct pci_dev *dev) +{ + comedi_pci_auto_unconfig(dev); +} + +static DEFINE_PCI_DEVICE_TABLE(amplc_pci224_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI224) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI234) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, amplc_pci224_pci_table); + +static struct pci_driver amplc_pci224_pci_driver = { + .name = "amplc_pci224", + .id_table = amplc_pci224_pci_table, + .probe = amplc_pci224_pci_probe, + .remove = __devexit_p(amplc_pci224_pci_remove), +}; +module_comedi_pci_driver(amplc_pci224_driver, amplc_pci224_pci_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/amplc_pci230.c b/trunk/drivers/staging/comedi/drivers/amplc_pci230.c index 538979551c8e..d4c80b1281f2 100644 --- a/trunk/drivers/staging/comedi/drivers/amplc_pci230.c +++ b/trunk/drivers/staging/comedi/drivers/amplc_pci230.c @@ -500,13 +500,6 @@ static const struct pci230_board pci230_boards[] = { }, }; -static DEFINE_PCI_DEVICE_TABLE(pci230_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI230) }, - { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI260) }, - {0} -}; - -MODULE_DEVICE_TABLE(pci, pci230_pci_table); /* * Useful for shorthand access to the particular board structure */ @@ -595,65 +588,6 @@ static const struct comedi_lrange pci230_ao_range = { 2, { /* PCI230 daccon bipolar flag for each analogue output range. */ static const unsigned char pci230_ao_bipolar[2] = { 0, 1 }; -/* - * The struct comedi_driver structure tells the Comedi core module - * which functions to call to configure/deconfigure (attach/detach) - * the board, and also about the kernel module that contains - * the device code. - */ -static int pci230_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pci230_detach(struct comedi_device *dev); -static struct comedi_driver driver_amplc_pci230 = { - .driver_name = "amplc_pci230", - .module = THIS_MODULE, - .attach = pci230_attach, - .detach = pci230_detach, - .board_name = &pci230_boards[0].name, - .offset = sizeof(pci230_boards[0]), - .num_names = ARRAY_SIZE(pci230_boards), -}; - -static int __devinit driver_amplc_pci230_pci_probe(struct pci_dev *dev, - const struct pci_device_id - *ent) -{ - return comedi_pci_auto_config(dev, driver_amplc_pci230.driver_name); -} - -static void __devexit driver_amplc_pci230_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_amplc_pci230_pci_driver = { - .id_table = pci230_pci_table, - .probe = &driver_amplc_pci230_pci_probe, - .remove = __devexit_p(&driver_amplc_pci230_pci_remove) -}; - -static int __init driver_amplc_pci230_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_amplc_pci230); - if (retval < 0) - return retval; - - driver_amplc_pci230_pci_driver.name = - (char *)driver_amplc_pci230.driver_name; - return pci_register_driver(&driver_amplc_pci230_pci_driver); -} - -static void __exit driver_amplc_pci230_cleanup_module(void) -{ - pci_unregister_driver(&driver_amplc_pci230_pci_driver); - comedi_driver_unregister(&driver_amplc_pci230); -} - -module_init(driver_amplc_pci230_init_module); -module_exit(driver_amplc_pci230_cleanup_module); - static int pci230_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); @@ -1003,35 +937,19 @@ static int pci230_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 1; } -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int pci230_detach(struct comedi_device *dev) +static void pci230_detach(struct comedi_device *dev) { - printk("comedi%d: amplc_pci230: remove\n", dev->minor); - if (dev->subdevices && thisboard->have_dio) - /* Clean up dio subdevice. */ subdev_8255_cleanup(dev, dev->subdevices + 2); - if (dev->irq) free_irq(dev->irq, dev); - if (devpriv) { if (devpriv->pci_dev) { if (dev->iobase) comedi_pci_disable(devpriv->pci_dev); - pci_dev_put(devpriv->pci_dev); } } - - return 0; } static int get_resources(struct comedi_device *dev, unsigned int res_mask, @@ -3048,6 +2966,42 @@ static int pci230_ai_cancel(struct comedi_device *dev, return 0; } +static struct comedi_driver amplc_pci230_driver = { + .driver_name = "amplc_pci230", + .module = THIS_MODULE, + .attach = pci230_attach, + .detach = pci230_detach, + .board_name = &pci230_boards[0].name, + .offset = sizeof(pci230_boards[0]), + .num_names = ARRAY_SIZE(pci230_boards), +}; + +static int __devinit amplc_pci230_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + return comedi_pci_auto_config(dev, &lc_pci230_driver); +} + +static void __devexit amplc_pci230_pci_remove(struct pci_dev *dev) +{ + comedi_pci_auto_unconfig(dev); +} + +static DEFINE_PCI_DEVICE_TABLE(amplc_pci230_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI230) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI260) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, amplc_pci230_pci_table); + +static struct pci_driver amplc_pci230_pci_driver = { + .name = "amplc_pci230", + .id_table = amplc_pci230_pci_table, + .probe = amplc_pci230_pci_probe, + .remove = __devexit_p(amplc_pci230_pci_remove) +}; +module_comedi_pci_driver(amplc_pci230_driver, amplc_pci230_pci_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/c6xdigio.c b/trunk/drivers/staging/comedi/drivers/c6xdigio.c index 11cdaf2a5aa5..fb9951a746a6 100644 --- a/trunk/drivers/staging/comedi/drivers/c6xdigio.c +++ b/trunk/drivers/staging/comedi/drivers/c6xdigio.c @@ -97,16 +97,6 @@ union encvaluetype { #define C6XDIGIO_TIME_OUT 20 -static int c6xdigio_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int c6xdigio_detach(struct comedi_device *dev); -struct comedi_driver driver_c6xdigio = { - .driver_name = "c6xdigio", - .module = THIS_MODULE, - .attach = c6xdigio_attach, - .detach = c6xdigio_detach, -}; - static void C6X_pwmInit(unsigned long baseAddr) { int timeout = 0; @@ -407,10 +397,6 @@ static void board_init(struct comedi_device *dev) } -/* static void board_halt(struct comedi_device *dev) { */ -/* C6X_pwmInit(dev->iobase); */ -/* } */ - /* options[0] - I/O port options[1] - irq @@ -500,36 +486,22 @@ static int c6xdigio_attach(struct comedi_device *dev, return 0; } -static int c6xdigio_detach(struct comedi_device *dev) +static void c6xdigio_detach(struct comedi_device *dev) { - /* board_halt(dev); may not need this */ - - printk(KERN_DEBUG "comedi%d: c6xdigio: remove\n", dev->minor); - if (dev->iobase) release_region(dev->iobase, C6XDIGIO_SIZE); - - /* Not using IRQ so I am not sure if I need this */ if (dev->irq) free_irq(dev->irq, dev); - pnp_unregister_driver(&c6xdigio_pnp_driver); - - return 0; -} - -static int __init driver_c6xdigio_init_module(void) -{ - return comedi_driver_register(&driver_c6xdigio); } -static void __exit driver_c6xdigio_cleanup_module(void) -{ - comedi_driver_unregister(&driver_c6xdigio); -} - -module_init(driver_c6xdigio_init_module); -module_exit(driver_c6xdigio_cleanup_module); +static struct comedi_driver c6xdigio_driver = { + .driver_name = "c6xdigio", + .module = THIS_MODULE, + .attach = c6xdigio_attach, + .detach = c6xdigio_detach, +}; +module_comedi_driver(c6xdigio_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/cb_das16_cs.c b/trunk/drivers/staging/comedi/drivers/cb_das16_cs.c index 49404f49f7b7..35159235a1b6 100644 --- a/trunk/drivers/staging/comedi/drivers/cb_das16_cs.c +++ b/trunk/drivers/staging/comedi/drivers/cb_das16_cs.c @@ -91,7 +91,7 @@ struct das16cs_private { static int das16cs_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int das16cs_detach(struct comedi_device *dev); +static void das16cs_detach(struct comedi_device *dev); static struct comedi_driver driver_das16cs = { .driver_name = "cb_das16_cs", .module = THIS_MODULE, @@ -255,15 +255,10 @@ static int das16cs_attach(struct comedi_device *dev, return 1; } -static int das16cs_detach(struct comedi_device *dev) +static void das16cs_detach(struct comedi_device *dev) { - dev_dbg(dev->hw_dev, "comedi%d: das16cs: remove\n", dev->minor); - if (dev->irq) free_irq(dev->irq, dev); - - - return 0; } static irqreturn_t das16cs_interrupt(int irq, void *d) diff --git a/trunk/drivers/staging/comedi/drivers/cb_pcidas.c b/trunk/drivers/staging/comedi/drivers/cb_pcidas.c index 7e4ffcfdac62..ee9e084bb96c 100644 --- a/trunk/drivers/staging/comedi/drivers/cb_pcidas.c +++ b/trunk/drivers/staging/comedi/drivers/cb_pcidas.c @@ -405,20 +405,6 @@ static const struct cb_pcidas_board cb_pcidas_boards[] = { }, }; -static DEFINE_PCI_DEVICE_TABLE(cb_pcidas_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0001) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x000f) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0010) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0019) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001c) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x004c) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001a) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001b) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, cb_pcidas_pci_table); - /* * Useful for shorthand access to the particular board structure */ @@ -462,22 +448,6 @@ struct cb_pcidas_private { */ #define devpriv ((struct cb_pcidas_private *)dev->private) -/* - * The struct comedi_driver structure tells the Comedi core module - * which functions to call to configure/deconfigure (attach/detach) - * the board, and also about the kernel module that contains - * the device code. - */ -static int cb_pcidas_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int cb_pcidas_detach(struct comedi_device *dev); -static struct comedi_driver driver_cb_pcidas = { - .driver_name = "cb_pcidas", - .module = THIS_MODULE, - .attach = cb_pcidas_attach, - .detach = cb_pcidas_detach, -}; - static int cb_pcidas_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); @@ -756,26 +726,12 @@ static int cb_pcidas_attach(struct comedi_device *dev, return 1; } -/* - * cb_pcidas_detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int cb_pcidas_detach(struct comedi_device *dev) +static void cb_pcidas_detach(struct comedi_device *dev) { - if (devpriv) { if (devpriv->s5933_config) { - /* disable and clear interrupts on amcc s5933 */ outl(INTCSR_INBOX_INTR_STATUS, devpriv->s5933_config + AMCC_OP_REG_INTCSR); -#ifdef CB_PCIDAS_DEBUG - dev_dbg(dev->hw_dev, "detaching, incsr is 0x%x\n", - inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR)); -#endif } } if (dev->irq) @@ -787,8 +743,6 @@ static int cb_pcidas_detach(struct comedi_device *dev) comedi_pci_disable(devpriv->pci_dev); pci_dev_put(devpriv->pci_dev); } - - return 0; } /* @@ -1918,47 +1872,44 @@ static int nvram_read(struct comedi_device *dev, unsigned int address, return 0; } -/* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. - */ -static int __devinit driver_cb_pcidas_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) +static struct comedi_driver cb_pcidas_driver = { + .driver_name = "cb_pcidas", + .module = THIS_MODULE, + .attach = cb_pcidas_attach, + .detach = cb_pcidas_detach, +}; + +static int __devinit cb_pcidas_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, driver_cb_pcidas.driver_name); + return comedi_pci_auto_config(dev, &cb_pcidas_driver); } -static void __devexit driver_cb_pcidas_pci_remove(struct pci_dev *dev) +static void __devexit cb_pcidas_pci_remove(struct pci_dev *dev) { comedi_pci_auto_unconfig(dev); } -static struct pci_driver driver_cb_pcidas_pci_driver = { - .id_table = cb_pcidas_pci_table, - .probe = &driver_cb_pcidas_pci_probe, - .remove = __devexit_p(&driver_cb_pcidas_pci_remove) +static DEFINE_PCI_DEVICE_TABLE(cb_pcidas_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0001) }, + { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x000f) }, + { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0010) }, + { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0019) }, + { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001c) }, + { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x004c) }, + { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001a) }, + { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001b) }, + { 0 } }; +MODULE_DEVICE_TABLE(pci, cb_pcidas_pci_table); -static int __init driver_cb_pcidas_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_cb_pcidas); - if (retval < 0) - return retval; - - driver_cb_pcidas_pci_driver.name = (char *)driver_cb_pcidas.driver_name; - return pci_register_driver(&driver_cb_pcidas_pci_driver); -} - -static void __exit driver_cb_pcidas_cleanup_module(void) -{ - pci_unregister_driver(&driver_cb_pcidas_pci_driver); - comedi_driver_unregister(&driver_cb_pcidas); -} - -module_init(driver_cb_pcidas_init_module); -module_exit(driver_cb_pcidas_cleanup_module); +static struct pci_driver cb_pcidas_pci_driver = { + .name = "cb_pcidas", + .id_table = cb_pcidas_pci_table, + .probe = cb_pcidas_pci_probe, + .remove = __devexit_p(cb_pcidas_pci_remove) +}; +module_comedi_pci_driver(cb_pcidas_driver, cb_pcidas_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/cb_pcidas64.c b/trunk/drivers/staging/comedi/drivers/cb_pcidas64.c index 915157d47805..9d0b8754ff5b 100644 --- a/trunk/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/trunk/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -1026,31 +1026,6 @@ static const struct pcidas64_board pcidas64_boards[] = { #endif }; -static DEFINE_PCI_DEVICE_TABLE(pcidas64_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x001d) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x001e) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0035) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0036) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0037) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0052) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005d) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005e) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005f) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0061) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0062) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0063) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0064) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0066) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0067) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0068) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x006f) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0078) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0079) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, pcidas64_pci_table); - static inline struct pcidas64_board *board(const struct comedi_device *dev) { return (struct pcidas64_board *)dev->board_ptr; @@ -1127,21 +1102,6 @@ static inline struct pcidas64_private *priv(struct comedi_device *dev) return dev->private; } -/* - * The comedi_driver structure tells the Comedi core module - * which functions to call to configure/deconfigure (attach/detach) - * the board, and also about the kernel module that contains - * the device code. - */ -static int attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int detach(struct comedi_device *dev); -static struct comedi_driver driver_cb_pcidas = { - .driver_name = "cb_pcidas64", - .module = THIS_MODULE, - .attach = attach, - .detach = detach, -}; - static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); static int ai_config_insn(struct comedi_device *dev, struct comedi_subdevice *s, @@ -1216,44 +1176,6 @@ static unsigned int get_ao_divisor(unsigned int ns, unsigned int flags); static void load_ao_dma(struct comedi_device *dev, const struct comedi_cmd *cmd); -static int __devinit driver_cb_pcidas_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, driver_cb_pcidas.driver_name); -} - -static void __devexit driver_cb_pcidas_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_cb_pcidas_pci_driver = { - .id_table = pcidas64_pci_table, - .probe = &driver_cb_pcidas_pci_probe, - .remove = __devexit_p(&driver_cb_pcidas_pci_remove) -}; - -static int __init driver_cb_pcidas_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_cb_pcidas); - if (retval < 0) - return retval; - - driver_cb_pcidas_pci_driver.name = (char *)driver_cb_pcidas.driver_name; - return pci_register_driver(&driver_cb_pcidas_pci_driver); -} - -static void __exit driver_cb_pcidas_cleanup_module(void) -{ - pci_unregister_driver(&driver_cb_pcidas_pci_driver); - comedi_driver_unregister(&driver_cb_pcidas); -} - -module_init(driver_cb_pcidas_init_module); -module_exit(driver_cb_pcidas_cleanup_module); - static unsigned int ai_range_bits_6xxx(const struct comedi_device *dev, unsigned int range_index) { @@ -1781,7 +1703,7 @@ static int attach(struct comedi_device *dev, struct comedi_devconfig *it) dev_dbg(dev->hw_dev, "Found %s on bus %i, slot %i\n", board(dev)->name, pcidev->bus->number, PCI_SLOT(pcidev->devfn)); - if (comedi_pci_enable(pcidev, driver_cb_pcidas.driver_name)) { + if (comedi_pci_enable(pcidev, dev->driver->driver_name)) { dev_warn(dev->hw_dev, "failed to enable PCI device and request regions\n"); return -EIO; } @@ -1868,15 +1790,7 @@ static int attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int detach(struct comedi_device *dev) +static void detach(struct comedi_device *dev) { unsigned int i; @@ -1938,8 +1852,6 @@ static int detach(struct comedi_device *dev) } if (dev->subdevices) subdev_8255_cleanup(dev, dev->subdevices + 4); - - return 0; } static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, @@ -4315,6 +4227,56 @@ static void i2c_write(struct comedi_device *dev, unsigned int address, i2c_stop(dev); } +static struct comedi_driver cb_pcidas64_driver = { + .driver_name = "cb_pcidas64", + .module = THIS_MODULE, + .attach = attach, + .detach = detach, +}; + +static int __devinit cb_pcidas64_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + return comedi_pci_auto_config(dev, &cb_pcidas64_driver); +} + +static void __devexit cb_pcidas64_pci_remove(struct pci_dev *dev) +{ + comedi_pci_auto_unconfig(dev); +} + +static DEFINE_PCI_DEVICE_TABLE(cb_pcidas64_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x001d) }, + { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x001e) }, + { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0035) }, + { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0036) }, + { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0037) }, + { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0052) }, + { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005d) }, + { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005e) }, + { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005f) }, + { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0061) }, + { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0062) }, + { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0063) }, + { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0064) }, + { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0066) }, + { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0067) }, + { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0068) }, + { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x006f) }, + { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0078) }, + { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0079) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, cb_pcidas64_pci_table); + +static struct pci_driver cb_pcidas64_pci_driver = { + .name = "cb_pcidas64", + .id_table = cb_pcidas64_pci_table, + .probe = cb_pcidas64_pci_probe, + .remove = __devexit_p(cb_pcidas64_pci_remove), +}; +module_comedi_pci_driver(cb_pcidas64_driver, cb_pcidas64_pci_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/cb_pcidda.c b/trunk/drivers/staging/comedi/drivers/cb_pcidda.c index abba220a767f..25ebca11eadc 100644 --- a/trunk/drivers/staging/comedi/drivers/cb_pcidda.c +++ b/trunk/drivers/staging/comedi/drivers/cb_pcidda.c @@ -51,9 +51,12 @@ Please report success/failure with other different cards to #include "comedi_pci.h" #include "8255.h" -#define PCI_VENDOR_ID_CB 0x1307 /* PCI vendor number of ComputerBoards */ + +/* PCI vendor number of ComputerBoards */ +#define PCI_VENDOR_ID_CB 0x1307 #define EEPROM_SIZE 128 /* number of entries in eeprom */ -#define MAX_AO_CHANNELS 8 /* maximum number of ao channels for supported boards */ +/* maximum number of ao channels for supported boards */ +#define MAX_AO_CHANNELS 8 /* PCI-DDA base addresses */ #define DIGITALIO_BADRINDEX 2 @@ -94,20 +97,26 @@ Please report success/failure with other different cards to #define DACALIBRATION1 4 /* D/A CALIBRATION REGISTER 1 */ /* write bits */ -#define SERIAL_IN_BIT 0x1 /* serial data input for eeprom, caldacs, reference dac */ +/* serial data input for eeprom, caldacs, reference dac */ +#define SERIAL_IN_BIT 0x1 #define CAL_CHANNEL_MASK (0x7 << 1) #define CAL_CHANNEL_BITS(channel) (((channel) << 1) & CAL_CHANNEL_MASK) /* read bits */ #define CAL_COUNTER_MASK 0x1f -#define CAL_COUNTER_OVERFLOW_BIT 0x20 /* calibration counter overflow status bit */ -#define AO_BELOW_REF_BIT 0x40 /* analog output is less than reference dac voltage */ +/* calibration counter overflow status bit */ +#define CAL_COUNTER_OVERFLOW_BIT 0x20 +/* analog output is less than reference dac voltage */ +#define AO_BELOW_REF_BIT 0x40 #define SERIAL_OUT_BIT 0x80 /* serial data out, for reading from eeprom */ #define DACALIBRATION2 6 /* D/A CALIBRATION REGISTER 2 */ #define SELECT_EEPROM_BIT 0x1 /* send serial data in to eeprom */ -#define DESELECT_REF_DAC_BIT 0x2 /* don't send serial data to MAX542 reference dac */ -#define DESELECT_CALDAC_BIT(n) (0x4 << (n)) /* don't send serial data to caldac n */ -#define DUMMY_BIT 0x40 /* manual says to set this bit with no explanation */ +/* don't send serial data to MAX542 reference dac */ +#define DESELECT_REF_DAC_BIT 0x2 +/* don't send serial data to caldac n */ +#define DESELECT_CALDAC_BIT(n) (0x4 << (n)) +/* manual says to set this bit with no explanation */ +#define DUMMY_BIT 0x40 #define DADATA 8 /* FIRST D/A DATA REGISTER (0) */ @@ -195,26 +204,17 @@ static const struct cb_pcidda_board cb_pcidda_boards[] = { }, }; -static DEFINE_PCI_DEVICE_TABLE(cb_pcidda_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0020) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0021) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0022) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0023) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0024) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0025) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, cb_pcidda_pci_table); - /* * Useful for shorthand access to the particular board structure */ #define thisboard ((const struct cb_pcidda_board *)dev->board_ptr) -/* this structure is for data unique to this hardware driver. If - several hardware drivers keep similar information in this structure, - feel free to suggest moving the variable to the struct comedi_device struct. */ +/* + * this structure is for data unique to this hardware driver. If + * several hardware drivers keep similar information in this structure, + * feel free to suggest moving the variable to the struct comedi_device + * struct. + */ struct cb_pcidda_private { int data; @@ -227,8 +227,10 @@ struct cb_pcidda_private { /* unsigned long control_status; */ /* unsigned long adc_fifo; */ - unsigned int dac_cal1_bits; /* bits last written to da calibration register 1 */ - unsigned int ao_range[MAX_AO_CHANNELS]; /* current range settings for output channels */ + /* bits last written to da calibration register 1 */ + unsigned int dac_cal1_bits; + /* current range settings for output channels */ + unsigned int ao_range[MAX_AO_CHANNELS]; u16 eeprom_data[EEPROM_SIZE]; /* software copy of board's eeprom */ }; @@ -238,9 +240,6 @@ struct cb_pcidda_private { */ #define devpriv ((struct cb_pcidda_private *)dev->private) -static int cb_pcidda_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int cb_pcidda_detach(struct comedi_device *dev); /* static int cb_pcidda_ai_rinsn(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data); */ static int cb_pcidda_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, @@ -258,19 +257,6 @@ static unsigned int cb_pcidda_read_eeprom(struct comedi_device *dev, static void cb_pcidda_calibrate(struct comedi_device *dev, unsigned int channel, unsigned int range); -/* - * The struct comedi_driver structure tells the Comedi core module - * which functions to call to configure/deconfigure (attach/detach) - * the board, and also about the kernel module that contains - * the device code. - */ -static struct comedi_driver driver_cb_pcidda = { - .driver_name = "cb_pcidda", - .module = THIS_MODULE, - .attach = cb_pcidda_attach, - .detach = cb_pcidda_detach, -}; - /* * Attach is called by the Comedi core to configure the driver * for a particular board. @@ -377,7 +363,8 @@ static int cb_pcidda_attach(struct comedi_device *dev, dev_dbg(dev->hw_dev, "eeprom:\n"); for (index = 0; index < EEPROM_SIZE; index++) { devpriv->eeprom_data[index] = cb_pcidda_read_eeprom(dev, index); - dev_dbg(dev->hw_dev, "%i:0x%x\n", index, devpriv->eeprom_data[index]); + dev_dbg(dev->hw_dev, "%i:0x%x\n", index, + devpriv->eeprom_data[index]); } /* set calibrations dacs */ @@ -387,19 +374,8 @@ static int cb_pcidda_attach(struct comedi_device *dev, return 1; } -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int cb_pcidda_detach(struct comedi_device *dev) +static void cb_pcidda_detach(struct comedi_device *dev) { -/* - * Deallocate the I/O ports. - */ if (devpriv) { if (devpriv->pci_dev) { if (devpriv->dac) @@ -407,13 +383,10 @@ static int cb_pcidda_detach(struct comedi_device *dev) pci_dev_put(devpriv->pci_dev); } } - /* cleanup 8255 */ if (dev->subdevices) { subdev_8255_cleanup(dev, dev->subdevices + 1); subdev_8255_cleanup(dev, dev->subdevices + 2); } - - return 0; } /* @@ -484,7 +457,10 @@ static int cb_pcidda_ai_cmdtest(struct comedi_device *dev, if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually compatible */ + /* + * step 2: make sure trigger sources are unique and mutually + * compatible + */ /* note that mutual compatibility is not an issue here */ if (cmd->scan_begin_src != TRIG_TIMER @@ -696,8 +672,10 @@ static unsigned int cb_pcidda_read_eeprom(struct comedi_device *dev, unsigned int i; unsigned int cal2_bits; unsigned int value; - const int max_num_caldacs = 4; /* one caldac for every two dac channels */ - const int read_instruction = 0x6; /* bits to send to tell eeprom we want to read */ + /* one caldac for every two dac channels */ + const int max_num_caldacs = 4; + /* bits to send to tell eeprom we want to read */ + const int read_instruction = 0x6; const int instruction_length = 3; const int address_length = 8; @@ -729,9 +707,11 @@ static void cb_pcidda_write_caldac(struct comedi_device *dev, { unsigned int cal2_bits; unsigned int i; - const int num_channel_bits = 3; /* caldacs use 3 bit channel specification */ + /* caldacs use 3 bit channel specification */ + const int num_channel_bits = 3; const int num_caldac_bits = 8; /* 8 bit calibration dacs */ - const int max_num_caldacs = 4; /* one caldac for every two dac channels */ + /* one caldac for every two dac channels */ + const int max_num_caldacs = 4; /* write 3 bit channel */ cb_pcidda_serial_out(dev, channel, num_channel_bits); @@ -790,14 +770,20 @@ static unsigned int offset_eeprom_address(unsigned int ao_channel, return 0x7 + 2 * range + 12 * ao_channel; } -/* returns eeprom address that provides gain calibration for given ao channel and range */ +/* + * returns eeprom address that provides gain calibration for given ao + * channel and range + */ static unsigned int gain_eeprom_address(unsigned int ao_channel, unsigned int range) { return 0x8 + 2 * range + 12 * ao_channel; } -/* returns upper byte of eeprom entry, which gives the coarse adjustment values */ +/* + * returns upper byte of eeprom entry, which gives the coarse adjustment + * values + */ static unsigned int eeprom_coarse_byte(unsigned int word) { return (word >> 8) & 0xff; @@ -815,7 +801,7 @@ static void cb_pcidda_calibrate(struct comedi_device *dev, unsigned int channel, { unsigned int coarse_offset, fine_offset, coarse_gain, fine_gain; - /* remember range so we can tell when we need to readjust calibration */ + /* remember range so we can tell when we need to readjust calibration */ devpriv->ao_range[channel] = range; /* get values from eeprom data */ @@ -843,47 +829,42 @@ static void cb_pcidda_calibrate(struct comedi_device *dev, unsigned int channel, fine_gain_channel(channel), fine_gain); } -/* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. - */ -static int __devinit driver_cb_pcidda_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) +static struct comedi_driver cb_pcidda_driver = { + .driver_name = "cb_pcidda", + .module = THIS_MODULE, + .attach = cb_pcidda_attach, + .detach = cb_pcidda_detach, +}; + +static int __devinit cb_pcidda_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, driver_cb_pcidda.driver_name); + return comedi_pci_auto_config(dev, &cb_pcidda_driver); } -static void __devexit driver_cb_pcidda_pci_remove(struct pci_dev *dev) +static void __devexit cb_pcidda_pci_remove(struct pci_dev *dev) { comedi_pci_auto_unconfig(dev); } -static struct pci_driver driver_cb_pcidda_pci_driver = { - .id_table = cb_pcidda_pci_table, - .probe = &driver_cb_pcidda_pci_probe, - .remove = __devexit_p(&driver_cb_pcidda_pci_remove) +static DEFINE_PCI_DEVICE_TABLE(cb_pcidda_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0020) }, + { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0021) }, + { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0022) }, + { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0023) }, + { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0024) }, + { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0025) }, + { 0 } }; +MODULE_DEVICE_TABLE(pci, cb_pcidda_pci_table); -static int __init driver_cb_pcidda_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_cb_pcidda); - if (retval < 0) - return retval; - - driver_cb_pcidda_pci_driver.name = (char *)driver_cb_pcidda.driver_name; - return pci_register_driver(&driver_cb_pcidda_pci_driver); -} - -static void __exit driver_cb_pcidda_cleanup_module(void) -{ - pci_unregister_driver(&driver_cb_pcidda_pci_driver); - comedi_driver_unregister(&driver_cb_pcidda); -} - -module_init(driver_cb_pcidda_init_module); -module_exit(driver_cb_pcidda_cleanup_module); +static struct pci_driver cb_pcidda_pci_driver = { + .name = "cb_pcidda", + .id_table = cb_pcidda_pci_table, + .probe = cb_pcidda_pci_probe, + .remove = __devexit_p(cb_pcidda_pci_remove), +}; +module_comedi_pci_driver(cb_pcidda_driver, cb_pcidda_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/cb_pcidio.c b/trunk/drivers/staging/comedi/drivers/cb_pcidio.c index 8f3215239a15..713132c8dbb5 100644 --- a/trunk/drivers/staging/comedi/drivers/cb_pcidio.c +++ b/trunk/drivers/staging/comedi/drivers/cb_pcidio.c @@ -86,19 +86,6 @@ static const struct pcidio_board pcidio_boards[] = { }, }; -/* This is used by modprobe to translate PCI IDs to drivers. Should - * only be used for PCI and ISA-PnP devices */ -/* Please add your PCI vendor ID to comedidev.h, and it will be forwarded - * upstream. */ -static DEFINE_PCI_DEVICE_TABLE(pcidio_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0028) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0014) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x000b) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, pcidio_pci_table); - /* * Useful for shorthand access to the particular board structure */ @@ -125,59 +112,6 @@ struct pcidio_private { */ #define devpriv ((struct pcidio_private *)dev->private) -/* - * The struct comedi_driver structure tells the Comedi core module - * which functions to call to configure/deconfigure (attach/detach) - * the board, and also about the kernel module that contains - * the device code. - */ -static int pcidio_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcidio_detach(struct comedi_device *dev); -static struct comedi_driver driver_cb_pcidio = { - .driver_name = "cb_pcidio", - .module = THIS_MODULE, - .attach = pcidio_attach, - .detach = pcidio_detach, - -/* It is not necessary to implement the following members if you are - * writing a driver for a ISA PnP or PCI card */ - - /* Most drivers will support multiple types of boards by - * having an array of board structures. These were defined - * in pcidio_boards[] above. Note that the element 'name' - * was first in the structure -- Comedi uses this fact to - * extract the name of the board without knowing any details - * about the structure except for its length. - * When a device is attached (by comedi_config), the name - * of the device is given to Comedi, and Comedi tries to - * match it by going through the list of board names. If - * there is a match, the address of the pointer is put - * into dev->board_ptr and driver->attach() is called. - * - * Note that these are not necessary if you can determine - * the type of board in software. ISA PnP, PCI, and PCMCIA - * devices are such boards. - */ - -/* The following fields should NOT be initialized if you are dealing - * with PCI devices - * - * .board_name = pcidio_boards, - * .offset = sizeof(struct pcidio_board), - * .num_names = sizeof(pcidio_boards) / sizeof(structpcidio_board), - */ - -}; - -/*------------------------------- FUNCTIONS -----------------------------------*/ - -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ static int pcidio_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct pci_dev *pcidev = NULL; @@ -261,15 +195,7 @@ static int pcidio_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 1; } -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int pcidio_detach(struct comedi_device *dev) +static void pcidio_detach(struct comedi_device *dev) { if (devpriv) { if (devpriv->pci_dev) { @@ -283,50 +209,41 @@ static int pcidio_detach(struct comedi_device *dev) for (i = 0; i < thisboard->n_8255; i++) subdev_8255_cleanup(dev, dev->subdevices + i); } - return 0; } -/* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. - */ -static int __devinit driver_cb_pcidio_pci_probe(struct pci_dev *dev, +static struct comedi_driver cb_pcidio_driver = { + .driver_name = "cb_pcidio", + .module = THIS_MODULE, + .attach = pcidio_attach, + .detach = pcidio_detach, +}; + +static int __devinit cb_pcidio_pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, driver_cb_pcidio.driver_name); + return comedi_pci_auto_config(dev, &cb_pcidio_driver); } -static void __devexit driver_cb_pcidio_pci_remove(struct pci_dev *dev) +static void __devexit cb_pcidio_pci_remove(struct pci_dev *dev) { comedi_pci_auto_unconfig(dev); } -static struct pci_driver driver_cb_pcidio_pci_driver = { - .id_table = pcidio_pci_table, - .probe = &driver_cb_pcidio_pci_probe, - .remove = __devexit_p(&driver_cb_pcidio_pci_remove) +static DEFINE_PCI_DEVICE_TABLE(cb_pcidio_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0028) }, + { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0014) }, + { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x000b) }, + { 0 } }; +MODULE_DEVICE_TABLE(pci, cb_pcidio_pci_table); -static int __init driver_cb_pcidio_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_cb_pcidio); - if (retval < 0) - return retval; - - driver_cb_pcidio_pci_driver.name = (char *)driver_cb_pcidio.driver_name; - return pci_register_driver(&driver_cb_pcidio_pci_driver); -} - -static void __exit driver_cb_pcidio_cleanup_module(void) -{ - pci_unregister_driver(&driver_cb_pcidio_pci_driver); - comedi_driver_unregister(&driver_cb_pcidio); -} - -module_init(driver_cb_pcidio_init_module); -module_exit(driver_cb_pcidio_cleanup_module); +static struct pci_driver cb_pcidio_pci_driver = { + .name = "cb_pcidio", + .id_table = cb_pcidio_pci_table, + .probe = cb_pcidio_pci_probe, + .remove = __devexit_p(cb_pcidio_pci_remove), +}; +module_comedi_pci_driver(cb_pcidio_driver, cb_pcidio_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/cb_pcimdas.c b/trunk/drivers/staging/comedi/drivers/cb_pcimdas.c index 8ba694263bd3..5f834d02ec24 100644 --- a/trunk/drivers/staging/comedi/drivers/cb_pcimdas.c +++ b/trunk/drivers/staging/comedi/drivers/cb_pcimdas.c @@ -123,15 +123,6 @@ static const struct cb_pcimdas_board cb_pcimdas_boards[] = { }, }; -/* This is used by modprobe to translate PCI IDs to drivers. Should - * only be used for PCI and ISA-PnP devices */ -static DEFINE_PCI_DEVICE_TABLE(cb_pcimdas_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0056) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, cb_pcimdas_pci_table); - #define N_BOARDS 1 /* Max number of boards supported */ /* @@ -139,9 +130,12 @@ MODULE_DEVICE_TABLE(pci, cb_pcimdas_pci_table); */ #define thisboard ((const struct cb_pcimdas_board *)dev->board_ptr) -/* this structure is for data unique to this hardware driver. If - several hardware drivers keep similar information in this structure, - feel free to suggest moving the variable to the struct comedi_device struct. */ +/* + * this structure is for data unique to this hardware driver. If + * several hardware drivers keep similar information in this structure, + * feel free to suggest moving the variable to the struct comedi_device + * struct. + */ struct cb_pcimdas_private { int data; @@ -172,22 +166,6 @@ struct cb_pcimdas_private { */ #define devpriv ((struct cb_pcimdas_private *)dev->private) -/* - * The struct comedi_driver structure tells the Comedi core module - * which functions to call to configure/deconfigure (attach/detach) - * the board, and also about the kernel module that contains - * the device code. - */ -static int cb_pcimdas_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int cb_pcimdas_detach(struct comedi_device *dev); -static struct comedi_driver driver_cb_pcimdas = { - .driver_name = "cb_pcimdas", - .module = THIS_MODULE, - .attach = cb_pcimdas_attach, - .detach = cb_pcimdas_detach, -}; - static int cb_pcimdas_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); @@ -317,7 +295,8 @@ static int cb_pcimdas_attach(struct comedi_device *dev, s->subdev_flags = SDF_WRITABLE; s->n_chan = thisboard->ao_nchan; s->maxdata = 1 << thisboard->ao_bits; - s->range_table = &range_unknown; /* ranges are hardware settable, but not software readable. */ + /* ranges are hardware settable, but not software readable. */ + s->range_table = &range_unknown; s->insn_write = &cb_pcimdas_ao_winsn; s->insn_read = &cb_pcimdas_ao_rinsn; @@ -331,29 +310,8 @@ static int cb_pcimdas_attach(struct comedi_device *dev, return 1; } -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int cb_pcimdas_detach(struct comedi_device *dev) +static void cb_pcimdas_detach(struct comedi_device *dev) { - if (devpriv) { - dev_dbg(dev->hw_dev, "devpriv->BADR0 = 0x%lx\n", - devpriv->BADR0); - dev_dbg(dev->hw_dev, "devpriv->BADR1 = 0x%lx\n", - devpriv->BADR1); - dev_dbg(dev->hw_dev, "devpriv->BADR2 = 0x%lx\n", - devpriv->BADR2); - dev_dbg(dev->hw_dev, "devpriv->BADR3 = 0x%lx\n", - devpriv->BADR3); - dev_dbg(dev->hw_dev, "devpriv->BADR4 = 0x%lx\n", - devpriv->BADR4); - } - if (dev->irq) free_irq(dev->irq, dev); if (devpriv) { @@ -363,8 +321,6 @@ static int cb_pcimdas_detach(struct comedi_device *dev) pci_dev_put(devpriv->pci_dev); } } - - return 0; } /* @@ -402,7 +358,10 @@ static int cb_pcimdas_ai_rinsn(struct comedi_device *dev, outb(0x01, devpriv->BADR3 + 6); /* set bursting off, conversions on */ outb(0x00, devpriv->BADR3 + 7); /* set range to 10V. UP/BP is controlled by a switch on the board */ - /* write channel limits to multiplexer, set Low (bits 0-3) and High (bits 4-7) channels to chan. */ + /* + * write channel limits to multiplexer, set Low (bits 0-3) and + * High (bits 4-7) channels to chan. + */ chanlims = chan | (chan << 4); outb(chanlims, devpriv->BADR3 + 0); @@ -479,49 +438,37 @@ static int cb_pcimdas_ao_rinsn(struct comedi_device *dev, return i; } -/* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. - */ -static int __devinit driver_cb_pcimdas_pci_probe(struct pci_dev *dev, - const struct pci_device_id - *ent) +static struct comedi_driver cb_pcimdas_driver = { + .driver_name = "cb_pcimdas", + .module = THIS_MODULE, + .attach = cb_pcimdas_attach, + .detach = cb_pcimdas_detach, +}; + +static int __devinit cb_pcimdas_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, driver_cb_pcimdas.driver_name); + return comedi_pci_auto_config(dev, &cb_pcimdas_driver); } -static void __devexit driver_cb_pcimdas_pci_remove(struct pci_dev *dev) +static void __devexit cb_pcimdas_pci_remove(struct pci_dev *dev) { comedi_pci_auto_unconfig(dev); } -static struct pci_driver driver_cb_pcimdas_pci_driver = { - .id_table = cb_pcimdas_pci_table, - .probe = &driver_cb_pcimdas_pci_probe, - .remove = __devexit_p(&driver_cb_pcimdas_pci_remove) +static DEFINE_PCI_DEVICE_TABLE(cb_pcimdas_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0056) }, + { 0 } }; +MODULE_DEVICE_TABLE(pci, cb_pcimdas_pci_table); -static int __init driver_cb_pcimdas_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_cb_pcimdas); - if (retval < 0) - return retval; - - driver_cb_pcimdas_pci_driver.name = - (char *)driver_cb_pcimdas.driver_name; - return pci_register_driver(&driver_cb_pcimdas_pci_driver); -} - -static void __exit driver_cb_pcimdas_cleanup_module(void) -{ - pci_unregister_driver(&driver_cb_pcimdas_pci_driver); - comedi_driver_unregister(&driver_cb_pcimdas); -} - -module_init(driver_cb_pcimdas_init_module); -module_exit(driver_cb_pcimdas_cleanup_module); +static struct pci_driver cb_pcimdas_pci_driver = { + .name = "cb_pcimdas", + .id_table = cb_pcimdas_pci_table, + .probe = cb_pcimdas_pci_probe, + .remove = __devexit_p(cb_pcimdas_pci_remove), +}; +module_comedi_pci_driver(cb_pcimdas_driver, cb_pcimdas_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/cb_pcimdda.c b/trunk/drivers/staging/comedi/drivers/cb_pcimdda.c index 40bddfa22220..b339685e234d 100644 --- a/trunk/drivers/staging/comedi/drivers/cb_pcimdda.c +++ b/trunk/drivers/staging/comedi/drivers/cb_pcimdda.c @@ -140,17 +140,6 @@ static const struct board_struct boards[] = { #define REG_SZ (thisboard->reg_sz) #define REGS_BADRINDEX (thisboard->regs_badrindex) -/* This is used by modprobe to translate PCI IDs to drivers. Should - * only be used for PCI and ISA-PnP devices */ -/* Please add your PCI vendor ID to comedidev.h, and it will be forwarded - * upstream. */ -static DEFINE_PCI_DEVICE_TABLE(pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, PCI_ID_PCIM_DDA06_16) }, - {0} -}; - -MODULE_DEVICE_TABLE(pci, pci_table); - /* * this structure is for data unique to this hardware driver. If * several hardware drivers keep similar information in this structure, @@ -161,7 +150,6 @@ struct board_private_struct { unsigned long registers; /* set by probe */ unsigned long dio_registers; char attached_to_8255; /* boolean */ - char attached_successfully; /* boolean */ /* would be useful for a PCI device */ struct pci_dev *pci_dev; @@ -177,66 +165,6 @@ struct board_private_struct { */ #define devpriv ((struct board_private_struct *)dev->private) -/* - * The struct comedi_driver structure tells the Comedi core module - * which functions to call to configure/deconfigure (attach/detach) - * the board, and also about the kernel module that contains - * the device code. - */ -static int attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int detach(struct comedi_device *dev); -static struct comedi_driver cb_pcimdda_driver = { - .driver_name = "cb_pcimdda", - .module = THIS_MODULE, - .attach = attach, - .detach = detach, -}; - -MODULE_AUTHOR("Calin A. Culianu "); -MODULE_DESCRIPTION("Comedi low-level driver for the Computerboards PCIM-DDA " - "series. Currently only supports PCIM-DDA06-16 (which " - "also happens to be the only board in this series. :) ) "); -MODULE_LICENSE("GPL"); -static int __devinit cb_pcimdda_driver_pci_probe(struct pci_dev *dev, - const struct pci_device_id - *ent) -{ - return comedi_pci_auto_config(dev, cb_pcimdda_driver.driver_name); -} - -static void __devexit cb_pcimdda_driver_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver cb_pcimdda_driver_pci_driver = { - .id_table = pci_table, - .probe = &cb_pcimdda_driver_pci_probe, - .remove = __devexit_p(&cb_pcimdda_driver_pci_remove) -}; - -static int __init cb_pcimdda_driver_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&cb_pcimdda_driver); - if (retval < 0) - return retval; - - cb_pcimdda_driver_pci_driver.name = - (char *)cb_pcimdda_driver.driver_name; - return pci_register_driver(&cb_pcimdda_driver_pci_driver); -} - -static void __exit cb_pcimdda_driver_cleanup_module(void) -{ - pci_unregister_driver(&cb_pcimdda_driver_pci_driver); - comedi_driver_unregister(&cb_pcimdda_driver); -} - -module_init(cb_pcimdda_driver_init_module); -module_exit(cb_pcimdda_driver_cleanup_module); - static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, @@ -354,44 +282,24 @@ static int attach(struct comedi_device *dev, struct comedi_devconfig *it) s->type = COMEDI_SUBD_UNUSED; } - devpriv->attached_successfully = 1; - printk("attached\n"); return 1; } -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int detach(struct comedi_device *dev) +static void detach(struct comedi_device *dev) { if (devpriv) { - if (dev->subdevices && devpriv->attached_to_8255) { - /* de-register us from the 8255 driver */ subdev_8255_cleanup(dev, dev->subdevices + 2); devpriv->attached_to_8255 = 0; } - if (devpriv->pci_dev) { if (devpriv->registers) comedi_pci_disable(devpriv->pci_dev); pci_dev_put(devpriv->pci_dev); } - - if (devpriv->attached_successfully && thisboard) - printk("comedi%d: %s: detached\n", dev->minor, - thisboard->name); - } - - return 0; } static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, @@ -515,3 +423,41 @@ static int probe(struct comedi_device *dev, const struct comedi_devconfig *it) "card found at the requested position\n"); return -ENODEV; } + +static struct comedi_driver cb_pcimdda_driver = { + .driver_name = "cb_pcimdda", + .module = THIS_MODULE, + .attach = attach, + .detach = detach, +}; + +static int __devinit cb_pcimdda_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + return comedi_pci_auto_config(dev, &cb_pcimdda_driver); +} + +static void __devexit cb_pcimdda_pci_remove(struct pci_dev *dev) +{ + comedi_pci_auto_unconfig(dev); +} + +static DEFINE_PCI_DEVICE_TABLE(cb_pcimdda_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, PCI_ID_PCIM_DDA06_16) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, cb_pcimdda_pci_table); + +static struct pci_driver cb_pcimdda_driver_pci_driver = { + .name = "cb_pcimdda", + .id_table = cb_pcimdda_pci_table, + .probe = cb_pcimdda_pci_probe, + .remove = __devexit_p(cb_pcimdda_pci_remove), +}; +module_comedi_pci_driver(cb_pcimdda_driver, cb_pcimdda_driver_pci_driver); + +MODULE_AUTHOR("Calin A. Culianu "); +MODULE_DESCRIPTION("Comedi low-level driver for the Computerboards PCIM-DDA " + "series. Currently only supports PCIM-DDA06-16 (which " + "also happens to be the only board in this series. :) ) "); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/comedi_bond.c b/trunk/drivers/staging/comedi/drivers/comedi_bond.c index d8aefb23d6b9..29412de06c31 100644 --- a/trunk/drivers/staging/comedi/drivers/comedi_bond.c +++ b/trunk/drivers/staging/comedi/drivers/comedi_bond.c @@ -60,7 +60,6 @@ Configuration Options: #define MAX_CHANS 256 #define MODULE_NAME "comedi_bond" -MODULE_LICENSE("GPL"); #ifndef STR # define STR1(x) #x # define STR(x) STR1(x) @@ -79,10 +78,6 @@ MODULE_PARM_DESC(debug, "If true, print extra cryptic debugging output useful" } while (0) #define WARNING(x...) printk(KERN_WARNING MODULE_NAME ": WARNING: "x) #define ERROR(x...) printk(KERN_ERR MODULE_NAME ": INTERNAL ERROR: "x) -MODULE_AUTHOR("Calin A. Culianu"); -MODULE_DESCRIPTION(MODULE_NAME "A driver for COMEDI to bond multiple COMEDI " - "devices together as one. In the words of John Lennon: " - "'And the world will live as one...'"); /* * Board descriptions for two imaginary boards. Describing the @@ -93,12 +88,6 @@ struct BondingBoard { const char *name; }; -static const struct BondingBoard bondingBoards[] = { - { - .name = MODULE_NAME, - }, -}; - /* * Useful for shorthand access to the particular board structure */ @@ -133,129 +122,6 @@ struct Private { */ #define devpriv ((struct Private *)dev->private) -/* - * The struct comedi_driver structure tells the Comedi core module - * which functions to call to configure/deconfigure (attach/detach) - * the board, and also about the kernel module that contains - * the device code. - */ -static int bonding_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int bonding_detach(struct comedi_device *dev); -/** Build Private array of all devices.. */ -static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it); -static void doDevUnconfig(struct comedi_device *dev); -/* Ugly implementation of realloc that always copies memory around -- I'm lazy, - * what can I say? I like to do wasteful memcopies.. :) */ -static void *Realloc(const void *ptr, size_t len, size_t old_len); - -static struct comedi_driver driver_bonding = { - .driver_name = MODULE_NAME, - .module = THIS_MODULE, - .attach = bonding_attach, - .detach = bonding_detach, - /* It is not necessary to implement the following members if you are - * writing a driver for a ISA PnP or PCI card */ - /* Most drivers will support multiple types of boards by - * having an array of board structures. These were defined - * in skel_boards[] above. Note that the element 'name' - * was first in the structure -- Comedi uses this fact to - * extract the name of the board without knowing any details - * about the structure except for its length. - * When a device is attached (by comedi_config), the name - * of the device is given to Comedi, and Comedi tries to - * match it by going through the list of board names. If - * there is a match, the address of the pointer is put - * into dev->board_ptr and driver->attach() is called. - * - * Note that these are not necessary if you can determine - * the type of board in software. ISA PnP, PCI, and PCMCIA - * devices are such boards. - */ - .board_name = &bondingBoards[0].name, - .offset = sizeof(struct BondingBoard), - .num_names = ARRAY_SIZE(bondingBoards), -}; - -static int bonding_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int bonding_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ -static int bonding_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - - LOG_MSG("comedi%d\n", dev->minor); - - /* - * Allocate the private structure area. alloc_private() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_private(dev, sizeof(struct Private)) < 0) - return -ENOMEM; - - /* - * Setup our bonding from config params.. sets up our Private struct.. - */ - if (!doDevConfig(dev, it)) - return -EINVAL; - - /* - * Initialize dev->board_name. Note that we can use the "thisboard" - * macro now, since we just initialized it in the last line. - */ - dev->board_name = devpriv->name; - - /* - * Allocate the subdevice structures. alloc_subdevice() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_subdevices(dev, 1) < 0) - return -ENOMEM; - - s = dev->subdevices + 0; - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = devpriv->nchans; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = bonding_dio_insn_bits; - s->insn_config = bonding_dio_insn_config; - - LOG_MSG("attached with %u DIO channels coming from %u different " - "subdevices all bonded together. " - "John Lennon would be proud!\n", - devpriv->nchans, devpriv->ndevs); - - return 1; -} - -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int bonding_detach(struct comedi_device *dev) -{ - LOG_MSG("comedi%d: remove\n", dev->minor); - doDevUnconfig(dev); - return 0; -} - /* DIO devices are slightly special. Although it is possible to * implement the insn_read/insn_write interface, it is much more * useful to applications if you implement the insn_bits interface. @@ -466,7 +332,57 @@ static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it) return 1; } -static void doDevUnconfig(struct comedi_device *dev) +static int bonding_attach(struct comedi_device *dev, + struct comedi_devconfig *it) +{ + struct comedi_subdevice *s; + + LOG_MSG("comedi%d\n", dev->minor); + + /* + * Allocate the private structure area. alloc_private() is a + * convenient macro defined in comedidev.h. + */ + if (alloc_private(dev, sizeof(struct Private)) < 0) + return -ENOMEM; + + /* + * Setup our bonding from config params.. sets up our Private struct.. + */ + if (!doDevConfig(dev, it)) + return -EINVAL; + + /* + * Initialize dev->board_name. Note that we can use the "thisboard" + * macro now, since we just initialized it in the last line. + */ + dev->board_name = devpriv->name; + + /* + * Allocate the subdevice structures. alloc_subdevice() is a + * convenient macro defined in comedidev.h. + */ + if (alloc_subdevices(dev, 1) < 0) + return -ENOMEM; + + s = dev->subdevices + 0; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = devpriv->nchans; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = bonding_dio_insn_bits; + s->insn_config = bonding_dio_insn_config; + + LOG_MSG("attached with %u DIO channels coming from %u different " + "subdevices all bonded together. " + "John Lennon would be proud!\n", + devpriv->nchans, devpriv->ndevs); + + return 1; +} + +static void bonding_detach(struct comedi_device *dev) { unsigned long devs_closed = 0; @@ -490,15 +406,25 @@ static void doDevUnconfig(struct comedi_device *dev) } } -static int __init init(void) -{ - return comedi_driver_register(&driver_bonding); -} +static const struct BondingBoard bondingBoards[] = { + { + .name = "comedi_bond", + }, +}; -static void __exit cleanup(void) -{ - comedi_driver_unregister(&driver_bonding); -} +static struct comedi_driver bonding_driver = { + .driver_name = "comedi_bond", + .module = THIS_MODULE, + .attach = bonding_attach, + .detach = bonding_detach, + .board_name = &bondingBoards[0].name, + .offset = sizeof(struct BondingBoard), + .num_names = ARRAY_SIZE(bondingBoards), +}; +module_comedi_driver(bonding_driver); -module_init(init); -module_exit(cleanup); +MODULE_AUTHOR("Calin A. Culianu"); +MODULE_DESCRIPTION(MODULE_NAME "A driver for COMEDI to bond multiple COMEDI " + "devices together as one. In the words of John Lennon: " + "'And the world will live as one...'"); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/comedi_parport.c b/trunk/drivers/staging/comedi/drivers/comedi_parport.c index 21d834dd92b6..bff5dcd76107 100644 --- a/trunk/drivers/staging/comedi/drivers/comedi_parport.c +++ b/trunk/drivers/staging/comedi/drivers/comedi_parport.c @@ -91,29 +91,6 @@ pin, which can be used to wake up tasks. #define PARPORT_B 1 #define PARPORT_C 2 -static int parport_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int parport_detach(struct comedi_device *dev); -static struct comedi_driver driver_parport = { - .driver_name = "comedi_parport", - .module = THIS_MODULE, - .attach = parport_attach, - .detach = parport_detach, -}; - -static int __init driver_parport_init_module(void) -{ - return comedi_driver_register(&driver_parport); -} - -static void __exit driver_parport_cleanup_module(void) -{ - comedi_driver_unregister(&driver_parport); -} - -module_init(driver_parport_init_module); -module_exit(driver_parport_cleanup_module); - struct parport_private { unsigned int a_data; unsigned int c_data; @@ -395,19 +372,22 @@ static int parport_attach(struct comedi_device *dev, return 1; } -static int parport_detach(struct comedi_device *dev) +static void parport_detach(struct comedi_device *dev) { - printk(KERN_INFO "comedi%d: parport: remove\n", dev->minor); - if (dev->iobase) release_region(dev->iobase, PARPORT_SIZE); - if (dev->irq) free_irq(dev->irq, dev); - - return 0; } +static struct comedi_driver parport_driver = { + .driver_name = "comedi_parport", + .module = THIS_MODULE, + .attach = parport_attach, + .detach = parport_detach, +}; +module_comedi_driver(parport_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/comedi_test.c b/trunk/drivers/staging/comedi/drivers/comedi_test.c index a804742b8022..873e37450bba 100644 --- a/trunk/drivers/staging/comedi/drivers/comedi_test.c +++ b/trunk/drivers/staging/comedi/drivers/comedi_test.c @@ -67,15 +67,6 @@ struct waveform_board { #define N_CHANS 8 -static const struct waveform_board waveform_boards[] = { - { - .name = "comedi_test", - .ai_chans = N_CHANS, - .ai_bits = 16, - .have_dio = 0, - }, -}; - #define thisboard ((const struct waveform_board *)dev->board_ptr) /* Data unique to this driver */ @@ -94,54 +85,6 @@ struct waveform_private { }; #define devpriv ((struct waveform_private *)dev->private) -static int waveform_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int waveform_detach(struct comedi_device *dev); -static struct comedi_driver driver_waveform = { - .driver_name = "comedi_test", - .module = THIS_MODULE, - .attach = waveform_attach, - .detach = waveform_detach, - .board_name = &waveform_boards[0].name, - .offset = sizeof(struct waveform_board), - .num_names = ARRAY_SIZE(waveform_boards), -}; - -static int __init driver_waveform_init_module(void) -{ - return comedi_driver_register(&driver_waveform); -} - -static void __exit driver_waveform_cleanup_module(void) -{ - comedi_driver_unregister(&driver_waveform); -} - -module_init(driver_waveform_init_module); -module_exit(driver_waveform_cleanup_module); - -static int waveform_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static int waveform_ai_cmd(struct comedi_device *dev, - struct comedi_subdevice *s); -static int waveform_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -static int waveform_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int waveform_ao_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static short fake_sawtooth(struct comedi_device *dev, unsigned int range, - unsigned long current_time); -static short fake_squarewave(struct comedi_device *dev, unsigned int range, - unsigned long current_time); -static short fake_flatline(struct comedi_device *dev, unsigned int range, - unsigned long current_time); -static short fake_waveform(struct comedi_device *dev, unsigned int channel, - unsigned int range, unsigned long current_time); - /* 1000 nanosec in a microsec */ static const int nano_per_micro = 1000; @@ -154,6 +97,78 @@ static const struct comedi_lrange waveform_ai_ranges = { } }; +static short fake_sawtooth(struct comedi_device *dev, unsigned int range_index, + unsigned long current_time) +{ + struct comedi_subdevice *s = dev->read_subdev; + unsigned int offset = s->maxdata / 2; + u64 value; + const struct comedi_krange *krange = + &s->range_table->range[range_index]; + u64 binary_amplitude; + + binary_amplitude = s->maxdata; + binary_amplitude *= devpriv->uvolt_amplitude; + do_div(binary_amplitude, krange->max - krange->min); + + current_time %= devpriv->usec_period; + value = current_time; + value *= binary_amplitude * 2; + do_div(value, devpriv->usec_period); + value -= binary_amplitude; /* get rid of sawtooth's dc offset */ + + return offset + value; +} + +static short fake_squarewave(struct comedi_device *dev, + unsigned int range_index, + unsigned long current_time) +{ + struct comedi_subdevice *s = dev->read_subdev; + unsigned int offset = s->maxdata / 2; + u64 value; + const struct comedi_krange *krange = + &s->range_table->range[range_index]; + current_time %= devpriv->usec_period; + + value = s->maxdata; + value *= devpriv->uvolt_amplitude; + do_div(value, krange->max - krange->min); + + if (current_time < devpriv->usec_period / 2) + value *= -1; + + return offset + value; +} + +static short fake_flatline(struct comedi_device *dev, unsigned int range_index, + unsigned long current_time) +{ + return dev->read_subdev->maxdata / 2; +} + +/* generates a different waveform depending on what channel is read */ +static short fake_waveform(struct comedi_device *dev, unsigned int channel, + unsigned int range, unsigned long current_time) +{ + enum { + SAWTOOTH_CHAN, + SQUARE_CHAN, + }; + switch (channel) { + case SAWTOOTH_CHAN: + return fake_sawtooth(dev, range, current_time); + break; + case SQUARE_CHAN: + return fake_squarewave(dev, range, current_time); + break; + default: + break; + } + + return fake_flatline(dev, range, current_time); +} + /* This is the background routine used to generate arbitrary data. It should run in the background; therefore it is scheduled by @@ -217,84 +232,6 @@ static void waveform_ai_interrupt(unsigned long arg) comedi_event(dev, dev->read_subdev); } -static int waveform_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - int amplitude = it->options[0]; - int period = it->options[1]; - int i; - - dev->board_name = thisboard->name; - - if (alloc_private(dev, sizeof(struct waveform_private)) < 0) - return -ENOMEM; - - /* set default amplitude and period */ - if (amplitude <= 0) - amplitude = 1000000; /* 1 volt */ - if (period <= 0) - period = 100000; /* 0.1 sec */ - - devpriv->uvolt_amplitude = amplitude; - devpriv->usec_period = period; - - dev->n_subdevices = 2; - if (alloc_subdevices(dev, dev->n_subdevices) < 0) - return -ENOMEM; - - s = dev->subdevices + 0; - dev->read_subdev = s; - /* analog input subdevice */ - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ; - s->n_chan = thisboard->ai_chans; - s->maxdata = (1 << thisboard->ai_bits) - 1; - s->range_table = &waveform_ai_ranges; - s->len_chanlist = s->n_chan * 2; - s->insn_read = waveform_ai_insn_read; - s->do_cmd = waveform_ai_cmd; - s->do_cmdtest = waveform_ai_cmdtest; - s->cancel = waveform_ai_cancel; - - s = dev->subdevices + 1; - dev->write_subdev = s; - /* analog output subdevice (loopback) */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE | SDF_GROUND; - s->n_chan = thisboard->ai_chans; - s->maxdata = (1 << thisboard->ai_bits) - 1; - 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++) - devpriv->ao_loopbacks[i] = s->maxdata / 2; - - init_timer(&(devpriv->timer)); - devpriv->timer.function = waveform_ai_interrupt; - devpriv->timer.data = (unsigned long)dev; - - printk(KERN_INFO "comedi%d: comedi_test: " - "%i microvolt, %li microsecond waveform attached\n", dev->minor, - devpriv->uvolt_amplitude, devpriv->usec_period); - return 1; -} - -static int waveform_detach(struct comedi_device *dev) -{ - printk("comedi%d: comedi_test: remove\n", dev->minor); - - if (dev->private) - waveform_ai_cancel(dev, dev->read_subdev); - - return 0; -} - static int waveform_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) @@ -465,78 +402,6 @@ static int waveform_ai_cancel(struct comedi_device *dev, return 0; } -static short fake_sawtooth(struct comedi_device *dev, unsigned int range_index, - unsigned long current_time) -{ - struct comedi_subdevice *s = dev->read_subdev; - unsigned int offset = s->maxdata / 2; - u64 value; - const struct comedi_krange *krange = - &s->range_table->range[range_index]; - u64 binary_amplitude; - - binary_amplitude = s->maxdata; - binary_amplitude *= devpriv->uvolt_amplitude; - do_div(binary_amplitude, krange->max - krange->min); - - current_time %= devpriv->usec_period; - value = current_time; - value *= binary_amplitude * 2; - do_div(value, devpriv->usec_period); - value -= binary_amplitude; /* get rid of sawtooth's dc offset */ - - return offset + value; -} - -static short fake_squarewave(struct comedi_device *dev, - unsigned int range_index, - unsigned long current_time) -{ - struct comedi_subdevice *s = dev->read_subdev; - unsigned int offset = s->maxdata / 2; - u64 value; - const struct comedi_krange *krange = - &s->range_table->range[range_index]; - current_time %= devpriv->usec_period; - - value = s->maxdata; - value *= devpriv->uvolt_amplitude; - do_div(value, krange->max - krange->min); - - if (current_time < devpriv->usec_period / 2) - value *= -1; - - return offset + value; -} - -static short fake_flatline(struct comedi_device *dev, unsigned int range_index, - unsigned long current_time) -{ - return dev->read_subdev->maxdata / 2; -} - -/* generates a different waveform depending on what channel is read */ -static short fake_waveform(struct comedi_device *dev, unsigned int channel, - unsigned int range, unsigned long current_time) -{ - enum { - SAWTOOTH_CHAN, - SQUARE_CHAN, - }; - switch (channel) { - case SAWTOOTH_CHAN: - return fake_sawtooth(dev, range, current_time); - break; - case SQUARE_CHAN: - return fake_squarewave(dev, range, current_time); - break; - default: - break; - } - - return fake_flatline(dev, range, current_time); -} - static int waveform_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -561,6 +426,100 @@ static int waveform_ao_insn_write(struct comedi_device *dev, return insn->n; } +static int waveform_attach(struct comedi_device *dev, + struct comedi_devconfig *it) +{ + struct comedi_subdevice *s; + int amplitude = it->options[0]; + int period = it->options[1]; + int i; + + dev->board_name = thisboard->name; + + if (alloc_private(dev, sizeof(struct waveform_private)) < 0) + return -ENOMEM; + + /* set default amplitude and period */ + if (amplitude <= 0) + amplitude = 1000000; /* 1 volt */ + if (period <= 0) + period = 100000; /* 0.1 sec */ + + devpriv->uvolt_amplitude = amplitude; + devpriv->usec_period = period; + + dev->n_subdevices = 2; + if (alloc_subdevices(dev, dev->n_subdevices) < 0) + return -ENOMEM; + + s = dev->subdevices + 0; + dev->read_subdev = s; + /* analog input subdevice */ + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ; + s->n_chan = thisboard->ai_chans; + s->maxdata = (1 << thisboard->ai_bits) - 1; + s->range_table = &waveform_ai_ranges; + s->len_chanlist = s->n_chan * 2; + s->insn_read = waveform_ai_insn_read; + s->do_cmd = waveform_ai_cmd; + s->do_cmdtest = waveform_ai_cmdtest; + s->cancel = waveform_ai_cancel; + + s = dev->subdevices + 1; + dev->write_subdev = s; + /* analog output subdevice (loopback) */ + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE | SDF_GROUND; + s->n_chan = thisboard->ai_chans; + s->maxdata = (1 << thisboard->ai_bits) - 1; + 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++) + devpriv->ao_loopbacks[i] = s->maxdata / 2; + + init_timer(&(devpriv->timer)); + devpriv->timer.function = waveform_ai_interrupt; + devpriv->timer.data = (unsigned long)dev; + + printk(KERN_INFO "comedi%d: comedi_test: " + "%i microvolt, %li microsecond waveform attached\n", dev->minor, + devpriv->uvolt_amplitude, devpriv->usec_period); + return 1; +} + +static void waveform_detach(struct comedi_device *dev) +{ + if (dev->private) + waveform_ai_cancel(dev, dev->read_subdev); +} + +static const struct waveform_board waveform_boards[] = { + { + .name = "comedi_test", + .ai_chans = N_CHANS, + .ai_bits = 16, + .have_dio = 0, + }, +}; + +static struct comedi_driver waveform_driver = { + .driver_name = "comedi_test", + .module = THIS_MODULE, + .attach = waveform_attach, + .detach = waveform_detach, + .board_name = &waveform_boards[0].name, + .offset = sizeof(struct waveform_board), + .num_names = ARRAY_SIZE(waveform_boards), +}; +module_comedi_driver(waveform_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/contec_pci_dio.c b/trunk/drivers/staging/comedi/drivers/contec_pci_dio.c index e3659bd6e85e..b8bac80f2baf 100644 --- a/trunk/drivers/staging/comedi/drivers/contec_pci_dio.c +++ b/trunk/drivers/staging/comedi/drivers/contec_pci_dio.c @@ -56,13 +56,6 @@ static const struct contec_board contec_boards[] = { }; #define PCI_DEVICE_ID_PIO1616L 0x8172 -static DEFINE_PCI_DEVICE_TABLE(contec_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_CONTEC, PCI_DEVICE_ID_PIO1616L), - .driver_data = PIO1616L }, - {0} -}; - -MODULE_DEVICE_TABLE(pci, contec_pci_table); #define thisboard ((const struct contec_board *)dev->board_ptr) @@ -75,30 +68,42 @@ struct contec_private { #define devpriv ((struct contec_private *)dev->private) -static int contec_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int contec_detach(struct comedi_device *dev); -static struct comedi_driver driver_contec = { - .driver_name = "contec_pci_dio", - .module = THIS_MODULE, - .attach = contec_attach, - .detach = contec_detach, -}; +static int contec_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + + dev_dbg(dev->hw_dev, "contec_do_insn_bits called\n"); + dev_dbg(dev->hw_dev, "data: %d %d\n", data[0], data[1]); + + if (insn->n != 2) + return -EINVAL; + + if (data[0]) { + s->state &= ~data[0]; + s->state |= data[0] & data[1]; + dev_dbg(dev->hw_dev, "out: %d on %lx\n", s->state, + dev->iobase + thisboard->out_offs); + outw(s->state, dev->iobase + thisboard->out_offs); + } + return 2; +} -/* Classic digital IO */ static int contec_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int contec_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); + struct comedi_insn *insn, unsigned int *data) +{ + + dev_dbg(dev->hw_dev, "contec_di_insn_bits called\n"); + dev_dbg(dev->hw_dev, "data: %d %d\n", data[0], data[1]); -#if 0 -static int contec_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd); + if (insn->n != 2) + return -EINVAL; -static int contec_ns_to_timer(unsigned int *ns, int round); -#endif + data[1] = inw(dev->iobase + thisboard->in_offs); + + return 2; +} static int contec_attach(struct comedi_device *dev, struct comedi_devconfig *it) { @@ -164,107 +169,47 @@ static int contec_attach(struct comedi_device *dev, struct comedi_devconfig *it) return -EIO; } -static int contec_detach(struct comedi_device *dev) +static void contec_detach(struct comedi_device *dev) { - printk("comedi%d: contec: remove\n", dev->minor); - if (devpriv && devpriv->pci_dev) { if (dev->iobase) comedi_pci_disable(devpriv->pci_dev); pci_dev_put(devpriv->pci_dev); } - - return 0; -} - -#if 0 -static int contec_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd) -{ - printk("contec_cmdtest called\n"); - return 0; -} - -static int contec_ns_to_timer(unsigned int *ns, int round) -{ - return *ns; -} -#endif - -static int contec_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - - dev_dbg(dev->hw_dev, "contec_do_insn_bits called\n"); - dev_dbg(dev->hw_dev, "data: %d %d\n", data[0], data[1]); - - if (insn->n != 2) - return -EINVAL; - - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - dev_dbg(dev->hw_dev, "out: %d on %lx\n", s->state, - dev->iobase + thisboard->out_offs); - outw(s->state, dev->iobase + thisboard->out_offs); - } - return 2; } -static int contec_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - - dev_dbg(dev->hw_dev, "contec_di_insn_bits called\n"); - dev_dbg(dev->hw_dev, "data: %d %d\n", data[0], data[1]); - - if (insn->n != 2) - return -EINVAL; - - data[1] = inw(dev->iobase + thisboard->in_offs); - - return 2; -} +static struct comedi_driver contec_pci_dio_driver = { + .driver_name = "contec_pci_dio", + .module = THIS_MODULE, + .attach = contec_attach, + .detach = contec_detach, +}; -static int __devinit driver_contec_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) +static int __devinit contec_pci_dio_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, driver_contec.driver_name); + return comedi_pci_auto_config(dev, &contec_pci_dio_driver); } -static void __devexit driver_contec_pci_remove(struct pci_dev *dev) +static void __devexit contec_pci_dio_pci_remove(struct pci_dev *dev) { comedi_pci_auto_unconfig(dev); } -static struct pci_driver driver_contec_pci_driver = { - .id_table = contec_pci_table, - .probe = &driver_contec_pci_probe, - .remove = __devexit_p(&driver_contec_pci_remove) +static DEFINE_PCI_DEVICE_TABLE(contec_pci_dio_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_CONTEC, PCI_DEVICE_ID_PIO1616L), + .driver_data = PIO1616L }, + { 0 } }; +MODULE_DEVICE_TABLE(pci, contec_pci_dio_pci_table); -static int __init driver_contec_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_contec); - if (retval < 0) - return retval; - - driver_contec_pci_driver.name = (char *)driver_contec.driver_name; - return pci_register_driver(&driver_contec_pci_driver); -} - -static void __exit driver_contec_cleanup_module(void) -{ - pci_unregister_driver(&driver_contec_pci_driver); - comedi_driver_unregister(&driver_contec); -} - -module_init(driver_contec_init_module); -module_exit(driver_contec_cleanup_module); +static struct pci_driver contec_pci_dio_pci_driver = { + .name = "contec_pci_dio", + .id_table = contec_pci_dio_pci_table, + .probe = contec_pci_dio_pci_probe, + .remove = __devexit_p(contec_pci_dio_pci_remove), +}; +module_comedi_pci_driver(contec_pci_dio_driver, contec_pci_dio_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/daqboard2000.c b/trunk/drivers/staging/comedi/drivers/daqboard2000.c index e61c6a8f2857..696b58ca2e59 100644 --- a/trunk/drivers/staging/comedi/drivers/daqboard2000.c +++ b/trunk/drivers/staging/comedi/drivers/daqboard2000.c @@ -301,17 +301,6 @@ struct daqboard2000_hw { #define DAQBOARD2000_PosRefDacSelect 0x0100 #define DAQBOARD2000_NegRefDacSelect 0x0000 -static int daqboard2000_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int daqboard2000_detach(struct comedi_device *dev); - -static struct comedi_driver driver_daqboard2000 = { - .driver_name = "daqboard2000", - .module = THIS_MODULE, - .attach = daqboard2000_attach, - .detach = daqboard2000_detach, -}; - struct daq200_boardtype { const char *name; int id; @@ -321,16 +310,8 @@ static const struct daq200_boardtype boardtypes[] = { {"ids4", DAQBOARD2000_SUBSYSTEM_IDS4}, }; -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct daq200_boardtype)) #define this_board ((const struct daq200_boardtype *)dev->board_ptr) -static DEFINE_PCI_DEVICE_TABLE(daqboard2000_pci_table) = { - { PCI_DEVICE(0x1616, 0x0409) }, - {0} -}; - -MODULE_DEVICE_TABLE(pci, daqboard2000_pci_table); - struct daqboard2000_private { enum { card_daqboard_2000 @@ -412,9 +393,12 @@ static int daqboard2000_ai_insn_read(struct comedi_device *dev, DAQBOARD2000_AcqResetScanListFifo | DAQBOARD2000_AcqResetResultsFifo | DAQBOARD2000_AcqResetConfigPipe; - /* If pacer clock is not set to some high value (> 10 us), we - risk multiple samples to be put into the result FIFO. */ - fpga->acqPacerClockDivLow = 1000000; /* 1 second, should be long enough */ + /* + * If pacer clock is not set to some high value (> 10 us), we + * risk multiple samples to be put into the result FIFO. + */ + /* 1 second, should be long enough */ + fpga->acqPacerClockDivLow = 1000000; fpga->acqPacerClockDivHigh = 0; gain = CR_RANGE(insn->chanspec); @@ -761,7 +745,7 @@ static int daqboard2000_attach(struct comedi_device *dev, devpriv->pci_dev = card; id = ((u32) card-> subsystem_device << 16) | card->subsystem_vendor; - for (i = 0; i < n_boardtypes; i++) { + for (i = 0; i < ARRAY_SIZE(boardtypes); i++) { if (boardtypes[i].id == id) { dev_dbg(dev->hw_dev, "%s\n", boardtypes[i].name); @@ -852,14 +836,12 @@ static int daqboard2000_attach(struct comedi_device *dev, return result; } -static int daqboard2000_detach(struct comedi_device *dev) +static void daqboard2000_detach(struct comedi_device *dev) { if (dev->subdevices) subdev_8255_cleanup(dev, dev->subdevices + 2); - if (dev->irq) free_irq(dev->irq, dev); - if (devpriv) { if (devpriv->daq) iounmap(devpriv->daq); @@ -871,48 +853,39 @@ static int daqboard2000_detach(struct comedi_device *dev) pci_dev_put(devpriv->pci_dev); } } - return 0; } -static int __devinit driver_daqboard2000_pci_probe(struct pci_dev *dev, - const struct pci_device_id - *ent) +static struct comedi_driver daqboard2000_driver = { + .driver_name = "daqboard2000", + .module = THIS_MODULE, + .attach = daqboard2000_attach, + .detach = daqboard2000_detach, +}; + +static int __devinit daqboard2000_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, driver_daqboard2000.driver_name); + return comedi_pci_auto_config(dev, &daqboard2000_driver); } -static void __devexit driver_daqboard2000_pci_remove(struct pci_dev *dev) +static void __devexit daqboard2000_pci_remove(struct pci_dev *dev) { comedi_pci_auto_unconfig(dev); } -static struct pci_driver driver_daqboard2000_pci_driver = { - .id_table = daqboard2000_pci_table, - .probe = &driver_daqboard2000_pci_probe, - .remove = __devexit_p(&driver_daqboard2000_pci_remove) +static DEFINE_PCI_DEVICE_TABLE(daqboard2000_pci_table) = { + { PCI_DEVICE(0x1616, 0x0409) }, + { 0 } }; +MODULE_DEVICE_TABLE(pci, daqboard2000_pci_table); -static int __init driver_daqboard2000_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_daqboard2000); - if (retval < 0) - return retval; - - driver_daqboard2000_pci_driver.name = - (char *)driver_daqboard2000.driver_name; - return pci_register_driver(&driver_daqboard2000_pci_driver); -} - -static void __exit driver_daqboard2000_cleanup_module(void) -{ - pci_unregister_driver(&driver_daqboard2000_pci_driver); - comedi_driver_unregister(&driver_daqboard2000); -} - -module_init(driver_daqboard2000_init_module); -module_exit(driver_daqboard2000_cleanup_module); +static struct pci_driver daqboard2000_pci_driver = { + .name = "daqboard2000", + .id_table = daqboard2000_pci_table, + .probe = daqboard2000_pci_probe, + .remove = __devexit_p(daqboard2000_pci_remove), +}; +module_comedi_pci_driver(daqboard2000_driver, daqboard2000_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/das08.c b/trunk/drivers/staging/comedi/drivers/das08.c index c2dd0ed36a73..1f319435e23f 100644 --- a/trunk/drivers/staging/comedi/drivers/das08.c +++ b/trunk/drivers/staging/comedi/drivers/das08.c @@ -61,6 +61,20 @@ #define DRV_NAME "das08" +#ifdef CONFIG_COMEDI_DAS08_ISA_MODULE +#define CONFIG_COMEDI_DAS08_ISA +#endif +#ifdef CONFIG_COMEDI_DAS08_PCI_MODULE +#define CONFIG_COMEDI_DAS08_PCI +#endif +#ifdef CONFIG_COMEDI_DAS08_CS_MODULE +#define CONFIG_COMEDI_DAS08_CS +#endif + +#if defined(CONFIG_COMEDI_DAS08_ISA) || defined(CONFIG_COMEDI_DAS08_PCI) +#define DO_COMEDI_DRIVER_REGISTER +#endif + #define PCI_VENDOR_ID_COMPUTERBOARDS 0x1307 #define PCI_DEVICE_ID_PCIDAS08 0x29 #define PCIDAS08_SIZE 0x54 @@ -160,6 +174,7 @@ static int das08_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); static int das08_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); +#ifdef CONFIG_COMEDI_DAS08_ISA static int das08jr_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); @@ -172,6 +187,7 @@ static int das08jr_ao_winsn(struct comedi_device *dev, static int das08ao_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); +#endif static void i8254_set_mode_low(unsigned int base, int channel, unsigned int mode); @@ -253,7 +269,9 @@ static const int *const das08_gainlists[] = { das08_pgm_gainlist, }; +#ifdef DO_COMEDI_DRIVER_REGISTER static const struct das08_board_struct das08_boards[] = { +#ifdef CONFIG_COMEDI_DAS08_ISA { .name = "isa-das08", /* cio-das08.pdf */ .bustype = isa, @@ -395,25 +413,6 @@ static const struct das08_board_struct das08_boards[] = { .i8254_offset = 0x04, .iosize = 16, /* unchecked */ }, -#ifdef CONFIG_COMEDI_PCI - { - .name = "das08", /* pci-das08 */ - .id = PCI_DEVICE_ID_PCIDAS08, - .bustype = pci, - .ai = das08_ai_rinsn, - .ai_nbits = 12, - .ai_pg = das08_bipolar5, - .ai_encoding = das08_encode12, - .ao = NULL, - .ao_nbits = 0, - .di = das08_di_rbits, - .do_ = das08_do_wbits, - .do_nchan = 4, - .i8255_offset = 0, - .i8254_offset = 4, - .iosize = 8, - }, -#endif { .name = "pc104-das08", .bustype = pc104, @@ -462,9 +461,30 @@ static const struct das08_board_struct das08_boards[] = { .name = "das08-pga-g2", /* a KM board */ }, #endif +#endif /* CONFIG_COMEDI_DAS08_ISA */ +#ifdef CONFIG_COMEDI_DAS08_PCI + { + .name = "das08", /* pci-das08 */ + .id = PCI_DEVICE_ID_PCIDAS08, + .bustype = pci, + .ai = das08_ai_rinsn, + .ai_nbits = 12, + .ai_pg = das08_bipolar5, + .ai_encoding = das08_encode12, + .ao = NULL, + .ao_nbits = 0, + .di = das08_di_rbits, + .do_ = das08_do_wbits, + .do_nchan = 4, + .i8255_offset = 0, + .i8254_offset = 4, + .iosize = 8, + }, +#endif /* CONFIG_COMEDI_DAS08_PCI */ }; +#endif /* DO_COMEDI_DRIVER_REGISTER */ -#ifdef CONFIG_COMEDI_PCMCIA +#ifdef CONFIG_COMEDI_DAS08_CS struct das08_board_struct das08_cs_boards[NUM_DAS08_CS_BOARDS] = { { .name = "pcm-das08", @@ -504,7 +524,7 @@ struct das08_board_struct das08_cs_boards[NUM_DAS08_CS_BOARDS] = { }; #endif -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_DAS08_PCI static DEFINE_PCI_DEVICE_TABLE(das08_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, PCI_DEVICE_ID_PCIDAS08) }, {0} @@ -619,6 +639,7 @@ static int das08_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, return 2; } +#ifdef CONFIG_COMEDI_DAS08_ISA static int das08jr_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -628,7 +649,9 @@ static int das08jr_di_rbits(struct comedi_device *dev, return 2; } +#endif +#ifdef CONFIG_COMEDI_DAS08_ISA static int das08jr_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -643,7 +666,9 @@ static int das08jr_do_wbits(struct comedi_device *dev, return 2; } +#endif +#ifdef CONFIG_COMEDI_DAS08_ISA static int das08jr_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -672,6 +697,7 @@ static int das08jr_ao_winsn(struct comedi_device *dev, return n; } +#endif /* * @@ -679,6 +705,7 @@ static int das08jr_ao_winsn(struct comedi_device *dev, * a different method to force an update. * */ +#ifdef CONFIG_COMEDI_DAS08_ISA static int das08ao_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -707,6 +734,7 @@ static int das08ao_ao_winsn(struct comedi_device *dev, return n; } +#endif static unsigned int i8254_read_channel_low(unsigned int base, int chan) { @@ -842,6 +870,7 @@ static int das08_counter_config(struct comedi_device *dev, return 2; } +#ifdef DO_COMEDI_DRIVER_REGISTER static int das08_attach(struct comedi_device *dev, struct comedi_devconfig *it); static struct comedi_driver driver_das08 = { @@ -853,6 +882,7 @@ static struct comedi_driver driver_das08 = { .num_names = sizeof(das08_boards) / sizeof(struct das08_board_struct), .offset = sizeof(struct das08_board_struct), }; +#endif int das08_common_attach(struct comedi_device *dev, unsigned long iobase) { @@ -972,11 +1002,12 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase) } EXPORT_SYMBOL_GPL(das08_common_attach); +#ifdef DO_COMEDI_DRIVER_REGISTER static int das08_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int ret; unsigned long iobase; -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_DAS08_PCI unsigned long pci_iobase = 0; struct pci_dev *pdev = NULL; #endif @@ -986,9 +1017,9 @@ static int das08_attach(struct comedi_device *dev, struct comedi_devconfig *it) return ret; printk(KERN_INFO "comedi%d: das08: ", dev->minor); +#ifdef CONFIG_COMEDI_DAS08_PCI /* deal with a pci board */ if (thisboard->bustype == pci) { -#ifdef CONFIG_COMEDI_PCI if (it->options[0] || it->options[1]) { printk("bus %i slot %i ", it->options[0], it->options[1]); @@ -1037,32 +1068,26 @@ static int das08_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* Enable local interrupt 1 and pci interrupt */ outw(INTR1_ENABLE | PCI_INTR_ENABLE, pci_iobase + INTCSR); #endif -#else /* CONFIG_COMEDI_PCI */ - printk(KERN_ERR "this driver has not been built with PCI support.\n"); - return -EINVAL; -#endif /* CONFIG_COMEDI_PCI */ - } else { + } else +#endif /* CONFIG_COMEDI_DAS08_PCI */ + { iobase = it->options[0]; } printk(KERN_INFO "\n"); return das08_common_attach(dev, iobase); } +#endif /* DO_COMEDI_DRIVER_REGISTER */ - -int das08_common_detach(struct comedi_device *dev) +void das08_common_detach(struct comedi_device *dev) { - printk(KERN_INFO "comedi%d: das08: remove\n", dev->minor); - if (dev->subdevices) subdev_8255_cleanup(dev, dev->subdevices + 4); - - /* deallocate ioports for non-pcmcia, non-pci boards */ if ((thisboard->bustype != pcmcia) && (thisboard->bustype != pci)) { if (dev->iobase) release_region(dev->iobase, thisboard->iosize); } -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_DAS08_PCI if (devpriv) { if (devpriv->pdev) { if (devpriv->pci_iobase) @@ -1072,16 +1097,14 @@ int das08_common_detach(struct comedi_device *dev) } } #endif - - return 0; } EXPORT_SYMBOL_GPL(das08_common_detach); -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_COMEDI_DAS08_PCI static int __devinit driver_das08_pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, driver_das08.driver_name); + return comedi_pci_auto_config(dev, &driver_das08); } static void __devexit driver_das08_pci_remove(struct pci_dev *dev) @@ -1094,43 +1117,38 @@ static struct pci_driver driver_das08_pci_driver = { .probe = &driver_das08_pci_probe, .remove = __devexit_p(&driver_das08_pci_remove) }; +#endif /* CONFIG_COMEDI_DAS08_PCI */ static int __init driver_das08_init_module(void) { - int retval; + int retval = 0; +#ifdef DO_COMEDI_DRIVER_REGISTER retval = comedi_driver_register(&driver_das08); if (retval < 0) return retval; - +#endif +#ifdef CONFIG_COMEDI_DAS08_PCI driver_das08_pci_driver.name = (char *)driver_das08.driver_name; - return pci_register_driver(&driver_das08_pci_driver); + retval = pci_register_driver(&driver_das08_pci_driver); +#endif + return retval; } static void __exit driver_das08_cleanup_module(void) { +#ifdef CONFIG_COMEDI_DAS08_PCI pci_unregister_driver(&driver_das08_pci_driver); +#endif +#ifdef DO_COMEDI_DRIVER_REGISTER comedi_driver_unregister(&driver_das08); +#endif } module_init(driver_das08_init_module); module_exit(driver_das08_cleanup_module); -#else -static int __init driver_das08_init_module(void) -{ - return comedi_driver_register(&driver_das08); -} - -static void __exit driver_das08_cleanup_module(void) -{ - comedi_driver_unregister(&driver_das08); -} - -module_init(driver_das08_init_module); -module_exit(driver_das08_cleanup_module); -#endif -#ifdef CONFIG_COMEDI_PCMCIA +#ifdef CONFIG_COMEDI_DAS08_CS EXPORT_SYMBOL_GPL(das08_cs_boards); #endif diff --git a/trunk/drivers/staging/comedi/drivers/das08.h b/trunk/drivers/staging/comedi/drivers/das08.h index 2a30d764ddfc..0b92f24b261f 100644 --- a/trunk/drivers/staging/comedi/drivers/das08.h +++ b/trunk/drivers/staging/comedi/drivers/das08.h @@ -74,6 +74,6 @@ struct das08_private_struct { extern struct das08_board_struct das08_cs_boards[NUM_DAS08_CS_BOARDS]; int das08_common_attach(struct comedi_device *dev, unsigned long iobase); -int das08_common_detach(struct comedi_device *dev); +void das08_common_detach(struct comedi_device *dev); #endif /* _DAS08_H */ diff --git a/trunk/drivers/staging/comedi/drivers/das16.c b/trunk/drivers/staging/comedi/drivers/das16.c index e7905bac92da..998444c1ba32 100644 --- a/trunk/drivers/staging/comedi/drivers/das16.c +++ b/trunk/drivers/staging/comedi/drivers/das16.c @@ -339,38 +339,6 @@ struct munge_info { unsigned have_byte:1; }; -static int das16_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int das16_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int das16_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int das16_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static int das16_cmd_exec(struct comedi_device *dev, - struct comedi_subdevice *s); -static int das16_cancel(struct comedi_device *dev, struct comedi_subdevice *s); -static void das16_ai_munge(struct comedi_device *dev, - struct comedi_subdevice *s, void *array, - unsigned int num_bytes, - unsigned int start_chan_index); - -static void das16_reset(struct comedi_device *dev); -static irqreturn_t das16_dma_interrupt(int irq, void *d); -static void das16_timer_interrupt(unsigned long arg); -static void das16_interrupt(struct comedi_device *dev); - -static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns, - int flags); -static int das1600_mode_detect(struct comedi_device *dev); -static unsigned int das16_suggest_transfer_size(struct comedi_device *dev, - struct comedi_cmd cmd); - -static void reg_dump(struct comedi_device *dev); - struct das16_board { const char *name; void *ai; @@ -389,344 +357,6 @@ struct das16_board { unsigned int id; }; -static const struct das16_board das16_boards[] = { - { - .name = "das-16", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 15000, - .ai_pg = das16_pg_none, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x10, - .i8254_offset = 0x0c, - .size = 0x14, - .id = 0x00, - }, - { - .name = "das-16g", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 15000, - .ai_pg = das16_pg_none, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x10, - .i8254_offset = 0x0c, - .size = 0x14, - .id = 0x00, - }, - { - .name = "das-16f", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 8500, - .ai_pg = das16_pg_none, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x10, - .i8254_offset = 0x0c, - .size = 0x14, - .id = 0x00, - }, - { - .name = "cio-das16", /* cio-das16.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 20000, - .ai_pg = das16_pg_none, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x10, - .i8254_offset = 0x0c, - .size = 0x14, - .id = 0x80, - }, - { - .name = "cio-das16/f", /* das16.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 10000, - .ai_pg = das16_pg_none, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x10, - .i8254_offset = 0x0c, - .size = 0x14, - .id = 0x80, - }, - { - .name = "cio-das16/jr", /* cio-das16jr.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 7692, - .ai_pg = das16_pg_16jr, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0, - .i8254_offset = 0x0c, - .size = 0x10, - .id = 0x00, - }, - { - .name = "pc104-das16jr", /* pc104-das16jr_xx.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 3300, - .ai_pg = das16_pg_16jr, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0, - .i8254_offset = 0x0c, - .size = 0x10, - .id = 0x00, - }, - { - .name = "cio-das16jr/16", /* cio-das16jr_16.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 16, - .ai_speed = 10000, - .ai_pg = das16_pg_16jr_16, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0, - .i8254_offset = 0x0c, - .size = 0x10, - .id = 0x00, - }, - { - .name = "pc104-das16jr/16", /* pc104-das16jr_xx.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 16, - .ai_speed = 10000, - .ai_pg = das16_pg_16jr_16, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0, - .i8254_offset = 0x0c, - .size = 0x10, - .id = 0x00, - }, - { - .name = "das-1201", /* 4924.pdf (keithley user's manual) */ - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 20000, - .ai_pg = das16_pg_none, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x400, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0x20, - }, - { - .name = "das-1202", /* 4924.pdf (keithley user's manual) */ - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 10000, - .ai_pg = das16_pg_none, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x400, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0x20, - }, - { - /* 4919.pdf and 4922.pdf (keithley user's manual) */ - .name = "das-1401", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 10000, - .ai_pg = das16_pg_1601, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x0, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0 /* 4919.pdf says id bits are 0xe0, 4922.pdf says 0xc0 */ - }, - { - /* 4919.pdf and 4922.pdf (keithley user's manual) */ - .name = "das-1402", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 10000, - .ai_pg = das16_pg_1602, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x0, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0 /* 4919.pdf says id bits are 0xe0, 4922.pdf says 0xc0 */ - }, - { - .name = "das-1601", /* 4919.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 10000, - .ai_pg = das16_pg_1601, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x400, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0}, - { - .name = "das-1602", /* 4919.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 10000, - .ai_pg = das16_pg_1602, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x400, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0}, - { - .name = "cio-das1401/12", /* cio-das1400_series.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 6250, - .ai_pg = das16_pg_1601, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0}, - { - .name = "cio-das1402/12", /* cio-das1400_series.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 6250, - .ai_pg = das16_pg_1602, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0}, - { - .name = "cio-das1402/16", /* cio-das1400_series.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 16, - .ai_speed = 10000, - .ai_pg = das16_pg_1602, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0}, - { - .name = "cio-das1601/12", /* cio-das160x-1x.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 6250, - .ai_pg = das16_pg_1601, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x400, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0}, - { - .name = "cio-das1602/12", /* cio-das160x-1x.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 10000, - .ai_pg = das16_pg_1602, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x400, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0}, - { - .name = "cio-das1602/16", /* cio-das160x-1x.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 16, - .ai_speed = 10000, - .ai_pg = das16_pg_1602, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x400, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0}, - { - .name = "cio-das16/330", /* ? */ - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 3030, - .ai_pg = das16_pg_16jr, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0, - .i8254_offset = 0x0c, - .size = 0x14, - .id = 0xf0}, -#if 0 - { - .name = "das16/330i", /* ? */ - }, - { - .name = "das16/jr/ctr5", /* ? */ - }, - { - /* cio-das16_m1_16.pdf, this board is a bit quirky, no dma */ - .name = "cio-das16/m1/16", - }, -#endif -}; - -static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int das16_detach(struct comedi_device *dev); -static struct comedi_driver driver_das16 = { - .driver_name = "das16", - .module = THIS_MODULE, - .attach = das16_attach, - .detach = das16_detach, - .board_name = &das16_boards[0].name, - .num_names = ARRAY_SIZE(das16_boards), - .offset = sizeof(das16_boards[0]), -}; - #define DAS16_TIMEOUT 1000 /* Period for timer interrupt in jiffies. It's a function @@ -926,6 +556,62 @@ static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, return 0; } +/* utility function that suggests a dma transfer size in bytes */ +static unsigned int das16_suggest_transfer_size(struct comedi_device *dev, + struct comedi_cmd cmd) +{ + unsigned int size; + unsigned int freq; + + /* if we are using timer interrupt, we don't care how long it + * will take to complete transfer since it will be interrupted + * by timer interrupt */ + if (devpriv->timer_mode) + return DAS16_DMA_SIZE; + + /* otherwise, we are relying on dma terminal count interrupt, + * so pick a reasonable size */ + if (cmd.convert_src == TRIG_TIMER) + freq = 1000000000 / cmd.convert_arg; + else if (cmd.scan_begin_src == TRIG_TIMER) + freq = (1000000000 / cmd.scan_begin_arg) * cmd.chanlist_len; + /* return some default value */ + else + freq = 0xffffffff; + + if (cmd.flags & TRIG_WAKE_EOS) { + size = sample_size * cmd.chanlist_len; + } else { + /* make buffer fill in no more than 1/3 second */ + size = (freq / 3) * sample_size; + } + + /* set a minimum and maximum size allowed */ + if (size > DAS16_DMA_SIZE) + size = DAS16_DMA_SIZE - DAS16_DMA_SIZE % sample_size; + else if (size < sample_size) + size = sample_size; + + if (cmd.stop_src == TRIG_COUNT && size > devpriv->adc_byte_count) + size = devpriv->adc_byte_count; + + return size; +} + +static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns, + int rounding_flags) +{ + i8253_cascade_ns_to_timer_2div(devpriv->clockbase, &(devpriv->divisor1), + &(devpriv->divisor2), &ns, + rounding_flags & TRIG_ROUND_MASK); + + /* Write the values of ctr1 and ctr2 into counters 1 and 2 */ + i8254_load(dev->iobase + DAS16_CNTR0_DATA, 0, 1, devpriv->divisor1, 2); + i8254_load(dev->iobase + DAS16_CNTR0_DATA, 0, 2, devpriv->divisor2, 2); + + return ns; +} + static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_async *async = s->async; @@ -1170,34 +856,6 @@ static int das16_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, return i; } -static irqreturn_t das16_dma_interrupt(int irq, void *d) -{ - int status; - struct comedi_device *dev = d; - - status = inb(dev->iobase + DAS16_STATUS); - - if ((status & DAS16_INT) == 0) { - DEBUG_PRINT("spurious interrupt\n"); - return IRQ_NONE; - } - - /* clear interrupt */ - outb(0x00, dev->iobase + DAS16_STATUS); - das16_interrupt(dev); - return IRQ_HANDLED; -} - -static void das16_timer_interrupt(unsigned long arg) -{ - struct comedi_device *dev = (struct comedi_device *)arg; - - das16_interrupt(dev); - - if (devpriv->timer_running) - mod_timer(&devpriv->timer, jiffies + timer_period()); -} - /* the pc104-das16jr (at least) has problems if the dma transfer is interrupted in the middle of transferring a 16 bit sample, so this function takes care to get @@ -1309,18 +967,32 @@ static void das16_interrupt(struct comedi_device *dev) cfc_handle_events(dev, s); } -static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns, - int rounding_flags) +static irqreturn_t das16_dma_interrupt(int irq, void *d) { - i8253_cascade_ns_to_timer_2div(devpriv->clockbase, &(devpriv->divisor1), - &(devpriv->divisor2), &ns, - rounding_flags & TRIG_ROUND_MASK); + int status; + struct comedi_device *dev = d; - /* Write the values of ctr1 and ctr2 into counters 1 and 2 */ - i8254_load(dev->iobase + DAS16_CNTR0_DATA, 0, 1, devpriv->divisor1, 2); - i8254_load(dev->iobase + DAS16_CNTR0_DATA, 0, 2, devpriv->divisor2, 2); + status = inb(dev->iobase + DAS16_STATUS); - return ns; + if ((status & DAS16_INT) == 0) { + DEBUG_PRINT("spurious interrupt\n"); + return IRQ_NONE; + } + + /* clear interrupt */ + outb(0x00, dev->iobase + DAS16_STATUS); + das16_interrupt(dev); + return IRQ_HANDLED; +} + +static void das16_timer_interrupt(unsigned long arg) +{ + struct comedi_device *dev = (struct comedi_device *)arg; + + das16_interrupt(dev); + + if (devpriv->timer_running) + mod_timer(&devpriv->timer, jiffies + timer_period()); } static void reg_dump(struct comedi_device *dev) @@ -1394,6 +1066,22 @@ static int das1600_mode_detect(struct comedi_device *dev) return 0; } +static void das16_ai_munge(struct comedi_device *dev, + struct comedi_subdevice *s, void *array, + unsigned int num_bytes, + unsigned int start_chan_index) +{ + unsigned int i, num_samples = num_bytes / sizeof(short); + short *data = array; + + for (i = 0; i < num_samples; i++) { + data[i] = le16_to_cpu(data[i]); + if (thisboard->ai_nbits == 12) + data[i] = (data[i] >> 4) & 0xfff; + + } +} + /* * * Options list: @@ -1402,7 +1090,6 @@ static int das1600_mode_detect(struct comedi_device *dev) * 2 DMA * 3 Clock speed (in MHz) */ - static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; @@ -1675,15 +1362,11 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -static int das16_detach(struct comedi_device *dev) +static void das16_detach(struct comedi_device *dev) { - printk(KERN_INFO "comedi%d: das16: remove\n", dev->minor); - das16_reset(dev); - if (dev->subdevices) subdev_8255_cleanup(dev, dev->subdevices + 4); - if (devpriv) { int i; for (i = 0; i < 2; i++) { @@ -1698,10 +1381,8 @@ static int das16_detach(struct comedi_device *dev) kfree(devpriv->user_ai_range_table); kfree(devpriv->user_ao_range_table); } - if (dev->irq) free_irq(dev->irq, dev); - if (dev->iobase) { if (thisboard->size < 0x400) { release_region(dev->iobase, thisboard->size); @@ -1711,80 +1392,318 @@ static int das16_detach(struct comedi_device *dev) thisboard->size & 0x3ff); } } - - return 0; } -static int __init driver_das16_init_module(void) -{ - return comedi_driver_register(&driver_das16); -} - -static void __exit driver_das16_cleanup_module(void) -{ - comedi_driver_unregister(&driver_das16); -} - -module_init(driver_das16_init_module); -module_exit(driver_das16_cleanup_module); - -/* utility function that suggests a dma transfer size in bytes */ -static unsigned int das16_suggest_transfer_size(struct comedi_device *dev, - struct comedi_cmd cmd) -{ - unsigned int size; - unsigned int freq; - - /* if we are using timer interrupt, we don't care how long it - * will take to complete transfer since it will be interrupted - * by timer interrupt */ - if (devpriv->timer_mode) - return DAS16_DMA_SIZE; - - /* otherwise, we are relying on dma terminal count interrupt, - * so pick a reasonable size */ - if (cmd.convert_src == TRIG_TIMER) - freq = 1000000000 / cmd.convert_arg; - else if (cmd.scan_begin_src == TRIG_TIMER) - freq = (1000000000 / cmd.scan_begin_arg) * cmd.chanlist_len; - /* return some default value */ - else - freq = 0xffffffff; - - if (cmd.flags & TRIG_WAKE_EOS) { - size = sample_size * cmd.chanlist_len; - } else { - /* make buffer fill in no more than 1/3 second */ - size = (freq / 3) * sample_size; - } - - /* set a minimum and maximum size allowed */ - if (size > DAS16_DMA_SIZE) - size = DAS16_DMA_SIZE - DAS16_DMA_SIZE % sample_size; - else if (size < sample_size) - size = sample_size; - - if (cmd.stop_src == TRIG_COUNT && size > devpriv->adc_byte_count) - size = devpriv->adc_byte_count; - - return size; -} - -static void das16_ai_munge(struct comedi_device *dev, - struct comedi_subdevice *s, void *array, - unsigned int num_bytes, - unsigned int start_chan_index) -{ - unsigned int i, num_samples = num_bytes / sizeof(short); - short *data = array; - - for (i = 0; i < num_samples; i++) { - data[i] = le16_to_cpu(data[i]); - if (thisboard->ai_nbits == 12) - data[i] = (data[i] >> 4) & 0xfff; +static const struct das16_board das16_boards[] = { + { + .name = "das-16", + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 15000, + .ai_pg = das16_pg_none, + .ao = das16_ao_winsn, + .ao_nbits = 12, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x10, + .i8254_offset = 0x0c, + .size = 0x14, + .id = 0x00, + }, { + .name = "das-16g", + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 15000, + .ai_pg = das16_pg_none, + .ao = das16_ao_winsn, + .ao_nbits = 12, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x10, + .i8254_offset = 0x0c, + .size = 0x14, + .id = 0x00, + }, { + .name = "das-16f", + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 8500, + .ai_pg = das16_pg_none, + .ao = das16_ao_winsn, + .ao_nbits = 12, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x10, + .i8254_offset = 0x0c, + .size = 0x14, + .id = 0x00, + }, { + .name = "cio-das16", + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 20000, + .ai_pg = das16_pg_none, + .ao = das16_ao_winsn, + .ao_nbits = 12, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x10, + .i8254_offset = 0x0c, + .size = 0x14, + .id = 0x80, + }, { + .name = "cio-das16/f", + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 10000, + .ai_pg = das16_pg_none, + .ao = das16_ao_winsn, + .ao_nbits = 12, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x10, + .i8254_offset = 0x0c, + .size = 0x14, + .id = 0x80, + }, { + .name = "cio-das16/jr", + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 7692, + .ai_pg = das16_pg_16jr, + .ao = NULL, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0, + .i8254_offset = 0x0c, + .size = 0x10, + .id = 0x00, + }, { + .name = "pc104-das16jr", + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 3300, + .ai_pg = das16_pg_16jr, + .ao = NULL, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0, + .i8254_offset = 0x0c, + .size = 0x10, + .id = 0x00, + }, { + .name = "cio-das16jr/16", + .ai = das16_ai_rinsn, + .ai_nbits = 16, + .ai_speed = 10000, + .ai_pg = das16_pg_16jr_16, + .ao = NULL, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0, + .i8254_offset = 0x0c, + .size = 0x10, + .id = 0x00, + }, { + .name = "pc104-das16jr/16", + .ai = das16_ai_rinsn, + .ai_nbits = 16, + .ai_speed = 10000, + .ai_pg = das16_pg_16jr_16, + .ao = NULL, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0, + .i8254_offset = 0x0c, + .size = 0x10, + .id = 0x00, + }, { + .name = "das-1201", + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 20000, + .ai_pg = das16_pg_none, + .ao = NULL, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x400, + .i8254_offset = 0x0c, + .size = 0x408, + .id = 0x20, + }, { + .name = "das-1202", + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 10000, + .ai_pg = das16_pg_none, + .ao = NULL, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x400, + .i8254_offset = 0x0c, + .size = 0x408, + .id = 0x20, + }, { + .name = "das-1401", + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 10000, + .ai_pg = das16_pg_1601, + .ao = NULL, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x0, + .i8254_offset = 0x0c, + .size = 0x408, + .id = 0xc0, + }, { + .name = "das-1402", + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 10000, + .ai_pg = das16_pg_1602, + .ao = NULL, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x0, + .i8254_offset = 0x0c, + .size = 0x408, + .id = 0xc0, + }, { + .name = "das-1601", + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 10000, + .ai_pg = das16_pg_1601, + .ao = das16_ao_winsn, + .ao_nbits = 12, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x400, + .i8254_offset = 0x0c, + .size = 0x408, + .id = 0xc0, + }, { + .name = "das-1602", + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 10000, + .ai_pg = das16_pg_1602, + .ao = das16_ao_winsn, + .ao_nbits = 12, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x400, + .i8254_offset = 0x0c, + .size = 0x408, + .id = 0xc0, + }, { + .name = "cio-das1401/12", + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 6250, + .ai_pg = das16_pg_1601, + .ao = NULL, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0, + .i8254_offset = 0x0c, + .size = 0x408, + .id = 0xc0, + }, { + .name = "cio-das1402/12", + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 6250, + .ai_pg = das16_pg_1602, + .ao = NULL, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0, + .i8254_offset = 0x0c, + .size = 0x408, + .id = 0xc0, + }, { + .name = "cio-das1402/16", + .ai = das16_ai_rinsn, + .ai_nbits = 16, + .ai_speed = 10000, + .ai_pg = das16_pg_1602, + .ao = NULL, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0, + .i8254_offset = 0x0c, + .size = 0x408, + .id = 0xc0, + }, { + .name = "cio-das1601/12", + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 6250, + .ai_pg = das16_pg_1601, + .ao = das16_ao_winsn, + .ao_nbits = 12, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x400, + .i8254_offset = 0x0c, + .size = 0x408, + .id = 0xc0, + }, { + .name = "cio-das1602/12", + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 10000, + .ai_pg = das16_pg_1602, + .ao = das16_ao_winsn, + .ao_nbits = 12, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x400, + .i8254_offset = 0x0c, + .size = 0x408, + .id = 0xc0, + }, { + .name = "cio-das1602/16", + .ai = das16_ai_rinsn, + .ai_nbits = 16, + .ai_speed = 10000, + .ai_pg = das16_pg_1602, + .ao = das16_ao_winsn, + .ao_nbits = 12, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0x400, + .i8254_offset = 0x0c, + .size = 0x408, + .id = 0xc0, + }, { + .name = "cio-das16/330", + .ai = das16_ai_rinsn, + .ai_nbits = 12, + .ai_speed = 3030, + .ai_pg = das16_pg_16jr, + .ao = NULL, + .di = das16_di_rbits, + .do_ = das16_do_wbits, + .i8255_offset = 0, + .i8254_offset = 0x0c, + .size = 0x14, + .id = 0xf0, + }, +}; - } -} +static struct comedi_driver das16_driver = { + .driver_name = "das16", + .module = THIS_MODULE, + .attach = das16_attach, + .detach = das16_detach, + .board_name = &das16_boards[0].name, + .num_names = ARRAY_SIZE(das16_boards), + .offset = sizeof(das16_boards[0]), +}; +module_comedi_driver(das16_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/das16m1.c b/trunk/drivers/staging/comedi/drivers/das16m1.c index 5376e718e3d7..d2e1490cd808 100644 --- a/trunk/drivers/staging/comedi/drivers/das16m1.c +++ b/trunk/drivers/staging/comedi/drivers/das16m1.c @@ -132,57 +132,11 @@ static const struct comedi_lrange range_das16m1 = { 9, } }; -static int das16m1_do_wbits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int das16m1_di_rbits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int das16m1_ai_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static int das16m1_cmd_test(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd); -static int das16m1_cmd_exec(struct comedi_device *dev, - struct comedi_subdevice *s); -static int das16m1_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); - -static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s); -static irqreturn_t das16m1_interrupt(int irq, void *d); -static void das16m1_handler(struct comedi_device *dev, unsigned int status); - -static unsigned int das16m1_set_pacer(struct comedi_device *dev, - unsigned int ns, int round_flag); - -static int das16m1_irq_bits(unsigned int irq); - struct das16m1_board { const char *name; unsigned int ai_speed; }; -static const struct das16m1_board das16m1_boards[] = { - { - .name = "cio-das16/m1", /* CIO-DAS16_M1.pdf */ - .ai_speed = 1000, /* 1MHz max speed */ - }, -}; - -static int das16m1_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int das16m1_detach(struct comedi_device *dev); -static struct comedi_driver driver_das16m1 = { - .driver_name = "das16m1", - .module = THIS_MODULE, - .attach = das16m1_attach, - .detach = das16m1_detach, - .board_name = &das16m1_boards[0].name, - .num_names = ARRAY_SIZE(das16m1_boards), - .offset = sizeof(das16m1_boards[0]), -}; - struct das16m1_private_struct { unsigned int control_state; volatile unsigned int adc_count; /* number of samples completed */ @@ -198,22 +152,17 @@ struct das16m1_private_struct { #define devpriv ((struct das16m1_private_struct *)(dev->private)) #define thisboard ((const struct das16m1_board *)(dev->board_ptr)) -static int __init driver_das16m1_init_module(void) +static inline short munge_sample(short data) { - return comedi_driver_register(&driver_das16m1); + return (data >> 4) & 0xfff; } -static void __exit driver_das16m1_cleanup_module(void) +static void munge_sample_array(short *array, unsigned int num_elements) { - comedi_driver_unregister(&driver_das16m1); -} - -module_init(driver_das16m1_init_module); -module_exit(driver_das16m1_cleanup_module); + unsigned int i; -static inline short munge_sample(short data) -{ - return (data >> 4) & 0xfff; + for (i = 0; i < num_elements; i++) + array[i] = munge_sample(array[i]); } static int das16m1_cmd_test(struct comedi_device *dev, @@ -340,6 +289,25 @@ 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) +{ + i8253_cascade_ns_to_timer_2div(DAS16M1_XTAL, &(devpriv->divisor1), + &(devpriv->divisor2), &ns, + rounding_flags & TRIG_ROUND_MASK); + + /* 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); + + return ns; +} + static int das16m1_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s) { @@ -484,57 +452,6 @@ static int das16m1_do_wbits(struct comedi_device *dev, return 2; } -static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s) -{ - unsigned long flags; - unsigned int status; - - /* prevent race with interrupt handler */ - spin_lock_irqsave(&dev->spinlock, flags); - status = inb(dev->iobase + DAS16M1_CS); - das16m1_handler(dev, status); - spin_unlock_irqrestore(&dev->spinlock, flags); - - return s->async->buf_write_count - s->async->buf_read_count; -} - -static irqreturn_t das16m1_interrupt(int irq, void *d) -{ - int status; - struct comedi_device *dev = d; - - if (dev->attached == 0) { - comedi_error(dev, "premature interrupt"); - return IRQ_HANDLED; - } - /* prevent race with comedi_poll() */ - spin_lock(&dev->spinlock); - - status = inb(dev->iobase + DAS16M1_CS); - - if ((status & (IRQDATA | OVRUN)) == 0) { - comedi_error(dev, "spurious interrupt"); - spin_unlock(&dev->spinlock); - return IRQ_NONE; - } - - das16m1_handler(dev, status); - - /* clear interrupt */ - outb(0, dev->iobase + DAS16M1_CLEAR_INTR); - - spin_unlock(&dev->spinlock); - return IRQ_HANDLED; -} - -static void munge_sample_array(short *array, unsigned int num_elements) -{ - unsigned int i; - - for (i = 0; i < num_elements; i++) - array[i] = munge_sample(array[i]); -} - static void das16m1_handler(struct comedi_device *dev, unsigned int status) { struct comedi_subdevice *s; @@ -596,23 +513,47 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status) } -/* 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 int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s) { - i8253_cascade_ns_to_timer_2div(DAS16M1_XTAL, &(devpriv->divisor1), - &(devpriv->divisor2), &ns, - rounding_flags & TRIG_ROUND_MASK); + unsigned long flags; + unsigned int status; - /* 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); + /* prevent race with interrupt handler */ + spin_lock_irqsave(&dev->spinlock, flags); + status = inb(dev->iobase + DAS16M1_CS); + das16m1_handler(dev, status); + spin_unlock_irqrestore(&dev->spinlock, flags); - return ns; + return s->async->buf_write_count - s->async->buf_read_count; +} + +static irqreturn_t das16m1_interrupt(int irq, void *d) +{ + int status; + struct comedi_device *dev = d; + + if (dev->attached == 0) { + comedi_error(dev, "premature interrupt"); + return IRQ_HANDLED; + } + /* prevent race with comedi_poll() */ + spin_lock(&dev->spinlock); + + status = inb(dev->iobase + DAS16M1_CS); + + if ((status & (IRQDATA | OVRUN)) == 0) { + comedi_error(dev, "spurious interrupt"); + spin_unlock(&dev->spinlock); + return IRQ_NONE; + } + + das16m1_handler(dev, status); + + /* clear interrupt */ + outb(0, dev->iobase + DAS16M1_CLEAR_INTR); + + spin_unlock(&dev->spinlock); + return IRQ_HANDLED; } static int das16m1_irq_bits(unsigned int irq) @@ -656,7 +597,6 @@ static int das16m1_irq_bits(unsigned int irq) * 0 I/O base * 1 IRQ */ - static int das16m1_attach(struct comedi_device *dev, struct comedi_devconfig *it) { @@ -673,12 +613,12 @@ static int das16m1_attach(struct comedi_device *dev, dev->board_name = thisboard->name; - if (!request_region(iobase, DAS16M1_SIZE, driver_das16m1.driver_name)) { + if (!request_region(iobase, DAS16M1_SIZE, dev->driver->driver_name)) { comedi_error(dev, "I/O port conflict\n"); return -EIO; } if (!request_region(iobase + DAS16M1_82C55, DAS16M1_SIZE2, - driver_das16m1.driver_name)) { + dev->driver->driver_name)) { release_region(iobase, DAS16M1_SIZE); comedi_error(dev, "I/O port conflict\n"); return -EIO; @@ -690,7 +630,7 @@ static int das16m1_attach(struct comedi_device *dev, /* make sure it is valid */ if (das16m1_irq_bits(irq) >= 0) { ret = request_irq(irq, das16m1_interrupt, 0, - driver_das16m1.driver_name, dev); + dev->driver->driver_name, dev); if (ret < 0) return ret; dev->irq = irq; @@ -763,25 +703,36 @@ static int das16m1_attach(struct comedi_device *dev, return 0; } -static int das16m1_detach(struct comedi_device *dev) +static void das16m1_detach(struct comedi_device *dev) { - -/* das16m1_reset(dev); */ - if (dev->subdevices) subdev_8255_cleanup(dev, dev->subdevices + 3); - if (dev->irq) free_irq(dev->irq, dev); - if (dev->iobase) { release_region(dev->iobase, DAS16M1_SIZE); release_region(dev->iobase + DAS16M1_82C55, DAS16M1_SIZE2); } - - return 0; } +static const struct das16m1_board das16m1_boards[] = { + { + .name = "cio-das16/m1", /* CIO-DAS16_M1.pdf */ + .ai_speed = 1000, /* 1MHz max speed */ + }, +}; + +static struct comedi_driver das16m1_driver = { + .driver_name = "das16m1", + .module = THIS_MODULE, + .attach = das16m1_attach, + .detach = das16m1_detach, + .board_name = &das16m1_boards[0].name, + .num_names = ARRAY_SIZE(das16m1_boards), + .offset = sizeof(das16m1_boards[0]), +}; +module_comedi_driver(das16m1_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/das1800.c b/trunk/drivers/staging/comedi/drivers/das1800.c index 99ada5a53b9e..2ac344354c1d 100644 --- a/trunk/drivers/staging/comedi/drivers/das1800.c +++ b/trunk/drivers/staging/comedi/drivers/das1800.c @@ -183,9 +183,6 @@ enum { das1802hr, das1802hr_da, das1801hc, das1802hc, das1801ao, das1802ao }; -static int das1800_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int das1800_detach(struct comedi_device *dev); static int das1800_probe(struct comedi_device *dev); static int das1800_cancel(struct comedi_device *dev, struct comedi_subdevice *s); @@ -518,33 +515,6 @@ static const struct comedi_lrange range_ao_2 = { }; */ -static struct comedi_driver driver_das1800 = { - .driver_name = "das1800", - .module = THIS_MODULE, - .attach = das1800_attach, - .detach = das1800_detach, - .num_names = ARRAY_SIZE(das1800_boards), - .board_name = &das1800_boards[0].name, - .offset = sizeof(struct das1800_board), -}; - -/* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. - */ -static int __init driver_das1800_init_module(void) -{ - return comedi_driver_register(&driver_das1800); -} - -static void __exit driver_das1800_cleanup_module(void) -{ - comedi_driver_unregister(&driver_das1800); -} - -module_init(driver_das1800_init_module); -module_exit(driver_das1800_cleanup_module); - static int das1800_init_dma(struct comedi_device *dev, unsigned int dma0, unsigned int dma1) { @@ -579,7 +549,7 @@ static int das1800_init_dma(struct comedi_device *dev, unsigned int dma0, return -EINVAL; break; } - if (request_dma(dma0, driver_das1800.driver_name)) { + if (request_dma(dma0, dev->driver->driver_name)) { dev_err(dev->hw_dev, "failed to allocate dma channel %i\n", dma0); return -EINVAL; @@ -587,7 +557,7 @@ static int das1800_init_dma(struct comedi_device *dev, unsigned int dma0, devpriv->dma0 = dma0; devpriv->dma_current = dma0; if (dma1) { - if (request_dma(dma1, driver_das1800.driver_name)) { + if (request_dma(dma1, dev->driver->driver_name)) { dev_err(dev->hw_dev, "failed to allocate dma channel %i\n", dma1); return -EINVAL; @@ -633,7 +603,7 @@ static int das1800_attach(struct comedi_device *dev, return -ENOMEM; printk(KERN_DEBUG "comedi%d: %s: io 0x%lx", dev->minor, - driver_das1800.driver_name, iobase); + dev->driver->driver_name, iobase); if (irq) { printk(KERN_CONT ", irq %u", irq); if (dma0) { @@ -650,7 +620,7 @@ static int das1800_attach(struct comedi_device *dev, } /* check if io addresses are available */ - if (!request_region(iobase, DAS1800_SIZE, driver_das1800.driver_name)) { + if (!request_region(iobase, DAS1800_SIZE, dev->driver->driver_name)) { printk (" I/O port conflict: failed to allocate ports 0x%lx to 0x%lx\n", iobase, iobase + DAS1800_SIZE - 1); @@ -671,7 +641,7 @@ static int das1800_attach(struct comedi_device *dev, if (thisboard->ao_ability == 2) { iobase2 = iobase + IOBASE2; if (!request_region(iobase2, DAS1800_SIZE, - driver_das1800.driver_name)) { + dev->driver->driver_name)) { printk (" I/O port conflict: failed to allocate ports 0x%lx to 0x%lx\n", iobase2, iobase2 + DAS1800_SIZE - 1); @@ -683,7 +653,7 @@ static int das1800_attach(struct comedi_device *dev, /* grab our IRQ */ if (irq) { if (request_irq(irq, das1800_interrupt, 0, - driver_das1800.driver_name, dev)) { + dev->driver->driver_name, dev)) { dev_dbg(dev->hw_dev, "unable to allocate irq %u\n", irq); return -EINVAL; @@ -797,9 +767,8 @@ static int das1800_attach(struct comedi_device *dev, return 0; }; -static int das1800_detach(struct comedi_device *dev) +static void das1800_detach(struct comedi_device *dev) { - /* only free stuff if it has been allocated by _attach */ if (dev->iobase) release_region(dev->iobase, DAS1800_SIZE); if (dev->irq) @@ -814,11 +783,6 @@ static int das1800_detach(struct comedi_device *dev) kfree(devpriv->ai_buf0); kfree(devpriv->ai_buf1); } - - dev_dbg(dev->hw_dev, "comedi%d: %s: remove\n", dev->minor, - driver_das1800.driver_name); - - return 0; }; /* probes and checks das-1800 series board type @@ -1811,6 +1775,17 @@ static unsigned int suggest_transfer_size(struct comedi_cmd *cmd) return size; } +static struct comedi_driver das1800_driver = { + .driver_name = "das1800", + .module = THIS_MODULE, + .attach = das1800_attach, + .detach = das1800_detach, + .num_names = ARRAY_SIZE(das1800_boards), + .board_name = &das1800_boards[0].name, + .offset = sizeof(struct das1800_board), +}; +module_comedi_driver(das1800_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/das6402.c b/trunk/drivers/staging/comedi/drivers/das6402.c index f25684145e84..881f392d1dba 100644 --- a/trunk/drivers/staging/comedi/drivers/das6402.c +++ b/trunk/drivers/staging/comedi/drivers/das6402.c @@ -99,29 +99,6 @@ This driver has suffered bitrot. #define C2 0x80 #define RWLH 0x30 -static int das6402_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int das6402_detach(struct comedi_device *dev); -static struct comedi_driver driver_das6402 = { - .driver_name = "das6402", - .module = THIS_MODULE, - .attach = das6402_attach, - .detach = das6402_detach, -}; - -static int __init driver_das6402_init_module(void) -{ - return comedi_driver_register(&driver_das6402); -} - -static void __exit driver_das6402_cleanup_module(void) -{ - comedi_driver_unregister(&driver_das6402); -} - -module_init(driver_das6402_init_module); -module_exit(driver_das6402_cleanup_module); - struct das6402_private { int ai_bytes_to_read; @@ -130,7 +107,14 @@ struct das6402_private { #define devpriv ((struct das6402_private *)dev->private) static void das6402_ai_fifo_dregs(struct comedi_device *dev, - struct comedi_subdevice *s); + struct comedi_subdevice *s) +{ + while (1) { + if (!(inb(dev->iobase + 8) & 0x01)) + return; + comedi_buf_put(s->async, inw(dev->iobase)); + } +} static void das6402_setcounter(struct comedi_device *dev) { @@ -209,16 +193,6 @@ static void das6402_ai_fifo_read(struct comedi_device *dev, short *data, int n) } #endif -static void das6402_ai_fifo_dregs(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - while (1) { - if (!(inb(dev->iobase + 8) & 0x01)) - return; - comedi_buf_put(s->async, inw(dev->iobase)); - } -} - static int das6402_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { @@ -300,16 +274,6 @@ static int board_init(struct comedi_device *dev) return 0; } -static int das6402_detach(struct comedi_device *dev) -{ - if (dev->irq) - free_irq(dev->irq, dev); - if (dev->iobase) - release_region(dev->iobase, DAS6402_SIZE); - - return 0; -} - static int das6402_attach(struct comedi_device *dev, struct comedi_devconfig *it) { @@ -363,6 +327,22 @@ static int das6402_attach(struct comedi_device *dev, return 0; } +static void das6402_detach(struct comedi_device *dev) +{ + if (dev->irq) + free_irq(dev->irq, dev); + if (dev->iobase) + release_region(dev->iobase, DAS6402_SIZE); +} + +static struct comedi_driver das6402_driver = { + .driver_name = "das6402", + .module = THIS_MODULE, + .attach = das6402_attach, + .detach = das6402_detach, +}; +module_comedi_driver(das6402_driver) + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/das800.c b/trunk/drivers/staging/comedi/drivers/das800.c index 6e347b40fe61..a3a54e1c5c98 100644 --- a/trunk/drivers/staging/comedi/drivers/das800.c +++ b/trunk/drivers/staging/comedi/drivers/das800.c @@ -245,7 +245,7 @@ struct das800_private { static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int das800_detach(struct comedi_device *dev); +static void das800_detach(struct comedi_device *dev); static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s); static struct comedi_driver driver_das800 = { @@ -556,16 +556,12 @@ static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; }; -static int das800_detach(struct comedi_device *dev) +static void das800_detach(struct comedi_device *dev) { - dev_info(dev->hw_dev, "comedi%d: das800: remove\n", dev->minor); - - /* only free stuff if it has been allocated by _attach */ if (dev->iobase) release_region(dev->iobase, DAS800_SIZE); if (dev->irq) free_irq(dev->irq, dev); - return 0; }; static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s) diff --git a/trunk/drivers/staging/comedi/drivers/dmm32at.c b/trunk/drivers/staging/comedi/drivers/dmm32at.c index 2b4e6e6eb825..83828903db4b 100644 --- a/trunk/drivers/staging/comedi/drivers/dmm32at.c +++ b/trunk/drivers/staging/comedi/drivers/dmm32at.c @@ -224,7 +224,7 @@ struct dmm32at_private { */ static int dmm32at_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int dmm32at_detach(struct comedi_device *dev); +static void dmm32at_detach(struct comedi_device *dev); static struct comedi_driver driver_dmm32at = { .driver_name = "dmm32at", .module = THIS_MODULE, @@ -450,23 +450,12 @@ static int dmm32at_attach(struct comedi_device *dev, } -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int dmm32at_detach(struct comedi_device *dev) +static void dmm32at_detach(struct comedi_device *dev) { - printk(KERN_INFO "comedi%d: dmm32at: remove\n", dev->minor); if (dev->irq) free_irq(dev->irq, dev); if (dev->iobase) release_region(dev->iobase, DMM32AT_MEMSIZE); - - return 0; } /* diff --git a/trunk/drivers/staging/comedi/drivers/dt2801.c b/trunk/drivers/staging/comedi/drivers/dt2801.c index b85c8366a396..625bd617a8e9 100644 --- a/trunk/drivers/staging/comedi/drivers/dt2801.c +++ b/trunk/drivers/staging/comedi/drivers/dt2801.c @@ -88,29 +88,6 @@ Configuration options: #define DT2801_STATUS 1 #define DT2801_CMD 1 -static int dt2801_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int dt2801_detach(struct comedi_device *dev); -static struct comedi_driver driver_dt2801 = { - .driver_name = "dt2801", - .module = THIS_MODULE, - .attach = dt2801_attach, - .detach = dt2801_detach, -}; - -static int __init driver_dt2801_init_module(void) -{ - return comedi_driver_register(&driver_dt2801); -} - -static void __exit driver_dt2801_cleanup_module(void) -{ - comedi_driver_unregister(&driver_dt2801); -} - -module_init(driver_dt2801_init_module); -module_exit(driver_dt2801_cleanup_module); - #if 0 /* ignore 'defined but not used' warning */ static const struct comedi_lrange range_dt2801_ai_pgh_bipolar = { 4, { @@ -258,22 +235,6 @@ struct dt2801_private { #define devpriv ((struct dt2801_private *)dev->private) -static int dt2801_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int dt2801_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int dt2801_ao_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int dt2801_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int dt2801_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - /* These are the low-level routines: writecommand: write a command to the board writedata: write data byte @@ -503,6 +464,123 @@ static const struct comedi_lrange *ai_range_lkup(int type, int opt) return &range_unknown; } +static int dt2801_error(struct comedi_device *dev, int stat) +{ + if (stat < 0) { + if (stat == -ETIME) + printk("dt2801: timeout\n"); + else + printk("dt2801: error %d\n", stat); + return stat; + } + printk("dt2801: error status 0x%02x, resetting...\n", stat); + + dt2801_reset(dev); + dt2801_reset(dev); + + return -EIO; +} + +static int dt2801_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + int d; + int stat; + int i; + + for (i = 0; i < insn->n; i++) { + stat = dt2801_writecmd(dev, DT_C_READ_ADIM); + dt2801_writedata(dev, CR_RANGE(insn->chanspec)); + dt2801_writedata(dev, CR_CHAN(insn->chanspec)); + stat = dt2801_readdata2(dev, &d); + + if (stat != 0) + return dt2801_error(dev, stat); + + data[i] = d; + } + + return i; +} + +static int dt2801_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + data[0] = devpriv->ao_readback[CR_CHAN(insn->chanspec)]; + + return 1; +} + +static int dt2801_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + dt2801_writecmd(dev, DT_C_WRITE_DAIM); + dt2801_writedata(dev, CR_CHAN(insn->chanspec)); + dt2801_writedata2(dev, data[0]); + + devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[0]; + + return 1; +} + +static int dt2801_dio_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + int which = 0; + + if (s == dev->subdevices + 4) + which = 1; + + if (insn->n != 2) + return -EINVAL; + if (data[0]) { + s->state &= ~data[0]; + s->state |= (data[0] & data[1]); + dt2801_writecmd(dev, DT_C_WRITE_DIG); + dt2801_writedata(dev, which); + dt2801_writedata(dev, s->state); + } + dt2801_writecmd(dev, DT_C_READ_DIG); + dt2801_writedata(dev, which); + dt2801_readdata(dev, data + 1); + + return 2; +} + +static int dt2801_dio_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + int which = 0; + + if (s == dev->subdevices + 4) + which = 1; + + /* configure */ + switch (data[0]) { + case INSN_CONFIG_DIO_OUTPUT: + s->io_bits = 0xff; + dt2801_writecmd(dev, DT_C_SET_DIGOUT); + break; + case INSN_CONFIG_DIO_INPUT: + s->io_bits = 0; + dt2801_writecmd(dev, DT_C_SET_DIGIN); + break; + case INSN_CONFIG_DIO_QUERY: + data[1] = s->io_bits ? COMEDI_OUTPUT : COMEDI_INPUT; + return insn->n; + default: + return -EINVAL; + } + dt2801_writedata(dev, which); + + return 1; +} + /* options: [0] - i/o base @@ -615,130 +693,19 @@ static int dt2801_attach(struct comedi_device *dev, struct comedi_devconfig *it) return ret; } -static int dt2801_detach(struct comedi_device *dev) +static void dt2801_detach(struct comedi_device *dev) { if (dev->iobase) release_region(dev->iobase, DT2801_IOSIZE); - - return 0; -} - -static int dt2801_error(struct comedi_device *dev, int stat) -{ - if (stat < 0) { - if (stat == -ETIME) - printk("dt2801: timeout\n"); - else - printk("dt2801: error %d\n", stat); - return stat; - } - printk("dt2801: error status 0x%02x, resetting...\n", stat); - - dt2801_reset(dev); - dt2801_reset(dev); - - return -EIO; -} - -static int dt2801_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int d; - int stat; - int i; - - for (i = 0; i < insn->n; i++) { - stat = dt2801_writecmd(dev, DT_C_READ_ADIM); - dt2801_writedata(dev, CR_RANGE(insn->chanspec)); - dt2801_writedata(dev, CR_CHAN(insn->chanspec)); - stat = dt2801_readdata2(dev, &d); - - if (stat != 0) - return dt2801_error(dev, stat); - - data[i] = d; - } - - return i; -} - -static int dt2801_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - data[0] = devpriv->ao_readback[CR_CHAN(insn->chanspec)]; - - return 1; -} - -static int dt2801_ao_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - dt2801_writecmd(dev, DT_C_WRITE_DAIM); - dt2801_writedata(dev, CR_CHAN(insn->chanspec)); - dt2801_writedata2(dev, data[0]); - - devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[0]; - - return 1; -} - -static int dt2801_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int which = 0; - - if (s == dev->subdevices + 4) - which = 1; - - if (insn->n != 2) - return -EINVAL; - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - dt2801_writecmd(dev, DT_C_WRITE_DIG); - dt2801_writedata(dev, which); - dt2801_writedata(dev, s->state); - } - dt2801_writecmd(dev, DT_C_READ_DIG); - dt2801_writedata(dev, which); - dt2801_readdata(dev, data + 1); - - return 2; } -static int dt2801_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int which = 0; - - if (s == dev->subdevices + 4) - which = 1; - - /* configure */ - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits = 0xff; - dt2801_writecmd(dev, DT_C_SET_DIGOUT); - break; - case INSN_CONFIG_DIO_INPUT: - s->io_bits = 0; - dt2801_writecmd(dev, DT_C_SET_DIGIN); - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = s->io_bits ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - default: - return -EINVAL; - } - dt2801_writedata(dev, which); - - return 1; -} +static struct comedi_driver dt2801_driver = { + .driver_name = "dt2801", + .module = THIS_MODULE, + .attach = dt2801_attach, + .detach = dt2801_detach, +}; +module_comedi_driver(dt2801_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/dt2811.c b/trunk/drivers/staging/comedi/drivers/dt2811.c index 0131d5225b52..106ffea30b95 100644 --- a/trunk/drivers/staging/comedi/drivers/dt2811.c +++ b/trunk/drivers/staging/comedi/drivers/dt2811.c @@ -211,61 +211,8 @@ struct dt2811_board { const struct comedi_lrange *unip_5; }; -static const struct dt2811_board boardtypes[] = { - {"dt2811-pgh", - &range_dt2811_pgh_ai_5_bipolar, - &range_dt2811_pgh_ai_2_5_bipolar, - &range_dt2811_pgh_ai_5_unipolar, - }, - {"dt2811-pgl", - &range_dt2811_pgl_ai_5_bipolar, - &range_dt2811_pgl_ai_2_5_bipolar, - &range_dt2811_pgl_ai_5_unipolar, - }, -}; - #define this_board ((const struct dt2811_board *)dev->board_ptr) -static int dt2811_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int dt2811_detach(struct comedi_device *dev); -static struct comedi_driver driver_dt2811 = { - .driver_name = "dt2811", - .module = THIS_MODULE, - .attach = dt2811_attach, - .detach = dt2811_detach, - .board_name = &boardtypes[0].name, - .num_names = ARRAY_SIZE(boardtypes), - .offset = sizeof(struct dt2811_board), -}; - -static int __init driver_dt2811_init_module(void) -{ - return comedi_driver_register(&driver_dt2811); -} - -static void __exit driver_dt2811_cleanup_module(void) -{ - comedi_driver_unregister(&driver_dt2811); -} - -module_init(driver_dt2811_init_module); -module_exit(driver_dt2811_cleanup_module); - -static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int dt2811_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int dt2811_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int dt2811_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - enum { card_2811_pgh, card_2811_pgl }; struct dt2811_private { @@ -317,6 +264,120 @@ static irqreturn_t dt2811_interrupt(int irq, void *d) } #endif +static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + int chan = CR_CHAN(insn->chanspec); + int timeout = DT2811_TIMEOUT; + int i; + + for (i = 0; i < insn->n; i++) { + outb(chan, dev->iobase + DT2811_ADGCR); + + while (timeout + && inb(dev->iobase + DT2811_ADCSR) & DT2811_ADBUSY) + timeout--; + if (!timeout) + return -ETIME; + + data[i] = inb(dev->iobase + DT2811_ADDATLO); + data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8; + data[i] &= 0xfff; + } + + return i; +} + +#if 0 +/* Wow. This is code from the Comedi stone age. But it hasn't been + * replaced, so I'll let it stay. */ +int dt2811_adtrig(kdev_t minor, comedi_adtrig *adtrig) +{ + struct comedi_device *dev = comedi_devices + minor; + + if (adtrig->n < 1) + return 0; + dev->curadchan = adtrig->chan; + switch (dev->i_admode) { + case COMEDI_MDEMAND: + dev->ntrig = adtrig->n - 1; + /* not necessary */ + /*printk("dt2811: AD soft trigger\n"); */ + /*outb(DT2811_CLRERROR|DT2811_INTENB, + dev->iobase+DT2811_ADCSR); */ + outb(dev->curadchan, dev->iobase + DT2811_ADGCR); + do_gettimeofday(&trigtime); + break; + case COMEDI_MCONTS: + dev->ntrig = adtrig->n; + break; + } + + return 0; +} +#endif + +static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + int i; + int chan; + + chan = CR_CHAN(insn->chanspec); + + for (i = 0; i < insn->n; i++) { + outb(data[i] & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan); + outb((data[i] >> 8) & 0xff, + dev->iobase + DT2811_DADAT0HI + 2 * chan); + devpriv->ao_readback[chan] = data[i]; + } + + return i; +} + +static int dt2811_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + int i; + int chan; + + chan = CR_CHAN(insn->chanspec); + + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; + + return i; +} + +static int dt2811_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + if (insn->n != 2) + return -EINVAL; + + data[1] = inb(dev->iobase + DT2811_DIO); + + return 2; +} + +static int dt2811_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + if (insn->n != 2) + return -EINVAL; + + s->state &= ~data[0]; + s->state |= data[0] & data[1]; + outb(s->state, dev->iobase + DT2811_DIO); + + data[1] = s->state; + + return 2; +} + /* options[0] Board base address options[1] IRQ @@ -337,7 +398,6 @@ static irqreturn_t dt2811_interrupt(int irq, void *d) 1 == bipolar 2.5V (-2.5V -- +2.5V) 2 == unipolar 5V (0V -- +5V) */ - static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) { /* int i, irq; */ @@ -511,131 +571,38 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -static int dt2811_detach(struct comedi_device *dev) +static void dt2811_detach(struct comedi_device *dev) { - printk(KERN_INFO "comedi%d: dt2811: remove\n", dev->minor); - if (dev->irq) free_irq(dev->irq, dev); if (dev->iobase) release_region(dev->iobase, DT2811_SIZE); - - return 0; -} - -static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int chan = CR_CHAN(insn->chanspec); - int timeout = DT2811_TIMEOUT; - int i; - - for (i = 0; i < insn->n; i++) { - outb(chan, dev->iobase + DT2811_ADGCR); - - while (timeout - && inb(dev->iobase + DT2811_ADCSR) & DT2811_ADBUSY) - timeout--; - if (!timeout) - return -ETIME; - - data[i] = inb(dev->iobase + DT2811_ADDATLO); - data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8; - data[i] &= 0xfff; - } - - return i; } -#if 0 -/* Wow. This is code from the Comedi stone age. But it hasn't been - * replaced, so I'll let it stay. */ -int dt2811_adtrig(kdev_t minor, comedi_adtrig *adtrig) -{ - struct comedi_device *dev = comedi_devices + minor; - - if (adtrig->n < 1) - return 0; - dev->curadchan = adtrig->chan; - switch (dev->i_admode) { - case COMEDI_MDEMAND: - dev->ntrig = adtrig->n - 1; - /* not necessary */ - /*printk("dt2811: AD soft trigger\n"); */ - /*outb(DT2811_CLRERROR|DT2811_INTENB, - dev->iobase+DT2811_ADCSR); */ - outb(dev->curadchan, dev->iobase + DT2811_ADGCR); - do_gettimeofday(&trigtime); - break; - case COMEDI_MCONTS: - dev->ntrig = adtrig->n; - break; - } - - return 0; -} -#endif - -static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int i; - int chan; - - chan = CR_CHAN(insn->chanspec); - - for (i = 0; i < insn->n; i++) { - outb(data[i] & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan); - outb((data[i] >> 8) & 0xff, - dev->iobase + DT2811_DADAT0HI + 2 * chan); - devpriv->ao_readback[chan] = data[i]; - } - - return i; -} - -static int dt2811_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int i; - int chan; - - chan = CR_CHAN(insn->chanspec); - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; - - return i; -} - -static int dt2811_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - if (insn->n != 2) - return -EINVAL; - - data[1] = inb(dev->iobase + DT2811_DIO); - - return 2; -} - -static int dt2811_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - if (insn->n != 2) - return -EINVAL; - - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - outb(s->state, dev->iobase + DT2811_DIO); - - data[1] = s->state; +static const struct dt2811_board boardtypes[] = { + { + .name = "dt2811-pgh", + .bip_5 = &range_dt2811_pgh_ai_5_bipolar, + .bip_2_5 = &range_dt2811_pgh_ai_2_5_bipolar, + .unip_5 = &range_dt2811_pgh_ai_5_unipolar, + }, { + .name = "dt2811-pgl", + .bip_5 = &range_dt2811_pgl_ai_5_bipolar, + .bip_2_5 = &range_dt2811_pgl_ai_2_5_bipolar, + .unip_5 = &range_dt2811_pgl_ai_5_unipolar, + }, +}; - return 2; -} +static struct comedi_driver dt2811_driver = { + .driver_name = "dt2811", + .module = THIS_MODULE, + .attach = dt2811_attach, + .detach = dt2811_detach, + .board_name = &boardtypes[0].name, + .num_names = ARRAY_SIZE(boardtypes), + .offset = sizeof(struct dt2811_board), +}; +module_comedi_driver(dt2811_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/dt2814.c b/trunk/drivers/staging/comedi/drivers/dt2814.c index 1c6248cf5928..fa4ade61be5f 100644 --- a/trunk/drivers/staging/comedi/drivers/dt2814.c +++ b/trunk/drivers/staging/comedi/drivers/dt2814.c @@ -60,31 +60,6 @@ addition, the clock does not seem to be very accurate. #define DT2814_ENB 0x10 #define DT2814_CHANMASK 0x0f -static int dt2814_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int dt2814_detach(struct comedi_device *dev); -static struct comedi_driver driver_dt2814 = { - .driver_name = "dt2814", - .module = THIS_MODULE, - .attach = dt2814_attach, - .detach = dt2814_detach, -}; - -static int __init driver_dt2814_init_module(void) -{ - return comedi_driver_register(&driver_dt2814); -} - -static void __exit driver_dt2814_cleanup_module(void) -{ - comedi_driver_unregister(&driver_dt2814); -} - -module_init(driver_dt2814_init_module); -module_exit(driver_dt2814_cleanup_module); - -static irqreturn_t dt2814_interrupt(int irq, void *dev); - struct dt2814_private { int ntrig; @@ -260,6 +235,45 @@ static int dt2814_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } +static irqreturn_t dt2814_interrupt(int irq, void *d) +{ + int lo, hi; + struct comedi_device *dev = d; + struct comedi_subdevice *s; + int data; + + if (!dev->attached) { + comedi_error(dev, "spurious interrupt"); + return IRQ_HANDLED; + } + + s = dev->subdevices + 0; + + hi = inb(dev->iobase + DT2814_DATA); + lo = inb(dev->iobase + DT2814_DATA); + + data = (hi << 4) | (lo >> 4); + + if (!(--devpriv->ntrig)) { + int i; + + outb(0, dev->iobase + DT2814_CSR); + /* note: turning off timed mode triggers another + sample. */ + + for (i = 0; i < DT2814_TIMEOUT; i++) { + if (inb(dev->iobase + DT2814_CSR) & DT2814_FINISH) + break; + } + inb(dev->iobase + DT2814_DATA); + inb(dev->iobase + DT2814_DATA); + + s->async->events |= COMEDI_CB_EOA; + } + comedi_event(dev, s); + return IRQ_HANDLED; +} + static int dt2814_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int i, irq; @@ -347,57 +361,21 @@ static int dt2814_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -static int dt2814_detach(struct comedi_device *dev) +static void dt2814_detach(struct comedi_device *dev) { - printk(KERN_INFO "comedi%d: dt2814: remove\n", dev->minor); - if (dev->irq) free_irq(dev->irq, dev); - if (dev->iobase) release_region(dev->iobase, DT2814_SIZE); - - return 0; } -static irqreturn_t dt2814_interrupt(int irq, void *d) -{ - int lo, hi; - struct comedi_device *dev = d; - struct comedi_subdevice *s; - int data; - - if (!dev->attached) { - comedi_error(dev, "spurious interrupt"); - return IRQ_HANDLED; - } - - s = dev->subdevices + 0; - - hi = inb(dev->iobase + DT2814_DATA); - lo = inb(dev->iobase + DT2814_DATA); - - data = (hi << 4) | (lo >> 4); - - if (!(--devpriv->ntrig)) { - int i; - - outb(0, dev->iobase + DT2814_CSR); - /* note: turning off timed mode triggers another - sample. */ - - for (i = 0; i < DT2814_TIMEOUT; i++) { - if (inb(dev->iobase + DT2814_CSR) & DT2814_FINISH) - break; - } - inb(dev->iobase + DT2814_DATA); - inb(dev->iobase + DT2814_DATA); - - s->async->events |= COMEDI_CB_EOA; - } - comedi_event(dev, s); - return IRQ_HANDLED; -} +static struct comedi_driver dt2814_driver = { + .driver_name = "dt2814", + .module = THIS_MODULE, + .attach = dt2814_attach, + .detach = dt2814_detach, +}; +module_comedi_driver(dt2814_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/dt2815.c b/trunk/drivers/staging/comedi/drivers/dt2815.c index 4155da43fd51..bbab712be4b9 100644 --- a/trunk/drivers/staging/comedi/drivers/dt2815.c +++ b/trunk/drivers/staging/comedi/drivers/dt2815.c @@ -72,31 +72,6 @@ static const struct comedi_lrange #define DT2815_DATA 0 #define DT2815_STATUS 1 -static int dt2815_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int dt2815_detach(struct comedi_device *dev); -static struct comedi_driver driver_dt2815 = { - .driver_name = "dt2815", - .module = THIS_MODULE, - .attach = dt2815_attach, - .detach = dt2815_detach, -}; - -static int __init driver_dt2815_init_module(void) -{ - return comedi_driver_register(&driver_dt2815); -} - -static void __exit driver_dt2815_cleanup_module(void) -{ - comedi_driver_unregister(&driver_dt2815); -} - -module_init(driver_dt2815_init_module); -module_exit(driver_dt2815_cleanup_module); - -static void dt2815_free_resources(struct comedi_device *dev); - struct dt2815_private { const struct comedi_lrange *range_type_list[8]; @@ -252,20 +227,19 @@ static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -static void dt2815_free_resources(struct comedi_device *dev) +static void dt2815_detach(struct comedi_device *dev) { if (dev->iobase) release_region(dev->iobase, DT2815_SIZE); } -static int dt2815_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: dt2815: remove\n", dev->minor); - - dt2815_free_resources(dev); - - return 0; -} +static struct comedi_driver dt2815_driver = { + .driver_name = "dt2815", + .module = THIS_MODULE, + .attach = dt2815_attach, + .detach = dt2815_detach, +}; +module_comedi_driver(dt2815_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/dt2817.c b/trunk/drivers/staging/comedi/drivers/dt2817.c index 99c1584153d7..1ee10e7bf1d2 100644 --- a/trunk/drivers/staging/comedi/drivers/dt2817.c +++ b/trunk/drivers/staging/comedi/drivers/dt2817.c @@ -47,29 +47,6 @@ Configuration options: #define DT2817_CR 0 #define DT2817_DATA 1 -static int dt2817_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int dt2817_detach(struct comedi_device *dev); -static struct comedi_driver driver_dt2817 = { - .driver_name = "dt2817", - .module = THIS_MODULE, - .attach = dt2817_attach, - .detach = dt2817_detach, -}; - -static int __init driver_dt2817_init_module(void) -{ - return comedi_driver_register(&driver_dt2817); -} - -static void __exit driver_dt2817_cleanup_module(void) -{ - comedi_driver_unregister(&driver_dt2817); -} - -module_init(driver_dt2817_init_module); -module_exit(driver_dt2817_cleanup_module); - static int dt2817_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -182,16 +159,20 @@ static int dt2817_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -static int dt2817_detach(struct comedi_device *dev) +static void dt2817_detach(struct comedi_device *dev) { - printk(KERN_INFO "comedi%d: dt2817: remove\n", dev->minor); - if (dev->iobase) release_region(dev->iobase, DT2817_SIZE); - - return 0; } +static struct comedi_driver dt2817_driver = { + .driver_name = "dt2817", + .module = THIS_MODULE, + .attach = dt2817_attach, + .detach = dt2817_detach, +}; +module_comedi_driver(dt2817_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/dt282x.c b/trunk/drivers/staging/comedi/drivers/dt282x.c index 95ebc267bb74..736d8facaee8 100644 --- a/trunk/drivers/staging/comedi/drivers/dt282x.c +++ b/trunk/drivers/staging/comedi/drivers/dt282x.c @@ -221,136 +221,6 @@ struct dt282x_board { int dabits; }; -static const struct dt282x_board boardtypes[] = { - {.name = "dt2821", - .adbits = 12, - .adchan_se = 16, - .adchan_di = 8, - .ai_speed = 20000, - .ispgl = 0, - .dachan = 2, - .dabits = 12, - }, - {.name = "dt2821-f", - .adbits = 12, - .adchan_se = 16, - .adchan_di = 8, - .ai_speed = 6500, - .ispgl = 0, - .dachan = 2, - .dabits = 12, - }, - {.name = "dt2821-g", - .adbits = 12, - .adchan_se = 16, - .adchan_di = 8, - .ai_speed = 4000, - .ispgl = 0, - .dachan = 2, - .dabits = 12, - }, - {.name = "dt2823", - .adbits = 16, - .adchan_se = 0, - .adchan_di = 4, - .ai_speed = 10000, - .ispgl = 0, - .dachan = 2, - .dabits = 16, - }, - {.name = "dt2824-pgh", - .adbits = 12, - .adchan_se = 16, - .adchan_di = 8, - .ai_speed = 20000, - .ispgl = 0, - .dachan = 0, - .dabits = 0, - }, - {.name = "dt2824-pgl", - .adbits = 12, - .adchan_se = 16, - .adchan_di = 8, - .ai_speed = 20000, - .ispgl = 1, - .dachan = 0, - .dabits = 0, - }, - {.name = "dt2825", - .adbits = 12, - .adchan_se = 16, - .adchan_di = 8, - .ai_speed = 20000, - .ispgl = 1, - .dachan = 2, - .dabits = 12, - }, - {.name = "dt2827", - .adbits = 16, - .adchan_se = 0, - .adchan_di = 4, - .ai_speed = 10000, - .ispgl = 0, - .dachan = 2, - .dabits = 12, - }, - {.name = "dt2828", - .adbits = 12, - .adchan_se = 4, - .adchan_di = 0, - .ai_speed = 10000, - .ispgl = 0, - .dachan = 2, - .dabits = 12, - }, - {.name = "dt2829", - .adbits = 16, - .adchan_se = 8, - .adchan_di = 0, - .ai_speed = 33250, - .ispgl = 0, - .dachan = 2, - .dabits = 16, - }, - {.name = "dt21-ez", - .adbits = 12, - .adchan_se = 16, - .adchan_di = 8, - .ai_speed = 10000, - .ispgl = 0, - .dachan = 2, - .dabits = 12, - }, - {.name = "dt23-ez", - .adbits = 16, - .adchan_se = 16, - .adchan_di = 8, - .ai_speed = 10000, - .ispgl = 0, - .dachan = 0, - .dabits = 0, - }, - {.name = "dt24-ez", - .adbits = 12, - .adchan_se = 16, - .adchan_di = 8, - .ai_speed = 10000, - .ispgl = 0, - .dachan = 0, - .dabits = 0, - }, - {.name = "dt24-ez-pgl", - .adbits = 12, - .adchan_se = 16, - .adchan_di = 8, - .ai_speed = 10000, - .ispgl = 1, - .dachan = 0, - .dabits = 0, - }, -}; - -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct dt282x_board)) #define this_board ((const struct dt282x_board *)dev->board_ptr) struct dt282x_private { @@ -411,33 +281,6 @@ struct dt282x_private { b \ } while (0) -static int dt282x_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int dt282x_detach(struct comedi_device *dev); -static struct comedi_driver driver_dt282x = { - .driver_name = "dt282x", - .module = THIS_MODULE, - .attach = dt282x_attach, - .detach = dt282x_detach, - .board_name = &boardtypes[0].name, - .num_names = n_boardtypes, - .offset = sizeof(struct dt282x_board), -}; - -static int __init driver_dt282x_init_module(void) -{ - return comedi_driver_register(&driver_dt282x); -} - -static void __exit driver_dt282x_cleanup_module(void) -{ - comedi_driver_unregister(&driver_dt282x); -} - -module_init(driver_dt282x_init_module); -module_exit(driver_dt282x_cleanup_module); - -static void free_resources(struct comedi_device *dev); static int prep_ai_dma(struct comedi_device *dev, int chan, int size); static int prep_ao_dma(struct comedi_device *dev, int chan, int size); static int dt282x_ai_cancel(struct comedi_device *dev, @@ -1271,6 +1114,52 @@ enum { /* i/o base, irq, dma channels */ opt_ai_range, opt_ao0_range, opt_ao1_range, /* range */ }; +static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2) +{ + int ret; + + devpriv->usedma = 0; + + if (!dma1 && !dma2) { + printk(KERN_ERR " (no dma)"); + return 0; + } + + if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7) + return -EINVAL; + + if (dma2 < dma1) { + int i; + i = dma1; + dma1 = dma2; + dma2 = i; + } + + ret = request_dma(dma1, "dt282x A"); + if (ret) + return -EBUSY; + devpriv->dma[0].chan = dma1; + + ret = request_dma(dma2, "dt282x B"); + if (ret) + return -EBUSY; + devpriv->dma[1].chan = dma2; + + devpriv->dma_maxsize = PAGE_SIZE; + devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); + devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); + if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) { + printk(KERN_ERR " can't get DMA memory"); + return -ENOMEM; + } + + printk(KERN_INFO " (dma=%d,%d)", dma1, dma2); + + devpriv->usedma = 1; + + return 0; +} + /* options: 0 i/o base @@ -1442,7 +1331,7 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -static void free_resources(struct comedi_device *dev) +static void dt282x_detach(struct comedi_device *dev) { if (dev->irq) free_irq(dev->irq, dev); @@ -1460,60 +1349,146 @@ static void free_resources(struct comedi_device *dev) } } -static int dt282x_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: dt282x: remove\n", dev->minor); - - free_resources(dev); - - return 0; -} - -static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2) -{ - int ret; - - devpriv->usedma = 0; - - if (!dma1 && !dma2) { - printk(KERN_ERR " (no dma)"); - return 0; - } - - if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7) - return -EINVAL; - - if (dma2 < dma1) { - int i; - i = dma1; - dma1 = dma2; - dma2 = i; - } - - ret = request_dma(dma1, "dt282x A"); - if (ret) - return -EBUSY; - devpriv->dma[0].chan = dma1; - - ret = request_dma(dma2, "dt282x B"); - if (ret) - return -EBUSY; - devpriv->dma[1].chan = dma2; - - devpriv->dma_maxsize = PAGE_SIZE; - devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); - devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); - if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) { - printk(KERN_ERR " can't get DMA memory"); - return -ENOMEM; - } - - printk(KERN_INFO " (dma=%d,%d)", dma1, dma2); - - devpriv->usedma = 1; +static const struct dt282x_board boardtypes[] = { + { + .name = "dt2821", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 20000, + .ispgl = 0, + .dachan = 2, + .dabits = 12, + }, { + .name = "dt2821-f", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 6500, + .ispgl = 0, + .dachan = 2, + .dabits = 12, + }, { + .name = "dt2821-g", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 4000, + .ispgl = 0, + .dachan = 2, + .dabits = 12, + }, { + .name = "dt2823", + .adbits = 16, + .adchan_se = 0, + .adchan_di = 4, + .ai_speed = 10000, + .ispgl = 0, + .dachan = 2, + .dabits = 16, + }, { + .name = "dt2824-pgh", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 20000, + .ispgl = 0, + .dachan = 0, + .dabits = 0, + }, { + .name = "dt2824-pgl", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 20000, + .ispgl = 1, + .dachan = 0, + .dabits = 0, + }, { + .name = "dt2825", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 20000, + .ispgl = 1, + .dachan = 2, + .dabits = 12, + }, { + .name = "dt2827", + .adbits = 16, + .adchan_se = 0, + .adchan_di = 4, + .ai_speed = 10000, + .ispgl = 0, + .dachan = 2, + .dabits = 12, + }, { + .name = "dt2828", + .adbits = 12, + .adchan_se = 4, + .adchan_di = 0, + .ai_speed = 10000, + .ispgl = 0, + .dachan = 2, + .dabits = 12, + }, { + .name = "dt2829", + .adbits = 16, + .adchan_se = 8, + .adchan_di = 0, + .ai_speed = 33250, + .ispgl = 0, + .dachan = 2, + .dabits = 16, + }, { + .name = "dt21-ez", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 10000, + .ispgl = 0, + .dachan = 2, + .dabits = 12, + }, { + .name = "dt23-ez", + .adbits = 16, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 10000, + .ispgl = 0, + .dachan = 0, + .dabits = 0, + }, { + .name = "dt24-ez", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 10000, + .ispgl = 0, + .dachan = 0, + .dabits = 0, + }, { + .name = "dt24-ez-pgl", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 10000, + .ispgl = 1, + .dachan = 0, + .dabits = 0, + }, +}; - return 0; -} +static struct comedi_driver dt282x_driver = { + .driver_name = "dt282x", + .module = THIS_MODULE, + .attach = dt282x_attach, + .detach = dt282x_detach, + .board_name = &boardtypes[0].name, + .num_names = ARRAY_SIZE(boardtypes), + .offset = sizeof(struct dt282x_board), +}; +module_comedi_driver(dt282x_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/dt3000.c b/trunk/drivers/staging/comedi/drivers/dt3000.c index 0a7979e52999..0d273269b572 100644 --- a/trunk/drivers/staging/comedi/drivers/dt3000.c +++ b/trunk/drivers/staging/comedi/drivers/dt3000.c @@ -164,19 +164,6 @@ static const struct dt3k_boardtype dt3k_boardtypes[] = { #define n_dt3k_boards sizeof(dt3k_boardtypes)/sizeof(struct dt3k_boardtype) #define this_board ((const struct dt3k_boardtype *)dev->board_ptr) -static DEFINE_PCI_DEVICE_TABLE(dt3k_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0022) }, - { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0027) }, - { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0023) }, - { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0024) }, - { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0028) }, - { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0025) }, - { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0026) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, dt3k_pci_table); - #define DT3000_SIZE (4*0x1000) /* dual-ported RAM location definitions */ @@ -276,54 +263,6 @@ struct dt3k_private { #define devpriv ((struct dt3k_private *)dev->private) -static int dt3000_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int dt3000_detach(struct comedi_device *dev); -static struct comedi_driver driver_dt3000 = { - .driver_name = "dt3000", - .module = THIS_MODULE, - .attach = dt3000_attach, - .detach = dt3000_detach, -}; - -static int __devinit driver_dt3000_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, driver_dt3000.driver_name); -} - -static void __devexit driver_dt3000_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_dt3000_pci_driver = { - .id_table = dt3k_pci_table, - .probe = &driver_dt3000_pci_probe, - .remove = __devexit_p(&driver_dt3000_pci_remove) -}; - -static int __init driver_dt3000_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_dt3000); - if (retval < 0) - return retval; - - driver_dt3000_pci_driver.name = (char *)driver_dt3000.driver_name; - return pci_register_driver(&driver_dt3000_pci_driver); -} - -static void __exit driver_dt3000_cleanup_module(void) -{ - pci_unregister_driver(&driver_dt3000_pci_driver); - comedi_driver_unregister(&driver_dt3000); -} - -module_init(driver_dt3000_init_module); -module_exit(driver_dt3000_cleanup_module); - static void dt3k_ai_empty_fifo(struct comedi_device *dev, struct comedi_subdevice *s); static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *arg, @@ -841,7 +780,77 @@ static int dt3k_mem_insn_read(struct comedi_device *dev, return i; } -static int dt_pci_probe(struct comedi_device *dev, int bus, int slot); +static int setup_pci(struct comedi_device *dev) +{ + resource_size_t addr; + int ret; + + ret = comedi_pci_enable(devpriv->pci_dev, "dt3000"); + if (ret < 0) + return ret; + + addr = pci_resource_start(devpriv->pci_dev, 0); + devpriv->phys_addr = addr; + devpriv->io_addr = ioremap(devpriv->phys_addr, DT3000_SIZE); + if (!devpriv->io_addr) + return -ENOMEM; +#if DEBUG + printk("0x%08llx mapped to %p, ", + (unsigned long long)devpriv->phys_addr, devpriv->io_addr); +#endif + + return 0; +} + +static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board) +{ + int i; + + for (from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from); + from != NULL; + from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from)) { + for (i = 0; i < n_dt3k_boards; i++) { + if (from->device == dt3k_boardtypes[i].device_id) { + *board = i; + return from; + } + } + printk + ("unknown Data Translation PCI device found with device_id=0x%04x\n", + from->device); + } + *board = -1; + return from; +} + +static int dt_pci_probe(struct comedi_device *dev, int bus, int slot) +{ + int board; + int ret; + struct pci_dev *pcidev; + + pcidev = NULL; + while ((pcidev = dt_pci_find_device(pcidev, &board)) != NULL) { + if ((bus == 0 && slot == 0) || + (pcidev->bus->number == bus && + PCI_SLOT(pcidev->devfn) == slot)) { + break; + } + } + devpriv->pci_dev = pcidev; + + if (board >= 0) + dev->board_ptr = dt3k_boardtypes + board; + + if (!devpriv->pci_dev) + return 0; + + ret = setup_pci(dev); + if (ret < 0) + return ret; + + return 1; +} static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it) { @@ -935,11 +944,10 @@ static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -static int dt3000_detach(struct comedi_device *dev) +static void dt3000_detach(struct comedi_device *dev) { if (dev->irq) free_irq(dev->irq, dev); - if (devpriv) { if (devpriv->pci_dev) { if (devpriv->phys_addr) @@ -949,85 +957,45 @@ static int dt3000_detach(struct comedi_device *dev) if (devpriv->io_addr) iounmap(devpriv->io_addr); } - /* XXX */ - - return 0; } -static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board); -static int setup_pci(struct comedi_device *dev); +static struct comedi_driver dt3000_driver = { + .driver_name = "dt3000", + .module = THIS_MODULE, + .attach = dt3000_attach, + .detach = dt3000_detach, +}; -static int dt_pci_probe(struct comedi_device *dev, int bus, int slot) +static int __devinit dt3000_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) { - int board; - int ret; - struct pci_dev *pcidev; - - pcidev = NULL; - while ((pcidev = dt_pci_find_device(pcidev, &board)) != NULL) { - if ((bus == 0 && slot == 0) || - (pcidev->bus->number == bus && - PCI_SLOT(pcidev->devfn) == slot)) { - break; - } - } - devpriv->pci_dev = pcidev; - - if (board >= 0) - dev->board_ptr = dt3k_boardtypes + board; - - if (!devpriv->pci_dev) - return 0; - - ret = setup_pci(dev); - if (ret < 0) - return ret; - - return 1; + return comedi_pci_auto_config(dev, &dt3000_driver); } -static int setup_pci(struct comedi_device *dev) +static void __devexit dt3000_pci_remove(struct pci_dev *dev) { - resource_size_t addr; - int ret; - - ret = comedi_pci_enable(devpriv->pci_dev, "dt3000"); - if (ret < 0) - return ret; - - addr = pci_resource_start(devpriv->pci_dev, 0); - devpriv->phys_addr = addr; - devpriv->io_addr = ioremap(devpriv->phys_addr, DT3000_SIZE); - if (!devpriv->io_addr) - return -ENOMEM; -#if DEBUG - printk("0x%08llx mapped to %p, ", - (unsigned long long)devpriv->phys_addr, devpriv->io_addr); -#endif - - return 0; + comedi_pci_auto_unconfig(dev); } -static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board) -{ - int i; +static DEFINE_PCI_DEVICE_TABLE(dt3000_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0022) }, + { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0027) }, + { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0023) }, + { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0024) }, + { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0028) }, + { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0025) }, + { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0026) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, dt3000_pci_table); - for (from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from); - from != NULL; - from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from)) { - for (i = 0; i < n_dt3k_boards; i++) { - if (from->device == dt3k_boardtypes[i].device_id) { - *board = i; - return from; - } - } - printk - ("unknown Data Translation PCI device found with device_id=0x%04x\n", - from->device); - } - *board = -1; - return from; -} +static struct pci_driver dt3000_pci_driver = { + .name = "dt3000", + .id_table = dt3000_pci_table, + .probe = dt3000_pci_probe, + .remove = __devexit_p(dt3000_pci_remove), +}; +module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/dt9812.c b/trunk/drivers/staging/comedi/drivers/dt9812.c index e86ab5862895..22cda5c76ce4 100644 --- a/trunk/drivers/staging/comedi/drivers/dt9812.c +++ b/trunk/drivers/staging/comedi/drivers/dt9812.c @@ -196,7 +196,7 @@ struct dt9812_flash_data { }; #define DT9812_MAX_NUM_MULTI_BYTE_RDS \ - ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / sizeof(u8)) + ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / sizeof(u8)) struct dt9812_read_multi { u8 count; @@ -209,8 +209,8 @@ struct dt9812_write_byte { }; #define DT9812_MAX_NUM_MULTI_BYTE_WRTS \ - ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / \ - sizeof(struct dt9812_write_byte)) + ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / \ + sizeof(struct dt9812_write_byte)) struct dt9812_write_multi { u8 count; @@ -224,7 +224,8 @@ struct dt9812_rmw_byte { }; #define DT9812_MAX_NUM_MULTI_BYTE_RMWS \ - ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / sizeof(struct dt9812_rmw_byte)) + ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / \ + sizeof(struct dt9812_rmw_byte)) struct dt9812_rmw_multi { u8 count; @@ -365,7 +366,7 @@ static int dt9812_read_info(struct usb_dt9812 *dev, int offset, void *buf, } static int dt9812_read_multiple_registers(struct usb_dt9812 *dev, int reg_count, - u8 * address, u8 * value) + u8 *address, u8 *value) { struct dt9812_usb_cmd cmd; int i, count, retval; @@ -391,8 +392,8 @@ static int dt9812_read_multiple_registers(struct usb_dt9812 *dev, int reg_count, } static int dt9812_write_multiple_registers(struct usb_dt9812 *dev, - int reg_count, u8 * address, - u8 * value) + int reg_count, u8 *address, + u8 *value) { struct dt9812_usb_cmd cmd; int i, count, retval; @@ -430,7 +431,7 @@ static int dt9812_rmw_multiple_registers(struct usb_dt9812 *dev, int reg_count, return retval; } -static int dt9812_digital_in(struct slot_dt9812 *slot, u8 * bits) +static int dt9812_digital_in(struct slot_dt9812 *slot, u8 *bits) { int result = -ENODEV; @@ -476,7 +477,7 @@ static int dt9812_digital_out(struct slot_dt9812 *slot, u8 bits) return result; } -static int dt9812_digital_out_shadow(struct slot_dt9812 *slot, u8 * bits) +static int dt9812_digital_out_shadow(struct slot_dt9812 *slot, u8 *bits) { int result = -ENODEV; @@ -547,12 +548,12 @@ static void dt9812_configure_gain(struct usb_dt9812 *dev, rmw->or_value = F020_MASK_ADC0CF_AMP0GN2; break; default: - err("Illegal gain %d\n", gain); + dev_err(&dev->interface->dev, "Illegal gain %d\n", gain); } } -static int dt9812_analog_in(struct slot_dt9812 *slot, int channel, u16 * value, +static int dt9812_analog_in(struct slot_dt9812 *slot, int channel, u16 *value, enum dt9812_gain gain) { struct dt9812_rmw_byte rmw[3]; @@ -619,7 +620,7 @@ static int dt9812_analog_in(struct slot_dt9812 *slot, int channel, u16 * value, } static int dt9812_analog_out_shadow(struct slot_dt9812 *slot, int channel, - u16 * value) + u16 *value) { int result = -ENODEV; @@ -715,7 +716,7 @@ static int dt9812_probe(struct usb_interface *interface, iface_desc = interface->cur_altsetting; if (iface_desc->desc.bNumEndpoints != 5) { - err("Wrong number of endpints."); + dev_err(&interface->dev, "Wrong number of endpoints.\n"); retval = -ENODEV; goto error; } @@ -781,22 +782,22 @@ static int dt9812_probe(struct usb_interface *interface, } if (dt9812_read_info(dev, 1, &dev->vendor, sizeof(dev->vendor)) != 0) { - err("Failed to read vendor."); + dev_err(&interface->dev, "Failed to read vendor.\n"); retval = -ENODEV; goto error; } if (dt9812_read_info(dev, 3, &dev->product, sizeof(dev->product)) != 0) { - err("Failed to read product."); + dev_err(&interface->dev, "Failed to read product.\n"); retval = -ENODEV; goto error; } if (dt9812_read_info(dev, 5, &dev->device, sizeof(dev->device)) != 0) { - err("Failed to read device."); + dev_err(&interface->dev, "Failed to read device.\n"); retval = -ENODEV; goto error; } if (dt9812_read_info(dev, 7, &dev->serial, sizeof(dev->serial)) != 0) { - err("Failed to read serial."); + dev_err(&interface->dev, "Failed to read serial.\n"); retval = -ENODEV; goto error; } @@ -1110,9 +1111,9 @@ static int dt9812_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -static int dt9812_detach(struct comedi_device *dev) +static void dt9812_detach(struct comedi_device *dev) { - return 0; + /* Nothing to cleanup */ } static struct comedi_driver dt9812_comedi_driver = { @@ -1146,7 +1147,9 @@ static int __init usb_dt9812_init(void) result = comedi_driver_register(&dt9812_comedi_driver); if (result) { usb_deregister(&dt9812_usb_driver); - err("comedi_driver_register failed. Error number %d", result); + printk(KERN_ERR KBUILD_MODNAME + ": comedi_driver_register failed. Error number %d\n", + result); } return result; diff --git a/trunk/drivers/staging/comedi/drivers/dyna_pci10xx.c b/trunk/drivers/staging/comedi/drivers/dyna_pci10xx.c index da8a2bf31657..b0cec7b1b0c9 100644 --- a/trunk/drivers/staging/comedi/drivers/dyna_pci10xx.c +++ b/trunk/drivers/staging/comedi/drivers/dyna_pci10xx.c @@ -48,17 +48,6 @@ static DEFINE_MUTEX(start_stop_sem); -static DEFINE_PCI_DEVICE_TABLE(dyna_pci10xx_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_DYNALOG, 0x1050) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, dyna_pci10xx_pci_table); - -static int dyna_pci10xx_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int dyna_pci10xx_detach(struct comedi_device *dev); - static const struct comedi_lrange range_pci1050_ai = { 3, { BIP_RANGE(10), BIP_RANGE(5), @@ -113,16 +102,6 @@ static const struct boardtype boardtypes[] = { {.name = DRV_NAME}, }; -static struct comedi_driver driver_dyna_pci10xx = { - .driver_name = DRV_NAME, - .module = THIS_MODULE, - .attach = dyna_pci10xx_attach, - .detach = dyna_pci10xx_detach, - .board_name = &boardtypes[0].name, - .offset = sizeof(struct boardtype), - .num_names = ARRAY_SIZE(boardtypes), -}; - struct dyna_pci10xx_private { struct pci_dev *pci_dev; /* ptr to PCI device */ char valid; /* card is usable */ @@ -408,54 +387,48 @@ static int dyna_pci10xx_attach(struct comedi_device *dev, return 1; } -static int dyna_pci10xx_detach(struct comedi_device *dev) +static void dyna_pci10xx_detach(struct comedi_device *dev) { if (devpriv && devpriv->pci_dev) { comedi_pci_disable(devpriv->pci_dev); mutex_destroy(&devpriv->mutex); } - - return 0; } -static int __devinit driver_dyna_pci10xx_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) +static struct comedi_driver dyna_pci10xx_driver = { + .driver_name = "dyna_pci10xx", + .module = THIS_MODULE, + .attach = dyna_pci10xx_attach, + .detach = dyna_pci10xx_detach, + .board_name = &boardtypes[0].name, + .offset = sizeof(struct boardtype), + .num_names = ARRAY_SIZE(boardtypes), +}; + +static int __devinit dyna_pci10xx_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, driver_dyna_pci10xx.driver_name); + return comedi_pci_auto_config(dev, &dyna_pci10xx_driver); } -static void __devexit driver_dyna_pci10xx_pci_remove(struct pci_dev *dev) +static void __devexit dyna_pci10xx_pci_remove(struct pci_dev *dev) { comedi_pci_auto_unconfig(dev); } -static struct pci_driver driver_dyna_pci10xx_pci_driver = { - .id_table = dyna_pci10xx_pci_table, - .probe = &driver_dyna_pci10xx_pci_probe, - .remove = __devexit_p(&driver_dyna_pci10xx_pci_remove) +static DEFINE_PCI_DEVICE_TABLE(dyna_pci10xx_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_DYNALOG, 0x1050) }, + { 0 } }; +MODULE_DEVICE_TABLE(pci, dyna_pci10xx_pci_table); -static int __init driver_dyna_pci10xx_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_dyna_pci10xx); - if (retval < 0) - return retval; - - driver_dyna_pci10xx_pci_driver.name = - (char *)driver_dyna_pci10xx.driver_name; - return pci_register_driver(&driver_dyna_pci10xx_pci_driver); -} - -static void __exit driver_dyna_pci10xx_cleanup_module(void) -{ - pci_unregister_driver(&driver_dyna_pci10xx_pci_driver); - comedi_driver_unregister(&driver_dyna_pci10xx); -} - -module_init(driver_dyna_pci10xx_init_module); -module_exit(driver_dyna_pci10xx_cleanup_module); +static struct pci_driver dyna_pci10xx_pci_driver = { + .name = "dyna_pci10xx", + .id_table = dyna_pci10xx_pci_table, + .probe = dyna_pci10xx_pci_probe, + .remove = __devexit_p(dyna_pci10xx_pci_remove), +}; +module_comedi_pci_driver(dyna_pci10xx_driver, dyna_pci10xx_pci_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Prashant Shah "); diff --git a/trunk/drivers/staging/comedi/drivers/fl512.c b/trunk/drivers/staging/comedi/drivers/fl512.c index 7f49add60b21..d23814450b40 100644 --- a/trunk/drivers/staging/comedi/drivers/fl512.c +++ b/trunk/drivers/staging/comedi/drivers/fl512.c @@ -42,38 +42,6 @@ static const struct comedi_lrange range_fl512 = { 4, { } }; -static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int fl512_detach(struct comedi_device *dev); - -static struct comedi_driver driver_fl512 = { - .driver_name = "fl512", - .module = THIS_MODULE, - .attach = fl512_attach, - .detach = fl512_detach, -}; - -static int __init driver_fl512_init_module(void) -{ - return comedi_driver_register(&driver_fl512); -} - -static void __exit driver_fl512_cleanup_module(void) -{ - comedi_driver_unregister(&driver_fl512); -} - -module_init(driver_fl512_init_module); -module_exit(driver_fl512_cleanup_module); - -static int fl512_ai_insn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); -static int fl512_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int fl512_ao_insn_readback(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - /* * fl512_ai_insn : this is the analog input function */ @@ -140,9 +108,6 @@ static int fl512_ao_insn_readback(struct comedi_device *dev, return n; } -/* - * start attach - */ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it) { unsigned long iobase; @@ -209,14 +174,20 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 1; } -static int fl512_detach(struct comedi_device *dev) +static void fl512_detach(struct comedi_device *dev) { if (dev->iobase) release_region(dev->iobase, FL512_SIZE); - printk(KERN_INFO "comedi%d: fl512: dummy i detach\n", dev->minor); - return 0; } +static struct comedi_driver fl512_driver = { + .driver_name = "fl512", + .module = THIS_MODULE, + .attach = fl512_attach, + .detach = fl512_detach, +}; +module_comedi_driver(fl512_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/gsc_hpdi.c b/trunk/drivers/staging/comedi/drivers/gsc_hpdi.c index bc020dea141b..8aece08bd0dd 100644 --- a/trunk/drivers/staging/comedi/drivers/gsc_hpdi.c +++ b/trunk/drivers/staging/comedi/drivers/gsc_hpdi.c @@ -53,8 +53,6 @@ support could be added to this driver. #include "plx9080.h" #include "comedi_fc.h" -static int hpdi_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int hpdi_detach(struct comedi_device *dev); static void abort_dma(struct comedi_device *dev, unsigned int channel); static int hpdi_cmd(struct comedi_device *dev, struct comedi_subdevice *s); static int hpdi_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, @@ -287,15 +285,6 @@ static const struct hpdi_board hpdi_boards[] = { #endif }; -static DEFINE_PCI_DEVICE_TABLE(hpdi_pci_table) = { - { - PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9080, PCI_VENDOR_ID_PLX, - 0x2400, 0, 0, 0}, { - 0} -}; - -MODULE_DEVICE_TABLE(pci, hpdi_pci_table); - static inline struct hpdi_board *board(const struct comedi_device *dev) { return (struct hpdi_board *)dev->board_ptr; @@ -338,51 +327,6 @@ static inline struct hpdi_private *priv(struct comedi_device *dev) return dev->private; } -static struct comedi_driver driver_hpdi = { - .driver_name = "gsc_hpdi", - .module = THIS_MODULE, - .attach = hpdi_attach, - .detach = hpdi_detach, -}; - -static int __devinit driver_hpdi_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, driver_hpdi.driver_name); -} - -static void __devexit driver_hpdi_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_hpdi_pci_driver = { - .id_table = hpdi_pci_table, - .probe = &driver_hpdi_pci_probe, - .remove = __devexit_p(&driver_hpdi_pci_remove) -}; - -static int __init driver_hpdi_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_hpdi); - if (retval < 0) - return retval; - - driver_hpdi_pci_driver.name = (char *)driver_hpdi.driver_name; - return pci_register_driver(&driver_hpdi_pci_driver); -} - -static void __exit driver_hpdi_cleanup_module(void) -{ - pci_unregister_driver(&driver_hpdi_pci_driver); - comedi_driver_unregister(&driver_hpdi); -} - -module_init(driver_hpdi_init_module); -module_exit(driver_hpdi_cleanup_module); - static int dio_config_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -645,7 +589,7 @@ static int hpdi_attach(struct comedi_device *dev, struct comedi_devconfig *it) "gsc_hpdi: found %s on bus %i, slot %i\n", board(dev)->name, pcidev->bus->number, PCI_SLOT(pcidev->devfn)); - if (comedi_pci_enable(pcidev, driver_hpdi.driver_name)) { + if (comedi_pci_enable(pcidev, dev->driver->driver_name)) { printk(KERN_WARNING " failed enable PCI device and request regions\n"); return -EIO; @@ -679,7 +623,7 @@ static int hpdi_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* get irq */ if (request_irq(pcidev->irq, handle_interrupt, IRQF_SHARED, - driver_hpdi.driver_name, dev)) { + dev->driver->driver_name, dev)) { printk(KERN_WARNING " unable to allocate irq %u\n", pcidev->irq); return -EINVAL; @@ -720,12 +664,10 @@ static int hpdi_attach(struct comedi_device *dev, struct comedi_devconfig *it) return init_hpdi(dev); } -static int hpdi_detach(struct comedi_device *dev) +static void hpdi_detach(struct comedi_device *dev) { unsigned int i; - printk(KERN_WARNING "comedi%d: gsc_hpdi: remove\n", dev->minor); - if (dev->irq) free_irq(dev->irq, dev); if ((priv(dev)) && (priv(dev)->hw_dev)) { @@ -758,7 +700,6 @@ static int hpdi_detach(struct comedi_device *dev) comedi_pci_disable(priv(dev)->hw_dev); pci_dev_put(priv(dev)->hw_dev); } - return 0; } static int dio_config_block_size(struct comedi_device *dev, unsigned int *data) @@ -1113,6 +1054,39 @@ static int hpdi_cancel(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } +static struct comedi_driver gsc_hpdi_driver = { + .driver_name = "gsc_hpdi", + .module = THIS_MODULE, + .attach = hpdi_attach, + .detach = hpdi_detach, +}; + +static int __devinit gsc_hpdi_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + return comedi_pci_auto_config(dev, &gsc_hpdi_driver); +} + +static void __devexit gsc_hpdi_pci_remove(struct pci_dev *dev) +{ + comedi_pci_auto_unconfig(dev); +} + +static DEFINE_PCI_DEVICE_TABLE(gsc_hpdi_pci_table) = { + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9080, PCI_VENDOR_ID_PLX, + 0x2400, 0, 0, 0}, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, gsc_hpdi_pci_table); + +static struct pci_driver gsc_hpdi_pci_driver = { + .name = "gsc_hpdi", + .id_table = gsc_hpdi_pci_table, + .probe = gsc_hpdi_pci_probe, + .remove = __devexit_p(gsc_hpdi_pci_remove) +}; +module_comedi_pci_driver(gsc_hpdi_driver, gsc_hpdi_pci_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/icp_multi.c b/trunk/drivers/staging/comedi/drivers/icp_multi.c index 126550f3c02b..fdc596fb0990 100644 --- a/trunk/drivers/staging/comedi/drivers/icp_multi.c +++ b/trunk/drivers/staging/comedi/drivers/icp_multi.c @@ -119,15 +119,6 @@ static const struct comedi_lrange range_analog = { 4, { static const char range_codes_analog[] = { 0x00, 0x20, 0x10, 0x30 }; -/* -============================================================================== - Forward declarations -============================================================================== -*/ -static int icp_multi_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int icp_multi_detach(struct comedi_device *dev); - /* ============================================================================== Data & Structure declarations @@ -154,50 +145,6 @@ struct boardtype { const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */ }; -static const struct boardtype boardtypes[] = { - {"icp_multi", /* Driver name */ - DEVICE_ID, /* PCI device ID */ - IORANGE_ICP_MULTI, /* I/O range length */ - 1, /* 1=Card supports interrupts */ - TYPE_ICP_MULTI, /* Card type = ICP MULTI */ - 16, /* Num of A/D channels */ - 8, /* Num of A/D channels in diff mode */ - 4, /* Num of D/A channels */ - 16, /* Num of digital inputs */ - 8, /* Num of digital outputs */ - 4, /* Num of counters */ - 0x0fff, /* Resolution of A/D */ - 0x0fff, /* Resolution of D/A */ - &range_analog, /* Rangelist for A/D */ - range_codes_analog, /* Range codes for programming */ - &range_analog}, /* Rangelist for D/A */ -}; - -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype)) - -static struct comedi_driver driver_icp_multi = { - .driver_name = "icp_multi", - .module = THIS_MODULE, - .attach = icp_multi_attach, - .detach = icp_multi_detach, - .num_names = n_boardtypes, - .board_name = &boardtypes[0].name, - .offset = sizeof(struct boardtype), -}; - -static int __init driver_icp_multi_init_module(void) -{ - return comedi_driver_register(&driver_icp_multi); -} - -static void __exit driver_icp_multi_cleanup_module(void) -{ - comedi_driver_unregister(&driver_icp_multi); -} - -module_init(driver_icp_multi_init_module); -module_exit(driver_icp_multi_cleanup_module); - struct icp_multi_private { struct pcilst_struct *card; /* pointer to card */ char valid; /* card is usable */ @@ -222,25 +169,81 @@ struct icp_multi_private { /* ============================================================================== - More forward declarations + +Name: setup_channel_list + +Description: + This function sets the appropriate channel selection, + differential input mode and range bits in the ADC Command/ + Status register. + +Parameters: + struct comedi_device *dev Pointer to current service structure + struct comedi_subdevice *s Pointer to current subdevice structure + unsigned int *chanlist Pointer to packed channel list + unsigned int n_chan Number of channels to scan + +Returns:Void + ============================================================================== */ - -#if 0 -static int check_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan); -#endif static void setup_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan); -static int icp_multi_reset(struct comedi_device *dev); + unsigned int *chanlist, unsigned int n_chan) +{ + unsigned int i, range, chanprog; + unsigned int diff; -/* -============================================================================== - Functions -============================================================================== -*/ +#ifdef ICP_MULTI_EXTDEBUG + printk(KERN_DEBUG + "icp multi EDBG: setup_channel_list(...,%d)\n", n_chan); +#endif + devpriv->act_chanlist_len = n_chan; + devpriv->act_chanlist_pos = 0; + + for (i = 0; i < n_chan; i++) { + /* Get channel */ + chanprog = CR_CHAN(chanlist[i]); + + /* Determine if it is a differential channel (Bit 15 = 1) */ + if (CR_AREF(chanlist[i]) == AREF_DIFF) { + diff = 1; + chanprog &= 0x0007; + } else { + diff = 0; + chanprog &= 0x000f; + } + + /* Clear channel, range and input mode bits + * in A/D command/status register */ + devpriv->AdcCmdStatus &= 0xf00f; + + /* Set channel number and differential mode status bit */ + if (diff) { + /* Set channel number, bits 9-11 & mode, bit 6 */ + devpriv->AdcCmdStatus |= (chanprog << 9); + devpriv->AdcCmdStatus |= ADC_DI; + } else + /* Set channel number, bits 8-11 */ + devpriv->AdcCmdStatus |= (chanprog << 8); + + /* Get range for current channel */ + range = this_board->rangecode[CR_RANGE(chanlist[i])]; + /* Set range. bits 4-5 */ + devpriv->AdcCmdStatus |= range; + + /* Output channel, range, mode to ICP Multi */ + writew(devpriv->AdcCmdStatus, + devpriv->io_addr + ICP_MULTI_ADC_CSR); + +#ifdef ICP_MULTI_EXTDEBUG + printk(KERN_DEBUG + "GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range, + devpriv->act_chanlist[i]); +#endif + } + +} /* ============================================================================== @@ -764,84 +767,6 @@ static int check_channel_list(struct comedi_device *dev, /* ============================================================================== -Name: setup_channel_list - -Description: - This function sets the appropriate channel selection, - differential input mode and range bits in the ADC Command/ - Status register. - -Parameters: - struct comedi_device *dev Pointer to current service structure - struct comedi_subdevice *s Pointer to current subdevice structure - unsigned int *chanlist Pointer to packed channel list - unsigned int n_chan Number of channels to scan - -Returns:Void - -============================================================================== -*/ -static void setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan) -{ - unsigned int i, range, chanprog; - unsigned int diff; - -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "icp multi EDBG: setup_channel_list(...,%d)\n", n_chan); -#endif - devpriv->act_chanlist_len = n_chan; - devpriv->act_chanlist_pos = 0; - - for (i = 0; i < n_chan; i++) { - /* Get channel */ - chanprog = CR_CHAN(chanlist[i]); - - /* Determine if it is a differential channel (Bit 15 = 1) */ - if (CR_AREF(chanlist[i]) == AREF_DIFF) { - diff = 1; - chanprog &= 0x0007; - } else { - diff = 0; - chanprog &= 0x000f; - } - - /* Clear channel, range and input mode bits - * in A/D command/status register */ - devpriv->AdcCmdStatus &= 0xf00f; - - /* Set channel number and differential mode status bit */ - if (diff) { - /* Set channel number, bits 9-11 & mode, bit 6 */ - devpriv->AdcCmdStatus |= (chanprog << 9); - devpriv->AdcCmdStatus |= ADC_DI; - } else - /* Set channel number, bits 8-11 */ - devpriv->AdcCmdStatus |= (chanprog << 8); - - /* Get range for current channel */ - range = this_board->rangecode[CR_RANGE(chanlist[i])]; - /* Set range. bits 4-5 */ - devpriv->AdcCmdStatus |= range; - - /* Output channel, range, mode to ICP Multi */ - writew(devpriv->AdcCmdStatus, - devpriv->io_addr + ICP_MULTI_ADC_CSR); - -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range, - devpriv->act_chanlist[i]); -#endif - } - -} - -/* -============================================================================== - Name: icp_multi_reset Description: @@ -897,23 +822,6 @@ static int icp_multi_reset(struct comedi_device *dev) return 0; } -/* -============================================================================== - -Name: icp_multi_attach - -Description: - This function sets up all the appropriate data for the current - device. - -Parameters: - struct comedi_device *dev Pointer to current device structure - struct comedi_devconfig *it Pointer to current device configuration - -Returns:int 0 = success - -============================================================================== -*/ static int icp_multi_attach(struct comedi_device *dev, struct comedi_devconfig *it) { @@ -1099,44 +1007,53 @@ static int icp_multi_attach(struct comedi_device *dev, return 0; } -/* -============================================================================== - -Name: icp_multi_detach - -Description: - This function releases all the resources used by the current - device. - -Parameters: - struct comedi_device *dev Pointer to current device structure - -Returns:int 0 = success - -============================================================================== -*/ -static int icp_multi_detach(struct comedi_device *dev) +static void icp_multi_detach(struct comedi_device *dev) { - if (dev->private) if (devpriv->valid) icp_multi_reset(dev); - if (dev->irq) free_irq(dev->irq, dev); - if (dev->private && devpriv->io_addr) iounmap(devpriv->io_addr); - if (dev->private && devpriv->card) pci_card_free(devpriv->card); - if (--pci_list_builded == 0) pci_card_list_cleanup(PCI_VENDOR_ID_ICP); - - return 0; } +static const struct boardtype boardtypes[] = { + { + .name = "icp_multi", + .device_id = DEVICE_ID, + .iorange = IORANGE_ICP_MULTI, + .have_irq = 1, + .cardtype = TYPE_ICP_MULTI, + .n_aichan = 16, + .n_aichand = 8, + .n_aochan = 4, + .n_dichan = 16, + .n_dochan = 8, + .n_ctrs = 4, + .ai_maxdata = 0x0fff, + .ao_maxdata = 0x0fff, + .rangelist_ai = &range_analog, + .rangecode = range_codes_analog, + .rangelist_ao = &range_analog, + }, +}; + +static struct comedi_driver icp_multi_driver = { + .driver_name = "icp_multi", + .module = THIS_MODULE, + .attach = icp_multi_attach, + .detach = icp_multi_detach, + .num_names = ARRAY_SIZE(boardtypes), + .board_name = &boardtypes[0].name, + .offset = sizeof(struct boardtype), +}; +module_comedi_driver(icp_multi_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/ii_pci20kc.c b/trunk/drivers/staging/comedi/drivers/ii_pci20kc.c index e4711ef54719..f0a579a04a7d 100644 --- a/trunk/drivers/staging/comedi/drivers/ii_pci20kc.c +++ b/trunk/drivers/staging/comedi/drivers/ii_pci20kc.c @@ -159,17 +159,6 @@ struct pci20xxx_private { #define devpriv ((struct pci20xxx_private *)dev->private) #define CHAN (CR_CHAN(it->chanlist[0])) -static int pci20xxx_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pci20xxx_detach(struct comedi_device *dev); - -static struct comedi_driver driver_pci20xxx = { - .driver_name = "ii_pci20kc", - .module = THIS_MODULE, - .attach = pci20xxx_attach, - .detach = pci20xxx_detach, -}; - static int pci20006_init(struct comedi_device *dev, struct comedi_subdevice *s, int opt0, int opt1); static int pci20341_init(struct comedi_device *dev, struct comedi_subdevice *s, @@ -275,11 +264,9 @@ static int pci20xxx_attach(struct comedi_device *dev, return 1; } -static int pci20xxx_detach(struct comedi_device *dev) +static void pci20xxx_detach(struct comedi_device *dev) { - printk(KERN_INFO "comedi%d: pci20xxx: remove\n", dev->minor); - - return 0; + /* Nothing to cleanup */ } /* pci20006m */ @@ -666,18 +653,13 @@ static unsigned int pci20xxx_di(struct comedi_device *dev, } #endif -static int __init driver_pci20xxx_init_module(void) -{ - return comedi_driver_register(&driver_pci20xxx); -} - -static void __exit driver_pci20xxx_cleanup_module(void) -{ - comedi_driver_unregister(&driver_pci20xxx); -} - -module_init(driver_pci20xxx_init_module); -module_exit(driver_pci20xxx_cleanup_module); +static struct comedi_driver pci20xxx_driver = { + .driver_name = "ii_pci20kc", + .module = THIS_MODULE, + .attach = pci20xxx_attach, + .detach = pci20xxx_detach, +}; +module_comedi_driver(pci20xxx_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/jr3_pci.c b/trunk/drivers/staging/comedi/drivers/jr3_pci.c index 6a79ba10630d..d536a11edb95 100644 --- a/trunk/drivers/staging/comedi/drivers/jr3_pci.c +++ b/trunk/drivers/staging/comedi/drivers/jr3_pci.c @@ -59,28 +59,6 @@ Devices: [JR3] PCI force sensor board (jr3_pci) #define PCI_DEVICE_ID_JR3_3_CHANNEL 0x3113 #define PCI_DEVICE_ID_JR3_4_CHANNEL 0x3114 -static int jr3_pci_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int jr3_pci_detach(struct comedi_device *dev); - -static struct comedi_driver driver_jr3_pci = { - .driver_name = "jr3_pci", - .module = THIS_MODULE, - .attach = jr3_pci_attach, - .detach = jr3_pci_detach, -}; - -static DEFINE_PCI_DEVICE_TABLE(jr3_pci_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL) }, - { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL_NEW) }, - { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_2_CHANNEL) }, - { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_3_CHANNEL) }, - { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_4_CHANNEL) }, - {0} -}; - -MODULE_DEVICE_TABLE(pci, jr3_pci_pci_table); - struct jr3_pci_dev_private { struct pci_dev *pci_dev; @@ -948,9 +926,7 @@ static int jr3_pci_attach(struct comedi_device *dev, return result; } -MODULE_FIRMWARE("comedi/jr3pci.idm"); - -static int jr3_pci_detach(struct comedi_device *dev) +static void jr3_pci_detach(struct comedi_device *dev) { int i; struct jr3_pci_dev_private *devpriv = dev->private; @@ -962,56 +938,52 @@ static int jr3_pci_detach(struct comedi_device *dev) for (i = 0; i < devpriv->n_channels; i++) kfree(dev->subdevices[i].private); } - if (devpriv->iobase) iounmap((void *)devpriv->iobase); if (devpriv->pci_enabled) comedi_pci_disable(devpriv->pci_dev); - if (devpriv->pci_dev) pci_dev_put(devpriv->pci_dev); } - return 0; } -static int __devinit driver_jr3_pci_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) +static struct comedi_driver jr3_pci_driver = { + .driver_name = "jr3_pci", + .module = THIS_MODULE, + .attach = jr3_pci_attach, + .detach = jr3_pci_detach, +}; + +static int __devinit jr3_pci_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, driver_jr3_pci.driver_name); + return comedi_pci_auto_config(dev, &jr3_pci_driver); } -static void __devexit driver_jr3_pci_pci_remove(struct pci_dev *dev) +static void __devexit jr3_pci_pci_remove(struct pci_dev *dev) { comedi_pci_auto_unconfig(dev); } -static struct pci_driver driver_jr3_pci_pci_driver = { - .id_table = jr3_pci_pci_table, - .probe = &driver_jr3_pci_pci_probe, - .remove = __devexit_p(&driver_jr3_pci_pci_remove) +static DEFINE_PCI_DEVICE_TABLE(jr3_pci_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL) }, + { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL_NEW) }, + { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_2_CHANNEL) }, + { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_3_CHANNEL) }, + { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_4_CHANNEL) }, + { 0 } }; +MODULE_DEVICE_TABLE(pci, jr3_pci_pci_table); -static int __init driver_jr3_pci_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_jr3_pci); - if (retval < 0) - return retval; - - driver_jr3_pci_pci_driver.name = (char *)driver_jr3_pci.driver_name; - return pci_register_driver(&driver_jr3_pci_pci_driver); -} - -static void __exit driver_jr3_pci_cleanup_module(void) -{ - pci_unregister_driver(&driver_jr3_pci_pci_driver); - comedi_driver_unregister(&driver_jr3_pci); -} - -module_init(driver_jr3_pci_init_module); -module_exit(driver_jr3_pci_cleanup_module); +static struct pci_driver jr3_pci_pci_driver = { + .name = "jr3_pci", + .id_table = jr3_pci_pci_table, + .probe = jr3_pci_pci_probe, + .remove = __devexit_p(jr3_pci_pci_remove), +}; +module_comedi_pci_driver(jr3_pci_driver, jr3_pci_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE("comedi/jr3pci.idm"); diff --git a/trunk/drivers/staging/comedi/drivers/ke_counter.c b/trunk/drivers/staging/comedi/drivers/ke_counter.c index 4e9e9a078652..09d191844bf8 100644 --- a/trunk/drivers/staging/comedi/drivers/ke_counter.c +++ b/trunk/drivers/staging/comedi/drivers/ke_counter.c @@ -46,18 +46,6 @@ Kolter Electronic PCI Counter Card. #define PCI_VENDOR_ID_KOLTER 0x1001 #define CNT_CARD_DEVICE_ID 0x0014 -/*-- function prototypes ----------------------------------------------------*/ - -static int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int cnt_detach(struct comedi_device *dev); - -static DEFINE_PCI_DEVICE_TABLE(cnt_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_KOLTER, CNT_CARD_DEVICE_ID) }, - {0} -}; - -MODULE_DEVICE_TABLE(pci, cnt_pci_table); - /*-- board specification structure ------------------------------------------*/ struct cnt_board_struct { @@ -87,51 +75,6 @@ struct cnt_device_private { #define devpriv ((struct cnt_device_private *)dev->private) -static struct comedi_driver cnt_driver = { - .driver_name = CNT_DRIVER_NAME, - .module = THIS_MODULE, - .attach = cnt_attach, - .detach = cnt_detach, -}; - -static int __devinit cnt_driver_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, cnt_driver.driver_name); -} - -static void __devexit cnt_driver_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver cnt_driver_pci_driver = { - .id_table = cnt_pci_table, - .probe = &cnt_driver_pci_probe, - .remove = __devexit_p(&cnt_driver_pci_remove) -}; - -static int __init cnt_driver_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&cnt_driver); - if (retval < 0) - return retval; - - cnt_driver_pci_driver.name = (char *)cnt_driver.driver_name; - return pci_register_driver(&cnt_driver_pci_driver); -} - -static void __exit cnt_driver_cleanup_module(void) -{ - pci_unregister_driver(&cnt_driver_pci_driver); - comedi_driver_unregister(&cnt_driver); -} - -module_init(cnt_driver_init_module); -module_exit(cnt_driver_cleanup_module); - /*-- counter write ----------------------------------------------------------*/ /* This should be used only for resetting the counters; maybe it is better @@ -181,8 +124,6 @@ static int cnt_rinsn(struct comedi_device *dev, return 1; } -/*-- attach -----------------------------------------------------------------*/ - static int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *subdevice; @@ -278,20 +219,47 @@ static int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -/*-- detach -----------------------------------------------------------------*/ - -static int cnt_detach(struct comedi_device *dev) +static void cnt_detach(struct comedi_device *dev) { if (devpriv && devpriv->pcidev) { if (dev->iobase) comedi_pci_disable(devpriv->pcidev); pci_dev_put(devpriv->pcidev); } - printk(KERN_INFO "comedi%d: " CNT_DRIVER_NAME " remove\n", - dev->minor); - return 0; } +static struct comedi_driver ke_counter_driver = { + .driver_name = "ke_counter", + .module = THIS_MODULE, + .attach = cnt_attach, + .detach = cnt_detach, +}; + +static int __devinit ke_counter_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + return comedi_pci_auto_config(dev, &ke_counter_driver); +} + +static void __devexit ke_counter_pci_remove(struct pci_dev *dev) +{ + comedi_pci_auto_unconfig(dev); +} + +static DEFINE_PCI_DEVICE_TABLE(ke_counter_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_KOLTER, CNT_CARD_DEVICE_ID) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, ke_counter_pci_table); + +static struct pci_driver ke_counter_pci_driver = { + .name = "ke_counter", + .id_table = ke_counter_pci_table, + .probe = ke_counter_pci_probe, + .remove = __devexit_p(ke_counter_pci_remove), +}; +module_comedi_pci_driver(ke_counter_driver, ke_counter_pci_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/me4000.c b/trunk/drivers/staging/comedi/drivers/me4000.c index b0bc6bb877ab..8ca1b54600db 100644 --- a/trunk/drivers/staging/comedi/drivers/me4000.c +++ b/trunk/drivers/staging/comedi/drivers/me4000.c @@ -65,30 +65,6 @@ broken. #include "me4000_fw.h" #endif -/*============================================================================= - PCI device table. - This is used by modprobe to translate PCI IDs to drivers. - ===========================================================================*/ - -static DEFINE_PCI_DEVICE_TABLE(me4000_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4650) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4660) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4661) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4662) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4663) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4670) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4671) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4672) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4673) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4680) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4681) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4682) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4683) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, me4000_pci_table); - static const struct me4000_board me4000_boards[] = { {"ME-4650", 0x4650, {0, 0}, {16, 0, 0, 0}, {4}, {0} }, @@ -112,23 +88,9 @@ static const struct me4000_board me4000_boards[] = { #define ME4000_BOARD_VERSIONS (ARRAY_SIZE(me4000_boards) - 1) -/*----------------------------------------------------------------------------- - Comedi function prototypes - ---------------------------------------------------------------------------*/ -static int me4000_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int me4000_detach(struct comedi_device *dev); -static struct comedi_driver driver_me4000 = { - .driver_name = "me4000", - .module = THIS_MODULE, - .attach = me4000_attach, - .detach = me4000_detach, -}; - /*----------------------------------------------------------------------------- Meilhaus function prototypes ---------------------------------------------------------------------------*/ -static int me4000_probe(struct comedi_device *dev, struct comedi_devconfig *it); static int get_registers(struct comedi_device *dev, struct pci_dev *pci_dev_p); static int init_board_info(struct comedi_device *dev, struct pci_dev *pci_dev_p); @@ -139,76 +101,10 @@ static int init_cnt_context(struct comedi_device *dev); static int xilinx_download(struct comedi_device *dev); static int reset_board(struct comedi_device *dev); -static int me4000_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static int me4000_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static int cnt_reset(struct comedi_device *dev, unsigned int channel); - -static int cnt_config(struct comedi_device *dev, - unsigned int channel, unsigned int mode); - -static int me4000_cnt_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static int me4000_cnt_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static int me4000_cnt_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static int me4000_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *subdevice, - struct comedi_insn *insn, unsigned int *data); - -static int me4000_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); - -static int ai_check_chanlist(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); - -static int ai_round_cmd_args(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd, - unsigned int *init_ticks, - unsigned int *scan_ticks, - unsigned int *chan_ticks); - -static int ai_prepare(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd, - unsigned int init_ticks, - unsigned int scan_ticks, unsigned int chan_ticks); - static int ai_write_chanlist(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd); -static irqreturn_t me4000_ai_isr(int irq, void *dev_id); - -static int me4000_ai_do_cmd_test(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); - -static int me4000_ai_do_cmd(struct comedi_device *dev, - struct comedi_subdevice *s); - -static int me4000_ao_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static int me4000_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - /*----------------------------------------------------------------------------- Meilhaus inline functions ---------------------------------------------------------------------------*/ @@ -262,130 +158,6 @@ static const struct comedi_lrange me4000_ao_range = { } }; -static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - int result; - - CALL_PDEBUG("In me4000_attach()\n"); - - result = me4000_probe(dev, it); - if (result) - return result; - - /* - * Allocate the subdevice structures. alloc_subdevice() is a - * convenient macro defined in comedidev.h. It relies on - * n_subdevices being set correctly. - */ - if (alloc_subdevices(dev, 4) < 0) - return -ENOMEM; - - /*========================================================================= - Analog input subdevice - ========================================================================*/ - - s = dev->subdevices + 0; - - if (thisboard->ai.count) { - s->type = COMEDI_SUBD_AI; - s->subdev_flags = - SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF; - s->n_chan = thisboard->ai.count; - s->maxdata = 0xFFFF; /* 16 bit ADC */ - s->len_chanlist = ME4000_AI_CHANNEL_LIST_COUNT; - s->range_table = &me4000_ai_range; - s->insn_read = me4000_ai_insn_read; - - if (info->irq > 0) { - if (request_irq(info->irq, me4000_ai_isr, - IRQF_SHARED, "ME-4000", dev)) { - printk - ("comedi%d: me4000: me4000_attach(): " - "Unable to allocate irq\n", dev->minor); - } else { - dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->cancel = me4000_ai_cancel; - s->do_cmdtest = me4000_ai_do_cmd_test; - s->do_cmd = me4000_ai_do_cmd; - } - } else { - printk(KERN_WARNING - "comedi%d: me4000: me4000_attach(): " - "No interrupt available\n", dev->minor); - } - } else { - s->type = COMEDI_SUBD_UNUSED; - } - - /*========================================================================= - Analog output subdevice - ========================================================================*/ - - s = dev->subdevices + 1; - - if (thisboard->ao.count) { - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE | SDF_COMMON | SDF_GROUND; - s->n_chan = thisboard->ao.count; - s->maxdata = 0xFFFF; /* 16 bit DAC */ - s->range_table = &me4000_ao_range; - s->insn_write = me4000_ao_insn_write; - s->insn_read = me4000_ao_insn_read; - } else { - s->type = COMEDI_SUBD_UNUSED; - } - - /*========================================================================= - Digital I/O subdevice - ========================================================================*/ - - s = dev->subdevices + 2; - - if (thisboard->dio.count) { - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = thisboard->dio.count * 8; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = me4000_dio_insn_bits; - s->insn_config = me4000_dio_insn_config; - } else { - s->type = COMEDI_SUBD_UNUSED; - } - - /* - * Check for optoisolated ME-4000 version. If one the first - * port is a fixed output port and the second is a fixed input port. - */ - if (!me4000_inl(dev, info->dio_context.dir_reg)) { - s->io_bits |= 0xFF; - me4000_outl(dev, ME4000_DIO_CTRL_BIT_MODE_0, - info->dio_context.dir_reg); - } - - /*========================================================================= - Counter subdevice - ========================================================================*/ - - s = dev->subdevices + 3; - - if (thisboard->cnt.count) { - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = thisboard->cnt.count; - s->maxdata = 0xFFFF; /* 16 bit counters */ - s->insn_read = me4000_cnt_insn_read; - s->insn_write = me4000_cnt_insn_write; - s->insn_config = me4000_cnt_insn_config; - } else { - s->type = COMEDI_SUBD_UNUSED; - } - - return 0; -} - static int me4000_probe(struct comedi_device *dev, struct comedi_devconfig *it) { struct pci_dev *pci_device = NULL; @@ -920,22 +692,6 @@ static int reset_board(struct comedi_device *dev) return 0; } -static int me4000_detach(struct comedi_device *dev) -{ - CALL_PDEBUG("In me4000_detach()\n"); - - if (info) { - if (info->pci_dev_p) { - reset_board(dev); - if (info->plx_regbase) - comedi_pci_disable(info->pci_dev_p); - pci_dev_put(info->pci_dev_p); - } - } - - return 0; -} - /*============================================================================= Analog input section ===========================================================================*/ @@ -2424,43 +2180,185 @@ static int me4000_cnt_insn_write(struct comedi_device *dev, return 1; } -static int __devinit driver_me4000_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) +static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - return comedi_pci_auto_config(dev, driver_me4000.driver_name); + struct comedi_subdevice *s; + int result; + + CALL_PDEBUG("In me4000_attach()\n"); + + result = me4000_probe(dev, it); + if (result) + return result; + + /* + * Allocate the subdevice structures. alloc_subdevice() is a + * convenient macro defined in comedidev.h. It relies on + * n_subdevices being set correctly. + */ + if (alloc_subdevices(dev, 4) < 0) + return -ENOMEM; + + /*========================================================================= + Analog input subdevice + ========================================================================*/ + + s = dev->subdevices + 0; + + if (thisboard->ai.count) { + s->type = COMEDI_SUBD_AI; + s->subdev_flags = + SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF; + s->n_chan = thisboard->ai.count; + s->maxdata = 0xFFFF; /* 16 bit ADC */ + s->len_chanlist = ME4000_AI_CHANNEL_LIST_COUNT; + s->range_table = &me4000_ai_range; + s->insn_read = me4000_ai_insn_read; + + if (info->irq > 0) { + if (request_irq(info->irq, me4000_ai_isr, + IRQF_SHARED, "ME-4000", dev)) { + printk + ("comedi%d: me4000: me4000_attach(): " + "Unable to allocate irq\n", dev->minor); + } else { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->cancel = me4000_ai_cancel; + s->do_cmdtest = me4000_ai_do_cmd_test; + s->do_cmd = me4000_ai_do_cmd; + } + } else { + printk(KERN_WARNING + "comedi%d: me4000: me4000_attach(): " + "No interrupt available\n", dev->minor); + } + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + /*========================================================================= + Analog output subdevice + ========================================================================*/ + + s = dev->subdevices + 1; + + if (thisboard->ao.count) { + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE | SDF_COMMON | SDF_GROUND; + s->n_chan = thisboard->ao.count; + s->maxdata = 0xFFFF; /* 16 bit DAC */ + s->range_table = &me4000_ao_range; + s->insn_write = me4000_ao_insn_write; + s->insn_read = me4000_ao_insn_read; + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + /*========================================================================= + Digital I/O subdevice + ========================================================================*/ + + s = dev->subdevices + 2; + + if (thisboard->dio.count) { + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = thisboard->dio.count * 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = me4000_dio_insn_bits; + s->insn_config = me4000_dio_insn_config; + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + /* + * Check for optoisolated ME-4000 version. If one the first + * port is a fixed output port and the second is a fixed input port. + */ + if (!me4000_inl(dev, info->dio_context.dir_reg)) { + s->io_bits |= 0xFF; + me4000_outl(dev, ME4000_DIO_CTRL_BIT_MODE_0, + info->dio_context.dir_reg); + } + + /*========================================================================= + Counter subdevice + ========================================================================*/ + + s = dev->subdevices + 3; + + if (thisboard->cnt.count) { + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = thisboard->cnt.count; + s->maxdata = 0xFFFF; /* 16 bit counters */ + s->insn_read = me4000_cnt_insn_read; + s->insn_write = me4000_cnt_insn_write; + s->insn_config = me4000_cnt_insn_config; + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + return 0; } -static void __devexit driver_me4000_pci_remove(struct pci_dev *dev) +static void me4000_detach(struct comedi_device *dev) { - comedi_pci_auto_unconfig(dev); + if (info) { + if (info->pci_dev_p) { + reset_board(dev); + if (info->plx_regbase) + comedi_pci_disable(info->pci_dev_p); + pci_dev_put(info->pci_dev_p); + } + } } -static struct pci_driver driver_me4000_pci_driver = { - .id_table = me4000_pci_table, - .probe = &driver_me4000_pci_probe, - .remove = __devexit_p(&driver_me4000_pci_remove) +static struct comedi_driver me4000_driver = { + .driver_name = "me4000", + .module = THIS_MODULE, + .attach = me4000_attach, + .detach = me4000_detach, }; -static int __init driver_me4000_init_module(void) +static int __devinit me4000_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) { - int retval; - - retval = comedi_driver_register(&driver_me4000); - if (retval < 0) - return retval; - - driver_me4000_pci_driver.name = (char *)driver_me4000.driver_name; - return pci_register_driver(&driver_me4000_pci_driver); + return comedi_pci_auto_config(dev, &me4000_driver); } -static void __exit driver_me4000_cleanup_module(void) +static void __devexit me4000_pci_remove(struct pci_dev *dev) { - pci_unregister_driver(&driver_me4000_pci_driver); - comedi_driver_unregister(&driver_me4000); + comedi_pci_auto_unconfig(dev); } -module_init(driver_me4000_init_module); -module_exit(driver_me4000_cleanup_module); +static DEFINE_PCI_DEVICE_TABLE(me4000_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4650) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4660) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4661) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4662) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4663) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4670) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4671) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4672) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4673) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4680) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4681) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4682) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4683) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, me4000_pci_table); + +static struct pci_driver me4000_pci_driver = { + .name = "me4000", + .id_table = me4000_pci_table, + .probe = me4000_pci_probe, + .remove = __devexit_p(me4000_pci_remove), +}; +module_comedi_pci_driver(me4000_driver, me4000_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/me_daq.c b/trunk/drivers/staging/comedi/drivers/me_daq.c index 8b812e41c52b..ffe251250e6f 100644 --- a/trunk/drivers/staging/comedi/drivers/me_daq.c +++ b/trunk/drivers/staging/comedi/drivers/me_daq.c @@ -146,10 +146,6 @@ from http://www.comedi.org #define ME_COUNTER_STARTDATA_B 0x0022 /* - | W */ #define ME_COUNTER_VALUE_B 0x0022 /* R | - */ -/* Function prototypes */ -static int me_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int me_detach(struct comedi_device *dev); - static const struct comedi_lrange me2000_ai_range = { 8, { @@ -187,14 +183,6 @@ static const struct comedi_lrange me2600_ao_range = { } }; -static DEFINE_PCI_DEVICE_TABLE(me_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, ME2600_DEVICE_ID) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, ME2000_DEVICE_ID) }, - {0} -}; - -MODULE_DEVICE_TABLE(pci, me_pci_table); - /* Board specification structure */ struct me_board { const char *name; /* driver name */ @@ -247,51 +235,6 @@ static const struct me_board me_boards[] = { #define me_board_nbr (sizeof(me_boards)/sizeof(struct me_board)) -static struct comedi_driver me_driver = { - .driver_name = ME_DRIVER_NAME, - .module = THIS_MODULE, - .attach = me_attach, - .detach = me_detach, -}; - -static int __devinit me_driver_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, me_driver.driver_name); -} - -static void __devexit me_driver_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver me_driver_pci_driver = { - .id_table = me_pci_table, - .probe = &me_driver_pci_probe, - .remove = __devexit_p(&me_driver_pci_remove) -}; - -static int __init me_driver_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&me_driver); - if (retval < 0) - return retval; - - me_driver_pci_driver.name = (char *)me_driver.driver_name; - return pci_register_driver(&me_driver_pci_driver); -} - -static void __exit me_driver_cleanup_module(void) -{ - pci_unregister_driver(&me_driver_pci_driver); - comedi_driver_unregister(&me_driver); -} - -module_init(me_driver_init_module); -module_exit(me_driver_cleanup_module); - /* Private data structure */ struct me_private_data { struct pci_dev *pci_device; @@ -669,12 +612,6 @@ static int me_reset(struct comedi_device *dev) return 0; } -/* - * Attach - * - * - Register PCI device - * - Declare device driver capability - */ static int me_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct pci_dev *pci_device = NULL; @@ -869,8 +806,7 @@ static int me_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -/* Detach */ -static int me_detach(struct comedi_device *dev) +static void me_detach(struct comedi_device *dev) { if (dev_private) { if (dev_private->me_regbase) { @@ -882,13 +818,44 @@ static int me_detach(struct comedi_device *dev) if (dev_private->pci_device) { if (dev_private->plx_regbase_size) comedi_pci_disable(dev_private->pci_device); - pci_dev_put(dev_private->pci_device); } } - return 0; } +static struct comedi_driver me_daq_driver = { + .driver_name = "me_daq", + .module = THIS_MODULE, + .attach = me_attach, + .detach = me_detach, +}; + +static int __devinit me_daq_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + return comedi_pci_auto_config(dev, &me_daq_driver); +} + +static void __devexit me_daq_pci_remove(struct pci_dev *dev) +{ + comedi_pci_auto_unconfig(dev); +} + +static DEFINE_PCI_DEVICE_TABLE(me_daq_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, ME2600_DEVICE_ID) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, ME2000_DEVICE_ID) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, me_daq_pci_table); + +static struct pci_driver me_daq_pci_driver = { + .name = "me_daq", + .id_table = me_daq_pci_table, + .probe = me_daq_pci_probe, + .remove = __devexit_p(me_daq_pci_remove), +}; +module_comedi_pci_driver(me_daq_driver, me_daq_pci_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/mite.h b/trunk/drivers/staging/comedi/drivers/mite.h index 999551f54c2a..83f1b27a4720 100644 --- a/trunk/drivers/staging/comedi/drivers/mite.h +++ b/trunk/drivers/staging/comedi/drivers/mite.h @@ -66,9 +66,9 @@ struct mite_struct { struct pci_dev *pcidev; resource_size_t mite_phys_addr; - void *mite_io_addr; + void __iomem *mite_io_addr; resource_size_t daq_phys_addr; - void *daq_io_addr; + void __iomem *daq_io_addr; struct mite_channel channels[MAX_MITE_DMA_CHANNELS]; short channel_allocated[MAX_MITE_DMA_CHANNELS]; diff --git a/trunk/drivers/staging/comedi/drivers/mpc624.c b/trunk/drivers/staging/comedi/drivers/mpc624.c index dd09a6d46e5c..4304e864a4d4 100644 --- a/trunk/drivers/staging/comedi/drivers/mpc624.c +++ b/trunk/drivers/staging/comedi/drivers/mpc624.c @@ -148,131 +148,6 @@ static const struct comedi_lrange range_mpc624_bipolar10 = { } }; -/* -------------------------------------------------------------------------- */ -static int mpc624_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int mpc624_detach(struct comedi_device *dev); -/* -------------------------------------------------------------------------- */ -static struct comedi_driver driver_mpc624 = { - .driver_name = "mpc624", - .module = THIS_MODULE, - .attach = mpc624_attach, - .detach = mpc624_detach -}; - -/* -------------------------------------------------------------------------- */ -static int mpc624_ai_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); -/* -------------------------------------------------------------------------- */ -static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - unsigned long iobase; - - iobase = it->options[0]; - printk(KERN_INFO "comedi%d: mpc624 [0x%04lx, ", dev->minor, iobase); - if (request_region(iobase, MPC624_SIZE, "mpc624") == NULL) { - printk(KERN_ERR "I/O port(s) in use\n"); - return -EIO; - } - - dev->iobase = iobase; - dev->board_name = "mpc624"; - - /* Private structure initialization */ - if (alloc_private(dev, sizeof(struct skel_private)) < 0) - return -ENOMEM; - - switch (it->options[1]) { - case 0: - devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz; - printk(KERN_INFO "3.52 kHz, "); - break; - case 1: - devpriv->ulConvertionRate = MPC624_SPEED_1_76_kHz; - printk(KERN_INFO "1.76 kHz, "); - break; - case 2: - devpriv->ulConvertionRate = MPC624_SPEED_880_Hz; - printk(KERN_INFO "880 Hz, "); - break; - case 3: - devpriv->ulConvertionRate = MPC624_SPEED_440_Hz; - printk(KERN_INFO "440 Hz, "); - break; - case 4: - devpriv->ulConvertionRate = MPC624_SPEED_220_Hz; - printk(KERN_INFO "220 Hz, "); - break; - case 5: - devpriv->ulConvertionRate = MPC624_SPEED_110_Hz; - printk(KERN_INFO "110 Hz, "); - break; - case 6: - devpriv->ulConvertionRate = MPC624_SPEED_55_Hz; - printk(KERN_INFO "55 Hz, "); - break; - case 7: - devpriv->ulConvertionRate = MPC624_SPEED_27_5_Hz; - printk(KERN_INFO "27.5 Hz, "); - break; - case 8: - devpriv->ulConvertionRate = MPC624_SPEED_13_75_Hz; - printk(KERN_INFO "13.75 Hz, "); - break; - case 9: - devpriv->ulConvertionRate = MPC624_SPEED_6_875_Hz; - printk(KERN_INFO "6.875 Hz, "); - break; - default: - printk - (KERN_ERR "illegal conversion rate setting!" - " Valid numbers are 0..9. Using 9 => 6.875 Hz, "); - devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz; - } - - /* Subdevices structures */ - if (alloc_subdevices(dev, 1) < 0) - return -ENOMEM; - - s = dev->subdevices + 0; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_DIFF; - s->n_chan = 8; - switch (it->options[1]) { - default: - s->maxdata = 0x3FFFFFFF; - printk(KERN_INFO "30 bit, "); - } - - switch (it->options[1]) { - case 0: - s->range_table = &range_mpc624_bipolar1; - printk(KERN_INFO "1.01V]: "); - break; - default: - s->range_table = &range_mpc624_bipolar10; - printk(KERN_INFO "10.1V]: "); - } - s->len_chanlist = 1; - s->insn_read = mpc624_ai_rinsn; - - printk(KERN_INFO "attached\n"); - - return 1; -} - -static int mpc624_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: mpc624: remove\n", dev->minor); - - if (dev->iobase) - release_region(dev->iobase, MPC624_SIZE); - - return 0; -} - /* Timeout 200ms */ #define TIMEOUT 200 @@ -406,18 +281,117 @@ static int mpc624_ai_rinsn(struct comedi_device *dev, return n; } -static int __init driver_mpc624_init_module(void) +static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - return comedi_driver_register(&driver_mpc624); + struct comedi_subdevice *s; + unsigned long iobase; + + iobase = it->options[0]; + printk(KERN_INFO "comedi%d: mpc624 [0x%04lx, ", dev->minor, iobase); + if (request_region(iobase, MPC624_SIZE, "mpc624") == NULL) { + printk(KERN_ERR "I/O port(s) in use\n"); + return -EIO; + } + + dev->iobase = iobase; + dev->board_name = "mpc624"; + + /* Private structure initialization */ + if (alloc_private(dev, sizeof(struct skel_private)) < 0) + return -ENOMEM; + + switch (it->options[1]) { + case 0: + devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz; + printk(KERN_INFO "3.52 kHz, "); + break; + case 1: + devpriv->ulConvertionRate = MPC624_SPEED_1_76_kHz; + printk(KERN_INFO "1.76 kHz, "); + break; + case 2: + devpriv->ulConvertionRate = MPC624_SPEED_880_Hz; + printk(KERN_INFO "880 Hz, "); + break; + case 3: + devpriv->ulConvertionRate = MPC624_SPEED_440_Hz; + printk(KERN_INFO "440 Hz, "); + break; + case 4: + devpriv->ulConvertionRate = MPC624_SPEED_220_Hz; + printk(KERN_INFO "220 Hz, "); + break; + case 5: + devpriv->ulConvertionRate = MPC624_SPEED_110_Hz; + printk(KERN_INFO "110 Hz, "); + break; + case 6: + devpriv->ulConvertionRate = MPC624_SPEED_55_Hz; + printk(KERN_INFO "55 Hz, "); + break; + case 7: + devpriv->ulConvertionRate = MPC624_SPEED_27_5_Hz; + printk(KERN_INFO "27.5 Hz, "); + break; + case 8: + devpriv->ulConvertionRate = MPC624_SPEED_13_75_Hz; + printk(KERN_INFO "13.75 Hz, "); + break; + case 9: + devpriv->ulConvertionRate = MPC624_SPEED_6_875_Hz; + printk(KERN_INFO "6.875 Hz, "); + break; + default: + printk + (KERN_ERR "illegal conversion rate setting!" + " Valid numbers are 0..9. Using 9 => 6.875 Hz, "); + devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz; + } + + /* Subdevices structures */ + if (alloc_subdevices(dev, 1) < 0) + return -ENOMEM; + + s = dev->subdevices + 0; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_DIFF; + s->n_chan = 8; + switch (it->options[1]) { + default: + s->maxdata = 0x3FFFFFFF; + printk(KERN_INFO "30 bit, "); + } + + switch (it->options[1]) { + case 0: + s->range_table = &range_mpc624_bipolar1; + printk(KERN_INFO "1.01V]: "); + break; + default: + s->range_table = &range_mpc624_bipolar10; + printk(KERN_INFO "10.1V]: "); + } + s->len_chanlist = 1; + s->insn_read = mpc624_ai_rinsn; + + printk(KERN_INFO "attached\n"); + + return 1; } -static void __exit driver_mpc624_cleanup_module(void) +static void mpc624_detach(struct comedi_device *dev) { - comedi_driver_unregister(&driver_mpc624); + if (dev->iobase) + release_region(dev->iobase, MPC624_SIZE); } -module_init(driver_mpc624_init_module); -module_exit(driver_mpc624_cleanup_module); +static struct comedi_driver mpc624_driver = { + .driver_name = "mpc624", + .module = THIS_MODULE, + .attach = mpc624_attach, + .detach = mpc624_detach +}; +module_comedi_driver(mpc624_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/mpc8260cpm.c b/trunk/drivers/staging/comedi/drivers/mpc8260cpm.c index 5f6816a3fe8c..364470e4458f 100644 --- a/trunk/drivers/staging/comedi/drivers/mpc8260cpm.c +++ b/trunk/drivers/staging/comedi/drivers/mpc8260cpm.c @@ -46,75 +46,6 @@ struct mpc8260cpm_private { #define devpriv ((struct mpc8260cpm_private *)dev->private) -static int mpc8260cpm_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int mpc8260cpm_detach(struct comedi_device *dev); -static struct comedi_driver driver_mpc8260cpm = { - .driver_name = "mpc8260cpm", - .module = THIS_MODULE, - .attach = mpc8260cpm_attach, - .detach = mpc8260cpm_detach, -}; - -static int __init driver_mpc8260cpm_init_module(void) -{ - return comedi_driver_register(&driver_mpc8260cpm); -} - -static void __exit driver_mpc8260cpm_cleanup_module(void) -{ - comedi_driver_unregister(&driver_mpc8260cpm); -} - -module_init(driver_mpc8260cpm_init_module); -module_exit(driver_mpc8260cpm_cleanup_module); - -static int mpc8260cpm_dio_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int mpc8260cpm_dio_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static int mpc8260cpm_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - int i; - - printk("comedi%d: mpc8260cpm: ", dev->minor); - - dev->board_ptr = mpc8260cpm_boards + dev->board; - - dev->board_name = thisboard->name; - - if (alloc_private(dev, sizeof(struct mpc8260cpm_private)) < 0) - return -ENOMEM; - - if (alloc_subdevices(dev, 4) < 0) - return -ENOMEM; - - for (i = 0; i < 4; i++) { - s = dev->subdevices + i; - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 32; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_config = mpc8260cpm_dio_config; - s->insn_bits = mpc8260cpm_dio_bits; - } - - return 1; -} - -static int mpc8260cpm_detach(struct comedi_device *dev) -{ - printk("comedi%d: mpc8260cpm: remove\n", dev->minor); - - return 0; -} - static unsigned long *cpm_pdat(int port) { switch (port) { @@ -184,3 +115,48 @@ static int mpc8260cpm_dio_bits(struct comedi_device *dev, return 2; } + +static int mpc8260cpm_attach(struct comedi_device *dev, + struct comedi_devconfig *it) +{ + struct comedi_subdevice *s; + int i; + + printk("comedi%d: mpc8260cpm: ", dev->minor); + + dev->board_ptr = mpc8260cpm_boards + dev->board; + + dev->board_name = thisboard->name; + + if (alloc_private(dev, sizeof(struct mpc8260cpm_private)) < 0) + return -ENOMEM; + + if (alloc_subdevices(dev, 4) < 0) + return -ENOMEM; + + for (i = 0; i < 4; i++) { + s = dev->subdevices + i; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 32; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_config = mpc8260cpm_dio_config; + s->insn_bits = mpc8260cpm_dio_bits; + } + + return 1; +} + +static void mpc8260cpm_detach(struct comedi_device *dev) +{ + /* Nothing to cleanup */ +} + +static struct comedi_driver mpc8260cpm_driver = { + .driver_name = "mpc8260cpm", + .module = THIS_MODULE, + .attach = mpc8260cpm_attach, + .detach = mpc8260cpm_detach, +}; +module_comedi_driver(mpc8260cpm_driver); diff --git a/trunk/drivers/staging/comedi/drivers/multiq3.c b/trunk/drivers/staging/comedi/drivers/multiq3.c index dace902d3bce..e951e73d66f5 100644 --- a/trunk/drivers/staging/comedi/drivers/multiq3.c +++ b/trunk/drivers/staging/comedi/drivers/multiq3.c @@ -83,29 +83,6 @@ Devices: [Quanser Consulting] MultiQ-3 (multiq3) #define MULTIQ3_TIMEOUT 30 -static int multiq3_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int multiq3_detach(struct comedi_device *dev); -static struct comedi_driver driver_multiq3 = { - .driver_name = "multiq3", - .module = THIS_MODULE, - .attach = multiq3_attach, - .detach = multiq3_detach, -}; - -static int __init driver_multiq3_init_module(void) -{ - return comedi_driver_register(&driver_multiq3); -} - -static void __exit driver_multiq3_cleanup_module(void) -{ - comedi_driver_unregister(&driver_multiq3); -} - -module_init(driver_multiq3_init_module); -module_exit(driver_multiq3_cleanup_module); - struct multiq3_private { unsigned int ao_readback[2]; }; @@ -338,18 +315,22 @@ static int multiq3_attach(struct comedi_device *dev, return 0; } -static int multiq3_detach(struct comedi_device *dev) +static void multiq3_detach(struct comedi_device *dev) { - printk(KERN_INFO "comedi%d: multiq3: remove\n", dev->minor); - if (dev->iobase) release_region(dev->iobase, MULTIQ3_SIZE); if (dev->irq) free_irq(dev->irq, dev); - - return 0; } +static struct comedi_driver multiq3_driver = { + .driver_name = "multiq3", + .module = THIS_MODULE, + .attach = multiq3_attach, + .detach = multiq3_detach, +}; +module_comedi_driver(multiq3_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/ni_6527.c b/trunk/drivers/staging/comedi/drivers/ni_6527.c index 54741c9e1af5..b02aa0efcd86 100644 --- a/trunk/drivers/staging/comedi/drivers/ni_6527.c +++ b/trunk/drivers/staging/comedi/drivers/ni_6527.c @@ -78,7 +78,7 @@ Updated: Sat, 25 Jan 2003 13:24:40 -0800 static int ni6527_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int ni6527_detach(struct comedi_device *dev); +static void ni6527_detach(struct comedi_device *dev); static struct comedi_driver driver_ni6527 = { .driver_name = "ni6527", .module = THIS_MODULE, @@ -449,19 +449,15 @@ static int ni6527_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -static int ni6527_detach(struct comedi_device *dev) +static void ni6527_detach(struct comedi_device *dev) { if (devpriv && devpriv->mite && devpriv->mite->daq_io_addr) writeb(0x00, devpriv->mite->daq_io_addr + Master_Interrupt_Control); - if (dev->irq) free_irq(dev->irq, dev); - if (devpriv && devpriv->mite) mite_unsetup(devpriv->mite); - - return 0; } static int ni6527_find_device(struct comedi_device *dev, int bus, int slot) @@ -493,7 +489,7 @@ static int ni6527_find_device(struct comedi_device *dev, int bus, int slot) static int __devinit driver_ni6527_pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, driver_ni6527.driver_name); + return comedi_pci_auto_config(dev, &driver_ni6527); } static void __devexit driver_ni6527_pci_remove(struct pci_dev *dev) diff --git a/trunk/drivers/staging/comedi/drivers/ni_65xx.c b/trunk/drivers/staging/comedi/drivers/ni_65xx.c index 403fc0997d37..0d27a9323bc0 100644 --- a/trunk/drivers/staging/comedi/drivers/ni_65xx.c +++ b/trunk/drivers/staging/comedi/drivers/ni_65xx.c @@ -111,7 +111,7 @@ static inline unsigned Filter_Enable(unsigned port) static int ni_65xx_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int ni_65xx_detach(struct comedi_device *dev); +static void ni_65xx_detach(struct comedi_device *dev); static struct comedi_driver driver_ni_65xx = { .driver_name = "ni_65xx", .module = THIS_MODULE, @@ -784,7 +784,7 @@ static int ni_65xx_attach(struct comedi_device *dev, return 0; } -static int ni_65xx_detach(struct comedi_device *dev) +static void ni_65xx_detach(struct comedi_device *dev) { if (private(dev) && private(dev)->mite && private(dev)->mite->daq_io_addr) { @@ -792,10 +792,8 @@ static int ni_65xx_detach(struct comedi_device *dev) private(dev)->mite->daq_io_addr + Master_Interrupt_Control); } - if (dev->irq) free_irq(dev->irq, dev); - if (private(dev)) { unsigned i; for (i = 0; i < dev->n_subdevices; ++i) { @@ -805,7 +803,6 @@ static int ni_65xx_detach(struct comedi_device *dev) if (private(dev)->mite) mite_unsetup(private(dev)->mite); } - return 0; } static int ni_65xx_find_device(struct comedi_device *dev, int bus, int slot) @@ -837,7 +834,7 @@ static int ni_65xx_find_device(struct comedi_device *dev, int bus, int slot) static int __devinit driver_ni_65xx_pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, driver_ni_65xx.driver_name); + return comedi_pci_auto_config(dev, &driver_ni_65xx); } static void __devexit driver_ni_65xx_pci_remove(struct pci_dev *dev) diff --git a/trunk/drivers/staging/comedi/drivers/ni_660x.c b/trunk/drivers/staging/comedi/drivers/ni_660x.c index 35f3a4749825..8c40730e296a 100644 --- a/trunk/drivers/staging/comedi/drivers/ni_660x.c +++ b/trunk/drivers/staging/comedi/drivers/ni_660x.c @@ -458,7 +458,7 @@ static inline const struct ni_660x_board *board(struct comedi_device *dev) static int ni_660x_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int ni_660x_detach(struct comedi_device *dev); +static void ni_660x_detach(struct comedi_device *dev); static void init_tio_chip(struct comedi_device *dev, int chipset); static void ni_660x_select_pfi_output(struct comedi_device *dev, unsigned pfi_channel, @@ -474,7 +474,7 @@ static struct comedi_driver driver_ni_660x = { static int __devinit driver_ni_660x_pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, driver_ni_660x.driver_name); + return comedi_pci_auto_config(dev, &driver_ni_660x); } static void __devexit driver_ni_660x_pci_remove(struct pci_dev *dev) @@ -761,7 +761,7 @@ static inline void ni_660x_write_register(struct comedi_device *dev, unsigned chip_index, unsigned bits, enum NI_660x_Register reg) { - void *const write_address = + void __iomem *write_address = private(dev)->mite->daq_io_addr + GPCT_OFFSET[chip_index] + registerData[reg].offset; @@ -784,7 +784,7 @@ static inline unsigned ni_660x_read_register(struct comedi_device *dev, unsigned chip_index, enum NI_660x_Register reg) { - void *const read_address = + void __iomem *read_address = private(dev)->mite->daq_io_addr + GPCT_OFFSET[chip_index] + registerData[reg].offset; @@ -1188,14 +1188,10 @@ static int ni_660x_attach(struct comedi_device *dev, return 0; } -static int ni_660x_detach(struct comedi_device *dev) +static void ni_660x_detach(struct comedi_device *dev) { - printk(KERN_INFO "comedi%d: ni_660x: remove\n", dev->minor); - - /* Free irq */ if (dev->irq) free_irq(dev->irq, dev); - if (dev->private) { if (private(dev)->counter_dev) ni_gpct_device_destroy(private(dev)->counter_dev); @@ -1204,7 +1200,6 @@ static int ni_660x_detach(struct comedi_device *dev) mite_unsetup(private(dev)->mite); } } - return 0; } static int diff --git a/trunk/drivers/staging/comedi/drivers/ni_670x.c b/trunk/drivers/staging/comedi/drivers/ni_670x.c index d8d91f90060e..a9cf94fd0c30 100644 --- a/trunk/drivers/staging/comedi/drivers/ni_670x.c +++ b/trunk/drivers/staging/comedi/drivers/ni_670x.c @@ -111,7 +111,7 @@ struct ni_670x_private { static int ni_670x_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int ni_670x_detach(struct comedi_device *dev); +static void ni_670x_detach(struct comedi_device *dev); static struct comedi_driver driver_ni_670x = { .driver_name = "ni_670x", @@ -123,7 +123,7 @@ static struct comedi_driver driver_ni_670x = { static int __devinit driver_ni_670x_pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, driver_ni_670x.driver_name); + return comedi_pci_auto_config(dev, &driver_ni_670x); } static void __devexit driver_ni_670x_pci_remove(struct pci_dev *dev) @@ -249,19 +249,13 @@ static int ni_670x_attach(struct comedi_device *dev, return 1; } -static int ni_670x_detach(struct comedi_device *dev) +static void ni_670x_detach(struct comedi_device *dev) { - printk(KERN_INFO "comedi%d: ni_670x: remove\n", dev->minor); - kfree(dev->subdevices[0].range_table_list); - if (dev->private && devpriv->mite) mite_unsetup(devpriv->mite); - if (dev->irq) free_irq(dev->irq, dev); - - return 0; } static int ni_670x_ao_winsn(struct comedi_device *dev, diff --git a/trunk/drivers/staging/comedi/drivers/ni_at_a2150.c b/trunk/drivers/staging/comedi/drivers/ni_at_a2150.c index c25e44c1905e..ae896a094150 100644 --- a/trunk/drivers/staging/comedi/drivers/ni_at_a2150.c +++ b/trunk/drivers/staging/comedi/drivers/ni_at_a2150.c @@ -171,46 +171,13 @@ struct a2150_private { #define devpriv ((struct a2150_private *)dev->private) -static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int a2150_detach(struct comedi_device *dev); static int a2150_cancel(struct comedi_device *dev, struct comedi_subdevice *s); -static struct comedi_driver driver_a2150 = { - .driver_name = "ni_at_a2150", - .module = THIS_MODULE, - .attach = a2150_attach, - .detach = a2150_detach, -}; - -static irqreturn_t a2150_interrupt(int irq, void *d); -static int a2150_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd); -static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s); -static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); static int a2150_get_timing(struct comedi_device *dev, unsigned int *period, int flags); -static int a2150_probe(struct comedi_device *dev); static int a2150_set_chanlist(struct comedi_device *dev, unsigned int start_channel, unsigned int num_channels); -/* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. - */ -static int __init driver_a2150_init_module(void) -{ - return comedi_driver_register(&driver_a2150); -} - -static void __exit driver_a2150_cleanup_module(void) -{ - comedi_driver_unregister(&driver_a2150); -} - -module_init(driver_a2150_init_module); -module_exit(driver_a2150_cleanup_module); - #ifdef A2150_DEBUG static void ni_dump_regs(struct comedi_device *dev) @@ -331,161 +298,6 @@ static irqreturn_t a2150_interrupt(int irq, void *d) return IRQ_HANDLED; } -/* probes board type, returns offset */ -static int a2150_probe(struct comedi_device *dev) -{ - int status = inw(dev->iobase + STATUS_REG); - return ID_BITS(status); -} - -static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - unsigned long iobase = it->options[0]; - unsigned int irq = it->options[1]; - unsigned int dma = it->options[2]; - static const int timeout = 2000; - int i; - - printk("comedi%d: %s: io 0x%lx", dev->minor, driver_a2150.driver_name, - iobase); - if (irq) { - printk(", irq %u", irq); - } else { - printk(", no irq"); - } - if (dma) { - printk(", dma %u", dma); - } else { - printk(", no dma"); - } - printk("\n"); - - /* allocate and initialize dev->private */ - if (alloc_private(dev, sizeof(struct a2150_private)) < 0) - return -ENOMEM; - - if (iobase == 0) { - printk(" io base address required\n"); - return -EINVAL; - } - - /* check if io addresses are available */ - if (!request_region(iobase, A2150_SIZE, driver_a2150.driver_name)) { - printk(" I/O port conflict\n"); - return -EIO; - } - dev->iobase = iobase; - - /* grab our IRQ */ - if (irq) { - /* check that irq is supported */ - if (irq < 3 || irq == 8 || irq == 13 || irq > 15) { - printk(" invalid irq line %u\n", irq); - return -EINVAL; - } - if (request_irq(irq, a2150_interrupt, 0, - driver_a2150.driver_name, dev)) { - printk("unable to allocate irq %u\n", irq); - return -EINVAL; - } - devpriv->irq_dma_bits |= IRQ_LVL_BITS(irq); - dev->irq = irq; - } - /* initialize dma */ - if (dma) { - if (dma == 4 || dma > 7) { - printk(" invalid dma channel %u\n", dma); - return -EINVAL; - } - if (request_dma(dma, driver_a2150.driver_name)) { - printk(" failed to allocate dma channel %u\n", dma); - return -EINVAL; - } - devpriv->dma = dma; - devpriv->dma_buffer = - kmalloc(A2150_DMA_BUFFER_SIZE, GFP_KERNEL | GFP_DMA); - if (devpriv->dma_buffer == NULL) - return -ENOMEM; - - disable_dma(dma); - set_dma_mode(dma, DMA_MODE_READ); - - devpriv->irq_dma_bits |= DMA_CHAN_BITS(dma); - } - - dev->board_ptr = a2150_boards + a2150_probe(dev); - dev->board_name = thisboard->name; - - if (alloc_subdevices(dev, 1) < 0) - return -ENOMEM; - - /* analog input subdevice */ - s = dev->subdevices + 0; - dev->read_subdev = s; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_OTHER | SDF_CMD_READ; - s->n_chan = 4; - s->len_chanlist = 4; - s->maxdata = 0xffff; - s->range_table = &range_a2150; - s->do_cmd = a2150_ai_cmd; - s->do_cmdtest = a2150_ai_cmdtest; - s->insn_read = a2150_ai_rinsn; - s->cancel = a2150_cancel; - - /* need to do this for software counting of completed conversions, to - * prevent hardware count from stopping acquisition */ - outw(HW_COUNT_DISABLE, dev->iobase + I8253_MODE_REG); - - /* set card's irq and dma levels */ - outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG); - - /* reset and sync adc clock circuitry */ - outw_p(DPD_BIT | APD_BIT, dev->iobase + CONFIG_REG); - outw_p(DPD_BIT, dev->iobase + CONFIG_REG); - /* initialize configuration register */ - devpriv->config_bits = 0; - outw(devpriv->config_bits, dev->iobase + CONFIG_REG); - /* wait until offset calibration is done, then enable analog inputs */ - for (i = 0; i < timeout; i++) { - if ((DCAL_BIT & inw(dev->iobase + STATUS_REG)) == 0) - break; - udelay(1000); - } - if (i == timeout) { - printk - (" timed out waiting for offset calibration to complete\n"); - return -ETIME; - } - devpriv->config_bits |= ENABLE0_BIT | ENABLE1_BIT; - outw(devpriv->config_bits, dev->iobase + CONFIG_REG); - - return 0; -}; - -static int a2150_detach(struct comedi_device *dev) -{ - printk("comedi%d: %s: remove\n", dev->minor, driver_a2150.driver_name); - - /* only free stuff if it has been allocated by _attach */ - if (dev->iobase) { - /* put board in power-down mode */ - outw(APD_BIT | DPD_BIT, dev->iobase + CONFIG_REG); - release_region(dev->iobase, A2150_SIZE); - } - - if (dev->irq) - free_irq(dev->irq, dev); - if (devpriv) { - if (devpriv->dma) - free_dma(devpriv->dma); - kfree(devpriv->dma_buffer); - } - - return 0; -}; - static int a2150_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { /* disable dma on card */ @@ -539,7 +351,10 @@ static int a2150_ai_cmdtest(struct comedi_device *dev, if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually compatible */ + /* + * step 2: make sure trigger sources are unique and mutually + * compatible + */ if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) err++; @@ -771,7 +586,10 @@ static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, /* start acquisition for soft trigger */ outw(0, dev->iobase + FIFO_START_REG); - /* there is a 35.6 sample delay for data to get through the antialias filter */ + /* + * there is a 35.6 sample delay for data to get through the + * antialias filter + */ for (n = 0; n < filter_delay; n++) { for (i = 0; i < timeout; i++) { if (inw(dev->iobase + STATUS_REG) & FNE_BIT) @@ -812,8 +630,10 @@ static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, return n; } -/* sets bits in devpriv->clock_bits to nearest approximation of requested period, - * adjusts requested period to actual timing. */ +/* + * sets bits in devpriv->clock_bits to nearest approximation of requested + * period, adjusts requested period to actual timing. + */ static int a2150_get_timing(struct comedi_device *dev, unsigned int *period, int flags) { @@ -920,6 +740,162 @@ static int a2150_set_chanlist(struct comedi_device *dev, return 0; } +/* probes board type, returns offset */ +static int a2150_probe(struct comedi_device *dev) +{ + int status = inw(dev->iobase + STATUS_REG); + return ID_BITS(status); +} + +static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it) +{ + struct comedi_subdevice *s; + unsigned long iobase = it->options[0]; + unsigned int irq = it->options[1]; + unsigned int dma = it->options[2]; + static const int timeout = 2000; + int i; + + printk("comedi%d: %s: io 0x%lx", dev->minor, dev->driver->driver_name, + iobase); + if (irq) { + printk(", irq %u", irq); + } else { + printk(", no irq"); + } + if (dma) { + printk(", dma %u", dma); + } else { + printk(", no dma"); + } + printk("\n"); + + /* allocate and initialize dev->private */ + if (alloc_private(dev, sizeof(struct a2150_private)) < 0) + return -ENOMEM; + + if (iobase == 0) { + printk(" io base address required\n"); + return -EINVAL; + } + + /* check if io addresses are available */ + if (!request_region(iobase, A2150_SIZE, dev->driver->driver_name)) { + printk(" I/O port conflict\n"); + return -EIO; + } + dev->iobase = iobase; + + /* grab our IRQ */ + if (irq) { + /* check that irq is supported */ + if (irq < 3 || irq == 8 || irq == 13 || irq > 15) { + printk(" invalid irq line %u\n", irq); + return -EINVAL; + } + if (request_irq(irq, a2150_interrupt, 0, + dev->driver->driver_name, dev)) { + printk("unable to allocate irq %u\n", irq); + return -EINVAL; + } + devpriv->irq_dma_bits |= IRQ_LVL_BITS(irq); + dev->irq = irq; + } + /* initialize dma */ + if (dma) { + if (dma == 4 || dma > 7) { + printk(" invalid dma channel %u\n", dma); + return -EINVAL; + } + if (request_dma(dma, dev->driver->driver_name)) { + printk(" failed to allocate dma channel %u\n", dma); + return -EINVAL; + } + devpriv->dma = dma; + devpriv->dma_buffer = + kmalloc(A2150_DMA_BUFFER_SIZE, GFP_KERNEL | GFP_DMA); + if (devpriv->dma_buffer == NULL) + return -ENOMEM; + + disable_dma(dma); + set_dma_mode(dma, DMA_MODE_READ); + + devpriv->irq_dma_bits |= DMA_CHAN_BITS(dma); + } + + dev->board_ptr = a2150_boards + a2150_probe(dev); + dev->board_name = thisboard->name; + + if (alloc_subdevices(dev, 1) < 0) + return -ENOMEM; + + /* analog input subdevice */ + s = dev->subdevices + 0; + dev->read_subdev = s; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_OTHER | SDF_CMD_READ; + s->n_chan = 4; + s->len_chanlist = 4; + s->maxdata = 0xffff; + s->range_table = &range_a2150; + s->do_cmd = a2150_ai_cmd; + s->do_cmdtest = a2150_ai_cmdtest; + s->insn_read = a2150_ai_rinsn; + s->cancel = a2150_cancel; + + /* need to do this for software counting of completed conversions, to + * prevent hardware count from stopping acquisition */ + outw(HW_COUNT_DISABLE, dev->iobase + I8253_MODE_REG); + + /* set card's irq and dma levels */ + outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG); + + /* reset and sync adc clock circuitry */ + outw_p(DPD_BIT | APD_BIT, dev->iobase + CONFIG_REG); + outw_p(DPD_BIT, dev->iobase + CONFIG_REG); + /* initialize configuration register */ + devpriv->config_bits = 0; + outw(devpriv->config_bits, dev->iobase + CONFIG_REG); + /* wait until offset calibration is done, then enable analog inputs */ + for (i = 0; i < timeout; i++) { + if ((DCAL_BIT & inw(dev->iobase + STATUS_REG)) == 0) + break; + udelay(1000); + } + if (i == timeout) { + printk + (" timed out waiting for offset calibration to complete\n"); + return -ETIME; + } + devpriv->config_bits |= ENABLE0_BIT | ENABLE1_BIT; + outw(devpriv->config_bits, dev->iobase + CONFIG_REG); + + return 0; +}; + +static void a2150_detach(struct comedi_device *dev) +{ + if (dev->iobase) { + outw(APD_BIT | DPD_BIT, dev->iobase + CONFIG_REG); + release_region(dev->iobase, A2150_SIZE); + } + if (dev->irq) + free_irq(dev->irq, dev); + if (devpriv) { + if (devpriv->dma) + free_dma(devpriv->dma); + kfree(devpriv->dma_buffer); + } +}; + +static struct comedi_driver ni_at_a2150_driver = { + .driver_name = "ni_at_a2150", + .module = THIS_MODULE, + .attach = a2150_attach, + .detach = a2150_detach, +}; +module_comedi_driver(ni_at_a2150_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/ni_at_ao.c b/trunk/drivers/staging/comedi/drivers/ni_at_ao.c index 138dcc2275ab..c43dd8ada1da 100644 --- a/trunk/drivers/staging/comedi/drivers/ni_at_ao.c +++ b/trunk/drivers/staging/comedi/drivers/ni_at_ao.c @@ -157,17 +157,6 @@ struct atao_board { int n_ao_chans; }; -static const struct atao_board atao_boards[] = { - { - .name = "ai-ao-6", - .n_ao_chans = 6, - }, - { - .name = "ai-ao-10", - .n_ao_chans = 10, - }, -}; - #define thisboard ((struct atao_board *)dev->board_ptr) struct atao_private { @@ -182,133 +171,6 @@ struct atao_private { #define devpriv ((struct atao_private *)dev->private) -static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int atao_detach(struct comedi_device *dev); -static struct comedi_driver driver_atao = { - .driver_name = "ni_at_ao", - .module = THIS_MODULE, - .attach = atao_attach, - .detach = atao_detach, - .board_name = &atao_boards[0].name, - .offset = sizeof(struct atao_board), - .num_names = ARRAY_SIZE(atao_boards), -}; - -static int __init driver_atao_init_module(void) -{ - return comedi_driver_register(&driver_atao); -} - -static void __exit driver_atao_cleanup_module(void) -{ - comedi_driver_unregister(&driver_atao); -} - -module_init(driver_atao_init_module); -module_exit(driver_atao_cleanup_module); - -static void atao_reset(struct comedi_device *dev); - -static int atao_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int atao_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int atao_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int atao_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int atao_calib_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int atao_calib_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - unsigned long iobase; - int ao_unipolar; - - iobase = it->options[0]; - if (iobase == 0) - iobase = 0x1c0; - ao_unipolar = it->options[3]; - - printk(KERN_INFO "comedi%d: ni_at_ao: 0x%04lx", dev->minor, iobase); - - if (!request_region(iobase, ATAO_SIZE, "ni_at_ao")) { - printk(" I/O port conflict\n"); - return -EIO; - } - dev->iobase = iobase; - - /* dev->board_ptr = atao_probe(dev); */ - - dev->board_name = thisboard->name; - - if (alloc_private(dev, sizeof(struct atao_private)) < 0) - return -ENOMEM; - - if (alloc_subdevices(dev, 4) < 0) - return -ENOMEM; - - s = dev->subdevices + 0; - /* analog output subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = thisboard->n_ao_chans; - s->maxdata = (1 << 12) - 1; - if (ao_unipolar) - s->range_table = &range_unipolar10; - else - s->range_table = &range_bipolar10; - s->insn_write = &atao_ao_winsn; - s->insn_read = &atao_ao_rinsn; - - s = dev->subdevices + 1; - /* digital i/o subdevice */ - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 8; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = atao_dio_insn_bits; - s->insn_config = atao_dio_insn_config; - - s = dev->subdevices + 2; - /* caldac subdevice */ - s->type = COMEDI_SUBD_CALIB; - s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL; - s->n_chan = 21; - s->maxdata = 0xff; - s->insn_read = atao_calib_insn_read; - s->insn_write = atao_calib_insn_write; - - s = dev->subdevices + 3; - /* eeprom subdevice */ - /* s->type=COMEDI_SUBD_EEPROM; */ - s->type = COMEDI_SUBD_UNUSED; - - atao_reset(dev); - - printk(KERN_INFO "\n"); - - return 0; -} - -static int atao_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: atao: remove\n", dev->minor); - - if (dev->iobase) - release_region(dev->iobase, ATAO_SIZE); - - return 0; -} - static void atao_reset(struct comedi_device *dev) { /* This is the reset sequence described in the manual */ @@ -471,6 +333,106 @@ static int atao_calib_insn_write(struct comedi_device *dev, return insn->n; } +static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it) +{ + struct comedi_subdevice *s; + unsigned long iobase; + int ao_unipolar; + + iobase = it->options[0]; + if (iobase == 0) + iobase = 0x1c0; + ao_unipolar = it->options[3]; + + printk(KERN_INFO "comedi%d: ni_at_ao: 0x%04lx", dev->minor, iobase); + + if (!request_region(iobase, ATAO_SIZE, "ni_at_ao")) { + printk(" I/O port conflict\n"); + return -EIO; + } + dev->iobase = iobase; + + /* dev->board_ptr = atao_probe(dev); */ + + dev->board_name = thisboard->name; + + if (alloc_private(dev, sizeof(struct atao_private)) < 0) + return -ENOMEM; + + if (alloc_subdevices(dev, 4) < 0) + return -ENOMEM; + + s = dev->subdevices + 0; + /* analog output subdevice */ + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = thisboard->n_ao_chans; + s->maxdata = (1 << 12) - 1; + if (ao_unipolar) + s->range_table = &range_unipolar10; + else + s->range_table = &range_bipolar10; + s->insn_write = &atao_ao_winsn; + s->insn_read = &atao_ao_rinsn; + + s = dev->subdevices + 1; + /* digital i/o subdevice */ + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = atao_dio_insn_bits; + s->insn_config = atao_dio_insn_config; + + s = dev->subdevices + 2; + /* caldac subdevice */ + s->type = COMEDI_SUBD_CALIB; + s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL; + s->n_chan = 21; + s->maxdata = 0xff; + s->insn_read = atao_calib_insn_read; + s->insn_write = atao_calib_insn_write; + + s = dev->subdevices + 3; + /* eeprom subdevice */ + /* s->type=COMEDI_SUBD_EEPROM; */ + s->type = COMEDI_SUBD_UNUSED; + + atao_reset(dev); + + printk(KERN_INFO "\n"); + + return 0; +} + +static void atao_detach(struct comedi_device *dev) +{ + if (dev->iobase) + release_region(dev->iobase, ATAO_SIZE); +} + +static const struct atao_board atao_boards[] = { + { + .name = "ai-ao-6", + .n_ao_chans = 6, + }, { + .name = "ai-ao-10", + .n_ao_chans = 10, + }, +}; + +static struct comedi_driver ni_at_ao_driver = { + .driver_name = "ni_at_ao", + .module = THIS_MODULE, + .attach = atao_attach, + .detach = atao_detach, + .board_name = &atao_boards[0].name, + .offset = sizeof(struct atao_board), + .num_names = ARRAY_SIZE(atao_boards), +}; +module_comedi_driver(ni_at_ao_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/ni_atmio.c b/trunk/drivers/staging/comedi/drivers/ni_atmio.c index 647c228abfbf..6448373878ed 100644 --- a/trunk/drivers/staging/comedi/drivers/ni_atmio.c +++ b/trunk/drivers/staging/comedi/drivers/ni_atmio.c @@ -343,49 +343,8 @@ static struct pnp_device_id device_ids[] = { MODULE_DEVICE_TABLE(pnp, device_ids); -static int ni_atmio_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int ni_atmio_detach(struct comedi_device *dev); -static struct comedi_driver driver_atmio = { - .driver_name = "ni_atmio", - .module = THIS_MODULE, - .attach = ni_atmio_attach, - .detach = ni_atmio_detach, -}; - -static int __init driver_atmio_init_module(void) -{ - return comedi_driver_register(&driver_atmio); -} - -static void __exit driver_atmio_cleanup_module(void) -{ - comedi_driver_unregister(&driver_atmio); -} - -module_init(driver_atmio_init_module); -module_exit(driver_atmio_cleanup_module); - #include "ni_mio_common.c" -static int ni_getboardtype(struct comedi_device *dev); - -/* clean up allocated resources */ -static int ni_atmio_detach(struct comedi_device *dev) -{ - mio_common_detach(dev); - - if (dev->iobase) - release_region(dev->iobase, NI_SIZE); - if (dev->irq) - free_irq(dev->irq, dev); - - if (devpriv->isapnp_dev) - pnp_device_detach(devpriv->isapnp_dev); - - return 0; -} - static int ni_isapnp_find_board(struct pnp_dev **dev) { struct pnp_dev *isapnp_dev = NULL; @@ -424,6 +383,26 @@ static int ni_isapnp_find_board(struct pnp_dev **dev) return 0; } +static int ni_getboardtype(struct comedi_device *dev) +{ + int device_id = ni_read_eeprom(dev, 511); + int i; + + for (i = 0; i < n_ni_boards; i++) { + if (ni_boards[i].device_id == device_id) + return i; + + } + if (device_id == 255) + printk(" can't find board\n"); + else if (device_id == 0) + printk(" EEPROM read error (?) or device not found\n"); + else + printk(" unknown device ID %d -- contact author\n", device_id); + + return -1; +} + static int ni_atmio_attach(struct comedi_device *dev, struct comedi_devconfig *it) { @@ -518,22 +497,21 @@ static int ni_atmio_attach(struct comedi_device *dev, return 0; } -static int ni_getboardtype(struct comedi_device *dev) +static void ni_atmio_detach(struct comedi_device *dev) { - int device_id = ni_read_eeprom(dev, 511); - int i; - - for (i = 0; i < n_ni_boards; i++) { - if (ni_boards[i].device_id == device_id) - return i; - - } - if (device_id == 255) - printk(" can't find board\n"); - else if (device_id == 0) - printk(" EEPROM read error (?) or device not found\n"); - else - printk(" unknown device ID %d -- contact author\n", device_id); - - return -1; + mio_common_detach(dev); + if (dev->iobase) + release_region(dev->iobase, NI_SIZE); + if (dev->irq) + free_irq(dev->irq, dev); + if (devpriv->isapnp_dev) + pnp_device_detach(devpriv->isapnp_dev); } + +static struct comedi_driver ni_atmio_driver = { + .driver_name = "ni_atmio", + .module = THIS_MODULE, + .attach = ni_atmio_attach, + .detach = ni_atmio_detach, +}; +module_comedi_driver(ni_atmio_driver); diff --git a/trunk/drivers/staging/comedi/drivers/ni_atmio16d.c b/trunk/drivers/staging/comedi/drivers/ni_atmio16d.c index 285b933551ab..4f6145326747 100644 --- a/trunk/drivers/staging/comedi/drivers/ni_atmio16d.c +++ b/trunk/drivers/staging/comedi/drivers/ni_atmio16d.c @@ -110,60 +110,8 @@ struct atmio16_board_t { int has_8255; }; -static const struct atmio16_board_t atmio16_boards[] = { - { - .name = "atmio16", - .has_8255 = 0, - }, - { - .name = "atmio16d", - .has_8255 = 1, - }, -}; - -#define n_atmio16_boards ARRAY_SIZE(atmio16_boards) - #define boardtype ((const struct atmio16_board_t *)dev->board_ptr) -/* function prototypes */ -static int atmio16d_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int atmio16d_detach(struct comedi_device *dev); -static irqreturn_t atmio16d_interrupt(int irq, void *d); -static int atmio16d_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static int atmio16d_ai_cmd(struct comedi_device *dev, - struct comedi_subdevice *s); -static int atmio16d_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -static void reset_counters(struct comedi_device *dev); -static void reset_atmio16d(struct comedi_device *dev); - -/* main driver struct */ -static struct comedi_driver driver_atmio16d = { - .driver_name = "atmio16", - .module = THIS_MODULE, - .attach = atmio16d_attach, - .detach = atmio16d_detach, - .board_name = &atmio16_boards[0].name, - .num_names = n_atmio16_boards, - .offset = sizeof(struct atmio16_board_t), -}; - -static int __init driver_atmio16d_init_module(void) -{ - return comedi_driver_register(&driver_atmio16d); -} - -static void __exit driver_atmio16d_cleanup_module(void) -{ - comedi_driver_unregister(&driver_atmio16d); -} - -module_init(driver_atmio16d_init_module); -module_exit(driver_atmio16d_cleanup_module); - /* range structs */ static const struct comedi_lrange range_atmio16d_ai_10_bipolar = { 4, { BIP_RANGE @@ -881,24 +829,38 @@ static int atmio16d_attach(struct comedi_device *dev, return 0; } -static int atmio16d_detach(struct comedi_device *dev) +static void atmio16d_detach(struct comedi_device *dev) { - printk(KERN_INFO "comedi%d: atmio16d: remove\n", dev->minor); - if (dev->subdevices && boardtype->has_8255) subdev_8255_cleanup(dev, dev->subdevices + 3); - if (dev->irq) free_irq(dev->irq, dev); - reset_atmio16d(dev); - if (dev->iobase) release_region(dev->iobase, ATMIO16D_SIZE); - - return 0; } +static const struct atmio16_board_t atmio16_boards[] = { + { + .name = "atmio16", + .has_8255 = 0, + }, { + .name = "atmio16d", + .has_8255 = 1, + }, +}; + +static struct comedi_driver atmio16d_driver = { + .driver_name = "atmio16", + .module = THIS_MODULE, + .attach = atmio16d_attach, + .detach = atmio16d_detach, + .board_name = &atmio16_boards[0].name, + .num_names = ARRAY_SIZE(atmio16_boards), + .offset = sizeof(struct atmio16_board_t), +}; +module_comedi_driver(atmio16d_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/ni_daq_700.c b/trunk/drivers/staging/comedi/drivers/ni_daq_700.c index e2420123db87..75764e8d27eb 100644 --- a/trunk/drivers/staging/comedi/drivers/ni_daq_700.c +++ b/trunk/drivers/staging/comedi/drivers/ni_daq_700.c @@ -57,7 +57,7 @@ static struct pcmcia_device *pcmcia_cur_dev; static int dio700_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int dio700_detach(struct comedi_device *dev); +static void dio700_detach(struct comedi_device *dev); enum dio700_bustype { pcmcia_bustype }; @@ -419,19 +419,14 @@ static int dio700_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; }; -static int dio700_detach(struct comedi_device *dev) +static void dio700_detach(struct comedi_device *dev) { - printk(KERN_ERR "comedi%d: ni_daq_700: cs-remove\n", dev->minor); - if (dev->subdevices) subdev_700_cleanup(dev, dev->subdevices + 0); - if (thisboard->bustype != pcmcia_bustype && dev->iobase) release_region(dev->iobase, DIO700_SIZE); if (dev->irq) free_irq(dev->irq, dev); - - return 0; }; static void dio700_config(struct pcmcia_device *link); @@ -472,18 +467,12 @@ static int dio700_cs_attach(struct pcmcia_device *link) static void dio700_cs_detach(struct pcmcia_device *link) { - - printk(KERN_INFO "ni_daq_700: cs-detach!\n"); - - dev_dbg(&link->dev, "dio700_cs_detach\n"); - ((struct local_info_t *)link->priv)->stop = 1; dio700_release(link); /* This points to the parent struct local_info_t struct */ kfree(link->priv); - -} /* dio700_cs_detach */ +} static int dio700_pcmcia_config_loop(struct pcmcia_device *p_dev, void *priv_data) diff --git a/trunk/drivers/staging/comedi/drivers/ni_daq_dio24.c b/trunk/drivers/staging/comedi/drivers/ni_daq_dio24.c index c0423a8c3e36..493a22788637 100644 --- a/trunk/drivers/staging/comedi/drivers/ni_daq_dio24.c +++ b/trunk/drivers/staging/comedi/drivers/ni_daq_dio24.c @@ -57,7 +57,7 @@ static struct pcmcia_device *pcmcia_cur_dev; #define DIO24_SIZE 4 /* size of io region used by board */ static int dio24_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int dio24_detach(struct comedi_device *dev); +static void dio24_detach(struct comedi_device *dev); enum dio24_bustype { pcmcia_bustype }; @@ -168,19 +168,14 @@ static int dio24_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; }; -static int dio24_detach(struct comedi_device *dev) +static void dio24_detach(struct comedi_device *dev) { - dev_info(dev->hw_dev, "comedi%d: ni_daq_dio24: remove\n", dev->minor); - if (dev->subdevices) subdev_8255_cleanup(dev, dev->subdevices + 0); - if (thisboard->bustype != pcmcia_bustype && dev->iobase) release_region(dev->iobase, DIO24_SIZE); if (dev->irq) free_irq(dev->irq, dev); - - return 0; }; static void dio24_config(struct pcmcia_device *link); @@ -221,18 +216,12 @@ static int dio24_cs_attach(struct pcmcia_device *link) static void dio24_cs_detach(struct pcmcia_device *link) { - - printk(KERN_INFO "ni_daq_dio24: HOLA SOY YO - cs-detach!\n"); - - dev_dbg(&link->dev, "dio24_cs_detach\n"); - ((struct local_info_t *)link->priv)->stop = 1; dio24_release(link); /* This points to the parent local_info_t struct */ kfree(link->priv); - -} /* dio24_cs_detach */ +} static int dio24_pcmcia_config_loop(struct pcmcia_device *p_dev, void *priv_data) diff --git a/trunk/drivers/staging/comedi/drivers/ni_labpc.c b/trunk/drivers/staging/comedi/drivers/ni_labpc.c index 721b2be22500..53349777246b 100644 --- a/trunk/drivers/staging/comedi/drivers/ni_labpc.c +++ b/trunk/drivers/staging/comedi/drivers/ni_labpc.c @@ -805,13 +805,10 @@ static int labpc_find_device(struct comedi_device *dev, int bus, int slot) } #endif -int labpc_common_detach(struct comedi_device *dev) +void labpc_common_detach(struct comedi_device *dev) { - printk(KERN_ERR "comedi%d: ni_labpc: detach\n", dev->minor); - if (dev->subdevices) subdev_8255_cleanup(dev, dev->subdevices + 2); - #ifdef CONFIG_ISA_DMA_API /* only free stuff if it has been allocated by _attach */ kfree(devpriv->dma_buffer); @@ -826,8 +823,6 @@ int labpc_common_detach(struct comedi_device *dev) if (devpriv->mite) mite_unsetup(devpriv->mite); #endif - - return 0; }; EXPORT_SYMBOL_GPL(labpc_common_detach); @@ -2141,7 +2136,7 @@ static void write_caldac(struct comedi_device *dev, unsigned int channel, static int __devinit driver_labpc_pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, driver_labpc.driver_name); + return comedi_pci_auto_config(dev, &driver_labpc); } static void __devexit driver_labpc_pci_remove(struct pci_dev *dev) diff --git a/trunk/drivers/staging/comedi/drivers/ni_labpc.h b/trunk/drivers/staging/comedi/drivers/ni_labpc.h index 422cee58a967..e052ed3ba544 100644 --- a/trunk/drivers/staging/comedi/drivers/ni_labpc.h +++ b/trunk/drivers/staging/comedi/drivers/ni_labpc.h @@ -103,7 +103,7 @@ struct labpc_private { int labpc_common_attach(struct comedi_device *dev, unsigned long iobase, unsigned int irq, unsigned int dma); -int labpc_common_detach(struct comedi_device *dev); +void labpc_common_detach(struct comedi_device *dev); extern const int labpc_1200_is_unipolar[]; extern const int labpc_1200_ai_gain_bits[]; diff --git a/trunk/drivers/staging/comedi/drivers/ni_labpc_cs.c b/trunk/drivers/staging/comedi/drivers/ni_labpc_cs.c index ff3840544dd4..dbb61b6b3ed1 100644 --- a/trunk/drivers/staging/comedi/drivers/ni_labpc_cs.c +++ b/trunk/drivers/staging/comedi/drivers/ni_labpc_cs.c @@ -188,21 +188,13 @@ static int labpc_cs_attach(struct pcmcia_device *link) static void labpc_cs_detach(struct pcmcia_device *link) { - dev_dbg(&link->dev, "labpc_cs_detach\n"); - - /* - If the device is currently configured and active, we won't - actually delete it yet. Instead, it is marked so that when - the release() function is called, that will trigger a proper - detach(). - */ ((struct local_info_t *)link->priv)->stop = 1; labpc_release(link); /* This points to the parent local_info_t struct (may be null) */ kfree(link->priv); -} /* labpc_cs_detach */ +} static int labpc_pcmcia_config_loop(struct pcmcia_device *p_dev, void *priv_data) diff --git a/trunk/drivers/staging/comedi/drivers/ni_mio_cs.c b/trunk/drivers/staging/comedi/drivers/ni_mio_cs.c index 53ec24bb6dce..b85765d266c2 100644 --- a/trunk/drivers/staging/comedi/drivers/ni_mio_cs.c +++ b/trunk/drivers/staging/comedi/drivers/ni_mio_cs.c @@ -227,7 +227,7 @@ static uint16_t mio_cs_win_in(struct comedi_device *dev, int addr) static int mio_cs_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int mio_cs_detach(struct comedi_device *dev); +static void mio_cs_detach(struct comedi_device *dev); static struct comedi_driver driver_ni_mio_cs = { .driver_name = "ni_mio_cs", .module = THIS_MODULE, @@ -240,18 +240,11 @@ static struct comedi_driver driver_ni_mio_cs = { static int ni_getboardtype(struct comedi_device *dev, struct pcmcia_device *link); -/* clean up allocated resources */ -/* called when driver is removed */ -static int mio_cs_detach(struct comedi_device *dev) +static void mio_cs_detach(struct comedi_device *dev) { mio_common_detach(dev); - - /* PCMCIA layer frees the IO region */ - if (dev->irq) free_irq(dev->irq, dev); - - return 0; } static void mio_cs_config(struct pcmcia_device *link); @@ -276,8 +269,6 @@ static void cs_release(struct pcmcia_device *link) static void cs_detach(struct pcmcia_device *link) { - DPRINTK("cs_detach(link=%p)\n", link); - cs_release(link); } diff --git a/trunk/drivers/staging/comedi/drivers/ni_pcidio.c b/trunk/drivers/staging/comedi/drivers/ni_pcidio.c index 1df8fcbcd108..37b700830e21 100644 --- a/trunk/drivers/staging/comedi/drivers/ni_pcidio.c +++ b/trunk/drivers/staging/comedi/drivers/ni_pcidio.c @@ -293,18 +293,9 @@ enum FPGA_Control_Bits { #define IntEn (TransferReady|CountExpired|Waited|PrimaryTC|SecondaryTC) #endif -static int nidio_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int nidio_detach(struct comedi_device *dev); static int ni_pcidio_cancel(struct comedi_device *dev, struct comedi_subdevice *s); -static struct comedi_driver driver_pcidio = { - .driver_name = "ni_pcidio", - .module = THIS_MODULE, - .attach = nidio_attach, - .detach = nidio_detach, -}; - struct nidio_board { int dev_id; @@ -381,22 +372,6 @@ static const struct nidio_board nidio_boards[] = { #define n_nidio_boards ARRAY_SIZE(nidio_boards) #define this_board ((const struct nidio_board *)dev->board_ptr) -static DEFINE_PCI_DEVICE_TABLE(ni_pcidio_pci_table) = { - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1150)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1320)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x12b0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0160)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1630)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x13c0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0400)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1250)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x17d0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1800)}, - {0} -}; - -MODULE_DEVICE_TABLE(pci, ni_pcidio_pci_table); - struct nidio96_private { struct mite_struct *mite; int boardtype; @@ -414,7 +389,6 @@ static int ni_pcidio_cmdtest(struct comedi_device *dev, static int ni_pcidio_cmd(struct comedi_device *dev, struct comedi_subdevice *s); static int ni_pcidio_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trignum); -static int nidio_find_device(struct comedi_device *dev, int bus, int slot); static int ni_pcidio_ns_to_timer(int *nanosec, int round_mode); static int setup_mite_dma(struct comedi_device *dev, struct comedi_subdevice *s); @@ -1205,6 +1179,33 @@ static int pci_6534_upload_firmware(struct comedi_device *dev, int options[]) return 0; } +static int nidio_find_device(struct comedi_device *dev, int bus, int slot) +{ + struct mite_struct *mite; + int i; + + for (mite = mite_devices; mite; mite = mite->next) { + if (mite->used) + continue; + if (bus || slot) { + if (bus != mite->pcidev->bus->number || + slot != PCI_SLOT(mite->pcidev->devfn)) + continue; + } + for (i = 0; i < n_nidio_boards; i++) { + if (mite_device_id(mite) == nidio_boards[i].dev_id) { + dev->board_ptr = nidio_boards + i; + devpriv->mite = mite; + + return 0; + } + } + } + printk(KERN_WARNING "no device found\n"); + mite_list_devices(); + return -EIO; +} + static int nidio_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; @@ -1306,7 +1307,7 @@ static int nidio_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -static int nidio_detach(struct comedi_device *dev) +static void nidio_detach(struct comedi_device *dev) { int i; @@ -1314,10 +1315,8 @@ static int nidio_detach(struct comedi_device *dev) for (i = 0; i < this_board->n_8255; i++) subdev_8255_cleanup(dev, dev->subdevices + i); } - if (dev->irq) free_irq(dev->irq, dev); - if (devpriv) { if (devpriv->di_mite_ring) { mite_free_ring(devpriv->di_mite_ring); @@ -1326,73 +1325,48 @@ static int nidio_detach(struct comedi_device *dev) if (devpriv->mite) mite_unsetup(devpriv->mite); } - return 0; } -static int nidio_find_device(struct comedi_device *dev, int bus, int slot) -{ - struct mite_struct *mite; - int i; - - for (mite = mite_devices; mite; mite = mite->next) { - if (mite->used) - continue; - if (bus || slot) { - if (bus != mite->pcidev->bus->number || - slot != PCI_SLOT(mite->pcidev->devfn)) - continue; - } - for (i = 0; i < n_nidio_boards; i++) { - if (mite_device_id(mite) == nidio_boards[i].dev_id) { - dev->board_ptr = nidio_boards + i; - devpriv->mite = mite; - - return 0; - } - } - } - printk(KERN_WARNING "no device found\n"); - mite_list_devices(); - return -EIO; -} +static struct comedi_driver ni_pcidio_driver = { + .driver_name = "ni_pcidio", + .module = THIS_MODULE, + .attach = nidio_attach, + .detach = nidio_detach, +}; -static int __devinit driver_pcidio_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) +static int __devinit ni_pcidio_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, driver_pcidio.driver_name); + return comedi_pci_auto_config(dev, &ni_pcidio_driver); } -static void __devexit driver_pcidio_pci_remove(struct pci_dev *dev) +static void __devexit ni_pcidio_pci_remove(struct pci_dev *dev) { comedi_pci_auto_unconfig(dev); } -static struct pci_driver driver_pcidio_pci_driver = { - .id_table = ni_pcidio_pci_table, - .probe = &driver_pcidio_pci_probe, - .remove = __devexit_p(&driver_pcidio_pci_remove) +static DEFINE_PCI_DEVICE_TABLE(ni_pcidio_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1150) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1320) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x12b0) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0160) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1630) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x13c0) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0400) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1250) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x17d0) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1800) }, + { 0 } }; +MODULE_DEVICE_TABLE(pci, ni_pcidio_pci_table); -static int __init driver_pcidio_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_pcidio); - if (retval < 0) - return retval; - - driver_pcidio_pci_driver.name = (char *)driver_pcidio.driver_name; - return pci_register_driver(&driver_pcidio_pci_driver); -} - -static void __exit driver_pcidio_cleanup_module(void) -{ - pci_unregister_driver(&driver_pcidio_pci_driver); - comedi_driver_unregister(&driver_pcidio); -} - -module_init(driver_pcidio_init_module); -module_exit(driver_pcidio_cleanup_module); +static struct pci_driver ni_pcidio_pci_driver = { + .name = "ni_pcidio", + .id_table = ni_pcidio_pci_table, + .probe = ni_pcidio_pci_probe, + .remove = __devexit_p(ni_pcidio_pci_remove), +}; +module_comedi_pci_driver(ni_pcidio_driver, ni_pcidio_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/ni_pcimio.c b/trunk/drivers/staging/comedi/drivers/ni_pcimio.c index 27baefa32b17..3974c0d98d2a 100644 --- a/trunk/drivers/staging/comedi/drivers/ni_pcimio.c +++ b/trunk/drivers/staging/comedi/drivers/ni_pcimio.c @@ -129,66 +129,6 @@ SCXI is probably broken for m-series boards. #define DRV_NAME "ni_pcimio" -/* The following two tables must be in the same order */ -static DEFINE_PCI_DEVICE_TABLE(ni_pci_table) = { - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0162)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1170)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1180)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1190)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11b0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11c0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11d0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1270)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1330)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1340)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1350)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x14e0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x14f0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1580)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x15b0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1880)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1870)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x18b0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x18c0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2410)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2420)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2430)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2890)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x28c0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a60)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a70)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a80)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2ab0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b80)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b90)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2c80)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2ca0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70aa)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70ab)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70ac)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70af)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b4)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b6)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b7)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b8)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bc)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bd)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bf)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70c0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70f2)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x710d)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x716c)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x716d)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717f)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x71bc)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717d)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x72e8)}, - {0} -}; - -MODULE_DEVICE_TABLE(pci, ni_pci_table); - /* These are not all the possible ao ranges for 628x boards. They can do OFFSET +- REFERENCE where OFFSET can be 0V, 5V, APFI<0,1>, or AO<0...3> and RANGE can @@ -1250,54 +1190,6 @@ static const struct ni_board_struct ni_boards[] = { #define n_pcimio_boards ARRAY_SIZE(ni_boards) -static int pcimio_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcimio_detach(struct comedi_device *dev); -static struct comedi_driver driver_pcimio = { - .driver_name = DRV_NAME, - .module = THIS_MODULE, - .attach = pcimio_attach, - .detach = pcimio_detach, -}; - -static int __devinit driver_pcimio_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, driver_pcimio.driver_name); -} - -static void __devexit driver_pcimio_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_pcimio_pci_driver = { - .id_table = ni_pci_table, - .probe = &driver_pcimio_pci_probe, - .remove = __devexit_p(&driver_pcimio_pci_remove) -}; - -static int __init driver_pcimio_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_pcimio); - if (retval < 0) - return retval; - - driver_pcimio_pci_driver.name = (char *)driver_pcimio.driver_name; - return pci_register_driver(&driver_pcimio_pci_driver); -} - -static void __exit driver_pcimio_cleanup_module(void) -{ - pci_unregister_driver(&driver_pcimio_pci_driver); - comedi_driver_unregister(&driver_pcimio); -} - -module_init(driver_pcimio_init_module); -module_exit(driver_pcimio_cleanup_module); - struct ni_private { NI_PRIVATE_COMMON}; #define devpriv ((struct ni_private *)dev->private) @@ -1681,13 +1573,11 @@ static void init_6143(struct comedi_device *dev) ni_writew(devpriv->ai_calib_source, Calibration_Channel_6143); } -/* cleans up allocated resources */ -static int pcimio_detach(struct comedi_device *dev) +static void pcimio_detach(struct comedi_device *dev) { mio_common_detach(dev); if (dev->irq) free_irq(dev->irq, dev); - if (dev->private) { mite_free_ring(devpriv->ai_mite_ring); mite_free_ring(devpriv->ao_mite_ring); @@ -1697,8 +1587,6 @@ static int pcimio_detach(struct comedi_device *dev) if (devpriv->mite) mite_unsetup(devpriv->mite); } - - return 0; } static int pcimio_attach(struct comedi_device *dev, struct comedi_devconfig *it) @@ -1874,6 +1762,90 @@ static int pcimio_dio_change(struct comedi_device *dev, return 0; } +static struct comedi_driver ni_pcimio_driver = { + .driver_name = "ni_pcimio", + .module = THIS_MODULE, + .attach = pcimio_attach, + .detach = pcimio_detach, +}; + +static int __devinit ni_pcimio_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + return comedi_pci_auto_config(dev, &ni_pcimio_driver); +} + +static void __devexit ni_pcimio_pci_remove(struct pci_dev *dev) +{ + comedi_pci_auto_unconfig(dev); +} + +static DEFINE_PCI_DEVICE_TABLE(ni_pcimio_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0162) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1170) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1180) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1190) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11b0) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11c0) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11d0) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1270) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1330) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1340) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1350) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x14e0) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x14f0) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1580) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x15b0) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1880) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1870) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x18b0) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x18c0) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2410) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2420) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2430) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2890) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x28c0) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a60) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a70) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a80) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2ab0) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b80) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b90) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2c80) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2ca0) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70aa) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70ab) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70ac) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70af) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b0) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b4) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b6) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b7) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b8) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bc) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bd) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bf) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70c0) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70f2) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x710d) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x716c) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x716d) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717f) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x71bc) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717d) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x72e8) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, ni_pcimio_pci_table); + +static struct pci_driver ni_pcimio_pci_driver = { + .name = "ni_pcimio", + .id_table = ni_pcimio_pci_table, + .probe = ni_pcimio_pci_probe, + .remove = __devexit_p(ni_pcimio_pci_remove) +}; +module_comedi_pci_driver(ni_pcimio_driver, ni_pcimio_pci_driver) + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/ni_tio_internal.h b/trunk/drivers/staging/comedi/drivers/ni_tio_internal.h index c4ca53785832..5e00212aa022 100644 --- a/trunk/drivers/staging/comedi/drivers/ni_tio_internal.h +++ b/trunk/drivers/staging/comedi/drivers/ni_tio_internal.h @@ -362,8 +362,8 @@ static inline enum ni_gpct_register NITIO_Gi_ABZ_Reg(int counter_index) return 0; } -static inline enum ni_gpct_register NITIO_Gi_Interrupt_Acknowledge_Reg(int - counter_index) +static inline enum ni_gpct_register NITIO_Gi_Interrupt_Acknowledge_Reg( + int counter_index) { switch (counter_index) { case 0: @@ -407,8 +407,8 @@ static inline enum ni_gpct_register NITIO_Gi_Status_Reg(int counter_index) return 0; } -static inline enum ni_gpct_register NITIO_Gi_Interrupt_Enable_Reg(int - counter_index) +static inline enum ni_gpct_register NITIO_Gi_Interrupt_Enable_Reg( + int counter_index) { switch (counter_index) { case 0: @@ -472,15 +472,22 @@ enum Gi_Counting_Mode_Reg_Bits { Gi_Index_Phase_LowA_HighB = 0x1 << Gi_Index_Phase_Bitshift, Gi_Index_Phase_HighA_LowB = 0x2 << Gi_Index_Phase_Bitshift, Gi_Index_Phase_HighA_HighB = 0x3 << Gi_Index_Phase_Bitshift, - Gi_HW_Arm_Enable_Bit = 0x80, /* from m-series example code, not documented in 660x register level manual */ - Gi_660x_HW_Arm_Select_Mask = 0x7 << Gi_HW_Arm_Select_Shift, /* from m-series example code, not documented in 660x register level manual */ + /* from m-series example code, not documented in 660x register level + * manual */ + Gi_HW_Arm_Enable_Bit = 0x80, + /* from m-series example code, not documented in 660x register level + * manual */ + Gi_660x_HW_Arm_Select_Mask = 0x7 << Gi_HW_Arm_Select_Shift, Gi_660x_Prescale_X8_Bit = 0x1000, Gi_M_Series_Prescale_X8_Bit = 0x2000, Gi_M_Series_HW_Arm_Select_Mask = 0x1f << Gi_HW_Arm_Select_Shift, - /* must be set for clocks over 40MHz, which includes synchronous counting and quadrature modes */ + /* must be set for clocks over 40MHz, which includes synchronous + * counting and quadrature modes */ Gi_660x_Alternate_Sync_Bit = 0x2000, Gi_M_Series_Alternate_Sync_Bit = 0x4000, - Gi_660x_Prescale_X2_Bit = 0x4000, /* from m-series example code, not documented in 660x register level manual */ + /* from m-series example code, not documented in 660x register level + * manual */ + Gi_660x_Prescale_X2_Bit = 0x4000, Gi_M_Series_Prescale_X2_Bit = 0x8000, }; @@ -503,7 +510,8 @@ enum Gi_Mode_Bits { Gi_Level_Gating_Bits = 0x1, Gi_Rising_Edge_Gating_Bits = 0x2, Gi_Falling_Edge_Gating_Bits = 0x3, - Gi_Gate_On_Both_Edges_Bit = 0x4, /* used in conjunction with rising edge gating mode */ + Gi_Gate_On_Both_Edges_Bit = 0x4, /* used in conjunction with + * rising edge gating mode */ Gi_Trigger_Mode_for_Edge_Gate_Mask = 0x18, Gi_Edge_Gate_Starts_Stops_Bits = 0x0, Gi_Edge_Gate_Stops_Starts_Bits = 0x8, @@ -686,11 +694,10 @@ static inline unsigned Gi_Gate_Interrupt_Enable_Bit(unsigned counter_index) { unsigned bit; - if (counter_index % 2) { + if (counter_index % 2) bit = G1_Gate_Interrupt_Enable_Bit; - } else { + else bit = G0_Gate_Interrupt_Enable_Bit; - } return bit; } @@ -748,8 +755,9 @@ static inline void ni_tio_set_bits_transient(struct ni_gpct *counter, } /* ni_tio_set_bits( ) is for safely writing to registers whose bits may be -twiddled in interrupt context, or whose software copy may be read in interrupt context. -*/ + * twiddled in interrupt context, or whose software copy may be read in + * interrupt context. + */ static inline void ni_tio_set_bits(struct ni_gpct *counter, enum ni_gpct_register register_index, unsigned bit_mask, unsigned bit_values) diff --git a/trunk/drivers/staging/comedi/drivers/pcl711.c b/trunk/drivers/staging/comedi/drivers/pcl711.c index b44386a6b636..2e7753f988aa 100644 --- a/trunk/drivers/staging/comedi/drivers/pcl711.c +++ b/trunk/drivers/staging/comedi/drivers/pcl711.c @@ -148,42 +148,8 @@ struct pcl711_board { const struct comedi_lrange *ai_range_type; }; -static const struct pcl711_board boardtypes[] = { - {"pcl711", 0, 0, 0, 5, 8, 1, 0, &range_bipolar5}, - {"pcl711b", 1, 0, 0, 5, 8, 1, 7, &range_pcl711b_ai}, - {"acl8112hg", 0, 1, 0, 12, 16, 2, 15, &range_acl8112hg_ai}, - {"acl8112dg", 0, 1, 1, 9, 16, 2, 15, &range_acl8112dg_ai}, -}; - -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl711_board)) #define this_board ((const struct pcl711_board *)dev->board_ptr) -static int pcl711_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcl711_detach(struct comedi_device *dev); -static struct comedi_driver driver_pcl711 = { - .driver_name = "pcl711", - .module = THIS_MODULE, - .attach = pcl711_attach, - .detach = pcl711_detach, - .board_name = &boardtypes[0].name, - .num_names = n_boardtypes, - .offset = sizeof(struct pcl711_board), -}; - -static int __init driver_pcl711_init_module(void) -{ - return comedi_driver_register(&driver_pcl711); -} - -static void __exit driver_pcl711_cleanup_module(void) -{ - comedi_driver_unregister(&driver_pcl711); -} - -module_init(driver_pcl711_init_module); -module_exit(driver_pcl711_cleanup_module); - struct pcl711_private { int board; @@ -513,21 +479,6 @@ static int pcl711_do_insn_bits(struct comedi_device *dev, return 2; } -/* Free any resources that we have claimed */ -static int pcl711_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: pcl711: remove\n", dev->minor); - - if (dev->irq) - free_irq(dev->irq, dev); - - if (dev->iobase) - release_region(dev->iobase, PCL711_SIZE); - - return 0; -} - -/* Initialization */ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int ret; @@ -640,6 +591,32 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } +static void pcl711_detach(struct comedi_device *dev) +{ + if (dev->irq) + free_irq(dev->irq, dev); + if (dev->iobase) + release_region(dev->iobase, PCL711_SIZE); +} + +static const struct pcl711_board boardtypes[] = { + { "pcl711", 0, 0, 0, 5, 8, 1, 0, &range_bipolar5 }, + { "pcl711b", 1, 0, 0, 5, 8, 1, 7, &range_pcl711b_ai }, + { "acl8112hg", 0, 1, 0, 12, 16, 2, 15, &range_acl8112hg_ai }, + { "acl8112dg", 0, 1, 1, 9, 16, 2, 15, &range_acl8112dg_ai }, +}; + +static struct comedi_driver pcl711_driver = { + .driver_name = "pcl711", + .module = THIS_MODULE, + .attach = pcl711_attach, + .detach = pcl711_detach, + .board_name = &boardtypes[0].name, + .num_names = ARRAY_SIZE(boardtypes), + .offset = sizeof(struct pcl711_board), +}; +module_comedi_driver(pcl711_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/pcl724.c b/trunk/drivers/staging/comedi/drivers/pcl724.c index 61b075db66ef..1f66fe1c7d5e 100644 --- a/trunk/drivers/staging/comedi/drivers/pcl724.c +++ b/trunk/drivers/staging/comedi/drivers/pcl724.c @@ -56,10 +56,6 @@ See the source for configuration details. /* #define PCL724_IRQ 1 no IRQ support now */ -static int pcl724_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcl724_detach(struct comedi_device *dev); - struct pcl724_board { const char *name; /* board name */ @@ -71,41 +67,8 @@ struct pcl724_board { char is_pet48; }; -static const struct pcl724_board boardtypes[] = { - {"pcl724", 24, 1, 0x00fc, PCL724_SIZE, 0, 0,}, - {"pcl722", 144, 6, 0x00fc, PCL722_SIZE, 1, 0,}, - {"pcl731", 48, 2, 0x9cfc, PCL731_SIZE, 0, 0,}, - {"acl7122", 144, 6, 0x9ee8, PCL722_SIZE, 1, 0,}, - {"acl7124", 24, 1, 0x00fc, PCL724_SIZE, 0, 0,}, - {"pet48dio", 48, 2, 0x9eb8, PET48_SIZE, 0, 1,}, -}; - -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl724_board)) #define this_board ((const struct pcl724_board *)dev->board_ptr) -static struct comedi_driver driver_pcl724 = { - .driver_name = "pcl724", - .module = THIS_MODULE, - .attach = pcl724_attach, - .detach = pcl724_detach, - .board_name = &boardtypes[0].name, - .num_names = n_boardtypes, - .offset = sizeof(struct pcl724_board), -}; - -static int __init driver_pcl724_init_module(void) -{ - return comedi_driver_register(&driver_pcl724); -} - -static void __exit driver_pcl724_cleanup_module(void) -{ - comedi_driver_unregister(&driver_pcl724); -} - -module_init(driver_pcl724_init_module); -module_exit(driver_pcl724_cleanup_module); - static int subdev_8255_cb(int dir, int port, int data, unsigned long arg) { unsigned long iobase = arg; @@ -214,25 +177,39 @@ static int pcl724_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -static int pcl724_detach(struct comedi_device *dev) +static void pcl724_detach(struct comedi_device *dev) { int i; - /* printk("comedi%d: pcl724: remove\n",dev->minor); */ - for (i = 0; i < dev->n_subdevices; i++) subdev_8255_cleanup(dev, dev->subdevices + i); - #ifdef PCL724_IRQ if (dev->irq) free_irq(dev->irq, dev); #endif - release_region(dev->iobase, this_board->io_range); - - return 0; } +static const struct pcl724_board boardtypes[] = { + { "pcl724", 24, 1, 0x00fc, PCL724_SIZE, 0, 0, }, + { "pcl722", 144, 6, 0x00fc, PCL722_SIZE, 1, 0, }, + { "pcl731", 48, 2, 0x9cfc, PCL731_SIZE, 0, 0, }, + { "acl7122", 144, 6, 0x9ee8, PCL722_SIZE, 1, 0, }, + { "acl7124", 24, 1, 0x00fc, PCL724_SIZE, 0, 0, }, + { "pet48dio", 48, 2, 0x9eb8, PET48_SIZE, 0, 1, }, +}; + +static struct comedi_driver pcl724_driver = { + .driver_name = "pcl724", + .module = THIS_MODULE, + .attach = pcl724_attach, + .detach = pcl724_detach, + .board_name = &boardtypes[0].name, + .num_names = ARRAY_SIZE(boardtypes), + .offset = sizeof(struct pcl724_board), +}; +module_comedi_driver(pcl724_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/pcl725.c b/trunk/drivers/staging/comedi/drivers/pcl725.c index 24b223ca4399..83a6fa53dddd 100644 --- a/trunk/drivers/staging/comedi/drivers/pcl725.c +++ b/trunk/drivers/staging/comedi/drivers/pcl725.c @@ -20,29 +20,6 @@ Devices: [Advantech] PCL-725 (pcl725) #define PCL725_DO 0 #define PCL725_DI 1 -static int pcl725_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcl725_detach(struct comedi_device *dev); -static struct comedi_driver driver_pcl725 = { - .driver_name = "pcl725", - .module = THIS_MODULE, - .attach = pcl725_attach, - .detach = pcl725_detach, -}; - -static int __init driver_pcl725_init_module(void) -{ - return comedi_driver_register(&driver_pcl725); -} - -static void __exit driver_pcl725_cleanup_module(void) -{ - comedi_driver_unregister(&driver_pcl725); -} - -module_init(driver_pcl725_init_module); -module_exit(driver_pcl725_cleanup_module); - static int pcl725_do_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { @@ -112,16 +89,20 @@ static int pcl725_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -static int pcl725_detach(struct comedi_device *dev) +static void pcl725_detach(struct comedi_device *dev) { - printk(KERN_INFO "comedi%d: pcl725: remove\n", dev->minor); - if (dev->iobase) release_region(dev->iobase, PCL725_SIZE); - - return 0; } +static struct comedi_driver pcl725_driver = { + .driver_name = "pcl725", + .module = THIS_MODULE, + .attach = pcl725_attach, + .detach = pcl725_detach, +}; +module_comedi_driver(pcl725_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/pcl726.c b/trunk/drivers/staging/comedi/drivers/pcl726.c index 897cd808eeb7..d25c30c694e3 100644 --- a/trunk/drivers/staging/comedi/drivers/pcl726.c +++ b/trunk/drivers/staging/comedi/drivers/pcl726.c @@ -111,10 +111,6 @@ static const struct comedi_lrange *const rangelist_728[] = { &range_4_20mA, &range_0_20mA }; -static int pcl726_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcl726_detach(struct comedi_device *dev); - struct pcl726_board { const char *name; /* driver name */ @@ -149,32 +145,8 @@ static const struct pcl726_board boardtypes[] = { &rangelist_728[0],}, }; -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl726_board)) #define this_board ((const struct pcl726_board *)dev->board_ptr) -static struct comedi_driver driver_pcl726 = { - .driver_name = "pcl726", - .module = THIS_MODULE, - .attach = pcl726_attach, - .detach = pcl726_detach, - .board_name = &boardtypes[0].name, - .num_names = n_boardtypes, - .offset = sizeof(struct pcl726_board), -}; - -static int __init driver_pcl726_init_module(void) -{ - return comedi_driver_register(&driver_pcl726); -} - -static void __exit driver_pcl726_cleanup_module(void) -{ - comedi_driver_unregister(&driver_pcl726); -} - -module_init(driver_pcl726_init_module); -module_exit(driver_pcl726_cleanup_module); - struct pcl726_private { int bipolar[12]; @@ -378,21 +350,27 @@ static int pcl726_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -static int pcl726_detach(struct comedi_device *dev) +static void pcl726_detach(struct comedi_device *dev) { -/* printk("comedi%d: pcl726: remove\n",dev->minor); */ - #ifdef ACL6126_IRQ if (dev->irq) free_irq(dev->irq, dev); #endif - if (dev->iobase) release_region(dev->iobase, this_board->io_range); - - return 0; } +static struct comedi_driver pcl726_driver = { + .driver_name = "pcl726", + .module = THIS_MODULE, + .attach = pcl726_attach, + .detach = pcl726_detach, + .board_name = &boardtypes[0].name, + .num_names = ARRAY_SIZE(boardtypes), + .offset = sizeof(struct pcl726_board), +}; +module_comedi_driver(pcl726_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/pcl730.c b/trunk/drivers/staging/comedi/drivers/pcl730.c index c9682d614e0e..e11704addedb 100644 --- a/trunk/drivers/staging/comedi/drivers/pcl730.c +++ b/trunk/drivers/staging/comedi/drivers/pcl730.c @@ -26,48 +26,14 @@ The ACL-7130 card have an 8254 timer/counter not supported by this driver. #define PCL730_DIO_LO 2 /* TTL Digital I/O low byte (D0-D7) */ #define PCL730_DIO_HI 3 /* TTL Digital I/O high byte (D8-D15) */ -static int pcl730_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcl730_detach(struct comedi_device *dev); - struct pcl730_board { const char *name; /* board name */ unsigned int io_range; /* len of I/O space */ }; -static const struct pcl730_board boardtypes[] = { - {"pcl730", PCL730_SIZE,}, - {"iso730", PCL730_SIZE,}, - {"acl7130", ACL7130_SIZE,}, -}; - -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl730_board)) #define this_board ((const struct pcl730_board *)dev->board_ptr) -static struct comedi_driver driver_pcl730 = { - .driver_name = "pcl730", - .module = THIS_MODULE, - .attach = pcl730_attach, - .detach = pcl730_detach, - .board_name = &boardtypes[0].name, - .num_names = n_boardtypes, - .offset = sizeof(struct pcl730_board), -}; - -static int __init driver_pcl730_init_module(void) -{ - return comedi_driver_register(&driver_pcl730); -} - -static void __exit driver_pcl730_cleanup_module(void) -{ - comedi_driver_unregister(&driver_pcl730); -} - -module_init(driver_pcl730_init_module); -module_exit(driver_pcl730_cleanup_module); - static int pcl730_do_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { @@ -168,16 +134,29 @@ static int pcl730_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -static int pcl730_detach(struct comedi_device *dev) +static void pcl730_detach(struct comedi_device *dev) { - printk(KERN_INFO "comedi%d: pcl730: remove\n", dev->minor); - if (dev->iobase) release_region(dev->iobase, this_board->io_range); - - return 0; } +static const struct pcl730_board boardtypes[] = { + { "pcl730", PCL730_SIZE, }, + { "iso730", PCL730_SIZE, }, + { "acl7130", ACL7130_SIZE, }, +}; + +static struct comedi_driver pcl730_driver = { + .driver_name = "pcl730", + .module = THIS_MODULE, + .attach = pcl730_attach, + .detach = pcl730_detach, + .board_name = &boardtypes[0].name, + .num_names = ARRAY_SIZE(boardtypes), + .offset = sizeof(struct pcl730_board), +}; +module_comedi_driver(pcl730_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/pcl812.c b/trunk/drivers/staging/comedi/drivers/pcl812.c index 6fc74645af2c..51f4ca9f7927 100644 --- a/trunk/drivers/staging/comedi/drivers/pcl812.c +++ b/trunk/drivers/staging/comedi/drivers/pcl812.c @@ -316,10 +316,6 @@ static const struct comedi_lrange range_a821pgh_ai = { 4, { } }; -static int pcl812_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcl812_detach(struct comedi_device *dev); - struct pcl812_board { const char *name; /* board name */ @@ -340,89 +336,8 @@ struct pcl812_board { unsigned char haveMPC508; /* 1=board use MPC508A multiplexor */ }; -static const struct pcl812_board boardtypes[] = { - {"pcl812", boardPCL812, 16, 0, 2, 16, 16, 0x0fff, - 33000, 500, &range_bipolar10, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"pcl812pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff, - 33000, 500, &range_pcl812pg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"acl8112pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff, - 10000, 500, &range_pcl812pg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"acl8112dg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, 500, &range_acl8112dg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, - {"acl8112hg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, 500, &range_acl8112hg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, - {"a821pgl", boardA821, 16, 8, 1, 16, 16, 0x0fff, - 10000, 500, &range_pcl813b_ai, &range_unipolar5, - 0x000c, 0x00, PCLx1x_IORANGE, 0}, - {"a821pglnda", boardA821, 16, 8, 0, 0, 0, 0x0fff, - 10000, 500, &range_pcl813b_ai, NULL, - 0x000c, 0x00, PCLx1x_IORANGE, 0}, - {"a821pgh", boardA821, 16, 8, 1, 16, 16, 0x0fff, - 10000, 500, &range_a821pgh_ai, &range_unipolar5, - 0x000c, 0x00, PCLx1x_IORANGE, 0}, - {"a822pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, 500, &range_acl8112dg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"a822pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, 500, &range_acl8112hg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"a823pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 8000, 500, &range_acl8112dg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"a823pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 8000, 500, &range_acl8112hg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"pcl813", boardPCL813, 32, 0, 0, 0, 0, 0x0fff, - 0, 0, &range_pcl813b_ai, NULL, - 0x0000, 0x00, PCLx1x_IORANGE, 0}, - {"pcl813b", boardPCL813B, 32, 0, 0, 0, 0, 0x0fff, - 0, 0, &range_pcl813b_ai, NULL, - 0x0000, 0x00, PCLx1x_IORANGE, 0}, - {"acl8113", boardACL8113, 32, 0, 0, 0, 0, 0x0fff, - 0, 0, &range_acl8113_1_ai, NULL, - 0x0000, 0x00, PCLx1x_IORANGE, 0}, - {"iso813", boardISO813, 32, 0, 0, 0, 0, 0x0fff, - 0, 0, &range_iso813_1_ai, NULL, - 0x0000, 0x00, PCLx1x_IORANGE, 0}, - {"acl8216", boardACL8216, 16, 8, 2, 16, 16, 0xffff, - 10000, 500, &range_pcl813b2_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, - {"a826pg", boardACL8216, 16, 8, 2, 16, 16, 0xffff, - 10000, 500, &range_pcl813b2_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, -}; - -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl812_board)) #define this_board ((const struct pcl812_board *)dev->board_ptr) -static struct comedi_driver driver_pcl812 = { - .driver_name = "pcl812", - .module = THIS_MODULE, - .attach = pcl812_attach, - .detach = pcl812_detach, - .board_name = &boardtypes[0].name, - .num_names = n_boardtypes, - .offset = sizeof(struct pcl812_board), -}; - -static int __init driver_pcl812_init_module(void) -{ - return comedi_driver_register(&driver_pcl812); -} - -static void __exit driver_pcl812_cleanup_module(void) -{ - comedi_driver_unregister(&driver_pcl812); -} - -module_init(driver_pcl812_init_module); -module_exit(driver_pcl812_cleanup_module); - struct pcl812_private { unsigned char valid; /* =1 device is OK */ @@ -1356,9 +1271,6 @@ static void pcl812_reset(struct comedi_device *dev) #endif } -/* -============================================================================== -*/ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int ret, subdev; @@ -1702,19 +1614,79 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -/* -============================================================================== - */ -static int pcl812_detach(struct comedi_device *dev) +static void pcl812_detach(struct comedi_device *dev) { - -#ifdef PCL812_EXTDEBUG - printk(KERN_DEBUG "comedi%d: pcl812: remove\n", dev->minor); -#endif free_resources(dev); - return 0; } +static const struct pcl812_board boardtypes[] = { + {"pcl812", boardPCL812, 16, 0, 2, 16, 16, 0x0fff, + 33000, 500, &range_bipolar10, &range_unipolar5, + 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, + {"pcl812pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff, + 33000, 500, &range_pcl812pg_ai, &range_unipolar5, + 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, + {"acl8112pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff, + 10000, 500, &range_pcl812pg_ai, &range_unipolar5, + 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, + {"acl8112dg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, + 10000, 500, &range_acl8112dg_ai, &range_unipolar5, + 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, + {"acl8112hg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, + 10000, 500, &range_acl8112hg_ai, &range_unipolar5, + 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, + {"a821pgl", boardA821, 16, 8, 1, 16, 16, 0x0fff, + 10000, 500, &range_pcl813b_ai, &range_unipolar5, + 0x000c, 0x00, PCLx1x_IORANGE, 0}, + {"a821pglnda", boardA821, 16, 8, 0, 0, 0, 0x0fff, + 10000, 500, &range_pcl813b_ai, NULL, + 0x000c, 0x00, PCLx1x_IORANGE, 0}, + {"a821pgh", boardA821, 16, 8, 1, 16, 16, 0x0fff, + 10000, 500, &range_a821pgh_ai, &range_unipolar5, + 0x000c, 0x00, PCLx1x_IORANGE, 0}, + {"a822pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, + 10000, 500, &range_acl8112dg_ai, &range_unipolar5, + 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, + {"a822pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, + 10000, 500, &range_acl8112hg_ai, &range_unipolar5, + 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, + {"a823pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, + 8000, 500, &range_acl8112dg_ai, &range_unipolar5, + 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, + {"a823pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, + 8000, 500, &range_acl8112hg_ai, &range_unipolar5, + 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, + {"pcl813", boardPCL813, 32, 0, 0, 0, 0, 0x0fff, + 0, 0, &range_pcl813b_ai, NULL, + 0x0000, 0x00, PCLx1x_IORANGE, 0}, + {"pcl813b", boardPCL813B, 32, 0, 0, 0, 0, 0x0fff, + 0, 0, &range_pcl813b_ai, NULL, + 0x0000, 0x00, PCLx1x_IORANGE, 0}, + {"acl8113", boardACL8113, 32, 0, 0, 0, 0, 0x0fff, + 0, 0, &range_acl8113_1_ai, NULL, + 0x0000, 0x00, PCLx1x_IORANGE, 0}, + {"iso813", boardISO813, 32, 0, 0, 0, 0, 0x0fff, + 0, 0, &range_iso813_1_ai, NULL, + 0x0000, 0x00, PCLx1x_IORANGE, 0}, + {"acl8216", boardACL8216, 16, 8, 2, 16, 16, 0xffff, + 10000, 500, &range_pcl813b2_ai, &range_unipolar5, + 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, + {"a826pg", boardACL8216, 16, 8, 2, 16, 16, 0xffff, + 10000, 500, &range_pcl813b2_ai, &range_unipolar5, + 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, +}; + +static struct comedi_driver pcl812_driver = { + .driver_name = "pcl812", + .module = THIS_MODULE, + .attach = pcl812_attach, + .detach = pcl812_detach, + .board_name = &boardtypes[0].name, + .num_names = ARRAY_SIZE(boardtypes), + .offset = sizeof(struct pcl812_board), +}; +module_comedi_driver(pcl812_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/pcl816.c b/trunk/drivers/staging/comedi/drivers/pcl816.c index 96cd7ec2ad53..cc67b6d46059 100644 --- a/trunk/drivers/staging/comedi/drivers/pcl816.c +++ b/trunk/drivers/staging/comedi/drivers/pcl816.c @@ -125,63 +125,14 @@ struct pcl816_board { int i8254_osc_base; /* 1/frequency of on board oscilator in ns */ }; -static const struct pcl816_board boardtypes[] = { - {"pcl816", 8, 16, 10000, 1, 16, 16, &range_pcl816, - &range_pcl816, PCLx1x_RANGE, - 0x00fc, /* IRQ mask */ - 0x0a, /* DMA mask */ - 0xffff, /* 16-bit card */ - 0xffff, /* D/A maxdata */ - 1024, - 1, /* ao chan list */ - 100}, - {"pcl814b", 8, 16, 10000, 1, 16, 16, &range_pcl816, - &range_pcl816, PCLx1x_RANGE, - 0x00fc, - 0x0a, - 0x3fff, /* 14 bit card */ - 0x3fff, - 1024, - 1, - 100}, -}; - -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl816_board)) #define devpriv ((struct pcl816_private *)dev->private) #define this_board ((const struct pcl816_board *)dev->board_ptr) -static int pcl816_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcl816_detach(struct comedi_device *dev); - #ifdef unused static int RTC_lock; /* RTC lock */ static int RTC_timer_lock; /* RTC int lock */ #endif -static struct comedi_driver driver_pcl816 = { - .driver_name = "pcl816", - .module = THIS_MODULE, - .attach = pcl816_attach, - .detach = pcl816_detach, - .board_name = &boardtypes[0].name, - .num_names = n_boardtypes, - .offset = sizeof(struct pcl816_board), -}; - -static int __init driver_pcl816_init_module(void) -{ - return comedi_driver_register(&driver_pcl816); -} - -static void __exit driver_pcl816_cleanup_module(void) -{ - comedi_driver_unregister(&driver_pcl816); -} - -module_init(driver_pcl816_init_module); -module_exit(driver_pcl816_cleanup_module); - struct pcl816_private { unsigned int dma; /* used DMA, 0=don't use DMA */ @@ -1075,46 +1026,6 @@ static int set_rtc_irq_bit(unsigned char bit) } #endif -/* -============================================================================== - Free any resources that we have claimed -*/ -static void free_resources(struct comedi_device *dev) -{ - /* printk("free_resource()\n"); */ - if (dev->private) { - pcl816_ai_cancel(dev, devpriv->sub_ai); - pcl816_reset(dev); - if (devpriv->dma) - free_dma(devpriv->dma); - if (devpriv->dmabuf[0]) - free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]); - if (devpriv->dmabuf[1]) - free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]); -#ifdef unused - if (devpriv->rtc_irq) - free_irq(devpriv->rtc_irq, dev); - if ((devpriv->dma_rtc) && (RTC_lock == 1)) { - if (devpriv->rtc_iobase) - release_region(devpriv->rtc_iobase, - devpriv->rtc_iosize); - } -#endif - } - - if (dev->irq) - free_irq(dev->irq, dev); - if (dev->iobase) - release_region(dev->iobase, this_board->io_range); - /* printk("free_resource() end\n"); */ -} - -/* -============================================================================== - - Initialization - -*/ static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int ret; @@ -1340,21 +1251,69 @@ case COMEDI_SUBD_DO: return 0; } -/* -============================================================================== - Removes device - */ -static int pcl816_detach(struct comedi_device *dev) +static void pcl816_detach(struct comedi_device *dev) { - DEBUG(printk(KERN_INFO "comedi%d: pcl816: remove\n", dev->minor);) - free_resources(dev); + if (dev->private) { + pcl816_ai_cancel(dev, devpriv->sub_ai); + pcl816_reset(dev); + if (devpriv->dma) + free_dma(devpriv->dma); + if (devpriv->dmabuf[0]) + free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]); + if (devpriv->dmabuf[1]) + free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]); +#ifdef unused + if (devpriv->rtc_irq) + free_irq(devpriv->rtc_irq, dev); + if ((devpriv->dma_rtc) && (RTC_lock == 1)) { + if (devpriv->rtc_iobase) + release_region(devpriv->rtc_iobase, + devpriv->rtc_iosize); + } +#endif + } + if (dev->irq) + free_irq(dev->irq, dev); + if (dev->iobase) + release_region(dev->iobase, this_board->io_range); #ifdef unused if (devpriv->dma_rtc) RTC_lock--; #endif - return 0; } +static const struct pcl816_board boardtypes[] = { + {"pcl816", 8, 16, 10000, 1, 16, 16, &range_pcl816, + &range_pcl816, PCLx1x_RANGE, + 0x00fc, /* IRQ mask */ + 0x0a, /* DMA mask */ + 0xffff, /* 16-bit card */ + 0xffff, /* D/A maxdata */ + 1024, + 1, /* ao chan list */ + 100}, + {"pcl814b", 8, 16, 10000, 1, 16, 16, &range_pcl816, + &range_pcl816, PCLx1x_RANGE, + 0x00fc, + 0x0a, + 0x3fff, /* 14 bit card */ + 0x3fff, + 1024, + 1, + 100}, +}; + +static struct comedi_driver pcl816_driver = { + .driver_name = "pcl816", + .module = THIS_MODULE, + .attach = pcl816_attach, + .detach = pcl816_detach, + .board_name = &boardtypes[0].name, + .num_names = ARRAY_SIZE(boardtypes), + .offset = sizeof(struct pcl816_board), +}; +module_comedi_driver(pcl816_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/pcl818.c b/trunk/drivers/staging/comedi/drivers/pcl818.c index 7344a53a81c4..1406c9720f5d 100644 --- a/trunk/drivers/staging/comedi/drivers/pcl818.c +++ b/trunk/drivers/staging/comedi/drivers/pcl818.c @@ -247,10 +247,6 @@ static const struct comedi_lrange range718_bipolar0_5 = static const struct comedi_lrange range718_unipolar2 = { 1, {UNI_RANGE(2),} }; static const struct comedi_lrange range718_unipolar1 = { 1, {BIP_RANGE(1),} }; -static int pcl818_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcl818_detach(struct comedi_device *dev); - #ifdef unused static int RTC_lock; /* RTC lock */ static int RTC_timer_lock; /* RTC int lock */ @@ -277,56 +273,6 @@ struct pcl818_board { int is_818; }; -static const struct pcl818_board boardtypes[] = { - {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 1}, - {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 1}, - {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 1, 1}, - {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 1, 1}, - {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 1}, - {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 0}, - /* pcm3718 */ - {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ }, -}; - -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl818_board)) - -static struct comedi_driver driver_pcl818 = { - .driver_name = "pcl818", - .module = THIS_MODULE, - .attach = pcl818_attach, - .detach = pcl818_detach, - .board_name = &boardtypes[0].name, - .num_names = n_boardtypes, - .offset = sizeof(struct pcl818_board), -}; - -static int __init driver_pcl818_init_module(void) -{ - return comedi_driver_register(&driver_pcl818); -} - -static void __exit driver_pcl818_cleanup_module(void) -{ - comedi_driver_unregister(&driver_pcl818); -} - -module_init(driver_pcl818_init_module); -module_exit(driver_pcl818_cleanup_module); - struct pcl818_private { unsigned int dma; /* used DMA, 0=don't use DMA */ @@ -1688,48 +1634,6 @@ static int rtc_setfreq_irq(int freq) } #endif -/* -============================================================================== - Free any resources that we have claimed -*/ -static void free_resources(struct comedi_device *dev) -{ - /* printk("free_resource()\n"); */ - if (dev->private) { - pcl818_ai_cancel(dev, devpriv->sub_ai); - pcl818_reset(dev); - if (devpriv->dma) - free_dma(devpriv->dma); - if (devpriv->dmabuf[0]) - free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]); - if (devpriv->dmabuf[1]) - free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]); -#ifdef unused - if (devpriv->rtc_irq) - free_irq(devpriv->rtc_irq, dev); - if ((devpriv->dma_rtc) && (RTC_lock == 1)) { - if (devpriv->rtc_iobase) - release_region(devpriv->rtc_iobase, - devpriv->rtc_iosize); - } - if (devpriv->dma_rtc) - RTC_lock--; -#endif - } - - if (dev->irq) - free_irq(dev->irq, dev); - if (dev->iobase) - release_region(dev->iobase, devpriv->io_range); - /* printk("free_resource() end\n"); */ -} - -/* -============================================================================== - - Initialization - -*/ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int ret; @@ -2020,17 +1924,71 @@ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -/* -============================================================================== - Removes device - */ -static int pcl818_detach(struct comedi_device *dev) +static void pcl818_detach(struct comedi_device *dev) { - /* printk("comedi%d: pcl818: remove\n", dev->minor); */ - free_resources(dev); - return 0; + if (dev->private) { + pcl818_ai_cancel(dev, devpriv->sub_ai); + pcl818_reset(dev); + if (devpriv->dma) + free_dma(devpriv->dma); + if (devpriv->dmabuf[0]) + free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]); + if (devpriv->dmabuf[1]) + free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]); +#ifdef unused + if (devpriv->rtc_irq) + free_irq(devpriv->rtc_irq, dev); + if ((devpriv->dma_rtc) && (RTC_lock == 1)) { + if (devpriv->rtc_iobase) + release_region(devpriv->rtc_iobase, + devpriv->rtc_iosize); + } + if (devpriv->dma_rtc) + RTC_lock--; +#endif + } + if (dev->irq) + free_irq(dev->irq, dev); + if (dev->iobase) + release_region(dev->iobase, devpriv->io_range); } +static const struct pcl818_board boardtypes[] = { + {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai, + &range_unipolar5, PCLx1x_RANGE, 0x00fc, + 0x0a, 0xfff, 0xfff, 0, 1}, + {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai, + &range_unipolar5, PCLx1x_RANGE, 0x00fc, + 0x0a, 0xfff, 0xfff, 0, 1}, + {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai, + &range_unipolar5, PCLx1x_RANGE, 0x00fc, + 0x0a, 0xfff, 0xfff, 1, 1}, + {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai, + &range_unipolar5, PCLx1x_RANGE, 0x00fc, + 0x0a, 0xfff, 0xfff, 1, 1}, + {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai, + &range_unipolar5, PCLx1x_RANGE, 0x00fc, + 0x0a, 0xfff, 0xfff, 0, 1}, + {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5, + &range_unipolar5, PCLx1x_RANGE, 0x00fc, + 0x0a, 0xfff, 0xfff, 0, 0}, + /* pcm3718 */ + {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai, + &range_unipolar5, PCLx1x_RANGE, 0x00fc, + 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ }, +}; + +static struct comedi_driver pcl818_driver = { + .driver_name = "pcl818", + .module = THIS_MODULE, + .attach = pcl818_attach, + .detach = pcl818_detach, + .board_name = &boardtypes[0].name, + .num_names = ARRAY_SIZE(boardtypes), + .offset = sizeof(struct pcl818_board), +}; +module_comedi_driver(pcl818_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/pcm3724.c b/trunk/drivers/staging/comedi/drivers/pcm3724.c index f5c0bd17684c..7492b8f1d499 100644 --- a/trunk/drivers/staging/comedi/drivers/pcm3724.c +++ b/trunk/drivers/staging/comedi/drivers/pcm3724.c @@ -62,10 +62,6 @@ Copy/pasted/hacked from pcm724.c #define CR_A_MODE(a) ((a)<<5) #define CR_CW 0x80 -static int pcm3724_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcm3724_detach(struct comedi_device *dev); - struct pcm3724_board { const char *name; /* driver name */ int dio; /* num of DIO */ @@ -80,36 +76,8 @@ struct priv_pcm3724 { int dio_2; }; -static const struct pcm3724_board boardtypes[] = { - {"pcm3724", 48, 2, 0x00fc, PCM3724_SIZE,}, -}; - -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcm3724_board)) #define this_board ((const struct pcm3724_board *)dev->board_ptr) -static struct comedi_driver driver_pcm3724 = { - .driver_name = "pcm3724", - .module = THIS_MODULE, - .attach = pcm3724_attach, - .detach = pcm3724_detach, - .board_name = &boardtypes[0].name, - .num_names = n_boardtypes, - .offset = sizeof(struct pcm3724_board), -}; - -static int __init driver_pcm3724_init_module(void) -{ - return comedi_driver_register(&driver_pcm3724); -} - -static void __exit driver_pcm3724_cleanup_module(void) -{ - comedi_driver_unregister(&driver_pcm3724); -} - -module_init(driver_pcm3724_init_module); -module_exit(driver_pcm3724_cleanup_module); - /* (setq c-basic-offset 8) */ static int subdev_8255_cb(int dir, int port, int data, unsigned long arg) @@ -305,7 +273,7 @@ static int pcm3724_attach(struct comedi_device *dev, return 0; } -static int pcm3724_detach(struct comedi_device *dev) +static void pcm3724_detach(struct comedi_device *dev) { int i; @@ -315,10 +283,23 @@ static int pcm3724_detach(struct comedi_device *dev) } if (dev->iobase) release_region(dev->iobase, this_board->io_range); - - return 0; } +static const struct pcm3724_board boardtypes[] = { + { "pcm3724", 48, 2, 0x00fc, PCM3724_SIZE, }, +}; + +static struct comedi_driver pcm3724_driver = { + .driver_name = "pcm3724", + .module = THIS_MODULE, + .attach = pcm3724_attach, + .detach = pcm3724_detach, + .board_name = &boardtypes[0].name, + .num_names = ARRAY_SIZE(boardtypes), + .offset = sizeof(struct pcm3724_board), +}; +module_comedi_driver(pcm3724_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/pcm3730.c b/trunk/drivers/staging/comedi/drivers/pcm3730.c index bada6b236ff1..f8d1c644daf8 100644 --- a/trunk/drivers/staging/comedi/drivers/pcm3730.c +++ b/trunk/drivers/staging/comedi/drivers/pcm3730.c @@ -28,29 +28,6 @@ Configuration options: #define PCM3730_DIB 2 #define PCM3730_DIC 3 -static int pcm3730_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcm3730_detach(struct comedi_device *dev); -static struct comedi_driver driver_pcm3730 = { - .driver_name = "pcm3730", - .module = THIS_MODULE, - .attach = pcm3730_attach, - .detach = pcm3730_detach, -}; - -static int __init driver_pcm3730_init_module(void) -{ - return comedi_driver_register(&driver_pcm3730); -} - -static void __exit driver_pcm3730_cleanup_module(void) -{ - comedi_driver_unregister(&driver_pcm3730); -} - -module_init(driver_pcm3730_init_module); -module_exit(driver_pcm3730_cleanup_module); - static int pcm3730_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -156,16 +133,20 @@ static int pcm3730_attach(struct comedi_device *dev, return 0; } -static int pcm3730_detach(struct comedi_device *dev) +static void pcm3730_detach(struct comedi_device *dev) { - printk(KERN_INFO "comedi%d: pcm3730: remove\n", dev->minor); - if (dev->iobase) release_region(dev->iobase, PCM3730_SIZE); - - return 0; } +static struct comedi_driver pcm3730_driver = { + .driver_name = "pcm3730", + .module = THIS_MODULE, + .attach = pcm3730_attach, + .detach = pcm3730_detach, +}; +module_comedi_driver(pcm3730_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/pcmad.c b/trunk/drivers/staging/comedi/drivers/pcmad.c index 23b3d777340c..1ec7d5cb346a 100644 --- a/trunk/drivers/staging/comedi/drivers/pcmad.c +++ b/trunk/drivers/staging/comedi/drivers/pcmad.c @@ -57,19 +57,8 @@ struct pcmad_board_struct { const char *name; int n_ai_bits; }; -static const struct pcmad_board_struct pcmad_boards[] = { - { - .name = "pcmad12", - .n_ai_bits = 12, - }, - { - .name = "pcmad16", - .n_ai_bits = 16, - }, -}; #define this_board ((const struct pcmad_board_struct *)(dev->board_ptr)) -#define n_pcmad_boards ARRAY_SIZE(pcmad_boards) struct pcmad_priv_struct { int differential; @@ -77,31 +66,6 @@ struct pcmad_priv_struct { }; #define devpriv ((struct pcmad_priv_struct *)dev->private) -static int pcmad_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int pcmad_detach(struct comedi_device *dev); -static struct comedi_driver driver_pcmad = { - .driver_name = "pcmad", - .module = THIS_MODULE, - .attach = pcmad_attach, - .detach = pcmad_detach, - .board_name = &pcmad_boards[0].name, - .num_names = n_pcmad_boards, - .offset = sizeof(pcmad_boards[0]), -}; - -static int __init driver_pcmad_init_module(void) -{ - return comedi_driver_register(&driver_pcmad); -} - -static void __exit driver_pcmad_cleanup_module(void) -{ - comedi_driver_unregister(&driver_pcmad); -} - -module_init(driver_pcmad_init_module); -module_exit(driver_pcmad_cleanup_module); - #define TIMEOUT 100 static int pcmad_ai_insn_read(struct comedi_device *dev, @@ -175,19 +139,34 @@ static int pcmad_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -static int pcmad_detach(struct comedi_device *dev) +static void pcmad_detach(struct comedi_device *dev) { - printk(KERN_INFO "comedi%d: pcmad: remove\n", dev->minor); - if (dev->irq) free_irq(dev->irq, dev); - if (dev->iobase) release_region(dev->iobase, PCMAD_SIZE); - - return 0; } +static const struct pcmad_board_struct pcmad_boards[] = { + { + .name = "pcmad12", + .n_ai_bits = 12, + }, { + .name = "pcmad16", + .n_ai_bits = 16, + }, +}; +static struct comedi_driver pcmad_driver = { + .driver_name = "pcmad", + .module = THIS_MODULE, + .attach = pcmad_attach, + .detach = pcmad_detach, + .board_name = &pcmad_boards[0].name, + .num_names = ARRAY_SIZE(pcmad_boards), + .offset = sizeof(pcmad_boards[0]), +}; +module_comedi_driver(pcmad_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/pcmda12.c b/trunk/drivers/staging/comedi/drivers/pcmda12.c index 0e9ffa28d745..4786148b4fd0 100644 --- a/trunk/drivers/staging/comedi/drivers/pcmda12.c +++ b/trunk/drivers/staging/comedi/drivers/pcmda12.c @@ -80,12 +80,6 @@ static const struct comedi_lrange pcmda12_ranges = { } }; -static const struct pcmda12_board pcmda12_boards[] = { - { - .name = "pcmda12", - }, -}; - /* * Useful for shorthand access to the particular board structure */ @@ -99,137 +93,6 @@ struct pcmda12_private { #define devpriv ((struct pcmda12_private *)(dev->private)) -/* - * The struct comedi_driver structure tells the Comedi core module - * which functions to call to configure/deconfigure (attach/detach) - * the board, and also about the kernel module that contains - * the device code. - */ -static int pcmda12_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcmda12_detach(struct comedi_device *dev); - -static void zero_chans(struct comedi_device *dev); - -static struct comedi_driver driver = { - .driver_name = "pcmda12", - .module = THIS_MODULE, - .attach = pcmda12_attach, - .detach = pcmda12_detach, -/* It is not necessary to implement the following members if you are - * writing a driver for a ISA PnP or PCI card */ - /* Most drivers will support multiple types of boards by - * having an array of board structures. These were defined - * in pcmda12_boards[] above. Note that the element 'name' - * was first in the structure -- Comedi uses this fact to - * extract the name of the board without knowing any details - * about the structure except for its length. - * When a device is attached (by comedi_config), the name - * of the device is given to Comedi, and Comedi tries to - * match it by going through the list of board names. If - * there is a match, the address of the pointer is put - * into dev->board_ptr and driver->attach() is called. - * - * Note that these are not necessary if you can determine - * the type of board in software. ISA PnP, PCI, and PCMCIA - * devices are such boards. - */ - .board_name = &pcmda12_boards[0].name, - .offset = sizeof(struct pcmda12_board), - .num_names = ARRAY_SIZE(pcmda12_boards), -}; - -static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ -static int pcmda12_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - unsigned long iobase; - - iobase = it->options[0]; - printk(KERN_INFO - "comedi%d: %s: io: %lx %s ", dev->minor, driver.driver_name, - iobase, it->options[1] ? "simultaneous xfer mode enabled" : ""); - - if (!request_region(iobase, IOSIZE, driver.driver_name)) { - printk("I/O port conflict\n"); - return -EIO; - } - dev->iobase = iobase; - -/* - * Initialize dev->board_name. Note that we can use the "thisboard" - * macro now, since we just initialized it in the last line. - */ - dev->board_name = thisboard->name; - -/* - * Allocate the private structure area. alloc_private() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_private(dev, sizeof(struct pcmda12_private)) < 0) { - printk(KERN_ERR "cannot allocate private data structure\n"); - return -ENOMEM; - } - - devpriv->simultaneous_xfer_mode = it->options[1]; - - /* - * Allocate the subdevice structures. alloc_subdevice() is a - * convenient macro defined in comedidev.h. - * - * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the - * 96-channel version of the board. - */ - if (alloc_subdevices(dev, 1) < 0) { - printk(KERN_ERR "cannot allocate subdevice data structures\n"); - return -ENOMEM; - } - - s = dev->subdevices; - s->private = NULL; - s->maxdata = (0x1 << BITS) - 1; - s->range_table = &pcmda12_ranges; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = CHANS; - s->insn_write = &ao_winsn; - s->insn_read = &ao_rinsn; - - zero_chans(dev); /* clear out all the registers, basically */ - - printk(KERN_INFO "attached\n"); - - return 1; -} - -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int pcmda12_detach(struct comedi_device *dev) -{ - printk(KERN_INFO - "comedi%d: %s: remove\n", dev->minor, driver.driver_name); - if (dev->iobase) - release_region(dev->iobase, IOSIZE); - return 0; -} - static void zero_chans(struct comedi_device *dev) { /* sets up an ASIC chip to defaults */ @@ -301,22 +164,91 @@ static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, return i; } +static int pcmda12_attach(struct comedi_device *dev, + struct comedi_devconfig *it) +{ + struct comedi_subdevice *s; + unsigned long iobase; + + iobase = it->options[0]; + printk(KERN_INFO + "comedi%d: %s: io: %lx %s ", dev->minor, dev->driver->driver_name, + iobase, it->options[1] ? "simultaneous xfer mode enabled" : ""); + + if (!request_region(iobase, IOSIZE, dev->driver->driver_name)) { + printk("I/O port conflict\n"); + return -EIO; + } + dev->iobase = iobase; + /* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. + * Initialize dev->board_name. Note that we can use the "thisboard" + * macro now, since we just initialized it in the last line. */ -static int __init driver_init_module(void) -{ - return comedi_driver_register(&driver); + dev->board_name = thisboard->name; + +/* + * Allocate the private structure area. alloc_private() is a + * convenient macro defined in comedidev.h. + */ + if (alloc_private(dev, sizeof(struct pcmda12_private)) < 0) { + printk(KERN_ERR "cannot allocate private data structure\n"); + return -ENOMEM; + } + + devpriv->simultaneous_xfer_mode = it->options[1]; + + /* + * Allocate the subdevice structures. alloc_subdevice() is a + * convenient macro defined in comedidev.h. + * + * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the + * 96-channel version of the board. + */ + if (alloc_subdevices(dev, 1) < 0) { + printk(KERN_ERR "cannot allocate subdevice data structures\n"); + return -ENOMEM; + } + + s = dev->subdevices; + s->private = NULL; + s->maxdata = (0x1 << BITS) - 1; + s->range_table = &pcmda12_ranges; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = CHANS; + s->insn_write = &ao_winsn; + s->insn_read = &ao_rinsn; + + zero_chans(dev); /* clear out all the registers, basically */ + + printk(KERN_INFO "attached\n"); + + return 1; } -static void __exit driver_cleanup_module(void) +static void pcmda12_detach(struct comedi_device *dev) { - comedi_driver_unregister(&driver); + if (dev->iobase) + release_region(dev->iobase, IOSIZE); } -module_init(driver_init_module); -module_exit(driver_cleanup_module); +static const struct pcmda12_board pcmda12_boards[] = { + { + .name = "pcmda12", + }, +}; + +static struct comedi_driver pcmda12_driver = { + .driver_name = "pcmda12", + .module = THIS_MODULE, + .attach = pcmda12_attach, + .detach = pcmda12_detach, + .board_name = &pcmda12_boards[0].name, + .offset = sizeof(struct pcmda12_board), + .num_names = ARRAY_SIZE(pcmda12_boards), +}; +module_comedi_driver(pcmda12_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/pcmmio.c b/trunk/drivers/staging/comedi/drivers/pcmmio.c index eddac00e4e29..efed168d2bac 100644 --- a/trunk/drivers/staging/comedi/drivers/pcmmio.c +++ b/trunk/drivers/staging/comedi/drivers/pcmmio.c @@ -145,13 +145,6 @@ Configuration Options: #define PAGE_ENAB 2 #define PAGE_INT_ID 3 -static int ai_rinsn(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); -static int ao_rinsn(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); -static int ao_winsn(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - /* * Board descriptions for two imaginary boards. Describing the * boards in this way is optional, and completely driver-dependent. @@ -190,23 +183,6 @@ static const struct comedi_lrange ranges_ao = { RANGE(-2.5, 2.5), RANGE(-2.5, 7.5)} }; -static const struct pcmmio_board pcmmio_boards[] = { - { - .name = "pcmmio", - .dio_num_asics = 1, - .dio_num_ports = 6, - .total_iosize = 32, - .ai_bits = 16, - .ao_bits = 16, - .n_ai_chans = 16, - .n_ao_chans = 8, - .ai_range_table = &ranges_ai, - .ao_range_table = &ranges_ao, - .ai_rinsn = ai_rinsn, - .ao_rinsn = ao_rinsn, - .ao_winsn = ao_winsn}, -}; - /* * Useful for shorthand access to the particular board structure */ @@ -293,312 +269,6 @@ struct pcmmio_private { */ #define devpriv ((struct pcmmio_private *)dev->private) #define subpriv ((struct pcmmio_subdev_private *)s->private) -/* - * The struct comedi_driver structure tells the Comedi core module - * which functions to call to configure/deconfigure (attach/detach) - * the board, and also about the kernel module that contains - * the device code. - */ -static int pcmmio_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcmmio_detach(struct comedi_device *dev); - -static struct comedi_driver driver = { - .driver_name = "pcmmio", - .module = THIS_MODULE, - .attach = pcmmio_attach, - .detach = pcmmio_detach, -/* It is not necessary to implement the following members if you are - * writing a driver for a ISA PnP or PCI card */ - /* Most drivers will support multiple types of boards by - * having an array of board structures. These were defined - * in pcmmio_boards[] above. Note that the element 'name' - * was first in the structure -- Comedi uses this fact to - * extract the name of the board without knowing any details - * about the structure except for its length. - * When a device is attached (by comedi_config), the name - * of the device is given to Comedi, and Comedi tries to - * match it by going through the list of board names. If - * there is a match, the address of the pointer is put - * into dev->board_ptr and driver->attach() is called. - * - * Note that these are not necessary if you can determine - * the type of board in software. ISA PnP, PCI, and PCMCIA - * devices are such boards. - */ - .board_name = &pcmmio_boards[0].name, - .offset = sizeof(struct pcmmio_board), - .num_names = ARRAY_SIZE(pcmmio_boards), -}; - -static int pcmmio_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int pcmmio_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static irqreturn_t interrupt_pcmmio(int irq, void *d); -static void pcmmio_stop_intr(struct comedi_device *, struct comedi_subdevice *); -static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s); -static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s); -static int pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd); - -/* some helper functions to deal with specifics of this device's registers */ -/* sets up/clears ASIC chips to defaults */ -static void init_asics(struct comedi_device *dev); -static void switch_page(struct comedi_device *dev, int asic, int page); -#ifdef notused -static void lock_port(struct comedi_device *dev, int asic, int port); -static void unlock_port(struct comedi_device *dev, int asic, int port); -#endif - -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ -static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic, - thisasic_chanct = 0; - unsigned long iobase; - unsigned int irq[MAX_ASICS]; - - iobase = it->options[0]; - irq[0] = it->options[1]; - - printk(KERN_INFO "comedi%d: %s: io: %lx attaching...\n", dev->minor, - driver.driver_name, iobase); - - dev->iobase = iobase; - - if (!iobase || !request_region(iobase, - thisboard->total_iosize, - driver.driver_name)) { - printk(KERN_ERR "comedi%d: I/O port conflict\n", dev->minor); - return -EIO; - } - -/* - * Initialize dev->board_name. Note that we can use the "thisboard" - * macro now, since we just initialized it in the last line. - */ - dev->board_name = thisboard->name; - -/* - * Allocate the private structure area. alloc_private() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_private(dev, sizeof(struct pcmmio_private)) < 0) { - printk(KERN_ERR "comedi%d: cannot allocate private data structure\n", - dev->minor); - return -ENOMEM; - } - - for (asic = 0; asic < MAX_ASICS; ++asic) { - devpriv->asics[asic].num = asic; - devpriv->asics[asic].iobase = - dev->iobase + 16 + asic * ASIC_IOSIZE; - /* - * this gets actually set at the end of this function when we - * request_irqs - */ - devpriv->asics[asic].irq = 0; - spin_lock_init(&devpriv->asics[asic].spinlock); - } - - chans_left = CHANS_PER_ASIC * thisboard->dio_num_asics; - n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left); - n_subdevs = n_dio_subdevs + 2; - devpriv->sprivs = - kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private), - GFP_KERNEL); - if (!devpriv->sprivs) { - printk(KERN_ERR "comedi%d: cannot allocate subdevice private data structures\n", - dev->minor); - return -ENOMEM; - } - /* - * Allocate the subdevice structures. alloc_subdevice() is a - * convenient macro defined in comedidev.h. - * - * Allocate 1 AI + 1 AO + 2 DIO subdevs (24 lines per DIO) - */ - if (alloc_subdevices(dev, n_subdevs) < 0) { - printk(KERN_ERR "comedi%d: cannot allocate subdevice data structures\n", - dev->minor); - return -ENOMEM; - } - - /* First, AI */ - sdev_no = 0; - s = dev->subdevices + sdev_no; - s->private = devpriv->sprivs + sdev_no; - s->maxdata = (1 << thisboard->ai_bits) - 1; - s->range_table = thisboard->ai_range_table; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; - s->type = COMEDI_SUBD_AI; - s->n_chan = thisboard->n_ai_chans; - s->len_chanlist = s->n_chan; - s->insn_read = thisboard->ai_rinsn; - subpriv->iobase = dev->iobase + 0; - /* initialize the resource enable register by clearing it */ - outb(0, subpriv->iobase + 3); - outb(0, subpriv->iobase + 4 + 3); - - /* Next, AO */ - ++sdev_no; - s = dev->subdevices + sdev_no; - s->private = devpriv->sprivs + sdev_no; - s->maxdata = (1 << thisboard->ao_bits) - 1; - s->range_table = thisboard->ao_range_table; - s->subdev_flags = SDF_READABLE; - s->type = COMEDI_SUBD_AO; - s->n_chan = thisboard->n_ao_chans; - s->len_chanlist = s->n_chan; - s->insn_read = thisboard->ao_rinsn; - s->insn_write = thisboard->ao_winsn; - subpriv->iobase = dev->iobase + 8; - /* initialize the resource enable register by clearing it */ - outb(0, subpriv->iobase + 3); - outb(0, subpriv->iobase + 4 + 3); - - ++sdev_no; - port = 0; - asic = 0; - for (; sdev_no < (int)dev->n_subdevices; ++sdev_no) { - int byte_no; - - s = dev->subdevices + sdev_no; - s->private = devpriv->sprivs + sdev_no; - s->maxdata = 1; - s->range_table = &range_digital; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->type = COMEDI_SUBD_DIO; - s->insn_bits = pcmmio_dio_insn_bits; - s->insn_config = pcmmio_dio_insn_config; - s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV); - subpriv->dio.intr.asic = -1; - subpriv->dio.intr.first_chan = -1; - subpriv->dio.intr.asic_chan = -1; - subpriv->dio.intr.num_asic_chans = -1; - subpriv->dio.intr.active = 0; - s->len_chanlist = 1; - - /* save the ioport address for each 'port' of 8 channels in the - subdevice */ - for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) { - if (port >= PORTS_PER_ASIC) { - port = 0; - ++asic; - thisasic_chanct = 0; - } - subpriv->iobases[byte_no] = - devpriv->asics[asic].iobase + port; - - if (thisasic_chanct < - CHANS_PER_PORT * INTR_PORTS_PER_ASIC - && subpriv->dio.intr.asic < 0) { - /* - * this is an interrupt subdevice, - * so setup the struct - */ - subpriv->dio.intr.asic = asic; - subpriv->dio.intr.active = 0; - subpriv->dio.intr.stop_count = 0; - subpriv->dio.intr.first_chan = byte_no * 8; - subpriv->dio.intr.asic_chan = thisasic_chanct; - subpriv->dio.intr.num_asic_chans = - s->n_chan - subpriv->dio.intr.first_chan; - s->cancel = pcmmio_cancel; - s->do_cmd = pcmmio_cmd; - s->do_cmdtest = pcmmio_cmdtest; - s->len_chanlist = - subpriv->dio.intr.num_asic_chans; - } - thisasic_chanct += CHANS_PER_PORT; - } - spin_lock_init(&subpriv->dio.intr.spinlock); - - chans_left -= s->n_chan; - - if (!chans_left) { - /* - * reset the asic to our first asic, - * to do intr subdevs - */ - asic = 0; - port = 0; - } - - } - - init_asics(dev); /* clear out all the registers, basically */ - - for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) { - if (irq[asic] - && request_irq(irq[asic], interrupt_pcmmio, - IRQF_SHARED, thisboard->name, dev)) { - int i; - /* unroll the allocated irqs.. */ - for (i = asic - 1; i >= 0; --i) { - free_irq(irq[i], dev); - devpriv->asics[i].irq = irq[i] = 0; - } - irq[asic] = 0; - } - devpriv->asics[asic].irq = irq[asic]; - } - - dev->irq = irq[0]; /* - * grr.. wish comedi dev struct supported - * multiple irqs.. - */ - - if (irq[0]) { - printk(KERN_DEBUG "comedi%d: irq: %u\n", dev->minor, irq[0]); - if (thisboard->dio_num_asics == 2 && irq[1]) - printk(KERN_DEBUG "comedi%d: second ASIC irq: %u\n", - dev->minor, irq[1]); - } else { - printk(KERN_INFO "comedi%d: (IRQ mode disabled)\n", dev->minor); - } - - printk(KERN_INFO "comedi%d: attached\n", dev->minor); - - return 1; -} - -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int pcmmio_detach(struct comedi_device *dev) -{ - int i; - - printk(KERN_INFO "comedi%d: %s: remove\n", dev->minor, driver.driver_name); - if (dev->iobase) - release_region(dev->iobase, thisboard->total_iosize); - - for (i = 0; i < MAX_ASICS; ++i) { - if (devpriv && devpriv->asics[i].irq) - free_irq(devpriv->asics[i].irq, dev); - } - - if (devpriv && devpriv->sprivs) - kfree(devpriv->sprivs); - - return 0; -} /* DIO devices are slightly special. Although it is possible to * implement the insn_read/insn_write interface, it is much more @@ -667,7 +337,7 @@ static int pcmmio_dio_insn_bits(struct comedi_device *dev, } #ifdef DAMMIT_ITS_BROKEN /* DEBUG */ - printk("data_out_byte %02x\n", (unsigned)byte); + printk(KERN_DEBUG "data_out_byte %02x\n", (unsigned)byte); #endif /* save the digital input lines for this byte.. */ s->state |= ((unsigned int)byte) << offset; @@ -751,6 +421,21 @@ static int pcmmio_dio_insn_config(struct comedi_device *dev, return insn->n; } +static void switch_page(struct comedi_device *dev, int asic, int page) +{ + if (asic < 0 || asic >= thisboard->dio_num_asics) + return; /* paranoia */ + if (page < 0 || page >= NUM_PAGES) + return; /* more paranoia */ + + devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK; + devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET; + + /* now write out the shadow register */ + outb(devpriv->asics[asic].pagelock, + devpriv->asics[asic].iobase + REG_PAGELOCK); +} + static void init_asics(struct comedi_device *dev) { /* sets up an ASIC chip to defaults */ @@ -788,21 +473,6 @@ static void init_asics(struct comedi_device *dev) } } -static void switch_page(struct comedi_device *dev, int asic, int page) -{ - if (asic < 0 || asic >= thisboard->dio_num_asics) - return; /* paranoia */ - if (page < 0 || page >= NUM_PAGES) - return; /* more paranoia */ - - devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK; - devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET; - - /* now write out the shadow register */ - outb(devpriv->asics[asic].pagelock, - devpriv->asics[asic].iobase + REG_PAGELOCK); -} - #ifdef notused static void lock_port(struct comedi_device *dev, int asic, int port) { @@ -829,7 +499,28 @@ static void unlock_port(struct comedi_device *dev, int asic, int port) outb(devpriv->asics[asic].pagelock, devpriv->asics[asic].iobase + REG_PAGELOCK); } -#endif /* notused */ +#endif /* notused */ + +static void pcmmio_stop_intr(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + int nports, firstport, asic, port; + + asic = subpriv->dio.intr.asic; + if (asic < 0) + return; /* not an interrupt subdev */ + + subpriv->dio.intr.enabled_mask = 0; + subpriv->dio.intr.active = 0; + s->async->inttrig = 0; + nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT; + firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT; + switch_page(dev, asic, PAGE_ENAB); + for (port = firstport; port < firstport + nports; ++port) { + /* disable all intrs for this subdev.. */ + outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port); + } +} static irqreturn_t interrupt_pcmmio(int irq, void *d) { @@ -991,27 +682,6 @@ static irqreturn_t interrupt_pcmmio(int irq, void *d) return IRQ_HANDLED; } -static void pcmmio_stop_intr(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - int nports, firstport, asic, port; - - asic = subpriv->dio.intr.asic; - if (asic < 0) - return; /* not an interrupt subdev */ - - subpriv->dio.intr.enabled_mask = 0; - subpriv->dio.intr.active = 0; - s->async->inttrig = 0; - nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT; - firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT; - switch_page(dev, asic, PAGE_ENAB); - for (port = firstport; port < firstport + nports; ++port) { - /* disable all intrs for this subdev.. */ - outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port); - } -} - static int pcmmio_start_intr(struct comedi_device *dev, struct comedi_subdevice *s) { @@ -1340,22 +1010,261 @@ static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, return n; } +static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it) +{ + struct comedi_subdevice *s; + int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic, + thisasic_chanct = 0; + unsigned long iobase; + unsigned int irq[MAX_ASICS]; + + iobase = it->options[0]; + irq[0] = it->options[1]; + + printk(KERN_INFO "comedi%d: %s: io: %lx attaching...\n", dev->minor, + dev->driver->driver_name, iobase); + + dev->iobase = iobase; + + if (!iobase || !request_region(iobase, + thisboard->total_iosize, + dev->driver->driver_name)) { + printk(KERN_ERR "comedi%d: I/O port conflict\n", dev->minor); + return -EIO; + } + +/* + * Initialize dev->board_name. Note that we can use the "thisboard" + * macro now, since we just initialized it in the last line. + */ + dev->board_name = thisboard->name; + /* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. + * Allocate the private structure area. alloc_private() is a + * convenient macro defined in comedidev.h. */ -static int __init driver_init_module(void) -{ - return comedi_driver_register(&driver); + if (alloc_private(dev, sizeof(struct pcmmio_private)) < 0) { + printk(KERN_ERR "comedi%d: cannot allocate private data structure\n", + dev->minor); + return -ENOMEM; + } + + for (asic = 0; asic < MAX_ASICS; ++asic) { + devpriv->asics[asic].num = asic; + devpriv->asics[asic].iobase = + dev->iobase + 16 + asic * ASIC_IOSIZE; + /* + * this gets actually set at the end of this function when we + * request_irqs + */ + devpriv->asics[asic].irq = 0; + spin_lock_init(&devpriv->asics[asic].spinlock); + } + + chans_left = CHANS_PER_ASIC * thisboard->dio_num_asics; + n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left); + n_subdevs = n_dio_subdevs + 2; + devpriv->sprivs = + kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private), + GFP_KERNEL); + if (!devpriv->sprivs) { + printk(KERN_ERR "comedi%d: cannot allocate subdevice private data structures\n", + dev->minor); + return -ENOMEM; + } + /* + * Allocate the subdevice structures. alloc_subdevice() is a + * convenient macro defined in comedidev.h. + * + * Allocate 1 AI + 1 AO + 2 DIO subdevs (24 lines per DIO) + */ + if (alloc_subdevices(dev, n_subdevs) < 0) { + printk(KERN_ERR "comedi%d: cannot allocate subdevice data structures\n", + dev->minor); + return -ENOMEM; + } + + /* First, AI */ + sdev_no = 0; + s = dev->subdevices + sdev_no; + s->private = devpriv->sprivs + sdev_no; + s->maxdata = (1 << thisboard->ai_bits) - 1; + s->range_table = thisboard->ai_range_table; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; + s->type = COMEDI_SUBD_AI; + s->n_chan = thisboard->n_ai_chans; + s->len_chanlist = s->n_chan; + s->insn_read = thisboard->ai_rinsn; + subpriv->iobase = dev->iobase + 0; + /* initialize the resource enable register by clearing it */ + outb(0, subpriv->iobase + 3); + outb(0, subpriv->iobase + 4 + 3); + + /* Next, AO */ + ++sdev_no; + s = dev->subdevices + sdev_no; + s->private = devpriv->sprivs + sdev_no; + s->maxdata = (1 << thisboard->ao_bits) - 1; + s->range_table = thisboard->ao_range_table; + s->subdev_flags = SDF_READABLE; + s->type = COMEDI_SUBD_AO; + s->n_chan = thisboard->n_ao_chans; + s->len_chanlist = s->n_chan; + s->insn_read = thisboard->ao_rinsn; + s->insn_write = thisboard->ao_winsn; + subpriv->iobase = dev->iobase + 8; + /* initialize the resource enable register by clearing it */ + outb(0, subpriv->iobase + 3); + outb(0, subpriv->iobase + 4 + 3); + + ++sdev_no; + port = 0; + asic = 0; + for (; sdev_no < (int)dev->n_subdevices; ++sdev_no) { + int byte_no; + + s = dev->subdevices + sdev_no; + s->private = devpriv->sprivs + sdev_no; + s->maxdata = 1; + s->range_table = &range_digital; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->type = COMEDI_SUBD_DIO; + s->insn_bits = pcmmio_dio_insn_bits; + s->insn_config = pcmmio_dio_insn_config; + s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV); + subpriv->dio.intr.asic = -1; + subpriv->dio.intr.first_chan = -1; + subpriv->dio.intr.asic_chan = -1; + subpriv->dio.intr.num_asic_chans = -1; + subpriv->dio.intr.active = 0; + s->len_chanlist = 1; + + /* save the ioport address for each 'port' of 8 channels in the + subdevice */ + for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) { + if (port >= PORTS_PER_ASIC) { + port = 0; + ++asic; + thisasic_chanct = 0; + } + subpriv->iobases[byte_no] = + devpriv->asics[asic].iobase + port; + + if (thisasic_chanct < + CHANS_PER_PORT * INTR_PORTS_PER_ASIC + && subpriv->dio.intr.asic < 0) { + /* + * this is an interrupt subdevice, + * so setup the struct + */ + subpriv->dio.intr.asic = asic; + subpriv->dio.intr.active = 0; + subpriv->dio.intr.stop_count = 0; + subpriv->dio.intr.first_chan = byte_no * 8; + subpriv->dio.intr.asic_chan = thisasic_chanct; + subpriv->dio.intr.num_asic_chans = + s->n_chan - subpriv->dio.intr.first_chan; + s->cancel = pcmmio_cancel; + s->do_cmd = pcmmio_cmd; + s->do_cmdtest = pcmmio_cmdtest; + s->len_chanlist = + subpriv->dio.intr.num_asic_chans; + } + thisasic_chanct += CHANS_PER_PORT; + } + spin_lock_init(&subpriv->dio.intr.spinlock); + + chans_left -= s->n_chan; + + if (!chans_left) { + /* + * reset the asic to our first asic, + * to do intr subdevs + */ + asic = 0; + port = 0; + } + + } + + init_asics(dev); /* clear out all the registers, basically */ + + for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) { + if (irq[asic] + && request_irq(irq[asic], interrupt_pcmmio, + IRQF_SHARED, thisboard->name, dev)) { + int i; + /* unroll the allocated irqs.. */ + for (i = asic - 1; i >= 0; --i) { + free_irq(irq[i], dev); + devpriv->asics[i].irq = irq[i] = 0; + } + irq[asic] = 0; + } + devpriv->asics[asic].irq = irq[asic]; + } + + dev->irq = irq[0]; /* + * grr.. wish comedi dev struct supported + * multiple irqs.. + */ + + if (irq[0]) { + printk(KERN_DEBUG "comedi%d: irq: %u\n", dev->minor, irq[0]); + if (thisboard->dio_num_asics == 2 && irq[1]) + printk(KERN_DEBUG "comedi%d: second ASIC irq: %u\n", + dev->minor, irq[1]); + } else { + printk(KERN_INFO "comedi%d: (IRQ mode disabled)\n", dev->minor); + } + + printk(KERN_INFO "comedi%d: attached\n", dev->minor); + + return 1; } -static void __exit driver_cleanup_module(void) +static void pcmmio_detach(struct comedi_device *dev) { - comedi_driver_unregister(&driver); + int i; + + if (dev->iobase) + release_region(dev->iobase, thisboard->total_iosize); + for (i = 0; i < MAX_ASICS; ++i) { + if (devpriv && devpriv->asics[i].irq) + free_irq(devpriv->asics[i].irq, dev); + } + if (devpriv && devpriv->sprivs) + kfree(devpriv->sprivs); } -module_init(driver_init_module); -module_exit(driver_cleanup_module); +static const struct pcmmio_board pcmmio_boards[] = { + { + .name = "pcmmio", + .dio_num_asics = 1, + .dio_num_ports = 6, + .total_iosize = 32, + .ai_bits = 16, + .ao_bits = 16, + .n_ai_chans = 16, + .n_ao_chans = 8, + .ai_range_table = &ranges_ai, + .ao_range_table = &ranges_ao, + .ai_rinsn = ai_rinsn, + .ao_rinsn = ao_rinsn, + .ao_winsn = ao_winsn + }, +}; + +static struct comedi_driver pcmmio_driver = { + .driver_name = "pcmmio", + .module = THIS_MODULE, + .attach = pcmmio_attach, + .detach = pcmmio_detach, + .board_name = &pcmmio_boards[0].name, + .offset = sizeof(struct pcmmio_board), + .num_names = ARRAY_SIZE(pcmmio_boards), +}; +module_comedi_driver(pcmmio_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/pcmuio.c b/trunk/drivers/staging/comedi/drivers/pcmuio.c index 661ba2e03892..623381d50dac 100644 --- a/trunk/drivers/staging/comedi/drivers/pcmuio.c +++ b/trunk/drivers/staging/comedi/drivers/pcmuio.c @@ -155,19 +155,6 @@ struct pcmuio_board { const int num_ports; }; -static const struct pcmuio_board pcmuio_boards[] = { - { - .name = "pcmuio48", - .num_asics = 1, - .num_ports = 6, - }, - { - .name = "pcmuio96", - .num_asics = 2, - .num_ports = 12, - }, -}; - /* * Useful for shorthand access to the particular board structure */ @@ -218,262 +205,6 @@ struct pcmuio_private { */ #define devpriv ((struct pcmuio_private *)dev->private) #define subpriv ((struct pcmuio_subdev_private *)s->private) -/* - * The struct comedi_driver structure tells the Comedi core module - * which functions to call to configure/deconfigure (attach/detach) - * the board, and also about the kernel module that contains - * the device code. - */ -static int pcmuio_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcmuio_detach(struct comedi_device *dev); - -static struct comedi_driver driver = { - .driver_name = "pcmuio", - .module = THIS_MODULE, - .attach = pcmuio_attach, - .detach = pcmuio_detach, -/* It is not necessary to implement the following members if you are - * writing a driver for a ISA PnP or PCI card */ - /* Most drivers will support multiple types of boards by - * having an array of board structures. These were defined - * in pcmuio_boards[] above. Note that the element 'name' - * was first in the structure -- Comedi uses this fact to - * extract the name of the board without knowing any details - * about the structure except for its length. - * When a device is attached (by comedi_config), the name - * of the device is given to Comedi, and Comedi tries to - * match it by going through the list of board names. If - * there is a match, the address of the pointer is put - * into dev->board_ptr and driver->attach() is called. - * - * Note that these are not necessary if you can determine - * the type of board in software. ISA PnP, PCI, and PCMCIA - * devices are such boards. - */ - .board_name = &pcmuio_boards[0].name, - .offset = sizeof(struct pcmuio_board), - .num_names = ARRAY_SIZE(pcmuio_boards), -}; - -static int pcmuio_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int pcmuio_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static irqreturn_t interrupt_pcmuio(int irq, void *d); -static void pcmuio_stop_intr(struct comedi_device *, struct comedi_subdevice *); -static int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s); -static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s); -static int pcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd); - -/* some helper functions to deal with specifics of this device's registers */ -static void init_asics(struct comedi_device *dev); /* sets up/clears ASIC chips to defaults */ -static void switch_page(struct comedi_device *dev, int asic, int page); -#ifdef notused -static void lock_port(struct comedi_device *dev, int asic, int port); -static void unlock_port(struct comedi_device *dev, int asic, int port); -#endif - -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ -static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0; - unsigned long iobase; - unsigned int irq[MAX_ASICS]; - - iobase = it->options[0]; - irq[0] = it->options[1]; - irq[1] = it->options[2]; - - dev_dbg(dev->hw_dev, "comedi%d: %s: io: %lx attached\n", dev->minor, - driver.driver_name, iobase); - - dev->iobase = iobase; - - if (!iobase || !request_region(iobase, - thisboard->num_asics * ASIC_IOSIZE, - driver.driver_name)) { - dev_err(dev->hw_dev, "I/O port conflict\n"); - return -EIO; - } - -/* - * Initialize dev->board_name. Note that we can use the "thisboard" - * macro now, since we just initialized it in the last line. - */ - dev->board_name = thisboard->name; - -/* - * Allocate the private structure area. alloc_private() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_private(dev, sizeof(struct pcmuio_private)) < 0) { - dev_warn(dev->hw_dev, "cannot allocate private data structure\n"); - return -ENOMEM; - } - - for (asic = 0; asic < MAX_ASICS; ++asic) { - devpriv->asics[asic].num = asic; - devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE; - devpriv->asics[asic].irq = 0; /* this gets actually set at the end of - this function when we - request_irqs */ - spin_lock_init(&devpriv->asics[asic].spinlock); - } - - chans_left = CHANS_PER_ASIC * thisboard->num_asics; - n_subdevs = CALC_N_SUBDEVS(chans_left); - devpriv->sprivs = - kcalloc(n_subdevs, sizeof(struct pcmuio_subdev_private), - GFP_KERNEL); - if (!devpriv->sprivs) { - dev_warn(dev->hw_dev, "cannot allocate subdevice private data structures\n"); - return -ENOMEM; - } - /* - * Allocate the subdevice structures. alloc_subdevice() is a - * convenient macro defined in comedidev.h. - * - * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the - * 96-channel version of the board. - */ - if (alloc_subdevices(dev, n_subdevs) < 0) { - dev_dbg(dev->hw_dev, "cannot allocate subdevice data structures\n"); - return -ENOMEM; - } - - port = 0; - asic = 0; - for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) { - int byte_no; - - s = dev->subdevices + sdev_no; - s->private = devpriv->sprivs + sdev_no; - s->maxdata = 1; - s->range_table = &range_digital; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->type = COMEDI_SUBD_DIO; - s->insn_bits = pcmuio_dio_insn_bits; - s->insn_config = pcmuio_dio_insn_config; - s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV); - subpriv->intr.asic = -1; - subpriv->intr.first_chan = -1; - subpriv->intr.asic_chan = -1; - subpriv->intr.num_asic_chans = -1; - subpriv->intr.active = 0; - s->len_chanlist = 1; - - /* save the ioport address for each 'port' of 8 channels in the - subdevice */ - for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) { - if (port >= PORTS_PER_ASIC) { - port = 0; - ++asic; - thisasic_chanct = 0; - } - subpriv->iobases[byte_no] = - devpriv->asics[asic].iobase + port; - - if (thisasic_chanct < - CHANS_PER_PORT * INTR_PORTS_PER_ASIC - && subpriv->intr.asic < 0) { - /* this is an interrupt subdevice, so setup the struct */ - subpriv->intr.asic = asic; - subpriv->intr.active = 0; - subpriv->intr.stop_count = 0; - subpriv->intr.first_chan = byte_no * 8; - subpriv->intr.asic_chan = thisasic_chanct; - subpriv->intr.num_asic_chans = - s->n_chan - subpriv->intr.first_chan; - dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->cancel = pcmuio_cancel; - s->do_cmd = pcmuio_cmd; - s->do_cmdtest = pcmuio_cmdtest; - s->len_chanlist = subpriv->intr.num_asic_chans; - } - thisasic_chanct += CHANS_PER_PORT; - } - spin_lock_init(&subpriv->intr.spinlock); - - chans_left -= s->n_chan; - - if (!chans_left) { - asic = 0; /* reset the asic to our first asic, to do intr subdevs */ - port = 0; - } - - } - - init_asics(dev); /* clear out all the registers, basically */ - - for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) { - if (irq[asic] - && request_irq(irq[asic], interrupt_pcmuio, - IRQF_SHARED, thisboard->name, dev)) { - int i; - /* unroll the allocated irqs.. */ - for (i = asic - 1; i >= 0; --i) { - free_irq(irq[i], dev); - devpriv->asics[i].irq = irq[i] = 0; - } - irq[asic] = 0; - } - devpriv->asics[asic].irq = irq[asic]; - } - - dev->irq = irq[0]; /* grr.. wish comedi dev struct supported multiple - irqs.. */ - - if (irq[0]) { - dev_dbg(dev->hw_dev, "irq: %u\n", irq[0]); - if (irq[1] && thisboard->num_asics == 2) - dev_dbg(dev->hw_dev, "second ASIC irq: %u\n", irq[1]); - } else { - dev_dbg(dev->hw_dev, "(IRQ mode disabled)\n"); - } - - - return 1; -} - -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int pcmuio_detach(struct comedi_device *dev) -{ - int i; - - dev_dbg(dev->hw_dev, "comedi%d: %s: remove\n", dev->minor, - driver.driver_name); - if (dev->iobase) - release_region(dev->iobase, ASIC_IOSIZE * thisboard->num_asics); - - for (i = 0; i < MAX_ASICS; ++i) { - if (devpriv->asics[i].irq) - free_irq(devpriv->asics[i].irq, dev); - } - - if (devpriv && devpriv->sprivs) - kfree(devpriv->sprivs); - - return 0; -} /* DIO devices are slightly special. Although it is possible to * implement the insn_read/insn_write interface, it is much more @@ -621,6 +352,21 @@ static int pcmuio_dio_insn_config(struct comedi_device *dev, return insn->n; } +static void switch_page(struct comedi_device *dev, int asic, int page) +{ + if (asic < 0 || asic >= thisboard->num_asics) + return; /* paranoia */ + if (page < 0 || page >= NUM_PAGES) + return; /* more paranoia */ + + devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK; + devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET; + + /* now write out the shadow register */ + outb(devpriv->asics[asic].pagelock, + dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK); +} + static void init_asics(struct comedi_device *dev) { /* sets up an ASIC chip to defaults */ @@ -658,21 +404,6 @@ static void init_asics(struct comedi_device *dev) } } -static void switch_page(struct comedi_device *dev, int asic, int page) -{ - if (asic < 0 || asic >= thisboard->num_asics) - return; /* paranoia */ - if (page < 0 || page >= NUM_PAGES) - return; /* more paranoia */ - - devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK; - devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET; - - /* now write out the shadow register */ - outb(devpriv->asics[asic].pagelock, - dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK); -} - #ifdef notused static void lock_port(struct comedi_device *dev, int asic, int port) { @@ -700,6 +431,27 @@ static void unlock_port(struct comedi_device *dev, int asic, int port) } #endif /* notused */ +static void pcmuio_stop_intr(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + int nports, firstport, asic, port; + + asic = subpriv->intr.asic; + if (asic < 0) + return; /* not an interrupt subdev */ + + subpriv->intr.enabled_mask = 0; + subpriv->intr.active = 0; + s->async->inttrig = 0; + nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT; + firstport = subpriv->intr.asic_chan / CHANS_PER_PORT; + switch_page(dev, asic, PAGE_ENAB); + for (port = firstport; port < firstport + nports; ++port) { + /* disable all intrs for this subdev.. */ + outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port); + } +} + static irqreturn_t interrupt_pcmuio(int irq, void *d) { int asic, got1 = 0; @@ -852,27 +604,6 @@ static irqreturn_t interrupt_pcmuio(int irq, void *d) return IRQ_HANDLED; } -static void pcmuio_stop_intr(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - int nports, firstport, asic, port; - - asic = subpriv->intr.asic; - if (asic < 0) - return; /* not an interrupt subdev */ - - subpriv->intr.enabled_mask = 0; - subpriv->intr.active = 0; - s->async->inttrig = 0; - nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT; - firstport = subpriv->intr.asic_chan / CHANS_PER_PORT; - switch_page(dev, asic, PAGE_ENAB); - for (port = firstport; port < firstport + nports; ++port) { - /* disable all intrs for this subdev.. */ - outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port); - } -} - static int pcmuio_start_intr(struct comedi_device *dev, struct comedi_subdevice *s) { @@ -1014,22 +745,205 @@ pcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, return comedi_pcm_cmdtest(dev, s, cmd); } +static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it) +{ + struct comedi_subdevice *s; + int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0; + unsigned long iobase; + unsigned int irq[MAX_ASICS]; + + iobase = it->options[0]; + irq[0] = it->options[1]; + irq[1] = it->options[2]; + + dev_dbg(dev->hw_dev, "comedi%d: %s: io: %lx attached\n", dev->minor, + dev->driver->driver_name, iobase); + + dev->iobase = iobase; + + if (!iobase || !request_region(iobase, + thisboard->num_asics * ASIC_IOSIZE, + dev->driver->driver_name)) { + dev_err(dev->hw_dev, "I/O port conflict\n"); + return -EIO; + } + /* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. + * Initialize dev->board_name. Note that we can use the "thisboard" + * macro now, since we just initialized it in the last line. */ -static int __init driver_init_module(void) -{ - return comedi_driver_register(&driver); + dev->board_name = thisboard->name; + +/* + * Allocate the private structure area. alloc_private() is a + * convenient macro defined in comedidev.h. + */ + if (alloc_private(dev, sizeof(struct pcmuio_private)) < 0) { + dev_warn(dev->hw_dev, "cannot allocate private data structure\n"); + return -ENOMEM; + } + + for (asic = 0; asic < MAX_ASICS; ++asic) { + devpriv->asics[asic].num = asic; + devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE; + devpriv->asics[asic].irq = 0; /* this gets actually set at the end of + this function when we + request_irqs */ + spin_lock_init(&devpriv->asics[asic].spinlock); + } + + chans_left = CHANS_PER_ASIC * thisboard->num_asics; + n_subdevs = CALC_N_SUBDEVS(chans_left); + devpriv->sprivs = + kcalloc(n_subdevs, sizeof(struct pcmuio_subdev_private), + GFP_KERNEL); + if (!devpriv->sprivs) { + dev_warn(dev->hw_dev, "cannot allocate subdevice private data structures\n"); + return -ENOMEM; + } + /* + * Allocate the subdevice structures. alloc_subdevice() is a + * convenient macro defined in comedidev.h. + * + * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the + * 96-channel version of the board. + */ + if (alloc_subdevices(dev, n_subdevs) < 0) { + dev_dbg(dev->hw_dev, "cannot allocate subdevice data structures\n"); + return -ENOMEM; + } + + port = 0; + asic = 0; + for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) { + int byte_no; + + s = dev->subdevices + sdev_no; + s->private = devpriv->sprivs + sdev_no; + s->maxdata = 1; + s->range_table = &range_digital; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->type = COMEDI_SUBD_DIO; + s->insn_bits = pcmuio_dio_insn_bits; + s->insn_config = pcmuio_dio_insn_config; + s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV); + subpriv->intr.asic = -1; + subpriv->intr.first_chan = -1; + subpriv->intr.asic_chan = -1; + subpriv->intr.num_asic_chans = -1; + subpriv->intr.active = 0; + s->len_chanlist = 1; + + /* save the ioport address for each 'port' of 8 channels in the + subdevice */ + for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) { + if (port >= PORTS_PER_ASIC) { + port = 0; + ++asic; + thisasic_chanct = 0; + } + subpriv->iobases[byte_no] = + devpriv->asics[asic].iobase + port; + + if (thisasic_chanct < + CHANS_PER_PORT * INTR_PORTS_PER_ASIC + && subpriv->intr.asic < 0) { + /* this is an interrupt subdevice, so setup the struct */ + subpriv->intr.asic = asic; + subpriv->intr.active = 0; + subpriv->intr.stop_count = 0; + subpriv->intr.first_chan = byte_no * 8; + subpriv->intr.asic_chan = thisasic_chanct; + subpriv->intr.num_asic_chans = + s->n_chan - subpriv->intr.first_chan; + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->cancel = pcmuio_cancel; + s->do_cmd = pcmuio_cmd; + s->do_cmdtest = pcmuio_cmdtest; + s->len_chanlist = subpriv->intr.num_asic_chans; + } + thisasic_chanct += CHANS_PER_PORT; + } + spin_lock_init(&subpriv->intr.spinlock); + + chans_left -= s->n_chan; + + if (!chans_left) { + asic = 0; /* reset the asic to our first asic, to do intr subdevs */ + port = 0; + } + + } + + init_asics(dev); /* clear out all the registers, basically */ + + for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) { + if (irq[asic] + && request_irq(irq[asic], interrupt_pcmuio, + IRQF_SHARED, thisboard->name, dev)) { + int i; + /* unroll the allocated irqs.. */ + for (i = asic - 1; i >= 0; --i) { + free_irq(irq[i], dev); + devpriv->asics[i].irq = irq[i] = 0; + } + irq[asic] = 0; + } + devpriv->asics[asic].irq = irq[asic]; + } + + dev->irq = irq[0]; /* grr.. wish comedi dev struct supported multiple + irqs.. */ + + if (irq[0]) { + dev_dbg(dev->hw_dev, "irq: %u\n", irq[0]); + if (irq[1] && thisboard->num_asics == 2) + dev_dbg(dev->hw_dev, "second ASIC irq: %u\n", irq[1]); + } else { + dev_dbg(dev->hw_dev, "(IRQ mode disabled)\n"); + } + + + return 1; } -static void __exit driver_cleanup_module(void) +static void pcmuio_detach(struct comedi_device *dev) { - comedi_driver_unregister(&driver); + int i; + + if (dev->iobase) + release_region(dev->iobase, ASIC_IOSIZE * thisboard->num_asics); + for (i = 0; i < MAX_ASICS; ++i) { + if (devpriv->asics[i].irq) + free_irq(devpriv->asics[i].irq, dev); + } + if (devpriv && devpriv->sprivs) + kfree(devpriv->sprivs); } -module_init(driver_init_module); -module_exit(driver_cleanup_module); +static const struct pcmuio_board pcmuio_boards[] = { + { + .name = "pcmuio48", + .num_asics = 1, + .num_ports = 6, + }, { + .name = "pcmuio96", + .num_asics = 2, + .num_ports = 12, + }, +}; + +static struct comedi_driver pcmuio_driver = { + .driver_name = "pcmuio", + .module = THIS_MODULE, + .attach = pcmuio_attach, + .detach = pcmuio_detach, + .board_name = &pcmuio_boards[0].name, + .offset = sizeof(struct pcmuio_board), + .num_names = ARRAY_SIZE(pcmuio_boards), +}; +module_comedi_driver(pcmuio_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/poc.c b/trunk/drivers/staging/comedi/drivers/poc.c index 831a576c24aa..e7120480687b 100644 --- a/trunk/drivers/staging/comedi/drivers/poc.c +++ b/trunk/drivers/staging/comedi/drivers/poc.c @@ -41,20 +41,6 @@ Configuration options: #include -static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int poc_detach(struct comedi_device *dev); -static int readback_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static int dac02_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int pcl733_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int pcl734_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - struct boarddef_struct { const char *name; unsigned int iosize; @@ -70,108 +56,9 @@ struct boarddef_struct { struct comedi_insn *, unsigned int *); const struct comedi_lrange *range; }; -static const struct boarddef_struct boards[] = { - { - .name = "dac02", - .iosize = 8, - /* .setup = dac02_setup, */ - .type = COMEDI_SUBD_AO, - .n_chan = 2, - .n_bits = 12, - .winsn = dac02_ao_winsn, - .rinsn = readback_insn, - .range = &range_unknown, - }, - { - .name = "pcl733", - .iosize = 4, - .type = COMEDI_SUBD_DI, - .n_chan = 32, - .n_bits = 1, - .insnbits = pcl733_insn_bits, - .range = &range_digital, - }, - { - .name = "pcl734", - .iosize = 4, - .type = COMEDI_SUBD_DO, - .n_chan = 32, - .n_bits = 1, - .insnbits = pcl734_insn_bits, - .range = &range_digital, - }, -}; -#define n_boards ARRAY_SIZE(boards) #define this_board ((const struct boarddef_struct *)dev->board_ptr) -static struct comedi_driver driver_poc = { - .driver_name = "poc", - .module = THIS_MODULE, - .attach = poc_attach, - .detach = poc_detach, - .board_name = &boards[0].name, - .num_names = n_boards, - .offset = sizeof(boards[0]), -}; - -static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - unsigned long iobase; - unsigned int iosize; - - iobase = it->options[0]; - printk(KERN_INFO "comedi%d: poc: using %s iobase 0x%lx\n", dev->minor, - this_board->name, iobase); - - dev->board_name = this_board->name; - - if (iobase == 0) { - printk(KERN_ERR "io base address required\n"); - return -EINVAL; - } - - iosize = this_board->iosize; - /* check if io addresses are available */ - if (!request_region(iobase, iosize, "dac02")) { - printk(KERN_ERR "I/O port conflict: failed to allocate ports " - "0x%lx to 0x%lx\n", iobase, iobase + iosize - 1); - return -EIO; - } - dev->iobase = iobase; - - if (alloc_subdevices(dev, 1) < 0) - return -ENOMEM; - if (alloc_private(dev, sizeof(unsigned int) * this_board->n_chan) < 0) - return -ENOMEM; - - /* analog output subdevice */ - s = dev->subdevices + 0; - s->type = this_board->type; - s->n_chan = this_board->n_chan; - s->maxdata = (1 << this_board->n_bits) - 1; - s->range_table = this_board->range; - s->insn_write = this_board->winsn; - s->insn_read = this_board->rinsn; - s->insn_bits = this_board->insnbits; - if (s->type == COMEDI_SUBD_AO || s->type == COMEDI_SUBD_DO) - s->subdev_flags = SDF_WRITABLE; - - return 0; -} - -static int poc_detach(struct comedi_device *dev) -{ - /* only free stuff if it has been allocated by _attach */ - if (dev->iobase) - release_region(dev->iobase, this_board->iosize); - - printk(KERN_INFO "comedi%d: dac02: remove\n", dev->minor); - - return 0; -} - static int readback_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { @@ -248,18 +135,98 @@ static int pcl734_insn_bits(struct comedi_device *dev, return 2; } -static int __init driver_poc_init_module(void) +static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - return comedi_driver_register(&driver_poc); + struct comedi_subdevice *s; + unsigned long iobase; + unsigned int iosize; + + iobase = it->options[0]; + printk(KERN_INFO "comedi%d: poc: using %s iobase 0x%lx\n", dev->minor, + this_board->name, iobase); + + dev->board_name = this_board->name; + + if (iobase == 0) { + printk(KERN_ERR "io base address required\n"); + return -EINVAL; + } + + iosize = this_board->iosize; + /* check if io addresses are available */ + if (!request_region(iobase, iosize, "dac02")) { + printk(KERN_ERR "I/O port conflict: failed to allocate ports " + "0x%lx to 0x%lx\n", iobase, iobase + iosize - 1); + return -EIO; + } + dev->iobase = iobase; + + if (alloc_subdevices(dev, 1) < 0) + return -ENOMEM; + if (alloc_private(dev, sizeof(unsigned int) * this_board->n_chan) < 0) + return -ENOMEM; + + /* analog output subdevice */ + s = dev->subdevices + 0; + s->type = this_board->type; + s->n_chan = this_board->n_chan; + s->maxdata = (1 << this_board->n_bits) - 1; + s->range_table = this_board->range; + s->insn_write = this_board->winsn; + s->insn_read = this_board->rinsn; + s->insn_bits = this_board->insnbits; + if (s->type == COMEDI_SUBD_AO || s->type == COMEDI_SUBD_DO) + s->subdev_flags = SDF_WRITABLE; + + return 0; } -static void __exit driver_poc_cleanup_module(void) +static void poc_detach(struct comedi_device *dev) { - comedi_driver_unregister(&driver_poc); + if (dev->iobase) + release_region(dev->iobase, this_board->iosize); } -module_init(driver_poc_init_module); -module_exit(driver_poc_cleanup_module); +static const struct boarddef_struct boards[] = { + { + .name = "dac02", + .iosize = 8, + /* .setup = dac02_setup, */ + .type = COMEDI_SUBD_AO, + .n_chan = 2, + .n_bits = 12, + .winsn = dac02_ao_winsn, + .rinsn = readback_insn, + .range = &range_unknown, + }, { + .name = "pcl733", + .iosize = 4, + .type = COMEDI_SUBD_DI, + .n_chan = 32, + .n_bits = 1, + .insnbits = pcl733_insn_bits, + .range = &range_digital, + }, { + .name = "pcl734", + .iosize = 4, + .type = COMEDI_SUBD_DO, + .n_chan = 32, + .n_bits = 1, + .insnbits = pcl734_insn_bits, + .range = &range_digital, + }, +}; + +static struct comedi_driver poc_driver = { + .driver_name = "poc", + .module = THIS_MODULE, + .attach = poc_attach, + .detach = poc_detach, + .board_name = &boards[0].name, + .num_names = ARRAY_SIZE(boards), + .offset = sizeof(boards[0]), +}; +module_comedi_driver(poc_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/trunk/drivers/staging/comedi/drivers/quatech_daqp_cs.c index e0bb73445dd8..2f130b3095e9 100644 --- a/trunk/drivers/staging/comedi/drivers/quatech_daqp_cs.c +++ b/trunk/drivers/staging/comedi/drivers/quatech_daqp_cs.c @@ -181,7 +181,7 @@ static const struct comedi_lrange range_daqp_ao = { 1, {BIP_RANGE(5)} }; /* comedi interface code */ static int daqp_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int daqp_detach(struct comedi_device *dev); +static void daqp_detach(struct comedi_device *dev); static struct comedi_driver driver_daqp = { .driver_name = "quatech_daqp_cs", .module = THIS_MODULE, @@ -922,15 +922,9 @@ static int daqp_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 1; } -/* daqp_detach (called from comedi_comdig) does nothing. If the PCMCIA - * card is removed, daqp_cs_detach() is called by the pcmcia subsystem. - */ - -static int daqp_detach(struct comedi_device *dev) +static void daqp_detach(struct comedi_device *dev) { - printk(KERN_INFO "comedi%d: detaching daqp\n", dev->minor); - - return 0; + /* Nothing to cleanup */ } /*==================================================================== @@ -1010,8 +1004,6 @@ static void daqp_cs_detach(struct pcmcia_device *link) { struct local_info_t *dev = link->priv; - dev_dbg(&link->dev, "daqp_cs_detach\n"); - dev->stop = 1; daqp_cs_release(link); @@ -1019,7 +1011,7 @@ static void daqp_cs_detach(struct pcmcia_device *link) dev_table[dev->table_index] = NULL; kfree(dev); -} /* daqp_cs_detach */ +} static int daqp_pcmcia_config_loop(struct pcmcia_device *p_dev, void *priv_data) { diff --git a/trunk/drivers/staging/comedi/drivers/rtd520.c b/trunk/drivers/staging/comedi/drivers/rtd520.c index 138441960506..1678a0ccb8c1 100644 --- a/trunk/drivers/staging/comedi/drivers/rtd520.c +++ b/trunk/drivers/staging/comedi/drivers/rtd520.c @@ -328,14 +328,6 @@ static const struct rtdBoard rtd520Boards[] = { }, }; -static DEFINE_PCI_DEVICE_TABLE(rtd520_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_RTD, 0x7520) }, - { PCI_DEVICE(PCI_VENDOR_ID_RTD, 0x4520) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, rtd520_pci_table); - /* * Useful for shorthand access to the particular board structure */ @@ -347,13 +339,13 @@ MODULE_DEVICE_TABLE(pci, rtd520_pci_table); */ struct rtdPrivate { /* memory mapped board structures */ - void *las0; - void *las1; - void *lcfg; + void __iomem *las0; + void __iomem *las1; + void __iomem *lcfg; unsigned long intCount; /* interrupt count */ long aiCount; /* total transfer size (samples) */ - int transCount; /* # to tranfer data. 0->1/2FIFO */ + int transCount; /* # to transfer data. 0->1/2FIFO */ int flags; /* flag event modes */ /* PCI device info */ @@ -377,8 +369,11 @@ struct rtdPrivate { u8 utcCtrl[4]; /* crtl mode for 3 utc + read back */ u8 dioStatus; /* could be read back (dio0Ctrl) */ #ifdef USE_DMA - /* Always DMA 1/2 FIFO. Buffer (dmaBuff?) is (at least) twice that size. - After transferring, interrupt processes 1/2 FIFO and passes to comedi */ + /* + * Always DMA 1/2 FIFO. Buffer (dmaBuff?) is (at least) twice that + * size. After transferring, interrupt processes 1/2 FIFO and + * passes to comedi + */ s16 dma0Offset; /* current processing offset (0, 1/2) */ uint16_t *dma0Buff[DMA_CHAIN_COUNT]; /* DMA buffers (for ADC) */ dma_addr_t dma0BuffPhysAddr[DMA_CHAIN_COUNT]; /* physical addresses */ @@ -581,7 +576,8 @@ struct rtdPrivate { /* User output N source select (write only) */ #define RtdUsrOutSource(dev, n, v) \ - writel(v, devpriv->las0+((n <= 0) ? LAS0_UOUT0_SELECT : LAS0_UOUT1_SELECT)) + writel(v, devpriv->las0+((n <= 0) ? LAS0_UOUT0_SELECT : \ + LAS0_UOUT1_SELECT)) /* Digital IO */ #define RtdDio0Read(dev) \ @@ -608,7 +604,8 @@ struct rtdPrivate { /* Write one data value (sign + 12bit + marker bits) */ /* Note: matches what DMA would put. Actual value << 3 */ #define RtdDacFifoPut(dev, n, v) \ - writew((v), devpriv->las1 + (((n) == 0) ? LAS1_DAC1_FIFO : LAS1_DAC2_FIFO)) + writew((v), devpriv->las1 + (((n) == 0) ? LAS1_DAC1_FIFO : \ + LAS1_DAC2_FIFO)) /* Start single DAC conversion */ #define RtdDacUpdate(dev, n) \ @@ -625,7 +622,8 @@ struct rtdPrivate { /* Reset DAC FIFO */ #define RtdDacClearFifo(dev, n) \ - writel(0, devpriv->las0+(((n) == 0) ? LAS0_DAC1_RESET : LAS0_DAC2_RESET)) + writel(0, devpriv->las0+(((n) == 0) ? LAS0_DAC1_RESET : \ + LAS0_DAC2_RESET)) /* Set source for DMA 0 (write only, shadow?) */ #define RtdDma0Source(dev, n) \ @@ -705,22 +703,6 @@ struct rtdPrivate { #define RtdDma1Status(dev) \ readb(devpriv->lcfg+LCFG_DMACSR1) -/* - * The struct comedi_driver structure tells the Comedi core module - * which functions to call to configure/deconfigure (attac/detach) - * the board, and also about the kernel module that contains - * the device code. - */ -static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int rtd_detach(struct comedi_device *dev); - -static struct comedi_driver rtd520Driver = { - .driver_name = DRV_NAME, - .module = THIS_MODULE, - .attach = rtd_attach, - .detach = rtd_detach, -}; - static int rtd_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); static int rtd_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, @@ -737,7 +719,10 @@ static int rtd_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd); static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s); static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s); -/* static int rtd_ai_poll (struct comedi_device *dev,struct comedi_subdevice *s); */ +/* + * static int rtd_ai_poll(struct comedi_device *dev, + * struct comedi_subdevice *s); + */ static int rtd_ns_to_timer(unsigned int *ns, int roundMode); static irqreturn_t rtd_interrupt(int irq, void *d); static int rtd520_probe_fifo_depth(struct comedi_device *dev); @@ -857,7 +842,9 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it) DPRINTK("rtd520: PCI latency = %d\n", pci_latency); } - /* Undocumented EPLD version (doesn't match RTD driver results) */ + /* + * Undocumented EPLD version (doesn't match RTD driver results) + */ /*DPRINTK ("rtd520: Reading epld from %p\n", devpriv->las0+0); epld_version = readl (devpriv->las0+0); @@ -970,9 +957,11 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it) #ifdef USE_DMA if (dev->irq > 0) { printk("( DMA buff=%d )\n", DMA_CHAIN_COUNT); - /* The PLX9080 has 2 DMA controllers, but there could be 4 sources: - ADC, digital, DAC1, and DAC2. Since only the ADC supports cmd mode - right now, this isn't an issue (yet) */ + /* + * The PLX9080 has 2 DMA controllers, but there could be + * 4 sources: ADC, digital, DAC1, and DAC2. Since only the + * ADC supports cmd mode right now, this isn't an issue (yet) + */ devpriv->dma0Offset = 0; for (index = 0; index < DMA_CHAIN_COUNT; index++) { @@ -988,10 +977,14 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it) } /*DPRINTK ("buff[%d] @ %p virtual, %x PCI\n", index, - devpriv->dma0Buff[index], devpriv->dma0BuffPhysAddr[index]); */ + devpriv->dma0Buff[index], + devpriv->dma0BuffPhysAddr[index]); */ } - /* setup DMA descriptor ring (use cpu_to_le32 for byte ordering?) */ + /* + * setup DMA descriptor ring (use cpu_to_le32 for byte + * ordering?) + */ devpriv->dma0Chain = pci_alloc_consistent(devpriv->pci_dev, sizeof(struct plx_dma_desc) * @@ -1088,30 +1081,12 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it) #endif } -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int rtd_detach(struct comedi_device *dev) +static void rtd_detach(struct comedi_device *dev) { #ifdef USE_DMA int index; #endif - DPRINTK("comedi%d: rtd520: removing (%ld ints)\n", - dev->minor, (devpriv ? devpriv->intCount : 0L)); - if (devpriv && devpriv->lcfg) { - DPRINTK - ("(int status 0x%x, overrun status 0x%x, fifo status 0x%x)...\n", - 0xffff & RtdInterruptStatus(dev), - 0xffff & RtdInterruptOverrunStatus(dev), - (0xffff & RtdFifoStatus(dev)) ^ 0x6666); - } - if (devpriv) { /* Shut down any board ops by resetting it */ #ifdef USE_DMA @@ -1148,37 +1123,24 @@ static int rtd_detach(struct comedi_device *dev) devpriv->dma0Chain = NULL; } #endif /* USE_DMA */ - - /* release IRQ */ if (dev->irq) { - /* disable interrupt controller */ RtdPlxInterruptWrite(dev, RtdPlxInterruptRead(dev) & ~(ICS_PLIE | ICS_DMA0_E | ICS_DMA1_E)); free_irq(dev->irq, dev); } - - /* release all regions that were allocated */ if (devpriv->las0) iounmap(devpriv->las0); - if (devpriv->las1) iounmap(devpriv->las1); - if (devpriv->lcfg) iounmap(devpriv->lcfg); - if (devpriv->pci_dev) { if (devpriv->got_regions) comedi_pci_disable(devpriv->pci_dev); - pci_dev_put(devpriv->pci_dev); } } - - printk(KERN_INFO "comedi%d: rtd520: removed.\n", dev->minor); - - return 0; } /* @@ -1278,7 +1240,8 @@ static int rtd520_probe_fifo_depth(struct comedi_device *dev) } } if (i == limit) { - printk(KERN_INFO "\ncomedi: %s: failed to probe fifo size.\n", DRV_NAME); + printk(KERN_INFO "\ncomedi: %s: failed to probe fifo size.\n", + DRV_NAME); return -EIO; } RtdAdcClearFifo(dev); @@ -1378,9 +1341,10 @@ static int ai_read_n(struct comedi_device *dev, struct comedi_subdevice *s, d = RtdAdcFifoGet(dev); /* get 2s comp value */ d = d >> 3; /* low 3 bits are marker lines */ - if (CHAN_ARRAY_TEST(devpriv->chanBipolar, s->async->cur_chan)) - sample = d + 2048; /* convert to comedi unsigned data */ - else + if (CHAN_ARRAY_TEST(devpriv->chanBipolar, s->async->cur_chan)) { + /* convert to comedi unsigned data */ + sample = d + 2048; + } else sample = d; if (!comedi_buf_put(s->async, sample)) @@ -1406,9 +1370,10 @@ static int ai_read_dregs(struct comedi_device *dev, struct comedi_subdevice *s) } d = d >> 3; /* low 3 bits are marker lines */ - if (CHAN_ARRAY_TEST(devpriv->chanBipolar, s->async->cur_chan)) - sample = d + 2048; /* convert to comedi unsigned data */ - else + if (CHAN_ARRAY_TEST(devpriv->chanBipolar, s->async->cur_chan)) { + /* convert to comedi unsigned data */ + sample = d + 2048; + } else sample = d; if (!comedi_buf_put(s->async, sample)) @@ -1525,7 +1490,9 @@ static int ai_process_dma(struct comedi_device *dev, struct comedi_subdevice *s) comedi_buf_memcpy_to(s->async, 0, dp, n); comedi_buf_write_free(s->async, n); - /* always at least 1 scan -- 1/2 FIFO is larger than our max scan list */ + /* + * always at least 1 scan -- 1/2 FIFO is larger than our max scan list + */ s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; if (++devpriv->dma0Offset >= DMA_CHAIN_COUNT) { /* next buffer */ @@ -1989,7 +1956,7 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) (TRANS_TARGET_PERIOD * cmd->chanlist_len) / cmd->scan_begin_arg; if (devpriv->transCount < cmd->chanlist_len) { - /* tranfer after each scan (and avoid 0) */ + /* transfer after each scan (and avoid 0) */ devpriv->transCount = cmd->chanlist_len; } else { /* make a multiple of scan length */ devpriv->transCount = @@ -2005,12 +1972,12 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->transCount = 0; devpriv->flags &= ~SEND_EOS; } else { - /* interrupt for each tranfer */ + /* interrupt for each transfer */ RtdAboutCounter(dev, devpriv->transCount - 1); } DPRINTK - ("rtd520: scanLen=%d tranferCount=%d fifoLen=%d\n scanTime(ns)=%d flags=0x%x\n", + ("rtd520: scanLen=%d transferCount=%d fifoLen=%d\n scanTime(ns)=%d flags=0x%x\n", cmd->chanlist_len, devpriv->transCount, devpriv->fifoLen, cmd->scan_begin_arg, devpriv->flags); } else { /* unknown timing, just use 1/2 FIFO */ @@ -2348,47 +2315,38 @@ static int rtd_dio_insn_config(struct comedi_device *dev, return 1; } -/* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. - */ -static int __devinit rtd520Driver_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) +static struct comedi_driver rtd520_driver = { + .driver_name = "rtd520", + .module = THIS_MODULE, + .attach = rtd_attach, + .detach = rtd_detach, +}; + +static int __devinit rtd520_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, rtd520Driver.driver_name); + return comedi_pci_auto_config(dev, &rtd520_driver); } -static void __devexit rtd520Driver_pci_remove(struct pci_dev *dev) +static void __devexit rtd520_pci_remove(struct pci_dev *dev) { comedi_pci_auto_unconfig(dev); } -static struct pci_driver rtd520Driver_pci_driver = { - .id_table = rtd520_pci_table, - .probe = &rtd520Driver_pci_probe, - .remove = __devexit_p(&rtd520Driver_pci_remove) +static DEFINE_PCI_DEVICE_TABLE(rtd520_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_RTD, 0x7520) }, + { PCI_DEVICE(PCI_VENDOR_ID_RTD, 0x4520) }, + { 0 } }; +MODULE_DEVICE_TABLE(pci, rtd520_pci_table); -static int __init rtd520Driver_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&rtd520Driver); - if (retval < 0) - return retval; - - rtd520Driver_pci_driver.name = (char *)rtd520Driver.driver_name; - return pci_register_driver(&rtd520Driver_pci_driver); -} - -static void __exit rtd520Driver_cleanup_module(void) -{ - pci_unregister_driver(&rtd520Driver_pci_driver); - comedi_driver_unregister(&rtd520Driver); -} - -module_init(rtd520Driver_init_module); -module_exit(rtd520Driver_cleanup_module); +static struct pci_driver rtd520_pci_driver = { + .name = "rtd520", + .id_table = rtd520_pci_table, + .probe = rtd520_pci_probe, + .remove = __devexit_p(rtd520_pci_remove), +}; +module_comedi_pci_driver(rtd520_driver, rtd520_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/rti800.c b/trunk/drivers/staging/comedi/drivers/rti800.c index 72042b818310..f0eb52a77881 100644 --- a/trunk/drivers/staging/comedi/drivers/rti800.c +++ b/trunk/drivers/staging/comedi/drivers/rti800.c @@ -138,39 +138,8 @@ struct rti800_board { int has_ao; }; -static const struct rti800_board boardtypes[] = { - {"rti800", 0}, - {"rti815", 1}, -}; - #define this_board ((const struct rti800_board *)dev->board_ptr) -static int rti800_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int rti800_detach(struct comedi_device *dev); -static struct comedi_driver driver_rti800 = { - .driver_name = "rti800", - .module = THIS_MODULE, - .attach = rti800_attach, - .detach = rti800_detach, - .num_names = ARRAY_SIZE(boardtypes), - .board_name = &boardtypes[0].name, - .offset = sizeof(struct rti800_board), -}; - -static int __init driver_rti800_init_module(void) -{ - return comedi_driver_register(&driver_rti800); -} - -static void __exit driver_rti800_cleanup_module(void) -{ - comedi_driver_unregister(&driver_rti800); -} - -module_init(driver_rti800_init_module); -module_exit(driver_rti800_cleanup_module); - static irqreturn_t rti800_interrupt(int irq, void *dev); struct rti800_private { @@ -474,19 +443,30 @@ static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -static int rti800_detach(struct comedi_device *dev) +static void rti800_detach(struct comedi_device *dev) { - printk(KERN_INFO "comedi%d: rti800: remove\n", dev->minor); - if (dev->iobase) release_region(dev->iobase, RTI800_SIZE); - if (dev->irq) free_irq(dev->irq, dev); - - return 0; } +static const struct rti800_board boardtypes[] = { + { "rti800", 0 }, + { "rti815", 1 }, +}; + +static struct comedi_driver rti800_driver = { + .driver_name = "rti800", + .module = THIS_MODULE, + .attach = rti800_attach, + .detach = rti800_detach, + .num_names = ARRAY_SIZE(boardtypes), + .board_name = &boardtypes[0].name, + .offset = sizeof(struct rti800_board), +}; +module_comedi_driver(rti800_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/rti802.c b/trunk/drivers/staging/comedi/drivers/rti802.c index f59cb11590f6..09da5c21858c 100644 --- a/trunk/drivers/staging/comedi/drivers/rti802.c +++ b/trunk/drivers/staging/comedi/drivers/rti802.c @@ -47,29 +47,6 @@ Configuration Options: #define RTI802_DATALOW 1 #define RTI802_DATAHIGH 2 -static int rti802_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int rti802_detach(struct comedi_device *dev); -static struct comedi_driver driver_rti802 = { - .driver_name = "rti802", - .module = THIS_MODULE, - .attach = rti802_attach, - .detach = rti802_detach, -}; - -static int __init driver_rti802_init_module(void) -{ - return comedi_driver_register(&driver_rti802); -} - -static void __exit driver_rti802_cleanup_module(void) -{ - comedi_driver_unregister(&driver_rti802); -} - -module_init(driver_rti802_init_module); -module_exit(driver_rti802_cleanup_module); - struct rti802_private { enum { dac_2comp, dac_straight @@ -152,16 +129,20 @@ static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -static int rti802_detach(struct comedi_device *dev) +static void rti802_detach(struct comedi_device *dev) { - printk(KERN_INFO "comedi%d: rti802: remove\n", dev->minor); - if (dev->iobase) release_region(dev->iobase, RTI802_SIZE); - - return 0; } +static struct comedi_driver rti802_driver = { + .driver_name = "rti802", + .module = THIS_MODULE, + .attach = rti802_attach, + .detach = rti802_detach, +}; +module_comedi_driver(rti802_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/s526.c b/trunk/drivers/staging/comedi/drivers/s526.c index 2b34daedc3d7..7a56434eb224 100644 --- a/trunk/drivers/staging/comedi/drivers/s526.c +++ b/trunk/drivers/staging/comedi/drivers/s526.c @@ -230,287 +230,6 @@ struct s526_private { */ #define devpriv ((struct s526_private *)dev->private) -/* - * The struct comedi_driver structure tells the Comedi core module - * which functions to call to configure/deconfigure (attach/detach) - * the board, and also about the kernel module that contains - * the device code. - */ -static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int s526_detach(struct comedi_device *dev); -static struct comedi_driver driver_s526 = { - .driver_name = "s526", - .module = THIS_MODULE, - .attach = s526_attach, - .detach = s526_detach, -/* It is not necessary to implement the following members if you are - * writing a driver for a ISA PnP or PCI card */ - /* Most drivers will support multiple types of boards by - * having an array of board structures. These were defined - * in s526_boards[] above. Note that the element 'name' - * was first in the structure -- Comedi uses this fact to - * extract the name of the board without knowing any details - * about the structure except for its length. - * When a device is attached (by comedi_config), the name - * of the device is given to Comedi, and Comedi tries to - * match it by going through the list of board names. If - * there is a match, the address of the pointer is put - * into dev->board_ptr and driver->attach() is called. - * - * Note that these are not necessary if you can determine - * the type of board in software. ISA PnP, PCI, and PCMCIA - * devices are such boards. - */ - .board_name = &s526_boards[0].name, - .offset = sizeof(struct s526_board), - .num_names = ARRAY_SIZE(s526_boards), -}; - -static int s526_gpct_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); -static int s526_gpct_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int s526_gpct_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); -static int s526_ai_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int s526_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int s526_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int s526_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int s526_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ -static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - int iobase; - int i, n; -/* short value; */ -/* int subdev_channel = 0; */ - union cmReg cmReg; - - printk(KERN_INFO "comedi%d: s526: ", dev->minor); - - iobase = it->options[0]; - if (!iobase || !request_region(iobase, S526_IOSIZE, thisboard->name)) { - comedi_error(dev, "I/O port conflict"); - return -EIO; - } - dev->iobase = iobase; - - printk("iobase=0x%lx\n", dev->iobase); - - /*** make it a little quieter, exw, 8/29/06 - for (i = 0; i < S526_NUM_PORTS; i++) { - printk("0x%02x: 0x%04x\n", ADDR_REG(s526_ports[i]), - inw(ADDR_REG(s526_ports[i]))); - } - ***/ - -/* - * Initialize dev->board_name. Note that we can use the "thisboard" - * macro now, since we just initialized it in the last line. - */ - dev->board_ptr = &s526_boards[0]; - - dev->board_name = thisboard->name; - -/* - * Allocate the private structure area. alloc_private() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_private(dev, sizeof(struct s526_private)) < 0) - return -ENOMEM; - -/* - * Allocate the subdevice structures. alloc_subdevice() is a - * convenient macro defined in comedidev.h. - */ - dev->n_subdevices = 4; - if (alloc_subdevices(dev, dev->n_subdevices) < 0) - return -ENOMEM; - - s = dev->subdevices + 0; - /* GENERAL-PURPOSE COUNTER/TIME (GPCT) */ - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL; - /* KG: What does SDF_LSAMPL (see multiq3.c) mean? */ - s->n_chan = thisboard->gpct_chans; - s->maxdata = 0x00ffffff; /* 24 bit counter */ - s->insn_read = s526_gpct_rinsn; - s->insn_config = s526_gpct_insn_config; - s->insn_write = s526_gpct_winsn; - - /* Command are not implemented yet, however they are necessary to - allocate the necessary memory for the comedi_async struct (used - to trigger the GPCT in case of pulsegenerator function */ - /* s->do_cmd = s526_gpct_cmd; */ - /* s->do_cmdtest = s526_gpct_cmdtest; */ - /* s->cancel = s526_gpct_cancel; */ - - s = dev->subdevices + 1; - /* dev->read_subdev=s; */ - /* analog input subdevice */ - s->type = COMEDI_SUBD_AI; - /* we support differential */ - s->subdev_flags = SDF_READABLE | SDF_DIFF; - /* channels 0 to 7 are the regular differential inputs */ - /* channel 8 is "reference 0" (+10V), channel 9 is "reference 1" (0V) */ - s->n_chan = 10; - s->maxdata = 0xffff; - s->range_table = &range_bipolar10; - s->len_chanlist = 16; /* This is the maximum chanlist length that - the board can handle */ - s->insn_read = s526_ai_rinsn; - s->insn_config = s526_ai_insn_config; - - s = dev->subdevices + 2; - /* analog output subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 4; - s->maxdata = 0xffff; - s->range_table = &range_bipolar10; - s->insn_write = s526_ao_winsn; - s->insn_read = s526_ao_rinsn; - - s = dev->subdevices + 3; - /* digital i/o subdevice */ - if (thisboard->have_dio) { - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 8; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = s526_dio_insn_bits; - s->insn_config = s526_dio_insn_config; - } else { - s->type = COMEDI_SUBD_UNUSED; - } - - printk(KERN_INFO "attached\n"); - - return 1; - -#if 0 - /* Example of Counter Application */ - /* One-shot (software trigger) */ - cmReg.reg.coutSource = 0; /* out RCAP */ - cmReg.reg.coutPolarity = 1; /* Polarity inverted */ - cmReg.reg.autoLoadResetRcap = 1;/* Auto load 0:disabled, 1:enabled */ - cmReg.reg.hwCtEnableSource = 3; /* NOT RCAP */ - cmReg.reg.ctEnableCtrl = 2; /* Hardware */ - cmReg.reg.clockSource = 2; /* Internal */ - cmReg.reg.countDir = 1; /* Down */ - cmReg.reg.countDirCtrl = 1; /* Software */ - cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */ - cmReg.reg.preloadRegSel = 0; /* PR0 */ - cmReg.reg.reserved = 0; - - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); - - outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel)); - outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel)); - - /* Reset the counter */ - outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); - /* Load the counter from PR0 */ - outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); - /* Reset RCAP (fires one-shot) */ - outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel)); - -#else - - /* Set Counter Mode Register */ - cmReg.reg.coutSource = 0; /* out RCAP */ - cmReg.reg.coutPolarity = 0; /* Polarity inverted */ - cmReg.reg.autoLoadResetRcap = 0; /* Auto load disabled */ - cmReg.reg.hwCtEnableSource = 2; /* NOT RCAP */ - cmReg.reg.ctEnableCtrl = 1; /* 1: Software, >1 : Hardware */ - cmReg.reg.clockSource = 3; /* x4 */ - cmReg.reg.countDir = 0; /* up */ - cmReg.reg.countDirCtrl = 0; /* quadrature */ - cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */ - cmReg.reg.preloadRegSel = 0; /* PR0 */ - cmReg.reg.reserved = 0; - - n = 0; - printk(KERN_INFO "Mode reg=0x%04x, 0x%04lx\n", - cmReg.value, ADDR_CHAN_REG(REG_C0M, n)); - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n)); - udelay(1000); - printk(KERN_INFO "Read back mode reg=0x%04x\n", - inw(ADDR_CHAN_REG(REG_C0M, n))); - - /* Load the pre-load register high word */ -/* value = (short) (0x55); */ -/* outw(value, ADDR_CHAN_REG(REG_C0H, n)); */ - - /* Load the pre-load register low word */ -/* value = (short)(0xaa55); */ -/* outw(value, ADDR_CHAN_REG(REG_C0L, n)); */ - - /* Write the Counter Control Register */ -/* outw(value, ADDR_CHAN_REG(REG_C0C, 0)); */ - - /* Reset the counter if it is software preload */ - if (cmReg.reg.autoLoadResetRcap == 0) { - /* Reset the counter */ - outw(0x8000, ADDR_CHAN_REG(REG_C0C, n)); - /* Load the counter from PR0 */ - outw(0x4000, ADDR_CHAN_REG(REG_C0C, n)); - } - - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n)); - udelay(1000); - printk(KERN_INFO "Read back mode reg=0x%04x\n", - inw(ADDR_CHAN_REG(REG_C0M, n))); - -#endif - printk(KERN_INFO "Current registres:\n"); - - for (i = 0; i < S526_NUM_PORTS; i++) { - printk(KERN_INFO "0x%02lx: 0x%04x\n", - ADDR_REG(s526_ports[i]), inw(ADDR_REG(s526_ports[i]))); - } - return 1; -} - -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int s526_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: s526: remove\n", dev->minor); - - if (dev->iobase > 0) - release_region(dev->iobase, S526_IOSIZE); - - return 0; -} - static int s526_gpct_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -1023,22 +742,218 @@ static int s526_dio_insn_config(struct comedi_device *dev, return 1; } +static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) +{ + struct comedi_subdevice *s; + int iobase; + int i, n; +/* short value; */ +/* int subdev_channel = 0; */ + union cmReg cmReg; + + printk(KERN_INFO "comedi%d: s526: ", dev->minor); + + iobase = it->options[0]; + if (!iobase || !request_region(iobase, S526_IOSIZE, thisboard->name)) { + comedi_error(dev, "I/O port conflict"); + return -EIO; + } + dev->iobase = iobase; + + printk("iobase=0x%lx\n", dev->iobase); + + /*** make it a little quieter, exw, 8/29/06 + for (i = 0; i < S526_NUM_PORTS; i++) { + printk("0x%02x: 0x%04x\n", ADDR_REG(s526_ports[i]), + inw(ADDR_REG(s526_ports[i]))); + } + ***/ + /* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. + * Initialize dev->board_name. Note that we can use the "thisboard" + * macro now, since we just initialized it in the last line. */ -static int __init driver_s526_init_module(void) -{ - return comedi_driver_register(&driver_s526); + dev->board_ptr = &s526_boards[0]; + + dev->board_name = thisboard->name; + +/* + * Allocate the private structure area. alloc_private() is a + * convenient macro defined in comedidev.h. + */ + if (alloc_private(dev, sizeof(struct s526_private)) < 0) + return -ENOMEM; + +/* + * Allocate the subdevice structures. alloc_subdevice() is a + * convenient macro defined in comedidev.h. + */ + dev->n_subdevices = 4; + if (alloc_subdevices(dev, dev->n_subdevices) < 0) + return -ENOMEM; + + s = dev->subdevices + 0; + /* GENERAL-PURPOSE COUNTER/TIME (GPCT) */ + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL; + /* KG: What does SDF_LSAMPL (see multiq3.c) mean? */ + s->n_chan = thisboard->gpct_chans; + s->maxdata = 0x00ffffff; /* 24 bit counter */ + s->insn_read = s526_gpct_rinsn; + s->insn_config = s526_gpct_insn_config; + s->insn_write = s526_gpct_winsn; + + /* Command are not implemented yet, however they are necessary to + allocate the necessary memory for the comedi_async struct (used + to trigger the GPCT in case of pulsegenerator function */ + /* s->do_cmd = s526_gpct_cmd; */ + /* s->do_cmdtest = s526_gpct_cmdtest; */ + /* s->cancel = s526_gpct_cancel; */ + + s = dev->subdevices + 1; + /* dev->read_subdev=s; */ + /* analog input subdevice */ + s->type = COMEDI_SUBD_AI; + /* we support differential */ + s->subdev_flags = SDF_READABLE | SDF_DIFF; + /* channels 0 to 7 are the regular differential inputs */ + /* channel 8 is "reference 0" (+10V), channel 9 is "reference 1" (0V) */ + s->n_chan = 10; + s->maxdata = 0xffff; + s->range_table = &range_bipolar10; + s->len_chanlist = 16; /* This is the maximum chanlist length that + the board can handle */ + s->insn_read = s526_ai_rinsn; + s->insn_config = s526_ai_insn_config; + + s = dev->subdevices + 2; + /* analog output subdevice */ + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 4; + s->maxdata = 0xffff; + s->range_table = &range_bipolar10; + s->insn_write = s526_ao_winsn; + s->insn_read = s526_ao_rinsn; + + s = dev->subdevices + 3; + /* digital i/o subdevice */ + if (thisboard->have_dio) { + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = s526_dio_insn_bits; + s->insn_config = s526_dio_insn_config; + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + printk(KERN_INFO "attached\n"); + + return 1; + +#if 0 + /* Example of Counter Application */ + /* One-shot (software trigger) */ + cmReg.reg.coutSource = 0; /* out RCAP */ + cmReg.reg.coutPolarity = 1; /* Polarity inverted */ + cmReg.reg.autoLoadResetRcap = 1;/* Auto load 0:disabled, 1:enabled */ + cmReg.reg.hwCtEnableSource = 3; /* NOT RCAP */ + cmReg.reg.ctEnableCtrl = 2; /* Hardware */ + cmReg.reg.clockSource = 2; /* Internal */ + cmReg.reg.countDir = 1; /* Down */ + cmReg.reg.countDirCtrl = 1; /* Software */ + cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */ + cmReg.reg.preloadRegSel = 0; /* PR0 */ + cmReg.reg.reserved = 0; + + outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); + + outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel)); + outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel)); + + /* Reset the counter */ + outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + /* Load the counter from PR0 */ + outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + /* Reset RCAP (fires one-shot) */ + outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + +#else + + /* Set Counter Mode Register */ + cmReg.reg.coutSource = 0; /* out RCAP */ + cmReg.reg.coutPolarity = 0; /* Polarity inverted */ + cmReg.reg.autoLoadResetRcap = 0; /* Auto load disabled */ + cmReg.reg.hwCtEnableSource = 2; /* NOT RCAP */ + cmReg.reg.ctEnableCtrl = 1; /* 1: Software, >1 : Hardware */ + cmReg.reg.clockSource = 3; /* x4 */ + cmReg.reg.countDir = 0; /* up */ + cmReg.reg.countDirCtrl = 0; /* quadrature */ + cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */ + cmReg.reg.preloadRegSel = 0; /* PR0 */ + cmReg.reg.reserved = 0; + + n = 0; + printk(KERN_INFO "Mode reg=0x%04x, 0x%04lx\n", + cmReg.value, ADDR_CHAN_REG(REG_C0M, n)); + outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n)); + udelay(1000); + printk(KERN_INFO "Read back mode reg=0x%04x\n", + inw(ADDR_CHAN_REG(REG_C0M, n))); + + /* Load the pre-load register high word */ +/* value = (short) (0x55); */ +/* outw(value, ADDR_CHAN_REG(REG_C0H, n)); */ + + /* Load the pre-load register low word */ +/* value = (short)(0xaa55); */ +/* outw(value, ADDR_CHAN_REG(REG_C0L, n)); */ + + /* Write the Counter Control Register */ +/* outw(value, ADDR_CHAN_REG(REG_C0C, 0)); */ + + /* Reset the counter if it is software preload */ + if (cmReg.reg.autoLoadResetRcap == 0) { + /* Reset the counter */ + outw(0x8000, ADDR_CHAN_REG(REG_C0C, n)); + /* Load the counter from PR0 */ + outw(0x4000, ADDR_CHAN_REG(REG_C0C, n)); + } + + outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n)); + udelay(1000); + printk(KERN_INFO "Read back mode reg=0x%04x\n", + inw(ADDR_CHAN_REG(REG_C0M, n))); + +#endif + printk(KERN_INFO "Current registres:\n"); + + for (i = 0; i < S526_NUM_PORTS; i++) { + printk(KERN_INFO "0x%02lx: 0x%04x\n", + ADDR_REG(s526_ports[i]), inw(ADDR_REG(s526_ports[i]))); + } + return 1; } -static void __exit driver_s526_cleanup_module(void) +static void s526_detach(struct comedi_device *dev) { - comedi_driver_unregister(&driver_s526); + if (dev->iobase > 0) + release_region(dev->iobase, S526_IOSIZE); } -module_init(driver_s526_init_module); -module_exit(driver_s526_cleanup_module); +static struct comedi_driver s526_driver = { + .driver_name = "s526", + .module = THIS_MODULE, + .attach = s526_attach, + .detach = s526_detach, + .board_name = &s526_boards[0].name, + .offset = sizeof(struct s526_board), + .num_names = ARRAY_SIZE(s526_boards), +}; +module_comedi_driver(s526_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/s626.c b/trunk/drivers/staging/comedi/drivers/s626.c index 23fc64b9988e..7beb8f6853af 100644 --- a/trunk/drivers/staging/comedi/drivers/s626.c +++ b/trunk/drivers/staging/comedi/drivers/s626.c @@ -79,12 +79,17 @@ INSN_CONFIG instructions: #include "comedi_fc.h" #include "s626.h" -MODULE_AUTHOR("Gianluca Palli "); -MODULE_DESCRIPTION("Sensoray 626 Comedi driver module"); -MODULE_LICENSE("GPL"); +#define PCI_VENDOR_ID_S626 0x1131 +#define PCI_DEVICE_ID_S626 0x7146 +#define PCI_SUBVENDOR_ID_S626 0x6000 +#define PCI_SUBDEVICE_ID_S626 0x0272 struct s626_board { const char *name; + int vendor_id; + int device_id; + int subvendor_id; + int subdevice_id; int ai_chans; int ai_bits; int ao_chans; @@ -97,6 +102,10 @@ struct s626_board { static const struct s626_board s626_boards[] = { { .name = "s626", + .vendor_id = PCI_VENDOR_ID_S626, + .device_id = PCI_DEVICE_ID_S626, + .subvendor_id = PCI_SUBVENDOR_ID_S626, + .subdevice_id = PCI_SUBDEVICE_ID_S626, .ai_chans = S626_ADC_CHANNELS, .ai_bits = 14, .ao_chans = S626_DAC_CHANNELS, @@ -108,30 +117,6 @@ static const struct s626_board s626_boards[] = { }; #define thisboard ((const struct s626_board *)dev->board_ptr) -#define PCI_VENDOR_ID_S626 0x1131 -#define PCI_DEVICE_ID_S626 0x7146 - -/* - * For devices with vendor:device id == 0x1131:0x7146 you must specify - * also subvendor:subdevice ids, because otherwise it will conflict with - * Philips SAA7146 media/dvb based cards. - */ -static DEFINE_PCI_DEVICE_TABLE(s626_pci_table) = { - {PCI_VENDOR_ID_S626, PCI_DEVICE_ID_S626, 0x6000, 0x0272, 0, 0, 0}, - {0} -}; - -MODULE_DEVICE_TABLE(pci, s626_pci_table); - -static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int s626_detach(struct comedi_device *dev); - -static struct comedi_driver driver_s626 = { - .driver_name = "s626", - .module = THIS_MODULE, - .attach = s626_attach, - .detach = s626_detach, -}; struct s626_private { struct pci_dev *pdev; @@ -224,44 +209,6 @@ static struct dio_private *dio_private_word[]={ #define devpriv ((struct s626_private *)dev->private) #define diopriv ((struct dio_private *)s->private) -static int __devinit driver_s626_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, driver_s626.driver_name); -} - -static void __devexit driver_s626_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_s626_pci_driver = { - .id_table = s626_pci_table, - .probe = &driver_s626_pci_probe, - .remove = __devexit_p(&driver_s626_pci_remove) -}; - -static int __init driver_s626_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_s626); - if (retval < 0) - return retval; - - driver_s626_pci_driver.name = (char *)driver_s626.driver_name; - return pci_register_driver(&driver_s626_pci_driver); -} - -static void __exit driver_s626_cleanup_module(void) -{ - pci_unregister_driver(&driver_s626_pci_driver); - comedi_driver_unregister(&driver_s626); -} - -module_init(driver_s626_init_module); -module_exit(driver_s626_cleanup_module); - /* ioctl routines */ static int s626_ai_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, @@ -554,17 +501,17 @@ static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it) resource_size_t resourceStart; dma_addr_t appdma; struct comedi_subdevice *s; - const struct pci_device_id *ids; struct pci_dev *pdev = NULL; if (alloc_private(dev, sizeof(struct s626_private)) < 0) return -ENOMEM; - for (i = 0; i < (ARRAY_SIZE(s626_pci_table) - 1) && !pdev; i++) { - ids = &s626_pci_table[i]; + for (i = 0; i < ARRAY_SIZE(s626_boards) && !pdev; i++) { do { - pdev = pci_get_subsys(ids->vendor, ids->device, - ids->subvendor, ids->subdevice, + pdev = pci_get_subsys(s626_boards[i].vendor_id, + s626_boards[i].device_id, + s626_boards[i].subvendor_id, + s626_boards[i].subdevice_id, pdev); if ((it->options[0] || it->options[1]) && pdev) { @@ -1365,7 +1312,7 @@ static irqreturn_t s626_irq_handler(int irq, void *d) return IRQ_HANDLED; } -static int s626_detach(struct comedi_device *dev) +static void s626_detach(struct comedi_device *dev) { if (devpriv) { /* stop ai_command */ @@ -1389,20 +1336,14 @@ static int s626_detach(struct comedi_device *dev) if (dev->irq) free_irq(dev->irq, dev); - if (devpriv->base_addr) iounmap(devpriv->base_addr); - if (devpriv->pdev) { if (devpriv->got_regions) comedi_pci_disable(devpriv->pdev); pci_dev_put(devpriv->pdev); } } - - DEBUG("s626_detach: S626 detached!\n"); - - return 0; } /* @@ -3367,3 +3308,45 @@ static void CountersInit(struct comedi_device *dev) DEBUG("CountersInit: counters initialized\n"); } + +static struct comedi_driver s626_driver = { + .driver_name = "s626", + .module = THIS_MODULE, + .attach = s626_attach, + .detach = s626_detach, +}; + +static int __devinit s626_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + return comedi_pci_auto_config(dev, &s626_driver); +} + +static void __devexit s626_pci_remove(struct pci_dev *dev) +{ + comedi_pci_auto_unconfig(dev); +} + +/* + * For devices with vendor:device id == 0x1131:0x7146 you must specify + * also subvendor:subdevice ids, because otherwise it will conflict with + * Philips SAA7146 media/dvb based cards. + */ +static DEFINE_PCI_DEVICE_TABLE(s626_pci_table) = { + { PCI_VENDOR_ID_S626, PCI_DEVICE_ID_S626, + PCI_SUBVENDOR_ID_S626, PCI_SUBDEVICE_ID_S626, 0, 0, 0 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, s626_pci_table); + +static struct pci_driver s626_pci_driver = { + .name = "s626", + .id_table = s626_pci_table, + .probe = s626_pci_probe, + .remove = __devexit_p(s626_pci_remove), +}; +module_comedi_pci_driver(s626_driver, s626_pci_driver); + +MODULE_AUTHOR("Gianluca Palli "); +MODULE_DESCRIPTION("Sensoray 626 Comedi driver module"); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/serial2002.c b/trunk/drivers/staging/comedi/drivers/serial2002.c index d880c2f6fbc1..6342bc5ddb3e 100644 --- a/trunk/drivers/staging/comedi/drivers/serial2002.c +++ b/trunk/drivers/staging/comedi/drivers/serial2002.c @@ -43,20 +43,10 @@ Status: in development #include #include -/* - * Board descriptions for two imaginary boards. Describing the - * boards in this way is optional, and completely driver-dependent. - * Some drivers use arrays such as this, other do not. - */ struct serial2002_board { const char *name; }; -static const struct serial2002_board serial2002_boards[] = { - { - .name = "serial2002"} -}; - /* * Useful for shorthand access to the particular board structure */ @@ -89,35 +79,6 @@ struct serial2002_private { */ #define devpriv ((struct serial2002_private *)dev->private) -static int serial2002_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int serial2002_detach(struct comedi_device *dev); -struct comedi_driver driver_serial2002 = { - .driver_name = "serial2002", - .module = THIS_MODULE, - .attach = serial2002_attach, - .detach = serial2002_detach, - .board_name = &serial2002_boards[0].name, - .offset = sizeof(struct serial2002_board), - .num_names = ARRAY_SIZE(serial2002_boards), -}; - -static int serial2002_di_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int serial2002_do_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int serial2002_ai_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int serial2002_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int serial2002_ao_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - struct serial_data { enum { is_invalid, is_digital, is_channel } kind; int index; @@ -887,32 +848,34 @@ static int serial2002_attach(struct comedi_device *dev, return 1; } -static int serial2002_detach(struct comedi_device *dev) +static void serial2002_detach(struct comedi_device *dev) { struct comedi_subdevice *s; int i; - dev_dbg(dev->hw_dev, "comedi%d: remove\n", dev->minor); for (i = 0; i < 5; i++) { s = &dev->subdevices[i]; kfree(s->maxdata_list); kfree(s->range_table_list); } - return 0; -} - -static int __init driver_serial2002_init_module(void) -{ - return comedi_driver_register(&driver_serial2002); } -static void __exit driver_serial2002_cleanup_module(void) -{ - comedi_driver_unregister(&driver_serial2002); -} +static const struct serial2002_board serial2002_boards[] = { + { + .name = "serial2002" + }, +}; -module_init(driver_serial2002_init_module); -module_exit(driver_serial2002_cleanup_module); +static struct comedi_driver serial2002_driver = { + .driver_name = "serial2002", + .module = THIS_MODULE, + .attach = serial2002_attach, + .detach = serial2002_detach, + .board_name = &serial2002_boards[0].name, + .offset = sizeof(struct serial2002_board), + .num_names = ARRAY_SIZE(serial2002_boards), +}; +module_comedi_driver(serial2002_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/skel.c b/trunk/drivers/staging/comedi/drivers/skel.c index ed69008f0d39..7d13ffa7f4f9 100644 --- a/trunk/drivers/staging/comedi/drivers/skel.c +++ b/trunk/drivers/staging/comedi/drivers/skel.c @@ -156,7 +156,7 @@ struct skel_private { * the device code. */ static int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int skel_detach(struct comedi_device *dev); +static void skel_detach(struct comedi_device *dev); static struct comedi_driver driver_skel = { .driver_name = "dummy", .module = THIS_MODULE, @@ -295,11 +295,8 @@ static int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it) * allocated by _attach(). dev->private and dev->subdevices are * deallocated automatically by the core. */ -static int skel_detach(struct comedi_device *dev) +static void skel_detach(struct comedi_device *dev) { - pr_info("comedi%d: skel: remove\n", dev->minor); - - return 0; } /* @@ -623,7 +620,7 @@ static int skel_dio_insn_config(struct comedi_device *dev, static int __devinit driver_skel_pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, driver_skel.driver_name); + return comedi_pci_auto_config(dev, &driver_skel); } static void __devexit driver_skel_pci_remove(struct pci_dev *dev) diff --git a/trunk/drivers/staging/comedi/drivers/ssv_dnp.c b/trunk/drivers/staging/comedi/drivers/ssv_dnp.c index 526de2efa125..16c4f5a757bb 100644 --- a/trunk/drivers/staging/comedi/drivers/ssv_dnp.c +++ b/trunk/drivers/staging/comedi/drivers/ssv_dnp.c @@ -59,16 +59,6 @@ struct dnp_board { int have_dio; }; -/* We only support one DNP 'board' variant at the moment */ -static const struct dnp_board dnp_boards[] = { -{ - .name = "dnp-1486", - .ai_chans = 16, - .ai_bits = 12, - .have_dio = 1, - }, -}; - /* Useful for shorthand access to the particular board structure ----------- */ #define thisboard ((const struct dnp_board *)dev->board_ptr) @@ -80,136 +70,6 @@ struct dnp_private_data { /* Shorthand macro for faster access to the private data ------------------- */ #define devpriv ((dnp_private *)dev->private) -/* ------------------------------------------------------------------------- */ -/* The struct comedi_driver structure tells the Comedi core module which */ -/* functions to call to configure/deconfigure (attach/detach) the board, and */ -/* also about the kernel module that contains the device code. */ -/* */ -/* In the following section we define the API of this driver. */ -/* ------------------------------------------------------------------------- */ - -static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int dnp_detach(struct comedi_device *dev); - -static struct comedi_driver driver_dnp = { - .driver_name = "ssv_dnp", - .module = THIS_MODULE, - .attach = dnp_attach, - .detach = dnp_detach, - .board_name = &dnp_boards[0].name, - /* only necessary for non-PnP devs */ - .offset = sizeof(struct dnp_board), /* like ISA-PnP, PCI or PCMCIA */ - .num_names = ARRAY_SIZE(dnp_boards), -}; - -static int __init driver_dnp_init_module(void) -{ - return comedi_driver_register(&driver_dnp); -} - -static void __exit driver_dnp_cleanup_module(void) -{ - comedi_driver_unregister(&driver_dnp); -} - -module_init(driver_dnp_init_module); -module_exit(driver_dnp_cleanup_module); - -static int dnp_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static int dnp_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* ------------------------------------------------------------------------- */ -/* Attach is called by comedi core to configure the driver for a particular */ -/* board. If you specified a board_name array in the driver structure, */ -/* dev->board_ptr contains that address. */ -/* ------------------------------------------------------------------------- */ - -static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - - struct comedi_subdevice *s; - - printk(KERN_INFO "comedi%d: dnp: ", dev->minor); - - /* Autoprobing: this should find out which board we have. Currently */ - /* only the 1486 board is supported and autoprobing is not */ - /* implemented :-) */ - /* dev->board_ptr = dnp_probe(dev); */ - - /* Initialize the name of the board. */ - /* We can use the "thisboard" macro now. */ - dev->board_name = thisboard->name; - - /* Allocate the private structure area. alloc_private() is a */ - /* convenient macro defined in comedidev.h. */ - if (alloc_private(dev, sizeof(struct dnp_private_data)) < 0) - return -ENOMEM; - - /* Allocate the subdevice structures. alloc_subdevice() is a */ - /* convenient macro defined in comedidev.h. */ - - if (alloc_subdevices(dev, 1) < 0) - return -ENOMEM; - - s = dev->subdevices + 0; - /* digital i/o subdevice */ - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 20; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = dnp_dio_insn_bits; - s->insn_config = dnp_dio_insn_config; - - printk("attached\n"); - - /* We use the I/O ports 0x22,0x23 and 0xa3-0xa9, which are always - * allocated for the primary 8259, so we don't need to allocate them - * ourselves. */ - - /* configure all ports as input (default) */ - outb(PAMR, CSCIR); - outb(0x00, CSCDR); - outb(PBMR, CSCIR); - outb(0x00, CSCDR); - outb(PCMR, CSCIR); - outb((inb(CSCDR) & 0xAA), CSCDR); - - return 1; - -} - -/* ------------------------------------------------------------------------- */ -/* detach is called to deconfigure a device. It should deallocate the */ -/* resources. This function is also called when _attach() fails, so it */ -/* should be careful not to release resources that were not necessarily */ -/* allocated by _attach(). dev->private and dev->subdevices are */ -/* deallocated automatically by the core. */ -/* ------------------------------------------------------------------------- */ - -static int dnp_detach(struct comedi_device *dev) -{ - - /* configure all ports as input (default) */ - outb(PAMR, CSCIR); - outb(0x00, CSCDR); - outb(PBMR, CSCIR); - outb(0x00, CSCDR); - outb(PCMR, CSCIR); - outb((inb(CSCDR) & 0xAA), CSCDR); - - /* announce that we are finished */ - printk(KERN_INFO "comedi%d: dnp: remove\n", dev->minor); - - return 0; - -} - /* ------------------------------------------------------------------------- */ /* The insn_bits interface allows packed reading/writing of DIO channels. */ /* The comedi core can convert between insn_bits and insn_read/write, so you */ @@ -326,6 +186,89 @@ static int dnp_dio_insn_config(struct comedi_device *dev, } +static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it) +{ + struct comedi_subdevice *s; + + printk(KERN_INFO "comedi%d: dnp: ", dev->minor); + + /* Autoprobing: this should find out which board we have. Currently */ + /* only the 1486 board is supported and autoprobing is not */ + /* implemented :-) */ + /* dev->board_ptr = dnp_probe(dev); */ + + /* Initialize the name of the board. */ + /* We can use the "thisboard" macro now. */ + dev->board_name = thisboard->name; + + /* Allocate the private structure area. alloc_private() is a */ + /* convenient macro defined in comedidev.h. */ + if (alloc_private(dev, sizeof(struct dnp_private_data)) < 0) + return -ENOMEM; + + /* Allocate the subdevice structures. alloc_subdevice() is a */ + /* convenient macro defined in comedidev.h. */ + + if (alloc_subdevices(dev, 1) < 0) + return -ENOMEM; + + s = dev->subdevices + 0; + /* digital i/o subdevice */ + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 20; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = dnp_dio_insn_bits; + s->insn_config = dnp_dio_insn_config; + + printk("attached\n"); + + /* We use the I/O ports 0x22,0x23 and 0xa3-0xa9, which are always + * allocated for the primary 8259, so we don't need to allocate them + * ourselves. */ + + /* configure all ports as input (default) */ + outb(PAMR, CSCIR); + outb(0x00, CSCDR); + outb(PBMR, CSCIR); + outb(0x00, CSCDR); + outb(PCMR, CSCIR); + outb((inb(CSCDR) & 0xAA), CSCDR); + + return 1; +} + +static void dnp_detach(struct comedi_device *dev) +{ + outb(PAMR, CSCIR); + outb(0x00, CSCDR); + outb(PBMR, CSCIR); + outb(0x00, CSCDR); + outb(PCMR, CSCIR); + outb((inb(CSCDR) & 0xAA), CSCDR); +} + +static const struct dnp_board dnp_boards[] = { + { + .name = "dnp-1486", + .ai_chans = 16, + .ai_bits = 12, + .have_dio = 1, + }, +}; + +static struct comedi_driver dnp_driver = { + .driver_name = "ssv_dnp", + .module = THIS_MODULE, + .attach = dnp_attach, + .detach = dnp_detach, + .board_name = &dnp_boards[0].name, + .offset = sizeof(struct dnp_board), + .num_names = ARRAY_SIZE(dnp_boards), +}; +module_comedi_driver(dnp_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/comedi/drivers/unioxx5.c b/trunk/drivers/staging/comedi/drivers/unioxx5.c index f45824f0d86b..d5f1f22aa708 100644 --- a/trunk/drivers/staging/comedi/drivers/unioxx5.c +++ b/trunk/drivers/staging/comedi/drivers/unioxx5.c @@ -83,96 +83,188 @@ struct unioxx5_subd_priv { unsigned char usp_prev_cn_val[3]; /* previous channel value */ }; -static int unioxx5_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int unioxx5_subdev_write(struct comedi_device *dev, - struct comedi_subdevice *subdev, - struct comedi_insn *insn, unsigned int *data); -static int unioxx5_subdev_read(struct comedi_device *dev, - struct comedi_subdevice *subdev, - struct comedi_insn *insn, unsigned int *data); -static int unioxx5_insn_config(struct comedi_device *dev, - struct comedi_subdevice *subdev, - struct comedi_insn *insn, unsigned int *data); -static int unioxx5_detach(struct comedi_device *dev); -static int __unioxx5_subdev_init(struct comedi_subdevice *subdev, - int subdev_iobase, int minor); -static int __unioxx5_digital_write(struct unioxx5_subd_priv *usp, - unsigned int *data, int channel, int minor); -static int __unioxx5_digital_read(struct unioxx5_subd_priv *usp, - unsigned int *data, int channel, int minor); -/* static void __unioxx5_digital_config(struct unioxx5_subd_priv* usp, int mode); */ -static int __unioxx5_analog_write(struct unioxx5_subd_priv *usp, - unsigned int *data, int channel, int minor); -static int __unioxx5_analog_read(struct unioxx5_subd_priv *usp, - unsigned int *data, int channel, int minor); -static int __unioxx5_define_chan_offset(int chan_num); -static void __unioxx5_analog_config(struct unioxx5_subd_priv *usp, int channel); +static int __unioxx5_define_chan_offset(int chan_num) +{ -static struct comedi_driver unioxx5_driver = { - .driver_name = DRIVER_NAME, - .module = THIS_MODULE, - .attach = unioxx5_attach, - .detach = unioxx5_detach -}; + if (chan_num < 0 || chan_num > 23) + return -1; -static int __init unioxx5_driver_init_module(void) + return (chan_num >> 3) + 1; +} + +#if 0 /* not used? */ +static void __unioxx5_digital_config(struct unioxx5_subd_priv *usp, int mode) { - return comedi_driver_register(&unioxx5_driver); + int i, mask; + + mask = (mode == ALL_2_OUTPUT) ? 0xFF : 0x00; + printk("COMEDI: mode = %d\n", mask); + + outb(1, usp->usp_iobase + 0); + + for (i = 0; i < 3; i++) + outb(mask, usp->usp_iobase + i); + + outb(0, usp->usp_iobase + 0); } +#endif -static void __exit unioxx5_driver_cleanup_module(void) +/* configure channels for analog i/o (even to output, odd to input) */ +static void __unioxx5_analog_config(struct unioxx5_subd_priv *usp, int channel) { - comedi_driver_unregister(&unioxx5_driver); + int chan_a, chan_b, conf, channel_offset; + + channel_offset = __unioxx5_define_chan_offset(channel); + conf = usp->usp_prev_cn_val[channel_offset - 1]; + chan_a = chan_b = 1; + + /* setting channel A and channel B mask */ + if (channel % 2 == 0) { + chan_a <<= channel & 0x07; + chan_b <<= (channel + 1) & 0x07; + } else { + chan_a <<= (channel - 1) & 0x07; + chan_b <<= channel & 0x07; + } + + conf |= chan_a; /* even channel ot output */ + conf &= ~chan_b; /* odd channel to input */ + + outb(1, usp->usp_iobase + 0); + outb(conf, usp->usp_iobase + channel_offset); + outb(0, usp->usp_iobase + 0); + + usp->usp_prev_cn_val[channel_offset - 1] = conf; } -module_init(unioxx5_driver_init_module); -module_exit(unioxx5_driver_cleanup_module); +static int __unioxx5_digital_read(struct unioxx5_subd_priv *usp, + unsigned int *data, int channel, int minor) +{ + int channel_offset, mask = 1 << (channel & 0x07); -static int unioxx5_attach(struct comedi_device *dev, - struct comedi_devconfig *it) + channel_offset = __unioxx5_define_chan_offset(channel); + if (channel_offset < 0) { + printk(KERN_ERR + "comedi%d: undefined channel %d. channel range is 0 .. 23\n", + minor, channel); + return 0; + } + + *data = inb(usp->usp_iobase + channel_offset); + *data &= mask; + + /* correct the read value to 0 or 1 */ + if (channel_offset > 1) + channel -= 2 << channel_offset; + *data >>= channel; + return 1; +} + +static int __unioxx5_analog_read(struct unioxx5_subd_priv *usp, + unsigned int *data, int channel, int minor) { - int iobase, i, n_subd; - int id, num, ba; + int module_no, read_ch; + char control; - iobase = it->options[0]; + module_no = channel / 2; + read_ch = channel % 2; /* depend on type of channel (A or B) */ - dev->board_name = DRIVER_NAME; - dev->iobase = iobase; - iobase += UNIOXX5_SUBDEV_BASE; + /* defining if given module can work on input */ + if (usp->usp_module_type[module_no] & MODULE_OUTPUT_MASK) { + printk(KERN_ERR + "comedi%d: module in position %d with id 0x%02x is for output only", + minor, module_no, usp->usp_module_type[module_no]); + return 0; + } - /* defining number of subdevices and getting they types (it must be 'g01') */ - for (i = n_subd = 0, ba = iobase; i < 4; i++, ba += UNIOXX5_SUBDEV_ODDS) { - id = inb(ba + 0xE); - num = inb(ba + 0xF); + __unioxx5_analog_config(usp, channel); + /* sends module number to card(1 .. 12) */ + outb(module_no + 1, usp->usp_iobase + 5); + outb('V', usp->usp_iobase + 6); /* sends to module (V)erify command */ + control = inb(usp->usp_iobase); /* get control register byte */ - if (id != 'g' || num != 1) - continue; + /* waits while reading four bytes will be allowed */ + while (!((control = inb(usp->usp_iobase + 0)) & Rx4CA)) + ; - n_subd++; + /* if four bytes readding error occurs - return 0(false) */ + if ((control & Rx4CA_ERR_MASK)) { + printk("COMEDI: 4 bytes error\n"); + return 0; } - /* unioxx5 can has from two to four subdevices */ - if (n_subd < 2) { + if (read_ch) + *data = inw(usp->usp_iobase + 6); /* channel B */ + else + *data = inw(usp->usp_iobase + 4); /* channel A */ + + return 1; +} + +static int __unioxx5_digital_write(struct unioxx5_subd_priv *usp, + unsigned int *data, int channel, int minor) +{ + int channel_offset, val; + int mask = 1 << (channel & 0x07); + + channel_offset = __unioxx5_define_chan_offset(channel); + if (channel_offset < 0) { printk(KERN_ERR - "your card must has at least 2 'g01' subdevices\n"); - return -1; + "comedi%d: undefined channel %d. channel range is 0 .. 23\n", + minor, channel); + return 0; } - if (alloc_subdevices(dev, n_subd) < 0) { - printk(KERN_ERR "out of memory\n"); - return -ENOMEM; + /* getting previous written value */ + val = usp->usp_prev_wr_val[channel_offset - 1]; + + if (*data) + val |= mask; + else + val &= ~mask; + + outb(val, usp->usp_iobase + channel_offset); + /* saving new written value */ + usp->usp_prev_wr_val[channel_offset - 1] = val; + + return 1; +} + +static int __unioxx5_analog_write(struct unioxx5_subd_priv *usp, + unsigned int *data, int channel, int minor) +{ + int module, i; + + module = channel / 2; /* definig module number(0 .. 11) */ + i = (channel % 2) << 1; /* depends on type of channel (A or B) */ + + /* defining if given module can work on output */ + if (!(usp->usp_module_type[module] & MODULE_OUTPUT_MASK)) { + printk(KERN_ERR + "comedi%d: module in position %d with id 0x%0x is for input only!\n", + minor, module, usp->usp_module_type[module]); + return 0; } - /* initializing each of for same subdevices */ - for (i = 0; i < n_subd; i++, iobase += UNIOXX5_SUBDEV_ODDS) { - if (__unioxx5_subdev_init(&dev->subdevices[i], iobase, - dev->minor) < 0) - return -1; + __unioxx5_analog_config(usp, channel); + /* saving minor byte */ + usp->usp_extra_data[module][i++] = (unsigned char)(*data & 0x00FF); + /* saving major byte */ + usp->usp_extra_data[module][i] = (unsigned char)((*data & 0xFF00) >> 8); + + /* while(!((inb(usp->usp_iobase + 0)) & TxBE)); */ + /* sending module number to card(1 .. 12) */ + outb(module + 1, usp->usp_iobase + 5); + outb('W', usp->usp_iobase + 6); /* sends (W)rite command to module */ + + /* sending for bytes to module(one byte per cycle iteration) */ + for (i = 0; i < 4; i++) { + while (!((inb(usp->usp_iobase + 0)) & TxBE)) + ; /* waits while writting will be allowed */ + outb(usp->usp_extra_data[module][i], usp->usp_iobase + 6); } - printk(KERN_INFO "attached\n"); - return 0; + return 1; } static int unioxx5_subdev_read(struct comedi_device *dev, @@ -275,22 +367,6 @@ static int unioxx5_insn_config(struct comedi_device *dev, return 0; } -static int unioxx5_detach(struct comedi_device *dev) -{ - int i; - struct comedi_subdevice *subdev; - struct unioxx5_subd_priv *usp; - - for (i = 0; i < dev->n_subdevices; i++) { - subdev = &dev->subdevices[i]; - usp = subdev->private; - release_region(usp->usp_iobase, UNIOXX5_SIZE); - kfree(subdev->private); - } - - return 0; -} - /* initializing subdevice with given address */ static int __unioxx5_subdev_init(struct comedi_subdevice *subdev, int subdev_iobase, int minor) @@ -362,196 +438,73 @@ static int __unioxx5_subdev_init(struct comedi_subdevice *subdev, return 0; } -static int __unioxx5_digital_write(struct unioxx5_subd_priv *usp, - unsigned int *data, int channel, int minor) +static int unioxx5_attach(struct comedi_device *dev, + struct comedi_devconfig *it) { - int channel_offset, val; - int mask = 1 << (channel & 0x07); - - channel_offset = __unioxx5_define_chan_offset(channel); - if (channel_offset < 0) { - printk(KERN_ERR - "comedi%d: undefined channel %d. channel range is 0 .. 23\n", - minor, channel); - return 0; - } - - /* getting previous written value */ - val = usp->usp_prev_wr_val[channel_offset - 1]; + int iobase, i, n_subd; + int id, num, ba; - if (*data) - val |= mask; - else - val &= ~mask; + iobase = it->options[0]; - outb(val, usp->usp_iobase + channel_offset); - /* saving new written value */ - usp->usp_prev_wr_val[channel_offset - 1] = val; + dev->board_name = DRIVER_NAME; + dev->iobase = iobase; + iobase += UNIOXX5_SUBDEV_BASE; - return 1; -} + /* defining number of subdevices and getting they types (it must be 'g01') */ + for (i = n_subd = 0, ba = iobase; i < 4; i++, ba += UNIOXX5_SUBDEV_ODDS) { + id = inb(ba + 0xE); + num = inb(ba + 0xF); -/* function for digital reading */ -static int __unioxx5_digital_read(struct unioxx5_subd_priv *usp, - unsigned int *data, int channel, int minor) -{ - int channel_offset, mask = 1 << (channel & 0x07); + if (id != 'g' || num != 1) + continue; - channel_offset = __unioxx5_define_chan_offset(channel); - if (channel_offset < 0) { - printk(KERN_ERR - "comedi%d: undefined channel %d. channel range is 0 .. 23\n", - minor, channel); - return 0; + n_subd++; } - *data = inb(usp->usp_iobase + channel_offset); - *data &= mask; - - if (channel_offset > 1) - channel -= 2 << channel_offset; /* this operation is created for correct readed value to 0 or 1 */ - *data >>= channel; - return 1; -} - -#if 0 /* not used? */ -static void __unioxx5_digital_config(struct unioxx5_subd_priv *usp, int mode) -{ - int i, mask; - - mask = (mode == ALL_2_OUTPUT) ? 0xFF : 0x00; - printk("COMEDI: mode = %d\n", mask); - - outb(1, usp->usp_iobase + 0); - - for (i = 0; i < 3; i++) - outb(mask, usp->usp_iobase + i); - - outb(0, usp->usp_iobase + 0); -} -#endif - -static int __unioxx5_analog_write(struct unioxx5_subd_priv *usp, - unsigned int *data, int channel, int minor) -{ - int module, i; - - module = channel / 2; /* definig module number(0 .. 11) */ - i = (channel % 2) << 1; /* depends on type of channel (A or B) */ - - /* defining if given module can work on output */ - if (!(usp->usp_module_type[module] & MODULE_OUTPUT_MASK)) { + /* unioxx5 can has from two to four subdevices */ + if (n_subd < 2) { printk(KERN_ERR - "comedi%d: module in position %d with id 0x%0x is for input only!\n", - minor, module, usp->usp_module_type[module]); - return 0; - } - - __unioxx5_analog_config(usp, channel); - /* saving minor byte */ - usp->usp_extra_data[module][i++] = (unsigned char)(*data & 0x00FF); - /* saving major byte */ - usp->usp_extra_data[module][i] = (unsigned char)((*data & 0xFF00) >> 8); - - /* while(!((inb(usp->usp_iobase + 0)) & TxBE)); */ - /* sending module number to card(1 .. 12) */ - outb(module + 1, usp->usp_iobase + 5); - outb('W', usp->usp_iobase + 6); /* sends (W)rite command to module */ - - /* sending for bytes to module(one byte per cycle iteration) */ - for (i = 0; i < 4; i++) { - while (!((inb(usp->usp_iobase + 0)) & TxBE)) - ; /* waits while writting will be allowed */ - outb(usp->usp_extra_data[module][i], usp->usp_iobase + 6); + "your card must has at least 2 'g01' subdevices\n"); + return -1; } - return 1; -} - -static int __unioxx5_analog_read(struct unioxx5_subd_priv *usp, - unsigned int *data, int channel, int minor) -{ - int module_no, read_ch; - char control; - - module_no = channel / 2; - read_ch = channel % 2; /* depend on type of channel (A or B) */ - - /* defining if given module can work on input */ - if (usp->usp_module_type[module_no] & MODULE_OUTPUT_MASK) { - printk(KERN_ERR - "comedi%d: module in position %d with id 0x%02x is for output only", - minor, module_no, usp->usp_module_type[module_no]); - return 0; + if (alloc_subdevices(dev, n_subd) < 0) { + printk(KERN_ERR "out of memory\n"); + return -ENOMEM; } - __unioxx5_analog_config(usp, channel); - /* sends module number to card(1 .. 12) */ - outb(module_no + 1, usp->usp_iobase + 5); - outb('V', usp->usp_iobase + 6); /* sends to module (V)erify command */ - control = inb(usp->usp_iobase); /* get control register byte */ - - /* waits while reading four bytes will be allowed */ - while (!((control = inb(usp->usp_iobase + 0)) & Rx4CA)) - ; - - /* if four bytes readding error occurs - return 0(false) */ - if ((control & Rx4CA_ERR_MASK)) { - printk("COMEDI: 4 bytes error\n"); - return 0; + /* initializing each of for same subdevices */ + for (i = 0; i < n_subd; i++, iobase += UNIOXX5_SUBDEV_ODDS) { + if (__unioxx5_subdev_init(&dev->subdevices[i], iobase, + dev->minor) < 0) + return -1; } - if (read_ch) - *data = inw(usp->usp_iobase + 6); /* channel B */ - else - *data = inw(usp->usp_iobase + 4); /* channel A */ - - return 1; + printk(KERN_INFO "attached\n"); + return 0; } -/* configure channels for analog i/o (even to output, odd to input) */ -static void __unioxx5_analog_config(struct unioxx5_subd_priv *usp, int channel) +static void unioxx5_detach(struct comedi_device *dev) { - int chan_a, chan_b, conf, channel_offset; - - channel_offset = __unioxx5_define_chan_offset(channel); - conf = usp->usp_prev_cn_val[channel_offset - 1]; - chan_a = chan_b = 1; + int i; + struct comedi_subdevice *subdev; + struct unioxx5_subd_priv *usp; - /* setting channel A and channel B mask */ - if (channel % 2 == 0) { - chan_a <<= channel & 0x07; - chan_b <<= (channel + 1) & 0x07; - } else { - chan_a <<= (channel - 1) & 0x07; - chan_b <<= channel & 0x07; + for (i = 0; i < dev->n_subdevices; i++) { + subdev = &dev->subdevices[i]; + usp = subdev->private; + release_region(usp->usp_iobase, UNIOXX5_SIZE); + kfree(subdev->private); } - - conf |= chan_a; /* even channel ot output */ - conf &= ~chan_b; /* odd channel to input */ - - outb(1, usp->usp_iobase + 0); - outb(conf, usp->usp_iobase + channel_offset); - outb(0, usp->usp_iobase + 0); - - usp->usp_prev_cn_val[channel_offset - 1] = conf; } -/* *\ - * this function defines if the given channel number * - * enters in default numeric interspace(from 0 to 23) * - * and it returns address offset for usage needed * - * channel. * -\* */ - -static int __unioxx5_define_chan_offset(int chan_num) -{ - - if (chan_num < 0 || chan_num > 23) - return -1; - - return (chan_num >> 3) + 1; -} +static struct comedi_driver unioxx5_driver = { + .driver_name = DRIVER_NAME, + .module = THIS_MODULE, + .attach = unioxx5_attach, + .detach = unioxx5_detach, +}; +module_comedi_driver(unioxx5_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/trunk/drivers/staging/comedi/drivers/usbdux.c b/trunk/drivers/staging/comedi/drivers/usbdux.c index bf62e0dd6f69..13d9fd3efcfd 100644 --- a/trunk/drivers/staging/comedi/drivers/usbdux.c +++ b/trunk/drivers/staging/comedi/drivers/usbdux.c @@ -317,6 +317,8 @@ static struct usbduxsub usbduxsub[NUMUSBDUX]; static DEFINE_SEMAPHORE(start_stop_sem); +static struct comedi_driver driver_usbdux; /* see below for initializer */ + /* * Stops the data acquision * It should be safe to call this function from any context @@ -2304,11 +2306,11 @@ static void usbdux_firmware_request_complete_handler(const struct firmware *fw, void *context) { struct usbduxsub *usbduxsub_tmp = context; - struct usb_device *usbdev = usbduxsub_tmp->usbdev; + struct usb_interface *uinterf = usbduxsub_tmp->interface; int ret; if (fw == NULL) { - dev_err(&usbdev->dev, + dev_err(&uinterf->dev, "Firmware complete handler without firmware!\n"); return; } @@ -2320,11 +2322,11 @@ static void usbdux_firmware_request_complete_handler(const struct firmware *fw, ret = firmwareUpload(usbduxsub_tmp, fw->data, fw->size); if (ret) { - dev_err(&usbdev->dev, + dev_err(&uinterf->dev, "Could not upload firmware (err=%d)\n", ret); goto out; } - comedi_usb_auto_config(usbdev, BOARDNAME); + comedi_usb_auto_config(uinterf, &driver_usbdux); out: release_firmware(fw); } @@ -2606,7 +2608,7 @@ static void usbduxsub_disconnect(struct usb_interface *intf) dev_err(&intf->dev, "comedi_: BUG! called with wrong ptr!!!\n"); return; } - comedi_usb_auto_unconfig(udev); + comedi_usb_auto_unconfig(intf); down(&start_stop_sem); down(&usbduxsub_tmp->sem); tidy_up(usbduxsub_tmp); @@ -2615,46 +2617,21 @@ static void usbduxsub_disconnect(struct usb_interface *intf) dev_dbg(&intf->dev, "comedi_: disconnected from the usb\n"); } -/* is called when comedi-config is called */ -static int usbdux_attach(struct comedi_device *dev, struct comedi_devconfig *it) +/* common part of attach and attach_usb */ +static int usbdux_attach_common(struct comedi_device *dev, + struct usbduxsub *udev, + void *aux_data, int aux_len) { int ret; - int index; - int i; - struct usbduxsub *udev; - struct comedi_subdevice *s = NULL; - dev->private = NULL; - - down(&start_stop_sem); - /* find a valid device which has been detected by the probe function of - * the usb */ - index = -1; - for (i = 0; i < NUMUSBDUX; i++) { - if ((usbduxsub[i].probed) && (!usbduxsub[i].attached)) { - index = i; - break; - } - } - if (index < 0) { - printk(KERN_ERR "comedi%d: usbdux: error: attach failed, no " - "usbdux devs connected to the usb bus.\n", dev->minor); - up(&start_stop_sem); - return -ENODEV; - } - - udev = &usbduxsub[index]; down(&udev->sem); /* pointer back to the corresponding comedi device */ udev->comedidev = dev; /* trying to upload the firmware into the chip */ - if (comedi_aux_data(it->options, 0) && - it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) { - firmwareUpload(udev, comedi_aux_data(it->options, 0), - it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]); - } + if (aux_data) + firmwareUpload(udev, aux_data, aux_len); dev->board_name = BOARDNAME; @@ -2673,13 +2650,9 @@ static int usbdux_attach(struct comedi_device *dev, struct comedi_devconfig *it) dev_err(&udev->interface->dev, "comedi%d: error alloc space for subdev\n", dev->minor); up(&udev->sem); - up(&start_stop_sem); return ret; } - dev_info(&udev->interface->dev, - "comedi%d: usb-device %d is attached to comedi.\n", - dev->minor, index); /* private structure is also simply the usb-structure */ dev->private = udev; @@ -2776,44 +2749,91 @@ static int usbdux_attach(struct comedi_device *dev, struct comedi_devconfig *it) up(&udev->sem); - up(&start_stop_sem); - dev_info(&udev->interface->dev, "comedi%d: attached to usbdux.\n", dev->minor); return 0; } -static int usbdux_detach(struct comedi_device *dev) +/* is called when comedi-config is called */ +static int usbdux_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - struct usbduxsub *usbduxsub_tmp; + int ret; + int index; + int i; + void *aux_data; + int aux_len; - if (!dev) { - printk(KERN_ERR - "comedi?: usbdux: detach without dev variable...\n"); - return -EFAULT; + dev->private = NULL; + + aux_data = comedi_aux_data(it->options, 0); + aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]; + if (aux_data == NULL) + aux_len = 0; + else if (aux_len == 0) + aux_data = NULL; + + down(&start_stop_sem); + /* find a valid device which has been detected by the probe function of + * the usb */ + index = -1; + for (i = 0; i < NUMUSBDUX; i++) { + if ((usbduxsub[i].probed) && (!usbduxsub[i].attached)) { + index = i; + break; + } } - usbduxsub_tmp = dev->private; - if (!usbduxsub_tmp) { + if (index < 0) { printk(KERN_ERR - "comedi?: usbdux: detach without ptr to usbduxsub[]\n"); - return -EFAULT; - } + "comedi%d: usbdux: error: attach failed, no usbdux devs connected to the usb bus.\n", + dev->minor); + ret = -ENODEV; + } else + ret = usbdux_attach_common(dev, &usbduxsub[index], + aux_data, aux_len); + up(&start_stop_sem); + return ret; +} - dev_dbg(&usbduxsub_tmp->interface->dev, "comedi%d: detach usb device\n", - dev->minor); +/* is called from comedi_usb_auto_config() */ +static int usbdux_attach_usb(struct comedi_device *dev, + struct usb_interface *uinterf) +{ + int ret; + struct usbduxsub *this_usbduxsub; - down(&usbduxsub_tmp->sem); - /* Don't allow detach to free the private structure */ - /* It's one entry of of usbduxsub[] */ dev->private = NULL; - usbduxsub_tmp->attached = 0; - usbduxsub_tmp->comedidev = NULL; - dev_dbg(&usbduxsub_tmp->interface->dev, - "comedi%d: detach: successfully removed\n", dev->minor); - up(&usbduxsub_tmp->sem); - return 0; + + down(&start_stop_sem); + this_usbduxsub = usb_get_intfdata(uinterf); + if (!this_usbduxsub || !this_usbduxsub->probed) { + printk(KERN_ERR + "comedi%d: usbdux: error: attach_usb failed, not connected\n", + dev->minor); + ret = -ENODEV; + } else if (this_usbduxsub->attached) { + printk(KERN_ERR + "comedi%d: usbdux: error: attach_usb failed, already attached\n", + dev->minor); + ret = -ENODEV; + } else + ret = usbdux_attach_common(dev, this_usbduxsub, NULL, 0); + up(&start_stop_sem); + return ret; +} + +static void usbdux_detach(struct comedi_device *dev) +{ + struct usbduxsub *usb = dev->private; + + if (usb) { + down(&usb->sem); + dev->private = NULL; + usb->attached = 0; + usb->comedidev = NULL; + up(&usb->sem); + } } /* main driver struct */ @@ -2822,6 +2842,7 @@ static struct comedi_driver driver_usbdux = { .module = THIS_MODULE, .attach = usbdux_attach, .detach = usbdux_detach, + .attach_usb = usbdux_attach_usb, }; /* Table with the USB-devices: just now only testing IDs */ diff --git a/trunk/drivers/staging/comedi/drivers/usbduxfast.c b/trunk/drivers/staging/comedi/drivers/usbduxfast.c index 2a8e725b7859..7b1d21a6fc53 100644 --- a/trunk/drivers/staging/comedi/drivers/usbduxfast.c +++ b/trunk/drivers/staging/comedi/drivers/usbduxfast.c @@ -201,6 +201,8 @@ static struct usbduxfastsub_s usbduxfastsub[NUMUSBDUXFAST]; static DEFINE_SEMAPHORE(start_stop_sem); +static struct comedi_driver driver_usbduxfast; /* see below for initializer */ + /* * bulk transfers to usbduxfast */ @@ -453,14 +455,15 @@ static int usbduxfastsub_start(struct usbduxfastsub_s *udfs) /* 7f92 to zero */ local_transfer_buffer[0] = 0; /* bRequest, "Firmware" */ - ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), USBDUXFASTSUB_FIRMWARE, - VENDOR_DIR_OUT, /* bmRequestType */ - USBDUXFASTSUB_CPUCS, /* Value */ - 0x0000, /* Index */ - /* address of the transfer buffer */ - local_transfer_buffer, - 1, /* Length */ - EZTIMEOUT); /* Timeout */ + ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), + USBDUXFASTSUB_FIRMWARE, + VENDOR_DIR_OUT, /* bmRequestType */ + USBDUXFASTSUB_CPUCS, /* Value */ + 0x0000, /* Index */ + /* address of the transfer buffer */ + local_transfer_buffer, + 1, /* Length */ + EZTIMEOUT); /* Timeout */ if (ret < 0) { printk("comedi_: usbduxfast_: control msg failed (start)\n"); return ret; @@ -477,7 +480,8 @@ static int usbduxfastsub_stop(struct usbduxfastsub_s *udfs) /* 7f92 to one */ local_transfer_buffer[0] = 1; /* bRequest, "Firmware" */ - ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), USBDUXFASTSUB_FIRMWARE, + ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), + USBDUXFASTSUB_FIRMWARE, VENDOR_DIR_OUT, /* bmRequestType */ USBDUXFASTSUB_CPUCS, /* Value */ 0x0000, /* Index */ @@ -504,14 +508,15 @@ static int usbduxfastsub_upload(struct usbduxfastsub_s *udfs, startAddr, local_transfer_buffer[0]); #endif /* brequest, firmware */ - ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), USBDUXFASTSUB_FIRMWARE, - VENDOR_DIR_OUT, /* bmRequestType */ - startAddr, /* value */ - 0x0000, /* index */ - /* our local safe buffer */ - local_transfer_buffer, - len, /* length */ - EZTIMEOUT); /* timeout */ + ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), + USBDUXFASTSUB_FIRMWARE, + VENDOR_DIR_OUT, /* bmRequestType */ + startAddr, /* value */ + 0x0000, /* index */ + /* our local safe buffer */ + local_transfer_buffer, + len, /* length */ + EZTIMEOUT); /* timeout */ #ifdef CONFIG_COMEDI_DEBUG printk(KERN_DEBUG "comedi_: usbduxfast: result=%d\n", ret); @@ -1440,7 +1445,7 @@ static void usbduxfast_firmware_request_complete_handler(const struct firmware *fw, void *context) { struct usbduxfastsub_s *usbduxfastsub_tmp = context; - struct usb_device *usbdev = usbduxfastsub_tmp->usbdev; + struct usb_interface *uinterf = usbduxfastsub_tmp->interface; int ret; if (fw == NULL) @@ -1453,12 +1458,12 @@ static void usbduxfast_firmware_request_complete_handler(const struct firmware ret = firmwareUpload(usbduxfastsub_tmp, fw->data, fw->size); if (ret) { - dev_err(&usbdev->dev, + dev_err(&uinterf->dev, "Could not upload firmware (err=%d)\n", ret); goto out; } - comedi_usb_auto_config(usbdev, BOARDNAME); + comedi_usb_auto_config(uinterf, &driver_usbduxfast); out: release_firmware(fw); } @@ -1606,7 +1611,7 @@ static void usbduxfastsub_disconnect(struct usb_interface *intf) return; } - comedi_usb_auto_unconfig(udev); + comedi_usb_auto_unconfig(intf); down(&start_stop_sem); down(&udfs->sem); @@ -1721,43 +1726,19 @@ static int usbduxfast_attach(struct comedi_device *dev, return 0; } -static int usbduxfast_detach(struct comedi_device *dev) +static void usbduxfast_detach(struct comedi_device *dev) { - struct usbduxfastsub_s *udfs; - - if (!dev) { - printk(KERN_ERR "comedi?: usbduxfast: detach without dev " - "variable...\n"); - return -EFAULT; - } -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi%d: usbduxfast: detach usb device\n", - dev->minor); -#endif - - udfs = dev->private; - if (!udfs) { - printk(KERN_ERR "comedi?: usbduxfast: detach without ptr to " - "usbduxfastsub[]\n"); - return -EFAULT; + struct usbduxfastsub_s *usb = dev->private; + + if (usb) { + down(&usb->sem); + down(&start_stop_sem); + dev->private = NULL; + usb->attached = 0; + usb->comedidev = NULL; + up(&start_stop_sem); + up(&usb->sem); } - - down(&udfs->sem); - down(&start_stop_sem); - /* - * Don't allow detach to free the private structure - * It's one entry of of usbduxfastsub[] - */ - dev->private = NULL; - udfs->attached = 0; - udfs->comedidev = NULL; -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi%d: usbduxfast: detach: successfully " - "removed\n", dev->minor); -#endif - up(&start_stop_sem); - up(&udfs->sem); - return 0; } /* diff --git a/trunk/drivers/staging/comedi/drivers/usbduxsigma.c b/trunk/drivers/staging/comedi/drivers/usbduxsigma.c index 63c9b6dbc317..465afbdf4069 100644 --- a/trunk/drivers/staging/comedi/drivers/usbduxsigma.c +++ b/trunk/drivers/staging/comedi/drivers/usbduxsigma.c @@ -267,6 +267,8 @@ static struct usbduxsub usbduxsub[NUMUSBDUX]; static DEFINE_SEMAPHORE(start_stop_sem); +static struct comedi_driver driver_usbduxsigma; /* see below for initializer */ + /* * Stops the data acquision * It should be safe to call this function from any context @@ -2312,11 +2314,11 @@ static void usbdux_firmware_request_complete_handler(const struct firmware *fw, void *context) { struct usbduxsub *usbduxsub_tmp = context; - struct usb_device *usbdev = usbduxsub_tmp->usbdev; + struct usb_interface *uinterf = usbduxsub_tmp->interface; int ret; if (fw == NULL) { - dev_err(&usbdev->dev, + dev_err(&uinterf->dev, "Firmware complete handler without firmware!\n"); return; } @@ -2328,11 +2330,11 @@ static void usbdux_firmware_request_complete_handler(const struct firmware *fw, ret = firmwareUpload(usbduxsub_tmp, fw->data, fw->size); if (ret) { - dev_err(&usbdev->dev, + dev_err(&uinterf->dev, "Could not upload firmware (err=%d)\n", ret); goto out; } - comedi_usb_auto_config(usbdev, BOARDNAME); + comedi_usb_auto_config(uinterf, &driver_usbduxsigma); out: release_firmware(fw); } @@ -2623,7 +2625,7 @@ static void usbduxsigma_disconnect(struct usb_interface *intf) if (usbduxsub_tmp->ao_cmd_running) /* we are still running a command */ usbdux_ao_stop(usbduxsub_tmp, 1); - comedi_usb_auto_unconfig(udev); + comedi_usb_auto_unconfig(intf); down(&start_stop_sem); down(&usbduxsub_tmp->sem); tidy_up(usbduxsub_tmp); @@ -2799,37 +2801,17 @@ static int usbduxsigma_attach(struct comedi_device *dev, return 0; } -static int usbduxsigma_detach(struct comedi_device *dev) +static void usbduxsigma_detach(struct comedi_device *dev) { - struct usbduxsub *usbduxsub_tmp; + struct usbduxsub *usb = dev->private; - if (!dev) { - printk(KERN_ERR - "comedi? usbduxsigma detach: dev=NULL\n"); - return -EFAULT; + if (usb) { + down(&usb->sem); + dev->private = NULL; + usb->attached = 0; + usb->comedidev = NULL; + up(&usb->sem); } - - usbduxsub_tmp = dev->private; - if (!usbduxsub_tmp) { - printk(KERN_ERR - "comedi?: usbduxsigma detach: private=NULL\n"); - return -EFAULT; - } - - dev_dbg(&usbduxsub_tmp->interface->dev, - "comedi%d: detach usb device\n", - dev->minor); - - down(&usbduxsub_tmp->sem); - /* Don't allow detach to free the private structure */ - /* It's one entry of of usbduxsub[] */ - dev->private = NULL; - usbduxsub_tmp->attached = 0; - usbduxsub_tmp->comedidev = NULL; - dev_info(&usbduxsub_tmp->interface->dev, - "comedi%d: successfully detached.\n", dev->minor); - up(&usbduxsub_tmp->sem); - return 0; } /* main driver struct */ diff --git a/trunk/drivers/staging/comedi/drivers/vmk80xx.c b/trunk/drivers/staging/comedi/drivers/vmk80xx.c index 3d13ca6e1670..baee8d767636 100644 --- a/trunk/drivers/staging/comedi/drivers/vmk80xx.c +++ b/trunk/drivers/staging/comedi/drivers/vmk80xx.c @@ -151,27 +151,12 @@ MODULE_DEVICE_TABLE(usb, vmk80xx_id_table); #define URB_RCV_FLAG (1 << 0) #define URB_SND_FLAG (1 << 1) -#define CONFIG_VMK80XX_DEBUG -#undef CONFIG_VMK80XX_DEBUG - -#ifdef CONFIG_VMK80XX_DEBUG -static int dbgvm = 1; -#else -static int dbgvm; -#endif - #ifdef CONFIG_COMEDI_DEBUG static int dbgcm = 1; #else static int dbgcm; #endif -#define dbgvm(fmt, arg...) \ -do { \ - if (dbgvm) \ - printk(KERN_DEBUG fmt, ##arg); \ -} while (0) - #define dbgcm(fmt, arg...) \ do { \ if (dbgcm) \ @@ -247,13 +232,13 @@ static struct vmk80xx_usb vmb[VMK80XX_MAX_BOARDS]; static DEFINE_MUTEX(glb_mutex); +static struct comedi_driver driver_vmk80xx; /* see below for initializer */ + static void vmk80xx_tx_callback(struct urb *urb) { struct vmk80xx_usb *dev = urb->context; int stat = urb->status; - dbgvm("vmk80xx: %s\n", __func__); - if (stat && !(stat == -ENOENT || stat == -ECONNRESET || stat == -ESHUTDOWN)) dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n", @@ -272,8 +257,6 @@ static void vmk80xx_rx_callback(struct urb *urb) struct vmk80xx_usb *dev = urb->context; int stat = urb->status; - dbgvm("vmk80xx: %s\n", __func__); - switch (stat) { case 0: break; @@ -295,7 +278,9 @@ static void vmk80xx_rx_callback(struct urb *urb) if (!usb_submit_urb(urb, GFP_KERNEL)) goto exit; - err("comedi#: vmk80xx: %s - submit urb failed\n", __func__); + dev_err(&urb->dev->dev, + "comedi#: vmk80xx: %s - submit urb failed\n", + __func__); usb_unanchor_urb(urb); } @@ -312,8 +297,6 @@ static int vmk80xx_check_data_link(struct vmk80xx_usb *dev) unsigned char tx[1]; unsigned char rx[2]; - dbgvm("vmk80xx: %s\n", __func__); - tx_pipe = usb_sndbulkpipe(dev->udev, 0x01); rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81); @@ -338,8 +321,6 @@ static void vmk80xx_read_eeprom(struct vmk80xx_usb *dev, int flag) unsigned char rx[64]; int cnt; - dbgvm("vmk80xx: %s\n", __func__); - tx_pipe = usb_sndbulkpipe(dev->udev, 0x01); rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81); @@ -367,8 +348,6 @@ static int vmk80xx_reset_device(struct vmk80xx_usb *dev) int ival; size_t size; - dbgvm("vmk80xx: %s\n", __func__); - urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) return -ENOMEM; @@ -406,8 +385,6 @@ static void vmk80xx_build_int_urb(struct urb *urb, int flag) void (*callback) (struct urb *); int ival; - dbgvm("vmk80xx: %s\n", __func__); - if (flag & URB_RCV_FLAG) { rx_addr = dev->ep_rx->bEndpointAddress; pipe = usb_rcvintpipe(dev->udev, rx_addr); @@ -435,8 +412,6 @@ static void vmk80xx_do_bulk_msg(struct vmk80xx_usb *dev) unsigned int rx_pipe; size_t size; - dbgvm("vmk80xx: %s\n", __func__); - set_bit(TRANS_IN_BUSY, &dev->flags); set_bit(TRANS_OUT_BUSY, &dev->flags); @@ -464,8 +439,6 @@ static int vmk80xx_read_packet(struct vmk80xx_usb *dev) struct urb *urb; int retval; - dbgvm("vmk80xx: %s\n", __func__); - if (!dev->intf) return -ENODEV; @@ -512,8 +485,6 @@ static int vmk80xx_write_packet(struct vmk80xx_usb *dev, int cmd) struct urb *urb; int retval; - dbgvm("vmk80xx: %s\n", __func__); - if (!dev->intf) return -ENODEV; @@ -588,8 +559,6 @@ static int vmk80xx_ai_rinsn(struct comedi_device *cdev, int reg[2]; int n; - dbgvm("vmk80xx: %s\n", __func__); - n = rudimentary_check(dev, DIR_IN); if (n) return n; @@ -641,8 +610,6 @@ static int vmk80xx_ao_winsn(struct comedi_device *cdev, int reg; int n; - dbgvm("vmk80xx: %s\n", __func__); - n = rudimentary_check(dev, DIR_OUT); if (n) return n; @@ -686,8 +653,6 @@ static int vmk80xx_ao_rinsn(struct comedi_device *cdev, int reg; int n; - dbgvm("vmk80xx: %s\n", __func__); - n = rudimentary_check(dev, DIR_IN); if (n) return n; @@ -720,8 +685,6 @@ static int vmk80xx_di_bits(struct comedi_device *cdev, int reg; int retval; - dbgvm("vmk80xx: %s\n", __func__); - retval = rudimentary_check(dev, DIR_IN); if (retval) return retval; @@ -766,8 +729,6 @@ static int vmk80xx_di_rinsn(struct comedi_device *cdev, int inp; int n; - dbgvm("vmk80xx: %s\n", __func__); - n = rudimentary_check(dev, DIR_IN); if (n) return n; @@ -813,8 +774,6 @@ static int vmk80xx_do_winsn(struct comedi_device *cdev, int cmd; int n; - dbgvm("vmk80xx: %s\n", __func__); - n = rudimentary_check(dev, DIR_OUT); if (n) return n; @@ -861,8 +820,6 @@ static int vmk80xx_do_rinsn(struct comedi_device *cdev, int reg; int n; - dbgvm("vmk80xx: %s\n", __func__); - n = rudimentary_check(dev, DIR_IN); if (n) return n; @@ -895,8 +852,6 @@ static int vmk80xx_do_bits(struct comedi_device *cdev, int dir, reg, cmd; int retval; - dbgvm("vmk80xx: %s\n", __func__); - dir = 0; if (data[0]) @@ -962,8 +917,6 @@ static int vmk80xx_cnt_rinsn(struct comedi_device *cdev, int reg[2]; int n; - dbgvm("vmk80xx: %s\n", __func__); - n = rudimentary_check(dev, DIR_IN); if (n) return n; @@ -1012,18 +965,16 @@ static int vmk80xx_cnt_cinsn(struct comedi_device *cdev, int reg; int n; - dbgvm("vmk80xx: %s\n", __func__); - n = rudimentary_check(dev, DIR_OUT); if (n) return n; - down(&dev->limit_sem); - insn_cmd = data[0]; if (insn_cmd != INSN_CONFIG_RESET && insn_cmd != GPCT_RESET) return -EINVAL; + down(&dev->limit_sem); + chan = CR_CHAN(insn->chanspec); if (dev->board.model == VMK8055_MODEL) { @@ -1060,8 +1011,6 @@ static int vmk80xx_cnt_winsn(struct comedi_device *cdev, int cmd; int n; - dbgvm("vmk80xx: %s\n", __func__); - n = rudimentary_check(dev, DIR_OUT); if (n) return n; @@ -1106,8 +1055,6 @@ static int vmk80xx_pwm_rinsn(struct comedi_device *cdev, int reg[2]; int n; - dbgvm("vmk80xx: %s\n", __func__); - n = rudimentary_check(dev, DIR_IN); if (n) return n; @@ -1141,8 +1088,6 @@ static int vmk80xx_pwm_winsn(struct comedi_device *cdev, int cmd; int n; - dbgvm("vmk80xx: %s\n", __func__); - n = rudimentary_check(dev, DIR_OUT); if (n) return n; @@ -1191,8 +1136,6 @@ static int vmk80xx_attach(struct comedi_device *cdev, struct comedi_subdevice *s; int minor; - dbgvm("vmk80xx: %s\n", __func__); - mutex_lock(&glb_mutex); for (i = 0; i < VMK80XX_MAX_BOARDS; i++) @@ -1307,34 +1250,16 @@ static int vmk80xx_attach(struct comedi_device *cdev, return 0; } -static int vmk80xx_detach(struct comedi_device *cdev) +static void vmk80xx_detach(struct comedi_device *dev) { - struct vmk80xx_usb *dev; - int minor; - - dbgvm("vmk80xx: %s\n", __func__); - - if (!cdev) - return -EFAULT; - - dev = cdev->private; - if (!dev) - return -EFAULT; + struct vmk80xx_usb *usb = dev->private; - down(&dev->limit_sem); - - cdev->private = NULL; - dev->attached = 0; - - minor = cdev->minor; - - printk(KERN_INFO - "comedi%d: vmk80xx: board #%d [%s] detached from comedi\n", - minor, dev->count, dev->board.name); - - up(&dev->limit_sem); - - return 0; + if (usb) { + down(&usb->limit_sem); + dev->private = NULL; + usb->attached = 0; + up(&usb->limit_sem); + } } static int vmk80xx_probe(struct usb_interface *intf, @@ -1346,8 +1271,6 @@ static int vmk80xx_probe(struct usb_interface *intf, struct usb_endpoint_descriptor *ep_desc; size_t size; - dbgvm("vmk80xx: %s\n", __func__); - mutex_lock(&glb_mutex); for (i = 0; i < VMK80XX_MAX_BOARDS; i++) @@ -1482,7 +1405,7 @@ static int vmk80xx_probe(struct usb_interface *intf, mutex_unlock(&glb_mutex); - comedi_usb_auto_config(dev->udev, BOARDNAME); + comedi_usb_auto_config(intf, &driver_vmk80xx); return 0; error: @@ -1495,12 +1418,10 @@ static void vmk80xx_disconnect(struct usb_interface *intf) { struct vmk80xx_usb *dev = usb_get_intfdata(intf); - dbgvm("vmk80xx: %s\n", __func__); - if (!dev) return; - comedi_usb_auto_unconfig(dev->udev); + comedi_usb_auto_unconfig(intf); mutex_lock(&glb_mutex); down(&dev->limit_sem); diff --git a/trunk/drivers/staging/comedi/internal.h b/trunk/drivers/staging/comedi/internal.h index 434ce3433368..7ed20a04eef5 100644 --- a/trunk/drivers/staging/comedi/internal.h +++ b/trunk/drivers/staging/comedi/internal.h @@ -1,5 +1,5 @@ /* - * various internal comedi functions + * various internal comedi stuff */ int do_rangeinfo_ioctl(struct comedi_device *dev, struct comedi_rangeinfo __user *arg); @@ -7,6 +7,10 @@ int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); int comedi_alloc_board_minor(struct device *hardware_device); void comedi_free_board_minor(unsigned minor); +int comedi_find_board_minor(struct device *hardware_device); void comedi_reset_async_buf(struct comedi_async *async); int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long new_size); + +extern unsigned int comedi_default_buf_size_kb; +extern unsigned int comedi_default_buf_maxsize_kb; diff --git a/trunk/drivers/staging/et131x/et131x.c b/trunk/drivers/staging/et131x/et131x.c index 886f5650444e..5b11c5e3622e 100644 --- a/trunk/drivers/staging/et131x/et131x.c +++ b/trunk/drivers/staging/et131x/et131x.c @@ -1710,7 +1710,8 @@ static int et131x_mdio_read(struct mii_bus *bus, int phy_addr, int reg) return value; } -static int et131x_mdio_write(struct mii_bus *bus, int phy_addr, int reg, u16 value) +static int et131x_mdio_write(struct mii_bus *bus, int phy_addr, + int reg, u16 value) { struct net_device *netdev = bus->priv; struct et131x_adapter *adapter = netdev_priv(netdev); @@ -4013,7 +4014,7 @@ static int et131x_pci_init(struct et131x_adapter *adapter, dev_err(&pdev->dev, "Missing PCIe capabilities\n"); goto err_out; } - + /* Let's set up the PORT LOGIC Register. First we need to know what * the max_payload_size is */ @@ -4060,7 +4061,7 @@ static int et131x_pci_init(struct et131x_adapter *adapter, goto err_out; } - ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | ( 0x04 << 12); + ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | (0x04 << 12); if (pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl)) { dev_err(&pdev->dev, @@ -4824,7 +4825,8 @@ static int et131x_open(struct net_device *netdev) adapter->error_timer.data = (unsigned long)adapter; add_timer(&adapter->error_timer); - result = request_irq(irq, et131x_isr, IRQF_SHARED, netdev->name, netdev); + result = request_irq(irq, et131x_isr, + IRQF_SHARED, netdev->name, netdev); if (result) { dev_err(&pdev->dev, "could not register IRQ %d\n", irq); return result; diff --git a/trunk/drivers/staging/frontier/alphatrack.c b/trunk/drivers/staging/frontier/alphatrack.c index 3bf0f40e97fd..acbb2cc510f9 100644 --- a/trunk/drivers/staging/frontier/alphatrack.c +++ b/trunk/drivers/staging/frontier/alphatrack.c @@ -333,8 +333,8 @@ static int usb_alphatrack_open(struct inode *inode, struct file *file) interface = usb_find_interface(&usb_alphatrack_driver, subminor); if (!interface) { - err("%s - error, can't find device for minor %d\n", - __func__, subminor); + printk(KERN_ERR "%s - error, can't find device for minor %d\n", + __func__, subminor); retval = -ENODEV; goto unlock_disconnect_exit; } @@ -494,7 +494,8 @@ static ssize_t usb_alphatrack_read(struct file *file, char __user *buffer, /* verify that the device wasn't unplugged */ if (dev->intf == NULL) { retval = -ENODEV; - err("No device or device unplugged %d\n", retval); + printk(KERN_ERR "%s: No device or device unplugged %d\n", + __func__, retval); goto unlock_exit; } @@ -564,7 +565,8 @@ static ssize_t usb_alphatrack_write(struct file *file, /* verify that the device wasn't unplugged */ if (dev->intf == NULL) { retval = -ENODEV; - err("No device or device unplugged %d\n", retval); + printk(KERN_ERR "%s: No device or device unplugged %d\n", + __func__, retval); goto unlock_exit; } @@ -599,7 +601,7 @@ static ssize_t usb_alphatrack_write(struct file *file, } if (dev->interrupt_out_endpoint == NULL) { - err("Endpoint should not be be null!\n"); + dev_err(&dev->intf->dev, "Endpoint should not be be null!\n"); goto unlock_exit; } @@ -619,7 +621,8 @@ static ssize_t usb_alphatrack_write(struct file *file, retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL); if (retval) { dev->interrupt_out_busy = 0; - err("Couldn't submit interrupt_out_urb %d\n", retval); + dev_err(&dev->intf->dev, + "Couldn't submit interrupt_out_urb %d\n", retval); atomic_dec(&dev->writes_pending); goto unlock_exit; } diff --git a/trunk/drivers/staging/frontier/tranzport.c b/trunk/drivers/staging/frontier/tranzport.c index 29e99bbcae48..376706f1c712 100644 --- a/trunk/drivers/staging/frontier/tranzport.c +++ b/trunk/drivers/staging/frontier/tranzport.c @@ -353,7 +353,7 @@ static int usb_tranzport_open(struct inode *inode, struct file *file) interface = usb_find_interface(&usb_tranzport_driver, subminor); if (!interface) { - err("%s - error, can't find device for minor %d\n", + printk(KERN_ERR "%s - error, can't find device for minor %d\n", __func__, subminor); retval = -ENODEV; goto unlock_disconnect_exit; @@ -517,9 +517,11 @@ static ssize_t usb_tranzport_read(struct file *file, char __user *buffer, goto exit; } - /* verify that the device wasn't unplugged */ if (dev->intf == NULL) { + /* verify that the device wasn't unplugged */ + if (dev->intf == NULL) { retval = -ENODEV; - err("No device or device unplugged %d\n", retval); + printk(KERN_ERR "%s: No device or device unplugged %d\n", + __func__, retval); goto unlock_exit; } @@ -691,7 +693,8 @@ static ssize_t usb_tranzport_write(struct file *file, /* verify that the device wasn't unplugged */ if (dev->intf == NULL) { retval = -ENODEV; - err("No device or device unplugged %d\n", retval); + printk(KERN_ERR "%s: No device or device unplugged %d\n", + __func__, retval); goto unlock_exit; } @@ -726,7 +729,7 @@ static ssize_t usb_tranzport_write(struct file *file, } if (dev->interrupt_out_endpoint == NULL) { - err("Endpoint should not be be null!\n"); + dev_err(&dev->intf->dev, "Endpoint should not be be null!\n"); goto unlock_exit; } @@ -746,7 +749,8 @@ static ssize_t usb_tranzport_write(struct file *file, retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL); if (retval) { dev->interrupt_out_busy = 0; - err("Couldn't submit interrupt_out_urb %d\n", retval); + dev_err(&dev->intf->dev, + "Couldn't submit interrupt_out_urb %d\n", retval); goto unlock_exit; } retval = bytes_to_write; diff --git a/trunk/drivers/staging/gdm72xx/Kconfig b/trunk/drivers/staging/gdm72xx/Kconfig new file mode 100644 index 000000000000..3c18efe31365 --- /dev/null +++ b/trunk/drivers/staging/gdm72xx/Kconfig @@ -0,0 +1,46 @@ +# +# GCT GDM72xx WiMAX driver configuration +# + +menuconfig WIMAX_GDM72XX + tristate "GCT GDM72xx WiMAX support" + depends on NET + help + Support for the GCT GDM72xx WiMAX chip + +if WIMAX_GDM72XX + +config WIMAX_GDM72XX_QOS + bool "Enable QoS support" + default n + +config WIMAX_GDM72XX_K_MODE + bool "Enable K mode" + default n + +config WIMAX_GDM72XX_WIMAX2 + bool "Enable WIMAX2 support" + default n + +choice + prompt "Select interface" + +config WIMAX_GDM72XX_USB + bool "USB interface" + depends on USB + +config WIMAX_GDM72XX_SDIO + bool "SDIO interface" + depends on MMC + +endchoice + +if WIMAX_GDM72XX_USB + +config WIMAX_GDM72XX_USB_PM + bool "Enable power managerment support" + depends on USB_SUSPEND + +endif # WIMAX_GDM72XX_USB + +endif # WIMAX_GDM72XX diff --git a/trunk/drivers/staging/gdm72xx/Makefile b/trunk/drivers/staging/gdm72xx/Makefile new file mode 100644 index 000000000000..35da7b90b19b --- /dev/null +++ b/trunk/drivers/staging/gdm72xx/Makefile @@ -0,0 +1,6 @@ +obj-$(CONFIG_WIMAX_GDM72XX) := gdmwm.o + +gdmwm-y += gdm_wimax.o netlink_k.o +gdmwm-$(CONFIG_WIMAX_GDM72XX_QOS) += gdm_qos.o +gdmwm-$(CONFIG_WIMAX_GDM72XX_SDIO) += gdm_sdio.o sdio_boot.o +gdmwm-$(CONFIG_WIMAX_GDM72XX_USB) += gdm_usb.o usb_boot.o diff --git a/trunk/drivers/staging/gdm72xx/TODO b/trunk/drivers/staging/gdm72xx/TODO new file mode 100644 index 000000000000..30ac01ab972f --- /dev/null +++ b/trunk/drivers/staging/gdm72xx/TODO @@ -0,0 +1,5 @@ +TODO: +- Replace kernel_thread with kthread in gdm_usb.c +- Replace hard-coded firmware paths with request_firmware in + sdio_boot.c and usb_boot.c +- Clean up coding style to meet kernel standard. diff --git a/trunk/drivers/staging/gdm72xx/gdm_qos.c b/trunk/drivers/staging/gdm72xx/gdm_qos.c new file mode 100644 index 000000000000..0217680ec545 --- /dev/null +++ b/trunk/drivers/staging/gdm72xx/gdm_qos.c @@ -0,0 +1,460 @@ +/* + * Copyright (c) 2012 GCT Semiconductor, Inc. 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 + +#include "gdm_wimax.h" +#include "hci.h" +#include "gdm_qos.h" + +#define B2H(x) __be16_to_cpu(x) + +#undef dprintk +#define dprintk(fmt, args ...) printk(KERN_DEBUG "[QoS] " fmt, ## args) +#undef wprintk +#define wprintk(fmt, args ...) \ + printk(KERN_WARNING "[QoS WARNING] " fmt, ## args) +#undef eprintk +#define eprintk(fmt, args ...) printk(KERN_ERR "[QoS ERROR] " fmt, ## args) + + +#define MAX_FREE_LIST_CNT 32 +static struct { + struct list_head head; + int cnt; + spinlock_t lock; +} qos_free_list; + +static void init_qos_entry_list(void) +{ + qos_free_list.cnt = 0; + INIT_LIST_HEAD(&qos_free_list.head); + spin_lock_init(&qos_free_list.lock); +} + +static void *alloc_qos_entry(void) +{ + struct qos_entry_s *entry; + unsigned long flags; + + spin_lock_irqsave(&qos_free_list.lock, flags); + if (qos_free_list.cnt) { + entry = list_entry(qos_free_list.head.prev, struct qos_entry_s, + list); + list_del(&entry->list); + qos_free_list.cnt--; + spin_unlock_irqrestore(&qos_free_list.lock, flags); + return entry; + } + spin_unlock_irqrestore(&qos_free_list.lock, flags); + + entry = kmalloc(sizeof(struct qos_entry_s), GFP_ATOMIC); + return entry; +} + +static void free_qos_entry(void *entry) +{ + struct qos_entry_s *qentry = (struct qos_entry_s *) entry; + unsigned long flags; + + spin_lock_irqsave(&qos_free_list.lock, flags); + if (qos_free_list.cnt < MAX_FREE_LIST_CNT) { + list_add(&qentry->list, &qos_free_list.head); + qos_free_list.cnt++; + spin_unlock_irqrestore(&qos_free_list.lock, flags); + return; + } + spin_unlock_irqrestore(&qos_free_list.lock, flags); + + kfree(entry); +} + +static void free_qos_entry_list(struct list_head *free_list) +{ + struct qos_entry_s *entry, *n; + int total_free = 0; + + list_for_each_entry_safe(entry, n, free_list, list) { + list_del(&entry->list); + kfree(entry); + total_free++; + } + + dprintk("%s: total_free_cnt=%d\n", __func__, total_free); +} + +void gdm_qos_init(void *nic_ptr) +{ + struct nic *nic = nic_ptr; + struct qos_cb_s *qcb = &nic->qos; + int i; + + for (i = 0 ; i < QOS_MAX; i++) { + INIT_LIST_HEAD(&qcb->qos_list[i]); + qcb->csr[i].QoSBufCount = 0; + qcb->csr[i].Enabled = 0; + } + + qcb->qos_list_cnt = 0; + qcb->qos_null_idx = QOS_MAX-1; + qcb->qos_limit_size = 255; + + spin_lock_init(&qcb->qos_lock); + + init_qos_entry_list(); +} + +void gdm_qos_release_list(void *nic_ptr) +{ + struct nic *nic = nic_ptr; + struct qos_cb_s *qcb = &nic->qos; + unsigned long flags; + struct qos_entry_s *entry, *n; + struct list_head free_list; + int i; + + INIT_LIST_HEAD(&free_list); + + spin_lock_irqsave(&qcb->qos_lock, flags); + + for (i = 0; i < QOS_MAX; i++) { + qcb->csr[i].QoSBufCount = 0; + qcb->csr[i].Enabled = 0; + } + + qcb->qos_list_cnt = 0; + qcb->qos_null_idx = QOS_MAX-1; + + for (i = 0; i < QOS_MAX; i++) { + list_for_each_entry_safe(entry, n, &qcb->qos_list[i], list) { + list_move_tail(&entry->list, &free_list); + } + } + spin_unlock_irqrestore(&qcb->qos_lock, flags); + free_qos_entry_list(&free_list); +} + +static u32 chk_ipv4_rule(struct gdm_wimax_csr_s *csr, u8 *Stream, u8 *port) +{ + int i; + + if (csr->ClassifierRuleEnable&IPTYPEOFSERVICE) { + if (((Stream[1] & csr->IPToSMask) < csr->IPToSLow) || + ((Stream[1] & csr->IPToSMask) > csr->IPToSHigh)) + return 1; + } + + if (csr->ClassifierRuleEnable&PROTOCOL) { + if (Stream[9] != csr->Protocol) + return 1; + } + + if (csr->ClassifierRuleEnable&IPMASKEDSRCADDRESS) { + for (i = 0; i < 4; i++) { + if ((Stream[12 + i] & csr->IPSrcAddrMask[i]) != + (csr->IPSrcAddr[i] & csr->IPSrcAddrMask[i])) + return 1; + } + } + + if (csr->ClassifierRuleEnable&IPMASKEDDSTADDRESS) { + for (i = 0; i < 4; i++) { + if ((Stream[16 + i] & csr->IPDstAddrMask[i]) != + (csr->IPDstAddr[i] & csr->IPDstAddrMask[i])) + return 1; + } + } + + if (csr->ClassifierRuleEnable&PROTOCOLSRCPORTRANGE) { + i = ((port[0]<<8)&0xff00)+port[1]; + if ((i < csr->SrcPortLow) || (i > csr->SrcPortHigh)) + return 1; + } + + if (csr->ClassifierRuleEnable&PROTOCOLDSTPORTRANGE) { + i = ((port[2]<<8)&0xff00)+port[3]; + if ((i < csr->DstPortLow) || (i > csr->DstPortHigh)) + return 1; + } + + return 0; +} + +static u32 get_qos_index(struct nic *nic, u8* iph, u8* tcpudph) +{ + u32 IP_Ver, Header_Len, i; + struct qos_cb_s *qcb = &nic->qos; + + if (iph == NULL || tcpudph == NULL) + return -1; + + IP_Ver = (iph[0]>>4)&0xf; + Header_Len = iph[0]&0xf; + + if (IP_Ver == 4) { + for (i = 0; i < QOS_MAX; i++) { + if (qcb->csr[i].Enabled) { + if (qcb->csr[i].ClassifierRuleEnable) { + if (chk_ipv4_rule(&qcb->csr[i], iph, + tcpudph) == 0) + return i; + } + } + } + } + + return -1; +} + +static u32 extract_qos_list(struct nic *nic, struct list_head *head) +{ + struct qos_cb_s *qcb = &nic->qos; + struct qos_entry_s *entry; + int i; + + INIT_LIST_HEAD(head); + + for (i = 0; i < QOS_MAX; i++) { + if (qcb->csr[i].Enabled) { + if (qcb->csr[i].QoSBufCount < qcb->qos_limit_size) { + if (!list_empty(&qcb->qos_list[i])) { + entry = list_entry( + qcb->qos_list[i].prev, + struct qos_entry_s, list); + list_move_tail(&entry->list, head); + qcb->csr[i].QoSBufCount++; + + if (!list_empty(&qcb->qos_list[i])) + wprintk("QoS Index(%d) " + "is piled!!\n", i); + } + } + } + } + + return 0; +} + +static void send_qos_list(struct nic *nic, struct list_head *head) +{ + struct qos_entry_s *entry, *n; + + list_for_each_entry_safe(entry, n, head, list) { + list_del(&entry->list); + free_qos_entry(entry); + gdm_wimax_send_tx(entry->skb, entry->dev); + } +} + +int gdm_qos_send_hci_pkt(struct sk_buff *skb, struct net_device *dev) +{ + struct nic *nic = netdev_priv(dev); + int index; + struct qos_cb_s *qcb = &nic->qos; + unsigned long flags; + struct ethhdr *ethh = (struct ethhdr *) (skb->data + HCI_HEADER_SIZE); + struct iphdr *iph = (struct iphdr *) ((char *) ethh + ETH_HLEN); + struct tcphdr *tcph; + struct qos_entry_s *entry = NULL; + struct list_head send_list; + int ret = 0; + + tcph = (struct tcphdr *) iph + iph->ihl*4; + + if (B2H(ethh->h_proto) == ETH_P_IP) { + if (qcb->qos_list_cnt && !qos_free_list.cnt) { + entry = alloc_qos_entry(); + entry->skb = skb; + entry->dev = dev; + dprintk("qcb->qos_list_cnt=%d\n", qcb->qos_list_cnt); + } + + spin_lock_irqsave(&qcb->qos_lock, flags); + if (qcb->qos_list_cnt) { + index = get_qos_index(nic, (u8 *)iph, (u8 *) tcph); + if (index == -1) + index = qcb->qos_null_idx; + + if (!entry) { + entry = alloc_qos_entry(); + entry->skb = skb; + entry->dev = dev; + } + + list_add_tail(&entry->list, &qcb->qos_list[index]); + extract_qos_list(nic, &send_list); + spin_unlock_irqrestore(&qcb->qos_lock, flags); + send_qos_list(nic, &send_list); + goto out; + } + spin_unlock_irqrestore(&qcb->qos_lock, flags); + if (entry) + free_qos_entry(entry); + } + + ret = gdm_wimax_send_tx(skb, dev); +out: + return ret; +} + +static u32 get_csr(struct qos_cb_s *qcb, u32 SFID, int mode) +{ + int i; + + for (i = 0; i < qcb->qos_list_cnt; i++) { + if (qcb->csr[i].SFID == SFID) + return i; + } + + if (mode) { + for (i = 0; i < QOS_MAX; i++) { + if (qcb->csr[i].Enabled == 0) { + qcb->csr[i].Enabled = 1; + qcb->qos_list_cnt++; + return i; + } + } + } + return -1; +} + +#define QOS_CHANGE_DEL 0xFC +#define QOS_ADD 0xFD +#define QOS_REPORT 0xFE + +void gdm_recv_qos_hci_packet(void *nic_ptr, u8 *buf, int size) +{ + struct nic *nic = nic_ptr; + u32 i, SFID, index, pos; + u8 subCmdEvt; + u8 len; + struct qos_cb_s *qcb = &nic->qos; + struct qos_entry_s *entry, *n; + struct list_head send_list; + struct list_head free_list; + unsigned long flags; + + subCmdEvt = (u8)buf[4]; + + if (subCmdEvt == QOS_REPORT) { + len = (u8)buf[5]; + + spin_lock_irqsave(&qcb->qos_lock, flags); + for (i = 0; i < qcb->qos_list_cnt; i++) { + SFID = ((buf[(i*5)+6]<<24)&0xff000000); + SFID += ((buf[(i*5)+7]<<16)&0xff0000); + SFID += ((buf[(i*5)+8]<<8)&0xff00); + SFID += (buf[(i*5)+9]); + index = get_csr(qcb, SFID, 0); + if (index == -1) { + spin_unlock_irqrestore(&qcb->qos_lock, flags); + eprintk("QoS ERROR: No SF\n"); + return; + } + qcb->csr[index].QoSBufCount = buf[(i*5)+10]; + } + + extract_qos_list(nic, &send_list); + spin_unlock_irqrestore(&qcb->qos_lock, flags); + send_qos_list(nic, &send_list); + return; + } else if (subCmdEvt == QOS_ADD) { + pos = 5; + len = (u8)buf[pos++]; + + SFID = ((buf[pos++]<<24)&0xff000000); + SFID += ((buf[pos++]<<16)&0xff0000); + SFID += ((buf[pos++]<<8)&0xff00); + SFID += (buf[pos++]); + + index = get_csr(qcb, SFID, 1); + if (index == -1) { + eprintk("QoS ERROR: csr Update Error\n"); + return; + } + + dprintk("QOS_ADD SFID = 0x%x, index=%d\n", SFID, index); + + spin_lock_irqsave(&qcb->qos_lock, flags); + qcb->csr[index].SFID = SFID; + qcb->csr[index].ClassifierRuleEnable = ((buf[pos++]<<8)&0xff00); + qcb->csr[index].ClassifierRuleEnable += buf[pos++]; + if (qcb->csr[index].ClassifierRuleEnable == 0) + qcb->qos_null_idx = index; + qcb->csr[index].IPToSMask = buf[pos++]; + qcb->csr[index].IPToSLow = buf[pos++]; + qcb->csr[index].IPToSHigh = buf[pos++]; + qcb->csr[index].Protocol = buf[pos++]; + qcb->csr[index].IPSrcAddrMask[0] = buf[pos++]; + qcb->csr[index].IPSrcAddrMask[1] = buf[pos++]; + qcb->csr[index].IPSrcAddrMask[2] = buf[pos++]; + qcb->csr[index].IPSrcAddrMask[3] = buf[pos++]; + qcb->csr[index].IPSrcAddr[0] = buf[pos++]; + qcb->csr[index].IPSrcAddr[1] = buf[pos++]; + qcb->csr[index].IPSrcAddr[2] = buf[pos++]; + qcb->csr[index].IPSrcAddr[3] = buf[pos++]; + qcb->csr[index].IPDstAddrMask[0] = buf[pos++]; + qcb->csr[index].IPDstAddrMask[1] = buf[pos++]; + qcb->csr[index].IPDstAddrMask[2] = buf[pos++]; + qcb->csr[index].IPDstAddrMask[3] = buf[pos++]; + qcb->csr[index].IPDstAddr[0] = buf[pos++]; + qcb->csr[index].IPDstAddr[1] = buf[pos++]; + qcb->csr[index].IPDstAddr[2] = buf[pos++]; + qcb->csr[index].IPDstAddr[3] = buf[pos++]; + qcb->csr[index].SrcPortLow = ((buf[pos++]<<8)&0xff00); + qcb->csr[index].SrcPortLow += buf[pos++]; + qcb->csr[index].SrcPortHigh = ((buf[pos++]<<8)&0xff00); + qcb->csr[index].SrcPortHigh += buf[pos++]; + qcb->csr[index].DstPortLow = ((buf[pos++]<<8)&0xff00); + qcb->csr[index].DstPortLow += buf[pos++]; + qcb->csr[index].DstPortHigh = ((buf[pos++]<<8)&0xff00); + qcb->csr[index].DstPortHigh += buf[pos++]; + + qcb->qos_limit_size = 254/qcb->qos_list_cnt; + spin_unlock_irqrestore(&qcb->qos_lock, flags); + } else if (subCmdEvt == QOS_CHANGE_DEL) { + pos = 5; + len = (u8)buf[pos++]; + SFID = ((buf[pos++]<<24)&0xff000000); + SFID += ((buf[pos++]<<16)&0xff0000); + SFID += ((buf[pos++]<<8)&0xff00); + SFID += (buf[pos++]); + index = get_csr(qcb, SFID, 1); + if (index == -1) { + eprintk("QoS ERROR: Wrong index(%d)\n", index); + return; + } + + dprintk("QOS_CHANGE_DEL SFID = 0x%x, index=%d\n", SFID, index); + + INIT_LIST_HEAD(&free_list); + + spin_lock_irqsave(&qcb->qos_lock, flags); + qcb->csr[index].Enabled = 0; + qcb->qos_list_cnt--; + qcb->qos_limit_size = 254/qcb->qos_list_cnt; + + list_for_each_entry_safe(entry, n, &qcb->qos_list[index], + list) { + list_move_tail(&entry->list, &free_list); + } + spin_unlock_irqrestore(&qcb->qos_lock, flags); + free_qos_entry_list(&free_list); + } +} diff --git a/trunk/drivers/staging/gdm72xx/gdm_qos.h b/trunk/drivers/staging/gdm72xx/gdm_qos.h new file mode 100644 index 000000000000..33f2bd4cee32 --- /dev/null +++ b/trunk/drivers/staging/gdm72xx/gdm_qos.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2012 GCT Semiconductor, Inc. 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. + */ + +#if !defined(GDM_QOS_H_20090403) +#define GDM_QOS_H_20090403 + +#include +#include +#include + +#define BOOLEAN u8 + +#define QOS_MAX 16 +#define IPTYPEOFSERVICE 0x8000 +#define PROTOCOL 0x4000 +#define IPMASKEDSRCADDRESS 0x2000 +#define IPMASKEDDSTADDRESS 0x1000 +#define PROTOCOLSRCPORTRANGE 0x800 +#define PROTOCOLDSTPORTRANGE 0x400 +#define DSTMACADDR 0x200 +#define SRCMACADDR 0x100 +#define ETHERTYPE 0x80 +#define IEEE802_1DUSERPRIORITY 0x40 +#define IEEE802_1QVLANID 0x10 + +struct gdm_wimax_csr_s { + /* union{ + U16 all; + struct _CS_CLASSIFIER_RULE_ENABLE{ + IPTypeOfService:1, + Protocol:1, + IPMaskedSrcAddress:1, + IPMaskedDstAddress:1, + ProtocolSrcPortRange:1, + ProtocolDstPortRange:1, + DstMacAddr:1, + SrcMacAddr:1, + Ethertype:1, + IEEE802_1DUserPriority:1, + IEEE802_1QVLANID:1, + Reserved:5; + } fields; + } */ + BOOLEAN Enabled; + u32 SFID; + u8 QoSBufCount; + u16 ClassifierRuleEnable; + u8 IPToSLow; + u8 IPToSHigh; + u8 IPToSMask; + u8 Protocol; + u8 IPSrcAddr[16]; + u8 IPSrcAddrMask[16]; + u8 IPDstAddr[16]; + u8 IPDstAddrMask[16]; + u16 SrcPortLow; + u16 SrcPortHigh; + u16 DstPortLow; + u16 DstPortHigh; +}; + +struct qos_entry_s { + struct list_head list; + struct sk_buff *skb; + struct net_device *dev; + +}; + +struct qos_cb_s { + struct list_head qos_list[QOS_MAX]; + u32 qos_list_cnt; + u32 qos_null_idx; + struct gdm_wimax_csr_s csr[QOS_MAX]; + spinlock_t qos_lock; + u32 qos_limit_size; +}; + +void gdm_qos_init(void *nic_ptr); +void gdm_qos_release_list(void *nic_ptr); +int gdm_qos_send_hci_pkt(struct sk_buff *skb, struct net_device *dev); +void gdm_recv_qos_hci_packet(void *nic_ptr, u8 *buf, int size); + +#endif diff --git a/trunk/drivers/staging/gdm72xx/gdm_sdio.c b/trunk/drivers/staging/gdm72xx/gdm_sdio.c new file mode 100644 index 000000000000..e1a3dd2fc4af --- /dev/null +++ b/trunk/drivers/staging/gdm72xx/gdm_sdio.c @@ -0,0 +1,754 @@ +/* + * Copyright (c) 2012 GCT Semiconductor, Inc. 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 +#include +#include + +#include "gdm_sdio.h" +#include "gdm_wimax.h" +#include "sdio_boot.h" +#include "hci.h" + +#define TYPE_A_HEADER_SIZE 4 +#define TYPE_A_LOOKAHEAD_SIZE 16 + +#define MAX_NR_RX_BUF 4 + +#define SDU_TX_BUF_SIZE 2048 +#define TX_BUF_SIZE 2048 +#define TX_CHUNK_SIZE (2048 - TYPE_A_HEADER_SIZE) +#define RX_BUF_SIZE (25*1024) + +#define TX_HZ 2000 +#define TX_INTERVAL (1000000/TX_HZ) + +/*#define DEBUG*/ + +static int init_sdio(struct sdiowm_dev *sdev); +static void release_sdio(struct sdiowm_dev *sdev); + +#ifdef DEBUG +static void hexdump(char *title, u8 *data, int len) +{ + int i; + + printk(KERN_DEBUG "%s: length = %d\n", title, len); + for (i = 0; i < len; i++) { + printk(KERN_DEBUG "%02x ", data[i]); + if ((i & 0xf) == 0xf) + printk(KERN_DEBUG "\n"); + } + printk(KERN_DEBUG "\n"); +} +#endif + +static struct sdio_tx *alloc_tx_struct(struct tx_cxt *tx) +{ + struct sdio_tx *t = NULL; + + t = kmalloc(sizeof(*t), GFP_ATOMIC); + if (t == NULL) + goto out; + + memset(t, 0, sizeof(*t)); + + t->buf = kmalloc(TX_BUF_SIZE, GFP_ATOMIC); + if (t->buf == NULL) + goto out; + + t->tx_cxt = tx; + + return t; +out: + if (t) { + kfree(t->buf); + kfree(t); + } + return NULL; +} + +static void free_tx_struct(struct sdio_tx *t) +{ + if (t) { + kfree(t->buf); + kfree(t); + } +} + +static struct sdio_rx *alloc_rx_struct(struct rx_cxt *rx) +{ + struct sdio_rx *r = NULL; + + r = kmalloc(sizeof(*r), GFP_ATOMIC); + if (r == NULL) + goto out; + + memset(r, 0, sizeof(*r)); + + r->rx_cxt = rx; + + return r; +out: + kfree(r); + return NULL; +} + +static void free_rx_struct(struct sdio_rx *r) +{ + kfree(r); +} + +/* Before this function is called, spin lock should be locked. */ +static struct sdio_tx *get_tx_struct(struct tx_cxt *tx, int *no_spc) +{ + struct sdio_tx *t; + + if (list_empty(&tx->free_list)) + return NULL; + + t = list_entry(tx->free_list.prev, struct sdio_tx, list); + list_del(&t->list); + + *no_spc = list_empty(&tx->free_list) ? 1 : 0; + + return t; +} + +/* Before this function is called, spin lock should be locked. */ +static void put_tx_struct(struct tx_cxt *tx, struct sdio_tx *t) +{ + list_add_tail(&t->list, &tx->free_list); +} + +/* Before this function is called, spin lock should be locked. */ +static struct sdio_rx *get_rx_struct(struct rx_cxt *rx) +{ + struct sdio_rx *r; + + if (list_empty(&rx->free_list)) + return NULL; + + r = list_entry(rx->free_list.prev, struct sdio_rx, list); + list_del(&r->list); + + return r; +} + +/* Before this function is called, spin lock should be locked. */ +static void put_rx_struct(struct rx_cxt *rx, struct sdio_rx *r) +{ + list_add_tail(&r->list, &rx->free_list); +} + +static int init_sdio(struct sdiowm_dev *sdev) +{ + int ret = 0, i; + struct tx_cxt *tx = &sdev->tx; + struct rx_cxt *rx = &sdev->rx; + struct sdio_tx *t; + struct sdio_rx *r; + + INIT_LIST_HEAD(&tx->free_list); + INIT_LIST_HEAD(&tx->sdu_list); + INIT_LIST_HEAD(&tx->hci_list); + + spin_lock_init(&tx->lock); + + tx->sdu_buf = kmalloc(SDU_TX_BUF_SIZE, GFP_KERNEL); + if (tx->sdu_buf == NULL) { + printk(KERN_ERR "Failed to allocate SDU tx buffer.\n"); + goto fail; + } + + for (i = 0; i < MAX_NR_SDU_BUF; i++) { + t = alloc_tx_struct(tx); + if (t == NULL) { + ret = -ENOMEM; + goto fail; + } + list_add(&t->list, &tx->free_list); + } + + INIT_LIST_HEAD(&rx->free_list); + INIT_LIST_HEAD(&rx->req_list); + + spin_lock_init(&rx->lock); + + for (i = 0; i < MAX_NR_RX_BUF; i++) { + r = alloc_rx_struct(rx); + if (r == NULL) { + ret = -ENOMEM; + goto fail; + } + list_add(&r->list, &rx->free_list); + } + + rx->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL); + if (rx->rx_buf == NULL) { + printk(KERN_ERR "Failed to allocate rx buffer.\n"); + goto fail; + } + + return 0; + +fail: + release_sdio(sdev); + return ret; +} + +static void release_sdio(struct sdiowm_dev *sdev) +{ + struct tx_cxt *tx = &sdev->tx; + struct rx_cxt *rx = &sdev->rx; + struct sdio_tx *t, *t_next; + struct sdio_rx *r, *r_next; + + kfree(tx->sdu_buf); + + list_for_each_entry_safe(t, t_next, &tx->free_list, list) { + list_del(&t->list); + free_tx_struct(t); + } + + list_for_each_entry_safe(t, t_next, &tx->sdu_list, list) { + list_del(&t->list); + free_tx_struct(t); + } + + list_for_each_entry_safe(t, t_next, &tx->hci_list, list) { + list_del(&t->list); + free_tx_struct(t); + } + + kfree(rx->rx_buf); + + list_for_each_entry_safe(r, r_next, &rx->free_list, list) { + list_del(&r->list); + free_rx_struct(r); + } + + list_for_each_entry_safe(r, r_next, &rx->req_list, list) { + list_del(&r->list); + free_rx_struct(r); + } +} + +static void send_sdio_pkt(struct sdio_func *func, u8 *data, int len) +{ + int n, blocks, ret, remain; + + sdio_claim_host(func); + + blocks = len / func->cur_blksize; + n = blocks * func->cur_blksize; + if (blocks) { + ret = sdio_memcpy_toio(func, 0, data, n); + if (ret < 0) { + if (ret != -ENOMEDIUM) + printk(KERN_ERR "gdmwms: %s error: ret = %d\n", + __func__, ret); + goto end_io; + } + } + + remain = len - n; + remain = (remain + 3) & ~3; + + if (remain) { + ret = sdio_memcpy_toio(func, 0, data + n, remain); + if (ret < 0) { + if (ret != -ENOMEDIUM) + printk(KERN_ERR "gdmwms: %s error: ret = %d\n", + __func__, ret); + goto end_io; + } + } + +end_io: + sdio_release_host(func); +} + +static void send_sdu(struct sdio_func *func, struct tx_cxt *tx) +{ + struct list_head *l, *next; + struct hci_s *hci; + struct sdio_tx *t; + int pos, len, i, estlen, aggr_num = 0, aggr_len; + u8 *buf; + unsigned long flags; + + spin_lock_irqsave(&tx->lock, flags); + + pos = TYPE_A_HEADER_SIZE + HCI_HEADER_SIZE; + list_for_each_entry(t, &tx->sdu_list, list) { + estlen = ((t->len + 3) & ~3) + 4; + if ((pos + estlen) > SDU_TX_BUF_SIZE) + break; + + aggr_num++; + memcpy(tx->sdu_buf + pos, t->buf, t->len); + memset(tx->sdu_buf + pos + t->len, 0, estlen - t->len); + pos += estlen; + } + aggr_len = pos; + + hci = (struct hci_s *)(tx->sdu_buf + TYPE_A_HEADER_SIZE); + hci->cmd_evt = H2B(WIMAX_TX_SDU_AGGR); + hci->length = H2B(aggr_len - TYPE_A_HEADER_SIZE - HCI_HEADER_SIZE); + + spin_unlock_irqrestore(&tx->lock, flags); + +#ifdef DEBUG + hexdump("sdio_send", tx->sdu_buf + TYPE_A_HEADER_SIZE, + aggr_len - TYPE_A_HEADER_SIZE); +#endif + + for (pos = TYPE_A_HEADER_SIZE; pos < aggr_len; pos += TX_CHUNK_SIZE) { + len = aggr_len - pos; + len = len > TX_CHUNK_SIZE ? TX_CHUNK_SIZE : len; + buf = tx->sdu_buf + pos - TYPE_A_HEADER_SIZE; + + buf[0] = len & 0xff; + buf[1] = (len >> 8) & 0xff; + buf[2] = (len >> 16) & 0xff; + buf[3] = (pos + len) >= aggr_len ? 0 : 1; + send_sdio_pkt(func, buf, len + TYPE_A_HEADER_SIZE); + } + + spin_lock_irqsave(&tx->lock, flags); + + for (l = tx->sdu_list.next, i = 0; i < aggr_num; i++, l = next) { + next = l->next; + t = list_entry(l, struct sdio_tx, list); + if (t->callback) + t->callback(t->cb_data); + + list_del(l); + put_tx_struct(t->tx_cxt, t); + } + + do_gettimeofday(&tx->sdu_stamp); + spin_unlock_irqrestore(&tx->lock, flags); +} + +static void send_hci(struct sdio_func *func, struct tx_cxt *tx, + struct sdio_tx *t) +{ + unsigned long flags; + +#ifdef DEBUG + hexdump("sdio_send", t->buf + TYPE_A_HEADER_SIZE, + t->len - TYPE_A_HEADER_SIZE); +#endif + send_sdio_pkt(func, t->buf, t->len); + + spin_lock_irqsave(&tx->lock, flags); + if (t->callback) + t->callback(t->cb_data); + free_tx_struct(t); + spin_unlock_irqrestore(&tx->lock, flags); +} + +static void do_tx(struct work_struct *work) +{ + struct sdiowm_dev *sdev = container_of(work, struct sdiowm_dev, ws); + struct sdio_func *func = sdev->func; + struct tx_cxt *tx = &sdev->tx; + struct sdio_tx *t = NULL; + struct timeval now, *before; + int is_sdu = 0; + long diff; + unsigned long flags; + + spin_lock_irqsave(&tx->lock, flags); + if (!tx->can_send) { + spin_unlock_irqrestore(&tx->lock, flags); + return; + } + + if (!list_empty(&tx->hci_list)) { + t = list_entry(tx->hci_list.next, struct sdio_tx, list); + list_del(&t->list); + is_sdu = 0; + } else if (!tx->stop_sdu_tx && !list_empty(&tx->sdu_list)) { + do_gettimeofday(&now); + before = &tx->sdu_stamp; + + diff = (now.tv_sec - before->tv_sec) * 1000000 + + (now.tv_usec - before->tv_usec); + if (diff >= 0 && diff < TX_INTERVAL) { + schedule_work(&sdev->ws); + spin_unlock_irqrestore(&tx->lock, flags); + return; + } + is_sdu = 1; + } + + if (!is_sdu && t == NULL) { + spin_unlock_irqrestore(&tx->lock, flags); + return; + } + + tx->can_send = 0; + + spin_unlock_irqrestore(&tx->lock, flags); + + if (is_sdu) + send_sdu(func, tx); + else + send_hci(func, tx, t); +} + +static int gdm_sdio_send(void *priv_dev, void *data, int len, + void (*cb)(void *data), void *cb_data) +{ + struct sdiowm_dev *sdev = priv_dev; + struct tx_cxt *tx = &sdev->tx; + struct sdio_tx *t; + u8 *pkt = data; + int no_spc = 0; + u16 cmd_evt; + unsigned long flags; + + BUG_ON(len > TX_BUF_SIZE - TYPE_A_HEADER_SIZE); + + spin_lock_irqsave(&tx->lock, flags); + + cmd_evt = (pkt[0] << 8) | pkt[1]; + if (cmd_evt == WIMAX_TX_SDU) { + t = get_tx_struct(tx, &no_spc); + if (t == NULL) { + /* This case must not happen. */ + spin_unlock_irqrestore(&tx->lock, flags); + return -ENOSPC; + } + list_add_tail(&t->list, &tx->sdu_list); + + memcpy(t->buf, data, len); + + t->len = len; + t->callback = cb; + t->cb_data = cb_data; + } else { + t = alloc_tx_struct(tx); + if (t == NULL) { + spin_unlock_irqrestore(&tx->lock, flags); + return -ENOMEM; + } + list_add_tail(&t->list, &tx->hci_list); + + t->buf[0] = len & 0xff; + t->buf[1] = (len >> 8) & 0xff; + t->buf[2] = (len >> 16) & 0xff; + t->buf[3] = 2; + memcpy(t->buf + TYPE_A_HEADER_SIZE, data, len); + + t->len = len + TYPE_A_HEADER_SIZE; + t->callback = cb; + t->cb_data = cb_data; + } + + if (tx->can_send) + schedule_work(&sdev->ws); + + spin_unlock_irqrestore(&tx->lock, flags); + + if (no_spc) + return -ENOSPC; + + return 0; +} + +/* + * Handle the HCI, WIMAX_SDU_TX_FLOW. + */ +static int control_sdu_tx_flow(struct sdiowm_dev *sdev, u8 *hci_data, int len) +{ + struct tx_cxt *tx = &sdev->tx; + u16 cmd_evt; + unsigned long flags; + + spin_lock_irqsave(&tx->lock, flags); + + cmd_evt = (hci_data[0] << 8) | (hci_data[1]); + if (cmd_evt != WIMAX_SDU_TX_FLOW) + goto out; + + if (hci_data[4] == 0) { +#ifdef DEBUG + printk(KERN_DEBUG "WIMAX ==> STOP SDU TX\n"); +#endif + tx->stop_sdu_tx = 1; + } else if (hci_data[4] == 1) { +#ifdef DEBUG + printk(KERN_DEBUG "WIMAX ==> START SDU TX\n"); +#endif + tx->stop_sdu_tx = 0; + if (tx->can_send) + schedule_work(&sdev->ws); + /* + * If free buffer for sdu tx doesn't exist, then tx queue + * should not be woken. For this reason, don't pass the command, + * START_SDU_TX. + */ + if (list_empty(&tx->free_list)) + len = 0; + } + +out: + spin_unlock_irqrestore(&tx->lock, flags); + return len; +} + +static void gdm_sdio_irq(struct sdio_func *func) +{ + struct phy_dev *phy_dev = sdio_get_drvdata(func); + struct sdiowm_dev *sdev = phy_dev->priv_dev; + struct tx_cxt *tx = &sdev->tx; + struct rx_cxt *rx = &sdev->rx; + struct sdio_rx *r; + unsigned long flags; + u8 val, hdr[TYPE_A_LOOKAHEAD_SIZE], *buf; + u32 len, blocks, n; + int ret, remain; + + /* Check interrupt */ + val = sdio_readb(func, 0x13, &ret); + if (val & 0x01) + sdio_writeb(func, 0x01, 0x13, &ret); /* clear interrupt */ + else + return; + + ret = sdio_memcpy_fromio(func, hdr, 0x0, TYPE_A_LOOKAHEAD_SIZE); + if (ret) { + printk(KERN_ERR "Cannot read from function %d\n", func->num); + goto done; + } + + len = (hdr[2] << 16) | (hdr[1] << 8) | hdr[0]; + if (len > (RX_BUF_SIZE - TYPE_A_HEADER_SIZE)) { + printk(KERN_ERR "Too big Type-A size: %d\n", len); + goto done; + } + + if (hdr[3] == 1) { /* Ack */ +#ifdef DEBUG + u32 *ack_seq = (u32 *)&hdr[4]; +#endif + spin_lock_irqsave(&tx->lock, flags); + tx->can_send = 1; + + if (!list_empty(&tx->sdu_list) || !list_empty(&tx->hci_list)) + schedule_work(&sdev->ws); + spin_unlock_irqrestore(&tx->lock, flags); +#ifdef DEBUG + printk(KERN_DEBUG "Ack... %0x\n", ntohl(*ack_seq)); +#endif + goto done; + } + + memcpy(rx->rx_buf, hdr + TYPE_A_HEADER_SIZE, + TYPE_A_LOOKAHEAD_SIZE - TYPE_A_HEADER_SIZE); + + buf = rx->rx_buf + TYPE_A_LOOKAHEAD_SIZE - TYPE_A_HEADER_SIZE; + remain = len - TYPE_A_LOOKAHEAD_SIZE + TYPE_A_HEADER_SIZE; + if (remain <= 0) + goto end_io; + + blocks = remain / func->cur_blksize; + + if (blocks) { + n = blocks * func->cur_blksize; + ret = sdio_memcpy_fromio(func, buf, 0x0, n); + if (ret) { + printk(KERN_ERR "Cannot read from function %d\n", + func->num); + goto done; + } + buf += n; + remain -= n; + } + + if (remain) { + ret = sdio_memcpy_fromio(func, buf, 0x0, remain); + if (ret) { + printk(KERN_ERR "Cannot read from function %d\n", + func->num); + goto done; + } + } + +end_io: +#ifdef DEBUG + hexdump("sdio_receive", rx->rx_buf, len); +#endif + len = control_sdu_tx_flow(sdev, rx->rx_buf, len); + + spin_lock_irqsave(&rx->lock, flags); + + if (!list_empty(&rx->req_list)) { + r = list_entry(rx->req_list.next, struct sdio_rx, list); + spin_unlock_irqrestore(&rx->lock, flags); + if (r->callback) + r->callback(r->cb_data, rx->rx_buf, len); + spin_lock_irqsave(&rx->lock, flags); + list_del(&r->list); + put_rx_struct(rx, r); + } + + spin_unlock_irqrestore(&rx->lock, flags); + +done: + sdio_writeb(func, 0x00, 0x10, &ret); /* PCRRT */ + if (!phy_dev->netdev) + register_wimax_device(phy_dev, &func->dev); +} + +static int gdm_sdio_receive(void *priv_dev, + void (*cb)(void *cb_data, void *data, int len), + void *cb_data) +{ + struct sdiowm_dev *sdev = priv_dev; + struct rx_cxt *rx = &sdev->rx; + struct sdio_rx *r; + unsigned long flags; + + spin_lock_irqsave(&rx->lock, flags); + r = get_rx_struct(rx); + if (r == NULL) { + spin_unlock_irqrestore(&rx->lock, flags); + return -ENOMEM; + } + + r->callback = cb; + r->cb_data = cb_data; + + list_add_tail(&r->list, &rx->req_list); + spin_unlock_irqrestore(&rx->lock, flags); + + return 0; +} + +static int sdio_wimax_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + int ret; + struct phy_dev *phy_dev = NULL; + struct sdiowm_dev *sdev = NULL; + + printk(KERN_INFO "Found GDM SDIO VID = 0x%04x PID = 0x%04x...\n", + func->vendor, func->device); + printk(KERN_INFO "GCT WiMax driver version %s\n", DRIVER_VERSION); + + sdio_claim_host(func); + sdio_enable_func(func); + sdio_claim_irq(func, gdm_sdio_irq); + + ret = sdio_boot(func); + if (ret) + return ret; + + phy_dev = kmalloc(sizeof(*phy_dev), GFP_KERNEL); + if (phy_dev == NULL) { + ret = -ENOMEM; + goto out; + } + sdev = kmalloc(sizeof(*sdev), GFP_KERNEL); + if (sdev == NULL) { + ret = -ENOMEM; + goto out; + } + + memset(phy_dev, 0, sizeof(*phy_dev)); + memset(sdev, 0, sizeof(*sdev)); + + phy_dev->priv_dev = (void *)sdev; + phy_dev->send_func = gdm_sdio_send; + phy_dev->rcv_func = gdm_sdio_receive; + + ret = init_sdio(sdev); + if (sdev < 0) + goto out; + + sdev->func = func; + + sdio_writeb(func, 1, 0x14, &ret); /* Enable interrupt */ + sdio_release_host(func); + + INIT_WORK(&sdev->ws, do_tx); + + sdio_set_drvdata(func, phy_dev); +out: + if (ret) { + kfree(phy_dev); + kfree(sdev); + } + + return ret; +} + +static void sdio_wimax_remove(struct sdio_func *func) +{ + struct phy_dev *phy_dev = sdio_get_drvdata(func); + struct sdiowm_dev *sdev = phy_dev->priv_dev; + + if (phy_dev->netdev) + unregister_wimax_device(phy_dev); + sdio_claim_host(func); + sdio_release_irq(func); + sdio_disable_func(func); + sdio_release_host(func); + release_sdio(sdev); + + kfree(sdev); + kfree(phy_dev); +} + +static const struct sdio_device_id sdio_wimax_ids[] = { + { SDIO_DEVICE(0x0296, 0x5347) }, + {0} +}; + +MODULE_DEVICE_TABLE(sdio, sdio_wimax_ids); + +static struct sdio_driver sdio_wimax_driver = { + .probe = sdio_wimax_probe, + .remove = sdio_wimax_remove, + .name = "sdio_wimax", + .id_table = sdio_wimax_ids, +}; + +static int __init sdio_gdm_wimax_init(void) +{ + return sdio_register_driver(&sdio_wimax_driver); +} + +static void __exit sdio_gdm_wimax_exit(void) +{ + sdio_unregister_driver(&sdio_wimax_driver); +} + +module_init(sdio_gdm_wimax_init); +module_exit(sdio_gdm_wimax_exit); + +MODULE_VERSION(DRIVER_VERSION); +MODULE_DESCRIPTION("GCT WiMax SDIO Device Driver"); +MODULE_AUTHOR("Ethan Park"); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/gdm72xx/gdm_sdio.h b/trunk/drivers/staging/gdm72xx/gdm_sdio.h new file mode 100644 index 000000000000..216e98f31bae --- /dev/null +++ b/trunk/drivers/staging/gdm72xx/gdm_sdio.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2012 GCT Semiconductor, Inc. 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 __GDM_SDIO_H__ +#define __GDM_SDIO_H__ + +#include +#include + +#define MAX_NR_SDU_BUF 64 + +struct sdio_tx { + struct list_head list; + struct tx_cxt *tx_cxt; + + u8 *buf; + int len; + + void (*callback)(void *cb_data); + void *cb_data; +}; + +struct tx_cxt { + struct list_head free_list; + struct list_head sdu_list; + struct list_head hci_list; + struct timeval sdu_stamp; + + u8 *sdu_buf; + + spinlock_t lock; + int can_send; + int stop_sdu_tx; +}; + +struct sdio_rx { + struct list_head list; + struct rx_cxt *rx_cxt; + + void (*callback)(void *cb_data, void *data, int len); + void *cb_data; +}; + +struct rx_cxt { + struct list_head free_list; + struct list_head req_list; + + u8 *rx_buf; + + spinlock_t lock; +}; + +struct sdiowm_dev { + struct sdio_func *func; + + struct tx_cxt tx; + struct rx_cxt rx; + + struct work_struct ws; +}; + +#endif /* __GDM_SDIO_H__ */ diff --git a/trunk/drivers/staging/gdm72xx/gdm_usb.c b/trunk/drivers/staging/gdm72xx/gdm_usb.c new file mode 100644 index 000000000000..1e9dc0d90362 --- /dev/null +++ b/trunk/drivers/staging/gdm72xx/gdm_usb.c @@ -0,0 +1,798 @@ +/* + * Copyright (c) 2012 GCT Semiconductor, Inc. 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 "gdm_usb.h" +#include "gdm_wimax.h" +#include "usb_boot.h" +#include "hci.h" + +#include "usb_ids.h" + +MODULE_DEVICE_TABLE(usb, id_table); + +#define TX_BUF_SIZE 2048 +#if defined(CONFIG_WIMAX_GDM72XX_WIMAX2) +#define RX_BUF_SIZE (128*1024) /* For packet aggregation */ +#else +#define RX_BUF_SIZE 2048 +#endif + +#define GDM7205_PADDING 256 + +#define H2B(x) __cpu_to_be16(x) +#define B2H(x) __be16_to_cpu(x) +#define DB2H(x) __be32_to_cpu(x) + +#define DOWNLOAD_CONF_VALUE 0x21 + +#ifdef CONFIG_WIMAX_GDM72XX_K_MODE + +static DECLARE_WAIT_QUEUE_HEAD(k_wait); +static LIST_HEAD(k_list); +static DEFINE_SPINLOCK(k_lock); +static int k_mode_stop; + +#define K_WAIT_TIME (2 * HZ / 100) + +#endif /* CONFIG_WIMAX_GDM72XX_K_MODE */ + +static int init_usb(struct usbwm_dev *udev); +static void release_usb(struct usbwm_dev *udev); + +/*#define DEBUG */ +#ifdef DEBUG +static void hexdump(char *title, u8 *data, int len) +{ + int i; + + printk(KERN_DEBUG "%s: length = %d\n", title, len); + for (i = 0; i < len; i++) { + printk(KERN_DEBUG "%02x ", data[i]); + if ((i & 0xf) == 0xf) + printk(KERN_DEBUG "\n"); + } + printk(KERN_DEBUG "\n"); +} +#endif + +static struct usb_tx *alloc_tx_struct(struct tx_cxt *tx) +{ + struct usb_tx *t = NULL; + + t = kmalloc(sizeof(*t), GFP_ATOMIC); + if (t == NULL) + goto out; + + memset(t, 0, sizeof(*t)); + + t->urb = usb_alloc_urb(0, GFP_ATOMIC); + t->buf = kmalloc(TX_BUF_SIZE, GFP_ATOMIC); + if (t->urb == NULL || t->buf == NULL) + goto out; + + t->tx_cxt = tx; + + return t; +out: + if (t) { + usb_free_urb(t->urb); + kfree(t->buf); + kfree(t); + } + return NULL; +} + +static void free_tx_struct(struct usb_tx *t) +{ + if (t) { + usb_free_urb(t->urb); + kfree(t->buf); + kfree(t); + } +} + +static struct usb_rx *alloc_rx_struct(struct rx_cxt *rx) +{ + struct usb_rx *r = NULL; + + r = kmalloc(sizeof(*r), GFP_ATOMIC); + if (r == NULL) + goto out; + + memset(r, 0, sizeof(*r)); + + r->urb = usb_alloc_urb(0, GFP_ATOMIC); + r->buf = kmalloc(RX_BUF_SIZE, GFP_ATOMIC); + if (r->urb == NULL || r->buf == NULL) + goto out; + + r->rx_cxt = rx; + return r; +out: + if (r) { + usb_free_urb(r->urb); + kfree(r->buf); + kfree(r); + } + return NULL; +} + +static void free_rx_struct(struct usb_rx *r) +{ + if (r) { + usb_free_urb(r->urb); + kfree(r->buf); + kfree(r); + } +} + +/* Before this function is called, spin lock should be locked. */ +static struct usb_tx *get_tx_struct(struct tx_cxt *tx, int *no_spc) +{ + struct usb_tx *t; + + if (list_empty(&tx->free_list)) { + *no_spc = 1; + return NULL; + } + + t = list_entry(tx->free_list.next, struct usb_tx, list); + list_del(&t->list); + + *no_spc = list_empty(&tx->free_list) ? 1 : 0; + + return t; +} + +/* Before this function is called, spin lock should be locked. */ +static void put_tx_struct(struct tx_cxt *tx, struct usb_tx *t) +{ + list_add_tail(&t->list, &tx->free_list); +} + +/* Before this function is called, spin lock should be locked. */ +static struct usb_rx *get_rx_struct(struct rx_cxt *rx) +{ + struct usb_rx *r; + + if (list_empty(&rx->free_list)) { + r = alloc_rx_struct(rx); + if (r == NULL) + return NULL; + + list_add(&r->list, &rx->free_list); + } + + r = list_entry(rx->free_list.next, struct usb_rx, list); + list_del(&r->list); + list_add_tail(&r->list, &rx->used_list); + + return r; +} + +/* Before this function is called, spin lock should be locked. */ +static void put_rx_struct(struct rx_cxt *rx, struct usb_rx *r) +{ + list_del(&r->list); + list_add(&r->list, &rx->free_list); +} + +static int init_usb(struct usbwm_dev *udev) +{ + int ret = 0, i; + struct tx_cxt *tx = &udev->tx; + struct rx_cxt *rx = &udev->rx; + struct usb_tx *t; + struct usb_rx *r; + + INIT_LIST_HEAD(&tx->free_list); + INIT_LIST_HEAD(&tx->sdu_list); + INIT_LIST_HEAD(&tx->hci_list); +#if defined(CONFIG_WIMAX_GDM72XX_USB_PM) || defined(CONFIG_WIMAX_GDM72XX_K_MODE) + INIT_LIST_HEAD(&tx->pending_list); +#endif + + INIT_LIST_HEAD(&rx->free_list); + INIT_LIST_HEAD(&rx->used_list); + + spin_lock_init(&tx->lock); + spin_lock_init(&rx->lock); + + for (i = 0; i < MAX_NR_SDU_BUF; i++) { + t = alloc_tx_struct(tx); + if (t == NULL) { + ret = -ENOMEM; + goto fail; + } + list_add(&t->list, &tx->free_list); + } + + r = alloc_rx_struct(rx); + if (r == NULL) { + ret = -ENOMEM; + goto fail; + } + + list_add(&r->list, &rx->free_list); + return ret; + +fail: + release_usb(udev); + return ret; +} + +static void release_usb(struct usbwm_dev *udev) +{ + struct tx_cxt *tx = &udev->tx; + struct rx_cxt *rx = &udev->rx; + struct usb_tx *t, *t_next; + struct usb_rx *r, *r_next; + + list_for_each_entry_safe(t, t_next, &tx->sdu_list, list) { + list_del(&t->list); + free_tx_struct(t); + } + + list_for_each_entry_safe(t, t_next, &tx->hci_list, list) { + list_del(&t->list); + free_tx_struct(t); + } + + list_for_each_entry_safe(t, t_next, &tx->free_list, list) { + list_del(&t->list); + free_tx_struct(t); + } + + list_for_each_entry_safe(r, r_next, &rx->free_list, list) { + list_del(&r->list); + free_rx_struct(r); + } + + list_for_each_entry_safe(r, r_next, &rx->used_list, list) { + list_del(&r->list); + free_rx_struct(r); + } +} + +static void gdm_usb_send_complete(struct urb *urb) +{ + struct usb_tx *t = urb->context; + struct tx_cxt *tx = t->tx_cxt; + u8 *pkt = t->buf; + u16 cmd_evt; + unsigned long flags; + + /* Completion by usb_unlink_urb */ + if (urb->status == -ECONNRESET) + return; + + spin_lock_irqsave(&tx->lock, flags); + + if (t->callback) + t->callback(t->cb_data); + + /* Delete from sdu list or hci list. */ + list_del(&t->list); + + cmd_evt = (pkt[0] << 8) | pkt[1]; + if (cmd_evt == WIMAX_TX_SDU) + put_tx_struct(tx, t); + else + free_tx_struct(t); + + spin_unlock_irqrestore(&tx->lock, flags); +} + +static int gdm_usb_send(void *priv_dev, void *data, int len, + void (*cb)(void *data), void *cb_data) +{ + struct usbwm_dev *udev = priv_dev; + struct usb_device *usbdev = udev->usbdev; + struct tx_cxt *tx = &udev->tx; + struct usb_tx *t; + int padding = udev->padding; + int no_spc = 0, ret; + u8 *pkt = data; + u16 cmd_evt; + unsigned long flags; + + if (!udev->usbdev) { + printk(KERN_ERR "%s: No such device\n", __func__); + return -ENODEV; + } + + BUG_ON(len > TX_BUF_SIZE - padding - 1); + + spin_lock_irqsave(&tx->lock, flags); + + cmd_evt = (pkt[0] << 8) | pkt[1]; + if (cmd_evt == WIMAX_TX_SDU) { + t = get_tx_struct(tx, &no_spc); + if (t == NULL) { + /* This case must not happen. */ + spin_unlock_irqrestore(&tx->lock, flags); + return -ENOSPC; + } + list_add_tail(&t->list, &tx->sdu_list); + } else { + t = alloc_tx_struct(tx); + if (t == NULL) { + spin_unlock_irqrestore(&tx->lock, flags); + return -ENOMEM; + } + list_add_tail(&t->list, &tx->hci_list); + } + + memcpy(t->buf + padding, data, len); + t->callback = cb; + t->cb_data = cb_data; + + /* + * In some cases, USB Module of WiMax is blocked when data size is + * the multiple of 512. So, increment length by one in that case. + */ + if ((len % 512) == 0) + len++; + + usb_fill_bulk_urb(t->urb, + usbdev, + usb_sndbulkpipe(usbdev, 1), + t->buf, + len + padding, + gdm_usb_send_complete, + t); + +#ifdef DEBUG + hexdump("usb_send", t->buf, len + padding); +#endif +#ifdef CONFIG_WIMAX_GDM72XX_USB_PM + if (usbdev->state & USB_STATE_SUSPENDED) { + list_add_tail(&t->p_list, &tx->pending_list); + schedule_work(&udev->pm_ws); + goto out; + } +#endif /* CONFIG_WIMAX_GDM72XX_USB_PM */ + +#ifdef CONFIG_WIMAX_GDM72XX_K_MODE + if (udev->bw_switch) { + list_add_tail(&t->p_list, &tx->pending_list); + goto out; + } else if (cmd_evt == WIMAX_SCAN) { + struct rx_cxt *rx; + struct usb_rx *r; + + rx = &udev->rx; + + list_for_each_entry(r, &rx->used_list, list) + usb_unlink_urb(r->urb); + udev->bw_switch = 1; + + spin_lock(&k_lock); + list_add_tail(&udev->list, &k_list); + spin_unlock(&k_lock); + + wake_up(&k_wait); + } +#endif /* CONFIG_WIMAX_GDM72XX_K_MODE */ + + ret = usb_submit_urb(t->urb, GFP_ATOMIC); + if (ret) + goto send_fail; + +#ifdef CONFIG_WIMAX_GDM72XX_USB_PM + usb_mark_last_busy(usbdev); +#endif /* CONFIG_WIMAX_GDM72XX_USB_PM */ + +#if defined(CONFIG_WIMAX_GDM72XX_USB_PM) || defined(CONFIG_WIMAX_GDM72XX_K_MODE) +out: +#endif + spin_unlock_irqrestore(&tx->lock, flags); + + if (no_spc) + return -ENOSPC; + + return 0; + +send_fail: + t->callback = NULL; + gdm_usb_send_complete(t->urb); + spin_unlock_irqrestore(&tx->lock, flags); + return ret; +} + +static void gdm_usb_rcv_complete(struct urb *urb) +{ + struct usb_rx *r = urb->context; + struct rx_cxt *rx = r->rx_cxt; + struct usbwm_dev *udev = container_of(r->rx_cxt, struct usbwm_dev, rx); + struct tx_cxt *tx = &udev->tx; + struct usb_tx *t; + u16 cmd_evt; + unsigned long flags; + +#ifdef CONFIG_WIMAX_GDM72XX_USB_PM + struct usb_device *dev = urb->dev; +#endif + + /* Completion by usb_unlink_urb */ + if (urb->status == -ECONNRESET) + return; + + spin_lock_irqsave(&tx->lock, flags); + + if (!urb->status) { + cmd_evt = (r->buf[0] << 8) | (r->buf[1]); +#ifdef DEBUG + hexdump("usb_receive", r->buf, urb->actual_length); +#endif + if (cmd_evt == WIMAX_SDU_TX_FLOW) { + if (r->buf[4] == 0) { +#ifdef DEBUG + printk(KERN_DEBUG "WIMAX ==> STOP SDU TX\n"); +#endif + list_for_each_entry(t, &tx->sdu_list, list) + usb_unlink_urb(t->urb); + } else if (r->buf[4] == 1) { +#ifdef DEBUG + printk(KERN_DEBUG "WIMAX ==> START SDU TX\n"); +#endif + list_for_each_entry(t, &tx->sdu_list, list) { + usb_submit_urb(t->urb, GFP_ATOMIC); + } + /* + * If free buffer for sdu tx doesn't + * exist, then tx queue should not be + * woken. For this reason, don't pass + * the command, START_SDU_TX. + */ + if (list_empty(&tx->free_list)) + urb->actual_length = 0; + } + } + } + + if (!urb->status && r->callback) + r->callback(r->cb_data, r->buf, urb->actual_length); + + spin_lock(&rx->lock); + put_rx_struct(rx, r); + spin_unlock(&rx->lock); + + spin_unlock_irqrestore(&tx->lock, flags); + +#ifdef CONFIG_WIMAX_GDM72XX_USB_PM + usb_mark_last_busy(dev); +#endif +} + +static int gdm_usb_receive(void *priv_dev, + void (*cb)(void *cb_data, void *data, int len), + void *cb_data) +{ + struct usbwm_dev *udev = priv_dev; + struct usb_device *usbdev = udev->usbdev; + struct rx_cxt *rx = &udev->rx; + struct usb_rx *r; + unsigned long flags; + + if (!udev->usbdev) { + printk(KERN_ERR "%s: No such device\n", __func__); + return -ENODEV; + } + + spin_lock_irqsave(&rx->lock, flags); + r = get_rx_struct(rx); + spin_unlock_irqrestore(&rx->lock, flags); + + if (r == NULL) + return -ENOMEM; + + r->callback = cb; + r->cb_data = cb_data; + + usb_fill_bulk_urb(r->urb, + usbdev, + usb_rcvbulkpipe(usbdev, 0x82), + r->buf, + RX_BUF_SIZE, + gdm_usb_rcv_complete, + r); + + return usb_submit_urb(r->urb, GFP_ATOMIC); +} + +#ifdef CONFIG_WIMAX_GDM72XX_USB_PM +static void do_pm_control(struct work_struct *work) +{ + struct usbwm_dev *udev = container_of(work, struct usbwm_dev, pm_ws); + struct tx_cxt *tx = &udev->tx; + int ret; + unsigned long flags; + + ret = usb_autopm_get_interface(udev->intf); + if (!ret) + usb_autopm_put_interface(udev->intf); + + spin_lock_irqsave(&tx->lock, flags); + if (!(udev->usbdev->state & USB_STATE_SUSPENDED) + && (!list_empty(&tx->hci_list) || !list_empty(&tx->sdu_list))) { + struct usb_tx *t, *temp; + + list_for_each_entry_safe(t, temp, &tx->pending_list, p_list) { + list_del(&t->p_list); + ret = usb_submit_urb(t->urb, GFP_ATOMIC); + + if (ret) { + t->callback = NULL; + gdm_usb_send_complete(t->urb); + } + } + } + spin_unlock_irqrestore(&tx->lock, flags); +} +#endif /* CONFIG_WIMAX_GDM72XX_USB_PM */ + +static int gdm_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int ret = 0; + u8 bConfigurationValue; + struct phy_dev *phy_dev = NULL; + struct usbwm_dev *udev = NULL; + u16 idVendor, idProduct, bcdDevice; + + struct usb_device *usbdev = interface_to_usbdev(intf); + + usb_get_dev(usbdev); + bConfigurationValue = usbdev->actconfig->desc.bConfigurationValue; + + /*USB description is set up with Little-Endian*/ + idVendor = L2H(usbdev->descriptor.idVendor); + idProduct = L2H(usbdev->descriptor.idProduct); + bcdDevice = L2H(usbdev->descriptor.bcdDevice); + + printk(KERN_INFO "Found GDM USB VID = 0x%04x PID = 0x%04x...\n", + idVendor, idProduct); + printk(KERN_INFO "GCT WiMax driver version %s\n", DRIVER_VERSION); + + + if (idProduct == EMERGENCY_PID) { + ret = usb_emergency(usbdev); + goto out; + } + + /* Support for EEPROM bootloader */ + if (bConfigurationValue == DOWNLOAD_CONF_VALUE || + idProduct & B_DOWNLOAD) { + ret = usb_boot(usbdev, bcdDevice); + goto out; + } + + phy_dev = kmalloc(sizeof(*phy_dev), GFP_KERNEL); + if (phy_dev == NULL) { + ret = -ENOMEM; + goto out; + } + udev = kmalloc(sizeof(*udev), GFP_KERNEL); + if (udev == NULL) { + ret = -ENOMEM; + goto out; + } + + memset(phy_dev, 0, sizeof(*phy_dev)); + memset(udev, 0, sizeof(*udev)); + + if (idProduct == 0x7205 || idProduct == 0x7206) + udev->padding = GDM7205_PADDING; + else + udev->padding = 0; + + phy_dev->priv_dev = (void *)udev; + phy_dev->send_func = gdm_usb_send; + phy_dev->rcv_func = gdm_usb_receive; + + ret = init_usb(udev); + if (ret < 0) + goto out; + + udev->usbdev = usbdev; + +#ifdef CONFIG_WIMAX_GDM72XX_USB_PM + udev->intf = intf; + + intf->needs_remote_wakeup = 1; + device_init_wakeup(&intf->dev, 1); + + pm_runtime_set_autosuspend_delay(&usbdev->dev, 10 * 1000); /* msec */ + + INIT_WORK(&udev->pm_ws, do_pm_control); +#endif /* CONFIG_WIMAX_GDM72XX_USB_PM */ + + ret = register_wimax_device(phy_dev, &intf->dev); + +out: + if (ret) { + kfree(phy_dev); + kfree(udev); + } + usb_set_intfdata(intf, phy_dev); + return ret; +} + +static void gdm_usb_disconnect(struct usb_interface *intf) +{ + u8 bConfigurationValue; + struct phy_dev *phy_dev; + struct usbwm_dev *udev; + u16 idProduct; + struct usb_device *usbdev = interface_to_usbdev(intf); + + bConfigurationValue = usbdev->actconfig->desc.bConfigurationValue; + phy_dev = usb_get_intfdata(intf); + + /*USB description is set up with Little-Endian*/ + idProduct = L2H(usbdev->descriptor.idProduct); + + if (idProduct != EMERGENCY_PID && + bConfigurationValue != DOWNLOAD_CONF_VALUE && + (idProduct & B_DOWNLOAD) == 0) { + udev = phy_dev->priv_dev; + udev->usbdev = NULL; + + unregister_wimax_device(phy_dev); + release_usb(udev); + kfree(udev); + kfree(phy_dev); + } + + usb_put_dev(usbdev); +} + +#ifdef CONFIG_WIMAX_GDM72XX_USB_PM +static int gdm_suspend(struct usb_interface *intf, pm_message_t pm_msg) +{ + struct phy_dev *phy_dev; + struct usbwm_dev *udev; + struct rx_cxt *rx; + struct usb_rx *r; + + phy_dev = usb_get_intfdata(intf); + udev = phy_dev->priv_dev; + rx = &udev->rx; + + list_for_each_entry(r, &rx->used_list, list) + usb_unlink_urb(r->urb); + + return 0; +} + +static int gdm_resume(struct usb_interface *intf) +{ + struct phy_dev *phy_dev; + struct usbwm_dev *udev; + struct rx_cxt *rx; + struct usb_rx *r; + + phy_dev = usb_get_intfdata(intf); + udev = phy_dev->priv_dev; + rx = &udev->rx; + + list_for_each_entry(r, &rx->used_list, list) + usb_submit_urb(r->urb, GFP_ATOMIC); + + return 0; +} + +#endif /* CONFIG_WIMAX_GDM72XX_USB_PM */ + +#ifdef CONFIG_WIMAX_GDM72XX_K_MODE +static int k_mode_thread(void *arg) +{ + struct usbwm_dev *udev; + struct tx_cxt *tx; + struct rx_cxt *rx; + struct usb_tx *t, *temp; + struct usb_rx *r; + unsigned long flags, flags2, expire; + int ret; + + daemonize("k_mode_wimax"); + + while (!k_mode_stop) { + + spin_lock_irqsave(&k_lock, flags2); + while (!list_empty(&k_list)) { + + udev = list_entry(k_list.next, struct usbwm_dev, list); + tx = &udev->tx; + rx = &udev->rx; + + list_del(&udev->list); + spin_unlock_irqrestore(&k_lock, flags2); + + expire = jiffies + K_WAIT_TIME; + while (jiffies < expire) + schedule_timeout(K_WAIT_TIME); + + list_for_each_entry(r, &rx->used_list, list) + usb_submit_urb(r->urb, GFP_ATOMIC); + + spin_lock_irqsave(&tx->lock, flags); + + list_for_each_entry_safe(t, temp, &tx->pending_list, + p_list) { + list_del(&t->p_list); + ret = usb_submit_urb(t->urb, GFP_ATOMIC); + + if (ret) { + t->callback = NULL; + gdm_usb_send_complete(t->urb); + } + } + + udev->bw_switch = 0; + spin_unlock_irqrestore(&tx->lock, flags); + + spin_lock_irqsave(&k_lock, flags2); + } + spin_unlock_irqrestore(&k_lock, flags2); + + interruptible_sleep_on(&k_wait); + } + return 0; +} +#endif /* CONFIG_WIMAX_GDM72XX_K_MODE */ + +static struct usb_driver gdm_usb_driver = { + .name = "gdm_wimax", + .probe = gdm_usb_probe, + .disconnect = gdm_usb_disconnect, + .id_table = id_table, +#ifdef CONFIG_WIMAX_GDM72XX_USB_PM + .supports_autosuspend = 1, + .suspend = gdm_suspend, + .resume = gdm_resume, + .reset_resume = gdm_resume, +#endif +}; + +static int __init usb_gdm_wimax_init(void) +{ +#ifdef CONFIG_WIMAX_GDM72XX_K_MODE + kernel_thread(k_mode_thread, NULL, CLONE_KERNEL); +#endif /* CONFIG_WIMAX_GDM72XX_K_MODE */ + return usb_register(&gdm_usb_driver); +} + +static void __exit usb_gdm_wimax_exit(void) +{ +#ifdef CONFIG_WIMAX_GDM72XX_K_MODE + k_mode_stop = 1; + wake_up(&k_wait); +#endif + usb_deregister(&gdm_usb_driver); +} + +module_init(usb_gdm_wimax_init); +module_exit(usb_gdm_wimax_exit); + +MODULE_VERSION(DRIVER_VERSION); +MODULE_DESCRIPTION("GCT WiMax Device Driver"); +MODULE_AUTHOR("Ethan Park"); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/gdm72xx/gdm_usb.h b/trunk/drivers/staging/gdm72xx/gdm_usb.h new file mode 100644 index 000000000000..ecb891f6a599 --- /dev/null +++ b/trunk/drivers/staging/gdm72xx/gdm_usb.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2012 GCT Semiconductor, Inc. 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 __GDM_USB_H__ +#define __GDM_USB_H__ + +#include +#include +#include + +#define B_DIFF_DL_DRV (1<<4) +#define B_DOWNLOAD (1 << 5) +#define MAX_NR_SDU_BUF 64 + +struct usb_tx { + struct list_head list; +#if defined(CONFIG_WIMAX_GDM72XX_USB_PM) || defined(CONFIG_WIMAX_GDM72XX_K_MODE) + struct list_head p_list; +#endif + struct tx_cxt *tx_cxt; + + struct urb *urb; + u8 *buf; + + void (*callback)(void *cb_data); + void *cb_data; +}; + +struct tx_cxt { + struct list_head free_list; + struct list_head sdu_list; + struct list_head hci_list; +#if defined(CONFIG_WIMAX_GDM72XX_USB_PM) || defined(CONFIG_WIMAX_GDM72XX_K_MODE) + struct list_head pending_list; +#endif + + spinlock_t lock; +}; + +struct usb_rx { + struct list_head list; + struct rx_cxt *rx_cxt; + + struct urb *urb; + u8 *buf; + + void (*callback)(void *cb_data, void *data, int len); + void *cb_data; +}; + +struct rx_cxt { + struct list_head free_list; + struct list_head used_list; + spinlock_t lock; +}; + +struct usbwm_dev { + struct usb_device *usbdev; +#ifdef CONFIG_WIMAX_GDM72XX_USB_PM + struct work_struct pm_ws; + + struct usb_interface *intf; +#endif +#ifdef CONFIG_WIMAX_GDM72XX_K_MODE + int bw_switch; + struct list_head list; +#endif + + struct tx_cxt tx; + struct rx_cxt rx; + + int padding; +}; + +#endif /* __GDM_USB_H__ */ diff --git a/trunk/drivers/staging/gdm72xx/gdm_wimax.c b/trunk/drivers/staging/gdm72xx/gdm_wimax.c new file mode 100644 index 000000000000..f1936b92533b --- /dev/null +++ b/trunk/drivers/staging/gdm72xx/gdm_wimax.c @@ -0,0 +1,1026 @@ +/* + * Copyright (c) 2012 GCT Semiconductor, Inc. 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 +#include + +#include "gdm_wimax.h" +#include "hci.h" +#include "wm_ioctl.h" +#include "netlink_k.h" + +#define gdm_wimax_send(n, d, l) \ + (n->phy_dev->send_func)(n->phy_dev->priv_dev, d, l, NULL, NULL) +#define gdm_wimax_send_with_cb(n, d, l, c, b) \ + (n->phy_dev->send_func)(n->phy_dev->priv_dev, d, l, c, b) +#define gdm_wimax_rcv_with_cb(n, c, b) \ + (n->phy_dev->rcv_func)(n->phy_dev->priv_dev, c, b) + +#define EVT_MAX_SIZE 2048 + +struct evt_entry { + struct list_head list; + struct net_device *dev; + char evt_data[EVT_MAX_SIZE]; + int size; +}; + +static void __gdm_wimax_event_send(struct work_struct *work); +static inline struct evt_entry *alloc_event_entry(void); +static inline void free_event_entry(struct evt_entry *e); +static struct evt_entry *get_event_entry(void); +static void put_event_entry(struct evt_entry *e); + +static struct { + int ref_cnt; + struct sock *sock; + struct list_head evtq; + spinlock_t evt_lock; + + struct list_head freeq; + struct work_struct ws; +} wm_event; + +static u8 gdm_wimax_macaddr[6] = {0x00, 0x0a, 0x3b, 0xf0, 0x01, 0x30}; + +static void gdm_wimax_ind_fsm_update(struct net_device *dev, struct fsm_s *fsm); +static void gdm_wimax_ind_if_updown(struct net_device *dev, int if_up); + +#if defined(DEBUG_SDU) +static void printk_hex(u8 *buf, u32 size) +{ + int i; + + for (i = 0; i < size; i++) { + if (i && i % 16 == 0) + printk(KERN_DEBUG "\n%02x ", *buf++); + else + printk(KERN_DEBUG "%02x ", *buf++); + } + + printk(KERN_DEBUG "\n"); +} + +static const char *get_protocol_name(u16 protocol) +{ + static char buf[32]; + const char *name = "-"; + + switch (protocol) { + case ETH_P_ARP: + name = "ARP"; + break; + case ETH_P_IP: + name = "IP"; + break; + case ETH_P_IPV6: + name = "IPv6"; + break; + } + + sprintf(buf, "0x%04x(%s)", protocol, name); + return buf; +} + +static const char *get_ip_protocol_name(u8 ip_protocol) +{ + static char buf[32]; + const char *name = "-"; + + switch (ip_protocol) { + case IPPROTO_TCP: + name = "TCP"; + break; + case IPPROTO_UDP: + name = "UDP"; + break; + case IPPROTO_ICMP: + name = "ICMP"; + break; + } + + sprintf(buf, "%u(%s)", ip_protocol, name); + return buf; +} + +static const char *get_port_name(u16 port) +{ + static char buf[32]; + const char *name = "-"; + + switch (port) { + case 67: + name = "DHCP-Server"; + break; + case 68: + name = "DHCP-Client"; + break; + case 69: + name = "TFTP"; + break; + } + + sprintf(buf, "%u(%s)", port, name); + return buf; +} + +static void dump_eth_packet(const char *title, u8 *data, int len) +{ + struct iphdr *ih = NULL; + struct udphdr *uh = NULL; + u16 protocol = 0; + u8 ip_protocol = 0; + u16 port = 0; + + protocol = (data[12]<<8) | data[13]; + ih = (struct iphdr *) (data+ETH_HLEN); + + if (protocol == ETH_P_IP) { + uh = (struct udphdr *) ((char *)ih + sizeof(struct iphdr)); + ip_protocol = ih->protocol; + port = ntohs(uh->dest); + } else if (protocol == ETH_P_IPV6) { + struct ipv6hdr *i6h = (struct ipv6hdr *) data; + uh = (struct udphdr *) ((char *)i6h + sizeof(struct ipv6hdr)); + ip_protocol = i6h->nexthdr; + port = ntohs(uh->dest); + } + + printk(KERN_DEBUG "[%s] len=%d, %s, %s, %s\n", + title, len, + get_protocol_name(protocol), + get_ip_protocol_name(ip_protocol), + get_port_name(port)); + + #if 1 + if (!(data[0] == 0xff && data[1] == 0xff)) { + if (protocol == ETH_P_IP) { + printk(KERN_DEBUG " src=%u.%u.%u.%u\n", + NIPQUAD(ih->saddr)); + } else if (protocol == ETH_P_IPV6) { + #ifdef NIP6 + printk(KERN_DEBUG " src=%x:%x:%x:%x:%x:%x:%x:%x\n", + NIP6(ih->saddr)); + #else + printk(KERN_DEBUG " src=%pI6\n", &ih->saddr); + #endif + } + } + #endif + + #if (DUMP_PACKET & DUMP_SDU_ALL) + printk_hex(data, len); + #else + #if (DUMP_PACKET & DUMP_SDU_ARP) + if (protocol == ETH_P_ARP) + printk_hex(data, len); + #endif + #if (DUMP_PACKET & DUMP_SDU_IP) + if (protocol == ETH_P_IP || protocol == ETH_P_IPV6) + printk_hex(data, len); + #else + #if (DUMP_PACKET & DUMP_SDU_IP_TCP) + if (ip_protocol == IPPROTO_TCP) + printk_hex(data, len); + #endif + #if (DUMP_PACKET & DUMP_SDU_IP_UDP) + if (ip_protocol == IPPROTO_UDP) + printk_hex(data, len); + #endif + #if (DUMP_PACKET & DUMP_SDU_IP_ICMP) + if (ip_protocol == IPPROTO_ICMP) + printk_hex(data, len); + #endif + #endif + #endif +} +#endif + + +static inline int gdm_wimax_header(struct sk_buff **pskb) +{ + u16 buf[HCI_HEADER_SIZE / sizeof(u16)]; + struct sk_buff *skb = *pskb; + int ret = 0; + + if (unlikely(skb_headroom(skb) < HCI_HEADER_SIZE)) { + struct sk_buff *skb2; + + skb2 = skb_realloc_headroom(skb, HCI_HEADER_SIZE); + if (skb2 == NULL) + return -ENOMEM; + if (skb->sk) + skb_set_owner_w(skb2, skb->sk); + kfree_skb(skb); + skb = skb2; + } + + skb_push(skb, HCI_HEADER_SIZE); + buf[0] = H2B(WIMAX_TX_SDU); + buf[1] = H2B(skb->len - HCI_HEADER_SIZE); + memcpy(skb->data, buf, HCI_HEADER_SIZE); + + *pskb = skb; + return ret; +} + +static void gdm_wimax_event_rcv(struct net_device *dev, u16 type, void *msg, + int len) +{ + struct nic *nic = netdev_priv(dev); + + #if defined(DEBUG_HCI) + u8 *buf = (u8 *) msg; + u16 hci_cmd = (buf[0]<<8) | buf[1]; + u16 hci_len = (buf[2]<<8) | buf[3]; + printk(KERN_DEBUG "H=>D: 0x%04x(%d)\n", hci_cmd, hci_len); + #endif + + gdm_wimax_send(nic, msg, len); +} + +static int gdm_wimax_event_init(void) +{ + if (wm_event.ref_cnt == 0) { + wm_event.sock = netlink_init(NETLINK_WIMAX, + gdm_wimax_event_rcv); + INIT_LIST_HEAD(&wm_event.evtq); + INIT_LIST_HEAD(&wm_event.freeq); + INIT_WORK(&wm_event.ws, __gdm_wimax_event_send); + spin_lock_init(&wm_event.evt_lock); + } + + if (wm_event.sock) { + wm_event.ref_cnt++; + return 0; + } + + printk(KERN_ERR "Creating WiMax Event netlink is failed\n"); + return -1; +} + +static void gdm_wimax_event_exit(void) +{ + if (wm_event.sock && --wm_event.ref_cnt == 0) { + struct evt_entry *e, *temp; + unsigned long flags; + + spin_lock_irqsave(&wm_event.evt_lock, flags); + + list_for_each_entry_safe(e, temp, &wm_event.evtq, list) { + list_del(&e->list); + free_event_entry(e); + } + list_for_each_entry_safe(e, temp, &wm_event.freeq, list) { + list_del(&e->list); + free_event_entry(e); + } + + spin_unlock_irqrestore(&wm_event.evt_lock, flags); + netlink_exit(wm_event.sock); + wm_event.sock = NULL; + } +} + +static inline struct evt_entry *alloc_event_entry(void) +{ + return kmalloc(sizeof(struct evt_entry), GFP_ATOMIC); +} + +static inline void free_event_entry(struct evt_entry *e) +{ + kfree(e); +} + +static struct evt_entry *get_event_entry(void) +{ + struct evt_entry *e; + + if (list_empty(&wm_event.freeq)) + e = alloc_event_entry(); + else { + e = list_entry(wm_event.freeq.next, struct evt_entry, list); + list_del(&e->list); + } + + return e; +} + +static void put_event_entry(struct evt_entry *e) +{ + BUG_ON(!e); + + list_add_tail(&e->list, &wm_event.freeq); +} + +static void __gdm_wimax_event_send(struct work_struct *work) +{ + int idx; + unsigned long flags; + struct evt_entry *e; + + spin_lock_irqsave(&wm_event.evt_lock, flags); + + while (!list_empty(&wm_event.evtq)) { + e = list_entry(wm_event.evtq.next, struct evt_entry, list); + spin_unlock_irqrestore(&wm_event.evt_lock, flags); + + sscanf(e->dev->name, "wm%d", &idx); + netlink_send(wm_event.sock, idx, 0, e->evt_data, e->size); + + spin_lock_irqsave(&wm_event.evt_lock, flags); + list_del(&e->list); + put_event_entry(e); + } + + spin_unlock_irqrestore(&wm_event.evt_lock, flags); +} + +static int gdm_wimax_event_send(struct net_device *dev, char *buf, int size) +{ + struct evt_entry *e; + unsigned long flags; + + #if defined(DEBUG_HCI) + u16 hci_cmd = ((u8)buf[0]<<8) | (u8)buf[1]; + u16 hci_len = ((u8)buf[2]<<8) | (u8)buf[3]; + printk(KERN_DEBUG "D=>H: 0x%04x(%d)\n", hci_cmd, hci_len); + #endif + + spin_lock_irqsave(&wm_event.evt_lock, flags); + + e = get_event_entry(); + if (!e) { + printk(KERN_ERR "%s: No memory for event\n", __func__); + spin_unlock_irqrestore(&wm_event.evt_lock, flags); + return -ENOMEM; + } + + e->dev = dev; + e->size = size; + memcpy(e->evt_data, buf, size); + + list_add_tail(&e->list, &wm_event.evtq); + spin_unlock_irqrestore(&wm_event.evt_lock, flags); + + schedule_work(&wm_event.ws); + + return 0; +} + +static void tx_complete(void *arg) +{ + struct nic *nic = arg; + + if (netif_queue_stopped(nic->netdev)) + netif_wake_queue(nic->netdev); +} + +int gdm_wimax_send_tx(struct sk_buff *skb, struct net_device *dev) +{ + int ret = 0; + struct nic *nic = netdev_priv(dev); + + ret = gdm_wimax_send_with_cb(nic, skb->data, skb->len, tx_complete, + nic); + if (ret == -ENOSPC) { + netif_stop_queue(dev); + ret = 0; + } + + if (ret) { + skb_pull(skb, HCI_HEADER_SIZE); + return ret; + } + + nic->stats.tx_packets++; + nic->stats.tx_bytes += skb->len - HCI_HEADER_SIZE; + kfree_skb(skb); + return ret; +} + +static int gdm_wimax_tx(struct sk_buff *skb, struct net_device *dev) +{ + int ret = 0; + struct nic *nic = netdev_priv(dev); + struct fsm_s *fsm = (struct fsm_s *) nic->sdk_data[SIOC_DATA_FSM].buf; + + #if defined(DEBUG_SDU) + dump_eth_packet("TX", skb->data, skb->len); + #endif + + ret = gdm_wimax_header(&skb); + if (ret < 0) { + skb_pull(skb, HCI_HEADER_SIZE); + return ret; + } + + #if !defined(LOOPBACK_TEST) + if (!fsm) + printk(KERN_ERR "ASSERTION ERROR: fsm is NULL!!\n"); + else if (fsm->m_status != M_CONNECTED) { + printk(KERN_EMERG "ASSERTION ERROR: Device is NOT ready. status=%d\n", + fsm->m_status); + kfree_skb(skb); + return 0; + } + #endif + +#if defined(CONFIG_WIMAX_GDM72XX_QOS) + ret = gdm_qos_send_hci_pkt(skb, dev); +#else + ret = gdm_wimax_send_tx(skb, dev); +#endif + return ret; +} + +static int gdm_wimax_set_config(struct net_device *dev, struct ifmap *map) +{ + if (dev->flags & IFF_UP) + return -EBUSY; + + return 0; +} + +static void __gdm_wimax_set_mac_addr(struct net_device *dev, char *mac_addr) +{ + u16 hci_pkt_buf[32 / sizeof(u16)]; + u8 *pkt = (u8 *) &hci_pkt_buf[0]; + struct nic *nic = netdev_priv(dev); + + /* Since dev is registered as a ethernet device, + * ether_setup has made dev->addr_len to be ETH_ALEN + */ + memcpy(dev->dev_addr, mac_addr, dev->addr_len); + + /* Let lower layer know of this change by sending + * SetInformation(MAC Address) + */ + hci_pkt_buf[0] = H2B(WIMAX_SET_INFO); /* cmd_evt */ + hci_pkt_buf[1] = H2B(8); /* size */ + pkt[4] = 0; /* T */ + pkt[5] = 6; /* L */ + memcpy(pkt + 6, mac_addr, dev->addr_len); /* V */ + + gdm_wimax_send(nic, pkt, HCI_HEADER_SIZE + 8); +} + +/* A driver function */ +static int gdm_wimax_set_mac_addr(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + + if (netif_running(dev)) + return -EBUSY; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + __gdm_wimax_set_mac_addr(dev, addr->sa_data); + + return 0; +} + +static struct net_device_stats *gdm_wimax_stats(struct net_device *dev) +{ + struct nic *nic = netdev_priv(dev); + + return &nic->stats; +} + +static int gdm_wimax_open(struct net_device *dev) +{ + struct nic *nic = netdev_priv(dev); + struct fsm_s *fsm = (struct fsm_s *) nic->sdk_data[SIOC_DATA_FSM].buf; + + netif_start_queue(dev); + + if (fsm && fsm->m_status != M_INIT) + gdm_wimax_ind_if_updown(dev, 1); + return 0; +} + +static int gdm_wimax_close(struct net_device *dev) +{ + struct nic *nic = netdev_priv(dev); + struct fsm_s *fsm = (struct fsm_s *) nic->sdk_data[SIOC_DATA_FSM].buf; + + netif_stop_queue(dev); + + if (fsm && fsm->m_status != M_INIT) + gdm_wimax_ind_if_updown(dev, 0); + return 0; +} + +static void kdelete(void **buf) +{ + if (buf && *buf) { + kfree(*buf); + *buf = NULL; + } +} + +static int gdm_wimax_ioctl_get_data(struct data_s *dst, struct data_s *src) +{ + int size; + + size = dst->size < src->size ? dst->size : src->size; + + dst->size = size; + if (src->size) { + if (!dst->buf) + return -EINVAL; + if (copy_to_user(dst->buf, src->buf, size)) + return -EFAULT; + } + return 0; +} + +static int gdm_wimax_ioctl_set_data(struct data_s *dst, struct data_s *src) +{ + if (!src->size) { + dst->size = 0; + return 0; + } + + if (!src->buf) + return -EINVAL; + + if (!(dst->buf && dst->size == src->size)) { + kdelete(&dst->buf); + dst->buf = kmalloc(src->size, GFP_KERNEL); + if (dst->buf == NULL) + return -ENOMEM; + } + + if (copy_from_user(dst->buf, src->buf, src->size)) { + kdelete(&dst->buf); + return -EFAULT; + } + dst->size = src->size; + return 0; +} + +static void gdm_wimax_cleanup_ioctl(struct net_device *dev) +{ + struct nic *nic = netdev_priv(dev); + int i; + + for (i = 0; i < SIOC_DATA_MAX; i++) + kdelete(&nic->sdk_data[i].buf); +} + +static void gdm_update_fsm(struct net_device *dev, struct fsm_s *new_fsm) +{ + struct nic *nic = netdev_priv(dev); + struct fsm_s *cur_fsm = + (struct fsm_s *) nic->sdk_data[SIOC_DATA_FSM].buf; + + if (!cur_fsm) + return; + + if (cur_fsm->m_status != new_fsm->m_status || + cur_fsm->c_status != new_fsm->c_status) { + if (new_fsm->m_status == M_CONNECTED) + netif_carrier_on(dev); + else if (cur_fsm->m_status == M_CONNECTED) { + netif_carrier_off(dev); + #if defined(CONFIG_WIMAX_GDM72XX_QOS) + gdm_qos_release_list(nic); + #endif + } + gdm_wimax_ind_fsm_update(dev, new_fsm); + } +} + +static int gdm_wimax_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct wm_req_s *req = (struct wm_req_s *) ifr; + struct nic *nic = netdev_priv(dev); + int ret; + + if (cmd != SIOCWMIOCTL) + return -EOPNOTSUPP; + + switch (req->cmd) { + case SIOCG_DATA: + case SIOCS_DATA: + if (req->data_id >= SIOC_DATA_MAX) { + printk(KERN_ERR + "%s error: data-index(%d) is invalid!!\n", + __func__, req->data_id); + return -EOPNOTSUPP; + } + if (req->cmd == SIOCG_DATA) { + ret = gdm_wimax_ioctl_get_data(&req->data, + &nic->sdk_data[req->data_id]); + if (ret < 0) + return ret; + } else if (req->cmd == SIOCS_DATA) { + if (req->data_id == SIOC_DATA_FSM) { + /*NOTE: gdm_update_fsm should be called + before gdm_wimax_ioctl_set_data is called*/ + gdm_update_fsm(dev, + (struct fsm_s *) req->data.buf); + } + ret = gdm_wimax_ioctl_set_data( + &nic->sdk_data[req->data_id], &req->data); + if (ret < 0) + return ret; + } + break; + default: + printk(KERN_ERR "%s: %x unknown ioctl\n", __func__, cmd); + return -EOPNOTSUPP; + } + + return 0; +} + +static void gdm_wimax_prepare_device(struct net_device *dev) +{ + struct nic *nic = netdev_priv(dev); + u16 buf[32 / sizeof(u16)]; + struct hci_s *hci = (struct hci_s *) buf; + u16 len = 0; + u32 val = 0; + + #define BIT_MULTI_CS 0 + #define BIT_WIMAX 1 + #define BIT_QOS 2 + #define BIT_AGGREGATION 3 + + /* GetInformation mac address */ + len = 0; + hci->cmd_evt = H2B(WIMAX_GET_INFO); + hci->data[len++] = TLV_T(T_MAC_ADDRESS); + hci->length = H2B(len); + gdm_wimax_send(nic, hci, HCI_HEADER_SIZE+len); + + val = (1<cmd_evt = H2B(WIMAX_SET_INFO); + hci->data[len++] = TLV_T(T_CAPABILITY); + hci->data[len++] = TLV_L(T_CAPABILITY); + val = DH2B(val); + memcpy(&hci->data[len], &val, TLV_L(T_CAPABILITY)); + len += TLV_L(T_CAPABILITY); + hci->length = H2B(len); + gdm_wimax_send(nic, hci, HCI_HEADER_SIZE+len); + + printk(KERN_INFO "GDM WiMax Set CAPABILITY: 0x%08X\n", DB2H(val)); +} + +static int gdm_wimax_hci_get_tlv(u8 *buf, u8 *T, u16 *L, u8 **V) +{ + #define __U82U16(b) ((u16)((u8 *)(b))[0] | ((u16)((u8 *)(b))[1] << 8)) + int next_pos; + + *T = buf[0]; + if (buf[1] == 0x82) { + *L = B2H(__U82U16(&buf[2])); + next_pos = 1/*type*/+3/*len*/; + } else { + *L = buf[1]; + next_pos = 1/*type*/+1/*len*/; + } + *V = &buf[next_pos]; + + next_pos += *L/*length of val*/; + return next_pos; +} + +static int gdm_wimax_get_prepared_info(struct net_device *dev, char *buf, + int len) +{ + u8 T, *V; + u16 L; + u16 cmd_evt, cmd_len; + int pos = HCI_HEADER_SIZE; + + cmd_evt = B2H(*(u16 *)&buf[0]); + cmd_len = B2H(*(u16 *)&buf[2]); + + if (len < cmd_len + HCI_HEADER_SIZE) { + printk(KERN_ERR "%s: invalid length [%d/%d]\n", __func__, + cmd_len + HCI_HEADER_SIZE, len); + return -1; + } + + if (cmd_evt == WIMAX_GET_INFO_RESULT) { + if (cmd_len < 2) { + printk(KERN_ERR "%s: len is too short [%x/%d]\n", + __func__, cmd_evt, len); + return -1; + } + + pos += gdm_wimax_hci_get_tlv(&buf[pos], &T, &L, &V); + if (T == TLV_T(T_MAC_ADDRESS)) { + if (L != dev->addr_len) { + printk(KERN_ERR + "%s Invalid inofrmation result T/L " + "[%x/%d]\n", __func__, T, L); + return -1; + } + printk(KERN_INFO + "MAC change [%02x:%02x:%02x:%02x:%02x:%02x]" + "->[%02x:%02x:%02x:%02x:%02x:%02x]\n", + dev->dev_addr[0], dev->dev_addr[1], + dev->dev_addr[2], dev->dev_addr[3], + dev->dev_addr[4], dev->dev_addr[5], + V[0], V[1], V[2], V[3], V[4], V[5]); + memcpy(dev->dev_addr, V, dev->addr_len); + return 1; + } + } + + gdm_wimax_event_send(dev, buf, len); + return 0; +} + +static void gdm_wimax_netif_rx(struct net_device *dev, char *buf, int len) +{ + struct nic *nic = netdev_priv(dev); + struct sk_buff *skb; + int ret; + + #if defined(DEBUG_SDU) + dump_eth_packet("RX", buf, len); + #endif + + skb = dev_alloc_skb(len + 2); + if (!skb) { + printk(KERN_ERR "%s: dev_alloc_skb failed!\n", __func__); + return; + } + skb_reserve(skb, 2); + + nic->stats.rx_packets++; + nic->stats.rx_bytes += len; + + memcpy(skb_put(skb, len), buf, len); + + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); /* what will happen? */ + + ret = in_interrupt() ? netif_rx(skb) : netif_rx_ni(skb); + if (ret == NET_RX_DROP) + printk(KERN_ERR "%s skb dropped\n", __func__); +} + +static void gdm_wimax_transmit_aggr_pkt(struct net_device *dev, char *buf, + int len) +{ + #define HCI_PADDING_BYTE 4 + #define HCI_RESERVED_BYTE 4 + struct hci_s *hci; + int length; + + while (len > 0) { + hci = (struct hci_s *) buf; + + if (B2H(hci->cmd_evt) != WIMAX_RX_SDU) { + printk(KERN_ERR "Wrong cmd_evt(0x%04X)\n", + B2H(hci->cmd_evt)); + break; + } + + length = B2H(hci->length); + gdm_wimax_netif_rx(dev, hci->data, length); + + if (length & 0x3) { + /* Add padding size */ + length += HCI_PADDING_BYTE - (length & 0x3); + } + + length += HCI_HEADER_SIZE + HCI_RESERVED_BYTE; + len -= length; + buf += length; + } +} + +static void gdm_wimax_transmit_pkt(struct net_device *dev, char *buf, int len) +{ + #if defined(CONFIG_WIMAX_GDM72XX_QOS) + struct nic *nic = netdev_priv(dev); + #endif + u16 cmd_evt, cmd_len; + + /* This code is added for certain rx packet to be ignored. */ + if (len == 0) + return; + + cmd_evt = B2H(*(u16 *)&buf[0]); + cmd_len = B2H(*(u16 *)&buf[2]); + + if (len < cmd_len + HCI_HEADER_SIZE) { + if (len) + printk(KERN_ERR "%s: invalid length [%d/%d]\n", + __func__, cmd_len + HCI_HEADER_SIZE, len); + return; + } + + switch (cmd_evt) { + case WIMAX_RX_SDU_AGGR: + gdm_wimax_transmit_aggr_pkt(dev, &buf[HCI_HEADER_SIZE], + cmd_len); + break; + case WIMAX_RX_SDU: + gdm_wimax_netif_rx(dev, &buf[HCI_HEADER_SIZE], cmd_len); + break; + #if defined(CONFIG_WIMAX_GDM72XX_QOS) + case WIMAX_EVT_MODEM_REPORT: + gdm_recv_qos_hci_packet(nic, buf, len); + break; + #endif + case WIMAX_SDU_TX_FLOW: + if (buf[4] == 0) { + if (!netif_queue_stopped(dev)) + netif_stop_queue(dev); + } else if (buf[4] == 1) { + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); + } + break; + default: + gdm_wimax_event_send(dev, buf, len); + break; + } +} + +static void gdm_wimax_ind_fsm_update(struct net_device *dev, struct fsm_s *fsm) +{ + u16 buf[32 / sizeof(u16)]; + u8 *hci_pkt_buf = (u8 *)&buf[0]; + + /* Indicate updating fsm */ + buf[0] = H2B(WIMAX_FSM_UPDATE); + buf[1] = H2B(sizeof(struct fsm_s)); + memcpy(&hci_pkt_buf[HCI_HEADER_SIZE], fsm, sizeof(struct fsm_s)); + + gdm_wimax_event_send(dev, hci_pkt_buf, + HCI_HEADER_SIZE + sizeof(struct fsm_s)); +} + +static void gdm_wimax_ind_if_updown(struct net_device *dev, int if_up) +{ + u16 buf[32 / sizeof(u16)]; + struct hci_s *hci = (struct hci_s *) buf; + unsigned char up_down; + + up_down = if_up ? WIMAX_IF_UP : WIMAX_IF_DOWN; + + /* Indicate updating fsm */ + hci->cmd_evt = H2B(WIMAX_IF_UPDOWN); + hci->length = H2B(sizeof(up_down)); + hci->data[0] = up_down; + + gdm_wimax_event_send(dev, (char *)hci, HCI_HEADER_SIZE+sizeof(up_down)); +} + +static void rx_complete(void *arg, void *data, int len) +{ + struct nic *nic = arg; + + gdm_wimax_transmit_pkt(nic->netdev, data, len); + gdm_wimax_rcv_with_cb(nic, rx_complete, nic); +} + +static void prepare_rx_complete(void *arg, void *data, int len) +{ + struct nic *nic = arg; + int ret; + + ret = gdm_wimax_get_prepared_info(nic->netdev, data, len); + if (ret == 1) + gdm_wimax_rcv_with_cb(nic, rx_complete, nic); + else { + if (ret < 0) + printk(KERN_ERR "get_prepared_info failed(%d)\n", ret); + gdm_wimax_rcv_with_cb(nic, prepare_rx_complete, nic); + #if 0 + /* Re-prepare WiMax device */ + gdm_wimax_prepare_device(nic->netdev); + #endif + } +} + +static void start_rx_proc(struct nic *nic) +{ + gdm_wimax_rcv_with_cb(nic, prepare_rx_complete, nic); +} + +static struct net_device_ops gdm_netdev_ops = { + .ndo_open = gdm_wimax_open, + .ndo_stop = gdm_wimax_close, + .ndo_set_config = gdm_wimax_set_config, + .ndo_start_xmit = gdm_wimax_tx, + .ndo_get_stats = gdm_wimax_stats, + .ndo_set_mac_address = gdm_wimax_set_mac_addr, + .ndo_do_ioctl = gdm_wimax_ioctl, +}; + +int register_wimax_device(struct phy_dev *phy_dev, struct device *pdev) +{ + struct nic *nic = NULL; + struct net_device *dev; + int ret; + + dev = (struct net_device *)alloc_netdev(sizeof(*nic), + "wm%d", ether_setup); + + if (dev == NULL) { + printk(KERN_ERR "alloc_etherdev failed\n"); + return -ENOMEM; + } + + SET_NETDEV_DEV(dev, pdev); + dev->mtu = 1400; + dev->netdev_ops = &gdm_netdev_ops; + dev->flags &= ~IFF_MULTICAST; + memcpy(dev->dev_addr, gdm_wimax_macaddr, sizeof(gdm_wimax_macaddr)); + + nic = netdev_priv(dev); + memset(nic, 0, sizeof(*nic)); + + nic->netdev = dev; + nic->phy_dev = phy_dev; + phy_dev->netdev = dev; + + /* event socket init */ + ret = gdm_wimax_event_init(); + if (ret < 0) { + printk(KERN_ERR "Cannot create event.\n"); + goto cleanup; + } + + ret = register_netdev(dev); + if (ret) + goto cleanup; + + #if defined(LOOPBACK_TEST) + netif_start_queue(dev); + netif_carrier_on(dev); + #else + netif_carrier_off(dev); + #endif + +#ifdef CONFIG_WIMAX_GDM72XX_QOS + gdm_qos_init(nic); +#endif + + start_rx_proc(nic); + + /* Prepare WiMax device */ + gdm_wimax_prepare_device(dev); + + return 0; + +cleanup: + printk(KERN_ERR "register_netdev failed\n"); + free_netdev(dev); + return ret; +} + +void unregister_wimax_device(struct phy_dev *phy_dev) +{ + struct nic *nic = netdev_priv(phy_dev->netdev); + struct fsm_s *fsm = (struct fsm_s *) nic->sdk_data[SIOC_DATA_FSM].buf; + + if (fsm) + fsm->m_status = M_INIT; + unregister_netdev(nic->netdev); + + gdm_wimax_event_exit(); + +#if defined(CONFIG_WIMAX_GDM72XX_QOS) + gdm_qos_release_list(nic); +#endif + + gdm_wimax_cleanup_ioctl(phy_dev->netdev); + + free_netdev(nic->netdev); +} diff --git a/trunk/drivers/staging/gdm72xx/gdm_wimax.h b/trunk/drivers/staging/gdm72xx/gdm_wimax.h new file mode 100644 index 000000000000..023e6492e33d --- /dev/null +++ b/trunk/drivers/staging/gdm72xx/gdm_wimax.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2012 GCT Semiconductor, Inc. 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 __GDM_WIMAX_H__ +#define __GDM_WIMAX_H__ + +#include +#include +#include +#include "wm_ioctl.h" +#if defined(CONFIG_WIMAX_GDM72XX_QOS) +#include "gdm_qos.h" +#endif + +#define DRIVER_VERSION "3.2.3" + +/*#define ETH_P_IP 0x0800 */ +/*#define ETH_P_ARP 0x0806 */ +/*#define ETH_P_IPV6 0x86DD */ + +#define H2L(x) __cpu_to_le16(x) +#define L2H(x) __le16_to_cpu(x) +#define DH2L(x) __cpu_to_le32(x) +#define DL2H(x) __le32_to_cpu(x) + +#define H2B(x) __cpu_to_be16(x) +#define B2H(x) __be16_to_cpu(x) +#define DH2B(x) __cpu_to_be32(x) +#define DB2H(x) __be32_to_cpu(x) + +struct phy_dev { + void *priv_dev; + struct net_device *netdev; + + int (*send_func)(void *priv_dev, void *data, int len, + void (*cb)(void *cb_data), void *cb_data); + int (*rcv_func)(void *priv_dev, + void (*cb)(void *cb_data, void *data, int len), + void *cb_data); +}; + +struct nic { + struct net_device *netdev; + struct phy_dev *phy_dev; + + struct net_device_stats stats; + + struct data_s sdk_data[SIOC_DATA_MAX]; + +#if defined(CONFIG_WIMAX_GDM72XX_QOS) + struct qos_cb_s qos; +#endif + +}; + + +#if 0 +#define dprintk(fmt, args ...) printk(KERN_DEBUG " [GDM] " fmt, ## args) +#else +#define dprintk(...) +#endif + +/*#define DEBUG_SDU */ +#if defined(DEBUG_SDU) +#define DUMP_SDU_ALL (1<<0) +#define DUMP_SDU_ARP (1<<1) +#define DUMP_SDU_IP (1<<2) +#define DUMP_SDU_IP_TCP (1<<8) +#define DUMP_SDU_IP_UDP (1<<9) +#define DUMP_SDU_IP_ICMP (1<<10) +#define DUMP_PACKET (DUMP_SDU_ALL) +#endif + +/*#define DEBUG_HCI */ + +/*#define LOOPBACK_TEST */ + +extern int register_wimax_device(struct phy_dev *phy_dev, struct device *pdev); +extern int gdm_wimax_send_tx(struct sk_buff *skb, struct net_device *dev); +extern void unregister_wimax_device(struct phy_dev *phy_dev); + +#endif diff --git a/trunk/drivers/staging/gdm72xx/hci.h b/trunk/drivers/staging/gdm72xx/hci.h new file mode 100644 index 000000000000..0e0676622f1d --- /dev/null +++ b/trunk/drivers/staging/gdm72xx/hci.h @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2012 GCT Semiconductor, Inc. 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 HCI_H_20080801 +#define HCI_H_20080801 + +#define HCI_HEADER_SIZE 4 +#define HCI_VALUE_OFFS (HCI_HEADER_SIZE) +#define HCI_MAX_PACKET 2048 +#define HCI_MAX_PARAM (HCI_MAX_PACKET-HCI_HEADER_SIZE) +#define HCI_MAX_TLV 32 + +/* CMD-EVT */ + +/* Category 0 */ +#define WIMAX_RESET 0x0000 +#define WIMAX_SET_INFO 0x0001 +#define WIMAX_GET_INFO 0x0002 +#define WIMAX_GET_INFO_RESULT 0x8003 +#define WIMAX_RADIO_OFF 0x0004 +#define WIMAX_RADIO_ON 0x0006 +#define WIMAX_WIMAX_RESET 0x0007 /* Is this still here */ + +/* Category 1 */ +#define WIMAX_NET_ENTRY 0x0100 +#define WIMAX_NET_DISCONN 0x0102 +#define WIMAX_ENTER_SLEEP 0x0103 +#define WIMAX_EXIT_SLEEP 0x0104 +#define WIMAX_ENTER_IDLE 0x0105 +#define WIMAX_EXIT_IDLE 0x0106 +#define WIMAX_MODE_CHANGE 0x8108 +#define WIMAX_HANDOVER 0x8109 /* obsolete */ + +#define WIMAX_SCAN 0x010d +#define WIMAX_SCAN_COMPLETE 0x810e +#define WIMAX_SCAN_RESULT 0x810f + +#define WIMAX_CONNECT 0x0110 +#define WIMAX_CONNECT_START 0x8111 +#define WIMAX_CONNECT_COMPLETE 0x8112 +#define WIMAX_ASSOC_START 0x8113 +#define WIMAX_ASSOC_COMPLETE 0x8114 +#define WIMAX_DISCONN_IND 0x8115 +#define WIMAX_ENTRY_IND 0x8116 +#define WIMAX_HO_START 0x8117 +#define WIMAX_HO_COMPLETE 0x8118 +#define WIMAX_RADIO_STATE_IND 0x8119 +#define WIMAX_IP_RENEW_IND 0x811a + +#define WIMAX_DISCOVER_NSP 0x011d +#define WIMAX_DISCOVER_NSP_RESULT 0x811e + +#define WIMAX_SDU_TX_FLOW 0x8125 + +/* Category 2 */ +#define WIMAX_TX_EAP 0x0200 +#define WIMAX_RX_EAP 0x8201 +#define WIMAX_TX_SDU 0x0202 +#define WIMAX_RX_SDU 0x8203 +#define WIMAX_RX_SDU_AGGR 0x8204 +#define WIMAX_TX_SDU_AGGR 0x0205 + +/* Category 3 */ +#define WIMAX_DM_CMD 0x030a +#define WIMAX_DM_RSP 0x830b + +#define WIMAX_CLI_CMD 0x030c +#define WIMAX_CLI_RSP 0x830d + +#define WIMAX_DL_IMAGE 0x0310 +#define WIMAX_DL_IMAGE_STATUS 0x8311 +#define WIMAX_UL_IMAGE 0x0312 +#define WIMAX_UL_IMAGE_RESULT 0x8313 +#define WIMAX_UL_IMAGE_STATUS 0x0314 + +#define WIMAX_EVT_MODEM_REPORT 0x8325 + +/* Category 0xF */ +#define WIMAX_FSM_UPDATE 0x8F01 +#define WIMAX_IF_UPDOWN 0x8F02 + #define WIMAX_IF_UP 1 + #define WIMAX_IF_DOWN 2 + +/* WIMAX mode */ +#define W_NULL 0 +#define W_STANDBY 1 +#define W_OOZ 2 +#define W_AWAKE 3 +#define W_IDLE 4 +#define W_SLEEP 5 +#define W_WAIT 6 + +#define W_NET_ENTRY_RNG 0x80 +#define W_NET_ENTRY_SBC 0x81 +#define W_NET_ENTRY_PKM 0x82 +#define W_NET_ENTRY_REG 0x83 +#define W_NET_ENTRY_DSX 0x84 + +#define W_NET_ENTRY_RNG_FAIL 0x1100100 +#define W_NET_ENTRY_SBC_FAIL 0x1100200 +#define W_NET_ENTRY_PKM_FAIL 0x1102000 +#define W_NET_ENTRY_REG_FAIL 0x1103000 +#define W_NET_ENTRY_DSX_FAIL 0x1104000 + +/* Scan Type */ +#define W_SCAN_ALL_CHANNEL 0 +#define W_SCAN_ALL_SUBSCRIPTION 1 +#define W_SCAN_SPECIFIED_SUBSCRIPTION 2 + +/* + * TLV + * + * [31:31] indicates the type is composite. + * [30:16] is the length of the type. 0 length means length is variable. + * [15:0] is the actual type. + * + */ +#define TLV_L(x) (((x) >> 16) & 0xff) +#define TLV_T(x) ((x) & 0xff) +#define TLV_COMPOSITE(x) ((x) >> 31) + +/* GENERAL */ +#define T_MAC_ADDRESS (0x00 | (6 << 16)) +#define T_BSID (0x01 | (6 << 16)) +#define T_MSK (0x02 | (64 << 16)) +#define T_RSSI_THRSHLD (0x03 | (1 << 16)) +#define T_FREQUENCY (0x04 | (4 << 16)) +#define T_CONN_CS_TYPE (0x05 | (1 << 16)) +#define T_HOST_IP_VER (0x06 | (1 << 16)) +#define T_STBY_SCAN_INTERVAL (0x07 | (4 << 16)) +#define T_OOZ_SCAN_INTERVAL (0x08 | (4 << 16)) +#define T_IMEI (0x09 | (8 << 16)) +#define T_PID (0x0a | (12 << 16)) + +#define T_CAPABILITY (0x1a | (4 << 16)) +#define T_RELEASE_NUMBER (0x1b | (4 << 16)) +#define T_DRIVER_REVISION (0x1c | (4 << 16)) +#define T_FW_REVISION (0x1d | (4 << 16)) +#define T_MAC_HW_REVISION (0x1e | (4 << 16)) +#define T_PHY_HW_REVISION (0x1f | (4 << 16)) + +/* HANDOVER */ +#define T_SCAN_INTERVAL (0x20 | (1 << 16)) + +#define T_RSC_RETAIN_TIME (0x2f | (2 << 16)) + +/* SLEEP */ +#define T_TYPE1_ISW (0x40 | (1 << 16)) + +#define T_SLP_START_TO (0x4a | (2 << 16)) + +/* IDLE */ +#define T_IDLE_MODE_TO (0x50 | (2 << 16)) + +#define T_IDLE_START_TO (0x54 | (2 << 16)) + +/* MONITOR */ +#define T_RSSI (0x60 | (1 << 16)) +#define T_CINR (0x61 | (1 << 16)) +#define T_TX_POWER (0x6a | (1 << 16)) +#define T_CUR_FREQ (0x7f | (4 << 16)) + + +/* WIMAX */ +#define T_MAX_SUBSCRIPTION (0xa1 | (1 << 16)) +#define T_MAX_SF (0xa2 | (1 << 16)) +#define T_PHY_TYPE (0xa3 | (1 << 16)) +#define T_PKM (0xa4 | (1 << 16)) +#define T_AUTH_POLICY (0xa5 | (1 << 16)) +#define T_CS_TYPE (0xa6 | (2 << 16)) +#define T_VENDOR_NAME (0xa7 | (0 << 16)) +#define T_MOD_NAME (0xa8 | (0 << 16)) +#define T_PACKET_FILTER (0xa9 | (1 << 16)) +#define T_NSP_CHANGE_COUNT (0xaa | (4 << 16)) +#define T_RADIO_STATE (0xab | (1 << 16)) +#define T_URI_CONTACT_TYPE (0xac | (1 << 16)) +#define T_URI_TEXT (0xad | (0 << 16)) +#define T_URI (0xae | (0 << 16)) +#define T_ENABLE_AUTH (0xaf | (1 << 16)) +#define T_TIMEOUT (0xb0 | (2 << 16)) +#define T_RUN_MODE (0xb1 | (1 << 16)) +#define T_OMADMT_VER (0xb2 | (4 << 16)) +/* This is measured in seconds from 00:00:00 GMT January 1, 1970. */ +#define T_RTC_TIME (0xb3 | (4 << 16)) +#define T_CERT_STATUS (0xb4 | (4 << 16)) +#define T_CERT_MASK (0xb5 | (4 << 16)) +#define T_EMSK (0xb6 | (64 << 16)) + +/* Subscription TLV */ +#define T_SUBSCRIPTION_LIST (0xd1 | (0 << 16) | (1 << 31)) +#define T_H_NSPID (0xd2 | (3 << 16)) +#define T_NSP_NAME (0xd3 | (0 << 16)) +#define T_SUBSCRIPTION_NAME (0xd4 | (0 << 16)) +#define T_SUBSCRIPTION_FLAG (0xd5 | (2 << 16)) +#define T_V_NSPID (0xd6 | (3 << 16)) +#define T_NAP_ID (0xd7 | (3 << 16)) +#define T_PREAMBLES (0xd8 | (15 << 16)) +#define T_BW (0xd9 | (4 << 16)) +#define T_FFTSIZE (0xda | (4 << 16)) +#define T_DUPLEX_MODE (0xdb | (4 << 16)) + +struct hci_s { + unsigned short cmd_evt; + unsigned short length; + unsigned char data[0]; +} __packed; + +#endif diff --git a/trunk/drivers/staging/gdm72xx/netlink_k.c b/trunk/drivers/staging/gdm72xx/netlink_k.c new file mode 100644 index 000000000000..292af0f7f451 --- /dev/null +++ b/trunk/drivers/staging/gdm72xx/netlink_k.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2012 GCT Semiconductor, Inc. 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 + +#if !defined(NLMSG_HDRLEN) +#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr))) +#endif + +#define ND_MAX_GROUP 30 +#define ND_IFINDEX_LEN sizeof(int) +#define ND_NLMSG_SPACE(len) (NLMSG_SPACE(len) + ND_IFINDEX_LEN) +#define ND_NLMSG_DATA(nlh) \ + ((void *)((char *)NLMSG_DATA(nlh) + ND_IFINDEX_LEN)) +#define ND_NLMSG_S_LEN(len) (len+ND_IFINDEX_LEN) +#define ND_NLMSG_R_LEN(nlh) (nlh->nlmsg_len-ND_IFINDEX_LEN) +#define ND_NLMSG_IFIDX(nlh) NLMSG_DATA(nlh) +#define ND_MAX_MSG_LEN 8096 + +#if defined(DEFINE_MUTEX) +static DEFINE_MUTEX(netlink_mutex); +#else +static struct semaphore netlink_mutex; +#define mutex_lock(x) down(x) +#define mutex_unlock(x) up(x) +#endif + +static void (*rcv_cb)(struct net_device *dev, u16 type, void *msg, int len); + +static void netlink_rcv_cb(struct sk_buff *skb) +{ + struct nlmsghdr *nlh; + struct net_device *dev; + u32 mlen; + void *msg; + int ifindex; + + if (skb->len >= NLMSG_SPACE(0)) { + nlh = (struct nlmsghdr *)skb->data; + + if (skb->len < nlh->nlmsg_len || + nlh->nlmsg_len > ND_MAX_MSG_LEN) { + printk(KERN_ERR "Invalid length (%d,%d)\n", skb->len, + nlh->nlmsg_len); + return; + } + + memcpy(&ifindex, ND_NLMSG_IFIDX(nlh), ND_IFINDEX_LEN); + msg = ND_NLMSG_DATA(nlh); + mlen = ND_NLMSG_R_LEN(nlh); + + if (rcv_cb) { + dev = dev_get_by_index(&init_net, ifindex); + if (dev) { + rcv_cb(dev, nlh->nlmsg_type, msg, mlen); + dev_put(dev); + } else + printk(KERN_ERR "dev_get_by_index(%d) " + "is not found.\n", ifindex); + } else + printk(KERN_ERR "Unregistered Callback\n"); + } +} + +static void netlink_rcv(struct sk_buff *skb) +{ + mutex_lock(&netlink_mutex); + netlink_rcv_cb(skb); + mutex_unlock(&netlink_mutex); +} + +struct sock *netlink_init(int unit, void (*cb)(struct net_device *dev, u16 type, + void *msg, int len)) +{ + struct sock *sock; + +#if !defined(DEFINE_MUTEX) + init_MUTEX(&netlink_mutex); +#endif + + sock = netlink_kernel_create(&init_net, unit, 0, netlink_rcv, NULL, + THIS_MODULE); + + if (sock) + rcv_cb = cb; + + return sock; +} + +void netlink_exit(struct sock *sock) +{ + sock_release(sock->sk_socket); +} + +int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len) +{ + static u32 seq; + struct sk_buff *skb = NULL; + struct nlmsghdr *nlh; + int ret = 0; + + if (group > ND_MAX_GROUP) { + printk(KERN_ERR "Group %d is invalied.\n", group); + printk(KERN_ERR "Valid group is 0 ~ %d.\n", ND_MAX_GROUP); + return -EINVAL; + } + + skb = alloc_skb(NLMSG_SPACE(len), GFP_ATOMIC); + if (!skb) { + printk(KERN_ERR "netlink_broadcast ret=%d\n", ret); + return -ENOMEM; + } + + seq++; + nlh = NLMSG_PUT(skb, 0, seq, type, len); + memcpy(NLMSG_DATA(nlh), msg, len); + + NETLINK_CB(skb).pid = 0; + NETLINK_CB(skb).dst_group = 0; + + ret = netlink_broadcast(sock, skb, 0, group+1, GFP_ATOMIC); + + if (!ret) + return len; + else { + if (ret != -ESRCH) { + printk(KERN_ERR "netlink_broadcast g=%d, t=%d, l=%d, r=%d\n", + group, type, len, ret); + } + ret = 0; + } + +nlmsg_failure: + return ret; +} diff --git a/trunk/drivers/staging/gdm72xx/netlink_k.h b/trunk/drivers/staging/gdm72xx/netlink_k.h new file mode 100644 index 000000000000..1dffaa6156e4 --- /dev/null +++ b/trunk/drivers/staging/gdm72xx/netlink_k.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2012 GCT Semiconductor, Inc. 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. + */ + +#if !defined(NETLINK_H_20081202) +#define NETLINK_H_20081202 +#include +#include + +struct sock *netlink_init(int unit, + void (*cb)(struct net_device *dev, u16 type, void *msg, int len)); +void netlink_exit(struct sock *sock); +int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len); + +#endif diff --git a/trunk/drivers/staging/gdm72xx/sdio_boot.c b/trunk/drivers/staging/gdm72xx/sdio_boot.c new file mode 100644 index 000000000000..6ff4dc372522 --- /dev/null +++ b/trunk/drivers/staging/gdm72xx/sdio_boot.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2012 GCT Semiconductor, Inc. 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 +#include +#include +#include + +#include +#include +#include + +#include "gdm_sdio.h" + +#define TYPE_A_HEADER_SIZE 4 +#define TYPE_A_LOOKAHEAD_SIZE 16 +#define YMEM0_SIZE 0x8000 /* 32kbytes */ +#define DOWNLOAD_SIZE (YMEM0_SIZE - TYPE_A_HEADER_SIZE) + +#define KRN_PATH "/lib/firmware/gdm72xx/gdmskrn.bin" +#define RFS_PATH "/lib/firmware/gdm72xx/gdmsrfs.bin" + +static u8 *tx_buf; + +static int ack_ready(struct sdio_func *func) +{ + unsigned long start = jiffies; + u8 val; + int ret; + + while ((jiffies - start) < HZ) { + val = sdio_readb(func, 0x13, &ret); + if (val & 0x01) + return 1; + schedule(); + } + + return 0; +} + +static int download_image(struct sdio_func *func, char *img_name) +{ + int ret = 0, len, size, pno; + struct file *filp = NULL; + struct inode *inode = NULL; + u8 *buf = tx_buf; + loff_t pos = 0; + + filp = filp_open(img_name, O_RDONLY | O_LARGEFILE, 0); + if (IS_ERR(filp)) { + printk(KERN_ERR "Can't find %s.\n", img_name); + return -ENOENT; + } + + if (filp->f_dentry) + inode = filp->f_dentry->d_inode; + if (!inode || !S_ISREG(inode->i_mode)) { + printk(KERN_ERR "Invalid file type: %s\n", img_name); + ret = -EINVAL; + goto out; + } + + size = i_size_read(inode->i_mapping->host); + if (size <= 0) { + printk(KERN_ERR "Unable to find file size: %s\n", img_name); + ret = size; + goto out; + } + + pno = 0; + while ((len = filp->f_op->read(filp, buf + TYPE_A_HEADER_SIZE, + DOWNLOAD_SIZE, &pos))) { + if (len < 0) { + ret = -1; + goto out; + } + + buf[0] = len & 0xff; + buf[1] = (len >> 8) & 0xff; + buf[2] = (len >> 16) & 0xff; + + if (pos >= size) /* The last packet */ + buf[3] = 2; + else + buf[3] = 0; + + ret = sdio_memcpy_toio(func, 0, buf, len + TYPE_A_HEADER_SIZE); + if (ret < 0) { + printk(KERN_ERR "gdmwm: send image error: " + "packet number = %d ret = %d\n", pno, ret); + goto out; + } + if (buf[3] == 2) /* The last packet */ + break; + if (!ack_ready(func)) { + ret = -EIO; + printk(KERN_ERR "gdmwm: Ack is not ready.\n"); + goto out; + } + ret = sdio_memcpy_fromio(func, buf, 0, TYPE_A_LOOKAHEAD_SIZE); + if (ret < 0) { + printk(KERN_ERR "gdmwm: receive ack error: " + "packet number = %d ret = %d\n", pno, ret); + goto out; + } + sdio_writeb(func, 0x01, 0x13, &ret); + sdio_writeb(func, 0x00, 0x10, &ret); /* PCRRT */ + + pno++; + } +out: + filp_close(filp, current->files); + return ret; +} + +int sdio_boot(struct sdio_func *func) +{ + static mm_segment_t fs; + int ret; + + tx_buf = kmalloc(YMEM0_SIZE, GFP_KERNEL); + if (tx_buf == NULL) { + printk(KERN_ERR "Error: kmalloc: %s %d\n", __func__, __LINE__); + return -ENOMEM; + } + + fs = get_fs(); + set_fs(get_ds()); + + ret = download_image(func, KRN_PATH); + if (ret) + goto restore_fs; + printk(KERN_INFO "GCT: Kernel download success.\n"); + + ret = download_image(func, RFS_PATH); + if (ret) + goto restore_fs; + printk(KERN_INFO "GCT: Filesystem download success.\n"); + +restore_fs: + set_fs(fs); + kfree(tx_buf); + return ret; +} diff --git a/trunk/drivers/staging/gdm72xx/sdio_boot.h b/trunk/drivers/staging/gdm72xx/sdio_boot.h new file mode 100644 index 000000000000..373ac28063c6 --- /dev/null +++ b/trunk/drivers/staging/gdm72xx/sdio_boot.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2012 GCT Semiconductor, Inc. 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 __SDIO_BOOT_H__ +#define __SDIO_BOOT_H__ + +struct sdio_func; + +extern int sdio_boot(struct sdio_func *func); + +#endif /* __SDIO_BOOT_H__ */ diff --git a/trunk/drivers/staging/gdm72xx/usb_boot.c b/trunk/drivers/staging/gdm72xx/usb_boot.c new file mode 100644 index 000000000000..5a0e030220dc --- /dev/null +++ b/trunk/drivers/staging/gdm72xx/usb_boot.c @@ -0,0 +1,404 @@ +/* + * Copyright (c) 2012 GCT Semiconductor, Inc. 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 +#include +#include + +#include +#include "gdm_usb.h" +#include "usb_boot.h" + +#define DN_KERNEL_MAGIC_NUMBER 0x10760001 +#define DN_ROOTFS_MAGIC_NUMBER 0x10760002 + +#define DOWNLOAD_SIZE 1024 + +#define DH2B(x) __cpu_to_be32(x) +#define DL2H(x) __le32_to_cpu(x) + +#define MIN(a, b) ((a) > (b) ? (b) : (a)) + +#define MAX_IMG_CNT 16 +#define UIMG_PATH "/lib/firmware/gdm72xx/gdmuimg.bin" +#define KERN_PATH "/lib/firmware/gdm72xx/zImage" +#define FS_PATH "/lib/firmware/gdm72xx/ramdisk.jffs2" + +struct dn_header { + u32 magic_num; + u32 file_size; +}; + +struct img_header { + u32 magic_code; + u32 count; + u32 len; + u32 offset[MAX_IMG_CNT]; + char hostname[32]; + char date[32]; +}; + +struct fw_info { + u32 id; + u32 len; + u32 kernel_len; + u32 rootfs_len; + u32 kernel_offset; + u32 rootfs_offset; + u32 fw_ver; + u32 mac_ver; + char hostname[32]; + char userid[16]; + char date[32]; + char user_desc[128]; +}; + +static void array_le32_to_cpu(u32 *arr, int num) +{ + int i; + for (i = 0; i < num; i++, arr++) + *arr = DL2H(*arr); +} + +static u8 *tx_buf; + +static int gdm_wibro_send(struct usb_device *usbdev, void *data, int len) +{ + int ret; + int actual; + + ret = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), data, len, + &actual, 1000); + + if (ret < 0) { + printk(KERN_ERR "Error : usb_bulk_msg ( result = %d )\n", ret); + return ret; + } + return 0; +} + +static int gdm_wibro_recv(struct usb_device *usbdev, void *data, int len) +{ + int ret; + int actual; + + ret = usb_bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, 2), data, len, + &actual, 5000); + + if (ret < 0) { + printk(KERN_ERR "Error : usb_bulk_msg(recv) ( result = %d )\n", + ret); + return ret; + } + return 0; +} + +static int download_image(struct usb_device *usbdev, struct file *filp, + loff_t *pos, u32 img_len, u32 magic_num) +{ + struct dn_header h; + int ret = 0; + u32 size; + int len, readn; + + size = (img_len + DOWNLOAD_SIZE - 1) & ~(DOWNLOAD_SIZE - 1); + h.magic_num = DH2B(magic_num); + h.file_size = DH2B(size); + + ret = gdm_wibro_send(usbdev, &h, sizeof(h)); + if (ret < 0) + goto out; + + readn = 0; + while ((len = filp->f_op->read(filp, tx_buf, DOWNLOAD_SIZE, pos))) { + + if (len < 0) { + ret = -1; + goto out; + } + readn += len; + + ret = gdm_wibro_send(usbdev, tx_buf, DOWNLOAD_SIZE); + if (ret < 0) + goto out; + if (readn >= img_len) + break; + } + + if (readn < img_len) { + printk(KERN_ERR "gdmwm: Cannot read to the requested size. " + "Read = %d Requested = %d\n", readn, img_len); + ret = -EIO; + } +out: + + return ret; +} + +int usb_boot(struct usb_device *usbdev, u16 pid) +{ + int i, ret = 0; + struct file *filp = NULL; + struct inode *inode = NULL; + static mm_segment_t fs; + struct img_header hdr; + struct fw_info fw_info; + loff_t pos = 0; + char *img_name = UIMG_PATH; + int len; + + tx_buf = kmalloc(DOWNLOAD_SIZE, GFP_KERNEL); + if (tx_buf == NULL) { + printk(KERN_ERR "Error: kmalloc\n"); + return -ENOMEM; + } + + fs = get_fs(); + set_fs(get_ds()); + + filp = filp_open(img_name, O_RDONLY | O_LARGEFILE, 0); + if (IS_ERR(filp)) { + printk(KERN_ERR "Can't find %s.\n", img_name); + set_fs(fs); + ret = -ENOENT; + goto restore_fs; + } + + if (filp->f_dentry) + inode = filp->f_dentry->d_inode; + if (!inode || !S_ISREG(inode->i_mode)) { + printk(KERN_ERR "Invalid file type: %s\n", img_name); + ret = -EINVAL; + goto out; + } + + len = filp->f_op->read(filp, (u8 *)&hdr, sizeof(hdr), &pos); + if (len != sizeof(hdr)) { + printk(KERN_ERR "gdmwm: Cannot read the image info.\n"); + ret = -EIO; + goto out; + } + + array_le32_to_cpu((u32 *)&hdr, 19); +#if 0 + if (hdr.magic_code != 0x10767fff) { + printk(KERN_ERR "gdmwm: Invalid magic code 0x%08x\n", + hdr.magic_code); + ret = -EINVAL; + goto out; + } +#endif + if (hdr.count > MAX_IMG_CNT) { + printk(KERN_ERR "gdmwm: Too many images. %d\n", hdr.count); + ret = -EINVAL; + goto out; + } + + for (i = 0; i < hdr.count; i++) { + if (hdr.offset[i] > hdr.len) { + printk(KERN_ERR "gdmwm: Invalid offset. " + "Entry = %d Offset = 0x%08x " + "Image length = 0x%08x\n", + i, hdr.offset[i], hdr.len); + ret = -EINVAL; + goto out; + } + + pos = hdr.offset[i]; + len = filp->f_op->read(filp, (u8 *)&fw_info, sizeof(fw_info), + &pos); + if (len != sizeof(fw_info)) { + printk(KERN_ERR "gdmwm: Cannot read the FW info.\n"); + ret = -EIO; + goto out; + } + + array_le32_to_cpu((u32 *)&fw_info, 8); +#if 0 + if ((fw_info.id & 0xfffff000) != 0x10767000) { + printk(KERN_ERR "gdmwm: Invalid FW id. 0x%08x\n", + fw_info.id); + ret = -EIO; + goto out; + } +#endif + + if ((fw_info.id & 0xffff) != pid) + continue; + + pos = hdr.offset[i] + fw_info.kernel_offset; + ret = download_image(usbdev, filp, &pos, fw_info.kernel_len, + DN_KERNEL_MAGIC_NUMBER); + if (ret < 0) + goto out; + printk(KERN_INFO "GCT: Kernel download success.\n"); + + pos = hdr.offset[i] + fw_info.rootfs_offset; + ret = download_image(usbdev, filp, &pos, fw_info.rootfs_len, + DN_ROOTFS_MAGIC_NUMBER); + if (ret < 0) + goto out; + printk(KERN_INFO "GCT: Filesystem download success.\n"); + + break; + } + + if (i == hdr.count) { + printk(KERN_ERR "Firmware for gsk%x is not installed.\n", pid); + ret = -EINVAL; + } +out: + filp_close(filp, current->files); + +restore_fs: + set_fs(fs); + kfree(tx_buf); + return ret; +} + +/*#define GDM7205_PADDING 256 */ +#define DOWNLOAD_CHUCK 2048 +#define KERNEL_TYPE_STRING "linux" +#define FS_TYPE_STRING "rootfs" + +static int em_wait_ack(struct usb_device *usbdev, int send_zlp) +{ + int ack; + int ret = -1; + + if (send_zlp) { + /*Send ZLP*/ + ret = gdm_wibro_send(usbdev, NULL, 0); + if (ret < 0) + goto out; + } + + /*Wait for ACK*/ + ret = gdm_wibro_recv(usbdev, &ack, sizeof(ack)); + if (ret < 0) + goto out; +out: + return ret; +} + +static int em_download_image(struct usb_device *usbdev, char *path, + char *type_string) +{ + struct file *filp; + struct inode *inode; + static mm_segment_t fs; + char *buf = NULL; + loff_t pos = 0; + int ret = 0; + int len, readn = 0; + #if defined(GDM7205_PADDING) + const int pad_size = GDM7205_PADDING; + #else + const int pad_size = 0; + #endif + + fs = get_fs(); + set_fs(get_ds()); + + filp = filp_open(path, O_RDONLY | O_LARGEFILE, 0); + if (IS_ERR(filp)) { + printk(KERN_ERR "Can't find %s.\n", path); + set_fs(fs); + ret = -ENOENT; + goto restore_fs; + } + + if (filp->f_dentry) { + inode = filp->f_dentry->d_inode; + if (!inode || !S_ISREG(inode->i_mode)) { + printk(KERN_ERR "Invalid file type: %s\n", path); + ret = -EINVAL; + goto out; + } + } + + buf = kmalloc(DOWNLOAD_CHUCK + pad_size, GFP_KERNEL); + if (buf == NULL) { + printk(KERN_ERR "Error: kmalloc\n"); + return -ENOMEM; + } + + strcpy(buf+pad_size, type_string); + ret = gdm_wibro_send(usbdev, buf, strlen(type_string)+pad_size); + if (ret < 0) + goto out; + + while ((len = filp->f_op->read(filp, buf+pad_size, DOWNLOAD_CHUCK, + &pos))) { + if (len < 0) { + ret = -1; + goto out; + } + readn += len; + + ret = gdm_wibro_send(usbdev, buf, len+pad_size); + if (ret < 0) + goto out; + + ret = em_wait_ack(usbdev, ((len+pad_size) % 512 == 0)); + if (ret < 0) + goto out; + } + + ret = em_wait_ack(usbdev, 1); + if (ret < 0) + goto out; + +out: + filp_close(filp, current->files); + +restore_fs: + set_fs(fs); + + kfree(buf); + + return ret; +} + +static int em_fw_reset(struct usb_device *usbdev) +{ + int ret; + + /*Send ZLP*/ + ret = gdm_wibro_send(usbdev, NULL, 0); + return ret; +} + +int usb_emergency(struct usb_device *usbdev) +{ + int ret; + + ret = em_download_image(usbdev, KERN_PATH, KERNEL_TYPE_STRING); + if (ret < 0) + goto out; + printk(KERN_INFO "GCT Emergency: Kernel download success.\n"); + + ret = em_download_image(usbdev, FS_PATH, FS_TYPE_STRING); + if (ret < 0) + goto out; + printk(KERN_INFO "GCT Emergency: Filesystem download success.\n"); + + ret = em_fw_reset(usbdev); +out: + return ret; +} diff --git a/trunk/drivers/staging/gdm72xx/usb_boot.h b/trunk/drivers/staging/gdm72xx/usb_boot.h new file mode 100644 index 000000000000..c715cd3cd300 --- /dev/null +++ b/trunk/drivers/staging/gdm72xx/usb_boot.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2012 GCT Semiconductor, Inc. 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 __USB_BOOT_H__ +#define __USB_BOOT_H__ + +struct usb_device; + +extern int usb_boot(struct usb_device *usbdev, u16 pid); +extern int usb_emergency(struct usb_device *usbdev); + +#endif /* __USB_BOOT_H__ */ diff --git a/trunk/drivers/staging/gdm72xx/usb_ids.h b/trunk/drivers/staging/gdm72xx/usb_ids.h new file mode 100644 index 000000000000..b34616b7203f --- /dev/null +++ b/trunk/drivers/staging/gdm72xx/usb_ids.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2012 GCT Semiconductor, Inc. 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 __USB_IDS_H__ +#define __USB_IDS_H__ + +/*You can replace vendor-ID as yours.*/ +#define GCT_VID 0x1076 + +/*You can replace product-ID as yours.*/ +#define GCT_PID1 0x7e00 +#define GCT_PID2 0x7f00 + +#define USB_DEVICE_ID_MATCH_DEVICE_INTERFACE \ + (USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_CLASS) + +#define USB_DEVICE_INTF(vend, prod, intf) \ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE_INTERFACE, \ + .idVendor = (vend), .idProduct = (prod), .bInterfaceClass = (intf) + +#define EMERGENCY_PID 0x720f +#define BL_PID_MASK 0xffc0 + +#define USB_DEVICE_BOOTLOADER(vid, pid) \ + {USB_DEVICE((vid), ((pid)&BL_PID_MASK)|B_DOWNLOAD)}, \ + {USB_DEVICE((vid), ((pid)&BL_PID_MASK)|B_DOWNLOAD|B_DIFF_DL_DRV)} + +#define USB_DEVICE_CDC_DATA(vid, pid) \ + {USB_DEVICE_INTF((vid), (pid), USB_CLASS_CDC_DATA)} + +static const struct usb_device_id id_table[] = { + USB_DEVICE_BOOTLOADER(GCT_VID, GCT_PID1), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x1), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x2), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x3), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x4), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x5), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x6), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x7), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x8), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x9), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xa), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xb), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xc), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xd), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xe), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xf), + + USB_DEVICE_BOOTLOADER(GCT_VID, GCT_PID2), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x1), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x2), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x3), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x4), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x5), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x6), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x7), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x8), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x9), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xa), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xb), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xc), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xd), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xe), + USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xf), + + {USB_DEVICE(GCT_VID, EMERGENCY_PID)}, + { } +}; + +#endif /* __USB_IDS_H__ */ diff --git a/trunk/drivers/staging/gdm72xx/wm_ioctl.h b/trunk/drivers/staging/gdm72xx/wm_ioctl.h new file mode 100644 index 000000000000..9f46e06f2303 --- /dev/null +++ b/trunk/drivers/staging/gdm72xx/wm_ioctl.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2012 GCT Semiconductor, Inc. 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. + */ + +#if !defined(WM_IOCTL_H_20080714) +#define WM_IOCTL_H_20080714 +#if !defined(__KERNEL__) +#include +#endif + +#define NETLINK_WIMAX 31 + +#define SIOCWMIOCTL SIOCDEVPRIVATE + +#define SIOCG_DATA 0x8D10 +#define SIOCS_DATA 0x8D11 + +enum { + SIOC_DATA_FSM, + SIOC_DATA_NETLIST, + SIOC_DATA_CONNNSP, + SIOC_DATA_CONNCOMP, + SIOC_DATA_PROFILEID, + + SIOC_DATA_END +}; + +#define SIOC_DATA_MAX 16 + +/* FSM */ +enum { + M_INIT = 0, + M_OPEN_OFF, + M_OPEN_ON, + M_SCAN, + M_CONNECTING, + M_CONNECTED, + M_FSM_END, + + C_INIT = 0, + C_CONNSTART, + C_ASSOCSTART, + C_RNG, + C_SBC, + C_AUTH, + C_REG, + C_DSX, + C_ASSOCCOMPLETE, + C_CONNCOMPLETE, + C_FSM_END, + + D_INIT = 0, + D_READY, + D_LISTEN, + D_IPACQUISITION, + + END_FSM +}; + +struct fsm_s { + int m_status; /*main status*/ + int c_status; /*connection status*/ + int d_status; /*oma-dm status*/ +}; + +struct data_s { + int size; + void *buf; +}; + +struct wm_req_s { + union { + char ifrn_name[IFNAMSIZ]; + } ifr_ifrn; + + unsigned short cmd; + + unsigned short data_id; + struct data_s data; + +/* NOTE: sizeof(struct wm_req_s) must be less than sizeof(struct ifreq). */ +}; + +#ifndef ifr_name +#define ifr_name ifr_ifrn.ifrn_name +#endif + +#endif diff --git a/trunk/drivers/staging/iio/Documentation/device.txt b/trunk/drivers/staging/iio/Documentation/device.txt index 8926f2448cc9..0338c7cd0a8b 100644 --- a/trunk/drivers/staging/iio/Documentation/device.txt +++ b/trunk/drivers/staging/iio/Documentation/device.txt @@ -8,7 +8,7 @@ The crucial structure for device drivers in iio is iio_dev. First allocate one using: -struct iio_dev *indio_dev = iio_allocate_device(sizeof(struct chip_state)); +struct iio_dev *indio_dev = iio_device_alloc(sizeof(struct chip_state)); where chip_state is a structure of local state data for this instance of the chip. @@ -78,4 +78,4 @@ be registered afterwards (otherwise the whole parentage of devices gets confused) On remove, iio_device_unregister(indio_dev) will remove the device from -the core, and iio_free_device will clean up. +the core, and iio_device_free will clean up. diff --git a/trunk/drivers/staging/iio/Documentation/generic_buffer.c b/trunk/drivers/staging/iio/Documentation/generic_buffer.c index 69a05b9456d6..bf553356fdad 100644 --- a/trunk/drivers/staging/iio/Documentation/generic_buffer.c +++ b/trunk/drivers/staging/iio/Documentation/generic_buffer.c @@ -60,9 +60,9 @@ void print2byte(int input, struct iio_channel_info *info) /* First swap if incorrect endian */ if (info->be) - input = be16toh((uint_16t)input); + input = be16toh((uint16_t)input); else - input = le16toh((uint_16t)input); + input = le16toh((uint16_t)input); /* shift before conversion to avoid sign extension of left aligned data */ diff --git a/trunk/drivers/staging/iio/Documentation/iio_event_monitor.c b/trunk/drivers/staging/iio/Documentation/iio_event_monitor.c index 0d21a277305f..22275845fb12 100644 --- a/trunk/drivers/staging/iio/Documentation/iio_event_monitor.c +++ b/trunk/drivers/staging/iio/Documentation/iio_event_monitor.c @@ -27,7 +27,7 @@ #include #include #include "iio_utils.h" -#include "../events.h" +#include static const char * const iio_chan_type_name_spec[] = { [IIO_VOLTAGE] = "voltage", diff --git a/trunk/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2583 b/trunk/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2583 new file mode 100755 index 000000000000..470f7ad9c073 --- /dev/null +++ b/trunk/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2583 @@ -0,0 +1,6 @@ +What: /sys/bus/iio/devices/device[n]/in_illuminance0_calibrate +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + This property causes an internal calibration of the als gain trim + value which is later used in calculating illuminance in lux. diff --git a/trunk/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2x7x b/trunk/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2x7x new file mode 100755 index 000000000000..b2798b258bf7 --- /dev/null +++ b/trunk/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2x7x @@ -0,0 +1,13 @@ +What: /sys/bus/iio/devices/device[n]/in_illuminance0_calibrate +KernelVersion: 3.3-rc1 +Contact: linux-iio@vger.kernel.org +Description: + Causes an internal calibration of the als gain trim + value which is later used in calculating illuminance in lux. + +What: /sys/bus/iio/devices/device[n]/in_proximity0_calibrate +KernelVersion: 3.3-rc1 +Contact: linux-iio@vger.kernel.org +Description: + Causes a recalculation and adjustment to the + proximity_thresh_rising_value. diff --git a/trunk/drivers/staging/iio/Documentation/sysfs-bus-iio-ad7192 b/trunk/drivers/staging/iio/Documentation/sysfs-bus-iio-ad7192 new file mode 100644 index 000000000000..1c35c507cc05 --- /dev/null +++ b/trunk/drivers/staging/iio/Documentation/sysfs-bus-iio-ad7192 @@ -0,0 +1,20 @@ +What: /sys/.../iio:deviceX/ac_excitation_en +KernelVersion: 3.1.0 +Contact: linux-iio@vger.kernel.org +Description: + This attribute, if available, is used to enable the AC + excitation mode found on some converters. In ac excitation mode, + the polarity of the excitation voltage is reversed on + alternate cycles, to eliminate DC errors. + +What: /sys/.../iio:deviceX/bridge_switch_en +KernelVersion: 3.1.0 +Contact: linux-iio@vger.kernel.org +Description: + This attribute, if available, is used to close or open the + bridge power down switch found on some converters. + In bridge applications, such as strain gauges and load cells, + the bridge itself consumes the majority of the current in the + system. To minimize the current consumption of the system, + the bridge can be disconnected (when it is not being used + using the bridge_switch_en attribute. diff --git a/trunk/drivers/staging/iio/Documentation/sysfs-bus-iio-dds b/trunk/drivers/staging/iio/Documentation/sysfs-bus-iio-dds index ffdd5478a35d..ee8c509c6733 100644 --- a/trunk/drivers/staging/iio/Documentation/sysfs-bus-iio-dds +++ b/trunk/drivers/staging/iio/Documentation/sysfs-bus-iio-dds @@ -1,83 +1,86 @@ -What: /sys/bus/iio/devices/.../ddsX_freqY +What: /sys/bus/iio/devices/.../out_altvoltageX_frequencyY KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: Stores frequency into tuning word Y. - There will be more than one ddsX_freqY file, which allows for - pin controlled FSK Frequency Shift Keying - (ddsX_pincontrol_freq_en is active) or the user can control - the desired active tuning word by writing Y to the - ddsX_freqsymbol file. + There will be more than one out_altvoltageX_frequencyY file, + which allows for pin controlled FSK Frequency Shift Keying + (out_altvoltageX_pincontrol_frequency_en is active) or the user + can control the desired active tuning word by writing Y to the + out_altvoltageX_frequencysymbol file. -What: /sys/bus/iio/devices/.../ddsX_freqY_scale +What: /sys/bus/iio/devices/.../out_altvoltageX_frequencyY_scale KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: - Scale to be applied to ddsX_freqY in order to obtain the - desired value in Hz. If shared across all frequency registers - Y is not present. It is also possible X is not present if - shared across all channels. + Scale to be applied to out_altvoltageX_frequencyY in order to + obtain the desired value in Hz. If shared across all frequency + registers Y is not present. It is also possible X is not present + if shared across all channels. -What: /sys/bus/iio/devices/.../ddsX_freqsymbol +What: /sys/bus/iio/devices/.../out_altvoltageX_frequencysymbol KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: Specifies the active output frequency tuning word. The value - corresponds to the Y in ddsX_freqY. To exit this mode the user - can write ddsX_pincontrol_freq_en or ddsX_out_enable file. + corresponds to the Y in out_altvoltageX_frequencyY. + To exit this mode the user can write + out_altvoltageX_pincontrol_frequency_en or + out_altvoltageX_out_enable file. -What: /sys/bus/iio/devices/.../ddsX_phaseY +What: /sys/bus/iio/devices/.../out_altvoltageX_phaseY KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: Stores phase into Y. - There will be more than one ddsX_phaseY file, which allows for - pin controlled PSK Phase Shift Keying - (ddsX_pincontrol_phase_en is active) or the user can + There will be more than one out_altvoltageX_phaseY file, which + allows for pin controlled PSK Phase Shift Keying + (out_altvoltageX_pincontrol_phase_en is active) or the user can control the desired phase Y which is added to the phase - accumulator output by writing Y to the en_phase file. + accumulator output by writing Y to the phase_en file. -What: /sys/bus/iio/devices/.../ddsX_phaseY_scale +What: /sys/bus/iio/devices/.../out_altvoltageX_phaseY_scale KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: - Scale to be applied to ddsX_phaseY in order to obtain the - desired value in rad. If shared across all phase registers + Scale to be applied to out_altvoltageX_phaseY in order to obtain + the desired value in rad. If shared across all phase registers Y is not present. It is also possible X is not present if shared across all channels. -What: /sys/bus/iio/devices/.../ddsX_phasesymbol +What: /sys/bus/iio/devices/.../out_altvoltageX_phasesymbol KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: Specifies the active phase Y which is added to the phase accumulator output. The value corresponds to the Y in - ddsX_phaseY. To exit this mode the user can write - ddsX_pincontrol_phase_en or disable file. + out_altvoltageX_phaseY. To exit this mode the user can write + out_altvoltageX_pincontrol_phase_en or disable file. -What: /sys/bus/iio/devices/.../ddsX_pincontrol_en -What: /sys/bus/iio/devices/.../ddsX_pincontrol_freq_en -What: /sys/bus/iio/devices/.../ddsX_pincontrol_phase_en +What: /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_en +What: /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_frequency_en +What: /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_phase_en KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: - ddsX_pincontrol_en: Both, the active frequency and phase is - controlled by the respective phase and frequency control inputs. - In case the device in question allows to independent controls, - then there are dedicated files (ddsX_pincontrol_freq_en, - ddsX_pincontrol_phase_en). + out_altvoltageX_pincontrol_en: Both, the active frequency and + phase is controlled by the respective phase and frequency + control inputs. In case the device in features independent + controls, then there are dedicated files + (out_altvoltageX_pincontrol_frequency_en, + out_altvoltageX_pincontrol_phase_en). -What: /sys/bus/iio/devices/.../ddsX_out_enable -What: /sys/bus/iio/devices/.../ddsX_outY_enable +What: /sys/bus/iio/devices/.../out_altvoltageX_out_enable +What: /sys/bus/iio/devices/.../out_altvoltageX_outY_enable KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: - ddsX_outY_enable controls signal generation on output Y of - channel X. Y may be suppressed if all channels are + out_altvoltageX_outY_enable controls signal generation on + output Y of channel X. Y may be suppressed if all channels are controlled together. -What: /sys/bus/iio/devices/.../ddsX_outY_wavetype +What: /sys/bus/iio/devices/.../out_altvoltageX_outY_wavetype KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: @@ -86,7 +89,7 @@ Description: For a list of available output waveform options read available_output_modes. -What: /sys/bus/iio/devices/.../ddsX_outY_wavetype_available +What: /sys/bus/iio/devices/.../out_altvoltageX_outY_wavetype_available KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: diff --git a/trunk/drivers/staging/iio/Documentation/sysfs-bus-iio-light b/trunk/drivers/staging/iio/Documentation/sysfs-bus-iio-light index edbf470e4e30..715c74dcb53a 100644 --- a/trunk/drivers/staging/iio/Documentation/sysfs-bus-iio-light +++ b/trunk/drivers/staging/iio/Documentation/sysfs-bus-iio-light @@ -26,7 +26,7 @@ Description: Hardware dependent list of possible values supported for the adc_resolution of the given sensor. -What: /sys/bus/iio/devices/device[n]/illuminance0[_input|_raw] +What: /sys/bus/iio/devices/device[n]/in_illuminance0[_input|_raw] KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: @@ -45,7 +45,7 @@ Description: do this calculation manually by reading the infrared sensor value and doing the negation in sw. -What: /sys/bus/iio/devices/device[n]/proximity[_input|_raw] +What: /sys/bus/iio/devices/device[n]/in_proximity[_input|_raw] KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: @@ -63,23 +63,22 @@ Description: and if expressed in SI units, should include _input. If this value is not in SI units, then it should include _raw. -What: /sys/bus/iio/devices/device[n]/illuminance0_target +What: /sys/bus/iio/devices/device[n]/in_illuminance0_target KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: This property gets/sets the last known external lux measurement used in/for calibration. -What: /sys/bus/iio/devices/device[n]/illuminance0_integration_time +What: /sys/bus/iio/devices/device[n]/in_illuminance0_integration_time KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: This property gets/sets the sensors ADC analog integration time. -What: /sys/bus/iio/devices/device[n]/illuminance0_calibscale +What: /sys/bus/iio/devices/device[n]/in_illuminance0_lux_table KernelVersion: 2.6.37 Contact: linux-iio@vger.kernel.org Description: - Hardware or software applied calibration scale factor assumed - to account for attenuation due to industrial design (glass - filters or aperture holes). + This property gets/sets the table of coefficients + used in calculating illuminance in lux. diff --git a/trunk/drivers/staging/iio/Documentation/trigger.txt b/trunk/drivers/staging/iio/Documentation/trigger.txt index fc2012ebc100..75cc37ff1ed0 100644 --- a/trunk/drivers/staging/iio/Documentation/trigger.txt +++ b/trunk/drivers/staging/iio/Documentation/trigger.txt @@ -5,7 +5,7 @@ an IIO device. Whilst this can create device specific complexities such triggers are registered with the core in the same way as stand-alone triggers. -struct iio_trig *trig = iio_allocate_trigger("", ...); +struct iio_trig *trig = iio_trigger_alloc("", ...); allocates a trigger structure. The key elements to then fill in within a driver are: diff --git a/trunk/drivers/staging/iio/Kconfig b/trunk/drivers/staging/iio/Kconfig index fe1586718880..3c8e5ec26ac1 100644 --- a/trunk/drivers/staging/iio/Kconfig +++ b/trunk/drivers/staging/iio/Kconfig @@ -1,16 +1,9 @@ # # Industrial I/O subsytem configuration # +menu "IIO staging drivers" + depends on IIO -menuconfig IIO - tristate "Industrial I/O support" - depends on GENERIC_HARDIRQS - help - The industrial I/O subsystem provides a unified framework for - drivers for many different types of embedded sensors using a - number of different physical interfaces (i2c, spi, etc). See - drivers/staging/iio/Documentation for more information. -if IIO config IIO_ST_HWMON tristate "Hwmon driver that uses channels specified via iio maps" depends on HWMON @@ -19,12 +12,6 @@ config IIO_ST_HWMON map allows IIO devices to provide basic hwmon functionality for those channels specified in the map. -config IIO_BUFFER - bool "Enable buffer support within IIO" - help - Provide core support for various buffer based data - acquisition methods. - if IIO_BUFFER config IIO_SW_RING @@ -36,39 +23,14 @@ config IIO_SW_RING with the intention that some devices would be able to write in interrupt context. -config IIO_KFIFO_BUF - select IIO_TRIGGER - tristate "Industrial I/O buffering based on kfifo" - help - A simple fifo based on kfifo. Use this if you want a fifo - rather than a ring buffer. Note that this currently provides - no buffer events so it is up to userspace to work out how - often to read from the buffer. - endif # IIO_BUFFER -config IIO_TRIGGER - boolean "Enable triggered sampling support" - help - Provides IIO core support for triggers. Currently these - are used to initialize capture of samples to push into - ring buffers. The triggers are effectively a 'capture - data now' interrupt. - -config IIO_CONSUMERS_PER_TRIGGER - int "Maximum number of consumers per trigger" - depends on IIO_TRIGGER - default "2" - help - This value controls the maximum number of consumers that a - given trigger may handle. Default is 2. - source "drivers/staging/iio/accel/Kconfig" source "drivers/staging/iio/adc/Kconfig" source "drivers/staging/iio/addac/Kconfig" source "drivers/staging/iio/cdc/Kconfig" source "drivers/staging/iio/dac/Kconfig" -source "drivers/staging/iio/dds/Kconfig" +source "drivers/staging/iio/frequency/Kconfig" source "drivers/staging/iio/gyro/Kconfig" source "drivers/staging/iio/impedance-analyzer/Kconfig" source "drivers/staging/iio/imu/Kconfig" @@ -104,4 +66,4 @@ config IIO_SIMPLE_DUMMY_BUFFER endif # IIO_SIMPLE_DUMMY -endif # IIO +endmenu diff --git a/trunk/drivers/staging/iio/Makefile b/trunk/drivers/staging/iio/Makefile index 5075291dda7a..6a46d5afb380 100644 --- a/trunk/drivers/staging/iio/Makefile +++ b/trunk/drivers/staging/iio/Makefile @@ -2,13 +2,7 @@ # Makefile for the industrial I/O core. # -obj-$(CONFIG_IIO) += industrialio.o -industrialio-y := industrialio-core.o industrialio-event.o inkern.o -industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o -industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o - obj-$(CONFIG_IIO_SW_RING) += ring_sw.o -obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o obj-$(CONFIG_IIO_SIMPLE_DUMMY) += iio_dummy.o iio_dummy-y := iio_simple_dummy.o @@ -24,7 +18,7 @@ obj-y += adc/ obj-y += addac/ obj-y += cdc/ obj-y += dac/ -obj-y += dds/ +obj-y += frequency/ obj-y += gyro/ obj-y += impedance-analyzer/ obj-y += imu/ diff --git a/trunk/drivers/staging/iio/TODO b/trunk/drivers/staging/iio/TODO index d1ad35e24abb..cf3f9489b9da 100644 --- a/trunk/drivers/staging/iio/TODO +++ b/trunk/drivers/staging/iio/TODO @@ -67,7 +67,7 @@ e-mailing the normal IIO list (see below). Documentation 1) Lots of cleanup and expansion. -2) Some device require indvidual docs. +2) Some device require individual docs. Contact: Jonathan Cameron . Mailing list: linux-iio@vger.kernel.org diff --git a/trunk/drivers/staging/iio/accel/adis16201_core.c b/trunk/drivers/staging/iio/accel/adis16201_core.c index d439e45d07fa..02b340919c0e 100644 --- a/trunk/drivers/staging/iio/accel/adis16201_core.c +++ b/trunk/drivers/staging/iio/accel/adis16201_core.c @@ -15,9 +15,9 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../buffer.h" +#include +#include +#include #include "adis16201.h" @@ -171,7 +171,7 @@ static ssize_t adis16201_write_reset(struct device *dev, ret = strtobool(buf, &res); if (ret || !res) return ret; - return adis16201_reset(dev_get_drvdata(dev)); + return adis16201_reset(dev_to_iio_dev(dev)); } int adis16201_set_irq(struct iio_dev *indio_dev, bool enable) @@ -298,7 +298,7 @@ static int adis16201_read_raw(struct iio_dev *indio_dev, s16 val16; switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: mutex_lock(&indio_dev->mlock); addr = adis16201_addresses[chan->address][0]; ret = adis16201_spi_read_reg_16(indio_dev, addr, &val16); @@ -406,39 +406,104 @@ static int adis16201_write_raw(struct iio_dev *indio_dev, } static struct iio_chan_spec adis16201_channels[] = { - IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "supply", 0, 0, + { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 0, + .extend_name = "supply", + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - in_supply, ADIS16201_SCAN_SUPPLY, - IIO_ST('u', 12, 16, 0), 0), - IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0, + .address = in_supply, + .scan_index = ADIS16201_SCAN_SUPPLY, + .scan_type = { + .sign = 'u', + .realbits = 12, + .storagebits = 16, + }, + }, { + .type = IIO_TEMP, + .indexed = 1, + .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT | IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, - temp, ADIS16201_SCAN_TEMP, - IIO_ST('u', 12, 16, 0), 0), - IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X, + .address = temp, + .scan_index = ADIS16201_SCAN_TEMP, + .scan_type = { + .sign = 'u', + .realbits = 12, + .storagebits = 16, + }, + }, { + .type = IIO_ACCEL, + .modified = 1, + .channel2 = IIO_MOD_X, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, - accel_x, ADIS16201_SCAN_ACC_X, - IIO_ST('s', 14, 16, 0), 0), - IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y, + .address = accel_x, + .scan_index = ADIS16201_SCAN_ACC_X, + .scan_type = { + .sign = 's', + .realbits = 14, + .storagebits = 16, + }, + }, { + .type = IIO_ACCEL, + .modified = 1, + .channel2 = IIO_MOD_Y, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, - accel_y, ADIS16201_SCAN_ACC_Y, - IIO_ST('s', 14, 16, 0), 0), - IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0, + .address = accel_y, + .scan_index = ADIS16201_SCAN_ACC_Y, + .scan_type = { + .sign = 's', + .realbits = 14, + .storagebits = 16, + }, + }, { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 1, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - in_aux, ADIS16201_SCAN_AUX_ADC, - IIO_ST('u', 12, 16, 0), 0), - IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_X, + .address = in_aux, + .scan_index = ADIS16201_SCAN_AUX_ADC, + .scan_type = { + .sign = 'u', + .realbits = 12, + .storagebits = 16, + }, + }, { + .type = IIO_INCLI, + .modified = 1, + .channel2 = IIO_MOD_X, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, - incli_x, ADIS16201_SCAN_INCLI_X, - IIO_ST('s', 14, 16, 0), 0), - IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_Y, + .address = incli_x, + .scan_index = ADIS16201_SCAN_INCLI_X, + .scan_type = { + .sign = 's', + .realbits = 14, + .storagebits = 16, + }, + }, { + .type = IIO_INCLI, + .modified = 1, + .channel2 = IIO_MOD_Y, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, - incli_y, ADIS16201_SCAN_INCLI_Y, - IIO_ST('s', 14, 16, 0), 0), + .address = incli_y, + .scan_index = ADIS16201_SCAN_INCLI_Y, + .scan_type = { + .sign = 's', + .realbits = 14, + .storagebits = 16, + }, + }, IIO_CHAN_SOFT_TIMESTAMP(7) }; @@ -467,7 +532,7 @@ static int __devinit adis16201_probe(struct spi_device *spi) struct iio_dev *indio_dev; /* setup the industrialio driver allocated elements */ - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -522,7 +587,7 @@ static int __devinit adis16201_probe(struct spi_device *spi) error_unreg_ring_funcs: adis16201_unconfigure_ring(indio_dev); error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; } @@ -535,7 +600,7 @@ static int adis16201_remove(struct spi_device *spi) adis16201_remove_trigger(indio_dev); iio_buffer_unregister(indio_dev); adis16201_unconfigure_ring(indio_dev); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/accel/adis16201_ring.c b/trunk/drivers/staging/iio/accel/adis16201_ring.c index 97f9e6b159d9..247602a8e54c 100644 --- a/trunk/drivers/staging/iio/accel/adis16201_ring.c +++ b/trunk/drivers/staging/iio/accel/adis16201_ring.c @@ -5,9 +5,9 @@ #include #include -#include "../iio.h" +#include #include "../ring_sw.h" -#include "../trigger_consumer.h" +#include #include "adis16201.h" @@ -66,9 +66,8 @@ static irqreturn_t adis16201_trigger_handler(int irq, void *p) int i = 0; s16 *data; - size_t datasize = ring->access->get_bytes_per_datum(ring); - data = kmalloc(datasize, GFP_KERNEL); + data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); if (data == NULL) { dev_err(&st->us->dev, "memory alloc failed in ring bh"); return -ENOMEM; @@ -81,7 +80,7 @@ static irqreturn_t adis16201_trigger_handler(int irq, void *p) data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2])); /* Guaranteed to be aligned with 8 byte boundary */ - if (ring->scan_timestamp) + if (indio_dev->scan_timestamp) *((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp; ring->access->store_to(ring, (u8 *)data, pf->timestamp); diff --git a/trunk/drivers/staging/iio/accel/adis16201_trigger.c b/trunk/drivers/staging/iio/accel/adis16201_trigger.c index bce505e716d0..96fdabbac201 100644 --- a/trunk/drivers/staging/iio/accel/adis16201_trigger.c +++ b/trunk/drivers/staging/iio/accel/adis16201_trigger.c @@ -3,8 +3,8 @@ #include #include -#include "../iio.h" -#include "../trigger.h" +#include +#include #include "adis16201.h" /** @@ -29,7 +29,7 @@ int adis16201_probe_trigger(struct iio_dev *indio_dev) int ret; struct adis16201_state *st = iio_priv(indio_dev); - st->trig = iio_allocate_trigger("adis16201-dev%d", indio_dev->id); + st->trig = iio_trigger_alloc("adis16201-dev%d", indio_dev->id); if (st->trig == NULL) { ret = -ENOMEM; goto error_ret; @@ -56,7 +56,7 @@ int adis16201_probe_trigger(struct iio_dev *indio_dev) error_free_irq: free_irq(st->us->irq, st->trig); error_free_trig: - iio_free_trigger(st->trig); + iio_trigger_free(st->trig); error_ret: return ret; } @@ -67,5 +67,5 @@ void adis16201_remove_trigger(struct iio_dev *indio_dev) iio_trigger_unregister(state->trig); free_irq(state->us->irq, state->trig); - iio_free_trigger(state->trig); + iio_trigger_free(state->trig); } diff --git a/trunk/drivers/staging/iio/accel/adis16203_core.c b/trunk/drivers/staging/iio/accel/adis16203_core.c index 1a5140f9e3f4..15d46bfd1b42 100644 --- a/trunk/drivers/staging/iio/accel/adis16203_core.c +++ b/trunk/drivers/staging/iio/accel/adis16203_core.c @@ -15,9 +15,9 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../buffer.h" +#include +#include +#include #include "adis16203.h" @@ -182,7 +182,7 @@ static ssize_t adis16203_write_reset(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); if (len < 1) return -EINVAL; switch (buf[0]) { @@ -305,7 +305,7 @@ static int adis16203_read_raw(struct iio_dev *indio_dev, u8 addr; s16 val16; switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: mutex_lock(&indio_dev->mlock); addr = adis16203_addresses[chan->address][0]; ret = adis16203_spi_read_reg_16(indio_dev, addr, &val16); @@ -372,29 +372,75 @@ static int adis16203_read_raw(struct iio_dev *indio_dev, } static struct iio_chan_spec adis16203_channels[] = { - IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "supply", 0, 0, - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - in_supply, ADIS16203_SCAN_SUPPLY, - IIO_ST('u', 12, 16, 0), 0), - IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0, - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - in_aux, ADIS16203_SCAN_AUX_ADC, - IIO_ST('u', 12, 16, 0), 0), - IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_X, - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, - incli_x, ADIS16203_SCAN_INCLI_X, - IIO_ST('s', 14, 16, 0), 0), - /* Fixme: Not what it appears to be - see data sheet */ - IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_Y, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - incli_y, ADIS16203_SCAN_INCLI_Y, - IIO_ST('s', 14, 16, 0), 0), - IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0, - IIO_CHAN_INFO_SCALE_SEPARATE_BIT | - IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, - temp, ADIS16203_SCAN_TEMP, - IIO_ST('u', 12, 16, 0), 0), + { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 0, + .extend_name = "supply", + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + .address = in_supply, + .scan_index = ADIS16203_SCAN_SUPPLY, + .scan_type = { + .sign = 'u', + .realbits = 12, + .storagebits = 16, + }, + }, { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 1, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + .address = in_aux, + .scan_index = ADIS16203_SCAN_AUX_ADC, + .scan_type = { + .sign = 'u', + .realbits = 12, + .storagebits = 16, + }, + }, { + .type = IIO_INCLI, + .modified = 1, + .channel2 = IIO_MOD_X, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, + .address = incli_x, + .scan_index = ADIS16203_SCAN_INCLI_X, + .scan_type = { + .sign = 's', + .realbits = 14, + .storagebits = 16, + }, + }, { /* Fixme: Not what it appears to be - see data sheet */ + .type = IIO_INCLI, + .modified = 1, + .channel2 = IIO_MOD_Y, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, + .address = incli_y, + .scan_index = ADIS16203_SCAN_INCLI_Y, + .scan_type = { + .sign = 's', + .realbits = 14, + .storagebits = 16, + }, + }, { + .type = IIO_TEMP, + .indexed = 1, + .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, + .address = temp, + .scan_index = ADIS16203_SCAN_TEMP, + .scan_type = { + .sign = 'u', + .realbits = 12, + .storagebits = 16, + }, + }, IIO_CHAN_SOFT_TIMESTAMP(5), }; @@ -423,7 +469,7 @@ static int __devinit adis16203_probe(struct spi_device *spi) struct adis16203_state *st; /* setup the industrialio driver allocated elements */ - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -477,7 +523,7 @@ static int __devinit adis16203_probe(struct spi_device *spi) error_unreg_ring_funcs: adis16203_unconfigure_ring(indio_dev); error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; } @@ -490,7 +536,7 @@ static int adis16203_remove(struct spi_device *spi) adis16203_remove_trigger(indio_dev); iio_buffer_unregister(indio_dev); adis16203_unconfigure_ring(indio_dev); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/accel/adis16203_ring.c b/trunk/drivers/staging/iio/accel/adis16203_ring.c index 6a8963db4f60..7bbd2c2bbd19 100644 --- a/trunk/drivers/staging/iio/accel/adis16203_ring.c +++ b/trunk/drivers/staging/iio/accel/adis16203_ring.c @@ -5,20 +5,19 @@ #include #include -#include "../iio.h" +#include #include "../ring_sw.h" -#include "../trigger_consumer.h" +#include #include "adis16203.h" /** * adis16203_read_ring_data() read data registers which will be placed into ring - * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @indio_dev: the IIO device * @rx: somewhere to pass back the value read **/ -static int adis16203_read_ring_data(struct device *dev, u8 *rx) +static int adis16203_read_ring_data(struct iio_dev *indio_dev, u8 *rx) { struct spi_message msg; - struct iio_dev *indio_dev = dev_get_drvdata(dev); struct adis16203_state *st = iio_priv(indio_dev); struct spi_transfer xfers[ADIS16203_OUTPUTS + 1]; int ret; @@ -66,22 +65,21 @@ static irqreturn_t adis16203_trigger_handler(int irq, void *p) int i = 0; s16 *data; - size_t datasize = ring->access->get_bytes_per_datum(ring); - data = kmalloc(datasize, GFP_KERNEL); + data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); if (data == NULL) { dev_err(&st->us->dev, "memory alloc failed in ring bh"); return -ENOMEM; } if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) && - adis16203_read_ring_data(&indio_dev->dev, st->rx) >= 0) + adis16203_read_ring_data(indio_dev, st->rx) >= 0) for (; i < bitmap_weight(indio_dev->active_scan_mask, indio_dev->masklength); i++) data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2])); /* Guaranteed to be aligned with 8 byte boundary */ - if (ring->scan_timestamp) + if (indio_dev->scan_timestamp) *((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp; ring->access->store_to(ring, diff --git a/trunk/drivers/staging/iio/accel/adis16203_trigger.c b/trunk/drivers/staging/iio/accel/adis16203_trigger.c index 24bcb8e15c55..b8a04073d6d7 100644 --- a/trunk/drivers/staging/iio/accel/adis16203_trigger.c +++ b/trunk/drivers/staging/iio/accel/adis16203_trigger.c @@ -3,8 +3,8 @@ #include #include -#include "../iio.h" -#include "../trigger.h" +#include +#include #include "adis16203.h" /** @@ -29,7 +29,7 @@ int adis16203_probe_trigger(struct iio_dev *indio_dev) int ret; struct adis16203_state *st = iio_priv(indio_dev); - st->trig = iio_allocate_trigger("adis16203-dev%d", indio_dev->id); + st->trig = iio_trigger_alloc("adis16203-dev%d", indio_dev->id); if (st->trig == NULL) { ret = -ENOMEM; goto error_ret; @@ -58,7 +58,7 @@ int adis16203_probe_trigger(struct iio_dev *indio_dev) error_free_irq: free_irq(st->us->irq, st->trig); error_free_trig: - iio_free_trigger(st->trig); + iio_trigger_free(st->trig); error_ret: return ret; } @@ -69,5 +69,5 @@ void adis16203_remove_trigger(struct iio_dev *indio_dev) iio_trigger_unregister(st->trig); free_irq(st->us->irq, st->trig); - iio_free_trigger(st->trig); + iio_trigger_free(st->trig); } diff --git a/trunk/drivers/staging/iio/accel/adis16204_core.c b/trunk/drivers/staging/iio/accel/adis16204_core.c index fa89364b841e..ac9d95e4ea47 100644 --- a/trunk/drivers/staging/iio/accel/adis16204_core.c +++ b/trunk/drivers/staging/iio/accel/adis16204_core.c @@ -18,9 +18,9 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../buffer.h" +#include +#include +#include #include "adis16204.h" @@ -173,7 +173,7 @@ static ssize_t adis16204_read_14bit_signed(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); s16 val = 0; ssize_t ret; @@ -211,7 +211,7 @@ static ssize_t adis16204_write_reset(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); if (len < 1) return -EINVAL; @@ -342,7 +342,7 @@ static int adis16204_read_raw(struct iio_dev *indio_dev, int addrind; switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: mutex_lock(&indio_dev->mlock); addr = adis16204_addresses[chan->address][0]; ret = adis16204_spi_read_reg_16(indio_dev, addr, &val16); @@ -444,31 +444,78 @@ static int adis16204_write_raw(struct iio_dev *indio_dev, } static struct iio_chan_spec adis16204_channels[] = { - IIO_CHAN(IIO_VOLTAGE, 0, 0, 0, "supply", 0, 0, - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - in_supply, ADIS16204_SCAN_SUPPLY, - IIO_ST('u', 12, 16, 0), 0), - IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0, - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - in_aux, ADIS16204_SCAN_AUX_ADC, - IIO_ST('u', 12, 16, 0), 0), - IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0, - IIO_CHAN_INFO_SCALE_SEPARATE_BIT | - IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, - temp, ADIS16204_SCAN_TEMP, - IIO_ST('u', 12, 16, 0), 0), - IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X, - IIO_CHAN_INFO_SCALE_SEPARATE_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | - IIO_CHAN_INFO_PEAK_SEPARATE_BIT, - accel_x, ADIS16204_SCAN_ACC_X, - IIO_ST('s', 14, 16, 0), 0), - IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y, - IIO_CHAN_INFO_SCALE_SEPARATE_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | - IIO_CHAN_INFO_PEAK_SEPARATE_BIT, - accel_y, ADIS16204_SCAN_ACC_Y, - IIO_ST('s', 14, 16, 0), 0), + { + .type = IIO_VOLTAGE, + .indexed = 1, /* Note was not previously indexed */ + .channel = 0, + .extend_name = "supply", + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + .address = in_supply, + .scan_index = ADIS16204_SCAN_SUPPLY, + .scan_type = { + .sign = 'u', + .realbits = 12, + .storagebits = 16, + }, + }, { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 1, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + .address = in_aux, + .scan_index = ADIS16204_SCAN_AUX_ADC, + .scan_type = { + .sign = 'u', + .realbits = 12, + .storagebits = 16, + }, + }, { + .type = IIO_TEMP, + .indexed = 1, + .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, + .address = temp, + .scan_index = ADIS16204_SCAN_TEMP, + .scan_type = { + .sign = 'u', + .realbits = 12, + .storagebits = 16, + }, + }, { + .type = IIO_ACCEL, + .modified = 1, + .channel2 = IIO_MOD_X, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_PEAK_SEPARATE_BIT, + .address = accel_x, + .scan_index = ADIS16204_SCAN_ACC_X, + .scan_type = { + .sign = 's', + .realbits = 14, + .storagebits = 16, + }, + }, { + .type = IIO_ACCEL, + .modified = 1, + .channel2 = IIO_MOD_Y, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + IIO_CHAN_INFO_PEAK_SEPARATE_BIT, + .address = accel_y, + .scan_index = ADIS16204_SCAN_ACC_Y, + .scan_type = { + .sign = 's', + .realbits = 14, + .storagebits = 16, + }, + }, IIO_CHAN_SOFT_TIMESTAMP(5), }; @@ -498,7 +545,7 @@ static int __devinit adis16204_probe(struct spi_device *spi) struct iio_dev *indio_dev; /* setup the industrialio driver allocated elements */ - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -551,7 +598,7 @@ static int __devinit adis16204_probe(struct spi_device *spi) error_unreg_ring_funcs: adis16204_unconfigure_ring(indio_dev); error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; } @@ -564,7 +611,7 @@ static int adis16204_remove(struct spi_device *spi) adis16204_remove_trigger(indio_dev); iio_buffer_unregister(indio_dev); adis16204_unconfigure_ring(indio_dev); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/accel/adis16204_ring.c b/trunk/drivers/staging/iio/accel/adis16204_ring.c index 5c8ab7338864..f73518bc6587 100644 --- a/trunk/drivers/staging/iio/accel/adis16204_ring.c +++ b/trunk/drivers/staging/iio/accel/adis16204_ring.c @@ -5,20 +5,19 @@ #include #include -#include "../iio.h" +#include #include "../ring_sw.h" -#include "../trigger_consumer.h" +#include #include "adis16204.h" /** * adis16204_read_ring_data() read data registers which will be placed into ring - * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @indio_dev: the IIO device * @rx: somewhere to pass back the value read **/ -static int adis16204_read_ring_data(struct device *dev, u8 *rx) +static int adis16204_read_ring_data(struct iio_dev *indio_dev, u8 *rx) { struct spi_message msg; - struct iio_dev *indio_dev = dev_get_drvdata(dev); struct adis16204_state *st = iio_priv(indio_dev); struct spi_transfer xfers[ADIS16204_OUTPUTS + 1]; int ret; @@ -63,22 +62,21 @@ static irqreturn_t adis16204_trigger_handler(int irq, void *p) struct iio_buffer *ring = indio_dev->buffer; int i = 0; s16 *data; - size_t datasize = ring->access->get_bytes_per_datum(ring); - data = kmalloc(datasize, GFP_KERNEL); + data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); if (data == NULL) { dev_err(&st->us->dev, "memory alloc failed in ring bh"); return -ENOMEM; } if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) && - adis16204_read_ring_data(&indio_dev->dev, st->rx) >= 0) + adis16204_read_ring_data(indio_dev, st->rx) >= 0) for (; i < bitmap_weight(indio_dev->active_scan_mask, indio_dev->masklength); i++) data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2])); /* Guaranteed to be aligned with 8 byte boundary */ - if (ring->scan_timestamp) + if (indio_dev->scan_timestamp) *((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp; ring->access->store_to(ring, (u8 *)data, pf->timestamp); diff --git a/trunk/drivers/staging/iio/accel/adis16204_trigger.c b/trunk/drivers/staging/iio/accel/adis16204_trigger.c index 6e542af02c09..408a1682368e 100644 --- a/trunk/drivers/staging/iio/accel/adis16204_trigger.c +++ b/trunk/drivers/staging/iio/accel/adis16204_trigger.c @@ -3,8 +3,8 @@ #include #include -#include "../iio.h" -#include "../trigger.h" +#include +#include #include "adis16204.h" /** @@ -29,7 +29,7 @@ int adis16204_probe_trigger(struct iio_dev *indio_dev) int ret; struct adis16204_state *st = iio_priv(indio_dev); - st->trig = iio_allocate_trigger("adis16204-dev%d", indio_dev->id); + st->trig = iio_trigger_alloc("adis16204-dev%d", indio_dev->id); if (st->trig == NULL) { ret = -ENOMEM; goto error_ret; @@ -58,7 +58,7 @@ int adis16204_probe_trigger(struct iio_dev *indio_dev) error_free_irq: free_irq(st->us->irq, st->trig); error_free_trig: - iio_free_trigger(st->trig); + iio_trigger_free(st->trig); error_ret: return ret; } @@ -69,5 +69,5 @@ void adis16204_remove_trigger(struct iio_dev *indio_dev) iio_trigger_unregister(state->trig); free_irq(state->us->irq, state->trig); - iio_free_trigger(state->trig); + iio_trigger_free(state->trig); } diff --git a/trunk/drivers/staging/iio/accel/adis16209_core.c b/trunk/drivers/staging/iio/accel/adis16209_core.c index a98715f6bd6d..f6fd0d31d4f0 100644 --- a/trunk/drivers/staging/iio/accel/adis16209_core.c +++ b/trunk/drivers/staging/iio/accel/adis16209_core.c @@ -16,9 +16,9 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../buffer.h" +#include +#include +#include #include "adis16209.h" @@ -157,7 +157,7 @@ static ssize_t adis16209_write_reset(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); if (len < 1) return -EINVAL; @@ -331,7 +331,7 @@ static int adis16209_read_raw(struct iio_dev *indio_dev, s16 val16; switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: mutex_lock(&indio_dev->mlock); addr = adis16209_addresses[chan->address][0]; ret = adis16209_spi_read_reg_16(indio_dev, addr, &val16); @@ -408,41 +408,114 @@ static int adis16209_read_raw(struct iio_dev *indio_dev, } static struct iio_chan_spec adis16209_channels[] = { - IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0, - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - in_supply, ADIS16209_SCAN_SUPPLY, - IIO_ST('u', 14, 16, 0), 0), - IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0, - IIO_CHAN_INFO_SCALE_SEPARATE_BIT | - IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, - temp, ADIS16209_SCAN_TEMP, - IIO_ST('u', 12, 16, 0), 0), - IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X, - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, - accel_x, ADIS16209_SCAN_ACC_X, - IIO_ST('s', 14, 16, 0), 0), - IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y, - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, - accel_y, ADIS16209_SCAN_ACC_Y, - IIO_ST('s', 14, 16, 0), 0), - IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0, - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - in_aux, ADIS16209_SCAN_AUX_ADC, - IIO_ST('u', 12, 16, 0), 0), - IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_X, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - incli_x, ADIS16209_SCAN_INCLI_X, - IIO_ST('s', 14, 16, 0), 0), - IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_Y, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - incli_y, ADIS16209_SCAN_INCLI_Y, - IIO_ST('s', 14, 16, 0), 0), - IIO_CHAN(IIO_ROT, 0, 1, 0, NULL, 0, IIO_MOD_X, - 0, - rot, ADIS16209_SCAN_ROT, - IIO_ST('s', 14, 16, 0), 0), + { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 0, + .extend_name = "supply", + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + .address = in_supply, + .scan_index = ADIS16209_SCAN_SUPPLY, + .scan_type = { + .sign = 'u', + .realbits = 14, + .storagebits = 16, + }, + }, { + .type = IIO_TEMP, + .indexed = 0, + .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, + .address = temp, + .scan_index = ADIS16209_SCAN_TEMP, + .scan_type = { + .sign = 'u', + .realbits = 12, + .storagebits = 16, + }, + }, { + .type = IIO_ACCEL, + .modified = 1, + .channel2 = IIO_MOD_X, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, + .address = accel_x, + .scan_index = ADIS16209_SCAN_ACC_X, + .scan_type = { + .sign = 's', + .realbits = 14, + .storagebits = 16, + }, + }, { + .type = IIO_ACCEL, + .modified = 1, + .channel2 = IIO_MOD_Y, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, + .address = accel_y, + .scan_index = ADIS16209_SCAN_ACC_Y, + .scan_type = { + .sign = 's', + .realbits = 14, + .storagebits = 16, + }, + }, { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 1, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + .address = in_aux, + .scan_index = ADIS16209_SCAN_AUX_ADC, + .scan_type = { + .sign = 'u', + .realbits = 12, + .storagebits = 16, + }, + }, { + .type = IIO_INCLI, + .modified = 1, + .channel2 = IIO_MOD_X, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, + .address = incli_x, + .scan_index = ADIS16209_SCAN_INCLI_X, + .scan_type = { + .sign = 's', + .realbits = 14, + .storagebits = 16, + }, + }, { + .type = IIO_INCLI, + .modified = 1, + .channel2 = IIO_MOD_Y, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, + .address = incli_y, + .scan_index = ADIS16209_SCAN_INCLI_Y, + .scan_type = { + .sign = 's', + .realbits = 14, + .storagebits = 16, + }, + }, { + .type = IIO_ROT, + .modified = 1, + .channel2 = IIO_MOD_X, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, + .address = rot, + .scan_index = ADIS16209_SCAN_ROT, + .scan_type = { + .sign = 's', + .realbits = 14, + .storagebits = 16, + }, + }, IIO_CHAN_SOFT_TIMESTAMP(8) }; @@ -471,7 +544,7 @@ static int __devinit adis16209_probe(struct spi_device *spi) struct iio_dev *indio_dev; /* setup the industrialio driver allocated elements */ - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -524,7 +597,7 @@ static int __devinit adis16209_probe(struct spi_device *spi) error_unreg_ring_funcs: adis16209_unconfigure_ring(indio_dev); error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; } @@ -539,7 +612,7 @@ static int adis16209_remove(struct spi_device *spi) adis16209_remove_trigger(indio_dev); iio_buffer_unregister(indio_dev); adis16209_unconfigure_ring(indio_dev); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/accel/adis16209_ring.c b/trunk/drivers/staging/iio/accel/adis16209_ring.c index 57254b6b38b7..090607504c93 100644 --- a/trunk/drivers/staging/iio/accel/adis16209_ring.c +++ b/trunk/drivers/staging/iio/accel/adis16209_ring.c @@ -5,20 +5,19 @@ #include #include -#include "../iio.h" +#include #include "../ring_sw.h" -#include "../trigger_consumer.h" +#include #include "adis16209.h" /** * adis16209_read_ring_data() read data registers which will be placed into ring - * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @indio_dev: the IIO device * @rx: somewhere to pass back the value read **/ -static int adis16209_read_ring_data(struct device *dev, u8 *rx) +static int adis16209_read_ring_data(struct iio_dev *indio_dev, u8 *rx) { struct spi_message msg; - struct iio_dev *indio_dev = dev_get_drvdata(dev); struct adis16209_state *st = iio_priv(indio_dev); struct spi_transfer xfers[ADIS16209_OUTPUTS + 1]; int ret; @@ -61,25 +60,23 @@ static irqreturn_t adis16209_trigger_handler(int irq, void *p) struct iio_dev *indio_dev = pf->indio_dev; struct adis16209_state *st = iio_priv(indio_dev); struct iio_buffer *ring = indio_dev->buffer; - int i = 0; s16 *data; - size_t datasize = ring->access->get_bytes_per_datum(ring); - data = kmalloc(datasize , GFP_KERNEL); + data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); if (data == NULL) { dev_err(&st->us->dev, "memory alloc failed in ring bh"); return -ENOMEM; } if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) && - adis16209_read_ring_data(&indio_dev->dev, st->rx) >= 0) + adis16209_read_ring_data(indio_dev, st->rx) >= 0) for (; i < bitmap_weight(indio_dev->active_scan_mask, indio_dev->masklength); i++) data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2])); /* Guaranteed to be aligned with 8 byte boundary */ - if (ring->scan_timestamp) + if (indio_dev->scan_timestamp) *((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp; ring->access->store_to(ring, (u8 *)data, pf->timestamp); diff --git a/trunk/drivers/staging/iio/accel/adis16209_trigger.c b/trunk/drivers/staging/iio/accel/adis16209_trigger.c index c5d82c1a55d9..2ad93dcaf40d 100644 --- a/trunk/drivers/staging/iio/accel/adis16209_trigger.c +++ b/trunk/drivers/staging/iio/accel/adis16209_trigger.c @@ -3,8 +3,8 @@ #include #include -#include "../iio.h" -#include "../trigger.h" +#include +#include #include "adis16209.h" /** @@ -38,7 +38,7 @@ int adis16209_probe_trigger(struct iio_dev *indio_dev) int ret; struct adis16209_state *st = iio_priv(indio_dev); - st->trig = iio_allocate_trigger("adis16209-dev%d", indio_dev->id); + st->trig = iio_trigger_alloc("adis16209-dev%d", indio_dev->id); if (st->trig == NULL) { ret = -ENOMEM; goto error_ret; @@ -66,7 +66,7 @@ int adis16209_probe_trigger(struct iio_dev *indio_dev) error_free_irq: free_irq(st->us->irq, st->trig); error_free_trig: - iio_free_trigger(st->trig); + iio_trigger_free(st->trig); error_ret: return ret; } @@ -77,5 +77,5 @@ void adis16209_remove_trigger(struct iio_dev *indio_dev) iio_trigger_unregister(st->trig); free_irq(st->us->irq, st->trig); - iio_free_trigger(st->trig); + iio_trigger_free(st->trig); } diff --git a/trunk/drivers/staging/iio/accel/adis16220_core.c b/trunk/drivers/staging/iio/accel/adis16220_core.c index 51a852d45482..6a9ac898cb01 100644 --- a/trunk/drivers/staging/iio/accel/adis16220_core.c +++ b/trunk/drivers/staging/iio/accel/adis16220_core.c @@ -15,8 +15,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #include "adis16220.h" @@ -145,7 +145,7 @@ static ssize_t adis16220_read_16bit(struct device *dev, char *buf) { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); ssize_t ret; s16 val = 0; @@ -164,7 +164,7 @@ static ssize_t adis16220_write_16bit(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; u16 val; @@ -208,7 +208,7 @@ static ssize_t adis16220_write_reset(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); bool val; int ret; @@ -228,7 +228,7 @@ static ssize_t adis16220_write_capture(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); bool val; int ret; @@ -393,7 +393,7 @@ static ssize_t adis16220_accel_bin_read(struct file *filp, struct kobject *kobj, size_t count) { struct device *dev = container_of(kobj, struct device, kobj); - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); return adis16220_capture_buffer_read(indio_dev, buf, off, count, @@ -415,7 +415,7 @@ static ssize_t adis16220_adc1_bin_read(struct file *filp, struct kobject *kobj, size_t count) { struct device *dev = container_of(kobj, struct device, kobj); - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); return adis16220_capture_buffer_read(indio_dev, buf, off, count, @@ -437,7 +437,7 @@ static ssize_t adis16220_adc2_bin_read(struct file *filp, struct kobject *kobj, size_t count) { struct device *dev = container_of(kobj, struct device, kobj); - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); return adis16220_capture_buffer_read(indio_dev, buf, off, count, @@ -507,7 +507,7 @@ static int adis16220_read_raw(struct iio_dev *indio_dev, u8 bits; switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: addrind = 0; break; case IIO_CHAN_INFO_OFFSET: @@ -575,11 +575,13 @@ static const struct iio_chan_spec adis16220_channels[] = { .indexed = 1, .channel = 0, .extend_name = "supply", - .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = in_supply, }, { .type = IIO_ACCEL, - .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT | IIO_CHAN_INFO_PEAK_SEPARATE_BIT, .address = accel, @@ -587,20 +589,23 @@ static const struct iio_chan_spec adis16220_channels[] = { .type = IIO_TEMP, .indexed = 1, .channel = 0, - .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = temp, }, { .type = IIO_VOLTAGE, .indexed = 1, .channel = 1, - .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = in_1, }, { .type = IIO_VOLTAGE, .indexed = 1, .channel = 2, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .address = in_2, } }; @@ -629,7 +634,7 @@ static int __devinit adis16220_probe(struct spi_device *spi) struct iio_dev *indio_dev; /* setup the industrialio driver allocated elements */ - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -680,7 +685,7 @@ static int __devinit adis16220_probe(struct spi_device *spi) error_unregister_dev: iio_device_unregister(indio_dev); error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; } @@ -695,7 +700,7 @@ static int adis16220_remove(struct spi_device *spi) sysfs_remove_bin_file(&indio_dev->dev.kobj, &adc1_bin); sysfs_remove_bin_file(&indio_dev->dev.kobj, &accel_bin); iio_device_unregister(indio_dev); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/accel/adis16240_core.c b/trunk/drivers/staging/iio/accel/adis16240_core.c index 17f77fef7f2b..8b15eaea3381 100644 --- a/trunk/drivers/staging/iio/accel/adis16240_core.c +++ b/trunk/drivers/staging/iio/accel/adis16240_core.c @@ -19,9 +19,9 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../buffer.h" +#include +#include +#include #include "adis16240.h" @@ -154,7 +154,7 @@ static ssize_t adis16240_spi_read_signed(struct device *dev, char *buf, unsigned bits) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); int ret; s16 val = 0; unsigned shift = 16 - bits; @@ -177,7 +177,7 @@ static ssize_t adis16240_read_12bit_signed(struct device *dev, char *buf) { ssize_t ret; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); /* Take the iio_dev status lock */ mutex_lock(&indio_dev->mlock); @@ -203,7 +203,7 @@ static ssize_t adis16240_write_reset(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); if (len < 1) return -EINVAL; @@ -365,7 +365,7 @@ static int adis16240_read_raw(struct iio_dev *indio_dev, s16 val16; switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: mutex_lock(&indio_dev->mlock); addr = adis16240_addresses[chan->address][0]; ret = adis16240_spi_read_reg_16(indio_dev, addr, &val16); @@ -468,33 +468,88 @@ static int adis16240_write_raw(struct iio_dev *indio_dev, } static struct iio_chan_spec adis16240_channels[] = { - IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "supply", 0, 0, - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - in_supply, ADIS16240_SCAN_SUPPLY, - IIO_ST('u', 10, 16, 0), 0), - IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0, - 0, - in_aux, ADIS16240_SCAN_AUX_ADC, - IIO_ST('u', 10, 16, 0), 0), - IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X, - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, - accel_x, ADIS16240_SCAN_ACC_X, - IIO_ST('s', 10, 16, 0), 0), - IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y, - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, - accel_y, ADIS16240_SCAN_ACC_Y, - IIO_ST('s', 10, 16, 0), 0), - IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Z, - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, - accel_z, ADIS16240_SCAN_ACC_Z, - IIO_ST('s', 10, 16, 0), 0), - IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0, - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - temp, ADIS16240_SCAN_TEMP, - IIO_ST('u', 10, 16, 0), 0), + { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 0, + .extend_name = "supply", + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + .address = in_supply, + .scan_index = ADIS16240_SCAN_SUPPLY, + .scan_type = { + .sign = 'u', + .realbits = 10, + .storagebits = 16, + }, + }, { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 1, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, + .address = in_aux, + .scan_index = ADIS16240_SCAN_AUX_ADC, + .scan_type = { + .sign = 'u', + .realbits = 10, + .storagebits = 16, + }, + }, { + .type = IIO_ACCEL, + .modified = 1, + .channel2 = IIO_MOD_X, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, + .address = accel_x, + .scan_index = ADIS16240_SCAN_ACC_X, + .scan_type = { + .sign = 's', + .realbits = 10, + .storagebits = 16, + }, + }, { + .type = IIO_ACCEL, + .modified = 1, + .channel2 = IIO_MOD_Y, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, + .address = accel_y, + .scan_index = ADIS16240_SCAN_ACC_Y, + .scan_type = { + .sign = 's', + .realbits = 10, + .storagebits = 16, + }, + }, { + .type = IIO_ACCEL, + .modified = 1, + .channel2 = IIO_MOD_Z, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, + .address = accel_z, + .scan_index = ADIS16240_SCAN_ACC_Z, + .scan_type = { + .sign = 's', + .realbits = 10, + .storagebits = 16, + }, + }, { + .type = IIO_TEMP, + .indexed = 1, + .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + .address = temp, + .scan_index = ADIS16240_SCAN_TEMP, + .scan_type = { + .sign = 'u', + .realbits = 10, + .storagebits = 16, + }, + }, IIO_CHAN_SOFT_TIMESTAMP(6) }; @@ -523,7 +578,7 @@ static int __devinit adis16240_probe(struct spi_device *spi) struct iio_dev *indio_dev; /* setup the industrialio driver allocated elements */ - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -576,7 +631,7 @@ static int __devinit adis16240_probe(struct spi_device *spi) error_unreg_ring_funcs: adis16240_unconfigure_ring(indio_dev); error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; } @@ -592,7 +647,7 @@ static int adis16240_remove(struct spi_device *spi) adis16240_remove_trigger(indio_dev); iio_buffer_unregister(indio_dev); adis16240_unconfigure_ring(indio_dev); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/accel/adis16240_ring.c b/trunk/drivers/staging/iio/accel/adis16240_ring.c index 43ba84e993ad..86a2a4757ea7 100644 --- a/trunk/drivers/staging/iio/accel/adis16240_ring.c +++ b/trunk/drivers/staging/iio/accel/adis16240_ring.c @@ -5,20 +5,19 @@ #include #include -#include "../iio.h" +#include #include "../ring_sw.h" -#include "../trigger_consumer.h" +#include #include "adis16240.h" /** * adis16240_read_ring_data() read data registers which will be placed into ring - * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @indio_dev: the IIO device * @rx: somewhere to pass back the value read **/ -static int adis16240_read_ring_data(struct device *dev, u8 *rx) +static int adis16240_read_ring_data(struct iio_dev *indio_dev, u8 *rx) { struct spi_message msg; - struct iio_dev *indio_dev = dev_get_drvdata(dev); struct adis16240_state *st = iio_priv(indio_dev); struct spi_transfer xfers[ADIS16240_OUTPUTS + 1]; int ret; @@ -61,22 +60,21 @@ static irqreturn_t adis16240_trigger_handler(int irq, void *p) int i = 0; s16 *data; - size_t datasize = ring->access->get_bytes_per_datum(ring); - data = kmalloc(datasize, GFP_KERNEL); + data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); if (data == NULL) { dev_err(&st->us->dev, "memory alloc failed in ring bh"); return -ENOMEM; } if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) && - adis16240_read_ring_data(&indio_dev->dev, st->rx) >= 0) + adis16240_read_ring_data(indio_dev, st->rx) >= 0) for (; i < bitmap_weight(indio_dev->active_scan_mask, indio_dev->masklength); i++) data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2])); /* Guaranteed to be aligned with 8 byte boundary */ - if (ring->scan_timestamp) + if (indio_dev->scan_timestamp) *((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp; ring->access->store_to(ring, (u8 *)data, pf->timestamp); diff --git a/trunk/drivers/staging/iio/accel/adis16240_trigger.c b/trunk/drivers/staging/iio/accel/adis16240_trigger.c index 8e0ce568e64c..fa90a22b143e 100644 --- a/trunk/drivers/staging/iio/accel/adis16240_trigger.c +++ b/trunk/drivers/staging/iio/accel/adis16240_trigger.c @@ -3,8 +3,8 @@ #include #include -#include "../iio.h" -#include "../trigger.h" +#include +#include #include "adis16240.h" /** @@ -38,7 +38,7 @@ int adis16240_probe_trigger(struct iio_dev *indio_dev) int ret; struct adis16240_state *st = iio_priv(indio_dev); - st->trig = iio_allocate_trigger("adis16240-dev%d", indio_dev->id); + st->trig = iio_trigger_alloc("adis16240-dev%d", indio_dev->id); if (st->trig == NULL) { ret = -ENOMEM; goto error_ret; @@ -67,7 +67,7 @@ int adis16240_probe_trigger(struct iio_dev *indio_dev) error_free_irq: free_irq(st->us->irq, st->trig); error_free_trig: - iio_free_trigger(st->trig); + iio_trigger_free(st->trig); error_ret: return ret; } @@ -78,5 +78,5 @@ void adis16240_remove_trigger(struct iio_dev *indio_dev) iio_trigger_unregister(st->trig); free_irq(st->us->irq, st->trig); - iio_free_trigger(st->trig); + iio_trigger_free(st->trig); } diff --git a/trunk/drivers/staging/iio/accel/kxsd9.c b/trunk/drivers/staging/iio/accel/kxsd9.c index d13d7215ff6e..8cf7cd943c90 100644 --- a/trunk/drivers/staging/iio/accel/kxsd9.c +++ b/trunk/drivers/staging/iio/accel/kxsd9.c @@ -23,8 +23,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #define KXSD9_REG_X 0x00 #define KXSD9_REG_Y 0x02 @@ -158,7 +158,7 @@ static int kxsd9_read_raw(struct iio_dev *indio_dev, struct kxsd9_state *st = iio_priv(indio_dev); switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: ret = kxsd9_read(indio_dev, chan->address); if (ret < 0) goto error_ret; @@ -181,7 +181,8 @@ static int kxsd9_read_raw(struct iio_dev *indio_dev, .type = IIO_ACCEL, \ .modified = 1, \ .channel2 = IIO_MOD_##axis, \ - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SHARED_BIT, \ .address = KXSD9_REG_##axis, \ } @@ -189,6 +190,7 @@ static struct iio_chan_spec kxsd9_channels[] = { KXSD9_ACCEL_CHAN(X), KXSD9_ACCEL_CHAN(Y), KXSD9_ACCEL_CHAN(Z), { .type = IIO_VOLTAGE, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .indexed = 1, .address = KXSD9_REG_AUX, } @@ -226,7 +228,7 @@ static int __devinit kxsd9_probe(struct spi_device *spi) struct kxsd9_state *st; int ret = 0; - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -254,7 +256,7 @@ static int __devinit kxsd9_probe(struct spi_device *spi) return 0; error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; } @@ -262,7 +264,7 @@ static int __devinit kxsd9_probe(struct spi_device *spi) static int __devexit kxsd9_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_free_device(spi_get_drvdata(spi)); + iio_device_free(spi_get_drvdata(spi)); return 0; } diff --git a/trunk/drivers/staging/iio/accel/lis3l02dq_core.c b/trunk/drivers/staging/iio/accel/lis3l02dq_core.c index 376da5137967..9d263484fb86 100644 --- a/trunk/drivers/staging/iio/accel/lis3l02dq_core.c +++ b/trunk/drivers/staging/iio/accel/lis3l02dq_core.c @@ -23,10 +23,10 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../events.h" -#include "../buffer.h" +#include +#include +#include +#include #include "lis3l02dq.h" @@ -257,7 +257,7 @@ static int lis3l02dq_read_raw(struct iio_dev *indio_dev, u8 reg; switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: /* Take the iio_dev status lock */ mutex_lock(&indio_dev->mlock); if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) { @@ -297,7 +297,7 @@ static ssize_t lis3l02dq_read_frequency(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); int ret, len = 0; s8 t; ret = lis3l02dq_spi_read_reg_8(indio_dev, @@ -328,7 +328,7 @@ static ssize_t lis3l02dq_write_frequency(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); unsigned long val; int ret; u8 t; @@ -513,7 +513,8 @@ static irqreturn_t lis3l02dq_event_handler(int irq, void *private) } #define LIS3L02DQ_INFO_MASK \ - (IIO_CHAN_INFO_SCALE_SHARED_BIT | \ + (IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SHARED_BIT | \ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT) @@ -521,13 +522,26 @@ static irqreturn_t lis3l02dq_event_handler(int irq, void *private) (IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | \ IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING)) +#define LIS3L02DQ_CHAN(index, mod) \ + { \ + .type = IIO_ACCEL, \ + .modified = 1, \ + .channel2 = mod, \ + .info_mask = LIS3L02DQ_INFO_MASK, \ + .address = index, \ + .scan_index = index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 12, \ + .storagebits = 16, \ + }, \ + .event_mask = LIS3L02DQ_EVENT_MASK, \ + } + static struct iio_chan_spec lis3l02dq_channels[] = { - IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X, LIS3L02DQ_INFO_MASK, - 0, 0, IIO_ST('s', 12, 16, 0), LIS3L02DQ_EVENT_MASK), - IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y, LIS3L02DQ_INFO_MASK, - 1, 1, IIO_ST('s', 12, 16, 0), LIS3L02DQ_EVENT_MASK), - IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Z, LIS3L02DQ_INFO_MASK, - 2, 2, IIO_ST('s', 12, 16, 0), LIS3L02DQ_EVENT_MASK), + LIS3L02DQ_CHAN(0, IIO_MOD_X), + LIS3L02DQ_CHAN(1, IIO_MOD_Y), + LIS3L02DQ_CHAN(2, IIO_MOD_Z), IIO_CHAN_SOFT_TIMESTAMP(3) }; @@ -666,7 +680,7 @@ static int __devinit lis3l02dq_probe(struct spi_device *spi) struct lis3l02dq_state *st; struct iio_dev *indio_dev; - indio_dev = iio_allocate_device(sizeof *st); + indio_dev = iio_device_alloc(sizeof *st); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -724,7 +738,7 @@ static int __devinit lis3l02dq_probe(struct spi_device *spi) return 0; error_remove_trigger: - if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) + if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq))) lis3l02dq_remove_trigger(indio_dev); error_free_interrupt: if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) @@ -734,7 +748,7 @@ static int __devinit lis3l02dq_probe(struct spi_device *spi) error_unreg_buffer_funcs: lis3l02dq_unconfigure_buffer(indio_dev); error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; } @@ -789,7 +803,7 @@ static int lis3l02dq_remove(struct spi_device *spi) iio_buffer_unregister(indio_dev); lis3l02dq_unconfigure_buffer(indio_dev); - iio_free_device(indio_dev); + iio_device_free(indio_dev); err_ret: return ret; } diff --git a/trunk/drivers/staging/iio/accel/lis3l02dq_ring.c b/trunk/drivers/staging/iio/accel/lis3l02dq_ring.c index 0fc3973f32ae..51b00dfc0465 100644 --- a/trunk/drivers/staging/iio/accel/lis3l02dq_ring.c +++ b/trunk/drivers/staging/iio/accel/lis3l02dq_ring.c @@ -6,11 +6,11 @@ #include #include -#include "../iio.h" +#include #include "../ring_sw.h" -#include "../kfifo_buf.h" -#include "../trigger.h" -#include "../trigger_consumer.h" +#include +#include +#include #include "lis3l02dq.h" /** @@ -137,9 +137,9 @@ static irqreturn_t lis3l02dq_trigger_handler(int irq, void *p) struct iio_dev *indio_dev = pf->indio_dev; struct iio_buffer *buffer = indio_dev->buffer; int len = 0; - size_t datasize = buffer->access->get_bytes_per_datum(buffer); - char *data = kmalloc(datasize, GFP_KERNEL); + char *data; + data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); if (data == NULL) { dev_err(indio_dev->dev.parent, "memory alloc failed in buffer bh"); @@ -150,7 +150,7 @@ static irqreturn_t lis3l02dq_trigger_handler(int irq, void *p) len = lis3l02dq_get_buffer_element(indio_dev, data); /* Guaranteed to be aligned with 8 byte boundary */ - if (buffer->scan_timestamp) + if (indio_dev->scan_timestamp) *(s64 *)(((phys_addr_t)data + len + sizeof(s64) - 1) & ~(sizeof(s64) - 1)) = pf->timestamp; @@ -163,12 +163,11 @@ static irqreturn_t lis3l02dq_trigger_handler(int irq, void *p) /* Caller responsible for locking as necessary. */ static int -__lis3l02dq_write_data_ready_config(struct device *dev, bool state) +__lis3l02dq_write_data_ready_config(struct iio_dev *indio_dev, bool state) { int ret; u8 valold; bool currentlyset; - struct iio_dev *indio_dev = dev_get_drvdata(dev); struct lis3l02dq_state *st = iio_priv(indio_dev); /* Get the current event mask register */ @@ -236,7 +235,7 @@ static int lis3l02dq_data_rdy_trigger_set_state(struct iio_trigger *trig, int ret = 0; u8 t; - __lis3l02dq_write_data_ready_config(&indio_dev->dev, state); + __lis3l02dq_write_data_ready_config(indio_dev, state); if (state == false) { /* * A possible quirk with the handler is currently worked around @@ -286,7 +285,7 @@ int lis3l02dq_probe_trigger(struct iio_dev *indio_dev) int ret; struct lis3l02dq_state *st = iio_priv(indio_dev); - st->trig = iio_allocate_trigger("lis3l02dq-dev%d", indio_dev->id); + st->trig = iio_trigger_alloc("lis3l02dq-dev%d", indio_dev->id); if (!st->trig) { ret = -ENOMEM; goto error_ret; @@ -302,7 +301,7 @@ int lis3l02dq_probe_trigger(struct iio_dev *indio_dev) return 0; error_free_trig: - iio_free_trigger(st->trig); + iio_trigger_free(st->trig); error_ret: return ret; } @@ -312,7 +311,7 @@ void lis3l02dq_remove_trigger(struct iio_dev *indio_dev) struct lis3l02dq_state *st = iio_priv(indio_dev); iio_trigger_unregister(st->trig); - iio_free_trigger(st->trig); + iio_trigger_free(st->trig); } void lis3l02dq_unconfigure_buffer(struct iio_dev *indio_dev) diff --git a/trunk/drivers/staging/iio/accel/sca3000_core.c b/trunk/drivers/staging/iio/accel/sca3000_core.c index 49764fb7181c..6ec5c204ff1d 100644 --- a/trunk/drivers/staging/iio/accel/sca3000_core.c +++ b/trunk/drivers/staging/iio/accel/sca3000_core.c @@ -18,10 +18,10 @@ #include #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../events.h" -#include "../buffer.h" +#include +#include +#include +#include #include "sca3000.h" @@ -241,7 +241,7 @@ static int sca3000_read_ctrl_reg(struct sca3000_state *st, static int sca3000_check_status(struct device *dev) { int ret; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct sca3000_state *st = iio_priv(indio_dev); mutex_lock(&st->lock); @@ -268,7 +268,7 @@ static ssize_t sca3000_show_rev(struct device *dev, char *buf) { int len = 0, ret; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct sca3000_state *st = iio_priv(indio_dev); mutex_lock(&st->lock); @@ -296,7 +296,7 @@ sca3000_show_available_measurement_modes(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct sca3000_state *st = iio_priv(indio_dev); int len = 0; @@ -328,7 +328,7 @@ sca3000_show_measurement_mode(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct sca3000_state *st = iio_priv(indio_dev); int len = 0, ret; @@ -379,7 +379,7 @@ sca3000_store_measurement_mode(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct sca3000_state *st = iio_priv(indio_dev); int ret; u8 mask = 0x03; @@ -429,17 +429,31 @@ static IIO_DEVICE_ATTR(measurement_mode, S_IRUGO | S_IWUSR, static IIO_DEVICE_ATTR(revision, S_IRUGO, sca3000_show_rev, NULL, 0); #define SCA3000_INFO_MASK \ - IIO_CHAN_INFO_SCALE_SHARED_BIT + IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT #define SCA3000_EVENT_MASK \ (IIO_EV_BIT(IIO_EV_TYPE_MAG, IIO_EV_DIR_RISING)) +#define SCA3000_CHAN(index, mod) \ + { \ + .type = IIO_ACCEL, \ + .modified = 1, \ + .channel2 = mod, \ + .info_mask = SCA3000_INFO_MASK, \ + .address = index, \ + .scan_index = index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 11, \ + .storagebits = 16, \ + .shift = 5, \ + }, \ + .event_mask = SCA3000_EVENT_MASK, \ + } + static struct iio_chan_spec sca3000_channels[] = { - IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X, SCA3000_INFO_MASK, - 0, 0, IIO_ST('s', 11, 16, 5), SCA3000_EVENT_MASK), - IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y, SCA3000_INFO_MASK, - 1, 1, IIO_ST('s', 11, 16, 5), SCA3000_EVENT_MASK), - IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Z, SCA3000_INFO_MASK, - 2, 2, IIO_ST('s', 11, 16, 5), SCA3000_EVENT_MASK), + SCA3000_CHAN(0, IIO_MOD_X), + SCA3000_CHAN(1, IIO_MOD_Y), + SCA3000_CHAN(2, IIO_MOD_Z), }; static u8 sca3000_addresses[3][3] = { @@ -462,7 +476,7 @@ static int sca3000_read_raw(struct iio_dev *indio_dev, u8 address; switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: mutex_lock(&st->lock); if (st->mo_det_use_count) { mutex_unlock(&st->lock); @@ -503,7 +517,7 @@ static ssize_t sca3000_read_av_freq(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct sca3000_state *st = iio_priv(indio_dev); int len = 0, ret, val; @@ -574,7 +588,7 @@ static ssize_t sca3000_read_frequency(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct sca3000_state *st = iio_priv(indio_dev); int ret, len = 0, base_freq = 0, val; @@ -616,7 +630,7 @@ static ssize_t sca3000_set_frequency(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct sca3000_state *st = iio_priv(indio_dev); int ret, base_freq = 0; int ctrlval; @@ -676,7 +690,7 @@ static ssize_t sca3000_read_temp(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct sca3000_state *st = iio_priv(indio_dev); int ret; int val; @@ -897,7 +911,7 @@ static ssize_t sca3000_query_free_fall_mode(struct device *dev, char *buf) { int ret, len; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct sca3000_state *st = iio_priv(indio_dev); int val; @@ -925,7 +939,7 @@ static ssize_t sca3000_set_free_fall_mode(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct sca3000_state *st = iio_priv(indio_dev); long val; int ret; @@ -1131,7 +1145,7 @@ static int __devinit sca3000_probe(struct spi_device *spi) struct sca3000_state *st; struct iio_dev *indio_dev; - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -1195,7 +1209,7 @@ static int __devinit sca3000_probe(struct spi_device *spi) error_unregister_dev: iio_device_unregister(indio_dev); error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; @@ -1233,7 +1247,7 @@ static int sca3000_remove(struct spi_device *spi) iio_device_unregister(indio_dev); iio_buffer_unregister(indio_dev); sca3000_unconfigure_ring(indio_dev); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/accel/sca3000_ring.c b/trunk/drivers/staging/iio/accel/sca3000_ring.c index 6b824a11f7f4..b7e1a002630a 100644 --- a/trunk/drivers/staging/iio/accel/sca3000_ring.c +++ b/trunk/drivers/staging/iio/accel/sca3000_ring.c @@ -18,9 +18,9 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../buffer.h" +#include +#include +#include #include "../ring_hw.h" #include "sca3000.h" @@ -157,7 +157,7 @@ static ssize_t sca3000_query_ring_int(struct device *dev, { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret, val; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct sca3000_state *st = iio_priv(indio_dev); mutex_lock(&st->lock); @@ -178,7 +178,7 @@ static ssize_t sca3000_set_ring_int(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct sca3000_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); long val; @@ -219,7 +219,7 @@ static ssize_t sca3000_show_buffer_scale(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct sca3000_state *st = iio_priv(indio_dev); return sprintf(buf, "0.%06d\n", 4*st->info->scale); diff --git a/trunk/drivers/staging/iio/adc/Kconfig b/trunk/drivers/staging/iio/adc/Kconfig index 592eabd85f36..2490dd25093b 100644 --- a/trunk/drivers/staging/iio/adc/Kconfig +++ b/trunk/drivers/staging/iio/adc/Kconfig @@ -25,7 +25,7 @@ config AD7606 depends on GPIOLIB select IIO_BUFFER select IIO_TRIGGER - select IIO_SW_RING + select IIO_KFIFO_BUF help Say yes here to build support for Analog Devices: ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC). @@ -63,7 +63,7 @@ config AD799X_RING_BUFFER bool "Analog Devices AD799x: use ring buffer" depends on AD799X select IIO_BUFFER - select IIO_SW_RING + select IIO_KFIFO_BUF help Say yes here to include ring buffer support in the AD799X ADC driver. @@ -72,7 +72,7 @@ config AD7476 tristate "Analog Devices AD7475/6/7/8 AD7466/7/8 and AD7495 ADC driver" depends on SPI select IIO_BUFFER - select IIO_SW_RING + select IIO_KFIFO_BUF select IIO_TRIGGER help Say yes here to build support for Analog Devices @@ -87,7 +87,7 @@ config AD7887 tristate "Analog Devices AD7887 ADC driver" depends on SPI select IIO_BUFFER - select IIO_SW_RING + select IIO_KFIFO_BUF select IIO_TRIGGER help Say yes here to build support for Analog Devices @@ -113,7 +113,7 @@ config AD7793 tristate "Analog Devices AD7792 AD7793 ADC driver" depends on SPI select IIO_BUFFER - select IIO_SW_RING + select IIO_KFIFO_BUF select IIO_TRIGGER help Say yes here to build support for Analog Devices @@ -135,7 +135,7 @@ config AD7192 tristate "Analog Devices AD7190 AD7192 AD7195 ADC driver" depends on SPI select IIO_BUFFER - select IIO_SW_RING + select IIO_KFIFO_BUF select IIO_TRIGGER help Say yes here to build support for Analog Devices AD7190, @@ -195,11 +195,20 @@ config MAX1363_RING_BUFFER config LPC32XX_ADC tristate "NXP LPC32XX ADC" - depends on ARCH_LPC32XX && !TOUCHSCREEN_LPC32XX + depends on ARCH_LPC32XX help Say yes here to build support for the integrated ADC inside the LPC32XX SoC. Note that this feature uses the same hardware as the - touchscreen driver, so you can only select one of the two drivers - (lpc32xx_adc or lpc32xx_ts). Provides direct access via sysfs. + touchscreen driver, so you should either select only one of the two + drivers (lpc32xx_adc or lpc32xx_ts) or, in the OpenFirmware case, + activate only one via device tree selection. Provides direct access + via sysfs. + +config SPEAR_ADC + tristate "ST SPEAr ADC" + depends on PLAT_SPEAR + help + Say yes here to build support for the integrated ADC inside the + ST SPEAr SoC. Provides direct access via sysfs. endmenu diff --git a/trunk/drivers/staging/iio/adc/Makefile b/trunk/drivers/staging/iio/adc/Makefile index f83ab9551d8e..14e98b62b70a 100644 --- a/trunk/drivers/staging/iio/adc/Makefile +++ b/trunk/drivers/staging/iio/adc/Makefile @@ -38,3 +38,4 @@ obj-$(CONFIG_ADT7310) += adt7310.o obj-$(CONFIG_ADT7410) += adt7410.o obj-$(CONFIG_AD7280) += ad7280a.o obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o +obj-$(CONFIG_SPEAR_ADC) += spear_adc.o diff --git a/trunk/drivers/staging/iio/adc/ad7192.c b/trunk/drivers/staging/iio/adc/ad7192.c index 9fd6d63d2999..5eaeaf1f0ae8 100644 --- a/trunk/drivers/staging/iio/adc/ad7192.c +++ b/trunk/drivers/staging/iio/adc/ad7192.c @@ -1,7 +1,7 @@ /* * AD7190 AD7192 AD7195 SPI ADC driver * - * Copyright 2011 Analog Devices Inc. + * Copyright 2011-2012 Analog Devices Inc. * * Licensed under the GPL-2. */ @@ -17,12 +17,12 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../buffer.h" -#include "../ring_sw.h" -#include "../trigger.h" -#include "../trigger_consumer.h" +#include +#include +#include +#include +#include +#include #include "ad7192.h" @@ -456,31 +456,19 @@ static int ad7192_setup(struct ad7192_state *st) static int ad7192_ring_preenable(struct iio_dev *indio_dev) { struct ad7192_state *st = iio_priv(indio_dev); - struct iio_buffer *ring = indio_dev->buffer; - size_t d_size; unsigned channel; + int ret; if (bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) return -EINVAL; + ret = iio_sw_buffer_preenable(indio_dev); + if (ret < 0) + return ret; + channel = find_first_bit(indio_dev->active_scan_mask, indio_dev->masklength); - d_size = bitmap_weight(indio_dev->active_scan_mask, - indio_dev->masklength) * - indio_dev->channels[0].scan_type.storagebits / 8; - - if (ring->scan_timestamp) { - d_size += sizeof(s64); - - if (d_size % sizeof(s64)) - d_size += sizeof(s64) - (d_size % sizeof(s64)); - } - - if (indio_dev->buffer->access->set_bytes_per_datum) - indio_dev->buffer->access-> - set_bytes_per_datum(indio_dev->buffer, d_size); - st->mode = (st->mode & ~AD7192_MODE_SEL(-1)) | AD7192_MODE_SEL(AD7192_MODE_CONT); st->conf = (st->conf & ~AD7192_CONF_CHAN(-1)) | @@ -533,7 +521,7 @@ static irqreturn_t ad7192_trigger_handler(int irq, void *p) indio_dev->channels[0].scan_type.realbits/8); /* Guaranteed to be aligned with 8 byte boundary */ - if (ring->scan_timestamp) + if (indio_dev->scan_timestamp) dat64[1] = pf->timestamp; ring->access->store_to(ring, (u8 *)dat64, pf->timestamp); @@ -556,7 +544,7 @@ static int ad7192_register_ring_funcs_and_init(struct iio_dev *indio_dev) { int ret; - indio_dev->buffer = iio_sw_rb_allocate(indio_dev); + indio_dev->buffer = iio_kfifo_allocate(indio_dev); if (!indio_dev->buffer) { ret = -ENOMEM; goto error_ret; @@ -569,7 +557,7 @@ static int ad7192_register_ring_funcs_and_init(struct iio_dev *indio_dev) indio_dev->id); if (indio_dev->pollfunc == NULL) { ret = -ENOMEM; - goto error_deallocate_sw_rb; + goto error_deallocate_kfifo; } /* Ring buffer functions - here trigger setup related */ @@ -579,8 +567,8 @@ static int ad7192_register_ring_funcs_and_init(struct iio_dev *indio_dev) indio_dev->modes |= INDIO_BUFFER_TRIGGERED; return 0; -error_deallocate_sw_rb: - iio_sw_rb_free(indio_dev->buffer); +error_deallocate_kfifo: + iio_kfifo_free(indio_dev->buffer); error_ret: return ret; } @@ -588,7 +576,7 @@ static int ad7192_register_ring_funcs_and_init(struct iio_dev *indio_dev) static void ad7192_ring_cleanup(struct iio_dev *indio_dev) { iio_dealloc_pollfunc(indio_dev->pollfunc); - iio_sw_rb_free(indio_dev->buffer); + iio_kfifo_free(indio_dev->buffer); } /** @@ -616,7 +604,7 @@ static int ad7192_probe_trigger(struct iio_dev *indio_dev) struct ad7192_state *st = iio_priv(indio_dev); int ret; - st->trig = iio_allocate_trigger("%s-dev%d", + st->trig = iio_trigger_alloc("%s-dev%d", spi_get_device_id(st->spi)->name, indio_dev->id); if (st->trig == NULL) { @@ -649,7 +637,7 @@ static int ad7192_probe_trigger(struct iio_dev *indio_dev) error_free_irq: free_irq(st->spi->irq, indio_dev); error_free_trig: - iio_free_trigger(st->trig); + iio_trigger_free(st->trig); error_ret: return ret; } @@ -660,14 +648,14 @@ static void ad7192_remove_trigger(struct iio_dev *indio_dev) iio_trigger_unregister(st->trig); free_irq(st->spi->irq, indio_dev); - iio_free_trigger(st->trig); + iio_trigger_free(st->trig); } static ssize_t ad7192_read_frequency(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7192_state *st = iio_priv(indio_dev); return sprintf(buf, "%d\n", st->mclk / @@ -679,7 +667,7 @@ static ssize_t ad7192_write_frequency(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7192_state *st = iio_priv(indio_dev); unsigned long lval; int div, ret; @@ -718,7 +706,7 @@ static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, static ssize_t ad7192_show_scale_available(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7192_state *st = iio_priv(indio_dev); int i, len = 0; @@ -742,7 +730,7 @@ static ssize_t ad7192_show_ac_excitation(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7192_state *st = iio_priv(indio_dev); return sprintf(buf, "%d\n", !!(st->mode & AD7192_MODE_ACX)); @@ -752,7 +740,7 @@ static ssize_t ad7192_show_bridge_switch(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7192_state *st = iio_priv(indio_dev); return sprintf(buf, "%d\n", !!(st->gpocon & AD7192_GPOCON_BPDSW)); @@ -763,7 +751,7 @@ static ssize_t ad7192_set(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7192_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; @@ -849,7 +837,7 @@ static int ad7192_read_raw(struct iio_dev *indio_dev, bool unipolar = !!(st->conf & AD7192_CONF_UNIPOLAR); switch (m) { - case 0: + case IIO_CHAN_INFO_RAW: mutex_lock(&indio_dev->mlock); if (iio_buffer_enabled(indio_dev)) ret = -EBUSY; @@ -981,7 +969,8 @@ static const struct iio_info ad7195_info = { .extend_name = _name, \ .channel = _chan, \ .channel2 = _chan2, \ - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SHARED_BIT, \ .address = _address, \ .scan_index = _si, \ .scan_type = IIO_ST('s', 24, 32, 0)} @@ -990,7 +979,8 @@ static const struct iio_info ad7195_info = { { .type = IIO_VOLTAGE, \ .indexed = 1, \ .channel = _chan, \ - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SHARED_BIT, \ .address = _address, \ .scan_index = _si, \ .scan_type = IIO_ST('s', 24, 32, 0)} @@ -999,7 +989,8 @@ static const struct iio_info ad7195_info = { { .type = IIO_TEMP, \ .indexed = 1, \ .channel = _chan, \ - .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ .address = _address, \ .scan_index = _si, \ .scan_type = IIO_ST('s', 24, 32, 0)} @@ -1033,7 +1024,7 @@ static int __devinit ad7192_probe(struct spi_device *spi) return -ENODEV; } - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -1114,7 +1105,7 @@ static int __devinit ad7192_probe(struct spi_device *spi) if (!IS_ERR(st->reg)) regulator_put(st->reg); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return ret; } diff --git a/trunk/drivers/staging/iio/adc/ad7280a.c b/trunk/drivers/staging/iio/adc/ad7280a.c index 7dbd6812c240..cfc39a703126 100644 --- a/trunk/drivers/staging/iio/adc/ad7280a.c +++ b/trunk/drivers/staging/iio/adc/ad7280a.c @@ -16,9 +16,9 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../events.h" +#include +#include +#include #include "ad7280a.h" @@ -384,7 +384,7 @@ static ssize_t ad7280_show_balance_sw(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7280_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); @@ -398,7 +398,7 @@ static ssize_t ad7280_store_balance_sw(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7280_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); bool readin; @@ -429,7 +429,7 @@ static ssize_t ad7280_show_balance_timer(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7280_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; @@ -453,7 +453,7 @@ static ssize_t ad7280_store_balance_timer(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7280_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); unsigned long val; @@ -508,6 +508,7 @@ static int ad7280_channel_init(struct ad7280_state *st) } st->channels[cnt].indexed = 1; st->channels[cnt].info_mask = + IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT; st->channels[cnt].address = AD7280A_DEVADDR(dev) << 8 | ch; @@ -524,7 +525,9 @@ static int ad7280_channel_init(struct ad7280_state *st) st->channels[cnt].channel2 = dev * 6; st->channels[cnt].address = AD7280A_ALL_CELLS; st->channels[cnt].indexed = 1; - st->channels[cnt].info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT; + st->channels[cnt].info_mask = + IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT; st->channels[cnt].scan_index = cnt; st->channels[cnt].scan_type.sign = 'u'; st->channels[cnt].scan_type.realbits = 32; @@ -596,7 +599,7 @@ static ssize_t ad7280_read_channel_config(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7280_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); unsigned val; @@ -626,7 +629,7 @@ static ssize_t ad7280_write_channel_config(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7280_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); @@ -788,7 +791,7 @@ static int ad7280_read_raw(struct iio_dev *indio_dev, int ret; switch (m) { - case 0: + case IIO_CHAN_INFO_RAW: mutex_lock(&indio_dev->mlock); if (chan->address == AD7280A_ALL_CELLS) ret = ad7280_read_all_channels(st, st->scan_cnt, NULL); @@ -836,7 +839,7 @@ static int __devinit ad7280_probe(struct spi_device *spi) int ret; const unsigned short tACQ_ns[4] = {465, 1010, 1460, 1890}; const unsigned short nAVG[4] = {1, 2, 4, 8}; - struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st)); + struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -942,7 +945,7 @@ static int __devinit ad7280_probe(struct spi_device *spi) kfree(st->channels); error_free_device: - iio_free_device(indio_dev); + iio_device_free(indio_dev); return ret; } @@ -961,7 +964,7 @@ static int __devexit ad7280_remove(struct spi_device *spi) kfree(st->channels); kfree(st->iio_attr); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/adc/ad7291.c b/trunk/drivers/staging/iio/adc/ad7291.c index 81d6b6128cb0..029b39c0ba60 100644 --- a/trunk/drivers/staging/iio/adc/ad7291.c +++ b/trunk/drivers/staging/iio/adc/ad7291.c @@ -17,9 +17,9 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../events.h" +#include +#include +#include /* * Simplified handling @@ -132,7 +132,7 @@ static ssize_t ad7291_store_reset(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7291_chip_info *chip = iio_priv(indio_dev); return ad7291_i2c_write(chip, AD7291_COMMAND, @@ -214,7 +214,7 @@ static inline ssize_t ad7291_show_hyst(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7291_chip_info *chip = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); u16 data; @@ -232,7 +232,7 @@ static inline ssize_t ad7291_set_hyst(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7291_chip_info *chip = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); u16 data; @@ -461,7 +461,7 @@ static int ad7291_read_raw(struct iio_dev *indio_dev, s16 signval; switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: switch (chan->type) { case IIO_VOLTAGE: mutex_lock(&chip->state_lock); @@ -536,7 +536,8 @@ static int ad7291_read_raw(struct iio_dev *indio_dev, #define AD7291_VOLTAGE_CHAN(_chan) \ { \ .type = IIO_VOLTAGE, \ - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SHARED_BIT, \ .indexed = 1, \ .channel = _chan, \ .event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING)|\ @@ -554,7 +555,8 @@ static const struct iio_chan_spec ad7291_channels[] = { AD7291_VOLTAGE_CHAN(7), { .type = IIO_TEMP, - .info_mask = IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .indexed = 1, .channel = 0, @@ -585,7 +587,7 @@ static int __devinit ad7291_probe(struct i2c_client *client, struct iio_dev *indio_dev; int ret = 0, voltage_uv = 0; - indio_dev = iio_allocate_device(sizeof(*chip)); + indio_dev = iio_device_alloc(sizeof(*chip)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -667,7 +669,7 @@ static int __devinit ad7291_probe(struct i2c_client *client, if (!IS_ERR(chip->reg)) regulator_put(chip->reg); - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; } @@ -687,7 +689,7 @@ static int __devexit ad7291_remove(struct i2c_client *client) regulator_put(chip->reg); } - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/adc/ad7298.h b/trunk/drivers/staging/iio/adc/ad7298.h index a0e5dea415ef..5051a7e4d4fd 100644 --- a/trunk/drivers/staging/iio/adc/ad7298.h +++ b/trunk/drivers/staging/iio/adc/ad7298.h @@ -38,7 +38,6 @@ struct ad7298_platform_data { struct ad7298_state { struct spi_device *spi; struct regulator *reg; - size_t d_size; u16 int_vref_mv; unsigned ext_ref; struct spi_transfer ring_xfer[10]; diff --git a/trunk/drivers/staging/iio/adc/ad7298_core.c b/trunk/drivers/staging/iio/adc/ad7298_core.c index 8dd6aa9cf928..c90f2b3e661f 100644 --- a/trunk/drivers/staging/iio/adc/ad7298_core.c +++ b/trunk/drivers/staging/iio/adc/ad7298_core.c @@ -16,40 +16,51 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../buffer.h" +#include +#include +#include #include "ad7298.h" +#define AD7298_V_CHAN(index) \ + { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = index, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SHARED_BIT, \ + .address = index, \ + .scan_index = index, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 12, \ + .storagebits = 16, \ + }, \ + } + static struct iio_chan_spec ad7298_channels[] = { - IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0, - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - 9, AD7298_CH_TEMP, IIO_ST('s', 32, 32, 0), 0), - IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - 0, 0, IIO_ST('u', 12, 16, 0), 0), - IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - 1, 1, IIO_ST('u', 12, 16, 0), 0), - IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 2, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - 2, 2, IIO_ST('u', 12, 16, 0), 0), - IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 3, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - 3, 3, IIO_ST('u', 12, 16, 0), 0), - IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 4, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - 4, 4, IIO_ST('u', 12, 16, 0), 0), - IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 5, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - 5, 5, IIO_ST('u', 12, 16, 0), 0), - IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 6, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - 6, 6, IIO_ST('u', 12, 16, 0), 0), - IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 7, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - 7, 7, IIO_ST('u', 12, 16, 0), 0), + { + .type = IIO_TEMP, + .indexed = 1, + .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + .address = 9, + .scan_index = AD7298_CH_TEMP, + .scan_type = { + .sign = 's', + .realbits = 32, + .storagebits = 32, + }, + }, + AD7298_V_CHAN(0), + AD7298_V_CHAN(1), + AD7298_V_CHAN(2), + AD7298_V_CHAN(3), + AD7298_V_CHAN(4), + AD7298_V_CHAN(5), + AD7298_V_CHAN(6), + AD7298_V_CHAN(7), IIO_CHAN_SOFT_TIMESTAMP(8), }; @@ -121,7 +132,7 @@ static int ad7298_read_raw(struct iio_dev *indio_dev, unsigned int scale_uv; switch (m) { - case 0: + case IIO_CHAN_INFO_RAW: mutex_lock(&indio_dev->mlock); if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) { ret = -EBUSY; @@ -168,7 +179,7 @@ static int __devinit ad7298_probe(struct spi_device *spi) struct ad7298_platform_data *pdata = spi->dev.platform_data; struct ad7298_state *st; int ret; - struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st)); + struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -241,7 +252,7 @@ static int __devinit ad7298_probe(struct spi_device *spi) error_put_reg: if (!IS_ERR(st->reg)) regulator_put(st->reg); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return ret; } @@ -258,7 +269,7 @@ static int __devexit ad7298_remove(struct spi_device *spi) regulator_disable(st->reg); regulator_put(st->reg); } - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/adc/ad7298_ring.c b/trunk/drivers/staging/iio/adc/ad7298_ring.c index feeb0eeba59a..908a3e5609df 100644 --- a/trunk/drivers/staging/iio/adc/ad7298_ring.c +++ b/trunk/drivers/staging/iio/adc/ad7298_ring.c @@ -1,7 +1,7 @@ /* * AD7298 SPI ADC driver * - * Copyright 2011 Analog Devices Inc. + * Copyright 2011-2012 Analog Devices Inc. * * Licensed under the GPL-2. */ @@ -11,10 +11,10 @@ #include #include -#include "../iio.h" -#include "../buffer.h" -#include "../ring_sw.h" -#include "../trigger_consumer.h" +#include +#include +#include +#include #include "ad7298.h" @@ -28,25 +28,17 @@ static int ad7298_ring_preenable(struct iio_dev *indio_dev) { struct ad7298_state *st = iio_priv(indio_dev); - struct iio_buffer *ring = indio_dev->buffer; - size_t d_size; int i, m; unsigned short command; - int scan_count = bitmap_weight(indio_dev->active_scan_mask, - indio_dev->masklength); - d_size = scan_count * (AD7298_STORAGE_BITS / 8); - - if (ring->scan_timestamp) { - d_size += sizeof(s64); - - if (d_size % sizeof(s64)) - d_size += sizeof(s64) - (d_size % sizeof(s64)); - } + int scan_count, ret; - if (ring->access->set_bytes_per_datum) - ring->access->set_bytes_per_datum(ring, d_size); + ret = iio_sw_buffer_preenable(indio_dev); + if (ret < 0) + return ret; - st->d_size = d_size; + /* Now compute overall size */ + scan_count = bitmap_weight(indio_dev->active_scan_mask, + indio_dev->masklength); command = AD7298_WRITE | st->ext_ref; @@ -100,9 +92,9 @@ static irqreturn_t ad7298_trigger_handler(int irq, void *p) if (b_sent) return b_sent; - if (ring->scan_timestamp) { + if (indio_dev->scan_timestamp) { time_ns = iio_get_time_ns(); - memcpy((u8 *)buf + st->d_size - sizeof(s64), + memcpy((u8 *)buf + indio_dev->scan_bytes - sizeof(s64), &time_ns, sizeof(time_ns)); } @@ -126,7 +118,7 @@ int ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev) { int ret; - indio_dev->buffer = iio_sw_rb_allocate(indio_dev); + indio_dev->buffer = iio_kfifo_allocate(indio_dev); if (!indio_dev->buffer) { ret = -ENOMEM; goto error_ret; @@ -140,7 +132,7 @@ int ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev) if (indio_dev->pollfunc == NULL) { ret = -ENOMEM; - goto error_deallocate_sw_rb; + goto error_deallocate_kfifo; } /* Ring buffer functions - here trigger setup related */ @@ -151,8 +143,8 @@ int ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev) indio_dev->modes |= INDIO_BUFFER_TRIGGERED; return 0; -error_deallocate_sw_rb: - iio_sw_rb_free(indio_dev->buffer); +error_deallocate_kfifo: + iio_kfifo_free(indio_dev->buffer); error_ret: return ret; } @@ -160,5 +152,5 @@ int ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev) void ad7298_ring_cleanup(struct iio_dev *indio_dev) { iio_dealloc_pollfunc(indio_dev->pollfunc); - iio_sw_rb_free(indio_dev->buffer); + iio_kfifo_free(indio_dev->buffer); } diff --git a/trunk/drivers/staging/iio/adc/ad7476.h b/trunk/drivers/staging/iio/adc/ad7476.h index 27f696c75cc4..b1dd9317fe1f 100644 --- a/trunk/drivers/staging/iio/adc/ad7476.h +++ b/trunk/drivers/staging/iio/adc/ad7476.h @@ -27,7 +27,6 @@ struct ad7476_state { struct spi_device *spi; const struct ad7476_chip_info *chip_info; struct regulator *reg; - size_t d_size; u16 int_vref_mv; struct spi_transfer xfer; struct spi_message msg; diff --git a/trunk/drivers/staging/iio/adc/ad7476_core.c b/trunk/drivers/staging/iio/adc/ad7476_core.c index 0c064d1c3927..be1c260cf165 100644 --- a/trunk/drivers/staging/iio/adc/ad7476_core.c +++ b/trunk/drivers/staging/iio/adc/ad7476_core.c @@ -15,9 +15,9 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../buffer.h" +#include +#include +#include #include "ad7476.h" @@ -43,7 +43,7 @@ static int ad7476_read_raw(struct iio_dev *indio_dev, unsigned int scale_uv; switch (m) { - case 0: + case IIO_CHAN_INFO_RAW: mutex_lock(&indio_dev->mlock); if (iio_buffer_enabled(indio_dev)) ret = -EBUSY; @@ -66,53 +66,51 @@ static int ad7476_read_raw(struct iio_dev *indio_dev, return -EINVAL; } +#define AD7476_CHAN(bits) \ + { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SHARED_BIT, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = bits, \ + .storagebits = 16, \ + .shift = 12 - bits, \ + }, \ +} + static const struct ad7476_chip_info ad7476_chip_info_tbl[] = { [ID_AD7466] = { - .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - 0, 0, IIO_ST('u', 12, 16, 0), 0), + .channel[0] = AD7476_CHAN(12), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), }, [ID_AD7467] = { - .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - 0, 0, IIO_ST('u', 10, 16, 2), 0), + .channel[0] = AD7476_CHAN(10), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), }, [ID_AD7468] = { - .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1 , 0, NULL, 0, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - 0, 0, IIO_ST('u', 8, 16, 4), 0), + .channel[0] = AD7476_CHAN(8), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), }, [ID_AD7475] = { - .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - 0, 0, IIO_ST('u', 12, 16, 0), 0), + .channel[0] = AD7476_CHAN(12), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), }, [ID_AD7476] = { - .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - 0, 0, IIO_ST('u', 12, 16, 0), 0), + .channel[0] = AD7476_CHAN(12), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), }, [ID_AD7477] = { - .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - 0, 0, IIO_ST('u', 10, 16, 2), 0), + .channel[0] = AD7476_CHAN(10), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), }, [ID_AD7478] = { - .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - 0, 0, IIO_ST('u', 8, 16, 4), 0), + .channel[0] = AD7476_CHAN(8), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), }, [ID_AD7495] = { - .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - 0, 0, IIO_ST('u', 12, 16, 0), 0), + .channel[0] = AD7476_CHAN(12), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), .int_vref_mv = 2500, }, @@ -130,7 +128,7 @@ static int __devinit ad7476_probe(struct spi_device *spi) struct iio_dev *indio_dev; int ret, voltage_uv = 0; - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -200,7 +198,7 @@ static int __devinit ad7476_probe(struct spi_device *spi) error_put_reg: if (!IS_ERR(st->reg)) regulator_put(st->reg); - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; @@ -218,7 +216,7 @@ static int ad7476_remove(struct spi_device *spi) regulator_disable(st->reg); regulator_put(st->reg); } - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/adc/ad7476_ring.c b/trunk/drivers/staging/iio/adc/ad7476_ring.c index d6af6c05ce1c..383611b05764 100644 --- a/trunk/drivers/staging/iio/adc/ad7476_ring.c +++ b/trunk/drivers/staging/iio/adc/ad7476_ring.c @@ -1,5 +1,5 @@ /* - * Copyright 2010 Analog Devices Inc. + * Copyright 2010-2012 Analog Devices Inc. * Copyright (C) 2008 Jonathan Cameron * * Licensed under the GPL-2 or later. @@ -13,43 +13,13 @@ #include #include -#include "../iio.h" -#include "../buffer.h" -#include "../ring_sw.h" -#include "../trigger_consumer.h" +#include +#include +#include +#include #include "ad7476.h" -/** - * ad7476_ring_preenable() setup the parameters of the ring before enabling - * - * The complex nature of the setting of the number of bytes per datum is due - * to this driver currently ensuring that the timestamp is stored at an 8 - * byte boundary. - **/ -static int ad7476_ring_preenable(struct iio_dev *indio_dev) -{ - struct ad7476_state *st = iio_priv(indio_dev); - struct iio_buffer *ring = indio_dev->buffer; - - st->d_size = bitmap_weight(indio_dev->active_scan_mask, - indio_dev->masklength) * - st->chip_info->channel[0].scan_type.storagebits / 8; - - if (ring->scan_timestamp) { - st->d_size += sizeof(s64); - - if (st->d_size % sizeof(s64)) - st->d_size += sizeof(s64) - (st->d_size % sizeof(s64)); - } - - if (indio_dev->buffer->access->set_bytes_per_datum) - indio_dev->buffer->access-> - set_bytes_per_datum(indio_dev->buffer, st->d_size); - - return 0; -} - static irqreturn_t ad7476_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; @@ -59,7 +29,7 @@ static irqreturn_t ad7476_trigger_handler(int irq, void *p) __u8 *rxbuf; int b_sent; - rxbuf = kzalloc(st->d_size, GFP_KERNEL); + rxbuf = kzalloc(indio_dev->scan_bytes, GFP_KERNEL); if (rxbuf == NULL) return -ENOMEM; @@ -70,8 +40,8 @@ static irqreturn_t ad7476_trigger_handler(int irq, void *p) time_ns = iio_get_time_ns(); - if (indio_dev->buffer->scan_timestamp) - memcpy(rxbuf + st->d_size - sizeof(s64), + if (indio_dev->scan_timestamp) + memcpy(rxbuf + indio_dev->scan_bytes - sizeof(s64), &time_ns, sizeof(time_ns)); indio_dev->buffer->access->store_to(indio_dev->buffer, rxbuf, time_ns); @@ -83,7 +53,7 @@ static irqreturn_t ad7476_trigger_handler(int irq, void *p) } static const struct iio_buffer_setup_ops ad7476_ring_setup_ops = { - .preenable = &ad7476_ring_preenable, + .preenable = &iio_sw_buffer_preenable, .postenable = &iio_triggered_buffer_postenable, .predisable = &iio_triggered_buffer_predisable, }; @@ -93,7 +63,7 @@ int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev) struct ad7476_state *st = iio_priv(indio_dev); int ret = 0; - indio_dev->buffer = iio_sw_rb_allocate(indio_dev); + indio_dev->buffer = iio_kfifo_allocate(indio_dev); if (!indio_dev->buffer) { ret = -ENOMEM; goto error_ret; @@ -108,7 +78,7 @@ int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev) indio_dev->id); if (indio_dev->pollfunc == NULL) { ret = -ENOMEM; - goto error_deallocate_sw_rb; + goto error_deallocate_kfifo; } /* Ring buffer functions - here trigger setup related */ @@ -119,8 +89,8 @@ int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev) indio_dev->modes |= INDIO_BUFFER_TRIGGERED; return 0; -error_deallocate_sw_rb: - iio_sw_rb_free(indio_dev->buffer); +error_deallocate_kfifo: + iio_kfifo_free(indio_dev->buffer); error_ret: return ret; } @@ -128,5 +98,5 @@ int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev) void ad7476_ring_cleanup(struct iio_dev *indio_dev) { iio_dealloc_pollfunc(indio_dev->pollfunc); - iio_sw_rb_free(indio_dev->buffer); + iio_kfifo_free(indio_dev->buffer); } diff --git a/trunk/drivers/staging/iio/adc/ad7606_core.c b/trunk/drivers/staging/iio/adc/ad7606_core.c index 97e8d3d4471e..10ab6dc823b9 100644 --- a/trunk/drivers/staging/iio/adc/ad7606_core.c +++ b/trunk/drivers/staging/iio/adc/ad7606_core.c @@ -18,9 +18,9 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../buffer.h" +#include +#include +#include #include "ad7606.h" @@ -88,7 +88,7 @@ static int ad7606_read_raw(struct iio_dev *indio_dev, unsigned int scale_uv; switch (m) { - case 0: + case IIO_CHAN_INFO_RAW: mutex_lock(&indio_dev->mlock); if (iio_buffer_enabled(indio_dev)) ret = -EBUSY; @@ -113,7 +113,7 @@ static int ad7606_read_raw(struct iio_dev *indio_dev, static ssize_t ad7606_show_range(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7606_state *st = iio_priv(indio_dev); return sprintf(buf, "%u\n", st->range); @@ -122,7 +122,7 @@ static ssize_t ad7606_show_range(struct device *dev, static ssize_t ad7606_store_range(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7606_state *st = iio_priv(indio_dev); unsigned long lval; @@ -147,7 +147,7 @@ static IIO_CONST_ATTR(in_voltage_range_available, "5000 10000"); static ssize_t ad7606_show_oversampling_ratio(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7606_state *st = iio_priv(indio_dev); return sprintf(buf, "%u\n", st->oversampling); @@ -168,7 +168,7 @@ static int ad7606_oversampling_get_index(unsigned val) static ssize_t ad7606_store_oversampling_ratio(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7606_state *st = iio_priv(indio_dev); unsigned long lval; int ret; @@ -229,14 +229,15 @@ static const struct attribute_group ad7606_attribute_group_range = { .attrs = ad7606_attributes_range, }; -#define AD7606_CHANNEL(num) \ - { \ - .type = IIO_VOLTAGE, \ - .indexed = 1, \ - .channel = num, \ - .address = num, \ - .scan_index = num, \ - .scan_type = IIO_ST('s', 16, 16, 0), \ +#define AD7606_CHANNEL(num) \ + { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = num, \ + .address = num, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, \ + .scan_index = num, \ + .scan_type = IIO_ST('s', 16, 16, 0), \ } static struct iio_chan_spec ad7606_8_channels[] = { @@ -460,7 +461,7 @@ struct iio_dev *ad7606_probe(struct device *dev, int irq, struct ad7606_platform_data *pdata = dev->platform_data; struct ad7606_state *st; int ret; - struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st)); + struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; @@ -559,7 +560,7 @@ struct iio_dev *ad7606_probe(struct device *dev, int irq, error_put_reg: if (!IS_ERR(st->reg)) regulator_put(st->reg); - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ERR_PTR(ret); } @@ -579,7 +580,7 @@ int ad7606_remove(struct iio_dev *indio_dev, int irq) } ad7606_free_gpios(st); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/adc/ad7606_par.c b/trunk/drivers/staging/iio/adc/ad7606_par.c index bb152a8e8c92..a53faafec070 100644 --- a/trunk/drivers/staging/iio/adc/ad7606_par.c +++ b/trunk/drivers/staging/iio/adc/ad7606_par.c @@ -12,7 +12,7 @@ #include #include -#include "../iio.h" +#include #include "ad7606.h" static int ad7606_par16_read_block(struct device *dev, diff --git a/trunk/drivers/staging/iio/adc/ad7606_ring.c b/trunk/drivers/staging/iio/adc/ad7606_ring.c index 1ef9fbcaf2de..24ce8fc71646 100644 --- a/trunk/drivers/staging/iio/adc/ad7606_ring.c +++ b/trunk/drivers/staging/iio/adc/ad7606_ring.c @@ -1,5 +1,5 @@ /* - * Copyright 2011 Analog Devices Inc. + * Copyright 2011-2012 Analog Devices Inc. * * Licensed under the GPL-2. * @@ -11,10 +11,10 @@ #include #include -#include "../iio.h" -#include "../buffer.h" -#include "../ring_sw.h" -#include "../trigger_consumer.h" +#include +#include +#include +#include #include "ad7606.h" @@ -51,8 +51,7 @@ static void ad7606_poll_bh_to_ring(struct work_struct *work_s) __u8 *buf; int ret; - buf = kzalloc(ring->access->get_bytes_per_datum(ring), - GFP_KERNEL); + buf = kzalloc(indio_dev->scan_bytes, GFP_KERNEL); if (buf == NULL) return; @@ -82,9 +81,8 @@ static void ad7606_poll_bh_to_ring(struct work_struct *work_s) time_ns = iio_get_time_ns(); - if (ring->scan_timestamp) - *((s64 *)(buf + ring->access->get_bytes_per_datum(ring) - - sizeof(s64))) = time_ns; + if (indio_dev->scan_timestamp) + *((s64 *)(buf + indio_dev->scan_bytes - sizeof(s64))) = time_ns; ring->access->store_to(indio_dev->buffer, buf, time_ns); done: @@ -104,7 +102,7 @@ int ad7606_register_ring_funcs_and_init(struct iio_dev *indio_dev) struct ad7606_state *st = iio_priv(indio_dev); int ret; - indio_dev->buffer = iio_sw_rb_allocate(indio_dev); + indio_dev->buffer = iio_kfifo_allocate(indio_dev); if (!indio_dev->buffer) { ret = -ENOMEM; goto error_ret; @@ -119,13 +117,13 @@ int ad7606_register_ring_funcs_and_init(struct iio_dev *indio_dev) indio_dev->id); if (indio_dev->pollfunc == NULL) { ret = -ENOMEM; - goto error_deallocate_sw_rb; + goto error_deallocate_kfifo; } /* Ring buffer functions - here trigger setup related */ indio_dev->setup_ops = &ad7606_ring_setup_ops; - indio_dev->buffer->scan_timestamp = true ; + indio_dev->buffer->scan_timestamp = true; INIT_WORK(&st->poll_work, &ad7606_poll_bh_to_ring); @@ -133,8 +131,8 @@ int ad7606_register_ring_funcs_and_init(struct iio_dev *indio_dev) indio_dev->modes |= INDIO_BUFFER_TRIGGERED; return 0; -error_deallocate_sw_rb: - iio_sw_rb_free(indio_dev->buffer); +error_deallocate_kfifo: + iio_kfifo_free(indio_dev->buffer); error_ret: return ret; } @@ -142,5 +140,5 @@ int ad7606_register_ring_funcs_and_init(struct iio_dev *indio_dev) void ad7606_ring_cleanup(struct iio_dev *indio_dev) { iio_dealloc_pollfunc(indio_dev->pollfunc); - iio_sw_rb_free(indio_dev->buffer); + iio_kfifo_free(indio_dev->buffer); } diff --git a/trunk/drivers/staging/iio/adc/ad7606_spi.c b/trunk/drivers/staging/iio/adc/ad7606_spi.c index 237f1c44d296..099d347da52d 100644 --- a/trunk/drivers/staging/iio/adc/ad7606_spi.c +++ b/trunk/drivers/staging/iio/adc/ad7606_spi.c @@ -11,7 +11,7 @@ #include #include -#include "../iio.h" +#include #include "ad7606.h" #define MAX_SPI_FREQ_HZ 23500000 /* VDRIVE above 4.75 V */ diff --git a/trunk/drivers/staging/iio/adc/ad7780.c b/trunk/drivers/staging/iio/adc/ad7780.c index a13e58c814e6..1ece2ac8de56 100644 --- a/trunk/drivers/staging/iio/adc/ad7780.c +++ b/trunk/drivers/staging/iio/adc/ad7780.c @@ -18,8 +18,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #include "ad7780.h" @@ -94,7 +94,7 @@ static int ad7780_read_raw(struct iio_dev *indio_dev, unsigned long scale_uv; switch (m) { - case 0: + case IIO_CHAN_INFO_RAW: mutex_lock(&indio_dev->mlock); ret = ad7780_read(st, &smpl); mutex_unlock(&indio_dev->mlock); @@ -126,14 +126,34 @@ static int ad7780_read_raw(struct iio_dev *indio_dev, static const struct ad7780_chip_info ad7780_chip_info_tbl[] = { [ID_AD7780] = { - .channel = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - 0, 0, IIO_ST('s', 24, 32, 8), 0), + .channel = { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, + .scan_type = { + .sign = 's', + .realbits = 24, + .storagebits = 32, + .shift = 8, + }, + }, }, [ID_AD7781] = { - .channel = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - 0, 0, IIO_ST('s', 20, 32, 12), 0), + .channel = { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, + .scan_type = { + .sign = 's', + .realbits = 20, + .storagebits = 32, + .shift = 12, + }, + }, }, }; @@ -167,7 +187,7 @@ static int __devinit ad7780_probe(struct spi_device *spi) return -ENODEV; } - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -245,7 +265,7 @@ static int __devinit ad7780_probe(struct spi_device *spi) if (!IS_ERR(st->reg)) regulator_put(st->reg); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return ret; } @@ -262,7 +282,7 @@ static int ad7780_remove(struct spi_device *spi) regulator_disable(st->reg); regulator_put(st->reg); } - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/adc/ad7793.c b/trunk/drivers/staging/iio/adc/ad7793.c index 84ecde1ad042..b36556fa2957 100644 --- a/trunk/drivers/staging/iio/adc/ad7793.c +++ b/trunk/drivers/staging/iio/adc/ad7793.c @@ -1,7 +1,7 @@ /* * AD7792/AD7793 SPI ADC driver * - * Copyright 2011 Analog Devices Inc. + * Copyright 2011-2012 Analog Devices Inc. * * Licensed under the GPL-2. */ @@ -18,12 +18,12 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../buffer.h" -#include "../ring_sw.h" -#include "../trigger.h" -#include "../trigger_consumer.h" +#include +#include +#include +#include +#include +#include #include "ad7793.h" @@ -319,31 +319,18 @@ static int ad7793_setup(struct ad7793_state *st) static int ad7793_ring_preenable(struct iio_dev *indio_dev) { struct ad7793_state *st = iio_priv(indio_dev); - struct iio_buffer *ring = indio_dev->buffer; - size_t d_size; unsigned channel; + int ret; if (bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) return -EINVAL; + ret = iio_sw_buffer_preenable(indio_dev); + if (ret < 0) + return ret; channel = find_first_bit(indio_dev->active_scan_mask, indio_dev->masklength); - d_size = bitmap_weight(indio_dev->active_scan_mask, - indio_dev->masklength) * - indio_dev->channels[0].scan_type.storagebits / 8; - - if (ring->scan_timestamp) { - d_size += sizeof(s64); - - if (d_size % sizeof(s64)) - d_size += sizeof(s64) - (d_size % sizeof(s64)); - } - - if (indio_dev->buffer->access->set_bytes_per_datum) - indio_dev->buffer->access-> - set_bytes_per_datum(indio_dev->buffer, d_size); - st->mode = (st->mode & ~AD7793_MODE_SEL(-1)) | AD7793_MODE_SEL(AD7793_MODE_CONT); st->conf = (st->conf & ~AD7793_CONF_CHAN(-1)) | @@ -399,7 +386,7 @@ static irqreturn_t ad7793_trigger_handler(int irq, void *p) indio_dev->channels[0].scan_type.realbits/8); /* Guaranteed to be aligned with 8 byte boundary */ - if (ring->scan_timestamp) + if (indio_dev->scan_timestamp) dat64[1] = pf->timestamp; ring->access->store_to(ring, (u8 *)dat64, pf->timestamp); @@ -422,7 +409,7 @@ static int ad7793_register_ring_funcs_and_init(struct iio_dev *indio_dev) { int ret; - indio_dev->buffer = iio_sw_rb_allocate(indio_dev); + indio_dev->buffer = iio_kfifo_allocate(indio_dev); if (!indio_dev->buffer) { ret = -ENOMEM; goto error_ret; @@ -435,7 +422,7 @@ static int ad7793_register_ring_funcs_and_init(struct iio_dev *indio_dev) indio_dev->id); if (indio_dev->pollfunc == NULL) { ret = -ENOMEM; - goto error_deallocate_sw_rb; + goto error_deallocate_kfifo; } /* Ring buffer functions - here trigger setup related */ @@ -445,8 +432,8 @@ static int ad7793_register_ring_funcs_and_init(struct iio_dev *indio_dev) indio_dev->modes |= INDIO_BUFFER_TRIGGERED; return 0; -error_deallocate_sw_rb: - iio_sw_rb_free(indio_dev->buffer); +error_deallocate_kfifo: + iio_kfifo_free(indio_dev->buffer); error_ret: return ret; } @@ -454,7 +441,7 @@ static int ad7793_register_ring_funcs_and_init(struct iio_dev *indio_dev) static void ad7793_ring_cleanup(struct iio_dev *indio_dev) { iio_dealloc_pollfunc(indio_dev->pollfunc); - iio_sw_rb_free(indio_dev->buffer); + iio_kfifo_free(indio_dev->buffer); } /** @@ -482,7 +469,7 @@ static int ad7793_probe_trigger(struct iio_dev *indio_dev) struct ad7793_state *st = iio_priv(indio_dev); int ret; - st->trig = iio_allocate_trigger("%s-dev%d", + st->trig = iio_trigger_alloc("%s-dev%d", spi_get_device_id(st->spi)->name, indio_dev->id); if (st->trig == NULL) { @@ -516,7 +503,7 @@ static int ad7793_probe_trigger(struct iio_dev *indio_dev) error_free_irq: free_irq(st->spi->irq, indio_dev); error_free_trig: - iio_free_trigger(st->trig); + iio_trigger_free(st->trig); error_ret: return ret; } @@ -527,7 +514,7 @@ static void ad7793_remove_trigger(struct iio_dev *indio_dev) iio_trigger_unregister(st->trig); free_irq(st->spi->irq, indio_dev); - iio_free_trigger(st->trig); + iio_trigger_free(st->trig); } static const u16 sample_freq_avail[16] = {0, 470, 242, 123, 62, 50, 39, 33, 19, @@ -537,7 +524,7 @@ static ssize_t ad7793_read_frequency(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7793_state *st = iio_priv(indio_dev); return sprintf(buf, "%d\n", @@ -549,7 +536,7 @@ static ssize_t ad7793_write_frequency(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7793_state *st = iio_priv(indio_dev); long lval; int i, ret; @@ -591,7 +578,7 @@ static IIO_CONST_ATTR_SAMP_FREQ_AVAIL( static ssize_t ad7793_show_scale_available(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7793_state *st = iio_priv(indio_dev); int i, len = 0; @@ -630,7 +617,7 @@ static int ad7793_read_raw(struct iio_dev *indio_dev, bool unipolar = !!(st->conf & AD7793_CONF_UNIPOLAR); switch (m) { - case 0: + case IIO_CHAN_INFO_RAW: mutex_lock(&indio_dev->mlock); if (iio_buffer_enabled(indio_dev)) ret = -EBUSY; @@ -760,7 +747,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { .channel = 0, .channel2 = 0, .address = AD7793_CH_AIN1P_AIN1M, - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, .scan_index = 0, .scan_type = IIO_ST('s', 24, 32, 0) }, @@ -771,7 +759,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { .channel = 1, .channel2 = 1, .address = AD7793_CH_AIN2P_AIN2M, - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, .scan_index = 1, .scan_type = IIO_ST('s', 24, 32, 0) }, @@ -782,7 +771,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { .channel = 2, .channel2 = 2, .address = AD7793_CH_AIN3P_AIN3M, - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, .scan_index = 2, .scan_type = IIO_ST('s', 24, 32, 0) }, @@ -794,7 +784,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { .channel = 2, .channel2 = 2, .address = AD7793_CH_AIN1M_AIN1M, - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, .scan_index = 2, .scan_type = IIO_ST('s', 24, 32, 0) }, @@ -803,7 +794,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { .indexed = 1, .channel = 0, .address = AD7793_CH_TEMP, - .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .scan_index = 4, .scan_type = IIO_ST('s', 24, 32, 0), }, @@ -813,7 +805,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { .indexed = 1, .channel = 4, .address = AD7793_CH_AVDD_MONITOR, - .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .scan_index = 5, .scan_type = IIO_ST('s', 24, 32, 0), }, @@ -827,7 +820,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { .channel = 0, .channel2 = 0, .address = AD7793_CH_AIN1P_AIN1M, - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, .scan_index = 0, .scan_type = IIO_ST('s', 16, 32, 0) }, @@ -838,7 +832,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { .channel = 1, .channel2 = 1, .address = AD7793_CH_AIN2P_AIN2M, - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, .scan_index = 1, .scan_type = IIO_ST('s', 16, 32, 0) }, @@ -849,7 +844,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { .channel = 2, .channel2 = 2, .address = AD7793_CH_AIN3P_AIN3M, - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, .scan_index = 2, .scan_type = IIO_ST('s', 16, 32, 0) }, @@ -861,7 +857,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { .channel = 2, .channel2 = 2, .address = AD7793_CH_AIN1M_AIN1M, - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, .scan_index = 2, .scan_type = IIO_ST('s', 16, 32, 0) }, @@ -870,7 +867,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { .indexed = 1, .channel = 0, .address = AD7793_CH_TEMP, - .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .scan_index = 4, .scan_type = IIO_ST('s', 16, 32, 0), }, @@ -880,7 +878,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { .indexed = 1, .channel = 4, .address = AD7793_CH_AVDD_MONITOR, - .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .scan_index = 5, .scan_type = IIO_ST('s', 16, 32, 0), }, @@ -905,7 +904,7 @@ static int __devinit ad7793_probe(struct spi_device *spi) return -ENODEV; } - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -989,7 +988,7 @@ static int __devinit ad7793_probe(struct spi_device *spi) if (!IS_ERR(st->reg)) regulator_put(st->reg); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return ret; } @@ -1009,7 +1008,7 @@ static int ad7793_remove(struct spi_device *spi) regulator_put(st->reg); } - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/adc/ad7816.c b/trunk/drivers/staging/iio/adc/ad7816.c index 52b720e2b03a..5356b091b08f 100644 --- a/trunk/drivers/staging/iio/adc/ad7816.c +++ b/trunk/drivers/staging/iio/adc/ad7816.c @@ -16,9 +16,9 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../events.h" +#include +#include +#include /* * AD7816 config masks @@ -113,7 +113,7 @@ static ssize_t ad7816_show_mode(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7816_chip_info *chip = iio_priv(indio_dev); if (chip->mode) @@ -127,7 +127,7 @@ static ssize_t ad7816_store_mode(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7816_chip_info *chip = iio_priv(indio_dev); if (strcmp(buf, "full")) { @@ -159,7 +159,7 @@ static ssize_t ad7816_show_channel(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7816_chip_info *chip = iio_priv(indio_dev); return sprintf(buf, "%d\n", chip->channel_id); @@ -170,7 +170,7 @@ static ssize_t ad7816_store_channel(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7816_chip_info *chip = iio_priv(indio_dev); unsigned long data; int ret; @@ -208,7 +208,7 @@ static ssize_t ad7816_show_value(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7816_chip_info *chip = iio_priv(indio_dev); u16 data; s8 value; @@ -263,7 +263,7 @@ static ssize_t ad7816_show_oti(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7816_chip_info *chip = iio_priv(indio_dev); int value; @@ -284,7 +284,7 @@ static inline ssize_t ad7816_set_oti(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7816_chip_info *chip = iio_priv(indio_dev); long value; u8 data; @@ -354,7 +354,7 @@ static int __devinit ad7816_probe(struct spi_device *spi_dev) return -EINVAL; } - indio_dev = iio_allocate_device(sizeof(*chip)); + indio_dev = iio_device_alloc(sizeof(*chip)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -426,7 +426,7 @@ static int __devinit ad7816_probe(struct spi_device *spi_dev) error_free_gpio_rdwr: gpio_free(chip->rdwr_pin); error_free_device: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; } @@ -443,7 +443,7 @@ static int __devexit ad7816_remove(struct spi_device *spi_dev) gpio_free(chip->busy_pin); gpio_free(chip->convert_pin); gpio_free(chip->rdwr_pin); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/adc/ad7887.h b/trunk/drivers/staging/iio/adc/ad7887.h index bc53b6532121..2e09e54fc9c5 100644 --- a/trunk/drivers/staging/iio/adc/ad7887.h +++ b/trunk/drivers/staging/iio/adc/ad7887.h @@ -63,7 +63,6 @@ struct ad7887_state { struct spi_device *spi; const struct ad7887_chip_info *chip_info; struct regulator *reg; - size_t d_size; u16 int_vref_mv; struct spi_transfer xfer[4]; struct spi_message msg[3]; diff --git a/trunk/drivers/staging/iio/adc/ad7887_core.c b/trunk/drivers/staging/iio/adc/ad7887_core.c index e9bbc3eed15d..7186074deeb3 100644 --- a/trunk/drivers/staging/iio/adc/ad7887_core.c +++ b/trunk/drivers/staging/iio/adc/ad7887_core.c @@ -15,9 +15,9 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../buffer.h" +#include +#include +#include #include "ad7887.h" @@ -42,7 +42,7 @@ static int ad7887_read_raw(struct iio_dev *indio_dev, unsigned int scale_uv; switch (m) { - case 0: + case IIO_CHAN_INFO_RAW: mutex_lock(&indio_dev->mlock); if (iio_buffer_enabled(indio_dev)) ret = -EBUSY; @@ -75,7 +75,8 @@ static const struct ad7887_chip_info ad7887_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 1, - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, .address = 1, .scan_index = 1, .scan_type = IIO_ST('u', 12, 16, 0), @@ -84,7 +85,8 @@ static const struct ad7887_chip_info ad7887_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 0, - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, .address = 0, .scan_index = 0, .scan_type = IIO_ST('u', 12, 16, 0), @@ -104,7 +106,7 @@ static int __devinit ad7887_probe(struct spi_device *spi) struct ad7887_platform_data *pdata = spi->dev.platform_data; struct ad7887_state *st; int ret, voltage_uv = 0; - struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st)); + struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -220,7 +222,7 @@ static int __devinit ad7887_probe(struct spi_device *spi) error_put_reg: if (!IS_ERR(st->reg)) regulator_put(st->reg); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return ret; } @@ -237,7 +239,7 @@ static int ad7887_remove(struct spi_device *spi) regulator_disable(st->reg); regulator_put(st->reg); } - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/adc/ad7887_ring.c b/trunk/drivers/staging/iio/adc/ad7887_ring.c index d1809079b63d..fd91384db894 100644 --- a/trunk/drivers/staging/iio/adc/ad7887_ring.c +++ b/trunk/drivers/staging/iio/adc/ad7887_ring.c @@ -1,5 +1,5 @@ /* - * Copyright 2010-2011 Analog Devices Inc. + * Copyright 2010-2012 Analog Devices Inc. * Copyright (C) 2008 Jonathan Cameron * * Licensed under the GPL-2. @@ -12,10 +12,10 @@ #include #include -#include "../iio.h" -#include "../buffer.h" -#include "../ring_sw.h" -#include "../trigger_consumer.h" +#include +#include +#include +#include #include "ad7887.h" @@ -29,22 +29,11 @@ static int ad7887_ring_preenable(struct iio_dev *indio_dev) { struct ad7887_state *st = iio_priv(indio_dev); - struct iio_buffer *ring = indio_dev->buffer; - - st->d_size = bitmap_weight(indio_dev->active_scan_mask, - indio_dev->masklength) * - st->chip_info->channel[0].scan_type.storagebits / 8; - - if (ring->scan_timestamp) { - st->d_size += sizeof(s64); - - if (st->d_size % sizeof(s64)) - st->d_size += sizeof(s64) - (st->d_size % sizeof(s64)); - } + int ret; - if (indio_dev->buffer->access->set_bytes_per_datum) - indio_dev->buffer->access-> - set_bytes_per_datum(indio_dev->buffer, st->d_size); + ret = iio_sw_buffer_preenable(indio_dev); + if (ret < 0) + return ret; /* We know this is a single long so can 'cheat' */ switch (*indio_dev->active_scan_mask) { @@ -83,7 +72,6 @@ static irqreturn_t ad7887_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct ad7887_state *st = iio_priv(indio_dev); - struct iio_buffer *ring = indio_dev->buffer; s64 time_ns; __u8 *buf; int b_sent; @@ -92,7 +80,7 @@ static irqreturn_t ad7887_trigger_handler(int irq, void *p) indio_dev->masklength) * st->chip_info->channel[0].scan_type.storagebits / 8; - buf = kzalloc(st->d_size, GFP_KERNEL); + buf = kzalloc(indio_dev->scan_bytes, GFP_KERNEL); if (buf == NULL) return -ENOMEM; @@ -103,8 +91,8 @@ static irqreturn_t ad7887_trigger_handler(int irq, void *p) time_ns = iio_get_time_ns(); memcpy(buf, st->data, bytes); - if (ring->scan_timestamp) - memcpy(buf + st->d_size - sizeof(s64), + if (indio_dev->scan_timestamp) + memcpy(buf + indio_dev->scan_bytes - sizeof(s64), &time_ns, sizeof(time_ns)); indio_dev->buffer->access->store_to(indio_dev->buffer, buf, time_ns); @@ -126,7 +114,7 @@ int ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev) { int ret; - indio_dev->buffer = iio_sw_rb_allocate(indio_dev); + indio_dev->buffer = iio_kfifo_allocate(indio_dev); if (!indio_dev->buffer) { ret = -ENOMEM; goto error_ret; @@ -139,7 +127,7 @@ int ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev) indio_dev->id); if (indio_dev->pollfunc == NULL) { ret = -ENOMEM; - goto error_deallocate_sw_rb; + goto error_deallocate_kfifo; } /* Ring buffer functions - here trigger setup related */ indio_dev->setup_ops = &ad7887_ring_setup_ops; @@ -148,8 +136,8 @@ int ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev) indio_dev->modes |= INDIO_BUFFER_TRIGGERED; return 0; -error_deallocate_sw_rb: - iio_sw_rb_free(indio_dev->buffer); +error_deallocate_kfifo: + iio_kfifo_free(indio_dev->buffer); error_ret: return ret; } @@ -157,5 +145,5 @@ int ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev) void ad7887_ring_cleanup(struct iio_dev *indio_dev) { iio_dealloc_pollfunc(indio_dev->pollfunc); - iio_sw_rb_free(indio_dev->buffer); + iio_kfifo_free(indio_dev->buffer); } diff --git a/trunk/drivers/staging/iio/adc/ad799x.h b/trunk/drivers/staging/iio/adc/ad799x.h index 356f690a76fb..99f8abe9731b 100644 --- a/trunk/drivers/staging/iio/adc/ad799x.h +++ b/trunk/drivers/staging/iio/adc/ad799x.h @@ -104,7 +104,6 @@ struct ad799x_chip_info { struct ad799x_state { struct i2c_client *client; const struct ad799x_chip_info *chip_info; - size_t d_size; struct iio_trigger *trig; struct regulator *reg; u16 int_vref_mv; diff --git a/trunk/drivers/staging/iio/adc/ad799x_core.c b/trunk/drivers/staging/iio/adc/ad799x_core.c index a8458669350f..80e0c6e25a9b 100644 --- a/trunk/drivers/staging/iio/adc/ad799x_core.c +++ b/trunk/drivers/staging/iio/adc/ad799x_core.c @@ -33,10 +33,10 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../events.h" -#include "../buffer.h" +#include +#include +#include +#include #include "ad799x.h" @@ -148,7 +148,7 @@ static int ad799x_read_raw(struct iio_dev *indio_dev, unsigned int scale_uv; switch (m) { - case 0: + case IIO_CHAN_INFO_RAW: mutex_lock(&indio_dev->mlock); if (iio_buffer_enabled(indio_dev)) ret = -EBUSY; @@ -182,7 +182,7 @@ static ssize_t ad799x_read_frequency(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad799x_state *st = iio_priv(indio_dev); int ret; @@ -201,7 +201,7 @@ static ssize_t ad799x_write_frequency(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad799x_state *st = iio_priv(indio_dev); long val; @@ -294,7 +294,7 @@ static ssize_t ad799x_read_channel_config(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad799x_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); @@ -312,7 +312,7 @@ static ssize_t ad799x_write_channel_config(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad799x_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); @@ -454,6 +454,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 0, .scan_type = IIO_ST('u', 12, 16, 0), }, @@ -461,6 +462,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 1, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 1, .scan_type = IIO_ST('u', 12, 16, 0), }, @@ -468,6 +470,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 2, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 2, .scan_type = IIO_ST('u', 12, 16, 0), }, @@ -475,6 +478,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 3, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 3, .scan_type = IIO_ST('u', 12, 16, 0), }, @@ -490,6 +494,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 0, .scan_type = IIO_ST('u', 10, 16, 2), }, @@ -497,6 +502,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 1, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 1, .scan_type = IIO_ST('u', 10, 16, 2), }, @@ -504,6 +510,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 2, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 2, .scan_type = IIO_ST('u', 10, 16, 2), }, @@ -511,6 +518,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 3, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 3, .scan_type = IIO_ST('u', 10, 16, 2), }, @@ -526,6 +534,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 0, .scan_type = IIO_ST('u', 8, 16, 4), }, @@ -533,6 +542,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 1, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 1, .scan_type = IIO_ST('u', 8, 16, 4), }, @@ -540,6 +550,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 2, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 2, .scan_type = IIO_ST('u', 8, 16, 4), }, @@ -547,6 +558,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 3, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 3, .scan_type = IIO_ST('u', 8, 16, 4), }, @@ -562,6 +574,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 0, .scan_type = IIO_ST('u', 12, 16, 0), .event_mask = AD799X_EV_MASK, @@ -570,6 +583,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 1, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 1, .scan_type = IIO_ST('u', 12, 16, 0), .event_mask = AD799X_EV_MASK, @@ -587,6 +601,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 0, .scan_type = IIO_ST('u', 10, 16, 2), .event_mask = AD799X_EV_MASK, @@ -596,6 +611,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .indexed = 1, .channel = 1, .scan_index = 1, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_type = IIO_ST('u', 10, 16, 2), .event_mask = AD799X_EV_MASK, }, @@ -603,6 +619,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 2, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 2, .scan_type = IIO_ST('u', 10, 16, 2), .event_mask = AD799X_EV_MASK, @@ -611,6 +628,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 3, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 3, .scan_type = IIO_ST('u', 10, 16, 2), .event_mask = AD799X_EV_MASK, @@ -628,6 +646,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 0, .scan_type = IIO_ST('u', 12, 16, 0), .event_mask = AD799X_EV_MASK, @@ -636,6 +655,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 1, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 1, .scan_type = IIO_ST('u', 12, 16, 0), .event_mask = AD799X_EV_MASK, @@ -644,6 +664,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 2, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 2, .scan_type = IIO_ST('u', 12, 16, 0), .event_mask = AD799X_EV_MASK, @@ -652,6 +673,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 3, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 3, .scan_type = IIO_ST('u', 12, 16, 0), .event_mask = AD799X_EV_MASK, @@ -669,6 +691,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 0, .scan_type = IIO_ST('u', 10, 16, 2), .event_mask = AD799X_EV_MASK, @@ -677,6 +700,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 1, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 1, .scan_type = IIO_ST('u', 10, 16, 2), .event_mask = AD799X_EV_MASK, @@ -685,6 +709,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 2, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 2, .scan_type = IIO_ST('u', 10, 16, 2), .event_mask = AD799X_EV_MASK, @@ -693,6 +718,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 3, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 3, .scan_type = IIO_ST('u', 10, 16, 2), .event_mask = AD799X_EV_MASK, @@ -701,6 +727,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 4, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 4, .scan_type = IIO_ST('u', 10, 16, 2), }, @@ -708,6 +735,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 5, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 5, .scan_type = IIO_ST('u', 10, 16, 2), }, @@ -715,6 +743,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 6, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 6, .scan_type = IIO_ST('u', 10, 16, 2), }, @@ -722,6 +751,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 7, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 7, .scan_type = IIO_ST('u', 10, 16, 2), }, @@ -738,6 +768,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 0, .scan_type = IIO_ST('u', 12, 16, 0), .event_mask = AD799X_EV_MASK, @@ -746,6 +777,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 1, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 1, .scan_type = IIO_ST('u', 12, 16, 0), .event_mask = AD799X_EV_MASK, @@ -754,6 +786,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 2, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 2, .scan_type = IIO_ST('u', 12, 16, 0), .event_mask = AD799X_EV_MASK, @@ -762,6 +795,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 3, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 3, .scan_type = IIO_ST('u', 12, 16, 0), .event_mask = AD799X_EV_MASK, @@ -770,6 +804,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 4, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 4, .scan_type = IIO_ST('u', 12, 16, 0), }, @@ -777,6 +812,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 5, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 5, .scan_type = IIO_ST('u', 12, 16, 0), }, @@ -784,6 +820,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 6, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 6, .scan_type = IIO_ST('u', 12, 16, 0), }, @@ -791,6 +828,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 7, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .scan_index = 7, .scan_type = IIO_ST('u', 12, 16, 0), }, @@ -809,7 +847,7 @@ static int __devinit ad799x_probe(struct i2c_client *client, int ret; struct ad799x_platform_data *pdata = client->dev.platform_data; struct ad799x_state *st; - struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st)); + struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -882,7 +920,7 @@ static int __devinit ad799x_probe(struct i2c_client *client, error_put_reg: if (!IS_ERR(st->reg)) regulator_put(st->reg); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return ret; } @@ -902,7 +940,7 @@ static __devexit int ad799x_remove(struct i2c_client *client) regulator_disable(st->reg); regulator_put(st->reg); } - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/adc/ad799x_ring.c b/trunk/drivers/staging/iio/adc/ad799x_ring.c index 069765cab275..1c7ff4423db4 100644 --- a/trunk/drivers/staging/iio/adc/ad799x_ring.c +++ b/trunk/drivers/staging/iio/adc/ad799x_ring.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc. + * 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 @@ -16,10 +16,10 @@ #include #include -#include "../iio.h" -#include "../buffer.h" -#include "../ring_sw.h" -#include "../trigger_consumer.h" +#include +#include +#include +#include #include "ad799x.h" @@ -32,9 +32,7 @@ **/ static int ad799x_ring_preenable(struct iio_dev *indio_dev) { - struct iio_buffer *ring = indio_dev->buffer; struct ad799x_state *st = iio_priv(indio_dev); - /* * Need to figure out the current mode based upon the requested * scan mask in iio_dev @@ -43,21 +41,7 @@ static int ad799x_ring_preenable(struct iio_dev *indio_dev) if (st->id == ad7997 || st->id == ad7998) ad7997_8_set_scan_mode(st, *indio_dev->active_scan_mask); - st->d_size = bitmap_weight(indio_dev->active_scan_mask, - indio_dev->masklength) * 2; - - if (ring->scan_timestamp) { - st->d_size += sizeof(s64); - - if (st->d_size % sizeof(s64)) - st->d_size += sizeof(s64) - (st->d_size % sizeof(s64)); - } - - if (indio_dev->buffer->access->set_bytes_per_datum) - indio_dev->buffer->access-> - set_bytes_per_datum(indio_dev->buffer, st->d_size); - - return 0; + return iio_sw_buffer_preenable(indio_dev); } /** @@ -78,7 +62,7 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p) int b_sent; u8 cmd; - rxbuf = kmalloc(st->d_size, GFP_KERNEL); + rxbuf = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); if (rxbuf == NULL) goto out; @@ -111,8 +95,8 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p) time_ns = iio_get_time_ns(); - if (ring->scan_timestamp) - memcpy(rxbuf + st->d_size - sizeof(s64), + if (indio_dev->scan_timestamp) + memcpy(rxbuf + indio_dev->scan_bytes - sizeof(s64), &time_ns, sizeof(time_ns)); ring->access->store_to(indio_dev->buffer, rxbuf, time_ns); @@ -136,7 +120,7 @@ int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev) { int ret = 0; - indio_dev->buffer = iio_sw_rb_allocate(indio_dev); + indio_dev->buffer = iio_kfifo_allocate(indio_dev); if (!indio_dev->buffer) { ret = -ENOMEM; goto error_ret; @@ -150,7 +134,7 @@ int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev) indio_dev->id); if (indio_dev->pollfunc == NULL) { ret = -ENOMEM; - goto error_deallocate_sw_rb; + goto error_deallocate_kfifo; } /* Ring buffer functions - here trigger setup related */ @@ -161,8 +145,8 @@ int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev) indio_dev->modes |= INDIO_BUFFER_TRIGGERED; return 0; -error_deallocate_sw_rb: - iio_sw_rb_free(indio_dev->buffer); +error_deallocate_kfifo: + iio_kfifo_free(indio_dev->buffer); error_ret: return ret; } @@ -170,5 +154,5 @@ int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev) void ad799x_ring_cleanup(struct iio_dev *indio_dev) { iio_dealloc_pollfunc(indio_dev->pollfunc); - iio_sw_rb_free(indio_dev->buffer); + iio_kfifo_free(indio_dev->buffer); } diff --git a/trunk/drivers/staging/iio/adc/adt7310.c b/trunk/drivers/staging/iio/adc/adt7310.c index caf57c1169b1..e5f1ed7f8696 100644 --- a/trunk/drivers/staging/iio/adc/adt7310.c +++ b/trunk/drivers/staging/iio/adc/adt7310.c @@ -15,9 +15,9 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../events.h" +#include +#include +#include /* * ADT7310 registers definition */ @@ -175,7 +175,7 @@ static ssize_t adt7310_show_mode(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7310_chip_info *chip = iio_priv(dev_info); u8 config; @@ -198,7 +198,7 @@ static ssize_t adt7310_store_mode(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7310_chip_info *chip = iio_priv(dev_info); u16 config; int ret; @@ -242,7 +242,7 @@ static ssize_t adt7310_show_resolution(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7310_chip_info *chip = iio_priv(dev_info); int ret; int bits; @@ -264,7 +264,7 @@ static ssize_t adt7310_store_resolution(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7310_chip_info *chip = iio_priv(dev_info); unsigned long data; u16 config; @@ -300,7 +300,7 @@ static ssize_t adt7310_show_id(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7310_chip_info *chip = iio_priv(dev_info); u8 id; int ret; @@ -350,7 +350,7 @@ static ssize_t adt7310_show_value(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7310_chip_info *chip = iio_priv(dev_info); u8 status; u16 data; @@ -424,7 +424,7 @@ static ssize_t adt7310_show_event_mode(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7310_chip_info *chip = iio_priv(dev_info); int ret; @@ -443,7 +443,7 @@ static ssize_t adt7310_set_event_mode(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7310_chip_info *chip = iio_priv(dev_info); u16 config; int ret; @@ -476,7 +476,7 @@ static ssize_t adt7310_show_fault_queue(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7310_chip_info *chip = iio_priv(dev_info); int ret; @@ -492,7 +492,7 @@ static ssize_t adt7310_set_fault_queue(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7310_chip_info *chip = iio_priv(dev_info); unsigned long data; int ret; @@ -522,7 +522,7 @@ static inline ssize_t adt7310_show_t_bound(struct device *dev, u8 bound_reg, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7310_chip_info *chip = iio_priv(dev_info); u16 data; int ret; @@ -540,7 +540,7 @@ static inline ssize_t adt7310_set_t_bound(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7310_chip_info *chip = iio_priv(dev_info); long tmp1, tmp2; u16 data; @@ -660,7 +660,7 @@ static ssize_t adt7310_show_t_hyst(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7310_chip_info *chip = iio_priv(dev_info); int ret; u8 t_hyst; @@ -677,7 +677,7 @@ static inline ssize_t adt7310_set_t_hyst(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7310_chip_info *chip = iio_priv(dev_info); int ret; unsigned long data; @@ -753,7 +753,7 @@ static int __devinit adt7310_probe(struct spi_device *spi_dev) unsigned long *adt7310_platform_data = spi_dev->dev.platform_data; unsigned long irq_flags; - indio_dev = iio_allocate_device(sizeof(*chip)); + indio_dev = iio_device_alloc(sizeof(*chip)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -833,7 +833,7 @@ static int __devinit adt7310_probe(struct spi_device *spi_dev) error_unreg_ct_irq: free_irq(spi_dev->irq, indio_dev); error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; } @@ -849,7 +849,7 @@ static int __devexit adt7310_remove(struct spi_device *spi_dev) free_irq(adt7310_platform_data[0], indio_dev); if (spi_dev->irq) free_irq(spi_dev->irq, indio_dev); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/adc/adt7410.c b/trunk/drivers/staging/iio/adc/adt7410.c index dff3e8ca2d78..917b6921e24d 100644 --- a/trunk/drivers/staging/iio/adc/adt7410.c +++ b/trunk/drivers/staging/iio/adc/adt7410.c @@ -15,9 +15,9 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../events.h" +#include +#include +#include /* * ADT7410 registers definition @@ -144,7 +144,7 @@ static ssize_t adt7410_show_mode(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7410_chip_info *chip = iio_priv(dev_info); u8 config; @@ -167,7 +167,7 @@ static ssize_t adt7410_store_mode(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7410_chip_info *chip = iio_priv(dev_info); u16 config; int ret; @@ -211,7 +211,7 @@ static ssize_t adt7410_show_resolution(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7410_chip_info *chip = iio_priv(dev_info); int ret; int bits; @@ -233,7 +233,7 @@ static ssize_t adt7410_store_resolution(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7410_chip_info *chip = iio_priv(dev_info); unsigned long data; u16 config; @@ -269,7 +269,7 @@ static ssize_t adt7410_show_id(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7410_chip_info *chip = iio_priv(dev_info); u8 id; int ret; @@ -319,7 +319,7 @@ static ssize_t adt7410_show_value(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7410_chip_info *chip = iio_priv(dev_info); u8 status; u16 data; @@ -392,7 +392,7 @@ static ssize_t adt7410_show_event_mode(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7410_chip_info *chip = iio_priv(dev_info); int ret; @@ -411,7 +411,7 @@ static ssize_t adt7410_set_event_mode(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7410_chip_info *chip = iio_priv(dev_info); u16 config; int ret; @@ -444,7 +444,7 @@ static ssize_t adt7410_show_fault_queue(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7410_chip_info *chip = iio_priv(dev_info); int ret; @@ -460,7 +460,7 @@ static ssize_t adt7410_set_fault_queue(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7410_chip_info *chip = iio_priv(dev_info); unsigned long data; int ret; @@ -490,7 +490,7 @@ static inline ssize_t adt7410_show_t_bound(struct device *dev, u8 bound_reg, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7410_chip_info *chip = iio_priv(dev_info); u16 data; int ret; @@ -508,7 +508,7 @@ static inline ssize_t adt7410_set_t_bound(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7410_chip_info *chip = iio_priv(dev_info); long tmp1, tmp2; u16 data; @@ -628,7 +628,7 @@ static ssize_t adt7410_show_t_hyst(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7410_chip_info *chip = iio_priv(dev_info); int ret; u8 t_hyst; @@ -645,7 +645,7 @@ static inline ssize_t adt7410_set_t_hyst(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7410_chip_info *chip = iio_priv(dev_info); int ret; unsigned long data; @@ -721,7 +721,7 @@ static int __devinit adt7410_probe(struct i2c_client *client, int ret = 0; unsigned long *adt7410_platform_data = client->dev.platform_data; - indio_dev = iio_allocate_device(sizeof(*chip)); + indio_dev = iio_device_alloc(sizeof(*chip)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -797,7 +797,7 @@ static int __devinit adt7410_probe(struct i2c_client *client, error_unreg_ct_irq: free_irq(client->irq, indio_dev); error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; } @@ -812,7 +812,7 @@ static int __devexit adt7410_remove(struct i2c_client *client) free_irq(adt7410_platform_data[0], indio_dev); if (client->irq) free_irq(client->irq, indio_dev); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/adc/lpc32xx_adc.c b/trunk/drivers/staging/iio/adc/lpc32xx_adc.c index dfc9033843a3..9690306d1f8f 100644 --- a/trunk/drivers/staging/iio/adc/lpc32xx_adc.c +++ b/trunk/drivers/staging/iio/adc/lpc32xx_adc.c @@ -30,9 +30,10 @@ #include #include #include +#include -#include "../iio.h" -#include "../sysfs.h" +#include +#include /* * LPC32XX registers definitions @@ -73,7 +74,7 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev, { struct lpc32xx_adc_info *info = iio_priv(indio_dev); - if (mask == 0) { + if (mask == IIO_CHAN_INFO_RAW) { mutex_lock(&indio_dev->mlock); clk_enable(info->clk); /* Measurement setup */ @@ -98,12 +99,13 @@ static const struct iio_info lpc32xx_adc_iio_info = { .driver_module = THIS_MODULE, }; -#define LPC32XX_ADC_CHANNEL(_index) { \ - .type = IIO_VOLTAGE, \ - .indexed = 1, \ - .channel = _index, \ - .address = AD_IN * _index, \ - .scan_index = _index, \ +#define LPC32XX_ADC_CHANNEL(_index) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = _index, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, \ + .address = AD_IN * _index, \ + .scan_index = _index, \ } static struct iio_chan_spec lpc32xx_adc_iio_channels[] = { @@ -139,7 +141,7 @@ static int __devinit lpc32xx_adc_probe(struct platform_device *pdev) goto errout1; } - iodev = iio_allocate_device(sizeof(struct lpc32xx_adc_info)); + iodev = iio_device_alloc(sizeof(struct lpc32xx_adc_info)); if (!iodev) { dev_err(&pdev->dev, "failed allocating iio device\n"); retval = -ENOMEM; @@ -200,7 +202,7 @@ static int __devinit lpc32xx_adc_probe(struct platform_device *pdev) errout3: iounmap(info->adc_base); errout2: - iio_free_device(iodev); + iio_device_free(iodev); errout1: return retval; } @@ -216,17 +218,26 @@ static int __devexit lpc32xx_adc_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); clk_put(info->clk); iounmap(info->adc_base); - iio_free_device(iodev); + iio_device_free(iodev); return 0; } +#ifdef CONFIG_OF +static const struct of_device_id lpc32xx_adc_match[] = { + { .compatible = "nxp,lpc3220-adc" }, + {}, +}; +MODULE_DEVICE_TABLE(of, lpc32xx_adc_match); +#endif + static struct platform_driver lpc32xx_adc_driver = { .probe = lpc32xx_adc_probe, .remove = __devexit_p(lpc32xx_adc_remove), .driver = { .name = MOD_NAME, .owner = THIS_MODULE, + .of_match_table = of_match_ptr(lpc32xx_adc_match), }, }; diff --git a/trunk/drivers/staging/iio/adc/max1363_core.c b/trunk/drivers/staging/iio/adc/max1363_core.c index cf3e2ca7e314..6799ce23a395 100644 --- a/trunk/drivers/staging/iio/adc/max1363_core.c +++ b/trunk/drivers/staging/iio/adc/max1363_core.c @@ -32,10 +32,11 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../events.h" -#include "../buffer.h" +#include +#include +#include +#include +#include #include "max1363.h" @@ -248,7 +249,7 @@ static int max1363_read_raw(struct iio_dev *indio_dev, struct max1363_state *st = iio_priv(indio_dev); int ret; switch (m) { - case 0: + case IIO_CHAN_INFO_RAW: ret = max1363_read_single_chan(indio_dev, chan, val, m); if (ret < 0) return ret; @@ -281,7 +282,8 @@ static const enum max1363_modes max1363_mode_list[] = { #define MAX1363_EV_M \ (IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) \ | IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING)) -#define MAX1363_INFO_MASK IIO_CHAN_INFO_SCALE_SHARED_BIT +#define MAX1363_INFO_MASK (IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SHARED_BIT) #define MAX1363_CHAN_U(num, addr, si, bits, evmask) \ { \ .type = IIO_VOLTAGE, \ @@ -497,7 +499,7 @@ static ssize_t max1363_monitor_show_freq(struct device *dev, struct device_attribute *attr, char *buf) { - struct max1363_state *st = iio_priv(dev_get_drvdata(dev)); + struct max1363_state *st = iio_priv(dev_to_iio_dev(dev)); return sprintf(buf, "%d\n", max1363_monitor_speeds[st->monitor_speed]); } @@ -506,7 +508,7 @@ static ssize_t max1363_monitor_store_freq(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct max1363_state *st = iio_priv(indio_dev); int i, ret; unsigned long val; @@ -830,6 +832,7 @@ static struct attribute_group max1363_event_attribute_group = { static const struct iio_info max1238_info = { .read_raw = &max1363_read_raw, .driver_module = THIS_MODULE, + .update_scan_mode = &max1363_update_scan_mode, }; static const struct iio_info max1363_info = { @@ -1284,11 +1287,14 @@ static int __devinit max1363_probe(struct i2c_client *client, if (ret) goto error_put_reg; - indio_dev = iio_allocate_device(sizeof(struct max1363_state)); + indio_dev = iio_device_alloc(sizeof(struct max1363_state)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_disable_reg; } + ret = iio_map_array_register(indio_dev, client->dev.platform_data); + if (ret < 0) + goto error_free_device; st = iio_priv(indio_dev); st->reg = reg; /* this is only used for device removal purposes */ @@ -1299,7 +1305,7 @@ static int __devinit max1363_probe(struct i2c_client *client, ret = max1363_alloc_scan_masks(indio_dev); if (ret) - goto error_free_device; + goto error_unregister_map; /* Estabilish that the iio_dev is a child of the i2c device */ indio_dev->dev.parent = &client->dev; @@ -1349,8 +1355,10 @@ static int __devinit max1363_probe(struct i2c_client *client, max1363_ring_cleanup(indio_dev); error_free_available_scan_masks: kfree(indio_dev->available_scan_masks); +error_unregister_map: + iio_map_array_unregister(indio_dev, client->dev.platform_data); error_free_device: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_disable_reg: regulator_disable(reg); error_put_reg: @@ -1375,7 +1383,8 @@ static int max1363_remove(struct i2c_client *client) regulator_disable(reg); regulator_put(reg); } - iio_free_device(indio_dev); + iio_map_array_unregister(indio_dev, client->dev.platform_data); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/adc/max1363_ring.c b/trunk/drivers/staging/iio/adc/max1363_ring.c index d0a60a382930..b30201300121 100644 --- a/trunk/drivers/staging/iio/adc/max1363_ring.c +++ b/trunk/drivers/staging/iio/adc/max1363_ring.c @@ -14,10 +14,10 @@ #include #include -#include "../iio.h" -#include "../buffer.h" +#include +#include #include "../ring_sw.h" -#include "../trigger_consumer.h" +#include #include "max1363.h" @@ -54,7 +54,7 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p) d_size = numvals*2; else d_size = numvals; - if (indio_dev->buffer->scan_timestamp) { + if (indio_dev->scan_timestamp) { d_size += sizeof(s64); if (d_size % sizeof(s64)) d_size += sizeof(s64) - (d_size % sizeof(s64)); @@ -78,7 +78,7 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p) time_ns = iio_get_time_ns(); - if (indio_dev->buffer->scan_timestamp) + if (indio_dev->scan_timestamp) memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns)); iio_push_to_buffer(indio_dev->buffer, rxbuf, time_ns); diff --git a/trunk/drivers/staging/iio/adc/spear_adc.c b/trunk/drivers/staging/iio/adc/spear_adc.c new file mode 100644 index 000000000000..64d630e6fe29 --- /dev/null +++ b/trunk/drivers/staging/iio/adc/spear_adc.c @@ -0,0 +1,448 @@ +/* + * ST SPEAr ADC driver + * + * Copyright 2012 Stefan Roese + * + * Licensed under the GPL-2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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) + +/* 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 DATA_MASK 0x03ff +#define DATA_BITS 10 + +#define MOD_NAME "spear-adc" + +#define ADC_CHANNEL_NUM 8 + +#define CLK_MIN 2500000 +#define 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]; +}; + +struct chan_data { + u32 lsb; + u32 msb; +}; + +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 scan_rate_lo; + u32 scan_rate_hi; + struct chan_data average; +}; + +struct spear_adc_info { + struct device_node *np; + struct adc_regs_spear3xx __iomem *adc_base_spear3xx; + struct adc_regs_spear6xx __iomem *adc_base_spear6xx; + struct clk *clk; + struct completion completion; + u32 current_clk; + u32 sampling_freq; + u32 avg_samples; + u32 vref_external; + u32 value; +}; + +/* + * Functions to access some SPEAr ADC register. Abstracted into + * 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) +{ + __raw_writel(val, &info->adc_base_spear6xx->status); +} + +static void spear_adc_set_clk(struct spear_adc_info *info, u32 val) +{ + u32 clk_high, clk_low, count; + u32 apb_clk = clk_get_rate(info->clk); + + count = (apb_clk + val - 1) / val; + clk_low = count / 2; + clk_high = count - clk_low; + info->current_clk = apb_clk / count; + + __raw_writel(CLK_LOW(clk_low) | CLK_HIGH(clk_high), + &info->adc_base_spear6xx->clk); +} + +static void spear_adc_set_ctrl(struct spear_adc_info *info, int n, + u32 val) +{ + __raw_writel(val, &info->adc_base_spear6xx->ch_ctrl[n]); +} + +static u32 spear_adc_get_average(struct spear_adc_info *info) +{ + if (of_device_is_compatible(info->np, "st,spear600-adc")) { + return __raw_readl(&info->adc_base_spear6xx->average.msb) & + DATA_MASK; + } else { + return __raw_readl(&info->adc_base_spear3xx->average) & + DATA_MASK; + } +} + +static void spear_adc_set_scanrate(struct spear_adc_info *info, 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); + } else { + __raw_writel(rate, &info->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) +{ + struct spear_adc_info *info = iio_priv(indio_dev); + u32 scale_mv; + 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; + + spear_adc_set_status(info, status); + wait_for_completion(&info->completion); /* set by ISR */ + *val = info->value; + + mutex_unlock(&indio_dev->mlock); + + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + scale_mv = (info->vref_external * 1000) >> DATA_BITS; + *val = scale_mv / 1000; + *val2 = (scale_mv % 1000) * 1000; + return IIO_VAL_INT_PLUS_MICRO; + } + + return -EINVAL; +} + +#define SPEAR_ADC_CHAN(idx) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SHARED_BIT, \ + .channel = idx, \ + .scan_type = { \ + .sign = 'u', \ + .storagebits = 16, \ + }, \ +} + +static struct iio_chan_spec spear_adc_iio_channels[] = { + SPEAR_ADC_CHAN(0), + SPEAR_ADC_CHAN(1), + SPEAR_ADC_CHAN(2), + SPEAR_ADC_CHAN(3), + SPEAR_ADC_CHAN(4), + SPEAR_ADC_CHAN(5), + SPEAR_ADC_CHAN(6), + SPEAR_ADC_CHAN(7), +}; + +static irqreturn_t spear_adc_isr(int irq, void *dev_id) +{ + struct spear_adc_info *info = (struct spear_adc_info *)dev_id; + + /* Read value to clear IRQ */ + info->value = spear_adc_get_average(info); + complete(&info->completion); + + return IRQ_HANDLED; +} + +static int spear_adc_configure(struct spear_adc_info *info) +{ + int i; + + /* Reset ADC core */ + spear_adc_set_status(info, 0); + __raw_writel(0, &info->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_clk(info, info->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, + .driver_module = THIS_MODULE, +}; + +static int __devinit 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; + int ret = -ENODEV; + int irq; + + iodev = iio_device_alloc(sizeof(struct spear_adc_info)); + if (!iodev) { + dev_err(dev, "failed allocating iio device\n"); + ret = -ENOMEM; + goto errout1; + } + + info = iio_priv(iodev); + info->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) { + dev_err(dev, "failed mapping memory\n"); + ret = -ENOMEM; + goto errout2; + } + info->adc_base_spear3xx = + (struct adc_regs_spear3xx *)info->adc_base_spear6xx; + + info->clk = clk_get(dev, NULL); + if (IS_ERR(info->clk)) { + dev_err(dev, "failed getting clock\n"); + goto errout3; + } + + ret = clk_prepare(info->clk); + if (ret) { + dev_err(dev, "failed preparing clock\n"); + goto errout4; + } + + ret = clk_enable(info->clk); + if (ret) { + dev_err(dev, "failed enabling clock\n"); + goto errout5; + } + + irq = platform_get_irq(pdev, 0); + if ((irq < 0) || (irq >= NR_IRQS)) { + dev_err(dev, "failed getting interrupt resource\n"); + ret = -EINVAL; + goto errout6; + } + + ret = devm_request_irq(dev, irq, spear_adc_isr, 0, MOD_NAME, info); + if (ret < 0) { + dev_err(dev, "failed requesting interrupt\n"); + goto errout6; + } + + if (of_property_read_u32(np, "sampling-frequency", + &info->sampling_freq)) { + dev_err(dev, "sampling-frequency missing in DT\n"); + ret = -EINVAL; + goto errout6; + } + + /* + * Optional avg_samples defaults to 0, resulting in single data + * conversion + */ + of_property_read_u32(np, "average-samples", &info->avg_samples); + + /* + * Optional vref_external defaults to 0, resulting in internal vref + * selection + */ + of_property_read_u32(np, "vref-external", &info->vref_external); + + spear_adc_configure(info); + + platform_set_drvdata(pdev, iodev); + + init_completion(&info->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); + + ret = iio_device_register(iodev); + if (ret) + goto errout6; + + dev_info(dev, "SPEAR ADC driver loaded, IRQ %d\n", irq); + + return 0; + +errout6: + clk_disable(info->clk); +errout5: + clk_unprepare(info->clk); +errout4: + clk_put(info->clk); +errout3: + iounmap(info->adc_base_spear6xx); +errout2: + iio_device_free(iodev); +errout1: + return ret; +} + +static int __devexit spear_adc_remove(struct platform_device *pdev) +{ + struct iio_dev *iodev = platform_get_drvdata(pdev); + struct spear_adc_info *info = iio_priv(iodev); + + iio_device_unregister(iodev); + platform_set_drvdata(pdev, NULL); + clk_disable(info->clk); + clk_unprepare(info->clk); + clk_put(info->clk); + iounmap(info->adc_base_spear6xx); + iio_device_free(iodev); + + return 0; +} + +static const struct of_device_id spear_adc_dt_ids[] = { + { .compatible = "st,spear600-adc", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, spear_adc_dt_ids); + +static struct platform_driver spear_adc_driver = { + .probe = spear_adc_probe, + .remove = __devexit_p(spear_adc_remove), + .driver = { + .name = MOD_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(spear_adc_dt_ids), + }, +}; + +module_platform_driver(spear_adc_driver); + +MODULE_AUTHOR("Stefan Roese "); +MODULE_DESCRIPTION("SPEAr ADC driver"); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/iio/addac/adt7316.c b/trunk/drivers/staging/iio/addac/adt7316.c index fd6a45444058..8fb014a046a2 100644 --- a/trunk/drivers/staging/iio/addac/adt7316.c +++ b/trunk/drivers/staging/iio/addac/adt7316.c @@ -19,9 +19,9 @@ #include #include -#include "../iio.h" -#include "../events.h" -#include "../sysfs.h" +#include +#include +#include #include "adt7316.h" /* @@ -220,7 +220,7 @@ static ssize_t adt7316_show_enabled(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return sprintf(buf, "%d\n", !!(chip->config1 & ADT7316_EN)); @@ -252,7 +252,7 @@ static ssize_t adt7316_store_enabled(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); int enable; @@ -276,7 +276,7 @@ static ssize_t adt7316_show_select_ex_temp(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX) @@ -290,7 +290,7 @@ static ssize_t adt7316_store_select_ex_temp(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 config1; int ret; @@ -320,7 +320,7 @@ static ssize_t adt7316_show_mode(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); if (chip->config2 & ADT7316_AD_SINGLE_CH_MODE) @@ -334,7 +334,7 @@ static ssize_t adt7316_store_mode(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 config2; int ret; @@ -370,7 +370,7 @@ static ssize_t adt7316_show_ad_channel(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); if (!(chip->config2 & ADT7316_AD_SINGLE_CH_MODE)) @@ -409,7 +409,7 @@ static ssize_t adt7316_store_ad_channel(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 config2; unsigned long data = 0; @@ -455,7 +455,7 @@ static ssize_t adt7316_show_all_ad_channels(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); if (!(chip->config2 & ADT7316_AD_SINGLE_CH_MODE)) @@ -477,7 +477,7 @@ static ssize_t adt7316_show_disable_averaging(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return sprintf(buf, "%d\n", @@ -489,7 +489,7 @@ static ssize_t adt7316_store_disable_averaging(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 config2; int ret; @@ -516,7 +516,7 @@ static ssize_t adt7316_show_enable_smbus_timeout(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return sprintf(buf, "%d\n", @@ -528,7 +528,7 @@ static ssize_t adt7316_store_enable_smbus_timeout(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 config2; int ret; @@ -557,7 +557,7 @@ static ssize_t adt7316_store_reset(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 config2; int ret; @@ -580,7 +580,7 @@ static ssize_t adt7316_show_powerdown(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return sprintf(buf, "%d\n", !!(chip->config1 & ADT7316_PD)); @@ -591,7 +591,7 @@ static ssize_t adt7316_store_powerdown(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 config1; int ret; @@ -618,7 +618,7 @@ static ssize_t adt7316_show_fast_ad_clock(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return sprintf(buf, "%d\n", !!(chip->config3 & ADT7316_ADCLK_22_5)); @@ -629,7 +629,7 @@ static ssize_t adt7316_store_fast_ad_clock(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 config3; int ret; @@ -656,7 +656,7 @@ static ssize_t adt7316_show_da_high_resolution(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); if (chip->config3 & ADT7316_DA_HIGH_RESOLUTION) { @@ -674,7 +674,7 @@ static ssize_t adt7316_store_da_high_resolution(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 config3; int ret; @@ -708,7 +708,7 @@ static ssize_t adt7316_show_AIN_internal_Vref(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX) @@ -723,7 +723,7 @@ static ssize_t adt7316_store_AIN_internal_Vref(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 config3; int ret; @@ -755,7 +755,7 @@ static ssize_t adt7316_show_enable_prop_DACA(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return sprintf(buf, "%d\n", @@ -767,7 +767,7 @@ static ssize_t adt7316_store_enable_prop_DACA(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 config3; int ret; @@ -794,7 +794,7 @@ static ssize_t adt7316_show_enable_prop_DACB(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return sprintf(buf, "%d\n", @@ -806,7 +806,7 @@ static ssize_t adt7316_store_enable_prop_DACB(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 config3; int ret; @@ -833,7 +833,7 @@ static ssize_t adt7316_show_DAC_2Vref_ch_mask(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return sprintf(buf, "0x%x\n", @@ -845,7 +845,7 @@ static ssize_t adt7316_store_DAC_2Vref_ch_mask(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 dac_config; unsigned long data = 0; @@ -876,7 +876,7 @@ static ssize_t adt7316_show_DAC_update_mode(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); if (!(chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA)) @@ -900,7 +900,7 @@ static ssize_t adt7316_store_DAC_update_mode(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 dac_config; unsigned long data; @@ -934,7 +934,7 @@ static ssize_t adt7316_show_all_DAC_update_modes(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); if (chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA) @@ -955,7 +955,7 @@ static ssize_t adt7316_store_update_DAC(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 ldac_config; unsigned long data; @@ -994,7 +994,7 @@ static ssize_t adt7316_show_DA_AB_Vref_bypass(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) @@ -1009,7 +1009,7 @@ static ssize_t adt7316_store_DA_AB_Vref_bypass(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 dac_config; int ret; @@ -1039,7 +1039,7 @@ static ssize_t adt7316_show_DA_CD_Vref_bypass(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) @@ -1054,7 +1054,7 @@ static ssize_t adt7316_store_DA_CD_Vref_bypass(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 dac_config; int ret; @@ -1084,7 +1084,7 @@ static ssize_t adt7316_show_DAC_internal_Vref(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) @@ -1101,7 +1101,7 @@ static ssize_t adt7316_store_DAC_internal_Vref(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 ldac_config; unsigned long data; @@ -1220,7 +1220,7 @@ static ssize_t adt7316_show_VDD(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_VDD, buf); @@ -1231,7 +1231,7 @@ static ssize_t adt7316_show_in_temp(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_IN, buf); @@ -1243,7 +1243,7 @@ static ssize_t adt7316_show_ex_temp_AIN1(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_EX, buf); @@ -1256,7 +1256,7 @@ static ssize_t adt7316_show_AIN2(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN2, buf); @@ -1267,7 +1267,7 @@ static ssize_t adt7316_show_AIN3(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN3, buf); @@ -1278,7 +1278,7 @@ static ssize_t adt7316_show_AIN4(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN4, buf); @@ -1330,7 +1330,7 @@ static ssize_t adt7316_show_in_temp_offset(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return adt7316_show_temp_offset(chip, ADT7316_IN_TEMP_OFFSET, buf); @@ -1341,7 +1341,7 @@ static ssize_t adt7316_store_in_temp_offset(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return adt7316_store_temp_offset(chip, ADT7316_IN_TEMP_OFFSET, buf, len); @@ -1355,7 +1355,7 @@ static ssize_t adt7316_show_ex_temp_offset(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return adt7316_show_temp_offset(chip, ADT7316_EX_TEMP_OFFSET, buf); @@ -1366,7 +1366,7 @@ static ssize_t adt7316_store_ex_temp_offset(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return adt7316_store_temp_offset(chip, ADT7316_EX_TEMP_OFFSET, buf, len); @@ -1380,7 +1380,7 @@ static ssize_t adt7316_show_in_analog_temp_offset(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return adt7316_show_temp_offset(chip, @@ -1392,7 +1392,7 @@ static ssize_t adt7316_store_in_analog_temp_offset(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return adt7316_store_temp_offset(chip, @@ -1407,7 +1407,7 @@ static ssize_t adt7316_show_ex_analog_temp_offset(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return adt7316_show_temp_offset(chip, @@ -1419,7 +1419,7 @@ static ssize_t adt7316_store_ex_analog_temp_offset(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return adt7316_store_temp_offset(chip, @@ -1504,7 +1504,7 @@ static ssize_t adt7316_show_DAC_A(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return adt7316_show_DAC(chip, 0, buf); @@ -1515,7 +1515,7 @@ static ssize_t adt7316_store_DAC_A(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return adt7316_store_DAC(chip, 0, buf, len); @@ -1528,7 +1528,7 @@ static ssize_t adt7316_show_DAC_B(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return adt7316_show_DAC(chip, 1, buf); @@ -1539,7 +1539,7 @@ static ssize_t adt7316_store_DAC_B(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return adt7316_store_DAC(chip, 1, buf, len); @@ -1552,7 +1552,7 @@ static ssize_t adt7316_show_DAC_C(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return adt7316_show_DAC(chip, 2, buf); @@ -1563,7 +1563,7 @@ static ssize_t adt7316_store_DAC_C(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return adt7316_store_DAC(chip, 2, buf, len); @@ -1576,7 +1576,7 @@ static ssize_t adt7316_show_DAC_D(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return adt7316_show_DAC(chip, 3, buf); @@ -1587,7 +1587,7 @@ static ssize_t adt7316_store_DAC_D(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return adt7316_store_DAC(chip, 3, buf, len); @@ -1600,7 +1600,7 @@ static ssize_t adt7316_show_device_id(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 id; int ret; @@ -1618,7 +1618,7 @@ static ssize_t adt7316_show_manufactorer_id(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 id; int ret; @@ -1637,7 +1637,7 @@ static ssize_t adt7316_show_device_rev(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 rev; int ret; @@ -1655,7 +1655,7 @@ static ssize_t adt7316_show_bus_type(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 stat; int ret; @@ -1841,7 +1841,7 @@ static ssize_t adt7316_show_int_mask(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return sprintf(buf, "0x%x\n", chip->int_mask); @@ -1855,7 +1855,7 @@ static ssize_t adt7316_set_int_mask(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); unsigned long data; int ret; @@ -1895,7 +1895,7 @@ static inline ssize_t adt7316_show_ad_bound(struct device *dev, char *buf) { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 val; int data; @@ -1926,7 +1926,7 @@ static inline ssize_t adt7316_set_ad_bound(struct device *dev, size_t len) { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); long data; u8 val; @@ -1965,7 +1965,7 @@ static ssize_t adt7316_show_int_enabled(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); return sprintf(buf, "%d\n", !!(chip->config1 & ADT7316_INT_EN)); @@ -1976,7 +1976,7 @@ static ssize_t adt7316_set_int_enabled(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); u8 config1; int ret; @@ -2133,7 +2133,7 @@ int __devinit adt7316_probe(struct device *dev, struct adt7316_bus *bus, unsigned short *adt7316_platform_data = dev->platform_data; int ret = 0; - indio_dev = iio_allocate_device(sizeof(*chip)); + indio_dev = iio_device_alloc(sizeof(*chip)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -2210,7 +2210,7 @@ int __devinit adt7316_probe(struct device *dev, struct adt7316_bus *bus, error_unreg_irq: free_irq(chip->bus.irq, indio_dev); error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; } @@ -2224,7 +2224,7 @@ int __devexit adt7316_remove(struct device *dev) iio_device_unregister(indio_dev); if (chip->bus.irq) free_irq(chip->bus.irq, indio_dev); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/cdc/ad7150.c b/trunk/drivers/staging/iio/cdc/ad7150.c index e4a08dc9b6f5..a16d1a22db0a 100644 --- a/trunk/drivers/staging/iio/cdc/ad7150.c +++ b/trunk/drivers/staging/iio/cdc/ad7150.c @@ -13,9 +13,9 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../events.h" +#include +#include +#include /* * AD7150 registers definition */ @@ -104,7 +104,7 @@ static int ad7150_read_raw(struct iio_dev *indio_dev, struct ad7150_chip_info *chip = iio_priv(indio_dev); switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: ret = i2c_smbus_read_word_data(chip->client, ad7150_addresses[chan->channel][0]); if (ret < 0) @@ -341,7 +341,7 @@ static ssize_t ad7150_show_timeout(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7150_chip_info *chip = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); u8 value; @@ -370,7 +370,7 @@ static ssize_t ad7150_store_timeout(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7150_chip_info *chip = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int chan = IIO_EVENT_CODE_EXTRACT_CHAN(this_attr->address); @@ -429,7 +429,8 @@ static const struct iio_chan_spec ad7150_channels[] = { .type = IIO_CAPACITANCE, .indexed = 1, .channel = 0, - .info_mask = IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT, .event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING) | @@ -441,7 +442,8 @@ static const struct iio_chan_spec ad7150_channels[] = { .type = IIO_CAPACITANCE, .indexed = 1, .channel = 1, - .info_mask = IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT, .event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING) | @@ -556,7 +558,7 @@ static int __devinit ad7150_probe(struct i2c_client *client, struct ad7150_chip_info *chip; struct iio_dev *indio_dev; - indio_dev = iio_allocate_device(sizeof(*chip)); + indio_dev = iio_device_alloc(sizeof(*chip)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -619,7 +621,7 @@ static int __devinit ad7150_probe(struct i2c_client *client, if (client->irq) free_irq(client->irq, indio_dev); error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; } @@ -635,7 +637,7 @@ static int __devexit ad7150_remove(struct i2c_client *client) if (client->dev.platform_data) free_irq(*(unsigned int *)client->dev.platform_data, indio_dev); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/cdc/ad7152.c b/trunk/drivers/staging/iio/cdc/ad7152.c index fdb83c35e6dd..98c3015116aa 100644 --- a/trunk/drivers/staging/iio/cdc/ad7152.c +++ b/trunk/drivers/staging/iio/cdc/ad7152.c @@ -15,8 +15,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include /* * TODO: Check compliance of calibbias with abi (units) @@ -97,7 +97,7 @@ static inline ssize_t ad7152_start_calib(struct device *dev, size_t len, u8 regval) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7152_chip_info *chip = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); bool doit; @@ -169,7 +169,7 @@ static ssize_t ad7152_show_filter_rate_setup(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7152_chip_info *chip = iio_priv(indio_dev); return sprintf(buf, "%d\n", @@ -181,7 +181,7 @@ static ssize_t ad7152_store_filter_rate_setup(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7152_chip_info *chip = iio_priv(indio_dev); u8 data; int ret, i; @@ -329,7 +329,7 @@ static int ad7152_read_raw(struct iio_dev *indio_dev, mutex_lock(&indio_dev->mlock); switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: /* First set whether in differential mode */ regval = chip->setup[chan->channel]; @@ -436,7 +436,8 @@ static const struct iio_chan_spec ad7152_channels[] = { .type = IIO_CAPACITANCE, .indexed = 1, .channel = 0, - .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, }, { @@ -445,14 +446,16 @@ static const struct iio_chan_spec ad7152_channels[] = { .indexed = 1, .channel = 0, .channel2 = 2, - .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, }, { .type = IIO_CAPACITANCE, .indexed = 1, .channel = 1, - .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, }, { @@ -461,7 +464,8 @@ static const struct iio_chan_spec ad7152_channels[] = { .indexed = 1, .channel = 1, .channel2 = 3, - .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, } @@ -477,7 +481,7 @@ static int __devinit ad7152_probe(struct i2c_client *client, struct ad7152_chip_info *chip; struct iio_dev *indio_dev; - indio_dev = iio_allocate_device(sizeof(*chip)); + indio_dev = iio_device_alloc(sizeof(*chip)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -509,7 +513,7 @@ static int __devinit ad7152_probe(struct i2c_client *client, return 0; error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; } @@ -519,7 +523,7 @@ static int __devexit ad7152_remove(struct i2c_client *client) struct iio_dev *indio_dev = i2c_get_clientdata(client); iio_device_unregister(indio_dev); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/cdc/ad7746.c b/trunk/drivers/staging/iio/cdc/ad7746.c index 40b8512cbc32..754e11e87193 100644 --- a/trunk/drivers/staging/iio/cdc/ad7746.c +++ b/trunk/drivers/staging/iio/cdc/ad7746.c @@ -16,8 +16,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #include "ad7746.h" @@ -123,7 +123,8 @@ static const struct iio_chan_spec ad7746_channels[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 0, - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, .address = AD7746_REG_VT_DATA_HIGH << 8 | AD7746_VTSETUP_VTMD_EXT_VIN, }, @@ -132,7 +133,8 @@ static const struct iio_chan_spec ad7746_channels[] = { .indexed = 1, .channel = 1, .extend_name = "supply", - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, .address = AD7746_REG_VT_DATA_HIGH << 8 | AD7746_VTSETUP_VTMD_VDD_MON, }, @@ -140,7 +142,7 @@ static const struct iio_chan_spec ad7746_channels[] = { .type = IIO_TEMP, .indexed = 1, .channel = 0, - .processed_val = IIO_PROCESSED, + .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT, .address = AD7746_REG_VT_DATA_HIGH << 8 | AD7746_VTSETUP_VTMD_INT_TEMP, }, @@ -148,7 +150,7 @@ static const struct iio_chan_spec ad7746_channels[] = { .type = IIO_TEMP, .indexed = 1, .channel = 1, - .processed_val = IIO_PROCESSED, + .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT, .address = AD7746_REG_VT_DATA_HIGH << 8 | AD7746_VTSETUP_VTMD_EXT_TEMP, }, @@ -156,7 +158,8 @@ static const struct iio_chan_spec ad7746_channels[] = { .type = IIO_CAPACITANCE, .indexed = 1, .channel = 0, - .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT | IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT, @@ -168,7 +171,8 @@ static const struct iio_chan_spec ad7746_channels[] = { .indexed = 1, .channel = 0, .channel2 = 2, - .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT | IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT, @@ -179,7 +183,8 @@ static const struct iio_chan_spec ad7746_channels[] = { .type = IIO_CAPACITANCE, .indexed = 1, .channel = 1, - .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT | IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT, @@ -192,7 +197,8 @@ static const struct iio_chan_spec ad7746_channels[] = { .indexed = 1, .channel = 1, .channel2 = 3, - .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT | IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT, @@ -280,7 +286,7 @@ static inline ssize_t ad7746_start_calib(struct device *dev, size_t len, u8 regval) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7746_chip_info *chip = iio_priv(indio_dev); bool doit; int ret, timeout = 10; @@ -319,7 +325,7 @@ static ssize_t ad7746_start_offset_calib(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); int ret = ad7746_select_channel(indio_dev, &ad7746_channels[to_iio_dev_attr(attr)->address]); if (ret < 0) @@ -334,7 +340,7 @@ static ssize_t ad7746_start_gain_calib(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); int ret = ad7746_select_channel(indio_dev, &ad7746_channels[to_iio_dev_attr(attr)->address]); if (ret < 0) @@ -359,7 +365,7 @@ static ssize_t ad7746_show_cap_filter_rate_setup(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7746_chip_info *chip = iio_priv(indio_dev); return sprintf(buf, "%d\n", ad7746_cap_filter_rate_table[ @@ -371,7 +377,7 @@ static ssize_t ad7746_store_cap_filter_rate_setup(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7746_chip_info *chip = iio_priv(indio_dev); u8 data; int ret, i; @@ -399,7 +405,7 @@ static ssize_t ad7746_show_vt_filter_rate_setup(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7746_chip_info *chip = iio_priv(indio_dev); return sprintf(buf, "%d\n", ad7746_vt_filter_rate_table[ @@ -411,7 +417,7 @@ static ssize_t ad7746_store_vt_filter_rate_setup(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7746_chip_info *chip = iio_priv(indio_dev); u8 data; int ret, i; @@ -572,7 +578,8 @@ static int ad7746_read_raw(struct iio_dev *indio_dev, mutex_lock(&indio_dev->mlock); switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: + case IIO_CHAN_INFO_PROCESSED: ret = ad7746_select_channel(indio_dev, chan); if (ret < 0) goto out; @@ -696,7 +703,7 @@ static int __devinit ad7746_probe(struct i2c_client *client, int ret = 0; unsigned char regval = 0; - indio_dev = iio_allocate_device(sizeof(*chip)); + indio_dev = iio_device_alloc(sizeof(*chip)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -756,7 +763,7 @@ static int __devinit ad7746_probe(struct i2c_client *client, return 0; error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; } @@ -766,7 +773,7 @@ static int __devexit ad7746_remove(struct i2c_client *client) struct iio_dev *indio_dev = i2c_get_clientdata(client); iio_device_unregister(indio_dev); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/dac/Kconfig b/trunk/drivers/staging/iio/dac/Kconfig index a57803a5d1a7..a626f03871ec 100644 --- a/trunk/drivers/staging/iio/dac/Kconfig +++ b/trunk/drivers/staging/iio/dac/Kconfig @@ -56,12 +56,12 @@ config AD5624R_SPI AD5664R converters (DAC). This driver uses the common SPI interface. config AD5446 - tristate "Analog Devices AD5444/6, AD5620/40/60 and AD5542A/12A DAC SPI driver" + tristate "Analog Devices AD5446 and similar single channel DACs driver" depends on SPI help Say yes here to build support for Analog Devices AD5444, AD5446, - AD5512A, AD5542A, AD5543, AD5553, AD5601, AD5611, AD5620, AD5621, - AD5640, AD5660, AD5662 DACs. + AD5512A, AD5541A, AD5542A, AD5543, AD5553, AD5601, AD5611, AD5620, + AD5621, AD5640, AD5660, AD5662 DACs. To compile this driver as a module, choose M here: the module will be called ad5446. diff --git a/trunk/drivers/staging/iio/dac/ad5064.c b/trunk/drivers/staging/iio/dac/ad5064.c index 06b162745a3e..047148aa66b2 100644 --- a/trunk/drivers/staging/iio/dac/ad5064.c +++ b/trunk/drivers/staging/iio/dac/ad5064.c @@ -16,8 +16,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #include "dac.h" #define AD5064_MAX_DAC_CHANNELS 8 @@ -144,14 +144,14 @@ static const char ad5064_powerdown_modes[][15] = { }; static ssize_t ad5064_read_powerdown_mode_available(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, char *buf) + uintptr_t private, const struct iio_chan_spec *chan, char *buf) { return sprintf(buf, "%s %s %s\n", ad5064_powerdown_modes[1], ad5064_powerdown_modes[2], ad5064_powerdown_modes[3]); } static ssize_t ad5064_read_powerdown_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, char *buf) + uintptr_t private, const struct iio_chan_spec *chan, char *buf) { struct ad5064_state *st = iio_priv(indio_dev); @@ -160,7 +160,8 @@ static ssize_t ad5064_read_powerdown_mode(struct iio_dev *indio_dev, } static ssize_t ad5064_write_powerdown_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, const char *buf, size_t len) + uintptr_t private, const struct iio_chan_spec *chan, const char *buf, + size_t len) { struct ad5064_state *st = iio_priv(indio_dev); unsigned int mode, i; @@ -187,7 +188,7 @@ static ssize_t ad5064_write_powerdown_mode(struct iio_dev *indio_dev, } static ssize_t ad5064_read_dac_powerdown(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, char *buf) + uintptr_t private, const struct iio_chan_spec *chan, char *buf) { struct ad5064_state *st = iio_priv(indio_dev); @@ -195,7 +196,8 @@ static ssize_t ad5064_read_dac_powerdown(struct iio_dev *indio_dev, } static ssize_t ad5064_write_dac_powerdown(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, const char *buf, size_t len) + uintptr_t private, const struct iio_chan_spec *chan, const char *buf, + size_t len) { struct ad5064_state *st = iio_priv(indio_dev); bool pwr_down; @@ -235,7 +237,7 @@ static int ad5064_read_raw(struct iio_dev *indio_dev, int scale_uv; switch (m) { - case 0: + case IIO_CHAN_INFO_RAW: *val = st->dac_cache[chan->channel]; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: @@ -260,7 +262,7 @@ static int ad5064_write_raw(struct iio_dev *indio_dev, int ret; switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: if (val > (1 << chan->scan_type.realbits) || val < 0) return -EINVAL; @@ -308,7 +310,8 @@ static struct iio_chan_spec_ext_info ad5064_ext_info[] = { .indexed = 1, \ .output = 1, \ .channel = (chan), \ - .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ .address = AD5064_ADDR_DAC(chan), \ .scan_type = IIO_ST('u', (bits), 16, 20 - (bits)), \ .ext_info = ad5064_ext_info, \ @@ -442,7 +445,7 @@ static int __devinit ad5064_probe(struct spi_device *spi) unsigned int i; int ret; - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -499,7 +502,7 @@ static int __devinit ad5064_probe(struct spi_device *spi) if (!st->use_internal_vref) regulator_bulk_free(ad5064_num_vref(st), st->vref_reg); error_free: - iio_free_device(indio_dev); + iio_device_free(indio_dev); return ret; } @@ -517,7 +520,7 @@ static int __devexit ad5064_remove(struct spi_device *spi) regulator_bulk_free(ad5064_num_vref(st), st->vref_reg); } - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/dac/ad5360.c b/trunk/drivers/staging/iio/dac/ad5360.c index cec3693b50a3..38660efca78a 100644 --- a/trunk/drivers/staging/iio/dac/ad5360.c +++ b/trunk/drivers/staging/iio/dac/ad5360.c @@ -16,8 +16,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #include "dac.h" #define AD5360_CMD(x) ((x) << 22) @@ -103,7 +103,8 @@ enum ad5360_type { .type = IIO_VOLTAGE, \ .indexed = 1, \ .output = 1, \ - .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, \ @@ -250,7 +251,7 @@ static ssize_t ad5360_read_dac_powerdown(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5360_state *st = iio_priv(indio_dev); return sprintf(buf, "%d\n", (bool)(st->ctrl & AD5360_SF_CTRL_PWR_DOWN)); @@ -278,7 +279,7 @@ static int ad5360_update_ctrl(struct iio_dev *indio_dev, unsigned int set, static ssize_t ad5360_write_dac_powerdown(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); bool pwr_down; int ret; @@ -319,7 +320,7 @@ static int ad5360_write_raw(struct iio_dev *indio_dev, unsigned int ofs_index; switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: if (val >= max_val || val < 0) return -EINVAL; @@ -376,7 +377,7 @@ static int ad5360_read_raw(struct iio_dev *indio_dev, int ret; switch (m) { - case 0: + case IIO_CHAN_INFO_RAW: ret = ad5360_read(indio_dev, AD5360_READBACK_X1A, chan->address); if (ret < 0) @@ -464,7 +465,7 @@ static int __devinit ad5360_probe(struct spi_device *spi) unsigned int i; int ret; - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { dev_err(&spi->dev, "Failed to allocate iio device\n"); return -ENOMEM; @@ -519,7 +520,7 @@ static int __devinit ad5360_probe(struct spi_device *spi) error_free_channels: kfree(indio_dev->channels); error_free: - iio_free_device(indio_dev); + iio_device_free(indio_dev); return ret; } @@ -536,7 +537,7 @@ static int __devexit ad5360_remove(struct spi_device *spi) regulator_bulk_disable(st->chip_info->num_vrefs, st->vref_reg); regulator_bulk_free(st->chip_info->num_vrefs, st->vref_reg); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/dac/ad5380.c b/trunk/drivers/staging/iio/dac/ad5380.c index 4c50716fa801..370d2842190e 100644 --- a/trunk/drivers/staging/iio/dac/ad5380.c +++ b/trunk/drivers/staging/iio/dac/ad5380.c @@ -18,8 +18,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #include "dac.h" @@ -85,7 +85,8 @@ enum ad5380_type { .type = IIO_VOLTAGE, \ .indexed = 1, \ .output = 1, \ - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT | \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SHARED_BIT | \ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, \ .scan_type = IIO_ST('u', (_bits), 16, 14 - (_bits)) \ @@ -167,7 +168,7 @@ static const struct ad5380_chip_info ad5380_chip_info_tbl[] = { static ssize_t ad5380_read_dac_powerdown(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5380_state *st = iio_priv(indio_dev); return sprintf(buf, "%d\n", st->pwr_down); @@ -176,7 +177,7 @@ static ssize_t ad5380_read_dac_powerdown(struct device *dev, static ssize_t ad5380_write_dac_powerdown(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5380_state *st = iio_priv(indio_dev); bool pwr_down; int ret; @@ -212,7 +213,7 @@ static const char ad5380_powerdown_modes[][15] = { static ssize_t ad5380_read_powerdown_mode(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5380_state *st = iio_priv(indio_dev); unsigned int mode; int ret; @@ -229,7 +230,7 @@ static ssize_t ad5380_read_powerdown_mode(struct device *dev, static ssize_t ad5380_write_powerdown_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5380_state *st = iio_priv(indio_dev); unsigned int i; int ret; @@ -292,7 +293,7 @@ static int ad5380_write_raw(struct iio_dev *indio_dev, struct ad5380_state *st = iio_priv(indio_dev); switch (info) { - case 0: + case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_CALIBSCALE: if (val >= max_val || val < 0) return -EINVAL; @@ -322,7 +323,7 @@ static int ad5380_read_raw(struct iio_dev *indio_dev, int ret; switch (info) { - case 0: + case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_CALIBSCALE: ret = regmap_read(st->regmap, ad5380_info_to_reg(chan, info), val); @@ -388,7 +389,7 @@ static int __devinit ad5380_probe(struct device *dev, struct regmap *regmap, unsigned int ctrl = 0; int ret; - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { dev_err(dev, "Failed to allocate iio device\n"); ret = -ENOMEM; @@ -454,7 +455,7 @@ static int __devinit ad5380_probe(struct device *dev, struct regmap *regmap, kfree(indio_dev->channels); error_free: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_regmap_exit: regmap_exit(regmap); @@ -476,7 +477,7 @@ static int __devexit ad5380_remove(struct device *dev) } regmap_exit(st->regmap); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/dac/ad5421.c b/trunk/drivers/staging/iio/dac/ad5421.c index 0b040b204697..ffbd4c234f57 100644 --- a/trunk/drivers/staging/iio/dac/ad5421.c +++ b/trunk/drivers/staging/iio/dac/ad5421.c @@ -16,9 +16,9 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../events.h" +#include +#include +#include #include "dac.h" #include "ad5421.h" @@ -87,7 +87,8 @@ static const struct iio_chan_spec ad5421_channels[] = { .indexed = 1, .output = 1, .channel = 0, - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_OFFSET_SHARED_BIT | IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, @@ -304,7 +305,7 @@ static int ad5421_read_raw(struct iio_dev *indio_dev, return -EINVAL; switch (m) { - case 0: + case IIO_CHAN_INFO_RAW: ret = ad5421_read(indio_dev, AD5421_REG_DAC_DATA); if (ret < 0) return ret; @@ -340,7 +341,7 @@ static int ad5421_write_raw(struct iio_dev *indio_dev, const unsigned int max_val = 1 << 16; switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: if (val >= max_val || val < 0) return -EINVAL; @@ -456,7 +457,7 @@ static int __devinit ad5421_probe(struct spi_device *spi) struct ad5421_state *st; int ret; - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { dev_err(&spi->dev, "Failed to allocate iio device\n"); return -ENOMEM; @@ -511,7 +512,7 @@ static int __devinit ad5421_probe(struct spi_device *spi) if (spi->irq) free_irq(spi->irq, indio_dev); error_free: - iio_free_device(indio_dev); + iio_device_free(indio_dev); return ret; } @@ -523,7 +524,7 @@ static int __devexit ad5421_remove(struct spi_device *spi) iio_device_unregister(indio_dev); if (spi->irq) free_irq(spi->irq, indio_dev); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/dac/ad5446.c b/trunk/drivers/staging/iio/dac/ad5446.c index 633ffbb21814..daa65b384c13 100644 --- a/trunk/drivers/staging/iio/dac/ad5446.c +++ b/trunk/drivers/staging/iio/dac/ad5446.c @@ -18,229 +18,212 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #include "dac.h" #include "ad5446.h" -static void ad5446_store_sample(struct ad5446_state *st, unsigned val) +static int ad5446_write(struct ad5446_state *st, unsigned val) { - st->data.d16 = cpu_to_be16(AD5446_LOAD | val); + __be16 data = cpu_to_be16(val); + return spi_write(st->spi, &data, sizeof(data)); } -static void ad5542_store_sample(struct ad5446_state *st, unsigned val) +static int ad5660_write(struct ad5446_state *st, unsigned val) { - st->data.d16 = cpu_to_be16(val); -} + uint8_t data[3]; -static void ad5620_store_sample(struct ad5446_state *st, unsigned val) -{ - st->data.d16 = cpu_to_be16(AD5620_LOAD | val); -} + data[0] = (val >> 16) & 0xFF; + data[1] = (val >> 8) & 0xFF; + data[2] = val & 0xFF; -static void ad5660_store_sample(struct ad5446_state *st, unsigned val) -{ - val |= AD5660_LOAD; - st->data.d24[0] = (val >> 16) & 0xFF; - st->data.d24[1] = (val >> 8) & 0xFF; - st->data.d24[2] = val & 0xFF; + return spi_write(st->spi, data, sizeof(data)); } -static void ad5620_store_pwr_down(struct ad5446_state *st, unsigned mode) -{ - st->data.d16 = cpu_to_be16(mode << 14); -} +static const char * const ad5446_powerdown_modes[] = { + "", "1kohm_to_gnd", "100kohm_to_gnd", "three_state" +}; -static void ad5660_store_pwr_down(struct ad5446_state *st, unsigned mode) +static ssize_t ad5446_read_powerdown_mode_available(struct iio_dev *indio_dev, + uintptr_t private, const struct iio_chan_spec *chan, char *buf) { - unsigned val = mode << 16; - - st->data.d24[0] = (val >> 16) & 0xFF; - st->data.d24[1] = (val >> 8) & 0xFF; - st->data.d24[2] = val & 0xFF; + return sprintf(buf, "%s %s %s\n", ad5446_powerdown_modes[1], + ad5446_powerdown_modes[2], ad5446_powerdown_modes[3]); } -static ssize_t ad5446_write_powerdown_mode(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) +static ssize_t ad5446_write_powerdown_mode(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad5446_state *st = iio_priv(indio_dev); + int i; - if (sysfs_streq(buf, "1kohm_to_gnd")) - st->pwr_down_mode = MODE_PWRDWN_1k; - else if (sysfs_streq(buf, "100kohm_to_gnd")) - st->pwr_down_mode = MODE_PWRDWN_100k; - else if (sysfs_streq(buf, "three_state")) - st->pwr_down_mode = MODE_PWRDWN_TRISTATE; - else + for (i = 1; i < ARRAY_SIZE(ad5446_powerdown_modes); i++) { + if (sysfs_streq(buf, ad5446_powerdown_modes[i])) { + st->pwr_down_mode = i; + break; + } + } + + if (i == ARRAY_SIZE(ad5446_powerdown_modes)) return -EINVAL; return len; } -static ssize_t ad5446_read_powerdown_mode(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t ad5446_read_powerdown_mode(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad5446_state *st = iio_priv(indio_dev); - char mode[][15] = {"", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"}; - - return sprintf(buf, "%s\n", mode[st->pwr_down_mode]); + return sprintf(buf, "%s\n", ad5446_powerdown_modes[st->pwr_down_mode]); } -static ssize_t ad5446_read_dac_powerdown(struct device *dev, - struct device_attribute *attr, +static ssize_t ad5446_read_dac_powerdown(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad5446_state *st = iio_priv(indio_dev); return sprintf(buf, "%d\n", st->pwr_down); } -static ssize_t ad5446_write_dac_powerdown(struct device *dev, - struct device_attribute *attr, +static ssize_t ad5446_write_dac_powerdown(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad5446_state *st = iio_priv(indio_dev); - unsigned long readin; + unsigned int shift; + unsigned int val; + bool powerdown; int ret; - ret = strict_strtol(buf, 10, &readin); + ret = strtobool(buf, &powerdown); if (ret) return ret; - if (readin > 1) - ret = -EINVAL; - mutex_lock(&indio_dev->mlock); - st->pwr_down = readin; + st->pwr_down = powerdown; - if (st->pwr_down) - st->chip_info->store_pwr_down(st, st->pwr_down_mode); - else - st->chip_info->store_sample(st, st->cached_val); + if (st->pwr_down) { + shift = chan->scan_type.realbits + chan->scan_type.shift; + val = st->pwr_down_mode << shift; + } else { + val = st->cached_val; + } - ret = spi_sync(st->spi, &st->msg); + ret = st->chip_info->write(st, val); mutex_unlock(&indio_dev->mlock); return ret ? ret : len; } -static IIO_DEVICE_ATTR(out_voltage_powerdown_mode, S_IRUGO | S_IWUSR, - ad5446_read_powerdown_mode, - ad5446_write_powerdown_mode, 0); - -static IIO_CONST_ATTR(out_voltage_powerdown_mode_available, - "1kohm_to_gnd 100kohm_to_gnd three_state"); - -static IIO_DEVICE_ATTR(out_voltage0_powerdown, S_IRUGO | S_IWUSR, - ad5446_read_dac_powerdown, - ad5446_write_dac_powerdown, 0); - -static struct attribute *ad5446_attributes[] = { - &iio_dev_attr_out_voltage0_powerdown.dev_attr.attr, - &iio_dev_attr_out_voltage_powerdown_mode.dev_attr.attr, - &iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr, - NULL, -}; - -static const struct attribute_group ad5446_attribute_group = { - .attrs = ad5446_attributes, +static const struct iio_chan_spec_ext_info ad5064_ext_info_powerdown[] = { + { + .name = "powerdown", + .read = ad5446_read_dac_powerdown, + .write = ad5446_write_dac_powerdown, + }, { + .name = "powerdown_mode", + .read = ad5446_read_powerdown_mode, + .write = ad5446_write_powerdown_mode, + }, { + .name = "powerdown_mode_available", + .shared = true, + .read = ad5446_read_powerdown_mode_available, + }, + { }, }; -#define AD5446_CHANNEL(bits, storage, shift) { \ +#define _AD5446_CHANNEL(bits, storage, shift, ext) { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ .output = 1, \ .channel = 0, \ - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \ - .scan_type = IIO_ST('u', (bits), (storage), (shift)) \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SHARED_BIT, \ + .scan_type = IIO_ST('u', (bits), (storage), (shift)), \ + .ext_info = (ext), \ } +#define AD5446_CHANNEL(bits, storage, shift) \ + _AD5446_CHANNEL(bits, storage, shift, NULL) + +#define AD5446_CHANNEL_POWERDOWN(bits, storage, shift) \ + _AD5446_CHANNEL(bits, storage, shift, ad5064_ext_info_powerdown) + static const struct ad5446_chip_info ad5446_chip_info_tbl[] = { [ID_AD5444] = { .channel = AD5446_CHANNEL(12, 16, 2), - .store_sample = ad5446_store_sample, + .write = ad5446_write, }, [ID_AD5446] = { .channel = AD5446_CHANNEL(14, 16, 0), - .store_sample = ad5446_store_sample, + .write = ad5446_write, }, [ID_AD5541A] = { .channel = AD5446_CHANNEL(16, 16, 0), - .store_sample = ad5542_store_sample, - }, - [ID_AD5542A] = { - .channel = AD5446_CHANNEL(16, 16, 0), - .store_sample = ad5542_store_sample, - }, - [ID_AD5543] = { - .channel = AD5446_CHANNEL(16, 16, 0), - .store_sample = ad5542_store_sample, + .write = ad5446_write, }, [ID_AD5512A] = { .channel = AD5446_CHANNEL(12, 16, 4), - .store_sample = ad5542_store_sample, + .write = ad5446_write, }, [ID_AD5553] = { .channel = AD5446_CHANNEL(14, 16, 0), - .store_sample = ad5542_store_sample, + .write = ad5446_write, }, [ID_AD5601] = { - .channel = AD5446_CHANNEL(8, 16, 6), - .store_sample = ad5542_store_sample, - .store_pwr_down = ad5620_store_pwr_down, + .channel = AD5446_CHANNEL_POWERDOWN(8, 16, 6), + .write = ad5446_write, }, [ID_AD5611] = { - .channel = AD5446_CHANNEL(10, 16, 4), - .store_sample = ad5542_store_sample, - .store_pwr_down = ad5620_store_pwr_down, + .channel = AD5446_CHANNEL_POWERDOWN(10, 16, 4), + .write = ad5446_write, }, [ID_AD5621] = { - .channel = AD5446_CHANNEL(12, 16, 2), - .store_sample = ad5542_store_sample, - .store_pwr_down = ad5620_store_pwr_down, + .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2), + .write = ad5446_write, }, [ID_AD5620_2500] = { - .channel = AD5446_CHANNEL(12, 16, 2), + .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2), .int_vref_mv = 2500, - .store_sample = ad5620_store_sample, - .store_pwr_down = ad5620_store_pwr_down, + .write = ad5446_write, }, [ID_AD5620_1250] = { - .channel = AD5446_CHANNEL(12, 16, 2), + .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2), .int_vref_mv = 1250, - .store_sample = ad5620_store_sample, - .store_pwr_down = ad5620_store_pwr_down, + .write = ad5446_write, }, [ID_AD5640_2500] = { - .channel = AD5446_CHANNEL(14, 16, 0), + .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0), .int_vref_mv = 2500, - .store_sample = ad5620_store_sample, - .store_pwr_down = ad5620_store_pwr_down, + .write = ad5446_write, }, [ID_AD5640_1250] = { - .channel = AD5446_CHANNEL(14, 16, 0), + .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0), .int_vref_mv = 1250, - .store_sample = ad5620_store_sample, - .store_pwr_down = ad5620_store_pwr_down, + .write = ad5446_write, }, [ID_AD5660_2500] = { - .channel = AD5446_CHANNEL(16, 16, 0), + .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0), .int_vref_mv = 2500, - .store_sample = ad5660_store_sample, - .store_pwr_down = ad5660_store_pwr_down, + .write = ad5660_write, }, [ID_AD5660_1250] = { - .channel = AD5446_CHANNEL(16, 16, 0), + .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0), .int_vref_mv = 1250, - .store_sample = ad5660_store_sample, - .store_pwr_down = ad5660_store_pwr_down, + .write = ad5660_write, + }, + [ID_AD5662] = { + .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0), + .write = ad5660_write, }, }; @@ -254,6 +237,9 @@ static int ad5446_read_raw(struct iio_dev *indio_dev, unsigned long scale_uv; switch (m) { + case IIO_CHAN_INFO_RAW: + *val = st->cached_val; + return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: scale_uv = (st->vref_mv * 1000) >> chan->scan_type.realbits; *val = scale_uv / 1000; @@ -271,18 +257,18 @@ static int ad5446_write_raw(struct iio_dev *indio_dev, long mask) { struct ad5446_state *st = iio_priv(indio_dev); - int ret; + int ret = 0; switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: if (val >= (1 << chan->scan_type.realbits) || val < 0) return -EINVAL; val <<= chan->scan_type.shift; mutex_lock(&indio_dev->mlock); st->cached_val = val; - st->chip_info->store_sample(st, val); - ret = spi_sync(st->spi, &st->msg); + if (!st->pwr_down) + ret = st->chip_info->write(st, val); mutex_unlock(&indio_dev->mlock); break; default: @@ -293,13 +279,6 @@ static int ad5446_write_raw(struct iio_dev *indio_dev, } static const struct iio_info ad5446_info = { - .read_raw = ad5446_read_raw, - .write_raw = ad5446_write_raw, - .attrs = &ad5446_attribute_group, - .driver_module = THIS_MODULE, -}; - -static const struct iio_info ad5446_info_no_pwr_down = { .read_raw = ad5446_read_raw, .write_raw = ad5446_write_raw, .driver_module = THIS_MODULE, @@ -321,7 +300,7 @@ static int __devinit ad5446_probe(struct spi_device *spi) voltage_uv = regulator_get_voltage(reg); } - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_disable_reg; @@ -337,38 +316,17 @@ static int __devinit ad5446_probe(struct spi_device *spi) /* Establish that the iio_dev is a child of the spi device */ indio_dev->dev.parent = &spi->dev; indio_dev->name = spi_get_device_id(spi)->name; - if (st->chip_info->store_pwr_down) - indio_dev->info = &ad5446_info; - else - indio_dev->info = &ad5446_info_no_pwr_down; + indio_dev->info = &ad5446_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = &st->chip_info->channel; indio_dev->num_channels = 1; - /* Setup default message */ - - st->xfer.tx_buf = &st->data; - st->xfer.len = st->chip_info->channel.scan_type.storagebits / 8; - - spi_message_init(&st->msg); - spi_message_add_tail(&st->xfer, &st->msg); - - switch (spi_get_device_id(spi)->driver_data) { - case ID_AD5620_2500: - case ID_AD5620_1250: - case ID_AD5640_2500: - case ID_AD5640_1250: - case ID_AD5660_2500: - case ID_AD5660_1250: + if (st->chip_info->int_vref_mv) st->vref_mv = st->chip_info->int_vref_mv; - break; - default: - if (voltage_uv) - st->vref_mv = voltage_uv / 1000; - else - dev_warn(&spi->dev, - "reference voltage unspecified\n"); - } + else if (voltage_uv) + st->vref_mv = voltage_uv / 1000; + else + dev_warn(&spi->dev, "reference voltage unspecified\n"); ret = iio_device_register(indio_dev); if (ret) @@ -377,7 +335,7 @@ static int __devinit ad5446_probe(struct spi_device *spi) return 0; error_free_device: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_disable_reg: if (!IS_ERR(reg)) regulator_disable(reg); @@ -398,7 +356,7 @@ static int ad5446_remove(struct spi_device *spi) regulator_disable(st->reg); regulator_put(st->reg); } - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } @@ -408,8 +366,8 @@ static const struct spi_device_id ad5446_id[] = { {"ad5446", ID_AD5446}, {"ad5512a", ID_AD5512A}, {"ad5541a", ID_AD5541A}, - {"ad5542a", ID_AD5542A}, - {"ad5543", ID_AD5543}, + {"ad5542a", ID_AD5541A}, /* ad5541a and ad5542a are compatible */ + {"ad5543", ID_AD5541A}, /* ad5541a and ad5543 are compatible */ {"ad5553", ID_AD5553}, {"ad5601", ID_AD5601}, {"ad5611", ID_AD5611}, @@ -420,6 +378,7 @@ static const struct spi_device_id ad5446_id[] = { {"ad5640-1250", ID_AD5640_1250}, {"ad5660-2500", ID_AD5660_2500}, {"ad5660-1250", ID_AD5660_1250}, + {"ad5662", ID_AD5662}, {} }; MODULE_DEVICE_TABLE(spi, ad5446_id); diff --git a/trunk/drivers/staging/iio/dac/ad5446.h b/trunk/drivers/staging/iio/dac/ad5446.h index 4ea3476fb065..dfd68ce7427e 100644 --- a/trunk/drivers/staging/iio/dac/ad5446.h +++ b/trunk/drivers/staging/iio/dac/ad5446.h @@ -34,43 +34,30 @@ * @spi: spi_device * @chip_info: chip model specific constants, available modes etc * @reg: supply regulator - * @poll_work: bottom half of polling interrupt handler * @vref_mv: actual reference voltage used - * @xfer: default spi transfer - * @msg: default spi message - * @data: spi transmit buffer */ struct ad5446_state { struct spi_device *spi; const struct ad5446_chip_info *chip_info; struct regulator *reg; - struct work_struct poll_work; unsigned short vref_mv; unsigned cached_val; unsigned pwr_down_mode; unsigned pwr_down; - struct spi_transfer xfer; - struct spi_message msg; - union { - unsigned short d16; - unsigned char d24[3]; - } data; }; /** * struct ad5446_chip_info - chip specific information * @channel: channel spec for the DAC * @int_vref_mv: AD5620/40/60: the internal reference voltage - * @store_sample: chip specific helper function to store the datum - * @store_sample: chip specific helper function to store the powerpown cmd + * @write: chip specific helper function to write to the register */ struct ad5446_chip_info { struct iio_chan_spec channel; u16 int_vref_mv; - void (*store_sample) (struct ad5446_state *st, unsigned val); - void (*store_pwr_down) (struct ad5446_state *st, unsigned mode); + int (*write)(struct ad5446_state *st, unsigned val); }; /** @@ -85,8 +72,6 @@ enum ad5446_supported_device_ids { ID_AD5444, ID_AD5446, ID_AD5541A, - ID_AD5542A, - ID_AD5543, ID_AD5512A, ID_AD5553, ID_AD5601, @@ -98,6 +83,7 @@ enum ad5446_supported_device_ids { ID_AD5640_1250, ID_AD5660_2500, ID_AD5660_1250, + ID_AD5662, }; #endif /* IIO_DAC_AD5446_H_ */ diff --git a/trunk/drivers/staging/iio/dac/ad5504.c b/trunk/drivers/staging/iio/dac/ad5504.c index bc17205fe722..019cf15cd24a 100644 --- a/trunk/drivers/staging/iio/dac/ad5504.c +++ b/trunk/drivers/staging/iio/dac/ad5504.c @@ -16,9 +16,9 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../events.h" +#include +#include +#include #include "dac.h" #include "ad5504.h" @@ -27,7 +27,8 @@ .indexed = 1, \ .output = 1, \ .channel = (_chan), \ - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SHARED_BIT, \ .address = AD5504_ADDR_DAC(_chan), \ .scan_type = IIO_ST('u', 12, 16, 0), \ } @@ -81,7 +82,7 @@ static int ad5504_read_raw(struct iio_dev *indio_dev, int ret; switch (m) { - case 0: + case IIO_CHAN_INFO_RAW: ret = ad5504_spi_read(st->spi, chan->address); if (ret < 0) return ret; @@ -109,7 +110,7 @@ static int ad5504_write_raw(struct iio_dev *indio_dev, int ret; switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: if (val >= (1 << chan->scan_type.realbits) || val < 0) return -EINVAL; @@ -124,7 +125,7 @@ static int ad5504_write_raw(struct iio_dev *indio_dev, static ssize_t ad5504_read_powerdown_mode(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5504_state *st = iio_priv(indio_dev); const char mode[][14] = {"20kohm_to_gnd", "three_state"}; @@ -136,7 +137,7 @@ static ssize_t ad5504_write_powerdown_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5504_state *st = iio_priv(indio_dev); int ret; @@ -154,7 +155,7 @@ static ssize_t ad5504_read_dac_powerdown(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5504_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); @@ -168,7 +169,7 @@ static ssize_t ad5504_write_dac_powerdown(struct device *dev, { long readin; int ret; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5504_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); @@ -287,7 +288,7 @@ static int __devinit ad5504_probe(struct spi_device *spi) struct regulator *reg; int ret, voltage_uv = 0; - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -350,7 +351,7 @@ static int __devinit ad5504_probe(struct spi_device *spi) if (!IS_ERR(reg)) regulator_put(reg); - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; } @@ -368,7 +369,7 @@ static int __devexit ad5504_remove(struct spi_device *spi) regulator_disable(st->reg); regulator_put(st->reg); } - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/dac/ad5624r_spi.c b/trunk/drivers/staging/iio/dac/ad5624r_spi.c index 10c7484366ef..42ff644ac43e 100644 --- a/trunk/drivers/staging/iio/dac/ad5624r_spi.c +++ b/trunk/drivers/staging/iio/dac/ad5624r_spi.c @@ -16,8 +16,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #include "dac.h" #include "ad5624r.h" @@ -26,7 +26,8 @@ .indexed = 1, \ .output = 1, \ .channel = (_chan), \ - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SHARED_BIT, \ .address = (_chan), \ .scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits)), \ } @@ -122,7 +123,7 @@ static int ad5624r_write_raw(struct iio_dev *indio_dev, int ret; switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: if (val >= (1 << chan->scan_type.realbits) || val < 0) return -EINVAL; @@ -140,7 +141,7 @@ static int ad5624r_write_raw(struct iio_dev *indio_dev, static ssize_t ad5624r_read_powerdown_mode(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5624r_state *st = iio_priv(indio_dev); char mode[][15] = {"", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"}; @@ -152,7 +153,7 @@ static ssize_t ad5624r_write_powerdown_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5624r_state *st = iio_priv(indio_dev); int ret; @@ -172,7 +173,7 @@ static ssize_t ad5624r_read_dac_powerdown(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5624r_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); @@ -186,7 +187,7 @@ static ssize_t ad5624r_write_dac_powerdown(struct device *dev, { long readin; int ret; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5624r_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); @@ -255,7 +256,7 @@ static int __devinit ad5624r_probe(struct spi_device *spi) struct iio_dev *indio_dev; int ret, voltage_uv = 0; - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -305,7 +306,7 @@ static int __devinit ad5624r_probe(struct spi_device *spi) error_put_reg: if (!IS_ERR(st->reg)) regulator_put(st->reg); - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; @@ -321,7 +322,7 @@ static int __devexit ad5624r_remove(struct spi_device *spi) regulator_disable(st->reg); regulator_put(st->reg); } - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/dac/ad5686.c b/trunk/drivers/staging/iio/dac/ad5686.c index 2415a6e60c77..c1e903ebc7b9 100644 --- a/trunk/drivers/staging/iio/dac/ad5686.c +++ b/trunk/drivers/staging/iio/dac/ad5686.c @@ -16,8 +16,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #include "dac.h" #define AD5686_DAC_CHANNELS 4 @@ -98,7 +98,8 @@ enum ad5686_supported_device_ids { .indexed = 1, \ .output = 1, \ .channel = chan, \ - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SHARED_BIT, \ .address = AD5686_ADDR_DAC(chan), \ .scan_type = IIO_ST('u', bits, 16, shift) \ } @@ -172,7 +173,7 @@ static int ad5686_spi_read(struct ad5686_state *st, u8 addr) static ssize_t ad5686_read_powerdown_mode(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5686_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); @@ -186,7 +187,7 @@ static ssize_t ad5686_write_powerdown_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5686_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); unsigned mode; @@ -210,7 +211,7 @@ static ssize_t ad5686_read_dac_powerdown(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5686_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); @@ -224,7 +225,7 @@ static ssize_t ad5686_write_dac_powerdown(struct device *dev, { bool readin; int ret; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5686_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); @@ -296,7 +297,7 @@ static int ad5686_read_raw(struct iio_dev *indio_dev, int ret; switch (m) { - case 0: + case IIO_CHAN_INFO_RAW: mutex_lock(&indio_dev->mlock); ret = ad5686_spi_read(st, chan->address); mutex_unlock(&indio_dev->mlock); @@ -326,7 +327,7 @@ static int ad5686_write_raw(struct iio_dev *indio_dev, int ret; switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: if (val > (1 << chan->scan_type.realbits) || val < 0) return -EINVAL; @@ -358,7 +359,7 @@ static int __devinit ad5686_probe(struct spi_device *spi) struct iio_dev *indio_dev; int ret, regdone = 0, voltage_uv = 0; - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -410,7 +411,7 @@ static int __devinit ad5686_probe(struct spi_device *spi) if (!IS_ERR(st->reg)) regulator_put(st->reg); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return ret; } @@ -425,7 +426,7 @@ static int __devexit ad5686_remove(struct spi_device *spi) regulator_disable(st->reg); regulator_put(st->reg); } - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/dac/ad5764.c b/trunk/drivers/staging/iio/dac/ad5764.c index f73a73079490..03dbd937b081 100644 --- a/trunk/drivers/staging/iio/dac/ad5764.c +++ b/trunk/drivers/staging/iio/dac/ad5764.c @@ -16,8 +16,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #include "dac.h" #define AD5764_REG_SF_NOP 0x0 @@ -79,7 +79,8 @@ enum ad5764_type { .output = 1, \ .channel = (_chan), \ .address = (_chan), \ - .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_OFFSET_SHARED_BIT | \ IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, \ @@ -188,7 +189,7 @@ static int ad5764_write_raw(struct iio_dev *indio_dev, unsigned int reg; switch (info) { - case 0: + case IIO_CHAN_INFO_RAW: if (val >= max_val || val < 0) return -EINVAL; val <<= chan->scan_type.shift; @@ -228,7 +229,7 @@ static int ad5764_read_raw(struct iio_dev *indio_dev, int ret; switch (info) { - case 0: + case IIO_CHAN_INFO_RAW: reg = AD5764_REG_DATA(chan->address); ret = ad5764_read(indio_dev, reg, val); if (ret < 0) @@ -280,7 +281,7 @@ static int __devinit ad5764_probe(struct spi_device *spi) struct ad5764_state *st; int ret; - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { dev_err(&spi->dev, "Failed to allocate iio device\n"); return -ENOMEM; @@ -335,7 +336,7 @@ static int __devinit ad5764_probe(struct spi_device *spi) if (st->chip_info->int_vref == 0) regulator_bulk_free(ARRAY_SIZE(st->vref_reg), st->vref_reg); error_free: - iio_free_device(indio_dev); + iio_device_free(indio_dev); return ret; } @@ -352,7 +353,7 @@ static int __devexit ad5764_remove(struct spi_device *spi) regulator_bulk_free(ARRAY_SIZE(st->vref_reg), st->vref_reg); } - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/dac/ad5791.c b/trunk/drivers/staging/iio/dac/ad5791.c index ac45636a8d72..13d8b5bb1cea 100644 --- a/trunk/drivers/staging/iio/dac/ad5791.c +++ b/trunk/drivers/staging/iio/dac/ad5791.c @@ -17,8 +17,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #include "dac.h" #include "ad5791.h" @@ -78,7 +78,8 @@ static int ad5791_spi_read(struct spi_device *spi, u8 addr, u32 *val) .indexed = 1, \ .address = AD5791_ADDR_DAC0, \ .channel = 0, \ - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT | \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SHARED_BIT | \ IIO_CHAN_INFO_OFFSET_SHARED_BIT, \ .scan_type = IIO_ST('u', bits, 24, shift) \ } @@ -93,7 +94,7 @@ static const struct iio_chan_spec ad5791_channels[] = { static ssize_t ad5791_read_powerdown_mode(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5791_state *st = iio_priv(indio_dev); const char mode[][14] = {"6kohm_to_gnd", "three_state"}; @@ -105,7 +106,7 @@ static ssize_t ad5791_write_powerdown_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5791_state *st = iio_priv(indio_dev); int ret; @@ -123,7 +124,7 @@ static ssize_t ad5791_read_dac_powerdown(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5791_state *st = iio_priv(indio_dev); return sprintf(buf, "%d\n", st->pwr_down); @@ -135,7 +136,7 @@ static ssize_t ad5791_write_dac_powerdown(struct device *dev, { long readin; int ret; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5791_state *st = iio_priv(indio_dev); ret = strict_strtol(buf, 10, &readin); @@ -231,7 +232,7 @@ static int ad5791_read_raw(struct iio_dev *indio_dev, int ret; switch (m) { - case 0: + case IIO_CHAN_INFO_RAW: ret = ad5791_spi_read(st->spi, chan->address, val); if (ret) return ret; @@ -263,7 +264,7 @@ static int ad5791_write_raw(struct iio_dev *indio_dev, struct ad5791_state *st = iio_priv(indio_dev); switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: val &= AD5791_RES_MASK(chan->scan_type.realbits); val <<= chan->scan_type.shift; @@ -288,7 +289,7 @@ static int __devinit ad5791_probe(struct spi_device *spi) struct ad5791_state *st; int ret, pos_voltage_uv = 0, neg_voltage_uv = 0; - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -368,7 +369,7 @@ static int __devinit ad5791_probe(struct spi_device *spi) error_put_reg_pos: if (!IS_ERR(st->reg_vdd)) regulator_put(st->reg_vdd); - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; @@ -389,7 +390,7 @@ static int __devexit ad5791_remove(struct spi_device *spi) regulator_disable(st->reg_vss); regulator_put(st->reg_vss); } - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/dac/max517.c b/trunk/drivers/staging/iio/dac/max517.c index 41483c72cec1..5287cad1f3a4 100644 --- a/trunk/drivers/staging/iio/dac/max517.c +++ b/trunk/drivers/staging/iio/dac/max517.c @@ -25,8 +25,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #include "dac.h" #include "max517.h" @@ -59,7 +59,7 @@ static ssize_t max517_set_value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count, int channel) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct max517_data *data = iio_priv(indio_dev); struct i2c_client *client = data->client; u8 outbuf[4]; /* 1x or 2x command + value */ @@ -128,7 +128,7 @@ static ssize_t max517_show_scale(struct device *dev, struct device_attribute *attr, char *buf, int channel) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct max517_data *data = iio_priv(indio_dev); /* Corresponds to Vref / 2^(bits) */ unsigned int scale_uv = (data->vref_mv[channel - 1] * 1000) >> 8; @@ -218,7 +218,7 @@ static int max517_probe(struct i2c_client *client, struct max517_platform_data *platform_data = client->dev.platform_data; int err; - indio_dev = iio_allocate_device(sizeof(*data)); + indio_dev = iio_device_alloc(sizeof(*data)); if (indio_dev == NULL) { err = -ENOMEM; goto exit; @@ -257,14 +257,15 @@ static int max517_probe(struct i2c_client *client, return 0; exit_free_device: - iio_free_device(indio_dev); + iio_device_free(indio_dev); exit: return err; } static int max517_remove(struct i2c_client *client) { - iio_free_device(i2c_get_clientdata(client)); + iio_device_unregister(i2c_get_clientdata(client)); + iio_device_free(i2c_get_clientdata(client)); return 0; } diff --git a/trunk/drivers/staging/iio/dds/dds.h b/trunk/drivers/staging/iio/dds/dds.h deleted file mode 100644 index d8ac3a93baf6..000000000000 --- a/trunk/drivers/staging/iio/dds/dds.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * dds.h - sysfs attributes associated with DDS devices - * - * Copyright (c) 2010 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -/** - * /sys/bus/iio/devices/.../ddsX_freqY - */ - -#define IIO_DEV_ATTR_FREQ(_channel, _num, _mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(dds##_channel##_freq##_num, \ - _mode, _show, _store, _addr) - -/** - * /sys/bus/iio/devices/.../ddsX_freqY_scale - */ - -#define IIO_CONST_ATTR_FREQ_SCALE(_channel, _string) \ - IIO_CONST_ATTR(dds##_channel##_freq_scale, _string) - -/** - * /sys/bus/iio/devices/.../ddsX_freqsymbol - */ - -#define IIO_DEV_ATTR_FREQSYMBOL(_channel, _mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(dds##_channel##_freqsymbol, \ - _mode, _show, _store, _addr); - -/** - * /sys/bus/iio/devices/.../ddsX_phaseY - */ - -#define IIO_DEV_ATTR_PHASE(_channel, _num, _mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(dds##_channel##_phase##_num, \ - _mode, _show, _store, _addr) - -/** - * /sys/bus/iio/devices/.../ddsX_phaseY_scale - */ - -#define IIO_CONST_ATTR_PHASE_SCALE(_channel, _string) \ - IIO_CONST_ATTR(dds##_channel##_phase_scale, _string) - -/** - * /sys/bus/iio/devices/.../ddsX_phasesymbol - */ - -#define IIO_DEV_ATTR_PHASESYMBOL(_channel, _mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(dds##_channel##_phasesymbol, \ - _mode, _show, _store, _addr); - -/** - * /sys/bus/iio/devices/.../ddsX_pincontrol_en - */ - -#define IIO_DEV_ATTR_PINCONTROL_EN(_channel, _mode, _show, _store, _addr)\ - IIO_DEVICE_ATTR(dds##_channel##_pincontrol_en, \ - _mode, _show, _store, _addr); - -/** - * /sys/bus/iio/devices/.../ddsX_pincontrol_freq_en - */ - -#define IIO_DEV_ATTR_PINCONTROL_FREQ_EN(_channel, _mode, _show, _store, _addr)\ - IIO_DEVICE_ATTR(dds##_channel##_pincontrol_freq_en, \ - _mode, _show, _store, _addr); - -/** - * /sys/bus/iio/devices/.../ddsX_pincontrol_phase_en - */ - -#define IIO_DEV_ATTR_PINCONTROL_PHASE_EN(_channel, _mode, _show, _store, _addr)\ - IIO_DEVICE_ATTR(dds##_channel##_pincontrol_phase_en, \ - _mode, _show, _store, _addr); - -/** - * /sys/bus/iio/devices/.../ddsX_out_enable - */ - -#define IIO_DEV_ATTR_OUT_ENABLE(_channel, _mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(dds##_channel##_out_enable, \ - _mode, _show, _store, _addr); - -/** - * /sys/bus/iio/devices/.../ddsX_outY_enable - */ - -#define IIO_DEV_ATTR_OUTY_ENABLE(_channel, _output, \ - _mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(dds##_channel##_out##_output##_enable, \ - _mode, _show, _store, _addr); - -/** - * /sys/bus/iio/devices/.../ddsX_outY_wavetype - */ - -#define IIO_DEV_ATTR_OUT_WAVETYPE(_channel, _output, _store, _addr) \ - IIO_DEVICE_ATTR(dds##_channel##_out##_output##_wavetype, \ - S_IWUSR, NULL, _store, _addr); - -/** - * /sys/bus/iio/devices/.../ddsX_outY_wavetype_available - */ - -#define IIO_CONST_ATTR_OUT_WAVETYPES_AVAILABLE(_channel, _output, _modes)\ - IIO_CONST_ATTR(dds##_channel##_out##_output##_wavetype_available,\ - _modes); diff --git a/trunk/drivers/staging/iio/dds/Kconfig b/trunk/drivers/staging/iio/frequency/Kconfig similarity index 100% rename from trunk/drivers/staging/iio/dds/Kconfig rename to trunk/drivers/staging/iio/frequency/Kconfig diff --git a/trunk/drivers/staging/iio/dds/Makefile b/trunk/drivers/staging/iio/frequency/Makefile similarity index 100% rename from trunk/drivers/staging/iio/dds/Makefile rename to trunk/drivers/staging/iio/frequency/Makefile diff --git a/trunk/drivers/staging/iio/dds/ad5930.c b/trunk/drivers/staging/iio/frequency/ad5930.c similarity index 94% rename from trunk/drivers/staging/iio/dds/ad5930.c rename to trunk/drivers/staging/iio/frequency/ad5930.c index 9c32d1beae25..2d541d0eebef 100644 --- a/trunk/drivers/staging/iio/dds/ad5930.c +++ b/trunk/drivers/staging/iio/frequency/ad5930.c @@ -16,8 +16,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #define DRV_NAME "ad5930" @@ -48,7 +48,7 @@ static ssize_t ad5930_set_parameter(struct device *dev, struct spi_transfer xfer; int ret; struct ad5903_config *config = (struct ad5903_config *)buf; - struct iio_dev *idev = dev_get_drvdata(dev); + struct iio_dev *idev = dev_to_iio_dev(dev); struct ad5930_state *st = iio_priv(idev); config->control = (config->control & ~value_mask); @@ -97,7 +97,7 @@ static int __devinit ad5930_probe(struct spi_device *spi) struct iio_dev *idev; int ret = 0; - idev = iio_allocate_device(sizeof(*st)); + idev = iio_device_alloc(sizeof(*st)); if (idev == NULL) { ret = -ENOMEM; goto error_ret; @@ -122,7 +122,7 @@ static int __devinit ad5930_probe(struct spi_device *spi) return 0; error_free_dev: - iio_free_device(idev); + iio_device_free(idev); error_ret: return ret; } @@ -130,7 +130,7 @@ static int __devinit ad5930_probe(struct spi_device *spi) static int __devexit ad5930_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_free_device(spi_get_drvdata(spi)); + iio_device_free(spi_get_drvdata(spi)); return 0; } diff --git a/trunk/drivers/staging/iio/dds/ad9832.c b/trunk/drivers/staging/iio/frequency/ad9832.c similarity index 90% rename from trunk/drivers/staging/iio/dds/ad9832.c rename to trunk/drivers/staging/iio/frequency/ad9832.c index 2ccf25dd9289..fed39404e34a 100644 --- a/trunk/drivers/staging/iio/dds/ad9832.c +++ b/trunk/drivers/staging/iio/frequency/ad9832.c @@ -16,8 +16,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #include "dds.h" #include "ad9832.h" @@ -77,7 +77,7 @@ static ssize_t ad9832_write(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad9832_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; @@ -177,18 +177,18 @@ static IIO_DEV_ATTR_OUT_ENABLE(0, S_IWUSR, NULL, ad9832_write, AD9832_OUTPUT_EN); static struct attribute *ad9832_attributes[] = { - &iio_dev_attr_dds0_freq0.dev_attr.attr, - &iio_dev_attr_dds0_freq1.dev_attr.attr, - &iio_const_attr_dds0_freq_scale.dev_attr.attr, - &iio_dev_attr_dds0_phase0.dev_attr.attr, - &iio_dev_attr_dds0_phase1.dev_attr.attr, - &iio_dev_attr_dds0_phase2.dev_attr.attr, - &iio_dev_attr_dds0_phase3.dev_attr.attr, - &iio_const_attr_dds0_phase_scale.dev_attr.attr, - &iio_dev_attr_dds0_pincontrol_en.dev_attr.attr, - &iio_dev_attr_dds0_freqsymbol.dev_attr.attr, - &iio_dev_attr_dds0_phasesymbol.dev_attr.attr, - &iio_dev_attr_dds0_out_enable.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_frequency0.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_frequency1.dev_attr.attr, + &iio_const_attr_out_altvoltage0_frequency_scale.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_phase0.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_phase1.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_phase2.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_phase3.dev_attr.attr, + &iio_const_attr_out_altvoltage0_phase_scale.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_pincontrol_en.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_frequencysymbol.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_phasesymbol.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_out_enable.dev_attr.attr, NULL, }; @@ -221,7 +221,7 @@ static int __devinit ad9832_probe(struct spi_device *spi) goto error_put_reg; } - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_disable_reg; @@ -313,7 +313,7 @@ static int __devinit ad9832_probe(struct spi_device *spi) return 0; error_free_device: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_disable_reg: if (!IS_ERR(reg)) regulator_disable(reg); @@ -334,7 +334,7 @@ static int __devexit ad9832_remove(struct spi_device *spi) regulator_disable(st->reg); regulator_put(st->reg); } - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/dds/ad9832.h b/trunk/drivers/staging/iio/frequency/ad9832.h similarity index 100% rename from trunk/drivers/staging/iio/dds/ad9832.h rename to trunk/drivers/staging/iio/frequency/ad9832.h diff --git a/trunk/drivers/staging/iio/dds/ad9834.c b/trunk/drivers/staging/iio/frequency/ad9834.c similarity index 83% rename from trunk/drivers/staging/iio/dds/ad9834.c rename to trunk/drivers/staging/iio/frequency/ad9834.c index 38a2de08626f..1b2dc741d2ce 100644 --- a/trunk/drivers/staging/iio/dds/ad9834.c +++ b/trunk/drivers/staging/iio/frequency/ad9834.c @@ -19,8 +19,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #include "dds.h" #include "ad9834.h" @@ -66,7 +66,7 @@ static ssize_t ad9834_write(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad9834_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; @@ -145,7 +145,7 @@ static ssize_t ad9834_store_wavetype(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad9834_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret = 0; @@ -203,7 +203,7 @@ static ssize_t ad9834_show_out0_wavetype_available(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad9834_state *st = iio_priv(indio_dev); char *str; @@ -218,14 +218,14 @@ static ssize_t ad9834_show_out0_wavetype_available(struct device *dev, } -static IIO_DEVICE_ATTR(dds0_out0_wavetype_available, S_IRUGO, +static IIO_DEVICE_ATTR(out_altvoltage0_out0_wavetype_available, S_IRUGO, ad9834_show_out0_wavetype_available, NULL, 0); static ssize_t ad9834_show_out1_wavetype_available(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad9834_state *st = iio_priv(indio_dev); char *str; @@ -237,7 +237,7 @@ static ssize_t ad9834_show_out1_wavetype_available(struct device *dev, return sprintf(buf, "%s\n", str); } -static IIO_DEVICE_ATTR(dds0_out1_wavetype_available, S_IRUGO, +static IIO_DEVICE_ATTR(out_altvoltage0_out1_wavetype_available, S_IRUGO, ad9834_show_out1_wavetype_available, NULL, 0); /** @@ -263,36 +263,36 @@ static IIO_DEV_ATTR_OUT_WAVETYPE(0, 0, ad9834_store_wavetype, 0); static IIO_DEV_ATTR_OUT_WAVETYPE(0, 1, ad9834_store_wavetype, 1); static struct attribute *ad9834_attributes[] = { - &iio_dev_attr_dds0_freq0.dev_attr.attr, - &iio_dev_attr_dds0_freq1.dev_attr.attr, - &iio_const_attr_dds0_freq_scale.dev_attr.attr, - &iio_dev_attr_dds0_phase0.dev_attr.attr, - &iio_dev_attr_dds0_phase1.dev_attr.attr, - &iio_const_attr_dds0_phase_scale.dev_attr.attr, - &iio_dev_attr_dds0_pincontrol_en.dev_attr.attr, - &iio_dev_attr_dds0_freqsymbol.dev_attr.attr, - &iio_dev_attr_dds0_phasesymbol.dev_attr.attr, - &iio_dev_attr_dds0_out_enable.dev_attr.attr, - &iio_dev_attr_dds0_out1_enable.dev_attr.attr, - &iio_dev_attr_dds0_out0_wavetype.dev_attr.attr, - &iio_dev_attr_dds0_out1_wavetype.dev_attr.attr, - &iio_dev_attr_dds0_out0_wavetype_available.dev_attr.attr, - &iio_dev_attr_dds0_out1_wavetype_available.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_frequency0.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_frequency1.dev_attr.attr, + &iio_const_attr_out_altvoltage0_frequency_scale.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_phase0.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_phase1.dev_attr.attr, + &iio_const_attr_out_altvoltage0_phase_scale.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_pincontrol_en.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_frequencysymbol.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_phasesymbol.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_out_enable.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_out1_enable.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_out0_wavetype.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_out1_wavetype.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_out0_wavetype_available.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_out1_wavetype_available.dev_attr.attr, NULL, }; static struct attribute *ad9833_attributes[] = { - &iio_dev_attr_dds0_freq0.dev_attr.attr, - &iio_dev_attr_dds0_freq1.dev_attr.attr, - &iio_const_attr_dds0_freq_scale.dev_attr.attr, - &iio_dev_attr_dds0_phase0.dev_attr.attr, - &iio_dev_attr_dds0_phase1.dev_attr.attr, - &iio_const_attr_dds0_phase_scale.dev_attr.attr, - &iio_dev_attr_dds0_freqsymbol.dev_attr.attr, - &iio_dev_attr_dds0_phasesymbol.dev_attr.attr, - &iio_dev_attr_dds0_out_enable.dev_attr.attr, - &iio_dev_attr_dds0_out0_wavetype.dev_attr.attr, - &iio_dev_attr_dds0_out0_wavetype_available.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_frequency0.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_frequency1.dev_attr.attr, + &iio_const_attr_out_altvoltage0_frequency_scale.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_phase0.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_phase1.dev_attr.attr, + &iio_const_attr_out_altvoltage0_phase_scale.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_frequencysymbol.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_phasesymbol.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_out_enable.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_out0_wavetype.dev_attr.attr, + &iio_dev_attr_out_altvoltage0_out0_wavetype_available.dev_attr.attr, NULL, }; @@ -334,7 +334,7 @@ static int __devinit ad9834_probe(struct spi_device *spi) goto error_put_reg; } - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_disable_reg; @@ -414,7 +414,7 @@ static int __devinit ad9834_probe(struct spi_device *spi) return 0; error_free_device: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_disable_reg: if (!IS_ERR(reg)) regulator_disable(reg); @@ -434,7 +434,7 @@ static int __devexit ad9834_remove(struct spi_device *spi) regulator_disable(st->reg); regulator_put(st->reg); } - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/dds/ad9834.h b/trunk/drivers/staging/iio/frequency/ad9834.h similarity index 100% rename from trunk/drivers/staging/iio/dds/ad9834.h rename to trunk/drivers/staging/iio/frequency/ad9834.h diff --git a/trunk/drivers/staging/iio/dds/ad9850.c b/trunk/drivers/staging/iio/frequency/ad9850.c similarity index 92% rename from trunk/drivers/staging/iio/dds/ad9850.c rename to trunk/drivers/staging/iio/frequency/ad9850.c index f4f731bb2191..74abee054ac0 100644 --- a/trunk/drivers/staging/iio/dds/ad9850.c +++ b/trunk/drivers/staging/iio/frequency/ad9850.c @@ -16,8 +16,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #define DRV_NAME "ad9850" @@ -43,7 +43,7 @@ static ssize_t ad9850_set_parameter(struct device *dev, struct spi_transfer xfer; int ret; struct ad9850_config *config = (struct ad9850_config *)buf; - struct iio_dev *idev = dev_get_drvdata(dev); + struct iio_dev *idev = dev_to_iio_dev(dev); struct ad9850_state *st = iio_priv(idev); xfer.len = len; @@ -83,7 +83,7 @@ static int __devinit ad9850_probe(struct spi_device *spi) struct iio_dev *idev; int ret = 0; - idev = iio_allocate_device(sizeof(*st)); + idev = iio_device_alloc(sizeof(*st)); if (idev == NULL) { ret = -ENOMEM; goto error_ret; @@ -108,7 +108,7 @@ static int __devinit ad9850_probe(struct spi_device *spi) return 0; error_free_dev: - iio_free_device(idev); + iio_device_free(idev); error_ret: return ret; } @@ -116,7 +116,7 @@ static int __devinit ad9850_probe(struct spi_device *spi) static int __devexit ad9850_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_free_device(spi_get_drvdata(spi)); + iio_device_free(spi_get_drvdata(spi)); return 0; } diff --git a/trunk/drivers/staging/iio/dds/ad9852.c b/trunk/drivers/staging/iio/frequency/ad9852.c similarity index 96% rename from trunk/drivers/staging/iio/dds/ad9852.c rename to trunk/drivers/staging/iio/frequency/ad9852.c index 554266c615a8..fd9d14a413a5 100644 --- a/trunk/drivers/staging/iio/dds/ad9852.c +++ b/trunk/drivers/staging/iio/frequency/ad9852.c @@ -16,8 +16,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #define DRV_NAME "ad9852" @@ -71,7 +71,7 @@ static ssize_t ad9852_set_parameter(struct device *dev, struct spi_transfer xfer; int ret; struct ad9852_config *config = (struct ad9852_config *)buf; - struct iio_dev *idev = dev_get_drvdata(dev); + struct iio_dev *idev = dev_to_iio_dev(dev); struct ad9852_state *st = iio_priv(idev); xfer.len = 3; @@ -232,7 +232,7 @@ static int __devinit ad9852_probe(struct spi_device *spi) struct iio_dev *idev; int ret = 0; - idev = iio_allocate_device(sizeof(*st)); + idev = iio_device_alloc(sizeof(*st)); if (idev == NULL) { ret = -ENOMEM; goto error_ret; @@ -258,7 +258,7 @@ static int __devinit ad9852_probe(struct spi_device *spi) return 0; error_free_dev: - iio_free_device(idev); + iio_device_free(idev); error_ret: return ret; @@ -267,7 +267,7 @@ static int __devinit ad9852_probe(struct spi_device *spi) static int __devexit ad9852_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_free_device(spi_get_drvdata(spi)); + iio_device_free(spi_get_drvdata(spi)); return 0; } diff --git a/trunk/drivers/staging/iio/dds/ad9910.c b/trunk/drivers/staging/iio/frequency/ad9910.c similarity index 97% rename from trunk/drivers/staging/iio/dds/ad9910.c rename to trunk/drivers/staging/iio/frequency/ad9910.c index 3985766d6f87..5a7ba305b75a 100644 --- a/trunk/drivers/staging/iio/dds/ad9910.c +++ b/trunk/drivers/staging/iio/frequency/ad9910.c @@ -16,8 +16,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #define DRV_NAME "ad9910" @@ -123,7 +123,7 @@ static ssize_t ad9910_set_parameter(struct device *dev, struct spi_transfer xfer; int ret; struct ad9910_config *config = (struct ad9910_config *)buf; - struct iio_dev *idev = dev_get_drvdata(dev); + struct iio_dev *idev = dev_to_iio_dev(dev); struct ad9910_state *st = iio_priv(idev); xfer.len = 5; @@ -367,7 +367,7 @@ static int __devinit ad9910_probe(struct spi_device *spi) struct iio_dev *idev; int ret = 0; - idev = iio_allocate_device(sizeof(*st)); + idev = iio_device_alloc(sizeof(*st)); if (idev == NULL) { ret = -ENOMEM; goto error_ret; @@ -392,7 +392,7 @@ static int __devinit ad9910_probe(struct spi_device *spi) return 0; error_free_dev: - iio_free_device(idev); + iio_device_free(idev); error_ret: return ret; } @@ -400,7 +400,7 @@ static int __devinit ad9910_probe(struct spi_device *spi) static int __devexit ad9910_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_free_device(spi_get_drvdata(spi)); + iio_device_free(spi_get_drvdata(spi)); return 0; } diff --git a/trunk/drivers/staging/iio/dds/ad9951.c b/trunk/drivers/staging/iio/frequency/ad9951.c similarity index 95% rename from trunk/drivers/staging/iio/dds/ad9951.c rename to trunk/drivers/staging/iio/frequency/ad9951.c index 4d150048002a..ba6f49ff09ae 100644 --- a/trunk/drivers/staging/iio/dds/ad9951.c +++ b/trunk/drivers/staging/iio/frequency/ad9951.c @@ -16,8 +16,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #define DRV_NAME "ad9951" @@ -64,7 +64,7 @@ static ssize_t ad9951_set_parameter(struct device *dev, struct spi_transfer xfer; int ret; struct ad9951_config *config = (struct ad9951_config *)buf; - struct iio_dev *idev = dev_get_drvdata(dev); + struct iio_dev *idev = dev_to_iio_dev(dev); struct ad9951_state *st = iio_priv(idev); xfer.len = 3; @@ -176,7 +176,7 @@ static int __devinit ad9951_probe(struct spi_device *spi) struct iio_dev *idev; int ret = 0; - idev = iio_allocate_device(sizeof(*st)); + idev = iio_device_alloc(sizeof(*st)); if (idev == NULL) { ret = -ENOMEM; goto error_ret; @@ -202,7 +202,7 @@ static int __devinit ad9951_probe(struct spi_device *spi) return 0; error_free_dev: - iio_free_device(idev); + iio_device_free(idev); error_ret: return ret; @@ -211,7 +211,7 @@ static int __devinit ad9951_probe(struct spi_device *spi) static int __devexit ad9951_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_free_device(spi_get_drvdata(spi)); + iio_device_free(spi_get_drvdata(spi)); return 0; } diff --git a/trunk/drivers/staging/iio/frequency/dds.h b/trunk/drivers/staging/iio/frequency/dds.h new file mode 100644 index 000000000000..c3342f6e052b --- /dev/null +++ b/trunk/drivers/staging/iio/frequency/dds.h @@ -0,0 +1,110 @@ +/* + * dds.h - sysfs attributes associated with DDS devices + * + * Copyright (c) 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +/** + * /sys/bus/iio/devices/.../out_altvoltageX_frequencyY + */ + +#define IIO_DEV_ATTR_FREQ(_channel, _num, _mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(out_altvoltage##_channel##_frequency##_num, \ + _mode, _show, _store, _addr) + +/** + * /sys/bus/iio/devices/.../out_altvoltageX_frequencyY_scale + */ + +#define IIO_CONST_ATTR_FREQ_SCALE(_channel, _string) \ + IIO_CONST_ATTR(out_altvoltage##_channel##_frequency_scale, _string) + +/** + * /sys/bus/iio/devices/.../out_altvoltageX_frequencysymbol + */ + +#define IIO_DEV_ATTR_FREQSYMBOL(_channel, _mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(out_altvoltage##_channel##_frequencysymbol, \ + _mode, _show, _store, _addr); + +/** + * /sys/bus/iio/devices/.../out_altvoltageX_phaseY + */ + +#define IIO_DEV_ATTR_PHASE(_channel, _num, _mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(out_altvoltage##_channel##_phase##_num, \ + _mode, _show, _store, _addr) + +/** + * /sys/bus/iio/devices/.../out_altvoltageX_phaseY_scale + */ + +#define IIO_CONST_ATTR_PHASE_SCALE(_channel, _string) \ + IIO_CONST_ATTR(out_altvoltage##_channel##_phase_scale, _string) + +/** + * /sys/bus/iio/devices/.../out_altvoltageX_phasesymbol + */ + +#define IIO_DEV_ATTR_PHASESYMBOL(_channel, _mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(out_altvoltage##_channel##_phasesymbol, \ + _mode, _show, _store, _addr); + +/** + * /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_en + */ + +#define IIO_DEV_ATTR_PINCONTROL_EN(_channel, _mode, _show, _store, _addr)\ + IIO_DEVICE_ATTR(out_altvoltage##_channel##_pincontrol_en, \ + _mode, _show, _store, _addr); + +/** + * /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_frequency_en + */ + +#define IIO_DEV_ATTR_PINCONTROL_FREQ_EN(_channel, _mode, _show, _store, _addr)\ + IIO_DEVICE_ATTR(out_altvoltage##_channel##_pincontrol_frequency_en,\ + _mode, _show, _store, _addr); + +/** + * /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_phase_en + */ + +#define IIO_DEV_ATTR_PINCONTROL_PHASE_EN(_channel, _mode, _show, _store, _addr)\ + IIO_DEVICE_ATTR(out_altvoltage##_channel##_pincontrol_phase_en, \ + _mode, _show, _store, _addr); + +/** + * /sys/bus/iio/devices/.../out_altvoltageX_out_enable + */ + +#define IIO_DEV_ATTR_OUT_ENABLE(_channel, _mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(out_altvoltage##_channel##_out_enable, \ + _mode, _show, _store, _addr); + +/** + * /sys/bus/iio/devices/.../out_altvoltageX_outY_enable + */ + +#define IIO_DEV_ATTR_OUTY_ENABLE(_channel, _output, \ + _mode, _show, _store, _addr) \ + IIO_DEVICE_ATTR(out_altvoltage##_channel##_out##_output##_enable,\ + _mode, _show, _store, _addr); + +/** + * /sys/bus/iio/devices/.../out_altvoltageX_outY_wavetype + */ + +#define IIO_DEV_ATTR_OUT_WAVETYPE(_channel, _output, _store, _addr) \ + IIO_DEVICE_ATTR(out_altvoltage##_channel##_out##_output##_wavetype,\ + S_IWUSR, NULL, _store, _addr); + +/** + * /sys/bus/iio/devices/.../out_altvoltageX_outY_wavetype_available + */ + +#define IIO_CONST_ATTR_OUT_WAVETYPES_AVAILABLE(_channel, _output, _modes)\ + IIO_CONST_ATTR( \ + out_altvoltage##_channel##_out##_output##_wavetype_available, _modes); diff --git a/trunk/drivers/staging/iio/gyro/adis16060_core.c b/trunk/drivers/staging/iio/gyro/adis16060_core.c index 02cc23420b90..9931e2060e1f 100644 --- a/trunk/drivers/staging/iio/gyro/adis16060_core.c +++ b/trunk/drivers/staging/iio/gyro/adis16060_core.c @@ -15,8 +15,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #define ADIS16060_GYRO 0x20 /* Measure Angular Rate (Gyro) */ #define ADIS16060_TEMP_OUT 0x10 /* Measure Temperature */ @@ -85,7 +85,7 @@ static int adis16060_read_raw(struct iio_dev *indio_dev, int ret; switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: /* Take the iio_dev status lock */ mutex_lock(&indio_dev->mlock); ret = adis16060_spi_write(indio_dev, chan->address); @@ -120,22 +120,26 @@ static const struct iio_chan_spec adis16060_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_Z, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .address = ADIS16060_GYRO, }, { .type = IIO_VOLTAGE, .indexed = 1, .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .address = ADIS16060_AIN1, }, { .type = IIO_VOLTAGE, .indexed = 1, .channel = 1, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .address = ADIS16060_AIN2, }, { .type = IIO_TEMP, .indexed = 1, .channel = 0, - .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = ADIS16060_TEMP_OUT, } @@ -148,7 +152,7 @@ static int __devinit adis16060_r_probe(struct spi_device *spi) struct iio_dev *indio_dev; /* setup the industrialio driver allocated elements */ - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -174,7 +178,7 @@ static int __devinit adis16060_r_probe(struct spi_device *spi) return 0; error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; } @@ -183,7 +187,7 @@ static int __devinit adis16060_r_probe(struct spi_device *spi) static int adis16060_r_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_free_device(spi_get_drvdata(spi)); + iio_device_free(spi_get_drvdata(spi)); return 0; } diff --git a/trunk/drivers/staging/iio/gyro/adis16080_core.c b/trunk/drivers/staging/iio/gyro/adis16080_core.c index 1815490db8b4..11f1dccd7a0d 100644 --- a/trunk/drivers/staging/iio/gyro/adis16080_core.c +++ b/trunk/drivers/staging/iio/gyro/adis16080_core.c @@ -14,8 +14,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #define ADIS16080_DIN_GYRO (0 << 10) /* Gyroscope output */ #define ADIS16080_DIN_TEMP (1 << 10) /* Temperature output */ @@ -87,7 +87,7 @@ static int adis16080_read_raw(struct iio_dev *indio_dev, mutex_lock(&indio_dev->mlock); switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: ret = adis16080_spi_write(indio_dev, chan->address | ADIS16080_DIN_WRITE); @@ -110,21 +110,25 @@ static const struct iio_chan_spec adis16080_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_Z, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .address = ADIS16080_DIN_GYRO, }, { .type = IIO_VOLTAGE, .indexed = 1, .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .address = ADIS16080_DIN_AIN1, }, { .type = IIO_VOLTAGE, .indexed = 1, .channel = 1, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .address = ADIS16080_DIN_AIN2, }, { .type = IIO_TEMP, .indexed = 1, .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .address = ADIS16080_DIN_TEMP, } }; @@ -141,7 +145,7 @@ static int __devinit adis16080_probe(struct spi_device *spi) struct iio_dev *indio_dev; /* setup the industrialio driver allocated elements */ - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -167,7 +171,7 @@ static int __devinit adis16080_probe(struct spi_device *spi) return 0; error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; } @@ -176,7 +180,7 @@ static int __devinit adis16080_probe(struct spi_device *spi) static int adis16080_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_free_device(spi_get_drvdata(spi)); + iio_device_free(spi_get_drvdata(spi)); return 0; } diff --git a/trunk/drivers/staging/iio/gyro/adis16130_core.c b/trunk/drivers/staging/iio/gyro/adis16130_core.c index 947eb86f05d8..bf61cd0b5bbc 100644 --- a/trunk/drivers/staging/iio/gyro/adis16130_core.c +++ b/trunk/drivers/staging/iio/gyro/adis16130_core.c @@ -16,8 +16,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #define ADIS16130_CON 0x0 #define ADIS16130_CON_RD (1 << 6) @@ -100,11 +100,13 @@ static const struct iio_chan_spec adis16130_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_Z, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .address = ADIS16130_RATEDATA, }, { .type = IIO_TEMP, .indexed = 1, .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .address = ADIS16130_TEMPDATA, } }; @@ -121,7 +123,7 @@ static int __devinit adis16130_probe(struct spi_device *spi) struct iio_dev *indio_dev; /* setup the industrialio driver allocated elements */ - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -145,7 +147,7 @@ static int __devinit adis16130_probe(struct spi_device *spi) return 0; error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; @@ -155,7 +157,7 @@ static int __devinit adis16130_probe(struct spi_device *spi) static int adis16130_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_free_device(spi_get_drvdata(spi)); + iio_device_free(spi_get_drvdata(spi)); return 0; } diff --git a/trunk/drivers/staging/iio/gyro/adis16260_core.c b/trunk/drivers/staging/iio/gyro/adis16260_core.c index 8f6af47e9559..ec765f955f8d 100644 --- a/trunk/drivers/staging/iio/gyro/adis16260_core.c +++ b/trunk/drivers/staging/iio/gyro/adis16260_core.c @@ -18,9 +18,9 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../buffer.h" +#include +#include +#include #include "adis16260.h" @@ -149,7 +149,7 @@ static ssize_t adis16260_read_frequency_available(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct adis16260_state *st = iio_priv(indio_dev); if (spi_get_device_id(st->us)->driver_data) return sprintf(buf, "%s\n", "0.129 ~ 256"); @@ -161,7 +161,7 @@ static ssize_t adis16260_read_frequency(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct adis16260_state *st = iio_priv(indio_dev); int ret, len = 0; u16 t; @@ -186,7 +186,7 @@ static ssize_t adis16260_write_frequency(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct adis16260_state *st = iio_priv(indio_dev); long val; int ret; @@ -237,7 +237,7 @@ static ssize_t adis16260_write_reset(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); if (len < 1) return -EINVAL; switch (buf[0]) { @@ -389,30 +389,76 @@ enum adis16260_channel { }; #define ADIS16260_GYRO_CHANNEL_SET(axis, mod) \ struct iio_chan_spec adis16260_channels_##axis[] = { \ - IIO_CHAN(IIO_ANGL_VEL, 1, 0, 0, NULL, 0, mod, \ - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \ - IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \ - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ - gyro, ADIS16260_SCAN_GYRO, \ - IIO_ST('s', 14, 16, 0), 0), \ - IIO_CHAN(IIO_ANGL, 1, 0, 0, NULL, 0, mod, \ - 0, \ - angle, ADIS16260_SCAN_ANGL, \ - IIO_ST('u', 14, 16, 0), 0), \ - IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0, \ - IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \ - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ - temp, ADIS16260_SCAN_TEMP, \ - IIO_ST('u', 12, 16, 0), 0), \ - IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "supply", 0, 0, \ - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ - in_supply, ADIS16260_SCAN_SUPPLY, \ - IIO_ST('u', 12, 16, 0), 0), \ - IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0, \ - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ - in_aux, ADIS16260_SCAN_AUX_ADC, \ - IIO_ST('u', 12, 16, 0), 0), \ - IIO_CHAN_SOFT_TIMESTAMP(5) \ + { \ + .type = IIO_ANGL_VEL, \ + .modified = 1, \ + .channel2 = mod, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \ + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ + .address = gyro, \ + .scan_index = ADIS16260_SCAN_GYRO, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 14, \ + .storagebits = 16, \ + }, \ + }, { \ + .type = IIO_ANGL, \ + .modified = 1, \ + .channel2 = mod, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, \ + .address = angle, \ + .scan_index = ADIS16260_SCAN_ANGL, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 14, \ + .storagebits = 16, \ + }, \ + }, { \ + .type = IIO_TEMP, \ + .indexed = 1, \ + .channel = 0, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ + .address = temp, \ + .scan_index = ADIS16260_SCAN_TEMP, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 12, \ + .storagebits = 16, \ + }, \ + }, { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = 0, \ + .extend_name = "supply", \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ + .address = in_supply, \ + .scan_index = ADIS16260_SCAN_SUPPLY, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 12, \ + .storagebits = 16, \ + }, \ + }, { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = 1, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ + .address = in_aux, \ + .scan_index = ADIS16260_SCAN_AUX_ADC, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 12, \ + .storagebits = 16, \ + }, \ + }, \ + IIO_CHAN_SOFT_TIMESTAMP(5), \ } static const ADIS16260_GYRO_CHANNEL_SET(x, IIO_MOD_X); @@ -440,7 +486,7 @@ static int adis16260_read_raw(struct iio_dev *indio_dev, s16 val16; switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: mutex_lock(&indio_dev->mlock); addr = adis16260_addresses[chan->address][0]; ret = adis16260_spi_read_reg_16(indio_dev, addr, &val16); @@ -581,7 +627,7 @@ static int __devinit adis16260_probe(struct spi_device *spi) struct iio_dev *indio_dev; /* setup the industrialio driver allocated elements */ - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -666,7 +712,7 @@ static int __devinit adis16260_probe(struct spi_device *spi) error_unreg_ring_funcs: adis16260_unconfigure_ring(indio_dev); error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; } @@ -687,7 +733,7 @@ static int adis16260_remove(struct spi_device *spi) adis16260_remove_trigger(indio_dev); iio_buffer_unregister(indio_dev); adis16260_unconfigure_ring(indio_dev); - iio_free_device(indio_dev); + iio_device_free(indio_dev); err_ret: return ret; diff --git a/trunk/drivers/staging/iio/gyro/adis16260_ring.c b/trunk/drivers/staging/iio/gyro/adis16260_ring.c index 711f15122a08..0fe2d9dfb6cd 100644 --- a/trunk/drivers/staging/iio/gyro/adis16260_ring.c +++ b/trunk/drivers/staging/iio/gyro/adis16260_ring.c @@ -5,20 +5,19 @@ #include #include -#include "../iio.h" +#include #include "../ring_sw.h" -#include "../trigger_consumer.h" +#include #include "adis16260.h" /** * adis16260_read_ring_data() read data registers which will be placed into ring - * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @indio_dev: the IIO device * @rx: somewhere to pass back the value read **/ -static int adis16260_read_ring_data(struct device *dev, u8 *rx) +static int adis16260_read_ring_data(struct iio_dev *indio_dev, u8 *rx) { struct spi_message msg; - struct iio_dev *indio_dev = dev_get_drvdata(dev); struct adis16260_state *st = iio_priv(indio_dev); struct spi_transfer xfers[ADIS16260_OUTPUTS + 1]; int ret; @@ -66,22 +65,21 @@ static irqreturn_t adis16260_trigger_handler(int irq, void *p) struct iio_buffer *ring = indio_dev->buffer; int i = 0; s16 *data; - size_t datasize = ring->access->get_bytes_per_datum(ring); - data = kmalloc(datasize , GFP_KERNEL); + data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); if (data == NULL) { dev_err(&st->us->dev, "memory alloc failed in ring bh"); return -ENOMEM; } if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) && - adis16260_read_ring_data(&indio_dev->dev, st->rx) >= 0) + adis16260_read_ring_data(indio_dev, st->rx) >= 0) for (; i < bitmap_weight(indio_dev->active_scan_mask, indio_dev->masklength); i++) data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2])); /* Guaranteed to be aligned with 8 byte boundary */ - if (ring->scan_timestamp) + if (indio_dev->scan_timestamp) *((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp; ring->access->store_to(ring, (u8 *)data, pf->timestamp); diff --git a/trunk/drivers/staging/iio/gyro/adis16260_trigger.c b/trunk/drivers/staging/iio/gyro/adis16260_trigger.c index 8299cd18d705..034559e4d5b9 100644 --- a/trunk/drivers/staging/iio/gyro/adis16260_trigger.c +++ b/trunk/drivers/staging/iio/gyro/adis16260_trigger.c @@ -3,8 +3,8 @@ #include #include -#include "../iio.h" -#include "../trigger.h" +#include +#include #include "adis16260.h" /** @@ -29,7 +29,7 @@ int adis16260_probe_trigger(struct iio_dev *indio_dev) int ret; struct adis16260_state *st = iio_priv(indio_dev); - st->trig = iio_allocate_trigger("%s-dev%d", + st->trig = iio_trigger_alloc("%s-dev%d", spi_get_device_id(st->us)->name, indio_dev->id); if (st->trig == NULL) { @@ -60,7 +60,7 @@ int adis16260_probe_trigger(struct iio_dev *indio_dev) error_free_irq: free_irq(st->us->irq, st->trig); error_free_trig: - iio_free_trigger(st->trig); + iio_trigger_free(st->trig); error_ret: return ret; } @@ -71,5 +71,5 @@ void adis16260_remove_trigger(struct iio_dev *indio_dev) iio_trigger_unregister(st->trig); free_irq(st->us->irq, st->trig); - iio_free_trigger(st->trig); + iio_trigger_free(st->trig); } diff --git a/trunk/drivers/staging/iio/gyro/adxrs450.h b/trunk/drivers/staging/iio/gyro/adxrs450.h index af0c870100b6..f8cf21f02943 100644 --- a/trunk/drivers/staging/iio/gyro/adxrs450.h +++ b/trunk/drivers/staging/iio/gyro/adxrs450.h @@ -49,7 +49,7 @@ enum { * @us: actual spi_device * @buf_lock: mutex to protect tx and rx * @tx: transmit buffer - * @rx: recieve buffer + * @rx: receive buffer **/ struct adxrs450_state { struct spi_device *us; diff --git a/trunk/drivers/staging/iio/gyro/adxrs450_core.c b/trunk/drivers/staging/iio/gyro/adxrs450_core.c index 15e2496f70c8..6513119b1e90 100644 --- a/trunk/drivers/staging/iio/gyro/adxrs450_core.c +++ b/trunk/drivers/staging/iio/gyro/adxrs450_core.c @@ -18,8 +18,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #include "adxrs450.h" @@ -265,7 +265,7 @@ static int adxrs450_read_raw(struct iio_dev *indio_dev, s16 t; switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: switch (chan->type) { case IIO_ANGL_VEL: ret = adxrs450_spi_sensor_data(indio_dev, &t); @@ -329,14 +329,16 @@ static const struct iio_chan_spec adxrs450_channels[2][2] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_Z, - .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, }, { .type = IIO_TEMP, .indexed = 1, .channel = 0, - .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, } }, [ID_ADXRS453] = { @@ -344,13 +346,15 @@ static const struct iio_chan_spec adxrs450_channels[2][2] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_Z, - .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT | IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SEPARATE_BIT, }, { .type = IIO_TEMP, .indexed = 1, .channel = 0, - .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, } }, }; @@ -368,7 +372,7 @@ static int __devinit adxrs450_probe(struct spi_device *spi) struct iio_dev *indio_dev; /* setup the industrialio driver allocated elements */ - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -399,7 +403,7 @@ static int __devinit adxrs450_probe(struct spi_device *spi) error_initial: iio_device_unregister(indio_dev); error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; @@ -408,7 +412,7 @@ static int __devinit adxrs450_probe(struct spi_device *spi) static int adxrs450_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_free_device(spi_get_drvdata(spi)); + iio_device_free(spi_get_drvdata(spi)); return 0; } diff --git a/trunk/drivers/staging/iio/iio_dummy_evgen.c b/trunk/drivers/staging/iio/iio_dummy_evgen.c index f39f346bf04f..0cd4fe916bf9 100644 --- a/trunk/drivers/staging/iio/iio_dummy_evgen.c +++ b/trunk/drivers/staging/iio/iio_dummy_evgen.c @@ -22,8 +22,8 @@ #include #include "iio_dummy_evgen.h" -#include "iio.h" -#include "sysfs.h" +#include +#include /* Fiddly bit of faking and irq without hardware */ #define IIO_EVENTGEN_NO 10 diff --git a/trunk/drivers/staging/iio/iio_hwmon.c b/trunk/drivers/staging/iio/iio_hwmon.c index a603a5f51f93..b03554fee443 100644 --- a/trunk/drivers/staging/iio/iio_hwmon.c +++ b/trunk/drivers/staging/iio/iio_hwmon.c @@ -14,8 +14,8 @@ #include #include #include -#include "consumer.h" -#include "types.h" +#include +#include /** * struct iio_hwmon_state - device instance state diff --git a/trunk/drivers/staging/iio/iio_simple_dummy.c b/trunk/drivers/staging/iio/iio_simple_dummy.c index e3a94572bb40..310411911ed7 100644 --- a/trunk/drivers/staging/iio/iio_simple_dummy.c +++ b/trunk/drivers/staging/iio/iio_simple_dummy.c @@ -19,10 +19,10 @@ #include #include -#include "iio.h" -#include "sysfs.h" -#include "events.h" -#include "buffer.h" +#include +#include +#include +#include #include "iio_simple_dummy.h" /* @@ -72,6 +72,12 @@ static struct iio_chan_spec iio_dummy_channels[] = { .channel = 0, /* What other information is available? */ .info_mask = + /* + * in_voltage0_raw + * Raw (unscaled no bias removal etc) measurement + * from the device. + */ + IIO_CHAN_INFO_RAW_SEPARATE_BIT | /* * in_voltage0_offset * Offset for userspace to apply prior to scale @@ -113,6 +119,12 @@ static struct iio_chan_spec iio_dummy_channels[] = { .channel = 1, .channel2 = 2, .info_mask = + /* + * in_voltage1-voltage2_raw + * Raw (unscaled no bias removal etc) measurement + * from the device. + */ + IIO_CHAN_INFO_RAW_SEPARATE_BIT | /* * in_voltage-voltage_scale * Shared version of scale - shared by differential @@ -135,6 +147,7 @@ static struct iio_chan_spec iio_dummy_channels[] = { .channel = 3, .channel2 = 4, .info_mask = + IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT, .scan_index = diffvoltage3m4, .scan_type = { @@ -154,6 +167,7 @@ static struct iio_chan_spec iio_dummy_channels[] = { /* Channel 2 is use for modifiers */ .channel2 = IIO_MOD_X, .info_mask = + IIO_CHAN_INFO_RAW_SEPARATE_BIT | /* * Internal bias correction value. Applied * by the hardware or driver prior to userspace @@ -177,6 +191,7 @@ static struct iio_chan_spec iio_dummy_channels[] = { /* DAC channel out_voltage0_raw */ { .type = IIO_VOLTAGE, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .output = 1, .indexed = 1, .channel = 0, @@ -203,7 +218,7 @@ static int iio_dummy_read_raw(struct iio_dev *indio_dev, mutex_lock(&st->lock); switch (mask) { - case 0: /* magic value - channel value read */ + case IIO_CHAN_INFO_RAW: /* magic value - channel value read */ switch (chan->type) { case IIO_VOLTAGE: if (chan->output) { @@ -290,7 +305,7 @@ static int iio_dummy_write_raw(struct iio_dev *indio_dev, struct iio_dummy_state *st = iio_priv(indio_dev); switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: if (chan->output == 0) return -EINVAL; @@ -377,7 +392,7 @@ static int __devinit iio_dummy_probe(int index) * It also has a region (accessed by iio_priv() * for chip specific state information. */ - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -455,9 +470,7 @@ static int __devinit iio_dummy_probe(int index) error_unregister_events: iio_simple_dummy_events_unregister(indio_dev); error_free_device: - /* Note free device should only be called, before registration - * has succeeded. */ - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; } @@ -494,7 +507,7 @@ static int iio_dummy_remove(int index) goto error_ret; /* Free all structures */ - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; diff --git a/trunk/drivers/staging/iio/iio_simple_dummy_buffer.c b/trunk/drivers/staging/iio/iio_simple_dummy_buffer.c index bb4daf744362..fdfc8739095a 100644 --- a/trunk/drivers/staging/iio/iio_simple_dummy_buffer.c +++ b/trunk/drivers/staging/iio/iio_simple_dummy_buffer.c @@ -18,9 +18,9 @@ #include #include -#include "iio.h" -#include "trigger_consumer.h" -#include "kfifo_buf.h" +#include +#include +#include #include "iio_simple_dummy.h" @@ -37,7 +37,7 @@ static const s16 fakedata[] = { * @irq: the interrupt number * @p: private data - always a pointer to the poll func. * - * This is the guts of buffered capture. On a trigger event occuring, + * This is the guts of buffered capture. On a trigger event occurring, * if the pollfunc is attached then this handler is called as a threaded * interrupt (and hence may sleep). It is responsible for grabbing data * from the device and pushing it into the associated buffer. @@ -48,12 +48,9 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p) struct iio_dev *indio_dev = pf->indio_dev; struct iio_buffer *buffer = indio_dev->buffer; int len = 0; - /* - * The datasize is obtained from the buffer. It was stored when - * the preenable setup function was called. - */ - size_t datasize = buffer->access->get_bytes_per_datum(buffer); - u16 *data = kmalloc(datasize, GFP_KERNEL); + u16 *data; + + data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); if (data == NULL) return -ENOMEM; @@ -64,7 +61,7 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p) * up a fast read. The capture will consist of all of them. * Hence we just call the grab data function and fill the * buffer without processing. - * sofware scans: can be considered to be random access + * software scans: can be considered to be random access * so efficient reading is just a case of minimal bus * transactions. * software culled hardware scans: @@ -87,7 +84,7 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p) } } /* Store a timestampe at an 8 byte boundary */ - if (buffer->scan_timestamp) + if (indio_dev->scan_timestamp) *(s64 *)(((phys_addr_t)data + len + sizeof(s64) - 1) & ~(sizeof(s64) - 1)) = iio_get_time_ns(); diff --git a/trunk/drivers/staging/iio/iio_simple_dummy_events.c b/trunk/drivers/staging/iio/iio_simple_dummy_events.c index 449c7a5ece80..317b77465db4 100644 --- a/trunk/drivers/staging/iio/iio_simple_dummy_events.c +++ b/trunk/drivers/staging/iio/iio_simple_dummy_events.c @@ -12,9 +12,9 @@ #include #include -#include "iio.h" -#include "sysfs.h" -#include "events.h" +#include +#include +#include #include "iio_simple_dummy.h" /* Evgen 'fakes' interrupt events for this example */ @@ -122,7 +122,7 @@ int iio_simple_dummy_write_event_value(struct iio_dev *indio_dev, * @private: pointer to device instance state. * * This handler is responsible for querying the device to find out what - * event occured and for then pushing that event towards userspace. + * event occurred and for then pushing that event towards userspace. * Here only one event occurs so we push that directly on with locally * grabbed timestamp. */ diff --git a/trunk/drivers/staging/iio/impedance-analyzer/ad5933.c b/trunk/drivers/staging/iio/impedance-analyzer/ad5933.c index cd82b56d58af..a8e51bc04439 100644 --- a/trunk/drivers/staging/iio/impedance-analyzer/ad5933.c +++ b/trunk/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -19,9 +19,9 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../buffer.h" +#include +#include +#include #include "../ring_sw.h" #include "ad5933.h" @@ -109,15 +109,46 @@ static struct ad5933_platform_data ad5933_default_pdata = { }; static struct iio_chan_spec ad5933_channels[] = { - IIO_CHAN(IIO_TEMP, 0, 1, 1, NULL, 0, 0, 0, - 0, AD5933_REG_TEMP_DATA, IIO_ST('s', 14, 16, 0), 0), - /* Ring Channels */ - IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "real_raw", 0, 0, - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - AD5933_REG_REAL_DATA, 0, IIO_ST('s', 16, 16, 0), 0), - IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "imag_raw", 0, 0, - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - AD5933_REG_IMAG_DATA, 1, IIO_ST('s', 16, 16, 0), 0), + { + .type = IIO_TEMP, + .indexed = 1, + .channel = 0, + .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT, + .address = AD5933_REG_TEMP_DATA, + .scan_type = { + .sign = 's', + .realbits = 14, + .storagebits = 16, + }, + }, { /* Ring Channels */ + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 0, + .extend_name = "real_raw", + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + .address = AD5933_REG_REAL_DATA, + .scan_index = 0, + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + }, + }, { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 0, + .extend_name = "imag_raw", + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + .address = AD5933_REG_IMAG_DATA, + .scan_index = 1, + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + }, + }, }; static int ad5933_i2c_write(struct i2c_client *client, @@ -260,7 +291,7 @@ static ssize_t ad5933_show_frequency(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5933_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; @@ -289,7 +320,7 @@ static ssize_t ad5933_store_frequency(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5933_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); long val; @@ -323,7 +354,7 @@ static ssize_t ad5933_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5933_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret = 0, len = 0; @@ -366,7 +397,7 @@ static ssize_t ad5933_store(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad5933_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); long val; @@ -495,7 +526,8 @@ static int ad5933_read_raw(struct iio_dev *indio_dev, mutex_lock(&indio_dev->mlock); switch (m) { - case 0: + case IIO_CHAN_INFO_RAW: + case IIO_CHAN_INFO_PROCESSED: if (iio_buffer_enabled(indio_dev)) { ret = -EBUSY; goto out; @@ -537,19 +569,14 @@ static const struct iio_info ad5933_info = { static int ad5933_ring_preenable(struct iio_dev *indio_dev) { struct ad5933_state *st = iio_priv(indio_dev); - size_t d_size; int ret; if (bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) return -EINVAL; - d_size = bitmap_weight(indio_dev->active_scan_mask, - indio_dev->masklength) * - ad5933_channels[1].scan_type.storagebits / 8; - - if (indio_dev->buffer->access->set_bytes_per_datum) - indio_dev->buffer->access-> - set_bytes_per_datum(indio_dev->buffer, d_size); + ret = iio_sw_buffer_preenable(indio_dev); + if (ret < 0) + return ret; ret = ad5933_reset(st); if (ret < 0) @@ -678,7 +705,7 @@ static int __devinit ad5933_probe(struct i2c_client *client, int ret, voltage_uv = 0; struct ad5933_platform_data *pdata = client->dev.platform_data; struct ad5933_state *st; - struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st)); + struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; @@ -757,7 +784,7 @@ static int __devinit ad5933_probe(struct i2c_client *client, if (!IS_ERR(st->reg)) regulator_put(st->reg); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return ret; } @@ -774,7 +801,7 @@ static __devexit int ad5933_remove(struct i2c_client *client) regulator_disable(st->reg); regulator_put(st->reg); } - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/imu/adis16400_core.c b/trunk/drivers/staging/iio/imu/adis16400_core.c index e73ad7818d85..1f6bd854e950 100644 --- a/trunk/drivers/staging/iio/imu/adis16400_core.c +++ b/trunk/drivers/staging/iio/imu/adis16400_core.c @@ -26,9 +26,9 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../buffer.h" +#include +#include +#include #include "adis16400.h" enum adis16400_chip_variant { @@ -179,7 +179,7 @@ static ssize_t adis16400_read_frequency(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); int ret, len = 0; ret = adis16400_get_freq(indio_dev); if (ret < 0) @@ -225,7 +225,7 @@ static ssize_t adis16400_write_frequency(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct adis16400_state *st = iio_priv(indio_dev); long val; int ret; @@ -279,7 +279,7 @@ static ssize_t adis16400_write_reset(struct device *dev, if (ret < 0) return ret; if (val) { - ret = adis16400_reset(dev_get_drvdata(dev)); + ret = adis16400_reset(dev_to_iio_dev(dev)); if (ret < 0) return ret; } @@ -545,7 +545,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, s16 val16; switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: mutex_lock(&indio_dev->mlock); ret = adis16400_spi_read_reg_16(indio_dev, adis16400_addresses[chan->address][0], @@ -635,7 +635,8 @@ static struct iio_chan_spec adis16400_channels[] = { .indexed = 1, .channel = 0, .extend_name = "supply", - .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = in_supply, .scan_index = ADIS16400_SCAN_SUPPLY, .scan_type = IIO_ST('u', 14, 16, 0) @@ -643,7 +644,8 @@ static struct iio_chan_spec adis16400_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_X, - .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = gyro_x, @@ -653,7 +655,8 @@ static struct iio_chan_spec adis16400_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_Y, - .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = gyro_y, @@ -663,7 +666,8 @@ static struct iio_chan_spec adis16400_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_Z, - .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = gyro_z, @@ -673,7 +677,8 @@ static struct iio_chan_spec adis16400_channels[] = { .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_X, - .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = accel_x, @@ -683,7 +688,8 @@ static struct iio_chan_spec adis16400_channels[] = { .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_Y, - .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = accel_y, @@ -693,7 +699,8 @@ static struct iio_chan_spec adis16400_channels[] = { .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_Z, - .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = accel_z, @@ -703,7 +710,8 @@ static struct iio_chan_spec adis16400_channels[] = { .type = IIO_MAGN, .modified = 1, .channel2 = IIO_MOD_X, - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = magn_x, .scan_index = ADIS16400_SCAN_MAGN_X, @@ -712,7 +720,8 @@ static struct iio_chan_spec adis16400_channels[] = { .type = IIO_MAGN, .modified = 1, .channel2 = IIO_MOD_Y, - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = magn_y, .scan_index = ADIS16400_SCAN_MAGN_Y, @@ -721,7 +730,8 @@ static struct iio_chan_spec adis16400_channels[] = { .type = IIO_MAGN, .modified = 1, .channel2 = IIO_MOD_Z, - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = magn_z, .scan_index = ADIS16400_SCAN_MAGN_Z, @@ -730,7 +740,8 @@ static struct iio_chan_spec adis16400_channels[] = { .type = IIO_TEMP, .indexed = 1, .channel = 0, - .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = temp, .scan_index = ADIS16400_SCAN_TEMP, @@ -739,7 +750,8 @@ static struct iio_chan_spec adis16400_channels[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 1, - .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = in1, .scan_index = ADIS16400_SCAN_ADC_0, .scan_type = IIO_ST('s', 12, 16, 0), @@ -753,7 +765,8 @@ static struct iio_chan_spec adis16350_channels[] = { .indexed = 1, .channel = 0, .extend_name = "supply", - .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = in_supply, .scan_index = ADIS16400_SCAN_SUPPLY, .scan_type = IIO_ST('u', 12, 16, 0) @@ -761,7 +774,8 @@ static struct iio_chan_spec adis16350_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_X, - .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = gyro_x, @@ -771,7 +785,8 @@ static struct iio_chan_spec adis16350_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_Y, - .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = gyro_y, @@ -781,17 +796,19 @@ static struct iio_chan_spec adis16350_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_Z, - .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = gyro_z, .scan_index = ADIS16400_SCAN_GYRO_Z, .scan_type = IIO_ST('s', 14, 16, 0), }, { - .type = IIO_ACCEL, + .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_X, - .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = accel_x, @@ -801,7 +818,8 @@ static struct iio_chan_spec adis16350_channels[] = { .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_Y, - .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = accel_y, @@ -811,7 +829,8 @@ static struct iio_chan_spec adis16350_channels[] = { .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_Z, - .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = accel_z, @@ -822,7 +841,8 @@ static struct iio_chan_spec adis16350_channels[] = { .indexed = 1, .channel = 0, .extend_name = "x", - .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = temp0, @@ -833,7 +853,8 @@ static struct iio_chan_spec adis16350_channels[] = { .indexed = 1, .channel = 1, .extend_name = "y", - .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = temp1, @@ -844,7 +865,8 @@ static struct iio_chan_spec adis16350_channels[] = { .indexed = 1, .channel = 2, .extend_name = "z", - .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = temp2, .scan_index = ADIS16350_SCAN_TEMP_Z, @@ -853,7 +875,8 @@ static struct iio_chan_spec adis16350_channels[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 1, - .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = in1, .scan_index = ADIS16350_SCAN_ADC_0, .scan_type = IIO_ST('s', 12, 16, 0), @@ -867,7 +890,8 @@ static struct iio_chan_spec adis16300_channels[] = { .indexed = 1, .channel = 0, .extend_name = "supply", - .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = in_supply, .scan_index = ADIS16400_SCAN_SUPPLY, .scan_type = IIO_ST('u', 12, 16, 0) @@ -875,7 +899,8 @@ static struct iio_chan_spec adis16300_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_X, - .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = gyro_x, @@ -885,7 +910,8 @@ static struct iio_chan_spec adis16300_channels[] = { .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_X, - .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = accel_x, @@ -895,7 +921,8 @@ static struct iio_chan_spec adis16300_channels[] = { .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_Y, - .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = accel_y, @@ -905,7 +932,8 @@ static struct iio_chan_spec adis16300_channels[] = { .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_Z, - .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = accel_z, @@ -915,7 +943,8 @@ static struct iio_chan_spec adis16300_channels[] = { .type = IIO_TEMP, .indexed = 1, .channel = 0, - .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = temp, .scan_index = ADIS16400_SCAN_TEMP, @@ -924,7 +953,8 @@ static struct iio_chan_spec adis16300_channels[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 1, - .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, .address = in1, .scan_index = ADIS16350_SCAN_ADC_0, .scan_type = IIO_ST('s', 12, 16, 0), @@ -932,7 +962,8 @@ static struct iio_chan_spec adis16300_channels[] = { .type = IIO_INCLI, .modified = 1, .channel2 = IIO_MOD_X, - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, .address = incli_x, .scan_index = ADIS16300_SCAN_INCLI_X, .scan_type = IIO_ST('s', 13, 16, 0), @@ -940,7 +971,8 @@ static struct iio_chan_spec adis16300_channels[] = { .type = IIO_INCLI, .modified = 1, .channel2 = IIO_MOD_Y, - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, .address = incli_y, .scan_index = ADIS16300_SCAN_INCLI_Y, .scan_type = IIO_ST('s', 13, 16, 0), @@ -953,7 +985,8 @@ static const struct iio_chan_spec adis16334_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_X, - .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = gyro_x, @@ -963,7 +996,8 @@ static const struct iio_chan_spec adis16334_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_Y, - .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = gyro_y, @@ -973,7 +1007,8 @@ static const struct iio_chan_spec adis16334_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_Z, - .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = gyro_z, @@ -983,7 +1018,8 @@ static const struct iio_chan_spec adis16334_channels[] = { .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_X, - .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = accel_x, @@ -993,7 +1029,8 @@ static const struct iio_chan_spec adis16334_channels[] = { .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_Y, - .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = accel_y, @@ -1003,7 +1040,8 @@ static const struct iio_chan_spec adis16334_channels[] = { .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_Z, - .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, .address = accel_z, @@ -1013,7 +1051,8 @@ static const struct iio_chan_spec adis16334_channels[] = { .type = IIO_TEMP, .indexed = 1, .channel = 0, - .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT, .address = accel_z, .scan_index = ADIS16400_SCAN_ACC_Z, @@ -1122,7 +1161,7 @@ static int __devinit adis16400_probe(struct spi_device *spi) { int ret; struct adis16400_state *st; - struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st)); + struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -1172,14 +1211,14 @@ static int __devinit adis16400_probe(struct spi_device *spi) return 0; error_remove_trigger: - if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) + if (spi->irq) adis16400_remove_trigger(indio_dev); error_uninitialize_ring: iio_buffer_unregister(indio_dev); error_unreg_ring_funcs: adis16400_unconfigure_ring(indio_dev); error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; } @@ -1198,7 +1237,7 @@ static int adis16400_remove(struct spi_device *spi) adis16400_remove_trigger(indio_dev); iio_buffer_unregister(indio_dev); adis16400_unconfigure_ring(indio_dev); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; diff --git a/trunk/drivers/staging/iio/imu/adis16400_ring.c b/trunk/drivers/staging/iio/imu/adis16400_ring.c index 8daa038b23e6..809e2c4270d1 100644 --- a/trunk/drivers/staging/iio/imu/adis16400_ring.c +++ b/trunk/drivers/staging/iio/imu/adis16400_ring.c @@ -6,20 +6,19 @@ #include #include -#include "../iio.h" +#include #include "../ring_sw.h" -#include "../trigger_consumer.h" +#include #include "adis16400.h" /** * adis16400_spi_read_burst() - read all data registers - * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @indio_dev: the IIO device * @rx: somewhere to pass back the value read (min size is 24 bytes) **/ -static int adis16400_spi_read_burst(struct device *dev, u8 *rx) +static int adis16400_spi_read_burst(struct iio_dev *indio_dev, u8 *rx) { struct spi_message msg; - struct iio_dev *indio_dev = dev_get_drvdata(dev); struct adis16400_state *st = iio_priv(indio_dev); u32 old_speed_hz = st->us->max_speed_hz; int ret; @@ -71,9 +70,8 @@ static const u16 read_all_tx_array[] = { cpu_to_be16(ADIS16400_READ_REG(ADIS16400_AUX_ADC)), }; -static int adis16350_spi_read_all(struct device *dev, u8 *rx) +static int adis16350_spi_read_all(struct iio_dev *indio_dev, u8 *rx) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); struct adis16400_state *st = iio_priv(indio_dev); struct spi_message msg; @@ -119,12 +117,12 @@ static irqreturn_t adis16400_trigger_handler(int irq, void *p) struct iio_buffer *ring = indio_dev->buffer; int i = 0, j, ret = 0; s16 *data; - size_t datasize = ring->access->get_bytes_per_datum(ring); + /* Asumption that long is enough for maximum channels */ unsigned long mask = *indio_dev->active_scan_mask; int scan_count = bitmap_weight(indio_dev->active_scan_mask, indio_dev->masklength); - data = kmalloc(datasize , GFP_KERNEL); + data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL); if (data == NULL) { dev_err(&st->us->dev, "memory alloc failed in ring bh"); return -ENOMEM; @@ -132,13 +130,13 @@ static irqreturn_t adis16400_trigger_handler(int irq, void *p) if (scan_count) { if (st->variant->flags & ADIS16400_NO_BURST) { - ret = adis16350_spi_read_all(&indio_dev->dev, st->rx); + ret = adis16350_spi_read_all(indio_dev, st->rx); if (ret < 0) goto err; for (; i < scan_count; i++) data[i] = *(s16 *)(st->rx + i*2); } else { - ret = adis16400_spi_read_burst(&indio_dev->dev, st->rx); + ret = adis16400_spi_read_burst(indio_dev, st->rx); if (ret < 0) goto err; for (; i < scan_count; i++) { diff --git a/trunk/drivers/staging/iio/imu/adis16400_trigger.c b/trunk/drivers/staging/iio/imu/adis16400_trigger.c index 5bf000757522..42a678e92fc6 100644 --- a/trunk/drivers/staging/iio/imu/adis16400_trigger.c +++ b/trunk/drivers/staging/iio/imu/adis16400_trigger.c @@ -3,8 +3,8 @@ #include #include -#include "../iio.h" -#include "../trigger.h" +#include +#include #include "adis16400.h" /** @@ -29,7 +29,7 @@ int adis16400_probe_trigger(struct iio_dev *indio_dev) int ret; struct adis16400_state *st = iio_priv(indio_dev); - st->trig = iio_allocate_trigger("%s-dev%d", + st->trig = iio_trigger_alloc("%s-dev%d", indio_dev->name, indio_dev->id); if (st->trig == NULL) { @@ -59,7 +59,7 @@ int adis16400_probe_trigger(struct iio_dev *indio_dev) error_free_irq: free_irq(st->us->irq, st->trig); error_free_trig: - iio_free_trigger(st->trig); + iio_trigger_free(st->trig); error_ret: return ret; } @@ -70,5 +70,5 @@ void adis16400_remove_trigger(struct iio_dev *indio_dev) iio_trigger_unregister(st->trig); free_irq(st->us->irq, st->trig); - iio_free_trigger(st->trig); + iio_trigger_free(st->trig); } diff --git a/trunk/drivers/staging/iio/kfifo_buf.h b/trunk/drivers/staging/iio/kfifo_buf.h deleted file mode 100644 index 9f7da016af04..000000000000 --- a/trunk/drivers/staging/iio/kfifo_buf.h +++ /dev/null @@ -1,8 +0,0 @@ - -#include -#include "iio.h" -#include "buffer.h" - -struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev); -void iio_kfifo_free(struct iio_buffer *r); - diff --git a/trunk/drivers/staging/iio/light/Kconfig b/trunk/drivers/staging/iio/light/Kconfig index e7e9159d9895..4bed30eac3ed 100644 --- a/trunk/drivers/staging/iio/light/Kconfig +++ b/trunk/drivers/staging/iio/light/Kconfig @@ -4,15 +4,26 @@ menu "Light sensors" config SENSORS_ISL29018 - tristate "ISL 29018 light and proximity sensor" - depends on I2C - default n - help - If you say yes here you get support for ambient light sensing and - proximity infrared sensing from Intersil ISL29018. - This driver will provide the measurements of ambient light intensity - in lux, proximity infrared sensing and normal infrared sensing. - Data from sensor is accessible via sysfs. + tristate "ISL 29018 light and proximity sensor" + depends on I2C + select REGMAP_I2C + default n + help + If you say yes here you get support for ambient light sensing and + proximity infrared sensing from Intersil ISL29018. + This driver will provide the measurements of ambient light intensity + in lux, proximity infrared sensing and normal infrared sensing. + Data from sensor is accessible via sysfs. + +config SENSORS_ISL29028 + tristate "Intersil ISL29028 Concurrent Light and Proximity Sensor" + depends on I2C + select REGMAP_I2C + help + Provides driver for the Intersil's ISL29028 device. + This driver supports the sysfs interface to get the ALS, IR intensity, + Proximity value via iio. The ISL29028 provides the concurrent sensing + of ambient light and proximity. config SENSORS_TSL2563 tristate "TAOS TSL2560, TSL2561, TSL2562 and TSL2563 ambient light sensors" @@ -31,4 +42,12 @@ config TSL2583 Provides support for the TAOS tsl2580, tsl2581 and tsl2583 devices. Access ALS data via iio, sysfs. +config TSL2x7x + tristate "TAOS TSL/TMD2x71 and TSL/TMD2x72 Family of light and proximity sensors" + depends on I2C + help + Support for: tsl2571, tsl2671, tmd2671, tsl2771, tmd2771, tsl2572, tsl2672, + tmd2672, tsl2772, tmd2772 devices. + Provides iio_events and direct access via sysfs. + endmenu diff --git a/trunk/drivers/staging/iio/light/Makefile b/trunk/drivers/staging/iio/light/Makefile index 3011fbfa8dc2..141af1eb164c 100644 --- a/trunk/drivers/staging/iio/light/Makefile +++ b/trunk/drivers/staging/iio/light/Makefile @@ -4,4 +4,6 @@ obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o +obj-$(CONFIG_SENSORS_ISL29028) += isl29028.o obj-$(CONFIG_TSL2583) += tsl2583.o +obj-$(CONFIG_TSL2x7x) += tsl2x7x_core.o diff --git a/trunk/drivers/staging/iio/light/isl29018.c b/trunk/drivers/staging/iio/light/isl29018.c index 38ec52b65dfa..0abbf18d6103 100644 --- a/trunk/drivers/staging/iio/light/isl29018.c +++ b/trunk/drivers/staging/iio/light/isl29018.c @@ -26,9 +26,11 @@ #include #include #include +#include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include + #define CONVERSION_TIME_MS 100 #define ISL29018_REG_ADD_COMMAND1 0x00 @@ -51,49 +53,22 @@ #define ISL29018_REG_ADD_DATA_LSB 0x02 #define ISL29018_REG_ADD_DATA_MSB 0x03 -#define ISL29018_MAX_REGS (ISL29018_REG_ADD_DATA_MSB+1) #define ISL29018_REG_TEST 0x08 #define ISL29018_TEST_SHIFT 0 #define ISL29018_TEST_MASK (0xFF << ISL29018_TEST_SHIFT) struct isl29018_chip { - struct i2c_client *client; + struct device *dev; + struct regmap *regmap; struct mutex lock; unsigned int lux_scale; unsigned int range; unsigned int adc_bit; int prox_scheme; - u8 reg_cache[ISL29018_MAX_REGS]; }; -static int isl29018_write_data(struct i2c_client *client, u8 reg, - u8 val, u8 mask, u8 shift) -{ - u8 regval = val; - int ret; - struct isl29018_chip *chip = iio_priv(i2c_get_clientdata(client)); - - /* don't cache or mask REG_TEST */ - if (reg < ISL29018_MAX_REGS) { - regval = chip->reg_cache[reg]; - regval &= ~mask; - regval |= val << shift; - } - - ret = i2c_smbus_write_byte_data(client, reg, regval); - if (ret) { - dev_err(&client->dev, "Write to device fails status %x\n", ret); - } else { - /* don't update cache on err */ - if (reg < ISL29018_MAX_REGS) - chip->reg_cache[reg] = regval; - } - - return ret; -} - -static int isl29018_set_range(struct i2c_client *client, unsigned long range, +static int isl29018_set_range(struct isl29018_chip *chip, unsigned long range, unsigned int *new_range) { static const unsigned long supp_ranges[] = {1000, 4000, 16000, 64000}; @@ -109,11 +84,11 @@ static int isl29018_set_range(struct i2c_client *client, unsigned long range, if (i >= ARRAY_SIZE(supp_ranges)) return -EINVAL; - return isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII, - i, COMMANDII_RANGE_MASK, COMMANDII_RANGE_SHIFT); + return regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMANDII, + COMMANDII_RANGE_MASK, i << COMMANDII_RANGE_SHIFT); } -static int isl29018_set_resolution(struct i2c_client *client, +static int isl29018_set_resolution(struct isl29018_chip *chip, unsigned long adcbit, unsigned int *conf_adc_bit) { static const unsigned long supp_adcbit[] = {16, 12, 8, 4}; @@ -129,48 +104,49 @@ static int isl29018_set_resolution(struct i2c_client *client, if (i >= ARRAY_SIZE(supp_adcbit)) return -EINVAL; - return isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII, - i, COMMANDII_RESOLUTION_MASK, - COMMANDII_RESOLUTION_SHIFT); + return regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMANDII, + COMMANDII_RESOLUTION_MASK, + i << COMMANDII_RESOLUTION_SHIFT); } -static int isl29018_read_sensor_input(struct i2c_client *client, int mode) +static int isl29018_read_sensor_input(struct isl29018_chip *chip, int mode) { int status; - int lsb; - int msb; + unsigned int lsb; + unsigned int msb; /* Set mode */ - status = isl29018_write_data(client, ISL29018_REG_ADD_COMMAND1, - mode, COMMMAND1_OPMODE_MASK, COMMMAND1_OPMODE_SHIFT); + status = regmap_write(chip->regmap, ISL29018_REG_ADD_COMMAND1, + mode << COMMMAND1_OPMODE_SHIFT); if (status) { - dev_err(&client->dev, "Error in setting operating mode\n"); + dev_err(chip->dev, + "Error in setting operating mode err %d\n", status); return status; } msleep(CONVERSION_TIME_MS); - lsb = i2c_smbus_read_byte_data(client, ISL29018_REG_ADD_DATA_LSB); - if (lsb < 0) { - dev_err(&client->dev, "Error in reading LSB DATA\n"); - return lsb; + status = regmap_read(chip->regmap, ISL29018_REG_ADD_DATA_LSB, &lsb); + if (status < 0) { + dev_err(chip->dev, + "Error in reading LSB DATA with err %d\n", status); + return status; } - msb = i2c_smbus_read_byte_data(client, ISL29018_REG_ADD_DATA_MSB); - if (msb < 0) { - dev_err(&client->dev, "Error in reading MSB DATA\n"); - return msb; + status = regmap_read(chip->regmap, ISL29018_REG_ADD_DATA_MSB, &msb); + if (status < 0) { + dev_err(chip->dev, + "Error in reading MSB DATA with error %d\n", status); + return status; } - dev_vdbg(&client->dev, "MSB 0x%x and LSB 0x%x\n", msb, lsb); + dev_vdbg(chip->dev, "MSB 0x%x and LSB 0x%x\n", msb, lsb); return (msb << 8) | lsb; } -static int isl29018_read_lux(struct i2c_client *client, int *lux) +static int isl29018_read_lux(struct isl29018_chip *chip, int *lux) { int lux_data; - struct isl29018_chip *chip = iio_priv(i2c_get_clientdata(client)); - lux_data = isl29018_read_sensor_input(client, - COMMMAND1_OPMODE_ALS_ONCE); + lux_data = isl29018_read_sensor_input(chip, COMMMAND1_OPMODE_ALS_ONCE); if (lux_data < 0) return lux_data; @@ -180,11 +156,11 @@ static int isl29018_read_lux(struct i2c_client *client, int *lux) return 0; } -static int isl29018_read_ir(struct i2c_client *client, int *ir) +static int isl29018_read_ir(struct isl29018_chip *chip, int *ir) { int ir_data; - ir_data = isl29018_read_sensor_input(client, COMMMAND1_OPMODE_IR_ONCE); + ir_data = isl29018_read_sensor_input(chip, COMMMAND1_OPMODE_IR_ONCE); if (ir_data < 0) return ir_data; @@ -194,7 +170,7 @@ static int isl29018_read_ir(struct i2c_client *client, int *ir) return 0; } -static int isl29018_read_proximity_ir(struct i2c_client *client, int scheme, +static int isl29018_read_proximity_ir(struct isl29018_chip *chip, int scheme, int *near_ir) { int status; @@ -202,14 +178,15 @@ static int isl29018_read_proximity_ir(struct i2c_client *client, int scheme, int ir_data = -1; /* Do proximity sensing with required scheme */ - status = isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII, - scheme, COMMANDII_SCHEME_MASK, COMMANDII_SCHEME_SHIFT); + status = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMANDII, + COMMANDII_SCHEME_MASK, + scheme << COMMANDII_SCHEME_SHIFT); if (status) { - dev_err(&client->dev, "Error in setting operating mode\n"); + dev_err(chip->dev, "Error in setting operating mode\n"); return status; } - prox_data = isl29018_read_sensor_input(client, + prox_data = isl29018_read_sensor_input(chip, COMMMAND1_OPMODE_PROX_ONCE); if (prox_data < 0) return prox_data; @@ -219,8 +196,7 @@ static int isl29018_read_proximity_ir(struct i2c_client *client, int scheme, return 0; } - ir_data = isl29018_read_sensor_input(client, - COMMMAND1_OPMODE_IR_ONCE); + ir_data = isl29018_read_sensor_input(chip, COMMMAND1_OPMODE_IR_ONCE); if (ir_data < 0) return ir_data; @@ -238,7 +214,7 @@ static int isl29018_read_proximity_ir(struct i2c_client *client, int scheme, static ssize_t show_range(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct isl29018_chip *chip = iio_priv(indio_dev); return sprintf(buf, "%u\n", chip->range); @@ -247,9 +223,8 @@ static ssize_t show_range(struct device *dev, static ssize_t store_range(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct isl29018_chip *chip = iio_priv(indio_dev); - struct i2c_client *client = chip->client; int status; unsigned long lval; unsigned int new_range; @@ -264,10 +239,11 @@ static ssize_t store_range(struct device *dev, } mutex_lock(&chip->lock); - status = isl29018_set_range(client, lval, &new_range); + status = isl29018_set_range(chip, lval, &new_range); if (status < 0) { mutex_unlock(&chip->lock); - dev_err(dev, "Error in setting max range\n"); + dev_err(dev, + "Error in setting max range with err %d\n", status); return status; } chip->range = new_range; @@ -280,7 +256,7 @@ static ssize_t store_range(struct device *dev, static ssize_t show_resolution(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct isl29018_chip *chip = iio_priv(indio_dev); return sprintf(buf, "%u\n", chip->adc_bit); @@ -289,9 +265,8 @@ static ssize_t show_resolution(struct device *dev, static ssize_t store_resolution(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct isl29018_chip *chip = iio_priv(indio_dev); - struct i2c_client *client = chip->client; int status; unsigned long lval; unsigned int new_adc_bit; @@ -304,7 +279,7 @@ static ssize_t store_resolution(struct device *dev, } mutex_lock(&chip->lock); - status = isl29018_set_resolution(client, lval, &new_adc_bit); + status = isl29018_set_resolution(chip, lval, &new_adc_bit); if (status < 0) { mutex_unlock(&chip->lock); dev_err(dev, "Error in setting resolution\n"); @@ -320,7 +295,7 @@ static ssize_t store_resolution(struct device *dev, static ssize_t show_prox_infrared_supression(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct isl29018_chip *chip = iio_priv(indio_dev); /* return the "proximity scheme" i.e. if the chip does on chip @@ -331,7 +306,7 @@ static ssize_t show_prox_infrared_supression(struct device *dev, static ssize_t store_prox_infrared_supression(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct isl29018_chip *chip = iio_priv(indio_dev); unsigned long lval; @@ -379,20 +354,20 @@ static int isl29018_read_raw(struct iio_dev *indio_dev, { int ret = -EINVAL; struct isl29018_chip *chip = iio_priv(indio_dev); - struct i2c_client *client = chip->client; mutex_lock(&chip->lock); switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: + case IIO_CHAN_INFO_PROCESSED: switch (chan->type) { case IIO_LIGHT: - ret = isl29018_read_lux(client, val); + ret = isl29018_read_lux(chip, val); break; case IIO_INTENSITY: - ret = isl29018_read_ir(client, val); + ret = isl29018_read_ir(chip, val); break; case IIO_PROXIMITY: - ret = isl29018_read_proximity_ir(client, + ret = isl29018_read_proximity_ir(chip, chip->prox_scheme, val); break; default: @@ -419,15 +394,17 @@ static const struct iio_chan_spec isl29018_channels[] = { .type = IIO_LIGHT, .indexed = 1, .channel = 0, - .processed_val = IIO_PROCESSED, - .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, + .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, }, { .type = IIO_INTENSITY, .modified = 1, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .channel2 = IIO_MOD_LIGHT_IR, }, { /* Unindexed in current ABI. But perhaps it should be. */ .type = IIO_PROXIMITY, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, } }; @@ -456,15 +433,12 @@ static const struct attribute_group isl29108_group = { .attrs = isl29018_attributes, }; -static int isl29018_chip_init(struct i2c_client *client) +static int isl29018_chip_init(struct isl29018_chip *chip) { - struct isl29018_chip *chip = iio_priv(i2c_get_clientdata(client)); int status; int new_adc_bit; unsigned int new_range; - memset(chip->reg_cache, 0, sizeof(chip->reg_cache)); - /* Code added per Intersil Application Note 1534: * When VDD sinks to approximately 1.8V or below, some of * the part's registers may change their state. When VDD @@ -485,10 +459,9 @@ static int isl29018_chip_init(struct i2c_client *client) * the same thing EXCEPT the data sheet asks for a 1ms delay after * writing the CMD1 register. */ - status = isl29018_write_data(client, ISL29018_REG_TEST, 0, - ISL29018_TEST_MASK, ISL29018_TEST_SHIFT); + status = regmap_write(chip->regmap, ISL29018_REG_TEST, 0x0); if (status < 0) { - dev_err(&client->dev, "Failed to clear isl29018 TEST reg." + dev_err(chip->dev, "Failed to clear isl29018 TEST reg." "(%d)\n", status); return status; } @@ -497,10 +470,9 @@ static int isl29018_chip_init(struct i2c_client *client) * "Operating Mode" (COMMAND1) register is reprogrammed when * data is read from the device. */ - status = isl29018_write_data(client, ISL29018_REG_ADD_COMMAND1, 0, - 0xff, 0); + status = regmap_write(chip->regmap, ISL29018_REG_ADD_COMMAND1, 0); if (status < 0) { - dev_err(&client->dev, "Failed to clear isl29018 CMD1 reg." + dev_err(chip->dev, "Failed to clear isl29018 CMD1 reg." "(%d)\n", status); return status; } @@ -508,13 +480,13 @@ static int isl29018_chip_init(struct i2c_client *client) msleep(1); /* per data sheet, page 10 */ /* set defaults */ - status = isl29018_set_range(client, chip->range, &new_range); + status = isl29018_set_range(chip, chip->range, &new_range); if (status < 0) { - dev_err(&client->dev, "Init of isl29018 fails\n"); + dev_err(chip->dev, "Init of isl29018 fails\n"); return status; } - status = isl29018_set_resolution(client, chip->adc_bit, + status = isl29018_set_resolution(chip, chip->adc_bit, &new_adc_bit); return 0; @@ -527,6 +499,32 @@ static const struct iio_info isl29108_info = { .write_raw = &isl29018_write_raw, }; +static bool is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ISL29018_REG_ADD_DATA_LSB: + case ISL29018_REG_ADD_DATA_MSB: + case ISL29018_REG_ADD_COMMAND1: + case ISL29018_REG_TEST: + return true; + default: + return false; + } +} + +/* + * isl29018_regmap_config: regmap configuration. + * Use RBTREE mechanism for caching. + */ +static const struct regmap_config isl29018_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_reg = is_volatile_reg, + .max_register = ISL29018_REG_TEST, + .num_reg_defaults_raw = ISL29018_REG_TEST + 1, + .cache_type = REGCACHE_RBTREE, +}; + static int __devinit isl29018_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -534,7 +532,7 @@ static int __devinit isl29018_probe(struct i2c_client *client, struct iio_dev *indio_dev; int err; - indio_dev = iio_allocate_device(sizeof(*chip)); + indio_dev = iio_device_alloc(sizeof(*chip)); if (indio_dev == NULL) { dev_err(&client->dev, "iio allocation fails\n"); err = -ENOMEM; @@ -543,7 +541,7 @@ static int __devinit isl29018_probe(struct i2c_client *client, chip = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); - chip->client = client; + chip->dev = &client->dev; mutex_init(&chip->lock); @@ -551,7 +549,14 @@ static int __devinit isl29018_probe(struct i2c_client *client, chip->range = 1000; chip->adc_bit = 16; - err = isl29018_chip_init(client); + chip->regmap = devm_regmap_init_i2c(client, &isl29018_regmap_config); + if (IS_ERR(chip->regmap)) { + err = PTR_ERR(chip->regmap); + dev_err(chip->dev, "regmap initialization failed: %d\n", err); + goto exit; + } + + err = isl29018_chip_init(chip); if (err) goto exit_iio_free; @@ -569,7 +574,7 @@ static int __devinit isl29018_probe(struct i2c_client *client, return 0; exit_iio_free: - iio_free_device(indio_dev); + iio_device_free(indio_dev); exit: return err; } @@ -580,7 +585,7 @@ static int __devexit isl29018_remove(struct i2c_client *client) dev_dbg(&client->dev, "%s()\n", __func__); iio_device_unregister(indio_dev); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } @@ -593,7 +598,7 @@ static const struct i2c_device_id isl29018_id[] = { MODULE_DEVICE_TABLE(i2c, isl29018_id); static const struct of_device_id isl29018_of_match[] = { - { .compatible = "invn,isl29018", }, + { .compatible = "isil,isl29018", }, { }, }; MODULE_DEVICE_TABLE(of, isl29018_of_match); diff --git a/trunk/drivers/staging/iio/light/isl29028.c b/trunk/drivers/staging/iio/light/isl29028.c new file mode 100644 index 000000000000..33a4c3f94a14 --- /dev/null +++ b/trunk/drivers/staging/iio/light/isl29028.c @@ -0,0 +1,566 @@ +/* + * IIO driver for the light sensor ISL29028. + * ISL29028 is Concurrent Ambient Light and Proximity Sensor + * + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CONVERSION_TIME_MS 100 + +#define ISL29028_REG_CONFIGURE 0x01 + +#define CONFIGURE_ALS_IR_MODE_ALS 0 +#define CONFIGURE_ALS_IR_MODE_IR BIT(0) +#define CONFIGURE_ALS_IR_MODE_MASK BIT(0) + +#define CONFIGURE_ALS_RANGE_LOW_LUX 0 +#define CONFIGURE_ALS_RANGE_HIGH_LUX BIT(1) +#define CONFIGURE_ALS_RANGE_MASK BIT(1) + +#define CONFIGURE_ALS_DIS 0 +#define CONFIGURE_ALS_EN BIT(2) +#define CONFIGURE_ALS_EN_MASK BIT(2) + +#define CONFIGURE_PROX_DRIVE BIT(3) + +#define CONFIGURE_PROX_SLP_SH 4 +#define CONFIGURE_PROX_SLP_MASK (7 << CONFIGURE_PROX_SLP_SH) + +#define CONFIGURE_PROX_EN BIT(7) +#define CONFIGURE_PROX_EN_MASK BIT(7) + +#define ISL29028_REG_INTERRUPT 0x02 + +#define ISL29028_REG_PROX_DATA 0x08 +#define ISL29028_REG_ALSIR_L 0x09 +#define ISL29028_REG_ALSIR_U 0x0A + +#define ISL29028_REG_TEST1_MODE 0x0E +#define ISL29028_REG_TEST2_MODE 0x0F + +#define ISL29028_NUM_REGS (ISL29028_REG_TEST2_MODE + 1) + +enum als_ir_mode { + MODE_NONE = 0, + MODE_ALS, + MODE_IR +}; + +struct isl29028_chip { + struct device *dev; + struct mutex lock; + struct regmap *regmap; + + unsigned int prox_sampling; + bool enable_prox; + + int lux_scale; + int als_ir_mode; +}; + +static int isl29028_set_proxim_sampling(struct isl29028_chip *chip, + unsigned int sampling) +{ + static unsigned int prox_period[] = {800, 400, 200, 100, 75, 50, 12, 0}; + int sel; + unsigned int period = DIV_ROUND_UP(1000, sampling); + + for (sel = 0; sel < ARRAY_SIZE(prox_period); ++sel) { + if (period >= prox_period[sel]) + break; + } + return regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, + CONFIGURE_PROX_SLP_MASK, sel << CONFIGURE_PROX_SLP_SH); +} + +static int isl29028_enable_proximity(struct isl29028_chip *chip, bool enable) +{ + int ret; + int val = 0; + + if (enable) + val = CONFIGURE_PROX_EN; + ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, + CONFIGURE_PROX_EN_MASK, val); + if (ret < 0) + return ret; + + /* Wait for conversion to be complete for first sample */ + mdelay(DIV_ROUND_UP(1000, chip->prox_sampling)); + return 0; +} + +static int isl29028_set_als_scale(struct isl29028_chip *chip, int lux_scale) +{ + int val = (lux_scale == 2000) ? CONFIGURE_ALS_RANGE_HIGH_LUX : + CONFIGURE_ALS_RANGE_LOW_LUX; + + return regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, + CONFIGURE_ALS_RANGE_MASK, val); +} + +static int isl29028_set_als_ir_mode(struct isl29028_chip *chip, + enum als_ir_mode mode) +{ + int ret = 0; + + switch (mode) { + case MODE_ALS: + ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, + CONFIGURE_ALS_IR_MODE_MASK, CONFIGURE_ALS_IR_MODE_ALS); + if (ret < 0) + return ret; + + ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, + CONFIGURE_ALS_RANGE_MASK, CONFIGURE_ALS_RANGE_HIGH_LUX); + break; + + case MODE_IR: + ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, + CONFIGURE_ALS_IR_MODE_MASK, CONFIGURE_ALS_IR_MODE_IR); + break; + + case MODE_NONE: + return regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, + CONFIGURE_ALS_EN_MASK, CONFIGURE_ALS_DIS); + } + + if (ret < 0) + return ret; + + /* Enable the ALS/IR */ + ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, + CONFIGURE_ALS_EN_MASK, CONFIGURE_ALS_EN); + if (ret < 0) + return ret; + + /* Need to wait for conversion time if ALS/IR mode enabled */ + mdelay(CONVERSION_TIME_MS); + return 0; +} + +static int isl29028_read_als_ir(struct isl29028_chip *chip, int *als_ir) +{ + unsigned int lsb; + unsigned int msb; + int ret; + + ret = regmap_read(chip->regmap, ISL29028_REG_ALSIR_L, &lsb); + if (ret < 0) { + dev_err(chip->dev, + "Error in reading register ALSIR_L err %d\n", ret); + return ret; + } + + ret = regmap_read(chip->regmap, ISL29028_REG_ALSIR_U, &msb); + if (ret < 0) { + dev_err(chip->dev, + "Error in reading register ALSIR_U err %d\n", ret); + return ret; + } + + *als_ir = ((msb & 0xF) << 8) | (lsb & 0xFF); + return 0; +} + +static int isl29028_read_proxim(struct isl29028_chip *chip, int *prox) +{ + unsigned int data; + int ret; + + ret = regmap_read(chip->regmap, ISL29028_REG_PROX_DATA, &data); + if (ret < 0) { + dev_err(chip->dev, "Error in reading register %d, error %d\n", + ISL29028_REG_PROX_DATA, ret); + return ret; + } + *prox = data; + return 0; +} + +static int isl29028_proxim_get(struct isl29028_chip *chip, int *prox_data) +{ + int ret; + + if (!chip->enable_prox) { + ret = isl29028_enable_proximity(chip, true); + if (ret < 0) + return ret; + chip->enable_prox = true; + } + return isl29028_read_proxim(chip, prox_data); +} + +static int isl29028_als_get(struct isl29028_chip *chip, int *als_data) +{ + int ret; + int als_ir_data; + + if (chip->als_ir_mode != MODE_ALS) { + ret = isl29028_set_als_ir_mode(chip, MODE_ALS); + if (ret < 0) { + dev_err(chip->dev, + "Error in enabling ALS mode err %d\n", ret); + return ret; + } + chip->als_ir_mode = MODE_ALS; + } + + ret = isl29028_read_als_ir(chip, &als_ir_data); + if (ret < 0) + return ret; + + /* + * convert als data count to lux. + * if lux_scale = 125, lux = count * 0.031 + * if lux_scale = 2000, lux = count * 0.49 + */ + if (chip->lux_scale == 125) + als_ir_data = (als_ir_data * 31) / 1000; + else + als_ir_data = (als_ir_data * 49) / 100; + + *als_data = als_ir_data; + return 0; +} + +static int isl29028_ir_get(struct isl29028_chip *chip, int *ir_data) +{ + int ret; + + if (chip->als_ir_mode != MODE_IR) { + ret = isl29028_set_als_ir_mode(chip, MODE_IR); + if (ret < 0) { + dev_err(chip->dev, + "Error in enabling IR mode err %d\n", ret); + return ret; + } + chip->als_ir_mode = MODE_IR; + } + return isl29028_read_als_ir(chip, ir_data); +} + +/* Channel IO */ +static int isl29028_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, int val2, long mask) +{ + struct isl29028_chip *chip = iio_priv(indio_dev); + int ret = -EINVAL; + + mutex_lock(&chip->lock); + switch (chan->type) { + case IIO_PROXIMITY: + if (mask != IIO_CHAN_INFO_SAMP_FREQ) { + dev_err(chip->dev, + "proximity: mask value 0x%08lx not supported\n", + mask); + break; + } + if (val < 1 || val > 100) { + dev_err(chip->dev, + "Samp_freq %d is not in range[1:100]\n", val); + break; + } + ret = isl29028_set_proxim_sampling(chip, val); + if (ret < 0) { + dev_err(chip->dev, + "Setting proximity samp_freq fail, err %d\n", + ret); + break; + } + chip->prox_sampling = val; + break; + + case IIO_LIGHT: + if (mask != IIO_CHAN_INFO_SCALE) { + dev_err(chip->dev, + "light: mask value 0x%08lx not supported\n", + mask); + break; + } + if ((val != 125) && (val != 2000)) { + dev_err(chip->dev, + "lux scale %d is invalid [125, 2000]\n", val); + break; + } + ret = isl29028_set_als_scale(chip, val); + if (ret < 0) { + dev_err(chip->dev, + "Setting lux scale fail with error %d\n", ret); + break; + } + chip->lux_scale = val; + break; + + default: + dev_err(chip->dev, "Unsupported channel type\n"); + break; + } + mutex_unlock(&chip->lock); + return ret; +} + +static int isl29028_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, int *val2, long mask) +{ + struct isl29028_chip *chip = iio_priv(indio_dev); + int ret = -EINVAL; + + mutex_lock(&chip->lock); + switch (mask) { + case IIO_CHAN_INFO_RAW: + case IIO_CHAN_INFO_PROCESSED: + switch (chan->type) { + case IIO_LIGHT: + ret = isl29028_als_get(chip, val); + break; + case IIO_INTENSITY: + ret = isl29028_ir_get(chip, val); + break; + case IIO_PROXIMITY: + ret = isl29028_proxim_get(chip, val); + break; + default: + break; + } + if (ret < 0) + break; + ret = IIO_VAL_INT; + break; + + case IIO_CHAN_INFO_SAMP_FREQ: + if (chan->type != IIO_PROXIMITY) + break; + *val = chip->prox_sampling; + ret = IIO_VAL_INT; + break; + + case IIO_CHAN_INFO_SCALE: + if (chan->type != IIO_LIGHT) + break; + *val = chip->lux_scale; + ret = IIO_VAL_INT; + break; + + default: + dev_err(chip->dev, "mask value 0x%08lx not supported\n", mask); + break; + } + mutex_unlock(&chip->lock); + return ret; +} + +static IIO_CONST_ATTR(in_proximity_sampling_frequency_available, + "1, 3, 5, 10, 13, 20, 83, 100"); +static IIO_CONST_ATTR(in_illuminance_scale_available, "125, 2000"); + +#define ISL29028_DEV_ATTR(name) (&iio_dev_attr_##name.dev_attr.attr) +#define ISL29028_CONST_ATTR(name) (&iio_const_attr_##name.dev_attr.attr) +static struct attribute *isl29028_attributes[] = { + ISL29028_CONST_ATTR(in_proximity_sampling_frequency_available), + ISL29028_CONST_ATTR(in_illuminance_scale_available), + NULL, +}; + +static const struct attribute_group isl29108_group = { + .attrs = isl29028_attributes, +}; + +static const struct iio_chan_spec isl29028_channels[] = { + { + .type = IIO_LIGHT, + .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + }, { + .type = IIO_INTENSITY, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, + }, { + .type = IIO_PROXIMITY, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SAMP_FREQ_SEPARATE_BIT, + } +}; + +static const struct iio_info isl29028_info = { + .attrs = &isl29108_group, + .driver_module = THIS_MODULE, + .read_raw = &isl29028_read_raw, + .write_raw = &isl29028_write_raw, +}; + +static int isl29028_chip_init(struct isl29028_chip *chip) +{ + int ret; + + chip->enable_prox = false; + chip->prox_sampling = 20; + chip->lux_scale = 2000; + chip->als_ir_mode = MODE_NONE; + + ret = regmap_write(chip->regmap, ISL29028_REG_TEST1_MODE, 0x0); + if (ret < 0) { + dev_err(chip->dev, "%s(): write to reg %d failed, err = %d\n", + __func__, ISL29028_REG_TEST1_MODE, ret); + return ret; + } + ret = regmap_write(chip->regmap, ISL29028_REG_TEST2_MODE, 0x0); + if (ret < 0) { + dev_err(chip->dev, "%s(): write to reg %d failed, err = %d\n", + __func__, ISL29028_REG_TEST2_MODE, ret); + return ret; + } + + ret = regmap_write(chip->regmap, ISL29028_REG_CONFIGURE, 0x0); + if (ret < 0) { + dev_err(chip->dev, "%s(): write to reg %d failed, err = %d\n", + __func__, ISL29028_REG_CONFIGURE, ret); + return ret; + } + + ret = isl29028_set_proxim_sampling(chip, chip->prox_sampling); + if (ret < 0) { + dev_err(chip->dev, "%s(): setting the proximity, err = %d\n", + __func__, ret); + return ret; + } + + ret = isl29028_set_als_scale(chip, chip->lux_scale); + if (ret < 0) + dev_err(chip->dev, "%s(): setting als scale failed, err = %d\n", + __func__, ret); + return ret; +} + +static bool is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ISL29028_REG_INTERRUPT: + case ISL29028_REG_PROX_DATA: + case ISL29028_REG_ALSIR_L: + case ISL29028_REG_ALSIR_U: + return true; + default: + return false; + } +} + +static const struct regmap_config isl29028_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_reg = is_volatile_reg, + .max_register = ISL29028_NUM_REGS - 1, + .num_reg_defaults_raw = ISL29028_NUM_REGS, + .cache_type = REGCACHE_RBTREE, +}; + +static int __devinit isl29028_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct isl29028_chip *chip; + struct iio_dev *indio_dev; + int ret; + + indio_dev = iio_device_alloc(sizeof(*chip)); + if (!indio_dev) { + dev_err(&client->dev, "iio allocation fails\n"); + return -ENOMEM; + } + + chip = iio_priv(indio_dev); + + i2c_set_clientdata(client, indio_dev); + chip->dev = &client->dev; + mutex_init(&chip->lock); + + chip->regmap = devm_regmap_init_i2c(client, &isl29028_regmap_config); + if (IS_ERR(chip->regmap)) { + ret = PTR_ERR(chip->regmap); + dev_err(chip->dev, "regmap initialization failed: %d\n", ret); + goto exit_iio_free; + } + + ret = isl29028_chip_init(chip); + if (ret < 0) { + dev_err(chip->dev, "chip initialization failed: %d\n", ret); + goto exit_iio_free; + } + + indio_dev->info = &isl29028_info; + indio_dev->channels = isl29028_channels; + indio_dev->num_channels = ARRAY_SIZE(isl29028_channels); + indio_dev->name = id->name; + indio_dev->dev.parent = &client->dev; + indio_dev->modes = INDIO_DIRECT_MODE; + ret = iio_device_register(indio_dev); + if (ret < 0) { + dev_err(chip->dev, "iio registration fails with error %d\n", + ret); + goto exit_iio_free; + } + return 0; + +exit_iio_free: + iio_device_free(indio_dev); + return ret; +} + +static int __devexit isl29028_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + + iio_device_unregister(indio_dev); + iio_device_free(indio_dev); + return 0; +} + +static const struct i2c_device_id isl29028_id[] = { + {"isl29028", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, isl29028_id); + +static const struct of_device_id isl29028_of_match[] = { + { .compatible = "isil,isl29028", }, + { }, +}; +MODULE_DEVICE_TABLE(of, isl29028_of_match); + +static struct i2c_driver isl29028_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "isl29028", + .owner = THIS_MODULE, + .of_match_table = isl29028_of_match, + }, + .probe = isl29028_probe, + .remove = __devexit_p(isl29028_remove), + .id_table = isl29028_id, +}; + +module_i2c_driver(isl29028_driver); + +MODULE_DESCRIPTION("ISL29028 Ambient Light and Proximity Sensor driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Laxman Dewangan "); diff --git a/trunk/drivers/staging/iio/light/tsl2563.c b/trunk/drivers/staging/iio/light/tsl2563.c index 546c95a4ea9e..9d740be43a82 100644 --- a/trunk/drivers/staging/iio/light/tsl2563.c +++ b/trunk/drivers/staging/iio/light/tsl2563.c @@ -35,9 +35,9 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../events.h" +#include +#include +#include #include "tsl2563.h" /* Use this many bits for fraction part. */ @@ -465,7 +465,7 @@ static int tsl2563_write_raw(struct iio_dev *indio_dev, { struct tsl2563_chip *chip = iio_priv(indio_dev); - if (chan->channel == 0) + if (chan->channel == IIO_MOD_LIGHT_BOTH) chip->calib0 = calib_from_sysfs(val); else chip->calib1 = calib_from_sysfs(val); @@ -485,7 +485,8 @@ static int tsl2563_read_raw(struct iio_dev *indio_dev, mutex_lock(&chip->lock); switch (m) { - case 0: + case IIO_CHAN_INFO_RAW: + case IIO_CHAN_INFO_PROCESSED: switch (chan->type) { case IIO_LIGHT: ret = tsl2563_get_adc(chip); @@ -534,12 +535,14 @@ static const struct iio_chan_spec tsl2563_channels[] = { { .type = IIO_LIGHT, .indexed = 1, + .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT, .channel = 0, }, { .type = IIO_INTENSITY, .modified = 1, .channel2 = IIO_MOD_LIGHT_BOTH, - .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, .event_mask = (IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | IIO_EV_BIT(IIO_EV_TYPE_THRESH, @@ -548,7 +551,8 @@ static const struct iio_chan_spec tsl2563_channels[] = { .type = IIO_INTENSITY, .modified = 1, .channel2 = IIO_MOD_LIGHT_IR, - .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, } }; @@ -710,7 +714,7 @@ static int __devinit tsl2563_probe(struct i2c_client *client, int err = 0; u8 id = 0; - indio_dev = iio_allocate_device(sizeof(*chip)); + indio_dev = iio_device_alloc(sizeof(*chip)); if (!indio_dev) return -ENOMEM; @@ -797,7 +801,7 @@ static int __devinit tsl2563_probe(struct i2c_client *client, if (client->irq) free_irq(client->irq, indio_dev); fail1: - iio_free_device(indio_dev); + iio_device_free(indio_dev); return err; } @@ -818,7 +822,7 @@ static int tsl2563_remove(struct i2c_client *client) if (client->irq) free_irq(client->irq, indio_dev); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/light/tsl2583.c b/trunk/drivers/staging/iio/light/tsl2583.c index 8671d98e0448..5e23ad5a30d5 100644 --- a/trunk/drivers/staging/iio/light/tsl2583.c +++ b/trunk/drivers/staging/iio/light/tsl2583.c @@ -28,7 +28,7 @@ #include #include #include -#include "../iio.h" +#include #define TSL258X_MAX_DEVICE_REGS 32 @@ -483,7 +483,7 @@ static int taos_chip_off(struct iio_dev *indio_dev) static ssize_t taos_power_state_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct tsl2583_chip *chip = iio_priv(indio_dev); return sprintf(buf, "%d\n", chip->taos_chip_status); @@ -492,7 +492,7 @@ static ssize_t taos_power_state_show(struct device *dev, static ssize_t taos_power_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); unsigned long value; if (strict_strtoul(buf, 0, &value)) @@ -509,7 +509,7 @@ static ssize_t taos_power_state_store(struct device *dev, static ssize_t taos_gain_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct tsl2583_chip *chip = iio_priv(indio_dev); char gain[4] = {0}; @@ -534,7 +534,7 @@ static ssize_t taos_gain_show(struct device *dev, static ssize_t taos_gain_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct tsl2583_chip *chip = iio_priv(indio_dev); unsigned long value; @@ -571,7 +571,7 @@ static ssize_t taos_gain_available_show(struct device *dev, static ssize_t taos_als_time_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct tsl2583_chip *chip = iio_priv(indio_dev); return sprintf(buf, "%d\n", chip->taos_settings.als_time); @@ -580,7 +580,7 @@ static ssize_t taos_als_time_show(struct device *dev, static ssize_t taos_als_time_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct tsl2583_chip *chip = iio_priv(indio_dev); unsigned long value; @@ -608,7 +608,7 @@ static ssize_t taos_als_time_available_show(struct device *dev, static ssize_t taos_als_trim_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct tsl2583_chip *chip = iio_priv(indio_dev); return sprintf(buf, "%d\n", chip->taos_settings.als_gain_trim); @@ -617,7 +617,7 @@ static ssize_t taos_als_trim_show(struct device *dev, static ssize_t taos_als_trim_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct tsl2583_chip *chip = iio_priv(indio_dev); unsigned long value; @@ -633,7 +633,7 @@ static ssize_t taos_als_trim_store(struct device *dev, static ssize_t taos_als_cal_target_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct tsl2583_chip *chip = iio_priv(indio_dev); return sprintf(buf, "%d\n", chip->taos_settings.als_cal_target); @@ -642,7 +642,7 @@ static ssize_t taos_als_cal_target_show(struct device *dev, static ssize_t taos_als_cal_target_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct tsl2583_chip *chip = iio_priv(indio_dev); unsigned long value; @@ -660,7 +660,7 @@ static ssize_t taos_lux_show(struct device *dev, struct device_attribute *attr, { int ret; - ret = taos_get_lux(dev_get_drvdata(dev)); + ret = taos_get_lux(dev_to_iio_dev(dev)); if (ret < 0) return ret; @@ -670,7 +670,7 @@ static ssize_t taos_lux_show(struct device *dev, struct device_attribute *attr, static ssize_t taos_do_calibrate(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); unsigned long value; if (strict_strtoul(buf, 0, &value)) @@ -708,7 +708,7 @@ static ssize_t taos_luxtable_show(struct device *dev, static ssize_t taos_luxtable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct tsl2583_chip *chip = iio_priv(indio_dev); int value[ARRAY_SIZE(taos_device_lux)*3 + 1]; int n; @@ -815,7 +815,7 @@ static int __devinit taos_probe(struct i2c_client *clientp, return -EOPNOTSUPP; } - indio_dev = iio_allocate_device(sizeof(*chip)); + indio_dev = iio_device_alloc(sizeof(*chip)); if (indio_dev == NULL) { ret = -ENOMEM; dev_err(&clientp->dev, "iio allocation failed\n"); @@ -879,7 +879,7 @@ static int __devinit taos_probe(struct i2c_client *clientp, dev_info(&clientp->dev, "Light sensor found.\n"); return 0; fail1: - iio_free_device(indio_dev); + iio_device_free(indio_dev); fail2: return ret; } @@ -926,7 +926,7 @@ static SIMPLE_DEV_PM_OPS(taos_pm_ops, taos_suspend, taos_resume); static int __devexit taos_remove(struct i2c_client *client) { iio_device_unregister(i2c_get_clientdata(client)); - iio_free_device(i2c_get_clientdata(client)); + iio_device_free(i2c_get_clientdata(client)); return 0; } diff --git a/trunk/drivers/staging/iio/light/tsl2x7x.h b/trunk/drivers/staging/iio/light/tsl2x7x.h new file mode 100755 index 000000000000..c4acf5ff1794 --- /dev/null +++ b/trunk/drivers/staging/iio/light/tsl2x7x.h @@ -0,0 +1,100 @@ +/* + * Device driver for monitoring ambient light intensity (lux) + * and proximity (prox) within the TAOS TSL2X7X family of devices. + * + * Copyright (c) 2012, TAOS Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __TSL2X7X_H +#define __TSL2X7X_H +#include + +/* Max number of segments allowable in LUX table */ +#define TSL2X7X_MAX_LUX_TABLE_SIZE 9 +#define MAX_DEFAULT_TABLE_BYTES (sizeof(int) * TSL2X7X_MAX_LUX_TABLE_SIZE) + +struct iio_dev; + +struct tsl2x7x_lux { + unsigned int ratio; + unsigned int ch0; + unsigned int ch1; +}; + +/** + * struct tsl2x7x_default_settings - power on defaults unless + * overridden by platform data. + * @als_time: ALS Integration time - multiple of 50mS + * @als_gain: Index into the ALS gain table. + * @als_gain_trim: default gain trim to account for + * aperture effects. + * @wait_time: Time between PRX and ALS cycles + * in 2.7 periods + * @prx_time: 5.2ms prox integration time - + * decrease in 2.7ms periods + * @prx_gain: Proximity gain index + * @prox_config: Prox configuration filters. + * @als_cal_target: Known external ALS reading for + * calibration. + * @interrupts_en: Enable/Disable - 0x00 = none, 0x10 = als, + * 0x20 = prx, 0x30 = bth + * @persistence: H/W Filters, Number of 'out of limits' + * ADC readings PRX/ALS. + * @als_thresh_low: CH0 'low' count to trigger interrupt. + * @als_thresh_high: CH0 'high' count to trigger interrupt. + * @prox_thres_low: Low threshold proximity detection. + * @prox_thres_high: High threshold proximity detection + * @prox_pulse_count: Number if proximity emitter pulses + * @prox_max_samples_cal: Used for prox cal. + */ +struct tsl2x7x_settings { + int als_time; + int als_gain; + int als_gain_trim; + int wait_time; + int prx_time; + int prox_gain; + int prox_config; + int als_cal_target; + u8 interrupts_en; + u8 persistence; + int als_thresh_low; + int als_thresh_high; + int prox_thres_low; + int prox_thres_high; + int prox_pulse_count; + int prox_max_samples_cal; +}; + +/** + * struct tsl2X7X_platform_data - Platform callback, glass and defaults + * @platform_power: Suspend/resume platform callback + * @power_on: Power on callback + * @power_off: Power off callback + * @platform_lux_table: Device specific glass coefficents + * @platform_default_settings: Device specific power on defaults + * + */ +struct tsl2X7X_platform_data { + int (*platform_power)(struct device *dev, pm_message_t); + int (*power_on) (struct iio_dev *indio_dev); + int (*power_off) (struct i2c_client *dev); + struct tsl2x7x_lux platform_lux_table[TSL2X7X_MAX_LUX_TABLE_SIZE]; + struct tsl2x7x_settings *platform_default_settings; +}; + +#endif /* __TSL2X7X_H */ diff --git a/trunk/drivers/staging/iio/light/tsl2x7x_core.c b/trunk/drivers/staging/iio/light/tsl2x7x_core.c new file mode 100755 index 000000000000..c3b05a1b3ea8 --- /dev/null +++ b/trunk/drivers/staging/iio/light/tsl2x7x_core.c @@ -0,0 +1,2082 @@ +/* + * Device driver for monitoring ambient light intensity in (lux) + * and proximity detection (prox) within the TAOS TSL2X7X family of devices. + * + * Copyright (c) 2012, TAOS Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tsl2x7x.h" + +/* Cal defs*/ +#define PROX_STAT_CAL 0 +#define PROX_STAT_SAMP 1 +#define MAX_SAMPLES_CAL 200 + +/* TSL2X7X Device ID */ +#define TRITON_ID 0x00 +#define SWORDFISH_ID 0x30 +#define HALIBUT_ID 0x20 + +/* Lux calculation constants */ +#define TSL2X7X_LUX_CALC_OVER_FLOW 65535 + +/* TAOS Register definitions - note: + * depending on device, some of these register are not used and the + * register address is benign. + */ +/* 2X7X register offsets */ +#define TSL2X7X_MAX_CONFIG_REG 16 + +/* Device Registers and Masks */ +#define TSL2X7X_CNTRL 0x00 +#define TSL2X7X_ALS_TIME 0X01 +#define TSL2X7X_PRX_TIME 0x02 +#define TSL2X7X_WAIT_TIME 0x03 +#define TSL2X7X_ALS_MINTHRESHLO 0X04 +#define TSL2X7X_ALS_MINTHRESHHI 0X05 +#define TSL2X7X_ALS_MAXTHRESHLO 0X06 +#define TSL2X7X_ALS_MAXTHRESHHI 0X07 +#define TSL2X7X_PRX_MINTHRESHLO 0X08 +#define TSL2X7X_PRX_MINTHRESHHI 0X09 +#define TSL2X7X_PRX_MAXTHRESHLO 0X0A +#define TSL2X7X_PRX_MAXTHRESHHI 0X0B +#define TSL2X7X_PERSISTENCE 0x0C +#define TSL2X7X_PRX_CONFIG 0x0D +#define TSL2X7X_PRX_COUNT 0x0E +#define TSL2X7X_GAIN 0x0F +#define TSL2X7X_NOTUSED 0x10 +#define TSL2X7X_REVID 0x11 +#define TSL2X7X_CHIPID 0x12 +#define TSL2X7X_STATUS 0x13 +#define TSL2X7X_ALS_CHAN0LO 0x14 +#define TSL2X7X_ALS_CHAN0HI 0x15 +#define TSL2X7X_ALS_CHAN1LO 0x16 +#define TSL2X7X_ALS_CHAN1HI 0x17 +#define TSL2X7X_PRX_LO 0x18 +#define TSL2X7X_PRX_HI 0x19 + +/* tsl2X7X cmd reg masks */ +#define TSL2X7X_CMD_REG 0x80 +#define TSL2X7X_CMD_SPL_FN 0x60 + +#define TSL2X7X_CMD_PROX_INT_CLR 0X05 +#define TSL2X7X_CMD_ALS_INT_CLR 0x06 +#define TSL2X7X_CMD_PROXALS_INT_CLR 0X07 + +/* tsl2X7X cntrl reg masks */ +#define TSL2X7X_CNTL_ADC_ENBL 0x02 +#define TSL2X7X_CNTL_PWR_ON 0x01 + +/* tsl2X7X status reg masks */ +#define TSL2X7X_STA_ADC_VALID 0x01 +#define TSL2X7X_STA_PRX_VALID 0x02 +#define TSL2X7X_STA_ADC_PRX_VALID (TSL2X7X_STA_ADC_VALID |\ + TSL2X7X_STA_PRX_VALID) +#define TSL2X7X_STA_ALS_INTR 0x10 +#define TSL2X7X_STA_PRX_INTR 0x20 + +/* tsl2X7X cntrl reg masks */ +#define TSL2X7X_CNTL_REG_CLEAR 0x00 +#define TSL2X7X_CNTL_PROX_INT_ENBL 0X20 +#define TSL2X7X_CNTL_ALS_INT_ENBL 0X10 +#define TSL2X7X_CNTL_WAIT_TMR_ENBL 0X08 +#define TSL2X7X_CNTL_PROX_DET_ENBL 0X04 +#define TSL2X7X_CNTL_PWRON 0x01 +#define TSL2X7X_CNTL_ALSPON_ENBL 0x03 +#define TSL2X7X_CNTL_INTALSPON_ENBL 0x13 +#define TSL2X7X_CNTL_PROXPON_ENBL 0x0F +#define TSL2X7X_CNTL_INTPROXPON_ENBL 0x2F + +/*Prox diode to use */ +#define TSL2X7X_DIODE0 0x10 +#define TSL2X7X_DIODE1 0x20 +#define TSL2X7X_DIODE_BOTH 0x30 + +/* LED Power */ +#define TSL2X7X_mA100 0x00 +#define TSL2X7X_mA50 0x40 +#define TSL2X7X_mA25 0x80 +#define TSL2X7X_mA13 0xD0 +#define TSL2X7X_MAX_TIMER_CNT (0xFF) + +/*Common device IIO EventMask */ +#define TSL2X7X_EVENT_MASK \ + (IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | \ + IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING)), + +#define TSL2X7X_MIN_ITIME 3 + +/* TAOS txx2x7x Device family members */ +enum { + tsl2571, + tsl2671, + tmd2671, + tsl2771, + tmd2771, + tsl2572, + tsl2672, + tmd2672, + tsl2772, + tmd2772 +}; + +enum { + TSL2X7X_CHIP_UNKNOWN = 0, + TSL2X7X_CHIP_WORKING = 1, + TSL2X7X_CHIP_SUSPENDED = 2 +}; + +struct tsl2x7x_parse_result { + int integer; + int fract; +}; + +/* Per-device data */ +struct tsl2x7x_als_info { + u16 als_ch0; + u16 als_ch1; + u16 lux; +}; + +struct tsl2x7x_prox_stat { + int min; + int max; + int mean; + unsigned long stddev; +}; + +struct tsl2x7x_chip_info { + int chan_table_elements; + struct iio_chan_spec channel[4]; + const struct iio_info *info; +}; + +struct tsl2X7X_chip { + kernel_ulong_t id; + struct mutex prox_mutex; + struct mutex als_mutex; + struct i2c_client *client; + u16 prox_data; + struct tsl2x7x_als_info als_cur_info; + struct tsl2x7x_settings tsl2x7x_settings; + struct tsl2X7X_platform_data *pdata; + int als_time_scale; + int als_saturation; + int tsl2x7x_chip_status; + u8 tsl2x7x_config[TSL2X7X_MAX_CONFIG_REG]; + const struct tsl2x7x_chip_info *chip_info; + const struct iio_info *info; + s64 event_timestamp; + /* This structure is intentionally large to accommodate + * updates via sysfs. */ + /* Sized to 9 = max 8 segments + 1 termination segment */ + struct tsl2x7x_lux tsl2x7x_device_lux[TSL2X7X_MAX_LUX_TABLE_SIZE]; +}; + +/* Different devices require different coefficents */ +static const struct tsl2x7x_lux tsl2x71_lux_table[] = { + { 14461, 611, 1211 }, + { 18540, 352, 623 }, + { 0, 0, 0 }, +}; + +static const struct tsl2x7x_lux tmd2x71_lux_table[] = { + { 11635, 115, 256 }, + { 15536, 87, 179 }, + { 0, 0, 0 }, +}; + +static const struct tsl2x7x_lux tsl2x72_lux_table[] = { + { 14013, 466, 917 }, + { 18222, 310, 552 }, + { 0, 0, 0 }, +}; + +static const struct tsl2x7x_lux tmd2x72_lux_table[] = { + { 13218, 130, 262 }, + { 17592, 92, 169 }, + { 0, 0, 0 }, +}; + +static const struct tsl2x7x_lux *tsl2x7x_default_lux_table_group[] = { + [tsl2571] = tsl2x71_lux_table, + [tsl2671] = tsl2x71_lux_table, + [tmd2671] = tmd2x71_lux_table, + [tsl2771] = tsl2x71_lux_table, + [tmd2771] = tmd2x71_lux_table, + [tsl2572] = tsl2x72_lux_table, + [tsl2672] = tsl2x72_lux_table, + [tmd2672] = tmd2x72_lux_table, + [tsl2772] = tsl2x72_lux_table, + [tmd2772] = tmd2x72_lux_table, +}; + +static const struct tsl2x7x_settings tsl2x7x_default_settings = { + .als_time = 219, /* 101 ms */ + .als_gain = 0, + .prx_time = 254, /* 5.4 ms */ + .prox_gain = 1, + .wait_time = 245, + .prox_config = 0, + .als_gain_trim = 1000, + .als_cal_target = 150, + .als_thresh_low = 200, + .als_thresh_high = 256, + .persistence = 255, + .interrupts_en = 0, + .prox_thres_low = 0, + .prox_thres_high = 512, + .prox_max_samples_cal = 30, + .prox_pulse_count = 8 +}; + +static const s16 tsl2X7X_als_gainadj[] = { + 1, + 8, + 16, + 120 +}; + +static const s16 tsl2X7X_prx_gainadj[] = { + 1, + 2, + 4, + 8 +}; + +/* Channel variations */ +enum { + ALS, + PRX, + ALSPRX, + PRX2, + ALSPRX2, +}; + +static const u8 device_channel_config[] = { + ALS, + PRX, + PRX, + ALSPRX, + ALSPRX, + ALS, + PRX2, + PRX2, + ALSPRX2, + ALSPRX2 +}; + +/** + * tsl2x7x_parse_buffer() - parse a decimal result from a buffer. + * @*buf: pointer to char buffer to parse + * @*result: pointer to buffer to contain + * resulting interger / decimal as ints. + * + */ +static int +tsl2x7x_parse_buffer(const char *buf, struct tsl2x7x_parse_result *result) +{ + int integer = 0, fract = 0, fract_mult = 100000; + bool integer_part = true, negative = false; + + if (buf[0] == '-') { + negative = true; + buf++; + } + + while (*buf) { + if ('0' <= *buf && *buf <= '9') { + if (integer_part) + integer = integer*10 + *buf - '0'; + else { + fract += fract_mult*(*buf - '0'); + if (fract_mult == 1) + break; + fract_mult /= 10; + } + } else if (*buf == '\n') { + if (*(buf + 1) == '\0') + break; + else + return -EINVAL; + } else if (*buf == '.') { + integer_part = false; + } else { + return -EINVAL; + } + buf++; + } + if (negative) { + if (integer) + integer = -integer; + else + fract = -fract; + } + + result->integer = integer; + result->fract = fract; + + return 0; +} + +/** + * tsl2x7x_i2c_read() - Read a byte from a register. + * @client: i2c client + * @reg: device register to read from + * @*val: pointer to location to store register contents. + * + */ +static int +tsl2x7x_i2c_read(struct i2c_client *client, u8 reg, u8 *val) +{ + int ret = 0; + + /* select register to write */ + ret = i2c_smbus_write_byte(client, (TSL2X7X_CMD_REG | reg)); + if (ret < 0) { + dev_err(&client->dev, "%s: failed to write register %x\n" + , __func__, reg); + return ret; + } + + /* read the data */ + ret = i2c_smbus_read_byte(client); + if (ret >= 0) + *val = (u8)ret; + else + dev_err(&client->dev, "%s: failed to read register %x\n" + , __func__, reg); + + return ret; +} + +/** + * tsl2x7x_get_lux() - Reads and calculates current lux value. + * @indio_dev: pointer to IIO device + * + * The raw ch0 and ch1 values of the ambient light sensed in the last + * integration cycle are read from the device. + * Time scale factor array values are adjusted based on the integration time. + * The raw values are multiplied by a scale factor, and device gain is obtained + * using gain index. Limit checks are done next, then the ratio of a multiple + * of ch1 value, to the ch0 value, is calculated. Array tsl2x7x_device_lux[] + * is then scanned to find the first ratio value that is just above the ratio + * we just calculated. The ch0 and ch1 multiplier constants in the array are + * then used along with the time scale factor array values, to calculate the + * lux. + */ +static int tsl2x7x_get_lux(struct iio_dev *indio_dev) +{ + u16 ch0, ch1; /* separated ch0/ch1 data from device */ + u32 lux; /* raw lux calculated from device data */ + u64 lux64; + u32 ratio; + u8 buf[4]; + struct tsl2x7x_lux *p; + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + int i, ret; + u32 ch0lux = 0; + u32 ch1lux = 0; + + if (mutex_trylock(&chip->als_mutex) == 0) + return chip->als_cur_info.lux; /* busy, so return LAST VALUE */ + + if (chip->tsl2x7x_chip_status != TSL2X7X_CHIP_WORKING) { + /* device is not enabled */ + dev_err(&chip->client->dev, "%s: device is not enabled\n", + __func__); + ret = -EBUSY ; + goto out_unlock; + } + + ret = tsl2x7x_i2c_read(chip->client, + (TSL2X7X_CMD_REG | TSL2X7X_STATUS), &buf[0]); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: Failed to read STATUS Reg\n", __func__); + goto out_unlock; + } + /* is data new & valid */ + if (!(buf[0] & TSL2X7X_STA_ADC_VALID)) { + dev_err(&chip->client->dev, + "%s: data not valid yet\n", __func__); + ret = chip->als_cur_info.lux; /* return LAST VALUE */ + goto out_unlock; + } + + for (i = 0; i < 4; i++) { + ret = tsl2x7x_i2c_read(chip->client, + (TSL2X7X_CMD_REG | (TSL2X7X_ALS_CHAN0LO + i)), + &buf[i]); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: failed to read. err=%x\n", __func__, ret); + goto out_unlock; + } + } + + /* clear any existing interrupt status */ + ret = i2c_smbus_write_byte(chip->client, + (TSL2X7X_CMD_REG | + TSL2X7X_CMD_SPL_FN | + TSL2X7X_CMD_ALS_INT_CLR)); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: i2c_write_command failed - err = %d\n", + __func__, ret); + goto out_unlock; /* have no data, so return failure */ + } + + /* extract ALS/lux data */ + ch0 = le16_to_cpup((const __le16 *)&buf[0]); + ch1 = le16_to_cpup((const __le16 *)&buf[2]); + + chip->als_cur_info.als_ch0 = ch0; + chip->als_cur_info.als_ch1 = ch1; + + if ((ch0 >= chip->als_saturation) || (ch1 >= chip->als_saturation)) { + lux = TSL2X7X_LUX_CALC_OVER_FLOW; + goto return_max; + } + + if (ch0 == 0) { + /* have no data, so return LAST VALUE */ + ret = chip->als_cur_info.lux; + goto out_unlock; + } + /* calculate ratio */ + ratio = (ch1 << 15) / ch0; + /* convert to unscaled lux using the pointer to the table */ + p = (struct tsl2x7x_lux *) chip->tsl2x7x_device_lux; + while (p->ratio != 0 && p->ratio < ratio) + p++; + + if (p->ratio == 0) { + lux = 0; + } else { + ch0lux = DIV_ROUND_UP((ch0 * p->ch0), + tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain]); + ch1lux = DIV_ROUND_UP((ch1 * p->ch1), + tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain]); + lux = ch0lux - ch1lux; + } + + /* note: lux is 31 bit max at this point */ + if (ch1lux > ch0lux) { + dev_dbg(&chip->client->dev, "ch1lux > ch0lux-return last value\n"); + ret = chip->als_cur_info.lux; + goto out_unlock; + } + + /* adjust for active time scale */ + if (chip->als_time_scale == 0) + lux = 0; + else + lux = (lux + (chip->als_time_scale >> 1)) / + chip->als_time_scale; + + /* adjust for active gain scale + * The tsl2x7x_device_lux tables have a factor of 256 built-in. + * User-specified gain provides a multiplier. + * Apply user-specified gain before shifting right to retain precision. + * Use 64 bits to avoid overflow on multiplication. + * Then go back to 32 bits before division to avoid using div_u64(). + */ + + lux64 = lux; + lux64 = lux64 * chip->tsl2x7x_settings.als_gain_trim; + lux64 >>= 8; + lux = lux64; + lux = (lux + 500) / 1000; + + if (lux > TSL2X7X_LUX_CALC_OVER_FLOW) /* check for overflow */ + lux = TSL2X7X_LUX_CALC_OVER_FLOW; + + /* Update the structure with the latest lux. */ +return_max: + chip->als_cur_info.lux = lux; + ret = lux; + +out_unlock: + mutex_unlock(&chip->als_mutex); + + return ret; +} + +/** + * tsl2x7x_get_prox() - Reads proximity data registers and updates + * chip->prox_data. + * + * @indio_dev: pointer to IIO device + */ +static int tsl2x7x_get_prox(struct iio_dev *indio_dev) +{ + int i; + int ret; + u8 status; + u8 chdata[2]; + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + + if (mutex_trylock(&chip->prox_mutex) == 0) { + dev_err(&chip->client->dev, + "%s: Can't get prox mutex\n", __func__); + return -EBUSY; + } + + ret = tsl2x7x_i2c_read(chip->client, + (TSL2X7X_CMD_REG | TSL2X7X_STATUS), &status); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: i2c err=%d\n", __func__, ret); + goto prox_poll_err; + } + + switch (chip->id) { + case tsl2571: + case tsl2671: + case tmd2671: + case tsl2771: + case tmd2771: + if (!(status & TSL2X7X_STA_ADC_VALID)) + goto prox_poll_err; + break; + case tsl2572: + case tsl2672: + case tmd2672: + case tsl2772: + case tmd2772: + if (!(status & TSL2X7X_STA_PRX_VALID)) + goto prox_poll_err; + break; + } + + for (i = 0; i < 2; i++) { + ret = tsl2x7x_i2c_read(chip->client, + (TSL2X7X_CMD_REG | + (TSL2X7X_PRX_LO + i)), &chdata[i]); + if (ret < 0) + goto prox_poll_err; + } + + chip->prox_data = + le16_to_cpup((const __le16 *)&chdata[0]); + +prox_poll_err: + + mutex_unlock(&chip->prox_mutex); + + return chip->prox_data; +} + +/** + * tsl2x7x_defaults() - Populates the device nominal operating parameters + * with those provided by a 'platform' data struct or + * with prefined defaults. + * + * @chip: pointer to device structure. + */ +static void tsl2x7x_defaults(struct tsl2X7X_chip *chip) +{ + /* If Operational settings defined elsewhere.. */ + if (chip->pdata && chip->pdata->platform_default_settings != 0) + memcpy(&(chip->tsl2x7x_settings), + chip->pdata->platform_default_settings, + sizeof(tsl2x7x_default_settings)); + else + memcpy(&(chip->tsl2x7x_settings), + &tsl2x7x_default_settings, + sizeof(tsl2x7x_default_settings)); + + /* Load up the proper lux table. */ + if (chip->pdata && chip->pdata->platform_lux_table[0].ratio != 0) + memcpy(chip->tsl2x7x_device_lux, + chip->pdata->platform_lux_table, + sizeof(chip->pdata->platform_lux_table)); + else + memcpy(chip->tsl2x7x_device_lux, + (struct tsl2x7x_lux *)tsl2x7x_default_lux_table_group[chip->id], + MAX_DEFAULT_TABLE_BYTES); +} + +/** + * tsl2x7x_als_calibrate() - Obtain single reading and calculate + * the als_gain_trim. + * + * @indio_dev: pointer to IIO device + */ +static int tsl2x7x_als_calibrate(struct iio_dev *indio_dev) +{ + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + u8 reg_val; + int gain_trim_val; + int ret; + int lux_val; + + ret = i2c_smbus_write_byte(chip->client, + (TSL2X7X_CMD_REG | TSL2X7X_CNTRL)); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: failed to write CNTRL register, ret=%d\n", + __func__, ret); + return ret; + } + + reg_val = i2c_smbus_read_byte(chip->client); + if ((reg_val & (TSL2X7X_CNTL_ADC_ENBL | TSL2X7X_CNTL_PWR_ON)) + != (TSL2X7X_CNTL_ADC_ENBL | TSL2X7X_CNTL_PWR_ON)) { + dev_err(&chip->client->dev, + "%s: failed: ADC not enabled\n", __func__); + return -1; + } + + ret = i2c_smbus_write_byte(chip->client, + (TSL2X7X_CMD_REG | TSL2X7X_CNTRL)); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: failed to write ctrl reg: ret=%d\n", + __func__, ret); + return ret; + } + + reg_val = i2c_smbus_read_byte(chip->client); + if ((reg_val & TSL2X7X_STA_ADC_VALID) != TSL2X7X_STA_ADC_VALID) { + dev_err(&chip->client->dev, + "%s: failed: STATUS - ADC not valid.\n", __func__); + return -ENODATA; + } + + lux_val = tsl2x7x_get_lux(indio_dev); + if (lux_val < 0) { + dev_err(&chip->client->dev, + "%s: failed to get lux\n", __func__); + return lux_val; + } + + gain_trim_val = (((chip->tsl2x7x_settings.als_cal_target) + * chip->tsl2x7x_settings.als_gain_trim) / lux_val); + if ((gain_trim_val < 250) || (gain_trim_val > 4000)) + return -ERANGE; + + chip->tsl2x7x_settings.als_gain_trim = gain_trim_val; + dev_info(&chip->client->dev, + "%s als_calibrate completed\n", chip->client->name); + + return (int) gain_trim_val; +} + +static int tsl2x7x_chip_on(struct iio_dev *indio_dev) +{ + int i; + int ret = 0; + u8 *dev_reg; + u8 utmp; + int als_count; + int als_time; + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + u8 reg_val = 0; + + if (chip->pdata && chip->pdata->power_on) + chip->pdata->power_on(indio_dev); + + /* Non calculated parameters */ + chip->tsl2x7x_config[TSL2X7X_PRX_TIME] = + chip->tsl2x7x_settings.prx_time; + chip->tsl2x7x_config[TSL2X7X_WAIT_TIME] = + chip->tsl2x7x_settings.wait_time; + chip->tsl2x7x_config[TSL2X7X_PRX_CONFIG] = + chip->tsl2x7x_settings.prox_config; + + chip->tsl2x7x_config[TSL2X7X_ALS_MINTHRESHLO] = + (chip->tsl2x7x_settings.als_thresh_low) & 0xFF; + chip->tsl2x7x_config[TSL2X7X_ALS_MINTHRESHHI] = + (chip->tsl2x7x_settings.als_thresh_low >> 8) & 0xFF; + chip->tsl2x7x_config[TSL2X7X_ALS_MAXTHRESHLO] = + (chip->tsl2x7x_settings.als_thresh_high) & 0xFF; + chip->tsl2x7x_config[TSL2X7X_ALS_MAXTHRESHHI] = + (chip->tsl2x7x_settings.als_thresh_high >> 8) & 0xFF; + chip->tsl2x7x_config[TSL2X7X_PERSISTENCE] = + chip->tsl2x7x_settings.persistence; + + chip->tsl2x7x_config[TSL2X7X_PRX_COUNT] = + chip->tsl2x7x_settings.prox_pulse_count; + chip->tsl2x7x_config[TSL2X7X_PRX_MINTHRESHLO] = + chip->tsl2x7x_settings.prox_thres_low; + chip->tsl2x7x_config[TSL2X7X_PRX_MAXTHRESHLO] = + chip->tsl2x7x_settings.prox_thres_high; + + /* and make sure we're not already on */ + if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) { + /* if forcing a register update - turn off, then on */ + dev_info(&chip->client->dev, "device is already enabled\n"); + return -EINVAL; + } + + /* determine als integration regster */ + als_count = (chip->tsl2x7x_settings.als_time * 100 + 135) / 270; + if (als_count == 0) + als_count = 1; /* ensure at least one cycle */ + + /* convert back to time (encompasses overrides) */ + als_time = (als_count * 27 + 5) / 10; + chip->tsl2x7x_config[TSL2X7X_ALS_TIME] = 256 - als_count; + + /* Set the gain based on tsl2x7x_settings struct */ + chip->tsl2x7x_config[TSL2X7X_GAIN] = + (chip->tsl2x7x_settings.als_gain | + (TSL2X7X_mA100 | TSL2X7X_DIODE1) + | ((chip->tsl2x7x_settings.prox_gain) << 2)); + + /* set chip struct re scaling and saturation */ + chip->als_saturation = als_count * 922; /* 90% of full scale */ + chip->als_time_scale = (als_time + 25) / 50; + + /* TSL2X7X Specific power-on / adc enable sequence + * Power on the device 1st. */ + utmp = TSL2X7X_CNTL_PWR_ON; + ret = i2c_smbus_write_byte_data(chip->client, + TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: failed on CNTRL reg.\n", __func__); + return ret; + } + + /* Use the following shadow copy for our delay before enabling ADC. + * Write all the registers. */ + for (i = 0, dev_reg = chip->tsl2x7x_config; + i < TSL2X7X_MAX_CONFIG_REG; i++) { + ret = i2c_smbus_write_byte_data(chip->client, + TSL2X7X_CMD_REG + i, *dev_reg++); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: failed on write to reg %d.\n", __func__, i); + return ret; + } + } + + mdelay(3); /* Power-on settling time */ + + /* NOW enable the ADC + * initialize the desired mode of operation */ + utmp = TSL2X7X_CNTL_PWR_ON | + TSL2X7X_CNTL_ADC_ENBL | + TSL2X7X_CNTL_PROX_DET_ENBL; + ret = i2c_smbus_write_byte_data(chip->client, + TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: failed on 2nd CTRL reg.\n", __func__); + return ret; + } + + chip->tsl2x7x_chip_status = TSL2X7X_CHIP_WORKING; + + if (chip->tsl2x7x_settings.interrupts_en != 0) { + dev_info(&chip->client->dev, "Setting Up Interrupt(s)\n"); + + reg_val = TSL2X7X_CNTL_PWR_ON | TSL2X7X_CNTL_ADC_ENBL; + if ((chip->tsl2x7x_settings.interrupts_en == 0x20) || + (chip->tsl2x7x_settings.interrupts_en == 0x30)) + reg_val |= TSL2X7X_CNTL_PROX_DET_ENBL; + + reg_val |= chip->tsl2x7x_settings.interrupts_en; + ret = i2c_smbus_write_byte_data(chip->client, + (TSL2X7X_CMD_REG | TSL2X7X_CNTRL), reg_val); + if (ret < 0) + dev_err(&chip->client->dev, + "%s: failed in tsl2x7x_IOCTL_INT_SET.\n", + __func__); + + /* Clear out any initial interrupts */ + ret = i2c_smbus_write_byte(chip->client, + TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN | + TSL2X7X_CMD_PROXALS_INT_CLR); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: Failed to clear Int status\n", + __func__); + return ret; + } + } + + return ret; +} + +static int tsl2x7x_chip_off(struct iio_dev *indio_dev) +{ + int ret; + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + + /* turn device off */ + chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED; + + ret = i2c_smbus_write_byte_data(chip->client, + TSL2X7X_CMD_REG | TSL2X7X_CNTRL, 0x00); + + if (chip->pdata && chip->pdata->power_off) + chip->pdata->power_off(chip->client); + + return ret; +} + +/** + * tsl2x7x_invoke_change + * @indio_dev: pointer to IIO device + * + * Obtain and lock both ALS and PROX resources, + * determine and save device state (On/Off), + * cycle device to implement updated parameter, + * put device back into proper state, and unlock + * resource. + */ +static +int tsl2x7x_invoke_change(struct iio_dev *indio_dev) +{ + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + int device_status = chip->tsl2x7x_chip_status; + + mutex_lock(&chip->als_mutex); + mutex_lock(&chip->prox_mutex); + + if (device_status == TSL2X7X_CHIP_WORKING) + tsl2x7x_chip_off(indio_dev); + + tsl2x7x_chip_on(indio_dev); + + if (device_status != TSL2X7X_CHIP_WORKING) + tsl2x7x_chip_off(indio_dev); + + mutex_unlock(&chip->prox_mutex); + mutex_unlock(&chip->als_mutex); + + return 0; +} + +static +void tsl2x7x_prox_calculate(int *data, int length, + struct tsl2x7x_prox_stat *statP) +{ + int i; + int sample_sum; + int tmp; + + if (length == 0) + length = 1; + + sample_sum = 0; + statP->min = INT_MAX; + statP->max = INT_MIN; + for (i = 0; i < length; i++) { + sample_sum += data[i]; + statP->min = min(statP->min, data[i]); + statP->max = max(statP->max, data[i]); + } + + statP->mean = sample_sum / length; + sample_sum = 0; + for (i = 0; i < length; i++) { + tmp = data[i] - statP->mean; + sample_sum += tmp * tmp; + } + statP->stddev = int_sqrt((long)sample_sum)/length; +} + +/** + * tsl2x7x_prox_cal() - Calculates std. and sets thresholds. + * @indio_dev: pointer to IIO device + * + * Calculates a standard deviation based on the samples, + * and sets the threshold accordingly. + */ +static void tsl2x7x_prox_cal(struct iio_dev *indio_dev) +{ + int prox_history[MAX_SAMPLES_CAL + 1]; + int i; + struct tsl2x7x_prox_stat prox_stat_data[2]; + struct tsl2x7x_prox_stat *calP; + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + u8 tmp_irq_settings; + u8 current_state = chip->tsl2x7x_chip_status; + + if (chip->tsl2x7x_settings.prox_max_samples_cal > MAX_SAMPLES_CAL) { + dev_err(&chip->client->dev, + "%s: max prox samples cal is too big: %d\n", + __func__, chip->tsl2x7x_settings.prox_max_samples_cal); + chip->tsl2x7x_settings.prox_max_samples_cal = MAX_SAMPLES_CAL; + } + + /* have to stop to change settings */ + tsl2x7x_chip_off(indio_dev); + + /* Enable proximity detection save just in case prox not wanted yet*/ + tmp_irq_settings = chip->tsl2x7x_settings.interrupts_en; + chip->tsl2x7x_settings.interrupts_en |= TSL2X7X_CNTL_PROX_INT_ENBL; + + /*turn on device if not already on*/ + tsl2x7x_chip_on(indio_dev); + + /*gather the samples*/ + for (i = 0; i < chip->tsl2x7x_settings.prox_max_samples_cal; i++) { + mdelay(15); + tsl2x7x_get_prox(indio_dev); + prox_history[i] = chip->prox_data; + dev_info(&chip->client->dev, "2 i=%d prox data= %d\n", + i, chip->prox_data); + } + + tsl2x7x_chip_off(indio_dev); + calP = &prox_stat_data[PROX_STAT_CAL]; + tsl2x7x_prox_calculate(prox_history, + chip->tsl2x7x_settings.prox_max_samples_cal, calP); + chip->tsl2x7x_settings.prox_thres_high = (calP->max << 1) - calP->mean; + + dev_info(&chip->client->dev, " cal min=%d mean=%d max=%d\n", + calP->min, calP->mean, calP->max); + dev_info(&chip->client->dev, + "%s proximity threshold set to %d\n", + chip->client->name, chip->tsl2x7x_settings.prox_thres_high); + + /* back to the way they were */ + chip->tsl2x7x_settings.interrupts_en = tmp_irq_settings; + if (current_state == TSL2X7X_CHIP_WORKING) + tsl2x7x_chip_on(indio_dev); +} + +static ssize_t tsl2x7x_power_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev)); + + return snprintf(buf, PAGE_SIZE, "%d\n", chip->tsl2x7x_chip_status); +} + +static ssize_t tsl2x7x_power_state_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + bool value; + + if (strtobool(buf, &value)) + return -EINVAL; + + if (value) + tsl2x7x_chip_on(indio_dev); + else + tsl2x7x_chip_off(indio_dev); + + return len; +} + +static ssize_t tsl2x7x_gain_available_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev)); + + switch (chip->id) { + case tsl2571: + case tsl2671: + case tmd2671: + case tsl2771: + case tmd2771: + return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 128"); + break; + } + + return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 120"); +} + +static ssize_t tsl2x7x_prox_gain_available_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", "1 2 4 8"); +} + +static ssize_t tsl2x7x_als_time_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev)); + int y, z; + + y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1; + z = y * TSL2X7X_MIN_ITIME; + y /= 1000; + z %= 1000; + + return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z); +} + +static ssize_t tsl2x7x_als_time_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + struct tsl2x7x_parse_result result; + + result.integer = 0; + result.fract = 0; + + tsl2x7x_parse_buffer(buf, &result); + + result.fract /= 1000; + result.fract /= 3; + chip->tsl2x7x_settings.als_time = + (TSL2X7X_MAX_TIMER_CNT - (u8)result.fract); + + dev_info(&chip->client->dev, "%s: als time = %d", + __func__, chip->tsl2x7x_settings.als_time); + + tsl2x7x_invoke_change(indio_dev); + + return IIO_VAL_INT_PLUS_MICRO; +} + +static IIO_CONST_ATTR(in_illuminance0_integration_time_available, + ".00272 - .696"); + +static ssize_t tsl2x7x_als_cal_target_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev)); + + return snprintf(buf, PAGE_SIZE, "%d\n", + chip->tsl2x7x_settings.als_cal_target); +} + +static ssize_t tsl2x7x_als_cal_target_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + unsigned long value; + + if (kstrtoul(buf, 0, &value)) + return -EINVAL; + + if (value) + chip->tsl2x7x_settings.als_cal_target = value; + + tsl2x7x_invoke_change(indio_dev); + + return len; +} + +/* persistence settings */ +static ssize_t tsl2x7x_als_persistence_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev)); + int y, z, filter_delay; + + /* Determine integration time */ + y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1; + z = y * TSL2X7X_MIN_ITIME; + filter_delay = z * (chip->tsl2x7x_settings.persistence & 0x0F); + y = (filter_delay / 1000); + z = (filter_delay % 1000); + + return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z); +} + +static ssize_t tsl2x7x_als_persistence_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + struct tsl2x7x_parse_result result; + int y, z, filter_delay; + + result.integer = 0; + result.fract = 0; + tsl2x7x_parse_buffer(buf, &result); + + result.fract /= 1000; + y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1; + z = y * TSL2X7X_MIN_ITIME; + + filter_delay = + DIV_ROUND_UP(((result.integer * 1000) + result.fract), z); + + chip->tsl2x7x_settings.persistence &= 0xF0; + chip->tsl2x7x_settings.persistence |= (filter_delay & 0x0F); + + dev_info(&chip->client->dev, "%s: als persistence = %d", + __func__, filter_delay); + + tsl2x7x_invoke_change(indio_dev); + + return IIO_VAL_INT_PLUS_MICRO; +} + +static ssize_t tsl2x7x_prox_persistence_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev)); + int y, z, filter_delay; + + /* Determine integration time */ + y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.prx_time) + 1; + z = y * TSL2X7X_MIN_ITIME; + filter_delay = z * ((chip->tsl2x7x_settings.persistence & 0xF0) >> 4); + y = (filter_delay / 1000); + z = (filter_delay % 1000); + + return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z); +} + +static ssize_t tsl2x7x_prox_persistence_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + struct tsl2x7x_parse_result result; + int y, z, filter_delay; + + result.integer = 0; + result.fract = 0; + tsl2x7x_parse_buffer(buf, &result); + + result.fract /= 1000; + y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.prx_time) + 1; + z = y * TSL2X7X_MIN_ITIME; + + filter_delay = + DIV_ROUND_UP(((result.integer * 1000) + result.fract), z); + + chip->tsl2x7x_settings.persistence &= 0x0F; + chip->tsl2x7x_settings.persistence |= ((filter_delay << 4) & 0xF0); + + dev_info(&chip->client->dev, "%s: prox persistence = %d", + __func__, filter_delay); + + tsl2x7x_invoke_change(indio_dev); + + return IIO_VAL_INT_PLUS_MICRO; +} + +static ssize_t tsl2x7x_do_calibrate(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + bool value; + + if (strtobool(buf, &value)) + return -EINVAL; + + if (value) + tsl2x7x_als_calibrate(indio_dev); + + tsl2x7x_invoke_change(indio_dev); + + return len; +} + +static ssize_t tsl2x7x_luxtable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev)); + int i = 0; + int offset = 0; + + while (i < (TSL2X7X_MAX_LUX_TABLE_SIZE * 3)) { + offset += snprintf(buf + offset, PAGE_SIZE, "%d,%d,%d,", + chip->tsl2x7x_device_lux[i].ratio, + chip->tsl2x7x_device_lux[i].ch0, + chip->tsl2x7x_device_lux[i].ch1); + if (chip->tsl2x7x_device_lux[i].ratio == 0) { + /* We just printed the first "0" entry. + * Now get rid of the extra "," and break. */ + offset--; + break; + } + i++; + } + + offset += snprintf(buf + offset, PAGE_SIZE, "\n"); + return offset; +} + +static ssize_t tsl2x7x_luxtable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + int value[ARRAY_SIZE(chip->tsl2x7x_device_lux)*3 + 1]; + int n; + + get_options(buf, ARRAY_SIZE(value), value); + + /* We now have an array of ints starting at value[1], and + * enumerated by value[0]. + * We expect each group of three ints is one table entry, + * and the last table entry is all 0. + */ + n = value[0]; + if ((n % 3) || n < 6 || + n > ((ARRAY_SIZE(chip->tsl2x7x_device_lux) - 1) * 3)) { + dev_info(dev, "LUX TABLE INPUT ERROR 1 Value[0]=%d\n", n); + return -EINVAL; + } + + if ((value[(n - 2)] | value[(n - 1)] | value[n]) != 0) { + dev_info(dev, "LUX TABLE INPUT ERROR 2 Value[0]=%d\n", n); + return -EINVAL; + } + + if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) + tsl2x7x_chip_off(indio_dev); + + /* Zero out the table */ + memset(chip->tsl2x7x_device_lux, 0, sizeof(chip->tsl2x7x_device_lux)); + memcpy(chip->tsl2x7x_device_lux, &value[1], (value[0] * 4)); + + tsl2x7x_invoke_change(indio_dev); + + return len; +} + +static ssize_t tsl2x7x_do_prox_calibrate(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + bool value; + + if (strtobool(buf, &value)) + return -EINVAL; + + if (value) + tsl2x7x_prox_cal(indio_dev); + + tsl2x7x_invoke_change(indio_dev); + + return len; +} + +static int tsl2x7x_read_interrupt_config(struct iio_dev *indio_dev, + u64 event_code) +{ + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + int ret; + + if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY) + ret = !!(chip->tsl2x7x_settings.interrupts_en & 0x10); + else + ret = !!(chip->tsl2x7x_settings.interrupts_en & 0x20); + + return ret; +} + +static int tsl2x7x_write_interrupt_config(struct iio_dev *indio_dev, + u64 event_code, + int val) +{ + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + + if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY) { + if (val) + chip->tsl2x7x_settings.interrupts_en |= 0x10; + else + chip->tsl2x7x_settings.interrupts_en &= 0x20; + } else { + if (val) + chip->tsl2x7x_settings.interrupts_en |= 0x20; + else + chip->tsl2x7x_settings.interrupts_en &= 0x10; + } + + tsl2x7x_invoke_change(indio_dev); + + return 0; +} + +static int tsl2x7x_write_thresh(struct iio_dev *indio_dev, + u64 event_code, + int val) +{ + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + + if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY) { + switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) { + case IIO_EV_DIR_RISING: + chip->tsl2x7x_settings.als_thresh_high = val; + break; + case IIO_EV_DIR_FALLING: + chip->tsl2x7x_settings.als_thresh_low = val; + break; + default: + return -EINVAL; + } + } else { + switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) { + case IIO_EV_DIR_RISING: + chip->tsl2x7x_settings.prox_thres_high = val; + break; + case IIO_EV_DIR_FALLING: + chip->tsl2x7x_settings.prox_thres_low = val; + break; + default: + return -EINVAL; + } + } + + tsl2x7x_invoke_change(indio_dev); + + return 0; +} + +static int tsl2x7x_read_thresh(struct iio_dev *indio_dev, + u64 event_code, + int *val) +{ + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + + if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY) { + switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) { + case IIO_EV_DIR_RISING: + *val = chip->tsl2x7x_settings.als_thresh_high; + break; + case IIO_EV_DIR_FALLING: + *val = chip->tsl2x7x_settings.als_thresh_low; + break; + default: + return -EINVAL; + } + } else { + switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) { + case IIO_EV_DIR_RISING: + *val = chip->tsl2x7x_settings.prox_thres_high; + break; + case IIO_EV_DIR_FALLING: + *val = chip->tsl2x7x_settings.prox_thres_low; + break; + default: + return -EINVAL; + } + } + + return 0; +} + +static int tsl2x7x_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + int ret = -EINVAL; + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + switch (chan->type) { + case IIO_LIGHT: + tsl2x7x_get_lux(indio_dev); + *val = chip->als_cur_info.lux; + ret = IIO_VAL_INT; + break; + default: + return -EINVAL; + break; + } + break; + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_INTENSITY: + tsl2x7x_get_lux(indio_dev); + if (chan->channel == 0) + *val = chip->als_cur_info.als_ch0; + else + *val = chip->als_cur_info.als_ch1; + ret = IIO_VAL_INT; + break; + case IIO_PROXIMITY: + tsl2x7x_get_prox(indio_dev); + *val = chip->prox_data; + ret = IIO_VAL_INT; + break; + default: + return -EINVAL; + break; + } + break; + case IIO_CHAN_INFO_CALIBSCALE: + if (chan->type == IIO_LIGHT) + *val = + tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain]; + else + *val = + tsl2X7X_prx_gainadj[chip->tsl2x7x_settings.prox_gain]; + ret = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_CALIBBIAS: + *val = chip->tsl2x7x_settings.als_gain_trim; + ret = IIO_VAL_INT; + break; + + default: + ret = -EINVAL; + } + + return ret; +} + +static int tsl2x7x_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_CALIBSCALE: + if (chan->type == IIO_INTENSITY) { + switch (val) { + case 1: + chip->tsl2x7x_settings.als_gain = 0; + break; + case 8: + chip->tsl2x7x_settings.als_gain = 1; + break; + case 16: + chip->tsl2x7x_settings.als_gain = 2; + break; + case 120: + switch (chip->id) { + case tsl2572: + case tsl2672: + case tmd2672: + case tsl2772: + case tmd2772: + return -EINVAL; + break; + } + chip->tsl2x7x_settings.als_gain = 3; + break; + case 128: + switch (chip->id) { + case tsl2571: + case tsl2671: + case tmd2671: + case tsl2771: + case tmd2771: + return -EINVAL; + break; + } + chip->tsl2x7x_settings.als_gain = 3; + break; + default: + return -EINVAL; + } + } else { + switch (val) { + case 1: + chip->tsl2x7x_settings.prox_gain = 0; + break; + case 2: + chip->tsl2x7x_settings.prox_gain = 1; + break; + case 4: + chip->tsl2x7x_settings.prox_gain = 2; + break; + case 8: + chip->tsl2x7x_settings.prox_gain = 3; + break; + default: + return -EINVAL; + } + } + break; + case IIO_CHAN_INFO_CALIBBIAS: + chip->tsl2x7x_settings.als_gain_trim = val; + break; + + default: + return -EINVAL; + } + + tsl2x7x_invoke_change(indio_dev); + + return 0; +} + +static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, + tsl2x7x_power_state_show, tsl2x7x_power_state_store); + +static DEVICE_ATTR(in_proximity0_calibscale_available, S_IRUGO, + tsl2x7x_prox_gain_available_show, NULL); + +static DEVICE_ATTR(in_illuminance0_calibscale_available, S_IRUGO, + tsl2x7x_gain_available_show, NULL); + +static DEVICE_ATTR(in_illuminance0_integration_time, S_IRUGO | S_IWUSR, + tsl2x7x_als_time_show, tsl2x7x_als_time_store); + +static DEVICE_ATTR(in_illuminance0_target_input, S_IRUGO | S_IWUSR, + tsl2x7x_als_cal_target_show, tsl2x7x_als_cal_target_store); + +static DEVICE_ATTR(in_illuminance0_calibrate, S_IWUSR, NULL, + tsl2x7x_do_calibrate); + +static DEVICE_ATTR(in_proximity0_calibrate, S_IWUSR, NULL, + tsl2x7x_do_prox_calibrate); + +static DEVICE_ATTR(in_illuminance0_lux_table, S_IRUGO | S_IWUSR, + tsl2x7x_luxtable_show, tsl2x7x_luxtable_store); + +static DEVICE_ATTR(in_intensity0_thresh_period, S_IRUGO | S_IWUSR, + tsl2x7x_als_persistence_show, tsl2x7x_als_persistence_store); + +static DEVICE_ATTR(in_proximity0_thresh_period, S_IRUGO | S_IWUSR, + tsl2x7x_prox_persistence_show, tsl2x7x_prox_persistence_store); + +/* Use the default register values to identify the Taos device */ +static int tsl2x7x_device_id(unsigned char *id, int target) +{ + switch (target) { + case tsl2571: + case tsl2671: + case tsl2771: + return ((*id & 0xf0) == TRITON_ID); + break; + case tmd2671: + case tmd2771: + return ((*id & 0xf0) == HALIBUT_ID); + break; + case tsl2572: + case tsl2672: + case tmd2672: + case tsl2772: + case tmd2772: + return ((*id & 0xf0) == SWORDFISH_ID); + break; + } + + return -EINVAL; +} + +static irqreturn_t tsl2x7x_event_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + s64 timestamp = iio_get_time_ns(); + int ret; + u8 value; + + value = i2c_smbus_read_byte_data(chip->client, + TSL2X7X_CMD_REG | TSL2X7X_STATUS); + + /* What type of interrupt do we need to process */ + if (value & TSL2X7X_STA_PRX_INTR) { + tsl2x7x_get_prox(indio_dev); /* freshen data for ABI */ + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, + 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER), + timestamp); + } + + if (value & TSL2X7X_STA_ALS_INTR) { + tsl2x7x_get_lux(indio_dev); /* freshen data for ABI */ + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_LIGHT, + 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER), + timestamp); + } + /* Clear interrupt now that we have handled it. */ + ret = i2c_smbus_write_byte(chip->client, + TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN | + TSL2X7X_CMD_PROXALS_INT_CLR); + if (ret < 0) + dev_err(&chip->client->dev, + "%s: Failed to clear irq from event handler. err = %d\n", + __func__, ret); + + return IRQ_HANDLED; +} + +static struct attribute *tsl2x7x_ALS_device_attrs[] = { + &dev_attr_power_state.attr, + &dev_attr_in_illuminance0_calibscale_available.attr, + &dev_attr_in_illuminance0_integration_time.attr, + &iio_const_attr_in_illuminance0_integration_time_available\ + .dev_attr.attr, + &dev_attr_in_illuminance0_target_input.attr, + &dev_attr_in_illuminance0_calibrate.attr, + &dev_attr_in_illuminance0_lux_table.attr, + NULL +}; + +static struct attribute *tsl2x7x_PRX_device_attrs[] = { + &dev_attr_power_state.attr, + &dev_attr_in_proximity0_calibrate.attr, + NULL +}; + +static struct attribute *tsl2x7x_ALSPRX_device_attrs[] = { + &dev_attr_power_state.attr, + &dev_attr_in_illuminance0_calibscale_available.attr, + &dev_attr_in_illuminance0_integration_time.attr, + &iio_const_attr_in_illuminance0_integration_time_available\ + .dev_attr.attr, + &dev_attr_in_illuminance0_target_input.attr, + &dev_attr_in_illuminance0_calibrate.attr, + &dev_attr_in_illuminance0_lux_table.attr, + &dev_attr_in_proximity0_calibrate.attr, + NULL +}; + +static struct attribute *tsl2x7x_PRX2_device_attrs[] = { + &dev_attr_power_state.attr, + &dev_attr_in_proximity0_calibrate.attr, + &dev_attr_in_proximity0_calibscale_available.attr, + NULL +}; + +static struct attribute *tsl2x7x_ALSPRX2_device_attrs[] = { + &dev_attr_power_state.attr, + &dev_attr_in_illuminance0_calibscale_available.attr, + &dev_attr_in_illuminance0_integration_time.attr, + &iio_const_attr_in_illuminance0_integration_time_available\ + .dev_attr.attr, + &dev_attr_in_illuminance0_target_input.attr, + &dev_attr_in_illuminance0_calibrate.attr, + &dev_attr_in_illuminance0_lux_table.attr, + &dev_attr_in_proximity0_calibrate.attr, + &dev_attr_in_proximity0_calibscale_available.attr, + NULL +}; + +static struct attribute *tsl2X7X_ALS_event_attrs[] = { + &dev_attr_in_intensity0_thresh_period.attr, + NULL, +}; +static struct attribute *tsl2X7X_PRX_event_attrs[] = { + &dev_attr_in_proximity0_thresh_period.attr, + NULL, +}; + +static struct attribute *tsl2X7X_ALSPRX_event_attrs[] = { + &dev_attr_in_intensity0_thresh_period.attr, + &dev_attr_in_proximity0_thresh_period.attr, + NULL, +}; + +static const struct attribute_group tsl2X7X_device_attr_group_tbl[] = { + [ALS] = { + .attrs = tsl2x7x_ALS_device_attrs, + }, + [PRX] = { + .attrs = tsl2x7x_PRX_device_attrs, + }, + [ALSPRX] = { + .attrs = tsl2x7x_ALSPRX_device_attrs, + }, + [PRX2] = { + .attrs = tsl2x7x_PRX2_device_attrs, + }, + [ALSPRX2] = { + .attrs = tsl2x7x_ALSPRX2_device_attrs, + }, +}; + +static struct attribute_group tsl2X7X_event_attr_group_tbl[] = { + [ALS] = { + .attrs = tsl2X7X_ALS_event_attrs, + .name = "events", + }, + [PRX] = { + .attrs = tsl2X7X_PRX_event_attrs, + .name = "events", + }, + [ALSPRX] = { + .attrs = tsl2X7X_ALSPRX_event_attrs, + .name = "events", + }, +}; + +static const struct iio_info tsl2X7X_device_info[] = { + [ALS] = { + .attrs = &tsl2X7X_device_attr_group_tbl[ALS], + .event_attrs = &tsl2X7X_event_attr_group_tbl[ALS], + .driver_module = THIS_MODULE, + .read_raw = &tsl2x7x_read_raw, + .write_raw = &tsl2x7x_write_raw, + .read_event_value = &tsl2x7x_read_thresh, + .write_event_value = &tsl2x7x_write_thresh, + .read_event_config = &tsl2x7x_read_interrupt_config, + .write_event_config = &tsl2x7x_write_interrupt_config, + }, + [PRX] = { + .attrs = &tsl2X7X_device_attr_group_tbl[PRX], + .event_attrs = &tsl2X7X_event_attr_group_tbl[PRX], + .driver_module = THIS_MODULE, + .read_raw = &tsl2x7x_read_raw, + .write_raw = &tsl2x7x_write_raw, + .read_event_value = &tsl2x7x_read_thresh, + .write_event_value = &tsl2x7x_write_thresh, + .read_event_config = &tsl2x7x_read_interrupt_config, + .write_event_config = &tsl2x7x_write_interrupt_config, + }, + [ALSPRX] = { + .attrs = &tsl2X7X_device_attr_group_tbl[ALSPRX], + .event_attrs = &tsl2X7X_event_attr_group_tbl[ALSPRX], + .driver_module = THIS_MODULE, + .read_raw = &tsl2x7x_read_raw, + .write_raw = &tsl2x7x_write_raw, + .read_event_value = &tsl2x7x_read_thresh, + .write_event_value = &tsl2x7x_write_thresh, + .read_event_config = &tsl2x7x_read_interrupt_config, + .write_event_config = &tsl2x7x_write_interrupt_config, + }, + [PRX2] = { + .attrs = &tsl2X7X_device_attr_group_tbl[PRX2], + .event_attrs = &tsl2X7X_event_attr_group_tbl[PRX], + .driver_module = THIS_MODULE, + .read_raw = &tsl2x7x_read_raw, + .write_raw = &tsl2x7x_write_raw, + .read_event_value = &tsl2x7x_read_thresh, + .write_event_value = &tsl2x7x_write_thresh, + .read_event_config = &tsl2x7x_read_interrupt_config, + .write_event_config = &tsl2x7x_write_interrupt_config, + }, + [ALSPRX2] = { + .attrs = &tsl2X7X_device_attr_group_tbl[ALSPRX2], + .event_attrs = &tsl2X7X_event_attr_group_tbl[ALSPRX], + .driver_module = THIS_MODULE, + .read_raw = &tsl2x7x_read_raw, + .write_raw = &tsl2x7x_write_raw, + .read_event_value = &tsl2x7x_read_thresh, + .write_event_value = &tsl2x7x_write_thresh, + .read_event_config = &tsl2x7x_read_interrupt_config, + .write_event_config = &tsl2x7x_write_interrupt_config, + }, +}; + +static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = { + [ALS] = { + .channel = { + { + .type = IIO_LIGHT, + .indexed = 1, + .channel = 0, + .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT, + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, + .event_mask = TSL2X7X_EVENT_MASK + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 1, + }, + }, + .chan_table_elements = 3, + .info = &tsl2X7X_device_info[ALS], + }, + [PRX] = { + .channel = { + { + .type = IIO_PROXIMITY, + .indexed = 1, + .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, + .event_mask = TSL2X7X_EVENT_MASK + }, + }, + .chan_table_elements = 1, + .info = &tsl2X7X_device_info[PRX], + }, + [ALSPRX] = { + .channel = { + { + .type = IIO_LIGHT, + .indexed = 1, + .channel = 0, + .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, + .event_mask = TSL2X7X_EVENT_MASK + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 1, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, + }, { + .type = IIO_PROXIMITY, + .indexed = 1, + .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, + .event_mask = TSL2X7X_EVENT_MASK + }, + }, + .chan_table_elements = 4, + .info = &tsl2X7X_device_info[ALSPRX], + }, + [PRX2] = { + .channel = { + { + .type = IIO_PROXIMITY, + .indexed = 1, + .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, + .event_mask = TSL2X7X_EVENT_MASK + }, + }, + .chan_table_elements = 1, + .info = &tsl2X7X_device_info[PRX2], + }, + [ALSPRX2] = { + .channel = { + { + .type = IIO_LIGHT, + .indexed = 1, + .channel = 0, + .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT, + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, + .event_mask = TSL2X7X_EVENT_MASK + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 1, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, + }, { + .type = IIO_PROXIMITY, + .indexed = 1, + .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, + .event_mask = TSL2X7X_EVENT_MASK + }, + }, + .chan_table_elements = 4, + .info = &tsl2X7X_device_info[ALSPRX2], + }, +}; + +static int __devinit tsl2x7x_probe(struct i2c_client *clientp, + const struct i2c_device_id *id) +{ + int ret; + unsigned char device_id; + struct iio_dev *indio_dev; + struct tsl2X7X_chip *chip; + + indio_dev = iio_device_alloc(sizeof(*chip)); + if (!indio_dev) + return -ENOMEM; + + chip = iio_priv(indio_dev); + chip->client = clientp; + i2c_set_clientdata(clientp, indio_dev); + + ret = tsl2x7x_i2c_read(chip->client, + TSL2X7X_CHIPID, &device_id); + if (ret < 0) + goto fail1; + + if ((!tsl2x7x_device_id(&device_id, id->driver_data)) || + (tsl2x7x_device_id(&device_id, id->driver_data) == -EINVAL)) { + dev_info(&chip->client->dev, + "%s: i2c device found does not match expected id\n", + __func__); + goto fail1; + } + + ret = i2c_smbus_write_byte(clientp, (TSL2X7X_CMD_REG | TSL2X7X_CNTRL)); + if (ret < 0) { + dev_err(&clientp->dev, "%s: write to cmd reg failed. err = %d\n", + __func__, ret); + goto fail1; + } + + /* ALS and PROX functions can be invoked via user space poll + * or H/W interrupt. If busy return last sample. */ + mutex_init(&chip->als_mutex); + mutex_init(&chip->prox_mutex); + + chip->tsl2x7x_chip_status = TSL2X7X_CHIP_UNKNOWN; + chip->pdata = clientp->dev.platform_data; + chip->id = id->driver_data; + chip->chip_info = + &tsl2x7x_chip_info_tbl[device_channel_config[id->driver_data]]; + + indio_dev->info = chip->chip_info->info; + indio_dev->dev.parent = &clientp->dev; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->name = chip->client->name; + indio_dev->channels = chip->chip_info->channel; + indio_dev->num_channels = chip->chip_info->chan_table_elements; + + if (clientp->irq) { + ret = request_threaded_irq(clientp->irq, + NULL, + &tsl2x7x_event_handler, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + "TSL2X7X_event", + indio_dev); + if (ret) { + dev_err(&clientp->dev, + "%s: irq request failed", __func__); + goto fail2; + } + } + + /* Load up the defaults */ + tsl2x7x_defaults(chip); + /* Make sure the chip is on */ + tsl2x7x_chip_on(indio_dev); + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&clientp->dev, + "%s: iio registration failed\n", __func__); + goto fail1; + } + + dev_info(&clientp->dev, "%s Light sensor found.\n", id->name); + + return 0; + +fail1: + if (clientp->irq) + free_irq(clientp->irq, indio_dev); +fail2: + iio_device_free(indio_dev); + + return ret; +} + +static int tsl2x7x_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + int ret = 0; + + if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) { + ret = tsl2x7x_chip_off(indio_dev); + chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED; + } + + if (chip->pdata && chip->pdata->platform_power) { + pm_message_t pmm = {PM_EVENT_SUSPEND}; + chip->pdata->platform_power(dev, pmm); + } + + return ret; +} + +static int tsl2x7x_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + int ret = 0; + + if (chip->pdata && chip->pdata->platform_power) { + pm_message_t pmm = {PM_EVENT_RESUME}; + chip->pdata->platform_power(dev, pmm); + } + + if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_SUSPENDED) + ret = tsl2x7x_chip_on(indio_dev); + + return ret; +} + +static int __devexit tsl2x7x_remove(struct i2c_client *client) +{ + struct tsl2X7X_chip *chip = i2c_get_clientdata(client); + struct iio_dev *indio_dev = iio_priv_to_dev(chip); + + tsl2x7x_chip_off(indio_dev); + + iio_device_unregister(indio_dev); + if (client->irq) + free_irq(client->irq, chip->client->name); + + iio_device_free(indio_dev); + + return 0; +} + +static struct i2c_device_id tsl2x7x_idtable[] = { + { "tsl2571", tsl2571 }, + { "tsl2671", tsl2671 }, + { "tmd2671", tmd2671 }, + { "tsl2771", tsl2771 }, + { "tmd2771", tmd2771 }, + { "tsl2572", tsl2572 }, + { "tsl2672", tsl2672 }, + { "tmd2672", tmd2672 }, + { "tsl2772", tsl2772 }, + { "tmd2772", tmd2772 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, tsl2x7x_idtable); + +static const struct dev_pm_ops tsl2x7x_pm_ops = { + .suspend = tsl2x7x_suspend, + .resume = tsl2x7x_resume, +}; + +/* Driver definition */ +static struct i2c_driver tsl2x7x_driver = { + .driver = { + .name = "tsl2x7x", + .pm = &tsl2x7x_pm_ops, + }, + .id_table = tsl2x7x_idtable, + .probe = tsl2x7x_probe, + .remove = __devexit_p(tsl2x7x_remove), +}; + +module_i2c_driver(tsl2x7x_driver); + +MODULE_AUTHOR("J. August Brenner"); +MODULE_DESCRIPTION("TAOS tsl2x7x ambient and proximity light sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/iio/magnetometer/Kconfig b/trunk/drivers/staging/iio/magnetometer/Kconfig index 722c4e13f713..b9d932595ba9 100644 --- a/trunk/drivers/staging/iio/magnetometer/Kconfig +++ b/trunk/drivers/staging/iio/magnetometer/Kconfig @@ -15,13 +15,13 @@ config SENSORS_AK8975 will be called ak8975. config SENSORS_HMC5843 - tristate "Honeywell HMC5843 3-Axis Magnetometer" + tristate "Honeywell HMC5843/5883/5883L 3-Axis Magnetometer" depends on I2C help - Say Y here to add support for the Honeywell HMC 5843 3-Axis - Magnetometer (digital compass). + Say Y here to add support for the Honeywell HMC5843, HMC5883 and + HMC5883L 3-Axis Magnetometer (digital compass). To compile this driver as a module, choose M here: the module - will be called hmc5843 + will be called hmc5843. endmenu diff --git a/trunk/drivers/staging/iio/magnetometer/ak8975.c b/trunk/drivers/staging/iio/magnetometer/ak8975.c index ebc2d0840caf..5834e4a70f8c 100644 --- a/trunk/drivers/staging/iio/magnetometer/ak8975.c +++ b/trunk/drivers/staging/iio/magnetometer/ak8975.c @@ -30,8 +30,8 @@ #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include /* * Register definitions, as well as various shifts and masks to get at the * individual fields of the registers. @@ -242,7 +242,7 @@ static int ak8975_setup(struct i2c_client *client) static ssize_t show_mode(struct device *dev, struct device_attribute *devattr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ak8975_data *data = iio_priv(indio_dev); return sprintf(buf, "%u\n", data->mode); @@ -255,7 +255,7 @@ static ssize_t show_mode(struct device *dev, struct device_attribute *devattr, static ssize_t store_mode(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ak8975_data *data = iio_priv(indio_dev); struct i2c_client *client = data->client; bool value; @@ -431,7 +431,7 @@ static int ak8975_read_raw(struct iio_dev *indio_dev, struct ak8975_data *data = iio_priv(indio_dev); switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: return ak8975_read_axis(indio_dev, chan->address, val); case IIO_CHAN_INFO_SCALE: *val = data->raw_to_gauss[chan->address]; @@ -445,7 +445,8 @@ static int ak8975_read_raw(struct iio_dev *indio_dev, .type = IIO_MAGN, \ .modified = 1, \ .channel2 = IIO_MOD_##axis, \ - .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ .address = index, \ } @@ -505,7 +506,7 @@ static int ak8975_probe(struct i2c_client *client, } /* Register with IIO */ - indio_dev = iio_allocate_device(sizeof(*data)); + indio_dev = iio_device_alloc(sizeof(*data)); if (indio_dev == NULL) { err = -ENOMEM; goto exit_gpio; @@ -536,7 +537,7 @@ static int ak8975_probe(struct i2c_client *client, return 0; exit_free_iio: - iio_free_device(indio_dev); + iio_device_free(indio_dev); exit_gpio: if (gpio_is_valid(eoc_gpio)) gpio_free(eoc_gpio); @@ -554,7 +555,7 @@ static int ak8975_remove(struct i2c_client *client) if (gpio_is_valid(data->eoc_gpio)) gpio_free(data->eoc_gpio); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/magnetometer/hmc5843.c b/trunk/drivers/staging/iio/magnetometer/hmc5843.c index e00b416c4d33..c1fa09f07625 100644 --- a/trunk/drivers/staging/iio/magnetometer/hmc5843.c +++ b/trunk/drivers/staging/iio/magnetometer/hmc5843.c @@ -2,6 +2,8 @@ Author: Shubhrajyoti Datta Acknowledgement: Jonathan Cameron for valuable inputs. + Support for HMC5883 and HMC5883L by Peter Meerwald . + 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 @@ -22,10 +24,8 @@ #include #include #include -#include "../iio.h" -#include "../sysfs.h" - -#define HMC5843_I2C_ADDRESS 0x1E +#include +#include #define HMC5843_CONFIG_REG_A 0x00 #define HMC5843_CONFIG_REG_B 0x01 @@ -36,110 +36,185 @@ #define HMC5843_DATA_OUT_Y_LSB_REG 0x06 #define HMC5843_DATA_OUT_Z_MSB_REG 0x07 #define HMC5843_DATA_OUT_Z_LSB_REG 0x08 +/* Beware: Y and Z are exchanged on HMC5883 */ +#define HMC5883_DATA_OUT_Z_MSB_REG 0x05 +#define HMC5883_DATA_OUT_Z_LSB_REG 0x06 +#define HMC5883_DATA_OUT_Y_MSB_REG 0x07 +#define HMC5883_DATA_OUT_Y_LSB_REG 0x08 #define HMC5843_STATUS_REG 0x09 #define HMC5843_ID_REG_A 0x0A #define HMC5843_ID_REG_B 0x0B #define HMC5843_ID_REG_C 0x0C +enum hmc5843_ids { + HMC5843_ID, + HMC5883_ID, + HMC5883L_ID, +}; + +/* + * Beware: identification of the HMC5883 is still "H43"; + * I2C address is also unchanged + */ #define HMC5843_ID_REG_LENGTH 0x03 #define HMC5843_ID_STRING "H43" +#define HMC5843_I2C_ADDRESS 0x1E /* - * Range settings in (+-)Ga - * */ -#define RANGE_GAIN_OFFSET 0x05 - -#define RANGE_0_7 0x00 -#define RANGE_1_0 0x01 /* default */ -#define RANGE_1_5 0x02 -#define RANGE_2_0 0x03 -#define RANGE_3_2 0x04 -#define RANGE_3_8 0x05 -#define RANGE_4_5 0x06 -#define RANGE_6_5 0x07 /* Not recommended */ + * Range gain settings in (+-)Ga + * Beware: HMC5843 and HMC5883 have different recommended sensor field + * ranges; default corresponds to +-1.0 Ga and +-1.3 Ga, respectively + */ +#define HMC5843_RANGE_GAIN_OFFSET 0x05 +#define HMC5843_RANGE_GAIN_DEFAULT 0x01 +#define HMC5843_RANGE_GAIN_MAX 0x07 /* * Device status */ -#define DATA_READY 0x01 -#define DATA_OUTPUT_LOCK 0x02 -#define VOLTAGE_REGULATOR_ENABLED 0x04 +#define HMC5843_DATA_READY 0x01 +#define HMC5843_DATA_OUTPUT_LOCK 0x02 +/* Does not exist on HMC5883, not used */ +#define HMC5843_VOLTAGE_REGULATOR_ENABLED 0x04 /* * Mode register configuration */ -#define MODE_CONVERSION_CONTINUOUS 0x00 -#define MODE_CONVERSION_SINGLE 0x01 -#define MODE_IDLE 0x02 -#define MODE_SLEEP 0x03 - -/* Minimum Data Output Rate in 1/10 Hz */ -#define RATE_OFFSET 0x02 -#define RATE_BITMASK 0x1C -#define RATE_5 0x00 -#define RATE_10 0x01 -#define RATE_20 0x02 -#define RATE_50 0x03 -#define RATE_100 0x04 -#define RATE_200 0x05 -#define RATE_500 0x06 -#define RATE_NOT_USED 0x07 +#define HMC5843_MODE_CONVERSION_CONTINUOUS 0x00 +#define HMC5843_MODE_CONVERSION_SINGLE 0x01 +#define HMC5843_MODE_IDLE 0x02 +#define HMC5843_MODE_SLEEP 0x03 +#define HMC5843_MODE_MASK 0x03 + +/* + * HMC5843: Minimum data output rate + * HMC5883: Typical data output rate + */ +#define HMC5843_RATE_OFFSET 0x02 +#define HMC5843_RATE_BITMASK 0x1C +#define HMC5843_RATE_NOT_USED 0x07 /* - * Device Configuration + * Device measurement configuration */ -#define CONF_NORMAL 0x00 -#define CONF_POSITIVE_BIAS 0x01 -#define CONF_NEGATIVE_BIAS 0x02 -#define CONF_NOT_USED 0x03 -#define MEAS_CONF_MASK 0x03 +#define HMC5843_MEAS_CONF_NORMAL 0x00 +#define HMC5843_MEAS_CONF_POSITIVE_BIAS 0x01 +#define HMC5843_MEAS_CONF_NEGATIVE_BIAS 0x02 +#define HMC5843_MEAS_CONF_NOT_USED 0x03 +#define HMC5843_MEAS_CONF_MASK 0x03 -static int hmc5843_regval_to_nanoscale[] = { +/* + * Scaling factors: 10000000/Gain + */ +static const int hmc5843_regval_to_nanoscale[] = { 6173, 7692, 10309, 12821, 18868, 21739, 25641, 35714 }; -static const int regval_to_input_field_mg[] = { - 700, - 1000, - 1500, - 2000, - 3200, - 3800, - 4500, - 6500 +static const int hmc5883_regval_to_nanoscale[] = { + 7812, 9766, 13021, 16287, 24096, 27701, 32573, 45662 }; -static const char * const regval_to_samp_freq[] = { - "0.5", - "1", - "2", - "5", - "10", - "20", - "50", + +static const int hmc5883l_regval_to_nanoscale[] = { + 7299, 9174, 12195, 15152, 22727, 25641, 30303, 43478 +}; + +/* + * From the HMC5843 datasheet: + * Value | Sensor input field range (Ga) | Gain (counts/milli-Gauss) + * 0 | (+-)0.7 | 1620 + * 1 | (+-)1.0 | 1300 + * 2 | (+-)1.5 | 970 + * 3 | (+-)2.0 | 780 + * 4 | (+-)3.2 | 530 + * 5 | (+-)3.8 | 460 + * 6 | (+-)4.5 | 390 + * 7 | (+-)6.5 | 280 + * + * From the HMC5883 datasheet: + * Value | Recommended sensor field range (Ga) | Gain (counts/Gauss) + * 0 | (+-)0.9 | 1280 + * 1 | (+-)1.2 | 1024 + * 2 | (+-)1.9 | 768 + * 3 | (+-)2.5 | 614 + * 4 | (+-)4.0 | 415 + * 5 | (+-)4.6 | 361 + * 6 | (+-)5.5 | 307 + * 7 | (+-)7.9 | 219 + * + * From the HMC5883L datasheet: + * Value | Recommended sensor field range (Ga) | Gain (LSB/Gauss) + * 0 | (+-)0.88 | 1370 + * 1 | (+-)1.3 | 1090 + * 2 | (+-)1.9 | 820 + * 3 | (+-)2.5 | 660 + * 4 | (+-)4.0 | 440 + * 5 | (+-)4.7 | 390 + * 6 | (+-)5.6 | 330 + * 7 | (+-)8.1 | 230 + */ +static const int hmc5843_regval_to_input_field_mga[] = { + 700, 1000, 1500, 2000, 3200, 3800, 4500, 6500 +}; + +static const int hmc5883_regval_to_input_field_mga[] = { + 900, 1200, 1900, 2500, 4000, 4600, 5500, 7900 +}; + +static const int hmc5883l_regval_to_input_field_mga[] = { + 880, 1300, 1900, 2500, 4000, 4700, 5600, 8100 +}; + +/* + * From the datasheet: + * Value | HMC5843 | HMC5883/HMC5883L + * | Data output rate (Hz) | Data output rate (Hz) + * 0 | 0.5 | 0.75 + * 1 | 1 | 1.5 + * 2 | 2 | 3 + * 3 | 5 | 7.5 + * 4 | 10 (default) | 15 + * 5 | 20 | 30 + * 6 | 50 | 75 + * 7 | Not used | Not used + */ +static const char * const hmc5843_regval_to_sample_freq[] = { + "0.5", "1", "2", "5", "10", "20", "50", +}; + +static const char * const hmc5883_regval_to_sample_freq[] = { + "0.75", "1.5", "3", "7.5", "15", "30", "75", }; /* Addresses to scan: 0x1E */ static const unsigned short normal_i2c[] = { HMC5843_I2C_ADDRESS, - I2C_CLIENT_END }; + I2C_CLIENT_END }; + +/* Describe chip variants */ +struct hmc5843_chip_info { + const struct iio_chan_spec *channels; + int num_channels; + const char * const *regval_to_sample_freq; + const int *regval_to_input_field_mga; + const int *regval_to_nanoscale; +}; /* Each client has this additional data */ struct hmc5843_data { struct mutex lock; - u8 rate; - u8 meas_conf; - u8 operating_mode; - u8 range; + u8 rate; + u8 meas_conf; + u8 operating_mode; + u8 range; + const struct hmc5843_chip_info *variant; }; -static void hmc5843_init_client(struct i2c_client *client); - +/* The lower two bits contain the current conversion mode */ static s32 hmc5843_configure(struct i2c_client *client, u8 operating_mode) { - /* The lower two bits contain the current conversion mode */ return i2c_smbus_write_byte_data(client, HMC5843_MODE_REG, - (operating_mode & 0x03)); + operating_mode & HMC5843_MODE_MASK); } /* Return the measurement value from the specified channel */ @@ -153,7 +228,7 @@ static int hmc5843_read_measurement(struct iio_dev *indio_dev, mutex_lock(&data->lock); result = i2c_smbus_read_byte_data(client, HMC5843_STATUS_REG); - while (!(result & DATA_READY)) + while (!(result & HMC5843_DATA_READY)) result = i2c_smbus_read_byte_data(client, HMC5843_STATUS_REG); result = i2c_smbus_read_word_data(client, address); @@ -161,30 +236,29 @@ static int hmc5843_read_measurement(struct iio_dev *indio_dev, if (result < 0) return -EINVAL; - *val = (s16)swab16((u16)result); + *val = (s16)swab16((u16)result); return IIO_VAL_INT; } - /* - * From the datasheet + * From the datasheet: * 0 - Continuous-Conversion Mode: In continuous-conversion mode, the - * device continuously performs conversions and places the result in the - * data register. + * device continuously performs conversions and places the result in + * the data register. * - * 1 - Single-Conversion Mode : device performs a single measurement, - * sets RDY high and returned to sleep mode + * 1 - Single-Conversion Mode : Device performs a single measurement, + * sets RDY high and returns to sleep mode. * - * 2 - Idle Mode : Device is placed in idle mode. + * 2 - Idle Mode : Device is placed in idle mode. * - * 3 - Sleep Mode. Device is placed in sleep mode. + * 3 - Sleep Mode : Device is placed in sleep mode. * */ static ssize_t hmc5843_show_operating_mode(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct hmc5843_data *data = iio_priv(indio_dev); return sprintf(buf, "%d\n", data->operating_mode); } @@ -194,21 +268,22 @@ static ssize_t hmc5843_set_operating_mode(struct device *dev, const char *buf, size_t count) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct i2c_client *client = to_i2c_client(indio_dev->dev.parent); struct hmc5843_data *data = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); unsigned long operating_mode = 0; s32 status; int error; + mutex_lock(&data->lock); - error = strict_strtoul(buf, 10, &operating_mode); + error = kstrtoul(buf, 10, &operating_mode); if (error) { count = error; goto exit; } - dev_dbg(dev, "set Conversion mode to %lu\n", operating_mode); - if (operating_mode > MODE_SLEEP) { + dev_dbg(dev, "set conversion mode to %lu\n", operating_mode); + if (operating_mode > HMC5843_MODE_SLEEP) { count = -EINVAL; goto exit; } @@ -225,6 +300,7 @@ static ssize_t hmc5843_set_operating_mode(struct device *dev, mutex_unlock(&data->lock); return count; } + static IIO_DEVICE_ATTR(operating_mode, S_IWUSR | S_IRUGO, hmc5843_show_operating_mode, @@ -234,25 +310,29 @@ static IIO_DEVICE_ATTR(operating_mode, /* * API for setting the measurement configuration to * Normal, Positive bias and Negative bias - * From the datasheet * - * Normal measurement configuration (default): In normal measurement - * configuration the device follows normal measurement flow. Pins BP and BN - * are left floating and high impedance. + * From the datasheet: + * 0 - Normal measurement configuration (default): In normal measurement + * configuration the device follows normal measurement flow. Pins BP + * and BN are left floating and high impedance. * - * Positive bias configuration: In positive bias configuration, a positive - * current is forced across the resistive load on pins BP and BN. + * 1 - Positive bias configuration: In positive bias configuration, a + * positive current is forced across the resistive load on pins BP + * and BN. * - * Negative bias configuration. In negative bias configuration, a negative - * current is forced across the resistive load on pins BP and BN. + * 2 - Negative bias configuration. In negative bias configuration, a + * negative current is forced across the resistive load on pins BP + * and BN. * */ static s32 hmc5843_set_meas_conf(struct i2c_client *client, u8 meas_conf) { - struct hmc5843_data *data = i2c_get_clientdata(client); + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct hmc5843_data *data = iio_priv(indio_dev); u8 reg_val; - reg_val = (meas_conf & MEAS_CONF_MASK) | (data->rate << RATE_OFFSET); + reg_val = (meas_conf & HMC5843_MEAS_CONF_MASK) | + (data->rate << HMC5843_RATE_OFFSET); return i2c_smbus_write_byte_data(client, HMC5843_CONFIG_REG_A, reg_val); } @@ -260,7 +340,7 @@ static ssize_t hmc5843_show_measurement_configuration(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct hmc5843_data *data = iio_priv(indio_dev); return sprintf(buf, "%d\n", data->meas_conf); } @@ -270,16 +350,20 @@ static ssize_t hmc5843_set_measurement_configuration(struct device *dev, const char *buf, size_t count) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct i2c_client *client = to_i2c_client(indio_dev->dev.parent); - struct hmc5843_data *data = i2c_get_clientdata(client); + struct hmc5843_data *data = iio_priv(indio_dev); unsigned long meas_conf = 0; - int error = strict_strtoul(buf, 10, &meas_conf); + int error; + + error = kstrtoul(buf, 10, &meas_conf); if (error) return error; - mutex_lock(&data->lock); + if (meas_conf >= HMC5843_MEAS_CONF_NOT_USED) + return -EINVAL; - dev_dbg(dev, "set mode to %lu\n", meas_conf); + mutex_lock(&data->lock); + dev_dbg(dev, "set measurement configuration to %lu\n", meas_conf); if (hmc5843_set_meas_conf(client, meas_conf)) { count = -EINVAL; goto exit; @@ -290,71 +374,85 @@ static ssize_t hmc5843_set_measurement_configuration(struct device *dev, mutex_unlock(&data->lock); return count; } + static IIO_DEVICE_ATTR(meas_conf, S_IWUSR | S_IRUGO, hmc5843_show_measurement_configuration, hmc5843_set_measurement_configuration, 0); -/* - * From Datasheet - * The table shows the minimum data output - * Value | Minimum data output rate(Hz) - * 0 | 0.5 - * 1 | 1 - * 2 | 2 - * 3 | 5 - * 4 | 10 (default) - * 5 | 20 - * 6 | 50 - * 7 | Not used - */ -static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("0.5 1 2 5 10 20 50"); +static ssize_t hmc5843_show_sampling_frequencies_available(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct hmc5843_data *data = iio_priv(indio_dev); + ssize_t total_n = 0; + int i; + + for (i = 0; i < HMC5843_RATE_NOT_USED; i++) { + ssize_t n = sprintf(buf, "%s ", data->variant->regval_to_sample_freq[i]); + buf += n; + total_n += n; + } + /* replace trailing space by newline */ + buf[-1] = '\n'; + + return total_n; +} + +static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(hmc5843_show_sampling_frequencies_available); static s32 hmc5843_set_rate(struct i2c_client *client, u8 rate) { - struct hmc5843_data *data = i2c_get_clientdata(client); + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct hmc5843_data *data = iio_priv(indio_dev); u8 reg_val; - reg_val = (data->meas_conf) | (rate << RATE_OFFSET); - if (rate >= RATE_NOT_USED) { + if (rate >= HMC5843_RATE_NOT_USED) { dev_err(&client->dev, - "This data output rate is not supported\n"); + "data output rate is not supported\n"); return -EINVAL; } + + reg_val = data->meas_conf | (rate << HMC5843_RATE_OFFSET); return i2c_smbus_write_byte_data(client, HMC5843_CONFIG_REG_A, reg_val); } -static ssize_t set_sampling_frequency(struct device *dev, +static int hmc5843_check_sampling_frequency(struct hmc5843_data *data, + const char *buf) +{ + const char * const *samp_freq = data->variant->regval_to_sample_freq; + int i; + + for (i = 0; i < HMC5843_RATE_NOT_USED; i++) { + if (sysfs_streq(buf, samp_freq[i])) + return i; + } + + return -EINVAL; +} + +static ssize_t hmc5843_set_sampling_frequency(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct i2c_client *client = to_i2c_client(indio_dev->dev.parent); struct hmc5843_data *data = iio_priv(indio_dev); - unsigned long rate = 0; - - if (strncmp(buf, "0.5" , 3) == 0) - rate = RATE_5; - else if (strncmp(buf, "1" , 1) == 0) - rate = RATE_10; - else if (strncmp(buf, "2", 1) == 0) - rate = RATE_20; - else if (strncmp(buf, "5", 1) == 0) - rate = RATE_50; - else if (strncmp(buf, "10", 2) == 0) - rate = RATE_100; - else if (strncmp(buf, "20" , 2) == 0) - rate = RATE_200; - else if (strncmp(buf, "50" , 2) == 0) - rate = RATE_500; - else - return -EINVAL; + int rate; + + rate = hmc5843_check_sampling_frequency(data, buf); + if (rate < 0) { + dev_err(&client->dev, + "sampling frequency is not supported\n"); + return rate; + } mutex_lock(&data->lock); - dev_dbg(dev, "set rate to %lu\n", rate); + dev_dbg(dev, "set rate to %d\n", rate); if (hmc5843_set_rate(client, rate)) { count = -EINVAL; goto exit; @@ -366,89 +464,79 @@ static ssize_t set_sampling_frequency(struct device *dev, return count; } -static ssize_t show_sampling_frequency(struct device *dev, +static ssize_t hmc5843_show_sampling_frequency(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct i2c_client *client = to_i2c_client(indio_dev->dev.parent); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + struct hmc5843_data *data = iio_priv(indio_dev); s32 rate; - rate = i2c_smbus_read_byte_data(client, this_attr->address); + rate = i2c_smbus_read_byte_data(client, this_attr->address); if (rate < 0) return rate; - rate = (rate & RATE_BITMASK) >> RATE_OFFSET; - return sprintf(buf, "%s\n", regval_to_samp_freq[rate]); + rate = (rate & HMC5843_RATE_BITMASK) >> HMC5843_RATE_OFFSET; + return sprintf(buf, "%s\n", data->variant->regval_to_sample_freq[rate]); } + static IIO_DEVICE_ATTR(sampling_frequency, S_IWUSR | S_IRUGO, - show_sampling_frequency, - set_sampling_frequency, + hmc5843_show_sampling_frequency, + hmc5843_set_sampling_frequency, HMC5843_CONFIG_REG_A); -/* - * From Datasheet - * Nominal gain settings - * Value | Sensor Input Field Range(Ga) | Gain(counts/ milli-gauss) - *0 |(+-)0.7 |1620 - *1 |(+-)1.0 |1300 - *2 |(+-)1.5 |970 - *3 |(+-)2.0 |780 - *4 |(+-)3.2 |530 - *5 |(+-)3.8 |460 - *6 |(+-)4.5 |390 - *7 |(+-)6.5 |280 - */ -static ssize_t show_range(struct device *dev, +static ssize_t hmc5843_show_range_gain(struct device *dev, struct device_attribute *attr, char *buf) { u8 range; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct hmc5843_data *data = iio_priv(indio_dev); range = data->range; - return sprintf(buf, "%d\n", regval_to_input_field_mg[range]); + return sprintf(buf, "%d\n", data->variant->regval_to_input_field_mga[range]); } -static ssize_t set_range(struct device *dev, +static ssize_t hmc5843_set_range_gain(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct i2c_client *client = to_i2c_client(indio_dev->dev.parent); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); struct hmc5843_data *data = iio_priv(indio_dev); unsigned long range = 0; int error; + mutex_lock(&data->lock); - error = strict_strtoul(buf, 10, &range); + error = kstrtoul(buf, 10, &range); if (error) { count = error; goto exit; } dev_dbg(dev, "set range to %lu\n", range); - if (range > RANGE_6_5) { + if (range > HMC5843_RANGE_GAIN_MAX) { count = -EINVAL; goto exit; } data->range = range; - range = range << RANGE_GAIN_OFFSET; + range = range << HMC5843_RANGE_GAIN_OFFSET; if (i2c_smbus_write_byte_data(client, this_attr->address, range)) count = -EINVAL; exit: mutex_unlock(&data->lock); return count; - } + static IIO_DEVICE_ATTR(in_magn_range, S_IWUSR | S_IRUGO, - show_range, - set_range, + hmc5843_show_range_gain, + hmc5843_set_range_gain, HMC5843_CONFIG_REG_B); static int hmc5843_read_raw(struct iio_dev *indio_dev, @@ -459,13 +547,13 @@ static int hmc5843_read_raw(struct iio_dev *indio_dev, struct hmc5843_data *data = iio_priv(indio_dev); switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: return hmc5843_read_measurement(indio_dev, chan->address, val); case IIO_CHAN_INFO_SCALE: *val = 0; - *val2 = hmc5843_regval_to_nanoscale[data->range]; + *val2 = data->variant->regval_to_nanoscale[data->range]; return IIO_VAL_INT_PLUS_NANO; }; return -EINVAL; @@ -476,7 +564,8 @@ static int hmc5843_read_raw(struct iio_dev *indio_dev, .type = IIO_MAGN, \ .modified = 1, \ .channel2 = IIO_MOD_##axis, \ - .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SHARED_BIT, \ .address = add \ } @@ -486,12 +575,18 @@ static const struct iio_chan_spec hmc5843_channels[] = { HMC5843_CHANNEL(Z, HMC5843_DATA_OUT_Z_MSB_REG), }; +static const struct iio_chan_spec hmc5883_channels[] = { + HMC5843_CHANNEL(X, HMC5843_DATA_OUT_X_MSB_REG), + HMC5843_CHANNEL(Y, HMC5883_DATA_OUT_Y_MSB_REG), + HMC5843_CHANNEL(Z, HMC5883_DATA_OUT_Z_MSB_REG), +}; + static struct attribute *hmc5843_attributes[] = { &iio_dev_attr_meas_conf.dev_attr.attr, &iio_dev_attr_operating_mode.dev_attr.attr, &iio_dev_attr_sampling_frequency.dev_attr.attr, &iio_dev_attr_in_magn_range.dev_attr.attr, - &iio_const_attr_sampling_frequency_available.dev_attr.attr, + &iio_dev_attr_sampling_frequency_available.dev_attr.attr, NULL }; @@ -499,6 +594,33 @@ static const struct attribute_group hmc5843_group = { .attrs = hmc5843_attributes, }; +static const struct hmc5843_chip_info hmc5843_chip_info_tbl[] = { + [HMC5843_ID] = { + .channels = hmc5843_channels, + .num_channels = ARRAY_SIZE(hmc5843_channels), + .regval_to_sample_freq = hmc5843_regval_to_sample_freq, + .regval_to_input_field_mga = + hmc5843_regval_to_input_field_mga, + .regval_to_nanoscale = hmc5843_regval_to_nanoscale, + }, + [HMC5883_ID] = { + .channels = hmc5883_channels, + .num_channels = ARRAY_SIZE(hmc5883_channels), + .regval_to_sample_freq = hmc5883_regval_to_sample_freq, + .regval_to_input_field_mga = + hmc5883_regval_to_input_field_mga, + .regval_to_nanoscale = hmc5883_regval_to_nanoscale, + }, + [HMC5883L_ID] = { + .channels = hmc5883_channels, + .num_channels = ARRAY_SIZE(hmc5883_channels), + .regval_to_sample_freq = hmc5883_regval_to_sample_freq, + .regval_to_input_field_mga = + hmc5883l_regval_to_input_field_mga, + .regval_to_nanoscale = hmc5883l_regval_to_nanoscale, + }, +}; + static int hmc5843_detect(struct i2c_client *client, struct i2c_board_info *info) { @@ -518,18 +640,23 @@ static int hmc5843_detect(struct i2c_client *client, return 0; } -/* Called when we have found a new HMC5843. */ -static void hmc5843_init_client(struct i2c_client *client) +/* Called when we have found a new HMC58X3 */ +static void hmc5843_init_client(struct i2c_client *client, + const struct i2c_device_id *id) { struct iio_dev *indio_dev = i2c_get_clientdata(client); struct hmc5843_data *data = iio_priv(indio_dev); + data->variant = &hmc5843_chip_info_tbl[id->driver_data]; + indio_dev->channels = data->variant->channels; + indio_dev->num_channels = data->variant->num_channels; hmc5843_set_meas_conf(client, data->meas_conf); hmc5843_set_rate(client, data->rate); hmc5843_configure(client, data->operating_mode); i2c_smbus_write_byte_data(client, HMC5843_CONFIG_REG_B, data->range); mutex_init(&data->lock); - pr_info("HMC5843 initialized\n"); + + pr_info("%s initialized\n", id->name); } static const struct iio_info hmc5843_info = { @@ -545,35 +672,34 @@ static int hmc5843_probe(struct i2c_client *client, struct iio_dev *indio_dev; int err = 0; - indio_dev = iio_allocate_device(sizeof(*data)); + indio_dev = iio_device_alloc(sizeof(*data)); if (indio_dev == NULL) { err = -ENOMEM; goto exit; } - data = iio_priv(indio_dev); - /* default settings at probe */ - data->meas_conf = CONF_NORMAL; - data->range = RANGE_1_0; - data->operating_mode = MODE_CONVERSION_CONTINUOUS; + /* default settings at probe */ + data = iio_priv(indio_dev); + data->meas_conf = HMC5843_MEAS_CONF_NORMAL; + data->range = HMC5843_RANGE_GAIN_DEFAULT; + data->operating_mode = HMC5843_MODE_CONVERSION_CONTINUOUS; i2c_set_clientdata(client, indio_dev); - - /* Initialize the HMC5843 chip */ - hmc5843_init_client(client); + hmc5843_init_client(client, id); indio_dev->info = &hmc5843_info; indio_dev->name = id->name; - indio_dev->channels = hmc5843_channels; - indio_dev->num_channels = ARRAY_SIZE(hmc5843_channels); indio_dev->dev.parent = &client->dev; indio_dev->modes = INDIO_DIRECT_MODE; + err = iio_device_register(indio_dev); if (err) goto exit_free2; + return 0; + exit_free2: - iio_free_device(indio_dev); + iio_device_free(indio_dev); exit: return err; } @@ -584,8 +710,8 @@ static int hmc5843_remove(struct i2c_client *client) iio_device_unregister(indio_dev); /* sleep mode to save power */ - hmc5843_configure(client, MODE_SLEEP); - iio_free_device(indio_dev); + hmc5843_configure(client, HMC5843_MODE_SLEEP); + iio_device_free(indio_dev); return 0; } @@ -593,14 +719,18 @@ static int hmc5843_remove(struct i2c_client *client) #ifdef CONFIG_PM_SLEEP static int hmc5843_suspend(struct device *dev) { - hmc5843_configure(to_i2c_client(dev), MODE_SLEEP); + hmc5843_configure(to_i2c_client(dev), HMC5843_MODE_SLEEP); return 0; } static int hmc5843_resume(struct device *dev) { - struct hmc5843_data *data = i2c_get_clientdata(to_i2c_client(dev)); - hmc5843_configure(to_i2c_client(dev), data->operating_mode); + struct i2c_client *client = to_i2c_client(dev); + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct hmc5843_data *data = iio_priv(indio_dev); + + hmc5843_configure(client, data->operating_mode); + return 0; } @@ -611,7 +741,9 @@ static SIMPLE_DEV_PM_OPS(hmc5843_pm_ops, hmc5843_suspend, hmc5843_resume); #endif static const struct i2c_device_id hmc5843_id[] = { - { "hmc5843", 0 }, + { "hmc5843", HMC5843_ID }, + { "hmc5883", HMC5883_ID }, + { "hmc5883l", HMC5883L_ID }, { } }; MODULE_DEVICE_TABLE(i2c, hmc5843_id); @@ -630,5 +762,5 @@ static struct i2c_driver hmc5843_driver = { module_i2c_driver(hmc5843_driver); MODULE_AUTHOR("Shubhrajyoti Datta #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #include "meter.h" #include "ade7753.h" @@ -28,7 +28,7 @@ static int ade7753_spi_write_reg_8(struct device *dev, u8 val) { int ret; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7753_state *st = iio_priv(indio_dev); mutex_lock(&st->buf_lock); @@ -46,7 +46,7 @@ static int ade7753_spi_write_reg_16(struct device *dev, u16 value) { int ret; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7753_state *st = iio_priv(indio_dev); mutex_lock(&st->buf_lock); @@ -63,7 +63,7 @@ static int ade7753_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7753_state *st = iio_priv(indio_dev); ssize_t ret; @@ -82,7 +82,7 @@ static int ade7753_spi_read_reg_16(struct device *dev, u8 reg_address, u16 *val) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7753_state *st = iio_priv(indio_dev); ssize_t ret; @@ -104,7 +104,7 @@ static int ade7753_spi_read_reg_24(struct device *dev, u32 *val) { struct spi_message msg; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7753_state *st = iio_priv(indio_dev); int ret; struct spi_transfer xfers[] = { @@ -416,7 +416,7 @@ static ssize_t ade7753_write_frequency(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7753_state *st = iio_priv(indio_dev); unsigned long val; int ret; @@ -517,7 +517,7 @@ static int __devinit ade7753_probe(struct spi_device *spi) struct iio_dev *indio_dev; /* setup the industrialio driver allocated elements */ - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -546,7 +546,7 @@ static int __devinit ade7753_probe(struct spi_device *spi) return 0; error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; @@ -564,7 +564,7 @@ static int ade7753_remove(struct spi_device *spi) if (ret) goto err_ret; - iio_free_device(indio_dev); + iio_device_free(indio_dev); err_ret: return ret; } diff --git a/trunk/drivers/staging/iio/meter/ade7754.c b/trunk/drivers/staging/iio/meter/ade7754.c index 8d81c92007e9..6cee28a5e877 100644 --- a/trunk/drivers/staging/iio/meter/ade7754.c +++ b/trunk/drivers/staging/iio/meter/ade7754.c @@ -18,8 +18,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #include "meter.h" #include "ade7754.h" @@ -28,7 +28,7 @@ static int ade7754_spi_write_reg_8(struct device *dev, u8 val) { int ret; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7754_state *st = iio_priv(indio_dev); mutex_lock(&st->buf_lock); @@ -46,7 +46,7 @@ static int ade7754_spi_write_reg_16(struct device *dev, u16 value) { int ret; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7754_state *st = iio_priv(indio_dev); mutex_lock(&st->buf_lock); @@ -63,7 +63,7 @@ static int ade7754_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7754_state *st = iio_priv(indio_dev); int ret; @@ -82,7 +82,7 @@ static int ade7754_spi_read_reg_16(struct device *dev, u8 reg_address, u16 *val) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7754_state *st = iio_priv(indio_dev); int ret; @@ -104,7 +104,7 @@ static int ade7754_spi_read_reg_24(struct device *dev, u32 *val) { struct spi_message msg; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7754_state *st = iio_priv(indio_dev); int ret; struct spi_transfer xfers[] = { @@ -436,7 +436,7 @@ static ssize_t ade7754_write_frequency(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7754_state *st = iio_priv(indio_dev); unsigned long val; int ret; @@ -540,7 +540,7 @@ static int __devinit ade7754_probe(struct spi_device *spi) struct iio_dev *indio_dev; /* setup the industrialio driver allocated elements */ - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -568,7 +568,7 @@ static int __devinit ade7754_probe(struct spi_device *spi) return 0; error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; @@ -585,7 +585,7 @@ static int ade7754_remove(struct spi_device *spi) if (ret) goto err_ret; - iio_free_device(indio_dev); + iio_device_free(indio_dev); err_ret: return ret; diff --git a/trunk/drivers/staging/iio/meter/ade7758_core.c b/trunk/drivers/staging/iio/meter/ade7758_core.c index dcb20294dfe8..96d6114a31aa 100644 --- a/trunk/drivers/staging/iio/meter/ade7758_core.c +++ b/trunk/drivers/staging/iio/meter/ade7758_core.c @@ -18,9 +18,9 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" -#include "../buffer.h" +#include +#include +#include #include "meter.h" #include "ade7758.h" @@ -29,7 +29,7 @@ int ade7758_spi_write_reg_8(struct device *dev, u8 val) { int ret; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7758_state *st = iio_priv(indio_dev); mutex_lock(&st->buf_lock); @@ -48,7 +48,7 @@ static int ade7758_spi_write_reg_16(struct device *dev, { int ret; struct spi_message msg; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7758_state *st = iio_priv(indio_dev); struct spi_transfer xfers[] = { { @@ -77,7 +77,7 @@ static int ade7758_spi_write_reg_24(struct device *dev, { int ret; struct spi_message msg; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7758_state *st = iio_priv(indio_dev); struct spi_transfer xfers[] = { { @@ -106,7 +106,7 @@ int ade7758_spi_read_reg_8(struct device *dev, u8 *val) { struct spi_message msg; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7758_state *st = iio_priv(indio_dev); int ret; struct spi_transfer xfers[] = { @@ -149,7 +149,7 @@ static int ade7758_spi_read_reg_16(struct device *dev, u16 *val) { struct spi_message msg; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7758_state *st = iio_priv(indio_dev); int ret; struct spi_transfer xfers[] = { @@ -195,7 +195,7 @@ static int ade7758_spi_read_reg_24(struct device *dev, u32 *val) { struct spi_message msg; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7758_state *st = iio_priv(indio_dev); int ret; struct spi_transfer xfers[] = { @@ -534,7 +534,7 @@ static ssize_t ade7758_write_frequency(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); unsigned long val; int ret; u8 reg, t; @@ -662,66 +662,217 @@ static const struct attribute_group ade7758_attribute_group = { }; static struct iio_chan_spec ade7758_channels[] = { - IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "raw", 0, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - AD7758_WT(AD7758_PHASE_A, AD7758_VOLTAGE), - 0, IIO_ST('s', 24, 32, 0), 0), - IIO_CHAN(IIO_CURRENT, 0, 1, 0, "raw", 0, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - AD7758_WT(AD7758_PHASE_A, AD7758_CURRENT), - 1, IIO_ST('s', 24, 32, 0), 0), - IIO_CHAN(IIO_POWER, 0, 1, 0, "apparent_raw", 0, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - AD7758_WT(AD7758_PHASE_A, AD7758_APP_PWR), - 2, IIO_ST('s', 24, 32, 0), 0), - IIO_CHAN(IIO_POWER, 0, 1, 0, "active_raw", 0, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - AD7758_WT(AD7758_PHASE_A, AD7758_ACT_PWR), - 3, IIO_ST('s', 24, 32, 0), 0), - IIO_CHAN(IIO_POWER, 0, 1, 0, "reactive_raw", 0, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - AD7758_WT(AD7758_PHASE_A, AD7758_REACT_PWR), - 4, IIO_ST('s', 24, 32, 0), 0), - IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "raw", 1, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - AD7758_WT(AD7758_PHASE_B, AD7758_VOLTAGE), - 5, IIO_ST('s', 24, 32, 0), 0), - IIO_CHAN(IIO_CURRENT, 0, 1, 0, "raw", 1, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - AD7758_WT(AD7758_PHASE_B, AD7758_CURRENT), - 6, IIO_ST('s', 24, 32, 0), 0), - IIO_CHAN(IIO_POWER, 0, 1, 0, "apparent_raw", 1, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - AD7758_WT(AD7758_PHASE_B, AD7758_APP_PWR), - 7, IIO_ST('s', 24, 32, 0), 0), - IIO_CHAN(IIO_POWER, 0, 1, 0, "active_raw", 1, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - AD7758_WT(AD7758_PHASE_B, AD7758_ACT_PWR), - 8, IIO_ST('s', 24, 32, 0), 0), - IIO_CHAN(IIO_POWER, 0, 1, 0, "reactive_raw", 1, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - AD7758_WT(AD7758_PHASE_B, AD7758_REACT_PWR), - 9, IIO_ST('s', 24, 32, 0), 0), - IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "raw", 2, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - AD7758_WT(AD7758_PHASE_C, AD7758_VOLTAGE), - 10, IIO_ST('s', 24, 32, 0), 0), - IIO_CHAN(IIO_CURRENT, 0, 1, 0, "raw", 2, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - AD7758_WT(AD7758_PHASE_C, AD7758_CURRENT), - 11, IIO_ST('s', 24, 32, 0), 0), - IIO_CHAN(IIO_POWER, 0, 1, 0, "apparent_raw", 2, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - AD7758_WT(AD7758_PHASE_C, AD7758_APP_PWR), - 12, IIO_ST('s', 24, 32, 0), 0), - IIO_CHAN(IIO_POWER, 0, 1, 0, "active_raw", 2, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - AD7758_WT(AD7758_PHASE_C, AD7758_ACT_PWR), - 13, IIO_ST('s', 24, 32, 0), 0), - IIO_CHAN(IIO_POWER, 0, 1, 0, "reactive_raw", 2, 0, - IIO_CHAN_INFO_SCALE_SHARED_BIT, - AD7758_WT(AD7758_PHASE_C, AD7758_REACT_PWR), - 14, IIO_ST('s', 24, 32, 0), 0), + { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 0, + .extend_name = "raw", + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, + .address = AD7758_WT(AD7758_PHASE_A, AD7758_VOLTAGE), + .scan_index = 0, + .scan_type = { + .sign = 's', + .realbits = 24, + .storagebits = 32, + }, + }, { + .type = IIO_CURRENT, + .indexed = 1, + .channel = 0, + .extend_name = "raw", + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, + .address = AD7758_WT(AD7758_PHASE_A, AD7758_CURRENT), + .scan_index = 1, + .scan_type = { + .sign = 's', + .realbits = 24, + .storagebits = 32, + }, + }, { + .type = IIO_POWER, + .indexed = 1, + .channel = 0, + .extend_name = "apparent_raw", + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, + .address = AD7758_WT(AD7758_PHASE_A, AD7758_APP_PWR), + .scan_index = 2, + .scan_type = { + .sign = 's', + .realbits = 24, + .storagebits = 32, + }, + }, { + .type = IIO_POWER, + .indexed = 1, + .channel = 0, + .extend_name = "active_raw", + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, + .address = AD7758_WT(AD7758_PHASE_A, AD7758_ACT_PWR), + .scan_index = 3, + .scan_type = { + .sign = 's', + .realbits = 24, + .storagebits = 32, + }, + }, { + .type = IIO_POWER, + .indexed = 1, + .channel = 0, + .extend_name = "reactive_raw", + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, + .address = AD7758_WT(AD7758_PHASE_A, AD7758_REACT_PWR), + .scan_index = 4, + .scan_type = { + .sign = 's', + .realbits = 24, + .storagebits = 32, + }, + }, { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 1, + .extend_name = "raw", + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, + .address = AD7758_WT(AD7758_PHASE_B, AD7758_VOLTAGE), + .scan_index = 5, + .scan_type = { + .sign = 's', + .realbits = 24, + .storagebits = 32, + }, + }, { + .type = IIO_CURRENT, + .indexed = 1, + .channel = 1, + .extend_name = "raw", + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, + .address = AD7758_WT(AD7758_PHASE_B, AD7758_CURRENT), + .scan_index = 6, + .scan_type = { + .sign = 's', + .realbits = 24, + .storagebits = 32, + }, + }, { + .type = IIO_POWER, + .indexed = 1, + .channel = 1, + .extend_name = "apparent_raw", + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, + .address = AD7758_WT(AD7758_PHASE_B, AD7758_APP_PWR), + .scan_index = 7, + .scan_type = { + .sign = 's', + .realbits = 24, + .storagebits = 32, + }, + }, { + .type = IIO_POWER, + .indexed = 1, + .channel = 1, + .extend_name = "active_raw", + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, + .address = AD7758_WT(AD7758_PHASE_B, AD7758_ACT_PWR), + .scan_index = 8, + .scan_type = { + .sign = 's', + .realbits = 24, + .storagebits = 32, + }, + }, { + .type = IIO_POWER, + .indexed = 1, + .channel = 1, + .extend_name = "reactive_raw", + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, + .address = AD7758_WT(AD7758_PHASE_B, AD7758_REACT_PWR), + .scan_index = 9, + .scan_type = { + .sign = 's', + .realbits = 24, + .storagebits = 32, + }, + }, { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 2, + .extend_name = "raw", + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, + .address = AD7758_WT(AD7758_PHASE_C, AD7758_VOLTAGE), + .scan_index = 10, + .scan_type = { + .sign = 's', + .realbits = 24, + .storagebits = 32, + }, + }, { + .type = IIO_CURRENT, + .indexed = 1, + .channel = 2, + .extend_name = "raw", + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, + .address = AD7758_WT(AD7758_PHASE_C, AD7758_CURRENT), + .scan_index = 11, + .scan_type = { + .sign = 's', + .realbits = 24, + .storagebits = 32, + }, + }, { + .type = IIO_POWER, + .indexed = 1, + .channel = 2, + .extend_name = "apparent_raw", + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, + .address = AD7758_WT(AD7758_PHASE_C, AD7758_APP_PWR), + .scan_index = 12, + .scan_type = { + .sign = 's', + .realbits = 24, + .storagebits = 32, + }, + }, { + .type = IIO_POWER, + .indexed = 1, + .channel = 2, + .extend_name = "active_raw", + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, + .address = AD7758_WT(AD7758_PHASE_C, AD7758_ACT_PWR), + .scan_index = 13, + .scan_type = { + .sign = 's', + .realbits = 24, + .storagebits = 32, + }, + }, { + .type = IIO_POWER, + .indexed = 1, + .channel = 2, + .extend_name = "reactive_raw", + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, + .address = AD7758_WT(AD7758_PHASE_C, AD7758_REACT_PWR), + .scan_index = 14, + .scan_type = { + .sign = 's', + .realbits = 24, + .storagebits = 32, + }, + }, IIO_CHAN_SOFT_TIMESTAMP(15), }; @@ -734,7 +885,7 @@ static int __devinit ade7758_probe(struct spi_device *spi) { int i, ret; struct ade7758_state *st; - struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st)); + struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; @@ -800,7 +951,7 @@ static int __devinit ade7758_probe(struct spi_device *spi) return 0; error_remove_trigger: - if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) + if (spi->irq) ade7758_remove_trigger(indio_dev); error_uninitialize_ring: ade7758_uninitialize_ring(indio_dev); @@ -811,7 +962,7 @@ static int __devinit ade7758_probe(struct spi_device *spi) error_free_rx: kfree(st->rx); error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; } @@ -833,7 +984,7 @@ static int ade7758_remove(struct spi_device *spi) kfree(st->tx); kfree(st->rx); - iio_free_device(indio_dev); + iio_device_free(indio_dev); err_ret: return ret; diff --git a/trunk/drivers/staging/iio/meter/ade7758_ring.c b/trunk/drivers/staging/iio/meter/ade7758_ring.c index c45b23bb1229..92159f208d14 100644 --- a/trunk/drivers/staging/iio/meter/ade7758_ring.c +++ b/trunk/drivers/staging/iio/meter/ade7758_ring.c @@ -12,18 +12,17 @@ #include #include -#include "../iio.h" +#include #include "../ring_sw.h" -#include "../trigger_consumer.h" +#include #include "ade7758.h" /** * ade7758_spi_read_burst() - read data registers - * @dev: device associated with child of actual device (iio_dev or iio_trig) + * @indio_dev: the IIO device **/ -static int ade7758_spi_read_burst(struct device *dev) +static int ade7758_spi_read_burst(struct iio_dev *indio_dev) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ade7758_state *st = iio_priv(indio_dev); int ret; @@ -68,11 +67,11 @@ static irqreturn_t ade7758_trigger_handler(int irq, void *p) u32 *dat32 = (u32 *)dat64; if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) - if (ade7758_spi_read_burst(&indio_dev->dev) >= 0) + if (ade7758_spi_read_burst(indio_dev) >= 0) *dat32 = get_unaligned_be32(&st->rx_buf[5]) & 0xFFFFFF; /* Guaranteed to be aligned with 8 byte boundary */ - if (ring->scan_timestamp) + if (indio_dev->scan_timestamp) dat64[1] = pf->timestamp; ring->access->store_to(ring, (u8 *)dat64, pf->timestamp); @@ -92,29 +91,19 @@ static irqreturn_t ade7758_trigger_handler(int irq, void *p) static int ade7758_ring_preenable(struct iio_dev *indio_dev) { struct ade7758_state *st = iio_priv(indio_dev); - struct iio_buffer *ring = indio_dev->buffer; - size_t d_size; unsigned channel; + int ret; if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) return -EINVAL; + ret = iio_sw_buffer_preenable(indio_dev); + if (ret < 0) + return ret; + channel = find_first_bit(indio_dev->active_scan_mask, indio_dev->masklength); - d_size = st->ade7758_ring_channels[channel].scan_type.storagebits / 8; - - if (ring->scan_timestamp) { - d_size += sizeof(s64); - - if (d_size % sizeof(s64)) - d_size += sizeof(s64) - (d_size % sizeof(s64)); - } - - if (indio_dev->buffer->access->set_bytes_per_datum) - indio_dev->buffer->access-> - set_bytes_per_datum(indio_dev->buffer, d_size); - ade7758_write_waveform_type(&indio_dev->dev, st->ade7758_ring_channels[channel].address); diff --git a/trunk/drivers/staging/iio/meter/ade7758_trigger.c b/trunk/drivers/staging/iio/meter/ade7758_trigger.c index b6569c706651..f9c6a340092b 100644 --- a/trunk/drivers/staging/iio/meter/ade7758_trigger.c +++ b/trunk/drivers/staging/iio/meter/ade7758_trigger.c @@ -11,8 +11,8 @@ #include #include -#include "../iio.h" -#include "../trigger.h" +#include +#include #include "ade7758.h" /** @@ -63,7 +63,7 @@ int ade7758_probe_trigger(struct iio_dev *indio_dev) struct ade7758_state *st = iio_priv(indio_dev); int ret; - st->trig = iio_allocate_trigger("%s-dev%d", + st->trig = iio_trigger_alloc("%s-dev%d", spi_get_device_id(st->us)->name, indio_dev->id); if (st->trig == NULL) { @@ -94,7 +94,7 @@ int ade7758_probe_trigger(struct iio_dev *indio_dev) error_free_irq: free_irq(st->us->irq, st->trig); error_free_trig: - iio_free_trigger(st->trig); + iio_trigger_free(st->trig); error_ret: return ret; } @@ -105,5 +105,5 @@ void ade7758_remove_trigger(struct iio_dev *indio_dev) iio_trigger_unregister(st->trig); free_irq(st->us->irq, st->trig); - iio_free_trigger(st->trig); + iio_trigger_free(st->trig); } diff --git a/trunk/drivers/staging/iio/meter/ade7759.c b/trunk/drivers/staging/iio/meter/ade7759.c index 0beab478dcd9..b3f7e0fa9612 100644 --- a/trunk/drivers/staging/iio/meter/ade7759.c +++ b/trunk/drivers/staging/iio/meter/ade7759.c @@ -18,8 +18,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #include "meter.h" #include "ade7759.h" @@ -28,7 +28,7 @@ static int ade7759_spi_write_reg_8(struct device *dev, u8 val) { int ret; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7759_state *st = iio_priv(indio_dev); mutex_lock(&st->buf_lock); @@ -46,7 +46,7 @@ static int ade7759_spi_write_reg_16(struct device *dev, u16 value) { int ret; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7759_state *st = iio_priv(indio_dev); mutex_lock(&st->buf_lock); @@ -63,7 +63,7 @@ static int ade7759_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7759_state *st = iio_priv(indio_dev); int ret; @@ -82,7 +82,7 @@ static int ade7759_spi_read_reg_16(struct device *dev, u8 reg_address, u16 *val) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7759_state *st = iio_priv(indio_dev); int ret; @@ -104,7 +104,7 @@ static int ade7759_spi_read_reg_40(struct device *dev, u64 *val) { struct spi_message msg; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7759_state *st = iio_priv(indio_dev); int ret; struct spi_transfer xfers[] = { @@ -376,7 +376,7 @@ static ssize_t ade7759_write_frequency(struct device *dev, const char *buf, size_t len) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7759_state *st = iio_priv(indio_dev); unsigned long val; int ret; @@ -463,7 +463,7 @@ static int __devinit ade7759_probe(struct spi_device *spi) struct iio_dev *indio_dev; /* setup the industrialio driver allocated elements */ - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -491,7 +491,7 @@ static int __devinit ade7759_probe(struct spi_device *spi) return 0; error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; } @@ -507,7 +507,7 @@ static int ade7759_remove(struct spi_device *spi) if (ret) goto err_ret; - iio_free_device(indio_dev); + iio_device_free(indio_dev); err_ret: return ret; diff --git a/trunk/drivers/staging/iio/meter/ade7854-i2c.c b/trunk/drivers/staging/iio/meter/ade7854-i2c.c index 1e1faa0479d3..06090465fa5f 100644 --- a/trunk/drivers/staging/iio/meter/ade7854-i2c.c +++ b/trunk/drivers/staging/iio/meter/ade7854-i2c.c @@ -12,7 +12,7 @@ #include #include -#include "../iio.h" +#include #include "ade7854.h" static int ade7854_i2c_write_reg_8(struct device *dev, @@ -20,7 +20,7 @@ static int ade7854_i2c_write_reg_8(struct device *dev, u8 value) { int ret; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); mutex_lock(&st->buf_lock); @@ -39,7 +39,7 @@ static int ade7854_i2c_write_reg_16(struct device *dev, u16 value) { int ret; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); mutex_lock(&st->buf_lock); @@ -59,7 +59,7 @@ static int ade7854_i2c_write_reg_24(struct device *dev, u32 value) { int ret; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); mutex_lock(&st->buf_lock); @@ -80,7 +80,7 @@ static int ade7854_i2c_write_reg_32(struct device *dev, u32 value) { int ret; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); mutex_lock(&st->buf_lock); @@ -101,7 +101,7 @@ static int ade7854_i2c_read_reg_8(struct device *dev, u16 reg_address, u8 *val) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); int ret; @@ -127,7 +127,7 @@ static int ade7854_i2c_read_reg_16(struct device *dev, u16 reg_address, u16 *val) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); int ret; @@ -153,7 +153,7 @@ static int ade7854_i2c_read_reg_24(struct device *dev, u16 reg_address, u32 *val) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); int ret; @@ -179,7 +179,7 @@ static int ade7854_i2c_read_reg_32(struct device *dev, u16 reg_address, u32 *val) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); int ret; @@ -208,7 +208,7 @@ static int __devinit ade7854_i2c_probe(struct i2c_client *client, struct ade7854_state *st; struct iio_dev *indio_dev; - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; st = iio_priv(indio_dev); @@ -226,7 +226,7 @@ static int __devinit ade7854_i2c_probe(struct i2c_client *client, ret = ade7854_probe(indio_dev, &client->dev); if (ret) - iio_free_device(indio_dev); + iio_device_free(indio_dev); return ret; } diff --git a/trunk/drivers/staging/iio/meter/ade7854-spi.c b/trunk/drivers/staging/iio/meter/ade7854-spi.c index 81121862c1bd..9fb2f8bfca81 100644 --- a/trunk/drivers/staging/iio/meter/ade7854-spi.c +++ b/trunk/drivers/staging/iio/meter/ade7854-spi.c @@ -12,7 +12,7 @@ #include #include -#include "../iio.h" +#include #include "ade7854.h" static int ade7854_spi_write_reg_8(struct device *dev, @@ -21,7 +21,7 @@ static int ade7854_spi_write_reg_8(struct device *dev, { int ret; struct spi_message msg; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); struct spi_transfer xfer = { .tx_buf = st->tx, @@ -49,7 +49,7 @@ static int ade7854_spi_write_reg_16(struct device *dev, { int ret; struct spi_message msg; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); struct spi_transfer xfer = { .tx_buf = st->tx, @@ -78,7 +78,7 @@ static int ade7854_spi_write_reg_24(struct device *dev, { int ret; struct spi_message msg; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); struct spi_transfer xfer = { .tx_buf = st->tx, @@ -108,7 +108,7 @@ static int ade7854_spi_write_reg_32(struct device *dev, { int ret; struct spi_message msg; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); struct spi_transfer xfer = { .tx_buf = st->tx, @@ -138,7 +138,7 @@ static int ade7854_spi_read_reg_8(struct device *dev, u8 *val) { struct spi_message msg; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); int ret; struct spi_transfer xfers[] = { @@ -180,7 +180,7 @@ static int ade7854_spi_read_reg_16(struct device *dev, u16 *val) { struct spi_message msg; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); int ret; struct spi_transfer xfers[] = { @@ -221,7 +221,7 @@ static int ade7854_spi_read_reg_24(struct device *dev, u32 *val) { struct spi_message msg; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); int ret; struct spi_transfer xfers[] = { @@ -263,7 +263,7 @@ static int ade7854_spi_read_reg_32(struct device *dev, u32 *val) { struct spi_message msg; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); int ret; struct spi_transfer xfers[] = { @@ -306,7 +306,7 @@ static int __devinit ade7854_spi_probe(struct spi_device *spi) struct ade7854_state *st; struct iio_dev *indio_dev; - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; st = iio_priv(indio_dev); @@ -325,7 +325,7 @@ static int __devinit ade7854_spi_probe(struct spi_device *spi) ret = ade7854_probe(indio_dev, &spi->dev); if (ret) - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/meter/ade7854.c b/trunk/drivers/staging/iio/meter/ade7854.c index 49c01c5c1b59..c642da84842a 100644 --- a/trunk/drivers/staging/iio/meter/ade7854.c +++ b/trunk/drivers/staging/iio/meter/ade7854.c @@ -17,8 +17,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #include "meter.h" #include "ade7854.h" @@ -28,7 +28,7 @@ static ssize_t ade7854_read_8bit(struct device *dev, { int ret; u8 val = 0; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); @@ -45,7 +45,7 @@ static ssize_t ade7854_read_16bit(struct device *dev, { int ret; u16 val = 0; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); @@ -62,7 +62,7 @@ static ssize_t ade7854_read_24bit(struct device *dev, { int ret; u32 val; - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); @@ -80,7 +80,7 @@ static ssize_t ade7854_read_32bit(struct device *dev, int ret; u32 val = 0; struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); ret = st->read_reg_32(dev, this_attr->address, &val); @@ -96,7 +96,7 @@ static ssize_t ade7854_write_8bit(struct device *dev, size_t len) { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); int ret; @@ -117,7 +117,7 @@ static ssize_t ade7854_write_16bit(struct device *dev, size_t len) { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); int ret; @@ -138,7 +138,7 @@ static ssize_t ade7854_write_24bit(struct device *dev, size_t len) { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); int ret; @@ -159,7 +159,7 @@ static ssize_t ade7854_write_32bit(struct device *dev, size_t len) { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); int ret; @@ -176,7 +176,7 @@ static ssize_t ade7854_write_32bit(struct device *dev, static int ade7854_reset(struct device *dev) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); u16 val; @@ -425,7 +425,7 @@ static IIO_DEV_ATTR_CVAHR(ade7854_read_32bit, static int ade7854_set_irq(struct device *dev, bool enable) { - struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); int ret; @@ -581,7 +581,7 @@ int ade7854_probe(struct iio_dev *indio_dev, struct device *dev) error_unreg_dev: iio_device_unregister(indio_dev); error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); return ret; } @@ -590,7 +590,7 @@ EXPORT_SYMBOL(ade7854_probe); int ade7854_remove(struct iio_dev *indio_dev) { iio_device_unregister(indio_dev); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/meter/meter.h b/trunk/drivers/staging/iio/meter/meter.h index 6a3db1423631..23e1b5f480a9 100644 --- a/trunk/drivers/staging/iio/meter/meter.h +++ b/trunk/drivers/staging/iio/meter/meter.h @@ -1,4 +1,4 @@ -#include "../sysfs.h" +#include /* metering ic types of attribute */ diff --git a/trunk/drivers/staging/iio/resolver/ad2s1200.c b/trunk/drivers/staging/iio/resolver/ad2s1200.c index d8ce854c1897..8b71eb0e16f5 100644 --- a/trunk/drivers/staging/iio/resolver/ad2s1200.c +++ b/trunk/drivers/staging/iio/resolver/ad2s1200.c @@ -19,8 +19,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #define DRV_NAME "ad2s1200" @@ -85,10 +85,12 @@ static const struct iio_chan_spec ad2s1200_channels[] = { .type = IIO_ANGL, .indexed = 1, .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, }, { .type = IIO_ANGL_VEL, .indexed = 1, .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, } }; @@ -110,7 +112,7 @@ static int __devinit ad2s1200_probe(struct spi_device *spi) DRV_NAME, pins[pn]); goto error_ret; } - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -140,7 +142,7 @@ static int __devinit ad2s1200_probe(struct spi_device *spi) return 0; error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: for (--pn; pn >= 0; pn--) gpio_free(pins[pn]); @@ -150,7 +152,7 @@ static int __devinit ad2s1200_probe(struct spi_device *spi) static int __devexit ad2s1200_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_free_device(spi_get_drvdata(spi)); + iio_device_free(spi_get_drvdata(spi)); return 0; } diff --git a/trunk/drivers/staging/iio/resolver/ad2s1210.c b/trunk/drivers/staging/iio/resolver/ad2s1210.c index c439fcf72be7..f313859476c1 100644 --- a/trunk/drivers/staging/iio/resolver/ad2s1210.c +++ b/trunk/drivers/staging/iio/resolver/ad2s1210.c @@ -18,8 +18,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include #include "ad2s1210.h" #define DRV_NAME "ad2s1210" @@ -200,7 +200,7 @@ static ssize_t ad2s1210_store_softreset(struct device *dev, const char *buf, size_t len) { - struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); + struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); int ret; mutex_lock(&st->lock); @@ -214,7 +214,7 @@ static ssize_t ad2s1210_show_fclkin(struct device *dev, struct device_attribute *attr, char *buf) { - struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); + struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); return sprintf(buf, "%d\n", st->fclkin); } @@ -223,7 +223,7 @@ static ssize_t ad2s1210_store_fclkin(struct device *dev, const char *buf, size_t len) { - struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); + struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); unsigned long fclkin; int ret; @@ -252,7 +252,7 @@ static ssize_t ad2s1210_show_fexcit(struct device *dev, struct device_attribute *attr, char *buf) { - struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); + struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); return sprintf(buf, "%d\n", st->fexcit); } @@ -260,7 +260,7 @@ static ssize_t ad2s1210_store_fexcit(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); + struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); unsigned long fexcit; int ret; @@ -287,7 +287,7 @@ static ssize_t ad2s1210_show_control(struct device *dev, struct device_attribute *attr, char *buf) { - struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); + struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); int ret; mutex_lock(&st->lock); ret = ad2s1210_config_read(st, AD2S1210_REG_CONTROL); @@ -299,7 +299,7 @@ static ssize_t ad2s1210_store_control(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); + struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); unsigned long udata; unsigned char data; int ret; @@ -345,7 +345,7 @@ static ssize_t ad2s1210_store_control(struct device *dev, static ssize_t ad2s1210_show_resolution(struct device *dev, struct device_attribute *attr, char *buf) { - struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); + struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); return sprintf(buf, "%d\n", st->resolution); } @@ -353,7 +353,7 @@ static ssize_t ad2s1210_store_resolution(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); + struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); unsigned char data; unsigned long udata; int ret; @@ -403,7 +403,7 @@ static ssize_t ad2s1210_store_resolution(struct device *dev, static ssize_t ad2s1210_show_fault(struct device *dev, struct device_attribute *attr, char *buf) { - struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); + struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); int ret; mutex_lock(&st->lock); @@ -418,7 +418,7 @@ static ssize_t ad2s1210_clear_fault(struct device *dev, const char *buf, size_t len) { - struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); + struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); int ret; mutex_lock(&st->lock); @@ -441,7 +441,7 @@ static ssize_t ad2s1210_show_reg(struct device *dev, struct device_attribute *attr, char *buf) { - struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); + struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); struct iio_dev_attr *iattr = to_iio_dev_attr(attr); int ret; @@ -455,7 +455,7 @@ static ssize_t ad2s1210_show_reg(struct device *dev, static ssize_t ad2s1210_store_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); + struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); unsigned long data; int ret; struct iio_dev_attr *iattr = to_iio_dev_attr(attr); @@ -580,10 +580,12 @@ static struct iio_chan_spec ad2s1210_channels[] = { .type = IIO_ANGL, .indexed = 1, .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, }, { .type = IIO_ANGL_VEL, .indexed = 1, .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, } }; @@ -688,7 +690,7 @@ static int __devinit ad2s1210_probe(struct spi_device *spi) if (spi->dev.platform_data == NULL) return -EINVAL; - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -729,7 +731,7 @@ static int __devinit ad2s1210_probe(struct spi_device *spi) error_free_gpios: ad2s1210_free_gpios(st); error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; } @@ -740,7 +742,7 @@ static int __devexit ad2s1210_remove(struct spi_device *spi) iio_device_unregister(indio_dev); ad2s1210_free_gpios(iio_priv(indio_dev)); - iio_free_device(indio_dev); + iio_device_free(indio_dev); return 0; } diff --git a/trunk/drivers/staging/iio/resolver/ad2s90.c b/trunk/drivers/staging/iio/resolver/ad2s90.c index 2a86f582ddf1..a8057228dca1 100644 --- a/trunk/drivers/staging/iio/resolver/ad2s90.c +++ b/trunk/drivers/staging/iio/resolver/ad2s90.c @@ -16,8 +16,8 @@ #include #include -#include "../iio.h" -#include "../sysfs.h" +#include +#include struct ad2s90_state { struct mutex lock; @@ -55,6 +55,7 @@ static const struct iio_chan_spec ad2s90_chan = { .type = IIO_ANGL, .indexed = 1, .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, }; static int __devinit ad2s90_probe(struct spi_device *spi) @@ -63,7 +64,7 @@ static int __devinit ad2s90_probe(struct spi_device *spi) struct ad2s90_state *st; int ret = 0; - indio_dev = iio_allocate_device(sizeof(*st)); + indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; goto error_ret; @@ -92,7 +93,7 @@ static int __devinit ad2s90_probe(struct spi_device *spi) return 0; error_free_dev: - iio_free_device(indio_dev); + iio_device_free(indio_dev); error_ret: return ret; } @@ -100,7 +101,7 @@ static int __devinit ad2s90_probe(struct spi_device *spi) static int __devexit ad2s90_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); - iio_free_device(spi_get_drvdata(spi)); + iio_device_free(spi_get_drvdata(spi)); return 0; } diff --git a/trunk/drivers/staging/iio/ring_sw.c b/trunk/drivers/staging/iio/ring_sw.c index b9945ec44faa..9358c6cb1c72 100644 --- a/trunk/drivers/staging/iio/ring_sw.c +++ b/trunk/drivers/staging/iio/ring_sw.c @@ -15,7 +15,7 @@ #include #include #include "ring_sw.h" -#include "trigger.h" +#include /** * struct iio_sw_ring_buffer - software ring buffer diff --git a/trunk/drivers/staging/iio/ring_sw.h b/trunk/drivers/staging/iio/ring_sw.h index 7556e2122367..a5857aa7aefa 100644 --- a/trunk/drivers/staging/iio/ring_sw.h +++ b/trunk/drivers/staging/iio/ring_sw.h @@ -23,7 +23,7 @@ #ifndef _IIO_RING_SW_H_ #define _IIO_RING_SW_H_ -#include "buffer.h" +#include struct iio_buffer *iio_sw_rb_allocate(struct iio_dev *indio_dev); void iio_sw_rb_free(struct iio_buffer *ring); diff --git a/trunk/drivers/staging/iio/trigger/iio-trig-bfin-timer.c b/trunk/drivers/staging/iio/trigger/iio-trig-bfin-timer.c index 665653d79f02..f85734d212bb 100644 --- a/trunk/drivers/staging/iio/trigger/iio-trig-bfin-timer.c +++ b/trunk/drivers/staging/iio/trigger/iio-trig-bfin-timer.c @@ -15,8 +15,8 @@ #include -#include "../iio.h" -#include "../trigger.h" +#include +#include struct bfin_timer { unsigned short id, bit; @@ -172,7 +172,7 @@ static int __devinit iio_bfin_tmr_trigger_probe(struct platform_device *pdev) st->timer_num = ret; st->t = &iio_bfin_timer_code[st->timer_num]; - st->trig = iio_allocate_trigger("bfintmr%d", st->timer_num); + st->trig = iio_trigger_alloc("bfintmr%d", st->timer_num); if (!st->trig) { ret = -ENOMEM; goto out1; @@ -203,7 +203,7 @@ static int __devinit iio_bfin_tmr_trigger_probe(struct platform_device *pdev) out4: iio_trigger_unregister(st->trig); out2: - iio_put_trigger(st->trig); + iio_trigger_put(st->trig); out1: kfree(st); out: @@ -217,7 +217,7 @@ static int __devexit iio_bfin_tmr_trigger_remove(struct platform_device *pdev) disable_gptimers(st->t->bit); free_irq(st->irq, st); iio_trigger_unregister(st->trig); - iio_put_trigger(st->trig); + iio_trigger_put(st->trig); kfree(st); return 0; diff --git a/trunk/drivers/staging/iio/trigger/iio-trig-gpio.c b/trunk/drivers/staging/iio/trigger/iio-trig-gpio.c index a3465947235e..90b26846fc6b 100644 --- a/trunk/drivers/staging/iio/trigger/iio-trig-gpio.c +++ b/trunk/drivers/staging/iio/trigger/iio-trig-gpio.c @@ -22,8 +22,8 @@ #include #include -#include "../iio.h" -#include "../trigger.h" +#include +#include static LIST_HEAD(iio_gpio_trigger_list); static DEFINE_MUTEX(iio_gpio_trigger_list_lock); @@ -72,7 +72,7 @@ static int iio_gpio_trigger_probe(struct platform_device *pdev) for (irq = irq_res->start; irq <= irq_res->end; irq++) { - trig = iio_allocate_trigger("irqtrig%d", irq); + trig = iio_trigger_alloc("irqtrig%d", irq); if (!trig) { ret = -ENOMEM; goto error_free_completed_registrations; @@ -114,7 +114,7 @@ static int iio_gpio_trigger_probe(struct platform_device *pdev) error_free_trig_info: kfree(trig_info); error_put_trigger: - iio_put_trigger(trig); + iio_trigger_put(trig); error_free_completed_registrations: /* The rest should have been added to the iio_gpio_trigger_list */ list_for_each_entry_safe(trig, @@ -144,7 +144,7 @@ static int iio_gpio_trigger_remove(struct platform_device *pdev) iio_trigger_unregister(trig); free_irq(trig_info->irq, trig); kfree(trig_info); - iio_put_trigger(trig); + iio_trigger_put(trig); } mutex_unlock(&iio_gpio_trigger_list_lock); diff --git a/trunk/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c b/trunk/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c index a80cf67bf84d..9f2d055524a3 100644 --- a/trunk/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c +++ b/trunk/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c @@ -16,8 +16,8 @@ #include #include #include -#include "../iio.h" -#include "../trigger.h" +#include +#include static LIST_HEAD(iio_prtc_trigger_list); static DEFINE_MUTEX(iio_prtc_trigger_list_lock); @@ -112,7 +112,7 @@ static int iio_trig_periodic_rtc_probe(struct platform_device *dev) for (i = 0;; i++) { if (pdata[i] == NULL) break; - trig = iio_allocate_trigger("periodic%s", pdata[i]); + trig = iio_trigger_alloc("periodic%s", pdata[i]); if (!trig) { ret = -ENOMEM; goto error_free_completed_registrations; @@ -152,7 +152,7 @@ static int iio_trig_periodic_rtc_probe(struct platform_device *dev) kfree(trig_info); error_put_trigger_and_remove_from_list: list_del(&trig->alloc_list); - iio_put_trigger(trig); + iio_trigger_put(trig); error_free_completed_registrations: list_for_each_entry_safe(trig, trig2, diff --git a/trunk/drivers/staging/iio/trigger/iio-trig-sysfs.c b/trunk/drivers/staging/iio/trigger/iio-trig-sysfs.c index 174dc65709d5..552763bb3d4c 100644 --- a/trunk/drivers/staging/iio/trigger/iio-trig-sysfs.c +++ b/trunk/drivers/staging/iio/trigger/iio-trig-sysfs.c @@ -11,8 +11,8 @@ #include #include -#include "../iio.h" -#include "../trigger.h" +#include +#include struct iio_sysfs_trig { struct iio_trigger *trig; @@ -139,7 +139,7 @@ static int iio_sysfs_trigger_probe(int id) goto out1; } t->id = id; - t->trig = iio_allocate_trigger("sysfstrig%d", id); + t->trig = iio_trigger_alloc("sysfstrig%d", id); if (!t->trig) { ret = -ENOMEM; goto free_t; @@ -158,7 +158,7 @@ static int iio_sysfs_trigger_probe(int id) return 0; out2: - iio_put_trigger(t->trig); + iio_trigger_put(t->trig); free_t: kfree(t); out1: @@ -182,7 +182,7 @@ static int iio_sysfs_trigger_remove(int id) } iio_trigger_unregister(t->trig); - iio_free_trigger(t->trig); + iio_trigger_free(t->trig); list_del(&t->l); kfree(t); diff --git a/trunk/drivers/staging/ipack/Kconfig b/trunk/drivers/staging/ipack/Kconfig new file mode 100644 index 000000000000..af321789dddb --- /dev/null +++ b/trunk/drivers/staging/ipack/Kconfig @@ -0,0 +1,20 @@ +# +# IPACK configuration. +# + +menuconfig IPACK_BUS + tristate "IndustryPack bus support" + ---help--- + If you say Y here you get support for the IndustryPack Framework + for drivers for many types of boards that support this industrial + bus. The IndustryPack Framework is a virtual bus allowing to + communicate between carrier and mezzanine cards connected through + this bus. + +if IPACK_BUS + +source "drivers/staging/ipack/bridges/Kconfig" + +source "drivers/staging/ipack/devices/Kconfig" + +endif # IPACK diff --git a/trunk/drivers/staging/ipack/Makefile b/trunk/drivers/staging/ipack/Makefile new file mode 100644 index 000000000000..85ff223616fd --- /dev/null +++ b/trunk/drivers/staging/ipack/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the IPACK bridge device drivers. +# +obj-$(CONFIG_IPACK_BUS) += ipack.o +obj-y += devices/ +obj-y += bridges/ diff --git a/trunk/drivers/staging/ipack/TODO b/trunk/drivers/staging/ipack/TODO new file mode 100644 index 000000000000..3a45a53afd88 --- /dev/null +++ b/trunk/drivers/staging/ipack/TODO @@ -0,0 +1,46 @@ + TODO + ==== +Introduction +============ + +These drivers add support for IndustryPack devices: carrier and mezzanine +boards. + +The ipack driver is just an abstraction of the bus providing the common +operations between the two kind of boards. + +TODO +==== + +TPCI-200 +-------- + +* It receives the name of the mezzanine plugged in each slot by SYSFS. + No autodetection supported yet, because the mezzanine driver could not be + loaded at the time that the tpci200 driver loads. + +* It has a linked list with the tpci200 devices it is managing. Get rid of it + and use driver_for_each_device() instead. + +IP-OCTAL +-------- + +* It has a linked list which saves the devices it is currently + managing. It should use the driver_for_each_device() function. It is not there + due to the impossibility of using container_of macro to recover the + corresponding "struct ipoctal" because the attribute "struct ipack_device" is + a pointer. This code should be refactored. + +Ipack +----- + +* The structures and API exported can be improved a lot. For example, the + way to unregistering mezzanine devices, doing the mezzanine driver a call to + remove_device() to notify the carrier driver, or the opposite with the call to + the ipack_driver_ops' remove() function could be improved. + + +Contact +======= + +Contact: Samuel Iglesias Gonsalvez \ No newline at end of file diff --git a/trunk/drivers/staging/ipack/bridges/Kconfig b/trunk/drivers/staging/ipack/bridges/Kconfig new file mode 100644 index 000000000000..97c837ea7a03 --- /dev/null +++ b/trunk/drivers/staging/ipack/bridges/Kconfig @@ -0,0 +1,8 @@ +config BOARD_TPCI200 + tristate "TEWS TPCI-200 support for IndustryPack bus" + depends on IPACK_BUS + depends on PCI + help + This driver supports the TEWS TPCI200 device for the IndustryPack bus. + default n + diff --git a/trunk/drivers/staging/ipack/bridges/Makefile b/trunk/drivers/staging/ipack/bridges/Makefile new file mode 100644 index 000000000000..d8b76459300f --- /dev/null +++ b/trunk/drivers/staging/ipack/bridges/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_BOARD_TPCI200) += tpci200.o diff --git a/trunk/drivers/staging/ipack/bridges/tpci200.c b/trunk/drivers/staging/ipack/bridges/tpci200.c new file mode 100644 index 000000000000..ad2870750235 --- /dev/null +++ b/trunk/drivers/staging/ipack/bridges/tpci200.c @@ -0,0 +1,1141 @@ +/** + * tpci200.c + * + * driver for the TEWS TPCI-200 device + * Copyright (c) 2009 Nicolas Serafini, EIC2 SA + * Copyright (c) 2010,2011 Samuel Iglesias Gonsalvez , CERN + * Copyright (c) 2012 Samuel Iglesias Gonsalvez , Igalia + * + * 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 "tpci200.h" + +static struct ipack_bus_ops tpci200_bus_ops; + +/* TPCI200 controls registers */ +static int control_reg[] = { + TPCI200_CONTROL_A_REG, + TPCI200_CONTROL_B_REG, + TPCI200_CONTROL_C_REG, + TPCI200_CONTROL_D_REG +}; + +/* Linked list to save the registered devices */ +static LIST_HEAD(tpci200_list); + +static int tpci200_slot_unregister(struct ipack_device *dev); + +static struct tpci200_board *check_slot(struct ipack_device *dev) +{ + struct tpci200_board *tpci200; + int found = 0; + + if (dev == NULL) { + pr_info("Slot doesn't exist.\n"); + return NULL; + } + + list_for_each_entry(tpci200, &tpci200_list, list) { + if (tpci200->number == dev->bus_nr) { + found = 1; + break; + } + } + + if (!found) { + pr_err("Carrier not found\n"); + return NULL; + } + + if (dev->slot >= TPCI200_NB_SLOT) { + pr_info("Slot [%d:%d] doesn't exist! Last tpci200 slot is %d.\n", + dev->bus_nr, dev->slot, TPCI200_NB_SLOT-1); + return NULL; + } + + BUG_ON(tpci200->slots == NULL); + if (tpci200->slots[dev->slot].dev == NULL) { + pr_info("Slot [%d:%d] is not registered !\n", dev->bus_nr, + dev->slot); + return NULL; + } + + return tpci200; +} + +static inline unsigned char __tpci200_read8(void __iomem *address, + unsigned long offset) +{ + return ioread8(address + (offset^1)); +} + +static inline unsigned short __tpci200_read16(void __iomem *address, + unsigned long offset) +{ + return ioread16(address + offset); +} + +static inline unsigned int __tpci200_read32(void __iomem *address, + unsigned long offset) +{ + return swahw32(ioread32(address + offset)); +} + +static inline void __tpci200_write8(unsigned char value, + void __iomem *address, unsigned long offset) +{ + iowrite8(value, address+(offset^1)); +} + +static inline void __tpci200_write16(unsigned short value, + void __iomem *address, + unsigned long offset) +{ + iowrite16(value, address+offset); +} + +static inline void __tpci200_write32(unsigned int value, + void __iomem *address, + unsigned long offset) +{ + iowrite32(swahw32(value), address+offset); +} + +static struct ipack_addr_space *get_slot_address_space(struct ipack_device *dev, + int space) +{ + struct ipack_addr_space *addr; + + switch (space) { + case IPACK_IO_SPACE: + addr = &dev->io_space; + break; + case IPACK_ID_SPACE: + addr = &dev->id_space; + break; + case IPACK_MEM_SPACE: + addr = &dev->mem_space; + break; + default: + pr_err("Slot [%d:%d] space number %d doesn't exist !\n", + dev->bus_nr, dev->slot, space); + return NULL; + break; + } + + if ((addr->size == 0) || (addr->address == NULL)) { + pr_err("Error, slot space not mapped !\n"); + return NULL; + } + + return addr; +} + +static int tpci200_read8(struct ipack_device *dev, int space, + unsigned long offset, unsigned char *value) +{ + struct ipack_addr_space *addr; + struct tpci200_board *tpci200; + + tpci200 = check_slot(dev); + if (tpci200 == NULL) + return -EINVAL; + + addr = get_slot_address_space(dev, space); + if (addr == NULL) + return -EINVAL; + + if (offset >= addr->size) { + pr_err("Error, slot space offset error !\n"); + return -EFAULT; + } + + *value = __tpci200_read8(addr->address, offset); + + return 0; +} + +static int tpci200_read16(struct ipack_device *dev, int space, + unsigned long offset, unsigned short *value) +{ + struct ipack_addr_space *addr; + struct tpci200_board *tpci200; + + tpci200 = check_slot(dev); + if (tpci200 == NULL) + return -EINVAL; + + addr = get_slot_address_space(dev, space); + if (addr == NULL) + return -EINVAL; + + if ((offset+2) >= addr->size) { + pr_err("Error, slot space offset error !\n"); + return -EFAULT; + } + *value = __tpci200_read16(addr->address, offset); + + return 0; +} + +static int tpci200_read32(struct ipack_device *dev, int space, + unsigned long offset, unsigned int *value) +{ + struct ipack_addr_space *addr; + struct tpci200_board *tpci200; + + tpci200 = check_slot(dev); + if (tpci200 == NULL) + return -EINVAL; + + addr = get_slot_address_space(dev, space); + if (addr == NULL) + return -EINVAL; + + if ((offset+4) >= addr->size) { + pr_err("Error, slot space offset error !\n"); + return -EFAULT; + } + + *value = __tpci200_read32(addr->address, offset); + + return 0; +} + +static int tpci200_write8(struct ipack_device *dev, int space, + unsigned long offset, unsigned char value) +{ + struct ipack_addr_space *addr; + struct tpci200_board *tpci200; + + tpci200 = check_slot(dev); + if (tpci200 == NULL) + return -EINVAL; + + addr = get_slot_address_space(dev, space); + if (addr == NULL) + return -EINVAL; + + if (offset >= addr->size) { + pr_err("Error, slot space offset error !\n"); + return -EFAULT; + } + + __tpci200_write8(value, addr->address, offset); + + return 0; +} + +static int tpci200_write16(struct ipack_device *dev, int space, + unsigned long offset, unsigned short value) +{ + struct ipack_addr_space *addr; + struct tpci200_board *tpci200; + + tpci200 = check_slot(dev); + if (tpci200 == NULL) + return -EINVAL; + + addr = get_slot_address_space(dev, space); + if (addr == NULL) + return -EINVAL; + + if ((offset+2) >= addr->size) { + pr_err("Error, slot space offset error !\n"); + return -EFAULT; + } + + __tpci200_write16(value, addr->address, offset); + + return 0; +} + +static int tpci200_write32(struct ipack_device *dev, int space, + unsigned long offset, unsigned int value) +{ + struct ipack_addr_space *addr; + struct tpci200_board *tpci200; + + tpci200 = check_slot(dev); + if (tpci200 == NULL) + return -EINVAL; + + addr = get_slot_address_space(dev, space); + if (addr == NULL) + return -EINVAL; + + if ((offset+4) >= addr->size) { + pr_err("Error, slot space offset error !\n"); + return -EFAULT; + } + + __tpci200_write32(value, addr->address, offset); + + return 0; +} + +static void tpci200_unregister(struct tpci200_board *tpci200) +{ + int i; + + free_irq(tpci200->info->pdev->irq, (void *) tpci200); + + pci_iounmap(tpci200->info->pdev, tpci200->info->interface_regs); + pci_iounmap(tpci200->info->pdev, tpci200->info->ioidint_space); + pci_iounmap(tpci200->info->pdev, tpci200->info->mem8_space); + + pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR); + pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR); + pci_release_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR); + + pci_disable_device(tpci200->info->pdev); + pci_dev_put(tpci200->info->pdev); + + kfree(tpci200->info); + + for (i = 0; i < TPCI200_NB_SLOT; i++) { + tpci200->slots[i].io_phys.address = NULL; + tpci200->slots[i].io_phys.size = 0; + tpci200->slots[i].id_phys.address = NULL; + tpci200->slots[i].id_phys.size = 0; + tpci200->slots[i].mem_phys.address = NULL; + tpci200->slots[i].mem_phys.size = 0; + } +} + +static irqreturn_t tpci200_interrupt(int irq, void *dev_id) +{ + struct tpci200_board *tpci200 = (struct tpci200_board *) dev_id; + int i; + unsigned long flags; + unsigned short status_reg, reg_value; + unsigned short unhandled_ints = 0; + irqreturn_t ret = IRQ_NONE; + + spin_lock_irqsave(&tpci200->info->access_lock, flags); + + /* Read status register */ + status_reg = readw(tpci200->info->interface_regs + + TPCI200_STATUS_REG); + + if (status_reg & TPCI200_SLOT_INT_MASK) { + unhandled_ints = status_reg & TPCI200_SLOT_INT_MASK; + /* callback to the IRQ handler for the corresponding slot */ + for (i = 0; i < TPCI200_NB_SLOT; i++) { + if ((tpci200->slots[i].irq != NULL) && + (status_reg & ((TPCI200_A_INT0 | TPCI200_A_INT1) << (2*i)))) { + + ret = tpci200->slots[i].irq->handler(tpci200->slots[i].irq->arg); + + /* Dummy reads */ + readw(tpci200->slots[i].dev->io_space.address + + 0xC0); + readw(tpci200->slots[i].dev->io_space.address + + 0xC2); + + unhandled_ints &= ~(((TPCI200_A_INT0 | TPCI200_A_INT1) << (2*i))); + } + } + } + /* Interrupt not handled are disabled */ + if (unhandled_ints) { + for (i = 0; i < TPCI200_NB_SLOT; i++) { + if (unhandled_ints & ((TPCI200_INT0_EN | TPCI200_INT1_EN) << (2*i))) { + pr_info("No registered ISR for slot [%d:%d]!. IRQ will be disabled.\n", + tpci200->number, i); + reg_value = readw( + tpci200->info->interface_regs + + control_reg[i]); + reg_value &= + ~(TPCI200_INT0_EN | TPCI200_INT1_EN); + writew(reg_value, + (tpci200->info->interface_regs + + control_reg[i])); + } + } + } + + spin_unlock_irqrestore(&tpci200->info->access_lock, flags); + return ret; +} + +#ifdef CONFIG_SYSFS + +static struct ipack_device *tpci200_slot_register(unsigned int tpci200_number, + unsigned int slot_position) +{ + int found = 0; + struct ipack_device *dev; + struct tpci200_board *tpci200; + + list_for_each_entry(tpci200, &tpci200_list, list) { + if (tpci200->number == tpci200_number) { + found = 1; + break; + } + } + + if (!found) { + pr_err("carrier board not found for the device\n"); + return NULL; + } + + if (slot_position >= TPCI200_NB_SLOT) { + pr_info("Slot [%d:%d] doesn't exist!\n", tpci200_number, + slot_position); + return NULL; + } + + if (mutex_lock_interruptible(&tpci200->mutex)) + return NULL; + + if (tpci200->slots[slot_position].dev != NULL) { + pr_err("Slot [%d:%d] already installed !\n", tpci200_number, + slot_position); + goto err_unlock; + } + + /* + * Give the same IRQ number as the slot number. + * The TPCI200 has assigned his own two IRQ by PCI bus driver + */ + dev = ipack_device_register(tpci200->info->ipack_bus, + slot_position, slot_position); + if (dev == NULL) { + pr_info("Slot [%d:%d] Unable to register an ipack device\n", + tpci200_number, slot_position); + goto err_unlock; + } + + tpci200->slots[slot_position].dev = dev; + mutex_unlock(&tpci200->mutex); + return dev; + +err_unlock: + mutex_unlock(&tpci200->mutex); + return NULL; +} + +static ssize_t tpci200_store_board(struct device *pdev, const char *buf, + size_t count, int slot) +{ + struct tpci200_board *card = dev_get_drvdata(pdev); + struct ipack_device *dev = card->slots[slot].dev; + + if (dev != NULL) + return -EBUSY; + + dev = tpci200_slot_register(card->number, slot); + if (dev == NULL) + return -ENODEV; + + return count; +} + +static ssize_t tpci200_show_board(struct device *pdev, char *buf, int slot) +{ + struct tpci200_board *card = dev_get_drvdata(pdev); + struct ipack_device *dev = card->slots[slot].dev; + + if (dev != NULL) + return snprintf(buf, PAGE_SIZE, "%s\n", dev_name(&dev->dev)); + else + return snprintf(buf, PAGE_SIZE, "none\n"); +} + +static ssize_t tpci200_show_description(struct device *pdev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, + "TEWS tpci200 carrier PCI for Industry-pack mezzanines.\n"); +} + +static ssize_t tpci200_show_board_slot0(struct device *pdev, + struct device_attribute *attr, + char *buf) +{ + return tpci200_show_board(pdev, buf, 0); +} + +static ssize_t tpci200_store_board_slot0(struct device *pdev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return tpci200_store_board(pdev, buf, count, 0); +} + +static ssize_t tpci200_show_board_slot1(struct device *pdev, + struct device_attribute *attr, + char *buf) +{ + return tpci200_show_board(pdev, buf, 1); +} + +static ssize_t tpci200_store_board_slot1(struct device *pdev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return tpci200_store_board(pdev, buf, count, 1); +} + +static ssize_t tpci200_show_board_slot2(struct device *pdev, + struct device_attribute *attr, + char *buf) +{ + return tpci200_show_board(pdev, buf, 2); +} + +static ssize_t tpci200_store_board_slot2(struct device *pdev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return tpci200_store_board(pdev, buf, count, 2); +} + + +static ssize_t tpci200_show_board_slot3(struct device *pdev, + struct device_attribute *attr, + char *buf) +{ + return tpci200_show_board(pdev, buf, 3); +} + +static ssize_t tpci200_store_board_slot3(struct device *pdev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return tpci200_store_board(pdev, buf, count, 3); +} + +/* Declaration of the device attributes for the TPCI200 */ +static DEVICE_ATTR(description, S_IRUGO, + tpci200_show_description, NULL); +static DEVICE_ATTR(board_slot0, S_IRUGO | S_IWUSR, + tpci200_show_board_slot0, tpci200_store_board_slot0); +static DEVICE_ATTR(board_slot1, S_IRUGO | S_IWUSR, + tpci200_show_board_slot1, tpci200_store_board_slot1); +static DEVICE_ATTR(board_slot2, S_IRUGO | S_IWUSR, + tpci200_show_board_slot2, tpci200_store_board_slot2); +static DEVICE_ATTR(board_slot3, S_IRUGO | S_IWUSR, + tpci200_show_board_slot3, tpci200_store_board_slot3); + +static struct attribute *tpci200_attrs[] = { + &dev_attr_description.attr, + &dev_attr_board_slot0.attr, + &dev_attr_board_slot1.attr, + &dev_attr_board_slot2.attr, + &dev_attr_board_slot3.attr, + NULL, +}; + +static struct attribute_group tpci200_attr_group = { + .attrs = tpci200_attrs, +}; + +static int tpci200_create_sysfs_files(struct tpci200_board *card) +{ + return sysfs_create_group(&card->info->pdev->dev.kobj, + &tpci200_attr_group); +} + +static void tpci200_remove_sysfs_files(struct tpci200_board *card) +{ + sysfs_remove_group(&card->info->pdev->dev.kobj, &tpci200_attr_group); +} + +#else + +static int tpci200_create_sysfs_files(struct tpci200_board *card) +{ + return 0; +} + +static void tpci200_remove_sysfs_files(struct tpci200_board *card) +{ +} + +#endif /* CONFIG_SYSFS */ + +static int tpci200_register(struct tpci200_board *tpci200) +{ + int i; + int res; + unsigned long ioidint_base; + unsigned long mem_base; + unsigned short slot_ctrl; + + if (pci_enable_device(tpci200->info->pdev) < 0) + return -ENODEV; + + if (tpci200_create_sysfs_files(tpci200) < 0) { + pr_err("failed creating sysfs files\n"); + res = -EFAULT; + goto out_disable_pci; + } + + /* Request IP interface register (Bar 2) */ + res = pci_request_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR, + "Carrier IP interface registers"); + if (res) { + pr_err("(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 2 !", + tpci200->info->pdev->bus->number, + tpci200->info->pdev->devfn); + goto out_remove_sysfs; + } + + /* Request IO ID INT space (Bar 3) */ + res = pci_request_region(tpci200->info->pdev, + TPCI200_IO_ID_INT_SPACES_BAR, + "Carrier IO ID INT space"); + if (res) { + pr_err("(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 3 !", + tpci200->info->pdev->bus->number, + tpci200->info->pdev->devfn); + goto out_release_ip_space; + } + + /* Request MEM space (Bar 4) */ + res = pci_request_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR, + "Carrier MEM space"); + if (res) { + pr_err("(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 4!", + tpci200->info->pdev->bus->number, + tpci200->info->pdev->devfn); + goto out_release_ioid_int_space; + } + + /* Map internal tpci200 driver user space */ + tpci200->info->interface_regs = + ioremap(pci_resource_start(tpci200->info->pdev, + TPCI200_IP_INTERFACE_BAR), + TPCI200_IFACE_SIZE); + tpci200->info->ioidint_space = + ioremap(pci_resource_start(tpci200->info->pdev, + TPCI200_IO_ID_INT_SPACES_BAR), + TPCI200_IOIDINT_SIZE); + tpci200->info->mem8_space = + ioremap(pci_resource_start(tpci200->info->pdev, + TPCI200_MEM8_SPACE_BAR), + TPCI200_MEM8_SIZE); + + spin_lock_init(&tpci200->info->access_lock); + ioidint_base = pci_resource_start(tpci200->info->pdev, + TPCI200_IO_ID_INT_SPACES_BAR); + mem_base = pci_resource_start(tpci200->info->pdev, + TPCI200_MEM8_SPACE_BAR); + + /* Set the default parameters of the slot + * INT0 disabled, level sensitive + * INT1 disabled, level sensitive + * error interrupt disabled + * timeout interrupt disabled + * recover time disabled + * clock rate 8 MHz + */ + slot_ctrl = 0; + + /* Set all slot physical address space */ + for (i = 0; i < TPCI200_NB_SLOT; i++) { + tpci200->slots[i].io_phys.address = + (void __iomem *)ioidint_base + + TPCI200_IO_SPACE_OFF + TPCI200_IO_SPACE_GAP*i; + tpci200->slots[i].io_phys.size = TPCI200_IO_SPACE_SIZE; + + tpci200->slots[i].id_phys.address = + (void __iomem *)ioidint_base + + TPCI200_ID_SPACE_OFF + TPCI200_ID_SPACE_GAP*i; + tpci200->slots[i].id_phys.size = TPCI200_ID_SPACE_SIZE; + + tpci200->slots[i].mem_phys.address = + (void __iomem *)mem_base + TPCI200_MEM8_GAP*i; + tpci200->slots[i].mem_phys.size = TPCI200_MEM8_SIZE; + + writew(slot_ctrl, (tpci200->info->interface_regs + + control_reg[i])); + } + + res = request_irq(tpci200->info->pdev->irq, + tpci200_interrupt, IRQF_SHARED, + KBUILD_MODNAME, (void *) tpci200); + if (res) { + pr_err("(bn 0x%X, sn 0x%X) unable to register IRQ !", + tpci200->info->pdev->bus->number, + tpci200->info->pdev->devfn); + tpci200_unregister(tpci200); + goto out_err; + } + + return 0; + +out_release_ioid_int_space: + pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR); +out_release_ip_space: + pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR); +out_remove_sysfs: + tpci200_remove_sysfs_files(tpci200); +out_disable_pci: + pci_disable_device(tpci200->info->pdev); +out_err: + return res; +} + +static int __tpci200_request_irq(struct tpci200_board *tpci200, + struct ipack_device *dev) +{ + unsigned short slot_ctrl; + + /* Set the default parameters of the slot + * INT0 enabled, level sensitive + * INT1 enabled, level sensitive + * error interrupt disabled + * timeout interrupt disabled + * recover time disabled + * clock rate 8 MHz + */ + slot_ctrl = TPCI200_INT0_EN | TPCI200_INT1_EN; + writew(slot_ctrl, (tpci200->info->interface_regs + + control_reg[dev->slot])); + + return 0; +} + +static void __tpci200_free_irq(struct tpci200_board *tpci200, + struct ipack_device *dev) +{ + unsigned short slot_ctrl; + + /* Set the default parameters of the slot + * INT0 disabled, level sensitive + * INT1 disabled, level sensitive + * error interrupt disabled + * timeout interrupt disabled + * recover time disabled + * clock rate 8 MHz + */ + slot_ctrl = 0; + writew(slot_ctrl, (tpci200->info->interface_regs + + control_reg[dev->slot])); +} + +static int tpci200_free_irq(struct ipack_device *dev) +{ + int res; + struct slot_irq *slot_irq; + struct tpci200_board *tpci200; + + tpci200 = check_slot(dev); + if (tpci200 == NULL) { + res = -EINVAL; + goto out; + } + + if (mutex_lock_interruptible(&tpci200->mutex)) { + res = -ERESTARTSYS; + goto out; + } + + if (tpci200->slots[dev->slot].irq == NULL) { + res = -EINVAL; + goto out_unlock; + } + + __tpci200_free_irq(tpci200, dev); + slot_irq = tpci200->slots[dev->slot].irq; + tpci200->slots[dev->slot].irq = NULL; + kfree(slot_irq); + +out_unlock: + mutex_unlock(&tpci200->mutex); +out: + return res; +} + +static int tpci200_slot_unmap_space(struct ipack_device *dev, int space) +{ + int res; + struct ipack_addr_space *virt_addr_space; + struct tpci200_board *tpci200; + + tpci200 = check_slot(dev); + if (tpci200 == NULL) { + res = -EINVAL; + goto out; + } + + if (mutex_lock_interruptible(&tpci200->mutex)) { + res = -ERESTARTSYS; + goto out; + } + + switch (space) { + case IPACK_IO_SPACE: + if (dev->io_space.address == NULL) { + pr_info("Slot [%d:%d] IO space not mapped !\n", + dev->bus_nr, dev->slot); + goto out_unlock; + } + virt_addr_space = &dev->io_space; + break; + case IPACK_ID_SPACE: + if (dev->id_space.address == NULL) { + pr_info("Slot [%d:%d] ID space not mapped !\n", + dev->bus_nr, dev->slot); + goto out_unlock; + } + virt_addr_space = &dev->id_space; + break; + case IPACK_MEM_SPACE: + if (dev->mem_space.address == NULL) { + pr_info("Slot [%d:%d] MEM space not mapped !\n", + dev->bus_nr, dev->slot); + goto out_unlock; + } + virt_addr_space = &dev->mem_space; + break; + default: + pr_err("Slot [%d:%d] space number %d doesn't exist !\n", + dev->bus_nr, dev->slot, space); + res = -EINVAL; + goto out_unlock; + break; + } + + iounmap(virt_addr_space->address); + + virt_addr_space->address = NULL; + virt_addr_space->size = 0; +out_unlock: + mutex_unlock(&tpci200->mutex); +out: + return res; +} + +static int tpci200_slot_unregister(struct ipack_device *dev) +{ + struct tpci200_board *tpci200; + + if (dev == NULL) + return -ENODEV; + + tpci200 = check_slot(dev); + if (tpci200 == NULL) + return -EINVAL; + + tpci200_free_irq(dev); + + if (mutex_lock_interruptible(&tpci200->mutex)) + return -ERESTARTSYS; + + ipack_device_unregister(dev); + tpci200->slots[dev->slot].dev = NULL; + mutex_unlock(&tpci200->mutex); + + return 0; +} + +static int tpci200_slot_map_space(struct ipack_device *dev, + unsigned int memory_size, int space) +{ + int res; + unsigned int size_to_map; + void __iomem *phys_address; + struct ipack_addr_space *virt_addr_space; + struct tpci200_board *tpci200; + + tpci200 = check_slot(dev); + if (tpci200 == NULL) { + res = -EINVAL; + goto out; + } + + if (mutex_lock_interruptible(&tpci200->mutex)) { + res = -ERESTARTSYS; + goto out; + } + + switch (space) { + case IPACK_IO_SPACE: + if (dev->io_space.address != NULL) { + pr_err("Slot [%d:%d] IO space already mapped !\n", + tpci200->number, dev->slot); + res = -EINVAL; + goto out_unlock; + } + virt_addr_space = &dev->io_space; + + phys_address = tpci200->slots[dev->slot].io_phys.address; + size_to_map = tpci200->slots[dev->slot].io_phys.size; + break; + case IPACK_ID_SPACE: + if (dev->id_space.address != NULL) { + pr_err("Slot [%d:%d] ID space already mapped !\n", + tpci200->number, dev->slot); + res = -EINVAL; + goto out_unlock; + } + virt_addr_space = &dev->id_space; + + phys_address = tpci200->slots[dev->slot].id_phys.address; + size_to_map = tpci200->slots[dev->slot].id_phys.size; + break; + case IPACK_MEM_SPACE: + if (dev->mem_space.address != NULL) { + pr_err("Slot [%d:%d] MEM space already mapped !\n", + tpci200->number, dev->slot); + res = -EINVAL; + goto out_unlock; + } + virt_addr_space = &dev->mem_space; + + if (memory_size > tpci200->slots[dev->slot].mem_phys.size) { + pr_err("Slot [%d:%d] request is 0x%X memory, only 0x%X available !\n", + dev->bus_nr, dev->slot, memory_size, + tpci200->slots[dev->slot].mem_phys.size); + res = -EINVAL; + goto out_unlock; + } + + phys_address = tpci200->slots[dev->slot].mem_phys.address; + size_to_map = memory_size; + break; + default: + pr_err("Slot [%d:%d] space %d doesn't exist !\n", + tpci200->number, dev->slot, space); + res = -EINVAL; + goto out_unlock; + break; + } + + virt_addr_space->size = size_to_map; + virt_addr_space->address = + ioremap((unsigned long)phys_address, size_to_map); + +out_unlock: + mutex_unlock(&tpci200->mutex); +out: + return res; +} + +static int tpci200_request_irq(struct ipack_device *dev, int vector, + int (*handler)(void *), void *arg) +{ + int res; + struct slot_irq *slot_irq; + struct tpci200_board *tpci200; + + tpci200 = check_slot(dev); + if (tpci200 == NULL) { + res = -EINVAL; + goto out; + } + + if (mutex_lock_interruptible(&tpci200->mutex)) { + res = -ERESTARTSYS; + goto out; + } + + if (tpci200->slots[dev->slot].irq != NULL) { + pr_err("Slot [%d:%d] IRQ already registered !\n", dev->bus_nr, + dev->slot); + res = -EINVAL; + goto out_unlock; + } + + slot_irq = kzalloc(sizeof(struct slot_irq), GFP_KERNEL); + if (slot_irq == NULL) { + pr_err("Slot [%d:%d] unable to allocate memory for IRQ !\n", + dev->bus_nr, dev->slot); + res = -ENOMEM; + goto out_unlock; + } + + /* + * WARNING: Setup Interrupt Vector in the IndustryPack device + * before an IRQ request. + * Read the User Manual of your IndustryPack device to know + * where to write the vector in memory. + */ + slot_irq->vector = vector; + slot_irq->handler = handler; + slot_irq->arg = arg; + slot_irq->name = dev_name(&dev->dev); + + tpci200->slots[dev->slot].irq = slot_irq; + res = __tpci200_request_irq(tpci200, dev); + +out_unlock: + mutex_unlock(&tpci200->mutex); +out: + return res; +} + +static void tpci200_slot_remove(struct tpci200_slot *slot) +{ + if ((slot->dev == NULL) || + (slot->dev->driver->ops->remove == NULL)) + return; + + slot->dev->driver->ops->remove(slot->dev); +} + +static void tpci200_uninstall(struct tpci200_board *tpci200) +{ + int i; + + for (i = 0; i < TPCI200_NB_SLOT; i++) + tpci200_slot_remove(&tpci200->slots[i]); + + tpci200_unregister(tpci200); + kfree(tpci200->slots); +} + +static struct ipack_bus_ops tpci200_bus_ops = { + .map_space = tpci200_slot_map_space, + .unmap_space = tpci200_slot_unmap_space, + .request_irq = tpci200_request_irq, + .free_irq = tpci200_free_irq, + .read8 = tpci200_read8, + .read16 = tpci200_read16, + .read32 = tpci200_read32, + .write8 = tpci200_write8, + .write16 = tpci200_write16, + .write32 = tpci200_write32, + .remove_device = tpci200_slot_unregister, +}; + +static int tpci200_install(struct tpci200_board *tpci200) +{ + int res; + + tpci200->slots = kzalloc( + TPCI200_NB_SLOT * sizeof(struct tpci200_slot), GFP_KERNEL); + if (tpci200->slots == NULL) { + res = -ENOMEM; + goto out_err; + } + + res = tpci200_register(tpci200); + if (res) + goto out_free; + + mutex_init(&tpci200->mutex); + return 0; + +out_free: + kfree(tpci200->slots); + tpci200->slots = NULL; +out_err: + return res; +} + +static int tpci200_pciprobe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int ret; + struct tpci200_board *tpci200; + + tpci200 = kzalloc(sizeof(struct tpci200_board), GFP_KERNEL); + if (!tpci200) + return -ENOMEM; + + tpci200->info = kzalloc(sizeof(struct tpci200_infos), GFP_KERNEL); + if (!tpci200->info) { + kfree(tpci200); + return -ENOMEM; + } + + /* Save struct pci_dev pointer */ + tpci200->info->pdev = pdev; + tpci200->info->id_table = (struct pci_device_id *)id; + + /* register the device and initialize it */ + ret = tpci200_install(tpci200); + if (ret) { + pr_err("Error during tpci200 install !\n"); + kfree(tpci200->info); + kfree(tpci200); + return -ENODEV; + } + + /* Register the carrier in the industry pack bus driver */ + tpci200->info->ipack_bus = ipack_bus_register(&pdev->dev, + TPCI200_NB_SLOT, + &tpci200_bus_ops); + if (!tpci200->info->ipack_bus) { + pr_err("error registering the carrier on ipack driver\n"); + tpci200_uninstall(tpci200); + kfree(tpci200->info); + kfree(tpci200); + return -EFAULT; + } + + /* save the bus number given by ipack to logging purpose */ + tpci200->number = tpci200->info->ipack_bus->bus_nr; + dev_set_drvdata(&pdev->dev, tpci200); + /* add the registered device in an internal linked list */ + list_add_tail(&tpci200->list, &tpci200_list); + return ret; +} + +static void __tpci200_pci_remove(struct tpci200_board *tpci200) +{ + tpci200_uninstall(tpci200); + tpci200_remove_sysfs_files(tpci200); + list_del(&tpci200->list); + ipack_bus_unregister(tpci200->info->ipack_bus); + kfree(tpci200->info); + kfree(tpci200); +} + +static void __devexit tpci200_pci_remove(struct pci_dev *dev) +{ + struct tpci200_board *tpci200, *next; + + /* Search the registered device to uninstall it */ + list_for_each_entry_safe(tpci200, next, &tpci200_list, list) { + if (tpci200->info->pdev == dev) { + __tpci200_pci_remove(tpci200); + break; + } + } +} + +static struct pci_device_id tpci200_idtable[2] = { + { TPCI200_VENDOR_ID, TPCI200_DEVICE_ID, TPCI200_SUBVENDOR_ID, + TPCI200_SUBDEVICE_ID }, + { 0, }, +}; + +static struct pci_driver tpci200_pci_drv = { + .name = "tpci200", + .id_table = tpci200_idtable, + .probe = tpci200_pciprobe, + .remove = __devexit_p(tpci200_pci_remove), +}; + +static int __init tpci200_drvr_init_module(void) +{ + return pci_register_driver(&tpci200_pci_drv); +} + +static void __exit tpci200_drvr_exit_module(void) +{ + struct tpci200_board *tpci200, *next; + + list_for_each_entry_safe(tpci200, next, &tpci200_list, list) + __tpci200_pci_remove(tpci200); + + pci_unregister_driver(&tpci200_pci_drv); +} + +MODULE_DESCRIPTION("TEWS TPCI-200 device driver"); +MODULE_LICENSE("GPL"); +module_init(tpci200_drvr_init_module); +module_exit(tpci200_drvr_exit_module); diff --git a/trunk/drivers/staging/ipack/bridges/tpci200.h b/trunk/drivers/staging/ipack/bridges/tpci200.h new file mode 100644 index 000000000000..0b547eedddc2 --- /dev/null +++ b/trunk/drivers/staging/ipack/bridges/tpci200.h @@ -0,0 +1,162 @@ +/** + * tpci200.h + * + * driver for the carrier TEWS TPCI-200 + * Copyright (c) 2009 Nicolas Serafini, EIC2 SA + * Copyright (c) 2010,2011 Samuel Iglesias Gonsalvez , CERN + * Copyright (c) 2012 Samuel Iglesias Gonsalvez , Igalia + * + * 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. + */ + +#ifndef _TPCI200_H_ +#define _TPCI200_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "../ipack.h" + +#define TPCI200_NB_SLOT 0x4 +#define TPCI200_NB_BAR 0x6 + +#define TPCI200_VENDOR_ID 0x1498 +#define TPCI200_DEVICE_ID 0x30C8 +#define TPCI200_SUBVENDOR_ID 0x1498 +#define TPCI200_SUBDEVICE_ID 0x300A + +#define TPCI200_IP_INTERFACE_BAR 2 +#define TPCI200_IO_ID_INT_SPACES_BAR 3 +#define TPCI200_MEM16_SPACE_BAR 4 +#define TPCI200_MEM8_SPACE_BAR 5 + +#define TPCI200_REVISION_REG 0x00 +#define TPCI200_CONTROL_A_REG 0x02 +#define TPCI200_CONTROL_B_REG 0x04 +#define TPCI200_CONTROL_C_REG 0x06 +#define TPCI200_CONTROL_D_REG 0x08 +#define TPCI200_RESET_REG 0x0A +#define TPCI200_STATUS_REG 0x0C + +#define TPCI200_IFACE_SIZE 0x100 + +#define TPCI200_IO_SPACE_OFF 0x0000 +#define TPCI200_IO_SPACE_GAP 0x0100 +#define TPCI200_IO_SPACE_SIZE 0x0080 +#define TPCI200_ID_SPACE_OFF 0x0080 +#define TPCI200_ID_SPACE_GAP 0x0100 +#define TPCI200_ID_SPACE_SIZE 0x0040 +#define TPCI200_INT_SPACE_OFF 0x00C0 +#define TPCI200_INT_SPACE_GAP 0x0100 +#define TPCI200_INT_SPACE_SIZE 0x0040 +#define TPCI200_IOIDINT_SIZE 0x0400 + +#define TPCI200_MEM8_GAP 0x00400000 +#define TPCI200_MEM8_SIZE 0x00400000 +#define TPCI200_MEM16_GAP 0x00800000 +#define TPCI200_MEM16_SIZE 0x00800000 + +#define TPCI200_INT0_EN 0x0040 +#define TPCI200_INT1_EN 0x0080 +#define TPCI200_INT0_EDGE 0x0010 +#define TPCI200_INT1_EDGE 0x0020 +#define TPCI200_ERR_INT_EN 0x0008 +#define TPCI200_TIME_INT_EN 0x0004 +#define TPCI200_RECOVER_EN 0x0002 +#define TPCI200_CLK32 0x0001 + +#define TPCI200_A_RESET 0x0001 +#define TPCI200_B_RESET 0x0002 +#define TPCI200_C_RESET 0x0004 +#define TPCI200_D_RESET 0x0008 + +#define TPCI200_A_TIMEOUT 0x1000 +#define TPCI200_B_TIMEOUT 0x2000 +#define TPCI200_C_TIMEOUT 0x4000 +#define TPCI200_D_TIMEOUT 0x8000 + +#define TPCI200_A_ERROR 0x0100 +#define TPCI200_B_ERROR 0x0200 +#define TPCI200_C_ERROR 0x0400 +#define TPCI200_D_ERROR 0x0800 + +#define TPCI200_A_INT0 0x0001 +#define TPCI200_A_INT1 0x0002 +#define TPCI200_B_INT0 0x0004 +#define TPCI200_B_INT1 0x0008 +#define TPCI200_C_INT0 0x0010 +#define TPCI200_C_INT1 0x0020 +#define TPCI200_D_INT0 0x0040 +#define TPCI200_D_INT1 0x0080 + +#define TPCI200_SLOT_INT_MASK 0x00FF + +#define VME_IOID_SPACE "IOID" +#define VME_MEM_SPACE "MEM" + +/** + * struct slot_irq - slot IRQ definition. + * @vector Vector number + * @handler Handler called when IRQ arrives + * @arg Handler argument + * @name IRQ name + * + */ +struct slot_irq { + int vector; + int (*handler)(void *); + void *arg; + const char *name; +}; + +/** + * struct tpci200_slot - data specific to the tpci200 slot. + * @slot_id Slot identification gived to external interface + * @irq Slot IRQ infos + * @io_phys IO physical base address register of the slot + * @id_phys ID physical base address register of the slot + * @mem_phys MEM physical base address register of the slot + * + */ +struct tpci200_slot { + struct ipack_device *dev; + struct slot_irq *irq; + struct ipack_addr_space io_phys; + struct ipack_addr_space id_phys; + struct ipack_addr_space mem_phys; +}; + +/** + * struct tpci200_infos - informations specific of the TPCI200 tpci200. + * @pci_dev PCI device + * @interface_regs Pointer to IP interface space (Bar 2) + * @ioidint_space Pointer to IP ID, IO and INT space (Bar 3) + * @mem8_space Pointer to MEM space (Bar 4) + * @access_lock Mutex lock for simultaneous access + * + */ +struct tpci200_infos { + struct pci_dev *pdev; + struct pci_device_id *id_table; + void __iomem *interface_regs; + void __iomem *ioidint_space; + void __iomem *mem8_space; + spinlock_t access_lock; + struct ipack_bus_device *ipack_bus; +}; +struct tpci200_board { + struct list_head list; + unsigned int number; + struct mutex mutex; + struct tpci200_slot *slots; + struct tpci200_infos *info; +}; + +#endif /* _TPCI200_H_ */ diff --git a/trunk/drivers/staging/ipack/devices/Kconfig b/trunk/drivers/staging/ipack/devices/Kconfig new file mode 100644 index 000000000000..39f71888a584 --- /dev/null +++ b/trunk/drivers/staging/ipack/devices/Kconfig @@ -0,0 +1,7 @@ +config SERIAL_IPOCTAL + tristate "IndustryPack IP-OCTAL uart support" + depends on IPACK_BUS + help + This driver supports the IPOCTAL serial port device for the IndustryPack bus. + default n + diff --git a/trunk/drivers/staging/ipack/devices/Makefile b/trunk/drivers/staging/ipack/devices/Makefile new file mode 100644 index 000000000000..6de18bda4a9a --- /dev/null +++ b/trunk/drivers/staging/ipack/devices/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_SERIAL_IPOCTAL) += ipoctal.o diff --git a/trunk/drivers/staging/ipack/devices/ipoctal.c b/trunk/drivers/staging/ipack/devices/ipoctal.c new file mode 100644 index 000000000000..29f6fa841d23 --- /dev/null +++ b/trunk/drivers/staging/ipack/devices/ipoctal.c @@ -0,0 +1,901 @@ +/** + * ipoctal.c + * + * driver for the GE IP-OCTAL boards + * Copyright (c) 2009 Nicolas Serafini, EIC2 SA + * Copyright (c) 2010,2011 Samuel Iglesias Gonsalvez , CERN + * Copyright (c) 2012 Samuel Iglesias Gonsalvez , Igalia + * + * 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 +#include +#include +#include +#include +#include "../ipack.h" +#include "ipoctal.h" +#include "scc2698.h" + +#define IP_OCTAL_MANUFACTURER_ID 0xF0 +#define IP_OCTAL_232_ID 0x22 +#define IP_OCTAL_422_ID 0x2A +#define IP_OCTAL_485_ID 0x48 + +#define IP_OCTAL_ID_SPACE_VECTOR 0x41 +#define IP_OCTAL_NB_BLOCKS 4 + +static struct ipack_driver driver; +static const struct tty_operations ipoctal_fops; + +struct ipoctal { + struct list_head list; + struct ipack_device *dev; + unsigned int board_id; + struct scc2698_channel *chan_regs; + struct scc2698_block *block_regs; + struct ipoctal_stats chan_stats[NR_CHANNELS]; + char *buffer[NR_CHANNELS]; + unsigned int nb_bytes[NR_CHANNELS]; + unsigned int count_wr[NR_CHANNELS]; + struct ipoctal_config chan_config[NR_CHANNELS]; + wait_queue_head_t queue[NR_CHANNELS]; + unsigned short error_flag[NR_CHANNELS]; + spinlock_t lock[NR_CHANNELS]; + unsigned int pointer_read[NR_CHANNELS]; + unsigned int pointer_write[NR_CHANNELS]; + atomic_t open[NR_CHANNELS]; + unsigned char write; + struct tty_port tty_port[NR_CHANNELS]; + struct tty_driver *tty_drv; +}; + +/* Linked list to save the registered devices */ +static LIST_HEAD(ipoctal_list); + +static inline void ipoctal_write_io_reg(struct ipoctal *ipoctal, + unsigned char *dest, + unsigned char value) +{ + unsigned long offset; + + offset = ((void __iomem *) dest) - ipoctal->dev->io_space.address; + ipoctal->dev->bus->ops->write8(ipoctal->dev, IPACK_IO_SPACE, offset, + value); +} + +static inline void ipoctal_write_cr_cmd(struct ipoctal *ipoctal, + unsigned char *dest, + unsigned char value) +{ + ipoctal_write_io_reg(ipoctal, dest, value); +} + +static inline unsigned char ipoctal_read_io_reg(struct ipoctal *ipoctal, + unsigned char *src) +{ + unsigned long offset; + unsigned char value; + + offset = ((void __iomem *) src) - ipoctal->dev->io_space.address; + ipoctal->dev->bus->ops->read8(ipoctal->dev, IPACK_IO_SPACE, offset, + &value); + return value; +} + +static struct ipoctal *ipoctal_find_board(struct tty_struct *tty) +{ + struct ipoctal *p; + + list_for_each_entry(p, &ipoctal_list, list) { + if (tty->driver->major == p->tty_drv->major) + return p; + } + + return NULL; +} + +static int ipoctal_port_activate(struct tty_port *port, struct tty_struct *tty) +{ + struct ipoctal *ipoctal; + int channel = tty->index; + + ipoctal = ipoctal_find_board(tty); + + if (ipoctal == NULL) { + pr_err("Device not found. Major %d\n", tty->driver->major); + return -ENODEV; + } + + ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, + CR_ENABLE_RX); + tty->driver_data = ipoctal; + + return 0; +} + +static int ipoctal_open(struct tty_struct *tty, struct file *file) +{ + int channel = tty->index; + int res; + struct ipoctal *ipoctal; + + ipoctal = ipoctal_find_board(tty); + + if (ipoctal == NULL) { + pr_err("Device not found. Major %d\n", tty->driver->major); + return -ENODEV; + } + + if (atomic_read(&ipoctal->open[channel])) + return -EBUSY; + + res = tty_port_open(&ipoctal->tty_port[channel], tty, file); + if (res) + return res; + + atomic_inc(&ipoctal->open[channel]); + return 0; +} + +static void ipoctal_reset_stats(struct ipoctal_stats *stats) +{ + stats->tx = 0; + stats->rx = 0; + stats->rcv_break = 0; + stats->framing_err = 0; + stats->overrun_err = 0; + stats->parity_err = 0; +} + +static void ipoctal_free_channel(struct tty_struct *tty) +{ + int channel = tty->index; + struct ipoctal *ipoctal = tty->driver_data; + + if (ipoctal == NULL) + return; + + ipoctal_reset_stats(&ipoctal->chan_stats[channel]); + ipoctal->pointer_read[channel] = 0; + ipoctal->pointer_write[channel] = 0; + ipoctal->nb_bytes[channel] = 0; +} + +static void ipoctal_close(struct tty_struct *tty, struct file *filp) +{ + int channel = tty->index; + struct ipoctal *ipoctal = tty->driver_data; + + tty_port_close(&ipoctal->tty_port[channel], tty, filp); + + if (atomic_dec_and_test(&ipoctal->open[channel])) + ipoctal_free_channel(tty); +} + +static int ipoctal_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount) +{ + struct ipoctal *ipoctal = tty->driver_data; + int channel = tty->index; + + icount->cts = 0; + icount->dsr = 0; + icount->rng = 0; + icount->dcd = 0; + icount->rx = ipoctal->chan_stats[channel].rx; + icount->tx = ipoctal->chan_stats[channel].tx; + icount->frame = ipoctal->chan_stats[channel].framing_err; + icount->parity = ipoctal->chan_stats[channel].parity_err; + icount->brk = ipoctal->chan_stats[channel].rcv_break; + return 0; +} + +static int ipoctal_irq_handler(void *arg) +{ + unsigned int channel; + unsigned int block; + unsigned char isr; + unsigned char sr; + unsigned char isr_tx_rdy, isr_rx_rdy; + unsigned char value; + unsigned char flag; + struct tty_struct *tty; + struct ipoctal *ipoctal = (struct ipoctal *) arg; + + /* Check all channels */ + for (channel = 0; channel < NR_CHANNELS; channel++) { + /* If there is no client, skip the check */ + if (!atomic_read(&ipoctal->open[channel])) + continue; + + tty = tty_port_tty_get(&ipoctal->tty_port[channel]); + if (!tty) + continue; + + /* + * The HW is organized in pair of channels. + * See which register we need to read from + */ + block = channel / 2; + isr = ipoctal_read_io_reg(ipoctal, + &ipoctal->block_regs[block].u.r.isr); + sr = ipoctal_read_io_reg(ipoctal, + &ipoctal->chan_regs[channel].u.r.sr); + + if ((channel % 2) == 1) { + isr_tx_rdy = isr & ISR_TxRDY_B; + isr_rx_rdy = isr & ISR_RxRDY_FFULL_B; + } else { + isr_tx_rdy = isr & ISR_TxRDY_A; + isr_rx_rdy = isr & ISR_RxRDY_FFULL_A; + } + + /* In case of RS-485, change from TX to RX when finishing TX. + * Half-duplex. + */ + if ((ipoctal->board_id == IP_OCTAL_485_ID) && + (sr & SR_TX_EMPTY) && + (ipoctal->nb_bytes[channel] == 0)) { + ipoctal_write_io_reg(ipoctal, + &ipoctal->chan_regs[channel].u.w.cr, + CR_DISABLE_TX); + ipoctal_write_cr_cmd(ipoctal, + &ipoctal->chan_regs[channel].u.w.cr, + CR_CMD_NEGATE_RTSN); + ipoctal_write_io_reg(ipoctal, + &ipoctal->chan_regs[channel].u.w.cr, + CR_ENABLE_RX); + ipoctal->write = 1; + wake_up_interruptible(&ipoctal->queue[channel]); + } + + /* RX data */ + if (isr_rx_rdy && (sr & SR_RX_READY)) { + value = ipoctal_read_io_reg(ipoctal, + &ipoctal->chan_regs[channel].u.r.rhr); + flag = TTY_NORMAL; + + /* Error: count statistics */ + if (sr & SR_ERROR) { + ipoctal_write_cr_cmd(ipoctal, + &ipoctal->chan_regs[channel].u.w.cr, + CR_CMD_RESET_ERR_STATUS); + + if (sr & SR_OVERRUN_ERROR) { + ipoctal->error_flag[channel] |= UART_OVERRUN; + ipoctal->chan_stats[channel].overrun_err++; + /* Overrun doesn't affect the current character*/ + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + } + if (sr & SR_PARITY_ERROR) { + ipoctal->error_flag[channel] |= UART_PARITY; + ipoctal->chan_stats[channel].parity_err++; + flag = TTY_PARITY; + } + if (sr & SR_FRAMING_ERROR) { + ipoctal->error_flag[channel] |= UART_FRAMING; + ipoctal->chan_stats[channel].framing_err++; + flag = TTY_FRAME; + } + if (sr & SR_RECEIVED_BREAK) { + ipoctal->error_flag[channel] |= UART_BREAK; + ipoctal->chan_stats[channel].rcv_break++; + flag = TTY_BREAK; + } + } + + tty_insert_flip_char(tty, value, flag); + } + + /* TX of each character */ + if (isr_tx_rdy && (sr & SR_TX_READY)) { + unsigned int *pointer_write = + &ipoctal->pointer_write[channel]; + + if (ipoctal->nb_bytes[channel] <= 0) { + ipoctal->nb_bytes[channel] = 0; + continue; + } + spin_lock(&ipoctal->lock[channel]); + value = ipoctal->buffer[channel][*pointer_write]; + ipoctal_write_io_reg(ipoctal, + &ipoctal->chan_regs[channel].u.w.thr, + value); + ipoctal->chan_stats[channel].tx++; + ipoctal->count_wr[channel]++; + (*pointer_write)++; + *pointer_write = *pointer_write % PAGE_SIZE; + ipoctal->nb_bytes[channel]--; + spin_unlock(&ipoctal->lock[channel]); + + if ((ipoctal->nb_bytes[channel] == 0) && + (waitqueue_active(&ipoctal->queue[channel]))) { + + if (ipoctal->board_id != IP_OCTAL_485_ID) { + ipoctal->write = 1; + wake_up_interruptible(&ipoctal->queue[channel]); + } + } + } + + tty_flip_buffer_push(tty); + tty_kref_put(tty); + } + return IRQ_HANDLED; +} + +static int ipoctal_check_model(struct ipack_device *dev, unsigned char *id) +{ + unsigned char manufacturerID; + unsigned char board_id; + + dev->bus->ops->read8(dev, IPACK_ID_SPACE, + IPACK_IDPROM_OFFSET_MANUFACTURER_ID, &manufacturerID); + if (manufacturerID != IP_OCTAL_MANUFACTURER_ID) + return -ENODEV; + + dev->bus->ops->read8(dev, IPACK_ID_SPACE, + IPACK_IDPROM_OFFSET_MODEL, (unsigned char *)&board_id); + + switch (board_id) { + case IP_OCTAL_232_ID: + case IP_OCTAL_422_ID: + case IP_OCTAL_485_ID: + *id = board_id; + break; + default: + return -ENODEV; + } + + return 0; +} + +static const struct tty_port_operations ipoctal_tty_port_ops = { + .dtr_rts = NULL, + .activate = ipoctal_port_activate, +}; + +static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr, + unsigned int slot, unsigned int vector) +{ + int res = 0; + int i; + struct tty_driver *tty; + char name[20]; + unsigned char board_id; + + res = ipoctal->dev->bus->ops->map_space(ipoctal->dev, 0, + IPACK_ID_SPACE); + if (res) { + pr_err("Unable to map slot [%d:%d] ID space!\n", bus_nr, slot); + return res; + } + + res = ipoctal_check_model(ipoctal->dev, &board_id); + if (res) { + ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, + IPACK_ID_SPACE); + goto out_unregister_id_space; + } + ipoctal->board_id = board_id; + + res = ipoctal->dev->bus->ops->map_space(ipoctal->dev, 0, + IPACK_IO_SPACE); + if (res) { + pr_err("Unable to map slot [%d:%d] IO space!\n", bus_nr, slot); + goto out_unregister_id_space; + } + + res = ipoctal->dev->bus->ops->map_space(ipoctal->dev, + 0x8000, IPACK_MEM_SPACE); + if (res) { + pr_err("Unable to map slot [%d:%d] MEM space!\n", bus_nr, slot); + goto out_unregister_io_space; + } + + /* Save the virtual address to access the registers easily */ + ipoctal->chan_regs = + (struct scc2698_channel *) ipoctal->dev->io_space.address; + ipoctal->block_regs = + (struct scc2698_block *) ipoctal->dev->io_space.address; + + /* Disable RX and TX before touching anything */ + for (i = 0; i < NR_CHANNELS ; i++) { + ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[i].u.w.cr, + CR_DISABLE_RX | CR_DISABLE_TX); + } + + for (i = 0; i < IP_OCTAL_NB_BLOCKS; i++) { + ipoctal_write_io_reg(ipoctal, + &ipoctal->block_regs[i].u.w.acr, + ACR_BRG_SET2); + ipoctal_write_io_reg(ipoctal, + &ipoctal->block_regs[i].u.w.opcr, + OPCR_MPP_OUTPUT | OPCR_MPOa_RTSN | + OPCR_MPOb_RTSN); + ipoctal_write_io_reg(ipoctal, + &ipoctal->block_regs[i].u.w.imr, + IMR_TxRDY_A | IMR_RxRDY_FFULL_A | + IMR_DELTA_BREAK_A | IMR_TxRDY_B | + IMR_RxRDY_FFULL_B | IMR_DELTA_BREAK_B); + } + + /* + * IP-OCTAL has different addresses to copy its IRQ vector. + * Depending of the carrier these addresses are accesible or not. + * More info in the datasheet. + */ + ipoctal->dev->bus->ops->request_irq(ipoctal->dev, vector, + ipoctal_irq_handler, ipoctal); + ipoctal->dev->bus->ops->write8(ipoctal->dev, IPACK_ID_SPACE, 0, vector); + + /* Register the TTY device */ + + /* Each IP-OCTAL channel is a TTY port */ + tty = alloc_tty_driver(NR_CHANNELS); + + if (!tty) { + res = -ENOMEM; + goto out_unregister_slot_unmap; + } + + /* Fill struct tty_driver with ipoctal data */ + tty->owner = THIS_MODULE; + tty->driver_name = "ipoctal"; + sprintf(name, "ipoctal.%d.%d.", bus_nr, slot); + tty->name = name; + tty->major = 0; + + tty->minor_start = 0; + tty->type = TTY_DRIVER_TYPE_SERIAL; + tty->subtype = SERIAL_TYPE_NORMAL; + tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + tty->init_termios = tty_std_termios; + tty->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + tty->init_termios.c_ispeed = 9600; + tty->init_termios.c_ospeed = 9600; + + tty_set_operations(tty, &ipoctal_fops); + res = tty_register_driver(tty); + if (res) { + pr_err("Can't register tty driver.\n"); + put_tty_driver(tty); + goto out_unregister_slot_unmap; + } + + /* Save struct tty_driver for use it when uninstalling the device */ + ipoctal->tty_drv = tty; + + for (i = 0; i < NR_CHANNELS; i++) { + tty_port_init(&ipoctal->tty_port[i]); + tty_port_alloc_xmit_buf(&ipoctal->tty_port[i]); + ipoctal->tty_port[i].ops = &ipoctal_tty_port_ops; + + ipoctal_reset_stats(&ipoctal->chan_stats[i]); + ipoctal->nb_bytes[i] = 0; + init_waitqueue_head(&ipoctal->queue[i]); + ipoctal->error_flag[i] = UART_NOERROR; + + spin_lock_init(&ipoctal->lock[i]); + ipoctal->pointer_read[i] = 0; + ipoctal->pointer_write[i] = 0; + ipoctal->nb_bytes[i] = 0; + tty_register_device(tty, i, NULL); + + /* + * Enable again the RX. TX will be enabled when + * there is something to send + */ + ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[i].u.w.cr, + CR_ENABLE_RX); + } + + return 0; + +out_unregister_slot_unmap: + ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_ID_SPACE); +out_unregister_io_space: + ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_IO_SPACE); +out_unregister_id_space: + ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_MEM_SPACE); + return res; +} + +static inline int ipoctal_copy_write_buffer(struct ipoctal *ipoctal, + unsigned int channel, + const unsigned char *buf, + int count) +{ + unsigned long flags; + int i; + unsigned int *pointer_read = &ipoctal->pointer_read[channel]; + + /* Copy the bytes from the user buffer to the internal one */ + for (i = 0; i < count; i++) { + if (i <= (PAGE_SIZE - ipoctal->nb_bytes[channel])) { + spin_lock_irqsave(&ipoctal->lock[channel], flags); + ipoctal->tty_port[channel].xmit_buf[*pointer_read] = buf[i]; + *pointer_read = (*pointer_read + 1) % PAGE_SIZE; + ipoctal->nb_bytes[channel]++; + spin_unlock_irqrestore(&ipoctal->lock[channel], flags); + } else { + break; + } + } + return i; +} + +static int ipoctal_write(struct ipoctal *ipoctal, unsigned int channel, + const unsigned char *buf, int count) +{ + ipoctal->nb_bytes[channel] = 0; + ipoctal->count_wr[channel] = 0; + + ipoctal_copy_write_buffer(ipoctal, channel, buf, count); + + ipoctal->error_flag[channel] = UART_NOERROR; + + /* As the IP-OCTAL 485 only supports half duplex, do it manually */ + if (ipoctal->board_id == IP_OCTAL_485_ID) { + ipoctal_write_io_reg(ipoctal, + &ipoctal->chan_regs[channel].u.w.cr, + CR_DISABLE_RX); + ipoctal_write_cr_cmd(ipoctal, + &ipoctal->chan_regs[channel].u.w.cr, + CR_CMD_ASSERT_RTSN); + } + + /* + * Send a packet and then disable TX to avoid failure after several send + * operations + */ + ipoctal_write_io_reg(ipoctal, + &ipoctal->chan_regs[channel].u.w.cr, + CR_ENABLE_TX); + wait_event_interruptible(ipoctal->queue[channel], ipoctal->write); + ipoctal_write_io_reg(ipoctal, + &ipoctal->chan_regs[channel].u.w.cr, + CR_DISABLE_TX); + + ipoctal->write = 0; + return ipoctal->count_wr[channel]; +} + +static int ipoctal_write_tty(struct tty_struct *tty, + const unsigned char *buf, int count) +{ + unsigned int channel = tty->index; + struct ipoctal *ipoctal = tty->driver_data; + + return ipoctal_write(ipoctal, channel, buf, count); +} + +static int ipoctal_write_room(struct tty_struct *tty) +{ + int channel = tty->index; + struct ipoctal *ipoctal = tty->driver_data; + + return PAGE_SIZE - ipoctal->nb_bytes[channel]; +} + +static int ipoctal_chars_in_buffer(struct tty_struct *tty) +{ + int channel = tty->index; + struct ipoctal *ipoctal = tty->driver_data; + + return ipoctal->nb_bytes[channel]; +} + +static void ipoctal_set_termios(struct tty_struct *tty, + struct ktermios *old_termios) +{ + unsigned int cflag; + unsigned char mr1 = 0; + unsigned char mr2 = 0; + unsigned char csr = 0; + unsigned int channel = tty->index; + struct ipoctal *ipoctal = tty->driver_data; + speed_t baud; + + cflag = tty->termios->c_cflag; + + /* Disable and reset everything before change the setup */ + ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, + CR_DISABLE_RX | CR_DISABLE_TX); + ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, + CR_CMD_RESET_RX); + ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, + CR_CMD_RESET_TX); + ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, + CR_CMD_RESET_ERR_STATUS); + ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, + CR_CMD_RESET_MR); + + /* Set Bits per chars */ + switch (cflag & CSIZE) { + case CS6: + mr1 |= MR1_CHRL_6_BITS; + break; + case CS7: + mr1 |= MR1_CHRL_7_BITS; + break; + case CS8: + default: + mr1 |= MR1_CHRL_8_BITS; + /* By default, select CS8 */ + tty->termios->c_cflag = (cflag & ~CSIZE) | CS8; + break; + } + + /* Set Parity */ + if (cflag & PARENB) + if (cflag & PARODD) + mr1 |= MR1_PARITY_ON | MR1_PARITY_ODD; + else + mr1 |= MR1_PARITY_ON | MR1_PARITY_EVEN; + else + mr1 |= MR1_PARITY_OFF; + + /* Mark or space parity is not supported */ + tty->termios->c_cflag &= ~CMSPAR; + + /* Set stop bits */ + if (cflag & CSTOPB) + mr2 |= MR2_STOP_BITS_LENGTH_2; + else + mr2 |= MR2_STOP_BITS_LENGTH_1; + + /* Set the flow control */ + switch (ipoctal->board_id) { + case IP_OCTAL_232_ID: + if (cflag & CRTSCTS) { + mr1 |= MR1_RxRTS_CONTROL_ON; + mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_ON; + ipoctal->chan_config[channel].flow_control = 1; + } else { + mr1 |= MR1_RxRTS_CONTROL_OFF; + mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_OFF; + ipoctal->chan_config[channel].flow_control = 0; + } + break; + case IP_OCTAL_422_ID: + mr1 |= MR1_RxRTS_CONTROL_OFF; + mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_OFF; + ipoctal->chan_config[channel].flow_control = 0; + break; + case IP_OCTAL_485_ID: + mr1 |= MR1_RxRTS_CONTROL_OFF; + mr2 |= MR2_TxRTS_CONTROL_ON | MR2_CTS_ENABLE_TX_OFF; + ipoctal->chan_config[channel].flow_control = 0; + break; + default: + return; + break; + } + + baud = tty_get_baud_rate(tty); + tty_termios_encode_baud_rate(tty->termios, baud, baud); + + /* Set baud rate */ + switch (tty->termios->c_ospeed) { + case 75: + csr |= TX_CLK_75 | RX_CLK_75; + break; + case 110: + csr |= TX_CLK_110 | RX_CLK_110; + break; + case 150: + csr |= TX_CLK_150 | RX_CLK_150; + break; + case 300: + csr |= TX_CLK_300 | RX_CLK_300; + break; + case 600: + csr |= TX_CLK_600 | RX_CLK_600; + break; + case 1200: + csr |= TX_CLK_1200 | RX_CLK_1200; + break; + case 1800: + csr |= TX_CLK_1800 | RX_CLK_1800; + break; + case 2000: + csr |= TX_CLK_2000 | RX_CLK_2000; + break; + case 2400: + csr |= TX_CLK_2400 | RX_CLK_2400; + break; + case 4800: + csr |= TX_CLK_4800 | RX_CLK_4800; + break; + case 9600: + csr |= TX_CLK_9600 | RX_CLK_9600; + break; + case 19200: + csr |= TX_CLK_19200 | RX_CLK_19200; + break; + case 38400: + default: + csr |= TX_CLK_38400 | RX_CLK_38400; + /* In case of default, we establish 38400 bps */ + tty_termios_encode_baud_rate(tty->termios, 38400, 38400); + break; + } + + mr1 |= MR1_ERROR_CHAR; + mr1 |= MR1_RxINT_RxRDY; + + /* Write the control registers */ + ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.mr, mr1); + ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.mr, mr2); + ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.csr, csr); + + /* save the setup in the structure */ + ipoctal->chan_config[channel].baud = tty_get_baud_rate(tty); + ipoctal->chan_config[channel].bits_per_char = cflag & CSIZE; + ipoctal->chan_config[channel].parity = cflag & PARENB; + ipoctal->chan_config[channel].stop_bits = cflag & CSTOPB; + + /* Enable again the RX */ + ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, + CR_ENABLE_RX); +} + +static void ipoctal_hangup(struct tty_struct *tty) +{ + unsigned long flags; + int channel = tty->index; + struct ipoctal *ipoctal = tty->driver_data; + + if (ipoctal == NULL) + return; + + spin_lock_irqsave(&ipoctal->lock[channel], flags); + ipoctal->nb_bytes[channel] = 0; + ipoctal->pointer_read[channel] = 0; + ipoctal->pointer_write[channel] = 0; + spin_unlock_irqrestore(&ipoctal->lock[channel], flags); + + tty_port_hangup(&ipoctal->tty_port[channel]); + + ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, + CR_DISABLE_RX | CR_DISABLE_TX); + ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, + CR_CMD_RESET_RX); + ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, + CR_CMD_RESET_TX); + ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, + CR_CMD_RESET_ERR_STATUS); + ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, + CR_CMD_RESET_MR); + + clear_bit(ASYNCB_INITIALIZED, &ipoctal->tty_port[channel].flags); + wake_up_interruptible(&ipoctal->tty_port[channel].open_wait); +} + +static const struct tty_operations ipoctal_fops = { + .ioctl = NULL, + .open = ipoctal_open, + .close = ipoctal_close, + .write = ipoctal_write_tty, + .set_termios = ipoctal_set_termios, + .write_room = ipoctal_write_room, + .chars_in_buffer = ipoctal_chars_in_buffer, + .get_icount = ipoctal_get_icount, + .hangup = ipoctal_hangup, +}; + +static int ipoctal_match(struct ipack_device *dev) +{ + int res; + unsigned char board_id; + + if ((!dev->bus->ops) || (!dev->bus->ops->map_space) || + (!dev->bus->ops->unmap_space)) + return 0; + + res = dev->bus->ops->map_space(dev, 0, IPACK_ID_SPACE); + if (res) + return 0; + + res = ipoctal_check_model(dev, &board_id); + dev->bus->ops->unmap_space(dev, IPACK_ID_SPACE); + if (!res) + return 1; + + return 0; +} + +static int ipoctal_probe(struct ipack_device *dev) +{ + int res; + struct ipoctal *ipoctal; + + ipoctal = kzalloc(sizeof(struct ipoctal), GFP_KERNEL); + if (ipoctal == NULL) + return -ENOMEM; + + ipoctal->dev = dev; + res = ipoctal_inst_slot(ipoctal, dev->bus_nr, dev->slot, dev->irq); + if (res) + goto out_uninst; + + list_add_tail(&ipoctal->list, &ipoctal_list); + return 0; + +out_uninst: + kfree(ipoctal); + return res; +} + +static void __ipoctal_remove(struct ipoctal *ipoctal) +{ + int i; + + for (i = 0; i < NR_CHANNELS; i++) { + tty_unregister_device(ipoctal->tty_drv, i); + tty_port_free_xmit_buf(&ipoctal->tty_port[i]); + } + + tty_unregister_driver(ipoctal->tty_drv); + put_tty_driver(ipoctal->tty_drv); + + /* Tell the carrier board to free all the resources for this device */ + if (ipoctal->dev->bus->ops->remove_device != NULL) + ipoctal->dev->bus->ops->remove_device(ipoctal->dev); + + list_del(&ipoctal->list); + kfree(ipoctal); +} + +static void ipoctal_remove(struct ipack_device *device) +{ + struct ipoctal *ipoctal, *next; + + list_for_each_entry_safe(ipoctal, next, &ipoctal_list, list) { + if (ipoctal->dev == device) + __ipoctal_remove(ipoctal); + } +} + +static struct ipack_driver_ops ipoctal_drv_ops = { + .match = ipoctal_match, + .probe = ipoctal_probe, + .remove = ipoctal_remove, +}; + +static int __init ipoctal_init(void) +{ + driver.ops = &ipoctal_drv_ops; + return ipack_driver_register(&driver, THIS_MODULE, KBUILD_MODNAME); +} + +static void __exit ipoctal_exit(void) +{ + struct ipoctal *p, *next; + + list_for_each_entry_safe(p, next, &ipoctal_list, list) + __ipoctal_remove(p); + + ipack_driver_unregister(&driver); +} + +MODULE_DESCRIPTION("IP-Octal 232, 422 and 485 device driver"); +MODULE_LICENSE("GPL"); + +module_init(ipoctal_init); +module_exit(ipoctal_exit); diff --git a/trunk/drivers/staging/ipack/devices/ipoctal.h b/trunk/drivers/staging/ipack/devices/ipoctal.h new file mode 100644 index 000000000000..266f3617069d --- /dev/null +++ b/trunk/drivers/staging/ipack/devices/ipoctal.h @@ -0,0 +1,80 @@ +/** + * ipoctal.h + * + * driver for the IPOCTAL boards + * Copyright (c) 2009 Nicolas Serafini, EIC2 SA + * Copyright (c) 2010,2011 Samuel Iglesias Gonsalvez , CERN + * Copyright (c) 2012 Samuel Iglesias Gonsalvez , Igalia + * + * 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. + */ + +#ifndef _IPOCTAL_H +#define _IPOCTAL_H_ + +#define NR_CHANNELS 8 +#define IPOCTAL_MAX_BOARDS 16 +#define MAX_DEVICES (NR_CHANNELS * IPOCTAL_MAX_BOARDS) +#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + +/** + * enum uart_parity_e - UART supported parity. + */ +enum uart_parity_e { + UART_NONE = 0, + UART_ODD = 1, + UART_EVEN = 2, +}; + +/** + * enum uart_error - UART error type + * + */ +enum uart_error { + UART_NOERROR = 0, /* No error during transmission */ + UART_TIMEOUT = 1 << 0, /* Timeout error */ + UART_OVERRUN = 1 << 1, /* Overrun error */ + UART_PARITY = 1 << 2, /* Parity error */ + UART_FRAMING = 1 << 3, /* Framing error */ + UART_BREAK = 1 << 4, /* Received break */ +}; + +/** + * struct ipoctal_config - Serial configuration + * + * @baud: Baud rate + * @stop_bits: Stop bits (1 or 2) + * @bits_per_char: data size in bits + * @parity + * @flow_control: Flow control management (RTS/CTS) (0 disabled, 1 enabled) + */ +struct ipoctal_config { + unsigned int baud; + unsigned int stop_bits; + unsigned int bits_per_char; + unsigned short parity; + unsigned int flow_control; +}; + +/** + * struct ipoctal_stats -- Stats since last reset + * + * @tx: Number of transmitted bytes + * @rx: Number of received bytes + * @overrun: Number of overrun errors + * @parity_err: Number of parity errors + * @framing_err: Number of framing errors + * @rcv_break: Number of break received + */ +struct ipoctal_stats { + unsigned long tx; + unsigned long rx; + unsigned long overrun_err; + unsigned long parity_err; + unsigned long framing_err; + unsigned long rcv_break; +}; + +#endif /* _IPOCTAL_H_ */ diff --git a/trunk/drivers/staging/ipack/devices/scc2698.h b/trunk/drivers/staging/ipack/devices/scc2698.h new file mode 100644 index 000000000000..47f6269985fd --- /dev/null +++ b/trunk/drivers/staging/ipack/devices/scc2698.h @@ -0,0 +1,228 @@ +/* + * scc2698.h + * + * driver for the IPOCTAL boards + * Copyright (c) 2009 Nicolas Serafini, EIC2 SA + * Copyright (c) 2010,2011 Samuel Iglesias Gonsalvez , CERN + * Copyright (c) 2012 Samuel Iglesias Gonsalvez , Igalia + * + * 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. + */ + +#ifndef SCC2698_H_ +#define SCC2698_H_ + +/* + * struct scc2698_channel - Channel access to scc2698 IO + * + * dn value are only spacer. + * + */ +struct scc2698_channel { + union { + struct { + unsigned char d0, mr; /* Mode register 1/2*/ + unsigned char d1, sr; /* Status register */ + unsigned char d2, r1; /* reserved */ + unsigned char d3, rhr; /* Receive holding register (R) */ + unsigned char junk[8]; /* other crap for block control */ + } r; /* Read access */ + struct { + unsigned char d0, mr; /* Mode register 1/2 */ + unsigned char d1, csr; /* Clock select register */ + unsigned char d2, cr; /* Command register */ + unsigned char d3, thr; /* Transmit holding register */ + unsigned char junk[8]; /* other crap for block control */ + } w; /* Write access */ + } u; +}; + +/* + * struct scc2698_block - Block access to scc2698 IO + * + * The scc2698 contain 4 block. + * Each block containt two channel a and b. + * dn value are only spacer. + * + */ +struct scc2698_block { + union { + struct { + unsigned char d0, mra; /* Mode register 1/2 (a) */ + unsigned char d1, sra; /* Status register (a) */ + unsigned char d2, r1; /* reserved */ + unsigned char d3, rhra; /* Receive holding register (a) */ + unsigned char d4, ipcr; /* Input port change register of block */ + unsigned char d5, isr; /* Interrupt status register of block */ + unsigned char d6, ctur; /* Counter timer upper register of block */ + unsigned char d7, ctlr; /* Counter timer lower register of block */ + unsigned char d8, mrb; /* Mode register 1/2 (b) */ + unsigned char d9, srb; /* Status register (b) */ + unsigned char da, r2; /* reserved */ + unsigned char db, rhrb; /* Receive holding register (b) */ + unsigned char dc, r3; /* reserved */ + unsigned char dd, ip; /* Input port register of block */ + unsigned char de, ctg; /* Start counter timer of block */ + unsigned char df, cts; /* Stop counter timer of block */ + } r; /* Read access */ + struct { + unsigned char d0, mra; /* Mode register 1/2 (a) */ + unsigned char d1, csra; /* Clock select register (a) */ + unsigned char d2, cra; /* Command register (a) */ + unsigned char d3, thra; /* Transmit holding register (a) */ + unsigned char d4, acr; /* Auxiliary control register of block */ + unsigned char d5, imr; /* Interrupt mask register of block */ + unsigned char d6, ctu; /* Counter timer upper register of block */ + unsigned char d7, ctl; /* Counter timer lower register of block */ + unsigned char d8, mrb; /* Mode register 1/2 (b) */ + unsigned char d9, csrb; /* Clock select register (a) */ + unsigned char da, crb; /* Command register (b) */ + unsigned char db, thrb; /* Transmit holding register (b) */ + unsigned char dc, r1; /* reserved */ + unsigned char dd, opcr; /* Output port configuration register of block */ + unsigned char de, r2; /* reserved */ + unsigned char df, r3; /* reserved */ + } w; /* Write access */ + } u; +} ; + +#define MR1_CHRL_5_BITS (0x0 << 0) +#define MR1_CHRL_6_BITS (0x1 << 0) +#define MR1_CHRL_7_BITS (0x2 << 0) +#define MR1_CHRL_8_BITS (0x3 << 0) +#define MR1_PARITY_EVEN (0x1 << 2) +#define MR1_PARITY_ODD (0x0 << 2) +#define MR1_PARITY_ON (0x0 << 3) +#define MR1_PARITY_FORCE (0x1 << 3) +#define MR1_PARITY_OFF (0x2 << 3) +#define MR1_PARITY_SPECIAL (0x3 << 3) +#define MR1_ERROR_CHAR (0x0 << 5) +#define MR1_ERROR_BLOCK (0x1 << 5) +#define MR1_RxINT_RxRDY (0x0 << 6) +#define MR1_RxINT_FFULL (0x1 << 6) +#define MR1_RxRTS_CONTROL_ON (0x1 << 7) +#define MR1_RxRTS_CONTROL_OFF (0x0 << 7) + +#define MR2_STOP_BITS_LENGTH_1 (0x7 << 0) +#define MR2_STOP_BITS_LENGTH_2 (0xF << 0) +#define MR2_CTS_ENABLE_TX_ON (0x1 << 4) +#define MR2_CTS_ENABLE_TX_OFF (0x0 << 4) +#define MR2_TxRTS_CONTROL_ON (0x1 << 5) +#define MR2_TxRTS_CONTROL_OFF (0x0 << 5) +#define MR2_CH_MODE_NORMAL (0x0 << 6) +#define MR2_CH_MODE_ECHO (0x1 << 6) +#define MR2_CH_MODE_LOCAL (0x2 << 6) +#define MR2_CH_MODE_REMOTE (0x3 << 6) + +#define CR_ENABLE_RX (0x1 << 0) +#define CR_DISABLE_RX (0x1 << 1) +#define CR_ENABLE_TX (0x1 << 2) +#define CR_DISABLE_TX (0x1 << 3) +#define CR_CMD_RESET_MR (0x1 << 4) +#define CR_CMD_RESET_RX (0x2 << 4) +#define CR_CMD_RESET_TX (0x3 << 4) +#define CR_CMD_RESET_ERR_STATUS (0x4 << 4) +#define CR_CMD_RESET_BREAK_CHANGE (0x5 << 4) +#define CR_CMD_START_BREAK (0x6 << 4) +#define CR_CMD_STOP_BREAK (0x7 << 4) +#define CR_CMD_ASSERT_RTSN (0x8 << 4) +#define CR_CMD_NEGATE_RTSN (0x9 << 4) +#define CR_CMD_SET_TIMEOUT_MODE (0xA << 4) +#define CR_CMD_DISABLE_TIMEOUT_MODE (0xC << 4) + +#define SR_RX_READY (0x1 << 0) +#define SR_FIFO_FULL (0x1 << 1) +#define SR_TX_READY (0x1 << 2) +#define SR_TX_EMPTY (0x1 << 3) +#define SR_OVERRUN_ERROR (0x1 << 4) +#define SR_PARITY_ERROR (0x1 << 5) +#define SR_FRAMING_ERROR (0x1 << 6) +#define SR_RECEIVED_BREAK (0x1 << 7) + +#define SR_ERROR (0xF0) + +#define ACR_DELTA_IP0_IRQ_EN (0x1 << 0) +#define ACR_DELTA_IP1_IRQ_EN (0x1 << 1) +#define ACR_DELTA_IP2_IRQ_EN (0x1 << 2) +#define ACR_DELTA_IP3_IRQ_EN (0x1 << 3) +#define ACR_CT_Mask (0x7 << 4) +#define ACR_CExt (0x0 << 4) +#define ACR_CTxCA (0x1 << 4) +#define ACR_CTxCB (0x2 << 4) +#define ACR_CClk16 (0x3 << 4) +#define ACR_TExt (0x4 << 4) +#define ACR_TExt16 (0x5 << 4) +#define ACR_TClk (0x6 << 4) +#define ACR_TClk16 (0x7 << 4) +#define ACR_BRG_SET1 (0x0 << 7) +#define ACR_BRG_SET2 (0x1 << 7) + +#define TX_CLK_75 (0x0 << 0) +#define TX_CLK_110 (0x1 << 0) +#define TX_CLK_38400 (0x2 << 0) +#define TX_CLK_150 (0x3 << 0) +#define TX_CLK_300 (0x4 << 0) +#define TX_CLK_600 (0x5 << 0) +#define TX_CLK_1200 (0x6 << 0) +#define TX_CLK_2000 (0x7 << 0) +#define TX_CLK_2400 (0x8 << 0) +#define TX_CLK_4800 (0x9 << 0) +#define TX_CLK_1800 (0xA << 0) +#define TX_CLK_9600 (0xB << 0) +#define TX_CLK_19200 (0xC << 0) +#define RX_CLK_75 (0x0 << 4) +#define RX_CLK_110 (0x1 << 4) +#define RX_CLK_38400 (0x2 << 4) +#define RX_CLK_150 (0x3 << 4) +#define RX_CLK_300 (0x4 << 4) +#define RX_CLK_600 (0x5 << 4) +#define RX_CLK_1200 (0x6 << 4) +#define RX_CLK_2000 (0x7 << 4) +#define RX_CLK_2400 (0x8 << 4) +#define RX_CLK_4800 (0x9 << 4) +#define RX_CLK_1800 (0xA << 4) +#define RX_CLK_9600 (0xB << 4) +#define RX_CLK_19200 (0xC << 4) + +#define OPCR_MPOa_RTSN (0x0 << 0) +#define OPCR_MPOa_C_TO (0x1 << 0) +#define OPCR_MPOa_TxC1X (0x2 << 0) +#define OPCR_MPOa_TxC16X (0x3 << 0) +#define OPCR_MPOa_RxC1X (0x4 << 0) +#define OPCR_MPOa_RxC16X (0x5 << 0) +#define OPCR_MPOa_TxRDY (0x6 << 0) +#define OPCR_MPOa_RxRDY_FF (0x7 << 0) + +#define OPCR_MPOb_RTSN (0x0 << 4) +#define OPCR_MPOb_C_TO (0x1 << 4) +#define OPCR_MPOb_TxC1X (0x2 << 4) +#define OPCR_MPOb_TxC16X (0x3 << 4) +#define OPCR_MPOb_RxC1X (0x4 << 4) +#define OPCR_MPOb_RxC16X (0x5 << 4) +#define OPCR_MPOb_TxRDY (0x6 << 4) +#define OPCR_MPOb_RxRDY_FF (0x7 << 4) + +#define OPCR_MPP_INPUT (0x0 << 7) +#define OPCR_MPP_OUTPUT (0x1 << 7) + +#define IMR_TxRDY_A (0x1 << 0) +#define IMR_RxRDY_FFULL_A (0x1 << 1) +#define IMR_DELTA_BREAK_A (0x1 << 2) +#define IMR_COUNTER_READY (0x1 << 3) +#define IMR_TxRDY_B (0x1 << 4) +#define IMR_RxRDY_FFULL_B (0x1 << 5) +#define IMR_DELTA_BREAK_B (0x1 << 6) +#define IMR_INPUT_PORT_CHANGE (0x1 << 7) + +#define ISR_TxRDY_A (0x1 << 0) +#define ISR_RxRDY_FFULL_A (0x1 << 1) +#define ISR_DELTA_BREAK_A (0x1 << 2) +#define ISR_COUNTER_READY (0x1 << 3) +#define ISR_TxRDY_B (0x1 << 4) +#define ISR_RxRDY_FFULL_B (0x1 << 5) +#define ISR_DELTA_BREAK_B (0x1 << 6) +#define ISR_INPUT_PORT_CHANGE (0x1 << 7) + +#endif /* SCC2698_H_ */ diff --git a/trunk/drivers/staging/ipack/ipack.c b/trunk/drivers/staging/ipack/ipack.c new file mode 100644 index 000000000000..2b4fa51bf167 --- /dev/null +++ b/trunk/drivers/staging/ipack/ipack.c @@ -0,0 +1,205 @@ +/* + * Industry-pack bus support functions. + * + * (C) 2011 Samuel Iglesias Gonsalvez , CERN + * (C) 2012 Samuel Iglesias Gonsalvez , Igalia + * + * 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 "ipack.h" + +#define to_ipack_dev(device) container_of(device, struct ipack_device, dev) +#define to_ipack_driver(drv) container_of(drv, struct ipack_driver, driver) + +/* used when allocating bus numbers */ +#define IPACK_MAXBUS 64 + +static DEFINE_MUTEX(ipack_mutex); + +struct ipack_busmap { + unsigned long busmap[IPACK_MAXBUS / (8*sizeof(unsigned long))]; +}; +static struct ipack_busmap busmap; + +static void ipack_device_release(struct device *dev) +{ + struct ipack_device *device = to_ipack_dev(dev); + kfree(device); +} + +static int ipack_bus_match(struct device *device, struct device_driver *driver) +{ + int ret; + struct ipack_device *dev = to_ipack_dev(device); + struct ipack_driver *drv = to_ipack_driver(driver); + + if ((!drv->ops) || (!drv->ops->match)) + return -EINVAL; + + ret = drv->ops->match(dev); + if (ret) + dev->driver = drv; + + return 0; +} + +static int ipack_bus_probe(struct device *device) +{ + struct ipack_device *dev = to_ipack_dev(device); + + if (!dev->driver->ops->probe) + return -EINVAL; + + return dev->driver->ops->probe(dev); +} + +static int ipack_bus_remove(struct device *device) +{ + struct ipack_device *dev = to_ipack_dev(device); + + if (!dev->driver->ops->remove) + return -EINVAL; + + dev->driver->ops->remove(dev); + return 0; +} + +static struct bus_type ipack_bus_type = { + .name = "ipack", + .probe = ipack_bus_probe, + .match = ipack_bus_match, + .remove = ipack_bus_remove, +}; + +static int ipack_assign_bus_number(void) +{ + int busnum; + + mutex_lock(&ipack_mutex); + busnum = find_next_zero_bit(busmap.busmap, IPACK_MAXBUS, 1); + + if (busnum >= IPACK_MAXBUS) { + pr_err("too many buses\n"); + busnum = -1; + goto error_find_busnum; + } + + set_bit(busnum, busmap.busmap); + +error_find_busnum: + mutex_unlock(&ipack_mutex); + return busnum; +} + +struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots, + struct ipack_bus_ops *ops) +{ + int bus_nr; + struct ipack_bus_device *bus; + + bus = kzalloc(sizeof(struct ipack_bus_device), GFP_KERNEL); + if (!bus) + return NULL; + + bus_nr = ipack_assign_bus_number(); + if (bus_nr < 0) { + kfree(bus); + return NULL; + } + + bus->bus_nr = bus_nr; + bus->parent = parent; + bus->slots = slots; + bus->ops = ops; + return bus; +} +EXPORT_SYMBOL_GPL(ipack_bus_register); + +int ipack_bus_unregister(struct ipack_bus_device *bus) +{ + mutex_lock(&ipack_mutex); + clear_bit(bus->bus_nr, busmap.busmap); + mutex_unlock(&ipack_mutex); + kfree(bus); + return 0; +} +EXPORT_SYMBOL_GPL(ipack_bus_unregister); + +int ipack_driver_register(struct ipack_driver *edrv, struct module *owner, + char *name) +{ + edrv->driver.owner = owner; + edrv->driver.name = name; + edrv->driver.bus = &ipack_bus_type; + return driver_register(&edrv->driver); +} +EXPORT_SYMBOL_GPL(ipack_driver_register); + +void ipack_driver_unregister(struct ipack_driver *edrv) +{ + driver_unregister(&edrv->driver); +} +EXPORT_SYMBOL_GPL(ipack_driver_unregister); + +struct ipack_device *ipack_device_register(struct ipack_bus_device *bus, + int slot, int irqv) +{ + int ret; + struct ipack_device *dev; + + dev = kzalloc(sizeof(struct ipack_device), GFP_KERNEL); + if (!dev) + return NULL; + + dev->dev.bus = &ipack_bus_type; + dev->dev.release = ipack_device_release; + dev->dev.parent = bus->parent; + dev->slot = slot; + dev->bus_nr = bus->bus_nr; + dev->irq = irqv; + dev->bus = bus; + dev_set_name(&dev->dev, + "ipack-dev.%u.%u", dev->bus_nr, dev->slot); + + ret = device_register(&dev->dev); + if (ret < 0) { + pr_err("error registering the device.\n"); + dev->driver->ops->remove(dev); + kfree(dev); + return NULL; + } + + return dev; +} +EXPORT_SYMBOL_GPL(ipack_device_register); + +void ipack_device_unregister(struct ipack_device *dev) +{ + device_unregister(&dev->dev); +} +EXPORT_SYMBOL_GPL(ipack_device_unregister); + +static int __init ipack_init(void) +{ + return bus_register(&ipack_bus_type); +} + +static void __exit ipack_exit(void) +{ + bus_unregister(&ipack_bus_type); +} + +module_init(ipack_init); +module_exit(ipack_exit); + +MODULE_AUTHOR("Samuel Iglesias Gonsalvez "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Industry-pack bus core"); diff --git a/trunk/drivers/staging/ipack/ipack.h b/trunk/drivers/staging/ipack/ipack.h new file mode 100644 index 000000000000..8bc001e3ca4e --- /dev/null +++ b/trunk/drivers/staging/ipack/ipack.h @@ -0,0 +1,183 @@ +/* + * Industry-pack bus. + * + * (C) 2011 Samuel Iglesias Gonsalvez , CERN + * (C) 2012 Samuel Iglesias Gonsalvez , Igalia + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; version 2 of the License. + */ + +#include + +#define IPACK_IDPROM_OFFSET_I 0x01 +#define IPACK_IDPROM_OFFSET_P 0x03 +#define IPACK_IDPROM_OFFSET_A 0x05 +#define IPACK_IDPROM_OFFSET_C 0x07 +#define IPACK_IDPROM_OFFSET_MANUFACTURER_ID 0x09 +#define IPACK_IDPROM_OFFSET_MODEL 0x0B +#define IPACK_IDPROM_OFFSET_REVISION 0x0D +#define IPACK_IDPROM_OFFSET_RESERVED 0x0F +#define IPACK_IDPROM_OFFSET_DRIVER_ID_L 0x11 +#define IPACK_IDPROM_OFFSET_DRIVER_ID_H 0x13 +#define IPACK_IDPROM_OFFSET_NUM_BYTES 0x15 +#define IPACK_IDPROM_OFFSET_CRC 0x17 + +struct ipack_bus_ops; +struct ipack_driver; + +enum ipack_space { + IPACK_IO_SPACE = 0, + IPACK_ID_SPACE = 1, + IPACK_MEM_SPACE = 2, +}; + +/** + * struct ipack_addr_space - Virtual address space mapped for a specified type. + * + * @address: virtual address + * @size: size of the mapped space + */ +struct ipack_addr_space { + void __iomem *address; + unsigned int size; +}; + +/** + * struct ipack_device + * + * @bus_nr: IP bus number where the device is plugged + * @slot: Slot where the device is plugged in the carrier board + * @irq: IRQ vector + * @driver: Pointer to the ipack_driver that manages the device + * @bus: ipack_bus_device where the device is plugged to. + * @id_space: Virtual address to ID space. + * @io_space: Virtual address to IO space. + * @mem_space: Virtual address to MEM space. + * @dev: device in kernel representation. + * + * Warning: Direct access to mapped memory is possible but the endianness + * is not the same with PCI carrier or VME carrier. The endianness is managed + * by the carrier board throught bus->ops. + */ +struct ipack_device { + unsigned int bus_nr; + unsigned int slot; + unsigned int irq; + struct ipack_driver *driver; + struct ipack_bus_device *bus; + struct ipack_addr_space id_space; + struct ipack_addr_space io_space; + struct ipack_addr_space mem_space; + struct device dev; +}; + +/** + * struct ipack_driver_ops -- callbacks to mezzanine driver for installing/removing one device + * + * @match: Match function + * @probe: Probe function + * @remove: tell the driver that the carrier board wants to remove one device + */ + +struct ipack_driver_ops { + int (*match) (struct ipack_device *dev); + int (*probe) (struct ipack_device *dev); + void (*remove) (struct ipack_device *dev); +}; + +/** + * struct ipack_driver -- Specific data to each ipack board driver + * + * @driver: Device driver kernel representation + * @ops: Mezzanine driver operations specific for the ipack bus. + */ +struct ipack_driver { + struct device_driver driver; + struct ipack_driver_ops *ops; +}; + +/** + * struct ipack_bus_ops - available operations on a bridge module + * + * @map_space: map IP address space + * @unmap_space: unmap IP address space + * @request_irq: request IRQ + * @free_irq: free IRQ + * @read8: read unsigned char + * @read16: read unsigned short + * @read32: read unsigned int + * @write8: read unsigned char + * @write16: read unsigned short + * @write32: read unsigned int + * @remove_device: tell the bridge module that the device has been removed + */ +struct ipack_bus_ops { + int (*map_space) (struct ipack_device *dev, unsigned int memory_size, int space); + int (*unmap_space) (struct ipack_device *dev, int space); + int (*request_irq) (struct ipack_device *dev, int vector, int (*handler)(void *), void *arg); + int (*free_irq) (struct ipack_device *dev); + int (*read8) (struct ipack_device *dev, int space, unsigned long offset, unsigned char *value); + int (*read16) (struct ipack_device *dev, int space, unsigned long offset, unsigned short *value); + int (*read32) (struct ipack_device *dev, int space, unsigned long offset, unsigned int *value); + int (*write8) (struct ipack_device *dev, int space, unsigned long offset, unsigned char value); + int (*write16) (struct ipack_device *dev, int space, unsigned long offset, unsigned short value); + int (*write32) (struct ipack_device *dev, int space, unsigned long offset, unsigned int value); + int (*remove_device) (struct ipack_device *dev); +}; + +/** + * struct ipack_bus_device + * + * @dev: pointer to carrier device + * @slots: number of slots available + * @bus_nr: ipack bus number + * @ops: bus operations for the mezzanine drivers + */ +struct ipack_bus_device { + struct device *parent; + int slots; + int bus_nr; + struct ipack_bus_ops *ops; +}; + +/** + * ipack_bus_register -- register a new ipack bus + * + * @parent: pointer to the parent device, if any. + * @slots: number of slots available in the bus device. + * @ops: bus operations for the mezzanine drivers. + * + * The carrier board device should call this function to register itself as + * available bus device in ipack. + */ +struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots, + struct ipack_bus_ops *ops); + +/** + * ipack_bus_unregister -- unregister an ipack bus + */ +int ipack_bus_unregister(struct ipack_bus_device *bus); + +/** + * ipack_driver_register -- Register a new driver + * + * Called by a ipack driver to register itself as a driver + * that can manage ipack devices. + */ +int ipack_driver_register(struct ipack_driver *edrv, struct module *owner, char *name); +void ipack_driver_unregister(struct ipack_driver *edrv); + +/** + * ipack_device_register -- register a new mezzanine device + * + * @bus: ipack bus device it is plugged to. + * @slot: slot position in the bus device. + * @irqv: IRQ vector for the mezzanine. + * + * Register a new ipack device (mezzanine device). The call is done by + * the carrier device driver. + */ +struct ipack_device *ipack_device_register(struct ipack_bus_device *bus, int slot, int irqv); +void ipack_device_unregister(struct ipack_device *dev); diff --git a/trunk/drivers/staging/line6/config.h b/trunk/drivers/staging/line6/config.h deleted file mode 100644 index f8a5149e3dad..000000000000 --- a/trunk/drivers/staging/line6/config.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Line6 Linux USB driver - 0.8.0 - * - * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at) - * - * 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. - * - */ - -#ifndef CONFIG_H -#define CONFIG_H - - -#ifdef CONFIG_USB_DEBUG -#define DEBUG 1 -#endif - - -/* - * Development tools. - */ -#define DO_DEBUG_MESSAGES 0 -#define DO_DUMP_URB_SEND DO_DEBUG_MESSAGES -#define DO_DUMP_URB_RECEIVE DO_DEBUG_MESSAGES -#define DO_DUMP_PCM_SEND 0 -#define DO_DUMP_PCM_RECEIVE 0 -#define DO_DUMP_MIDI_SEND DO_DEBUG_MESSAGES -#define DO_DUMP_MIDI_RECEIVE DO_DEBUG_MESSAGES -#define DO_DUMP_ANY (DO_DUMP_URB_SEND || DO_DUMP_URB_RECEIVE || \ - DO_DUMP_PCM_SEND || DO_DUMP_PCM_RECEIVE || \ - DO_DUMP_MIDI_SEND || DO_DUMP_MIDI_RECEIVE) -#define CREATE_RAW_FILE 0 - -#if DO_DEBUG_MESSAGES -#define CHECKPOINT printk(KERN_INFO "line6usb: %s (%s:%d)\n", \ - __func__, __FILE__, __LINE__) -#endif - -#if DO_DEBUG_MESSAGES -#define DEBUG_MESSAGES(x) (x) -#else -#define DEBUG_MESSAGES(x) -#endif - - -#endif diff --git a/trunk/drivers/staging/line6/driver.c b/trunk/drivers/staging/line6/driver.c index e8023afd3656..4513f78f1127 100644 --- a/trunk/drivers/staging/line6/driver.c +++ b/trunk/drivers/staging/line6/driver.c @@ -92,15 +92,10 @@ const unsigned char line6_midi_id[] = { Code to request version of POD, Variax interface (and maybe other devices). */ -static const char line6_request_version0[] = { +static const char line6_request_version[] = { 0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7 }; -/* - Copy of version request code with GFP_KERNEL flag for use in URB. -*/ -static const char *line6_request_version; - struct usb_line6 *line6_devices[LINE6_MAX_DEVICES]; /** @@ -336,8 +331,21 @@ int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer, */ int line6_version_request_async(struct usb_line6 *line6) { - return line6_send_raw_message_async(line6, line6_request_version, - sizeof(line6_request_version0)); + char *buffer; + int retval; + + buffer = kmalloc(sizeof(line6_request_version), GFP_ATOMIC); + if (buffer == NULL) { + dev_err(line6->ifcdev, "Out of memory"); + return -ENOMEM; + } + + memcpy(buffer, line6_request_version, sizeof(line6_request_version)); + + retval = line6_send_raw_message_async(line6, buffer, + sizeof(line6_request_version)); + kfree(buffer); + return retval; } /* @@ -1292,69 +1300,7 @@ static struct usb_driver line6_driver = { .id_table = line6_id_table, }; -/* - Module initialization. -*/ -static int __init line6_init(void) -{ - int i, retval; - - printk(KERN_INFO "%s driver version %s\n", DRIVER_NAME, DRIVER_VERSION); - - for (i = LINE6_MAX_DEVICES; i--;) - line6_devices[i] = NULL; - - retval = usb_register(&line6_driver); - - if (retval) { - err("usb_register failed. Error number %d", retval); - return retval; - } - - line6_request_version = kmalloc(sizeof(line6_request_version0), - GFP_KERNEL); - - if (line6_request_version == NULL) { - err("Out of memory"); - return -ENOMEM; - } - - memcpy((char *)line6_request_version, line6_request_version0, - sizeof(line6_request_version0)); - - return retval; -} - -/* - Module cleanup. -*/ -static void __exit line6_exit(void) -{ - int i; - struct usb_line6 *line6; - struct snd_line6_pcm *line6pcm; - - /* stop all PCM channels */ - for (i = LINE6_MAX_DEVICES; i--;) { - line6 = line6_devices[i]; - - if (line6 == NULL) - continue; - - line6pcm = line6->line6pcm; - - if (line6pcm == NULL) - continue; - - line6_pcm_release(line6pcm, ~0); - } - - usb_deregister(&line6_driver); - kfree(line6_request_version); -} - -module_init(line6_init); -module_exit(line6_exit); +module_usb_driver(line6_driver); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/trunk/drivers/staging/line6/midi.c b/trunk/drivers/staging/line6/midi.c index 13d02939c3cb..50407294fbd4 100644 --- a/trunk/drivers/staging/line6/midi.c +++ b/trunk/drivers/staging/line6/midi.c @@ -406,7 +406,7 @@ int line6_init_midi(struct usb_line6 *line6) line6midi->line6 = line6; - switch(line6->product) { + switch (line6->product) { case LINE6_DEVID_PODHD300: case LINE6_DEVID_PODHD500: line6midi->midi_mask_transmit = 1; diff --git a/trunk/drivers/staging/line6/midibuf.c b/trunk/drivers/staging/line6/midibuf.c index 7b532e5ce8b4..836e8c847c52 100644 --- a/trunk/drivers/staging/line6/midibuf.c +++ b/trunk/drivers/staging/line6/midibuf.c @@ -64,7 +64,7 @@ int line6_midibuf_init(struct MidiBuffer *this, int size, int split) void line6_midibuf_status(struct MidiBuffer *this) { - printk(KERN_DEBUG "midibuf size=%d split=%d pos_read=%d pos_write=%d " + pr_debug("midibuf size=%d split=%d pos_read=%d pos_write=%d " "full=%d command_prev=%02x\n", this->size, this->split, this->pos_read, this->pos_write, this->full, this->command_prev); } diff --git a/trunk/drivers/staging/line6/pcm.c b/trunk/drivers/staging/line6/pcm.c index 90d2d4475cb4..5e319e3ce685 100644 --- a/trunk/drivers/staging/line6/pcm.c +++ b/trunk/drivers/staging/line6/pcm.c @@ -99,7 +99,7 @@ int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels) unsigned long flags_new = flags_old | channels; unsigned long flags_final = flags_old; int err = 0; - + line6pcm->prev_fbuf = NULL; if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) { diff --git a/trunk/drivers/staging/line6/toneport.c b/trunk/drivers/staging/line6/toneport.c index b754f69a29c4..31b624b63425 100644 --- a/trunk/drivers/staging/line6/toneport.c +++ b/trunk/drivers/staging/line6/toneport.c @@ -168,7 +168,7 @@ static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2) cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ); if (ret < 0) { - err("send failed (error %d)\n", ret); + dev_err(&usbdev->dev, "send failed (error %d)\n", ret); return ret; } diff --git a/trunk/drivers/staging/media/as102/as102_drv.c b/trunk/drivers/staging/media/as102/as102_drv.c index ea4f992de235..ac92eaf6c74b 100644 --- a/trunk/drivers/staging/media/as102/as102_drv.c +++ b/trunk/drivers/staging/media/as102/as102_drv.c @@ -279,40 +279,8 @@ void as102_dvb_unregister(struct as102_dev_t *as102_dev) pr_info("Unregistered device %s", as102_dev->name); } -static int __init as102_driver_init(void) -{ - int ret; - - /* register this driver with the low level subsystem */ - ret = usb_register(&as102_usb_driver); - if (ret) - err("usb_register failed (ret = %d)", ret); - - return ret; -} - -/* - * Mandatory function : Adds a special section to the module indicating - * where initialisation function is defined - */ -module_init(as102_driver_init); - -/** - * as102_driver_exit - as102 driver exit point - * - * This function is called when device has to be removed. - */ -static void __exit as102_driver_exit(void) -{ - /* deregister this driver with the low level bus subsystem */ - usb_deregister(&as102_usb_driver); -} +module_usb_driver(as102_usb_driver); -/* - * required function for unload: Adds a special section to the module - * indicating where unload function is defined - */ -module_exit(as102_driver_exit); /* modinfo details */ MODULE_DESCRIPTION(DRIVER_FULL_NAME); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/media/as102/as102_fe.c b/trunk/drivers/staging/media/as102/as102_fe.c index 5917657b9d0f..9ce8c9daa2e7 100644 --- a/trunk/drivers/staging/media/as102/as102_fe.c +++ b/trunk/drivers/staging/media/as102/as102_fe.c @@ -17,8 +17,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include - #include "as102_drv.h" #include "as10x_types.h" #include "as10x_cmd.h" diff --git a/trunk/drivers/staging/media/as102/as102_fw.c b/trunk/drivers/staging/media/as102/as102_fw.c index 1075fb1df0d9..b9670ee41b4e 100644 --- a/trunk/drivers/staging/media/as102/as102_fw.c +++ b/trunk/drivers/staging/media/as102/as102_fw.c @@ -230,11 +230,8 @@ int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap) pr_info("%s: firmware: %s loaded with success\n", DRIVER_NAME, fw2); error: - /* free data buffer */ kfree(cmd_buf); - /* release firmware if needed */ - if (firmware != NULL) - release_firmware(firmware); + release_firmware(firmware); LEAVE(); return errno; diff --git a/trunk/drivers/staging/media/as102/as102_usb_drv.c b/trunk/drivers/staging/media/as102/as102_usb_drv.c index 0f6bfe7eccba..aaf1bc2ad1b2 100644 --- a/trunk/drivers/staging/media/as102/as102_usb_drv.c +++ b/trunk/drivers/staging/media/as102/as102_usb_drv.c @@ -367,7 +367,7 @@ static int as102_usb_probe(struct usb_interface *intf, ENTER(); /* This should never actually happen */ - if ((sizeof(as102_usb_id_table) / sizeof(struct usb_device_id)) != + if (ARRAY_SIZE(as102_usb_id_table) != (sizeof(as102_device_names) / sizeof(const char *))) { pr_err("Device names table invalid size"); return -EINVAL; @@ -375,13 +375,12 @@ static int as102_usb_probe(struct usb_interface *intf, as102_dev = kzalloc(sizeof(struct as102_dev_t), GFP_KERNEL); if (as102_dev == NULL) { - err("%s: kzalloc failed", __func__); + dev_err(&intf->dev, "%s: kzalloc failed\n", __func__); return -ENOMEM; } /* Assign the user-friendly device name */ - for (i = 0; i < (sizeof(as102_usb_id_table) / - sizeof(struct usb_device_id)); i++) { + for (i = 0; i < ARRAY_SIZE(as102_usb_id_table); i++) { if (id == &as102_usb_id_table[i]) { as102_dev->name = as102_device_names[i]; as102_dev->elna_cfg = as102_elna_cfg[i]; @@ -411,8 +410,9 @@ static int as102_usb_probe(struct usb_interface *intf, ret = usb_register_dev(intf, &as102_usb_class_driver); if (ret < 0) { /* something prevented us from registering this driver */ - err("%s: usb_register_dev() failed (errno = %d)", - __func__, ret); + dev_err(&intf->dev, + "%s: usb_register_dev() failed (errno = %d)\n", + __func__, ret); goto failed; } diff --git a/trunk/drivers/staging/media/as102/as102_usb_drv.h b/trunk/drivers/staging/media/as102/as102_usb_drv.h index fc2884ab02a2..1ad1ec52b11e 100644 --- a/trunk/drivers/staging/media/as102/as102_usb_drv.h +++ b/trunk/drivers/staging/media/as102/as102_usb_drv.h @@ -17,8 +17,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include - #ifndef _AS102_USB_DRV_H_ #define _AS102_USB_DRV_H_ diff --git a/trunk/drivers/staging/media/easycap/easycap_ioctl.c b/trunk/drivers/staging/media/easycap/easycap_ioctl.c index 9413b37490c2..3cee3cd986d2 100644 --- a/trunk/drivers/staging/media/easycap/easycap_ioctl.c +++ b/trunk/drivers/staging/media/easycap/easycap_ioctl.c @@ -26,6 +26,7 @@ /*****************************************************************************/ #include "easycap.h" +#include /*--------------------------------------------------------------------------*/ /* diff --git a/trunk/drivers/staging/media/easycap/easycap_main.c b/trunk/drivers/staging/media/easycap/easycap_main.c index d0fe34afc2e5..6f83d362ab0d 100644 --- a/trunk/drivers/staging/media/easycap/easycap_main.c +++ b/trunk/drivers/staging/media/easycap/easycap_main.c @@ -3578,7 +3578,8 @@ static int easycap_usb_probe(struct usb_interface *intf, if (0 != (video_register_device(&(peasycap->video_device), VFL_TYPE_GRABBER, -1))) { - err("Not able to register with videodev"); + dev_err(&intf->dev, + "Not able to register with videodev\n"); videodev_release(&(peasycap->video_device)); return -ENODEV; } @@ -3822,7 +3823,8 @@ static int easycap_usb_probe(struct usb_interface *intf, rc = easycap_alsa_probe(peasycap); if (rc) { - err("easycap_alsa_probe() rc = %i\n", rc); + dev_err(&intf->dev, "easycap_alsa_probe() rc = %i\n", + rc); return -ENODEV; } diff --git a/trunk/drivers/staging/media/go7007/README b/trunk/drivers/staging/media/go7007/README index 48f447637817..aeba1324a9c5 100644 --- a/trunk/drivers/staging/media/go7007/README +++ b/trunk/drivers/staging/media/go7007/README @@ -6,6 +6,6 @@ Todo: - testing? - handle churn in v4l layer. -Please send patchs to Greg Kroah-Hartman and Cc: Ross +Please send patches to Greg Kroah-Hartman and Cc: Ross Cohen as well. diff --git a/trunk/drivers/staging/media/go7007/go7007.txt b/trunk/drivers/staging/media/go7007/go7007.txt index 9db1f3952fd2..fcb3e235abbf 100644 --- a/trunk/drivers/staging/media/go7007/go7007.txt +++ b/trunk/drivers/staging/media/go7007/go7007.txt @@ -87,7 +87,6 @@ kernel as built-in or modules: CONFIG_SOUND - Sound card support CONFIG_SND - Advanced Linux Sound Architecture CONFIG_USB - Support for Host-side USB - CONFIG_USB_DEVICEFS - USB device filesystem CONFIG_USB_EHCI_HCD - EHCI HCD (USB 2.0) support Additionally, to use the example application, the following options need to diff --git a/trunk/drivers/staging/media/go7007/s2250-loader.c b/trunk/drivers/staging/media/go7007/s2250-loader.c index 4e132519e253..7c5af4f289b6 100644 --- a/trunk/drivers/staging/media/go7007/s2250-loader.c +++ b/trunk/drivers/staging/media/go7007/s2250-loader.c @@ -160,31 +160,7 @@ static struct usb_driver s2250loader_driver = { .id_table = s2250loader_ids, }; -static int __init s2250loader_init(void) -{ - int r; - unsigned i = 0; - - for (i = 0; i < MAX_DEVICES; i++) - s2250_dev_table[i] = NULL; - - r = usb_register(&s2250loader_driver); - if (r) { - printk(KERN_ERR "usb_register failed. Error number %d\n", r); - return -1; - } - - printk(KERN_INFO "s2250loader_init: driver registered\n"); - return 0; -} -module_init(s2250loader_init); - -static void __exit s2250loader_cleanup(void) -{ - printk(KERN_INFO "s2250loader_cleanup\n"); - usb_deregister(&s2250loader_driver); -} -module_exit(s2250loader_cleanup); +module_usb_driver(s2250loader_driver); MODULE_AUTHOR(""); MODULE_DESCRIPTION("firmware loader for Sensoray 2250/2251"); diff --git a/trunk/drivers/staging/media/lirc/lirc_imon.c b/trunk/drivers/staging/media/lirc/lirc_imon.c index 5f7f8cd3a661..d7cf5ef076a5 100644 --- a/trunk/drivers/staging/media/lirc/lirc_imon.c +++ b/trunk/drivers/staging/media/lirc/lirc_imon.c @@ -209,8 +209,9 @@ static void deregister_from_lirc(struct imon_context *context) retval = lirc_unregister_driver(minor); if (retval) - err("%s: unable to deregister from lirc(%d)", - __func__, retval); + printk(KERN_ERR KBUILD_MODNAME + ": %s: unable to deregister from lirc(%d)", + __func__, retval); else printk(KERN_INFO MOD_NAME ": Deregistered iMON driver " "(minor:%d)\n", minor); @@ -234,16 +235,18 @@ static int display_open(struct inode *inode, struct file *file) subminor = iminor(inode); interface = usb_find_interface(&imon_driver, subminor); if (!interface) { - err("%s: could not find interface for minor %d", - __func__, subminor); + printk(KERN_ERR KBUILD_MODNAME + ": %s: could not find interface for minor %d\n", + __func__, subminor); retval = -ENODEV; goto exit; } context = usb_get_intfdata(interface); if (!context) { - err("%s: no context found for minor %d", - __func__, subminor); + dev_err(&interface->dev, + "%s: no context found for minor %d\n", + __func__, subminor); retval = -ENODEV; goto exit; } @@ -251,10 +254,12 @@ static int display_open(struct inode *inode, struct file *file) mutex_lock(&context->ctx_lock); if (!context->display) { - err("%s: display not supported by device", __func__); + dev_err(&interface->dev, + "%s: display not supported by device\n", __func__); retval = -ENODEV; } else if (context->display_isopen) { - err("%s: display port is already open", __func__); + dev_err(&interface->dev, + "%s: display port is already open\n", __func__); retval = -EBUSY; } else { context->display_isopen = 1; @@ -281,17 +286,20 @@ static int display_close(struct inode *inode, struct file *file) context = file->private_data; if (!context) { - err("%s: no context for device", __func__); + printk(KERN_ERR KBUILD_MODNAME + "%s: no context for device\n", __func__); return -ENODEV; } mutex_lock(&context->ctx_lock); if (!context->display) { - err("%s: display not supported by device", __func__); + dev_err(&context->usbdev->dev, + "%s: display not supported by device\n", __func__); retval = -ENODEV; } else if (!context->display_isopen) { - err("%s: display is not open", __func__); + dev_err(&context->usbdev->dev, + "%s: display is not open\n", __func__); retval = -EIO; } else { context->display_isopen = 0; @@ -340,19 +348,23 @@ static int send_packet(struct imon_context *context) retval = usb_submit_urb(context->tx_urb, GFP_KERNEL); if (retval) { atomic_set(&(context->tx.busy), 0); - err("%s: error submitting urb(%d)", __func__, retval); + dev_err(&context->usbdev->dev, + "%s: error submitting urb(%d)\n", __func__, retval); } else { /* Wait for transmission to complete (or abort) */ mutex_unlock(&context->ctx_lock); retval = wait_for_completion_interruptible( &context->tx.finished); if (retval) - err("%s: task interrupted", __func__); + dev_err(&context->usbdev->dev, + "%s: task interrupted\n", __func__); mutex_lock(&context->ctx_lock); retval = context->tx.status; if (retval) - err("%s: packet tx failed (%d)", __func__, retval); + dev_err(&context->usbdev->dev, + "%s: packet tx failed (%d)\n", + __func__, retval); } return retval; @@ -383,20 +395,23 @@ static ssize_t vfd_write(struct file *file, const char __user *buf, context = file->private_data; if (!context) { - err("%s: no context for device", __func__); + printk(KERN_ERR KBUILD_MODNAME + "%s: no context for device\n", __func__); return -ENODEV; } mutex_lock(&context->ctx_lock); if (!context->dev_present) { - err("%s: no iMON device present", __func__); + dev_err(&context->usbdev->dev, + "%s: no iMON device present\n", __func__); retval = -ENODEV; goto exit; } if (n_bytes <= 0 || n_bytes > IMON_DATA_BUF_SZ - 3) { - err("%s: invalid payload size", __func__); + dev_err(&context->usbdev->dev, + "%s: invalid payload size\n", __func__); retval = -EINVAL; goto exit; } @@ -425,8 +440,9 @@ static ssize_t vfd_write(struct file *file, const char __user *buf, retval = send_packet(context); if (retval) { - err("%s: send packet failed for packet #%d", - __func__, seq/2); + dev_err(&context->usbdev->dev, + "%s: send packet failed for packet #%d\n", + __func__, seq/2); goto exit; } else { seq += 2; @@ -441,7 +457,8 @@ static ssize_t vfd_write(struct file *file, const char __user *buf, context->usb_tx_buf[7] = (unsigned char) seq; retval = send_packet(context); if (retval) - err("%s: send packet failed for packet #%d", + dev_err(&context->usbdev->dev, + "%s: send packet failed for packet #%d\n", __func__, seq/2); } @@ -508,7 +525,8 @@ static void ir_close(void *data) context = (struct imon_context *)data; if (!context) { - err("%s: no context for device", __func__); + printk(KERN_ERR KBUILD_MODNAME + "%s: no context for device\n", __func__); return; } @@ -732,7 +750,7 @@ static int imon_probe(struct usb_interface *interface, context = kzalloc(sizeof(struct imon_context), GFP_KERNEL); if (!context) { - err("%s: kzalloc failed for context", __func__); + dev_err(dev, "%s: kzalloc failed for context\n", __func__); alloc_status = 1; goto alloc_status_switch; } @@ -797,7 +815,7 @@ static int imon_probe(struct usb_interface *interface, /* Input endpoint is mandatory */ if (!ir_ep_found) { - err("%s: no valid input (IR) endpoint found.", __func__); + dev_err(dev, "%s: no valid input (IR) endpoint found.\n", __func__); retval = -ENODEV; alloc_status = 2; goto alloc_status_switch; @@ -814,30 +832,30 @@ static int imon_probe(struct usb_interface *interface, driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); if (!driver) { - err("%s: kzalloc failed for lirc_driver", __func__); + dev_err(dev, "%s: kzalloc failed for lirc_driver\n", __func__); alloc_status = 2; goto alloc_status_switch; } rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); if (!rbuf) { - err("%s: kmalloc failed for lirc_buffer", __func__); + dev_err(dev, "%s: kmalloc failed for lirc_buffer\n", __func__); alloc_status = 3; goto alloc_status_switch; } if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) { - err("%s: lirc_buffer_init failed", __func__); + dev_err(dev, "%s: lirc_buffer_init failed\n", __func__); alloc_status = 4; goto alloc_status_switch; } rx_urb = usb_alloc_urb(0, GFP_KERNEL); if (!rx_urb) { - err("%s: usb_alloc_urb failed for IR urb", __func__); + dev_err(dev, "%s: usb_alloc_urb failed for IR urb\n", __func__); alloc_status = 5; goto alloc_status_switch; } tx_urb = usb_alloc_urb(0, GFP_KERNEL); if (!tx_urb) { - err("%s: usb_alloc_urb failed for display urb", + dev_err(dev, "%s: usb_alloc_urb failed for display urb\n", __func__); alloc_status = 6; goto alloc_status_switch; @@ -865,7 +883,7 @@ static int imon_probe(struct usb_interface *interface, lirc_minor = lirc_register_driver(driver); if (lirc_minor < 0) { - err("%s: lirc_register_driver failed", __func__); + dev_err(dev, "%s: lirc_register_driver failed\n", __func__); alloc_status = 7; goto unlock; } else @@ -900,8 +918,8 @@ static int imon_probe(struct usb_interface *interface, retval = usb_submit_urb(context->rx_urb, GFP_KERNEL); if (retval) { - err("%s: usb_submit_urb failed for intf0 (%d)", - __func__, retval); + dev_err(dev, "%s: usb_submit_urb failed for intf0 (%d)\n", + __func__, retval); mutex_unlock(&context->ctx_lock); goto exit; } diff --git a/trunk/drivers/staging/media/lirc/lirc_sasem.c b/trunk/drivers/staging/media/lirc/lirc_sasem.c index 74421043b954..352a20229ca2 100644 --- a/trunk/drivers/staging/media/lirc/lirc_sasem.c +++ b/trunk/drivers/staging/media/lirc/lirc_sasem.c @@ -185,7 +185,7 @@ static void deregister_from_lirc(struct sasem_context *context) retval = lirc_unregister_driver(minor); if (retval) - err("%s: unable to deregister from lirc (%d)", + printk(KERN_ERR "%s: unable to deregister from lirc (%d)\n", __func__, retval); else printk(KERN_INFO "Deregistered Sasem driver (minor:%d)\n", @@ -210,16 +210,18 @@ static int vfd_open(struct inode *inode, struct file *file) subminor = iminor(inode); interface = usb_find_interface(&sasem_driver, subminor); if (!interface) { - err("%s: could not find interface for minor %d", - __func__, subminor); + printk(KERN_ERR KBUILD_MODNAME + ": %s: could not find interface for minor %d\n", + __func__, subminor); retval = -ENODEV; goto exit; } context = usb_get_intfdata(interface); if (!context) { - err("%s: no context found for minor %d", - __func__, subminor); + dev_err(&interface->dev, + "%s: no context found for minor %d\n", + __func__, subminor); retval = -ENODEV; goto exit; } @@ -227,12 +229,13 @@ static int vfd_open(struct inode *inode, struct file *file) mutex_lock(&context->ctx_lock); if (context->vfd_isopen) { - err("%s: VFD port is already open", __func__); + dev_err(&interface->dev, + "%s: VFD port is already open", __func__); retval = -EBUSY; } else { context->vfd_isopen = 1; file->private_data = context; - printk(KERN_INFO "VFD port opened\n"); + dev_info(&interface->dev, "VFD port opened\n"); } mutex_unlock(&context->ctx_lock); @@ -253,7 +256,8 @@ static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg) context = (struct sasem_context *) file->private_data; if (!context) { - err("%s: no context for device", __func__); + printk(KERN_ERR KBUILD_MODNAME + ": %s: no context for device\n", __func__); return -ENODEV; } @@ -287,14 +291,15 @@ static int vfd_close(struct inode *inode, struct file *file) context = (struct sasem_context *) file->private_data; if (!context) { - err("%s: no context for device", __func__); + printk(KERN_ERR KBUILD_MODNAME + ": %s: no context for device\n", __func__); return -ENODEV; } mutex_lock(&context->ctx_lock); if (!context->vfd_isopen) { - err("%s: VFD is not open", __func__); + dev_err(&context->dev->dev, "%s: VFD is not open\n", __func__); retval = -EIO; } else { context->vfd_isopen = 0; @@ -339,7 +344,8 @@ static int send_packet(struct sasem_context *context) retval = usb_submit_urb(context->tx_urb, GFP_KERNEL); if (retval) { atomic_set(&(context->tx.busy), 0); - err("%s: error submitting urb (%d)", __func__, retval); + dev_err(&context->dev->dev, "%s: error submitting urb (%d)\n", + __func__, retval); } else { /* Wait for transmission to complete (or abort) */ mutex_unlock(&context->ctx_lock); @@ -348,7 +354,9 @@ static int send_packet(struct sasem_context *context) retval = context->tx.status; if (retval) - err("%s: packet tx failed (%d)", __func__, retval); + dev_err(&context->dev->dev, + "%s: packet tx failed (%d)\n", + __func__, retval); } return retval; @@ -369,20 +377,23 @@ static ssize_t vfd_write(struct file *file, const char *buf, context = (struct sasem_context *) file->private_data; if (!context) { - err("%s: no context for device", __func__); + printk(KERN_ERR KBUILD_MODNAME + ": %s: no context for device\n", __func__); return -ENODEV; } mutex_lock(&context->ctx_lock); if (!context->dev_present) { - err("%s: no Sasem device present", __func__); + printk(KERN_ERR KBUILD_MODNAME + ": %s: no Sasem device present\n", __func__); retval = -ENODEV; goto exit; } if (n_bytes <= 0 || n_bytes > SASEM_DATA_BUF_SZ) { - err("%s: invalid payload size", __func__); + dev_err(&context->dev->dev, "%s: invalid payload size\n", + __func__); retval = -EINVAL; goto exit; } @@ -440,9 +451,9 @@ static ssize_t vfd_write(struct file *file, const char *buf, } retval = send_packet(context); if (retval) { - - err("%s: send packet failed for packet #%d", - __func__, i); + dev_err(&context->dev->dev, + "%s: send packet failed for packet #%d\n", + __func__, i); goto exit; } } @@ -492,7 +503,8 @@ static int ir_open(void *data) mutex_lock(&context->ctx_lock); if (context->ir_isopen) { - err("%s: IR port is already open", __func__); + dev_err(&context->dev->dev, "%s: IR port is already open\n", + __func__); retval = -EBUSY; goto exit; } @@ -506,8 +518,9 @@ static int ir_open(void *data) retval = usb_submit_urb(context->rx_urb, GFP_KERNEL); if (retval) - err("%s: usb_submit_urb failed for ir_open (%d)", - __func__, retval); + dev_err(&context->dev->dev, + "%s: usb_submit_urb failed for ir_open (%d)\n", + __func__, retval); else { context->ir_isopen = 1; printk(KERN_INFO "IR port opened\n"); @@ -529,7 +542,8 @@ static void ir_close(void *data) context = (struct sasem_context *)data; if (!context) { - err("%s: no context for device", __func__); + printk(KERN_ERR KBUILD_MODNAME + ": %s: no context for device\n", __func__); return; } @@ -687,7 +701,7 @@ static int sasem_probe(struct usb_interface *interface, struct sasem_context *context = NULL; int i; - printk(KERN_INFO "%s: found Sasem device\n", __func__); + dev_info(&interface->dev, "%s: found Sasem device\n", __func__); dev = usb_get_dev(interface_to_usbdev(interface)); @@ -719,8 +733,8 @@ static int sasem_probe(struct usb_interface *interface, rx_endpoint = ep; ir_ep_found = 1; if (debug) - printk(KERN_INFO "%s: found IR endpoint\n", - __func__); + dev_info(&interface->dev, + "%s: found IR endpoint\n", __func__); } else if (!vfd_ep_found && ep_dir == USB_DIR_OUT && @@ -729,22 +743,23 @@ static int sasem_probe(struct usb_interface *interface, tx_endpoint = ep; vfd_ep_found = 1; if (debug) - printk(KERN_INFO "%s: found VFD endpoint\n", - __func__); + dev_info(&interface->dev, + "%s: found VFD endpoint\n", __func__); } } /* Input endpoint is mandatory */ if (!ir_ep_found) { - - err("%s: no valid input (IR) endpoint found.", __func__); + dev_err(&interface->dev, + "%s: no valid input (IR) endpoint found.\n", __func__); retval = -ENODEV; goto exit; } if (!vfd_ep_found) - printk(KERN_INFO "%s: no valid output (VFD) endpoint found.\n", - __func__); + dev_info(&interface->dev, + "%s: no valid output (VFD) endpoint found.\n", + __func__); /* Allocate memory */ @@ -752,38 +767,44 @@ static int sasem_probe(struct usb_interface *interface, context = kzalloc(sizeof(struct sasem_context), GFP_KERNEL); if (!context) { - err("%s: kzalloc failed for context", __func__); + dev_err(&interface->dev, + "%s: kzalloc failed for context\n", __func__); alloc_status = 1; goto alloc_status_switch; } driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); if (!driver) { - err("%s: kzalloc failed for lirc_driver", __func__); + dev_err(&interface->dev, + "%s: kzalloc failed for lirc_driver\n", __func__); alloc_status = 2; goto alloc_status_switch; } rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); if (!rbuf) { - err("%s: kmalloc failed for lirc_buffer", __func__); + dev_err(&interface->dev, + "%s: kmalloc failed for lirc_buffer\n", __func__); alloc_status = 3; goto alloc_status_switch; } if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) { - err("%s: lirc_buffer_init failed", __func__); + dev_err(&interface->dev, + "%s: lirc_buffer_init failed\n", __func__); alloc_status = 4; goto alloc_status_switch; } rx_urb = usb_alloc_urb(0, GFP_KERNEL); if (!rx_urb) { - err("%s: usb_alloc_urb failed for IR urb", __func__); + dev_err(&interface->dev, + "%s: usb_alloc_urb failed for IR urb\n", __func__); alloc_status = 5; goto alloc_status_switch; } if (vfd_ep_found) { tx_urb = usb_alloc_urb(0, GFP_KERNEL); if (!tx_urb) { - err("%s: usb_alloc_urb failed for VFD urb", - __func__); + dev_err(&interface->dev, + "%s: usb_alloc_urb failed for VFD urb", + __func__); alloc_status = 6; goto alloc_status_switch; } @@ -807,7 +828,8 @@ static int sasem_probe(struct usb_interface *interface, lirc_minor = lirc_register_driver(driver); if (lirc_minor < 0) { - err("%s: lirc_register_driver failed", __func__); + dev_err(&interface->dev, + "%s: lirc_register_driver failed\n", __func__); alloc_status = 7; retval = lirc_minor; goto unlock; diff --git a/trunk/drivers/staging/media/lirc/lirc_ttusbir.c b/trunk/drivers/staging/media/lirc/lirc_ttusbir.c index 7950887ff113..3bb865c02173 100644 --- a/trunk/drivers/staging/media/lirc/lirc_ttusbir.c +++ b/trunk/drivers/staging/media/lirc/lirc_ttusbir.c @@ -113,8 +113,9 @@ static int set_use_inc(void *data) for (i = 0; i < num_urbs; i++) { retval = usb_submit_urb(ttusbir->urb[i], GFP_KERNEL); if (retval) { - err("%s: usb_submit_urb failed on urb %d", - __func__, i); + dev_err(&ttusbir->interf->dev, + "%s: usb_submit_urb failed on urb %d\n", + __func__, i); return retval; } } @@ -278,7 +279,7 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id) if (ttusbir->alt_setting != -1) DPRINTK("alt setting: %d\n", ttusbir->alt_setting); else { - err("Could not find alternate setting\n"); + dev_err(&intf->dev, "Could not find alternate setting\n"); kfree(ttusbir); return -EINVAL; } @@ -291,7 +292,7 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id) /* Register as a LIRC driver */ if (lirc_buffer_init(&ttusbir->rbuf, sizeof(int), 256) < 0) { - err("Could not get memory for LIRC data buffer\n"); + dev_err(&intf->dev, "Could not get memory for LIRC data buffer\n"); usb_set_intfdata(intf, NULL); kfree(ttusbir); return -ENOMEM; @@ -310,7 +311,7 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id) ttusbir->driver.features = LIRC_CAN_REC_MODE2; ttusbir->minor = lirc_register_driver(&ttusbir->driver); if (ttusbir->minor < 0) { - err("Error registering as LIRC driver\n"); + dev_err(&intf->dev, "Error registering as LIRC driver\n"); usb_set_intfdata(intf, NULL); lirc_buffer_free(&ttusbir->rbuf); kfree(ttusbir); @@ -321,7 +322,7 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id) for (i = 0; i < num_urbs; i++) { ttusbir->urb[i] = usb_alloc_urb(8, GFP_KERNEL); if (!ttusbir->urb[i]) { - err("Could not allocate memory for the URB\n"); + dev_err(&intf->dev, "Could not allocate memory for the URB\n"); for (j = i - 1; j >= 0; j--) kfree(ttusbir->urb[j]); lirc_buffer_free(&ttusbir->rbuf); diff --git a/trunk/drivers/staging/mei/TODO b/trunk/drivers/staging/mei/TODO deleted file mode 100644 index fc266018355e..000000000000 --- a/trunk/drivers/staging/mei/TODO +++ /dev/null @@ -1,10 +0,0 @@ -TODO: - - Cleanup and split the timer function -Upon Unstaging: - - move mei.h to include/linux/mei.h - - Documentation/ioctl/ioctl-number.txt - - move mei.txt under Documentation/mei/ - - move mei-amt-version.c under Documentation/mei - - add hostprogs-y for mei-amt-version.c - - drop mei_version.h - - Updated MAINTAINERS diff --git a/trunk/drivers/staging/mei/init.c b/trunk/drivers/staging/mei/init.c deleted file mode 100644 index eab711fb5fc4..000000000000 --- a/trunk/drivers/staging/mei/init.c +++ /dev/null @@ -1,735 +0,0 @@ -/* - * - * Intel Management Engine Interface (Intel MEI) Linux driver - * Copyright (c) 2003-2012, 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 "mei_dev.h" -#include "hw.h" -#include "interface.h" -#include "mei.h" - -const uuid_le mei_amthi_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac, - 0xa8, 0x46, 0xe0, 0xff, 0x65, - 0x81, 0x4c); - -/** - * mei_io_list_init - Sets up a queue list. - * - * @list: An instance io list structure - * @dev: the device structure - */ -void mei_io_list_init(struct mei_io_list *list) -{ - /* initialize our queue list */ - INIT_LIST_HEAD(&list->mei_cb.cb_list); -} - -/** - * mei_io_list_flush - removes list entry belonging to cl. - * - * @list: An instance of our list structure - * @cl: private data of the file object - */ -void mei_io_list_flush(struct mei_io_list *list, struct mei_cl *cl) -{ - struct mei_cl_cb *pos; - struct mei_cl_cb *next; - - list_for_each_entry_safe(pos, next, &list->mei_cb.cb_list, cb_list) { - if (pos->file_private) { - struct mei_cl *cl_tmp; - cl_tmp = (struct mei_cl *)pos->file_private; - if (mei_cl_cmp_id(cl, cl_tmp)) - list_del(&pos->cb_list); - } - } -} -/** - * mei_cl_flush_queues - flushes queue lists belonging to cl. - * - * @dev: the device structure - * @cl: private data of the file object - */ -int mei_cl_flush_queues(struct mei_cl *cl) -{ - if (!cl || !cl->dev) - return -EINVAL; - - dev_dbg(&cl->dev->pdev->dev, "remove list entry belonging to cl\n"); - mei_io_list_flush(&cl->dev->read_list, cl); - mei_io_list_flush(&cl->dev->write_list, cl); - mei_io_list_flush(&cl->dev->write_waiting_list, cl); - mei_io_list_flush(&cl->dev->ctrl_wr_list, cl); - mei_io_list_flush(&cl->dev->ctrl_rd_list, cl); - mei_io_list_flush(&cl->dev->amthi_cmd_list, cl); - mei_io_list_flush(&cl->dev->amthi_read_complete_list, cl); - return 0; -} - - - -/** - * mei_reset_iamthif_params - initializes mei device iamthif - * - * @dev: the device structure - */ -static void mei_reset_iamthif_params(struct mei_device *dev) -{ - /* reset iamthif parameters. */ - dev->iamthif_current_cb = NULL; - dev->iamthif_msg_buf_size = 0; - dev->iamthif_msg_buf_index = 0; - dev->iamthif_canceled = false; - dev->iamthif_ioctl = false; - dev->iamthif_state = MEI_IAMTHIF_IDLE; - dev->iamthif_timer = 0; -} - -/** - * init_mei_device - allocates and initializes the mei device structure - * - * @pdev: The pci device structure - * - * returns The mei_device_device pointer on success, NULL on failure. - */ -struct mei_device *mei_device_init(struct pci_dev *pdev) -{ - struct mei_device *dev; - - dev = kzalloc(sizeof(struct mei_device), GFP_KERNEL); - if (!dev) - return NULL; - - /* setup our list array */ - INIT_LIST_HEAD(&dev->file_list); - INIT_LIST_HEAD(&dev->wd_cl.link); - INIT_LIST_HEAD(&dev->iamthif_cl.link); - mutex_init(&dev->device_lock); - init_waitqueue_head(&dev->wait_recvd_msg); - init_waitqueue_head(&dev->wait_stop_wd); - dev->mei_state = MEI_INITIALIZING; - dev->iamthif_state = MEI_IAMTHIF_IDLE; - dev->wd_interface_reg = false; - - - mei_io_list_init(&dev->read_list); - mei_io_list_init(&dev->write_list); - mei_io_list_init(&dev->write_waiting_list); - mei_io_list_init(&dev->ctrl_wr_list); - mei_io_list_init(&dev->ctrl_rd_list); - mei_io_list_init(&dev->amthi_cmd_list); - mei_io_list_init(&dev->amthi_read_complete_list); - dev->pdev = pdev; - return dev; -} - -/** - * mei_hw_init - initializes host and fw to start work. - * - * @dev: the device structure - * - * returns 0 on success, <0 on failure. - */ -int mei_hw_init(struct mei_device *dev) -{ - int err = 0; - int ret; - - mutex_lock(&dev->device_lock); - - dev->host_hw_state = mei_hcsr_read(dev); - dev->me_hw_state = mei_mecsr_read(dev); - dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, mestate = 0x%08x.\n", - dev->host_hw_state, dev->me_hw_state); - - /* acknowledge interrupt and stop interupts */ - if ((dev->host_hw_state & H_IS) == H_IS) - mei_reg_write(dev, H_CSR, dev->host_hw_state); - - dev->recvd_msg = false; - dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n"); - - mei_reset(dev, 1); - - dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n", - dev->host_hw_state, dev->me_hw_state); - - /* wait for ME to turn on ME_RDY */ - if (!dev->recvd_msg) { - mutex_unlock(&dev->device_lock); - err = wait_event_interruptible_timeout(dev->wait_recvd_msg, - dev->recvd_msg, MEI_INTEROP_TIMEOUT); - mutex_lock(&dev->device_lock); - } - - if (err <= 0 && !dev->recvd_msg) { - dev->mei_state = MEI_DISABLED; - dev_dbg(&dev->pdev->dev, - "wait_event_interruptible_timeout failed" - "on wait for ME to turn on ME_RDY.\n"); - ret = -ENODEV; - goto out; - } - - if (!(((dev->host_hw_state & H_RDY) == H_RDY) && - ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA))) { - dev->mei_state = MEI_DISABLED; - dev_dbg(&dev->pdev->dev, - "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n", - dev->host_hw_state, dev->me_hw_state); - - if (!(dev->host_hw_state & H_RDY)) - dev_dbg(&dev->pdev->dev, "host turn off H_RDY.\n"); - - if (!(dev->me_hw_state & ME_RDY_HRA)) - dev_dbg(&dev->pdev->dev, "ME turn off ME_RDY.\n"); - - printk(KERN_ERR "mei: link layer initialization failed.\n"); - ret = -ENODEV; - goto out; - } - - if (dev->version.major_version != HBM_MAJOR_VERSION || - dev->version.minor_version != HBM_MINOR_VERSION) { - dev_dbg(&dev->pdev->dev, "MEI start failed.\n"); - ret = -ENODEV; - goto out; - } - - dev->recvd_msg = false; - dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n", - dev->host_hw_state, dev->me_hw_state); - dev_dbg(&dev->pdev->dev, "ME turn on ME_RDY and host turn on H_RDY.\n"); - dev_dbg(&dev->pdev->dev, "link layer has been established.\n"); - dev_dbg(&dev->pdev->dev, "MEI start success.\n"); - ret = 0; - -out: - mutex_unlock(&dev->device_lock); - return ret; -} - -/** - * mei_hw_reset - resets fw via mei csr register. - * - * @dev: the device structure - * @interrupts_enabled: if interrupt should be enabled after reset. - */ -static void mei_hw_reset(struct mei_device *dev, int interrupts_enabled) -{ - dev->host_hw_state |= (H_RST | H_IG); - - if (interrupts_enabled) - mei_enable_interrupts(dev); - else - mei_disable_interrupts(dev); -} - -/** - * mei_reset - resets host and fw. - * - * @dev: the device structure - * @interrupts_enabled: if interrupt should be enabled after reset. - */ -void mei_reset(struct mei_device *dev, int interrupts_enabled) -{ - struct mei_cl *cl_pos = NULL; - struct mei_cl *cl_next = NULL; - struct mei_cl_cb *cb_pos = NULL; - struct mei_cl_cb *cb_next = NULL; - bool unexpected; - - if (dev->mei_state == MEI_RECOVERING_FROM_RESET) { - dev->need_reset = true; - return; - } - - unexpected = (dev->mei_state != MEI_INITIALIZING && - dev->mei_state != MEI_DISABLED && - dev->mei_state != MEI_POWER_DOWN && - dev->mei_state != MEI_POWER_UP); - - dev->host_hw_state = mei_hcsr_read(dev); - - dev_dbg(&dev->pdev->dev, "before reset host_hw_state = 0x%08x.\n", - dev->host_hw_state); - - mei_hw_reset(dev, interrupts_enabled); - - dev->host_hw_state &= ~H_RST; - dev->host_hw_state |= H_IG; - - mei_hcsr_set(dev); - - dev_dbg(&dev->pdev->dev, "currently saved host_hw_state = 0x%08x.\n", - dev->host_hw_state); - - dev->need_reset = false; - - if (dev->mei_state != MEI_INITIALIZING) { - if (dev->mei_state != MEI_DISABLED && - dev->mei_state != MEI_POWER_DOWN) - dev->mei_state = MEI_RESETING; - - list_for_each_entry_safe(cl_pos, - cl_next, &dev->file_list, link) { - cl_pos->state = MEI_FILE_DISCONNECTED; - cl_pos->mei_flow_ctrl_creds = 0; - cl_pos->read_cb = NULL; - cl_pos->timer_count = 0; - } - /* remove entry if already in list */ - dev_dbg(&dev->pdev->dev, "list del iamthif and wd file list.\n"); - mei_remove_client_from_file_list(dev, - dev->wd_cl.host_client_id); - - mei_remove_client_from_file_list(dev, - dev->iamthif_cl.host_client_id); - - mei_reset_iamthif_params(dev); - dev->wd_due_counter = 0; - dev->extra_write_index = 0; - } - - dev->me_clients_num = 0; - dev->rd_msg_hdr = 0; - dev->stop = false; - dev->wd_pending = false; - - /* update the state of the registers after reset */ - dev->host_hw_state = mei_hcsr_read(dev); - dev->me_hw_state = mei_mecsr_read(dev); - - dev_dbg(&dev->pdev->dev, "after reset host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n", - dev->host_hw_state, dev->me_hw_state); - - if (unexpected) - dev_warn(&dev->pdev->dev, "unexpected reset.\n"); - - /* Wake up all readings so they can be interrupted */ - list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { - if (waitqueue_active(&cl_pos->rx_wait)) { - dev_dbg(&dev->pdev->dev, "Waking up client!\n"); - wake_up_interruptible(&cl_pos->rx_wait); - } - } - /* remove all waiting requests */ - list_for_each_entry_safe(cb_pos, cb_next, - &dev->write_list.mei_cb.cb_list, cb_list) { - list_del(&cb_pos->cb_list); - mei_free_cb_private(cb_pos); - } -} - - - -/** - * host_start_message - mei host sends start message. - * - * @dev: the device structure - * - * returns none. - */ -void mei_host_start_message(struct mei_device *dev) -{ - struct mei_msg_hdr *mei_hdr; - struct hbm_host_version_request *host_start_req; - - /* host start message */ - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_host_version_request); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - host_start_req = - (struct hbm_host_version_request *) &dev->wr_msg_buf[1]; - memset(host_start_req, 0, sizeof(struct hbm_host_version_request)); - host_start_req->hbm_cmd = HOST_START_REQ_CMD; - host_start_req->host_version.major_version = HBM_MAJOR_VERSION; - host_start_req->host_version.minor_version = HBM_MINOR_VERSION; - dev->recvd_msg = false; - if (mei_write_message(dev, mei_hdr, (unsigned char *)host_start_req, - mei_hdr->length)) { - dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n"); - dev->mei_state = MEI_RESETING; - mei_reset(dev, 1); - } - dev->init_clients_state = MEI_START_MESSAGE; - dev->init_clients_timer = INIT_CLIENTS_TIMEOUT; - return ; -} - -/** - * host_enum_clients_message - host sends enumeration client request message. - * - * @dev: the device structure - * - * returns none. - */ -void mei_host_enum_clients_message(struct mei_device *dev) -{ - struct mei_msg_hdr *mei_hdr; - struct hbm_host_enum_request *host_enum_req; - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - /* enumerate clients */ - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_host_enum_request); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - host_enum_req = (struct hbm_host_enum_request *) &dev->wr_msg_buf[1]; - memset(host_enum_req, 0, sizeof(struct hbm_host_enum_request)); - host_enum_req->hbm_cmd = HOST_ENUM_REQ_CMD; - if (mei_write_message(dev, mei_hdr, (unsigned char *)host_enum_req, - mei_hdr->length)) { - dev->mei_state = MEI_RESETING; - dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n"); - mei_reset(dev, 1); - } - dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE; - dev->init_clients_timer = INIT_CLIENTS_TIMEOUT; - return; -} - - -/** - * allocate_me_clients_storage - allocates storage for me clients - * - * @dev: the device structure - * - * returns none. - */ -void mei_allocate_me_clients_storage(struct mei_device *dev) -{ - struct mei_me_client *clients; - int b; - - /* count how many ME clients we have */ - for_each_set_bit(b, dev->me_clients_map, MEI_CLIENTS_MAX) - dev->me_clients_num++; - - if (dev->me_clients_num <= 0) - return ; - - - if (dev->me_clients != NULL) { - kfree(dev->me_clients); - dev->me_clients = NULL; - } - dev_dbg(&dev->pdev->dev, "memory allocation for ME clients size=%zd.\n", - dev->me_clients_num * sizeof(struct mei_me_client)); - /* allocate storage for ME clients representation */ - clients = kcalloc(dev->me_clients_num, - sizeof(struct mei_me_client), GFP_KERNEL); - if (!clients) { - dev_dbg(&dev->pdev->dev, "memory allocation for ME clients failed.\n"); - dev->mei_state = MEI_RESETING; - mei_reset(dev, 1); - return ; - } - dev->me_clients = clients; - return ; -} -/** - * host_client_properties - reads properties for client - * - * @dev: the device structure - * - * returns: - * < 0 - Error. - * = 0 - no more clients. - * = 1 - still have clients to send properties request. - */ -int mei_host_client_properties(struct mei_device *dev) -{ - struct mei_msg_hdr *mei_header; - struct hbm_props_request *host_cli_req; - int b; - u8 client_num = dev->me_client_presentation_num; - - b = dev->me_client_index; - b = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX, b); - if (b < MEI_CLIENTS_MAX) { - dev->me_clients[client_num].client_id = b; - dev->me_clients[client_num].mei_flow_ctrl_creds = 0; - mei_header = (struct mei_msg_hdr *)&dev->wr_msg_buf[0]; - mei_header->host_addr = 0; - mei_header->me_addr = 0; - mei_header->length = sizeof(struct hbm_props_request); - mei_header->msg_complete = 1; - mei_header->reserved = 0; - - host_cli_req = (struct hbm_props_request *)&dev->wr_msg_buf[1]; - - memset(host_cli_req, 0, sizeof(struct hbm_props_request)); - - host_cli_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD; - host_cli_req->address = b; - - if (mei_write_message(dev, mei_header, - (unsigned char *)host_cli_req, - mei_header->length)) { - dev->mei_state = MEI_RESETING; - dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n"); - mei_reset(dev, 1); - return -EIO; - } - - dev->init_clients_timer = INIT_CLIENTS_TIMEOUT; - dev->me_client_index = b; - return 1; - } - - return 0; -} - -/** - * mei_init_file_private - initializes private file structure. - * - * @priv: private file structure to be initialized - * @file: the file structure - */ -void mei_cl_init(struct mei_cl *priv, struct mei_device *dev) -{ - memset(priv, 0, sizeof(struct mei_cl)); - init_waitqueue_head(&priv->wait); - init_waitqueue_head(&priv->rx_wait); - init_waitqueue_head(&priv->tx_wait); - INIT_LIST_HEAD(&priv->link); - priv->reading_state = MEI_IDLE; - priv->writing_state = MEI_IDLE; - priv->dev = dev; -} - -int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid) -{ - int i, res = -1; - - for (i = 0; i < dev->me_clients_num; ++i) - if (uuid_le_cmp(cuuid, - dev->me_clients[i].props.protocol_name) == 0) { - res = i; - break; - } - - return res; -} - - -/** - * mei_find_me_client_update_filext - searches for ME client guid - * sets client_id in mei_file_private if found - * @dev: the device structure - * @priv: private file structure to set client_id in - * @cguid: searched guid of ME client - * @client_id: id of host client to be set in file private structure - * - * returns ME client index - */ -u8 mei_find_me_client_update_filext(struct mei_device *dev, struct mei_cl *priv, - const uuid_le *cguid, u8 client_id) -{ - int i; - - if (!dev || !priv || !cguid) - return 0; - - /* check for valid client id */ - i = mei_find_me_client_index(dev, *cguid); - if (i >= 0) { - priv->me_client_id = dev->me_clients[i].client_id; - priv->state = MEI_FILE_CONNECTING; - priv->host_client_id = client_id; - - list_add_tail(&priv->link, &dev->file_list); - return (u8)i; - } - - return 0; -} - -/** - * host_init_iamthif - mei initialization iamthif client. - * - * @dev: the device structure - * - */ -void mei_host_init_iamthif(struct mei_device *dev) -{ - u8 i; - unsigned char *msg_buf; - - mei_cl_init(&dev->iamthif_cl, dev); - dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; - - /* find ME amthi client */ - i = mei_find_me_client_update_filext(dev, &dev->iamthif_cl, - &mei_amthi_guid, MEI_IAMTHIF_HOST_CLIENT_ID); - if (dev->iamthif_cl.state != MEI_FILE_CONNECTING) { - dev_dbg(&dev->pdev->dev, "failed to find iamthif client.\n"); - return; - } - - /* Assign iamthif_mtu to the value received from ME */ - - dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length; - dev_dbg(&dev->pdev->dev, "IAMTHIF_MTU = %d\n", - dev->me_clients[i].props.max_msg_length); - - kfree(dev->iamthif_msg_buf); - dev->iamthif_msg_buf = NULL; - - /* allocate storage for ME message buffer */ - msg_buf = kcalloc(dev->iamthif_mtu, - sizeof(unsigned char), GFP_KERNEL); - if (!msg_buf) { - dev_dbg(&dev->pdev->dev, "memory allocation for ME message buffer failed.\n"); - return; - } - - dev->iamthif_msg_buf = msg_buf; - - if (mei_connect(dev, &dev->iamthif_cl)) { - dev_dbg(&dev->pdev->dev, "Failed to connect to AMTHI client\n"); - dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; - dev->iamthif_cl.host_client_id = 0; - } else { - dev->iamthif_cl.timer_count = CONNECT_TIMEOUT; - } -} - -/** - * mei_alloc_file_private - allocates a private file structure and sets it up. - * @file: the file structure - * - * returns The allocated file or NULL on failure - */ -struct mei_cl *mei_cl_allocate(struct mei_device *dev) -{ - struct mei_cl *cl; - - cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL); - if (!cl) - return NULL; - - mei_cl_init(cl, dev); - - return cl; -} - - - -/** - * mei_disconnect_host_client - sends disconnect message to fw from host client. - * - * @dev: the device structure - * @cl: private data of the file object - * - * Locking: called under "dev->device_lock" lock - * - * returns 0 on success, <0 on failure. - */ -int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) -{ - int rets, err; - long timeout = 15; /* 15 seconds */ - struct mei_cl_cb *cb; - - if (!dev || !cl) - return -ENODEV; - - if (cl->state != MEI_FILE_DISCONNECTING) - return 0; - - cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); - if (!cb) - return -ENOMEM; - - INIT_LIST_HEAD(&cb->cb_list); - cb->file_private = cl; - cb->major_file_operations = MEI_CLOSE; - if (dev->mei_host_buffer_is_empty) { - dev->mei_host_buffer_is_empty = false; - if (mei_disconnect(dev, cl)) { - rets = -ENODEV; - dev_dbg(&dev->pdev->dev, "failed to call mei_disconnect.\n"); - goto free; - } - mdelay(10); /* Wait for hardware disconnection ready */ - list_add_tail(&cb->cb_list, &dev->ctrl_rd_list.mei_cb.cb_list); - } else { - dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n"); - list_add_tail(&cb->cb_list, - &dev->ctrl_wr_list.mei_cb.cb_list); - } - mutex_unlock(&dev->device_lock); - - err = wait_event_timeout(dev->wait_recvd_msg, - (MEI_FILE_DISCONNECTED == cl->state), - timeout * HZ); - - mutex_lock(&dev->device_lock); - if (MEI_FILE_DISCONNECTED == cl->state) { - rets = 0; - dev_dbg(&dev->pdev->dev, "successfully disconnected from FW client.\n"); - } else { - rets = -ENODEV; - if (MEI_FILE_DISCONNECTED != cl->state) - dev_dbg(&dev->pdev->dev, "wrong status client disconnect.\n"); - - if (err) - dev_dbg(&dev->pdev->dev, - "wait failed disconnect err=%08x\n", - err); - - dev_dbg(&dev->pdev->dev, "failed to disconnect from FW client.\n"); - } - - mei_io_list_flush(&dev->ctrl_rd_list, cl); - mei_io_list_flush(&dev->ctrl_wr_list, cl); -free: - mei_free_cb_private(cb); - return rets; -} - -/** - * mei_remove_client_from_file_list - - * removes file private data from device file list - * - * @dev: the device structure - * @host_client_id: host client id to be removed - */ -void mei_remove_client_from_file_list(struct mei_device *dev, - u8 host_client_id) -{ - struct mei_cl *cl_pos = NULL; - struct mei_cl *cl_next = NULL; - list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { - if (host_client_id == cl_pos->host_client_id) { - dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n", - cl_pos->host_client_id, - cl_pos->me_client_id); - list_del_init(&cl_pos->link); - break; - } - } -} diff --git a/trunk/drivers/staging/mei/main.c b/trunk/drivers/staging/mei/main.c deleted file mode 100644 index 7c9321fa7bb1..000000000000 --- a/trunk/drivers/staging/mei/main.c +++ /dev/null @@ -1,1237 +0,0 @@ -/* - * - * Intel Management Engine Interface (Intel MEI) Linux driver - * Copyright (c) 2003-2012, 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 -#include -#include -#include -#include -#include -#include -#include - -#include "mei_dev.h" -#include "mei.h" -#include "interface.h" - - -#define MEI_READ_TIMEOUT 45 -#define MEI_DRIVER_NAME "mei" -#define MEI_DEV_NAME "mei" - -/* - * mei driver strings - */ -static char mei_driver_name[] = MEI_DRIVER_NAME; -static const char mei_driver_string[] = "Intel(R) Management Engine Interface"; - -/* The device pointer */ -/* Currently this driver works as long as there is only a single AMT device. */ -struct pci_dev *mei_device; - -/* mei_pci_tbl - PCI Device ID Table */ -static DEFINE_PCI_DEVICE_TABLE(mei_pci_tbl) = { - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82946GZ)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G35)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82Q965)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G965)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82GM965)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82GME965)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82Q35)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82G33)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82Q33)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82X38)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_3200)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_6)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_7)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_8)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_9)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_10)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_1)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_2)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_3)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_4)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_1)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_2)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_3)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_4)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_IBXPK_1)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_IBXPK_2)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_CPT_1)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PBG_1)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_1)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_2)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_3)}, - - /* required last entry */ - {0, } -}; - -MODULE_DEVICE_TABLE(pci, mei_pci_tbl); - -static DEFINE_MUTEX(mei_mutex); - - -/** - * mei_clear_list - removes all callbacks associated with file - * from mei_cb_list - * - * @dev: device structure. - * @file: file structure - * @mei_cb_list: callbacks list - * - * mei_clear_list is called to clear resources associated with file - * when application calls close function or Ctrl-C was pressed - * - * returns true if callback removed from the list, false otherwise - */ -static bool mei_clear_list(struct mei_device *dev, - struct file *file, struct list_head *mei_cb_list) -{ - struct mei_cl_cb *cb_pos = NULL; - struct mei_cl_cb *cb_next = NULL; - struct file *file_temp; - bool removed = false; - - /* list all list member */ - list_for_each_entry_safe(cb_pos, cb_next, mei_cb_list, cb_list) { - file_temp = (struct file *)cb_pos->file_object; - /* check if list member associated with a file */ - if (file_temp == file) { - /* remove member from the list */ - list_del(&cb_pos->cb_list); - /* check if cb equal to current iamthif cb */ - if (dev->iamthif_current_cb == cb_pos) { - dev->iamthif_current_cb = NULL; - /* send flow control to iamthif client */ - mei_send_flow_control(dev, &dev->iamthif_cl); - } - /* free all allocated buffers */ - mei_free_cb_private(cb_pos); - cb_pos = NULL; - removed = true; - } - } - return removed; -} - -/** - * mei_clear_lists - removes all callbacks associated with file - * - * @dev: device structure - * @file: file structure - * - * mei_clear_lists is called to clear resources associated with file - * when application calls close function or Ctrl-C was pressed - * - * returns true if callback removed from the list, false otherwise - */ -static bool mei_clear_lists(struct mei_device *dev, struct file *file) -{ - bool removed = false; - - /* remove callbacks associated with a file */ - mei_clear_list(dev, file, &dev->amthi_cmd_list.mei_cb.cb_list); - if (mei_clear_list(dev, file, - &dev->amthi_read_complete_list.mei_cb.cb_list)) - removed = true; - - mei_clear_list(dev, file, &dev->ctrl_rd_list.mei_cb.cb_list); - - if (mei_clear_list(dev, file, &dev->ctrl_wr_list.mei_cb.cb_list)) - removed = true; - - if (mei_clear_list(dev, file, &dev->write_waiting_list.mei_cb.cb_list)) - removed = true; - - if (mei_clear_list(dev, file, &dev->write_list.mei_cb.cb_list)) - removed = true; - - /* check if iamthif_current_cb not NULL */ - if (dev->iamthif_current_cb && !removed) { - /* check file and iamthif current cb association */ - if (dev->iamthif_current_cb->file_object == file) { - /* remove cb */ - mei_free_cb_private(dev->iamthif_current_cb); - dev->iamthif_current_cb = NULL; - removed = true; - } - } - return removed; -} -/** - * find_read_list_entry - find read list entry - * - * @dev: device structure - * @file: pointer to file structure - * - * returns cb on success, NULL on error - */ -static struct mei_cl_cb *find_read_list_entry( - struct mei_device *dev, - struct mei_cl *cl) -{ - struct mei_cl_cb *pos = NULL; - struct mei_cl_cb *next = NULL; - - dev_dbg(&dev->pdev->dev, "remove read_list CB\n"); - list_for_each_entry_safe(pos, next, - &dev->read_list.mei_cb.cb_list, cb_list) { - struct mei_cl *cl_temp; - cl_temp = (struct mei_cl *)pos->file_private; - - if (mei_cl_cmp_id(cl, cl_temp)) - return pos; - } - return NULL; -} - -/** - * mei_open - the open function - * - * @inode: pointer to inode structure - * @file: pointer to file structure - * - * returns 0 on success, <0 on error - */ -static int mei_open(struct inode *inode, struct file *file) -{ - struct mei_cl *cl; - struct mei_device *dev; - unsigned long cl_id; - int err; - - err = -ENODEV; - if (!mei_device) - goto out; - - dev = pci_get_drvdata(mei_device); - if (!dev) - goto out; - - mutex_lock(&dev->device_lock); - err = -ENOMEM; - cl = mei_cl_allocate(dev); - if (!cl) - goto out_unlock; - - err = -ENODEV; - if (dev->mei_state != MEI_ENABLED) { - dev_dbg(&dev->pdev->dev, "mei_state != MEI_ENABLED mei_state= %d\n", - dev->mei_state); - goto out_unlock; - } - err = -EMFILE; - if (dev->open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) - goto out_unlock; - - cl_id = find_first_zero_bit(dev->host_clients_map, MEI_CLIENTS_MAX); - if (cl_id >= MEI_CLIENTS_MAX) - goto out_unlock; - - cl->host_client_id = cl_id; - - dev_dbg(&dev->pdev->dev, "client_id = %d\n", cl->host_client_id); - - dev->open_handle_count++; - - list_add_tail(&cl->link, &dev->file_list); - - set_bit(cl->host_client_id, dev->host_clients_map); - cl->state = MEI_FILE_INITIALIZING; - cl->sm_state = 0; - - file->private_data = cl; - mutex_unlock(&dev->device_lock); - - return nonseekable_open(inode, file); - -out_unlock: - mutex_unlock(&dev->device_lock); - kfree(cl); -out: - return err; -} - -/** - * mei_release - the release function - * - * @inode: pointer to inode structure - * @file: pointer to file structure - * - * returns 0 on success, <0 on error - */ -static int mei_release(struct inode *inode, struct file *file) -{ - struct mei_cl *cl = file->private_data; - struct mei_cl_cb *cb; - struct mei_device *dev; - int rets = 0; - - if (WARN_ON(!cl || !cl->dev)) - return -ENODEV; - - dev = cl->dev; - - mutex_lock(&dev->device_lock); - if (cl != &dev->iamthif_cl) { - if (cl->state == MEI_FILE_CONNECTED) { - cl->state = MEI_FILE_DISCONNECTING; - dev_dbg(&dev->pdev->dev, - "disconnecting client host client = %d, " - "ME client = %d\n", - cl->host_client_id, - cl->me_client_id); - rets = mei_disconnect_host_client(dev, cl); - } - mei_cl_flush_queues(cl); - dev_dbg(&dev->pdev->dev, "remove client host client = %d, ME client = %d\n", - cl->host_client_id, - cl->me_client_id); - - if (dev->open_handle_count > 0) { - clear_bit(cl->host_client_id, dev->host_clients_map); - dev->open_handle_count--; - } - mei_remove_client_from_file_list(dev, cl->host_client_id); - - /* free read cb */ - cb = NULL; - if (cl->read_cb) { - cb = find_read_list_entry(dev, cl); - /* Remove entry from read list */ - if (cb) - list_del(&cb->cb_list); - - cb = cl->read_cb; - cl->read_cb = NULL; - } - - file->private_data = NULL; - - if (cb) { - mei_free_cb_private(cb); - cb = NULL; - } - - kfree(cl); - } else { - if (dev->open_handle_count > 0) - dev->open_handle_count--; - - if (dev->iamthif_file_object == file && - dev->iamthif_state != MEI_IAMTHIF_IDLE) { - - dev_dbg(&dev->pdev->dev, "amthi canceled iamthif state %d\n", - dev->iamthif_state); - dev->iamthif_canceled = true; - if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) { - dev_dbg(&dev->pdev->dev, "run next amthi iamthif cb\n"); - mei_run_next_iamthif_cmd(dev); - } - } - - if (mei_clear_lists(dev, file)) - dev->iamthif_state = MEI_IAMTHIF_IDLE; - - } - mutex_unlock(&dev->device_lock); - return rets; -} - - -/** - * mei_read - the read function. - * - * @file: pointer to file structure - * @ubuf: pointer to user buffer - * @length: buffer length - * @offset: data offset in buffer - * - * returns >=0 data length on success , <0 on error - */ -static ssize_t mei_read(struct file *file, char __user *ubuf, - size_t length, loff_t *offset) -{ - struct mei_cl *cl = file->private_data; - struct mei_cl_cb *cb_pos = NULL; - struct mei_cl_cb *cb = NULL; - struct mei_device *dev; - int i; - int rets; - int err; - - - if (WARN_ON(!cl || !cl->dev)) - return -ENODEV; - - dev = cl->dev; - - mutex_lock(&dev->device_lock); - if (dev->mei_state != MEI_ENABLED) { - rets = -ENODEV; - goto out; - } - - if ((cl->sm_state & MEI_WD_STATE_INDEPENDENCE_MSG_SENT) == 0) { - /* Do not allow to read watchdog client */ - i = mei_find_me_client_index(dev, mei_wd_guid); - if (i >= 0) { - struct mei_me_client *me_client = &dev->me_clients[i]; - - if (cl->me_client_id == me_client->client_id) { - rets = -EBADF; - goto out; - } - } - } else { - cl->sm_state &= ~MEI_WD_STATE_INDEPENDENCE_MSG_SENT; - } - - if (cl == &dev->iamthif_cl) { - rets = amthi_read(dev, file, ubuf, length, offset); - goto out; - } - - if (cl->read_cb && cl->read_cb->information > *offset) { - cb = cl->read_cb; - goto copy_buffer; - } else if (cl->read_cb && cl->read_cb->information > 0 && - cl->read_cb->information <= *offset) { - cb = cl->read_cb; - rets = 0; - goto free; - } else if ((!cl->read_cb || !cl->read_cb->information) && - *offset > 0) { - /*Offset needs to be cleaned for contiguous reads*/ - *offset = 0; - rets = 0; - goto out; - } - - err = mei_start_read(dev, cl); - if (err && err != -EBUSY) { - dev_dbg(&dev->pdev->dev, - "mei start read failure with status = %d\n", err); - rets = err; - goto out; - } - - if (MEI_READ_COMPLETE != cl->reading_state && - !waitqueue_active(&cl->rx_wait)) { - if (file->f_flags & O_NONBLOCK) { - rets = -EAGAIN; - goto out; - } - - mutex_unlock(&dev->device_lock); - - if (wait_event_interruptible(cl->rx_wait, - (MEI_READ_COMPLETE == cl->reading_state || - MEI_FILE_INITIALIZING == cl->state || - MEI_FILE_DISCONNECTED == cl->state || - MEI_FILE_DISCONNECTING == cl->state))) { - if (signal_pending(current)) - return -EINTR; - return -ERESTARTSYS; - } - - mutex_lock(&dev->device_lock); - if (MEI_FILE_INITIALIZING == cl->state || - MEI_FILE_DISCONNECTED == cl->state || - MEI_FILE_DISCONNECTING == cl->state) { - rets = -EBUSY; - goto out; - } - } - - cb = cl->read_cb; - - if (!cb) { - rets = -ENODEV; - goto out; - } - if (cl->reading_state != MEI_READ_COMPLETE) { - rets = 0; - goto out; - } - /* now copy the data to user space */ -copy_buffer: - dev_dbg(&dev->pdev->dev, "cb->response_buffer size - %d\n", - cb->response_buffer.size); - dev_dbg(&dev->pdev->dev, "cb->information - %lu\n", - cb->information); - if (length == 0 || ubuf == NULL || *offset > cb->information) { - rets = -EMSGSIZE; - goto free; - } - - /* length is being truncated to PAGE_SIZE, however, */ - /* information size may be longer */ - length = min_t(size_t, length, (cb->information - *offset)); - - if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) { - rets = -EFAULT; - goto free; - } - - rets = length; - *offset += length; - if ((unsigned long)*offset < cb->information) - goto out; - -free: - cb_pos = find_read_list_entry(dev, cl); - /* Remove entry from read list */ - if (cb_pos) - list_del(&cb_pos->cb_list); - mei_free_cb_private(cb); - cl->reading_state = MEI_IDLE; - cl->read_cb = NULL; - cl->read_pending = 0; -out: - dev_dbg(&dev->pdev->dev, "end mei read rets= %d\n", rets); - mutex_unlock(&dev->device_lock); - return rets; -} - -/** - * mei_write - the write function. - * - * @file: pointer to file structure - * @ubuf: pointer to user buffer - * @length: buffer length - * @offset: data offset in buffer - * - * returns >=0 data length on success , <0 on error - */ -static ssize_t mei_write(struct file *file, const char __user *ubuf, - size_t length, loff_t *offset) -{ - struct mei_cl *cl = file->private_data; - struct mei_cl_cb *write_cb = NULL; - struct mei_msg_hdr mei_hdr; - struct mei_device *dev; - unsigned long timeout = 0; - int rets; - int i; - - if (WARN_ON(!cl || !cl->dev)) - return -ENODEV; - - dev = cl->dev; - - mutex_lock(&dev->device_lock); - - if (dev->mei_state != MEI_ENABLED) { - mutex_unlock(&dev->device_lock); - return -ENODEV; - } - - if (cl == &dev->iamthif_cl) { - write_cb = find_amthi_read_list_entry(dev, file); - - if (write_cb) { - timeout = write_cb->read_time + - msecs_to_jiffies(IAMTHIF_READ_TIMER); - - if (time_after(jiffies, timeout) || - cl->reading_state == MEI_READ_COMPLETE) { - *offset = 0; - list_del(&write_cb->cb_list); - mei_free_cb_private(write_cb); - write_cb = NULL; - } - } - } - - /* free entry used in read */ - if (cl->reading_state == MEI_READ_COMPLETE) { - *offset = 0; - write_cb = find_read_list_entry(dev, cl); - if (write_cb) { - list_del(&write_cb->cb_list); - mei_free_cb_private(write_cb); - write_cb = NULL; - cl->reading_state = MEI_IDLE; - cl->read_cb = NULL; - cl->read_pending = 0; - } - } else if (cl->reading_state == MEI_IDLE && !cl->read_pending) - *offset = 0; - - - write_cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); - if (!write_cb) { - mutex_unlock(&dev->device_lock); - return -ENOMEM; - } - - write_cb->file_object = file; - write_cb->file_private = cl; - write_cb->request_buffer.data = kmalloc(length, GFP_KERNEL); - rets = -ENOMEM; - if (!write_cb->request_buffer.data) - goto unlock_dev; - - dev_dbg(&dev->pdev->dev, "length =%d\n", (int) length); - - rets = -EFAULT; - if (copy_from_user(write_cb->request_buffer.data, ubuf, length)) - goto unlock_dev; - - cl->sm_state = 0; - if (length == 4 && - ((memcmp(mei_wd_state_independence_msg[0], - write_cb->request_buffer.data, 4) == 0) || - (memcmp(mei_wd_state_independence_msg[1], - write_cb->request_buffer.data, 4) == 0) || - (memcmp(mei_wd_state_independence_msg[2], - write_cb->request_buffer.data, 4) == 0))) - cl->sm_state |= MEI_WD_STATE_INDEPENDENCE_MSG_SENT; - - INIT_LIST_HEAD(&write_cb->cb_list); - if (cl == &dev->iamthif_cl) { - write_cb->response_buffer.data = - kmalloc(dev->iamthif_mtu, GFP_KERNEL); - if (!write_cb->response_buffer.data) { - rets = -ENOMEM; - goto unlock_dev; - } - if (dev->mei_state != MEI_ENABLED) { - rets = -ENODEV; - goto unlock_dev; - } - for (i = 0; i < dev->me_clients_num; i++) { - if (dev->me_clients[i].client_id == - dev->iamthif_cl.me_client_id) - break; - } - - if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) { - rets = -ENODEV; - goto unlock_dev; - } - if (i == dev->me_clients_num || - (dev->me_clients[i].client_id != - dev->iamthif_cl.me_client_id)) { - rets = -ENODEV; - goto unlock_dev; - } else if (length > dev->me_clients[i].props.max_msg_length || - length <= 0) { - rets = -EMSGSIZE; - goto unlock_dev; - } - - write_cb->response_buffer.size = dev->iamthif_mtu; - write_cb->major_file_operations = MEI_IOCTL; - write_cb->information = 0; - write_cb->request_buffer.size = length; - if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) { - rets = -ENODEV; - goto unlock_dev; - } - - if (!list_empty(&dev->amthi_cmd_list.mei_cb.cb_list) || - dev->iamthif_state != MEI_IAMTHIF_IDLE) { - dev_dbg(&dev->pdev->dev, "amthi_state = %d\n", - (int) dev->iamthif_state); - dev_dbg(&dev->pdev->dev, "add amthi cb to amthi cmd waiting list\n"); - list_add_tail(&write_cb->cb_list, - &dev->amthi_cmd_list.mei_cb.cb_list); - rets = length; - } else { - dev_dbg(&dev->pdev->dev, "call amthi write\n"); - rets = amthi_write(dev, write_cb); - - if (rets) { - dev_dbg(&dev->pdev->dev, "amthi write failed with status = %d\n", - rets); - goto unlock_dev; - } - rets = length; - } - mutex_unlock(&dev->device_lock); - return rets; - } - - write_cb->major_file_operations = MEI_WRITE; - /* make sure information is zero before we start */ - - write_cb->information = 0; - write_cb->request_buffer.size = length; - - dev_dbg(&dev->pdev->dev, "host client = %d, ME client = %d\n", - cl->host_client_id, cl->me_client_id); - if (cl->state != MEI_FILE_CONNECTED) { - rets = -ENODEV; - dev_dbg(&dev->pdev->dev, "host client = %d, is not connected to ME client = %d", - cl->host_client_id, - cl->me_client_id); - goto unlock_dev; - } - for (i = 0; i < dev->me_clients_num; i++) { - if (dev->me_clients[i].client_id == - cl->me_client_id) - break; - } - if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) { - rets = -ENODEV; - goto unlock_dev; - } - if (i == dev->me_clients_num) { - rets = -ENODEV; - goto unlock_dev; - } - if (length > dev->me_clients[i].props.max_msg_length || length <= 0) { - rets = -EINVAL; - goto unlock_dev; - } - write_cb->file_private = cl; - - rets = mei_flow_ctrl_creds(dev, cl); - if (rets < 0) - goto unlock_dev; - - if (rets && dev->mei_host_buffer_is_empty) { - rets = 0; - dev->mei_host_buffer_is_empty = false; - if (length > ((((dev->host_hw_state & H_CBD) >> 24) * - sizeof(u32)) - sizeof(struct mei_msg_hdr))) { - - mei_hdr.length = - (((dev->host_hw_state & H_CBD) >> 24) * - sizeof(u32)) - - sizeof(struct mei_msg_hdr); - mei_hdr.msg_complete = 0; - } else { - mei_hdr.length = length; - mei_hdr.msg_complete = 1; - } - mei_hdr.host_addr = cl->host_client_id; - mei_hdr.me_addr = cl->me_client_id; - mei_hdr.reserved = 0; - dev_dbg(&dev->pdev->dev, "call mei_write_message header=%08x.\n", - *((u32 *) &mei_hdr)); - if (mei_write_message(dev, &mei_hdr, - (unsigned char *) (write_cb->request_buffer.data), - mei_hdr.length)) { - rets = -ENODEV; - goto unlock_dev; - } - cl->writing_state = MEI_WRITING; - write_cb->information = mei_hdr.length; - if (mei_hdr.msg_complete) { - if (mei_flow_ctrl_reduce(dev, cl)) { - rets = -ENODEV; - goto unlock_dev; - } - list_add_tail(&write_cb->cb_list, - &dev->write_waiting_list.mei_cb.cb_list); - } else { - list_add_tail(&write_cb->cb_list, - &dev->write_list.mei_cb.cb_list); - } - - } else { - - write_cb->information = 0; - cl->writing_state = MEI_WRITING; - list_add_tail(&write_cb->cb_list, - &dev->write_list.mei_cb.cb_list); - } - mutex_unlock(&dev->device_lock); - return length; - -unlock_dev: - mutex_unlock(&dev->device_lock); - mei_free_cb_private(write_cb); - return rets; -} - - -/** - * mei_ioctl - the IOCTL function - * - * @file: pointer to file structure - * @cmd: ioctl command - * @data: pointer to mei message structure - * - * returns 0 on success , <0 on error - */ -static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data) -{ - struct mei_device *dev; - struct mei_cl *cl = file->private_data; - struct mei_connect_client_data *connect_data = NULL; - int rets; - - if (cmd != IOCTL_MEI_CONNECT_CLIENT) - return -EINVAL; - - if (WARN_ON(!cl || !cl->dev)) - return -ENODEV; - - dev = cl->dev; - - dev_dbg(&dev->pdev->dev, "IOCTL cmd = 0x%x", cmd); - - mutex_lock(&dev->device_lock); - if (dev->mei_state != MEI_ENABLED) { - rets = -ENODEV; - goto out; - } - - dev_dbg(&dev->pdev->dev, ": IOCTL_MEI_CONNECT_CLIENT.\n"); - - connect_data = kzalloc(sizeof(struct mei_connect_client_data), - GFP_KERNEL); - if (!connect_data) { - rets = -ENOMEM; - goto out; - } - dev_dbg(&dev->pdev->dev, "copy connect data from user\n"); - if (copy_from_user(connect_data, (char __user *)data, - sizeof(struct mei_connect_client_data))) { - dev_dbg(&dev->pdev->dev, "failed to copy data from userland\n"); - rets = -EFAULT; - goto out; - } - rets = mei_ioctl_connect_client(file, connect_data); - - /* if all is ok, copying the data back to user. */ - if (rets) - goto out; - - dev_dbg(&dev->pdev->dev, "copy connect data to user\n"); - if (copy_to_user((char __user *)data, connect_data, - sizeof(struct mei_connect_client_data))) { - dev_dbg(&dev->pdev->dev, "failed to copy data to userland\n"); - rets = -EFAULT; - goto out; - } - -out: - kfree(connect_data); - mutex_unlock(&dev->device_lock); - return rets; -} - -/** - * mei_compat_ioctl - the compat IOCTL function - * - * @file: pointer to file structure - * @cmd: ioctl command - * @data: pointer to mei message structure - * - * returns 0 on success , <0 on error - */ -#ifdef CONFIG_COMPAT -static long mei_compat_ioctl(struct file *file, - unsigned int cmd, unsigned long data) -{ - return mei_ioctl(file, cmd, (unsigned long)compat_ptr(data)); -} -#endif - - -/** - * mei_poll - the poll function - * - * @file: pointer to file structure - * @wait: pointer to poll_table structure - * - * returns poll mask - */ -static unsigned int mei_poll(struct file *file, poll_table *wait) -{ - struct mei_cl *cl = file->private_data; - struct mei_device *dev; - unsigned int mask = 0; - - if (WARN_ON(!cl || !cl->dev)) - return mask; - - dev = cl->dev; - - mutex_lock(&dev->device_lock); - - if (dev->mei_state != MEI_ENABLED) - goto out; - - - if (cl == &dev->iamthif_cl) { - mutex_unlock(&dev->device_lock); - poll_wait(file, &dev->iamthif_cl.wait, wait); - mutex_lock(&dev->device_lock); - if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE && - dev->iamthif_file_object == file) { - mask |= (POLLIN | POLLRDNORM); - dev_dbg(&dev->pdev->dev, "run next amthi cb\n"); - mei_run_next_iamthif_cmd(dev); - } - goto out; - } - - mutex_unlock(&dev->device_lock); - poll_wait(file, &cl->tx_wait, wait); - mutex_lock(&dev->device_lock); - if (MEI_WRITE_COMPLETE == cl->writing_state) - mask |= (POLLIN | POLLRDNORM); - -out: - mutex_unlock(&dev->device_lock); - return mask; -} - -/* - * file operations structure will be used for mei char device. - */ -static const struct file_operations mei_fops = { - .owner = THIS_MODULE, - .read = mei_read, - .unlocked_ioctl = mei_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = mei_compat_ioctl, -#endif - .open = mei_open, - .release = mei_release, - .write = mei_write, - .poll = mei_poll, - .llseek = no_llseek -}; - - -/* - * Misc Device Struct - */ -static struct miscdevice mei_misc_device = { - .name = MEI_DRIVER_NAME, - .fops = &mei_fops, - .minor = MISC_DYNAMIC_MINOR, -}; - -/** - * mei_probe - Device Initialization Routine - * - * @pdev: PCI device structure - * @ent: entry in kcs_pci_tbl - * - * returns 0 on success, <0 on failure. - */ -static int __devinit mei_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct mei_device *dev; - int err; - - mutex_lock(&mei_mutex); - if (mei_device) { - err = -EEXIST; - goto end; - } - /* enable pci dev */ - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR "mei: Failed to enable pci device.\n"); - goto end; - } - /* set PCI host mastering */ - pci_set_master(pdev); - /* pci request regions for mei driver */ - err = pci_request_regions(pdev, mei_driver_name); - if (err) { - printk(KERN_ERR "mei: Failed to get pci regions.\n"); - goto disable_device; - } - /* allocates and initializes the mei dev structure */ - dev = mei_device_init(pdev); - if (!dev) { - err = -ENOMEM; - goto release_regions; - } - /* mapping IO device memory */ - dev->mem_addr = pci_iomap(pdev, 0, 0); - if (!dev->mem_addr) { - printk(KERN_ERR "mei: mapping I/O device memory failure.\n"); - err = -ENOMEM; - goto free_device; - } - pci_enable_msi(pdev); - - /* request and enable interrupt */ - if (pci_dev_msi_enabled(pdev)) - err = request_threaded_irq(pdev->irq, - NULL, - mei_interrupt_thread_handler, - 0, mei_driver_name, dev); - else - err = request_threaded_irq(pdev->irq, - mei_interrupt_quick_handler, - mei_interrupt_thread_handler, - IRQF_SHARED, mei_driver_name, dev); - - if (err) { - printk(KERN_ERR "mei: request_threaded_irq failure. irq = %d\n", - pdev->irq); - goto unmap_memory; - } - INIT_DELAYED_WORK(&dev->timer_work, mei_timer); - if (mei_hw_init(dev)) { - printk(KERN_ERR "mei: Init hw failure.\n"); - err = -ENODEV; - goto release_irq; - } - - err = misc_register(&mei_misc_device); - if (err) - goto release_irq; - - mei_device = pdev; - pci_set_drvdata(pdev, dev); - - - schedule_delayed_work(&dev->timer_work, HZ); - - mutex_unlock(&mei_mutex); - - pr_debug("mei: Driver initialization successful.\n"); - - return 0; - -release_irq: - /* disable interrupts */ - dev->host_hw_state = mei_hcsr_read(dev); - mei_disable_interrupts(dev); - flush_scheduled_work(); - free_irq(pdev->irq, dev); - pci_disable_msi(pdev); -unmap_memory: - pci_iounmap(pdev, dev->mem_addr); -free_device: - kfree(dev); -release_regions: - pci_release_regions(pdev); -disable_device: - pci_disable_device(pdev); -end: - mutex_unlock(&mei_mutex); - printk(KERN_ERR "mei: Driver initialization failed.\n"); - return err; -} - -/** - * mei_remove - Device Removal Routine - * - * @pdev: PCI device structure - * - * mei_remove is called by the PCI subsystem to alert the driver - * that it should release a PCI device. - */ -static void __devexit mei_remove(struct pci_dev *pdev) -{ - struct mei_device *dev; - - if (mei_device != pdev) - return; - - dev = pci_get_drvdata(pdev); - if (!dev) - return; - - mutex_lock(&dev->device_lock); - - mei_wd_stop(dev, false); - - mei_device = NULL; - - if (dev->iamthif_cl.state == MEI_FILE_CONNECTED) { - dev->iamthif_cl.state = MEI_FILE_DISCONNECTING; - mei_disconnect_host_client(dev, &dev->iamthif_cl); - } - if (dev->wd_cl.state == MEI_FILE_CONNECTED) { - dev->wd_cl.state = MEI_FILE_DISCONNECTING; - mei_disconnect_host_client(dev, &dev->wd_cl); - } - - /* Unregistering watchdog device */ - mei_watchdog_unregister(dev); - - /* remove entry if already in list */ - dev_dbg(&pdev->dev, "list del iamthif and wd file list.\n"); - mei_remove_client_from_file_list(dev, dev->wd_cl.host_client_id); - mei_remove_client_from_file_list(dev, dev->iamthif_cl.host_client_id); - - dev->iamthif_current_cb = NULL; - dev->me_clients_num = 0; - - mutex_unlock(&dev->device_lock); - - flush_scheduled_work(); - - /* disable interrupts */ - mei_disable_interrupts(dev); - - free_irq(pdev->irq, dev); - pci_disable_msi(pdev); - pci_set_drvdata(pdev, NULL); - - if (dev->mem_addr) - pci_iounmap(pdev, dev->mem_addr); - - kfree(dev); - - pci_release_regions(pdev); - pci_disable_device(pdev); -} -#ifdef CONFIG_PM -static int mei_pci_suspend(struct device *device) -{ - struct pci_dev *pdev = to_pci_dev(device); - struct mei_device *dev = pci_get_drvdata(pdev); - int err; - - if (!dev) - return -ENODEV; - mutex_lock(&dev->device_lock); - /* Stop watchdog if exists */ - err = mei_wd_stop(dev, true); - /* Set new mei state */ - if (dev->mei_state == MEI_ENABLED || - dev->mei_state == MEI_RECOVERING_FROM_RESET) { - dev->mei_state = MEI_POWER_DOWN; - mei_reset(dev, 0); - } - mutex_unlock(&dev->device_lock); - - free_irq(pdev->irq, dev); - pci_disable_msi(pdev); - - return err; -} - -static int mei_pci_resume(struct device *device) -{ - struct pci_dev *pdev = to_pci_dev(device); - struct mei_device *dev; - int err; - - dev = pci_get_drvdata(pdev); - if (!dev) - return -ENODEV; - - pci_enable_msi(pdev); - - /* request and enable interrupt */ - if (pci_dev_msi_enabled(pdev)) - err = request_threaded_irq(pdev->irq, - NULL, - mei_interrupt_thread_handler, - 0, mei_driver_name, dev); - else - err = request_threaded_irq(pdev->irq, - mei_interrupt_quick_handler, - mei_interrupt_thread_handler, - IRQF_SHARED, mei_driver_name, dev); - - if (err) { - printk(KERN_ERR "mei: Request_irq failure. irq = %d\n", - pdev->irq); - return err; - } - - mutex_lock(&dev->device_lock); - dev->mei_state = MEI_POWER_UP; - mei_reset(dev, 1); - mutex_unlock(&dev->device_lock); - - /* Start timer if stopped in suspend */ - schedule_delayed_work(&dev->timer_work, HZ); - - return err; -} -static SIMPLE_DEV_PM_OPS(mei_pm_ops, mei_pci_suspend, mei_pci_resume); -#define MEI_PM_OPS (&mei_pm_ops) -#else -#define MEI_PM_OPS NULL -#endif /* CONFIG_PM */ -/* - * PCI driver structure - */ -static struct pci_driver mei_driver = { - .name = mei_driver_name, - .id_table = mei_pci_tbl, - .probe = mei_probe, - .remove = __devexit_p(mei_remove), - .shutdown = __devexit_p(mei_remove), - .driver.pm = MEI_PM_OPS, -}; - -/** - * mei_init_module - Driver Registration Routine - * - * mei_init_module is the first routine called when the driver is - * loaded. All it does is to register with the PCI subsystem. - * - * returns 0 on success, <0 on failure. - */ -static int __init mei_init_module(void) -{ - int ret; - - pr_debug("mei: %s\n", mei_driver_string); - /* init pci module */ - ret = pci_register_driver(&mei_driver); - if (ret < 0) - printk(KERN_ERR "mei: Error registering driver.\n"); - - return ret; -} - -module_init(mei_init_module); - -/** - * mei_exit_module - Driver Exit Cleanup Routine - * - * mei_exit_module is called just before the driver is removed - * from memory. - */ -static void __exit mei_exit_module(void) -{ - misc_deregister(&mei_misc_device); - pci_unregister_driver(&mei_driver); - - pr_debug("mei: Driver unloaded successfully.\n"); -} - -module_exit(mei_exit_module); - - -MODULE_AUTHOR("Intel Corporation"); -MODULE_DESCRIPTION("Intel(R) Management Engine Interface"); -MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/staging/net/Kconfig b/trunk/drivers/staging/net/Kconfig new file mode 100644 index 000000000000..a64e56b1898a --- /dev/null +++ b/trunk/drivers/staging/net/Kconfig @@ -0,0 +1,38 @@ +if NETDEVICES + +if WAN + +config PC300 + tristate "Cyclades-PC300 support (RS-232/V.35, X.21, T1/E1 boards)" + depends on HDLC && PCI && BROKEN + ---help--- + This driver is broken because of struct tty_driver change. + + Driver for the Cyclades-PC300 synchronous communication boards. + + These boards provide synchronous serial interfaces to your + Linux box (interfaces currently available are RS-232/V.35, X.21 and + T1/E1). If you wish to support Multilink PPP, please select the + option later and read the file README.mlppp provided by PC300 + package. + + To compile this as a module, choose M here: the module + will be called pc300. + + If unsure, say N. + +config PC300_MLPPP + bool "Cyclades-PC300 MLPPP support" + depends on PC300 && PPP_MULTILINK && PPP_SYNC_TTY && HDLC_PPP + help + Multilink PPP over the PC300 synchronous communication boards. + +comment "Cyclades-PC300 MLPPP support is disabled." + depends on HDLC && PC300 && (PPP=n || !PPP_MULTILINK || PPP_SYNC_TTY=n || !HDLC_PPP) + +comment "Refer to the file README.mlppp, provided by PC300 package." + depends on HDLC && PC300 && (PPP=n || !PPP_MULTILINK || PPP_SYNC_TTY=n || !HDLC_PPP) + +endif # WAN + +endif # NETDEVICES diff --git a/trunk/drivers/staging/net/Makefile b/trunk/drivers/staging/net/Makefile new file mode 100644 index 000000000000..0799c43d5114 --- /dev/null +++ b/trunk/drivers/staging/net/Makefile @@ -0,0 +1,5 @@ +pc300-y := pc300_drv.o +pc300-$(CONFIG_PC300_MLPPP) += pc300_tty.o +pc300-objs := $(pc300-y) + +obj-$(CONFIG_PC300) += pc300.o diff --git a/trunk/drivers/staging/net/TODO b/trunk/drivers/staging/net/TODO new file mode 100644 index 000000000000..e3446f2ad7c7 --- /dev/null +++ b/trunk/drivers/staging/net/TODO @@ -0,0 +1,5 @@ +PC300 +The driver is very broken and cannot work with the current TTY layer. It is +inevitable to convert it to the new TTY API. + +If no one steps in to adopt the driver, it will be removed in the 3.7 release. diff --git a/trunk/drivers/net/wan/pc300-falc-lh.h b/trunk/drivers/staging/net/pc300-falc-lh.h similarity index 100% rename from trunk/drivers/net/wan/pc300-falc-lh.h rename to trunk/drivers/staging/net/pc300-falc-lh.h diff --git a/trunk/drivers/net/wan/pc300.h b/trunk/drivers/staging/net/pc300.h similarity index 100% rename from trunk/drivers/net/wan/pc300.h rename to trunk/drivers/staging/net/pc300.h diff --git a/trunk/drivers/net/wan/pc300_drv.c b/trunk/drivers/staging/net/pc300_drv.c similarity index 100% rename from trunk/drivers/net/wan/pc300_drv.c rename to trunk/drivers/staging/net/pc300_drv.c diff --git a/trunk/drivers/net/wan/pc300_tty.c b/trunk/drivers/staging/net/pc300_tty.c similarity index 100% rename from trunk/drivers/net/wan/pc300_tty.c rename to trunk/drivers/staging/net/pc300_tty.c diff --git a/trunk/drivers/staging/nvec/nvec.h b/trunk/drivers/staging/nvec/nvec.h index a4c17b0e10cf..ba6ed8f4e8a3 100644 --- a/trunk/drivers/staging/nvec/nvec.h +++ b/trunk/drivers/staging/nvec/nvec.h @@ -42,7 +42,7 @@ * enum nvec_event_size - The size of an event message * @NVEC_2BYTES: The message has one command byte and one data byte * @NVEC_3BYTES: The message has one command byte and two data bytes - * @NVEC_VAR_SIZE: The message has one command byte, one count byte, and as + * @NVEC_VAR_SIZE: The message has one command byte, one count byte, and has * up to as many bytes as the number in the count byte. The * maximum is 32 * diff --git a/trunk/drivers/staging/octeon/ethernet-rx.c b/trunk/drivers/staging/octeon/ethernet-rx.c index d91751f9ffe8..34afc16bc493 100644 --- a/trunk/drivers/staging/octeon/ethernet-rx.c +++ b/trunk/drivers/staging/octeon/ethernet-rx.c @@ -163,7 +163,7 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) /* * We received a packet with either an alignment error * or a FCS error. This may be signalling that we are - * running 10Mbps with GMXX_RXX_FRM_CTL[PRE_CHK} + * running 10Mbps with GMXX_RXX_FRM_CTL[PRE_CHK] * off. If this is the case we need to parse the * packet to determine if we can remove a non spec * preamble and generate a correct packet. diff --git a/trunk/drivers/staging/octeon/ethernet-tx.c b/trunk/drivers/staging/octeon/ethernet-tx.c index 91a97b3e45c6..5631dd9f8201 100644 --- a/trunk/drivers/staging/octeon/ethernet-tx.c +++ b/trunk/drivers/staging/octeon/ethernet-tx.c @@ -62,7 +62,7 @@ * You can define GET_SKBUFF_QOS() to override how the skbuff output * function determines which output queue is used. The default * implementation always uses the base queue for the port. If, for - * example, you wanted to use the skb->priority fieid, define + * example, you wanted to use the skb->priority field, define * GET_SKBUFF_QOS as: #define GET_SKBUFF_QOS(skb) ((skb)->priority) */ #ifndef GET_SKBUFF_QOS @@ -165,8 +165,8 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev) #endif /* - * Prefetch the private data structure. It is larger that one - * cache line. + * Prefetch the private data structure. It is larger than the + * one cache line. */ prefetch(priv); @@ -291,8 +291,8 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev) * See if we can put this skb in the FPA pool. Any strange * behavior from the Linux networking stack will most likely * be caused by a bug in the following code. If some field is - * in use by the network stack and get carried over when a - * buffer is reused, bad thing may happen. If in doubt and + * in use by the network stack and gets carried over when a + * buffer is reused, bad things may happen. If in doubt and * you dont need the absolute best performance, disable the * define REUSE_SKBUFFS_WITHOUT_FREE. The reuse of buffers has * shown a 25% increase in performance under some loads. @@ -345,7 +345,7 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev) } if (unlikely (skb->truesize != - sizeof(*skb) + skb_end_pointer(skb) - skb->head)) { + sizeof(*skb) + skb_end_offset(skb))) { /* printk("TX buffer truesize has been changed\n"); */ diff --git a/trunk/drivers/staging/octeon/ethernet-util.h b/trunk/drivers/staging/octeon/ethernet-util.h index 144fb99bf50c..2da5ce17ead0 100644 --- a/trunk/drivers/staging/octeon/ethernet-util.h +++ b/trunk/drivers/staging/octeon/ethernet-util.h @@ -38,7 +38,7 @@ static inline void *cvm_oct_get_buffer_ptr(union cvmx_buf_ptr packet_ptr) } /** - * INTERFACE - convert IPD port to locgical interface + * INTERFACE - convert IPD port to logical interface * @ipd_port: Port to check * * Returns Logical interface diff --git a/trunk/drivers/staging/octeon/ethernet.c b/trunk/drivers/staging/octeon/ethernet.c index 60cba8194de3..18f7a790f73d 100644 --- a/trunk/drivers/staging/octeon/ethernet.c +++ b/trunk/drivers/staging/octeon/ethernet.c @@ -357,7 +357,7 @@ static void cvm_oct_common_set_multicast_list(struct net_device *dev) /* Force accept multicast packets */ control.s.mcst = 2; else - /* Force reject multicat packets */ + /* Force reject multicast packets */ control.s.mcst = 1; if (dev->flags & IFF_PROMISC) diff --git a/trunk/drivers/staging/olpc_dcon/olpc_dcon.c b/trunk/drivers/staging/olpc_dcon/olpc_dcon.c index 3d9199320d86..992275c0d87c 100644 --- a/trunk/drivers/staging/olpc_dcon/olpc_dcon.c +++ b/trunk/drivers/staging/olpc_dcon/olpc_dcon.c @@ -71,8 +71,8 @@ static int dcon_hw_init(struct dcon_priv *dcon, int is_init) ver = dcon_read(dcon, DCON_REG_ID); if ((ver >> 8) != 0xDC) { - printk(KERN_ERR "olpc-dcon: DCON ID not 0xDCxx: 0x%04x " - "instead.\n", ver); + printk(KERN_ERR "olpc-dcon: DCON ID not 0xDCxx: 0x%04x instead.\n", + ver); rc = -ENXIO; goto err; } @@ -134,10 +134,10 @@ static int dcon_bus_stabilize(struct dcon_priv *dcon, int is_powered_down) power_up: if (is_powered_down) { x = 1; - x = olpc_ec_cmd(0x26, (unsigned char *) &x, 1, NULL, 0); + x = olpc_ec_cmd(0x26, (unsigned char *)&x, 1, NULL, 0); if (x) { - printk(KERN_WARNING "olpc-dcon: unable to force dcon " - "to power up: %d!\n", x); + printk(KERN_WARNING "olpc-dcon: unable to force dcon to power up: %d!\n", + x); return x; } msleep(10); /* we'll be conservative */ @@ -150,11 +150,10 @@ static int dcon_bus_stabilize(struct dcon_priv *dcon, int is_powered_down) x = dcon_read(dcon, DCON_REG_ID); } if (x < 0) { - printk(KERN_ERR "olpc-dcon: unable to stabilize dcon's " - "smbus, reasserting power and praying.\n"); + printk(KERN_ERR "olpc-dcon: unable to stabilize dcon's smbus, reasserting power and praying.\n"); BUG_ON(olpc_board_at_least(olpc_board(0xc2))); x = 0; - olpc_ec_cmd(0x26, (unsigned char *) &x, 1, NULL, 0); + olpc_ec_cmd(0x26, (unsigned char *)&x, 1, NULL, 0); msleep(100); is_powered_down = 1; goto power_up; /* argh, stupid hardware.. */ @@ -220,10 +219,10 @@ static void dcon_sleep(struct dcon_priv *dcon, bool sleep) if (sleep) { x = 0; - x = olpc_ec_cmd(0x26, (unsigned char *) &x, 1, NULL, 0); + x = olpc_ec_cmd(0x26, (unsigned char *)&x, 1, NULL, 0); if (x) - printk(KERN_WARNING "olpc-dcon: unable to force dcon " - "to power down: %d!\n", x); + printk(KERN_WARNING "olpc-dcon: unable to force dcon to power down: %d!\n", + x); else dcon->asleep = sleep; } else { @@ -232,8 +231,8 @@ static void dcon_sleep(struct dcon_priv *dcon, bool sleep) dcon->disp_mode |= MODE_BL_ENABLE; x = dcon_bus_stabilize(dcon, 1); if (x) - printk(KERN_WARNING "olpc-dcon: unable to reinit dcon" - " hardware: %d!\n", x); + printk(KERN_WARNING "olpc-dcon: unable to reinit dcon hardware: %d!\n", + x); else dcon->asleep = sleep; @@ -304,7 +303,7 @@ static void dcon_source_switch(struct work_struct *work) switch (source) { case DCON_SOURCE_CPU: - printk("dcon_source_switch to CPU\n"); + printk(KERN_INFO "dcon_source_switch to CPU\n"); /* Enable the scanline interrupt bit */ if (dcon_write(dcon, DCON_REG_MODE, dcon->disp_mode | MODE_SCAN_INT)) @@ -599,7 +598,7 @@ static int dcon_fb_notifier(struct notifier_block *self, struct fb_event *evdata = data; struct dcon_priv *dcon = container_of(self, struct dcon_priv, fbevent_nb); - int *blank = (int *) evdata->data; + int *blank = (int *)evdata->data; if (((event != FB_EVENT_BLANK) && (event != FB_EVENT_CONBLANK)) || dcon->ignore_fb_events) return 0; diff --git a/trunk/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c b/trunk/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c index cb6ce0cf92a0..c87fdfac4855 100644 --- a/trunk/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c +++ b/trunk/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c @@ -116,7 +116,7 @@ static int dcon_init_xo_1(struct dcon_priv *dcon) cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_NEGATIVE_EDGE_STS); cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_NEGATIVE_EDGE_STS); - /* FIXME: Clear the posiitive status as well, just to be sure */ + /* FIXME: Clear the positive status as well, just to be sure */ cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_POSITIVE_EDGE_STS); cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_POSITIVE_EDGE_STS); diff --git a/trunk/drivers/staging/omapdrm/Makefile b/trunk/drivers/staging/omapdrm/Makefile index d9cdc120d122..1ca0e0016de4 100644 --- a/trunk/drivers/staging/omapdrm/Makefile +++ b/trunk/drivers/staging/omapdrm/Makefile @@ -13,6 +13,7 @@ omapdrm-y := omap_drv.o \ omap_fb.o \ omap_fbdev.o \ omap_gem.o \ + omap_gem_dmabuf.o \ omap_dmm_tiler.o \ tcm-sita.o diff --git a/trunk/drivers/staging/omapdrm/omap_dmm_tiler.c b/trunk/drivers/staging/omapdrm/omap_dmm_tiler.c index 1ecb6a73d790..9d83060e753a 100644 --- a/trunk/drivers/staging/omapdrm/omap_dmm_tiler.c +++ b/trunk/drivers/staging/omapdrm/omap_dmm_tiler.c @@ -347,7 +347,7 @@ struct tiler_block *tiler_reserve_2d(enum tiler_fmt fmt, uint16_t w, ret = tcm_reserve_2d(containers[fmt], w, h, align, &block->area); if (ret) { kfree(block); - return 0; + return ERR_PTR(-ENOMEM); } /* add to allocation list */ @@ -371,7 +371,7 @@ struct tiler_block *tiler_reserve_1d(size_t size) if (tcm_reserve_1d(containers[TILFMT_PAGE], num_pages, &block->area)) { kfree(block); - return 0; + return ERR_PTR(-ENOMEM); } spin_lock(&omap_dmm->list_lock); diff --git a/trunk/drivers/staging/omapdrm/omap_drv.c b/trunk/drivers/staging/omapdrm/omap_drv.c index 620b8d54223d..0d2acca376ca 100644 --- a/trunk/drivers/staging/omapdrm/omap_drv.c +++ b/trunk/drivers/staging/omapdrm/omap_drv.c @@ -746,7 +746,7 @@ static const struct file_operations omapdriver_fops = { static struct drm_driver omap_drm_driver = { .driver_features = - DRIVER_HAVE_IRQ | DRIVER_MODESET | DRIVER_GEM, + DRIVER_HAVE_IRQ | DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME, .load = dev_load, .unload = dev_unload, .open = dev_open, @@ -766,6 +766,10 @@ static struct drm_driver omap_drm_driver = { .debugfs_init = omap_debugfs_init, .debugfs_cleanup = omap_debugfs_cleanup, #endif + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .gem_prime_export = omap_gem_prime_export, + .gem_prime_import = omap_gem_prime_import, .gem_init_object = omap_gem_init_object, .gem_free_object = omap_gem_free_object, .gem_vm_ops = &omap_gem_vm_ops, diff --git a/trunk/drivers/staging/omapdrm/omap_drv.h b/trunk/drivers/staging/omapdrm/omap_drv.h index b7e0f0773003..f238d574da0c 100644 --- a/trunk/drivers/staging/omapdrm/omap_drv.h +++ b/trunk/drivers/staging/omapdrm/omap_drv.h @@ -138,6 +138,8 @@ int omap_gem_dumb_destroy(struct drm_file *file, struct drm_device *dev, int omap_gem_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args); int omap_gem_mmap(struct file *filp, struct vm_area_struct *vma); +int omap_gem_mmap_obj(struct drm_gem_object *obj, + struct vm_area_struct *vma); int omap_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); int omap_gem_op_start(struct drm_gem_object *obj, enum omap_gem_op op); int omap_gem_op_finish(struct drm_gem_object *obj, enum omap_gem_op op); @@ -145,12 +147,24 @@ int omap_gem_op_sync(struct drm_gem_object *obj, enum omap_gem_op op); int omap_gem_op_async(struct drm_gem_object *obj, enum omap_gem_op op, void (*fxn)(void *arg), void *arg); int omap_gem_roll(struct drm_gem_object *obj, uint32_t roll); +void omap_gem_cpu_sync(struct drm_gem_object *obj, int pgoff); +void omap_gem_dma_sync(struct drm_gem_object *obj, + enum dma_data_direction dir); int omap_gem_get_paddr(struct drm_gem_object *obj, dma_addr_t *paddr, bool remap); int omap_gem_put_paddr(struct drm_gem_object *obj); +int omap_gem_get_pages(struct drm_gem_object *obj, struct page ***pages, + bool remap); +int omap_gem_put_pages(struct drm_gem_object *obj); +uint32_t omap_gem_flags(struct drm_gem_object *obj); uint64_t omap_gem_mmap_offset(struct drm_gem_object *obj); size_t omap_gem_mmap_size(struct drm_gem_object *obj); +struct dma_buf * omap_gem_prime_export(struct drm_device *dev, + struct drm_gem_object *obj, int flags); +struct drm_gem_object * omap_gem_prime_import(struct drm_device *dev, + struct dma_buf *buffer); + static inline int align_pitch(int pitch, int width, int bpp) { int bytespp = (bpp + 7) / 8; diff --git a/trunk/drivers/staging/omapdrm/omap_fb.c b/trunk/drivers/staging/omapdrm/omap_fb.c index 04b235b6724a..74260f043ab1 100644 --- a/trunk/drivers/staging/omapdrm/omap_fb.c +++ b/trunk/drivers/staging/omapdrm/omap_fb.c @@ -167,7 +167,7 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, int x, int y, } /* Call for unpin 'a' (if not NULL), and pin 'b' (if not NULL). Although - * buffers to unpin are just just pushed to the unpin fifo so that the + * buffers to unpin are just pushed to the unpin fifo so that the * caller can defer unpin until vblank. * * Note if this fails (ie. something went very wrong!), all buffers are @@ -197,8 +197,11 @@ int omap_framebuffer_replace(struct drm_framebuffer *a, pa->paddr = 0; } - if (pb && !ret) + if (pb && !ret) { ret = omap_gem_get_paddr(pb->bo, &pb->paddr, true); + if (!ret) + omap_gem_dma_sync(pb->bo, DMA_TO_DEVICE); + } } if (ret) { diff --git a/trunk/drivers/staging/omapdrm/omap_gem.c b/trunk/drivers/staging/omapdrm/omap_gem.c index 921f058cc6a4..3a0d035a9e03 100644 --- a/trunk/drivers/staging/omapdrm/omap_gem.c +++ b/trunk/drivers/staging/omapdrm/omap_gem.c @@ -207,13 +207,27 @@ static inline bool is_shmem(struct drm_gem_object *obj) return obj->filp != NULL; } +/** + * shmem buffers that are mapped cached can simulate coherency via using + * page faulting to keep track of dirty pages + */ +static inline bool is_cached_coherent(struct drm_gem_object *obj) +{ + struct omap_gem_object *omap_obj = to_omap_bo(obj); + return is_shmem(obj) && + ((omap_obj->flags & OMAP_BO_CACHE_MASK) == OMAP_BO_CACHED); +} + static DEFINE_SPINLOCK(sync_lock); /** ensure backing pages are allocated */ static int omap_gem_attach_pages(struct drm_gem_object *obj) { + struct drm_device *dev = obj->dev; struct omap_gem_object *omap_obj = to_omap_bo(obj); struct page **pages; + int i, npages = obj->size >> PAGE_SHIFT; + dma_addr_t *addrs; WARN_ON(omap_obj->pages); @@ -231,16 +245,18 @@ static int omap_gem_attach_pages(struct drm_gem_object *obj) * DSS, GPU, etc. are not cache coherent: */ if (omap_obj->flags & (OMAP_BO_WC|OMAP_BO_UNCACHED)) { - int i, npages = obj->size >> PAGE_SHIFT; - dma_addr_t *addrs = kmalloc(npages * sizeof(addrs), GFP_KERNEL); + addrs = kmalloc(npages * sizeof(addrs), GFP_KERNEL); for (i = 0; i < npages; i++) { - addrs[i] = dma_map_page(obj->dev->dev, pages[i], + addrs[i] = dma_map_page(dev->dev, pages[i], 0, PAGE_SIZE, DMA_BIDIRECTIONAL); } - omap_obj->addrs = addrs; + } else { + addrs = kzalloc(npages * sizeof(addrs), GFP_KERNEL); } + omap_obj->addrs = addrs; omap_obj->pages = pages; + return 0; } @@ -258,14 +274,21 @@ static void omap_gem_detach_pages(struct drm_gem_object *obj) dma_unmap_page(obj->dev->dev, omap_obj->addrs[i], PAGE_SIZE, DMA_BIDIRECTIONAL); } - kfree(omap_obj->addrs); - omap_obj->addrs = NULL; } + kfree(omap_obj->addrs); + omap_obj->addrs = NULL; + _drm_gem_put_pages(obj, omap_obj->pages, true, false); omap_obj->pages = NULL; } +/* get buffer flags */ +uint32_t omap_gem_flags(struct drm_gem_object *obj) +{ + return to_omap_bo(obj)->flags; +} + /** get mmap offset */ static uint64_t mmap_offset(struct drm_gem_object *obj) { @@ -330,6 +353,7 @@ static int fault_1d(struct drm_gem_object *obj, vma->vm_start) >> PAGE_SHIFT; if (omap_obj->pages) { + omap_gem_cpu_sync(obj, pgoff); pfn = page_to_pfn(omap_obj->pages[pgoff]); } else { BUG_ON(!(omap_obj->flags & OMAP_BO_DMA)); @@ -504,7 +528,6 @@ int omap_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) /** We override mainly to fix up some of the vm mapping flags.. */ int omap_gem_mmap(struct file *filp, struct vm_area_struct *vma) { - struct omap_gem_object *omap_obj; int ret; ret = drm_gem_mmap(filp, vma); @@ -513,8 +536,13 @@ int omap_gem_mmap(struct file *filp, struct vm_area_struct *vma) return ret; } - /* after drm_gem_mmap(), it is safe to access the obj */ - omap_obj = to_omap_bo(vma->vm_private_data); + return omap_gem_mmap_obj(vma->vm_private_data, vma); +} + +int omap_gem_mmap_obj(struct drm_gem_object *obj, + struct vm_area_struct *vma) +{ + struct omap_gem_object *omap_obj = to_omap_bo(obj); vma->vm_flags &= ~VM_PFNMAP; vma->vm_flags |= VM_MIXEDMAP; @@ -524,12 +552,31 @@ int omap_gem_mmap(struct file *filp, struct vm_area_struct *vma) } else if (omap_obj->flags & OMAP_BO_UNCACHED) { vma->vm_page_prot = pgprot_noncached(vm_get_page_prot(vma->vm_flags)); } else { + /* + * We do have some private objects, at least for scanout buffers + * on hardware without DMM/TILER. But these are allocated write- + * combine + */ + if (WARN_ON(!obj->filp)) + return -EINVAL; + + /* + * Shunt off cached objs to shmem file so they have their own + * address_space (so unmap_mapping_range does what we want, + * in particular in the case of mmap'd dmabufs) + */ + fput(vma->vm_file); + get_file(obj->filp); + vma->vm_pgoff = 0; + vma->vm_file = obj->filp; + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); } - return ret; + return 0; } + /** * omap_gem_dumb_create - create a dumb buffer * @drm_file: our client file @@ -639,6 +686,48 @@ int omap_gem_roll(struct drm_gem_object *obj, uint32_t roll) return ret; } +/* Sync the buffer for CPU access.. note pages should already be + * attached, ie. omap_gem_get_pages() + */ +void omap_gem_cpu_sync(struct drm_gem_object *obj, int pgoff) +{ + struct drm_device *dev = obj->dev; + struct omap_gem_object *omap_obj = to_omap_bo(obj); + + if (is_cached_coherent(obj) && omap_obj->addrs[pgoff]) { + dma_unmap_page(dev->dev, omap_obj->addrs[pgoff], + PAGE_SIZE, DMA_BIDIRECTIONAL); + omap_obj->addrs[pgoff] = 0; + } +} + +/* sync the buffer for DMA access */ +void omap_gem_dma_sync(struct drm_gem_object *obj, + enum dma_data_direction dir) +{ + struct drm_device *dev = obj->dev; + struct omap_gem_object *omap_obj = to_omap_bo(obj); + + if (is_cached_coherent(obj)) { + int i, npages = obj->size >> PAGE_SHIFT; + struct page **pages = omap_obj->pages; + bool dirty = false; + + for (i = 0; i < npages; i++) { + if (!omap_obj->addrs[i]) { + omap_obj->addrs[i] = dma_map_page(dev->dev, pages[i], 0, + PAGE_SIZE, DMA_BIDIRECTIONAL); + dirty = true; + } + } + + if (dirty) { + unmap_mapping_range(obj->filp->f_mapping, 0, + omap_gem_mmap_size(obj), 1); + } + } +} + /* Get physical address for DMA.. if 'remap' is true, and the buffer is not * already contiguous, remap it to pin in physically contiguous memory.. (ie. * map in TILER) @@ -703,6 +792,7 @@ int omap_gem_get_paddr(struct drm_gem_object *obj, *paddr = omap_obj->paddr; } else { ret = -EINVAL; + goto fail; } fail: @@ -764,9 +854,27 @@ static int get_pages(struct drm_gem_object *obj, struct page ***pages) return 0; } -int omap_gem_get_pages(struct drm_gem_object *obj, struct page ***pages) +/* if !remap, and we don't have pages backing, then fail, rather than + * increasing the pin count (which we don't really do yet anyways, + * because we don't support swapping pages back out). And 'remap' + * might not be quite the right name, but I wanted to keep it working + * similarly to omap_gem_get_paddr(). Note though that mutex is not + * aquired if !remap (because this can be called in atomic ctxt), + * but probably omap_gem_get_paddr() should be changed to work in the + * same way. If !remap, a matching omap_gem_put_pages() call is not + * required (and should not be made). + */ +int omap_gem_get_pages(struct drm_gem_object *obj, struct page ***pages, + bool remap) { int ret; + if (!remap) { + struct omap_gem_object *omap_obj = to_omap_bo(obj); + if (!omap_obj->pages) + return -ENOMEM; + *pages = omap_obj->pages; + return 0; + } mutex_lock(&obj->dev->struct_mutex); ret = get_pages(obj, pages); mutex_unlock(&obj->dev->struct_mutex); diff --git a/trunk/drivers/staging/omapdrm/omap_gem_dmabuf.c b/trunk/drivers/staging/omapdrm/omap_gem_dmabuf.c new file mode 100644 index 000000000000..42728e0cc194 --- /dev/null +++ b/trunk/drivers/staging/omapdrm/omap_gem_dmabuf.c @@ -0,0 +1,220 @@ +/* + * drivers/staging/omapdrm/omap_gem_dmabuf.c + * + * Copyright (C) 2011 Texas Instruments + * Author: Rob Clark + * + * 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 "omap_drv.h" + +#include + +static struct sg_table *omap_gem_map_dma_buf( + struct dma_buf_attachment *attachment, + enum dma_data_direction dir) +{ + struct drm_gem_object *obj = attachment->dmabuf->priv; + struct sg_table *sg; + dma_addr_t paddr; + int ret; + + sg = kzalloc(sizeof(*sg), GFP_KERNEL); + if (!sg) + return ERR_PTR(-ENOMEM); + + /* camera, etc, need physically contiguous.. but we need a + * better way to know this.. + */ + ret = omap_gem_get_paddr(obj, &paddr, true); + if (ret) + goto out; + + ret = sg_alloc_table(sg, 1, GFP_KERNEL); + if (ret) + goto out; + + sg_init_table(sg->sgl, 1); + sg_dma_len(sg->sgl) = obj->size; + sg_set_page(sg->sgl, pfn_to_page(PFN_DOWN(paddr)), obj->size, 0); + sg_dma_address(sg->sgl) = paddr; + + /* this should be after _get_paddr() to ensure we have pages attached */ + omap_gem_dma_sync(obj, dir); + +out: + if (ret) + return ERR_PTR(ret); + return sg; +} + +static void omap_gem_unmap_dma_buf(struct dma_buf_attachment *attachment, + struct sg_table *sg, enum dma_data_direction dir) +{ + struct drm_gem_object *obj = attachment->dmabuf->priv; + omap_gem_put_paddr(obj); + sg_free_table(sg); + kfree(sg); +} + +static void omap_gem_dmabuf_release(struct dma_buf *buffer) +{ + struct drm_gem_object *obj = buffer->priv; + /* release reference that was taken when dmabuf was exported + * in omap_gem_prime_set().. + */ + drm_gem_object_unreference_unlocked(obj); +} + + +static int omap_gem_dmabuf_begin_cpu_access(struct dma_buf *buffer, + size_t start, size_t len, enum dma_data_direction dir) +{ + struct drm_gem_object *obj = buffer->priv; + struct page **pages; + if (omap_gem_flags(obj) & OMAP_BO_TILED) { + /* TODO we would need to pin at least part of the buffer to + * get de-tiled view. For now just reject it. + */ + return -ENOMEM; + } + /* make sure we have the pages: */ + return omap_gem_get_pages(obj, &pages, true); +} + +static void omap_gem_dmabuf_end_cpu_access(struct dma_buf *buffer, + size_t start, size_t len, enum dma_data_direction dir) +{ + struct drm_gem_object *obj = buffer->priv; + omap_gem_put_pages(obj); +} + + +static void *omap_gem_dmabuf_kmap_atomic(struct dma_buf *buffer, + unsigned long page_num) +{ + struct drm_gem_object *obj = buffer->priv; + struct page **pages; + omap_gem_get_pages(obj, &pages, false); + omap_gem_cpu_sync(obj, page_num); + return kmap_atomic(pages[page_num]); +} + +static void omap_gem_dmabuf_kunmap_atomic(struct dma_buf *buffer, + unsigned long page_num, void *addr) +{ + kunmap_atomic(addr); +} + +static void *omap_gem_dmabuf_kmap(struct dma_buf *buffer, + unsigned long page_num) +{ + struct drm_gem_object *obj = buffer->priv; + struct page **pages; + omap_gem_get_pages(obj, &pages, false); + omap_gem_cpu_sync(obj, page_num); + return kmap(pages[page_num]); +} + +static void omap_gem_dmabuf_kunmap(struct dma_buf *buffer, + unsigned long page_num, void *addr) +{ + struct drm_gem_object *obj = buffer->priv; + struct page **pages; + omap_gem_get_pages(obj, &pages, false); + kunmap(pages[page_num]); +} + +/* + * TODO maybe we can split up drm_gem_mmap to avoid duplicating + * some here.. or at least have a drm_dmabuf_mmap helper. + */ +static int omap_gem_dmabuf_mmap(struct dma_buf *buffer, + struct vm_area_struct *vma) +{ + struct drm_gem_object *obj = buffer->priv; + int ret = 0; + + if (WARN_ON(!obj->filp)) + return -EINVAL; + + /* Check for valid size. */ + if (omap_gem_mmap_size(obj) < vma->vm_end - vma->vm_start) { + ret = -EINVAL; + goto out_unlock; + } + + if (!obj->dev->driver->gem_vm_ops) { + ret = -EINVAL; + goto out_unlock; + } + + vma->vm_flags |= VM_RESERVED | VM_IO | VM_PFNMAP | VM_DONTEXPAND; + vma->vm_ops = obj->dev->driver->gem_vm_ops; + vma->vm_private_data = obj; + vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); + + /* Take a ref for this mapping of the object, so that the fault + * handler can dereference the mmap offset's pointer to the object. + * This reference is cleaned up by the corresponding vm_close + * (which should happen whether the vma was created by this call, or + * by a vm_open due to mremap or partial unmap or whatever). + */ + vma->vm_ops->open(vma); + +out_unlock: + + return omap_gem_mmap_obj(obj, vma); +} + +struct dma_buf_ops omap_dmabuf_ops = { + .map_dma_buf = omap_gem_map_dma_buf, + .unmap_dma_buf = omap_gem_unmap_dma_buf, + .release = omap_gem_dmabuf_release, + .begin_cpu_access = omap_gem_dmabuf_begin_cpu_access, + .end_cpu_access = omap_gem_dmabuf_end_cpu_access, + .kmap_atomic = omap_gem_dmabuf_kmap_atomic, + .kunmap_atomic = omap_gem_dmabuf_kunmap_atomic, + .kmap = omap_gem_dmabuf_kmap, + .kunmap = omap_gem_dmabuf_kunmap, + .mmap = omap_gem_dmabuf_mmap, +}; + +struct dma_buf * omap_gem_prime_export(struct drm_device *dev, + struct drm_gem_object *obj, int flags) +{ + return dma_buf_export(obj, &omap_dmabuf_ops, obj->size, 0600); +} + +struct drm_gem_object * omap_gem_prime_import(struct drm_device *dev, + struct dma_buf *buffer) +{ + struct drm_gem_object *obj; + + /* is this one of own objects? */ + if (buffer->ops == &omap_dmabuf_ops) { + obj = buffer->priv; + /* is it from our device? */ + if (obj->dev == dev) { + drm_gem_object_reference(obj); + return obj; + } + } + + /* + * TODO add support for importing buffers from other devices.. + * for now we don't need this but would be nice to add eventually + */ + return ERR_PTR(-EINVAL); +} diff --git a/trunk/drivers/staging/omapdrm/tcm-sita.c b/trunk/drivers/staging/omapdrm/tcm-sita.c index 10d5ac3dae4b..efb609510540 100644 --- a/trunk/drivers/staging/omapdrm/tcm-sita.c +++ b/trunk/drivers/staging/omapdrm/tcm-sita.c @@ -200,7 +200,7 @@ static s32 sita_reserve_1d(struct tcm *tcm, u32 num_slots, * * @param w width * @param h height - * @param area pointer to the area that will be populated with the reesrved + * @param area pointer to the area that will be populated with the reserved * area * * @return 0 on success, non-0 error value on failure. diff --git a/trunk/drivers/staging/ozwpan/README b/trunk/drivers/staging/ozwpan/README index bb1a69b94541..7c055ec99544 100644 --- a/trunk/drivers/staging/ozwpan/README +++ b/trunk/drivers/staging/ozwpan/README @@ -9,7 +9,7 @@ technology. To operate the driver must be bound to a suitable network interface. This can be done when the module is loaded (specifying the name of the network interface -as a paramter - e.g. 'insmod ozwpan g_net_dev=go0') or can be bound after +as a parameter - e.g. 'insmod ozwpan g_net_dev=go0') or can be bound after loading using an ioctl call. See the ozappif.h file and the ioctls OZ_IOCTL_ADD_BINDING and OZ_IOCTL_REMOVE_BINDING. diff --git a/trunk/drivers/staging/ozwpan/ozappif.h b/trunk/drivers/staging/ozwpan/ozappif.h index af0273293872..1b59b0748c6b 100644 --- a/trunk/drivers/staging/ozwpan/ozappif.h +++ b/trunk/drivers/staging/ozwpan/ozappif.h @@ -11,13 +11,13 @@ #define OZ_IOCTL_MAGIC 0xf4 struct oz_mac_addr { - unsigned char a[6]; + __u8 a[6]; }; #define OZ_MAX_PDS 8 struct oz_pd_list { - int count; + __u32 count; struct oz_mac_addr addr[OZ_MAX_PDS]; }; @@ -27,18 +27,10 @@ struct oz_binding_info { char name[OZ_MAX_BINDING_LEN]; }; -struct oz_test { - int action; -}; - #define OZ_IOCTL_GET_PD_LIST _IOR(OZ_IOCTL_MAGIC, 0, struct oz_pd_list) #define OZ_IOCTL_SET_ACTIVE_PD _IOW(OZ_IOCTL_MAGIC, 1, struct oz_mac_addr) #define OZ_IOCTL_GET_ACTIVE_PD _IOR(OZ_IOCTL_MAGIC, 2, struct oz_mac_addr) -#define OZ_IOCTL_CLEAR_EVENTS _IO(OZ_IOCTL_MAGIC, 3) -#define OZ_IOCTL_GET_EVENTS _IOR(OZ_IOCTL_MAGIC, 4, struct oz_evtlist) #define OZ_IOCTL_ADD_BINDING _IOW(OZ_IOCTL_MAGIC, 5, struct oz_binding_info) -#define OZ_IOCTL_TEST _IOWR(OZ_IOCTL_MAGIC, 6, struct oz_test) -#define OZ_IOCTL_SET_EVENT_MASK _IOW(OZ_IOCTL_MAGIC, 7, unsigned long) #define OZ_IOCTL_REMOVE_BINDING _IOW(OZ_IOCTL_MAGIC, 8, struct oz_binding_info) #define OZ_IOCTL_MAX 9 diff --git a/trunk/drivers/staging/ozwpan/ozcdev.c b/trunk/drivers/staging/ozwpan/ozcdev.c index 1c380d687963..27325f74ecdc 100644 --- a/trunk/drivers/staging/ozwpan/ozcdev.c +++ b/trunk/drivers/staging/ozwpan/ozcdev.c @@ -39,9 +39,6 @@ struct oz_serial_ctx { int rd_in; int rd_out; }; -/*------------------------------------------------------------------------------ - */ -int g_taction; /*------------------------------------------------------------------------------ */ static struct oz_cdev g_cdev; @@ -276,20 +273,6 @@ long oz_cdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return -EFAULT; } break; -#ifdef WANT_EVENT_TRACE - case OZ_IOCTL_CLEAR_EVENTS: - oz_events_clear(); - break; - case OZ_IOCTL_GET_EVENTS: - rc = oz_events_copy((void __user *)arg); - break; - case OZ_IOCTL_SET_EVENT_MASK: - if (copy_from_user(&g_evt_mask, (void __user *)arg, - sizeof(unsigned long))) { - return -EFAULT; - } - break; -#endif /* WANT_EVENT_TRACE */ case OZ_IOCTL_ADD_BINDING: case OZ_IOCTL_REMOVE_BINDING: { struct oz_binding_info b; diff --git a/trunk/drivers/staging/ozwpan/ozevent.c b/trunk/drivers/staging/ozwpan/ozevent.c index 73703d3e96bd..7f66b4f19b01 100644 --- a/trunk/drivers/staging/ozwpan/ozevent.c +++ b/trunk/drivers/staging/ozwpan/ozevent.c @@ -5,29 +5,46 @@ */ #include "ozconfig.h" #ifdef WANT_EVENT_TRACE +#include +#include #include #include #include "oztrace.h" #include "ozevent.h" +#include "ozappif.h" /*------------------------------------------------------------------------------ + * Although the event mask is logically part of the oz_evtdev structure, it is + * needed outside of this file so define it seperately to avoid the need to + * export definition of struct oz_evtdev. */ -unsigned long g_evt_mask = 0xffffffff; +u32 g_evt_mask; /*------------------------------------------------------------------------------ */ #define OZ_MAX_EVTS 2048 /* Must be power of 2 */ -DEFINE_SPINLOCK(g_eventlock); -static int g_evt_in; -static int g_evt_out; -static int g_missed_events; -static struct oz_event g_events[OZ_MAX_EVTS]; +struct oz_evtdev { + struct dentry *root_dir; + int evt_in; + int evt_out; + int missed_events; + int present; + atomic_t users; + spinlock_t lock; + struct oz_event evts[OZ_MAX_EVTS]; +}; + +static struct oz_evtdev g_evtdev; + /*------------------------------------------------------------------------------ * Context: process */ void oz_event_init(void) { + /* Because g_evtdev is static external all fields initally zero so no + * need to reinitialised those. + */ oz_trace("Event tracing initialized\n"); - g_evt_in = g_evt_out = 0; - g_missed_events = 0; + spin_lock_init(&g_evtdev.lock); + atomic_set(&g_evtdev.users, 0); } /*------------------------------------------------------------------------------ * Context: process @@ -43,74 +60,136 @@ void oz_event_log2(u8 evt, u8 ctx1, u16 ctx2, void *ctx3, unsigned ctx4) { unsigned long irqstate; int ix; - spin_lock_irqsave(&g_eventlock, irqstate); - ix = (g_evt_in + 1) & (OZ_MAX_EVTS - 1); - if (ix != g_evt_out) { - struct oz_event *e = &g_events[g_evt_in]; + spin_lock_irqsave(&g_evtdev.lock, irqstate); + ix = (g_evtdev.evt_in + 1) & (OZ_MAX_EVTS - 1); + if (ix != g_evtdev.evt_out) { + struct oz_event *e = &g_evtdev.evts[g_evtdev.evt_in]; e->jiffies = jiffies; e->evt = evt; e->ctx1 = ctx1; e->ctx2 = ctx2; - e->ctx3 = ctx3; + e->ctx3 = (__u32)(unsigned long)ctx3; e->ctx4 = ctx4; - g_evt_in = ix; + g_evtdev.evt_in = ix; } else { - g_missed_events++; + g_evtdev.missed_events++; } - spin_unlock_irqrestore(&g_eventlock, irqstate); + spin_unlock_irqrestore(&g_evtdev.lock, irqstate); } /*------------------------------------------------------------------------------ * Context: process */ -int oz_events_copy(struct oz_evtlist __user *lst) +static void oz_events_clear(struct oz_evtdev *dev) { - int first; - int ix; - struct hdr { - int count; - int missed; - } hdr; - ix = g_evt_out; - hdr.count = g_evt_in - ix; - if (hdr.count < 0) - hdr.count += OZ_MAX_EVTS; - if (hdr.count > OZ_EVT_LIST_SZ) - hdr.count = OZ_EVT_LIST_SZ; - hdr.missed = g_missed_events; - g_missed_events = 0; - if (copy_to_user((void __user *)lst, &hdr, sizeof(hdr))) - return -EFAULT; - first = OZ_MAX_EVTS - ix; - if (first > hdr.count) - first = hdr.count; - if (first) { - int sz = first*sizeof(struct oz_event); - void __user *p = (void __user *)lst->evts; - if (copy_to_user(p, &g_events[ix], sz)) - return -EFAULT; - if (hdr.count > first) { - p = (void __user *)&lst->evts[first]; - sz = (hdr.count-first)*sizeof(struct oz_event); - if (copy_to_user(p, g_events, sz)) - return -EFAULT; - } + unsigned long irqstate; + oz_trace("Clearing events\n"); + spin_lock_irqsave(&dev->lock, irqstate); + dev->evt_in = dev->evt_out = 0; + dev->missed_events = 0; + spin_unlock_irqrestore(&dev->lock, irqstate); +} +#ifdef CONFIG_DEBUG_FS +/*------------------------------------------------------------------------------ + * Context: process + */ +int oz_events_open(struct inode *inode, struct file *filp) +{ + oz_trace("oz_evt_open()\n"); + oz_trace("Open flags: 0x%x\n", filp->f_flags); + if (atomic_add_return(1, &g_evtdev.users) == 1) { + oz_events_clear(&g_evtdev); + return nonseekable_open(inode, filp); + } else { + atomic_dec(&g_evtdev.users); + return -EBUSY; } - ix += hdr.count; - if (ix >= OZ_MAX_EVTS) - ix -= OZ_MAX_EVTS; - g_evt_out = ix; +} +/*------------------------------------------------------------------------------ + * Context: process + */ +int oz_events_release(struct inode *inode, struct file *filp) +{ + oz_events_clear(&g_evtdev); + atomic_dec(&g_evtdev.users); + g_evt_mask = 0; + oz_trace("oz_evt_release()\n"); return 0; } /*------------------------------------------------------------------------------ * Context: process */ -void oz_events_clear(void) +ssize_t oz_events_read(struct file *filp, char __user *buf, size_t count, + loff_t *fpos) { - unsigned long irqstate; - spin_lock_irqsave(&g_eventlock, irqstate); - g_evt_in = g_evt_out = 0; - g_missed_events = 0; - spin_unlock_irqrestore(&g_eventlock, irqstate); + struct oz_evtdev *dev = &g_evtdev; + int rc = 0; + int nb_evts = count / sizeof(struct oz_event); + int n; + int sz; + + n = dev->evt_in - dev->evt_out; + if (n < 0) + n += OZ_MAX_EVTS; + if (nb_evts > n) + nb_evts = n; + if (nb_evts == 0) + goto out; + n = OZ_MAX_EVTS - dev->evt_out; + if (n > nb_evts) + n = nb_evts; + sz = n * sizeof(struct oz_event); + if (copy_to_user(buf, &dev->evts[dev->evt_out], sz)) { + rc = -EFAULT; + goto out; + } + if (n == nb_evts) + goto out2; + n = nb_evts - n; + if (copy_to_user(buf + sz, dev->evts, n * sizeof(struct oz_event))) { + rc = -EFAULT; + goto out; + } +out2: + dev->evt_out = (dev->evt_out + nb_evts) & (OZ_MAX_EVTS - 1); + rc = nb_evts * sizeof(struct oz_event); +out: + return rc; } -#endif /* WANT_EVENT_TRACE */ +/*------------------------------------------------------------------------------ + */ +const struct file_operations oz_events_fops = { + .owner = THIS_MODULE, + .open = oz_events_open, + .release = oz_events_release, + .read = oz_events_read, +}; +/*------------------------------------------------------------------------------ + * Context: process + */ +void oz_debugfs_init(void) +{ + struct dentry *parent; + parent = debugfs_create_dir("ozwpan", NULL); + if (parent == NULL) { + oz_trace("Failed to create debugfs directory ozmo\n"); + return; + } else { + g_evtdev.root_dir = parent; + if (debugfs_create_file("events", S_IRUSR, parent, NULL, + &oz_events_fops) == NULL) + oz_trace("Failed to create file ozmo/events\n"); + if (debugfs_create_x32("event_mask", S_IRUSR | S_IWUSR, parent, + &g_evt_mask) == NULL) + oz_trace("Failed to create file ozmo/event_mask\n"); + } +} +/*------------------------------------------------------------------------------ + * Context: process + */ +void oz_debugfs_remove(void) +{ + debugfs_remove_recursive(g_evtdev.root_dir); +} +#endif /* CONFIG_DEBUG_FS */ +#endif /* WANT_EVENT_TRACE */ diff --git a/trunk/drivers/staging/ozwpan/ozevent.h b/trunk/drivers/staging/ozwpan/ozevent.h index f033d014c6f3..32f6f9859c41 100644 --- a/trunk/drivers/staging/ozwpan/ozevent.h +++ b/trunk/drivers/staging/ozwpan/ozevent.h @@ -9,23 +9,24 @@ #include "ozeventdef.h" #ifdef WANT_EVENT_TRACE -extern unsigned long g_evt_mask; +extern u32 g_evt_mask; void oz_event_init(void); void oz_event_term(void); void oz_event_log2(u8 evt, u8 ctx1, u16 ctx2, void *ctx3, unsigned ctx4); +void oz_debugfs_init(void); +void oz_debugfs_remove(void); #define oz_event_log(__evt, __ctx1, __ctx2, __ctx3, __ctx4) \ do { \ if ((1<<(__evt)) & g_evt_mask) \ oz_event_log2(__evt, __ctx1, __ctx2, __ctx3, __ctx4); \ } while (0) -int oz_events_copy(struct oz_evtlist __user *lst); -void oz_events_clear(void); + #else #define oz_event_init() #define oz_event_term() #define oz_event_log(__evt, __ctx1, __ctx2, __ctx3, __ctx4) -#define oz_events_copy(__lst) -#define oz_events_clear() +#define oz_debugfs_init() +#define oz_debugfs_remove() #endif /* WANT_EVENT_TRACE */ #endif /* _OZEVENT_H */ diff --git a/trunk/drivers/staging/ozwpan/ozeventdef.h b/trunk/drivers/staging/ozwpan/ozeventdef.h index a880288bab11..4b938981671a 100644 --- a/trunk/drivers/staging/ozwpan/ozeventdef.h +++ b/trunk/drivers/staging/ozwpan/ozeventdef.h @@ -29,19 +29,12 @@ #define OZ_EVT_DEBUG 20 struct oz_event { - unsigned long jiffies; - unsigned char evt; - unsigned char ctx1; - unsigned short ctx2; - void *ctx3; - unsigned ctx4; -}; - -#define OZ_EVT_LIST_SZ 64 -struct oz_evtlist { - int count; - int missed; - struct oz_event evts[OZ_EVT_LIST_SZ]; + __u32 jiffies; + __u8 evt; + __u8 ctx1; + __u16 ctx2; + __u32 ctx3; + __u32 ctx4; }; #endif /* _OZEVENTDEF_H */ diff --git a/trunk/drivers/staging/ozwpan/ozhcd.c b/trunk/drivers/staging/ozwpan/ozhcd.c index 750b14eb505e..251f07c39a6b 100644 --- a/trunk/drivers/staging/ozwpan/ozhcd.c +++ b/trunk/drivers/staging/ozwpan/ozhcd.c @@ -1416,7 +1416,7 @@ static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb, oz_trace("USB_REQ_SET_CONFIGURATION - req\n"); break; case USB_REQ_GET_CONFIGURATION: - /* We short curcuit this case and reply directly since + /* We short circuit this case and reply directly since * we have the selected configuration number cached. */ oz_event_log(OZ_EVT_CTRL_LOCAL, setup->bRequest, 0, 0, @@ -1432,7 +1432,7 @@ static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb, } break; case USB_REQ_GET_INTERFACE: - /* We short curcuit this case and reply directly since + /* We short circuit this case and reply directly since * we have the selected interface alternative cached. */ oz_event_log(OZ_EVT_CTRL_LOCAL, setup->bRequest, 0, 0, @@ -1463,7 +1463,7 @@ static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb, rc = -ENOMEM; } else { /* Note: we are queuing the request after we have - * submitted it to be tranmitted. If the request were + * submitted it to be transmitted. If the request were * to complete before we queued it then it would not * be found in the queue. It seems impossible for * this to happen but if it did the request would diff --git a/trunk/drivers/staging/ozwpan/ozmain.c b/trunk/drivers/staging/ozwpan/ozmain.c index aaf2ccc0bcfb..7579645d642a 100644 --- a/trunk/drivers/staging/ozwpan/ozmain.c +++ b/trunk/drivers/staging/ozwpan/ozmain.c @@ -33,6 +33,9 @@ static int __init ozwpan_init(void) oz_protocol_init(g_net_dev); oz_app_enable(OZ_APPID_USB, 1); oz_apps_init(); +#ifdef CONFIG_DEBUG_FS + oz_debugfs_init(); +#endif return 0; } /*------------------------------------------------------------------------------ @@ -44,6 +47,9 @@ static void __exit ozwpan_exit(void) oz_apps_term(); oz_cdev_deregister(); oz_event_term(); +#ifdef CONFIG_DEBUG_FS + oz_debugfs_remove(); +#endif } /*------------------------------------------------------------------------------ */ @@ -53,6 +59,6 @@ module_exit(ozwpan_exit); MODULE_AUTHOR("Chris Kelly"); MODULE_DESCRIPTION("Ozmo Devices USB over WiFi hcd driver"); -MODULE_VERSION("1.0.8"); +MODULE_VERSION("1.0.9"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/staging/ozwpan/ozusbsvc.c b/trunk/drivers/staging/ozwpan/ozusbsvc.c index 9e74f9602384..8fa7f256ad8c 100644 --- a/trunk/drivers/staging/ozwpan/ozusbsvc.c +++ b/trunk/drivers/staging/ozwpan/ozusbsvc.c @@ -7,7 +7,7 @@ * The implementation of this service is split into two parts the first of which * is protocol independent and the second contains protocol specific details. * This split is to allow alternative protocols to be defined. - * The implemenation of this service uses ozhcd.c to implement a USB HCD. + * The implementation of this service uses ozhcd.c to implement a USB HCD. * ----------------------------------------------------------------------------- */ #include diff --git a/trunk/drivers/staging/panel/panel.c b/trunk/drivers/staging/panel/panel.c index 6183573f112f..7365089a33e8 100644 --- a/trunk/drivers/staging/panel/panel.c +++ b/trunk/drivers/staging/panel/panel.c @@ -754,7 +754,7 @@ static void lcd_backlight(int on) if (lcd_bl_pin == PIN_NONE) return; - /* The backlight is activated by seting the AUTOFEED line to +5V */ + /* The backlight is activated by setting the AUTOFEED line to +5V */ spin_lock(&pprt_lock); bits.bl = on; panel_set_bits(); diff --git a/trunk/drivers/staging/quatech_usb2/Kconfig b/trunk/drivers/staging/quatech_usb2/Kconfig deleted file mode 100644 index 1494f42f3da0..000000000000 --- a/trunk/drivers/staging/quatech_usb2/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -config USB_SERIAL_QUATECH_USB2 - tristate "USB Quatech xSU2-[14]00 USB Serial Driver" - depends on USB_SERIAL - help - Say Y here if you want to use a Quatech USB2.0 to serial adaptor. This - driver supports the SSU2-100, DSU2-100, DSU2-400, QSU2-100, QSU2-400, - ESU2-400 and ESU2-100 USB2.0 to RS232 / 485 / 422 serial adaptors. - - Some hardware has an incorrect product string and announces itself as - ESU-100 (which uses the serqt driver) even though it is an ESU2-100. - Check the label on the bottom of your device. - - To compile this driver as a module, choose M here: the module will be - called quatech_usb2 . - diff --git a/trunk/drivers/staging/quatech_usb2/Makefile b/trunk/drivers/staging/quatech_usb2/Makefile deleted file mode 100644 index bcd1f890d163..000000000000 --- a/trunk/drivers/staging/quatech_usb2/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_USB_SERIAL_QUATECH_USB2) += quatech_usb2.o diff --git a/trunk/drivers/staging/quatech_usb2/TODO b/trunk/drivers/staging/quatech_usb2/TODO deleted file mode 100644 index 67f61dbe14ac..000000000000 --- a/trunk/drivers/staging/quatech_usb2/TODO +++ /dev/null @@ -1,8 +0,0 @@ -Incomplete list of things that this driver does not yet implement completely or -at all. some of these may not be possible to implement because the hardware -support does not exist. Others may be possible, but the magic control codes to -make them happen are unknown, and some may just need the driver support to -implement them writing. - -* Mark/Space parity is not implemented (reported back correctly) -* IXANY flow control mode is not implemented (flag ignored completely) diff --git a/trunk/drivers/staging/quatech_usb2/quatech_usb2.c b/trunk/drivers/staging/quatech_usb2/quatech_usb2.c deleted file mode 100644 index bb977e00cc86..000000000000 --- a/trunk/drivers/staging/quatech_usb2/quatech_usb2.c +++ /dev/null @@ -1,1976 +0,0 @@ -/* - * Driver for Quatech Inc USB2.0 to serial adaptors. Largely unrelated to the - * serqt_usb driver, based on a re-write of the vendor supplied serqt_usb2 code, - * which is unrelated to the serqt_usb2 in the staging kernel - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static bool debug; - -/* Version Information */ -#define DRIVER_VERSION "v2.00" -#define DRIVER_AUTHOR "Tim Gobeli, Quatech, Inc" -#define DRIVER_DESC "Quatech USB 2.0 to Serial Driver" - -/* vendor and device IDs */ -#define USB_VENDOR_ID_QUATECH 0x061d /* Quatech VID */ -#define QUATECH_SSU2_100 0xC120 /* RS232 single port */ -#define QUATECH_DSU2_100 0xC140 /* RS232 dual port */ -#define QUATECH_DSU2_400 0xC150 /* RS232/422/485 dual port */ -#define QUATECH_QSU2_100 0xC160 /* RS232 four port */ -#define QUATECH_QSU2_400 0xC170 /* RS232/422/485 four port */ -#define QUATECH_ESU2_100 0xC1A0 /* RS232 eight port */ -#define QUATECH_ESU2_400 0xC180 /* RS232/422/485 eight port */ - -/* magic numbers go here, when we find out which ones are needed */ - -#define QU2BOXPWRON 0x8000 /* magic number to turn FPGA power on */ -#define QU2BOX232 0x40 /* RS232 mode on MEI devices */ -#define QU2BOXSPD9600 0x60 /* set speed to 9600 baud */ -#define QT2_FIFO_DEPTH 1024 /* size of hardware fifos */ -#define QT2_TX_HEADER_LENGTH 5 -/* length of the header sent to the box with each write URB */ - -/* directions for USB transfers */ -#define USBD_TRANSFER_DIRECTION_IN 0xc0 -#define USBD_TRANSFER_DIRECTION_OUT 0x40 - -/* special Quatech command IDs. These are pushed down the - USB control pipe to get the box on the end to do things */ -#define QT_SET_GET_DEVICE 0xc2 -#define QT_OPEN_CLOSE_CHANNEL 0xca -/*#define QT_GET_SET_PREBUF_TRIG_LVL 0xcc -#define QT_SET_ATF 0xcd*/ -#define QT2_GET_SET_REGISTER 0xc0 -#define QT2_GET_SET_UART 0xc1 -#define QT2_HW_FLOW_CONTROL_MASK 0xc5 -#define QT2_SW_FLOW_CONTROL_MASK 0xc6 -#define QT2_SW_FLOW_CONTROL_DISABLE 0xc7 -#define QT2_BREAK_CONTROL 0xc8 -#define QT2_STOP_RECEIVE 0xe0 -#define QT2_FLUSH_DEVICE 0xc4 -#define QT2_GET_SET_QMCR 0xe1 - -/* sorts of flush we can do on */ -#define QT2_FLUSH_RX 0x00 -#define QT2_FLUSH_TX 0x01 - -/* port setting constants, used to set up serial port speeds, flow - * control and so on */ -#define QT2_SERIAL_MCR_DTR 0x01 -#define QT2_SERIAL_MCR_RTS 0x02 -#define QT2_SERIAL_MCR_LOOP 0x10 - -#define QT2_SERIAL_MSR_CTS 0x10 -#define QT2_SERIAL_MSR_CD 0x80 -#define QT2_SERIAL_MSR_RI 0x40 -#define QT2_SERIAL_MSR_DSR 0x20 -#define QT2_SERIAL_MSR_MASK 0xf0 - -#define QT2_SERIAL_8_DATA 0x03 -#define QT2_SERIAL_7_DATA 0x02 -#define QT2_SERIAL_6_DATA 0x01 -#define QT2_SERIAL_5_DATA 0x00 - -#define QT2_SERIAL_ODD_PARITY 0x08 -#define QT2_SERIAL_EVEN_PARITY 0x18 -#define QT2_SERIAL_TWO_STOPB 0x04 -#define QT2_SERIAL_ONE_STOPB 0x00 - -#define QT2_MAX_BAUD_RATE 921600 -#define QT2_MAX_BAUD_REMAINDER 4608 - -#define QT2_SERIAL_LSR_OE 0x02 -#define QT2_SERIAL_LSR_PE 0x04 -#define QT2_SERIAL_LSR_FE 0x08 -#define QT2_SERIAL_LSR_BI 0x10 - -/* value of Line Status Register when UART has completed - * emptying data out on the line */ -#define QT2_LSR_TEMT 0x40 - -/* register numbers on each UART, for use with qt2_box_[get|set]_register*/ -#define QT2_XMT_HOLD_REGISTER 0x00 -#define QT2_XVR_BUFFER_REGISTER 0x00 -#define QT2_FIFO_CONTROL_REGISTER 0x02 -#define QT2_LINE_CONTROL_REGISTER 0x03 -#define QT2_MODEM_CONTROL_REGISTER 0x04 -#define QT2_LINE_STATUS_REGISTER 0x05 -#define QT2_MODEM_STATUS_REGISTER 0x06 - -/* handy macros for doing escape sequence parsing on data reads */ -#define THISCHAR ((unsigned char *)(urb->transfer_buffer))[i] -#define NEXTCHAR ((unsigned char *)(urb->transfer_buffer))[i + 1] -#define THIRDCHAR ((unsigned char *)(urb->transfer_buffer))[i + 2] -#define FOURTHCHAR ((unsigned char *)(urb->transfer_buffer))[i + 3] -#define FIFTHCHAR ((unsigned char *)(urb->transfer_buffer))[i + 4] - -static const struct usb_device_id quausb2_id_table[] = { - {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU2_100)}, - {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_100)}, - {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_400)}, - {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_100)}, - {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_400)}, - {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_100)}, - {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_400)}, - {} /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, quausb2_id_table); - -/* custom structures we need go here */ -static struct usb_driver quausb2_usb_driver = { - .name = "quatech-usb2-serial", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = quausb2_id_table, -}; - -/** - * quatech2_port: Structure in which to keep all the messy stuff that this - * driver needs alongside the usb_serial_port structure - * @read_urb_busy: Flag indicating that port->read_urb is in use - * @close_pending: flag indicating that this port is in the process of - * being closed (and so no new reads / writes should be started). - * @shadowLSR: Last received state of the line status register, holds the - * value of the line status flags from the port - * @shadowMSR: Last received state of the modem status register, holds - * the value of the modem status received from the port - * @rcv_flush: Flag indicating that a receive flush has occurred on - * the hardware. - * @xmit_flush: Flag indicating that a transmit flush has been processed by - * the hardware. - * @tx_pending_bytes: Number of bytes waiting to be sent. This total - * includes the size (excluding header) of URBs that have been submitted but - * have not yet been sent to to the device, and bytes that have been sent out - * of the port but not yet reported sent by the "xmit_empty" messages (which - * indicate the number of bytes sent each time they are received, despite the - * misleading name). - * - Starts at zero when port is initialised. - * - is incremented by the size of the data to be written (no headers) - * each time a write urb is dispatched. - * - is decremented each time a "transmit empty" message is received - * by the driver in the data stream. - * @lock: Mutex to lock access to this structure when we need to ensure that - * races don't occur to access bits of it. - * @open_count: The number of uses of the port currently having - * it open, i.e. the reference count. - */ -struct quatech2_port { - int magic; - bool read_urb_busy; - bool close_pending; - __u8 shadowLSR; - __u8 shadowMSR; - bool rcv_flush; - bool xmit_flush; - int tx_pending_bytes; - struct mutex modelock; - int open_count; - - char active; /* someone has this device open */ - unsigned char *xfer_to_tty_buffer; - wait_queue_head_t wait; - __u8 shadowLCR; /* last LCR value received */ - __u8 shadowMCR; /* last MCR value received */ - char RxHolding; - struct semaphore pend_xmit_sem; /* locks this structure */ - spinlock_t lock; -}; - -/** - * Structure to hold device-wide internal status information - * @param ReadBulkStopped The last bulk read attempt ended in tears - * @param open_ports The number of serial ports currently in use on the box - * @param current_port Pointer to the serial port structure of the port which - * the read stream is currently directed to. Escape sequences in the read - * stream will change this around as data arrives from different ports on the - * box - * @buffer_size: The max size buffer each URB can take, used to set the size of - * the buffers allocated for writing to each port on the device (we need to - * store this because it is known only to the endpoint, but used each time a - * port is opened and a new buffer is allocated. - */ -struct quatech2_dev { - bool ReadBulkStopped; - char open_ports; - struct usb_serial_port *current_port; - int buffer_size; -}; - -/* structure which holds line and modem status flags */ -struct qt2_status_data { - __u8 line_status; - __u8 modem_status; -}; - -/* Function prototypes */ -static int qt2_boxpoweron(struct usb_serial *serial); -static int qt2_boxsetQMCR(struct usb_serial *serial, __u16 Uart_Number, - __u8 QMCR_Value); -static int port_paranoia_check(struct usb_serial_port *port, - const char *function); -static int serial_paranoia_check(struct usb_serial *serial, - const char *function); -static inline struct quatech2_port *qt2_get_port_private(struct usb_serial_port - *port); -static inline void qt2_set_port_private(struct usb_serial_port *port, - struct quatech2_port *data); -static inline struct quatech2_dev *qt2_get_dev_private(struct usb_serial - *serial); -static inline void qt2_set_dev_private(struct usb_serial *serial, - struct quatech2_dev *data); -static int qt2_openboxchannel(struct usb_serial *serial, __u16 - Uart_Number, struct qt2_status_data *pDeviceData); -static int qt2_closeboxchannel(struct usb_serial *serial, __u16 - Uart_Number); -static int qt2_conf_uart(struct usb_serial *serial, unsigned short Uart_Number, - unsigned short divisor, unsigned char LCR); -static void qt2_read_bulk_callback(struct urb *urb); -static void qt2_write_bulk_callback(struct urb *urb); -static void qt2_process_line_status(struct usb_serial_port *port, - unsigned char LineStatus); -static void qt2_process_modem_status(struct usb_serial_port *port, - unsigned char ModemStatus); -static void qt2_process_xmit_empty(struct usb_serial_port *port, - unsigned char fourth_char, unsigned char fifth_char); -static void qt2_process_port_change(struct usb_serial_port *port, - unsigned char New_Current_Port); -static void qt2_process_rcv_flush(struct usb_serial_port *port); -static void qt2_process_xmit_flush(struct usb_serial_port *port); -static void qt2_process_rx_char(struct usb_serial_port *port, - unsigned char data); -static int qt2_box_get_register(struct usb_serial *serial, - unsigned char uart_number, unsigned short register_num, - __u8 *pValue); -static int qt2_box_set_register(struct usb_serial *serial, - unsigned short Uart_Number, unsigned short Register_Num, - unsigned short Value); -static int qt2_boxsetuart(struct usb_serial *serial, unsigned short Uart_Number, - unsigned short default_divisor, unsigned char default_LCR); -static int qt2_boxsethw_flowctl(struct usb_serial *serial, - unsigned int UartNumber, bool bSet); -static int qt2_boxsetsw_flowctl(struct usb_serial *serial, __u16 UartNumber, - unsigned char stop_char, unsigned char start_char); -static int qt2_boxunsetsw_flowctl(struct usb_serial *serial, __u16 UartNumber); -static int qt2_boxstoprx(struct usb_serial *serial, unsigned short uart_number, - unsigned short stop); - -/* implementation functions, roughly in order of use, are here */ -static int qt2_calc_num_ports(struct usb_serial *serial) -{ - int num_ports; - int flag_as_400; - switch (serial->dev->descriptor.idProduct) { - case QUATECH_SSU2_100: - num_ports = 1; - break; - - case QUATECH_DSU2_400: - flag_as_400 = true; - case QUATECH_DSU2_100: - num_ports = 2; - break; - - case QUATECH_QSU2_400: - flag_as_400 = true; - case QUATECH_QSU2_100: - num_ports = 4; - break; - - case QUATECH_ESU2_400: - flag_as_400 = true; - case QUATECH_ESU2_100: - num_ports = 8; - break; - default: - num_ports = 1; - break; - } - return num_ports; -} - -static int qt2_attach(struct usb_serial *serial) -{ - struct usb_serial_port *port; - struct quatech2_port *qt2_port; /* port-specific private data pointer */ - struct quatech2_dev *qt2_dev; /* dev-specific private data pointer */ - int i; - /* stuff for storing endpoint addresses now */ - struct usb_endpoint_descriptor *endpoint; - struct usb_host_interface *iface_desc; - struct usb_serial_port *port0; /* first port structure on device */ - - /* check how many endpoints there are on the device, for - * sanity's sake */ - dbg("%s(): Endpoints: %d bulk in, %d bulk out, %d interrupt in", - __func__, serial->num_bulk_in, - serial->num_bulk_out, serial->num_interrupt_in); - if ((serial->num_bulk_in != 1) || (serial->num_bulk_out != 1)) { - dbg("Device has wrong number of bulk endpoints!"); - return -ENODEV; - } - iface_desc = serial->interface->cur_altsetting; - - /* Set up per-device private data, storing extra data alongside - * struct usb_serial */ - qt2_dev = kzalloc(sizeof(*qt2_dev), GFP_KERNEL); - if (!qt2_dev) { - dbg("%s: kmalloc for quatech2_dev failed!", - __func__); - return -ENOMEM; - } - qt2_dev->open_ports = 0; /* no ports open */ - qt2_set_dev_private(serial, qt2_dev); /* store private data */ - - /* Now setup per port private data, which replaces all the things - * that quatech added to standard kernel structures in their driver */ - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - qt2_port = kzalloc(sizeof(*qt2_port), GFP_KERNEL); - if (!qt2_port) { - dbg("%s: kmalloc for quatech2_port (%d) failed!.", - __func__, i); - return -ENOMEM; - } - /* initialise stuff in the structure */ - qt2_port->open_count = 0; /* port is not open */ - spin_lock_init(&qt2_port->lock); - mutex_init(&qt2_port->modelock); - qt2_set_port_private(port, qt2_port); - } - - /* gain access to port[0]'s structure because we want to store - * device-level stuff in it */ - if (serial_paranoia_check(serial, __func__)) - return -ENODEV; - port0 = serial->port[0]; /* get the first port's device structure */ - - /* print endpoint addresses so we can check them later - * by hand */ - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - if ((endpoint->bEndpointAddress & 0x80) && - ((endpoint->bmAttributes & 3) == 0x02)) { - /* we found a bulk in endpoint */ - dbg("found bulk in at %#.2x", - endpoint->bEndpointAddress); - } - - if (((endpoint->bEndpointAddress & 0x80) == 0x00) && - ((endpoint->bmAttributes & 3) == 0x02)) { - /* we found a bulk out endpoint */ - dbg("found bulk out at %#.2x", - endpoint->bEndpointAddress); - qt2_dev->buffer_size = endpoint->wMaxPacketSize; - /* max size of URB needs recording for the device */ - } - } /* end printing endpoint addresses */ - - /* switch on power to the hardware */ - if (qt2_boxpoweron(serial) < 0) { - dbg("qt2_boxpoweron() failed"); - goto startup_error; - } - /* set all ports to RS232 mode */ - for (i = 0; i < serial->num_ports; ++i) { - if (qt2_boxsetQMCR(serial, i, QU2BOX232) < 0) { - dbg("qt2_boxsetQMCR() on port %d failed", - i); - goto startup_error; - } - } - - return 0; - -startup_error: - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - qt2_port = qt2_get_port_private(port); - kfree(qt2_port); - qt2_set_port_private(port, NULL); - } - qt2_dev = qt2_get_dev_private(serial); - kfree(qt2_dev); - qt2_set_dev_private(serial, NULL); - - dbg("Exit fail %s\n", __func__); - return -EIO; -} - -static void qt2_release(struct usb_serial *serial) -{ - struct usb_serial_port *port; - struct quatech2_port *qt_port; - int i; - - dbg("enterting %s", __func__); - - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - if (!port) - continue; - - qt_port = usb_get_serial_port_data(port); - kfree(qt_port); - usb_set_serial_port_data(port, NULL); - } -} -/* This function is called once per serial port on the device, when - * that port is opened by a userspace application. - * The tty_struct and the usb_serial_port belong to this port, - * i.e. there are multiple ones for a multi-port device. - * However the usb_serial_port structure has a back-pointer - * to the parent usb_serial structure which belongs to the device, - * so we can access either the device-wide information or - * any other port's information (because there are also forward - * pointers) via that pointer. - * This is most helpful if the device shares resources (e.g. end - * points) between different ports - */ -int qt2_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct usb_serial *serial; /* device structure */ - struct usb_serial_port *port0; /* first port structure on device */ - struct quatech2_port *port_extra; /* extra data for this port */ - struct quatech2_port *port0_extra; /* extra data for first port */ - struct quatech2_dev *dev_extra; /* extra data for the device */ - struct qt2_status_data ChannelData; - unsigned short default_divisor = QU2BOXSPD9600; - unsigned char default_LCR = QT2_SERIAL_8_DATA; - int status; - int result; - - if (port_paranoia_check(port, __func__)) - return -ENODEV; - - dbg("%s(): port %d", __func__, port->number); - - serial = port->serial; /* get the parent device structure */ - if (serial_paranoia_check(serial, __func__)) { - dbg("usb_serial struct failed sanity check"); - return -ENODEV; - } - dev_extra = qt2_get_dev_private(serial); - /* get the device private data */ - if (dev_extra == NULL) { - dbg("device extra data pointer is null"); - return -ENODEV; - } - port0 = serial->port[0]; /* get the first port's device structure */ - if (port_paranoia_check(port0, __func__)) { - dbg("port0 usb_serial_port struct failed sanity check"); - return -ENODEV; - } - - port_extra = qt2_get_port_private(port); - port0_extra = qt2_get_port_private(port0); - if (port_extra == NULL || port0_extra == NULL) { - dbg("failed to get private data for port or port0"); - return -ENODEV; - } - - /* FIXME: are these needed? Does it even do anything useful? */ - /* get the modem and line status values from the UART */ - status = qt2_openboxchannel(serial, port->number, - &ChannelData); - if (status < 0) { - dbg("qt2_openboxchannel on channel %d failed", - port->number); - return status; - } - port_extra->shadowLSR = ChannelData.line_status & - (QT2_SERIAL_LSR_OE | QT2_SERIAL_LSR_PE | - QT2_SERIAL_LSR_FE | QT2_SERIAL_LSR_BI); - port_extra->shadowMSR = ChannelData.modem_status & - (QT2_SERIAL_MSR_CTS | QT2_SERIAL_MSR_DSR | - QT2_SERIAL_MSR_RI | QT2_SERIAL_MSR_CD); - -/* port_extra->fifo_empty_flag = true;*/ - dbg("qt2_openboxchannel on channel %d completed.", - port->number); - - /* Set Baud rate to default and turn off flow control here */ - status = qt2_conf_uart(serial, port->number, default_divisor, - default_LCR); - if (status < 0) { - dbg("qt2_conf_uart() failed on channel %d", - port->number); - return status; - } - dbg("qt2_conf_uart() completed on channel %d", - port->number); - - /* - * At this point we will need some end points to make further progress. - * Handlily, the correct endpoint addresses have been filled out into - * the usb_serial_port structure for us by the driver core, so we - * already have access to them. - * As there is only one bulk in and one bulk out end-point, these are in - * port[0]'s structure, and the rest are uninitialised. Handily, - * when we do a write to a port, we will use the same endpoint - * regardless of the port, with a 5-byte header added on to - * tell the box which port it should eventually come out of, so we only - * need the one set of endpoints. We will have one URB per port for - * writing, so that multiple ports can be writing at once. - * Finally we need a bulk in URB to use for background reads from the - * device, which will deal with uplink data from the box to host. - */ - dbg("port0 bulk in endpoint is %#.2x", port0->bulk_in_endpointAddress); - dbg("port0 bulk out endpoint is %#.2x", - port0->bulk_out_endpointAddress); - - /* set up write_urb for bulk out transfers on this port. The USB - * serial framework will have allocated a blank URB, buffer etc for - * port0 when it put the endpoints there, but not for any of the other - * ports on the device because there are no more endpoints. Thus we - * have to allocate our own URBs for ports 1-7 - */ - if (port->write_urb == NULL) { - dbg("port->write_urb == NULL, allocating one"); - port->write_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!port->write_urb) { - err("Allocating write URB failed"); - return -ENOMEM; - } - /* buffer same size as port0 */ - port->bulk_out_size = dev_extra->buffer_size; - port->bulk_out_buffer = kmalloc(port->bulk_out_size, - GFP_KERNEL); - if (!port->bulk_out_buffer) { - err("Couldn't allocate bulk_out_buffer"); - return -ENOMEM; - } - } - if (serial->dev == NULL) - dbg("serial->dev == NULL"); - dbg("port->bulk_out_size is %d", port->bulk_out_size); - - usb_fill_bulk_urb(port->write_urb, serial->dev, - usb_sndbulkpipe(serial->dev, - port0->bulk_out_endpointAddress), - port->bulk_out_buffer, - port->bulk_out_size, - qt2_write_bulk_callback, - port); - port_extra->tx_pending_bytes = 0; - - if (dev_extra->open_ports == 0) { - /* this is first port to be opened, so need the read URB - * initialised for bulk in transfers (this is shared amongst - * all the ports on the device) */ - usb_fill_bulk_urb(port0->read_urb, serial->dev, - usb_rcvbulkpipe(serial->dev, - port0->bulk_in_endpointAddress), - port0->bulk_in_buffer, - port0->bulk_in_size, - qt2_read_bulk_callback, serial); - dbg("port0 bulk in URB initialised"); - - /* submit URB, i.e. start reading from device (async) */ - dev_extra->ReadBulkStopped = false; - port_extra->read_urb_busy = true; - result = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (result) { - dev_err(&port->dev, - "%s(): Error %d submitting bulk in urb", - __func__, result); - port_extra->read_urb_busy = false; - dev_extra->ReadBulkStopped = true; - } - - /* When the first port is opened, initialise the value of - * current_port in dev_extra to this port, so it is set - * to something. Once the box sends data it will send the - * relevant escape sequences to get it to the right port anyway - */ - dev_extra->current_port = port; - } - - /* initialize our wait queues */ - init_waitqueue_head(&port_extra->wait); - /* increment the count of openings of this port by one */ - port_extra->open_count++; - - /* remember to store dev_extra, port_extra and port0_extra back again at - * end !*/ - qt2_set_port_private(port, port_extra); - qt2_set_port_private(serial->port[0], port0_extra); - qt2_set_dev_private(serial, dev_extra); - - dev_extra->open_ports++; /* one more port opened */ - - return 0; -} - -/* called when a port is closed by userspace. It won't be called, however, - * until calls to chars_in_buffer() reveal that the port has completed - * sending buffered data, and there is nothing else to do. Thus we don't have - * to rely on forcing data through in this function. */ -/* Setting close_pending should keep new data from being written out, - * once all the data in the enpoint buffers is moved out we won't get - * any more. */ -/* BoxStopReceive would keep any more data from coming from a given - * port, but isn't called by the vendor driver, although their comments - * mention it. Should it be used here to stop the inbound data - * flow? - */ -static void qt2_close(struct usb_serial_port *port) -{ - /* time out value for flush loops */ - unsigned long jift; - struct quatech2_port *port_extra; /* extra data for this port */ - struct usb_serial *serial; /* device structure */ - struct quatech2_dev *dev_extra; /* extra data for the device */ - __u8 lsr_value = 0; /* value of Line Status Register */ - int status; /* result of last USB comms function */ - - dbg("%s(): port %d", __func__, port->number); - serial = port->serial; /* get the parent device structure */ - dev_extra = qt2_get_dev_private(serial); - /* get the device private data */ - port_extra = qt2_get_port_private(port); /* port private data */ - - /* we can now (and only now) stop reading data */ - port_extra->close_pending = true; - dbg("%s(): port_extra->close_pending = true", __func__); - /* although the USB side is now empty, the UART itself may - * still be pushing characters out over the line, so we have to - * wait testing the actual line status until the lines change - * indicating that the data is done transferring. */ - /* FIXME: slow this polling down so it doesn't run the USB bus flat out - * if it actually has to spend any time in this loop (which it normally - * doesn't because the buffer is nearly empty) */ - jift = jiffies + (10 * HZ); /* 10 sec timeout */ - do { - status = qt2_box_get_register(serial, port->number, - QT2_LINE_STATUS_REGISTER, &lsr_value); - if (status < 0) { - dbg("%s(): qt2_box_get_register failed", __func__); - break; - } - if ((lsr_value & QT2_LSR_TEMT)) { - dbg("UART done sending"); - break; - } - schedule(); - } while (jiffies <= jift); - - status = qt2_closeboxchannel(serial, port->number); - if (status < 0) - dbg("%s(): port %d qt2_box_open_close_channel failed", - __func__, port->number); - /* to avoid leaking URBs, we should now free the write_urb for this - * port and set the pointer to null so that next time the port is opened - * a new URB is allocated. This avoids leaking URBs when the device is - * removed */ - usb_free_urb(port->write_urb); - kfree(port->bulk_out_buffer); - port->bulk_out_buffer = NULL; - port->bulk_out_size = 0; - - /* decrement the count of openings of this port by one */ - port_extra->open_count--; - /* one less overall open as well */ - dev_extra->open_ports--; - dbg("%s(): Exit, dev_extra->open_ports = %d", __func__, - dev_extra->open_ports); -} - -/** - * qt2_write - write bytes from the tty layer out to the USB device. - * @buf: The data to be written, size at least count. - * @count: The number of bytes requested for transmission. - * @return The number of bytes actually accepted for transmission to the device. - */ -static int qt2_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - struct usb_serial *serial; /* parent device struct */ - __u8 header_array[5]; /* header used to direct writes to the correct - port on the device */ - struct quatech2_port *port_extra; /* extra data for this port */ - int result; - - serial = port->serial; /* get the parent device of the port */ - port_extra = qt2_get_port_private(port); /* port extra info */ - if (serial == NULL) - return -ENODEV; - dbg("%s(): port %d, requested to write %d bytes, %d already pending", - __func__, port->number, count, port_extra->tx_pending_bytes); - - if (count <= 0) { - dbg("%s(): write request of <= 0 bytes", __func__); - return 0; /* no bytes written */ - } - - /* check if the write urb is already in use, i.e. data already being - * sent to this port */ - if ((port->write_urb->status == -EINPROGRESS)) { - /* Fifo hasn't been emptied since last write to this port */ - dbg("%s(): already writing, port->write_urb->status == " - "-EINPROGRESS", __func__); - /* schedule_work(&port->work); commented in vendor driver */ - return 0; - } else if (port_extra->tx_pending_bytes >= QT2_FIFO_DEPTH) { - /* buffer is full (==). > should not occur, but would indicate - * that an overflow had occurred */ - dbg("%s(): port transmit buffer is full!", __func__); - /* schedule_work(&port->work); commented in vendor driver */ - return 0; - } - - /* We must fill the first 5 bytes of anything we sent with a transmit - * header which directes the data to the correct port. The maximum - * size we can send out in one URB is port->bulk_out_size, which caps - * the number of bytes of real data we can send in each write. As the - * semantics of write allow us to write less than we were give, we cap - * the maximum we will ever write to the device as 5 bytes less than - * one URB's worth, by reducing the value of the count argument - * appropriately*/ - if (count > port->bulk_out_size - QT2_TX_HEADER_LENGTH) { - count = port->bulk_out_size - QT2_TX_HEADER_LENGTH; - dbg("%s(): write request bigger than urb, only accepting " - "%d bytes", __func__, count); - } - /* we must also ensure that the FIFO at the other end can cope with the - * URB we send it, otherwise it will have problems. As above, we can - * restrict the write size by just shrinking count.*/ - if (count > (QT2_FIFO_DEPTH - port_extra->tx_pending_bytes)) { - count = QT2_FIFO_DEPTH - port_extra->tx_pending_bytes; - dbg("%s(): not enough room in buffer, only accepting %d bytes", - __func__, count); - } - /* now build the header for transmission */ - header_array[0] = 0x1b; - header_array[1] = 0x1b; - header_array[2] = (__u8)port->number; - header_array[3] = (__u8)count; - header_array[4] = (__u8)count >> 8; - /* copy header into URB */ - memcpy(port->write_urb->transfer_buffer, header_array, - QT2_TX_HEADER_LENGTH); - /* and actual data to write */ - memcpy(port->write_urb->transfer_buffer + 5, buf, count); - - dbg("%s(): first data byte to send = %#.2x", __func__, *buf); - - /* set up our urb */ - usb_fill_bulk_urb(port->write_urb, serial->dev, - usb_sndbulkpipe(serial->dev, - port->bulk_out_endpointAddress), - port->write_urb->transfer_buffer, count + 5, - (qt2_write_bulk_callback), port); - /* send the data out the bulk port */ - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (result) { - /* error couldn't submit urb */ - result = 0; /* return 0 as nothing got written */ - dbg("%s(): failed submitting write urb, error %d", - __func__, result); - } else { - port_extra->tx_pending_bytes += count; - result = count; /* return number of bytes written, i.e. count */ - dbg("%s(): submitted write urb, wrote %d bytes, " - "total pending bytes %d", - __func__, result, port_extra->tx_pending_bytes); - } - return result; -} - -/* This is used by the next layer up to know how much space is available - * in the buffer on the device. It is used on a device closure to avoid - * calling close() until the buffer is reported to be empty. - * The returned value must never go down by more than the number of bytes - * written for correct behaviour further up the driver stack, i.e. if I call - * it, then write 6 bytes, then call again I should get 6 less, or possibly - * only 5 less if one was written in the meantime, etc. I should never get 7 - * less (or any bigger number) because I only wrote 6 bytes. - */ -static int qt2_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - /* parent usb_serial_port pointer */ - struct quatech2_port *port_extra; /* extra data for this port */ - int room = 0; - port_extra = qt2_get_port_private(port); - - if (port_extra->close_pending == true) { - dbg("%s(): port_extra->close_pending == true", __func__); - return -ENODEV; - } - /* Q: how many bytes would a write() call actually succeed in writing - * if it happened now? - * A: one QT2_FIFO_DEPTH, less the number of bytes waiting to be sent - * out of the port, unless this is more than the size of the - * write_urb output buffer less the header, which is the maximum - * size write we can do. - - * Most of the implementation of this is done when writes to the device - * are started or terminate. When we send a write to the device, we - * reduce the free space count by the size of the dispatched write. - * When a "transmit empty" message comes back up the USB read stream, - * we decrement the count by the number of bytes reported sent, thus - * keeping track of the difference between sent and received bytes. - */ - - room = (QT2_FIFO_DEPTH - port_extra->tx_pending_bytes); - /* space in FIFO */ - if (room > port->bulk_out_size - QT2_TX_HEADER_LENGTH) - room = port->bulk_out_size - QT2_TX_HEADER_LENGTH; - /* if more than the URB can hold, then cap to that limit */ - - dbg("%s(): port %d: write room is %d", __func__, port->number, room); - return room; -} - -static int qt2_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - /* parent usb_serial_port pointer */ - struct quatech2_port *port_extra; /* extra data for this port */ - port_extra = qt2_get_port_private(port); - - dbg("%s(): port %d: chars_in_buffer = %d", __func__, - port->number, port_extra->tx_pending_bytes); - return port_extra->tx_pending_bytes; -} - -/* called when userspace does an ioctl() on the device. Note that - * TIOCMGET and TIOCMSET are filtered off to their own methods before they get - * here, so we don't have to handle them. - */ -static int qt2_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; - __u8 mcr_value; /* Modem Control Register value */ - __u8 msr_value; /* Modem Status Register value */ - unsigned short prev_msr_value; /* Previous value of Modem Status - * Register used to implement waiting for a line status change to - * occur */ - struct quatech2_port *port_extra; /* extra data for this port */ - DECLARE_WAITQUEUE(wait, current); - /* Declare a wait queue named "wait" */ - - unsigned int value; - unsigned int UartNumber; - - if (serial == NULL) - return -ENODEV; - UartNumber = tty->index - serial->minor; - port_extra = qt2_get_port_private(port); - - dbg("%s(): port %d, UartNumber %d, tty =0x%p", __func__, - port->number, UartNumber, tty); - - if (cmd == TIOCMBIS || cmd == TIOCMBIC) { - if (qt2_box_get_register(port->serial, UartNumber, - QT2_MODEM_CONTROL_REGISTER, &mcr_value) < 0) - return -ESPIPE; - if (copy_from_user(&value, (unsigned int *)arg, - sizeof(value))) - return -EFAULT; - - switch (cmd) { - case TIOCMBIS: - if (value & TIOCM_RTS) - mcr_value |= QT2_SERIAL_MCR_RTS; - if (value & TIOCM_DTR) - mcr_value |= QT2_SERIAL_MCR_DTR; - if (value & TIOCM_LOOP) - mcr_value |= QT2_SERIAL_MCR_LOOP; - break; - case TIOCMBIC: - if (value & TIOCM_RTS) - mcr_value &= ~QT2_SERIAL_MCR_RTS; - if (value & TIOCM_DTR) - mcr_value &= ~QT2_SERIAL_MCR_DTR; - if (value & TIOCM_LOOP) - mcr_value &= ~QT2_SERIAL_MCR_LOOP; - break; - default: - break; - } /* end of local switch on cmd */ - if (qt2_box_set_register(port->serial, UartNumber, - QT2_MODEM_CONTROL_REGISTER, mcr_value) < 0) { - return -ESPIPE; - } else { - port_extra->shadowMCR = mcr_value; - return 0; - } - } else if (cmd == TIOCMIWAIT) { - dbg("%s() port %d, cmd == TIOCMIWAIT enter", - __func__, port->number); - prev_msr_value = port_extra->shadowMSR & QT2_SERIAL_MSR_MASK; - barrier(); - __set_current_state(TASK_INTERRUPTIBLE); - while (1) { - add_wait_queue(&port_extra->wait, &wait); - schedule(); - dbg("%s(): port %d, cmd == TIOCMIWAIT here\n", - __func__, port->number); - remove_wait_queue(&port_extra->wait, &wait); - /* see if a signal woke us up */ - if (signal_pending(current)) - return -ERESTARTSYS; - set_current_state(TASK_INTERRUPTIBLE); - msr_value = port_extra->shadowMSR & QT2_SERIAL_MSR_MASK; - if (msr_value == prev_msr_value) { - __set_current_state(TASK_RUNNING); - return -EIO; /* no change - error */ - } - if ((arg & TIOCM_RNG && - ((prev_msr_value & QT2_SERIAL_MSR_RI) == - (msr_value & QT2_SERIAL_MSR_RI))) || - (arg & TIOCM_DSR && - ((prev_msr_value & QT2_SERIAL_MSR_DSR) == - (msr_value & QT2_SERIAL_MSR_DSR))) || - (arg & TIOCM_CD && - ((prev_msr_value & QT2_SERIAL_MSR_CD) == - (msr_value & QT2_SERIAL_MSR_CD))) || - (arg & TIOCM_CTS && - ((prev_msr_value & QT2_SERIAL_MSR_CTS) == - (msr_value & QT2_SERIAL_MSR_CTS)))) { - __set_current_state(TASK_RUNNING); - return 0; - } - } /* end inifinite while */ - /* FIXME: This while loop needs a way to break out if the device - * is disconnected while a process is waiting for the MSR to - * change, because once it's disconnected, it isn't going to - * change state ... */ - } else { - /* any other ioctls we don't know about come here */ - dbg("%s(): No ioctl for that one. port = %d", __func__, - port->number); - return -ENOIOCTLCMD; - } -} - -/* Called when the user wishes to change the port settings using the termios - * userspace interface */ -static void qt2_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) -{ - struct usb_serial *serial; /* parent serial device */ - int baud, divisor, remainder; - unsigned char LCR_change_to = 0; - int status; - __u16 UartNumber; - - dbg("%s(): port %d", __func__, port->number); - - serial = port->serial; - - UartNumber = port->number; - - if (old_termios && !tty_termios_hw_change(old_termios, tty->termios)) - return; - - switch (tty->termios->c_cflag) { - case CS5: - LCR_change_to |= QT2_SERIAL_5_DATA; - break; - case CS6: - LCR_change_to |= QT2_SERIAL_6_DATA; - break; - case CS7: - LCR_change_to |= QT2_SERIAL_7_DATA; - break; - default: - case CS8: - LCR_change_to |= QT2_SERIAL_8_DATA; - break; - } - - /* Parity stuff */ - if (tty->termios->c_cflag & PARENB) { - if (tty->termios->c_cflag & PARODD) - LCR_change_to |= QT2_SERIAL_ODD_PARITY; - else - LCR_change_to |= QT2_SERIAL_EVEN_PARITY; - } - /* Because LCR_change_to is initialised to zero, we don't have to worry - * about the case where PARENB is not set or clearing bits, because by - * default all of them are cleared, turning parity off. - * as we don't support mark/space parity, we should clear the - * mark/space parity bit in c_cflag, so the caller can tell we have - * ignored the request */ - tty->termios->c_cflag &= ~CMSPAR; - - if (tty->termios->c_cflag & CSTOPB) - LCR_change_to |= QT2_SERIAL_TWO_STOPB; - else - LCR_change_to |= QT2_SERIAL_ONE_STOPB; - - /* Thats the LCR stuff, next we need to work out the divisor as the - * LCR and the divisor are set together */ - baud = tty_get_baud_rate(tty); - if (!baud) { - /* pick a default, any default... */ - baud = 9600; - } - dbg("%s(): got baud = %d", __func__, baud); - - divisor = QT2_MAX_BAUD_RATE / baud; - remainder = QT2_MAX_BAUD_RATE % baud; - /* Round to nearest divisor */ - if (((remainder * 2) >= baud) && (baud != 110)) - divisor++; - dbg("%s(): setting divisor = %d, QT2_MAX_BAUD_RATE = %d , LCR = %#.2x", - __func__, divisor, QT2_MAX_BAUD_RATE, LCR_change_to); - - status = qt2_boxsetuart(serial, UartNumber, (unsigned short) divisor, - LCR_change_to); - if (status < 0) { - dbg("qt2_boxsetuart() failed"); - return; - } else { - /* now encode the baud rate we actually set, which may be - * different to the request */ - baud = QT2_MAX_BAUD_RATE / divisor; - tty_encode_baud_rate(tty, baud, baud); - } - - /* Now determine flow control */ - if (tty->termios->c_cflag & CRTSCTS) { - dbg("%s(): Enabling HW flow control port %d", __func__, - port->number); - /* Enable RTS/CTS flow control */ - status = qt2_boxsethw_flowctl(serial, UartNumber, true); - if (status < 0) { - dbg("qt2_boxsethw_flowctl() failed"); - return; - } - } else { - /* Disable RTS/CTS flow control */ - dbg("%s(): disabling HW flow control port %d", __func__, - port->number); - status = qt2_boxsethw_flowctl(serial, UartNumber, false); - if (status < 0) { - dbg("qt2_boxsethw_flowctl failed"); - return; - } - } - /* if we are implementing XON/XOFF, set the start and stop character - * in the device */ - if (I_IXOFF(tty) || I_IXON(tty)) { - unsigned char stop_char = STOP_CHAR(tty); - unsigned char start_char = START_CHAR(tty); - status = qt2_boxsetsw_flowctl(serial, UartNumber, stop_char, - start_char); - if (status < 0) - dbg("qt2_boxsetsw_flowctl (enabled) failed"); - } else { - /* disable SW flow control */ - status = qt2_boxunsetsw_flowctl(serial, UartNumber); - if (status < 0) - dbg("qt2_boxunsetsw_flowctl (disabling) failed"); - } -} - -static int qt2_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; - - __u8 mcr_value; /* Modem Control Register value */ - __u8 msr_value; /* Modem Status Register value */ - unsigned int result = 0; - int status; - unsigned int UartNumber; - - if (serial == NULL) - return -ENODEV; - - dbg("%s(): port %d, tty =0x%p", __func__, port->number, tty); - UartNumber = tty->index - serial->minor; - dbg("UartNumber is %d", UartNumber); - - status = qt2_box_get_register(port->serial, UartNumber, - QT2_MODEM_CONTROL_REGISTER, &mcr_value); - if (status >= 0) { - status = qt2_box_get_register(port->serial, UartNumber, - QT2_MODEM_STATUS_REGISTER, &msr_value); - } - if (status >= 0) { - result = ((mcr_value & QT2_SERIAL_MCR_DTR) ? TIOCM_DTR : 0) - /*DTR set */ - | ((mcr_value & QT2_SERIAL_MCR_RTS) ? TIOCM_RTS : 0) - /*RTS set */ - | ((msr_value & QT2_SERIAL_MSR_CTS) ? TIOCM_CTS : 0) - /* CTS set */ - | ((msr_value & QT2_SERIAL_MSR_CD) ? TIOCM_CAR : 0) - /*Carrier detect set */ - | ((msr_value & QT2_SERIAL_MSR_RI) ? TIOCM_RI : 0) - /* Ring indicator set */ - | ((msr_value & QT2_SERIAL_MSR_DSR) ? TIOCM_DSR : 0); - /* DSR set */ - return result; - } else { - return -ESPIPE; - } -} - -static int qt2_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; - __u8 mcr_value; /* Modem Control Register value */ - int status; - unsigned int UartNumber; - - if (serial == NULL) - return -ENODEV; - - UartNumber = tty->index - serial->minor; - dbg("%s(): port %d, UartNumber %d", __func__, port->number, UartNumber); - - status = qt2_box_get_register(port->serial, UartNumber, - QT2_MODEM_CONTROL_REGISTER, &mcr_value); - if (status < 0) - return -ESPIPE; - - /* Turn off RTS, DTR and loopback, then only turn on what was asked - * for */ - mcr_value &= ~(QT2_SERIAL_MCR_RTS | QT2_SERIAL_MCR_DTR | - QT2_SERIAL_MCR_LOOP); - if (set & TIOCM_RTS) - mcr_value |= QT2_SERIAL_MCR_RTS; - if (set & TIOCM_DTR) - mcr_value |= QT2_SERIAL_MCR_DTR; - if (set & TIOCM_LOOP) - mcr_value |= QT2_SERIAL_MCR_LOOP; - - status = qt2_box_set_register(port->serial, UartNumber, - QT2_MODEM_CONTROL_REGISTER, mcr_value); - if (status < 0) - return -ESPIPE; - else - return 0; -} - -/** qt2_break - Turn BREAK on and off on the UARTs - */ -static void qt2_break(struct tty_struct *tty, int break_state) -{ - struct usb_serial_port *port = tty->driver_data; /* parent port */ - struct usb_serial *serial = port->serial; /* parent device */ - struct quatech2_port *port_extra; /* extra data for this port */ - __u16 break_value; - unsigned int result; - - port_extra = qt2_get_port_private(port); - if (!serial) { - dbg("%s(): port %d: no serial object", __func__, port->number); - return; - } - - if (break_state == -1) - break_value = 1; - else - break_value = 0; - dbg("%s(): port %d, break_value %d", __func__, port->number, - break_value); - - mutex_lock(&port_extra->modelock); - if (!port_extra->open_count) { - dbg("%s(): port not open", __func__); - goto exit; - } - - result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - QT2_BREAK_CONTROL, 0x40, break_value, - port->number, NULL, 0, 300); -exit: - mutex_unlock(&port_extra->modelock); - dbg("%s(): exit port %d", __func__, port->number); - -} -/** - * qt2_throttle: - stop reading new data from the port - */ -static void qt2_throttle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; - struct quatech2_port *port_extra; /* extra data for this port */ - dbg("%s(): port %d", __func__, port->number); - - port_extra = qt2_get_port_private(port); - if (!serial) { - dbg("%s(): enter port %d no serial object", __func__, - port->number); - return; - } - - mutex_lock(&port_extra->modelock); /* lock structure */ - if (!port_extra->open_count) { - dbg("%s(): port not open", __func__); - goto exit; - } - /* Send command to box to stop receiving stuff. This will stop this - * particular UART from filling the endpoint - in the multiport case the - * FPGA UART will handle any flow control implemented, but for the single - * port it's handed differently and we just quit submitting urbs - */ - if (serial->dev->descriptor.idProduct != QUATECH_SSU2_100) - qt2_boxstoprx(serial, port->number, 1); - - port->throttled = 1; -exit: - mutex_unlock(&port_extra->modelock); - dbg("%s(): port %d: setting port->throttled", __func__, port->number); - return; -} - -/** - * qt2_unthrottle: - start receiving data through the port again after being - * throttled - */ -static void qt2_unthrottle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; - struct quatech2_port *port_extra; /* extra data for this port */ - struct usb_serial_port *port0; /* first port structure on device */ - struct quatech2_dev *dev_extra; /* extra data for the device */ - - if (!serial) { - dbg("%s() enter port %d no serial object!", __func__, - port->number); - return; - } - dbg("%s(): enter port %d", __func__, port->number); - dev_extra = qt2_get_dev_private(serial); - port_extra = qt2_get_port_private(port); - port0 = serial->port[0]; /* get the first port's device structure */ - - mutex_lock(&port_extra->modelock); - if (!port_extra->open_count) { - dbg("%s(): port %d not open", __func__, port->number); - goto exit; - } - - if (port->throttled != 0) { - dbg("%s(): port %d: unsetting port->throttled", __func__, - port->number); - port->throttled = 0; - /* Send command to box to start receiving stuff */ - if (serial->dev->descriptor.idProduct != QUATECH_SSU2_100) { - qt2_boxstoprx(serial, port->number, 0); - } else if (dev_extra->ReadBulkStopped == true) { - usb_fill_bulk_urb(port0->read_urb, serial->dev, - usb_rcvbulkpipe(serial->dev, - port0->bulk_in_endpointAddress), - port0->bulk_in_buffer, - port0->bulk_in_size, - qt2_read_bulk_callback, - serial); - } - } -exit: - mutex_unlock(&port_extra->modelock); - dbg("%s(): exit port %d", __func__, port->number); - return; -} - -/* internal, private helper functions for the driver */ - -/* Power up the FPGA in the box to get it working */ -static int qt2_boxpoweron(struct usb_serial *serial) -{ - int result; - __u8 Direcion; - unsigned int pipe; - Direcion = USBD_TRANSFER_DIRECTION_OUT; - pipe = usb_rcvctrlpipe(serial->dev, 0); - result = usb_control_msg(serial->dev, pipe, QT_SET_GET_DEVICE, - Direcion, QU2BOXPWRON, 0x00, NULL, 0x00, - 5000); - return result; -} - -/* - * qt2_boxsetQMCR Issue a QT2_GET_SET_QMCR vendor-spcific request on the - * default control pipe. If successful return the number of bytes written, - * otherwise return a negative error number of the problem. - */ -static int qt2_boxsetQMCR(struct usb_serial *serial, __u16 Uart_Number, - __u8 QMCR_Value) -{ - int result; - __u16 PortSettings; - - PortSettings = (__u16)(QMCR_Value); - - dbg("%s(): Port = %d, PortSettings = 0x%x", __func__, - Uart_Number, PortSettings); - - result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - QT2_GET_SET_QMCR, 0x40, PortSettings, - (__u16)Uart_Number, NULL, 0, 5000); - return result; -} - -static int port_paranoia_check(struct usb_serial_port *port, - const char *function) -{ - if (!port) { - dbg("%s - port == NULL", function); - return -1; - } - if (!port->serial) { - dbg("%s - port->serial == NULL\n", function); - return -1; - } - return 0; -} - -static int serial_paranoia_check(struct usb_serial *serial, - const char *function) -{ - if (!serial) { - dbg("%s - serial == NULL\n", function); - return -1; - } - - if (!serial->type) { - dbg("%s - serial->type == NULL!", function); - return -1; - } - - return 0; -} - -static inline struct quatech2_port *qt2_get_port_private(struct usb_serial_port - *port) -{ - return (struct quatech2_port *)usb_get_serial_port_data(port); -} - -static inline void qt2_set_port_private(struct usb_serial_port *port, - struct quatech2_port *data) -{ - usb_set_serial_port_data(port, (void *)data); -} - -static inline struct quatech2_dev *qt2_get_dev_private(struct usb_serial - *serial) -{ - return (struct quatech2_dev *)usb_get_serial_data(serial); -} -static inline void qt2_set_dev_private(struct usb_serial *serial, - struct quatech2_dev *data) -{ - usb_set_serial_data(serial, (void *)data); -} - -static int qt2_openboxchannel(struct usb_serial *serial, __u16 - Uart_Number, struct qt2_status_data *status) -{ - int result; - __u16 length; - __u8 Direcion; - unsigned int pipe; - length = sizeof(struct qt2_status_data); - Direcion = USBD_TRANSFER_DIRECTION_IN; - pipe = usb_rcvctrlpipe(serial->dev, 0); - result = usb_control_msg(serial->dev, pipe, QT_OPEN_CLOSE_CHANNEL, - Direcion, 0x00, Uart_Number, status, length, 5000); - return result; -} -static int qt2_closeboxchannel(struct usb_serial *serial, __u16 Uart_Number) -{ - int result; - __u8 direcion; - unsigned int pipe; - direcion = USBD_TRANSFER_DIRECTION_OUT; - pipe = usb_sndctrlpipe(serial->dev, 0); - result = usb_control_msg(serial->dev, pipe, QT_OPEN_CLOSE_CHANNEL, - direcion, 0, Uart_Number, NULL, 0, 5000); - return result; -} - -/* qt2_conf_uart Issue a SET_UART vendor-spcific request on the default - * control pipe. If successful sets baud rate divisor and LCR value - */ -static int qt2_conf_uart(struct usb_serial *serial, unsigned short Uart_Number, - unsigned short divisor, unsigned char LCR) -{ - int result; - unsigned short UartNumandLCR; - - UartNumandLCR = (LCR << 8) + Uart_Number; - - result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - QT2_GET_SET_UART, 0x40, divisor, UartNumandLCR, - NULL, 0, 300); - return result; -} - -/** @brief Callback for asynchronous submission of read URBs on bulk in - * endpoints - * - * Registered in qt2_open_port(), used to deal with incomming data - * from the box. - */ -static void qt2_read_bulk_callback(struct urb *urb) -{ - /* Get the device pointer (struct usb_serial) back out of the URB */ - struct usb_serial *serial = urb->context; - /* get the extra struct for the device */ - struct quatech2_dev *dev_extra = qt2_get_dev_private(serial); - /* Get first port structure from the device */ - struct usb_serial_port *port0 = serial->port[0]; - /* Get the currently active port structure from serial struct */ - struct usb_serial_port *active = dev_extra->current_port; - /* get the extra struct for port 0 */ - struct quatech2_port *port0_extra = qt2_get_port_private(port0); - /* and for the currently active port */ - struct quatech2_port *active_extra = qt2_get_port_private(active); - /* When we finally get to doing some tty stuff, we will need this */ - struct tty_struct *tty_st; - unsigned int RxCount; /* the length of the data to process */ - unsigned int i; /* loop counter over the data to process */ - int result; /* return value cache variable */ - bool escapeflag; /* flag set to true if this loop iteration is - * parsing an escape sequence, rather than - * ordinary data */ - dbg("%s(): callback running, active port is %d", __func__, - active->number); - - if (urb->status) { - /* read didn't go well */ - dev_extra->ReadBulkStopped = true; - dbg("%s(): nonzero bulk read status received: %d", - __func__, urb->status); - return; - } - - /* inline port_sofrint() here */ - if (port_paranoia_check(port0, __func__) != 0) { - dbg("%s - port_paranoia_check on port0 failed, exiting\n", -__func__); - return; - } - if (port_paranoia_check(active, __func__) != 0) { - dbg("%s - port_paranoia_check on current_port " - "failed, exiting", __func__); - return; - } - -/* This single callback function has to do for all the ports on - * the device. Data being read up the USB can contain certain - * escape sequences which are used to communicate out-of-band - * information from the serial port in-band over the USB. - * These escapes include sending modem and flow control line - * status, and switching the port. The concept of a "Current Port" - * is used, which is where data is going until a port change - * escape seqence is received. This Current Port is kept between - * callbacks so that when this function enters we know which the - * currently active port is and can get to work right away without - * the box having to send repeat escape sequences (anyway, how - * would it know to do so?). - */ - - if (active_extra->close_pending == true) { - /* We are closing , stop reading */ - dbg("%s - (active->close_pending == true", __func__); - if (dev_extra->open_ports <= 0) { - /* If this is the only port left open - stop the - * bulk read */ - dev_extra->ReadBulkStopped = true; - dbg("%s - (ReadBulkStopped == true;", __func__); - return; - } - } - - /* - * RxHolding is asserted by throttle, if we assert it, we're not - * receiving any more characters and let the box handle the flow - * control - */ - if ((port0_extra->RxHolding == true) && - (serial->dev->descriptor.idProduct == QUATECH_SSU2_100)) { - /* single port device, input is already stopped, so we don't - * need any more input data */ - dev_extra->ReadBulkStopped = true; - return; - } - /* finally, we are in a situation where we might consider the data - * that is contained within the URB, and what to do about it. - * This is likely to involved communicating up to the TTY layer, so - * we will need to get hold of the tty for the port we are currently - * dealing with */ - - /* active is a usb_serial_port. It has a member port which is a - * tty_port. From this we get a tty_struct pointer which is what we - * actually wanted, and keep it on tty_st */ - tty_st = tty_port_tty_get(&active->port); - if (!tty_st) { - dbg("%s - bad tty pointer - exiting", __func__); - return; - } - RxCount = urb->actual_length; /* grab length of data handy */ - - if (RxCount) { - /* skip all this if no data to process */ - for (i = 0; i < RxCount ; ++i) { - /* Look ahead code here -works on several bytes at onc*/ - if ((i <= (RxCount - 3)) && (THISCHAR == 0x1b) - && (NEXTCHAR == 0x1b)) { - /* we are in an escape sequence, type - * determined by the 3rd char */ - escapeflag = false; - switch (THIRDCHAR) { - case 0x00: - /* Line status change 4th byte must - * follow */ - if (i > (RxCount - 4)) { - dbg("Illegal escape sequences " - "in received data"); - break; - } - qt2_process_line_status(active, - FOURTHCHAR); - i += 3; - escapeflag = true; - break; - case 0x01: - /* Modem status status change 4th byte - * must follow */ - if (i > (RxCount - 4)) { - dbg("Illegal escape sequences " - "in received data"); - break; - } - qt2_process_modem_status(active, - FOURTHCHAR); - i += 3; - escapeflag = true; - break; - case 0x02: - /* xmit hold empty 4th byte - * must follow */ - if (i > (RxCount - 4)) { - dbg("Illegal escape sequences " - "in received data"); - break; - } - qt2_process_xmit_empty(active, - FOURTHCHAR, FIFTHCHAR); - i += 4; - escapeflag = true; - break; - case 0x03: - /* Port number change 4th byte - * must follow */ - if (i > (RxCount - 4)) { - dbg("Illegal escape sequences " - "in received data"); - break; - } - /* Port change. If port open push - * current data up to tty layer */ - if (active_extra->open_count > 0) - tty_flip_buffer_push(tty_st); - - dbg("Port Change: new port = %d", - FOURTHCHAR); - qt2_process_port_change(active, - FOURTHCHAR); - i += 3; - escapeflag = true; - /* having changed port, the pointers for - * the currently active port are all out - * of date and need updating */ - active = dev_extra->current_port; - active_extra = - qt2_get_port_private(active); - tty_st = tty_port_tty_get( - &active->port); - break; - case 0x04: - /* Recv flush 3rd byte must - * follow */ - if (i > (RxCount - 3)) { - dbg("Illegal escape sequences " - "in received data"); - break; - } - qt2_process_rcv_flush(active); - i += 2; - escapeflag = true; - break; - case 0x05: - /* xmit flush 3rd byte must follow */ - if (i > (RxCount - 3)) { - dbg("Illegal escape sequences " - "in received data"); - break; - } - qt2_process_xmit_flush(active); - i += 2; - escapeflag = true; - break; - case 0xff: - dbg("No status sequence"); - qt2_process_rx_char(active, THISCHAR); - qt2_process_rx_char(active, NEXTCHAR); - i += 2; - break; - default: - qt2_process_rx_char(active, THISCHAR); - i += 1; - break; - } /*end switch*/ - if (escapeflag == true) - continue; - /* if we did an escape char, we don't need - * to mess around pushing data through the - * tty layer, and can go round again */ - } /*endif*/ - if (tty_st && urb->actual_length) { - tty_buffer_request_room(tty_st, 1); - tty_insert_flip_string(tty_st, &( - (unsigned char *) - (urb->transfer_buffer) - )[i], 1); - } - } /*endfor*/ - tty_flip_buffer_push(tty_st); - } /*endif*/ - - /* at this point we have complete dealing with the data for this - * callback. All we have to do now is to start the async read process - * back off again. */ - - usb_fill_bulk_urb(port0->read_urb, serial->dev, - usb_rcvbulkpipe(serial->dev, port0->bulk_in_endpointAddress), - port0->bulk_in_buffer, port0->bulk_in_size, - qt2_read_bulk_callback, serial); - result = usb_submit_urb(port0->read_urb, GFP_ATOMIC); - if (result) { - dbg("%s(): failed resubmitting read urb, error %d", - __func__, result); - } else { - dbg("%s() successfully resubmitted read urb", __func__); - if (tty_st && RxCount) { - /* if some inbound data was processed, then - * we need to push that through the tty layer - */ - tty_flip_buffer_push(tty_st); - tty_schedule_flip(tty_st); - } - } - - /* cribbed from serqt_usb2 driver, but not sure which work needs - * scheduling - port0 or currently active port? */ - /* schedule_work(&port->work); */ - dbg("%s() completed", __func__); - return; -} - -/** @brief Callback for asynchronous submission of write URBs on bulk in - * endpoints - * - * Registered in qt2_write(), used to deal with outgoing data - * to the box. - */ -static void qt2_write_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = (struct usb_serial_port *)urb->context; - struct usb_serial *serial = port->serial; - dbg("%s(): port %d", __func__, port->number); - if (!serial) { - dbg("%s(): bad serial pointer, exiting", __func__); - return; - } - if (urb->status) { - dbg("%s(): nonzero write bulk status received: %d", - __func__, urb->status); - return; - } - /* FIXME What is supposed to be going on here? - * does this actually do anything useful, and should it? - */ - /*port_softint((void *) serial); commented in vendor driver */ - schedule_work(&port->work); - dbg("%s(): port %d exit", __func__, port->number); - return; -} - -static void qt2_process_line_status(struct usb_serial_port *port, - unsigned char LineStatus) -{ - /* obtain the private structure for the port */ - struct quatech2_port *port_extra = qt2_get_port_private(port); - port_extra->shadowLSR = LineStatus & (QT2_SERIAL_LSR_OE | - QT2_SERIAL_LSR_PE | QT2_SERIAL_LSR_FE | QT2_SERIAL_LSR_BI); -} -static void qt2_process_modem_status(struct usb_serial_port *port, - unsigned char ModemStatus) -{ - /* obtain the private structure for the port */ - struct quatech2_port *port_extra = qt2_get_port_private(port); - port_extra->shadowMSR = ModemStatus; - wake_up_interruptible(&port_extra->wait); - /* this wakes up the otherwise indefinitely waiting code for - * the TIOCMIWAIT ioctl, so that it can notice that - * port_extra->shadowMSR has changed and the ioctl needs to return. - */ -} - -static void qt2_process_xmit_empty(struct usb_serial_port *port, - unsigned char fourth_char, unsigned char fifth_char) -{ - int byte_count; - /* obtain the private structure for the port */ - struct quatech2_port *port_extra = qt2_get_port_private(port); - - byte_count = (int)(fifth_char * 16); - byte_count += (int)fourth_char; - /* byte_count indicates how many bytes the device has written out. This - * message appears to occur regularly, and is used in the vendor driver - * to keep track of the fill state of the port transmit buffer */ - port_extra->tx_pending_bytes -= byte_count; - /* reduce the stored data queue length by the known number of bytes - * sent */ - dbg("port %d: %d bytes reported sent, %d still pending", port->number, - byte_count, port_extra->tx_pending_bytes); - - /*port_extra->xmit_fifo_room_bytes = FIFO_DEPTH; ???*/ -} - -static void qt2_process_port_change(struct usb_serial_port *port, - unsigned char New_Current_Port) -{ - /* obtain the parent usb serial device structure */ - struct usb_serial *serial = port->serial; - /* obtain the private structure for the device */ - struct quatech2_dev *dev_extra = qt2_get_dev_private(serial); - dev_extra->current_port = serial->port[New_Current_Port]; - /* what should I do with this? commented out in upstream - * driver */ - /*schedule_work(&port->work);*/ -} - -static void qt2_process_rcv_flush(struct usb_serial_port *port) -{ - /* obtain the private structure for the port */ - struct quatech2_port *port_extra = qt2_get_port_private(port); - port_extra->rcv_flush = true; -} -static void qt2_process_xmit_flush(struct usb_serial_port *port) -{ - /* obtain the private structure for the port */ - struct quatech2_port *port_extra = qt2_get_port_private(port); - port_extra->xmit_flush = true; -} - -static void qt2_process_rx_char(struct usb_serial_port *port, - unsigned char data) -{ - /* get the tty_struct for this port */ - struct tty_struct *tty = tty_port_tty_get(&(port->port)); - /* get the URB with the data in to push */ - struct urb *urb = port->serial->port[0]->read_urb; - - if (tty && urb->actual_length) { - tty_buffer_request_room(tty, 1); - tty_insert_flip_string(tty, &data, 1); - /* should this be commented out here? */ - /*tty_flip_buffer_push(tty);*/ - } -} - -/** @brief Retrieve the value of a register from the device - * - * Issues a GET_REGISTER vendor-spcific request over the USB control - * pipe to obtain a value back from a specific register on a specific - * UART - * @param serial Serial device handle to access the device through - * @param uart_number Which UART the value is wanted from - * @param register_num Which register to read the value from - * @param pValue Pointer to somewhere to put the retrieved value - */ -static int qt2_box_get_register(struct usb_serial *serial, - unsigned char uart_number, unsigned short register_num, - __u8 *pValue) -{ - int result; - result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - QT2_GET_SET_REGISTER, 0xC0, register_num, - uart_number, (void *)pValue, sizeof(*pValue), 300); - return result; -} - -/** qt2_box_set_register - * Issue a SET_REGISTER vendor-specific request on the default control pipe - */ -static int qt2_box_set_register(struct usb_serial *serial, - unsigned short Uart_Number, unsigned short Register_Num, - unsigned short Value) -{ - int result; - unsigned short reg_and_byte; - - reg_and_byte = Value; - reg_and_byte = reg_and_byte << 8; - reg_and_byte = reg_and_byte + Register_Num; - - result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - QT2_GET_SET_REGISTER, 0x40, reg_and_byte, - Uart_Number, NULL, 0, 300); - return result; -} - -/** qt2_boxsetuart - Issue a SET_UART vendor-spcific request on the default - * control pipe. If successful sets baud rate divisor and LCR value. - */ -static int qt2_boxsetuart(struct usb_serial *serial, unsigned short Uart_Number, - unsigned short default_divisor, unsigned char default_LCR) -{ - unsigned short UartNumandLCR; - - UartNumandLCR = (default_LCR << 8) + Uart_Number; - - return usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - QT2_GET_SET_UART, 0x40, default_divisor, UartNumandLCR, - NULL, 0, 300); -} - -/** qt2_boxsethw_flowctl - Turn hardware (RTS/CTS) flow control on and off for - * a hardware UART. - */ -static int qt2_boxsethw_flowctl(struct usb_serial *serial, - unsigned int UartNumber, bool bSet) -{ - __u8 MCR_Value = 0; - __u8 MSR_Value = 0; - __u16 MOUT_Value = 0; - - if (bSet == true) { - MCR_Value = QT2_SERIAL_MCR_RTS; - /* flow control, box will clear RTS line to prevent remote - * device from transmitting more chars */ - } else { - /* no flow control to remote device */ - MCR_Value = 0; - } - MOUT_Value = MCR_Value << 8; - - if (bSet == true) { - MSR_Value = QT2_SERIAL_MSR_CTS; - /* flow control on, box will inhibit tx data if CTS line is - * asserted */ - } else { - /* Box will not inhibit tx data due to CTS line */ - MSR_Value = 0; - } - MOUT_Value |= MSR_Value; - return usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - QT2_HW_FLOW_CONTROL_MASK, 0x40, MOUT_Value, UartNumber, - NULL, 0, 300); -} - -/** qt2_boxsetsw_flowctl - Turn software (XON/XOFF) flow control on for - * a hardware UART, and set the XON and XOFF characters. - */ -static int qt2_boxsetsw_flowctl(struct usb_serial *serial, __u16 UartNumber, - unsigned char stop_char, unsigned char start_char) -{ - __u16 nSWflowout; - - nSWflowout = start_char << 8; - nSWflowout = (unsigned short)stop_char; - return usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - QT2_SW_FLOW_CONTROL_MASK, 0x40, nSWflowout, UartNumber, - NULL, 0, 300); -} - -/** qt2_boxunsetsw_flowctl - Turn software (XON/XOFF) flow control off for - * a hardware UART. - */ -static int qt2_boxunsetsw_flowctl(struct usb_serial *serial, __u16 UartNumber) -{ - return usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - QT2_SW_FLOW_CONTROL_DISABLE, 0x40, 0, UartNumber, NULL, - 0, 300); -} - -/** - * qt2_boxstoprx - Start and stop reception of data by the FPGA UART in - * response to requests from the tty layer - * @serial: pointer to the usb_serial structure for the parent device - * @uart_number: which UART on the device we are addressing - * @stop: Whether to start or stop data reception. Set to 1 to stop data being - * received, and to 0 to start it being received. - */ -static int qt2_boxstoprx(struct usb_serial *serial, unsigned short uart_number, - unsigned short stop) -{ - return usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - QT2_STOP_RECEIVE, 0x40, stop, uart_number, NULL, 0, 300); -} - - -/* - * last things in file: stuff to register this driver into the generic - * USB serial framework. - */ - -static struct usb_serial_driver quatech2_device = { - .driver = { - .owner = THIS_MODULE, - .name = "quatech_usb2", - }, - .description = DRIVER_DESC, - .id_table = quausb2_id_table, - .num_ports = 8, - .open = qt2_open, - .close = qt2_close, - .write = qt2_write, - .write_room = qt2_write_room, - .chars_in_buffer = qt2_chars_in_buffer, - .throttle = qt2_throttle, - .unthrottle = qt2_unthrottle, - .calc_num_ports = qt2_calc_num_ports, - .ioctl = qt2_ioctl, - .set_termios = qt2_set_termios, - .break_ctl = qt2_break, - .tiocmget = qt2_tiocmget, - .tiocmset = qt2_tiocmset, - .attach = qt2_attach, - .release = qt2_release, - .read_bulk_callback = qt2_read_bulk_callback, - .write_bulk_callback = qt2_write_bulk_callback, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &quatech2_device, NULL -}; - -module_usb_serial_driver(quausb2_usb_driver, serial_drivers); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/trunk/drivers/staging/ramster/Kconfig b/trunk/drivers/staging/ramster/Kconfig index 4af1f8d4b953..8349887827dc 100644 --- a/trunk/drivers/staging/ramster/Kconfig +++ b/trunk/drivers/staging/ramster/Kconfig @@ -1,6 +1,6 @@ config RAMSTER bool "Cross-machine RAM capacity sharing, aka peer-to-peer tmem" - depends on (CLEANCACHE || FRONTSWAP) && CONFIGFS_FS=y && !ZCACHE && !XVMALLOC && !HIGHMEM + depends on (CLEANCACHE || FRONTSWAP) && CONFIGFS_FS=y && !ZCACHE && !XVMALLOC && !HIGHMEM && NET select LZO_COMPRESS select LZO_DECOMPRESS default n diff --git a/trunk/drivers/staging/ramster/cluster/tcp.c b/trunk/drivers/staging/ramster/cluster/tcp.c index 3af1b2c51b78..d0a07d722b61 100644 --- a/trunk/drivers/staging/ramster/cluster/tcp.c +++ b/trunk/drivers/staging/ramster/cluster/tcp.c @@ -111,7 +111,7 @@ static struct socket *r2net_listen_sock; * r2net_wq. teardown detaches the callbacks before destroying the workqueue. * quorum work is queued as sock containers are shutdown.. stop_listening * tears down all the node's sock containers, preventing future shutdowns - * and queued quroum work, before canceling delayed quorum work and + * and queued quorum work, before canceling delayed quorum work and * destroying the work queue. */ static struct workqueue_struct *r2net_wq; @@ -660,7 +660,7 @@ static void r2net_state_change(struct sock *sk) /* * we register callbacks so we can queue work on events before calling - * the original callbacks. our callbacks our careful to test user_data + * the original callbacks. our callbacks are careful to test user_data * to discover when they've reaced with r2net_unregister_callbacks(). */ static void r2net_register_callbacks(struct sock *sk, @@ -2106,7 +2106,7 @@ static int r2net_open_listening_sock(__be32 addr, __be16 port) r2net_listen_sock = sock; INIT_WORK(&r2net_listen_work, r2net_accept_many); - sock->sk->sk_reuse = 1; + sock->sk->sk_reuse = SK_CAN_REUSE; ret = sock->ops->bind(sock, (struct sockaddr *)&sin, sizeof(sin)); if (ret < 0) { printk(KERN_ERR "ramster: Error %d while binding socket at " diff --git a/trunk/drivers/staging/ramster/xvmalloc.c b/trunk/drivers/staging/ramster/xvmalloc.c index 93ba8e9407aa..44ceb0b823a9 100644 --- a/trunk/drivers/staging/ramster/xvmalloc.c +++ b/trunk/drivers/staging/ramster/xvmalloc.c @@ -132,7 +132,7 @@ static u32 find_block(struct xv_pool *pool, u32 size, if (!pool->flbitmap) return 0; - /* Get freelist index correspoding to this size */ + /* Get freelist index corresponding to this size */ slindex = get_index(size); slbitmap = pool->slbitmap[slindex / BITS_PER_LONG]; slbitstart = slindex % BITS_PER_LONG; diff --git a/trunk/drivers/staging/ramster/zcache-main.c b/trunk/drivers/staging/ramster/zcache-main.c index 68b2e053a0e6..4e7ef0e6b79c 100644 --- a/trunk/drivers/staging/ramster/zcache-main.c +++ b/trunk/drivers/staging/ramster/zcache-main.c @@ -1331,7 +1331,7 @@ static ssize_t zv_max_mean_zsize_store(struct kobject *kobj, * when that limit is reached, further puts will be rejected (until * some pages have been flushed). Note that, due to compression, * this number may exceed 100; it defaults to 75 and we set an - * arbitary limit of 150. A poor choice will almost certainly result + * arbitrary limit of 150. A poor choice will almost certainly result * in OOM's, so this value should only be changed prudently. */ static ssize_t zv_page_count_policy_percent_show(struct kobject *kobj, @@ -2004,7 +2004,7 @@ int zcache_pampd_replace_in_obj(void *new_pampd, struct tmem_obj *obj) * Called by the message handler after a (still compressed) page has been * fetched from the remote machine in response to an "is_remote" tmem_get * or persistent tmem_localify. For a tmem_get, "extra" is the address of - * the page that is to be filled to succesfully resolve the tmem_get; for + * the page that is to be filled to successfully resolve the tmem_get; for * a (persistent) tmem_localify, "extra" is NULL (as the data is placed only * in the local zcache). "data" points to "size" bytes of (compressed) data * passed in the message. In the case of a persistent remote get, if @@ -2095,7 +2095,7 @@ int zcache_localify(int pool_id, struct tmem_oid *oidp, /* * Called on a remote persistent tmem_get to attempt to preallocate * local storage for the data contained in the remote persistent page. - * If succesfully preallocated, returns the pampd, marked as remote and + * If successfully preallocated, returns the pampd, marked as remote and * in_transit. Else returns NULL. Note that the appropriate tmem data * structure must be locked. */ diff --git a/trunk/drivers/staging/rtl8187se/Makefile b/trunk/drivers/staging/rtl8187se/Makefile index 72db504b23b4..91d1aa2830c9 100644 --- a/trunk/drivers/staging/rtl8187se/Makefile +++ b/trunk/drivers/staging/rtl8187se/Makefile @@ -10,7 +10,7 @@ ccflags-y += -DHIGH_POWER ccflags-y += -DSW_DIG ccflags-y += -DRATE_ADAPT -#enable it for legacy power save, disable it for leisure power save +#enable it for legacy power save, disable it for leisure power save ccflags-y += -DENABLE_LPS diff --git a/trunk/drivers/staging/rtl8187se/ieee80211/dot11d.c b/trunk/drivers/staging/rtl8187se/ieee80211/dot11d.c index 309bb8bf287e..0e93eb0735a7 100644 --- a/trunk/drivers/staging/rtl8187se/ieee80211/dot11d.c +++ b/trunk/drivers/staging/rtl8187se/ieee80211/dot11d.c @@ -55,7 +55,7 @@ Dot11d_Reset(struct ieee80211_device *ieee) // // Description: -// Update country IE from Beacon or Probe Resopnse +// Update country IE from Beacon or Probe Response // and configure PHY for operation in the regulatory domain. // // TODO: diff --git a/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211.h b/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211.h index 40dd715d9df7..b94c48b29302 100644 --- a/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211.h +++ b/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211.h @@ -834,7 +834,7 @@ enum ieee80211_state { /* the association procedure is sending AUTH request*/ IEEE80211_ASSOCIATING_AUTHENTICATING, - /* the association procedure has successfully authentcated + /* the association procedure has successfully authenticated * and is sending association request */ IEEE80211_ASSOCIATING_AUTHENTICATED, @@ -934,7 +934,7 @@ struct ieee80211_device { * with RX of broad/multicast frames */ /* Fragmentation structures */ - // each streaming contain a entry + /* each stream contains an entry */ struct ieee80211_frag_entry frag_cache[17][IEEE80211_FRAG_CACHE_LEN]; unsigned int frag_next_idx[17]; u16 fts; /* Fragmentation Threshold */ @@ -972,7 +972,7 @@ struct ieee80211_device { int rate; /* current rate */ int basic_rate; - //FIXME: pleace callback, see if redundant with softmac_features + //FIXME: please callback, see if redundant with softmac_features short active_scan; /* this contains flags for selectively enable softmac support */ @@ -1106,7 +1106,7 @@ struct ieee80211_device { /* used instead of hard_start_xmit (not softmac_hard_start_xmit) * if the IEEE_SOFTMAC_TX_QUEUE feature is used to TX data - * frames. I the option IEEE_SOFTMAC_SINGLE_QUEUE is also set + * frames. If the option IEEE_SOFTMAC_SINGLE_QUEUE is also set * then also management frames are sent via this callback. * This function can't sleep. */ @@ -1124,7 +1124,7 @@ struct ieee80211_device { /* ask to the driver to retune the radio . * This function can sleep. the driver should ensure - * the radio has been swithced before return. + * the radio has been switched before return. */ void (*set_chan)(struct net_device *dev,short ch); @@ -1135,7 +1135,7 @@ struct ieee80211_device { * The syncro version is similar to the start_scan but * does not return until all channels has been scanned. * this is called in user context and should sleep, - * it is called in a work_queue when swithcing to ad-hoc mode + * it is called in a work_queue when switching to ad-hoc mode * or in behalf of iwlist scan when the card is associated * and root user ask for a scan. * the function stop_scan should stop both the syncro and @@ -1196,7 +1196,7 @@ struct ieee80211_device { /* Generate probe requests */ #define IEEE_SOFTMAC_PROBERQ (1<<4) -/* Generate respones to probe requests */ +/* Generate response to probe requests */ #define IEEE_SOFTMAC_PROBERS (1<<5) /* The ieee802.11 stack will manages the netif queue diff --git a/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c b/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c index 26bacb96d247..8173240dcf7a 100644 --- a/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c +++ b/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c @@ -42,7 +42,7 @@ short ieee80211_is_shortslot(const struct ieee80211_network *net) return net->capability & WLAN_CAPABILITY_SHORT_SLOT; } -/* returns the total length needed for pleacing the RATE MFIE +/* returns the total length needed for placing the RATE MFIE * tag and the EXTENDED RATE MFIE tag if needed. * It encludes two bytes per tag for the tag itself and its len */ @@ -60,7 +60,7 @@ unsigned int ieee80211_MFIE_rate_len(struct ieee80211_device *ieee) return rate_len; } -/* pleace the MFIE rate, tag to the memory (double) poined. +/* place the MFIE rate, tag to the memory (double) poised. * Then it updates the pointer so that * it points after the new MFIE tag added. */ @@ -467,7 +467,7 @@ void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee) * So we switch to IEEE80211_LINKED_SCANNING to remember * that we are still logically linked (not interested in * new network events, despite for updating the net list, - * but we are temporarly 'unlinked' as the driver shall + * but we are temporarily 'unlinked' as the driver shall * not filter RX frames and the channel is changing. * So the only situation in witch are interested is to check * if the state become LINKED because of the #1 situation @@ -530,7 +530,7 @@ void ieee80211_softmac_ips_scan_syncro(struct ieee80211_device *ieee) * So we switch to IEEE80211_LINKED_SCANNING to remember * that we are still logically linked (not interested in * new network events, despite for updating the net list, - * but we are temporarly 'unlinked' as the driver shall + * but we are temporarily 'unlinked' as the driver shall * not filter RX frames and the channel is changing. * So the only situation in witch are interested is to check * if the state become LINKED because of the #1 situation @@ -1140,7 +1140,7 @@ void ieee80211_associate_abort(struct ieee80211_device *ieee) ieee->associate_seq++; - /* don't scan, and avoid to have the RX path possibily + /* don't scan, and avoid to have the RX path possibly * try again to associate. Even do not react to AUTH or * ASSOC response. Just wait for the retry wq to be scheduled. * Here we will check if there are good nets to associate @@ -1346,14 +1346,14 @@ inline void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee //printk("apset=%d apmatch=%d ssidset=%d ssidbroad=%d ssidmatch=%d\n",apset,apmatch,ssidset,ssidbroad,ssidmatch); if ( /* if the user set the AP check if match. - * if the network does not broadcast essid we check the user supplyed ANY essid + * if the network does not broadcast essid we check the user supplied ANY essid * if the network does broadcast and the user does not set essid it is OK * if the network does broadcast and the user did set essid chech if essid match */ ( apset && apmatch && ((ssidset && ssidbroad && ssidmatch) || (ssidbroad && !ssidset) || (!ssidbroad && ssidset)) ) || /* if the ap is not set, check that the user set the bssid - * and the network does bradcast and that those two bssid matches + * and the network does broadcast and that those two bssid matches */ (!apset && ssidset && ssidbroad && ssidmatch) ){ @@ -1821,7 +1821,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, while (left >= sizeof(struct ieee80211_info_element_hdr)) { if (sizeof(struct ieee80211_info_element_hdr) + info_element->len > left) { - printk(KERN_WARNING "[re]associate reeponse error!"); + printk(KERN_WARNING "[re]associate response error!"); return 1; } switch (info_element->id) { @@ -1905,7 +1905,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, } }else{ ieee->softmac_stats.rx_auth_rs_err++; - IEEE80211_DEBUG_MGMT("Authentication respose status code 0x%x",errcode); + IEEE80211_DEBUG_MGMT("Authentication response status code 0x%x",errcode); ieee80211_associate_abort(ieee); } @@ -2184,15 +2184,15 @@ void ieee80211_start_ibss_wq(struct work_struct *work) if(ieee->state == IEEE80211_NOLINK) ieee->current_network.channel = 10; - /* if not then the state is not linked. Maybe the user swithced to + /* if not then the state is not linked. Maybe the user switched to * ad-hoc mode just after being in monitor mode, or just after * being very few time in managed mode (so the card have had no * time to scan all the chans..) or we have just run up the iface * after setting ad-hoc mode. So we have to give another try.. * Here, in ibss mode, should be safe to do this without extra care - * (in bss mode we had to make sure no-one tryed to associate when + * (in bss mode we had to make sure no-one tried to associate when * we had just checked the ieee->state and we was going to start the - * scan) beacause in ibss mode the ieee80211_new_net function, when + * scan) because in ibss mode the ieee80211_new_net function, when * finds a good net, just set the ieee->state to IEEE80211_LINKED, * so, at worst, we waste a bit of time to initiate an unneeded syncro * scan, that will stop at the first round because it sees the state @@ -2342,7 +2342,7 @@ void ieee80211_associate_retry_wq(struct work_struct *work) goto exit; /* until we do not set the state to IEEE80211_NOLINK * there are no possibility to have someone else trying - * to start an association procdure (we get here with + * to start an association procedure (we get here with * ieee->state = IEEE80211_ASSOCIATING). * When we set the state to IEEE80211_NOLINK it is possible * that the RX path run an attempt to associate, but diff --git a/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c b/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c index e46ff2ffa09b..5d204906baf7 100644 --- a/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c +++ b/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c @@ -362,7 +362,7 @@ int ieee80211_wx_set_essid(struct ieee80211_device *ieee, ieee80211_stop_protocol(ieee); /* this is just to be sure that the GET wx callback - * has consisten infos. not needed otherwise + * has consistent infos. not needed otherwise */ spin_lock_irqsave(&ieee->lock, flags); diff --git a/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c b/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c index 552115cd760e..89ed86ef0d15 100644 --- a/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c +++ b/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c @@ -328,7 +328,7 @@ int ieee80211_rtl_xmit(struct sk_buff *skb, //printk(KERN_WARNING "upper layer packet!\n"); spin_lock_irqsave(&ieee->lock, flags); - /* If there is no driver handler to take the TXB, dont' bother + /* If there is no driver handler to take the TXB, don't bother * creating it... */ if ((!ieee->hard_start_xmit && !(ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE))|| ((!ieee->softmac_data_hard_start_xmit && (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE)))) { @@ -413,10 +413,7 @@ int ieee80211_rtl_xmit(struct sk_buff *skb, /* Determine fragmentation size based on destination (multicast * and broadcast are not fragmented) */ -// if (is_multicast_ether_addr(dest) || -// is_broadcast_ether_addr(dest)) { - if (is_multicast_ether_addr(header.addr1) || - is_broadcast_ether_addr(header.addr1)) { + if (is_multicast_ether_addr(header.addr1)) { frag_size = MAX_FRAG_THRESHOLD; qos_ctl = QOS_CTL_NOTCONTAIN_ACK; } diff --git a/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c b/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c index ca414a915a4e..c7917b24425c 100644 --- a/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c +++ b/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c @@ -363,7 +363,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, (*crypt)->priv); sec.flags |= (1 << key); /* This ensures a key will be activated if no key is - * explicitely set */ + * explicitly set */ if (key == sec.active_key) sec.flags |= SEC_ACTIVE_KEY; ieee->tx_keyidx = key;//by wb 080312 diff --git a/trunk/drivers/staging/rtl8187se/r8180.h b/trunk/drivers/staging/rtl8187se/r8180.h index a2c46ae4a400..2682afbac4ff 100644 --- a/trunk/drivers/staging/rtl8187se/r8180.h +++ b/trunk/drivers/staging/rtl8187se/r8180.h @@ -11,7 +11,7 @@ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver - We want to tanks the Authors of those projects and the Ndiswrapper + We want to thanks the Authors of those projects and the Ndiswrapper project Authors. */ @@ -514,12 +514,12 @@ typedef struct r8180_priv bool bDefaultAntenna1; u8 SignalStrength; long Stats_SignalStrength; - long LastSignalStrengthInPercent; // In percentange, used for smoothing, e.g. Moving Average. + long LastSignalStrengthInPercent; // In percentage, used for smoothing, e.g. Moving Average. u8 SignalQuality; // in 0-100 index. long Stats_SignalQuality; long RecvSignalPower; // in dBm. long Stats_RecvSignalPower; - u8 LastRxPktAntenna; // +by amy 080312 Antenn which received the lasted packet. 0: Aux, 1:Main. Added by Roger, 2008.01.25. + u8 LastRxPktAntenna; // +by amy 080312 Antenna which received the lasted packet. 0: Aux, 1:Main. Added by Roger, 2008.01.25. u32 AdRxOkCnt; long AdRxSignalStrength; u8 CurrAntennaIndex; // Index to current Antenna (both Tx and Rx). @@ -530,7 +530,7 @@ typedef struct r8180_priv long AdRxSsThreshold; // Signal strength threshold to switch antenna. long AdMaxRxSsThreshold; // Max value of AdRxSsThreshold. bool bAdSwitchedChecking; // TRUE if we shall shall check Rx signal strength for last time switching antenna. - long AdRxSsBeforeSwitched; // Rx signal strength before we swithed antenna. + long AdRxSsBeforeSwitched; // Rx signal strength before we switched antenna. struct timer_list SwAntennaDiversityTimer; //by amy for antenna //{by amy 080312 @@ -553,7 +553,7 @@ typedef struct r8180_priv bool bDigMechanism; // TRUE if DIG is enabled, FALSE ow. bool bRegHighPowerMechanism; // For High Power Mechanism. 061010, by rcnjko. u32 FalseAlarmRegValue; - u8 RegDigOfdmFaUpTh; // Upper threhold of OFDM false alarm, which is used in DIG. + u8 RegDigOfdmFaUpTh; // Upper threshold of OFDM false alarm, which is used in DIG. u8 DIG_NumberFallbackVote; u8 DIG_NumberUpgradeVote; // For HW antenna diversity, added by Roger, 2008.01.30. diff --git a/trunk/drivers/staging/rtl8187se/r8180_core.c b/trunk/drivers/staging/rtl8187se/r8180_core.c index 4fe52f6b0034..fd22b75aea4f 100644 --- a/trunk/drivers/staging/rtl8187se/r8180_core.c +++ b/trunk/drivers/staging/rtl8187se/r8180_core.c @@ -1329,7 +1329,7 @@ u16 N_DBPSOfRate(u16 DataRate) } /* - * For Netgear case, they want good-looking singal strength. + * For Netgear case, they want good-looking signal strength. */ long NetgearSignalStrengthTranslate(long LastSS, long CurrSS) { @@ -1380,7 +1380,7 @@ long TranslateToDbm8185(u8 SignalStrengthIndex) /* * Perform signal smoothing for dynamic mechanism. - * This is different with PerformSignalSmoothing8185 in smoothing fomula. + * This is different with PerformSignalSmoothing8185 in smoothing formula. * No dramatic adjustion is apply because dynamic mechanism need some degree * of correctness. Ported from 8187B. */ @@ -1535,7 +1535,7 @@ void rtl8180_rx(struct net_device *dev) /* HW is probably passing several buggy frames * without FD or LD flag set. * Throw this garbage away to prevent skb - * memory exausting + * memory exhausting */ if (!priv->rx_skb_complete) dev_kfree_skb_any(priv->rx_skb); @@ -1648,14 +1648,14 @@ void rtl8180_rx(struct net_device *dev) priv->Stats_SignalQuality = (long)(priv->Stats_SignalQuality * 5 + (long)priv->SignalQuality + 5) / 6; priv->Stats_RecvSignalPower = (long)(priv->Stats_RecvSignalPower * 5 + priv->RecvSignalPower - 1) / 6; - /* Figure out which antenna that received the lasted packet. */ + /* Figure out which antenna that received the last packet. */ priv->LastRxPktAntenna = Antenna ? 1 : 0; /* 0: aux, 1: main. */ SwAntennaDiversityRxOk8185(dev, priv->SignalStrength); } if (first) { if (!priv->rx_skb_complete) { - /* seems that HW sometimes fails to reiceve and + /* seems that HW sometimes fails to receive and doesn't provide the last descriptor */ dev_kfree_skb_any(priv->rx_skb); priv->stats.rxnolast++; @@ -1672,7 +1672,7 @@ void rtl8180_rx(struct net_device *dev) priv->rx_skb_complete = 0; priv->rx_skb->dev = dev; } else { - /* if we are here we should have already RXed + /* if we are here we should have already RXed * the first frame. * If we get here and the skb is not allocated then * we have just throw out garbage (skb not allocated) @@ -1821,15 +1821,15 @@ rate) { /* * This is a rough attempt to TX a frame * This is called by the ieee 80211 stack to TX management frames. - * If the ring is full packet are dropped (for data frame the queue + * If the ring is full packets are dropped (for data frame the queue * is stopped before this can happen). For this reason it is better * if the descriptors are larger than the largest management frame - * we intend to TX: i'm unsure what the HW does if it will not found + * we intend to TX: i'm unsure what the HW does if it will not find * the last fragment of a frame because it has been dropped... * Since queues for Management and Data frames are different we * might use a different lock than tx_lock (for example mgmt_tx_lock) */ -/* these function may loops if invoked with 0 descriptors or 0 len buffer */ +/* these function may loop if invoked with 0 descriptors or 0 len buffer */ int rtl8180_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); @@ -2003,8 +2003,7 @@ short rtl8180_tx(struct net_device *dev, u8* txbuf, int len, int priority, } memcpy(&dest, frag_hdr->addr1, ETH_ALEN); - if (is_multicast_ether_addr(dest) || - is_broadcast_ether_addr(dest)) { + if (is_multicast_ether_addr(dest)) { Duration = 0; RtsDur = 0; bRTSEnable = 0; @@ -2378,7 +2377,7 @@ void rtl8180_wmm_param_update(struct work_struct *work) u8 u1bAIFS; u32 u4bAcParam; pAcParam = (PAC_PARAM)(&AcParam); - /* Retrive paramters to udpate. */ + /* Retrieve paramters to update. */ u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime; u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit))<f.Ecw.f.ECWmax))<f.AciAifsn.f.ACI; /* Mode G/A: slotTimeTimer = 9; Mode B: 20 */ u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime; @@ -2700,7 +2699,7 @@ short rtl8180_init(struct net_device *dev) priv->bTxPowerTrack = false; priv->ThermalMeter = 0; priv->FalseAlarmRegValue = 0; - priv->RegDigOfdmFaUpTh = 0xc; /* Upper threhold of OFDM false alarm, which is used in DIG. */ + priv->RegDigOfdmFaUpTh = 0xc; /* Upper threshold of OFDM false alarm, which is used in DIG. */ priv->DIG_NumberFallbackVote = 0; priv->DIG_NumberUpgradeVote = 0; priv->LastSignalStrengthInPercent = 0; @@ -2896,7 +2895,7 @@ short rtl8180_init(struct net_device *dev) priv->chtxpwr_ofdm[i+1] = (word & 0xff00) >> 8; } - /* 3Read crystal calibtration and thermal meter indication on 87SE. */ + /* 3Read crystal calibration and thermal meter indication on 87SE. */ eeprom_93cx6_read(&eeprom, EEPROM_RSV>>1, &tmpu16); /* Crystal calibration for Xin and Xout resp. */ @@ -3140,7 +3139,7 @@ void rtl8180_adapter_start(struct net_device *dev) /* * The following is very strange. seems to be that 1 means test mode, - * but we need to acknolwledges the nic when a packet is ready + * but we need to acknowledges the nic when a packet is ready * although we set it to 0 */ @@ -3971,7 +3970,7 @@ irqreturn_t rtl8180_interrupt(int irq, void *netdev, struct pt_regs *regs) } if (inta == 0xffff) { - /* HW disappared */ + /* HW disappeared */ spin_unlock_irqrestore(&priv->irq_th_lock, flags); return IRQ_HANDLED; } diff --git a/trunk/drivers/staging/rtl8187se/r8180_dm.c b/trunk/drivers/staging/rtl8187se/r8180_dm.c index 4d7a5951486e..b8f2ba010a04 100644 --- a/trunk/drivers/staging/rtl8187se/r8180_dm.c +++ b/trunk/drivers/staging/rtl8187se/r8180_dm.c @@ -2,7 +2,7 @@ #include "r8180_hw.h" #include "r8180_93cx6.h" - /* Return TRUE if we shall perform High Power Mecahnism, FALSE otherwise. */ + /* Return TRUE if we shall perform High Power Mechanism, FALSE otherwise. */ #define RATE_ADAPTIVE_TIMER_PERIOD 300 bool CheckHighPower(struct net_device *dev) @@ -105,7 +105,7 @@ void rtl8180_tx_pw_wq(struct work_struct *work) /* - * Return TRUE if we shall perform DIG Mecahnism, FALSE otherwise. + * Return TRUE if we shall perform DIG Mechanism, FALSE otherwise. */ bool CheckDig(struct net_device *dev) { @@ -507,7 +507,7 @@ void StaRateAdaptive87SE(struct net_device *dev) * and retry rate. * (3) Remove all Initial Gain Updates over OFDM rate. To avoid the complicated * situation, Initial Gain Update is upon on DIG mechanism except CCK rate. - * (4) Add the mehanism of trying to upgrade tx rate. + * (4) Add the mechanism of trying to upgrade tx rate. * (5) Record the information of upping tx rate to avoid trying upping tx rate constantly. * */ @@ -528,7 +528,7 @@ void StaRateAdaptive87SE(struct net_device *dev) if (priv->bTryuping == true) { /* 2 For Test Upgrading mechanism * Note: - * Sometimes the throughput is upon on the capability bwtween the AP and NIC, + * Sometimes the throughput is upon on the capability between the AP and NIC, * thus the low data rate does not improve the performance. * We randomly upgrade the data rate and check if the retry rate is improved. */ @@ -704,7 +704,7 @@ void StaRateAdaptive87SE(struct net_device *dev) /* * The difference in throughput between 48Mbps and 36Mbps is 8M. - * So, we must be carefully in this rate scale. Isaiah 2008-02-15. + * So, we must be careful in this rate scale. Isaiah 2008-02-15. */ if (((priv->CurrentOperaRate == 72) || (priv->CurrentOperaRate == 48) || (priv->CurrentOperaRate == 36)) && (priv->FailTxRateCount > 2)) @@ -1009,7 +1009,7 @@ void SwAntennaDiversity(struct net_device *dev) if (priv->AdCheckPeriod > priv->AdMaxCheckPeriod) priv->AdCheckPeriod = priv->AdMaxCheckPeriod; - /* Wrong deceision => switch back. */ + /* Wrong decision => switch back. */ SwitchAntenna(dev); } else { /* Rx Signal Strength is improved. */ @@ -1057,7 +1057,7 @@ void SwAntennaDiversity(struct net_device *dev) } /* * We evaluate Rx signal strength ONLY when default antenna - * didn't changed by HW evaluation. + * didn't change by HW evaluation. * 2008.02.27. * * [TRC Dell Lab] SignalStrength is inaccuracy. Isaiah 2008-03-05 @@ -1098,7 +1098,7 @@ void SwAntennaDiversity(struct net_device *dev) priv->AdAuxAntennaRxOkCnt = 0; } - /* Return TRUE if we shall perform Tx Power Tracking Mecahnism, FALSE otherwise. */ + /* Return TRUE if we shall perform Tx Power Tracking Mechanism, FALSE otherwise. */ bool CheckTxPwrTracking(struct net_device *dev) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); diff --git a/trunk/drivers/staging/rtl8187se/r8180_rtl8225z2.c b/trunk/drivers/staging/rtl8187se/r8180_rtl8225z2.c index ee5b867fd0d4..d28c1d996084 100644 --- a/trunk/drivers/staging/rtl8187se/r8180_rtl8225z2.c +++ b/trunk/drivers/staging/rtl8187se/r8180_rtl8225z2.c @@ -190,7 +190,7 @@ static void rtl8225_SetTXPowerLevel(struct net_device *dev, short ch) write_phy_cck(dev, 0x44 + i, power); } - /* FIXME Is this delay really needeed ? */ + /* FIXME Is this delay really needed ? */ force_pci_posting(dev); mdelay(1); @@ -479,7 +479,7 @@ s8 DbmToTxPwrIdx(struct r8180_priv *priv, WIRELESS_MODE WirelessMode, /* * TRUE if we want to use a default implementation. - * We shall set it to FALSE when we have exact translation formular + * We shall set it to FALSE when we have exact translation formula * for target IC. 070622, by rcnjko. */ if (bUseDefault) { diff --git a/trunk/drivers/staging/rtl8187se/r8180_wx.c b/trunk/drivers/staging/rtl8187se/r8180_wx.c index 303ec691262a..46ee6f47f525 100644 --- a/trunk/drivers/staging/rtl8187se/r8180_wx.c +++ b/trunk/drivers/staging/rtl8187se/r8180_wx.c @@ -13,7 +13,7 @@ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. - We want to tanks the Authors of those projects and the Ndiswrapper + We want to thanks the Authors of those projects and the Ndiswrapper project Authors. */ @@ -1181,7 +1181,7 @@ static iw_handler r8180_wx_handlers[] = { r8180_wx_set_wap, /* SIOCSIWAP */ r8180_wx_get_wap, /* SIOCGIWAP */ r8180_wx_set_mlme, /* SIOCSIWMLME*/ - dummy, /* SIOCGIWAPLIST -- depricated */ + dummy, /* SIOCGIWAPLIST -- deprecated */ r8180_wx_set_scan, /* SIOCSIWSCAN */ r8180_wx_get_scan, /* SIOCGIWSCAN */ r8180_wx_set_essid, /* SIOCSIWESSID */ @@ -1369,7 +1369,7 @@ static inline int is_same_network(struct ieee80211_network *src, (dst->capability & WLAN_CAPABILITY_BSS))); } -/* WB modefied to show signal to GUI on 18-01-2008 */ +/* WB modified to show signal to GUI on 18-01-2008 */ static struct iw_statistics *r8180_get_wireless_stats(struct net_device *dev) { struct r8180_priv *priv = ieee80211_priv(dev); diff --git a/trunk/drivers/staging/rtl8187se/r8180_wx.h b/trunk/drivers/staging/rtl8187se/r8180_wx.h index 735d03dceed3..408191403112 100644 --- a/trunk/drivers/staging/rtl8187se/r8180_wx.h +++ b/trunk/drivers/staging/rtl8187se/r8180_wx.h @@ -7,7 +7,7 @@ Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver - We want to tanks the Authors of such projects and the Ndiswrapper project Authors. + We want to thanks the Authors of such projects and the Ndiswrapper project Authors. */ /* this file (will) contains wireless extension handlers*/ diff --git a/trunk/drivers/staging/rtl8187se/r8185b_init.c b/trunk/drivers/staging/rtl8187se/r8185b_init.c index 4b0b830f9ab6..914495783c06 100644 --- a/trunk/drivers/staging/rtl8187se/r8185b_init.c +++ b/trunk/drivers/staging/rtl8187se/r8185b_init.c @@ -1,22 +1,22 @@ -/*++ -Copyright (c) Realtek Semiconductor Corp. All rights reserved. - -Module Name: - r8185b_init.c - -Abstract: - Hardware Initialization and Hardware IO for RTL8185B - -Major Change History: - When Who What - ---------- --------------- ------------------------------- - 2006-11-15 Xiong Created - -Notes: - This file is ported from RTL8185B Windows driver. - - ---*/ +/* + * Copyright (c) Realtek Semiconductor Corp. All rights reserved. + * + * Module Name: + * r8185b_init.c + * + * Abstract: + * Hardware Initialization and Hardware IO for RTL8185B + * + * Major Change History: + * When Who What + * ---------- --------------- ------------------------------- + * 2006-11-15 Xiong Created + * + * Notes: + * This file is ported from RTL8185B Windows driver. + * + * + */ /*--------------------------Include File------------------------------------*/ #include @@ -25,155 +25,134 @@ Major Change History: #include "r8180_rtl8225.h" /* RTL8225 Radio frontend */ #include "r8180_93cx6.h" /* Card EEPROM */ #include "r8180_wx.h" - #include "ieee80211/dot11d.h" - - /* #define CONFIG_RTL8180_IO_MAP */ - #define TC_3W_POLL_MAX_TRY_CNT 5 + static u8 MAC_REG_TABLE[][2] = { - /*PAGA 0: */ - /* 0x34(BRSR), 0xBE(RATE_FALLBACK_CTL), 0x1E0(ARFR) would set in HwConfigureRTL8185() */ - /* 0x272(RFSW_CTRL), 0x1CE(AESMSK_QC) set in InitializeAdapter8185(). */ - /* 0x1F0~0x1F8 set in MacConfig_85BASIC() */ - {0x08, 0xae}, {0x0a, 0x72}, {0x5b, 0x42}, - {0x84, 0x88}, {0x85, 0x24}, {0x88, 0x54}, {0x8b, 0xb8}, {0x8c, 0x03}, - {0x8d, 0x40}, {0x8e, 0x00}, {0x8f, 0x00}, {0x5b, 0x18}, {0x91, 0x03}, - {0x94, 0x0F}, {0x95, 0x32}, - {0x96, 0x00}, {0x97, 0x07}, {0xb4, 0x22}, {0xdb, 0x00}, - {0xf0, 0x32}, {0xf1, 0x32}, {0xf2, 0x00}, {0xf3, 0x00}, {0xf4, 0x32}, - {0xf5, 0x43}, {0xf6, 0x00}, {0xf7, 0x00}, {0xf8, 0x46}, {0xf9, 0xa4}, - {0xfa, 0x00}, {0xfb, 0x00}, {0xfc, 0x96}, {0xfd, 0xa4}, {0xfe, 0x00}, - {0xff, 0x00}, - - /*PAGE 1: */ - /* For Flextronics system Logo PCIHCT failure: */ - /* 0x1C4~0x1CD set no-zero value to avoid PCI configuration space 0x45[7]=1 */ - {0x5e, 0x01}, - {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x04}, {0x5b, 0x00}, {0x60, 0x24}, - {0x61, 0x97}, {0x62, 0xF0}, {0x63, 0x09}, {0x80, 0x0F}, {0x81, 0xFF}, - {0x82, 0xFF}, {0x83, 0x03}, - {0xC4, 0x22}, {0xC5, 0x22}, {0xC6, 0x22}, {0xC7, 0x22}, {0xC8, 0x22}, /* lzm add 080826 */ - {0xC9, 0x22}, {0xCA, 0x22}, {0xCB, 0x22}, {0xCC, 0x22}, {0xCD, 0x22},/* lzm add 080826 */ - {0xe2, 0x00}, - - - /* PAGE 2: */ - {0x5e, 0x02}, - {0x0c, 0x04}, {0x4c, 0x30}, {0x4d, 0x08}, {0x50, 0x05}, {0x51, 0xf5}, - {0x52, 0x04}, {0x53, 0xa0}, {0x54, 0xff}, {0x55, 0xff}, {0x56, 0xff}, - {0x57, 0xff}, {0x58, 0x08}, {0x59, 0x08}, {0x5a, 0x08}, {0x5b, 0x08}, - {0x60, 0x08}, {0x61, 0x08}, {0x62, 0x08}, {0x63, 0x08}, {0x64, 0x2f}, - {0x8c, 0x3f}, {0x8d, 0x3f}, {0x8e, 0x3f}, - {0x8f, 0x3f}, {0xc4, 0xff}, {0xc5, 0xff}, {0xc6, 0xff}, {0xc7, 0xff}, - {0xc8, 0x00}, {0xc9, 0x00}, {0xca, 0x80}, {0xcb, 0x00}, - - /* PAGA 0: */ - {0x5e, 0x00}, {0x9f, 0x03} - }; - - -static u8 ZEBRA_AGC[] = { - 0, - 0x7E, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, - 0x71, 0x70, 0x6F, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69, 0x68, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62, - 0x48, 0x47, 0x46, 0x45, 0x44, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x08, 0x07, - 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x15, 0x16, - 0x17, 0x17, 0x18, 0x18, 0x19, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, - 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, - 0x24, 0x25, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F - }; - -static u32 ZEBRA_RF_RX_GAIN_TABLE[] = { - 0x0096, 0x0076, 0x0056, 0x0036, 0x0016, 0x01f6, 0x01d6, 0x01b6, - 0x0196, 0x0176, 0x00F7, 0x00D7, 0x00B7, 0x0097, 0x0077, 0x0057, - 0x0037, 0x00FB, 0x00DB, 0x00BB, 0x00FF, 0x00E3, 0x00C3, 0x00A3, - 0x0083, 0x0063, 0x0043, 0x0023, 0x0003, 0x01E3, 0x01C3, 0x01A3, - 0x0183, 0x0163, 0x0143, 0x0123, 0x0103 + /*PAGA 0: */ + /* 0x34(BRSR), 0xBE(RATE_FALLBACK_CTL), 0x1E0(ARFR) would set in HwConfigureRTL8185() */ + /* 0x272(RFSW_CTRL), 0x1CE(AESMSK_QC) set in InitializeAdapter8185(). */ + /* 0x1F0~0x1F8 set in MacConfig_85BASIC() */ + {0x08, 0xae}, {0x0a, 0x72}, {0x5b, 0x42}, + {0x84, 0x88}, {0x85, 0x24}, {0x88, 0x54}, {0x8b, 0xb8}, {0x8c, 0x03}, + {0x8d, 0x40}, {0x8e, 0x00}, {0x8f, 0x00}, {0x5b, 0x18}, {0x91, 0x03}, + {0x94, 0x0F}, {0x95, 0x32}, + {0x96, 0x00}, {0x97, 0x07}, {0xb4, 0x22}, {0xdb, 0x00}, + {0xf0, 0x32}, {0xf1, 0x32}, {0xf2, 0x00}, {0xf3, 0x00}, {0xf4, 0x32}, + {0xf5, 0x43}, {0xf6, 0x00}, {0xf7, 0x00}, {0xf8, 0x46}, {0xf9, 0xa4}, + {0xfa, 0x00}, {0xfb, 0x00}, {0xfc, 0x96}, {0xfd, 0xa4}, {0xfe, 0x00}, + {0xff, 0x00}, + + /*PAGE 1: */ + /* For Flextronics system Logo PCIHCT failure: */ + /* 0x1C4~0x1CD set no-zero value to avoid PCI configuration space 0x45[7]=1 */ + {0x5e, 0x01}, + {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x04}, {0x5b, 0x00}, {0x60, 0x24}, + {0x61, 0x97}, {0x62, 0xF0}, {0x63, 0x09}, {0x80, 0x0F}, {0x81, 0xFF}, + {0x82, 0xFF}, {0x83, 0x03}, + {0xC4, 0x22}, {0xC5, 0x22}, {0xC6, 0x22}, {0xC7, 0x22}, {0xC8, 0x22}, /* lzm add 080826 */ + {0xC9, 0x22}, {0xCA, 0x22}, {0xCB, 0x22}, {0xCC, 0x22}, {0xCD, 0x22}, /* lzm add 080826 */ + {0xe2, 0x00}, + + + /* PAGE 2: */ + {0x5e, 0x02}, + {0x0c, 0x04}, {0x4c, 0x30}, {0x4d, 0x08}, {0x50, 0x05}, {0x51, 0xf5}, + {0x52, 0x04}, {0x53, 0xa0}, {0x54, 0xff}, {0x55, 0xff}, {0x56, 0xff}, + {0x57, 0xff}, {0x58, 0x08}, {0x59, 0x08}, {0x5a, 0x08}, {0x5b, 0x08}, + {0x60, 0x08}, {0x61, 0x08}, {0x62, 0x08}, {0x63, 0x08}, {0x64, 0x2f}, + {0x8c, 0x3f}, {0x8d, 0x3f}, {0x8e, 0x3f}, + {0x8f, 0x3f}, {0xc4, 0xff}, {0xc5, 0xff}, {0xc6, 0xff}, {0xc7, 0xff}, + {0xc8, 0x00}, {0xc9, 0x00}, {0xca, 0x80}, {0xcb, 0x00}, + + /* PAGA 0: */ + {0x5e, 0x00}, {0x9f, 0x03} + }; + + +static u8 ZEBRA_AGC[] = { + 0, + 0x7E, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, + 0x71, 0x70, 0x6F, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69, 0x68, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62, + 0x48, 0x47, 0x46, 0x45, 0x44, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x08, 0x07, + 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x15, 0x16, + 0x17, 0x17, 0x18, 0x18, 0x19, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, + 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, + 0x24, 0x25, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F + }; + +static u32 ZEBRA_RF_RX_GAIN_TABLE[] = { + 0x0096, 0x0076, 0x0056, 0x0036, 0x0016, 0x01f6, 0x01d6, 0x01b6, + 0x0196, 0x0176, 0x00F7, 0x00D7, 0x00B7, 0x0097, 0x0077, 0x0057, + 0x0037, 0x00FB, 0x00DB, 0x00BB, 0x00FF, 0x00E3, 0x00C3, 0x00A3, + 0x0083, 0x0063, 0x0043, 0x0023, 0x0003, 0x01E3, 0x01C3, 0x01A3, + 0x0183, 0x0163, 0x0143, 0x0123, 0x0103 }; -static u8 OFDM_CONFIG[] = { - /* OFDM reg0x06[7:0]=0xFF: Enable power saving mode in RX */ - /* OFDM reg0x3C[4]=1'b1: Enable RX power saving mode */ - /* ofdm 0x3a = 0x7b ,(original : 0xfb) For ECS shielding room TP test */ - - /* 0x00 */ - 0x10, 0x0F, 0x0A, 0x0C, 0x14, 0xFA, 0xFF, 0x50, - 0x00, 0x50, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, - /* 0x10 */ - 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xA8, 0x26, - 0x32, 0x33, 0x06, 0xA5, 0x6F, 0x55, 0xC8, 0xBB, - /* 0x20 */ - 0x0A, 0xE1, 0x2C, 0x4A, 0x86, 0x83, 0x34, 0x00, - 0x4F, 0x24, 0x6F, 0xC2, 0x03, 0x40, 0x80, 0x00, - /* 0x30 */ - 0xC0, 0xC1, 0x58, 0xF1, 0x00, 0xC4, 0x90, 0x3e, - 0xD8, 0x3C, 0x7B, 0x10, 0x10 - }; - -/* --------------------------------------------------------------- - * Hardware IO - * the code is ported from Windows source code - ----------------------------------------------------------------*/ - -void -PlatformIOWrite1Byte( - struct net_device *dev, - u32 offset, - u8 data - ) +static u8 OFDM_CONFIG[] = { + /* OFDM reg0x06[7:0]=0xFF: Enable power saving mode in RX */ + /* OFDM reg0x3C[4]=1'b1: Enable RX power saving mode */ + /* ofdm 0x3a = 0x7b ,(original : 0xfb) For ECS shielding room TP test */ + /* 0x00 */ + 0x10, 0x0F, 0x0A, 0x0C, 0x14, 0xFA, 0xFF, 0x50, + 0x00, 0x50, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, + /* 0x10 */ + 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xA8, 0x26, + 0x32, 0x33, 0x06, 0xA5, 0x6F, 0x55, 0xC8, 0xBB, + /* 0x20 */ + 0x0A, 0xE1, 0x2C, 0x4A, 0x86, 0x83, 0x34, 0x00, + 0x4F, 0x24, 0x6F, 0xC2, 0x03, 0x40, 0x80, 0x00, + /* 0x30 */ + 0xC0, 0xC1, 0x58, 0xF1, 0x00, 0xC4, 0x90, 0x3e, + 0xD8, 0x3C, 0x7B, 0x10, 0x10 + }; + + /*--------------------------------------------------------------- + * Hardware IO + * the code is ported from Windows source code + *--------------------------------------------------------------- + */ + +void PlatformIOWrite1Byte(struct net_device *dev, u32 offset, u8 data) { write_nic_byte(dev, offset, data); - read_nic_byte(dev, offset); /* To make sure write operation is completed, 2005.11.09, by rcnjko. */ - + read_nic_byte(dev, offset); /* To make sure write operation is completed, 2005.11.09, by rcnjko. */ } -void -PlatformIOWrite2Byte( - struct net_device *dev, - u32 offset, - u16 data - ) +void PlatformIOWrite2Byte(struct net_device *dev, u32 offset, u16 data) { write_nic_word(dev, offset, data); read_nic_word(dev, offset); /* To make sure write operation is completed, 2005.11.09, by rcnjko. */ - - } + u8 PlatformIORead1Byte(struct net_device *dev, u32 offset); -void -PlatformIOWrite4Byte( - struct net_device *dev, - u32 offset, - u32 data - ) +void PlatformIOWrite4Byte(struct net_device *dev, u32 offset, u32 data) { -/* {by amy 080312 */ -if (offset == PhyAddr) { -/* For Base Band configuration. */ + if (offset == PhyAddr) { + /* For Base Band configuration. */ unsigned char cmdByte; unsigned long dataBytes; unsigned char idx; - u8 u1bTmp; + u8 u1bTmp; cmdByte = (u8)(data & 0x000000ff); dataBytes = data>>8; /* - 071010, rcnjko: - The critical section is only BB read/write race condition. - Assumption: - 1. We assume NO one will access BB at DIRQL, otherwise, system will crash for - acquiring the spinlock in such context. - 2. PlatformIOWrite4Byte() MUST NOT be recursive. - */ -/* NdisAcquireSpinLock( &(pDevice->IoSpinLock) ); */ - - for (idx = 0; idx < 30; idx++) { - /* Make sure command bit is clear before access it. */ + * 071010, rcnjko: + * The critical section is only BB read/write race condition. + * Assumption: + * 1. We assume NO one will access BB at DIRQL, otherwise, system will crash for + * acquiring the spinlock in such context. + * 2. PlatformIOWrite4Byte() MUST NOT be recursive. + */ + /* NdisAcquireSpinLock( &(pDevice->IoSpinLock) ); */ + + for (idx = 0; idx < 30; idx++) { + /* Make sure command bit is clear before access it. */ u1bTmp = PlatformIORead1Byte(dev, PhyAddr); if ((u1bTmp & BIT7) == 0) break; @@ -186,20 +165,14 @@ if (offset == PhyAddr) { write_nic_byte(dev, offset, cmdByte); -/* NdisReleaseSpinLock( &(pDevice->IoSpinLock) ); */ - } -/* by amy 080312} */ - else { + /* NdisReleaseSpinLock( &(pDevice->IoSpinLock) ); */ + } else { write_nic_dword(dev, offset, data); read_nic_dword(dev, offset); /* To make sure write operation is completed, 2005.11.09, by rcnjko. */ } } -u8 -PlatformIORead1Byte( - struct net_device *dev, - u32 offset - ) +u8 PlatformIORead1Byte(struct net_device *dev, u32 offset) { u8 data = 0; @@ -209,11 +182,7 @@ PlatformIORead1Byte( return data; } -u16 -PlatformIORead2Byte( - struct net_device *dev, - u32 offset - ) +u16 PlatformIORead2Byte(struct net_device *dev, u32 offset) { u16 data = 0; @@ -223,11 +192,7 @@ PlatformIORead2Byte( return data; } -u32 -PlatformIORead4Byte( - struct net_device *dev, - u32 offset - ) +u32 PlatformIORead4Byte(struct net_device *dev, u32 offset) { u32 data = 0; @@ -242,22 +207,19 @@ void SetOutputEnableOfRfPins(struct net_device *dev) write_nic_word(dev, RFPinsEnable, 0x1bff); } -static int -HwHSSIThreeWire( - struct net_device *dev, - u8 *pDataBuf, - u8 nDataBufBitCnt, - int bSI, - int bWrite - ) +static int HwHSSIThreeWire(struct net_device *dev, + u8 *pDataBuf, + u8 nDataBufBitCnt, + int bSI, + int bWrite) { int bResult = 1; u8 TryCnt; u8 u1bTmp; - do { + do { /* Check if WE and RE are cleared. */ - for (TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++) { + for (TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++) { u1bTmp = read_nic_byte(dev, SW_3W_CMD1); if ((u1bTmp & (SW_3W_CMD1_RE|SW_3W_CMD1_WE)) == 0) break; @@ -275,15 +237,15 @@ HwHSSIThreeWire( u1bTmp = read_nic_byte(dev, RF_SW_CONFIG); if (bSI) - u1bTmp |= RF_SW_CFG_SI; /* reg08[1]=1 Serial Interface(SI) */ + u1bTmp |= RF_SW_CFG_SI; /* reg08[1]=1 Serial Interface(SI) */ else - u1bTmp &= ~RF_SW_CFG_SI; /* reg08[1]=0 Parallel Interface(PI) */ + u1bTmp &= ~RF_SW_CFG_SI; /* reg08[1]=0 Parallel Interface(PI) */ write_nic_byte(dev, RF_SW_CONFIG, u1bTmp); - if (bSI) { + if (bSI) { /* jong: HW SI read must set reg84[3]=0. */ u1bTmp = read_nic_byte(dev, RFPinsSelect); u1bTmp &= ~BIT3; @@ -291,14 +253,14 @@ HwHSSIThreeWire( } /* Fill up data buffer for write operation. */ - if (bWrite) { - if (nDataBufBitCnt == 16) { + if (bWrite) { + if (nDataBufBitCnt == 16) { write_nic_word(dev, SW_3W_DB0, *((u16 *)pDataBuf)); - } else if (nDataBufBitCnt == 64) { + } else if (nDataBufBitCnt == 64) { /* RTL8187S shouldn't enter this case */ write_nic_dword(dev, SW_3W_DB0, *((u32 *)pDataBuf)); write_nic_dword(dev, SW_3W_DB1, *((u32 *)(pDataBuf + 4))); - } else { + } else { int idx; int ByteCnt = nDataBufBitCnt / 8; /* printk("%d\n",nDataBufBitCnt); */ @@ -324,11 +286,11 @@ HwHSSIThreeWire( write_nic_byte(dev, (SW_3W_DB0+idx), *(pDataBuf+idx)); } - } else { /* read */ - if (bSI) { - /* SI - reg274[3:0] : RF register's Address */ + } else { /* read */ + if (bSI) { + /* SI - reg274[3:0] : RF register's Address */ write_nic_word(dev, SW_3W_DB0, *((u16 *)pDataBuf)); - } else { + } else { /* PI - reg274[15:12] : RF register's Address */ write_nic_word(dev, SW_3W_DB0, (*((u16 *)pDataBuf)) << 12); } @@ -343,7 +305,7 @@ HwHSSIThreeWire( /* Check if DONE is set. */ - for (TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++) { + for (TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++) { u1bTmp = read_nic_byte(dev, SW_3W_CMD1); if ((u1bTmp & SW_3W_CMD1_DONE) != 0) break; @@ -353,12 +315,12 @@ HwHSSIThreeWire( write_nic_byte(dev, SW_3W_CMD1, 0); - /* Read back data for read operation. */ - if (bWrite == 0) { - if (bSI) { + /* Read back data for read operation. */ + if (bWrite == 0) { + if (bSI) { /* Serial Interface : reg363_362[11:0] */ *((u16 *)pDataBuf) = read_nic_word(dev, SI_DATA_READ) ; - } else { + } else { /* Parallel Interface : reg361_360[11:0] */ *((u16 *)pDataBuf) = read_nic_word(dev, PI_DATA_READ); } @@ -366,13 +328,12 @@ HwHSSIThreeWire( *((u16 *)pDataBuf) &= 0x0FFF; } - } while (0); + } while (0); return bResult; } -void -RF_WriteReg(struct net_device *dev, u8 offset, u32 data) +void RF_WriteReg(struct net_device *dev, u8 offset, u32 data) { u32 data2Write; u8 len; @@ -400,11 +361,7 @@ u32 RF_ReadReg(struct net_device *dev, u8 offset) /* by Owen on 04/07/14 for writing BB register successfully */ -void -WriteBBPortUchar( - struct net_device *dev, - u32 Data - ) +void WriteBBPortUchar(struct net_device *dev, u32 Data) { /* u8 TimeoutCounter; */ u8 RegisterContent; @@ -421,11 +378,7 @@ WriteBBPortUchar( } } -u8 -ReadBBPortUchar( - struct net_device *dev, - u32 addr - ) +u8 ReadBBPortUchar(struct net_device *dev, u32 addr) { /*u8 TimeoutCounter; */ u8 RegisterContent; @@ -435,66 +388,62 @@ ReadBBPortUchar( return RegisterContent; } -/* {by amy 080312 */ /* - Description: - Perform Antenna settings with antenna diversity on 87SE. - Created by Roger, 2008.01.25. -*/ -bool -SetAntennaConfig87SE( - struct net_device *dev, - u8 DefaultAnt, /* 0: Main, 1: Aux. */ - bool bAntDiversity /* 1:Enable, 0: Disable. */ -) + * Description: + * Perform Antenna settings with antenna diversity on 87SE. + * Created by Roger, 2008.01.25. + */ +bool SetAntennaConfig87SE(struct net_device *dev, + u8 DefaultAnt, /* 0: Main, 1: Aux. */ + bool bAntDiversity) /* 1:Enable, 0: Disable. */ { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); bool bAntennaSwitched = true; /* printk("SetAntennaConfig87SE(): DefaultAnt(%d), bAntDiversity(%d)\n", DefaultAnt, bAntDiversity); */ - /* Threshold for antenna diversity. */ + /* Threshold for antenna diversity. */ write_phy_cck(dev, 0x0c, 0x09); /* Reg0c : 09 */ - if (bAntDiversity) { /* Enable Antenna Diversity. */ - if (DefaultAnt == 1) { /* aux antenna */ + if (bAntDiversity) { /* Enable Antenna Diversity. */ + if (DefaultAnt == 1) { /* aux antenna */ - /* Mac register, aux antenna */ + /* Mac register, aux antenna */ write_nic_byte(dev, ANTSEL, 0x00); - /* Config CCK RX antenna. */ + /* Config CCK RX antenna. */ write_phy_cck(dev, 0x11, 0xbb); /* Reg11 : bb */ write_phy_cck(dev, 0x01, 0xc7); /* Reg01 : c7 */ - /* Config OFDM RX antenna. */ - write_phy_ofdm(dev, 0x0D, 0x54); /* Reg0d : 54 */ - write_phy_ofdm(dev, 0x18, 0xb2); /* Reg18 : b2 */ - } else { /* use main antenna */ - /* Mac register, main antenna */ + /* Config OFDM RX antenna. */ + write_phy_ofdm(dev, 0x0D, 0x54); /* Reg0d : 54 */ + write_phy_ofdm(dev, 0x18, 0xb2); /* Reg18 : b2 */ + } else { /* use main antenna */ + /* Mac register, main antenna */ write_nic_byte(dev, ANTSEL, 0x03); - /* base band */ - /* Config CCK RX antenna. */ - write_phy_cck(dev, 0x11, 0x9b); /* Reg11 : 9b */ - write_phy_cck(dev, 0x01, 0xc7); /* Reg01 : c7 */ + /* base band */ + /* Config CCK RX antenna. */ + write_phy_cck(dev, 0x11, 0x9b); /* Reg11 : 9b */ + write_phy_cck(dev, 0x01, 0xc7); /* Reg01 : c7 */ /* Config OFDM RX antenna. */ write_phy_ofdm(dev, 0x0d, 0x5c); /* Reg0d : 5c */ write_phy_ofdm(dev, 0x18, 0xb2); /* Reg18 : b2 */ } - } else { + } else { /* Disable Antenna Diversity. */ - if (DefaultAnt == 1) { /* aux Antenna */ + if (DefaultAnt == 1) { /* aux Antenna */ /* Mac register, aux antenna */ write_nic_byte(dev, ANTSEL, 0x00); /* Config CCK RX antenna. */ - write_phy_cck(dev, 0x11, 0xbb); /* Reg11 : bb */ - write_phy_cck(dev, 0x01, 0x47); /* Reg01 : 47 */ + write_phy_cck(dev, 0x11, 0xbb); /* Reg11 : bb */ + write_phy_cck(dev, 0x01, 0x47); /* Reg01 : 47 */ /* Config OFDM RX antenna. */ - write_phy_ofdm(dev, 0x0D, 0x54); /* Reg0d : 54 */ - write_phy_ofdm(dev, 0x18, 0x32); /* Reg18 : 32 */ - } else { /* main Antenna */ + write_phy_ofdm(dev, 0x0D, 0x54); /* Reg0d : 54 */ + write_phy_ofdm(dev, 0x18, 0x32); /* Reg18 : 32 */ + } else { /* main Antenna */ /* Mac register, main antenna */ write_nic_byte(dev, ANTSEL, 0x03); @@ -502,25 +451,22 @@ SetAntennaConfig87SE( write_phy_cck(dev, 0x11, 0x9b); /* Reg11 : 9b */ write_phy_cck(dev, 0x01, 0x47); /* Reg01 : 47 */ - /* Config OFDM RX antenna. */ - write_phy_ofdm(dev, 0x0D, 0x5c); /* Reg0d : 5c */ - write_phy_ofdm(dev, 0x18, 0x32); /*Reg18 : 32 */ + /* Config OFDM RX antenna. */ + write_phy_ofdm(dev, 0x0D, 0x5c); /* Reg0d : 5c */ + write_phy_ofdm(dev, 0x18, 0x32); /*Reg18 : 32 */ } } priv->CurrAntennaIndex = DefaultAnt; /* Update default settings. */ return bAntennaSwitched; } -/* by amy 080312 */ /* ---------------------------------------------------------------- - * Hardware Initialization. - * the code is ported from Windows source code -----------------------------------------------------------------*/ - -void -ZEBRA_Config_85BASIC_HardCode( - struct net_device *dev - ) + *-------------------------------------------------------------- + * Hardware Initialization. + * the code is ported from Windows source code + *-------------------------------------------------------------- + */ + +void ZEBRA_Config_85BASIC_HardCode(struct net_device *dev) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); @@ -532,163 +478,151 @@ ZEBRA_Config_85BASIC_HardCode( /* -============================================================================= - 87S_PCIE :: RADIOCFG.TXT -============================================================================= -*/ + *=========================================================================== + * 87S_PCIE :: RADIOCFG.TXT + *=========================================================================== + */ /* Page1 : reg16-reg30 */ - RF_WriteReg(dev, 0x00, 0x013f); mdelay(1); /* switch to page1 */ - u4bRF23 = RF_ReadReg(dev, 0x08); mdelay(1); - u4bRF24 = RF_ReadReg(dev, 0x09); mdelay(1); + RF_WriteReg(dev, 0x00, 0x013f); mdelay(1); /* switch to page1 */ + u4bRF23 = RF_ReadReg(dev, 0x08); mdelay(1); + u4bRF24 = RF_ReadReg(dev, 0x09); mdelay(1); if (u4bRF23 == 0x818 && u4bRF24 == 0x70C) { d_cut = 1; printk(KERN_INFO "rtl8187se: card type changed from C- to D-cut\n"); } - /* Page0 : reg0-reg15 */ - - RF_WriteReg(dev, 0x00, 0x009f); mdelay(1);/* 1 */ - - RF_WriteReg(dev, 0x01, 0x06e0); mdelay(1); - - RF_WriteReg(dev, 0x02, 0x004d); mdelay(1);/* 2 */ - - RF_WriteReg(dev, 0x03, 0x07f1); mdelay(1);/* 3 */ - - RF_WriteReg(dev, 0x04, 0x0975); mdelay(1); - RF_WriteReg(dev, 0x05, 0x0c72); mdelay(1); - RF_WriteReg(dev, 0x06, 0x0ae6); mdelay(1); - RF_WriteReg(dev, 0x07, 0x00ca); mdelay(1); - RF_WriteReg(dev, 0x08, 0x0e1c); mdelay(1); - RF_WriteReg(dev, 0x09, 0x02f0); mdelay(1); - RF_WriteReg(dev, 0x0a, 0x09d0); mdelay(1); - RF_WriteReg(dev, 0x0b, 0x01ba); mdelay(1); - RF_WriteReg(dev, 0x0c, 0x0640); mdelay(1); - RF_WriteReg(dev, 0x0d, 0x08df); mdelay(1); - RF_WriteReg(dev, 0x0e, 0x0020); mdelay(1); - RF_WriteReg(dev, 0x0f, 0x0990); mdelay(1); - + /* Page0 : reg0-reg15 */ + + RF_WriteReg(dev, 0x00, 0x009f); mdelay(1);/* 1 */ + RF_WriteReg(dev, 0x01, 0x06e0); mdelay(1); + RF_WriteReg(dev, 0x02, 0x004d); mdelay(1);/* 2 */ + RF_WriteReg(dev, 0x03, 0x07f1); mdelay(1);/* 3 */ + RF_WriteReg(dev, 0x04, 0x0975); mdelay(1); + RF_WriteReg(dev, 0x05, 0x0c72); mdelay(1); + RF_WriteReg(dev, 0x06, 0x0ae6); mdelay(1); + RF_WriteReg(dev, 0x07, 0x00ca); mdelay(1); + RF_WriteReg(dev, 0x08, 0x0e1c); mdelay(1); + RF_WriteReg(dev, 0x09, 0x02f0); mdelay(1); + RF_WriteReg(dev, 0x0a, 0x09d0); mdelay(1); + RF_WriteReg(dev, 0x0b, 0x01ba); mdelay(1); + RF_WriteReg(dev, 0x0c, 0x0640); mdelay(1); + RF_WriteReg(dev, 0x0d, 0x08df); mdelay(1); + RF_WriteReg(dev, 0x0e, 0x0020); mdelay(1); + RF_WriteReg(dev, 0x0f, 0x0990); mdelay(1); /* Page1 : reg16-reg30 */ - RF_WriteReg(dev, 0x00, 0x013f); mdelay(1); - - RF_WriteReg(dev, 0x03, 0x0806); mdelay(1); - - RF_WriteReg(dev, 0x04, 0x03a7); mdelay(1); - RF_WriteReg(dev, 0x05, 0x059b); mdelay(1); - RF_WriteReg(dev, 0x06, 0x0081); mdelay(1); - - - RF_WriteReg(dev, 0x07, 0x01A0); mdelay(1); + RF_WriteReg(dev, 0x00, 0x013f); mdelay(1); + RF_WriteReg(dev, 0x03, 0x0806); mdelay(1); + RF_WriteReg(dev, 0x04, 0x03a7); mdelay(1); + RF_WriteReg(dev, 0x05, 0x059b); mdelay(1); + RF_WriteReg(dev, 0x06, 0x0081); mdelay(1); + RF_WriteReg(dev, 0x07, 0x01A0); mdelay(1); /* Don't write RF23/RF24 to make a difference between 87S C cut and D cut. asked by SD3 stevenl. */ - RF_WriteReg(dev, 0x0a, 0x0001); mdelay(1); - RF_WriteReg(dev, 0x0b, 0x0418); mdelay(1); + RF_WriteReg(dev, 0x0a, 0x0001); mdelay(1); + RF_WriteReg(dev, 0x0b, 0x0418); mdelay(1); if (d_cut) { - RF_WriteReg(dev, 0x0c, 0x0fbe); mdelay(1); - RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1); - RF_WriteReg(dev, 0x0e, 0x0807); mdelay(1); /* RX LO buffer */ - } else { - RF_WriteReg(dev, 0x0c, 0x0fbe); mdelay(1); - RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1); - RF_WriteReg(dev, 0x0e, 0x0806); mdelay(1); /* RX LO buffer */ + RF_WriteReg(dev, 0x0c, 0x0fbe); mdelay(1); + RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1); + RF_WriteReg(dev, 0x0e, 0x0807); mdelay(1); /* RX LO buffer */ + } else { + RF_WriteReg(dev, 0x0c, 0x0fbe); mdelay(1); + RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1); + RF_WriteReg(dev, 0x0e, 0x0806); mdelay(1); /* RX LO buffer */ } - RF_WriteReg(dev, 0x0f, 0x0acc); mdelay(1); - - RF_WriteReg(dev, 0x00, 0x01d7); mdelay(1); /* 6 */ + RF_WriteReg(dev, 0x0f, 0x0acc); mdelay(1); + RF_WriteReg(dev, 0x00, 0x01d7); mdelay(1); /* 6 */ + RF_WriteReg(dev, 0x03, 0x0e00); mdelay(1); + RF_WriteReg(dev, 0x04, 0x0e50); mdelay(1); - RF_WriteReg(dev, 0x03, 0x0e00); mdelay(1); - RF_WriteReg(dev, 0x04, 0x0e50); mdelay(1); - for (i = 0; i <= 36; i++) { - RF_WriteReg(dev, 0x01, i); mdelay(1); + for (i = 0; i <= 36; i++) { + RF_WriteReg(dev, 0x01, i); mdelay(1); RF_WriteReg(dev, 0x02, ZEBRA_RF_RX_GAIN_TABLE[i]); mdelay(1); } - RF_WriteReg(dev, 0x05, 0x0203); mdelay(1); /* 203, 343 */ - RF_WriteReg(dev, 0x06, 0x0200); mdelay(1); /* 400 */ + RF_WriteReg(dev, 0x05, 0x0203); mdelay(1); /* 203, 343 */ + RF_WriteReg(dev, 0x06, 0x0200); mdelay(1); /* 400 */ + RF_WriteReg(dev, 0x00, 0x0137); mdelay(1); /* switch to reg16-reg30, and HSSI disable 137 */ + mdelay(10); /* Deay 10 ms. */ /* 0xfd */ - RF_WriteReg(dev, 0x00, 0x0137); mdelay(1); /* switch to reg16-reg30, and HSSI disable 137 */ - mdelay(10); /* Deay 10 ms. */ /* 0xfd */ + RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1); /* Z4 synthesizer loop filter setting, 392 */ + mdelay(10); /* Deay 10 ms. */ /* 0xfd */ - RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1); /* Z4 synthesizer loop filter setting, 392 */ - mdelay(10); /* Deay 10 ms. */ /* 0xfd */ + RF_WriteReg(dev, 0x00, 0x0037); mdelay(1); /* switch to reg0-reg15, and HSSI disable */ + mdelay(10); /* Deay 10 ms. */ /* 0xfd */ - RF_WriteReg(dev, 0x00, 0x0037); mdelay(1); /* switch to reg0-reg15, and HSSI disable */ - mdelay(10); /* Deay 10 ms. */ /* 0xfd */ + RF_WriteReg(dev, 0x04, 0x0160); mdelay(1); /* CBC on, Tx Rx disable, High gain */ + mdelay(10); /* Deay 10 ms. */ /* 0xfd */ - RF_WriteReg(dev, 0x04, 0x0160); mdelay(1); /* CBC on, Tx Rx disable, High gain */ - mdelay(10); /* Deay 10 ms. */ /* 0xfd */ + RF_WriteReg(dev, 0x07, 0x0080); mdelay(1); /* Z4 setted channel 1 */ + mdelay(10); /* Deay 10 ms. */ /* 0xfd */ - RF_WriteReg(dev, 0x07, 0x0080); mdelay(1); /* Z4 setted channel 1 */ - mdelay(10); /* Deay 10 ms. */ /* 0xfd */ + RF_WriteReg(dev, 0x02, 0x088D); mdelay(1); /* LC calibration */ + mdelay(200); /* Deay 200 ms. */ /* 0xfd */ + mdelay(10); /* Deay 10 ms. */ /* 0xfd */ + mdelay(10); /* Deay 10 ms. */ /* 0xfd */ - RF_WriteReg(dev, 0x02, 0x088D); mdelay(1); /* LC calibration */ - mdelay(200); /* Deay 200 ms. */ /* 0xfd */ - mdelay(10); /* Deay 10 ms. */ /* 0xfd */ - mdelay(10); /* Deay 10 ms. */ /* 0xfd */ + RF_WriteReg(dev, 0x00, 0x0137); mdelay(1); /* switch to reg16-reg30 137, and HSSI disable 137 */ + mdelay(10); /* Deay 10 ms. */ /* 0xfd */ - RF_WriteReg(dev, 0x00, 0x0137); mdelay(1); /* switch to reg16-reg30 137, and HSSI disable 137 */ - mdelay(10); /* Deay 10 ms. */ /* 0xfd */ - - RF_WriteReg(dev, 0x07, 0x0000); mdelay(1); - RF_WriteReg(dev, 0x07, 0x0180); mdelay(1); - RF_WriteReg(dev, 0x07, 0x0220); mdelay(1); - RF_WriteReg(dev, 0x07, 0x03E0); mdelay(1); + RF_WriteReg(dev, 0x07, 0x0000); mdelay(1); + RF_WriteReg(dev, 0x07, 0x0180); mdelay(1); + RF_WriteReg(dev, 0x07, 0x0220); mdelay(1); + RF_WriteReg(dev, 0x07, 0x03E0); mdelay(1); /* DAC calibration off 20070702 */ - RF_WriteReg(dev, 0x06, 0x00c1); mdelay(1); - RF_WriteReg(dev, 0x0a, 0x0001); mdelay(1); -/* {by amy 080312 */ + RF_WriteReg(dev, 0x06, 0x00c1); mdelay(1); + RF_WriteReg(dev, 0x0a, 0x0001); mdelay(1); /* For crystal calibration, added by Roger, 2007.12.11. */ - if (priv->bXtalCalibration) { /* reg 30. */ - /* enable crystal calibration. - RF Reg[30], (1)Xin:[12:9], Xout:[8:5], addr[4:0]. - (2)PA Pwr delay timer[15:14], default: 2.4us, set BIT15=0 - (3)RF signal on/off when calibration[13], default: on, set BIT13=0. - So we should minus 4 BITs offset. */ - RF_WriteReg(dev, 0x0f, (priv->XtalCal_Xin<<5) | (priv->XtalCal_Xout<<1) | BIT11 | BIT9); mdelay(1); + if (priv->bXtalCalibration) { /* reg 30. */ + /* + * enable crystal calibration. + * RF Reg[30], (1)Xin:[12:9], Xout:[8:5], addr[4:0]. + * (2)PA Pwr delay timer[15:14], default: 2.4us, set BIT15=0 + * (3)RF signal on/off when calibration[13], default: on, set BIT13=0. + * So we should minus 4 BITs offset. + */ + RF_WriteReg(dev, 0x0f, (priv->XtalCal_Xin<<5) | (priv->XtalCal_Xout<<1) | BIT11 | BIT9); mdelay(1); printk("ZEBRA_Config_85BASIC_HardCode(): (%02x)\n", - (priv->XtalCal_Xin<<5) | (priv->XtalCal_Xout<<1) | BIT11 | BIT9); - } else { + (priv->XtalCal_Xin<<5) | (priv->XtalCal_Xout<<1) | BIT11 | BIT9); + } else { /* using default value. Xin=6, Xout=6. */ - RF_WriteReg(dev, 0x0f, 0x0acc); mdelay(1); + RF_WriteReg(dev, 0x0f, 0x0acc); mdelay(1); } -/* by amy 080312 */ - RF_WriteReg(dev, 0x00, 0x00bf); mdelay(1); /* switch to reg0-reg15, and HSSI enable */ - RF_WriteReg(dev, 0x0d, 0x08df); mdelay(1); /* Rx BB start calibration, 00c//+edward */ - RF_WriteReg(dev, 0x02, 0x004d); mdelay(1); /* temperature meter off */ - RF_WriteReg(dev, 0x04, 0x0975); mdelay(1); /* Rx mode */ + RF_WriteReg(dev, 0x00, 0x00bf); mdelay(1); /* switch to reg0-reg15, and HSSI enable */ + RF_WriteReg(dev, 0x0d, 0x08df); mdelay(1); /* Rx BB start calibration, 00c//+edward */ + RF_WriteReg(dev, 0x02, 0x004d); mdelay(1); /* temperature meter off */ + RF_WriteReg(dev, 0x04, 0x0975); mdelay(1); /* Rx mode */ mdelay(10); /* Deay 10 ms.*/ /* 0xfe */ mdelay(10); /* Deay 10 ms.*/ /* 0xfe */ mdelay(10); /* Deay 10 ms.*/ /* 0xfe */ - RF_WriteReg(dev, 0x00, 0x0197); mdelay(1); /* Rx mode*/ /*+edward */ - RF_WriteReg(dev, 0x05, 0x05ab); mdelay(1); /* Rx mode*/ /*+edward */ - RF_WriteReg(dev, 0x00, 0x009f); mdelay(1); /* Rx mode*/ /*+edward */ - - RF_WriteReg(dev, 0x01, 0x0000); mdelay(1); /* Rx mode*/ /*+edward */ - RF_WriteReg(dev, 0x02, 0x0000); mdelay(1); /* Rx mode*/ /*+edward */ - /* power save parameters. */ + RF_WriteReg(dev, 0x00, 0x0197); mdelay(1); /* Rx mode*/ /*+edward */ + RF_WriteReg(dev, 0x05, 0x05ab); mdelay(1); /* Rx mode*/ /*+edward */ + RF_WriteReg(dev, 0x00, 0x009f); mdelay(1); /* Rx mode*/ /*+edward */ + RF_WriteReg(dev, 0x01, 0x0000); mdelay(1); /* Rx mode*/ /*+edward */ + RF_WriteReg(dev, 0x02, 0x0000); mdelay(1); /* Rx mode*/ /*+edward */ + /* power save parameters. */ u1b24E = read_nic_byte(dev, 0x24E); write_nic_byte(dev, 0x24E, (u1b24E & (~(BIT5|BIT6)))); /*============================================================================= - - ============================================================================= - CCKCONF.TXT - ============================================================================= - */ - /* [POWER SAVE] Power Saving Parameters by jong. 2007-11-27 - CCK reg0x00[7]=1'b1 :power saving for TX (default) - CCK reg0x00[6]=1'b1: power saving for RX (default) - CCK reg0x06[4]=1'b1: turn off channel estimation related circuits if not doing channel estimation. - CCK reg0x06[3]=1'b1: turn off unused circuits before cca = 1 - CCK reg0x06[2]=1'b1: turn off cck's circuit if macrst =0 - */ + * + *=========================================================================== + * CCKCONF.TXT + *=========================================================================== + * + * [POWER SAVE] Power Saving Parameters by jong. 2007-11-27 + * CCK reg0x00[7]=1'b1 :power saving for TX (default) + * CCK reg0x00[6]=1'b1: power saving for RX (default) + * CCK reg0x06[4]=1'b1: turn off channel estimation related circuits if not doing channel estimation. + * CCK reg0x06[3]=1'b1: turn off unused circuits before cca = 1 + * CCK reg0x06[2]=1'b1: turn off cck's circuit if macrst =0 + */ write_phy_cck(dev, 0x00, 0xc8); write_phy_cck(dev, 0x06, 0x1c); @@ -697,7 +631,7 @@ ZEBRA_Config_85BASIC_HardCode( write_phy_cck(dev, 0x2f, 0x06); write_phy_cck(dev, 0x01, 0x46); - /* power control */ + /* power control */ write_nic_byte(dev, CCK_TXAGC, 0x10); write_nic_byte(dev, OFDM_TXAGC, 0x1B); write_nic_byte(dev, ANTSEL, 0x03); @@ -705,14 +639,14 @@ ZEBRA_Config_85BASIC_HardCode( /* - ============================================================================= - AGC.txt - ============================================================================= - */ + *=========================================================================== + * AGC.txt + *=========================================================================== + */ write_phy_ofdm(dev, 0x00, 0x12); - for (i = 0; i < 128; i++) { + for (i = 0; i < 128; i++) { data = ZEBRA_AGC[i+1]; data = data << 8; @@ -730,49 +664,43 @@ ZEBRA_Config_85BASIC_HardCode( PlatformIOWrite4Byte(dev, PhyAddr, 0x00001080); /* Annie, 2006-05-05 */ /* - ============================================================================= - - ============================================================================= - OFDMCONF.TXT - ============================================================================= - */ - - for (i = 0; i < 60; i++) { + *=========================================================================== + * + *=========================================================================== + * OFDMCONF.TXT + *=========================================================================== + */ + + for (i = 0; i < 60; i++) { u4bRegOffset = i; u4bRegValue = OFDM_CONFIG[i]; WriteBBPortUchar(dev, - (0x00000080 | - (u4bRegOffset & 0x7f) | - ((u4bRegValue & 0xff) << 8))); + (0x00000080 | + (u4bRegOffset & 0x7f) | + ((u4bRegValue & 0xff) << 8))); } /* - ============================================================================= - by amy for antenna - ============================================================================= - */ -/* {by amy 080312 */ + *=========================================================================== + * by amy for antenna + *=========================================================================== + */ /* Config Sw/Hw Combinational Antenna Diversity. Added by Roger, 2008.02.26. */ SetAntennaConfig87SE(dev, priv->bDefaultAntenna1, priv->bSwAntennaDiverity); -/* by amy 080312} */ -/* by amy for antenna */ } -void -UpdateInitialGain( - struct net_device *dev - ) +void UpdateInitialGain(struct net_device *dev) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); /* lzm add 080826 */ - if (priv->eRFPowerState != eRfOn) { + if (priv->eRFPowerState != eRfOn) { /* Don't access BB/RF under disable PLL situation. - RT_TRACE(COMP_DIG, DBG_LOUD, ("UpdateInitialGain - pHalData->eRFPowerState!=eRfOn\n")); - Back to the original state - */ + * RT_TRACE(COMP_DIG, DBG_LOUD, ("UpdateInitialGain - pHalData->eRFPowerState!=eRfOn\n")); + * Back to the original state + */ priv->InitialGain = priv->InitialGainBackUp; return; } @@ -826,7 +754,7 @@ UpdateInitialGain( write_phy_ofdm(dev, 0x05, 0xfc); mdelay(1); break; - default: /* MP */ + default: /* MP */ write_phy_ofdm(dev, 0x17, 0x26); mdelay(1); write_phy_ofdm(dev, 0x24, 0x86); mdelay(1); write_phy_ofdm(dev, 0x05, 0xfa); mdelay(1); @@ -834,14 +762,11 @@ UpdateInitialGain( } } /* - Description: - Tx Power tracking mechanism routine on 87SE. - Created by Roger, 2007.12.11. -*/ -void -InitTxPwrTracking87SE( - struct net_device *dev -) + * Description: + * Tx Power tracking mechanism routine on 87SE. + * Created by Roger, 2007.12.11. + */ +void InitTxPwrTracking87SE(struct net_device *dev) { u32 u4bRfReg; @@ -851,49 +776,41 @@ InitTxPwrTracking87SE( RF_WriteReg(dev, 0x02, u4bRfReg|PWR_METER_EN); mdelay(1); } -void -PhyConfig8185( - struct net_device *dev - ) +void PhyConfig8185(struct net_device *dev) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); write_nic_dword(dev, RCR, priv->ReceiveConfig); priv->RFProgType = read_nic_byte(dev, CONFIG4) & 0x03; /* RF config */ ZEBRA_Config_85BASIC_HardCode(dev); -/* {by amy 080312 */ /* Set default initial gain state to 4, approved by SD3 DZ, by Bruce, 2007-06-06. */ - if (priv->bDigMechanism) { + if (priv->bDigMechanism) { if (priv->InitialGain == 0) priv->InitialGain = 4; } /* - Enable thermal meter indication to implement TxPower tracking on 87SE. - We initialize thermal meter here to avoid unsuccessful configuration. - Added by Roger, 2007.12.11. - */ + * Enable thermal meter indication to implement TxPower tracking on 87SE. + * We initialize thermal meter here to avoid unsuccessful configuration. + * Added by Roger, 2007.12.11. + */ if (priv->bTxPowerTrack) InitTxPwrTracking87SE(dev); -/* by amy 080312} */ priv->InitialGainBackUp = priv->InitialGain; UpdateInitialGain(dev); return; } -void -HwConfigureRTL8185( - struct net_device *dev - ) +void HwConfigureRTL8185(struct net_device *dev) { /* RTL8185_TODO: Determine Retrylimit, TxAGC, AutoRateFallback control. */ - u8 bUNIVERSAL_CONTROL_RL = 0; - u8 bUNIVERSAL_CONTROL_AGC = 1; - u8 bUNIVERSAL_CONTROL_ANT = 1; - u8 bAUTO_RATE_FALLBACK_CTL = 1; - u8 val8; + u8 bUNIVERSAL_CONTROL_RL = 0; + u8 bUNIVERSAL_CONTROL_AGC = 1; + u8 bUNIVERSAL_CONTROL_ANT = 1; + u8 bAUTO_RATE_FALLBACK_CTL = 1; + u8 val8; write_nic_word(dev, BRSR, 0x0fff); /* Retry limit */ val8 = read_nic_byte(dev, CW_CONF); @@ -907,24 +824,24 @@ HwConfigureRTL8185( /* Tx AGC */ val8 = read_nic_byte(dev, TXAGC_CTL); - if (bUNIVERSAL_CONTROL_AGC) { + if (bUNIVERSAL_CONTROL_AGC) { write_nic_byte(dev, CCK_TXAGC, 128); write_nic_byte(dev, OFDM_TXAGC, 128); val8 = val8 & 0xfe; - } else { + } else { val8 = val8 | 0x01 ; } write_nic_byte(dev, TXAGC_CTL, val8); - /* Tx Antenna including Feedback control */ + /* Tx Antenna including Feedback control */ val8 = read_nic_byte(dev, TXAGC_CTL); - if (bUNIVERSAL_CONTROL_ANT) { + if (bUNIVERSAL_CONTROL_ANT) { write_nic_byte(dev, ANTSEL, 0x00); val8 = val8 & 0xfd; - } else { + } else { val8 = val8 & (val8|0x02); /* xiong-2006-11-15 */ } @@ -933,7 +850,7 @@ HwConfigureRTL8185( /* Auto Rate fallback control */ val8 = read_nic_byte(dev, RATE_FALLBACK); val8 &= 0x7c; - if (bAUTO_RATE_FALLBACK_CTL) { + if (bAUTO_RATE_FALLBACK_CTL) { val8 |= RATE_FALLBACK_CTL_ENABLE | RATE_FALLBACK_CTL_AUTO_STEP1; /* We shall set up the ARFR according to user's setting. */ @@ -942,40 +859,34 @@ HwConfigureRTL8185( write_nic_byte(dev, RATE_FALLBACK, val8); } -static void -MacConfig_85BASIC_HardCode( - struct net_device *dev) +static void MacConfig_85BASIC_HardCode(struct net_device *dev) { /* - ============================================================================ - MACREG.TXT - ============================================================================ - */ - int nLinesRead = 0; - - u32 u4bRegOffset, u4bRegValue, u4bPageIndex = 0; - int i; + *========================================================================== + * MACREG.TXT + *========================================================================== + */ + int nLinesRead = 0; + u32 u4bRegOffset, u4bRegValue, u4bPageIndex = 0; + int i; nLinesRead = sizeof(MAC_REG_TABLE)/2; - for (i = 0; i < nLinesRead; i++) { /* nLinesRead=101 */ + for (i = 0; i < nLinesRead; i++) { /* nLinesRead=101 */ u4bRegOffset = MAC_REG_TABLE[i][0]; u4bRegValue = MAC_REG_TABLE[i][1]; if (u4bRegOffset == 0x5e) u4bPageIndex = u4bRegValue; - else - u4bRegOffset |= (u4bPageIndex << 8); + u4bRegOffset |= (u4bPageIndex << 8); write_nic_byte(dev, u4bRegOffset, (u8)u4bRegValue); } /* ============================================================================ */ } -static void -MacConfig_85BASIC( - struct net_device *dev) +static void MacConfig_85BASIC(struct net_device *dev) { u8 u1DA; @@ -994,18 +905,18 @@ MacConfig_85BASIC( PlatformIOWrite4Byte(dev, 0x1F4, 0x00000000); PlatformIOWrite1Byte(dev, 0x1F8, 0x00); - /* Asked for by SD3 CM Lin, 2006.06.27, by rcnjko. */ - /* power save parameter based on "87SE power save parameters 20071127.doc", as follow. */ + /* Asked for by SD3 CM Lin, 2006.06.27, by rcnjko. */ + /* power save parameter based on "87SE power save parameters 20071127.doc", as follow. */ /* Enable DA10 TX power saving */ u1DA = read_nic_byte(dev, PHYPR); write_nic_byte(dev, PHYPR, (u1DA | BIT2)); - /* POWER: */ + /* POWER: */ write_nic_word(dev, 0x360, 0x1000); write_nic_word(dev, 0x362, 0x1000); - /* AFE. */ + /* AFE. */ write_nic_word(dev, 0x370, 0x0560); write_nic_word(dev, 0x372, 0x0560); write_nic_word(dev, 0x374, 0x0DA4); @@ -1013,54 +924,48 @@ MacConfig_85BASIC( write_nic_word(dev, 0x378, 0x0560); write_nic_word(dev, 0x37A, 0x0560); write_nic_word(dev, 0x37C, 0x00EC); - write_nic_word(dev, 0x37E, 0x00EC); /*+edward */ + write_nic_word(dev, 0x37E, 0x00EC); /* +edward */ write_nic_byte(dev, 0x24E, 0x01); } -u8 -GetSupportedWirelessMode8185( - struct net_device *dev -) +u8 GetSupportedWirelessMode8185(struct net_device *dev) { - u8 btSupportedWirelessMode = 0; + u8 btSupportedWirelessMode = 0; btSupportedWirelessMode = (WIRELESS_MODE_B | WIRELESS_MODE_G); return btSupportedWirelessMode; } -void -ActUpdateChannelAccessSetting( - struct net_device *dev, - WIRELESS_MODE WirelessMode, - PCHANNEL_ACCESS_SETTING ChnlAccessSetting - ) +void ActUpdateChannelAccessSetting(struct net_device *dev, + WIRELESS_MODE WirelessMode, + PCHANNEL_ACCESS_SETTING ChnlAccessSetting) { - struct r8180_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee80211; + struct r8180_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee80211; AC_CODING eACI; AC_PARAM AcParam; - u8 bFollowLegacySetting = 0; - u8 u1bAIFS; + u8 bFollowLegacySetting = 0; + u8 u1bAIFS; /* - - TODO: We still don't know how to set up these registers, just follow WMAC to - verify 8185B FPAG. - - - Jong said CWmin/CWmax register are not functional in 8185B, - so we shall fill channel access realted register into AC parameter registers, - even in nQBss. - */ + * + * TODO: We still don't know how to set up these registers, just follow WMAC to + * verify 8185B FPAG. + * + * + * Jong said CWmin/CWmax register are not functional in 8185B, + * so we shall fill channel access realted register into AC parameter registers, + * even in nQBss. + */ ChnlAccessSetting->SIFS_Timer = 0x22; /* Suggested by Jong, 2005.12.08. */ - ChnlAccessSetting->DIFS_Timer = 0x1C; /* 2006.06.02, by rcnjko. */ - ChnlAccessSetting->SlotTimeTimer = 9; /* 2006.06.02, by rcnjko. */ - ChnlAccessSetting->EIFS_Timer = 0x5B; /* Suggested by wcchu, it is the default value of EIFS register, 2005.12.08. */ - ChnlAccessSetting->CWminIndex = 3; /* 2006.06.02, by rcnjko. */ - ChnlAccessSetting->CWmaxIndex = 7; /* 2006.06.02, by rcnjko. */ + ChnlAccessSetting->DIFS_Timer = 0x1C; /* 2006.06.02, by rcnjko. */ + ChnlAccessSetting->SlotTimeTimer = 9; /* 2006.06.02, by rcnjko. */ + ChnlAccessSetting->EIFS_Timer = 0x5B; /* Suggested by wcchu, it is the default value of EIFS register, 2005.12.08. */ + ChnlAccessSetting->CWminIndex = 3; /* 2006.06.02, by rcnjko. */ + ChnlAccessSetting->CWmaxIndex = 7; /* 2006.06.02, by rcnjko. */ write_nic_byte(dev, SIFS, ChnlAccessSetting->SIFS_Timer); - write_nic_byte(dev, SLOT, ChnlAccessSetting->SlotTimeTimer); /* Rewrited from directly use PlatformEFIOWrite1Byte(), by Annie, 2006-03-29. */ + write_nic_byte(dev, SLOT, ChnlAccessSetting->SlotTimeTimer); /* Rewrited from directly use PlatformEFIOWrite1Byte(), by Annie, 2006-03-29. */ u1bAIFS = aSifsTime + (2 * ChnlAccessSetting->SlotTimeTimer); @@ -1074,17 +979,17 @@ ActUpdateChannelAccessSetting( } /* this setting is copied from rtl8187B. xiong-2006-11-13 */ - if (bFollowLegacySetting) { + if (bFollowLegacySetting) { /* - Follow 802.11 seeting to AC parameter, all AC shall use the same parameter. - 2005.12.01, by rcnjko. - */ + * Follow 802.11 seeting to AC parameter, all AC shall use the same parameter. + * 2005.12.01, by rcnjko. + */ AcParam.longData = 0; AcParam.f.AciAifsn.f.AIFSN = 2; /* Follow 802.11 DIFS. */ AcParam.f.AciAifsn.f.ACM = 0; - AcParam.f.Ecw.f.ECWmin = ChnlAccessSetting->CWminIndex; /* Follow 802.11 CWmin. */ - AcParam.f.Ecw.f.ECWmax = ChnlAccessSetting->CWmaxIndex; /* Follow 802.11 CWmax. */ + AcParam.f.Ecw.f.ECWmin = ChnlAccessSetting->CWminIndex; /* Follow 802.11 CWmin. */ + AcParam.f.Ecw.f.ECWmax = ChnlAccessSetting->CWmaxIndex; /* Follow 802.11 CWmax. */ AcParam.f.TXOPLimit = 0; /* lzm reserved 080826 */ @@ -1095,7 +1000,7 @@ ActUpdateChannelAccessSetting( if (ieee->iw_mode == IW_MODE_ADHOC) AcParam.f.TXOPLimit = 0x0020; - for (eACI = 0; eACI < AC_MAX; eACI++) { + for (eACI = 0; eACI < AC_MAX; eACI++) { AcParam.f.AciAifsn.f.ACI = (u8)eACI; { PAC_PARAM pAcParam = (PAC_PARAM)(&AcParam); @@ -1103,7 +1008,7 @@ ActUpdateChannelAccessSetting( u8 u1bAIFS; u32 u4bAcParam; - /* Retrive paramters to udpate. */ + /* Retrieve paramters to update. */ eACI = pAcParam->f.AciAifsn.f.ACI; u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * ChnlAccessSetting->SlotTimeTimer + aSifsTime; u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit)) << AC_PARAM_TXOP_LIMIT_OFFSET) | @@ -1111,7 +1016,7 @@ ActUpdateChannelAccessSetting( (((u32)(pAcParam->f.Ecw.f.ECWmin)) << AC_PARAM_ECW_MIN_OFFSET) | (((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET)); - switch (eACI) { + switch (eACI) { case AC1_BK: /* write_nic_dword(dev, AC_BK_PARAM, u4bAcParam); */ break; @@ -1133,47 +1038,46 @@ ActUpdateChannelAccessSetting( break; } - /* Cehck ACM bit. */ + /* Cehck ACM bit. */ /* If it is set, immediately set ACM control bit to downgrading AC for passing WMM testplan. Annie, 2005-12-13. */ { PACI_AIFSN pAciAifsn = (PACI_AIFSN)(&pAcParam->f.AciAifsn); AC_CODING eACI = pAciAifsn->f.ACI; - /*modified Joseph */ - /*for 8187B AsynIORead issue */ + /*for 8187B AsynIORead issue */ u8 AcmCtrl = 0; - if (pAciAifsn->f.ACM) { + if (pAciAifsn->f.ACM) { /* ACM bit is 1. */ - switch (eACI) { + switch (eACI) { case AC0_BE: - AcmCtrl |= (BEQ_ACM_EN|BEQ_ACM_CTL|ACM_HW_EN); /* or 0x21 */ + AcmCtrl |= (BEQ_ACM_EN|BEQ_ACM_CTL|ACM_HW_EN); /* or 0x21 */ break; case AC2_VI: - AcmCtrl |= (VIQ_ACM_EN|VIQ_ACM_CTL|ACM_HW_EN); /* or 0x42 */ + AcmCtrl |= (VIQ_ACM_EN|VIQ_ACM_CTL|ACM_HW_EN); /* or 0x42 */ break; case AC3_VO: - AcmCtrl |= (VOQ_ACM_EN|VOQ_ACM_CTL|ACM_HW_EN); /* or 0x84 */ + AcmCtrl |= (VOQ_ACM_EN|VOQ_ACM_CTL|ACM_HW_EN); /* or 0x84 */ break; default: DMESGW("SetHwReg8185(): [HW_VAR_ACM_CTRL] ACM set failed: eACI is %d\n", eACI); break; } - } else { + } else { /* ACM bit is 0. */ - switch (eACI) { + switch (eACI) { case AC0_BE: - AcmCtrl &= ((~BEQ_ACM_EN) & (~BEQ_ACM_CTL) & (~ACM_HW_EN)); /* and 0xDE */ + AcmCtrl &= ((~BEQ_ACM_EN) & (~BEQ_ACM_CTL) & (~ACM_HW_EN)); /* and 0xDE */ break; case AC2_VI: - AcmCtrl &= ((~VIQ_ACM_EN) & (~VIQ_ACM_CTL) & (~ACM_HW_EN)); /* and 0xBD */ + AcmCtrl &= ((~VIQ_ACM_EN) & (~VIQ_ACM_CTL) & (~ACM_HW_EN)); /* and 0xBD */ break; case AC3_VO: - AcmCtrl &= ((~VOQ_ACM_EN) & (~VOQ_ACM_CTL) & (~ACM_HW_EN)); /* and 0x7B */ + AcmCtrl &= ((~VOQ_ACM_EN) & (~VOQ_ACM_CTL) & (~ACM_HW_EN)); /* and 0x7B */ break; default: @@ -1187,53 +1091,51 @@ ActUpdateChannelAccessSetting( } } -void -ActSetWirelessMode8185( - struct net_device *dev, - u8 btWirelessMode - ) +void ActSetWirelessMode8185(struct net_device *dev, u8 btWirelessMode) { - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee80211; + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee80211; u8 btSupportedWirelessMode = GetSupportedWirelessMode8185(dev); if ((btWirelessMode & btSupportedWirelessMode) == 0) { - /* Don't switch to unsupported wireless mode, 2006.02.15, by rcnjko. */ + /* Don't switch to unsupported wireless mode, 2006.02.15, by rcnjko. */ DMESGW("ActSetWirelessMode8185(): WirelessMode(%d) is not supported (%d)!\n", btWirelessMode, btSupportedWirelessMode); return; } - /* 1. Assign wireless mode to swtich if necessary. */ - if (btWirelessMode == WIRELESS_MODE_AUTO) { - if ((btSupportedWirelessMode & WIRELESS_MODE_A)) { + /* 1. Assign wireless mode to switch if necessary. */ + if (btWirelessMode == WIRELESS_MODE_AUTO) { + if ((btSupportedWirelessMode & WIRELESS_MODE_A)) { btWirelessMode = WIRELESS_MODE_A; - } else if (btSupportedWirelessMode & WIRELESS_MODE_G) { + } else if (btSupportedWirelessMode & WIRELESS_MODE_G) { btWirelessMode = WIRELESS_MODE_G; - } else if ((btSupportedWirelessMode & WIRELESS_MODE_B)) { - btWirelessMode = WIRELESS_MODE_B; - } else { - DMESGW("ActSetWirelessMode8185(): No valid wireless mode supported, btSupportedWirelessMode(%x)!!!\n", - btSupportedWirelessMode); + } else if ((btSupportedWirelessMode & WIRELESS_MODE_B)) { btWirelessMode = WIRELESS_MODE_B; + } else { + DMESGW("ActSetWirelessMode8185(): No valid wireless mode supported, btSupportedWirelessMode(%x)!!!\n", + btSupportedWirelessMode); + btWirelessMode = WIRELESS_MODE_B; } } - /* 2. Swtich band: RF or BB specific actions, + /* + * 2. Swtich band: RF or BB specific actions, * for example, refresh tables in omc8255, or change initial gain if necessary. * Nothing to do for Zebra to switch band. - * Update current wireless mode if we swtich to specified band successfully. */ + * Update current wireless mode if we switch to specified band successfully. + */ ieee->mode = (WIRELESS_MODE)btWirelessMode; - /* 3. Change related setting. */ - if( ieee->mode == WIRELESS_MODE_A ) { + /* 3. Change related setting. */ + if( ieee->mode == WIRELESS_MODE_A ) { DMESG("WIRELESS_MODE_A\n"); - } else if( ieee->mode == WIRELESS_MODE_B ) { - DMESG("WIRELESS_MODE_B\n"); - } else if( ieee->mode == WIRELESS_MODE_G ) { - DMESG("WIRELESS_MODE_G\n"); + } else if( ieee->mode == WIRELESS_MODE_B ) { + DMESG("WIRELESS_MODE_B\n"); + } else if( ieee->mode == WIRELESS_MODE_G ) { + DMESG("WIRELESS_MODE_G\n"); } ActUpdateChannelAccessSetting( dev, ieee->mode, &priv->ChannelAccessSetting); } @@ -1245,22 +1147,16 @@ void rtl8185b_irq_enable(struct net_device *dev) priv->irq_enabled = 1; write_nic_dword(dev, IMR, priv->IntrMask); } -/* by amy for power save */ -void -DrvIFIndicateDisassociation( - struct net_device *dev, - u16 reason - ) + +void DrvIFIndicateDisassociation(struct net_device *dev, u16 reason) { /* nothing is needed after disassociation request. */ - } -void -MgntDisconnectIBSS( - struct net_device *dev -) +} + +void MgntDisconnectIBSS(struct net_device *dev) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - u8 i; + u8 i; DrvIFIndicateDisassociation(dev, unspec_reason); @@ -1271,166 +1167,143 @@ MgntDisconnectIBSS( priv->ieee80211->state = IEEE80211_NOLINK; /* - Stop Beacon. - - Vista add a Adhoc profile, HW radio off until OID_DOT11_RESET_REQUEST - Driver would set MSR=NO_LINK, then HW Radio ON, MgntQueue Stuck. - Because Bcn DMA isn't complete, mgnt queue would stuck until Bcn packet send. - - Disable Beacon Queue Own bit, suggested by jong */ + * Stop Beacon. + * + * Vista add a Adhoc profile, HW radio off until OID_DOT11_RESET_REQUEST + * Driver would set MSR=NO_LINK, then HW Radio ON, MgntQueue Stuck. + * Because Bcn DMA isn't complete, mgnt queue would stuck until Bcn packet send. + * + * Disable Beacon Queue Own bit, suggested by jong + */ ieee80211_stop_send_beacons(priv->ieee80211); priv->ieee80211->link_change(dev); notify_wx_assoc_event(priv->ieee80211); } -void -MlmeDisassociateRequest( - struct net_device *dev, - u8 *asSta, - u8 asRsn - ) + +void MlmeDisassociateRequest(struct net_device *dev, u8 *asSta, u8 asRsn) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); u8 i; SendDisassociation(priv->ieee80211, asSta, asRsn); - if (memcmp(priv->ieee80211->current_network.bssid, asSta, 6) == 0) { - /*ShuChen TODO: change media status. */ - /*ShuChen TODO: What to do when disassociate. */ + if (memcmp(priv->ieee80211->current_network.bssid, asSta, 6) == 0) { + /* ShuChen TODO: change media status. */ + /* ShuChen TODO: What to do when disassociate. */ DrvIFIndicateDisassociation(dev, unspec_reason); - - for (i = 0; i < 6; i++) priv->ieee80211->current_network.bssid[i] = 0x22; ieee80211_disassociate(priv->ieee80211); } - } -void -MgntDisconnectAP( - struct net_device *dev, - u8 asRsn -) +void MgntDisconnectAP(struct net_device *dev, u8 asRsn) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); /* - Commented out by rcnjko, 2005.01.27: - I move SecClearAllKeys() to MgntActSet_802_11_DISASSOCIATE(). - - 2004/09/15, kcwu, the key should be cleared, or the new handshaking will not success - - In WPA WPA2 need to Clear all key ... because new key will set after new handshaking. - 2004.10.11, by rcnjko. */ + * Commented out by rcnjko, 2005.01.27: + * I move SecClearAllKeys() to MgntActSet_802_11_DISASSOCIATE(). + * + * 2004/09/15, kcwu, the key should be cleared, or the new handshaking will not success + * + * In WPA WPA2 need to Clear all key ... because new key will set after new handshaking. + * 2004.10.11, by rcnjko. + */ MlmeDisassociateRequest(dev, priv->ieee80211->current_network.bssid, asRsn); priv->ieee80211->state = IEEE80211_NOLINK; } -bool -MgntDisconnect( - struct net_device *dev, - u8 asRsn -) + +bool MgntDisconnect(struct net_device *dev, u8 asRsn) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); /* - Schedule an workitem to wake up for ps mode, 070109, by rcnjko. - */ + * Schedule an workitem to wake up for ps mode, 070109, by rcnjko. + */ if (IS_DOT11D_ENABLE(priv->ieee80211)) Dot11d_Reset(priv->ieee80211); - /* In adhoc mode, update beacon frame. */ + /* In adhoc mode, update beacon frame. */ if (priv->ieee80211->state == IEEE80211_LINKED) { if (priv->ieee80211->iw_mode == IW_MODE_ADHOC) MgntDisconnectIBSS(dev); - if (priv->ieee80211->iw_mode == IW_MODE_INFRA) { - /* We clear key here instead of MgntDisconnectAP() because that - MgntActSet_802_11_DISASSOCIATE() is an interface called by OS, - e.g. OID_802_11_DISASSOCIATE in Windows while as MgntDisconnectAP() is - used to handle disassociation related things to AP, e.g. send Disassoc - frame to AP. 2005.01.27, by rcnjko. */ + if (priv->ieee80211->iw_mode == IW_MODE_INFRA) { + /* + * We clear key here instead of MgntDisconnectAP() because that + * MgntActSet_802_11_DISASSOCIATE() is an interface called by OS, + * e.g. OID_802_11_DISASSOCIATE in Windows while as MgntDisconnectAP() is + * used to handle disassociation related things to AP, e.g. send Disassoc + * frame to AP. 2005.01.27, by rcnjko. + */ MgntDisconnectAP(dev, asRsn); } - /* Inidicate Disconnect, 2005.02.23, by rcnjko. */ + /* Indicate Disconnect, 2005.02.23, by rcnjko. */ } return true; } /* - Description: - Chang RF Power State. - Note that, only MgntActSet_RF_State() is allowed to set HW_VAR_RF_STATE. - - Assumption: - PASSIVE LEVEL. -*/ -bool -SetRFPowerState( - struct net_device *dev, - RT_RF_POWER_STATE eRFPowerState - ) + * Description: + * Chang RF Power State. + * Note that, only MgntActSet_RF_State() is allowed to set HW_VAR_RF_STATE. + * + * Assumption: + * PASSIVE LEVEL. + */ +bool SetRFPowerState(struct net_device *dev, RT_RF_POWER_STATE eRFPowerState) { - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - bool bResult = false; + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + bool bResult = false; if (eRFPowerState == priv->eRFPowerState) return bResult; - bResult = SetZebraRFPowerState8185(dev, eRFPowerState); + bResult = SetZebraRFPowerState8185(dev, eRFPowerState); return bResult; } -void -HalEnableRx8185Dummy( - struct net_device *dev - ) + +void HalEnableRx8185Dummy(struct net_device *dev) { } -void -HalDisableRx8185Dummy( - struct net_device *dev - ) + +void HalDisableRx8185Dummy(struct net_device *dev) { } -bool -MgntActSet_RF_State( - struct net_device *dev, - RT_RF_POWER_STATE StateToSet, - u32 ChangeSource - ) +bool MgntActSet_RF_State(struct net_device *dev, RT_RF_POWER_STATE StateToSet, u32 ChangeSource) { - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - bool bActionAllowed = false; - bool bConnectBySSID = false; - RT_RF_POWER_STATE rtState; - u16 RFWaitCounter = 0; + struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); + bool bActionAllowed = false; + bool bConnectBySSID = false; + RT_RF_POWER_STATE rtState; + u16 RFWaitCounter = 0; unsigned long flag; /* - Prevent the race condition of RF state change. By Bruce, 2007-11-28. - Only one thread can change the RF state at one time, and others should wait to be executed. - */ - while (true) { + * Prevent the race condition of RF state change. By Bruce, 2007-11-28. + * Only one thread can change the RF state at one time, and others should wait to be executed. + */ + while (true) { spin_lock_irqsave(&priv->rf_ps_lock, flag); - if (priv->RFChangeInProgress) { + if (priv->RFChangeInProgress) { spin_unlock_irqrestore(&priv->rf_ps_lock, flag); /* Set RF after the previous action is done. */ - while (priv->RFChangeInProgress) { + while (priv->RFChangeInProgress) { RFWaitCounter++; udelay(1000); /* 1 ms */ - /* Wait too long, return FALSE to avoid to be stuck here. */ - if (RFWaitCounter > 1000) { /* 1sec */ + /* Wait too long, return FALSE to avoid to be stuck here. */ + if (RFWaitCounter > 1000) { /* 1sec */ printk("MgntActSet_RF_State(): Wait too long to set RF\n"); - /* TODO: Reset RF state? */ + /* TODO: Reset RF state? */ return false; } } - } else { + } else { priv->RFChangeInProgress = true; spin_unlock_irqrestore(&priv->rf_ps_lock, flag); break; @@ -1438,12 +1311,12 @@ MgntActSet_RF_State( } rtState = priv->eRFPowerState; - switch (StateToSet) { + switch (StateToSet) { case eRfOn: /* - Turn On RF no matter the IPS setting because we need to update the RF state to Ndis under Vista, or - the Windows does not allow the driver to perform site survey any more. By Bruce, 2007-10-02. - */ + * Turn On RF no matter the IPS setting because we need to update the RF state to Ndis under Vista, or + * the Windows does not allow the driver to perform site survey any more. By Bruce, 2007-10-02. + */ priv->RfOffReason &= (~ChangeSource); if (!priv->RfOffReason) { @@ -1453,25 +1326,24 @@ MgntActSet_RF_State( if (rtState == eRfOff && ChangeSource >= RF_CHANGE_BY_HW && !priv->bInHctTest) bConnectBySSID = true; - } else - ; + } else + ; break; case eRfOff: - /* 070125, rcnjko: we always keep connected in AP mode. */ - - if (priv->RfOffReason > RF_CHANGE_BY_IPS) { - /* - 060808, Annie: - Disconnect to current BSS when radio off. Asked by QuanTa. - - Calling MgntDisconnect() instead of MgntActSet_802_11_DISASSOCIATE(), - because we do NOT need to set ssid to dummy ones. - */ - MgntDisconnect(dev, disas_lv_ss); - - /* Clear content of bssDesc[] and bssDesc4Query[] to avoid reporting old bss to UI. */ - } + /* 070125, rcnjko: we always keep connected in AP mode. */ + + if (priv->RfOffReason > RF_CHANGE_BY_IPS) { + /* + * 060808, Annie: + * Disconnect to current BSS when radio off. Asked by QuanTa. + * + * Calling MgntDisconnect() instead of MgntActSet_802_11_DISASSOCIATE(), + * because we do NOT need to set ssid to dummy ones. + */ + MgntDisconnect(dev, disas_lv_ss); + /* Clear content of bssDesc[] and bssDesc4Query[] to avoid reporting old bss to UI. */ + } priv->RfOffReason |= ChangeSource; bActionAllowed = true; @@ -1484,14 +1356,14 @@ MgntActSet_RF_State( break; } - if (bActionAllowed) { - /* Config HW to the specified mode. */ + if (bActionAllowed) { + /* Config HW to the specified mode. */ SetRFPowerState(dev, StateToSet); /* Turn on RF. */ - if (StateToSet == eRfOn) { + if (StateToSet == eRfOn) { HalEnableRx8185Dummy(dev); - if (bConnectBySSID) { + if (bConnectBySSID) { /* by amy not supported */ } } @@ -1507,69 +1379,61 @@ MgntActSet_RF_State( spin_unlock_irqrestore(&priv->rf_ps_lock, flag); return bActionAllowed; } -void -InactivePowerSave( - struct net_device *dev - ) + +void InactivePowerSave(struct net_device *dev) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); /* - This flag "bSwRfProcessing", indicates the status of IPS procedure, should be set if the IPS workitem - is really scheduled. - The old code, sets this flag before scheduling the IPS workitem and however, at the same time the - previous IPS workitem did not end yet, fails to schedule the current workitem. Thus, bSwRfProcessing - blocks the IPS procedure of switching RF. - */ + * This flag "bSwRfProcessing", indicates the status of IPS procedure, should be set if the IPS workitem + * is really scheduled. + * The old code, sets this flag before scheduling the IPS workitem and however, at the same time the + * previous IPS workitem did not end yet, fails to schedule the current workitem. Thus, bSwRfProcessing + * blocks the IPS procedure of switching RF. + */ priv->bSwRfProcessing = true; MgntActSet_RF_State(dev, priv->eInactivePowerState, RF_CHANGE_BY_IPS); /* - To solve CAM values miss in RF OFF, rewrite CAM values after RF ON. By Bruce, 2007-09-20. - */ + * To solve CAM values miss in RF OFF, rewrite CAM values after RF ON. By Bruce, 2007-09-20. + */ priv->bSwRfProcessing = false; } /* - Description: - Enter the inactive power save mode. RF will be off -*/ -void -IPSEnter( - struct net_device *dev - ) + * Description: + * Enter the inactive power save mode. RF will be off + */ +void IPSEnter(struct net_device *dev) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); RT_RF_POWER_STATE rtState; - if (priv->bInactivePs) { + if (priv->bInactivePs) { rtState = priv->eRFPowerState; /* - Do not enter IPS in the following conditions: - (1) RF is already OFF or Sleep - (2) bSwRfProcessing (indicates the IPS is still under going) - (3) Connectted (only disconnected can trigger IPS) - (4) IBSS (send Beacon) - (5) AP mode (send Beacon) - */ + * Do not enter IPS in the following conditions: + * (1) RF is already OFF or Sleep + * (2) bSwRfProcessing (indicates the IPS is still under going) + * (3) Connected (only disconnected can trigger IPS) + * (4) IBSS (send Beacon) + * (5) AP mode (send Beacon) + */ if (rtState == eRfOn && !priv->bSwRfProcessing - && (priv->ieee80211->state != IEEE80211_LINKED)) { + && (priv->ieee80211->state != IEEE80211_LINKED)) { priv->eInactivePowerState = eRfOff; InactivePowerSave(dev); } } } -void -IPSLeave( - struct net_device *dev - ) +void IPSLeave(struct net_device *dev) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); RT_RF_POWER_STATE rtState; - if (priv->bInactivePs) { + if (priv->bInactivePs) { rtState = priv->eRFPowerState; - if ((rtState == eRfOff || rtState == eRfSleep) && (!priv->bSwRfProcessing) && priv->RfOffReason <= RF_CHANGE_BY_IPS) { + if ((rtState == eRfOff || rtState == eRfSleep) && (!priv->bSwRfProcessing) && priv->RfOffReason <= RF_CHANGE_BY_IPS) { priv->eInactivePowerState = eRfOn; InactivePowerSave(dev); } @@ -1582,8 +1446,8 @@ void rtl8185b_adapter_start(struct net_device *dev) struct ieee80211_device *ieee = priv->ieee80211; u8 SupportedWirelessMode; - u8 InitWirelessMode; - u8 bInvalidWirelessMode = 0; + u8 InitWirelessMode; + u8 bInvalidWirelessMode = 0; u8 tmpu8; u8 btCR9346; u8 TmpU1b; @@ -1598,89 +1462,89 @@ void rtl8185b_adapter_start(struct net_device *dev) HwConfigureRTL8185(dev); write_nic_dword(dev, MAC0, ((u32 *)dev->dev_addr)[0]); write_nic_word(dev, MAC4, ((u32 *)dev->dev_addr)[1] & 0xffff); - write_nic_byte(dev, MSR, read_nic_byte(dev, MSR) & 0xf3); /* default network type to 'No Link' */ + write_nic_byte(dev, MSR, read_nic_byte(dev, MSR) & 0xf3); /* default network type to 'No Link' */ write_nic_word(dev, BcnItv, 100); write_nic_word(dev, AtimWnd, 2); PlatformIOWrite2Byte(dev, FEMR, 0xFFFF); write_nic_byte(dev, WPA_CONFIG, 0); MacConfig_85BASIC(dev); - /* Override the RFSW_CTRL (MAC offset 0x272-0x273), 2006.06.07, by rcnjko. */ - /* BT_DEMO_BOARD type */ + /* Override the RFSW_CTRL (MAC offset 0x272-0x273), 2006.06.07, by rcnjko. */ + /* BT_DEMO_BOARD type */ PlatformIOWrite2Byte(dev, RFSW_CTRL, 0x569a); /* - ----------------------------------------------------------------------------- - Set up PHY related. - ----------------------------------------------------------------------------- - */ - /* Enable Config3.PARAM_En to revise AnaaParm. */ - write_nic_byte(dev, CR9346, 0xc0); /* enable config register write */ + *--------------------------------------------------------------------------- + * Set up PHY related. + *--------------------------------------------------------------------------- + */ + /* Enable Config3.PARAM_En to revise AnaaParm. */ + write_nic_byte(dev, CR9346, 0xc0); /* enable config register write */ tmpu8 = read_nic_byte(dev, CONFIG3); write_nic_byte(dev, CONFIG3, (tmpu8 | CONFIG3_PARM_En)); - /* Turn on Analog power. */ - /* Asked for by William, otherwise, MAC 3-wire can't work, 2006.06.27, by rcnjko. */ + /* Turn on Analog power. */ + /* Asked for by William, otherwise, MAC 3-wire can't work, 2006.06.27, by rcnjko. */ write_nic_dword(dev, ANAPARAM2, ANAPARM2_ASIC_ON); write_nic_dword(dev, ANAPARAM, ANAPARM_ASIC_ON); write_nic_word(dev, ANAPARAM3, 0x0010); write_nic_byte(dev, CONFIG3, tmpu8); write_nic_byte(dev, CR9346, 0x00); - /* enable EEM0 and EEM1 in 9346CR */ + /* enable EEM0 and EEM1 in 9346CR */ btCR9346 = read_nic_byte(dev, CR9346); write_nic_byte(dev, CR9346, (btCR9346 | 0xC0)); - /* B cut use LED1 to control HW RF on/off */ + /* B cut use LED1 to control HW RF on/off */ TmpU1b = read_nic_byte(dev, CONFIG5); TmpU1b = TmpU1b & ~BIT3; write_nic_byte(dev, CONFIG5, TmpU1b); - /* disable EEM0 and EEM1 in 9346CR */ + /* disable EEM0 and EEM1 in 9346CR */ btCR9346 &= ~(0xC0); write_nic_byte(dev, CR9346, btCR9346); - /* Enable Led (suggested by Jong) */ - /* B-cut RF Radio on/off 5e[3]=0 */ + /* Enable Led (suggested by Jong) */ + /* B-cut RF Radio on/off 5e[3]=0 */ btPSR = read_nic_byte(dev, PSR); write_nic_byte(dev, PSR, (btPSR | BIT3)); - /* setup initial timing for RFE. */ + /* setup initial timing for RFE. */ write_nic_word(dev, RFPinsOutput, 0x0480); SetOutputEnableOfRfPins(dev); write_nic_word(dev, RFPinsSelect, 0x2488); - /* PHY config. */ + /* PHY config. */ PhyConfig8185(dev); /* - We assume RegWirelessMode has already been initialized before, - however, we has to validate the wireless mode here and provide a - reasonable initialized value if necessary. 2005.01.13, by rcnjko. - */ + * We assume RegWirelessMode has already been initialized before, + * however, we has to validate the wireless mode here and provide a + * reasonable initialized value if necessary. 2005.01.13, by rcnjko. + */ SupportedWirelessMode = GetSupportedWirelessMode8185(dev); if ((ieee->mode != WIRELESS_MODE_B) && (ieee->mode != WIRELESS_MODE_G) && (ieee->mode != WIRELESS_MODE_A) && - (ieee->mode != WIRELESS_MODE_AUTO)) { - /* It should be one of B, G, A, or AUTO. */ + (ieee->mode != WIRELESS_MODE_AUTO)) { + /* It should be one of B, G, A, or AUTO. */ bInvalidWirelessMode = 1; - } else { - /* One of B, G, A, or AUTO. */ - /* Check if the wireless mode is supported by RF. */ + } else { + /* One of B, G, A, or AUTO. */ + /* Check if the wireless mode is supported by RF. */ if ((ieee->mode != WIRELESS_MODE_AUTO) && - (ieee->mode & SupportedWirelessMode) == 0) { + (ieee->mode & SupportedWirelessMode) == 0) { bInvalidWirelessMode = 1; } } - if (bInvalidWirelessMode || ieee->mode == WIRELESS_MODE_AUTO) { - /* Auto or other invalid value. */ - /* Assigne a wireless mode to initialize. */ - if ((SupportedWirelessMode & WIRELESS_MODE_A)) { + if (bInvalidWirelessMode || ieee->mode == WIRELESS_MODE_AUTO) { + /* Auto or other invalid value. */ + /* Assigne a wireless mode to initialize. */ + if ((SupportedWirelessMode & WIRELESS_MODE_A)) { InitWirelessMode = WIRELESS_MODE_A; - } else if ((SupportedWirelessMode & WIRELESS_MODE_G)) { + } else if ((SupportedWirelessMode & WIRELESS_MODE_G)) { InitWirelessMode = WIRELESS_MODE_G; - } else if ((SupportedWirelessMode & WIRELESS_MODE_B)) { + } else if ((SupportedWirelessMode & WIRELESS_MODE_B)) { InitWirelessMode = WIRELESS_MODE_B; - } else { + } else { DMESGW("InitializeAdapter8185(): No valid wireless mode supported, SupportedWirelessMode(%x)!!!\n", SupportedWirelessMode); InitWirelessMode = WIRELESS_MODE_B; @@ -1690,24 +1554,21 @@ void rtl8185b_adapter_start(struct net_device *dev) if (bInvalidWirelessMode) ieee->mode = (WIRELESS_MODE)InitWirelessMode; - } else { - /* One of B, G, A. */ + } else { + /* One of B, G, A. */ InitWirelessMode = ieee->mode; } -/* by amy for power save */ priv->eRFPowerState = eRfOff; priv->RfOffReason = 0; { MgntActSet_RF_State(dev, eRfOn, 0); } /* - If inactive power mode is enabled, disable rf while in disconnected state. - */ + * If inactive power mode is enabled, disable rf while in disconnected state. + */ if (priv->bInactivePs) MgntActSet_RF_State(dev , eRfOff, RF_CHANGE_BY_IPS); -/* by amy for power save */ - ActSetWirelessMode8185(dev, (u8)(InitWirelessMode)); /* ----------------------------------------------------------------------------- */ @@ -1715,7 +1576,7 @@ void rtl8185b_adapter_start(struct net_device *dev) rtl8185b_irq_enable(dev); netif_start_queue(dev); - } +} void rtl8185b_rx_enable(struct net_device *dev) { @@ -1728,7 +1589,7 @@ void rtl8185b_rx_enable(struct net_device *dev) DMESG("NIC in promisc mode"); if (priv->ieee80211->iw_mode == IW_MODE_MONITOR || \ - dev->flags & IFF_PROMISC) { + dev->flags & IFF_PROMISC) { priv->ReceiveConfig = priv->ReceiveConfig & (~RCR_APM); priv->ReceiveConfig = priv->ReceiveConfig | RCR_AAP; } diff --git a/trunk/drivers/staging/rtl8192e/Kconfig b/trunk/drivers/staging/rtl8192e/Kconfig index f87e21101857..4602a47cdb4a 100644 --- a/trunk/drivers/staging/rtl8192e/Kconfig +++ b/trunk/drivers/staging/rtl8192e/Kconfig @@ -14,6 +14,7 @@ if RTLLIB config RTLLIB_CRYPTO_CCMP tristate "Support for rtllib CCMP crypto" depends on RTLLIB + select CRYPTO_AES default y ---help--- CCMP crypto driver for rtllib. @@ -23,6 +24,8 @@ config RTLLIB_CRYPTO_CCMP config RTLLIB_CRYPTO_TKIP tristate "Support for rtllib TKIP crypto" depends on RTLLIB + select CRYPTO_ARC4 + select CRYPTO_MICHAEL_MIC default y ---help--- TKIP crypto driver for rtllib. @@ -31,6 +34,7 @@ config RTLLIB_CRYPTO_TKIP config RTLLIB_CRYPTO_WEP tristate "Support for rtllib WEP crypto" + select CRYPTO_ARC4 depends on RTLLIB default y ---help--- diff --git a/trunk/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c b/trunk/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c index 58d044ea5524..ea91744f7ccf 100644 --- a/trunk/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c +++ b/trunk/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c @@ -342,7 +342,6 @@ static void cmpk_handle_tx_rate_history(struct net_device *dev, u8 *pmsg) u32 cmpk_message_handle_rx(struct net_device *dev, struct rtllib_rx_stats *pstats) { - struct r8192_priv *priv = rtllib_priv(dev); int total_length; u8 cmd_length, exe_cnt = 0; u8 element_id; @@ -409,8 +408,6 @@ u32 cmpk_message_handle_rx(struct net_device *dev, return 1; } - priv->stats.rxcmdpkt[element_id]++; - total_length -= cmd_length; pcmd_buff += cmd_length; } diff --git a/trunk/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c b/trunk/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c index 37719859bdae..b526fa428679 100644 --- a/trunk/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c +++ b/trunk/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c @@ -216,7 +216,7 @@ static bool firmware_check_ready(struct net_device *dev, break; default: rt_status = false; - RT_TRACE(COMP_FIRMWARE, "Unknown firware status"); + RT_TRACE(COMP_FIRMWARE, "Unknown firmware status"); break; } diff --git a/trunk/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/trunk/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index 3e705efaaf22..9676c591c859 100644 --- a/trunk/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/trunk/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -689,7 +689,7 @@ void rtl8192_phy_setTxPower(struct net_device *dev, u8 channel) case RF_8258: break; default: - RT_TRACE(COMP_ERR, "unknown rf chip in funtion %s()\n", + RT_TRACE(COMP_ERR, "unknown rf chip in function %s()\n", __func__); break; } diff --git a/trunk/drivers/staging/rtl8192e/rtl8192e/r819xE_phyreg.h b/trunk/drivers/staging/rtl8192e/rtl8192e/r819xE_phyreg.h index d5de279f6644..970298b07af7 100644 --- a/trunk/drivers/staging/rtl8192e/rtl8192e/r819xE_phyreg.h +++ b/trunk/drivers/staging/rtl8192e/rtl8192e/r819xE_phyreg.h @@ -306,7 +306,7 @@ #define bRFStart 0x0000f000 #define bBBStart 0x000000f0 #define bBBCCKStart 0x0000000f -/* Reg)x814 */ +/* Reg x814 */ #define bPAEnd 0xf #define bTREnd 0x0f000000 #define bRFEnd 0x000f0000 @@ -844,7 +844,7 @@ #define bRTL8258_RxLPFBW 0xc00 #define bRTL8258_RSSILPFBW 0xc0 -/* byte endable for sb_write */ +/* byte enable for sb_write */ #define bByte0 0x1 #define bByte1 0x2 #define bByte2 0x4 diff --git a/trunk/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/trunk/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 71adb6b3344d..4f602b227b50 100644 --- a/trunk/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/trunk/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -1025,7 +1025,7 @@ static int rtl8192_sta_down(struct net_device *dev, bool shutdownrf) break; } RT_TRACE(COMP_DBG, "===>%s():RF is in progress, need to wait " - "until rf chang is done.\n", __func__); + "until rf change is done.\n", __func__); mdelay(1); RFInProgressTimeOut++; spin_lock_irqsave(&priv->rf_ps_lock, flags); @@ -1211,7 +1211,7 @@ static void rtl8192_init_priv_variable(struct net_device *dev) priv->AcmControl = 0; priv->pFirmware = vzalloc(sizeof(struct rt_firmware)); if (!priv->pFirmware) - printk(KERN_ERR "rtl8193e: Unable to allocate space " + printk(KERN_ERR "rtl8192e: Unable to allocate space " "for firmware\n"); skb_queue_head_init(&priv->rx_queue); @@ -2024,10 +2024,10 @@ short rtl8192_tx(struct net_device *dev, struct sk_buff *skb) stype = WLAN_FC_GET_STYPE(fc); pda_addr = header->addr1; - if (is_multicast_ether_addr(pda_addr)) - multi_addr = true; - else if (is_broadcast_ether_addr(pda_addr)) + if (is_broadcast_ether_addr(pda_addr)) broad_addr = true; + else if (is_multicast_ether_addr(pda_addr)) + multi_addr = true; else uni_addr = true; @@ -2358,8 +2358,7 @@ static void rtl8192_rx_normal(struct net_device *dev) stats.RxBufShift); skb_trim(skb, skb->len - 4/*sCrcLng*/); rtllib_hdr = (struct rtllib_hdr_1addr *)skb->data; - if (!is_broadcast_ether_addr(rtllib_hdr->addr1) && - !is_multicast_ether_addr(rtllib_hdr->addr1)) { + if (!is_multicast_ether_addr(rtllib_hdr->addr1)) { /* unicast packet */ unicast_packet = true; } diff --git a/trunk/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/trunk/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index 2a2519cc284d..320d5fc026b4 100644 --- a/trunk/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/trunk/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -353,7 +353,6 @@ struct rt_stats { unsigned long rxrdu; unsigned long rxok; unsigned long rxframgment; - unsigned long rxcmdpkt[8]; unsigned long rxurberr; unsigned long rxstaterr; unsigned long rxdatacrcerr; @@ -944,7 +943,7 @@ struct r8192_priv { bool bfsync_processing; u32 rate_record; u32 rateCountDiffRecord; - u32 ContiuneDiffCount; + u32 ContinueDiffCount; bool bswitch_fsync; u8 framesync; u32 framesyncC34; diff --git a/trunk/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/trunk/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index f026b7171f62..481b1e4d4913 100644 --- a/trunk/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/trunk/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -493,7 +493,7 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev) if (priv->bResetInProgress) { RT_TRACE(COMP_POWER_TRACKING, - "we are in slient reset progress, so return\n"); + "we are in silent reset progress, so return\n"); write_nic_byte(dev, Pw_Track_Flag, 0); write_nic_byte(dev, FW_Busy_Flag, 0); return; @@ -2615,22 +2615,22 @@ void dm_fsync_timer_callback(unsigned long data) rate_count_diff; if (DiffNum >= priv->rtllib->fsync_seconddiff_ratethreshold) - priv->ContiuneDiffCount++; + priv->ContinueDiffCount++; else - priv->ContiuneDiffCount = 0; + priv->ContinueDiffCount = 0; - if (priv->ContiuneDiffCount >= 2) { + if (priv->ContinueDiffCount >= 2) { bSwitchFromCountDiff = true; - priv->ContiuneDiffCount = 0; + priv->ContinueDiffCount = 0; } } else { - priv->ContiuneDiffCount = 0; + priv->ContinueDiffCount = 0; } if (rate_count_diff <= priv->rtllib->fsync_firstdiff_ratethreshold) { bSwitchFromCountDiff = true; - priv->ContiuneDiffCount = 0; + priv->ContinueDiffCount = 0; } priv->rate_record = rate_count; priv->rateCountDiffRecord = rate_count_diff; @@ -2677,10 +2677,10 @@ void dm_fsync_timer_callback(unsigned long data) write_nic_byte(dev, 0xC36, 0x5c); write_nic_byte(dev, 0xC3e, 0x96); } - priv->ContiuneDiffCount = 0; + priv->ContinueDiffCount = 0; write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd); } - RT_TRACE(COMP_HALDM, "ContiuneDiffCount %d\n", priv->ContiuneDiffCount); + RT_TRACE(COMP_HALDM, "ContinueDiffCount %d\n", priv->ContinueDiffCount); RT_TRACE(COMP_HALDM, "rateRecord %d rateCount %d, rateCountdiff %d " "bSwitchFsync %d\n", priv->rate_record, rate_count, rate_count_diff, priv->bswitch_fsync); @@ -2723,7 +2723,7 @@ static void dm_EndSWFsync(struct net_device *dev) write_nic_byte(dev, 0xC3e, 0x96); } - priv->ContiuneDiffCount = 0; + priv->ContinueDiffCount = 0; write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd); } @@ -2735,7 +2735,7 @@ static void dm_StartSWFsync(struct net_device *dev) RT_TRACE(COMP_HALDM, "%s\n", __func__); priv->rate_record = 0; - priv->ContiuneDiffCount = 0; + priv->ContinueDiffCount = 0; priv->rateCountDiffRecord = 0; priv->bswitch_fsync = false; diff --git a/trunk/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/trunk/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c index 4e93669210af..778d7baf8e08 100644 --- a/trunk/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c +++ b/trunk/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c @@ -1322,9 +1322,9 @@ static struct iw_statistics *r8192_get_wireless_stats(struct net_device *dev) struct iw_handler_def r8192_wx_handlers_def = { .standard = r8192_wx_handlers, - .num_standard = sizeof(r8192_wx_handlers) / sizeof(iw_handler), + .num_standard = ARRAY_SIZE(r8192_wx_handlers), .private = r8192_private_handler, - .num_private = sizeof(r8192_private_handler) / sizeof(iw_handler), + .num_private = ARRAY_SIZE(r8192_private_handler), .num_private_args = sizeof(r8192_private_args) / sizeof(struct iw_priv_args), .get_wireless_stats = r8192_get_wireless_stats, diff --git a/trunk/drivers/staging/rtl8192e/rtl819x_TSProc.c b/trunk/drivers/staging/rtl8192e/rtl819x_TSProc.c index 711a096be7a7..658e875232aa 100644 --- a/trunk/drivers/staging/rtl8192e/rtl819x_TSProc.c +++ b/trunk/drivers/staging/rtl8192e/rtl819x_TSProc.c @@ -310,7 +310,7 @@ bool GetTs(struct rtllib_device *ieee, struct ts_common_info **ppTS, u8 *Addr, u8 TID, enum tr_select TxRxSelect, bool bAddNewTs) { u8 UP = 0; - if (is_broadcast_ether_addr(Addr) || is_multicast_ether_addr(Addr)) { + if (is_multicast_ether_addr(Addr)) { RTLLIB_DEBUG(RTLLIB_DL_ERR, "ERR! get TS for Broadcast or " "Multicast\n"); return false; diff --git a/trunk/drivers/staging/rtl8192e/rtllib.h b/trunk/drivers/staging/rtl8192e/rtllib.h index e26aec86a5c8..d7460ae3a765 100644 --- a/trunk/drivers/staging/rtl8192e/rtllib.h +++ b/trunk/drivers/staging/rtl8192e/rtllib.h @@ -169,7 +169,7 @@ struct cb_desc { u8 nStuckCount; - /* Tx Firmware Relaged flags (10-11)*/ + /* Tx Firmware Related flags (10-11)*/ u8 bCTSEnable:1; u8 bRTSEnable:1; u8 bUseShortGI:1; @@ -1690,7 +1690,7 @@ enum rtllib_state { /* the association procedure is sending AUTH request*/ RTLLIB_ASSOCIATING_AUTHENTICATING, - /* the association procedure has successfully authentcated + /* the association procedure has successfully authenticated * and is sending association request */ RTLLIB_ASSOCIATING_AUTHENTICATED, @@ -2409,7 +2409,7 @@ struct rtllib_device { /* used instead of hard_start_xmit (not softmac_hard_start_xmit) * if the IEEE_SOFTMAC_TX_QUEUE feature is used to TX data - * frames. I the option IEEE_SOFTMAC_SINGLE_QUEUE is also set + * frames. If the option IEEE_SOFTMAC_SINGLE_QUEUE is also set * then also management frames are sent via this callback. * This function can't sleep. */ @@ -2422,12 +2422,12 @@ struct rtllib_device { */ void (*data_hard_stop)(struct net_device *dev); - /* OK this is complementar to data_poll_hard_stop */ + /* OK this is complementing to data_poll_hard_stop */ void (*data_hard_resume)(struct net_device *dev); /* ask to the driver to retune the radio . * This function can sleep. the driver should ensure - * the radio has been swithced before return. + * the radio has been switched before return. */ void (*set_chan)(struct net_device *dev, short ch); @@ -2438,7 +2438,7 @@ struct rtllib_device { * The syncro version is similar to the start_scan but * does not return until all channels has been scanned. * this is called in user context and should sleep, - * it is called in a work_queue when swithcing to ad-hoc mode + * it is called in a work_queue when switching to ad-hoc mode * or in behalf of iwlist scan when the card is associated * and root user ask for a scan. * the fucntion stop_scan should stop both the syncro and @@ -2481,7 +2481,7 @@ struct rtllib_device { struct rtllib_network *network); - /* check whether Tx hw resouce available */ + /* check whether Tx hw resource available */ short (*check_nic_enough_desc)(struct net_device *dev, int queue_index); short (*get_nic_desc_num)(struct net_device *dev, int queue_index); void (*SetBWModeHandler)(struct net_device *dev, @@ -2543,10 +2543,10 @@ struct rtllib_device { /* Generate probe requests */ #define IEEE_SOFTMAC_PROBERQ (1<<4) -/* Generate respones to probe requests */ +/* Generate response to probe requests */ #define IEEE_SOFTMAC_PROBERS (1<<5) -/* The ieee802.11 stack will manages the netif queue +/* The ieee802.11 stack will manage the netif queue * wake/stop for the driver, taking care of 802.11 * fragmentation. See softmac.c for details. */ #define IEEE_SOFTMAC_TX_QUEUE (1<<7) diff --git a/trunk/drivers/staging/rtl8192e/rtllib_rx.c b/trunk/drivers/staging/rtl8192e/rtllib_rx.c index 13979b5ea32a..8b8a5c661a26 100644 --- a/trunk/drivers/staging/rtl8192e/rtllib_rx.c +++ b/trunk/drivers/staging/rtl8192e/rtllib_rx.c @@ -496,7 +496,7 @@ void rtllib_indicate_packets(struct rtllib_device *ieee, struct rtllib_rxb **prx memcpy(skb_push(sub_skb, ETH_ALEN), prxb->dst, ETH_ALEN); } - /* Indicat the packets to upper layer */ + /* Indicate the packets to upper layer */ if (sub_skb) { stats->rx_packets++; stats->rx_bytes += sub_skb->len; @@ -1000,7 +1000,7 @@ static int rtllib_rx_data_filter(struct rtllib_device *ieee, u16 fc, return -1; /* {broad,multi}cast packets to our BSS go through */ - if (is_multicast_ether_addr(dst) || is_broadcast_ether_addr(dst)) { + if (is_multicast_ether_addr(dst)) { if (memcmp(bssid, ieee->current_network.bssid, ETH_ALEN)) return -1; } @@ -1233,7 +1233,7 @@ static void rtllib_rx_indicate_pkt_legacy(struct rtllib_device *ieee, if (is_multicast_ether_addr(dst)) ieee->stats.multicast++; - /* Indicat the packets to upper layer */ + /* Indicate the packets to upper layer */ memset(sub_skb->cb, 0, sizeof(sub_skb->cb)); sub_skb->protocol = eth_type_trans(sub_skb, dev); sub_skb->dev = dev; @@ -1269,7 +1269,7 @@ static int rtllib_rx_InfraAdhoc(struct rtllib_device *ieee, struct sk_buff *skb, sc = le16_to_cpu(hdr->seq_ctl); /*Filter pkt not to me*/ - multicast = is_multicast_ether_addr(hdr->addr1)|is_broadcast_ether_addr(hdr->addr1); + multicast = is_multicast_ether_addr(hdr->addr1); unicast = !multicast; if (unicast && (compare_ether_addr(dev->dev_addr, hdr->addr1) != 0)) { if (ieee->bNetPromiscuousMode) @@ -1350,7 +1350,7 @@ static int rtllib_rx_InfraAdhoc(struct rtllib_device *ieee, struct sk_buff *skb, /* Get TS for Rx Reorder */ hdr = (struct rtllib_hdr_4addr *) skb->data; if (ieee->current_network.qos_data.active && IsQoSDataFrame(skb->data) - && !is_multicast_ether_addr(hdr->addr1) && !is_broadcast_ether_addr(hdr->addr1) + && !is_multicast_ether_addr(hdr->addr1) && (!bToOtherSTA)) { TID = Frame_QoSTID(skb->data); SeqNum = WLAN_GET_SEQ_SEQ(sc); diff --git a/trunk/drivers/staging/rtl8192e/rtllib_softmac.c b/trunk/drivers/staging/rtl8192e/rtllib_softmac.c index c5a15dba1bf5..a21b4d91a596 100644 --- a/trunk/drivers/staging/rtl8192e/rtllib_softmac.c +++ b/trunk/drivers/staging/rtl8192e/rtllib_softmac.c @@ -31,7 +31,7 @@ short rtllib_is_shortslot(const struct rtllib_network *net) return net->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME; } -/* returns the total length needed for pleacing the RATE MFIE +/* returns the total length needed for placing the RATE MFIE * tag and the EXTENDED RATE MFIE tag if needed. * It encludes two bytes per tag for the tag itself and its len */ @@ -49,7 +49,7 @@ static unsigned int rtllib_MFIE_rate_len(struct rtllib_device *ieee) return rate_len; } -/* pleace the MFIE rate, tag to the memory (double) poined. +/* place the MFIE rate, tag to the memory (double) pointed. * Then it updates the pointer so that * it points after the new MFIE tag added. */ @@ -557,7 +557,7 @@ void rtllib_softmac_scan_syncro(struct rtllib_device *ieee, u8 is_mesh) * new network events, despite for updating the net list, * but we are temporarly 'unlinked' as the driver shall * not filter RX frames and the channel is changing. - * So the only situation in witch are interested is to check + * So the only situation in which are interested is to check * if the state become LINKED because of the #1 situation */ @@ -1681,7 +1681,7 @@ inline void rtllib_softmac_new_net(struct rtllib_device *ieee, /* if the user set the AP check if match. * if the network does not broadcast essid we check the - * user supplyed ANY essid + * user supplied ANY essid * if the network does broadcast and the user does not set * essid it is OK * if the network does broadcast and the user did set essid @@ -2444,16 +2444,16 @@ inline int rtllib_rx_frame_softmac(struct rtllib_device *ieee, /* following are for a simplier TX queue management. * Instead of using netif_[stop/wake]_queue the driver - * will uses these two function (plus a reset one), that - * will internally uses the kernel netif_* and takes + * will use these two functions (plus a reset one), that + * will internally use the kernel netif_* and takes * care of the ieee802.11 fragmentation. * So the driver receives a fragment per time and might - * call the stop function when it want without take care - * to have enought room to TX an entire packet. - * This might be useful if each fragment need it's own + * call the stop function when it wants to not + * have enough room to TX an entire packet. + * This might be useful if each fragment needs it's own * descriptor, thus just keep a total free memory > than - * the max fragmentation treshold is not enought.. If the - * ieee802.11 stack passed a TXB struct then you needed + * the max fragmentation threshold is not enough.. If the + * ieee802.11 stack passed a TXB struct then you need * to keep N free descriptors where * N = MAX_PACKET_SIZE / MIN_FRAG_TRESHOLD * In this way you need just one and the 802.11 stack @@ -2696,15 +2696,15 @@ static void rtllib_start_ibss_wq(void *data) rtllib_softmac_check_all_nets(ieee); - /* if not then the state is not linked. Maybe the user swithced to + /* if not then the state is not linked. Maybe the user switched to * ad-hoc mode just after being in monitor mode, or just after * being very few time in managed mode (so the card have had no * time to scan all the chans..) or we have just run up the iface * after setting ad-hoc mode. So we have to give another try.. * Here, in ibss mode, should be safe to do this without extra care - * (in bss mode we had to make sure no-one tryed to associate when + * (in bss mode we had to make sure no-one tried to associate when * we had just checked the ieee->state and we was going to start the - * scan) beacause in ibss mode the rtllib_new_net function, when + * scan) because in ibss mode the rtllib_new_net function, when * finds a good net, just set the ieee->state to RTLLIB_LINKED, * so, at worst, we waste a bit of time to initiate an unneeded syncro * scan, that will stop at the first round because it sees the state @@ -2819,7 +2819,7 @@ void rtllib_start_bss(struct rtllib_device *ieee) /* ensure no-one start an associating process (thus setting * the ieee->state to rtllib_ASSOCIATING) while we - * have just cheked it and we are going to enable scan. + * have just checked it and we are going to enable scan. * The rtllib_new_net function is always called with * lock held (from both rtllib_softmac_check_all_nets and * the rx path), so we cannot be in the middle of such function @@ -2872,7 +2872,7 @@ static void rtllib_associate_retry_wq(void *data) /* until we do not set the state to RTLLIB_NOLINK * there are no possibility to have someone else trying - * to start an association procdure (we get here with + * to start an association procedure (we get here with * ieee->state = RTLLIB_ASSOCIATING). * When we set the state to RTLLIB_NOLINK it is possible * that the RX path run an attempt to associate, but @@ -3679,8 +3679,7 @@ void rtllib_MlmeDisassociateRequest(struct rtllib_device *rtllib, u8 *asSta, RemovePeerTS(rtllib, asSta); - - if (memcpy(rtllib->current_network.bssid, asSta, 6) == NULL) { + if (memcmp(rtllib->current_network.bssid, asSta, 6) == 0) { rtllib->state = RTLLIB_NOLINK; for (i = 0; i < 6; i++) diff --git a/trunk/drivers/staging/rtl8192e/rtllib_softmac_wx.c b/trunk/drivers/staging/rtl8192e/rtllib_softmac_wx.c index 1523bc7a2105..1bb6b52e0f24 100644 --- a/trunk/drivers/staging/rtl8192e/rtllib_softmac_wx.c +++ b/trunk/drivers/staging/rtl8192e/rtllib_softmac_wx.c @@ -479,7 +479,7 @@ int rtllib_wx_set_essid(struct rtllib_device *ieee, /* this is just to be sure that the GET wx callback - * has consisten infos. not needed otherwise + * has consistent infos. not needed otherwise */ spin_lock_irqsave(&ieee->lock, flags); @@ -575,7 +575,7 @@ int rtllib_wx_set_power(struct rtllib_device *ieee, if ((!ieee->sta_wake_up) || (!ieee->enter_sleep_state) || (!ieee->ps_is_queue_empty)) { - RTLLIB_DEBUG(RTLLIB_DL_ERR, "%s(): PS mode is tryied to be use " + RTLLIB_DEBUG(RTLLIB_DL_ERR, "%s(): PS mode is tried to be use " "but driver missed a callback\n\n", __func__); return -1; } diff --git a/trunk/drivers/staging/rtl8192e/rtllib_tx.c b/trunk/drivers/staging/rtl8192e/rtllib_tx.c index f451bfc27a86..42900ee4825b 100644 --- a/trunk/drivers/staging/rtl8192e/rtllib_tx.c +++ b/trunk/drivers/staging/rtl8192e/rtllib_tx.c @@ -59,7 +59,7 @@ 802.11 Data Frame -802.11 frame_contorl for data frames - 2 bytes +802.11 frame_control for data frames - 2 bytes ,-----------------------------------------------------------------------------------------. bits | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c | d | e | |----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|------| @@ -296,8 +296,7 @@ static void rtllib_tx_query_agg_cap(struct rtllib_device *ieee, return; if (!IsQoSDataFrame(skb->data)) return; - if (is_multicast_ether_addr(hdr->addr1) || - is_broadcast_ether_addr(hdr->addr1)) + if (is_multicast_ether_addr(hdr->addr1)) return; if (tcb_desc->bdhcp || ieee->CntAfterLink < 2) @@ -515,7 +514,7 @@ u16 rtllib_query_seqnum(struct rtllib_device *ieee, struct sk_buff *skb, { u16 seqnum = 0; - if (is_multicast_ether_addr(dst) || is_broadcast_ether_addr(dst)) + if (is_multicast_ether_addr(dst)) return 0; if (IsQoSDataFrame(skb->data)) { struct tx_ts_record *pTS = NULL; @@ -576,7 +575,7 @@ int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev) spin_lock_irqsave(&ieee->lock, flags); - /* If there is no driver handler to take the TXB, dont' bother + /* If there is no driver handler to take the TXB, don't bother * creating it... */ if ((!ieee->hard_start_xmit && !(ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE)) || @@ -698,8 +697,7 @@ int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev) ETH_ALEN); } - bIsMulticast = is_broadcast_ether_addr(header.addr1) || - is_multicast_ether_addr(header.addr1); + bIsMulticast = is_multicast_ether_addr(header.addr1); header.frame_ctl = cpu_to_le16(fc); @@ -738,7 +736,7 @@ int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev) (CFG_RTLLIB_COMPUTE_FCS | CFG_RTLLIB_RESERVE_FCS)) bytes_per_frag -= RTLLIB_FCS_LEN; - /* Each fragment may need to have room for encryptiong + /* Each fragment may need to have room for encrypting * pre/postfix */ if (encrypt) { bytes_per_frag -= crypt->ops->extra_mpdu_prefix_len + diff --git a/trunk/drivers/staging/rtl8192e/rtllib_wx.c b/trunk/drivers/staging/rtl8192e/rtllib_wx.c index c27ff7edbaf2..c7e8d4d8ec2b 100644 --- a/trunk/drivers/staging/rtl8192e/rtllib_wx.c +++ b/trunk/drivers/staging/rtl8192e/rtllib_wx.c @@ -88,7 +88,7 @@ static inline char *rtl819x_translate_scan(struct rtllib_device *ieee, } /* Add the protocol name */ iwe.cmd = SIOCGIWNAME; - for (i = 0; i < (sizeof(rtllib_modes)/sizeof(rtllib_modes[0])); i++) { + for (i = 0; i < ARRAY_SIZE(rtllib_modes); i++) { if (network->mode&(1<priv); sec.flags |= (1 << key); /* This ensures a key will be activated if no key is - * explicitely set */ + * explicitly set */ if (key == sec.active_key) sec.flags |= SEC_ACTIVE_KEY; ieee->crypt_info.tx_keyidx = key; diff --git a/trunk/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c b/trunk/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c index e3d47bcf4cab..82d4bf6a86a5 100644 --- a/trunk/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c +++ b/trunk/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c @@ -161,7 +161,7 @@ struct net_device *alloc_ieee80211(int sizeof_priv) if (ieee->pHTInfo == NULL) { IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc memory for HTInfo\n"); - return NULL; + goto failed; } HTUpdateDefaultSetting(ieee); HTInitializeHTInfo(ieee); //may move to other place. diff --git a/trunk/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c b/trunk/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c index be2a28cf8edd..e3cf7a45b900 100644 --- a/trunk/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c +++ b/trunk/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c @@ -671,7 +671,7 @@ void RxReorderIndicatePacket( struct ieee80211_device *ieee, index = 1; } else { /* Current packet is going to be inserted into pending list.*/ - //IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): We RX no ordered packed, insert to orderd list\n",__FUNCTION__); + //IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): We RX no ordered packed, insert to ordered list\n",__FUNCTION__); if(!list_empty(&ieee->RxReorder_Unused_List)) { pReorderEntry = (PRX_REORDER_ENTRY)list_entry(ieee->RxReorder_Unused_List.next,RX_REORDER_ENTRY,List); list_del_init(&pReorderEntry->List); @@ -1285,7 +1285,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, */ //added by amy for reorder if(ieee->current_network.qos_data.active && IsQoSDataFrame(skb->data) - && !is_multicast_ether_addr(hdr->addr1) && !is_broadcast_ether_addr(hdr->addr1)) + && !is_multicast_ether_addr(hdr->addr1)) { TID = Frame_QoSTID(skb->data); SeqNum = WLAN_GET_SEQ_SEQ(sc); diff --git a/trunk/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/trunk/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c index c2ab5fa15465..f6ff8cff313a 100644 --- a/trunk/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c +++ b/trunk/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c @@ -2062,7 +2062,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, } }else{ ieee->softmac_stats.rx_auth_rs_err++; - IEEE80211_DEBUG_MGMT("Authentication respose status code 0x%x",errcode); + IEEE80211_DEBUG_MGMT("Authentication response status code 0x%x",errcode); ieee80211_associate_abort(ieee); } diff --git a/trunk/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c b/trunk/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c index 59c45a510efb..3f5ceeb88b6c 100644 --- a/trunk/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c +++ b/trunk/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c @@ -314,7 +314,7 @@ void ieee80211_tx_query_agg_cap(struct ieee80211_device* ieee, struct sk_buff* s if (!IsQoSDataFrame(skb->data)) return; - if (is_multicast_ether_addr(hdr->addr1) || is_broadcast_ether_addr(hdr->addr1)) + if (is_multicast_ether_addr(hdr->addr1)) return; //check packet and mode later #ifdef TO_DO_LIST @@ -575,7 +575,7 @@ void ieee80211_txrate_selectmode(struct ieee80211_device* ieee, cb_desc* tcb_des void ieee80211_query_seqnum(struct ieee80211_device*ieee, struct sk_buff* skb, u8* dst) { - if (is_multicast_ether_addr(dst) || is_broadcast_ether_addr(dst)) + if (is_multicast_ether_addr(dst)) return; if (IsQoSDataFrame(skb->data)) //we deal qos data only { @@ -693,8 +693,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) /* Determine fragmentation size based on destination (multicast * and broadcast are not fragmented) */ - if (is_multicast_ether_addr(header.addr1) || - is_broadcast_ether_addr(header.addr1)) { + if (is_multicast_ether_addr(header.addr1)) { frag_size = MAX_FRAG_THRESHOLD; qos_ctl |= QOS_CTL_NOTCONTAIN_ACK; } diff --git a/trunk/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c b/trunk/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c index 957ce4ef48b5..06a9824bbff1 100644 --- a/trunk/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c +++ b/trunk/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c @@ -350,7 +350,7 @@ bool GetTs( // We do not build any TS for Broadcast or Multicast stream. // So reject these kinds of search here. // - if(is_broadcast_ether_addr(Addr) || is_multicast_ether_addr(Addr)) + if (is_multicast_ether_addr(Addr)) { IEEE80211_DEBUG(IEEE80211_DL_ERR, "get TS for Broadcast or Multicast\n"); return false; diff --git a/trunk/drivers/staging/rtl8192u/r8180_93cx6.c b/trunk/drivers/staging/rtl8192u/r8180_93cx6.c index 8878cfeb0fbb..3c515b7bc542 100644 --- a/trunk/drivers/staging/rtl8192u/r8180_93cx6.c +++ b/trunk/drivers/staging/rtl8192u/r8180_93cx6.c @@ -14,7 +14,7 @@ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. - We want to tanks the Authors of those projects and the Ndiswrapper + We want to thank the Authors of those projects and the Ndiswrapper project Authors. */ diff --git a/trunk/drivers/staging/rtl8192u/r8180_93cx6.h b/trunk/drivers/staging/rtl8192u/r8180_93cx6.h index fb3ac9766ea5..5cea51e1142e 100644 --- a/trunk/drivers/staging/rtl8192u/r8180_93cx6.h +++ b/trunk/drivers/staging/rtl8192u/r8180_93cx6.h @@ -7,7 +7,7 @@ Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver - We want to tanks the Authors of such projects and the Ndiswrapper project Authors. + We want to thank the Authors of such projects and the Ndiswrapper project Authors. */ /*This files contains card eeprom (93c46 or 93c56) programming routines*/ diff --git a/trunk/drivers/staging/rtl8192u/r8192U.h b/trunk/drivers/staging/rtl8192u/r8192U.h index 9b81f26d40fe..57e3383cc935 100644 --- a/trunk/drivers/staging/rtl8192u/r8192U.h +++ b/trunk/drivers/staging/rtl8192u/r8192U.h @@ -11,7 +11,7 @@ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver - We want to tanks the Authors of those projects and the Ndiswrapper + We want to thank the Authors of those projects and the Ndiswrapper project Authors. */ @@ -98,7 +98,7 @@ do { if(rt_global_debug_component & component) \ #define COMP_INIT BIT2 // during driver initialization / halt / reset. -#define COMP_RECV BIT3 // Reveive part data path. +#define COMP_RECV BIT3 // Receive data path. #define COMP_SEND BIT4 // Send part path. #define COMP_IO BIT5 // I/O Related. Added by Annie, 2006-03-02. #define COMP_POWER BIT6 // 802.11 Power Save mode or System/Device Power state related. @@ -322,7 +322,7 @@ typedef struct _tx_fwinfo_819x_usb { u8 TxSubCarrier:2; // This is used for legacy OFDM rate only. u8 STBC:2; u8 AllowAggregation:1; - u8 RtsHT:1; //Interpre RtsRate field as high throughput data rate + u8 RtsHT:1; //Interpret RtsRate field as high throughput data rate u8 RtsShort:1; //Short PLCP for CCK, or short GI for 11n MCS u8 RtsBandwidth:1; // This is used for HT MCS rate only. u8 RtsSubcarrier:2; // This is used for legacy OFDM rate only. @@ -610,7 +610,6 @@ typedef struct Stats // unsigned long rxnopointer; unsigned long rxok; unsigned long rxframgment; - unsigned long rxcmdpkt[4]; //08/05/08 amy rx cmd element txfeedback/bcn report/cfg set/query unsigned long rxurberr; unsigned long rxstaterr; unsigned long received_rate_histogram[4][32]; //0: Total, 1:OK, 2:CRC, 3:ICV, 2007 07 03 cosa @@ -1117,7 +1116,7 @@ typedef struct r8192_priv bool bfsync_processing; // 500ms Fsync timer is active or not u32 rate_record; u32 rateCountDiffRecord; - u32 ContiuneDiffCount; + u32 ContinueDiffCount; bool bswitch_fsync; u8 framesync; diff --git a/trunk/drivers/staging/rtl8192u/r8192U_core.c b/trunk/drivers/staging/rtl8192u/r8192U_core.c index 9c00865f302a..5981d6658320 100644 --- a/trunk/drivers/staging/rtl8192u/r8192U_core.c +++ b/trunk/drivers/staging/rtl8192u/r8192U_core.c @@ -203,7 +203,7 @@ static void rtl819x_set_channel_map(u8 channel_plan, struct r8192_priv* priv) { Dot11d_Init(ieee); ieee->bGlobalDomain = false; - //acturally 8225 & 8256 rf chip only support B,G,24N mode + //actually 8225 & 8256 rf chips only support B,G,24N mode if ((priv->rf_chip == RF_8225) || (priv->rf_chip == RF_8256)) { min_chan = 1; @@ -1103,7 +1103,7 @@ inline u16 rtl8192_rate2rate(short rate) } -/* The protype of rx_isr has changed since one verion of Linux Kernel */ +/* The prototype of rx_isr has changed since one version of Linux Kernel */ static void rtl8192_rx_isr(struct urb *urb) { struct sk_buff *skb = (struct sk_buff *) urb->context; @@ -1476,7 +1476,7 @@ static void rtl8192_tx_isr(struct urb *tx_urb) if(tcb_desc->queue_index != TXCMD_QUEUE) { if(tx_urb->status == 0) { dev->trans_start = jiffies; - // As act as station mode, destion shall be unicast address. + // Act as station mode, destination shall be unicast address. //priv->ieee80211->stats.tx_bytes+=(skb->len - priv->ieee80211->tx_headroom); //priv->ieee80211->stats.tx_packets++; priv->stats.txoktotal++; @@ -1522,13 +1522,13 @@ static void rtl8192_tx_isr(struct urb *tx_urb) else if ((skb_queue_len(&priv->ieee80211->skb_drv_aggQ[queue_index])!= 0)&&\ (!(priv->ieee80211->queue_stop))) { // Tx Driver Aggregation process - /* The driver will aggregation the packets according to the following stets + /* The driver will aggregation the packets according to the following stats * 1. check whether there's tx irq available, for it's a completion return * function, it should contain enough tx irq; - * 2. check pakcet type; + * 2. check packet type; * 3. initialize sendlist, check whether the to-be send packet no greater than 1 - * 4. aggregation the packets, and fill firmware info and tx desc to it, etc. - * 5. check whehter the packet could be sent, otherwise just insert to wait head + * 4. aggregates the packets, and fill firmware info and tx desc into it, etc. + * 5. check whether the packet could be sent, otherwise just insert into wait head * */ skb = skb_dequeue(&priv->ieee80211->skb_drv_aggQ[queue_index]); if(!check_nic_enough_desc(dev, queue_index)) { @@ -2447,7 +2447,7 @@ static int rtl8192_qos_handle_probe_response(struct r8192_priv *priv, return 0; } -/* handle manage frame frame beacon and probe response */ +/* handle and manage frame from beacon and probe response */ static int rtl8192_handle_beacon(struct net_device * dev, struct ieee80211_beacon * beacon, struct ieee80211_network * network) @@ -2625,7 +2625,7 @@ bool GetHalfNmodeSupportByAPs819xUsb(struct net_device* dev) void rtl8192_refresh_supportrate(struct r8192_priv* priv) { struct ieee80211_device* ieee = priv->ieee80211; - //we donot consider set support rate for ABG mode, only HT MCS rate is set here. + //we do not consider set support rate for ABG mode, only HT MCS rate is set here. if (ieee->mode == WIRELESS_MODE_N_24G || ieee->mode == WIRELESS_MODE_N_5G) { memcpy(ieee->Regdot11HTOperationalRateSet, ieee->RegHTSuppRateSet, 16); @@ -2780,10 +2780,10 @@ static void rtl8192_init_priv_variable(struct net_device* dev) priv->TransmitConfig = // TCR_DurProcMode | //for RTL8185B, duration setting by HW //? TCR_DISReqQsize | - (TCR_MXDMA_2048<ShortRetryLimit<LongRetryLimit<bInHctTest) pHalData->ReceiveConfig = pHalData->CSMethod | @@ -3437,7 +3437,7 @@ if(Adapter->ResetProgress == RESET_TYPE_NORESET) { // User disable RF via registry. RT_TRACE((COMP_INIT|COMP_RF), DBG_LOUD, ("InitializeAdapter819xUsb(): Turn off RF for RegRfOff ----------\n")); MgntActSet_RF_State(Adapter, eRfOff, RF_CHANGE_BY_SW); - // Those action will be discard in MgntActSet_RF_State because off the same state + // Those actions will be discard in MgntActSet_RF_State because of the same state for(eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) PHY_SetRFReg(Adapter, (RF90_RADIO_PATH_E)eRFPath, 0x4, 0xC00, 0x0); } @@ -3458,7 +3458,7 @@ if(Adapter->ResetProgress == RESET_TYPE_NORESET) if(pHalData->eRFPowerState == eRfOff) { MgntActSet_RF_State(Adapter, eRfOff, pMgntInfo->RfOffReason); - // Those action will be discard in MgntActSet_RF_State because off the same state + // Those actions will be discard in MgntActSet_RF_State because of the same state for(eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) PHY_SetRFReg(Adapter, (RF90_RADIO_PATH_E)eRFPath, 0x4, 0xC00, 0x0); } @@ -3586,7 +3586,7 @@ TxCheckStuck(struct net_device *dev) //unsigned long flags; // - // Decide Stuch threshold according to current power save mode + // Decide such threshold according to current power save mode // // RT_TRACE(COMP_RESET, " ==> TxCheckStuck()\n"); @@ -3745,7 +3745,7 @@ rtl819x_ifcheck_resetornot(struct net_device *dev) // Driver should not check RX stuck in IBSS mode because it is required to // set Check BSSID in order to send beacon, however, if check BSSID is - // set, STA cannot hear any packet a all. Emily, 2008.04.12 + // set, STA cannot hear any packet at all. Emily, 2008.04.12 RxResetType = RxCheckStuck(dev); } if(TxResetType==RESET_TYPE_NORMAL || RxResetType==RESET_TYPE_NORMAL) @@ -3962,7 +3962,7 @@ rtl819x_ifsilentreset(struct net_device *dev) up(&priv->wx_sem); RT_TRACE(COMP_RESET,"%s():<==========down process is finished\n",__FUNCTION__); //rtl8192_irq_disable(dev); - RT_TRACE(COMP_RESET,"%s():===========>start to up the driver\n",__FUNCTION__); + RT_TRACE(COMP_RESET,"%s():===========>start up the driver\n",__FUNCTION__); reset_status = _rtl8192_up(dev); RT_TRACE(COMP_RESET,"%s():<===========up process is finished\n",__FUNCTION__); @@ -4155,7 +4155,7 @@ extern void rtl819x_watchdog_wqcallback(struct work_struct *work) void watch_dog_timer_callback(unsigned long data) { struct r8192_priv *priv = ieee80211_priv((struct net_device *) data); - //printk("===============>watch_dog timer\n"); + //printk("===============>watch_dog timer\n"); queue_delayed_work(priv->priv_wq,&priv->watch_dog_wq, 0); mod_timer(&priv->watch_dog_timer, jiffies + MSECS(IEEE80211_WATCH_DOG_TIME)); } @@ -4170,7 +4170,7 @@ int _rtl8192_up(struct net_device *dev) init_status = rtl8192_adapter_start(dev); if(!init_status) { - RT_TRACE(COMP_ERR,"ERR!!! %s(): initialization is failed!\n", __FUNCTION__); + RT_TRACE(COMP_ERR,"ERR!!! %s(): initialization failed!\n", __FUNCTION__); priv->up=priv->ieee80211->ieee_up = 0; return -EAGAIN; } @@ -4256,7 +4256,7 @@ int rtl8192_down(struct net_device *dev) skb_queue_purge(&priv->ieee80211->skb_drv_aggQ [i]); } - //as cancel_delayed_work will del work->timer, so if work is not definedas struct delayed_work, it will corrupt + //as cancel_delayed_work will del work->timer, so if work is not defined as struct delayed_work, it will corrupt // flush_scheduled_work(); rtl8192_cancel_deferred_work(priv); deinit_hal_dm(dev); @@ -4516,7 +4516,7 @@ u8 HwRateToMRate90(bool bIsHT, u8 rate) /** * Function: UpdateRxPktTimeStamp - * Overview: Recored down the TSF time stamp when receiving a packet + * Overview: Record the TSF time stamp when receiving a packet * * Input: * PADAPTER Adapter @@ -4556,10 +4556,10 @@ long rtl819x_translate_todbm(u8 signal_strength_index )// 0-100 index. } -/* 2008/01/22 MH We can not delcare RSSI/EVM total value of sliding window to +/* 2008/01/22 MH We can not declare RSSI/EVM total value of sliding window to be a local static. Otherwise, it may increase when we return from S3/S4. The - value will be kept in memory or disk. We must delcare the value in adapter - and it will be reinitialized when return from S3/S4. */ + value will be kept in memory or disk. Declare the value in the adaptor + and it will be reinitialized when returned from S3/S4. */ void rtl8192_process_phyinfo(struct r8192_priv * priv,u8* buffer, struct ieee80211_rx_stats * pprevious_stats, struct ieee80211_rx_stats * pcurrent_stats) { bool bcheck = false; @@ -5091,8 +5091,8 @@ static void rtl8192_query_rxphystatus( tmp_rxevm = pofdm_buf->rxevm_X[i]; rx_evmX = (char)(tmp_rxevm); - // Do not use shift operation like "rx_evmX >>= 1" because the compilor of free build environment - // fill most significant bit to "zero" when doing shifting operation which may change a negative + // Do not use shift operation like "rx_evmX >>= 1" because the compiler of free build environment + // will set the most significant bit to "zero" when doing shifting operation which may change a negative // value to positive one, then the dbm value (which is supposed to be negative) is not correct anymore. rx_evmX /= 2; //dbm @@ -5171,7 +5171,7 @@ void TranslateRxSignalStuff819xUsb(struct sk_buff *skb, type = WLAN_FC_GET_TYPE(fc); praddr = hdr->addr1; - /* Check if the received packet is acceptabe. */ + /* Check if the received packet is acceptable. */ bpacket_match_bssid = ((IEEE80211_FTYPE_CTL != type) && (eqMacAddr(priv->ieee80211->current_network.bssid, (fc & IEEE80211_FCTL_TODS)? hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS )? hdr->addr2 : hdr->addr3)) && (!pstats->bHwError) && (!pstats->bCRC)&& (!pstats->bICV)); @@ -5211,7 +5211,7 @@ void TranslateRxSignalStuff819xUsb(struct sk_buff *skb, /** * Function: UpdateReceivedRateHistogramStatistics -* Overview: Recored down the received data rate +* Overview: Record the received data rate * * Input: * struct net_device *dev @@ -5401,7 +5401,7 @@ void query_rxdesc_status(struct sk_buff *skb, struct ieee80211_rx_stats *stats, } #ifdef USB_RX_AGGREGATION_SUPPORT - /* for the rx aggregated sub frame, the redundant space truelly contained in the packet */ + /* for the rx aggregated sub frame, the redundant space truly contained in the packet */ if(bIsRxAggrSubframe) { skb_pull(skb, 8); } @@ -5480,7 +5480,7 @@ void rtl8192_rx_nomal(struct sk_buff* skb) PacketShiftBytes = GetRxPacketShiftBytes819xUsb(&stats, false); } #endif - /* Process the MPDU recevied */ + /* Process the MPDU received */ skb_trim(skb, skb->len - 4/*sCrcLng*/); rx_pkt_len = skb->len; @@ -5538,7 +5538,7 @@ void rtl8192_rx_nomal(struct sk_buff* skb) if(PacketLength > agg_skb->len) { break; } - /* Process the MPDU recevied */ + /* Process the MPDU received */ skb = dev_alloc_skb(PacketLength); memcpy(skb_put(skb,PacketLength),agg_skb->data, PacketLength); skb_trim(skb, skb->len - 4/*sCrcLng*/); diff --git a/trunk/drivers/staging/rtl8192u/r8192U_dm.c b/trunk/drivers/staging/rtl8192u/r8192U_dm.c index 2dde9fa5c21e..cd8dc85e9c0f 100644 --- a/trunk/drivers/staging/rtl8192u/r8192U_dm.c +++ b/trunk/drivers/staging/rtl8192u/r8192U_dm.c @@ -38,7 +38,7 @@ static u32 edca_setting_UL[HT_IOT_PEER_MAX] = /*------------------------Define global variable-----------------------------*/ // Debug variable ? dig_t dm_digtable; -// Store current shoftware write register content for MAC PHY. +// Store current software write register content for MAC PHY. u8 dm_shadow[16][256] = {{0}}; // For Dynamic Rx Path Selection by Signal Strength DRxPathSel DM_RxPathSelTable; @@ -119,7 +119,7 @@ static void dm_pd_th(struct net_device *dev); static void dm_cs_ratio(struct net_device *dev); static void dm_init_ctstoself(struct net_device *dev); -// DM --> EDCA turboe mode control +// DM --> EDCA turbo mode control static void dm_check_edca_turbo(struct net_device *dev); // DM --> HW RF control @@ -348,7 +348,7 @@ extern void init_rate_adaptive(struct net_device * dev) * * Revised History: * When Who Remark - * 05/26/08 amy Create version 0 proting from windows code. + * 05/26/08 amy Create version 0 porting from windows code. * *---------------------------------------------------------------------------*/ static void dm_check_rate_adaptive(struct net_device * dev) @@ -543,7 +543,7 @@ static u32 OFDMSwingTable[OFDM_Table_Length] = { 0x5a400169, // 3, +3db 0x50800142, // 4, +2db 0x47c0011f, // 5, +1db - 0x40000100, // 6, +0db ===> default, upper for higher temprature, lower for low temprature + 0x40000100, // 6, +0db ===> default, upper for higher temperature, lower for low temperature 0x390000e4, // 7, -1db 0x32c000cb, // 8, -2db 0x2d4000b5, // 9, -3db @@ -678,7 +678,7 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device * dev) { write_nic_byte(dev, 0x1ba, 0); viviflag = FALSE; - RT_TRACE(COMP_POWER_TRACKING, "we filted this data\n"); + RT_TRACE(COMP_POWER_TRACKING, "we filtered the data\n"); for(k = 0;k < 5; k++) tmp_report[k] = 0; break; @@ -864,14 +864,14 @@ static void dm_TXPowerTrackingCallback_ThermalMeter(struct net_device * dev) RT_TRACE(COMP_POWER_TRACKING, "Readback ThermalMeterA = %d \n", tmpRegA); if(tmpRegA < 3 || tmpRegA > 13) return; - if(tmpRegA >= 12) // if over 12, TP will be bad when high temprature + if(tmpRegA >= 12) // if over 12, TP will be bad when high temperature tmpRegA = 12; RT_TRACE(COMP_POWER_TRACKING, "Valid ThermalMeterA = %d \n", tmpRegA); priv->ThermalMeter[0] = ThermalMeterVal; //We use fixed value by Bryant's suggestion priv->ThermalMeter[1] = ThermalMeterVal; //We use fixed value by Bryant's suggestion - //Get current RF-A temprature index - if(priv->ThermalMeter[0] >= (u8)tmpRegA) //lower temprature + //Get current RF-A temperature index + if(priv->ThermalMeter[0] >= (u8)tmpRegA) //lower temperature { tmpOFDMindex = tmpCCK20Mindex = 6+(priv->ThermalMeter[0]-(u8)tmpRegA); tmpCCK40Mindex = tmpCCK20Mindex - 6; @@ -885,7 +885,7 @@ static void dm_TXPowerTrackingCallback_ThermalMeter(struct net_device * dev) else { tmpval = ((u8)tmpRegA - priv->ThermalMeter[0]); - if(tmpval >= 6) // higher temprature + if(tmpval >= 6) // higher temperature tmpOFDMindex = tmpCCK20Mindex = 0; // max to +6dB else tmpOFDMindex = tmpCCK20Mindex = 6 - tmpval; @@ -1457,9 +1457,9 @@ static void dm_InitializeTXPowerTracking_ThermalMeter(struct net_device *dev) { struct r8192_priv *priv = ieee80211_priv(dev); - // Tx Power tracking by Theremal Meter require Firmware R/W 3-wire. This mechanism + // Tx Power tracking by Thermal Meter requires Firmware R/W 3-wire. This mechanism // can be enabled only when Firmware R/W 3-wire is enabled. Otherwise, frequent r/w - // 3-wire by driver cause RF goes into wrong state. + // 3-wire by driver causes RF to go into a wrong state. if(priv->ieee80211->FwRWRF) priv->btxpower_tracking = TRUE; else @@ -1520,7 +1520,7 @@ static void dm_CheckTXPowerTracking_ThermalMeter(struct net_device *dev) if(!TM_Trigger) { - //Attention!! You have to wirte all 12bits data to RF, or it may cause RF to crash + //Attention!! You have to write all 12bits of data to RF, or it may cause RF to crash //actually write reg0x02 bit1=0, then bit1=1. //DbgPrint("Trigger ThermalMeter, write RF reg0x2 = 0x4d to 0x4f\n"); rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4d); @@ -1744,7 +1744,7 @@ extern void dm_restore_dynamic_mechanism_state(struct net_device *dev) write_nic_dword(dev, RATR0, ratr_value); write_nic_byte(dev, UFWP, 1); } - //Resore TX Power Tracking Index + //Restore TX Power Tracking Index if(priv->btxpower_trackingInit && priv->btxpower_tracking){ dm_txpower_reset_recovery(dev); } @@ -2031,7 +2031,7 @@ static void dm_dig_init(struct net_device *dev) dm_digtable.dbg_mode = DM_DBG_OFF; //off=by real rssi value, on=by DM_DigTable.Rssi_val for new dig dm_digtable.dig_algorithm_switch = 0; - /* 2007/10/04 MH Define init gain threshol. */ + /* 2007/10/04 MH Define init gain threshold. */ dm_digtable.dig_state = DM_STA_DIG_MAX; dm_digtable.dig_highpwr_state = DM_STA_DIG_MAX; dm_digtable.initialgain_lowerbound_state = false; @@ -2097,7 +2097,7 @@ static void dm_ctrl_initgain_byrssi_by_driverrssi( return; //DbgPrint("Dig by Sw Rssi \n"); - if(dm_digtable.dig_algorithm_switch) // if swithed algorithm, we have to disable FW Dig. + if(dm_digtable.dig_algorithm_switch) // if switched algorithm, we have to disable FW Dig. fw_dig = 0; if(fw_dig <= 3) // execute several times to make sure the FW Dig is disabled {// FW DIG Off @@ -2160,8 +2160,8 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm( /*DbgPrint("DIG Check\n\r RSSI=%d LOW=%d HIGH=%d STATE=%d", pHalData->UndecoratedSmoothedPWDB, DM_DigTable.RssiLowThresh, DM_DigTable.RssiHighThresh, DM_DigTable.Dig_State);*/ - /* 1. When RSSI decrease, We have to judge if it is smaller than a treshold - and then execute below step. */ + /* 1. When RSSI decrease, We have to judge if it is smaller than a threshold + and then execute the step below. */ if ((priv->undecorated_smoothed_pwdb <= dm_digtable.rssi_low_thresh)) { /* 2008/02/05 MH When we execute silent reset, the DIG PHY parameters @@ -2220,8 +2220,8 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm( } - /* 2. When RSSI increase, We have to judge if it is larger than a treshold - and then execute below step. */ + /* 2. When RSSI increase, We have to judge if it is larger than a threshold + and then execute the step below. */ if ((priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_thresh) ) { u8 reset_flag = 0; @@ -2329,7 +2329,7 @@ static void dm_ctrl_initgain_byrssi_highpwr( } /* 3. When RSSI >75% or <70%, it is a high power issue. We have to judge if - it is larger than a treshold and then execute below step. */ + it is larger than a threshold and then execute the step below. */ // 2008/02/05 MH SD3-Jerry Modify PD_TH for high power issue. if (priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_power_highthresh) { @@ -2841,8 +2841,8 @@ static void dm_check_rfctrl_gpio(struct net_device * dev) { //struct r8192_priv *priv = ieee80211_priv(dev); - // Walk around for DTM test, we will not enable HW - radio on/off because r/w - // page 1 register before Lextra bus is enabled cause system fails when resuming + // Work around for DTM test, we will not enable HW - radio on/off because r/w + // page 1 register before extra bus is enabled causing system failures when resuming // from S4. 20080218, Emily // Stop to execute workitem to prevent S3/S4 bug. @@ -3377,30 +3377,30 @@ extern void dm_fsync_timer_callback(unsigned long data) { u32 DiffNum = priv->rateCountDiffRecord - rate_count_diff; - // Contiune count + // Continue count if(DiffNum >= priv->ieee80211->fsync_seconddiff_ratethreshold) - priv->ContiuneDiffCount++; + priv->ContinueDiffCount++; else - priv->ContiuneDiffCount = 0; + priv->ContinueDiffCount = 0; - // Contiune count over - if(priv->ContiuneDiffCount >=2) + // Continue count over + if(priv->ContinueDiffCount >=2) { bSwitchFromCountDiff = true; - priv->ContiuneDiffCount = 0; + priv->ContinueDiffCount = 0; } } else { - // Stop contiune count - priv->ContiuneDiffCount = 0; + // Stop the continued count + priv->ContinueDiffCount = 0; } //If Count diff <= FsyncRateCountThreshold if(rate_count_diff <= priv->ieee80211->fsync_firstdiff_ratethreshold) { bSwitchFromCountDiff = true; - priv->ContiuneDiffCount = 0; + priv->ContinueDiffCount = 0; } priv->rate_record = rate_count; priv->rateCountDiffRecord = rate_count_diff; @@ -3468,14 +3468,14 @@ extern void dm_fsync_timer_callback(unsigned long data) #endif write_nic_byte(dev, 0xC3e, 0x96); } - priv->ContiuneDiffCount = 0; + priv->ContinueDiffCount = 0; #ifdef RTL8190P write_nic_dword(dev, rOFDM0_RxDetector2, 0x164052cd); #else write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd); #endif } - RT_TRACE(COMP_HALDM, "ContiuneDiffCount %d\n", priv->ContiuneDiffCount); + RT_TRACE(COMP_HALDM, "ContinueDiffCount %d\n", priv->ContinueDiffCount); RT_TRACE(COMP_HALDM, "rateRecord %d rateCount %d, rateCountdiff %d bSwitchFsync %d\n", priv->rate_record, rate_count, rate_count_diff , priv->bswitch_fsync); } @@ -3507,7 +3507,7 @@ static void dm_EndSWFsync(struct net_device *dev) write_nic_byte(dev, 0xC3e, 0x96); } - priv->ContiuneDiffCount = 0; + priv->ContinueDiffCount = 0; #ifndef RTL8190P write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd); #endif @@ -3523,8 +3523,8 @@ static void dm_StartSWFsync(struct net_device *dev) RT_TRACE(COMP_HALDM,"%s\n", __FUNCTION__); // Initial rate record to zero, start to record. priv->rate_record = 0; - // Initial contiune diff count to zero, start to record. - priv->ContiuneDiffCount = 0; + // Initialize continue diff count to zero, start to record. + priv->ContinueDiffCount = 0; priv->rateCountDiffRecord = 0; priv->bswitch_fsync = false; @@ -3875,7 +3875,7 @@ static void dm_send_rssi_tofw(struct net_device *dev) // If we test chariot, we should stop the TX command ? // Because 92E will always silent reset when we send tx command. We use register - // 0x1e0(byte) to botify driver. + // 0x1e0(byte) to notify driver. write_nic_byte(dev, DRIVER_RSSI, (u8)priv->undecorated_smoothed_pwdb); return; tx_cmd.Op = TXCMD_SET_RX_RSSI; diff --git a/trunk/drivers/staging/rtl8192u/r8192U_hw.h b/trunk/drivers/staging/rtl8192u/r8192U_hw.h index e89aaf70143b..1bfe871dcfb2 100644 --- a/trunk/drivers/staging/rtl8192u/r8192U_hw.h +++ b/trunk/drivers/staging/rtl8192u/r8192U_hw.h @@ -10,7 +10,7 @@ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. - We want to tanks the Authors of those projects + We want to thank the Authors of those projects and the Ndiswrapper project Authors. */ diff --git a/trunk/drivers/staging/rtl8192u/r8192U_wx.c b/trunk/drivers/staging/rtl8192u/r8192U_wx.c index f6408f98ede6..71f2d2349c38 100644 --- a/trunk/drivers/staging/rtl8192u/r8192U_wx.c +++ b/trunk/drivers/staging/rtl8192u/r8192U_wx.c @@ -13,7 +13,7 @@ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. - We want to tanks the Authors of those projects and the Ndiswrapper + We want to thank the Authors of those projects and the Ndiswrapper project Authors. */ @@ -256,7 +256,7 @@ static int r8192_wx_get_ap_status(struct net_device *dev, //count the length of input ssid for(name_len=0 ; ((char*)wrqu->data.pointer)[name_len]!='\0' ; name_len++); - //search for the correspoding info which is received + //search for the corresponding info which is received list_for_each_entry(target, &ieee->network_list, list) { if ( (target->ssid_len == name_len) && (strncmp(target->ssid, (char*)wrqu->data.pointer, name_len)==0)){ @@ -419,7 +419,7 @@ static int rtl8180_wx_get_range(struct net_device *dev, range->max_qual.updated = 7; /* Updated all three */ range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */ - /* TODO: Find real 'good' to 'bad' threshol value for RSSI */ + /* TODO: Find real 'good' to 'bad' threshold value for RSSI */ range->avg_qual.level = 20 + -98; range->avg_qual.noise = 0; range->avg_qual.updated = 7; /* Updated all three */ @@ -1047,7 +1047,7 @@ static iw_handler r8192_wx_handlers[] = #else NULL, #endif - dummy, /* SIOCGIWAPLIST -- depricated */ + dummy, /* SIOCGIWAPLIST -- deprecated */ r8192_wx_set_scan, /* SIOCSIWSCAN */ r8192_wx_get_scan, /* SIOCGIWSCAN */ r8192_wx_set_essid, /* SIOCSIWESSID */ @@ -1211,9 +1211,9 @@ struct iw_statistics *r8192_get_wireless_stats(struct net_device *dev) struct iw_handler_def r8192_wx_handlers_def={ .standard = r8192_wx_handlers, - .num_standard = sizeof(r8192_wx_handlers) / sizeof(iw_handler), + .num_standard = ARRAY_SIZE(r8192_wx_handlers), .private = r8192_private_handler, - .num_private = sizeof(r8192_private_handler) / sizeof(iw_handler), + .num_private = ARRAY_SIZE(r8192_private_handler), .num_private_args = sizeof(r8192_private_args) / sizeof(struct iw_priv_args), #if WIRELESS_EXT >= 17 .get_wireless_stats = r8192_get_wireless_stats, diff --git a/trunk/drivers/staging/rtl8192u/r8192U_wx.h b/trunk/drivers/staging/rtl8192u/r8192U_wx.h index f4cf2801136a..9f6b10505426 100644 --- a/trunk/drivers/staging/rtl8192u/r8192U_wx.h +++ b/trunk/drivers/staging/rtl8192u/r8192U_wx.h @@ -7,7 +7,7 @@ Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver - We want to tanks the Authors of such projects and the Ndiswrapper project Authors. + We want to thank the Authors of such projects and the Ndiswrapper project Authors. */ /* this file (will) contains wireless extension handlers*/ diff --git a/trunk/drivers/staging/rtl8192u/r819xU_HTType.h b/trunk/drivers/staging/rtl8192u/r819xU_HTType.h index 2ac421626e7c..e07f8b17a0d6 100644 --- a/trunk/drivers/staging/rtl8192u/r819xU_HTType.h +++ b/trunk/drivers/staging/rtl8192u/r819xU_HTType.h @@ -211,7 +211,7 @@ typedef struct _RT_HIGH_THROUGHPUT{ u8 bEnableHT; u8 bCurrentHTSupport; - u8 bRegBW40MHz; // Tx 40MHz channel capablity + u8 bRegBW40MHz; // Tx 40MHz channel capability u8 bCurBW40MHz; // Tx 40MHz channel capability u8 bRegShortGI40MHz; // Tx Short GI for 40Mhz diff --git a/trunk/drivers/staging/rtl8192u/r819xU_cmdpkt.c b/trunk/drivers/staging/rtl8192u/r819xU_cmdpkt.c index 0cb28c776c49..a8a6dc2c365f 100644 --- a/trunk/drivers/staging/rtl8192u/r819xU_cmdpkt.c +++ b/trunk/drivers/staging/rtl8192u/r819xU_cmdpkt.c @@ -157,7 +157,7 @@ SendTxCommandPacket( seg_ptr = skb_put(skb, buffer_len); /* * Transform from little endian to big endian - * and pending zero + * and pending zero */ memcpy(seg_ptr,codevirtualaddress,buffer_len); tcb_desc->txbuf_size= (u16)buffer_len; @@ -697,7 +697,6 @@ cmpk_message_handle_rx( struct ieee80211_rx_stats *pstats) { // u32 debug_level = DBG_LOUD; - struct r8192_priv *priv = ieee80211_priv(dev); int total_length; u8 cmd_length, exe_cnt = 0; u8 element_id; @@ -719,15 +718,15 @@ cmpk_message_handle_rx( /* 2. Read virtual address from RFD. */ pcmd_buff = pstats->virtual_address; - /* 3. Read command pakcet element id and length. */ + /* 3. Read command packet element id and length. */ element_id = pcmd_buff[0]; /*RT_TRACE(COMP_SEND, DebugLevel, ("\n\r[CMPK]-->element ID=%d Len=%d", element_id, total_length));*/ - /* 4. Check every received command packet conent according to different + /* 4. Check every received command packet content according to different element type. Because FW may aggregate RX command packet to minimize transmit time between DRV and FW.*/ - // Add a counter to prevent to locked in the loop too long + // Add a counter to prevent the lock in the loop from being held too long while (total_length > 0 || exe_cnt++ >100) { /* 2007/01/17 MH We support aggregation of different cmd in the same packet. */ @@ -779,9 +778,6 @@ cmpk_message_handle_rx( // 2007/01/22 MH Add to display tx statistic. //cmpk_DisplayTxStatistic(pAdapter); - /* 2007/03/09 MH Collect sidderent cmd element pkt num. */ - priv->stats.rxcmdpkt[element_id]++; - total_length -= cmd_length; pcmd_buff += cmd_length; } /* while (total_length > 0) */ diff --git a/trunk/drivers/staging/rtl8192u/r819xU_firmware.c b/trunk/drivers/staging/rtl8192u/r819xU_firmware.c index 4bb5fffca5b9..b12d19079798 100644 --- a/trunk/drivers/staging/rtl8192u/r819xU_firmware.c +++ b/trunk/drivers/staging/rtl8192u/r819xU_firmware.c @@ -275,11 +275,11 @@ bool init_firmware(struct net_device *dev) /* * Download boot, main, and data image for System reset. - * Download data image for firmware reseta + * Download data image for firmware reset */ for(init_step = starting_state; init_step <= FW_INIT_STEP2_DATA; init_step++) { /* - * Open Image file, and map file to contineous memory if open file success. + * Open image file, and map file to continuous memory if open file success. * or read image file from array. Default load from IMG file */ if(rst_opt == OPT_SYSTEM_RESET) { diff --git a/trunk/drivers/staging/rtl8192u/r819xU_phy.c b/trunk/drivers/staging/rtl8192u/r819xU_phy.c index c4586b0817d1..dd1954daea2d 100644 --- a/trunk/drivers/staging/rtl8192u/r819xU_phy.c +++ b/trunk/drivers/staging/rtl8192u/r819xU_phy.c @@ -40,7 +40,7 @@ static u32 RF_CHANNEL_TABLE_ZEBRA[] = { * and do register read/write * input: u32 dwBitMask //taget bit pos in the addr to be modified * output: none - * return: u32 return the shift bit bit position of the mask + * return: u32 return the shift bit position of the mask * ****************************************************************************/ u32 rtl8192_CalculateBitShift(u32 dwBitMask) { @@ -176,7 +176,7 @@ u32 rtl8192_phy_RFSerialRead(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, bLSSIReadEdge, 0x1); - // TODO: we should not delay such a long time. Ask help from SD3 + // TODO: we should not delay such a long time. Ask for help from SD3 msleep(1); ret = rtl8192_QueryBBReg(dev, pPhyReg->rfLSSIReadBack, bLSSIReadBackData); @@ -252,7 +252,7 @@ void rtl8192_phy_RFSerialWrite(struct net_device* dev, RF90_RADIO_PATH_E eRFPath NewOffset = Offset; } - // Put write addr in [5:0] and write data in [31:16] + // Put write addr in [5:0] and write data in [31:16] DataAndAddr = (Data<<16) | (NewOffset&0x3f); // Write Operation @@ -525,7 +525,7 @@ void rtl8192_phy_configmac(struct net_device* dev) } /****************************************************************************** - *function: This function do dirty work + *function: This function does dirty work * input: dev * output: none * return: none @@ -578,7 +578,7 @@ void rtl8192_phyConfigBB(struct net_device* dev, u8 ConfigType) void rtl8192_InitBBRFRegDef(struct net_device* dev) { struct r8192_priv *priv = ieee80211_priv(dev); -// RF Interface Sowrtware Control +// RF Interface Software Control priv->PHYRegDef[RF90_PATH_A].rfintfs = rFPGA0_XAB_RFInterfaceSW; // 16 LSBs if read 32-bit from 0x870 priv->PHYRegDef[RF90_PATH_B].rfintfs = rFPGA0_XAB_RFInterfaceSW; // 16 MSBs if read 32-bit from 0x870 (16-bit for 0x872) priv->PHYRegDef[RF90_PATH_C].rfintfs = rFPGA0_XCD_RFInterfaceSW;// 16 LSBs if read 32-bit from 0x874 @@ -602,7 +602,7 @@ void rtl8192_InitBBRFRegDef(struct net_device* dev) priv->PHYRegDef[RF90_PATH_C].rfintfe = rFPGA0_XC_RFInterfaceOE;// 16 MSBs if read 32-bit from 0x86A (16-bit for 0x86A) priv->PHYRegDef[RF90_PATH_D].rfintfe = rFPGA0_XD_RFInterfaceOE;// 16 MSBs if read 32-bit from 0x86C (16-bit for 0x86E) - //Addr of LSSI. Wirte RF register by driver + //Addr of LSSI. Write RF register by driver priv->PHYRegDef[RF90_PATH_A].rf3wireOffset = rFPGA0_XA_LSSIParameter; //LSSI Parameter priv->PHYRegDef[RF90_PATH_B].rf3wireOffset = rFPGA0_XB_LSSIParameter; priv->PHYRegDef[RF90_PATH_C].rf3wireOffset = rFPGA0_XC_LSSIParameter; @@ -1384,7 +1384,7 @@ u8 rtl8192_phy_SwChnlStepByStep(struct net_device *dev, u8 channel, u8* stage, u } /****************************************************************************** - *function: This function does acturally set channel work + *function: This function does actually set channel work * input: struct net_device *dev * u8 channel * output: none @@ -1425,7 +1425,7 @@ void rtl8192_SwChnl_WorkItem(struct net_device *dev) } /****************************************************************************** - *function: This function scheduled actural workitem to set channel + *function: This function scheduled actual work item to set channel * input: net_device dev * u8 channel //channel to set * output: none diff --git a/trunk/drivers/staging/rtl8192u/r819xU_phyreg.h b/trunk/drivers/staging/rtl8192u/r819xU_phyreg.h index 06b0b539e1bc..50f24dce8b16 100644 --- a/trunk/drivers/staging/rtl8192u/r819xU_phyreg.h +++ b/trunk/drivers/staging/rtl8192u/r819xU_phyreg.h @@ -443,7 +443,7 @@ #define bCCKRxIG 0x7f00 #define bCCKLNAPolarity 0x800000 #define bCCKRx1stGain 0x7f0000 -#define bCCKRFExtend 0x20000000 //CCK Rx Iinital gain polarity +#define bCCKRFExtend 0x20000000 //CCK Rx inital gain polarity #define bCCKRxAGCSatLevel 0x1f000000 #define bCCKRxAGCSatCount 0xe0 #define bCCKRxRFSettle 0x1f //AGCsamp_dly diff --git a/trunk/drivers/staging/rtl8712/big_endian.h b/trunk/drivers/staging/rtl8712/big_endian.h deleted file mode 100644 index b16f8ecf99c6..000000000000 --- a/trunk/drivers/staging/rtl8712/big_endian.h +++ /dev/null @@ -1,94 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 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 - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef _LINUX_BYTEORDER_BIG_ENDIAN_H -#define _LINUX_BYTEORDER_BIG_ENDIAN_H - -#ifndef __BIG_ENDIAN -#define __BIG_ENDIAN 4321 -#endif -#ifndef __BIG_ENDIAN_BITFIELD -#define __BIG_ENDIAN_BITFIELD -#endif - -#include "swab.h" - -#define __constant_htonl(x) ((__u32)(x)) -#define __constant_ntohl(x) ((__u32)(x)) -#define __constant_htons(x) ((__u16)(x)) -#define __constant_ntohs(x) ((__u16)(x)) -#define __constant_cpu_to_le64(x) ___constant_swab64((x)) -#define __constant_le64_to_cpu(x) ___constant_swab64((x)) -#define __constant_cpu_to_le32(x) ___constant_swab32((x)) -#define __constant_le32_to_cpu(x) ___constant_swab32((x)) -#define __constant_cpu_to_le16(x) ___constant_swab16((x)) -#define __constant_le16_to_cpu(x) ___constant_swab16((x)) -#define __constant_cpu_to_be64(x) ((__u64)(x)) -#define __constant_be64_to_cpu(x) ((__u64)(x)) -#define __constant_cpu_to_be32(x) ((__u32)(x)) -#define __constant_be32_to_cpu(x) ((__u32)(x)) -#define __constant_cpu_to_be16(x) ((__u16)(x)) -#define __constant_be16_to_cpu(x) ((__u16)(x)) -#define __cpu_to_le64(x) __swab64((x)) -#define __le64_to_cpu(x) __swab64((x)) -#define __cpu_to_le32(x) __swab32((x)) -#define __le32_to_cpu(x) __swab32((x)) -#define __cpu_to_le16(x) __swab16((x)) -#define __le16_to_cpu(x) __swab16((x)) -#define __cpu_to_be64(x) ((__u64)(x)) -#define __be64_to_cpu(x) ((__u64)(x)) -#define __cpu_to_be32(x) ((__u32)(x)) -#define __be32_to_cpu(x) ((__u32)(x)) -#define __cpu_to_be16(x) ((__u16)(x)) -#define __be16_to_cpu(x) ((__u16)(x)) -#define __cpu_to_le64p(x) __swab64p((x)) -#define __le64_to_cpup(x) __swab64p((x)) -#define __cpu_to_le32p(x) __swab32p((x)) -#define __le32_to_cpup(x) __swab32p((x)) -#define __cpu_to_le16p(x) __swab16p((x)) -#define __le16_to_cpup(x) __swab16p((x)) -#define __cpu_to_be64p(x) (*(__u64 *)(x)) -#define __be64_to_cpup(x) (*(__u64 *)(x)) -#define __cpu_to_be32p(x) (*(__u32 *)(x)) -#define __be32_to_cpup(x) (*(__u32 *)(x)) -#define __cpu_to_be16p(x) (*(__u16 *)(x)) -#define __be16_to_cpup(x) (*(__u16 *)(x)) -#define __cpu_to_le64s(x) __swab64s((x)) -#define __le64_to_cpus(x) __swab64s((x)) -#define __cpu_to_le32s(x) __swab32s((x)) -#define __le32_to_cpus(x) __swab32s((x)) -#define __cpu_to_le16s(x) __swab16s((x)) -#define __le16_to_cpus(x) __swab16s((x)) -#define __cpu_to_be64s(x) do {} while (0) -#define __be64_to_cpus(x) do {} while (0) -#define __cpu_to_be32s(x) do {} while (0) -#define __be32_to_cpus(x) do {} while (0) -#define __cpu_to_be16s(x) do {} while (0) -#define __be16_to_cpus(x) do {} while (0) - -#include "generic.h" - -#endif /* _LINUX_BYTEORDER_BIG_ENDIAN_H */ - diff --git a/trunk/drivers/staging/rtl8712/drv_types.h b/trunk/drivers/staging/rtl8712/drv_types.h index e83665d06020..62b55663c63a 100644 --- a/trunk/drivers/staging/rtl8712/drv_types.h +++ b/trunk/drivers/staging/rtl8712/drv_types.h @@ -146,7 +146,7 @@ struct dvobj_priv { /** * struct _adapter - the main adapter structure for this device. * - * bup: True indicates that the interface is Up. + * bup: True indicates that the interface is up. */ struct _adapter { struct dvobj_priv dvobjpriv; diff --git a/trunk/drivers/staging/rtl8712/generic.h b/trunk/drivers/staging/rtl8712/generic.h deleted file mode 100644 index 8868c9f4adf8..000000000000 --- a/trunk/drivers/staging/rtl8712/generic.h +++ /dev/null @@ -1,178 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 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 - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef _LINUX_BYTEORDER_GENERIC_H -#define _LINUX_BYTEORDER_GENERIC_H - -/* - * linux/byteorder_generic.h - * Generic Byte-reordering support - * - * Francois-Rene Rideau 19970707 - * gathered all the good ideas from all asm-foo/byteorder.h into one file, - * cleaned them up. - * I hope it is compliant with non-GCC compilers. - * I decided to put __BYTEORDER_HAS_U64__ in byteorder.h, - * because I wasn't sure it would be ok to put it in types.h - * Upgraded it to 2.1.43 - * Francois-Rene Rideau 19971012 - * Upgraded it to 2.1.57 - * to please Linus T., replaced huge #ifdef's between little/big endian - * by nestedly #include'd files. - * Francois-Rene Rideau 19971205 - * Made it to 2.1.71; now a facelift: - * Put files under include/linux/byteorder/ - * Split swab from generic support. - * - * TODO: - * = Regular kernel maintainers could also replace all these manual - * byteswap macros that remain, disseminated among drivers, - * after some grep or the sources... - * = Linus might want to rename all these macros and files to fit his taste, - * to fit his personal naming scheme. - * = it seems that a few drivers would also appreciate - * nybble swapping support... - * = every architecture could add their byteswap macro in asm/byteorder.h - * see how some architectures already do (i386, alpha, ppc, etc) - * = cpu_to_beXX and beXX_to_cpu might some day need to be well - * distinguished throughout the kernel. This is not the case currently, - * since little endian, big endian, and pdp endian machines needn't it. - * But this might be the case for, say, a port of Linux to 20/21 bit - * architectures (and F21 Linux addict around?). - */ - -/* - * The following macros are to be defined by : - * - * Conversion of long and short int between network and host format - * ntohl(__u32 x) - * ntohs(__u16 x) - * htonl(__u32 x) - * htons(__u16 x) - * It seems that some programs (which? where? or perhaps a standard? POSIX?) - * might like the above to be functions, not macros (why?). - * if that's true, then detect them, and take measures. - * Anyway, the measure is: define only ___ntohl as a macro instead, - * and in a separate file, have - * unsigned long inline ntohl(x){return ___ntohl(x);} - * - * The same for constant arguments - * __constant_ntohl(__u32 x) - * __constant_ntohs(__u16 x) - * __constant_htonl(__u32 x) - * __constant_htons(__u16 x) - * - * Conversion of XX-bit integers (16- 32- or 64-) - * between native CPU format and little/big endian format - * 64-bit stuff only defined for proper architectures - * cpu_to_[bl]eXX(__uXX x) - * [bl]eXX_to_cpu(__uXX x) - * - * The same, but takes a pointer to the value to convert - * cpu_to_[bl]eXXp(__uXX x) - * [bl]eXX_to_cpup(__uXX x) - * - * The same, but change in situ - * cpu_to_[bl]eXXs(__uXX x) - * [bl]eXX_to_cpus(__uXX x) - * - * See asm-foo/byteorder.h for examples of how to provide - * architecture-optimized versions - * - */ - - -/* - * inside the kernel, we can use nicknames; - * outside of it, we must avoid POSIX namespace pollution... - */ -#define cpu_to_le64 __cpu_to_le64 -#define le64_to_cpu __le64_to_cpu -#define cpu_to_le32 __cpu_to_le32 -#define le32_to_cpu __le32_to_cpu -#define cpu_to_le16 __cpu_to_le16 -#define le16_to_cpu __le16_to_cpu -#define cpu_to_be64 __cpu_to_be64 -#define be64_to_cpu __be64_to_cpu -#define cpu_to_be32 __cpu_to_be32 -#define be32_to_cpu __be32_to_cpu -#define cpu_to_be16 __cpu_to_be16 -#define be16_to_cpu __be16_to_cpu -#define cpu_to_le64p __cpu_to_le64p -#define le64_to_cpup __le64_to_cpup -#define cpu_to_le32p __cpu_to_le32p -#define le32_to_cpup __le32_to_cpup -#define cpu_to_le16p __cpu_to_le16p -#define le16_to_cpup __le16_to_cpup -#define cpu_to_be64p __cpu_to_be64p -#define be64_to_cpup __be64_to_cpup -#define cpu_to_be32p __cpu_to_be32p -#define be32_to_cpup __be32_to_cpup -#define cpu_to_be16p __cpu_to_be16p -#define be16_to_cpup __be16_to_cpup -#define cpu_to_le64s __cpu_to_le64s -#define le64_to_cpus __le64_to_cpus -#define cpu_to_le32s __cpu_to_le32s -#define le32_to_cpus __le32_to_cpus -#define cpu_to_le16s __cpu_to_le16s -#define le16_to_cpus __le16_to_cpus -#define cpu_to_be64s __cpu_to_be64s -#define be64_to_cpus __be64_to_cpus -#define cpu_to_be32s __cpu_to_be32s -#define be32_to_cpus __be32_to_cpus -#define cpu_to_be16s __cpu_to_be16s -#define be16_to_cpus __be16_to_cpus - - -/* - * Handle ntohl and suches. These have various compatibility - * issues - like we want to give the prototype even though we - * also have a macro for them in case some strange program - * wants to take the address of the thing or something.. - * - * Note that these used to return a "long" in libc5, even though - * long is often 64-bit these days.. Thus the casts. - * - * They have to be macros in order to do the constant folding - * correctly - if the argument passed into a inline function - * it is no longer constant according to gcc.. - */ - -#undef ntohl -#undef ntohs -#undef htonl -#undef htons - -/* - * Do the prototypes. Somebody might want to take the - * address or some such sick thing.. - */ -extern __u32 ntohl(__u32); -extern __u32 htonl(__u32); -extern unsigned short int ntohs(unsigned short int); -extern unsigned short int htons(unsigned short int); - -#endif /* _LINUX_BYTEORDER_GENERIC_H */ - diff --git a/trunk/drivers/staging/rtl8712/hal_init.c b/trunk/drivers/staging/rtl8712/hal_init.c index cc893c0f5ad3..cb9d4cfe8fe4 100644 --- a/trunk/drivers/staging/rtl8712/hal_init.c +++ b/trunk/drivers/staging/rtl8712/hal_init.c @@ -36,7 +36,6 @@ #include "osdep_service.h" #include "drv_types.h" -#include "rtl871x_byteorder.h" #include "usb_osintf.h" #define FWBUFF_ALIGN_SZ 512 diff --git a/trunk/drivers/staging/rtl8712/ieee80211.h b/trunk/drivers/staging/rtl8712/ieee80211.h index 3c0092b7de09..21515c31b373 100644 --- a/trunk/drivers/staging/rtl8712/ieee80211.h +++ b/trunk/drivers/staging/rtl8712/ieee80211.h @@ -705,7 +705,7 @@ enum ieee80211_state { IEEE80211_ASSOCIATING_RETRY, /* the association procedure is sending AUTH request*/ IEEE80211_ASSOCIATING_AUTHENTICATING, - /* the association procedure has successfully authentcated + /* the association procedure has successfully authenticated * and is sending association request */ IEEE80211_ASSOCIATING_AUTHENTICATED, diff --git a/trunk/drivers/staging/rtl8712/if_ether.h b/trunk/drivers/staging/rtl8712/if_ether.h deleted file mode 100644 index 2bbe527bcd5c..000000000000 --- a/trunk/drivers/staging/rtl8712/if_ether.h +++ /dev/null @@ -1,141 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 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 - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Global definitions for the Ethernet IEEE 802.3 interface. - * - * Version: @(#)if_ether.h 1.0.1a 02/08/94 - * - * Author: Fred N. van Kempen, - * Donald Becker, - * Alan Cox, - * Steve Whitehouse, - * - * 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_IF_ETHER_H -#define _LINUX_IF_ETHER_H - -/* - * IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble - * and FCS/CRC (frame check sequence). - */ - -#define ETH_ALEN 6 /* Octets in one ethernet addr */ -#define ETH_HLEN 14 /* Total octets in header. */ -#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ -#define ETH_DATA_LEN 1500 /* Max. octets in payload */ -#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */ - -/* - * These are the defined Ethernet Protocol ID's. - */ - -#define ETH_P_LOOP 0x0060 /* Ethernet Loopback packet */ -#define ETH_P_PUP 0x0200 /* Xerox PUP packet */ -#define ETH_P_PUPAT 0x0201 /* Xerox PUP Addr Trans packet */ -#define ETH_P_IP 0x0800 /* Internet Protocol packet */ -#define ETH_P_X25 0x0805 /* CCITT X.25 */ -#define ETH_P_ARP 0x0806 /* Address Resolution packet */ -#define ETH_P_BPQ 0x08FF /* G8BPQ AX.25 Ethernet Packet - * [ NOT AN OFFICIAL ID ] */ -#define ETH_P_IEEEPUP 0x0a00 /* Xerox IEEE802.3 PUP packet */ -#define ETH_P_IEEEPUPAT 0x0a01 /* Xerox IEEE802.3 PUP Addr - * Trans packet */ -#define ETH_P_DEC 0x6000 /* DEC Assigned proto */ -#define ETH_P_DNA_DL 0x6001 /* DEC DNA Dump/Load */ -#define ETH_P_DNA_RC 0x6002 /* DEC DNA Remote Console */ -#define ETH_P_DNA_RT 0x6003 /* DEC DNA Routing */ -#define ETH_P_LAT 0x6004 /* DEC LAT */ -#define ETH_P_DIAG 0x6005 /* DEC Diagnostics */ -#define ETH_P_CUST 0x6006 /* DEC Customer use */ -#define ETH_P_SCA 0x6007 /* DEC Systems Comms Arch */ -#define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */ -#define ETH_P_ATALK 0x809B /* Appletalk DDP */ -#define ETH_P_AARP 0x80F3 /* Appletalk AARP */ -#define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */ -#define ETH_P_IPX 0x8137 /* IPX over DIX */ -#define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */ -#define ETH_P_PPP_DISC 0x8863 /* PPPoE discovery messages */ -#define ETH_P_PPP_SES 0x8864 /* PPPoE session messages */ -#define ETH_P_ATMMPOA 0x884c /* MultiProtocol Over ATM */ -#define ETH_P_ATMFATE 0x8884 /* Frame-based ATM Transport - * over Ethernet - */ - -/* - * Non DIX types. Won't clash for 1500 types. - */ - -#define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */ -#define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */ -#define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */ -#define ETH_P_802_2 0x0004 /* 802.2 frames */ -#define ETH_P_SNAP 0x0005 /* Internal only */ -#define ETH_P_DDCMP 0x0006 /* DEC DDCMP: Internal only */ -#define ETH_P_WAN_PPP 0x0007 /* Dummy type for WAN PPP frames*/ -#define ETH_P_PPP_MP 0x0008 /* Dummy type for PPP MP frames */ -#define ETH_P_LOCALTALK 0x0009 /* Localtalk pseudo type */ -#define ETH_P_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/ -#define ETH_P_TR_802_2 0x0011i /* 802.2 frames */ -#define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */ -#define ETH_P_CONTROL 0x0016 /* Card specific control frames */ -#define ETH_P_IRDA 0x0017 /* Linux-IrDA */ -#define ETH_P_ECONET 0x0018 /* Acorn Econet */ - -/* - * This is an Ethernet frame header. - */ - -struct ethhdr { - unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ - unsigned char h_source[ETH_ALEN]; /* source ether addr */ - unsigned short h_proto; /* packet type ID field */ -}; - -struct _vlan { - unsigned short h_vlan_TCI; /* Encapsulates priority and VLAN ID*/ - unsigned short h_vlan_encapsulated_proto; -}; - - - -#define get_vlan_id(pvlan) ((ntohs((unsigned short)pvlan->h_vlan_TCI)) & 0xfff) -#define get_vlan_priority(pvlan) ((ntohs((unsigned short)\ - pvlan->h_vlan_TCI)) >> 13) -#define get_vlan_encap_proto(pvlan) (ntohs((unsigned short)\ - pvlan->h_vlan_encapsulated_proto)) - - -#endif /* _LINUX_IF_ETHER_H */ - diff --git a/trunk/drivers/staging/rtl8712/ip.h b/trunk/drivers/staging/rtl8712/ip.h deleted file mode 100644 index f37b0f8d14d4..000000000000 --- a/trunk/drivers/staging/rtl8712/ip.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the IP protocol. - * - * Version: @(#)ip.h 1.0.2 04/28/93 - * - * Authors: Fred N. van Kempen, - * - * 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_IP_H -#define _LINUX_IP_H - -#include "rtl871x_byteorder.h" - -/* SOL_IP socket options */ - -#define IPTOS_TOS_MASK 0x1E -#define IPTOS_TOS(tos) ((tos)&IPTOS_TOS_MASK) -#define IPTOS_LOWDELAY 0x10 -#define IPTOS_THROUGHPUT 0x08 -#define IPTOS_RELIABILITY 0x04 -#define IPTOS_MINCOST 0x02 - -#define IPTOS_PREC_MASK 0xE0 -#define IPTOS_PREC(tos) ((tos)&IPTOS_PREC_MASK) -#define IPTOS_PREC_NETCONTROL 0xe0 -#define IPTOS_PREC_INTERNETCONTROL 0xc0 -#define IPTOS_PREC_CRITIC_ECP 0xa0 -#define IPTOS_PREC_FLASHOVERRIDE 0x80 -#define IPTOS_PREC_FLASH 0x60 -#define IPTOS_PREC_IMMEDIATE 0x40 -#define IPTOS_PREC_PRIORITY 0x20 -#define IPTOS_PREC_ROUTINE 0x00 - -/* IP options */ -#define IPOPT_COPY 0x80 -#define IPOPT_CLASS_MASK 0x60 -#define IPOPT_NUMBER_MASK 0x1f - -#define IPOPT_COPIED(o) ((o)&IPOPT_COPY) -#define IPOPT_CLASS(o) ((o)&IPOPT_CLASS_MASK) -#define IPOPT_NUMBER(o) ((o)&IPOPT_NUMBER_MASK) - -#define IPOPT_CONTROL 0x00 -#define IPOPT_RESERVED1 0x20 -#define IPOPT_MEASUREMENT 0x40 -#define IPOPT_RESERVED2 0x60 - -#define IPOPT_END (0 | IPOPT_CONTROL) -#define IPOPT_NOOP (1 | IPOPT_CONTROL) -#define IPOPT_SEC (2 | IPOPT_CONTROL|IPOPT_COPY) -#define IPOPT_LSRR (3 | IPOPT_CONTROL|IPOPT_COPY) -#define IPOPT_TIMESTAMP (4 | IPOPT_MEASUREMENT) -#define IPOPT_RR (7 | IPOPT_CONTROL) -#define IPOPT_SID (8 | IPOPT_CONTROL | IPOPT_COPY) -#define IPOPT_SSRR (9 | IPOPT_CONTROL | IPOPT_COPY) -#define IPOPT_RA (20 | IPOPT_CONTROL | IPOPT_COPY) - -#define IPVERSION 4 -#define MAXTTL 255 -#define IPDEFTTL 64 - -/* struct timestamp, struct route and MAX_ROUTES are removed. - * - * REASONS: it is clear that nobody used them because: - * - MAX_ROUTES value was wrong. - * - "struct route" was wrong. - * - "struct timestamp" had fatally misaligned bitfields and was completely - * unusable. - */ - -#define IPOPT_OPTVAL 0 -#define IPOPT_OLEN 1 -#define IPOPT_OFFSET 2 -#define IPOPT_MINOFF 4 -#define MAX_IPOPTLEN 40 -#define IPOPT_NOP IPOPT_NOOP -#define IPOPT_EOL IPOPT_END -#define IPOPT_TS IPOPT_TIMESTAMP - -#define IPOPT_TS_TSONLY 0 /* timestamps only */ -#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ -#define IPOPT_TS_PRESPEC 3 /* specified modules only */ - -struct ip_options { - __u32 faddr; /* Saved first hop address */ - unsigned char optlen; - unsigned char srr; - unsigned char rr; - unsigned char ts; - unsigned char is_setbyuser:1, /* Set by setsockopt? */ - is_data:1, /* Options in __data, rather than skb */ - is_strictroute:1, /* Strict source route */ - srr_is_hit:1, /* Packet destination addr was our one*/ - is_changed:1, /* IP checksum more not valid */ - rr_needaddr:1, /* Need to record addr of outgoing dev*/ - ts_needtime:1, /* Need to record timestamp */ - ts_needaddr:1; /* Need to record addr of outgoing dev*/ - unsigned char router_alert; - unsigned char __pad1; - unsigned char __pad2; - unsigned char __data[0]; -}; - -#define optlength(opt) (sizeof(struct ip_options) + opt->optlen) - -struct iphdr { -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8 ihl:4, - version:4; -#elif defined(__BIG_ENDIAN_BITFIELD) - __u8 version:4, - ihl:4; -#else -#error "Please fix " -#endif - __u8 tos; - __u16 tot_len; - __u16 id; - __u16 frag_off; - __u8 ttl; - __u8 protocol; - __u16 check; - __u32 saddr; - __u32 daddr; - /*The options start here. */ -}; - -#endif /* _LINUX_IP_H */ - diff --git a/trunk/drivers/staging/rtl8712/little_endian.h b/trunk/drivers/staging/rtl8712/little_endian.h deleted file mode 100644 index cd57d6c2850f..000000000000 --- a/trunk/drivers/staging/rtl8712/little_endian.h +++ /dev/null @@ -1,94 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 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 - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef _LINUX_BYTEORDER_LITTLE_ENDIAN_H -#define _LINUX_BYTEORDER_LITTLE_ENDIAN_H - -#ifndef __LITTLE_ENDIAN -#define __LITTLE_ENDIAN 1234 -#endif -#ifndef __LITTLE_ENDIAN_BITFIELD -#define __LITTLE_ENDIAN_BITFIELD -#endif - -#include "swab.h" - -#define __constant_htonl(x) ___constant_swab32((x)) -#define __constant_ntohl(x) ___constant_swab32((x)) -#define __constant_htons(x) ___constant_swab16((x)) -#define __constant_ntohs(x) ___constant_swab16((x)) -#define __constant_cpu_to_le64(x) ((__u64)(x)) -#define __constant_le64_to_cpu(x) ((__u64)(x)) -#define __constant_cpu_to_le32(x) ((__u32)(x)) -#define __constant_le32_to_cpu(x) ((__u32)(x)) -#define __constant_cpu_to_le16(x) ((__u16)(x)) -#define __constant_le16_to_cpu(x) ((__u16)(x)) -#define __constant_cpu_to_be64(x) ___constant_swab64((x)) -#define __constant_be64_to_cpu(x) ___constant_swab64((x)) -#define __constant_cpu_to_be32(x) ___constant_swab32((x)) -#define __constant_be32_to_cpu(x) ___constant_swab32((x)) -#define __constant_cpu_to_be16(x) ___constant_swab16((x)) -#define __constant_be16_to_cpu(x) ___constant_swab16((x)) -#define __cpu_to_le64(x) ((__u64)(x)) -#define __le64_to_cpu(x) ((__u64)(x)) -#define __cpu_to_le32(x) ((__u32)(x)) -#define __le32_to_cpu(x) ((__u32)(x)) -#define __cpu_to_le16(x) ((__u16)(x)) -#define __le16_to_cpu(x) ((__u16)(x)) -#define __cpu_to_be64(x) __swab64((x)) -#define __be64_to_cpu(x) __swab64((x)) -#define __cpu_to_be32(x) __swab32((x)) -#define __be32_to_cpu(x) __swab32((x)) -#define __cpu_to_be16(x) __swab16((x)) -#define __be16_to_cpu(x) __swab16((x)) -#define __cpu_to_le64p(x) (*(__u64 *)(x)) -#define __le64_to_cpup(x) (*(__u64 *)(x)) -#define __cpu_to_le32p(x) (*(__u32 *)(x)) -#define __le32_to_cpup(x) (*(__u32 *)(x)) -#define __cpu_to_le16p(x) (*(__u16 *)(x)) -#define __le16_to_cpup(x) (*(__u16 *)(x)) -#define __cpu_to_be64p(x) __swab64p((x)) -#define __be64_to_cpup(x) __swab64p((x)) -#define __cpu_to_be32p(x) __swab32p((x)) -#define __be32_to_cpup(x) __swab32p((x)) -#define __cpu_to_be16p(x) __swab16p((x)) -#define __be16_to_cpup(x) __swab16p((x)) -#define __cpu_to_le64s(x) do {} while (0) -#define __le64_to_cpus(x) do {} while (0) -#define __cpu_to_le32s(x) do {} while (0) -#define __le32_to_cpus(x) do {} while (0) -#define __cpu_to_le16s(x) do {} while (0) -#define __le16_to_cpus(x) do {} while (0) -#define __cpu_to_be64s(x) __swab64s((x)) -#define __be64_to_cpus(x) __swab64s((x)) -#define __cpu_to_be32s(x) __swab32s((x)) -#define __be32_to_cpus(x) __swab32s((x)) -#define __cpu_to_be16s(x) __swab16s((x)) -#define __be16_to_cpus(x) __swab16s((x)) - -#include "generic.h" - -#endif /* _LINUX_BYTEORDER_LITTLE_ENDIAN_H */ - diff --git a/trunk/drivers/staging/rtl8712/os_intfs.c b/trunk/drivers/staging/rtl8712/os_intfs.c index 7bbd53a410e3..448f00dd68fe 100644 --- a/trunk/drivers/staging/rtl8712/os_intfs.c +++ b/trunk/drivers/staging/rtl8712/os_intfs.c @@ -52,7 +52,7 @@ static int lbkmode = RTL8712_AIR_TRX; static int hci = RTL8712_USB; static int ampdu_enable = 1;/*for enable tx_ampdu*/ -/* The video_mode variable is for vedio mode.*/ +/* The video_mode variable is for video mode.*/ /* It may be specify when inserting module with video_mode=1 parameter.*/ static int video_mode = 1; /* enable video mode*/ @@ -248,7 +248,7 @@ static u32 start_drv_threads(struct _adapter *padapter) void r8712_stop_drv_threads(struct _adapter *padapter) { - /*Below is to termindate r8712_cmd_thread & event_thread...*/ + /*Below is to terminate r8712_cmd_thread & event_thread...*/ up(&padapter->cmdpriv.cmd_queue_sema); if (padapter->cmdThread) _down_sema(&padapter->cmdpriv.terminate_cmdthread_sema); diff --git a/trunk/drivers/staging/rtl8712/osdep_service.h b/trunk/drivers/staging/rtl8712/osdep_service.h index 9ba603310fdc..f1ccc7ebbda7 100644 --- a/trunk/drivers/staging/rtl8712/osdep_service.h +++ b/trunk/drivers/staging/rtl8712/osdep_service.h @@ -29,7 +29,6 @@ #define _SUCCESS 1 #define _FAIL 0 -#include #include #include @@ -107,8 +106,6 @@ static inline void _set_workitem(_workitem *pwork) schedule_work(pwork); } -#include "rtl871x_byteorder.h" - #ifndef BIT #define BIT(x) (1 << (x)) #endif diff --git a/trunk/drivers/staging/rtl8712/rtl8712_cmd.c b/trunk/drivers/staging/rtl8712/rtl8712_cmd.c index 9f6ebc419b0b..088647cdca99 100644 --- a/trunk/drivers/staging/rtl8712/rtl8712_cmd.c +++ b/trunk/drivers/staging/rtl8712/rtl8712_cmd.c @@ -50,7 +50,6 @@ #include "drv_types.h" #include "recv_osdep.h" #include "mlme_osdep.h" -#include "rtl871x_byteorder.h" #include "rtl871x_ioctl_set.h" static void check_hw_pbc(struct _adapter *padapter) @@ -69,7 +68,7 @@ static void check_hw_pbc(struct _adapter *padapter) * After trigger PBC, the variable will be set to false */ DBG_8712("CheckPbcGPIO - PBC is pressed !!!!\n"); /* 0 is the default value and it means the application monitors - * the HW PBC doesn't privde its pid to driver. */ + * the HW PBC doesn't provide its pid to driver. */ if (padapter->pid == 0) return; kill_pid(find_vpid(padapter->pid), SIGUSR1, 1); @@ -382,7 +381,7 @@ int r8712_cmd_thread(void *context) *pcmdbuf = cpu_to_le32((cmdsz & 0x0000ffff) | (pcmd->cmdcode << 16) | (pcmdpriv->cmd_seq << 24)); - pcmdbuf += 2 ; /* 8 bytes aligment */ + pcmdbuf += 2 ; /* 8 bytes alignment */ memcpy((u8 *)pcmdbuf, pcmd->parmbuf, pcmd->cmdsz); while (check_cmd_fifo(padapter, wr_sz) == _FAIL) { if ((padapter->bDriverStopped == true) || @@ -471,7 +470,7 @@ void r8712_event_handle(struct _adapter *padapter, uint *peventbuf) pevt_priv->event_seq++; /* update evt_seq */ if (pevt_priv->event_seq > 127) pevt_priv->event_seq = 0; - peventbuf = peventbuf + 2; /* move to event content, 8 bytes aligment */ + peventbuf = peventbuf + 2; /* move to event content, 8 bytes alignment */ if (peventbuf) { event_callback = wlanevents[evt_code].event_callback; if (event_callback) diff --git a/trunk/drivers/staging/rtl8712/rtl8712_cmd.h b/trunk/drivers/staging/rtl8712/rtl8712_cmd.h index 766a6463266a..039ab3e97172 100644 --- a/trunk/drivers/staging/rtl8712/rtl8712_cmd.h +++ b/trunk/drivers/staging/rtl8712/rtl8712_cmd.h @@ -121,7 +121,7 @@ enum rtl8712_h2c_cmd { GEN_CMD_CODE(_GetCurDataRate) , GEN_CMD_CODE(_GetTxRetrycnt), /* to record times that Tx retry to - * transmmit packet after association + * transmit packet after association */ GEN_CMD_CODE(_GetRxRetrycnt), /* to record total number of the * received frame with ReTry bit set in diff --git a/trunk/drivers/staging/rtl8712/rtl8712_efuse.c b/trunk/drivers/staging/rtl8712/rtl8712_efuse.c index b08e9a25c9c5..377fca905801 100644 --- a/trunk/drivers/staging/rtl8712/rtl8712_efuse.c +++ b/trunk/drivers/staging/rtl8712/rtl8712_efuse.c @@ -417,7 +417,7 @@ u8 r8712_efuse_pg_packet_write(struct _adapter *padapter, const u8 offset, } else { /* write header fail */ bResult = false; if (0xFF == efuse_data) - return bResult; /* not thing damaged. */ + return bResult; /* nothing damaged. */ /* call rescue procedure */ if (fix_header(padapter, efuse_data, efuse_addr) == false) diff --git a/trunk/drivers/staging/rtl8712/rtl8712_gp_bitdef.h b/trunk/drivers/staging/rtl8712/rtl8712_gp_bitdef.h index 884a8212176d..138ea453d9df 100644 --- a/trunk/drivers/staging/rtl8712/rtl8712_gp_bitdef.h +++ b/trunk/drivers/staging/rtl8712/rtl8712_gp_bitdef.h @@ -70,7 +70,7 @@ #define GPIOSEL_BT 2 /* BT_coex*/ #define GPIOSEL_WLANDBG 3 /* WLANDBG*/ #define GPIOSEL_GPIO_MASK (~(BIT(0)|BIT(1))) -/* HW Readio OFF switch (GPIO BIT) */ +/* HW Radio OFF switch (GPIO BIT) */ #define HAL_8192S_HW_GPIO_OFF_BIT BIT(3) #define HAL_8192S_HW_GPIO_OFF_MASK 0xF7 #define HAL_8192S_HW_GPIO_WPS_BIT BIT(4) diff --git a/trunk/drivers/staging/rtl8712/rtl8712_hal.h b/trunk/drivers/staging/rtl8712/rtl8712_hal.h index d19865a5a50c..4c51fa373b54 100644 --- a/trunk/drivers/staging/rtl8712/rtl8712_hal.h +++ b/trunk/drivers/staging/rtl8712/rtl8712_hal.h @@ -83,7 +83,7 @@ struct fw_priv { /*8-bytes alignment required*/ unsigned char rfintfs; /* 0:SWSI, 1:HWSI, 2:HWPI*/ unsigned char def_nettype; unsigned char turboMode; - unsigned char lowPowerMode;/* 0: noral mode, 1: low power mode*/ + unsigned char lowPowerMode;/* 0: normal mode, 1: low power mode*/ /*--- long word 2 ----*/ unsigned char lbk_mode; /*0x00: normal, 0x03: MACLBK, 0x01: PHYLBK*/ unsigned char mp_mode; /* 1: for MP use, 0: for normal driver */ @@ -123,7 +123,7 @@ struct fw_priv { /*8-bytes alignment required*/ unsigned char rsvd053; }; -struct fw_hdr {/*8-byte alinment required*/ +struct fw_hdr {/*8-byte alignment required*/ unsigned short signature; unsigned short version; /*0x8000 ~ 0x8FFF for FPGA version, *0x0000 ~ 0x7FFF for ASIC version,*/ diff --git a/trunk/drivers/staging/rtl8712/rtl8712_led.c b/trunk/drivers/staging/rtl8712/rtl8712_led.c index bac56e5caf12..c9eb4b74799b 100644 --- a/trunk/drivers/staging/rtl8712/rtl8712_led.c +++ b/trunk/drivers/staging/rtl8712/rtl8712_led.c @@ -60,7 +60,7 @@ enum _LED_STATE_871x { * the # of times to blink is depend on time * for scanning. */ LED_NO_LINK_BLINK = 7, /* LED is blinking during no link state. */ - LED_BLINK_StartToBlink = 8,/* Customzied for Sercomm Printer + LED_BLINK_StartToBlink = 8,/* Customized for Sercomm Printer * Server case */ LED_BLINK_WPS = 9, /* LED is blinkg during WPS communication */ LED_TXRX_BLINK = 10, @@ -826,7 +826,7 @@ static void BlinkTimerCallback(unsigned long data) { struct LED_871x *pLed = (struct LED_871x *)data; - /* This fixed the crash problem on Fedora 12 when trying to do thei + /* This fixed the crash problem on Fedora 12 when trying to do the * insmod;ifconfig up;rmmod commands. */ if ((pLed->padapter->bSurpriseRemoved == true) || (pLed->padapter->bDriverStopped == true)) @@ -836,7 +836,7 @@ static void BlinkTimerCallback(unsigned long data) /* Description: * Callback function of LED BlinkWorkItem. - * We dispatch acture LED blink action according to LedStrategy. + * We dispatch actual LED blink action according to LedStrategy. */ static void BlinkWorkItemCallback(struct work_struct *work) { diff --git a/trunk/drivers/staging/rtl8712/rtl8712_recv.c b/trunk/drivers/staging/rtl8712/rtl8712_recv.c index fa6dc9c09b3f..8e82ce2fee38 100644 --- a/trunk/drivers/staging/rtl8712/rtl8712_recv.c +++ b/trunk/drivers/staging/rtl8712/rtl8712_recv.c @@ -28,12 +28,13 @@ #define _RTL8712_RECV_C_ +#include +#include + #include "osdep_service.h" #include "drv_types.h" #include "recv_osdep.h" #include "mlme_osdep.h" -#include "ip.h" -#include "if_ether.h" #include "ethernet.h" #include "usb_ops.h" #include "wifi.h" @@ -459,7 +460,7 @@ void r8712_rxcmd_event_hdl(struct _adapter *padapter, void *prxcmdbuf) cmd_seq = (u8)((le32_to_cpu(voffset) >> 24) & 0x7f); eid = (u8)((le32_to_cpu(voffset) >> 16) & 0xff); r8712_event_handle(padapter, (uint *)poffset); - poffset += (cmd_len + 8);/*8 bytes aligment*/ + poffset += (cmd_len + 8);/*8 bytes alignment*/ } while (le32_to_cpu(voffset) & BIT(31)); } @@ -603,7 +604,7 @@ static int recv_indicatepkt_reorder(struct _adapter *padapter, } } spin_lock_irqsave(&ppending_recvframe_queue->lock, irql); - /*s2. check if winstart_b(indicate_seq) needs to been updated*/ + /*s2. check if winstart_b(indicate_seq) needs to be updated*/ if (!check_indicate_seq(preorder_ctrl, pattrib->seq_num)) goto _err_exit; /*s3. Insert all packet into Reorder Queue to maintain its ordering.*/ diff --git a/trunk/drivers/staging/rtl8712/rtl8712_xmit.c b/trunk/drivers/staging/rtl8712/rtl8712_xmit.c index 693331955d67..3d23514c0222 100644 --- a/trunk/drivers/staging/rtl8712/rtl8712_xmit.c +++ b/trunk/drivers/staging/rtl8712/rtl8712_xmit.c @@ -30,7 +30,6 @@ #include "osdep_service.h" #include "drv_types.h" -#include "rtl871x_byteorder.h" #include "wifi.h" #include "osdep_intf.h" #include "usb_ops.h" diff --git a/trunk/drivers/staging/rtl8712/rtl871x_byteorder.h b/trunk/drivers/staging/rtl8712/rtl871x_byteorder.h deleted file mode 100644 index bd3703b98bce..000000000000 --- a/trunk/drivers/staging/rtl8712/rtl871x_byteorder.h +++ /dev/null @@ -1,32 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 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 _RTL871X_BYTEORDER_H_ -#define _RTL871X_BYTEORDER_H_ - -#if defined(__LITTLE_ENDIAN) -# include "little_endian.h" -#elif defined(__BIG_ENDIAN) -# include "big_endian.h" -#else -# error "Must be LITTLE/BIG Endian Host" -#endif - -#endif /* _RTL871X_BYTEORDER_H_ */ - diff --git a/trunk/drivers/staging/rtl8712/rtl871x_cmd.c b/trunk/drivers/staging/rtl8712/rtl871x_cmd.c index d77388bdba7b..659683e022b9 100644 --- a/trunk/drivers/staging/rtl8712/rtl871x_cmd.c +++ b/trunk/drivers/staging/rtl8712/rtl871x_cmd.c @@ -50,7 +50,6 @@ #include "drv_types.h" #include "recv_osdep.h" #include "mlme_osdep.h" -#include "rtl871x_byteorder.h" /* Caller and the r8712_cmd_thread can protect cmd_q by spin_lock. diff --git a/trunk/drivers/staging/rtl8712/rtl871x_cmd.h b/trunk/drivers/staging/rtl8712/rtl871x_cmd.h index 757ebf77e9d6..9d93189d8700 100644 --- a/trunk/drivers/staging/rtl8712/rtl871x_cmd.h +++ b/trunk/drivers/staging/rtl8712/rtl871x_cmd.h @@ -720,7 +720,7 @@ struct DisconnectCtrlEx_param { * Result: * 0x00: success * 0x01: success, and check Response. - * 0x02: cmd ignored due to duplicated sequcne number + * 0x02: cmd ignored due to duplicated sequence number * 0x03: cmd dropped due to invalid cmd code * 0x04: reserved. */ diff --git a/trunk/drivers/staging/rtl8712/rtl871x_io.h b/trunk/drivers/staging/rtl8712/rtl871x_io.h index d3d8727c2ec5..dc23395fec3b 100644 --- a/trunk/drivers/staging/rtl8712/rtl871x_io.h +++ b/trunk/drivers/staging/rtl8712/rtl871x_io.h @@ -117,7 +117,7 @@ struct io_req { u32 command; u32 status; u8 *pbuf; - void (*_async_io_callback)(struct _adapter *padater, + void (*_async_io_callback)(struct _adapter *padapter, struct io_req *pio_req, u8 *cnxt); u8 *cnxt; }; diff --git a/trunk/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/trunk/drivers/staging/rtl8712/rtl871x_ioctl_linux.c index ef35bc29a3fa..35e781fca4a0 100644 --- a/trunk/drivers/staging/rtl8712/rtl871x_ioctl_linux.c +++ b/trunk/drivers/staging/rtl8712/rtl871x_ioctl_linux.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include @@ -242,7 +241,7 @@ static inline char *translate_scan(struct _adapter *padapter, /* Add frequency/channel */ iwe.cmd = SIOCGIWFREQ; { - /* check legel index */ + /* check legal index */ u8 dsconfig = pnetwork->network.Configuration.DSConfig; if (dsconfig >= 1 && dsconfig <= sizeof( ieee80211_wlan_frequencies) / sizeof(long)) @@ -810,11 +809,11 @@ static int r871x_wx_set_pmkid(struct net_device *dev, /* There are the BSSID information in the bssid.sa_data array. - If cmd is IW_PMKSA_FLUSH, it means the wpa_suppplicant wants to clear - all the PMKID information. If cmd is IW_PMKSA_ADD, it means the - wpa_supplicant wants to add a PMKID/BSSID to driver. + If cmd is IW_PMKSA_FLUSH, it means the wpa_supplicant wants to clear + all the PMKID information. If cmd is IW_PMKSA_ADD, it means the + wpa_supplicant wants to add a PMKID/BSSID to driver. If cmd is IW_PMKSA_REMOVE, it means the wpa_supplicant wants to - remove a PMKID/BSSID from driver. + remove a PMKID/BSSID from driver. */ if (pPMK == NULL) return -EINVAL; @@ -924,7 +923,7 @@ static int r8711_wx_get_range(struct net_device *dev, range->max_qual.noise = 100; range->max_qual.updated = 7; /* Updated all three */ range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */ - /* TODO: Find real 'good' to 'bad' threshol value for RSSI */ + /* TODO: Find real 'good' to 'bad' threshold value for RSSI */ range->avg_qual.level = 20 + -98; range->avg_qual.noise = 0; range->avg_qual.updated = 7; /* Updated all three */ @@ -1071,7 +1070,7 @@ static int r871x_wx_set_priv(struct net_device *dev, * MAC# of a preferred Access Point. * Currently, the request comes via Wireless Extensions' SIOCSIWAP ioctl. * - * For this operation to succeed, there is no need for the interface to be Up. + * For this operation to succeed, there is no need for the interface to be up. * */ static int r8711_wx_set_wap(struct net_device *dev, @@ -2389,10 +2388,10 @@ static struct iw_statistics *r871x_get_wireless_stats(struct net_device *dev) struct iw_handler_def r871x_handlers_def = { .standard = r8711_handlers, - .num_standard = sizeof(r8711_handlers) / sizeof(iw_handler), + .num_standard = ARRAY_SIZE(r8711_handlers), .private = r8711_private_handler, .private_args = (struct iw_priv_args *)r8711_private_args, - .num_private = sizeof(r8711_private_handler) / sizeof(iw_handler), + .num_private = ARRAY_SIZE(r8711_private_handler), .num_private_args = sizeof(r8711_private_args) / sizeof(struct iw_priv_args), .get_wireless_stats = r871x_get_wireless_stats diff --git a/trunk/drivers/staging/rtl8712/rtl871x_ioctl_set.c b/trunk/drivers/staging/rtl8712/rtl871x_ioctl_set.c index fb29b423752f..f352b32355a0 100644 --- a/trunk/drivers/staging/rtl8712/rtl871x_ioctl_set.c +++ b/trunk/drivers/staging/rtl8712/rtl871x_ioctl_set.c @@ -264,7 +264,7 @@ void r8712_set_802_11_infrastructure_mode(struct _adapter *padapter, (*pold_state == Ndis802_11Infrastructure) || (*pold_state == Ndis802_11IBSS)) { /* will clr Linked_state before this function, - * we must have chked whether issue dis-assoc_cmd or + * we must have checked whether issue dis-assoc_cmd or * not */ r8712_ind_disconnect(padapter); } diff --git a/trunk/drivers/staging/rtl8712/rtl871x_mlme.c b/trunk/drivers/staging/rtl8712/rtl871x_mlme.c index 4277d0304b7a..dc7adc132d12 100644 --- a/trunk/drivers/staging/rtl8712/rtl871x_mlme.c +++ b/trunk/drivers/staging/rtl8712/rtl871x_mlme.c @@ -137,7 +137,7 @@ static void _free_network_nolock(struct mlme_priv *pmlmepriv, /* return the wlan_network with the matching addr - Shall be calle under atomic context... + Shall be called under atomic context... to avoid possible racing condition... */ static struct wlan_network *_r8712_find_network(struct __queue *scanned_queue, @@ -255,7 +255,7 @@ void r8712_free_network_queue(struct _adapter *dev) /* return the wlan_network with the matching addr - Shall be calle under atomic context... + Shall be called under atomic context... to avoid possible racing condition... */ static struct wlan_network *r8712_find_network(struct __queue *scanned_queue, @@ -1037,7 +1037,7 @@ void r8712_cpwm_event_callback(struct _adapter *adapter, u8 *pbuf) * and the WiFi client will drop the data with seq number 0. * So, the 8712 firmware has to inform driver with receiving the * ADDBA-Req frame so that the driver can reset the - * sequence value of Rx reorder contorl. + * sequence value of Rx reorder control. */ void r8712_got_addbareq_event_callback(struct _adapter *adapter, u8 *pbuf) { @@ -1775,7 +1775,7 @@ static void update_ht_cap(struct _adapter *padapter, u8 *pie, uint ie_len) phtpriv->rx_ampdu_maxlen = max_ampdu_sz; } /* for A-MPDU Rx reordering buffer control for bmc_sta & sta_info - * if A-MPDU Rx is enabled, reseting rx_ordering_ctrl + * if A-MPDU Rx is enabled, resetting rx_ordering_ctrl * wstart_b(indicate_seq) to default value=0xffff * todo: check if AP can send A-MPDU packets */ diff --git a/trunk/drivers/staging/rtl8712/rtl871x_mlme.h b/trunk/drivers/staging/rtl8712/rtl871x_mlme.h index 71ca01350b5e..42bd0bf8a816 100644 --- a/trunk/drivers/staging/rtl8712/rtl871x_mlme.h +++ b/trunk/drivers/staging/rtl8712/rtl871x_mlme.h @@ -69,8 +69,8 @@ since mlme_priv is a shared resource between many threads, like ISR/Call-Back functions, the OID handlers, and even timer functions. Each _queue has its own locks, already. Other items are protected by mlme_priv.lock. -To avoid possible dead lock, any thread trying to modifiying mlme_priv -SHALL not lock up more than one locks at a time! +To avoid possible dead lock, any thread trying to modify mlme_priv +SHALL not lock up more than one lock at a time! */ #define traffic_threshold 10 @@ -132,7 +132,7 @@ static inline sint get_fwstate(struct mlme_priv *pmlmepriv) * therefore set it to be the critical section... * * ### NOTE:#### (!!!!) - * TAKE CARE THAT BEFORE CALLING THIS FUNC, LOCK pmlmepriv->lock + * TAKE CARE BEFORE CALLING THIS FUNC, LOCK pmlmepriv->lock */ static inline void set_fwstate(struct mlme_priv *pmlmepriv, sint state) { diff --git a/trunk/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h b/trunk/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h index 23532a793859..8e2586231ffd 100644 --- a/trunk/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h +++ b/trunk/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h @@ -184,7 +184,7 @@ /*RxIQ DC offset, Rx digital filter, DC notch filter */ #define rOFDM0_XARxAFE 0xc10 -#define rOFDM0_XARxIQImbalance 0xc14 /* RxIQ imblance matrix */ +#define rOFDM0_XARxIQImbalance 0xc14 /* RxIQ imbalance matrix */ #define rOFDM0_XBRxAFE 0xc18 #define rOFDM0_XBRxIQImbalance 0xc1c #define rOFDM0_XCRxAFE 0xc20 @@ -603,7 +603,7 @@ #define bCCKRxIG 0x7f00 #define bCCKLNAPolarity 0x800000 #define bCCKRx1stGain 0x7f0000 -#define bCCKRFExtend 0x20000000 /* CCK Rx Iinital gain polarity */ +#define bCCKRFExtend 0x20000000 /* CCK Rx inital gain polarity */ #define bCCKRxAGCSatLevel 0x1f000000 #define bCCKRxAGCSatCount 0xe0 #define bCCKRxRFSettle 0x1f /* AGCsamp_dly */ diff --git a/trunk/drivers/staging/rtl8712/rtl871x_recv.c b/trunk/drivers/staging/rtl8712/rtl871x_recv.c index 5b03b405883e..c9d1743e5c5d 100644 --- a/trunk/drivers/staging/rtl8712/rtl871x_recv.c +++ b/trunk/drivers/staging/rtl8712/rtl871x_recv.c @@ -28,15 +28,15 @@ #define _RTL871X_RECV_C_ +#include #include +#include #include #include "osdep_service.h" #include "drv_types.h" #include "recv_osdep.h" #include "mlme_osdep.h" -#include "ip.h" -#include "if_ether.h" #include "ethernet.h" #include "usb_ops.h" #include "wifi.h" diff --git a/trunk/drivers/staging/rtl8712/rtl871x_xmit.c b/trunk/drivers/staging/rtl8712/rtl871x_xmit.c index aa57e7754f04..78f570b571a7 100644 --- a/trunk/drivers/staging/rtl8712/rtl871x_xmit.c +++ b/trunk/drivers/staging/rtl8712/rtl871x_xmit.c @@ -30,7 +30,6 @@ #include "osdep_service.h" #include "drv_types.h" -#include "rtl871x_byteorder.h" #include "wifi.h" #include "osdep_intf.h" #include "usb_ops.h" @@ -72,7 +71,7 @@ sint _r8712_init_xmit_priv(struct xmit_priv *pxmitpriv, memset((unsigned char *)pxmitpriv, 0, sizeof(struct xmit_priv)); spin_lock_init(&pxmitpriv->lock); /* - Please insert all the queue initializaiton using _init_queue below + Please insert all the queue initialization using _init_queue below */ pxmitpriv->adapter = padapter; _init_queue(&pxmitpriv->be_pending); diff --git a/trunk/drivers/staging/rtl8712/rtl871x_xmit.h b/trunk/drivers/staging/rtl8712/rtl871x_xmit.h index 638b79b4c5a8..ee906987735a 100644 --- a/trunk/drivers/staging/rtl8712/rtl871x_xmit.h +++ b/trunk/drivers/staging/rtl8712/rtl871x_xmit.h @@ -119,7 +119,7 @@ struct pkt_attrib { u8 priority; u8 encrypt; /* when 0 indicate no encrypt. when non-zero, - * indicate the encrypt algorith*/ + * indicate the encrypt algorithm*/ u8 iv_len; u8 icv_len; unsigned char iv[8]; diff --git a/trunk/drivers/staging/rtl8712/swab.h b/trunk/drivers/staging/rtl8712/swab.h deleted file mode 100644 index f12781829c1b..000000000000 --- a/trunk/drivers/staging/rtl8712/swab.h +++ /dev/null @@ -1,131 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 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 - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef _LINUX_BYTEORDER_SWAB_H -#define _LINUX_BYTEORDER_SWAB_H - -#ifndef __u16 - #define __u16 unsigned short -#endif - -#ifndef __u32 - #define __u32 unsigned int -#endif - -#ifndef __u8 - #define __u8 unsigned char -#endif - -#ifndef __u64 - #define __u64 unsigned long long -#endif - - -static inline __u16 ___swab16(__u16 x) -{ - __u16 __x = x; - return (__u16)( - (((__u16)(__x) & (__u16)0x00ffU) << 8) | - (((__u16)(__x) & (__u16)0xff00U) >> 8)); - -} - -static inline __u32 ___swab32(__u32 x) -{ - __u32 __x = (x); - return (__u32)( - (((__u32)(__x) & (__u32)0x000000ffUL) << 24) | - (((__u32)(__x) & (__u32)0x0000ff00UL) << 8) | - (((__u32)(__x) & (__u32)0x00ff0000UL) >> 8) | - (((__u32)(__x) & (__u32)0xff000000UL) >> 24)); -} - -static inline __u64 ___swab64(__u64 x) -{ - __u64 __x = (x); - - return (__u64)( \ - (__u64)(((__u64)(__x) & (__u64)0x00000000000000ffULL) << 56) | \ - (__u64)(((__u64)(__x) & (__u64)0x000000000000ff00ULL) << 40) | \ - (__u64)(((__u64)(__x) & (__u64)0x0000000000ff0000ULL) << 24) | \ - (__u64)(((__u64)(__x) & (__u64)0x00000000ff000000ULL) << 8) | \ - (__u64)(((__u64)(__x) & (__u64)0x000000ff00000000ULL) >> 8) | \ - (__u64)(((__u64)(__x) & (__u64)0x0000ff0000000000ULL) >> 24) | \ - (__u64)(((__u64)(__x) & (__u64)0x00ff000000000000ULL) >> 40) | \ - (__u64)(((__u64)(__x) & (__u64)0xff00000000000000ULL) >> 56)); -} - -#ifndef __arch__swab16 -static inline __u16 __arch__swab16(__u16 x) -{ - return ___swab16(x); -} - -#endif - -#ifndef __arch__swab32 -static inline __u32 __arch__swab32(__u32 x) -{ - __u32 __tmp = (x) ; - return ___swab32(__tmp); -} -#endif - -#ifndef __arch__swab64 - -static inline __u64 __arch__swab64(__u64 x) -{ - __u64 __tmp = (x) ; - return ___swab64(__tmp); -} - - -#endif - -#define __swab16(x) __fswab16(x) -#define __swab32(x) __fswab32(x) -#define __swab64(x) __fswab64(x) - -static inline const __u16 __fswab16(__u16 x) -{ - return __arch__swab16(x); -} -static inline const __u32 __fswab32(__u32 x) -{ - return __arch__swab32(x); -} - -#define swab16 __swab16 -#define swab32 __swab32 -#define swab64 __swab64 -#define swab16p __swab16p -#define swab32p __swab32p -#define swab64p __swab64p -#define swab16s __swab16s -#define swab32s __swab32s -#define swab64s __swab64s - -#endif /* _LINUX_BYTEORDER_SWAB_H */ - diff --git a/trunk/drivers/staging/rtl8712/usb_halinit.c b/trunk/drivers/staging/rtl8712/usb_halinit.c index 46287c17a417..b4ae11a78b46 100644 --- a/trunk/drivers/staging/rtl8712/usb_halinit.c +++ b/trunk/drivers/staging/rtl8712/usb_halinit.c @@ -141,7 +141,7 @@ u8 r8712_usb_hal_bus_init(struct _adapter *padapter) /* Enable AFE PLL Macro Block */ val8 = r8712_read8(padapter, AFE_PLL_CTRL); r8712_write8(padapter, AFE_PLL_CTRL, (val8 | 0x11)); - /* Attatch AFE PLL to MACTOP/BB/PCIe Digital */ + /* Attach AFE PLL to MACTOP/BB/PCIe Digital */ val8 = r8712_read8(padapter, SYS_ISO_CTRL); r8712_write8(padapter, SYS_ISO_CTRL, (val8 & 0xEE)); /* Switch to 40M clock */ @@ -234,7 +234,7 @@ u8 r8712_usb_hal_bus_init(struct _adapter *padapter) udelay(500); r8712_write8(padapter, AFE_PLL_CTRL, (val8 | 0x11)); udelay(500); - /* Attatch AFE PLL to MACTOP/BB/PCIe Digital */ + /* Attach AFE PLL to MACTOP/BB/PCIe Digital */ val8 = r8712_read8(padapter, SYS_ISO_CTRL); r8712_write8(padapter, SYS_ISO_CTRL, (val8 & 0xEE)); /* Switch to 40M clock */ diff --git a/trunk/drivers/staging/rtl8712/usb_intf.c b/trunk/drivers/staging/rtl8712/usb_intf.c index e419b4fd82b9..9bd18e2d0513 100644 --- a/trunk/drivers/staging/rtl8712/usb_intf.c +++ b/trunk/drivers/staging/rtl8712/usb_intf.c @@ -621,30 +621,28 @@ static void r871xu_dev_remove(struct usb_interface *pusb_intf) struct usb_device *udev = interface_to_usbdev(pusb_intf); usb_set_intfdata(pusb_intf, NULL); - if (padapter) { - if (padapter->fw_found) - release_firmware(padapter->fw); - /* never exit with a firmware callback pending */ - wait_for_completion(&padapter->rtl8712_fw_ready); - if (drvpriv.drv_registered == true) - padapter->bSurpriseRemoved = true; - if (pnetdev != NULL) { - /* will call netdev_close() */ - unregister_netdev(pnetdev); - } - flush_scheduled_work(); - udelay(1); - /*Stop driver mlme relation timer */ - if (padapter->fw_found) - r8712_stop_drv_timers(padapter); - r871x_dev_unload(padapter); - r8712_free_drv_sw(padapter); + if (padapter->fw_found) + release_firmware(padapter->fw); + /* never exit with a firmware callback pending */ + wait_for_completion(&padapter->rtl8712_fw_ready); + if (drvpriv.drv_registered == true) + padapter->bSurpriseRemoved = true; + if (pnetdev != NULL) { + /* will call netdev_close() */ + unregister_netdev(pnetdev); } + flush_scheduled_work(); + udelay(1); + /*Stop driver mlme relation timer */ + if (padapter->fw_found) + r8712_stop_drv_timers(padapter); + r871x_dev_unload(padapter); + r8712_free_drv_sw(padapter); usb_set_intfdata(pusb_intf, NULL); /* decrease the reference count of the usb device structure * when disconnect */ usb_put_dev(udev); - /* If we didn't unplug usb dongle and remove/insert modlue, driver + /* If we didn't unplug usb dongle and remove/insert module, driver * fails on sitesurvey for the first time when device is up. * Reset usb port for sitesurvey fail issue. */ if (udev->state != USB_STATE_NOTATTACHED) diff --git a/trunk/drivers/staging/rtl8712/usb_ops.c b/trunk/drivers/staging/rtl8712/usb_ops.c index 5a8b0ebd0b79..c03508d935f2 100644 --- a/trunk/drivers/staging/rtl8712/usb_ops.c +++ b/trunk/drivers/staging/rtl8712/usb_ops.c @@ -33,7 +33,6 @@ #include "osdep_intf.h" #include "usb_ops.h" #include "recv_osdep.h" -#include "rtl871x_byteorder.h" static u8 usb_read8(struct intf_hdl *pintfhdl, u32 addr) { diff --git a/trunk/drivers/staging/rtl8712/wifi.h b/trunk/drivers/staging/rtl8712/wifi.h index 277398cff0a7..793443e758ac 100644 --- a/trunk/drivers/staging/rtl8712/wifi.h +++ b/trunk/drivers/staging/rtl8712/wifi.h @@ -26,7 +26,6 @@ #ifndef _WIFI_H_ #define _WIFI_H_ -#include "rtl871x_byteorder.h" #include #ifdef BIT diff --git a/trunk/drivers/staging/rtl8712/xmit_linux.c b/trunk/drivers/staging/rtl8712/xmit_linux.c index c9703627c8f5..65542cb7168f 100644 --- a/trunk/drivers/staging/rtl8712/xmit_linux.c +++ b/trunk/drivers/staging/rtl8712/xmit_linux.c @@ -29,14 +29,12 @@ #define _XMIT_OSDEP_C_ #include +#include +#include #include "osdep_service.h" #include "drv_types.h" - -#include "if_ether.h" -#include "ip.h" -#include "rtl871x_byteorder.h" #include "wifi.h" #include "mlme_osdep.h" #include "xmit_osdep.h" diff --git a/trunk/drivers/staging/rts5139/ms.c b/trunk/drivers/staging/rts5139/ms.c index b0e9071c8e52..6eef33b03f55 100644 --- a/trunk/drivers/staging/rts5139/ms.c +++ b/trunk/drivers/staging/rts5139/ms.c @@ -2680,7 +2680,7 @@ static int mspro_set_rw_cmd(struct rts51x_chip *chip, u32 start_sec, return STATUS_SUCCESS; } -void mspro_stop_seq_mode(struct rts51x_chip *chip) +static void mspro_stop_seq_mode(struct rts51x_chip *chip) { struct ms_info *ms_card = &(chip->ms_card); int retval; @@ -3149,7 +3149,7 @@ static int ms_read_multiple_pages(struct rts51x_chip *chip, u16 phy_blk, TRACE_RET(chip, STATUS_FAIL); sec_cnt = chip->rsp_buf[0]; - RTS51X_DEBUGP("%d pages need be trasferred, %d pages remained\n", + RTS51X_DEBUGP("%d pages need be transferred, %d pages remained\n", (int)page_cnt, (int)sec_cnt); page_addr = start_page + (page_cnt - sec_cnt); @@ -3864,7 +3864,7 @@ static int ms_rw_multi_sector(struct scsi_cmnd *srb, struct rts51x_chip *chip, log_blk = (u16) (start_sector >> ms_card->block_shift); start_page = (u8) (start_sector & ms_card->page_off); - for (seg_no = 0; seg_no < sizeof(ms_start_idx) / 2; seg_no++) { + for (seg_no = 0; seg_no < ARRAY_SIZE(ms_start_idx) - 1; seg_no++) { if (log_blk < ms_start_idx[seg_no + 1]) break; } @@ -4020,7 +4020,8 @@ static int ms_rw_multi_sector(struct scsi_cmnd *srb, struct rts51x_chip *chip, log_blk++; - for (seg_no = 0; seg_no < sizeof(ms_start_idx) / 2; seg_no++) { + for (seg_no = 0; seg_no < ARRAY_SIZE(ms_start_idx) - 1; + seg_no++) { if (log_blk < ms_start_idx[seg_no + 1]) break; } @@ -4134,7 +4135,7 @@ void ms_cleanup_work(struct rts51x_chip *chip) } } -int ms_power_off_card3v3(struct rts51x_chip *chip) +static int ms_power_off_card3v3(struct rts51x_chip *chip) { int retval; diff --git a/trunk/drivers/staging/rts5139/ms.h b/trunk/drivers/staging/rts5139/ms.h index 3ce1dc90f19d..0321d06e776d 100644 --- a/trunk/drivers/staging/rts5139/ms.h +++ b/trunk/drivers/staging/rts5139/ms.h @@ -234,7 +234,6 @@ void mspro_polling_format_status(struct rts51x_chip *chip); void mspro_format_sense(struct rts51x_chip *chip, unsigned int lun); -void mspro_stop_seq_mode(struct rts51x_chip *chip); int reset_ms_card(struct rts51x_chip *chip); int ms_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 start_sector, u16 sector_cnt); @@ -242,7 +241,6 @@ int mspro_format(struct scsi_cmnd *srb, struct rts51x_chip *chip, int short_data_len, int quick_format); void ms_free_l2p_tbl(struct rts51x_chip *chip); void ms_cleanup_work(struct rts51x_chip *chip); -int ms_power_off_card3v3(struct rts51x_chip *chip); int release_ms_card(struct rts51x_chip *chip); int ms_delay_write(struct rts51x_chip *chip); diff --git a/trunk/drivers/staging/rts5139/ms_mg.c b/trunk/drivers/staging/rts5139/ms_mg.c index 154b5230aa5e..057d96c1a937 100644 --- a/trunk/drivers/staging/rts5139/ms_mg.c +++ b/trunk/drivers/staging/rts5139/ms_mg.c @@ -38,7 +38,7 @@ #ifdef SUPPORT_MAGIC_GATE -int mg_check_int_error(struct rts51x_chip *chip) +static int mg_check_int_error(struct rts51x_chip *chip) { u8 value; @@ -444,7 +444,7 @@ int mg_rsp(struct scsi_cmnd *srb, struct rts51x_chip *chip) * * Since the extra 4 bytes data is just only a prefix to original data * that read from medium, so that the 4-byte data pushed into Ring buffer - * precedes data tramsinssion from medium to Ring buffer by DMA mechanisim + * precedes data transmission from medium to Ring buffer by DMA mechanism * in order to get maximum performance and minimum code size simultaneously. */ int mg_get_ICV(struct scsi_cmnd *srb, struct rts51x_chip *chip) diff --git a/trunk/drivers/staging/rts5139/rts51x.c b/trunk/drivers/staging/rts5139/rts51x.c index 2b9f785954df..c3fe7dda1f4e 100644 --- a/trunk/drivers/staging/rts5139/rts51x.c +++ b/trunk/drivers/staging/rts5139/rts51x.c @@ -56,12 +56,6 @@ MODULE_DESCRIPTION(RTS51X_DESC); MODULE_LICENSE("GPL"); MODULE_VERSION(DRIVER_VERSION); -#ifdef SCSI_SCAN_DELAY -static unsigned int delay_use = 5; -module_param(delay_use, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device"); -#endif - static int auto_delink_en; module_param(auto_delink_en, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(auto_delink_en, "enable auto delink"); @@ -114,7 +108,7 @@ static inline void usb_autopm_disable(struct usb_interface *intf) usb_autopm_get_interface(intf); } -void rts51x_try_to_enter_ss(struct rts51x_chip *chip) +static void rts51x_try_to_enter_ss(struct rts51x_chip *chip) { RTS51X_DEBUGP("Ready to enter SS state\n"); usb_autopm_enable(chip->usb->pusb_intf); @@ -207,7 +201,7 @@ int rts51x_reset_resume(struct usb_interface *iface) #else /* CONFIG_PM */ -void rts51x_try_to_enter_ss(struct rts51x_chip *chip) +static void rts51x_try_to_enter_ss(struct rts51x_chip *chip) { } @@ -364,11 +358,6 @@ static int rts51x_polling_thread(void *__chip) { struct rts51x_chip *chip = (struct rts51x_chip *)__chip; -#ifdef SCSI_SCAN_DELAY - /* Wait until SCSI scan finished */ - wait_timeout((delay_use + 5) * HZ); -#endif - for (;;) { wait_timeout(POLLING_INTERVAL); @@ -432,38 +421,6 @@ static int rts51x_polling_thread(void *__chip) return 0; } -#ifdef SCSI_SCAN_DELAY -/* Thread to carry out delayed SCSI-device scanning */ -static int rts51x_scan_thread(void *__chip) -{ - struct rts51x_chip *chip = (struct rts51x_chip *)__chip; - - printk(KERN_DEBUG - "rts51x: device found at %d\n", chip->usb->pusb_dev->devnum); - - set_freezable(); - /* Wait for the timeout to expire or for a disconnect */ - if (delay_use > 0) { - printk(KERN_DEBUG "rts51x: waiting for device " - "to settle before scanning\n"); - wait_event_freezable_timeout(chip->usb->delay_wait, - test_bit(FLIDX_DONT_SCAN, - &chip->usb->dflags), - delay_use * HZ); - } - - /* If the device is still connected, perform the scanning */ - if (!test_bit(FLIDX_DONT_SCAN, &chip->usb->dflags)) { - scsi_scan_host(rts51x_to_host(chip)); - printk(KERN_DEBUG "rts51x: device scan complete\n"); - - /* Should we unbind if no devices were detected? */ - } - - complete_and_exit(&chip->usb->scanning_done, 0); -} -#endif - /* Associate our private data with the USB device */ static int associate_dev(struct rts51x_chip *chip, struct usb_interface *intf) { @@ -521,7 +478,6 @@ static void rts51x_init_options(struct rts51x_chip *chip) { struct rts51x_option *option = &(chip->option); - option->led_blink_speed = 7; option->mspro_formatter_enable = 1; option->fpga_sd_sdr104_clk = CLK_100; @@ -549,7 +505,6 @@ static void rts51x_init_options(struct rts51x_chip *chip) option->ss_en = ss_en; option->ss_delay = ss_delay; - option->needs_remote_wakeup = needs_remote_wakeup; option->auto_delink_en = auto_delink_en; @@ -561,10 +516,7 @@ static void rts51x_init_options(struct rts51x_chip *chip) option->rts5129_D3318_off_enable = 0; option->sd20_pad_drive = 0; option->reset_or_rw_fail_set_pad_drive = 1; - option->rcc_fail_flag = 0; - option->rcc_bug_fix_en = 1; option->debounce_num = 2; - option->polling_time = 100; option->led_toggle_interval = 6; option->xd_rwn_step = 0; option->sd_send_status_en = 0; @@ -737,15 +689,6 @@ static void quiesce_and_remove_host(struct rts51x_chip *chip) if (rts51x->pusb_dev->state == USB_STATE_NOTATTACHED) set_bit(FLIDX_DISCONNECTING, &rts51x->dflags); -#ifdef SCSI_SCAN_DELAY - /* Prevent SCSI-scanning (if it hasn't started yet) - * and wait for the SCSI-scanning thread to stop. - */ - set_bit(FLIDX_DONT_SCAN, &rts51x->dflags); - wake_up(&rts51x->delay_wait); - wait_for_completion(&rts51x->scanning_done); -#endif - /* Removing the host will perform an orderly shutdown: caches * synchronized, disks spun down, etc. */ @@ -757,9 +700,6 @@ static void quiesce_and_remove_host(struct rts51x_chip *chip) scsi_lock(host); set_bit(FLIDX_DISCONNECTING, &rts51x->dflags); scsi_unlock(host); -#ifdef SCSI_SCAN_DELAY - wake_up(&rts51x->delay_wait); -#endif } /* Second stage of disconnect processing: deallocate all resources */ @@ -818,10 +758,6 @@ static int rts51x_probe(struct usb_interface *intf, init_completion(&rts51x->control_exit); init_completion(&rts51x->polling_exit); init_completion(&(rts51x->notify)); -#ifdef SCSI_SCAN_DELAY - init_waitqueue_head(&rts51x->delay_wait); - init_completion(&rts51x->scanning_done); -#endif chip->usb = rts51x; @@ -855,22 +791,7 @@ static int rts51x_probe(struct usb_interface *intf, printk(KERN_WARNING RTS51X_TIP "Unable to add the scsi host\n"); goto BadDevice; } -#ifdef SCSI_SCAN_DELAY - /* Start up the thread for delayed SCSI-device scanning */ - th = kthread_create(rts51x_scan_thread, chip, RTS51X_SCAN_THREAD); - if (IS_ERR(th)) { - printk(KERN_WARNING RTS51X_TIP - "Unable to start the device-scanning thread\n"); - complete(&rts51x->scanning_done); - quiesce_and_remove_host(chip); - result = PTR_ERR(th); - goto BadDevice; - } - - wake_up_process(th); -#else scsi_scan_host(rts51x_to_host(chip)); -#endif /* Start up our polling thread */ th = kthread_run(rts51x_polling_thread, chip, RTS51X_POLLING_THREAD); diff --git a/trunk/drivers/staging/rts5139/rts51x.h b/trunk/drivers/staging/rts5139/rts51x.h index b2c58390bfc5..ecc0109a5b1a 100644 --- a/trunk/drivers/staging/rts5139/rts51x.h +++ b/trunk/drivers/staging/rts5139/rts51x.h @@ -47,11 +47,9 @@ #define RTS51X_DESC "Realtek RTS5139/29 USB card reader driver" #define RTS51X_NAME "rts5139" #define RTS51X_CTL_THREAD "rts5139-control" -#define RTS51X_SCAN_THREAD "rts5139-scan" #define RTS51X_POLLING_THREAD "rts5139-polling" #define POLLING_IN_THREAD -/* #define SCSI_SCAN_DELAY */ #define SUPPORT_FILE_OP #define wait_timeout_x(task_state, msecs) \ @@ -66,8 +64,6 @@ do { \ /* Size of the DMA-mapped I/O buffer */ #define RTS51X_IOBUF_SIZE 1024 -/* Size of the autosense data buffer */ -#define RTS51X_SENSE_SIZE 18 /* Dynamic bitflag definitions (dflags): used in set_bit() etc. */ #define FLIDX_URB_ACTIVE 0 /* current_urb is in use */ @@ -76,7 +72,6 @@ do { \ #define FLIDX_DISCONNECTING 3 /* disconnect in progress */ #define FLIDX_RESETTING 4 /* device reset in progress */ #define FLIDX_TIMED_OUT 5 /* SCSI midlayer timed out */ -#define FLIDX_DONT_SCAN 6 /* don't scan (disconnect) */ struct rts51x_chip; @@ -116,10 +111,6 @@ struct rts51x_usb { struct completion control_exit; /* control thread exit */ struct completion polling_exit; /* polling thread exit */ struct completion notify; /* thread begin/end */ -#ifdef SCSI_SCAN_DELAY - wait_queue_head_t delay_wait; /* wait during scan, reset */ - struct completion scanning_done; /* wait for scan thread */ -#endif }; extern struct usb_driver rts51x_driver; @@ -188,7 +179,6 @@ enum xfer_buf_dir { TO_XFER_BUF, FROM_XFER_BUF }; /* General routines provided by the usb-storage standard core */ #ifdef CONFIG_PM -void rts51x_try_to_enter_ss(struct rts51x_chip *chip); void rts51x_try_to_exit_ss(struct rts51x_chip *chip); int rts51x_suspend(struct usb_interface *iface, pm_message_t message); int rts51x_resume(struct usb_interface *iface); diff --git a/trunk/drivers/staging/rts5139/rts51x_card.c b/trunk/drivers/staging/rts5139/rts51x_card.c index 424a84581b86..4192c3bac12f 100644 --- a/trunk/drivers/staging/rts5139/rts51x_card.c +++ b/trunk/drivers/staging/rts5139/rts51x_card.c @@ -37,7 +37,6 @@ #include "rts51x_chip.h" #include "rts51x_card.h" #include "rts51x_transport.h" -#include "rts51x_sys.h" #include "xd.h" #include "sd.h" #include "ms.h" @@ -94,7 +93,7 @@ void do_remaining_work(struct rts51x_chip *chip) ms_cleanup_work(chip); } -void do_reset_xd_card(struct rts51x_chip *chip) +static void do_reset_xd_card(struct rts51x_chip *chip) { int retval; @@ -148,7 +147,7 @@ void do_reset_sd_card(struct rts51x_chip *chip) } } -void do_reset_ms_card(struct rts51x_chip *chip) +static void do_reset_ms_card(struct rts51x_chip *chip) { int retval; @@ -175,7 +174,7 @@ void do_reset_ms_card(struct rts51x_chip *chip) } } -void card_cd_debounce(struct rts51x_chip *chip, u8 *need_reset, +static void card_cd_debounce(struct rts51x_chip *chip, u8 *need_reset, u8 *need_release) { int retval; @@ -191,7 +190,6 @@ void card_cd_debounce(struct rts51x_chip *chip, u8 *need_reset, goto Exit_Debounce; if (chip->card_exist) { - rts51x_clear_start_time(chip); retval = rts51x_read_register(chip, CARD_INT_PEND, &value); if (retval != STATUS_SUCCESS) { rts51x_ep0_write_register(chip, MC_FIFO_CTL, FIFO_FLUSH, @@ -214,17 +212,11 @@ void card_cd_debounce(struct rts51x_chip *chip, u8 *need_reset, } } else { if (chip->card_status & XD_CD) { - rts51x_clear_start_time(chip); reset_map |= XD_CARD; } else if (chip->card_status & SD_CD) { - rts51x_clear_start_time(chip); reset_map |= SD_CARD; } else if (chip->card_status & MS_CD) { - rts51x_clear_start_time(chip); reset_map |= MS_CARD; - } else { - if (rts51x_check_start_time(chip)) - rts51x_set_start_time(chip); } } @@ -709,7 +701,7 @@ u8 get_lun_card(struct rts51x_chip *chip, unsigned int lun) return 0; } -int card_share_mode(struct rts51x_chip *chip, int card) +static int card_share_mode(struct rts51x_chip *chip, int card) { u8 value; @@ -823,22 +815,6 @@ int enable_card_clock(struct rts51x_chip *chip, u8 card) return STATUS_SUCCESS; } -int disable_card_clock(struct rts51x_chip *chip, u8 card) -{ - u8 clk_en = 0; - - if (card & XD_CARD) - clk_en |= XD_CLK_EN; - if (card & SD_CARD) - clk_en |= SD_CLK_EN; - if (card & MS_CARD) - clk_en |= MS_CLK_EN; - - RTS51X_WRITE_REG(chip, CARD_CLK_EN, clk_en, 0); - - return STATUS_SUCCESS; -} - int card_power_on(struct rts51x_chip *chip, u8 card) { u8 mask, val1, val2; @@ -851,16 +827,7 @@ int card_power_on(struct rts51x_chip *chip, u8 card) if ((card == SD_CARD) || (card == XD_CARD)) { RTS51X_WRITE_REG(chip, CARD_PWR_CTL, mask | LDO3318_PWR_MASK, val1 | LDO_SUSPEND); - /* RTS51X_WRITE_REG(chip, CARD_PWR_CTL, - LDO3318_PWR_MASK, LDO_SUSPEND); */ } - /* else if(card==XD_CARD) - { - RTS51X_WRITE_REG(chip, CARD_PWR_CTL, - mask|LDO3318_PWR_MASK, val1|LDO_SUSPEND); - //RTS51X_WRITE_REG(chip, CARD_PWR_CTL, - // LDO3318_PWR_MASK, LDO_SUSPEND); - } */ else { #endif RTS51X_WRITE_REG(chip, CARD_PWR_CTL, mask, val1); @@ -879,17 +846,6 @@ int card_power_on(struct rts51x_chip *chip, u8 card) return STATUS_SUCCESS; } -int card_power_off(struct rts51x_chip *chip, u8 card) -{ - u8 mask, val; - - mask = POWER_MASK; - val = POWER_OFF; - RTS51X_WRITE_REG(chip, CARD_PWR_CTL, mask, val); - - return STATUS_SUCCESS; -} - int monitor_card_cd(struct rts51x_chip *chip, u8 card) { int retval; diff --git a/trunk/drivers/staging/rts5139/rts51x_card.h b/trunk/drivers/staging/rts5139/rts51x_card.h index ac3c1e741ab9..c5c03cce98bd 100644 --- a/trunk/drivers/staging/rts5139/rts51x_card.h +++ b/trunk/drivers/staging/rts5139/rts51x_card.h @@ -204,13 +204,7 @@ /* LDO_POWER_CFG */ #define TUNE_SD18_MASK 0x1C -#define TUNE_SD18_1V7 0x00 #define TUNE_SD18_1V8 (0x01 << 2) -#define TUNE_SD18_1V9 (0x02 << 2) -#define TUNE_SD18_2V0 (0x03 << 2) -#define TUNE_SD18_2V7 (0x04 << 2) -#define TUNE_SD18_2V8 (0x05 << 2) -#define TUNE_SD18_2V9 (0x06 << 2) #define TUNE_SD18_3V3 (0x07 << 2) /* XD_CP_WAITTIME */ @@ -744,9 +738,7 @@ int monitor_card_cd(struct rts51x_chip *chip, u8 card); void do_remaining_work(struct rts51x_chip *chip); -void do_reset_xd_card(struct rts51x_chip *chip); void do_reset_sd_card(struct rts51x_chip *chip); -void do_reset_ms_card(struct rts51x_chip *chip); void rts51x_init_cards(struct rts51x_chip *chip); void rts51x_release_cards(struct rts51x_chip *chip); int switch_ssc_clock(struct rts51x_chip *chip, int clk); @@ -754,15 +746,12 @@ int switch_normal_clock(struct rts51x_chip *chip, int clk); int card_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 sec_addr, u16 sec_cnt); u8 get_lun_card(struct rts51x_chip *chip, unsigned int lun); -int card_share_mode(struct rts51x_chip *chip, int card); int rts51x_select_card(struct rts51x_chip *chip, int card); void eject_card(struct rts51x_chip *chip, unsigned int lun); void trans_dma_enable(enum dma_data_direction dir, struct rts51x_chip *chip, u32 byte_cnt, u8 pack_size); int enable_card_clock(struct rts51x_chip *chip, u8 card); -int disable_card_clock(struct rts51x_chip *chip, u8 card); int card_power_on(struct rts51x_chip *chip, u8 card); -int card_power_off(struct rts51x_chip *chip, u8 card); int toggle_gpio(struct rts51x_chip *chip, u8 gpio); int turn_on_led(struct rts51x_chip *chip, u8 gpio); int turn_off_led(struct rts51x_chip *chip, u8 gpio); diff --git a/trunk/drivers/staging/rts5139/rts51x_chip.c b/trunk/drivers/staging/rts5139/rts51x_chip.c index b3e0bb22b0ff..db88d7a194b8 100644 --- a/trunk/drivers/staging/rts5139/rts51x_chip.c +++ b/trunk/drivers/staging/rts5139/rts51x_chip.c @@ -34,7 +34,6 @@ #include "rts51x_chip.h" #include "rts51x_card.h" #include "rts51x_transport.h" -#include "rts51x_sys.h" #include "xd.h" #include "ms.h" #include "sd.h" @@ -79,20 +78,18 @@ int rts51x_reset_chip(struct rts51x_chip *chip) chip->option.sd20_pad_drive); if (chip->rts5179) rts51x_write_register(chip, CARD_PULL_CTL5, 0x03, 0x01); - if (!chip->option.ww_enable) { - if (CHECK_PKG(chip, LQFP48)) { - rts51x_write_register(chip, CARD_PULL_CTL3, - 0x80, 0x80); - rts51x_write_register(chip, CARD_PULL_CTL6, - 0xf0, 0xA0); - } else { - rts51x_write_register(chip, CARD_PULL_CTL1, - 0x30, 0x20); - rts51x_write_register(chip, CARD_PULL_CTL3, - 0x80, 0x80); - rts51x_write_register(chip, CARD_PULL_CTL6, - 0x0c, 0x08); - } + if (CHECK_PKG(chip, LQFP48)) { + rts51x_write_register(chip, CARD_PULL_CTL3, + 0x80, 0x80); + rts51x_write_register(chip, CARD_PULL_CTL6, + 0xf0, 0xA0); + } else { + rts51x_write_register(chip, CARD_PULL_CTL1, + 0x30, 0x20); + rts51x_write_register(chip, CARD_PULL_CTL3, + 0x80, 0x80); + rts51x_write_register(chip, CARD_PULL_CTL6, + 0x0c, 0x08); } } if (chip->option.sd_ctl & SUPPORT_UHS50_MMC44) { @@ -121,12 +118,6 @@ int rts51x_reset_chip(struct rts51x_chip *chip) /* GPIO OE */ rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_GPIO, GPIO_OE, GPIO_OE); -#ifdef LED_AUTO_BLINK - /* LED autoblink */ - rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_AUTO_BLINK, - BLINK_ENABLE | BLINK_SPEED_MASK, - BLINK_ENABLE | chip->option.led_blink_speed); -#endif rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DMA1_CTL, EXTEND_DMA1_ASYNC_SIGNAL, EXTEND_DMA1_ASYNC_SIGNAL); @@ -144,7 +135,6 @@ int rts51x_reset_chip(struct rts51x_chip *chip) card_power_on(chip, SD_CARD | MS_CARD | XD_CARD); wait_timeout(10); } - rts51x_clear_start_time(chip); return STATUS_SUCCESS; } @@ -164,12 +154,6 @@ int rts51x_init_chip(struct rts51x_chip *chip) chip->card_ejected = 0; chip->lun2card[0] = XD_CARD | SD_CARD | MS_CARD; -#if 0 - chip->option.sdr50_tx_phase = 0x01; - chip->option.sdr50_rx_phase = 0x05; - chip->option.ddr50_tx_phase = 0x09; - chip->option.ddr50_rx_phase = 0x06; /* add for debug */ -#endif #ifdef CLOSE_SSC_POWER rts51x_write_register(chip, FPDCTL, SSC_POWER_MASK, SSC_POWER_ON); udelay(100); @@ -178,9 +162,6 @@ int rts51x_init_chip(struct rts51x_chip *chip) RTS51X_SET_STAT(chip, STAT_RUN); RTS51X_READ_REG(chip, HW_VERSION, &val); - if ((val & 0x0f) >= 2) - chip->option.rcc_bug_fix_en = 0; - RTS51X_DEBUGP("rcc bug fix enable:%d\n", chip->option.rcc_bug_fix_en); RTS51X_DEBUGP("HW_VERSION: 0x%x\n", val); if (val & FPGA_VER) { chip->asic_code = 0; @@ -237,7 +218,6 @@ int rts51x_release_chip(struct rts51x_chip *chip) return STATUS_SUCCESS; } -#ifndef LED_AUTO_BLINK static inline void rts51x_blink_led(struct rts51x_chip *chip) { /* Read/Write */ @@ -251,20 +231,6 @@ static inline void rts51x_blink_led(struct rts51x_chip *chip) } } } -#endif - -int rts51x_check_start_time(struct rts51x_chip *chip) -{ - return 0; -} - -void rts51x_set_start_time(struct rts51x_chip *chip) -{ -} - -void rts51x_clear_start_time(struct rts51x_chip *chip) -{ -} static void rts51x_auto_delink_cmd(struct rts51x_chip *chip) { @@ -287,7 +253,6 @@ static void rts51x_auto_delink_polling_cycle(struct rts51x_chip *chip) chip->option.delink_delay * 2) { if (chip->auto_delink_counter == chip->option.delink_delay) { - clear_first_install_mark(chip); if (chip->card_exist) { /* False card */ if (!chip->card_ejected) { @@ -321,91 +286,13 @@ static void rts51x_auto_delink(struct rts51x_chip *chip) } #else /* some of called funcs are not implemented, so comment it out */ -#if 0 -/* using precise time as delink time */ -static void rts51x_auto_delink_precise_time(struct rts51x_chip *chip) -{ - int retvalue = 0; - - retvalue = rts51x_get_card_status(chip, &chip->card_status); - /* get card CD status success and card CD not exist, - * then check whether delink */ - if ((retvalue == STATUS_SUCCESS) - && (!(chip->card_status & (SD_CD | MS_CD | XD_CD)))) { - if (rts51x_count_delink_time(chip) >= - chip->option.delink_delay) { - clear_first_install_mark(chip); - RTS51X_DEBUGP("No card inserted, do delink\n"); - /* sangdy2010-05-17:disable because there is error - * after SSC clock closed and card power - * has been closed before */ - /* rts51x_write_register(chip, CARD_PWR_CTL, - DV3318_AUTO_PWR_OFF, 0); */ - rts51x_auto_delink_cmd(chip); - } - /* card CD exist and not ready, then do force delink */ - if ((retvalue == STATUS_SUCCESS) - && (chip->card_status & (SD_CD | MS_CD | XD_CD))) { - /* if card is not ejected or safely remove, - * then do force delink */ - if (!chip->card_ejected) { - /* sangdy2010-11-16:polling at least 2 cycles - * then do force delink for card may force delink - * if card is extracted and insert quickly - * after ready. */ - if (chip->auto_delink_counter > 1) { - if (rts51x_count_delink_time(chip) > - chip->option.delink_delay * 2) { - RTS51X_DEBUGP("Try to do force" - "delink\n"); - rts51x_auto_delink_force_cmd(chip); - } - } - } - } - chip->auto_delink_counter++; -} -#else -static void rts51x_auto_delink_precise_time(struct rts51x_chip *chip) -{ -} -#endif - static void rts51x_auto_delink(struct rts51x_chip *chip) { - rts51x_auto_delink_precise_time(chip); } #endif void rts51x_polling_func(struct rts51x_chip *chip) { -#ifdef SUPPORT_SD_LOCK - struct sd_info *sd_card = &(chip->sd_card); - - if (sd_card->sd_erase_status) { - if (chip->card_exist & SD_CARD) { - u8 val; - rts51x_read_register(chip, SD_BUS_STAT, &val); - if (val & SD_DAT0_STATUS) { - /* Erase completed */ - sd_card->sd_erase_status = SD_NOT_ERASE; - sd_card->sd_lock_notify = 1; - - /* SD card should be reinited, - * so we release it here. */ - sd_cleanup_work(chip); - release_sd_card(chip); - chip->card_ready &= ~SD_CARD; - chip->card_exist &= ~SD_CARD; - chip->rw_card[chip->card2lun[SD_CARD]] = NULL; - clear_bit(chip->card2lun[SD_CARD], - &(chip->lun_mc)); - } - } else { - sd_card->sd_erase_status = SD_NOT_ERASE; - } - } -#endif rts51x_init_cards(chip); @@ -431,9 +318,7 @@ void rts51x_polling_func(struct rts51x_chip *chip) if (!RTS51X_CHK_STAT(chip, STAT_IDLE)) { RTS51X_DEBUGP("Idle state!\n"); RTS51X_SET_STAT(chip, STAT_IDLE); -#ifndef LED_AUTO_BLINK chip->led_toggle_counter = 0; -#endif /* Idle state, turn off LED * to reduce power consumption */ if (chip->option.led_always_on @@ -467,9 +352,7 @@ void rts51x_polling_func(struct rts51x_chip *chip) switch (RTS51X_GET_STAT(chip)) { case STAT_RUN: -#ifndef LED_AUTO_BLINK rts51x_blink_led(chip); -#endif do_remaining_work(chip); break; @@ -484,7 +367,6 @@ void rts51x_polling_func(struct rts51x_chip *chip) rts51x_auto_delink(chip); } else { chip->auto_delink_counter = 0; - rts51x_clear_start_time(chip); } } @@ -831,7 +713,7 @@ void rts51x_do_before_power_down(struct rts51x_chip *chip) chip->cur_clk = 0; chip->card_exist = 0; chip->cur_card = 0; - if (chip->asic_code && !chip->option.ww_enable) { + if (chip->asic_code) { if (CHECK_PKG(chip, LQFP48)) { rts51x_write_register(chip, CARD_PULL_CTL3, 0x80, 0x00); rts51x_write_register(chip, CARD_PULL_CTL6, 0xf0, 0x50); @@ -863,16 +745,6 @@ void rts51x_prepare_run(struct rts51x_chip *chip) rts51x_write_register(chip, CLK_DIV, CLK_CHANGE, 0x00); } #endif -#if 0 - if (chip->option.ss_en && RTS51X_CHK_STAT(chip, STAT_SS)) { - rts51x_try_to_exit_ss(chip); - wait_timeout(100); - rts51x_init_chip(chip); - rts51x_init_cards(chip); - } - - RTS51X_SET_STAT(chip, STAT_RUN); -#endif } #ifdef _MSG_TRACE @@ -1017,24 +889,6 @@ void rts51x_pp_status(struct rts51x_chip *chip, unsigned int lun, u8 *status, status[0x0F] = 0x00; } } -#ifdef SUPPORT_SD_LOCK - /* SD Lock/Unlock */ - if (card == SD_CARD) { - status[0x17] = 0x80; - if (sd_card->sd_erase_status) - status[0x17] |= 0x01; /* Under erasing */ - if (sd_card->sd_lock_status & SD_LOCKED) { - status[0x17] |= 0x02; /* Locked */ - status[0x07] |= 0x40; /* Read protected */ - } - if (sd_card->sd_lock_status & SD_PWD_EXIST) - status[0x17] |= 0x04; /* Contain PWD */ - } else { - status[0x17] = 0x00; - } - - RTS51X_DEBUGP("status[0x17] = 0x%x\n", status[0x17]); -#endif /* Function 0 * Support Magic Gate, CPRM and PhyRegister R/W */ @@ -1044,12 +898,6 @@ void rts51x_pp_status(struct rts51x_chip *chip, unsigned int lun, u8 *status, * Support OC LUN status & WP LUN status */ status[0x1A] = 0x28; - /* Function 7 */ -#ifdef SUPPORT_SD_LOCK - /* Support SD Lock/Unlock */ - status[0x1F] = 0x01; -#endif - /* Function 2 * Support OC LUN status & WP LUN status */ status[0x1A] = 0x28; diff --git a/trunk/drivers/staging/rts5139/rts51x_chip.h b/trunk/drivers/staging/rts5139/rts51x_chip.h index 13fc2a410d90..6d395b6533a8 100644 --- a/trunk/drivers/staging/rts5139/rts51x_chip.h +++ b/trunk/drivers/staging/rts5139/rts51x_chip.h @@ -39,12 +39,7 @@ #define SUPPORT_CPRM #define SUPPORT_MAGIC_GATE #define SUPPORT_MSXC -/* #define LED_AUTO_BLINK */ - -/* { wwang, 2010-07-26 - * Add support for SD lock/unlock */ -/* #define SUPPORT_SD_LOCK */ -/* } wwang, 2010-07-26 */ +#define USING_POLLING_CYCLE_DELINK #ifdef SUPPORT_MAGIC_GA /* Using NORMAL_WRITE instead of AUTO_WRITE to set ICVTE */ @@ -63,7 +58,6 @@ #define SUPPORT_OCP #define MS_SPEEDUP -/* #define XD_SPEEDUP */ #define SD_XD_IO_FOLLOW_PWR @@ -81,7 +75,6 @@ #define MAX_ALLOWED_LUN_CNT 8 #define CMD_BUF_LEN 1024 -#define RSP_BUF_LEN 1024 #define POLLING_INTERVAL 50 /* 50ms */ #define XD_FREE_TABLE_CNT 1200 @@ -128,8 +121,6 @@ #endif #define STATUS_FAIL 1 -#define STATUS_READ_FAIL 2 -#define STATUS_WRITE_FAIL 3 #define STATUS_TIMEDOUT 4 #define STATUS_NOMEM 5 #define STATUS_TRANS_SHORT 6 @@ -139,8 +130,6 @@ #define IDLE_MAX_COUNT 10 #define POLLING_WAIT_CNT 1 -#define DELINK_DELAY 100 -#define LED_TOGGLE_INTERVAL 6 #define LED_GPIO 0 /* package */ @@ -157,8 +146,6 @@ #define TRANSPORT_GOOD 0 /* Transport good, command failed */ #define TRANSPORT_FAILED 1 -/* Command failed, no auto-sense */ -#define TRANSPORT_NO_SENSE 2 /* Transport bad (i.e. device dead) */ #define TRANSPORT_ERROR 3 @@ -195,7 +182,6 @@ struct trace_msg_t { #define SENSE_TYPE_MEDIA_INVALID_CMD_FIELD 6 #define SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR 7 #define SENSE_TYPE_MEDIA_WRITE_ERR 8 -#define SENSE_TYPE_FORMAT_IN_PROGRESS 9 #define SENSE_TYPE_FORMAT_CMD_FAILED 10 #ifdef SUPPORT_MAGIC_GATE /* COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT ESTABLISHED */ @@ -207,83 +193,27 @@ struct trace_msg_t { /* WRITE ERROR */ #define SENSE_TYPE_MG_WRITE_ERR 0x0e #endif -#ifdef SUPPORT_SD_LOCK -/* FOR Locked SD card */ -#define SENSE_TYPE_MEDIA_READ_FORBIDDEN 0x10 -#endif /*---- sense key ----*/ -#define ILI 0x20 /* ILI bit is on */ - -#define NO_SENSE 0x00 /* not exist sense key */ -#define RECOVER_ERR 0x01 /* Target/Logical unit is recoverd */ -#define NOT_READY 0x02 /* Logical unit is not ready */ -#define MEDIA_ERR 0x03 /* medium/data error */ -#define HARDWARE_ERR 0x04 /* hardware error */ #define ILGAL_REQ 0x05 /* CDB/parameter/identify msg error */ -#define UNIT_ATTENTION 0x06 /* unit attention condition occur */ -#define DAT_PRTCT 0x07 /* read/write is desable */ -#define BLNC_CHK 0x08 /* find blank/DOF in read */ - /* write to unblank area */ -#define CPY_ABRT 0x0a /* Copy/Compare/Copy&Verify illgal */ -#define ABRT_CMD 0x0b /* Target make the command in error */ -#define EQUAL 0x0c /* Search Data end with Equal */ -#define VLM_OVRFLW 0x0d /* Some data are left in buffer */ -#define MISCMP 0x0e /* find inequality */ /*----------------------------------- SENSE_DATA -----------------------------------*/ -/*---- valid ----*/ -#define SENSE_VALID 0x80 /* Sense data is valid as SCSI2 */ -#define SENSE_INVALID 0x00 /* Sense data is invalid as SCSI2 */ /*---- error code ----*/ #define CUR_ERR 0x70 /* current error */ -#define DEF_ERR 0x71 /* specific command error */ /*---- sense key Infomation ----*/ -#define SNSKEYINFO_LEN 3 /* length of sense key infomation */ #define SKSV 0x80 #define CDB_ILLEGAL 0x40 -#define DAT_ILLEGAL 0x00 -#define BPV 0x08 -#define BIT_ILLEGAL0 0 /* bit0 is illegal */ -#define BIT_ILLEGAL1 1 /* bit1 is illegal */ -#define BIT_ILLEGAL2 2 /* bit2 is illegal */ -#define BIT_ILLEGAL3 3 /* bit3 is illegal */ -#define BIT_ILLEGAL4 4 /* bit4 is illegal */ -#define BIT_ILLEGAL5 5 /* bit5 is illegal */ -#define BIT_ILLEGAL6 6 /* bit6 is illegal */ -#define BIT_ILLEGAL7 7 /* bit7 is illegal */ /*---- ASC ----*/ -#define ASC_NO_INFO 0x00 -#define ASC_MISCMP 0x1d #define ASC_INVLD_CDB 0x24 -#define ASC_INVLD_PARA 0x26 -#define ASC_LU_NOT_READY 0x04 -#define ASC_WRITE_ERR 0x0c -#define ASC_READ_ERR 0x11 -#define ASC_LOAD_EJCT_ERR 0x53 -#define ASC_MEDIA_NOT_PRESENT 0x3A -#define ASC_MEDIA_CHANGED 0x28 -#define ASC_MEDIA_IN_PROCESS 0x04 -#define ASC_WRITE_PROTECT 0x27 -#define ASC_LUN_NOT_SUPPORTED 0x25 /*---- ASQC ----*/ -#define ASCQ_NO_INFO 0x00 -#define ASCQ_MEDIA_IN_PROCESS 0x01 -#define ASCQ_MISCMP 0x00 #define ASCQ_INVLD_CDB 0x00 -#define ASCQ_INVLD_PARA 0x02 -#define ASCQ_LU_NOT_READY 0x02 -#define ASCQ_WRITE_ERR 0x02 -#define ASCQ_READ_ERR 0x00 -#define ASCQ_LOAD_EJCT_ERR 0x00 -#define ASCQ_WRITE_PROTECT 0x00 struct sense_data_t { unsigned char err_code; /* error code */ @@ -296,13 +226,13 @@ struct sense_data_t { unsigned char seg_no; /* segment No. */ unsigned char sense_key; /* byte5 : ILI */ /* bit3-0 : sense key */ - unsigned char info[4]; /* infomation */ + unsigned char info[4]; /* information */ unsigned char ad_sense_len; /* additional sense data length */ - unsigned char cmd_info[4]; /* command specific infomation */ + unsigned char cmd_info[4]; /* command specific information */ unsigned char asc; /* ASC */ unsigned char ascq; /* ASCQ */ unsigned char rfu; /* FRU */ - unsigned char sns_key_info[3]; /* sense key specific infomation */ + unsigned char sns_key_info[3]; /* sense key specific information */ }; /* sd_ctl bit map */ @@ -323,8 +253,6 @@ struct sense_data_t { #define SUPPORT_UHS50_MMC44 0x40 struct rts51x_option { - u8 led_blink_speed; - int mspro_formatter_enable; /* card clock expected by user for fpga platform */ @@ -368,8 +296,6 @@ struct rts51x_option { int ss_en; /* Interval to enter SS from IDLE state (second) */ int ss_delay; - int needs_remote_wakeup; - u8 ww_enable; /* sangdy2010-08-03:add for remote wakeup */ /* Enable SSC clock */ int ssc_en; @@ -392,10 +318,7 @@ struct rts51x_option { /*if reset or rw fail,then set SD20 pad drive again */ u8 reset_or_rw_fail_set_pad_drive; - u8 rcc_fail_flag; /* add to indicate whether rcc bug happen */ - u8 rcc_bug_fix_en; /* if set,then support fixing rcc bug */ u8 debounce_num; /* debounce number */ - int polling_time; /* polling delay time */ u8 led_toggle_interval; /* used to control led toggle speed */ int xd_rwn_step; u8 sd_send_status_en; @@ -405,7 +328,7 @@ struct rts51x_option { u8 ddr50_rx_phase; u8 sdr50_tx_phase; u8 sdr50_rx_phase; - /* used to enable select sdr50 tx phase according to proportion. */ + /* used to enable select sdr50 tx phase according to proportion. */ u8 sdr50_phase_sel; u8 ms_errreg_fix; u8 reset_mmc_first; @@ -614,11 +537,6 @@ struct sd_info { u8 sd_reset_fail; /* sangdy2010-07-01 */ u8 sd_send_status_en; -#ifdef SUPPORT_SD_LOCK - u8 sd_lock_status; - u8 sd_erase_status; - u8 sd_lock_notify; -#endif }; #define MODE_512_SEQ 0x01 @@ -720,9 +638,8 @@ struct rts51x_chip { struct scsi_cmnd *srb; struct sense_data_t sense_buffer[MAX_ALLOWED_LUN_CNT]; -#ifndef LED_AUTO_BLINK int led_toggle_counter; -#endif + int ss_counter; int idle_counter; int auto_delink_counter; diff --git a/trunk/drivers/staging/rts5139/rts51x_fop.c b/trunk/drivers/staging/rts5139/rts51x_fop.c index 6eaebb6223c9..ef893c8cdec6 100644 --- a/trunk/drivers/staging/rts5139/rts51x_fop.c +++ b/trunk/drivers/staging/rts5139/rts51x_fop.c @@ -234,12 +234,7 @@ ssize_t rts51x_write(struct file *filp, const char __user *buf, size_t count, return 0; } -#if 0 /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) */ -int rts51x_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) -#else long rts51x_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -#endif { struct rts51x_chip *chip; struct sd_direct_cmnd cmnd; diff --git a/trunk/drivers/staging/rts5139/rts51x_fop.h b/trunk/drivers/staging/rts5139/rts51x_fop.h index 94d75f08d255..eb45acf50d1a 100644 --- a/trunk/drivers/staging/rts5139/rts51x_fop.h +++ b/trunk/drivers/staging/rts5139/rts51x_fop.h @@ -50,12 +50,7 @@ ssize_t rts51x_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos); ssize_t rts51x_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos); -#if 0 /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) */ -int rts51x_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg); -#else long rts51x_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); -#endif #endif diff --git a/trunk/drivers/staging/rts5139/rts51x_scsi.c b/trunk/drivers/staging/rts5139/rts51x_scsi.c index 87c9cdc8bd29..e07a1f4f58cf 100644 --- a/trunk/drivers/staging/rts5139/rts51x_scsi.c +++ b/trunk/drivers/staging/rts5139/rts51x_scsi.c @@ -40,7 +40,6 @@ #include "rts51x_scsi.h" #include "rts51x_card.h" #include "rts51x_transport.h" -#include "rts51x_sys.h" #include "sd_cprm.h" #include "ms_mg.h" #include "trace.h" @@ -370,10 +369,6 @@ void set_sense_type(struct rts51x_chip *chip, unsigned int lun, int sense_type) ASC_INVLD_CDB, ASCQ_INVLD_CDB, CDB_ILLEGAL, 1); break; - case SENSE_TYPE_FORMAT_IN_PROGRESS: - set_sense_data(chip, lun, CUR_ERR, 0x02, 0, 0x04, 0x04, 0, 0); - break; - case SENSE_TYPE_FORMAT_CMD_FAILED: set_sense_data(chip, lun, CUR_ERR, 0x03, 0, 0x31, 0x01, 0, 0); break; @@ -396,12 +391,6 @@ void set_sense_type(struct rts51x_chip *chip, unsigned int lun, int sense_type) break; #endif -#ifdef SUPPORT_SD_LOCK - case SENSE_TYPE_MEDIA_READ_FORBIDDEN: - set_sense_data(chip, lun, CUR_ERR, 0x07, 0, 0x11, 0x13, 0, 0); - break; -#endif - case SENSE_TYPE_NO_SENSE: default: set_sense_data(chip, lun, CUR_ERR, 0, 0, 0, 0, 0, 0); @@ -448,20 +437,6 @@ static int test_unit_ready(struct scsi_cmnd *srb, struct rts51x_chip *chip) set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE); return TRANSPORT_FAILED; } -#ifdef SUPPORT_SD_LOCK - if (get_lun_card(chip, SCSI_LUN(srb)) == SD_CARD) { - struct sd_info *sd_card = &(chip->sd_card); - if (sd_card->sd_lock_notify) { - sd_card->sd_lock_notify = 0; - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE); - return TRANSPORT_FAILED; - } else if (sd_card->sd_lock_status & SD_LOCKED) { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_READ_FORBIDDEN); - return TRANSPORT_FAILED; - } - } -#endif return TRANSPORT_GOOD; } @@ -797,9 +772,6 @@ static int request_sense(struct scsi_cmnd *srb, struct rts51x_chip *chip) static int read_write(struct scsi_cmnd *srb, struct rts51x_chip *chip) { -#ifdef SUPPORT_SD_LOCK - struct sd_info *sd_card = &(chip->sd_card); -#endif unsigned int lun = SCSI_LUN(srb); int retval; u32 start_sec; @@ -819,25 +791,6 @@ static int read_write(struct scsi_cmnd *srb, struct rts51x_chip *chip) rts51x_prepare_run(chip); RTS51X_SET_STAT(chip, STAT_RUN); -#ifdef SUPPORT_SD_LOCK - if (sd_card->sd_erase_status) { - /* Accessing to any card is forbidden - * until the erase procedure of SD is completed */ - RTS51X_DEBUGP("SD card being erased!\n"); - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_READ_FORBIDDEN); - TRACE_RET(chip, TRANSPORT_FAILED); - } - - if (get_lun_card(chip, lun) == SD_CARD) { - if (sd_card->sd_lock_status & SD_LOCKED) { - RTS51X_DEBUGP("SD card locked!\n"); - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_READ_FORBIDDEN); - TRACE_RET(chip, TRANSPORT_FAILED); - } - } -#endif - if ((srb->cmnd[0] == READ_10) || (srb->cmnd[0] == WRITE_10)) { start_sec = ((u32) srb->cmnd[2] << 24) | @@ -883,20 +836,12 @@ static int read_write(struct scsi_cmnd *srb, struct rts51x_chip *chip) retval = card_rw(srb, chip, start_sec, sec_cnt); if (retval != STATUS_SUCCESS) { -#if 0 - if (chip->need_release & chip->lun2card[lun]) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - } else { -#endif if (srb->sc_data_direction == DMA_FROM_DEVICE) { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); } else { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR); } -#if 0 - } -#endif TRACE_RET(chip, TRANSPORT_FAILED); } @@ -1516,7 +1461,7 @@ static int ms_format_cmnd(struct scsi_cmnd *srb, struct rts51x_chip *chip) } #ifdef SUPPORT_PCGL_1P18 -int get_ms_information(struct scsi_cmnd *srb, struct rts51x_chip *chip) +static int get_ms_information(struct scsi_cmnd *srb, struct rts51x_chip *chip) { struct ms_info *ms_card = &(chip->ms_card); unsigned int lun = SCSI_LUN(srb); @@ -1677,7 +1622,7 @@ static int sd_extention_cmnd(struct scsi_cmnd *srb, struct rts51x_chip *chip) #endif #ifdef SUPPORT_MAGIC_GATE -int mg_report_key(struct scsi_cmnd *srb, struct rts51x_chip *chip) +static int mg_report_key(struct scsi_cmnd *srb, struct rts51x_chip *chip) { struct ms_info *ms_card = &(chip->ms_card); unsigned int lun = SCSI_LUN(srb); @@ -1764,7 +1709,7 @@ int mg_report_key(struct scsi_cmnd *srb, struct rts51x_chip *chip) return TRANSPORT_GOOD; } -int mg_send_key(struct scsi_cmnd *srb, struct rts51x_chip *chip) +static int mg_send_key(struct scsi_cmnd *srb, struct rts51x_chip *chip) { struct ms_info *ms_card = &(chip->ms_card); unsigned int lun = SCSI_LUN(srb); @@ -1871,30 +1816,10 @@ int mg_send_key(struct scsi_cmnd *srb, struct rts51x_chip *chip) int rts51x_scsi_handler(struct scsi_cmnd *srb, struct rts51x_chip *chip) { -#ifdef SUPPORT_SD_LOCK - struct sd_info *sd_card = &(chip->sd_card); -#endif struct ms_info *ms_card = &(chip->ms_card); unsigned int lun = SCSI_LUN(srb); int result = TRANSPORT_GOOD; -#ifdef SUPPORT_SD_LOCK - if (sd_card->sd_erase_status) { - /* Block all SCSI command except for REQUEST_SENSE - * and rs_ppstatus */ - if (! - ((srb->cmnd[0] == VENDOR_CMND) - && (srb->cmnd[1] == SCSI_APP_CMD) - && (srb->cmnd[2] == GET_DEV_STATUS)) - && (srb->cmnd[0] != REQUEST_SENSE)) { - /* Logical Unit Not Ready Format in Progress */ - set_sense_data(chip, lun, CUR_ERR, 0x02, 0, 0x04, 0x04, - 0, 0); - TRACE_RET(chip, TRANSPORT_FAILED); - } - } -#endif - if ((get_lun_card(chip, lun) == MS_CARD) && (ms_card->format_status == FORMAT_IN_PROGRESS)) { if ((srb->cmnd[0] != REQUEST_SENSE) @@ -1994,11 +1919,6 @@ int rts51x_scsi_handler(struct scsi_cmnd *srb, struct rts51x_chip *chip) * Host functions ***********************************************************************/ -const char *host_info(struct Scsi_Host *host) -{ - return "SCSI emulation for RTS51xx USB driver-based card reader"; -} - int slave_alloc(struct scsi_device *sdev) { /* @@ -2111,14 +2031,7 @@ int queuecommand_lck(struct scsi_cmnd *srb, void (*done) (struct scsi_cmnd *)) return 0; } -#if 0 /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) */ -int queuecommand(struct scsi_cmnd *srb, void (*done) (struct scsi_cmnd *)) -{ - return queuecommand_lck(srb, done); -} -#else DEF_SCSI_QCMD(queuecommand) -#endif /*********************************************************************** * Error handling functions ***********************************************************************/ diff --git a/trunk/drivers/staging/rts5139/rts51x_scsi.h b/trunk/drivers/staging/rts5139/rts51x_scsi.h index 3a8ca069b278..060d2c2e77ec 100644 --- a/trunk/drivers/staging/rts5139/rts51x_scsi.h +++ b/trunk/drivers/staging/rts5139/rts51x_scsi.h @@ -145,16 +145,11 @@ struct Scsi_Host; struct scsi_device; struct scsi_cmnd; -const char *host_info(struct Scsi_Host *host); int slave_alloc(struct scsi_device *sdev); int slave_configure(struct scsi_device *sdev); int proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int inout); -#if 0 /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) */ -int queuecommand(struct scsi_cmnd *srb, void (*done) (struct scsi_cmnd *)); -#else int queuecommand(struct Scsi_Host *, struct scsi_cmnd *); -#endif int command_abort(struct scsi_cmnd *srb); int device_reset(struct scsi_cmnd *srb); int bus_reset(struct scsi_cmnd *srb); diff --git a/trunk/drivers/staging/rts5139/rts51x_sys.h b/trunk/drivers/staging/rts5139/rts51x_sys.h deleted file mode 100644 index b09cd34a6c02..000000000000 --- a/trunk/drivers/staging/rts5139/rts51x_sys.h +++ /dev/null @@ -1,54 +0,0 @@ -/* Driver for Realtek USB RTS51xx card reader - * Header file - * - * Copyright(c) 2009 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 as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - * - * Author: - * wwang (wei_wang@realsil.com.cn) - * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China - * Maintainer: - * Edwin Rong (edwin_rong@realsil.com.cn) - * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China - */ - -#ifndef __RTS51X_SYS_H -#define __RTS51X_SYS_H - -#include "rts51x.h" -#include "rts51x_chip.h" -#include "rts51x_card.h" - -#define USING_POLLING_CYCLE_DELINK - -extern int rts51x_check_start_time(struct rts51x_chip *chip); -extern void rts51x_set_start_time(struct rts51x_chip *chip); -extern void rts51x_clear_start_time(struct rts51x_chip *chip); - -/* typedef dma_addr_t ULONG_PTR; */ - -static inline void rts51x_reset_detected_cards(struct rts51x_chip *chip) -{ -/* rts51x_reset_cards(chip); */ -} - -static inline void clear_first_install_mark(struct rts51x_chip *chip) -{ -} - -void rts51x_enter_ss(struct rts51x_chip *chip); -void rts51x_exit_ss(struct rts51x_chip *chip); - -#endif /* __RTS51X_SYS_H */ diff --git a/trunk/drivers/staging/rts5139/rts51x_transport.c b/trunk/drivers/staging/rts5139/rts51x_transport.c index da9c83b49426..89e4d805a345 100644 --- a/trunk/drivers/staging/rts5139/rts51x_transport.c +++ b/trunk/drivers/staging/rts5139/rts51x_transport.c @@ -120,7 +120,7 @@ unsigned int rts51x_access_sglist(unsigned char *buffer, return cnt; } -unsigned int rts51x_access_xfer_buf(unsigned char *buffer, +static unsigned int rts51x_access_xfer_buf(unsigned char *buffer, unsigned int buflen, struct scsi_cmnd *srb, struct scatterlist **sgptr, unsigned int *offset, enum xfer_buf_dir dir) @@ -252,6 +252,8 @@ static int rts51x_msg_common(struct rts51x_chip *chip, struct urb *urb, return status; } +static int rts51x_clear_halt(struct rts51x_chip *chip, unsigned int pipe); + /* * Interpret the results of a URB transfer */ @@ -359,7 +361,7 @@ int rts51x_ctrl_transfer(struct rts51x_chip *chip, unsigned int pipe, rts51x->current_urb->actual_length); } -int rts51x_clear_halt(struct rts51x_chip *chip, unsigned int pipe) +static int rts51x_clear_halt(struct rts51x_chip *chip, unsigned int pipe) { int result; int endp = usb_pipeendpoint(pipe); @@ -378,11 +380,6 @@ int rts51x_clear_halt(struct rts51x_chip *chip, unsigned int pipe) return STATUS_SUCCESS; } -int rts51x_reset_pipe(struct rts51x_chip *chip, char pipe) -{ - return rts51x_clear_halt(chip, pipe); -} - static void rts51x_sg_clean(struct usb_sg_request *io) { if (io->urbs) { @@ -391,226 +388,17 @@ static void rts51x_sg_clean(struct usb_sg_request *io) kfree(io->urbs); io->urbs = NULL; } -#if 0 /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) */ - if (io->dev->dev.dma_mask != NULL) - usb_buffer_unmap_sg(io->dev, usb_pipein(io->pipe), - io->sg, io->nents); -#endif io->dev = NULL; } -#if 0 -static void rts51x_sg_complete(struct urb *urb) -{ - struct usb_sg_request *io = urb->context; - int status = urb->status; - - spin_lock(&io->lock); - - /* In 2.5 we require hcds' endpoint queues not to progress after fault - * reports, until the completion callback (this!) returns. That lets - * device driver code (like this routine) unlink queued urbs first, - * if it needs to, since the HC won't work on them at all. So it's - * not possible for page N+1 to overwrite page N, and so on. - * - * That's only for "hard" faults; "soft" faults (unlinks) sometimes - * complete before the HCD can get requests away from hardware, - * though never during cleanup after a hard fault. - */ - if (io->status - && (io->status != -ECONNRESET - || status != -ECONNRESET) - && urb->actual_length) { - dev_err(io->dev->bus->controller, - "dev %s ep%d%s scatterlist error %d/%d\n", - io->dev->devpath, - usb_endpoint_num(&urb->ep->desc), - usb_urb_dir_in(urb) ? "in" : "out", - status, io->status); - /* BUG (); */ - } - - if (io->status == 0 && status && status != -ECONNRESET) { - int i, found, retval; - - io->status = status; - - /* the previous urbs, and this one, completed already. - * unlink pending urbs so they won't rx/tx bad data. - * careful: unlink can sometimes be synchronous... - */ - spin_unlock(&io->lock); - for (i = 0, found = 0; i < io->entries; i++) { - if (!io->urbs[i] || !io->urbs[i]->dev) - continue; - if (found) { - retval = usb_unlink_urb(io->urbs[i]); - if (retval != -EINPROGRESS && - retval != -ENODEV && - retval != -EBUSY) - dev_err(&io->dev->dev, - "%s, unlink --> %d\n", - __func__, retval); - } else if (urb == io->urbs[i]) - found = 1; - } - spin_lock(&io->lock); - } - urb->dev = NULL; - - /* on the last completion, signal usb_sg_wait() */ - io->bytes += urb->actual_length; - io->count--; - if (!io->count) - complete(&io->complete); - - spin_unlock(&io->lock); -} - -/* This function is ported from usb_sg_init, which can transfer - * sg list partially */ -int rts51x_sg_init_partial(struct usb_sg_request *io, struct usb_device *dev, - unsigned pipe, unsigned period, void *buf, struct scatterlist **sgptr, - unsigned int *offset, int nents, size_t length, gfp_t mem_flags) -{ - int i; - int urb_flags; - int dma; - struct scatterlist *sg = *sgptr, *first_sg; - - first_sg = (struct scatterlist *)buf; - if (!sg) - sg = first_sg; - - if (!io || !dev || !sg - || usb_pipecontrol(pipe) - || usb_pipeisoc(pipe) - || (nents <= 0)) - return -EINVAL; - - spin_lock_init(&io->lock); - io->dev = dev; - io->pipe = pipe; - io->sg = first_sg; /* used by unmap */ - io->nents = nents; - - RTS51X_DEBUGP("Before map, sg address: 0x%x\n", (unsigned int)sg); - RTS51X_DEBUGP("Before map, dev address: 0x%x\n", (unsigned int)dev); - - /* not all host controllers use DMA (like the mainstream pci ones); - * they can use PIO (sl811) or be software over another transport. - */ - dma = (dev->dev.dma_mask != NULL); - if (dma) { - /* map the whole sg list, because here we only know the - * total nents */ - io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe), - first_sg, nents); - } else { - io->entries = nents; - } - - /* initialize all the urbs we'll use */ - if (io->entries <= 0) - return io->entries; - - io->urbs = kmalloc(io->entries * sizeof *io->urbs, mem_flags); - if (!io->urbs) - goto nomem; - - urb_flags = URB_NO_INTERRUPT; - if (dma) - urb_flags |= URB_NO_TRANSFER_DMA_MAP; - if (usb_pipein(pipe)) - urb_flags |= URB_SHORT_NOT_OK; - - RTS51X_DEBUGP("io->entries = %d\n", io->entries); - - for (i = 0; (sg != NULL) && (length > 0); i++) { - unsigned len; - - RTS51X_DEBUGP("sg address: 0x%x\n", (unsigned int)sg); - RTS51X_DEBUGP("length = %d, *offset = %d\n", length, *offset); - - io->urbs[i] = usb_alloc_urb(0, mem_flags); - if (!io->urbs[i]) { - io->entries = i; - goto nomem; - } - - io->urbs[i]->dev = NULL; - io->urbs[i]->pipe = pipe; - io->urbs[i]->interval = period; - io->urbs[i]->transfer_flags = urb_flags; - - io->urbs[i]->complete = rts51x_sg_complete; - io->urbs[i]->context = io; - - if (dma) { - io->urbs[i]->transfer_dma = - sg_dma_address(sg) + *offset; - len = sg_dma_len(sg) - *offset; - io->urbs[i]->transfer_buffer = NULL; - RTS51X_DEBUGP(" -- sg entry dma length = %d\n", - sg_dma_len(sg)); - } else { - /* hc may use _only_ transfer_buffer */ - io->urbs[i]->transfer_buffer = sg_virt(sg) + *offset; - len = sg->length - *offset; - RTS51X_DEBUGP(" -- sg entry length = %d\n", - sg->length); - } - - if (length >= len) { - *offset = 0; - io->urbs[i]->transfer_buffer_length = len; - length -= len; - sg = sg_next(sg); - } else { - *offset += length; - io->urbs[i]->transfer_buffer_length = length; - length = 0; - } - if (length == 0) - io->entries = i + 1; -#if 0 - if (length) { - len = min_t(unsigned, len, length); - length -= len; - if (length == 0) { - io->entries = i + 1; - *offset += len; - } else { - *offset = 0; - } - } -#endif - } - RTS51X_DEBUGP("In %s, urb count: %d\n", __func__, i); - io->urbs[--i]->transfer_flags &= ~URB_NO_INTERRUPT; - - RTS51X_DEBUGP("sg address stored in sgptr: 0x%x\n", (unsigned int)sg); - *sgptr = sg; - - /* transaction state */ - io->count = io->entries; - io->status = 0; - io->bytes = 0; - init_completion(&io->complete); - return 0; -nomem: - rts51x_sg_clean(io); - return -ENOMEM; -} -#endif -int rts51x_sg_init(struct usb_sg_request *io, struct usb_device *dev, +static int rts51x_sg_init(struct usb_sg_request *io, struct usb_device *dev, unsigned pipe, unsigned period, struct scatterlist *sg, int nents, size_t length, gfp_t mem_flags) { return usb_sg_init(io, dev, pipe, period, sg, nents, length, mem_flags); } -int rts51x_sg_wait(struct usb_sg_request *io, int timeout) +static int rts51x_sg_wait(struct usb_sg_request *io, int timeout) { long timeleft; int i; @@ -630,7 +418,7 @@ int rts51x_sg_wait(struct usb_sg_request *io, int timeout) */ spin_unlock_irq(&io->lock); switch (retval) { - /* maybe we retrying will recover */ + /* maybe the retry will recover */ case -ENXIO: /* hc didn't queue this one */ case -EAGAIN: case -ENOMEM: @@ -740,56 +528,9 @@ static int rts51x_bulk_transfer_sglist(struct rts51x_chip *chip, return interpret_urb_result(chip, pipe, length, result, chip->usb->current_sg.bytes); } -#if 0 -static int rts51x_bulk_transfer_sglist_partial(struct rts51x_chip *chip, - unsigned int pipe, void *buf, struct scatterlist **sgptr, - unsigned int *offset, int num_sg, unsigned int length, - unsigned int *act_len, int timeout) -{ - int result; - - /* don't submit s-g requests during abort processing */ - if (test_bit(FLIDX_ABORTING, &chip->usb->dflags)) - TRACE_RET(chip, STATUS_ERROR); - /* initialize the scatter-gather request block */ - RTS51X_DEBUGP("%s: xfer %u bytes, %d entries\n", __func__, - length, num_sg); - result = rts51x_sg_init_partial(&chip->usb->current_sg, - chip->usb->pusb_dev, pipe, 0, buf, sgptr, offset, - num_sg, length, GFP_NOIO); - if (result) { - RTS51X_DEBUGP("rts51x_sg_init_partial returned %d\n", result); - TRACE_RET(chip, STATUS_ERROR); - } - - /* since the block has been initialized successfully, it's now - * okay to cancel it */ - set_bit(FLIDX_SG_ACTIVE, &chip->usb->dflags); - - /* did an abort occur during the submission? */ - if (test_bit(FLIDX_ABORTING, &chip->usb->dflags)) { - - /* cancel the request, if it hasn't been cancelled already */ - if (test_and_clear_bit(FLIDX_SG_ACTIVE, &chip->usb->dflags)) { - RTS51X_DEBUGP("-- cancelling sg request\n"); - usb_sg_cancel(&chip->usb->current_sg); - } - } - - /* wait for the completion of the transfer */ - result = rts51x_sg_wait(&chip->usb->current_sg, timeout); - - clear_bit(FLIDX_SG_ACTIVE, &chip->usb->dflags); - - /* result = us->current_sg.status; */ - if (act_len) - *act_len = chip->usb->current_sg.bytes; - return interpret_urb_result(chip, pipe, length, result, - chip->usb->current_sg.bytes); -} -#endif -int rts51x_bulk_transfer_buf(struct rts51x_chip *chip, unsigned int pipe, +static int rts51x_bulk_transfer_buf(struct rts51x_chip *chip, + unsigned int pipe, void *buf, unsigned int length, unsigned int *act_len, int timeout) { @@ -860,11 +601,6 @@ int rts51x_transfer_data_partial(struct rts51x_chip *chip, unsigned int pipe, } kfree(tmp_buf); -#if 0 - result = rts51x_bulk_transfer_sglist_partial(chip, pipe, buf, - (struct scatterlist **)ptr, offset, - use_sg, len, act_len, timeout); -#endif } else { unsigned int step = 0; if (offset) diff --git a/trunk/drivers/staging/rts5139/rts51x_transport.h b/trunk/drivers/staging/rts5139/rts51x_transport.h index 9dd556ea9c08..024f115540a6 100644 --- a/trunk/drivers/staging/rts5139/rts51x_transport.h +++ b/trunk/drivers/staging/rts5139/rts51x_transport.h @@ -40,11 +40,6 @@ unsigned int rts51x_access_sglist(unsigned char *buffer, unsigned int buflen, void *sglist, void **sgptr, unsigned int *offset, enum xfer_buf_dir dir); -unsigned int rts51x_access_xfer_buf(unsigned char *buffer, unsigned int buflen, - struct scsi_cmnd *srb, - struct scatterlist **sgptr, - unsigned int *offset, - enum xfer_buf_dir dir); void rts51x_set_xfer_buf(unsigned char *buffer, unsigned int buflen, struct scsi_cmnd *srb); void rts51x_get_xfer_buf(unsigned char *buffer, unsigned int buflen, @@ -53,7 +48,6 @@ void rts51x_get_xfer_buf(unsigned char *buffer, unsigned int buflen, int rts51x_ctrl_transfer(struct rts51x_chip *chip, unsigned int pipe, u8 request, u8 requesttype, u16 value, u16 index, void *data, u16 size, int timeout); -int rts51x_clear_halt(struct rts51x_chip *chip, unsigned int pipe); int rts51x_transfer_data(struct rts51x_chip *chip, unsigned int pipe, void *buf, unsigned int len, int use_sg, unsigned int *act_len, int timeout); @@ -62,12 +56,6 @@ int rts51x_transfer_data_partial(struct rts51x_chip *chip, unsigned int pipe, unsigned int len, int use_sg, unsigned int *act_len, int timeout); -/* whichPipe: - * 0: bulk in pipe - * 1: bulk out pipe - * 2: intr in pipe */ -int rts51x_reset_pipe(struct rts51x_chip *chip, char pipe); - #ifndef POLLING_IN_THREAD int rts51x_start_epc_transfer(struct rts51x_chip *chip); void rts51x_cancel_epc_transfer(struct rts51x_chip *chip); diff --git a/trunk/drivers/staging/rts5139/sd.c b/trunk/drivers/staging/rts5139/sd.c index d5dd2f926d1d..b739f26f78cc 100644 --- a/trunk/drivers/staging/rts5139/sd.c +++ b/trunk/drivers/staging/rts5139/sd.c @@ -246,12 +246,7 @@ static int sd_send_cmd_get_rsp(struct rts51x_chip *chip, u8 cmd_idx, if (buf[1] & 0x80) TRACE_RET(chip, STATUS_FAIL); } -#ifdef SUPPORT_SD_LOCK - /* exclude bit25 CARD_IS_LOCKED */ - if (buf[1] & 0x7D) { -#else if (buf[1] & 0x7F) { -#endif RTS51X_DEBUGP("buf[1]: 0x%02x\n", buf[1]); TRACE_RET(chip, STATUS_FAIL); } @@ -709,37 +704,7 @@ int sd_select_card(struct rts51x_chip *chip, int select) return STATUS_SUCCESS; } -#ifdef SUPPORT_SD_LOCK -int sd_update_lock_status(struct rts51x_chip *chip) -{ - struct sd_info *sd_card = &(chip->sd_card); - int retval; - u8 rsp[5]; - - retval = - sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr, - SD_RSP_TYPE_R1, rsp, 5); - if (retval != STATUS_SUCCESS) - TRACE_RET(chip, STATUS_FAIL); - - if (rsp[1] & 0x02) - sd_card->sd_lock_status |= SD_LOCKED; - else - sd_card->sd_lock_status &= ~SD_LOCKED; - - RTS51X_DEBUGP("sd_card->sd_lock_status = 0x%x\n", - sd_card->sd_lock_status); - - if (rsp[1] & 0x01) { - /* LOCK_UNLOCK_FAILED */ - TRACE_RET(chip, STATUS_FAIL); - } - - return STATUS_SUCCESS; -} -#endif - -int sd_wait_currentstate_dataready(struct rts51x_chip *chip, u8 statechk, +static int sd_wait_currentstate_dataready(struct rts51x_chip *chip, u8 statechk, u8 rdychk, u16 pollingcnt) { struct sd_info *sd_card = &(chip->sd_card); @@ -1197,15 +1162,6 @@ static int sd_switch_function(struct rts51x_chip *chip, u8 bus_width) RTS51X_DEBUGP("SD_FUNC_GROUP_1: func_to_switch = 0x%02x", func_to_switch); -#ifdef SUPPORT_SD_LOCK - if ((sd_card->sd_lock_status & SD_SDR_RST) - && (DDR50_SUPPORT == func_to_switch) - && (sd_card->func_group1_mask & SDR50_SUPPORT_MASK)) { - func_to_switch = SDR50_SUPPORT; - RTS51X_DEBUGP("Using SDR50 instead of DDR50 for SD Lock\n"); - } -#endif - if (func_to_switch) { retval = sd_check_switch(chip, SD_FUNC_GROUP_1, func_to_switch, @@ -1562,7 +1518,7 @@ static u8 sd_search_final_phase(struct rts51x_chip *chip, u32 phase_map, } Search_Finish: - RTS51X_DEBUGP("Final choosen phase: %d\n", final_phase); + RTS51X_DEBUGP("Final chosen phase: %d\n", final_phase); return final_phase; } @@ -2024,10 +1980,6 @@ int reset_sd(struct rts51x_chip *chip) k = 0; hi_cap_flow = 0; support_1v8 = 0; -#ifdef SUPPORT_SD_LOCK - if (sd_card->sd_lock_status & SD_UNLOCK_POW_ON) - goto SD_UNLOCK_ENTRY; -#endif retval = sd_prepare_reset(chip); if (retval != STATUS_SUCCESS) @@ -2182,7 +2134,7 @@ int reset_sd(struct rts51x_chip *chip) sd_card->sd_addr += (u32) rsp[2] << 16; /* Get CSD register for Calculating Timing,Capacity, - * Check CSD to determaine as if this is the SD ROM card */ + * Check CSD to determine as if this is the SD ROM card */ retval = sd_check_csd(chip, 1); if (retval != STATUS_SUCCESS) TRACE_RET(chip, retval); @@ -2190,20 +2142,6 @@ int reset_sd(struct rts51x_chip *chip) retval = sd_select_card(chip, 1); if (retval != STATUS_SUCCESS) TRACE_RET(chip, retval); -#ifdef SUPPORT_SD_LOCK -SD_UNLOCK_ENTRY: - /* Get SD lock status */ - retval = sd_update_lock_status(chip); - if (retval != STATUS_SUCCESS) - TRACE_RET(chip, STATUS_FAIL); - - if (sd_card->sd_lock_status & SD_LOCKED) { - sd_card->sd_lock_status |= (SD_LOCK_1BIT_MODE | SD_PWD_EXIST); - return STATUS_SUCCESS; - } else if (!(sd_card->sd_lock_status & SD_UNLOCK_POW_ON)) { - sd_card->sd_lock_status &= ~SD_PWD_EXIST; - } -#endif /* ACMD42 */ retval = @@ -2294,10 +2232,6 @@ int reset_sd(struct rts51x_chip *chip) if (retval != STATUS_SUCCESS) TRACE_RET(chip, retval); } -#ifdef SUPPORT_SD_LOCK - /* clear 1 bit mode status */ - sd_card->sd_lock_status &= ~SD_LOCK_1BIT_MODE; -#endif if (CHK_SD30_SPEED(sd_card)) { rts51x_write_register(chip, SD30_DRIVE_SEL, SD30_DRIVE_MASK, @@ -2380,19 +2314,6 @@ int reset_sd(struct rts51x_chip *chip) chip->card_bus_width[chip->card2lun[SD_CARD]] = 4; -#ifdef SUPPORT_SD_LOCK - if (sd_card->sd_lock_status & SD_UNLOCK_POW_ON) { - rts51x_init_cmd(chip); - - rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0x02); - rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 0x00); - - retval = rts51x_send_cmd(chip, MODE_C, 100); - if (retval != STATUS_SUCCESS) - TRACE_RET(chip, retval); - } -#endif - return STATUS_SUCCESS; } @@ -2587,17 +2508,10 @@ static int mmc_switch_timing_bus(struct rts51x_chip *chip) sd_card->capacity = ((u32) buf[5] << 24) | ((u32) buf[4] << 16) | ((u32) buf[3] << 8) | ((u32) buf[2]); -#ifdef SUPPORT_SD_LOCK - if (!(sd_card->sd_lock_status & SD_SDR_RST) && CHECK_UHS50(chip)) - card_type_mask = 0x07; - else - card_type_mask = 0x03; -#else if (CHECK_UHS50(chip)) card_type_mask = 0x07; else card_type_mask = 0x03; -#endif card_type = buf[1] & card_type_mask; if (card_type) { @@ -2626,15 +2540,9 @@ static int mmc_switch_timing_bus(struct rts51x_chip *chip) if (mmc_test_switch_bus(chip, MMC_8BIT_BUS) == STATUS_SUCCESS) { SET_MMC_8BIT(sd_card); chip->card_bus_width[chip->card2lun[SD_CARD]] = 8; -#ifdef SUPPORT_SD_LOCK - sd_card->sd_lock_status &= ~SD_LOCK_1BIT_MODE; -#endif } else if (mmc_test_switch_bus(chip, MMC_4BIT_BUS) == STATUS_SUCCESS) { SET_MMC_4BIT(sd_card); chip->card_bus_width[chip->card2lun[SD_CARD]] = 4; -#ifdef SUPPORT_SD_LOCK - sd_card->sd_lock_status &= ~SD_LOCK_1BIT_MODE; -#endif } else { CLR_MMC_8BIT(sd_card); CLR_MMC_4BIT(sd_card); @@ -2652,11 +2560,6 @@ static int reset_mmc(struct rts51x_chip *chip) u8 change_to_ddr52 = 1; u8 cmd[5]; -#ifdef SUPPORT_SD_LOCK - if (sd_card->sd_lock_status & SD_UNLOCK_POW_ON) - goto MMC_UNLOCK_ENTRY; -#endif - MMC_DDR_FAIL: retval = sd_prepare_reset(chip); @@ -2745,7 +2648,7 @@ static int reset_mmc(struct rts51x_chip *chip) TRACE_RET(chip, retval); /* Get CSD register for Calculating Timing,Capacity - * Check CSD to determaine as if this is the SD ROM card */ + * Check CSD to determine as if this is the SD ROM card */ retval = sd_check_csd(chip, 1); if (retval != STATUS_SUCCESS) TRACE_RET(chip, retval); @@ -2763,13 +2666,6 @@ static int reset_mmc(struct rts51x_chip *chip) 0); if (retval != STATUS_SUCCESS) TRACE_RET(chip, retval); -#ifdef SUPPORT_SD_LOCK -MMC_UNLOCK_ENTRY: - /* Get SD lock status */ - retval = sd_update_lock_status(chip); - if (retval != STATUS_SUCCESS) - TRACE_RET(chip, STATUS_FAIL); -#endif RTS51X_WRITE_REG(chip, SD_CFG1, SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_0); @@ -2842,18 +2738,6 @@ static int reset_mmc(struct rts51x_chip *chip) } } } -#ifdef SUPPORT_SD_LOCK - if (sd_card->sd_lock_status & SD_UNLOCK_POW_ON) { - rts51x_init_cmd(chip); - - rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0x02); - rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 0x00); - - retval = rts51x_send_cmd(chip, MODE_C, 100); - if (retval != STATUS_SUCCESS) - TRACE_RET(chip, retval); - } -#endif retval = rts51x_get_card_status(chip, &(chip->card_status)); if (retval != STATUS_SUCCESS) @@ -2879,11 +2763,6 @@ int reset_sd_card(struct rts51x_chip *chip) sd_card->capacity = 0; sd_card->sd_switch_fail = 0; -#ifdef SUPPORT_SD_LOCK - sd_card->sd_lock_status = 0; - sd_card->sd_erase_status = 0; -#endif - sd_clear_reset_fail(chip); enable_card_clock(chip, SD_CARD); @@ -3006,7 +2885,7 @@ static int wait_data_buf_ready(struct rts51x_chip *chip) TRACE_RET(chip, STATUS_FAIL); } -void sd_stop_seq_mode(struct rts51x_chip *chip) +static void sd_stop_seq_mode(struct rts51x_chip *chip) { struct sd_info *sd_card = &(chip->sd_card); int retval; @@ -3300,7 +3179,7 @@ void sd_cleanup_work(struct rts51x_chip *chip) } } -inline void sd_fill_power_off_card3v3(struct rts51x_chip *chip) +static inline void sd_fill_power_off_card3v3(struct rts51x_chip *chip) { rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_CLK_EN, SD_CLK_EN, 0); @@ -3322,7 +3201,7 @@ inline void sd_fill_power_off_card3v3(struct rts51x_chip *chip) } } -int sd_power_off_card3v3(struct rts51x_chip *chip) +static int sd_power_off_card3v3(struct rts51x_chip *chip) { int retval; @@ -3346,17 +3225,12 @@ int release_sd_card(struct rts51x_chip *chip) struct sd_info *sd_card = &(chip->sd_card); int retval; - RTS51X_DEBUGP("elease_sd_card\n"); + RTS51X_DEBUGP("release_sd_card\n"); chip->card_ready &= ~SD_CARD; chip->card_fail &= ~SD_CARD; chip->card_wp &= ~SD_CARD; -#ifdef SUPPORT_SD_LOCK - sd_card->sd_lock_status = 0; - sd_card->sd_erase_status = 0; -#endif - memset(sd_card->raw_csd, 0, 16); memset(sd_card->raw_scr, 0, 8); diff --git a/trunk/drivers/staging/rts5139/sd.h b/trunk/drivers/staging/rts5139/sd.h index 0805edcaea86..de155d8e682d 100644 --- a/trunk/drivers/staging/rts5139/sd.h +++ b/trunk/drivers/staging/rts5139/sd.h @@ -141,29 +141,6 @@ #define SWITCH_MODE_ERR 0x06 #define SWITCH_PASS 0x07 -#ifdef SUPPORT_SD_LOCK -/* CMD42 Parameter */ -#define SD_ERASE 0x08 -#define SD_LOCK 0x04 -#define SD_UNLOCK 0x00 -#define SD_CLR_PWD 0x02 -#define SD_SET_PWD 0x01 - -#define SD_PWD_LEN 0x10 - -/* SD lock unlock Status */ -#define SD_LOCKED 0x80 /* Global lock status */ -#define SD_LOCK_1BIT_MODE 0x40 /**/ -#define SD_PWD_EXIST 0x20 -#define SD_UNLOCK_POW_ON 0x01 /**/ -#define SD_SDR_RST 0x02 /* Reset SD30 card with current DDR mode to SDR mode. */ -/* g_bySDEraseStatus */ -#define SD_NOT_ERASE 0x00 -#define SD_UNDER_ERASING 0x01 -#define SD_COMPLETE_ERASE 0x02 -/* SD_RW FAIL status */ -#define SD_RW_FORBIDDEN 0x0F /* read/write is forbidden (SD card) */ -#endif /* Function Group Definition */ /* Function Group 1 */ #define HS_SUPPORT 0x01 @@ -282,17 +259,11 @@ struct timing_phase_path { int sd_select_card(struct rts51x_chip *chip, int select); int reset_sd_card(struct rts51x_chip *chip); int sd_switch_clock(struct rts51x_chip *chip); -void sd_stop_seq_mode(struct rts51x_chip *chip); int sd_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 start_sector, u16 sector_cnt); void sd_cleanup_work(struct rts51x_chip *chip); -int sd_power_off_card3v3(struct rts51x_chip *chip); int release_sd_card(struct rts51x_chip *chip); -#ifdef SUPPORT_SD_LOCK -int sd_update_lock_status(struct rts51x_chip *chip); -#endif - #ifdef SUPPORT_CPRM extern int reset_sd(struct rts51x_chip *chip); extern int sd_check_data0_status(struct rts51x_chip *chip); diff --git a/trunk/drivers/staging/rts5139/sd_cprm.c b/trunk/drivers/staging/rts5139/sd_cprm.c index d5969d992d84..f8c60711f710 100644 --- a/trunk/drivers/staging/rts5139/sd_cprm.c +++ b/trunk/drivers/staging/rts5139/sd_cprm.c @@ -77,12 +77,7 @@ static inline int get_rsp_type(u8 rsp_code, u8 *rsp_type, int *rsp_len) return STATUS_SUCCESS; } -int soft_reset_sd_card(struct rts51x_chip *chip) -{ - return reset_sd(chip); -} - -int ext_sd_send_cmd_get_rsp(struct rts51x_chip *chip, u8 cmd_idx, +static int ext_sd_send_cmd_get_rsp(struct rts51x_chip *chip, u8 cmd_idx, u32 arg, u8 rsp_type, u8 *rsp, int rsp_len, int special_check) { @@ -206,11 +201,7 @@ int ext_sd_send_cmd_get_rsp(struct rts51x_chip *chip, u8 cmd_idx, if (buf[1] & 0x80) TRACE_RET(chip, STATUS_FAIL); } -#ifdef SUPPORT_SD_LOCK - if (buf[1] & 0x7D) { -#else if (buf[1] & 0x7F) { -#endif TRACE_RET(chip, STATUS_FAIL); } if (buf[2] & 0xF8) @@ -233,7 +224,7 @@ int ext_sd_send_cmd_get_rsp(struct rts51x_chip *chip, u8 cmd_idx, return STATUS_SUCCESS; } -int ext_sd_get_rsp(struct rts51x_chip *chip, int len, u8 *rsp, u8 rsp_type) +static int ext_sd_get_rsp(struct rts51x_chip *chip, int len, u8 *rsp, u8 rsp_type) { int retval, rsp_len; u16 reg_addr; @@ -305,26 +296,8 @@ int ext_sd_execute_no_data(struct rts51x_chip *chip, unsigned int lun, retval = sd_switch_clock(chip); if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); -#ifdef SUPPORT_SD_LOCK - if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) { - if (CHK_MMC_8BIT(sd_card)) { - retval = - rts51x_write_register(chip, SD_CFG1, 0x03, - SD_BUS_WIDTH_8); - if (retval != STATUS_SUCCESS) - TRACE_RET(chip, TRANSPORT_FAILED); - } else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card)) { - retval = - rts51x_write_register(chip, SD_CFG1, 0x03, - SD_BUS_WIDTH_4); - if (retval != STATUS_SUCCESS) - TRACE_RET(chip, TRANSPORT_FAILED); - } - } -#else /* Set H/W SD/MMC Bus Width */ rts51x_write_register(chip, SD_CFG1, 0x03, SD_BUS_WIDTH_4); -#endif if (standby) { retval = sd_select_card(chip, 0); @@ -350,12 +323,6 @@ int ext_sd_execute_no_data(struct rts51x_chip *chip, unsigned int lun, if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Cmd_Failed); } -#ifdef SUPPORT_SD_LOCK - /* Get SD lock status */ - retval = sd_update_lock_status(chip); - if (retval != STATUS_SUCCESS) - TRACE_GOTO(chip, SD_Execute_Cmd_Failed); -#endif return TRANSPORT_GOOD; @@ -399,21 +366,7 @@ int ext_sd_execute_read_data(struct rts51x_chip *chip, unsigned int lun, retval = sd_switch_clock(chip); if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); -#ifdef SUPPORT_SD_LOCK - if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) { - if (CHK_MMC_8BIT(sd_card)) - bus_width = SD_BUS_WIDTH_8; - else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card)) - bus_width = SD_BUS_WIDTH_4; - else - bus_width = SD_BUS_WIDTH_1; - } else { - bus_width = SD_BUS_WIDTH_4; - } - RTS51X_DEBUGP("bus_width = %d\n", bus_width); -#else bus_width = SD_BUS_WIDTH_4; -#endif if (data_len < 512) { retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, data_len, @@ -599,11 +552,6 @@ int ext_sd_execute_write_data(struct rts51x_chip *chip, unsigned int lun, int cmd13_checkbit = 0, write_err = 0; u8 rsp_type; u32 i; -#ifdef SUPPORT_SD_LOCK - int lock_cmd_fail = 0; - u8 sd_lock_state = 0; - u8 lock_cmd_type = 0; -#endif if (sd_card->pre_cmd_err) { sd_card->pre_cmd_err = 0; @@ -614,12 +562,6 @@ int ext_sd_execute_write_data(struct rts51x_chip *chip, unsigned int lun, retval = sd_switch_clock(chip); if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); -#ifdef SUPPORT_SD_LOCK - if (cmd_idx == LOCK_UNLOCK) { - sd_lock_state = sd_card->sd_lock_status; - sd_lock_state &= SD_LOCKED; - } -#endif retval = get_rsp_type(rsp_code, &rsp_type, &rsp_len); if (retval != STATUS_SUCCESS) { @@ -631,25 +573,7 @@ int ext_sd_execute_write_data(struct rts51x_chip *chip, unsigned int lun, retval = sd_switch_clock(chip); if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); -#ifdef SUPPORT_SD_LOCK - if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) { - if (CHK_MMC_8BIT(sd_card)) { - retval = - rts51x_write_register(chip, SD_CFG1, 0x03, - SD_BUS_WIDTH_8); - if (retval != STATUS_SUCCESS) - TRACE_RET(chip, TRANSPORT_FAILED); - } else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card)) { - retval = - rts51x_write_register(chip, SD_CFG1, 0x03, - SD_BUS_WIDTH_4); - if (retval != STATUS_SUCCESS) - TRACE_RET(chip, TRANSPORT_FAILED); - } - } -#else rts51x_write_register(chip, SD_CFG1, 0x03, SD_BUS_WIDTH_4); -#endif if (data_len < 512) { retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, data_len, @@ -692,10 +616,6 @@ int ext_sd_execute_write_data(struct rts51x_chip *chip, unsigned int lun, else memcpy(buf, data_buf, data_len); -#ifdef SUPPORT_SD_LOCK - if (cmd_idx == LOCK_UNLOCK) - lock_cmd_type = buf[0] & 0x0F; -#endif if (data_len > 256) { rts51x_init_cmd(chip); @@ -802,29 +722,6 @@ int ext_sd_execute_write_data(struct rts51x_chip *chip, unsigned int lun, SD_STOP | SD_CLR_ERR); TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); } -#ifdef SUPPORT_SD_LOCK - if (cmd_idx == LOCK_UNLOCK) { - if (lock_cmd_type == SD_ERASE) { - sd_card->sd_erase_status = SD_UNDER_ERASING; - scsi_set_resid(srb, 0); - return TRANSPORT_GOOD; - } - - rts51x_init_cmd(chip); - rts51x_add_cmd(chip, CHECK_REG_CMD, SD_BUS_STAT, SD_DAT0_STATUS, - SD_DAT0_STATUS); - retval = rts51x_send_cmd(chip, MODE_CR, 250); - if (retval != STATUS_SUCCESS) - TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); - rts51x_get_rsp(chip, 1, 200); /* Don't care return value */ - - retval = sd_update_lock_status(chip); - if (retval != STATUS_SUCCESS) { - RTS51X_DEBUGP("Lock command fail!\n"); - lock_cmd_fail = 1; - } - } -#endif /* SUPPORT_SD_LOCK */ if (standby) { retval = sd_select_card(chip, 1); @@ -865,51 +762,6 @@ int ext_sd_execute_write_data(struct rts51x_chip *chip, unsigned int lun, } if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); -#ifdef SUPPORT_SD_LOCK - if (cmd_idx == LOCK_UNLOCK) { - if (!lock_cmd_fail) { - RTS51X_DEBUGP("lock_cmd_type = 0x%x\n", - lock_cmd_type); - if (lock_cmd_type & SD_CLR_PWD) - sd_card->sd_lock_status &= ~SD_PWD_EXIST; - if (lock_cmd_type & SD_SET_PWD) - sd_card->sd_lock_status |= SD_PWD_EXIST; - } - - RTS51X_DEBUGP("sd_lock_state = 0x%x," - "sd_card->sd_lock_status = 0x%x\n", - sd_lock_state, sd_card->sd_lock_status); - if (sd_lock_state ^ (sd_card->sd_lock_status & SD_LOCKED)) { - sd_card->sd_lock_notify = 1; - if (sd_lock_state) { - if (sd_card->sd_lock_status & - SD_LOCK_1BIT_MODE) { - sd_card->sd_lock_status |= - (SD_UNLOCK_POW_ON | SD_SDR_RST); - if (CHK_SD(sd_card)) { - retval = reset_sd(chip); - if (retval != STATUS_SUCCESS) { - sd_card->sd_lock_status - &= ~(SD_UNLOCK_POW_ON | - SD_SDR_RST); - TRACE_GOTO(chip, - SD_Execute_Write_Cmd_Failed); - } - } - - sd_card->sd_lock_status &= - ~(SD_UNLOCK_POW_ON | SD_SDR_RST); - } - } - } - } - - if (lock_cmd_fail) { - scsi_set_resid(srb, 0); - set_sense_type(chip, lun, SENSE_TYPE_NO_SENSE); - TRACE_RET(chip, TRANSPORT_FAILED); - } -#endif /* SUPPORT_SD_LOCK */ return TRANSPORT_GOOD; @@ -1173,30 +1025,18 @@ int sd_hw_rst(struct scsi_cmnd *srb, struct rts51x_chip *chip) switch (srb->cmnd[1] & 0x0F) { case 0: /* SD Card Power Off -> ON and Initialization */ -#ifdef SUPPORT_SD_LOCK - if (0x64 == srb->cmnd[9]) { - /* Command Mode */ - sd_card->sd_lock_status |= SD_SDR_RST; - } -#endif /* SUPPORT_SD_LOCK */ retval = reset_sd_card(chip); if (retval != STATUS_SUCCESS) { -#ifdef SUPPORT_SD_LOCK - sd_card->sd_lock_status &= ~SD_SDR_RST; -#endif set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); sd_card->pre_cmd_err = 1; TRACE_RET(chip, TRANSPORT_FAILED); } -#ifdef SUPPORT_SD_LOCK - sd_card->sd_lock_status &= ~SD_SDR_RST; -#endif break; case 1: /* reset CMD(CMD0) and Initialization * (without SD Card Power Off -> ON) */ - retval = soft_reset_sd_card(chip); + retval = reset_sd(chip); if (retval != STATUS_SUCCESS) { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); sd_card->pre_cmd_err = 1; diff --git a/trunk/drivers/staging/rts5139/xd.c b/trunk/drivers/staging/rts5139/xd.c index 5820605d1806..58f8ba24caed 100644 --- a/trunk/drivers/staging/rts5139/xd.c +++ b/trunk/drivers/staging/rts5139/xd.c @@ -47,13 +47,6 @@ static inline void xd_set_err_code(struct rts51x_chip *chip, u8 err_code) xd_card->err_code = err_code; } -static inline int xd_check_err_code(struct rts51x_chip *chip, u8 err_code) -{ - struct xd_info *xd_card = &(chip->xd_card); - - return (xd_card->err_code == err_code); -} - static int xd_set_init_para(struct rts51x_chip *chip) { struct xd_info *xd_card = &(chip->xd_card); @@ -862,6 +855,8 @@ static void xd_set_l2p_tbl(struct rts51x_chip *chip, int zone_no, u16 log_off, zone->l2p_table[log_off] = phy_off; } +static int xd_delay_write(struct rts51x_chip *chip); + static u32 xd_get_l2p_tbl(struct rts51x_chip *chip, int zone_no, u16 log_off) { struct xd_info *xd_card = &(chip->xd_card); @@ -1182,91 +1177,6 @@ static int xd_copy_page(struct rts51x_chip *chip, return STATUS_SUCCESS; } -#ifdef XD_SPEEDUP -static int xd_auto_copy_page(struct rts51x_chip *chip, - u32 old_blk, u32 new_blk, - u8 start_page, u8 end_page) -{ - struct xd_info *xd_card = &(chip->xd_card); - u32 old_page, new_page; - int retval; - u8 page_count; - - RTS51X_DEBUGP("Auto copy page from block 0x%x to block 0x%x\n", - old_blk, new_blk); - - if (start_page > end_page) - TRACE_RET(chip, STATUS_FAIL); - - page_count = end_page - start_page; - - if ((old_blk == BLK_NOT_FOUND) || (new_blk == BLK_NOT_FOUND)) - TRACE_RET(chip, STATUS_FAIL); - - old_page = (old_blk << xd_card->block_shift) + start_page; - new_page = (new_blk << xd_card->block_shift) + start_page; - - XD_CLR_BAD_NEWBLK(xd_card); - - rts51x_init_cmd(chip); - - rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WAITTIME, 0x03, WAIT_FF); - rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_PAGELEN, 0xFF, page_count); - - rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_READADDR0, 0xFF, 0); - rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_READADDR1, 0xFF, - (u8) old_page); - rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_READADDR2, 0xFF, - (u8) (old_page >> 8)); - rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_READADDR3, 0xFF, - (u8) (old_page >> 16)); - rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_READADDR4, 0xFF, 0); - - rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WRITEADDR0, 0xFF, 0); - rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WRITEADDR1, 0xFF, - (u8) new_page); - rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WRITEADDR2, 0xFF, - (u8) (new_page >> 8)); - rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WRITEADDR3, 0xFF, - (u8) (new_page >> 16)); - rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WRITEADDR4, 0xFF, 0); - - rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, - PINGPONG_BUFFER); - - rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CFG, - XD_BA_TRANSFORM | XD_ADDR_MASK, 0 | xd_card->addr_cycle); - - rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CHK_DATA_STATUS, - XD_AUTO_CHK_DATA_STATUS, 0); - rts51x_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF, - XD_TRANSFER_START | XD_COPY_PAGES); - rts51x_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER, XD_TRANSFER_END, - XD_TRANSFER_END); - - retval = rts51x_send_cmd(chip, MODE_CR, 100); - if (retval != STATUS_SUCCESS) { - rts51x_clear_xd_error(chip); - TRACE_GOTO(chip, Copy_Fail); - } - - retval = rts51x_get_rsp(chip, 1, 800); - if (retval != STATUS_SUCCESS) { - rts51x_clear_xd_error(chip); - TRACE_GOTO(chip, Copy_Fail); - } - - return STATUS_SUCCESS; - -Copy_Fail: - retval = xd_copy_page(chip, old_blk, new_blk, start_page, end_page); - if (retval != STATUS_SUCCESS) - TRACE_RET(chip, retval); - - return STATUS_SUCCESS; -} -#endif - static int xd_reset_cmd(struct rts51x_chip *chip) { int retval; @@ -1686,15 +1596,9 @@ static int xd_read_multiple_pages(struct rts51x_chip *chip, u32 phy_blk, XD_CLR_BAD_OLDBLK(xd_card); TRACE_RET(chip, STATUS_FAIL); } -#ifdef XD_SPEEDUP - retval = - xd_auto_copy_page(chip, phy_blk, new_blk, 0, - xd_card->page_off + 1); -#else retval = xd_copy_page(chip, phy_blk, new_blk, 0, xd_card->page_off + 1); -#endif if (retval != STATUS_SUCCESS) { if (!XD_CHK_BAD_NEWBLK(xd_card)) { retval = xd_erase_block(chip, new_blk); @@ -1741,13 +1645,8 @@ static int xd_finish_write(struct rts51x_chip *chip, TRACE_RET(chip, STATUS_FAIL); } } else { -#ifdef XD_SPEEDUP - retval = xd_auto_copy_page(chip, old_blk, new_blk, - page_off, xd_card->page_off + 1); -#else retval = xd_copy_page(chip, old_blk, new_blk, page_off, xd_card->page_off + 1); -#endif if (retval != STATUS_SUCCESS) { if (!XD_CHK_BAD_NEWBLK(xd_card)) { retval = xd_erase_block(chip, new_blk); @@ -1789,11 +1688,7 @@ static int xd_prepare_write(struct rts51x_chip *chip, old_blk, new_blk, log_blk, (int)page_off); if (page_off) { -#ifdef XD_SPEEDUP - retval = xd_auto_copy_page(chip, old_blk, new_blk, 0, page_off); -#else retval = xd_copy_page(chip, old_blk, new_blk, 0, page_off); -#endif if (retval != STATUS_SUCCESS) TRACE_RET(chip, retval); } @@ -1922,7 +1817,7 @@ static int xd_write_multiple_pages(struct rts51x_chip *chip, u32 old_blk, TRACE_RET(chip, STATUS_FAIL); } -int xd_delay_write(struct rts51x_chip *chip) +static int xd_delay_write(struct rts51x_chip *chip) { struct xd_info *xd_card = &(chip->xd_card); struct xd_delay_write_tag *delay_write = &(xd_card->delay_write); @@ -1999,18 +1894,11 @@ int xd_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 start_sector, (start_page > delay_write->pageoff)) { delay_write->delay_write_flag = 0; if (delay_write->old_phyblock != BLK_NOT_FOUND) { -#ifdef XD_SPEEDUP - retval = xd_auto_copy_page(chip, - delay_write->old_phyblock, - delay_write->new_phyblock, - delay_write->pageoff, start_page); -#else retval = xd_copy_page(chip, delay_write->old_phyblock, delay_write->new_phyblock, delay_write->pageoff, start_page); -#endif if (retval != STATUS_SUCCESS) { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR); @@ -2198,7 +2086,7 @@ void xd_cleanup_work(struct rts51x_chip *chip) } } -int xd_power_off_card3v3(struct rts51x_chip *chip) +static int xd_power_off_card3v3(struct rts51x_chip *chip) { int retval; @@ -2232,7 +2120,7 @@ int release_xd_card(struct rts51x_chip *chip) struct xd_info *xd_card = &(chip->xd_card); int retval; - RTS51X_DEBUGP("elease_xd_card\n"); + RTS51X_DEBUGP("release_xd_card\n"); chip->card_ready &= ~XD_CARD; chip->card_fail &= ~XD_CARD; diff --git a/trunk/drivers/staging/rts5139/xd.h b/trunk/drivers/staging/rts5139/xd.h index fa695903ba65..55e4205e23fa 100644 --- a/trunk/drivers/staging/rts5139/xd.h +++ b/trunk/drivers/staging/rts5139/xd.h @@ -182,12 +182,10 @@ #define CIS1_9 (256 + 9) int reset_xd_card(struct rts51x_chip *chip); -int xd_delay_write(struct rts51x_chip *chip); int xd_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 start_sector, u16 sector_cnt); void xd_free_l2p_tbl(struct rts51x_chip *chip); void xd_cleanup_work(struct rts51x_chip *chip); -int xd_power_off_card3v3(struct rts51x_chip *chip); int release_xd_card(struct rts51x_chip *chip); #endif /* __RTS51X_XD_H */ diff --git a/trunk/drivers/staging/rts_pstor/ms.c b/trunk/drivers/staging/rts_pstor/ms.c index f9a4498984cc..0bf6d95b3fab 100644 --- a/trunk/drivers/staging/rts_pstor/ms.c +++ b/trunk/drivers/staging/rts_pstor/ms.c @@ -4136,7 +4136,7 @@ int mg_set_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip) #else retval = ms_transfer_data(chip, MS_TM_AUTO_WRITE, PRO_WRITE_LONG_DATA, 2, WAIT_INT, 0, 0, buf + 4, 1024); - if ((retval != STATUS_SUCCESS) || check_ms_err(chip) { + if ((retval != STATUS_SUCCESS) || check_ms_err(chip)) { rtsx_clear_ms_error(chip); if (ms_card->mg_auth == 0) { if ((buf[5] & 0xC0) != 0) { diff --git a/trunk/drivers/staging/rts_pstor/rtsx_transport.c b/trunk/drivers/staging/rts_pstor/rtsx_transport.c index 9b2e5c99870f..54a474235f26 100644 --- a/trunk/drivers/staging/rts_pstor/rtsx_transport.c +++ b/trunk/drivers/staging/rts_pstor/rtsx_transport.c @@ -130,7 +130,7 @@ unsigned int rtsx_stor_access_xfer_buf(unsigned char *buffer, /* Store the contents of buffer into srb's transfer buffer and set the * SCSI residue. */ void rtsx_stor_set_xfer_buf(unsigned char *buffer, - unsigned int buflen, struct scsi_cmnd *srb) + unsigned int buflen, struct scsi_cmnd *srb) { unsigned int index = 0, offset = 0; @@ -141,7 +141,7 @@ void rtsx_stor_set_xfer_buf(unsigned char *buffer, } void rtsx_stor_get_xfer_buf(unsigned char *buffer, - unsigned int buflen, struct scsi_cmnd *srb) + unsigned int buflen, struct scsi_cmnd *srb) { unsigned int index = 0, offset = 0; diff --git a/trunk/drivers/staging/sep/sep_driver_config.h b/trunk/drivers/staging/sep/sep_driver_config.h index fa7c0d09bfa5..9d9fc7c94a6e 100644 --- a/trunk/drivers/staging/sep/sep_driver_config.h +++ b/trunk/drivers/staging/sep/sep_driver_config.h @@ -68,11 +68,11 @@ #define SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE 16 /* flag that signifies tah the lock is -currently held by the proccess (struct file) */ +currently held by the process (struct file) */ #define SEP_DRIVER_OWN_LOCK_FLAG 1 /* flag that signifies tah the lock is currently NOT -held by the proccess (struct file) */ +held by the process (struct file) */ #define SEP_DRIVER_DISOWN_LOCK_FLAG 0 /* indicates whether driver has mapped/unmapped shared area */ @@ -280,7 +280,7 @@ held by the proccess (struct file) */ /* * Used to limit number of concurrent processes - * allowed to allocte dynamic buffers in fastcall + * allowed to allocate dynamic buffers in fastcall * interface. */ #define SEP_DOUBLEBUF_USERS_LIMIT 3 diff --git a/trunk/drivers/staging/sep/sep_main.c b/trunk/drivers/staging/sep/sep_main.c index f1701bc6e312..df1d13e96fcd 100644 --- a/trunk/drivers/staging/sep/sep_main.c +++ b/trunk/drivers/staging/sep/sep_main.c @@ -786,7 +786,7 @@ static unsigned int sep_poll(struct file *filp, poll_table *wait) "[PID%d] poll: send_ct is %lx reply ct is %lx\n", current->pid, sep->send_ct, sep->reply_ct); - /* Check if error occured during poll */ + /* Check if error occurred during poll */ retval2 = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR); if ((retval2 != 0x0) && (retval2 != 0x8)) { dev_dbg(&sep->pdev->dev, "[PID%d] poll; poll error %x\n", @@ -1160,7 +1160,7 @@ static int sep_lock_kernel_pages(struct sep_device *sep, /* Put mapped kernel sg into kernel resource array */ - /* Set output params acording to the in_out flag */ + /* Set output params according to the in_out flag */ if (in_out_flag == SEP_DRIVER_IN_FLAG) { *lli_array_ptr = lli_array; dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_num_pages = @@ -1358,7 +1358,7 @@ static int sep_lock_user_pages(struct sep_device *sep, lli_array[num_pages - 1].block_size); } - /* Set output params acording to the in_out flag */ + /* Set output params according to the in_out flag */ if (in_out_flag == SEP_DRIVER_IN_FLAG) { *lli_array_ptr = lli_array; dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_num_pages = @@ -2038,7 +2038,7 @@ static int sep_prepare_input_dma_table(struct sep_device *sep, /* * If this is not the last table - - * then allign it to the block size + * then align it to the block size */ if (!last_table_flag) table_data_size = @@ -3033,7 +3033,7 @@ static int sep_free_dcb_handler(struct sep_device *sep, * @cmd: command * @arg: pointer to argument structure * - * Implement the ioctl methods availble on the SEP device. + * Implement the ioctl methods available on the SEP device. */ static long sep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -4460,7 +4460,7 @@ static int sep_pm_runtime_suspend(struct device *dev) * @sep_pm_runtime_resume: resume- no communication with cpu & main memory * @sep_pm_runtime_suspend: suspend- no communication with cpu & main memory * @sep_pci_suspend: suspend - main memory is still ON - * @sep_pci_resume: resume - main meory is still ON + * @sep_pci_resume: resume - main memory is still ON */ static const struct dev_pm_ops sep_pm = { .runtime_resume = sep_pm_runtime_resume, diff --git a/trunk/drivers/staging/serial/68360serial.c b/trunk/drivers/staging/serial/68360serial.c deleted file mode 100644 index daf0b1d0dc28..000000000000 --- a/trunk/drivers/staging/serial/68360serial.c +++ /dev/null @@ -1,2979 +0,0 @@ -/* - * UART driver for 68360 CPM SCC or SMC - * Copyright (c) 2000 D. Jeff Dionne , - * Copyright (c) 2000 Michael Leslie - * Copyright (c) 1997 Dan Malek - * - * I used the serial.c driver as the framework for this driver. - * Give credit to those guys. - * The original code was written for the MBX860 board. I tried to make - * it generic, but there may be some assumptions in the structures that - * have to be fixed later. - * To save porting time, I did not bother to change any object names - * that are not accessed outside of this file. - * It still needs lots of work........When it was easy, I included code - * to support the SCCs, but this has never been tested, nor is it complete. - * Only the SCCs support modem control, so that is not complete either. - * - * This module exports the following rs232 io functions: - * - * int rs_360_init(void); - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#ifdef CONFIG_KGDB -extern void breakpoint(void); -extern void set_debug_traps(void); -extern int kgdb_output_string (const char* s, unsigned int count); -#endif - - -/* #ifdef CONFIG_SERIAL_CONSOLE */ /* This seems to be a post 2.0 thing - mles */ -#include -#include - -/* this defines the index into rs_table for the port to use - */ -#ifndef CONFIG_SERIAL_CONSOLE_PORT -#define CONFIG_SERIAL_CONSOLE_PORT 1 /* ie SMC2 - note USE_SMC2 must be defined */ -#endif -/* #endif */ - -#if 0 -/* SCC2 for console - */ -#undef CONFIG_SERIAL_CONSOLE_PORT -#define CONFIG_SERIAL_CONSOLE_PORT 2 -#endif - - -#define TX_WAKEUP ASYNC_SHARE_IRQ - -static char *serial_name = "CPM UART driver"; -static char *serial_version = "0.03"; - -static struct tty_driver *serial_driver; -int serial_console_setup(struct console *co, char *options); - -/* - * Serial driver configuration section. Here are the various options: - */ -#define SERIAL_PARANOIA_CHECK -#define CONFIG_SERIAL_NOPAUSE_IO -#define SERIAL_DO_RESTART - -/* Set of debugging defines */ - -#undef SERIAL_DEBUG_INTR -#undef SERIAL_DEBUG_OPEN -#undef SERIAL_DEBUG_FLOW -#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - -#define _INLINE_ inline - -#define DBG_CNT(s) - -/* We overload some of the items in the data structure to meet our - * needs. For example, the port address is the CPM parameter ram - * offset for the SCC or SMC. The maximum number of ports is 4 SCCs and - * 2 SMCs. The "hub6" field is used to indicate the channel number, with - * a flag indicating SCC or SMC, and the number is used as an index into - * the CPM parameter area for this device. - * The "type" field is currently set to 0, for PORT_UNKNOWN. It is - * not currently used. I should probably use it to indicate the port - * type of SMC or SCC. - * The SMCs do not support any modem control signals. - */ -#define smc_scc_num hub6 -#define NUM_IS_SCC ((int)0x00010000) -#define PORT_NUM(P) ((P) & 0x0000ffff) - - -#if defined (CONFIG_UCQUICC) - -volatile extern void *_periph_base; -/* sipex transceiver - * mode bits for are on pins - * - * SCC2 d16..19 - * SCC3 d20..23 - * SCC4 d24..27 - */ -#define SIPEX_MODE(n,m) ((m & 0x0f)<<(16+4*(n-1))) - -static uint sipex_mode_bits = 0x00000000; - -#endif - -/* There is no `serial_state' defined back here in 2.0. - * Try to get by with serial_struct - */ -/* #define serial_state serial_struct */ - -/* 2.4 -> 2.0 portability problem: async_icount in 2.4 has a few - * extras: */ - -#if 0 -struct async_icount_24 { - __u32 cts, dsr, rng, dcd, tx, rx; - __u32 frame, parity, overrun, brk; - __u32 buf_overrun; -} icount; -#endif - -#if 0 - -struct serial_state { - int magic; - int baud_base; - unsigned long port; - int irq; - int flags; - int hub6; - int type; - int line; - int revision; /* Chip revision (950) */ - int xmit_fifo_size; - int custom_divisor; - int count; - u8 *iomem_base; - u16 iomem_reg_shift; - unsigned short close_delay; - unsigned short closing_wait; /* time to wait before closing */ - struct async_icount_24 icount; - int io_type; - struct async_struct *info; -}; -#endif - -#define SSTATE_MAGIC 0x5302 - - - -/* SMC2 is sometimes used for low performance TDM interfaces. Define - * this as 1 if you want SMC2 as a serial port UART managed by this driver. - * Define this as 0 if you wish to use SMC2 for something else. - */ -#define USE_SMC2 1 - -#if 0 -/* Define SCC to ttySx mapping. */ -#define SCC_NUM_BASE (USE_SMC2 + 1) /* SCC base tty "number" */ - -/* Define which SCC is the first one to use for a serial port. These - * are 0-based numbers, i.e. this assumes the first SCC (SCC1) is used - * for Ethernet, and the first available SCC for serial UART is SCC2. - * NOTE: IF YOU CHANGE THIS, you have to change the PROFF_xxx and - * interrupt vectors in the table below to match. - */ -#define SCC_IDX_BASE 1 /* table index */ -#endif - - -/* Processors other than the 860 only get SMCs configured by default. - * Either they don't have SCCs or they are allocated somewhere else. - * Of course, there are now 860s without some SCCs, so we will need to - * address that someday. - * The Embedded Planet Multimedia I/O cards use TDM interfaces to the - * stereo codec parts, and we use SMC2 to help support that. - */ -static struct serial_state rs_table[] = { -/* type line PORT IRQ FLAGS smc_scc_num (F.K.A. hub6) */ - { 0, 0, PRSLOT_SMC1, CPMVEC_SMC1, 0, 0 } /* SMC1 ttyS0 */ -#if USE_SMC2 - ,{ 0, 0, PRSLOT_SMC2, CPMVEC_SMC2, 0, 1 } /* SMC2 ttyS1 */ -#endif - -#if defined(CONFIG_SERIAL_68360_SCC) - ,{ 0, 0, PRSLOT_SCC2, CPMVEC_SCC2, 0, (NUM_IS_SCC | 1) } /* SCC2 ttyS2 */ - ,{ 0, 0, PRSLOT_SCC3, CPMVEC_SCC3, 0, (NUM_IS_SCC | 2) } /* SCC3 ttyS3 */ - ,{ 0, 0, PRSLOT_SCC4, CPMVEC_SCC4, 0, (NUM_IS_SCC | 3) } /* SCC4 ttyS4 */ -#endif -}; - -#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state)) - -/* The number of buffer descriptors and their sizes. - */ -#define RX_NUM_FIFO 4 -#define RX_BUF_SIZE 32 -#define TX_NUM_FIFO 4 -#define TX_BUF_SIZE 32 - -#define CONSOLE_NUM_FIFO 2 -#define CONSOLE_BUF_SIZE 4 - -char *console_fifos[CONSOLE_NUM_FIFO * CONSOLE_BUF_SIZE]; - -/* The async_struct in serial.h does not really give us what we - * need, so define our own here. - */ -typedef struct serial_info { - int magic; - int flags; - - struct serial_state *state; - /* struct serial_struct *state; */ - /* struct async_struct *state; */ - - struct tty_struct *tty; - int read_status_mask; - int ignore_status_mask; - int timeout; - int line; - int x_char; /* xon/xoff character */ - int close_delay; - unsigned short closing_wait; - unsigned short closing_wait2; - unsigned long event; - unsigned long last_active; - int blocked_open; /* # of blocked opens */ - struct work_struct tqueue; - struct work_struct tqueue_hangup; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; - - -/* CPM Buffer Descriptor pointers. - */ - QUICC_BD *rx_bd_base; - QUICC_BD *rx_cur; - QUICC_BD *tx_bd_base; - QUICC_BD *tx_cur; -} ser_info_t; - - -/* since kmalloc_init() does not get called until much after this initialization: */ -static ser_info_t quicc_ser_info[NR_PORTS]; -static char rx_buf_pool[NR_PORTS * RX_NUM_FIFO * RX_BUF_SIZE]; -static char tx_buf_pool[NR_PORTS * TX_NUM_FIFO * TX_BUF_SIZE]; - -static void change_speed(ser_info_t *info); -static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout); - -static inline int serial_paranoia_check(ser_info_t *info, - char *name, const char *routine) -{ -#ifdef SERIAL_PARANOIA_CHECK - static const char *badmagic = - "Warning: bad magic number for serial struct (%s) in %s\n"; - static const char *badinfo = - "Warning: null async_struct for (%s) in %s\n"; - - if (!info) { - printk(badinfo, name, routine); - return 1; - } - if (info->magic != SERIAL_MAGIC) { - printk(badmagic, name, routine); - return 1; - } -#endif - return 0; -} - -/* - * This is used to figure out the divisor speeds and the timeouts, - * indexed by the termio value. The generic CPM functions are responsible - * for setting and assigning baud rate generators for us. - */ -static int baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 }; - -/* This sucks. There is a better way: */ -#if defined(CONFIG_CONSOLE_9600) - #define CONSOLE_BAUDRATE 9600 -#elif defined(CONFIG_CONSOLE_19200) - #define CONSOLE_BAUDRATE 19200 -#elif defined(CONFIG_CONSOLE_115200) - #define CONSOLE_BAUDRATE 115200 -#else - #warning "console baud rate undefined" - #define CONSOLE_BAUDRATE 9600 -#endif - -/* - * ------------------------------------------------------------ - * rs_stop() and rs_start() - * - * This routines are called before setting or resetting tty->stopped. - * They enable or disable transmitter interrupts, as necessary. - * ------------------------------------------------------------ - */ -static void rs_360_stop(struct tty_struct *tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - int idx; - unsigned long flags; - volatile struct scc_regs *sccp; - volatile struct smc_regs *smcp; - - if (serial_paranoia_check(info, tty->name, "rs_stop")) - return; - - local_irq_save(flags); - idx = PORT_NUM(info->state->smc_scc_num); - if (info->state->smc_scc_num & NUM_IS_SCC) { - sccp = &pquicc->scc_regs[idx]; - sccp->scc_sccm &= ~UART_SCCM_TX; - } else { - /* smcp = &cpmp->cp_smc[idx]; */ - smcp = &pquicc->smc_regs[idx]; - smcp->smc_smcm &= ~SMCM_TX; - } - local_irq_restore(flags); -} - - -static void rs_360_start(struct tty_struct *tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - int idx; - unsigned long flags; - volatile struct scc_regs *sccp; - volatile struct smc_regs *smcp; - - if (serial_paranoia_check(info, tty->name, "rs_stop")) - return; - - local_irq_save(flags); - idx = PORT_NUM(info->state->smc_scc_num); - if (info->state->smc_scc_num & NUM_IS_SCC) { - sccp = &pquicc->scc_regs[idx]; - sccp->scc_sccm |= UART_SCCM_TX; - } else { - smcp = &pquicc->smc_regs[idx]; - smcp->smc_smcm |= SMCM_TX; - } - local_irq_restore(flags); -} - -/* - * ---------------------------------------------------------------------- - * - * Here starts the interrupt handling routines. All of the following - * subroutines are declared as inline and are folded into - * rs_interrupt(). They were separated out for readability's sake. - * - * Note: rs_interrupt() is a "fast" interrupt, which means that it - * runs with interrupts turned off. People who may want to modify - * rs_interrupt() should try to keep the interrupt handler as fast as - * possible. After you are done making modifications, it is not a bad - * idea to do: - * - * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c - * - * and look at the resulting assemble code in serial.s. - * - * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 - * ----------------------------------------------------------------------- - */ - -static _INLINE_ void receive_chars(ser_info_t *info) -{ - struct tty_struct *tty = info->port.tty; - unsigned char ch, flag, *cp; - /*int ignored = 0;*/ - int i; - ushort status; - struct async_icount *icount; - /* struct async_icount_24 *icount; */ - volatile QUICC_BD *bdp; - - icount = &info->state->icount; - - /* Just loop through the closed BDs and copy the characters into - * the buffer. - */ - bdp = info->rx_cur; - for (;;) { - if (bdp->status & BD_SC_EMPTY) /* If this one is empty */ - break; /* we are all done */ - - /* The read status mask tell us what we should do with - * incoming characters, especially if errors occur. - * One special case is the use of BD_SC_EMPTY. If - * this is not set, we are supposed to be ignoring - * inputs. In this case, just mark the buffer empty and - * continue. - */ - if (!(info->read_status_mask & BD_SC_EMPTY)) { - bdp->status |= BD_SC_EMPTY; - bdp->status &= - ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV); - - if (bdp->status & BD_SC_WRAP) - bdp = info->rx_bd_base; - else - bdp++; - continue; - } - - /* Get the number of characters and the buffer pointer. - */ - i = bdp->length; - /* cp = (unsigned char *)__va(bdp->buf); */ - cp = (char *)bdp->buf; - status = bdp->status; - - while (i-- > 0) { - ch = *cp++; - icount->rx++; - -#ifdef SERIAL_DEBUG_INTR - printk("DR%02x:%02x...", ch, status); -#endif - flag = TTY_NORMAL; - - if (status & (BD_SC_BR | BD_SC_FR | - BD_SC_PR | BD_SC_OV)) { - /* - * For statistics only - */ - if (status & BD_SC_BR) - icount->brk++; - else if (status & BD_SC_PR) - icount->parity++; - else if (status & BD_SC_FR) - icount->frame++; - if (status & BD_SC_OV) - icount->overrun++; - - /* - * Now check to see if character should be - * ignored, and mask off conditions which - * should be ignored. - if (status & info->ignore_status_mask) { - if (++ignored > 100) - break; - continue; - } - */ - status &= info->read_status_mask; - - if (status & (BD_SC_BR)) { -#ifdef SERIAL_DEBUG_INTR - printk("handling break...."); -#endif - *tty->flip.flag_buf_ptr = TTY_BREAK; - if (info->flags & ASYNC_SAK) - do_SAK(tty); - } else if (status & BD_SC_PR) - flag = TTY_PARITY; - else if (status & BD_SC_FR) - flag = TTY_FRAME; - } - tty_insert_flip_char(tty, ch, flag); - if (status & BD_SC_OV) - /* - * Overrun is special, since it's - * reported immediately, and doesn't - * affect the current character - */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } - - /* This BD is ready to be used again. Clear status. - * Get next BD. - */ - bdp->status |= BD_SC_EMPTY; - bdp->status &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV); - - if (bdp->status & BD_SC_WRAP) - bdp = info->rx_bd_base; - else - bdp++; - } - - info->rx_cur = (QUICC_BD *)bdp; - - tty_schedule_flip(tty); -} - -static _INLINE_ void receive_break(ser_info_t *info) -{ - struct tty_struct *tty = info->port.tty; - - info->state->icount.brk++; - /* Check to see if there is room in the tty buffer for - * the break. If not, we exit now, losing the break. FIXME - */ - tty_insert_flip_char(tty, 0, TTY_BREAK); - tty_schedule_flip(tty); -} - -static _INLINE_ void transmit_chars(ser_info_t *info) -{ - - if ((info->flags & TX_WAKEUP) || - (info->port.tty->flags & (1 << TTY_DO_WRITE_WAKEUP))) { - schedule_work(&info->tqueue); - } - -#ifdef SERIAL_DEBUG_INTR - printk("THRE..."); -#endif -} - -#ifdef notdef - /* I need to do this for the SCCs, so it is left as a reminder. - */ -static _INLINE_ void check_modem_status(struct async_struct *info) -{ - int status; - /* struct async_icount *icount; */ - struct async_icount_24 *icount; - - status = serial_in(info, UART_MSR); - - if (status & UART_MSR_ANY_DELTA) { - icount = &info->state->icount; - /* update input line counters */ - if (status & UART_MSR_TERI) - icount->rng++; - if (status & UART_MSR_DDSR) - icount->dsr++; - if (status & UART_MSR_DDCD) { - icount->dcd++; -#ifdef CONFIG_HARD_PPS - if ((info->flags & ASYNC_HARDPPS_CD) && - (status & UART_MSR_DCD)) - hardpps(); -#endif - } - if (status & UART_MSR_DCTS) - icount->cts++; - wake_up_interruptible(&info->delta_msr_wait); - } - - if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { -#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) - printk("ttys%d CD now %s...", info->line, - (status & UART_MSR_DCD) ? "on" : "off"); -#endif - if (status & UART_MSR_DCD) - wake_up_interruptible(&info->open_wait); - else { -#ifdef SERIAL_DEBUG_OPEN - printk("scheduling hangup..."); -#endif - queue_task(&info->tqueue_hangup, - &tq_scheduler); - } - } - if (info->flags & ASYNC_CTS_FLOW) { - if (info->port.tty->hw_stopped) { - if (status & UART_MSR_CTS) { -#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) - printk("CTS tx start..."); -#endif - info->port.tty->hw_stopped = 0; - info->IER |= UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); - return; - } - } else { - if (!(status & UART_MSR_CTS)) { -#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) - printk("CTS tx stop..."); -#endif - info->port.tty->hw_stopped = 1; - info->IER &= ~UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - } - } - } -} -#endif - -/* - * This is the serial driver's interrupt routine for a single port - */ -/* static void rs_360_interrupt(void *dev_id) */ /* until and if we start servicing irqs here */ -static void rs_360_interrupt(int vec, void *dev_id) -{ - u_char events; - int idx; - ser_info_t *info; - volatile struct smc_regs *smcp; - volatile struct scc_regs *sccp; - - info = dev_id; - - idx = PORT_NUM(info->state->smc_scc_num); - if (info->state->smc_scc_num & NUM_IS_SCC) { - sccp = &pquicc->scc_regs[idx]; - events = sccp->scc_scce; - if (events & SCCM_RX) - receive_chars(info); - if (events & SCCM_TX) - transmit_chars(info); - sccp->scc_scce = events; - } else { - smcp = &pquicc->smc_regs[idx]; - events = smcp->smc_smce; - if (events & SMCM_BRKE) - receive_break(info); - if (events & SMCM_RX) - receive_chars(info); - if (events & SMCM_TX) - transmit_chars(info); - smcp->smc_smce = events; - } - -#ifdef SERIAL_DEBUG_INTR - printk("rs_interrupt_single(%d, %x)...", - info->state->smc_scc_num, events); -#endif -#ifdef modem_control - check_modem_status(info); -#endif - info->last_active = jiffies; -#ifdef SERIAL_DEBUG_INTR - printk("end.\n"); -#endif -} - - -/* - * ------------------------------------------------------------------- - * Here ends the serial interrupt routines. - * ------------------------------------------------------------------- - */ - - -static void do_softint(void *private_) -{ - ser_info_t *info = (ser_info_t *) private_; - struct tty_struct *tty; - - tty = info->port.tty; - if (!tty) - return; - - if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) - tty_wakeup(tty); -} - - -/* - * This routine is called from the scheduler tqueue when the interrupt - * routine has signalled that a hangup has occurred. The path of - * hangup processing is: - * - * serial interrupt routine -> (scheduler tqueue) -> - * do_serial_hangup() -> tty->hangup() -> rs_hangup() - * - */ -static void do_serial_hangup(void *private_) -{ - struct async_struct *info = (struct async_struct *) private_; - struct tty_struct *tty; - - tty = info->port.tty; - if (!tty) - return; - - tty_hangup(tty); -} - - -static int startup(ser_info_t *info) -{ - unsigned long flags; - int retval=0; - int idx; - /*struct serial_state *state = info->state;*/ - volatile struct smc_regs *smcp; - volatile struct scc_regs *sccp; - volatile struct smc_uart_pram *up; - volatile struct uart_pram *scup; - - - local_irq_save(flags); - - if (info->flags & ASYNC_INITIALIZED) { - goto errout; - } - -#ifdef maybe - if (!state->port || !state->type) { - if (info->port.tty) - set_bit(TTY_IO_ERROR, &info->port.tty->flags); - goto errout; - } -#endif - -#ifdef SERIAL_DEBUG_OPEN - printk("starting up ttys%d (irq %d)...", info->line, state->irq); -#endif - - -#ifdef modem_control - info->MCR = 0; - if (info->port.tty->termios->c_cflag & CBAUD) - info->MCR = UART_MCR_DTR | UART_MCR_RTS; -#endif - - if (info->port.tty) - clear_bit(TTY_IO_ERROR, &info->port.tty->flags); - - /* - * and set the speed of the serial port - */ - change_speed(info); - - idx = PORT_NUM(info->state->smc_scc_num); - if (info->state->smc_scc_num & NUM_IS_SCC) { - sccp = &pquicc->scc_regs[idx]; - scup = &pquicc->pram[info->state->port].scc.pscc.u; - - scup->mrblr = RX_BUF_SIZE; - scup->max_idl = RX_BUF_SIZE; - - sccp->scc_sccm |= (UART_SCCM_TX | UART_SCCM_RX); - sccp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); - - } else { - smcp = &pquicc->smc_regs[idx]; - - /* Enable interrupts and I/O. - */ - smcp->smc_smcm |= (SMCM_RX | SMCM_TX); - smcp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN); - - /* We can tune the buffer length and idle characters - * to take advantage of the entire incoming buffer size. - * If mrblr is something other than 1, maxidl has to be - * non-zero or we never get an interrupt. The maxidl - * is the number of character times we wait after reception - * of the last character before we decide no more characters - * are coming. - */ - /* up = (smc_uart_t *)&pquicc->cp_dparam[state->port]; */ - /* holy unionized structures, Batman: */ - up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u; - - up->mrblr = RX_BUF_SIZE; - up->max_idl = RX_BUF_SIZE; - - up->brkcr = 1; /* number of break chars */ - } - - info->flags |= ASYNC_INITIALIZED; - local_irq_restore(flags); - return 0; - -errout: - local_irq_restore(flags); - return retval; -} - -/* - * This routine will shutdown a serial port; interrupts are disabled, and - * DTR is dropped if the hangup on close termio flag is on. - */ -static void shutdown(ser_info_t *info) -{ - unsigned long flags; - struct serial_state *state; - int idx; - volatile struct smc_regs *smcp; - volatile struct scc_regs *sccp; - - if (!(info->flags & ASYNC_INITIALIZED)) - return; - - state = info->state; - -#ifdef SERIAL_DEBUG_OPEN - printk("Shutting down serial port %d (irq %d)....", info->line, - state->irq); -#endif - - local_irq_save(flags); - - idx = PORT_NUM(state->smc_scc_num); - if (state->smc_scc_num & NUM_IS_SCC) { - sccp = &pquicc->scc_regs[idx]; - sccp->scc_gsmr.w.low &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); -#ifdef CONFIG_SERIAL_CONSOLE - /* We can't disable the transmitter if this is the - * system console. - */ - if ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT) -#endif - sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); - } else { - smcp = &pquicc->smc_regs[idx]; - - /* Disable interrupts and I/O. - */ - smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX); -#ifdef CONFIG_SERIAL_CONSOLE - /* We can't disable the transmitter if this is the - * system console. - */ - if ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT) -#endif - smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); - } - - if (info->port.tty) - set_bit(TTY_IO_ERROR, &info->port.tty->flags); - - info->flags &= ~ASYNC_INITIALIZED; - local_irq_restore(flags); -} - -/* - * This routine is called to set the UART divisor registers to match - * the specified baud rate for a serial port. - */ -static void change_speed(ser_info_t *info) -{ - int baud_rate; - unsigned cflag, cval, scval, prev_mode; - int i, bits, sbits, idx; - unsigned long flags; - struct serial_state *state; - volatile struct smc_regs *smcp; - volatile struct scc_regs *sccp; - - if (!info->port.tty || !info->port.tty->termios) - return; - cflag = info->port.tty->termios->c_cflag; - - state = info->state; - - /* Character length programmed into the mode register is the - * sum of: 1 start bit, number of data bits, 0 or 1 parity bit, - * 1 or 2 stop bits, minus 1. - * The value 'bits' counts this for us. - */ - cval = 0; - scval = 0; - - /* byte size and parity */ - switch (cflag & CSIZE) { - case CS5: bits = 5; break; - case CS6: bits = 6; break; - case CS7: bits = 7; break; - case CS8: bits = 8; break; - /* Never happens, but GCC is too dumb to figure it out */ - default: bits = 8; break; - } - sbits = bits - 5; - - if (cflag & CSTOPB) { - cval |= SMCMR_SL; /* Two stops */ - scval |= SCU_PMSR_SL; - bits++; - } - if (cflag & PARENB) { - cval |= SMCMR_PEN; - scval |= SCU_PMSR_PEN; - bits++; - } - if (!(cflag & PARODD)) { - cval |= SMCMR_PM_EVEN; - scval |= (SCU_PMSR_REVP | SCU_PMSR_TEVP); - } - - /* Determine divisor based on baud rate */ - i = cflag & CBAUD; - if (i >= (sizeof(baud_table)/sizeof(int))) - baud_rate = 9600; - else - baud_rate = baud_table[i]; - - info->timeout = (TX_BUF_SIZE*HZ*bits); - info->timeout += HZ/50; /* Add .02 seconds of slop */ - -#ifdef modem_control - /* CTS flow control flag and modem status interrupts */ - info->IER &= ~UART_IER_MSI; - if (info->flags & ASYNC_HARDPPS_CD) - info->IER |= UART_IER_MSI; - if (cflag & CRTSCTS) { - info->flags |= ASYNC_CTS_FLOW; - info->IER |= UART_IER_MSI; - } else - info->flags &= ~ASYNC_CTS_FLOW; - if (cflag & CLOCAL) - info->flags &= ~ASYNC_CHECK_CD; - else { - info->flags |= ASYNC_CHECK_CD; - info->IER |= UART_IER_MSI; - } - serial_out(info, UART_IER, info->IER); -#endif - - /* - * Set up parity check flag - */ - info->read_status_mask = (BD_SC_EMPTY | BD_SC_OV); - if (I_INPCK(info->port.tty)) - info->read_status_mask |= BD_SC_FR | BD_SC_PR; - if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) - info->read_status_mask |= BD_SC_BR; - - /* - * Characters to ignore - */ - info->ignore_status_mask = 0; - if (I_IGNPAR(info->port.tty)) - info->ignore_status_mask |= BD_SC_PR | BD_SC_FR; - if (I_IGNBRK(info->port.tty)) { - info->ignore_status_mask |= BD_SC_BR; - /* - * If we're ignore parity and break indicators, ignore - * overruns too. (For real raw support). - */ - if (I_IGNPAR(info->port.tty)) - info->ignore_status_mask |= BD_SC_OV; - } - /* - * !!! ignore all characters if CREAD is not set - */ - if ((cflag & CREAD) == 0) - info->read_status_mask &= ~BD_SC_EMPTY; - local_irq_save(flags); - - /* Start bit has not been added (so don't, because we would just - * subtract it later), and we need to add one for the number of - * stops bits (there is always at least one). - */ - bits++; - idx = PORT_NUM(state->smc_scc_num); - if (state->smc_scc_num & NUM_IS_SCC) { - sccp = &pquicc->scc_regs[idx]; - sccp->scc_psmr = (sbits << 12) | scval; - } else { - smcp = &pquicc->smc_regs[idx]; - - /* Set the mode register. We want to keep a copy of the - * enables, because we want to put them back if they were - * present. - */ - prev_mode = smcp->smc_smcmr; - smcp->smc_smcmr = smcr_mk_clen(bits) | cval | SMCMR_SM_UART; - smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN)); - } - - m360_cpm_setbrg((state - rs_table), baud_rate); - - local_irq_restore(flags); -} - -static void rs_360_put_char(struct tty_struct *tty, unsigned char ch) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - volatile QUICC_BD *bdp; - - if (serial_paranoia_check(info, tty->name, "rs_put_char")) - return 0; - - if (!tty) - return 0; - - bdp = info->tx_cur; - while (bdp->status & BD_SC_READY); - - /* *((char *)__va(bdp->buf)) = ch; */ - *((char *)bdp->buf) = ch; - bdp->length = 1; - bdp->status |= BD_SC_READY; - - /* Get next BD. - */ - if (bdp->status & BD_SC_WRAP) - bdp = info->tx_bd_base; - else - bdp++; - - info->tx_cur = (QUICC_BD *)bdp; - return 1; - -} - -static int rs_360_write(struct tty_struct * tty, - const unsigned char *buf, int count) -{ - int c, ret = 0; - ser_info_t *info = (ser_info_t *)tty->driver_data; - volatile QUICC_BD *bdp; - -#ifdef CONFIG_KGDB - /* Try to let stub handle output. Returns true if it did. */ - if (kgdb_output_string(buf, count)) - return ret; -#endif - - if (serial_paranoia_check(info, tty->name, "rs_write")) - return 0; - - if (!tty) - return 0; - - bdp = info->tx_cur; - - while (1) { - c = min(count, TX_BUF_SIZE); - - if (c <= 0) - break; - - if (bdp->status & BD_SC_READY) { - info->flags |= TX_WAKEUP; - break; - } - - /* memcpy(__va(bdp->buf), buf, c); */ - memcpy((void *)bdp->buf, buf, c); - - bdp->length = c; - bdp->status |= BD_SC_READY; - - buf += c; - count -= c; - ret += c; - - /* Get next BD. - */ - if (bdp->status & BD_SC_WRAP) - bdp = info->tx_bd_base; - else - bdp++; - info->tx_cur = (QUICC_BD *)bdp; - } - return ret; -} - -static int rs_360_write_room(struct tty_struct *tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - int ret; - - if (serial_paranoia_check(info, tty->name, "rs_write_room")) - return 0; - - if ((info->tx_cur->status & BD_SC_READY) == 0) { - info->flags &= ~TX_WAKEUP; - ret = TX_BUF_SIZE; - } - else { - info->flags |= TX_WAKEUP; - ret = 0; - } - return ret; -} - -/* I could track this with transmit counters....maybe later. -*/ -static int rs_360_chars_in_buffer(struct tty_struct *tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer")) - return 0; - return 0; -} - -static void rs_360_flush_buffer(struct tty_struct *tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "rs_flush_buffer")) - return; - - /* There is nothing to "flush", whatever we gave the CPM - * is on its way out. - */ - tty_wakeup(tty); - info->flags &= ~TX_WAKEUP; -} - -/* - * This function is used to send a high-priority XON/XOFF character to - * the device - */ -static void rs_360_send_xchar(struct tty_struct *tty, char ch) -{ - volatile QUICC_BD *bdp; - - ser_info_t *info = (ser_info_t *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "rs_send_char")) - return; - - bdp = info->tx_cur; - while (bdp->status & BD_SC_READY); - - /* *((char *)__va(bdp->buf)) = ch; */ - *((char *)bdp->buf) = ch; - bdp->length = 1; - bdp->status |= BD_SC_READY; - - /* Get next BD. - */ - if (bdp->status & BD_SC_WRAP) - bdp = info->tx_bd_base; - else - bdp++; - - info->tx_cur = (QUICC_BD *)bdp; -} - -/* - * ------------------------------------------------------------ - * rs_throttle() - * - * This routine is called by the upper-layer tty layer to signal that - * incoming characters should be throttled. - * ------------------------------------------------------------ - */ -static void rs_360_throttle(struct tty_struct * tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; -#ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("throttle %s: %d....\n", _tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty)); -#endif - - if (serial_paranoia_check(info, tty->name, "rs_throttle")) - return; - - if (I_IXOFF(tty)) - rs_360_send_xchar(tty, STOP_CHAR(tty)); - -#ifdef modem_control - if (tty->termios->c_cflag & CRTSCTS) - info->MCR &= ~UART_MCR_RTS; - - local_irq_disable(); - serial_out(info, UART_MCR, info->MCR); - local_irq_enable(); -#endif -} - -static void rs_360_unthrottle(struct tty_struct * tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; -#ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("unthrottle %s: %d....\n", _tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty)); -#endif - - if (serial_paranoia_check(info, tty->name, "rs_unthrottle")) - return; - - if (I_IXOFF(tty)) { - if (info->x_char) - info->x_char = 0; - else - rs_360_send_xchar(tty, START_CHAR(tty)); - } -#ifdef modem_control - if (tty->termios->c_cflag & CRTSCTS) - info->MCR |= UART_MCR_RTS; - local_irq_disable(); - serial_out(info, UART_MCR, info->MCR); - local_irq_enable(); -#endif -} - -/* - * ------------------------------------------------------------ - * rs_ioctl() and friends - * ------------------------------------------------------------ - */ - -#ifdef maybe -/* - * get_lsr_info - get line status register info - * - * Purpose: Let user call ioctl() to get info when the UART physically - * is emptied. On bus types like RS485, the transmitter must - * release the bus after transmitting. This must be done when - * the transmit shift register is empty, not be done when the - * transmit holding register is empty. This functionality - * allows an RS485 driver to be written in user space. - */ -static int get_lsr_info(struct async_struct * info, unsigned int *value) -{ - unsigned char status; - unsigned int result; - - local_irq_disable(); - status = serial_in(info, UART_LSR); - local_irq_enable(); - result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); - return put_user(result,value); -} -#endif - -static int rs_360_tiocmget(struct tty_struct *tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - unsigned int result = 0; -#ifdef modem_control - unsigned char control, status; - - if (serial_paranoia_check(info, tty->name, __func__)) - return -ENODEV; - - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - - control = info->MCR; - local_irq_disable(); - status = serial_in(info, UART_MSR); - local_irq_enable(); - result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) - | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) -#ifdef TIOCM_OUT1 - | ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0) - | ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0) -#endif - | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) - | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) - | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) - | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); -#endif - return result; -} - -static int rs_360_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ -#ifdef modem_control - ser_info_t *info = (ser_info_t *)tty->driver_data; - unsigned int arg; - - if (serial_paranoia_check(info, tty->name, __func__)) - return -ENODEV; - - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - /* FIXME: locking on info->mcr */ - if (set & TIOCM_RTS) - info->mcr |= UART_MCR_RTS; - if (set & TIOCM_DTR) - info->mcr |= UART_MCR_DTR; - if (clear & TIOCM_RTS) - info->MCR &= ~UART_MCR_RTS; - if (clear & TIOCM_DTR) - info->MCR &= ~UART_MCR_DTR; - -#ifdef TIOCM_OUT1 - if (set & TIOCM_OUT1) - info->MCR |= UART_MCR_OUT1; - if (set & TIOCM_OUT2) - info->MCR |= UART_MCR_OUT2; - if (clear & TIOCM_OUT1) - info->MCR &= ~UART_MCR_OUT1; - if (clear & TIOCM_OUT2) - info->MCR &= ~UART_MCR_OUT2; -#endif - - local_irq_disable(); - serial_out(info, UART_MCR, info->MCR); - local_irq_enable(); -#endif - return 0; -} - -/* Sending a break is a two step process on the SMC/SCC. It is accomplished - * by sending a STOP TRANSMIT command followed by a RESTART TRANSMIT - * command. We take advantage of the begin/end functions to make this - * happen. - */ -static ushort smc_chan_map[] = { - CPM_CR_CH_SMC1, - CPM_CR_CH_SMC2 -}; - -static ushort scc_chan_map[] = { - CPM_CR_CH_SCC1, - CPM_CR_CH_SCC2, - CPM_CR_CH_SCC3, - CPM_CR_CH_SCC4 -}; - -static void begin_break(ser_info_t *info) -{ - volatile QUICC *cp; - ushort chan; - int idx; - - cp = pquicc; - - idx = PORT_NUM(info->state->smc_scc_num); - if (info->state->smc_scc_num & NUM_IS_SCC) - chan = scc_chan_map[idx]; - else - chan = smc_chan_map[idx]; - - cp->cp_cr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG; - while (cp->cp_cr & CPM_CR_FLG); -} - -static void end_break(ser_info_t *info) -{ - volatile QUICC *cp; - ushort chan; - int idx; - - cp = pquicc; - - idx = PORT_NUM(info->state->smc_scc_num); - if (info->state->smc_scc_num & NUM_IS_SCC) - chan = scc_chan_map[idx]; - else - chan = smc_chan_map[idx]; - - cp->cp_cr = mk_cr_cmd(chan, CPM_CR_RESTART_TX) | CPM_CR_FLG; - while (cp->cp_cr & CPM_CR_FLG); -} - -/* - * This routine sends a break character out the serial port. - */ -static void send_break(ser_info_t *info, unsigned int duration) -{ -#ifdef SERIAL_DEBUG_SEND_BREAK - printk("rs_send_break(%d) jiff=%lu...", duration, jiffies); -#endif - begin_break(info); - msleep_interruptible(duration); - end_break(info); -#ifdef SERIAL_DEBUG_SEND_BREAK - printk("done jiffies=%lu\n", jiffies); -#endif -} - - -/* - * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) - * Return: write counters to the user passed counter struct - * NB: both 1->0 and 0->1 transitions are counted except for - * RI where only 0->1 is counted. - */ -static int rs_360_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - struct async_icount cnow; - - local_irq_disable(); - cnow = info->state->icount; - local_irq_enable(); - - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - - return 0; -} - -static int rs_360_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - int error; - ser_info_t *info = (ser_info_t *)tty->driver_data; - int retval; - struct async_icount cnow; - /* struct async_icount_24 cnow;*/ /* kernel counter temps */ - struct serial_icounter_struct *p_cuser; /* user space */ - - if (serial_paranoia_check(info, tty->name, "rs_ioctl")) - return -ENODEV; - - if (cmd != TIOCMIWAIT) { - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - } - - switch (cmd) { - case TCSBRK: /* SVID version: non-zero arg --> no break */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - if (signal_pending(current)) - return -EINTR; - if (!arg) { - send_break(info, 250); /* 1/4 second */ - if (signal_pending(current)) - return -EINTR; - } - return 0; - case TCSBRKP: /* support for POSIX tcsendbreak() */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - if (signal_pending(current)) - return -EINTR; - send_break(info, arg ? arg*100 : 250); - if (signal_pending(current)) - return -EINTR; - return 0; - case TIOCSBRK: - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - begin_break(info); - return 0; - case TIOCCBRK: - retval = tty_check_change(tty); - if (retval) - return retval; - end_break(info); - return 0; -#ifdef maybe - case TIOCSERGETLSR: /* Get line status register */ - return get_lsr_info(info, (unsigned int *) arg); -#endif - /* - * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - * - mask passed in arg for lines of interest - * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) - * Caller should use TIOCGICOUNT to see which one it was - */ - case TIOCMIWAIT: -#ifdef modem_control - local_irq_disable(); - /* note the counters on entry */ - cprev = info->state->icount; - local_irq_enable(); - while (1) { - interruptible_sleep_on(&info->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - local_irq_disable(); - cnow = info->state->icount; /* atomic copy */ - local_irq_enable(); - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { - return 0; - } - cprev = cnow; - } - /* NOTREACHED */ -#else - return 0; -#endif - - - default: - return -ENOIOCTLCMD; - } - return 0; -} - -/* FIX UP modem control here someday...... -*/ -static void rs_360_set_termios(struct tty_struct *tty, struct ktermios *old_termios) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - - change_speed(info); - -#ifdef modem_control - /* Handle transition to B0 status */ - if ((old_termios->c_cflag & CBAUD) && - !(tty->termios->c_cflag & CBAUD)) { - info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); - local_irq_disable(); - serial_out(info, UART_MCR, info->MCR); - local_irq_enable(); - } - - /* Handle transition away from B0 status */ - if (!(old_termios->c_cflag & CBAUD) && - (tty->termios->c_cflag & CBAUD)) { - info->MCR |= UART_MCR_DTR; - if (!tty->hw_stopped || - !(tty->termios->c_cflag & CRTSCTS)) { - info->MCR |= UART_MCR_RTS; - } - local_irq_disable(); - serial_out(info, UART_MCR, info->MCR); - local_irq_enable(); - } - - /* Handle turning off CRTSCTS */ - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { - tty->hw_stopped = 0; - rs_360_start(tty); - } -#endif - -#if 0 - /* - * No need to wake up processes in open wait, since they - * sample the CLOCAL flag once, and don't recheck it. - * XXX It's not clear whether the current behavior is correct - * or not. Hence, this may change..... - */ - if (!(old_termios->c_cflag & CLOCAL) && - (tty->termios->c_cflag & CLOCAL)) - wake_up_interruptible(&info->open_wait); -#endif -} - -/* - * ------------------------------------------------------------ - * rs_close() - * - * This routine is called when the serial port gets closed. First, we - * wait for the last remaining data to be sent. Then, we unlink its - * async structure from the interrupt chain if necessary, and we free - * that IRQ if nothing is left in the chain. - * ------------------------------------------------------------ - */ -static void rs_360_close(struct tty_struct *tty, struct file * filp) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - /* struct async_state *state; */ - struct serial_state *state; - unsigned long flags; - int idx; - volatile struct smc_regs *smcp; - volatile struct scc_regs *sccp; - - if (!info || serial_paranoia_check(info, tty->name, "rs_close")) - return; - - state = info->state; - - local_irq_save(flags); - - if (tty_hung_up_p(filp)) { - DBG_CNT("before DEC-hung"); - local_irq_restore(flags); - return; - } - -#ifdef SERIAL_DEBUG_OPEN - printk("rs_close ttys%d, count = %d\n", info->line, state->count); -#endif - if ((tty->count == 1) && (state->count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. state->count should always - * be one in these conditions. If it's greater than - * one, we've got real problems, since it means the - * serial port won't be shutdown. - */ - printk("rs_close: bad serial port count; tty->count is 1, " - "state->count is %d\n", state->count); - state->count = 1; - } - if (--state->count < 0) { - printk("rs_close: bad serial port count for ttys%d: %d\n", - info->line, state->count); - state->count = 0; - } - if (state->count) { - DBG_CNT("before DEC-2"); - local_irq_restore(flags); - return; - } - info->flags |= ASYNC_CLOSING; - /* - * Now we wait for the transmit buffer to clear; and we notify - * the line discipline to only process XON/XOFF characters. - */ - tty->closing = 1; - if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, info->closing_wait); - /* - * At this point we stop accepting input. To do this, we - * disable the receive line status interrupts, and tell the - * interrupt driver to stop checking the data ready bit in the - * line status register. - */ - info->read_status_mask &= ~BD_SC_EMPTY; - if (info->flags & ASYNC_INITIALIZED) { - - idx = PORT_NUM(info->state->smc_scc_num); - if (info->state->smc_scc_num & NUM_IS_SCC) { - sccp = &pquicc->scc_regs[idx]; - sccp->scc_sccm &= ~UART_SCCM_RX; - sccp->scc_gsmr.w.low &= ~SCC_GSMRL_ENR; - } else { - smcp = &pquicc->smc_regs[idx]; - smcp->smc_smcm &= ~SMCM_RX; - smcp->smc_smcmr &= ~SMCMR_REN; - } - /* - * Before we drop DTR, make sure the UART transmitter - * has completely drained; this is especially - * important if there is a transmit FIFO! - */ - rs_360_wait_until_sent(tty, info->timeout); - } - shutdown(info); - rs_360_flush_buffer(tty); - tty_ldisc_flush(tty); - tty->closing = 0; - info->event = 0; - info->port.tty = NULL; - if (info->blocked_open) { - if (info->close_delay) { - msleep_interruptible(jiffies_to_msecs(info->close_delay)); - } - wake_up_interruptible(&info->open_wait); - } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&info->close_wait); - local_irq_restore(flags); -} - -/* - * rs_wait_until_sent() --- wait until the transmitter is empty - */ -static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - unsigned long orig_jiffies, char_time; - /*int lsr;*/ - volatile QUICC_BD *bdp; - - if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent")) - return; - -#ifdef maybe - if (info->state->type == PORT_UNKNOWN) - return; -#endif - - orig_jiffies = jiffies; - /* - * Set the check interval to be 1/5 of the estimated time to - * send a single character, and make it at least 1. The check - * interval should also be less than the timeout. - * - * Note: we have to use pretty tight timings here to satisfy - * the NIST-PCTS. - */ - char_time = 1; - if (timeout) - char_time = min(char_time, (unsigned long)timeout); -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time); - printk("jiff=%lu...", jiffies); -#endif - - /* We go through the loop at least once because we can't tell - * exactly when the last character exits the shifter. There can - * be at least two characters waiting to be sent after the buffers - * are empty. - */ - do { -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - printk("lsr = %d (jiff=%lu)...", lsr, jiffies); -#endif -/* current->counter = 0; make us low-priority */ - msleep_interruptible(jiffies_to_msecs(char_time)); - if (signal_pending(current)) - break; - if (timeout && (time_after(jiffies, orig_jiffies + timeout))) - break; - /* The 'tx_cur' is really the next buffer to send. We - * have to back up to the previous BD and wait for it - * to go. This isn't perfect, because all this indicates - * is the buffer is available. There are still characters - * in the CPM FIFO. - */ - bdp = info->tx_cur; - if (bdp == info->tx_bd_base) - bdp += (TX_NUM_FIFO-1); - else - bdp--; - } while (bdp->status & BD_SC_READY); - current->state = TASK_RUNNING; -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); -#endif -} - -/* - * rs_hangup() --- called by tty_hangup() when a hangup is signaled. - */ -static void rs_360_hangup(struct tty_struct *tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - struct serial_state *state = info->state; - - if (serial_paranoia_check(info, tty->name, "rs_hangup")) - return; - - state = info->state; - - rs_360_flush_buffer(tty); - shutdown(info); - info->event = 0; - state->count = 0; - info->flags &= ~ASYNC_NORMAL_ACTIVE; - info->port.tty = NULL; - wake_up_interruptible(&info->open_wait); -} - -/* - * ------------------------------------------------------------ - * rs_open() and friends - * ------------------------------------------------------------ - */ -static int block_til_ready(struct tty_struct *tty, struct file * filp, - ser_info_t *info) -{ -#ifdef DO_THIS_LATER - DECLARE_WAITQUEUE(wait, current); -#endif - struct serial_state *state = info->state; - int retval; - int do_clocal = 0; - - /* - * If the device is in the middle of being closed, then block - * until it's done, and then try again. - */ - if (tty_hung_up_p(filp) || - (info->flags & ASYNC_CLOSING)) { - if (info->flags & ASYNC_CLOSING) - interruptible_sleep_on(&info->close_wait); -#ifdef SERIAL_DO_RESTART - if (info->flags & ASYNC_HUP_NOTIFY) - return -EAGAIN; - else - return -ERESTARTSYS; -#else - return -EAGAIN; -#endif - } - - /* - * If non-blocking mode is set, or the port is not enabled, - * then make the check up front and then exit. - * If this is an SMC port, we don't have modem control to wait - * for, so just get out here. - */ - if ((filp->f_flags & O_NONBLOCK) || - (tty->flags & (1 << TTY_IO_ERROR)) || - !(info->state->smc_scc_num & NUM_IS_SCC)) { - info->flags |= ASYNC_NORMAL_ACTIVE; - return 0; - } - - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - - /* - * Block waiting for the carrier detect and the line to become - * free (i.e., not in use by the callout). While we are in - * this loop, state->count is dropped by one, so that - * rs_close() knows when to free things. We restore it upon - * exit, either normal or abnormal. - */ - retval = 0; -#ifdef DO_THIS_LATER - add_wait_queue(&info->open_wait, &wait); -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready before block: ttys%d, count = %d\n", - state->line, state->count); -#endif - local_irq_disable(); - if (!tty_hung_up_p(filp)) - state->count--; - local_irq_enable(); - info->blocked_open++; - while (1) { - local_irq_disable(); - if (tty->termios->c_cflag & CBAUD) - serial_out(info, UART_MCR, - serial_inp(info, UART_MCR) | - (UART_MCR_DTR | UART_MCR_RTS)); - local_irq_enable(); - set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || - !(info->flags & ASYNC_INITIALIZED)) { -#ifdef SERIAL_DO_RESTART - if (info->flags & ASYNC_HUP_NOTIFY) - retval = -EAGAIN; - else - retval = -ERESTARTSYS; -#else - retval = -EAGAIN; -#endif - break; - } - if (!(info->flags & ASYNC_CLOSING) && - (do_clocal || (serial_in(info, UART_MSR) & - UART_MSR_DCD))) - break; - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready blocking: ttys%d, count = %d\n", - info->line, state->count); -#endif - tty_unlock(); - schedule(); - tty_lock(); - } - current->state = TASK_RUNNING; - remove_wait_queue(&info->open_wait, &wait); - if (!tty_hung_up_p(filp)) - state->count++; - info->blocked_open--; -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready after blocking: ttys%d, count = %d\n", - info->line, state->count); -#endif -#endif /* DO_THIS_LATER */ - if (retval) - return retval; - info->flags |= ASYNC_NORMAL_ACTIVE; - return 0; -} - -static int get_async_struct(int line, ser_info_t **ret_info) -{ - struct serial_state *sstate; - - sstate = rs_table + line; - if (sstate->info) { - sstate->count++; - *ret_info = (ser_info_t *)sstate->info; - return 0; - } - else { - return -ENOMEM; - } -} - -/* - * This routine is called whenever a serial port is opened. It - * enables interrupts for a serial port, linking in its async structure into - * the IRQ chain. It also performs the serial-specific - * initialization for the tty structure. - */ -static int rs_360_open(struct tty_struct *tty, struct file * filp) -{ - ser_info_t *info; - int retval, line; - - line = tty->index; - if ((line < 0) || (line >= NR_PORTS)) - return -ENODEV; - retval = get_async_struct(line, &info); - if (retval) - return retval; - if (serial_paranoia_check(info, tty->name, "rs_open")) - return -ENODEV; - -#ifdef SERIAL_DEBUG_OPEN - printk("rs_open %s, count = %d\n", tty->name, info->state->count); -#endif - tty->driver_data = info; - info->port.tty = tty; - - /* - * Start up serial port - */ - retval = startup(info); - if (retval) - return retval; - - retval = block_til_ready(tty, filp, info); - if (retval) { -#ifdef SERIAL_DEBUG_OPEN - printk("rs_open returning after block_til_ready with %d\n", - retval); -#endif - return retval; - } - -#ifdef SERIAL_DEBUG_OPEN - printk("rs_open %s successful...", tty->name); -#endif - return 0; -} - -/* - * /proc fs routines.... - */ - -static inline int line_info(char *buf, struct serial_state *state) -{ -#ifdef notdef - struct async_struct *info = state->info, scr_info; - char stat_buf[30], control, status; -#endif - int ret; - - ret = sprintf(buf, "%d: uart:%s port:%X irq:%d", - state->line, - (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC", - (unsigned int)(state->port), state->irq); - - if (!state->port || (state->type == PORT_UNKNOWN)) { - ret += sprintf(buf+ret, "\n"); - return ret; - } - -#ifdef notdef - /* - * Figure out the current RS-232 lines - */ - if (!info) { - info = &scr_info; /* This is just for serial_{in,out} */ - - info->magic = SERIAL_MAGIC; - info->port = state->port; - info->flags = state->flags; - info->quot = 0; - info->port.tty = NULL; - } - local_irq_disable(); - status = serial_in(info, UART_MSR); - control = info ? info->MCR : serial_in(info, UART_MCR); - local_irq_enable(); - - stat_buf[0] = 0; - stat_buf[1] = 0; - if (control & UART_MCR_RTS) - strcat(stat_buf, "|RTS"); - if (status & UART_MSR_CTS) - strcat(stat_buf, "|CTS"); - if (control & UART_MCR_DTR) - strcat(stat_buf, "|DTR"); - if (status & UART_MSR_DSR) - strcat(stat_buf, "|DSR"); - if (status & UART_MSR_DCD) - strcat(stat_buf, "|CD"); - if (status & UART_MSR_RI) - strcat(stat_buf, "|RI"); - - if (info->quot) { - ret += sprintf(buf+ret, " baud:%d", - state->baud_base / info->quot); - } - - ret += sprintf(buf+ret, " tx:%d rx:%d", - state->icount.tx, state->icount.rx); - - if (state->icount.frame) - ret += sprintf(buf+ret, " fe:%d", state->icount.frame); - - if (state->icount.parity) - ret += sprintf(buf+ret, " pe:%d", state->icount.parity); - - if (state->icount.brk) - ret += sprintf(buf+ret, " brk:%d", state->icount.brk); - - if (state->icount.overrun) - ret += sprintf(buf+ret, " oe:%d", state->icount.overrun); - - /* - * Last thing is the RS-232 status lines - */ - ret += sprintf(buf+ret, " %s\n", stat_buf+1); -#endif - return ret; -} - -int rs_360_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - int i, len = 0; - off_t begin = 0; - - len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version); - for (i = 0; i < NR_PORTS && len < 4000; i++) { - len += line_info(page + len, &rs_table[i]); - if (len+begin > off+count) - goto done; - if (len+begin < off) { - begin += len; - len = 0; - } - } - *eof = 1; -done: - if (off >= len+begin) - return 0; - *start = page + (begin-off); - return ((count < begin+len-off) ? count : begin+len-off); -} - -/* - * --------------------------------------------------------------------- - * rs_init() and friends - * - * rs_init() is called at boot-time to initialize the serial driver. - * --------------------------------------------------------------------- - */ - -/* - * This routine prints out the appropriate serial driver version - * number, and identifies which options were configured into this - * driver. - */ -static _INLINE_ void show_serial_version(void) -{ - printk(KERN_INFO "%s version %s\n", serial_name, serial_version); -} - - -/* - * The serial console driver used during boot. Note that these names - * clash with those found in "serial.c", so we currently can't support - * the 16xxx uarts and these at the same time. I will fix this to become - * an indirect function call from tty_io.c (or something). - */ - -#ifdef CONFIG_SERIAL_CONSOLE - -/* - * Print a string to the serial port trying not to disturb any possible - * real use of the port... - */ -static void my_console_write(int idx, const char *s, - unsigned count) -{ - struct serial_state *ser; - ser_info_t *info; - unsigned i; - QUICC_BD *bdp, *bdbase; - volatile struct smc_uart_pram *up; - volatile u_char *cp; - - ser = rs_table + idx; - - - /* If the port has been initialized for general use, we have - * to use the buffer descriptors allocated there. Otherwise, - * we simply use the single buffer allocated. - */ - if ((info = (ser_info_t *)ser->info) != NULL) { - bdp = info->tx_cur; - bdbase = info->tx_bd_base; - } - else { - /* Pointer to UART in parameter ram. - */ - /* up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; */ - up = &pquicc->pram[ser->port].scc.pothers.idma_smc.psmc.u; - - /* Get the address of the host memory buffer. - */ - bdp = bdbase = (QUICC_BD *)((uint)pquicc + (uint)up->tbase); - } - - /* - * We need to gracefully shut down the transmitter, disable - * interrupts, then send our bytes out. - */ - - /* - * Now, do each character. This is not as bad as it looks - * since this is a holding FIFO and not a transmitting FIFO. - * We could add the complexity of filling the entire transmit - * buffer, but we would just wait longer between accesses...... - */ - for (i = 0; i < count; i++, s++) { - /* Wait for transmitter fifo to empty. - * Ready indicates output is ready, and xmt is doing - * that, not that it is ready for us to send. - */ - while (bdp->status & BD_SC_READY); - - /* Send the character out. - */ - cp = bdp->buf; - *cp = *s; - - bdp->length = 1; - bdp->status |= BD_SC_READY; - - if (bdp->status & BD_SC_WRAP) - bdp = bdbase; - else - bdp++; - - /* if a LF, also do CR... */ - if (*s == 10) { - while (bdp->status & BD_SC_READY); - /* cp = __va(bdp->buf); */ - cp = bdp->buf; - *cp = 13; - bdp->length = 1; - bdp->status |= BD_SC_READY; - - if (bdp->status & BD_SC_WRAP) { - bdp = bdbase; - } - else { - bdp++; - } - } - } - - /* - * Finally, Wait for transmitter & holding register to empty - * and restore the IER - */ - while (bdp->status & BD_SC_READY); - - if (info) - info->tx_cur = (QUICC_BD *)bdp; -} - -static void serial_console_write(struct console *c, const char *s, - unsigned count) -{ -#ifdef CONFIG_KGDB - /* Try to let stub handle output. Returns true if it did. */ - if (kgdb_output_string(s, count)) - return; -#endif - my_console_write(c->index, s, count); -} - - - -/*void console_print_68360(const char *p) -{ - const char *cp = p; - int i; - - for (i=0;cp[i]!=0;i++); - - serial_console_write (p, i); - - //Comment this if you want to have a strict interrupt-driven output - //rs_fair_output(); - - return; -}*/ - - - - - - -#ifdef CONFIG_XMON -int -xmon_360_write(const char *s, unsigned count) -{ - my_console_write(0, s, count); - return(count); -} -#endif - -#ifdef CONFIG_KGDB -void -putDebugChar(char ch) -{ - my_console_write(0, &ch, 1); -} -#endif - -/* - * Receive character from the serial port. This only works well - * before the port is initialized for real use. - */ -static int my_console_wait_key(int idx, int xmon, char *obuf) -{ - struct serial_state *ser; - u_char c, *cp; - ser_info_t *info; - QUICC_BD *bdp; - volatile struct smc_uart_pram *up; - int i; - - ser = rs_table + idx; - - /* Get the address of the host memory buffer. - * If the port has been initialized for general use, we must - * use information from the port structure. - */ - if ((info = (ser_info_t *)ser->info)) - bdp = info->rx_cur; - else - /* bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_rbase]; */ - bdp = (QUICC_BD *)((uint)pquicc + (uint)up->tbase); - - /* Pointer to UART in parameter ram. - */ - /* up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; */ - up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u; - - /* - * We need to gracefully shut down the receiver, disable - * interrupts, then read the input. - * XMON just wants a poll. If no character, return -1, else - * return the character. - */ - if (!xmon) { - while (bdp->status & BD_SC_EMPTY); - } - else { - if (bdp->status & BD_SC_EMPTY) - return -1; - } - - cp = (char *)bdp->buf; - - if (obuf) { - i = c = bdp->length; - while (i-- > 0) - *obuf++ = *cp++; - } - else { - c = *cp; - } - bdp->status |= BD_SC_EMPTY; - - if (info) { - if (bdp->status & BD_SC_WRAP) { - bdp = info->rx_bd_base; - } - else { - bdp++; - } - info->rx_cur = (QUICC_BD *)bdp; - } - - return((int)c); -} - -static int serial_console_wait_key(struct console *co) -{ - return(my_console_wait_key(co->index, 0, NULL)); -} - -#ifdef CONFIG_XMON -int -xmon_360_read_poll(void) -{ - return(my_console_wait_key(0, 1, NULL)); -} - -int -xmon_360_read_char(void) -{ - return(my_console_wait_key(0, 0, NULL)); -} -#endif - -#ifdef CONFIG_KGDB -static char kgdb_buf[RX_BUF_SIZE], *kgdp; -static int kgdb_chars; - -unsigned char -getDebugChar(void) -{ - if (kgdb_chars <= 0) { - kgdb_chars = my_console_wait_key(0, 0, kgdb_buf); - kgdp = kgdb_buf; - } - kgdb_chars--; - - return(*kgdp++); -} - -void kgdb_interruptible(int state) -{ -} -void kgdb_map_scc(void) -{ - struct serial_state *ser; - uint mem_addr; - volatile QUICC_BD *bdp; - volatile smc_uart_t *up; - - cpmp = (cpm360_t *)&(((immap_t *)IMAP_ADDR)->im_cpm); - - /* To avoid data cache CPM DMA coherency problems, allocate a - * buffer in the CPM DPRAM. This will work until the CPM and - * serial ports are initialized. At that time a memory buffer - * will be allocated. - * The port is already initialized from the boot procedure, all - * we do here is give it a different buffer and make it a FIFO. - */ - - ser = rs_table; - - /* Right now, assume we are using SMCs. - */ - up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; - - /* Allocate space for an input FIFO, plus a few bytes for output. - * Allocate bytes to maintain word alignment. - */ - mem_addr = (uint)(&cpmp->cp_dpmem[0x1000]); - - /* Set the physical address of the host memory buffers in - * the buffer descriptors. - */ - bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_rbase]; - bdp->buf = mem_addr; - - bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_tbase]; - bdp->buf = mem_addr+RX_BUF_SIZE; - - up->smc_mrblr = RX_BUF_SIZE; /* receive buffer length */ - up->smc_maxidl = RX_BUF_SIZE; -} -#endif - -static struct tty_struct *serial_console_device(struct console *c, int *index) -{ - *index = c->index; - return serial_driver; -} - - -struct console sercons = { - .name = "ttyS", - .write = serial_console_write, - .device = serial_console_device, - .wait_key = serial_console_wait_key, - .setup = serial_console_setup, - .flags = CON_PRINTBUFFER, - .index = CONFIG_SERIAL_CONSOLE_PORT, -}; - - - -/* - * Register console. - */ -long console_360_init(long kmem_start, long kmem_end) -{ - register_console(&sercons); - /*register_console (console_print_68360); - 2.0.38 only required a write - function pointer. */ - return kmem_start; -} - -#endif - -/* Index in baud rate table of the default console baud rate. -*/ -static int baud_idx; - -static const struct tty_operations rs_360_ops = { - .owner = THIS_MODULE, - .open = rs_360_open, - .close = rs_360_close, - .write = rs_360_write, - .put_char = rs_360_put_char, - .write_room = rs_360_write_room, - .chars_in_buffer = rs_360_chars_in_buffer, - .flush_buffer = rs_360_flush_buffer, - .ioctl = rs_360_ioctl, - .throttle = rs_360_throttle, - .unthrottle = rs_360_unthrottle, - /* .send_xchar = rs_360_send_xchar, */ - .set_termios = rs_360_set_termios, - .stop = rs_360_stop, - .start = rs_360_start, - .hangup = rs_360_hangup, - /* .wait_until_sent = rs_360_wait_until_sent, */ - /* .read_proc = rs_360_read_proc, */ - .tiocmget = rs_360_tiocmget, - .tiocmset = rs_360_tiocmset, - .get_icount = rs_360_get_icount, -}; - -static int __init rs_360_init(void) -{ - struct serial_state * state; - ser_info_t *info; - void *mem_addr; - uint dp_addr, iobits; - int i, j, idx; - ushort chan; - QUICC_BD *bdp; - volatile QUICC *cp; - volatile struct smc_regs *sp; - volatile struct smc_uart_pram *up; - volatile struct scc_regs *scp; - volatile struct uart_pram *sup; - /* volatile immap_t *immap; */ - - serial_driver = alloc_tty_driver(NR_PORTS); - if (!serial_driver) - return -1; - - show_serial_version(); - - serial_driver->name = "ttyS"; - serial_driver->major = TTY_MAJOR; - serial_driver->minor_start = 64; - serial_driver->type = TTY_DRIVER_TYPE_SERIAL; - serial_driver->subtype = SERIAL_TYPE_NORMAL; - serial_driver->init_termios = tty_std_termios; - serial_driver->init_termios.c_cflag = - baud_idx | CS8 | CREAD | HUPCL | CLOCAL; - serial_driver->flags = TTY_DRIVER_REAL_RAW; - tty_set_operations(serial_driver, &rs_360_ops); - - if (tty_register_driver(serial_driver)) - panic("Couldn't register serial driver\n"); - - cp = pquicc; /* Get pointer to Communication Processor */ - /* immap = (immap_t *)IMAP_ADDR; */ /* and to internal registers */ - - - /* Configure SCC2, SCC3, and SCC4 instead of port A parallel I/O. - */ - /* The "standard" configuration through the 860. - */ -/* immap->im_ioport.iop_papar |= 0x00fc; */ -/* immap->im_ioport.iop_padir &= ~0x00fc; */ -/* immap->im_ioport.iop_paodr &= ~0x00fc; */ - cp->pio_papar |= 0x00fc; - cp->pio_padir &= ~0x00fc; - /* cp->pio_paodr &= ~0x00fc; */ - - - /* Since we don't yet do modem control, connect the port C pins - * as general purpose I/O. This will assert CTS and CD for the - * SCC ports. - */ - /* FIXME: see 360um p.7-365 and 860um p.34-12 - * I can't make sense of these bits - mleslie*/ -/* immap->im_ioport.iop_pcdir |= 0x03c6; */ -/* immap->im_ioport.iop_pcpar &= ~0x03c6; */ - -/* cp->pio_pcdir |= 0x03c6; */ -/* cp->pio_pcpar &= ~0x03c6; */ - - - - /* Connect SCC2 and SCC3 to NMSI. Connect BRG3 to SCC2 and - * BRG4 to SCC3. - */ - cp->si_sicr &= ~0x00ffff00; - cp->si_sicr |= 0x001b1200; - -#ifdef CONFIG_PP04 - /* Frequentis PP04 forced to RS-232 until we know better. - * Port C 12 and 13 low enables RS-232 on SCC3 and SCC4. - */ - immap->im_ioport.iop_pcdir |= 0x000c; - immap->im_ioport.iop_pcpar &= ~0x000c; - immap->im_ioport.iop_pcdat &= ~0x000c; - - /* This enables the TX driver. - */ - cp->cp_pbpar &= ~0x6000; - cp->cp_pbdat &= ~0x6000; -#endif - - for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { - state->magic = SSTATE_MAGIC; - state->line = i; - state->type = PORT_UNKNOWN; - state->custom_divisor = 0; - state->close_delay = 5*HZ/10; - state->closing_wait = 30*HZ; - state->icount.cts = state->icount.dsr = - state->icount.rng = state->icount.dcd = 0; - state->icount.rx = state->icount.tx = 0; - state->icount.frame = state->icount.parity = 0; - state->icount.overrun = state->icount.brk = 0; - printk(KERN_INFO "ttyS%d at irq 0x%02x is an %s\n", - i, (unsigned int)(state->irq), - (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC"); - -#ifdef CONFIG_SERIAL_CONSOLE - /* If we just printed the message on the console port, and - * we are about to initialize it for general use, we have - * to wait a couple of character times for the CR/NL to - * make it out of the transmit buffer. - */ - if (i == CONFIG_SERIAL_CONSOLE_PORT) - mdelay(8); - - -/* idx = PORT_NUM(info->state->smc_scc_num); */ -/* if (info->state->smc_scc_num & NUM_IS_SCC) */ -/* chan = scc_chan_map[idx]; */ -/* else */ -/* chan = smc_chan_map[idx]; */ - -/* cp->cp_cr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG; */ -/* while (cp->cp_cr & CPM_CR_FLG); */ - -#endif - /* info = kmalloc(sizeof(ser_info_t), GFP_KERNEL); */ - info = &quicc_ser_info[i]; - if (info) { - memset (info, 0, sizeof(ser_info_t)); - info->magic = SERIAL_MAGIC; - info->line = i; - info->flags = state->flags; - INIT_WORK(&info->tqueue, do_softint, info); - INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info); - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); - info->state = state; - state->info = (struct async_struct *)info; - - /* We need to allocate a transmit and receive buffer - * descriptors from dual port ram, and a character - * buffer area from host mem. - */ - dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * RX_NUM_FIFO); - - /* Allocate space for FIFOs in the host memory. - * (for now this is from a static array of buffers :( - */ - /* mem_addr = m360_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE); */ - /* mem_addr = kmalloc (RX_NUM_FIFO * RX_BUF_SIZE, GFP_BUFFER); */ - mem_addr = &rx_buf_pool[i * RX_NUM_FIFO * RX_BUF_SIZE]; - - /* Set the physical address of the host memory - * buffers in the buffer descriptors, and the - * virtual address for us to work with. - */ - bdp = (QUICC_BD *)((uint)pquicc + dp_addr); - info->rx_cur = info->rx_bd_base = bdp; - - /* initialize rx buffer descriptors */ - for (j=0; j<(RX_NUM_FIFO-1); j++) { - bdp->buf = &rx_buf_pool[(i * RX_NUM_FIFO + j ) * RX_BUF_SIZE]; - bdp->status = BD_SC_EMPTY | BD_SC_INTRPT; - mem_addr += RX_BUF_SIZE; - bdp++; - } - bdp->buf = &rx_buf_pool[(i * RX_NUM_FIFO + j ) * RX_BUF_SIZE]; - bdp->status = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT; - - - idx = PORT_NUM(info->state->smc_scc_num); - if (info->state->smc_scc_num & NUM_IS_SCC) { - -#if defined (CONFIG_UCQUICC) && 1 - /* set the transceiver mode to RS232 */ - sipex_mode_bits &= ~(uint)SIPEX_MODE(idx,0x0f); /* clear current mode */ - sipex_mode_bits |= (uint)SIPEX_MODE(idx,0x02); - *(uint *)_periph_base = sipex_mode_bits; - /* printk ("sipex bits = 0x%08x\n", sipex_mode_bits); */ -#endif - } - - dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * TX_NUM_FIFO); - - /* Allocate space for FIFOs in the host memory. - */ - /* mem_addr = m360_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE); */ - /* mem_addr = kmalloc (TX_NUM_FIFO * TX_BUF_SIZE, GFP_BUFFER); */ - mem_addr = &tx_buf_pool[i * TX_NUM_FIFO * TX_BUF_SIZE]; - - /* Set the physical address of the host memory - * buffers in the buffer descriptors, and the - * virtual address for us to work with. - */ - /* bdp = (QUICC_BD *)&cp->cp_dpmem[dp_addr]; */ - bdp = (QUICC_BD *)((uint)pquicc + dp_addr); - info->tx_cur = info->tx_bd_base = (QUICC_BD *)bdp; - - /* initialize tx buffer descriptors */ - for (j=0; j<(TX_NUM_FIFO-1); j++) { - bdp->buf = &tx_buf_pool[(i * TX_NUM_FIFO + j ) * TX_BUF_SIZE]; - bdp->status = BD_SC_INTRPT; - mem_addr += TX_BUF_SIZE; - bdp++; - } - bdp->buf = &tx_buf_pool[(i * TX_NUM_FIFO + j ) * TX_BUF_SIZE]; - bdp->status = (BD_SC_WRAP | BD_SC_INTRPT); - - if (info->state->smc_scc_num & NUM_IS_SCC) { - scp = &pquicc->scc_regs[idx]; - sup = &pquicc->pram[info->state->port].scc.pscc.u; - sup->rbase = dp_addr; - sup->tbase = dp_addr; - - /* Set up the uart parameters in the - * parameter ram. - */ - sup->rfcr = SMC_EB; - sup->tfcr = SMC_EB; - - /* Set this to 1 for now, so we get single - * character interrupts. Using idle character - * time requires some additional tuning. - */ - sup->mrblr = 1; - sup->max_idl = 0; - sup->brkcr = 1; - sup->parec = 0; - sup->frmer = 0; - sup->nosec = 0; - sup->brkec = 0; - sup->uaddr1 = 0; - sup->uaddr2 = 0; - sup->toseq = 0; - { - int i; - for (i=0;i<8;i++) - sup->cc[i] = 0x8000; - } - sup->rccm = 0xc0ff; - - /* Send the CPM an initialize command. - */ - chan = scc_chan_map[idx]; - - /* execute the INIT RX & TX PARAMS command for this channel. */ - cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cr & CPM_CR_FLG); - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - scp->scc_gsmr.w.high = 0; - scp->scc_gsmr.w.low = - (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); - - /* Disable all interrupts and clear all pending - * events. - */ - scp->scc_sccm = 0; - scp->scc_scce = 0xffff; - scp->scc_dsr = 0x7e7e; - scp->scc_psmr = 0x3000; - - /* If the port is the console, enable Rx and Tx. - */ -#ifdef CONFIG_SERIAL_CONSOLE - if (i == CONFIG_SERIAL_CONSOLE_PORT) - scp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); -#endif - } - else { - /* Configure SMCs Tx/Rx instead of port B - * parallel I/O. - */ - up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u; - up->rbase = dp_addr; - - iobits = 0xc0 << (idx * 4); - cp->pip_pbpar |= iobits; - cp->pip_pbdir &= ~iobits; - cp->pip_pbodr &= ~iobits; - - - /* Connect the baud rate generator to the - * SMC based upon index in rs_table. Also - * make sure it is connected to NMSI. - */ - cp->si_simode &= ~(0xffff << (idx * 16)); - cp->si_simode |= (i << ((idx * 16) + 12)); - - up->tbase = dp_addr; - - /* Set up the uart parameters in the - * parameter ram. - */ - up->rfcr = SMC_EB; - up->tfcr = SMC_EB; - - /* Set this to 1 for now, so we get single - * character interrupts. Using idle character - * time requires some additional tuning. - */ - up->mrblr = 1; - up->max_idl = 0; - up->brkcr = 1; - - /* Send the CPM an initialize command. - */ - chan = smc_chan_map[idx]; - - cp->cp_cr = mk_cr_cmd(chan, - CPM_CR_INIT_TRX) | CPM_CR_FLG; -#ifdef CONFIG_SERIAL_CONSOLE - if (i == CONFIG_SERIAL_CONSOLE_PORT) - printk(""); -#endif - while (cp->cp_cr & CPM_CR_FLG); - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - sp = &cp->smc_regs[idx]; - sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; - - /* Disable all interrupts and clear all pending - * events. - */ - sp->smc_smcm = 0; - sp->smc_smce = 0xff; - - /* If the port is the console, enable Rx and Tx. - */ -#ifdef CONFIG_SERIAL_CONSOLE - if (i == CONFIG_SERIAL_CONSOLE_PORT) - sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; -#endif - } - - /* Install interrupt handler. - */ - /* cpm_install_handler(IRQ_MACHSPEC | state->irq, rs_360_interrupt, info); */ - /*request_irq(IRQ_MACHSPEC | state->irq, rs_360_interrupt, */ - request_irq(state->irq, rs_360_interrupt, 0, "ttyS", - (void *)info); - - /* Set up the baud rate generator. - */ - m360_cpm_setbrg(i, baud_table[baud_idx]); - - } - } - - return 0; -} -module_init(rs_360_init); - -/* This must always be called before the rs_360_init() function, otherwise - * it blows away the port control information. - */ -//static int __init serial_console_setup( struct console *co, char *options) -int serial_console_setup( struct console *co, char *options) -{ - struct serial_state *ser; - uint mem_addr, dp_addr, bidx, idx, iobits; - ushort chan; - QUICC_BD *bdp; - volatile QUICC *cp; - volatile struct smc_regs *sp; - volatile struct scc_regs *scp; - volatile struct smc_uart_pram *up; - volatile struct uart_pram *sup; - -/* mleslie TODO: - * add something to the 68k bootloader to store a desired initial console baud rate */ - -/* bd_t *bd; */ /* a board info struct used by EPPC-bug */ -/* bd = (bd_t *)__res; */ - - for (bidx = 0; bidx < (sizeof(baud_table) / sizeof(int)); bidx++) - /* if (bd->bi_baudrate == baud_table[bidx]) */ - if (CONSOLE_BAUDRATE == baud_table[bidx]) - break; - - /* co->cflag = CREAD|CLOCAL|bidx|CS8; */ - baud_idx = bidx; - - ser = rs_table + CONFIG_SERIAL_CONSOLE_PORT; - - cp = pquicc; /* Get pointer to Communication Processor */ - - idx = PORT_NUM(ser->smc_scc_num); - if (ser->smc_scc_num & NUM_IS_SCC) { - - /* TODO: need to set up SCC pin assignment etc. here */ - - } - else { - iobits = 0xc0 << (idx * 4); - cp->pip_pbpar |= iobits; - cp->pip_pbdir &= ~iobits; - cp->pip_pbodr &= ~iobits; - - /* Connect the baud rate generator to the - * SMC based upon index in rs_table. Also - * make sure it is connected to NMSI. - */ - cp->si_simode &= ~(0xffff << (idx * 16)); - cp->si_simode |= (idx << ((idx * 16) + 12)); - } - - /* When we get here, the CPM has been reset, so we need - * to configure the port. - * We need to allocate a transmit and receive buffer descriptor - * from dual port ram, and a character buffer area from host mem. - */ - - /* Allocate space for two buffer descriptors in the DP ram. - */ - dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * CONSOLE_NUM_FIFO); - - /* Allocate space for two 2 byte FIFOs in the host memory. - */ - /* mem_addr = m360_cpm_hostalloc(8); */ - mem_addr = (uint)console_fifos; - - - /* Set the physical address of the host memory buffers in - * the buffer descriptors. - */ - /* bdp = (QUICC_BD *)&cp->cp_dpmem[dp_addr]; */ - bdp = (QUICC_BD *)((uint)pquicc + dp_addr); - bdp->buf = (char *)mem_addr; - (bdp+1)->buf = (char *)(mem_addr+4); - - /* For the receive, set empty and wrap. - * For transmit, set wrap. - */ - bdp->status = BD_SC_EMPTY | BD_SC_WRAP; - (bdp+1)->status = BD_SC_WRAP; - - /* Set up the uart parameters in the parameter ram. - */ - if (ser->smc_scc_num & NUM_IS_SCC) { - scp = &cp->scc_regs[idx]; - /* sup = (scc_uart_t *)&cp->cp_dparam[ser->port]; */ - sup = &pquicc->pram[ser->port].scc.pscc.u; - - sup->rbase = dp_addr; - sup->tbase = dp_addr + sizeof(QUICC_BD); - - /* Set up the uart parameters in the - * parameter ram. - */ - sup->rfcr = SMC_EB; - sup->tfcr = SMC_EB; - - /* Set this to 1 for now, so we get single - * character interrupts. Using idle character - * time requires some additional tuning. - */ - sup->mrblr = 1; - sup->max_idl = 0; - sup->brkcr = 1; - sup->parec = 0; - sup->frmer = 0; - sup->nosec = 0; - sup->brkec = 0; - sup->uaddr1 = 0; - sup->uaddr2 = 0; - sup->toseq = 0; - { - int i; - for (i=0;i<8;i++) - sup->cc[i] = 0x8000; - } - sup->rccm = 0xc0ff; - - /* Send the CPM an initialize command. - */ - chan = scc_chan_map[idx]; - - cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cr & CPM_CR_FLG); - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - scp->scc_gsmr.w.high = 0; - scp->scc_gsmr.w.low = - (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); - - /* Disable all interrupts and clear all pending - * events. - */ - scp->scc_sccm = 0; - scp->scc_scce = 0xffff; - scp->scc_dsr = 0x7e7e; - scp->scc_psmr = 0x3000; - - scp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); - - } - else { - /* up = (smc_uart_t *)&cp->cp_dparam[ser->port]; */ - up = &pquicc->pram[ser->port].scc.pothers.idma_smc.psmc.u; - - up->rbase = dp_addr; /* Base of receive buffer desc. */ - up->tbase = dp_addr+sizeof(QUICC_BD); /* Base of xmt buffer desc. */ - up->rfcr = SMC_EB; - up->tfcr = SMC_EB; - - /* Set this to 1 for now, so we get single character interrupts. - */ - up->mrblr = 1; /* receive buffer length */ - up->max_idl = 0; /* wait forever for next char */ - - /* Send the CPM an initialize command. - */ - chan = smc_chan_map[idx]; - cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cr & CPM_CR_FLG); - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - sp = &cp->smc_regs[idx]; - sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; - - /* And finally, enable Rx and Tx. - */ - sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; - } - - /* Set up the baud rate generator. - */ - /* m360_cpm_setbrg((ser - rs_table), bd->bi_baudrate); */ - m360_cpm_setbrg((ser - rs_table), CONSOLE_BAUDRATE); - - return 0; -} - -/* - * Local variables: - * c-indent-level: 4 - * c-basic-offset: 4 - * tab-width: 4 - * End: - */ diff --git a/trunk/drivers/staging/serial/Kconfig b/trunk/drivers/staging/serial/Kconfig deleted file mode 100644 index 9489688397e0..000000000000 --- a/trunk/drivers/staging/serial/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -config SERIAL_68360_SMC - bool "68360 SMC uart support" - depends on M68360 - help - This driver supports the SMC serial ports of the Motorola 68360 CPU. - -config SERIAL_68360_SCC - bool "68360 SCC uart support" - depends on M68360 - help - This driver supports the SCC serial ports of the Motorola 68360 CPU. - -config SERIAL_68360 - bool - depends on SERIAL_68360_SMC || SERIAL_68360_SCC - default y diff --git a/trunk/drivers/staging/serial/Makefile b/trunk/drivers/staging/serial/Makefile deleted file mode 100644 index 37a6a0b35fba..000000000000 --- a/trunk/drivers/staging/serial/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_SERIAL_68360) += 68360serial.o diff --git a/trunk/drivers/staging/serial/TODO b/trunk/drivers/staging/serial/TODO deleted file mode 100644 index a19cda81dab4..000000000000 --- a/trunk/drivers/staging/serial/TODO +++ /dev/null @@ -1,6 +0,0 @@ -These are a few serial drivers that either do not build, or do not work if they -do build, or if they seem to work, are for obsolete hardware, or are full of -unfixable races and no one uses them anymore. - -If no one steps up to adopt any of these drivers, they will be removed -in the 3.4 release. diff --git a/trunk/drivers/staging/serqt_usb2/serqt_usb2.c b/trunk/drivers/staging/serqt_usb2/serqt_usb2.c index ae1d815e2a53..43045db982d4 100644 --- a/trunk/drivers/staging/serqt_usb2/serqt_usb2.c +++ b/trunk/drivers/staging/serqt_usb2/serqt_usb2.c @@ -41,13 +41,6 @@ static bool debug; #define QUATECH_HSU200B 0xC0B1 /* HSU200B */ #define QUATECH_HSU200C 0xC0B2 /* HSU200C */ #define QUATECH_HSU200D 0xC0B3 /* HSU200D */ -#define QUATECH_SSU100_2 0xC120 /* SSU100_2 */ -#define QUATECH_DSU100_2 0xC140 /* DSU100_2 */ -#define QUATECH_DSU400_2 0xC150 /* DSU400_2 */ -#define QUATECH_QSU100_2 0xC160 /* QSU100_2 */ -#define QUATECH_QSU400_2 0xC170 /* QSU400_2 */ -#define QUATECH_ESU400_2 0xC180 /* ESU400_2 */ -#define QUATECH_ESU100_2 0xC1A0 /* ESU100_2 */ #define QT_SET_GET_DEVICE 0xc2 #define QT_OPEN_CLOSE_CHANNEL 0xca @@ -125,7 +118,7 @@ static bool debug; #define MODEM_CTRL 0x40 #define RS232_MODE 0x00 -static const struct usb_device_id serqt_id_table[] = { +static const struct usb_device_id id_table[] = { {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU200)}, {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU100)}, {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU200)}, @@ -143,17 +136,9 @@ static const struct usb_device_id serqt_id_table[] = { {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_HSU200B)}, {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_HSU200C)}, {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_HSU200D)}, - {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU100_2)}, - {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU100_2)}, - {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU400_2)}, - {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU100_2)}, - {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU400_2)}, - {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU400_2)}, - {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU100_2)}, {} /* Terminating entry */ }; - -MODULE_DEVICE_TABLE(usb, serqt_id_table); +MODULE_DEVICE_TABLE(usb, id_table); struct qt_get_device_data { __u8 porta; @@ -195,13 +180,6 @@ struct quatech_port { char closePending; }; -static struct usb_driver serqt_usb_driver = { - .name = "quatech-usb-serial", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = serqt_id_table, -}; - static int port_paranoia_check(struct usb_serial_port *port, const char *function) { @@ -304,8 +282,6 @@ static void qt_write_bulk_callback(struct urb *urb) quatech_port = urb->context; - dbg("%s - port %d\n", __func__, quatech_port->port_num); - tty = tty_port_tty_get(&quatech_port->port->port); if (tty) @@ -351,7 +327,6 @@ static void qt_read_bulk_callback(struct urb *urb) /* index = MINOR(port->tty->device) - serial->minor; */ index = tty->index - serial->minor; - dbg("%s - port %d\n", __func__, port->number); dbg("%s - port->RxHolding = %d\n", __func__, qt_port->RxHolding); if (port_paranoia_check(port, __func__) != 0) { @@ -726,8 +701,6 @@ static int qt_startup(struct usb_serial *serial) int i; int status; - dbg("enterting %s", __func__); - /* Now setup per port private data */ for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; @@ -855,8 +828,6 @@ static void qt_release(struct usb_serial *serial) struct quatech_port *qt_port; int i; - dbg("enterting %s", __func__); - for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; if (!port) @@ -882,8 +853,6 @@ static int qt_open(struct tty_struct *tty, if (port_paranoia_check(port, __func__)) return -ENODEV; - dbg("%s - port %d\n", __func__, port->number); - serial = port->serial; if (serial_paranoia_check(serial, __func__)) @@ -1006,8 +975,6 @@ static int qt_chars_in_buffer(struct tty_struct *tty) serial = get_usb_serial(port, __func__); - dbg("%s - port %d\n", __func__, port->number); - if (serial->num_bulk_out) { if (port->write_urb->status == -EINPROGRESS) chars = port->write_urb->transfer_buffer_length; @@ -1054,8 +1021,6 @@ static void qt_close(struct usb_serial_port *port) unsigned int index; status = 0; - dbg("%s - port %d\n", __func__, port->number); - tty = tty_port_tty_get(&port->port); index = tty->index - serial->minor; @@ -1109,8 +1074,6 @@ static int qt_write(struct tty_struct *tty, struct usb_serial_port *port, if (serial == NULL) return -ENODEV; - dbg("%s - port %d\n", __func__, port->number); - if (count == 0) { dbg("%s - write request of 0 bytes\n", __func__); return 0; @@ -1173,8 +1136,6 @@ static int qt_write_room(struct tty_struct *tty) mutex_lock(&qt_port->lock); - dbg("%s - port %d\n", __func__, port->number); - if (serial->num_bulk_out) { if (port->write_urb->status != -EINPROGRESS) retval = port->bulk_out_size; @@ -1241,8 +1202,6 @@ static void qt_set_termios(struct tty_struct *tty, int baud, divisor, remainder; int status; - dbg("%s", __func__); - index = tty->index - port->serial->minor; switch (cflag) { @@ -1365,8 +1324,6 @@ static void qt_break(struct tty_struct *tty, int break_state) mutex_lock(&qt_port->lock); - dbg("%s - port %d\n", __func__, port->number); - result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), QT_BREAK_CONTROL, 0x40, onoff, index, NULL, 0, 300); @@ -1385,8 +1342,6 @@ static inline int qt_real_tiocmget(struct tty_struct *tty, int status; unsigned int index; - dbg("%s - port %d, tty =0x%p\n", __func__, port->number, tty); - index = tty->index - serial->minor; status = BoxGetRegister(port->serial, index, MODEM_CONTROL_REGISTER, &mcr); @@ -1426,8 +1381,6 @@ static inline int qt_real_tiocmset(struct tty_struct *tty, int status; unsigned int index; - dbg("%s - port %d\n", __func__, port->number); - index = tty->index - serial->minor; status = BoxGetRegister(port->serial, index, MODEM_CONTROL_REGISTER, &mcr); @@ -1461,18 +1414,11 @@ static int qt_tiocmget(struct tty_struct *tty) struct quatech_port *qt_port = qt_get_port_private(port); int retval = -ENODEV; - dbg("In %s\n", __func__); - if (!serial) return -ENODEV; mutex_lock(&qt_port->lock); - - dbg("%s - port %d\n", __func__, port->number); - dbg("%s - port->RxHolding = %d\n", __func__, qt_port->RxHolding); - retval = qt_real_tiocmget(tty, port, serial); - mutex_unlock(&qt_port->lock); return retval; } @@ -1486,18 +1432,11 @@ static int qt_tiocmset(struct tty_struct *tty, struct quatech_port *qt_port = qt_get_port_private(port); int retval = -ENODEV; - dbg("In %s\n", __func__); - if (!serial) return -ENODEV; mutex_lock(&qt_port->lock); - - dbg("%s - port %d\n", __func__, port->number); - dbg("%s - qt_port->RxHolding = %d\n", __func__, qt_port->RxHolding); - retval = qt_real_tiocmset(tty, port, serial, set); - mutex_unlock(&qt_port->lock); return retval; } @@ -1508,8 +1447,6 @@ static void qt_throttle(struct tty_struct *tty) struct usb_serial *serial = get_usb_serial(port, __func__); struct quatech_port *qt_port; - dbg("%s - port %d\n", __func__, port->number); - if (!serial) return; @@ -1519,7 +1456,6 @@ static void qt_throttle(struct tty_struct *tty) /* pass on to the driver specific version of this function */ qt_port->RxHolding = 1; - dbg("%s - port->RxHolding = 1\n", __func__); mutex_unlock(&qt_port->lock); return; @@ -1539,8 +1475,6 @@ static void qt_unthrottle(struct tty_struct *tty) mutex_lock(&qt_port->lock); - dbg("%s - port %d\n", __func__, port->number); - if (qt_port->RxHolding == 1) { dbg("%s -qt_port->RxHolding == 1\n", __func__); @@ -1559,8 +1493,9 @@ static void qt_unthrottle(struct tty_struct *tty) qt_read_bulk_callback, port); result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) - err("%s - failed restarting read urb, error %d", - __func__, result); + dev_err(&port->dev, + "%s - failed restarting read urb, error %d\n", + __func__, result); } } mutex_unlock(&qt_port->lock); @@ -1589,7 +1524,7 @@ static struct usb_serial_driver quatech_device = { .name = "serqt", }, .description = DRIVER_DESC, - .id_table = serqt_id_table, + .id_table = id_table, .num_ports = 8, .open = qt_open, .close = qt_close, @@ -1612,7 +1547,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &quatech_device, NULL }; -module_usb_serial_driver(serqt_usb_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/trunk/drivers/staging/sm7xx/smtcfb.c b/trunk/drivers/staging/sm7xx/smtcfb.c index 83c582ed12e5..746c4cd5d30e 100644 --- a/trunk/drivers/staging/sm7xx/smtcfb.c +++ b/trunk/drivers/staging/sm7xx/smtcfb.c @@ -2,31 +2,19 @@ * Silicon Motion SM7XX frame buffer device * * Copyright (C) 2006 Silicon Motion Technology Corp. - * Authors: Ge Wang, gewang@siliconmotion.com - * Boyod boyod.yang@siliconmotion.com.cn + * Authors: Ge Wang, gewang@siliconmotion.com + * Boyod boyod.yang@siliconmotion.com.cn * * Copyright (C) 2009 Lemote, Inc. - * Author: Wu Zhangjin, wuzhangjin@gmail.com + * Author: Wu Zhangjin, wuzhangjin@gmail.com * * Copyright (C) 2011 Igalia, S.L. - * Author: Javier M. Mellid + * Author: Javier M. Mellid * - * 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 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. * - * Version 0.10.26192.21.01 - * - Add PowerPC/Big endian support - * - Verified on 2.6.19.2 - * Boyod.yang - * - * Version 0.09.2621.00.01 - * - Only support Linux Kernel's version 2.6.21 - * Boyod.yang - * - * Version 0.09 - * - Only support Linux Kernel's version 2.6.12 - * Boyod.yang */ #include @@ -45,40 +33,19 @@ #include "smtcfb.h" -#ifdef DEBUG -#define smdbg(format, arg...) printk(KERN_DEBUG format , ## arg) -#else -#define smdbg(format, arg...) -#endif - struct screen_info smtc_screen_info; /* * Private structure */ struct smtcfb_info { - /* - * The following is a pointer to be passed into the - * functions below. The modules outside the main - * voyager.c driver have no knowledge as to what - * is within this structure. - */ struct fb_info fb; - struct display_switch *dispsw; - struct pci_dev *dev; - signed int currcon; - + struct pci_dev *pdev; struct { u8 red, green, blue; } palette[NR_RGB]; - u_int palette_size; -}; -struct par_info { - /* - * Hardware - */ u16 chipID; unsigned char __iomem *m_pMMIO; char __iomem *m_pLFB; @@ -121,15 +88,6 @@ char __iomem *smtc_RegBaseAddress; /* Memory Map IO starting address */ char __iomem *smtc_VRAMBaseAddress; /* video memory starting address */ static u32 colreg[17]; -static struct par_info hw; /* hardware information */ - -u16 smtc_ChipIDs[] = { - 0x710, - 0x712, - 0x720 -}; - -#define numSMTCchipIDs ARRAY_SIZE(smtc_ChipIDs) static struct fb_var_screeninfo smtcfb_var = { .xres = 1024, @@ -154,30 +112,29 @@ static struct fb_fix_screeninfo smtcfb_fix = { .accel = FB_ACCEL_SMI_LYNX, }; -static void sm712_set_timing(struct smtcfb_info *sfb, - struct par_info *ppar_info) +static void sm712_set_timing(struct smtcfb_info *sfb) { int i = 0, j = 0; u32 m_nScreenStride; - smdbg("\nppar_info->width = %d ppar_info->height = %d" - "sfb->fb.var.bits_per_pixel = %d ppar_info->hz = %d\n", - ppar_info->width, ppar_info->height, - sfb->fb.var.bits_per_pixel, ppar_info->hz); + dev_dbg(&sfb->pdev->dev, + "sfb->width=%d sfb->height=%d " + "sfb->fb.var.bits_per_pixel=%d sfb->hz=%d\n", + sfb->width, sfb->height, sfb->fb.var.bits_per_pixel, sfb->hz); for (j = 0; j < numVGAModes; j++) { - if (VGAMode[j].mmSizeX == ppar_info->width && - VGAMode[j].mmSizeY == ppar_info->height && + if (VGAMode[j].mmSizeX == sfb->width && + VGAMode[j].mmSizeY == sfb->height && VGAMode[j].bpp == sfb->fb.var.bits_per_pixel && - VGAMode[j].hz == ppar_info->hz) { + VGAMode[j].hz == sfb->hz) { - smdbg("\nVGAMode[j].mmSizeX = %d VGAMode[j].mmSizeY =" - "%d VGAMode[j].bpp = %d" - "VGAMode[j].hz=%d\n", - VGAMode[j].mmSizeX, VGAMode[j].mmSizeY, - VGAMode[j].bpp, VGAMode[j].hz); + dev_dbg(&sfb->pdev->dev, + "VGAMode[j].mmSizeX=%d VGAMode[j].mmSizeY=%d " + "VGAMode[j].bpp=%d VGAMode[j].hz=%d\n", + VGAMode[j].mmSizeX, VGAMode[j].mmSizeY, + VGAMode[j].bpp, VGAMode[j].hz); - smdbg("VGAMode index=%d\n", j); + dev_dbg(&sfb->pdev->dev, "VGAMode index=%d\n", j); smtc_mmiowb(0x0, 0x3c6); @@ -238,37 +195,37 @@ static void sm712_set_timing(struct smtcfb_info *sfb, smtc_mmiowb(0x67, 0x3c2); /* set VPR registers */ - writel(0x0, ppar_info->m_pVPR + 0x0C); - writel(0x0, ppar_info->m_pVPR + 0x40); + writel(0x0, sfb->m_pVPR + 0x0C); + writel(0x0, sfb->m_pVPR + 0x40); /* set data width */ m_nScreenStride = - (ppar_info->width * sfb->fb.var.bits_per_pixel) / 64; + (sfb->width * sfb->fb.var.bits_per_pixel) / 64; switch (sfb->fb.var.bits_per_pixel) { case 8: - writel(0x0, ppar_info->m_pVPR + 0x0); + writel(0x0, sfb->m_pVPR + 0x0); break; case 16: - writel(0x00020000, ppar_info->m_pVPR + 0x0); + writel(0x00020000, sfb->m_pVPR + 0x0); break; case 24: - writel(0x00040000, ppar_info->m_pVPR + 0x0); + writel(0x00040000, sfb->m_pVPR + 0x0); break; case 32: - writel(0x00030000, ppar_info->m_pVPR + 0x0); + writel(0x00030000, sfb->m_pVPR + 0x0); break; } writel((u32) (((m_nScreenStride + 2) << 16) | m_nScreenStride), - ppar_info->m_pVPR + 0x10); + sfb->m_pVPR + 0x10); } static void sm712_setpalette(int regno, unsigned red, unsigned green, unsigned blue, struct fb_info *info) { - struct par_info *cur_par = (struct par_info *)info->par; + struct smtcfb_info *sfb = info->par; - if (cur_par->BaseAddressInVRAM) + if (sfb->BaseAddressInVRAM) /* * second display palette for dual head. Enable CRT RAM, 6-bit * RAM @@ -283,14 +240,13 @@ static void sm712_setpalette(int regno, unsigned red, unsigned green, smtc_mmiowb(blue >> 10, dac_val); } -static void smtc_set_timing(struct smtcfb_info *sfb, struct par_info - *ppar_info) +static void smtc_set_timing(struct smtcfb_info *sfb) { - switch (ppar_info->chipID) { + switch (sfb->chipID) { case 0x710: case 0x712: case 0x720: - sm712_set_timing(sfb, ppar_info); + sm712_set_timing(sfb); break; } } @@ -310,7 +266,7 @@ static inline unsigned int chan_to_field(unsigned int chan, return chan << bf->offset; } -static int cfb_blank(int blank_mode, struct fb_info *info) +static int smtc_blank(int blank_mode, struct fb_info *info) { /* clear DPMS setting */ switch (blank_mode) { @@ -660,10 +616,10 @@ void smtcfb_setmode(struct smtcfb_info *sfb) break; } - hw.width = sfb->fb.var.xres; - hw.height = sfb->fb.var.yres; - hw.hz = 60; - smtc_set_timing(sfb, &hw); + sfb->width = sfb->fb.var.xres; + sfb->height = sfb->fb.var.yres; + sfb->hz = 60; + smtc_set_timing(sfb); } static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info) @@ -697,7 +653,7 @@ static struct fb_ops smtcfb_ops = { .fb_check_var = smtc_check_var, .fb_set_par = smtc_set_par, .fb_setcolreg = smtc_setcolreg, - .fb_blank = cfb_blank, + .fb_blank = smtc_blank, .fb_fillrect = cfb_fillrect, .fb_imageblit = cfb_imageblit, .fb_copyarea = cfb_copyarea, @@ -710,8 +666,7 @@ static struct fb_ops smtcfb_ops = { /* * Alloc struct smtcfb_info and assign the default value */ -static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *dev, - char *name) +static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *pdev, char *name) { struct smtcfb_info *sfb; @@ -720,8 +675,7 @@ static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *dev, if (!sfb) return NULL; - sfb->currcon = -1; - sfb->dev = dev; + sfb->pdev = pdev; /*** Init sfb->fb with default value ***/ sfb->fb.flags = FBINFO_FLAG_DEFAULT; @@ -745,7 +699,9 @@ static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *dev, /* text mode acceleration */ sfb->fb.var.accel_flags = FB_ACCELF_TEXT; sfb->fb.var.vmode = FB_VMODE_NONINTERLACED; - sfb->fb.par = &hw; + + sfb->fb.par = sfb; + sfb->fb.pseudo_palette = colreg; return sfb; @@ -766,17 +722,17 @@ static void smtc_unmap_mmio(struct smtcfb_info *sfb) */ static int smtc_map_smem(struct smtcfb_info *sfb, - struct pci_dev *dev, u_long smem_len) + struct pci_dev *pdev, u_long smem_len) { if (sfb->fb.var.bits_per_pixel == 32) { #ifdef __BIG_ENDIAN - sfb->fb.fix.smem_start = pci_resource_start(dev, 0) + sfb->fb.fix.smem_start = pci_resource_start(pdev, 0) + 0x800000; #else - sfb->fb.fix.smem_start = pci_resource_start(dev, 0); + sfb->fb.fix.smem_start = pci_resource_start(pdev, 0); #endif } else { - sfb->fb.fix.smem_start = pci_resource_start(dev, 0); + sfb->fb.fix.smem_start = pci_resource_start(pdev, 0); } sfb->fb.fix.smem_len = smem_len; @@ -784,8 +740,8 @@ static int smtc_map_smem(struct smtcfb_info *sfb, sfb->fb.screen_base = smtc_VRAMBaseAddress; if (!sfb->fb.screen_base) { - printk(KERN_ERR "%s: unable to map screen memory\n", - sfb->fb.fix.id); + dev_err(&pdev->dev, + "%s: unable to map screen memory\n", sfb->fb.fix.id); return -ENOMEM; } @@ -831,16 +787,14 @@ static int __init sm712vga_setup(char *options) { int index; - if (!options || !*options) { - smdbg("\n No vga parameter\n"); + if (!options || !*options) return -EINVAL; - } smtc_screen_info.lfb_width = 0; smtc_screen_info.lfb_height = 0; smtc_screen_info.lfb_depth = 0; - smdbg("\nsm712vga_setup = %s\n", options); + pr_debug("sm712vga_setup = %s\n", options); for (index = 0; index < ARRAY_SIZE(vesa_mode); @@ -858,10 +812,6 @@ static int __init sm712vga_setup(char *options) } __setup("vga=", sm712vga_setup); -/* Jason (08/13/2009) - * Original init function changed to probe method to be used by pci_drv - * process used to detect chips replaced with kernel process in pci_drv - */ static int __devinit smtcfb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -871,23 +821,20 @@ static int __devinit smtcfb_pci_probe(struct pci_dev *pdev, int err; unsigned long pFramebufferPhysical; - printk(KERN_INFO - "Silicon Motion display driver " SMTC_LINUX_FB_VERSION "\n"); + dev_info(&pdev->dev, "Silicon Motion display driver."); err = pci_enable_device(pdev); /* enable SMTC chip */ if (err) return err; - hw.chipID = ent->device; - sprintf(name, "sm%Xfb", hw.chipID); - sfb = smtc_alloc_fb_info(pdev, name); if (!sfb) goto failed_free; - /* Jason (08/13/2009) - * Store fb_info to be further used when suspending and resuming - */ + + sfb->chipID = ent->device; + sprintf(name, "sm%Xfb", sfb->chipID); + pci_set_drvdata(pdev, sfb); sm7xx_init_hw(); @@ -910,37 +857,37 @@ static int __devinit smtcfb_pci_probe(struct pci_dev *pdev, #endif /* Map address and memory detection */ pFramebufferPhysical = pci_resource_start(pdev, 0); - pci_read_config_byte(pdev, PCI_REVISION_ID, &hw.chipRevID); + pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chipRevID); - switch (hw.chipID) { + switch (sfb->chipID) { case 0x710: case 0x712: sfb->fb.fix.mmio_start = pFramebufferPhysical + 0x00400000; sfb->fb.fix.mmio_len = 0x00400000; smem_size = SM712_VIDEOMEMORYSIZE; #ifdef __BIG_ENDIAN - hw.m_pLFB = (smtc_VRAMBaseAddress = + sfb->m_pLFB = (smtc_VRAMBaseAddress = ioremap(pFramebufferPhysical, 0x00c00000)); #else - hw.m_pLFB = (smtc_VRAMBaseAddress = + sfb->m_pLFB = (smtc_VRAMBaseAddress = ioremap(pFramebufferPhysical, 0x00800000)); #endif - hw.m_pMMIO = (smtc_RegBaseAddress = + sfb->m_pMMIO = (smtc_RegBaseAddress = smtc_VRAMBaseAddress + 0x00700000); - hw.m_pDPR = smtc_VRAMBaseAddress + 0x00408000; - hw.m_pVPR = hw.m_pLFB + 0x0040c000; + sfb->m_pDPR = smtc_VRAMBaseAddress + 0x00408000; + sfb->m_pVPR = sfb->m_pLFB + 0x0040c000; #ifdef __BIG_ENDIAN if (sfb->fb.var.bits_per_pixel == 32) { smtc_VRAMBaseAddress += 0x800000; - hw.m_pLFB += 0x800000; - printk(KERN_INFO - "\nsmtc_VRAMBaseAddress=%p hw.m_pLFB=%p\n", - smtc_VRAMBaseAddress, hw.m_pLFB); + sfb->m_pLFB += 0x800000; + dev_info(&pdev->dev, + "smtc_VRAMBaseAddress=%p sfb->m_pLFB=%p", + smtc_VRAMBaseAddress, sfb->m_pLFB); } #endif if (!smtc_RegBaseAddress) { - printk(KERN_ERR - "%s: unable to map memory mapped IO\n", + dev_err(&pdev->dev, + "%s: unable to map memory mapped IO!", sfb->fb.fix.id); err = -ENOMEM; goto failed_fb; @@ -962,20 +909,20 @@ static int __devinit smtcfb_pci_probe(struct pci_dev *pdev, sfb->fb.fix.mmio_start = pFramebufferPhysical; sfb->fb.fix.mmio_len = 0x00200000; smem_size = SM722_VIDEOMEMORYSIZE; - hw.m_pDPR = ioremap(pFramebufferPhysical, 0x00a00000); - hw.m_pLFB = (smtc_VRAMBaseAddress = - hw.m_pDPR + 0x00200000); - hw.m_pMMIO = (smtc_RegBaseAddress = - hw.m_pDPR + 0x000c0000); - hw.m_pVPR = hw.m_pDPR + 0x800; + sfb->m_pDPR = ioremap(pFramebufferPhysical, 0x00a00000); + sfb->m_pLFB = (smtc_VRAMBaseAddress = + sfb->m_pDPR + 0x00200000); + sfb->m_pMMIO = (smtc_RegBaseAddress = + sfb->m_pDPR + 0x000c0000); + sfb->m_pVPR = sfb->m_pDPR + 0x800; smtc_seqw(0x62, 0xff); smtc_seqw(0x6a, 0x0d); smtc_seqw(0x6b, 0x02); break; default: - printk(KERN_ERR - "No valid Silicon Motion display chip was detected!\n"); + dev_err(&pdev->dev, + "No valid Silicon Motion display chip was detected!"); goto failed_fb; } @@ -992,22 +939,21 @@ static int __devinit smtcfb_pci_probe(struct pci_dev *pdev, smtcfb_setmode(sfb); /* Primary display starting from 0 position */ - hw.BaseAddressInVRAM = 0; - sfb->fb.par = &hw; + sfb->BaseAddressInVRAM = 0; err = register_framebuffer(&sfb->fb); if (err < 0) goto failed; - printk(KERN_INFO "Silicon Motion SM%X Rev%X primary display mode" - "%dx%d-%d Init Complete.\n", hw.chipID, hw.chipRevID, - sfb->fb.var.xres, sfb->fb.var.yres, - sfb->fb.var.bits_per_pixel); + dev_info(&pdev->dev, + "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.", + sfb->chipID, sfb->chipRevID, sfb->fb.var.xres, + sfb->fb.var.yres, sfb->fb.var.bits_per_pixel); return 0; failed: - printk(KERN_ERR "Silicon Motion, Inc. primary display init fail\n"); + dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail."); smtc_unmap_smem(sfb); smtc_unmap_mmio(sfb); @@ -1021,7 +967,6 @@ static int __devinit smtcfb_pci_probe(struct pci_dev *pdev, } -/* Jason (08/11/2009) PCI_DRV wrapper essential structs */ static DEFINE_PCI_DEVICE_TABLE(smtcfb_pci_table) = { { PCI_DEVICE(0x126f, 0x710), }, { PCI_DEVICE(0x126f, 0x712), }, @@ -1030,9 +975,6 @@ static DEFINE_PCI_DEVICE_TABLE(smtcfb_pci_table) = { }; -/* Jason (08/14/2009) - * do some clean up when the driver module is removed - */ static void __devexit smtcfb_pci_remove(struct pci_dev *pdev) { struct smtcfb_info *sfb; @@ -1078,7 +1020,7 @@ static int smtcfb_pci_resume(struct device *device) /* reinit hardware */ sm7xx_init_hw(); - switch (hw.chipID) { + switch (sfb->chipID) { case 0x710: case 0x712: /* set MCLK = 14.31818 * (0x16 / 0x2) */ diff --git a/trunk/drivers/staging/sm7xx/smtcfb.h b/trunk/drivers/staging/sm7xx/smtcfb.h index ab95af2b9c07..43d86f873410 100644 --- a/trunk/drivers/staging/sm7xx/smtcfb.h +++ b/trunk/drivers/staging/sm7xx/smtcfb.h @@ -13,19 +13,11 @@ * more details. */ -#define SMTC_LINUX_FB_VERSION "version 0.11.2619.21.01 July 27, 2008" - #define NR_PALETTE 256 #define NR_RGB 2 #define FB_ACCEL_SMI_LYNX 88 -#ifdef __BIG_ENDIAN -#define PC_VGA 0 -#else -#define PC_VGA 1 -#endif - #define SCREEN_X_RES 1024 #define SCREEN_Y_RES 600 #define SCREEN_BPP 16 diff --git a/trunk/drivers/staging/telephony/ixj.c b/trunk/drivers/staging/telephony/ixj.c index f96027921f60..fd7757ad7fa3 100644 --- a/trunk/drivers/staging/telephony/ixj.c +++ b/trunk/drivers/staging/telephony/ixj.c @@ -19,20 +19,20 @@ * David W. Erhart, * John Sellers, * Mike Preston, - * + * * Fixes: David Huggins-Daines, * Fabio Ferrari, * Artis Kugevics, * Daniele Bellucci, * - * More information about the hardware related to this driver can be found + * More information about the hardware related to this driver can be found * at our website: http://www.quicknet.net * * IN NO EVENT SHALL QUICKNET TECHNOLOGIES, INC. BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF QUICKNET * TECHNOLOGIES, INC. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * QUICKNET TECHNOLOGIES, INC. SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS @@ -317,7 +317,7 @@ static IXJ *ixj[IXJMAX]; /* * Allocate a free IXJ device */ - + static IXJ *ixj_alloc() { for(cnt=0; cntboard, j->cadence_f[4].on3, j->cadence_f[4].on3min, j->cadence_f[4].on3dot, j->cadence_f[4].on3max); break; - case 6: + case 6: printk(KERN_INFO "IXJ /dev/phone%d Next Ring Cadence state at %u min %ld - %ld - max %ld\n", j->board, j->cadence_f[4].off3, j->cadence_f[4].off3min, j->cadence_f[4].off3dot, j->cadence_f[4].off3max); break; @@ -1109,7 +1109,7 @@ static void ixj_pstn_state(IXJ *j) } j->pstn_ring_stop = j->pstn_ring_int = 0; daa_set_mode(j, SOP_PU_SLEEP); - } + } outb_p(j->pld_scrw.byte, j->XILINXbase); if (j->pstn_cid_intr && time_after(jiffies, j->pstn_cid_received + hertz)) { ixj_daa_cid_read(j); @@ -1133,7 +1133,7 @@ static void ixj_pstn_state(IXJ *j) printk("IXJ DAA possible wink /dev/phone%d %ld\n", j->board, jiffies); } j->pstn_winkstart = jiffies; - } + } } else { if (j->pstn_winkstart) { if(ixjdebug & 0x0008) { @@ -1524,7 +1524,7 @@ static inline void LED_SetState(int state, IXJ *j) /********************************************************************* * GPIO Pins are configured as follows on the Quicknet Internet * PhoneJACK Telephony Cards -* +* * POTS Select GPIO_6=0 GPIO_7=0 * Mic/Speaker Select GPIO_6=0 GPIO_7=1 * Handset Select GPIO_6=1 GPIO_7=0 @@ -1932,7 +1932,7 @@ static int ixj_hookstate(IXJ *j) if(fOffHook != j->p_hook) { if(!j->checkwait) { j->checkwait = jiffies; - } + } if(time_before(jiffies, j->checkwait + 2)) { fOffHook ^= 1; } else { @@ -2342,8 +2342,8 @@ static int ixj_release(struct inode *inode, struct file *file_p) j->ixj_signals[cnt] = SIGIO; /* Set the excetion signal enable flags */ - j->ex_sig.bits.dtmf_ready = j->ex_sig.bits.hookstate = j->ex_sig.bits.flash = j->ex_sig.bits.pstn_ring = - j->ex_sig.bits.caller_id = j->ex_sig.bits.pstn_wink = j->ex_sig.bits.f0 = j->ex_sig.bits.f1 = j->ex_sig.bits.f2 = + j->ex_sig.bits.dtmf_ready = j->ex_sig.bits.hookstate = j->ex_sig.bits.flash = j->ex_sig.bits.pstn_ring = + j->ex_sig.bits.caller_id = j->ex_sig.bits.pstn_wink = j->ex_sig.bits.f0 = j->ex_sig.bits.f1 = j->ex_sig.bits.f2 = j->ex_sig.bits.f3 = j->ex_sig.bits.fc0 = j->ex_sig.bits.fc1 = j->ex_sig.bits.fc2 = j->ex_sig.bits.fc3 = 1; file_p->private_data = NULL; @@ -2506,7 +2506,7 @@ static int read_filters(IXJ *j) j->cadence_f[cnt].on1, j->cadence_f[cnt].on1min, j->cadence_f[cnt].on1dot, j->cadence_f[cnt].on1max); break; case 2: - printk(KERN_INFO "IXJ /dev/phone%d Next Tone Cadence state at %ld - %ld\n", j->board, j->cadence_f[cnt].off1min, + printk(KERN_INFO "IXJ /dev/phone%d Next Tone Cadence state at %ld - %ld\n", j->board, j->cadence_f[cnt].off1min, j->cadence_f[cnt].off1max); break; case 3: @@ -2521,12 +2521,12 @@ static int read_filters(IXJ *j) printk(KERN_INFO "IXJ /dev/phone%d Next Tone Cadence state at %ld - %ld\n", j->board, j->cadence_f[cnt].on3min, j->cadence_f[cnt].on3max); break; - case 6: + case 6: printk(KERN_INFO "IXJ /dev/phone%d Next Tone Cadence state at %ld - %ld\n", j->board, j->cadence_f[cnt].off3min, j->cadence_f[cnt].off3max); break; } - } + } } if (j->cadence_f[cnt].state == 7) { j->cadence_f[cnt].state = 0; @@ -2656,37 +2656,37 @@ static void ulaw2alaw(unsigned char *buff, unsigned long len) { static unsigned char table_ulaw2alaw[] = { - 0x2A, 0x2B, 0x28, 0x29, 0x2E, 0x2F, 0x2C, 0x2D, - 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, - 0x3A, 0x3B, 0x38, 0x39, 0x3E, 0x3F, 0x3C, 0x3D, - 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, - 0x0B, 0x08, 0x09, 0x0E, 0x0F, 0x0C, 0x0D, 0x02, - 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x1A, - 0x1B, 0x18, 0x19, 0x1E, 0x1F, 0x1C, 0x1D, 0x12, - 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x6B, - 0x68, 0x69, 0x6E, 0x6F, 0x6C, 0x6D, 0x62, 0x63, - 0x60, 0x61, 0x66, 0x67, 0x64, 0x65, 0x7B, 0x79, - 0x7E, 0x7F, 0x7C, 0x7D, 0x72, 0x73, 0x70, 0x71, - 0x76, 0x77, 0x74, 0x75, 0x4B, 0x49, 0x4F, 0x4D, - 0x42, 0x43, 0x40, 0x41, 0x46, 0x47, 0x44, 0x45, - 0x5A, 0x5B, 0x58, 0x59, 0x5E, 0x5F, 0x5C, 0x5D, - 0x52, 0x52, 0x53, 0x53, 0x50, 0x50, 0x51, 0x51, - 0x56, 0x56, 0x57, 0x57, 0x54, 0x54, 0x55, 0xD5, - 0xAA, 0xAB, 0xA8, 0xA9, 0xAE, 0xAF, 0xAC, 0xAD, - 0xA2, 0xA3, 0xA0, 0xA1, 0xA6, 0xA7, 0xA4, 0xA5, - 0xBA, 0xBB, 0xB8, 0xB9, 0xBE, 0xBF, 0xBC, 0xBD, - 0xB2, 0xB3, 0xB0, 0xB1, 0xB6, 0xB7, 0xB4, 0xB5, - 0x8B, 0x88, 0x89, 0x8E, 0x8F, 0x8C, 0x8D, 0x82, - 0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85, 0x9A, - 0x9B, 0x98, 0x99, 0x9E, 0x9F, 0x9C, 0x9D, 0x92, - 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95, 0xEB, - 0xE8, 0xE9, 0xEE, 0xEF, 0xEC, 0xED, 0xE2, 0xE3, - 0xE0, 0xE1, 0xE6, 0xE7, 0xE4, 0xE5, 0xFB, 0xF9, - 0xFE, 0xFF, 0xFC, 0xFD, 0xF2, 0xF3, 0xF0, 0xF1, - 0xF6, 0xF7, 0xF4, 0xF5, 0xCB, 0xC9, 0xCF, 0xCD, - 0xC2, 0xC3, 0xC0, 0xC1, 0xC6, 0xC7, 0xC4, 0xC5, - 0xDA, 0xDB, 0xD8, 0xD9, 0xDE, 0xDF, 0xDC, 0xDD, - 0xD2, 0xD2, 0xD3, 0xD3, 0xD0, 0xD0, 0xD1, 0xD1, + 0x2A, 0x2B, 0x28, 0x29, 0x2E, 0x2F, 0x2C, 0x2D, + 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, + 0x3A, 0x3B, 0x38, 0x39, 0x3E, 0x3F, 0x3C, 0x3D, + 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, + 0x0B, 0x08, 0x09, 0x0E, 0x0F, 0x0C, 0x0D, 0x02, + 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x1A, + 0x1B, 0x18, 0x19, 0x1E, 0x1F, 0x1C, 0x1D, 0x12, + 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x6B, + 0x68, 0x69, 0x6E, 0x6F, 0x6C, 0x6D, 0x62, 0x63, + 0x60, 0x61, 0x66, 0x67, 0x64, 0x65, 0x7B, 0x79, + 0x7E, 0x7F, 0x7C, 0x7D, 0x72, 0x73, 0x70, 0x71, + 0x76, 0x77, 0x74, 0x75, 0x4B, 0x49, 0x4F, 0x4D, + 0x42, 0x43, 0x40, 0x41, 0x46, 0x47, 0x44, 0x45, + 0x5A, 0x5B, 0x58, 0x59, 0x5E, 0x5F, 0x5C, 0x5D, + 0x52, 0x52, 0x53, 0x53, 0x50, 0x50, 0x51, 0x51, + 0x56, 0x56, 0x57, 0x57, 0x54, 0x54, 0x55, 0xD5, + 0xAA, 0xAB, 0xA8, 0xA9, 0xAE, 0xAF, 0xAC, 0xAD, + 0xA2, 0xA3, 0xA0, 0xA1, 0xA6, 0xA7, 0xA4, 0xA5, + 0xBA, 0xBB, 0xB8, 0xB9, 0xBE, 0xBF, 0xBC, 0xBD, + 0xB2, 0xB3, 0xB0, 0xB1, 0xB6, 0xB7, 0xB4, 0xB5, + 0x8B, 0x88, 0x89, 0x8E, 0x8F, 0x8C, 0x8D, 0x82, + 0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85, 0x9A, + 0x9B, 0x98, 0x99, 0x9E, 0x9F, 0x9C, 0x9D, 0x92, + 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95, 0xEB, + 0xE8, 0xE9, 0xEE, 0xEF, 0xEC, 0xED, 0xE2, 0xE3, + 0xE0, 0xE1, 0xE6, 0xE7, 0xE4, 0xE5, 0xFB, 0xF9, + 0xFE, 0xFF, 0xFC, 0xFD, 0xF2, 0xF3, 0xF0, 0xF1, + 0xF6, 0xF7, 0xF4, 0xF5, 0xCB, 0xC9, 0xCF, 0xCD, + 0xC2, 0xC3, 0xC0, 0xC1, 0xC6, 0xC7, 0xC4, 0xC5, + 0xDA, 0xDB, 0xD8, 0xD9, 0xDE, 0xDF, 0xDC, 0xDD, + 0xD2, 0xD2, 0xD3, 0xD3, 0xD0, 0xD0, 0xD1, 0xD1, 0xD6, 0xD6, 0xD7, 0xD7, 0xD4, 0xD4, 0xD5, 0xD5 }; @@ -2701,37 +2701,37 @@ static void alaw2ulaw(unsigned char *buff, unsigned long len) { static unsigned char table_alaw2ulaw[] = { - 0x29, 0x2A, 0x27, 0x28, 0x2D, 0x2E, 0x2B, 0x2C, - 0x21, 0x22, 0x1F, 0x20, 0x25, 0x26, 0x23, 0x24, - 0x39, 0x3A, 0x37, 0x38, 0x3D, 0x3E, 0x3B, 0x3C, - 0x31, 0x32, 0x2F, 0x30, 0x35, 0x36, 0x33, 0x34, - 0x0A, 0x0B, 0x08, 0x09, 0x0E, 0x0F, 0x0C, 0x0D, - 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, - 0x1A, 0x1B, 0x18, 0x19, 0x1E, 0x1F, 0x1C, 0x1D, - 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, - 0x62, 0x63, 0x60, 0x61, 0x66, 0x67, 0x64, 0x65, - 0x5D, 0x5D, 0x5C, 0x5C, 0x5F, 0x5F, 0x5E, 0x5E, - 0x74, 0x76, 0x70, 0x72, 0x7C, 0x7E, 0x78, 0x7A, - 0x6A, 0x6B, 0x68, 0x69, 0x6E, 0x6F, 0x6C, 0x6D, - 0x48, 0x49, 0x46, 0x47, 0x4C, 0x4D, 0x4A, 0x4B, - 0x40, 0x41, 0x3F, 0x3F, 0x44, 0x45, 0x42, 0x43, - 0x56, 0x57, 0x54, 0x55, 0x5A, 0x5B, 0x58, 0x59, - 0x4F, 0x4F, 0x4E, 0x4E, 0x52, 0x53, 0x50, 0x51, - 0xA9, 0xAA, 0xA7, 0xA8, 0xAD, 0xAE, 0xAB, 0xAC, - 0xA1, 0xA2, 0x9F, 0xA0, 0xA5, 0xA6, 0xA3, 0xA4, - 0xB9, 0xBA, 0xB7, 0xB8, 0xBD, 0xBE, 0xBB, 0xBC, - 0xB1, 0xB2, 0xAF, 0xB0, 0xB5, 0xB6, 0xB3, 0xB4, - 0x8A, 0x8B, 0x88, 0x89, 0x8E, 0x8F, 0x8C, 0x8D, - 0x82, 0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85, - 0x9A, 0x9B, 0x98, 0x99, 0x9E, 0x9F, 0x9C, 0x9D, - 0x92, 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95, - 0xE2, 0xE3, 0xE0, 0xE1, 0xE6, 0xE7, 0xE4, 0xE5, - 0xDD, 0xDD, 0xDC, 0xDC, 0xDF, 0xDF, 0xDE, 0xDE, - 0xF4, 0xF6, 0xF0, 0xF2, 0xFC, 0xFE, 0xF8, 0xFA, - 0xEA, 0xEB, 0xE8, 0xE9, 0xEE, 0xEF, 0xEC, 0xED, - 0xC8, 0xC9, 0xC6, 0xC7, 0xCC, 0xCD, 0xCA, 0xCB, - 0xC0, 0xC1, 0xBF, 0xBF, 0xC4, 0xC5, 0xC2, 0xC3, - 0xD6, 0xD7, 0xD4, 0xD5, 0xDA, 0xDB, 0xD8, 0xD9, + 0x29, 0x2A, 0x27, 0x28, 0x2D, 0x2E, 0x2B, 0x2C, + 0x21, 0x22, 0x1F, 0x20, 0x25, 0x26, 0x23, 0x24, + 0x39, 0x3A, 0x37, 0x38, 0x3D, 0x3E, 0x3B, 0x3C, + 0x31, 0x32, 0x2F, 0x30, 0x35, 0x36, 0x33, 0x34, + 0x0A, 0x0B, 0x08, 0x09, 0x0E, 0x0F, 0x0C, 0x0D, + 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, + 0x1A, 0x1B, 0x18, 0x19, 0x1E, 0x1F, 0x1C, 0x1D, + 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, + 0x62, 0x63, 0x60, 0x61, 0x66, 0x67, 0x64, 0x65, + 0x5D, 0x5D, 0x5C, 0x5C, 0x5F, 0x5F, 0x5E, 0x5E, + 0x74, 0x76, 0x70, 0x72, 0x7C, 0x7E, 0x78, 0x7A, + 0x6A, 0x6B, 0x68, 0x69, 0x6E, 0x6F, 0x6C, 0x6D, + 0x48, 0x49, 0x46, 0x47, 0x4C, 0x4D, 0x4A, 0x4B, + 0x40, 0x41, 0x3F, 0x3F, 0x44, 0x45, 0x42, 0x43, + 0x56, 0x57, 0x54, 0x55, 0x5A, 0x5B, 0x58, 0x59, + 0x4F, 0x4F, 0x4E, 0x4E, 0x52, 0x53, 0x50, 0x51, + 0xA9, 0xAA, 0xA7, 0xA8, 0xAD, 0xAE, 0xAB, 0xAC, + 0xA1, 0xA2, 0x9F, 0xA0, 0xA5, 0xA6, 0xA3, 0xA4, + 0xB9, 0xBA, 0xB7, 0xB8, 0xBD, 0xBE, 0xBB, 0xBC, + 0xB1, 0xB2, 0xAF, 0xB0, 0xB5, 0xB6, 0xB3, 0xB4, + 0x8A, 0x8B, 0x88, 0x89, 0x8E, 0x8F, 0x8C, 0x8D, + 0x82, 0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85, + 0x9A, 0x9B, 0x98, 0x99, 0x9E, 0x9F, 0x9C, 0x9D, + 0x92, 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95, + 0xE2, 0xE3, 0xE0, 0xE1, 0xE6, 0xE7, 0xE4, 0xE5, + 0xDD, 0xDD, 0xDC, 0xDC, 0xDF, 0xDF, 0xDE, 0xDE, + 0xF4, 0xF6, 0xF0, 0xF2, 0xFC, 0xFE, 0xF8, 0xFA, + 0xEA, 0xEB, 0xE8, 0xE9, 0xEE, 0xEF, 0xEC, 0xED, + 0xC8, 0xC9, 0xC6, 0xC7, 0xCC, 0xCD, 0xCA, 0xCB, + 0xC0, 0xC1, 0xBF, 0xBF, 0xC4, 0xC5, 0xC2, 0xC3, + 0xD6, 0xD7, 0xD4, 0xD5, 0xDA, 0xDB, 0xD8, 0xD9, 0xCF, 0xCF, 0xCE, 0xCE, 0xD2, 0xD3, 0xD0, 0xD1 }; @@ -3090,7 +3090,7 @@ static int ixj_write_cid_string(IXJ *j, char *s, int checksum) static void ixj_pad_fsk(IXJ *j, int pad) { - int cnt; + int cnt; for (cnt = 0; cnt < pad; cnt++) { if(j->fskdcnt < (j->fsksize - 1)) @@ -3474,7 +3474,7 @@ static void ixj_write_frame(IXJ *j) ixj_post_cid(j); } /* This may seem rude, but if we just played one frame of FSK data for CallerID - and there is real audio data in the buffer, we need to throw it away because + and there is real audio data in the buffer, we need to throw it away because we just used it's time slot */ if (j->write_buffer_rp > j->write_buffer_wp) { j->write_buffer_rp += j->cid_play_frame_size * 2; @@ -3486,7 +3486,7 @@ static void ixj_write_frame(IXJ *j) wake_up_interruptible(&j->poll_q); /* Wake any blocked selects */ } - } else if (j->write_buffer && j->write_buffers_empty < 1) { + } else if (j->write_buffer && j->write_buffers_empty < 1) { if (j->write_buffer_wp > j->write_buffer_rp) { frame_count = (j->write_buffer_wp - j->write_buffer_rp) / (j->play_frame_size * 2); @@ -4150,7 +4150,7 @@ static void ixj_aec_start(IXJ *j, int level) ixj_WriteDSPCommand(0xCF97, j); /* Set AGC Enable */ ixj_WriteDSPCommand(0x0000, j); /* to off */ - + break; case AEC_MED: @@ -4161,7 +4161,7 @@ static void ixj_aec_start(IXJ *j, int level) ixj_WriteDSPCommand(0xCF97, j); /* Set AGC Enable */ ixj_WriteDSPCommand(0x0000, j); /* to off */ - + break; case AEC_HIGH: @@ -4172,7 +4172,7 @@ static void ixj_aec_start(IXJ *j, int level) ixj_WriteDSPCommand(0xCF97, j); /* Set AGC Enable */ ixj_WriteDSPCommand(0x0000, j); /* to off */ - + break; case AEC_AGC: @@ -4197,28 +4197,28 @@ static void ixj_aec_start(IXJ *j, int level) /* Now we can set the AGC initial parameters and turn it on */ ixj_WriteDSPCommand(0xCF90, j); /* Set AGC Minimum gain */ ixj_WriteDSPCommand(0x0020, j); /* to 0.125 (-18dB) */ - + ixj_WriteDSPCommand(0xCF91, j); /* Set AGC Maximum gain */ ixj_WriteDSPCommand(0x1000, j); /* to 16 (24dB) */ - + ixj_WriteDSPCommand(0xCF92, j); /* Set AGC start gain */ ixj_WriteDSPCommand(0x0800, j); /* to 8 (+18dB) */ - + ixj_WriteDSPCommand(0xCF93, j); /* Set AGC hold time */ ixj_WriteDSPCommand(0x1F40, j); /* to 2 seconds (units are 250us) */ - + ixj_WriteDSPCommand(0xCF94, j); /* Set AGC Attack Time Constant */ ixj_WriteDSPCommand(0x0005, j); /* to 8ms */ - + ixj_WriteDSPCommand(0xCF95, j); /* Set AGC Decay Time Constant */ ixj_WriteDSPCommand(0x000D, j); /* to 4096ms */ - + ixj_WriteDSPCommand(0xCF96, j); /* Set AGC Attack Threshold */ ixj_WriteDSPCommand(0x1200, j); /* to 25% */ - + ixj_WriteDSPCommand(0xCF97, j); /* Set AGC Enable */ ixj_WriteDSPCommand(0x0001, j); /* to on */ - + break; case AEC_AUTO: @@ -4495,7 +4495,7 @@ static int ixj_play_start(IXJ *j) return -ENOMEM; } /* j->write_buffers_empty = 2; */ - j->write_buffers_empty = 1; + j->write_buffers_empty = 1; j->write_buffer_size = j->play_frame_size * 2; j->write_buffer_end = j->write_buffer + j->play_frame_size * 2; j->write_buffer_rp = j->write_buffer_wp = j->write_buffer; @@ -6465,9 +6465,9 @@ static long do_ixj_ioctl(struct file *file_p, unsigned int cmd, unsigned long ar ixj_ringback(j); break; case PHONE_WINK: - if(j->cardtype == QTI_PHONEJACK) + if(j->cardtype == QTI_PHONEJACK) retval = -1; - else + else retval = ixj_wink(j); break; case PHONE_CPT_STOP: @@ -6553,7 +6553,7 @@ static long do_ixj_ioctl(struct file *file_p, unsigned int cmd, unsigned long ar ixj_write_vmwi(j, arg); break; case IXJCTL_CID: - if (copy_to_user(argp, &j->cid, sizeof(PHONE_CID))) + if (copy_to_user(argp, &j->cid, sizeof(PHONE_CID))) retval = -EFAULT; j->ex.bits.caller_id = 0; break; @@ -6575,13 +6575,13 @@ static long do_ixj_ioctl(struct file *file_p, unsigned int cmd, unsigned long ar break; case PHONE_CAPABILITIES_LIST: add_caps(j); - if (copy_to_user(argp, j->caplist, sizeof(struct phone_capability) * j->caps)) + if (copy_to_user(argp, j->caplist, sizeof(struct phone_capability) * j->caps)) retval = -EFAULT; break; case PHONE_CAPABILITIES_CHECK: { struct phone_capability cap; - if (copy_from_user(&cap, argp, sizeof(cap))) + if (copy_from_user(&cap, argp, sizeof(cap))) retval = -EFAULT; else { add_caps(j); @@ -6597,13 +6597,13 @@ static long do_ixj_ioctl(struct file *file_p, unsigned int cmd, unsigned long ar j->ex.bits.pstn_ring = 0; break; case IXJCTL_SET_FILTER: - if (copy_from_user(&jf, argp, sizeof(jf))) + if (copy_from_user(&jf, argp, sizeof(jf))) retval = -EFAULT; else retval = ixj_init_filter(j, &jf); break; case IXJCTL_SET_FILTER_RAW: - if (copy_from_user(&jfr, argp, sizeof(jfr))) + if (copy_from_user(&jfr, argp, sizeof(jfr))) retval = -EFAULT; else retval = ixj_init_filter_raw(j, &jfr); @@ -6638,9 +6638,9 @@ static long do_ixj_ioctl(struct file *file_p, unsigned int cmd, unsigned long ar raise *= 2; } if(j->sigdef.signal) - j->ex_sig.bytes |= raise; + j->ex_sig.bytes |= raise; else - j->ex_sig.bytes &= (raise^0xffff); + j->ex_sig.bytes &= (raise^0xffff); } break; case IXJCTL_INTERCOM_STOP: @@ -7040,9 +7040,9 @@ static int ixj_selfprobe(IXJ *j) /* initialise the DTMF prescale to a sensible value */ if (j->cardtype == QTI_LINEJACK) { - set_dtmf_prescale(j, 0x10); + set_dtmf_prescale(j, 0x10); } else { - set_dtmf_prescale(j, 0x40); + set_dtmf_prescale(j, 0x40); } set_play_volume(j, 0x100); set_rec_volume(j, 0x100); @@ -7095,15 +7095,15 @@ static int ixj_selfprobe(IXJ *j) j->ixj_signals[cnt] = SIGIO; /* Set the excetion signal enable flags */ - j->ex_sig.bits.dtmf_ready = j->ex_sig.bits.hookstate = j->ex_sig.bits.flash = j->ex_sig.bits.pstn_ring = - j->ex_sig.bits.caller_id = j->ex_sig.bits.pstn_wink = j->ex_sig.bits.f0 = j->ex_sig.bits.f1 = j->ex_sig.bits.f2 = + j->ex_sig.bits.dtmf_ready = j->ex_sig.bits.hookstate = j->ex_sig.bits.flash = j->ex_sig.bits.pstn_ring = + j->ex_sig.bits.caller_id = j->ex_sig.bits.pstn_wink = j->ex_sig.bits.f0 = j->ex_sig.bits.f1 = j->ex_sig.bits.f2 = j->ex_sig.bits.f3 = j->ex_sig.bits.fc0 = j->ex_sig.bits.fc1 = j->ex_sig.bits.fc2 = j->ex_sig.bits.fc3 = 1; #ifdef IXJ_DYN_ALLOC j->fskdata = NULL; #endif j->fskdcnt = 0; j->cidcw_wait = 0; - + /* Register with the Telephony for Linux subsystem */ j->p.f_op = &ixj_fops; j->p.open = ixj_open; @@ -7118,7 +7118,7 @@ static int ixj_selfprobe(IXJ *j) /* * Exported service for pcmcia card handling */ - + IXJ *ixj_pcmcia_probe(unsigned long dsp, unsigned long xilinx) { IXJ *j = ixj_alloc(); @@ -7320,7 +7320,7 @@ static int ixj_get_status_proc(char *buf) len += sprintf(buf + len, "\nRec volume 0x%x", get_rec_volume(j)); len += sprintf(buf + len, "\nPlay volume 0x%x", get_play_volume(j)); len += sprintf(buf + len, "\nDTMF prescale 0x%x", get_dtmf_prescale(j)); - + len += sprintf(buf + len, "\nHook state %d", j->hookstate); /* j->r_hook); */ if (j->cardtype == QTI_LINEJACK) { @@ -7417,7 +7417,7 @@ static int ixj_get_status_proc(char *buf) len += sprintf(buf + len, "\nPControl Wait Fails %ld", j->pcontrolwaitfail); len += sprintf(buf + len, "\nIs Control Ready Checks %ld", j->iscontrolready); len += sprintf(buf + len, "\nIs Control Ready Check failures %ld", j->iscontrolreadyfail); - + #endif len += sprintf(buf + len, "\n"); } @@ -7608,7 +7608,7 @@ static IXJ *new_ixj(unsigned long port) } static int __init ixj_probe_isapnp(int *cnt) -{ +{ int probe = 0; int func = 0x110; struct pnp_dev *dev = NULL, *old_dev = NULL; @@ -7686,7 +7686,7 @@ static int __init ixj_probe_isapnp(int *cnt) } return probe; } - + static int __init ixj_probe_isa(int *cnt) { int i, probe; @@ -7713,7 +7713,7 @@ static int __init ixj_probe_isa(int *cnt) static int __init ixj_probe_pci(int *cnt) { - struct pci_dev *pci = NULL; + struct pci_dev *pci = NULL; int i, probe = 0; IXJ *j = NULL; @@ -7745,7 +7745,7 @@ static int __init ixj_probe_pci(int *cnt) static int __init ixj_init(void) { int cnt = 0; - int probe = 0; + int probe = 0; cnt = 0; @@ -7887,7 +7887,7 @@ static void DAA_Coeff_US(IXJ *j) /* j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x2D; */ /* j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0x62; */ /* j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x2D; */ - /* Bytes for Ringing part 2 (06):13,42,A6,BA,D4,73,CA,D5 */ + /* Bytes for Ringing part 2 (06):13,42,A6,BA,D4,73,CA,D5 */ /* j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x2D; */ /* j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0x62; */ /* j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[5] = 0xA6; */ diff --git a/trunk/drivers/staging/tidspbridge/core/io_sm.c b/trunk/drivers/staging/tidspbridge/core/io_sm.c index 9b50b5bd4edb..c51f651dfd1b 100644 --- a/trunk/drivers/staging/tidspbridge/core/io_sm.c +++ b/trunk/drivers/staging/tidspbridge/core/io_sm.c @@ -2212,7 +2212,7 @@ void dump_dl_modules(struct bridge_dev_context *bridge_context) if (status) { pr_debug( - "%s: Failed to read dll_module stuct for 0x%x.\n", + "%s: Failed to read dll_module struct for 0x%x.\n", __func__, module_dsp_addr); break; } diff --git a/trunk/drivers/staging/tidspbridge/core/ue_deh.c b/trunk/drivers/staging/tidspbridge/core/ue_deh.c index 006ffd752895..3d28b2345fbd 100644 --- a/trunk/drivers/staging/tidspbridge/core/ue_deh.c +++ b/trunk/drivers/staging/tidspbridge/core/ue_deh.c @@ -215,7 +215,7 @@ static inline const char *event_to_string(int event) case DSP_MMUFAULT: return "DSP_MMUFAULT"; break; case DSP_PWRERROR: return "DSP_PWRERROR"; break; case DSP_WDTOVERFLOW: return "DSP_WDTOVERFLOW"; break; - default: return "unkown event"; break; + default: return "unknown event"; break; } } diff --git a/trunk/drivers/staging/usbip/stub_dev.c b/trunk/drivers/staging/usbip/stub_dev.c index fa870e3f7f6a..92ced35e6b7f 100644 --- a/trunk/drivers/staging/usbip/stub_dev.c +++ b/trunk/drivers/staging/usbip/stub_dev.c @@ -113,8 +113,8 @@ static ssize_t store_sockfd(struct device *dev, struct device_attribute *attr, spin_unlock(&sdev->ud.lock); - sdev->ud.tcp_rx = kthread_run(stub_rx_loop, &sdev->ud, "stub_rx"); - sdev->ud.tcp_tx = kthread_run(stub_tx_loop, &sdev->ud, "stub_tx"); + sdev->ud.tcp_rx = kthread_get_run(stub_rx_loop, &sdev->ud, "stub_rx"); + sdev->ud.tcp_tx = kthread_get_run(stub_tx_loop, &sdev->ud, "stub_tx"); spin_lock(&sdev->ud.lock); sdev->ud.status = SDEV_ST_USED; @@ -187,10 +187,10 @@ static void stub_shutdown_connection(struct usbip_device *ud) } /* 1. stop threads */ - if (ud->tcp_rx && !task_is_dead(ud->tcp_rx)) - kthread_stop(ud->tcp_rx); - if (ud->tcp_tx && !task_is_dead(ud->tcp_tx)) - kthread_stop(ud->tcp_tx); + if (ud->tcp_rx) + kthread_stop_put(ud->tcp_rx); + if (ud->tcp_tx) + kthread_stop_put(ud->tcp_tx); /* * 2. close the socket diff --git a/trunk/drivers/staging/usbip/usbip_common.h b/trunk/drivers/staging/usbip/usbip_common.h index c7b888ca54f5..5d89c0fd6f7b 100644 --- a/trunk/drivers/staging/usbip/usbip_common.h +++ b/trunk/drivers/staging/usbip/usbip_common.h @@ -292,6 +292,23 @@ struct usbip_device { } eh_ops; }; +#define kthread_get_run(threadfn, data, namefmt, ...) \ +({ \ + struct task_struct *__k \ + = kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \ + if (!IS_ERR(__k)) { \ + get_task_struct(__k); \ + wake_up_process(__k); \ + } \ + __k; \ +}) + +#define kthread_stop_put(k) \ + do { \ + kthread_stop(k); \ + put_task_struct(k); \ + } while (0) + /* usbip_common.c */ void usbip_dump_urb(struct urb *purb); void usbip_dump_header(struct usbip_header *pdu); diff --git a/trunk/drivers/staging/usbip/usbip_protocol.txt b/trunk/drivers/staging/usbip/usbip_protocol.txt index 0f102081e86c..16b6fe27284c 100644 --- a/trunk/drivers/staging/usbip/usbip_protocol.txt +++ b/trunk/drivers/staging/usbip/usbip_protocol.txt @@ -27,7 +27,7 @@ Once the client knows the list of exported USB devices it may decide to use one of them. First the client opens a TCP/IP connection towards the server and sends an OP_REQ_IMPORT packet. The server replies with OP_REP_IMPORT. If the import was successful the TCP/IP connection remains open and will be used -to trasfer the URB traffic between the client and the server. The client may +to transfer the URB traffic between the client and the server. The client may send two types of packets: the USBIP_CMD_SUBMIT to submit an URB, and USBIP_CMD_UNLINK to unlink a previously submitted URB. The answers of the server may be USBIP_RET_SUBMIT and USBIP_RET_UNLINK respectively. diff --git a/trunk/drivers/staging/usbip/userspace/libsrc/vhci_driver.c b/trunk/drivers/staging/usbip/userspace/libsrc/vhci_driver.c index 269787751b20..0958ba53e94a 100644 --- a/trunk/drivers/staging/usbip/userspace/libsrc/vhci_driver.c +++ b/trunk/drivers/staging/usbip/userspace/libsrc/vhci_driver.c @@ -59,7 +59,10 @@ static int parse_status(char *value) /* skip a header line */ - c = strchr(value, '\n') + 1; + c = strchr(value, '\n'); + if (!c) + return -1; + c++; while (*c != '\0') { int port, status, speed, devid; @@ -109,7 +112,10 @@ static int parse_status(char *value) /* go to the next line */ - c = strchr(c, '\n') + 1; + c = strchr(c, '\n'); + if (!c) + break; + c++; } dbg("exit"); @@ -264,11 +270,17 @@ static int get_nports(void) attr_status->method, attr_status->value); /* skip a header line */ - c = strchr(attr_status->value, '\n') + 1; + c = strchr(attr_status->value, '\n'); + if (!c) + return 0; + c++; while (*c != '\0') { /* go to the next line */ - c = strchr(c, '\n') + 1; + c = strchr(c, '\n'); + if (!c) + return nports; + c++; nports += 1; } diff --git a/trunk/drivers/staging/usbip/vhci_hcd.c b/trunk/drivers/staging/usbip/vhci_hcd.c index dca9bf11f0c2..f708cbaee16b 100644 --- a/trunk/drivers/staging/usbip/vhci_hcd.c +++ b/trunk/drivers/staging/usbip/vhci_hcd.c @@ -821,10 +821,10 @@ static void vhci_shutdown_connection(struct usbip_device *ud) } /* kill threads related to this sdev, if v.c. exists */ - if (vdev->ud.tcp_rx && !task_is_dead(vdev->ud.tcp_rx)) - kthread_stop(vdev->ud.tcp_rx); - if (vdev->ud.tcp_tx && !task_is_dead(vdev->ud.tcp_tx)) - kthread_stop(vdev->ud.tcp_tx); + if (vdev->ud.tcp_rx) + kthread_stop_put(vdev->ud.tcp_rx); + if (vdev->ud.tcp_tx) + kthread_stop_put(vdev->ud.tcp_tx); pr_info("stop threads\n"); diff --git a/trunk/drivers/staging/usbip/vhci_rx.c b/trunk/drivers/staging/usbip/vhci_rx.c index f5fba7320c5a..f0eaf04fa25b 100644 --- a/trunk/drivers/staging/usbip/vhci_rx.c +++ b/trunk/drivers/staging/usbip/vhci_rx.c @@ -162,7 +162,7 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev, * already received the result of its submit result and gave * back the URB. */ - pr_info("the urb (seqnum %d) was already given backed\n", + pr_info("the urb (seqnum %d) was already given back\n", pdu->base.seqnum); } else { usbip_dbg_vhci_rx("now giveback urb %p\n", urb); diff --git a/trunk/drivers/staging/usbip/vhci_sysfs.c b/trunk/drivers/staging/usbip/vhci_sysfs.c index 0cd039bb5fd6..7ce9c2f7e442 100644 --- a/trunk/drivers/staging/usbip/vhci_sysfs.c +++ b/trunk/drivers/staging/usbip/vhci_sysfs.c @@ -222,8 +222,8 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, spin_unlock(&the_controller->lock); /* end the lock */ - vdev->ud.tcp_rx = kthread_run(vhci_rx_loop, &vdev->ud, "vhci_rx"); - vdev->ud.tcp_tx = kthread_run(vhci_tx_loop, &vdev->ud, "vhci_tx"); + vdev->ud.tcp_rx = kthread_get_run(vhci_rx_loop, &vdev->ud, "vhci_rx"); + vdev->ud.tcp_tx = kthread_get_run(vhci_tx_loop, &vdev->ud, "vhci_tx"); rh_port_connect(rhport, speed); diff --git a/trunk/drivers/staging/vme/Kconfig b/trunk/drivers/staging/vme/Kconfig deleted file mode 100644 index 6411ae51ed3f..000000000000 --- a/trunk/drivers/staging/vme/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -# -# VME configuration. -# - -menuconfig VME_BUS - tristate "VME bridge support" - depends on PCI - ---help--- - If you say Y here you get support for the VME bridge Framework. - -if VME_BUS - -source "drivers/staging/vme/bridges/Kconfig" - -source "drivers/staging/vme/devices/Kconfig" - -source "drivers/staging/vme/boards/Kconfig" - -endif # VME diff --git a/trunk/drivers/staging/vme/Makefile b/trunk/drivers/staging/vme/Makefile index b4ea3f8d0a50..accdb72e39e2 100644 --- a/trunk/drivers/staging/vme/Makefile +++ b/trunk/drivers/staging/vme/Makefile @@ -1,8 +1 @@ -# -# Makefile for the VME bridge device drivers. -# -obj-$(CONFIG_VME_BUS) += vme.o - -obj-y += bridges/ obj-y += devices/ -obj-y += boards/ diff --git a/trunk/drivers/staging/vme/TODO b/trunk/drivers/staging/vme/TODO deleted file mode 100644 index 79f00333e7ef..000000000000 --- a/trunk/drivers/staging/vme/TODO +++ /dev/null @@ -1,5 +0,0 @@ - TODO - ==== - -- Add one or more device drivers which use the VME framework. - diff --git a/trunk/drivers/staging/vme/devices/Kconfig b/trunk/drivers/staging/vme/devices/Kconfig index 55ec30cb1fa2..d0cab1766190 100644 --- a/trunk/drivers/staging/vme/devices/Kconfig +++ b/trunk/drivers/staging/vme/devices/Kconfig @@ -2,6 +2,7 @@ comment "VME Device Drivers" config VME_USER tristate "VME user space access driver" + depends on STAGING help If you say Y here you want to be able to access a limited number of VME windows in a manner at least semi-compatible with the interface @@ -9,7 +10,7 @@ config VME_USER config VME_PIO2 tristate "GE PIO2 VME" - depends on GPIOLIB + depends on STAGING && GPIOLIB help Say Y here to include support for the GE PIO2. The PIO2 is a 6U VME slave card, implementing 32 solid-state relay switched IO lines, in diff --git a/trunk/drivers/staging/vme/devices/vme_pio2_cntr.c b/trunk/drivers/staging/vme/devices/vme_pio2_cntr.c index 08e0d59806ca..6335471faa36 100644 --- a/trunk/drivers/staging/vme/devices/vme_pio2_cntr.c +++ b/trunk/drivers/staging/vme/devices/vme_pio2_cntr.c @@ -17,8 +17,8 @@ #include #include #include +#include -#include "../vme.h" #include "vme_pio2.h" static int pio2_cntr_irq_set(struct pio2_card *card, int id) diff --git a/trunk/drivers/staging/vme/devices/vme_pio2_core.c b/trunk/drivers/staging/vme/devices/vme_pio2_core.c index 573c80003f0c..4bf8e05ac312 100644 --- a/trunk/drivers/staging/vme/devices/vme_pio2_core.c +++ b/trunk/drivers/staging/vme/devices/vme_pio2_core.c @@ -10,7 +10,6 @@ * option) any later version. */ -#include #include #include #include @@ -20,8 +19,8 @@ #include #include #include +#include -#include "../vme.h" #include "vme_pio2.h" diff --git a/trunk/drivers/staging/vme/devices/vme_pio2_gpio.c b/trunk/drivers/staging/vme/devices/vme_pio2_gpio.c index 858484915f08..ad76a477825b 100644 --- a/trunk/drivers/staging/vme/devices/vme_pio2_gpio.c +++ b/trunk/drivers/staging/vme/devices/vme_pio2_gpio.c @@ -10,7 +10,6 @@ * option) any later version. */ -#include #include #include #include @@ -21,8 +20,8 @@ #include #include #include +#include -#include "../vme.h" #include "vme_pio2.h" static const char driver_name[] = "pio2_gpio"; @@ -79,7 +78,7 @@ static void pio2_gpio_set(struct gpio_chip *chip, unsigned int offset, if ((card->bank[PIO2_CHANNEL_BANK[offset]].config == INPUT) | (card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) { - dev_err(&card->vdev->dev, "Channel not availabe as output\n"); + dev_err(&card->vdev->dev, "Channel not available as output\n"); return; } diff --git a/trunk/drivers/staging/vme/devices/vme_user.c b/trunk/drivers/staging/vme/devices/vme_user.c index 7dcd1622b5f5..e24a6f95db12 100644 --- a/trunk/drivers/staging/vme/devices/vme_user.c +++ b/trunk/drivers/staging/vme/devices/vme_user.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include @@ -36,8 +36,8 @@ #include #include +#include -#include "../vme.h" #include "vme_user.h" static DEFINE_MUTEX(vme_user_mutex); @@ -95,7 +95,7 @@ struct image_desc { void *kern_buf; /* Buffer address in kernel space */ dma_addr_t pci_buf; /* Buffer address in PCI address space */ unsigned long long size_buf; /* Buffer size */ - struct semaphore sem; /* Semaphore for locking image */ + struct mutex mutex; /* Mutex for locking image */ struct device *device; /* Sysfs device */ struct vme_resource *resource; /* VME resource */ int users; /* Number of current users */ @@ -168,7 +168,7 @@ static int vme_user_open(struct inode *inode, struct file *file) int err; unsigned int minor = MINOR(inode->i_rdev); - down(&image[minor].sem); + mutex_lock(&image[minor].mutex); /* Allow device to be opened if a resource is needed and allocated. */ if (minor < CONTROL_MINOR && image[minor].resource == NULL) { printk(KERN_ERR "No resources allocated for device\n"); @@ -179,12 +179,12 @@ static int vme_user_open(struct inode *inode, struct file *file) /* Increment user count */ image[minor].users++; - up(&image[minor].sem); + mutex_unlock(&image[minor].mutex); return 0; err_res: - up(&image[minor].sem); + mutex_unlock(&image[minor].mutex); return err; } @@ -193,12 +193,12 @@ static int vme_user_release(struct inode *inode, struct file *file) { unsigned int minor = MINOR(inode->i_rdev); - down(&image[minor].sem); + mutex_lock(&image[minor].mutex); /* Decrement user count */ image[minor].users--; - up(&image[minor].sem); + mutex_unlock(&image[minor].mutex); return 0; } @@ -325,14 +325,14 @@ static ssize_t vme_user_read(struct file *file, char __user *buf, size_t count, if (minor == CONTROL_MINOR) return 0; - down(&image[minor].sem); + mutex_lock(&image[minor].mutex); /* XXX Do we *really* want this helper - we can use vme_*_get ? */ image_size = vme_get_size(image[minor].resource); /* Ensure we are starting at a valid location */ if ((*ppos < 0) || (*ppos > (image_size - 1))) { - up(&image[minor].sem); + mutex_unlock(&image[minor].mutex); return 0; } @@ -353,8 +353,7 @@ static ssize_t vme_user_read(struct file *file, char __user *buf, size_t count, retval = -EINVAL; } - up(&image[minor].sem); - + mutex_unlock(&image[minor].mutex); if (retval > 0) *ppos += retval; @@ -372,13 +371,13 @@ static ssize_t vme_user_write(struct file *file, const char __user *buf, if (minor == CONTROL_MINOR) return 0; - down(&image[minor].sem); + mutex_lock(&image[minor].mutex); image_size = vme_get_size(image[minor].resource); /* Ensure we are starting at a valid location */ if ((*ppos < 0) || (*ppos > (image_size - 1))) { - up(&image[minor].sem); + mutex_unlock(&image[minor].mutex); return 0; } @@ -398,8 +397,8 @@ static ssize_t vme_user_write(struct file *file, const char __user *buf, default: retval = -EINVAL; } - - up(&image[minor].sem); + + mutex_unlock(&image[minor].mutex); if (retval > 0) *ppos += retval; @@ -416,7 +415,7 @@ static loff_t vme_user_llseek(struct file *file, loff_t off, int whence) if (minor == CONTROL_MINOR) return -EINVAL; - down(&image[minor].sem); + mutex_lock(&image[minor].mutex); image_size = vme_get_size(image[minor].resource); switch (whence) { @@ -430,19 +429,19 @@ static loff_t vme_user_llseek(struct file *file, loff_t off, int whence) absolute = image_size + off; break; default: - up(&image[minor].sem); + mutex_unlock(&image[minor].mutex); return -EINVAL; break; } if ((absolute < 0) || (absolute >= image_size)) { - up(&image[minor].sem); + mutex_unlock(&image[minor].mutex); return -EINVAL; } file->f_pos = absolute; - up(&image[minor].sem); + mutex_unlock(&image[minor].mutex); return absolute; } @@ -696,7 +695,7 @@ static int __devinit vme_user_probe(struct vme_dev *vdev) for (i = 0; i < VME_DEVS; i++) { image[i].kern_buf = NULL; image[i].pci_buf = 0; - sema_init(&image[i].sem, 1); + mutex_init(&image[i].mutex); image[i].device = NULL; image[i].resource = NULL; image[i].users = 0; @@ -858,8 +857,10 @@ static int __devexit vme_user_remove(struct vme_dev *dev) int i; /* Remove sysfs Entries */ - for (i = 0; i < VME_DEVS; i++) + for (i = 0; i < VME_DEVS; i++) { + mutex_destroy(&image[i].mutex); device_destroy(vme_user_sysfs_class, MKDEV(VME_MAJOR, i)); + } class_destroy(vme_user_sysfs_class); for (i = MASTER_MINOR; i < (MASTER_MAX + 1); i++) { diff --git a/trunk/drivers/staging/vt6655/wpa.c b/trunk/drivers/staging/vt6655/wpa.c index 61ac46fa505e..0afb9fe0379a 100644 --- a/trunk/drivers/staging/vt6655/wpa.c +++ b/trunk/drivers/staging/vt6655/wpa.c @@ -148,7 +148,7 @@ WPA_ParseRSN ( { j = 0; DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wPKCount: %d, sizeof(pBSSList->abyPKType): %zu\n", pRSN->wPKCount, sizeof(pBSSList->abyPKType)); - for(i = 0; (i < pRSN->wPKCount) && (j < sizeof(pBSSList->abyPKType)/sizeof(unsigned char)); i++) { + for(i = 0; (i < pRSN->wPKCount) && (j < ARRAY_SIZE(pBSSList->abyPKType)); i++) { if(pRSN->len >= 12+i*4+4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*i) if ( !memcmp(pRSN->PKSList[i].abyOUI, abyOUI00, 4)) pBSSList->abyPKType[j++] = WPA_NONE; @@ -180,7 +180,7 @@ WPA_ParseRSN ( j = 0; DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wAuthCount: %d, sizeof(pBSSList->abyAuthType): %zu\n", pIE_RSN_Auth->wAuthCount, sizeof(pBSSList->abyAuthType)); - for(i = 0; (i < pIE_RSN_Auth->wAuthCount) && (j < sizeof(pBSSList->abyAuthType)/sizeof(unsigned char)); i++) { + for(i = 0; (i < pIE_RSN_Auth->wAuthCount) && (j < ARRAY_SIZE(pBSSList->abyAuthType)); i++) { if(pRSN->len >= 14+4+(m+i)*4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*m)+AKC(2)+AKS(4*i) if ( !memcmp(pIE_RSN_Auth->AuthKSList[i].abyOUI, abyOUI01, 4)) pBSSList->abyAuthType[j++] = WPA_AUTH_IEEE802_1X; diff --git a/trunk/drivers/staging/vt6656/dpc.c b/trunk/drivers/staging/vt6656/dpc.c index c0edf97535dc..e4bdf2a2b582 100644 --- a/trunk/drivers/staging/vt6656/dpc.c +++ b/trunk/drivers/staging/vt6656/dpc.c @@ -452,7 +452,7 @@ RXbBulkInProcessData ( } } - if (!is_multicast_ether_addr(pMACHeader->abyAddr1) && !is_broadcast_ether_addr(pMACHeader->abyAddr1)) { + if (!is_multicast_ether_addr(pMACHeader->abyAddr1)) { if ( WCTLbIsDuplicate(&(pDevice->sDupRxCache), (PS802_11Header) pbyFrame) ) { pDevice->s802_11Counter.FrameDuplicateCount++; return FALSE; diff --git a/trunk/drivers/staging/vt6656/ioctl.c b/trunk/drivers/staging/vt6656/ioctl.c index d59456c29df1..5b9a84f95185 100644 --- a/trunk/drivers/staging/vt6656/ioctl.c +++ b/trunk/drivers/staging/vt6656/ioctl.c @@ -90,18 +90,17 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) spin_lock_irq(&pDevice->lock); if (memcmp(pMgmt->abyCurrBSSID, &abyNullAddr[0], 6) == 0) - BSSvClearBSSList((void *)pDevice, FALSE); + BSSvClearBSSList(pDevice, FALSE); else - BSSvClearBSSList((void *)pDevice, pDevice->bLinkPass); + BSSvClearBSSList(pDevice, pDevice->bLinkPass); DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WLAN_CMD_BSS_SCAN..begin\n"); if (pItemSSID->len != 0) - bScheduleCommand((void *)pDevice, - WLAN_CMD_BSSID_SCAN, + bScheduleCommand(pDevice, WLAN_CMD_BSSID_SCAN, abyScanSSID); else - bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN, NULL); + bScheduleCommand(pDevice, WLAN_CMD_BSSID_SCAN, NULL); spin_unlock_irq(&pDevice->lock); break; @@ -150,6 +149,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) } } break; + case WLAN_CMD_BSS_JOIN: if (copy_from_user(&sJoinCmd, pReq->data, sizeof(SCmdBSSJoin))) { result = -EFAULT; @@ -190,10 +190,9 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) netif_stop_queue(pDevice->dev); spin_lock_irq(&pDevice->lock); pMgmt->eCurrState = WMAC_STATE_IDLE; - bScheduleCommand((void *) pDevice, - WLAN_CMD_BSSID_SCAN, + bScheduleCommand(pDevice, WLAN_CMD_BSSID_SCAN, pMgmt->abyDesireSSID); - bScheduleCommand((void *) pDevice, WLAN_CMD_SSID, NULL); + bScheduleCommand(pDevice, WLAN_CMD_SSID, NULL); spin_unlock_irq(&pDevice->lock); break; @@ -299,7 +298,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) result = -EINVAL; break; } - pList = (PSBSSIDList)kmalloc(sizeof(SBSSIDList) + (sList.uItem * sizeof(SBSSIDItem)), (int)GFP_ATOMIC); + pList = kmalloc(sizeof(SBSSIDList) + (sList.uItem * sizeof(SBSSIDItem)), GFP_ATOMIC); if (pList == NULL) { result = -ENOMEM; break; @@ -313,7 +312,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) pList->sBSSIDList[ii].wBeaconInterval = pBSS->wBeaconInterval; pList->sBSSIDList[ii].wCapInfo = pBSS->wCapInfo; RFvRSSITodBm(pDevice, (BYTE)(pBSS->uRSSI), &ldBm); - pList->sBSSIDList[ii].uRSSI = (unsigned int) ldBm; + pList->sBSSIDList[ii].uRSSI = (unsigned int)ldBm; /* pList->sBSSIDList[ii].uRSSI = pBSS->uRSSI; */ memcpy(pList->sBSSIDList[ii].abyBSSID, pBSS->abyBSSID, WLAN_BSSID_LEN); pItemSSID = (PWLAN_IE_SSID)pBSS->abySSID; @@ -356,6 +355,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) break; } break; + case WLAN_CMD_STOP_MAC: DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WLAN_CMD_STOP_MAC\n"); /* Todo xxxxxx */ @@ -534,7 +534,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) netif_stop_queue(pDevice->dev); spin_lock_irq(&pDevice->lock); - bScheduleCommand((void *)pDevice, WLAN_CMD_RUN_AP, NULL); + bScheduleCommand(pDevice, WLAN_CMD_RUN_AP, NULL); spin_unlock_irq(&pDevice->lock); break; @@ -565,7 +565,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) result = -ENOMEM; break; } - pNodeList = kmalloc(sizeof(SNodeList) + (sNodeList.uItem * sizeof(SNodeItem)), (int)GFP_ATOMIC); + pNodeList = kmalloc(sizeof(SNodeList) + (sNodeList.uItem * sizeof(SNodeItem)), GFP_ATOMIC); if (pNodeList == NULL) { result = -ENOMEM; break; diff --git a/trunk/drivers/staging/vt6656/main_usb.c b/trunk/drivers/staging/vt6656/main_usb.c index 763e028a5cc5..ee5261a36886 100644 --- a/trunk/drivers/staging/vt6656/main_usb.c +++ b/trunk/drivers/staging/vt6656/main_usb.c @@ -1257,9 +1257,7 @@ static void __devexit vt6656_disconnect(struct usb_interface *intf) } device_release_WPADEV(device); - - if (device->firmware) - release_firmware(device->firmware); + release_firmware(device->firmware); usb_set_intfdata(intf, NULL); usb_put_dev(interface_to_usbdev(intf)); diff --git a/trunk/drivers/staging/vt6656/wpa.c b/trunk/drivers/staging/vt6656/wpa.c index 7dde3d6941ab..b16d4ddc117b 100644 --- a/trunk/drivers/staging/vt6656/wpa.c +++ b/trunk/drivers/staging/vt6656/wpa.c @@ -149,7 +149,7 @@ WPA_ParseRSN( j = 0; DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wPKCount: %d, sizeof(pBSSList->abyPKType): %zu\n", pRSN->wPKCount, sizeof(pBSSList->abyPKType)); for (i = 0; (i < pRSN->wPKCount) && - (j < sizeof(pBSSList->abyPKType)/sizeof(BYTE)); i++) { + (j < ARRAY_SIZE(pBSSList->abyPKType)); i++) { if(pRSN->len >= 12+i*4+4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*i) if ( !memcmp(pRSN->PKSList[i].abyOUI, abyOUI00, 4)) pBSSList->abyPKType[j++] = WPA_NONE; @@ -182,7 +182,7 @@ WPA_ParseRSN( DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wAuthCount: %d, sizeof(pBSSList->abyAuthType): %zu\n", pIE_RSN_Auth->wAuthCount, sizeof(pBSSList->abyAuthType)); for (i = 0; (i < pIE_RSN_Auth->wAuthCount) && - (j < sizeof(pBSSList->abyAuthType)/sizeof(BYTE)); i++) { + (j < ARRAY_SIZE(pBSSList->abyAuthType)); i++) { if(pRSN->len >= 14+4+(m+i)*4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*m)+AKC(2)+AKS(4*i) if ( !memcmp(pIE_RSN_Auth->AuthKSList[i].abyOUI, abyOUI01, 4)) pBSSList->abyAuthType[j++] = WPA_AUTH_IEEE802_1X; diff --git a/trunk/drivers/staging/wlags49_h2/README.ubuntu b/trunk/drivers/staging/wlags49_h2/README.ubuntu index edee8b9385be..5f1cfb8fd427 100644 --- a/trunk/drivers/staging/wlags49_h2/README.ubuntu +++ b/trunk/drivers/staging/wlags49_h2/README.ubuntu @@ -87,7 +87,7 @@ The linux driver files (wl_xxxx.c) are changed in the following ways: -- Recovery actions added The major problem was the order in which calls can be made. The original -looks like a traditonal UNIX driver. To call an "ioctl" function you +looks like a traditional UNIX driver. To call an "ioctl" function you have to "open" the device first to get a handle and after "close" no "ioctl" function can be called anymore. With the 2.6 driver this all changed; the former ioctl functions are now called before "open" and diff --git a/trunk/drivers/staging/wlags49_h2/hcf.c b/trunk/drivers/staging/wlags49_h2/hcf.c index 5957c3a439ac..366e4a4b75c5 100644 --- a/trunk/drivers/staging/wlags49_h2/hcf.c +++ b/trunk/drivers/staging/wlags49_h2/hcf.c @@ -2871,8 +2871,8 @@ or * The Assert validates the HCF assumption about Hermes implementation upon which the range of * Pseudo-RIDs is based. * Then the control fields up to the start of the 802.3 frame are read from the NIC into the lookahead buffer. -* The status field is converted to native Endianess. -* The length is, after implicit Endianess conversion if needed, and adjustment for the 14 bytes of the +* The status field is converted to native Endianness. +* The length is, after implicit Endianness conversion if needed, and adjustment for the 14 bytes of the * 802.3 MAC header, stored in IFB_RxLen. * In MAC Monitor mode, 802.11 control frames with a TOTAL length of 14 are received, so without this * length adjustment, IFB_RxLen could not be used to distinguish these frames from "no frame". @@ -2894,7 +2894,7 @@ or * - the Hermes reported Tunnel encapsulation or * - the Hermes reported 1042 Encapsulation and hcf_encap reports that the HCF would not have used * 1042 as the encapsulation mechanism -* Note that the first field of the RxFS in bufp has Native Endianess due to the conversion done by the +* Note that the first field of the RxFS in bufp has Native Endianness due to the conversion done by the * BE_PAR in get_frag. *36: The Type field is the only word kept (after moving) of the just read 8 bytes, it is moved to the * L-field. The original L-field and 6 byte SNAP header are discarded, so IFB_RxLen and buf_addr must @@ -3831,7 +3831,7 @@ get_fid( IFBP ifbp ) *.DESCRIPTION * process the single byte (if applicable) read by the previous get_frag and copy len (or len-1) bytes from * NIC to bufp. - * On a Big Endian platform, the parameter word_len controls the number of leading bytes whose endianess is + * On a Big Endian platform, the parameter word_len controls the number of leading bytes whose endianness is * converted (i.e. byte swapped) * * @@ -3980,7 +3980,7 @@ get_frag( IFBP ifbp, wci_bufp bufp, int len BE_PAR( int word_len ) ) * appropriate means on H-I: always * and on H-II if F/W supplier reflects a primary (i.e. only after an Hermes Reset or Init * command). - * QUESTION ;? !!!!!! should, For each of the above RIDs the Endianess is converted to native Endianess. + * QUESTION ;? !!!!!! should, For each of the above RIDs the Endianness is converted to native Endianness. * Only the return code of the first hcf_get_info is used. All hcf_get_info calls are made, regardless of * the success or failure of the 1st hcf_get_info. The assumptions are: * - if any call fails, they all fail, so remembering the result of the 1st call is adequate diff --git a/trunk/drivers/staging/wlags49_h2/hcf.h b/trunk/drivers/staging/wlags49_h2/hcf.h index 95527b5cf863..68e23303b5e8 100644 --- a/trunk/drivers/staging/wlags49_h2/hcf.h +++ b/trunk/drivers/staging/wlags49_h2/hcf.h @@ -90,7 +90,7 @@ #define LOF(x) (sizeof(x)/sizeof(hcf_16)-1) -/* Endianess +/* Endianness * Little Endian (a.k.a. Intel), least significant byte first * Big Endian (a.k.a. Motorola), most significant byte first * @@ -101,7 +101,7 @@ */ /* To increase portability, use unsigned char and unsigned char * when accessing parts of larger - * types to convert their Endianess + * types to convert their Endianness */ #define CNV_END_SHORT(w) (hcf_16)( ((hcf_16)(w) & 0x00FF) << 8 | ((hcf_16)(w) & 0xFF00) >> 8 ) @@ -109,14 +109,14 @@ #if HCF_BIG_ENDIAN //******************************************** B I G E N D I A N ******************************************* -#define CNV_LITTLE_TO_SHORT(w) CNV_END_SHORT(w) // endianess conversion needed -#define CNV_BIG_TO_SHORT(w) (w) // no endianess conversion needed +#define CNV_LITTLE_TO_SHORT(w) CNV_END_SHORT(w) // endianness conversion needed +#define CNV_BIG_TO_SHORT(w) (w) // no endianness conversion needed #define CNV_LITTLE_TO_LONG(dw) CNV_END_LONG(dw) #define CNV_LONG_TO_LITTLE(dw) CNV_END_LONG(dw) #else //****************************************** L I T T L E E N D I A N **************************************** -#define CNV_LITTLE_TO_SHORT(w) (w) // no endianess conversion needed -#define CNV_BIG_TO_SHORT(w) CNV_END_SHORT(w) // endianess conversion needed +#define CNV_LITTLE_TO_SHORT(w) (w) // no endianness conversion needed +#define CNV_BIG_TO_SHORT(w) CNV_END_SHORT(w) // endianness conversion needed #define CNV_LITTLE_TO_LONG(dw) (dw) #define CNV_LONG_TO_LITTLE(dw) (dw) diff --git a/trunk/drivers/staging/wlags49_h2/mmd.c b/trunk/drivers/staging/wlags49_h2/mmd.c index c8f52107e6ca..7204a373bc51 100644 --- a/trunk/drivers/staging/wlags49_h2/mmd.c +++ b/trunk/drivers/staging/wlags49_h2/mmd.c @@ -101,10 +101,10 @@ * supp address of the supplier specification * * Description: mmd_check_comp is a support routine to check the compatibility between an actor and a -* supplier. mmd_check_comp is independent of the endianess of the actp and supp structures. This is +* supplier. mmd_check_comp is independent of the endianness of the actp and supp structures. This is * achieved by checking the "bottom" or "role" fields of these structures. Since these fields are restricted * to a limited range, comparing the contents to a value with a known endian-ess gives a clue to their actual -* endianess. +* endianness. * *.DIAGRAM *1a: The role-field of the actor structure has a known non-zero, not "byte symmetric" value (namely @@ -114,16 +114,16 @@ * for a supplier. A supplier has always exactly 1 variant,top,bottom record with (officially, but see the * note below) each of these 3 values in the range 1 through 99, so one byte of the word value of variant, * top and bottom words is 0x00 and the other byte is non-zero. Whether the lowest address byte or the -* highest address byte is non-zero depends on the Endianess of the LTV. If and only if the word value of +* highest address byte is non-zero depends on the Endianness of the LTV. If and only if the word value of * bottom is less than 0x0100, the supplier is Native Endian. * NOTE: the variant field of the supplier structure can not be used for the Endian Detection Algorithm, * because a a zero-valued variant has been used as Controlled Deployment indication in the past. * Note: An actor may have multiple sets of variant,top,bottom records, including dummy sets with variant, -* top and bottom fields with a zero-value. As a consequence the endianess of the actor can not be determined +* top and bottom fields with a zero-value. As a consequence the endianness of the actor can not be determined * based on its variant,top,bottom values. * * Note: the L and T field of the structures are always in Native Endian format, so you can not draw -* conclusions concerning the Endianess of the structure based on these two fields. +* conclusions concerning the Endianness of the structure based on these two fields. * *1b/2b * The only purpose of the CFG_RANGE_SPEC_BYTE_STRCT is to give easy access to the non-zero byte of the word @@ -149,7 +149,7 @@ * * This is implemented as: * #if HCF_BIG_ENDIAN == 0 //platform is LE -* sup/act_endian becomes reverse of structure-endianess as determined in 1a/1b +* sup/act_endian becomes reverse of structure-endianness as determined in 1a/1b * #endif *6: Each of the actor variant-bottom-top records is checked against the (single) supplier variant-bottom-top * range till either an acceptable match is found or all actor records are tried. As explained above, due to diff --git a/trunk/drivers/staging/wlags49_h2/wl_cs.c b/trunk/drivers/staging/wlags49_h2/wl_cs.c index 7084f414846e..7c7c77f9c862 100644 --- a/trunk/drivers/staging/wlags49_h2/wl_cs.c +++ b/trunk/drivers/staging/wlags49_h2/wl_cs.c @@ -177,10 +177,9 @@ static void wl_adapter_detach(struct pcmcia_device *link) if (dev) { unregister_wlags_sysfs(dev); unregister_netdev(dev); + wl_device_dealloc(dev); } - wl_device_dealloc(dev); - DBG_LEAVE(DbgInfo); } /* wl_adapter_detach */ /*============================================================================*/ diff --git a/trunk/drivers/staging/wlags49_h2/wl_netdev.c b/trunk/drivers/staging/wlags49_h2/wl_netdev.c index 90820ff1aced..824b85232353 100644 --- a/trunk/drivers/staging/wlags49_h2/wl_netdev.c +++ b/trunk/drivers/staging/wlags49_h2/wl_netdev.c @@ -1063,7 +1063,7 @@ void wl_multicast( struct net_device *dev ) #if DBG if( DBG_FLAGS( DbgInfo ) & DBG_PARAM_ON ) { DBG_PRINT(" flags: %s%s%s\n", - ( dev->flags & IFF_PROMISC ) ? "Promiscous " : "", + ( dev->flags & IFF_PROMISC ) ? "Promiscuous " : "", ( dev->flags & IFF_MULTICAST ) ? "Multicast " : "", ( dev->flags & IFF_ALLMULTI ) ? "All-Multicast" : "" ); @@ -1510,8 +1510,11 @@ void wl_wds_device_alloc( struct wl_private *lp ) for( count = 0; count < NUM_WDS_PORTS; count++ ) { struct net_device *dev_wds = NULL; - dev_wds = kmalloc( sizeof( struct net_device ), GFP_KERNEL ); - memset( dev_wds, 0, sizeof( struct net_device )); + dev_wds = kzalloc(sizeof(struct net_device), GFP_KERNEL); + if (!dev_wds) { + DBG_LEAVE(DbgInfo); + return; + } ether_setup( dev_wds ); diff --git a/trunk/drivers/staging/wlags49_h2/wl_pci.c b/trunk/drivers/staging/wlags49_h2/wl_pci.c index 3df990c7306a..0b31b01bd490 100644 --- a/trunk/drivers/staging/wlags49_h2/wl_pci.c +++ b/trunk/drivers/staging/wlags49_h2/wl_pci.c @@ -524,6 +524,7 @@ int wl_pci_setup( struct pci_dev *pdev ) /* Make sure that space was allocated for our private adapter struct */ if( dev->priv == NULL ) { DBG_ERROR( DbgInfo, "Private adapter struct was not allocated!!!\n" ); + wl_device_dealloc(dev); DBG_LEAVE( DbgInfo ); return -ENOMEM; } @@ -532,6 +533,7 @@ int wl_pci_setup( struct pci_dev *pdev ) /* Allocate DMA Descriptors */ if( wl_pci_dma_alloc( pdev, dev->priv ) < 0 ) { DBG_ERROR( DbgInfo, "Could not allocate DMA descriptor memory!!!\n" ); + wl_device_dealloc(dev); DBG_LEAVE( DbgInfo ); return -ENOMEM; } @@ -561,6 +563,8 @@ int wl_pci_setup( struct pci_dev *pdev ) result = request_irq(dev->irq, wl_isr, SA_SHIRQ, dev->name, dev); if( result ) { DBG_WARNING( DbgInfo, "Could not register ISR!!!\n" ); + wl_remove(dev); + wl_device_dealloc(dev); DBG_LEAVE( DbgInfo ); return result; } diff --git a/trunk/drivers/staging/wlags49_h2/wl_profile.c b/trunk/drivers/staging/wlags49_h2/wl_profile.c index b8c96cf18de5..0e49272bc7a8 100644 --- a/trunk/drivers/staging/wlags49_h2/wl_profile.c +++ b/trunk/drivers/staging/wlags49_h2/wl_profile.c @@ -401,7 +401,7 @@ void translate_option(char *buffer, struct wl_private *lp) if ((value_convert >= PARM_MIN_BRSC) || (value_convert <= PARM_MAX_BRSC)) lp->brsc[0] = value_convert; else - DBG_WARNING(DbgInfo, "%s invaid; will be ignored\n", PARM_NAME_BRSC_2GHZ); + DBG_WARNING(DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_BRSC_2GHZ); } else if (strcmp(key, PARM_NAME_BRSC_5GHZ) == 0) { DBG_TRACE(DbgInfo, "%s, value: %s\n", PARM_NAME_BRSC_5GHZ, value); @@ -409,7 +409,7 @@ void translate_option(char *buffer, struct wl_private *lp) if ((value_convert >= PARM_MIN_BRSC) || (value_convert <= PARM_MAX_BRSC)) lp->brsc[1] = value_convert; else - DBG_WARNING(DbgInfo, "%s invaid; will be ignored\n", PARM_NAME_BRSC_5GHZ); + DBG_WARNING(DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_BRSC_5GHZ); } else if ((strcmp(key, PARM_NAME_DESIRED_SSID) == 0) || (strcmp(key, PARM_NAME_OWN_SSID) == 0)) { DBG_TRACE(DbgInfo, "SSID, value: %s\n", value); @@ -556,7 +556,7 @@ void translate_option(char *buffer, struct wl_private *lp) if ((value_convert >= PARM_MIN_SRSC) || (value_convert <= PARM_MAX_SRSC)) lp->srsc[0] = value_convert; else - DBG_WARNING(DbgInfo, "%s invaid; will be ignored\n", PARM_NAME_SRSC_2GHZ); + DBG_WARNING(DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_SRSC_2GHZ); } else if (strcmp(key, PARM_NAME_SRSC_5GHZ) == 0) { DBG_TRACE(DbgInfo, "%s, value: %s\n", PARM_NAME_SRSC_5GHZ, value); @@ -564,7 +564,7 @@ void translate_option(char *buffer, struct wl_private *lp) if ((value_convert >= PARM_MIN_SRSC) || (value_convert <= PARM_MAX_SRSC)) lp->srsc[1] = value_convert; else - DBG_WARNING(DbgInfo, "%s invaid; will be ignored\n", PARM_NAME_SRSC_5GHZ); + DBG_WARNING(DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_SRSC_5GHZ); } else if (strcmp(key, PARM_NAME_SYSTEM_SCALE) == 0) { DBG_TRACE(DbgInfo, "%s, value: %s\n", PARM_NAME_SYSTEM_SCALE, value); diff --git a/trunk/drivers/staging/wlags49_h2/wl_util.c b/trunk/drivers/staging/wlags49_h2/wl_util.c index f104e6f1e980..404ec7da0348 100644 --- a/trunk/drivers/staging/wlags49_h2/wl_util.c +++ b/trunk/drivers/staging/wlags49_h2/wl_util.c @@ -98,8 +98,7 @@ ******************************************************************************/ /* A matrix which maps channels to frequencies */ -#define MAX_CHAN_FREQ_MAP_ENTRIES 50 -static const long chan_freq_list[][MAX_CHAN_FREQ_MAP_ENTRIES] = +static const long chan_freq_list[][2] = { {1,2412}, {2,2417}, @@ -846,7 +845,7 @@ int wl_is_a_valid_chan( int channel ) } /* Iterate through the matrix and retrieve the frequency */ - for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) { + for( i = 0; i < ARRAY_SIZE(chan_freq_list); i++ ) { if( chan_freq_list[i][0] == channel ) { return 1; } @@ -884,7 +883,7 @@ int wl_is_a_valid_freq( long frequency ) /* Iterate through the matrix and retrieve the channel */ - for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) { + for( i = 0; i < ARRAY_SIZE(chan_freq_list); i++ ) { if( chan_freq_list[i][1] == frequency ) { return 1; } @@ -927,7 +926,7 @@ long wl_get_freq_from_chan( int channel ) } /* Iterate through the matrix and retrieve the frequency */ - for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) { + for( i = 0; i < ARRAY_SIZE(chan_freq_list); i++ ) { if( chan_freq_list[i][0] == channel ) { return chan_freq_list[i][1]; } @@ -965,7 +964,7 @@ int wl_get_chan_from_freq( long frequency ) /* Iterate through the matrix and retrieve the channel */ - for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) { + for( i = 0; i < ARRAY_SIZE(chan_freq_list); i++ ) { if( chan_freq_list[i][1] == frequency ) { return chan_freq_list[i][0]; } diff --git a/trunk/drivers/staging/wlan-ng/cfg80211.c b/trunk/drivers/staging/wlan-ng/cfg80211.c index 4cd3ba5d5646..8bc562b8c4d9 100644 --- a/trunk/drivers/staging/wlan-ng/cfg80211.c +++ b/trunk/drivers/staging/wlan-ng/cfg80211.c @@ -332,6 +332,7 @@ int prism2_scan(struct wiphy *wiphy, struct net_device *dev, wlandevice_t *wlandev = dev->ml_priv; struct p80211msg_dot11req_scan msg1; struct p80211msg_dot11req_scan_results msg2; + struct cfg80211_bss *bss; int result; int err = 0; int numbss = 0; @@ -401,7 +402,7 @@ int prism2_scan(struct wiphy *wiphy, struct net_device *dev, ie_buf[1] = msg2.ssid.data.len; ie_len = ie_buf[1] + 2; memcpy(&ie_buf[2], &(msg2.ssid.data.data), msg2.ssid.data.len); - cfg80211_inform_bss(wiphy, + bss = cfg80211_inform_bss(wiphy, ieee80211_get_channel(wiphy, ieee80211_dsss_chan_to_freq(msg2.dschannel.data)), (const u8 *) &(msg2.bssid.data.data), msg2.timestamp.data, msg2.capinfo.data, @@ -411,6 +412,13 @@ int prism2_scan(struct wiphy *wiphy, struct net_device *dev, (msg2.signal.data - 65536) * 100, /* Conversion to signed type */ GFP_KERNEL ); + + if (!bss) { + err = -ENOMEM; + goto exit; + } + + cfg80211_put_bss(bss); } if (result) diff --git a/trunk/drivers/staging/wlan-ng/prism2mgmt.c b/trunk/drivers/staging/wlan-ng/prism2mgmt.c index c3bb05dd744f..4efa9bc0fcf0 100644 --- a/trunk/drivers/staging/wlan-ng/prism2mgmt.c +++ b/trunk/drivers/staging/wlan-ng/prism2mgmt.c @@ -380,8 +380,8 @@ int prism2mgmt_scan_results(wlandevice_t *wlandev, void *msgp) } count = (hw->scanresults->framelen - 3) / 32; - if (count > 32) - count = 32; + if (count > HFA384x_SCANRESULT_MAX) + count = HFA384x_SCANRESULT_MAX; if (req->bssindex.data >= count) { pr_debug("requested index (%d) out of range (%d)\n", diff --git a/trunk/drivers/staging/xgifb/XGI_main.h b/trunk/drivers/staging/xgifb/XGI_main.h index e828fd403c35..9c62aeb9ede9 100644 --- a/trunk/drivers/staging/xgifb/XGI_main.h +++ b/trunk/drivers/staging/xgifb/XGI_main.h @@ -12,9 +12,6 @@ #define XGIFAIL(x) do { printk(x "\n"); return -EINVAL; } while (0) -#ifndef PCI_DEVICE_ID_XGI_41 -#define PCI_DEVICE_ID_XGI_41 0x041 -#endif #ifndef PCI_DEVICE_ID_XGI_42 #define PCI_DEVICE_ID_XGI_42 0x042 #endif @@ -82,177 +79,79 @@ static int XGIfb_tvplug = -1; /* TW: For ioctl XGIFB_GET_INFO */ /* XGIfb_info XGIfbinfo; */ -#define MD_XGI300 1 -#define MD_XGI315 2 +#define MD_XGI315 1 /* mode table */ static const struct _XGIbios_mode { - char name[15]; u8 mode_no; u16 vesa_mode_no_1; /* "XGI defined" VESA mode number */ u16 vesa_mode_no_2; /* Real VESA mode numbers */ u16 xres; u16 yres; u16 bpp; - u16 rate_idx; - u16 cols; - u16 rows; u8 chipset; } XGIbios_mode[] = { - {"320x240x16", 0x56, 0x0000, 0x0000, 320, 240, 16, 1, 40, 15, - MD_XGI315}, - {"320x480x8", 0x5A, 0x0000, 0x0000, 320, 480, 8, 1, 40, 30, - MD_XGI315}, /* TW: FSTN */ - {"320x480x16", 0x5B, 0x0000, 0x0000, 320, 480, 16, 1, 40, 30, - MD_XGI315}, /* TW: FSTN */ - {"640x480x8", 0x2E, 0x0101, 0x0101, 640, 480, 8, 1, 80, 30, - MD_XGI300|MD_XGI315}, - {"640x480x16", 0x44, 0x0111, 0x0111, 640, 480, 16, 1, 80, 30, - MD_XGI300|MD_XGI315}, - {"640x480x24", 0x62, 0x013a, 0x0112, 640, 480, 32, 1, 80, 30, - MD_XGI300|MD_XGI315}, /* TW: That's for people who mix up color- - and fb depth */ - {"640x480x32", 0x62, 0x013a, 0x0112, 640, 480, 32, 1, 80, 30, - MD_XGI300|MD_XGI315}, - {"720x480x8", 0x31, 0x0000, 0x0000, 720, 480, 8, 1, 90, 30, - MD_XGI300|MD_XGI315}, - {"720x480x16", 0x33, 0x0000, 0x0000, 720, 480, 16, 1, 90, 30, - MD_XGI300|MD_XGI315}, - {"720x480x24", 0x35, 0x0000, 0x0000, 720, 480, 32, 1, 90, 30, - MD_XGI300|MD_XGI315}, - {"720x480x32", 0x35, 0x0000, 0x0000, 720, 480, 32, 1, 90, 30, - MD_XGI300|MD_XGI315}, - {"720x576x8", 0x32, 0x0000, 0x0000, 720, 576, 8, 1, 90, 36, - MD_XGI300|MD_XGI315}, - {"720x576x16", 0x34, 0x0000, 0x0000, 720, 576, 16, 1, 90, 36, - MD_XGI300|MD_XGI315}, - {"720x576x24", 0x36, 0x0000, 0x0000, 720, 576, 32, 1, 90, 36, - MD_XGI300|MD_XGI315}, - {"720x576x32", 0x36, 0x0000, 0x0000, 720, 576, 32, 1, 90, 36, - MD_XGI300|MD_XGI315}, - {"800x480x8", 0x70, 0x0000, 0x0000, 800, 480, 8, 1, 100, 30, - MD_XGI300|MD_XGI315}, - {"800x480x16", 0x7a, 0x0000, 0x0000, 800, 480, 16, 1, 100, 30, - MD_XGI300|MD_XGI315}, - {"800x480x24", 0x76, 0x0000, 0x0000, 800, 480, 32, 1, 100, 30, - MD_XGI300|MD_XGI315}, - {"800x480x32", 0x76, 0x0000, 0x0000, 800, 480, 32, 1, 100, 30, - MD_XGI300|MD_XGI315}, - {"800x600x8", 0x30, 0x0103, 0x0103, 800, 600, 8, 1, 100, 37, - MD_XGI300|MD_XGI315}, -#define DEFAULT_MODE 20 /* index for 800x600x16 */ - {"800x600x16", 0x47, 0x0114, 0x0114, 800, 600, 16, 1, 100, 37, - MD_XGI300|MD_XGI315}, - {"800x600x24", 0x63, 0x013b, 0x0115, 800, 600, 32, 1, 100, 37, - MD_XGI300|MD_XGI315}, - {"800x600x32", 0x63, 0x013b, 0x0115, 800, 600, 32, 1, 100, 37, - MD_XGI300|MD_XGI315}, - {"1024x576x8", 0x71, 0x0000, 0x0000, 1024, 576, 8, 1, 128, 36, - MD_XGI300|MD_XGI315}, - {"1024x576x16", 0x74, 0x0000, 0x0000, 1024, 576, 16, 1, 128, 36, - MD_XGI300|MD_XGI315}, - {"1024x576x24", 0x77, 0x0000, 0x0000, 1024, 576, 32, 1, 128, 36, - MD_XGI300|MD_XGI315}, - {"1024x576x32", 0x77, 0x0000, 0x0000, 1024, 576, 32, 1, 128, 36, - MD_XGI300|MD_XGI315}, - {"1024x600x8", 0x20, 0x0000, 0x0000, 1024, 600, 8, 1, 128, 37, - MD_XGI300 }, /* TW: 300 series only */ - {"1024x600x16", 0x21, 0x0000, 0x0000, 1024, 600, 16, 1, 128, 37, - MD_XGI300 }, - {"1024x600x24", 0x22, 0x0000, 0x0000, 1024, 600, 32, 1, 128, 37, - MD_XGI300 }, - {"1024x600x32", 0x22, 0x0000, 0x0000, 1024, 600, 32, 1, 128, 37, - MD_XGI300 }, - {"1024x768x8", 0x38, 0x0105, 0x0105, 1024, 768, 8, 1, 128, 48, - MD_XGI300|MD_XGI315}, - {"1024x768x16", 0x4A, 0x0117, 0x0117, 1024, 768, 16, 1, 128, 48, - MD_XGI300|MD_XGI315}, - {"1024x768x24", 0x64, 0x013c, 0x0118, 1024, 768, 32, 1, 128, 48, - MD_XGI300|MD_XGI315}, - {"1024x768x32", 0x64, 0x013c, 0x0118, 1024, 768, 32, 1, 128, 48, - MD_XGI300|MD_XGI315}, - {"1152x768x8", 0x23, 0x0000, 0x0000, 1152, 768, 8, 1, 144, 48, - MD_XGI300 }, /* TW: 300 series only */ - {"1152x768x16", 0x24, 0x0000, 0x0000, 1152, 768, 16, 1, 144, 48, - MD_XGI300 }, - {"1152x768x24", 0x25, 0x0000, 0x0000, 1152, 768, 32, 1, 144, 48, - MD_XGI300 }, - {"1152x768x32", 0x25, 0x0000, 0x0000, 1152, 768, 32, 1, 144, 48, - MD_XGI300 }, - {"1280x720x8", 0x79, 0x0000, 0x0000, 1280, 720, 8, 1, 160, 45, - MD_XGI300|MD_XGI315}, - {"1280x720x16", 0x75, 0x0000, 0x0000, 1280, 720, 16, 1, 160, 45, - MD_XGI300|MD_XGI315}, - {"1280x720x24", 0x78, 0x0000, 0x0000, 1280, 720, 32, 1, 160, 45, - MD_XGI300|MD_XGI315}, - {"1280x720x32", 0x78, 0x0000, 0x0000, 1280, 720, 32, 1, 160, 45, - MD_XGI300|MD_XGI315}, - {"1280x768x8", 0x23, 0x0000, 0x0000, 1280, 768, 8, 1, 160, 48, - MD_XGI315}, /* TW: 310/325 series only */ - {"1280x768x16", 0x24, 0x0000, 0x0000, 1280, 768, 16, 1, 160, 48, - MD_XGI315}, - {"1280x768x24", 0x25, 0x0000, 0x0000, 1280, 768, 32, 1, 160, 48, - MD_XGI315}, - {"1280x768x32", 0x25, 0x0000, 0x0000, 1280, 768, 32, 1, 160, 48, - MD_XGI315}, - {"1280x960x8", 0x7C, 0x0000, 0x0000, 1280, 960, 8, 1, 160, 60, - MD_XGI300|MD_XGI315}, - {"1280x960x16", 0x7D, 0x0000, 0x0000, 1280, 960, 16, 1, 160, 60, - MD_XGI300|MD_XGI315}, - {"1280x960x24", 0x7E, 0x0000, 0x0000, 1280, 960, 32, 1, 160, 60, - MD_XGI300|MD_XGI315}, - {"1280x960x32", 0x7E, 0x0000, 0x0000, 1280, 960, 32, 1, 160, 60, - MD_XGI300|MD_XGI315}, - {"1280x1024x8", 0x3A, 0x0107, 0x0107, 1280, 1024, 8, 1, 160, 64, - MD_XGI300|MD_XGI315}, - {"1280x1024x16", 0x4D, 0x011a, 0x011a, 1280, 1024, 16, 1, 160, 64, - MD_XGI300|MD_XGI315}, - {"1280x1024x24", 0x65, 0x013d, 0x011b, 1280, 1024, 32, 1, 160, 64, - MD_XGI300|MD_XGI315}, - {"1280x1024x32", 0x65, 0x013d, 0x011b, 1280, 1024, 32, 1, 160, 64, - MD_XGI300|MD_XGI315}, - {"1400x1050x8", 0x26, 0x0000, 0x0000, 1400, 1050, 8, 1, 175, 65, - MD_XGI315}, /* TW: 310/325 series only */ - {"1400x1050x16", 0x27, 0x0000, 0x0000, 1400, 1050, 16, 1, 175, 65, - MD_XGI315}, - {"1400x1050x24", 0x28, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65, - MD_XGI315}, - {"1400x1050x32", 0x28, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65, - MD_XGI315}, - {"1600x1200x8", 0x3C, 0x0130, 0x011c, 1600, 1200, 8, 1, 200, 75, - MD_XGI300|MD_XGI315}, - {"1600x1200x16", 0x3D, 0x0131, 0x011e, 1600, 1200, 16, 1, 200, 75, - MD_XGI300|MD_XGI315}, - {"1600x1200x24", 0x66, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75, - MD_XGI300|MD_XGI315}, - {"1600x1200x32", 0x66, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75, - MD_XGI300|MD_XGI315}, - {"1920x1440x8", 0x68, 0x013f, 0x0000, 1920, 1440, 8, 1, 240, 75, - MD_XGI300|MD_XGI315}, - {"1920x1440x16", 0x69, 0x0140, 0x0000, 1920, 1440, 16, 1, 240, 75, - MD_XGI300|MD_XGI315}, - {"1920x1440x24", 0x6B, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, - MD_XGI300|MD_XGI315}, - {"1920x1440x32", 0x6B, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, - MD_XGI300|MD_XGI315}, - {"2048x1536x8", 0x6c, 0x0000, 0x0000, 2048, 1536, 8, 1, 256, 96, - MD_XGI315}, /* TW: 310/325 series only */ - {"2048x1536x16", 0x6d, 0x0000, 0x0000, 2048, 1536, 16, 1, 256, 96, - MD_XGI315}, - {"2048x1536x24", 0x6e, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96, - MD_XGI315}, - {"2048x1536x32", 0x6e, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96, - MD_XGI315}, - {"\0", 0x00, 0, 0, 0, 0, 0, 0, 0} + { 0x56, 0x0000, 0x0000, 320, 240, 16, MD_XGI315 }, + { 0x5A, 0x0000, 0x0000, 320, 480, 8, MD_XGI315 }, + { 0x5B, 0x0000, 0x0000, 320, 480, 16, MD_XGI315 }, + { 0x2E, 0x0101, 0x0101, 640, 480, 8, MD_XGI315 }, + { 0x44, 0x0111, 0x0111, 640, 480, 16, MD_XGI315 }, + { 0x62, 0x013a, 0x0112, 640, 480, 32, MD_XGI315 }, + { 0x31, 0x0000, 0x0000, 720, 480, 8, MD_XGI315 }, + { 0x33, 0x0000, 0x0000, 720, 480, 16, MD_XGI315 }, + { 0x35, 0x0000, 0x0000, 720, 480, 32, MD_XGI315 }, + { 0x32, 0x0000, 0x0000, 720, 576, 8, MD_XGI315 }, + { 0x34, 0x0000, 0x0000, 720, 576, 16, MD_XGI315 }, + { 0x36, 0x0000, 0x0000, 720, 576, 32, MD_XGI315 }, + { 0x36, 0x0000, 0x0000, 720, 576, 32, MD_XGI315 }, + { 0x70, 0x0000, 0x0000, 800, 480, 8, MD_XGI315 }, + { 0x7a, 0x0000, 0x0000, 800, 480, 16, MD_XGI315 }, + { 0x76, 0x0000, 0x0000, 800, 480, 32, MD_XGI315 }, + { 0x30, 0x0103, 0x0103, 800, 600, 8, MD_XGI315 }, +#define DEFAULT_MODE 17 /* index for 800x600x16 */ + { 0x47, 0x0114, 0x0114, 800, 600, 16, MD_XGI315 }, + { 0x63, 0x013b, 0x0115, 800, 600, 32, MD_XGI315 }, + { 0x71, 0x0000, 0x0000, 1024, 576, 8, MD_XGI315 }, + { 0x74, 0x0000, 0x0000, 1024, 576, 16, MD_XGI315 }, + { 0x77, 0x0000, 0x0000, 1024, 576, 32, MD_XGI315 }, + { 0x77, 0x0000, 0x0000, 1024, 576, 32, MD_XGI315 }, + { 0x20, 0x0000, 0x0000, 1024, 600, 8, }, + { 0x21, 0x0000, 0x0000, 1024, 600, 16, }, + { 0x22, 0x0000, 0x0000, 1024, 600, 32, }, + { 0x38, 0x0105, 0x0105, 1024, 768, 8, MD_XGI315 }, + { 0x4A, 0x0117, 0x0117, 1024, 768, 16, MD_XGI315 }, + { 0x64, 0x013c, 0x0118, 1024, 768, 32, MD_XGI315 }, + { 0x64, 0x013c, 0x0118, 1024, 768, 32, MD_XGI315 }, + { 0x23, 0x0000, 0x0000, 1152, 768, 8, }, + { 0x24, 0x0000, 0x0000, 1152, 768, 16, }, + { 0x25, 0x0000, 0x0000, 1152, 768, 32, }, + { 0x79, 0x0000, 0x0000, 1280, 720, 8, MD_XGI315 }, + { 0x75, 0x0000, 0x0000, 1280, 720, 16, MD_XGI315 }, + { 0x78, 0x0000, 0x0000, 1280, 720, 32, MD_XGI315 }, + { 0x23, 0x0000, 0x0000, 1280, 768, 8, MD_XGI315 }, + { 0x24, 0x0000, 0x0000, 1280, 768, 16, MD_XGI315 }, + { 0x25, 0x0000, 0x0000, 1280, 768, 32, MD_XGI315 }, + { 0x7C, 0x0000, 0x0000, 1280, 960, 8, MD_XGI315 }, + { 0x7D, 0x0000, 0x0000, 1280, 960, 16, MD_XGI315 }, + { 0x7E, 0x0000, 0x0000, 1280, 960, 32, MD_XGI315 }, + { 0x3A, 0x0107, 0x0107, 1280, 1024, 8, MD_XGI315 }, + { 0x4D, 0x011a, 0x011a, 1280, 1024, 16, MD_XGI315 }, + { 0x65, 0x013d, 0x011b, 1280, 1024, 32, MD_XGI315 }, + { 0x26, 0x0000, 0x0000, 1400, 1050, 8, MD_XGI315 }, + { 0x27, 0x0000, 0x0000, 1400, 1050, 16, MD_XGI315 }, + { 0x28, 0x0000, 0x0000, 1400, 1050, 32, MD_XGI315 }, + { 0x3C, 0x0130, 0x011c, 1600, 1200, 8, MD_XGI315 }, + { 0x3D, 0x0131, 0x011e, 1600, 1200, 16, MD_XGI315 }, + { 0x66, 0x013e, 0x011f, 1600, 1200, 32, MD_XGI315 }, + { 0x68, 0x013f, 0x0000, 1920, 1440, 8, MD_XGI315 }, + { 0x69, 0x0140, 0x0000, 1920, 1440, 16, MD_XGI315 }, + { 0x6B, 0x0141, 0x0000, 1920, 1440, 32, MD_XGI315 }, + { 0x6c, 0x0000, 0x0000, 2048, 1536, 8, MD_XGI315 }, + { 0x6d, 0x0000, 0x0000, 2048, 1536, 16, MD_XGI315 }, + { 0x6e, 0x0000, 0x0000, 2048, 1536, 32, MD_XGI315 }, + { 0 }, }; -/* TW: CR36 evaluation */ -static const unsigned short XGI300paneltype[] = { - LCD_UNKNOWN, LCD_800x600, LCD_1024x768, LCD_1280x1024, - LCD_1280x960, LCD_640x480, LCD_1024x600, LCD_1152x768, - LCD_1024x768, LCD_1024x768, LCD_1024x768, - LCD_1024x768, LCD_1024x768, LCD_1024x768, LCD_1024x768}; - static const unsigned short XGI310paneltype[] = { LCD_UNKNOWN, LCD_800x600, LCD_1024x768, LCD_1280x1024, LCD_640x480, LCD_1024x600, LCD_1152x864, LCD_1280x960, diff --git a/trunk/drivers/staging/xgifb/XGI_main_26.c b/trunk/drivers/staging/xgifb/XGI_main_26.c index 21c037827de4..85dbf32b1f66 100644 --- a/trunk/drivers/staging/xgifb/XGI_main_26.c +++ b/trunk/drivers/staging/xgifb/XGI_main_26.c @@ -156,25 +156,14 @@ static int XGIfb_mode_rate_to_dclock(struct vb_device_info *XGI_Pr, unsigned short ModeNo = modeno; unsigned short ModeIdIndex = 0, ClockIndex = 0; unsigned short RefreshRateTableIndex = 0; - - /* unsigned long temp = 0; */ int Clock; InitTo330Pointer(HwDeviceExtension->jChipType, XGI_Pr); + XGI_SearchModeID(ModeNo, &ModeIdIndex, XGI_Pr); + RefreshRateTableIndex = XGI_GetRatePtrCRT2(HwDeviceExtension, ModeNo, ModeIdIndex, XGI_Pr); - /* - temp = XGI_SearchModeID(ModeNo , &ModeIdIndex, XGI_Pr) ; - if (!temp) { - printk(KERN_ERR "Could not find mode %x\n", ModeNo); - return 65000; - } - - RefreshRateTableIndex = XGI_Pr->EModeIDTable[ModeIdIndex].REFindex; - RefreshRateTableIndex += (rateindex - 1); - - */ ClockIndex = XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; Clock = XGI_Pr->VCLKData[ClockIndex].CLOCK * 1000; @@ -190,7 +179,7 @@ static int XGIfb_mode_rate_to_ddata(struct vb_device_info *XGI_Pr, u32 *vmode) { unsigned short ModeNo = modeno; - unsigned short ModeIdIndex = 0, index = 0; + unsigned short ModeIdIndex, index = 0; unsigned short RefreshRateTableIndex = 0; unsigned short VRE, VBE, VRS, VBS, VDE, VT; @@ -199,16 +188,10 @@ static int XGIfb_mode_rate_to_ddata(struct vb_device_info *XGI_Pr, unsigned long cr_data3; int A, B, C, D, E, F, temp, j; InitTo330Pointer(HwDeviceExtension->jChipType, XGI_Pr); + if (!XGI_SearchModeID(ModeNo, &ModeIdIndex, XGI_Pr)) + return 0; RefreshRateTableIndex = XGI_GetRatePtrCRT2(HwDeviceExtension, ModeNo, ModeIdIndex, XGI_Pr); - /* - temp = XGI_SearchModeID(ModeNo, &ModeIdIndex, XGI_Pr); - if (!temp) - return 0; - - RefreshRateTableIndex = XGI_Pr->EModeIDTable[ModeIdIndex].REFindex; - RefreshRateTableIndex += (rateindex - 1); - */ index = XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; sr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[5]; @@ -219,12 +202,6 @@ static int XGIfb_mode_rate_to_ddata(struct vb_device_info *XGI_Pr, HT = (cr_data & 0xff) | ((unsigned short) (sr_data & 0x03) << 8); A = HT + 5; - /* - cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[1]; - - Horizontal display enable end - HDE = (cr_data & 0xff) | ((unsigned short) (sr_data & 0x0C) << 6); - */ HDE = (XGI_Pr->RefIndex[RefreshRateTableIndex].XRes >> 3) - 1; E = HDE + 1; @@ -358,7 +335,6 @@ static int XGIfb_mode_rate_to_ddata(struct vb_device_info *XGI_Pr, static void XGIRegInit(struct vb_device_info *XGI_Pr, unsigned long BaseAddr) { - XGI_Pr->RelIO = BaseAddr; XGI_Pr->P3c4 = BaseAddr + 0x14; XGI_Pr->P3d4 = BaseAddr + 0x24; XGI_Pr->P3c0 = BaseAddr + 0x10; @@ -414,19 +390,26 @@ static int XGIfb_GetXG21DefaultLVDSModeIdx(struct xgifb_video_info *xgifb_info) static void XGIfb_search_mode(struct xgifb_video_info *xgifb_info, const char *name) { - int i = 0, j = 0, l; + unsigned int xres; + unsigned int yres; + unsigned int bpp; + int i; - while (XGIbios_mode[i].mode_no != 0) { - l = min(strlen(name), strlen(XGIbios_mode[i].name)); - if (!strncmp(name, XGIbios_mode[i].name, l)) { + if (sscanf(name, "%ux%ux%u", &xres, &yres, &bpp) != 3) + goto invalid_mode; + + if (bpp == 24) + bpp = 32; /* That's for people who mix up color and fb depth. */ + + for (i = 0; XGIbios_mode[i].mode_no != 0; i++) + if (XGIbios_mode[i].xres == xres && + XGIbios_mode[i].yres == yres && + XGIbios_mode[i].bpp == bpp) { xgifb_info->mode_idx = i; - j = 1; - break; + return; } - i++; - } - if (!j) - pr_info("Invalid mode '%s'\n", name); +invalid_mode: + pr_info("Invalid mode '%s'\n", name); } static void XGIfb_search_vesamode(struct xgifb_video_info *xgifb_info, @@ -1088,7 +1071,7 @@ static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive, unsigned int vtotal = var->upper_margin + var->yres + var->lower_margin + var->vsync_len; #if defined(__powerpc__) - u8 sr_data, cr_data; + u8 cr_data; #endif unsigned int drate = 0, hrate = 0; int found_mode = 0; @@ -1162,8 +1145,7 @@ static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive, if (XGIfb_search_refresh_rate(xgifb_info, xgifb_info->refresh_rate) == 0) { - xgifb_info->rate_idx = - XGIbios_mode[xgifb_info->mode_idx].rate_idx; + xgifb_info->rate_idx = 1; xgifb_info->refresh_rate = 60; } @@ -1680,17 +1662,6 @@ static int XGIfb_get_dram_size(struct xgifb_video_info *xgifb_info) ChannelNum = 1; break; - case XG45: - if (tmp == 1) - ChannelNum = 2; - else if (tmp == 2) - ChannelNum = 3; - else if (tmp == 3) - ChannelNum = 4; - else - ChannelNum = 1; - break; - case XG40: default: if (tmp == 2) @@ -1911,11 +1882,9 @@ static int __devinit xgifb_probe(struct pci_dev *pdev, xgifb_info->mmio_base = pci_resource_start(pdev, 1); xgifb_info->mmio_size = pci_resource_len(pdev, 1); xgifb_info->vga_base = pci_resource_start(pdev, 2) + 0x30; - hw_info->pjIOAddress = (unsigned char *)xgifb_info->vga_base; - /* XGI_Pr.RelIO = ioremap(pci_resource_start(pdev, 2), 128) + 0x30; */ - pr_info("Relocate IO address: %lx [%08lx]\n", - (unsigned long)pci_resource_start(pdev, 2), - xgifb_info->dev_info.RelIO); + pr_info("Relocate IO address: %Lx [%08lx]\n", + (u64) pci_resource_start(pdev, 2), + xgifb_info->vga_base); if (pci_enable_device(pdev)) { ret = -EIO; @@ -1927,7 +1896,7 @@ static int __devinit xgifb_probe(struct pci_dev *pdev, xgifb_info->display2_force = true; } - XGIRegInit(&xgifb_info->dev_info, (unsigned long)hw_info->pjIOAddress); + XGIRegInit(&xgifb_info->dev_info, xgifb_info->vga_base); xgifb_reg_set(XGISR, IND_SIS_PASSWORD, SIS_PASSWORD); reg1 = xgifb_reg_get(XGISR, IND_SIS_PASSWORD); @@ -1950,9 +1919,6 @@ static int __devinit xgifb_probe(struct pci_dev *pdev, case PCI_DEVICE_ID_XGI_40: xgifb_info->chip = XG40; break; - case PCI_DEVICE_ID_XGI_41: - xgifb_info->chip = XG41; - break; case PCI_DEVICE_ID_XGI_42: xgifb_info->chip = XG42; break; @@ -2006,13 +1972,13 @@ static int __devinit xgifb_probe(struct pci_dev *pdev, xgifb_info->mmio_vbase = ioremap(xgifb_info->mmio_base, xgifb_info->mmio_size); - pr_info("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", - xgifb_info->video_base, + pr_info("Framebuffer at 0x%Lx, mapped to 0x%p, size %dk\n", + (u64) xgifb_info->video_base, xgifb_info->video_vbase, xgifb_info->video_size / 1024); - pr_info("MMIO at 0x%lx, mapped to 0x%p, size %ldk\n", - xgifb_info->mmio_base, xgifb_info->mmio_vbase, + pr_info("MMIO at 0x%Lx, mapped to 0x%p, size %ldk\n", + (u64) xgifb_info->mmio_base, xgifb_info->mmio_vbase, xgifb_info->mmio_size / 1024); pci_set_drvdata(pdev, xgifb_info); @@ -2174,8 +2140,7 @@ static int __devinit xgifb_probe(struct pci_dev *pdev, xgifb_info->refresh_rate = 60; if (XGIfb_search_refresh_rate(xgifb_info, xgifb_info->refresh_rate) == 0) { - xgifb_info->rate_idx = - XGIbios_mode[xgifb_info->mode_idx].rate_idx; + xgifb_info->rate_idx = 1; xgifb_info->refresh_rate = 60; } diff --git a/trunk/drivers/staging/xgifb/XGIfb.h b/trunk/drivers/staging/xgifb/XGIfb.h index 37bb730de047..9068c5ad76ec 100644 --- a/trunk/drivers/staging/xgifb/XGIfb.h +++ b/trunk/drivers/staging/xgifb/XGIfb.h @@ -23,9 +23,7 @@ enum xgifb_display_type { enum XGI_CHIP_TYPE { XG40 = 32, - XG41, XG42, - XG45, XG20 = 48, XG21, XG27, @@ -66,9 +64,9 @@ struct xgifb_video_info { int chip_id; unsigned int video_size; - unsigned long video_base; + phys_addr_t video_base; void __iomem *video_vbase; - unsigned long mmio_base; + phys_addr_t mmio_base; unsigned long mmio_size; void __iomem *mmio_vbase; unsigned long vga_base; diff --git a/trunk/drivers/staging/xgifb/vb_init.c b/trunk/drivers/staging/xgifb/vb_init.c index 3650bbff7686..c222d611431d 100644 --- a/trunk/drivers/staging/xgifb/vb_init.c +++ b/trunk/drivers/staging/xgifb/vb_init.c @@ -353,7 +353,6 @@ static void XGINew_DDR1x_DefaultRegister( XGINew_SetMemoryClock(HwDeviceExtension, pVBInfo); switch (HwDeviceExtension->jChipType) { - case XG41: case XG42: /* CR82 */ xgifb_reg_set(P3d4, @@ -556,8 +555,7 @@ static void XGINew_SetDRAMDefaultRegister340( xgifb_reg_set(P3d4, (0x8A + j), pVBInfo->CR40[1 + j][pVBInfo->ram_type]); - if ((HwDeviceExtension->jChipType == XG41) || - (HwDeviceExtension->jChipType == XG42)) + if (HwDeviceExtension->jChipType == XG42) xgifb_reg_set(P3d4, 0x8C, 0x87); xgifb_reg_set(P3d4, @@ -854,78 +852,6 @@ static void XGINew_CheckChannel(struct xgi_hw_device_info *HwDeviceExtension, pVBInfo->ram_channel = 1; /* Single channel */ xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x51); /* 32Mx16 bit*/ break; - case XG41: - if (XGINew_CheckFrequence(pVBInfo) == 1) { - pVBInfo->ram_bus = 32; /* 32 bits */ - pVBInfo->ram_channel = 3; /* Quad Channel */ - xgifb_reg_set(pVBInfo->P3c4, 0x13, 0xA1); - xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x4C); - - if (XGINew_ReadWriteRest(25, 23, pVBInfo) == 1) - return; - - pVBInfo->ram_channel = 2; /* Dual channels */ - xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x48); - - if (XGINew_ReadWriteRest(24, 23, pVBInfo) == 1) - return; - - xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x49); - - if (XGINew_ReadWriteRest(24, 23, pVBInfo) == 1) - return; - - pVBInfo->ram_channel = 3; - xgifb_reg_set(pVBInfo->P3c4, 0x13, 0x21); - xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x3C); - - if (XGINew_ReadWriteRest(24, 23, pVBInfo) == 1) - return; - - xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x38); - - if (XGINew_ReadWriteRest(8, 4, pVBInfo) == 1) - return; - else - xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x39); - } else { /* DDR */ - pVBInfo->ram_bus = 64; /* 64 bits */ - pVBInfo->ram_channel = 2; /* Dual channels */ - xgifb_reg_set(pVBInfo->P3c4, 0x13, 0xA1); - xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x5A); - - if (XGINew_ReadWriteRest(25, 24, pVBInfo) == 1) - return; - - pVBInfo->ram_channel = 1; /* Single channels */ - xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x52); - - if (XGINew_ReadWriteRest(24, 23, pVBInfo) == 1) - return; - - xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x53); - - if (XGINew_ReadWriteRest(24, 23, pVBInfo) == 1) - return; - - pVBInfo->ram_channel = 2; /* Dual channels */ - xgifb_reg_set(pVBInfo->P3c4, 0x13, 0x21); - xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x4A); - - if (XGINew_ReadWriteRest(24, 23, pVBInfo) == 1) - return; - - pVBInfo->ram_channel = 1; /* Single channels */ - xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x42); - - if (XGINew_ReadWriteRest(8, 4, pVBInfo) == 1) - return; - else - xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x43); - } - - break; - case XG42: /* XG42 SR14 D[3] Reserve @@ -1478,7 +1404,7 @@ unsigned char XGIInitNew(struct pci_dev *pdev) pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress; - pVBInfo->BaseAddr = (unsigned long) HwDeviceExtension->pjIOAddress; + pVBInfo->BaseAddr = xgifb_info->vga_base; /* Newdebugcode(0x99); */ diff --git a/trunk/drivers/staging/xgifb/vb_setmode.c b/trunk/drivers/staging/xgifb/vb_setmode.c index 60d4adf99923..b2f4338b1109 100644 --- a/trunk/drivers/staging/xgifb/vb_setmode.c +++ b/trunk/drivers/staging/xgifb/vb_setmode.c @@ -16,36 +16,6 @@ #define IndexMask 0xff -static const unsigned short XGINew_MDA_DAC[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F}; - -static const unsigned short XGINew_CGA_DAC[] = { - 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, - 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, - 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, - 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, - 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, - 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, - 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, - 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F}; - -static const unsigned short XGINew_EGA_DAC[] = { - 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15, - 0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35, - 0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D, - 0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D, - 0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17, - 0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37, - 0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F, - 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F}; - static const unsigned short XGINew_VGA_DAC[] = { 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, @@ -60,8 +30,7 @@ static const unsigned short XGINew_VGA_DAC[] = { void InitTo330Pointer(unsigned char ChipType, struct vb_device_info *pVBInfo) { - pVBInfo->SModeIDTable = (struct XGI_StStruct *) XGI330_SModeIDTable; - pVBInfo->StandTable = (struct SiS_StandTable_S *) XGI330_StandTable; + pVBInfo->StandTable = (struct SiS_StandTable_S *) &XGI330_StandTable; pVBInfo->EModeIDTable = (struct XGI_ExtStruct *) XGI330_EModeIDTable; pVBInfo->RefIndex = (struct XGI_Ext2Struct *) XGI330_RefIndex; pVBInfo->XGINEWUB_CRT1Table @@ -182,38 +151,17 @@ void InitTo330Pointer(unsigned char ChipType, struct vb_device_info *pVBInfo) } -static unsigned char XGI_GetModePtr(unsigned short ModeNo, - unsigned short ModeIdIndex, - struct vb_device_info *pVBInfo) -{ - unsigned char index; - - if (ModeNo <= 0x13) - index = pVBInfo->SModeIDTable[ModeIdIndex].St_StTableIndex; - else { - if (pVBInfo->ModeType <= 0x02) - index = 0x1B; /* 02 -> ModeEGA */ - else - index = 0x0F; - } - return index; /* Get pVBInfo->StandTable index */ -} - static void XGI_SetSeqRegs(unsigned short ModeNo, - unsigned short StandTableIndex, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo) { unsigned char tempah, SRdata; unsigned short i, modeflag; - if (ModeNo <= 0x13) - modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; - else - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; xgifb_reg_set(pVBInfo->P3c4, 0x00, 0x03); /* Set SR0 */ - tempah = pVBInfo->StandTable[StandTableIndex].SR[0]; + tempah = pVBInfo->StandTable->SR[0]; i = XGI_SetCRT2ToLCDA; if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) { @@ -230,13 +178,12 @@ static void XGI_SetSeqRegs(unsigned short ModeNo, for (i = 02; i <= 04; i++) { /* Get SR2,3,4 from file */ - SRdata = pVBInfo->StandTable[StandTableIndex].SR[i - 1]; + SRdata = pVBInfo->StandTable->SR[i - 1]; xgifb_reg_set(pVBInfo->P3c4, i, SRdata); /* Set SR2 3 4 */ } } static void XGI_SetCRTCRegs(struct xgi_hw_device_info *HwDeviceExtension, - unsigned short StandTableIndex, struct vb_device_info *pVBInfo) { unsigned char CRTCdata; @@ -248,26 +195,22 @@ static void XGI_SetCRTCRegs(struct xgi_hw_device_info *HwDeviceExtension, for (i = 0; i <= 0x18; i++) { /* Get CRTC from file */ - CRTCdata = pVBInfo->StandTable[StandTableIndex].CRTC[i]; + CRTCdata = pVBInfo->StandTable->CRTC[i]; xgifb_reg_set(pVBInfo->P3d4, i, CRTCdata); /* Set CRTC(3d4) */ } } static void XGI_SetATTRegs(unsigned short ModeNo, - unsigned short StandTableIndex, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo) { unsigned char ARdata; unsigned short i, modeflag; - if (ModeNo <= 0x13) - modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; - else - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; for (i = 0; i <= 0x13; i++) { - ARdata = pVBInfo->StandTable[StandTableIndex].ATTR[i]; + ARdata = pVBInfo->StandTable->ATTR[i]; if (modeflag & Charx8Dot) { /* ifndef Dot9 */ if (i == 0x13) { if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) { @@ -295,15 +238,14 @@ static void XGI_SetATTRegs(unsigned short ModeNo, outb(0x20, pVBInfo->P3c0); } -static void XGI_SetGRCRegs(unsigned short StandTableIndex, - struct vb_device_info *pVBInfo) +static void XGI_SetGRCRegs(struct vb_device_info *pVBInfo) { unsigned char GRdata; unsigned short i; for (i = 0; i <= 0x08; i++) { /* Get GR from file */ - GRdata = pVBInfo->StandTable[StandTableIndex].GRC[i]; + GRdata = pVBInfo->StandTable->GRC[i]; xgifb_reg_set(pVBInfo->P3ce, i, GRdata); /* Set GR(3ce) */ } @@ -344,12 +286,7 @@ static unsigned char XGI_AjustCRT2Rate(unsigned short ModeNo, { unsigned short tempax, tempbx, resinfo, modeflag, infoflag; - if (ModeNo <= 0x13) - /* si+St_ModeFlag */ - modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; - else - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; - + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; tempbx = pVBInfo->RefIndex[RefreshRateTableIndex + (*i)].ModeID; tempax = 0; @@ -584,11 +521,7 @@ static void XGI_SetCRT1Timing_V(unsigned short ModeIdIndex, data &= 0x80; data = data >> 2; - if (ModeNo <= 0x13) - i = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; - else - i = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; - + i = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; i &= DoubleScanMode; if (i) data |= 0x80; @@ -641,158 +574,97 @@ static void XGI_SetXG21CRTC(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo) { - unsigned char StandTableIndex, index, Tempax, Tempbx, Tempcx, Tempdx; + unsigned char index, Tempax, Tempbx, Tempcx, Tempdx; unsigned short Temp1, Temp2, Temp3; - if (ModeNo <= 0x13) { - StandTableIndex = XGI_GetModePtr(ModeNo, ModeIdIndex, pVBInfo); - /* CR04 HRS */ - Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[4]; - /* SR2E [7:0]->HRS */ - xgifb_reg_set(pVBInfo->P3c4, 0x2E, Tempax); - /* Tempbx: CR05 HRE */ - Tempbx = pVBInfo->StandTable[StandTableIndex].CRTC[5]; - Tempbx &= 0x1F; /* Tempbx: HRE[4:0] */ - Tempcx = Tempax; - Tempcx &= 0xE0; /* Tempcx: HRS[7:5] */ - Tempdx = Tempcx | Tempbx; /* Tempdx(HRE): HRS[7:5]HRE[4:0] */ - if (Tempbx < (Tempax & 0x1F)) /* IF HRE < HRS */ - Tempdx |= 0x20; /* Tempdx: HRE = HRE + 0x20 */ - Tempdx <<= 2; /* Tempdx << 2 */ - /* SR2F [7:2]->HRE */ - xgifb_reg_set(pVBInfo->P3c4, 0x2F, Tempdx); - xgifb_reg_and_or(pVBInfo->P3c4, 0x30, 0xE3, 00); - - /* Tempax: CR16 VRS */ - Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[16]; - Tempbx = Tempax; /* Tempbx=Tempax */ - Tempax &= 0x01; /* Tempax: VRS[0] */ - xgifb_reg_or(pVBInfo->P3c4, 0x33, Tempax); /* SR33[0]->VRS */ - - /* Tempax: CR7 VRS */ - Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[7]; - Tempdx = Tempbx >> 1; /* Tempdx: VRS[7:1] */ - Tempcx = Tempax & 0x04; /* Tempcx: CR7[2] */ - Tempcx <<= 5; /* Tempcx[7]: VRS[8] */ - Tempdx |= Tempcx; /* Tempdx: VRS[8:1] */ - /* SR34[7:0]: VRS[8:1] */ - xgifb_reg_set(pVBInfo->P3c4, 0x34, Tempdx); - - /* Temp1[8]: VRS[8] unsigned char -> unsigned short */ - Temp1 = Tempcx << 1; - Temp1 |= Tempbx; /* Temp1[8:0]: VRS[8:0] */ - Tempax &= 0x80; /* Tempax[7]: CR7[7] */ - Temp2 = Tempax << 2; /* Temp2[9]: VRS[9] */ - Temp1 |= Temp2; /* Temp1[9:0]: VRS[9:0] */ - - /* CR16 VRE */ - Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[17]; - Tempax &= 0x0F; /* Tempax[3:0]: VRE[3:0] */ - Temp2 = Temp1 & 0x3F0; /* Temp2[9:4]: VRS[9:4] */ - Temp2 |= Tempax; /* Temp2[9:0]: VRE[9:0] */ - Temp3 = Temp1 & 0x0F; /* Temp3[3:0]: VRS[3:0] */ - if (Tempax < Temp3) /* VRE[3:0]>= 9; /* [10:9]->[1:0] */ - Tempbx = (unsigned char) Temp1; /* Tempbx[1:0]: VRS[10:9] */ - Tempax |= Tempbx; /* VRE[5:0]VRS[10:9] */ - Tempax &= 0x7F; - /* SR3F D[7:2]->VRE D[1:0]->VRS */ - xgifb_reg_set(pVBInfo->P3c4, 0x3F, Tempax); - } else { - index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; - /* Tempax: CR4 HRS */ - Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[3]; - Tempcx = Tempax; /* Tempcx: HRS */ - /* SR2E[7:0]->HRS */ - xgifb_reg_set(pVBInfo->P3c4, 0x2E, Tempax); - - Tempdx = pVBInfo->XGINEWUB_CRT1Table[index].CR[5]; /* SRB */ - Tempdx &= 0xC0; /* Tempdx[7:6]: SRB[7:6] */ - Temp1 = Tempdx; /* Temp1[7:6]: HRS[9:8] */ - Temp1 <<= 2; /* Temp1[9:8]: HRS[9:8] */ - Temp1 |= Tempax; /* Temp1[9:0]: HRS[9:0] */ - - Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[4]; /* CR5 HRE */ - Tempax &= 0x1F; /* Tempax[4:0]: HRE[4:0] */ - - Tempbx = pVBInfo->XGINEWUB_CRT1Table[index].CR[6]; /* SRC */ - Tempbx &= 0x04; /* Tempbx[2]: HRE[5] */ - Tempbx <<= 3; /* Tempbx[5]: HRE[5] */ - Tempax |= Tempbx; /* Tempax[5:0]: HRE[5:0] */ - - Temp2 = Temp1 & 0x3C0; /* Temp2[9:6]: HRS[9:6] */ - Temp2 |= Tempax; /* Temp2[9:0]: HRE[9:0] */ - - Tempcx &= 0x3F; /* Tempcx[5:0]: HRS[5:0] */ - if (Tempax < Tempcx) /* HRE < HRS */ - Temp2 |= 0x40; /* Temp2 + 0x40 */ - - Temp2 &= 0xFF; - Tempax = (unsigned char) Temp2; /* Tempax: HRE[7:0] */ - Tempax <<= 2; /* Tempax[7:2]: HRE[5:0] */ - Tempdx >>= 6; /* Tempdx[7:6]->[1:0] HRS[9:8] */ - Tempax |= Tempdx; /* HRE[5:0]HRS[9:8] */ - /* SR2F D[7:2]->HRE, D[1:0]->HRS */ - xgifb_reg_set(pVBInfo->P3c4, 0x2F, Tempax); - xgifb_reg_and_or(pVBInfo->P3c4, 0x30, 0xE3, 00); - - /* CR10 VRS */ - Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[10]; - Tempbx = Tempax; /* Tempbx: VRS */ - Tempax &= 0x01; /* Tempax[0]: VRS[0] */ - xgifb_reg_or(pVBInfo->P3c4, 0x33, Tempax); /* SR33[0]->VRS[0] */ - /* CR7[2][7] VRE */ - Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[9]; - Tempcx = Tempbx >> 1; /* Tempcx[6:0]: VRS[7:1] */ - Tempdx = Tempax & 0x04; /* Tempdx[2]: CR7[2] */ - Tempdx <<= 5; /* Tempdx[7]: VRS[8] */ - Tempcx |= Tempdx; /* Tempcx[7:0]: VRS[8:1] */ - xgifb_reg_set(pVBInfo->P3c4, 0x34, Tempcx); /* SR34[8:1]->VRS */ - - Temp1 = Tempdx; /* Temp1[7]: Tempdx[7] */ - Temp1 <<= 1; /* Temp1[8]: VRS[8] */ - Temp1 |= Tempbx; /* Temp1[8:0]: VRS[8:0] */ - Tempax &= 0x80; - Temp2 = Tempax << 2; /* Temp2[9]: VRS[9] */ - Temp1 |= Temp2; /* Temp1[9:0]: VRS[9:0] */ - /* Tempax: SRA */ - Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[14]; - Tempax &= 0x08; /* Tempax[3]: VRS[3] */ - Temp2 = Tempax; - Temp2 <<= 7; /* Temp2[10]: VRS[10] */ - Temp1 |= Temp2; /* Temp1[10:0]: VRS[10:0] */ - - /* Tempax: CR11 VRE */ - Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[11]; - Tempax &= 0x0F; /* Tempax[3:0]: VRE[3:0] */ - /* Tempbx: SRA */ - Tempbx = pVBInfo->XGINEWUB_CRT1Table[index].CR[14]; - Tempbx &= 0x20; /* Tempbx[5]: VRE[5] */ - Tempbx >>= 1; /* Tempbx[4]: VRE[4] */ - Tempax |= Tempbx; /* Tempax[4:0]: VRE[4:0] */ - Temp2 = Temp1 & 0x7E0; /* Temp2[10:5]: VRS[10:5] */ - Temp2 |= Tempax; /* Temp2[10:5]: VRE[10:5] */ - - Temp3 = Temp1 & 0x1F; /* Temp3[4:0]: VRS[4:0] */ - if (Tempax < Temp3) /* VRE < VRS */ - Temp2 |= 0x20; /* VRE + 0x20 */ - - Temp2 &= 0xFF; - Tempax = (unsigned char) Temp2; /* Tempax: VRE[7:0] */ - Tempax <<= 2; /* Tempax[7:0]; VRE[5:0]00 */ - Temp1 &= 0x600; /* Temp1[10:9]: VRS[10:9] */ - Temp1 >>= 9; /* Temp1[1:0]: VRS[10:9] */ - Tempbx = (unsigned char) Temp1; - Tempax |= Tempbx; /* Tempax[7:0]: VRE[5:0]VRS[10:9] */ - Tempax &= 0x7F; - /* SR3F D[7:2]->VRE D[1:0]->VRS */ - xgifb_reg_set(pVBInfo->P3c4, 0x3F, Tempax); - } + index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; + /* Tempax: CR4 HRS */ + Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[3]; + Tempcx = Tempax; /* Tempcx: HRS */ + /* SR2E[7:0]->HRS */ + xgifb_reg_set(pVBInfo->P3c4, 0x2E, Tempax); + + Tempdx = pVBInfo->XGINEWUB_CRT1Table[index].CR[5]; /* SRB */ + Tempdx &= 0xC0; /* Tempdx[7:6]: SRB[7:6] */ + Temp1 = Tempdx; /* Temp1[7:6]: HRS[9:8] */ + Temp1 <<= 2; /* Temp1[9:8]: HRS[9:8] */ + Temp1 |= Tempax; /* Temp1[9:0]: HRS[9:0] */ + + Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[4]; /* CR5 HRE */ + Tempax &= 0x1F; /* Tempax[4:0]: HRE[4:0] */ + + Tempbx = pVBInfo->XGINEWUB_CRT1Table[index].CR[6]; /* SRC */ + Tempbx &= 0x04; /* Tempbx[2]: HRE[5] */ + Tempbx <<= 3; /* Tempbx[5]: HRE[5] */ + Tempax |= Tempbx; /* Tempax[5:0]: HRE[5:0] */ + + Temp2 = Temp1 & 0x3C0; /* Temp2[9:6]: HRS[9:6] */ + Temp2 |= Tempax; /* Temp2[9:0]: HRE[9:0] */ + + Tempcx &= 0x3F; /* Tempcx[5:0]: HRS[5:0] */ + if (Tempax < Tempcx) /* HRE < HRS */ + Temp2 |= 0x40; /* Temp2 + 0x40 */ + + Temp2 &= 0xFF; + Tempax = (unsigned char) Temp2; /* Tempax: HRE[7:0] */ + Tempax <<= 2; /* Tempax[7:2]: HRE[5:0] */ + Tempdx >>= 6; /* Tempdx[7:6]->[1:0] HRS[9:8] */ + Tempax |= Tempdx; /* HRE[5:0]HRS[9:8] */ + /* SR2F D[7:2]->HRE, D[1:0]->HRS */ + xgifb_reg_set(pVBInfo->P3c4, 0x2F, Tempax); + xgifb_reg_and_or(pVBInfo->P3c4, 0x30, 0xE3, 00); + + /* CR10 VRS */ + Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[10]; + Tempbx = Tempax; /* Tempbx: VRS */ + Tempax &= 0x01; /* Tempax[0]: VRS[0] */ + xgifb_reg_or(pVBInfo->P3c4, 0x33, Tempax); /* SR33[0]->VRS[0] */ + /* CR7[2][7] VRE */ + Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[9]; + Tempcx = Tempbx >> 1; /* Tempcx[6:0]: VRS[7:1] */ + Tempdx = Tempax & 0x04; /* Tempdx[2]: CR7[2] */ + Tempdx <<= 5; /* Tempdx[7]: VRS[8] */ + Tempcx |= Tempdx; /* Tempcx[7:0]: VRS[8:1] */ + xgifb_reg_set(pVBInfo->P3c4, 0x34, Tempcx); /* SR34[8:1]->VRS */ + + Temp1 = Tempdx; /* Temp1[7]: Tempdx[7] */ + Temp1 <<= 1; /* Temp1[8]: VRS[8] */ + Temp1 |= Tempbx; /* Temp1[8:0]: VRS[8:0] */ + Tempax &= 0x80; + Temp2 = Tempax << 2; /* Temp2[9]: VRS[9] */ + Temp1 |= Temp2; /* Temp1[9:0]: VRS[9:0] */ + /* Tempax: SRA */ + Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[14]; + Tempax &= 0x08; /* Tempax[3]: VRS[3] */ + Temp2 = Tempax; + Temp2 <<= 7; /* Temp2[10]: VRS[10] */ + Temp1 |= Temp2; /* Temp1[10:0]: VRS[10:0] */ + + /* Tempax: CR11 VRE */ + Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[11]; + Tempax &= 0x0F; /* Tempax[3:0]: VRE[3:0] */ + /* Tempbx: SRA */ + Tempbx = pVBInfo->XGINEWUB_CRT1Table[index].CR[14]; + Tempbx &= 0x20; /* Tempbx[5]: VRE[5] */ + Tempbx >>= 1; /* Tempbx[4]: VRE[4] */ + Tempax |= Tempbx; /* Tempax[4:0]: VRE[4:0] */ + Temp2 = Temp1 & 0x7E0; /* Temp2[10:5]: VRS[10:5] */ + Temp2 |= Tempax; /* Temp2[10:5]: VRE[10:5] */ + + Temp3 = Temp1 & 0x1F; /* Temp3[4:0]: VRS[4:0] */ + if (Tempax < Temp3) /* VRE < VRS */ + Temp2 |= 0x20; /* VRE + 0x20 */ + + Temp2 &= 0xFF; + Tempax = (unsigned char) Temp2; /* Tempax: VRE[7:0] */ + Tempax <<= 2; /* Tempax[7:0]; VRE[5:0]00 */ + Temp1 &= 0x600; /* Temp1[10:9]: VRS[10:9] */ + Temp1 >>= 9; /* Temp1[1:0]: VRS[10:9] */ + Tempbx = (unsigned char) Temp1; + Tempax |= Tempbx; /* Tempax[7:0]: VRE[5:0]VRS[10:9] */ + Tempax &= 0x7F; + /* SR3F D[7:2]->VRE D[1:0]->VRS */ + xgifb_reg_set(pVBInfo->P3c4, 0x3F, Tempax); } static void XGI_SetXG27CRTC(unsigned short ModeNo, @@ -800,139 +672,88 @@ static void XGI_SetXG27CRTC(unsigned short ModeNo, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo) { - unsigned short StandTableIndex, index, Tempax, Tempbx, Tempcx, Tempdx; - - if (ModeNo <= 0x13) { - StandTableIndex = XGI_GetModePtr(ModeNo, ModeIdIndex, pVBInfo); - /* CR04 HRS */ - Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[4]; - /* SR2E [7:0]->HRS */ - xgifb_reg_set(pVBInfo->P3c4, 0x2E, Tempax); - /* Tempbx: CR05 HRE */ - Tempbx = pVBInfo->StandTable[StandTableIndex].CRTC[5]; - Tempbx &= 0x1F; /* Tempbx: HRE[4:0] */ - Tempcx = Tempax; - Tempcx &= 0xE0; /* Tempcx: HRS[7:5] */ - Tempdx = Tempcx | Tempbx; /* Tempdx(HRE): HRS[7:5]HRE[4:0] */ - if (Tempbx < (Tempax & 0x1F)) /* IF HRE < HRS */ - Tempdx |= 0x20; /* Tempdx: HRE = HRE + 0x20 */ - Tempdx <<= 2; /* Tempdx << 2 */ - /* SR2F [7:2]->HRE */ - xgifb_reg_set(pVBInfo->P3c4, 0x2F, Tempdx); - xgifb_reg_and_or(pVBInfo->P3c4, 0x30, 0xE3, 00); - - /* Tempax: CR10 VRS */ - Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[16]; - xgifb_reg_set(pVBInfo->P3c4, 0x34, Tempax); /* SR34[7:0]->VRS */ - Tempcx = Tempax; /* Tempcx=Tempax=VRS[7:0] */ - /* Tempax[7][2]: CR7[7][2] VRS[9][8] */ - Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[7]; - Tempbx = Tempax; /* Tempbx=CR07 */ - Tempax &= 0x04; /* Tempax[2]: CR07[2] VRS[8] */ - Tempax >>= 2; - /* SR35 D[0]->VRS D[8] */ - xgifb_reg_and_or(pVBInfo->P3c4, 0x35, ~0x01, Tempax); - Tempcx |= (Tempax << 8); /* Tempcx[8] |= VRS[8] */ - Tempcx |= (Tempbx & 0x80) << 2; /* Tempcx[9] |= VRS[9] */ - - /* CR11 VRE */ - Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[17]; - Tempax &= 0x0F; /* Tempax: VRE[3:0] */ - Tempbx = Tempcx; /* Tempbx=Tempcx=VRS[9:0] */ - Tempbx &= 0x3F0; /* Tempbx[9:4]: VRS[9:4] */ - Tempbx |= Tempax; /* Tempbx[9:0]: VRE[9:0] */ - if (Tempax <= (Tempcx & 0x0F)) /* VRE[3:0]<=VRS[3:0] */ - Tempbx |= 0x10; /* Tempbx: VRE + 0x10 */ - /* Tempax[7:0]: VRE[7:0] */ - Tempax = (unsigned char) Tempbx & 0xFF; - Tempax <<= 2; /* Tempax << 2: VRE[5:0] */ - Tempcx = (Tempcx & 0x600) >> 8; /* Tempcx VRS[10:9] */ - /* SR3F D[7:2]->VRE D[5:0] */ - xgifb_reg_and_or(pVBInfo->P3c4, 0x3F, ~0xFC, Tempax); - /* SR35 D[2:1]->VRS[10:9] */ - xgifb_reg_and_or(pVBInfo->P3c4, 0x35, ~0x06, Tempcx); - } else { - index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; - /* Tempax: CR4 HRS */ - Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[3]; - Tempbx = Tempax; /* Tempbx: HRS[7:0] */ - /* SR2E[7:0]->HRS */ - xgifb_reg_set(pVBInfo->P3c4, 0x2E, Tempax); - - /* SR0B */ - Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[5]; - Tempax &= 0xC0; /* Tempax[7:6]: SR0B[7:6]: HRS[9:8]*/ - Tempbx |= (Tempax << 2); /* Tempbx: HRS[9:0] */ - - Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[4]; /* CR5 HRE */ - Tempax &= 0x1F; /* Tempax[4:0]: HRE[4:0] */ - Tempcx = Tempax; /* Tempcx: HRE[4:0] */ - - Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[6]; /* SRC */ - Tempax &= 0x04; /* Tempax[2]: HRE[5] */ - Tempax <<= 3; /* Tempax[5]: HRE[5] */ - Tempcx |= Tempax; /* Tempcx[5:0]: HRE[5:0] */ - - Tempbx = Tempbx & 0x3C0; /* Tempbx[9:6]: HRS[9:6] */ - Tempbx |= Tempcx; /* Tempbx: HRS[9:6]HRE[5:0] */ - - /* Tempax: CR4 HRS */ - Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[3]; - Tempax &= 0x3F; /* Tempax: HRS[5:0] */ - if (Tempcx <= Tempax) /* HRE[5:0] < HRS[5:0] */ - Tempbx += 0x40; /* Tempbx= Tempbx + 0x40 : HRE[9:0]*/ - - Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[5]; /* SR0B */ - Tempax &= 0xC0; /* Tempax[7:6]: SR0B[7:6]: HRS[9:8]*/ - Tempax >>= 6; /* Tempax[1:0]: HRS[9:8]*/ - Tempax |= ((Tempbx << 2) & 0xFF); /* Tempax[7:2]: HRE[5:0] */ - /* SR2F [7:2][1:0]: HRE[5:0]HRS[9:8] */ - xgifb_reg_set(pVBInfo->P3c4, 0x2F, Tempax); - xgifb_reg_and_or(pVBInfo->P3c4, 0x30, 0xE3, 00); - - /* CR10 VRS */ - Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[10]; - /* SR34[7:0]->VRS[7:0] */ - xgifb_reg_set(pVBInfo->P3c4, 0x34, Tempax); - - Tempcx = Tempax; /* Tempcx <= VRS[7:0] */ - /* CR7[7][2] VRS[9][8] */ - Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[9]; - Tempbx = Tempax; /* Tempbx <= CR07[7:0] */ - Tempax = Tempax & 0x04; /* Tempax[2]: CR7[2]: VRS[8] */ - Tempax >>= 2; /* Tempax[0]: VRS[8] */ - /* SR35[0]: VRS[8] */ - xgifb_reg_and_or(pVBInfo->P3c4, 0x35, ~0x01, Tempax); - Tempcx |= (Tempax << 8); /* Tempcx <= VRS[8:0] */ - Tempcx |= ((Tempbx & 0x80) << 2); /* Tempcx <= VRS[9:0] */ - /* Tempax: SR0A */ - Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[14]; - Tempax &= 0x08; /* SR0A[3] VRS[10] */ - Tempcx |= (Tempax << 7); /* Tempcx <= VRS[10:0] */ - - /* Tempax: CR11 VRE */ - Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[11]; - Tempax &= 0x0F; /* Tempax[3:0]: VRE[3:0] */ - /* Tempbx: SR0A */ - Tempbx = pVBInfo->XGINEWUB_CRT1Table[index].CR[14]; - Tempbx &= 0x20; /* Tempbx[5]: SR0A[5]: VRE[4] */ - Tempbx >>= 1; /* Tempbx[4]: VRE[4] */ - Tempax |= Tempbx; /* Tempax[4:0]: VRE[4:0] */ - Tempbx = Tempcx; /* Tempbx: VRS[10:0] */ - Tempbx &= 0x7E0; /* Tempbx[10:5]: VRS[10:5] */ - Tempbx |= Tempax; /* Tempbx: VRS[10:5]VRE[4:0] */ - - if (Tempbx <= Tempcx) /* VRE <= VRS */ - Tempbx |= 0x20; /* VRE + 0x20 */ - - /* Tempax: Tempax[7:0]; VRE[5:0]00 */ - Tempax = (Tempbx << 2) & 0xFF; - /* SR3F[7:2]:VRE[5:0] */ - xgifb_reg_and_or(pVBInfo->P3c4, 0x3F, ~0xFC, Tempax); - Tempax = Tempcx >> 8; - /* SR35[2:0]:VRS[10:8] */ - xgifb_reg_and_or(pVBInfo->P3c4, 0x35, ~0x07, Tempax); - } + unsigned short index, Tempax, Tempbx, Tempcx; + + index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; + /* Tempax: CR4 HRS */ + Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[3]; + Tempbx = Tempax; /* Tempbx: HRS[7:0] */ + /* SR2E[7:0]->HRS */ + xgifb_reg_set(pVBInfo->P3c4, 0x2E, Tempax); + + /* SR0B */ + Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[5]; + Tempax &= 0xC0; /* Tempax[7:6]: SR0B[7:6]: HRS[9:8]*/ + Tempbx |= (Tempax << 2); /* Tempbx: HRS[9:0] */ + + Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[4]; /* CR5 HRE */ + Tempax &= 0x1F; /* Tempax[4:0]: HRE[4:0] */ + Tempcx = Tempax; /* Tempcx: HRE[4:0] */ + + Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[6]; /* SRC */ + Tempax &= 0x04; /* Tempax[2]: HRE[5] */ + Tempax <<= 3; /* Tempax[5]: HRE[5] */ + Tempcx |= Tempax; /* Tempcx[5:0]: HRE[5:0] */ + + Tempbx = Tempbx & 0x3C0; /* Tempbx[9:6]: HRS[9:6] */ + Tempbx |= Tempcx; /* Tempbx: HRS[9:6]HRE[5:0] */ + + /* Tempax: CR4 HRS */ + Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[3]; + Tempax &= 0x3F; /* Tempax: HRS[5:0] */ + if (Tempcx <= Tempax) /* HRE[5:0] < HRS[5:0] */ + Tempbx += 0x40; /* Tempbx= Tempbx + 0x40 : HRE[9:0]*/ + + Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[5]; /* SR0B */ + Tempax &= 0xC0; /* Tempax[7:6]: SR0B[7:6]: HRS[9:8]*/ + Tempax >>= 6; /* Tempax[1:0]: HRS[9:8]*/ + Tempax |= ((Tempbx << 2) & 0xFF); /* Tempax[7:2]: HRE[5:0] */ + /* SR2F [7:2][1:0]: HRE[5:0]HRS[9:8] */ + xgifb_reg_set(pVBInfo->P3c4, 0x2F, Tempax); + xgifb_reg_and_or(pVBInfo->P3c4, 0x30, 0xE3, 00); + + /* CR10 VRS */ + Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[10]; + /* SR34[7:0]->VRS[7:0] */ + xgifb_reg_set(pVBInfo->P3c4, 0x34, Tempax); + + Tempcx = Tempax; /* Tempcx <= VRS[7:0] */ + /* CR7[7][2] VRS[9][8] */ + Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[9]; + Tempbx = Tempax; /* Tempbx <= CR07[7:0] */ + Tempax = Tempax & 0x04; /* Tempax[2]: CR7[2]: VRS[8] */ + Tempax >>= 2; /* Tempax[0]: VRS[8] */ + /* SR35[0]: VRS[8] */ + xgifb_reg_and_or(pVBInfo->P3c4, 0x35, ~0x01, Tempax); + Tempcx |= (Tempax << 8); /* Tempcx <= VRS[8:0] */ + Tempcx |= ((Tempbx & 0x80) << 2); /* Tempcx <= VRS[9:0] */ + /* Tempax: SR0A */ + Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[14]; + Tempax &= 0x08; /* SR0A[3] VRS[10] */ + Tempcx |= (Tempax << 7); /* Tempcx <= VRS[10:0] */ + + /* Tempax: CR11 VRE */ + Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[11]; + Tempax &= 0x0F; /* Tempax[3:0]: VRE[3:0] */ + /* Tempbx: SR0A */ + Tempbx = pVBInfo->XGINEWUB_CRT1Table[index].CR[14]; + Tempbx &= 0x20; /* Tempbx[5]: SR0A[5]: VRE[4] */ + Tempbx >>= 1; /* Tempbx[4]: VRE[4] */ + Tempax |= Tempbx; /* Tempax[4:0]: VRE[4:0] */ + Tempbx = Tempcx; /* Tempbx: VRS[10:0] */ + Tempbx &= 0x7E0; /* Tempbx[10:5]: VRS[10:5] */ + Tempbx |= Tempax; /* Tempbx: VRS[10:5]VRE[4:0] */ + + if (Tempbx <= Tempcx) /* VRE <= VRS */ + Tempbx |= 0x20; /* VRE + 0x20 */ + + /* Tempax: Tempax[7:0]; VRE[5:0]00 */ + Tempax = (Tempbx << 2) & 0xFF; + /* SR3F[7:2]:VRE[5:0] */ + xgifb_reg_and_or(pVBInfo->P3c4, 0x3F, ~0xFC, Tempax); + Tempax = Tempcx >> 8; + /* SR35[2:0]:VRS[10:8] */ + xgifb_reg_and_or(pVBInfo->P3c4, 0x35, ~0x07, Tempax); } static void XGI_SetXG27FPBits(struct vb_device_info *pVBInfo) @@ -954,7 +775,7 @@ static void xgifb_set_lcd(int chip_id, unsigned short RefreshRateTableIndex, unsigned short ModeNo) { - unsigned short Data, Temp, b3CC; + unsigned short Data, Temp; unsigned short XGI_P3cc; XGI_P3cc = pVBInfo->P3cc; @@ -995,23 +816,13 @@ static void xgifb_set_lcd(int chip_id, xgifb_reg_and(pVBInfo->P3c4, 0x30, ~0x20); /* Hsync polarity */ xgifb_reg_and(pVBInfo->P3c4, 0x35, ~0x80); /* Vsync polarity */ - if (ModeNo <= 0x13) { - b3CC = (unsigned char) inb(XGI_P3cc); - if (b3CC & 0x40) - /* Hsync polarity */ - xgifb_reg_or(pVBInfo->P3c4, 0x30, 0x20); - if (b3CC & 0x80) - /* Vsync polarity */ - xgifb_reg_or(pVBInfo->P3c4, 0x35, 0x80); - } else { - Data = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_InfoFlag; - if (Data & 0x4000) - /* Hsync polarity */ - xgifb_reg_or(pVBInfo->P3c4, 0x30, 0x20); - if (Data & 0x8000) - /* Vsync polarity */ - xgifb_reg_or(pVBInfo->P3c4, 0x35, 0x80); - } + Data = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_InfoFlag; + if (Data & 0x4000) + /* Hsync polarity */ + xgifb_reg_or(pVBInfo->P3c4, 0x30, 0x20); + if (Data & 0x8000) + /* Vsync polarity */ + xgifb_reg_or(pVBInfo->P3c4, 0x35, 0x80); } /* --------------------------------------------------------------------- */ @@ -1024,30 +835,22 @@ static void XGI_UpdateXG21CRTC(unsigned short ModeNo, struct vb_device_info *pVBInfo, unsigned short RefreshRateTableIndex) { - int i, index = -1; + int index = -1; xgifb_reg_and(pVBInfo->P3d4, 0x11, 0x7F); /* Unlock CR0~7 */ - if (ModeNo <= 0x13) { - for (i = 0; i < 12; i++) { - if (ModeNo == pVBInfo->UpdateCRT1[i].ModeID) - index = i; - } - } else { - if (ModeNo == 0x2E && - (pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC == - RES640x480x60)) - index = 12; - else if (ModeNo == 0x2E && - (pVBInfo->RefIndex[RefreshRateTableIndex]. + if (ModeNo == 0x2E && + (pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC == + RES640x480x60)) + index = 12; + else if (ModeNo == 0x2E && (pVBInfo->RefIndex[RefreshRateTableIndex]. Ext_CRT1CRTC == RES640x480x72)) - index = 13; - else if (ModeNo == 0x2F) - index = 14; - else if (ModeNo == 0x50) - index = 15; - else if (ModeNo == 0x59) - index = 16; - } + index = 13; + else if (ModeNo == 0x2F) + index = 14; + else if (ModeNo == 0x50) + index = 15; + else if (ModeNo == 0x59) + index = 16; if (index != -1) { xgifb_reg_set(pVBInfo->P3d4, 0x02, @@ -1061,20 +864,6 @@ static void XGI_UpdateXG21CRTC(unsigned short ModeNo, } } -static unsigned short XGI_GetResInfo(unsigned short ModeNo, - unsigned short ModeIdIndex, struct vb_device_info *pVBInfo) -{ - unsigned short resindex; - - if (ModeNo <= 0x13) - /* si+St_ResInfo */ - resindex = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo; - else - /* si+Ext_ResInfo */ - resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; - return resindex; -} - static void XGI_SetCRT1DE(struct xgi_hw_device_info *HwDeviceExtension, unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, @@ -1084,33 +873,25 @@ static void XGI_SetCRT1DE(struct xgi_hw_device_info *HwDeviceExtension, unsigned char data; - resindex = XGI_GetResInfo(ModeNo, ModeIdIndex, pVBInfo); + resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; - if (ModeNo <= 0x13) { - modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; - tempax = pVBInfo->StResInfo[resindex].HTotal; - tempbx = pVBInfo->StResInfo[resindex].VTotal; - } else { - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; - tempax = pVBInfo->ModeResInfo[resindex].HTotal; - tempbx = pVBInfo->ModeResInfo[resindex].VTotal; - } + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; + tempax = pVBInfo->ModeResInfo[resindex].HTotal; + tempbx = pVBInfo->ModeResInfo[resindex].VTotal; if (modeflag & HalfDCLK) tempax = tempax >> 1; - if (ModeNo > 0x13) { - if (modeflag & HalfDCLK) - tempax = tempax << 1; + if (modeflag & HalfDCLK) + tempax = tempax << 1; - temp = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_InfoFlag; + temp = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_InfoFlag; - if (temp & InterlaceMode) - tempbx = tempbx >> 1; + if (temp & InterlaceMode) + tempbx = tempbx >> 1; - if (modeflag & DoubleScanMode) - tempbx = tempbx << 1; - } + if (modeflag & DoubleScanMode) + tempbx = tempbx << 1; tempcx = 8; @@ -1258,18 +1039,10 @@ static unsigned short XGI_GetVCLK2Ptr(unsigned short ModeNo, unsigned short CRT2Index, VCLKIndex; unsigned short modeflag, resinfo; - if (ModeNo <= 0x13) { - /* si+St_ResInfo */ - modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; - resinfo = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo; - CRT2Index = pVBInfo->SModeIDTable[ModeIdIndex].St_CRT2CRTC; - } else { - /* si+Ext_ResInfo */ - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; - resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; - CRT2Index = pVBInfo->RefIndex[RefreshRateTableIndex]. - Ext_CRT2CRTC; - } + /* si+Ext_ResInfo */ + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; + resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; + CRT2Index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; if (pVBInfo->IF_DEF_LVDS == 0) { CRT2Index = CRT2Index >> 6; /* for LCD */ @@ -1318,23 +1091,13 @@ static unsigned short XGI_GetVCLK2Ptr(unsigned short ModeNo, VCLKIndex += 25; } } else { /* for CRT2 */ - /* Port 3cch */ - VCLKIndex = (unsigned char) inb((pVBInfo->P3ca + 0x02)); - VCLKIndex = ((VCLKIndex >> 2) & 0x03); - if (ModeNo > 0x13) { - /* di+Ext_CRTVCLK */ - VCLKIndex = pVBInfo->RefIndex[ - RefreshRateTableIndex]. + /* di+Ext_CRTVCLK */ + VCLKIndex = pVBInfo->RefIndex[RefreshRateTableIndex]. Ext_CRTVCLK; - VCLKIndex &= IndexMask; - } + VCLKIndex &= IndexMask; } } else { /* LVDS */ - if (ModeNo <= 0x13) - VCLKIndex = CRT2Index; - else - VCLKIndex = CRT2Index; - + VCLKIndex = CRT2Index; VCLKIndex = VCLKIndex >> 6; if ((pVBInfo->LCDResInfo == Panel_800x600) || (pVBInfo->LCDResInfo == Panel_320x480)) @@ -1431,27 +1194,13 @@ static void XGI_SetCRT1FIFO(unsigned short ModeNo, data &= 0xfe; xgifb_reg_set(pVBInfo->P3c4, 0x3D, data); /* diable auto-threshold */ - if (ModeNo > 0x13) { - xgifb_reg_set(pVBInfo->P3c4, 0x08, 0x34); - data = xgifb_reg_get(pVBInfo->P3c4, 0x09); - data &= 0xC0; - xgifb_reg_set(pVBInfo->P3c4, 0x09, data | 0x30); - data = xgifb_reg_get(pVBInfo->P3c4, 0x3D); - data |= 0x01; - xgifb_reg_set(pVBInfo->P3c4, 0x3D, data); - } else { - if (HwDeviceExtension->jChipType == XG27) { - xgifb_reg_set(pVBInfo->P3c4, 0x08, 0x0E); - data = xgifb_reg_get(pVBInfo->P3c4, 0x09); - data &= 0xC0; - xgifb_reg_set(pVBInfo->P3c4, 0x09, data | 0x20); - } else { - xgifb_reg_set(pVBInfo->P3c4, 0x08, 0xAE); - data = xgifb_reg_get(pVBInfo->P3c4, 0x09); - data &= 0xF0; - xgifb_reg_set(pVBInfo->P3c4, 0x09, data); - } - } + xgifb_reg_set(pVBInfo->P3c4, 0x08, 0x34); + data = xgifb_reg_get(pVBInfo->P3c4, 0x09); + data &= 0xC0; + xgifb_reg_set(pVBInfo->P3c4, 0x09, data | 0x30); + data = xgifb_reg_get(pVBInfo->P3c4, 0x3D); + data |= 0x01; + xgifb_reg_set(pVBInfo->P3c4, 0x3D, data); if (HwDeviceExtension->jChipType == XG21) XGI_SetXG21FPBits(pVBInfo); /* Fix SR9[7:6] can't read back */ @@ -1466,13 +1215,9 @@ static void XGI_SetVCLKState(struct xgi_hw_device_info *HwDeviceExtension, unsigned char index; - if (ModeNo <= 0x13) - VCLK = 0; - else { - index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; - index &= IndexMask; - VCLK = pVBInfo->VCLKData[index].CLOCK; - } + index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; + index &= IndexMask; + VCLK = pVBInfo->VCLKData[index].CLOCK; data = xgifb_reg_get(pVBInfo->P3c4, 0x32); data &= 0xf3; @@ -1508,44 +1253,26 @@ static void XGI_SetCRT1ModeRegs(struct xgi_hw_device_info *HwDeviceExtension, unsigned short data, data2, data3, infoflag = 0, modeflag, resindex, xres; - if (ModeNo > 0x13) { - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; - infoflag = pVBInfo->RefIndex[RefreshRateTableIndex]. - Ext_InfoFlag; - } else - /* si+St_ModeFlag */ - modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; + infoflag = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_InfoFlag; if (xgifb_reg_get(pVBInfo->P3d4, 0x31) & 0x01) xgifb_reg_and_or(pVBInfo->P3c4, 0x1F, 0x3F, 0x00); - if (ModeNo > 0x13) - data = infoflag; - else - data = 0; - + data = infoflag; data2 = 0; - - if (ModeNo > 0x13) { - if (pVBInfo->ModeType > 0x02) { - data2 |= 0x02; - data3 = pVBInfo->ModeType - ModeVGA; - data3 = data3 << 2; - data2 |= data3; - } - } - + data2 |= 0x02; + data3 = pVBInfo->ModeType - ModeVGA; + data3 = data3 << 2; + data2 |= data3; data &= InterlaceMode; if (data) data2 |= 0x20; xgifb_reg_and_or(pVBInfo->P3c4, 0x06, ~0x3F, data2); - resindex = XGI_GetResInfo(ModeNo, ModeIdIndex, pVBInfo); - if (ModeNo <= 0x13) - xres = pVBInfo->StResInfo[resindex].HTotal; - else - xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */ + resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; + xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */ data = 0x0000; if (infoflag & InterlaceMode) { @@ -1568,18 +1295,10 @@ static void XGI_SetCRT1ModeRegs(struct xgi_hw_device_info *HwDeviceExtension, if (modeflag & LineCompareOff) data2 |= 0x08; - if (ModeNo > 0x13) { - if (pVBInfo->ModeType == ModeEGA) - data2 |= 0x40; - } - xgifb_reg_and_or(pVBInfo->P3c4, 0x0F, ~0x48, data2); data = 0x60; - if (pVBInfo->ModeType != ModeText) { - data = data ^ 0x60; - if (pVBInfo->ModeType != ModeEGA) - data = data ^ 0xA0; - } + data = data ^ 0x60; + data = data ^ 0xA0; xgifb_reg_and_or(pVBInfo->P3c4, 0x21, 0x1F, data); XGI_SetVCLKState(HwDeviceExtension, ModeNo, RefreshRateTableIndex, @@ -1644,38 +1363,13 @@ static void XGI_WriteDAC(unsigned short dl, static void XGI_LoadDAC(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo) { - unsigned short data, data2, time, i, j, k, m, n, o, si, di, bx, dl, al, - ah, dh; - const unsigned short *table = NULL; - - if (ModeNo <= 0x13) - data = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; - else - data = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; - - data &= DACInfoFlag; - time = 64; - - if (data == 0x00) - table = XGINew_MDA_DAC; - else if (data == 0x08) - table = XGINew_CGA_DAC; - else if (data == 0x10) - table = XGINew_EGA_DAC; - else if (data == 0x18) { - time = 256; - table = XGINew_VGA_DAC; - } - - if (time == 256) - j = 16; - else - j = time; + unsigned short data, data2, i, k, m, n, o, si, di, bx, dl, al, ah, dh; + const unsigned short *table = XGINew_VGA_DAC; outb(0xFF, pVBInfo->P3c6); outb(0x00, pVBInfo->P3c8); - for (i = 0; i < j; i++) { + for (i = 0; i < 16; i++) { data = table[i]; for (k = 0; k < 3; k++) { @@ -1692,45 +1386,43 @@ static void XGI_LoadDAC(unsigned short ModeNo, unsigned short ModeIdIndex, } } - if (time == 256) { - for (i = 16; i < 32; i++) { - data = table[i]; - - for (k = 0; k < 3; k++) - outb(data, pVBInfo->P3c9); - } + for (i = 16; i < 32; i++) { + data = table[i]; - si = 32; + for (k = 0; k < 3; k++) + outb(data, pVBInfo->P3c9); + } - for (m = 0; m < 9; m++) { - di = si; - bx = si + 0x04; - dl = 0; + si = 32; - for (n = 0; n < 3; n++) { - for (o = 0; o < 5; o++) { - dh = table[si]; - ah = table[di]; - al = table[bx]; - si++; - XGI_WriteDAC(dl, ah, al, dh, pVBInfo); - } + for (m = 0; m < 9; m++) { + di = si; + bx = si + 0x04; + dl = 0; - si -= 2; + for (n = 0; n < 3; n++) { + for (o = 0; o < 5; o++) { + dh = table[si]; + ah = table[di]; + al = table[bx]; + si++; + XGI_WriteDAC(dl, ah, al, dh, pVBInfo); + } - for (o = 0; o < 3; o++) { - dh = table[bx]; - ah = table[di]; - al = table[si]; - si--; - XGI_WriteDAC(dl, ah, al, dh, pVBInfo); - } + si -= 2; - dl++; + for (o = 0; o < 3; o++) { + dh = table[bx]; + ah = table[di]; + al = table[si]; + si--; + XGI_WriteDAC(dl, ah, al, dh, pVBInfo); } - si += 5; + dl++; } + + si += 5; } } @@ -1740,34 +1432,20 @@ static void XGI_GetLVDSResInfo(unsigned short ModeNo, { unsigned short resindex, xres, yres, modeflag; - if (ModeNo <= 0x13) - /* si+St_ResInfo */ - modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo; - else - /* si+Ext_ResInfo */ - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; + /* si+Ext_ResInfo */ + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; - if (ModeNo <= 0x13) - /* si+St_ResInfo */ - resindex = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo; - else - /* si+Ext_ResInfo */ - resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; + /* si+Ext_ResInfo */ + resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; - if (ModeNo <= 0x13) { - xres = pVBInfo->StResInfo[resindex].HTotal; - yres = pVBInfo->StResInfo[resindex].VTotal; - } else { - xres = pVBInfo->ModeResInfo[resindex].HTotal; - yres = pVBInfo->ModeResInfo[resindex].VTotal; - } - if (ModeNo > 0x13) { - if (modeflag & HalfDCLK) - xres = xres << 1; + xres = pVBInfo->ModeResInfo[resindex].HTotal; + yres = pVBInfo->ModeResInfo[resindex].VTotal; - if (modeflag & DoubleScanMode) - yres = yres << 1; - } + if (modeflag & HalfDCLK) + xres = xres << 1; + + if (modeflag & DoubleScanMode) + yres = yres << 1; if (xres == 720) xres = 640; @@ -1789,32 +1467,16 @@ static void *XGI_GetLcdPtr(unsigned short BX, unsigned short ModeNo, tempbx = BX; - if (ModeNo <= 0x13) { - modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; - tempal = pVBInfo->SModeIDTable[ModeIdIndex].St_CRT2CRTC; - } else { - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; - tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; - } + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; + tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; tempal = tempal & 0x0f; if (tempbx <= 1) { /* ExpLink */ - if (ModeNo <= 0x13) { - /* find no Ext_CRT2CRTC2 */ - tempal = pVBInfo->SModeIDTable[ModeIdIndex].St_CRT2CRTC; - } else { - tempal = pVBInfo->RefIndex[RefreshRateTableIndex]. - Ext_CRT2CRTC; - } + tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) { - if (ModeNo <= 0x13) - tempal = pVBInfo->SModeIDTable[ModeIdIndex]. - St_CRT2CRTC2; - else - tempal = pVBInfo->RefIndex[ - RefreshRateTableIndex]. + tempal = pVBInfo->RefIndex[RefreshRateTableIndex]. Ext_CRT2CRTC2; } @@ -1882,9 +1544,6 @@ static void *XGI_GetLcdPtr(unsigned short BX, unsigned short ModeNo, tempbx = tempdi[i].MASK; tempdx = pVBInfo->LCDInfo; - if (ModeNo <= 0x13) /* alan 09/10/2003 */ - tempdx |= SetLCDStdMode; - if (modeflag & HalfDCLK) tempdx |= SetLCDLowResolution; @@ -2238,15 +1897,8 @@ static void *XGI_GetTVPtr(unsigned short BX, unsigned short ModeNo, struct XGI330_TVDataTablStruct *tempdi = NULL; tempbx = BX; - - if (ModeNo <= 0x13) { - modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; - tempal = pVBInfo->SModeIDTable[ModeIdIndex].St_CRT2CRTC; - } else { - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; - tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; - } - + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; + tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; tempal = tempal & 0x3f; table = tempbx; @@ -2413,11 +2065,7 @@ static void XGI_ModCRT1Regs(unsigned short ModeNo, unsigned short ModeIdIndex, struct XGI_LVDSCRT1HDataStruct *LCDPtr = NULL; struct XGI_LVDSCRT1VDataStruct *LCDPtr1 = NULL; - if (ModeNo <= 0x13) - index = pVBInfo->SModeIDTable[ModeIdIndex].St_CRT2CRTC; - else - index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; - + index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; index = index & IndexMask; tempbx = 0; @@ -2530,14 +2178,10 @@ static void XGI_SetLVDSRegs(unsigned short ModeNo, unsigned short ModeIdIndex, { unsigned short tempbx, tempax, tempcx, tempdx, push1, push2, modeflag; unsigned long temp, temp1, temp2, temp3, push3; - struct XGI330_LCDDataDesStruct *LCDPtr = NULL; + struct XGI_LCDDesStruct *LCDPtr = NULL; struct XGI330_LCDDataDesStruct2 *LCDPtr1 = NULL; - if (ModeNo > 0x13) - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; - else - modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; - + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; tempbx = 3; if (pVBInfo->LCDInfo & EnableScalingLCD) LCDPtr1 = @@ -2550,7 +2194,7 @@ static void XGI_SetLVDSRegs(unsigned short ModeNo, unsigned short ModeIdIndex, pVBInfo); else LCDPtr = - (struct XGI330_LCDDataDesStruct *) + (struct XGI_LCDDesStruct *) XGI_GetLcdPtr( tempbx, ModeNo, @@ -2829,12 +2473,8 @@ static unsigned char XGI_GetVCLKPtr(unsigned short RefreshRateTableIndex, unsigned short index, modeflag; unsigned char tempal; - if (ModeNo <= 0x13) - /* si+St_ResInfo */ - modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; - else - /* si+Ext_ResInfo */ - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; + /* si+Ext_ResInfo */ + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; if ((pVBInfo->SetFlag & ProgrammingCRT2) && (!(pVBInfo->LCDInfo & EnableScalingLCD))) { /* {LCDA/LCDB} */ @@ -2895,9 +2535,6 @@ static unsigned char XGI_GetVCLKPtr(unsigned short RefreshRateTableIndex, if ((pVBInfo->LCDInfo & EnableScalingLCD) && (modeflag & Charx8Dot)) tempal = tempal ^ tempal; /* ; set to VCLK25MHz always */ - if (ModeNo <= 0x13) - return tempal; - tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; return tempal; } @@ -3079,11 +2716,7 @@ static void XGI_GetVBInfo(unsigned short ModeNo, unsigned short ModeIdIndex, { unsigned short tempax, push, tempbx, temp, modeflag; - if (ModeNo <= 0x13) - modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; - else - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; - + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; pVBInfo->SetFlag = 0; pVBInfo->ModeType = modeflag & ModeTypeMask; tempbx = 0; @@ -3283,17 +2916,8 @@ static void XGI_GetTVInfo(unsigned short ModeNo, unsigned short ModeIdIndex, resinfo = 0; if (pVBInfo->VBInfo & SetCRT2ToTV) { - if (ModeNo <= 0x13) { - modeflag = pVBInfo->SModeIDTable[ModeIdIndex]. - St_ModeFlag; /* si+St_ModeFlag */ - resinfo = pVBInfo->SModeIDTable[ModeIdIndex]. - St_ResInfo; /* si+St_ResInfo */ - } else { - modeflag = pVBInfo->EModeIDTable[ModeIdIndex]. - Ext_ModeFlag; - resinfo = pVBInfo->EModeIDTable[ModeIdIndex]. - Ext_RESINFO; /* si+Ext_ResInfo */ - } + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; + resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; if (pVBInfo->VBInfo & SetCRT2ToTV) { temp = xgifb_reg_get(pVBInfo->P3d4, 0x35); @@ -3380,15 +3004,9 @@ static unsigned char XGI_GetLCDInfo(unsigned short ModeNo, pVBInfo->LCDTypeInfo = 0; pVBInfo->LCDInfo = 0; - if (ModeNo <= 0x13) { - /* si+St_ModeFlag // */ - modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; - } else { - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; - /* si+Ext_ResInfo // */ - resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; - } - + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; + /* si+Ext_ResInfo // */ + resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; temp = xgifb_reg_get(pVBInfo->P3d4, 0x36); /* Get LCD Res.Info */ tempbx = temp & 0x0F; @@ -3442,8 +3060,8 @@ static unsigned char XGI_GetLCDInfo(unsigned short ModeNo, if (pVBInfo->IF_DEF_LVDS == 0) { if ((pVBInfo->LCDResInfo == Panel_1400x1050) && (pVBInfo->VBInfo - & SetCRT2ToLCD) && (ModeNo > 0x13) && (resinfo - == 9) && (!(tempbx & EnableScalingLCD))) + & SetCRT2ToLCD) && (resinfo == 9) && + (!(tempbx & EnableScalingLCD))) /* set to center in 1280x1024 LCDB for Panel_1400x1050 */ tempbx |= SetLCDtoNonExpanding; } @@ -3453,12 +3071,9 @@ static unsigned char XGI_GetLCDInfo(unsigned short ModeNo, if (!(tempbx & SetLCDtoNonExpanding)) { tempbx |= XGI_EnableLVDSDDA; } else { - if (ModeNo > 0x13) { - if (pVBInfo->LCDResInfo - == Panel_1024x768) { - if (resinfo == 4) {/* 512x384 */ - tempbx |= XGI_EnableLVDSDDA; - } + if (pVBInfo->LCDResInfo == Panel_1024x768) { + if (resinfo == 4) {/* 512x384 */ + tempbx |= XGI_EnableLVDSDDA; } } } @@ -3474,56 +3089,17 @@ static unsigned char XGI_GetLCDInfo(unsigned short ModeNo, pVBInfo->LCDInfo = tempbx; - if (pVBInfo->IF_DEF_LVDS == 0) { - if (tempax & (LockLCDBToA | StLCDBToA)) { - if (pVBInfo->VBInfo & SetInSlaveMode) { - if (!(tempax & LockLCDBToA)) { - if (ModeNo <= 0x13) { - pVBInfo->VBInfo &= - ~(SetSimuScanMode | - SetInSlaveMode | - SetCRT2ToLCD); - pVBInfo->VBInfo |= - XGI_SetCRT2ToLCDA | - SetCRT2ToDualEdge; - } - } - } - } - } - return 1; } unsigned char XGI_SearchModeID(unsigned short ModeNo, unsigned short *ModeIdIndex, struct vb_device_info *pVBInfo) { - if (ModeNo <= 5) - ModeNo |= 1; - if (ModeNo <= 0x13) { - for (*ModeIdIndex = 0;; (*ModeIdIndex)++) { - if (pVBInfo->SModeIDTable[*ModeIdIndex].St_ModeID == - ModeNo) - break; - if (pVBInfo->SModeIDTable[*ModeIdIndex].St_ModeID == - 0xFF) - return 0; - } - - if (ModeNo == 0x07) - (*ModeIdIndex)++; /* 400 lines */ - if (ModeNo <= 3) - (*ModeIdIndex) += 2; /* 400 lines */ - /* else 350 lines */ - } else { - for (*ModeIdIndex = 0;; (*ModeIdIndex)++) { - if (pVBInfo->EModeIDTable[*ModeIdIndex].Ext_ModeID == - ModeNo) - break; - if (pVBInfo->EModeIDTable[*ModeIdIndex].Ext_ModeID == - 0xFF) - return 0; - } + for (*ModeIdIndex = 0;; (*ModeIdIndex)++) { + if (pVBInfo->EModeIDTable[*ModeIdIndex].Ext_ModeID == ModeNo) + break; + if (pVBInfo->EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF) + return 0; } return 1; @@ -3789,22 +3365,17 @@ static void XGI_GetCRT2ResInfo(unsigned short ModeNo, { unsigned short xres, yres, modeflag, resindex; - resindex = XGI_GetResInfo(ModeNo, ModeIdIndex, pVBInfo); - if (ModeNo <= 0x13) { - xres = pVBInfo->StResInfo[resindex].HTotal; - yres = pVBInfo->StResInfo[resindex].VTotal; - } else { - xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */ - yres = pVBInfo->ModeResInfo[resindex].VTotal; /* yres->bx */ - /* si+St_ModeFlag */ - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; + resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; + xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */ + yres = pVBInfo->ModeResInfo[resindex].VTotal; /* yres->bx */ + /* si+St_ModeFlag */ + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; - if (modeflag & HalfDCLK) - xres *= 2; + if (modeflag & HalfDCLK) + xres *= 2; - if (modeflag & DoubleScanMode) - yres *= 2; - } + if (modeflag & DoubleScanMode) + yres *= 2; if (pVBInfo->VBInfo & SetCRT2ToLCD) { if (pVBInfo->IF_DEF_LVDS == 0) { @@ -3868,37 +3439,23 @@ static void XGI_GetRAMDAC2DATA(unsigned short ModeNo, struct vb_device_info *pVBInfo) { unsigned short tempax, tempbx, temp1, temp2, modeflag = 0, tempcx, - StandTableIndex, CRT1Index; + CRT1Index; pVBInfo->RVBHCMAX = 1; pVBInfo->RVBHCFACT = 1; - - if (ModeNo <= 0x13) { - modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; - StandTableIndex = XGI_GetModePtr(ModeNo, ModeIdIndex, pVBInfo); - tempax = pVBInfo->StandTable[StandTableIndex].CRTC[0]; - tempbx = pVBInfo->StandTable[StandTableIndex].CRTC[6]; - temp1 = pVBInfo->StandTable[StandTableIndex].CRTC[7]; - } else { - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; - CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex]. - Ext_CRT1CRTC; - CRT1Index &= IndexMask; - temp1 = (unsigned short) pVBInfo-> - XGINEWUB_CRT1Table[CRT1Index].CR[0]; - temp2 = (unsigned short) pVBInfo-> - XGINEWUB_CRT1Table[CRT1Index].CR[5]; - tempax = (temp1 & 0xFF) | ((temp2 & 0x03) << 8); - tempbx = (unsigned short) pVBInfo-> - XGINEWUB_CRT1Table[CRT1Index].CR[8]; - tempcx = (unsigned short) pVBInfo-> - XGINEWUB_CRT1Table[CRT1Index].CR[14] << 8; - tempcx &= 0x0100; - tempcx = tempcx << 2; - tempbx |= tempcx; - temp1 = (unsigned short) pVBInfo-> - XGINEWUB_CRT1Table[CRT1Index].CR[9]; - } + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; + CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; + CRT1Index &= IndexMask; + temp1 = (unsigned short) pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[0]; + temp2 = (unsigned short) pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[5]; + tempax = (temp1 & 0xFF) | ((temp2 & 0x03) << 8); + tempbx = (unsigned short) pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[8]; + tempcx = (unsigned short) + pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[14] << 8; + tempcx &= 0x0100; + tempcx = tempcx << 2; + tempbx |= tempcx; + temp1 = (unsigned short) pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[9]; if (temp1 & 0x01) tempbx |= 0x0100; @@ -3928,16 +3485,9 @@ static void XGI_GetCRT2Data(unsigned short ModeNo, unsigned short ModeIdIndex, struct SiS_LCDData *LCDPtr = NULL; struct SiS_TVData *TVPtr = NULL; - if (ModeNo <= 0x13) { - /* si+St_ResInfo */ - modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; - resinfo = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo; - } else { - /* si+Ext_ResInfo */ - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; - resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; - } - + /* si+Ext_ResInfo */ + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; + resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; pVBInfo->NewFlickerMode = 0; pVBInfo->RVBHRS = 50; @@ -4141,11 +3691,7 @@ static unsigned short XGI_GetColorDepth(unsigned short ModeNo, short index; unsigned short modeflag; - if (ModeNo <= 0x13) - modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; - else - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; - + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; index = (modeflag & ModeTypeMask) - ModeEGA; if (index < 0) @@ -4164,11 +3710,7 @@ static unsigned short XGI_GetOffset(unsigned short ModeNo, ColorDepth[] = { 0x01, 0x02, 0x04 }; modeinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeInfo; - if (ModeNo <= 0x14) - infoflag = 0; - else - infoflag = pVBInfo-> - RefIndex[RefreshRateTableIndex].Ext_InfoFlag; + infoflag = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_InfoFlag; index = (modeinfo >> 8) & 0xFF; @@ -4228,12 +3770,9 @@ static void XGI_PreSetGroup1(unsigned short ModeNo, unsigned short ModeIdIndex, { unsigned short tempcx = 0, CRT1Index = 0, resinfo = 0; - if (ModeNo > 0x13) { - CRT1Index = pVBInfo-> - RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; - CRT1Index &= IndexMask; - resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; - } + CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; + CRT1Index &= IndexMask; + resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; XGI_SetCRT2Offset(ModeNo, ModeIdIndex, RefreshRateTableIndex, HwDeviceExtension, pVBInfo); @@ -4254,17 +3793,10 @@ static void XGI_SetGroup1(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short temp = 0, tempax = 0, tempbx = 0, tempcx = 0, pushbx = 0, CRT1Index = 0, modeflag, resinfo = 0; - if (ModeNo > 0x13) { - CRT1Index = pVBInfo-> - RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; - CRT1Index &= IndexMask; - resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; - } - - if (ModeNo <= 0x13) - modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; - else - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; + CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; + CRT1Index &= IndexMask; + resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* bainy change table name */ if (modeflag & HalfDCLK) { @@ -4422,18 +3954,11 @@ static void XGI_SetLockRegs(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short push1, push2, tempax, tempbx = 0, tempcx, temp, resinfo, modeflag, CRT1Index; - if (ModeNo <= 0x13) { - /* si+St_ResInfo */ - modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; - resinfo = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo; - } else { - /* si+Ext_ResInfo */ - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; - resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; - CRT1Index = pVBInfo-> - RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; - CRT1Index &= IndexMask; - } + /* si+Ext_ResInfo */ + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; + resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; + CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; + CRT1Index &= IndexMask; if (!(pVBInfo->VBInfo & SetInSlaveMode)) return; @@ -4500,8 +4025,7 @@ static void XGI_SetLockRegs(unsigned short ModeNo, unsigned short ModeIdIndex, temp -= 6; if (pVBInfo->TVInfo & TVSimuMode) { temp -= 4; - if (ModeNo > 0x13) - temp -= 10; + temp -= 10; } } } else { @@ -4523,14 +4047,6 @@ static void XGI_SetLockRegs(unsigned short ModeNo, unsigned short ModeIdIndex, if (pVBInfo->LCDResInfo != Panel_1280x960 && pVBInfo->VGAHDE >= 800) { temp -= 7; - if (pVBInfo->ModeType == ModeEGA && - pVBInfo->VGAVDE == 1024) { - temp += 15; - if (pVBInfo->LCDResInfo != - Panel_1280x1024) - temp += 7; - } - if (pVBInfo->VGAHDE >= 1280 && pVBInfo->LCDResInfo != Panel_1280x960 && (pVBInfo->LCDInfo & LCDNonExpanding)) @@ -4546,48 +4062,7 @@ static void XGI_SetLockRegs(unsigned short ModeNo, unsigned short ModeIdIndex, if (pVBInfo->VBInfo & SetCRT2ToTV) { if (pVBInfo->TVInfo & TVSimuMode) { - if ((ModeNo == 0x06) || (ModeNo == 0x10) || (ModeNo - == 0x11) || (ModeNo == 0x13) || (ModeNo - == 0x0F)) { - xgifb_reg_set(pVBInfo->Part1Port, 0x07, 0x5b); - xgifb_reg_set(pVBInfo->Part1Port, 0x08, 0x03); - } - - if ((ModeNo == 0x00) || (ModeNo == 0x01)) { - if (pVBInfo->TVInfo & SetNTSCTV) { - xgifb_reg_set(pVBInfo->Part1Port, - 0x07, 0x2A); - xgifb_reg_set(pVBInfo->Part1Port, - 0x08, 0x61); - } else { - xgifb_reg_set(pVBInfo->Part1Port, - 0x07, 0x2A); - xgifb_reg_set(pVBInfo->Part1Port, - 0x08, 0x41); - xgifb_reg_set(pVBInfo->Part1Port, - 0x0C, 0xF0); - } - } - - if ((ModeNo == 0x02) || (ModeNo == 0x03) || (ModeNo - == 0x07)) { - if (pVBInfo->TVInfo & SetNTSCTV) { - xgifb_reg_set(pVBInfo->Part1Port, - 0x07, 0x54); - xgifb_reg_set(pVBInfo->Part1Port, - 0x08, 0x00); - } else { - xgifb_reg_set(pVBInfo->Part1Port, - 0x07, 0x55); - xgifb_reg_set(pVBInfo->Part1Port, - 0x08, 0x00); - xgifb_reg_set(pVBInfo->Part1Port, - 0x0C, 0xF0); - } - } - - if ((ModeNo == 0x04) || (ModeNo == 0x05) || (ModeNo - == 0x0D) || (ModeNo == 0x50)) { + if (ModeNo == 0x50) { if (pVBInfo->TVInfo & SetNTSCTV) { xgifb_reg_set(pVBInfo->Part1Port, 0x07, 0x30); @@ -4796,18 +4271,10 @@ static void XGI_SetGroup2(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned long longtemp, tempeax, tempebx, temp2, tempecx; - if (ModeNo <= 0x13) { - /* si+St_ResInfo */ - modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; - resinfo = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo; - crt2crtc = pVBInfo->SModeIDTable[ModeIdIndex].St_CRT2CRTC; - } else { - /* si+Ext_ResInfo */ - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; - resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; - crt2crtc = pVBInfo->RefIndex[RefreshRateTableIndex]. - Ext_CRT2CRTC; - } + /* si+Ext_ResInfo */ + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; + resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; + crt2crtc = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; tempax = 0; @@ -5245,18 +4712,11 @@ static void XGI_SetLCDRegs(unsigned short ModeNo, unsigned short ModeIdIndex, struct XGI_LCDDesStruct *LCDBDesPtr = NULL; - if (ModeNo <= 0x13) { - /* si+St_ResInfo */ - modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; - resinfo = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo; - } else { - /* si+Ext_ResInfo */ - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; - resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; - CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex]. - Ext_CRT1CRTC; - CRT1Index &= IndexMask; - } + /* si+Ext_ResInfo */ + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; + resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; + CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; + CRT1Index &= IndexMask; if (!(pVBInfo->VBInfo & SetCRT2ToLCD)) return; @@ -5274,16 +4734,6 @@ static void XGI_SetLCDRegs(unsigned short ModeNo, unsigned short ModeIdIndex, xgifb_reg_and_or(pVBInfo->Part2Port, 0x2B, 0x0F, temp); temp = 0x01; - if (pVBInfo->LCDResInfo == Panel_1280x1024) { - if (pVBInfo->ModeType == ModeEGA) { - if (pVBInfo->VGAHDE >= 1024) { - temp = 0x02; - if (pVBInfo->LCDInfo & XGI_LCDVESATiming) - temp = 0x01; - } - } - } - xgifb_reg_set(pVBInfo->Part2Port, 0x0B, temp); tempbx = pVBInfo->VDE; /* RTVACTEO=(VDE-1)&0xFF */ push1 = tempbx; @@ -5542,12 +4992,8 @@ static void XGI_SetGroup3(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned char *tempdi; unsigned short modeflag; - if (ModeNo <= 0x13) - /* si+St_ResInfo */ - modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; - else - /* si+Ext_ResInfo */ - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; + /* si+Ext_ResInfo */ + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; xgifb_reg_set(pVBInfo->Part3Port, 0x00, 0x00); if (pVBInfo->TVInfo & TVSetPAL) { @@ -5605,13 +5051,8 @@ static void XGI_SetGroup4(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned long tempebx, tempeax, templong; - if (ModeNo <= 0x13) - /* si+St_ResInfo */ - modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; - else - /* si+Ext_ResInfo */ - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; - + /* si+Ext_ResInfo */ + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; temp = pVBInfo->RVBHCFACT; xgifb_reg_set(pVBInfo->Part4Port, 0x13, temp); @@ -5818,32 +5259,22 @@ static unsigned char XGI_XG21CheckLVDSMode(struct xgifb_video_info *xgifb_info, { unsigned short xres, yres, colordepth, modeflag, resindex; - resindex = XGI_GetResInfo(ModeNo, ModeIdIndex, pVBInfo); - if (ModeNo <= 0x13) { - xres = pVBInfo->StResInfo[resindex].HTotal; - yres = pVBInfo->StResInfo[resindex].VTotal; - /* si+St_ResInfo */ - modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; - } else { - xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */ - yres = pVBInfo->ModeResInfo[resindex].VTotal; /* yres->bx */ - /* si+St_ModeFlag */ - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; - } + resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; + xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */ + yres = pVBInfo->ModeResInfo[resindex].VTotal; /* yres->bx */ + /* si+St_ModeFlag */ + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; if (!(modeflag & Charx8Dot)) { xres /= 9; xres *= 8; } - if (ModeNo > 0x13) { - if ((ModeNo > 0x13) && (modeflag & HalfDCLK)) - xres *= 2; - - if ((ModeNo > 0x13) && (modeflag & DoubleScanMode)) - yres *= 2; + if ((ModeNo > 0x13) && (modeflag & HalfDCLK)) + xres *= 2; - } + if ((ModeNo > 0x13) && (modeflag & DoubleScanMode)) + yres *= 2; if (xres > xgifb_info->lvds_data.LVDSHDE) return 0; @@ -5851,16 +5282,11 @@ static unsigned char XGI_XG21CheckLVDSMode(struct xgifb_video_info *xgifb_info, if (yres > xgifb_info->lvds_data.LVDSVDE) return 0; - if (ModeNo > 0x13) { - if (xres != xgifb_info->lvds_data.LVDSHDE || - yres != xgifb_info->lvds_data.LVDSVDE) { - colordepth = XGI_GetColorDepth(ModeNo, - ModeIdIndex, - pVBInfo); - if (colordepth > 2) - return 0; - - } + if (xres != xgifb_info->lvds_data.LVDSHDE || + yres != xgifb_info->lvds_data.LVDSVDE) { + colordepth = XGI_GetColorDepth(ModeNo, ModeIdIndex, pVBInfo); + if (colordepth > 2) + return 0; } return 1; } @@ -5895,18 +5321,11 @@ static void xgifb_set_lvds(struct xgifb_video_info *xgifb_info, else XGI_SetXG21FPBits(pVBInfo); - resindex = XGI_GetResInfo(ModeNo, ModeIdIndex, pVBInfo); - if (ModeNo <= 0x13) { - xres = pVBInfo->StResInfo[resindex].HTotal; - yres = pVBInfo->StResInfo[resindex].VTotal; - /* si+St_ResInfo */ - modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; - } else { - xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */ - yres = pVBInfo->ModeResInfo[resindex].VTotal; /* yres->bx */ - /* si+St_ModeFlag */ - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; - } + resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO; + xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */ + yres = pVBInfo->ModeResInfo[resindex].VTotal; /* yres->bx */ + /* si+St_ModeFlag */ + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; if (!(modeflag & Charx8Dot)) xres = xres * 8 / 9; @@ -5914,8 +5333,6 @@ static void xgifb_set_lvds(struct xgifb_video_info *xgifb_info, LVDSHT = xgifb_info->lvds_data.LVDSHT; LVDSHBS = xres + (xgifb_info->lvds_data.LVDSHDE - xres) / 2; - if ((ModeNo <= 0x13) && (modeflag & HalfDCLK)) - LVDSHBS -= xres / 4; if (LVDSHBS > LVDSHT) LVDSHBS -= LVDSHT; @@ -5933,7 +5350,7 @@ static void xgifb_set_lvds(struct xgifb_video_info *xgifb_info, LVDSVT = xgifb_info->lvds_data.LVDSVT; LVDSVBS = yres + (xgifb_info->lvds_data.LVDSVDE - yres) / 2; - if ((ModeNo > 0x13) && (modeflag & DoubleScanMode)) + if (modeflag & DoubleScanMode) LVDSVBS += yres / 2; if (LVDSVBS > LVDSVT) @@ -6527,7 +5944,7 @@ static void XGI_SetAntiFlicker(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo) { - unsigned short tempbx, index; + unsigned short tempbx; unsigned char tempah; @@ -6536,13 +5953,6 @@ static void XGI_SetAntiFlicker(unsigned short ModeNo, tempbx = XGI_GetTVPtrIndex(pVBInfo); tempbx &= 0xFE; - - if (ModeNo <= 0x13) - index = pVBInfo->SModeIDTable[ModeIdIndex].VB_StTVFlickerIndex; - else - index = pVBInfo->EModeIDTable[ModeIdIndex].VB_ExtTVFlickerIndex; - - tempbx += index; tempah = TVAntiFlickList[tempbx]; tempah = tempah << 4; @@ -6553,19 +5963,12 @@ static void XGI_SetEdgeEnhance(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo) { - unsigned short tempbx, index; + unsigned short tempbx; unsigned char tempah; tempbx = XGI_GetTVPtrIndex(pVBInfo); tempbx &= 0xFE; - - if (ModeNo <= 0x13) - index = pVBInfo->SModeIDTable[ModeIdIndex].VB_StTVEdgeIndex; - else - index = pVBInfo->EModeIDTable[ModeIdIndex].VB_ExtTVEdgeIndex; - - tempbx += index; tempah = TVEdgeList[tempbx]; tempah = tempah << 5; @@ -6631,13 +6034,7 @@ static void XGI_SetYFilter(unsigned short ModeNo, unsigned short ModeIdIndex, return; } - if (ModeNo <= 0x13) - tempal = pVBInfo->SModeIDTable[ModeIdIndex]. - VB_StTVYFilterIndex; - else - tempal = pVBInfo->EModeIDTable[ModeIdIndex]. - VB_ExtTVYFilterIndex; - + tempal = pVBInfo->EModeIDTable[ModeIdIndex].VB_ExtTVYFilterIndex; if (tempcl == 0) index = tempal * 4; else @@ -6712,16 +6109,14 @@ static void XGI_SetCRT2ModeRegs(unsigned short ModeNo, if (pVBInfo->VBInfo & (SetCRT2ToRAMDAC | SetCRT2ToTV | SetCRT2ToLCD)) { tempah = 0x40; /* BTDRAM */ - if (ModeNo > 0x13) { - tempcl = pVBInfo->ModeType; - tempcl -= ModeVGA; - if (tempcl >= 0) { - /* BT Color */ - tempah = (0x008 >> tempcl); - if (tempah == 0) - tempah = 1; - tempah |= 0x040; - } + tempcl = pVBInfo->ModeType; + tempcl -= ModeVGA; + if (tempcl >= 0) { + /* BT Color */ + tempah = (0x008 >> tempcl); + if (tempah == 0) + tempah = 1; + tempah |= 0x040; } if (pVBInfo->VBInfo & SetInSlaveMode) tempah ^= 0x50; /* BTDAC */ @@ -6797,10 +6192,8 @@ static void XGI_SetCRT2ModeRegs(unsigned short ModeNo, if (pVBInfo->VBInfo & SetCRT2ToTV) { tempah |= 0x020; - if (ModeNo > 0x13) { - if (pVBInfo->VBInfo & DriverMode) - tempah = tempah ^ 0x20; - } + if (pVBInfo->VBInfo & DriverMode) + tempah = tempah ^ 0x20; } xgifb_reg_and_or(pVBInfo->Part4Port, 0x0D, ~0x0BF, tempah); @@ -6925,13 +6318,7 @@ unsigned short XGI_GetRatePtrCRT2(struct xgi_hw_device_info *pXGIHWDE, unsigned short RefreshRateTableIndex, i, modeflag, index, temp; - if (ModeNo <= 0x13) - modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; - else - modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; - - if (ModeNo < 0x14) - return 0xFFFF; + modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; index = xgifb_reg_get(pVBInfo->P3d4, 0x33); index = index >> pVBInfo->SelectCRT2Rate; @@ -7297,16 +6684,13 @@ static void XGI_SetCRT1Group(struct xgifb_video_info *xgifb_info, unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo) { - unsigned short StandTableIndex, RefreshRateTableIndex, b3CC, temp; + unsigned short RefreshRateTableIndex, temp; - unsigned short XGINew_P3cc = pVBInfo->P3cc; - - StandTableIndex = XGI_GetModePtr(ModeNo, ModeIdIndex, pVBInfo); - XGI_SetSeqRegs(ModeNo, StandTableIndex, ModeIdIndex, pVBInfo); - outb(pVBInfo->StandTable[StandTableIndex].MISC, pVBInfo->P3c2); - XGI_SetCRTCRegs(HwDeviceExtension, StandTableIndex, pVBInfo); - XGI_SetATTRegs(ModeNo, StandTableIndex, ModeIdIndex, pVBInfo); - XGI_SetGRCRegs(StandTableIndex, pVBInfo); + XGI_SetSeqRegs(ModeNo, ModeIdIndex, pVBInfo); + outb(pVBInfo->StandTable->MISC, pVBInfo->P3c2); + XGI_SetCRTCRegs(HwDeviceExtension, pVBInfo); + XGI_SetATTRegs(ModeNo, ModeIdIndex, pVBInfo); + XGI_SetGRCRegs(pVBInfo); XGI_ClearExt1Regs(pVBInfo); if (HwDeviceExtension->jChipType == XG27) { @@ -7340,22 +6724,6 @@ static void XGI_SetCRT1Group(struct xgifb_video_info *xgifb_info, RefreshRateTableIndex, pVBInfo); } - if ((HwDeviceExtension->jChipType >= XG20) && - (HwDeviceExtension->jChipType < XG27)) { /* fix H/W DCLK/2 bug */ - if ((ModeNo == 0x00) | (ModeNo == 0x01)) { - xgifb_reg_set(pVBInfo->P3c4, 0x2B, 0x4E); - xgifb_reg_set(pVBInfo->P3c4, 0x2C, 0xE9); - b3CC = (unsigned char) inb(XGINew_P3cc); - outb((b3CC |= 0x0C), XGINew_P3cc); - } else if ((ModeNo == 0x04) | (ModeNo == 0x05) | (ModeNo - == 0x0D)) { - xgifb_reg_set(pVBInfo->P3c4, 0x2B, 0x1B); - xgifb_reg_set(pVBInfo->P3c4, 0x2C, 0xE3); - b3CC = (unsigned char) inb(XGINew_P3cc); - outb((b3CC |= 0x0C), XGINew_P3cc); - } - } - if (HwDeviceExtension->jChipType >= XG21) { temp = xgifb_reg_get(pVBInfo->P3d4, 0x38); if (temp & 0xA0) { @@ -7394,7 +6762,7 @@ unsigned char XGISetModeNew(struct xgifb_video_info *xgifb_info, unsigned short ModeIdIndex; struct vb_device_info VBINF; struct vb_device_info *pVBInfo = &VBINF; - pVBInfo->BaseAddr = (unsigned long) HwDeviceExtension->pjIOAddress; + pVBInfo->BaseAddr = xgifb_info->vga_base; pVBInfo->IF_DEF_LVDS = 0; pVBInfo->IF_DEF_LCDA = 1; @@ -7509,13 +6877,8 @@ unsigned char XGISetModeNew(struct xgifb_video_info *xgifb_info, pVBInfo)) return 0; - if (ModeNo <= 0x13) { - pVBInfo->ModeType = pVBInfo->SModeIDTable[ModeIdIndex]. - St_ModeFlag & ModeTypeMask; - } else { - pVBInfo->ModeType = pVBInfo->EModeIDTable[ModeIdIndex]. + pVBInfo->ModeType = pVBInfo->EModeIDTable[ModeIdIndex]. Ext_ModeFlag & ModeTypeMask; - } pVBInfo->SetFlag = 0; pVBInfo->VBInfo = DisableCRT2Display; diff --git a/trunk/drivers/staging/xgifb/vb_struct.h b/trunk/drivers/staging/xgifb/vb_struct.h index a5bd56af92b1..38f47ffc69c4 100644 --- a/trunk/drivers/staging/xgifb/vb_struct.h +++ b/trunk/drivers/staging/xgifb/vb_struct.h @@ -10,28 +10,11 @@ struct XGI_LVDSCRT1VDataStruct { unsigned char Reg[7]; }; -struct XGI_StStruct { - unsigned char St_ModeID; - unsigned short St_ModeFlag; - unsigned char St_StTableIndex; - unsigned char St_CRT2CRTC; - unsigned char St_CRT2CRTC2; - unsigned char St_ResInfo; - unsigned char VB_StTVFlickerIndex; - unsigned char VB_StTVEdgeIndex; - unsigned char VB_StTVYFilterIndex; -}; - struct XGI_ExtStruct { unsigned char Ext_ModeID; unsigned short Ext_ModeFlag; unsigned short Ext_ModeInfo; - unsigned short Ext_Point; - unsigned short Ext_VESAID; - unsigned char Ext_VESAMEMSize; unsigned char Ext_RESINFO; - unsigned char VB_ExtTVFlickerIndex; - unsigned char VB_ExtTVEdgeIndex; unsigned char VB_ExtTVYFilterIndex; unsigned char REFindex; }; @@ -68,14 +51,6 @@ struct XGI_LCDDataTablStruct { unsigned short DATAPTR; }; -struct XGI330_LCDDataDesStruct { - unsigned short LCDHDES; - unsigned short LCDHRS; - unsigned short LCDVDES; - unsigned short LCDVRS; -}; - - struct XGI330_LVDSDataStruct { unsigned short VGAHT; unsigned short VGAVT; @@ -236,7 +211,6 @@ struct vb_device_info { void __iomem *FBAddr; unsigned long BaseAddr; - unsigned long RelIO; unsigned char (*CR6B)[4]; unsigned char (*CR6E)[4]; @@ -314,7 +288,6 @@ struct vb_device_info { struct XGI_TimingHStruct *TimingH; struct XGI_TimingVStruct *TimingV; - struct XGI_StStruct *SModeIDTable; struct SiS_StandTable_S *StandTable; struct XGI_ExtStruct *EModeIDTable; struct XGI_Ext2Struct *RefIndex; diff --git a/trunk/drivers/staging/xgifb/vb_table.h b/trunk/drivers/staging/xgifb/vb_table.h index e8d6f674b274..d22e599cb305 100644 --- a/trunk/drivers/staging/xgifb/vb_table.h +++ b/trunk/drivers/staging/xgifb/vb_table.h @@ -135,609 +135,92 @@ static unsigned char XGI330_SR33; static unsigned char XG40_CRCF = 0x13; static unsigned char XG40_DRAMTypeDefinition = 0xFF ; -static struct XGI_StStruct XGI330_SModeIDTable[] = { - {0x01, 0x9208, 0x01, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00}, - {0x01, 0x1210, 0x14, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00}, - {0x01, 0x1010, 0x17, 0x02, 0x11, 0x00, 0x00, 0x01, 0x01}, - {0x03, 0x8208, 0x03, 0x00, 0x14, 0x00, 0x00, 0x01, 0x02}, - {0x03, 0x0210, 0x16, 0x01, 0x04, 0x01, 0x00, 0x01, 0x02}, - {0x03, 0x0010, 0x18, 0x02, 0x15, 0x00, 0x00, 0x01, 0x03}, - {0x05, 0x9209, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04}, - {0x06, 0x8209, 0x06, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05}, - {0x07, 0x0000, 0x07, 0x03, 0x05, 0x03, 0x00, 0x01, 0x03}, - {0x07, 0x0000, 0x19, 0x02, 0x15, 0x02, 0x00, 0x01, 0x03}, - {0x0d, 0x920a, 0x0d, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04}, - {0x0e, 0x820a, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05}, - {0x0f, 0x0202, 0x11, 0x01, 0x04, 0x01, 0x00, 0x00, 0x05}, - {0x10, 0x0212, 0x12, 0x01, 0x04, 0x01, 0x00, 0x00, 0x05}, - {0x11, 0x0212, 0x1a, 0x04, 0x24, 0x04, 0x00, 0x00, 0x05}, - {0x12, 0x0212, 0x1b, 0x04, 0x24, 0x04, 0x00, 0x00, 0x05}, - {0x13, 0x021b, 0x1c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04}, - {0x12, 0x0010, 0x18, 0x02, 0x24, 0x02, 0x00, 0x00, 0x05},/* St_CRT2CRTC2 - not sure */ - {0x12, 0x0210, 0x18, 0x01, 0x24, 0x01, 0x00, 0x00, 0x05},/* St_CRT2CRTC2 - not sure */ - {0xff, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} -}; - - static struct XGI_ExtStruct XGI330_EModeIDTable[] = { - {0x6a, 0x2212, 0x0407, 0x3a81, 0x0102, 0x08, - 0x07, 0x00, 0x00, 0x07, 0x0e}, - {0x2e, 0x0a1b, 0x0306, 0x3a57, 0x0101, 0x08, - 0x06, 0x00, 0x00, 0x05, 0x06}, - {0x2f, 0x0a1b, 0x0305, 0x3a50, 0x0100, 0x08, - 0x05, 0x00, 0x00, 0x05, 0x05}, - {0x30, 0x2a1b, 0x0407, 0x3a81, 0x0103, 0x08, - 0x07, 0x00, 0x00, 0x07, 0x0e}, - {0x31, 0x0a1b, 0x030d, 0x3b85, 0x0000, 0x08, - 0x0d, 0x00, 0x00, 0x06, 0x3d}, - {0x32, 0x0a1b, 0x0a0e, 0x3b8c, 0x0000, 0x08, - 0x0e, 0x00, 0x00, 0x06, 0x3e}, - {0x33, 0x0a1d, 0x0a0d, 0x3b85, 0x0000, 0x08, - 0x0d, 0x00, 0x00, 0x06, 0x3d}, - {0x34, 0x2a1d, 0x0a0e, 0x3b8c, 0x0000, 0x08, - 0x0e, 0x00, 0x00, 0x06, 0x3e}, - {0x35, 0x0a1f, 0x0a0d, 0x3b85, 0x0000, 0x08, - 0x0d, 0x00, 0x00, 0x06, 0x3d}, - {0x36, 0x2a1f, 0x0a0e, 0x3b8c, 0x0000, 0x08, - 0x0e, 0x00, 0x00, 0x06, 0x3e}, - {0x37, 0x0212, 0x0508, 0x3aab, 0x0104, 0x08, - 0x08, 0x00, 0x00, 0x00, 0x16}, - {0x38, 0x0a1b, 0x0508, 0x3aab, 0x0105, 0x08, - 0x08, 0x00, 0x00, 0x00, 0x16}, - {0x3a, 0x0e3b, 0x0609, 0x3adc, 0x0107, 0x08, - 0x09, 0x00, 0x00, 0x00, 0x1e}, - {0x3c, 0x0e3b, 0x070a, 0x3af2, 0x0130, 0x08, - 0x0a, 0x00, 0x00, 0x00, 0x22}, /* mode 1600x1200 + {0x2e, 0x0a1b, 0x0306, 0x06, 0x05, 0x06}, + {0x2f, 0x0a1b, 0x0305, 0x05, 0x05, 0x05}, + {0x30, 0x2a1b, 0x0407, 0x07, 0x07, 0x0e}, + {0x31, 0x0a1b, 0x030d, 0x0d, 0x06, 0x3d}, + {0x32, 0x0a1b, 0x0a0e, 0x0e, 0x06, 0x3e}, + {0x33, 0x0a1d, 0x0a0d, 0x0d, 0x06, 0x3d}, + {0x34, 0x2a1d, 0x0a0e, 0x0e, 0x06, 0x3e}, + {0x35, 0x0a1f, 0x0a0d, 0x0d, 0x06, 0x3d}, + {0x36, 0x2a1f, 0x0a0e, 0x0e, 0x06, 0x3e}, + {0x38, 0x0a1b, 0x0508, 0x08, 0x00, 0x16}, + {0x3a, 0x0e3b, 0x0609, 0x09, 0x00, 0x1e}, + {0x3c, 0x0e3b, 0x070a, 0x0a, 0x00, 0x22}, /* mode 1600x1200 add CRT2MODE [2003/10/07] */ - {0x3d, 0x0e7d, 0x070a, 0x3af2, 0x0131, 0x08, - 0x0a, 0x00, 0x00, 0x00, 0x22}, /* mode 1600x1200 + {0x3d, 0x0e7d, 0x070a, 0x0a, 0x00, 0x22}, /* mode 1600x1200 add CRT2MODE */ - {0x40, 0x9a1c, 0x0000, 0x3a34, 0x010d, 0x08, - 0x00, 0x00, 0x00, 0x04, 0x00}, - {0x41, 0x9a1d, 0x0000, 0x3a34, 0x010e, 0x08, - 0x00, 0x00, 0x00, 0x04, 0x00}, /* ModeIdIndex = 0x10 */ - {0x43, 0x0a1c, 0x0306, 0x3a57, 0x0110, 0x08, - 0x06, 0x00, 0x00, 0x05, 0x06}, - {0x44, 0x0a1d, 0x0306, 0x3a57, 0x0111, 0x08, - 0x06, 0x00, 0x00, 0x05, 0x06}, - {0x46, 0x2a1c, 0x0407, 0x3a81, 0x0113, 0x08, - 0x07, 0x00, 0x00, 0x07, 0x0e}, - {0x47, 0x2a1d, 0x0407, 0x3a81, 0x0114, 0x08, - 0x07, 0x00, 0x00, 0x07, 0x0e}, - {0x49, 0x0a3c, 0x0508, 0x3aab, 0x0116, 0x08, - 0x08, 0x00, 0x00, 0x00, 0x16}, - {0x4a, 0x0a3d, 0x0508, 0x3aab, 0x0117, 0x08, - 0x08, 0x00, 0x00, 0x00, 0x16}, - {0x4c, 0x0e7c, 0x0609, 0x3adc, 0x0119, 0x08, - 0x09, 0x00, 0x00, 0x00, 0x1e}, - {0x4d, 0x0e7d, 0x0609, 0x3adc, 0x011a, 0x08, - 0x09, 0x00, 0x00, 0x00, 0x1e}, - {0x50, 0x9a1b, 0x0001, 0x3a3b, 0x0132, 0x08, - 0x01, 0x00, 0x00, 0x04, 0x02}, - {0x51, 0xba1b, 0x0103, 0x3a42, 0x0133, 0x08, - 0x03, 0x00, 0x00, 0x07, 0x03}, - {0x52, 0x9a1b, 0x0204, 0x3a49, 0x0134, 0x08, - 0x04, 0x00, 0x00, 0x00, 0x04}, - {0x56, 0x9a1d, 0x0001, 0x3a3b, 0x0135, 0x08, - 0x01, 0x00, 0x00, 0x04, 0x02}, - {0x57, 0xba1d, 0x0103, 0x3a42, 0x0136, 0x08, - 0x03, 0x00, 0x00, 0x07, 0x03}, - {0x58, 0x9a1d, 0x0204, 0x3a49, 0x0137, 0x08, - 0x04, 0x00, 0x00, 0x00, 0x04}, - {0x59, 0x9a1b, 0x0000, 0x3a34, 0x0138, 0x08, - 0x00, 0x00, 0x00, 0x04, 0x00}, - {0x5A, 0x021b, 0x0014, 0x3b83, 0x0138, 0x08, - 0x01, 0x00, 0x00, 0x04, 0x3f}, /* ModeIdIndex = 0x20 */ - {0x5B, 0x0a1d, 0x0014, 0x3b83, 0x0135, 0x08, - 0x01, 0x00, 0x00, 0x04, 0x3f}, - {0x5d, 0x0a1d, 0x0305, 0x3a50, 0x0139, 0x08, - 0x05, 0x00, 0x00, 0x07, 0x05}, - {0x62, 0x0a3f, 0x0306, 0x3a57, 0x013a, 0x08, - 0x06, 0x00, 0x00, 0x05, 0x06}, - {0x63, 0x2a3f, 0x0407, 0x3a81, 0x013b, 0x08, - 0x07, 0x00, 0x00, 0x07, 0x0e}, - {0x64, 0x0a7f, 0x0508, 0x3aab, 0x013c, 0x08, - 0x08, 0x00, 0x00, 0x00, 0x16}, - {0x65, 0x0eff, 0x0609, 0x3adc, 0x013d, 0x08, - 0x09, 0x00, 0x00, 0x00, 0x1e}, - {0x66, 0x0eff, 0x070a, 0x3af2, 0x013e, 0x08, - 0x0a, 0x00, 0x00, 0x00, 0x22}, /* mode 1600x1200 + {0x40, 0x9a1c, 0x0000, 0x00, 0x04, 0x00}, + {0x41, 0x9a1d, 0x0000, 0x00, 0x04, 0x00}, + {0x43, 0x0a1c, 0x0306, 0x06, 0x05, 0x06}, + {0x44, 0x0a1d, 0x0306, 0x06, 0x05, 0x06}, + {0x46, 0x2a1c, 0x0407, 0x07, 0x07, 0x0e}, + {0x47, 0x2a1d, 0x0407, 0x07, 0x07, 0x0e}, + {0x49, 0x0a3c, 0x0508, 0x08, 0x00, 0x16}, + {0x4a, 0x0a3d, 0x0508, 0x08, 0x00, 0x16}, + {0x4c, 0x0e7c, 0x0609, 0x09, 0x00, 0x1e}, + {0x4d, 0x0e7d, 0x0609, 0x09, 0x00, 0x1e}, + {0x50, 0x9a1b, 0x0001, 0x01, 0x04, 0x02}, + {0x51, 0xba1b, 0x0103, 0x03, 0x07, 0x03}, + {0x52, 0x9a1b, 0x0204, 0x04, 0x00, 0x04}, + {0x56, 0x9a1d, 0x0001, 0x01, 0x04, 0x02}, + {0x57, 0xba1d, 0x0103, 0x03, 0x07, 0x03}, + {0x58, 0x9a1d, 0x0204, 0x04, 0x00, 0x04}, + {0x59, 0x9a1b, 0x0000, 0x00, 0x04, 0x00}, + {0x5A, 0x021b, 0x0014, 0x01, 0x04, 0x3f}, + {0x5B, 0x0a1d, 0x0014, 0x01, 0x04, 0x3f}, + {0x5d, 0x0a1d, 0x0305, 0x05, 0x07, 0x05}, + {0x62, 0x0a3f, 0x0306, 0x06, 0x05, 0x06}, + {0x63, 0x2a3f, 0x0407, 0x07, 0x07, 0x0e}, + {0x64, 0x0a7f, 0x0508, 0x08, 0x00, 0x16}, + {0x65, 0x0eff, 0x0609, 0x09, 0x00, 0x1e}, + {0x66, 0x0eff, 0x070a, 0x0a, 0x00, 0x22}, /* mode 1600x1200 add CRT2MODE */ - {0x68, 0x067b, 0x080b, 0x3b17, 0x013f, 0x08, - 0x0b, 0x00, 0x00, 0x00, 0x29}, - {0x69, 0x06fd, 0x080b, 0x3b17, 0x0140, 0x08, - 0x0b, 0x00, 0x00, 0x00, 0x29}, - {0x6b, 0x07ff, 0x080b, 0x3b17, 0x0141, 0x10, - 0x0b, 0x00, 0x00, 0x00, 0x29}, - {0x6c, 0x067b, 0x090c, 0x3b37, 0x0000, 0x08, - 0x0c, 0x00, 0x00, 0x00, 0x2f}, - {0x6d, 0x06fd, 0x090c, 0x3b37, 0x0000, 0x10, - 0x0c, 0x00, 0x00, 0x00, 0x2f}, - {0x6e, 0x07ff, 0x090c, 0x3b37, 0x0000, 0x10, - 0x0c, 0x00, 0x00, 0x00, 0x2f}, - {0x70, 0x2a1b, 0x0410, 0x3b52, 0x0000, 0x08, - 0x10, 0x00, 0x00, 0x07, 0x34}, - {0x71, 0x0a1b, 0x0511, 0x3b63, 0x0000, 0x08, - 0x11, 0x00, 0x00, 0x00, 0x37}, - {0x74, 0x0a1d, 0x0511, 0x3b63, 0x0000, 0x08, - 0x11, 0x00, 0x00, 0x00, 0x37}, /* ModeIdIndex = 0x30 */ - {0x75, 0x0a3d, 0x0612, 0x3b74, 0x0000, 0x08, - 0x12, 0x00, 0x00, 0x00, 0x3a}, - {0x76, 0x2a1f, 0x0410, 0x3b52, 0x0000, 0x08, - 0x10, 0x00, 0x00, 0x07, 0x34}, - {0x77, 0x0a1f, 0x0511, 0x3b63, 0x0000, 0x08, - 0x11, 0x00, 0x00, 0x00, 0x37}, - {0x78, 0x0a3f, 0x0612, 0x3b74, 0x0000, 0x08, - 0x12, 0x00, 0x00, 0x00, 0x3a}, - {0x79, 0x0a3b, 0x0612, 0x3b74, 0x0000, 0x08, - 0x12, 0x00, 0x00, 0x00, 0x3a}, - {0x7a, 0x2a1d, 0x0410, 0x3b52, 0x0000, 0x08, - 0x10, 0x00, 0x00, 0x07, 0x34}, - {0x7b, 0x0e3b, 0x060f, 0x3ad0, 0x0000, 0x08, - 0x0f, 0x00, 0x00, 0x00, 0x1d}, - {0x7c, 0x0e7d, 0x060f, 0x3ad0, 0x0000, 0x08, - 0x0f, 0x00, 0x00, 0x00, 0x1d}, - {0x7d, 0x0eff, 0x060f, 0x3ad0, 0x0000, 0x08, - 0x0f, 0x00, 0x00, 0x00, 0x1d}, - {0x20, 0x0e3b, 0x0D16, 0x49e0, 0x0000, 0x08, - 0x16, 0x00, 0x00, 0x00, 0x43}, - {0x21, 0x0e7d, 0x0D16, 0x49e0, 0x0000, 0x08, - 0x16, 0x00, 0x00, 0x00, 0x43}, - {0x22, 0x0eff, 0x0D16, 0x49e0, 0x0000, 0x08, - 0x16, 0x00, 0x00, 0x00, 0x43}, - {0x23, 0x0e3b, 0x0614, 0x49d5, 0x0000, 0x08, - 0x14, 0x00, 0x00, 0x00, 0x41}, - {0x24, 0x0e7d, 0x0614, 0x49d5, 0x0000, 0x08, - 0x14, 0x00, 0x00, 0x00, 0x41}, - {0x25, 0x0eff, 0x0614, 0x49d5, 0x0000, 0x08, - 0x14, 0x00, 0x00, 0x00, 0x41}, - {0x26, 0x063b, 0x0c15, 0x49dc, 0x0000, 0x08, - 0x15, 0x00, 0x00, 0x00, 0x42}, /* ModeIdIndex = 0x40 */ - {0x27, 0x067d, 0x0c15, 0x49dc, 0x0000, 0x08, - 0x15, 0x00, 0x00, 0x00, 0x42}, - {0x28, 0x06ff, 0x0c15, 0x49dc, 0x0000, 0x08, - 0x15, 0x00, 0x00, 0x00, 0x42}, - {0xff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00} -}; - -static struct SiS_StandTable_S XGI330_StandTable[] = { -/* MD_0_200 */ - { - 0x28, 0x18, 0x08, 0x0800, - {0x09, 0x03, 0x00, 0x02}, - 0x63, - {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, - 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, - 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3, - 0xff}, - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x08, 0x00, 0x0f, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, - 0xff} - }, -/* MD_1_200 */ - { - 0x28, 0x18, 0x08, 0x0800, - {0x09, 0x03, 0x00, 0x02}, - 0x63, - {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, - 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, - 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3, - 0xff}, - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x08, 0x00, 0x0f, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, - 0xff} - }, -/* MD_2_200 */ - { - 0x50, 0x18, 0x08, 0x1000, - {0x01, 0x03, 0x00, 0x02}, - 0x63, - {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, - 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, - 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, - 0xff}, - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x08, 0x00, 0x0f, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, - 0xff} - }, -/* MD_3_200 */ - { - 0x50, 0x18, 0x08, 0x1000, - {0x01, 0x03, 0x00, 0x02}, - 0x63, - {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, - 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, - 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, - 0xff}, - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x08, 0x00, 0x0f, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, - 0xff} - }, -/* MD_4 */ - { - 0x28, 0x18, 0x08, 0x4000, - {0x09, 0x03, 0x00, 0x02}, - 0x63, - {0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, - 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2, - 0xff}, - {0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x01, 0x00, 0x03, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x00, - 0xff} - }, -/* MD_5 */ - { - 0x28, 0x18, 0x08, 0x4000, - {0x09, 0x03, 0x00, 0x02}, - 0x63, - {0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, - 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2, - 0xff}, - {0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x01, 0x00, 0x03, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x00, - 0xff} - }, -/* MD_6 */ - { - 0x50, 0x18, 0x08, 0x4000, - {0x01, 0x01, 0x00, 0x06}, - 0x63, - {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, - 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xc2, - 0xff}, - {0x00, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x01, 0x00, 0x01, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, - 0xff} - }, -/* MD_7 */ - { - 0x50, 0x18, 0x0e, 0x1000, - {0x00, 0x03, 0x00, 0x03}, - 0xa6, - {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, - 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, - 0x83, 0x85, 0x5d, 0x28, 0x0d, 0x63, 0xba, 0xa3, - 0xff}, - {0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x0e, 0x00, 0x0f, 0x08}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00, - 0xff} - }, -/* MDA_DAC */ - { - 0x00, 0x00, 0x00, 0x0000, - {0x00, 0x00, 0x00, 0x15}, - 0x15, - {0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x00, - 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15}, - {0x15, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f} - }, -/* CGA_DAC */ - { - 0x00, 0x10, 0x04, 0x0114, - {0x11, 0x09, 0x15, 0x00}, - 0x10, - {0x04, 0x14, 0x01, 0x11, 0x09, 0x15, 0x2a, 0x3a, - 0x2e, 0x3e, 0x2b, 0x3b, 0x2f, 0x3f, 0x2a, 0x3a, - 0x2e, 0x3e, 0x2b, 0x3b, 0x2f, 0x3f, 0x00, 0x10, - 0x04}, - {0x14, 0x01, 0x11, 0x09, 0x15, 0x00, 0x10, 0x04, - 0x14, 0x01, 0x11, 0x09, 0x15, 0x2a, 0x3a, 0x2e, - 0x3e, 0x2b, 0x3b, 0x2f}, - {0x3f, 0x2a, 0x3a, 0x2e, 0x3e, 0x2b, 0x3b, 0x2f, - 0x3f} - }, -/* EGA_DAC */ - { - 0x00, 0x10, 0x04, 0x0114, - {0x11, 0x05, 0x15, 0x20}, - 0x30, - {0x24, 0x34, 0x21, 0x31, 0x25, 0x35, 0x08, 0x18, - 0x0c, 0x1c, 0x09, 0x19, 0x0d, 0x1d, 0x28, 0x38, - 0x2c, 0x3c, 0x29, 0x39, 0x2d, 0x3d, 0x02, 0x12, - 0x06}, - {0x16, 0x03, 0x13, 0x07, 0x17, 0x22, 0x32, 0x26, - 0x36, 0x23, 0x33, 0x27, 0x37, 0x0a, 0x1a, 0x0e, - 0x1e, 0x0b, 0x1b, 0x0f}, - {0x1f, 0x2a, 0x3a, 0x2e, 0x3e, 0x2b, 0x3b, 0x2f, - 0x3f} - }, -/* VGA_DAC */ - { - 0x00, 0x10, 0x04, 0x0114, - {0x11, 0x09, 0x15, 0x2a}, - 0x3a, - {0x2e, 0x3e, 0x2b, 0x3b, 0x2f, 0x3f, 0x00, 0x05, - 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x18, 0x1c, 0x20, - 0x24, 0x28, 0x2d, 0x32, 0x38, 0x3f, 0x00, 0x10, - 0x1f}, - {0x2f, 0x3f, 0x1f, 0x27, 0x2f, 0x37, 0x3f, 0x2d, - 0x31, 0x36, 0x3a, 0x3f, 0x00, 0x07, 0x0e, 0x15, - 0x1c, 0x0e, 0x11, 0x15}, - {0x18, 0x1c, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x00, - 0x04} - }, - { - 0x08, 0x0c, 0x10, 0x0a08, - {0x0c, 0x0e, 0x10, 0x0b}, - 0x0c, - {0x0d, 0x0f, 0x10, 0x10, 0x01, 0x08, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, 0x01, 0x00, - 0x04, 0x04, 0x01, 0x00, 0x05, 0x02, 0x05, 0x00, - 0x06}, - {0x01, 0x06, 0x05, 0x06, 0x00, 0x08, 0x01, 0x08, - 0x00, 0x07, 0x02, 0x07, 0x06, 0x07, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00} - }, -/* MD_D */ - { - 0x28, 0x18, 0x08, 0x2000, - {0x09, 0x0f, 0x00, 0x06}, - 0x63, - {0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, - 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xe3, - 0xff}, - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x01, 0x00, 0x0f, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, - 0xff} - }, -/* MD_E */ - { - 0x50, 0x18, 0x08, 0x4000, - {0x01, 0x0f, 0x00, 0x06}, - 0x63, - {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, - 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xe3, - 0xff}, - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x01, 0x00, 0x0f, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, - 0xff} - }, + {0x68, 0x067b, 0x080b, 0x0b, 0x00, 0x29}, + {0x69, 0x06fd, 0x080b, 0x0b, 0x00, 0x29}, + {0x6b, 0x07ff, 0x080b, 0x0b, 0x00, 0x29}, + {0x6c, 0x067b, 0x090c, 0x0c, 0x00, 0x2f}, + {0x6d, 0x06fd, 0x090c, 0x0c, 0x00, 0x2f}, + {0x6e, 0x07ff, 0x090c, 0x0c, 0x00, 0x2f}, + {0x70, 0x2a1b, 0x0410, 0x10, 0x07, 0x34}, + {0x71, 0x0a1b, 0x0511, 0x11, 0x00, 0x37}, + {0x74, 0x0a1d, 0x0511, 0x11, 0x00, 0x37}, + {0x75, 0x0a3d, 0x0612, 0x12, 0x00, 0x3a}, + {0x76, 0x2a1f, 0x0410, 0x10, 0x07, 0x34}, + {0x77, 0x0a1f, 0x0511, 0x11, 0x00, 0x37}, + {0x78, 0x0a3f, 0x0612, 0x12, 0x00, 0x3a}, + {0x79, 0x0a3b, 0x0612, 0x12, 0x00, 0x3a}, + {0x7a, 0x2a1d, 0x0410, 0x10, 0x07, 0x34}, + {0x7b, 0x0e3b, 0x060f, 0x0f, 0x00, 0x1d}, + {0x7c, 0x0e7d, 0x060f, 0x0f, 0x00, 0x1d}, + {0x7d, 0x0eff, 0x060f, 0x0f, 0x00, 0x1d}, + {0x20, 0x0e3b, 0x0D16, 0x16, 0x00, 0x43}, + {0x21, 0x0e7d, 0x0D16, 0x16, 0x00, 0x43}, + {0x22, 0x0eff, 0x0D16, 0x16, 0x00, 0x43}, + {0x23, 0x0e3b, 0x0614, 0x14, 0x00, 0x41}, + {0x24, 0x0e7d, 0x0614, 0x14, 0x00, 0x41}, + {0x25, 0x0eff, 0x0614, 0x14, 0x00, 0x41}, + {0x26, 0x063b, 0x0c15, 0x15, 0x00, 0x42}, + {0x27, 0x067d, 0x0c15, 0x15, 0x00, 0x42}, + {0x28, 0x06ff, 0x0c15, 0x15, 0x00, 0x42}, + {0xff, 0x0000, 0x0000, 0x00, 0x00, 0x00} +}; + +static struct SiS_StandTable_S XGI330_StandTable = { /* ExtVGATable */ - { - 0x00, 0x00, 0x00, 0x0000, - {0x01, 0x0f, 0x00, 0x0e}, - 0x23, - {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, - 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3, - 0xff}, - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x01, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, - 0xff} - }, -/* ROM_SAVEPTR */ - { - 0x9f, 0x3b, 0x00, 0x00c0, - {0x00, 0x00, 0x00, 0x00}, - 0x00, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x3f, - 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1a, 0x00, 0xac, 0x3e, 0x00, 0xc0, - 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} - }, -/* MD_F */ - { - 0x50, 0x18, 0x0e, 0x8000, - {0x01, 0x0f, 0x00, 0x06}, - 0xa2, - {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, - 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x82, 0x84, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3, - 0xff}, - {0x00, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, - 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, - 0x0b, 0x00, 0x05, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, - 0xff} - }, -/* MD_10 */ - { - 0x50, 0x18, 0x0e, 0x8000, - {0x01, 0x0f, 0x00, 0x06}, - 0xa3, - {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, - 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x82, 0x84, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3, - 0xff}, - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x01, 0x00, 0x0f, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, - 0xff} - }, -/* MD_0_350 */ - { - 0x28, 0x18, 0x0e, 0x0800, - {0x09, 0x03, 0x00, 0x02}, - 0xa3, - {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xb1, 0xbf, 0x1f, - 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, - 0x83, 0x85, 0x5d, 0x14, 0x1f, 0x63, 0xba, 0xa3, - 0xff}, - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x08, 0x00, 0x0f, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, - 0xff} - }, -/* MD_1_350 */ - { - 0x28, 0x18, 0x0e, 0x0800, - {0x09, 0x03, 0x00, 0x02}, - 0xa3, - {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, - 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, - 0x83, 0x85, 0x5d, 0x14, 0x1f, 0x63, 0xba, 0xa3, - 0xff}, - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x08, 0x00, 0x0f, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, - 0xff} - }, -/* MD_2_350 */ - { - 0x50, 0x18, 0x0e, 0x1000, - {0x01, 0x03, 0x00, 0x02}, - 0xa3, - {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, - 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, - 0x83, 0x85, 0x5d, 0x28, 0x1f, 0x63, 0xba, 0xa3, - 0xff}, - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x08, 0x00, 0x0f, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, - 0xff} - }, -/* MD_3_350 */ - { - 0x50, 0x18, 0x0e, 0x1000, - {0x01, 0x03, 0x00, 0x02}, - 0xa3, - {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, - 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, - 0x83, 0x85, 0x5d, 0x28, 0x1f, 0x63, 0xba, 0xa3, - 0xff}, - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x08, 0x00, 0x0f, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, - 0xff} - }, -/* MD_0_1_400 */ - { - 0x28, 0x18, 0x10, 0x0800, - {0x08, 0x03, 0x00, 0x02}, - 0x67, - {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xb1, 0xbf, 0x1f, - 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, - 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3, - 0xff}, - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x0c, 0x00, 0x0f, 0x08}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, - 0xff} - }, -/* MD_2_3_400 */ - { - 0x50, 0x18, 0x10, 0x1000, - {0x00, 0x03, 0x00, 0x02}, - 0x67, - {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, - 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, - 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, - 0xff}, - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x0c, 0x00, 0x0f, 0x08}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, - 0xff} - }, -/* MD_7_400 */ - { - 0x50, 0x18, 0x10, 0x1000, - {0x00, 0x03, 0x00, 0x02}, - 0x66, - {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, - 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, - 0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3, - 0xff}, - {0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x0e, 0x00, 0x0f, 0x08}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00, - 0xff} - }, -/* MD_11 */ - { - 0x50, 0x1d, 0x10, 0xa000, - {0x01, 0x0f, 0x00, 0x06}, - 0xe3, - {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e, - 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xc3, - 0xff}, - {0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x01, 0x00, 0x0f, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x01, - 0xff} - }, -/* ExtEGATable */ - { - 0x50, 0x1d, 0x10, 0xa000, - {0x01, 0x0f, 0x00, 0x06}, - 0xe3, - {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e, - 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3, - 0xff}, - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x01, 0x00, 0x0f, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, - 0xff} - }, -/* MD_13 */ - { - 0x28, 0x18, 0x08, 0x2000, - {0x01, 0x0f, 0x00, 0x0e}, - 0x63, - {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, - 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x9c, 0x8e, 0x8f, 0x28, 0x40, 0x96, 0xb9, 0xa3, - 0xff}, - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x41, 0x00, 0x0f, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, - 0xff} - } + 0x00, 0x00, 0x00, 0x0000, + {0x01, 0x0f, 0x00, 0x0e}, + 0x23, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x01, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, + 0xff} }; static struct XGI_TimingHStruct XGI_TimingH[1]; @@ -1143,7 +626,7 @@ static struct XGI330_LCDDataStruct XGI_NoScalingDatax75[] = { {1, 1, 1688, 806, 1688, 806} /* ; 0A (1280x768x75Hz) */ }; -static struct XGI330_LCDDataDesStruct XGI_ExtLCDDes1024x768Data[] = { +static struct XGI_LCDDesStruct XGI_ExtLCDDes1024x768Data[] = { {9, 1057, 0, 771}, /* ; 00 (320x200,320x400,640x200,640x400) */ {9, 1057, 0, 771}, /* ; 01 (320x350,640x350) */ {9, 1057, 0, 771}, /* ; 02 (360x400,720x400) */ @@ -1153,7 +636,7 @@ static struct XGI330_LCDDataDesStruct XGI_ExtLCDDes1024x768Data[] = { {9, 1057, 805, 770} /* ; 06 (1024x768x60Hz) */ }; -static struct XGI330_LCDDataDesStruct XGI_StLCDDes1024x768Data[] = { +static struct XGI_LCDDesStruct XGI_StLCDDes1024x768Data[] = { {9, 1057, 737, 703}, /* ; 00 (320x200,320x400,640x200,640x400) */ {9, 1057, 686, 651}, /* ; 01 (320x350,640x350) */ {9, 1057, 737, 703}, /* ; 02 (360x400,720x400) */ @@ -1163,7 +646,7 @@ static struct XGI330_LCDDataDesStruct XGI_StLCDDes1024x768Data[] = { {9, 1057, 805, 770} /* ; 06 (1024x768x60Hz) */ }; -static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1024x768Data[] = { +static struct XGI_LCDDesStruct XGI_CetLCDDes1024x768Data[] = { {1152, 856, 622, 587}, /* ; 00 (320x200,320x400,640x200,640x400) */ {1152, 856, 597, 562}, /* ; 01 (320x350,640x350) */ {1152, 856, 622, 587}, /* ; 02 (360x400,720x400) */ @@ -1173,7 +656,7 @@ static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1024x768Data[] = { {0, 1048, 805, 770} /* ; 06 (1024x768x60Hz) */ }; -static struct XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1280x1024Data[] = { +static struct XGI_LCDDesStruct XGI_ExtLCDDLDes1280x1024Data[] = { {18, 1346, 981, 940}, /* 00 (320x200,320x400,640x200,640x400) */ {18, 1346, 926, 865}, /* 01 (320x350,640x350) */ {18, 1346, 981, 940}, /* 02 (360x400,720x400) */ @@ -1184,7 +667,7 @@ static struct XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1280x1024Data[] = { {18, 1346, 1065, 1024} /* 07 (1280x1024x60Hz) */ }; -static struct XGI330_LCDDataDesStruct XGI_StLCDDLDes1280x1024Data[] = { +static struct XGI_LCDDesStruct XGI_StLCDDLDes1280x1024Data[] = { {18, 1346, 970, 907}, /* 00 (320x200,320x400,640x200,640x400) */ {18, 1346, 917, 854}, /* 01 (320x350,640x350) */ {18, 1346, 970, 907}, /* 02 (360x400,720x400) */ @@ -1195,7 +678,7 @@ static struct XGI330_LCDDataDesStruct XGI_StLCDDLDes1280x1024Data[] = { {18, 1346, 1065, 1024} /* 07 (1280x1024x60Hz) */ }; -static struct XGI330_LCDDataDesStruct XGI_CetLCDDLDes1280x1024Data[] = { +static struct XGI_LCDDesStruct XGI_CetLCDDLDes1280x1024Data[] = { {1368, 1008, 752, 711}, /* 00 (320x200,320x400,640x200,640x400) */ {1368, 1008, 729, 688}, /* 01 (320x350,640x350) */ {1368, 1008, 752, 711}, /* 02 (360x400,720x400) */ @@ -1206,7 +689,7 @@ static struct XGI330_LCDDataDesStruct XGI_CetLCDDLDes1280x1024Data[] = { {18, 1346, 1065, 1024} /* 07 (1280x1024x60Hz) */ }; -static struct XGI330_LCDDataDesStruct XGI_ExtLCDDes1280x1024Data[] = { +static struct XGI_LCDDesStruct XGI_ExtLCDDes1280x1024Data[] = { {9, 1337, 981, 940}, /* ; 00 (320x200,320x400,640x200,640x400) */ {9, 1337, 926, 884}, /* ; 01 (320x350,640x350) alan, 2003/09/30 */ {9, 1337, 981, 940}, /* ; 02 (360x400,720x400) */ @@ -1217,7 +700,7 @@ static struct XGI330_LCDDataDesStruct XGI_ExtLCDDes1280x1024Data[] = { {9, 1337, 1065, 1024} /* ; 07 (1280x1024x60Hz) */ }; -static struct XGI330_LCDDataDesStruct XGI_StLCDDes1280x1024Data[] = { +static struct XGI_LCDDesStruct XGI_StLCDDes1280x1024Data[] = { {9, 1337, 970, 907}, /* ; 00 (320x200,320x400,640x200,640x400) */ {9, 1337, 917, 854}, /* ; 01 (320x350,640x350) */ {9, 1337, 970, 907}, /* ; 02 (360x400,720x400) */ @@ -1228,7 +711,7 @@ static struct XGI330_LCDDataDesStruct XGI_StLCDDes1280x1024Data[] = { {9, 1337, 1065, 1024} /* ; 07 (1280x1024x60Hz) */ }; -static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1280x1024Data[] = { +static struct XGI_LCDDesStruct XGI_CetLCDDes1280x1024Data[] = { {1368, 1008, 752, 711}, /* 00 (320x200,320x400,640x200,640x400) */ {1368, 1008, 729, 688}, /* 01 (320x350,640x350) */ {1368, 1008, 752, 711}, /* 02 (360x400,720x400) */ @@ -1239,7 +722,7 @@ static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1280x1024Data[] = { {9, 1337, 1065, 1024} /* 07 (1280x1024x60Hz) */ }; -static struct XGI330_LCDDataDesStruct xgifb_lcddldes_1400x1050[] = { +static struct XGI_LCDDesStruct xgifb_lcddldes_1400x1050[] = { {18, 1464, 0, 1051}, /* 00 (320x200,320x400,640x200,640x400) */ {18, 1464, 0, 1051}, /* 01 (320x350,640x350) */ {18, 1464, 0, 1051}, /* 02 (360x400,720x400) */ @@ -1251,7 +734,7 @@ static struct XGI330_LCDDataDesStruct xgifb_lcddldes_1400x1050[] = { {18, 1464, 0, 1051} /* 08 (1400x1050x60Hz) */ }; -static struct XGI330_LCDDataDesStruct xgifb_lcddes_1400x1050[] = { +static struct XGI_LCDDesStruct xgifb_lcddes_1400x1050[] = { {9, 1455, 0, 1051}, /* 00 (320x200,320x400,640x200,640x400) */ {9, 1455, 0, 1051}, /* 01 (320x350,640x350) */ {9, 1455, 0, 1051}, /* 02 (360x400,720x400) */ @@ -1263,7 +746,7 @@ static struct XGI330_LCDDataDesStruct xgifb_lcddes_1400x1050[] = { {9, 1455, 0, 1051} /* 08 (1400x1050x60Hz) */ }; -static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1400x1050Data[] = { +static struct XGI_LCDDesStruct XGI_CetLCDDes1400x1050Data[] = { {1308, 1068, 781, 766}, /* 00 (320x200,320x400,640x200,640x400) */ {1308, 1068, 781, 766}, /* 01 (320x350,640x350) */ {1308, 1068, 781, 766}, /* 02 (360x400,720x400) */ @@ -1275,7 +758,7 @@ static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1400x1050Data[] = { {18, 1464, 0, 1051} /* 08 (1400x1050x60Hz) */ }; -static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1400x1050Data2[] = { +static struct XGI_LCDDesStruct XGI_CetLCDDes1400x1050Data2[] = { {0, 1448, 0, 1051}, /* 00 (320x200,320x400,640x200,640x400) */ {0, 1448, 0, 1051}, /* 01 (320x350,640x350) */ {0, 1448, 0, 1051}, /* 02 (360x400,720x400) */ @@ -1283,7 +766,7 @@ static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1400x1050Data2[] = { {0, 1448, 0, 1051} /* 04 (640x480x60Hz) */ }; -static struct XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1600x1200Data[] = { +static struct XGI_LCDDesStruct XGI_ExtLCDDLDes1600x1200Data[] = { {18, 1682, 0, 1201}, /* 00 (320x200,320x400,640x200,640x400) */ {18, 1682, 0, 1201}, /* 01 (320x350,640x350) */ {18, 1682, 0, 1201}, /* 02 (360x400,720x400) */ @@ -1296,7 +779,7 @@ static struct XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1600x1200Data[] = { {18, 1682, 0, 1201} /* 09 (1600x1200x60Hz) */ }; -static struct XGI330_LCDDataDesStruct XGI_StLCDDLDes1600x1200Data[] = { +static struct XGI_LCDDesStruct XGI_StLCDDLDes1600x1200Data[] = { {18, 1682, 1150, 1101}, /* 00 (320x200,320x400,640x200,640x400) */ {18, 1682, 1083, 1034}, /* 01 (320x350,640x350) */ {18, 1682, 1150, 1101}, /* 02 (360x400,720x400) */ @@ -1309,7 +792,7 @@ static struct XGI330_LCDDataDesStruct XGI_StLCDDLDes1600x1200Data[] = { {18, 1682, 0, 1201} /* 09 (1600x1200x60Hz) */ }; -static struct XGI330_LCDDataDesStruct XGI_ExtLCDDes1600x1200Data[] = { +static struct XGI_LCDDesStruct XGI_ExtLCDDes1600x1200Data[] = { {9, 1673, 0, 1201}, /* 00 (320x200,320x400,640x200,640x400) */ {9, 1673, 0, 1201}, /* 01 (320x350,640x350) */ {9, 1673, 0, 1201}, /* 02 (360x400,720x400) */ @@ -1322,7 +805,7 @@ static struct XGI330_LCDDataDesStruct XGI_ExtLCDDes1600x1200Data[] = { {9, 1673, 0, 1201} /* 09 (1600x1200x60Hz) */ }; -static struct XGI330_LCDDataDesStruct XGI_StLCDDes1600x1200Data[] = { +static struct XGI_LCDDesStruct XGI_StLCDDes1600x1200Data[] = { {9, 1673, 1150, 1101}, /* 00 (320x200,320x400,640x200,640x400) */ {9, 1673, 1083, 1034}, /* 01 (320x350,640x350) */ {9, 1673, 1150, 1101}, /* 02 (360x400,720x400) */ @@ -1352,7 +835,7 @@ static struct XGI330_LCDDataDesStruct2 XGI_NoScalingDesData[] = { }; /* ;;1024x768x75Hz */ -static struct XGI330_LCDDataDesStruct xgifb_lcddes_1024x768x75[] = { +static struct XGI_LCDDesStruct xgifb_lcddes_1024x768x75[] = { {9, 1049, 0, 769}, /* ; 00 (320x200,320x400,640x200,640x400) */ {9, 1049, 0, 769}, /* ; 01 (320x350,640x350) */ {9, 1049, 0, 769}, /* ; 02 (360x400,720x400) */ @@ -1363,7 +846,7 @@ static struct XGI330_LCDDataDesStruct xgifb_lcddes_1024x768x75[] = { }; /* ;;1024x768x75Hz */ -static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1024x768x75Data[] = { +static struct XGI_LCDDesStruct XGI_CetLCDDes1024x768x75Data[] = { {1152, 856, 622, 587}, /* ; 00 (320x200,320x400,640x200,640x400) */ {1152, 856, 597, 562}, /* ; 01 (320x350,640x350) */ {1192, 896, 622, 587}, /* ; 02 (360x400,720x400) */ @@ -1374,7 +857,7 @@ static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1024x768x75Data[] = { }; /* ;;1280x1024x75Hz */ -static struct XGI330_LCDDataDesStruct xgifb_lcddldes_1280x1024x75[] = { +static struct XGI_LCDDesStruct xgifb_lcddldes_1280x1024x75[] = { {18, 1314, 0, 1025}, /* ; 00 (320x200,320x400,640x200,640x400) */ {18, 1314, 0, 1025}, /* ; 01 (320x350,640x350) */ {18, 1314, 0, 1025}, /* ; 02 (360x400,720x400) */ @@ -1386,7 +869,7 @@ static struct XGI330_LCDDataDesStruct xgifb_lcddldes_1280x1024x75[] = { }; /* 1280x1024x75Hz */ -static struct XGI330_LCDDataDesStruct XGI_CetLCDDLDes1280x1024x75Data[] = { +static struct XGI_LCDDesStruct XGI_CetLCDDLDes1280x1024x75Data[] = { {1368, 1008, 752, 711}, /* ; 00 (320x200,320x400,640x200,640x400) */ {1368, 1008, 729, 688}, /* ; 01 (320x350,640x350) */ {1408, 1048, 752, 711}, /* ; 02 (360x400,720x400) */ @@ -1398,7 +881,7 @@ static struct XGI330_LCDDataDesStruct XGI_CetLCDDLDes1280x1024x75Data[] = { }; /* ;;1280x1024x75Hz */ -static struct XGI330_LCDDataDesStruct xgifb_lcddes_1280x1024x75[] = { +static struct XGI_LCDDesStruct xgifb_lcddes_1280x1024x75[] = { {9, 1305, 0, 1025}, /* ; 00 (320x200,320x400,640x200,640x400) */ {9, 1305, 0, 1025}, /* ; 01 (320x350,640x350) */ {9, 1305, 0, 1025}, /* ; 02 (360x400,720x400) */ @@ -1410,7 +893,7 @@ static struct XGI330_LCDDataDesStruct xgifb_lcddes_1280x1024x75[] = { }; /* 1280x1024x75Hz */ -static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1280x1024x75Data[] = { +static struct XGI_LCDDesStruct XGI_CetLCDDes1280x1024x75Data[] = { {1368, 1008, 752, 711}, /* ; 00 (320x200,320x400,640x200,640x400) */ {1368, 1008, 729, 688}, /* ; 01 (320x350,640x350) */ {1408, 1048, 752, 711}, /* ; 02 (360x400,720x400) */ diff --git a/trunk/drivers/staging/xgifb/vgatypes.h b/trunk/drivers/staging/xgifb/vgatypes.h index a7208e315815..30cdd1af81f1 100644 --- a/trunk/drivers/staging/xgifb/vgatypes.h +++ b/trunk/drivers/staging/xgifb/vgatypes.h @@ -66,8 +66,6 @@ struct xgi_hw_device_info { unsigned long ulVideoMemorySize; /* size, in bytes, of the memory on the board */ - unsigned char *pjIOAddress; /* base I/O address of VGA ports (0x3B0) */ - unsigned char jChipType; /* Used to Identify Graphics Chip */ /* defined in the data structure type */ /* "XGI_CHIP_TYPE" */ diff --git a/trunk/drivers/staging/zsmalloc/zsmalloc-main.c b/trunk/drivers/staging/zsmalloc/zsmalloc-main.c index 917461c66014..449673773286 100644 --- a/trunk/drivers/staging/zsmalloc/zsmalloc-main.c +++ b/trunk/drivers/staging/zsmalloc/zsmalloc-main.c @@ -45,12 +45,12 @@ static DEFINE_PER_CPU(struct mapping_area, zs_map_area); static int is_first_page(struct page *page) { - return test_bit(PG_private, &page->flags); + return PagePrivate(page); } static int is_last_page(struct page *page) { - return test_bit(PG_private_2, &page->flags); + return PagePrivate2(page); } static void get_zspage_mapping(struct page *page, unsigned int *class_idx, @@ -180,7 +180,7 @@ static enum fullness_group fix_fullness_group(struct zs_pool *pool, * link together 3 PAGE_SIZE sized pages to form a zspage * since then we can perfectly fit in 8 such objects. */ -static int get_zspage_order(int class_size) +static int get_pages_per_zspage(int class_size) { int i, max_usedpc = 0; /* zspage order which gives maximum used size per KB */ @@ -368,7 +368,7 @@ static struct page *alloc_zspage(struct size_class *class, gfp_t flags) * identify the last page. */ error = -ENOMEM; - for (i = 0; i < class->zspage_order; i++) { + for (i = 0; i < class->pages_per_zspage; i++) { struct page *page, *prev_page; page = alloc_page(flags); @@ -377,7 +377,7 @@ static struct page *alloc_zspage(struct size_class *class, gfp_t flags) INIT_LIST_HEAD(&page->lru); if (i == 0) { /* first page */ - set_bit(PG_private, &page->flags); + SetPagePrivate(page); set_page_private(page, 0); first_page = page; first_page->inuse = 0; @@ -388,9 +388,8 @@ static struct page *alloc_zspage(struct size_class *class, gfp_t flags) page->first_page = first_page; if (i >= 2) list_add(&page->lru, &prev_page->lru); - if (i == class->zspage_order - 1) /* last page */ - set_bit(PG_private_2, &page->flags); - + if (i == class->pages_per_zspage - 1) /* last page */ + SetPagePrivate2(page); prev_page = page; } @@ -398,7 +397,7 @@ static struct page *alloc_zspage(struct size_class *class, gfp_t flags) first_page->freelist = obj_location_to_handle(first_page, 0); /* Maximum number of objects we can store in this zspage */ - first_page->objects = class->zspage_order * PAGE_SIZE / class->size; + first_page->objects = class->pages_per_zspage * PAGE_SIZE / class->size; error = 0; /* Success */ @@ -513,7 +512,7 @@ struct zs_pool *zs_create_pool(const char *name, gfp_t flags) class->size = size; class->index = i; spin_lock_init(&class->lock); - class->zspage_order = get_zspage_order(size); + class->pages_per_zspage = get_pages_per_zspage(size); } @@ -567,13 +566,9 @@ EXPORT_SYMBOL_GPL(zs_destroy_pool); * zs_malloc - Allocate block of given size from pool. * @pool: pool to allocate from * @size: size of block to allocate - * @page: page no. that holds the object - * @offset: location of object within page - * - * On success, identifies block allocated - * and 0 is returned. On failure, is set to - * 0 and -ENOMEM is returned. * + * On success, handle to the allocated object is returned, + * otherwise NULL. * Allocation requests with size > ZS_MAX_ALLOC_SIZE will fail. */ void *zs_malloc(struct zs_pool *pool, size_t size) @@ -604,7 +599,7 @@ void *zs_malloc(struct zs_pool *pool, size_t size) set_zspage_mapping(first_page, class->index, ZS_EMPTY); spin_lock(&class->lock); - class->pages_allocated += class->zspage_order; + class->pages_allocated += class->pages_per_zspage; } obj = first_page->freelist; @@ -659,7 +654,7 @@ void zs_free(struct zs_pool *pool, void *obj) fullness = fix_fullness_group(pool, first_page); if (fullness == ZS_EMPTY) - class->pages_allocated -= class->zspage_order; + class->pages_allocated -= class->pages_per_zspage; spin_unlock(&class->lock); @@ -668,6 +663,15 @@ void zs_free(struct zs_pool *pool, void *obj) } EXPORT_SYMBOL_GPL(zs_free); +/** + * zs_map_object - get address of allocated object from handle. + * @pool: pool from which the object was allocated + * @handle: handle returned from zs_malloc + * + * Before using an object allocated from zs_malloc, it must be mapped using + * this function. When done with the object, it must be unmapped using + * zs_unmap_object +*/ void *zs_map_object(struct zs_pool *pool, void *handle) { struct page *page; diff --git a/trunk/drivers/staging/zsmalloc/zsmalloc_int.h b/trunk/drivers/staging/zsmalloc/zsmalloc_int.h index 92eefc663afc..6fd32a9e0315 100644 --- a/trunk/drivers/staging/zsmalloc/zsmalloc_int.h +++ b/trunk/drivers/staging/zsmalloc/zsmalloc_int.h @@ -124,7 +124,7 @@ struct size_class { unsigned int index; /* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */ - int zspage_order; + int pages_per_zspage; spinlock_t lock; diff --git a/trunk/drivers/target/iscsi/iscsi_target.c b/trunk/drivers/target/iscsi/iscsi_target.c index 8b1d5e62ed40..d57d10cb2e47 100644 --- a/trunk/drivers/target/iscsi/iscsi_target.c +++ b/trunk/drivers/target/iscsi/iscsi_target.c @@ -27,8 +27,10 @@ #include #include #include +#include #include #include +#include #include "iscsi_target_core.h" #include "iscsi_target_parameters.h" @@ -593,7 +595,7 @@ static void __exit iscsi_target_cleanup_module(void) kfree(iscsit_global); } -int iscsit_add_reject( +static int iscsit_add_reject( u8 reason, int fail_conn, unsigned char *buf, @@ -622,7 +624,7 @@ int iscsit_add_reject( } spin_lock_bh(&conn->cmd_lock); - list_add_tail(&cmd->i_list, &conn->conn_cmd_list); + list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list); spin_unlock_bh(&conn->cmd_lock); cmd->i_state = ISTATE_SEND_REJECT; @@ -669,7 +671,7 @@ int iscsit_add_reject_from_cmd( if (add_to_conn) { spin_lock_bh(&conn->cmd_lock); - list_add_tail(&cmd->i_list, &conn->conn_cmd_list); + list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list); spin_unlock_bh(&conn->cmd_lock); } @@ -685,9 +687,7 @@ int iscsit_add_reject_from_cmd( /* * Map some portion of the allocated scatterlist to an iovec, suitable for - * kernel sockets to copy data in/out. This handles both pages and slab-allocated - * buffers, since we have been tricky and mapped t_mem_sg to the buffer in - * either case (see iscsit_alloc_buffs) + * kernel sockets to copy data in/out. */ static int iscsit_map_iovec( struct iscsi_cmd *cmd, @@ -700,10 +700,9 @@ static int iscsit_map_iovec( unsigned int page_off; /* - * We have a private mapping of the allocated pages in t_mem_sg. - * At this point, we also know each contains a page. + * We know each entry in t_data_sg contains a page. */ - sg = &cmd->t_mem_sg[data_offset / PAGE_SIZE]; + sg = &cmd->se_cmd.t_data_sg[data_offset / PAGE_SIZE]; page_off = (data_offset % PAGE_SIZE); cmd->first_data_sg = sg; @@ -744,7 +743,7 @@ static void iscsit_ack_from_expstatsn(struct iscsi_conn *conn, u32 exp_statsn) conn->exp_statsn = exp_statsn; spin_lock_bh(&conn->cmd_lock); - list_for_each_entry(cmd, &conn->conn_cmd_list, i_list) { + list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) { spin_lock(&cmd->istate_lock); if ((cmd->i_state == ISTATE_SENT_STATUS) && (cmd->stat_sn < exp_statsn)) { @@ -761,8 +760,7 @@ static void iscsit_ack_from_expstatsn(struct iscsi_conn *conn, u32 exp_statsn) static int iscsit_allocate_iovecs(struct iscsi_cmd *cmd) { - u32 iov_count = (cmd->se_cmd.t_data_nents == 0) ? 1 : - cmd->se_cmd.t_data_nents; + u32 iov_count = max(1UL, DIV_ROUND_UP(cmd->se_cmd.data_length, PAGE_SIZE)); iov_count += ISCSI_IOV_DATA_BUFFER; @@ -776,64 +774,6 @@ static int iscsit_allocate_iovecs(struct iscsi_cmd *cmd) return 0; } -static int iscsit_alloc_buffs(struct iscsi_cmd *cmd) -{ - struct scatterlist *sgl; - u32 length = cmd->se_cmd.data_length; - int nents = DIV_ROUND_UP(length, PAGE_SIZE); - int i = 0, j = 0, ret; - /* - * If no SCSI payload is present, allocate the default iovecs used for - * iSCSI PDU Header - */ - if (!length) - return iscsit_allocate_iovecs(cmd); - - sgl = kzalloc(sizeof(*sgl) * nents, GFP_KERNEL); - if (!sgl) - return -ENOMEM; - - sg_init_table(sgl, nents); - - while (length) { - int buf_size = min_t(int, length, PAGE_SIZE); - struct page *page; - - page = alloc_page(GFP_KERNEL | __GFP_ZERO); - if (!page) - goto page_alloc_failed; - - sg_set_page(&sgl[i], page, buf_size, 0); - - length -= buf_size; - i++; - } - - cmd->t_mem_sg = sgl; - cmd->t_mem_sg_nents = nents; - - /* BIDI ops not supported */ - - /* Tell the core about our preallocated memory */ - transport_generic_map_mem_to_cmd(&cmd->se_cmd, sgl, nents, NULL, 0); - /* - * Allocate iovecs for SCSI payload after transport_generic_map_mem_to_cmd - * so that cmd->se_cmd.t_tasks_se_num has been set. - */ - ret = iscsit_allocate_iovecs(cmd); - if (ret < 0) - return -ENOMEM; - - return 0; - -page_alloc_failed: - while (j < i) - __free_page(sg_page(&sgl[j++])); - - kfree(sgl); - return -ENOMEM; -} - static int iscsit_handle_scsi_cmd( struct iscsi_conn *conn, unsigned char *buf) @@ -842,6 +782,8 @@ static int iscsit_handle_scsi_cmd( int dump_immediate_data = 0, send_check_condition = 0, payload_length; struct iscsi_cmd *cmd = NULL; struct iscsi_scsi_req *hdr; + int iscsi_task_attr; + int sam_task_attr; spin_lock_bh(&conn->sess->session_stats_lock); conn->sess->cmd_pdus++; @@ -958,15 +900,30 @@ static int iscsit_handle_scsi_cmd( (hdr->flags & ISCSI_FLAG_CMD_READ) ? DMA_FROM_DEVICE : DMA_NONE; - cmd = iscsit_allocate_se_cmd(conn, hdr->data_length, data_direction, - (hdr->flags & ISCSI_FLAG_CMD_ATTR_MASK)); + cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); if (!cmd) return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES, 1, - buf, conn); + buf, conn); - pr_debug("Got SCSI Command, ITT: 0x%08x, CmdSN: 0x%08x," - " ExpXferLen: %u, Length: %u, CID: %hu\n", hdr->itt, - hdr->cmdsn, hdr->data_length, payload_length, conn->cid); + cmd->data_direction = data_direction; + iscsi_task_attr = hdr->flags & ISCSI_FLAG_CMD_ATTR_MASK; + /* + * Figure out the SAM Task Attribute for the incoming SCSI CDB + */ + if ((iscsi_task_attr == ISCSI_ATTR_UNTAGGED) || + (iscsi_task_attr == ISCSI_ATTR_SIMPLE)) + sam_task_attr = MSG_SIMPLE_TAG; + else if (iscsi_task_attr == ISCSI_ATTR_ORDERED) + sam_task_attr = MSG_ORDERED_TAG; + else if (iscsi_task_attr == ISCSI_ATTR_HEAD_OF_QUEUE) + sam_task_attr = MSG_HEAD_TAG; + else if (iscsi_task_attr == ISCSI_ATTR_ACA) + sam_task_attr = MSG_ACA_TAG; + else { + pr_debug("Unknown iSCSI Task Attribute: 0x%02x, using" + " MSG_SIMPLE_TAG\n", iscsi_task_attr); + sam_task_attr = MSG_SIMPLE_TAG; + } cmd->iscsi_opcode = ISCSI_OP_SCSI_CMD; cmd->i_state = ISTATE_NEW_CMD; @@ -1002,6 +959,17 @@ static int iscsit_handle_scsi_cmd( iscsit_attach_datain_req(cmd, dr); } + /* + * Initialize struct se_cmd descriptor from target_core_mod infrastructure + */ + transport_init_se_cmd(&cmd->se_cmd, &lio_target_fabric_configfs->tf_ops, + conn->sess->se_sess, hdr->data_length, cmd->data_direction, + sam_task_attr, &cmd->sense_buffer[0]); + + pr_debug("Got SCSI Command, ITT: 0x%08x, CmdSN: 0x%08x," + " ExpXferLen: %u, Length: %u, CID: %hu\n", hdr->itt, + hdr->cmdsn, hdr->data_length, payload_length, conn->cid); + /* * The CDB is going to an se_device_t. */ @@ -1016,13 +984,8 @@ static int iscsit_handle_scsi_cmd( send_check_condition = 1; goto attach_cmd; } - /* - * The Initiator Node has access to the LUN (the addressing method - * is handled inside of iscsit_get_lun_for_cmd()). Now it's time to - * allocate 1->N transport tasks (depending on sector count and - * maximum request size the physical HBA(s) can handle. - */ - transport_ret = transport_generic_allocate_tasks(&cmd->se_cmd, hdr->cdb); + + transport_ret = target_setup_cmd_from_cdb(&cmd->se_cmd, hdr->cdb); if (transport_ret == -ENOMEM) { return iscsit_add_reject_from_cmd( ISCSI_REASON_BOOKMARK_NO_RESOURCES, @@ -1035,9 +998,7 @@ static int iscsit_handle_scsi_cmd( */ send_check_condition = 1; } else { - cmd->data_length = cmd->se_cmd.data_length; - - if (iscsit_decide_list_to_build(cmd, payload_length) < 0) + if (iscsit_build_pdu_and_seq_lists(cmd, payload_length) < 0) return iscsit_add_reject_from_cmd( ISCSI_REASON_BOOKMARK_NO_RESOURCES, 1, 1, buf, cmd); @@ -1045,18 +1006,15 @@ static int iscsit_handle_scsi_cmd( attach_cmd: spin_lock_bh(&conn->cmd_lock); - list_add_tail(&cmd->i_list, &conn->conn_cmd_list); + list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list); spin_unlock_bh(&conn->cmd_lock); /* * Check if we need to delay processing because of ALUA * Active/NonOptimized primary access state.. */ core_alua_check_nonop_delay(&cmd->se_cmd); - /* - * Allocate and setup SGL used with transport_generic_map_mem_to_cmd(). - * also call iscsit_allocate_iovecs() - */ - ret = iscsit_alloc_buffs(cmd); + + ret = iscsit_allocate_iovecs(cmd); if (ret < 0) return iscsit_add_reject_from_cmd( ISCSI_REASON_BOOKMARK_NO_RESOURCES, @@ -1303,10 +1261,10 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf) se_cmd = &cmd->se_cmd; iscsit_mod_dataout_timer(cmd); - if ((hdr->offset + payload_length) > cmd->data_length) { + if ((hdr->offset + payload_length) > cmd->se_cmd.data_length) { pr_err("DataOut Offset: %u, Length %u greater than" " iSCSI Command EDTL %u, protocol error.\n", - hdr->offset, payload_length, cmd->data_length); + hdr->offset, payload_length, cmd->se_cmd.data_length); return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID, 1, 0, buf, cmd); } @@ -1442,7 +1400,7 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf) return 0; else if (ret == DATAOUT_SEND_R2T) { iscsit_set_dataout_sequence_values(cmd); - iscsit_build_r2ts_for_cmd(cmd, conn, 0); + iscsit_build_r2ts_for_cmd(cmd, conn, false); } else if (ret == DATAOUT_SEND_TO_TRANSPORT) { /* * Handle extra special case for out of order @@ -1617,7 +1575,7 @@ static int iscsit_handle_nop_out( * Initiator is expecting a NopIN ping reply, */ spin_lock_bh(&conn->cmd_lock); - list_add_tail(&cmd->i_list, &conn->conn_cmd_list); + list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list); spin_unlock_bh(&conn->cmd_lock); iscsit_ack_from_expstatsn(conn, hdr->exp_statsn); @@ -1723,10 +1681,75 @@ static int iscsit_handle_task_mgt_cmd( (hdr->refcmdsn != ISCSI_RESERVED_TAG)) hdr->refcmdsn = ISCSI_RESERVED_TAG; - cmd = iscsit_allocate_se_cmd_for_tmr(conn, function); + cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); if (!cmd) return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES, - 1, buf, conn); + 1, buf, conn); + + cmd->data_direction = DMA_NONE; + + cmd->tmr_req = kzalloc(sizeof(struct iscsi_tmr_req), GFP_KERNEL); + if (!cmd->tmr_req) { + pr_err("Unable to allocate memory for" + " Task Management command!\n"); + return iscsit_add_reject_from_cmd( + ISCSI_REASON_BOOKMARK_NO_RESOURCES, + 1, 1, buf, cmd); + } + + /* + * TASK_REASSIGN for ERL=2 / connection stays inside of + * LIO-Target $FABRIC_MOD + */ + if (function != ISCSI_TM_FUNC_TASK_REASSIGN) { + + u8 tcm_function; + int ret; + + transport_init_se_cmd(&cmd->se_cmd, + &lio_target_fabric_configfs->tf_ops, + conn->sess->se_sess, 0, DMA_NONE, + MSG_SIMPLE_TAG, &cmd->sense_buffer[0]); + + switch (function) { + case ISCSI_TM_FUNC_ABORT_TASK: + tcm_function = TMR_ABORT_TASK; + break; + case ISCSI_TM_FUNC_ABORT_TASK_SET: + tcm_function = TMR_ABORT_TASK_SET; + break; + case ISCSI_TM_FUNC_CLEAR_ACA: + tcm_function = TMR_CLEAR_ACA; + break; + case ISCSI_TM_FUNC_CLEAR_TASK_SET: + tcm_function = TMR_CLEAR_TASK_SET; + break; + case ISCSI_TM_FUNC_LOGICAL_UNIT_RESET: + tcm_function = TMR_LUN_RESET; + break; + case ISCSI_TM_FUNC_TARGET_WARM_RESET: + tcm_function = TMR_TARGET_WARM_RESET; + break; + case ISCSI_TM_FUNC_TARGET_COLD_RESET: + tcm_function = TMR_TARGET_COLD_RESET; + break; + default: + pr_err("Unknown iSCSI TMR Function:" + " 0x%02x\n", function); + return iscsit_add_reject_from_cmd( + ISCSI_REASON_BOOKMARK_NO_RESOURCES, + 1, 1, buf, cmd); + } + + ret = core_tmr_alloc_req(&cmd->se_cmd, cmd->tmr_req, + tcm_function, GFP_KERNEL); + if (ret < 0) + return iscsit_add_reject_from_cmd( + ISCSI_REASON_BOOKMARK_NO_RESOURCES, + 1, 1, buf, cmd); + + cmd->tmr_req->se_tmr_req = cmd->se_cmd.se_tmr_req; + } cmd->iscsi_opcode = ISCSI_OP_SCSI_TMFUNC; cmd->i_state = ISTATE_SEND_TASKMGTRSP; @@ -1804,7 +1827,7 @@ static int iscsit_handle_task_mgt_cmd( se_tmr->call_transport = 1; attach: spin_lock_bh(&conn->cmd_lock); - list_add_tail(&cmd->i_list, &conn->conn_cmd_list); + list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list); spin_unlock_bh(&conn->cmd_lock); if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) { @@ -1980,7 +2003,7 @@ static int iscsit_handle_text_cmd( cmd->data_direction = DMA_NONE; spin_lock_bh(&conn->cmd_lock); - list_add_tail(&cmd->i_list, &conn->conn_cmd_list); + list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list); spin_unlock_bh(&conn->cmd_lock); iscsit_ack_from_expstatsn(conn, hdr->exp_statsn); @@ -2168,7 +2191,7 @@ static int iscsit_handle_logout_cmd( logout_remove = 1; spin_lock_bh(&conn->cmd_lock); - list_add_tail(&cmd->i_list, &conn->conn_cmd_list); + list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list); spin_unlock_bh(&conn->cmd_lock); if (reason_code != ISCSI_LOGOUT_REASON_RECOVERY) @@ -2178,7 +2201,7 @@ static int iscsit_handle_logout_cmd( * Immediate commands are executed, well, immediately. * Non-Immediate Logout Commands are executed in CmdSN order. */ - if (hdr->opcode & ISCSI_OP_IMMEDIATE) { + if (cmd->immediate_cmd) { int ret = iscsit_execute_cmd(cmd, 0); if (ret < 0) @@ -2336,7 +2359,7 @@ static int iscsit_handle_immediate_data( cmd->write_data_done += length; - if (cmd->write_data_done == cmd->data_length) { + if (cmd->write_data_done == cmd->se_cmd.data_length) { spin_lock_bh(&cmd->istate_lock); cmd->cmd_flags |= ICF_GOT_LAST_DATAOUT; cmd->i_state = ISTATE_RECEIVED_LAST_DATAOUT; @@ -2381,7 +2404,7 @@ static void iscsit_build_conn_drop_async_message(struct iscsi_conn *conn) cmd->i_state = ISTATE_SEND_ASYNCMSG; spin_lock_bh(&conn_p->cmd_lock); - list_add_tail(&cmd->i_list, &conn_p->conn_cmd_list); + list_add_tail(&cmd->i_conn_node, &conn_p->conn_cmd_list); spin_unlock_bh(&conn_p->cmd_lock); iscsit_add_cmd_to_response_queue(cmd, conn_p, cmd->i_state); @@ -2434,10 +2457,19 @@ static int iscsit_send_conn_drop_async_message( return 0; } +static void iscsit_tx_thread_wait_for_tcp(struct iscsi_conn *conn) +{ + if ((conn->sock->sk->sk_shutdown & SEND_SHUTDOWN) || + (conn->sock->sk->sk_shutdown & RCV_SHUTDOWN)) { + wait_for_completion_interruptible_timeout( + &conn->tx_half_close_comp, + ISCSI_TX_THREAD_TCP_TIMEOUT * HZ); + } +} + static int iscsit_send_data_in( struct iscsi_cmd *cmd, - struct iscsi_conn *conn, - int *eodr) + struct iscsi_conn *conn) { int iov_ret = 0, set_statsn = 0; u32 iov_count = 0, tx_size = 0; @@ -2445,6 +2477,8 @@ static int iscsit_send_data_in( struct iscsi_datain_req *dr; struct iscsi_data_rsp *hdr; struct kvec *iov; + int eodr = 0; + int ret; memset(&datain, 0, sizeof(struct iscsi_datain)); dr = iscsit_get_datain_values(cmd, &datain); @@ -2457,11 +2491,11 @@ static int iscsit_send_data_in( /* * Be paranoid and double check the logic for now. */ - if ((datain.offset + datain.length) > cmd->data_length) { + if ((datain.offset + datain.length) > cmd->se_cmd.data_length) { pr_err("Command ITT: 0x%08x, datain.offset: %u and" " datain.length: %u exceeds cmd->data_length: %u\n", cmd->init_task_tag, datain.offset, datain.length, - cmd->data_length); + cmd->se_cmd.data_length); return -1; } @@ -2577,13 +2611,26 @@ static int iscsit_send_data_in( cmd->init_task_tag, ntohl(hdr->statsn), ntohl(hdr->datasn), ntohl(hdr->offset), datain.length, conn->cid); + /* sendpage is preferred but can't insert markers */ + if (!conn->conn_ops->IFMarker) + ret = iscsit_fe_sendpage_sg(cmd, conn); + else + ret = iscsit_send_tx_data(cmd, conn, 0); + + iscsit_unmap_iovec(cmd); + + if (ret < 0) { + iscsit_tx_thread_wait_for_tcp(conn); + return ret; + } + if (dr->dr_complete) { - *eodr = (cmd->se_cmd.se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) ? + eodr = (cmd->se_cmd.se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) ? 2 : 1; iscsit_free_datain_req(cmd, dr); } - return 0; + return eodr; } static int iscsit_send_logout_response( @@ -2715,6 +2762,7 @@ static int iscsit_send_unsolicited_nopin( { int tx_size = ISCSI_HDR_LEN; struct iscsi_nopin *hdr; + int ret; hdr = (struct iscsi_nopin *) cmd->pdu; memset(hdr, 0, ISCSI_HDR_LEN); @@ -2747,6 +2795,17 @@ static int iscsit_send_unsolicited_nopin( pr_debug("Sending Unsolicited NOPIN TTT: 0x%08x StatSN:" " 0x%08x CID: %hu\n", hdr->ttt, cmd->stat_sn, conn->cid); + ret = iscsit_send_tx_data(cmd, conn, 1); + if (ret < 0) { + iscsit_tx_thread_wait_for_tcp(conn); + return ret; + } + + spin_lock_bh(&cmd->istate_lock); + cmd->i_state = want_response ? + ISTATE_SENT_NOPIN_WANT_RESPONSE : ISTATE_SENT_STATUS; + spin_unlock_bh(&cmd->istate_lock); + return 0; } @@ -2837,13 +2896,14 @@ static int iscsit_send_nopin_response( return 0; } -int iscsit_send_r2t( +static int iscsit_send_r2t( struct iscsi_cmd *cmd, struct iscsi_conn *conn) { int tx_size = 0; struct iscsi_r2t *r2t; struct iscsi_r2t_rsp *hdr; + int ret; r2t = iscsit_get_r2t_from_list(cmd); if (!r2t) @@ -2899,19 +2959,27 @@ int iscsit_send_r2t( r2t->sent_r2t = 1; spin_unlock_bh(&cmd->r2t_lock); + ret = iscsit_send_tx_data(cmd, conn, 1); + if (ret < 0) { + iscsit_tx_thread_wait_for_tcp(conn); + return ret; + } + + spin_lock_bh(&cmd->dataout_timeout_lock); + iscsit_start_dataout_timer(cmd, conn); + spin_unlock_bh(&cmd->dataout_timeout_lock); + return 0; } /* - * type 0: Normal Operation. - * type 1: Called from Storage Transport. - * type 2: Called from iscsi_task_reassign_complete_write() for - * connection recovery. + * @recovery: If called from iscsi_task_reassign_complete_write() for + * connection recovery. */ int iscsit_build_r2ts_for_cmd( struct iscsi_cmd *cmd, struct iscsi_conn *conn, - int type) + bool recovery) { int first_r2t = 1; u32 offset = 0, xfer_len = 0; @@ -2922,32 +2990,37 @@ int iscsit_build_r2ts_for_cmd( return 0; } - if (conn->sess->sess_ops->DataSequenceInOrder && (type != 2)) - if (cmd->r2t_offset < cmd->write_data_done) - cmd->r2t_offset = cmd->write_data_done; + if (conn->sess->sess_ops->DataSequenceInOrder && + !recovery) + cmd->r2t_offset = max(cmd->r2t_offset, cmd->write_data_done); while (cmd->outstanding_r2ts < conn->sess->sess_ops->MaxOutstandingR2T) { if (conn->sess->sess_ops->DataSequenceInOrder) { offset = cmd->r2t_offset; - if (first_r2t && (type == 2)) { - xfer_len = ((offset + - (conn->sess->sess_ops->MaxBurstLength - - cmd->next_burst_len) > - cmd->data_length) ? - (cmd->data_length - offset) : - (conn->sess->sess_ops->MaxBurstLength - - cmd->next_burst_len)); + if (first_r2t && recovery) { + int new_data_end = offset + + conn->sess->sess_ops->MaxBurstLength - + cmd->next_burst_len; + + if (new_data_end > cmd->se_cmd.data_length) + xfer_len = cmd->se_cmd.data_length - offset; + else + xfer_len = + conn->sess->sess_ops->MaxBurstLength - + cmd->next_burst_len; } else { - xfer_len = ((offset + - conn->sess->sess_ops->MaxBurstLength) > - cmd->data_length) ? - (cmd->data_length - offset) : - conn->sess->sess_ops->MaxBurstLength; + int new_data_end = offset + + conn->sess->sess_ops->MaxBurstLength; + + if (new_data_end > cmd->se_cmd.data_length) + xfer_len = cmd->se_cmd.data_length - offset; + else + xfer_len = conn->sess->sess_ops->MaxBurstLength; } cmd->r2t_offset += xfer_len; - if (cmd->r2t_offset == cmd->data_length) + if (cmd->r2t_offset == cmd->se_cmd.data_length) cmd->cmd_flags |= ICF_SENT_LAST_R2T; } else { struct iscsi_seq *seq; @@ -3179,6 +3252,8 @@ static bool iscsit_check_inaddr_any(struct iscsi_np *np) return ret; } +#define SENDTARGETS_BUF_LIMIT 32768U + static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd) { char *payload = NULL; @@ -3187,12 +3262,10 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd) struct iscsi_tiqn *tiqn; struct iscsi_tpg_np *tpg_np; int buffer_len, end_of_buf = 0, len = 0, payload_len = 0; - unsigned char buf[256]; + unsigned char buf[ISCSI_IQN_LEN+12]; /* iqn + "TargetName=" + \0 */ - buffer_len = (conn->conn_ops->MaxRecvDataSegmentLength > 32768) ? - 32768 : conn->conn_ops->MaxRecvDataSegmentLength; - - memset(buf, 0, 256); + buffer_len = max(conn->conn_ops->MaxRecvDataSegmentLength, + SENDTARGETS_BUF_LIMIT); payload = kzalloc(buffer_len, GFP_KERNEL); if (!payload) { @@ -3408,18 +3481,6 @@ static int iscsit_send_reject( return 0; } -static void iscsit_tx_thread_wait_for_tcp(struct iscsi_conn *conn) -{ - if ((conn->sock->sk->sk_shutdown & SEND_SHUTDOWN) || - (conn->sock->sk->sk_shutdown & RCV_SHUTDOWN)) { - wait_for_completion_interruptible_timeout( - &conn->tx_half_close_comp, - ISCSI_TX_THREAD_TCP_TIMEOUT * HZ); - } -} - -#ifdef CONFIG_SMP - void iscsit_thread_get_cpumask(struct iscsi_conn *conn) { struct iscsi_thread_set *ts = conn->thread_set; @@ -3433,10 +3494,6 @@ void iscsit_thread_get_cpumask(struct iscsi_conn *conn) * execute upon. */ ord = ts->thread_id % cpumask_weight(cpu_online_mask); -#if 0 - pr_debug(">>>>>>>>>>>>>>>>>>>> Generated ord: %d from" - " thread_id: %d\n", ord, ts->thread_id); -#endif for_each_online_cpu(cpu) { if (ord-- == 0) { cpumask_set_cpu(cpu, conn->conn_cpumask); @@ -3476,34 +3533,196 @@ static inline void iscsit_thread_check_cpumask( */ memset(buf, 0, 128); cpumask_scnprintf(buf, 128, conn->conn_cpumask); -#if 0 - pr_debug(">>>>>>>>>>>>>> Calling set_cpus_allowed_ptr():" - " %s for %s\n", buf, p->comm); -#endif set_cpus_allowed_ptr(p, conn->conn_cpumask); } -#else - -void iscsit_thread_get_cpumask(struct iscsi_conn *conn) +static int handle_immediate_queue(struct iscsi_conn *conn) { - return; + struct iscsi_queue_req *qr; + struct iscsi_cmd *cmd; + u8 state; + int ret; + + while ((qr = iscsit_get_cmd_from_immediate_queue(conn))) { + atomic_set(&conn->check_immediate_queue, 0); + cmd = qr->cmd; + state = qr->state; + kmem_cache_free(lio_qr_cache, qr); + + switch (state) { + case ISTATE_SEND_R2T: + ret = iscsit_send_r2t(cmd, conn); + if (ret < 0) + goto err; + break; + case ISTATE_REMOVE: + if (cmd->data_direction == DMA_TO_DEVICE) + iscsit_stop_dataout_timer(cmd); + + spin_lock_bh(&conn->cmd_lock); + list_del(&cmd->i_conn_node); + spin_unlock_bh(&conn->cmd_lock); + + iscsit_free_cmd(cmd); + continue; + case ISTATE_SEND_NOPIN_WANT_RESPONSE: + iscsit_mod_nopin_response_timer(conn); + ret = iscsit_send_unsolicited_nopin(cmd, + conn, 1); + if (ret < 0) + goto err; + break; + case ISTATE_SEND_NOPIN_NO_RESPONSE: + ret = iscsit_send_unsolicited_nopin(cmd, + conn, 0); + if (ret < 0) + goto err; + break; + default: + pr_err("Unknown Opcode: 0x%02x ITT:" + " 0x%08x, i_state: %d on CID: %hu\n", + cmd->iscsi_opcode, cmd->init_task_tag, state, + conn->cid); + goto err; + } + } + + return 0; + +err: + return -1; } -#define iscsit_thread_check_cpumask(X, Y, Z) ({}) -#endif /* CONFIG_SMP */ +static int handle_response_queue(struct iscsi_conn *conn) +{ + struct iscsi_queue_req *qr; + struct iscsi_cmd *cmd; + u8 state; + int ret; + + while ((qr = iscsit_get_cmd_from_response_queue(conn))) { + cmd = qr->cmd; + state = qr->state; + kmem_cache_free(lio_qr_cache, qr); + +check_rsp_state: + switch (state) { + case ISTATE_SEND_DATAIN: + ret = iscsit_send_data_in(cmd, conn); + if (ret < 0) + goto err; + else if (!ret) + /* more drs */ + goto check_rsp_state; + else if (ret == 1) { + /* all done */ + spin_lock_bh(&cmd->istate_lock); + cmd->i_state = ISTATE_SENT_STATUS; + spin_unlock_bh(&cmd->istate_lock); + continue; + } else if (ret == 2) { + /* Still must send status, + SCF_TRANSPORT_TASK_SENSE was set */ + spin_lock_bh(&cmd->istate_lock); + cmd->i_state = ISTATE_SEND_STATUS; + spin_unlock_bh(&cmd->istate_lock); + state = ISTATE_SEND_STATUS; + goto check_rsp_state; + } + + break; + case ISTATE_SEND_STATUS: + case ISTATE_SEND_STATUS_RECOVERY: + ret = iscsit_send_status(cmd, conn); + break; + case ISTATE_SEND_LOGOUTRSP: + ret = iscsit_send_logout_response(cmd, conn); + break; + case ISTATE_SEND_ASYNCMSG: + ret = iscsit_send_conn_drop_async_message( + cmd, conn); + break; + case ISTATE_SEND_NOPIN: + ret = iscsit_send_nopin_response(cmd, conn); + break; + case ISTATE_SEND_REJECT: + ret = iscsit_send_reject(cmd, conn); + break; + case ISTATE_SEND_TASKMGTRSP: + ret = iscsit_send_task_mgt_rsp(cmd, conn); + if (ret != 0) + break; + ret = iscsit_tmr_post_handler(cmd, conn); + if (ret != 0) + iscsit_fall_back_to_erl0(conn->sess); + break; + case ISTATE_SEND_TEXTRSP: + ret = iscsit_send_text_rsp(cmd, conn); + break; + default: + pr_err("Unknown Opcode: 0x%02x ITT:" + " 0x%08x, i_state: %d on CID: %hu\n", + cmd->iscsi_opcode, cmd->init_task_tag, + state, conn->cid); + goto err; + } + if (ret < 0) + goto err; + + if (iscsit_send_tx_data(cmd, conn, 1) < 0) { + iscsit_tx_thread_wait_for_tcp(conn); + iscsit_unmap_iovec(cmd); + goto err; + } + iscsit_unmap_iovec(cmd); + + switch (state) { + case ISTATE_SEND_LOGOUTRSP: + if (!iscsit_logout_post_handler(cmd, conn)) + goto restart; + /* fall through */ + case ISTATE_SEND_STATUS: + case ISTATE_SEND_ASYNCMSG: + case ISTATE_SEND_NOPIN: + case ISTATE_SEND_STATUS_RECOVERY: + case ISTATE_SEND_TEXTRSP: + case ISTATE_SEND_TASKMGTRSP: + spin_lock_bh(&cmd->istate_lock); + cmd->i_state = ISTATE_SENT_STATUS; + spin_unlock_bh(&cmd->istate_lock); + break; + case ISTATE_SEND_REJECT: + if (cmd->cmd_flags & ICF_REJECT_FAIL_CONN) { + cmd->cmd_flags &= ~ICF_REJECT_FAIL_CONN; + complete(&cmd->reject_comp); + goto err; + } + complete(&cmd->reject_comp); + break; + default: + pr_err("Unknown Opcode: 0x%02x ITT:" + " 0x%08x, i_state: %d on CID: %hu\n", + cmd->iscsi_opcode, cmd->init_task_tag, + cmd->i_state, conn->cid); + goto err; + } + + if (atomic_read(&conn->check_immediate_queue)) + break; + } + + return 0; + +err: + return -1; +restart: + return -EAGAIN; +} int iscsi_target_tx_thread(void *arg) { - u8 state; - int eodr = 0; int ret = 0; - int sent_status = 0; - int use_misc = 0; - int map_sg = 0; - struct iscsi_cmd *cmd = NULL; struct iscsi_conn *conn; - struct iscsi_queue_req *qr = NULL; struct iscsi_thread_set *ts = arg; /* * Allow ourselves to be interrupted by SIGINT so that a @@ -3516,7 +3735,7 @@ int iscsi_target_tx_thread(void *arg) if (!conn) goto out; - eodr = map_sg = ret = sent_status = use_misc = 0; + ret = 0; while (!kthread_should_stop()) { /* @@ -3531,251 +3750,15 @@ int iscsi_target_tx_thread(void *arg) signal_pending(current)) goto transport_err; -get_immediate: - qr = iscsit_get_cmd_from_immediate_queue(conn); - if (qr) { - atomic_set(&conn->check_immediate_queue, 0); - cmd = qr->cmd; - state = qr->state; - kmem_cache_free(lio_qr_cache, qr); - - spin_lock_bh(&cmd->istate_lock); - switch (state) { - case ISTATE_SEND_R2T: - spin_unlock_bh(&cmd->istate_lock); - ret = iscsit_send_r2t(cmd, conn); - break; - case ISTATE_REMOVE: - spin_unlock_bh(&cmd->istate_lock); - - if (cmd->data_direction == DMA_TO_DEVICE) - iscsit_stop_dataout_timer(cmd); - - spin_lock_bh(&conn->cmd_lock); - list_del(&cmd->i_list); - spin_unlock_bh(&conn->cmd_lock); - - iscsit_free_cmd(cmd); - goto get_immediate; - case ISTATE_SEND_NOPIN_WANT_RESPONSE: - spin_unlock_bh(&cmd->istate_lock); - iscsit_mod_nopin_response_timer(conn); - ret = iscsit_send_unsolicited_nopin(cmd, - conn, 1); - break; - case ISTATE_SEND_NOPIN_NO_RESPONSE: - spin_unlock_bh(&cmd->istate_lock); - ret = iscsit_send_unsolicited_nopin(cmd, - conn, 0); - break; - default: - pr_err("Unknown Opcode: 0x%02x ITT:" - " 0x%08x, i_state: %d on CID: %hu\n", - cmd->iscsi_opcode, cmd->init_task_tag, state, - conn->cid); - spin_unlock_bh(&cmd->istate_lock); - goto transport_err; - } - if (ret < 0) { - conn->tx_immediate_queue = 0; - goto transport_err; - } - - if (iscsit_send_tx_data(cmd, conn, 1) < 0) { - conn->tx_immediate_queue = 0; - iscsit_tx_thread_wait_for_tcp(conn); - goto transport_err; - } - - spin_lock_bh(&cmd->istate_lock); - switch (state) { - case ISTATE_SEND_R2T: - spin_unlock_bh(&cmd->istate_lock); - spin_lock_bh(&cmd->dataout_timeout_lock); - iscsit_start_dataout_timer(cmd, conn); - spin_unlock_bh(&cmd->dataout_timeout_lock); - break; - case ISTATE_SEND_NOPIN_WANT_RESPONSE: - cmd->i_state = ISTATE_SENT_NOPIN_WANT_RESPONSE; - spin_unlock_bh(&cmd->istate_lock); - break; - case ISTATE_SEND_NOPIN_NO_RESPONSE: - cmd->i_state = ISTATE_SENT_STATUS; - spin_unlock_bh(&cmd->istate_lock); - break; - default: - pr_err("Unknown Opcode: 0x%02x ITT:" - " 0x%08x, i_state: %d on CID: %hu\n", - cmd->iscsi_opcode, cmd->init_task_tag, - state, conn->cid); - spin_unlock_bh(&cmd->istate_lock); - goto transport_err; - } - goto get_immediate; - } else - conn->tx_immediate_queue = 0; - -get_response: - qr = iscsit_get_cmd_from_response_queue(conn); - if (qr) { - cmd = qr->cmd; - state = qr->state; - kmem_cache_free(lio_qr_cache, qr); - - spin_lock_bh(&cmd->istate_lock); -check_rsp_state: - switch (state) { - case ISTATE_SEND_DATAIN: - spin_unlock_bh(&cmd->istate_lock); - ret = iscsit_send_data_in(cmd, conn, - &eodr); - map_sg = 1; - break; - case ISTATE_SEND_STATUS: - case ISTATE_SEND_STATUS_RECOVERY: - spin_unlock_bh(&cmd->istate_lock); - use_misc = 1; - ret = iscsit_send_status(cmd, conn); - break; - case ISTATE_SEND_LOGOUTRSP: - spin_unlock_bh(&cmd->istate_lock); - use_misc = 1; - ret = iscsit_send_logout_response(cmd, conn); - break; - case ISTATE_SEND_ASYNCMSG: - spin_unlock_bh(&cmd->istate_lock); - use_misc = 1; - ret = iscsit_send_conn_drop_async_message( - cmd, conn); - break; - case ISTATE_SEND_NOPIN: - spin_unlock_bh(&cmd->istate_lock); - use_misc = 1; - ret = iscsit_send_nopin_response(cmd, conn); - break; - case ISTATE_SEND_REJECT: - spin_unlock_bh(&cmd->istate_lock); - use_misc = 1; - ret = iscsit_send_reject(cmd, conn); - break; - case ISTATE_SEND_TASKMGTRSP: - spin_unlock_bh(&cmd->istate_lock); - use_misc = 1; - ret = iscsit_send_task_mgt_rsp(cmd, conn); - if (ret != 0) - break; - ret = iscsit_tmr_post_handler(cmd, conn); - if (ret != 0) - iscsit_fall_back_to_erl0(conn->sess); - break; - case ISTATE_SEND_TEXTRSP: - spin_unlock_bh(&cmd->istate_lock); - use_misc = 1; - ret = iscsit_send_text_rsp(cmd, conn); - break; - default: - pr_err("Unknown Opcode: 0x%02x ITT:" - " 0x%08x, i_state: %d on CID: %hu\n", - cmd->iscsi_opcode, cmd->init_task_tag, - state, conn->cid); - spin_unlock_bh(&cmd->istate_lock); - goto transport_err; - } - if (ret < 0) { - conn->tx_response_queue = 0; - goto transport_err; - } - - if (map_sg && !conn->conn_ops->IFMarker) { - if (iscsit_fe_sendpage_sg(cmd, conn) < 0) { - conn->tx_response_queue = 0; - iscsit_tx_thread_wait_for_tcp(conn); - iscsit_unmap_iovec(cmd); - goto transport_err; - } - } else { - if (iscsit_send_tx_data(cmd, conn, use_misc) < 0) { - conn->tx_response_queue = 0; - iscsit_tx_thread_wait_for_tcp(conn); - iscsit_unmap_iovec(cmd); - goto transport_err; - } - } - map_sg = 0; - iscsit_unmap_iovec(cmd); - - spin_lock_bh(&cmd->istate_lock); - switch (state) { - case ISTATE_SEND_DATAIN: - if (!eodr) - goto check_rsp_state; - - if (eodr == 1) { - cmd->i_state = ISTATE_SENT_LAST_DATAIN; - sent_status = 1; - eodr = use_misc = 0; - } else if (eodr == 2) { - cmd->i_state = state = - ISTATE_SEND_STATUS; - sent_status = 0; - eodr = use_misc = 0; - goto check_rsp_state; - } - break; - case ISTATE_SEND_STATUS: - use_misc = 0; - sent_status = 1; - break; - case ISTATE_SEND_ASYNCMSG: - case ISTATE_SEND_NOPIN: - case ISTATE_SEND_STATUS_RECOVERY: - case ISTATE_SEND_TEXTRSP: - use_misc = 0; - sent_status = 1; - break; - case ISTATE_SEND_REJECT: - use_misc = 0; - if (cmd->cmd_flags & ICF_REJECT_FAIL_CONN) { - cmd->cmd_flags &= ~ICF_REJECT_FAIL_CONN; - spin_unlock_bh(&cmd->istate_lock); - complete(&cmd->reject_comp); - goto transport_err; - } - complete(&cmd->reject_comp); - break; - case ISTATE_SEND_TASKMGTRSP: - use_misc = 0; - sent_status = 1; - break; - case ISTATE_SEND_LOGOUTRSP: - spin_unlock_bh(&cmd->istate_lock); - if (!iscsit_logout_post_handler(cmd, conn)) - goto restart; - spin_lock_bh(&cmd->istate_lock); - use_misc = 0; - sent_status = 1; - break; - default: - pr_err("Unknown Opcode: 0x%02x ITT:" - " 0x%08x, i_state: %d on CID: %hu\n", - cmd->iscsi_opcode, cmd->init_task_tag, - cmd->i_state, conn->cid); - spin_unlock_bh(&cmd->istate_lock); - goto transport_err; - } - - if (sent_status) { - cmd->i_state = ISTATE_SENT_STATUS; - sent_status = 0; - } - spin_unlock_bh(&cmd->istate_lock); - - if (atomic_read(&conn->check_immediate_queue)) - goto get_immediate; + ret = handle_immediate_queue(conn); + if (ret < 0) + goto transport_err; - goto get_response; - } else - conn->tx_response_queue = 0; + ret = handle_response_queue(conn); + if (ret == -EAGAIN) + goto restart; + else if (ret < 0) + goto transport_err; } transport_err: @@ -3952,9 +3935,9 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn) * has been reset -> returned sleeping pre-handler state. */ spin_lock_bh(&conn->cmd_lock); - list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_list) { + list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_conn_node) { - list_del(&cmd->i_list); + list_del(&cmd->i_conn_node); spin_unlock_bh(&conn->cmd_lock); iscsit_increment_maxcmdsn(cmd, sess); @@ -3972,7 +3955,7 @@ static void iscsit_stop_timers_for_cmds( struct iscsi_cmd *cmd; spin_lock_bh(&conn->cmd_lock); - list_for_each_entry(cmd, &conn->conn_cmd_list, i_list) { + list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) { if (cmd->data_direction == DMA_TO_DEVICE) iscsit_stop_dataout_timer(cmd); } diff --git a/trunk/drivers/target/iscsi/iscsi_target.h b/trunk/drivers/target/iscsi/iscsi_target.h index 5db2ddeed5eb..12abb4c9e34e 100644 --- a/trunk/drivers/target/iscsi/iscsi_target.h +++ b/trunk/drivers/target/iscsi/iscsi_target.h @@ -18,8 +18,7 @@ extern int iscsit_logout_closesession(struct iscsi_cmd *, struct iscsi_conn *); extern int iscsit_logout_closeconnection(struct iscsi_cmd *, struct iscsi_conn *); extern int iscsit_logout_removeconnforrecovery(struct iscsi_cmd *, struct iscsi_conn *); extern int iscsit_send_async_msg(struct iscsi_conn *, u16, u8, u8); -extern int iscsit_send_r2t(struct iscsi_cmd *, struct iscsi_conn *); -extern int iscsit_build_r2ts_for_cmd(struct iscsi_cmd *, struct iscsi_conn *, int); +extern int iscsit_build_r2ts_for_cmd(struct iscsi_cmd *, struct iscsi_conn *, bool recovery); extern void iscsit_thread_get_cpumask(struct iscsi_conn *); extern int iscsi_target_tx_thread(void *); extern int iscsi_target_rx_thread(void *); diff --git a/trunk/drivers/target/iscsi/iscsi_target_configfs.c b/trunk/drivers/target/iscsi/iscsi_target_configfs.c index 00c58cc82c85..69dc8e35c03a 100644 --- a/trunk/drivers/target/iscsi/iscsi_target_configfs.c +++ b/trunk/drivers/target/iscsi/iscsi_target_configfs.c @@ -1538,7 +1538,7 @@ static int lio_write_pending(struct se_cmd *se_cmd) struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); if (!cmd->immediate_data && !cmd->unsolicited_data) - return iscsit_build_r2ts_for_cmd(cmd, cmd->conn, 1); + return iscsit_build_r2ts_for_cmd(cmd, cmd->conn, false); return 0; } diff --git a/trunk/drivers/target/iscsi/iscsi_target_core.h b/trunk/drivers/target/iscsi/iscsi_target_core.h index 2aaee7efa683..1c70144cdaf1 100644 --- a/trunk/drivers/target/iscsi/iscsi_target_core.h +++ b/trunk/drivers/target/iscsi/iscsi_target_core.h @@ -296,12 +296,11 @@ struct iscsi_datain_req { u32 runlength; u32 data_length; u32 data_offset; - u32 data_offset_end; u32 data_sn; u32 next_burst_len; u32 read_data_done; u32 seq_send_order; - struct list_head dr_list; + struct list_head cmd_datain_node; } ____cacheline_aligned; struct iscsi_ooo_cmdsn { @@ -381,8 +380,6 @@ struct iscsi_cmd { u32 buf_ptr_size; /* Used to store DataDigest */ u32 data_crc; - /* Total size in bytes associated with command */ - u32 data_length; /* Counter for MaxOutstandingR2T */ u32 outstanding_r2ts; /* Next R2T Offset when DataSequenceInOrder=Yes */ @@ -464,16 +461,13 @@ struct iscsi_cmd { /* Session the command is part of, used for connection recovery */ struct iscsi_session *sess; /* list_head for connection list */ - struct list_head i_list; + struct list_head i_conn_node; /* The TCM I/O descriptor that is accessed via container_of() */ struct se_cmd se_cmd; /* Sense buffer that will be mapped into outgoing status */ #define ISCSI_SENSE_BUFFER_LEN (TRANSPORT_SENSE_BUFFER + 2) unsigned char sense_buffer[ISCSI_SENSE_BUFFER_LEN]; - struct scatterlist *t_mem_sg; - u32 t_mem_sg_nents; - u32 padding; u8 pad_bytes[4]; @@ -500,8 +494,6 @@ struct iscsi_conn { u8 network_transport; enum iscsi_timer_flags_table nopin_timer_flags; enum iscsi_timer_flags_table nopin_response_timer_flags; - u8 tx_immediate_queue; - u8 tx_response_queue; /* Used to know what thread encountered a transport failure */ u8 which_thread; /* connection id assigned by the Initiator */ diff --git a/trunk/drivers/target/iscsi/iscsi_target_datain_values.c b/trunk/drivers/target/iscsi/iscsi_target_datain_values.c index 8c0495129513..848fee768948 100644 --- a/trunk/drivers/target/iscsi/iscsi_target_datain_values.c +++ b/trunk/drivers/target/iscsi/iscsi_target_datain_values.c @@ -37,7 +37,7 @@ struct iscsi_datain_req *iscsit_allocate_datain_req(void) " struct iscsi_datain_req\n"); return NULL; } - INIT_LIST_HEAD(&dr->dr_list); + INIT_LIST_HEAD(&dr->cmd_datain_node); return dr; } @@ -45,14 +45,14 @@ struct iscsi_datain_req *iscsit_allocate_datain_req(void) void iscsit_attach_datain_req(struct iscsi_cmd *cmd, struct iscsi_datain_req *dr) { spin_lock(&cmd->datain_lock); - list_add_tail(&dr->dr_list, &cmd->datain_list); + list_add_tail(&dr->cmd_datain_node, &cmd->datain_list); spin_unlock(&cmd->datain_lock); } void iscsit_free_datain_req(struct iscsi_cmd *cmd, struct iscsi_datain_req *dr) { spin_lock(&cmd->datain_lock); - list_del(&dr->dr_list); + list_del(&dr->cmd_datain_node); spin_unlock(&cmd->datain_lock); kmem_cache_free(lio_dr_cache, dr); @@ -63,8 +63,8 @@ void iscsit_free_all_datain_reqs(struct iscsi_cmd *cmd) struct iscsi_datain_req *dr, *dr_tmp; spin_lock(&cmd->datain_lock); - list_for_each_entry_safe(dr, dr_tmp, &cmd->datain_list, dr_list) { - list_del(&dr->dr_list); + list_for_each_entry_safe(dr, dr_tmp, &cmd->datain_list, cmd_datain_node) { + list_del(&dr->cmd_datain_node); kmem_cache_free(lio_dr_cache, dr); } spin_unlock(&cmd->datain_lock); @@ -72,17 +72,14 @@ void iscsit_free_all_datain_reqs(struct iscsi_cmd *cmd) struct iscsi_datain_req *iscsit_get_datain_req(struct iscsi_cmd *cmd) { - struct iscsi_datain_req *dr; - if (list_empty(&cmd->datain_list)) { pr_err("cmd->datain_list is empty for ITT:" " 0x%08x\n", cmd->init_task_tag); return NULL; } - list_for_each_entry(dr, &cmd->datain_list, dr_list) - break; - return dr; + return list_first_entry(&cmd->datain_list, struct iscsi_datain_req, + cmd_datain_node); } /* @@ -113,7 +110,7 @@ static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_yes( read_data_done = (!dr->recovery) ? cmd->read_data_done : dr->read_data_done; - read_data_left = (cmd->data_length - read_data_done); + read_data_left = (cmd->se_cmd.data_length - read_data_done); if (!read_data_left) { pr_err("ITT: 0x%08x read_data_left is zero!\n", cmd->init_task_tag); @@ -212,7 +209,7 @@ static struct iscsi_datain_req *iscsit_set_datain_values_no_and_yes( seq_send_order = (!dr->recovery) ? cmd->seq_send_order : dr->seq_send_order; - read_data_left = (cmd->data_length - read_data_done); + read_data_left = (cmd->se_cmd.data_length - read_data_done); if (!read_data_left) { pr_err("ITT: 0x%08x read_data_left is zero!\n", cmd->init_task_tag); @@ -231,8 +228,8 @@ static struct iscsi_datain_req *iscsit_set_datain_values_no_and_yes( offset = (seq->offset + seq->next_burst_len); if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >= - cmd->data_length) { - datain->length = (cmd->data_length - offset); + cmd->se_cmd.data_length) { + datain->length = (cmd->se_cmd.data_length - offset); datain->offset = offset; datain->flags |= ISCSI_FLAG_CMD_FINAL; @@ -264,7 +261,7 @@ static struct iscsi_datain_req *iscsit_set_datain_values_no_and_yes( } } - if ((read_data_done + datain->length) == cmd->data_length) + if ((read_data_done + datain->length) == cmd->se_cmd.data_length) datain->flags |= ISCSI_FLAG_DATA_STATUS; datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++; @@ -333,7 +330,7 @@ static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_no( read_data_done = (!dr->recovery) ? cmd->read_data_done : dr->read_data_done; - read_data_left = (cmd->data_length - read_data_done); + read_data_left = (cmd->se_cmd.data_length - read_data_done); if (!read_data_left) { pr_err("ITT: 0x%08x read_data_left is zero!\n", cmd->init_task_tag); @@ -344,7 +341,7 @@ static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_no( if (!pdu) return dr; - if ((read_data_done + pdu->length) == cmd->data_length) { + if ((read_data_done + pdu->length) == cmd->se_cmd.data_length) { pdu->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS); if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) pdu->flags |= ISCSI_FLAG_DATA_ACK; @@ -433,7 +430,7 @@ static struct iscsi_datain_req *iscsit_set_datain_values_no_and_no( seq_send_order = (!dr->recovery) ? cmd->seq_send_order : dr->seq_send_order; - read_data_left = (cmd->data_length - read_data_done); + read_data_left = (cmd->se_cmd.data_length - read_data_done); if (!read_data_left) { pr_err("ITT: 0x%08x read_data_left is zero!\n", cmd->init_task_tag); @@ -463,7 +460,7 @@ static struct iscsi_datain_req *iscsit_set_datain_values_no_and_no( } else seq->next_burst_len += pdu->length; - if ((read_data_done + pdu->length) == cmd->data_length) + if ((read_data_done + pdu->length) == cmd->se_cmd.data_length) pdu->flags |= ISCSI_FLAG_DATA_STATUS; pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++; diff --git a/trunk/drivers/target/iscsi/iscsi_target_erl0.c b/trunk/drivers/target/iscsi/iscsi_target_erl0.c index 1ab0560b0924..1a02016ecdab 100644 --- a/trunk/drivers/target/iscsi/iscsi_target_erl0.c +++ b/trunk/drivers/target/iscsi/iscsi_target_erl0.c @@ -48,9 +48,9 @@ void iscsit_set_dataout_sequence_values( if (cmd->unsolicited_data) { cmd->seq_start_offset = cmd->write_data_done; cmd->seq_end_offset = (cmd->write_data_done + - (cmd->data_length > + (cmd->se_cmd.data_length > conn->sess->sess_ops->FirstBurstLength) ? - conn->sess->sess_ops->FirstBurstLength : cmd->data_length); + conn->sess->sess_ops->FirstBurstLength : cmd->se_cmd.data_length); return; } @@ -59,15 +59,15 @@ void iscsit_set_dataout_sequence_values( if (!cmd->seq_start_offset && !cmd->seq_end_offset) { cmd->seq_start_offset = cmd->write_data_done; - cmd->seq_end_offset = (cmd->data_length > + cmd->seq_end_offset = (cmd->se_cmd.data_length > conn->sess->sess_ops->MaxBurstLength) ? (cmd->write_data_done + - conn->sess->sess_ops->MaxBurstLength) : cmd->data_length; + conn->sess->sess_ops->MaxBurstLength) : cmd->se_cmd.data_length; } else { cmd->seq_start_offset = cmd->seq_end_offset; cmd->seq_end_offset = ((cmd->seq_end_offset + conn->sess->sess_ops->MaxBurstLength) >= - cmd->data_length) ? cmd->data_length : + cmd->se_cmd.data_length) ? cmd->se_cmd.data_length : (cmd->seq_end_offset + conn->sess->sess_ops->MaxBurstLength); } @@ -182,13 +182,13 @@ static int iscsit_dataout_check_unsolicited_sequence( if (!conn->sess->sess_ops->DataPDUInOrder) goto out; - if ((first_burst_len != cmd->data_length) && + if ((first_burst_len != cmd->se_cmd.data_length) && (first_burst_len != conn->sess->sess_ops->FirstBurstLength)) { pr_err("Unsolicited non-immediate data" " received %u does not equal FirstBurstLength: %u, and" " does not equal ExpXferLen %u.\n", first_burst_len, conn->sess->sess_ops->FirstBurstLength, - cmd->data_length); + cmd->se_cmd.data_length); transport_send_check_condition_and_sense(&cmd->se_cmd, TCM_INCORRECT_AMOUNT_OF_DATA, 0); return DATAOUT_CANNOT_RECOVER; @@ -201,10 +201,10 @@ static int iscsit_dataout_check_unsolicited_sequence( conn->sess->sess_ops->FirstBurstLength); return DATAOUT_CANNOT_RECOVER; } - if (first_burst_len == cmd->data_length) { + if (first_burst_len == cmd->se_cmd.data_length) { pr_err("Command ITT: 0x%08x reached" " ExpXferLen: %u, but ISCSI_FLAG_CMD_FINAL is not set. protocol" - " error.\n", cmd->init_task_tag, cmd->data_length); + " error.\n", cmd->init_task_tag, cmd->se_cmd.data_length); return DATAOUT_CANNOT_RECOVER; } } @@ -294,7 +294,7 @@ static int iscsit_dataout_check_sequence( if ((next_burst_len < conn->sess->sess_ops->MaxBurstLength) && ((cmd->write_data_done + payload_length) < - cmd->data_length)) { + cmd->se_cmd.data_length)) { pr_err("Command ITT: 0x%08x set ISCSI_FLAG_CMD_FINAL" " before end of DataOUT sequence, protocol" " error.\n", cmd->init_task_tag); @@ -319,7 +319,7 @@ static int iscsit_dataout_check_sequence( return DATAOUT_CANNOT_RECOVER; } if ((cmd->write_data_done + payload_length) == - cmd->data_length) { + cmd->se_cmd.data_length) { pr_err("Command ITT: 0x%08x reached" " last DataOUT PDU in sequence but ISCSI_FLAG_" "CMD_FINAL is not set, protocol error.\n", @@ -640,9 +640,12 @@ static int iscsit_dataout_post_crc_passed( cmd->write_data_done += payload_length; - return (cmd->write_data_done == cmd->data_length) ? - DATAOUT_SEND_TO_TRANSPORT : (send_r2t) ? - DATAOUT_SEND_R2T : DATAOUT_NORMAL; + if (cmd->write_data_done == cmd->se_cmd.data_length) + return DATAOUT_SEND_TO_TRANSPORT; + else if (send_r2t) + return DATAOUT_SEND_R2T; + else + return DATAOUT_NORMAL; } static int iscsit_dataout_post_crc_failed( diff --git a/trunk/drivers/target/iscsi/iscsi_target_erl1.c b/trunk/drivers/target/iscsi/iscsi_target_erl1.c index 006f605edb08..ecdd46deedda 100644 --- a/trunk/drivers/target/iscsi/iscsi_target_erl1.c +++ b/trunk/drivers/target/iscsi/iscsi_target_erl1.c @@ -279,11 +279,9 @@ int iscsit_create_recovery_datain_values_datasequenceinorder_no( * seq->first_datasn and seq->last_datasn have not been set. */ if (!seq->sent) { -#if 0 pr_err("Ignoring non-sent sequence 0x%08x ->" " 0x%08x\n\n", seq->first_datasn, seq->last_datasn); -#endif continue; } @@ -294,11 +292,10 @@ int iscsit_create_recovery_datain_values_datasequenceinorder_no( */ if ((seq->first_datasn < begrun) && (seq->last_datasn < begrun)) { -#if 0 pr_err("Pre BegRun sequence 0x%08x ->" " 0x%08x\n", seq->first_datasn, seq->last_datasn); -#endif + read_data_done += cmd->seq_list[i].xfer_len; seq->next_burst_len = seq->pdu_send_order = 0; continue; @@ -309,11 +306,10 @@ int iscsit_create_recovery_datain_values_datasequenceinorder_no( */ if ((seq->first_datasn <= begrun) && (seq->last_datasn >= begrun)) { -#if 0 pr_err("Found sequence begrun: 0x%08x in" " 0x%08x -> 0x%08x\n", begrun, seq->first_datasn, seq->last_datasn); -#endif + seq_send_order = seq->seq_send_order; data_sn = seq->first_datasn; seq->next_burst_len = seq->pdu_send_order = 0; @@ -369,10 +365,9 @@ int iscsit_create_recovery_datain_values_datasequenceinorder_no( */ if ((seq->first_datasn > begrun) || (seq->last_datasn > begrun)) { -#if 0 pr_err("Post BegRun sequence 0x%08x -> 0x%08x\n", seq->first_datasn, seq->last_datasn); -#endif + seq->next_burst_len = seq->pdu_send_order = 0; continue; } @@ -526,7 +521,7 @@ int iscsit_handle_status_snack( found_cmd = 0; spin_lock_bh(&conn->cmd_lock); - list_for_each_entry(cmd, &conn->conn_cmd_list, i_list) { + list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) { if (cmd->stat_sn == begrun) { found_cmd = 1; break; @@ -987,7 +982,7 @@ int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo) return 0; iscsit_set_dataout_sequence_values(cmd); - iscsit_build_r2ts_for_cmd(cmd, cmd->conn, 0); + iscsit_build_r2ts_for_cmd(cmd, cmd->conn, false); } return 0; } @@ -1121,8 +1116,8 @@ static int iscsit_set_dataout_timeout_values( if (cmd->unsolicited_data) { *offset = 0; *length = (conn->sess->sess_ops->FirstBurstLength > - cmd->data_length) ? - cmd->data_length : + cmd->se_cmd.data_length) ? + cmd->se_cmd.data_length : conn->sess->sess_ops->FirstBurstLength; return 0; } @@ -1193,8 +1188,8 @@ static void iscsit_handle_dataout_timeout(unsigned long data) if (conn->sess->sess_ops->DataPDUInOrder) { pdu_offset = cmd->write_data_done; if ((pdu_offset + (conn->sess->sess_ops->MaxBurstLength - - cmd->next_burst_len)) > cmd->data_length) - pdu_length = (cmd->data_length - + cmd->next_burst_len)) > cmd->se_cmd.data_length) + pdu_length = (cmd->se_cmd.data_length - cmd->write_data_done); else pdu_length = (conn->sess->sess_ops->MaxBurstLength - diff --git a/trunk/drivers/target/iscsi/iscsi_target_erl2.c b/trunk/drivers/target/iscsi/iscsi_target_erl2.c index 1af1f21af21f..65aac14fd831 100644 --- a/trunk/drivers/target/iscsi/iscsi_target_erl2.c +++ b/trunk/drivers/target/iscsi/iscsi_target_erl2.c @@ -138,9 +138,9 @@ void iscsit_free_connection_recovery_entires(struct iscsi_session *sess) spin_lock(&cr->conn_recovery_cmd_lock); list_for_each_entry_safe(cmd, cmd_tmp, - &cr->conn_recovery_cmd_list, i_list) { + &cr->conn_recovery_cmd_list, i_conn_node) { - list_del(&cmd->i_list); + list_del(&cmd->i_conn_node); cmd->conn = NULL; spin_unlock(&cr->conn_recovery_cmd_lock); iscsit_free_cmd(cmd); @@ -160,9 +160,9 @@ void iscsit_free_connection_recovery_entires(struct iscsi_session *sess) spin_lock(&cr->conn_recovery_cmd_lock); list_for_each_entry_safe(cmd, cmd_tmp, - &cr->conn_recovery_cmd_list, i_list) { + &cr->conn_recovery_cmd_list, i_conn_node) { - list_del(&cmd->i_list); + list_del(&cmd->i_conn_node); cmd->conn = NULL; spin_unlock(&cr->conn_recovery_cmd_lock); iscsit_free_cmd(cmd); @@ -220,7 +220,7 @@ int iscsit_remove_cmd_from_connection_recovery( } cr = cmd->cr; - list_del(&cmd->i_list); + list_del(&cmd->i_conn_node); return --cr->cmd_count; } @@ -234,7 +234,7 @@ void iscsit_discard_cr_cmds_by_expstatsn( spin_lock(&cr->conn_recovery_cmd_lock); list_for_each_entry_safe(cmd, cmd_tmp, - &cr->conn_recovery_cmd_list, i_list) { + &cr->conn_recovery_cmd_list, i_conn_node) { if (((cmd->deferred_i_state != ISTATE_SENT_STATUS) && (cmd->deferred_i_state != ISTATE_REMOVE)) || @@ -297,11 +297,11 @@ int iscsit_discard_unacknowledged_ooo_cmdsns_for_conn(struct iscsi_conn *conn) mutex_unlock(&sess->cmdsn_mutex); spin_lock_bh(&conn->cmd_lock); - list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_list) { + list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_conn_node) { if (!(cmd->cmd_flags & ICF_OOO_CMDSN)) continue; - list_del(&cmd->i_list); + list_del(&cmd->i_conn_node); spin_unlock_bh(&conn->cmd_lock); iscsit_free_cmd(cmd); @@ -339,14 +339,14 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn) /* * Only perform connection recovery on ISCSI_OP_SCSI_CMD or * ISCSI_OP_NOOP_OUT opcodes. For all other opcodes call - * list_del(&cmd->i_list); to release the command to the + * list_del(&cmd->i_conn_node); to release the command to the * session pool and remove it from the connection's list. * * Also stop the DataOUT timer, which will be restarted after * sending the TMR response. */ spin_lock_bh(&conn->cmd_lock); - list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_list) { + list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_conn_node) { if ((cmd->iscsi_opcode != ISCSI_OP_SCSI_CMD) && (cmd->iscsi_opcode != ISCSI_OP_NOOP_OUT)) { @@ -355,7 +355,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn) " CID: %hu\n", cmd->iscsi_opcode, cmd->init_task_tag, cmd->cmd_sn, conn->cid); - list_del(&cmd->i_list); + list_del(&cmd->i_conn_node); spin_unlock_bh(&conn->cmd_lock); iscsit_free_cmd(cmd); spin_lock_bh(&conn->cmd_lock); @@ -375,7 +375,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn) */ if (!(cmd->cmd_flags & ICF_OOO_CMDSN) && !cmd->immediate_cmd && (cmd->cmd_sn >= conn->sess->exp_cmd_sn)) { - list_del(&cmd->i_list); + list_del(&cmd->i_conn_node); spin_unlock_bh(&conn->cmd_lock); iscsit_free_cmd(cmd); spin_lock_bh(&conn->cmd_lock); @@ -397,7 +397,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn) cmd->sess = conn->sess; - list_del(&cmd->i_list); + list_del(&cmd->i_conn_node); spin_unlock_bh(&conn->cmd_lock); iscsit_free_all_datain_reqs(cmd); @@ -407,7 +407,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn) * Add the struct iscsi_cmd to the connection recovery cmd list */ spin_lock(&cr->conn_recovery_cmd_lock); - list_add_tail(&cmd->i_list, &cr->conn_recovery_cmd_list); + list_add_tail(&cmd->i_conn_node, &cr->conn_recovery_cmd_list); spin_unlock(&cr->conn_recovery_cmd_lock); spin_lock_bh(&conn->cmd_lock); diff --git a/trunk/drivers/target/iscsi/iscsi_target_parameters.c b/trunk/drivers/target/iscsi/iscsi_target_parameters.c index eb05c9d751ea..ed5241e7f12a 100644 --- a/trunk/drivers/target/iscsi/iscsi_target_parameters.c +++ b/trunk/drivers/target/iscsi/iscsi_target_parameters.c @@ -803,14 +803,6 @@ static int iscsi_check_numerical_value(struct iscsi_param *param, char *value_pt value = simple_strtoul(value_ptr, &tmpptr, 0); -/* #warning FIXME: Fix this */ -#if 0 - if (strspn(endptr, WHITE_SPACE) != strlen(endptr)) { - pr_err("Illegal value \"%s\" for \"%s\".\n", - value, param->name); - return -1; - } -#endif if (IS_TYPERANGE_0_TO_2(param)) { if ((value < 0) || (value > 2)) { pr_err("Illegal value for \"%s\", must be" @@ -1045,13 +1037,6 @@ static char *iscsi_check_valuelist_for_support( tmp2 = strchr(acceptor_values, ','); if (tmp2) *tmp2 = '\0'; - if (!acceptor_values || !proposer_values) { - if (tmp1) - *tmp1 = ','; - if (tmp2) - *tmp2 = ','; - return NULL; - } if (!strcmp(acceptor_values, proposer_values)) { if (tmp2) *tmp2 = ','; @@ -1061,8 +1046,6 @@ static char *iscsi_check_valuelist_for_support( *tmp2++ = ','; acceptor_values = tmp2; - if (!acceptor_values) - break; } while (acceptor_values); if (tmp1) *tmp1++ = ','; diff --git a/trunk/drivers/target/iscsi/iscsi_target_seq_pdu_list.c b/trunk/drivers/target/iscsi/iscsi_target_seq_pdu_list.c index fc694082bfc0..85a306e067ba 100644 --- a/trunk/drivers/target/iscsi/iscsi_target_seq_pdu_list.c +++ b/trunk/drivers/target/iscsi/iscsi_target_seq_pdu_list.c @@ -24,11 +24,13 @@ #include "iscsi_target_core.h" #include "iscsi_target_util.h" +#include "iscsi_target_tpg.h" #include "iscsi_target_seq_pdu_list.h" #define OFFLOAD_BUF_SIZE 32768 -void iscsit_dump_seq_list(struct iscsi_cmd *cmd) +#ifdef DEBUG +static void iscsit_dump_seq_list(struct iscsi_cmd *cmd) { int i; struct iscsi_seq *seq; @@ -46,7 +48,7 @@ void iscsit_dump_seq_list(struct iscsi_cmd *cmd) } } -void iscsit_dump_pdu_list(struct iscsi_cmd *cmd) +static void iscsit_dump_pdu_list(struct iscsi_cmd *cmd) { int i; struct iscsi_pdu *pdu; @@ -61,6 +63,10 @@ void iscsit_dump_pdu_list(struct iscsi_cmd *cmd) pdu->length, pdu->pdu_send_order, pdu->seq_no); } } +#else +static void iscsit_dump_seq_list(struct iscsi_cmd *cmd) {} +static void iscsit_dump_pdu_list(struct iscsi_cmd *cmd) {} +#endif static void iscsit_ordered_seq_lists( struct iscsi_cmd *cmd, @@ -135,11 +141,11 @@ static int iscsit_randomize_pdu_lists( seq_count++; continue; } - array = kzalloc(seq_count * sizeof(u32), GFP_KERNEL); + array = kcalloc(seq_count, sizeof(u32), GFP_KERNEL); if (!array) { pr_err("Unable to allocate memory" " for random array.\n"); - return -1; + return -ENOMEM; } iscsit_create_random_array(array, seq_count); @@ -155,11 +161,11 @@ static int iscsit_randomize_pdu_lists( } if (seq_count) { - array = kzalloc(seq_count * sizeof(u32), GFP_KERNEL); + array = kcalloc(seq_count, sizeof(u32), GFP_KERNEL); if (!array) { pr_err("Unable to allocate memory for" " random array.\n"); - return -1; + return -ENOMEM; } iscsit_create_random_array(array, seq_count); @@ -187,10 +193,10 @@ static int iscsit_randomize_seq_lists( if (!seq_count) return 0; - array = kzalloc(seq_count * sizeof(u32), GFP_KERNEL); + array = kcalloc(seq_count, sizeof(u32), GFP_KERNEL); if (!array) { pr_err("Unable to allocate memory for random array.\n"); - return -1; + return -ENOMEM; } iscsit_create_random_array(array, seq_count); @@ -221,11 +227,10 @@ static void iscsit_determine_counts_for_list( if ((bl->type == PDULIST_UNSOLICITED) || (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED)) - unsolicited_data_length = (cmd->data_length > - conn->sess->sess_ops->FirstBurstLength) ? - conn->sess->sess_ops->FirstBurstLength : cmd->data_length; + unsolicited_data_length = min(cmd->se_cmd.data_length, + conn->sess->sess_ops->FirstBurstLength); - while (offset < cmd->data_length) { + while (offset < cmd->se_cmd.data_length) { *pdu_count += 1; if (check_immediate) { @@ -239,10 +244,10 @@ static void iscsit_determine_counts_for_list( } if (unsolicited_data_length > 0) { if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) - >= cmd->data_length) { + >= cmd->se_cmd.data_length) { unsolicited_data_length -= - (cmd->data_length - offset); - offset += (cmd->data_length - offset); + (cmd->se_cmd.data_length - offset); + offset += (cmd->se_cmd.data_length - offset); continue; } if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) @@ -263,8 +268,8 @@ static void iscsit_determine_counts_for_list( continue; } if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >= - cmd->data_length) { - offset += (cmd->data_length - offset); + cmd->se_cmd.data_length) { + offset += (cmd->se_cmd.data_length - offset); continue; } if ((burstlength + conn->conn_ops->MaxRecvDataSegmentLength) >= @@ -283,10 +288,10 @@ static void iscsit_determine_counts_for_list( /* - * Builds PDU and/or Sequence list, called while DataSequenceInOrder=No - * and DataPDUInOrder=No. + * Builds PDU and/or Sequence list, called while DataSequenceInOrder=No + * or DataPDUInOrder=No. */ -static int iscsit_build_pdu_and_seq_list( +static int iscsit_do_build_pdu_and_seq_lists( struct iscsi_cmd *cmd, struct iscsi_build_list *bl) { @@ -306,11 +311,10 @@ static int iscsit_build_pdu_and_seq_list( if ((bl->type == PDULIST_UNSOLICITED) || (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED)) - unsolicited_data_length = (cmd->data_length > - conn->sess->sess_ops->FirstBurstLength) ? - conn->sess->sess_ops->FirstBurstLength : cmd->data_length; + unsolicited_data_length = min(cmd->se_cmd.data_length, + conn->sess->sess_ops->FirstBurstLength); - while (offset < cmd->data_length) { + while (offset < cmd->se_cmd.data_length) { pdu_count++; if (!datapduinorder) { pdu[i].offset = offset; @@ -346,21 +350,21 @@ static int iscsit_build_pdu_and_seq_list( if (unsolicited_data_length > 0) { if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >= - cmd->data_length) { + cmd->se_cmd.data_length) { if (!datapduinorder) { pdu[i].type = PDUTYPE_UNSOLICITED; pdu[i].length = - (cmd->data_length - offset); + (cmd->se_cmd.data_length - offset); } if (!datasequenceinorder) { seq[seq_no].type = SEQTYPE_UNSOLICITED; seq[seq_no].pdu_count = pdu_count; seq[seq_no].xfer_len = (burstlength + - (cmd->data_length - offset)); + (cmd->se_cmd.data_length - offset)); } unsolicited_data_length -= - (cmd->data_length - offset); - offset += (cmd->data_length - offset); + (cmd->se_cmd.data_length - offset); + offset += (cmd->se_cmd.data_length - offset); continue; } if ((offset + @@ -402,18 +406,18 @@ static int iscsit_build_pdu_and_seq_list( continue; } if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >= - cmd->data_length) { + cmd->se_cmd.data_length) { if (!datapduinorder) { pdu[i].type = PDUTYPE_NORMAL; - pdu[i].length = (cmd->data_length - offset); + pdu[i].length = (cmd->se_cmd.data_length - offset); } if (!datasequenceinorder) { seq[seq_no].type = SEQTYPE_NORMAL; seq[seq_no].pdu_count = pdu_count; seq[seq_no].xfer_len = (burstlength + - (cmd->data_length - offset)); + (cmd->se_cmd.data_length - offset)); } - offset += (cmd->data_length - offset); + offset += (cmd->se_cmd.data_length - offset); continue; } if ((burstlength + conn->conn_ops->MaxRecvDataSegmentLength) >= @@ -464,9 +468,8 @@ static int iscsit_build_pdu_and_seq_list( } else iscsit_ordered_seq_lists(cmd, bl->type); } -#if 0 + iscsit_dump_seq_list(cmd); -#endif } if (!datapduinorder) { if (bl->data_direction & ISCSI_PDU_WRITE) { @@ -484,50 +487,86 @@ static int iscsit_build_pdu_and_seq_list( } else iscsit_ordered_pdu_lists(cmd, bl->type); } -#if 0 + iscsit_dump_pdu_list(cmd); -#endif } return 0; } -/* - * Only called while DataSequenceInOrder=No or DataPDUInOrder=No. - */ -int iscsit_do_build_list( +int iscsit_build_pdu_and_seq_lists( struct iscsi_cmd *cmd, - struct iscsi_build_list *bl) + u32 immediate_data_length) { + struct iscsi_build_list bl; u32 pdu_count = 0, seq_count = 1; struct iscsi_conn *conn = cmd->conn; struct iscsi_pdu *pdu = NULL; struct iscsi_seq *seq = NULL; - iscsit_determine_counts_for_list(cmd, bl, &seq_count, &pdu_count); + struct iscsi_session *sess = conn->sess; + struct iscsi_node_attrib *na; + + /* + * Do nothing if no OOO shenanigans + */ + if (sess->sess_ops->DataSequenceInOrder && + sess->sess_ops->DataPDUInOrder) + return 0; + + if (cmd->data_direction == DMA_NONE) + return 0; + + na = iscsit_tpg_get_node_attrib(sess); + memset(&bl, 0, sizeof(struct iscsi_build_list)); + + if (cmd->data_direction == DMA_FROM_DEVICE) { + bl.data_direction = ISCSI_PDU_READ; + bl.type = PDULIST_NORMAL; + if (na->random_datain_pdu_offsets) + bl.randomize |= RANDOM_DATAIN_PDU_OFFSETS; + if (na->random_datain_seq_offsets) + bl.randomize |= RANDOM_DATAIN_SEQ_OFFSETS; + } else { + bl.data_direction = ISCSI_PDU_WRITE; + bl.immediate_data_length = immediate_data_length; + if (na->random_r2t_offsets) + bl.randomize |= RANDOM_R2T_OFFSETS; + + if (!cmd->immediate_data && !cmd->unsolicited_data) + bl.type = PDULIST_NORMAL; + else if (cmd->immediate_data && !cmd->unsolicited_data) + bl.type = PDULIST_IMMEDIATE; + else if (!cmd->immediate_data && cmd->unsolicited_data) + bl.type = PDULIST_UNSOLICITED; + else if (cmd->immediate_data && cmd->unsolicited_data) + bl.type = PDULIST_IMMEDIATE_AND_UNSOLICITED; + } + + iscsit_determine_counts_for_list(cmd, &bl, &seq_count, &pdu_count); if (!conn->sess->sess_ops->DataSequenceInOrder) { - seq = kzalloc(seq_count * sizeof(struct iscsi_seq), GFP_ATOMIC); + seq = kcalloc(seq_count, sizeof(struct iscsi_seq), GFP_ATOMIC); if (!seq) { pr_err("Unable to allocate struct iscsi_seq list\n"); - return -1; + return -ENOMEM; } cmd->seq_list = seq; cmd->seq_count = seq_count; } if (!conn->sess->sess_ops->DataPDUInOrder) { - pdu = kzalloc(pdu_count * sizeof(struct iscsi_pdu), GFP_ATOMIC); + pdu = kcalloc(pdu_count, sizeof(struct iscsi_pdu), GFP_ATOMIC); if (!pdu) { pr_err("Unable to allocate struct iscsi_pdu list.\n"); kfree(seq); - return -1; + return -ENOMEM; } cmd->pdu_list = pdu; cmd->pdu_count = pdu_count; } - return iscsit_build_pdu_and_seq_list(cmd, bl); + return iscsit_do_build_pdu_and_seq_lists(cmd, &bl); } struct iscsi_pdu *iscsit_get_pdu_holder( @@ -572,13 +611,12 @@ struct iscsi_pdu *iscsit_get_pdu_holder_for_seq( pdu = &cmd->pdu_list[cmd->pdu_start]; for (i = 0; pdu[i].seq_no != cmd->seq_no; i++) { -#if 0 pr_debug("pdu[i].seq_no: %d, pdu[i].pdu" "_send_order: %d, pdu[i].offset: %d," " pdu[i].length: %d\n", pdu[i].seq_no, pdu[i].pdu_send_order, pdu[i].offset, pdu[i].length); -#endif + if (pdu[i].pdu_send_order == cmd->pdu_send_order) { cmd->pdu_send_order++; return &pdu[i]; @@ -601,11 +639,11 @@ struct iscsi_pdu *iscsit_get_pdu_holder_for_seq( pr_err("struct iscsi_seq is NULL!\n"); return NULL; } -#if 0 + pr_debug("seq->pdu_start: %d, seq->pdu_count: %d," " seq->seq_no: %d\n", seq->pdu_start, seq->pdu_count, seq->seq_no); -#endif + pdu = &cmd->pdu_list[seq->pdu_start]; if (seq->pdu_send_order == seq->pdu_count) { @@ -645,12 +683,11 @@ struct iscsi_seq *iscsit_get_seq_holder( } for (i = 0; i < cmd->seq_count; i++) { -#if 0 pr_debug("seq_list[i].orig_offset: %d, seq_list[i]." "xfer_len: %d, seq_list[i].seq_no %u\n", cmd->seq_list[i].orig_offset, cmd->seq_list[i].xfer_len, cmd->seq_list[i].seq_no); -#endif + if ((cmd->seq_list[i].orig_offset + cmd->seq_list[i].xfer_len) >= (offset + length)) diff --git a/trunk/drivers/target/iscsi/iscsi_target_seq_pdu_list.h b/trunk/drivers/target/iscsi/iscsi_target_seq_pdu_list.h index 0d52a10e3069..d5b153751a8d 100644 --- a/trunk/drivers/target/iscsi/iscsi_target_seq_pdu_list.h +++ b/trunk/drivers/target/iscsi/iscsi_target_seq_pdu_list.h @@ -78,7 +78,7 @@ struct iscsi_seq { u32 xfer_len; } ____cacheline_aligned; -extern int iscsit_do_build_list(struct iscsi_cmd *, struct iscsi_build_list *); +extern int iscsit_build_pdu_and_seq_lists(struct iscsi_cmd *, u32); extern struct iscsi_pdu *iscsit_get_pdu_holder(struct iscsi_cmd *, u32, u32); extern struct iscsi_pdu *iscsit_get_pdu_holder_for_seq(struct iscsi_cmd *, struct iscsi_seq *); extern struct iscsi_seq *iscsit_get_seq_holder(struct iscsi_cmd *, u32, u32); diff --git a/trunk/drivers/target/iscsi/iscsi_target_tmr.c b/trunk/drivers/target/iscsi/iscsi_target_tmr.c index e01da9d2b37e..f4e640b51fd1 100644 --- a/trunk/drivers/target/iscsi/iscsi_target_tmr.c +++ b/trunk/drivers/target/iscsi/iscsi_target_tmr.c @@ -78,10 +78,7 @@ int iscsit_tmr_task_warm_reset( { struct iscsi_session *sess = conn->sess; struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess); -#if 0 - struct iscsi_init_task_mgt_cmnd *hdr = - (struct iscsi_init_task_mgt_cmnd *) buf; -#endif + if (!na->tmr_warm_reset) { pr_err("TMR Opcode TARGET_WARM_RESET authorization" " failed for Initiator Node: %s\n", @@ -216,7 +213,7 @@ static int iscsit_task_reassign_complete_nop_out( iscsit_task_reassign_remove_cmd(cmd, cr, conn->sess); spin_lock_bh(&conn->cmd_lock); - list_add_tail(&cmd->i_list, &conn->conn_cmd_list); + list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list); spin_unlock_bh(&conn->cmd_lock); cmd->i_state = ISTATE_SEND_NOPIN; @@ -272,9 +269,9 @@ static int iscsit_task_reassign_complete_write( offset = cmd->next_burst_len = cmd->write_data_done; if ((conn->sess->sess_ops->FirstBurstLength - offset) >= - cmd->data_length) { + cmd->se_cmd.data_length) { no_build_r2ts = 1; - length = (cmd->data_length - offset); + length = (cmd->se_cmd.data_length - offset); } else length = (conn->sess->sess_ops->FirstBurstLength - offset); @@ -292,7 +289,7 @@ static int iscsit_task_reassign_complete_write( /* * iscsit_build_r2ts_for_cmd() can handle the rest from here. */ - return iscsit_build_r2ts_for_cmd(cmd, conn, 2); + return iscsit_build_r2ts_for_cmd(cmd, conn, true); } static int iscsit_task_reassign_complete_read( @@ -385,7 +382,7 @@ static int iscsit_task_reassign_complete_scsi_cmnd( iscsit_task_reassign_remove_cmd(cmd, cr, conn->sess); spin_lock_bh(&conn->cmd_lock); - list_add_tail(&cmd->i_list, &conn->conn_cmd_list); + list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list); spin_unlock_bh(&conn->cmd_lock); if (se_cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) { diff --git a/trunk/drivers/target/iscsi/iscsi_target_util.c b/trunk/drivers/target/iscsi/iscsi_target_util.c index 4eba86d2bd82..b42cdeb153df 100644 --- a/trunk/drivers/target/iscsi/iscsi_target_util.c +++ b/trunk/drivers/target/iscsi/iscsi_target_util.c @@ -163,7 +163,7 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp_mask) } cmd->conn = conn; - INIT_LIST_HEAD(&cmd->i_list); + INIT_LIST_HEAD(&cmd->i_conn_node); INIT_LIST_HEAD(&cmd->datain_list); INIT_LIST_HEAD(&cmd->cmd_r2t_list); init_completion(&cmd->reject_comp); @@ -176,174 +176,6 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp_mask) return cmd; } -/* - * Called from iscsi_handle_scsi_cmd() - */ -struct iscsi_cmd *iscsit_allocate_se_cmd( - struct iscsi_conn *conn, - u32 data_length, - int data_direction, - int iscsi_task_attr) -{ - struct iscsi_cmd *cmd; - struct se_cmd *se_cmd; - int sam_task_attr; - - cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); - if (!cmd) - return NULL; - - cmd->data_direction = data_direction; - cmd->data_length = data_length; - /* - * Figure out the SAM Task Attribute for the incoming SCSI CDB - */ - if ((iscsi_task_attr == ISCSI_ATTR_UNTAGGED) || - (iscsi_task_attr == ISCSI_ATTR_SIMPLE)) - sam_task_attr = MSG_SIMPLE_TAG; - else if (iscsi_task_attr == ISCSI_ATTR_ORDERED) - sam_task_attr = MSG_ORDERED_TAG; - else if (iscsi_task_attr == ISCSI_ATTR_HEAD_OF_QUEUE) - sam_task_attr = MSG_HEAD_TAG; - else if (iscsi_task_attr == ISCSI_ATTR_ACA) - sam_task_attr = MSG_ACA_TAG; - else { - pr_debug("Unknown iSCSI Task Attribute: 0x%02x, using" - " MSG_SIMPLE_TAG\n", iscsi_task_attr); - sam_task_attr = MSG_SIMPLE_TAG; - } - - se_cmd = &cmd->se_cmd; - /* - * Initialize struct se_cmd descriptor from target_core_mod infrastructure - */ - transport_init_se_cmd(se_cmd, &lio_target_fabric_configfs->tf_ops, - conn->sess->se_sess, data_length, data_direction, - sam_task_attr, &cmd->sense_buffer[0]); - return cmd; -} - -struct iscsi_cmd *iscsit_allocate_se_cmd_for_tmr( - struct iscsi_conn *conn, - u8 function) -{ - struct iscsi_cmd *cmd; - struct se_cmd *se_cmd; - int rc; - u8 tcm_function; - - cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); - if (!cmd) - return NULL; - - cmd->data_direction = DMA_NONE; - - cmd->tmr_req = kzalloc(sizeof(struct iscsi_tmr_req), GFP_KERNEL); - if (!cmd->tmr_req) { - pr_err("Unable to allocate memory for" - " Task Management command!\n"); - goto out; - } - /* - * TASK_REASSIGN for ERL=2 / connection stays inside of - * LIO-Target $FABRIC_MOD - */ - if (function == ISCSI_TM_FUNC_TASK_REASSIGN) - return cmd; - - se_cmd = &cmd->se_cmd; - /* - * Initialize struct se_cmd descriptor from target_core_mod infrastructure - */ - transport_init_se_cmd(se_cmd, &lio_target_fabric_configfs->tf_ops, - conn->sess->se_sess, 0, DMA_NONE, - MSG_SIMPLE_TAG, &cmd->sense_buffer[0]); - - switch (function) { - case ISCSI_TM_FUNC_ABORT_TASK: - tcm_function = TMR_ABORT_TASK; - break; - case ISCSI_TM_FUNC_ABORT_TASK_SET: - tcm_function = TMR_ABORT_TASK_SET; - break; - case ISCSI_TM_FUNC_CLEAR_ACA: - tcm_function = TMR_CLEAR_ACA; - break; - case ISCSI_TM_FUNC_CLEAR_TASK_SET: - tcm_function = TMR_CLEAR_TASK_SET; - break; - case ISCSI_TM_FUNC_LOGICAL_UNIT_RESET: - tcm_function = TMR_LUN_RESET; - break; - case ISCSI_TM_FUNC_TARGET_WARM_RESET: - tcm_function = TMR_TARGET_WARM_RESET; - break; - case ISCSI_TM_FUNC_TARGET_COLD_RESET: - tcm_function = TMR_TARGET_COLD_RESET; - break; - default: - pr_err("Unknown iSCSI TMR Function:" - " 0x%02x\n", function); - goto out; - } - - rc = core_tmr_alloc_req(se_cmd, cmd->tmr_req, tcm_function, GFP_KERNEL); - if (rc < 0) - goto out; - - cmd->tmr_req->se_tmr_req = se_cmd->se_tmr_req; - - return cmd; -out: - iscsit_release_cmd(cmd); - return NULL; -} - -int iscsit_decide_list_to_build( - struct iscsi_cmd *cmd, - u32 immediate_data_length) -{ - struct iscsi_build_list bl; - struct iscsi_conn *conn = cmd->conn; - struct iscsi_session *sess = conn->sess; - struct iscsi_node_attrib *na; - - if (sess->sess_ops->DataSequenceInOrder && - sess->sess_ops->DataPDUInOrder) - return 0; - - if (cmd->data_direction == DMA_NONE) - return 0; - - na = iscsit_tpg_get_node_attrib(sess); - memset(&bl, 0, sizeof(struct iscsi_build_list)); - - if (cmd->data_direction == DMA_FROM_DEVICE) { - bl.data_direction = ISCSI_PDU_READ; - bl.type = PDULIST_NORMAL; - if (na->random_datain_pdu_offsets) - bl.randomize |= RANDOM_DATAIN_PDU_OFFSETS; - if (na->random_datain_seq_offsets) - bl.randomize |= RANDOM_DATAIN_SEQ_OFFSETS; - } else { - bl.data_direction = ISCSI_PDU_WRITE; - bl.immediate_data_length = immediate_data_length; - if (na->random_r2t_offsets) - bl.randomize |= RANDOM_R2T_OFFSETS; - - if (!cmd->immediate_data && !cmd->unsolicited_data) - bl.type = PDULIST_NORMAL; - else if (cmd->immediate_data && !cmd->unsolicited_data) - bl.type = PDULIST_IMMEDIATE; - else if (!cmd->immediate_data && cmd->unsolicited_data) - bl.type = PDULIST_UNSOLICITED; - else if (cmd->immediate_data && cmd->unsolicited_data) - bl.type = PDULIST_IMMEDIATE_AND_UNSOLICITED; - } - - return iscsit_do_build_list(cmd, &bl); -} - struct iscsi_seq *iscsit_get_seq_holder_for_datain( struct iscsi_cmd *cmd, u32 seq_send_order) @@ -502,14 +334,14 @@ int iscsit_check_unsolicited_dataout(struct iscsi_cmd *cmd, unsigned char *buf) if (!(hdr->flags & ISCSI_FLAG_CMD_FINAL)) return 0; - if (((cmd->first_burst_len + payload_length) != cmd->data_length) && + if (((cmd->first_burst_len + payload_length) != cmd->se_cmd.data_length) && ((cmd->first_burst_len + payload_length) != conn->sess->sess_ops->FirstBurstLength)) { pr_err("Unsolicited non-immediate data received %u" " does not equal FirstBurstLength: %u, and does" " not equal ExpXferLen %u.\n", (cmd->first_burst_len + payload_length), - conn->sess->sess_ops->FirstBurstLength, cmd->data_length); + conn->sess->sess_ops->FirstBurstLength, cmd->se_cmd.data_length); transport_send_check_condition_and_sense(se_cmd, TCM_INCORRECT_AMOUNT_OF_DATA, 0); return -1; @@ -524,7 +356,7 @@ struct iscsi_cmd *iscsit_find_cmd_from_itt( struct iscsi_cmd *cmd; spin_lock_bh(&conn->cmd_lock); - list_for_each_entry(cmd, &conn->conn_cmd_list, i_list) { + list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) { if (cmd->init_task_tag == init_task_tag) { spin_unlock_bh(&conn->cmd_lock); return cmd; @@ -545,7 +377,7 @@ struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump( struct iscsi_cmd *cmd; spin_lock_bh(&conn->cmd_lock); - list_for_each_entry(cmd, &conn->conn_cmd_list, i_list) { + list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) { if (cmd->init_task_tag == init_task_tag) { spin_unlock_bh(&conn->cmd_lock); return cmd; @@ -568,7 +400,7 @@ struct iscsi_cmd *iscsit_find_cmd_from_ttt( struct iscsi_cmd *cmd = NULL; spin_lock_bh(&conn->cmd_lock); - list_for_each_entry(cmd, &conn->conn_cmd_list, i_list) { + list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) { if (cmd->targ_xfer_tag == targ_xfer_tag) { spin_unlock_bh(&conn->cmd_lock); return cmd; @@ -596,7 +428,7 @@ int iscsit_find_cmd_for_recovery( spin_lock(&sess->cr_i_lock); list_for_each_entry(cr, &sess->cr_inactive_list, cr_list) { spin_lock(&cr->conn_recovery_cmd_lock); - list_for_each_entry(cmd, &cr->conn_recovery_cmd_list, i_list) { + list_for_each_entry(cmd, &cr->conn_recovery_cmd_list, i_conn_node) { if (cmd->init_task_tag == init_task_tag) { spin_unlock(&cr->conn_recovery_cmd_lock); spin_unlock(&sess->cr_i_lock); @@ -616,7 +448,7 @@ int iscsit_find_cmd_for_recovery( spin_lock(&sess->cr_a_lock); list_for_each_entry(cr, &sess->cr_active_list, cr_list) { spin_lock(&cr->conn_recovery_cmd_lock); - list_for_each_entry(cmd, &cr->conn_recovery_cmd_list, i_list) { + list_for_each_entry(cmd, &cr->conn_recovery_cmd_list, i_conn_node) { if (cmd->init_task_tag == init_task_tag) { spin_unlock(&cr->conn_recovery_cmd_lock); spin_unlock(&sess->cr_a_lock); @@ -813,7 +645,6 @@ void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *conn) void iscsit_release_cmd(struct iscsi_cmd *cmd) { struct iscsi_conn *conn = cmd->conn; - int i; iscsit_free_r2ts_from_list(cmd); iscsit_free_all_datain_reqs(cmd); @@ -824,11 +655,6 @@ void iscsit_release_cmd(struct iscsi_cmd *cmd) kfree(cmd->tmr_req); kfree(cmd->iov_data); - for (i = 0; i < cmd->t_mem_sg_nents; i++) - __free_page(sg_page(&cmd->t_mem_sg[i])); - - kfree(cmd->t_mem_sg); - if (conn) { iscsit_remove_cmd_from_immediate_queue(cmd, conn); iscsit_remove_cmd_from_response_queue(cmd, conn); @@ -1038,7 +864,7 @@ static int iscsit_add_nopin(struct iscsi_conn *conn, int want_response) spin_unlock_bh(&conn->sess->ttt_lock); spin_lock_bh(&conn->cmd_lock); - list_add_tail(&cmd->i_list, &conn->conn_cmd_list); + list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list); spin_unlock_bh(&conn->cmd_lock); if (want_response) diff --git a/trunk/drivers/target/iscsi/iscsi_target_util.h b/trunk/drivers/target/iscsi/iscsi_target_util.h index 835bf7de0281..e1c729b8a1c5 100644 --- a/trunk/drivers/target/iscsi/iscsi_target_util.h +++ b/trunk/drivers/target/iscsi/iscsi_target_util.h @@ -9,9 +9,6 @@ extern struct iscsi_r2t *iscsit_get_r2t_from_list(struct iscsi_cmd *); extern void iscsit_free_r2t(struct iscsi_r2t *, struct iscsi_cmd *); extern void iscsit_free_r2ts_from_list(struct iscsi_cmd *); extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t); -extern struct iscsi_cmd *iscsit_allocate_se_cmd(struct iscsi_conn *, u32, int, int); -extern struct iscsi_cmd *iscsit_allocate_se_cmd_for_tmr(struct iscsi_conn *, u8); -extern int iscsit_decide_list_to_build(struct iscsi_cmd *, u32); extern struct iscsi_seq *iscsit_get_seq_holder_for_datain(struct iscsi_cmd *, u32); extern struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *); extern struct iscsi_r2t *iscsit_get_holder_for_r2tsn(struct iscsi_cmd *, u32); diff --git a/trunk/drivers/target/loopback/tcm_loop.c b/trunk/drivers/target/loopback/tcm_loop.c index a9b4eeefe9fc..38dfac2b0a1c 100644 --- a/trunk/drivers/target/loopback/tcm_loop.c +++ b/trunk/drivers/target/loopback/tcm_loop.c @@ -213,7 +213,7 @@ static void tcm_loop_submission_work(struct work_struct *work) * associated read buffers, go ahead and do that here for type * SCF_SCSI_CONTROL_SG_IO_CDB. Also note that this is currently * guaranteed to be a single SGL for SCF_SCSI_CONTROL_SG_IO_CDB - * by target core in transport_generic_allocate_tasks() -> + * by target core in target_setup_cmd_from_cdb() -> * transport_generic_cmd_sequencer(). */ if (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB && @@ -227,7 +227,7 @@ static void tcm_loop_submission_work(struct work_struct *work) } } - ret = transport_generic_allocate_tasks(se_cmd, sc->cmnd); + ret = target_setup_cmd_from_cdb(se_cmd, sc->cmnd); if (ret == -ENOMEM) { transport_send_check_condition_and_sense(se_cmd, TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0); diff --git a/trunk/drivers/target/target_core_alua.c b/trunk/drivers/target/target_core_alua.c index c7746a3339d4..e624b836469c 100644 --- a/trunk/drivers/target/target_core_alua.c +++ b/trunk/drivers/target/target_core_alua.c @@ -59,26 +59,31 @@ struct t10_alua_lu_gp *default_lu_gp; * * See spc4r17 section 6.27 */ -int target_emulate_report_target_port_groups(struct se_task *task) +int target_emulate_report_target_port_groups(struct se_cmd *cmd) { - struct se_cmd *cmd = task->task_se_cmd; struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; struct se_port *port; struct t10_alua_tg_pt_gp *tg_pt_gp; struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; unsigned char *buf; - u32 rd_len = 0, off = 4; /* Skip over RESERVED area to first - Target port group descriptor */ + u32 rd_len = 0, off; + int ext_hdr = (cmd->t_task_cdb[1] & 0x20); /* - * Need at least 4 bytes of response data or else we can't - * even fit the return data length. + * Skip over RESERVED area to first Target port group descriptor + * depending on the PARAMETER DATA FORMAT type.. */ - if (cmd->data_length < 4) { - pr_warn("REPORT TARGET PORT GROUPS allocation length %u" - " too small\n", cmd->data_length); + if (ext_hdr != 0) + off = 8; + else + off = 4; + + if (cmd->data_length < off) { + pr_warn("REPORT TARGET PORT GROUPS allocation length %u too" + " small for %s header\n", cmd->data_length, + (ext_hdr) ? "extended" : "normal"); + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; return -EINVAL; } - buf = transport_kmap_data_sg(cmd); spin_lock(&su_dev->t10_alua.tg_pt_gps_lock); @@ -159,15 +164,34 @@ int target_emulate_report_target_port_groups(struct se_task *task) /* * Set the RETURN DATA LENGTH set in the header of the DataIN Payload */ - buf[0] = ((rd_len >> 24) & 0xff); - buf[1] = ((rd_len >> 16) & 0xff); - buf[2] = ((rd_len >> 8) & 0xff); - buf[3] = (rd_len & 0xff); + put_unaligned_be32(rd_len, &buf[0]); + /* + * Fill in the Extended header parameter data format if requested + */ + if (ext_hdr != 0) { + buf[4] = 0x10; + /* + * Set the implict transition time (in seconds) for the application + * client to use as a base for it's transition timeout value. + * + * Use the current tg_pt_gp_mem -> tg_pt_gp membership from the LUN + * this CDB was received upon to determine this value individually + * for ALUA target port group. + */ + port = cmd->se_lun->lun_sep; + tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; + if (tg_pt_gp_mem) { + spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; + if (tg_pt_gp) + buf[5] = tg_pt_gp->tg_pt_gp_implict_trans_secs; + spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + } + } transport_kunmap_data_sg(cmd); - task->task_scsi_status = GOOD; - transport_complete_task(task, 1); + target_complete_cmd(cmd, GOOD); return 0; } @@ -176,9 +200,8 @@ int target_emulate_report_target_port_groups(struct se_task *task) * * See spc4r17 section 6.35 */ -int target_emulate_set_target_port_groups(struct se_task *task) +int target_emulate_set_target_port_groups(struct se_cmd *cmd) { - struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; struct se_subsystem_dev *su_dev = dev->se_sub_dev; struct se_port *port, *l_port = cmd->se_lun->lun_sep; @@ -351,8 +374,7 @@ int target_emulate_set_target_port_groups(struct se_task *task) out: transport_kunmap_data_sg(cmd); - task->task_scsi_status = GOOD; - transport_complete_task(task, 1); + target_complete_cmd(cmd, GOOD); return 0; } @@ -391,7 +413,7 @@ static inline int core_alua_state_standby( case RECEIVE_DIAGNOSTIC: case SEND_DIAGNOSTIC: case MAINTENANCE_IN: - switch (cdb[1]) { + switch (cdb[1] & 0x1f) { case MI_REPORT_TARGET_PGS: return 0; default: @@ -433,7 +455,7 @@ static inline int core_alua_state_unavailable( case INQUIRY: case REPORT_LUNS: case MAINTENANCE_IN: - switch (cdb[1]) { + switch (cdb[1] & 0x1f) { case MI_REPORT_TARGET_PGS: return 0; default: @@ -473,7 +495,7 @@ static inline int core_alua_state_transition( case INQUIRY: case REPORT_LUNS: case MAINTENANCE_IN: - switch (cdb[1]) { + switch (cdb[1] & 0x1f) { case MI_REPORT_TARGET_PGS: return 0; default: @@ -1359,6 +1381,7 @@ struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp( */ tg_pt_gp->tg_pt_gp_nonop_delay_msecs = ALUA_DEFAULT_NONOP_DELAY_MSECS; tg_pt_gp->tg_pt_gp_trans_delay_msecs = ALUA_DEFAULT_TRANS_DELAY_MSECS; + tg_pt_gp->tg_pt_gp_implict_trans_secs = ALUA_DEFAULT_IMPLICT_TRANS_SECS; if (def_group) { spin_lock(&su_dev->t10_alua.tg_pt_gps_lock); @@ -1855,6 +1878,37 @@ ssize_t core_alua_store_trans_delay_msecs( return count; } +ssize_t core_alua_show_implict_trans_secs( + struct t10_alua_tg_pt_gp *tg_pt_gp, + char *page) +{ + return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_implict_trans_secs); +} + +ssize_t core_alua_store_implict_trans_secs( + struct t10_alua_tg_pt_gp *tg_pt_gp, + const char *page, + size_t count) +{ + unsigned long tmp; + int ret; + + ret = strict_strtoul(page, 0, &tmp); + if (ret < 0) { + pr_err("Unable to extract implict_trans_secs\n"); + return -EINVAL; + } + if (tmp > ALUA_MAX_IMPLICT_TRANS_SECS) { + pr_err("Passed implict_trans_secs: %lu, exceeds" + " ALUA_MAX_IMPLICT_TRANS_SECS: %d\n", tmp, + ALUA_MAX_IMPLICT_TRANS_SECS); + return -EINVAL; + } + tg_pt_gp->tg_pt_gp_implict_trans_secs = (int)tmp; + + return count; +} + ssize_t core_alua_show_preferred_bit( struct t10_alua_tg_pt_gp *tg_pt_gp, char *page) diff --git a/trunk/drivers/target/target_core_alua.h b/trunk/drivers/target/target_core_alua.h index c5b4ecd3e745..f920c170d47b 100644 --- a/trunk/drivers/target/target_core_alua.h +++ b/trunk/drivers/target/target_core_alua.h @@ -51,6 +51,12 @@ */ #define ALUA_DEFAULT_TRANS_DELAY_MSECS 0 #define ALUA_MAX_TRANS_DELAY_MSECS 30000 /* 30 seconds */ +/* + * Used for the recommended application client implict transition timeout + * in seconds, returned by the REPORT_TARGET_PORT_GROUPS w/ extended header. + */ +#define ALUA_DEFAULT_IMPLICT_TRANS_SECS 0 +#define ALUA_MAX_IMPLICT_TRANS_SECS 255 /* * Used by core_alua_update_tpg_primary_metadata() and * core_alua_update_tpg_secondary_metadata() @@ -66,8 +72,8 @@ extern struct kmem_cache *t10_alua_lu_gp_mem_cache; extern struct kmem_cache *t10_alua_tg_pt_gp_cache; extern struct kmem_cache *t10_alua_tg_pt_gp_mem_cache; -extern int target_emulate_report_target_port_groups(struct se_task *); -extern int target_emulate_set_target_port_groups(struct se_task *); +extern int target_emulate_report_target_port_groups(struct se_cmd *); +extern int target_emulate_set_target_port_groups(struct se_cmd *); extern int core_alua_check_nonop_delay(struct se_cmd *); extern int core_alua_do_port_transition(struct t10_alua_tg_pt_gp *, struct se_device *, struct se_port *, @@ -107,6 +113,10 @@ extern ssize_t core_alua_show_trans_delay_msecs(struct t10_alua_tg_pt_gp *, char *); extern ssize_t core_alua_store_trans_delay_msecs(struct t10_alua_tg_pt_gp *, const char *, size_t); +extern ssize_t core_alua_show_implict_trans_secs(struct t10_alua_tg_pt_gp *, + char *); +extern ssize_t core_alua_store_implict_trans_secs(struct t10_alua_tg_pt_gp *, + const char *, size_t); extern ssize_t core_alua_show_preferred_bit(struct t10_alua_tg_pt_gp *, char *); extern ssize_t core_alua_store_preferred_bit(struct t10_alua_tg_pt_gp *, diff --git a/trunk/drivers/target/target_core_cdb.c b/trunk/drivers/target/target_core_cdb.c index 30a67707036f..9888693a18fe 100644 --- a/trunk/drivers/target/target_core_cdb.c +++ b/trunk/drivers/target/target_core_cdb.c @@ -432,6 +432,7 @@ static int target_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) { struct se_device *dev = cmd->se_dev; + u32 max_sectors; int have_tp = 0; /* @@ -456,7 +457,9 @@ target_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) /* * Set MAXIMUM TRANSFER LENGTH */ - put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.fabric_max_sectors, &buf[8]); + max_sectors = min(dev->se_sub_dev->se_dev_attrib.fabric_max_sectors, + dev->se_sub_dev->se_dev_attrib.hw_max_sectors); + put_unaligned_be32(max_sectors, &buf[8]); /* * Set OPTIMAL TRANSFER LENGTH @@ -598,9 +601,8 @@ target_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf) return 0; } -int target_emulate_inquiry(struct se_task *task) +int target_emulate_inquiry(struct se_cmd *cmd) { - struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; struct se_portal_group *tpg = cmd->se_lun->lun_sep->sep_tpg; unsigned char *buf, *map_buf; @@ -664,16 +666,13 @@ int target_emulate_inquiry(struct se_task *task) } transport_kunmap_data_sg(cmd); - if (!ret) { - task->task_scsi_status = GOOD; - transport_complete_task(task, 1); - } + if (!ret) + target_complete_cmd(cmd, GOOD); return ret; } -int target_emulate_readcapacity(struct se_task *task) +int target_emulate_readcapacity(struct se_cmd *cmd) { - struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; unsigned char *buf; unsigned long long blocks_long = dev->transport->get_blocks(dev); @@ -697,14 +696,12 @@ int target_emulate_readcapacity(struct se_task *task) transport_kunmap_data_sg(cmd); - task->task_scsi_status = GOOD; - transport_complete_task(task, 1); + target_complete_cmd(cmd, GOOD); return 0; } -int target_emulate_readcapacity_16(struct se_task *task) +int target_emulate_readcapacity_16(struct se_cmd *cmd) { - struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; unsigned char *buf; unsigned long long blocks = dev->transport->get_blocks(dev); @@ -732,8 +729,7 @@ int target_emulate_readcapacity_16(struct se_task *task) transport_kunmap_data_sg(cmd); - task->task_scsi_status = GOOD; - transport_complete_task(task, 1); + target_complete_cmd(cmd, GOOD); return 0; } @@ -872,9 +868,8 @@ target_modesense_dpofua(unsigned char *buf, int type) } } -int target_emulate_modesense(struct se_task *task) +int target_emulate_modesense(struct se_cmd *cmd) { - struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; char *cdb = cmd->t_task_cdb; unsigned char *rbuf; @@ -947,14 +942,12 @@ int target_emulate_modesense(struct se_task *task) memcpy(rbuf, buf, offset); transport_kunmap_data_sg(cmd); - task->task_scsi_status = GOOD; - transport_complete_task(task, 1); + target_complete_cmd(cmd, GOOD); return 0; } -int target_emulate_request_sense(struct se_task *task) +int target_emulate_request_sense(struct se_cmd *cmd) { - struct se_cmd *cmd = task->task_se_cmd; unsigned char *cdb = cmd->t_task_cdb; unsigned char *buf; u8 ua_asc = 0, ua_ascq = 0; @@ -1008,8 +1001,7 @@ int target_emulate_request_sense(struct se_task *task) end: transport_kunmap_data_sg(cmd); - task->task_scsi_status = GOOD; - transport_complete_task(task, 1); + target_complete_cmd(cmd, GOOD); return 0; } @@ -1017,9 +1009,8 @@ int target_emulate_request_sense(struct se_task *task) * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support. * Note this is not used for TCM/pSCSI passthrough */ -int target_emulate_unmap(struct se_task *task) +int target_emulate_unmap(struct se_cmd *cmd) { - struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; unsigned char *buf, *ptr = NULL; unsigned char *cdb = &cmd->t_task_cdb[0]; @@ -1066,10 +1057,8 @@ int target_emulate_unmap(struct se_task *task) err: transport_kunmap_data_sg(cmd); - if (!ret) { - task->task_scsi_status = GOOD; - transport_complete_task(task, 1); - } + if (!ret) + target_complete_cmd(cmd, GOOD); return ret; } @@ -1077,9 +1066,8 @@ int target_emulate_unmap(struct se_task *task) * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support. * Note this is not used for TCM/pSCSI passthrough */ -int target_emulate_write_same(struct se_task *task) +int target_emulate_write_same(struct se_cmd *cmd) { - struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; sector_t range; sector_t lba = cmd->t_task_lba; @@ -1118,79 +1106,25 @@ int target_emulate_write_same(struct se_task *task) return ret; } - task->task_scsi_status = GOOD; - transport_complete_task(task, 1); + target_complete_cmd(cmd, GOOD); return 0; } -int target_emulate_synchronize_cache(struct se_task *task) +int target_emulate_synchronize_cache(struct se_cmd *cmd) { - struct se_device *dev = task->task_se_cmd->se_dev; - struct se_cmd *cmd = task->task_se_cmd; - - if (!dev->transport->do_sync_cache) { + if (!cmd->se_dev->transport->do_sync_cache) { pr_err("SYNCHRONIZE_CACHE emulation not supported" - " for: %s\n", dev->transport->name); + " for: %s\n", cmd->se_dev->transport->name); cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; return -ENOSYS; } - dev->transport->do_sync_cache(task); + cmd->se_dev->transport->do_sync_cache(cmd); return 0; } -int target_emulate_noop(struct se_task *task) +int target_emulate_noop(struct se_cmd *cmd) { - task->task_scsi_status = GOOD; - transport_complete_task(task, 1); + target_complete_cmd(cmd, GOOD); return 0; } - -/* - * Write a CDB into @cdb that is based on the one the intiator sent us, - * but updated to only cover the sectors that the current task handles. - */ -void target_get_task_cdb(struct se_task *task, unsigned char *cdb) -{ - struct se_cmd *cmd = task->task_se_cmd; - unsigned int cdb_len = scsi_command_size(cmd->t_task_cdb); - - memcpy(cdb, cmd->t_task_cdb, cdb_len); - if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) { - unsigned long long lba = task->task_lba; - u32 sectors = task->task_sectors; - - switch (cdb_len) { - case 6: - /* 21-bit LBA and 8-bit sectors */ - cdb[1] = (lba >> 16) & 0x1f; - cdb[2] = (lba >> 8) & 0xff; - cdb[3] = lba & 0xff; - cdb[4] = sectors & 0xff; - break; - case 10: - /* 32-bit LBA and 16-bit sectors */ - put_unaligned_be32(lba, &cdb[2]); - put_unaligned_be16(sectors, &cdb[7]); - break; - case 12: - /* 32-bit LBA and 32-bit sectors */ - put_unaligned_be32(lba, &cdb[2]); - put_unaligned_be32(sectors, &cdb[6]); - break; - case 16: - /* 64-bit LBA and 32-bit sectors */ - put_unaligned_be64(lba, &cdb[2]); - put_unaligned_be32(sectors, &cdb[10]); - break; - case 32: - /* 64-bit LBA and 32-bit sectors, extended CDB */ - put_unaligned_be64(lba, &cdb[12]); - put_unaligned_be32(sectors, &cdb[28]); - break; - default: - BUG(); - } - } -} -EXPORT_SYMBOL(target_get_task_cdb); diff --git a/trunk/drivers/target/target_core_configfs.c b/trunk/drivers/target/target_core_configfs.c index cbb66537d230..801efa892046 100644 --- a/trunk/drivers/target/target_core_configfs.c +++ b/trunk/drivers/target/target_core_configfs.c @@ -683,9 +683,6 @@ SE_DEV_ATTR(block_size, S_IRUGO | S_IWUSR); DEF_DEV_ATTRIB_RO(hw_max_sectors); SE_DEV_ATTR_RO(hw_max_sectors); -DEF_DEV_ATTRIB(max_sectors); -SE_DEV_ATTR(max_sectors, S_IRUGO | S_IWUSR); - DEF_DEV_ATTRIB(fabric_max_sectors); SE_DEV_ATTR(fabric_max_sectors, S_IRUGO | S_IWUSR); @@ -727,7 +724,6 @@ static struct configfs_attribute *target_core_dev_attrib_attrs[] = { &target_core_dev_attrib_hw_block_size.attr, &target_core_dev_attrib_block_size.attr, &target_core_dev_attrib_hw_max_sectors.attr, - &target_core_dev_attrib_max_sectors.attr, &target_core_dev_attrib_fabric_max_sectors.attr, &target_core_dev_attrib_optimal_sectors.attr, &target_core_dev_attrib_hw_queue_depth.attr, @@ -2450,6 +2446,26 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_trans_delay_msecs( SE_DEV_ALUA_TG_PT_ATTR(trans_delay_msecs, S_IRUGO | S_IWUSR); +/* + * implict_trans_secs + */ +static ssize_t target_core_alua_tg_pt_gp_show_attr_implict_trans_secs( + struct t10_alua_tg_pt_gp *tg_pt_gp, + char *page) +{ + return core_alua_show_implict_trans_secs(tg_pt_gp, page); +} + +static ssize_t target_core_alua_tg_pt_gp_store_attr_implict_trans_secs( + struct t10_alua_tg_pt_gp *tg_pt_gp, + const char *page, + size_t count) +{ + return core_alua_store_implict_trans_secs(tg_pt_gp, page, count); +} + +SE_DEV_ALUA_TG_PT_ATTR(implict_trans_secs, S_IRUGO | S_IWUSR); + /* * preferred */ @@ -2574,6 +2590,7 @@ static struct configfs_attribute *target_core_alua_tg_pt_gp_attrs[] = { &target_core_alua_tg_pt_gp_alua_write_metadata.attr, &target_core_alua_tg_pt_gp_nonop_delay_msecs.attr, &target_core_alua_tg_pt_gp_trans_delay_msecs.attr, + &target_core_alua_tg_pt_gp_implict_trans_secs.attr, &target_core_alua_tg_pt_gp_preferred.attr, &target_core_alua_tg_pt_gp_tg_pt_gp_id.attr, &target_core_alua_tg_pt_gp_members.attr, diff --git a/trunk/drivers/target/target_core_device.c b/trunk/drivers/target/target_core_device.c index aa6267746383..5ad972856a8d 100644 --- a/trunk/drivers/target/target_core_device.c +++ b/trunk/drivers/target/target_core_device.c @@ -643,9 +643,8 @@ void core_dev_unexport( lun->lun_se_dev = NULL; } -int target_report_luns(struct se_task *se_task) +int target_report_luns(struct se_cmd *se_cmd) { - struct se_cmd *se_cmd = se_task->task_se_cmd; struct se_dev_entry *deve; struct se_session *se_sess = se_cmd->se_sess; unsigned char *buf; @@ -696,8 +695,7 @@ int target_report_luns(struct se_task *se_task) buf[3] = (lun_count & 0xff); transport_kunmap_data_sg(se_cmd); - se_task->task_scsi_status = GOOD; - transport_complete_task(se_task, 1); + target_complete_cmd(se_cmd, GOOD); return 0; } @@ -878,15 +876,12 @@ void se_dev_set_default_attribs( dev->se_sub_dev->se_dev_attrib.hw_block_size = limits->logical_block_size; dev->se_sub_dev->se_dev_attrib.block_size = limits->logical_block_size; /* - * max_sectors is based on subsystem plugin dependent requirements. + * Align max_hw_sectors down to PAGE_SIZE I/O transfers */ - dev->se_sub_dev->se_dev_attrib.hw_max_sectors = limits->max_hw_sectors; - /* - * Align max_sectors down to PAGE_SIZE to follow transport_allocate_data_tasks() - */ - limits->max_sectors = se_dev_align_max_sectors(limits->max_sectors, + limits->max_hw_sectors = se_dev_align_max_sectors(limits->max_hw_sectors, limits->logical_block_size); - dev->se_sub_dev->se_dev_attrib.max_sectors = limits->max_sectors; + dev->se_sub_dev->se_dev_attrib.hw_max_sectors = limits->max_hw_sectors; + /* * Set fabric_max_sectors, which is reported in block limits * VPD page (B0h). @@ -1170,64 +1165,6 @@ int se_dev_set_queue_depth(struct se_device *dev, u32 queue_depth) return 0; } -int se_dev_set_max_sectors(struct se_device *dev, u32 max_sectors) -{ - int force = 0; /* Force setting for VDEVS */ - - if (atomic_read(&dev->dev_export_obj.obj_access_count)) { - pr_err("dev[%p]: Unable to change SE Device" - " max_sectors while dev_export_obj: %d count exists\n", - dev, atomic_read(&dev->dev_export_obj.obj_access_count)); - return -EINVAL; - } - if (!max_sectors) { - pr_err("dev[%p]: Illegal ZERO value for" - " max_sectors\n", dev); - return -EINVAL; - } - if (max_sectors < DA_STATUS_MAX_SECTORS_MIN) { - pr_err("dev[%p]: Passed max_sectors: %u less than" - " DA_STATUS_MAX_SECTORS_MIN: %u\n", dev, max_sectors, - DA_STATUS_MAX_SECTORS_MIN); - return -EINVAL; - } - if (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) { - if (max_sectors > dev->se_sub_dev->se_dev_attrib.hw_max_sectors) { - pr_err("dev[%p]: Passed max_sectors: %u" - " greater than TCM/SE_Device max_sectors:" - " %u\n", dev, max_sectors, - dev->se_sub_dev->se_dev_attrib.hw_max_sectors); - return -EINVAL; - } - } else { - if (!force && (max_sectors > - dev->se_sub_dev->se_dev_attrib.hw_max_sectors)) { - pr_err("dev[%p]: Passed max_sectors: %u" - " greater than TCM/SE_Device max_sectors" - ": %u, use force=1 to override.\n", dev, - max_sectors, dev->se_sub_dev->se_dev_attrib.hw_max_sectors); - return -EINVAL; - } - if (max_sectors > DA_STATUS_MAX_SECTORS_MAX) { - pr_err("dev[%p]: Passed max_sectors: %u" - " greater than DA_STATUS_MAX_SECTORS_MAX:" - " %u\n", dev, max_sectors, - DA_STATUS_MAX_SECTORS_MAX); - return -EINVAL; - } - } - /* - * Align max_sectors down to PAGE_SIZE to follow transport_allocate_data_tasks() - */ - max_sectors = se_dev_align_max_sectors(max_sectors, - dev->se_sub_dev->se_dev_attrib.block_size); - - dev->se_sub_dev->se_dev_attrib.max_sectors = max_sectors; - pr_debug("dev[%p]: SE Device max_sectors changed to %u\n", - dev, max_sectors); - return 0; -} - int se_dev_set_fabric_max_sectors(struct se_device *dev, u32 fabric_max_sectors) { if (atomic_read(&dev->dev_export_obj.obj_access_count)) { @@ -1341,7 +1278,6 @@ struct se_lun *core_dev_add_lun( u32 lun) { struct se_lun *lun_p; - u32 lun_access = 0; int rc; if (atomic_read(&dev->dev_access_obj.obj_access_count) != 0) { @@ -1354,12 +1290,8 @@ struct se_lun *core_dev_add_lun( if (IS_ERR(lun_p)) return lun_p; - if (dev->dev_flags & DF_READ_ONLY) - lun_access = TRANSPORT_LUNFLAGS_READ_ONLY; - else - lun_access = TRANSPORT_LUNFLAGS_READ_WRITE; - - rc = core_tpg_post_addlun(tpg, lun_p, lun_access, dev); + rc = core_tpg_post_addlun(tpg, lun_p, + TRANSPORT_LUNFLAGS_READ_WRITE, dev); if (rc < 0) return ERR_PTR(rc); diff --git a/trunk/drivers/target/target_core_file.c b/trunk/drivers/target/target_core_file.c index f286955331a2..686dba189f8e 100644 --- a/trunk/drivers/target/target_core_file.c +++ b/trunk/drivers/target/target_core_file.c @@ -133,15 +133,10 @@ static struct se_device *fd_create_virtdevice( ret = PTR_ERR(dev_p); goto fail; } -#if 0 - if (di->no_create_file) - flags = O_RDWR | O_LARGEFILE; - else - flags = O_RDWR | O_CREAT | O_LARGEFILE; -#else + + /* O_DIRECT too? */ flags = O_RDWR | O_CREAT | O_LARGEFILE; -#endif -/* flags |= O_DIRECT; */ + /* * If fd_buffered_io=1 has not been set explicitly (the default), * use O_SYNC to force FILEIO writes to disk. @@ -249,53 +244,33 @@ static void fd_free_device(void *p) kfree(fd_dev); } -static inline struct fd_request *FILE_REQ(struct se_task *task) -{ - return container_of(task, struct fd_request, fd_task); -} - - -static struct se_task * -fd_alloc_task(unsigned char *cdb) +static int fd_do_readv(struct se_cmd *cmd, struct scatterlist *sgl, + u32 sgl_nents) { - struct fd_request *fd_req; - - fd_req = kzalloc(sizeof(struct fd_request), GFP_KERNEL); - if (!fd_req) { - pr_err("Unable to allocate struct fd_request\n"); - return NULL; - } - - return &fd_req->fd_task; -} - -static int fd_do_readv(struct se_task *task) -{ - struct fd_request *req = FILE_REQ(task); - struct se_device *se_dev = req->fd_task.task_se_cmd->se_dev; + struct se_device *se_dev = cmd->se_dev; struct fd_dev *dev = se_dev->dev_ptr; struct file *fd = dev->fd_file; - struct scatterlist *sg = task->task_sg; + struct scatterlist *sg; struct iovec *iov; mm_segment_t old_fs; - loff_t pos = (task->task_lba * + loff_t pos = (cmd->t_task_lba * se_dev->se_sub_dev->se_dev_attrib.block_size); int ret = 0, i; - iov = kzalloc(sizeof(struct iovec) * task->task_sg_nents, GFP_KERNEL); + iov = kzalloc(sizeof(struct iovec) * sgl_nents, GFP_KERNEL); if (!iov) { pr_err("Unable to allocate fd_do_readv iov[]\n"); return -ENOMEM; } - for_each_sg(task->task_sg, sg, task->task_sg_nents, i) { + for_each_sg(sgl, sg, sgl_nents, i) { iov[i].iov_len = sg->length; iov[i].iov_base = sg_virt(sg); } old_fs = get_fs(); set_fs(get_ds()); - ret = vfs_readv(fd, &iov[0], task->task_sg_nents, &pos); + ret = vfs_readv(fd, &iov[0], sgl_nents, &pos); set_fs(old_fs); kfree(iov); @@ -305,10 +280,10 @@ static int fd_do_readv(struct se_task *task) * block_device. */ if (S_ISBLK(fd->f_dentry->d_inode->i_mode)) { - if (ret < 0 || ret != task->task_size) { + if (ret < 0 || ret != cmd->data_length) { pr_err("vfs_readv() returned %d," " expecting %d for S_ISBLK\n", ret, - (int)task->task_size); + (int)cmd->data_length); return (ret < 0 ? ret : -EINVAL); } } else { @@ -322,38 +297,38 @@ static int fd_do_readv(struct se_task *task) return 1; } -static int fd_do_writev(struct se_task *task) +static int fd_do_writev(struct se_cmd *cmd, struct scatterlist *sgl, + u32 sgl_nents) { - struct fd_request *req = FILE_REQ(task); - struct se_device *se_dev = req->fd_task.task_se_cmd->se_dev; + struct se_device *se_dev = cmd->se_dev; struct fd_dev *dev = se_dev->dev_ptr; struct file *fd = dev->fd_file; - struct scatterlist *sg = task->task_sg; + struct scatterlist *sg; struct iovec *iov; mm_segment_t old_fs; - loff_t pos = (task->task_lba * + loff_t pos = (cmd->t_task_lba * se_dev->se_sub_dev->se_dev_attrib.block_size); int ret, i = 0; - iov = kzalloc(sizeof(struct iovec) * task->task_sg_nents, GFP_KERNEL); + iov = kzalloc(sizeof(struct iovec) * sgl_nents, GFP_KERNEL); if (!iov) { pr_err("Unable to allocate fd_do_writev iov[]\n"); return -ENOMEM; } - for_each_sg(task->task_sg, sg, task->task_sg_nents, i) { + for_each_sg(sgl, sg, sgl_nents, i) { iov[i].iov_len = sg->length; iov[i].iov_base = sg_virt(sg); } old_fs = get_fs(); set_fs(get_ds()); - ret = vfs_writev(fd, &iov[0], task->task_sg_nents, &pos); + ret = vfs_writev(fd, &iov[0], sgl_nents, &pos); set_fs(old_fs); kfree(iov); - if (ret < 0 || ret != task->task_size) { + if (ret < 0 || ret != cmd->data_length) { pr_err("vfs_writev() returned %d\n", ret); return (ret < 0 ? ret : -EINVAL); } @@ -361,9 +336,8 @@ static int fd_do_writev(struct se_task *task) return 1; } -static void fd_emulate_sync_cache(struct se_task *task) +static void fd_emulate_sync_cache(struct se_cmd *cmd) { - struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; struct fd_dev *fd_dev = dev->dev_ptr; int immed = (cmd->t_task_cdb[1] & 0x2); @@ -375,7 +349,7 @@ static void fd_emulate_sync_cache(struct se_task *task) * for this SYNCHRONIZE_CACHE op */ if (immed) - transport_complete_sync_cache(cmd, 1); + target_complete_cmd(cmd, SAM_STAT_GOOD); /* * Determine if we will be flushing the entire device. @@ -395,33 +369,37 @@ static void fd_emulate_sync_cache(struct se_task *task) if (ret != 0) pr_err("FILEIO: vfs_fsync_range() failed: %d\n", ret); - if (!immed) - transport_complete_sync_cache(cmd, ret == 0); + if (immed) + return; + + if (ret) { + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + target_complete_cmd(cmd, SAM_STAT_CHECK_CONDITION); + } else { + target_complete_cmd(cmd, SAM_STAT_GOOD); + } } -/* - * WRITE Force Unit Access (FUA) emulation on a per struct se_task - * LBA range basis.. - */ -static void fd_emulate_write_fua(struct se_cmd *cmd, struct se_task *task) +static void fd_emulate_write_fua(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; struct fd_dev *fd_dev = dev->dev_ptr; - loff_t start = task->task_lba * dev->se_sub_dev->se_dev_attrib.block_size; - loff_t end = start + task->task_size; + loff_t start = cmd->t_task_lba * + dev->se_sub_dev->se_dev_attrib.block_size; + loff_t end = start + cmd->data_length; int ret; pr_debug("FILEIO: FUA WRITE LBA: %llu, bytes: %u\n", - task->task_lba, task->task_size); + cmd->t_task_lba, cmd->data_length); ret = vfs_fsync_range(fd_dev->fd_file, start, end, 1); if (ret != 0) pr_err("FILEIO: vfs_fsync_range() failed: %d\n", ret); } -static int fd_do_task(struct se_task *task) +static int fd_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl, + u32 sgl_nents, enum dma_data_direction data_direction) { - struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; int ret = 0; @@ -429,10 +407,10 @@ static int fd_do_task(struct se_task *task) * Call vectorized fileio functions to map struct scatterlist * physical memory addresses to struct iovec virtual memory. */ - if (task->task_data_direction == DMA_FROM_DEVICE) { - ret = fd_do_readv(task); + if (data_direction == DMA_FROM_DEVICE) { + ret = fd_do_readv(cmd, sgl, sgl_nents); } else { - ret = fd_do_writev(task); + ret = fd_do_writev(cmd, sgl, sgl_nents); if (ret > 0 && dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0 && @@ -443,7 +421,7 @@ static int fd_do_task(struct se_task *task) * and return some sense data to let the initiator * know the FUA WRITE cache sync failed..? */ - fd_emulate_write_fua(cmd, task); + fd_emulate_write_fua(cmd); } } @@ -452,24 +430,11 @@ static int fd_do_task(struct se_task *task) cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; return ret; } - if (ret) { - task->task_scsi_status = GOOD; - transport_complete_task(task, 1); - } + if (ret) + target_complete_cmd(cmd, SAM_STAT_GOOD); return 0; } -/* fd_free_task(): (Part of se_subsystem_api_t template) - * - * - */ -static void fd_free_task(struct se_task *task) -{ - struct fd_request *req = FILE_REQ(task); - - kfree(req); -} - enum { Opt_fd_dev_name, Opt_fd_dev_size, Opt_fd_buffered_io, Opt_err }; @@ -632,10 +597,8 @@ static struct se_subsystem_api fileio_template = { .allocate_virtdevice = fd_allocate_virtdevice, .create_virtdevice = fd_create_virtdevice, .free_device = fd_free_device, - .alloc_task = fd_alloc_task, - .do_task = fd_do_task, + .execute_cmd = fd_execute_cmd, .do_sync_cache = fd_emulate_sync_cache, - .free_task = fd_free_task, .check_configfs_dev_params = fd_check_configfs_dev_params, .set_configfs_dev_params = fd_set_configfs_dev_params, .show_configfs_dev_params = fd_show_configfs_dev_params, diff --git a/trunk/drivers/target/target_core_file.h b/trunk/drivers/target/target_core_file.h index 59e6e73106c2..fbd59ef7d8be 100644 --- a/trunk/drivers/target/target_core_file.h +++ b/trunk/drivers/target/target_core_file.h @@ -12,10 +12,6 @@ #define RRF_EMULATE_CDB 0x01 #define RRF_GOT_LBA 0x02 -struct fd_request { - struct se_task fd_task; -}; - #define FBDF_HAS_PATH 0x01 #define FBDF_HAS_SIZE 0x02 #define FDBD_USE_BUFFERED_IO 0x04 diff --git a/trunk/drivers/target/target_core_iblock.c b/trunk/drivers/target/target_core_iblock.c index 2ec299e8a73e..fd47950727b4 100644 --- a/trunk/drivers/target/target_core_iblock.c +++ b/trunk/drivers/target/target_core_iblock.c @@ -189,26 +189,6 @@ static void iblock_free_device(void *p) kfree(ib_dev); } -static inline struct iblock_req *IBLOCK_REQ(struct se_task *task) -{ - return container_of(task, struct iblock_req, ib_task); -} - -static struct se_task * -iblock_alloc_task(unsigned char *cdb) -{ - struct iblock_req *ib_req; - - ib_req = kzalloc(sizeof(struct iblock_req), GFP_KERNEL); - if (!ib_req) { - pr_err("Unable to allocate memory for struct iblock_req\n"); - return NULL; - } - - atomic_set(&ib_req->pending, 1); - return &ib_req->ib_task; -} - static unsigned long long iblock_emulate_read_cap_with_block_size( struct se_device *dev, struct block_device *bd, @@ -295,8 +275,16 @@ static void iblock_end_io_flush(struct bio *bio, int err) if (err) pr_err("IBLOCK: cache flush failed: %d\n", err); - if (cmd) - transport_complete_sync_cache(cmd, err == 0); + if (cmd) { + if (err) { + cmd->scsi_sense_reason = + TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + target_complete_cmd(cmd, SAM_STAT_CHECK_CONDITION); + } else { + target_complete_cmd(cmd, SAM_STAT_GOOD); + } + } + bio_put(bio); } @@ -304,9 +292,8 @@ static void iblock_end_io_flush(struct bio *bio, int err) * Implement SYCHRONIZE CACHE. Note that we can't handle lba ranges and must * always flush the whole cache. */ -static void iblock_emulate_sync_cache(struct se_task *task) +static void iblock_emulate_sync_cache(struct se_cmd *cmd) { - struct se_cmd *cmd = task->task_se_cmd; struct iblock_dev *ib_dev = cmd->se_dev->dev_ptr; int immed = (cmd->t_task_cdb[1] & 0x2); struct bio *bio; @@ -316,7 +303,7 @@ static void iblock_emulate_sync_cache(struct se_task *task) * for this SYNCHRONIZE_CACHE op. */ if (immed) - transport_complete_sync_cache(cmd, 1); + target_complete_cmd(cmd, SAM_STAT_GOOD); bio = bio_alloc(GFP_KERNEL, 0); bio->bi_end_io = iblock_end_io_flush; @@ -335,11 +322,6 @@ static int iblock_do_discard(struct se_device *dev, sector_t lba, u32 range) return blkdev_issue_discard(bd, lba, range, GFP_KERNEL, barrier); } -static void iblock_free_task(struct se_task *task) -{ - kfree(IBLOCK_REQ(task)); -} - enum { Opt_udev_path, Opt_force, Opt_err }; @@ -448,19 +430,35 @@ static ssize_t iblock_show_configfs_dev_params( return bl; } +static void iblock_complete_cmd(struct se_cmd *cmd) +{ + struct iblock_req *ibr = cmd->priv; + u8 status; + + if (!atomic_dec_and_test(&ibr->pending)) + return; + + if (atomic_read(&ibr->ib_bio_err_cnt)) + status = SAM_STAT_CHECK_CONDITION; + else + status = SAM_STAT_GOOD; + + target_complete_cmd(cmd, status); + kfree(ibr); +} + static void iblock_bio_destructor(struct bio *bio) { - struct se_task *task = bio->bi_private; - struct iblock_dev *ib_dev = task->task_se_cmd->se_dev->dev_ptr; + struct se_cmd *cmd = bio->bi_private; + struct iblock_dev *ib_dev = cmd->se_dev->dev_ptr; bio_free(bio, ib_dev->ibd_bio_set); } static struct bio * -iblock_get_bio(struct se_task *task, sector_t lba, u32 sg_num) +iblock_get_bio(struct se_cmd *cmd, sector_t lba, u32 sg_num) { - struct iblock_dev *ib_dev = task->task_se_cmd->se_dev->dev_ptr; - struct iblock_req *ib_req = IBLOCK_REQ(task); + struct iblock_dev *ib_dev = cmd->se_dev->dev_ptr; struct bio *bio; /* @@ -476,19 +474,11 @@ iblock_get_bio(struct se_task *task, sector_t lba, u32 sg_num) return NULL; } - pr_debug("Allocated bio: %p task_sg_nents: %u using ibd_bio_set:" - " %p\n", bio, task->task_sg_nents, ib_dev->ibd_bio_set); - pr_debug("Allocated bio: %p task_size: %u\n", bio, task->task_size); - bio->bi_bdev = ib_dev->ibd_bd; - bio->bi_private = task; + bio->bi_private = cmd; bio->bi_destructor = iblock_bio_destructor; bio->bi_end_io = &iblock_bio_done; bio->bi_sector = lba; - atomic_inc(&ib_req->pending); - - pr_debug("Set bio->bi_sector: %llu\n", (unsigned long long)bio->bi_sector); - pr_debug("Set ib_req->pending: %d\n", atomic_read(&ib_req->pending)); return bio; } @@ -503,20 +493,21 @@ static void iblock_submit_bios(struct bio_list *list, int rw) blk_finish_plug(&plug); } -static int iblock_do_task(struct se_task *task) +static int iblock_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl, + u32 sgl_nents, enum dma_data_direction data_direction) { - struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; - struct iblock_req *ibr = IBLOCK_REQ(task); + struct iblock_req *ibr; struct bio *bio; struct bio_list list; struct scatterlist *sg; - u32 i, sg_num = task->task_sg_nents; + u32 sg_num = sgl_nents; sector_t block_lba; unsigned bio_cnt; int rw; + int i; - if (task->task_data_direction == DMA_TO_DEVICE) { + if (data_direction == DMA_TO_DEVICE) { /* * Force data to disk if we pretend to not have a volatile * write cache, or the initiator set the Force Unit Access bit. @@ -532,17 +523,17 @@ static int iblock_do_task(struct se_task *task) } /* - * Do starting conversion up from non 512-byte blocksize with - * struct se_task SCSI blocksize into Linux/Block 512 units for BIO. + * Convert the blocksize advertised to the initiator to the 512 byte + * units unconditionally used by the Linux block layer. */ if (dev->se_sub_dev->se_dev_attrib.block_size == 4096) - block_lba = (task->task_lba << 3); + block_lba = (cmd->t_task_lba << 3); else if (dev->se_sub_dev->se_dev_attrib.block_size == 2048) - block_lba = (task->task_lba << 2); + block_lba = (cmd->t_task_lba << 2); else if (dev->se_sub_dev->se_dev_attrib.block_size == 1024) - block_lba = (task->task_lba << 1); + block_lba = (cmd->t_task_lba << 1); else if (dev->se_sub_dev->se_dev_attrib.block_size == 512) - block_lba = task->task_lba; + block_lba = cmd->t_task_lba; else { pr_err("Unsupported SCSI -> BLOCK LBA conversion:" " %u\n", dev->se_sub_dev->se_dev_attrib.block_size); @@ -550,17 +541,22 @@ static int iblock_do_task(struct se_task *task) return -ENOSYS; } - bio = iblock_get_bio(task, block_lba, sg_num); - if (!bio) { - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return -ENOMEM; - } + ibr = kzalloc(sizeof(struct iblock_req), GFP_KERNEL); + if (!ibr) + goto fail; + cmd->priv = ibr; + + bio = iblock_get_bio(cmd, block_lba, sgl_nents); + if (!bio) + goto fail_free_ibr; bio_list_init(&list); bio_list_add(&list, bio); + + atomic_set(&ibr->pending, 2); bio_cnt = 1; - for_each_sg(task->task_sg, sg, task->task_sg_nents, i) { + for_each_sg(sgl, sg, sgl_nents, i) { /* * XXX: if the length the device accepts is shorter than the * length of the S/G list entry this will cause and @@ -573,9 +569,11 @@ static int iblock_do_task(struct se_task *task) bio_cnt = 0; } - bio = iblock_get_bio(task, block_lba, sg_num); + bio = iblock_get_bio(cmd, block_lba, sg_num); if (!bio) - goto fail; + goto fail_put_bios; + + atomic_inc(&ibr->pending); bio_list_add(&list, bio); bio_cnt++; } @@ -586,17 +584,16 @@ static int iblock_do_task(struct se_task *task) } iblock_submit_bios(&list, rw); - - if (atomic_dec_and_test(&ibr->pending)) { - transport_complete_task(task, - !atomic_read(&ibr->ib_bio_err_cnt)); - } + iblock_complete_cmd(cmd); return 0; -fail: +fail_put_bios: while ((bio = bio_list_pop(&list))) bio_put(bio); +fail_free_ibr: + kfree(ibr); cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +fail: return -ENOMEM; } @@ -621,8 +618,8 @@ static sector_t iblock_get_blocks(struct se_device *dev) static void iblock_bio_done(struct bio *bio, int err) { - struct se_task *task = bio->bi_private; - struct iblock_req *ibr = IBLOCK_REQ(task); + struct se_cmd *cmd = bio->bi_private; + struct iblock_req *ibr = cmd->priv; /* * Set -EIO if !BIO_UPTODATE and the passed is still err=0 @@ -642,14 +639,7 @@ static void iblock_bio_done(struct bio *bio, int err) bio_put(bio); - if (!atomic_dec_and_test(&ibr->pending)) - return; - - pr_debug("done[%p] bio: %p task_lba: %llu bio_lba: %llu err=%d\n", - task, bio, task->task_lba, - (unsigned long long)bio->bi_sector, err); - - transport_complete_task(task, !atomic_read(&ibr->ib_bio_err_cnt)); + iblock_complete_cmd(cmd); } static struct se_subsystem_api iblock_template = { @@ -663,11 +653,9 @@ static struct se_subsystem_api iblock_template = { .allocate_virtdevice = iblock_allocate_virtdevice, .create_virtdevice = iblock_create_virtdevice, .free_device = iblock_free_device, - .alloc_task = iblock_alloc_task, - .do_task = iblock_do_task, + .execute_cmd = iblock_execute_cmd, .do_discard = iblock_do_discard, .do_sync_cache = iblock_emulate_sync_cache, - .free_task = iblock_free_task, .check_configfs_dev_params = iblock_check_configfs_dev_params, .set_configfs_dev_params = iblock_set_configfs_dev_params, .show_configfs_dev_params = iblock_show_configfs_dev_params, diff --git a/trunk/drivers/target/target_core_iblock.h b/trunk/drivers/target/target_core_iblock.h index e929370b6fd3..66cf7b9e205e 100644 --- a/trunk/drivers/target/target_core_iblock.h +++ b/trunk/drivers/target/target_core_iblock.h @@ -7,7 +7,6 @@ #define IBLOCK_LBA_SHIFT 9 struct iblock_req { - struct se_task ib_task; atomic_t pending; atomic_t ib_bio_err_cnt; } ____cacheline_aligned; diff --git a/trunk/drivers/target/target_core_internal.h b/trunk/drivers/target/target_core_internal.h index 21c05638f158..165e82429687 100644 --- a/trunk/drivers/target/target_core_internal.h +++ b/trunk/drivers/target/target_core_internal.h @@ -5,15 +5,15 @@ extern struct t10_alua_lu_gp *default_lu_gp; /* target_core_cdb.c */ -int target_emulate_inquiry(struct se_task *task); -int target_emulate_readcapacity(struct se_task *task); -int target_emulate_readcapacity_16(struct se_task *task); -int target_emulate_modesense(struct se_task *task); -int target_emulate_request_sense(struct se_task *task); -int target_emulate_unmap(struct se_task *task); -int target_emulate_write_same(struct se_task *task); -int target_emulate_synchronize_cache(struct se_task *task); -int target_emulate_noop(struct se_task *task); +int target_emulate_inquiry(struct se_cmd *cmd); +int target_emulate_readcapacity(struct se_cmd *cmd); +int target_emulate_readcapacity_16(struct se_cmd *cmd); +int target_emulate_modesense(struct se_cmd *cmd); +int target_emulate_request_sense(struct se_cmd *cmd); +int target_emulate_unmap(struct se_cmd *cmd); +int target_emulate_write_same(struct se_cmd *cmd); +int target_emulate_synchronize_cache(struct se_cmd *cmd); +int target_emulate_noop(struct se_cmd *cmd); /* target_core_device.c */ struct se_dev_entry *core_get_se_deve_from_rtpi(struct se_node_acl *, u16); @@ -28,7 +28,7 @@ int core_dev_export(struct se_device *, struct se_portal_group *, struct se_lun *); void core_dev_unexport(struct se_device *, struct se_portal_group *, struct se_lun *); -int target_report_luns(struct se_task *); +int target_report_luns(struct se_cmd *); void se_release_device_for_hba(struct se_device *); void se_release_vpd_for_dev(struct se_device *); int se_free_virtual_device(struct se_device *, struct se_hba *); @@ -104,8 +104,7 @@ void release_se_kmem_caches(void); u32 scsi_get_new_index(scsi_index_t); void transport_subsystem_check_init(void); void transport_cmd_finish_abort(struct se_cmd *, int); -void __transport_remove_task_from_execute_queue(struct se_task *, - struct se_device *); +void __target_remove_from_execute_list(struct se_cmd *); unsigned char *transport_dump_cmd_direction(struct se_cmd *); void transport_dump_dev_state(struct se_device *, char *, int *); void transport_dump_dev_info(struct se_device *, struct se_lun *, @@ -114,7 +113,7 @@ void transport_dump_vpd_proto_id(struct t10_vpd *, unsigned char *, int); int transport_dump_vpd_assoc(struct t10_vpd *, unsigned char *, int); int transport_dump_vpd_ident_type(struct t10_vpd *, unsigned char *, int); int transport_dump_vpd_ident(struct t10_vpd *, unsigned char *, int); -bool target_stop_task(struct se_task *task, unsigned long *flags); +bool target_stop_cmd(struct se_cmd *cmd, unsigned long *flags); int transport_clear_lun_from_sessions(struct se_lun *); void transport_send_task_abort(struct se_cmd *); diff --git a/trunk/drivers/target/target_core_pr.c b/trunk/drivers/target/target_core_pr.c index c3148b10b4b3..85564998500a 100644 --- a/trunk/drivers/target/target_core_pr.c +++ b/trunk/drivers/target/target_core_pr.c @@ -193,9 +193,8 @@ static int target_check_scsi2_reservation_conflict(struct se_cmd *cmd) return 0; } -int target_scsi2_reservation_release(struct se_task *task) +int target_scsi2_reservation_release(struct se_cmd *cmd) { - struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; struct se_session *sess = cmd->se_sess; struct se_portal_group *tpg = sess->se_tpg; @@ -237,16 +236,13 @@ int target_scsi2_reservation_release(struct se_task *task) out_unlock: spin_unlock(&dev->dev_reservation_lock); out: - if (!ret) { - task->task_scsi_status = GOOD; - transport_complete_task(task, 1); - } + if (!ret) + target_complete_cmd(cmd, GOOD); return ret; } -int target_scsi2_reservation_reserve(struct se_task *task) +int target_scsi2_reservation_reserve(struct se_cmd *cmd) { - struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; struct se_session *sess = cmd->se_sess; struct se_portal_group *tpg = sess->se_tpg; @@ -307,10 +303,8 @@ int target_scsi2_reservation_reserve(struct se_task *task) out_unlock: spin_unlock(&dev->dev_reservation_lock); out: - if (!ret) { - task->task_scsi_status = GOOD; - transport_complete_task(task, 1); - } + if (!ret) + target_complete_cmd(cmd, GOOD); return ret; } @@ -503,11 +497,10 @@ static int core_scsi3_pr_seq_non_holder( * statement. */ if (!ret && !other_cdb) { -#if 0 pr_debug("Allowing explict CDB: 0x%02x for %s" " reservation holder\n", cdb[0], core_scsi3_pr_dump_type(pr_reg_type)); -#endif + return ret; } /* @@ -535,14 +528,14 @@ static int core_scsi3_pr_seq_non_holder( * as we expect registered non-reservation holding * nexuses to issue CDBs. */ -#if 0 + if (!registered_nexus) { pr_debug("Allowing implict CDB: 0x%02x" " for %s reservation on unregistered" " nexus\n", cdb[0], core_scsi3_pr_dump_type(pr_reg_type)); } -#endif + return 0; } } else if ((reg_only) || (all_reg)) { @@ -551,11 +544,11 @@ static int core_scsi3_pr_seq_non_holder( * For PR_*_REG_ONLY and PR_*_ALL_REG reservations, * allow commands from registered nexuses. */ -#if 0 + pr_debug("Allowing implict CDB: 0x%02x for %s" " reservation\n", cdb[0], core_scsi3_pr_dump_type(pr_reg_type)); -#endif + return 0; } } @@ -1669,12 +1662,12 @@ static int core_scsi3_decode_spec_i_port( ret = -EINVAL; goto out; } -#if 0 + pr_debug("SPC-3 PR SPEC_I_PT: Got %s data_length: %u tpdl: %u" " tid_len: %d for %s + %s\n", dest_tpg->se_tpg_tfo->get_fabric_name(), cmd->data_length, tpdl, tid_len, i_str, iport_ptr); -#endif + if (tid_len > tpdl) { pr_err("SPC-3 PR SPEC_I_PT: Illegal tid_len:" " %u for Transport ID: %s\n", tid_len, ptr); @@ -1717,12 +1710,12 @@ static int core_scsi3_decode_spec_i_port( ret = -EINVAL; goto out; } -#if 0 + pr_debug("SPC-3 PR SPEC_I_PT: Located %s Node: %s" " dest_se_deve mapped_lun: %u\n", dest_tpg->se_tpg_tfo->get_fabric_name(), dest_node_acl->initiatorname, dest_se_deve->mapped_lun); -#endif + /* * Skip any TransportIDs that already have a registration for * this target port. @@ -3476,10 +3469,10 @@ static int core_scsi3_emulate_pro_register_and_move( buf = transport_kmap_data_sg(cmd); proto_ident = (buf[24] & 0x0f); -#if 0 + pr_debug("SPC-3 PR REGISTER_AND_MOVE: Extracted Protocol Identifier:" " 0x%02x\n", proto_ident); -#endif + if (proto_ident != dest_tf_ops->get_fabric_proto_ident(dest_se_tpg)) { pr_err("SPC-3 PR REGISTER_AND_MOVE: Received" " proto_ident: 0x%02x does not match ident: 0x%02x" @@ -3578,11 +3571,11 @@ static int core_scsi3_emulate_pro_register_and_move( ret = -EINVAL; goto out; } -#if 0 + pr_debug("SPC-3 PR REGISTER_AND_MOVE: Found %s dest_node_acl:" " %s from TransportID\n", dest_tf_ops->get_fabric_name(), dest_node_acl->initiatorname); -#endif + /* * Locate the struct se_dev_entry pointer for the matching RELATIVE TARGET * PORT IDENTIFIER. @@ -3606,12 +3599,12 @@ static int core_scsi3_emulate_pro_register_and_move( ret = -EINVAL; goto out; } -#if 0 + pr_debug("SPC-3 PR REGISTER_AND_MOVE: Located %s node %s LUN" " ACL for dest_se_deve->mapped_lun: %u\n", dest_tf_ops->get_fabric_name(), dest_node_acl->initiatorname, dest_se_deve->mapped_lun); -#endif + /* * A persistent reservation needs to already existing in order to * successfully complete the REGISTER_AND_MOVE service action.. @@ -3802,9 +3795,8 @@ static unsigned long long core_scsi3_extract_reservation_key(unsigned char *cdb) /* * See spc4r17 section 6.14 Table 170 */ -int target_scsi3_emulate_pr_out(struct se_task *task) +int target_scsi3_emulate_pr_out(struct se_cmd *cmd) { - struct se_cmd *cmd = task->task_se_cmd; unsigned char *cdb = &cmd->t_task_cdb[0]; unsigned char *buf; u64 res_key, sa_res_key; @@ -3944,10 +3936,8 @@ int target_scsi3_emulate_pr_out(struct se_task *task) } out: - if (!ret) { - task->task_scsi_status = GOOD; - transport_complete_task(task, 1); - } + if (!ret) + target_complete_cmd(cmd, GOOD); return ret; } @@ -4302,9 +4292,8 @@ static int core_scsi3_pri_read_full_status(struct se_cmd *cmd) return 0; } -int target_scsi3_emulate_pr_in(struct se_task *task) +int target_scsi3_emulate_pr_in(struct se_cmd *cmd) { - struct se_cmd *cmd = task->task_se_cmd; int ret; /* @@ -4345,10 +4334,8 @@ int target_scsi3_emulate_pr_in(struct se_task *task) break; } - if (!ret) { - task->task_scsi_status = GOOD; - transport_complete_task(task, 1); - } + if (!ret) + target_complete_cmd(cmd, GOOD); return ret; } diff --git a/trunk/drivers/target/target_core_pr.h b/trunk/drivers/target/target_core_pr.h index 7a233feb7e99..af6c460d886d 100644 --- a/trunk/drivers/target/target_core_pr.h +++ b/trunk/drivers/target/target_core_pr.h @@ -47,8 +47,8 @@ extern struct kmem_cache *t10_pr_reg_cache; extern int core_pr_dump_initiator_port(struct t10_pr_registration *, char *, u32); -extern int target_scsi2_reservation_release(struct se_task *task); -extern int target_scsi2_reservation_reserve(struct se_task *task); +extern int target_scsi2_reservation_release(struct se_cmd *); +extern int target_scsi2_reservation_reserve(struct se_cmd *); extern int core_scsi3_alloc_aptpl_registration( struct t10_reservation *, u64, unsigned char *, unsigned char *, u32, @@ -61,8 +61,8 @@ extern void core_scsi3_free_pr_reg_from_nacl(struct se_device *, extern void core_scsi3_free_all_registrations(struct se_device *); extern unsigned char *core_scsi3_pr_dump_type(int); -extern int target_scsi3_emulate_pr_in(struct se_task *task); -extern int target_scsi3_emulate_pr_out(struct se_task *task); +extern int target_scsi3_emulate_pr_in(struct se_cmd *); +extern int target_scsi3_emulate_pr_out(struct se_cmd *); extern int core_setup_reservations(struct se_device *, int); #endif /* TARGET_CORE_PR_H */ diff --git a/trunk/drivers/target/target_core_pscsi.c b/trunk/drivers/target/target_core_pscsi.c index 94c905fcbceb..4ce2cf642fce 100644 --- a/trunk/drivers/target/target_core_pscsi.c +++ b/trunk/drivers/target/target_core_pscsi.c @@ -663,22 +663,12 @@ static void pscsi_free_device(void *p) kfree(pdv); } -static inline struct pscsi_plugin_task *PSCSI_TASK(struct se_task *task) +static int pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg) { - return container_of(task, struct pscsi_plugin_task, pscsi_task); -} - - -/* pscsi_transport_complete(): - * - * - */ -static int pscsi_transport_complete(struct se_task *task) -{ - struct pscsi_dev_virt *pdv = task->task_se_cmd->se_dev->dev_ptr; + struct pscsi_dev_virt *pdv = cmd->se_dev->dev_ptr; struct scsi_device *sd = pdv->pdv_sd; int result; - struct pscsi_plugin_task *pt = PSCSI_TASK(task); + struct pscsi_plugin_task *pt = cmd->priv; unsigned char *cdb = &pt->pscsi_cdb[0]; result = pt->pscsi_result; @@ -688,12 +678,11 @@ static int pscsi_transport_complete(struct se_task *task) */ if (((cdb[0] == MODE_SENSE) || (cdb[0] == MODE_SENSE_10)) && (status_byte(result) << 1) == SAM_STAT_GOOD) { - if (!task->task_se_cmd->se_deve) + if (!cmd->se_deve) goto after_mode_sense; - if (task->task_se_cmd->se_deve->lun_flags & - TRANSPORT_LUNFLAGS_READ_ONLY) { - unsigned char *buf = transport_kmap_data_sg(task->task_se_cmd); + if (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY) { + unsigned char *buf = transport_kmap_data_sg(cmd); if (cdb[0] == MODE_SENSE_10) { if (!(buf[3] & 0x80)) @@ -703,7 +692,7 @@ static int pscsi_transport_complete(struct se_task *task) buf[2] |= 0x80; } - transport_kunmap_data_sg(task->task_se_cmd); + transport_kunmap_data_sg(cmd); } } after_mode_sense: @@ -722,7 +711,6 @@ static int pscsi_transport_complete(struct se_task *task) if (((cdb[0] == MODE_SELECT) || (cdb[0] == MODE_SELECT_10)) && (status_byte(result) << 1) == SAM_STAT_GOOD) { unsigned char *buf; - struct scatterlist *sg = task->task_sg; u16 bdl; u32 blocksize; @@ -757,35 +745,6 @@ static int pscsi_transport_complete(struct se_task *task) return 0; } -static struct se_task * -pscsi_alloc_task(unsigned char *cdb) -{ - struct pscsi_plugin_task *pt; - - /* - * Dynamically alloc cdb space, since it may be larger than - * TCM_MAX_COMMAND_SIZE - */ - pt = kzalloc(sizeof(*pt) + scsi_command_size(cdb), GFP_KERNEL); - if (!pt) { - pr_err("Unable to allocate struct pscsi_plugin_task\n"); - return NULL; - } - - return &pt->pscsi_task; -} - -static void pscsi_free_task(struct se_task *task) -{ - struct pscsi_plugin_task *pt = PSCSI_TASK(task); - - /* - * We do not release the bio(s) here associated with this task, as - * this is handled by bio_put() and pscsi_bi_endio(). - */ - kfree(pt); -} - enum { Opt_scsi_host_id, Opt_scsi_channel_id, Opt_scsi_target_id, Opt_scsi_lun_id, Opt_err @@ -958,26 +917,25 @@ static inline struct bio *pscsi_get_bio(int sg_num) return bio; } -static int pscsi_map_sg(struct se_task *task, struct scatterlist *task_sg, +static int pscsi_map_sg(struct se_cmd *cmd, struct scatterlist *sgl, + u32 sgl_nents, enum dma_data_direction data_direction, struct bio **hbio) { - struct se_cmd *cmd = task->task_se_cmd; - struct pscsi_dev_virt *pdv = task->task_se_cmd->se_dev->dev_ptr; - u32 task_sg_num = task->task_sg_nents; + struct pscsi_dev_virt *pdv = cmd->se_dev->dev_ptr; struct bio *bio = NULL, *tbio = NULL; struct page *page; struct scatterlist *sg; - u32 data_len = task->task_size, i, len, bytes, off; - int nr_pages = (task->task_size + task_sg[0].offset + + u32 data_len = cmd->data_length, i, len, bytes, off; + int nr_pages = (cmd->data_length + sgl[0].offset + PAGE_SIZE - 1) >> PAGE_SHIFT; int nr_vecs = 0, rc; - int rw = (task->task_data_direction == DMA_TO_DEVICE); + int rw = (data_direction == DMA_TO_DEVICE); *hbio = NULL; pr_debug("PSCSI: nr_pages: %d\n", nr_pages); - for_each_sg(task_sg, sg, task_sg_num, i) { + for_each_sg(sgl, sg, sgl_nents, i) { page = sg_page(sg); off = sg->offset; len = sg->length; @@ -1009,7 +967,7 @@ static int pscsi_map_sg(struct se_task *task, struct scatterlist *task_sg, * Set *hbio pointer to handle the case: * nr_pages > BIO_MAX_PAGES, where additional * bios need to be added to complete a given - * struct se_task + * command. */ if (!*hbio) *hbio = tbio = bio; @@ -1049,7 +1007,7 @@ static int pscsi_map_sg(struct se_task *task, struct scatterlist *task_sg, } } - return task->task_sg_nents; + return sgl_nents; fail: while (*hbio) { bio = *hbio; @@ -1061,52 +1019,61 @@ static int pscsi_map_sg(struct se_task *task, struct scatterlist *task_sg, return -ENOMEM; } -static int pscsi_do_task(struct se_task *task) +static int pscsi_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl, + u32 sgl_nents, enum dma_data_direction data_direction) { - struct se_cmd *cmd = task->task_se_cmd; - struct pscsi_dev_virt *pdv = task->task_se_cmd->se_dev->dev_ptr; - struct pscsi_plugin_task *pt = PSCSI_TASK(task); + struct pscsi_dev_virt *pdv = cmd->se_dev->dev_ptr; + struct pscsi_plugin_task *pt; struct request *req; struct bio *hbio; int ret; - target_get_task_cdb(task, pt->pscsi_cdb); + /* + * Dynamically alloc cdb space, since it may be larger than + * TCM_MAX_COMMAND_SIZE + */ + pt = kzalloc(sizeof(*pt) + scsi_command_size(cmd->t_task_cdb), GFP_KERNEL); + if (!pt) { + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return -ENOMEM; + } + cmd->priv = pt; + + memcpy(pt->pscsi_cdb, cmd->t_task_cdb, + scsi_command_size(cmd->t_task_cdb)); - if (task->task_se_cmd->se_cmd_flags & SCF_SCSI_NON_DATA_CDB) { + if (cmd->se_cmd_flags & SCF_SCSI_NON_DATA_CDB) { req = blk_get_request(pdv->pdv_sd->request_queue, - (task->task_data_direction == DMA_TO_DEVICE), + (data_direction == DMA_TO_DEVICE), GFP_KERNEL); if (!req || IS_ERR(req)) { pr_err("PSCSI: blk_get_request() failed: %ld\n", req ? IS_ERR(req) : -ENOMEM); cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return -ENODEV; + goto fail; } } else { - BUG_ON(!task->task_size); + BUG_ON(!cmd->data_length); - /* - * Setup the main struct request for the task->task_sg[] payload - */ - ret = pscsi_map_sg(task, task->task_sg, &hbio); + ret = pscsi_map_sg(cmd, sgl, sgl_nents, data_direction, &hbio); if (ret < 0) { cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - return ret; + goto fail; } req = blk_make_request(pdv->pdv_sd->request_queue, hbio, GFP_KERNEL); if (IS_ERR(req)) { pr_err("pSCSI: blk_make_request() failed\n"); - goto fail; + goto fail_free_bio; } } req->cmd_type = REQ_TYPE_BLOCK_PC; req->end_io = pscsi_req_done; - req->end_io_data = task; + req->end_io_data = cmd; req->cmd_len = scsi_command_size(pt->pscsi_cdb); req->cmd = &pt->pscsi_cdb[0]; req->sense = &pt->pscsi_sense[0]; @@ -1118,12 +1085,12 @@ static int pscsi_do_task(struct se_task *task) req->retries = PS_RETRY; blk_execute_rq_nowait(pdv->pdv_sd->request_queue, NULL, req, - (task->task_se_cmd->sam_task_attr == MSG_HEAD_TAG), + (cmd->sam_task_attr == MSG_HEAD_TAG), pscsi_req_done); return 0; -fail: +fail_free_bio: while (hbio) { struct bio *bio = hbio; hbio = hbio->bi_next; @@ -1131,16 +1098,14 @@ static int pscsi_do_task(struct se_task *task) bio_endio(bio, 0); /* XXX: should be error */ } cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +fail: + kfree(pt); return -ENOMEM; } -/* pscsi_get_sense_buffer(): - * - * - */ -static unsigned char *pscsi_get_sense_buffer(struct se_task *task) +static unsigned char *pscsi_get_sense_buffer(struct se_cmd *cmd) { - struct pscsi_plugin_task *pt = PSCSI_TASK(task); + struct pscsi_plugin_task *pt = cmd->priv; return pt->pscsi_sense; } @@ -1180,48 +1145,36 @@ static sector_t pscsi_get_blocks(struct se_device *dev) return 0; } -/* pscsi_handle_SAM_STATUS_failures(): - * - * - */ -static inline void pscsi_process_SAM_status( - struct se_task *task, - struct pscsi_plugin_task *pt) +static void pscsi_req_done(struct request *req, int uptodate) { - task->task_scsi_status = status_byte(pt->pscsi_result); - if (task->task_scsi_status) { - task->task_scsi_status <<= 1; - pr_debug("PSCSI Status Byte exception at task: %p CDB:" - " 0x%02x Result: 0x%08x\n", task, pt->pscsi_cdb[0], + struct se_cmd *cmd = req->end_io_data; + struct pscsi_plugin_task *pt = cmd->priv; + + pt->pscsi_result = req->errors; + pt->pscsi_resid = req->resid_len; + + cmd->scsi_status = status_byte(pt->pscsi_result) << 1; + if (cmd->scsi_status) { + pr_debug("PSCSI Status Byte exception at cmd: %p CDB:" + " 0x%02x Result: 0x%08x\n", cmd, pt->pscsi_cdb[0], pt->pscsi_result); } switch (host_byte(pt->pscsi_result)) { case DID_OK: - transport_complete_task(task, (!task->task_scsi_status)); + target_complete_cmd(cmd, cmd->scsi_status); break; default: - pr_debug("PSCSI Host Byte exception at task: %p CDB:" - " 0x%02x Result: 0x%08x\n", task, pt->pscsi_cdb[0], + pr_debug("PSCSI Host Byte exception at cmd: %p CDB:" + " 0x%02x Result: 0x%08x\n", cmd, pt->pscsi_cdb[0], pt->pscsi_result); - task->task_scsi_status = SAM_STAT_CHECK_CONDITION; - task->task_se_cmd->scsi_sense_reason = - TCM_UNSUPPORTED_SCSI_OPCODE; - transport_complete_task(task, 0); + cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; + target_complete_cmd(cmd, SAM_STAT_CHECK_CONDITION); break; } -} -static void pscsi_req_done(struct request *req, int uptodate) -{ - struct se_task *task = req->end_io_data; - struct pscsi_plugin_task *pt = PSCSI_TASK(task); - - pt->pscsi_result = req->errors; - pt->pscsi_resid = req->resid_len; - - pscsi_process_SAM_status(task, pt); __blk_put_request(req->q, req); + kfree(pt); } static struct se_subsystem_api pscsi_template = { @@ -1235,9 +1188,7 @@ static struct se_subsystem_api pscsi_template = { .create_virtdevice = pscsi_create_virtdevice, .free_device = pscsi_free_device, .transport_complete = pscsi_transport_complete, - .alloc_task = pscsi_alloc_task, - .do_task = pscsi_do_task, - .free_task = pscsi_free_task, + .execute_cmd = pscsi_execute_cmd, .check_configfs_dev_params = pscsi_check_configfs_dev_params, .set_configfs_dev_params = pscsi_set_configfs_dev_params, .show_configfs_dev_params = pscsi_show_configfs_dev_params, diff --git a/trunk/drivers/target/target_core_pscsi.h b/trunk/drivers/target/target_core_pscsi.h index 43f1c419e8e5..bc1e5e11eca0 100644 --- a/trunk/drivers/target/target_core_pscsi.h +++ b/trunk/drivers/target/target_core_pscsi.h @@ -22,7 +22,6 @@ #include struct pscsi_plugin_task { - struct se_task pscsi_task; unsigned char pscsi_sense[SCSI_SENSE_BUFFERSIZE]; int pscsi_direction; int pscsi_result; diff --git a/trunk/drivers/target/target_core_rd.c b/trunk/drivers/target/target_core_rd.c index 8b68f7b82631..d0ceb873c0e5 100644 --- a/trunk/drivers/target/target_core_rd.c +++ b/trunk/drivers/target/target_core_rd.c @@ -64,9 +64,6 @@ static int rd_attach_hba(struct se_hba *hba, u32 host_id) pr_debug("CORE_HBA[%d] - TCM Ramdisk HBA Driver %s on" " Generic Target Core Stack %s\n", hba->hba_id, RD_HBA_VERSION, TARGET_CORE_MOD_VERSION); - pr_debug("CORE_HBA[%d] - Attached Ramdisk HBA: %u to Generic" - " MaxSectors: %u\n", hba->hba_id, - rd_host->rd_host_id, RD_MAX_SECTORS); return 0; } @@ -199,10 +196,7 @@ static int rd_build_device_space(struct rd_dev *rd_dev) return 0; } -static void *rd_allocate_virtdevice( - struct se_hba *hba, - const char *name, - int rd_direct) +static void *rd_allocate_virtdevice(struct se_hba *hba, const char *name) { struct rd_dev *rd_dev; struct rd_host *rd_host = hba->hba_ptr; @@ -214,25 +208,12 @@ static void *rd_allocate_virtdevice( } rd_dev->rd_host = rd_host; - rd_dev->rd_direct = rd_direct; return rd_dev; } -static void *rd_MEMCPY_allocate_virtdevice(struct se_hba *hba, const char *name) -{ - return rd_allocate_virtdevice(hba, name, 0); -} - -/* rd_create_virtdevice(): - * - * - */ -static struct se_device *rd_create_virtdevice( - struct se_hba *hba, - struct se_subsystem_dev *se_dev, - void *p, - int rd_direct) +static struct se_device *rd_create_virtdevice(struct se_hba *hba, + struct se_subsystem_dev *se_dev, void *p) { struct se_device *dev; struct se_dev_limits dev_limits; @@ -247,13 +228,12 @@ static struct se_device *rd_create_virtdevice( if (ret < 0) goto fail; - snprintf(prod, 16, "RAMDISK-%s", (rd_dev->rd_direct) ? "DR" : "MCP"); - snprintf(rev, 4, "%s", (rd_dev->rd_direct) ? RD_DR_VERSION : - RD_MCP_VERSION); + snprintf(prod, 16, "RAMDISK-MCP"); + snprintf(rev, 4, "%s", RD_MCP_VERSION); dev_limits.limits.logical_block_size = RD_BLOCKSIZE; - dev_limits.limits.max_hw_sectors = RD_MAX_SECTORS; - dev_limits.limits.max_sectors = RD_MAX_SECTORS; + dev_limits.limits.max_hw_sectors = UINT_MAX; + dev_limits.limits.max_sectors = UINT_MAX; dev_limits.hw_queue_depth = RD_MAX_DEVICE_QUEUE_DEPTH; dev_limits.queue_depth = RD_DEVICE_QUEUE_DEPTH; @@ -264,12 +244,10 @@ static struct se_device *rd_create_virtdevice( goto fail; rd_dev->rd_dev_id = rd_host->rd_host_dev_id_count++; - rd_dev->rd_queue_depth = dev->queue_depth; - pr_debug("CORE_RD[%u] - Added TCM %s Ramdisk Device ID: %u of" + pr_debug("CORE_RD[%u] - Added TCM MEMCPY Ramdisk Device ID: %u of" " %u pages in %u tables, %lu total bytes\n", - rd_host->rd_host_id, (!rd_dev->rd_direct) ? "MEMCPY" : - "DIRECT", rd_dev->rd_dev_id, rd_dev->rd_page_count, + rd_host->rd_host_id, rd_dev->rd_dev_id, rd_dev->rd_page_count, rd_dev->sg_table_count, (unsigned long)(rd_dev->rd_page_count * PAGE_SIZE)); @@ -280,18 +258,6 @@ static struct se_device *rd_create_virtdevice( return ERR_PTR(ret); } -static struct se_device *rd_MEMCPY_create_virtdevice( - struct se_hba *hba, - struct se_subsystem_dev *se_dev, - void *p) -{ - return rd_create_virtdevice(hba, se_dev, p, 0); -} - -/* rd_free_device(): (Part of se_subsystem_api_t template) - * - * - */ static void rd_free_device(void *p) { struct rd_dev *rd_dev = p; @@ -300,29 +266,6 @@ static void rd_free_device(void *p) kfree(rd_dev); } -static inline struct rd_request *RD_REQ(struct se_task *task) -{ - return container_of(task, struct rd_request, rd_task); -} - -static struct se_task * -rd_alloc_task(unsigned char *cdb) -{ - struct rd_request *rd_req; - - rd_req = kzalloc(sizeof(struct rd_request), GFP_KERNEL); - if (!rd_req) { - pr_err("Unable to allocate struct rd_request\n"); - return NULL; - } - - return &rd_req->rd_task; -} - -/* rd_get_sg_table(): - * - * - */ static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page) { u32 i; @@ -341,31 +284,41 @@ static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page) return NULL; } -static int rd_MEMCPY(struct rd_request *req, u32 read_rd) +static int rd_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl, + u32 sgl_nents, enum dma_data_direction data_direction) { - struct se_task *task = &req->rd_task; - struct rd_dev *dev = req->rd_task.task_se_cmd->se_dev->dev_ptr; + struct se_device *se_dev = cmd->se_dev; + struct rd_dev *dev = se_dev->dev_ptr; struct rd_dev_sg_table *table; struct scatterlist *rd_sg; struct sg_mapping_iter m; - u32 rd_offset = req->rd_offset; + u32 rd_offset; + u32 rd_size; + u32 rd_page; u32 src_len; + u64 tmp; + + tmp = cmd->t_task_lba * se_dev->se_sub_dev->se_dev_attrib.block_size; + rd_offset = do_div(tmp, PAGE_SIZE); + rd_page = tmp; + rd_size = cmd->data_length; - table = rd_get_sg_table(dev, req->rd_page); + table = rd_get_sg_table(dev, rd_page); if (!table) return -EINVAL; - rd_sg = &table->sg_table[req->rd_page - table->page_start_offset]; + rd_sg = &table->sg_table[rd_page - table->page_start_offset]; pr_debug("RD[%u]: %s LBA: %llu, Size: %u Page: %u, Offset: %u\n", - dev->rd_dev_id, read_rd ? "Read" : "Write", - task->task_lba, req->rd_size, req->rd_page, - rd_offset); + dev->rd_dev_id, + data_direction == DMA_FROM_DEVICE ? "Read" : "Write", + cmd->t_task_lba, rd_size, rd_page, rd_offset); src_len = PAGE_SIZE - rd_offset; - sg_miter_start(&m, task->task_sg, task->task_sg_nents, - read_rd ? SG_MITER_TO_SG : SG_MITER_FROM_SG); - while (req->rd_size) { + sg_miter_start(&m, sgl, sgl_nents, + data_direction == DMA_FROM_DEVICE ? + SG_MITER_TO_SG : SG_MITER_FROM_SG); + while (rd_size) { u32 len; void *rd_addr; @@ -375,13 +328,13 @@ static int rd_MEMCPY(struct rd_request *req, u32 read_rd) rd_addr = sg_virt(rd_sg) + rd_offset; - if (read_rd) + if (data_direction == DMA_FROM_DEVICE) memcpy(m.addr, rd_addr, len); else memcpy(rd_addr, m.addr, len); - req->rd_size -= len; - if (!req->rd_size) + rd_size -= len; + if (!rd_size) continue; src_len -= len; @@ -391,15 +344,15 @@ static int rd_MEMCPY(struct rd_request *req, u32 read_rd) } /* rd page completed, next one please */ - req->rd_page++; + rd_page++; rd_offset = 0; src_len = PAGE_SIZE; - if (req->rd_page <= table->page_end_offset) { + if (rd_page <= table->page_end_offset) { rd_sg++; continue; } - table = rd_get_sg_table(dev, req->rd_page); + table = rd_get_sg_table(dev, rd_page); if (!table) { sg_miter_stop(&m); return -EINVAL; @@ -409,43 +362,11 @@ static int rd_MEMCPY(struct rd_request *req, u32 read_rd) rd_sg = table->sg_table; } sg_miter_stop(&m); - return 0; -} -/* rd_MEMCPY_do_task(): (Part of se_subsystem_api_t template) - * - * - */ -static int rd_MEMCPY_do_task(struct se_task *task) -{ - struct se_device *dev = task->task_se_cmd->se_dev; - struct rd_request *req = RD_REQ(task); - u64 tmp; - int ret; - - tmp = task->task_lba * dev->se_sub_dev->se_dev_attrib.block_size; - req->rd_offset = do_div(tmp, PAGE_SIZE); - req->rd_page = tmp; - req->rd_size = task->task_size; - - ret = rd_MEMCPY(req, task->task_data_direction == DMA_FROM_DEVICE); - if (ret != 0) - return ret; - - task->task_scsi_status = GOOD; - transport_complete_task(task, 1); + target_complete_cmd(cmd, SAM_STAT_GOOD); return 0; } -/* rd_free_task(): (Part of se_subsystem_api_t template) - * - * - */ -static void rd_free_task(struct se_task *task) -{ - kfree(RD_REQ(task)); -} - enum { Opt_rd_pages, Opt_err }; @@ -512,9 +433,8 @@ static ssize_t rd_show_configfs_dev_params( char *b) { struct rd_dev *rd_dev = se_dev->se_dev_su_ptr; - ssize_t bl = sprintf(b, "TCM RamDisk ID: %u RamDisk Makeup: %s\n", - rd_dev->rd_dev_id, (rd_dev->rd_direct) ? - "rd_direct" : "rd_mcp"); + ssize_t bl = sprintf(b, "TCM RamDisk ID: %u RamDisk Makeup: rd_mcp\n", + rd_dev->rd_dev_id); bl += sprintf(b + bl, " PAGES/PAGE_SIZE: %u*%lu" " SG_table_count: %u\n", rd_dev->rd_page_count, PAGE_SIZE, rd_dev->sg_table_count); @@ -545,12 +465,10 @@ static struct se_subsystem_api rd_mcp_template = { .transport_type = TRANSPORT_PLUGIN_VHBA_VDEV, .attach_hba = rd_attach_hba, .detach_hba = rd_detach_hba, - .allocate_virtdevice = rd_MEMCPY_allocate_virtdevice, - .create_virtdevice = rd_MEMCPY_create_virtdevice, + .allocate_virtdevice = rd_allocate_virtdevice, + .create_virtdevice = rd_create_virtdevice, .free_device = rd_free_device, - .alloc_task = rd_alloc_task, - .do_task = rd_MEMCPY_do_task, - .free_task = rd_free_task, + .execute_cmd = rd_execute_cmd, .check_configfs_dev_params = rd_check_configfs_dev_params, .set_configfs_dev_params = rd_set_configfs_dev_params, .show_configfs_dev_params = rd_show_configfs_dev_params, diff --git a/trunk/drivers/target/target_core_rd.h b/trunk/drivers/target/target_core_rd.h index 784e56a04100..21458125fe51 100644 --- a/trunk/drivers/target/target_core_rd.h +++ b/trunk/drivers/target/target_core_rd.h @@ -2,7 +2,6 @@ #define TARGET_CORE_RD_H #define RD_HBA_VERSION "v4.0" -#define RD_DR_VERSION "4.0" #define RD_MCP_VERSION "4.0" /* Largest piece of memory kmalloc can allocate */ @@ -10,28 +9,11 @@ #define RD_DEVICE_QUEUE_DEPTH 32 #define RD_MAX_DEVICE_QUEUE_DEPTH 128 #define RD_BLOCKSIZE 512 -#define RD_MAX_SECTORS 1024 /* Used in target_core_init_configfs() for virtual LUN 0 access */ int __init rd_module_init(void); void rd_module_exit(void); -#define RRF_EMULATE_CDB 0x01 -#define RRF_GOT_LBA 0x02 - -struct rd_request { - struct se_task rd_task; - - /* Offset from start of page */ - u32 rd_offset; - /* Starting page in Ramdisk for request */ - u32 rd_page; - /* Total number of pages needed for request */ - u32 rd_page_count; - /* Scatterlist count */ - u32 rd_size; -} ____cacheline_aligned; - struct rd_dev_sg_table { u32 page_start_offset; u32 page_end_offset; @@ -42,7 +24,6 @@ struct rd_dev_sg_table { #define RDF_HAS_PAGE_COUNT 0x01 struct rd_dev { - int rd_direct; u32 rd_flags; /* Unique Ramdisk Device ID in Ramdisk HBA */ u32 rd_dev_id; @@ -50,7 +31,6 @@ struct rd_dev { u32 rd_page_count; /* Number of SG tables in sg_table_array */ u32 sg_table_count; - u32 rd_queue_depth; /* Array of rd_dev_sg_table_t containing scatterlists */ struct rd_dev_sg_table *sg_table_array; /* Ramdisk HBA device is connected to */ diff --git a/trunk/drivers/target/target_core_tmr.c b/trunk/drivers/target/target_core_tmr.c index f015839aef89..84caf1bed9a3 100644 --- a/trunk/drivers/target/target_core_tmr.c +++ b/trunk/drivers/target/target_core_tmr.c @@ -244,7 +244,7 @@ static void core_tmr_drain_tmr_list( } } -static void core_tmr_drain_task_list( +static void core_tmr_drain_state_list( struct se_device *dev, struct se_cmd *prout_cmd, struct se_node_acl *tmr_nacl, @@ -252,12 +252,13 @@ static void core_tmr_drain_task_list( struct list_head *preempt_and_abort_list) { LIST_HEAD(drain_task_list); - struct se_cmd *cmd; - struct se_task *task, *task_tmp; + struct se_cmd *cmd, *next; unsigned long flags; int fe_count; + /* - * Complete outstanding struct se_task CDBs with TASK_ABORTED SAM status. + * Complete outstanding commands with TASK_ABORTED SAM status. + * * This is following sam4r17, section 5.6 Aborting commands, Table 38 * for TMR LUN_RESET: * @@ -278,56 +279,43 @@ static void core_tmr_drain_task_list( * in the Control Mode Page. */ spin_lock_irqsave(&dev->execute_task_lock, flags); - list_for_each_entry_safe(task, task_tmp, &dev->state_task_list, - t_state_list) { - if (!task->task_se_cmd) { - pr_err("task->task_se_cmd is NULL!\n"); - continue; - } - cmd = task->task_se_cmd; - + list_for_each_entry_safe(cmd, next, &dev->state_list, state_list) { /* * For PREEMPT_AND_ABORT usage, only process commands * with a matching reservation key. */ if (target_check_cdb_and_preempt(preempt_and_abort_list, cmd)) continue; + /* * Not aborting PROUT PREEMPT_AND_ABORT CDB.. */ if (prout_cmd == cmd) continue; - list_move_tail(&task->t_state_list, &drain_task_list); - task->t_state_active = false; - /* - * Remove from task execute list before processing drain_task_list - */ - if (!list_empty(&task->t_execute_list)) - __transport_remove_task_from_execute_queue(task, dev); + list_move_tail(&cmd->state_list, &drain_task_list); + cmd->state_active = false; + + if (!list_empty(&cmd->execute_list)) + __target_remove_from_execute_list(cmd); } spin_unlock_irqrestore(&dev->execute_task_lock, flags); while (!list_empty(&drain_task_list)) { - task = list_entry(drain_task_list.next, struct se_task, t_state_list); - list_del(&task->t_state_list); - cmd = task->task_se_cmd; + cmd = list_entry(drain_task_list.next, struct se_cmd, state_list); + list_del(&cmd->state_list); - pr_debug("LUN_RESET: %s cmd: %p task: %p" + pr_debug("LUN_RESET: %s cmd: %p" " ITT/CmdSN: 0x%08x/0x%08x, i_state: %d, t_state: %d" "cdb: 0x%02x\n", - (preempt_and_abort_list) ? "Preempt" : "", cmd, task, + (preempt_and_abort_list) ? "Preempt" : "", cmd, cmd->se_tfo->get_task_tag(cmd), 0, cmd->se_tfo->get_cmd_state(cmd), cmd->t_state, cmd->t_task_cdb[0]); pr_debug("LUN_RESET: ITT[0x%08x] - pr_res_key: 0x%016Lx" - " t_task_cdbs: %d t_task_cdbs_left: %d" - " t_task_cdbs_sent: %d -- CMD_T_ACTIVE: %d" + " -- CMD_T_ACTIVE: %d" " CMD_T_STOP: %d CMD_T_SENT: %d\n", cmd->se_tfo->get_task_tag(cmd), cmd->pr_res_key, - cmd->t_task_list_num, - atomic_read(&cmd->t_task_cdbs_left), - atomic_read(&cmd->t_task_cdbs_sent), (cmd->transport_state & CMD_T_ACTIVE) != 0, (cmd->transport_state & CMD_T_STOP) != 0, (cmd->transport_state & CMD_T_SENT) != 0); @@ -343,20 +331,13 @@ static void core_tmr_drain_task_list( cancel_work_sync(&cmd->work); spin_lock_irqsave(&cmd->t_state_lock, flags); - target_stop_task(task, &flags); + target_stop_cmd(cmd, &flags); - if (!atomic_dec_and_test(&cmd->t_task_cdbs_ex_left)) { - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - pr_debug("LUN_RESET: Skipping task: %p, dev: %p for" - " t_task_cdbs_ex_left: %d\n", task, dev, - atomic_read(&cmd->t_task_cdbs_ex_left)); - continue; - } fe_count = atomic_read(&cmd->t_fe_count); if (!(cmd->transport_state & CMD_T_ACTIVE)) { pr_debug("LUN_RESET: got CMD_T_ACTIVE for" - " task: %p, t_fe_count: %d dev: %p\n", task, + " cdb: %p, t_fe_count: %d dev: %p\n", cmd, fe_count, dev); cmd->transport_state |= CMD_T_ABORTED; spin_unlock_irqrestore(&cmd->t_state_lock, flags); @@ -364,8 +345,8 @@ static void core_tmr_drain_task_list( core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count); continue; } - pr_debug("LUN_RESET: Got !CMD_T_ACTIVE for task: %p," - " t_fe_count: %d dev: %p\n", task, fe_count, dev); + pr_debug("LUN_RESET: Got !CMD_T_ACTIVE for cdb: %p," + " t_fe_count: %d dev: %p\n", cmd, fe_count, dev); cmd->transport_state |= CMD_T_ABORTED; spin_unlock_irqrestore(&cmd->t_state_lock, flags); @@ -384,13 +365,11 @@ static void core_tmr_drain_cmd_list( struct se_queue_obj *qobj = &dev->dev_queue_obj; struct se_cmd *cmd, *tcmd; unsigned long flags; + /* - * Release all commands remaining in the struct se_device cmd queue. + * Release all commands remaining in the per-device command queue. * - * This follows the same logic as above for the struct se_device - * struct se_task state list, where commands are returned with - * TASK_ABORTED status, if there is an outstanding $FABRIC_MOD - * reference, otherwise the struct se_cmd is released. + * This follows the same logic as above for the state list. */ spin_lock_irqsave(&qobj->cmd_queue_lock, flags); list_for_each_entry_safe(cmd, tcmd, &qobj->qobj_list, se_queue_node) { @@ -466,7 +445,7 @@ int core_tmr_lun_reset( dev->transport->name, tas); core_tmr_drain_tmr_list(dev, tmr, preempt_and_abort_list); - core_tmr_drain_task_list(dev, prout_cmd, tmr_nacl, tas, + core_tmr_drain_state_list(dev, prout_cmd, tmr_nacl, tas, preempt_and_abort_list); core_tmr_drain_cmd_list(dev, prout_cmd, tmr_nacl, tas, preempt_and_abort_list); diff --git a/trunk/drivers/target/target_core_tpg.c b/trunk/drivers/target/target_core_tpg.c index e320ec24aa1b..8bd58e284185 100644 --- a/trunk/drivers/target/target_core_tpg.c +++ b/trunk/drivers/target/target_core_tpg.c @@ -153,10 +153,7 @@ void core_tpg_add_node_to_devs( * demo_mode_write_protect is ON, or READ_ONLY; */ if (!tpg->se_tpg_tfo->tpg_check_demo_mode_write_protect(tpg)) { - if (dev->dev_flags & DF_READ_ONLY) - lun_access = TRANSPORT_LUNFLAGS_READ_ONLY; - else - lun_access = TRANSPORT_LUNFLAGS_READ_WRITE; + lun_access = TRANSPORT_LUNFLAGS_READ_WRITE; } else { /* * Allow only optical drives to issue R/W in default RO diff --git a/trunk/drivers/target/target_core_transport.c b/trunk/drivers/target/target_core_transport.c index 443704f84fd5..b05fdc0c05d3 100644 --- a/trunk/drivers/target/target_core_transport.c +++ b/trunk/drivers/target/target_core_transport.c @@ -72,7 +72,6 @@ static int __transport_execute_tasks(struct se_device *dev, struct se_cmd *); static void transport_complete_task_attr(struct se_cmd *cmd); static void transport_handle_queue_full(struct se_cmd *cmd, struct se_device *dev); -static void transport_free_dev_tasks(struct se_cmd *cmd); static int transport_generic_get_mem(struct se_cmd *cmd); static void transport_put_cmd(struct se_cmd *cmd); static void transport_remove_cmd_from_queue(struct se_cmd *cmd); @@ -331,9 +330,9 @@ void target_get_session(struct se_session *se_sess) } EXPORT_SYMBOL(target_get_session); -int target_put_session(struct se_session *se_sess) +void target_put_session(struct se_session *se_sess) { - return kref_put(&se_sess->sess_kref, target_release_session); + kref_put(&se_sess->sess_kref, target_release_session); } EXPORT_SYMBOL(target_put_session); @@ -444,31 +443,23 @@ EXPORT_SYMBOL(transport_deregister_session); /* * Called with cmd->t_state_lock held. */ -static void transport_all_task_dev_remove_state(struct se_cmd *cmd) +static void target_remove_from_state_list(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; - struct se_task *task; unsigned long flags; if (!dev) return; - list_for_each_entry(task, &cmd->t_task_list, t_list) { - if (task->task_flags & TF_ACTIVE) - continue; - - spin_lock_irqsave(&dev->execute_task_lock, flags); - if (task->t_state_active) { - pr_debug("Removed ITT: 0x%08x dev: %p task[%p]\n", - cmd->se_tfo->get_task_tag(cmd), dev, task); + if (cmd->transport_state & CMD_T_BUSY) + return; - list_del(&task->t_state_list); - atomic_dec(&cmd->t_task_cdbs_ex_left); - task->t_state_active = false; - } - spin_unlock_irqrestore(&dev->execute_task_lock, flags); + spin_lock_irqsave(&dev->execute_task_lock, flags); + if (cmd->state_active) { + list_del(&cmd->state_list); + cmd->state_active = false; } - + spin_unlock_irqrestore(&dev->execute_task_lock, flags); } /* transport_cmd_check_stop(): @@ -497,7 +488,7 @@ static int transport_cmd_check_stop( cmd->transport_state &= ~CMD_T_ACTIVE; if (transport_off == 2) - transport_all_task_dev_remove_state(cmd); + target_remove_from_state_list(cmd); spin_unlock_irqrestore(&cmd->t_state_lock, flags); complete(&cmd->transport_lun_stop_comp); @@ -513,7 +504,7 @@ static int transport_cmd_check_stop( cmd->se_tfo->get_task_tag(cmd)); if (transport_off == 2) - transport_all_task_dev_remove_state(cmd); + target_remove_from_state_list(cmd); /* * Clear struct se_cmd->se_lun before the transport_off == 2 handoff @@ -529,7 +520,7 @@ static int transport_cmd_check_stop( if (transport_off) { cmd->transport_state &= ~CMD_T_ACTIVE; if (transport_off == 2) { - transport_all_task_dev_remove_state(cmd); + target_remove_from_state_list(cmd); /* * Clear struct se_cmd->se_lun before the transport_off == 2 * handoff to fabric module. @@ -577,7 +568,7 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd) spin_lock_irqsave(&cmd->t_state_lock, flags); if (cmd->transport_state & CMD_T_DEV_ACTIVE) { cmd->transport_state &= ~CMD_T_DEV_ACTIVE; - transport_all_task_dev_remove_state(cmd); + target_remove_from_state_list(cmd); } spin_unlock_irqrestore(&cmd->t_state_lock, flags); @@ -669,29 +660,6 @@ static void transport_remove_cmd_from_queue(struct se_cmd *cmd) spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); } -/* - * Completion function used by TCM subsystem plugins (such as FILEIO) - * for queueing up response from struct se_subsystem_api->do_task() - */ -void transport_complete_sync_cache(struct se_cmd *cmd, int good) -{ - struct se_task *task = list_entry(cmd->t_task_list.next, - struct se_task, t_list); - - if (good) { - cmd->scsi_status = SAM_STAT_GOOD; - task->task_scsi_status = GOOD; - } else { - task->task_scsi_status = SAM_STAT_CHECK_CONDITION; - task->task_se_cmd->scsi_sense_reason = - TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - - } - - transport_complete_task(task, good); -} -EXPORT_SYMBOL(transport_complete_sync_cache); - static void target_complete_failure_work(struct work_struct *work) { struct se_cmd *cmd = container_of(work, struct se_cmd, work); @@ -699,55 +667,38 @@ static void target_complete_failure_work(struct work_struct *work) transport_generic_request_failure(cmd); } -/* transport_complete_task(): - * - * Called from interrupt and non interrupt context depending - * on the transport plugin. - */ -void transport_complete_task(struct se_task *task, int success) +void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status) { - struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; + int success = scsi_status == GOOD; unsigned long flags; + cmd->scsi_status = scsi_status; + + spin_lock_irqsave(&cmd->t_state_lock, flags); - task->task_flags &= ~TF_ACTIVE; + cmd->transport_state &= ~CMD_T_BUSY; - /* - * See if any sense data exists, if so set the TASK_SENSE flag. - * Also check for any other post completion work that needs to be - * done by the plugins. - */ if (dev && dev->transport->transport_complete) { - if (dev->transport->transport_complete(task) != 0) { + if (dev->transport->transport_complete(cmd, + cmd->t_data_sg) != 0) { cmd->se_cmd_flags |= SCF_TRANSPORT_TASK_SENSE; - task->task_flags |= TF_HAS_SENSE; success = 1; } } /* - * See if we are waiting for outstanding struct se_task - * to complete for an exception condition + * See if we are waiting to complete for an exception condition. */ - if (task->task_flags & TF_REQUEST_STOP) { + if (cmd->transport_state & CMD_T_REQUEST_STOP) { spin_unlock_irqrestore(&cmd->t_state_lock, flags); - complete(&task->task_stop_comp); + complete(&cmd->task_stop_comp); return; } if (!success) cmd->transport_state |= CMD_T_FAILED; - /* - * Decrement the outstanding t_task_cdbs_left count. The last - * struct se_task from struct se_cmd will complete itself into the - * device queue depending upon int success. - */ - if (!atomic_dec_and_test(&cmd->t_task_cdbs_left)) { - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - return; - } /* * Check for case where an explict ABORT_TASK has been received * and transport_wait_for_tasks() will be waiting for completion.. @@ -770,157 +721,77 @@ void transport_complete_task(struct se_task *task, int success) queue_work(target_completion_wq, &cmd->work); } -EXPORT_SYMBOL(transport_complete_task); - -/* - * Called by transport_add_tasks_from_cmd() once a struct se_cmd's - * struct se_task list are ready to be added to the active execution list - * struct se_device +EXPORT_SYMBOL(target_complete_cmd); - * Called with se_dev_t->execute_task_lock called. - */ -static inline int transport_add_task_check_sam_attr( - struct se_task *task, - struct se_task *task_prev, - struct se_device *dev) +static void target_add_to_state_list(struct se_cmd *cmd) { - /* - * No SAM Task attribute emulation enabled, add to tail of - * execution queue - */ - if (dev->dev_task_attr_type != SAM_TASK_ATTR_EMULATED) { - list_add_tail(&task->t_execute_list, &dev->execute_task_list); - return 0; - } - /* - * HEAD_OF_QUEUE attribute for received CDB, which means - * the first task that is associated with a struct se_cmd goes to - * head of the struct se_device->execute_task_list, and task_prev - * after that for each subsequent task - */ - if (task->task_se_cmd->sam_task_attr == MSG_HEAD_TAG) { - list_add(&task->t_execute_list, - (task_prev != NULL) ? - &task_prev->t_execute_list : - &dev->execute_task_list); - - pr_debug("Set HEAD_OF_QUEUE for task CDB: 0x%02x" - " in execution queue\n", - task->task_se_cmd->t_task_cdb[0]); - return 1; + struct se_device *dev = cmd->se_dev; + unsigned long flags; + + spin_lock_irqsave(&dev->execute_task_lock, flags); + if (!cmd->state_active) { + list_add_tail(&cmd->state_list, &dev->state_list); + cmd->state_active = true; } - /* - * For ORDERED, SIMPLE or UNTAGGED attribute tasks once they have been - * transitioned from Dermant -> Active state, and are added to the end - * of the struct se_device->execute_task_list - */ - list_add_tail(&task->t_execute_list, &dev->execute_task_list); - return 0; + spin_unlock_irqrestore(&dev->execute_task_lock, flags); } -/* __transport_add_task_to_execute_queue(): - * - * Called with se_dev_t->execute_task_lock called. - */ -static void __transport_add_task_to_execute_queue( - struct se_task *task, - struct se_task *task_prev, - struct se_device *dev) +static void __target_add_to_execute_list(struct se_cmd *cmd) { - int head_of_queue; - - head_of_queue = transport_add_task_check_sam_attr(task, task_prev, dev); - atomic_inc(&dev->execute_tasks); + struct se_device *dev = cmd->se_dev; + bool head_of_queue = false; - if (task->t_state_active) + if (!list_empty(&cmd->execute_list)) return; - /* - * Determine if this task needs to go to HEAD_OF_QUEUE for the - * state list as well. Running with SAM Task Attribute emulation - * will always return head_of_queue == 0 here - */ - if (head_of_queue) - list_add(&task->t_state_list, (task_prev) ? - &task_prev->t_state_list : - &dev->state_task_list); - else - list_add_tail(&task->t_state_list, &dev->state_task_list); - task->t_state_active = true; + if (dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED && + cmd->sam_task_attr == MSG_HEAD_TAG) + head_of_queue = true; - pr_debug("Added ITT: 0x%08x task[%p] to dev: %p\n", - task->task_se_cmd->se_tfo->get_task_tag(task->task_se_cmd), - task, dev); -} + if (head_of_queue) + list_add(&cmd->execute_list, &dev->execute_list); + else + list_add_tail(&cmd->execute_list, &dev->execute_list); -static void transport_add_tasks_to_state_queue(struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - struct se_task *task; - unsigned long flags; + atomic_inc(&dev->execute_tasks); - spin_lock_irqsave(&cmd->t_state_lock, flags); - list_for_each_entry(task, &cmd->t_task_list, t_list) { - spin_lock(&dev->execute_task_lock); - if (!task->t_state_active) { - list_add_tail(&task->t_state_list, - &dev->state_task_list); - task->t_state_active = true; - - pr_debug("Added ITT: 0x%08x task[%p] to dev: %p\n", - task->task_se_cmd->se_tfo->get_task_tag( - task->task_se_cmd), task, dev); - } - spin_unlock(&dev->execute_task_lock); - } - spin_unlock_irqrestore(&cmd->t_state_lock, flags); -} + if (cmd->state_active) + return; -static void __transport_add_tasks_from_cmd(struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - struct se_task *task, *task_prev = NULL; + if (head_of_queue) + list_add(&cmd->state_list, &dev->state_list); + else + list_add_tail(&cmd->state_list, &dev->state_list); - list_for_each_entry(task, &cmd->t_task_list, t_list) { - if (!list_empty(&task->t_execute_list)) - continue; - /* - * __transport_add_task_to_execute_queue() handles the - * SAM Task Attribute emulation if enabled - */ - __transport_add_task_to_execute_queue(task, task_prev, dev); - task_prev = task; - } + cmd->state_active = true; } -static void transport_add_tasks_from_cmd(struct se_cmd *cmd) +static void target_add_to_execute_list(struct se_cmd *cmd) { unsigned long flags; struct se_device *dev = cmd->se_dev; spin_lock_irqsave(&dev->execute_task_lock, flags); - __transport_add_tasks_from_cmd(cmd); + __target_add_to_execute_list(cmd); spin_unlock_irqrestore(&dev->execute_task_lock, flags); } -void __transport_remove_task_from_execute_queue(struct se_task *task, - struct se_device *dev) +void __target_remove_from_execute_list(struct se_cmd *cmd) { - list_del_init(&task->t_execute_list); - atomic_dec(&dev->execute_tasks); + list_del_init(&cmd->execute_list); + atomic_dec(&cmd->se_dev->execute_tasks); } -static void transport_remove_task_from_execute_queue( - struct se_task *task, - struct se_device *dev) +static void target_remove_from_execute_list(struct se_cmd *cmd) { + struct se_device *dev = cmd->se_dev; unsigned long flags; - if (WARN_ON(list_empty(&task->t_execute_list))) + if (WARN_ON(list_empty(&cmd->execute_list))) return; spin_lock_irqsave(&dev->execute_task_lock, flags); - __transport_remove_task_from_execute_queue(task, dev); + __target_remove_from_execute_list(cmd); spin_unlock_irqrestore(&dev->execute_task_lock, flags); } @@ -999,8 +870,9 @@ void transport_dump_dev_state( *bl += sprintf(b + *bl, " Execute/Max Queue Depth: %d/%d", atomic_read(&dev->execute_tasks), dev->queue_depth); - *bl += sprintf(b + *bl, " SectorSize: %u MaxSectors: %u\n", - dev->se_sub_dev->se_dev_attrib.block_size, dev->se_sub_dev->se_dev_attrib.max_sectors); + *bl += sprintf(b + *bl, " SectorSize: %u HwMaxSectors: %u\n", + dev->se_sub_dev->se_dev_attrib.block_size, + dev->se_sub_dev->se_dev_attrib.hw_max_sectors); *bl += sprintf(b + *bl, " "); } @@ -1344,9 +1216,9 @@ struct se_device *transport_add_device_to_core_hba( INIT_LIST_HEAD(&dev->dev_list); INIT_LIST_HEAD(&dev->dev_sep_list); INIT_LIST_HEAD(&dev->dev_tmr_list); - INIT_LIST_HEAD(&dev->execute_task_list); + INIT_LIST_HEAD(&dev->execute_list); INIT_LIST_HEAD(&dev->delayed_cmd_list); - INIT_LIST_HEAD(&dev->state_task_list); + INIT_LIST_HEAD(&dev->state_list); INIT_LIST_HEAD(&dev->qf_cmd_list); spin_lock_init(&dev->execute_task_lock); spin_lock_init(&dev->delayed_cmd_lock); @@ -1457,6 +1329,7 @@ static inline void transport_generic_prepare_cdb( case VERIFY_16: /* SBC - VRProtect */ case WRITE_VERIFY: /* SBC - VRProtect */ case WRITE_VERIFY_12: /* SBC - VRProtect */ + case MAINTENANCE_IN: /* SPC - Parameter Data Format for SA RTPG */ break; default: cdb[1] &= 0x1f; /* clear logical unit number */ @@ -1464,29 +1337,6 @@ static inline void transport_generic_prepare_cdb( } } -static struct se_task * -transport_generic_get_task(struct se_cmd *cmd, - enum dma_data_direction data_direction) -{ - struct se_task *task; - struct se_device *dev = cmd->se_dev; - - task = dev->transport->alloc_task(cmd->t_task_cdb); - if (!task) { - pr_err("Unable to allocate struct se_task\n"); - return NULL; - } - - INIT_LIST_HEAD(&task->t_list); - INIT_LIST_HEAD(&task->t_execute_list); - INIT_LIST_HEAD(&task->t_state_list); - init_completion(&task->task_stop_comp); - task->task_se_cmd = cmd; - task->task_data_direction = data_direction; - - return task; -} - static int transport_generic_cmd_sequencer(struct se_cmd *, unsigned char *); /* @@ -1507,11 +1357,13 @@ void transport_init_se_cmd( INIT_LIST_HEAD(&cmd->se_qf_node); INIT_LIST_HEAD(&cmd->se_queue_node); INIT_LIST_HEAD(&cmd->se_cmd_list); - INIT_LIST_HEAD(&cmd->t_task_list); + INIT_LIST_HEAD(&cmd->execute_list); + INIT_LIST_HEAD(&cmd->state_list); init_completion(&cmd->transport_lun_fe_stop_comp); init_completion(&cmd->transport_lun_stop_comp); init_completion(&cmd->t_transport_stop_comp); init_completion(&cmd->cmd_wait_comp); + init_completion(&cmd->task_stop_comp); spin_lock_init(&cmd->t_state_lock); cmd->transport_state = CMD_T_DEV_ACTIVE; @@ -1521,6 +1373,8 @@ void transport_init_se_cmd( cmd->data_direction = data_direction; cmd->sam_task_attr = task_attr; cmd->sense_buffer = sense_buffer; + + cmd->state_active = false; } EXPORT_SYMBOL(transport_init_se_cmd); @@ -1550,11 +1404,11 @@ static int transport_check_alloc_task_attr(struct se_cmd *cmd) return 0; } -/* transport_generic_allocate_tasks(): +/* target_setup_cmd_from_cdb(): * * Called from fabric RX Thread. */ -int transport_generic_allocate_tasks( +int target_setup_cmd_from_cdb( struct se_cmd *cmd, unsigned char *cdb) { @@ -1620,7 +1474,7 @@ int transport_generic_allocate_tasks( spin_unlock(&cmd->se_lun->lun_sep_lock); return 0; } -EXPORT_SYMBOL(transport_generic_allocate_tasks); +EXPORT_SYMBOL(target_setup_cmd_from_cdb); /* * Used by fabric module frontends to queue tasks directly. @@ -1701,6 +1555,8 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, */ transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, data_length, data_dir, task_attr, sense); + if (flags & TARGET_SCF_UNKNOWN_SIZE) + se_cmd->unknown_data_length = 1; /* * Obtain struct se_cmd->cmd_kref reference and add new cmd to * se_sess->sess_cmd_list. A second kref_get here is necessary @@ -1726,11 +1582,18 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, * Sanitize CDBs via transport_generic_cmd_sequencer() and * allocate the necessary tasks to complete the received CDB+data */ - rc = transport_generic_allocate_tasks(se_cmd, cdb); + rc = target_setup_cmd_from_cdb(se_cmd, cdb); if (rc != 0) { transport_generic_request_failure(se_cmd); return; } + + /* + * Check if we need to delay processing because of ALUA + * Active/NonOptimized primary access state.. + */ + core_alua_check_nonop_delay(se_cmd); + /* * Dispatch se_cmd descriptor to se_lun->lun_se_dev backend * for immediate execution of READs, otherwise wait for @@ -1872,72 +1735,30 @@ int transport_generic_handle_tmr( EXPORT_SYMBOL(transport_generic_handle_tmr); /* - * If the task is active, request it to be stopped and sleep until it + * If the cmd is active, request it to be stopped and sleep until it * has completed. */ -bool target_stop_task(struct se_task *task, unsigned long *flags) +bool target_stop_cmd(struct se_cmd *cmd, unsigned long *flags) { - struct se_cmd *cmd = task->task_se_cmd; bool was_active = false; - if (task->task_flags & TF_ACTIVE) { - task->task_flags |= TF_REQUEST_STOP; + if (cmd->transport_state & CMD_T_BUSY) { + cmd->transport_state |= CMD_T_REQUEST_STOP; spin_unlock_irqrestore(&cmd->t_state_lock, *flags); - pr_debug("Task %p waiting to complete\n", task); - wait_for_completion(&task->task_stop_comp); - pr_debug("Task %p stopped successfully\n", task); + pr_debug("cmd %p waiting to complete\n", cmd); + wait_for_completion(&cmd->task_stop_comp); + pr_debug("cmd %p stopped successfully\n", cmd); spin_lock_irqsave(&cmd->t_state_lock, *flags); - atomic_dec(&cmd->t_task_cdbs_left); - task->task_flags &= ~(TF_ACTIVE | TF_REQUEST_STOP); + cmd->transport_state &= ~CMD_T_REQUEST_STOP; + cmd->transport_state &= ~CMD_T_BUSY; was_active = true; } return was_active; } -static int transport_stop_tasks_for_cmd(struct se_cmd *cmd) -{ - struct se_task *task, *task_tmp; - unsigned long flags; - int ret = 0; - - pr_debug("ITT[0x%08x] - Stopping tasks\n", - cmd->se_tfo->get_task_tag(cmd)); - - /* - * No tasks remain in the execution queue - */ - spin_lock_irqsave(&cmd->t_state_lock, flags); - list_for_each_entry_safe(task, task_tmp, - &cmd->t_task_list, t_list) { - pr_debug("Processing task %p\n", task); - /* - * If the struct se_task has not been sent and is not active, - * remove the struct se_task from the execution queue. - */ - if (!(task->task_flags & (TF_ACTIVE | TF_SENT))) { - spin_unlock_irqrestore(&cmd->t_state_lock, - flags); - transport_remove_task_from_execute_queue(task, - cmd->se_dev); - - pr_debug("Task %p removed from execute queue\n", task); - spin_lock_irqsave(&cmd->t_state_lock, flags); - continue; - } - - if (!target_stop_task(task, &flags)) { - pr_debug("Task %p - did nothing\n", task); - ret++; - } - } - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - - return ret; -} - /* * Handle SAM-esque emulation for generic transport request failures. */ @@ -1951,13 +1772,7 @@ void transport_generic_request_failure(struct se_cmd *cmd) pr_debug("-----[ i_state: %d t_state: %d scsi_sense_reason: %d\n", cmd->se_tfo->get_cmd_state(cmd), cmd->t_state, cmd->scsi_sense_reason); - pr_debug("-----[ t_tasks: %d t_task_cdbs_left: %d" - " t_task_cdbs_sent: %d t_task_cdbs_ex_left: %d --" - " CMD_T_ACTIVE: %d CMD_T_STOP: %d CMD_T_SENT: %d\n", - cmd->t_task_list_num, - atomic_read(&cmd->t_task_cdbs_left), - atomic_read(&cmd->t_task_cdbs_sent), - atomic_read(&cmd->t_task_cdbs_ex_left), + pr_debug("-----[ CMD_T_ACTIVE: %d CMD_T_STOP: %d CMD_T_SENT: %d\n", (cmd->transport_state & CMD_T_ACTIVE) != 0, (cmd->transport_state & CMD_T_STOP) != 0, (cmd->transport_state & CMD_T_SENT) != 0); @@ -2156,7 +1971,7 @@ static inline int transport_execute_task_attr(struct se_cmd *cmd) * Called from fabric module context in transport_generic_new_cmd() and * transport_generic_process_write() */ -static int transport_execute_tasks(struct se_cmd *cmd) +static void transport_execute_tasks(struct se_cmd *cmd) { int add_tasks; struct se_device *se_dev = cmd->se_dev; @@ -2170,71 +1985,52 @@ static int transport_execute_tasks(struct se_cmd *cmd) * attribute for the tasks of the received struct se_cmd CDB */ add_tasks = transport_execute_task_attr(cmd); - if (!add_tasks) - goto execute_tasks; - /* - * __transport_execute_tasks() -> __transport_add_tasks_from_cmd() - * adds associated se_tasks while holding dev->execute_task_lock - * before I/O dispath to avoid a double spinlock access. - */ - __transport_execute_tasks(se_dev, cmd); - return 0; + if (add_tasks) { + __transport_execute_tasks(se_dev, cmd); + return; + } } - -execute_tasks: __transport_execute_tasks(se_dev, NULL); - return 0; } -/* - * Called to check struct se_device tcq depth window, and once open pull struct se_task - * from struct se_device->execute_task_list and - * - * Called from transport_processing_thread() - */ static int __transport_execute_tasks(struct se_device *dev, struct se_cmd *new_cmd) { int error; struct se_cmd *cmd = NULL; - struct se_task *task = NULL; unsigned long flags; check_depth: spin_lock_irq(&dev->execute_task_lock); if (new_cmd != NULL) - __transport_add_tasks_from_cmd(new_cmd); + __target_add_to_execute_list(new_cmd); - if (list_empty(&dev->execute_task_list)) { + if (list_empty(&dev->execute_list)) { spin_unlock_irq(&dev->execute_task_lock); return 0; } - task = list_first_entry(&dev->execute_task_list, - struct se_task, t_execute_list); - __transport_remove_task_from_execute_queue(task, dev); + cmd = list_first_entry(&dev->execute_list, struct se_cmd, execute_list); + __target_remove_from_execute_list(cmd); spin_unlock_irq(&dev->execute_task_lock); - cmd = task->task_se_cmd; spin_lock_irqsave(&cmd->t_state_lock, flags); - task->task_flags |= (TF_ACTIVE | TF_SENT); - atomic_inc(&cmd->t_task_cdbs_sent); - - if (atomic_read(&cmd->t_task_cdbs_sent) == - cmd->t_task_list_num) - cmd->transport_state |= CMD_T_SENT; + cmd->transport_state |= CMD_T_BUSY; + cmd->transport_state |= CMD_T_SENT; spin_unlock_irqrestore(&cmd->t_state_lock, flags); - if (cmd->execute_task) - error = cmd->execute_task(task); - else - error = dev->transport->do_task(task); + if (cmd->execute_cmd) + error = cmd->execute_cmd(cmd); + else { + error = dev->transport->execute_cmd(cmd, cmd->t_data_sg, + cmd->t_data_nents, cmd->data_direction); + } + if (error != 0) { spin_lock_irqsave(&cmd->t_state_lock, flags); - task->task_flags &= ~TF_ACTIVE; + cmd->transport_state &= ~CMD_T_BUSY; cmd->transport_state &= ~CMD_T_SENT; spin_unlock_irqrestore(&cmd->t_state_lock, flags); - transport_stop_tasks_for_cmd(cmd); transport_generic_request_failure(cmd); } @@ -2392,12 +2188,12 @@ static inline u32 transport_get_size( } else /* bytes */ return sectors; } -#if 0 + pr_debug("Returning block_size: %u, sectors: %u == %u for" - " %s object\n", dev->se_sub_dev->se_dev_attrib.block_size, sectors, - dev->se_sub_dev->se_dev_attrib.block_size * sectors, - dev->transport->name); -#endif + " %s object\n", dev->se_sub_dev->se_dev_attrib.block_size, + sectors, dev->se_sub_dev->se_dev_attrib.block_size * sectors, + dev->transport->name); + return dev->se_sub_dev->se_dev_attrib.block_size * sectors; } @@ -2462,7 +2258,6 @@ static int transport_get_sense_data(struct se_cmd *cmd) { unsigned char *buffer = cmd->sense_buffer, *sense_buffer = NULL; struct se_device *dev = cmd->se_dev; - struct se_task *task = NULL, *task_tmp; unsigned long flags; u32 offset = 0; @@ -2477,44 +2272,37 @@ static int transport_get_sense_data(struct se_cmd *cmd) return 0; } - list_for_each_entry_safe(task, task_tmp, - &cmd->t_task_list, t_list) { - if (!(task->task_flags & TF_HAS_SENSE)) - continue; - - if (!dev->transport->get_sense_buffer) { - pr_err("dev->transport->get_sense_buffer" - " is NULL\n"); - continue; - } - - sense_buffer = dev->transport->get_sense_buffer(task); - if (!sense_buffer) { - pr_err("ITT[0x%08x]_TASK[%p]: Unable to locate" - " sense buffer for task with sense\n", - cmd->se_tfo->get_task_tag(cmd), task); - continue; - } - spin_unlock_irqrestore(&cmd->t_state_lock, flags); + if (!(cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE)) + goto out; - offset = cmd->se_tfo->set_fabric_sense_len(cmd, - TRANSPORT_SENSE_BUFFER); + if (!dev->transport->get_sense_buffer) { + pr_err("dev->transport->get_sense_buffer is NULL\n"); + goto out; + } - memcpy(&buffer[offset], sense_buffer, - TRANSPORT_SENSE_BUFFER); - cmd->scsi_status = task->task_scsi_status; - /* Automatically padded */ - cmd->scsi_sense_length = - (TRANSPORT_SENSE_BUFFER + offset); - - pr_debug("HBA_[%u]_PLUG[%s]: Set SAM STATUS: 0x%02x" - " and sense\n", - dev->se_hba->hba_id, dev->transport->name, - cmd->scsi_status); - return 0; + sense_buffer = dev->transport->get_sense_buffer(cmd); + if (!sense_buffer) { + pr_err("ITT 0x%08x cmd %p: Unable to locate" + " sense buffer for task with sense\n", + cmd->se_tfo->get_task_tag(cmd), cmd); + goto out; } + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + offset = cmd->se_tfo->set_fabric_sense_len(cmd, TRANSPORT_SENSE_BUFFER); + + memcpy(&buffer[offset], sense_buffer, TRANSPORT_SENSE_BUFFER); + + /* Automatically padded */ + cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER + offset; + + pr_debug("HBA_[%u]_PLUG[%s]: Set SAM STATUS: 0x%02x and sense\n", + dev->se_hba->hba_id, dev->transport->name, cmd->scsi_status); + return 0; + +out: + spin_unlock_irqrestore(&cmd->t_state_lock, flags); return -1; } @@ -2581,7 +2369,7 @@ static int target_check_write_same_discard(unsigned char *flags, struct se_devic * Generic Command Sequencer that should work for most DAS transport * drivers. * - * Called from transport_generic_allocate_tasks() in the $FABRIC_MOD + * Called from target_setup_cmd_from_cdb() in the $FABRIC_MOD * RX Thread. * * FIXME: Need to support other SCSI OPCODES where as well. @@ -2615,11 +2403,10 @@ static int transport_generic_cmd_sequencer( * by the ALUA primary or secondary access state.. */ if (ret > 0) { -#if 0 pr_debug("[%s]: ALUA TG Port not available," " SenseKey: NOT_READY, ASC/ASCQ: 0x04/0x%02x\n", cmd->se_tfo->get_fabric_name(), alua_ascq); -#endif + transport_set_sense_codes(cmd, 0x04, alua_ascq); cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; cmd->scsi_sense_reason = TCM_CHECK_CONDITION_NOT_READY; @@ -2695,6 +2482,7 @@ static int transport_generic_cmd_sequencer( cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; break; case WRITE_10: + case WRITE_VERIFY: sectors = transport_get_sectors_10(cdb, cmd, §or_ret); if (sector_ret) goto out_unsupported_cdb; @@ -2796,7 +2584,7 @@ static int transport_generic_cmd_sequencer( if (target_check_write_same_discard(&cdb[10], dev) < 0) goto out_unsupported_cdb; if (!passthrough) - cmd->execute_task = target_emulate_write_same; + cmd->execute_cmd = target_emulate_write_same; break; default: pr_err("VARIABLE_LENGTH_CMD service action" @@ -2810,9 +2598,9 @@ static int transport_generic_cmd_sequencer( /* * Check for emulated MI_REPORT_TARGET_PGS. */ - if (cdb[1] == MI_REPORT_TARGET_PGS && + if ((cdb[1] & 0x1f) == MI_REPORT_TARGET_PGS && su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) { - cmd->execute_task = + cmd->execute_cmd = target_emulate_report_target_port_groups; } size = (cdb[6] << 24) | (cdb[7] << 16) | @@ -2835,13 +2623,13 @@ static int transport_generic_cmd_sequencer( size = cdb[4]; cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; if (!passthrough) - cmd->execute_task = target_emulate_modesense; + cmd->execute_cmd = target_emulate_modesense; break; case MODE_SENSE_10: size = (cdb[7] << 8) + cdb[8]; cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; if (!passthrough) - cmd->execute_task = target_emulate_modesense; + cmd->execute_cmd = target_emulate_modesense; break; case GPCMD_READ_BUFFER_CAPACITY: case GPCMD_SEND_OPC: @@ -2863,13 +2651,13 @@ static int transport_generic_cmd_sequencer( break; case PERSISTENT_RESERVE_IN: if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS) - cmd->execute_task = target_scsi3_emulate_pr_in; + cmd->execute_cmd = target_scsi3_emulate_pr_in; size = (cdb[7] << 8) + cdb[8]; cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; case PERSISTENT_RESERVE_OUT: if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS) - cmd->execute_task = target_scsi3_emulate_pr_out; + cmd->execute_cmd = target_scsi3_emulate_pr_out; size = (cdb[7] << 8) + cdb[8]; cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; @@ -2890,7 +2678,7 @@ static int transport_generic_cmd_sequencer( */ if (cdb[1] == MO_SET_TARGET_PGS && su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) { - cmd->execute_task = + cmd->execute_cmd = target_emulate_set_target_port_groups; } @@ -2912,7 +2700,7 @@ static int transport_generic_cmd_sequencer( cmd->sam_task_attr = MSG_HEAD_TAG; cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; if (!passthrough) - cmd->execute_task = target_emulate_inquiry; + cmd->execute_cmd = target_emulate_inquiry; break; case READ_BUFFER: size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; @@ -2922,7 +2710,7 @@ static int transport_generic_cmd_sequencer( size = READ_CAP_LEN; cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; if (!passthrough) - cmd->execute_task = target_emulate_readcapacity; + cmd->execute_cmd = target_emulate_readcapacity; break; case READ_MEDIA_SERIAL_NUMBER: case SECURITY_PROTOCOL_IN: @@ -2934,7 +2722,7 @@ static int transport_generic_cmd_sequencer( switch (cmd->t_task_cdb[1] & 0x1f) { case SAI_READ_CAPACITY_16: if (!passthrough) - cmd->execute_task = + cmd->execute_cmd = target_emulate_readcapacity_16; break; default: @@ -2977,7 +2765,7 @@ static int transport_generic_cmd_sequencer( size = cdb[4]; cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; if (!passthrough) - cmd->execute_task = target_emulate_request_sense; + cmd->execute_cmd = target_emulate_request_sense; break; case READ_ELEMENT_STATUS: size = 65536 * cdb[7] + 256 * cdb[8] + cdb[9]; @@ -3006,7 +2794,7 @@ static int transport_generic_cmd_sequencer( * emulation disabled. */ if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) - cmd->execute_task = target_scsi2_reservation_reserve; + cmd->execute_cmd = target_scsi2_reservation_reserve; cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; break; case RELEASE: @@ -3021,7 +2809,7 @@ static int transport_generic_cmd_sequencer( size = cmd->data_length; if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH) - cmd->execute_task = target_scsi2_reservation_release; + cmd->execute_cmd = target_scsi2_reservation_release; cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; break; case SYNCHRONIZE_CACHE: @@ -3053,13 +2841,13 @@ static int transport_generic_cmd_sequencer( if (transport_cmd_get_valid_sectors(cmd) < 0) goto out_invalid_cdb_field; } - cmd->execute_task = target_emulate_synchronize_cache; + cmd->execute_cmd = target_emulate_synchronize_cache; break; case UNMAP: size = get_unaligned_be16(&cdb[7]); cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; if (!passthrough) - cmd->execute_task = target_emulate_unmap; + cmd->execute_cmd = target_emulate_unmap; break; case WRITE_SAME_16: sectors = transport_get_sectors_16(cdb, cmd, §or_ret); @@ -3079,7 +2867,7 @@ static int transport_generic_cmd_sequencer( if (target_check_write_same_discard(&cdb[1], dev) < 0) goto out_unsupported_cdb; if (!passthrough) - cmd->execute_task = target_emulate_write_same; + cmd->execute_cmd = target_emulate_write_same; break; case WRITE_SAME: sectors = transport_get_sectors_10(cdb, cmd, §or_ret); @@ -3102,7 +2890,7 @@ static int transport_generic_cmd_sequencer( if (target_check_write_same_discard(&cdb[1], dev) < 0) goto out_unsupported_cdb; if (!passthrough) - cmd->execute_task = target_emulate_write_same; + cmd->execute_cmd = target_emulate_write_same; break; case ALLOW_MEDIUM_REMOVAL: case ERASE: @@ -3115,7 +2903,7 @@ static int transport_generic_cmd_sequencer( case WRITE_FILEMARKS: cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; if (!passthrough) - cmd->execute_task = target_emulate_noop; + cmd->execute_cmd = target_emulate_noop; break; case GPCMD_CLOSE_TRACK: case INITIALIZE_ELEMENT_STATUS: @@ -3125,7 +2913,7 @@ static int transport_generic_cmd_sequencer( cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; break; case REPORT_LUNS: - cmd->execute_task = target_report_luns; + cmd->execute_cmd = target_report_luns; size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; /* * Do implict HEAD_OF_QUEUE processing for REPORT_LUNS @@ -3135,6 +2923,42 @@ static int transport_generic_cmd_sequencer( cmd->sam_task_attr = MSG_HEAD_TAG; cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; break; + case GET_EVENT_STATUS_NOTIFICATION: + size = (cdb[7] << 8) | cdb[8]; + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + break; + case ATA_16: + /* Only support ATA passthrough to pSCSI backends.. */ + if (!passthrough) + goto out_unsupported_cdb; + + /* T_LENGTH */ + switch (cdb[2] & 0x3) { + case 0x0: + sectors = 0; + break; + case 0x1: + sectors = (((cdb[1] & 0x1) ? cdb[3] : 0) << 8) | cdb[4]; + break; + case 0x2: + sectors = (((cdb[1] & 0x1) ? cdb[5] : 0) << 8) | cdb[6]; + break; + case 0x3: + pr_err("T_LENGTH=0x3 not supported for ATA_16\n"); + goto out_invalid_cdb_field; + } + + /* BYTE_BLOCK */ + if (cdb[2] & 0x4) { + /* BLOCK T_TYPE: 512 or sector */ + size = sectors * ((cdb[2] & 0x10) ? + dev->se_sub_dev->se_dev_attrib.block_size : 512); + } else { + /* BYTE */ + size = sectors; + } + cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; + break; default: pr_warn("TARGET_CORE[%s]: Unsupported SCSI Opcode" " 0x%02x, sending CHECK_CONDITION.\n", @@ -3142,6 +2966,9 @@ static int transport_generic_cmd_sequencer( goto out_unsupported_cdb; } + if (cmd->unknown_data_length) + cmd->data_length = size; + if (size != cmd->data_length) { pr_warn("TARGET_CORE[%s]: Expected Transfer Length:" " %u does not match SCSI CDB Length: %u for SAM Opcode:" @@ -3177,15 +3004,25 @@ static int transport_generic_cmd_sequencer( cmd->data_length = size; } - if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB && - sectors > dev->se_sub_dev->se_dev_attrib.fabric_max_sectors) { - printk_ratelimited(KERN_ERR "SCSI OP %02xh with too big sectors %u\n", - cdb[0], sectors); - goto out_invalid_cdb_field; + if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) { + if (sectors > su_dev->se_dev_attrib.fabric_max_sectors) { + printk_ratelimited(KERN_ERR "SCSI OP %02xh with too" + " big sectors %u exceeds fabric_max_sectors:" + " %u\n", cdb[0], sectors, + su_dev->se_dev_attrib.fabric_max_sectors); + goto out_invalid_cdb_field; + } + if (sectors > su_dev->se_dev_attrib.hw_max_sectors) { + printk_ratelimited(KERN_ERR "SCSI OP %02xh with too" + " big sectors %u exceeds backend hw_max_sectors:" + " %u\n", cdb[0], sectors, + su_dev->se_dev_attrib.hw_max_sectors); + goto out_invalid_cdb_field; + } } /* reject any command that we don't have a handler for */ - if (!(passthrough || cmd->execute_task || + if (!(passthrough || cmd->execute_cmd || (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB))) goto out_unsupported_cdb; @@ -3250,7 +3087,7 @@ static void transport_complete_task_attr(struct se_cmd *cmd) cmd_p->t_task_cdb[0], cmd_p->sam_task_attr, cmd_p->se_ordered_id); - transport_add_tasks_from_cmd(cmd_p); + target_add_to_execute_list(cmd_p); new_active_tasks++; spin_lock(&dev->delayed_cmd_lock); @@ -3346,10 +3183,6 @@ static void target_complete_ok_work(struct work_struct *work) if (transport_get_sense_data(cmd) < 0) reason = TCM_NON_EXISTENT_LUN; - /* - * Only set when an struct se_task->task_scsi_status returned - * a non GOOD status. - */ if (cmd->scsi_status) { ret = transport_send_check_condition_and_sense( cmd, reason, 1); @@ -3424,33 +3257,6 @@ static void target_complete_ok_work(struct work_struct *work) transport_handle_queue_full(cmd, cmd->se_dev); } -static void transport_free_dev_tasks(struct se_cmd *cmd) -{ - struct se_task *task, *task_tmp; - unsigned long flags; - LIST_HEAD(dispose_list); - - spin_lock_irqsave(&cmd->t_state_lock, flags); - list_for_each_entry_safe(task, task_tmp, - &cmd->t_task_list, t_list) { - if (!(task->task_flags & TF_ACTIVE)) - list_move_tail(&task->t_list, &dispose_list); - } - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - - while (!list_empty(&dispose_list)) { - task = list_first_entry(&dispose_list, struct se_task, t_list); - - if (task->task_sg != cmd->t_data_sg && - task->task_sg != cmd->t_bidi_data_sg) - kfree(task->task_sg); - - list_del(&task->t_list); - - cmd->se_dev->transport->free_task(task); - } -} - static inline void transport_free_sgl(struct scatterlist *sgl, int nents) { struct scatterlist *sg; @@ -3511,7 +3317,6 @@ static void transport_release_cmd(struct se_cmd *cmd) static void transport_put_cmd(struct se_cmd *cmd) { unsigned long flags; - int free_tasks = 0; spin_lock_irqsave(&cmd->t_state_lock, flags); if (atomic_read(&cmd->t_fe_count)) { @@ -3519,21 +3324,12 @@ static void transport_put_cmd(struct se_cmd *cmd) goto out_busy; } - if (atomic_read(&cmd->t_se_count)) { - if (!atomic_dec_and_test(&cmd->t_se_count)) - goto out_busy; - } - if (cmd->transport_state & CMD_T_DEV_ACTIVE) { cmd->transport_state &= ~CMD_T_DEV_ACTIVE; - transport_all_task_dev_remove_state(cmd); - free_tasks = 1; + target_remove_from_state_list(cmd); } spin_unlock_irqrestore(&cmd->t_state_lock, flags); - if (free_tasks != 0) - transport_free_dev_tasks(cmd); - transport_free_pages(cmd); transport_release_cmd(cmd); return; @@ -3683,245 +3479,14 @@ transport_generic_get_mem(struct se_cmd *cmd) return -ENOMEM; } -/* Reduce sectors if they are too long for the device */ -static inline sector_t transport_limit_task_sectors( - struct se_device *dev, - unsigned long long lba, - sector_t sectors) -{ - sectors = min_t(sector_t, sectors, dev->se_sub_dev->se_dev_attrib.max_sectors); - - if (dev->transport->get_device_type(dev) == TYPE_DISK) - if ((lba + sectors) > transport_dev_end_lba(dev)) - sectors = ((transport_dev_end_lba(dev) - lba) + 1); - - return sectors; -} - - -/* - * This function can be used by HW target mode drivers to create a linked - * scatterlist from all contiguously allocated struct se_task->task_sg[]. - * This is intended to be called during the completion path by TCM Core - * when struct target_core_fabric_ops->check_task_sg_chaining is enabled. - */ -void transport_do_task_sg_chain(struct se_cmd *cmd) -{ - struct scatterlist *sg_first = NULL; - struct scatterlist *sg_prev = NULL; - int sg_prev_nents = 0; - struct scatterlist *sg; - struct se_task *task; - u32 chained_nents = 0; - int i; - - BUG_ON(!cmd->se_tfo->task_sg_chaining); - - /* - * Walk the struct se_task list and setup scatterlist chains - * for each contiguously allocated struct se_task->task_sg[]. - */ - list_for_each_entry(task, &cmd->t_task_list, t_list) { - if (!task->task_sg) - continue; - - if (!sg_first) { - sg_first = task->task_sg; - chained_nents = task->task_sg_nents; - } else { - sg_chain(sg_prev, sg_prev_nents, task->task_sg); - chained_nents += task->task_sg_nents; - } - /* - * For the padded tasks, use the extra SGL vector allocated - * in transport_allocate_data_tasks() for the sg_prev_nents - * offset into sg_chain() above. - * - * We do not need the padding for the last task (or a single - * task), but in that case we will never use the sg_prev_nents - * value below which would be incorrect. - */ - sg_prev_nents = (task->task_sg_nents + 1); - sg_prev = task->task_sg; - } - /* - * Setup the starting pointer and total t_tasks_sg_linked_no including - * padding SGs for linking and to mark the end. - */ - cmd->t_tasks_sg_chained = sg_first; - cmd->t_tasks_sg_chained_no = chained_nents; - - pr_debug("Setup cmd: %p cmd->t_tasks_sg_chained: %p and" - " t_tasks_sg_chained_no: %u\n", cmd, cmd->t_tasks_sg_chained, - cmd->t_tasks_sg_chained_no); - - for_each_sg(cmd->t_tasks_sg_chained, sg, - cmd->t_tasks_sg_chained_no, i) { - - pr_debug("SG[%d]: %p page: %p length: %d offset: %d\n", - i, sg, sg_page(sg), sg->length, sg->offset); - if (sg_is_chain(sg)) - pr_debug("SG: %p sg_is_chain=1\n", sg); - if (sg_is_last(sg)) - pr_debug("SG: %p sg_is_last=1\n", sg); - } -} -EXPORT_SYMBOL(transport_do_task_sg_chain); - -/* - * Break up cmd into chunks transport can handle - */ -static int -transport_allocate_data_tasks(struct se_cmd *cmd, - enum dma_data_direction data_direction, - struct scatterlist *cmd_sg, unsigned int sgl_nents) -{ - struct se_device *dev = cmd->se_dev; - int task_count, i; - unsigned long long lba; - sector_t sectors, dev_max_sectors; - u32 sector_size; - - if (transport_cmd_get_valid_sectors(cmd) < 0) - return -EINVAL; - - dev_max_sectors = dev->se_sub_dev->se_dev_attrib.max_sectors; - sector_size = dev->se_sub_dev->se_dev_attrib.block_size; - - WARN_ON(cmd->data_length % sector_size); - - lba = cmd->t_task_lba; - sectors = DIV_ROUND_UP(cmd->data_length, sector_size); - task_count = DIV_ROUND_UP_SECTOR_T(sectors, dev_max_sectors); - - /* - * If we need just a single task reuse the SG list in the command - * and avoid a lot of work. - */ - if (task_count == 1) { - struct se_task *task; - unsigned long flags; - - task = transport_generic_get_task(cmd, data_direction); - if (!task) - return -ENOMEM; - - task->task_sg = cmd_sg; - task->task_sg_nents = sgl_nents; - - task->task_lba = lba; - task->task_sectors = sectors; - task->task_size = task->task_sectors * sector_size; - - spin_lock_irqsave(&cmd->t_state_lock, flags); - list_add_tail(&task->t_list, &cmd->t_task_list); - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - - return task_count; - } - - for (i = 0; i < task_count; i++) { - struct se_task *task; - unsigned int task_size, task_sg_nents_padded; - struct scatterlist *sg; - unsigned long flags; - int count; - - task = transport_generic_get_task(cmd, data_direction); - if (!task) - return -ENOMEM; - - task->task_lba = lba; - task->task_sectors = min(sectors, dev_max_sectors); - task->task_size = task->task_sectors * sector_size; - - /* - * This now assumes that passed sg_ents are in PAGE_SIZE chunks - * in order to calculate the number per task SGL entries - */ - task->task_sg_nents = DIV_ROUND_UP(task->task_size, PAGE_SIZE); - /* - * Check if the fabric module driver is requesting that all - * struct se_task->task_sg[] be chained together.. If so, - * then allocate an extra padding SG entry for linking and - * marking the end of the chained SGL for every task except - * the last one for (task_count > 1) operation, or skipping - * the extra padding for the (task_count == 1) case. - */ - if (cmd->se_tfo->task_sg_chaining && (i < (task_count - 1))) { - task_sg_nents_padded = (task->task_sg_nents + 1); - } else - task_sg_nents_padded = task->task_sg_nents; - - task->task_sg = kmalloc(sizeof(struct scatterlist) * - task_sg_nents_padded, GFP_KERNEL); - if (!task->task_sg) { - cmd->se_dev->transport->free_task(task); - return -ENOMEM; - } - - sg_init_table(task->task_sg, task_sg_nents_padded); - - task_size = task->task_size; - - /* Build new sgl, only up to task_size */ - for_each_sg(task->task_sg, sg, task->task_sg_nents, count) { - if (cmd_sg->length > task_size) - break; - - *sg = *cmd_sg; - task_size -= cmd_sg->length; - cmd_sg = sg_next(cmd_sg); - } - - lba += task->task_sectors; - sectors -= task->task_sectors; - - spin_lock_irqsave(&cmd->t_state_lock, flags); - list_add_tail(&task->t_list, &cmd->t_task_list); - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - } - - return task_count; -} - -static int -transport_allocate_control_task(struct se_cmd *cmd) -{ - struct se_task *task; - unsigned long flags; - - /* Workaround for handling zero-length control CDBs */ - if ((cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) && - !cmd->data_length) - return 0; - - task = transport_generic_get_task(cmd, cmd->data_direction); - if (!task) - return -ENOMEM; - - task->task_sg = cmd->t_data_sg; - task->task_size = cmd->data_length; - task->task_sg_nents = cmd->t_data_nents; - - spin_lock_irqsave(&cmd->t_state_lock, flags); - list_add_tail(&task->t_list, &cmd->t_task_list); - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - - /* Success! Return number of tasks allocated */ - return 1; -} - /* - * Allocate any required ressources to execute the command, and either place - * it on the execution queue if possible. For writes we might not have the - * payload yet, thus notify the fabric via a call to ->write_pending instead. + * Allocate any required resources to execute the command. For writes we + * might not have the payload yet, so notify the fabric via a call to + * ->write_pending instead. Otherwise place it on the execution queue. */ int transport_generic_new_cmd(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; - int task_cdbs, task_cdbs_bidi = 0; - int set_counts = 1; int ret = 0; /* @@ -3936,35 +3501,9 @@ int transport_generic_new_cmd(struct se_cmd *cmd) goto out_fail; } - /* - * For BIDI command set up the read tasks first. - */ - if (cmd->t_bidi_data_sg && - dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) { - BUG_ON(!(cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)); - - task_cdbs_bidi = transport_allocate_data_tasks(cmd, - DMA_FROM_DEVICE, cmd->t_bidi_data_sg, - cmd->t_bidi_data_nents); - if (task_cdbs_bidi <= 0) - goto out_fail; - - atomic_inc(&cmd->t_fe_count); - atomic_inc(&cmd->t_se_count); - set_counts = 0; - } - - if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) { - task_cdbs = transport_allocate_data_tasks(cmd, - cmd->data_direction, cmd->t_data_sg, - cmd->t_data_nents); - } else { - task_cdbs = transport_allocate_control_task(cmd); - } - - if (task_cdbs < 0) - goto out_fail; - else if (!task_cdbs && (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)) { + /* Workaround for handling zero-length control CDBs */ + if ((cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) && + !cmd->data_length) { spin_lock_irq(&cmd->t_state_lock); cmd->t_state = TRANSPORT_COMPLETE; cmd->transport_state |= CMD_T_ACTIVE; @@ -3982,29 +3521,31 @@ int transport_generic_new_cmd(struct se_cmd *cmd) return 0; } - if (set_counts) { - atomic_inc(&cmd->t_fe_count); - atomic_inc(&cmd->t_se_count); + if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) { + struct se_dev_attrib *attr = &dev->se_sub_dev->se_dev_attrib; + + if (transport_cmd_get_valid_sectors(cmd) < 0) + return -EINVAL; + + BUG_ON(cmd->data_length % attr->block_size); + BUG_ON(DIV_ROUND_UP(cmd->data_length, attr->block_size) > + attr->hw_max_sectors); } - cmd->t_task_list_num = (task_cdbs + task_cdbs_bidi); - atomic_set(&cmd->t_task_cdbs_left, cmd->t_task_list_num); - atomic_set(&cmd->t_task_cdbs_ex_left, cmd->t_task_list_num); + atomic_inc(&cmd->t_fe_count); /* - * For WRITEs, let the fabric know its buffer is ready.. - * This WRITE struct se_cmd (and all of its associated struct se_task's) - * will be added to the struct se_device execution queue after its WRITE - * data has arrived. (ie: It gets handled by the transport processing - * thread a second time) + * For WRITEs, let the fabric know its buffer is ready. + * + * The command will be added to the execution queue after its write + * data has arrived. */ if (cmd->data_direction == DMA_TO_DEVICE) { - transport_add_tasks_to_state_queue(cmd); + target_add_to_state_list(cmd); return transport_generic_write_pending(cmd); } /* - * Everything else but a WRITE, add the struct se_cmd's struct se_task's - * to the execution queue. + * Everything else but a WRITE, add the command to the execution queue. */ transport_execute_tasks(cmd); return 0; @@ -4091,8 +3632,6 @@ void transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) if (cmd->se_lun) transport_lun_remove_cmd(cmd); - transport_free_dev_tasks(cmd); - transport_put_cmd(cmd); } } @@ -4233,7 +3772,8 @@ EXPORT_SYMBOL(target_wait_for_sess_cmds); static int transport_lun_wait_for_tasks(struct se_cmd *cmd, struct se_lun *lun) { unsigned long flags; - int ret; + int ret = 0; + /* * If the frontend has already requested this struct se_cmd to * be stopped, we can safely ignore this struct se_cmd. @@ -4253,10 +3793,21 @@ static int transport_lun_wait_for_tasks(struct se_cmd *cmd, struct se_lun *lun) wake_up_interruptible(&cmd->se_dev->dev_queue_obj.thread_wq); - ret = transport_stop_tasks_for_cmd(cmd); + // XXX: audit task_flags checks. + spin_lock_irqsave(&cmd->t_state_lock, flags); + if ((cmd->transport_state & CMD_T_BUSY) && + (cmd->transport_state & CMD_T_SENT)) { + if (!target_stop_cmd(cmd, &flags)) + ret++; + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + } else { + spin_unlock_irqrestore(&cmd->t_state_lock, + flags); + target_remove_from_execute_list(cmd); + } - pr_debug("ConfigFS: cmd: %p t_tasks: %d stop tasks ret:" - " %d\n", cmd, cmd->t_task_list_num, ret); + pr_debug("ConfigFS: cmd: %p stop tasks ret:" + " %d\n", cmd, ret); if (!ret) { pr_debug("ConfigFS: ITT[0x%08x] - stopping cmd....\n", cmd->se_tfo->get_task_tag(cmd)); @@ -4328,10 +3879,9 @@ static void __transport_clear_lun_from_sessions(struct se_lun *lun) goto check_cond; } cmd->transport_state &= ~CMD_T_DEV_ACTIVE; - transport_all_task_dev_remove_state(cmd); + target_remove_from_state_list(cmd); spin_unlock_irqrestore(&cmd->t_state_lock, cmd_flags); - transport_free_dev_tasks(cmd); /* * The Storage engine stopped this struct se_cmd before it was * send to the fabric frontend for delivery back to the @@ -4444,7 +3994,7 @@ bool transport_wait_for_tasks(struct se_cmd *cmd) wait_for_completion(&cmd->transport_lun_fe_stop_comp); spin_lock_irqsave(&cmd->t_state_lock, flags); - transport_all_task_dev_remove_state(cmd); + target_remove_from_state_list(cmd); /* * At this point, the frontend who was the originator of this * struct se_cmd, now owns the structure and can be released through @@ -4710,12 +4260,12 @@ int transport_check_aborted_status(struct se_cmd *cmd, int send_status) if (!send_status || (cmd->se_cmd_flags & SCF_SENT_DELAYED_TAS)) return 1; -#if 0 + pr_debug("Sending delayed SAM_STAT_TASK_ABORTED" " status for CDB: 0x%02x ITT: 0x%08x\n", cmd->t_task_cdb[0], cmd->se_tfo->get_task_tag(cmd)); -#endif + cmd->se_cmd_flags |= SCF_SENT_DELAYED_TAS; cmd->se_tfo->queue_status(cmd); ret = 1; @@ -4748,11 +4298,11 @@ void transport_send_task_abort(struct se_cmd *cmd) } } cmd->scsi_status = SAM_STAT_TASK_ABORTED; -#if 0 + pr_debug("Setting SAM_STAT_TASK_ABORTED status for CDB: 0x%02x," " ITT: 0x%08x\n", cmd->t_task_cdb[0], cmd->se_tfo->get_task_tag(cmd)); -#endif + cmd->se_tfo->queue_status(cmd); } @@ -4865,7 +4415,7 @@ static int transport_processing_thread(void *param) } out: - WARN_ON(!list_empty(&dev->state_task_list)); + WARN_ON(!list_empty(&dev->state_list)); WARN_ON(!list_empty(&dev->dev_queue_obj.qobj_list)); dev->process_thread = NULL; return 0; diff --git a/trunk/drivers/target/tcm_fc/tfc_cmd.c b/trunk/drivers/target/tcm_fc/tfc_cmd.c index a375f257aabc..f03fb9730f5b 100644 --- a/trunk/drivers/target/tcm_fc/tfc_cmd.c +++ b/trunk/drivers/target/tcm_fc/tfc_cmd.c @@ -215,20 +215,10 @@ int ft_write_pending(struct se_cmd *se_cmd) */ if ((ep->xid <= lport->lro_xid) && (fh->fh_r_ctl == FC_RCTL_DD_DATA_DESC)) { - if (se_cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) { - /* - * cmd may have been broken up into multiple - * tasks. Link their sgs together so we can - * operate on them all at once. - */ - transport_do_task_sg_chain(se_cmd); - cmd->sg = se_cmd->t_tasks_sg_chained; - cmd->sg_cnt = - se_cmd->t_tasks_sg_chained_no; - } - if (cmd->sg && lport->tt.ddp_target(lport, ep->xid, - cmd->sg, - cmd->sg_cnt)) + if ((se_cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) && + lport->tt.ddp_target(lport, ep->xid, + se_cmd->t_data_sg, + se_cmd->t_data_nents)) cmd->was_ddp_setup = 1; } } diff --git a/trunk/drivers/target/tcm_fc/tfc_conf.c b/trunk/drivers/target/tcm_fc/tfc_conf.c index 2948dc944619..9501844fae2d 100644 --- a/trunk/drivers/target/tcm_fc/tfc_conf.c +++ b/trunk/drivers/target/tcm_fc/tfc_conf.c @@ -576,9 +576,6 @@ int ft_register_configfs(void) } fabric->tf_ops = ft_fabric_ops; - /* Allowing support for task_sg_chaining */ - fabric->tf_ops.task_sg_chaining = 1; - /* * Setup default attribute lists for various fabric->tf_cit_tmpl */ diff --git a/trunk/drivers/target/tcm_fc/tfc_io.c b/trunk/drivers/target/tcm_fc/tfc_io.c index dc7c0db26e20..071a505f98fc 100644 --- a/trunk/drivers/target/tcm_fc/tfc_io.c +++ b/trunk/drivers/target/tcm_fc/tfc_io.c @@ -228,7 +228,7 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp) "payload, Frame will be dropped if" "'Sequence Initiative' bit in f_ctl is" "not set\n", __func__, ep->xid, f_ctl, - cmd->sg, cmd->sg_cnt); + se_cmd->t_data_sg, se_cmd->t_data_nents); /* * Invalidate HW DDP context if it was setup for respective * command. Invalidation of HW DDP context is requited in both diff --git a/trunk/drivers/tty/amiserial.c b/trunk/drivers/tty/amiserial.c index 6cc4358f68c1..35819e312624 100644 --- a/trunk/drivers/tty/amiserial.c +++ b/trunk/drivers/tty/amiserial.c @@ -1033,7 +1033,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state, if (!retinfo) return -EFAULT; memset(&tmp, 0, sizeof(tmp)); - tty_lock(); + tty_lock(tty); tmp.line = tty->index; tmp.port = state->port; tmp.flags = state->tport.flags; @@ -1042,7 +1042,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state, tmp.close_delay = state->tport.close_delay; tmp.closing_wait = state->tport.closing_wait; tmp.custom_divisor = state->custom_divisor; - tty_unlock(); + tty_unlock(tty); if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) return -EFAULT; return 0; @@ -1059,12 +1059,12 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) return -EFAULT; - tty_lock(); + tty_lock(tty); change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) || new_serial.custom_divisor != state->custom_divisor; if (new_serial.irq || new_serial.port != state->port || new_serial.xmit_fifo_size != state->xmit_fifo_size) { - tty_unlock(); + tty_unlock(tty); return -EINVAL; } @@ -1074,7 +1074,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, (new_serial.xmit_fifo_size != state->xmit_fifo_size) || ((new_serial.flags & ~ASYNC_USR_MASK) != (port->flags & ~ASYNC_USR_MASK))) { - tty_unlock(); + tty_unlock(tty); return -EPERM; } port->flags = ((port->flags & ~ASYNC_USR_MASK) | @@ -1084,7 +1084,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, } if (new_serial.baud_base < 9600) { - tty_unlock(); + tty_unlock(tty); return -EINVAL; } @@ -1116,7 +1116,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, } } else retval = startup(tty, state); - tty_unlock(); + tty_unlock(tty); return retval; } diff --git a/trunk/drivers/tty/bfin_jtag_comm.c b/trunk/drivers/tty/bfin_jtag_comm.c index 946f799861f5..61fc74fe1747 100644 --- a/trunk/drivers/tty/bfin_jtag_comm.c +++ b/trunk/drivers/tty/bfin_jtag_comm.c @@ -62,9 +62,7 @@ static inline uint32_t bfin_write_emudat_chars(char a, char b, char c, char d) static struct tty_driver *bfin_jc_driver; static struct task_struct *bfin_jc_kthread; -static struct tty_struct * volatile bfin_jc_tty; -static unsigned long bfin_jc_count; -static DEFINE_MUTEX(bfin_jc_tty_mutex); +static struct tty_port port; static volatile struct circ_buf bfin_jc_write_buf; static int @@ -73,18 +71,21 @@ bfin_jc_emudat_manager(void *arg) uint32_t inbound_len = 0, outbound_len = 0; while (!kthread_should_stop()) { + struct tty_struct *tty = tty_port_tty_get(&port); /* no one left to give data to, so sleep */ - if (bfin_jc_tty == NULL && circ_empty(&bfin_jc_write_buf)) { + if (tty == NULL && circ_empty(&bfin_jc_write_buf)) { pr_debug("waiting for readers\n"); __set_current_state(TASK_UNINTERRUPTIBLE); schedule(); __set_current_state(TASK_RUNNING); + continue; } /* no data available, so just chill */ if (!(bfin_read_DBGSTAT() & EMUDIF) && circ_empty(&bfin_jc_write_buf)) { pr_debug("waiting for data (in_len = %i) (circ: %i %i)\n", inbound_len, bfin_jc_write_buf.tail, bfin_jc_write_buf.head); + tty_kref_put(tty); if (inbound_len) schedule(); else @@ -94,9 +95,6 @@ bfin_jc_emudat_manager(void *arg) /* if incoming data is ready, eat it */ if (bfin_read_DBGSTAT() & EMUDIF) { - struct tty_struct *tty; - mutex_lock(&bfin_jc_tty_mutex); - tty = (struct tty_struct *)bfin_jc_tty; if (tty != NULL) { uint32_t emudat = bfin_read_emudat(); if (inbound_len == 0) { @@ -110,7 +108,6 @@ bfin_jc_emudat_manager(void *arg) tty_flip_buffer_push(tty); } } - mutex_unlock(&bfin_jc_tty_mutex); } /* if outgoing data is ready, post it */ @@ -120,7 +117,6 @@ bfin_jc_emudat_manager(void *arg) bfin_write_emudat(outbound_len); pr_debug("outgoing length: 0x%08x\n", outbound_len); } else { - struct tty_struct *tty; int tail = bfin_jc_write_buf.tail; size_t ate = (4 <= outbound_len ? 4 : outbound_len); uint32_t emudat = @@ -132,14 +128,12 @@ bfin_jc_emudat_manager(void *arg) ); bfin_jc_write_buf.tail += ate; outbound_len -= ate; - mutex_lock(&bfin_jc_tty_mutex); - tty = (struct tty_struct *)bfin_jc_tty; if (tty) tty_wakeup(tty); - mutex_unlock(&bfin_jc_tty_mutex); pr_debug(" outgoing data: 0x%08x (pushing %zu)\n", emudat, ate); } } + tty_kref_put(tty); } __set_current_state(TASK_RUNNING); @@ -149,24 +143,28 @@ bfin_jc_emudat_manager(void *arg) static int bfin_jc_open(struct tty_struct *tty, struct file *filp) { - mutex_lock(&bfin_jc_tty_mutex); - pr_debug("open %lu\n", bfin_jc_count); - ++bfin_jc_count; - bfin_jc_tty = tty; + unsigned long flags; + + spin_lock_irqsave(&port.lock, flags); + port.count++; + spin_unlock_irqrestore(&port.lock, flags); + tty_port_tty_set(&port, tty); wake_up_process(bfin_jc_kthread); - mutex_unlock(&bfin_jc_tty_mutex); return 0; } static void bfin_jc_close(struct tty_struct *tty, struct file *filp) { - mutex_lock(&bfin_jc_tty_mutex); - pr_debug("close %lu\n", bfin_jc_count); - if (--bfin_jc_count == 0) - bfin_jc_tty = NULL; + unsigned long flags; + bool last; + + spin_lock_irqsave(&port.lock, flags); + last = --port.count == 0; + spin_unlock_irqrestore(&port.lock, flags); + if (last) + tty_port_tty_set(&port, NULL); wake_up_process(bfin_jc_kthread); - mutex_unlock(&bfin_jc_tty_mutex); } /* XXX: we dont handle the put_char() case where we must handle count = 1 */ @@ -242,6 +240,8 @@ static int __init bfin_jc_init(void) { int ret; + tty_port_init(&port); + bfin_jc_kthread = kthread_create(bfin_jc_emudat_manager, NULL, DRV_NAME); if (IS_ERR(bfin_jc_kthread)) return PTR_ERR(bfin_jc_kthread); diff --git a/trunk/drivers/tty/cyclades.c b/trunk/drivers/tty/cyclades.c index e61cabdd69df..6984e1a2686a 100644 --- a/trunk/drivers/tty/cyclades.c +++ b/trunk/drivers/tty/cyclades.c @@ -1599,7 +1599,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp) * If the port is the middle of closing, bail out now */ if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) { - wait_event_interruptible_tty(info->port.close_wait, + wait_event_interruptible_tty(tty, info->port.close_wait, !(info->port.flags & ASYNC_CLOSING)); return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS; } diff --git a/trunk/drivers/tty/hvc/hvc_console.c b/trunk/drivers/tty/hvc/hvc_console.c index 8880adf5fc6f..2d691eb7c40a 100644 --- a/trunk/drivers/tty/hvc/hvc_console.c +++ b/trunk/drivers/tty/hvc/hvc_console.c @@ -107,7 +107,7 @@ static struct hvc_struct *hvc_get_by_index(int index) list_for_each_entry(hp, &hvc_structs, next) { spin_lock_irqsave(&hp->lock, flags); if (hp->index == index) { - kref_get(&hp->kref); + tty_port_get(&hp->port); spin_unlock_irqrestore(&hp->lock, flags); spin_unlock(&hvc_structs_lock); return hp; @@ -229,9 +229,9 @@ static int __init hvc_console_init(void) console_initcall(hvc_console_init); /* callback when the kboject ref count reaches zero. */ -static void destroy_hvc_struct(struct kref *kref) +static void hvc_port_destruct(struct tty_port *port) { - struct hvc_struct *hp = container_of(kref, struct hvc_struct, kref); + struct hvc_struct *hp = container_of(port, struct hvc_struct, port); unsigned long flags; spin_lock(&hvc_structs_lock); @@ -264,7 +264,7 @@ int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops) /* make sure no no tty has been registered in this index */ hp = hvc_get_by_index(index); if (hp) { - kref_put(&hp->kref, destroy_hvc_struct); + tty_port_put(&hp->port); return -1; } @@ -313,20 +313,17 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) if (!(hp = hvc_get_by_index(tty->index))) return -ENODEV; - spin_lock_irqsave(&hp->lock, flags); + spin_lock_irqsave(&hp->port.lock, flags); /* Check and then increment for fast path open. */ - if (hp->count++ > 0) { - tty_kref_get(tty); - spin_unlock_irqrestore(&hp->lock, flags); + if (hp->port.count++ > 0) { + spin_unlock_irqrestore(&hp->port.lock, flags); hvc_kick(); return 0; } /* else count == 0 */ + spin_unlock_irqrestore(&hp->port.lock, flags); tty->driver_data = hp; - - hp->tty = tty_kref_get(tty); - - spin_unlock_irqrestore(&hp->lock, flags); + tty_port_tty_set(&hp->port, tty); if (hp->ops->notifier_add) rc = hp->ops->notifier_add(hp, hp->data); @@ -338,12 +335,9 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) * tty fields and return the kref reference. */ if (rc) { - spin_lock_irqsave(&hp->lock, flags); - hp->tty = NULL; - spin_unlock_irqrestore(&hp->lock, flags); - tty_kref_put(tty); + tty_port_tty_set(&hp->port, NULL); tty->driver_data = NULL; - kref_put(&hp->kref, destroy_hvc_struct); + tty_port_put(&hp->port); printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc); } /* Force wakeup of the polling thread */ @@ -370,12 +364,12 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) hp = tty->driver_data; - spin_lock_irqsave(&hp->lock, flags); + spin_lock_irqsave(&hp->port.lock, flags); - if (--hp->count == 0) { + if (--hp->port.count == 0) { + spin_unlock_irqrestore(&hp->port.lock, flags); /* We are done with the tty pointer now. */ - hp->tty = NULL; - spin_unlock_irqrestore(&hp->lock, flags); + tty_port_tty_set(&hp->port, NULL); if (hp->ops->notifier_del) hp->ops->notifier_del(hp, hp->data); @@ -390,14 +384,13 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) */ tty_wait_until_sent_from_close(tty, HVC_CLOSE_WAIT); } else { - if (hp->count < 0) + if (hp->port.count < 0) printk(KERN_ERR "hvc_close %X: oops, count is %d\n", - hp->vtermno, hp->count); - spin_unlock_irqrestore(&hp->lock, flags); + hp->vtermno, hp->port.count); + spin_unlock_irqrestore(&hp->port.lock, flags); } - tty_kref_put(tty); - kref_put(&hp->kref, destroy_hvc_struct); + tty_port_put(&hp->port); } static void hvc_hangup(struct tty_struct *tty) @@ -412,32 +405,31 @@ static void hvc_hangup(struct tty_struct *tty) /* cancel pending tty resize work */ cancel_work_sync(&hp->tty_resize); - spin_lock_irqsave(&hp->lock, flags); + spin_lock_irqsave(&hp->port.lock, flags); /* * The N_TTY line discipline has problems such that in a close vs * open->hangup case this can be called after the final close so prevent * that from happening for now. */ - if (hp->count <= 0) { - spin_unlock_irqrestore(&hp->lock, flags); + if (hp->port.count <= 0) { + spin_unlock_irqrestore(&hp->port.lock, flags); return; } - temp_open_count = hp->count; - hp->count = 0; - hp->n_outbuf = 0; - hp->tty = NULL; + temp_open_count = hp->port.count; + hp->port.count = 0; + spin_unlock_irqrestore(&hp->port.lock, flags); + tty_port_tty_set(&hp->port, NULL); - spin_unlock_irqrestore(&hp->lock, flags); + hp->n_outbuf = 0; if (hp->ops->notifier_hangup) hp->ops->notifier_hangup(hp, hp->data); while(temp_open_count) { --temp_open_count; - tty_kref_put(tty); - kref_put(&hp->kref, destroy_hvc_struct); + tty_port_put(&hp->port); } } @@ -478,7 +470,8 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count if (!hp) return -EPIPE; - if (hp->count <= 0) + /* FIXME what's this (unprotected) check for? */ + if (hp->port.count <= 0) return -EIO; spin_lock_irqsave(&hp->lock, flags); @@ -526,13 +519,12 @@ static void hvc_set_winsz(struct work_struct *work) hp = container_of(work, struct hvc_struct, tty_resize); - spin_lock_irqsave(&hp->lock, hvc_flags); - if (!hp->tty) { - spin_unlock_irqrestore(&hp->lock, hvc_flags); + tty = tty_port_tty_get(&hp->port); + if (!tty) return; - } - ws = hp->ws; - tty = tty_kref_get(hp->tty); + + spin_lock_irqsave(&hp->lock, hvc_flags); + ws = hp->ws; spin_unlock_irqrestore(&hp->lock, hvc_flags); tty_do_resize(tty, &ws); @@ -601,7 +593,7 @@ int hvc_poll(struct hvc_struct *hp) } /* No tty attached, just skip */ - tty = tty_kref_get(hp->tty); + tty = tty_port_tty_get(&hp->port); if (tty == NULL) goto bail; @@ -681,8 +673,7 @@ int hvc_poll(struct hvc_struct *hp) tty_flip_buffer_push(tty); } - if (tty) - tty_kref_put(tty); + tty_kref_put(tty); return poll_mask; } @@ -817,6 +808,10 @@ static const struct tty_operations hvc_ops = { #endif }; +static const struct tty_port_operations hvc_port_ops = { + .destruct = hvc_port_destruct, +}; + struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, const struct hv_ops *ops, int outbuf_size) @@ -842,7 +837,8 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, hp->outbuf_size = outbuf_size; hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))]; - kref_init(&hp->kref); + tty_port_init(&hp->port); + hp->port.ops = &hvc_port_ops; INIT_WORK(&hp->tty_resize, hvc_set_winsz); spin_lock_init(&hp->lock); @@ -875,9 +871,9 @@ int hvc_remove(struct hvc_struct *hp) unsigned long flags; struct tty_struct *tty; - spin_lock_irqsave(&hp->lock, flags); - tty = tty_kref_get(hp->tty); + tty = tty_port_tty_get(&hp->port); + spin_lock_irqsave(&hp->lock, flags); if (hp->index < MAX_NR_HVC_CONSOLES) vtermnos[hp->index] = -1; @@ -891,7 +887,7 @@ int hvc_remove(struct hvc_struct *hp) * kref cause it to be removed, which will probably be the tty_vhangup * below. */ - kref_put(&hp->kref, destroy_hvc_struct); + tty_port_put(&hp->port); /* * This function call will auto chain call hvc_hangup. diff --git a/trunk/drivers/tty/hvc/hvc_console.h b/trunk/drivers/tty/hvc/hvc_console.h index c335a1492a54..674d23cb919a 100644 --- a/trunk/drivers/tty/hvc/hvc_console.h +++ b/trunk/drivers/tty/hvc/hvc_console.h @@ -46,10 +46,9 @@ #define HVC_ALLOC_TTY_ADAPTERS 8 struct hvc_struct { + struct tty_port port; spinlock_t lock; int index; - struct tty_struct *tty; - int count; int do_wakeup; char *outbuf; int outbuf_size; @@ -61,7 +60,6 @@ struct hvc_struct { struct winsize ws; struct work_struct tty_resize; struct list_head next; - struct kref kref; /* ref count & hvc_struct lifetime */ }; /* implemented by a low level driver */ diff --git a/trunk/drivers/tty/hvc/hvc_xen.c b/trunk/drivers/tty/hvc/hvc_xen.c index 83d5c88e7165..d3d91dae065c 100644 --- a/trunk/drivers/tty/hvc/hvc_xen.c +++ b/trunk/drivers/tty/hvc/hvc_xen.c @@ -430,9 +430,9 @@ static int __devinit xencons_probe(struct xenbus_device *dev, if (devid == 0) return -ENODEV; - info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO); + info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL); if (!info) - goto error_nomem; + return -ENOMEM; dev_set_drvdata(&dev->dev, info); info->xbdev = dev; info->vtermno = xenbus_devid_to_vtermno(devid); diff --git a/trunk/drivers/tty/hvc/hvcs.c b/trunk/drivers/tty/hvc/hvcs.c index 3436436fe2d7..d56788c83974 100644 --- a/trunk/drivers/tty/hvc/hvcs.c +++ b/trunk/drivers/tty/hvc/hvcs.c @@ -261,6 +261,7 @@ static DEFINE_SPINLOCK(hvcs_pi_lock); /* One vty-server per hvcs_struct */ struct hvcs_struct { + struct tty_port port; spinlock_t lock; /* @@ -269,9 +270,6 @@ struct hvcs_struct { */ unsigned int index; - struct tty_struct *tty; - int open_count; - /* * Used to tell the driver kernel_thread what operations need to take * place upon this hvcs_struct instance. @@ -290,12 +288,11 @@ struct hvcs_struct { int chars_in_buffer; /* - * Any variable below the kref is valid before a tty is connected and + * Any variable below is valid before a tty is connected and * stays valid after the tty is disconnected. These shouldn't be * whacked until the kobject refcount reaches zero though some entries * may be changed via sysfs initiatives. */ - struct kref kref; /* ref count & hvcs_struct lifetime */ int connected; /* is the vty-server currently connected to a vty? */ uint32_t p_unit_address; /* partner unit address */ uint32_t p_partition_ID; /* partner partition ID */ @@ -304,9 +301,6 @@ struct hvcs_struct { struct vio_dev *vdev; }; -/* Required to back map a kref to its containing object */ -#define from_kref(k) container_of(k, struct hvcs_struct, kref) - static LIST_HEAD(hvcs_structs); static DEFINE_SPINLOCK(hvcs_structs_lock); static DEFINE_MUTEX(hvcs_init_mutex); @@ -422,7 +416,7 @@ static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribut spin_lock_irqsave(&hvcsd->lock, flags); - if (hvcsd->open_count > 0) { + if (hvcsd->port.count > 0) { spin_unlock_irqrestore(&hvcsd->lock, flags); printk(KERN_INFO "HVCS: vterm state unchanged. " "The hvcs device node is still in use.\n"); @@ -564,7 +558,7 @@ static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance) static void hvcs_try_write(struct hvcs_struct *hvcsd) { uint32_t unit_address = hvcsd->vdev->unit_address; - struct tty_struct *tty = hvcsd->tty; + struct tty_struct *tty = hvcsd->port.tty; int sent; if (hvcsd->todo_mask & HVCS_TRY_WRITE) { @@ -602,7 +596,7 @@ static int hvcs_io(struct hvcs_struct *hvcsd) spin_lock_irqsave(&hvcsd->lock, flags); unit_address = hvcsd->vdev->unit_address; - tty = hvcsd->tty; + tty = hvcsd->port.tty; hvcs_try_write(hvcsd); @@ -701,10 +695,9 @@ static void hvcs_return_index(int index) hvcs_index_list[index] = -1; } -/* callback when the kref ref count reaches zero */ -static void destroy_hvcs_struct(struct kref *kref) +static void hvcs_destruct_port(struct tty_port *p) { - struct hvcs_struct *hvcsd = from_kref(kref); + struct hvcs_struct *hvcsd = container_of(p, struct hvcs_struct, port); struct vio_dev *vdev; unsigned long flags; @@ -741,6 +734,10 @@ static void destroy_hvcs_struct(struct kref *kref) kfree(hvcsd); } +static const struct tty_port_operations hvcs_port_ops = { + .destruct = hvcs_destruct_port, +}; + static int hvcs_get_index(void) { int i; @@ -789,10 +786,9 @@ static int __devinit hvcs_probe( if (!hvcsd) return -ENODEV; - + tty_port_init(&hvcsd->port); + hvcsd->port.ops = &hvcs_port_ops; spin_lock_init(&hvcsd->lock); - /* Automatically incs the refcount the first time */ - kref_init(&hvcsd->kref); hvcsd->vdev = dev; dev_set_drvdata(&dev->dev, hvcsd); @@ -852,7 +848,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev) spin_lock_irqsave(&hvcsd->lock, flags); - tty = hvcsd->tty; + tty = hvcsd->port.tty; spin_unlock_irqrestore(&hvcsd->lock, flags); @@ -860,7 +856,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev) * Let the last holder of this object cause it to be removed, which * would probably be tty_hangup below. */ - kref_put(&hvcsd->kref, destroy_hvcs_struct); + tty_port_put(&hvcsd->port); /* * The hangup is a scheduled function which will auto chain call @@ -1094,7 +1090,7 @@ static struct hvcs_struct *hvcs_get_by_index(int index) list_for_each_entry(hvcsd, &hvcs_structs, next) { spin_lock_irqsave(&hvcsd->lock, flags); if (hvcsd->index == index) { - kref_get(&hvcsd->kref); + tty_port_get(&hvcsd->port); spin_unlock_irqrestore(&hvcsd->lock, flags); spin_unlock(&hvcs_structs_lock); return hvcsd; @@ -1138,8 +1134,8 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) if ((retval = hvcs_partner_connect(hvcsd))) goto error_release; - hvcsd->open_count = 1; - hvcsd->tty = tty; + hvcsd->port.count = 1; + hvcsd->port.tty = tty; tty->driver_data = hvcsd; memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN); @@ -1160,7 +1156,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) * and will grab the spinlock and free the connection if it fails. */ if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) { - kref_put(&hvcsd->kref, destroy_hvcs_struct); + tty_port_put(&hvcsd->port); printk(KERN_WARNING "HVCS: enable device failed.\n"); return rc; } @@ -1171,8 +1167,8 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) hvcsd = tty->driver_data; spin_lock_irqsave(&hvcsd->lock, flags); - kref_get(&hvcsd->kref); - hvcsd->open_count++; + tty_port_get(&hvcsd->port); + hvcsd->port.count++; hvcsd->todo_mask |= HVCS_SCHED_READ; spin_unlock_irqrestore(&hvcsd->lock, flags); @@ -1186,7 +1182,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) error_release: spin_unlock_irqrestore(&hvcsd->lock, flags); - kref_put(&hvcsd->kref, destroy_hvcs_struct); + tty_port_put(&hvcsd->port); printk(KERN_WARNING "HVCS: partner connect failed.\n"); return retval; @@ -1216,7 +1212,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) hvcsd = tty->driver_data; spin_lock_irqsave(&hvcsd->lock, flags); - if (--hvcsd->open_count == 0) { + if (--hvcsd->port.count == 0) { vio_disable_interrupts(hvcsd->vdev); @@ -1225,7 +1221,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) * execute any operations on the TTY even though it is obligated * to deliver any pending I/O to the hypervisor. */ - hvcsd->tty = NULL; + hvcsd->port.tty = NULL; irq = hvcsd->vdev->irq; spin_unlock_irqrestore(&hvcsd->lock, flags); @@ -1240,16 +1236,16 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) tty->driver_data = NULL; free_irq(irq, hvcsd); - kref_put(&hvcsd->kref, destroy_hvcs_struct); + tty_port_put(&hvcsd->port); return; - } else if (hvcsd->open_count < 0) { + } else if (hvcsd->port.count < 0) { printk(KERN_ERR "HVCS: vty-server@%X open_count: %d" " is missmanaged.\n", - hvcsd->vdev->unit_address, hvcsd->open_count); + hvcsd->vdev->unit_address, hvcsd->port.count); } spin_unlock_irqrestore(&hvcsd->lock, flags); - kref_put(&hvcsd->kref, destroy_hvcs_struct); + tty_port_put(&hvcsd->port); } static void hvcs_hangup(struct tty_struct * tty) @@ -1261,7 +1257,7 @@ static void hvcs_hangup(struct tty_struct * tty) spin_lock_irqsave(&hvcsd->lock, flags); /* Preserve this so that we know how many kref refs to put */ - temp_open_count = hvcsd->open_count; + temp_open_count = hvcsd->port.count; /* * Don't kref put inside the spinlock because the destruction @@ -1273,10 +1269,10 @@ static void hvcs_hangup(struct tty_struct * tty) hvcsd->todo_mask = 0; /* I don't think the tty needs the hvcs_struct pointer after a hangup */ - hvcsd->tty->driver_data = NULL; - hvcsd->tty = NULL; + tty->driver_data = NULL; + hvcsd->port.tty = NULL; - hvcsd->open_count = 0; + hvcsd->port.count = 0; /* This will drop any buffered data on the floor which is OK in a hangup * scenario. */ @@ -1301,7 +1297,7 @@ static void hvcs_hangup(struct tty_struct * tty) * NOTE: If this hangup was signaled from user space then the * final put will never happen. */ - kref_put(&hvcsd->kref, destroy_hvcs_struct); + tty_port_put(&hvcsd->port); } } @@ -1347,7 +1343,7 @@ static int hvcs_write(struct tty_struct *tty, * the middle of a write operation? This is a crummy place to do this * but we want to keep it all in the spinlock. */ - if (hvcsd->open_count <= 0) { + if (hvcsd->port.count <= 0) { spin_unlock_irqrestore(&hvcsd->lock, flags); return -ENODEV; } @@ -1421,7 +1417,7 @@ static int hvcs_write_room(struct tty_struct *tty) { struct hvcs_struct *hvcsd = tty->driver_data; - if (!hvcsd || hvcsd->open_count <= 0) + if (!hvcsd || hvcsd->port.count <= 0) return 0; return HVCS_BUFF_LEN - hvcsd->chars_in_buffer; diff --git a/trunk/drivers/tty/hvc/hvsi.c b/trunk/drivers/tty/hvc/hvsi.c index a7488b748647..6f5bc49c441f 100644 --- a/trunk/drivers/tty/hvc/hvsi.c +++ b/trunk/drivers/tty/hvc/hvsi.c @@ -69,14 +69,13 @@ #define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) struct hvsi_struct { + struct tty_port port; struct delayed_work writer; struct work_struct handshaker; wait_queue_head_t emptyq; /* woken when outbuf is emptied */ wait_queue_head_t stateq; /* woken when HVSI state changes */ spinlock_t lock; int index; - struct tty_struct *tty; - int count; uint8_t throttle_buf[128]; uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */ /* inbuf is for packet reassembly. leave a little room for leftovers. */ @@ -237,7 +236,7 @@ static int hvsi_read(struct hvsi_struct *hp, char *buf, int count) } static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet, - struct tty_struct **to_hangup, struct hvsi_struct **to_handshake) + struct tty_struct *tty, struct hvsi_struct **to_handshake) { struct hvsi_control *header = (struct hvsi_control *)packet; @@ -247,9 +246,8 @@ static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet, /* CD went away; no more connection */ pr_debug("hvsi%i: CD dropped\n", hp->index); hp->mctrl &= TIOCM_CD; - /* If userland hasn't done an open(2) yet, hp->tty is NULL. */ - if (hp->tty && !(hp->tty->flags & CLOCAL)) - *to_hangup = hp->tty; + if (tty && !C_CLOCAL(tty)) + tty_hangup(tty); } break; case VSV_CLOSE_PROTOCOL: @@ -331,7 +329,8 @@ static void hvsi_recv_query(struct hvsi_struct *hp, uint8_t *packet) } } -static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len) +static void hvsi_insert_chars(struct hvsi_struct *hp, struct tty_struct *tty, + const char *buf, int len) { int i; @@ -347,7 +346,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len) continue; } #endif /* CONFIG_MAGIC_SYSRQ */ - tty_insert_flip_char(hp->tty, c, 0); + tty_insert_flip_char(tty, c, 0); } } @@ -360,7 +359,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len) * revisited. */ #define TTY_THRESHOLD_THROTTLE 128 -static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, +static bool hvsi_recv_data(struct hvsi_struct *hp, struct tty_struct *tty, const uint8_t *packet) { const struct hvsi_header *header = (const struct hvsi_header *)packet; @@ -371,14 +370,14 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, pr_debug("queueing %i chars '%.*s'\n", datalen, datalen, data); if (datalen == 0) - return NULL; + return false; if (overflow > 0) { pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__); datalen = TTY_THRESHOLD_THROTTLE; } - hvsi_insert_chars(hp, data, datalen); + hvsi_insert_chars(hp, tty, data, datalen); if (overflow > 0) { /* @@ -390,7 +389,7 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, hp->n_throttle = overflow; } - return hp->tty; + return true; } /* @@ -399,14 +398,13 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, * machine during console handshaking (in which case tty = NULL and we ignore * incoming data). */ -static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, - struct tty_struct **hangup, struct hvsi_struct **handshake) +static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct *tty, + struct hvsi_struct **handshake) { uint8_t *packet = hp->inbuf; int chunklen; + bool flip = false; - *flip = NULL; - *hangup = NULL; *handshake = NULL; chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ); @@ -440,12 +438,12 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, case VS_DATA_PACKET_HEADER: if (!is_open(hp)) break; - if (hp->tty == NULL) + if (tty == NULL) break; /* no tty buffer to put data in */ - *flip = hvsi_recv_data(hp, packet); + flip = hvsi_recv_data(hp, tty, packet); break; case VS_CONTROL_PACKET_HEADER: - hvsi_recv_control(hp, packet, hangup, handshake); + hvsi_recv_control(hp, packet, tty, handshake); break; case VS_QUERY_RESPONSE_PACKET_HEADER: hvsi_recv_response(hp, packet); @@ -462,28 +460,26 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, packet += len_packet(packet); - if (*hangup || *handshake) { - pr_debug("%s: hangup or handshake\n", __func__); - /* - * we need to send the hangup now before receiving any more data. - * If we get "data, hangup, data", we can't deliver the second - * data before the hangup. - */ + if (*handshake) { + pr_debug("%s: handshake\n", __func__); break; } } compact_inbuf(hp, packet); + if (flip) + tty_flip_buffer_push(tty); + return 1; } -static void hvsi_send_overflow(struct hvsi_struct *hp) +static void hvsi_send_overflow(struct hvsi_struct *hp, struct tty_struct *tty) { pr_debug("%s: delivering %i bytes overflow\n", __func__, hp->n_throttle); - hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle); + hvsi_insert_chars(hp, tty, hp->throttle_buf, hp->n_throttle); hp->n_throttle = 0; } @@ -494,35 +490,20 @@ static void hvsi_send_overflow(struct hvsi_struct *hp) static irqreturn_t hvsi_interrupt(int irq, void *arg) { struct hvsi_struct *hp = (struct hvsi_struct *)arg; - struct tty_struct *flip; - struct tty_struct *hangup; struct hvsi_struct *handshake; + struct tty_struct *tty; unsigned long flags; int again = 1; pr_debug("%s\n", __func__); + tty = tty_port_tty_get(&hp->port); + while (again) { spin_lock_irqsave(&hp->lock, flags); - again = hvsi_load_chunk(hp, &flip, &hangup, &handshake); + again = hvsi_load_chunk(hp, tty, &handshake); spin_unlock_irqrestore(&hp->lock, flags); - /* - * we have to call tty_flip_buffer_push() and tty_hangup() outside our - * spinlock. But we also have to keep going until we've read all the - * available data. - */ - - if (flip) { - /* there was data put in the tty flip buffer */ - tty_flip_buffer_push(flip); - flip = NULL; - } - - if (hangup) { - tty_hangup(hangup); - } - if (handshake) { pr_debug("hvsi%i: attempting re-handshake\n", handshake->index); schedule_work(&handshake->handshaker); @@ -530,18 +511,15 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg) } spin_lock_irqsave(&hp->lock, flags); - if (hp->tty && hp->n_throttle - && (!test_bit(TTY_THROTTLED, &hp->tty->flags))) { - /* we weren't hung up and we weren't throttled, so we can deliver the - * rest now */ - flip = hp->tty; - hvsi_send_overflow(hp); + if (tty && hp->n_throttle && !test_bit(TTY_THROTTLED, &tty->flags)) { + /* we weren't hung up and we weren't throttled, so we can + * deliver the rest now */ + hvsi_send_overflow(hp, tty); + tty_flip_buffer_push(tty); } spin_unlock_irqrestore(&hp->lock, flags); - if (flip) { - tty_flip_buffer_push(flip); - } + tty_kref_put(tty); return IRQ_HANDLED; } @@ -749,9 +727,9 @@ static int hvsi_open(struct tty_struct *tty, struct file *filp) if (hp->state == HVSI_FSP_DIED) return -EIO; + tty_port_tty_set(&hp->port, tty); spin_lock_irqsave(&hp->lock, flags); - hp->tty = tty; - hp->count++; + hp->port.count++; atomic_set(&hp->seqno, 0); h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); spin_unlock_irqrestore(&hp->lock, flags); @@ -808,8 +786,8 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp) spin_lock_irqsave(&hp->lock, flags); - if (--hp->count == 0) { - hp->tty = NULL; + if (--hp->port.count == 0) { + tty_port_tty_set(&hp->port, NULL); hp->inbuf_end = hp->inbuf; /* discard remaining partial packets */ /* only close down connection if it is not the console */ @@ -841,9 +819,9 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp) spin_lock_irqsave(&hp->lock, flags); } - } else if (hp->count < 0) + } else if (hp->port.count < 0) printk(KERN_ERR "hvsi_close %lu: oops, count is %d\n", - hp - hvsi_ports, hp->count); + hp - hvsi_ports, hp->port.count); spin_unlock_irqrestore(&hp->lock, flags); } @@ -855,12 +833,11 @@ static void hvsi_hangup(struct tty_struct *tty) pr_debug("%s\n", __func__); - spin_lock_irqsave(&hp->lock, flags); + tty_port_tty_set(&hp->port, NULL); - hp->count = 0; + spin_lock_irqsave(&hp->lock, flags); + hp->port.count = 0; hp->n_outbuf = 0; - hp->tty = NULL; - spin_unlock_irqrestore(&hp->lock, flags); } @@ -888,6 +865,7 @@ static void hvsi_write_worker(struct work_struct *work) { struct hvsi_struct *hp = container_of(work, struct hvsi_struct, writer.work); + struct tty_struct *tty; unsigned long flags; #ifdef DEBUG static long start_j = 0; @@ -921,7 +899,11 @@ static void hvsi_write_worker(struct work_struct *work) start_j = 0; #endif /* DEBUG */ wake_up_all(&hp->emptyq); - tty_wakeup(hp->tty); + tty = tty_port_tty_get(&hp->port); + if (tty) { + tty_wakeup(tty); + tty_kref_put(tty); + } } out: @@ -966,8 +948,8 @@ static int hvsi_write(struct tty_struct *tty, * and hvsi_write_worker will be scheduled. subsequent hvsi_write() calls * will see there is no room in outbuf and return. */ - while ((count > 0) && (hvsi_write_room(hp->tty) > 0)) { - int chunksize = min(count, hvsi_write_room(hp->tty)); + while ((count > 0) && (hvsi_write_room(tty) > 0)) { + int chunksize = min(count, hvsi_write_room(tty)); BUG_ON(hp->n_outbuf < 0); memcpy(hp->outbuf + hp->n_outbuf, source, chunksize); @@ -1014,19 +996,16 @@ static void hvsi_unthrottle(struct tty_struct *tty) { struct hvsi_struct *hp = tty->driver_data; unsigned long flags; - int shouldflip = 0; pr_debug("%s\n", __func__); spin_lock_irqsave(&hp->lock, flags); if (hp->n_throttle) { - hvsi_send_overflow(hp); - shouldflip = 1; + hvsi_send_overflow(hp, tty); + tty_flip_buffer_push(tty); } spin_unlock_irqrestore(&hp->lock, flags); - if (shouldflip) - tty_flip_buffer_push(hp->tty); h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); } @@ -1228,6 +1207,7 @@ static int __init hvsi_console_init(void) init_waitqueue_head(&hp->emptyq); init_waitqueue_head(&hp->stateq); spin_lock_init(&hp->lock); + tty_port_init(&hp->port); hp->index = hvsi_count; hp->inbuf_end = hp->inbuf; hp->state = HVSI_CLOSED; diff --git a/trunk/drivers/tty/hvc/hvsi_lib.c b/trunk/drivers/tty/hvc/hvsi_lib.c index 6f4dd83d8695..59c135dd5d20 100644 --- a/trunk/drivers/tty/hvc/hvsi_lib.c +++ b/trunk/drivers/tty/hvc/hvsi_lib.c @@ -377,7 +377,7 @@ int hvsilib_open(struct hvsi_priv *pv, struct hvc_struct *hp) pr_devel("HVSI@%x: open !\n", pv->termno); /* Keep track of the tty data structure */ - pv->tty = tty_kref_get(hp->tty); + pv->tty = tty_port_tty_get(&hp->port); hvsilib_establish(pv); diff --git a/trunk/drivers/tty/ipwireless/tty.c b/trunk/drivers/tty/ipwireless/tty.c index 4daf962f7055..f8b5fa0093a3 100644 --- a/trunk/drivers/tty/ipwireless/tty.c +++ b/trunk/drivers/tty/ipwireless/tty.c @@ -44,14 +44,13 @@ #define TTYTYPE_RAS_RAW (2) struct ipw_tty { + struct tty_port port; int index; struct ipw_hardware *hardware; unsigned int channel_idx; unsigned int secondary_channel_idx; int tty_type; struct ipw_network *network; - struct tty_struct *linux_tty; - int open_count; unsigned int control_lines; struct mutex ipw_tty_mutex; int tx_bytes_queued; @@ -73,23 +72,6 @@ static char *tty_type_name(int tty_type) return channel_names[tty_type]; } -static void report_registering(struct ipw_tty *tty) -{ - char *iftype = tty_type_name(tty->tty_type); - - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": registering %s device ttyIPWp%d\n", iftype, tty->index); -} - -static void report_deregistering(struct ipw_tty *tty) -{ - char *iftype = tty_type_name(tty->tty_type); - - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": deregistering %s device ttyIPWp%d\n", iftype, - tty->index); -} - static struct ipw_tty *get_tty(int index) { /* @@ -117,12 +99,12 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp) mutex_unlock(&tty->ipw_tty_mutex); return -ENODEV; } - if (tty->open_count == 0) + if (tty->port.count == 0) tty->tx_bytes_queued = 0; - tty->open_count++; + tty->port.count++; - tty->linux_tty = linux_tty; + tty->port.tty = linux_tty; linux_tty->driver_data = tty; linux_tty->low_latency = 1; @@ -136,13 +118,13 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp) static void do_ipw_close(struct ipw_tty *tty) { - tty->open_count--; + tty->port.count--; - if (tty->open_count == 0) { - struct tty_struct *linux_tty = tty->linux_tty; + if (tty->port.count == 0) { + struct tty_struct *linux_tty = tty->port.tty; if (linux_tty != NULL) { - tty->linux_tty = NULL; + tty->port.tty = NULL; linux_tty->driver_data = NULL; if (tty->tty_type == TTYTYPE_MODEM) @@ -159,7 +141,7 @@ static void ipw_hangup(struct tty_struct *linux_tty) return; mutex_lock(&tty->ipw_tty_mutex); - if (tty->open_count == 0) { + if (tty->port.count == 0) { mutex_unlock(&tty->ipw_tty_mutex); return; } @@ -182,13 +164,13 @@ void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data, int work = 0; mutex_lock(&tty->ipw_tty_mutex); - linux_tty = tty->linux_tty; + linux_tty = tty->port.tty; if (linux_tty == NULL) { mutex_unlock(&tty->ipw_tty_mutex); return; } - if (!tty->open_count) { + if (!tty->port.count) { mutex_unlock(&tty->ipw_tty_mutex); return; } @@ -230,7 +212,7 @@ static int ipw_write(struct tty_struct *linux_tty, return -ENODEV; mutex_lock(&tty->ipw_tty_mutex); - if (!tty->open_count) { + if (!tty->port.count) { mutex_unlock(&tty->ipw_tty_mutex); return -EINVAL; } @@ -270,7 +252,7 @@ static int ipw_write_room(struct tty_struct *linux_tty) if (!tty) return -ENODEV; - if (!tty->open_count) + if (!tty->port.count) return -EINVAL; room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued; @@ -312,7 +294,7 @@ static int ipw_chars_in_buffer(struct tty_struct *linux_tty) if (!tty) return 0; - if (!tty->open_count) + if (!tty->port.count) return 0; return tty->tx_bytes_queued; @@ -393,7 +375,7 @@ static int ipw_tiocmget(struct tty_struct *linux_tty) if (!tty) return -ENODEV; - if (!tty->open_count) + if (!tty->port.count) return -EINVAL; return get_control_lines(tty); @@ -409,7 +391,7 @@ ipw_tiocmset(struct tty_struct *linux_tty, if (!tty) return -ENODEV; - if (!tty->open_count) + if (!tty->port.count) return -EINVAL; return set_control_lines(tty, set, clear); @@ -423,7 +405,7 @@ static int ipw_ioctl(struct tty_struct *linux_tty, if (!tty) return -ENODEV; - if (!tty->open_count) + if (!tty->port.count) return -EINVAL; /* FIXME: Exactly how is the tty object locked here .. */ @@ -492,6 +474,7 @@ static int add_tty(int j, ttys[j]->network = network; ttys[j]->tty_type = tty_type; mutex_init(&ttys[j]->ipw_tty_mutex); + tty_port_init(&ttys[j]->port); tty_register_device(ipw_tty_driver, j, NULL); ipwireless_associate_network_tty(network, channel_idx, ttys[j]); @@ -500,8 +483,12 @@ static int add_tty(int j, ipwireless_associate_network_tty(network, secondary_channel_idx, ttys[j]); - if (get_tty(j) == ttys[j]) - report_registering(ttys[j]); + /* check if we provide raw device (if loopback is enabled) */ + if (get_tty(j)) + printk(KERN_INFO IPWIRELESS_PCCARD_NAME + ": registering %s device ttyIPWp%d\n", + tty_type_name(tty_type), j); + return 0; } @@ -560,19 +547,21 @@ void ipwireless_tty_free(struct ipw_tty *tty) if (ttyj) { mutex_lock(&ttyj->ipw_tty_mutex); - if (get_tty(j) == ttyj) - report_deregistering(ttyj); + if (get_tty(j)) + printk(KERN_INFO IPWIRELESS_PCCARD_NAME + ": deregistering %s device ttyIPWp%d\n", + tty_type_name(ttyj->tty_type), j); ttyj->closing = 1; - if (ttyj->linux_tty != NULL) { + if (ttyj->port.tty != NULL) { mutex_unlock(&ttyj->ipw_tty_mutex); - tty_hangup(ttyj->linux_tty); - /* Wait till the tty_hangup has completed */ - flush_work_sync(&ttyj->linux_tty->hangup_work); + tty_vhangup(ttyj->port.tty); /* FIXME: Exactly how is the tty object locked here against a parallel ioctl etc */ + /* FIXME2: hangup does not mean all processes + * are gone */ mutex_lock(&ttyj->ipw_tty_mutex); } - while (ttyj->open_count) + while (ttyj->port.count) do_ipw_close(ttyj); ipwireless_disassociate_network_ttys(network, ttyj->channel_idx); @@ -661,8 +650,8 @@ ipwireless_tty_notify_control_line_change(struct ipw_tty *tty, */ if ((old_control_lines & IPW_CONTROL_LINE_DCD) && !(tty->control_lines & IPW_CONTROL_LINE_DCD) - && tty->linux_tty) { - tty_hangup(tty->linux_tty); + && tty->port.tty) { + tty_hangup(tty->port.tty); } } diff --git a/trunk/drivers/tty/mxser.c b/trunk/drivers/tty/mxser.c index c6f372dd5623..90cc680c4f0e 100644 --- a/trunk/drivers/tty/mxser.c +++ b/trunk/drivers/tty/mxser.c @@ -2326,7 +2326,7 @@ static const struct tty_operations mxser_ops = { .get_icount = mxser_get_icount, }; -struct tty_port_operations mxser_port_ops = { +static struct tty_port_operations mxser_port_ops = { .carrier_raised = mxser_carrier_raised, .dtr_rts = mxser_dtr_rts, .activate = mxser_activate, diff --git a/trunk/drivers/tty/n_r3964.c b/trunk/drivers/tty/n_r3964.c index 5c6c31459a2f..656ad93bbc96 100644 --- a/trunk/drivers/tty/n_r3964.c +++ b/trunk/drivers/tty/n_r3964.c @@ -1065,7 +1065,8 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, TRACE_L("read()"); - tty_lock(); + /* FIXME: should use a private lock */ + tty_lock(tty); pClient = findClient(pInfo, task_pid(current)); if (pClient) { @@ -1077,7 +1078,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, goto unlock; } /* block until there is a message: */ - wait_event_interruptible_tty(pInfo->read_wait, + wait_event_interruptible_tty(tty, pInfo->read_wait, (pMsg = remove_msg(pInfo, pClient))); } @@ -1107,7 +1108,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, } ret = -EPERM; unlock: - tty_unlock(); + tty_unlock(tty); return ret; } @@ -1156,7 +1157,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, pHeader->locks = 0; pHeader->owner = NULL; - tty_lock(); + tty_lock(tty); pClient = findClient(pInfo, task_pid(current)); if (pClient) { @@ -1175,7 +1176,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, add_tx_queue(pInfo, pHeader); trigger_transmit(pInfo); - tty_unlock(); + tty_unlock(tty); return 0; } diff --git a/trunk/drivers/tty/n_tty.c b/trunk/drivers/tty/n_tty.c index 94b6eda87afd..ee1c268f5f9d 100644 --- a/trunk/drivers/tty/n_tty.c +++ b/trunk/drivers/tty/n_tty.c @@ -1630,6 +1630,7 @@ static int copy_from_read_buf(struct tty_struct *tty, int retval; size_t n; unsigned long flags; + bool is_eof; retval = 0; spin_lock_irqsave(&tty->read_lock, flags); @@ -1639,15 +1640,15 @@ static int copy_from_read_buf(struct tty_struct *tty, if (n) { retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n); n -= retval; + is_eof = n == 1 && + tty->read_buf[tty->read_tail] == EOF_CHAR(tty); tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n); spin_lock_irqsave(&tty->read_lock, flags); tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1); tty->read_cnt -= n; /* Turn single EOF into zero-length read */ - if (L_EXTPROC(tty) && tty->icanon && n == 1) { - if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty)) - n--; - } + if (L_EXTPROC(tty) && tty->icanon && is_eof && !tty->read_cnt) + n = 0; spin_unlock_irqrestore(&tty->read_lock, flags); *b += n; *nr -= n; diff --git a/trunk/drivers/tty/pty.c b/trunk/drivers/tty/pty.c index eeae7fafe9a7..59af3945ea85 100644 --- a/trunk/drivers/tty/pty.c +++ b/trunk/drivers/tty/pty.c @@ -26,11 +26,13 @@ #include #include #include +#include #ifdef CONFIG_UNIX98_PTYS static struct tty_driver *ptm_driver; static struct tty_driver *pts_driver; +static DEFINE_MUTEX(devpts_mutex); #endif static void pty_close(struct tty_struct *tty, struct file *filp) @@ -45,6 +47,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp) wake_up_interruptible(&tty->read_wait); wake_up_interruptible(&tty->write_wait); tty->packet = 0; + /* Review - krefs on tty_link ?? */ if (!tty->link) return; tty->link->packet = 0; @@ -54,12 +57,15 @@ static void pty_close(struct tty_struct *tty, struct file *filp) if (tty->driver->subtype == PTY_TYPE_MASTER) { set_bit(TTY_OTHER_CLOSED, &tty->flags); #ifdef CONFIG_UNIX98_PTYS - if (tty->driver == ptm_driver) + if (tty->driver == ptm_driver) { + mutex_lock(&devpts_mutex); devpts_pty_kill(tty->link); + mutex_unlock(&devpts_mutex); + } #endif - tty_unlock(); + tty_unlock(tty); tty_vhangup(tty->link); - tty_lock(); + tty_lock(tty); } } @@ -475,13 +481,17 @@ static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver, * @idx: tty index * * Look up a pty master device. Called under the tty_mutex for now. - * This provides our locking. + * This provides our locking for the tty pointer. */ static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver, struct inode *pts_inode, int idx) { - struct tty_struct *tty = devpts_get_tty(pts_inode, idx); + struct tty_struct *tty; + + mutex_lock(&devpts_mutex); + tty = devpts_get_tty(pts_inode, idx); + mutex_unlock(&devpts_mutex); /* Master must be open before slave */ if (!tty) return ERR_PTR(-EIO); @@ -613,24 +623,29 @@ static int ptmx_open(struct inode *inode, struct file *filp) return retval; /* find a device that is not in use. */ - tty_lock(); + mutex_lock(&devpts_mutex); index = devpts_new_index(inode); - tty_unlock(); if (index < 0) { retval = index; goto err_file; } + mutex_unlock(&devpts_mutex); + mutex_lock(&tty_mutex); - tty_lock(); + mutex_lock(&devpts_mutex); tty = tty_init_dev(ptm_driver, index); - mutex_unlock(&tty_mutex); if (IS_ERR(tty)) { retval = PTR_ERR(tty); goto out; } + /* The tty returned here is locked so we can safely + drop the mutex */ + mutex_unlock(&devpts_mutex); + mutex_unlock(&tty_mutex); + set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ tty_add_file(tty, filp); @@ -643,16 +658,17 @@ static int ptmx_open(struct inode *inode, struct file *filp) if (retval) goto err_release; - tty_unlock(); + tty_unlock(tty); return 0; err_release: - tty_unlock(); + tty_unlock(tty); tty_release(inode, filp); return retval; out: + mutex_unlock(&tty_mutex); devpts_kill_index(inode, index); - tty_unlock(); err_file: + mutex_unlock(&devpts_mutex); tty_free_file(filp); return retval; } diff --git a/trunk/drivers/tty/serial/68328serial.c b/trunk/drivers/tty/serial/68328serial.c index 5ce782529d65..3ed20e435e59 100644 --- a/trunk/drivers/tty/serial/68328serial.c +++ b/trunk/drivers/tty/serial/68328serial.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -56,8 +57,6 @@ #endif /* CONFIG_M68VZ328 */ #endif /* CONFIG_M68EZ328 */ -#include "68328serial.h" - /* Turn off usage of real serial interrupt code, to "support" Copilot */ #ifdef CONFIG_XCOPILOT_BUGS #undef USE_INTS @@ -65,33 +64,82 @@ #define USE_INTS #endif -static struct m68k_serial m68k_soft[NR_PORTS]; +/* + * I believe this is the optimal setting that reduces the number of interrupts. + * At high speeds the output might become a little "bursted" (use USTCNT_TXHE + * if that bothers you), but in most cases it will not, since we try to + * transmit characters every time rs_interrupt is called. Thus, quite often + * you'll see that a receive interrupt occures before the transmit one. + * -- Vladimir Gurevich + */ +#define USTCNT_TX_INTR_MASK (USTCNT_TXEE) -static unsigned int uart_irqs[NR_PORTS] = UART_IRQ_DEFNS; +/* + * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special + * "Old data interrupt" which occures whenever the data stay in the FIFO + * longer than 30 bits time. This allows us to use FIFO without compromising + * latency. '328 does not have this feature and without the real 328-based + * board I would assume that RXRE is the safest setting. + * + * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of + * interrupts. RXFE (receive queue full) causes the system to lose data + * at least at 115200 baud + * + * If your board is busy doing other stuff, you might consider to use + * RXRE (data ready intrrupt) instead. + * + * The other option is to make these INTR masks run-time configurable, so + * that people can dynamically adapt them according to the current usage. + * -- Vladimir Gurevich + */ -/* multiple ports are contiguous in memory */ -m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR; +/* (es) */ +#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328) +#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN) +#elif defined(CONFIG_M68328) +#define USTCNT_RX_INTR_MASK (USTCNT_RXRE) +#else +#error Please, define the Rx interrupt events for your CPU +#endif +/* (/es) */ -struct tty_struct m68k_ttys; -struct m68k_serial *m68k_consinfo = 0; +/* + * This is our internal structure for each serial port's state. + */ +struct m68k_serial { + struct tty_port tport; + char is_cons; /* Is this our console. */ + int magic; + int baud_base; + int port; + int irq; + int type; /* UART type */ + int custom_divisor; + int x_char; /* xon/xoff character */ + int line; + unsigned char *xmit_buf; + int xmit_head; + int xmit_tail; + int xmit_cnt; +}; -#define M68K_CLOCK (16667000) /* FIXME: 16MHz is likely wrong */ +#define SERIAL_MAGIC 0x5301 -struct tty_driver *serial_driver; +/* + * Define the number of ports supported and their irqs. + */ +#define NR_PORTS 1 -/* number of characters left in xmit buffer before we ask for more */ -#define WAKEUP_CHARS 256 +static struct m68k_serial m68k_soft[NR_PORTS]; -/* Debugging... DEBUG_INTR is bad to use when one of the zs - * lines is your console ;( - */ -#undef SERIAL_DEBUG_INTR -#undef SERIAL_DEBUG_OPEN -#undef SERIAL_DEBUG_FLOW +static unsigned int uart_irqs[NR_PORTS] = { UART_IRQ_NUM }; -#define RS_ISR_PASS_LIMIT 256 +/* multiple ports are contiguous in memory */ +m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR; + +struct tty_driver *serial_driver; -static void change_speed(struct m68k_serial *info); +static void change_speed(struct m68k_serial *info, struct tty_struct *tty); /* * Setup for console. Argument comes from the boot command line. @@ -143,17 +191,6 @@ static int baud_table[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 0 }; -/* Sets or clears DTR/RTS on the requested line */ -static inline void m68k_rtsdtr(struct m68k_serial *ss, int set) -{ - if (set) { - /* set the RTS/CTS line */ - } else { - /* clear it */ - } - return; -} - /* Utility routines */ static inline int get_baud(struct m68k_serial *ss) { @@ -189,7 +226,8 @@ static void rs_stop(struct tty_struct *tty) static int rs_put_char(char ch) { - int flags, loops = 0; + unsigned long flags; + int loops = 0; local_irq_save(flags); @@ -224,28 +262,9 @@ static void rs_start(struct tty_struct *tty) local_irq_restore(flags); } -/* Drop into either the boot monitor or kadb upon receiving a break - * from keyboard/console input. - */ -static void batten_down_hatches(void) -{ - /* Drop into the debugger */ -} - -static void status_handle(struct m68k_serial *info, unsigned short status) +static void receive_chars(struct m68k_serial *info, struct tty_struct *tty, + unsigned short rx) { - /* If this is console input and this is a - * 'break asserted' status change interrupt - * see if we can drop into the debugger - */ - if((status & URX_BREAK) && info->break_abort) - batten_down_hatches(); - return; -} - -static void receive_chars(struct m68k_serial *info, unsigned short rx) -{ - struct tty_struct *tty = info->tty; m68328_uart *uart = &uart_addr[info->line]; unsigned char ch, flag; @@ -259,7 +278,6 @@ static void receive_chars(struct m68k_serial *info, unsigned short rx) if(info->is_cons) { if(URX_BREAK & rx) { /* whee, break received */ - status_handle(info, rx); return; #ifdef CONFIG_MAGIC_SYSRQ } else if (ch == 0x10) { /* ^P */ @@ -280,16 +298,13 @@ static void receive_chars(struct m68k_serial *info, unsigned short rx) flag = TTY_NORMAL; - if(rx & URX_PARITY_ERROR) { + if (rx & URX_PARITY_ERROR) flag = TTY_PARITY; - status_handle(info, rx); - } else if(rx & URX_OVRUN) { + else if (rx & URX_OVRUN) flag = TTY_OVERRUN; - status_handle(info, rx); - } else if(rx & URX_FRAME_ERROR) { + else if (rx & URX_FRAME_ERROR) flag = TTY_FRAME; - status_handle(info, rx); - } + tty_insert_flip_char(tty, ch, flag); #ifndef CONFIG_XCOPILOT_BUGS } while((rx = uart->urx.w) & URX_DATA_READY); @@ -301,7 +316,7 @@ static void receive_chars(struct m68k_serial *info, unsigned short rx) return; } -static void transmit_chars(struct m68k_serial *info) +static void transmit_chars(struct m68k_serial *info, struct tty_struct *tty) { m68328_uart *uart = &uart_addr[info->line]; @@ -312,7 +327,7 @@ static void transmit_chars(struct m68k_serial *info) goto clear_and_return; } - if((info->xmit_cnt <= 0) || info->tty->stopped) { + if ((info->xmit_cnt <= 0) || !tty || tty->stopped) { /* That's peculiar... TX ints off */ uart->ustcnt &= ~USTCNT_TX_INTR_MASK; goto clear_and_return; @@ -340,6 +355,7 @@ static void transmit_chars(struct m68k_serial *info) irqreturn_t rs_interrupt(int irq, void *dev_id) { struct m68k_serial *info = dev_id; + struct tty_struct *tty = tty_port_tty_get(&info->tport); m68328_uart *uart; unsigned short rx; unsigned short tx; @@ -350,20 +366,24 @@ irqreturn_t rs_interrupt(int irq, void *dev_id) #ifdef USE_INTS tx = uart->utx.w; - if (rx & URX_DATA_READY) receive_chars(info, rx); - if (tx & UTX_TX_AVAIL) transmit_chars(info); + if (rx & URX_DATA_READY) + receive_chars(info, tty, rx); + if (tx & UTX_TX_AVAIL) + transmit_chars(info, tty); #else - receive_chars(info, rx); + receive_chars(info, tty, rx); #endif + tty_kref_put(tty); + return IRQ_HANDLED; } -static int startup(struct m68k_serial * info) +static int startup(struct m68k_serial *info, struct tty_struct *tty) { m68328_uart *uart = &uart_addr[info->line]; unsigned long flags; - if (info->flags & S_INITIALIZED) + if (info->tport.flags & ASYNC_INITIALIZED) return 0; if (!info->xmit_buf) { @@ -380,7 +400,6 @@ static int startup(struct m68k_serial * info) */ uart->ustcnt = USTCNT_UEN; - info->xmit_fifo_size = 1; uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_TXEN; (void)uart->urx.w; @@ -394,17 +413,17 @@ static int startup(struct m68k_serial * info) uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK; #endif - if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); + if (tty) + clear_bit(TTY_IO_ERROR, &tty->flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; /* * and set the speed of the serial port */ - change_speed(info); + change_speed(info, tty); - info->flags |= S_INITIALIZED; + info->tport.flags |= ASYNC_INITIALIZED; local_irq_restore(flags); return 0; } @@ -413,13 +432,13 @@ static int startup(struct m68k_serial * info) * This routine will shutdown a serial port; interrupts are disabled, and * DTR is dropped if the hangup on close termio flag is on. */ -static void shutdown(struct m68k_serial * info) +static void shutdown(struct m68k_serial *info, struct tty_struct *tty) { m68328_uart *uart = &uart_addr[info->line]; unsigned long flags; uart->ustcnt = 0; /* All off! */ - if (!(info->flags & S_INITIALIZED)) + if (!(info->tport.flags & ASYNC_INITIALIZED)) return; local_irq_save(flags); @@ -429,10 +448,10 @@ static void shutdown(struct m68k_serial * info) info->xmit_buf = 0; } - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); + if (tty) + set_bit(TTY_IO_ERROR, &tty->flags); - info->flags &= ~S_INITIALIZED; + info->tport.flags &= ~ASYNC_INITIALIZED; local_irq_restore(flags); } @@ -488,7 +507,7 @@ struct { * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */ -static void change_speed(struct m68k_serial *info) +static void change_speed(struct m68k_serial *info, struct tty_struct *tty) { m68328_uart *uart = &uart_addr[info->line]; unsigned short port; @@ -496,9 +515,7 @@ static void change_speed(struct m68k_serial *info) unsigned cflag; int i; - if (!info->tty || !info->tty->termios) - return; - cflag = info->tty->termios->c_cflag; + cflag = tty->termios->c_cflag; if (!(port = info->port)) return; @@ -510,7 +527,6 @@ static void change_speed(struct m68k_serial *info) i = (i & ~CBAUDEX) + B38400; } - info->baud = baud_table[i]; uart->ubaud = PUT_FIELD(UBAUD_DIVIDE, hw_baud_table[i].divisor) | PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale); @@ -807,10 +823,10 @@ static int get_serial_info(struct m68k_serial * info, tmp.line = info->line; tmp.port = info->port; tmp.irq = info->irq; - tmp.flags = info->flags; + tmp.flags = info->tport.flags; tmp.baud_base = info->baud_base; - tmp.close_delay = info->close_delay; - tmp.closing_wait = info->closing_wait; + tmp.close_delay = info->tport.close_delay; + tmp.closing_wait = info->tport.closing_wait; tmp.custom_divisor = info->custom_divisor; if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) return -EFAULT; @@ -818,9 +834,10 @@ static int get_serial_info(struct m68k_serial * info, return 0; } -static int set_serial_info(struct m68k_serial * info, +static int set_serial_info(struct m68k_serial *info, struct tty_struct *tty, struct serial_struct * new_info) { + struct tty_port *port = &info->tport; struct serial_struct new_serial; struct m68k_serial old_info; int retval = 0; @@ -834,17 +851,17 @@ static int set_serial_info(struct m68k_serial * info, if (!capable(CAP_SYS_ADMIN)) { if ((new_serial.baud_base != info->baud_base) || (new_serial.type != info->type) || - (new_serial.close_delay != info->close_delay) || - ((new_serial.flags & ~S_USR_MASK) != - (info->flags & ~S_USR_MASK))) + (new_serial.close_delay != port->close_delay) || + ((new_serial.flags & ~ASYNC_USR_MASK) != + (port->flags & ~ASYNC_USR_MASK))) return -EPERM; - info->flags = ((info->flags & ~S_USR_MASK) | - (new_serial.flags & S_USR_MASK)); + port->flags = ((port->flags & ~ASYNC_USR_MASK) | + (new_serial.flags & ASYNC_USR_MASK)); info->custom_divisor = new_serial.custom_divisor; goto check_and_exit; } - if (info->count > 1) + if (port->count > 1) return -EBUSY; /* @@ -853,14 +870,14 @@ static int set_serial_info(struct m68k_serial * info, */ info->baud_base = new_serial.baud_base; - info->flags = ((info->flags & ~S_FLAGS) | - (new_serial.flags & S_FLAGS)); + port->flags = ((port->flags & ~ASYNC_FLAGS) | + (new_serial.flags & ASYNC_FLAGS)); info->type = new_serial.type; - info->close_delay = new_serial.close_delay; - info->closing_wait = new_serial.closing_wait; + port->close_delay = new_serial.close_delay; + port->closing_wait = new_serial.closing_wait; check_and_exit: - retval = startup(info); + retval = startup(info, tty); return retval; } @@ -946,7 +963,7 @@ static int rs_ioctl(struct tty_struct *tty, return get_serial_info(info, (struct serial_struct *) arg); case TIOCSSERIAL: - return set_serial_info(info, + return set_serial_info(info, tty, (struct serial_struct *) arg); case TIOCSERGETLSR: /* Get line status register */ return get_lsr_info(info, (unsigned int *) arg); @@ -965,7 +982,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - change_speed(info); + change_speed(info, tty); if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { @@ -988,6 +1005,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) static void rs_close(struct tty_struct *tty, struct file * filp) { struct m68k_serial * info = (struct m68k_serial *)tty->driver_data; + struct tty_port *port = &info->tport; m68328_uart *uart = &uart_addr[info->line]; unsigned long flags; @@ -1001,7 +1019,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) return; } - if ((tty->count == 1) && (info->count != 1)) { + if ((tty->count == 1) && (port->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. Info->count should always @@ -1010,26 +1028,26 @@ static void rs_close(struct tty_struct *tty, struct file * filp) * serial port won't be shutdown. */ printk("rs_close: bad serial port count; tty->count is 1, " - "info->count is %d\n", info->count); - info->count = 1; + "port->count is %d\n", port->count); + port->count = 1; } - if (--info->count < 0) { + if (--port->count < 0) { printk("rs_close: bad serial port count for ttyS%d: %d\n", - info->line, info->count); - info->count = 0; + info->line, port->count); + port->count = 0; } - if (info->count) { + if (port->count) { local_irq_restore(flags); return; } - info->flags |= S_CLOSING; + port->flags |= ASYNC_CLOSING; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. */ tty->closing = 1; - if (info->closing_wait != S_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, info->closing_wait); + if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, port->closing_wait); /* * At this point we stop accepting input. To do this, we * disable the receive line status interrupts, and tell the @@ -1040,13 +1058,12 @@ static void rs_close(struct tty_struct *tty, struct file * filp) uart->ustcnt &= ~USTCNT_RXEN; uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK); - shutdown(info); + shutdown(info, tty); rs_flush_buffer(tty); tty_ldisc_flush(tty); tty->closing = 0; - info->event = 0; - info->tty = NULL; + tty_port_tty_set(&info->tport, NULL); #warning "This is not and has never been valid so fix it" #if 0 if (tty->ldisc.num != ldiscs[N_TTY].num) { @@ -1058,14 +1075,13 @@ static void rs_close(struct tty_struct *tty, struct file * filp) (tty->ldisc.open)(tty); } #endif - if (info->blocked_open) { - if (info->close_delay) { - msleep_interruptible(jiffies_to_msecs(info->close_delay)); - } - wake_up_interruptible(&info->open_wait); + if (port->blocked_open) { + if (port->close_delay) + msleep_interruptible(jiffies_to_msecs(port->close_delay)); + wake_up_interruptible(&port->open_wait); } - info->flags &= ~(S_NORMAL_ACTIVE|S_CLOSING); - wake_up_interruptible(&info->close_wait); + port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + wake_up_interruptible(&port->close_wait); local_irq_restore(flags); } @@ -1080,106 +1096,13 @@ void rs_hangup(struct tty_struct *tty) return; rs_flush_buffer(tty); - shutdown(info); - info->event = 0; - info->count = 0; - info->flags &= ~S_NORMAL_ACTIVE; - info->tty = NULL; - wake_up_interruptible(&info->open_wait); + shutdown(info, tty); + info->tport.count = 0; + info->tport.flags &= ~ASYNC_NORMAL_ACTIVE; + tty_port_tty_set(&info->tport, NULL); + wake_up_interruptible(&info->tport.open_wait); } -/* - * ------------------------------------------------------------ - * rs_open() and friends - * ------------------------------------------------------------ - */ -static int block_til_ready(struct tty_struct *tty, struct file * filp, - struct m68k_serial *info) -{ - DECLARE_WAITQUEUE(wait, current); - int retval; - int do_clocal = 0; - - /* - * If the device is in the middle of being closed, then block - * until it's done, and then try again. - */ - if (info->flags & S_CLOSING) { - interruptible_sleep_on(&info->close_wait); -#ifdef SERIAL_DO_RESTART - if (info->flags & S_HUP_NOTIFY) - return -EAGAIN; - else - return -ERESTARTSYS; -#else - return -EAGAIN; -#endif - } - - /* - * If non-blocking mode is set, or the port is not enabled, - * then make the check up front and then exit. - */ - if ((filp->f_flags & O_NONBLOCK) || - (tty->flags & (1 << TTY_IO_ERROR))) { - info->flags |= S_NORMAL_ACTIVE; - return 0; - } - - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - - /* - * Block waiting for the carrier detect and the line to become - * free (i.e., not in use by the callout). While we are in - * this loop, info->count is dropped by one, so that - * rs_close() knows when to free things. We restore it upon - * exit, either normal or abnormal. - */ - retval = 0; - add_wait_queue(&info->open_wait, &wait); - - info->count--; - info->blocked_open++; - while (1) { - local_irq_disable(); - m68k_rtsdtr(info, 1); - local_irq_enable(); - current->state = TASK_INTERRUPTIBLE; - if (tty_hung_up_p(filp) || - !(info->flags & S_INITIALIZED)) { -#ifdef SERIAL_DO_RESTART - if (info->flags & S_HUP_NOTIFY) - retval = -EAGAIN; - else - retval = -ERESTARTSYS; -#else - retval = -EAGAIN; -#endif - break; - } - if (!(info->flags & S_CLOSING) && do_clocal) - break; - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - tty_unlock(); - schedule(); - tty_lock(); - } - current->state = TASK_RUNNING; - remove_wait_queue(&info->open_wait, &wait); - if (!tty_hung_up_p(filp)) - info->count++; - info->blocked_open--; - - if (retval) - return retval; - info->flags |= S_NORMAL_ACTIVE; - return 0; -} - /* * This routine is called whenever a serial port is opened. It * enables interrupts for a serial port, linking in its S structure into @@ -1196,18 +1119,18 @@ int rs_open(struct tty_struct *tty, struct file * filp) if (serial_paranoia_check(info, tty->name, "rs_open")) return -ENODEV; - info->count++; + info->tport.count++; tty->driver_data = info; - info->tty = tty; + tty_port_tty_set(&info->tport, tty); /* * Start up serial port */ - retval = startup(info); + retval = startup(info, tty); if (retval) return retval; - return block_til_ready(tty, filp, info); + return tty_port_block_til_ready(&info->tport, tty, filp); } /* Finally, routines used to initialize the serial driver. */ @@ -1235,11 +1158,15 @@ static const struct tty_operations rs_ops = { .set_ldisc = rs_set_ldisc, }; +static const struct tty_port_operations rs_port_ops = { +}; + /* rs_init inits the driver */ static int __init rs68328_init(void) { - int flags, i; + unsigned long flags; + int i; struct m68k_serial *info; serial_driver = alloc_tty_driver(NR_PORTS); @@ -1273,19 +1200,13 @@ rs68328_init(void) for(i=0;itport); + info->tport.ops = &rs_port_ops; info->magic = SERIAL_MAGIC; info->port = (int) &uart_addr[i]; - info->tty = NULL; info->irq = uart_irqs[i]; info->custom_divisor = 16; - info->close_delay = 50; - info->closing_wait = 3000; info->x_char = 0; - info->event = 0; - info->count = 0; - info->blocked_open = 0; - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); info->line = i; info->is_cons = 1; /* Means shortcuts work */ diff --git a/trunk/drivers/tty/serial/68328serial.h b/trunk/drivers/tty/serial/68328serial.h deleted file mode 100644 index 3d2faabd766f..000000000000 --- a/trunk/drivers/tty/serial/68328serial.h +++ /dev/null @@ -1,186 +0,0 @@ -/* 68328serial.h: Definitions for the mc68328 serial driver. - * - * Copyright (C) 1995 David S. Miller - * Copyright (C) 1998 Kenneth Albanowski - * Copyright (C) 1998, 1999 D. Jeff Dionne - * Copyright (C) 1999 Vladimir Gurevich - * - * VZ Support/Fixes Evan Stawnyczy - */ - -#ifndef _MC683XX_SERIAL_H -#define _MC683XX_SERIAL_H - - -struct serial_struct { - int type; - int line; - int port; - int irq; - int flags; - int xmit_fifo_size; - int custom_divisor; - int baud_base; - unsigned short close_delay; - char reserved_char[2]; - int hub6; /* FIXME: We don't have AT&T Hub6 boards! */ - unsigned short closing_wait; /* time to wait before closing */ - unsigned short closing_wait2; /* no longer used... */ - int reserved[4]; -}; - -/* - * For the close wait times, 0 means wait forever for serial port to - * flush its output. 65535 means don't wait at all. - */ -#define S_CLOSING_WAIT_INF 0 -#define S_CLOSING_WAIT_NONE 65535 - -/* - * Definitions for S_struct (and serial_struct) flags field - */ -#define S_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes - on the callout port */ -#define S_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */ -#define S_SAK 0x0004 /* Secure Attention Key (Orange book) */ -#define S_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */ - -#define S_SPD_MASK 0x0030 -#define S_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */ - -#define S_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */ -#define S_SPD_CUST 0x0030 /* Use user-specified divisor */ - -#define S_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */ -#define S_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */ -#define S_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */ -#define S_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */ -#define S_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */ - -#define S_FLAGS 0x0FFF /* Possible legal S flags */ -#define S_USR_MASK 0x0430 /* Legal flags that non-privileged - * users can set or reset */ - -/* Internal flags used only by kernel/chr_drv/serial.c */ -#define S_INITIALIZED 0x80000000 /* Serial port was initialized */ -#define S_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */ -#define S_NORMAL_ACTIVE 0x20000000 /* Normal device is active */ -#define S_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */ -#define S_CLOSING 0x08000000 /* Serial port is closing */ -#define S_CTS_FLOW 0x04000000 /* Do CTS flow control */ -#define S_CHECK_CD 0x02000000 /* i.e., CLOCAL */ - -/* Software state per channel */ - -#ifdef __KERNEL__ - -/* - * I believe this is the optimal setting that reduces the number of interrupts. - * At high speeds the output might become a little "bursted" (use USTCNT_TXHE - * if that bothers you), but in most cases it will not, since we try to - * transmit characters every time rs_interrupt is called. Thus, quite often - * you'll see that a receive interrupt occures before the transmit one. - * -- Vladimir Gurevich - */ -#define USTCNT_TX_INTR_MASK (USTCNT_TXEE) - -/* - * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special - * "Old data interrupt" which occures whenever the data stay in the FIFO - * longer than 30 bits time. This allows us to use FIFO without compromising - * latency. '328 does not have this feature and without the real 328-based - * board I would assume that RXRE is the safest setting. - * - * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of - * interrupts. RXFE (receive queue full) causes the system to lose data - * at least at 115200 baud - * - * If your board is busy doing other stuff, you might consider to use - * RXRE (data ready intrrupt) instead. - * - * The other option is to make these INTR masks run-time configurable, so - * that people can dynamically adapt them according to the current usage. - * -- Vladimir Gurevich - */ - -/* (es) */ -#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328) -#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN) -#elif defined(CONFIG_M68328) -#define USTCNT_RX_INTR_MASK (USTCNT_RXRE) -#else -#error Please, define the Rx interrupt events for your CPU -#endif -/* (/es) */ - -/* - * This is our internal structure for each serial port's state. - * - * Many fields are paralleled by the structure used by the serial_struct - * structure. - * - * For definitions of the flags field, see tty.h - */ - -struct m68k_serial { - char soft_carrier; /* Use soft carrier on this channel */ - char break_abort; /* Is serial console in, so process brk/abrt */ - char is_cons; /* Is this our console. */ - - /* We need to know the current clock divisor - * to read the bps rate the chip has currently - * loaded. - */ - unsigned char clk_divisor; /* May be 1, 16, 32, or 64 */ - int baud; - int magic; - int baud_base; - int port; - int irq; - int flags; /* defined in tty.h */ - int type; /* UART type */ - struct tty_struct *tty; - int read_status_mask; - int ignore_status_mask; - int timeout; - int xmit_fifo_size; - int custom_divisor; - int x_char; /* xon/xoff character */ - int close_delay; - unsigned short closing_wait; - unsigned short closing_wait2; - unsigned long event; - unsigned long last_active; - int line; - int count; /* # of fd on device */ - int blocked_open; /* # of blocked opens */ - unsigned char *xmit_buf; - int xmit_head; - int xmit_tail; - int xmit_cnt; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; -}; - - -#define SERIAL_MAGIC 0x5301 - -/* - * The size of the serial xmit buffer is 1 page, or 4096 bytes - */ -#define SERIAL_XMIT_SIZE 4096 - -/* - * Events are used to schedule things to happen at timer-interrupt - * time, instead of at rs interrupt time. - */ -#define RS_EVENT_WRITE_WAKEUP 0 - -/* - * Define the number of ports supported and their irqs. - */ -#define NR_PORTS 1 -#define UART_IRQ_DEFNS {UART_IRQ_NUM} - -#endif /* __KERNEL__ */ -#endif /* !(_MC683XX_SERIAL_H) */ diff --git a/trunk/drivers/tty/serial/8250/8250.c b/trunk/drivers/tty/serial/8250/8250.c index 5c27f7e6c9f1..47d061b9ad4d 100644 --- a/trunk/drivers/tty/serial/8250/8250.c +++ b/trunk/drivers/tty/serial/8250/8250.c @@ -284,7 +284,20 @@ static const struct serial8250_config uart_config[] = { }, }; -#if defined(CONFIG_MIPS_ALCHEMY) +/* Uart divisor latch read */ +static int default_serial_dl_read(struct uart_8250_port *up) +{ + return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8; +} + +/* Uart divisor latch write */ +static void default_serial_dl_write(struct uart_8250_port *up, int value) +{ + serial_out(up, UART_DLL, value & 0xff); + serial_out(up, UART_DLM, value >> 8 & 0xff); +} + +#ifdef CONFIG_MIPS_ALCHEMY /* Au1x00 UART hardware has a weird register layout */ static const u8 au_io_in_map[] = { @@ -305,22 +318,32 @@ static const u8 au_io_out_map[] = { [UART_MCR] = 6, }; -/* sane hardware needs no mapping */ -static inline int map_8250_in_reg(struct uart_port *p, int offset) +static unsigned int au_serial_in(struct uart_port *p, int offset) +{ + offset = au_io_in_map[offset] << p->regshift; + return __raw_readl(p->membase + offset); +} + +static void au_serial_out(struct uart_port *p, int offset, int value) +{ + offset = au_io_out_map[offset] << p->regshift; + __raw_writel(value, p->membase + offset); +} + +/* Au1x00 haven't got a standard divisor latch */ +static int au_serial_dl_read(struct uart_8250_port *up) { - if (p->iotype != UPIO_AU) - return offset; - return au_io_in_map[offset]; + return __raw_readl(up->port.membase + 0x28); } -static inline int map_8250_out_reg(struct uart_port *p, int offset) +static void au_serial_dl_write(struct uart_8250_port *up, int value) { - if (p->iotype != UPIO_AU) - return offset; - return au_io_out_map[offset]; + __raw_writel(value, up->port.membase + 0x28); } -#elif defined(CONFIG_SERIAL_8250_RM9K) +#endif + +#ifdef CONFIG_SERIAL_8250_RM9K static const u8 regmap_in[8] = { @@ -344,87 +367,79 @@ static const u8 [UART_SCR] = 0x2c }; -static inline int map_8250_in_reg(struct uart_port *p, int offset) +static unsigned int rm9k_serial_in(struct uart_port *p, int offset) { - if (p->iotype != UPIO_RM9000) - return offset; - return regmap_in[offset]; + offset = regmap_in[offset] << p->regshift; + return readl(p->membase + offset); } -static inline int map_8250_out_reg(struct uart_port *p, int offset) +static void rm9k_serial_out(struct uart_port *p, int offset, int value) { - if (p->iotype != UPIO_RM9000) - return offset; - return regmap_out[offset]; + offset = regmap_out[offset] << p->regshift; + writel(value, p->membase + offset); } -#else +static int rm9k_serial_dl_read(struct uart_8250_port *up) +{ + return ((__raw_readl(up->port.membase + 0x10) << 8) | + (__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff; +} -/* sane hardware needs no mapping */ -#define map_8250_in_reg(up, offset) (offset) -#define map_8250_out_reg(up, offset) (offset) +static void rm9k_serial_dl_write(struct uart_8250_port *up, int value) +{ + __raw_writel(value, up->port.membase + 0x08); + __raw_writel(value >> 8, up->port.membase + 0x10); +} #endif static unsigned int hub6_serial_in(struct uart_port *p, int offset) { - offset = map_8250_in_reg(p, offset) << p->regshift; + offset = offset << p->regshift; outb(p->hub6 - 1 + offset, p->iobase); return inb(p->iobase + 1); } static void hub6_serial_out(struct uart_port *p, int offset, int value) { - offset = map_8250_out_reg(p, offset) << p->regshift; + offset = offset << p->regshift; outb(p->hub6 - 1 + offset, p->iobase); outb(value, p->iobase + 1); } static unsigned int mem_serial_in(struct uart_port *p, int offset) { - offset = map_8250_in_reg(p, offset) << p->regshift; + offset = offset << p->regshift; return readb(p->membase + offset); } static void mem_serial_out(struct uart_port *p, int offset, int value) { - offset = map_8250_out_reg(p, offset) << p->regshift; + offset = offset << p->regshift; writeb(value, p->membase + offset); } static void mem32_serial_out(struct uart_port *p, int offset, int value) { - offset = map_8250_out_reg(p, offset) << p->regshift; + offset = offset << p->regshift; writel(value, p->membase + offset); } static unsigned int mem32_serial_in(struct uart_port *p, int offset) { - offset = map_8250_in_reg(p, offset) << p->regshift; + offset = offset << p->regshift; return readl(p->membase + offset); } -static unsigned int au_serial_in(struct uart_port *p, int offset) -{ - offset = map_8250_in_reg(p, offset) << p->regshift; - return __raw_readl(p->membase + offset); -} - -static void au_serial_out(struct uart_port *p, int offset, int value) -{ - offset = map_8250_out_reg(p, offset) << p->regshift; - __raw_writel(value, p->membase + offset); -} - static unsigned int io_serial_in(struct uart_port *p, int offset) { - offset = map_8250_in_reg(p, offset) << p->regshift; + offset = offset << p->regshift; return inb(p->iobase + offset); } static void io_serial_out(struct uart_port *p, int offset, int value) { - offset = map_8250_out_reg(p, offset) << p->regshift; + offset = offset << p->regshift; outb(value, p->iobase + offset); } @@ -434,6 +449,10 @@ static void set_io_from_upio(struct uart_port *p) { struct uart_8250_port *up = container_of(p, struct uart_8250_port, port); + + up->dl_read = default_serial_dl_read; + up->dl_write = default_serial_dl_write; + switch (p->iotype) { case UPIO_HUB6: p->serial_in = hub6_serial_in; @@ -445,16 +464,28 @@ static void set_io_from_upio(struct uart_port *p) p->serial_out = mem_serial_out; break; - case UPIO_RM9000: case UPIO_MEM32: p->serial_in = mem32_serial_in; p->serial_out = mem32_serial_out; break; +#ifdef CONFIG_SERIAL_8250_RM9K + case UPIO_RM9000: + p->serial_in = rm9k_serial_in; + p->serial_out = rm9k_serial_out; + up->dl_read = rm9k_serial_dl_read; + up->dl_write = rm9k_serial_dl_write; + break; +#endif + +#ifdef CONFIG_MIPS_ALCHEMY case UPIO_AU: p->serial_in = au_serial_in; p->serial_out = au_serial_out; + up->dl_read = au_serial_dl_read; + up->dl_write = au_serial_dl_write; break; +#endif default: p->serial_in = io_serial_in; @@ -481,59 +512,6 @@ serial_port_out_sync(struct uart_port *p, int offset, int value) } } -/* Uart divisor latch read */ -static inline int _serial_dl_read(struct uart_8250_port *up) -{ - return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8; -} - -/* Uart divisor latch write */ -static inline void _serial_dl_write(struct uart_8250_port *up, int value) -{ - serial_out(up, UART_DLL, value & 0xff); - serial_out(up, UART_DLM, value >> 8 & 0xff); -} - -#if defined(CONFIG_MIPS_ALCHEMY) -/* Au1x00 haven't got a standard divisor latch */ -static int serial_dl_read(struct uart_8250_port *up) -{ - if (up->port.iotype == UPIO_AU) - return __raw_readl(up->port.membase + 0x28); - else - return _serial_dl_read(up); -} - -static void serial_dl_write(struct uart_8250_port *up, int value) -{ - if (up->port.iotype == UPIO_AU) - __raw_writel(value, up->port.membase + 0x28); - else - _serial_dl_write(up, value); -} -#elif defined(CONFIG_SERIAL_8250_RM9K) -static int serial_dl_read(struct uart_8250_port *up) -{ - return (up->port.iotype == UPIO_RM9000) ? - (((__raw_readl(up->port.membase + 0x10) << 8) | - (__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff) : - _serial_dl_read(up); -} - -static void serial_dl_write(struct uart_8250_port *up, int value) -{ - if (up->port.iotype == UPIO_RM9000) { - __raw_writel(value, up->port.membase + 0x08); - __raw_writel(value >> 8, up->port.membase + 0x10); - } else { - _serial_dl_write(up, value); - } -} -#else -#define serial_dl_read(up) _serial_dl_read(up) -#define serial_dl_write(up, value) _serial_dl_write(up, value) -#endif - /* * For the 16C950 */ @@ -568,6 +546,16 @@ static void serial8250_clear_fifos(struct uart_8250_port *p) } } +void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p) +{ + unsigned char fcr; + + serial8250_clear_fifos(p); + fcr = uart_config[p->port.type].fcr; + serial_out(p, UART_FCR, fcr); +} +EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos); + /* * IER sleep support. UARTs which have EFRs need the "extended * capability" bit enabled. Note that on XR16C850s, we need to @@ -1331,27 +1319,6 @@ static void serial8250_enable_ms(struct uart_port *port) serial_port_out(port, UART_IER, up->ier); } -/* - * Clear the Tegra rx fifo after a break - * - * FIXME: This needs to become a port specific callback once we have a - * framework for this - */ -static void clear_rx_fifo(struct uart_8250_port *up) -{ - unsigned int status, tmout = 10000; - do { - status = serial_in(up, UART_LSR); - if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)) - status = serial_in(up, UART_RX); - else - break; - if (--tmout == 0) - break; - udelay(1); - } while (1); -} - /* * serial8250_rx_chars: processes according to the passed in LSR * value, and returns the remaining LSR bits not handled @@ -1386,19 +1353,9 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) up->lsr_saved_flags = 0; if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) { - /* - * For statistics only - */ if (lsr & UART_LSR_BI) { lsr &= ~(UART_LSR_FE | UART_LSR_PE); port->icount.brk++; - /* - * If tegra port then clear the rx fifo to - * accept another break/character. - */ - if (port->type == PORT_TEGRA) - clear_rx_fifo(up); - /* * We do the SysRQ and SAK checking * here because otherwise the break @@ -2280,10 +2237,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, quot++; if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) { - if (baud < 2400) - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; - else - fcr = uart_config[port->type].fcr; + fcr = uart_config[port->type].fcr; + if (baud < 2400) { + fcr &= ~UART_FCR_TRIGGER_MASK; + fcr |= UART_FCR_TRIGGER_1; + } } /* @@ -3037,6 +2995,7 @@ static int __devinit serial8250_probe(struct platform_device *dev) port.serial_in = p->serial_in; port.serial_out = p->serial_out; port.handle_irq = p->handle_irq; + port.handle_break = p->handle_break; port.set_termios = p->set_termios; port.pm = p->pm; port.dev = &dev->dev; @@ -3153,7 +3112,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port * } /** - * serial8250_register_port - register a serial port + * serial8250_register_8250_port - register a serial port * @port: serial port template * * Configure the serial port specified by the request. If the @@ -3165,50 +3124,56 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port * * * On success the port is ready to use and the line number is returned. */ -int serial8250_register_port(struct uart_port *port) +int serial8250_register_8250_port(struct uart_8250_port *up) { struct uart_8250_port *uart; int ret = -ENOSPC; - if (port->uartclk == 0) + if (up->port.uartclk == 0) return -EINVAL; mutex_lock(&serial_mutex); - uart = serial8250_find_match_or_unused(port); + uart = serial8250_find_match_or_unused(&up->port); if (uart) { uart_remove_one_port(&serial8250_reg, &uart->port); - uart->port.iobase = port->iobase; - uart->port.membase = port->membase; - uart->port.irq = port->irq; - uart->port.irqflags = port->irqflags; - uart->port.uartclk = port->uartclk; - uart->port.fifosize = port->fifosize; - uart->port.regshift = port->regshift; - uart->port.iotype = port->iotype; - uart->port.flags = port->flags | UPF_BOOT_AUTOCONF; - uart->port.mapbase = port->mapbase; - uart->port.private_data = port->private_data; - if (port->dev) - uart->port.dev = port->dev; - - if (port->flags & UPF_FIXED_TYPE) - serial8250_init_fixed_type_port(uart, port->type); + uart->port.iobase = up->port.iobase; + uart->port.membase = up->port.membase; + uart->port.irq = up->port.irq; + uart->port.irqflags = up->port.irqflags; + uart->port.uartclk = up->port.uartclk; + uart->port.fifosize = up->port.fifosize; + uart->port.regshift = up->port.regshift; + uart->port.iotype = up->port.iotype; + uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF; + uart->port.mapbase = up->port.mapbase; + uart->port.private_data = up->port.private_data; + if (up->port.dev) + uart->port.dev = up->port.dev; + + if (up->port.flags & UPF_FIXED_TYPE) + serial8250_init_fixed_type_port(uart, up->port.type); set_io_from_upio(&uart->port); /* Possibly override default I/O functions. */ - if (port->serial_in) - uart->port.serial_in = port->serial_in; - if (port->serial_out) - uart->port.serial_out = port->serial_out; - if (port->handle_irq) - uart->port.handle_irq = port->handle_irq; + if (up->port.serial_in) + uart->port.serial_in = up->port.serial_in; + if (up->port.serial_out) + uart->port.serial_out = up->port.serial_out; + if (up->port.handle_irq) + uart->port.handle_irq = up->port.handle_irq; /* Possibly override set_termios call */ - if (port->set_termios) - uart->port.set_termios = port->set_termios; - if (port->pm) - uart->port.pm = port->pm; + if (up->port.set_termios) + uart->port.set_termios = up->port.set_termios; + if (up->port.pm) + uart->port.pm = up->port.pm; + if (up->port.handle_break) + uart->port.handle_break = up->port.handle_break; + if (up->dl_read) + uart->dl_read = up->dl_read; + if (up->dl_write) + uart->dl_write = up->dl_write; if (serial8250_isa_config != NULL) serial8250_isa_config(0, &uart->port, @@ -3222,6 +3187,29 @@ int serial8250_register_port(struct uart_port *port) return ret; } +EXPORT_SYMBOL(serial8250_register_8250_port); + +/** + * serial8250_register_port - register a serial port + * @port: serial port template + * + * Configure the serial port specified by the request. If the + * port exists and is in use, it is hung up and unregistered + * first. + * + * The port is then probed and if necessary the IRQ is autodetected + * If this fails an error is returned. + * + * On success the port is ready to use and the line number is returned. + */ +int serial8250_register_port(struct uart_port *port) +{ + struct uart_8250_port up; + + memset(&up, 0, sizeof(up)); + memcpy(&up.port, port, sizeof(*port)); + return serial8250_register_8250_port(&up); +} EXPORT_SYMBOL(serial8250_register_port); /** diff --git a/trunk/drivers/tty/serial/8250/8250.h b/trunk/drivers/tty/serial/8250/8250.h index 2868a1da254d..f9719d167c8d 100644 --- a/trunk/drivers/tty/serial/8250/8250.h +++ b/trunk/drivers/tty/serial/8250/8250.h @@ -37,6 +37,10 @@ struct uart_8250_port { unsigned char lsr_saved_flags; #define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA unsigned char msr_saved_flags; + + /* 8250 specific callbacks */ + int (*dl_read)(struct uart_8250_port *); + void (*dl_write)(struct uart_8250_port *, int); }; struct old_serial_port { @@ -96,6 +100,18 @@ static inline void serial_out(struct uart_8250_port *up, int offset, int value) up->port.serial_out(&up->port, offset, value); } +void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p); + +static inline int serial_dl_read(struct uart_8250_port *up) +{ + return up->dl_read(up); +} + +static inline void serial_dl_write(struct uart_8250_port *up, int value) +{ + up->dl_write(up, value); +} + #if defined(__alpha__) && !defined(CONFIG_PCI) /* * Digital did something really horribly wrong with the OUT1 and OUT2 diff --git a/trunk/drivers/tty/serial/8250/8250_em.c b/trunk/drivers/tty/serial/8250/8250_em.c new file mode 100644 index 000000000000..3a0363e7f3a7 --- /dev/null +++ b/trunk/drivers/tty/serial/8250/8250_em.c @@ -0,0 +1,186 @@ +/* + * Renesas Emma Mobile 8250 driver + * + * 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; either 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "8250.h" + +#define UART_DLL_EM 9 +#define UART_DLM_EM 10 + +struct serial8250_em_priv { + struct clk *sclk; + int line; +}; + +static void serial8250_em_serial_out(struct uart_port *p, int offset, int value) +{ + switch (offset) { + case UART_TX: /* TX @ 0x00 */ + writeb(value, p->membase); + break; + case UART_FCR: /* FCR @ 0x0c (+1) */ + case UART_LCR: /* LCR @ 0x10 (+1) */ + case UART_MCR: /* MCR @ 0x14 (+1) */ + case UART_SCR: /* SCR @ 0x20 (+1) */ + writel(value, p->membase + ((offset + 1) << 2)); + break; + case UART_IER: /* IER @ 0x04 */ + value &= 0x0f; /* only 4 valid bits - not Xscale */ + /* fall-through */ + case UART_DLL_EM: /* DLL @ 0x24 (+9) */ + case UART_DLM_EM: /* DLM @ 0x28 (+9) */ + writel(value, p->membase + (offset << 2)); + } +} + +static unsigned int serial8250_em_serial_in(struct uart_port *p, int offset) +{ + switch (offset) { + case UART_RX: /* RX @ 0x00 */ + return readb(p->membase); + case UART_MCR: /* MCR @ 0x14 (+1) */ + case UART_LSR: /* LSR @ 0x18 (+1) */ + case UART_MSR: /* MSR @ 0x1c (+1) */ + case UART_SCR: /* SCR @ 0x20 (+1) */ + return readl(p->membase + ((offset + 1) << 2)); + case UART_IER: /* IER @ 0x04 */ + case UART_IIR: /* IIR @ 0x08 */ + case UART_DLL_EM: /* DLL @ 0x24 (+9) */ + case UART_DLM_EM: /* DLM @ 0x28 (+9) */ + return readl(p->membase + (offset << 2)); + } + return 0; +} + +static int serial8250_em_serial_dl_read(struct uart_8250_port *up) +{ + return serial_in(up, UART_DLL_EM) | serial_in(up, UART_DLM_EM) << 8; +} + +static void serial8250_em_serial_dl_write(struct uart_8250_port *up, int value) +{ + serial_out(up, UART_DLL_EM, value & 0xff); + serial_out(up, UART_DLM_EM, value >> 8 & 0xff); +} + +static int __devinit serial8250_em_probe(struct platform_device *pdev) +{ + struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + struct serial8250_em_priv *priv; + struct uart_8250_port up; + int ret = -EINVAL; + + if (!regs || !irq) { + dev_err(&pdev->dev, "missing registers or irq\n"); + goto err0; + } + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(&pdev->dev, "unable to allocate private data\n"); + ret = -ENOMEM; + goto err0; + } + + priv->sclk = clk_get(&pdev->dev, "sclk"); + if (IS_ERR(priv->sclk)) { + dev_err(&pdev->dev, "unable to get clock\n"); + ret = PTR_ERR(priv->sclk); + goto err1; + } + + memset(&up, 0, sizeof(up)); + up.port.mapbase = regs->start; + up.port.irq = irq->start; + up.port.type = PORT_UNKNOWN; + up.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_IOREMAP; + up.port.dev = &pdev->dev; + up.port.private_data = priv; + + clk_enable(priv->sclk); + up.port.uartclk = clk_get_rate(priv->sclk); + + up.port.iotype = UPIO_MEM32; + up.port.serial_in = serial8250_em_serial_in; + up.port.serial_out = serial8250_em_serial_out; + up.dl_read = serial8250_em_serial_dl_read; + up.dl_write = serial8250_em_serial_dl_write; + + ret = serial8250_register_8250_port(&up); + if (ret < 0) { + dev_err(&pdev->dev, "unable to register 8250 port\n"); + goto err2; + } + + priv->line = ret; + platform_set_drvdata(pdev, priv); + return 0; + + err2: + clk_disable(priv->sclk); + clk_put(priv->sclk); + err1: + kfree(priv); + err0: + return ret; +} + +static int __devexit serial8250_em_remove(struct platform_device *pdev) +{ + struct serial8250_em_priv *priv = platform_get_drvdata(pdev); + + serial8250_unregister_port(priv->line); + clk_disable(priv->sclk); + clk_put(priv->sclk); + kfree(priv); + return 0; +} + +static const struct of_device_id serial8250_em_dt_ids[] __devinitconst = { + { .compatible = "renesas,em-uart", }, + {}, +}; +MODULE_DEVICE_TABLE(of, serial8250_em_dt_ids); + +static struct platform_driver serial8250_em_platform_driver = { + .driver = { + .name = "serial8250-em", + .of_match_table = serial8250_em_dt_ids, + .owner = THIS_MODULE, + }, + .probe = serial8250_em_probe, + .remove = __devexit_p(serial8250_em_remove), +}; + +module_platform_driver(serial8250_em_platform_driver); + +MODULE_AUTHOR("Magnus Damm"); +MODULE_DESCRIPTION("Renesas Emma Mobile 8250 Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/tty/serial/8250/8250_pci.c b/trunk/drivers/tty/serial/8250/8250_pci.c index 858dca865d6a..28e7c7cce893 100644 --- a/trunk/drivers/tty/serial/8250/8250_pci.c +++ b/trunk/drivers/tty/serial/8250/8250_pci.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -1092,11 +1093,49 @@ static int skip_tx_en_setup(struct serial_private *priv, return pci_default_setup(priv, board, port, idx); } +static void kt_handle_break(struct uart_port *p) +{ + struct uart_8250_port *up = + container_of(p, struct uart_8250_port, port); + /* + * On receipt of a BI, serial device in Intel ME (Intel + * management engine) needs to have its fifos cleared for sane + * SOL (Serial Over Lan) output. + */ + serial8250_clear_and_reinit_fifos(up); +} + +static unsigned int kt_serial_in(struct uart_port *p, int offset) +{ + struct uart_8250_port *up = + container_of(p, struct uart_8250_port, port); + unsigned int val; + + /* + * When the Intel ME (management engine) gets reset its serial + * port registers could return 0 momentarily. Functions like + * serial8250_console_write, read and save the IER, perform + * some operation and then restore it. In order to avoid + * setting IER register inadvertently to 0, if the value read + * is 0, double check with ier value in uart_8250_port and use + * that instead. up->ier should be the same value as what is + * currently configured. + */ + val = inb(p->iobase + offset); + if (offset == UART_IER) { + if (val == 0) + val = up->ier; + } + return val; +} + static int kt_serial_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_port *port, int idx) { port->flags |= UPF_BUG_THRE; + port->serial_in = kt_serial_in; + port->handle_break = kt_handle_break; return skip_tx_en_setup(priv, board, port, idx); } @@ -1609,54 +1648,72 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { { .vendor = PCI_VENDOR_ID_INTEL, .device = 0x8811, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .init = pci_eg20t_init, .setup = pci_default_setup, }, { .vendor = PCI_VENDOR_ID_INTEL, .device = 0x8812, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .init = pci_eg20t_init, .setup = pci_default_setup, }, { .vendor = PCI_VENDOR_ID_INTEL, .device = 0x8813, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .init = pci_eg20t_init, .setup = pci_default_setup, }, { .vendor = PCI_VENDOR_ID_INTEL, .device = 0x8814, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .init = pci_eg20t_init, .setup = pci_default_setup, }, { .vendor = 0x10DB, .device = 0x8027, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .init = pci_eg20t_init, .setup = pci_default_setup, }, { .vendor = 0x10DB, .device = 0x8028, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .init = pci_eg20t_init, .setup = pci_default_setup, }, { .vendor = 0x10DB, .device = 0x8029, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .init = pci_eg20t_init, .setup = pci_default_setup, }, { .vendor = 0x10DB, .device = 0x800C, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .init = pci_eg20t_init, .setup = pci_default_setup, }, { .vendor = 0x10DB, .device = 0x800D, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .init = pci_eg20t_init, .setup = pci_default_setup, }, @@ -2775,6 +2832,12 @@ void pciserial_suspend_ports(struct serial_private *priv) for (i = 0; i < priv->nr; i++) if (priv->line[i] >= 0) serial8250_suspend_port(priv->line[i]); + + /* + * Ensure that every init quirk is properly torn down + */ + if (priv->quirk->exit) + priv->quirk->exit(priv->dev); } EXPORT_SYMBOL_GPL(pciserial_suspend_ports); diff --git a/trunk/drivers/tty/serial/8250/Kconfig b/trunk/drivers/tty/serial/8250/Kconfig index 591f8018e7dd..8bc7ecbf6bea 100644 --- a/trunk/drivers/tty/serial/8250/Kconfig +++ b/trunk/drivers/tty/serial/8250/Kconfig @@ -278,3 +278,11 @@ config SERIAL_8250_DW help Selecting this option will enable handling of the extra features present in the Synopsys DesignWare APB UART. + +config SERIAL_8250_EM + tristate "Support for Emma Mobile intergrated serial port" + depends on SERIAL_8250 && ARM && HAVE_CLK + help + Selecting this option will add support for the integrated serial + port hardware found on the Emma Mobile line of processors. + If unsure, say N. diff --git a/trunk/drivers/tty/serial/8250/Makefile b/trunk/drivers/tty/serial/8250/Makefile index 867bba738908..3f35eacdf673 100644 --- a/trunk/drivers/tty/serial/8250/Makefile +++ b/trunk/drivers/tty/serial/8250/Makefile @@ -18,3 +18,4 @@ obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o +obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o diff --git a/trunk/drivers/tty/serial/amba-pl011.c b/trunk/drivers/tty/serial/amba-pl011.c index 3d569cd68f58..4ad721fb8405 100644 --- a/trunk/drivers/tty/serial/amba-pl011.c +++ b/trunk/drivers/tty/serial/amba-pl011.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -67,30 +68,6 @@ #define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE) #define UART_DUMMY_DR_RX (1 << 16) - -#define UART_WA_SAVE_NR 14 - -static void pl011_lockup_wa(unsigned long data); -static const u32 uart_wa_reg[UART_WA_SAVE_NR] = { - ST_UART011_DMAWM, - ST_UART011_TIMEOUT, - ST_UART011_LCRH_RX, - UART011_IBRD, - UART011_FBRD, - ST_UART011_LCRH_TX, - UART011_IFLS, - ST_UART011_XFCR, - ST_UART011_XON1, - ST_UART011_XON2, - ST_UART011_XOFF1, - ST_UART011_XOFF2, - UART011_CR, - UART011_IMSC -}; - -static u32 uart_wa_regdata[UART_WA_SAVE_NR]; -static DECLARE_TASKLET(pl011_lockup_tlet, pl011_lockup_wa, 0); - /* There is by now at least one vendor with differing details, so handle it */ struct vendor_data { unsigned int ifls; @@ -100,6 +77,7 @@ struct vendor_data { bool oversampling; bool interrupt_may_hang; /* vendor-specific */ bool dma_threshold; + bool cts_event_workaround; }; static struct vendor_data vendor_arm = { @@ -109,6 +87,7 @@ static struct vendor_data vendor_arm = { .lcrh_rx = UART011_LCRH, .oversampling = false, .dma_threshold = false, + .cts_event_workaround = false, }; static struct vendor_data vendor_st = { @@ -119,6 +98,7 @@ static struct vendor_data vendor_st = { .oversampling = true, .interrupt_may_hang = true, .dma_threshold = true, + .cts_event_workaround = true, }; static struct uart_amba_port *amba_ports[UART_NR]; @@ -1054,69 +1034,6 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap) #define pl011_dma_flush_buffer NULL #endif - -/* - * pl011_lockup_wa - * This workaround aims to break the deadlock situation - * when after long transfer over uart in hardware flow - * control, uart interrupt registers cannot be cleared. - * Hence uart transfer gets blocked. - * - * It is seen that during such deadlock condition ICR - * don't get cleared even on multiple write. This leads - * pass_counter to decrease and finally reach zero. This - * can be taken as trigger point to run this UART_BT_WA. - * - */ -static void pl011_lockup_wa(unsigned long data) -{ - struct uart_amba_port *uap = amba_ports[0]; - void __iomem *base = uap->port.membase; - struct circ_buf *xmit = &uap->port.state->xmit; - struct tty_struct *tty = uap->port.state->port.tty; - int buf_empty_retries = 200; - int loop; - - /* Stop HCI layer from submitting data for tx */ - tty->hw_stopped = 1; - while (!uart_circ_empty(xmit)) { - if (buf_empty_retries-- == 0) - break; - udelay(100); - } - - /* Backup registers */ - for (loop = 0; loop < UART_WA_SAVE_NR; loop++) - uart_wa_regdata[loop] = readl(base + uart_wa_reg[loop]); - - /* Disable UART so that FIFO data is flushed out */ - writew(0x00, uap->port.membase + UART011_CR); - - /* Soft reset UART module */ - if (uap->port.dev->platform_data) { - struct amba_pl011_data *plat; - - plat = uap->port.dev->platform_data; - if (plat->reset) - plat->reset(); - } - - /* Restore registers */ - for (loop = 0; loop < UART_WA_SAVE_NR; loop++) - writew(uart_wa_regdata[loop] , - uap->port.membase + uart_wa_reg[loop]); - - /* Initialise the old status of the modem signals */ - uap->old_status = readw(uap->port.membase + UART01x_FR) & - UART01x_FR_MODEM_ANY; - - if (readl(base + UART011_MIS) & 0x2) - printk(KERN_EMERG "UART_BT_WA: ***FAILED***\n"); - - /* Start Tx/Rx */ - tty->hw_stopped = 0; -} - static void pl011_stop_tx(struct uart_port *port) { struct uart_amba_port *uap = (struct uart_amba_port *)port; @@ -1245,12 +1162,26 @@ static irqreturn_t pl011_int(int irq, void *dev_id) unsigned long flags; unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; int handled = 0; + unsigned int dummy_read; spin_lock_irqsave(&uap->port.lock, flags); status = readw(uap->port.membase + UART011_MIS); if (status) { do { + if (uap->vendor->cts_event_workaround) { + /* workaround to make sure that all bits are unlocked.. */ + writew(0x00, uap->port.membase + UART011_ICR); + + /* + * WA: introduce 26ns(1 uart clk) delay before W1C; + * single apb access will incur 2 pclk(133.12Mhz) delay, + * so add 2 dummy reads + */ + dummy_read = readw(uap->port.membase + UART011_ICR); + dummy_read = readw(uap->port.membase + UART011_ICR); + } + writew(status & ~(UART011_TXIS|UART011_RTIS| UART011_RXIS), uap->port.membase + UART011_ICR); @@ -1267,11 +1198,8 @@ static irqreturn_t pl011_int(int irq, void *dev_id) if (status & UART011_TXIS) pl011_tx_chars(uap); - if (pass_counter-- == 0) { - if (uap->interrupt_may_hang) - tasklet_schedule(&pl011_lockup_tlet); + if (pass_counter-- == 0) break; - } status = readw(uap->port.membase + UART011_MIS); } while (status != 0); @@ -1916,6 +1844,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) { struct uart_amba_port *uap; struct vendor_data *vendor = id->data; + struct pinctrl *pinctrl; void __iomem *base; int i, ret; @@ -1940,6 +1869,12 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) goto free; } + pinctrl = devm_pinctrl_get_select_default(&dev->dev); + if (IS_ERR(pinctrl)) { + ret = PTR_ERR(pinctrl); + goto unmap; + } + uap->clk = clk_get(&dev->dev, NULL); if (IS_ERR(uap->clk)) { ret = PTR_ERR(uap->clk); diff --git a/trunk/drivers/tty/serial/bfin_uart.c b/trunk/drivers/tty/serial/bfin_uart.c index 5832fdef11e9..bd97db23985b 100644 --- a/trunk/drivers/tty/serial/bfin_uart.c +++ b/trunk/drivers/tty/serial/bfin_uart.c @@ -1,7 +1,7 @@ /* * Blackfin On-Chip Serial Driver * - * Copyright 2006-2010 Analog Devices Inc. + * Copyright 2006-2011 Analog Devices Inc. * * Enter bugs at http://blackfin.uclinux.org/ * @@ -35,10 +35,6 @@ #include #include #include - -#define port_membase(uart) (((struct bfin_serial_port *)(uart))->port.membase) -#define get_lsr_cache(uart) (((struct bfin_serial_port *)(uart))->lsr) -#define put_lsr_cache(uart, v) (((struct bfin_serial_port *)(uart))->lsr = (v)) #include #ifdef CONFIG_SERIAL_BFIN_MODULE @@ -166,7 +162,7 @@ static void bfin_serial_stop_tx(struct uart_port *port) uart->tx_count = 0; uart->tx_done = 1; #else -#ifdef CONFIG_BF54x +#if defined(CONFIG_BF54x) || defined(CONFIG_BF60x) /* Clear TFI bit */ UART_PUT_LSR(uart, TFI); #endif @@ -337,7 +333,7 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart) struct circ_buf *xmit = &uart->port.state->xmit; if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { -#ifdef CONFIG_BF54x +#if defined(CONFIG_BF54x) || defined(CONFIG_BF60x) /* Clear TFI bit */ UART_PUT_LSR(uart, TFI); #endif @@ -536,7 +532,7 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id) */ UART_CLEAR_IER(uart, ETBEI); uart->port.icount.tx += uart->tx_count; - if (!uart_circ_empty(xmit)) { + if (!(xmit->tail == 0 && xmit->head == 0)) { xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) @@ -553,7 +549,7 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id) static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id) { struct bfin_serial_port *uart = dev_id; - unsigned short irqstat; + unsigned int irqstat; int x_pos, pos; spin_lock(&uart->rx_lock); @@ -586,7 +582,7 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id) static unsigned int bfin_serial_tx_empty(struct uart_port *port) { struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - unsigned short lsr; + unsigned int lsr; lsr = UART_GET_LSR(uart); if (lsr & TEMT) @@ -598,7 +594,7 @@ static unsigned int bfin_serial_tx_empty(struct uart_port *port) static void bfin_serial_break_ctl(struct uart_port *port, int break_state) { struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - u16 lcr = UART_GET_LCR(uart); + u32 lcr = UART_GET_LCR(uart); if (break_state) lcr |= SB; else @@ -745,7 +741,7 @@ static int bfin_serial_startup(struct uart_port *port) } /* CTS RTS PINs are negative assertive. */ - UART_PUT_MCR(uart, ACTS); + UART_PUT_MCR(uart, UART_GET_MCR(uart) | ACTS); UART_SET_IER(uart, EDSSI); } #endif @@ -803,7 +799,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, struct bfin_serial_port *uart = (struct bfin_serial_port *)port; unsigned long flags; unsigned int baud, quot; - unsigned short val, ier, lcr = 0; + unsigned int ier, lcr = 0; switch (termios->c_cflag & CSIZE) { case CS8: @@ -875,26 +871,23 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, /* Disable UART */ ier = UART_GET_IER(uart); + UART_PUT_GCTL(uart, UART_GET_GCTL(uart) & ~UCEN); UART_DISABLE_INTS(uart); - /* Set DLAB in LCR to Access DLL and DLH */ + /* Set DLAB in LCR to Access CLK */ UART_SET_DLAB(uart); - UART_PUT_DLL(uart, quot & 0xFF); - UART_PUT_DLH(uart, (quot >> 8) & 0xFF); + UART_PUT_CLK(uart, quot); SSYNC(); /* Clear DLAB in LCR to Access THR RBR IER */ UART_CLEAR_DLAB(uart); - UART_PUT_LCR(uart, lcr); + UART_PUT_LCR(uart, (UART_GET_LCR(uart) & ~LCR_MASK) | lcr); /* Enable UART */ UART_ENABLE_INTS(uart, ier); - - val = UART_GET_GCTL(uart); - val |= UCEN; - UART_PUT_GCTL(uart, val); + UART_PUT_GCTL(uart, UART_GET_GCTL(uart) | UCEN); /* Port speed changed, update the per-port timeout. */ uart_update_timeout(port, termios->c_cflag, baud); @@ -954,17 +947,17 @@ bfin_serial_verify_port(struct uart_port *port, struct serial_struct *ser) static void bfin_serial_set_ldisc(struct uart_port *port, int ld) { struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - unsigned short val; + unsigned int val; switch (ld) { case N_IRDA: val = UART_GET_GCTL(uart); - val |= (IREN | RPOLC); + val |= (UMOD_IRDA | RPOLC); UART_PUT_GCTL(uart, val); break; default: val = UART_GET_GCTL(uart); - val &= ~(IREN | RPOLC); + val &= ~(UMOD_MASK | RPOLC); UART_PUT_GCTL(uart, val); } } @@ -972,13 +965,13 @@ static void bfin_serial_set_ldisc(struct uart_port *port, int ld) static void bfin_serial_reset_irda(struct uart_port *port) { struct bfin_serial_port *uart = (struct bfin_serial_port *)port; - unsigned short val; + unsigned int val; val = UART_GET_GCTL(uart); - val &= ~(IREN | RPOLC); + val &= ~(UMOD_MASK | RPOLC); UART_PUT_GCTL(uart, val); SSYNC(); - val |= (IREN | RPOLC); + val |= (UMOD_IRDA | RPOLC); UART_PUT_GCTL(uart, val); SSYNC(); } @@ -1070,12 +1063,12 @@ static void __init bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud, int *parity, int *bits) { - unsigned short status; + unsigned int status; status = UART_GET_IER(uart) & (ERBFI | ETBEI); if (status == (ERBFI | ETBEI)) { /* ok, the port was enabled */ - u16 lcr, dlh, dll; + u32 lcr, clk; lcr = UART_GET_LCR(uart); @@ -1086,30 +1079,17 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud, else *parity = 'o'; } - switch (lcr & 0x03) { - case 0: - *bits = 5; - break; - case 1: - *bits = 6; - break; - case 2: - *bits = 7; - break; - case 3: - *bits = 8; - break; - } - /* Set DLAB in LCR to Access DLL and DLH */ + *bits = ((lcr & WLS_MASK) >> WLS_OFFSET) + 5; + + /* Set DLAB in LCR to Access CLK */ UART_SET_DLAB(uart); - dll = UART_GET_DLL(uart); - dlh = UART_GET_DLH(uart); + clk = UART_GET_CLK(uart); /* Clear DLAB in LCR to Access THR RBR IER */ UART_CLEAR_DLAB(uart); - *baud = get_sclk() / (16*(dll | dlh << 8)); + *baud = get_sclk() / (16*clk); } pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __func__, *baud, *parity, *bits); } diff --git a/trunk/drivers/tty/serial/clps711x.c b/trunk/drivers/tty/serial/clps711x.c index 836fe2731234..d0f719fafc84 100644 --- a/trunk/drivers/tty/serial/clps711x.c +++ b/trunk/drivers/tty/serial/clps711x.c @@ -40,7 +40,6 @@ #include #include -#include #define UART_NR 2 diff --git a/trunk/drivers/tty/serial/crisv10.c b/trunk/drivers/tty/serial/crisv10.c index 5b07c0c3a10c..7264d4d26717 100644 --- a/trunk/drivers/tty/serial/crisv10.c +++ b/trunk/drivers/tty/serial/crisv10.c @@ -952,19 +952,6 @@ static const struct control_pins e100_modem_pins[NR_PORTS] = /* Input */ #define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask) - -/* - * tmp_buf is used as a temporary buffer by serial_write. We need to - * lock it in case the memcpy_fromfs blocks while swapping in a page, - * and some other program tries to do a serial write at the same time. - * Since the lock will only come under contention when the system is - * swapping and available memory is low, it makes sense to share one - * buffer across all the serial ports, since it significantly saves - * memory if large numbers of serial ports are open. - */ -static unsigned char *tmp_buf; -static DEFINE_MUTEX(tmp_buf_mutex); - /* Calculate the chartime depending on baudrate, numbor of bits etc. */ static void update_char_time(struct e100_serial * info) { @@ -3150,7 +3137,7 @@ static int rs_raw_write(struct tty_struct *tty, /* first some sanity checks */ - if (!tty || !info->xmit.buf || !tmp_buf) + if (!tty || !info->xmit.buf) return 0; #ifdef SERIAL_DEBUG_DATA @@ -3989,7 +3976,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, */ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { - wait_event_interruptible_tty(info->close_wait, + wait_event_interruptible_tty(tty, info->close_wait, !(info->flags & ASYNC_CLOSING)); #ifdef SERIAL_DO_RESTART if (info->flags & ASYNC_HUP_NOTIFY) @@ -4065,9 +4052,9 @@ block_til_ready(struct tty_struct *tty, struct file * filp, printk("block_til_ready blocking: ttyS%d, count = %d\n", info->line, info->count); #endif - tty_unlock(); + tty_unlock(tty); schedule(); - tty_lock(); + tty_lock(tty); } set_current_state(TASK_RUNNING); remove_wait_queue(&info->open_wait, &wait); @@ -4106,7 +4093,6 @@ rs_open(struct tty_struct *tty, struct file * filp) { struct e100_serial *info; int retval; - unsigned long page; int allocated_resources = 0; info = rs_table + tty->index; @@ -4124,23 +4110,12 @@ rs_open(struct tty_struct *tty, struct file * filp) tty->low_latency = !!(info->flags & ASYNC_LOW_LATENCY); - if (!tmp_buf) { - page = get_zeroed_page(GFP_KERNEL); - if (!page) { - return -ENOMEM; - } - if (tmp_buf) - free_page(page); - else - tmp_buf = (unsigned char *) page; - } - /* * If the port is in the middle of closing, bail out now */ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { - wait_event_interruptible_tty(info->close_wait, + wait_event_interruptible_tty(tty, info->close_wait, !(info->flags & ASYNC_CLOSING)); #ifdef SERIAL_DO_RESTART return ((info->flags & ASYNC_HUP_NOTIFY) ? @@ -4487,6 +4462,7 @@ static int __init rs_init(void) info->enabled = 0; } } + tty_port_init(&info->port); info->uses_dma_in = 0; info->uses_dma_out = 0; info->line = i; diff --git a/trunk/drivers/tty/serial/imx.c b/trunk/drivers/tty/serial/imx.c index e7feceeebc2f..ec206732f68c 100644 --- a/trunk/drivers/tty/serial/imx.c +++ b/trunk/drivers/tty/serial/imx.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -1464,6 +1465,7 @@ static int serial_imx_probe(struct platform_device *pdev) void __iomem *base; int ret = 0; struct resource *res; + struct pinctrl *pinctrl; sport = kzalloc(sizeof(*sport), GFP_KERNEL); if (!sport) @@ -1503,6 +1505,12 @@ static int serial_imx_probe(struct platform_device *pdev) sport->timer.function = imx_timeout; sport->timer.data = (unsigned long)sport; + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(pinctrl)) { + ret = PTR_ERR(pinctrl); + goto unmap; + } + sport->clk = clk_get(&pdev->dev, "uart"); if (IS_ERR(sport->clk)) { ret = PTR_ERR(sport->clk); diff --git a/trunk/drivers/tty/serial/mxs-auart.c b/trunk/drivers/tty/serial/mxs-auart.c index 55fd362b9879..ec56d8397aae 100644 --- a/trunk/drivers/tty/serial/mxs-auart.c +++ b/trunk/drivers/tty/serial/mxs-auart.c @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -369,6 +370,8 @@ static void mxs_auart_settermios(struct uart_port *u, writel(ctrl, u->membase + AUART_LINECTRL); writel(ctrl2, u->membase + AUART_CTRL2); + + uart_update_timeout(u, termios->c_cflag, baud); } static irqreturn_t mxs_auart_irq_handle(int irq, void *context) @@ -678,6 +681,7 @@ static int __devinit mxs_auart_probe(struct platform_device *pdev) u32 version; int ret = 0; struct resource *r; + struct pinctrl *pinctrl; s = kzalloc(sizeof(struct mxs_auart_port), GFP_KERNEL); if (!s) { @@ -685,6 +689,12 @@ static int __devinit mxs_auart_probe(struct platform_device *pdev) goto out; } + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(pinctrl)) { + ret = PTR_ERR(pinctrl); + goto out_free; + } + s->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(s->clk)) { ret = PTR_ERR(s->clk); diff --git a/trunk/drivers/tty/serial/of_serial.c b/trunk/drivers/tty/serial/of_serial.c index e8c9cee07d00..5410c0637266 100644 --- a/trunk/drivers/tty/serial/of_serial.c +++ b/trunk/drivers/tty/serial/of_serial.c @@ -12,10 +12,13 @@ #include #include #include +#include #include #include +#include #include #include +#include #include #include @@ -24,6 +27,26 @@ struct of_serial_info { int line; }; +#ifdef CONFIG_ARCH_TEGRA +void tegra_serial_handle_break(struct uart_port *p) +{ + unsigned int status, tmout = 10000; + + do { + status = p->serial_in(p, UART_LSR); + if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)) + status = p->serial_in(p, UART_RX); + else + break; + if (--tmout == 0) + break; + udelay(1); + } while (1); +} +/* FIXME remove this export when tegra finishes conversion to open firmware */ +EXPORT_SYMBOL_GPL(tegra_serial_handle_break); +#endif + /* * Fill a struct uart_port for a given device node */ @@ -84,6 +107,9 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev, | UPF_FIXED_PORT | UPF_FIXED_TYPE; port->dev = &ofdev->dev; + if (type == PORT_TEGRA) + port->handle_break = tegra_serial_handle_break; + return 0; } diff --git a/trunk/drivers/tty/serial/omap-serial.c b/trunk/drivers/tty/serial/omap-serial.c index d00b38eb268e..d3cda0cb2df0 100644 --- a/trunk/drivers/tty/serial/omap-serial.c +++ b/trunk/drivers/tty/serial/omap-serial.c @@ -44,6 +44,13 @@ #include #include +#define UART_BUILD_REVISION(x, y) (((x) << 8) | (y)) + +#define OMAP_UART_REV_42 0x0402 +#define OMAP_UART_REV_46 0x0406 +#define OMAP_UART_REV_52 0x0502 +#define OMAP_UART_REV_63 0x0603 + #define DEFAULT_CLK_SPEED 48000000 /* 48Mhz*/ /* SCR register bitmasks */ @@ -53,6 +60,17 @@ #define OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT 6 #define OMAP_UART_FCR_RX_FIFO_TRIG_MASK (0x3 << 6) +/* MVR register bitmasks */ +#define OMAP_UART_MVR_SCHEME_SHIFT 30 + +#define OMAP_UART_LEGACY_MVR_MAJ_MASK 0xf0 +#define OMAP_UART_LEGACY_MVR_MAJ_SHIFT 4 +#define OMAP_UART_LEGACY_MVR_MIN_MASK 0x0f + +#define OMAP_UART_MVR_MAJ_MASK 0x700 +#define OMAP_UART_MVR_MAJ_SHIFT 8 +#define OMAP_UART_MVR_MIN_MASK 0x3f + static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS]; /* Forward declaration of functions */ @@ -1346,6 +1364,59 @@ static void uart_tx_dma_callback(int lch, u16 ch_status, void *data) return; } +static void omap_serial_fill_features_erratas(struct uart_omap_port *up) +{ + u32 mvr, scheme; + u16 revision, major, minor; + + mvr = serial_in(up, UART_OMAP_MVER); + + /* Check revision register scheme */ + scheme = mvr >> OMAP_UART_MVR_SCHEME_SHIFT; + + switch (scheme) { + case 0: /* Legacy Scheme: OMAP2/3 */ + /* MINOR_REV[0:4], MAJOR_REV[4:7] */ + major = (mvr & OMAP_UART_LEGACY_MVR_MAJ_MASK) >> + OMAP_UART_LEGACY_MVR_MAJ_SHIFT; + minor = (mvr & OMAP_UART_LEGACY_MVR_MIN_MASK); + break; + case 1: + /* New Scheme: OMAP4+ */ + /* MINOR_REV[0:5], MAJOR_REV[8:10] */ + major = (mvr & OMAP_UART_MVR_MAJ_MASK) >> + OMAP_UART_MVR_MAJ_SHIFT; + minor = (mvr & OMAP_UART_MVR_MIN_MASK); + break; + default: + dev_warn(&up->pdev->dev, + "Unknown %s revision, defaulting to highest\n", + up->name); + /* highest possible revision */ + major = 0xff; + minor = 0xff; + } + + /* normalize revision for the driver */ + revision = UART_BUILD_REVISION(major, minor); + + switch (revision) { + case OMAP_UART_REV_46: + up->errata |= (UART_ERRATA_i202_MDR1_ACCESS | + UART_ERRATA_i291_DMA_FORCEIDLE); + break; + case OMAP_UART_REV_52: + up->errata |= (UART_ERRATA_i202_MDR1_ACCESS | + UART_ERRATA_i291_DMA_FORCEIDLE); + break; + case OMAP_UART_REV_63: + up->errata |= UART_ERRATA_i202_MDR1_ACCESS; + break; + default: + break; + } +} + static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev) { struct omap_uart_port_info *omap_up_info; @@ -1439,7 +1510,6 @@ static int serial_omap_probe(struct platform_device *pdev) "%d\n", DEFAULT_CLK_SPEED); } up->uart_dma.uart_base = mem->start; - up->errata = omap_up_info->errata; if (omap_up_info->dma_enabled) { up->uart_dma.uart_dma_tx = dma_tx->start; @@ -1469,6 +1539,8 @@ static int serial_omap_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); + omap_serial_fill_features_erratas(up); + ui[up->port.line] = up; serial_omap_add_console_port(up); diff --git a/trunk/drivers/tty/serial/pch_uart.c b/trunk/drivers/tty/serial/pch_uart.c index c2816f494807..4fdec6a6b758 100644 --- a/trunk/drivers/tty/serial/pch_uart.c +++ b/trunk/drivers/tty/serial/pch_uart.c @@ -39,6 +39,7 @@ enum { PCH_UART_HANDLED_RX_ERR_INT_SHIFT, PCH_UART_HANDLED_RX_TRG_INT_SHIFT, PCH_UART_HANDLED_MS_INT_SHIFT, + PCH_UART_HANDLED_LS_INT_SHIFT, }; enum { @@ -63,6 +64,8 @@ enum { PCH_UART_HANDLED_RX_TRG_INT_SHIFT)<<1)) #define PCH_UART_HANDLED_MS_INT (1<<((PCH_UART_HANDLED_MS_INT_SHIFT)<<1)) +#define PCH_UART_HANDLED_LS_INT (1<<((PCH_UART_HANDLED_LS_INT_SHIFT)<<1)) + #define PCH_UART_RBR 0x00 #define PCH_UART_THR 0x00 @@ -229,7 +232,6 @@ struct eg20t_port { int start_tx; int start_rx; int tx_empty; - int int_dis_flag; int trigger; int trigger_level; struct pch_uart_buffer rxbuf; @@ -237,7 +239,6 @@ struct eg20t_port { unsigned int fcr; unsigned int mcr; unsigned int use_dma; - unsigned int use_dma_flag; struct dma_async_tx_descriptor *desc_tx; struct dma_async_tx_descriptor *desc_rx; struct pch_dma_slave param_tx; @@ -560,14 +561,10 @@ static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf, return i; } -static unsigned int pch_uart_hal_get_iid(struct eg20t_port *priv) +static unsigned char pch_uart_hal_get_iid(struct eg20t_port *priv) { - unsigned int iir; - int ret; - - iir = ioread8(priv->membase + UART_IIR); - ret = (iir & (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP)); - return ret; + return ioread8(priv->membase + UART_IIR) &\ + (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP); } static u8 pch_uart_hal_get_line_status(struct eg20t_port *priv) @@ -666,10 +663,13 @@ static void pch_free_dma(struct uart_port *port) dma_release_channel(priv->chan_rx); priv->chan_rx = NULL; } - if (sg_dma_address(&priv->sg_rx)) - dma_free_coherent(port->dev, port->fifosize, - sg_virt(&priv->sg_rx), - sg_dma_address(&priv->sg_rx)); + + if (priv->rx_buf_dma) { + dma_free_coherent(port->dev, port->fifosize, priv->rx_buf_virt, + priv->rx_buf_dma); + priv->rx_buf_virt = NULL; + priv->rx_buf_dma = 0; + } return; } @@ -1053,12 +1053,17 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) unsigned int handled; u8 lsr; int ret = 0; - unsigned int iid; + unsigned char iid; unsigned long flags; + int next = 1; + u8 msr; spin_lock_irqsave(&priv->port.lock, flags); handled = 0; - while ((iid = pch_uart_hal_get_iid(priv)) > 1) { + while (next) { + iid = pch_uart_hal_get_iid(priv); + if (iid & PCH_UART_IIR_IP) /* No Interrupt */ + break; switch (iid) { case PCH_UART_IID_RLS: /* Receiver Line Status */ lsr = pch_uart_hal_get_line_status(priv); @@ -1066,6 +1071,8 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) UART_LSR_PE | UART_LSR_OE)) { pch_uart_err_ir(priv, lsr); ret = PCH_UART_HANDLED_RX_ERR_INT; + } else { + ret = PCH_UART_HANDLED_LS_INT; } break; case PCH_UART_IID_RDR: /* Received Data Ready */ @@ -1092,20 +1099,22 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) ret = handle_tx(priv); break; case PCH_UART_IID_MS: /* Modem Status */ - ret = PCH_UART_HANDLED_MS_INT; + msr = pch_uart_hal_get_modem(priv); + next = 0; /* MS ir prioirty is the lowest. So, MS ir + means final interrupt */ + if ((msr & UART_MSR_ANY_DELTA) == 0) + break; + ret |= PCH_UART_HANDLED_MS_INT; break; default: /* Never junp to this label */ - dev_err(priv->port.dev, "%s:iid=%d (%lu)\n", __func__, + dev_err(priv->port.dev, "%s:iid=%02x (%lu)\n", __func__, iid, jiffies); ret = -1; + next = 0; break; } handled |= (unsigned int)ret; } - if (handled == 0 && iid <= 1) { - if (priv->int_dis_flag) - priv->int_dis_flag = 0; - } spin_unlock_irqrestore(&priv->port.lock, flags); return IRQ_RETVAL(handled); @@ -1200,7 +1209,6 @@ static void pch_uart_stop_rx(struct uart_port *port) priv = container_of(port, struct eg20t_port, port); priv->start_rx = 0; pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT); - priv->int_dis_flag = 1; } /* Enable the modem status interrupts. */ @@ -1447,7 +1455,6 @@ static int pch_uart_verify_port(struct uart_port *port, __func__); return -EOPNOTSUPP; #endif - priv->use_dma_flag = 1; dev_info(priv->port.dev, "PCH UART : Use DMA Mode\n"); if (!priv->use_dma) pch_request_dma(port); diff --git a/trunk/drivers/tty/serial/serial_core.c b/trunk/drivers/tty/serial/serial_core.c index 9c4c05b2825b..246b823c1b27 100644 --- a/trunk/drivers/tty/serial/serial_core.c +++ b/trunk/drivers/tty/serial/serial_core.c @@ -2282,6 +2282,7 @@ void uart_unregister_driver(struct uart_driver *drv) tty_unregister_driver(p); put_tty_driver(p); kfree(drv->state); + drv->state = NULL; drv->tty_driver = NULL; } diff --git a/trunk/drivers/tty/synclink.c b/trunk/drivers/tty/synclink.c index 593d40ad0a6b..5ed0daae6564 100644 --- a/trunk/drivers/tty/synclink.c +++ b/trunk/drivers/tty/synclink.c @@ -3338,9 +3338,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, printk("%s(%d):block_til_ready blocking on %s count=%d\n", __FILE__,__LINE__, tty->driver->name, port->count ); - tty_unlock(); + tty_unlock(tty); schedule(); - tty_lock(); + tty_lock(tty); } set_current_state(TASK_RUNNING); diff --git a/trunk/drivers/tty/synclink_gt.c b/trunk/drivers/tty/synclink_gt.c index aa1debf97cc7..45b43f11ca39 100644 --- a/trunk/drivers/tty/synclink_gt.c +++ b/trunk/drivers/tty/synclink_gt.c @@ -3336,9 +3336,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, } DBGINFO(("%s block_til_ready wait\n", tty->driver->name)); - tty_unlock(); + tty_unlock(tty); schedule(); - tty_lock(); + tty_lock(tty); } set_current_state(TASK_RUNNING); diff --git a/trunk/drivers/tty/synclinkmp.c b/trunk/drivers/tty/synclinkmp.c index a3dddc12d2fe..4a1e4f07765b 100644 --- a/trunk/drivers/tty/synclinkmp.c +++ b/trunk/drivers/tty/synclinkmp.c @@ -3357,9 +3357,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, printk("%s(%d):%s block_til_ready() count=%d\n", __FILE__,__LINE__, tty->driver->name, port->count ); - tty_unlock(); + tty_unlock(tty); schedule(); - tty_lock(); + tty_lock(tty); } set_current_state(TASK_RUNNING); diff --git a/trunk/drivers/tty/tty_buffer.c b/trunk/drivers/tty/tty_buffer.c index 6c9b7cd6778a..91e326ffe7db 100644 --- a/trunk/drivers/tty/tty_buffer.c +++ b/trunk/drivers/tty/tty_buffer.c @@ -185,25 +185,19 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) /* Should possibly check if this fails for the largest buffer we have queued and recycle that ? */ } - /** - * tty_buffer_request_room - grow tty buffer if needed + * __tty_buffer_request_room - grow tty buffer if needed * @tty: tty structure * @size: size desired * * Make at least size bytes of linear space available for the tty * buffer. If we fail return the size we managed to find. - * - * Locking: Takes tty->buf.lock + * Locking: Caller must hold tty->buf.lock */ -int tty_buffer_request_room(struct tty_struct *tty, size_t size) +static int __tty_buffer_request_room(struct tty_struct *tty, size_t size) { struct tty_buffer *b, *n; int left; - unsigned long flags; - - spin_lock_irqsave(&tty->buf.lock, flags); - /* OPTIMISATION: We could keep a per tty "zero" sized buffer to remove this conditional if its worth it. This would be invisible to the callers */ @@ -225,9 +219,30 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size) size = left; } - spin_unlock_irqrestore(&tty->buf.lock, flags); return size; } + + +/** + * tty_buffer_request_room - grow tty buffer if needed + * @tty: tty structure + * @size: size desired + * + * Make at least size bytes of linear space available for the tty + * buffer. If we fail return the size we managed to find. + * + * Locking: Takes tty->buf.lock + */ +int tty_buffer_request_room(struct tty_struct *tty, size_t size) +{ + unsigned long flags; + int length; + + spin_lock_irqsave(&tty->buf.lock, flags); + length = __tty_buffer_request_room(tty, size); + spin_unlock_irqrestore(&tty->buf.lock, flags); + return length; +} EXPORT_SYMBOL_GPL(tty_buffer_request_room); /** @@ -249,14 +264,22 @@ int tty_insert_flip_string_fixed_flag(struct tty_struct *tty, int copied = 0; do { int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); - int space = tty_buffer_request_room(tty, goal); - struct tty_buffer *tb = tty->buf.tail; + int space; + unsigned long flags; + struct tty_buffer *tb; + + spin_lock_irqsave(&tty->buf.lock, flags); + space = __tty_buffer_request_room(tty, goal); + tb = tty->buf.tail; /* If there is no space then tb may be NULL */ - if (unlikely(space == 0)) + if (unlikely(space == 0)) { + spin_unlock_irqrestore(&tty->buf.lock, flags); break; + } memcpy(tb->char_buf_ptr + tb->used, chars, space); memset(tb->flag_buf_ptr + tb->used, flag, space); tb->used += space; + spin_unlock_irqrestore(&tty->buf.lock, flags); copied += space; chars += space; /* There is a small chance that we need to split the data over @@ -286,14 +309,22 @@ int tty_insert_flip_string_flags(struct tty_struct *tty, int copied = 0; do { int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); - int space = tty_buffer_request_room(tty, goal); - struct tty_buffer *tb = tty->buf.tail; + int space; + unsigned long __flags; + struct tty_buffer *tb; + + spin_lock_irqsave(&tty->buf.lock, __flags); + space = __tty_buffer_request_room(tty, goal); + tb = tty->buf.tail; /* If there is no space then tb may be NULL */ - if (unlikely(space == 0)) + if (unlikely(space == 0)) { + spin_unlock_irqrestore(&tty->buf.lock, __flags); break; + } memcpy(tb->char_buf_ptr + tb->used, chars, space); memcpy(tb->flag_buf_ptr + tb->used, flags, space); tb->used += space; + spin_unlock_irqrestore(&tty->buf.lock, __flags); copied += space; chars += space; flags += space; @@ -344,13 +375,20 @@ EXPORT_SYMBOL(tty_schedule_flip); int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size) { - int space = tty_buffer_request_room(tty, size); + int space; + unsigned long flags; + struct tty_buffer *tb; + + spin_lock_irqsave(&tty->buf.lock, flags); + space = __tty_buffer_request_room(tty, size); + + tb = tty->buf.tail; if (likely(space)) { - struct tty_buffer *tb = tty->buf.tail; *chars = tb->char_buf_ptr + tb->used; memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); tb->used += space; } + spin_unlock_irqrestore(&tty->buf.lock, flags); return space; } EXPORT_SYMBOL_GPL(tty_prepare_flip_string); @@ -374,13 +412,20 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string); int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size) { - int space = tty_buffer_request_room(tty, size); + int space; + unsigned long __flags; + struct tty_buffer *tb; + + spin_lock_irqsave(&tty->buf.lock, __flags); + space = __tty_buffer_request_room(tty, size); + + tb = tty->buf.tail; if (likely(space)) { - struct tty_buffer *tb = tty->buf.tail; *chars = tb->char_buf_ptr + tb->used; *flags = tb->flag_buf_ptr + tb->used; tb->used += space; } + spin_unlock_irqrestore(&tty->buf.lock, __flags); return space; } EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); diff --git a/trunk/drivers/tty/tty_io.c b/trunk/drivers/tty/tty_io.c index d939bd705c71..9e930c009bf2 100644 --- a/trunk/drivers/tty/tty_io.c +++ b/trunk/drivers/tty/tty_io.c @@ -185,6 +185,7 @@ void free_tty_struct(struct tty_struct *tty) put_device(tty->dev); kfree(tty->write_buf); tty_buffer_free_all(tty); + tty->magic = 0xDEADDEAD; kfree(tty); } @@ -573,7 +574,7 @@ void __tty_hangup(struct tty_struct *tty) } spin_unlock(&redirect_lock); - tty_lock(); + tty_lock(tty); /* some functions below drop BTM, so we need this bit */ set_bit(TTY_HUPPING, &tty->flags); @@ -666,7 +667,7 @@ void __tty_hangup(struct tty_struct *tty) clear_bit(TTY_HUPPING, &tty->flags); tty_ldisc_enable(tty); - tty_unlock(); + tty_unlock(tty); if (f) fput(f); @@ -855,10 +856,11 @@ void disassociate_ctty(int on_exit) */ void no_tty(void) { + /* FIXME: Review locking here. The tty_lock never covered any race + between a new association and proc_clear_tty but possible we need + to protect against this anyway */ struct task_struct *tsk = current; - tty_lock(); disassociate_ctty(0); - tty_unlock(); proc_clear_tty(tsk); } @@ -1102,12 +1104,12 @@ void tty_write_message(struct tty_struct *tty, char *msg) { if (tty) { mutex_lock(&tty->atomic_write_lock); - tty_lock(); + tty_lock(tty); if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) { - tty_unlock(); + tty_unlock(tty); tty->ops->write(tty, msg, strlen(msg)); } else - tty_unlock(); + tty_unlock(tty); tty_write_unlock(tty); } return; @@ -1402,6 +1404,7 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) } initialize_tty_struct(tty, driver, idx); + tty_lock(tty); retval = tty_driver_install_tty(driver, tty); if (retval < 0) goto err_deinit_tty; @@ -1414,9 +1417,11 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) retval = tty_ldisc_setup(tty, tty->link); if (retval) goto err_release_tty; + /* Return the tty locked so that it cannot vanish under the caller */ return tty; err_deinit_tty: + tty_unlock(tty); deinitialize_tty_struct(tty); free_tty_struct(tty); err_module_put: @@ -1425,6 +1430,7 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) /* call the tty release_tty routine to clean out this slot */ err_release_tty: + tty_unlock(tty); printk_ratelimited(KERN_INFO "tty_init_dev: ldisc open failed, " "clearing slot %d\n", idx); release_tty(tty, idx); @@ -1627,7 +1633,7 @@ int tty_release(struct inode *inode, struct file *filp) if (tty_paranoia_check(tty, inode, __func__)) return 0; - tty_lock(); + tty_lock(tty); check_tty_count(tty, __func__); __tty_fasync(-1, filp, 0); @@ -1636,10 +1642,11 @@ int tty_release(struct inode *inode, struct file *filp) pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER); devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0; + /* Review: parallel close */ o_tty = tty->link; if (tty_release_checks(tty, o_tty, idx)) { - tty_unlock(); + tty_unlock(tty); return 0; } @@ -1651,7 +1658,7 @@ int tty_release(struct inode *inode, struct file *filp) if (tty->ops->close) tty->ops->close(tty, filp); - tty_unlock(); + tty_unlock(tty); /* * Sanity check: if tty->count is going to zero, there shouldn't be * any waiters on tty->read_wait or tty->write_wait. We test the @@ -1674,7 +1681,7 @@ int tty_release(struct inode *inode, struct file *filp) opens on /dev/tty */ mutex_lock(&tty_mutex); - tty_lock(); + tty_lock_pair(tty, o_tty); tty_closing = tty->count <= 1; o_tty_closing = o_tty && (o_tty->count <= (pty_master ? 1 : 0)); @@ -1705,7 +1712,7 @@ int tty_release(struct inode *inode, struct file *filp) printk(KERN_WARNING "%s: %s: read/write wait queue active!\n", __func__, tty_name(tty, buf)); - tty_unlock(); + tty_unlock_pair(tty, o_tty); mutex_unlock(&tty_mutex); schedule(); } @@ -1768,7 +1775,7 @@ int tty_release(struct inode *inode, struct file *filp) /* check whether both sides are closing ... */ if (!tty_closing || (o_tty && !o_tty_closing)) { - tty_unlock(); + tty_unlock_pair(tty, o_tty); return 0; } @@ -1781,14 +1788,16 @@ int tty_release(struct inode *inode, struct file *filp) tty_ldisc_release(tty, o_tty); /* * The release_tty function takes care of the details of clearing - * the slots and preserving the termios structure. + * the slots and preserving the termios structure. The tty_unlock_pair + * should be safe as we keep a kref while the tty is locked (so the + * unlock never unlocks a freed tty). */ release_tty(tty, idx); + tty_unlock_pair(tty, o_tty); /* Make this pty number available for reallocation */ if (devpts) devpts_kill_index(inode, idx); - tty_unlock(); return 0; } @@ -1800,6 +1809,9 @@ int tty_release(struct inode *inode, struct file *filp) * * We cannot return driver and index like for the other nodes because * devpts will not work then. It expects inodes to be from devpts FS. + * + * We need to move to returning a refcounted object from all the lookup + * paths including this one. */ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp) { @@ -1816,6 +1828,7 @@ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp) /* noctty = 1; */ tty_kref_put(tty); /* FIXME: we put a reference and return a TTY! */ + /* This is only safe because the caller holds tty_mutex */ return tty; } @@ -1888,6 +1901,9 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp, * Locking: tty_mutex protects tty, tty_lookup_driver and tty_init_dev. * tty->count should protect the rest. * ->siglock protects ->signal/->sighand + * + * Note: the tty_unlock/lock cases without a ref are only safe due to + * tty_mutex */ static int tty_open(struct inode *inode, struct file *filp) @@ -1911,8 +1927,7 @@ static int tty_open(struct inode *inode, struct file *filp) retval = 0; mutex_lock(&tty_mutex); - tty_lock(); - + /* This is protected by the tty_mutex */ tty = tty_open_current_tty(device, filp); if (IS_ERR(tty)) { retval = PTR_ERR(tty); @@ -1933,17 +1948,19 @@ static int tty_open(struct inode *inode, struct file *filp) } if (tty) { + tty_lock(tty); retval = tty_reopen(tty); - if (retval) + if (retval < 0) { + tty_unlock(tty); tty = ERR_PTR(retval); - } else + } + } else /* Returns with the tty_lock held for now */ tty = tty_init_dev(driver, index); mutex_unlock(&tty_mutex); if (driver) tty_driver_kref_put(driver); if (IS_ERR(tty)) { - tty_unlock(); retval = PTR_ERR(tty); goto err_file; } @@ -1972,7 +1989,7 @@ static int tty_open(struct inode *inode, struct file *filp) printk(KERN_DEBUG "%s: error %d in opening %s...\n", __func__, retval, tty->name); #endif - tty_unlock(); /* need to call tty_release without BTM */ + tty_unlock(tty); /* need to call tty_release without BTM */ tty_release(inode, filp); if (retval != -ERESTARTSYS) return retval; @@ -1984,17 +2001,15 @@ static int tty_open(struct inode *inode, struct file *filp) /* * Need to reset f_op in case a hangup happened. */ - tty_lock(); if (filp->f_op == &hung_up_tty_fops) filp->f_op = &tty_fops; - tty_unlock(); goto retry_open; } - tty_unlock(); + tty_unlock(tty); mutex_lock(&tty_mutex); - tty_lock(); + tty_lock(tty); spin_lock_irq(¤t->sighand->siglock); if (!noctty && current->signal->leader && @@ -2002,11 +2017,10 @@ static int tty_open(struct inode *inode, struct file *filp) tty->session == NULL) __proc_set_tty(current, tty); spin_unlock_irq(¤t->sighand->siglock); - tty_unlock(); + tty_unlock(tty); mutex_unlock(&tty_mutex); return 0; err_unlock: - tty_unlock(); mutex_unlock(&tty_mutex); /* after locks to avoid deadlock */ if (!IS_ERR_OR_NULL(driver)) @@ -2089,10 +2103,13 @@ static int __tty_fasync(int fd, struct file *filp, int on) static int tty_fasync(int fd, struct file *filp, int on) { + struct tty_struct *tty = file_tty(filp); int retval; - tty_lock(); + + tty_lock(tty); retval = __tty_fasync(fd, filp, on); - tty_unlock(); + tty_unlock(tty); + return retval; } @@ -2929,6 +2946,7 @@ void initialize_tty_struct(struct tty_struct *tty, tty->pgrp = NULL; tty->overrun_time = jiffies; tty_buffer_init(tty); + mutex_init(&tty->legacy_mutex); mutex_init(&tty->termios_mutex); mutex_init(&tty->ldisc_mutex); init_waitqueue_head(&tty->write_wait); diff --git a/trunk/drivers/tty/tty_ldisc.c b/trunk/drivers/tty/tty_ldisc.c index 24b95db75d84..173a9000a6cb 100644 --- a/trunk/drivers/tty/tty_ldisc.c +++ b/trunk/drivers/tty/tty_ldisc.c @@ -28,7 +28,6 @@ static DEFINE_SPINLOCK(tty_ldisc_lock); static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait); -static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_idle); /* Line disc dispatch table */ static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS]; @@ -65,7 +64,7 @@ static void put_ldisc(struct tty_ldisc *ld) return; } local_irq_restore(flags); - wake_up(&tty_ldisc_idle); + wake_up(&ld->wq_idle); } /** @@ -200,6 +199,8 @@ static struct tty_ldisc *tty_ldisc_get(int disc) ld->ops = ldops; atomic_set(&ld->users, 1); + init_waitqueue_head(&ld->wq_idle); + return ld; } @@ -538,7 +539,7 @@ static void tty_ldisc_flush_works(struct tty_struct *tty) static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout) { long ret; - ret = wait_event_timeout(tty_ldisc_idle, + ret = wait_event_timeout(tty->ldisc->wq_idle, atomic_read(&tty->ldisc->users) == 1, timeout); return ret > 0 ? 0 : -EBUSY; } @@ -567,7 +568,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) if (IS_ERR(new_ldisc)) return PTR_ERR(new_ldisc); - tty_lock(); + tty_lock(tty); /* * We need to look at the tty locking here for pty/tty pairs * when both sides try to change in parallel. @@ -581,12 +582,12 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) */ if (tty->ldisc->ops->num == ldisc) { - tty_unlock(); + tty_unlock(tty); tty_ldisc_put(new_ldisc); return 0; } - tty_unlock(); + tty_unlock(tty); /* * Problem: What do we do if this blocks ? * We could deadlock here @@ -594,7 +595,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) tty_wait_until_sent(tty, 0); - tty_lock(); + tty_lock(tty); mutex_lock(&tty->ldisc_mutex); /* @@ -604,10 +605,10 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) { mutex_unlock(&tty->ldisc_mutex); - tty_unlock(); + tty_unlock(tty); wait_event(tty_ldisc_wait, test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0); - tty_lock(); + tty_lock(tty); mutex_lock(&tty->ldisc_mutex); } @@ -622,7 +623,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) o_ldisc = tty->ldisc; - tty_unlock(); + tty_unlock(tty); /* * Make sure we don't change while someone holds a * reference to the line discipline. The TTY_LDISC bit @@ -649,7 +650,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) retval = tty_ldisc_wait_idle(tty, 5 * HZ); - tty_lock(); + tty_lock(tty); mutex_lock(&tty->ldisc_mutex); /* handle wait idle failure locked */ @@ -664,7 +665,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) clear_bit(TTY_LDISC_CHANGING, &tty->flags); mutex_unlock(&tty->ldisc_mutex); tty_ldisc_put(new_ldisc); - tty_unlock(); + tty_unlock(tty); return -EIO; } @@ -707,7 +708,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) if (o_work) schedule_work(&o_tty->buf.work); mutex_unlock(&tty->ldisc_mutex); - tty_unlock(); + tty_unlock(tty); return retval; } @@ -815,11 +816,11 @@ void tty_ldisc_hangup(struct tty_struct *tty) * need to wait for another function taking the BTM */ clear_bit(TTY_LDISC, &tty->flags); - tty_unlock(); + tty_unlock(tty); cancel_work_sync(&tty->buf.work); mutex_unlock(&tty->ldisc_mutex); retry: - tty_lock(); + tty_lock(tty); mutex_lock(&tty->ldisc_mutex); /* At this point we have a closed ldisc and we want to @@ -830,7 +831,7 @@ void tty_ldisc_hangup(struct tty_struct *tty) if (atomic_read(&tty->ldisc->users) != 1) { char cur_n[TASK_COMM_LEN], tty_n[64]; long timeout = 3 * HZ; - tty_unlock(); + tty_unlock(tty); while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) { timeout = MAX_SCHEDULE_TIMEOUT; @@ -911,10 +912,10 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) * race with the set_ldisc code path. */ - tty_unlock(); + tty_unlock(tty); tty_ldisc_halt(tty); tty_ldisc_flush_works(tty); - tty_lock(); + tty_lock(tty); mutex_lock(&tty->ldisc_mutex); /* diff --git a/trunk/drivers/tty/tty_mutex.c b/trunk/drivers/tty/tty_mutex.c index 9ff986c32a21..69adc80c98cd 100644 --- a/trunk/drivers/tty/tty_mutex.c +++ b/trunk/drivers/tty/tty_mutex.c @@ -4,29 +4,59 @@ #include #include -/* - * The 'big tty mutex' - * - * This mutex is taken and released by tty_lock() and tty_unlock(), - * replacing the older big kernel lock. - * It can no longer be taken recursively, and does not get - * released implicitly while sleeping. - * - * Don't use in new code. - */ -static DEFINE_MUTEX(big_tty_mutex); +/* Legacy tty mutex glue */ /* * Getting the big tty mutex. */ -void __lockfunc tty_lock(void) + +void __lockfunc tty_lock(struct tty_struct *tty) { - mutex_lock(&big_tty_mutex); + if (tty->magic != TTY_MAGIC) { + printk(KERN_ERR "L Bad %p\n", tty); + WARN_ON(1); + return; + } + tty_kref_get(tty); + mutex_lock(&tty->legacy_mutex); } EXPORT_SYMBOL(tty_lock); -void __lockfunc tty_unlock(void) +void __lockfunc tty_unlock(struct tty_struct *tty) { - mutex_unlock(&big_tty_mutex); + if (tty->magic != TTY_MAGIC) { + printk(KERN_ERR "U Bad %p\n", tty); + WARN_ON(1); + return; + } + mutex_unlock(&tty->legacy_mutex); + tty_kref_put(tty); } EXPORT_SYMBOL(tty_unlock); + +/* + * Getting the big tty mutex for a pair of ttys with lock ordering + * On a non pty/tty pair tty2 can be NULL which is just fine. + */ +void __lockfunc tty_lock_pair(struct tty_struct *tty, + struct tty_struct *tty2) +{ + if (tty < tty2) { + tty_lock(tty); + tty_lock(tty2); + } else { + if (tty2 && tty2 != tty) + tty_lock(tty2); + tty_lock(tty); + } +} +EXPORT_SYMBOL(tty_lock_pair); + +void __lockfunc tty_unlock_pair(struct tty_struct *tty, + struct tty_struct *tty2) +{ + tty_unlock(tty); + if (tty2 && tty2 != tty) + tty_unlock(tty2); +} +EXPORT_SYMBOL(tty_unlock_pair); diff --git a/trunk/drivers/tty/tty_port.c b/trunk/drivers/tty/tty_port.c index bf6e238146ae..d9cca95a5452 100644 --- a/trunk/drivers/tty/tty_port.c +++ b/trunk/drivers/tty/tty_port.c @@ -230,7 +230,7 @@ int tty_port_block_til_ready(struct tty_port *port, /* block if port is in the process of being closed */ if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { - wait_event_interruptible_tty(port->close_wait, + wait_event_interruptible_tty(tty, port->close_wait, !(port->flags & ASYNC_CLOSING)); if (port->flags & ASYNC_HUP_NOTIFY) return -EAGAIN; @@ -296,9 +296,9 @@ int tty_port_block_til_ready(struct tty_port *port, retval = -ERESTARTSYS; break; } - tty_unlock(); + tty_unlock(tty); schedule(); - tty_lock(); + tty_lock(tty); } finish_wait(&port->open_wait, &wait); diff --git a/trunk/drivers/tty/vt/consolemap.c b/trunk/drivers/tty/vt/consolemap.c index 8308fc7cdc26..2aaa0c228409 100644 --- a/trunk/drivers/tty/vt/consolemap.c +++ b/trunk/drivers/tty/vt/consolemap.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -312,6 +313,7 @@ int con_set_trans_old(unsigned char __user * arg) if (!access_ok(VERIFY_READ, arg, E_TABSZ)) return -EFAULT; + console_lock(); for (i=0; ivc_uni_pagedir_loc; - if (p && p->readonly) return -EIO; + if (p && p->readonly) + return -EIO; + if (!p || --p->refcount) { q = kzalloc(sizeof(*p), GFP_KERNEL); if (!q) { - if (p) p->refcount++; + if (p) + p->refcount++; return -ENOMEM; } q->refcount=1; @@ -511,23 +525,43 @@ int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui) return 0; } +int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui) +{ + int ret; + console_lock(); + ret = con_do_clear_unimap(vc, ui); + console_unlock(); + return ret; +} + int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) { int err = 0, err1, i; struct uni_pagedir *p, *q; + console_lock(); + /* Save original vc_unipagdir_loc in case we allocate a new one */ p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; - if (p->readonly) return -EIO; + if (p->readonly) { + console_unlock(); + return -EIO; + } - if (!ct) return 0; + if (!ct) { + console_unlock(); + return 0; + } if (p->refcount > 1) { int j, k; u16 **p1, *p2, l; - err1 = con_clear_unimap(vc, NULL); - if (err1) return err1; + err1 = con_do_clear_unimap(vc, NULL); + if (err1) { + console_unlock(); + return err1; + } /* * Since refcount was > 1, con_clear_unimap() allocated a @@ -558,7 +592,8 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) *vc->vc_uni_pagedir_loc = (unsigned long)p; con_release_unimap(q); kfree(q); - return err1; + console_unlock(); + return err1; } } } else { @@ -592,21 +627,30 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) /* * Merge with fontmaps of any other virtual consoles. */ - if (con_unify_unimap(vc, p)) + if (con_unify_unimap(vc, p)) { + console_unlock(); return err; + } for (i = 0; i <= 3; i++) set_inverse_transl(vc, p, i); /* Update inverse translations */ set_inverse_trans_unicode(vc, p); - + + console_unlock(); return err; } -/* Loads the unimap for the hardware font, as defined in uni_hash.tbl. - The representation used was the most compact I could come up - with. This routine is executed at sys_setup time, and when the - PIO_FONTRESET ioctl is called. */ - +/** + * con_set_default_unimap - set default unicode map + * @vc: the console we are updating + * + * Loads the unimap for the hardware font, as defined in uni_hash.tbl. + * The representation used was the most compact I could come up + * with. This routine is executed at video setup, and when the + * PIO_FONTRESET ioctl is called. + * + * The caller must hold the console lock + */ int con_set_default_unimap(struct vc_data *vc) { int i, j, err = 0, err1; @@ -617,6 +661,7 @@ int con_set_default_unimap(struct vc_data *vc) p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; if (p == dflt) return 0; + dflt->refcount++; *vc->vc_uni_pagedir_loc = (unsigned long)dflt; if (p && !--p->refcount) { @@ -628,8 +673,9 @@ int con_set_default_unimap(struct vc_data *vc) /* The default font is always 256 characters */ - err = con_clear_unimap(vc, NULL); - if (err) return err; + err = con_do_clear_unimap(vc, NULL); + if (err) + return err; p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; q = dfont_unitable; @@ -654,6 +700,13 @@ int con_set_default_unimap(struct vc_data *vc) } EXPORT_SYMBOL(con_set_default_unimap); +/** + * con_copy_unimap - copy unimap between two vts + * @dst_vc: target + * @src_vt: source + * + * The caller must hold the console lock when invoking this method + */ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc) { struct uni_pagedir *q; @@ -668,13 +721,23 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc) *dst_vc->vc_uni_pagedir_loc = (long)q; return 0; } +EXPORT_SYMBOL(con_copy_unimap); +/** + * con_get_unimap - get the unicode map + * @vc: the console to read from + * + * Read the console unicode data for this console. Called from the ioctl + * handlers. + */ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list) { int i, j, k, ect; u16 **p1, *p2; struct uni_pagedir *p; + console_lock(); + ect = 0; if (*vc->vc_uni_pagedir_loc) { p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; @@ -694,22 +757,19 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni } } __put_user(ect, uct); + console_unlock(); return ((ect <= ct) ? 0 : -ENOMEM); } -void con_protect_unimap(struct vc_data *vc, int rdonly) -{ - struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; - - if (p) - p->readonly = rdonly; -} - /* * Always use USER_MAP. These functions are used by the keyboard, * which shouldn't be affected by G0/G1 switching, etc. * If the user map still contains default values, i.e. the * direct-to-font mapping, then assume user is using Latin1. + * + * FIXME: at some point we need to decide if we want to lock the table + * update element itself via the keyboard_event_lock for consistency with the + * keyboard driver as well as the consoles */ /* may be called during an interrupt */ u32 conv_8bit_to_uni(unsigned char c) @@ -777,4 +837,3 @@ console_map_init(void) con_set_default_unimap(vc_cons[i].d); } -EXPORT_SYMBOL(con_copy_unimap); diff --git a/trunk/drivers/tty/vt/vt.c b/trunk/drivers/tty/vt/vt.c index 2156188db4a6..84cbf298c094 100644 --- a/trunk/drivers/tty/vt/vt.c +++ b/trunk/drivers/tty/vt/vt.c @@ -3892,36 +3892,6 @@ static void set_palette(struct vc_data *vc) vc->vc_sw->con_set_palette(vc, color_table); } -static int set_get_cmap(unsigned char __user *arg, int set) -{ - int i, j, k; - - WARN_CONSOLE_UNLOCKED(); - - for (i = 0; i < 16; i++) - if (set) { - get_user(default_red[i], arg++); - get_user(default_grn[i], arg++); - get_user(default_blu[i], arg++); - } else { - put_user(default_red[i], arg++); - put_user(default_grn[i], arg++); - put_user(default_blu[i], arg++); - } - if (set) { - for (i = 0; i < MAX_NR_CONSOLES; i++) - if (vc_cons_allocated(i)) { - for (j = k = 0; j < 16; j++) { - vc_cons[i].d->vc_palette[k++] = default_red[j]; - vc_cons[i].d->vc_palette[k++] = default_grn[j]; - vc_cons[i].d->vc_palette[k++] = default_blu[j]; - } - set_palette(vc_cons[i].d); - } - } - return 0; -} - /* * Load palette into the DAC registers. arg points to a colour * map, 3 bytes per colour, 16 colours, range from 0 to 255. @@ -3929,24 +3899,50 @@ static int set_get_cmap(unsigned char __user *arg, int set) int con_set_cmap(unsigned char __user *arg) { - int rc; + int i, j, k; + unsigned char colormap[3*16]; + + if (copy_from_user(colormap, arg, sizeof(colormap))) + return -EFAULT; console_lock(); - rc = set_get_cmap (arg,1); + for (i = k = 0; i < 16; i++) { + default_red[i] = colormap[k++]; + default_grn[i] = colormap[k++]; + default_blu[i] = colormap[k++]; + } + for (i = 0; i < MAX_NR_CONSOLES; i++) { + if (!vc_cons_allocated(i)) + continue; + for (j = k = 0; j < 16; j++) { + vc_cons[i].d->vc_palette[k++] = default_red[j]; + vc_cons[i].d->vc_palette[k++] = default_grn[j]; + vc_cons[i].d->vc_palette[k++] = default_blu[j]; + } + set_palette(vc_cons[i].d); + } console_unlock(); - return rc; + return 0; } int con_get_cmap(unsigned char __user *arg) { - int rc; + int i, k; + unsigned char colormap[3*16]; console_lock(); - rc = set_get_cmap (arg,0); + for (i = k = 0; i < 16; i++) { + colormap[k++] = default_red[i]; + colormap[k++] = default_grn[i]; + colormap[k++] = default_blu[i]; + } console_unlock(); - return rc; + if (copy_to_user(arg, colormap, sizeof(colormap))) + return -EFAULT; + + return 0; } void reset_palette(struct vc_data *vc) diff --git a/trunk/drivers/tty/vt/vt_ioctl.c b/trunk/drivers/tty/vt/vt_ioctl.c index ede2ef18d2fb..64618547be11 100644 --- a/trunk/drivers/tty/vt/vt_ioctl.c +++ b/trunk/drivers/tty/vt/vt_ioctl.c @@ -910,7 +910,9 @@ int vt_ioctl(struct tty_struct *tty, ret = con_font_op(vc_cons[fg_console].d, &op); if (ret) break; + console_lock(); con_set_default_unimap(vc_cons[fg_console].d); + console_unlock(); break; } #endif @@ -934,33 +936,23 @@ int vt_ioctl(struct tty_struct *tty, case PIO_SCRNMAP: if (!perm) ret = -EPERM; - else { - tty_lock(); + else ret = con_set_trans_old(up); - tty_unlock(); - } break; case GIO_SCRNMAP: - tty_lock(); ret = con_get_trans_old(up); - tty_unlock(); break; case PIO_UNISCRNMAP: if (!perm) ret = -EPERM; - else { - tty_lock(); + else ret = con_set_trans_new(up); - tty_unlock(); - } break; case GIO_UNISCRNMAP: - tty_lock(); ret = con_get_trans_new(up); - tty_unlock(); break; case PIO_UNIMAPCLR: @@ -970,19 +962,14 @@ int vt_ioctl(struct tty_struct *tty, ret = copy_from_user(&ui, up, sizeof(struct unimapinit)); if (ret) ret = -EFAULT; - else { - tty_lock(); + else con_clear_unimap(vc, &ui); - tty_unlock(); - } break; } case PIO_UNIMAP: case GIO_UNIMAP: - tty_lock(); ret = do_unimap_ioctl(cmd, up, perm, vc); - tty_unlock(); break; case VT_LOCKSWITCH: @@ -1196,9 +1183,7 @@ long vt_compat_ioctl(struct tty_struct *tty, case PIO_UNIMAP: case GIO_UNIMAP: - tty_lock(); ret = compat_unimap_ioctl(cmd, up, perm, vc); - tty_unlock(); break; /* diff --git a/trunk/drivers/uio/uio_pdrv_genirq.c b/trunk/drivers/uio/uio_pdrv_genirq.c index b98371d93a92..42202cd83158 100644 --- a/trunk/drivers/uio/uio_pdrv_genirq.c +++ b/trunk/drivers/uio/uio_pdrv_genirq.c @@ -146,6 +146,14 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev) priv->flags = 0; /* interrupt is enabled to begin with */ priv->pdev = pdev; + if (!uioinfo->irq) { + ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(&pdev->dev, "failed to get IRQ\n"); + goto bad0; + } + uioinfo->irq = ret; + } uiomem = &uioinfo->mem[0]; for (i = 0; i < pdev->num_resources; ++i) { diff --git a/trunk/drivers/usb/Kconfig b/trunk/drivers/usb/Kconfig index 76316a33061b..a7773a3e02b1 100644 --- a/trunk/drivers/usb/Kconfig +++ b/trunk/drivers/usb/Kconfig @@ -133,6 +133,8 @@ source "drivers/usb/host/Kconfig" source "drivers/usb/musb/Kconfig" +source "drivers/usb/chipidea/Kconfig" + source "drivers/usb/renesas_usbhs/Kconfig" source "drivers/usb/class/Kconfig" @@ -177,6 +179,8 @@ source "drivers/usb/serial/Kconfig" source "drivers/usb/misc/Kconfig" +source "drivers/usb/phy/Kconfig" + source "drivers/usb/atm/Kconfig" source "drivers/usb/gadget/Kconfig" diff --git a/trunk/drivers/usb/Makefile b/trunk/drivers/usb/Makefile index 53a7bc07dd8d..c691eea51537 100644 --- a/trunk/drivers/usb/Makefile +++ b/trunk/drivers/usb/Makefile @@ -46,12 +46,14 @@ obj-$(CONFIG_USB_MICROTEK) += image/ obj-$(CONFIG_USB_SERIAL) += serial/ obj-$(CONFIG_USB) += misc/ +obj-$(CONFIG_USB) += phy/ obj-$(CONFIG_EARLY_PRINTK_DBGP) += early/ obj-$(CONFIG_USB_ATM) += atm/ obj-$(CONFIG_USB_SPEEDTOUCH) += atm/ obj-$(CONFIG_USB_MUSB_HDRC) += musb/ +obj-$(CONFIG_USB_CHIPIDEA) += chipidea/ obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs/ obj-$(CONFIG_USB_GADGET) += gadget/ diff --git a/trunk/drivers/usb/atm/cxacru.c b/trunk/drivers/usb/atm/cxacru.c index 98b89fe19867..b7eb86ad6bf2 100644 --- a/trunk/drivers/usb/atm/cxacru.c +++ b/trunk/drivers/usb/atm/cxacru.c @@ -674,7 +674,7 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, } ret = offd; - dbg("cm %#x", cm); + usb_dbg(instance->usbatm, "cm %#x\n", cm); fail: mutex_unlock(&instance->cm_serialize); err: @@ -733,7 +733,7 @@ static int cxacru_card_status(struct cxacru_data *instance) { int ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_STATUS, NULL, 0, NULL, 0); if (ret < 0) { /* firmware not loaded */ - dbg("cxacru_adsl_start: CARD_GET_STATUS returned %d", ret); + usb_dbg(instance->usbatm, "cxacru_adsl_start: CARD_GET_STATUS returned %d\n", ret); return ret; } return 0; @@ -758,7 +758,7 @@ static int cxacru_atm_start(struct usbatm_data *usbatm_instance, int ret; int start_polling = 1; - dbg("cxacru_atm_start"); + dev_dbg(&intf->dev, "%s\n", __func__); /* Read MAC address */ ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_MAC_ADDRESS, NULL, 0, @@ -962,13 +962,13 @@ static int cxacru_fw(struct usb_device *usb_dev, enum cxacru_fw_request fw, ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_CMD), buf, offb, NULL, CMD_TIMEOUT); if (ret < 0) { - dbg("sending fw %#x failed", fw); + dev_dbg(&usb_dev->dev, "sending fw %#x failed\n", fw); goto cleanup; } offb = 0; } } while (offd < size); - dbg("sent fw %#x", fw); + dev_dbg(&usb_dev->dev, "sent fw %#x\n", fw); ret = 0; @@ -988,7 +988,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance, usb_dev->descriptor.idProduct }; __le32 val; - dbg("cxacru_upload_firmware"); + usb_dbg(usbatm, "%s\n", __func__); /* FirmwarePllFClkValue */ val = cpu_to_le32(instance->modem_type->pll_f_clk); @@ -1074,7 +1074,7 @@ static int cxacru_find_firmware(struct cxacru_data *instance, char buf[16]; sprintf(buf, "cxacru-%s.bin", phase); - dbg("cxacru_find_firmware: looking for %s", buf); + usb_dbg(usbatm, "cxacru_find_firmware: looking for %s\n", buf); if (request_firmware(fw_p, buf, dev)) { usb_dbg(usbatm, "no stage %s firmware found\n", phase); @@ -1115,9 +1115,9 @@ static int cxacru_heavy_init(struct usbatm_data *usbatm_instance, ret = cxacru_card_status(instance); if (ret) - dbg("modem initialisation failed"); + usb_dbg(usbatm_instance, "modem initialisation failed\n"); else - dbg("done setting up the modem"); + usb_dbg(usbatm_instance, "done setting up the modem\n"); return ret; } @@ -1133,7 +1133,7 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance, /* instance init */ instance = kzalloc(sizeof(*instance), GFP_KERNEL); if (!instance) { - dbg("cxacru_bind: no memory for instance data"); + usb_dbg(usbatm_instance, "cxacru_bind: no memory for instance data\n"); return -ENOMEM; } @@ -1149,31 +1149,31 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance, instance->rcv_buf = (u8 *) __get_free_page(GFP_KERNEL); if (!instance->rcv_buf) { - dbg("cxacru_bind: no memory for rcv_buf"); + usb_dbg(usbatm_instance, "cxacru_bind: no memory for rcv_buf\n"); ret = -ENOMEM; goto fail; } instance->snd_buf = (u8 *) __get_free_page(GFP_KERNEL); if (!instance->snd_buf) { - dbg("cxacru_bind: no memory for snd_buf"); + usb_dbg(usbatm_instance, "cxacru_bind: no memory for snd_buf\n"); ret = -ENOMEM; goto fail; } instance->rcv_urb = usb_alloc_urb(0, GFP_KERNEL); if (!instance->rcv_urb) { - dbg("cxacru_bind: no memory for rcv_urb"); + usb_dbg(usbatm_instance, "cxacru_bind: no memory for rcv_urb\n"); ret = -ENOMEM; goto fail; } instance->snd_urb = usb_alloc_urb(0, GFP_KERNEL); if (!instance->snd_urb) { - dbg("cxacru_bind: no memory for snd_urb"); + usb_dbg(usbatm_instance, "cxacru_bind: no memory for snd_urb\n"); ret = -ENOMEM; goto fail; } if (!cmd_ep) { - dbg("cxacru_bind: no command endpoint"); + usb_dbg(usbatm_instance, "cxacru_bind: no command endpoint\n"); ret = -ENODEV; goto fail; } @@ -1227,10 +1227,10 @@ static void cxacru_unbind(struct usbatm_data *usbatm_instance, struct cxacru_data *instance = usbatm_instance->driver_data; int is_polling = 1; - dbg("cxacru_unbind entered"); + usb_dbg(usbatm_instance, "cxacru_unbind entered\n"); if (!instance) { - dbg("cxacru_unbind: NULL instance!"); + usb_dbg(usbatm_instance, "cxacru_unbind: NULL instance!\n"); return; } diff --git a/trunk/drivers/usb/atm/speedtch.c b/trunk/drivers/usb/atm/speedtch.c index 98dd9e49b684..975e9c6691d6 100644 --- a/trunk/drivers/usb/atm/speedtch.c +++ b/trunk/drivers/usb/atm/speedtch.c @@ -170,7 +170,7 @@ static void speedtch_set_swbuff(struct speedtch_instance_data *instance, int sta "%sabling SW buffering: usb_control_msg returned %d\n", state ? "En" : "Dis", ret); else - dbg("speedtch_set_swbuff: %sbled SW buffering", state ? "En" : "Dis"); + usb_dbg(usbatm, "speedtch_set_swbuff: %sbled SW buffering\n", state ? "En" : "Dis"); } static void speedtch_test_sequence(struct speedtch_instance_data *instance) diff --git a/trunk/drivers/usb/atm/ueagle-atm.c b/trunk/drivers/usb/atm/ueagle-atm.c index 01ea5d7421d4..d7e422dc0ef7 100644 --- a/trunk/drivers/usb/atm/ueagle-atm.c +++ b/trunk/drivers/usb/atm/ueagle-atm.c @@ -1357,10 +1357,8 @@ static int uea_stat_e1(struct uea_softc *sc) /* release the dsp firmware as it is not needed until * the next failure */ - if (sc->dsp_firm) { - release_firmware(sc->dsp_firm); - sc->dsp_firm = NULL; - } + release_firmware(sc->dsp_firm); + sc->dsp_firm = NULL; } /* always update it as atm layer could not be init when we switch to @@ -1496,10 +1494,8 @@ static int uea_stat_e4(struct uea_softc *sc) /* release the dsp firmware as it is not needed until * the next failure */ - if (sc->dsp_firm) { - release_firmware(sc->dsp_firm); - sc->dsp_firm = NULL; - } + release_firmware(sc->dsp_firm); + sc->dsp_firm = NULL; } /* always update it as atm layer could not be init when we switch to @@ -2240,8 +2236,7 @@ static void uea_stop(struct uea_softc *sc) /* flush the work item, when no one can schedule it */ flush_work_sync(&sc->task); - if (sc->dsp_firm) - release_firmware(sc->dsp_firm); + release_firmware(sc->dsp_firm); uea_leaves(INS_TO_USBDEV(sc)); } diff --git a/trunk/drivers/usb/atm/usbatm.c b/trunk/drivers/usb/atm/usbatm.c index d3448ca110ce..ee62b3576f94 100644 --- a/trunk/drivers/usb/atm/usbatm.c +++ b/trunk/drivers/usb/atm/usbatm.c @@ -86,7 +86,7 @@ #ifdef VERBOSE_DEBUG static int usbatm_print_packet(const unsigned char *data, int len); #define PACKETDEBUG(arg...) usbatm_print_packet(arg) -#define vdbg(arg...) dbg(arg) +#define vdbg(arg...) dev_dbg(arg) #else #define PACKETDEBUG(arg...) #define vdbg(arg...) @@ -714,7 +714,7 @@ static void usbatm_destroy_instance(struct kref *kref) { struct usbatm_data *instance = container_of(kref, struct usbatm_data, refcount); - dbg("%s", __func__); + usb_dbg(instance, "%s\n", __func__); tasklet_kill(&instance->rx_channel.tasklet); tasklet_kill(&instance->tx_channel.tasklet); @@ -724,14 +724,14 @@ static void usbatm_destroy_instance(struct kref *kref) static void usbatm_get_instance(struct usbatm_data *instance) { - dbg("%s", __func__); + usb_dbg(instance, "%s\n", __func__); kref_get(&instance->refcount); } static void usbatm_put_instance(struct usbatm_data *instance) { - dbg("%s", __func__); + usb_dbg(instance, "%s\n", __func__); kref_put(&instance->refcount, usbatm_destroy_instance); } @@ -745,11 +745,10 @@ static void usbatm_atm_dev_close(struct atm_dev *atm_dev) { struct usbatm_data *instance = atm_dev->dev_data; - dbg("%s", __func__); - if (!instance) return; + usb_dbg(instance, "%s\n", __func__); atm_dev->dev_data = NULL; /* catch bugs */ usbatm_put_instance(instance); /* taken in usbatm_atm_init */ } @@ -759,10 +758,8 @@ static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *pag struct usbatm_data *instance = atm_dev->dev_data; int left = *pos; - if (!instance) { - dbg("%s: NULL instance!", __func__); + if (!instance) return -ENODEV; - } if (!left--) return sprintf(page, "%s\n", instance->description); @@ -804,10 +801,8 @@ static int usbatm_atm_open(struct atm_vcc *vcc) int vci = vcc->vci; short vpi = vcc->vpi; - if (!instance) { - dbg("%s: NULL data!", __func__); + if (!instance) return -ENODEV; - } atm_dbg(instance, "%s: vpi %hd, vci %d\n", __func__, vpi, vci); @@ -884,10 +879,8 @@ static void usbatm_atm_close(struct atm_vcc *vcc) struct usbatm_data *instance = vcc->dev->dev_data; struct usbatm_vcc_data *vcc_data = vcc->dev_data; - if (!instance || !vcc_data) { - dbg("%s: NULL data!", __func__); + if (!instance || !vcc_data) return; - } atm_dbg(instance, "%s entered\n", __func__); @@ -929,10 +922,8 @@ static int usbatm_atm_ioctl(struct atm_dev *atm_dev, unsigned int cmd, { struct usbatm_data *instance = atm_dev->dev_data; - if (!instance || instance->disconnected) { - dbg("%s: %s!", __func__, instance ? "disconnected" : "NULL instance"); + if (!instance || instance->disconnected) return -ENODEV; - } switch (cmd) { case ATM_QUERYLOOP: @@ -1336,8 +1327,6 @@ EXPORT_SYMBOL_GPL(usbatm_usb_disconnect); static int __init usbatm_usb_init(void) { - dbg("%s: driver version %s", __func__, DRIVER_VERSION); - if (sizeof(struct usbatm_control) > FIELD_SIZEOF(struct sk_buff, cb)) { printk(KERN_ERR "%s unusable with this kernel!\n", usbatm_driver_name); return -EIO; @@ -1357,7 +1346,6 @@ module_init(usbatm_usb_init); static void __exit usbatm_usb_exit(void) { - dbg("%s", __func__); } module_exit(usbatm_usb_exit); diff --git a/trunk/drivers/usb/atm/xusbatm.c b/trunk/drivers/usb/atm/xusbatm.c index 48ee0c5ff282..14ec9f0c5924 100644 --- a/trunk/drivers/usb/atm/xusbatm.c +++ b/trunk/drivers/usb/atm/xusbatm.c @@ -187,8 +187,6 @@ static int __init xusbatm_init(void) { int i; - dbg("xusbatm_init"); - if (!num_vendor || num_vendor != num_product || num_vendor != num_rx_endpoint || @@ -221,8 +219,6 @@ module_init(xusbatm_init); static void __exit xusbatm_exit(void) { - dbg("xusbatm_exit entered"); - usb_deregister(&xusbatm_usb_driver); } module_exit(xusbatm_exit); diff --git a/trunk/drivers/usb/chipidea/Kconfig b/trunk/drivers/usb/chipidea/Kconfig new file mode 100644 index 000000000000..fd36dc8b889b --- /dev/null +++ b/trunk/drivers/usb/chipidea/Kconfig @@ -0,0 +1,32 @@ +config USB_CHIPIDEA + tristate "ChipIdea Highspeed Dual Role Controller" + depends on USB + help + Say Y here if your system has a dual role high speed USB + controller based on ChipIdea silicon IP. Currently, only the + peripheral mode is supported. + + When compiled dynamically, the module will be called ci-hdrc.ko. + +if USB_CHIPIDEA + +config USB_CHIPIDEA_UDC + bool "ChipIdea device controller" + depends on USB_GADGET + select USB_GADGET_DUALSPEED + help + Say Y here to enable device controller functionality of the + ChipIdea driver. + +config USB_CHIPIDEA_HOST + bool "ChipIdea host controller" + help + Say Y here to enable host controller functionality of the + ChipIdea driver. + +config USB_CHIPIDEA_DEBUG + bool "ChipIdea driver debug" + help + Say Y here to enable debugging output of the ChipIdea driver. + +endif diff --git a/trunk/drivers/usb/chipidea/Makefile b/trunk/drivers/usb/chipidea/Makefile new file mode 100644 index 000000000000..cc3493769724 --- /dev/null +++ b/trunk/drivers/usb/chipidea/Makefile @@ -0,0 +1,14 @@ +obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc.o + +ci_hdrc-y := core.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 + +ifneq ($(CONFIG_PCI),) + obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_pci.o +endif + +ifneq ($(CONFIG_ARCH_MSM),) + obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_msm.o +endif diff --git a/trunk/drivers/usb/chipidea/bits.h b/trunk/drivers/usb/chipidea/bits.h new file mode 100644 index 000000000000..050de8562a04 --- /dev/null +++ b/trunk/drivers/usb/chipidea/bits.h @@ -0,0 +1,90 @@ +/* + * bits.h - register bits of the ChipIdea USB IP core + * + * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. + * + * Author: David Lopo + * + * 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_BITS_H +#define __DRIVERS_USB_CHIPIDEA_BITS_H + +#include + +/* HCCPARAMS */ +#define HCCPARAMS_LEN BIT(17) + +/* DCCPARAMS */ +#define DCCPARAMS_DEN (0x1F << 0) +#define DCCPARAMS_DC BIT(7) +#define DCCPARAMS_HC BIT(8) + +/* TESTMODE */ +#define TESTMODE_FORCE BIT(0) + +/* USBCMD */ +#define USBCMD_RS BIT(0) +#define USBCMD_RST BIT(1) +#define USBCMD_SUTW BIT(13) +#define USBCMD_ATDTW BIT(14) + +/* USBSTS & USBINTR */ +#define USBi_UI BIT(0) +#define USBi_UEI BIT(1) +#define USBi_PCI BIT(2) +#define USBi_URI BIT(6) +#define USBi_SLI BIT(8) + +/* DEVICEADDR */ +#define DEVICEADDR_USBADRA BIT(24) +#define DEVICEADDR_USBADR (0x7FUL << 25) + +/* PORTSC */ +#define PORTSC_FPR BIT(6) +#define PORTSC_SUSP BIT(7) +#define PORTSC_HSP BIT(9) +#define PORTSC_PTC (0x0FUL << 16) + +/* DEVLC */ +#define DEVLC_PSPD (0x03UL << 25) +#define DEVLC_PSPD_HS (0x02UL << 25) + +/* OTGSC */ +#define OTGSC_IDPU BIT(5) +#define OTGSC_ID BIT(8) +#define OTGSC_AVV BIT(9) +#define OTGSC_ASV BIT(10) +#define OTGSC_BSV BIT(11) +#define OTGSC_BSE BIT(12) +#define OTGSC_IDIS BIT(16) +#define OTGSC_AVVIS BIT(17) +#define OTGSC_ASVIS BIT(18) +#define OTGSC_BSVIS BIT(19) +#define OTGSC_BSEIS BIT(20) +#define OTGSC_IDIE BIT(24) +#define OTGSC_AVVIE BIT(25) +#define OTGSC_ASVIE BIT(26) +#define OTGSC_BSVIE BIT(27) +#define OTGSC_BSEIE BIT(28) + +/* USBMODE */ +#define USBMODE_CM (0x03UL << 0) +#define USBMODE_CM_DC (0x02UL << 0) +#define USBMODE_SLOM BIT(3) +#define USBMODE_CI_SDIS BIT(4) + +/* ENDPTCTRL */ +#define ENDPTCTRL_RXS BIT(0) +#define ENDPTCTRL_RXT (0x03UL << 2) +#define ENDPTCTRL_RXR BIT(6) /* reserved for port 0 */ +#define ENDPTCTRL_RXE BIT(7) +#define ENDPTCTRL_TXS BIT(16) +#define ENDPTCTRL_TXT (0x03UL << 18) +#define ENDPTCTRL_TXR BIT(22) /* reserved for port 0 */ +#define ENDPTCTRL_TXE BIT(23) + +#endif /* __DRIVERS_USB_CHIPIDEA_BITS_H */ diff --git a/trunk/drivers/usb/chipidea/ci.h b/trunk/drivers/usb/chipidea/ci.h new file mode 100644 index 000000000000..50911f8490d4 --- /dev/null +++ b/trunk/drivers/usb/chipidea/ci.h @@ -0,0 +1,313 @@ +/* + * ci.h - common structures, functions, and macros of the ChipIdea driver + * + * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. + * + * Author: David Lopo + * + * 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_CI_H +#define __DRIVERS_USB_CHIPIDEA_CI_H + +#include +#include +#include +#include + +/****************************************************************************** + * DEFINE + *****************************************************************************/ +#define CI13XXX_PAGE_SIZE 4096ul /* page size for TD's */ +#define ENDPT_MAX 32 + +/****************************************************************************** + * STRUCTURES + *****************************************************************************/ +/** + * struct ci13xxx_ep - endpoint representation + * @ep: endpoint structure for gadget drivers + * @dir: endpoint direction (TX/RX) + * @num: endpoint number + * @type: endpoint type + * @name: string description of the endpoint + * @qh: queue head for this endpoint + * @wedge: is the endpoint wedged + * @udc: pointer to the controller + * @lock: pointer to controller's spinlock + * @td_pool: pointer to controller's TD pool + */ +struct ci13xxx_ep { + struct usb_ep ep; + u8 dir; + u8 num; + u8 type; + char name[16]; + struct { + struct list_head queue; + struct ci13xxx_qh *ptr; + dma_addr_t dma; + } qh; + int wedge; + + /* global resources */ + struct ci13xxx *udc; + spinlock_t *lock; + struct dma_pool *td_pool; +}; + +enum ci_role { + CI_ROLE_HOST = 0, + CI_ROLE_GADGET, + CI_ROLE_END, +}; + +/** + * struct ci_role_driver - host/gadget role driver + * start: start this role + * stop: stop this role + * irq: irq handler for this role + * name: role name string (host/gadget) + */ +struct ci_role_driver { + int (*start)(struct ci13xxx *); + void (*stop)(struct ci13xxx *); + irqreturn_t (*irq)(struct ci13xxx *); + const char *name; +}; + +/** + * struct hw_bank - hardware register mapping representation + * @lpm: set if the device is LPM capable + * @phys: physical address of the controller's registers + * @abs: absolute address of the beginning of register window + * @cap: capability registers + * @op: operational registers + * @size: size of the register window + * @regmap: register lookup table + */ +struct hw_bank { + unsigned lpm; + resource_size_t phys; + void __iomem *abs; + void __iomem *cap; + void __iomem *op; + size_t size; + void __iomem **regmap; +}; + +/** + * struct ci13xxx - chipidea device representation + * @dev: pointer to parent device + * @lock: access synchronization + * @hw_bank: hardware register mapping + * @irq: IRQ number + * @roles: array of supported roles for this controller + * @role: current role + * @is_otg: if the device is otg-capable + * @work: work for role changing + * @wq: workqueue thread + * @qh_pool: allocation pool for queue heads + * @td_pool: allocation pool for transfer descriptors + * @gadget: device side representation for peripheral controller + * @driver: gadget driver + * @hw_ep_max: total number of endpoints supported by hardware + * @ci13xxx_ep: array of endpoints + * @ep0_dir: ep0 direction + * @ep0out: pointer to ep0 OUT endpoint + * @ep0in: pointer to ep0 IN endpoint + * @status: ep0 status request + * @setaddr: if we should set the address on status completion + * @address: usb address received from the host + * @remote_wakeup: host-enabled remote wakeup + * @suspended: suspended by host + * @test_mode: the selected test mode + * @udc_driver: platform specific information supplied by parent device + * @vbus_active: is VBUS active + * @transceiver: pointer to USB PHY, if any + * @hcd: pointer to usb_hcd for ehci host driver + */ +struct ci13xxx { + struct device *dev; + spinlock_t lock; + struct hw_bank hw_bank; + int irq; + struct ci_role_driver *roles[CI_ROLE_END]; + enum ci_role role; + bool is_otg; + struct work_struct work; + struct workqueue_struct *wq; + + struct dma_pool *qh_pool; + struct dma_pool *td_pool; + + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + unsigned hw_ep_max; + struct ci13xxx_ep ci13xxx_ep[ENDPT_MAX]; + u32 ep0_dir; + struct ci13xxx_ep *ep0out, *ep0in; + + struct usb_request *status; + bool setaddr; + u8 address; + u8 remote_wakeup; + u8 suspended; + u8 test_mode; + + struct ci13xxx_udc_driver *udc_driver; + int vbus_active; + struct usb_phy *transceiver; + struct usb_hcd *hcd; +}; + +static inline struct ci_role_driver *ci_role(struct ci13xxx *ci) +{ + BUG_ON(ci->role >= CI_ROLE_END || !ci->roles[ci->role]); + return ci->roles[ci->role]; +} + +static inline int ci_role_start(struct ci13xxx *ci, enum ci_role role) +{ + int ret; + + if (role >= CI_ROLE_END) + return -EINVAL; + + if (!ci->roles[role]) + return -ENXIO; + + ret = ci->roles[role]->start(ci); + if (!ret) + ci->role = role; + return ret; +} + +static inline void ci_role_stop(struct ci13xxx *ci) +{ + enum ci_role role = ci->role; + + if (role == CI_ROLE_END) + return; + + ci->role = CI_ROLE_END; + + ci->roles[role]->stop(ci); +} + +/****************************************************************************** + * REGISTERS + *****************************************************************************/ +/* register size */ +#define REG_BITS (32) + +/* register indices */ +enum ci13xxx_regs { + CAP_CAPLENGTH, + CAP_HCCPARAMS, + CAP_DCCPARAMS, + CAP_TESTMODE, + CAP_LAST = CAP_TESTMODE, + OP_USBCMD, + OP_USBSTS, + OP_USBINTR, + OP_DEVICEADDR, + OP_ENDPTLISTADDR, + OP_PORTSC, + OP_DEVLC, + OP_OTGSC, + OP_USBMODE, + OP_ENDPTSETUPSTAT, + OP_ENDPTPRIME, + OP_ENDPTFLUSH, + OP_ENDPTSTAT, + OP_ENDPTCOMPLETE, + OP_ENDPTCTRL, + /* endptctrl1..15 follow */ + OP_LAST = OP_ENDPTCTRL + ENDPT_MAX / 2, +}; + +/** + * ffs_nr: find first (least significant) bit set + * @x: the word to search + * + * This function returns bit number (instead of position) + */ +static inline int ffs_nr(u32 x) +{ + int n = ffs(x); + + return n ? n-1 : 32; +} + +/** + * hw_read: reads from a hw register + * @reg: register index + * @mask: bitfield mask + * + * This function returns register contents + */ +static inline u32 hw_read(struct ci13xxx *udc, enum ci13xxx_regs reg, u32 mask) +{ + return ioread32(udc->hw_bank.regmap[reg]) & mask; +} + +/** + * hw_write: writes to a hw register + * @reg: register index + * @mask: bitfield mask + * @data: new value + */ +static inline void hw_write(struct ci13xxx *udc, enum ci13xxx_regs reg, + u32 mask, u32 data) +{ + if (~mask) + data = (ioread32(udc->hw_bank.regmap[reg]) & ~mask) + | (data & mask); + + iowrite32(data, udc->hw_bank.regmap[reg]); +} + +/** + * hw_test_and_clear: tests & clears a hw register + * @reg: register index + * @mask: bitfield mask + * + * This function returns register contents + */ +static inline u32 hw_test_and_clear(struct ci13xxx *udc, enum ci13xxx_regs reg, + u32 mask) +{ + u32 val = ioread32(udc->hw_bank.regmap[reg]) & mask; + + iowrite32(val, udc->hw_bank.regmap[reg]); + return val; +} + +/** + * hw_test_and_write: tests & writes a hw register + * @reg: register index + * @mask: bitfield mask + * @data: new value + * + * This function returns register contents + */ +static inline u32 hw_test_and_write(struct ci13xxx *udc, enum ci13xxx_regs reg, + u32 mask, u32 data) +{ + u32 val = hw_read(udc, reg, ~0); + + hw_write(udc, reg, mask, data); + return (val & mask) >> ffs_nr(mask); +} + +int hw_device_reset(struct ci13xxx *ci, u32 mode); + +int hw_port_test_set(struct ci13xxx *ci, u8 mode); + +u8 hw_port_test_get(struct ci13xxx *ci); + +#endif /* __DRIVERS_USB_CHIPIDEA_CI_H */ diff --git a/trunk/drivers/usb/chipidea/ci13xxx_msm.c b/trunk/drivers/usb/chipidea/ci13xxx_msm.c new file mode 100644 index 000000000000..958069ef95e3 --- /dev/null +++ b/trunk/drivers/usb/chipidea/ci13xxx_msm.c @@ -0,0 +1,110 @@ +/* Copyright (c) 2010, Code Aurora Forum. 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "ci.h" + +#define MSM_USB_BASE (udc->hw_bank.abs) + +static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event) +{ + struct device *dev = udc->gadget.dev.parent; + int val; + + switch (event) { + case CI13XXX_CONTROLLER_RESET_EVENT: + dev_dbg(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n"); + writel(0, USB_AHBBURST); + writel(0, USB_AHBMODE); + break; + case CI13XXX_CONTROLLER_STOPPED_EVENT: + dev_dbg(dev, "CI13XXX_CONTROLLER_STOPPED_EVENT received\n"); + /* + * Put the transceiver in non-driving mode. Otherwise host + * may not detect soft-disconnection. + */ + val = usb_phy_io_read(udc->transceiver, ULPI_FUNC_CTRL); + val &= ~ULPI_FUNC_CTRL_OPMODE_MASK; + val |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING; + usb_phy_io_write(udc->transceiver, val, ULPI_FUNC_CTRL); + break; + default: + dev_dbg(dev, "unknown ci13xxx_udc event\n"); + break; + } +} + +static struct ci13xxx_udc_driver ci13xxx_msm_udc_driver = { + .name = "ci13xxx_msm", + .flags = CI13XXX_REGS_SHARED | + CI13XXX_REQUIRE_TRANSCEIVER | + CI13XXX_PULLUP_ON_VBUS | + CI13XXX_DISABLE_STREAMING, + + .notify_event = ci13xxx_msm_notify_event, +}; + +static int ci13xxx_msm_probe(struct platform_device *pdev) +{ + struct platform_device *plat_ci; + int ret; + + dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n"); + + plat_ci = platform_device_alloc("ci_hdrc", -1); + if (!plat_ci) { + dev_err(&pdev->dev, "can't allocate ci_hdrc platform device\n"); + return -ENOMEM; + } + + ret = platform_device_add_resources(plat_ci, pdev->resource, + pdev->num_resources); + if (ret) { + dev_err(&pdev->dev, "can't add resources to platform device\n"); + goto put_platform; + } + + ret = platform_device_add_data(plat_ci, &ci13xxx_msm_udc_driver, + sizeof(ci13xxx_msm_udc_driver)); + if (ret) + goto put_platform; + + ret = platform_device_add(plat_ci); + if (ret) + goto put_platform; + + pm_runtime_no_callbacks(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + return 0; + +put_platform: + platform_device_put(plat_ci); + + return ret; +} + +static struct platform_driver ci13xxx_msm_driver = { + .probe = ci13xxx_msm_probe, + .driver = { .name = "msm_hsusb", }, +}; +MODULE_ALIAS("platform:msm_hsusb"); + +static int __init ci13xxx_msm_init(void) +{ + return platform_driver_register(&ci13xxx_msm_driver); +} +module_init(ci13xxx_msm_init); + +MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/usb/chipidea/ci13xxx_pci.c b/trunk/drivers/usb/chipidea/ci13xxx_pci.c new file mode 100644 index 000000000000..e3dab27f5c75 --- /dev/null +++ b/trunk/drivers/usb/chipidea/ci13xxx_pci.c @@ -0,0 +1,180 @@ +/* + * ci13xxx_pci.c - MIPS USB IP core family device controller + * + * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. + * + * Author: David Lopo + * + * 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 + +/* driver name */ +#define UDC_DRIVER_NAME "ci13xxx_pci" + +/****************************************************************************** + * PCI block + *****************************************************************************/ +struct ci13xxx_udc_driver pci_driver = { + .name = UDC_DRIVER_NAME, + .capoffset = DEF_CAPOFFSET, +}; + +struct ci13xxx_udc_driver langwell_pci_driver = { + .name = UDC_DRIVER_NAME, + .capoffset = 0, +}; + +struct ci13xxx_udc_driver penwell_pci_driver = { + .name = UDC_DRIVER_NAME, + .capoffset = 0, + .power_budget = 200, +}; + +/** + * ci13xxx_pci_probe: PCI probe + * @pdev: USB device controller being probed + * @id: PCI hotplug ID connecting controller to UDC framework + * + * This function returns an error code + * Allocates basic PCI resources for this USB device controller, and then + * invokes the udc_probe() method to start the UDC associated with it + */ +static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct ci13xxx_udc_driver *driver = (void *)id->driver_data; + struct platform_device *plat_ci; + struct resource res[3]; + int retval = 0, nres = 2; + + if (!driver) { + dev_err(&pdev->dev, "device doesn't provide driver data\n"); + return -ENODEV; + } + + retval = pci_enable_device(pdev); + if (retval) + goto done; + + if (!pdev->irq) { + dev_err(&pdev->dev, "No IRQ, check BIOS/PCI setup!"); + retval = -ENODEV; + goto disable_device; + } + + pci_set_power_state(pdev, PCI_D0); + pci_set_master(pdev); + pci_try_set_mwi(pdev); + + plat_ci = platform_device_alloc("ci_hdrc", -1); + if (!plat_ci) { + dev_err(&pdev->dev, "can't allocate ci_hdrc platform device\n"); + retval = -ENOMEM; + goto disable_device; + } + + memset(res, 0, sizeof(res)); + res[0].start = pci_resource_start(pdev, 0); + res[0].end = pci_resource_end(pdev, 0); + res[0].flags = IORESOURCE_MEM; + res[1].start = pdev->irq; + res[1].flags = IORESOURCE_IRQ; + + retval = platform_device_add_resources(plat_ci, res, nres); + if (retval) { + dev_err(&pdev->dev, "can't add resources to platform device\n"); + goto put_platform; + } + + retval = platform_device_add_data(plat_ci, driver, sizeof(*driver)); + if (retval) + goto put_platform; + + dma_set_coherent_mask(&plat_ci->dev, pdev->dev.coherent_dma_mask); + plat_ci->dev.dma_mask = pdev->dev.dma_mask; + plat_ci->dev.dma_parms = pdev->dev.dma_parms; + plat_ci->dev.parent = &pdev->dev; + + pci_set_drvdata(pdev, plat_ci); + + retval = platform_device_add(plat_ci); + if (retval) + goto put_platform; + + return 0; + + put_platform: + pci_set_drvdata(pdev, NULL); + platform_device_put(plat_ci); + disable_device: + pci_disable_device(pdev); + done: + return retval; +} + +/** + * ci13xxx_pci_remove: PCI remove + * @pdev: USB Device Controller being removed + * + * Reverses the effect of ci13xxx_pci_probe(), + * first invoking the udc_remove() and then releases + * all PCI resources allocated for this USB device controller + */ +static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev) +{ + struct platform_device *plat_ci = pci_get_drvdata(pdev); + + platform_device_unregister(plat_ci); + pci_set_drvdata(pdev, NULL); + pci_disable_device(pdev); +} + +/** + * PCI device table + * PCI device structure + * + * Check "pci.h" for details + */ +static DEFINE_PCI_DEVICE_TABLE(ci13xxx_pci_id_table) = { + { + PCI_DEVICE(0x153F, 0x1004), + .driver_data = (kernel_ulong_t)&pci_driver, + }, + { + PCI_DEVICE(0x153F, 0x1006), + .driver_data = (kernel_ulong_t)&pci_driver, + }, + { + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0811), + .driver_data = (kernel_ulong_t)&langwell_pci_driver, + }, + { + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0829), + .driver_data = (kernel_ulong_t)&penwell_pci_driver, + }, + { 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ } +}; +MODULE_DEVICE_TABLE(pci, ci13xxx_pci_id_table); + +static struct pci_driver ci13xxx_pci_driver = { + .name = UDC_DRIVER_NAME, + .id_table = ci13xxx_pci_id_table, + .probe = ci13xxx_pci_probe, + .remove = __devexit_p(ci13xxx_pci_remove), +}; + +module_pci_driver(ci13xxx_pci_driver); + +MODULE_AUTHOR("MIPS - David Lopo "); +MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("June 2008"); diff --git a/trunk/drivers/usb/chipidea/core.c b/trunk/drivers/usb/chipidea/core.c new file mode 100644 index 000000000000..15e03b308f8a --- /dev/null +++ b/trunk/drivers/usb/chipidea/core.c @@ -0,0 +1,474 @@ +/* + * core.c - ChipIdea USB IP core family device controller + * + * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. + * + * Author: David Lopo + * + * 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. + */ + +/* + * Description: ChipIdea USB IP core family device controller + * + * This driver is composed of several blocks: + * - HW: hardware interface + * - DBG: debug facilities (optional) + * - UTIL: utilities + * - ISR: interrupts handling + * - ENDPT: endpoint operations (Gadget API) + * - GADGET: gadget operations (Gadget API) + * - BUS: bus glue code, bus abstraction layer + * + * Compile Options + * - CONFIG_USB_GADGET_DEBUG_FILES: enable debug facilities + * - STALL_IN: non-empty bulk-in pipes cannot be halted + * if defined mass storage compliance succeeds but with warnings + * => case 4: Hi > Dn + * => case 5: Hi > Di + * => case 8: Hi <> Do + * if undefined usbtest 13 fails + * - TRACE: enable function tracing (depends on DEBUG) + * + * Main Features + * - Chapter 9 & Mass Storage Compliance with Gadget File Storage + * - Chapter 9 Compliance with Gadget Zero (STALL_IN undefined) + * - Normal & LPM support + * + * USBTEST Report + * - OK: 0-12, 13 (STALL_IN defined) & 14 + * - Not Supported: 15 & 16 (ISO) + * + * TODO List + * - OTG + * - Isochronous & Interrupt Traffic + * - Handle requests which spawns into several TDs + * - GET_STATUS(device) - always reports 0 + * - Gadget API (majority of optional features) + * - Suspend & Remote Wakeup + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ci.h" +#include "udc.h" +#include "bits.h" +#include "host.h" +#include "debug.h" + +/* Controller register map */ +static uintptr_t ci_regs_nolpm[] = { + [CAP_CAPLENGTH] = 0x000UL, + [CAP_HCCPARAMS] = 0x008UL, + [CAP_DCCPARAMS] = 0x024UL, + [CAP_TESTMODE] = 0x038UL, + [OP_USBCMD] = 0x000UL, + [OP_USBSTS] = 0x004UL, + [OP_USBINTR] = 0x008UL, + [OP_DEVICEADDR] = 0x014UL, + [OP_ENDPTLISTADDR] = 0x018UL, + [OP_PORTSC] = 0x044UL, + [OP_DEVLC] = 0x084UL, + [OP_OTGSC] = 0x064UL, + [OP_USBMODE] = 0x068UL, + [OP_ENDPTSETUPSTAT] = 0x06CUL, + [OP_ENDPTPRIME] = 0x070UL, + [OP_ENDPTFLUSH] = 0x074UL, + [OP_ENDPTSTAT] = 0x078UL, + [OP_ENDPTCOMPLETE] = 0x07CUL, + [OP_ENDPTCTRL] = 0x080UL, +}; + +static uintptr_t ci_regs_lpm[] = { + [CAP_CAPLENGTH] = 0x000UL, + [CAP_HCCPARAMS] = 0x008UL, + [CAP_DCCPARAMS] = 0x024UL, + [CAP_TESTMODE] = 0x0FCUL, + [OP_USBCMD] = 0x000UL, + [OP_USBSTS] = 0x004UL, + [OP_USBINTR] = 0x008UL, + [OP_DEVICEADDR] = 0x014UL, + [OP_ENDPTLISTADDR] = 0x018UL, + [OP_PORTSC] = 0x044UL, + [OP_DEVLC] = 0x084UL, + [OP_OTGSC] = 0x0C4UL, + [OP_USBMODE] = 0x0C8UL, + [OP_ENDPTSETUPSTAT] = 0x0D8UL, + [OP_ENDPTPRIME] = 0x0DCUL, + [OP_ENDPTFLUSH] = 0x0E0UL, + [OP_ENDPTSTAT] = 0x0E4UL, + [OP_ENDPTCOMPLETE] = 0x0E8UL, + [OP_ENDPTCTRL] = 0x0ECUL, +}; + +static int hw_alloc_regmap(struct ci13xxx *ci, bool is_lpm) +{ + int i; + + kfree(ci->hw_bank.regmap); + + ci->hw_bank.regmap = kzalloc((OP_LAST + 1) * sizeof(void *), + GFP_KERNEL); + if (!ci->hw_bank.regmap) + return -ENOMEM; + + for (i = 0; i < OP_ENDPTCTRL; i++) + ci->hw_bank.regmap[i] = + (i <= CAP_LAST ? ci->hw_bank.cap : ci->hw_bank.op) + + (is_lpm ? ci_regs_lpm[i] : ci_regs_nolpm[i]); + + for (; i <= OP_LAST; i++) + ci->hw_bank.regmap[i] = ci->hw_bank.op + + 4 * (i - OP_ENDPTCTRL) + + (is_lpm + ? ci_regs_lpm[OP_ENDPTCTRL] + : ci_regs_nolpm[OP_ENDPTCTRL]); + + return 0; +} + +/** + * hw_port_test_set: writes port test mode (execute without interruption) + * @mode: new value + * + * This function returns an error code + */ +int hw_port_test_set(struct ci13xxx *ci, u8 mode) +{ + const u8 TEST_MODE_MAX = 7; + + if (mode > TEST_MODE_MAX) + return -EINVAL; + + hw_write(ci, OP_PORTSC, PORTSC_PTC, mode << ffs_nr(PORTSC_PTC)); + return 0; +} + +/** + * hw_port_test_get: reads port test mode value + * + * This function returns port test mode value + */ +u8 hw_port_test_get(struct ci13xxx *ci) +{ + return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> ffs_nr(PORTSC_PTC); +} + +static int hw_device_init(struct ci13xxx *ci, void __iomem *base) +{ + u32 reg; + + /* bank is a module variable */ + ci->hw_bank.abs = base; + + ci->hw_bank.cap = ci->hw_bank.abs; + ci->hw_bank.cap += ci->udc_driver->capoffset; + ci->hw_bank.op = ci->hw_bank.cap + ioread8(ci->hw_bank.cap); + + hw_alloc_regmap(ci, false); + reg = hw_read(ci, CAP_HCCPARAMS, HCCPARAMS_LEN) >> + ffs_nr(HCCPARAMS_LEN); + ci->hw_bank.lpm = reg; + hw_alloc_regmap(ci, !!reg); + ci->hw_bank.size = ci->hw_bank.op - ci->hw_bank.abs; + ci->hw_bank.size += OP_LAST; + ci->hw_bank.size /= sizeof(u32); + + reg = hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DEN) >> + ffs_nr(DCCPARAMS_DEN); + ci->hw_ep_max = reg * 2; /* cache hw ENDPT_MAX */ + + if (ci->hw_ep_max > ENDPT_MAX) + return -ENODEV; + + dev_dbg(ci->dev, "ChipIdea HDRC found, lpm: %d; cap: %p op: %p\n", + ci->hw_bank.lpm, ci->hw_bank.cap, ci->hw_bank.op); + + /* setup lock mode ? */ + + /* ENDPTSETUPSTAT is '0' by default */ + + /* HCSPARAMS.bf.ppc SHOULD BE zero for device */ + + return 0; +} + +/** + * hw_device_reset: resets chip (execute without interruption) + * @ci: the controller + * + * This function returns an error code + */ +int hw_device_reset(struct ci13xxx *ci, u32 mode) +{ + /* should flush & stop before reset */ + hw_write(ci, OP_ENDPTFLUSH, ~0, ~0); + hw_write(ci, OP_USBCMD, USBCMD_RS, 0); + + hw_write(ci, OP_USBCMD, USBCMD_RST, USBCMD_RST); + while (hw_read(ci, OP_USBCMD, USBCMD_RST)) + udelay(10); /* not RTOS friendly */ + + + if (ci->udc_driver->notify_event) + ci->udc_driver->notify_event(ci, + CI13XXX_CONTROLLER_RESET_EVENT); + + if (ci->udc_driver->flags & CI13XXX_DISABLE_STREAMING) + hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); + + /* USBMODE should be configured step by step */ + hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE); + hw_write(ci, OP_USBMODE, USBMODE_CM, mode); + /* HW >= 2.3 */ + hw_write(ci, OP_USBMODE, USBMODE_SLOM, USBMODE_SLOM); + + if (hw_read(ci, OP_USBMODE, USBMODE_CM) != mode) { + pr_err("cannot enter in %s mode", ci_role(ci)->name); + pr_err("lpm = %i", ci->hw_bank.lpm); + return -ENODEV; + } + + return 0; +} + +/** + * ci_otg_role - pick role based on ID pin state + * @ci: the controller + */ +static enum ci_role ci_otg_role(struct ci13xxx *ci) +{ + u32 sts = hw_read(ci, OP_OTGSC, ~0); + enum ci_role role = sts & OTGSC_ID + ? CI_ROLE_GADGET + : CI_ROLE_HOST; + + return role; +} + +/** + * ci_role_work - perform role changing based on ID pin + * @work: work struct + */ +static void ci_role_work(struct work_struct *work) +{ + struct ci13xxx *ci = container_of(work, struct ci13xxx, work); + enum ci_role role = ci_otg_role(ci); + + hw_write(ci, OP_OTGSC, OTGSC_IDIS, OTGSC_IDIS); + + if (role != ci->role) { + dev_dbg(ci->dev, "switching from %s to %s\n", + ci_role(ci)->name, ci->roles[role]->name); + + ci_role_stop(ci); + ci_role_start(ci, role); + } +} + +static ssize_t show_role(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ci13xxx *ci = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", ci_role(ci)->name); +} + +static ssize_t store_role(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ci13xxx *ci = dev_get_drvdata(dev); + enum ci_role role; + int ret; + + for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++) + if (ci->roles[role] && !strcmp(buf, ci->roles[role]->name)) + break; + + if (role == CI_ROLE_END || role == ci->role) + return -EINVAL; + + ci_role_stop(ci); + ret = ci_role_start(ci, role); + if (ret) + return ret; + + return count; +} + +static DEVICE_ATTR(role, S_IRUSR | S_IWUSR, show_role, store_role); + +static irqreturn_t ci_irq(int irq, void *data) +{ + struct ci13xxx *ci = data; + irqreturn_t ret = IRQ_NONE; + + if (ci->is_otg) { + u32 sts = hw_read(ci, OP_OTGSC, ~0); + + if (sts & OTGSC_IDIS) { + queue_work(ci->wq, &ci->work); + ret = IRQ_HANDLED; + } + } + + return ci->role == CI_ROLE_END ? ret : ci_role(ci)->irq(ci); +} + +static int __devinit ci_hdrc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ci13xxx *ci; + struct resource *res; + void __iomem *base; + int ret; + + if (!dev->platform_data) { + dev_err(dev, "platform data missing\n"); + return -ENODEV; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "missing resource\n"); + return -ENODEV; + } + + base = devm_request_and_ioremap(dev, res); + if (!res) { + dev_err(dev, "can't request and ioremap resource\n"); + return -ENOMEM; + } + + ci = devm_kzalloc(dev, sizeof(*ci), GFP_KERNEL); + if (!ci) { + dev_err(dev, "can't allocate device\n"); + return -ENOMEM; + } + + ci->dev = dev; + ci->udc_driver = dev->platform_data; + + ret = hw_device_init(ci, base); + if (ret < 0) { + dev_err(dev, "can't initialize hardware\n"); + return -ENODEV; + } + + ci->hw_bank.phys = res->start; + + ci->irq = platform_get_irq(pdev, 0); + if (ci->irq < 0) { + dev_err(dev, "missing IRQ\n"); + return -ENODEV; + } + + INIT_WORK(&ci->work, ci_role_work); + ci->wq = create_singlethread_workqueue("ci_otg"); + if (!ci->wq) { + dev_err(dev, "can't create workqueue\n"); + return -ENODEV; + } + + /* initialize role(s) before the interrupt is requested */ + ret = ci_hdrc_host_init(ci); + if (ret) + dev_info(dev, "doesn't support host\n"); + + ret = ci_hdrc_gadget_init(ci); + if (ret) + dev_info(dev, "doesn't support gadget\n"); + + if (!ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]) { + dev_err(dev, "no supported roles\n"); + ret = -ENODEV; + goto rm_wq; + } + + if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) { + ci->is_otg = true; + ci->role = ci_otg_role(ci); + } else { + ci->role = ci->roles[CI_ROLE_HOST] + ? CI_ROLE_HOST + : CI_ROLE_GADGET; + } + + ret = ci_role_start(ci, ci->role); + if (ret) { + dev_err(dev, "can't start %s role\n", ci_role(ci)->name); + ret = -ENODEV; + goto rm_wq; + } + + platform_set_drvdata(pdev, ci); + ret = request_irq(ci->irq, ci_irq, IRQF_SHARED, ci->udc_driver->name, + ci); + if (ret) + goto stop; + + ret = device_create_file(dev, &dev_attr_role); + if (ret) + goto rm_attr; + + if (ci->is_otg) + hw_write(ci, OP_OTGSC, OTGSC_IDIE, OTGSC_IDIE); + + return ret; + +rm_attr: + device_remove_file(dev, &dev_attr_role); +stop: + ci_role_stop(ci); +rm_wq: + flush_workqueue(ci->wq); + destroy_workqueue(ci->wq); + + return ret; +} + +static int __devexit ci_hdrc_remove(struct platform_device *pdev) +{ + struct ci13xxx *ci = platform_get_drvdata(pdev); + + flush_workqueue(ci->wq); + destroy_workqueue(ci->wq); + device_remove_file(ci->dev, &dev_attr_role); + free_irq(ci->irq, ci); + ci_role_stop(ci); + + return 0; +} + +static struct platform_driver ci_hdrc_driver = { + .probe = ci_hdrc_probe, + .remove = __devexit_p(ci_hdrc_remove), + .driver = { + .name = "ci_hdrc", + }, +}; + +module_platform_driver(ci_hdrc_driver); + +MODULE_ALIAS("platform:ci_hdrc"); +MODULE_ALIAS("platform:ci13xxx"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("David Lopo "); +MODULE_DESCRIPTION("ChipIdea HDRC Driver"); diff --git a/trunk/drivers/usb/chipidea/debug.c b/trunk/drivers/usb/chipidea/debug.c new file mode 100644 index 000000000000..c4b3e15532db --- /dev/null +++ b/trunk/drivers/usb/chipidea/debug.c @@ -0,0 +1,804 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ci.h" +#include "udc.h" +#include "bits.h" +#include "debug.h" + +/* Interrupt statistics */ +#define ISR_MASK 0x1F +static struct isr_statistics { + u32 test; + u32 ui; + u32 uei; + u32 pci; + u32 uri; + u32 sli; + u32 none; + struct { + u32 cnt; + u32 buf[ISR_MASK+1]; + u32 idx; + } hndl; +} isr_statistics; + +void dbg_interrupt(u32 intmask) +{ + if (!intmask) { + isr_statistics.none++; + return; + } + + isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intmask; + isr_statistics.hndl.idx &= ISR_MASK; + isr_statistics.hndl.cnt++; + + if (USBi_URI & intmask) + isr_statistics.uri++; + if (USBi_PCI & intmask) + isr_statistics.pci++; + if (USBi_UEI & intmask) + isr_statistics.uei++; + if (USBi_UI & intmask) + isr_statistics.ui++; + if (USBi_SLI & intmask) + isr_statistics.sli++; +} + +/** + * hw_register_read: reads all device registers (execute without interruption) + * @buf: destination buffer + * @size: buffer size + * + * This function returns number of registers read + */ +static size_t hw_register_read(struct ci13xxx *udc, u32 *buf, size_t size) +{ + unsigned i; + + if (size > udc->hw_bank.size) + size = udc->hw_bank.size; + + for (i = 0; i < size; i++) + buf[i] = hw_read(udc, i * sizeof(u32), ~0); + + return size; +} + +/** + * hw_register_write: writes to register + * @addr: register address + * @data: register value + * + * This function returns an error code + */ +static int hw_register_write(struct ci13xxx *udc, u16 addr, u32 data) +{ + /* align */ + addr /= sizeof(u32); + + if (addr >= udc->hw_bank.size) + return -EINVAL; + + /* align */ + addr *= sizeof(u32); + + hw_write(udc, addr, ~0, data); + return 0; +} + +/** + * hw_intr_clear: disables interrupt & clears interrupt status (execute without + * interruption) + * @n: interrupt bit + * + * This function returns an error code + */ +static int hw_intr_clear(struct ci13xxx *udc, int n) +{ + if (n >= REG_BITS) + return -EINVAL; + + hw_write(udc, OP_USBINTR, BIT(n), 0); + hw_write(udc, OP_USBSTS, BIT(n), BIT(n)); + return 0; +} + +/** + * hw_intr_force: enables interrupt & forces interrupt status (execute without + * interruption) + * @n: interrupt bit + * + * This function returns an error code + */ +static int hw_intr_force(struct ci13xxx *udc, int n) +{ + if (n >= REG_BITS) + return -EINVAL; + + hw_write(udc, CAP_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE); + hw_write(udc, OP_USBINTR, BIT(n), BIT(n)); + hw_write(udc, OP_USBSTS, BIT(n), BIT(n)); + hw_write(udc, CAP_TESTMODE, TESTMODE_FORCE, 0); + return 0; +} + +/** + * show_device: prints information about device capabilities and status + * + * Check "device.h" for details + */ +static ssize_t show_device(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); + struct usb_gadget *gadget = &udc->gadget; + int n = 0; + + if (attr == NULL || buf == NULL) { + dev_err(udc->dev, "[%s] EINVAL\n", __func__); + return 0; + } + + n += scnprintf(buf + n, PAGE_SIZE - n, "speed = %d\n", + gadget->speed); + n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed = %d\n", + gadget->max_speed); + /* TODO: Scheduled for removal in 3.8. */ + n += scnprintf(buf + n, PAGE_SIZE - n, "is_dualspeed = %d\n", + gadget_is_dualspeed(gadget)); + n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg = %d\n", + gadget->is_otg); + n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral = %d\n", + gadget->is_a_peripheral); + n += scnprintf(buf + n, PAGE_SIZE - n, "b_hnp_enable = %d\n", + gadget->b_hnp_enable); + n += scnprintf(buf + n, PAGE_SIZE - n, "a_hnp_support = %d\n", + gadget->a_hnp_support); + n += scnprintf(buf + n, PAGE_SIZE - n, "a_alt_hnp_support = %d\n", + gadget->a_alt_hnp_support); + n += scnprintf(buf + n, PAGE_SIZE - n, "name = %s\n", + (gadget->name ? gadget->name : "")); + + return n; +} +static DEVICE_ATTR(device, S_IRUSR, show_device, NULL); + +/** + * show_driver: prints information about attached gadget (if any) + * + * Check "device.h" for details + */ +static ssize_t show_driver(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); + struct usb_gadget_driver *driver = udc->driver; + int n = 0; + + if (attr == NULL || buf == NULL) { + dev_err(dev, "[%s] EINVAL\n", __func__); + return 0; + } + + if (driver == NULL) + return scnprintf(buf, PAGE_SIZE, + "There is no gadget attached!\n"); + + n += scnprintf(buf + n, PAGE_SIZE - n, "function = %s\n", + (driver->function ? driver->function : "")); + n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n", + driver->max_speed); + + return n; +} +static DEVICE_ATTR(driver, S_IRUSR, show_driver, NULL); + +/* Maximum event message length */ +#define DBG_DATA_MSG 64UL + +/* Maximum event messages */ +#define DBG_DATA_MAX 128UL + +/* Event buffer descriptor */ +static struct { + char (buf[DBG_DATA_MAX])[DBG_DATA_MSG]; /* buffer */ + unsigned idx; /* index */ + unsigned tty; /* print to console? */ + rwlock_t lck; /* lock */ +} dbg_data = { + .idx = 0, + .tty = 0, + .lck = __RW_LOCK_UNLOCKED(lck) +}; + +/** + * dbg_dec: decrements debug event index + * @idx: buffer index + */ +static void dbg_dec(unsigned *idx) +{ + *idx = (*idx - 1) & (DBG_DATA_MAX-1); +} + +/** + * dbg_inc: increments debug event index + * @idx: buffer index + */ +static void dbg_inc(unsigned *idx) +{ + *idx = (*idx + 1) & (DBG_DATA_MAX-1); +} + +/** + * dbg_print: prints the common part of the event + * @addr: endpoint address + * @name: event name + * @status: status + * @extra: extra information + */ +static void dbg_print(u8 addr, const char *name, int status, const char *extra) +{ + struct timeval tval; + unsigned int stamp; + unsigned long flags; + + write_lock_irqsave(&dbg_data.lck, flags); + + do_gettimeofday(&tval); + stamp = tval.tv_sec & 0xFFFF; /* 2^32 = 4294967296. Limit to 4096s */ + stamp = stamp * 1000000 + tval.tv_usec; + + scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG, + "%04X\t? %02X %-7.7s %4i ?\t%s\n", + stamp, addr, name, status, extra); + + dbg_inc(&dbg_data.idx); + + write_unlock_irqrestore(&dbg_data.lck, flags); + + if (dbg_data.tty != 0) + pr_notice("%04X\t? %02X %-7.7s %4i ?\t%s\n", + stamp, addr, name, status, extra); +} + +/** + * dbg_done: prints a DONE event + * @addr: endpoint address + * @td: transfer descriptor + * @status: status + */ +void dbg_done(u8 addr, const u32 token, int status) +{ + char msg[DBG_DATA_MSG]; + + scnprintf(msg, sizeof(msg), "%d %02X", + (int)(token & TD_TOTAL_BYTES) >> ffs_nr(TD_TOTAL_BYTES), + (int)(token & TD_STATUS) >> ffs_nr(TD_STATUS)); + dbg_print(addr, "DONE", status, msg); +} + +/** + * dbg_event: prints a generic event + * @addr: endpoint address + * @name: event name + * @status: status + */ +void dbg_event(u8 addr, const char *name, int status) +{ + if (name != NULL) + dbg_print(addr, name, status, ""); +} + +/* + * dbg_queue: prints a QUEUE event + * @addr: endpoint address + * @req: USB request + * @status: status + */ +void dbg_queue(u8 addr, const struct usb_request *req, int status) +{ + char msg[DBG_DATA_MSG]; + + if (req != NULL) { + scnprintf(msg, sizeof(msg), + "%d %d", !req->no_interrupt, req->length); + dbg_print(addr, "QUEUE", status, msg); + } +} + +/** + * dbg_setup: prints a SETUP event + * @addr: endpoint address + * @req: setup request + */ +void dbg_setup(u8 addr, const struct usb_ctrlrequest *req) +{ + char msg[DBG_DATA_MSG]; + + if (req != NULL) { + scnprintf(msg, sizeof(msg), + "%02X %02X %04X %04X %d", req->bRequestType, + req->bRequest, le16_to_cpu(req->wValue), + le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength)); + dbg_print(addr, "SETUP", 0, msg); + } +} + +/** + * show_events: displays the event buffer + * + * Check "device.h" for details + */ +static ssize_t show_events(struct device *dev, struct device_attribute *attr, + char *buf) +{ + unsigned long flags; + unsigned i, j, n = 0; + + if (attr == NULL || buf == NULL) { + dev_err(dev->parent, "[%s] EINVAL\n", __func__); + return 0; + } + + read_lock_irqsave(&dbg_data.lck, flags); + + i = dbg_data.idx; + for (dbg_dec(&i); i != dbg_data.idx; dbg_dec(&i)) { + n += strlen(dbg_data.buf[i]); + if (n >= PAGE_SIZE) { + n -= strlen(dbg_data.buf[i]); + break; + } + } + for (j = 0, dbg_inc(&i); j < n; dbg_inc(&i)) + j += scnprintf(buf + j, PAGE_SIZE - j, + "%s", dbg_data.buf[i]); + + read_unlock_irqrestore(&dbg_data.lck, flags); + + return n; +} + +/** + * store_events: configure if events are going to be also printed to console + * + * Check "device.h" for details + */ +static ssize_t store_events(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned tty; + + if (attr == NULL || buf == NULL) { + dev_err(dev, "[%s] EINVAL\n", __func__); + goto done; + } + + if (sscanf(buf, "%u", &tty) != 1 || tty > 1) { + dev_err(dev, "<1|0>: enable|disable console log\n"); + goto done; + } + + dbg_data.tty = tty; + dev_info(dev, "tty = %u", dbg_data.tty); + + done: + return count; +} +static DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events); + +/** + * show_inters: interrupt status, enable status and historic + * + * Check "device.h" for details + */ +static ssize_t show_inters(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); + unsigned long flags; + u32 intr; + unsigned i, j, n = 0; + + if (attr == NULL || buf == NULL) { + dev_err(udc->dev, "[%s] EINVAL\n", __func__); + return 0; + } + + spin_lock_irqsave(&udc->lock, flags); + + /*n += scnprintf(buf + n, PAGE_SIZE - n, + "status = %08x\n", hw_read_intr_status(udc)); + n += scnprintf(buf + n, PAGE_SIZE - n, + "enable = %08x\n", hw_read_intr_enable(udc));*/ + + n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n", + isr_statistics.test); + n += scnprintf(buf + n, PAGE_SIZE - n, "? ui = %d\n", + isr_statistics.ui); + n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n", + isr_statistics.uei); + n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n", + isr_statistics.pci); + n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n", + isr_statistics.uri); + n += scnprintf(buf + n, PAGE_SIZE - n, "? sli = %d\n", + isr_statistics.sli); + n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n", + isr_statistics.none); + n += scnprintf(buf + n, PAGE_SIZE - n, "*hndl = %d\n", + isr_statistics.hndl.cnt); + + for (i = isr_statistics.hndl.idx, j = 0; j <= ISR_MASK; j++, i++) { + i &= ISR_MASK; + intr = isr_statistics.hndl.buf[i]; + + if (USBi_UI & intr) + n += scnprintf(buf + n, PAGE_SIZE - n, "ui "); + intr &= ~USBi_UI; + if (USBi_UEI & intr) + n += scnprintf(buf + n, PAGE_SIZE - n, "uei "); + intr &= ~USBi_UEI; + if (USBi_PCI & intr) + n += scnprintf(buf + n, PAGE_SIZE - n, "pci "); + intr &= ~USBi_PCI; + if (USBi_URI & intr) + n += scnprintf(buf + n, PAGE_SIZE - n, "uri "); + intr &= ~USBi_URI; + if (USBi_SLI & intr) + n += scnprintf(buf + n, PAGE_SIZE - n, "sli "); + intr &= ~USBi_SLI; + if (intr) + n += scnprintf(buf + n, PAGE_SIZE - n, "??? "); + if (isr_statistics.hndl.buf[i]) + n += scnprintf(buf + n, PAGE_SIZE - n, "\n"); + } + + spin_unlock_irqrestore(&udc->lock, flags); + + return n; +} + +/** + * store_inters: enable & force or disable an individual interrutps + * (to be used for test purposes only) + * + * Check "device.h" for details + */ +static ssize_t store_inters(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); + unsigned long flags; + unsigned en, bit; + + if (attr == NULL || buf == NULL) { + dev_err(udc->dev, "EINVAL\n"); + goto done; + } + + if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) { + dev_err(udc->dev, "<1|0> : enable|disable interrupt\n"); + goto done; + } + + spin_lock_irqsave(&udc->lock, flags); + if (en) { + if (hw_intr_force(udc, bit)) + dev_err(dev, "invalid bit number\n"); + else + isr_statistics.test++; + } else { + if (hw_intr_clear(udc, bit)) + dev_err(dev, "invalid bit number\n"); + } + spin_unlock_irqrestore(&udc->lock, flags); + + done: + return count; +} +static DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters); + +/** + * show_port_test: reads port test mode + * + * Check "device.h" for details + */ +static ssize_t show_port_test(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); + unsigned long flags; + unsigned mode; + + if (attr == NULL || buf == NULL) { + dev_err(udc->dev, "EINVAL\n"); + return 0; + } + + spin_lock_irqsave(&udc->lock, flags); + mode = hw_port_test_get(udc); + spin_unlock_irqrestore(&udc->lock, flags); + + return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode); +} + +/** + * store_port_test: writes port test mode + * + * Check "device.h" for details + */ +static ssize_t store_port_test(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); + unsigned long flags; + unsigned mode; + + if (attr == NULL || buf == NULL) { + dev_err(udc->dev, "[%s] EINVAL\n", __func__); + goto done; + } + + if (sscanf(buf, "%u", &mode) != 1) { + dev_err(udc->dev, ": set port test mode"); + goto done; + } + + spin_lock_irqsave(&udc->lock, flags); + if (hw_port_test_set(udc, mode)) + dev_err(udc->dev, "invalid mode\n"); + spin_unlock_irqrestore(&udc->lock, flags); + + done: + return count; +} +static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR, + show_port_test, store_port_test); + +/** + * show_qheads: DMA contents of all queue heads + * + * Check "device.h" for details + */ +static ssize_t show_qheads(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); + unsigned long flags; + unsigned i, j, n = 0; + + if (attr == NULL || buf == NULL) { + dev_err(udc->dev, "[%s] EINVAL\n", __func__); + return 0; + } + + spin_lock_irqsave(&udc->lock, flags); + for (i = 0; i < udc->hw_ep_max/2; i++) { + struct ci13xxx_ep *mEpRx = &udc->ci13xxx_ep[i]; + struct ci13xxx_ep *mEpTx = + &udc->ci13xxx_ep[i + udc->hw_ep_max/2]; + n += scnprintf(buf + n, PAGE_SIZE - n, + "EP=%02i: RX=%08X TX=%08X\n", + i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma); + for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) { + n += scnprintf(buf + n, PAGE_SIZE - n, + " %04X: %08X %08X\n", j, + *((u32 *)mEpRx->qh.ptr + j), + *((u32 *)mEpTx->qh.ptr + j)); + } + } + spin_unlock_irqrestore(&udc->lock, flags); + + return n; +} +static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL); + +/** + * show_registers: dumps all registers + * + * Check "device.h" for details + */ +#define DUMP_ENTRIES 512 +static ssize_t show_registers(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); + unsigned long flags; + u32 *dump; + unsigned i, k, n = 0; + + if (attr == NULL || buf == NULL) { + dev_err(udc->dev, "[%s] EINVAL\n", __func__); + return 0; + } + + dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL); + if (!dump) { + dev_err(udc->dev, "%s: out of memory\n", __func__); + return 0; + } + + spin_lock_irqsave(&udc->lock, flags); + k = hw_register_read(udc, dump, DUMP_ENTRIES); + spin_unlock_irqrestore(&udc->lock, flags); + + for (i = 0; i < k; i++) { + n += scnprintf(buf + n, PAGE_SIZE - n, + "reg[0x%04X] = 0x%08X\n", + i * (unsigned)sizeof(u32), dump[i]); + } + kfree(dump); + + return n; +} + +/** + * store_registers: writes value to register address + * + * Check "device.h" for details + */ +static ssize_t store_registers(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); + unsigned long addr, data, flags; + + if (attr == NULL || buf == NULL) { + dev_err(udc->dev, "[%s] EINVAL\n", __func__); + goto done; + } + + if (sscanf(buf, "%li %li", &addr, &data) != 2) { + dev_err(udc->dev, + " : write data to register address\n"); + goto done; + } + + spin_lock_irqsave(&udc->lock, flags); + if (hw_register_write(udc, addr, data)) + dev_err(udc->dev, "invalid address range\n"); + spin_unlock_irqrestore(&udc->lock, flags); + + done: + return count; +} +static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR, + show_registers, store_registers); + +/** + * show_requests: DMA contents of all requests currently queued (all endpts) + * + * Check "device.h" for details + */ +static ssize_t show_requests(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); + unsigned long flags; + struct list_head *ptr = NULL; + struct ci13xxx_req *req = NULL; + unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32); + + if (attr == NULL || buf == NULL) { + dev_err(udc->dev, "[%s] EINVAL\n", __func__); + return 0; + } + + spin_lock_irqsave(&udc->lock, flags); + for (i = 0; i < udc->hw_ep_max; i++) + list_for_each(ptr, &udc->ci13xxx_ep[i].qh.queue) + { + req = list_entry(ptr, struct ci13xxx_req, queue); + + n += scnprintf(buf + n, PAGE_SIZE - n, + "EP=%02i: TD=%08X %s\n", + i % udc->hw_ep_max/2, (u32)req->dma, + ((i < udc->hw_ep_max/2) ? "RX" : "TX")); + + for (j = 0; j < qSize; j++) + n += scnprintf(buf + n, PAGE_SIZE - n, + " %04X: %08X\n", j, + *((u32 *)req->ptr + j)); + } + spin_unlock_irqrestore(&udc->lock, flags); + + return n; +} +static DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL); + +/** + * dbg_create_files: initializes the attribute interface + * @dev: device + * + * This function returns an error code + */ +int dbg_create_files(struct device *dev) +{ + int retval = 0; + + if (dev == NULL) + return -EINVAL; + retval = device_create_file(dev, &dev_attr_device); + if (retval) + goto done; + retval = device_create_file(dev, &dev_attr_driver); + if (retval) + goto rm_device; + retval = device_create_file(dev, &dev_attr_events); + if (retval) + goto rm_driver; + retval = device_create_file(dev, &dev_attr_inters); + if (retval) + goto rm_events; + retval = device_create_file(dev, &dev_attr_port_test); + if (retval) + goto rm_inters; + retval = device_create_file(dev, &dev_attr_qheads); + if (retval) + goto rm_port_test; + retval = device_create_file(dev, &dev_attr_registers); + if (retval) + goto rm_qheads; + retval = device_create_file(dev, &dev_attr_requests); + if (retval) + goto rm_registers; + return 0; + + rm_registers: + device_remove_file(dev, &dev_attr_registers); + rm_qheads: + device_remove_file(dev, &dev_attr_qheads); + rm_port_test: + device_remove_file(dev, &dev_attr_port_test); + rm_inters: + device_remove_file(dev, &dev_attr_inters); + rm_events: + device_remove_file(dev, &dev_attr_events); + rm_driver: + device_remove_file(dev, &dev_attr_driver); + rm_device: + device_remove_file(dev, &dev_attr_device); + done: + return retval; +} + +/** + * dbg_remove_files: destroys the attribute interface + * @dev: device + * + * This function returns an error code + */ +int dbg_remove_files(struct device *dev) +{ + if (dev == NULL) + return -EINVAL; + device_remove_file(dev, &dev_attr_requests); + device_remove_file(dev, &dev_attr_registers); + device_remove_file(dev, &dev_attr_qheads); + device_remove_file(dev, &dev_attr_port_test); + device_remove_file(dev, &dev_attr_inters); + device_remove_file(dev, &dev_attr_events); + device_remove_file(dev, &dev_attr_driver); + device_remove_file(dev, &dev_attr_device); + return 0; +} diff --git a/trunk/drivers/usb/chipidea/debug.h b/trunk/drivers/usb/chipidea/debug.h new file mode 100644 index 000000000000..80d96865775c --- /dev/null +++ b/trunk/drivers/usb/chipidea/debug.h @@ -0,0 +1,56 @@ +/* + * debug.h - ChipIdea USB driver debug interfaces + * + * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. + * + * Author: David Lopo + * + * 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_DEBUG_H +#define __DRIVERS_USB_CHIPIDEA_DEBUG_H + +#ifdef CONFIG_USB_CHIPIDEA_DEBUG +void dbg_interrupt(u32 intmask); +void dbg_done(u8 addr, const u32 token, int status); +void dbg_event(u8 addr, const char *name, int status); +void dbg_queue(u8 addr, const struct usb_request *req, int status); +void dbg_setup(u8 addr, const struct usb_ctrlrequest *req); +int dbg_create_files(struct device *dev); +int dbg_remove_files(struct device *dev); +#else +static inline void dbg_interrupt(u32 intmask) +{ +} + +static inline void dbg_done(u8 addr, const u32 token, int status) +{ +} + +static inline void dbg_event(u8 addr, const char *name, int status) +{ +} + +static inline void dbg_queue(u8 addr, const struct usb_request *req, int status) +{ +} + +static inline void dbg_setup(u8 addr, const struct usb_ctrlrequest *req) +{ +} + +static inline int dbg_create_files(struct device *dev) +{ + return 0; +} + +static inline int dbg_remove_files(struct device *dev) +{ + return 0; +} +#endif + +#endif /* __DRIVERS_USB_CHIPIDEA_DEBUG_H */ diff --git a/trunk/drivers/usb/chipidea/host.c b/trunk/drivers/usb/chipidea/host.c new file mode 100644 index 000000000000..9eacd21c0cd9 --- /dev/null +++ b/trunk/drivers/usb/chipidea/host.c @@ -0,0 +1,160 @@ +/* + * host.c - ChipIdea USB host controller driver + * + * Copyright (c) 2012 Intel Corporation + * + * Author: Alexander Shishkin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +#define CHIPIDEA_EHCI +#include "../host/ehci-hcd.c" + +#include "ci.h" +#include "bits.h" +#include "host.h" + +static int ci_ehci_setup(struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + int ret; + + hcd->has_tt = 1; + + ret = ehci_setup(hcd); + if (ret) + return ret; + + ehci_port_power(ehci, 0); + + return ret; +} + +static const struct hc_driver ci_ehci_hc_driver = { + .description = "ehci_hcd", + .product_desc = "ChipIdea HDRC EHCI", + .hcd_priv_size = sizeof(struct ehci_hcd), + + /* + * generic hardware linkage + */ + .irq = ehci_irq, + .flags = HCD_MEMORY | HCD_USB2, + + /* + * basic lifecycle operations + */ + .reset = ci_ehci_setup, + .start = ehci_run, + .stop = ehci_stop, + .shutdown = ehci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + .endpoint_reset = ehci_endpoint_reset, + + /* + * scheduling support + */ + .get_frame_number = ehci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, + .relinquish_port = ehci_relinquish_port, + .port_handed_over = ehci_port_handed_over, + + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, +}; + +static irqreturn_t host_irq(struct ci13xxx *ci) +{ + return usb_hcd_irq(ci->irq, ci->hcd); +} + +static int host_start(struct ci13xxx *ci) +{ + struct usb_hcd *hcd; + struct ehci_hcd *ehci; + int ret; + + if (usb_disabled()) + return -ENODEV; + + hcd = usb_create_hcd(&ci_ehci_hc_driver, ci->dev, dev_name(ci->dev)); + if (!hcd) + return -ENOMEM; + + dev_set_drvdata(ci->dev, ci); + hcd->rsrc_start = ci->hw_bank.phys; + hcd->rsrc_len = ci->hw_bank.size; + hcd->regs = ci->hw_bank.abs; + hcd->has_tt = 1; + + hcd->power_budget = ci->udc_driver->power_budget; + + ehci = hcd_to_ehci(hcd); + ehci->caps = ci->hw_bank.cap; + ehci->has_hostpc = ci->hw_bank.lpm; + + ret = usb_add_hcd(hcd, 0, 0); + if (ret) + usb_put_hcd(hcd); + else + ci->hcd = hcd; + + return ret; +} + +static void host_stop(struct ci13xxx *ci) +{ + struct usb_hcd *hcd = ci->hcd; + + usb_remove_hcd(hcd); + usb_put_hcd(hcd); +} + +int ci_hdrc_host_init(struct ci13xxx *ci) +{ + struct ci_role_driver *rdrv; + + if (!hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_HC)) + return -ENXIO; + + rdrv = devm_kzalloc(ci->dev, sizeof(struct ci_role_driver), GFP_KERNEL); + if (!rdrv) + return -ENOMEM; + + rdrv->start = host_start; + rdrv->stop = host_stop; + rdrv->irq = host_irq; + rdrv->name = "host"; + ci->roles[CI_ROLE_HOST] = rdrv; + + return 0; +} diff --git a/trunk/drivers/usb/chipidea/host.h b/trunk/drivers/usb/chipidea/host.h new file mode 100644 index 000000000000..761fb1fd6d99 --- /dev/null +++ b/trunk/drivers/usb/chipidea/host.h @@ -0,0 +1,17 @@ +#ifndef __DRIVERS_USB_CHIPIDEA_HOST_H +#define __DRIVERS_USB_CHIPIDEA_HOST_H + +#ifdef CONFIG_USB_CHIPIDEA_HOST + +int ci_hdrc_host_init(struct ci13xxx *ci); + +#else + +static inline int ci_hdrc_host_init(struct ci13xxx *ci) +{ + return -ENXIO; +} + +#endif + +#endif /* __DRIVERS_USB_CHIPIDEA_HOST_H */ diff --git a/trunk/drivers/usb/chipidea/udc.c b/trunk/drivers/usb/chipidea/udc.c new file mode 100644 index 000000000000..51f96942dc5e --- /dev/null +++ b/trunk/drivers/usb/chipidea/udc.c @@ -0,0 +1,1809 @@ +/* + * udc.c - ChipIdea UDC driver + * + * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. + * + * Author: David Lopo + * + * 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 "ci.h" +#include "udc.h" +#include "bits.h" +#include "debug.h" + +/* control endpoint description */ +static const struct usb_endpoint_descriptor +ctrl_endpt_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_CONTROL, + .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX), +}; + +static const struct usb_endpoint_descriptor +ctrl_endpt_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_CONTROL, + .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX), +}; + +/** + * hw_ep_bit: calculates the bit number + * @num: endpoint number + * @dir: endpoint direction + * + * This function returns bit number + */ +static inline int hw_ep_bit(int num, int dir) +{ + return num + (dir ? 16 : 0); +} + +static inline int ep_to_bit(struct ci13xxx *udc, int n) +{ + int fill = 16 - udc->hw_ep_max / 2; + + if (n >= udc->hw_ep_max / 2) + n += fill; + + return n; +} + +/** + * hw_device_state: enables/disables interrupts & starts/stops device (execute + * without interruption) + * @dma: 0 => disable, !0 => enable and set dma engine + * + * This function returns an error code + */ +static int hw_device_state(struct ci13xxx *udc, u32 dma) +{ + if (dma) { + hw_write(udc, OP_ENDPTLISTADDR, ~0, dma); + /* interrupt, error, port change, reset, sleep/suspend */ + hw_write(udc, OP_USBINTR, ~0, + USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI); + hw_write(udc, OP_USBCMD, USBCMD_RS, USBCMD_RS); + } else { + hw_write(udc, OP_USBCMD, USBCMD_RS, 0); + hw_write(udc, OP_USBINTR, ~0, 0); + } + return 0; +} + +/** + * hw_ep_flush: flush endpoint fifo (execute without interruption) + * @num: endpoint number + * @dir: endpoint direction + * + * This function returns an error code + */ +static int hw_ep_flush(struct ci13xxx *udc, int num, int dir) +{ + int n = hw_ep_bit(num, dir); + + do { + /* flush any pending transfer */ + hw_write(udc, OP_ENDPTFLUSH, BIT(n), BIT(n)); + while (hw_read(udc, OP_ENDPTFLUSH, BIT(n))) + cpu_relax(); + } while (hw_read(udc, OP_ENDPTSTAT, BIT(n))); + + return 0; +} + +/** + * hw_ep_disable: disables endpoint (execute without interruption) + * @num: endpoint number + * @dir: endpoint direction + * + * This function returns an error code + */ +static int hw_ep_disable(struct ci13xxx *udc, int num, int dir) +{ + hw_ep_flush(udc, num, dir); + hw_write(udc, OP_ENDPTCTRL + num, + dir ? ENDPTCTRL_TXE : ENDPTCTRL_RXE, 0); + return 0; +} + +/** + * hw_ep_enable: enables endpoint (execute without interruption) + * @num: endpoint number + * @dir: endpoint direction + * @type: endpoint type + * + * This function returns an error code + */ +static int hw_ep_enable(struct ci13xxx *udc, int num, int dir, int type) +{ + u32 mask, data; + + if (dir) { + mask = ENDPTCTRL_TXT; /* type */ + data = type << ffs_nr(mask); + + mask |= ENDPTCTRL_TXS; /* unstall */ + mask |= ENDPTCTRL_TXR; /* reset data toggle */ + data |= ENDPTCTRL_TXR; + mask |= ENDPTCTRL_TXE; /* enable */ + data |= ENDPTCTRL_TXE; + } else { + mask = ENDPTCTRL_RXT; /* type */ + data = type << ffs_nr(mask); + + mask |= ENDPTCTRL_RXS; /* unstall */ + mask |= ENDPTCTRL_RXR; /* reset data toggle */ + data |= ENDPTCTRL_RXR; + mask |= ENDPTCTRL_RXE; /* enable */ + data |= ENDPTCTRL_RXE; + } + hw_write(udc, OP_ENDPTCTRL + num, mask, data); + return 0; +} + +/** + * hw_ep_get_halt: return endpoint halt status + * @num: endpoint number + * @dir: endpoint direction + * + * This function returns 1 if endpoint halted + */ +static int hw_ep_get_halt(struct ci13xxx *udc, int num, int dir) +{ + u32 mask = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS; + + return hw_read(udc, OP_ENDPTCTRL + num, mask) ? 1 : 0; +} + +/** + * hw_test_and_clear_setup_status: test & clear setup status (execute without + * interruption) + * @n: endpoint number + * + * This function returns setup status + */ +static int hw_test_and_clear_setup_status(struct ci13xxx *udc, int n) +{ + n = ep_to_bit(udc, n); + return hw_test_and_clear(udc, OP_ENDPTSETUPSTAT, BIT(n)); +} + +/** + * hw_ep_prime: primes endpoint (execute without interruption) + * @num: endpoint number + * @dir: endpoint direction + * @is_ctrl: true if control endpoint + * + * This function returns an error code + */ +static int hw_ep_prime(struct ci13xxx *udc, int num, int dir, int is_ctrl) +{ + int n = hw_ep_bit(num, dir); + + if (is_ctrl && dir == RX && hw_read(udc, OP_ENDPTSETUPSTAT, BIT(num))) + return -EAGAIN; + + hw_write(udc, OP_ENDPTPRIME, BIT(n), BIT(n)); + + while (hw_read(udc, OP_ENDPTPRIME, BIT(n))) + cpu_relax(); + if (is_ctrl && dir == RX && hw_read(udc, OP_ENDPTSETUPSTAT, BIT(num))) + return -EAGAIN; + + /* status shoult be tested according with manual but it doesn't work */ + return 0; +} + +/** + * hw_ep_set_halt: configures ep halt & resets data toggle after clear (execute + * without interruption) + * @num: endpoint number + * @dir: endpoint direction + * @value: true => stall, false => unstall + * + * This function returns an error code + */ +static int hw_ep_set_halt(struct ci13xxx *udc, int num, int dir, int value) +{ + if (value != 0 && value != 1) + return -EINVAL; + + do { + enum ci13xxx_regs reg = OP_ENDPTCTRL + num; + u32 mask_xs = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS; + u32 mask_xr = dir ? ENDPTCTRL_TXR : ENDPTCTRL_RXR; + + /* data toggle - reserved for EP0 but it's in ESS */ + hw_write(udc, reg, mask_xs|mask_xr, + value ? mask_xs : mask_xr); + } while (value != hw_ep_get_halt(udc, num, dir)); + + return 0; +} + +/** + * hw_is_port_high_speed: test if port is high speed + * + * This function returns true if high speed port + */ +static int hw_port_is_high_speed(struct ci13xxx *udc) +{ + return udc->hw_bank.lpm ? hw_read(udc, OP_DEVLC, DEVLC_PSPD) : + hw_read(udc, OP_PORTSC, PORTSC_HSP); +} + +/** + * hw_read_intr_enable: returns interrupt enable register + * + * This function returns register data + */ +static u32 hw_read_intr_enable(struct ci13xxx *udc) +{ + return hw_read(udc, OP_USBINTR, ~0); +} + +/** + * hw_read_intr_status: returns interrupt status register + * + * This function returns register data + */ +static u32 hw_read_intr_status(struct ci13xxx *udc) +{ + return hw_read(udc, OP_USBSTS, ~0); +} + +/** + * hw_test_and_clear_complete: test & clear complete status (execute without + * interruption) + * @n: endpoint number + * + * This function returns complete status + */ +static int hw_test_and_clear_complete(struct ci13xxx *udc, int n) +{ + n = ep_to_bit(udc, n); + return hw_test_and_clear(udc, OP_ENDPTCOMPLETE, BIT(n)); +} + +/** + * hw_test_and_clear_intr_active: test & clear active interrupts (execute + * without interruption) + * + * This function returns active interrutps + */ +static u32 hw_test_and_clear_intr_active(struct ci13xxx *udc) +{ + u32 reg = hw_read_intr_status(udc) & hw_read_intr_enable(udc); + + hw_write(udc, OP_USBSTS, ~0, reg); + return reg; +} + +/** + * hw_test_and_clear_setup_guard: test & clear setup guard (execute without + * interruption) + * + * This function returns guard value + */ +static int hw_test_and_clear_setup_guard(struct ci13xxx *udc) +{ + return hw_test_and_write(udc, OP_USBCMD, USBCMD_SUTW, 0); +} + +/** + * hw_test_and_set_setup_guard: test & set setup guard (execute without + * interruption) + * + * This function returns guard value + */ +static int hw_test_and_set_setup_guard(struct ci13xxx *udc) +{ + return hw_test_and_write(udc, OP_USBCMD, USBCMD_SUTW, USBCMD_SUTW); +} + +/** + * hw_usb_set_address: configures USB address (execute without interruption) + * @value: new USB address + * + * This function explicitly sets the address, without the "USBADRA" (advance) + * feature, which is not supported by older versions of the controller. + */ +static void hw_usb_set_address(struct ci13xxx *udc, u8 value) +{ + hw_write(udc, OP_DEVICEADDR, DEVICEADDR_USBADR, + value << ffs_nr(DEVICEADDR_USBADR)); +} + +/** + * hw_usb_reset: restart device after a bus reset (execute without + * interruption) + * + * This function returns an error code + */ +static int hw_usb_reset(struct ci13xxx *udc) +{ + hw_usb_set_address(udc, 0); + + /* ESS flushes only at end?!? */ + hw_write(udc, OP_ENDPTFLUSH, ~0, ~0); + + /* clear setup token semaphores */ + hw_write(udc, OP_ENDPTSETUPSTAT, 0, 0); + + /* clear complete status */ + hw_write(udc, OP_ENDPTCOMPLETE, 0, 0); + + /* wait until all bits cleared */ + while (hw_read(udc, OP_ENDPTPRIME, ~0)) + udelay(10); /* not RTOS friendly */ + + /* reset all endpoints ? */ + + /* reset internal status and wait for further instructions + no need to verify the port reset status (ESS does it) */ + + return 0; +} + +/****************************************************************************** + * UTIL block + *****************************************************************************/ +/** + * _usb_addr: calculates endpoint address from direction & number + * @ep: endpoint + */ +static inline u8 _usb_addr(struct ci13xxx_ep *ep) +{ + return ((ep->dir == TX) ? USB_ENDPOINT_DIR_MASK : 0) | ep->num; +} + +/** + * _hardware_queue: configures a request at hardware level + * @gadget: gadget + * @mEp: endpoint + * + * This function returns an error code + */ +static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) +{ + struct ci13xxx *udc = mEp->udc; + unsigned i; + int ret = 0; + unsigned length = mReq->req.length; + + /* don't queue twice */ + if (mReq->req.status == -EALREADY) + return -EALREADY; + + mReq->req.status = -EALREADY; + + if (mReq->req.zero && length && (length % mEp->ep.maxpacket == 0)) { + mReq->zptr = dma_pool_alloc(mEp->td_pool, GFP_ATOMIC, + &mReq->zdma); + if (mReq->zptr == NULL) + return -ENOMEM; + + memset(mReq->zptr, 0, sizeof(*mReq->zptr)); + mReq->zptr->next = TD_TERMINATE; + mReq->zptr->token = TD_STATUS_ACTIVE; + if (!mReq->req.no_interrupt) + mReq->zptr->token |= TD_IOC; + } + ret = usb_gadget_map_request(&udc->gadget, &mReq->req, mEp->dir); + if (ret) + return ret; + + /* + * TD configuration + * TODO - handle requests which spawns into several TDs + */ + memset(mReq->ptr, 0, sizeof(*mReq->ptr)); + mReq->ptr->token = length << ffs_nr(TD_TOTAL_BYTES); + mReq->ptr->token &= TD_TOTAL_BYTES; + mReq->ptr->token |= TD_STATUS_ACTIVE; + if (mReq->zptr) { + mReq->ptr->next = mReq->zdma; + } else { + mReq->ptr->next = TD_TERMINATE; + if (!mReq->req.no_interrupt) + mReq->ptr->token |= TD_IOC; + } + mReq->ptr->page[0] = mReq->req.dma; + for (i = 1; i < 5; i++) + mReq->ptr->page[i] = + (mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK; + + if (!list_empty(&mEp->qh.queue)) { + struct ci13xxx_req *mReqPrev; + int n = hw_ep_bit(mEp->num, mEp->dir); + int tmp_stat; + + mReqPrev = list_entry(mEp->qh.queue.prev, + struct ci13xxx_req, queue); + if (mReqPrev->zptr) + mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK; + else + mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK; + wmb(); + if (hw_read(udc, OP_ENDPTPRIME, BIT(n))) + goto done; + do { + hw_write(udc, OP_USBCMD, USBCMD_ATDTW, USBCMD_ATDTW); + tmp_stat = hw_read(udc, OP_ENDPTSTAT, BIT(n)); + } while (!hw_read(udc, OP_USBCMD, USBCMD_ATDTW)); + hw_write(udc, OP_USBCMD, USBCMD_ATDTW, 0); + if (tmp_stat) + goto done; + } + + /* QH configuration */ + mEp->qh.ptr->td.next = mReq->dma; /* TERMINATE = 0 */ + mEp->qh.ptr->td.token &= ~TD_STATUS; /* clear status */ + mEp->qh.ptr->cap |= QH_ZLT; + + wmb(); /* synchronize before ep prime */ + + ret = hw_ep_prime(udc, mEp->num, mEp->dir, + mEp->type == USB_ENDPOINT_XFER_CONTROL); +done: + return ret; +} + +/** + * _hardware_dequeue: handles a request at hardware level + * @gadget: gadget + * @mEp: endpoint + * + * This function returns an error code + */ +static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) +{ + if (mReq->req.status != -EALREADY) + return -EINVAL; + + if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0) + return -EBUSY; + + if (mReq->zptr) { + if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0) + return -EBUSY; + dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma); + mReq->zptr = NULL; + } + + mReq->req.status = 0; + + usb_gadget_unmap_request(&mEp->udc->gadget, &mReq->req, mEp->dir); + + mReq->req.status = mReq->ptr->token & TD_STATUS; + if ((TD_STATUS_HALTED & mReq->req.status) != 0) + mReq->req.status = -1; + else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0) + mReq->req.status = -1; + else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0) + mReq->req.status = -1; + + mReq->req.actual = mReq->ptr->token & TD_TOTAL_BYTES; + mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES); + mReq->req.actual = mReq->req.length - mReq->req.actual; + mReq->req.actual = mReq->req.status ? 0 : mReq->req.actual; + + return mReq->req.actual; +} + +/** + * _ep_nuke: dequeues all endpoint requests + * @mEp: endpoint + * + * This function returns an error code + * Caller must hold lock + */ +static int _ep_nuke(struct ci13xxx_ep *mEp) +__releases(mEp->lock) +__acquires(mEp->lock) +{ + if (mEp == NULL) + return -EINVAL; + + hw_ep_flush(mEp->udc, mEp->num, mEp->dir); + + while (!list_empty(&mEp->qh.queue)) { + + /* pop oldest request */ + struct ci13xxx_req *mReq = \ + list_entry(mEp->qh.queue.next, + struct ci13xxx_req, queue); + list_del_init(&mReq->queue); + mReq->req.status = -ESHUTDOWN; + + if (mReq->req.complete != NULL) { + spin_unlock(mEp->lock); + mReq->req.complete(&mEp->ep, &mReq->req); + spin_lock(mEp->lock); + } + } + return 0; +} + +/** + * _gadget_stop_activity: stops all USB activity, flushes & disables all endpts + * @gadget: gadget + * + * This function returns an error code + */ +static int _gadget_stop_activity(struct usb_gadget *gadget) +{ + struct usb_ep *ep; + struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget); + unsigned long flags; + + spin_lock_irqsave(&udc->lock, flags); + udc->gadget.speed = USB_SPEED_UNKNOWN; + udc->remote_wakeup = 0; + udc->suspended = 0; + spin_unlock_irqrestore(&udc->lock, flags); + + /* flush all endpoints */ + gadget_for_each_ep(ep, gadget) { + usb_ep_fifo_flush(ep); + } + usb_ep_fifo_flush(&udc->ep0out->ep); + usb_ep_fifo_flush(&udc->ep0in->ep); + + if (udc->driver) + udc->driver->disconnect(gadget); + + /* make sure to disable all endpoints */ + gadget_for_each_ep(ep, gadget) { + usb_ep_disable(ep); + } + + if (udc->status != NULL) { + usb_ep_free_request(&udc->ep0in->ep, udc->status); + udc->status = NULL; + } + + return 0; +} + +/****************************************************************************** + * ISR block + *****************************************************************************/ +/** + * isr_reset_handler: USB reset interrupt handler + * @udc: UDC device + * + * This function resets USB engine after a bus reset occurred + */ +static void isr_reset_handler(struct ci13xxx *udc) +__releases(udc->lock) +__acquires(udc->lock) +{ + int retval; + + dbg_event(0xFF, "BUS RST", 0); + + spin_unlock(&udc->lock); + retval = _gadget_stop_activity(&udc->gadget); + if (retval) + goto done; + + retval = hw_usb_reset(udc); + if (retval) + goto done; + + udc->status = usb_ep_alloc_request(&udc->ep0in->ep, GFP_ATOMIC); + if (udc->status == NULL) + retval = -ENOMEM; + +done: + spin_lock(&udc->lock); + + if (retval) + dev_err(udc->dev, "error: %i\n", retval); +} + +/** + * isr_get_status_complete: get_status request complete function + * @ep: endpoint + * @req: request handled + * + * Caller must release lock + */ +static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req) +{ + if (ep == NULL || req == NULL) + return; + + kfree(req->buf); + usb_ep_free_request(ep, req); +} + +/** + * isr_get_status_response: get_status request response + * @udc: udc struct + * @setup: setup request packet + * + * This function returns an error code + */ +static int isr_get_status_response(struct ci13xxx *udc, + struct usb_ctrlrequest *setup) +__releases(mEp->lock) +__acquires(mEp->lock) +{ + struct ci13xxx_ep *mEp = udc->ep0in; + struct usb_request *req = NULL; + gfp_t gfp_flags = GFP_ATOMIC; + int dir, num, retval; + + if (mEp == NULL || setup == NULL) + return -EINVAL; + + spin_unlock(mEp->lock); + req = usb_ep_alloc_request(&mEp->ep, gfp_flags); + spin_lock(mEp->lock); + if (req == NULL) + return -ENOMEM; + + req->complete = isr_get_status_complete; + req->length = 2; + req->buf = kzalloc(req->length, gfp_flags); + if (req->buf == NULL) { + retval = -ENOMEM; + goto err_free_req; + } + + if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) { + /* Assume that device is bus powered for now. */ + *(u16 *)req->buf = udc->remote_wakeup << 1; + retval = 0; + } else if ((setup->bRequestType & USB_RECIP_MASK) \ + == USB_RECIP_ENDPOINT) { + dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ? + TX : RX; + num = le16_to_cpu(setup->wIndex) & USB_ENDPOINT_NUMBER_MASK; + *(u16 *)req->buf = hw_ep_get_halt(udc, num, dir); + } + /* else do nothing; reserved for future use */ + + spin_unlock(mEp->lock); + retval = usb_ep_queue(&mEp->ep, req, gfp_flags); + spin_lock(mEp->lock); + if (retval) + goto err_free_buf; + + return 0; + + err_free_buf: + kfree(req->buf); + err_free_req: + spin_unlock(mEp->lock); + usb_ep_free_request(&mEp->ep, req); + spin_lock(mEp->lock); + return retval; +} + +/** + * isr_setup_status_complete: setup_status request complete function + * @ep: endpoint + * @req: request handled + * + * Caller must release lock. Put the port in test mode if test mode + * feature is selected. + */ +static void +isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct ci13xxx *udc = req->context; + unsigned long flags; + + if (udc->setaddr) { + hw_usb_set_address(udc, udc->address); + udc->setaddr = false; + } + + spin_lock_irqsave(&udc->lock, flags); + if (udc->test_mode) + hw_port_test_set(udc, udc->test_mode); + spin_unlock_irqrestore(&udc->lock, flags); +} + +/** + * isr_setup_status_phase: queues the status phase of a setup transation + * @udc: udc struct + * + * This function returns an error code + */ +static int isr_setup_status_phase(struct ci13xxx *udc) +__releases(mEp->lock) +__acquires(mEp->lock) +{ + int retval; + struct ci13xxx_ep *mEp; + + mEp = (udc->ep0_dir == TX) ? udc->ep0out : udc->ep0in; + udc->status->context = udc; + udc->status->complete = isr_setup_status_complete; + + spin_unlock(mEp->lock); + retval = usb_ep_queue(&mEp->ep, udc->status, GFP_ATOMIC); + spin_lock(mEp->lock); + + return retval; +} + +/** + * isr_tr_complete_low: transaction complete low level handler + * @mEp: endpoint + * + * This function returns an error code + * Caller must hold lock + */ +static int isr_tr_complete_low(struct ci13xxx_ep *mEp) +__releases(mEp->lock) +__acquires(mEp->lock) +{ + struct ci13xxx_req *mReq, *mReqTemp; + struct ci13xxx_ep *mEpTemp = mEp; + int uninitialized_var(retval); + + if (list_empty(&mEp->qh.queue)) + return -EINVAL; + + list_for_each_entry_safe(mReq, mReqTemp, &mEp->qh.queue, + queue) { + retval = _hardware_dequeue(mEp, mReq); + if (retval < 0) + break; + list_del_init(&mReq->queue); + dbg_done(_usb_addr(mEp), mReq->ptr->token, retval); + if (mReq->req.complete != NULL) { + spin_unlock(mEp->lock); + if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) && + mReq->req.length) + mEpTemp = mEp->udc->ep0in; + mReq->req.complete(&mEpTemp->ep, &mReq->req); + spin_lock(mEp->lock); + } + } + + if (retval == -EBUSY) + retval = 0; + if (retval < 0) + dbg_event(_usb_addr(mEp), "DONE", retval); + + return retval; +} + +/** + * isr_tr_complete_handler: transaction complete interrupt handler + * @udc: UDC descriptor + * + * This function handles traffic events + */ +static void isr_tr_complete_handler(struct ci13xxx *udc) +__releases(udc->lock) +__acquires(udc->lock) +{ + unsigned i; + u8 tmode = 0; + + for (i = 0; i < udc->hw_ep_max; i++) { + struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i]; + int type, num, dir, err = -EINVAL; + struct usb_ctrlrequest req; + + if (mEp->ep.desc == NULL) + continue; /* not configured */ + + if (hw_test_and_clear_complete(udc, i)) { + err = isr_tr_complete_low(mEp); + if (mEp->type == USB_ENDPOINT_XFER_CONTROL) { + if (err > 0) /* needs status phase */ + err = isr_setup_status_phase(udc); + if (err < 0) { + dbg_event(_usb_addr(mEp), + "ERROR", err); + spin_unlock(&udc->lock); + if (usb_ep_set_halt(&mEp->ep)) + dev_err(udc->dev, + "error: ep_set_halt\n"); + spin_lock(&udc->lock); + } + } + } + + if (mEp->type != USB_ENDPOINT_XFER_CONTROL || + !hw_test_and_clear_setup_status(udc, i)) + continue; + + if (i != 0) { + dev_warn(udc->dev, "ctrl traffic at endpoint %d\n", i); + continue; + } + + /* + * Flush data and handshake transactions of previous + * setup packet. + */ + _ep_nuke(udc->ep0out); + _ep_nuke(udc->ep0in); + + /* read_setup_packet */ + do { + hw_test_and_set_setup_guard(udc); + memcpy(&req, &mEp->qh.ptr->setup, sizeof(req)); + } while (!hw_test_and_clear_setup_guard(udc)); + + type = req.bRequestType; + + udc->ep0_dir = (type & USB_DIR_IN) ? TX : RX; + + dbg_setup(_usb_addr(mEp), &req); + + switch (req.bRequest) { + case USB_REQ_CLEAR_FEATURE: + if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) && + le16_to_cpu(req.wValue) == + USB_ENDPOINT_HALT) { + if (req.wLength != 0) + break; + num = le16_to_cpu(req.wIndex); + dir = num & USB_ENDPOINT_DIR_MASK; + num &= USB_ENDPOINT_NUMBER_MASK; + if (dir) /* TX */ + num += udc->hw_ep_max/2; + if (!udc->ci13xxx_ep[num].wedge) { + spin_unlock(&udc->lock); + err = usb_ep_clear_halt( + &udc->ci13xxx_ep[num].ep); + spin_lock(&udc->lock); + if (err) + break; + } + err = isr_setup_status_phase(udc); + } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE) && + le16_to_cpu(req.wValue) == + USB_DEVICE_REMOTE_WAKEUP) { + if (req.wLength != 0) + break; + udc->remote_wakeup = 0; + err = isr_setup_status_phase(udc); + } else { + goto delegate; + } + break; + case USB_REQ_GET_STATUS: + if (type != (USB_DIR_IN|USB_RECIP_DEVICE) && + type != (USB_DIR_IN|USB_RECIP_ENDPOINT) && + type != (USB_DIR_IN|USB_RECIP_INTERFACE)) + goto delegate; + if (le16_to_cpu(req.wLength) != 2 || + le16_to_cpu(req.wValue) != 0) + break; + err = isr_get_status_response(udc, &req); + break; + case USB_REQ_SET_ADDRESS: + if (type != (USB_DIR_OUT|USB_RECIP_DEVICE)) + goto delegate; + if (le16_to_cpu(req.wLength) != 0 || + le16_to_cpu(req.wIndex) != 0) + break; + udc->address = (u8)le16_to_cpu(req.wValue); + udc->setaddr = true; + err = isr_setup_status_phase(udc); + break; + case USB_REQ_SET_FEATURE: + if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) && + le16_to_cpu(req.wValue) == + USB_ENDPOINT_HALT) { + if (req.wLength != 0) + break; + num = le16_to_cpu(req.wIndex); + dir = num & USB_ENDPOINT_DIR_MASK; + num &= USB_ENDPOINT_NUMBER_MASK; + if (dir) /* TX */ + num += udc->hw_ep_max/2; + + spin_unlock(&udc->lock); + err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep); + spin_lock(&udc->lock); + if (!err) + isr_setup_status_phase(udc); + } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE)) { + if (req.wLength != 0) + break; + switch (le16_to_cpu(req.wValue)) { + case USB_DEVICE_REMOTE_WAKEUP: + udc->remote_wakeup = 1; + err = isr_setup_status_phase(udc); + break; + case USB_DEVICE_TEST_MODE: + tmode = le16_to_cpu(req.wIndex) >> 8; + switch (tmode) { + case TEST_J: + case TEST_K: + case TEST_SE0_NAK: + case TEST_PACKET: + case TEST_FORCE_EN: + udc->test_mode = tmode; + err = isr_setup_status_phase( + udc); + break; + default: + break; + } + default: + goto delegate; + } + } else { + goto delegate; + } + break; + default: +delegate: + if (req.wLength == 0) /* no data phase */ + udc->ep0_dir = TX; + + spin_unlock(&udc->lock); + err = udc->driver->setup(&udc->gadget, &req); + spin_lock(&udc->lock); + break; + } + + if (err < 0) { + dbg_event(_usb_addr(mEp), "ERROR", err); + + spin_unlock(&udc->lock); + if (usb_ep_set_halt(&mEp->ep)) + dev_err(udc->dev, "error: ep_set_halt\n"); + spin_lock(&udc->lock); + } + } +} + +/****************************************************************************** + * ENDPT block + *****************************************************************************/ +/** + * ep_enable: configure endpoint, making it usable + * + * Check usb_ep_enable() at "usb_gadget.h" for details + */ +static int ep_enable(struct usb_ep *ep, + const struct usb_endpoint_descriptor *desc) +{ + struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); + int retval = 0; + unsigned long flags; + + if (ep == NULL || desc == NULL) + return -EINVAL; + + spin_lock_irqsave(mEp->lock, flags); + + /* only internal SW should enable ctrl endpts */ + + mEp->ep.desc = desc; + + if (!list_empty(&mEp->qh.queue)) + dev_warn(mEp->udc->dev, "enabling a non-empty endpoint!\n"); + + mEp->dir = usb_endpoint_dir_in(desc) ? TX : RX; + mEp->num = usb_endpoint_num(desc); + mEp->type = usb_endpoint_type(desc); + + mEp->ep.maxpacket = usb_endpoint_maxp(desc); + + dbg_event(_usb_addr(mEp), "ENABLE", 0); + + mEp->qh.ptr->cap = 0; + + if (mEp->type == USB_ENDPOINT_XFER_CONTROL) + mEp->qh.ptr->cap |= QH_IOS; + else if (mEp->type == USB_ENDPOINT_XFER_ISOC) + mEp->qh.ptr->cap &= ~QH_MULT; + else + mEp->qh.ptr->cap &= ~QH_ZLT; + + mEp->qh.ptr->cap |= + (mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT; + mEp->qh.ptr->td.next |= TD_TERMINATE; /* needed? */ + + /* + * Enable endpoints in the HW other than ep0 as ep0 + * is always enabled + */ + if (mEp->num) + retval |= hw_ep_enable(mEp->udc, mEp->num, mEp->dir, mEp->type); + + spin_unlock_irqrestore(mEp->lock, flags); + return retval; +} + +/** + * ep_disable: endpoint is no longer usable + * + * Check usb_ep_disable() at "usb_gadget.h" for details + */ +static int ep_disable(struct usb_ep *ep) +{ + struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); + int direction, retval = 0; + unsigned long flags; + + if (ep == NULL) + return -EINVAL; + else if (mEp->ep.desc == NULL) + return -EBUSY; + + spin_lock_irqsave(mEp->lock, flags); + + /* only internal SW should disable ctrl endpts */ + + direction = mEp->dir; + do { + dbg_event(_usb_addr(mEp), "DISABLE", 0); + + retval |= _ep_nuke(mEp); + retval |= hw_ep_disable(mEp->udc, mEp->num, mEp->dir); + + if (mEp->type == USB_ENDPOINT_XFER_CONTROL) + mEp->dir = (mEp->dir == TX) ? RX : TX; + + } while (mEp->dir != direction); + + mEp->ep.desc = NULL; + + spin_unlock_irqrestore(mEp->lock, flags); + return retval; +} + +/** + * ep_alloc_request: allocate a request object to use with this endpoint + * + * Check usb_ep_alloc_request() at "usb_gadget.h" for details + */ +static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) +{ + struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); + struct ci13xxx_req *mReq = NULL; + + if (ep == NULL) + return NULL; + + mReq = kzalloc(sizeof(struct ci13xxx_req), gfp_flags); + if (mReq != NULL) { + INIT_LIST_HEAD(&mReq->queue); + + mReq->ptr = dma_pool_alloc(mEp->td_pool, gfp_flags, + &mReq->dma); + if (mReq->ptr == NULL) { + kfree(mReq); + mReq = NULL; + } + } + + dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL); + + return (mReq == NULL) ? NULL : &mReq->req; +} + +/** + * ep_free_request: frees a request object + * + * Check usb_ep_free_request() at "usb_gadget.h" for details + */ +static void ep_free_request(struct usb_ep *ep, struct usb_request *req) +{ + struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); + struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); + unsigned long flags; + + if (ep == NULL || req == NULL) { + return; + } else if (!list_empty(&mReq->queue)) { + dev_err(mEp->udc->dev, "freeing queued request\n"); + return; + } + + spin_lock_irqsave(mEp->lock, flags); + + if (mReq->ptr) + dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma); + kfree(mReq); + + dbg_event(_usb_addr(mEp), "FREE", 0); + + spin_unlock_irqrestore(mEp->lock, flags); +} + +/** + * ep_queue: queues (submits) an I/O request to an endpoint + * + * Check usb_ep_queue()* at usb_gadget.h" for details + */ +static int ep_queue(struct usb_ep *ep, struct usb_request *req, + gfp_t __maybe_unused gfp_flags) +{ + struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); + struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); + struct ci13xxx *udc = mEp->udc; + int retval = 0; + unsigned long flags; + + if (ep == NULL || req == NULL || mEp->ep.desc == NULL) + return -EINVAL; + + spin_lock_irqsave(mEp->lock, flags); + + if (mEp->type == USB_ENDPOINT_XFER_CONTROL) { + if (req->length) + mEp = (udc->ep0_dir == RX) ? + udc->ep0out : udc->ep0in; + if (!list_empty(&mEp->qh.queue)) { + _ep_nuke(mEp); + retval = -EOVERFLOW; + dev_warn(mEp->udc->dev, "endpoint ctrl %X nuked\n", + _usb_addr(mEp)); + } + } + + /* first nuke then test link, e.g. previous status has not sent */ + if (!list_empty(&mReq->queue)) { + retval = -EBUSY; + dev_err(mEp->udc->dev, "request already in queue\n"); + goto done; + } + + if (req->length > 4 * CI13XXX_PAGE_SIZE) { + req->length = 4 * CI13XXX_PAGE_SIZE; + retval = -EMSGSIZE; + dev_warn(mEp->udc->dev, "request length truncated\n"); + } + + dbg_queue(_usb_addr(mEp), req, retval); + + /* push request */ + mReq->req.status = -EINPROGRESS; + mReq->req.actual = 0; + + retval = _hardware_enqueue(mEp, mReq); + + if (retval == -EALREADY) { + dbg_event(_usb_addr(mEp), "QUEUE", retval); + retval = 0; + } + if (!retval) + list_add_tail(&mReq->queue, &mEp->qh.queue); + + done: + spin_unlock_irqrestore(mEp->lock, flags); + return retval; +} + +/** + * ep_dequeue: dequeues (cancels, unlinks) an I/O request from an endpoint + * + * Check usb_ep_dequeue() at "usb_gadget.h" for details + */ +static int ep_dequeue(struct usb_ep *ep, struct usb_request *req) +{ + struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); + struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); + unsigned long flags; + + if (ep == NULL || req == NULL || mReq->req.status != -EALREADY || + mEp->ep.desc == NULL || list_empty(&mReq->queue) || + list_empty(&mEp->qh.queue)) + return -EINVAL; + + spin_lock_irqsave(mEp->lock, flags); + + dbg_event(_usb_addr(mEp), "DEQUEUE", 0); + + hw_ep_flush(mEp->udc, mEp->num, mEp->dir); + + /* pop request */ + list_del_init(&mReq->queue); + + usb_gadget_unmap_request(&mEp->udc->gadget, req, mEp->dir); + + req->status = -ECONNRESET; + + if (mReq->req.complete != NULL) { + spin_unlock(mEp->lock); + mReq->req.complete(&mEp->ep, &mReq->req); + spin_lock(mEp->lock); + } + + spin_unlock_irqrestore(mEp->lock, flags); + return 0; +} + +/** + * ep_set_halt: sets the endpoint halt feature + * + * Check usb_ep_set_halt() at "usb_gadget.h" for details + */ +static int ep_set_halt(struct usb_ep *ep, int value) +{ + struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); + int direction, retval = 0; + unsigned long flags; + + if (ep == NULL || mEp->ep.desc == NULL) + return -EINVAL; + + spin_lock_irqsave(mEp->lock, flags); + +#ifndef STALL_IN + /* g_file_storage MS compliant but g_zero fails chapter 9 compliance */ + if (value && mEp->type == USB_ENDPOINT_XFER_BULK && mEp->dir == TX && + !list_empty(&mEp->qh.queue)) { + spin_unlock_irqrestore(mEp->lock, flags); + return -EAGAIN; + } +#endif + + direction = mEp->dir; + do { + dbg_event(_usb_addr(mEp), "HALT", value); + retval |= hw_ep_set_halt(mEp->udc, mEp->num, mEp->dir, value); + + if (!value) + mEp->wedge = 0; + + if (mEp->type == USB_ENDPOINT_XFER_CONTROL) + mEp->dir = (mEp->dir == TX) ? RX : TX; + + } while (mEp->dir != direction); + + spin_unlock_irqrestore(mEp->lock, flags); + return retval; +} + +/** + * ep_set_wedge: sets the halt feature and ignores clear requests + * + * Check usb_ep_set_wedge() at "usb_gadget.h" for details + */ +static int ep_set_wedge(struct usb_ep *ep) +{ + struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); + unsigned long flags; + + if (ep == NULL || mEp->ep.desc == NULL) + return -EINVAL; + + spin_lock_irqsave(mEp->lock, flags); + + dbg_event(_usb_addr(mEp), "WEDGE", 0); + mEp->wedge = 1; + + spin_unlock_irqrestore(mEp->lock, flags); + + return usb_ep_set_halt(ep); +} + +/** + * ep_fifo_flush: flushes contents of a fifo + * + * Check usb_ep_fifo_flush() at "usb_gadget.h" for details + */ +static void ep_fifo_flush(struct usb_ep *ep) +{ + struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); + unsigned long flags; + + if (ep == NULL) { + dev_err(mEp->udc->dev, "%02X: -EINVAL\n", _usb_addr(mEp)); + return; + } + + spin_lock_irqsave(mEp->lock, flags); + + dbg_event(_usb_addr(mEp), "FFLUSH", 0); + hw_ep_flush(mEp->udc, mEp->num, mEp->dir); + + spin_unlock_irqrestore(mEp->lock, flags); +} + +/** + * Endpoint-specific part of the API to the USB controller hardware + * Check "usb_gadget.h" for details + */ +static const struct usb_ep_ops usb_ep_ops = { + .enable = ep_enable, + .disable = ep_disable, + .alloc_request = ep_alloc_request, + .free_request = ep_free_request, + .queue = ep_queue, + .dequeue = ep_dequeue, + .set_halt = ep_set_halt, + .set_wedge = ep_set_wedge, + .fifo_flush = ep_fifo_flush, +}; + +/****************************************************************************** + * GADGET block + *****************************************************************************/ +static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active) +{ + struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget); + unsigned long flags; + int gadget_ready = 0; + + if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS)) + return -EOPNOTSUPP; + + spin_lock_irqsave(&udc->lock, flags); + udc->vbus_active = is_active; + if (udc->driver) + gadget_ready = 1; + spin_unlock_irqrestore(&udc->lock, flags); + + if (gadget_ready) { + if (is_active) { + pm_runtime_get_sync(&_gadget->dev); + hw_device_reset(udc, USBMODE_CM_DC); + hw_device_state(udc, udc->ep0out->qh.dma); + } else { + hw_device_state(udc, 0); + if (udc->udc_driver->notify_event) + udc->udc_driver->notify_event(udc, + CI13XXX_CONTROLLER_STOPPED_EVENT); + _gadget_stop_activity(&udc->gadget); + pm_runtime_put_sync(&_gadget->dev); + } + } + + return 0; +} + +static int ci13xxx_wakeup(struct usb_gadget *_gadget) +{ + struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget); + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&udc->lock, flags); + if (!udc->remote_wakeup) { + ret = -EOPNOTSUPP; + goto out; + } + if (!hw_read(udc, OP_PORTSC, PORTSC_SUSP)) { + ret = -EINVAL; + goto out; + } + hw_write(udc, OP_PORTSC, PORTSC_FPR, PORTSC_FPR); +out: + spin_unlock_irqrestore(&udc->lock, flags); + return ret; +} + +static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA) +{ + struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget); + + if (udc->transceiver) + return usb_phy_set_power(udc->transceiver, mA); + return -ENOTSUPP; +} + +static int ci13xxx_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver); +static int ci13xxx_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver); +/** + * Device operations part of the API to the USB controller hardware, + * which don't involve endpoints (or i/o) + * Check "usb_gadget.h" for details + */ +static const struct usb_gadget_ops usb_gadget_ops = { + .vbus_session = ci13xxx_vbus_session, + .wakeup = ci13xxx_wakeup, + .vbus_draw = ci13xxx_vbus_draw, + .udc_start = ci13xxx_start, + .udc_stop = ci13xxx_stop, +}; + +static int init_eps(struct ci13xxx *udc) +{ + int retval = 0, i, j; + + for (i = 0; i < udc->hw_ep_max/2; i++) + for (j = RX; j <= TX; j++) { + int k = i + j * udc->hw_ep_max/2; + struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[k]; + + scnprintf(mEp->name, sizeof(mEp->name), "ep%i%s", i, + (j == TX) ? "in" : "out"); + + mEp->udc = udc; + mEp->lock = &udc->lock; + mEp->td_pool = udc->td_pool; + + mEp->ep.name = mEp->name; + mEp->ep.ops = &usb_ep_ops; + mEp->ep.maxpacket = CTRL_PAYLOAD_MAX; + + INIT_LIST_HEAD(&mEp->qh.queue); + mEp->qh.ptr = dma_pool_alloc(udc->qh_pool, GFP_KERNEL, + &mEp->qh.dma); + if (mEp->qh.ptr == NULL) + retval = -ENOMEM; + else + memset(mEp->qh.ptr, 0, sizeof(*mEp->qh.ptr)); + + /* + * set up shorthands for ep0 out and in endpoints, + * don't add to gadget's ep_list + */ + if (i == 0) { + if (j == RX) + udc->ep0out = mEp; + else + udc->ep0in = mEp; + + continue; + } + + list_add_tail(&mEp->ep.ep_list, &udc->gadget.ep_list); + } + + return retval; +} + +/** + * ci13xxx_start: register a gadget driver + * @gadget: our gadget + * @driver: the driver being registered + * + * Interrupts are enabled here. + */ +static int ci13xxx_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) +{ + struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget); + unsigned long flags; + int retval = -ENOMEM; + + if (driver->disconnect == NULL) + return -EINVAL; + + + udc->ep0out->ep.desc = &ctrl_endpt_out_desc; + retval = usb_ep_enable(&udc->ep0out->ep); + if (retval) + return retval; + + udc->ep0in->ep.desc = &ctrl_endpt_in_desc; + retval = usb_ep_enable(&udc->ep0in->ep); + if (retval) + return retval; + spin_lock_irqsave(&udc->lock, flags); + + udc->driver = driver; + pm_runtime_get_sync(&udc->gadget.dev); + if (udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) { + if (udc->vbus_active) { + if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) + hw_device_reset(udc, USBMODE_CM_DC); + } else { + pm_runtime_put_sync(&udc->gadget.dev); + goto done; + } + } + + retval = hw_device_state(udc, udc->ep0out->qh.dma); + if (retval) + pm_runtime_put_sync(&udc->gadget.dev); + + done: + spin_unlock_irqrestore(&udc->lock, flags); + return retval; +} + +/** + * ci13xxx_stop: unregister a gadget driver + */ +static int ci13xxx_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) +{ + struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget); + unsigned long flags; + + spin_lock_irqsave(&udc->lock, flags); + + if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) || + udc->vbus_active) { + hw_device_state(udc, 0); + if (udc->udc_driver->notify_event) + udc->udc_driver->notify_event(udc, + CI13XXX_CONTROLLER_STOPPED_EVENT); + udc->driver = NULL; + spin_unlock_irqrestore(&udc->lock, flags); + _gadget_stop_activity(&udc->gadget); + spin_lock_irqsave(&udc->lock, flags); + pm_runtime_put(&udc->gadget.dev); + } + + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +/****************************************************************************** + * BUS block + *****************************************************************************/ +/** + * udc_irq: udc interrupt handler + * + * This function returns IRQ_HANDLED if the IRQ has been handled + * It locks access to registers + */ +static irqreturn_t udc_irq(struct ci13xxx *udc) +{ + irqreturn_t retval; + u32 intr; + + if (udc == NULL) + return IRQ_HANDLED; + + spin_lock(&udc->lock); + + if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) { + if (hw_read(udc, OP_USBMODE, USBMODE_CM) != + USBMODE_CM_DC) { + spin_unlock(&udc->lock); + return IRQ_NONE; + } + } + intr = hw_test_and_clear_intr_active(udc); + dbg_interrupt(intr); + + if (intr) { + /* order defines priority - do NOT change it */ + if (USBi_URI & intr) + isr_reset_handler(udc); + + if (USBi_PCI & intr) { + udc->gadget.speed = hw_port_is_high_speed(udc) ? + USB_SPEED_HIGH : USB_SPEED_FULL; + if (udc->suspended && udc->driver->resume) { + spin_unlock(&udc->lock); + udc->driver->resume(&udc->gadget); + spin_lock(&udc->lock); + udc->suspended = 0; + } + } + + if (USBi_UI & intr) + isr_tr_complete_handler(udc); + + if (USBi_SLI & intr) { + if (udc->gadget.speed != USB_SPEED_UNKNOWN && + udc->driver->suspend) { + udc->suspended = 1; + spin_unlock(&udc->lock); + udc->driver->suspend(&udc->gadget); + spin_lock(&udc->lock); + } + } + retval = IRQ_HANDLED; + } else { + retval = IRQ_NONE; + } + spin_unlock(&udc->lock); + + return retval; +} + +/** + * udc_release: driver release function + * @dev: device + * + * Currently does nothing + */ +static void udc_release(struct device *dev) +{ +} + +/** + * udc_start: initialize gadget role + * @udc: chipidea controller + */ +static int udc_start(struct ci13xxx *udc) +{ + struct device *dev = udc->dev; + int retval = 0; + + if (!udc) + return -EINVAL; + + spin_lock_init(&udc->lock); + + udc->gadget.ops = &usb_gadget_ops; + udc->gadget.speed = USB_SPEED_UNKNOWN; + udc->gadget.max_speed = USB_SPEED_HIGH; + udc->gadget.is_otg = 0; + udc->gadget.name = udc->udc_driver->name; + + INIT_LIST_HEAD(&udc->gadget.ep_list); + + dev_set_name(&udc->gadget.dev, "gadget"); + udc->gadget.dev.dma_mask = dev->dma_mask; + udc->gadget.dev.coherent_dma_mask = dev->coherent_dma_mask; + udc->gadget.dev.parent = dev; + udc->gadget.dev.release = udc_release; + + /* alloc resources */ + udc->qh_pool = dma_pool_create("ci13xxx_qh", dev, + sizeof(struct ci13xxx_qh), + 64, CI13XXX_PAGE_SIZE); + if (udc->qh_pool == NULL) + return -ENOMEM; + + udc->td_pool = dma_pool_create("ci13xxx_td", dev, + sizeof(struct ci13xxx_td), + 64, CI13XXX_PAGE_SIZE); + if (udc->td_pool == NULL) { + retval = -ENOMEM; + goto free_qh_pool; + } + + retval = init_eps(udc); + if (retval) + goto free_pools; + + udc->gadget.ep0 = &udc->ep0in->ep; + + udc->transceiver = usb_get_transceiver(); + + if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) { + if (udc->transceiver == NULL) { + retval = -ENODEV; + goto free_pools; + } + } + + if (!(udc->udc_driver->flags & CI13XXX_REGS_SHARED)) { + retval = hw_device_reset(udc, USBMODE_CM_DC); + if (retval) + goto put_transceiver; + } + + retval = device_register(&udc->gadget.dev); + if (retval) { + put_device(&udc->gadget.dev); + goto put_transceiver; + } + + retval = dbg_create_files(&udc->gadget.dev); + if (retval) + goto unreg_device; + + if (udc->transceiver) { + retval = otg_set_peripheral(udc->transceiver->otg, + &udc->gadget); + if (retval) + goto remove_dbg; + } + + retval = usb_add_gadget_udc(dev, &udc->gadget); + if (retval) + goto remove_trans; + + pm_runtime_no_callbacks(&udc->gadget.dev); + pm_runtime_enable(&udc->gadget.dev); + + return retval; + +remove_trans: + if (udc->transceiver) { + otg_set_peripheral(udc->transceiver->otg, &udc->gadget); + usb_put_transceiver(udc->transceiver); + } + + dev_err(dev, "error = %i\n", retval); +remove_dbg: + dbg_remove_files(&udc->gadget.dev); +unreg_device: + device_unregister(&udc->gadget.dev); +put_transceiver: + if (udc->transceiver) + usb_put_transceiver(udc->transceiver); +free_pools: + dma_pool_destroy(udc->td_pool); +free_qh_pool: + dma_pool_destroy(udc->qh_pool); + return retval; +} + +/** + * udc_remove: parent remove must call this to remove UDC + * + * No interrupts active, the IRQ has been released + */ +static void udc_stop(struct ci13xxx *udc) +{ + int i; + + if (udc == NULL) + return; + + usb_del_gadget_udc(&udc->gadget); + + for (i = 0; i < udc->hw_ep_max; i++) { + struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i]; + + dma_pool_free(udc->qh_pool, mEp->qh.ptr, mEp->qh.dma); + } + + dma_pool_destroy(udc->td_pool); + dma_pool_destroy(udc->qh_pool); + + if (udc->transceiver) { + otg_set_peripheral(udc->transceiver->otg, NULL); + usb_put_transceiver(udc->transceiver); + } + dbg_remove_files(&udc->gadget.dev); + device_unregister(&udc->gadget.dev); + /* my kobject is dynamic, I swear! */ + memset(&udc->gadget, 0, sizeof(udc->gadget)); +} + +/** + * ci_hdrc_gadget_init - initialize device related bits + * ci: the controller + * + * This function enables the gadget role, if the device is "device capable". + */ +int ci_hdrc_gadget_init(struct ci13xxx *ci) +{ + struct ci_role_driver *rdrv; + + if (!hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DC)) + return -ENXIO; + + rdrv = devm_kzalloc(ci->dev, sizeof(struct ci_role_driver), GFP_KERNEL); + if (!rdrv) + return -ENOMEM; + + rdrv->start = udc_start; + rdrv->stop = udc_stop; + rdrv->irq = udc_irq; + rdrv->name = "gadget"; + ci->roles[CI_ROLE_GADGET] = rdrv; + + return 0; +} diff --git a/trunk/drivers/usb/chipidea/udc.h b/trunk/drivers/usb/chipidea/udc.h new file mode 100644 index 000000000000..4ff2384d7ca8 --- /dev/null +++ b/trunk/drivers/usb/chipidea/udc.h @@ -0,0 +1,93 @@ +/* + * udc.h - ChipIdea UDC structures + * + * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. + * + * Author: David Lopo + * + * 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_UDC_H +#define __DRIVERS_USB_CHIPIDEA_UDC_H + +#include + +#define CTRL_PAYLOAD_MAX 64 +#define RX 0 /* similar to USB_DIR_OUT but can be used as an index */ +#define TX 1 /* similar to USB_DIR_IN but can be used as an index */ + +/* DMA layout of transfer descriptors */ +struct ci13xxx_td { + /* 0 */ + u32 next; +#define TD_TERMINATE BIT(0) +#define TD_ADDR_MASK (0xFFFFFFEUL << 5) + /* 1 */ + u32 token; +#define TD_STATUS (0x00FFUL << 0) +#define TD_STATUS_TR_ERR BIT(3) +#define TD_STATUS_DT_ERR BIT(5) +#define TD_STATUS_HALTED BIT(6) +#define TD_STATUS_ACTIVE BIT(7) +#define TD_MULTO (0x0003UL << 10) +#define TD_IOC BIT(15) +#define TD_TOTAL_BYTES (0x7FFFUL << 16) + /* 2 */ + u32 page[5]; +#define TD_CURR_OFFSET (0x0FFFUL << 0) +#define TD_FRAME_NUM (0x07FFUL << 0) +#define TD_RESERVED_MASK (0x0FFFUL << 0) +} __attribute__ ((packed)); + +/* DMA layout of queue heads */ +struct ci13xxx_qh { + /* 0 */ + u32 cap; +#define QH_IOS BIT(15) +#define QH_MAX_PKT (0x07FFUL << 16) +#define QH_ZLT BIT(29) +#define QH_MULT (0x0003UL << 30) + /* 1 */ + u32 curr; + /* 2 - 8 */ + struct ci13xxx_td td; + /* 9 */ + u32 RESERVED; + struct usb_ctrlrequest setup; +} __attribute__ ((packed)); + +/** + * struct ci13xxx_req - usb request representation + * @req: request structure for gadget drivers + * @queue: link to QH list + * @ptr: transfer descriptor for this request + * @dma: dma address for the transfer descriptor + * @zptr: transfer descriptor for the zero packet + * @zdma: dma address of the zero packet's transfer descriptor + */ +struct ci13xxx_req { + struct usb_request req; + struct list_head queue; + struct ci13xxx_td *ptr; + dma_addr_t dma; + struct ci13xxx_td *zptr; + dma_addr_t zdma; +}; + +#ifdef CONFIG_USB_CHIPIDEA_UDC + +int ci_hdrc_gadget_init(struct ci13xxx *ci); + +#else + +static inline int ci_hdrc_gadget_init(struct ci13xxx *ci) +{ + return -ENXIO; +} + +#endif + +#endif /* __DRIVERS_USB_CHIPIDEA_UDC_H */ diff --git a/trunk/drivers/usb/class/cdc-acm.c b/trunk/drivers/usb/class/cdc-acm.c index b32ccb461019..f2a120eea9d4 100644 --- a/trunk/drivers/usb/class/cdc-acm.c +++ b/trunk/drivers/usb/class/cdc-acm.c @@ -1664,6 +1664,7 @@ static struct usb_driver acm_driver = { #ifdef CONFIG_PM .supports_autosuspend = 1, #endif + .disable_hub_initiated_lpm = 1, }; /* diff --git a/trunk/drivers/usb/class/cdc-wdm.c b/trunk/drivers/usb/class/cdc-wdm.c index 0bb2b3248dad..ea8b304f0e85 100644 --- a/trunk/drivers/usb/class/cdc-wdm.c +++ b/trunk/drivers/usb/class/cdc-wdm.c @@ -309,9 +309,6 @@ static void free_urbs(struct wdm_device *desc) static void cleanup(struct wdm_device *desc) { - spin_lock(&wdm_device_list_lock); - list_del(&desc->device_list); - spin_unlock(&wdm_device_list_lock); kfree(desc->sbuf); kfree(desc->inbuf); kfree(desc->orq); @@ -369,6 +366,7 @@ static ssize_t wdm_write r = usb_autopm_get_interface(desc->intf); if (r < 0) { kfree(buf); + rv = usb_translate_errors(r); goto outnp; } @@ -384,6 +382,7 @@ static ssize_t wdm_write if (r < 0) { kfree(buf); + rv = r; goto out; } @@ -415,6 +414,7 @@ static ssize_t wdm_write desc->outbuf = NULL; clear_bit(WDM_IN_USE, &desc->flags); dev_err(&desc->intf->dev, "Tx URB error: %d\n", rv); + rv = usb_translate_errors(rv); } else { dev_dbg(&desc->intf->dev, "Tx URB has been submitted index=%d", req->wIndex); @@ -530,11 +530,13 @@ static int wdm_flush(struct file *file, fl_owner_t id) struct wdm_device *desc = file->private_data; wait_event(desc->wait, !test_bit(WDM_IN_USE, &desc->flags)); - if (desc->werr < 0) + + /* cannot dereference desc->intf if WDM_DISCONNECTING */ + if (desc->werr < 0 && !test_bit(WDM_DISCONNECTING, &desc->flags)) dev_err(&desc->intf->dev, "Error in flush path: %d\n", desc->werr); - return desc->werr; + return usb_translate_errors(desc->werr); } static unsigned int wdm_poll(struct file *file, struct poll_table_struct *wait) @@ -545,7 +547,7 @@ static unsigned int wdm_poll(struct file *file, struct poll_table_struct *wait) spin_lock_irqsave(&desc->iuspin, flags); if (test_bit(WDM_DISCONNECTING, &desc->flags)) { - mask = POLLERR; + mask = POLLHUP | POLLERR; spin_unlock_irqrestore(&desc->iuspin, flags); goto desc_out; } @@ -596,6 +598,7 @@ static int wdm_open(struct inode *inode, struct file *file) desc->count--; dev_err(&desc->intf->dev, "Error submitting int urb - %d\n", rv); + rv = usb_translate_errors(rv); } } else { rv = 0; @@ -621,10 +624,15 @@ static int wdm_release(struct inode *inode, struct file *file) mutex_unlock(&desc->wlock); if (!desc->count) { - dev_dbg(&desc->intf->dev, "wdm_release: cleanup"); - kill_urbs(desc); - if (!test_bit(WDM_DISCONNECTING, &desc->flags)) + if (!test_bit(WDM_DISCONNECTING, &desc->flags)) { + dev_dbg(&desc->intf->dev, "wdm_release: cleanup"); + kill_urbs(desc); desc->manage_power(desc->intf, 0); + } else { + /* must avoid dev_printk here as desc->intf is invalid */ + pr_debug(KBUILD_MODNAME " %s: device gone - cleaning up\n", __func__); + cleanup(desc); + } } mutex_unlock(&wdm_mutex); return 0; @@ -771,6 +779,9 @@ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor out: return rv; err: + spin_lock(&wdm_device_list_lock); + list_del(&desc->device_list); + spin_unlock(&wdm_device_list_lock); cleanup(desc); return rv; } @@ -896,8 +907,16 @@ static void wdm_disconnect(struct usb_interface *intf) cancel_work_sync(&desc->rxwork); mutex_unlock(&desc->wlock); mutex_unlock(&desc->rlock); + + /* the desc->intf pointer used as list key is now invalid */ + spin_lock(&wdm_device_list_lock); + list_del(&desc->device_list); + spin_unlock(&wdm_device_list_lock); + if (!desc->count) cleanup(desc); + else + dev_dbg(&intf->dev, "%s: %d open files - postponing cleanup\n", __func__, desc->count); mutex_unlock(&wdm_mutex); } @@ -1015,6 +1034,7 @@ static struct usb_driver wdm_driver = { .post_reset = wdm_post_reset, .id_table = wdm_ids, .supports_autosuspend = 1, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(wdm_driver); diff --git a/trunk/drivers/usb/class/usblp.c b/trunk/drivers/usb/class/usblp.c index a68c1a63dc65..d4c47d5d7625 100644 --- a/trunk/drivers/usb/class/usblp.c +++ b/trunk/drivers/usb/class/usblp.c @@ -172,27 +172,31 @@ struct usblp { #ifdef DEBUG static void usblp_dump(struct usblp *usblp) { + struct device *dev = &usblp->intf->dev; int p; - dbg("usblp=0x%p", usblp); - dbg("dev=0x%p", usblp->dev); - dbg("present=%d", usblp->present); - dbg("readbuf=0x%p", usblp->readbuf); - dbg("readcount=%d", usblp->readcount); - dbg("ifnum=%d", usblp->ifnum); - for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) { - dbg("protocol[%d].alt_setting=%d", p, usblp->protocol[p].alt_setting); - dbg("protocol[%d].epwrite=%p", p, usblp->protocol[p].epwrite); - dbg("protocol[%d].epread=%p", p, usblp->protocol[p].epread); - } - dbg("current_protocol=%d", usblp->current_protocol); - dbg("minor=%d", usblp->minor); - dbg("wstatus=%d", usblp->wstatus); - dbg("rstatus=%d", usblp->rstatus); - dbg("quirks=%d", usblp->quirks); - dbg("used=%d", usblp->used); - dbg("bidir=%d", usblp->bidir); - dbg("device_id_string=\"%s\"", + dev_dbg(dev, "usblp=0x%p\n", usblp); + dev_dbg(dev, "dev=0x%p\n", usblp->dev); + dev_dbg(dev, "present=%d\n", usblp->present); + dev_dbg(dev, "readbuf=0x%p\n", usblp->readbuf); + dev_dbg(dev, "readcount=%d\n", usblp->readcount); + dev_dbg(dev, "ifnum=%d\n", usblp->ifnum); + for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) { + dev_dbg(dev, "protocol[%d].alt_setting=%d\n", p, + usblp->protocol[p].alt_setting); + dev_dbg(dev, "protocol[%d].epwrite=%p\n", p, + usblp->protocol[p].epwrite); + dev_dbg(dev, "protocol[%d].epread=%p\n", p, + usblp->protocol[p].epread); + } + dev_dbg(dev, "current_protocol=%d\n", usblp->current_protocol); + dev_dbg(dev, "minor=%d\n", usblp->minor); + dev_dbg(dev, "wstatus=%d\n", usblp->wstatus); + dev_dbg(dev, "rstatus=%d\n", usblp->rstatus); + dev_dbg(dev, "quirks=%d\n", usblp->quirks); + dev_dbg(dev, "used=%d\n", usblp->used); + dev_dbg(dev, "bidir=%d\n", usblp->bidir); + dev_dbg(dev, "device_id_string=\"%s\"\n", usblp->device_id_string ? usblp->device_id_string + 2 : (unsigned char *)"(null)"); @@ -262,7 +266,8 @@ static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, i retval = usb_control_msg(usblp->dev, dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0), request, type | dir | recip, value, index, buf, len, USBLP_CTL_TIMEOUT); - dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d", + dev_dbg(&usblp->intf->dev, + "usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d\n", request, !!dir, recip, value, index, len, retval); return retval < 0 ? retval : 0; } @@ -500,8 +505,9 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) goto done; } - dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd), - _IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd)); + dev_dbg(&usblp->intf->dev, + "usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)\n", cmd, + _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd)); if (_IOC_TYPE(cmd) == 'P') /* new-style ioctl number */ @@ -594,7 +600,8 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) goto done; } - dbg("usblp%d requested/got HP channel %ld/%d", + dev_dbg(&usblp->intf->dev, + "usblp%d requested/got HP channel %ld/%d\n", usblp->minor, arg, newChannel); break; @@ -614,7 +621,8 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) goto done; } - dbg("usblp%d is bus=%d, device=%d", + dev_dbg(&usblp->intf->dev, + "usblp%d is bus=%d, device=%d\n", usblp->minor, twoints[0], twoints[1]); break; @@ -634,7 +642,8 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) goto done; } - dbg("usblp%d is VID=0x%4.4X, PID=0x%4.4X", + dev_dbg(&usblp->intf->dev, + "usblp%d is VID=0x%4.4X, PID=0x%4.4X\n", usblp->minor, twoints[0], twoints[1]); break; @@ -987,7 +996,7 @@ static int usblp_submit_read(struct usblp *usblp) usblp->rcomplete = 0; spin_unlock_irqrestore(&usblp->lock, flags); if ((rc = usb_submit_urb(urb, GFP_KERNEL)) < 0) { - dbg("error submitting urb (%d)", rc); + dev_dbg(&usblp->intf->dev, "error submitting urb (%d)\n", rc); spin_lock_irqsave(&usblp->lock, flags); usblp->rstatus = rc; usblp->rcomplete = 1; @@ -1129,7 +1138,8 @@ static int usblp_probe(struct usb_interface *intf, /* Analyze and pick initial alternate settings and endpoints. */ protocol = usblp_select_alts(usblp); if (protocol < 0) { - dbg("incompatible printer-class device 0x%4.4X/0x%4.4X", + dev_dbg(&intf->dev, + "incompatible printer-class device 0x%4.4X/0x%4.4X\n", le16_to_cpu(dev->descriptor.idVendor), le16_to_cpu(dev->descriptor.idProduct)); retval = -ENODEV; @@ -1158,14 +1168,14 @@ static int usblp_probe(struct usb_interface *intf, retval = usb_register_dev(intf, &usblp_class); if (retval) { - printk(KERN_ERR "usblp: Not able to get a minor" - " (base %u, slice default): %d\n", - USBLP_MINOR_BASE, retval); + dev_err(&intf->dev, + "usblp: Not able to get a minor (base %u, slice default): %d\n", + USBLP_MINOR_BASE, retval); goto abort_intfdata; } usblp->minor = intf->minor; - printk(KERN_INFO "usblp%d: USB %sdirectional printer dev %d " - "if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X\n", + dev_info(&intf->dev, + "usblp%d: USB %sdirectional printer dev %d if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X\n", usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum, usblp->ifnum, usblp->protocol[usblp->current_protocol].alt_setting, @@ -1302,7 +1312,8 @@ static int usblp_set_protocol(struct usblp *usblp, int protocol) usblp->bidir = (usblp->protocol[protocol].epread != NULL); usblp->current_protocol = protocol; - dbg("usblp%d set protocol %d", usblp->minor, protocol); + dev_dbg(&usblp->intf->dev, "usblp%d set protocol %d\n", + usblp->minor, protocol); return 0; } @@ -1315,7 +1326,8 @@ static int usblp_cache_device_id_string(struct usblp *usblp) err = usblp_get_id(usblp, 0, usblp->device_id_string, USBLP_DEVICE_ID_SIZE - 1); if (err < 0) { - dbg("usblp%d: error = %d reading IEEE-1284 Device ID string", + dev_dbg(&usblp->intf->dev, + "usblp%d: error = %d reading IEEE-1284 Device ID string\n", usblp->minor, err); usblp->device_id_string[0] = usblp->device_id_string[1] = '\0'; return -EIO; @@ -1331,7 +1343,7 @@ static int usblp_cache_device_id_string(struct usblp *usblp) length = USBLP_DEVICE_ID_SIZE - 1; usblp->device_id_string[length] = '\0'; - dbg("usblp%d Device ID string [len=%d]=\"%s\"", + dev_dbg(&usblp->intf->dev, "usblp%d Device ID string [len=%d]=\"%s\"\n", usblp->minor, length, &usblp->device_id_string[2]); return length; diff --git a/trunk/drivers/usb/core/Kconfig b/trunk/drivers/usb/core/Kconfig index 18d02e32a3d5..9981984b365b 100644 --- a/trunk/drivers/usb/core/Kconfig +++ b/trunk/drivers/usb/core/Kconfig @@ -27,58 +27,6 @@ config USB_ANNOUNCE_NEW_DEVICES comment "Miscellaneous USB options" depends on USB -config USB_DEVICEFS - bool "USB device filesystem (DEPRECATED)" - depends on USB - ---help--- - If you say Y here (and to "/proc file system support" in the "File - systems" section, above), you will get a file /proc/bus/usb/devices - which lists the devices currently connected to your USB bus or - busses, and for every connected device a file named - "/proc/bus/usb/xxx/yyy", where xxx is the bus number and yyy the - device number; the latter files can be used by user space programs - to talk directly to the device. These files are "virtual", meaning - they are generated on the fly and not stored on the hard drive. - - You may need to mount the usbfs file system to see the files, use - mount -t usbfs none /proc/bus/usb - - For the format of the various /proc/bus/usb/ files, please read - . - - Modern Linux systems do not use this. - - Usbfs entries are files and not character devices; usbfs can't - handle Access Control Lists (ACL) which are the default way to - grant access to USB devices for untrusted users of a desktop - system. - - The usbfs functionality is replaced by real device-nodes managed by - udev. These nodes lived in /dev/bus/usb and are used by libusb. - -config USB_DEVICE_CLASS - bool "USB device class-devices (DEPRECATED)" - depends on USB - default y - ---help--- - Userspace access to USB devices is granted by device-nodes exported - directly from the usbdev in sysfs. Old versions of the driver - core and udev needed additional class devices to export device nodes. - - These additional devices are difficult to handle in userspace, if - information about USB interfaces must be available. One device - contains the device node, the other device contains the interface - data. Both devices are at the same level in sysfs (siblings) and one - can't access the other. The device node created directly by the - usb device is the parent device of the interface and therefore - easily accessible from the interface event. - - This option provides backward compatibility for libusb device - nodes (lsusb) when usbfs is not used, and the following udev rule - doesn't exist: - SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", \ - NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0644" - config USB_DYNAMIC_MINORS bool "Dynamic USB minor allocation" depends on USB @@ -125,7 +73,6 @@ config USB_OTG_WHITELIST bool "Rely on OTG Targeted Peripherals List" depends on USB_OTG || EXPERT default y if USB_OTG - default n if EXPERT help If you say Y here, the "otg_whitelist.h" file will be used as a product whitelist, so USB peripherals not listed there will be diff --git a/trunk/drivers/usb/core/Makefile b/trunk/drivers/usb/core/Makefile index 507a4e1b6360..26059b93dbf4 100644 --- a/trunk/drivers/usb/core/Makefile +++ b/trunk/drivers/usb/core/Makefile @@ -9,6 +9,6 @@ usbcore-y += config.o file.o buffer.o sysfs.o endpoint.o usbcore-y += devio.o notify.o generic.o quirks.o devices.o usbcore-$(CONFIG_PCI) += hcd-pci.o -usbcore-$(CONFIG_USB_DEVICEFS) += inode.o +usbcore-$(CONFIG_ACPI) += usb-acpi.o obj-$(CONFIG_USB) += usbcore.o diff --git a/trunk/drivers/usb/core/devio.c b/trunk/drivers/usb/core/devio.c index 8df4b76465ac..e0f107948eba 100644 --- a/trunk/drivers/usb/core/devio.c +++ b/trunk/drivers/usb/core/devio.c @@ -333,17 +333,14 @@ static struct async *async_getcompleted(struct dev_state *ps) static struct async *async_getpending(struct dev_state *ps, void __user *userurb) { - unsigned long flags; struct async *as; - spin_lock_irqsave(&ps->lock, flags); list_for_each_entry(as, &ps->async_pending, asynclist) if (as->userurb == userurb) { list_del_init(&as->asynclist); - spin_unlock_irqrestore(&ps->lock, flags); return as; } - spin_unlock_irqrestore(&ps->lock, flags); + return NULL; } @@ -398,6 +395,7 @@ static void cancel_bulk_urbs(struct dev_state *ps, unsigned bulk_addr) __releases(ps->lock) __acquires(ps->lock) { + struct urb *urb; struct async *as; /* Mark all the pending URBs that match bulk_addr, up to but not @@ -420,8 +418,11 @@ __acquires(ps->lock) list_for_each_entry(as, &ps->async_pending, asynclist) { if (as->bulk_status == AS_UNLINK) { as->bulk_status = 0; /* Only once */ + urb = as->urb; + usb_get_urb(urb); spin_unlock(&ps->lock); /* Allow completions */ - usb_unlink_urb(as->urb); + usb_unlink_urb(urb); + usb_put_urb(urb); spin_lock(&ps->lock); goto rescan; } @@ -472,6 +473,7 @@ static void async_completed(struct urb *urb) static void destroy_async(struct dev_state *ps, struct list_head *list) { + struct urb *urb; struct async *as; unsigned long flags; @@ -479,10 +481,13 @@ static void destroy_async(struct dev_state *ps, struct list_head *list) while (!list_empty(list)) { as = list_entry(list->next, struct async, asynclist); list_del_init(&as->asynclist); + urb = as->urb; + usb_get_urb(urb); /* drop the spinlock so the completion handler can run */ spin_unlock_irqrestore(&ps->lock, flags); - usb_kill_urb(as->urb); + usb_kill_urb(urb); + usb_put_urb(urb); spin_lock_irqsave(&ps->lock, flags); } spin_unlock_irqrestore(&ps->lock, flags); @@ -727,17 +732,6 @@ static int usbdev_open(struct inode *inode, struct file *file) if (imajor(inode) == USB_DEVICE_MAJOR) dev = usbdev_lookup_by_devt(inode->i_rdev); -#ifdef CONFIG_USB_DEVICEFS - /* procfs file */ - if (!dev) { - dev = inode->i_private; - if (dev && dev->usbfs_dentry && - dev->usbfs_dentry->d_inode == inode) - usb_get_dev(dev); - else - dev = NULL; - } -#endif mutex_unlock(&usbfs_mutex); if (!dev) @@ -1410,12 +1404,24 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg) static int proc_unlinkurb(struct dev_state *ps, void __user *arg) { + struct urb *urb; struct async *as; + unsigned long flags; + spin_lock_irqsave(&ps->lock, flags); as = async_getpending(ps, arg); - if (!as) + if (!as) { + spin_unlock_irqrestore(&ps->lock, flags); return -EINVAL; - usb_kill_urb(as->urb); + } + + urb = as->urb; + usb_get_urb(urb); + spin_unlock_irqrestore(&ps->lock, flags); + + usb_kill_urb(urb); + usb_put_urb(urb); + return 0; } @@ -2062,44 +2068,13 @@ static void usbdev_remove(struct usb_device *udev) } } -#ifdef CONFIG_USB_DEVICE_CLASS -static struct class *usb_classdev_class; - -static int usb_classdev_add(struct usb_device *dev) -{ - struct device *cldev; - - cldev = device_create(usb_classdev_class, &dev->dev, dev->dev.devt, - NULL, "usbdev%d.%d", dev->bus->busnum, - dev->devnum); - if (IS_ERR(cldev)) - return PTR_ERR(cldev); - dev->usb_classdev = cldev; - return 0; -} - -static void usb_classdev_remove(struct usb_device *dev) -{ - if (dev->usb_classdev) - device_unregister(dev->usb_classdev); -} - -#else -#define usb_classdev_add(dev) 0 -#define usb_classdev_remove(dev) do {} while (0) - -#endif - static int usbdev_notify(struct notifier_block *self, unsigned long action, void *dev) { switch (action) { case USB_DEVICE_ADD: - if (usb_classdev_add(dev)) - return NOTIFY_BAD; break; case USB_DEVICE_REMOVE: - usb_classdev_remove(dev); usbdev_remove(dev); break; } @@ -2129,21 +2104,6 @@ int __init usb_devio_init(void) USB_DEVICE_MAJOR); goto error_cdev; } -#ifdef CONFIG_USB_DEVICE_CLASS - usb_classdev_class = class_create(THIS_MODULE, "usb_device"); - if (IS_ERR(usb_classdev_class)) { - printk(KERN_ERR "Unable to register usb_device class\n"); - retval = PTR_ERR(usb_classdev_class); - cdev_del(&usb_device_cdev); - usb_classdev_class = NULL; - goto out; - } - /* devices of this class shadow the major:minor of their parent - * device, so clear ->dev_kobj to prevent adding duplicate entries - * to /sys/dev - */ - usb_classdev_class->dev_kobj = NULL; -#endif usb_register_notify(&usbdev_nb); out: return retval; @@ -2156,9 +2116,6 @@ int __init usb_devio_init(void) void usb_devio_cleanup(void) { usb_unregister_notify(&usbdev_nb); -#ifdef CONFIG_USB_DEVICE_CLASS - class_destroy(usb_classdev_class); -#endif cdev_del(&usb_device_cdev); unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX); } diff --git a/trunk/drivers/usb/core/driver.c b/trunk/drivers/usb/core/driver.c index 9a56635dc19c..f536aebc958e 100644 --- a/trunk/drivers/usb/core/driver.c +++ b/trunk/drivers/usb/core/driver.c @@ -79,6 +79,30 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids, } EXPORT_SYMBOL_GPL(usb_store_new_id); +ssize_t usb_show_dynids(struct usb_dynids *dynids, char *buf) +{ + struct usb_dynid *dynid; + size_t count = 0; + + list_for_each_entry(dynid, &dynids->list, node) + if (dynid->id.bInterfaceClass != 0) + count += scnprintf(&buf[count], PAGE_SIZE - count, "%04x %04x %02x\n", + dynid->id.idVendor, dynid->id.idProduct, + dynid->id.bInterfaceClass); + else + count += scnprintf(&buf[count], PAGE_SIZE - count, "%04x %04x\n", + dynid->id.idVendor, dynid->id.idProduct); + return count; +} +EXPORT_SYMBOL_GPL(usb_show_dynids); + +static ssize_t show_dynids(struct device_driver *driver, char *buf) +{ + struct usb_driver *usb_drv = to_usb_driver(driver); + + return usb_show_dynids(&usb_drv->dynids, buf); +} + static ssize_t store_new_id(struct device_driver *driver, const char *buf, size_t count) { @@ -86,7 +110,7 @@ static ssize_t store_new_id(struct device_driver *driver, return usb_store_new_id(&usb_drv->dynids, driver, buf, count); } -static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id); +static DRIVER_ATTR(new_id, S_IRUGO | S_IWUSR, show_dynids, store_new_id); /** * store_remove_id - remove a USB device ID from this driver @@ -127,7 +151,7 @@ store_remove_id(struct device_driver *driver, const char *buf, size_t count) return retval; return count; } -static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id); +static DRIVER_ATTR(remove_id, S_IRUGO | S_IWUSR, show_dynids, store_remove_id); static int usb_create_newid_files(struct usb_driver *usb_drv) { @@ -264,6 +288,7 @@ static int usb_probe_interface(struct device *dev) struct usb_device *udev = interface_to_usbdev(intf); const struct usb_device_id *id; int error = -ENODEV; + int lpm_disable_error; dev_dbg(dev, "%s\n", __func__); @@ -300,6 +325,25 @@ static int usb_probe_interface(struct device *dev) if (driver->supports_autosuspend) pm_runtime_enable(dev); + /* If the new driver doesn't allow hub-initiated LPM, and we can't + * disable hub-initiated LPM, then fail the probe. + * + * Otherwise, leaving LPM enabled should be harmless, because the + * endpoint intervals should remain the same, and the U1/U2 timeouts + * should remain the same. + * + * If we need to install alt setting 0 before probe, or another alt + * setting during probe, that should also be fine. usb_set_interface() + * will attempt to disable LPM, and fail if it can't disable it. + */ + lpm_disable_error = usb_unlocked_disable_lpm(udev); + if (lpm_disable_error && driver->disable_hub_initiated_lpm) { + dev_err(&intf->dev, "%s Failed to disable LPM for driver %s\n.", + __func__, driver->name); + error = lpm_disable_error; + goto err; + } + /* Carry out a deferred switch to altsetting 0 */ if (intf->needs_altsetting0) { error = usb_set_interface(udev, intf->altsetting[0]. @@ -314,6 +358,11 @@ static int usb_probe_interface(struct device *dev) goto err; intf->condition = USB_INTERFACE_BOUND; + + /* If the LPM disable succeeded, balance the ref counts. */ + if (!lpm_disable_error) + usb_unlocked_enable_lpm(udev); + usb_autosuspend_device(udev); return error; @@ -337,7 +386,7 @@ static int usb_unbind_interface(struct device *dev) struct usb_driver *driver = to_usb_driver(dev->driver); struct usb_interface *intf = to_usb_interface(dev); struct usb_device *udev; - int error, r; + int error, r, lpm_disable_error; intf->condition = USB_INTERFACE_UNBINDING; @@ -345,6 +394,13 @@ static int usb_unbind_interface(struct device *dev) udev = interface_to_usbdev(intf); error = usb_autoresume_device(udev); + /* Hub-initiated LPM policy may change, so attempt to disable LPM until + * the driver is unbound. If LPM isn't disabled, that's fine because it + * wouldn't be enabled unless all the bound interfaces supported + * hub-initiated LPM. + */ + lpm_disable_error = usb_unlocked_disable_lpm(udev); + /* Terminate all URBs for this interface unless the driver * supports "soft" unbinding. */ @@ -378,6 +434,10 @@ static int usb_unbind_interface(struct device *dev) intf->condition = USB_INTERFACE_UNBOUND; intf->needs_remote_wakeup = 0; + /* Attempt to re-enable USB3 LPM, if the disable succeeded. */ + if (!lpm_disable_error) + usb_unlocked_enable_lpm(udev); + /* Unbound interfaces are always runtime-PM-disabled and -suspended */ if (driver->supports_autosuspend) pm_runtime_disable(dev); @@ -418,17 +478,29 @@ int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void *priv) { struct device *dev = &iface->dev; + struct usb_device *udev; int retval = 0; + int lpm_disable_error; if (dev->driver) return -EBUSY; + udev = interface_to_usbdev(iface); + dev->driver = &driver->drvwrap.driver; usb_set_intfdata(iface, priv); iface->needs_binding = 0; iface->condition = USB_INTERFACE_BOUND; + /* Disable LPM until this driver is bound. */ + lpm_disable_error = usb_unlocked_disable_lpm(udev); + if (lpm_disable_error && driver->disable_hub_initiated_lpm) { + dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n.", + __func__, driver->name); + return -ENOMEM; + } + /* Claimed interfaces are initially inactive (suspended) and * runtime-PM-enabled, but only if the driver has autosuspend * support. Otherwise they are marked active, to prevent the @@ -447,6 +519,10 @@ int usb_driver_claim_interface(struct usb_driver *driver, if (device_is_registered(dev)) retval = device_bind_driver(dev); + /* Attempt to re-enable USB3 LPM, if the disable was successful. */ + if (!lpm_disable_error) + usb_unlocked_enable_lpm(udev); + return retval; } EXPORT_SYMBOL_GPL(usb_driver_claim_interface); @@ -726,16 +802,6 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env) return -ENODEV; } -#ifdef CONFIG_USB_DEVICEFS - /* If this is available, userspace programs can directly read - * all the device descriptors we don't tell them about. Or - * act as usermode drivers. - */ - if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d", - usb_dev->bus->busnum, usb_dev->devnum)) - return -ENOMEM; -#endif - /* per-device configurations are common */ if (add_uevent_var(env, "PRODUCT=%x/%x/%x", le16_to_cpu(usb_dev->descriptor.idVendor), @@ -788,15 +854,13 @@ int usb_register_device_driver(struct usb_device_driver *new_udriver, retval = driver_register(&new_udriver->drvwrap.driver); - if (!retval) { + if (!retval) pr_info("%s: registered new device driver %s\n", usbcore_name, new_udriver->name); - usbfs_update_special(); - } else { + else printk(KERN_ERR "%s: error %d registering device " " driver %s\n", usbcore_name, retval, new_udriver->name); - } return retval; } @@ -815,7 +879,6 @@ void usb_deregister_device_driver(struct usb_device_driver *udriver) usbcore_name, udriver->name); driver_unregister(&udriver->drvwrap.driver); - usbfs_update_special(); } EXPORT_SYMBOL_GPL(usb_deregister_device_driver); @@ -856,8 +919,6 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner, if (retval) goto out; - usbfs_update_special(); - retval = usb_create_newid_files(new_driver); if (retval) goto out_newid; @@ -897,8 +958,6 @@ void usb_deregister(struct usb_driver *driver) usb_remove_newid_files(driver); driver_unregister(&driver->drvwrap.driver); usb_free_dynids(driver); - - usbfs_update_special(); } EXPORT_SYMBOL_GPL(usb_deregister); diff --git a/trunk/drivers/usb/core/file.c b/trunk/drivers/usb/core/file.c index d95760de9e8b..e673b26e598f 100644 --- a/trunk/drivers/usb/core/file.c +++ b/trunk/drivers/usb/core/file.c @@ -183,7 +183,7 @@ int usb_register_dev(struct usb_interface *intf, if (retval) return retval; - dev_dbg(&intf->dev, "looking for a minor, starting at %d", minor_base); + dev_dbg(&intf->dev, "looking for a minor, starting at %d\n", minor_base); down_write(&minor_rwsem); for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) { @@ -239,7 +239,7 @@ void usb_deregister_dev(struct usb_interface *intf, if (intf->minor == -1) return; - dbg ("removing %d minor", intf->minor); + dev_dbg(&intf->dev, "removing %d minor\n", intf->minor); down_write(&minor_rwsem); usb_minors[intf->minor] = NULL; diff --git a/trunk/drivers/usb/core/hcd.c b/trunk/drivers/usb/core/hcd.c index 140d3e11f212..190b1ec7bdcb 100644 --- a/trunk/drivers/usb/core/hcd.c +++ b/trunk/drivers/usb/core/hcd.c @@ -138,7 +138,7 @@ static const u8 usb3_rh_dev_descriptor[18] = { 0x03, /* __u8 bDeviceProtocol; USB 3.0 hub */ 0x09, /* __u8 bMaxPacketSize0; 2^9 = 512 Bytes */ - 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */ + 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation 0x1d6b */ 0x03, 0x00, /* __le16 idProduct; device 0x0003 */ KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */ @@ -159,7 +159,7 @@ static const u8 usb2_rh_dev_descriptor [18] = { 0x00, /* __u8 bDeviceProtocol; [ usb 2.0 no TT ] */ 0x40, /* __u8 bMaxPacketSize0; 64 Bytes */ - 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */ + 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation 0x1d6b */ 0x02, 0x00, /* __le16 idProduct; device 0x0002 */ KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */ @@ -182,7 +182,7 @@ static const u8 usb11_rh_dev_descriptor [18] = { 0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */ 0x40, /* __u8 bMaxPacketSize0; 64 Bytes */ - 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */ + 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation 0x1d6b */ 0x01, 0x00, /* __le16 idProduct; device 0x0001 */ KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */ @@ -997,6 +997,15 @@ static int register_root_hub(struct usb_hcd *hcd) dev_name(&usb_dev->dev), retval); return (retval < 0) ? retval : -EMSGSIZE; } + if (usb_dev->speed == USB_SPEED_SUPER) { + retval = usb_get_bos_descriptor(usb_dev); + if (retval < 0) { + mutex_unlock(&usb_bus_list_lock); + dev_dbg(parent_dev, "can't read %s bos descriptor %d\n", + dev_name(&usb_dev->dev), retval); + return retval; + } + } retval = usb_new_device (usb_dev); if (retval) { diff --git a/trunk/drivers/usb/core/hub.c b/trunk/drivers/usb/core/hub.c index ec6c97dadbe4..04fb834c3fa1 100644 --- a/trunk/drivers/usb/core/hub.c +++ b/trunk/drivers/usb/core/hub.c @@ -177,6 +177,228 @@ static struct usb_hub *hdev_to_hub(struct usb_device *hdev) return usb_get_intfdata(hdev->actconfig->interface[0]); } +static int usb_device_supports_lpm(struct usb_device *udev) +{ + /* USB 2.1 (and greater) devices indicate LPM support through + * their USB 2.0 Extended Capabilities BOS descriptor. + */ + if (udev->speed == USB_SPEED_HIGH) { + if (udev->bos->ext_cap && + (USB_LPM_SUPPORT & + le32_to_cpu(udev->bos->ext_cap->bmAttributes))) + return 1; + return 0; + } + + /* All USB 3.0 must support LPM, but we need their max exit latency + * information from the SuperSpeed Extended Capabilities BOS descriptor. + */ + if (!udev->bos->ss_cap) { + dev_warn(&udev->dev, "No LPM exit latency info found. " + "Power management will be impacted.\n"); + return 0; + } + if (udev->parent->lpm_capable) + return 1; + + dev_warn(&udev->dev, "Parent hub missing LPM exit latency info. " + "Power management will be impacted.\n"); + return 0; +} + +/* + * Set the Maximum Exit Latency (MEL) for the host to initiate a transition from + * either U1 or U2. + */ +static void usb_set_lpm_mel(struct usb_device *udev, + struct usb3_lpm_parameters *udev_lpm_params, + unsigned int udev_exit_latency, + struct usb_hub *hub, + struct usb3_lpm_parameters *hub_lpm_params, + unsigned int hub_exit_latency) +{ + unsigned int total_mel; + unsigned int device_mel; + unsigned int hub_mel; + + /* + * Calculate the time it takes to transition all links from the roothub + * to the parent hub into U0. The parent hub must then decode the + * packet (hub header decode latency) to figure out which port it was + * bound for. + * + * The Hub Header decode latency is expressed in 0.1us intervals (0x1 + * means 0.1us). Multiply that by 100 to get nanoseconds. + */ + total_mel = hub_lpm_params->mel + + (hub->descriptor->u.ss.bHubHdrDecLat * 100); + + /* + * How long will it take to transition the downstream hub's port into + * U0? The greater of either the hub exit latency or the device exit + * latency. + * + * The BOS U1/U2 exit latencies are expressed in 1us intervals. + * Multiply that by 1000 to get nanoseconds. + */ + device_mel = udev_exit_latency * 1000; + hub_mel = hub_exit_latency * 1000; + if (device_mel > hub_mel) + total_mel += device_mel; + else + total_mel += hub_mel; + + udev_lpm_params->mel = total_mel; +} + +/* + * Set the maximum Device to Host Exit Latency (PEL) for the device to initiate + * a transition from either U1 or U2. + */ +static void usb_set_lpm_pel(struct usb_device *udev, + struct usb3_lpm_parameters *udev_lpm_params, + unsigned int udev_exit_latency, + struct usb_hub *hub, + struct usb3_lpm_parameters *hub_lpm_params, + unsigned int hub_exit_latency, + unsigned int port_to_port_exit_latency) +{ + unsigned int first_link_pel; + unsigned int hub_pel; + + /* + * First, the device sends an LFPS to transition the link between the + * device and the parent hub into U0. The exit latency is the bigger of + * the device exit latency or the hub exit latency. + */ + if (udev_exit_latency > hub_exit_latency) + first_link_pel = udev_exit_latency * 1000; + else + first_link_pel = hub_exit_latency * 1000; + + /* + * When the hub starts to receive the LFPS, there is a slight delay for + * it to figure out that one of the ports is sending an LFPS. Then it + * will forward the LFPS to its upstream link. The exit latency is the + * delay, plus the PEL that we calculated for this hub. + */ + hub_pel = port_to_port_exit_latency * 1000 + hub_lpm_params->pel; + + /* + * According to figure C-7 in the USB 3.0 spec, the PEL for this device + * is the greater of the two exit latencies. + */ + if (first_link_pel > hub_pel) + udev_lpm_params->pel = first_link_pel; + else + udev_lpm_params->pel = hub_pel; +} + +/* + * Set the System Exit Latency (SEL) to indicate the total worst-case time from + * when a device initiates a transition to U0, until when it will receive the + * first packet from the host controller. + * + * Section C.1.5.1 describes the four components to this: + * - t1: device PEL + * - t2: time for the ERDY to make it from the device to the host. + * - t3: a host-specific delay to process the ERDY. + * - t4: time for the packet to make it from the host to the device. + * + * t3 is specific to both the xHCI host and the platform the host is integrated + * into. The Intel HW folks have said it's negligible, FIXME if a different + * vendor says otherwise. + */ +static void usb_set_lpm_sel(struct usb_device *udev, + struct usb3_lpm_parameters *udev_lpm_params) +{ + struct usb_device *parent; + unsigned int num_hubs; + unsigned int total_sel; + + /* t1 = device PEL */ + total_sel = udev_lpm_params->pel; + /* How many external hubs are in between the device & the root port. */ + for (parent = udev->parent, num_hubs = 0; parent->parent; + parent = parent->parent) + num_hubs++; + /* t2 = 2.1us + 250ns * (num_hubs - 1) */ + if (num_hubs > 0) + total_sel += 2100 + 250 * (num_hubs - 1); + + /* t4 = 250ns * num_hubs */ + total_sel += 250 * num_hubs; + + udev_lpm_params->sel = total_sel; +} + +static void usb_set_lpm_parameters(struct usb_device *udev) +{ + struct usb_hub *hub; + unsigned int port_to_port_delay; + unsigned int udev_u1_del; + unsigned int udev_u2_del; + unsigned int hub_u1_del; + unsigned int hub_u2_del; + + if (!udev->lpm_capable || udev->speed != USB_SPEED_SUPER) + return; + + hub = hdev_to_hub(udev->parent); + /* It doesn't take time to transition the roothub into U0, since it + * doesn't have an upstream link. + */ + if (!hub) + return; + + udev_u1_del = udev->bos->ss_cap->bU1devExitLat; + udev_u2_del = udev->bos->ss_cap->bU2DevExitLat; + hub_u1_del = udev->parent->bos->ss_cap->bU1devExitLat; + hub_u2_del = udev->parent->bos->ss_cap->bU2DevExitLat; + + usb_set_lpm_mel(udev, &udev->u1_params, udev_u1_del, + hub, &udev->parent->u1_params, hub_u1_del); + + usb_set_lpm_mel(udev, &udev->u2_params, udev_u2_del, + hub, &udev->parent->u2_params, hub_u2_del); + + /* + * Appendix C, section C.2.2.2, says that there is a slight delay from + * when the parent hub notices the downstream port is trying to + * transition to U0 to when the hub initiates a U0 transition on its + * upstream port. The section says the delays are tPort2PortU1EL and + * tPort2PortU2EL, but it doesn't define what they are. + * + * The hub chapter, sections 10.4.2.4 and 10.4.2.5 seem to be talking + * about the same delays. Use the maximum delay calculations from those + * sections. For U1, it's tHubPort2PortExitLat, which is 1us max. For + * U2, it's tHubPort2PortExitLat + U2DevExitLat - U1DevExitLat. I + * assume the device exit latencies they are talking about are the hub + * exit latencies. + * + * What do we do if the U2 exit latency is less than the U1 exit + * latency? It's possible, although not likely... + */ + port_to_port_delay = 1; + + usb_set_lpm_pel(udev, &udev->u1_params, udev_u1_del, + hub, &udev->parent->u1_params, hub_u1_del, + port_to_port_delay); + + if (hub_u2_del > hub_u1_del) + port_to_port_delay = 1 + hub_u2_del - hub_u1_del; + else + port_to_port_delay = 1 + hub_u1_del; + + usb_set_lpm_pel(udev, &udev->u2_params, udev_u2_del, + hub, &udev->parent->u2_params, hub_u2_del, + port_to_port_delay); + + /* Now that we've got PEL, calculate SEL. */ + usb_set_lpm_sel(udev, &udev->u1_params); + usb_set_lpm_sel(udev, &udev->u2_params); +} + /* USB 2.0 spec Section 11.24.4.5 */ static int get_hub_descriptor(struct usb_device *hdev, void *data) { @@ -2480,6 +2702,12 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) if (udev->usb2_hw_lpm_enabled == 1) usb_set_usb2_hardware_lpm(udev, 0); + if (usb_unlocked_disable_lpm(udev)) { + dev_err(&udev->dev, "%s Failed to disable LPM before suspend\n.", + __func__); + return -ENOMEM; + } + /* see 7.1.7.6 */ if (hub_is_superspeed(hub->hdev)) status = set_port_feature(hub->hdev, @@ -2499,6 +2727,13 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) NULL, 0, USB_CTRL_SET_TIMEOUT); + /* Try to enable USB2 hardware LPM again */ + if (udev->usb2_hw_lpm_capable == 1) + usb_set_usb2_hardware_lpm(udev, 1); + + /* Try to enable USB3 LPM again */ + usb_unlocked_enable_lpm(udev); + /* System sleep transitions should never fail */ if (!PMSG_IS_AUTO(msg)) status = 0; @@ -2696,6 +2931,9 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) /* Try to enable USB2 hardware LPM */ if (udev->usb2_hw_lpm_capable == 1) usb_set_usb2_hardware_lpm(udev, 1); + + /* Try to enable USB3 LPM */ + usb_unlocked_enable_lpm(udev); } return status; @@ -2824,11 +3062,429 @@ void usb_root_hub_lost_power(struct usb_device *rhdev) } EXPORT_SYMBOL_GPL(usb_root_hub_lost_power); +static const char * const usb3_lpm_names[] = { + "U0", + "U1", + "U2", + "U3", +}; + +/* + * Send a Set SEL control transfer to the device, prior to enabling + * device-initiated U1 or U2. This lets the device know the exit latencies from + * the time the device initiates a U1 or U2 exit, to the time it will receive a + * packet from the host. + * + * This function will fail if the SEL or PEL values for udev are greater than + * the maximum allowed values for the link state to be enabled. + */ +static int usb_req_set_sel(struct usb_device *udev, enum usb3_link_state state) +{ + struct usb_set_sel_req *sel_values; + unsigned long long u1_sel; + unsigned long long u1_pel; + unsigned long long u2_sel; + unsigned long long u2_pel; + int ret; + + /* Convert SEL and PEL stored in ns to us */ + u1_sel = DIV_ROUND_UP(udev->u1_params.sel, 1000); + u1_pel = DIV_ROUND_UP(udev->u1_params.pel, 1000); + u2_sel = DIV_ROUND_UP(udev->u2_params.sel, 1000); + u2_pel = DIV_ROUND_UP(udev->u2_params.pel, 1000); + + /* + * Make sure that the calculated SEL and PEL values for the link + * state we're enabling aren't bigger than the max SEL/PEL + * value that will fit in the SET SEL control transfer. + * Otherwise the device would get an incorrect idea of the exit + * latency for the link state, and could start a device-initiated + * U1/U2 when the exit latencies are too high. + */ + if ((state == USB3_LPM_U1 && + (u1_sel > USB3_LPM_MAX_U1_SEL_PEL || + u1_pel > USB3_LPM_MAX_U1_SEL_PEL)) || + (state == USB3_LPM_U2 && + (u2_sel > USB3_LPM_MAX_U2_SEL_PEL || + u2_pel > USB3_LPM_MAX_U2_SEL_PEL))) { + dev_dbg(&udev->dev, "Device-initiated %s disabled due " + "to long SEL %llu ms or PEL %llu ms\n", + usb3_lpm_names[state], u1_sel, u1_pel); + return -EINVAL; + } + + /* + * If we're enabling device-initiated LPM for one link state, + * but the other link state has a too high SEL or PEL value, + * just set those values to the max in the Set SEL request. + */ + if (u1_sel > USB3_LPM_MAX_U1_SEL_PEL) + u1_sel = USB3_LPM_MAX_U1_SEL_PEL; + + if (u1_pel > USB3_LPM_MAX_U1_SEL_PEL) + u1_pel = USB3_LPM_MAX_U1_SEL_PEL; + + if (u2_sel > USB3_LPM_MAX_U2_SEL_PEL) + u2_sel = USB3_LPM_MAX_U2_SEL_PEL; + + if (u2_pel > USB3_LPM_MAX_U2_SEL_PEL) + u2_pel = USB3_LPM_MAX_U2_SEL_PEL; + + /* + * usb_enable_lpm() can be called as part of a failed device reset, + * which may be initiated by an error path of a mass storage driver. + * Therefore, use GFP_NOIO. + */ + sel_values = kmalloc(sizeof *(sel_values), GFP_NOIO); + if (!sel_values) + return -ENOMEM; + + sel_values->u1_sel = u1_sel; + sel_values->u1_pel = u1_pel; + sel_values->u2_sel = cpu_to_le16(u2_sel); + sel_values->u2_pel = cpu_to_le16(u2_pel); + + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_REQ_SET_SEL, + USB_RECIP_DEVICE, + 0, 0, + sel_values, sizeof *(sel_values), + USB_CTRL_SET_TIMEOUT); + kfree(sel_values); + return ret; +} + +/* + * Enable or disable device-initiated U1 or U2 transitions. + */ +static int usb_set_device_initiated_lpm(struct usb_device *udev, + enum usb3_link_state state, bool enable) +{ + int ret; + int feature; + + switch (state) { + case USB3_LPM_U1: + feature = USB_DEVICE_U1_ENABLE; + break; + case USB3_LPM_U2: + feature = USB_DEVICE_U2_ENABLE; + break; + default: + dev_warn(&udev->dev, "%s: Can't %s non-U1 or U2 state.\n", + __func__, enable ? "enable" : "disable"); + return -EINVAL; + } + + if (udev->state != USB_STATE_CONFIGURED) { + dev_dbg(&udev->dev, "%s: Can't %s %s state " + "for unconfigured device.\n", + __func__, enable ? "enable" : "disable", + usb3_lpm_names[state]); + return 0; + } + + if (enable) { + /* + * First, let the device know about the exit latencies + * associated with the link state we're about to enable. + */ + ret = usb_req_set_sel(udev, state); + if (ret < 0) { + dev_warn(&udev->dev, "Set SEL for device-initiated " + "%s failed.\n", usb3_lpm_names[state]); + return -EBUSY; + } + /* + * Now send the control transfer to enable device-initiated LPM + * for either U1 or U2. + */ + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_REQ_SET_FEATURE, + USB_RECIP_DEVICE, + feature, + 0, NULL, 0, + USB_CTRL_SET_TIMEOUT); + } else { + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_REQ_CLEAR_FEATURE, + USB_RECIP_DEVICE, + feature, + 0, NULL, 0, + USB_CTRL_SET_TIMEOUT); + } + if (ret < 0) { + dev_warn(&udev->dev, "%s of device-initiated %s failed.\n", + enable ? "Enable" : "Disable", + usb3_lpm_names[state]); + return -EBUSY; + } + return 0; +} + +static int usb_set_lpm_timeout(struct usb_device *udev, + enum usb3_link_state state, int timeout) +{ + int ret; + int feature; + + switch (state) { + case USB3_LPM_U1: + feature = USB_PORT_FEAT_U1_TIMEOUT; + break; + case USB3_LPM_U2: + feature = USB_PORT_FEAT_U2_TIMEOUT; + break; + default: + dev_warn(&udev->dev, "%s: Can't set timeout for non-U1 or U2 state.\n", + __func__); + return -EINVAL; + } + + if (state == USB3_LPM_U1 && timeout > USB3_LPM_U1_MAX_TIMEOUT && + timeout != USB3_LPM_DEVICE_INITIATED) { + dev_warn(&udev->dev, "Failed to set %s timeout to 0x%x, " + "which is a reserved value.\n", + usb3_lpm_names[state], timeout); + return -EINVAL; + } + + ret = set_port_feature(udev->parent, + USB_PORT_LPM_TIMEOUT(timeout) | udev->portnum, + feature); + if (ret < 0) { + dev_warn(&udev->dev, "Failed to set %s timeout to 0x%x," + "error code %i\n", usb3_lpm_names[state], + timeout, ret); + return -EBUSY; + } + if (state == USB3_LPM_U1) + udev->u1_params.timeout = timeout; + else + udev->u2_params.timeout = timeout; + return 0; +} + +/* + * Enable the hub-initiated U1/U2 idle timeouts, and enable device-initiated + * U1/U2 entry. + * + * We will attempt to enable U1 or U2, but there are no guarantees that the + * control transfers to set the hub timeout or enable device-initiated U1/U2 + * will be successful. + * + * If we cannot set the parent hub U1/U2 timeout, we attempt to let the xHCI + * driver know about it. If that call fails, it should be harmless, and just + * take up more slightly more bus bandwidth for unnecessary U1/U2 exit latency. + */ +static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev, + enum usb3_link_state state) +{ + int timeout; + + /* We allow the host controller to set the U1/U2 timeout internally + * first, so that it can change its schedule to account for the + * additional latency to send data to a device in a lower power + * link state. + */ + timeout = hcd->driver->enable_usb3_lpm_timeout(hcd, udev, state); + + /* xHCI host controller doesn't want to enable this LPM state. */ + if (timeout == 0) + return; + + if (timeout < 0) { + dev_warn(&udev->dev, "Could not enable %s link state, " + "xHCI error %i.\n", usb3_lpm_names[state], + timeout); + return; + } + + if (usb_set_lpm_timeout(udev, state, timeout)) + /* If we can't set the parent hub U1/U2 timeout, + * device-initiated LPM won't be allowed either, so let the xHCI + * host know that this link state won't be enabled. + */ + hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state); + + /* Only a configured device will accept the Set Feature U1/U2_ENABLE */ + else if (udev->actconfig) + usb_set_device_initiated_lpm(udev, state, true); + +} + +/* + * Disable the hub-initiated U1/U2 idle timeouts, and disable device-initiated + * U1/U2 entry. + * + * If this function returns -EBUSY, the parent hub will still allow U1/U2 entry. + * If zero is returned, the parent will not allow the link to go into U1/U2. + * + * If zero is returned, device-initiated U1/U2 entry may still be enabled, but + * it won't have an effect on the bus link state because the parent hub will + * still disallow device-initiated U1/U2 entry. + * + * If zero is returned, the xHCI host controller may still think U1/U2 entry is + * possible. The result will be slightly more bus bandwidth will be taken up + * (to account for U1/U2 exit latency), but it should be harmless. + */ +static int usb_disable_link_state(struct usb_hcd *hcd, struct usb_device *udev, + enum usb3_link_state state) +{ + int feature; + + switch (state) { + case USB3_LPM_U1: + feature = USB_PORT_FEAT_U1_TIMEOUT; + break; + case USB3_LPM_U2: + feature = USB_PORT_FEAT_U2_TIMEOUT; + break; + default: + dev_warn(&udev->dev, "%s: Can't disable non-U1 or U2 state.\n", + __func__); + return -EINVAL; + } + + if (usb_set_lpm_timeout(udev, state, 0)) + return -EBUSY; + + usb_set_device_initiated_lpm(udev, state, false); + + if (hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state)) + dev_warn(&udev->dev, "Could not disable xHCI %s timeout, " + "bus schedule bandwidth may be impacted.\n", + usb3_lpm_names[state]); + return 0; +} + +/* + * Disable hub-initiated and device-initiated U1 and U2 entry. + * Caller must own the bandwidth_mutex. + * + * This will call usb_enable_lpm() on failure, which will decrement + * lpm_disable_count, and will re-enable LPM if lpm_disable_count reaches zero. + */ +int usb_disable_lpm(struct usb_device *udev) +{ + struct usb_hcd *hcd; + + if (!udev || !udev->parent || + udev->speed != USB_SPEED_SUPER || + !udev->lpm_capable) + return 0; + + hcd = bus_to_hcd(udev->bus); + if (!hcd || !hcd->driver->disable_usb3_lpm_timeout) + return 0; + + udev->lpm_disable_count++; + if ((udev->u1_params.timeout == 0 && udev->u1_params.timeout == 0)) + return 0; + + /* If LPM is enabled, attempt to disable it. */ + if (usb_disable_link_state(hcd, udev, USB3_LPM_U1)) + goto enable_lpm; + if (usb_disable_link_state(hcd, udev, USB3_LPM_U2)) + goto enable_lpm; + + return 0; + +enable_lpm: + usb_enable_lpm(udev); + return -EBUSY; +} +EXPORT_SYMBOL_GPL(usb_disable_lpm); + +/* Grab the bandwidth_mutex before calling usb_disable_lpm() */ +int usb_unlocked_disable_lpm(struct usb_device *udev) +{ + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + int ret; + + if (!hcd) + return -EINVAL; + + mutex_lock(hcd->bandwidth_mutex); + ret = usb_disable_lpm(udev); + mutex_unlock(hcd->bandwidth_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_unlocked_disable_lpm); + +/* + * Attempt to enable device-initiated and hub-initiated U1 and U2 entry. The + * xHCI host policy may prevent U1 or U2 from being enabled. + * + * Other callers may have disabled link PM, so U1 and U2 entry will be disabled + * until the lpm_disable_count drops to zero. Caller must own the + * bandwidth_mutex. + */ +void usb_enable_lpm(struct usb_device *udev) +{ + struct usb_hcd *hcd; + + if (!udev || !udev->parent || + udev->speed != USB_SPEED_SUPER || + !udev->lpm_capable) + return; + + udev->lpm_disable_count--; + hcd = bus_to_hcd(udev->bus); + /* Double check that we can both enable and disable LPM. + * Device must be configured to accept set feature U1/U2 timeout. + */ + if (!hcd || !hcd->driver->enable_usb3_lpm_timeout || + !hcd->driver->disable_usb3_lpm_timeout) + return; + + if (udev->lpm_disable_count > 0) + return; + + usb_enable_link_state(hcd, udev, USB3_LPM_U1); + usb_enable_link_state(hcd, udev, USB3_LPM_U2); +} +EXPORT_SYMBOL_GPL(usb_enable_lpm); + +/* Grab the bandwidth_mutex before calling usb_enable_lpm() */ +void usb_unlocked_enable_lpm(struct usb_device *udev) +{ + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + + if (!hcd) + return; + + mutex_lock(hcd->bandwidth_mutex); + usb_enable_lpm(udev); + mutex_unlock(hcd->bandwidth_mutex); +} +EXPORT_SYMBOL_GPL(usb_unlocked_enable_lpm); + + #else /* CONFIG_PM */ #define hub_suspend NULL #define hub_resume NULL #define hub_reset_resume NULL + +int usb_disable_lpm(struct usb_device *udev) +{ + return 0; +} +EXPORT_SYMBOL_GPL(usb_disable_lpm); + +void usb_enable_lpm(struct usb_device *udev) { } +EXPORT_SYMBOL_GPL(usb_enable_lpm); + +int usb_unlocked_disable_lpm(struct usb_device *udev) +{ + return 0; +} +EXPORT_SYMBOL_GPL(usb_unlocked_disable_lpm); + +void usb_unlocked_enable_lpm(struct usb_device *udev) { } +EXPORT_SYMBOL_GPL(usb_unlocked_enable_lpm); #endif @@ -3208,9 +3864,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) { retval = usb_get_bos_descriptor(udev); if (!retval) { - if (udev->bos->ext_cap && (USB_LPM_SUPPORT & - le32_to_cpu(udev->bos->ext_cap->bmAttributes))) - udev->lpm_capable = 1; + udev->lpm_capable = usb_device_supports_lpm(udev); + usb_set_lpm_parameters(udev); } } @@ -4042,11 +4697,22 @@ static int usb_reset_and_verify_device(struct usb_device *udev) goto done; mutex_lock(hcd->bandwidth_mutex); + /* Disable LPM while we reset the device and reinstall the alt settings. + * Device-initiated LPM settings, and system exit latency settings are + * cleared when the device is reset, so we have to set them up again. + */ + ret = usb_disable_lpm(udev); + if (ret) { + dev_err(&udev->dev, "%s Failed to disable LPM\n.", __func__); + mutex_unlock(hcd->bandwidth_mutex); + goto done; + } ret = usb_hcd_alloc_bandwidth(udev, udev->actconfig, NULL, NULL); if (ret < 0) { dev_warn(&udev->dev, "Busted HC? Not enough HCD resources for " "old configuration.\n"); + usb_enable_lpm(udev); mutex_unlock(hcd->bandwidth_mutex); goto re_enumerate; } @@ -4058,6 +4724,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) dev_err(&udev->dev, "can't restore configuration #%d (error=%d)\n", udev->actconfig->desc.bConfigurationValue, ret); + usb_enable_lpm(udev); mutex_unlock(hcd->bandwidth_mutex); goto re_enumerate; } @@ -4096,10 +4763,13 @@ static int usb_reset_and_verify_device(struct usb_device *udev) desc->bInterfaceNumber, desc->bAlternateSetting, ret); + usb_unlocked_enable_lpm(udev); goto re_enumerate; } } + /* Now that the alt settings are re-installed, enable LPM. */ + usb_unlocked_enable_lpm(udev); done: return 0; diff --git a/trunk/drivers/usb/core/inode.c b/trunk/drivers/usb/core/inode.c deleted file mode 100644 index d2b9af59cba9..000000000000 --- a/trunk/drivers/usb/core/inode.c +++ /dev/null @@ -1,748 +0,0 @@ -/*****************************************************************************/ - -/* - * inode.c -- Inode/Dentry functions for the USB device file system. - * - * Copyright (C) 2000 Thomas Sailer (sailer@ife.ee.ethz.ch) - * Copyright (C) 2001,2002,2004 Greg Kroah-Hartman (greg@kroah.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; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * History: - * 0.1 04.01.2000 Created - * 0.2 10.12.2001 converted to use the vfs layer better - */ - -/*****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "usb.h" - -#define USBFS_DEFAULT_DEVMODE (S_IWUSR | S_IRUGO) -#define USBFS_DEFAULT_BUSMODE (S_IXUGO | S_IRUGO) -#define USBFS_DEFAULT_LISTMODE S_IRUGO - -static const struct file_operations default_file_operations; -static struct vfsmount *usbfs_mount; -static int usbfs_mount_count; /* = 0 */ - -static struct dentry *devices_usbfs_dentry; -static int num_buses; /* = 0 */ - -static uid_t devuid; /* = 0 */ -static uid_t busuid; /* = 0 */ -static uid_t listuid; /* = 0 */ -static gid_t devgid; /* = 0 */ -static gid_t busgid; /* = 0 */ -static gid_t listgid; /* = 0 */ -static umode_t devmode = USBFS_DEFAULT_DEVMODE; -static umode_t busmode = USBFS_DEFAULT_BUSMODE; -static umode_t listmode = USBFS_DEFAULT_LISTMODE; - -static int usbfs_show_options(struct seq_file *seq, struct dentry *root) -{ - if (devuid != 0) - seq_printf(seq, ",devuid=%u", devuid); - if (devgid != 0) - seq_printf(seq, ",devgid=%u", devgid); - if (devmode != USBFS_DEFAULT_DEVMODE) - seq_printf(seq, ",devmode=%o", devmode); - if (busuid != 0) - seq_printf(seq, ",busuid=%u", busuid); - if (busgid != 0) - seq_printf(seq, ",busgid=%u", busgid); - if (busmode != USBFS_DEFAULT_BUSMODE) - seq_printf(seq, ",busmode=%o", busmode); - if (listuid != 0) - seq_printf(seq, ",listuid=%u", listuid); - if (listgid != 0) - seq_printf(seq, ",listgid=%u", listgid); - if (listmode != USBFS_DEFAULT_LISTMODE) - seq_printf(seq, ",listmode=%o", listmode); - - return 0; -} - -enum { - Opt_devuid, Opt_devgid, Opt_devmode, - Opt_busuid, Opt_busgid, Opt_busmode, - Opt_listuid, Opt_listgid, Opt_listmode, - Opt_err, -}; - -static const match_table_t tokens = { - {Opt_devuid, "devuid=%u"}, - {Opt_devgid, "devgid=%u"}, - {Opt_devmode, "devmode=%o"}, - {Opt_busuid, "busuid=%u"}, - {Opt_busgid, "busgid=%u"}, - {Opt_busmode, "busmode=%o"}, - {Opt_listuid, "listuid=%u"}, - {Opt_listgid, "listgid=%u"}, - {Opt_listmode, "listmode=%o"}, - {Opt_err, NULL} -}; - -static int parse_options(struct super_block *s, char *data) -{ - char *p; - int option; - - /* (re)set to defaults. */ - devuid = 0; - busuid = 0; - listuid = 0; - devgid = 0; - busgid = 0; - listgid = 0; - devmode = USBFS_DEFAULT_DEVMODE; - busmode = USBFS_DEFAULT_BUSMODE; - listmode = USBFS_DEFAULT_LISTMODE; - - while ((p = strsep(&data, ",")) != NULL) { - substring_t args[MAX_OPT_ARGS]; - int token; - if (!*p) - continue; - - token = match_token(p, tokens, args); - switch (token) { - case Opt_devuid: - if (match_int(&args[0], &option)) - return -EINVAL; - devuid = option; - break; - case Opt_devgid: - if (match_int(&args[0], &option)) - return -EINVAL; - devgid = option; - break; - case Opt_devmode: - if (match_octal(&args[0], &option)) - return -EINVAL; - devmode = option & S_IRWXUGO; - break; - case Opt_busuid: - if (match_int(&args[0], &option)) - return -EINVAL; - busuid = option; - break; - case Opt_busgid: - if (match_int(&args[0], &option)) - return -EINVAL; - busgid = option; - break; - case Opt_busmode: - if (match_octal(&args[0], &option)) - return -EINVAL; - busmode = option & S_IRWXUGO; - break; - case Opt_listuid: - if (match_int(&args[0], &option)) - return -EINVAL; - listuid = option; - break; - case Opt_listgid: - if (match_int(&args[0], &option)) - return -EINVAL; - listgid = option; - break; - case Opt_listmode: - if (match_octal(&args[0], &option)) - return -EINVAL; - listmode = option & S_IRWXUGO; - break; - default: - printk(KERN_ERR "usbfs: unrecognised mount option " - "\"%s\" or missing value\n", p); - return -EINVAL; - } - } - - return 0; -} - -static void update_special(struct dentry *special) -{ - special->d_inode->i_uid = listuid; - special->d_inode->i_gid = listgid; - special->d_inode->i_mode = S_IFREG | listmode; -} - -static void update_dev(struct dentry *dev) -{ - dev->d_inode->i_uid = devuid; - dev->d_inode->i_gid = devgid; - dev->d_inode->i_mode = S_IFREG | devmode; -} - -static void update_bus(struct dentry *bus) -{ - struct dentry *dev = NULL; - - bus->d_inode->i_uid = busuid; - bus->d_inode->i_gid = busgid; - bus->d_inode->i_mode = S_IFDIR | busmode; - - mutex_lock(&bus->d_inode->i_mutex); - - list_for_each_entry(dev, &bus->d_subdirs, d_u.d_child) - if (dev->d_inode) - update_dev(dev); - - mutex_unlock(&bus->d_inode->i_mutex); -} - -static void update_sb(struct super_block *sb) -{ - struct dentry *root = sb->s_root; - struct dentry *bus = NULL; - - if (!root) - return; - - mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_PARENT); - - list_for_each_entry(bus, &root->d_subdirs, d_u.d_child) { - if (bus->d_inode) { - switch (S_IFMT & bus->d_inode->i_mode) { - case S_IFDIR: - update_bus(bus); - break; - case S_IFREG: - update_special(bus); - break; - default: - printk(KERN_WARNING "usbfs: Unknown node %s " - "mode %x found on remount!\n", - bus->d_name.name, bus->d_inode->i_mode); - break; - } - } - } - - mutex_unlock(&root->d_inode->i_mutex); -} - -static int remount(struct super_block *sb, int *flags, char *data) -{ - /* If this is not a real mount, - * i.e. it's a simple_pin_fs from create_special_files, - * then ignore it. - */ - if (*flags & MS_KERNMOUNT) - return 0; - - if (parse_options(sb, data)) { - printk(KERN_WARNING "usbfs: mount parameter error.\n"); - return -EINVAL; - } - - if (usbfs_mount) - update_sb(usbfs_mount->mnt_sb); - - return 0; -} - -static struct inode *usbfs_get_inode (struct super_block *sb, umode_t mode, dev_t dev) -{ - struct inode *inode = new_inode(sb); - - if (inode) { - inode->i_ino = get_next_ino(); - inode_init_owner(inode, NULL, mode); - inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - switch (mode & S_IFMT) { - default: - init_special_inode(inode, mode, dev); - break; - case S_IFREG: - inode->i_fop = &default_file_operations; - break; - case S_IFDIR: - inode->i_op = &simple_dir_inode_operations; - inode->i_fop = &simple_dir_operations; - - /* directory inodes start off with i_nlink == 2 (for "." entry) */ - inc_nlink(inode); - break; - } - } - return inode; -} - -/* SMP-safe */ -static int usbfs_mknod (struct inode *dir, struct dentry *dentry, umode_t mode, - dev_t dev) -{ - struct inode *inode = usbfs_get_inode(dir->i_sb, mode, dev); - int error = -EPERM; - - if (dentry->d_inode) - return -EEXIST; - - if (inode) { - d_instantiate(dentry, inode); - dget(dentry); - error = 0; - } - return error; -} - -static int usbfs_mkdir (struct inode *dir, struct dentry *dentry, umode_t mode) -{ - int res; - - mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR; - res = usbfs_mknod (dir, dentry, mode, 0); - if (!res) - inc_nlink(dir); - return res; -} - -static int usbfs_create (struct inode *dir, struct dentry *dentry, umode_t mode) -{ - mode = (mode & S_IALLUGO) | S_IFREG; - return usbfs_mknod (dir, dentry, mode, 0); -} - -static inline int usbfs_positive (struct dentry *dentry) -{ - return dentry->d_inode && !d_unhashed(dentry); -} - -static int usbfs_empty (struct dentry *dentry) -{ - struct list_head *list; - - spin_lock(&dentry->d_lock); - list_for_each(list, &dentry->d_subdirs) { - struct dentry *de = list_entry(list, struct dentry, d_u.d_child); - - spin_lock_nested(&de->d_lock, DENTRY_D_LOCK_NESTED); - if (usbfs_positive(de)) { - spin_unlock(&de->d_lock); - spin_unlock(&dentry->d_lock); - return 0; - } - spin_unlock(&de->d_lock); - } - spin_unlock(&dentry->d_lock); - return 1; -} - -static int usbfs_unlink (struct inode *dir, struct dentry *dentry) -{ - struct inode *inode = dentry->d_inode; - mutex_lock(&inode->i_mutex); - drop_nlink(dentry->d_inode); - dput(dentry); - mutex_unlock(&inode->i_mutex); - d_delete(dentry); - return 0; -} - -static int usbfs_rmdir(struct inode *dir, struct dentry *dentry) -{ - int error = -ENOTEMPTY; - struct inode * inode = dentry->d_inode; - - mutex_lock(&inode->i_mutex); - dentry_unhash(dentry); - if (usbfs_empty(dentry)) { - dont_mount(dentry); - drop_nlink(dentry->d_inode); - drop_nlink(dentry->d_inode); - dput(dentry); - inode->i_flags |= S_DEAD; - drop_nlink(dir); - error = 0; - } - mutex_unlock(&inode->i_mutex); - if (!error) - d_delete(dentry); - return error; -} - - -/* default file operations */ -static ssize_t default_read_file (struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - return 0; -} - -static ssize_t default_write_file (struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - return count; -} - -static loff_t default_file_lseek (struct file *file, loff_t offset, int orig) -{ - loff_t retval = -EINVAL; - - mutex_lock(&file->f_path.dentry->d_inode->i_mutex); - switch(orig) { - case 0: - if (offset > 0) { - file->f_pos = offset; - retval = file->f_pos; - } - break; - case 1: - if ((offset + file->f_pos) > 0) { - file->f_pos += offset; - retval = file->f_pos; - } - break; - default: - break; - } - mutex_unlock(&file->f_path.dentry->d_inode->i_mutex); - return retval; -} - -static const struct file_operations default_file_operations = { - .read = default_read_file, - .write = default_write_file, - .open = simple_open, - .llseek = default_file_lseek, -}; - -static const struct super_operations usbfs_ops = { - .statfs = simple_statfs, - .drop_inode = generic_delete_inode, - .remount_fs = remount, - .show_options = usbfs_show_options, -}; - -static int usbfs_fill_super(struct super_block *sb, void *data, int silent) -{ - struct inode *inode; - - sb->s_blocksize = PAGE_CACHE_SIZE; - sb->s_blocksize_bits = PAGE_CACHE_SHIFT; - sb->s_magic = USBDEVICE_SUPER_MAGIC; - sb->s_op = &usbfs_ops; - sb->s_time_gran = 1; - inode = usbfs_get_inode(sb, S_IFDIR | 0755, 0); - sb->s_root = d_make_root(inode); - if (!sb->s_root) { - dbg("%s: could not get root dentry!",__func__); - return -ENOMEM; - } - return 0; -} - -/* - * fs_create_by_name - create a file, given a name - * @name: name of file - * @mode: type of file - * @parent: dentry of directory to create it in - * @dentry: resulting dentry of file - * - * This function handles both regular files and directories. - */ -static int fs_create_by_name (const char *name, umode_t mode, - struct dentry *parent, struct dentry **dentry) -{ - int error = 0; - - /* If the parent is not specified, we create it in the root. - * We need the root dentry to do this, which is in the super - * block. A pointer to that is in the struct vfsmount that we - * have around. - */ - if (!parent ) { - if (usbfs_mount) - parent = usbfs_mount->mnt_root; - } - - if (!parent) { - dbg("Ah! can not find a parent!"); - return -EFAULT; - } - - *dentry = NULL; - mutex_lock(&parent->d_inode->i_mutex); - *dentry = lookup_one_len(name, parent, strlen(name)); - if (!IS_ERR(*dentry)) { - if (S_ISDIR(mode)) - error = usbfs_mkdir (parent->d_inode, *dentry, mode); - else - error = usbfs_create (parent->d_inode, *dentry, mode); - } else - error = PTR_ERR(*dentry); - mutex_unlock(&parent->d_inode->i_mutex); - - return error; -} - -static struct dentry *fs_create_file (const char *name, umode_t mode, - struct dentry *parent, void *data, - const struct file_operations *fops, - uid_t uid, gid_t gid) -{ - struct dentry *dentry; - int error; - - dbg("creating file '%s'",name); - - error = fs_create_by_name (name, mode, parent, &dentry); - if (error) { - dentry = NULL; - } else { - if (dentry->d_inode) { - if (data) - dentry->d_inode->i_private = data; - if (fops) - dentry->d_inode->i_fop = fops; - dentry->d_inode->i_uid = uid; - dentry->d_inode->i_gid = gid; - } - } - - return dentry; -} - -static void fs_remove_file (struct dentry *dentry) -{ - struct dentry *parent = dentry->d_parent; - - if (!parent || !parent->d_inode) - return; - - mutex_lock_nested(&parent->d_inode->i_mutex, I_MUTEX_PARENT); - if (usbfs_positive(dentry)) { - if (dentry->d_inode) { - if (S_ISDIR(dentry->d_inode->i_mode)) - usbfs_rmdir(parent->d_inode, dentry); - else - usbfs_unlink(parent->d_inode, dentry); - dput(dentry); - } - } - mutex_unlock(&parent->d_inode->i_mutex); -} - -/* --------------------------------------------------------------------- */ - -static struct dentry *usb_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - return mount_single(fs_type, flags, data, usbfs_fill_super); -} - -static struct file_system_type usb_fs_type = { - .owner = THIS_MODULE, - .name = "usbfs", - .mount = usb_mount, - .kill_sb = kill_litter_super, -}; - -/* --------------------------------------------------------------------- */ - -static int create_special_files (void) -{ - struct dentry *parent; - int retval; - - /* create the devices special file */ - retval = simple_pin_fs(&usb_fs_type, &usbfs_mount, &usbfs_mount_count); - if (retval) { - printk(KERN_ERR "Unable to get usbfs mount\n"); - goto exit; - } - - parent = usbfs_mount->mnt_root; - devices_usbfs_dentry = fs_create_file ("devices", - listmode | S_IFREG, parent, - NULL, &usbfs_devices_fops, - listuid, listgid); - if (devices_usbfs_dentry == NULL) { - printk(KERN_ERR "Unable to create devices usbfs file\n"); - retval = -ENODEV; - goto error_clean_mounts; - } - - goto exit; - -error_clean_mounts: - simple_release_fs(&usbfs_mount, &usbfs_mount_count); -exit: - return retval; -} - -static void remove_special_files (void) -{ - if (devices_usbfs_dentry) - fs_remove_file (devices_usbfs_dentry); - devices_usbfs_dentry = NULL; - simple_release_fs(&usbfs_mount, &usbfs_mount_count); -} - -void usbfs_update_special (void) -{ - struct inode *inode; - - if (devices_usbfs_dentry) { - inode = devices_usbfs_dentry->d_inode; - if (inode) - inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - } -} - -static void usbfs_add_bus(struct usb_bus *bus) -{ - struct dentry *parent; - char name[8]; - int retval; - - /* create the special files if this is the first bus added */ - if (num_buses == 0) { - retval = create_special_files(); - if (retval) - return; - } - ++num_buses; - - sprintf (name, "%03d", bus->busnum); - - parent = usbfs_mount->mnt_root; - bus->usbfs_dentry = fs_create_file (name, busmode | S_IFDIR, parent, - bus, NULL, busuid, busgid); - if (bus->usbfs_dentry == NULL) { - printk(KERN_ERR "Error creating usbfs bus entry\n"); - return; - } -} - -static void usbfs_remove_bus(struct usb_bus *bus) -{ - if (bus->usbfs_dentry) { - fs_remove_file (bus->usbfs_dentry); - bus->usbfs_dentry = NULL; - } - - --num_buses; - if (num_buses <= 0) { - remove_special_files(); - num_buses = 0; - } -} - -static void usbfs_add_device(struct usb_device *dev) -{ - char name[8]; - int i; - int i_size; - - sprintf (name, "%03d", dev->devnum); - dev->usbfs_dentry = fs_create_file (name, devmode | S_IFREG, - dev->bus->usbfs_dentry, dev, - &usbdev_file_operations, - devuid, devgid); - if (dev->usbfs_dentry == NULL) { - printk(KERN_ERR "Error creating usbfs device entry\n"); - return; - } - - /* Set the size of the device's file to be - * equal to the size of the device descriptors. */ - i_size = sizeof (struct usb_device_descriptor); - for (i = 0; i < dev->descriptor.bNumConfigurations; ++i) { - struct usb_config_descriptor *config = - (struct usb_config_descriptor *)dev->rawdescriptors[i]; - i_size += le16_to_cpu(config->wTotalLength); - } - if (dev->usbfs_dentry->d_inode) - dev->usbfs_dentry->d_inode->i_size = i_size; -} - -static void usbfs_remove_device(struct usb_device *dev) -{ - if (dev->usbfs_dentry) { - fs_remove_file (dev->usbfs_dentry); - dev->usbfs_dentry = NULL; - } -} - -static int usbfs_notify(struct notifier_block *self, unsigned long action, void *dev) -{ - switch (action) { - case USB_DEVICE_ADD: - usbfs_add_device(dev); - break; - case USB_DEVICE_REMOVE: - usbfs_remove_device(dev); - break; - case USB_BUS_ADD: - usbfs_add_bus(dev); - break; - case USB_BUS_REMOVE: - usbfs_remove_bus(dev); - } - - usbfs_update_special(); - usbfs_conn_disc_event(); - return NOTIFY_OK; -} - -static struct notifier_block usbfs_nb = { - .notifier_call = usbfs_notify, -}; - -/* --------------------------------------------------------------------- */ - -static struct proc_dir_entry *usbdir = NULL; - -int __init usbfs_init(void) -{ - int retval; - - retval = register_filesystem(&usb_fs_type); - if (retval) - return retval; - - usb_register_notify(&usbfs_nb); - - /* create mount point for usbfs */ - usbdir = proc_mkdir("bus/usb", NULL); - - return 0; -} - -void usbfs_cleanup(void) -{ - usb_unregister_notify(&usbfs_nb); - unregister_filesystem(&usb_fs_type); - if (usbdir) - remove_proc_entry("bus/usb", NULL); -} - diff --git a/trunk/drivers/usb/core/message.c b/trunk/drivers/usb/core/message.c index ca717da3be95..b548cf1dbc62 100644 --- a/trunk/drivers/usb/core/message.c +++ b/trunk/drivers/usb/core/message.c @@ -1308,10 +1308,19 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) * Remove the current alt setting and add the new alt setting. */ mutex_lock(hcd->bandwidth_mutex); + /* Disable LPM, and re-enable it once the new alt setting is installed, + * so that the xHCI driver can recalculate the U1/U2 timeouts. + */ + if (usb_disable_lpm(dev)) { + dev_err(&iface->dev, "%s Failed to disable LPM\n.", __func__); + mutex_unlock(hcd->bandwidth_mutex); + return -ENOMEM; + } ret = usb_hcd_alloc_bandwidth(dev, NULL, iface->cur_altsetting, alt); if (ret < 0) { dev_info(&dev->dev, "Not enough bandwidth for altsetting %d\n", alternate); + usb_enable_lpm(dev); mutex_unlock(hcd->bandwidth_mutex); return ret; } @@ -1334,6 +1343,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) } else if (ret < 0) { /* Re-instate the old alt setting */ usb_hcd_alloc_bandwidth(dev, NULL, alt, iface->cur_altsetting); + usb_enable_lpm(dev); mutex_unlock(hcd->bandwidth_mutex); return ret; } @@ -1354,6 +1364,9 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) iface->cur_altsetting = alt; + /* Now that the interface is installed, re-enable LPM. */ + usb_unlocked_enable_lpm(dev); + /* If the interface only has one altsetting and the device didn't * accept the request, we attempt to carry out the equivalent action * by manually clearing the HALT feature for each endpoint in the @@ -1437,6 +1450,14 @@ int usb_reset_configuration(struct usb_device *dev) config = dev->actconfig; retval = 0; mutex_lock(hcd->bandwidth_mutex); + /* Disable LPM, and re-enable it once the configuration is reset, so + * that the xHCI driver can recalculate the U1/U2 timeouts. + */ + if (usb_disable_lpm(dev)) { + dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__); + mutex_unlock(hcd->bandwidth_mutex); + return -ENOMEM; + } /* Make sure we have enough bandwidth for each alternate setting 0 */ for (i = 0; i < config->desc.bNumInterfaces; i++) { struct usb_interface *intf = config->interface[i]; @@ -1465,6 +1486,7 @@ int usb_reset_configuration(struct usb_device *dev) usb_hcd_alloc_bandwidth(dev, NULL, alt, intf->cur_altsetting); } + usb_enable_lpm(dev); mutex_unlock(hcd->bandwidth_mutex); return retval; } @@ -1502,6 +1524,8 @@ int usb_reset_configuration(struct usb_device *dev) create_intf_ep_devs(intf); } } + /* Now that the interfaces are installed, re-enable LPM. */ + usb_unlocked_enable_lpm(dev); return 0; } EXPORT_SYMBOL_GPL(usb_reset_configuration); @@ -1763,8 +1787,18 @@ int usb_set_configuration(struct usb_device *dev, int configuration) * this call fails, the device state is unchanged. */ mutex_lock(hcd->bandwidth_mutex); + /* Disable LPM, and re-enable it once the new configuration is + * installed, so that the xHCI driver can recalculate the U1/U2 + * timeouts. + */ + if (usb_disable_lpm(dev)) { + dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__); + mutex_unlock(hcd->bandwidth_mutex); + return -ENOMEM; + } ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL); if (ret < 0) { + usb_enable_lpm(dev); mutex_unlock(hcd->bandwidth_mutex); usb_autosuspend_device(dev); goto free_interfaces; @@ -1784,6 +1818,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) if (!cp) { usb_set_device_state(dev, USB_STATE_ADDRESS); usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL); + usb_enable_lpm(dev); mutex_unlock(hcd->bandwidth_mutex); usb_autosuspend_device(dev); goto free_interfaces; @@ -1838,6 +1873,9 @@ int usb_set_configuration(struct usb_device *dev, int configuration) !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS)) cp->string = usb_cache_string(dev, cp->desc.iConfiguration); + /* Now that the interfaces are installed, re-enable LPM. */ + usb_unlocked_enable_lpm(dev); + /* Now that all the interfaces are set up, register them * to trigger binding of drivers to interfaces. probe() * routines may install different altsettings and may diff --git a/trunk/drivers/usb/core/quirks.c b/trunk/drivers/usb/core/quirks.c index 4c65eb6a867a..32d3adc315f5 100644 --- a/trunk/drivers/usb/core/quirks.c +++ b/trunk/drivers/usb/core/quirks.c @@ -123,6 +123,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* Guillemot Webcam Hercules Dualpix Exchange*/ { USB_DEVICE(0x06f8, 0x3005), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Midiman M-Audio Keystation 88es */ + { USB_DEVICE(0x0763, 0x0192), .driver_info = USB_QUIRK_RESET_RESUME }, + /* M-Systems Flash Disk Pioneers */ { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME }, diff --git a/trunk/drivers/usb/core/sysfs.c b/trunk/drivers/usb/core/sysfs.c index 566d9f94f735..9a56e3adf476 100644 --- a/trunk/drivers/usb/core/sysfs.c +++ b/trunk/drivers/usb/core/sysfs.c @@ -73,7 +73,7 @@ set_bConfigurationValue(struct device *dev, struct device_attribute *attr, return (value < 0) ? value : count; } -static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR, +static DEVICE_ATTR_IGNORE_LOCKDEP(bConfigurationValue, S_IRUGO | S_IWUSR, show_bConfigurationValue, set_bConfigurationValue); /* String fields */ @@ -595,7 +595,7 @@ static ssize_t usb_dev_authorized_store(struct device *dev, return result < 0? result : size; } -static DEVICE_ATTR(authorized, 0644, +static DEVICE_ATTR_IGNORE_LOCKDEP(authorized, 0644, usb_dev_authorized_show, usb_dev_authorized_store); /* "Safely remove a device" */ @@ -618,7 +618,7 @@ static ssize_t usb_remove_store(struct device *dev, usb_unlock_device(udev); return rc; } -static DEVICE_ATTR(remove, 0200, NULL, usb_remove_store); +static DEVICE_ATTR_IGNORE_LOCKDEP(remove, 0200, NULL, usb_remove_store); static struct attribute *dev_attrs[] = { diff --git a/trunk/drivers/usb/core/urb.c b/trunk/drivers/usb/core/urb.c index cd9b3a2cd8a7..9d912bfdcffe 100644 --- a/trunk/drivers/usb/core/urb.c +++ b/trunk/drivers/usb/core/urb.c @@ -680,6 +680,27 @@ void usb_unpoison_urb(struct urb *urb) } EXPORT_SYMBOL_GPL(usb_unpoison_urb); +/** + * usb_block_urb - reliably prevent further use of an URB + * @urb: pointer to URB to be blocked, may be NULL + * + * After the routine has run, attempts to resubmit the URB will fail + * with error -EPERM. Thus even if the URB's completion handler always + * tries to resubmit, it will not succeed and the URB will become idle. + * + * The URB must not be deallocated while this routine is running. In + * particular, when a driver calls this routine, it must insure that the + * completion handler cannot deallocate the URB. + */ +void usb_block_urb(struct urb *urb) +{ + if (!urb) + return; + + atomic_inc(&urb->reject); +} +EXPORT_SYMBOL_GPL(usb_block_urb); + /** * usb_kill_anchored_urbs - cancel transfer requests en masse * @anchor: anchor the requests are bound to diff --git a/trunk/drivers/usb/core/usb-acpi.c b/trunk/drivers/usb/core/usb-acpi.c new file mode 100644 index 000000000000..8947b203d5a4 --- /dev/null +++ b/trunk/drivers/usb/core/usb-acpi.c @@ -0,0 +1,117 @@ +/* + * USB-ACPI glue code + * + * Copyright 2012 Red Hat + * + * 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. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "usb.h" + +static int usb_acpi_check_upc(struct usb_device *udev, acpi_handle handle) +{ + acpi_status status; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *upc; + int ret = 0; + + status = acpi_evaluate_object(handle, "_UPC", NULL, &buffer); + + if (ACPI_FAILURE(status)) + return -ENODEV; + + upc = buffer.pointer; + + if (!upc || (upc->type != ACPI_TYPE_PACKAGE) + || upc->package.count != 4) { + ret = -EINVAL; + goto out; + } + + if (upc->package.elements[0].integer.value) + udev->removable = USB_DEVICE_REMOVABLE; + else + udev->removable = USB_DEVICE_FIXED; + +out: + kfree(upc); + return ret; +} + +static int usb_acpi_check_pld(struct usb_device *udev, acpi_handle handle) +{ + acpi_status status; + struct acpi_pld pld; + + status = acpi_get_physical_device_location(handle, &pld); + + if (ACPI_FAILURE(status)) + return -ENODEV; + + if (pld.user_visible) + udev->removable = USB_DEVICE_REMOVABLE; + else + udev->removable = USB_DEVICE_FIXED; + + return 0; +} + +static int usb_acpi_find_device(struct device *dev, acpi_handle *handle) +{ + struct usb_device *udev; + struct device *parent; + acpi_handle *parent_handle; + + if (!is_usb_device(dev)) + return -ENODEV; + + udev = to_usb_device(dev); + parent = dev->parent; + parent_handle = DEVICE_ACPI_HANDLE(parent); + + if (!parent_handle) + return -ENODEV; + + *handle = acpi_get_child(parent_handle, udev->portnum); + + if (!*handle) + return -ENODEV; + + /* + * PLD will tell us whether a port is removable to the user or + * not. If we don't get an answer from PLD (it's not present + * or it's malformed) then try to infer it from UPC. If a + * device isn't connectable then it's probably not removable. + */ + if (usb_acpi_check_pld(udev, *handle) != 0) + usb_acpi_check_upc(udev, *handle); + + return 0; +} + +static struct acpi_bus_type usb_acpi_bus = { + .bus = &usb_bus_type, + .find_bridge = NULL, + .find_device = usb_acpi_find_device, +}; + +int usb_acpi_register(void) +{ + return register_acpi_bus_type(&usb_acpi_bus); +} + +void usb_acpi_unregister(void) +{ + unregister_acpi_bus_type(&usb_acpi_bus); +} diff --git a/trunk/drivers/usb/core/usb.c b/trunk/drivers/usb/core/usb.c index c74ba7bbc748..25d0c61c3f8a 100644 --- a/trunk/drivers/usb/core/usb.c +++ b/trunk/drivers/usb/core/usb.c @@ -1015,6 +1015,7 @@ static int __init usb_init(void) if (retval) goto out; + usb_acpi_register(); retval = bus_register(&usb_bus_type); if (retval) goto bus_register_failed; @@ -1030,9 +1031,6 @@ static int __init usb_init(void) retval = usb_devio_init(); if (retval) goto usb_devio_init_failed; - retval = usbfs_init(); - if (retval) - goto fs_init_failed; retval = usb_hub_init(); if (retval) goto hub_init_failed; @@ -1042,8 +1040,6 @@ static int __init usb_init(void) usb_hub_cleanup(); hub_init_failed: - usbfs_cleanup(); -fs_init_failed: usb_devio_cleanup(); usb_devio_init_failed: usb_deregister(&usbfs_driver); @@ -1054,6 +1050,7 @@ static int __init usb_init(void) bus_notifier_failed: bus_unregister(&usb_bus_type); bus_register_failed: + usb_acpi_unregister(); usb_debugfs_cleanup(); out: return retval; @@ -1070,12 +1067,12 @@ static void __exit usb_exit(void) usb_deregister_device_driver(&usb_generic_driver); usb_major_cleanup(); - usbfs_cleanup(); usb_deregister(&usbfs_driver); usb_devio_cleanup(); usb_hub_cleanup(); bus_unregister_notifier(&usb_bus_type, &usb_bus_nb); bus_unregister(&usb_bus_type); + usb_acpi_unregister(); usb_debugfs_cleanup(); } diff --git a/trunk/drivers/usb/core/usb.h b/trunk/drivers/usb/core/usb.h index 71648dcbe438..5c5c538ea73d 100644 --- a/trunk/drivers/usb/core/usb.h +++ b/trunk/drivers/usb/core/usb.h @@ -156,3 +156,10 @@ extern void usb_notify_remove_device(struct usb_device *udev); extern void usb_notify_add_bus(struct usb_bus *ubus); extern void usb_notify_remove_bus(struct usb_bus *ubus); +#ifdef CONFIG_ACPI +extern int usb_acpi_register(void); +extern void usb_acpi_unregister(void); +#else +static inline int usb_acpi_register(void) { return 0; }; +static inline void usb_acpi_unregister(void) { }; +#endif diff --git a/trunk/drivers/usb/dwc3/Kconfig b/trunk/drivers/usb/dwc3/Kconfig index d8f741f9e56e..d13c60f42139 100644 --- a/trunk/drivers/usb/dwc3/Kconfig +++ b/trunk/drivers/usb/dwc3/Kconfig @@ -4,7 +4,7 @@ config USB_DWC3 select USB_OTG_UTILS select USB_GADGET_DUALSPEED select USB_GADGET_SUPERSPEED - select USB_XHCI_PLATFORM + select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD help Say Y or M here if your system has a Dual Role SuperSpeed USB controller based on the DesignWare USB3 IP Core. diff --git a/trunk/drivers/usb/dwc3/core.c b/trunk/drivers/usb/dwc3/core.c index 99b58d84553a..1040bdb8dc88 100644 --- a/trunk/drivers/usb/dwc3/core.c +++ b/trunk/drivers/usb/dwc3/core.c @@ -410,7 +410,6 @@ static int __devinit dwc3_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; int ret = -ENOMEM; - int irq; void __iomem *regs; void *mem; @@ -425,15 +424,28 @@ static int __devinit dwc3_probe(struct platform_device *pdev) dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1); dwc->mem = mem; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res) { - dev_err(dev, "missing resource\n"); + dev_err(dev, "missing IRQ\n"); return -ENODEV; } + dwc->xhci_resources[1] = *res; - dwc->res = res; - - res = devm_request_mem_region(dev, res->start, resource_size(res), + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "missing memory resource\n"); + return -ENODEV; + } + dwc->xhci_resources[0] = *res; + dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + + DWC3_XHCI_REGS_END; + + /* + * Request memory region but exclude xHCI regs, + * since it will be requested by the xhci-plat driver. + */ + res = devm_request_mem_region(dev, res->start + DWC3_GLOBALS_REGS_START, + resource_size(res) - DWC3_GLOBALS_REGS_START, dev_name(dev)); if (!res) { dev_err(dev, "can't request mem region\n"); @@ -446,19 +458,12 @@ static int __devinit dwc3_probe(struct platform_device *pdev) return -ENOMEM; } - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(dev, "missing IRQ\n"); - return -ENODEV; - } - spin_lock_init(&dwc->lock); platform_set_drvdata(pdev, dwc); dwc->regs = regs; dwc->regs_size = resource_size(res); dwc->dev = dev; - dwc->irq = irq; if (!strncmp("super", maximum_speed, 5)) dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; diff --git a/trunk/drivers/usb/dwc3/core.h b/trunk/drivers/usb/dwc3/core.h index 6c7945b4cad3..f69c877add09 100644 --- a/trunk/drivers/usb/dwc3/core.h +++ b/trunk/drivers/usb/dwc3/core.h @@ -51,7 +51,9 @@ #include /* Global constants */ +#define DWC3_EP0_BOUNCE_SIZE 512 #define DWC3_ENDPOINTS_NUM 32 +#define DWC3_XHCI_RESOURCES_NUM 2 #define DWC3_EVENT_BUFFERS_SIZE PAGE_SIZE #define DWC3_EVENT_TYPE_MASK 0xfe @@ -75,6 +77,16 @@ #define DWC3_GSNPSID_MASK 0xffff0000 #define DWC3_GSNPSREV_MASK 0xffff +/* DWC3 registers memory space boundries */ +#define DWC3_XHCI_REGS_START 0x0 +#define DWC3_XHCI_REGS_END 0x7fff +#define DWC3_GLOBALS_REGS_START 0xc100 +#define DWC3_GLOBALS_REGS_END 0xc6ff +#define DWC3_DEVICE_REGS_START 0xc700 +#define DWC3_DEVICE_REGS_END 0xcbff +#define DWC3_OTG_REGS_START 0xcc00 +#define DWC3_OTG_REGS_END 0xccff + /* Global Registers */ #define DWC3_GSBUSCFG0 0xc100 #define DWC3_GSBUSCFG1 0xc104 @@ -183,6 +195,7 @@ #define DWC3_GHWPARAMS1_EN_PWROPT_CLK 1 /* Device Configuration Register */ +#define DWC3_DCFG_LPM_CAP (1 << 22) #define DWC3_DCFG_DEVADDR(addr) ((addr) << 3) #define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f) @@ -272,12 +285,14 @@ #define DWC3_DGCMD_SET_ENDPOINT_NRDY 0x0c #define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK 0x10 +#define DWC3_DGCMD_STATUS(n) (((n) >> 15) & 1) +#define DWC3_DGCMD_CMDACT (1 << 10) + /* Device Endpoint Command Register */ #define DWC3_DEPCMD_PARAM_SHIFT 16 #define DWC3_DEPCMD_PARAM(x) ((x) << DWC3_DEPCMD_PARAM_SHIFT) #define DWC3_DEPCMD_GET_RSC_IDX(x) (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f) -#define DWC3_DEPCMD_STATUS_MASK (0x0f << 12) -#define DWC3_DEPCMD_STATUS(x) (((x) & DWC3_DEPCMD_STATUS_MASK) >> 12) +#define DWC3_DEPCMD_STATUS(x) (((x) >> 15) & 1) #define DWC3_DEPCMD_HIPRI_FORCERM (1 << 11) #define DWC3_DEPCMD_CMDACT (1 << 10) #define DWC3_DEPCMD_CMDIOC (1 << 8) @@ -361,7 +376,6 @@ struct dwc3_ep { dma_addr_t trb_pool_dma; u32 free_slot; u32 busy_slot; - const struct usb_endpoint_descriptor *desc; const struct usb_ss_ep_comp_descriptor *comp_desc; struct dwc3 *dwc; @@ -561,6 +575,11 @@ struct dwc3_request { * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround * @needs_fifo_resize: not all users might want fifo resizing, flag it * @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes. + * @isoch_delay: wValue from Set Isochronous Delay request; + * @u2sel: parameter from Set SEL request. + * @u2pel: parameter from Set SEL request. + * @u1sel: parameter from Set SEL request. + * @u1pel: parameter from Set SEL request. * @ep0_next_event: hold the next expected event * @ep0state: state of endpoint zero * @link_state: link state @@ -583,7 +602,7 @@ struct dwc3 { struct device *dev; struct platform_device *xhci; - struct resource *res; + struct resource xhci_resources[DWC3_XHCI_RESOURCES_NUM]; struct dwc3_event_buffer **ev_buffs; struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM]; @@ -594,8 +613,6 @@ struct dwc3 { void __iomem *regs; size_t regs_size; - int irq; - u32 num_event_buffers; u32 u1u2; u32 maximum_speed; @@ -609,6 +626,10 @@ struct dwc3 { #define DWC3_REVISION_185A 0x5533185a #define DWC3_REVISION_188A 0x5533188a #define DWC3_REVISION_190A 0x5533190a +#define DWC3_REVISION_200A 0x5533200a +#define DWC3_REVISION_202A 0x5533202a +#define DWC3_REVISION_210A 0x5533210a +#define DWC3_REVISION_220A 0x5533220a unsigned is_selfpowered:1; unsigned three_stage_setup:1; @@ -625,7 +646,14 @@ struct dwc3 { enum dwc3_link_state link_state; enum dwc3_device_state dev_state; + u16 isoch_delay; + u16 u2sel; + u16 u2pel; + u8 u1sel; + u8 u1pel; + u8 speed; + void *mem; struct dwc3_hwparams hwparams; diff --git a/trunk/drivers/usb/dwc3/dwc3-omap.c b/trunk/drivers/usb/dwc3/dwc3-omap.c index d7d9c0ec9515..479dc047da3a 100644 --- a/trunk/drivers/usb/dwc3/dwc3-omap.c +++ b/trunk/drivers/usb/dwc3/dwc3-omap.c @@ -49,7 +49,6 @@ #include #include "core.h" -#include "io.h" /* * All these registers belong to OMAP's Wrapper around the @@ -143,6 +142,17 @@ struct dwc3_omap { u32 dma_status:1; }; +static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset) +{ + return readl(base + offset); +} + +static inline void dwc3_omap_writel(void __iomem *base, u32 offset, u32 value) +{ + writel(value, base + offset); +} + + static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap) { struct dwc3_omap *omap = _omap; @@ -150,7 +160,7 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap) spin_lock(&omap->lock); - reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_1); + reg = dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_1); if (reg & USBOTGSS_IRQ1_DMADISABLECLR) { dev_dbg(omap->dev, "DMA Disable was Cleared\n"); @@ -184,10 +194,10 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap) if (reg & USBOTGSS_IRQ1_IDPULLUP_FALL) dev_dbg(omap->dev, "IDPULLUP Fall\n"); - dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_1, reg); + dwc3_omap_writel(omap->base, USBOTGSS_IRQSTATUS_1, reg); - reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_0); - dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_0, reg); + reg = dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_0); + dwc3_omap_writel(omap->base, USBOTGSS_IRQSTATUS_0, reg); spin_unlock(&omap->lock); @@ -270,7 +280,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev) omap->base = base; omap->dwc3 = dwc3; - reg = dwc3_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS); + reg = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS); utmi_mode = of_get_property(node, "utmi-mode", &size); if (utmi_mode && size == sizeof(*utmi_mode)) { @@ -293,10 +303,10 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev) } } - dwc3_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg); + dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg); /* check the DMA Status */ - reg = dwc3_readl(omap->base, USBOTGSS_SYSCONFIG); + reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG); omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE); /* Set No-Idle and No-Standby */ @@ -306,7 +316,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev) reg |= (USBOTGSS_SYSCONFIG_STANDBYMODE(USBOTGSS_STANDBYMODE_NO_STANDBY) | USBOTGSS_SYSCONFIG_IDLEMODE(USBOTGSS_IDLEMODE_NO_IDLE)); - dwc3_writel(omap->base, USBOTGSS_SYSCONFIG, reg); + dwc3_omap_writel(omap->base, USBOTGSS_SYSCONFIG, reg); ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0, "dwc3-omap", omap); @@ -318,7 +328,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev) /* enable all IRQs */ reg = USBOTGSS_IRQO_COREIRQ_ST; - dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg); + dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg); reg = (USBOTGSS_IRQ1_OEVT | USBOTGSS_IRQ1_DRVVBUS_RISE | @@ -330,7 +340,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev) USBOTGSS_IRQ1_DISCHRGVBUS_FALL | USBOTGSS_IRQ1_IDPULLUP_FALL); - dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg); + dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg); ret = platform_device_add_resources(dwc3, pdev->resource, pdev->num_resources); diff --git a/trunk/drivers/usb/dwc3/ep0.c b/trunk/drivers/usb/dwc3/ep0.c index 3584a169886f..9e8a3dce69fd 100644 --- a/trunk/drivers/usb/dwc3/ep0.c +++ b/trunk/drivers/usb/dwc3/ep0.c @@ -179,7 +179,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, int ret; spin_lock_irqsave(&dwc->lock, flags); - if (!dep->desc) { + if (!dep->endpoint.desc) { dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n", request, dep->name); ret = -ESHUTDOWN; @@ -261,6 +261,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, { struct dwc3_ep *dep; u32 recip; + u32 reg; u16 usb_status = 0; __le16 *response_pkt; @@ -268,10 +269,18 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, switch (recip) { case USB_RECIP_DEVICE: /* - * We are self-powered. U1/U2/LTM will be set later - * once we handle this states. RemoteWakeup is 0 on SS + * LTM will be set once we know how to set this in HW. */ usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED; + + if (dwc->speed == DWC3_DSTS_SUPERSPEED) { + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + if (reg & DWC3_DCTL_INITU1ENA) + usb_status |= 1 << USB_DEV_STAT_U1_ENABLED; + if (reg & DWC3_DCTL_INITU2ENA) + usb_status |= 1 << USB_DEV_STAT_U2_ENABLED; + } + break; case USB_RECIP_INTERFACE: @@ -312,6 +321,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, u32 recip; u32 wValue; u32 wIndex; + u32 reg; int ret; wValue = le16_to_cpu(ctrl->wValue); @@ -320,29 +330,43 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, switch (recip) { case USB_RECIP_DEVICE: + switch (wValue) { + case USB_DEVICE_REMOTE_WAKEUP: + break; /* * 9.4.1 says only only for SS, in AddressState only for * default control pipe */ - switch (wValue) { case USB_DEVICE_U1_ENABLE: - case USB_DEVICE_U2_ENABLE: - case USB_DEVICE_LTM_ENABLE: if (dwc->dev_state != DWC3_CONFIGURED_STATE) return -EINVAL; if (dwc->speed != DWC3_DSTS_SUPERSPEED) return -EINVAL; - } - /* XXX add U[12] & LTM */ - switch (wValue) { - case USB_DEVICE_REMOTE_WAKEUP: - break; - case USB_DEVICE_U1_ENABLE: + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + if (set) + reg |= DWC3_DCTL_INITU1ENA; + else + reg &= ~DWC3_DCTL_INITU1ENA; + dwc3_writel(dwc->regs, DWC3_DCTL, reg); break; + case USB_DEVICE_U2_ENABLE: + if (dwc->dev_state != DWC3_CONFIGURED_STATE) + return -EINVAL; + if (dwc->speed != DWC3_DSTS_SUPERSPEED) + return -EINVAL; + + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + if (set) + reg |= DWC3_DCTL_INITU2ENA; + else + reg &= ~DWC3_DCTL_INITU2ENA; + dwc3_writel(dwc->regs, DWC3_DCTL, reg); break; + case USB_DEVICE_LTM_ENABLE: + return -EINVAL; break; case USB_DEVICE_TEST_MODE: @@ -469,6 +493,107 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) return ret; } +static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req) +{ + struct dwc3_ep *dep = to_dwc3_ep(ep); + struct dwc3 *dwc = dep->dwc; + + u32 param = 0; + u32 reg; + + struct timing { + u8 u1sel; + u8 u1pel; + u16 u2sel; + u16 u2pel; + } __packed timing; + + int ret; + + memcpy(&timing, req->buf, sizeof(timing)); + + dwc->u1sel = timing.u1sel; + dwc->u1pel = timing.u1pel; + dwc->u2sel = timing.u2sel; + dwc->u2pel = timing.u2pel; + + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + if (reg & DWC3_DCTL_INITU2ENA) + param = dwc->u2pel; + if (reg & DWC3_DCTL_INITU1ENA) + param = dwc->u1pel; + + /* + * According to Synopsys Databook, if parameter is + * greater than 125, a value of zero should be + * programmed in the register. + */ + if (param > 125) + param = 0; + + /* now that we have the time, issue DGCMD Set Sel */ + ret = dwc3_send_gadget_generic_command(dwc, + DWC3_DGCMD_SET_PERIODIC_PAR, param); + WARN_ON(ret < 0); +} + +static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) +{ + struct dwc3_ep *dep; + u16 wLength; + u16 wValue; + + if (dwc->dev_state == DWC3_DEFAULT_STATE) + return -EINVAL; + + wValue = le16_to_cpu(ctrl->wValue); + wLength = le16_to_cpu(ctrl->wLength); + + if (wLength != 6) { + dev_err(dwc->dev, "Set SEL should be 6 bytes, got %d\n", + wLength); + return -EINVAL; + } + + /* + * To handle Set SEL we need to receive 6 bytes from Host. So let's + * queue a usb_request for 6 bytes. + * + * Remember, though, this controller can't handle non-wMaxPacketSize + * aligned transfers on the OUT direction, so we queue a request for + * wMaxPacketSize instead. + */ + dep = dwc->eps[0]; + dwc->ep0_usb_req.dep = dep; + dwc->ep0_usb_req.request.length = dep->endpoint.maxpacket; + dwc->ep0_usb_req.request.buf = dwc->setup_buf; + dwc->ep0_usb_req.request.complete = dwc3_ep0_set_sel_cmpl; + + return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req); +} + +static int dwc3_ep0_set_isoch_delay(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) +{ + u16 wLength; + u16 wValue; + u16 wIndex; + + wValue = le16_to_cpu(ctrl->wValue); + wLength = le16_to_cpu(ctrl->wLength); + wIndex = le16_to_cpu(ctrl->wIndex); + + if (wIndex || wLength) + return -EINVAL; + + /* + * REVISIT It's unclear from Databook what to do with this + * value. For now, just cache it. + */ + dwc->isoch_delay = wValue; + + return 0; +} + static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) { int ret; @@ -494,6 +619,14 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) dev_vdbg(dwc->dev, "USB_REQ_SET_CONFIGURATION\n"); ret = dwc3_ep0_set_config(dwc, ctrl); break; + case USB_REQ_SET_SEL: + dev_vdbg(dwc->dev, "USB_REQ_SET_SEL\n"); + ret = dwc3_ep0_set_sel(dwc, ctrl); + break; + case USB_REQ_SET_ISOCH_DELAY: + dev_vdbg(dwc->dev, "USB_REQ_SET_ISOCH_DELAY\n"); + ret = dwc3_ep0_set_isoch_delay(dwc, ctrl); + break; default: dev_vdbg(dwc->dev, "Forwarding to gadget driver\n"); ret = dwc3_ep0_delegate_req(dwc, ctrl); diff --git a/trunk/drivers/usb/dwc3/gadget.c b/trunk/drivers/usb/dwc3/gadget.c index 5255fe975ea1..3df1a1973b05 100644 --- a/trunk/drivers/usb/dwc3/gadget.c +++ b/trunk/drivers/usb/dwc3/gadget.c @@ -178,8 +178,8 @@ int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc) if (!(dep->flags & DWC3_EP_ENABLED)) continue; - if (usb_endpoint_xfer_bulk(dep->desc) - || usb_endpoint_xfer_isoc(dep->desc)) + if (usb_endpoint_xfer_bulk(dep->endpoint.desc) + || usb_endpoint_xfer_isoc(dep->endpoint.desc)) mult = 3; /* @@ -229,7 +229,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, * completed (not the LINK TRB). */ if (((dep->busy_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) && - usb_endpoint_xfer_isoc(dep->desc)) + usb_endpoint_xfer_isoc(dep->endpoint.desc)) dep->busy_slot++; } list_del(&req->list); @@ -276,6 +276,33 @@ static const char *dwc3_gadget_ep_cmd_string(u8 cmd) } } +int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param) +{ + u32 timeout = 500; + u32 reg; + + dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param); + dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT); + + do { + reg = dwc3_readl(dwc->regs, DWC3_DGCMD); + if (!(reg & DWC3_DGCMD_CMDACT)) { + dev_vdbg(dwc->dev, "Command Complete --> %d\n", + DWC3_DGCMD_STATUS(reg)); + return 0; + } + + /* + * We can't sleep here, because it's also called from + * interrupt context. + */ + timeout--; + if (!timeout) + return -ETIMEDOUT; + udelay(1); + } while (1); +} + int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, unsigned cmd, struct dwc3_gadget_ep_cmd_params *params) { @@ -470,7 +497,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, if (ret) return ret; - dep->desc = desc; + dep->endpoint.desc = desc; dep->comp_desc = comp_desc; dep->type = usb_endpoint_type(desc); dep->flags |= DWC3_EP_ENABLED; @@ -533,7 +560,6 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) dwc3_writel(dwc->regs, DWC3_DALEPENA, reg); dep->stream_capable = false; - dep->desc = NULL; dep->endpoint.desc = NULL; dep->comp_desc = NULL; dep->type = 0; @@ -694,7 +720,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, /* Skip the LINK-TRB on ISOC */ if (((cur_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) && - usb_endpoint_xfer_isoc(dep->desc)) + usb_endpoint_xfer_isoc(dep->endpoint.desc)) return; if (!req->trb) { @@ -707,7 +733,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, trb->bpl = lower_32_bits(dma); trb->bph = upper_32_bits(dma); - switch (usb_endpoint_type(dep->desc)) { + switch (usb_endpoint_type(dep->endpoint.desc)) { case USB_ENDPOINT_XFER_CONTROL: trb->ctrl = DWC3_TRBCTL_CONTROL_SETUP; break; @@ -732,7 +758,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, BUG(); } - if (usb_endpoint_xfer_isoc(dep->desc)) { + if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI; trb->ctrl |= DWC3_TRB_CTRL_CSP; } else { @@ -743,7 +769,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, trb->ctrl |= DWC3_TRB_CTRL_LST; } - if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable) + if (usb_endpoint_xfer_bulk(dep->endpoint.desc) && dep->stream_capable) trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(req->request.stream_id); trb->ctrl |= DWC3_TRB_CTRL_HWO; @@ -771,7 +797,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting) trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK; /* Can't wrap around on a non-isoc EP since there's no link TRB */ - if (!usb_endpoint_xfer_isoc(dep->desc)) { + if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) { max = DWC3_TRB_NUM - (dep->free_slot & DWC3_TRB_MASK); if (trbs_left > max) trbs_left = max; @@ -797,7 +823,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting) * processed from the first TRB until the last one. Since we * don't wrap around we have to start at the beginning. */ - if (usb_endpoint_xfer_isoc(dep->desc)) { + if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { dep->busy_slot = 1; dep->free_slot = 1; } else { @@ -807,7 +833,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting) } /* The last TRB is a link TRB, not used for xfer */ - if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->desc)) + if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->endpoint.desc)) return; list_for_each_entry_safe(req, n, &dep->request_list, list) { @@ -930,10 +956,12 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param, } dep->flags |= DWC3_EP_BUSY; - dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc, - dep->number); - WARN_ON_ONCE(!dep->res_trans_idx); + if (start_new) { + dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc, + dep->number); + WARN_ON_ONCE(!dep->res_trans_idx); + } return 0; } @@ -967,28 +995,37 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) list_add_tail(&req->list, &dep->request_list); + if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && (dep->flags & DWC3_EP_BUSY)) + dep->flags |= DWC3_EP_PENDING_REQUEST; + /* - * There is one special case: XferNotReady with - * empty list of requests. We need to kick the - * transfer here in that situation, otherwise - * we will be NAKing forever. + * There are two special cases: + * + * 1. XferNotReady with empty list of requests. We need to kick the + * transfer here in that situation, otherwise we will be NAKing + * forever. If we get XferNotReady before gadget driver has a + * chance to queue a request, we will ACK the IRQ but won't be + * able to receive the data until the next request is queued. + * The following code is handling exactly that. * - * If we get XferNotReady before gadget driver - * has a chance to queue a request, we will ACK - * the IRQ but won't be able to receive the data - * until the next request is queued. The following - * code is handling exactly that. + * 2. XferInProgress on Isoc EP with an active transfer. We need to + * kick the transfer here after queuing a request, otherwise the + * core may not see the modified TRB(s). */ if (dep->flags & DWC3_EP_PENDING_REQUEST) { - int ret; - int start_trans; + int ret; + int start_trans = 1; + u8 trans_idx = dep->res_trans_idx; - start_trans = 1; - if (usb_endpoint_xfer_isoc(dep->desc) && - (dep->flags & DWC3_EP_BUSY)) + if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && + (dep->flags & DWC3_EP_BUSY)) { start_trans = 0; + WARN_ON_ONCE(!trans_idx); + } else { + trans_idx = 0; + } - ret = __dwc3_gadget_kick_transfer(dep, 0, start_trans); + ret = __dwc3_gadget_kick_transfer(dep, trans_idx, start_trans); if (ret && ret != -EBUSY) { struct dwc3 *dwc = dep->dwc; @@ -1011,7 +1048,7 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, int ret; - if (!dep->desc) { + if (!dep->endpoint.desc) { dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n", request, ep->name); return -ESHUTDOWN; @@ -1125,7 +1162,7 @@ static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value) spin_lock_irqsave(&dwc->lock, flags); - if (usb_endpoint_xfer_isoc(dep->desc)) { + if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { dev_err(dwc->dev, "%s is of Isochronous type\n", dep->name); ret = -EINVAL; goto out; @@ -1356,7 +1393,24 @@ static int dwc3_gadget_start(struct usb_gadget *g, reg = dwc3_readl(dwc->regs, DWC3_DCFG); reg &= ~(DWC3_DCFG_SPEED_MASK); - reg |= dwc->maximum_speed; + + /** + * WORKAROUND: DWC3 revision < 2.20a have an issue + * which would cause metastability state on Run/Stop + * bit if we try to force the IP to USB2-only mode. + * + * Because of that, we cannot configure the IP to any + * speed other than the SuperSpeed + * + * Refers to: + * + * STAR#9000525659: Clock Domain Crossing on DCTL in + * USB 2.0 Mode + */ + if (dwc->revision < DWC3_REVISION_220A) + reg |= DWC3_DCFG_SUPERSPEED; + else + reg |= dwc->maximum_speed; dwc3_writel(dwc->regs, DWC3_DCFG, reg); dwc->start_config_issued = false; @@ -1681,7 +1735,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, case DWC3_DEPEVT_XFERCOMPLETE: dep->res_trans_idx = 0; - if (usb_endpoint_xfer_isoc(dep->desc)) { + if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { dev_dbg(dwc->dev, "%s is an Isochronous endpoint\n", dep->name); return; @@ -1690,7 +1744,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, dwc3_endpoint_transfer_complete(dwc, dep, event, 1); break; case DWC3_DEPEVT_XFERINPROGRESS: - if (!usb_endpoint_xfer_isoc(dep->desc)) { + if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) { dev_dbg(dwc->dev, "%s is not an Isochronous endpoint\n", dep->name); return; @@ -1699,7 +1753,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, dwc3_endpoint_transfer_complete(dwc, dep, event, 0); break; case DWC3_DEPEVT_XFERNOTREADY: - if (usb_endpoint_xfer_isoc(dep->desc)) { + if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { dwc3_gadget_start_isoc(dwc, dep, event); } else { int ret; @@ -1720,7 +1774,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, break; case DWC3_DEPEVT_STREAMEVT: - if (!usb_endpoint_xfer_bulk(dep->desc)) { + if (!usb_endpoint_xfer_bulk(dep->endpoint.desc)) { dev_err(dwc->dev, "Stream event for non-Bulk %s\n", dep->name); return; @@ -1916,6 +1970,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg &= ~DWC3_DCTL_TSTCTRL_MASK; + reg &= ~(DWC3_DCTL_INITU1ENA | DWC3_DCTL_INITU2ENA); dwc3_writel(dwc->regs, DWC3_DCTL, reg); dwc->test_mode = false; @@ -2263,8 +2318,7 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc) goto err1; } - dwc->setup_buf = kzalloc(sizeof(*dwc->setup_buf) * 2, - GFP_KERNEL); + dwc->setup_buf = kzalloc(DWC3_EP0_BOUNCE_SIZE, GFP_KERNEL); if (!dwc->setup_buf) { dev_err(dwc->dev, "failed to allocate setup buffer\n"); ret = -ENOMEM; @@ -2272,7 +2326,8 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc) } dwc->ep0_bounce = dma_alloc_coherent(dwc->dev, - 512, &dwc->ep0_bounce_addr, GFP_KERNEL); + DWC3_EP0_BOUNCE_SIZE, &dwc->ep0_bounce_addr, + GFP_KERNEL); if (!dwc->ep0_bounce) { dev_err(dwc->dev, "failed to allocate ep0 bounce buffer\n"); ret = -ENOMEM; @@ -2313,6 +2368,14 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc) goto err5; } + reg = dwc3_readl(dwc->regs, DWC3_DCFG); + reg |= DWC3_DCFG_LPM_CAP; + dwc3_writel(dwc->regs, DWC3_DCFG, reg); + + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + reg |= DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA; + dwc3_writel(dwc->regs, DWC3_DCTL, reg); + /* Enable all but Start and End of Frame IRQs */ reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN | DWC3_DEVTEN_EVNTOVERFLOWEN | @@ -2351,8 +2414,8 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc) dwc3_gadget_free_endpoints(dwc); err4: - dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce, - dwc->ep0_bounce_addr); + dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE, + dwc->ep0_bounce, dwc->ep0_bounce_addr); err3: kfree(dwc->setup_buf); @@ -2381,8 +2444,8 @@ void dwc3_gadget_exit(struct dwc3 *dwc) dwc3_gadget_free_endpoints(dwc); - dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce, - dwc->ep0_bounce_addr); + dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE, + dwc->ep0_bounce, dwc->ep0_bounce_addr); kfree(dwc->setup_buf); diff --git a/trunk/drivers/usb/dwc3/gadget.h b/trunk/drivers/usb/dwc3/gadget.h index a8600084348c..95ef6a2f7764 100644 --- a/trunk/drivers/usb/dwc3/gadget.h +++ b/trunk/drivers/usb/dwc3/gadget.h @@ -111,6 +111,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value); int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, unsigned cmd, struct dwc3_gadget_ep_cmd_params *params); +int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param); /** * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW diff --git a/trunk/drivers/usb/dwc3/host.c b/trunk/drivers/usb/dwc3/host.c index b108d18fd40d..56a62342884d 100644 --- a/trunk/drivers/usb/dwc3/host.c +++ b/trunk/drivers/usb/dwc3/host.c @@ -39,15 +39,6 @@ #include "core.h" -static struct resource generic_resources[] = { - { - .flags = IORESOURCE_IRQ, - }, - { - .flags = IORESOURCE_MEM, - }, -}; - int dwc3_host_init(struct dwc3 *dwc) { struct platform_device *xhci; @@ -68,14 +59,8 @@ int dwc3_host_init(struct dwc3 *dwc) dwc->xhci = xhci; - /* setup resources */ - generic_resources[0].start = dwc->irq; - - generic_resources[1].start = dwc->res->start; - generic_resources[1].end = dwc->res->start + 0x7fff; - - ret = platform_device_add_resources(xhci, generic_resources, - ARRAY_SIZE(generic_resources)); + ret = platform_device_add_resources(xhci, dwc->xhci_resources, + DWC3_XHCI_RESOURCES_NUM); if (ret) { dev_err(dwc->dev, "couldn't add resources to xHCI device\n"); goto err1; diff --git a/trunk/drivers/usb/dwc3/io.h b/trunk/drivers/usb/dwc3/io.h index 071d561f3e68..a50f76b9d19b 100644 --- a/trunk/drivers/usb/dwc3/io.h +++ b/trunk/drivers/usb/dwc3/io.h @@ -41,14 +41,26 @@ #include +#include "core.h" + static inline u32 dwc3_readl(void __iomem *base, u32 offset) { - return readl(base + offset); + /* + * We requested the mem region starting from the Globals address + * space, see dwc3_probe in core.c. + * However, the offsets are given starting from xHCI address space. + */ + return readl(base + (offset - DWC3_GLOBALS_REGS_START)); } static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value) { - writel(value, base + offset); + /* + * We requested the mem region starting from the Globals address + * space, see dwc3_probe in core.c. + * However, the offsets are given starting from xHCI address space. + */ + writel(value, base + (offset - DWC3_GLOBALS_REGS_START)); } #endif /* __DRIVERS_USB_DWC3_IO_H */ diff --git a/trunk/drivers/usb/gadget/Kconfig b/trunk/drivers/usb/gadget/Kconfig index 2633f7595116..bddc8fd9a7be 100644 --- a/trunk/drivers/usb/gadget/Kconfig +++ b/trunk/drivers/usb/gadget/Kconfig @@ -123,13 +123,7 @@ config USB_GADGET_STORAGE_NUM_BUFFERS # - discrete ones (including all PCI-only controllers) # - debug/dummy gadget+hcd is last. # -choice - prompt "USB Peripheral Controller" - help - A USB device uses a controller to talk to its host. - Systems should have only one such upstream link. - Many controller drivers are platform-specific; these - often need board-specific hooks. +menu "USB Peripheral Controller" # # Integrated controllers @@ -147,6 +141,17 @@ config USB_AT91 dynamically linked module called "at91_udc" and force all gadget drivers to also be dynamically linked. +config USB_LPC32XX + tristate "LPC32XX USB Peripheral Controller" + depends on ARCH_LPC32XX + select USB_ISP1301 + help + This option selects the USB device controller in the LPC32xx SoC. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "lpc32xx_udc" and force all + gadget drivers to also be dynamically linked. + config USB_ATMEL_USBA tristate "Atmel USBA" select USB_GADGET_DUALSPEED @@ -161,7 +166,7 @@ config USB_FSL_USB2 select USB_GADGET_DUALSPEED select USB_FSL_MPH_DR_OF if OF help - Some of Freescale PowerPC processors have a High Speed + Some of Freescale PowerPC and i.MX processors have a High Speed Dual-Role(DR) USB controller, which supports device mode. The number of programmable endpoints is different through @@ -373,18 +378,6 @@ config USB_FSL_QE Set CONFIG_USB_GADGET to "m" to build this driver as a dynamically linked module called "fsl_qe_udc". -config USB_CI13XXX_PCI - tristate "MIPS USB CI13xxx PCI UDC" - depends on PCI - select USB_GADGET_DUALSPEED - help - MIPS USB IP core family device controller - Currently it only supports IP part number CI13412 - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "ci13xxx_udc" and force all - gadget drivers to also be dynamically linked. - config USB_NET2272 tristate "PLX NET2272" select USB_GADGET_DUALSPEED @@ -438,22 +431,6 @@ config USB_GOKU dynamically linked module called "goku_udc" and to force all gadget drivers to also be dynamically linked. -config USB_LANGWELL - tristate "Intel Langwell USB Device Controller" - depends on PCI - depends on !PHYS_ADDR_T_64BIT - select USB_GADGET_DUALSPEED - help - Intel Langwell USB Device Controller is a High-Speed USB - On-The-Go device controller. - - The number of programmable endpoints is different through - controller revision. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "langwell_udc" and force all - gadget drivers to also be dynamically linked. - config USB_EG20T tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC" depends on PCI @@ -477,23 +454,6 @@ config USB_EG20T ML7213/ML7831 is companion chip for Intel Atom E6xx series. ML7213/ML7831 is completely compatible for Intel EG20T PCH. -config USB_CI13XXX_MSM - tristate "MIPS USB CI13xxx for MSM" - depends on ARCH_MSM - select USB_GADGET_DUALSPEED - select USB_MSM_OTG - help - MSM SoC has chipidea USB controller. This driver uses - ci13xxx_udc core. - This driver depends on OTG driver for PHY initialization, - clock management, powering up VBUS, and power management. - This driver is not supported on boards like trout which - has an external PHY. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "ci13xxx_msm" and force all - gadget drivers to also be dynamically linked. - # # LAST -- dummy/emulated controller # @@ -525,7 +485,7 @@ config USB_DUMMY_HCD # NOTE: Please keep dummy_hcd LAST so that "real hardware" appears # first and will be selected by default. -endchoice +endmenu # Selected by UDC drivers that support high-speed operation. config USB_GADGET_DUALSPEED @@ -798,6 +758,16 @@ config USB_MASS_STORAGE Say "y" to link the driver statically, or "m" to build a dynamically linked module called "g_mass_storage". +config USB_GADGET_TARGET + tristate "USB Gadget Target Fabric Module" + depends on TARGET_CORE + help + This fabric is an USB gadget. Two USB protocols are supported that is + BBB or BOT (Bulk Only Transport) and UAS (USB Attached SCSI). BOT is + advertised on alternative interface 0 (primary) and UAS is on + alternative interface 1. Both protocols can work on USB2.0 and USB3.0. + UAS utilizes the USB 3.0 feature called streams support. + config USB_G_SERIAL tristate "Serial Gadget (with CDC ACM and CDC OBEX support)" help diff --git a/trunk/drivers/usb/gadget/Makefile b/trunk/drivers/usb/gadget/Makefile index b7f6eefc3927..1811513f1c27 100644 --- a/trunk/drivers/usb/gadget/Makefile +++ b/trunk/drivers/usb/gadget/Makefile @@ -22,14 +22,12 @@ 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_CI13XXX_PCI) += ci13xxx_pci.o obj-$(CONFIG_USB_S3C_HSOTG) += s3c-hsotg.o obj-$(CONFIG_USB_S3C_HSUDC) += s3c-hsudc.o -obj-$(CONFIG_USB_LANGWELL) += langwell_udc.o +obj-$(CONFIG_USB_LPC32XX) += lpc32xx_udc.o obj-$(CONFIG_USB_EG20T) += pch_udc.o obj-$(CONFIG_USB_MV_UDC) += mv_udc.o mv_udc-y := mv_udc_core.o -obj-$(CONFIG_USB_CI13XXX_MSM) += ci13xxx_msm.o obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o # @@ -52,6 +50,7 @@ g_nokia-y := nokia.o g_webcam-y := webcam.o g_ncm-y := ncm.o g_acm_ms-y := acm_ms.o +g_tcm_usb_gadget-y := tcm_usb_gadget.o obj-$(CONFIG_USB_ZERO) += g_zero.o obj-$(CONFIG_USB_AUDIO) += g_audio.o @@ -71,3 +70,4 @@ obj-$(CONFIG_USB_G_NOKIA) += g_nokia.o obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o obj-$(CONFIG_USB_G_NCM) += g_ncm.o obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o +obj-$(CONFIG_USB_GADGET_TARGET) += tcm_usb_gadget.o diff --git a/trunk/drivers/usb/gadget/amd5536udc.c b/trunk/drivers/usb/gadget/amd5536udc.c index 77779271f487..187d21181cd5 100644 --- a/trunk/drivers/usb/gadget/amd5536udc.c +++ b/trunk/drivers/usb/gadget/amd5536udc.c @@ -333,7 +333,7 @@ udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc) return -ESHUTDOWN; spin_lock_irqsave(&dev->lock, iflags); - ep->desc = desc; + ep->ep.desc = desc; ep->halted = 0; @@ -442,7 +442,6 @@ static void ep_init(struct udc_regs __iomem *regs, struct udc_ep *ep) u32 tmp; VDBG(ep->dev, "ep-%d reset\n", ep->num); - ep->desc = NULL; ep->ep.desc = NULL; ep->ep.ops = &udc_ep_ops; INIT_LIST_HEAD(&ep->queue); @@ -489,7 +488,7 @@ static int udc_ep_disable(struct usb_ep *usbep) return -EINVAL; ep = container_of(usbep, struct udc_ep, ep); - if (usbep->name == ep0_string || !ep->desc) + if (usbep->name == ep0_string || !ep->ep.desc) return -EINVAL; DBG(ep->dev, "Disable ep-%d\n", ep->num); @@ -1066,7 +1065,7 @@ udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp) return -EINVAL; ep = container_of(usbep, struct udc_ep, ep); - if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX)) + if (!ep->ep.desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX)) return -EINVAL; VDBG(ep->dev, "udc_queue(): ep%d-in=%d\n", ep->num, ep->in); @@ -1257,7 +1256,7 @@ static int udc_dequeue(struct usb_ep *usbep, struct usb_request *usbreq) unsigned long iflags; ep = container_of(usbep, struct udc_ep, ep); - if (!usbep || !usbreq || (!ep->desc && (ep->num != 0 + if (!usbep || !usbreq || (!ep->ep.desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))) return -EINVAL; @@ -1317,7 +1316,7 @@ udc_set_halt(struct usb_ep *usbep, int halt) pr_debug("set_halt %s: halt=%d\n", usbep->name, halt); ep = container_of(usbep, struct udc_ep, ep); - if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX)) + if (!ep->ep.desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX)) return -EINVAL; if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) return -ESHUTDOWN; @@ -1539,7 +1538,7 @@ static void udc_setup_endpoints(struct udc *dev) * disabling ep interrupts when ENUM interrupt occurs but ep is * not enabled by gadget driver */ - if (!ep->desc) + if (!ep->ep.desc) ep_init(dev->regs, ep); if (use_dma) { @@ -3402,19 +3401,7 @@ static struct pci_driver udc_pci_driver = { .remove = udc_pci_remove, }; -/* Inits driver */ -static int __init init(void) -{ - return pci_register_driver(&udc_pci_driver); -} -module_init(init); - -/* Cleans driver */ -static void __exit cleanup(void) -{ - pci_unregister_driver(&udc_pci_driver); -} -module_exit(cleanup); +module_pci_driver(udc_pci_driver); MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION); MODULE_AUTHOR("Thomas Dahlmann"); diff --git a/trunk/drivers/usb/gadget/amd5536udc.h b/trunk/drivers/usb/gadget/amd5536udc.h index f87e29c65325..14af87d65caa 100644 --- a/trunk/drivers/usb/gadget/amd5536udc.h +++ b/trunk/drivers/usb/gadget/amd5536udc.h @@ -512,7 +512,6 @@ struct udc_ep { /* queue for requests */ struct list_head queue; - const struct usb_endpoint_descriptor *desc; unsigned halted; unsigned cancel_transfer; unsigned num : 5, diff --git a/trunk/drivers/usb/gadget/at91_udc.c b/trunk/drivers/usb/gadget/at91_udc.c index 9d7bcd910074..1a4430f315c3 100644 --- a/trunk/drivers/usb/gadget/at91_udc.c +++ b/trunk/drivers/usb/gadget/at91_udc.c @@ -212,7 +212,7 @@ static int proc_udc_show(struct seq_file *s, void *unused) if (udc->enabled && udc->vbus) { proc_ep_show(s, &udc->ep[0]); list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) { - if (ep->desc) + if (ep->ep.desc) proc_ep_show(s, ep); } } @@ -475,7 +475,7 @@ static int at91_ep_enable(struct usb_ep *_ep, unsigned long flags; if (!_ep || !ep - || !desc || ep->desc + || !desc || ep->ep.desc || _ep->name == ep0name || desc->bDescriptorType != USB_DT_ENDPOINT || (maxpacket = usb_endpoint_maxp(desc)) == 0 @@ -530,7 +530,7 @@ static int at91_ep_enable(struct usb_ep *_ep, tmp |= AT91_UDP_EPEDS; __raw_writel(tmp, ep->creg); - ep->desc = desc; + ep->ep.desc = desc; ep->ep.maxpacket = maxpacket; /* @@ -558,7 +558,6 @@ static int at91_ep_disable (struct usb_ep * _ep) nuke(ep, -ESHUTDOWN); /* restore the endpoint's pristine config */ - ep->desc = NULL; ep->ep.desc = NULL; ep->ep.maxpacket = ep->maxpacket; @@ -618,7 +617,7 @@ static int at91_ep_queue(struct usb_ep *_ep, return -EINVAL; } - if (!_ep || (!ep->desc && ep->ep.name != ep0name)) { + if (!_ep || (!ep->ep.desc && ep->ep.name != ep0name)) { DBG("invalid ep\n"); return -EINVAL; } @@ -833,7 +832,7 @@ static void udc_reinit(struct at91_udc *udc) if (i != 0) list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); - ep->desc = NULL; + ep->ep.desc = NULL; ep->stopped = 0; ep->fifo_bank = 0; ep->ep.maxpacket = ep->maxpacket; @@ -978,18 +977,18 @@ static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on) return 0; } -static int at91_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int at91_stop(struct usb_gadget_driver *driver); - +static int at91_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver); +static int at91_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver); static const struct usb_gadget_ops at91_udc_ops = { .get_frame = at91_get_frame, .wakeup = at91_wakeup, .set_selfpowered = at91_set_selfpowered, .vbus_session = at91_vbus_session, .pullup = at91_pullup, - .start = at91_start, - .stop = at91_stop, + .udc_start = at91_start, + .udc_stop = at91_stop, /* * VBUS-powered devices may also also want to support bigger @@ -1172,7 +1171,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) | USB_REQ_GET_STATUS: tmp = w_index & USB_ENDPOINT_NUMBER_MASK; ep = &udc->ep[tmp]; - if (tmp >= NUM_ENDPOINTS || (tmp && !ep->desc)) + if (tmp >= NUM_ENDPOINTS || (tmp && !ep->ep.desc)) goto stall; if (tmp) { @@ -1197,7 +1196,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) ep = &udc->ep[tmp]; if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS) goto stall; - if (!ep->desc || ep->is_iso) + if (!ep->ep.desc || ep->is_iso) goto stall; if ((w_index & USB_DIR_IN)) { if (!ep->is_in) @@ -1218,7 +1217,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) goto stall; if (tmp == 0) goto succeed; - if (!ep->desc || ep->is_iso) + if (!ep->ep.desc || ep->is_iso) goto stall; if ((w_index & USB_DIR_IN)) { if (!ep->is_in) @@ -1627,66 +1626,34 @@ static void at91_vbus_timer(unsigned long data) schedule_work(&udc->vbus_timer_work); } -static int at91_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) +static int at91_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { - struct at91_udc *udc = &controller; - int retval; - unsigned long flags; - - if (!driver - || driver->max_speed < USB_SPEED_FULL - || !bind - || !driver->setup) { - DBG("bad parameter.\n"); - return -EINVAL; - } - - if (udc->driver) { - DBG("UDC already has a gadget driver\n"); - return -EBUSY; - } + struct at91_udc *udc; + udc = container_of(gadget, struct at91_udc, gadget); udc->driver = driver; udc->gadget.dev.driver = &driver->driver; dev_set_drvdata(&udc->gadget.dev, &driver->driver); udc->enabled = 1; udc->selfpowered = 1; - retval = bind(&udc->gadget); - if (retval) { - DBG("bind() returned %d\n", retval); - udc->driver = NULL; - udc->gadget.dev.driver = NULL; - dev_set_drvdata(&udc->gadget.dev, NULL); - udc->enabled = 0; - udc->selfpowered = 0; - return retval; - } - - spin_lock_irqsave(&udc->lock, flags); - pullup(udc, 1); - spin_unlock_irqrestore(&udc->lock, flags); - DBG("bound to %s\n", driver->driver.name); return 0; } -static int at91_stop(struct usb_gadget_driver *driver) +static int at91_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { - struct at91_udc *udc = &controller; + struct at91_udc *udc; unsigned long flags; - if (!driver || driver != udc->driver || !driver->unbind) - return -EINVAL; - + udc = container_of(gadget, struct at91_udc, gadget); spin_lock_irqsave(&udc->lock, flags); udc->enabled = 0; at91_udp_write(udc, AT91_UDP_IDR, ~0); - pullup(udc, 0); spin_unlock_irqrestore(&udc->lock, flags); - driver->unbind(&udc->gadget); udc->gadget.dev.driver = NULL; dev_set_drvdata(&udc->gadget.dev, NULL); udc->driver = NULL; diff --git a/trunk/drivers/usb/gadget/at91_udc.h b/trunk/drivers/usb/gadget/at91_udc.h index 3c0315b86ace..e647d1c2ada4 100644 --- a/trunk/drivers/usb/gadget/at91_udc.h +++ b/trunk/drivers/usb/gadget/at91_udc.h @@ -105,9 +105,6 @@ struct at91_ep { unsigned is_in:1; unsigned is_iso:1; unsigned fifo_bank:1; - - const struct usb_endpoint_descriptor - *desc; }; /* diff --git a/trunk/drivers/usb/gadget/atmel_usba_udc.c b/trunk/drivers/usb/gadget/atmel_usba_udc.c index 9f98508966d1..e23bf7984aaf 100644 --- a/trunk/drivers/usb/gadget/atmel_usba_udc.c +++ b/trunk/drivers/usb/gadget/atmel_usba_udc.c @@ -599,13 +599,13 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) spin_lock_irqsave(&ep->udc->lock, flags); - if (ep->desc) { + if (ep->ep.desc) { spin_unlock_irqrestore(&ep->udc->lock, flags); DBG(DBG_ERR, "ep%d already enabled\n", ep->index); return -EBUSY; } - ep->desc = desc; + ep->ep.desc = desc; ep->ep.maxpacket = maxpacket; usba_ep_writel(ep, CFG, ept_cfg); @@ -647,7 +647,7 @@ static int usba_ep_disable(struct usb_ep *_ep) spin_lock_irqsave(&udc->lock, flags); - if (!ep->desc) { + if (!ep->ep.desc) { spin_unlock_irqrestore(&udc->lock, flags); /* REVISIT because this driver disables endpoints in * reset_all_endpoints() before calling disconnect(), @@ -658,7 +658,6 @@ static int usba_ep_disable(struct usb_ep *_ep) ep->ep.name); return -EINVAL; } - ep->desc = NULL; ep->ep.desc = NULL; list_splice_init(&ep->queue, &req_list); @@ -752,7 +751,7 @@ static int queue_dma(struct usba_udc *udc, struct usba_ep *ep, */ ret = -ESHUTDOWN; spin_lock_irqsave(&udc->lock, flags); - if (ep->desc) { + if (ep->ep.desc) { if (list_empty(&ep->queue)) submit_request(ep, req); @@ -776,7 +775,8 @@ usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) DBG(DBG_GADGET | DBG_QUEUE | DBG_REQ, "%s: queue req %p, len %u\n", ep->ep.name, req, _req->length); - if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN || !ep->desc) + if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN || + !ep->ep.desc) return -ESHUTDOWN; req->submitted = 0; @@ -792,7 +792,7 @@ usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) /* May have received a reset since last time we checked */ ret = -ESHUTDOWN; spin_lock_irqsave(&udc->lock, flags); - if (ep->desc) { + if (ep->ep.desc) { list_add_tail(&req->queue, &ep->queue); if ((!ep_is_control(ep) && ep->is_in) || @@ -905,7 +905,7 @@ static int usba_ep_set_halt(struct usb_ep *_ep, int value) DBG(DBG_GADGET, "endpoint %s: %s HALT\n", ep->ep.name, value ? "set" : "clear"); - if (!ep->desc) { + if (!ep->ep.desc) { DBG(DBG_ERR, "Attempted to halt uninitialized ep %s\n", ep->ep.name); return -ENODEV; @@ -1008,16 +1008,16 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered) return 0; } -static int atmel_usba_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int atmel_usba_stop(struct usb_gadget_driver *driver); - +static int atmel_usba_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver); +static int atmel_usba_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver); static const struct usb_gadget_ops usba_udc_ops = { .get_frame = usba_udc_get_frame, .wakeup = usba_udc_wakeup, .set_selfpowered = usba_udc_set_selfpowered, - .start = atmel_usba_start, - .stop = atmel_usba_stop, + .udc_start = atmel_usba_start, + .udc_stop = atmel_usba_stop, }; static struct usb_endpoint_descriptor usba_ep0_desc = { @@ -1071,7 +1071,7 @@ static void reset_all_endpoints(struct usba_udc *udc) * FIXME remove this code ... and retest thoroughly. */ list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { - if (ep->desc) { + if (ep->ep.desc) { spin_unlock(&udc->lock); usba_ep_disable(&ep->ep); spin_lock(&udc->lock); @@ -1089,9 +1089,9 @@ static struct usba_ep *get_ep_by_addr(struct usba_udc *udc, u16 wIndex) list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) { u8 bEndpointAddress; - if (!ep->desc) + if (!ep->ep.desc) continue; - bEndpointAddress = ep->desc->bEndpointAddress; + bEndpointAddress = ep->ep.desc->bEndpointAddress; if ((wIndex ^ bEndpointAddress) & USB_DIR_IN) continue; if ((bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) @@ -1727,7 +1727,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid) usb_speed_string(udc->gadget.speed)); ep0 = &usba_ep[0]; - ep0->desc = &usba_ep0_desc; + ep0->ep.desc = &usba_ep0_desc; ep0->state = WAIT_FOR_SETUP; usba_ep_writel(ep0, CFG, (USBA_BF(EPT_SIZE, EP0_EPT_SIZE) @@ -1795,21 +1795,13 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid) return IRQ_HANDLED; } -static int atmel_usba_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) +static int atmel_usba_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { - struct usba_udc *udc = &the_udc; + struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget); unsigned long flags; - int ret; - - if (!udc->pdev) - return -ENODEV; spin_lock_irqsave(&udc->lock, flags); - if (udc->driver) { - spin_unlock_irqrestore(&udc->lock, flags); - return -EBUSY; - } udc->devstatus = 1 << USB_DEVICE_SELF_POWERED; udc->driver = driver; @@ -1819,13 +1811,6 @@ static int atmel_usba_start(struct usb_gadget_driver *driver, clk_enable(udc->pclk); clk_enable(udc->hclk); - ret = bind(&udc->gadget); - if (ret) { - DBG(DBG_ERR, "Could not bind to driver %s: error %d\n", - driver->driver.name, ret); - goto err_driver_bind; - } - DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name); udc->vbus_prev = 0; @@ -1842,23 +1827,14 @@ static int atmel_usba_start(struct usb_gadget_driver *driver, spin_unlock_irqrestore(&udc->lock, flags); return 0; - -err_driver_bind: - udc->driver = NULL; - udc->gadget.dev.driver = NULL; - return ret; } -static int atmel_usba_stop(struct usb_gadget_driver *driver) +static int atmel_usba_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { - struct usba_udc *udc = &the_udc; + struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget); unsigned long flags; - if (!udc->pdev) - return -ENODEV; - if (driver != udc->driver || !driver->unbind) - return -EINVAL; - if (gpio_is_valid(udc->vbus_pin)) disable_irq(gpio_to_irq(udc->vbus_pin)); @@ -1871,10 +1847,6 @@ static int atmel_usba_stop(struct usb_gadget_driver *driver) toggle_bias(0); usba_writel(udc, CTRL, USBA_DISABLE_MASK); - if (udc->driver->disconnect) - udc->driver->disconnect(&udc->gadget); - - driver->unbind(&udc->gadget); udc->gadget.dev.driver = NULL; udc->driver = NULL; diff --git a/trunk/drivers/usb/gadget/atmel_usba_udc.h b/trunk/drivers/usb/gadget/atmel_usba_udc.h index 88a2e07a11a8..9791259cbda7 100644 --- a/trunk/drivers/usb/gadget/atmel_usba_udc.h +++ b/trunk/drivers/usb/gadget/atmel_usba_udc.h @@ -280,7 +280,6 @@ struct usba_ep { struct usba_udc *udc; struct list_head queue; - const struct usb_endpoint_descriptor *desc; u16 fifo_size; u8 nr_banks; diff --git a/trunk/drivers/usb/gadget/ci13xxx_msm.c b/trunk/drivers/usb/gadget/ci13xxx_msm.c deleted file mode 100644 index d07e44c05e9b..000000000000 --- a/trunk/drivers/usb/gadget/ci13xxx_msm.c +++ /dev/null @@ -1,126 +0,0 @@ -/* Copyright (c) 2010, Code Aurora Forum. 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. - */ - -#include -#include -#include -#include -#include - -#include "ci13xxx_udc.c" - -#define MSM_USB_BASE (udc->regs) - -static irqreturn_t msm_udc_irq(int irq, void *data) -{ - return udc_irq(); -} - -static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event) -{ - struct device *dev = udc->gadget.dev.parent; - int val; - - switch (event) { - case CI13XXX_CONTROLLER_RESET_EVENT: - dev_dbg(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n"); - writel(0, USB_AHBBURST); - writel(0, USB_AHBMODE); - break; - case CI13XXX_CONTROLLER_STOPPED_EVENT: - dev_dbg(dev, "CI13XXX_CONTROLLER_STOPPED_EVENT received\n"); - /* - * Put the transceiver in non-driving mode. Otherwise host - * may not detect soft-disconnection. - */ - val = usb_phy_io_read(udc->transceiver, ULPI_FUNC_CTRL); - val &= ~ULPI_FUNC_CTRL_OPMODE_MASK; - val |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING; - usb_phy_io_write(udc->transceiver, val, ULPI_FUNC_CTRL); - break; - default: - dev_dbg(dev, "unknown ci13xxx_udc event\n"); - break; - } -} - -static struct ci13xxx_udc_driver ci13xxx_msm_udc_driver = { - .name = "ci13xxx_msm", - .flags = CI13XXX_REGS_SHARED | - CI13XXX_REQUIRE_TRANSCEIVER | - CI13XXX_PULLUP_ON_VBUS | - CI13XXX_DISABLE_STREAMING, - - .notify_event = ci13xxx_msm_notify_event, -}; - -static int ci13xxx_msm_probe(struct platform_device *pdev) -{ - struct resource *res; - void __iomem *regs; - int irq; - int ret; - - dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n"); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "failed to get platform resource mem\n"); - return -ENXIO; - } - - regs = ioremap(res->start, resource_size(res)); - if (!regs) { - dev_err(&pdev->dev, "ioremap failed\n"); - return -ENOMEM; - } - - ret = udc_probe(&ci13xxx_msm_udc_driver, &pdev->dev, regs); - if (ret < 0) { - dev_err(&pdev->dev, "udc_probe failed\n"); - goto iounmap; - } - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "IRQ not found\n"); - ret = -ENXIO; - goto udc_remove; - } - - ret = request_irq(irq, msm_udc_irq, IRQF_SHARED, pdev->name, pdev); - if (ret < 0) { - dev_err(&pdev->dev, "request_irq failed\n"); - goto udc_remove; - } - - pm_runtime_no_callbacks(&pdev->dev); - pm_runtime_enable(&pdev->dev); - - return 0; - -udc_remove: - udc_remove(); -iounmap: - iounmap(regs); - - return ret; -} - -static struct platform_driver ci13xxx_msm_driver = { - .probe = ci13xxx_msm_probe, - .driver = { .name = "msm_hsusb", }, -}; -MODULE_ALIAS("platform:msm_hsusb"); - -static int __init ci13xxx_msm_init(void) -{ - return platform_driver_register(&ci13xxx_msm_driver); -} -module_init(ci13xxx_msm_init); - -MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/usb/gadget/ci13xxx_pci.c b/trunk/drivers/usb/gadget/ci13xxx_pci.c deleted file mode 100644 index 883ab5e832d1..000000000000 --- a/trunk/drivers/usb/gadget/ci13xxx_pci.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * ci13xxx_pci.c - MIPS USB IP core family device controller - * - * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. - * - * Author: David Lopo - * - * 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 "ci13xxx_udc.c" - -/* driver name */ -#define UDC_DRIVER_NAME "ci13xxx_pci" - -/****************************************************************************** - * PCI block - *****************************************************************************/ -/** - * ci13xxx_pci_irq: interrut handler - * @irq: irq number - * @pdev: USB Device Controller interrupt source - * - * This function returns IRQ_HANDLED if the IRQ has been handled - * This is an ISR don't trace, use attribute interface instead - */ -static irqreturn_t ci13xxx_pci_irq(int irq, void *pdev) -{ - if (irq == 0) { - dev_err(&((struct pci_dev *)pdev)->dev, "Invalid IRQ0 usage!"); - return IRQ_HANDLED; - } - return udc_irq(); -} - -static struct ci13xxx_udc_driver ci13xxx_pci_udc_driver = { - .name = UDC_DRIVER_NAME, -}; - -/** - * ci13xxx_pci_probe: PCI probe - * @pdev: USB device controller being probed - * @id: PCI hotplug ID connecting controller to UDC framework - * - * This function returns an error code - * Allocates basic PCI resources for this USB device controller, and then - * invokes the udc_probe() method to start the UDC associated with it - */ -static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - void __iomem *regs = NULL; - int retval = 0; - - if (id == NULL) - return -EINVAL; - - retval = pci_enable_device(pdev); - if (retval) - goto done; - - if (!pdev->irq) { - dev_err(&pdev->dev, "No IRQ, check BIOS/PCI setup!"); - retval = -ENODEV; - goto disable_device; - } - - retval = pci_request_regions(pdev, UDC_DRIVER_NAME); - if (retval) - goto disable_device; - - /* BAR 0 holds all the registers */ - regs = pci_iomap(pdev, 0, 0); - if (!regs) { - dev_err(&pdev->dev, "Error mapping memory!"); - retval = -EFAULT; - goto release_regions; - } - pci_set_drvdata(pdev, (__force void *)regs); - - pci_set_master(pdev); - pci_try_set_mwi(pdev); - - retval = udc_probe(&ci13xxx_pci_udc_driver, &pdev->dev, regs); - if (retval) - goto iounmap; - - /* our device does not have MSI capability */ - - retval = request_irq(pdev->irq, ci13xxx_pci_irq, IRQF_SHARED, - UDC_DRIVER_NAME, pdev); - if (retval) - goto gadget_remove; - - return 0; - - gadget_remove: - udc_remove(); - iounmap: - pci_iounmap(pdev, regs); - release_regions: - pci_release_regions(pdev); - disable_device: - pci_disable_device(pdev); - done: - return retval; -} - -/** - * ci13xxx_pci_remove: PCI remove - * @pdev: USB Device Controller being removed - * - * Reverses the effect of ci13xxx_pci_probe(), - * first invoking the udc_remove() and then releases - * all PCI resources allocated for this USB device controller - */ -static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev) -{ - free_irq(pdev->irq, pdev); - udc_remove(); - pci_iounmap(pdev, (__force void __iomem *)pci_get_drvdata(pdev)); - pci_release_regions(pdev); - pci_disable_device(pdev); -} - -/** - * PCI device table - * PCI device structure - * - * Check "pci.h" for details - */ -static DEFINE_PCI_DEVICE_TABLE(ci13xxx_pci_id_table) = { - { PCI_DEVICE(0x153F, 0x1004) }, - { PCI_DEVICE(0x153F, 0x1006) }, - { 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ } -}; -MODULE_DEVICE_TABLE(pci, ci13xxx_pci_id_table); - -static struct pci_driver ci13xxx_pci_driver = { - .name = UDC_DRIVER_NAME, - .id_table = ci13xxx_pci_id_table, - .probe = ci13xxx_pci_probe, - .remove = __devexit_p(ci13xxx_pci_remove), -}; - -/** - * ci13xxx_pci_init: module init - * - * Driver load - */ -static int __init ci13xxx_pci_init(void) -{ - return pci_register_driver(&ci13xxx_pci_driver); -} -module_init(ci13xxx_pci_init); - -/** - * ci13xxx_pci_exit: module exit - * - * Driver unload - */ -static void __exit ci13xxx_pci_exit(void) -{ - pci_unregister_driver(&ci13xxx_pci_driver); -} -module_exit(ci13xxx_pci_exit); - -MODULE_AUTHOR("MIPS - David Lopo "); -MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller"); -MODULE_LICENSE("GPL"); -MODULE_VERSION("June 2008"); diff --git a/trunk/drivers/usb/gadget/ci13xxx_udc.c b/trunk/drivers/usb/gadget/ci13xxx_udc.c deleted file mode 100644 index 243ef1adf969..000000000000 --- a/trunk/drivers/usb/gadget/ci13xxx_udc.c +++ /dev/null @@ -1,2996 +0,0 @@ -/* - * ci13xxx_udc.c - MIPS USB IP core family device controller - * - * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. - * - * Author: David Lopo - * - * 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. - */ - -/* - * Description: MIPS USB IP core family device controller - * Currently it only supports IP part number CI13412 - * - * This driver is composed of several blocks: - * - HW: hardware interface - * - DBG: debug facilities (optional) - * - UTIL: utilities - * - ISR: interrupts handling - * - ENDPT: endpoint operations (Gadget API) - * - GADGET: gadget operations (Gadget API) - * - BUS: bus glue code, bus abstraction layer - * - * Compile Options - * - CONFIG_USB_GADGET_DEBUG_FILES: enable debug facilities - * - STALL_IN: non-empty bulk-in pipes cannot be halted - * if defined mass storage compliance succeeds but with warnings - * => case 4: Hi > Dn - * => case 5: Hi > Di - * => case 8: Hi <> Do - * if undefined usbtest 13 fails - * - TRACE: enable function tracing (depends on DEBUG) - * - * Main Features - * - Chapter 9 & Mass Storage Compliance with Gadget File Storage - * - Chapter 9 Compliance with Gadget Zero (STALL_IN undefined) - * - Normal & LPM support - * - * USBTEST Report - * - OK: 0-12, 13 (STALL_IN defined) & 14 - * - Not Supported: 15 & 16 (ISO) - * - * TODO List - * - OTG - * - Isochronous & Interrupt Traffic - * - Handle requests which spawns into several TDs - * - GET_STATUS(device) - always reports 0 - * - Gadget API (majority of optional features) - * - Suspend & Remote Wakeup - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ci13xxx_udc.h" - - -/****************************************************************************** - * DEFINE - *****************************************************************************/ - -#define DMA_ADDR_INVALID (~(dma_addr_t)0) - -/* ctrl register bank access */ -static DEFINE_SPINLOCK(udc_lock); - -/* control endpoint description */ -static const struct usb_endpoint_descriptor -ctrl_endpt_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, - .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX), -}; - -static const struct usb_endpoint_descriptor -ctrl_endpt_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, - .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX), -}; - -/* UDC descriptor */ -static struct ci13xxx *_udc; - -/* Interrupt statistics */ -#define ISR_MASK 0x1F -static struct { - u32 test; - u32 ui; - u32 uei; - u32 pci; - u32 uri; - u32 sli; - u32 none; - struct { - u32 cnt; - u32 buf[ISR_MASK+1]; - u32 idx; - } hndl; -} isr_statistics; - -/** - * ffs_nr: find first (least significant) bit set - * @x: the word to search - * - * This function returns bit number (instead of position) - */ -static int ffs_nr(u32 x) -{ - int n = ffs(x); - - return n ? n-1 : 32; -} - -/****************************************************************************** - * HW block - *****************************************************************************/ -/* register bank descriptor */ -static struct { - unsigned lpm; /* is LPM? */ - void __iomem *abs; /* bus map offset */ - void __iomem *cap; /* bus map offset + CAP offset + CAP data */ - size_t size; /* bank size */ -} hw_bank; - -/* MSM specific */ -#define ABS_AHBBURST (0x0090UL) -#define ABS_AHBMODE (0x0098UL) -/* UDC register map */ -#define ABS_CAPLENGTH (0x100UL) -#define ABS_HCCPARAMS (0x108UL) -#define ABS_DCCPARAMS (0x124UL) -#define ABS_TESTMODE (hw_bank.lpm ? 0x0FCUL : 0x138UL) -/* offset to CAPLENTGH (addr + data) */ -#define CAP_USBCMD (0x000UL) -#define CAP_USBSTS (0x004UL) -#define CAP_USBINTR (0x008UL) -#define CAP_DEVICEADDR (0x014UL) -#define CAP_ENDPTLISTADDR (0x018UL) -#define CAP_PORTSC (0x044UL) -#define CAP_DEVLC (0x084UL) -#define CAP_USBMODE (hw_bank.lpm ? 0x0C8UL : 0x068UL) -#define CAP_ENDPTSETUPSTAT (hw_bank.lpm ? 0x0D8UL : 0x06CUL) -#define CAP_ENDPTPRIME (hw_bank.lpm ? 0x0DCUL : 0x070UL) -#define CAP_ENDPTFLUSH (hw_bank.lpm ? 0x0E0UL : 0x074UL) -#define CAP_ENDPTSTAT (hw_bank.lpm ? 0x0E4UL : 0x078UL) -#define CAP_ENDPTCOMPLETE (hw_bank.lpm ? 0x0E8UL : 0x07CUL) -#define CAP_ENDPTCTRL (hw_bank.lpm ? 0x0ECUL : 0x080UL) -#define CAP_LAST (hw_bank.lpm ? 0x12CUL : 0x0C0UL) - -/* maximum number of enpoints: valid only after hw_device_reset() */ -static unsigned hw_ep_max; - -/** - * hw_ep_bit: calculates the bit number - * @num: endpoint number - * @dir: endpoint direction - * - * This function returns bit number - */ -static inline int hw_ep_bit(int num, int dir) -{ - return num + (dir ? 16 : 0); -} - -static int ep_to_bit(int n) -{ - int fill = 16 - hw_ep_max / 2; - - if (n >= hw_ep_max / 2) - n += fill; - - return n; -} - -/** - * hw_aread: reads from register bitfield - * @addr: address relative to bus map - * @mask: bitfield mask - * - * This function returns register bitfield data - */ -static u32 hw_aread(u32 addr, u32 mask) -{ - return ioread32(addr + hw_bank.abs) & mask; -} - -/** - * hw_awrite: writes to register bitfield - * @addr: address relative to bus map - * @mask: bitfield mask - * @data: new data - */ -static void hw_awrite(u32 addr, u32 mask, u32 data) -{ - iowrite32(hw_aread(addr, ~mask) | (data & mask), - addr + hw_bank.abs); -} - -/** - * hw_cread: reads from register bitfield - * @addr: address relative to CAP offset plus content - * @mask: bitfield mask - * - * This function returns register bitfield data - */ -static u32 hw_cread(u32 addr, u32 mask) -{ - return ioread32(addr + hw_bank.cap) & mask; -} - -/** - * hw_cwrite: writes to register bitfield - * @addr: address relative to CAP offset plus content - * @mask: bitfield mask - * @data: new data - */ -static void hw_cwrite(u32 addr, u32 mask, u32 data) -{ - iowrite32(hw_cread(addr, ~mask) | (data & mask), - addr + hw_bank.cap); -} - -/** - * hw_ctest_and_clear: tests & clears register bitfield - * @addr: address relative to CAP offset plus content - * @mask: bitfield mask - * - * This function returns register bitfield data - */ -static u32 hw_ctest_and_clear(u32 addr, u32 mask) -{ - u32 reg = hw_cread(addr, mask); - - iowrite32(reg, addr + hw_bank.cap); - return reg; -} - -/** - * hw_ctest_and_write: tests & writes register bitfield - * @addr: address relative to CAP offset plus content - * @mask: bitfield mask - * @data: new data - * - * This function returns register bitfield data - */ -static u32 hw_ctest_and_write(u32 addr, u32 mask, u32 data) -{ - u32 reg = hw_cread(addr, ~0); - - iowrite32((reg & ~mask) | (data & mask), addr + hw_bank.cap); - return (reg & mask) >> ffs_nr(mask); -} - -static int hw_device_init(void __iomem *base) -{ - u32 reg; - - /* bank is a module variable */ - hw_bank.abs = base; - - hw_bank.cap = hw_bank.abs; - hw_bank.cap += ABS_CAPLENGTH; - hw_bank.cap += ioread8(hw_bank.cap); - - reg = hw_aread(ABS_HCCPARAMS, HCCPARAMS_LEN) >> ffs_nr(HCCPARAMS_LEN); - hw_bank.lpm = reg; - hw_bank.size = hw_bank.cap - hw_bank.abs; - hw_bank.size += CAP_LAST; - hw_bank.size /= sizeof(u32); - - reg = hw_aread(ABS_DCCPARAMS, DCCPARAMS_DEN) >> ffs_nr(DCCPARAMS_DEN); - hw_ep_max = reg * 2; /* cache hw ENDPT_MAX */ - - if (hw_ep_max == 0 || hw_ep_max > ENDPT_MAX) - return -ENODEV; - - /* setup lock mode ? */ - - /* ENDPTSETUPSTAT is '0' by default */ - - /* HCSPARAMS.bf.ppc SHOULD BE zero for device */ - - return 0; -} -/** - * hw_device_reset: resets chip (execute without interruption) - * @base: register base address - * - * This function returns an error code - */ -static int hw_device_reset(struct ci13xxx *udc) -{ - /* should flush & stop before reset */ - hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0); - hw_cwrite(CAP_USBCMD, USBCMD_RS, 0); - - hw_cwrite(CAP_USBCMD, USBCMD_RST, USBCMD_RST); - while (hw_cread(CAP_USBCMD, USBCMD_RST)) - udelay(10); /* not RTOS friendly */ - - - if (udc->udc_driver->notify_event) - udc->udc_driver->notify_event(udc, - CI13XXX_CONTROLLER_RESET_EVENT); - - if (udc->udc_driver->flags & CI13XXX_DISABLE_STREAMING) - hw_cwrite(CAP_USBMODE, USBMODE_SDIS, USBMODE_SDIS); - - /* USBMODE should be configured step by step */ - hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE); - hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_DEVICE); - hw_cwrite(CAP_USBMODE, USBMODE_SLOM, USBMODE_SLOM); /* HW >= 2.3 */ - - if (hw_cread(CAP_USBMODE, USBMODE_CM) != USBMODE_CM_DEVICE) { - pr_err("cannot enter in device mode"); - pr_err("lpm = %i", hw_bank.lpm); - return -ENODEV; - } - - return 0; -} - -/** - * hw_device_state: enables/disables interrupts & starts/stops device (execute - * without interruption) - * @dma: 0 => disable, !0 => enable and set dma engine - * - * This function returns an error code - */ -static int hw_device_state(u32 dma) -{ - if (dma) { - hw_cwrite(CAP_ENDPTLISTADDR, ~0, dma); - /* interrupt, error, port change, reset, sleep/suspend */ - hw_cwrite(CAP_USBINTR, ~0, - USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI); - hw_cwrite(CAP_USBCMD, USBCMD_RS, USBCMD_RS); - } else { - hw_cwrite(CAP_USBCMD, USBCMD_RS, 0); - hw_cwrite(CAP_USBINTR, ~0, 0); - } - return 0; -} - -/** - * hw_ep_flush: flush endpoint fifo (execute without interruption) - * @num: endpoint number - * @dir: endpoint direction - * - * This function returns an error code - */ -static int hw_ep_flush(int num, int dir) -{ - int n = hw_ep_bit(num, dir); - - do { - /* flush any pending transfer */ - hw_cwrite(CAP_ENDPTFLUSH, BIT(n), BIT(n)); - while (hw_cread(CAP_ENDPTFLUSH, BIT(n))) - cpu_relax(); - } while (hw_cread(CAP_ENDPTSTAT, BIT(n))); - - return 0; -} - -/** - * hw_ep_disable: disables endpoint (execute without interruption) - * @num: endpoint number - * @dir: endpoint direction - * - * This function returns an error code - */ -static int hw_ep_disable(int num, int dir) -{ - hw_ep_flush(num, dir); - hw_cwrite(CAP_ENDPTCTRL + num * sizeof(u32), - dir ? ENDPTCTRL_TXE : ENDPTCTRL_RXE, 0); - return 0; -} - -/** - * hw_ep_enable: enables endpoint (execute without interruption) - * @num: endpoint number - * @dir: endpoint direction - * @type: endpoint type - * - * This function returns an error code - */ -static int hw_ep_enable(int num, int dir, int type) -{ - u32 mask, data; - - if (dir) { - mask = ENDPTCTRL_TXT; /* type */ - data = type << ffs_nr(mask); - - mask |= ENDPTCTRL_TXS; /* unstall */ - mask |= ENDPTCTRL_TXR; /* reset data toggle */ - data |= ENDPTCTRL_TXR; - mask |= ENDPTCTRL_TXE; /* enable */ - data |= ENDPTCTRL_TXE; - } else { - mask = ENDPTCTRL_RXT; /* type */ - data = type << ffs_nr(mask); - - mask |= ENDPTCTRL_RXS; /* unstall */ - mask |= ENDPTCTRL_RXR; /* reset data toggle */ - data |= ENDPTCTRL_RXR; - mask |= ENDPTCTRL_RXE; /* enable */ - data |= ENDPTCTRL_RXE; - } - hw_cwrite(CAP_ENDPTCTRL + num * sizeof(u32), mask, data); - return 0; -} - -/** - * hw_ep_get_halt: return endpoint halt status - * @num: endpoint number - * @dir: endpoint direction - * - * This function returns 1 if endpoint halted - */ -static int hw_ep_get_halt(int num, int dir) -{ - u32 mask = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS; - - return hw_cread(CAP_ENDPTCTRL + num * sizeof(u32), mask) ? 1 : 0; -} - -/** - * hw_test_and_clear_setup_status: test & clear setup status (execute without - * interruption) - * @n: endpoint number - * - * This function returns setup status - */ -static int hw_test_and_clear_setup_status(int n) -{ - n = ep_to_bit(n); - return hw_ctest_and_clear(CAP_ENDPTSETUPSTAT, BIT(n)); -} - -/** - * hw_ep_prime: primes endpoint (execute without interruption) - * @num: endpoint number - * @dir: endpoint direction - * @is_ctrl: true if control endpoint - * - * This function returns an error code - */ -static int hw_ep_prime(int num, int dir, int is_ctrl) -{ - int n = hw_ep_bit(num, dir); - - if (is_ctrl && dir == RX && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num))) - return -EAGAIN; - - hw_cwrite(CAP_ENDPTPRIME, BIT(n), BIT(n)); - - while (hw_cread(CAP_ENDPTPRIME, BIT(n))) - cpu_relax(); - if (is_ctrl && dir == RX && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num))) - return -EAGAIN; - - /* status shoult be tested according with manual but it doesn't work */ - return 0; -} - -/** - * hw_ep_set_halt: configures ep halt & resets data toggle after clear (execute - * without interruption) - * @num: endpoint number - * @dir: endpoint direction - * @value: true => stall, false => unstall - * - * This function returns an error code - */ -static int hw_ep_set_halt(int num, int dir, int value) -{ - if (value != 0 && value != 1) - return -EINVAL; - - do { - u32 addr = CAP_ENDPTCTRL + num * sizeof(u32); - u32 mask_xs = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS; - u32 mask_xr = dir ? ENDPTCTRL_TXR : ENDPTCTRL_RXR; - - /* data toggle - reserved for EP0 but it's in ESS */ - hw_cwrite(addr, mask_xs|mask_xr, value ? mask_xs : mask_xr); - - } while (value != hw_ep_get_halt(num, dir)); - - return 0; -} - -/** - * hw_intr_clear: disables interrupt & clears interrupt status (execute without - * interruption) - * @n: interrupt bit - * - * This function returns an error code - */ -static int hw_intr_clear(int n) -{ - if (n >= REG_BITS) - return -EINVAL; - - hw_cwrite(CAP_USBINTR, BIT(n), 0); - hw_cwrite(CAP_USBSTS, BIT(n), BIT(n)); - return 0; -} - -/** - * hw_intr_force: enables interrupt & forces interrupt status (execute without - * interruption) - * @n: interrupt bit - * - * This function returns an error code - */ -static int hw_intr_force(int n) -{ - if (n >= REG_BITS) - return -EINVAL; - - hw_awrite(ABS_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE); - hw_cwrite(CAP_USBINTR, BIT(n), BIT(n)); - hw_cwrite(CAP_USBSTS, BIT(n), BIT(n)); - hw_awrite(ABS_TESTMODE, TESTMODE_FORCE, 0); - return 0; -} - -/** - * hw_is_port_high_speed: test if port is high speed - * - * This function returns true if high speed port - */ -static int hw_port_is_high_speed(void) -{ - return hw_bank.lpm ? hw_cread(CAP_DEVLC, DEVLC_PSPD) : - hw_cread(CAP_PORTSC, PORTSC_HSP); -} - -/** - * hw_port_test_get: reads port test mode value - * - * This function returns port test mode value - */ -static u8 hw_port_test_get(void) -{ - return hw_cread(CAP_PORTSC, PORTSC_PTC) >> ffs_nr(PORTSC_PTC); -} - -/** - * hw_port_test_set: writes port test mode (execute without interruption) - * @mode: new value - * - * This function returns an error code - */ -static int hw_port_test_set(u8 mode) -{ - const u8 TEST_MODE_MAX = 7; - - if (mode > TEST_MODE_MAX) - return -EINVAL; - - hw_cwrite(CAP_PORTSC, PORTSC_PTC, mode << ffs_nr(PORTSC_PTC)); - return 0; -} - -/** - * hw_read_intr_enable: returns interrupt enable register - * - * This function returns register data - */ -static u32 hw_read_intr_enable(void) -{ - return hw_cread(CAP_USBINTR, ~0); -} - -/** - * hw_read_intr_status: returns interrupt status register - * - * This function returns register data - */ -static u32 hw_read_intr_status(void) -{ - return hw_cread(CAP_USBSTS, ~0); -} - -/** - * hw_register_read: reads all device registers (execute without interruption) - * @buf: destination buffer - * @size: buffer size - * - * This function returns number of registers read - */ -static size_t hw_register_read(u32 *buf, size_t size) -{ - unsigned i; - - if (size > hw_bank.size) - size = hw_bank.size; - - for (i = 0; i < size; i++) - buf[i] = hw_aread(i * sizeof(u32), ~0); - - return size; -} - -/** - * hw_register_write: writes to register - * @addr: register address - * @data: register value - * - * This function returns an error code - */ -static int hw_register_write(u16 addr, u32 data) -{ - /* align */ - addr /= sizeof(u32); - - if (addr >= hw_bank.size) - return -EINVAL; - - /* align */ - addr *= sizeof(u32); - - hw_awrite(addr, ~0, data); - return 0; -} - -/** - * hw_test_and_clear_complete: test & clear complete status (execute without - * interruption) - * @n: endpoint number - * - * This function returns complete status - */ -static int hw_test_and_clear_complete(int n) -{ - n = ep_to_bit(n); - return hw_ctest_and_clear(CAP_ENDPTCOMPLETE, BIT(n)); -} - -/** - * hw_test_and_clear_intr_active: test & clear active interrupts (execute - * without interruption) - * - * This function returns active interrutps - */ -static u32 hw_test_and_clear_intr_active(void) -{ - u32 reg = hw_read_intr_status() & hw_read_intr_enable(); - - hw_cwrite(CAP_USBSTS, ~0, reg); - return reg; -} - -/** - * hw_test_and_clear_setup_guard: test & clear setup guard (execute without - * interruption) - * - * This function returns guard value - */ -static int hw_test_and_clear_setup_guard(void) -{ - return hw_ctest_and_write(CAP_USBCMD, USBCMD_SUTW, 0); -} - -/** - * hw_test_and_set_setup_guard: test & set setup guard (execute without - * interruption) - * - * This function returns guard value - */ -static int hw_test_and_set_setup_guard(void) -{ - return hw_ctest_and_write(CAP_USBCMD, USBCMD_SUTW, USBCMD_SUTW); -} - -/** - * hw_usb_set_address: configures USB address (execute without interruption) - * @value: new USB address - * - * This function returns an error code - */ -static int hw_usb_set_address(u8 value) -{ - /* advance */ - hw_cwrite(CAP_DEVICEADDR, DEVICEADDR_USBADR | DEVICEADDR_USBADRA, - value << ffs_nr(DEVICEADDR_USBADR) | DEVICEADDR_USBADRA); - return 0; -} - -/** - * hw_usb_reset: restart device after a bus reset (execute without - * interruption) - * - * This function returns an error code - */ -static int hw_usb_reset(void) -{ - hw_usb_set_address(0); - - /* ESS flushes only at end?!? */ - hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0); /* flush all EPs */ - - /* clear setup token semaphores */ - hw_cwrite(CAP_ENDPTSETUPSTAT, 0, 0); /* writes its content */ - - /* clear complete status */ - hw_cwrite(CAP_ENDPTCOMPLETE, 0, 0); /* writes its content */ - - /* wait until all bits cleared */ - while (hw_cread(CAP_ENDPTPRIME, ~0)) - udelay(10); /* not RTOS friendly */ - - /* reset all endpoints ? */ - - /* reset internal status and wait for further instructions - no need to verify the port reset status (ESS does it) */ - - return 0; -} - -/****************************************************************************** - * DBG block - *****************************************************************************/ -/** - * show_device: prints information about device capabilities and status - * - * Check "device.h" for details - */ -static ssize_t show_device(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - struct usb_gadget *gadget = &udc->gadget; - int n = 0; - - dbg_trace("[%s] %p\n", __func__, buf); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - return 0; - } - - n += scnprintf(buf + n, PAGE_SIZE - n, "speed = %d\n", - gadget->speed); - n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed = %d\n", - gadget->max_speed); - /* TODO: Scheduled for removal in 3.8. */ - n += scnprintf(buf + n, PAGE_SIZE - n, "is_dualspeed = %d\n", - gadget_is_dualspeed(gadget)); - n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg = %d\n", - gadget->is_otg); - n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral = %d\n", - gadget->is_a_peripheral); - n += scnprintf(buf + n, PAGE_SIZE - n, "b_hnp_enable = %d\n", - gadget->b_hnp_enable); - n += scnprintf(buf + n, PAGE_SIZE - n, "a_hnp_support = %d\n", - gadget->a_hnp_support); - n += scnprintf(buf + n, PAGE_SIZE - n, "a_alt_hnp_support = %d\n", - gadget->a_alt_hnp_support); - n += scnprintf(buf + n, PAGE_SIZE - n, "name = %s\n", - (gadget->name ? gadget->name : "")); - - return n; -} -static DEVICE_ATTR(device, S_IRUSR, show_device, NULL); - -/** - * show_driver: prints information about attached gadget (if any) - * - * Check "device.h" for details - */ -static ssize_t show_driver(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - struct usb_gadget_driver *driver = udc->driver; - int n = 0; - - dbg_trace("[%s] %p\n", __func__, buf); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - return 0; - } - - if (driver == NULL) - return scnprintf(buf, PAGE_SIZE, - "There is no gadget attached!\n"); - - n += scnprintf(buf + n, PAGE_SIZE - n, "function = %s\n", - (driver->function ? driver->function : "")); - n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n", - driver->max_speed); - - return n; -} -static DEVICE_ATTR(driver, S_IRUSR, show_driver, NULL); - -/* Maximum event message length */ -#define DBG_DATA_MSG 64UL - -/* Maximum event messages */ -#define DBG_DATA_MAX 128UL - -/* Event buffer descriptor */ -static struct { - char (buf[DBG_DATA_MAX])[DBG_DATA_MSG]; /* buffer */ - unsigned idx; /* index */ - unsigned tty; /* print to console? */ - rwlock_t lck; /* lock */ -} dbg_data = { - .idx = 0, - .tty = 0, - .lck = __RW_LOCK_UNLOCKED(lck) -}; - -/** - * dbg_dec: decrements debug event index - * @idx: buffer index - */ -static void dbg_dec(unsigned *idx) -{ - *idx = (*idx - 1) & (DBG_DATA_MAX-1); -} - -/** - * dbg_inc: increments debug event index - * @idx: buffer index - */ -static void dbg_inc(unsigned *idx) -{ - *idx = (*idx + 1) & (DBG_DATA_MAX-1); -} - -/** - * dbg_print: prints the common part of the event - * @addr: endpoint address - * @name: event name - * @status: status - * @extra: extra information - */ -static void dbg_print(u8 addr, const char *name, int status, const char *extra) -{ - struct timeval tval; - unsigned int stamp; - unsigned long flags; - - write_lock_irqsave(&dbg_data.lck, flags); - - do_gettimeofday(&tval); - stamp = tval.tv_sec & 0xFFFF; /* 2^32 = 4294967296. Limit to 4096s */ - stamp = stamp * 1000000 + tval.tv_usec; - - scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG, - "%04X\t? %02X %-7.7s %4i ?\t%s\n", - stamp, addr, name, status, extra); - - dbg_inc(&dbg_data.idx); - - write_unlock_irqrestore(&dbg_data.lck, flags); - - if (dbg_data.tty != 0) - pr_notice("%04X\t? %02X %-7.7s %4i ?\t%s\n", - stamp, addr, name, status, extra); -} - -/** - * dbg_done: prints a DONE event - * @addr: endpoint address - * @td: transfer descriptor - * @status: status - */ -static void dbg_done(u8 addr, const u32 token, int status) -{ - char msg[DBG_DATA_MSG]; - - scnprintf(msg, sizeof(msg), "%d %02X", - (int)(token & TD_TOTAL_BYTES) >> ffs_nr(TD_TOTAL_BYTES), - (int)(token & TD_STATUS) >> ffs_nr(TD_STATUS)); - dbg_print(addr, "DONE", status, msg); -} - -/** - * dbg_event: prints a generic event - * @addr: endpoint address - * @name: event name - * @status: status - */ -static void dbg_event(u8 addr, const char *name, int status) -{ - if (name != NULL) - dbg_print(addr, name, status, ""); -} - -/* - * dbg_queue: prints a QUEUE event - * @addr: endpoint address - * @req: USB request - * @status: status - */ -static void dbg_queue(u8 addr, const struct usb_request *req, int status) -{ - char msg[DBG_DATA_MSG]; - - if (req != NULL) { - scnprintf(msg, sizeof(msg), - "%d %d", !req->no_interrupt, req->length); - dbg_print(addr, "QUEUE", status, msg); - } -} - -/** - * dbg_setup: prints a SETUP event - * @addr: endpoint address - * @req: setup request - */ -static void dbg_setup(u8 addr, const struct usb_ctrlrequest *req) -{ - char msg[DBG_DATA_MSG]; - - if (req != NULL) { - scnprintf(msg, sizeof(msg), - "%02X %02X %04X %04X %d", req->bRequestType, - req->bRequest, le16_to_cpu(req->wValue), - le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength)); - dbg_print(addr, "SETUP", 0, msg); - } -} - -/** - * show_events: displays the event buffer - * - * Check "device.h" for details - */ -static ssize_t show_events(struct device *dev, struct device_attribute *attr, - char *buf) -{ - unsigned long flags; - unsigned i, j, n = 0; - - dbg_trace("[%s] %p\n", __func__, buf); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - return 0; - } - - read_lock_irqsave(&dbg_data.lck, flags); - - i = dbg_data.idx; - for (dbg_dec(&i); i != dbg_data.idx; dbg_dec(&i)) { - n += strlen(dbg_data.buf[i]); - if (n >= PAGE_SIZE) { - n -= strlen(dbg_data.buf[i]); - break; - } - } - for (j = 0, dbg_inc(&i); j < n; dbg_inc(&i)) - j += scnprintf(buf + j, PAGE_SIZE - j, - "%s", dbg_data.buf[i]); - - read_unlock_irqrestore(&dbg_data.lck, flags); - - return n; -} - -/** - * store_events: configure if events are going to be also printed to console - * - * Check "device.h" for details - */ -static ssize_t store_events(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - unsigned tty; - - dbg_trace("[%s] %p, %d\n", __func__, buf, count); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - goto done; - } - - if (sscanf(buf, "%u", &tty) != 1 || tty > 1) { - dev_err(dev, "<1|0>: enable|disable console log\n"); - goto done; - } - - dbg_data.tty = tty; - dev_info(dev, "tty = %u", dbg_data.tty); - - done: - return count; -} -static DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events); - -/** - * show_inters: interrupt status, enable status and historic - * - * Check "device.h" for details - */ -static ssize_t show_inters(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long flags; - u32 intr; - unsigned i, j, n = 0; - - dbg_trace("[%s] %p\n", __func__, buf); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - return 0; - } - - spin_lock_irqsave(udc->lock, flags); - - n += scnprintf(buf + n, PAGE_SIZE - n, - "status = %08x\n", hw_read_intr_status()); - n += scnprintf(buf + n, PAGE_SIZE - n, - "enable = %08x\n", hw_read_intr_enable()); - - n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n", - isr_statistics.test); - n += scnprintf(buf + n, PAGE_SIZE - n, "? ui = %d\n", - isr_statistics.ui); - n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n", - isr_statistics.uei); - n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n", - isr_statistics.pci); - n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n", - isr_statistics.uri); - n += scnprintf(buf + n, PAGE_SIZE - n, "? sli = %d\n", - isr_statistics.sli); - n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n", - isr_statistics.none); - n += scnprintf(buf + n, PAGE_SIZE - n, "*hndl = %d\n", - isr_statistics.hndl.cnt); - - for (i = isr_statistics.hndl.idx, j = 0; j <= ISR_MASK; j++, i++) { - i &= ISR_MASK; - intr = isr_statistics.hndl.buf[i]; - - if (USBi_UI & intr) - n += scnprintf(buf + n, PAGE_SIZE - n, "ui "); - intr &= ~USBi_UI; - if (USBi_UEI & intr) - n += scnprintf(buf + n, PAGE_SIZE - n, "uei "); - intr &= ~USBi_UEI; - if (USBi_PCI & intr) - n += scnprintf(buf + n, PAGE_SIZE - n, "pci "); - intr &= ~USBi_PCI; - if (USBi_URI & intr) - n += scnprintf(buf + n, PAGE_SIZE - n, "uri "); - intr &= ~USBi_URI; - if (USBi_SLI & intr) - n += scnprintf(buf + n, PAGE_SIZE - n, "sli "); - intr &= ~USBi_SLI; - if (intr) - n += scnprintf(buf + n, PAGE_SIZE - n, "??? "); - if (isr_statistics.hndl.buf[i]) - n += scnprintf(buf + n, PAGE_SIZE - n, "\n"); - } - - spin_unlock_irqrestore(udc->lock, flags); - - return n; -} - -/** - * store_inters: enable & force or disable an individual interrutps - * (to be used for test purposes only) - * - * Check "device.h" for details - */ -static ssize_t store_inters(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long flags; - unsigned en, bit; - - dbg_trace("[%s] %p, %d\n", __func__, buf, count); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - goto done; - } - - if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) { - dev_err(dev, "<1|0> : enable|disable interrupt"); - goto done; - } - - spin_lock_irqsave(udc->lock, flags); - if (en) { - if (hw_intr_force(bit)) - dev_err(dev, "invalid bit number\n"); - else - isr_statistics.test++; - } else { - if (hw_intr_clear(bit)) - dev_err(dev, "invalid bit number\n"); - } - spin_unlock_irqrestore(udc->lock, flags); - - done: - return count; -} -static DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters); - -/** - * show_port_test: reads port test mode - * - * Check "device.h" for details - */ -static ssize_t show_port_test(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long flags; - unsigned mode; - - dbg_trace("[%s] %p\n", __func__, buf); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - return 0; - } - - spin_lock_irqsave(udc->lock, flags); - mode = hw_port_test_get(); - spin_unlock_irqrestore(udc->lock, flags); - - return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode); -} - -/** - * store_port_test: writes port test mode - * - * Check "device.h" for details - */ -static ssize_t store_port_test(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long flags; - unsigned mode; - - dbg_trace("[%s] %p, %d\n", __func__, buf, count); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - goto done; - } - - if (sscanf(buf, "%u", &mode) != 1) { - dev_err(dev, ": set port test mode"); - goto done; - } - - spin_lock_irqsave(udc->lock, flags); - if (hw_port_test_set(mode)) - dev_err(dev, "invalid mode\n"); - spin_unlock_irqrestore(udc->lock, flags); - - done: - return count; -} -static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR, - show_port_test, store_port_test); - -/** - * show_qheads: DMA contents of all queue heads - * - * Check "device.h" for details - */ -static ssize_t show_qheads(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long flags; - unsigned i, j, n = 0; - - dbg_trace("[%s] %p\n", __func__, buf); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - return 0; - } - - spin_lock_irqsave(udc->lock, flags); - for (i = 0; i < hw_ep_max/2; i++) { - struct ci13xxx_ep *mEpRx = &udc->ci13xxx_ep[i]; - struct ci13xxx_ep *mEpTx = &udc->ci13xxx_ep[i + hw_ep_max/2]; - n += scnprintf(buf + n, PAGE_SIZE - n, - "EP=%02i: RX=%08X TX=%08X\n", - i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma); - for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) { - n += scnprintf(buf + n, PAGE_SIZE - n, - " %04X: %08X %08X\n", j, - *((u32 *)mEpRx->qh.ptr + j), - *((u32 *)mEpTx->qh.ptr + j)); - } - } - spin_unlock_irqrestore(udc->lock, flags); - - return n; -} -static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL); - -/** - * show_registers: dumps all registers - * - * Check "device.h" for details - */ -#define DUMP_ENTRIES 512 -static ssize_t show_registers(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long flags; - u32 *dump; - unsigned i, k, n = 0; - - dbg_trace("[%s] %p\n", __func__, buf); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - return 0; - } - - dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL); - if (!dump) { - dev_err(dev, "%s: out of memory\n", __func__); - return 0; - } - - spin_lock_irqsave(udc->lock, flags); - k = hw_register_read(dump, DUMP_ENTRIES); - spin_unlock_irqrestore(udc->lock, flags); - - for (i = 0; i < k; i++) { - n += scnprintf(buf + n, PAGE_SIZE - n, - "reg[0x%04X] = 0x%08X\n", - i * (unsigned)sizeof(u32), dump[i]); - } - kfree(dump); - - return n; -} - -/** - * store_registers: writes value to register address - * - * Check "device.h" for details - */ -static ssize_t store_registers(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long addr, data, flags; - - dbg_trace("[%s] %p, %d\n", __func__, buf, count); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - goto done; - } - - if (sscanf(buf, "%li %li", &addr, &data) != 2) { - dev_err(dev, " : write data to register address"); - goto done; - } - - spin_lock_irqsave(udc->lock, flags); - if (hw_register_write(addr, data)) - dev_err(dev, "invalid address range\n"); - spin_unlock_irqrestore(udc->lock, flags); - - done: - return count; -} -static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR, - show_registers, store_registers); - -/** - * show_requests: DMA contents of all requests currently queued (all endpts) - * - * Check "device.h" for details - */ -static ssize_t show_requests(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long flags; - struct list_head *ptr = NULL; - struct ci13xxx_req *req = NULL; - unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32); - - dbg_trace("[%s] %p\n", __func__, buf); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - return 0; - } - - spin_lock_irqsave(udc->lock, flags); - for (i = 0; i < hw_ep_max; i++) - list_for_each(ptr, &udc->ci13xxx_ep[i].qh.queue) - { - req = list_entry(ptr, struct ci13xxx_req, queue); - - n += scnprintf(buf + n, PAGE_SIZE - n, - "EP=%02i: TD=%08X %s\n", - i % hw_ep_max/2, (u32)req->dma, - ((i < hw_ep_max/2) ? "RX" : "TX")); - - for (j = 0; j < qSize; j++) - n += scnprintf(buf + n, PAGE_SIZE - n, - " %04X: %08X\n", j, - *((u32 *)req->ptr + j)); - } - spin_unlock_irqrestore(udc->lock, flags); - - return n; -} -static DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL); - -/** - * dbg_create_files: initializes the attribute interface - * @dev: device - * - * This function returns an error code - */ -__maybe_unused static int dbg_create_files(struct device *dev) -{ - int retval = 0; - - if (dev == NULL) - return -EINVAL; - retval = device_create_file(dev, &dev_attr_device); - if (retval) - goto done; - retval = device_create_file(dev, &dev_attr_driver); - if (retval) - goto rm_device; - retval = device_create_file(dev, &dev_attr_events); - if (retval) - goto rm_driver; - retval = device_create_file(dev, &dev_attr_inters); - if (retval) - goto rm_events; - retval = device_create_file(dev, &dev_attr_port_test); - if (retval) - goto rm_inters; - retval = device_create_file(dev, &dev_attr_qheads); - if (retval) - goto rm_port_test; - retval = device_create_file(dev, &dev_attr_registers); - if (retval) - goto rm_qheads; - retval = device_create_file(dev, &dev_attr_requests); - if (retval) - goto rm_registers; - return 0; - - rm_registers: - device_remove_file(dev, &dev_attr_registers); - rm_qheads: - device_remove_file(dev, &dev_attr_qheads); - rm_port_test: - device_remove_file(dev, &dev_attr_port_test); - rm_inters: - device_remove_file(dev, &dev_attr_inters); - rm_events: - device_remove_file(dev, &dev_attr_events); - rm_driver: - device_remove_file(dev, &dev_attr_driver); - rm_device: - device_remove_file(dev, &dev_attr_device); - done: - return retval; -} - -/** - * dbg_remove_files: destroys the attribute interface - * @dev: device - * - * This function returns an error code - */ -__maybe_unused static int dbg_remove_files(struct device *dev) -{ - if (dev == NULL) - return -EINVAL; - device_remove_file(dev, &dev_attr_requests); - device_remove_file(dev, &dev_attr_registers); - device_remove_file(dev, &dev_attr_qheads); - device_remove_file(dev, &dev_attr_port_test); - device_remove_file(dev, &dev_attr_inters); - device_remove_file(dev, &dev_attr_events); - device_remove_file(dev, &dev_attr_driver); - device_remove_file(dev, &dev_attr_device); - return 0; -} - -/****************************************************************************** - * UTIL block - *****************************************************************************/ -/** - * _usb_addr: calculates endpoint address from direction & number - * @ep: endpoint - */ -static inline u8 _usb_addr(struct ci13xxx_ep *ep) -{ - return ((ep->dir == TX) ? USB_ENDPOINT_DIR_MASK : 0) | ep->num; -} - -/** - * _hardware_queue: configures a request at hardware level - * @gadget: gadget - * @mEp: endpoint - * - * This function returns an error code - */ -static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) -{ - unsigned i; - int ret = 0; - unsigned length = mReq->req.length; - - trace("%p, %p", mEp, mReq); - - /* don't queue twice */ - if (mReq->req.status == -EALREADY) - return -EALREADY; - - mReq->req.status = -EALREADY; - if (length && mReq->req.dma == DMA_ADDR_INVALID) { - mReq->req.dma = \ - dma_map_single(mEp->device, mReq->req.buf, - length, mEp->dir ? DMA_TO_DEVICE : - DMA_FROM_DEVICE); - if (mReq->req.dma == 0) - return -ENOMEM; - - mReq->map = 1; - } - - if (mReq->req.zero && length && (length % mEp->ep.maxpacket == 0)) { - mReq->zptr = dma_pool_alloc(mEp->td_pool, GFP_ATOMIC, - &mReq->zdma); - if (mReq->zptr == NULL) { - if (mReq->map) { - dma_unmap_single(mEp->device, mReq->req.dma, - length, mEp->dir ? DMA_TO_DEVICE : - DMA_FROM_DEVICE); - mReq->req.dma = DMA_ADDR_INVALID; - mReq->map = 0; - } - return -ENOMEM; - } - memset(mReq->zptr, 0, sizeof(*mReq->zptr)); - mReq->zptr->next = TD_TERMINATE; - mReq->zptr->token = TD_STATUS_ACTIVE; - if (!mReq->req.no_interrupt) - mReq->zptr->token |= TD_IOC; - } - /* - * TD configuration - * TODO - handle requests which spawns into several TDs - */ - memset(mReq->ptr, 0, sizeof(*mReq->ptr)); - mReq->ptr->token = length << ffs_nr(TD_TOTAL_BYTES); - mReq->ptr->token &= TD_TOTAL_BYTES; - mReq->ptr->token |= TD_STATUS_ACTIVE; - if (mReq->zptr) { - mReq->ptr->next = mReq->zdma; - } else { - mReq->ptr->next = TD_TERMINATE; - if (!mReq->req.no_interrupt) - mReq->ptr->token |= TD_IOC; - } - mReq->ptr->page[0] = mReq->req.dma; - for (i = 1; i < 5; i++) - mReq->ptr->page[i] = - (mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK; - - if (!list_empty(&mEp->qh.queue)) { - struct ci13xxx_req *mReqPrev; - int n = hw_ep_bit(mEp->num, mEp->dir); - int tmp_stat; - - mReqPrev = list_entry(mEp->qh.queue.prev, - struct ci13xxx_req, queue); - if (mReqPrev->zptr) - mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK; - else - mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK; - wmb(); - if (hw_cread(CAP_ENDPTPRIME, BIT(n))) - goto done; - do { - hw_cwrite(CAP_USBCMD, USBCMD_ATDTW, USBCMD_ATDTW); - tmp_stat = hw_cread(CAP_ENDPTSTAT, BIT(n)); - } while (!hw_cread(CAP_USBCMD, USBCMD_ATDTW)); - hw_cwrite(CAP_USBCMD, USBCMD_ATDTW, 0); - if (tmp_stat) - goto done; - } - - /* QH configuration */ - mEp->qh.ptr->td.next = mReq->dma; /* TERMINATE = 0 */ - mEp->qh.ptr->td.token &= ~TD_STATUS; /* clear status */ - mEp->qh.ptr->cap |= QH_ZLT; - - wmb(); /* synchronize before ep prime */ - - ret = hw_ep_prime(mEp->num, mEp->dir, - mEp->type == USB_ENDPOINT_XFER_CONTROL); -done: - return ret; -} - -/** - * _hardware_dequeue: handles a request at hardware level - * @gadget: gadget - * @mEp: endpoint - * - * This function returns an error code - */ -static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) -{ - trace("%p, %p", mEp, mReq); - - if (mReq->req.status != -EALREADY) - return -EINVAL; - - if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0) - return -EBUSY; - - if (mReq->zptr) { - if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0) - return -EBUSY; - dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma); - mReq->zptr = NULL; - } - - mReq->req.status = 0; - - if (mReq->map) { - dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length, - mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - mReq->req.dma = DMA_ADDR_INVALID; - mReq->map = 0; - } - - mReq->req.status = mReq->ptr->token & TD_STATUS; - if ((TD_STATUS_HALTED & mReq->req.status) != 0) - mReq->req.status = -1; - else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0) - mReq->req.status = -1; - else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0) - mReq->req.status = -1; - - mReq->req.actual = mReq->ptr->token & TD_TOTAL_BYTES; - mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES); - mReq->req.actual = mReq->req.length - mReq->req.actual; - mReq->req.actual = mReq->req.status ? 0 : mReq->req.actual; - - return mReq->req.actual; -} - -/** - * _ep_nuke: dequeues all endpoint requests - * @mEp: endpoint - * - * This function returns an error code - * Caller must hold lock - */ -static int _ep_nuke(struct ci13xxx_ep *mEp) -__releases(mEp->lock) -__acquires(mEp->lock) -{ - trace("%p", mEp); - - if (mEp == NULL) - return -EINVAL; - - hw_ep_flush(mEp->num, mEp->dir); - - while (!list_empty(&mEp->qh.queue)) { - - /* pop oldest request */ - struct ci13xxx_req *mReq = \ - list_entry(mEp->qh.queue.next, - struct ci13xxx_req, queue); - list_del_init(&mReq->queue); - mReq->req.status = -ESHUTDOWN; - - if (mReq->req.complete != NULL) { - spin_unlock(mEp->lock); - mReq->req.complete(&mEp->ep, &mReq->req); - spin_lock(mEp->lock); - } - } - return 0; -} - -/** - * _gadget_stop_activity: stops all USB activity, flushes & disables all endpts - * @gadget: gadget - * - * This function returns an error code - */ -static int _gadget_stop_activity(struct usb_gadget *gadget) -{ - struct usb_ep *ep; - struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget); - unsigned long flags; - - trace("%p", gadget); - - if (gadget == NULL) - return -EINVAL; - - spin_lock_irqsave(udc->lock, flags); - udc->gadget.speed = USB_SPEED_UNKNOWN; - udc->remote_wakeup = 0; - udc->suspended = 0; - spin_unlock_irqrestore(udc->lock, flags); - - /* flush all endpoints */ - gadget_for_each_ep(ep, gadget) { - usb_ep_fifo_flush(ep); - } - usb_ep_fifo_flush(&udc->ep0out.ep); - usb_ep_fifo_flush(&udc->ep0in.ep); - - udc->driver->disconnect(gadget); - - /* make sure to disable all endpoints */ - gadget_for_each_ep(ep, gadget) { - usb_ep_disable(ep); - } - - if (udc->status != NULL) { - usb_ep_free_request(&udc->ep0in.ep, udc->status); - udc->status = NULL; - } - - return 0; -} - -/****************************************************************************** - * ISR block - *****************************************************************************/ -/** - * isr_reset_handler: USB reset interrupt handler - * @udc: UDC device - * - * This function resets USB engine after a bus reset occurred - */ -static void isr_reset_handler(struct ci13xxx *udc) -__releases(udc->lock) -__acquires(udc->lock) -{ - int retval; - - trace("%p", udc); - - if (udc == NULL) { - err("EINVAL"); - return; - } - - dbg_event(0xFF, "BUS RST", 0); - - spin_unlock(udc->lock); - retval = _gadget_stop_activity(&udc->gadget); - if (retval) - goto done; - - retval = hw_usb_reset(); - if (retval) - goto done; - - udc->status = usb_ep_alloc_request(&udc->ep0in.ep, GFP_ATOMIC); - if (udc->status == NULL) - retval = -ENOMEM; - - spin_lock(udc->lock); - - done: - if (retval) - err("error: %i", retval); -} - -/** - * isr_get_status_complete: get_status request complete function - * @ep: endpoint - * @req: request handled - * - * Caller must release lock - */ -static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req) -{ - trace("%p, %p", ep, req); - - if (ep == NULL || req == NULL) { - err("EINVAL"); - return; - } - - kfree(req->buf); - usb_ep_free_request(ep, req); -} - -/** - * isr_get_status_response: get_status request response - * @udc: udc struct - * @setup: setup request packet - * - * This function returns an error code - */ -static int isr_get_status_response(struct ci13xxx *udc, - struct usb_ctrlrequest *setup) -__releases(mEp->lock) -__acquires(mEp->lock) -{ - struct ci13xxx_ep *mEp = &udc->ep0in; - struct usb_request *req = NULL; - gfp_t gfp_flags = GFP_ATOMIC; - int dir, num, retval; - - trace("%p, %p", mEp, setup); - - if (mEp == NULL || setup == NULL) - return -EINVAL; - - spin_unlock(mEp->lock); - req = usb_ep_alloc_request(&mEp->ep, gfp_flags); - spin_lock(mEp->lock); - if (req == NULL) - return -ENOMEM; - - req->complete = isr_get_status_complete; - req->length = 2; - req->buf = kzalloc(req->length, gfp_flags); - if (req->buf == NULL) { - retval = -ENOMEM; - goto err_free_req; - } - - if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) { - /* Assume that device is bus powered for now. */ - *((u16 *)req->buf) = _udc->remote_wakeup << 1; - retval = 0; - } else if ((setup->bRequestType & USB_RECIP_MASK) \ - == USB_RECIP_ENDPOINT) { - dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ? - TX : RX; - num = le16_to_cpu(setup->wIndex) & USB_ENDPOINT_NUMBER_MASK; - *((u16 *)req->buf) = hw_ep_get_halt(num, dir); - } - /* else do nothing; reserved for future use */ - - spin_unlock(mEp->lock); - retval = usb_ep_queue(&mEp->ep, req, gfp_flags); - spin_lock(mEp->lock); - if (retval) - goto err_free_buf; - - return 0; - - err_free_buf: - kfree(req->buf); - err_free_req: - spin_unlock(mEp->lock); - usb_ep_free_request(&mEp->ep, req); - spin_lock(mEp->lock); - return retval; -} - -/** - * isr_setup_status_complete: setup_status request complete function - * @ep: endpoint - * @req: request handled - * - * Caller must release lock. Put the port in test mode if test mode - * feature is selected. - */ -static void -isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct ci13xxx *udc = req->context; - unsigned long flags; - - trace("%p, %p", ep, req); - - spin_lock_irqsave(udc->lock, flags); - if (udc->test_mode) - hw_port_test_set(udc->test_mode); - spin_unlock_irqrestore(udc->lock, flags); -} - -/** - * isr_setup_status_phase: queues the status phase of a setup transation - * @udc: udc struct - * - * This function returns an error code - */ -static int isr_setup_status_phase(struct ci13xxx *udc) -__releases(mEp->lock) -__acquires(mEp->lock) -{ - int retval; - struct ci13xxx_ep *mEp; - - trace("%p", udc); - - mEp = (udc->ep0_dir == TX) ? &udc->ep0out : &udc->ep0in; - udc->status->context = udc; - udc->status->complete = isr_setup_status_complete; - - spin_unlock(mEp->lock); - retval = usb_ep_queue(&mEp->ep, udc->status, GFP_ATOMIC); - spin_lock(mEp->lock); - - return retval; -} - -/** - * isr_tr_complete_low: transaction complete low level handler - * @mEp: endpoint - * - * This function returns an error code - * Caller must hold lock - */ -static int isr_tr_complete_low(struct ci13xxx_ep *mEp) -__releases(mEp->lock) -__acquires(mEp->lock) -{ - struct ci13xxx_req *mReq, *mReqTemp; - struct ci13xxx_ep *mEpTemp = mEp; - int uninitialized_var(retval); - - trace("%p", mEp); - - if (list_empty(&mEp->qh.queue)) - return -EINVAL; - - list_for_each_entry_safe(mReq, mReqTemp, &mEp->qh.queue, - queue) { - retval = _hardware_dequeue(mEp, mReq); - if (retval < 0) - break; - list_del_init(&mReq->queue); - dbg_done(_usb_addr(mEp), mReq->ptr->token, retval); - if (mReq->req.complete != NULL) { - spin_unlock(mEp->lock); - if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) && - mReq->req.length) - mEpTemp = &_udc->ep0in; - mReq->req.complete(&mEpTemp->ep, &mReq->req); - spin_lock(mEp->lock); - } - } - - if (retval == -EBUSY) - retval = 0; - if (retval < 0) - dbg_event(_usb_addr(mEp), "DONE", retval); - - return retval; -} - -/** - * isr_tr_complete_handler: transaction complete interrupt handler - * @udc: UDC descriptor - * - * This function handles traffic events - */ -static void isr_tr_complete_handler(struct ci13xxx *udc) -__releases(udc->lock) -__acquires(udc->lock) -{ - unsigned i; - u8 tmode = 0; - - trace("%p", udc); - - if (udc == NULL) { - err("EINVAL"); - return; - } - - for (i = 0; i < hw_ep_max; i++) { - struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i]; - int type, num, dir, err = -EINVAL; - struct usb_ctrlrequest req; - - if (mEp->desc == NULL) - continue; /* not configured */ - - if (hw_test_and_clear_complete(i)) { - err = isr_tr_complete_low(mEp); - if (mEp->type == USB_ENDPOINT_XFER_CONTROL) { - if (err > 0) /* needs status phase */ - err = isr_setup_status_phase(udc); - if (err < 0) { - dbg_event(_usb_addr(mEp), - "ERROR", err); - spin_unlock(udc->lock); - if (usb_ep_set_halt(&mEp->ep)) - err("error: ep_set_halt"); - spin_lock(udc->lock); - } - } - } - - if (mEp->type != USB_ENDPOINT_XFER_CONTROL || - !hw_test_and_clear_setup_status(i)) - continue; - - if (i != 0) { - warn("ctrl traffic received at endpoint"); - continue; - } - - /* - * Flush data and handshake transactions of previous - * setup packet. - */ - _ep_nuke(&udc->ep0out); - _ep_nuke(&udc->ep0in); - - /* read_setup_packet */ - do { - hw_test_and_set_setup_guard(); - memcpy(&req, &mEp->qh.ptr->setup, sizeof(req)); - } while (!hw_test_and_clear_setup_guard()); - - type = req.bRequestType; - - udc->ep0_dir = (type & USB_DIR_IN) ? TX : RX; - - dbg_setup(_usb_addr(mEp), &req); - - switch (req.bRequest) { - case USB_REQ_CLEAR_FEATURE: - if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) && - le16_to_cpu(req.wValue) == - USB_ENDPOINT_HALT) { - if (req.wLength != 0) - break; - num = le16_to_cpu(req.wIndex); - dir = num & USB_ENDPOINT_DIR_MASK; - num &= USB_ENDPOINT_NUMBER_MASK; - if (dir) /* TX */ - num += hw_ep_max/2; - if (!udc->ci13xxx_ep[num].wedge) { - spin_unlock(udc->lock); - err = usb_ep_clear_halt( - &udc->ci13xxx_ep[num].ep); - spin_lock(udc->lock); - if (err) - break; - } - err = isr_setup_status_phase(udc); - } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE) && - le16_to_cpu(req.wValue) == - USB_DEVICE_REMOTE_WAKEUP) { - if (req.wLength != 0) - break; - udc->remote_wakeup = 0; - err = isr_setup_status_phase(udc); - } else { - goto delegate; - } - break; - case USB_REQ_GET_STATUS: - if (type != (USB_DIR_IN|USB_RECIP_DEVICE) && - type != (USB_DIR_IN|USB_RECIP_ENDPOINT) && - type != (USB_DIR_IN|USB_RECIP_INTERFACE)) - goto delegate; - if (le16_to_cpu(req.wLength) != 2 || - le16_to_cpu(req.wValue) != 0) - break; - err = isr_get_status_response(udc, &req); - break; - case USB_REQ_SET_ADDRESS: - if (type != (USB_DIR_OUT|USB_RECIP_DEVICE)) - goto delegate; - if (le16_to_cpu(req.wLength) != 0 || - le16_to_cpu(req.wIndex) != 0) - break; - err = hw_usb_set_address((u8)le16_to_cpu(req.wValue)); - if (err) - break; - err = isr_setup_status_phase(udc); - break; - case USB_REQ_SET_FEATURE: - if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) && - le16_to_cpu(req.wValue) == - USB_ENDPOINT_HALT) { - if (req.wLength != 0) - break; - num = le16_to_cpu(req.wIndex); - dir = num & USB_ENDPOINT_DIR_MASK; - num &= USB_ENDPOINT_NUMBER_MASK; - if (dir) /* TX */ - num += hw_ep_max/2; - - spin_unlock(udc->lock); - err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep); - spin_lock(udc->lock); - if (!err) - isr_setup_status_phase(udc); - } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE)) { - if (req.wLength != 0) - break; - switch (le16_to_cpu(req.wValue)) { - case USB_DEVICE_REMOTE_WAKEUP: - udc->remote_wakeup = 1; - err = isr_setup_status_phase(udc); - break; - case USB_DEVICE_TEST_MODE: - tmode = le16_to_cpu(req.wIndex) >> 8; - switch (tmode) { - case TEST_J: - case TEST_K: - case TEST_SE0_NAK: - case TEST_PACKET: - case TEST_FORCE_EN: - udc->test_mode = tmode; - err = isr_setup_status_phase( - udc); - break; - default: - break; - } - default: - goto delegate; - } - } else { - goto delegate; - } - break; - default: -delegate: - if (req.wLength == 0) /* no data phase */ - udc->ep0_dir = TX; - - spin_unlock(udc->lock); - err = udc->driver->setup(&udc->gadget, &req); - spin_lock(udc->lock); - break; - } - - if (err < 0) { - dbg_event(_usb_addr(mEp), "ERROR", err); - - spin_unlock(udc->lock); - if (usb_ep_set_halt(&mEp->ep)) - err("error: ep_set_halt"); - spin_lock(udc->lock); - } - } -} - -/****************************************************************************** - * ENDPT block - *****************************************************************************/ -/** - * ep_enable: configure endpoint, making it usable - * - * Check usb_ep_enable() at "usb_gadget.h" for details - */ -static int ep_enable(struct usb_ep *ep, - const struct usb_endpoint_descriptor *desc) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - int retval = 0; - unsigned long flags; - - trace("%p, %p", ep, desc); - - if (ep == NULL || desc == NULL) - return -EINVAL; - - spin_lock_irqsave(mEp->lock, flags); - - /* only internal SW should enable ctrl endpts */ - - mEp->desc = desc; - - if (!list_empty(&mEp->qh.queue)) - warn("enabling a non-empty endpoint!"); - - mEp->dir = usb_endpoint_dir_in(desc) ? TX : RX; - mEp->num = usb_endpoint_num(desc); - mEp->type = usb_endpoint_type(desc); - - mEp->ep.maxpacket = usb_endpoint_maxp(desc); - - dbg_event(_usb_addr(mEp), "ENABLE", 0); - - mEp->qh.ptr->cap = 0; - - if (mEp->type == USB_ENDPOINT_XFER_CONTROL) - mEp->qh.ptr->cap |= QH_IOS; - else if (mEp->type == USB_ENDPOINT_XFER_ISOC) - mEp->qh.ptr->cap &= ~QH_MULT; - else - mEp->qh.ptr->cap &= ~QH_ZLT; - - mEp->qh.ptr->cap |= - (mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT; - mEp->qh.ptr->td.next |= TD_TERMINATE; /* needed? */ - - /* - * Enable endpoints in the HW other than ep0 as ep0 - * is always enabled - */ - if (mEp->num) - retval |= hw_ep_enable(mEp->num, mEp->dir, mEp->type); - - spin_unlock_irqrestore(mEp->lock, flags); - return retval; -} - -/** - * ep_disable: endpoint is no longer usable - * - * Check usb_ep_disable() at "usb_gadget.h" for details - */ -static int ep_disable(struct usb_ep *ep) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - int direction, retval = 0; - unsigned long flags; - - trace("%p", ep); - - if (ep == NULL) - return -EINVAL; - else if (mEp->desc == NULL) - return -EBUSY; - - spin_lock_irqsave(mEp->lock, flags); - - /* only internal SW should disable ctrl endpts */ - - direction = mEp->dir; - do { - dbg_event(_usb_addr(mEp), "DISABLE", 0); - - retval |= _ep_nuke(mEp); - retval |= hw_ep_disable(mEp->num, mEp->dir); - - if (mEp->type == USB_ENDPOINT_XFER_CONTROL) - mEp->dir = (mEp->dir == TX) ? RX : TX; - - } while (mEp->dir != direction); - - mEp->desc = NULL; - mEp->ep.desc = NULL; - - spin_unlock_irqrestore(mEp->lock, flags); - return retval; -} - -/** - * ep_alloc_request: allocate a request object to use with this endpoint - * - * Check usb_ep_alloc_request() at "usb_gadget.h" for details - */ -static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - struct ci13xxx_req *mReq = NULL; - - trace("%p, %i", ep, gfp_flags); - - if (ep == NULL) { - err("EINVAL"); - return NULL; - } - - mReq = kzalloc(sizeof(struct ci13xxx_req), gfp_flags); - if (mReq != NULL) { - INIT_LIST_HEAD(&mReq->queue); - mReq->req.dma = DMA_ADDR_INVALID; - - mReq->ptr = dma_pool_alloc(mEp->td_pool, gfp_flags, - &mReq->dma); - if (mReq->ptr == NULL) { - kfree(mReq); - mReq = NULL; - } - } - - dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL); - - return (mReq == NULL) ? NULL : &mReq->req; -} - -/** - * ep_free_request: frees a request object - * - * Check usb_ep_free_request() at "usb_gadget.h" for details - */ -static void ep_free_request(struct usb_ep *ep, struct usb_request *req) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); - unsigned long flags; - - trace("%p, %p", ep, req); - - if (ep == NULL || req == NULL) { - err("EINVAL"); - return; - } else if (!list_empty(&mReq->queue)) { - err("EBUSY"); - return; - } - - spin_lock_irqsave(mEp->lock, flags); - - if (mReq->ptr) - dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma); - kfree(mReq); - - dbg_event(_usb_addr(mEp), "FREE", 0); - - spin_unlock_irqrestore(mEp->lock, flags); -} - -/** - * ep_queue: queues (submits) an I/O request to an endpoint - * - * Check usb_ep_queue()* at usb_gadget.h" for details - */ -static int ep_queue(struct usb_ep *ep, struct usb_request *req, - gfp_t __maybe_unused gfp_flags) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); - int retval = 0; - unsigned long flags; - - trace("%p, %p, %X", ep, req, gfp_flags); - - if (ep == NULL || req == NULL || mEp->desc == NULL) - return -EINVAL; - - spin_lock_irqsave(mEp->lock, flags); - - if (mEp->type == USB_ENDPOINT_XFER_CONTROL) { - if (req->length) - mEp = (_udc->ep0_dir == RX) ? - &_udc->ep0out : &_udc->ep0in; - if (!list_empty(&mEp->qh.queue)) { - _ep_nuke(mEp); - retval = -EOVERFLOW; - warn("endpoint ctrl %X nuked", _usb_addr(mEp)); - } - } - - /* first nuke then test link, e.g. previous status has not sent */ - if (!list_empty(&mReq->queue)) { - retval = -EBUSY; - err("request already in queue"); - goto done; - } - - if (req->length > (4 * CI13XXX_PAGE_SIZE)) { - req->length = (4 * CI13XXX_PAGE_SIZE); - retval = -EMSGSIZE; - warn("request length truncated"); - } - - dbg_queue(_usb_addr(mEp), req, retval); - - /* push request */ - mReq->req.status = -EINPROGRESS; - mReq->req.actual = 0; - - retval = _hardware_enqueue(mEp, mReq); - - if (retval == -EALREADY) { - dbg_event(_usb_addr(mEp), "QUEUE", retval); - retval = 0; - } - if (!retval) - list_add_tail(&mReq->queue, &mEp->qh.queue); - - done: - spin_unlock_irqrestore(mEp->lock, flags); - return retval; -} - -/** - * ep_dequeue: dequeues (cancels, unlinks) an I/O request from an endpoint - * - * Check usb_ep_dequeue() at "usb_gadget.h" for details - */ -static int ep_dequeue(struct usb_ep *ep, struct usb_request *req) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); - unsigned long flags; - - trace("%p, %p", ep, req); - - if (ep == NULL || req == NULL || mReq->req.status != -EALREADY || - mEp->desc == NULL || list_empty(&mReq->queue) || - list_empty(&mEp->qh.queue)) - return -EINVAL; - - spin_lock_irqsave(mEp->lock, flags); - - dbg_event(_usb_addr(mEp), "DEQUEUE", 0); - - hw_ep_flush(mEp->num, mEp->dir); - - /* pop request */ - list_del_init(&mReq->queue); - if (mReq->map) { - dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length, - mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - mReq->req.dma = DMA_ADDR_INVALID; - mReq->map = 0; - } - req->status = -ECONNRESET; - - if (mReq->req.complete != NULL) { - spin_unlock(mEp->lock); - mReq->req.complete(&mEp->ep, &mReq->req); - spin_lock(mEp->lock); - } - - spin_unlock_irqrestore(mEp->lock, flags); - return 0; -} - -/** - * ep_set_halt: sets the endpoint halt feature - * - * Check usb_ep_set_halt() at "usb_gadget.h" for details - */ -static int ep_set_halt(struct usb_ep *ep, int value) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - int direction, retval = 0; - unsigned long flags; - - trace("%p, %i", ep, value); - - if (ep == NULL || mEp->desc == NULL) - return -EINVAL; - - spin_lock_irqsave(mEp->lock, flags); - -#ifndef STALL_IN - /* g_file_storage MS compliant but g_zero fails chapter 9 compliance */ - if (value && mEp->type == USB_ENDPOINT_XFER_BULK && mEp->dir == TX && - !list_empty(&mEp->qh.queue)) { - spin_unlock_irqrestore(mEp->lock, flags); - return -EAGAIN; - } -#endif - - direction = mEp->dir; - do { - dbg_event(_usb_addr(mEp), "HALT", value); - retval |= hw_ep_set_halt(mEp->num, mEp->dir, value); - - if (!value) - mEp->wedge = 0; - - if (mEp->type == USB_ENDPOINT_XFER_CONTROL) - mEp->dir = (mEp->dir == TX) ? RX : TX; - - } while (mEp->dir != direction); - - spin_unlock_irqrestore(mEp->lock, flags); - return retval; -} - -/** - * ep_set_wedge: sets the halt feature and ignores clear requests - * - * Check usb_ep_set_wedge() at "usb_gadget.h" for details - */ -static int ep_set_wedge(struct usb_ep *ep) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - unsigned long flags; - - trace("%p", ep); - - if (ep == NULL || mEp->desc == NULL) - return -EINVAL; - - spin_lock_irqsave(mEp->lock, flags); - - dbg_event(_usb_addr(mEp), "WEDGE", 0); - mEp->wedge = 1; - - spin_unlock_irqrestore(mEp->lock, flags); - - return usb_ep_set_halt(ep); -} - -/** - * ep_fifo_flush: flushes contents of a fifo - * - * Check usb_ep_fifo_flush() at "usb_gadget.h" for details - */ -static void ep_fifo_flush(struct usb_ep *ep) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - unsigned long flags; - - trace("%p", ep); - - if (ep == NULL) { - err("%02X: -EINVAL", _usb_addr(mEp)); - return; - } - - spin_lock_irqsave(mEp->lock, flags); - - dbg_event(_usb_addr(mEp), "FFLUSH", 0); - hw_ep_flush(mEp->num, mEp->dir); - - spin_unlock_irqrestore(mEp->lock, flags); -} - -/** - * Endpoint-specific part of the API to the USB controller hardware - * Check "usb_gadget.h" for details - */ -static const struct usb_ep_ops usb_ep_ops = { - .enable = ep_enable, - .disable = ep_disable, - .alloc_request = ep_alloc_request, - .free_request = ep_free_request, - .queue = ep_queue, - .dequeue = ep_dequeue, - .set_halt = ep_set_halt, - .set_wedge = ep_set_wedge, - .fifo_flush = ep_fifo_flush, -}; - -/****************************************************************************** - * GADGET block - *****************************************************************************/ -static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active) -{ - struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget); - unsigned long flags; - int gadget_ready = 0; - - if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS)) - return -EOPNOTSUPP; - - spin_lock_irqsave(udc->lock, flags); - udc->vbus_active = is_active; - if (udc->driver) - gadget_ready = 1; - spin_unlock_irqrestore(udc->lock, flags); - - if (gadget_ready) { - if (is_active) { - pm_runtime_get_sync(&_gadget->dev); - hw_device_reset(udc); - hw_device_state(udc->ep0out.qh.dma); - } else { - hw_device_state(0); - if (udc->udc_driver->notify_event) - udc->udc_driver->notify_event(udc, - CI13XXX_CONTROLLER_STOPPED_EVENT); - _gadget_stop_activity(&udc->gadget); - pm_runtime_put_sync(&_gadget->dev); - } - } - - return 0; -} - -static int ci13xxx_wakeup(struct usb_gadget *_gadget) -{ - struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget); - unsigned long flags; - int ret = 0; - - trace(); - - spin_lock_irqsave(udc->lock, flags); - if (!udc->remote_wakeup) { - ret = -EOPNOTSUPP; - trace("remote wakeup feature is not enabled\n"); - goto out; - } - if (!hw_cread(CAP_PORTSC, PORTSC_SUSP)) { - ret = -EINVAL; - trace("port is not suspended\n"); - goto out; - } - hw_cwrite(CAP_PORTSC, PORTSC_FPR, PORTSC_FPR); -out: - spin_unlock_irqrestore(udc->lock, flags); - return ret; -} - -static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA) -{ - struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget); - - if (udc->transceiver) - return usb_phy_set_power(udc->transceiver, mA); - return -ENOTSUPP; -} - -static int ci13xxx_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int ci13xxx_stop(struct usb_gadget_driver *driver); -/** - * Device operations part of the API to the USB controller hardware, - * which don't involve endpoints (or i/o) - * Check "usb_gadget.h" for details - */ -static const struct usb_gadget_ops usb_gadget_ops = { - .vbus_session = ci13xxx_vbus_session, - .wakeup = ci13xxx_wakeup, - .vbus_draw = ci13xxx_vbus_draw, - .start = ci13xxx_start, - .stop = ci13xxx_stop, -}; - -/** - * ci13xxx_start: register a gadget driver - * @driver: the driver being registered - * @bind: the driver's bind callback - * - * Check ci13xxx_start() at for details. - * Interrupts are enabled here. - */ -static int ci13xxx_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) -{ - struct ci13xxx *udc = _udc; - unsigned long flags; - int i, j; - int retval = -ENOMEM; - - trace("%p", driver); - - if (driver == NULL || - bind == NULL || - driver->setup == NULL || - driver->disconnect == NULL) - return -EINVAL; - else if (udc == NULL) - return -ENODEV; - else if (udc->driver != NULL) - return -EBUSY; - - /* alloc resources */ - udc->qh_pool = dma_pool_create("ci13xxx_qh", &udc->gadget.dev, - sizeof(struct ci13xxx_qh), - 64, CI13XXX_PAGE_SIZE); - if (udc->qh_pool == NULL) - return -ENOMEM; - - udc->td_pool = dma_pool_create("ci13xxx_td", &udc->gadget.dev, - sizeof(struct ci13xxx_td), - 64, CI13XXX_PAGE_SIZE); - if (udc->td_pool == NULL) { - dma_pool_destroy(udc->qh_pool); - udc->qh_pool = NULL; - return -ENOMEM; - } - - spin_lock_irqsave(udc->lock, flags); - - info("hw_ep_max = %d", hw_ep_max); - - udc->gadget.dev.driver = NULL; - - retval = 0; - for (i = 0; i < hw_ep_max/2; i++) { - for (j = RX; j <= TX; j++) { - int k = i + j * hw_ep_max/2; - struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[k]; - - scnprintf(mEp->name, sizeof(mEp->name), "ep%i%s", i, - (j == TX) ? "in" : "out"); - - mEp->lock = udc->lock; - mEp->device = &udc->gadget.dev; - mEp->td_pool = udc->td_pool; - - mEp->ep.name = mEp->name; - mEp->ep.ops = &usb_ep_ops; - mEp->ep.maxpacket = CTRL_PAYLOAD_MAX; - - INIT_LIST_HEAD(&mEp->qh.queue); - spin_unlock_irqrestore(udc->lock, flags); - mEp->qh.ptr = dma_pool_alloc(udc->qh_pool, GFP_KERNEL, - &mEp->qh.dma); - spin_lock_irqsave(udc->lock, flags); - if (mEp->qh.ptr == NULL) - retval = -ENOMEM; - else - memset(mEp->qh.ptr, 0, sizeof(*mEp->qh.ptr)); - - /* skip ep0 out and in endpoints */ - if (i == 0) - continue; - - list_add_tail(&mEp->ep.ep_list, &udc->gadget.ep_list); - } - } - if (retval) - goto done; - spin_unlock_irqrestore(udc->lock, flags); - udc->ep0out.ep.desc = &ctrl_endpt_out_desc; - retval = usb_ep_enable(&udc->ep0out.ep); - if (retval) - return retval; - - udc->ep0in.ep.desc = &ctrl_endpt_in_desc; - retval = usb_ep_enable(&udc->ep0in.ep); - if (retval) - return retval; - spin_lock_irqsave(udc->lock, flags); - - udc->gadget.ep0 = &udc->ep0in.ep; - /* bind gadget */ - driver->driver.bus = NULL; - udc->gadget.dev.driver = &driver->driver; - - spin_unlock_irqrestore(udc->lock, flags); - retval = bind(&udc->gadget); /* MAY SLEEP */ - spin_lock_irqsave(udc->lock, flags); - - if (retval) { - udc->gadget.dev.driver = NULL; - goto done; - } - - udc->driver = driver; - pm_runtime_get_sync(&udc->gadget.dev); - if (udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) { - if (udc->vbus_active) { - if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) - hw_device_reset(udc); - } else { - pm_runtime_put_sync(&udc->gadget.dev); - goto done; - } - } - - retval = hw_device_state(udc->ep0out.qh.dma); - if (retval) - pm_runtime_put_sync(&udc->gadget.dev); - - done: - spin_unlock_irqrestore(udc->lock, flags); - return retval; -} - -/** - * ci13xxx_stop: unregister a gadget driver - * - * Check usb_gadget_unregister_driver() at "usb_gadget.h" for details - */ -static int ci13xxx_stop(struct usb_gadget_driver *driver) -{ - struct ci13xxx *udc = _udc; - unsigned long i, flags; - - trace("%p", driver); - - if (driver == NULL || - driver->unbind == NULL || - driver->setup == NULL || - driver->disconnect == NULL || - driver != udc->driver) - return -EINVAL; - - spin_lock_irqsave(udc->lock, flags); - - if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) || - udc->vbus_active) { - hw_device_state(0); - if (udc->udc_driver->notify_event) - udc->udc_driver->notify_event(udc, - CI13XXX_CONTROLLER_STOPPED_EVENT); - spin_unlock_irqrestore(udc->lock, flags); - _gadget_stop_activity(&udc->gadget); - spin_lock_irqsave(udc->lock, flags); - pm_runtime_put(&udc->gadget.dev); - } - - /* unbind gadget */ - spin_unlock_irqrestore(udc->lock, flags); - driver->unbind(&udc->gadget); /* MAY SLEEP */ - spin_lock_irqsave(udc->lock, flags); - - udc->gadget.dev.driver = NULL; - - /* free resources */ - for (i = 0; i < hw_ep_max; i++) { - struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i]; - - if (!list_empty(&mEp->ep.ep_list)) - list_del_init(&mEp->ep.ep_list); - - if (mEp->qh.ptr != NULL) - dma_pool_free(udc->qh_pool, mEp->qh.ptr, mEp->qh.dma); - } - - udc->gadget.ep0 = NULL; - udc->driver = NULL; - - spin_unlock_irqrestore(udc->lock, flags); - - if (udc->td_pool != NULL) { - dma_pool_destroy(udc->td_pool); - udc->td_pool = NULL; - } - if (udc->qh_pool != NULL) { - dma_pool_destroy(udc->qh_pool); - udc->qh_pool = NULL; - } - - return 0; -} - -/****************************************************************************** - * BUS block - *****************************************************************************/ -/** - * udc_irq: global interrupt handler - * - * This function returns IRQ_HANDLED if the IRQ has been handled - * It locks access to registers - */ -static irqreturn_t udc_irq(void) -{ - struct ci13xxx *udc = _udc; - irqreturn_t retval; - u32 intr; - - trace(); - - if (udc == NULL) { - err("ENODEV"); - return IRQ_HANDLED; - } - - spin_lock(udc->lock); - - if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) { - if (hw_cread(CAP_USBMODE, USBMODE_CM) != - USBMODE_CM_DEVICE) { - spin_unlock(udc->lock); - return IRQ_NONE; - } - } - intr = hw_test_and_clear_intr_active(); - if (intr) { - isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intr; - isr_statistics.hndl.idx &= ISR_MASK; - isr_statistics.hndl.cnt++; - - /* order defines priority - do NOT change it */ - if (USBi_URI & intr) { - isr_statistics.uri++; - isr_reset_handler(udc); - } - if (USBi_PCI & intr) { - isr_statistics.pci++; - udc->gadget.speed = hw_port_is_high_speed() ? - USB_SPEED_HIGH : USB_SPEED_FULL; - if (udc->suspended && udc->driver->resume) { - spin_unlock(udc->lock); - udc->driver->resume(&udc->gadget); - spin_lock(udc->lock); - udc->suspended = 0; - } - } - if (USBi_UEI & intr) - isr_statistics.uei++; - if (USBi_UI & intr) { - isr_statistics.ui++; - isr_tr_complete_handler(udc); - } - if (USBi_SLI & intr) { - if (udc->gadget.speed != USB_SPEED_UNKNOWN && - udc->driver->suspend) { - udc->suspended = 1; - spin_unlock(udc->lock); - udc->driver->suspend(&udc->gadget); - spin_lock(udc->lock); - } - isr_statistics.sli++; - } - retval = IRQ_HANDLED; - } else { - isr_statistics.none++; - retval = IRQ_NONE; - } - spin_unlock(udc->lock); - - return retval; -} - -/** - * udc_release: driver release function - * @dev: device - * - * Currently does nothing - */ -static void udc_release(struct device *dev) -{ - trace("%p", dev); - - if (dev == NULL) - err("EINVAL"); -} - -/** - * udc_probe: parent probe must call this to initialize UDC - * @dev: parent device - * @regs: registers base address - * @name: driver name - * - * This function returns an error code - * No interrupts active, the IRQ has not been requested yet - * Kernel assumes 32-bit DMA operations by default, no need to dma_set_mask - */ -static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev, - void __iomem *regs) -{ - struct ci13xxx *udc; - int retval = 0; - - trace("%p, %p, %p", dev, regs, driver->name); - - if (dev == NULL || regs == NULL || driver == NULL || - driver->name == NULL) - return -EINVAL; - - udc = kzalloc(sizeof(struct ci13xxx), GFP_KERNEL); - if (udc == NULL) - return -ENOMEM; - - udc->lock = &udc_lock; - udc->regs = regs; - udc->udc_driver = driver; - - udc->gadget.ops = &usb_gadget_ops; - udc->gadget.speed = USB_SPEED_UNKNOWN; - udc->gadget.max_speed = USB_SPEED_HIGH; - udc->gadget.is_otg = 0; - udc->gadget.name = driver->name; - - INIT_LIST_HEAD(&udc->gadget.ep_list); - udc->gadget.ep0 = NULL; - - dev_set_name(&udc->gadget.dev, "gadget"); - udc->gadget.dev.dma_mask = dev->dma_mask; - udc->gadget.dev.coherent_dma_mask = dev->coherent_dma_mask; - udc->gadget.dev.parent = dev; - udc->gadget.dev.release = udc_release; - - retval = hw_device_init(regs); - if (retval < 0) - goto free_udc; - - udc->transceiver = usb_get_transceiver(); - - if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) { - if (udc->transceiver == NULL) { - retval = -ENODEV; - goto free_udc; - } - } - - if (!(udc->udc_driver->flags & CI13XXX_REGS_SHARED)) { - retval = hw_device_reset(udc); - if (retval) - goto put_transceiver; - } - - retval = device_register(&udc->gadget.dev); - if (retval) { - put_device(&udc->gadget.dev); - goto put_transceiver; - } - -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - retval = dbg_create_files(&udc->gadget.dev); -#endif - if (retval) - goto unreg_device; - - if (udc->transceiver) { - retval = otg_set_peripheral(udc->transceiver->otg, - &udc->gadget); - if (retval) - goto remove_dbg; - } - - retval = usb_add_gadget_udc(dev, &udc->gadget); - if (retval) - goto remove_trans; - - pm_runtime_no_callbacks(&udc->gadget.dev); - pm_runtime_enable(&udc->gadget.dev); - - _udc = udc; - return retval; - -remove_trans: - if (udc->transceiver) { - otg_set_peripheral(udc->transceiver->otg, &udc->gadget); - usb_put_transceiver(udc->transceiver); - } - - err("error = %i", retval); -remove_dbg: -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - dbg_remove_files(&udc->gadget.dev); -#endif -unreg_device: - device_unregister(&udc->gadget.dev); -put_transceiver: - if (udc->transceiver) - usb_put_transceiver(udc->transceiver); -free_udc: - kfree(udc); - _udc = NULL; - return retval; -} - -/** - * udc_remove: parent remove must call this to remove UDC - * - * No interrupts active, the IRQ has been released - */ -static void udc_remove(void) -{ - struct ci13xxx *udc = _udc; - - if (udc == NULL) { - err("EINVAL"); - return; - } - usb_del_gadget_udc(&udc->gadget); - - if (udc->transceiver) { - otg_set_peripheral(udc->transceiver->otg, &udc->gadget); - usb_put_transceiver(udc->transceiver); - } -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - dbg_remove_files(&udc->gadget.dev); -#endif - device_unregister(&udc->gadget.dev); - - kfree(udc); - _udc = NULL; -} diff --git a/trunk/drivers/usb/gadget/ci13xxx_udc.h b/trunk/drivers/usb/gadget/ci13xxx_udc.h deleted file mode 100644 index 0d31af56c989..000000000000 --- a/trunk/drivers/usb/gadget/ci13xxx_udc.h +++ /dev/null @@ -1,227 +0,0 @@ -/* - * ci13xxx_udc.h - structures, registers, and macros MIPS USB IP core - * - * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. - * - * Author: David Lopo - * - * 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. - * - * Description: MIPS USB IP core family device controller - * Structures, registers and logging macros - */ - -#ifndef _CI13XXX_h_ -#define _CI13XXX_h_ - -/****************************************************************************** - * DEFINE - *****************************************************************************/ -#define CI13XXX_PAGE_SIZE 4096ul /* page size for TD's */ -#define ENDPT_MAX (32) -#define CTRL_PAYLOAD_MAX (64) -#define RX (0) /* similar to USB_DIR_OUT but can be used as an index */ -#define TX (1) /* similar to USB_DIR_IN but can be used as an index */ - -/****************************************************************************** - * STRUCTURES - *****************************************************************************/ -/* DMA layout of transfer descriptors */ -struct ci13xxx_td { - /* 0 */ - u32 next; -#define TD_TERMINATE BIT(0) -#define TD_ADDR_MASK (0xFFFFFFEUL << 5) - /* 1 */ - u32 token; -#define TD_STATUS (0x00FFUL << 0) -#define TD_STATUS_TR_ERR BIT(3) -#define TD_STATUS_DT_ERR BIT(5) -#define TD_STATUS_HALTED BIT(6) -#define TD_STATUS_ACTIVE BIT(7) -#define TD_MULTO (0x0003UL << 10) -#define TD_IOC BIT(15) -#define TD_TOTAL_BYTES (0x7FFFUL << 16) - /* 2 */ - u32 page[5]; -#define TD_CURR_OFFSET (0x0FFFUL << 0) -#define TD_FRAME_NUM (0x07FFUL << 0) -#define TD_RESERVED_MASK (0x0FFFUL << 0) -} __attribute__ ((packed)); - -/* DMA layout of queue heads */ -struct ci13xxx_qh { - /* 0 */ - u32 cap; -#define QH_IOS BIT(15) -#define QH_MAX_PKT (0x07FFUL << 16) -#define QH_ZLT BIT(29) -#define QH_MULT (0x0003UL << 30) - /* 1 */ - u32 curr; - /* 2 - 8 */ - struct ci13xxx_td td; - /* 9 */ - u32 RESERVED; - struct usb_ctrlrequest setup; -} __attribute__ ((packed)); - -/* Extension of usb_request */ -struct ci13xxx_req { - struct usb_request req; - unsigned map; - struct list_head queue; - struct ci13xxx_td *ptr; - dma_addr_t dma; - struct ci13xxx_td *zptr; - dma_addr_t zdma; -}; - -/* Extension of usb_ep */ -struct ci13xxx_ep { - struct usb_ep ep; - const struct usb_endpoint_descriptor *desc; - u8 dir; - u8 num; - u8 type; - char name[16]; - struct { - struct list_head queue; - struct ci13xxx_qh *ptr; - dma_addr_t dma; - } qh; - int wedge; - - /* global resources */ - spinlock_t *lock; - struct device *device; - struct dma_pool *td_pool; -}; - -struct ci13xxx; -struct ci13xxx_udc_driver { - const char *name; - unsigned long flags; -#define CI13XXX_REGS_SHARED BIT(0) -#define CI13XXX_REQUIRE_TRANSCEIVER BIT(1) -#define CI13XXX_PULLUP_ON_VBUS BIT(2) -#define CI13XXX_DISABLE_STREAMING BIT(3) - -#define CI13XXX_CONTROLLER_RESET_EVENT 0 -#define CI13XXX_CONTROLLER_STOPPED_EVENT 1 - void (*notify_event) (struct ci13xxx *udc, unsigned event); -}; - -/* CI13XXX UDC descriptor & global resources */ -struct ci13xxx { - spinlock_t *lock; /* ctrl register bank access */ - void __iomem *regs; /* registers address space */ - - struct dma_pool *qh_pool; /* DMA pool for queue heads */ - struct dma_pool *td_pool; /* DMA pool for transfer descs */ - struct usb_request *status; /* ep0 status request */ - - struct usb_gadget gadget; /* USB slave device */ - struct ci13xxx_ep ci13xxx_ep[ENDPT_MAX]; /* extended endpts */ - u32 ep0_dir; /* ep0 direction */ -#define ep0out ci13xxx_ep[0] -#define ep0in ci13xxx_ep[hw_ep_max / 2] - u8 remote_wakeup; /* Is remote wakeup feature - enabled by the host? */ - u8 suspended; /* suspended by the host */ - u8 test_mode; /* the selected test mode */ - - struct usb_gadget_driver *driver; /* 3rd party gadget driver */ - struct ci13xxx_udc_driver *udc_driver; /* device controller driver */ - int vbus_active; /* is VBUS active */ - struct usb_phy *transceiver; /* Transceiver struct */ -}; - -/****************************************************************************** - * REGISTERS - *****************************************************************************/ -/* register size */ -#define REG_BITS (32) - -/* HCCPARAMS */ -#define HCCPARAMS_LEN BIT(17) - -/* DCCPARAMS */ -#define DCCPARAMS_DEN (0x1F << 0) -#define DCCPARAMS_DC BIT(7) - -/* TESTMODE */ -#define TESTMODE_FORCE BIT(0) - -/* USBCMD */ -#define USBCMD_RS BIT(0) -#define USBCMD_RST BIT(1) -#define USBCMD_SUTW BIT(13) -#define USBCMD_ATDTW BIT(14) - -/* USBSTS & USBINTR */ -#define USBi_UI BIT(0) -#define USBi_UEI BIT(1) -#define USBi_PCI BIT(2) -#define USBi_URI BIT(6) -#define USBi_SLI BIT(8) - -/* DEVICEADDR */ -#define DEVICEADDR_USBADRA BIT(24) -#define DEVICEADDR_USBADR (0x7FUL << 25) - -/* PORTSC */ -#define PORTSC_FPR BIT(6) -#define PORTSC_SUSP BIT(7) -#define PORTSC_HSP BIT(9) -#define PORTSC_PTC (0x0FUL << 16) - -/* DEVLC */ -#define DEVLC_PSPD (0x03UL << 25) -#define DEVLC_PSPD_HS (0x02UL << 25) - -/* USBMODE */ -#define USBMODE_CM (0x03UL << 0) -#define USBMODE_CM_IDLE (0x00UL << 0) -#define USBMODE_CM_DEVICE (0x02UL << 0) -#define USBMODE_CM_HOST (0x03UL << 0) -#define USBMODE_SLOM BIT(3) -#define USBMODE_SDIS BIT(4) - -/* ENDPTCTRL */ -#define ENDPTCTRL_RXS BIT(0) -#define ENDPTCTRL_RXT (0x03UL << 2) -#define ENDPTCTRL_RXR BIT(6) /* reserved for port 0 */ -#define ENDPTCTRL_RXE BIT(7) -#define ENDPTCTRL_TXS BIT(16) -#define ENDPTCTRL_TXT (0x03UL << 18) -#define ENDPTCTRL_TXR BIT(22) /* reserved for port 0 */ -#define ENDPTCTRL_TXE BIT(23) - -/****************************************************************************** - * LOGGING - *****************************************************************************/ -#define ci13xxx_printk(level, format, args...) \ -do { \ - if (_udc == NULL) \ - printk(level "[%s] " format "\n", __func__, ## args); \ - else \ - dev_printk(level, _udc->gadget.dev.parent, \ - "[%s] " format "\n", __func__, ## args); \ -} while (0) - -#define err(format, args...) ci13xxx_printk(KERN_ERR, format, ## args) -#define warn(format, args...) ci13xxx_printk(KERN_WARNING, format, ## args) -#define info(format, args...) ci13xxx_printk(KERN_INFO, format, ## args) - -#ifdef TRACE -#define trace(format, args...) ci13xxx_printk(KERN_DEBUG, format, ## args) -#define dbg_trace(format, args...) dev_dbg(dev, format, ##args) -#else -#define trace(format, args...) do {} while (0) -#define dbg_trace(format, args...) do {} while (0) -#endif - -#endif /* _CI13XXX_h_ */ diff --git a/trunk/drivers/usb/gadget/composite.c b/trunk/drivers/usb/gadget/composite.c index baaebf2830fc..390749bbb0c3 100644 --- a/trunk/drivers/usb/gadget/composite.c +++ b/trunk/drivers/usb/gadget/composite.c @@ -40,27 +40,27 @@ static int (*composite_gadget_bind)(struct usb_composite_dev *cdev); */ static ushort idVendor; -module_param(idVendor, ushort, 0); +module_param(idVendor, ushort, 0644); MODULE_PARM_DESC(idVendor, "USB Vendor ID"); static ushort idProduct; -module_param(idProduct, ushort, 0); +module_param(idProduct, ushort, 0644); MODULE_PARM_DESC(idProduct, "USB Product ID"); static ushort bcdDevice; -module_param(bcdDevice, ushort, 0); +module_param(bcdDevice, ushort, 0644); MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)"); static char *iManufacturer; -module_param(iManufacturer, charp, 0); +module_param(iManufacturer, charp, 0644); MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string"); static char *iProduct; -module_param(iProduct, charp, 0); +module_param(iProduct, charp, 0644); MODULE_PARM_DESC(iProduct, "USB Product string"); static char *iSerialNumber; -module_param(iSerialNumber, charp, 0); +module_param(iSerialNumber, charp, 0644); MODULE_PARM_DESC(iSerialNumber, "SerialNumber string"); static char composite_manufacturer[50]; @@ -734,9 +734,23 @@ int usb_add_config(struct usb_composite_dev *cdev, INIT_LIST_HEAD(&config->functions); config->next_interface_id = 0; + memset(config->interface, 0, sizeof(config->interface)); status = bind(config); if (status < 0) { + while (!list_empty(&config->functions)) { + struct usb_function *f; + + f = list_first_entry(&config->functions, + struct usb_function, list); + list_del(&f->list); + if (f->unbind) { + DBG(cdev, "unbind function '%s'/%p\n", + f->name, f); + f->unbind(config, f); + /* may free memory for "f" */ + } + } list_del(&config->list); config->cdev = NULL; } else { @@ -774,6 +788,53 @@ int usb_add_config(struct usb_composite_dev *cdev, return status; } +static void remove_config(struct usb_composite_dev *cdev, + struct usb_configuration *config) +{ + while (!list_empty(&config->functions)) { + struct usb_function *f; + + f = list_first_entry(&config->functions, + struct usb_function, list); + list_del(&f->list); + if (f->unbind) { + DBG(cdev, "unbind function '%s'/%p\n", f->name, f); + f->unbind(config, f); + /* may free memory for "f" */ + } + } + list_del(&config->list); + if (config->unbind) { + DBG(cdev, "unbind config '%s'/%p\n", config->label, config); + config->unbind(config); + /* may free memory for "c" */ + } +} + +/** + * usb_remove_config() - remove a configuration from a device. + * @cdev: wraps the USB gadget + * @config: the configuration + * + * Drivers must call usb_gadget_disconnect before calling this function + * to disconnect the device from the host and make sure the host will not + * try to enumerate the device while we are changing the config list. + */ +void usb_remove_config(struct usb_composite_dev *cdev, + struct usb_configuration *config) +{ + unsigned long flags; + + spin_lock_irqsave(&cdev->lock, flags); + + if (cdev->config == config) + reset_config(cdev); + + spin_unlock_irqrestore(&cdev->lock, flags); + + remove_config(cdev, config); +} + /*-------------------------------------------------------------------------*/ /* We support strings in multiple languages ... string descriptor zero @@ -785,7 +846,7 @@ int usb_add_config(struct usb_composite_dev *cdev, static void collect_langs(struct usb_gadget_strings **sp, __le16 *buf) { const struct usb_gadget_strings *s; - u16 language; + __le16 language; __le16 *tmp; while (*sp) { @@ -877,7 +938,7 @@ static int get_string(struct usb_composite_dev *cdev, else if (cdev->product_override == id) str = iProduct ?: composite->iProduct; else if (cdev->serial_override == id) - str = iSerialNumber; + str = iSerialNumber ?: composite->iSerialNumber; else str = NULL; if (str) { @@ -1328,28 +1389,9 @@ composite_unbind(struct usb_gadget *gadget) while (!list_empty(&cdev->configs)) { struct usb_configuration *c; - c = list_first_entry(&cdev->configs, struct usb_configuration, list); - while (!list_empty(&c->functions)) { - struct usb_function *f; - - f = list_first_entry(&c->functions, - struct usb_function, list); - list_del(&f->list); - if (f->unbind) { - DBG(cdev, "unbind function '%s'/%p\n", - f->name, f); - f->unbind(c, f); - /* may free memory for "f" */ - } - } - list_del(&c->list); - if (c->unbind) { - DBG(cdev, "unbind config '%s'/%p\n", c->label, c); - c->unbind(c); - /* may free memory for "c" */ - } + remove_config(cdev, c); } if (composite->unbind) composite->unbind(cdev); @@ -1431,10 +1473,16 @@ static int composite_bind(struct usb_gadget *gadget) /* standardized runtime overrides for device ID data */ if (idVendor) cdev->desc.idVendor = cpu_to_le16(idVendor); + else + idVendor = le16_to_cpu(cdev->desc.idVendor); if (idProduct) cdev->desc.idProduct = cpu_to_le16(idProduct); + else + idProduct = le16_to_cpu(cdev->desc.idProduct); if (bcdDevice) cdev->desc.bcdDevice = cpu_to_le16(bcdDevice); + else + bcdDevice = le16_to_cpu(cdev->desc.bcdDevice); /* string overrides */ if (iManufacturer || !cdev->desc.iManufacturer) { @@ -1455,7 +1503,8 @@ static int composite_bind(struct usb_gadget *gadget) cdev->product_override = override_id(cdev, &cdev->desc.iProduct); - if (iSerialNumber) + if (iSerialNumber || + (!cdev->desc.iSerialNumber && composite->iSerialNumber)) cdev->serial_override = override_id(cdev, &cdev->desc.iSerialNumber); diff --git a/trunk/drivers/usb/gadget/dummy_hcd.c b/trunk/drivers/usb/gadget/dummy_hcd.c index 170cbe89d9f8..b799106027ad 100644 --- a/trunk/drivers/usb/gadget/dummy_hcd.c +++ b/trunk/drivers/usb/gadget/dummy_hcd.c @@ -595,14 +595,12 @@ static struct usb_request *dummy_alloc_request(struct usb_ep *_ep, static void dummy_free_request(struct usb_ep *_ep, struct usb_request *_req) { - struct dummy_ep *ep; struct dummy_request *req; - if (!_ep || !_req) - return; - ep = usb_ep_to_dummy_ep(_ep); - if (!ep->desc && _ep->name != ep0name) + if (!_ep || !_req) { + WARN_ON(1); return; + } req = usb_request_to_dummy_request(_req); WARN_ON(!list_empty(&req->queue)); diff --git a/trunk/drivers/usb/gadget/f_fs.c b/trunk/drivers/usb/gadget/f_fs.c index f52cb1ae45d9..dcd1c7fbb016 100644 --- a/trunk/drivers/usb/gadget/f_fs.c +++ b/trunk/drivers/usb/gadget/f_fs.c @@ -1031,6 +1031,12 @@ struct ffs_sb_fill_data { struct ffs_file_perms perms; umode_t root_mode; const char *dev_name; + union { + /* set by ffs_fs_mount(), read by ffs_sb_fill() */ + void *private_data; + /* set by ffs_sb_fill(), read by ffs_fs_mount */ + struct ffs_data *ffs_data; + }; }; static int ffs_sb_fill(struct super_block *sb, void *_data, int silent) @@ -1047,8 +1053,14 @@ static int ffs_sb_fill(struct super_block *sb, void *_data, int silent) goto Enomem; ffs->sb = sb; - ffs->dev_name = data->dev_name; + ffs->dev_name = kstrdup(data->dev_name, GFP_KERNEL); + if (unlikely(!ffs->dev_name)) + goto Enomem; ffs->file_perms = data->perms; + ffs->private_data = data->private_data; + + /* used by the caller of this function */ + data->ffs_data = ffs; sb->s_fs_info = ffs; sb->s_blocksize = PAGE_CACHE_SIZE; @@ -1167,20 +1179,29 @@ ffs_fs_mount(struct file_system_type *t, int flags, }, .root_mode = S_IFDIR | 0500, }; + struct dentry *rv; int ret; + void *ffs_dev; ENTER(); - ret = functionfs_check_dev_callback(dev_name); - if (unlikely(ret < 0)) - return ERR_PTR(ret); - ret = ffs_fs_parse_opts(&data, opts); if (unlikely(ret < 0)) return ERR_PTR(ret); + ffs_dev = functionfs_acquire_dev_callback(dev_name); + if (IS_ERR(ffs_dev)) + return ffs_dev; + data.dev_name = dev_name; - return mount_single(t, flags, &data, ffs_sb_fill); + data.private_data = ffs_dev; + rv = mount_nodev(t, flags, &data, ffs_sb_fill); + + /* data.ffs_data is set by ffs_sb_fill */ + if (IS_ERR(rv)) + functionfs_release_dev_callback(data.ffs_data); + + return rv; } static void @@ -1189,8 +1210,10 @@ ffs_fs_kill_sb(struct super_block *sb) ENTER(); kill_litter_super(sb); - if (sb->s_fs_info) + if (sb->s_fs_info) { + functionfs_release_dev_callback(sb->s_fs_info); ffs_data_put(sb->s_fs_info); + } } static struct file_system_type ffs_fs_type = { @@ -1256,6 +1279,7 @@ static void ffs_data_put(struct ffs_data *ffs) ffs_data_clear(ffs); BUG_ON(waitqueue_active(&ffs->ev.waitq) || waitqueue_active(&ffs->ep0req_completion.wait)); + kfree(ffs->dev_name); kfree(ffs); } } @@ -1473,8 +1497,22 @@ static int functionfs_bind_config(struct usb_composite_dev *cdev, static void ffs_func_free(struct ffs_function *func) { + struct ffs_ep *ep = func->eps; + unsigned count = func->ffs->eps_count; + unsigned long flags; + ENTER(); + /* cleanup after autoconfig */ + spin_lock_irqsave(&func->ffs->eps_lock, flags); + do { + if (ep->ep && ep->req) + usb_ep_free_request(ep->ep, ep->req); + ep->req = NULL; + ++ep; + } while (--count); + spin_unlock_irqrestore(&func->ffs->eps_lock, flags); + ffs_data_put(func->ffs); kfree(func->eps); diff --git a/trunk/drivers/usb/gadget/f_hid.c b/trunk/drivers/usb/gadget/f_hid.c index b2113420b806..3b3932c55361 100644 --- a/trunk/drivers/usb/gadget/f_hid.c +++ b/trunk/drivers/usb/gadget/f_hid.c @@ -374,7 +374,7 @@ static int hidg_setup(struct usb_function *f, break; default: - VDBG(cdev, "Unknown decriptor request 0x%x\n", + VDBG(cdev, "Unknown descriptor request 0x%x\n", value >> 8); goto stall; break; diff --git a/trunk/drivers/usb/gadget/f_loopback.c b/trunk/drivers/usb/gadget/f_loopback.c index 2c0cd824c667..7275706caeb0 100644 --- a/trunk/drivers/usb/gadget/f_loopback.c +++ b/trunk/drivers/usb/gadget/f_loopback.c @@ -286,7 +286,7 @@ static void disable_loopback(struct f_loopback *loop) struct usb_composite_dev *cdev; cdev = loop->function.config->cdev; - disable_endpoints(cdev, loop->in_ep, loop->out_ep); + disable_endpoints(cdev, loop->in_ep, loop->out_ep, NULL, NULL); VDBG(cdev, "%s disabled\n", loop->function.name); } @@ -329,7 +329,7 @@ enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop) * than 'buflen' bytes each. */ for (i = 0; i < qlen && result == 0; i++) { - req = alloc_ep_req(ep); + req = alloc_ep_req(ep, 0); if (req) { req->complete = loopback_complete; result = usb_ep_queue(ep, req, GFP_ATOMIC); diff --git a/trunk/drivers/usb/gadget/f_mass_storage.c b/trunk/drivers/usb/gadget/f_mass_storage.c index cb8c162cae5a..f67b453740bd 100644 --- a/trunk/drivers/usb/gadget/f_mass_storage.c +++ b/trunk/drivers/usb/gadget/f_mass_storage.c @@ -3110,13 +3110,6 @@ static int fsg_bind_config(struct usb_composite_dev *cdev, return rc; } -static inline int __deprecated __maybe_unused -fsg_add(struct usb_composite_dev *cdev, struct usb_configuration *c, - struct fsg_common *common) -{ - return fsg_bind_config(cdev, c, common); -} - /************************* Module parameters *************************/ diff --git a/trunk/drivers/usb/gadget/f_rndis.c b/trunk/drivers/usb/gadget/f_rndis.c index 52343654f5df..b1681e45aca7 100644 --- a/trunk/drivers/usb/gadget/f_rndis.c +++ b/trunk/drivers/usb/gadget/f_rndis.c @@ -71,6 +71,8 @@ struct f_rndis { struct gether port; u8 ctrl_id, data_id; u8 ethaddr[ETH_ALEN]; + u32 vendorID; + const char *manufacturer; int config; struct usb_ep *notify; @@ -637,7 +639,7 @@ static void rndis_open(struct gether *geth) DBG(cdev, "%s\n", __func__); - rndis_set_param_medium(rndis->config, NDIS_MEDIUM_802_3, + rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, bitrate(cdev->gadget) / 100); rndis_signal_connect(rndis->config); } @@ -648,7 +650,7 @@ static void rndis_close(struct gether *geth) DBG(geth->func.config->cdev, "%s\n", __func__); - rndis_set_param_medium(rndis->config, NDIS_MEDIUM_802_3, 0); + rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0); rndis_signal_disconnect(rndis->config); } @@ -765,15 +767,13 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) goto fail; rndis->config = status; - rndis_set_param_medium(rndis->config, NDIS_MEDIUM_802_3, 0); + rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0); rndis_set_host_mac(rndis->config, rndis->ethaddr); -#if 0 -// FIXME - if (rndis_set_param_vendor(rndis->config, vendorID, - manufacturer)) - goto fail0; -#endif + if (rndis->manufacturer && rndis->vendorID && + rndis_set_param_vendor(rndis->config, rndis->vendorID, + rndis->manufacturer)) + goto fail; /* NOTE: all that is done without knowing or caring about * the network link ... which is unavailable to this code @@ -820,6 +820,7 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f) rndis_deregister(rndis->config); rndis_exit(); + rndis_string_defs[0].id = 0; if (gadget_is_superspeed(c->cdev->gadget)) usb_free_descriptors(f->ss_descriptors); @@ -840,20 +841,9 @@ static inline bool can_support_rndis(struct usb_configuration *c) return true; } -/** - * rndis_bind_config - add RNDIS network link to a configuration - * @c: the configuration to support the network link - * @ethaddr: a buffer in which the ethernet address of the host side - * side of the link was recorded - * Context: single threaded during gadget setup - * - * Returns zero on success, else negative errno. - * - * Caller must have called @gether_setup(). Caller is also responsible - * for calling @gether_cleanup() before module unload. - */ int -rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) +rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], + u32 vendorID, const char *manufacturer) { struct f_rndis *rndis; int status; @@ -898,6 +888,8 @@ rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) goto fail; memcpy(rndis->ethaddr, ethaddr, ETH_ALEN); + rndis->vendorID = vendorID; + rndis->manufacturer = manufacturer; /* RNDIS activates when the host changes this filter */ rndis->port.cdc_filter = 0; diff --git a/trunk/drivers/usb/gadget/f_sourcesink.c b/trunk/drivers/usb/gadget/f_sourcesink.c index 7aa7ac82c02c..5c1b68b63c98 100644 --- a/trunk/drivers/usb/gadget/f_sourcesink.c +++ b/trunk/drivers/usb/gadget/f_sourcesink.c @@ -51,6 +51,9 @@ struct f_sourcesink { struct usb_ep *in_ep; struct usb_ep *out_ep; + struct usb_ep *iso_in_ep; + struct usb_ep *iso_out_ep; + int cur_alt; }; static inline struct f_sourcesink *func_to_ss(struct usb_function *f) @@ -59,18 +62,45 @@ static inline struct f_sourcesink *func_to_ss(struct usb_function *f) } static unsigned pattern; -module_param(pattern, uint, 0); -MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63 "); +module_param(pattern, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63, 2 = none"); + +static unsigned isoc_interval = 4; +module_param(isoc_interval, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(isoc_interval, "1 - 16"); + +static unsigned isoc_maxpacket = 1024; +module_param(isoc_maxpacket, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(isoc_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)"); + +static unsigned isoc_mult; +module_param(isoc_mult, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(isoc_mult, "0 - 2 (hs/ss only)"); + +static unsigned isoc_maxburst; +module_param(isoc_maxburst, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(isoc_maxburst, "0 - 15 (ss only)"); /*-------------------------------------------------------------------------*/ -static struct usb_interface_descriptor source_sink_intf = { - .bLength = sizeof source_sink_intf, +static struct usb_interface_descriptor source_sink_intf_alt0 = { + .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, + .bAlternateSetting = 0, .bNumEndpoints = 2, .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - /* .iInterface = DYNAMIC */ + /* .iInterface = DYNAMIC */ +}; + +static struct usb_interface_descriptor source_sink_intf_alt1 = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + + .bAlternateSetting = 1, + .bNumEndpoints = 4, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + /* .iInterface = DYNAMIC */ }; /* full speed support: */ @@ -91,10 +121,36 @@ static struct usb_endpoint_descriptor fs_sink_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, }; +static struct usb_endpoint_descriptor fs_iso_source_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = cpu_to_le16(1023), + .bInterval = 4, +}; + +static struct usb_endpoint_descriptor fs_iso_sink_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = cpu_to_le16(1023), + .bInterval = 4, +}; + static struct usb_descriptor_header *fs_source_sink_descs[] = { - (struct usb_descriptor_header *) &source_sink_intf, + (struct usb_descriptor_header *) &source_sink_intf_alt0, (struct usb_descriptor_header *) &fs_sink_desc, (struct usb_descriptor_header *) &fs_source_desc, + (struct usb_descriptor_header *) &source_sink_intf_alt1, +#define FS_ALT_IFC_1_OFFSET 3 + (struct usb_descriptor_header *) &fs_sink_desc, + (struct usb_descriptor_header *) &fs_source_desc, + (struct usb_descriptor_header *) &fs_iso_sink_desc, + (struct usb_descriptor_header *) &fs_iso_source_desc, NULL, }; @@ -116,10 +172,34 @@ static struct usb_endpoint_descriptor hs_sink_desc = { .wMaxPacketSize = cpu_to_le16(512), }; +static struct usb_endpoint_descriptor hs_iso_source_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bmAttributes = USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = cpu_to_le16(1024), + .bInterval = 4, +}; + +static struct usb_endpoint_descriptor hs_iso_sink_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bmAttributes = USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = cpu_to_le16(1024), + .bInterval = 4, +}; + static struct usb_descriptor_header *hs_source_sink_descs[] = { - (struct usb_descriptor_header *) &source_sink_intf, + (struct usb_descriptor_header *) &source_sink_intf_alt0, (struct usb_descriptor_header *) &hs_source_desc, (struct usb_descriptor_header *) &hs_sink_desc, + (struct usb_descriptor_header *) &source_sink_intf_alt1, +#define HS_ALT_IFC_1_OFFSET 3 + (struct usb_descriptor_header *) &hs_source_desc, + (struct usb_descriptor_header *) &hs_sink_desc, + (struct usb_descriptor_header *) &hs_iso_source_desc, + (struct usb_descriptor_header *) &hs_iso_sink_desc, NULL, }; @@ -136,6 +216,7 @@ static struct usb_endpoint_descriptor ss_source_desc = { struct usb_ss_ep_comp_descriptor ss_source_comp_desc = { .bLength = USB_DT_SS_EP_COMP_SIZE, .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bMaxBurst = 0, .bmAttributes = 0, .wBytesPerInterval = 0, @@ -152,17 +233,64 @@ static struct usb_endpoint_descriptor ss_sink_desc = { struct usb_ss_ep_comp_descriptor ss_sink_comp_desc = { .bLength = USB_DT_SS_EP_COMP_SIZE, .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bMaxBurst = 0, .bmAttributes = 0, .wBytesPerInterval = 0, }; +static struct usb_endpoint_descriptor ss_iso_source_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bmAttributes = USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = cpu_to_le16(1024), + .bInterval = 4, +}; + +struct usb_ss_ep_comp_descriptor ss_iso_source_comp_desc = { + .bLength = USB_DT_SS_EP_COMP_SIZE, + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + .bMaxBurst = 0, + .bmAttributes = 0, + .wBytesPerInterval = cpu_to_le16(1024), +}; + +static struct usb_endpoint_descriptor ss_iso_sink_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bmAttributes = USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = cpu_to_le16(1024), + .bInterval = 4, +}; + +struct usb_ss_ep_comp_descriptor ss_iso_sink_comp_desc = { + .bLength = USB_DT_SS_EP_COMP_SIZE, + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + .bMaxBurst = 0, + .bmAttributes = 0, + .wBytesPerInterval = cpu_to_le16(1024), +}; + static struct usb_descriptor_header *ss_source_sink_descs[] = { - (struct usb_descriptor_header *) &source_sink_intf, + (struct usb_descriptor_header *) &source_sink_intf_alt0, (struct usb_descriptor_header *) &ss_source_desc, (struct usb_descriptor_header *) &ss_source_comp_desc, (struct usb_descriptor_header *) &ss_sink_desc, (struct usb_descriptor_header *) &ss_sink_comp_desc, + (struct usb_descriptor_header *) &source_sink_intf_alt1, +#define SS_ALT_IFC_1_OFFSET 5 + (struct usb_descriptor_header *) &ss_source_desc, + (struct usb_descriptor_header *) &ss_source_comp_desc, + (struct usb_descriptor_header *) &ss_sink_desc, + (struct usb_descriptor_header *) &ss_sink_comp_desc, + (struct usb_descriptor_header *) &ss_iso_source_desc, + (struct usb_descriptor_header *) &ss_iso_source_comp_desc, + (struct usb_descriptor_header *) &ss_iso_sink_desc, + (struct usb_descriptor_header *) &ss_iso_sink_comp_desc, NULL, }; @@ -196,9 +324,10 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f) id = usb_interface_id(c, f); if (id < 0) return id; - source_sink_intf.bInterfaceNumber = id; + source_sink_intf_alt0.bInterfaceNumber = id; + source_sink_intf_alt1.bInterfaceNumber = id; - /* allocate endpoints */ + /* allocate bulk endpoints */ ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc); if (!ss->in_ep) { autoconf_fail: @@ -213,12 +342,74 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f) goto autoconf_fail; ss->out_ep->driver_data = cdev; /* claim */ + /* sanity check the isoc module parameters */ + if (isoc_interval < 1) + isoc_interval = 1; + if (isoc_interval > 16) + isoc_interval = 16; + if (isoc_mult > 2) + isoc_mult = 2; + if (isoc_maxburst > 15) + isoc_maxburst = 15; + + /* fill in the FS isoc descriptors from the module parameters */ + fs_iso_source_desc.wMaxPacketSize = isoc_maxpacket > 1023 ? + 1023 : isoc_maxpacket; + fs_iso_source_desc.bInterval = isoc_interval; + fs_iso_sink_desc.wMaxPacketSize = isoc_maxpacket > 1023 ? + 1023 : isoc_maxpacket; + fs_iso_sink_desc.bInterval = isoc_interval; + + /* allocate iso endpoints */ + ss->iso_in_ep = usb_ep_autoconfig(cdev->gadget, &fs_iso_source_desc); + if (!ss->iso_in_ep) + goto no_iso; + ss->iso_in_ep->driver_data = cdev; /* claim */ + + ss->iso_out_ep = usb_ep_autoconfig(cdev->gadget, &fs_iso_sink_desc); + if (ss->iso_out_ep) { + ss->iso_out_ep->driver_data = cdev; /* claim */ + } else { + ss->iso_in_ep->driver_data = NULL; + ss->iso_in_ep = NULL; +no_iso: + /* + * We still want to work even if the UDC doesn't have isoc + * endpoints, so null out the alt interface that contains + * them and continue. + */ + fs_source_sink_descs[FS_ALT_IFC_1_OFFSET] = NULL; + hs_source_sink_descs[HS_ALT_IFC_1_OFFSET] = NULL; + ss_source_sink_descs[SS_ALT_IFC_1_OFFSET] = NULL; + } + + if (isoc_maxpacket > 1024) + isoc_maxpacket = 1024; + /* support high speed hardware */ if (gadget_is_dualspeed(c->cdev->gadget)) { hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; + + /* + * Fill in the HS isoc descriptors from the module parameters. + * We assume that the user knows what they are doing and won't + * give parameters that their UDC doesn't support. + */ + hs_iso_source_desc.wMaxPacketSize = isoc_maxpacket; + hs_iso_source_desc.wMaxPacketSize |= isoc_mult << 11; + hs_iso_source_desc.bInterval = isoc_interval; + hs_iso_source_desc.bEndpointAddress = + fs_iso_source_desc.bEndpointAddress; + + hs_iso_sink_desc.wMaxPacketSize = isoc_maxpacket; + hs_iso_sink_desc.wMaxPacketSize |= isoc_mult << 11; + hs_iso_sink_desc.bInterval = isoc_interval; + hs_iso_sink_desc.bEndpointAddress = + fs_iso_sink_desc.bEndpointAddress; + f->hs_descriptors = hs_source_sink_descs; } @@ -228,13 +419,39 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f) fs_source_desc.bEndpointAddress; ss_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; + + /* + * Fill in the SS isoc descriptors from the module parameters. + * We assume that the user knows what they are doing and won't + * give parameters that their UDC doesn't support. + */ + ss_iso_source_desc.wMaxPacketSize = isoc_maxpacket; + ss_iso_source_desc.bInterval = isoc_interval; + ss_iso_source_comp_desc.bmAttributes = isoc_mult; + ss_iso_source_comp_desc.bMaxBurst = isoc_maxburst; + ss_iso_source_comp_desc.wBytesPerInterval = + isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1); + ss_iso_source_desc.bEndpointAddress = + fs_iso_source_desc.bEndpointAddress; + + ss_iso_sink_desc.wMaxPacketSize = isoc_maxpacket; + ss_iso_sink_desc.bInterval = isoc_interval; + ss_iso_sink_comp_desc.bmAttributes = isoc_mult; + ss_iso_sink_comp_desc.bMaxBurst = isoc_maxburst; + ss_iso_sink_comp_desc.wBytesPerInterval = + isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1); + ss_iso_sink_desc.bEndpointAddress = + fs_iso_sink_desc.bEndpointAddress; + f->ss_descriptors = ss_source_sink_descs; } - DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", + DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s\n", (gadget_is_superspeed(c->cdev->gadget) ? "super" : (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")), - f->name, ss->in_ep->name, ss->out_ep->name); + f->name, ss->in_ep->name, ss->out_ep->name, + ss->iso_in_ep ? ss->iso_in_ep->name : "", + ss->iso_out_ep ? ss->iso_out_ep->name : ""); return 0; } @@ -251,6 +468,9 @@ static int check_read_data(struct f_sourcesink *ss, struct usb_request *req) u8 *buf = req->buf; struct usb_composite_dev *cdev = ss->function.config->cdev; + if (pattern == 2) + return 0; + for (i = 0; i < req->actual; i++, buf++) { switch (pattern) { @@ -265,7 +485,7 @@ static int check_read_data(struct f_sourcesink *ss, struct usb_request *req) * each usb transfer request should be. Resync is done * with set_interface or set_config. (We *WANT* it to * get quickly out of sync if controllers or their drivers - * stutter for any reason, including buffer duplcation...) + * stutter for any reason, including buffer duplication...) */ case 1: if (*buf == (u8)(i % 63)) @@ -292,21 +512,30 @@ static void reinit_write_data(struct usb_ep *ep, struct usb_request *req) for (i = 0; i < req->length; i++) *buf++ = (u8) (i % 63); break; + case 2: + break; } } static void source_sink_complete(struct usb_ep *ep, struct usb_request *req) { - struct f_sourcesink *ss = ep->driver_data; - struct usb_composite_dev *cdev = ss->function.config->cdev; - int status = req->status; + struct usb_composite_dev *cdev; + struct f_sourcesink *ss = ep->driver_data; + int status = req->status; + + /* driver_data will be null if ep has been disabled */ + if (!ss) + return; + + cdev = ss->function.config->cdev; switch (status) { case 0: /* normal completion? */ if (ep == ss->out_ep) { check_read_data(ss, req); - memset(req->buf, 0x55, req->length); + if (pattern != 2) + memset(req->buf, 0x55, req->length); } else reinit_write_data(ep, req); break; @@ -344,32 +573,57 @@ static void source_sink_complete(struct usb_ep *ep, struct usb_request *req) } } -static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in) +static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in, + bool is_iso, int speed) { struct usb_ep *ep; struct usb_request *req; - int status; + int i, size, status; + + for (i = 0; i < 8; i++) { + if (is_iso) { + switch (speed) { + case USB_SPEED_SUPER: + size = isoc_maxpacket * (isoc_mult + 1) * + (isoc_maxburst + 1); + break; + case USB_SPEED_HIGH: + size = isoc_maxpacket * (isoc_mult + 1); + break; + default: + size = isoc_maxpacket > 1023 ? + 1023 : isoc_maxpacket; + break; + } + ep = is_in ? ss->iso_in_ep : ss->iso_out_ep; + req = alloc_ep_req(ep, size); + } else { + ep = is_in ? ss->in_ep : ss->out_ep; + req = alloc_ep_req(ep, 0); + } - ep = is_in ? ss->in_ep : ss->out_ep; - req = alloc_ep_req(ep); - if (!req) - return -ENOMEM; + if (!req) + return -ENOMEM; - req->complete = source_sink_complete; - if (is_in) - reinit_write_data(ep, req); - else - memset(req->buf, 0x55, req->length); + req->complete = source_sink_complete; + if (is_in) + reinit_write_data(ep, req); + else if (pattern != 2) + memset(req->buf, 0x55, req->length); - status = usb_ep_queue(ep, req, GFP_ATOMIC); - if (status) { - struct usb_composite_dev *cdev; + status = usb_ep_queue(ep, req, GFP_ATOMIC); + if (status) { + struct usb_composite_dev *cdev; - cdev = ss->function.config->cdev; - ERROR(cdev, "start %s %s --> %d\n", - is_in ? "IN" : "OUT", - ep->name, status); - free_ep_req(ep, req); + cdev = ss->function.config->cdev; + ERROR(cdev, "start %s%s %s --> %d\n", + is_iso ? "ISO-" : "", is_in ? "IN" : "OUT", + ep->name, status); + free_ep_req(ep, req); + } + + if (!is_iso) + break; } return status; @@ -380,17 +634,20 @@ static void disable_source_sink(struct f_sourcesink *ss) struct usb_composite_dev *cdev; cdev = ss->function.config->cdev; - disable_endpoints(cdev, ss->in_ep, ss->out_ep); + disable_endpoints(cdev, ss->in_ep, ss->out_ep, ss->iso_in_ep, + ss->iso_out_ep); VDBG(cdev, "%s disabled\n", ss->function.name); } static int -enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss) +enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss, + int alt) { int result = 0; + int speed = cdev->gadget->speed; struct usb_ep *ep; - /* one endpoint writes (sources) zeroes IN (to the host) */ + /* one bulk endpoint writes (sources) zeroes IN (to the host) */ ep = ss->in_ep; result = config_ep_by_speed(cdev->gadget, &(ss->function), ep); if (result) @@ -400,7 +657,7 @@ enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss) return result; ep->driver_data = ss; - result = source_sink_start_ep(ss, true); + result = source_sink_start_ep(ss, true, false, speed); if (result < 0) { fail: ep = ss->in_ep; @@ -409,7 +666,7 @@ enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss) return result; } - /* one endpoint reads (sinks) anything OUT (from the host) */ + /* one bulk endpoint reads (sinks) anything OUT (from the host) */ ep = ss->out_ep; result = config_ep_by_speed(cdev->gadget, &(ss->function), ep); if (result) @@ -419,27 +676,82 @@ enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss) goto fail; ep->driver_data = ss; - result = source_sink_start_ep(ss, false); + result = source_sink_start_ep(ss, false, false, speed); if (result < 0) { +fail2: + ep = ss->out_ep; usb_ep_disable(ep); ep->driver_data = NULL; goto fail; } - DBG(cdev, "%s enabled\n", ss->function.name); + if (alt == 0) + goto out; + + /* one iso endpoint writes (sources) zeroes IN (to the host) */ + ep = ss->iso_in_ep; + if (ep) { + result = config_ep_by_speed(cdev->gadget, &(ss->function), ep); + if (result) + goto fail2; + result = usb_ep_enable(ep); + if (result < 0) + goto fail2; + ep->driver_data = ss; + + result = source_sink_start_ep(ss, true, true, speed); + if (result < 0) { +fail3: + ep = ss->iso_in_ep; + if (ep) { + usb_ep_disable(ep); + ep->driver_data = NULL; + } + goto fail2; + } + } + + /* one iso endpoint reads (sinks) anything OUT (from the host) */ + ep = ss->iso_out_ep; + if (ep) { + result = config_ep_by_speed(cdev->gadget, &(ss->function), ep); + if (result) + goto fail3; + result = usb_ep_enable(ep); + if (result < 0) + goto fail3; + ep->driver_data = ss; + + result = source_sink_start_ep(ss, false, true, speed); + if (result < 0) { + usb_ep_disable(ep); + ep->driver_data = NULL; + goto fail3; + } + } +out: + ss->cur_alt = alt; + + DBG(cdev, "%s enabled, alt intf %d\n", ss->function.name, alt); return result; } static int sourcesink_set_alt(struct usb_function *f, unsigned intf, unsigned alt) { - struct f_sourcesink *ss = func_to_ss(f); - struct usb_composite_dev *cdev = f->config->cdev; + struct f_sourcesink *ss = func_to_ss(f); + struct usb_composite_dev *cdev = f->config->cdev; - /* we know alt is zero */ if (ss->in_ep->driver_data) disable_source_sink(ss); - return enable_source_sink(cdev, ss); + return enable_source_sink(cdev, ss, alt); +} + +static int sourcesink_get_alt(struct usb_function *f, unsigned intf) +{ + struct f_sourcesink *ss = func_to_ss(f); + + return ss->cur_alt; } static void sourcesink_disable(struct usb_function *f) @@ -465,6 +777,7 @@ static int __init sourcesink_bind_config(struct usb_configuration *c) ss->function.bind = sourcesink_bind; ss->function.unbind = sourcesink_unbind; ss->function.set_alt = sourcesink_set_alt; + ss->function.get_alt = sourcesink_get_alt; ss->function.disable = sourcesink_disable; status = usb_add_function(c, &ss->function); @@ -536,7 +849,7 @@ static int sourcesink_setup(struct usb_configuration *c, req->length = value; value = usb_ep_queue(c->cdev->gadget->ep0, req, GFP_ATOMIC); if (value < 0) - ERROR(c->cdev, "source/sinkc response, err %d\n", + ERROR(c->cdev, "source/sink response, err %d\n", value); } @@ -545,12 +858,12 @@ static int sourcesink_setup(struct usb_configuration *c, } static struct usb_configuration sourcesink_driver = { - .label = "source/sink", - .strings = sourcesink_strings, - .setup = sourcesink_setup, - .bConfigurationValue = 3, - .bmAttributes = USB_CONFIG_ATT_SELFPOWER, - /* .iConfiguration = DYNAMIC */ + .label = "source/sink", + .strings = sourcesink_strings, + .setup = sourcesink_setup, + .bConfigurationValue = 3, + .bmAttributes = USB_CONFIG_ATT_SELFPOWER, + /* .iConfiguration = DYNAMIC */ }; /** @@ -567,7 +880,8 @@ int __init sourcesink_add(struct usb_composite_dev *cdev, bool autoresume) return id; strings_sourcesink[0].id = id; - source_sink_intf.iInterface = id; + source_sink_intf_alt0.iInterface = id; + source_sink_intf_alt1.iInterface = id; sourcesink_driver.iConfiguration = id; /* support autoresume for remote wakeup testing */ diff --git a/trunk/drivers/usb/gadget/fsl_qe_udc.c b/trunk/drivers/usb/gadget/fsl_qe_udc.c index 877a2c46672b..51881f3bd07a 100644 --- a/trunk/drivers/usb/gadget/fsl_qe_udc.c +++ b/trunk/drivers/usb/gadget/fsl_qe_udc.c @@ -71,9 +71,6 @@ static struct usb_endpoint_descriptor qe_ep0_desc = { .wMaxPacketSize = USB_MAX_CTRL_PAYLOAD, }; -/* it is initialized in probe() */ -static struct qe_udc *udc_controller; - /******************************************************************** * Internal Used Function Start ********************************************************************/ @@ -188,8 +185,8 @@ static int qe_ep0_stall(struct qe_udc *udc) { qe_eptx_stall_change(&udc->eps[0], 1); qe_eprx_stall_change(&udc->eps[0], 1); - udc_controller->ep0_state = WAIT_FOR_SETUP; - udc_controller->ep0_dir = 0; + udc->ep0_state = WAIT_FOR_SETUP; + udc->ep0_dir = 0; return 0; } @@ -450,13 +447,13 @@ static int qe_ep_rxbd_update(struct qe_ep *ep) ep->rxbuf_d = virt_to_phys((void *)ep->rxbuffer); if (ep->rxbuf_d == DMA_ADDR_INVALID) { - ep->rxbuf_d = dma_map_single(udc_controller->gadget.dev.parent, + ep->rxbuf_d = dma_map_single(ep->udc->gadget.dev.parent, ep->rxbuffer, size, DMA_FROM_DEVICE); ep->rxbufmap = 1; } else { - dma_sync_single_for_device(udc_controller->gadget.dev.parent, + dma_sync_single_for_device(ep->udc->gadget.dev.parent, ep->rxbuf_d, size, DMA_FROM_DEVICE); ep->rxbufmap = 0; @@ -489,10 +486,10 @@ static int qe_ep_register_init(struct qe_udc *udc, unsigned char pipe_num) epparam = udc->ep_param[pipe_num]; usep = 0; - logepnum = (ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + logepnum = (ep->ep.desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); usep |= (logepnum << USB_EPNUM_SHIFT); - switch (ep->desc->bmAttributes & 0x03) { + switch (ep->ep.desc->bmAttributes & 0x03) { case USB_ENDPOINT_XFER_BULK: usep |= USB_TRANS_BULK; break; @@ -644,7 +641,7 @@ static int qe_ep_init(struct qe_udc *udc, /* initialize ep structure */ ep->ep.maxpacket = max; ep->tm = (u8)(desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); - ep->desc = desc; + ep->ep.desc = desc; ep->stopped = 0; ep->init = 1; @@ -698,14 +695,14 @@ static int qe_ep_init(struct qe_udc *udc, return -ENODEV; } -static inline void qe_usb_enable(void) +static inline void qe_usb_enable(struct qe_udc *udc) { - setbits8(&udc_controller->usb_regs->usb_usmod, USB_MODE_EN); + setbits8(&udc->usb_regs->usb_usmod, USB_MODE_EN); } -static inline void qe_usb_disable(void) +static inline void qe_usb_disable(struct qe_udc *udc) { - clrbits8(&udc_controller->usb_regs->usb_usmod, USB_MODE_EN); + clrbits8(&udc->usb_regs->usb_usmod, USB_MODE_EN); } /*----------------------------------------------------------------------------* @@ -1599,7 +1596,7 @@ static int qe_ep_enable(struct usb_ep *_ep, ep = container_of(_ep, struct qe_ep, ep); /* catch various bogus parameters */ - if (!_ep || !desc || ep->desc || _ep->name == ep_name[0] || + if (!_ep || !desc || ep->ep.desc || _ep->name == ep_name[0] || (desc->bDescriptorType != USB_DT_ENDPOINT)) return -EINVAL; @@ -1629,7 +1626,7 @@ static int qe_ep_disable(struct usb_ep *_ep) ep = container_of(_ep, struct qe_ep, ep); udc = ep->udc; - if (!_ep || !ep->desc) { + if (!_ep || !ep->ep.desc) { dev_dbg(udc->dev, "%s not enabled\n", _ep ? ep->ep.name : NULL); return -EINVAL; } @@ -1637,7 +1634,6 @@ static int qe_ep_disable(struct usb_ep *_ep) spin_lock_irqsave(&udc->lock, flags); /* Nuke all pending requests (does flush) */ nuke(ep, -ESHUTDOWN); - ep->desc = NULL; ep->ep.desc = NULL; ep->stopped = 1; ep->tx_req = NULL; @@ -1656,13 +1652,13 @@ static int qe_ep_disable(struct usb_ep *_ep) if (ep->dir != USB_DIR_IN) { kfree(ep->rxframe); if (ep->rxbufmap) { - dma_unmap_single(udc_controller->gadget.dev.parent, + dma_unmap_single(udc->gadget.dev.parent, ep->rxbuf_d, size, DMA_FROM_DEVICE); ep->rxbuf_d = DMA_ADDR_INVALID; } else { dma_sync_single_for_cpu( - udc_controller->gadget.dev.parent, + udc->gadget.dev.parent, ep->rxbuf_d, size, DMA_FROM_DEVICE); } @@ -1715,7 +1711,7 @@ static int __qe_ep_queue(struct usb_ep *_ep, struct usb_request *_req) dev_dbg(udc->dev, "bad params\n"); return -EINVAL; } - if (!_ep || (!ep->desc && ep_index(ep))) { + if (!_ep || (!ep->ep.desc && ep_index(ep))) { dev_dbg(udc->dev, "bad ep\n"); return -EINVAL; } @@ -1826,7 +1822,7 @@ static int qe_ep_set_halt(struct usb_ep *_ep, int value) struct qe_udc *udc; ep = container_of(_ep, struct qe_ep, ep); - if (!_ep || !ep->desc) { + if (!_ep || !ep->ep.desc) { status = -EINVAL; goto out; } @@ -1880,9 +1876,10 @@ static struct usb_ep_ops qe_ep_ops = { /* Get the current frame number */ static int qe_get_frame(struct usb_gadget *gadget) { + struct qe_udc *udc = container_of(gadget, struct qe_udc, gadget); u16 tmp; - tmp = in_be16(&udc_controller->usb_param->frame_n); + tmp = in_be16(&udc->usb_param->frame_n); if (tmp & 0x8000) tmp = tmp & 0x07ff; else @@ -1891,57 +1888,16 @@ static int qe_get_frame(struct usb_gadget *gadget) return (int)tmp; } -/* Tries to wake up the host connected to this gadget - * - * Return : 0-success - * Negative-this feature not enabled by host or not supported by device hw - */ -static int qe_wakeup(struct usb_gadget *gadget) -{ - return -ENOTSUPP; -} - -/* Notify controller that VBUS is powered, Called by whatever - detects VBUS sessions */ -static int qe_vbus_session(struct usb_gadget *gadget, int is_active) -{ - return -ENOTSUPP; -} - -/* constrain controller's VBUS power usage - * This call is used by gadget drivers during SET_CONFIGURATION calls, - * reporting how much power the device may consume. For example, this - * could affect how quickly batteries are recharged. - * - * Returns zero on success, else negative errno. - */ -static int qe_vbus_draw(struct usb_gadget *gadget, unsigned mA) -{ - return -ENOTSUPP; -} - -/* Change Data+ pullup status - * this func is used by usb_gadget_connect/disconnect - */ -static int qe_pullup(struct usb_gadget *gadget, int is_on) -{ - return -ENOTSUPP; -} - -static int fsl_qe_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int fsl_qe_stop(struct usb_gadget_driver *driver); +static int fsl_qe_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver); +static int fsl_qe_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver); /* defined in usb_gadget.h */ static struct usb_gadget_ops qe_gadget_ops = { .get_frame = qe_get_frame, - .wakeup = qe_wakeup, -/* .set_selfpowered = qe_set_selfpowered,*/ /* always selfpowered */ - .vbus_session = qe_vbus_session, - .vbus_draw = qe_vbus_draw, - .pullup = qe_pullup, - .start = fsl_qe_start, - .stop = fsl_qe_stop, + .udc_start = fsl_qe_start, + .udc_stop = fsl_qe_stop, }; /*------------------------------------------------------------------------- @@ -2015,7 +1971,7 @@ static void ch9getstatus(struct qe_udc *udc, u8 request_type, u16 value, u16 usep; /* stall if endpoint doesn't exist */ - if (!target_ep->desc) + if (!target_ep->ep.desc) goto stall; usep = in_be16(&udc->usb_regs->usb_usep[pipe]); @@ -2190,7 +2146,7 @@ static int reset_irq(struct qe_udc *udc) if (udc->usb_state == USB_STATE_DEFAULT) return 0; - qe_usb_disable(); + qe_usb_disable(udc); out_8(&udc->usb_regs->usb_usadr, 0); for (i = 0; i < USB_MAX_ENDPOINTS; i++) { @@ -2202,7 +2158,7 @@ static int reset_irq(struct qe_udc *udc) udc->usb_state = USB_STATE_DEFAULT; udc->ep0_state = WAIT_FOR_SETUP; udc->ep0_dir = USB_DIR_OUT; - qe_usb_enable(); + qe_usb_enable(udc); return 0; } @@ -2327,92 +2283,65 @@ static irqreturn_t qe_udc_irq(int irq, void *_udc) /*------------------------------------------------------------------------- Gadget driver probe and unregister. --------------------------------------------------------------------------*/ -static int fsl_qe_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) +static int fsl_qe_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { - int retval; - unsigned long flags = 0; - - /* standard operations */ - if (!udc_controller) - return -ENODEV; - - if (!driver || driver->max_speed < USB_SPEED_FULL - || !bind || !driver->disconnect || !driver->setup) - return -EINVAL; - - if (udc_controller->driver) - return -EBUSY; + struct qe_udc *udc; + unsigned long flags; + udc = container_of(gadget, struct qe_udc, gadget); /* lock is needed but whether should use this lock or another */ - spin_lock_irqsave(&udc_controller->lock, flags); + spin_lock_irqsave(&udc->lock, flags); driver->driver.bus = NULL; /* hook up the driver */ - udc_controller->driver = driver; - udc_controller->gadget.dev.driver = &driver->driver; - udc_controller->gadget.speed = driver->max_speed; - spin_unlock_irqrestore(&udc_controller->lock, flags); - - retval = bind(&udc_controller->gadget); - if (retval) { - dev_err(udc_controller->dev, "bind to %s --> %d", - driver->driver.name, retval); - udc_controller->gadget.dev.driver = NULL; - udc_controller->driver = NULL; - return retval; - } + udc->driver = driver; + udc->gadget.dev.driver = &driver->driver; + udc->gadget.speed = driver->max_speed; /* Enable IRQ reg and Set usbcmd reg EN bit */ - qe_usb_enable(); - - out_be16(&udc_controller->usb_regs->usb_usber, 0xffff); - out_be16(&udc_controller->usb_regs->usb_usbmr, USB_E_DEFAULT_DEVICE); - udc_controller->usb_state = USB_STATE_ATTACHED; - udc_controller->ep0_state = WAIT_FOR_SETUP; - udc_controller->ep0_dir = USB_DIR_OUT; - dev_info(udc_controller->dev, "%s bind to driver %s \n", - udc_controller->gadget.name, driver->driver.name); + qe_usb_enable(udc); + + out_be16(&udc->usb_regs->usb_usber, 0xffff); + out_be16(&udc->usb_regs->usb_usbmr, USB_E_DEFAULT_DEVICE); + udc->usb_state = USB_STATE_ATTACHED; + udc->ep0_state = WAIT_FOR_SETUP; + udc->ep0_dir = USB_DIR_OUT; + spin_unlock_irqrestore(&udc->lock, flags); + + dev_info(udc->dev, "%s bind to driver %s\n", udc->gadget.name, + driver->driver.name); return 0; } -static int fsl_qe_stop(struct usb_gadget_driver *driver) +static int fsl_qe_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { + struct qe_udc *udc; struct qe_ep *loop_ep; unsigned long flags; - if (!udc_controller) - return -ENODEV; - - if (!driver || driver != udc_controller->driver) - return -EINVAL; - + udc = container_of(gadget, struct qe_udc, gadget); /* stop usb controller, disable intr */ - qe_usb_disable(); + qe_usb_disable(udc); /* in fact, no needed */ - udc_controller->usb_state = USB_STATE_ATTACHED; - udc_controller->ep0_state = WAIT_FOR_SETUP; - udc_controller->ep0_dir = 0; + udc->usb_state = USB_STATE_ATTACHED; + udc->ep0_state = WAIT_FOR_SETUP; + udc->ep0_dir = 0; /* stand operation */ - spin_lock_irqsave(&udc_controller->lock, flags); - udc_controller->gadget.speed = USB_SPEED_UNKNOWN; - nuke(&udc_controller->eps[0], -ESHUTDOWN); - list_for_each_entry(loop_ep, &udc_controller->gadget.ep_list, - ep.ep_list) + spin_lock_irqsave(&udc->lock, flags); + udc->gadget.speed = USB_SPEED_UNKNOWN; + nuke(&udc->eps[0], -ESHUTDOWN); + list_for_each_entry(loop_ep, &udc->gadget.ep_list, ep.ep_list) nuke(loop_ep, -ESHUTDOWN); - spin_unlock_irqrestore(&udc_controller->lock, flags); - - /* report disconnect; the controller is already quiesced */ - driver->disconnect(&udc_controller->gadget); + spin_unlock_irqrestore(&udc->lock, flags); - /* unbind gadget and unhook driver. */ - driver->unbind(&udc_controller->gadget); - udc_controller->gadget.dev.driver = NULL; - udc_controller->driver = NULL; + udc->gadget.dev.driver = NULL; + udc->driver = NULL; - dev_info(udc_controller->dev, "unregistered gadget driver '%s'\r\n", + dev_info(udc->dev, "unregistered gadget driver '%s'\r\n", driver->driver.name); return 0; } @@ -2502,7 +2431,7 @@ static int __devinit qe_ep_config(struct qe_udc *udc, unsigned char pipe_num) ep->ep.ops = &qe_ep_ops; ep->stopped = 1; ep->ep.maxpacket = (unsigned short) ~0; - ep->desc = NULL; + ep->ep.desc = NULL; ep->dir = 0xff; ep->epnum = (u8)pipe_num; ep->sent = 0; @@ -2531,21 +2460,22 @@ static int __devinit qe_ep_config(struct qe_udc *udc, unsigned char pipe_num) *----------------------------------------------------------------------*/ static void qe_udc_release(struct device *dev) { - int i = 0; + struct qe_udc *udc = container_of(dev, struct qe_udc, gadget.dev); + int i; - complete(udc_controller->done); - cpm_muram_free(cpm_muram_offset(udc_controller->ep_param[0])); + complete(udc->done); + cpm_muram_free(cpm_muram_offset(udc->ep_param[0])); for (i = 0; i < USB_MAX_ENDPOINTS; i++) - udc_controller->ep_param[i] = NULL; + udc->ep_param[i] = NULL; - kfree(udc_controller); - udc_controller = NULL; + kfree(udc); } /* Driver probe functions */ static const struct of_device_id qe_udc_match[]; static int __devinit qe_udc_probe(struct platform_device *ofdev) { + struct qe_udc *udc; const struct of_device_id *match; struct device_node *np = ofdev->dev.of_node; struct qe_ep *ep; @@ -2562,44 +2492,44 @@ static int __devinit qe_udc_probe(struct platform_device *ofdev) return -ENODEV; /* Initialize the udc structure including QH member and other member */ - udc_controller = qe_udc_config(ofdev); - if (!udc_controller) { + udc = qe_udc_config(ofdev); + if (!udc) { dev_err(&ofdev->dev, "failed to initialize\n"); return -ENOMEM; } - udc_controller->soc_type = (unsigned long)match->data; - udc_controller->usb_regs = of_iomap(np, 0); - if (!udc_controller->usb_regs) { + udc->soc_type = (unsigned long)match->data; + udc->usb_regs = of_iomap(np, 0); + if (!udc->usb_regs) { ret = -ENOMEM; goto err1; } /* initialize usb hw reg except for regs for EP, * leave usbintr reg untouched*/ - qe_udc_reg_init(udc_controller); + qe_udc_reg_init(udc); /* here comes the stand operations for probe * set the qe_udc->gadget.xxx */ - udc_controller->gadget.ops = &qe_gadget_ops; + udc->gadget.ops = &qe_gadget_ops; /* gadget.ep0 is a pointer */ - udc_controller->gadget.ep0 = &udc_controller->eps[0].ep; + udc->gadget.ep0 = &udc->eps[0].ep; - INIT_LIST_HEAD(&udc_controller->gadget.ep_list); + INIT_LIST_HEAD(&udc->gadget.ep_list); /* modify in register gadget process */ - udc_controller->gadget.speed = USB_SPEED_UNKNOWN; + udc->gadget.speed = USB_SPEED_UNKNOWN; /* name: Identifies the controller hardware type. */ - udc_controller->gadget.name = driver_name; + udc->gadget.name = driver_name; - device_initialize(&udc_controller->gadget.dev); + device_initialize(&udc->gadget.dev); - dev_set_name(&udc_controller->gadget.dev, "gadget"); + dev_set_name(&udc->gadget.dev, "gadget"); - udc_controller->gadget.dev.release = qe_udc_release; - udc_controller->gadget.dev.parent = &ofdev->dev; + udc->gadget.dev.release = qe_udc_release; + udc->gadget.dev.parent = &ofdev->dev; /* initialize qe_ep struct */ for (i = 0; i < USB_MAX_ENDPOINTS ; i++) { @@ -2608,104 +2538,104 @@ static int __devinit qe_udc_probe(struct platform_device *ofdev) /* setup the qe_ep struct and link ep.ep.list * into gadget.ep_list */ - qe_ep_config(udc_controller, (unsigned char)i); + qe_ep_config(udc, (unsigned char)i); } /* ep0 initialization in here */ - ret = qe_ep_init(udc_controller, 0, &qe_ep0_desc); + ret = qe_ep_init(udc, 0, &qe_ep0_desc); if (ret) goto err2; /* create a buf for ZLP send, need to remain zeroed */ - udc_controller->nullbuf = kzalloc(256, GFP_KERNEL); - if (udc_controller->nullbuf == NULL) { - dev_err(udc_controller->dev, "cannot alloc nullbuf\n"); + udc->nullbuf = kzalloc(256, GFP_KERNEL); + if (udc->nullbuf == NULL) { + dev_err(udc->dev, "cannot alloc nullbuf\n"); ret = -ENOMEM; goto err3; } /* buffer for data of get_status request */ - udc_controller->statusbuf = kzalloc(2, GFP_KERNEL); - if (udc_controller->statusbuf == NULL) { + udc->statusbuf = kzalloc(2, GFP_KERNEL); + if (udc->statusbuf == NULL) { ret = -ENOMEM; goto err4; } - udc_controller->nullp = virt_to_phys((void *)udc_controller->nullbuf); - if (udc_controller->nullp == DMA_ADDR_INVALID) { - udc_controller->nullp = dma_map_single( - udc_controller->gadget.dev.parent, - udc_controller->nullbuf, + udc->nullp = virt_to_phys((void *)udc->nullbuf); + if (udc->nullp == DMA_ADDR_INVALID) { + udc->nullp = dma_map_single( + udc->gadget.dev.parent, + udc->nullbuf, 256, DMA_TO_DEVICE); - udc_controller->nullmap = 1; + udc->nullmap = 1; } else { - dma_sync_single_for_device(udc_controller->gadget.dev.parent, - udc_controller->nullp, 256, + dma_sync_single_for_device(udc->gadget.dev.parent, + udc->nullp, 256, DMA_TO_DEVICE); } - tasklet_init(&udc_controller->rx_tasklet, ep_rx_tasklet, - (unsigned long)udc_controller); + tasklet_init(&udc->rx_tasklet, ep_rx_tasklet, + (unsigned long)udc); /* request irq and disable DR */ - udc_controller->usb_irq = irq_of_parse_and_map(np, 0); - if (!udc_controller->usb_irq) { + udc->usb_irq = irq_of_parse_and_map(np, 0); + if (!udc->usb_irq) { ret = -EINVAL; goto err_noirq; } - ret = request_irq(udc_controller->usb_irq, qe_udc_irq, 0, - driver_name, udc_controller); + ret = request_irq(udc->usb_irq, qe_udc_irq, 0, + driver_name, udc); if (ret) { - dev_err(udc_controller->dev, "cannot request irq %d err %d \n", - udc_controller->usb_irq, ret); + dev_err(udc->dev, "cannot request irq %d err %d\n", + udc->usb_irq, ret); goto err5; } - ret = device_add(&udc_controller->gadget.dev); + ret = device_add(&udc->gadget.dev); if (ret) goto err6; - ret = usb_add_gadget_udc(&ofdev->dev, &udc_controller->gadget); + ret = usb_add_gadget_udc(&ofdev->dev, &udc->gadget); if (ret) goto err7; - dev_info(udc_controller->dev, + dev_set_drvdata(&ofdev->dev, udc); + dev_info(udc->dev, "%s USB controller initialized as device\n", - (udc_controller->soc_type == PORT_QE) ? "QE" : "CPM"); + (udc->soc_type == PORT_QE) ? "QE" : "CPM"); return 0; err7: - device_unregister(&udc_controller->gadget.dev); + device_unregister(&udc->gadget.dev); err6: - free_irq(udc_controller->usb_irq, udc_controller); + free_irq(udc->usb_irq, udc); err5: - irq_dispose_mapping(udc_controller->usb_irq); + irq_dispose_mapping(udc->usb_irq); err_noirq: - if (udc_controller->nullmap) { - dma_unmap_single(udc_controller->gadget.dev.parent, - udc_controller->nullp, 256, + if (udc->nullmap) { + dma_unmap_single(udc->gadget.dev.parent, + udc->nullp, 256, DMA_TO_DEVICE); - udc_controller->nullp = DMA_ADDR_INVALID; + udc->nullp = DMA_ADDR_INVALID; } else { - dma_sync_single_for_cpu(udc_controller->gadget.dev.parent, - udc_controller->nullp, 256, + dma_sync_single_for_cpu(udc->gadget.dev.parent, + udc->nullp, 256, DMA_TO_DEVICE); } - kfree(udc_controller->statusbuf); + kfree(udc->statusbuf); err4: - kfree(udc_controller->nullbuf); + kfree(udc->nullbuf); err3: - ep = &udc_controller->eps[0]; + ep = &udc->eps[0]; cpm_muram_free(cpm_muram_offset(ep->rxbase)); kfree(ep->rxframe); kfree(ep->rxbuffer); kfree(ep->txframe); err2: - iounmap(udc_controller->usb_regs); + iounmap(udc->usb_regs); err1: - kfree(udc_controller); - udc_controller = NULL; + kfree(udc); return ret; } @@ -2723,44 +2653,41 @@ static int qe_udc_resume(struct platform_device *dev) static int __devexit qe_udc_remove(struct platform_device *ofdev) { + struct qe_udc *udc = dev_get_drvdata(&ofdev->dev); struct qe_ep *ep; unsigned int size; - DECLARE_COMPLETION(done); - if (!udc_controller) - return -ENODEV; - - usb_del_gadget_udc(&udc_controller->gadget); + usb_del_gadget_udc(&udc->gadget); - udc_controller->done = &done; - tasklet_disable(&udc_controller->rx_tasklet); + udc->done = &done; + tasklet_disable(&udc->rx_tasklet); - if (udc_controller->nullmap) { - dma_unmap_single(udc_controller->gadget.dev.parent, - udc_controller->nullp, 256, + if (udc->nullmap) { + dma_unmap_single(udc->gadget.dev.parent, + udc->nullp, 256, DMA_TO_DEVICE); - udc_controller->nullp = DMA_ADDR_INVALID; + udc->nullp = DMA_ADDR_INVALID; } else { - dma_sync_single_for_cpu(udc_controller->gadget.dev.parent, - udc_controller->nullp, 256, + dma_sync_single_for_cpu(udc->gadget.dev.parent, + udc->nullp, 256, DMA_TO_DEVICE); } - kfree(udc_controller->statusbuf); - kfree(udc_controller->nullbuf); + kfree(udc->statusbuf); + kfree(udc->nullbuf); - ep = &udc_controller->eps[0]; + ep = &udc->eps[0]; cpm_muram_free(cpm_muram_offset(ep->rxbase)); size = (ep->ep.maxpacket + USB_CRC_SIZE + 2) * (USB_BDRING_LEN + 1); kfree(ep->rxframe); if (ep->rxbufmap) { - dma_unmap_single(udc_controller->gadget.dev.parent, + dma_unmap_single(udc->gadget.dev.parent, ep->rxbuf_d, size, DMA_FROM_DEVICE); ep->rxbuf_d = DMA_ADDR_INVALID; } else { - dma_sync_single_for_cpu(udc_controller->gadget.dev.parent, + dma_sync_single_for_cpu(udc->gadget.dev.parent, ep->rxbuf_d, size, DMA_FROM_DEVICE); } @@ -2768,14 +2695,14 @@ static int __devexit qe_udc_remove(struct platform_device *ofdev) kfree(ep->rxbuffer); kfree(ep->txframe); - free_irq(udc_controller->usb_irq, udc_controller); - irq_dispose_mapping(udc_controller->usb_irq); + free_irq(udc->usb_irq, udc); + irq_dispose_mapping(udc->usb_irq); - tasklet_kill(&udc_controller->rx_tasklet); + tasklet_kill(&udc->rx_tasklet); - iounmap(udc_controller->usb_regs); + iounmap(udc->usb_regs); - device_unregister(&udc_controller->gadget.dev); + device_unregister(&udc->gadget.dev); /* wait for release() of gadget.dev to free udc */ wait_for_completion(&done); diff --git a/trunk/drivers/usb/gadget/fsl_qe_udc.h b/trunk/drivers/usb/gadget/fsl_qe_udc.h index 1da5fb03d218..4c07ca9cebf3 100644 --- a/trunk/drivers/usb/gadget/fsl_qe_udc.h +++ b/trunk/drivers/usb/gadget/fsl_qe_udc.h @@ -266,7 +266,6 @@ struct qe_ep { struct usb_ep ep; struct list_head queue; struct qe_udc *udc; - const struct usb_endpoint_descriptor *desc; struct usb_gadget *gadget; u8 state; diff --git a/trunk/drivers/usb/gadget/fsl_udc_core.c b/trunk/drivers/usb/gadget/fsl_udc_core.c index 55abfb6bd612..28316858208b 100644 --- a/trunk/drivers/usb/gadget/fsl_udc_core.c +++ b/trunk/drivers/usb/gadget/fsl_udc_core.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007,2011 Freescale Semiconductor, Inc. + * Copyright (C) 2004-2007,2011-2012 Freescale Semiconductor, Inc. * All rights reserved. * * Author: Li Yang @@ -58,9 +58,8 @@ static const char driver_name[] = "fsl-usb2-udc"; static const char driver_desc[] = DRIVER_DESC; static struct usb_dr_device *dr_regs; -#ifndef CONFIG_ARCH_MXC + static struct usb_sys_interface *usb_sys_regs; -#endif /* it is initialized in probe() */ static struct fsl_udc *udc_controller = NULL; @@ -244,10 +243,9 @@ static int dr_controller_setup(struct fsl_udc *udc) { unsigned int tmp, portctrl, ep_num; unsigned int max_no_of_ep; -#ifndef CONFIG_ARCH_MXC unsigned int ctrl; -#endif unsigned long timeout; + #define FSL_UDC_RESET_TIMEOUT 1000 /* Config PHY interface */ @@ -255,12 +253,32 @@ static int dr_controller_setup(struct fsl_udc *udc) portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH); switch (udc->phy_mode) { case FSL_USB2_PHY_ULPI: + if (udc->pdata->have_sysif_regs) { + if (udc->pdata->controller_ver) { + /* controller version 1.6 or above */ + ctrl = __raw_readl(&usb_sys_regs->control); + ctrl &= ~USB_CTRL_UTMI_PHY_EN; + ctrl |= USB_CTRL_USB_EN; + __raw_writel(ctrl, &usb_sys_regs->control); + } + } portctrl |= PORTSCX_PTS_ULPI; break; case FSL_USB2_PHY_UTMI_WIDE: portctrl |= PORTSCX_PTW_16BIT; /* fall through */ case FSL_USB2_PHY_UTMI: + if (udc->pdata->have_sysif_regs) { + if (udc->pdata->controller_ver) { + /* controller version 1.6 or above */ + ctrl = __raw_readl(&usb_sys_regs->control); + ctrl |= (USB_CTRL_UTMI_PHY_EN | + USB_CTRL_USB_EN); + __raw_writel(ctrl, &usb_sys_regs->control); + mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI + PHY CLK to become stable - 10ms*/ + } + } portctrl |= PORTSCX_PTS_UTMI; break; case FSL_USB2_PHY_SERIAL: @@ -549,7 +567,7 @@ static int fsl_ep_enable(struct usb_ep *_ep, ep = container_of(_ep, struct fsl_ep, ep); /* catch various bogus parameters */ - if (!_ep || !desc || ep->desc + if (!_ep || !desc || ep->ep.desc || (desc->bDescriptorType != USB_DT_ENDPOINT)) return -EINVAL; @@ -590,7 +608,7 @@ static int fsl_ep_enable(struct usb_ep *_ep, spin_lock_irqsave(&udc->lock, flags); ep->ep.maxpacket = max; - ep->desc = desc; + ep->ep.desc = desc; ep->stopped = 0; /* Controller related setup */ @@ -614,7 +632,7 @@ static int fsl_ep_enable(struct usb_ep *_ep, retval = 0; VDBG("enabled %s (ep%d%s) maxpacket %d",ep->ep.name, - ep->desc->bEndpointAddress & 0x0f, + ep->ep.desc->bEndpointAddress & 0x0f, (desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out", max); en_done: @@ -634,7 +652,7 @@ static int fsl_ep_disable(struct usb_ep *_ep) int ep_num; ep = container_of(_ep, struct fsl_ep, ep); - if (!_ep || !ep->desc) { + if (!_ep || !ep->ep.desc) { VDBG("%s not enabled", _ep ? ep->ep.name : NULL); return -EINVAL; } @@ -657,7 +675,6 @@ static int fsl_ep_disable(struct usb_ep *_ep) /* nuke all pending requests (does flush) */ nuke(ep, -ESHUTDOWN); - ep->desc = NULL; ep->ep.desc = NULL; ep->stopped = 1; spin_unlock_irqrestore(&udc->lock, flags); @@ -736,6 +753,8 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req) lastreq = list_entry(ep->queue.prev, struct fsl_req, queue); lastreq->tail->next_td_ptr = cpu_to_hc32(req->head->td_dma & DTD_ADDR_MASK); + /* Ensure dTD's next dtd pointer to be updated */ + wmb(); /* Read prime bit, if 1 goto done */ if (fsl_readl(&dr_regs->endpointprime) & bitmask) return; @@ -874,11 +893,11 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) VDBG("%s, bad params", __func__); return -EINVAL; } - if (unlikely(!_ep || !ep->desc)) { + if (unlikely(!_ep || !ep->ep.desc)) { VDBG("%s, bad ep", __func__); return -EINVAL; } - if (usb_endpoint_xfer_isoc(ep->desc)) { + if (usb_endpoint_xfer_isoc(ep->ep.desc)) { if (req->req.length > ep->ep.maxpacket) return -EMSGSIZE; } @@ -1017,12 +1036,12 @@ static int fsl_ep_set_halt(struct usb_ep *_ep, int value) ep = container_of(_ep, struct fsl_ep, ep); udc = ep->udc; - if (!_ep || !ep->desc) { + if (!_ep || !ep->ep.desc) { status = -EINVAL; goto out; } - if (usb_endpoint_xfer_isoc(ep->desc)) { + if (usb_endpoint_xfer_isoc(ep->ep.desc)) { status = -EOPNOTSUPP; goto out; } @@ -1061,7 +1080,7 @@ static int fsl_ep_fifo_status(struct usb_ep *_ep) struct ep_queue_head *qh; ep = container_of(_ep, struct fsl_ep, ep); - if (!_ep || (!ep->desc && ep_index(ep) != 0)) + if (!_ep || (!ep->ep.desc && ep_index(ep) != 0)) return -ENODEV; udc = (struct fsl_udc *)ep->udc; @@ -1094,7 +1113,7 @@ static void fsl_ep_fifo_flush(struct usb_ep *_ep) return; } else { ep = container_of(_ep, struct fsl_ep, ep); - if (!ep->desc) + if (!ep->ep.desc) return; } ep_num = ep_index(ep); @@ -1349,7 +1368,7 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value, target_ep = get_ep_by_pipe(udc, get_pipe_by_windex(index)); /* stall if endpoint doesn't exist */ - if (!target_ep->desc) + if (!target_ep->ep.desc) goto stall; tmp = dr_ep_get_stall(ep_index(target_ep), ep_is_in(target_ep)) << USB_ENDPOINT_HALT; @@ -2259,7 +2278,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count, } /* other gadget->eplist ep */ list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { - if (ep->desc) { + if (ep->ep.desc) { t = scnprintf(next, size, "\nFor %s Maxpkt is 0x%x " "index is 0x%x\n", diff --git a/trunk/drivers/usb/gadget/fsl_usb2_udc.h b/trunk/drivers/usb/gadget/fsl_usb2_udc.h index e651469fd39b..5cd7b7e7ddb4 100644 --- a/trunk/drivers/usb/gadget/fsl_usb2_udc.h +++ b/trunk/drivers/usb/gadget/fsl_usb2_udc.h @@ -1,4 +1,12 @@ /* + * Copyright (C) 2004,2012 Freescale Semiconductor, Inc + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * * Freescale USB device/endpoint management registers */ #ifndef __FSL_USB2_UDC_H @@ -348,6 +356,9 @@ struct usb_sys_interface { /* control Register Bit Masks */ #define USB_CTRL_IOENB 0x00000004 #define USB_CTRL_ULPI_INT0EN 0x00000001 +#define USB_CTRL_UTMI_PHY_EN 0x00000200 +#define USB_CTRL_USB_EN 0x00000004 +#define USB_CTRL_ULPI_PHY_CLK_SEL 0x00000400 /* Endpoint Queue Head data struct * Rem: all the variables of qh are LittleEndian Mode @@ -450,7 +461,6 @@ struct fsl_ep { struct list_head queue; struct fsl_udc *udc; struct ep_queue_head *qh; - const struct usb_endpoint_descriptor *desc; struct usb_gadget *gadget; char name[14]; diff --git a/trunk/drivers/usb/gadget/fusb300_udc.c b/trunk/drivers/usb/gadget/fusb300_udc.c index 5831cb4a0b35..cdd94540e1cd 100644 --- a/trunk/drivers/usb/gadget/fusb300_udc.c +++ b/trunk/drivers/usb/gadget/fusb300_udc.c @@ -203,7 +203,7 @@ static int config_ep(struct fusb300_ep *ep, struct fusb300 *fusb300 = ep->fusb300; struct fusb300_ep_info info; - ep->desc = desc; + ep->ep.desc = desc; info.interval = 0; info.addrofs = 0; @@ -443,7 +443,7 @@ static int fusb300_queue(struct usb_ep *_ep, struct usb_request *_req, req->req.actual = 0; req->req.status = -EINPROGRESS; - if (ep->desc == NULL) /* ep0 */ + if (ep->ep.desc == NULL) /* ep0 */ ep0_queue(ep, req); else if (request && !ep->stall) enable_fifo_int(ep); diff --git a/trunk/drivers/usb/gadget/fusb300_udc.h b/trunk/drivers/usb/gadget/fusb300_udc.h index 92745bd03064..542cd83cc806 100644 --- a/trunk/drivers/usb/gadget/fusb300_udc.h +++ b/trunk/drivers/usb/gadget/fusb300_udc.h @@ -650,7 +650,6 @@ struct fusb300_ep { unsigned char epnum; unsigned char type; - const struct usb_endpoint_descriptor *desc; }; struct fusb300 { diff --git a/trunk/drivers/usb/gadget/g_ffs.c b/trunk/drivers/usb/gadget/g_ffs.c index a85eaf40b948..d3ace9002a6a 100644 --- a/trunk/drivers/usb/gadget/g_ffs.c +++ b/trunk/drivers/usb/gadget/g_ffs.c @@ -67,6 +67,15 @@ MODULE_LICENSE("GPL"); #define GFS_VENDOR_ID 0x1d6b /* Linux Foundation */ #define GFS_PRODUCT_ID 0x0105 /* FunctionFS Gadget */ +#define GFS_MAX_DEVS 10 + +struct gfs_ffs_obj { + const char *name; + bool mounted; + bool desc_ready; + struct ffs_data *ffs_data; +}; + static struct usb_device_descriptor gfs_dev_desc = { .bLength = sizeof gfs_dev_desc, .bDescriptorType = USB_DT_DEVICE, @@ -78,12 +87,17 @@ static struct usb_device_descriptor gfs_dev_desc = { .idProduct = cpu_to_le16(GFS_PRODUCT_ID), }; +static char *func_names[GFS_MAX_DEVS]; +static unsigned int func_num; + module_param_named(bDeviceClass, gfs_dev_desc.bDeviceClass, byte, 0644); MODULE_PARM_DESC(bDeviceClass, "USB Device class"); module_param_named(bDeviceSubClass, gfs_dev_desc.bDeviceSubClass, byte, 0644); MODULE_PARM_DESC(bDeviceSubClass, "USB Device subclass"); module_param_named(bDeviceProtocol, gfs_dev_desc.bDeviceProtocol, byte, 0644); MODULE_PARM_DESC(bDeviceProtocol, "USB Device protocol"); +module_param_array_named(functions, func_names, charp, &func_num, 0); +MODULE_PARM_DESC(functions, "USB Functions list"); static const struct usb_descriptor_header *gfs_otg_desc[] = { (const struct usb_descriptor_header *) @@ -158,13 +172,34 @@ static struct usb_composite_driver gfs_driver = { .iProduct = DRIVER_DESC, }; -static struct ffs_data *gfs_ffs_data; -static unsigned long gfs_registered; +static DEFINE_MUTEX(gfs_lock); +static unsigned int missing_funcs; +static bool gfs_ether_setup; +static bool gfs_registered; +static bool gfs_single_func; +static struct gfs_ffs_obj *ffs_tab; static int __init gfs_init(void) { + int i; + ENTER(); + if (!func_num) { + gfs_single_func = true; + func_num = 1; + } + + ffs_tab = kcalloc(func_num, sizeof *ffs_tab, GFP_KERNEL); + if (!ffs_tab) + return -ENOMEM; + + if (!gfs_single_func) + for (i = 0; i < func_num; i++) + ffs_tab[i].name = func_names[i]; + + missing_funcs = func_num; + return functionfs_init(); } module_init(gfs_init); @@ -172,63 +207,165 @@ module_init(gfs_init); static void __exit gfs_exit(void) { ENTER(); + mutex_lock(&gfs_lock); - if (test_and_clear_bit(0, &gfs_registered)) + if (gfs_registered) usb_composite_unregister(&gfs_driver); + gfs_registered = false; functionfs_cleanup(); + + mutex_unlock(&gfs_lock); + kfree(ffs_tab); } module_exit(gfs_exit); +static struct gfs_ffs_obj *gfs_find_dev(const char *dev_name) +{ + int i; + + ENTER(); + + if (gfs_single_func) + return &ffs_tab[0]; + + for (i = 0; i < func_num; i++) + if (strcmp(ffs_tab[i].name, dev_name) == 0) + return &ffs_tab[i]; + + return NULL; +} + static int functionfs_ready_callback(struct ffs_data *ffs) { + struct gfs_ffs_obj *ffs_obj; int ret; ENTER(); + mutex_lock(&gfs_lock); + + ffs_obj = ffs->private_data; + if (!ffs_obj) { + ret = -EINVAL; + goto done; + } + + if (WARN_ON(ffs_obj->desc_ready)) { + ret = -EBUSY; + goto done; + } + ffs_obj->desc_ready = true; + ffs_obj->ffs_data = ffs; - if (WARN_ON(test_and_set_bit(0, &gfs_registered))) - return -EBUSY; + if (--missing_funcs) { + ret = 0; + goto done; + } + + if (gfs_registered) { + ret = -EBUSY; + goto done; + } + gfs_registered = true; - gfs_ffs_data = ffs; ret = usb_composite_probe(&gfs_driver, gfs_bind); if (unlikely(ret < 0)) - clear_bit(0, &gfs_registered); + gfs_registered = false; + +done: + mutex_unlock(&gfs_lock); return ret; } static void functionfs_closed_callback(struct ffs_data *ffs) { + struct gfs_ffs_obj *ffs_obj; + ENTER(); + mutex_lock(&gfs_lock); - if (test_and_clear_bit(0, &gfs_registered)) + ffs_obj = ffs->private_data; + if (!ffs_obj) + goto done; + + ffs_obj->desc_ready = false; + missing_funcs++; + + if (gfs_registered) usb_composite_unregister(&gfs_driver); + gfs_registered = false; + +done: + mutex_unlock(&gfs_lock); } -static int functionfs_check_dev_callback(const char *dev_name) +static void *functionfs_acquire_dev_callback(const char *dev_name) { - return 0; + struct gfs_ffs_obj *ffs_dev; + + ENTER(); + mutex_lock(&gfs_lock); + + ffs_dev = gfs_find_dev(dev_name); + if (!ffs_dev) { + ffs_dev = ERR_PTR(-ENODEV); + goto done; + } + + if (ffs_dev->mounted) { + ffs_dev = ERR_PTR(-EBUSY); + goto done; + } + ffs_dev->mounted = true; + +done: + mutex_unlock(&gfs_lock); + return ffs_dev; } +static void functionfs_release_dev_callback(struct ffs_data *ffs_data) +{ + struct gfs_ffs_obj *ffs_dev; + + ENTER(); + mutex_lock(&gfs_lock); + + ffs_dev = ffs_data->private_data; + if (ffs_dev) + ffs_dev->mounted = false; + + mutex_unlock(&gfs_lock); +} + +/* + * It is assumed that gfs_bind is called from a context where gfs_lock is held + */ static int gfs_bind(struct usb_composite_dev *cdev) { int ret, i; ENTER(); - if (WARN_ON(!gfs_ffs_data)) + if (missing_funcs) return -ENODEV; ret = gether_setup(cdev->gadget, gfs_hostaddr); if (unlikely(ret < 0)) goto error_quick; + gfs_ether_setup = true; ret = usb_string_ids_tab(cdev, gfs_strings); if (unlikely(ret < 0)) goto error; - ret = functionfs_bind(gfs_ffs_data, cdev); - if (unlikely(ret < 0)) - goto error; + for (i = func_num; --i; ) { + ret = functionfs_bind(ffs_tab[i].ffs_data, cdev); + if (unlikely(ret < 0)) { + while (++i < func_num) + functionfs_unbind(ffs_tab[i].ffs_data); + goto error; + } + } for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) { struct gfs_configuration *c = gfs_configurations + i; @@ -246,16 +383,22 @@ static int gfs_bind(struct usb_composite_dev *cdev) return 0; error_unbind: - functionfs_unbind(gfs_ffs_data); + for (i = 0; i < func_num; i++) + functionfs_unbind(ffs_tab[i].ffs_data); error: gether_cleanup(); error_quick: - gfs_ffs_data = NULL; + gfs_ether_setup = false; return ret; } +/* + * It is assumed that gfs_unbind is called from a context where gfs_lock is held + */ static int gfs_unbind(struct usb_composite_dev *cdev) { + int i; + ENTER(); /* @@ -266,22 +409,29 @@ static int gfs_unbind(struct usb_composite_dev *cdev) * from composite on orror recovery, but what you're gonna * do...? */ - if (gfs_ffs_data) { + if (gfs_ether_setup) gether_cleanup(); - functionfs_unbind(gfs_ffs_data); - gfs_ffs_data = NULL; - } + gfs_ether_setup = false; + + for (i = func_num; --i; ) + if (ffs_tab[i].ffs_data) + functionfs_unbind(ffs_tab[i].ffs_data); return 0; } +/* + * It is assumed that gfs_do_config is called from a context where + * gfs_lock is held + */ static int gfs_do_config(struct usb_configuration *c) { struct gfs_configuration *gc = container_of(c, struct gfs_configuration, c); + int i; int ret; - if (WARN_ON(!gfs_ffs_data)) + if (missing_funcs) return -ENODEV; if (gadget_is_otg(c->cdev->gadget)) { @@ -295,9 +445,11 @@ static int gfs_do_config(struct usb_configuration *c) return ret; } - ret = functionfs_bind_config(c->cdev, c, gfs_ffs_data); - if (unlikely(ret < 0)) - return ret; + for (i = 0; i < func_num; i++) { + ret = functionfs_bind_config(c->cdev, c, ffs_tab[i].ffs_data); + if (unlikely(ret < 0)) + return ret; + } /* * After previous do_configs there may be some invalid diff --git a/trunk/drivers/usb/gadget/g_zero.h b/trunk/drivers/usb/gadget/g_zero.h index e84b3c47ed3c..71ca193358b8 100644 --- a/trunk/drivers/usb/gadget/g_zero.h +++ b/trunk/drivers/usb/gadget/g_zero.h @@ -13,10 +13,11 @@ extern unsigned buflen; extern const struct usb_descriptor_header *otg_desc[]; /* common utilities */ -struct usb_request *alloc_ep_req(struct usb_ep *ep); +struct usb_request *alloc_ep_req(struct usb_ep *ep, int len); void free_ep_req(struct usb_ep *ep, struct usb_request *req); void disable_endpoints(struct usb_composite_dev *cdev, - struct usb_ep *in, struct usb_ep *out); + struct usb_ep *in, struct usb_ep *out, + struct usb_ep *iso_in, struct usb_ep *iso_out); /* configuration-specific linkup */ int sourcesink_add(struct usb_composite_dev *cdev, bool autoresume); diff --git a/trunk/drivers/usb/gadget/gadget_chips.h b/trunk/drivers/usb/gadget/gadget_chips.h index a8855d0b7f3b..b8b3a3411218 100644 --- a/trunk/drivers/usb/gadget/gadget_chips.h +++ b/trunk/drivers/usb/gadget/gadget_chips.h @@ -37,6 +37,7 @@ #define gadget_is_goku(g) (!strcmp("goku_udc", (g)->name)) #define gadget_is_imx(g) (!strcmp("imx_udc", (g)->name)) #define gadget_is_langwell(g) (!strcmp("langwell_udc", (g)->name)) +#define gadget_is_lpc32xx(g) (!strcmp("lpc32xx_udc", (g)->name)) #define gadget_is_m66592(g) (!strcmp("m66592_udc", (g)->name)) #define gadget_is_musbhdrc(g) (!strcmp("musb-hdrc", (g)->name)) #define gadget_is_net2272(g) (!strcmp("net2272", (g)->name)) @@ -118,6 +119,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) return 0x31; else if (gadget_is_dwc3(gadget)) return 0x32; + else if (gadget_is_lpc32xx(gadget)) + return 0x33; return -ENOENT; } diff --git a/trunk/drivers/usb/gadget/goku_udc.c b/trunk/drivers/usb/gadget/goku_udc.c index e151d6b87dee..b241e6c6a7f2 100644 --- a/trunk/drivers/usb/gadget/goku_udc.c +++ b/trunk/drivers/usb/gadget/goku_udc.c @@ -102,7 +102,7 @@ goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) unsigned long flags; ep = container_of(_ep, struct goku_ep, ep); - if (!_ep || !desc || ep->desc + if (!_ep || !desc || ep->ep.desc || desc->bDescriptorType != USB_DT_ENDPOINT) return -EINVAL; dev = ep->dev; @@ -176,7 +176,7 @@ goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) command(ep->dev->regs, COMMAND_RESET, ep->num); ep->ep.maxpacket = max; ep->stopped = 0; - ep->desc = desc; + ep->ep.desc = desc; spin_unlock_irqrestore(&ep->dev->lock, flags); DBG(dev, "enable %s %s %s maxpacket %u\n", ep->ep.name, @@ -233,7 +233,6 @@ static void ep_reset(struct goku_udc_regs __iomem *regs, struct goku_ep *ep) } ep->ep.maxpacket = MAX_FIFO_SIZE; - ep->desc = NULL; ep->ep.desc = NULL; ep->stopped = 1; ep->irqs = 0; @@ -247,7 +246,7 @@ static int goku_ep_disable(struct usb_ep *_ep) unsigned long flags; ep = container_of(_ep, struct goku_ep, ep); - if (!_ep || !ep->desc) + if (!_ep || !ep->ep.desc) return -ENODEV; dev = ep->dev; if (dev->ep0state == EP0_SUSPEND) @@ -722,7 +721,7 @@ goku_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) || !_req->buf || !list_empty(&req->queue))) return -EINVAL; ep = container_of(_ep, struct goku_ep, ep); - if (unlikely(!_ep || (!ep->desc && ep->num != 0))) + if (unlikely(!_ep || (!ep->ep.desc && ep->num != 0))) return -EINVAL; dev = ep->dev; if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) @@ -815,7 +814,7 @@ static int goku_dequeue(struct usb_ep *_ep, struct usb_request *_req) unsigned long flags; ep = container_of(_ep, struct goku_ep, ep); - if (!_ep || !_req || (!ep->desc && ep->num != 0)) + if (!_ep || !_req || (!ep->ep.desc && ep->num != 0)) return -EINVAL; dev = ep->dev; if (!dev->driver) @@ -896,7 +895,7 @@ static int goku_set_halt(struct usb_ep *_ep, int value) return -EINVAL; /* don't change EPxSTATUS_EP_INVALID to READY */ - } else if (!ep->desc) { + } else if (!ep->ep.desc) { DBG(ep->dev, "%s %s inactive?\n", __func__, ep->ep.name); return -EINVAL; } @@ -955,7 +954,7 @@ static void goku_fifo_flush(struct usb_ep *_ep) VDBG(ep->dev, "%s %s\n", __func__, ep->ep.name); /* don't change EPxSTATUS_EP_INVALID to READY */ - if (!ep->desc && ep->num != 0) { + if (!ep->ep.desc && ep->num != 0) { DBG(ep->dev, "%s %s inactive?\n", __func__, ep->ep.name); return; } @@ -1152,7 +1151,7 @@ udc_proc_read(char *buffer, char **start, off_t off, int count, struct goku_ep *ep = &dev->ep [i]; struct goku_request *req; - if (i && !ep->desc) + if (i && !ep->ep.desc) continue; tmp = readl(ep->reg_status); @@ -1473,7 +1472,8 @@ static void ep0_setup(struct goku_udc *dev) case USB_RECIP_ENDPOINT: tmp = le16_to_cpu(ctrl.wIndex) & 0x0f; /* active endpoint */ - if (tmp > 3 || (!dev->ep[tmp].desc && tmp != 0)) + if (tmp > 3 || + (!dev->ep[tmp].ep.desc && tmp != 0)) goto stall; if (ctrl.wIndex & cpu_to_le16( USB_DIR_IN)) { @@ -1895,14 +1895,4 @@ static struct pci_driver goku_pci_driver = { /* FIXME add power management support */ }; -static int __init init (void) -{ - return pci_register_driver (&goku_pci_driver); -} -module_init (init); - -static void __exit cleanup (void) -{ - pci_unregister_driver (&goku_pci_driver); -} -module_exit (cleanup); +module_pci_driver(goku_pci_driver); diff --git a/trunk/drivers/usb/gadget/goku_udc.h b/trunk/drivers/usb/gadget/goku_udc.h index e7e0c69d3b1f..85cdce0d1901 100644 --- a/trunk/drivers/usb/gadget/goku_udc.h +++ b/trunk/drivers/usb/gadget/goku_udc.h @@ -216,7 +216,6 @@ struct goku_ep { /* analogous to a host-side qh */ struct list_head queue; - const struct usb_endpoint_descriptor *desc; u32 __iomem *reg_fifo; u32 __iomem *reg_mode; diff --git a/trunk/drivers/usb/gadget/imx_udc.c b/trunk/drivers/usb/gadget/imx_udc.c index 8d1c75abd73d..54034f84f992 100644 --- a/trunk/drivers/usb/gadget/imx_udc.c +++ b/trunk/drivers/usb/gadget/imx_udc.c @@ -1237,14 +1237,15 @@ irq_handler_t intr_handler(int i) ******************************************************************************* */ -static int imx_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int imx_udc_stop(struct usb_gadget_driver *driver); +static int imx_udc_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver); +static int imx_udc_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver); static const struct usb_gadget_ops imx_udc_ops = { - .get_frame = imx_udc_get_frame, - .wakeup = imx_udc_wakeup, - .start = imx_udc_start, - .stop = imx_udc_stop, + .get_frame = imx_udc_get_frame, + .wakeup = imx_udc_wakeup, + .udc_start = imx_udc_start, + .udc_stop = imx_udc_stop, }; static struct imx_udc_struct controller = { @@ -1329,23 +1330,13 @@ static struct imx_udc_struct controller = { * USB gadget driver functions ******************************************************************************* */ -static int imx_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) +static int imx_udc_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { - struct imx_udc_struct *imx_usb = &controller; + struct imx_udc_struct *imx_usb; int retval; - if (!driver - || driver->max_speed < USB_SPEED_FULL - || !bind - || !driver->disconnect - || !driver->setup) - return -EINVAL; - if (!imx_usb) - return -ENODEV; - if (imx_usb->driver) - return -EBUSY; - + imx_usb = container_of(gadget, struct imx_udc_struct, gadget); /* first hook up the driver ... */ imx_usb->driver = driver; imx_usb->gadget.dev.driver = &driver->driver; @@ -1353,14 +1344,6 @@ static int imx_udc_start(struct usb_gadget_driver *driver, retval = device_add(&imx_usb->gadget.dev); if (retval) goto fail; - retval = bind(&imx_usb->gadget); - if (retval) { - D_ERR(imx_usb->dev, "<%s> bind to driver %s --> error %d\n", - __func__, driver->driver.name, retval); - device_del(&imx_usb->gadget.dev); - - goto fail; - } D_INI(imx_usb->dev, "<%s> registered gadget driver '%s'\n", __func__, driver->driver.name); @@ -1374,20 +1357,16 @@ static int imx_udc_start(struct usb_gadget_driver *driver, return retval; } -static int imx_udc_stop(struct usb_gadget_driver *driver) +static int imx_udc_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { - struct imx_udc_struct *imx_usb = &controller; - - if (!imx_usb) - return -ENODEV; - if (!driver || driver != imx_usb->driver || !driver->unbind) - return -EINVAL; + struct imx_udc_struct *imx_usb = container_of(gadget, + struct imx_udc_struct, gadget); udc_stop_activity(imx_usb, driver); imx_udc_disable(imx_usb); del_timer(&imx_usb->timer); - driver->unbind(&imx_usb->gadget); imx_usb->gadget.dev.driver = NULL; imx_usb->driver = NULL; diff --git a/trunk/drivers/usb/gadget/langwell_udc.c b/trunk/drivers/usb/gadget/langwell_udc.c deleted file mode 100644 index f9cedd52cf20..000000000000 --- a/trunk/drivers/usb/gadget/langwell_udc.c +++ /dev/null @@ -1,3434 +0,0 @@ -/* - * Intel Langwell USB Device Controller driver - * Copyright (C) 2008-2009, 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. - */ - - -/* #undef DEBUG */ -/* #undef VERBOSE_DEBUG */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "langwell_udc.h" - - -#define DRIVER_DESC "Intel Langwell USB Device Controller driver" -#define DRIVER_VERSION "16 May 2009" - -static const char driver_name[] = "langwell_udc"; -static const char driver_desc[] = DRIVER_DESC; - - -/* for endpoint 0 operations */ -static const struct usb_endpoint_descriptor -langwell_ep0_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 0, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, - .wMaxPacketSize = EP0_MAX_PKT_SIZE, -}; - - -/*-------------------------------------------------------------------------*/ -/* debugging */ - -#ifdef VERBOSE_DEBUG -static inline void print_all_registers(struct langwell_udc *dev) -{ - int i; - - /* Capability Registers */ - dev_dbg(&dev->pdev->dev, - "Capability Registers (offset: 0x%04x, length: 0x%08x)\n", - CAP_REG_OFFSET, (u32)sizeof(struct langwell_cap_regs)); - dev_dbg(&dev->pdev->dev, "caplength=0x%02x\n", - readb(&dev->cap_regs->caplength)); - dev_dbg(&dev->pdev->dev, "hciversion=0x%04x\n", - readw(&dev->cap_regs->hciversion)); - dev_dbg(&dev->pdev->dev, "hcsparams=0x%08x\n", - readl(&dev->cap_regs->hcsparams)); - dev_dbg(&dev->pdev->dev, "hccparams=0x%08x\n", - readl(&dev->cap_regs->hccparams)); - dev_dbg(&dev->pdev->dev, "dciversion=0x%04x\n", - readw(&dev->cap_regs->dciversion)); - dev_dbg(&dev->pdev->dev, "dccparams=0x%08x\n", - readl(&dev->cap_regs->dccparams)); - - /* Operational Registers */ - dev_dbg(&dev->pdev->dev, - "Operational Registers (offset: 0x%04x, length: 0x%08x)\n", - OP_REG_OFFSET, (u32)sizeof(struct langwell_op_regs)); - dev_dbg(&dev->pdev->dev, "extsts=0x%08x\n", - readl(&dev->op_regs->extsts)); - dev_dbg(&dev->pdev->dev, "extintr=0x%08x\n", - readl(&dev->op_regs->extintr)); - dev_dbg(&dev->pdev->dev, "usbcmd=0x%08x\n", - readl(&dev->op_regs->usbcmd)); - dev_dbg(&dev->pdev->dev, "usbsts=0x%08x\n", - readl(&dev->op_regs->usbsts)); - dev_dbg(&dev->pdev->dev, "usbintr=0x%08x\n", - readl(&dev->op_regs->usbintr)); - dev_dbg(&dev->pdev->dev, "frindex=0x%08x\n", - readl(&dev->op_regs->frindex)); - dev_dbg(&dev->pdev->dev, "ctrldssegment=0x%08x\n", - readl(&dev->op_regs->ctrldssegment)); - dev_dbg(&dev->pdev->dev, "deviceaddr=0x%08x\n", - readl(&dev->op_regs->deviceaddr)); - dev_dbg(&dev->pdev->dev, "endpointlistaddr=0x%08x\n", - readl(&dev->op_regs->endpointlistaddr)); - dev_dbg(&dev->pdev->dev, "ttctrl=0x%08x\n", - readl(&dev->op_regs->ttctrl)); - dev_dbg(&dev->pdev->dev, "burstsize=0x%08x\n", - readl(&dev->op_regs->burstsize)); - dev_dbg(&dev->pdev->dev, "txfilltuning=0x%08x\n", - readl(&dev->op_regs->txfilltuning)); - dev_dbg(&dev->pdev->dev, "txttfilltuning=0x%08x\n", - readl(&dev->op_regs->txttfilltuning)); - dev_dbg(&dev->pdev->dev, "ic_usb=0x%08x\n", - readl(&dev->op_regs->ic_usb)); - dev_dbg(&dev->pdev->dev, "ulpi_viewport=0x%08x\n", - readl(&dev->op_regs->ulpi_viewport)); - dev_dbg(&dev->pdev->dev, "configflag=0x%08x\n", - readl(&dev->op_regs->configflag)); - dev_dbg(&dev->pdev->dev, "portsc1=0x%08x\n", - readl(&dev->op_regs->portsc1)); - dev_dbg(&dev->pdev->dev, "devlc=0x%08x\n", - readl(&dev->op_regs->devlc)); - dev_dbg(&dev->pdev->dev, "otgsc=0x%08x\n", - readl(&dev->op_regs->otgsc)); - dev_dbg(&dev->pdev->dev, "usbmode=0x%08x\n", - readl(&dev->op_regs->usbmode)); - dev_dbg(&dev->pdev->dev, "endptnak=0x%08x\n", - readl(&dev->op_regs->endptnak)); - dev_dbg(&dev->pdev->dev, "endptnaken=0x%08x\n", - readl(&dev->op_regs->endptnaken)); - dev_dbg(&dev->pdev->dev, "endptsetupstat=0x%08x\n", - readl(&dev->op_regs->endptsetupstat)); - dev_dbg(&dev->pdev->dev, "endptprime=0x%08x\n", - readl(&dev->op_regs->endptprime)); - dev_dbg(&dev->pdev->dev, "endptflush=0x%08x\n", - readl(&dev->op_regs->endptflush)); - dev_dbg(&dev->pdev->dev, "endptstat=0x%08x\n", - readl(&dev->op_regs->endptstat)); - dev_dbg(&dev->pdev->dev, "endptcomplete=0x%08x\n", - readl(&dev->op_regs->endptcomplete)); - - for (i = 0; i < dev->ep_max / 2; i++) { - dev_dbg(&dev->pdev->dev, "endptctrl[%d]=0x%08x\n", - i, readl(&dev->op_regs->endptctrl[i])); - } -} -#else - -#define print_all_registers(dev) do { } while (0) - -#endif /* VERBOSE_DEBUG */ - - -/*-------------------------------------------------------------------------*/ - -#define is_in(ep) (((ep)->ep_num == 0) ? ((ep)->dev->ep0_dir == \ - USB_DIR_IN) : (usb_endpoint_dir_in((ep)->desc))) - -#define DIR_STRING(ep) (is_in(ep) ? "in" : "out") - - -static char *type_string(const struct usb_endpoint_descriptor *desc) -{ - switch (usb_endpoint_type(desc)) { - case USB_ENDPOINT_XFER_BULK: - return "bulk"; - case USB_ENDPOINT_XFER_ISOC: - return "iso"; - case USB_ENDPOINT_XFER_INT: - return "int"; - }; - - return "control"; -} - - -/* configure endpoint control registers */ -static void ep_reset(struct langwell_ep *ep, unsigned char ep_num, - unsigned char is_in, unsigned char ep_type) -{ - struct langwell_udc *dev; - u32 endptctrl; - - dev = ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - endptctrl = readl(&dev->op_regs->endptctrl[ep_num]); - if (is_in) { /* TX */ - if (ep_num) - endptctrl |= EPCTRL_TXR; - endptctrl |= EPCTRL_TXE; - endptctrl |= ep_type << EPCTRL_TXT_SHIFT; - } else { /* RX */ - if (ep_num) - endptctrl |= EPCTRL_RXR; - endptctrl |= EPCTRL_RXE; - endptctrl |= ep_type << EPCTRL_RXT_SHIFT; - } - - writel(endptctrl, &dev->op_regs->endptctrl[ep_num]); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* reset ep0 dQH and endptctrl */ -static void ep0_reset(struct langwell_udc *dev) -{ - struct langwell_ep *ep; - int i; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* ep0 in and out */ - for (i = 0; i < 2; i++) { - ep = &dev->ep[i]; - ep->dev = dev; - - /* ep0 dQH */ - ep->dqh = &dev->ep_dqh[i]; - - /* configure ep0 endpoint capabilities in dQH */ - ep->dqh->dqh_ios = 1; - ep->dqh->dqh_mpl = EP0_MAX_PKT_SIZE; - - /* enable ep0-in HW zero length termination select */ - if (is_in(ep)) - ep->dqh->dqh_zlt = 0; - ep->dqh->dqh_mult = 0; - - ep->dqh->dtd_next = DTD_TERM; - - /* configure ep0 control registers */ - ep_reset(&dev->ep[0], 0, i, USB_ENDPOINT_XFER_CONTROL); - } - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/*-------------------------------------------------------------------------*/ - -/* endpoints operations */ - -/* configure endpoint, making it usable */ -static int langwell_ep_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct langwell_udc *dev; - struct langwell_ep *ep; - u16 max = 0; - unsigned long flags; - int i, retval = 0; - unsigned char zlt, ios = 0, mult = 0; - - ep = container_of(_ep, struct langwell_ep, ep); - dev = ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (!_ep || !desc || ep->desc - || desc->bDescriptorType != USB_DT_ENDPOINT) - return -EINVAL; - - if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - max = usb_endpoint_maxp(desc); - - /* - * disable HW zero length termination select - * driver handles zero length packet through req->req.zero - */ - zlt = 1; - - /* - * sanity check type, direction, address, and then - * initialize the endpoint capabilities fields in dQH - */ - switch (usb_endpoint_type(desc)) { - case USB_ENDPOINT_XFER_CONTROL: - ios = 1; - break; - case USB_ENDPOINT_XFER_BULK: - if ((dev->gadget.speed == USB_SPEED_HIGH - && max != 512) - || (dev->gadget.speed == USB_SPEED_FULL - && max > 64)) { - goto done; - } - break; - case USB_ENDPOINT_XFER_INT: - if (strstr(ep->ep.name, "-iso")) /* bulk is ok */ - goto done; - - switch (dev->gadget.speed) { - case USB_SPEED_HIGH: - if (max <= 1024) - break; - case USB_SPEED_FULL: - if (max <= 64) - break; - default: - if (max <= 8) - break; - goto done; - } - break; - case USB_ENDPOINT_XFER_ISOC: - if (strstr(ep->ep.name, "-bulk") - || strstr(ep->ep.name, "-int")) - goto done; - - switch (dev->gadget.speed) { - case USB_SPEED_HIGH: - if (max <= 1024) - break; - case USB_SPEED_FULL: - if (max <= 1023) - break; - default: - goto done; - } - /* - * FIXME: - * calculate transactions needed for high bandwidth iso - */ - mult = (unsigned char)(1 + ((max >> 11) & 0x03)); - max = max & 0x8ff; /* bit 0~10 */ - /* 3 transactions at most */ - if (mult > 3) - goto done; - break; - default: - goto done; - } - - spin_lock_irqsave(&dev->lock, flags); - - ep->ep.maxpacket = max; - ep->desc = desc; - ep->stopped = 0; - ep->ep_num = usb_endpoint_num(desc); - - /* ep_type */ - ep->ep_type = usb_endpoint_type(desc); - - /* configure endpoint control registers */ - ep_reset(ep, ep->ep_num, is_in(ep), ep->ep_type); - - /* configure endpoint capabilities in dQH */ - i = ep->ep_num * 2 + is_in(ep); - ep->dqh = &dev->ep_dqh[i]; - ep->dqh->dqh_ios = ios; - ep->dqh->dqh_mpl = cpu_to_le16(max); - ep->dqh->dqh_zlt = zlt; - ep->dqh->dqh_mult = mult; - ep->dqh->dtd_next = DTD_TERM; - - dev_dbg(&dev->pdev->dev, "enabled %s (ep%d%s-%s), max %04x\n", - _ep->name, - ep->ep_num, - DIR_STRING(ep), - type_string(desc), - max); - - spin_unlock_irqrestore(&dev->lock, flags); -done: - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return retval; -} - - -/*-------------------------------------------------------------------------*/ - -/* retire a request */ -static void done(struct langwell_ep *ep, struct langwell_request *req, - int status) -{ - struct langwell_udc *dev = ep->dev; - unsigned stopped = ep->stopped; - struct langwell_dtd *curr_dtd, *next_dtd; - int i; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* remove the req from ep->queue */ - list_del_init(&req->queue); - - if (req->req.status == -EINPROGRESS) - req->req.status = status; - else - status = req->req.status; - - /* free dTD for the request */ - next_dtd = req->head; - for (i = 0; i < req->dtd_count; i++) { - curr_dtd = next_dtd; - if (i != req->dtd_count - 1) - next_dtd = curr_dtd->next_dtd_virt; - dma_pool_free(dev->dtd_pool, curr_dtd, curr_dtd->dtd_dma); - } - - usb_gadget_unmap_request(&dev->gadget, &req->req, is_in(ep)); - - if (status != -ESHUTDOWN) - dev_dbg(&dev->pdev->dev, - "complete %s, req %p, stat %d, len %u/%u\n", - ep->ep.name, &req->req, status, - req->req.actual, req->req.length); - - /* don't modify queue heads during completion callback */ - ep->stopped = 1; - - spin_unlock(&dev->lock); - /* complete routine from gadget driver */ - if (req->req.complete) - req->req.complete(&ep->ep, &req->req); - - spin_lock(&dev->lock); - ep->stopped = stopped; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -static void langwell_ep_fifo_flush(struct usb_ep *_ep); - -/* delete all endpoint requests, called with spinlock held */ -static void nuke(struct langwell_ep *ep, int status) -{ - /* called with spinlock held */ - ep->stopped = 1; - - /* endpoint fifo flush */ - if (&ep->ep && ep->desc) - langwell_ep_fifo_flush(&ep->ep); - - while (!list_empty(&ep->queue)) { - struct langwell_request *req = NULL; - req = list_entry(ep->queue.next, struct langwell_request, - queue); - done(ep, req, status); - } -} - - -/*-------------------------------------------------------------------------*/ - -/* endpoint is no longer usable */ -static int langwell_ep_disable(struct usb_ep *_ep) -{ - struct langwell_ep *ep; - unsigned long flags; - struct langwell_udc *dev; - int ep_num; - u32 endptctrl; - - ep = container_of(_ep, struct langwell_ep, ep); - dev = ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (!_ep || !ep->desc) - return -EINVAL; - - spin_lock_irqsave(&dev->lock, flags); - - /* disable endpoint control register */ - ep_num = ep->ep_num; - endptctrl = readl(&dev->op_regs->endptctrl[ep_num]); - if (is_in(ep)) - endptctrl &= ~EPCTRL_TXE; - else - endptctrl &= ~EPCTRL_RXE; - writel(endptctrl, &dev->op_regs->endptctrl[ep_num]); - - /* nuke all pending requests (does flush) */ - nuke(ep, -ESHUTDOWN); - - ep->desc = NULL; - ep->ep.desc = NULL; - ep->stopped = 1; - - spin_unlock_irqrestore(&dev->lock, flags); - - dev_dbg(&dev->pdev->dev, "disabled %s\n", _ep->name); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - - return 0; -} - - -/* allocate a request object to use with this endpoint */ -static struct usb_request *langwell_alloc_request(struct usb_ep *_ep, - gfp_t gfp_flags) -{ - struct langwell_ep *ep; - struct langwell_udc *dev; - struct langwell_request *req = NULL; - - if (!_ep) - return NULL; - - ep = container_of(_ep, struct langwell_ep, ep); - dev = ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - req = kzalloc(sizeof(*req), gfp_flags); - if (!req) - return NULL; - - req->req.dma = DMA_ADDR_INVALID; - INIT_LIST_HEAD(&req->queue); - - dev_vdbg(&dev->pdev->dev, "alloc request for %s\n", _ep->name); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return &req->req; -} - - -/* free a request object */ -static void langwell_free_request(struct usb_ep *_ep, - struct usb_request *_req) -{ - struct langwell_ep *ep; - struct langwell_udc *dev; - struct langwell_request *req = NULL; - - ep = container_of(_ep, struct langwell_ep, ep); - dev = ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (!_ep || !_req) - return; - - req = container_of(_req, struct langwell_request, req); - WARN_ON(!list_empty(&req->queue)); - - if (_req) - kfree(req); - - dev_vdbg(&dev->pdev->dev, "free request for %s\n", _ep->name); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/*-------------------------------------------------------------------------*/ - -/* queue dTD and PRIME endpoint */ -static int queue_dtd(struct langwell_ep *ep, struct langwell_request *req) -{ - u32 bit_mask, usbcmd, endptstat, dtd_dma; - u8 dtd_status; - int i; - struct langwell_dqh *dqh; - struct langwell_udc *dev; - - dev = ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - i = ep->ep_num * 2 + is_in(ep); - dqh = &dev->ep_dqh[i]; - - if (ep->ep_num) - dev_vdbg(&dev->pdev->dev, "%s\n", ep->name); - else - /* ep0 */ - dev_vdbg(&dev->pdev->dev, "%s-%s\n", ep->name, DIR_STRING(ep)); - - dev_vdbg(&dev->pdev->dev, "ep_dqh[%d] addr: 0x%p\n", - i, &(dev->ep_dqh[i])); - - bit_mask = is_in(ep) ? - (1 << (ep->ep_num + 16)) : (1 << (ep->ep_num)); - - dev_vdbg(&dev->pdev->dev, "bit_mask = 0x%08x\n", bit_mask); - - /* check if the pipe is empty */ - if (!(list_empty(&ep->queue))) { - /* add dTD to the end of linked list */ - struct langwell_request *lastreq; - lastreq = list_entry(ep->queue.prev, - struct langwell_request, queue); - - lastreq->tail->dtd_next = - cpu_to_le32(req->head->dtd_dma & DTD_NEXT_MASK); - - /* read prime bit, if 1 goto out */ - if (readl(&dev->op_regs->endptprime) & bit_mask) - goto out; - - do { - /* set ATDTW bit in USBCMD */ - usbcmd = readl(&dev->op_regs->usbcmd); - writel(usbcmd | CMD_ATDTW, &dev->op_regs->usbcmd); - - /* read correct status bit */ - endptstat = readl(&dev->op_regs->endptstat) & bit_mask; - - } while (!(readl(&dev->op_regs->usbcmd) & CMD_ATDTW)); - - /* write ATDTW bit to 0 */ - usbcmd = readl(&dev->op_regs->usbcmd); - writel(usbcmd & ~CMD_ATDTW, &dev->op_regs->usbcmd); - - if (endptstat) - goto out; - } - - /* write dQH next pointer and terminate bit to 0 */ - dtd_dma = req->head->dtd_dma & DTD_NEXT_MASK; - dqh->dtd_next = cpu_to_le32(dtd_dma); - - /* clear active and halt bit */ - dtd_status = (u8) ~(DTD_STS_ACTIVE | DTD_STS_HALTED); - dqh->dtd_status &= dtd_status; - dev_vdbg(&dev->pdev->dev, "dqh->dtd_status = 0x%x\n", dqh->dtd_status); - - /* ensure that updates to the dQH will occur before priming */ - wmb(); - - /* write 1 to endptprime register to PRIME endpoint */ - bit_mask = is_in(ep) ? (1 << (ep->ep_num + 16)) : (1 << ep->ep_num); - dev_vdbg(&dev->pdev->dev, "endprime bit_mask = 0x%08x\n", bit_mask); - writel(bit_mask, &dev->op_regs->endptprime); -out: - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* fill in the dTD structure to build a transfer descriptor */ -static struct langwell_dtd *build_dtd(struct langwell_request *req, - unsigned *length, dma_addr_t *dma, int *is_last) -{ - u32 buf_ptr; - struct langwell_dtd *dtd; - struct langwell_udc *dev; - int i; - - dev = req->ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* the maximum transfer length, up to 16k bytes */ - *length = min(req->req.length - req->req.actual, - (unsigned)DTD_MAX_TRANSFER_LENGTH); - - /* create dTD dma_pool resource */ - dtd = dma_pool_alloc(dev->dtd_pool, GFP_KERNEL, dma); - if (dtd == NULL) - return dtd; - dtd->dtd_dma = *dma; - - /* initialize buffer page pointers */ - buf_ptr = (u32)(req->req.dma + req->req.actual); - for (i = 0; i < 5; i++) - dtd->dtd_buf[i] = cpu_to_le32(buf_ptr + i * PAGE_SIZE); - - req->req.actual += *length; - - /* fill in total bytes with transfer size */ - dtd->dtd_total = cpu_to_le16(*length); - dev_vdbg(&dev->pdev->dev, "dtd->dtd_total = %d\n", dtd->dtd_total); - - /* set is_last flag if req->req.zero is set or not */ - if (req->req.zero) { - if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0) - *is_last = 1; - else - *is_last = 0; - } else if (req->req.length == req->req.actual) { - *is_last = 1; - } else - *is_last = 0; - - if (*is_last == 0) - dev_vdbg(&dev->pdev->dev, "multi-dtd request!\n"); - - /* set interrupt on complete bit for the last dTD */ - if (*is_last && !req->req.no_interrupt) - dtd->dtd_ioc = 1; - - /* set multiplier override 0 for non-ISO and non-TX endpoint */ - dtd->dtd_multo = 0; - - /* set the active bit of status field to 1 */ - dtd->dtd_status = DTD_STS_ACTIVE; - dev_vdbg(&dev->pdev->dev, "dtd->dtd_status = 0x%02x\n", - dtd->dtd_status); - - dev_vdbg(&dev->pdev->dev, "length = %d, dma addr= 0x%08x\n", - *length, (int)*dma); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return dtd; -} - - -/* generate dTD linked list for a request */ -static int req_to_dtd(struct langwell_request *req) -{ - unsigned count; - int is_last, is_first = 1; - struct langwell_dtd *dtd, *last_dtd = NULL; - struct langwell_udc *dev; - dma_addr_t dma; - - dev = req->ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - do { - dtd = build_dtd(req, &count, &dma, &is_last); - if (dtd == NULL) - return -ENOMEM; - - if (is_first) { - is_first = 0; - req->head = dtd; - } else { - last_dtd->dtd_next = cpu_to_le32(dma); - last_dtd->next_dtd_virt = dtd; - } - last_dtd = dtd; - req->dtd_count++; - } while (!is_last); - - /* set terminate bit to 1 for the last dTD */ - dtd->dtd_next = DTD_TERM; - - req->tail = dtd; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* queue (submits) an I/O requests to an endpoint */ -static int langwell_ep_queue(struct usb_ep *_ep, struct usb_request *_req, - gfp_t gfp_flags) -{ - struct langwell_request *req; - struct langwell_ep *ep; - struct langwell_udc *dev; - unsigned long flags; - int is_iso = 0; - int ret; - - /* always require a cpu-view buffer */ - req = container_of(_req, struct langwell_request, req); - ep = container_of(_ep, struct langwell_ep, ep); - - if (!_req || !_req->complete || !_req->buf - || !list_empty(&req->queue)) { - return -EINVAL; - } - - if (unlikely(!_ep || !ep->desc)) - return -EINVAL; - - dev = ep->dev; - req->ep = ep; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (usb_endpoint_xfer_isoc(ep->desc)) { - if (req->req.length > ep->ep.maxpacket) - return -EMSGSIZE; - is_iso = 1; - } - - if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) - return -ESHUTDOWN; - - /* set up dma mapping */ - ret = usb_gadget_map_request(&dev->gadget, &req->req, is_in(ep)); - if (ret) - return ret; - - dev_dbg(&dev->pdev->dev, - "%s queue req %p, len %u, buf %p, dma 0x%08x\n", - _ep->name, - _req, _req->length, _req->buf, (int)_req->dma); - - _req->status = -EINPROGRESS; - _req->actual = 0; - req->dtd_count = 0; - - spin_lock_irqsave(&dev->lock, flags); - - /* build and put dTDs to endpoint queue */ - if (!req_to_dtd(req)) { - queue_dtd(ep, req); - } else { - spin_unlock_irqrestore(&dev->lock, flags); - return -ENOMEM; - } - - /* update ep0 state */ - if (ep->ep_num == 0) - dev->ep0_state = DATA_STATE_XMIT; - - if (likely(req != NULL)) { - list_add_tail(&req->queue, &ep->queue); - dev_vdbg(&dev->pdev->dev, "list_add_tail()\n"); - } - - spin_unlock_irqrestore(&dev->lock, flags); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* dequeue (cancels, unlinks) an I/O request from an endpoint */ -static int langwell_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct langwell_ep *ep; - struct langwell_udc *dev; - struct langwell_request *req; - unsigned long flags; - int stopped, ep_num, retval = 0; - u32 endptctrl; - - ep = container_of(_ep, struct langwell_ep, ep); - dev = ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (!_ep || !ep->desc || !_req) - return -EINVAL; - - if (!dev->driver) - return -ESHUTDOWN; - - spin_lock_irqsave(&dev->lock, flags); - stopped = ep->stopped; - - /* quiesce dma while we patch the queue */ - ep->stopped = 1; - ep_num = ep->ep_num; - - /* disable endpoint control register */ - endptctrl = readl(&dev->op_regs->endptctrl[ep_num]); - if (is_in(ep)) - endptctrl &= ~EPCTRL_TXE; - else - endptctrl &= ~EPCTRL_RXE; - writel(endptctrl, &dev->op_regs->endptctrl[ep_num]); - - /* make sure it's still queued on this endpoint */ - list_for_each_entry(req, &ep->queue, queue) { - if (&req->req == _req) - break; - } - - if (&req->req != _req) { - retval = -EINVAL; - goto done; - } - - /* queue head may be partially complete. */ - if (ep->queue.next == &req->queue) { - dev_dbg(&dev->pdev->dev, "unlink (%s) dma\n", _ep->name); - _req->status = -ECONNRESET; - langwell_ep_fifo_flush(&ep->ep); - - /* not the last request in endpoint queue */ - if (likely(ep->queue.next == &req->queue)) { - struct langwell_dqh *dqh; - struct langwell_request *next_req; - - dqh = ep->dqh; - next_req = list_entry(req->queue.next, - struct langwell_request, queue); - - /* point the dQH to the first dTD of next request */ - writel((u32) next_req->head, &dqh->dqh_current); - } - } else { - struct langwell_request *prev_req; - - prev_req = list_entry(req->queue.prev, - struct langwell_request, queue); - writel(readl(&req->tail->dtd_next), - &prev_req->tail->dtd_next); - } - - done(ep, req, -ECONNRESET); - -done: - /* enable endpoint again */ - endptctrl = readl(&dev->op_regs->endptctrl[ep_num]); - if (is_in(ep)) - endptctrl |= EPCTRL_TXE; - else - endptctrl |= EPCTRL_RXE; - writel(endptctrl, &dev->op_regs->endptctrl[ep_num]); - - ep->stopped = stopped; - spin_unlock_irqrestore(&dev->lock, flags); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return retval; -} - - -/*-------------------------------------------------------------------------*/ - -/* endpoint set/clear halt */ -static void ep_set_halt(struct langwell_ep *ep, int value) -{ - u32 endptctrl = 0; - int ep_num; - struct langwell_udc *dev = ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - ep_num = ep->ep_num; - endptctrl = readl(&dev->op_regs->endptctrl[ep_num]); - - /* value: 1 - set halt, 0 - clear halt */ - if (value) { - /* set the stall bit */ - if (is_in(ep)) - endptctrl |= EPCTRL_TXS; - else - endptctrl |= EPCTRL_RXS; - } else { - /* clear the stall bit and reset data toggle */ - if (is_in(ep)) { - endptctrl &= ~EPCTRL_TXS; - endptctrl |= EPCTRL_TXR; - } else { - endptctrl &= ~EPCTRL_RXS; - endptctrl |= EPCTRL_RXR; - } - } - - writel(endptctrl, &dev->op_regs->endptctrl[ep_num]); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* set the endpoint halt feature */ -static int langwell_ep_set_halt(struct usb_ep *_ep, int value) -{ - struct langwell_ep *ep; - struct langwell_udc *dev; - unsigned long flags; - int retval = 0; - - ep = container_of(_ep, struct langwell_ep, ep); - dev = ep->dev; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (!_ep || !ep->desc) - return -EINVAL; - - if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - if (usb_endpoint_xfer_isoc(ep->desc)) - return -EOPNOTSUPP; - - spin_lock_irqsave(&dev->lock, flags); - - /* - * attempt to halt IN ep will fail if any transfer requests - * are still queue - */ - if (!list_empty(&ep->queue) && is_in(ep) && value) { - /* IN endpoint FIFO holds bytes */ - dev_dbg(&dev->pdev->dev, "%s FIFO holds bytes\n", _ep->name); - retval = -EAGAIN; - goto done; - } - - /* endpoint set/clear halt */ - if (ep->ep_num) { - ep_set_halt(ep, value); - } else { /* endpoint 0 */ - dev->ep0_state = WAIT_FOR_SETUP; - dev->ep0_dir = USB_DIR_OUT; - } -done: - spin_unlock_irqrestore(&dev->lock, flags); - dev_dbg(&dev->pdev->dev, "%s %s halt\n", - _ep->name, value ? "set" : "clear"); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return retval; -} - - -/* set the halt feature and ignores clear requests */ -static int langwell_ep_set_wedge(struct usb_ep *_ep) -{ - struct langwell_ep *ep; - struct langwell_udc *dev; - - ep = container_of(_ep, struct langwell_ep, ep); - dev = ep->dev; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (!_ep || !ep->desc) - return -EINVAL; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return usb_ep_set_halt(_ep); -} - - -/* flush contents of a fifo */ -static void langwell_ep_fifo_flush(struct usb_ep *_ep) -{ - struct langwell_ep *ep; - struct langwell_udc *dev; - u32 flush_bit; - unsigned long timeout; - - ep = container_of(_ep, struct langwell_ep, ep); - dev = ep->dev; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (!_ep || !ep->desc) { - dev_vdbg(&dev->pdev->dev, "ep or ep->desc is NULL\n"); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return; - } - - dev_vdbg(&dev->pdev->dev, "%s-%s fifo flush\n", - _ep->name, DIR_STRING(ep)); - - /* flush endpoint buffer */ - if (ep->ep_num == 0) - flush_bit = (1 << 16) | 1; - else if (is_in(ep)) - flush_bit = 1 << (ep->ep_num + 16); /* TX */ - else - flush_bit = 1 << ep->ep_num; /* RX */ - - /* wait until flush complete */ - timeout = jiffies + FLUSH_TIMEOUT; - do { - writel(flush_bit, &dev->op_regs->endptflush); - while (readl(&dev->op_regs->endptflush)) { - if (time_after(jiffies, timeout)) { - dev_err(&dev->pdev->dev, "ep flush timeout\n"); - goto done; - } - cpu_relax(); - } - } while (readl(&dev->op_regs->endptstat) & flush_bit); -done: - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* endpoints operations structure */ -static const struct usb_ep_ops langwell_ep_ops = { - - /* configure endpoint, making it usable */ - .enable = langwell_ep_enable, - - /* endpoint is no longer usable */ - .disable = langwell_ep_disable, - - /* allocate a request object to use with this endpoint */ - .alloc_request = langwell_alloc_request, - - /* free a request object */ - .free_request = langwell_free_request, - - /* queue (submits) an I/O requests to an endpoint */ - .queue = langwell_ep_queue, - - /* dequeue (cancels, unlinks) an I/O request from an endpoint */ - .dequeue = langwell_ep_dequeue, - - /* set the endpoint halt feature */ - .set_halt = langwell_ep_set_halt, - - /* set the halt feature and ignores clear requests */ - .set_wedge = langwell_ep_set_wedge, - - /* flush contents of a fifo */ - .fifo_flush = langwell_ep_fifo_flush, -}; - - -/*-------------------------------------------------------------------------*/ - -/* device controller usb_gadget_ops structure */ - -/* returns the current frame number */ -static int langwell_get_frame(struct usb_gadget *_gadget) -{ - struct langwell_udc *dev; - u16 retval; - - if (!_gadget) - return -ENODEV; - - dev = container_of(_gadget, struct langwell_udc, gadget); - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - retval = readl(&dev->op_regs->frindex) & FRINDEX_MASK; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return retval; -} - - -/* enter or exit PHY low power state */ -static void langwell_phy_low_power(struct langwell_udc *dev, bool flag) -{ - u32 devlc; - u8 devlc_byte2; - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - devlc = readl(&dev->op_regs->devlc); - dev_vdbg(&dev->pdev->dev, "devlc = 0x%08x\n", devlc); - - if (flag) - devlc |= LPM_PHCD; - else - devlc &= ~LPM_PHCD; - - /* FIXME: workaround for Langwell A1/A2/A3 sighting */ - devlc_byte2 = (devlc >> 16) & 0xff; - writeb(devlc_byte2, (u8 *)&dev->op_regs->devlc + 2); - - devlc = readl(&dev->op_regs->devlc); - dev_vdbg(&dev->pdev->dev, - "%s PHY low power suspend, devlc = 0x%08x\n", - flag ? "enter" : "exit", devlc); -} - - -/* tries to wake up the host connected to this gadget */ -static int langwell_wakeup(struct usb_gadget *_gadget) -{ - struct langwell_udc *dev; - u32 portsc1; - unsigned long flags; - - if (!_gadget) - return 0; - - dev = container_of(_gadget, struct langwell_udc, gadget); - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* remote wakeup feature not enabled by host */ - if (!dev->remote_wakeup) { - dev_info(&dev->pdev->dev, "remote wakeup is disabled\n"); - return -ENOTSUPP; - } - - spin_lock_irqsave(&dev->lock, flags); - - portsc1 = readl(&dev->op_regs->portsc1); - if (!(portsc1 & PORTS_SUSP)) { - spin_unlock_irqrestore(&dev->lock, flags); - return 0; - } - - /* LPM L1 to L0 or legacy remote wakeup */ - if (dev->lpm && dev->lpm_state == LPM_L1) - dev_info(&dev->pdev->dev, "LPM L1 to L0 remote wakeup\n"); - else - dev_info(&dev->pdev->dev, "device remote wakeup\n"); - - /* exit PHY low power suspend */ - if (dev->pdev->device != 0x0829) - langwell_phy_low_power(dev, 0); - - /* force port resume */ - portsc1 |= PORTS_FPR; - writel(portsc1, &dev->op_regs->portsc1); - - spin_unlock_irqrestore(&dev->lock, flags); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* notify controller that VBUS is powered or not */ -static int langwell_vbus_session(struct usb_gadget *_gadget, int is_active) -{ - struct langwell_udc *dev; - unsigned long flags; - u32 usbcmd; - - if (!_gadget) - return -ENODEV; - - dev = container_of(_gadget, struct langwell_udc, gadget); - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - spin_lock_irqsave(&dev->lock, flags); - dev_vdbg(&dev->pdev->dev, "VBUS status: %s\n", - is_active ? "on" : "off"); - - dev->vbus_active = (is_active != 0); - if (dev->driver && dev->softconnected && dev->vbus_active) { - usbcmd = readl(&dev->op_regs->usbcmd); - usbcmd |= CMD_RUNSTOP; - writel(usbcmd, &dev->op_regs->usbcmd); - } else { - usbcmd = readl(&dev->op_regs->usbcmd); - usbcmd &= ~CMD_RUNSTOP; - writel(usbcmd, &dev->op_regs->usbcmd); - } - - spin_unlock_irqrestore(&dev->lock, flags); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* constrain controller's VBUS power usage */ -static int langwell_vbus_draw(struct usb_gadget *_gadget, unsigned mA) -{ - struct langwell_udc *dev; - - if (!_gadget) - return -ENODEV; - - dev = container_of(_gadget, struct langwell_udc, gadget); - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (dev->transceiver) { - dev_vdbg(&dev->pdev->dev, "usb_phy_set_power\n"); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return usb_phy_set_power(dev->transceiver, mA); - } - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return -ENOTSUPP; -} - - -/* D+ pullup, software-controlled connect/disconnect to USB host */ -static int langwell_pullup(struct usb_gadget *_gadget, int is_on) -{ - struct langwell_udc *dev; - u32 usbcmd; - unsigned long flags; - - if (!_gadget) - return -ENODEV; - - dev = container_of(_gadget, struct langwell_udc, gadget); - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - spin_lock_irqsave(&dev->lock, flags); - dev->softconnected = (is_on != 0); - - if (dev->driver && dev->softconnected && dev->vbus_active) { - usbcmd = readl(&dev->op_regs->usbcmd); - usbcmd |= CMD_RUNSTOP; - writel(usbcmd, &dev->op_regs->usbcmd); - } else { - usbcmd = readl(&dev->op_regs->usbcmd); - usbcmd &= ~CMD_RUNSTOP; - writel(usbcmd, &dev->op_regs->usbcmd); - } - spin_unlock_irqrestore(&dev->lock, flags); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - -static int langwell_start(struct usb_gadget *g, - struct usb_gadget_driver *driver); - -static int langwell_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver); - -/* device controller usb_gadget_ops structure */ -static const struct usb_gadget_ops langwell_ops = { - - /* returns the current frame number */ - .get_frame = langwell_get_frame, - - /* tries to wake up the host connected to this gadget */ - .wakeup = langwell_wakeup, - - /* set the device selfpowered feature, always selfpowered */ - /* .set_selfpowered = langwell_set_selfpowered, */ - - /* notify controller that VBUS is powered or not */ - .vbus_session = langwell_vbus_session, - - /* constrain controller's VBUS power usage */ - .vbus_draw = langwell_vbus_draw, - - /* D+ pullup, software-controlled connect/disconnect to USB host */ - .pullup = langwell_pullup, - - .udc_start = langwell_start, - .udc_stop = langwell_stop, -}; - - -/*-------------------------------------------------------------------------*/ - -/* device controller operations */ - -/* reset device controller */ -static int langwell_udc_reset(struct langwell_udc *dev) -{ - u32 usbcmd, usbmode, devlc, endpointlistaddr; - u8 devlc_byte0, devlc_byte2; - unsigned long timeout; - - if (!dev) - return -EINVAL; - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* set controller to stop state */ - usbcmd = readl(&dev->op_regs->usbcmd); - usbcmd &= ~CMD_RUNSTOP; - writel(usbcmd, &dev->op_regs->usbcmd); - - /* reset device controller */ - usbcmd = readl(&dev->op_regs->usbcmd); - usbcmd |= CMD_RST; - writel(usbcmd, &dev->op_regs->usbcmd); - - /* wait for reset to complete */ - timeout = jiffies + RESET_TIMEOUT; - while (readl(&dev->op_regs->usbcmd) & CMD_RST) { - if (time_after(jiffies, timeout)) { - dev_err(&dev->pdev->dev, "device reset timeout\n"); - return -ETIMEDOUT; - } - cpu_relax(); - } - - /* set controller to device mode */ - usbmode = readl(&dev->op_regs->usbmode); - usbmode |= MODE_DEVICE; - - /* turn setup lockout off, require setup tripwire in usbcmd */ - usbmode |= MODE_SLOM; - - writel(usbmode, &dev->op_regs->usbmode); - usbmode = readl(&dev->op_regs->usbmode); - dev_vdbg(&dev->pdev->dev, "usbmode=0x%08x\n", usbmode); - - /* Write-Clear setup status */ - writel(0, &dev->op_regs->usbsts); - - /* if support USB LPM, ACK all LPM token */ - if (dev->lpm) { - devlc = readl(&dev->op_regs->devlc); - dev_vdbg(&dev->pdev->dev, "devlc = 0x%08x\n", devlc); - /* FIXME: workaround for Langwell A1/A2/A3 sighting */ - devlc &= ~LPM_STL; /* don't STALL LPM token */ - devlc &= ~LPM_NYT_ACK; /* ACK LPM token */ - devlc_byte0 = devlc & 0xff; - devlc_byte2 = (devlc >> 16) & 0xff; - writeb(devlc_byte0, (u8 *)&dev->op_regs->devlc); - writeb(devlc_byte2, (u8 *)&dev->op_regs->devlc + 2); - devlc = readl(&dev->op_regs->devlc); - dev_vdbg(&dev->pdev->dev, - "ACK LPM token, devlc = 0x%08x\n", devlc); - } - - /* fill endpointlistaddr register */ - endpointlistaddr = dev->ep_dqh_dma; - endpointlistaddr &= ENDPOINTLISTADDR_MASK; - writel(endpointlistaddr, &dev->op_regs->endpointlistaddr); - - dev_vdbg(&dev->pdev->dev, - "dQH base (vir: %p, phy: 0x%08x), endpointlistaddr=0x%08x\n", - dev->ep_dqh, endpointlistaddr, - readl(&dev->op_regs->endpointlistaddr)); - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* reinitialize device controller endpoints */ -static int eps_reinit(struct langwell_udc *dev) -{ - struct langwell_ep *ep; - char name[14]; - int i; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* initialize ep0 */ - ep = &dev->ep[0]; - ep->dev = dev; - strncpy(ep->name, "ep0", sizeof(ep->name)); - ep->ep.name = ep->name; - ep->ep.ops = &langwell_ep_ops; - ep->stopped = 0; - ep->ep.maxpacket = EP0_MAX_PKT_SIZE; - ep->ep_num = 0; - ep->desc = &langwell_ep0_desc; - INIT_LIST_HEAD(&ep->queue); - - ep->ep_type = USB_ENDPOINT_XFER_CONTROL; - - /* initialize other endpoints */ - for (i = 2; i < dev->ep_max; i++) { - ep = &dev->ep[i]; - if (i % 2) - snprintf(name, sizeof(name), "ep%din", i / 2); - else - snprintf(name, sizeof(name), "ep%dout", i / 2); - ep->dev = dev; - strncpy(ep->name, name, sizeof(ep->name)); - ep->ep.name = ep->name; - - ep->ep.ops = &langwell_ep_ops; - ep->stopped = 0; - ep->ep.maxpacket = (unsigned short) ~0; - ep->ep_num = i / 2; - - INIT_LIST_HEAD(&ep->queue); - list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); - } - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* enable interrupt and set controller to run state */ -static void langwell_udc_start(struct langwell_udc *dev) -{ - u32 usbintr, usbcmd; - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* enable interrupts */ - usbintr = INTR_ULPIE /* ULPI */ - | INTR_SLE /* suspend */ - /* | INTR_SRE SOF received */ - | INTR_URE /* USB reset */ - | INTR_AAE /* async advance */ - | INTR_SEE /* system error */ - | INTR_FRE /* frame list rollover */ - | INTR_PCE /* port change detect */ - | INTR_UEE /* USB error interrupt */ - | INTR_UE; /* USB interrupt */ - writel(usbintr, &dev->op_regs->usbintr); - - /* clear stopped bit */ - dev->stopped = 0; - - /* set controller to run */ - usbcmd = readl(&dev->op_regs->usbcmd); - usbcmd |= CMD_RUNSTOP; - writel(usbcmd, &dev->op_regs->usbcmd); - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* disable interrupt and set controller to stop state */ -static void langwell_udc_stop(struct langwell_udc *dev) -{ - u32 usbcmd; - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* disable all interrupts */ - writel(0, &dev->op_regs->usbintr); - - /* set stopped bit */ - dev->stopped = 1; - - /* set controller to stop state */ - usbcmd = readl(&dev->op_regs->usbcmd); - usbcmd &= ~CMD_RUNSTOP; - writel(usbcmd, &dev->op_regs->usbcmd); - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* stop all USB activities */ -static void stop_activity(struct langwell_udc *dev) -{ - struct langwell_ep *ep; - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - nuke(&dev->ep[0], -ESHUTDOWN); - - list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) { - nuke(ep, -ESHUTDOWN); - } - - /* report disconnect; the driver is already quiesced */ - if (dev->driver) { - spin_unlock(&dev->lock); - dev->driver->disconnect(&dev->gadget); - spin_lock(&dev->lock); - } - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/*-------------------------------------------------------------------------*/ - -/* device "function" sysfs attribute file */ -static ssize_t show_function(struct device *_dev, - struct device_attribute *attr, char *buf) -{ - struct langwell_udc *dev = dev_get_drvdata(_dev); - - if (!dev->driver || !dev->driver->function - || strlen(dev->driver->function) > PAGE_SIZE) - return 0; - - return scnprintf(buf, PAGE_SIZE, "%s\n", dev->driver->function); -} -static DEVICE_ATTR(function, S_IRUGO, show_function, NULL); - - -static inline enum usb_device_speed lpm_device_speed(u32 reg) -{ - switch (LPM_PSPD(reg)) { - case LPM_SPEED_HIGH: - return USB_SPEED_HIGH; - case LPM_SPEED_FULL: - return USB_SPEED_FULL; - case LPM_SPEED_LOW: - return USB_SPEED_LOW; - default: - return USB_SPEED_UNKNOWN; - } -} - -/* device "langwell_udc" sysfs attribute file */ -static ssize_t show_langwell_udc(struct device *_dev, - struct device_attribute *attr, char *buf) -{ - struct langwell_udc *dev = dev_get_drvdata(_dev); - struct langwell_request *req; - struct langwell_ep *ep = NULL; - char *next; - unsigned size; - unsigned t; - unsigned i; - unsigned long flags; - u32 tmp_reg; - - next = buf; - size = PAGE_SIZE; - spin_lock_irqsave(&dev->lock, flags); - - /* driver basic information */ - t = scnprintf(next, size, - DRIVER_DESC "\n" - "%s version: %s\n" - "Gadget driver: %s\n\n", - driver_name, DRIVER_VERSION, - dev->driver ? dev->driver->driver.name : "(none)"); - size -= t; - next += t; - - /* device registers */ - tmp_reg = readl(&dev->op_regs->usbcmd); - t = scnprintf(next, size, - "USBCMD reg:\n" - "SetupTW: %d\n" - "Run/Stop: %s\n\n", - (tmp_reg & CMD_SUTW) ? 1 : 0, - (tmp_reg & CMD_RUNSTOP) ? "Run" : "Stop"); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->usbsts); - t = scnprintf(next, size, - "USB Status Reg:\n" - "Device Suspend: %d\n" - "Reset Received: %d\n" - "System Error: %s\n" - "USB Error Interrupt: %s\n\n", - (tmp_reg & STS_SLI) ? 1 : 0, - (tmp_reg & STS_URI) ? 1 : 0, - (tmp_reg & STS_SEI) ? "Error" : "No error", - (tmp_reg & STS_UEI) ? "Error detected" : "No error"); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->usbintr); - t = scnprintf(next, size, - "USB Intrrupt Enable Reg:\n" - "Sleep Enable: %d\n" - "SOF Received Enable: %d\n" - "Reset Enable: %d\n" - "System Error Enable: %d\n" - "Port Change Dectected Enable: %d\n" - "USB Error Intr Enable: %d\n" - "USB Intr Enable: %d\n\n", - (tmp_reg & INTR_SLE) ? 1 : 0, - (tmp_reg & INTR_SRE) ? 1 : 0, - (tmp_reg & INTR_URE) ? 1 : 0, - (tmp_reg & INTR_SEE) ? 1 : 0, - (tmp_reg & INTR_PCE) ? 1 : 0, - (tmp_reg & INTR_UEE) ? 1 : 0, - (tmp_reg & INTR_UE) ? 1 : 0); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->frindex); - t = scnprintf(next, size, - "USB Frame Index Reg:\n" - "Frame Number is 0x%08x\n\n", - (tmp_reg & FRINDEX_MASK)); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->deviceaddr); - t = scnprintf(next, size, - "USB Device Address Reg:\n" - "Device Addr is 0x%x\n\n", - USBADR(tmp_reg)); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->endpointlistaddr); - t = scnprintf(next, size, - "USB Endpoint List Address Reg:\n" - "Endpoint List Pointer is 0x%x\n\n", - EPBASE(tmp_reg)); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->portsc1); - t = scnprintf(next, size, - "USB Port Status & Control Reg:\n" - "Port Reset: %s\n" - "Port Suspend Mode: %s\n" - "Over-current Change: %s\n" - "Port Enable/Disable Change: %s\n" - "Port Enabled/Disabled: %s\n" - "Current Connect Status: %s\n" - "LPM Suspend Status: %s\n\n", - (tmp_reg & PORTS_PR) ? "Reset" : "Not Reset", - (tmp_reg & PORTS_SUSP) ? "Suspend " : "Not Suspend", - (tmp_reg & PORTS_OCC) ? "Detected" : "No", - (tmp_reg & PORTS_PEC) ? "Changed" : "Not Changed", - (tmp_reg & PORTS_PE) ? "Enable" : "Not Correct", - (tmp_reg & PORTS_CCS) ? "Attached" : "Not Attached", - (tmp_reg & PORTS_SLP) ? "LPM L1" : "LPM L0"); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->devlc); - t = scnprintf(next, size, - "Device LPM Control Reg:\n" - "Parallel Transceiver : %d\n" - "Serial Transceiver : %d\n" - "Port Speed: %s\n" - "Port Force Full Speed Connenct: %s\n" - "PHY Low Power Suspend Clock: %s\n" - "BmAttributes: %d\n\n", - LPM_PTS(tmp_reg), - (tmp_reg & LPM_STS) ? 1 : 0, - usb_speed_string(lpm_device_speed(tmp_reg)), - (tmp_reg & LPM_PFSC) ? "Force Full Speed" : "Not Force", - (tmp_reg & LPM_PHCD) ? "Disabled" : "Enabled", - LPM_BA(tmp_reg)); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->usbmode); - t = scnprintf(next, size, - "USB Mode Reg:\n" - "Controller Mode is : %s\n\n", ({ - char *s; - switch (MODE_CM(tmp_reg)) { - case MODE_IDLE: - s = "Idle"; break; - case MODE_DEVICE: - s = "Device Controller"; break; - case MODE_HOST: - s = "Host Controller"; break; - default: - s = "None"; break; - } - s; - })); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->endptsetupstat); - t = scnprintf(next, size, - "Endpoint Setup Status Reg:\n" - "SETUP on ep 0x%04x\n\n", - tmp_reg & SETUPSTAT_MASK); - size -= t; - next += t; - - for (i = 0; i < dev->ep_max / 2; i++) { - tmp_reg = readl(&dev->op_regs->endptctrl[i]); - t = scnprintf(next, size, "EP Ctrl Reg [%d]: 0x%08x\n", - i, tmp_reg); - size -= t; - next += t; - } - tmp_reg = readl(&dev->op_regs->endptprime); - t = scnprintf(next, size, "EP Prime Reg: 0x%08x\n\n", tmp_reg); - size -= t; - next += t; - - /* langwell_udc, langwell_ep, langwell_request structure information */ - ep = &dev->ep[0]; - t = scnprintf(next, size, "%s MaxPacketSize: 0x%x, ep_num: %d\n", - ep->ep.name, ep->ep.maxpacket, ep->ep_num); - size -= t; - next += t; - - if (list_empty(&ep->queue)) { - t = scnprintf(next, size, "its req queue is empty\n\n"); - size -= t; - next += t; - } else { - list_for_each_entry(req, &ep->queue, queue) { - t = scnprintf(next, size, - "req %p actual 0x%x length 0x%x buf %p\n", - &req->req, req->req.actual, - req->req.length, req->req.buf); - size -= t; - next += t; - } - } - /* other gadget->eplist ep */ - list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) { - if (ep->desc) { - t = scnprintf(next, size, - "\n%s MaxPacketSize: 0x%x, " - "ep_num: %d\n", - ep->ep.name, ep->ep.maxpacket, - ep->ep_num); - size -= t; - next += t; - - if (list_empty(&ep->queue)) { - t = scnprintf(next, size, - "its req queue is empty\n\n"); - size -= t; - next += t; - } else { - list_for_each_entry(req, &ep->queue, queue) { - t = scnprintf(next, size, - "req %p actual 0x%x length " - "0x%x buf %p\n", - &req->req, req->req.actual, - req->req.length, req->req.buf); - size -= t; - next += t; - } - } - } - } - - spin_unlock_irqrestore(&dev->lock, flags); - return PAGE_SIZE - size; -} -static DEVICE_ATTR(langwell_udc, S_IRUGO, show_langwell_udc, NULL); - - -/* device "remote_wakeup" sysfs attribute file */ -static ssize_t store_remote_wakeup(struct device *_dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct langwell_udc *dev = dev_get_drvdata(_dev); - unsigned long flags; - ssize_t rc = count; - - if (count > 2) - return -EINVAL; - - if (count > 0 && buf[count-1] == '\n') - ((char *) buf)[count-1] = 0; - - if (buf[0] != '1') - return -EINVAL; - - /* force remote wakeup enabled in case gadget driver doesn't support */ - spin_lock_irqsave(&dev->lock, flags); - dev->remote_wakeup = 1; - dev->dev_status |= (1 << USB_DEVICE_REMOTE_WAKEUP); - spin_unlock_irqrestore(&dev->lock, flags); - - langwell_wakeup(&dev->gadget); - - return rc; -} -static DEVICE_ATTR(remote_wakeup, S_IWUSR, NULL, store_remote_wakeup); - - -/*-------------------------------------------------------------------------*/ - -/* - * when a driver is successfully registered, it will receive - * control requests including set_configuration(), which enables - * non-control requests. then usb traffic follows until a - * disconnect is reported. then a host may connect again, or - * the driver might get unbound. - */ - -static int langwell_start(struct usb_gadget *g, - struct usb_gadget_driver *driver) -{ - struct langwell_udc *dev = gadget_to_langwell(g); - unsigned long flags; - int retval; - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - spin_lock_irqsave(&dev->lock, flags); - - /* hook up the driver ... */ - driver->driver.bus = NULL; - dev->driver = driver; - dev->gadget.dev.driver = &driver->driver; - - spin_unlock_irqrestore(&dev->lock, flags); - - retval = device_create_file(&dev->pdev->dev, &dev_attr_function); - if (retval) - goto err; - - dev->usb_state = USB_STATE_ATTACHED; - dev->ep0_state = WAIT_FOR_SETUP; - dev->ep0_dir = USB_DIR_OUT; - - /* enable interrupt and set controller to run state */ - if (dev->got_irq) - langwell_udc_start(dev); - - dev_vdbg(&dev->pdev->dev, - "After langwell_udc_start(), print all registers:\n"); - print_all_registers(dev); - - dev_info(&dev->pdev->dev, "register driver: %s\n", - driver->driver.name); - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - - return 0; - -err: - dev->gadget.dev.driver = NULL; - dev->driver = NULL; - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - - return retval; -} - -/* unregister gadget driver */ -static int langwell_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver) -{ - struct langwell_udc *dev = gadget_to_langwell(g); - unsigned long flags; - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* exit PHY low power suspend */ - if (dev->pdev->device != 0x0829) - langwell_phy_low_power(dev, 0); - - /* unbind OTG transceiver */ - if (dev->transceiver) - (void)otg_set_peripheral(dev->transceiver->otg, 0); - - /* disable interrupt and set controller to stop state */ - langwell_udc_stop(dev); - - dev->usb_state = USB_STATE_ATTACHED; - dev->ep0_state = WAIT_FOR_SETUP; - dev->ep0_dir = USB_DIR_OUT; - - spin_lock_irqsave(&dev->lock, flags); - - /* stop all usb activities */ - dev->gadget.speed = USB_SPEED_UNKNOWN; - dev->gadget.dev.driver = NULL; - dev->driver = NULL; - stop_activity(dev); - spin_unlock_irqrestore(&dev->lock, flags); - - device_remove_file(&dev->pdev->dev, &dev_attr_function); - - dev_info(&dev->pdev->dev, "unregistered driver '%s'\n", - driver->driver.name); - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* - * setup tripwire is used as a semaphore to ensure that the setup data - * payload is extracted from a dQH without being corrupted - */ -static void setup_tripwire(struct langwell_udc *dev) -{ - u32 usbcmd, - endptsetupstat; - unsigned long timeout; - struct langwell_dqh *dqh; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* ep0 OUT dQH */ - dqh = &dev->ep_dqh[EP_DIR_OUT]; - - /* Write-Clear endptsetupstat */ - endptsetupstat = readl(&dev->op_regs->endptsetupstat); - writel(endptsetupstat, &dev->op_regs->endptsetupstat); - - /* wait until endptsetupstat is cleared */ - timeout = jiffies + SETUPSTAT_TIMEOUT; - while (readl(&dev->op_regs->endptsetupstat)) { - if (time_after(jiffies, timeout)) { - dev_err(&dev->pdev->dev, "setup_tripwire timeout\n"); - break; - } - cpu_relax(); - } - - /* while a hazard exists when setup packet arrives */ - do { - /* set setup tripwire bit */ - usbcmd = readl(&dev->op_regs->usbcmd); - writel(usbcmd | CMD_SUTW, &dev->op_regs->usbcmd); - - /* copy the setup packet to local buffer */ - memcpy(&dev->local_setup_buff, &dqh->dqh_setup, 8); - } while (!(readl(&dev->op_regs->usbcmd) & CMD_SUTW)); - - /* Write-Clear setup tripwire bit */ - usbcmd = readl(&dev->op_regs->usbcmd); - writel(usbcmd & ~CMD_SUTW, &dev->op_regs->usbcmd); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* protocol ep0 stall, will automatically be cleared on new transaction */ -static void ep0_stall(struct langwell_udc *dev) -{ - u32 endptctrl; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* set TX and RX to stall */ - endptctrl = readl(&dev->op_regs->endptctrl[0]); - endptctrl |= EPCTRL_TXS | EPCTRL_RXS; - writel(endptctrl, &dev->op_regs->endptctrl[0]); - - /* update ep0 state */ - dev->ep0_state = WAIT_FOR_SETUP; - dev->ep0_dir = USB_DIR_OUT; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* PRIME a status phase for ep0 */ -static int prime_status_phase(struct langwell_udc *dev, int dir) -{ - struct langwell_request *req; - struct langwell_ep *ep; - int status = 0; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (dir == EP_DIR_IN) - dev->ep0_dir = USB_DIR_IN; - else - dev->ep0_dir = USB_DIR_OUT; - - ep = &dev->ep[0]; - dev->ep0_state = WAIT_FOR_OUT_STATUS; - - req = dev->status_req; - - req->ep = ep; - req->req.length = 0; - req->req.status = -EINPROGRESS; - req->req.actual = 0; - req->req.complete = NULL; - req->dtd_count = 0; - - if (!req_to_dtd(req)) - status = queue_dtd(ep, req); - else - return -ENOMEM; - - if (status) - dev_err(&dev->pdev->dev, "can't queue ep0 status request\n"); - - list_add_tail(&req->queue, &ep->queue); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return status; -} - - -/* SET_ADDRESS request routine */ -static void set_address(struct langwell_udc *dev, u16 value, - u16 index, u16 length) -{ - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* save the new address to device struct */ - dev->dev_addr = (u8) value; - dev_vdbg(&dev->pdev->dev, "dev->dev_addr = %d\n", dev->dev_addr); - - /* update usb state */ - dev->usb_state = USB_STATE_ADDRESS; - - /* STATUS phase */ - if (prime_status_phase(dev, EP_DIR_IN)) - ep0_stall(dev); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* return endpoint by windex */ -static struct langwell_ep *get_ep_by_windex(struct langwell_udc *dev, - u16 wIndex) -{ - struct langwell_ep *ep; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0) - return &dev->ep[0]; - - list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) { - u8 bEndpointAddress; - if (!ep->desc) - continue; - - bEndpointAddress = ep->desc->bEndpointAddress; - if ((wIndex ^ bEndpointAddress) & USB_DIR_IN) - continue; - - if ((wIndex & USB_ENDPOINT_NUMBER_MASK) - == (bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)) - return ep; - } - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return NULL; -} - - -/* return whether endpoint is stalled, 0: not stalled; 1: stalled */ -static int ep_is_stall(struct langwell_ep *ep) -{ - struct langwell_udc *dev = ep->dev; - u32 endptctrl; - int retval; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - endptctrl = readl(&dev->op_regs->endptctrl[ep->ep_num]); - if (is_in(ep)) - retval = endptctrl & EPCTRL_TXS ? 1 : 0; - else - retval = endptctrl & EPCTRL_RXS ? 1 : 0; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return retval; -} - - -/* GET_STATUS request routine */ -static void get_status(struct langwell_udc *dev, u8 request_type, u16 value, - u16 index, u16 length) -{ - struct langwell_request *req; - struct langwell_ep *ep; - u16 status_data = 0; /* 16 bits cpu view status data */ - int status = 0; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - ep = &dev->ep[0]; - - if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) { - /* get device status */ - status_data = dev->dev_status; - } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) { - /* get interface status */ - status_data = 0; - } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_ENDPOINT) { - /* get endpoint status */ - struct langwell_ep *epn; - epn = get_ep_by_windex(dev, index); - /* stall if endpoint doesn't exist */ - if (!epn) - goto stall; - - status_data = ep_is_stall(epn) << USB_ENDPOINT_HALT; - } - - dev_dbg(&dev->pdev->dev, "get status data: 0x%04x\n", status_data); - - dev->ep0_dir = USB_DIR_IN; - - /* borrow the per device status_req */ - req = dev->status_req; - - /* fill in the reqest structure */ - *((u16 *) req->req.buf) = cpu_to_le16(status_data); - req->ep = ep; - req->req.length = 2; - req->req.status = -EINPROGRESS; - req->req.actual = 0; - req->req.complete = NULL; - req->dtd_count = 0; - - /* prime the data phase */ - if (!req_to_dtd(req)) - status = queue_dtd(ep, req); - else /* no mem */ - goto stall; - - if (status) { - dev_err(&dev->pdev->dev, - "response error on GET_STATUS request\n"); - goto stall; - } - - list_add_tail(&req->queue, &ep->queue); - dev->ep0_state = DATA_STATE_XMIT; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return; -stall: - ep0_stall(dev); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* setup packet interrupt handler */ -static void handle_setup_packet(struct langwell_udc *dev, - struct usb_ctrlrequest *setup) -{ - u16 wValue = le16_to_cpu(setup->wValue); - u16 wIndex = le16_to_cpu(setup->wIndex); - u16 wLength = le16_to_cpu(setup->wLength); - u32 portsc1; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* ep0 fifo flush */ - nuke(&dev->ep[0], -ESHUTDOWN); - - dev_dbg(&dev->pdev->dev, "SETUP %02x.%02x v%04x i%04x l%04x\n", - setup->bRequestType, setup->bRequest, - wValue, wIndex, wLength); - - /* RNDIS gadget delegate */ - if ((setup->bRequestType == 0x21) && (setup->bRequest == 0x00)) { - /* USB_CDC_SEND_ENCAPSULATED_COMMAND */ - goto delegate; - } - - /* USB_CDC_GET_ENCAPSULATED_RESPONSE */ - if ((setup->bRequestType == 0xa1) && (setup->bRequest == 0x01)) { - /* USB_CDC_GET_ENCAPSULATED_RESPONSE */ - goto delegate; - } - - /* We process some stardard setup requests here */ - switch (setup->bRequest) { - case USB_REQ_GET_STATUS: - dev_dbg(&dev->pdev->dev, "SETUP: USB_REQ_GET_STATUS\n"); - /* get status, DATA and STATUS phase */ - if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK)) - != (USB_DIR_IN | USB_TYPE_STANDARD)) - break; - get_status(dev, setup->bRequestType, wValue, wIndex, wLength); - goto end; - - case USB_REQ_SET_ADDRESS: - dev_dbg(&dev->pdev->dev, "SETUP: USB_REQ_SET_ADDRESS\n"); - /* STATUS phase */ - if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD - | USB_RECIP_DEVICE)) - break; - set_address(dev, wValue, wIndex, wLength); - goto end; - - case USB_REQ_CLEAR_FEATURE: - case USB_REQ_SET_FEATURE: - /* STATUS phase */ - { - int rc = -EOPNOTSUPP; - if (setup->bRequest == USB_REQ_SET_FEATURE) - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_SET_FEATURE\n"); - else if (setup->bRequest == USB_REQ_CLEAR_FEATURE) - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_CLEAR_FEATURE\n"); - - if ((setup->bRequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) - == (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) { - struct langwell_ep *epn; - epn = get_ep_by_windex(dev, wIndex); - /* stall if endpoint doesn't exist */ - if (!epn) { - ep0_stall(dev); - goto end; - } - - if (wValue != 0 || wLength != 0 - || epn->ep_num > dev->ep_max) - break; - - spin_unlock(&dev->lock); - rc = langwell_ep_set_halt(&epn->ep, - (setup->bRequest == USB_REQ_SET_FEATURE) - ? 1 : 0); - spin_lock(&dev->lock); - - } else if ((setup->bRequestType & (USB_RECIP_MASK - | USB_TYPE_MASK)) == (USB_RECIP_DEVICE - | USB_TYPE_STANDARD)) { - rc = 0; - switch (wValue) { - case USB_DEVICE_REMOTE_WAKEUP: - if (setup->bRequest == USB_REQ_SET_FEATURE) { - dev->remote_wakeup = 1; - dev->dev_status |= (1 << wValue); - } else { - dev->remote_wakeup = 0; - dev->dev_status &= ~(1 << wValue); - } - break; - case USB_DEVICE_TEST_MODE: - dev_dbg(&dev->pdev->dev, "SETUP: TEST MODE\n"); - if ((wIndex & 0xff) || - (dev->gadget.speed != USB_SPEED_HIGH)) - ep0_stall(dev); - - switch (wIndex >> 8) { - case TEST_J: - case TEST_K: - case TEST_SE0_NAK: - case TEST_PACKET: - case TEST_FORCE_EN: - if (prime_status_phase(dev, EP_DIR_IN)) - ep0_stall(dev); - portsc1 = readl(&dev->op_regs->portsc1); - portsc1 |= (wIndex & 0xf00) << 8; - writel(portsc1, &dev->op_regs->portsc1); - goto end; - default: - rc = -EOPNOTSUPP; - } - break; - default: - rc = -EOPNOTSUPP; - break; - } - - if (!gadget_is_otg(&dev->gadget)) - break; - else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE) - dev->gadget.b_hnp_enable = 1; - else if (setup->bRequest == USB_DEVICE_A_HNP_SUPPORT) - dev->gadget.a_hnp_support = 1; - else if (setup->bRequest == - USB_DEVICE_A_ALT_HNP_SUPPORT) - dev->gadget.a_alt_hnp_support = 1; - else - break; - } else - break; - - if (rc == 0) { - if (prime_status_phase(dev, EP_DIR_IN)) - ep0_stall(dev); - } - goto end; - } - - case USB_REQ_GET_DESCRIPTOR: - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_GET_DESCRIPTOR\n"); - goto delegate; - - case USB_REQ_SET_DESCRIPTOR: - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_SET_DESCRIPTOR unsupported\n"); - goto delegate; - - case USB_REQ_GET_CONFIGURATION: - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_GET_CONFIGURATION\n"); - goto delegate; - - case USB_REQ_SET_CONFIGURATION: - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_SET_CONFIGURATION\n"); - goto delegate; - - case USB_REQ_GET_INTERFACE: - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_GET_INTERFACE\n"); - goto delegate; - - case USB_REQ_SET_INTERFACE: - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_SET_INTERFACE\n"); - goto delegate; - - case USB_REQ_SYNCH_FRAME: - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_SYNCH_FRAME unsupported\n"); - goto delegate; - - default: - /* delegate USB standard requests to the gadget driver */ - goto delegate; -delegate: - /* USB requests handled by gadget */ - if (wLength) { - /* DATA phase from gadget, STATUS phase from udc */ - dev->ep0_dir = (setup->bRequestType & USB_DIR_IN) - ? USB_DIR_IN : USB_DIR_OUT; - dev_vdbg(&dev->pdev->dev, - "dev->ep0_dir = 0x%x, wLength = %d\n", - dev->ep0_dir, wLength); - spin_unlock(&dev->lock); - if (dev->driver->setup(&dev->gadget, - &dev->local_setup_buff) < 0) - ep0_stall(dev); - spin_lock(&dev->lock); - dev->ep0_state = (setup->bRequestType & USB_DIR_IN) - ? DATA_STATE_XMIT : DATA_STATE_RECV; - } else { - /* no DATA phase, IN STATUS phase from gadget */ - dev->ep0_dir = USB_DIR_IN; - dev_vdbg(&dev->pdev->dev, - "dev->ep0_dir = 0x%x, wLength = %d\n", - dev->ep0_dir, wLength); - spin_unlock(&dev->lock); - if (dev->driver->setup(&dev->gadget, - &dev->local_setup_buff) < 0) - ep0_stall(dev); - spin_lock(&dev->lock); - dev->ep0_state = WAIT_FOR_OUT_STATUS; - } - break; - } -end: - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* transfer completion, process endpoint request and free the completed dTDs - * for this request - */ -static int process_ep_req(struct langwell_udc *dev, int index, - struct langwell_request *curr_req) -{ - struct langwell_dtd *curr_dtd; - struct langwell_dqh *curr_dqh; - int td_complete, actual, remaining_length; - int i, dir; - u8 dtd_status = 0; - int retval = 0; - - curr_dqh = &dev->ep_dqh[index]; - dir = index % 2; - - curr_dtd = curr_req->head; - td_complete = 0; - actual = curr_req->req.length; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - for (i = 0; i < curr_req->dtd_count; i++) { - - /* command execution states by dTD */ - dtd_status = curr_dtd->dtd_status; - - barrier(); - remaining_length = le16_to_cpu(curr_dtd->dtd_total); - actual -= remaining_length; - - if (!dtd_status) { - /* transfers completed successfully */ - if (!remaining_length) { - td_complete++; - dev_vdbg(&dev->pdev->dev, - "dTD transmitted successfully\n"); - } else { - if (dir) { - dev_vdbg(&dev->pdev->dev, - "TX dTD remains data\n"); - retval = -EPROTO; - break; - - } else { - td_complete++; - break; - } - } - } else { - /* transfers completed with errors */ - if (dtd_status & DTD_STS_ACTIVE) { - dev_dbg(&dev->pdev->dev, - "dTD status ACTIVE dQH[%d]\n", index); - retval = 1; - return retval; - } else if (dtd_status & DTD_STS_HALTED) { - dev_err(&dev->pdev->dev, - "dTD error %08x dQH[%d]\n", - dtd_status, index); - /* clear the errors and halt condition */ - curr_dqh->dtd_status = 0; - retval = -EPIPE; - break; - } else if (dtd_status & DTD_STS_DBE) { - dev_dbg(&dev->pdev->dev, - "data buffer (overflow) error\n"); - retval = -EPROTO; - break; - } else if (dtd_status & DTD_STS_TRE) { - dev_dbg(&dev->pdev->dev, - "transaction(ISO) error\n"); - retval = -EILSEQ; - break; - } else - dev_err(&dev->pdev->dev, - "unknown error (0x%x)!\n", - dtd_status); - } - - if (i != curr_req->dtd_count - 1) - curr_dtd = (struct langwell_dtd *) - curr_dtd->next_dtd_virt; - } - - if (retval) - return retval; - - curr_req->req.actual = actual; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* complete DATA or STATUS phase of ep0 prime status phase if needed */ -static void ep0_req_complete(struct langwell_udc *dev, - struct langwell_ep *ep0, struct langwell_request *req) -{ - u32 new_addr; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (dev->usb_state == USB_STATE_ADDRESS) { - /* set the new address */ - new_addr = (u32)dev->dev_addr; - writel(new_addr << USBADR_SHIFT, &dev->op_regs->deviceaddr); - - new_addr = USBADR(readl(&dev->op_regs->deviceaddr)); - dev_vdbg(&dev->pdev->dev, "new_addr = %d\n", new_addr); - } - - done(ep0, req, 0); - - switch (dev->ep0_state) { - case DATA_STATE_XMIT: - /* receive status phase */ - if (prime_status_phase(dev, EP_DIR_OUT)) - ep0_stall(dev); - break; - case DATA_STATE_RECV: - /* send status phase */ - if (prime_status_phase(dev, EP_DIR_IN)) - ep0_stall(dev); - break; - case WAIT_FOR_OUT_STATUS: - dev->ep0_state = WAIT_FOR_SETUP; - break; - case WAIT_FOR_SETUP: - dev_err(&dev->pdev->dev, "unexpect ep0 packets\n"); - break; - default: - ep0_stall(dev); - break; - } - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* USB transfer completion interrupt */ -static void handle_trans_complete(struct langwell_udc *dev) -{ - u32 complete_bits; - int i, ep_num, dir, bit_mask, status; - struct langwell_ep *epn; - struct langwell_request *curr_req, *temp_req; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - complete_bits = readl(&dev->op_regs->endptcomplete); - dev_vdbg(&dev->pdev->dev, "endptcomplete register: 0x%08x\n", - complete_bits); - - /* Write-Clear the bits in endptcomplete register */ - writel(complete_bits, &dev->op_regs->endptcomplete); - - if (!complete_bits) { - dev_dbg(&dev->pdev->dev, "complete_bits = 0\n"); - goto done; - } - - for (i = 0; i < dev->ep_max; i++) { - ep_num = i / 2; - dir = i % 2; - - bit_mask = 1 << (ep_num + 16 * dir); - - if (!(complete_bits & bit_mask)) - continue; - - /* ep0 */ - if (i == 1) - epn = &dev->ep[0]; - else - epn = &dev->ep[i]; - - if (epn->name == NULL) { - dev_warn(&dev->pdev->dev, "invalid endpoint\n"); - continue; - } - - if (i < 2) - /* ep0 in and out */ - dev_dbg(&dev->pdev->dev, "%s-%s transfer completed\n", - epn->name, - is_in(epn) ? "in" : "out"); - else - dev_dbg(&dev->pdev->dev, "%s transfer completed\n", - epn->name); - - /* process the req queue until an uncomplete request */ - list_for_each_entry_safe(curr_req, temp_req, - &epn->queue, queue) { - status = process_ep_req(dev, i, curr_req); - dev_vdbg(&dev->pdev->dev, "%s req status: %d\n", - epn->name, status); - - if (status) - break; - - /* write back status to req */ - curr_req->req.status = status; - - /* ep0 request completion */ - if (ep_num == 0) { - ep0_req_complete(dev, epn, curr_req); - break; - } else { - done(epn, curr_req, status); - } - } - } -done: - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - -/* port change detect interrupt handler */ -static void handle_port_change(struct langwell_udc *dev) -{ - u32 portsc1, devlc; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (dev->bus_reset) - dev->bus_reset = 0; - - portsc1 = readl(&dev->op_regs->portsc1); - devlc = readl(&dev->op_regs->devlc); - dev_vdbg(&dev->pdev->dev, "portsc1 = 0x%08x, devlc = 0x%08x\n", - portsc1, devlc); - - /* bus reset is finished */ - if (!(portsc1 & PORTS_PR)) { - /* get the speed */ - dev->gadget.speed = lpm_device_speed(devlc); - dev_vdbg(&dev->pdev->dev, "dev->gadget.speed = %d\n", - dev->gadget.speed); - } - - /* LPM L0 to L1 */ - if (dev->lpm && dev->lpm_state == LPM_L0) - if (portsc1 & PORTS_SUSP && portsc1 & PORTS_SLP) { - dev_info(&dev->pdev->dev, "LPM L0 to L1\n"); - dev->lpm_state = LPM_L1; - } - - /* LPM L1 to L0, force resume or remote wakeup finished */ - if (dev->lpm && dev->lpm_state == LPM_L1) - if (!(portsc1 & PORTS_SUSP)) { - dev_info(&dev->pdev->dev, "LPM L1 to L0\n"); - dev->lpm_state = LPM_L0; - } - - /* update USB state */ - if (!dev->resume_state) - dev->usb_state = USB_STATE_DEFAULT; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* USB reset interrupt handler */ -static void handle_usb_reset(struct langwell_udc *dev) -{ - u32 deviceaddr, - endptsetupstat, - endptcomplete; - unsigned long timeout; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* Write-Clear the device address */ - deviceaddr = readl(&dev->op_regs->deviceaddr); - writel(deviceaddr & ~USBADR_MASK, &dev->op_regs->deviceaddr); - - dev->dev_addr = 0; - - /* clear usb state */ - dev->resume_state = 0; - - /* LPM L1 to L0, reset */ - if (dev->lpm) - dev->lpm_state = LPM_L0; - - dev->ep0_dir = USB_DIR_OUT; - dev->ep0_state = WAIT_FOR_SETUP; - - /* remote wakeup reset to 0 when the device is reset */ - dev->remote_wakeup = 0; - dev->dev_status = 1 << USB_DEVICE_SELF_POWERED; - dev->gadget.b_hnp_enable = 0; - dev->gadget.a_hnp_support = 0; - dev->gadget.a_alt_hnp_support = 0; - - /* Write-Clear all the setup token semaphores */ - endptsetupstat = readl(&dev->op_regs->endptsetupstat); - writel(endptsetupstat, &dev->op_regs->endptsetupstat); - - /* Write-Clear all the endpoint complete status bits */ - endptcomplete = readl(&dev->op_regs->endptcomplete); - writel(endptcomplete, &dev->op_regs->endptcomplete); - - /* wait until all endptprime bits cleared */ - timeout = jiffies + PRIME_TIMEOUT; - while (readl(&dev->op_regs->endptprime)) { - if (time_after(jiffies, timeout)) { - dev_err(&dev->pdev->dev, "USB reset timeout\n"); - break; - } - cpu_relax(); - } - - /* write 1s to endptflush register to clear any primed buffers */ - writel((u32) ~0, &dev->op_regs->endptflush); - - if (readl(&dev->op_regs->portsc1) & PORTS_PR) { - dev_vdbg(&dev->pdev->dev, "USB bus reset\n"); - /* bus is reseting */ - dev->bus_reset = 1; - - /* reset all the queues, stop all USB activities */ - stop_activity(dev); - dev->usb_state = USB_STATE_DEFAULT; - } else { - dev_vdbg(&dev->pdev->dev, "device controller reset\n"); - /* controller reset */ - langwell_udc_reset(dev); - - /* reset all the queues, stop all USB activities */ - stop_activity(dev); - - /* reset ep0 dQH and endptctrl */ - ep0_reset(dev); - - /* enable interrupt and set controller to run state */ - langwell_udc_start(dev); - - dev->usb_state = USB_STATE_ATTACHED; - } - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* USB bus suspend/resume interrupt */ -static void handle_bus_suspend(struct langwell_udc *dev) -{ - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - dev->resume_state = dev->usb_state; - dev->usb_state = USB_STATE_SUSPENDED; - - /* report suspend to the driver */ - if (dev->driver) { - if (dev->driver->suspend) { - spin_unlock(&dev->lock); - dev->driver->suspend(&dev->gadget); - spin_lock(&dev->lock); - dev_dbg(&dev->pdev->dev, "suspend %s\n", - dev->driver->driver.name); - } - } - - /* enter PHY low power suspend */ - if (dev->pdev->device != 0x0829) - langwell_phy_low_power(dev, 0); - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -static void handle_bus_resume(struct langwell_udc *dev) -{ - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - dev->usb_state = dev->resume_state; - dev->resume_state = 0; - - /* exit PHY low power suspend */ - if (dev->pdev->device != 0x0829) - langwell_phy_low_power(dev, 0); - - /* report resume to the driver */ - if (dev->driver) { - if (dev->driver->resume) { - spin_unlock(&dev->lock); - dev->driver->resume(&dev->gadget); - spin_lock(&dev->lock); - dev_dbg(&dev->pdev->dev, "resume %s\n", - dev->driver->driver.name); - } - } - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* USB device controller interrupt handler */ -static irqreturn_t langwell_irq(int irq, void *_dev) -{ - struct langwell_udc *dev = _dev; - u32 usbsts, - usbintr, - irq_sts, - portsc1; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (dev->stopped) { - dev_vdbg(&dev->pdev->dev, "handle IRQ_NONE\n"); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return IRQ_NONE; - } - - spin_lock(&dev->lock); - - /* USB status */ - usbsts = readl(&dev->op_regs->usbsts); - - /* USB interrupt enable */ - usbintr = readl(&dev->op_regs->usbintr); - - irq_sts = usbsts & usbintr; - dev_vdbg(&dev->pdev->dev, - "usbsts = 0x%08x, usbintr = 0x%08x, irq_sts = 0x%08x\n", - usbsts, usbintr, irq_sts); - - if (!irq_sts) { - dev_vdbg(&dev->pdev->dev, "handle IRQ_NONE\n"); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - spin_unlock(&dev->lock); - return IRQ_NONE; - } - - /* Write-Clear interrupt status bits */ - writel(irq_sts, &dev->op_regs->usbsts); - - /* resume from suspend */ - portsc1 = readl(&dev->op_regs->portsc1); - if (dev->usb_state == USB_STATE_SUSPENDED) - if (!(portsc1 & PORTS_SUSP)) - handle_bus_resume(dev); - - /* USB interrupt */ - if (irq_sts & STS_UI) { - dev_vdbg(&dev->pdev->dev, "USB interrupt\n"); - - /* setup packet received from ep0 */ - if (readl(&dev->op_regs->endptsetupstat) - & EP0SETUPSTAT_MASK) { - dev_vdbg(&dev->pdev->dev, - "USB SETUP packet received interrupt\n"); - /* setup tripwire semaphone */ - setup_tripwire(dev); - handle_setup_packet(dev, &dev->local_setup_buff); - } - - /* USB transfer completion */ - if (readl(&dev->op_regs->endptcomplete)) { - dev_vdbg(&dev->pdev->dev, - "USB transfer completion interrupt\n"); - handle_trans_complete(dev); - } - } - - /* SOF received interrupt (for ISO transfer) */ - if (irq_sts & STS_SRI) { - /* FIXME */ - /* dev_vdbg(&dev->pdev->dev, "SOF received interrupt\n"); */ - } - - /* port change detect interrupt */ - if (irq_sts & STS_PCI) { - dev_vdbg(&dev->pdev->dev, "port change detect interrupt\n"); - handle_port_change(dev); - } - - /* suspend interrupt */ - if (irq_sts & STS_SLI) { - dev_vdbg(&dev->pdev->dev, "suspend interrupt\n"); - handle_bus_suspend(dev); - } - - /* USB reset interrupt */ - if (irq_sts & STS_URI) { - dev_vdbg(&dev->pdev->dev, "USB reset interrupt\n"); - handle_usb_reset(dev); - } - - /* USB error or system error interrupt */ - if (irq_sts & (STS_UEI | STS_SEI)) { - /* FIXME */ - dev_warn(&dev->pdev->dev, "error IRQ, irq_sts: %x\n", irq_sts); - } - - spin_unlock(&dev->lock); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return IRQ_HANDLED; -} - - -/*-------------------------------------------------------------------------*/ - -/* release device structure */ -static void gadget_release(struct device *_dev) -{ - struct langwell_udc *dev = dev_get_drvdata(_dev); - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - complete(dev->done); - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - kfree(dev); -} - - -/* enable SRAM caching if SRAM detected */ -static void sram_init(struct langwell_udc *dev) -{ - struct pci_dev *pdev = dev->pdev; - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - dev->sram_addr = pci_resource_start(pdev, 1); - dev->sram_size = pci_resource_len(pdev, 1); - dev_info(&dev->pdev->dev, "Found private SRAM at %x size:%x\n", - dev->sram_addr, dev->sram_size); - dev->got_sram = 1; - - if (pci_request_region(pdev, 1, kobject_name(&pdev->dev.kobj))) { - dev_warn(&dev->pdev->dev, "SRAM request failed\n"); - dev->got_sram = 0; - } else if (!dma_declare_coherent_memory(&pdev->dev, dev->sram_addr, - dev->sram_addr, dev->sram_size, DMA_MEMORY_MAP)) { - dev_warn(&dev->pdev->dev, "SRAM DMA declare failed\n"); - pci_release_region(pdev, 1); - dev->got_sram = 0; - } - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* release SRAM caching */ -static void sram_deinit(struct langwell_udc *dev) -{ - struct pci_dev *pdev = dev->pdev; - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - dma_release_declared_memory(&pdev->dev); - pci_release_region(pdev, 1); - - dev->got_sram = 0; - - dev_info(&dev->pdev->dev, "release SRAM caching\n"); - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* tear down the binding between this driver and the pci device */ -static void langwell_udc_remove(struct pci_dev *pdev) -{ - struct langwell_udc *dev = pci_get_drvdata(pdev); - - DECLARE_COMPLETION(done); - - BUG_ON(dev->driver); - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - dev->done = &done; - - /* free dTD dma_pool and dQH */ - if (dev->dtd_pool) - dma_pool_destroy(dev->dtd_pool); - - if (dev->ep_dqh) - dma_free_coherent(&pdev->dev, dev->ep_dqh_size, - dev->ep_dqh, dev->ep_dqh_dma); - - /* release SRAM caching */ - if (dev->has_sram && dev->got_sram) - sram_deinit(dev); - - if (dev->status_req) { - kfree(dev->status_req->req.buf); - kfree(dev->status_req); - } - - kfree(dev->ep); - - /* disable IRQ handler */ - if (dev->got_irq) - free_irq(pdev->irq, dev); - - if (dev->cap_regs) - iounmap(dev->cap_regs); - - if (dev->region) - release_mem_region(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - - if (dev->enabled) - pci_disable_device(pdev); - - dev->cap_regs = NULL; - - dev_info(&dev->pdev->dev, "unbind\n"); - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - - device_unregister(&dev->gadget.dev); - device_remove_file(&pdev->dev, &dev_attr_langwell_udc); - device_remove_file(&pdev->dev, &dev_attr_remote_wakeup); - - pci_set_drvdata(pdev, NULL); - - /* free dev, wait for the release() finished */ - wait_for_completion(&done); -} - - -/* - * wrap this driver around the specified device, but - * don't respond over USB until a gadget driver binds to us. - */ -static int langwell_udc_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - struct langwell_udc *dev; - unsigned long resource, len; - void __iomem *base = NULL; - size_t size; - int retval; - - /* alloc, and start init */ - dev = kzalloc(sizeof *dev, GFP_KERNEL); - if (dev == NULL) { - retval = -ENOMEM; - goto error; - } - - /* initialize device spinlock */ - spin_lock_init(&dev->lock); - - dev->pdev = pdev; - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - pci_set_drvdata(pdev, dev); - - /* now all the pci goodies ... */ - if (pci_enable_device(pdev) < 0) { - retval = -ENODEV; - goto error; - } - dev->enabled = 1; - - /* control register: BAR 0 */ - resource = pci_resource_start(pdev, 0); - len = pci_resource_len(pdev, 0); - if (!request_mem_region(resource, len, driver_name)) { - dev_err(&dev->pdev->dev, "controller already in use\n"); - retval = -EBUSY; - goto error; - } - dev->region = 1; - - base = ioremap_nocache(resource, len); - if (base == NULL) { - dev_err(&dev->pdev->dev, "can't map memory\n"); - retval = -EFAULT; - goto error; - } - - dev->cap_regs = (struct langwell_cap_regs __iomem *) base; - dev_vdbg(&dev->pdev->dev, "dev->cap_regs: %p\n", dev->cap_regs); - dev->op_regs = (struct langwell_op_regs __iomem *) - (base + OP_REG_OFFSET); - dev_vdbg(&dev->pdev->dev, "dev->op_regs: %p\n", dev->op_regs); - - /* irq setup after old hardware is cleaned up */ - if (!pdev->irq) { - dev_err(&dev->pdev->dev, "No IRQ. Check PCI setup!\n"); - retval = -ENODEV; - goto error; - } - - dev->has_sram = 1; - dev->got_sram = 0; - dev_vdbg(&dev->pdev->dev, "dev->has_sram: %d\n", dev->has_sram); - - /* enable SRAM caching if detected */ - if (dev->has_sram && !dev->got_sram) - sram_init(dev); - - dev_info(&dev->pdev->dev, - "irq %d, io mem: 0x%08lx, len: 0x%08lx, pci mem 0x%p\n", - pdev->irq, resource, len, base); - /* enables bus-mastering for device dev */ - pci_set_master(pdev); - - if (request_irq(pdev->irq, langwell_irq, IRQF_SHARED, - driver_name, dev) != 0) { - dev_err(&dev->pdev->dev, - "request interrupt %d failed\n", pdev->irq); - retval = -EBUSY; - goto error; - } - dev->got_irq = 1; - - /* set stopped bit */ - dev->stopped = 1; - - /* capabilities and endpoint number */ - dev->lpm = (readl(&dev->cap_regs->hccparams) & HCC_LEN) ? 1 : 0; - dev->dciversion = readw(&dev->cap_regs->dciversion); - dev->devcap = (readl(&dev->cap_regs->dccparams) & DEVCAP) ? 1 : 0; - dev_vdbg(&dev->pdev->dev, "dev->lpm: %d\n", dev->lpm); - dev_vdbg(&dev->pdev->dev, "dev->dciversion: 0x%04x\n", - dev->dciversion); - dev_vdbg(&dev->pdev->dev, "dccparams: 0x%08x\n", - readl(&dev->cap_regs->dccparams)); - dev_vdbg(&dev->pdev->dev, "dev->devcap: %d\n", dev->devcap); - if (!dev->devcap) { - dev_err(&dev->pdev->dev, "can't support device mode\n"); - retval = -ENODEV; - goto error; - } - - /* a pair of endpoints (out/in) for each address */ - dev->ep_max = DEN(readl(&dev->cap_regs->dccparams)) * 2; - dev_vdbg(&dev->pdev->dev, "dev->ep_max: %d\n", dev->ep_max); - - /* allocate endpoints memory */ - dev->ep = kzalloc(sizeof(struct langwell_ep) * dev->ep_max, - GFP_KERNEL); - if (!dev->ep) { - dev_err(&dev->pdev->dev, "allocate endpoints memory failed\n"); - retval = -ENOMEM; - goto error; - } - - /* allocate device dQH memory */ - size = dev->ep_max * sizeof(struct langwell_dqh); - dev_vdbg(&dev->pdev->dev, "orig size = %zd\n", size); - if (size < DQH_ALIGNMENT) - size = DQH_ALIGNMENT; - else if ((size % DQH_ALIGNMENT) != 0) { - size += DQH_ALIGNMENT + 1; - size &= ~(DQH_ALIGNMENT - 1); - } - dev->ep_dqh = dma_alloc_coherent(&pdev->dev, size, - &dev->ep_dqh_dma, GFP_KERNEL); - if (!dev->ep_dqh) { - dev_err(&dev->pdev->dev, "allocate dQH memory failed\n"); - retval = -ENOMEM; - goto error; - } - dev->ep_dqh_size = size; - dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %zd\n", dev->ep_dqh_size); - - /* initialize ep0 status request structure */ - dev->status_req = kzalloc(sizeof(struct langwell_request), GFP_KERNEL); - if (!dev->status_req) { - dev_err(&dev->pdev->dev, - "allocate status_req memory failed\n"); - retval = -ENOMEM; - goto error; - } - INIT_LIST_HEAD(&dev->status_req->queue); - - /* allocate a small amount of memory to get valid address */ - dev->status_req->req.buf = kmalloc(8, GFP_KERNEL); - dev->status_req->req.dma = virt_to_phys(dev->status_req->req.buf); - - dev->resume_state = USB_STATE_NOTATTACHED; - dev->usb_state = USB_STATE_POWERED; - dev->ep0_dir = USB_DIR_OUT; - - /* remote wakeup reset to 0 when the device is reset */ - dev->remote_wakeup = 0; - dev->dev_status = 1 << USB_DEVICE_SELF_POWERED; - - /* reset device controller */ - langwell_udc_reset(dev); - - /* initialize gadget structure */ - dev->gadget.ops = &langwell_ops; /* usb_gadget_ops */ - dev->gadget.ep0 = &dev->ep[0].ep; /* gadget ep0 */ - INIT_LIST_HEAD(&dev->gadget.ep_list); /* ep_list */ - dev->gadget.speed = USB_SPEED_UNKNOWN; /* speed */ - dev->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */ - - /* the "gadget" abstracts/virtualizes the controller */ - dev_set_name(&dev->gadget.dev, "gadget"); - dev->gadget.dev.parent = &pdev->dev; - dev->gadget.dev.dma_mask = pdev->dev.dma_mask; - dev->gadget.dev.release = gadget_release; - dev->gadget.name = driver_name; /* gadget name */ - - /* controller endpoints reinit */ - eps_reinit(dev); - - /* reset ep0 dQH and endptctrl */ - ep0_reset(dev); - - /* create dTD dma_pool resource */ - dev->dtd_pool = dma_pool_create("langwell_dtd", - &dev->pdev->dev, - sizeof(struct langwell_dtd), - DTD_ALIGNMENT, - DMA_BOUNDARY); - - if (!dev->dtd_pool) { - retval = -ENOMEM; - goto error; - } - - /* done */ - dev_info(&dev->pdev->dev, "%s\n", driver_desc); - dev_info(&dev->pdev->dev, "irq %d, pci mem %p\n", pdev->irq, base); - dev_info(&dev->pdev->dev, "Driver version: " DRIVER_VERSION "\n"); - dev_info(&dev->pdev->dev, "Support (max) %d endpoints\n", dev->ep_max); - dev_info(&dev->pdev->dev, "Device interface version: 0x%04x\n", - dev->dciversion); - dev_info(&dev->pdev->dev, "Controller mode: %s\n", - dev->devcap ? "Device" : "Host"); - dev_info(&dev->pdev->dev, "Support USB LPM: %s\n", - dev->lpm ? "Yes" : "No"); - - dev_vdbg(&dev->pdev->dev, - "After langwell_udc_probe(), print all registers:\n"); - print_all_registers(dev); - - retval = device_register(&dev->gadget.dev); - if (retval) - goto error; - - retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); - if (retval) - goto error; - - retval = device_create_file(&pdev->dev, &dev_attr_langwell_udc); - if (retval) - goto error; - - retval = device_create_file(&pdev->dev, &dev_attr_remote_wakeup); - if (retval) - goto error_attr1; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; - -error_attr1: - device_remove_file(&pdev->dev, &dev_attr_langwell_udc); -error: - if (dev) { - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - langwell_udc_remove(pdev); - } - - return retval; -} - - -/* device controller suspend */ -static int langwell_udc_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct langwell_udc *dev = pci_get_drvdata(pdev); - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - usb_del_gadget_udc(&dev->gadget); - /* disable interrupt and set controller to stop state */ - langwell_udc_stop(dev); - - /* disable IRQ handler */ - if (dev->got_irq) - free_irq(pdev->irq, dev); - dev->got_irq = 0; - - /* save PCI state */ - pci_save_state(pdev); - - spin_lock_irq(&dev->lock); - /* stop all usb activities */ - stop_activity(dev); - spin_unlock_irq(&dev->lock); - - /* free dTD dma_pool and dQH */ - if (dev->dtd_pool) - dma_pool_destroy(dev->dtd_pool); - - if (dev->ep_dqh) - dma_free_coherent(&pdev->dev, dev->ep_dqh_size, - dev->ep_dqh, dev->ep_dqh_dma); - - /* release SRAM caching */ - if (dev->has_sram && dev->got_sram) - sram_deinit(dev); - - /* set device power state */ - pci_set_power_state(pdev, PCI_D3hot); - - /* enter PHY low power suspend */ - if (dev->pdev->device != 0x0829) - langwell_phy_low_power(dev, 1); - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* device controller resume */ -static int langwell_udc_resume(struct pci_dev *pdev) -{ - struct langwell_udc *dev = pci_get_drvdata(pdev); - size_t size; - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* exit PHY low power suspend */ - if (dev->pdev->device != 0x0829) - langwell_phy_low_power(dev, 0); - - /* set device D0 power state */ - pci_set_power_state(pdev, PCI_D0); - - /* enable SRAM caching if detected */ - if (dev->has_sram && !dev->got_sram) - sram_init(dev); - - /* allocate device dQH memory */ - size = dev->ep_max * sizeof(struct langwell_dqh); - dev_vdbg(&dev->pdev->dev, "orig size = %zd\n", size); - if (size < DQH_ALIGNMENT) - size = DQH_ALIGNMENT; - else if ((size % DQH_ALIGNMENT) != 0) { - size += DQH_ALIGNMENT + 1; - size &= ~(DQH_ALIGNMENT - 1); - } - dev->ep_dqh = dma_alloc_coherent(&pdev->dev, size, - &dev->ep_dqh_dma, GFP_KERNEL); - if (!dev->ep_dqh) { - dev_err(&dev->pdev->dev, "allocate dQH memory failed\n"); - return -ENOMEM; - } - dev->ep_dqh_size = size; - dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %zd\n", dev->ep_dqh_size); - - /* create dTD dma_pool resource */ - dev->dtd_pool = dma_pool_create("langwell_dtd", - &dev->pdev->dev, - sizeof(struct langwell_dtd), - DTD_ALIGNMENT, - DMA_BOUNDARY); - - if (!dev->dtd_pool) - return -ENOMEM; - - /* restore PCI state */ - pci_restore_state(pdev); - - /* enable IRQ handler */ - if (request_irq(pdev->irq, langwell_irq, IRQF_SHARED, - driver_name, dev) != 0) { - dev_err(&dev->pdev->dev, "request interrupt %d failed\n", - pdev->irq); - return -EBUSY; - } - dev->got_irq = 1; - - /* reset and start controller to run state */ - if (dev->stopped) { - /* reset device controller */ - langwell_udc_reset(dev); - - /* reset ep0 dQH and endptctrl */ - ep0_reset(dev); - - /* start device if gadget is loaded */ - if (dev->driver) - langwell_udc_start(dev); - } - - /* reset USB status */ - dev->usb_state = USB_STATE_ATTACHED; - dev->ep0_state = WAIT_FOR_SETUP; - dev->ep0_dir = USB_DIR_OUT; - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* pci driver shutdown */ -static void langwell_udc_shutdown(struct pci_dev *pdev) -{ - struct langwell_udc *dev = pci_get_drvdata(pdev); - u32 usbmode; - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* reset controller mode to IDLE */ - usbmode = readl(&dev->op_regs->usbmode); - dev_dbg(&dev->pdev->dev, "usbmode = 0x%08x\n", usbmode); - usbmode &= (~3 | MODE_IDLE); - writel(usbmode, &dev->op_regs->usbmode); - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - -/*-------------------------------------------------------------------------*/ - -static const struct pci_device_id pci_ids[] = { { - .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), - .class_mask = ~0, - .vendor = 0x8086, - .device = 0x0811, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, -}, { /* end: all zeroes */ } -}; - -MODULE_DEVICE_TABLE(pci, pci_ids); - - -static struct pci_driver langwell_pci_driver = { - .name = (char *) driver_name, - .id_table = pci_ids, - - .probe = langwell_udc_probe, - .remove = langwell_udc_remove, - - /* device controller suspend/resume */ - .suspend = langwell_udc_suspend, - .resume = langwell_udc_resume, - - .shutdown = langwell_udc_shutdown, -}; - - -static int __init init(void) -{ - return pci_register_driver(&langwell_pci_driver); -} -module_init(init); - - -static void __exit cleanup(void) -{ - pci_unregister_driver(&langwell_pci_driver); -} -module_exit(cleanup); - - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("Xiaochen Shen "); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); - diff --git a/trunk/drivers/usb/gadget/langwell_udc.h b/trunk/drivers/usb/gadget/langwell_udc.h deleted file mode 100644 index 8c8087abb481..000000000000 --- a/trunk/drivers/usb/gadget/langwell_udc.h +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Intel Langwell USB Device Controller driver - * Copyright (C) 2008-2009, 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. - */ - -#include - -/*-------------------------------------------------------------------------*/ - -/* driver data structures and utilities */ - -/* - * dTD: Device Endpoint Transfer Descriptor - * describe to the device controller the location and quantity of - * data to be send/received for given transfer - */ -struct langwell_dtd { - u32 dtd_next; -/* bits 31:5, next transfer element pointer */ -#define DTD_NEXT(d) (((d)>>5)&0x7ffffff) -#define DTD_NEXT_MASK (0x7ffffff << 5) -/* terminate */ -#define DTD_TERM BIT(0) - /* bits 7:0, execution back states */ - u32 dtd_status:8; -#define DTD_STATUS(d) (((d)>>0)&0xff) -#define DTD_STS_ACTIVE BIT(7) /* active */ -#define DTD_STS_HALTED BIT(6) /* halted */ -#define DTD_STS_DBE BIT(5) /* data buffer error */ -#define DTD_STS_TRE BIT(3) /* transaction error */ - /* bits 9:8 */ - u32 dtd_res0:2; - /* bits 11:10, multipier override */ - u32 dtd_multo:2; -#define DTD_MULTO (BIT(11) | BIT(10)) - /* bits 14:12 */ - u32 dtd_res1:3; - /* bit 15, interrupt on complete */ - u32 dtd_ioc:1; -#define DTD_IOC BIT(15) - /* bits 30:16, total bytes */ - u32 dtd_total:15; -#define DTD_TOTAL(d) (((d)>>16)&0x7fff) -#define DTD_MAX_TRANSFER_LENGTH 0x4000 - /* bit 31 */ - u32 dtd_res2:1; - /* dTD buffer pointer page 0 to 4 */ - u32 dtd_buf[5]; -#define DTD_OFFSET_MASK 0xfff -/* bits 31:12, buffer pointer */ -#define DTD_BUFFER(d) (((d)>>12)&0x3ff) -/* bits 11:0, current offset */ -#define DTD_C_OFFSET(d) (((d)>>0)&0xfff) -/* bits 10:0, frame number */ -#define DTD_FRAME(d) (((d)>>0)&0x7ff) - - /* driver-private parts */ - - /* dtd dma address */ - dma_addr_t dtd_dma; - /* next dtd virtual address */ - struct langwell_dtd *next_dtd_virt; -}; - - -/* - * dQH: Device Endpoint Queue Head - * describe where all transfers are managed - * 48-byte data structure, aligned on 64-byte boundary - * - * These are associated with dTD structure - */ -struct langwell_dqh { - /* endpoint capabilities and characteristics */ - u32 dqh_res0:15; /* bits 14:0 */ - u32 dqh_ios:1; /* bit 15, interrupt on setup */ -#define DQH_IOS BIT(15) - u32 dqh_mpl:11; /* bits 26:16, maximum packet length */ -#define DQH_MPL (0x7ff << 16) - u32 dqh_res1:2; /* bits 28:27 */ - u32 dqh_zlt:1; /* bit 29, zero length termination */ -#define DQH_ZLT BIT(29) - u32 dqh_mult:2; /* bits 31:30 */ -#define DQH_MULT (BIT(30) | BIT(31)) - - /* current dTD pointer */ - u32 dqh_current; /* locate the transfer in progress */ -#define DQH_C_DTD(e) \ - (((e)>>5)&0x7ffffff) /* bits 31:5, current dTD pointer */ - - /* transfer overlay, hardware parts of a struct langwell_dtd */ - u32 dtd_next; - u32 dtd_status:8; /* bits 7:0, execution back states */ - u32 dtd_res0:2; /* bits 9:8 */ - u32 dtd_multo:2; /* bits 11:10, multipier override */ - u32 dtd_res1:3; /* bits 14:12 */ - u32 dtd_ioc:1; /* bit 15, interrupt on complete */ - u32 dtd_total:15; /* bits 30:16, total bytes */ - u32 dtd_res2:1; /* bit 31 */ - u32 dtd_buf[5]; /* dTD buffer pointer page 0 to 4 */ - - u32 dqh_res2; - struct usb_ctrlrequest dqh_setup; /* setup packet buffer */ -} __attribute__ ((aligned(64))); - - -/* endpoint data structure */ -struct langwell_ep { - struct usb_ep ep; - dma_addr_t dma; - struct langwell_udc *dev; - unsigned long irqs; - struct list_head queue; - struct langwell_dqh *dqh; - const struct usb_endpoint_descriptor *desc; - char name[14]; - unsigned stopped:1, - ep_type:2, - ep_num:8; -}; - - -/* request data structure */ -struct langwell_request { - struct usb_request req; - struct langwell_dtd *dtd, *head, *tail; - struct langwell_ep *ep; - dma_addr_t dtd_dma; - struct list_head queue; - unsigned dtd_count; - unsigned mapped:1; -}; - - -/* ep0 transfer state */ -enum ep0_state { - WAIT_FOR_SETUP, - DATA_STATE_XMIT, - DATA_STATE_NEED_ZLP, - WAIT_FOR_OUT_STATUS, - DATA_STATE_RECV, -}; - - -/* device suspend state */ -enum lpm_state { - LPM_L0, /* on */ - LPM_L1, /* LPM L1 sleep */ - LPM_L2, /* suspend */ - LPM_L3, /* off */ -}; - - -/* device data structure */ -struct langwell_udc { - /* each pci device provides one gadget, several endpoints */ - struct usb_gadget gadget; - spinlock_t lock; /* device lock */ - struct langwell_ep *ep; - struct usb_gadget_driver *driver; - struct usb_phy *transceiver; - u8 dev_addr; - u32 usb_state; - u32 resume_state; - u32 bus_reset; - enum lpm_state lpm_state; - enum ep0_state ep0_state; - u32 ep0_dir; - u16 dciversion; - unsigned ep_max; - unsigned devcap:1, - enabled:1, - region:1, - got_irq:1, - powered:1, - remote_wakeup:1, - rate:1, - is_reset:1, - softconnected:1, - vbus_active:1, - suspended:1, - stopped:1, - lpm:1, /* LPM capability */ - has_sram:1, /* SRAM caching */ - got_sram:1; - - /* pci state used to access those endpoints */ - struct pci_dev *pdev; - - /* Langwell otg transceiver */ - struct langwell_otg *lotg; - - /* control registers */ - struct langwell_cap_regs __iomem *cap_regs; - struct langwell_op_regs __iomem *op_regs; - - struct usb_ctrlrequest local_setup_buff; - struct langwell_dqh *ep_dqh; - size_t ep_dqh_size; - dma_addr_t ep_dqh_dma; - - /* ep0 status request */ - struct langwell_request *status_req; - - /* dma pool */ - struct dma_pool *dtd_pool; - - /* make sure release() is done */ - struct completion *done; - - /* for private SRAM caching */ - unsigned int sram_addr; - unsigned int sram_size; - - /* device status data for get_status request */ - u16 dev_status; -}; - -#define gadget_to_langwell(g) container_of((g), struct langwell_udc, gadget) - diff --git a/trunk/drivers/usb/gadget/lpc32xx_udc.c b/trunk/drivers/usb/gadget/lpc32xx_udc.c new file mode 100644 index 000000000000..262acfd53e32 --- /dev/null +++ b/trunk/drivers/usb/gadget/lpc32xx_udc.c @@ -0,0 +1,3538 @@ +/* + * USB Gadget driver for LPC32xx + * + * Authors: + * Kevin Wells + * Mike James + * Roland Stigge + * + * Copyright (C) 2006 Philips Semiconductors + * Copyright (C) 2009 NXP Semiconductors + * Copyright (C) 2012 Roland Stigge + * + * Note: This driver is based on original work done by Mike James for + * the LPC3180. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#ifdef CONFIG_USB_GADGET_DEBUG_FILES +#include +#endif + +/* + * USB device configuration structure + */ +typedef void (*usc_chg_event)(int); +struct lpc32xx_usbd_cfg { + int vbus_drv_pol; /* 0=active low drive for VBUS via ISP1301 */ + usc_chg_event conn_chgb; /* Connection change event (optional) */ + usc_chg_event susp_chgb; /* Suspend/resume event (optional) */ + usc_chg_event rmwk_chgb; /* Enable/disable remote wakeup */ +}; + +/* + * controller driver data structures + */ + +/* 16 endpoints (not to be confused with 32 hardware endpoints) */ +#define NUM_ENDPOINTS 16 + +/* + * IRQ indices make reading the code a little easier + */ +#define IRQ_USB_LP 0 +#define IRQ_USB_HP 1 +#define IRQ_USB_DEVDMA 2 +#define IRQ_USB_ATX 3 + +#define EP_OUT 0 /* RX (from host) */ +#define EP_IN 1 /* TX (to host) */ + +/* Returns the interrupt mask for the selected hardware endpoint */ +#define EP_MASK_SEL(ep, dir) (1 << (((ep) * 2) + dir)) + +#define EP_INT_TYPE 0 +#define EP_ISO_TYPE 1 +#define EP_BLK_TYPE 2 +#define EP_CTL_TYPE 3 + +/* EP0 states */ +#define WAIT_FOR_SETUP 0 /* Wait for setup packet */ +#define DATA_IN 1 /* Expect dev->host transfer */ +#define DATA_OUT 2 /* Expect host->dev transfer */ + +/* DD (DMA Descriptor) structure, requires word alignment, this is already + * defined in the LPC32XX USB device header file, but this version is slightly + * modified to tag some work data with each DMA descriptor. */ +struct lpc32xx_usbd_dd_gad { + u32 dd_next_phy; + u32 dd_setup; + u32 dd_buffer_addr; + u32 dd_status; + u32 dd_iso_ps_mem_addr; + u32 this_dma; + u32 iso_status[6]; /* 5 spare */ + u32 dd_next_v; +}; + +/* + * Logical endpoint structure + */ +struct lpc32xx_ep { + struct usb_ep ep; + struct list_head queue; + struct lpc32xx_udc *udc; + + u32 hwep_num_base; /* Physical hardware EP */ + u32 hwep_num; /* Maps to hardware endpoint */ + u32 maxpacket; + u32 lep; + + bool is_in; + bool req_pending; + u32 eptype; + + u32 totalints; + + bool wedge; + + const struct usb_endpoint_descriptor *desc; +}; + +/* + * Common UDC structure + */ +struct lpc32xx_udc { + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + struct platform_device *pdev; + struct device *dev; + struct dentry *pde; + spinlock_t lock; + struct i2c_client *isp1301_i2c_client; + + /* Board and device specific */ + struct lpc32xx_usbd_cfg *board; + u32 io_p_start; + u32 io_p_size; + void __iomem *udp_baseaddr; + int udp_irq[4]; + struct clk *usb_pll_clk; + struct clk *usb_slv_clk; + + /* DMA support */ + u32 *udca_v_base; + u32 udca_p_base; + struct dma_pool *dd_cache; + + /* Common EP and control data */ + u32 enabled_devints; + u32 enabled_hwepints; + u32 dev_status; + u32 realized_eps; + + /* VBUS detection, pullup, and power flags */ + u8 vbus; + u8 last_vbus; + int pullup; + int poweron; + + /* Work queues related to I2C support */ + struct work_struct pullup_job; + struct work_struct vbus_job; + struct work_struct power_job; + + /* USB device peripheral - various */ + struct lpc32xx_ep ep[NUM_ENDPOINTS]; + bool enabled; + bool clocked; + bool suspended; + bool selfpowered; + int ep0state; + atomic_t enabled_ep_cnt; + wait_queue_head_t ep_disable_wait_queue; +}; + +/* + * Endpoint request + */ +struct lpc32xx_request { + struct usb_request req; + struct list_head queue; + struct lpc32xx_usbd_dd_gad *dd_desc_ptr; + bool mapped; + bool send_zlp; +}; + +static inline struct lpc32xx_udc *to_udc(struct usb_gadget *g) +{ + return container_of(g, struct lpc32xx_udc, gadget); +} + +#define ep_dbg(epp, fmt, arg...) \ + dev_dbg(epp->udc->dev, "%s: " fmt, __func__, ## arg) +#define ep_err(epp, fmt, arg...) \ + dev_err(epp->udc->dev, "%s: " fmt, __func__, ## arg) +#define ep_info(epp, fmt, arg...) \ + dev_info(epp->udc->dev, "%s: " fmt, __func__, ## arg) +#define ep_warn(epp, fmt, arg...) \ + dev_warn(epp->udc->dev, "%s:" fmt, __func__, ## arg) + +#define UDCA_BUFF_SIZE (128) + +/* TODO: When the clock framework is introduced in LPC32xx, IO_ADDRESS will + * be replaced with an inremap()ed pointer, see USB_OTG_CLK_CTRL() + * */ +#define USB_CTRL IO_ADDRESS(LPC32XX_CLK_PM_BASE + 0x64) +#define USB_CLOCK_MASK (AHB_M_CLOCK_ON | OTG_CLOCK_ON | \ + DEV_CLOCK_ON | I2C_CLOCK_ON) + +/* USB_CTRL bit defines */ +#define USB_SLAVE_HCLK_EN (1 << 24) +#define USB_HOST_NEED_CLK_EN (1 << 21) +#define USB_DEV_NEED_CLK_EN (1 << 22) + +#define USB_OTG_CLK_CTRL(udc) ((udc)->udp_baseaddr + 0xFF4) +#define USB_OTG_CLK_STAT(udc) ((udc)->udp_baseaddr + 0xFF8) + +/* USB_OTG_CLK_CTRL bit defines */ +#define AHB_M_CLOCK_ON (1 << 4) +#define OTG_CLOCK_ON (1 << 3) +#define I2C_CLOCK_ON (1 << 2) +#define DEV_CLOCK_ON (1 << 1) +#define HOST_CLOCK_ON (1 << 0) + +#define USB_OTG_STAT_CONTROL(udc) (udc->udp_baseaddr + 0x110) + +/* USB_OTG_STAT_CONTROL bit defines */ +#define TRANSPARENT_I2C_EN (1 << 7) +#define HOST_EN (1 << 0) + +/********************************************************************** + * USB device controller register offsets + **********************************************************************/ + +#define USBD_DEVINTST(x) ((x) + 0x200) +#define USBD_DEVINTEN(x) ((x) + 0x204) +#define USBD_DEVINTCLR(x) ((x) + 0x208) +#define USBD_DEVINTSET(x) ((x) + 0x20C) +#define USBD_CMDCODE(x) ((x) + 0x210) +#define USBD_CMDDATA(x) ((x) + 0x214) +#define USBD_RXDATA(x) ((x) + 0x218) +#define USBD_TXDATA(x) ((x) + 0x21C) +#define USBD_RXPLEN(x) ((x) + 0x220) +#define USBD_TXPLEN(x) ((x) + 0x224) +#define USBD_CTRL(x) ((x) + 0x228) +#define USBD_DEVINTPRI(x) ((x) + 0x22C) +#define USBD_EPINTST(x) ((x) + 0x230) +#define USBD_EPINTEN(x) ((x) + 0x234) +#define USBD_EPINTCLR(x) ((x) + 0x238) +#define USBD_EPINTSET(x) ((x) + 0x23C) +#define USBD_EPINTPRI(x) ((x) + 0x240) +#define USBD_REEP(x) ((x) + 0x244) +#define USBD_EPIND(x) ((x) + 0x248) +#define USBD_EPMAXPSIZE(x) ((x) + 0x24C) +/* DMA support registers only below */ +/* Set, clear, or get enabled state of the DMA request status. If + * enabled, an IN or OUT token will start a DMA transfer for the EP */ +#define USBD_DMARST(x) ((x) + 0x250) +#define USBD_DMARCLR(x) ((x) + 0x254) +#define USBD_DMARSET(x) ((x) + 0x258) +/* DMA UDCA head pointer */ +#define USBD_UDCAH(x) ((x) + 0x280) +/* EP DMA status, enable, and disable. This is used to specifically + * enabled or disable DMA for a specific EP */ +#define USBD_EPDMAST(x) ((x) + 0x284) +#define USBD_EPDMAEN(x) ((x) + 0x288) +#define USBD_EPDMADIS(x) ((x) + 0x28C) +/* DMA master interrupts enable and pending interrupts */ +#define USBD_DMAINTST(x) ((x) + 0x290) +#define USBD_DMAINTEN(x) ((x) + 0x294) +/* DMA end of transfer interrupt enable, disable, status */ +#define USBD_EOTINTST(x) ((x) + 0x2A0) +#define USBD_EOTINTCLR(x) ((x) + 0x2A4) +#define USBD_EOTINTSET(x) ((x) + 0x2A8) +/* New DD request interrupt enable, disable, status */ +#define USBD_NDDRTINTST(x) ((x) + 0x2AC) +#define USBD_NDDRTINTCLR(x) ((x) + 0x2B0) +#define USBD_NDDRTINTSET(x) ((x) + 0x2B4) +/* DMA error interrupt enable, disable, status */ +#define USBD_SYSERRTINTST(x) ((x) + 0x2B8) +#define USBD_SYSERRTINTCLR(x) ((x) + 0x2BC) +#define USBD_SYSERRTINTSET(x) ((x) + 0x2C0) + +/********************************************************************** + * USBD_DEVINTST/USBD_DEVINTEN/USBD_DEVINTCLR/USBD_DEVINTSET/ + * USBD_DEVINTPRI register definitions + **********************************************************************/ +#define USBD_ERR_INT (1 << 9) +#define USBD_EP_RLZED (1 << 8) +#define USBD_TXENDPKT (1 << 7) +#define USBD_RXENDPKT (1 << 6) +#define USBD_CDFULL (1 << 5) +#define USBD_CCEMPTY (1 << 4) +#define USBD_DEV_STAT (1 << 3) +#define USBD_EP_SLOW (1 << 2) +#define USBD_EP_FAST (1 << 1) +#define USBD_FRAME (1 << 0) + +/********************************************************************** + * USBD_EPINTST/USBD_EPINTEN/USBD_EPINTCLR/USBD_EPINTSET/ + * USBD_EPINTPRI register definitions + **********************************************************************/ +/* End point selection macro (RX) */ +#define USBD_RX_EP_SEL(e) (1 << ((e) << 1)) + +/* End point selection macro (TX) */ +#define USBD_TX_EP_SEL(e) (1 << (((e) << 1) + 1)) + +/********************************************************************** + * USBD_REEP/USBD_DMARST/USBD_DMARCLR/USBD_DMARSET/USBD_EPDMAST/ + * USBD_EPDMAEN/USBD_EPDMADIS/ + * USBD_NDDRTINTST/USBD_NDDRTINTCLR/USBD_NDDRTINTSET/ + * USBD_EOTINTST/USBD_EOTINTCLR/USBD_EOTINTSET/ + * USBD_SYSERRTINTST/USBD_SYSERRTINTCLR/USBD_SYSERRTINTSET + * register definitions + **********************************************************************/ +/* Endpoint selection macro */ +#define USBD_EP_SEL(e) (1 << (e)) + +/********************************************************************** + * SBD_DMAINTST/USBD_DMAINTEN + **********************************************************************/ +#define USBD_SYS_ERR_INT (1 << 2) +#define USBD_NEW_DD_INT (1 << 1) +#define USBD_EOT_INT (1 << 0) + +/********************************************************************** + * USBD_RXPLEN register definitions + **********************************************************************/ +#define USBD_PKT_RDY (1 << 11) +#define USBD_DV (1 << 10) +#define USBD_PK_LEN_MASK 0x3FF + +/********************************************************************** + * USBD_CTRL register definitions + **********************************************************************/ +#define USBD_LOG_ENDPOINT(e) ((e) << 2) +#define USBD_WR_EN (1 << 1) +#define USBD_RD_EN (1 << 0) + +/********************************************************************** + * USBD_CMDCODE register definitions + **********************************************************************/ +#define USBD_CMD_CODE(c) ((c) << 16) +#define USBD_CMD_PHASE(p) ((p) << 8) + +/********************************************************************** + * USBD_DMARST/USBD_DMARCLR/USBD_DMARSET register definitions + **********************************************************************/ +#define USBD_DMAEP(e) (1 << (e)) + +/* DD (DMA Descriptor) structure, requires word alignment */ +struct lpc32xx_usbd_dd { + u32 *dd_next; + u32 dd_setup; + u32 dd_buffer_addr; + u32 dd_status; + u32 dd_iso_ps_mem_addr; +}; + +/* dd_setup bit defines */ +#define DD_SETUP_ATLE_DMA_MODE 0x01 +#define DD_SETUP_NEXT_DD_VALID 0x04 +#define DD_SETUP_ISO_EP 0x10 +#define DD_SETUP_PACKETLEN(n) (((n) & 0x7FF) << 5) +#define DD_SETUP_DMALENBYTES(n) (((n) & 0xFFFF) << 16) + +/* dd_status bit defines */ +#define DD_STATUS_DD_RETIRED 0x01 +#define DD_STATUS_STS_MASK 0x1E +#define DD_STATUS_STS_NS 0x00 /* Not serviced */ +#define DD_STATUS_STS_BS 0x02 /* Being serviced */ +#define DD_STATUS_STS_NC 0x04 /* Normal completion */ +#define DD_STATUS_STS_DUR 0x06 /* Data underrun (short packet) */ +#define DD_STATUS_STS_DOR 0x08 /* Data overrun */ +#define DD_STATUS_STS_SE 0x12 /* System error */ +#define DD_STATUS_PKT_VAL 0x20 /* Packet valid */ +#define DD_STATUS_LSB_EX 0x40 /* LS byte extracted (ATLE) */ +#define DD_STATUS_MSB_EX 0x80 /* MS byte extracted (ATLE) */ +#define DD_STATUS_MLEN(n) (((n) >> 8) & 0x3F) +#define DD_STATUS_CURDMACNT(n) (((n) >> 16) & 0xFFFF) + +/* + * + * Protocol engine bits below + * + */ +/* Device Interrupt Bit Definitions */ +#define FRAME_INT 0x00000001 +#define EP_FAST_INT 0x00000002 +#define EP_SLOW_INT 0x00000004 +#define DEV_STAT_INT 0x00000008 +#define CCEMTY_INT 0x00000010 +#define CDFULL_INT 0x00000020 +#define RxENDPKT_INT 0x00000040 +#define TxENDPKT_INT 0x00000080 +#define EP_RLZED_INT 0x00000100 +#define ERR_INT 0x00000200 + +/* Rx & Tx Packet Length Definitions */ +#define PKT_LNGTH_MASK 0x000003FF +#define PKT_DV 0x00000400 +#define PKT_RDY 0x00000800 + +/* USB Control Definitions */ +#define CTRL_RD_EN 0x00000001 +#define CTRL_WR_EN 0x00000002 + +/* Command Codes */ +#define CMD_SET_ADDR 0x00D00500 +#define CMD_CFG_DEV 0x00D80500 +#define CMD_SET_MODE 0x00F30500 +#define CMD_RD_FRAME 0x00F50500 +#define DAT_RD_FRAME 0x00F50200 +#define CMD_RD_TEST 0x00FD0500 +#define DAT_RD_TEST 0x00FD0200 +#define CMD_SET_DEV_STAT 0x00FE0500 +#define CMD_GET_DEV_STAT 0x00FE0500 +#define DAT_GET_DEV_STAT 0x00FE0200 +#define CMD_GET_ERR_CODE 0x00FF0500 +#define DAT_GET_ERR_CODE 0x00FF0200 +#define CMD_RD_ERR_STAT 0x00FB0500 +#define DAT_RD_ERR_STAT 0x00FB0200 +#define DAT_WR_BYTE(x) (0x00000100 | ((x) << 16)) +#define CMD_SEL_EP(x) (0x00000500 | ((x) << 16)) +#define DAT_SEL_EP(x) (0x00000200 | ((x) << 16)) +#define CMD_SEL_EP_CLRI(x) (0x00400500 | ((x) << 16)) +#define DAT_SEL_EP_CLRI(x) (0x00400200 | ((x) << 16)) +#define CMD_SET_EP_STAT(x) (0x00400500 | ((x) << 16)) +#define CMD_CLR_BUF 0x00F20500 +#define DAT_CLR_BUF 0x00F20200 +#define CMD_VALID_BUF 0x00FA0500 + +/* Device Address Register Definitions */ +#define DEV_ADDR_MASK 0x7F +#define DEV_EN 0x80 + +/* Device Configure Register Definitions */ +#define CONF_DVICE 0x01 + +/* Device Mode Register Definitions */ +#define AP_CLK 0x01 +#define INAK_CI 0x02 +#define INAK_CO 0x04 +#define INAK_II 0x08 +#define INAK_IO 0x10 +#define INAK_BI 0x20 +#define INAK_BO 0x40 + +/* Device Status Register Definitions */ +#define DEV_CON 0x01 +#define DEV_CON_CH 0x02 +#define DEV_SUS 0x04 +#define DEV_SUS_CH 0x08 +#define DEV_RST 0x10 + +/* Error Code Register Definitions */ +#define ERR_EC_MASK 0x0F +#define ERR_EA 0x10 + +/* Error Status Register Definitions */ +#define ERR_PID 0x01 +#define ERR_UEPKT 0x02 +#define ERR_DCRC 0x04 +#define ERR_TIMOUT 0x08 +#define ERR_EOP 0x10 +#define ERR_B_OVRN 0x20 +#define ERR_BTSTF 0x40 +#define ERR_TGL 0x80 + +/* Endpoint Select Register Definitions */ +#define EP_SEL_F 0x01 +#define EP_SEL_ST 0x02 +#define EP_SEL_STP 0x04 +#define EP_SEL_PO 0x08 +#define EP_SEL_EPN 0x10 +#define EP_SEL_B_1_FULL 0x20 +#define EP_SEL_B_2_FULL 0x40 + +/* Endpoint Status Register Definitions */ +#define EP_STAT_ST 0x01 +#define EP_STAT_DA 0x20 +#define EP_STAT_RF_MO 0x40 +#define EP_STAT_CND_ST 0x80 + +/* Clear Buffer Register Definitions */ +#define CLR_BUF_PO 0x01 + +/* DMA Interrupt Bit Definitions */ +#define EOT_INT 0x01 +#define NDD_REQ_INT 0x02 +#define SYS_ERR_INT 0x04 + +#define DRIVER_VERSION "1.03" +static const char driver_name[] = "lpc32xx_udc"; + +/* + * + * proc interface support + * + */ +#ifdef CONFIG_USB_GADGET_DEBUG_FILES +static char *epnames[] = {"INT", "ISO", "BULK", "CTRL"}; +static const char debug_filename[] = "driver/udc"; + +static void proc_ep_show(struct seq_file *s, struct lpc32xx_ep *ep) +{ + struct lpc32xx_request *req; + + seq_printf(s, "\n"); + seq_printf(s, "%12s, maxpacket %4d %3s", + ep->ep.name, ep->ep.maxpacket, + ep->is_in ? "in" : "out"); + seq_printf(s, " type %4s", epnames[ep->eptype]); + seq_printf(s, " ints: %12d", ep->totalints); + + if (list_empty(&ep->queue)) + seq_printf(s, "\t(queue empty)\n"); + else { + list_for_each_entry(req, &ep->queue, queue) { + u32 length = req->req.actual; + + seq_printf(s, "\treq %p len %d/%d buf %p\n", + &req->req, length, + req->req.length, req->req.buf); + } + } +} + +static int proc_udc_show(struct seq_file *s, void *unused) +{ + struct lpc32xx_udc *udc = s->private; + struct lpc32xx_ep *ep; + unsigned long flags; + + seq_printf(s, "%s: version %s\n", driver_name, DRIVER_VERSION); + + spin_lock_irqsave(&udc->lock, flags); + + seq_printf(s, "vbus %s, pullup %s, %s powered%s, gadget %s\n\n", + udc->vbus ? "present" : "off", + udc->enabled ? (udc->vbus ? "active" : "enabled") : + "disabled", + udc->selfpowered ? "self" : "VBUS", + udc->suspended ? ", suspended" : "", + udc->driver ? udc->driver->driver.name : "(none)"); + + if (udc->enabled && udc->vbus) { + proc_ep_show(s, &udc->ep[0]); + list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { + if (ep->desc) + proc_ep_show(s, ep); + } + } + + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static int proc_udc_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_udc_show, PDE(inode)->data); +} + +static const struct file_operations proc_ops = { + .owner = THIS_MODULE, + .open = proc_udc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void create_debug_file(struct lpc32xx_udc *udc) +{ + udc->pde = debugfs_create_file(debug_filename, 0, NULL, udc, &proc_ops); +} + +static void remove_debug_file(struct lpc32xx_udc *udc) +{ + if (udc->pde) + debugfs_remove(udc->pde); +} + +#else +static inline void create_debug_file(struct lpc32xx_udc *udc) {} +static inline void remove_debug_file(struct lpc32xx_udc *udc) {} +#endif + +/* Primary initialization sequence for the ISP1301 transceiver */ +static void isp1301_udc_configure(struct lpc32xx_udc *udc) +{ + /* LPC32XX only supports DAT_SE0 USB mode */ + /* This sequence is important */ + + /* Disable transparent UART mode first */ + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + (ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), + MC1_UART_EN); + + /* Set full speed and SE0 mode */ + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + (ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), ~0); + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_MODE_CONTROL_1, (MC1_SPEED_REG | MC1_DAT_SE0)); + + /* + * The PSW_OE enable bit state is reversed in the ISP1301 User's Guide + */ + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + (ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR), ~0); + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_MODE_CONTROL_2, (MC2_BI_DI | MC2_SPD_SUSP_CTRL)); + + /* Driver VBUS_DRV high or low depending on board setup */ + if (udc->board->vbus_drv_pol != 0) + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DRV); + else + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR, + OTG1_VBUS_DRV); + + /* Bi-directional mode with suspend control + * Enable both pulldowns for now - the pullup will be enable when VBUS + * is detected */ + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + (ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), ~0); + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_OTG_CONTROL_1, + (0 | OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN)); + + /* Discharge VBUS (just in case) */ + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DISCHRG); + msleep(1); + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + (ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), + OTG1_VBUS_DISCHRG); + + /* Clear and enable VBUS high edge interrupt */ + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR, ~0); + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR, ~0); + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_INTERRUPT_FALLING, INT_VBUS_VLD); + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR, ~0); + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_INTERRUPT_RISING, INT_VBUS_VLD); + + /* Enable usb_need_clk clock after transceiver is initialized */ + writel((readl(USB_CTRL) | (1 << 22)), USB_CTRL); + + dev_info(udc->dev, "ISP1301 Vendor ID : 0x%04x\n", + i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x00)); + dev_info(udc->dev, "ISP1301 Product ID : 0x%04x\n", + i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x02)); + dev_info(udc->dev, "ISP1301 Version ID : 0x%04x\n", + i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x14)); +} + +/* Enables or disables the USB device pullup via the ISP1301 transceiver */ +static void isp1301_pullup_set(struct lpc32xx_udc *udc) +{ + if (udc->pullup) + /* Enable pullup for bus signalling */ + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_OTG_CONTROL_1, OTG1_DP_PULLUP); + else + /* Enable pullup for bus signalling */ + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR, + OTG1_DP_PULLUP); +} + +static void pullup_work(struct work_struct *work) +{ + struct lpc32xx_udc *udc = + container_of(work, struct lpc32xx_udc, pullup_job); + + isp1301_pullup_set(udc); +} + +static void isp1301_pullup_enable(struct lpc32xx_udc *udc, int en_pullup, + int block) +{ + if (en_pullup == udc->pullup) + return; + + udc->pullup = en_pullup; + if (block) + isp1301_pullup_set(udc); + else + /* defer slow i2c pull up setting */ + schedule_work(&udc->pullup_job); +} + +#ifdef CONFIG_PM +/* Powers up or down the ISP1301 transceiver */ +static void isp1301_set_powerstate(struct lpc32xx_udc *udc, int enable) +{ + if (enable != 0) + /* Power up ISP1301 - this ISP1301 will automatically wakeup + when VBUS is detected */ + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR, + MC2_GLOBAL_PWR_DN); + else + /* Power down ISP1301 */ + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN); +} + +static void power_work(struct work_struct *work) +{ + struct lpc32xx_udc *udc = + container_of(work, struct lpc32xx_udc, power_job); + + isp1301_set_powerstate(udc, udc->poweron); +} +#endif + +/* + * + * USB protocol engine command/data read/write helper functions + * + */ +/* Issues a single command to the USB device state machine */ +static void udc_protocol_cmd_w(struct lpc32xx_udc *udc, u32 cmd) +{ + u32 pass = 0; + int to; + + /* EP may lock on CLRI if this read isn't done */ + u32 tmp = readl(USBD_DEVINTST(udc->udp_baseaddr)); + (void) tmp; + + while (pass == 0) { + writel(USBD_CCEMPTY, USBD_DEVINTCLR(udc->udp_baseaddr)); + + /* Write command code */ + writel(cmd, USBD_CMDCODE(udc->udp_baseaddr)); + to = 10000; + while (((readl(USBD_DEVINTST(udc->udp_baseaddr)) & + USBD_CCEMPTY) == 0) && (to > 0)) { + to--; + } + + if (to > 0) + pass = 1; + + cpu_relax(); + } +} + +/* Issues 2 commands (or command and data) to the USB device state machine */ +static inline void udc_protocol_cmd_data_w(struct lpc32xx_udc *udc, u32 cmd, + u32 data) +{ + udc_protocol_cmd_w(udc, cmd); + udc_protocol_cmd_w(udc, data); +} + +/* Issues a single command to the USB device state machine and reads + * response data */ +static u32 udc_protocol_cmd_r(struct lpc32xx_udc *udc, u32 cmd) +{ + u32 tmp; + int to = 1000; + + /* Write a command and read data from the protocol engine */ + writel((USBD_CDFULL | USBD_CCEMPTY), + USBD_DEVINTCLR(udc->udp_baseaddr)); + + /* Write command code */ + udc_protocol_cmd_w(udc, cmd); + + tmp = readl(USBD_DEVINTST(udc->udp_baseaddr)); + while ((!(readl(USBD_DEVINTST(udc->udp_baseaddr)) & USBD_CDFULL)) + && (to > 0)) + to--; + if (!to) + dev_dbg(udc->dev, + "Protocol engine didn't receive response (CDFULL)\n"); + + return readl(USBD_CMDDATA(udc->udp_baseaddr)); +} + +/* + * + * USB device interrupt mask support functions + * + */ +/* Enable one or more USB device interrupts */ +static inline void uda_enable_devint(struct lpc32xx_udc *udc, u32 devmask) +{ + udc->enabled_devints |= devmask; + writel(udc->enabled_devints, USBD_DEVINTEN(udc->udp_baseaddr)); +} + +/* Disable one or more USB device interrupts */ +static inline void uda_disable_devint(struct lpc32xx_udc *udc, u32 mask) +{ + udc->enabled_devints &= ~mask; + writel(udc->enabled_devints, USBD_DEVINTEN(udc->udp_baseaddr)); +} + +/* Clear one or more USB device interrupts */ +static inline void uda_clear_devint(struct lpc32xx_udc *udc, u32 mask) +{ + writel(mask, USBD_DEVINTCLR(udc->udp_baseaddr)); +} + +/* + * + * Endpoint interrupt disable/enable functions + * + */ +/* Enable one or more USB endpoint interrupts */ +static void uda_enable_hwepint(struct lpc32xx_udc *udc, u32 hwep) +{ + udc->enabled_hwepints |= (1 << hwep); + writel(udc->enabled_hwepints, USBD_EPINTEN(udc->udp_baseaddr)); +} + +/* Disable one or more USB endpoint interrupts */ +static void uda_disable_hwepint(struct lpc32xx_udc *udc, u32 hwep) +{ + udc->enabled_hwepints &= ~(1 << hwep); + writel(udc->enabled_hwepints, USBD_EPINTEN(udc->udp_baseaddr)); +} + +/* Clear one or more USB endpoint interrupts */ +static inline void uda_clear_hwepint(struct lpc32xx_udc *udc, u32 hwep) +{ + writel((1 << hwep), USBD_EPINTCLR(udc->udp_baseaddr)); +} + +/* Enable DMA for the HW channel */ +static inline void udc_ep_dma_enable(struct lpc32xx_udc *udc, u32 hwep) +{ + writel((1 << hwep), USBD_EPDMAEN(udc->udp_baseaddr)); +} + +/* Disable DMA for the HW channel */ +static inline void udc_ep_dma_disable(struct lpc32xx_udc *udc, u32 hwep) +{ + writel((1 << hwep), USBD_EPDMADIS(udc->udp_baseaddr)); +} + +/* + * + * Endpoint realize/unrealize functions + * + */ +/* Before an endpoint can be used, it needs to be realized + * in the USB protocol engine - this realizes the endpoint. + * The interrupt (FIFO or DMA) is not enabled with this function */ +static void udc_realize_hwep(struct lpc32xx_udc *udc, u32 hwep, + u32 maxpacket) +{ + int to = 1000; + + writel(USBD_EP_RLZED, USBD_DEVINTCLR(udc->udp_baseaddr)); + writel(hwep, USBD_EPIND(udc->udp_baseaddr)); + udc->realized_eps |= (1 << hwep); + writel(udc->realized_eps, USBD_REEP(udc->udp_baseaddr)); + writel(maxpacket, USBD_EPMAXPSIZE(udc->udp_baseaddr)); + + /* Wait until endpoint is realized in hardware */ + while ((!(readl(USBD_DEVINTST(udc->udp_baseaddr)) & + USBD_EP_RLZED)) && (to > 0)) + to--; + if (!to) + dev_dbg(udc->dev, "EP not correctly realized in hardware\n"); + + writel(USBD_EP_RLZED, USBD_DEVINTCLR(udc->udp_baseaddr)); +} + +/* Unrealize an EP */ +static void udc_unrealize_hwep(struct lpc32xx_udc *udc, u32 hwep) +{ + udc->realized_eps &= ~(1 << hwep); + writel(udc->realized_eps, USBD_REEP(udc->udp_baseaddr)); +} + +/* + * + * Endpoint support functions + * + */ +/* Select and clear endpoint interrupt */ +static u32 udc_selep_clrint(struct lpc32xx_udc *udc, u32 hwep) +{ + udc_protocol_cmd_w(udc, CMD_SEL_EP_CLRI(hwep)); + return udc_protocol_cmd_r(udc, DAT_SEL_EP_CLRI(hwep)); +} + +/* Disables the endpoint in the USB protocol engine */ +static void udc_disable_hwep(struct lpc32xx_udc *udc, u32 hwep) +{ + udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(hwep), + DAT_WR_BYTE(EP_STAT_DA)); +} + +/* Stalls the endpoint - endpoint will return STALL */ +static void udc_stall_hwep(struct lpc32xx_udc *udc, u32 hwep) +{ + udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(hwep), + DAT_WR_BYTE(EP_STAT_ST)); +} + +/* Clear stall or reset endpoint */ +static void udc_clrstall_hwep(struct lpc32xx_udc *udc, u32 hwep) +{ + udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(hwep), + DAT_WR_BYTE(0)); +} + +/* Select an endpoint for endpoint status, clear, validate */ +static void udc_select_hwep(struct lpc32xx_udc *udc, u32 hwep) +{ + udc_protocol_cmd_w(udc, CMD_SEL_EP(hwep)); +} + +/* + * + * Endpoint buffer management functions + * + */ +/* Clear the current endpoint's buffer */ +static void udc_clr_buffer_hwep(struct lpc32xx_udc *udc, u32 hwep) +{ + udc_select_hwep(udc, hwep); + udc_protocol_cmd_w(udc, CMD_CLR_BUF); +} + +/* Validate the current endpoint's buffer */ +static void udc_val_buffer_hwep(struct lpc32xx_udc *udc, u32 hwep) +{ + udc_select_hwep(udc, hwep); + udc_protocol_cmd_w(udc, CMD_VALID_BUF); +} + +static inline u32 udc_clearep_getsts(struct lpc32xx_udc *udc, u32 hwep) +{ + /* Clear EP interrupt */ + uda_clear_hwepint(udc, hwep); + return udc_selep_clrint(udc, hwep); +} + +/* + * + * USB EP DMA support + * + */ +/* Allocate a DMA Descriptor */ +static struct lpc32xx_usbd_dd_gad *udc_dd_alloc(struct lpc32xx_udc *udc) +{ + dma_addr_t dma; + struct lpc32xx_usbd_dd_gad *dd; + + dd = (struct lpc32xx_usbd_dd_gad *) dma_pool_alloc( + udc->dd_cache, (GFP_KERNEL | GFP_DMA), &dma); + if (dd) + dd->this_dma = dma; + + return dd; +} + +/* Free a DMA Descriptor */ +static void udc_dd_free(struct lpc32xx_udc *udc, struct lpc32xx_usbd_dd_gad *dd) +{ + dma_pool_free(udc->dd_cache, dd, dd->this_dma); +} + +/* + * + * USB setup and shutdown functions + * + */ +/* Enables or disables most of the USB system clocks when low power mode is + * needed. Clocks are typically started on a connection event, and disabled + * when a cable is disconnected */ +#define OTGOFF_CLK_MASK (AHB_M_CLOCK_ON | I2C_CLOCK_ON) +static void udc_clk_set(struct lpc32xx_udc *udc, int enable) +{ + int to = 1000; + + if (enable != 0) { + if (udc->clocked) + return; + + udc->clocked = 1; + + /* 48MHz PLL up */ + clk_enable(udc->usb_pll_clk); + + /* Enable the USB device clock */ + writel(readl(USB_CTRL) | USB_DEV_NEED_CLK_EN, + USB_CTRL); + + /* Set to enable all needed USB OTG clocks */ + writel(USB_CLOCK_MASK, USB_OTG_CLK_CTRL(udc)); + + while (((readl(USB_OTG_CLK_STAT(udc)) & USB_CLOCK_MASK) != + USB_CLOCK_MASK) && (to > 0)) + to--; + if (!to) + dev_dbg(udc->dev, "Cannot enable USB OTG clocking\n"); + } else { + if (!udc->clocked) + return; + + udc->clocked = 0; + + /* Never disable the USB_HCLK during normal operation */ + + /* 48MHz PLL dpwn */ + clk_disable(udc->usb_pll_clk); + + /* Enable the USB device clock */ + writel(readl(USB_CTRL) & ~USB_DEV_NEED_CLK_EN, + USB_CTRL); + + /* Set to enable all needed USB OTG clocks */ + writel(OTGOFF_CLK_MASK, USB_OTG_CLK_CTRL(udc)); + + while (((readl(USB_OTG_CLK_STAT(udc)) & + OTGOFF_CLK_MASK) != + OTGOFF_CLK_MASK) && (to > 0)) + to--; + if (!to) + dev_dbg(udc->dev, "Cannot disable USB OTG clocking\n"); + } +} + +/* Set/reset USB device address */ +static void udc_set_address(struct lpc32xx_udc *udc, u32 addr) +{ + /* Address will be latched at the end of the status phase, or + latched immediately if function is called twice */ + udc_protocol_cmd_data_w(udc, CMD_SET_ADDR, + DAT_WR_BYTE(DEV_EN | addr)); +} + +/* Setup up a IN request for DMA transfer - this consists of determining the + * list of DMA addresses for the transfer, allocating DMA Descriptors, + * installing the DD into the UDCA, and then enabling the DMA for that EP */ +static int udc_ep_in_req_dma(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep) +{ + struct lpc32xx_request *req; + u32 hwep = ep->hwep_num; + + ep->req_pending = 1; + + /* There will always be a request waiting here */ + req = list_entry(ep->queue.next, struct lpc32xx_request, queue); + + /* Place the DD Descriptor into the UDCA */ + udc->udca_v_base[hwep] = req->dd_desc_ptr->this_dma; + + /* Enable DMA and interrupt for the HW EP */ + udc_ep_dma_enable(udc, hwep); + + /* Clear ZLP if last packet is not of MAXP size */ + if (req->req.length % ep->ep.maxpacket) + req->send_zlp = 0; + + return 0; +} + +/* Setup up a OUT request for DMA transfer - this consists of determining the + * list of DMA addresses for the transfer, allocating DMA Descriptors, + * installing the DD into the UDCA, and then enabling the DMA for that EP */ +static int udc_ep_out_req_dma(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep) +{ + struct lpc32xx_request *req; + u32 hwep = ep->hwep_num; + + ep->req_pending = 1; + + /* There will always be a request waiting here */ + req = list_entry(ep->queue.next, struct lpc32xx_request, queue); + + /* Place the DD Descriptor into the UDCA */ + udc->udca_v_base[hwep] = req->dd_desc_ptr->this_dma; + + /* Enable DMA and interrupt for the HW EP */ + udc_ep_dma_enable(udc, hwep); + return 0; +} + +static void udc_disable(struct lpc32xx_udc *udc) +{ + u32 i; + + /* Disable device */ + udc_protocol_cmd_data_w(udc, CMD_CFG_DEV, DAT_WR_BYTE(0)); + udc_protocol_cmd_data_w(udc, CMD_SET_DEV_STAT, DAT_WR_BYTE(0)); + + /* Disable all device interrupts (including EP0) */ + uda_disable_devint(udc, 0x3FF); + + /* Disable and reset all endpoint interrupts */ + for (i = 0; i < 32; i++) { + uda_disable_hwepint(udc, i); + uda_clear_hwepint(udc, i); + udc_disable_hwep(udc, i); + udc_unrealize_hwep(udc, i); + udc->udca_v_base[i] = 0; + + /* Disable and clear all interrupts and DMA */ + udc_ep_dma_disable(udc, i); + writel((1 << i), USBD_EOTINTCLR(udc->udp_baseaddr)); + writel((1 << i), USBD_NDDRTINTCLR(udc->udp_baseaddr)); + writel((1 << i), USBD_SYSERRTINTCLR(udc->udp_baseaddr)); + writel((1 << i), USBD_DMARCLR(udc->udp_baseaddr)); + } + + /* Disable DMA interrupts */ + writel(0, USBD_DMAINTEN(udc->udp_baseaddr)); + + writel(0, USBD_UDCAH(udc->udp_baseaddr)); +} + +static void udc_enable(struct lpc32xx_udc *udc) +{ + u32 i; + struct lpc32xx_ep *ep = &udc->ep[0]; + + /* Start with known state */ + udc_disable(udc); + + /* Enable device */ + udc_protocol_cmd_data_w(udc, CMD_SET_DEV_STAT, DAT_WR_BYTE(DEV_CON)); + + /* EP interrupts on high priority, FRAME interrupt on low priority */ + writel(USBD_EP_FAST, USBD_DEVINTPRI(udc->udp_baseaddr)); + writel(0xFFFF, USBD_EPINTPRI(udc->udp_baseaddr)); + + /* Clear any pending device interrupts */ + writel(0x3FF, USBD_DEVINTCLR(udc->udp_baseaddr)); + + /* Setup UDCA - not yet used (DMA) */ + writel(udc->udca_p_base, USBD_UDCAH(udc->udp_baseaddr)); + + /* Only enable EP0 in and out for now, EP0 only works in FIFO mode */ + for (i = 0; i <= 1; i++) { + udc_realize_hwep(udc, i, ep->ep.maxpacket); + uda_enable_hwepint(udc, i); + udc_select_hwep(udc, i); + udc_clrstall_hwep(udc, i); + udc_clr_buffer_hwep(udc, i); + } + + /* Device interrupt setup */ + uda_clear_devint(udc, (USBD_ERR_INT | USBD_DEV_STAT | USBD_EP_SLOW | + USBD_EP_FAST)); + uda_enable_devint(udc, (USBD_ERR_INT | USBD_DEV_STAT | USBD_EP_SLOW | + USBD_EP_FAST)); + + /* Set device address to 0 - called twice to force a latch in the USB + engine without the need of a setup packet status closure */ + udc_set_address(udc, 0); + udc_set_address(udc, 0); + + /* Enable master DMA interrupts */ + writel((USBD_SYS_ERR_INT | USBD_EOT_INT), + USBD_DMAINTEN(udc->udp_baseaddr)); + + udc->dev_status = 0; +} + +/* + * + * USB device board specific events handled via callbacks + * + */ +/* Connection change event - notify board function of change */ +static void uda_power_event(struct lpc32xx_udc *udc, u32 conn) +{ + /* Just notify of a connection change event (optional) */ + if (udc->board->conn_chgb != NULL) + udc->board->conn_chgb(conn); +} + +/* Suspend/resume event - notify board function of change */ +static void uda_resm_susp_event(struct lpc32xx_udc *udc, u32 conn) +{ + /* Just notify of a Suspend/resume change event (optional) */ + if (udc->board->susp_chgb != NULL) + udc->board->susp_chgb(conn); + + if (conn) + udc->suspended = 0; + else + udc->suspended = 1; +} + +/* Remote wakeup enable/disable - notify board function of change */ +static void uda_remwkp_cgh(struct lpc32xx_udc *udc) +{ + if (udc->board->rmwk_chgb != NULL) + udc->board->rmwk_chgb(udc->dev_status & + (1 << USB_DEVICE_REMOTE_WAKEUP)); +} + +/* Reads data from FIFO, adjusts for alignment and data size */ +static void udc_pop_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes) +{ + int n, i, bl; + u16 *p16; + u32 *p32, tmp, cbytes; + + /* Use optimal data transfer method based on source address and size */ + switch (((u32) data) & 0x3) { + case 0: /* 32-bit aligned */ + p32 = (u32 *) data; + cbytes = (bytes & ~0x3); + + /* Copy 32-bit aligned data first */ + for (n = 0; n < cbytes; n += 4) + *p32++ = readl(USBD_RXDATA(udc->udp_baseaddr)); + + /* Handle any remaining bytes */ + bl = bytes - cbytes; + if (bl) { + tmp = readl(USBD_RXDATA(udc->udp_baseaddr)); + for (n = 0; n < bl; n++) + data[cbytes + n] = ((tmp >> (n * 8)) & 0xFF); + + } + break; + + case 1: /* 8-bit aligned */ + case 3: + /* Each byte has to be handled independently */ + for (n = 0; n < bytes; n += 4) { + tmp = readl(USBD_RXDATA(udc->udp_baseaddr)); + + bl = bytes - n; + if (bl > 3) + bl = 3; + + for (i = 0; i < bl; i++) + data[n + i] = (u8) ((tmp >> (n * 8)) & 0xFF); + } + break; + + case 2: /* 16-bit aligned */ + p16 = (u16 *) data; + cbytes = (bytes & ~0x3); + + /* Copy 32-bit sized objects first with 16-bit alignment */ + for (n = 0; n < cbytes; n += 4) { + tmp = readl(USBD_RXDATA(udc->udp_baseaddr)); + *p16++ = (u16)(tmp & 0xFFFF); + *p16++ = (u16)((tmp >> 16) & 0xFFFF); + } + + /* Handle any remaining bytes */ + bl = bytes - cbytes; + if (bl) { + tmp = readl(USBD_RXDATA(udc->udp_baseaddr)); + for (n = 0; n < bl; n++) + data[cbytes + n] = ((tmp >> (n * 8)) & 0xFF); + } + break; + } +} + +/* Read data from the FIFO for an endpoint. This function is for endpoints (such + * as EP0) that don't use DMA. This function should only be called if a packet + * is known to be ready to read for the endpoint. Note that the endpoint must + * be selected in the protocol engine prior to this call. */ +static u32 udc_read_hwep(struct lpc32xx_udc *udc, u32 hwep, u32 *data, + u32 bytes) +{ + u32 tmpv; + int to = 1000; + u32 tmp, hwrep = ((hwep & 0x1E) << 1) | CTRL_RD_EN; + + /* Setup read of endpoint */ + writel(hwrep, USBD_CTRL(udc->udp_baseaddr)); + + /* Wait until packet is ready */ + while ((((tmpv = readl(USBD_RXPLEN(udc->udp_baseaddr))) & + PKT_RDY) == 0) && (to > 0)) + to--; + if (!to) + dev_dbg(udc->dev, "No packet ready on FIFO EP read\n"); + + /* Mask out count */ + tmp = tmpv & PKT_LNGTH_MASK; + if (bytes < tmp) + tmp = bytes; + + if ((tmp > 0) && (data != NULL)) + udc_pop_fifo(udc, (u8 *) data, tmp); + + writel(((hwep & 0x1E) << 1), USBD_CTRL(udc->udp_baseaddr)); + + /* Clear the buffer */ + udc_clr_buffer_hwep(udc, hwep); + + return tmp; +} + +/* Stuffs data into the FIFO, adjusts for alignment and data size */ +static void udc_stuff_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes) +{ + int n, i, bl; + u16 *p16; + u32 *p32, tmp, cbytes; + + /* Use optimal data transfer method based on source address and size */ + switch (((u32) data) & 0x3) { + case 0: /* 32-bit aligned */ + p32 = (u32 *) data; + cbytes = (bytes & ~0x3); + + /* Copy 32-bit aligned data first */ + for (n = 0; n < cbytes; n += 4) + writel(*p32++, USBD_TXDATA(udc->udp_baseaddr)); + + /* Handle any remaining bytes */ + bl = bytes - cbytes; + if (bl) { + tmp = 0; + for (n = 0; n < bl; n++) + tmp |= data[cbytes + n] << (n * 8); + + writel(tmp, USBD_TXDATA(udc->udp_baseaddr)); + } + break; + + case 1: /* 8-bit aligned */ + case 3: + /* Each byte has to be handled independently */ + for (n = 0; n < bytes; n += 4) { + bl = bytes - n; + if (bl > 4) + bl = 4; + + tmp = 0; + for (i = 0; i < bl; i++) + tmp |= data[n + i] << (i * 8); + + writel(tmp, USBD_TXDATA(udc->udp_baseaddr)); + } + break; + + case 2: /* 16-bit aligned */ + p16 = (u16 *) data; + cbytes = (bytes & ~0x3); + + /* Copy 32-bit aligned data first */ + for (n = 0; n < cbytes; n += 4) { + tmp = *p16++ & 0xFFFF; + tmp |= (*p16++ & 0xFFFF) << 16; + writel(tmp, USBD_TXDATA(udc->udp_baseaddr)); + } + + /* Handle any remaining bytes */ + bl = bytes - cbytes; + if (bl) { + tmp = 0; + for (n = 0; n < bl; n++) + tmp |= data[cbytes + n] << (n * 8); + + writel(tmp, USBD_TXDATA(udc->udp_baseaddr)); + } + break; + } +} + +/* Write data to the FIFO for an endpoint. This function is for endpoints (such + * as EP0) that don't use DMA. Note that the endpoint must be selected in the + * protocol engine prior to this call. */ +static void udc_write_hwep(struct lpc32xx_udc *udc, u32 hwep, u32 *data, + u32 bytes) +{ + u32 hwwep = ((hwep & 0x1E) << 1) | CTRL_WR_EN; + + if ((bytes > 0) && (data == NULL)) + return; + + /* Setup write of endpoint */ + writel(hwwep, USBD_CTRL(udc->udp_baseaddr)); + + writel(bytes, USBD_TXPLEN(udc->udp_baseaddr)); + + /* Need at least 1 byte to trigger TX */ + if (bytes == 0) + writel(0, USBD_TXDATA(udc->udp_baseaddr)); + else + udc_stuff_fifo(udc, (u8 *) data, bytes); + + writel(((hwep & 0x1E) << 1), USBD_CTRL(udc->udp_baseaddr)); + + udc_val_buffer_hwep(udc, hwep); +} + +/* USB device reset - resets USB to a default state with just EP0 + enabled */ +static void uda_usb_reset(struct lpc32xx_udc *udc) +{ + u32 i = 0; + /* Re-init device controller and EP0 */ + udc_enable(udc); + udc->gadget.speed = USB_SPEED_FULL; + + for (i = 1; i < NUM_ENDPOINTS; i++) { + struct lpc32xx_ep *ep = &udc->ep[i]; + ep->req_pending = 0; + } +} + +/* Send a ZLP on EP0 */ +static void udc_ep0_send_zlp(struct lpc32xx_udc *udc) +{ + udc_write_hwep(udc, EP_IN, NULL, 0); +} + +/* Get current frame number */ +static u16 udc_get_current_frame(struct lpc32xx_udc *udc) +{ + u16 flo, fhi; + + udc_protocol_cmd_w(udc, CMD_RD_FRAME); + flo = (u16) udc_protocol_cmd_r(udc, DAT_RD_FRAME); + fhi = (u16) udc_protocol_cmd_r(udc, DAT_RD_FRAME); + + return (fhi << 8) | flo; +} + +/* Set the device as configured - enables all endpoints */ +static inline void udc_set_device_configured(struct lpc32xx_udc *udc) +{ + udc_protocol_cmd_data_w(udc, CMD_CFG_DEV, DAT_WR_BYTE(CONF_DVICE)); +} + +/* Set the device as unconfigured - disables all endpoints */ +static inline void udc_set_device_unconfigured(struct lpc32xx_udc *udc) +{ + udc_protocol_cmd_data_w(udc, CMD_CFG_DEV, DAT_WR_BYTE(0)); +} + +/* reinit == restore initial software state */ +static void udc_reinit(struct lpc32xx_udc *udc) +{ + u32 i; + + INIT_LIST_HEAD(&udc->gadget.ep_list); + INIT_LIST_HEAD(&udc->gadget.ep0->ep_list); + + for (i = 0; i < NUM_ENDPOINTS; i++) { + struct lpc32xx_ep *ep = &udc->ep[i]; + + if (i != 0) + list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); + ep->desc = NULL; + ep->ep.maxpacket = ep->maxpacket; + INIT_LIST_HEAD(&ep->queue); + ep->req_pending = 0; + } + + udc->ep0state = WAIT_FOR_SETUP; +} + +/* Must be called with lock */ +static void done(struct lpc32xx_ep *ep, struct lpc32xx_request *req, int status) +{ + struct lpc32xx_udc *udc = ep->udc; + + list_del_init(&req->queue); + if (req->req.status == -EINPROGRESS) + req->req.status = status; + else + status = req->req.status; + + if (ep->lep) { + enum dma_data_direction direction; + + if (ep->is_in) + direction = DMA_TO_DEVICE; + else + direction = DMA_FROM_DEVICE; + + if (req->mapped) { + dma_unmap_single(ep->udc->gadget.dev.parent, + req->req.dma, req->req.length, + direction); + req->req.dma = 0; + req->mapped = 0; + } else + dma_sync_single_for_cpu(ep->udc->gadget.dev.parent, + req->req.dma, req->req.length, + direction); + + /* Free DDs */ + udc_dd_free(udc, req->dd_desc_ptr); + } + + if (status && status != -ESHUTDOWN) + ep_dbg(ep, "%s done %p, status %d\n", ep->ep.name, req, status); + + ep->req_pending = 0; + spin_unlock(&udc->lock); + req->req.complete(&ep->ep, &req->req); + spin_lock(&udc->lock); +} + +/* Must be called with lock */ +static void nuke(struct lpc32xx_ep *ep, int status) +{ + struct lpc32xx_request *req; + + while (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, struct lpc32xx_request, queue); + done(ep, req, status); + } + + if (ep->desc && status == -ESHUTDOWN) { + uda_disable_hwepint(ep->udc, ep->hwep_num); + udc_disable_hwep(ep->udc, ep->hwep_num); + } +} + +/* IN endpoint 0 transfer */ +static int udc_ep0_in_req(struct lpc32xx_udc *udc) +{ + struct lpc32xx_request *req; + struct lpc32xx_ep *ep0 = &udc->ep[0]; + u32 tsend, ts = 0; + + if (list_empty(&ep0->queue)) + /* Nothing to send */ + return 0; + else + req = list_entry(ep0->queue.next, struct lpc32xx_request, + queue); + + tsend = ts = req->req.length - req->req.actual; + if (ts == 0) { + /* Send a ZLP */ + udc_ep0_send_zlp(udc); + done(ep0, req, 0); + return 1; + } else if (ts > ep0->ep.maxpacket) + ts = ep0->ep.maxpacket; /* Just send what we can */ + + /* Write data to the EP0 FIFO and start transfer */ + udc_write_hwep(udc, EP_IN, (req->req.buf + req->req.actual), ts); + + /* Increment data pointer */ + req->req.actual += ts; + + if (tsend >= ep0->ep.maxpacket) + return 0; /* Stay in data transfer state */ + + /* Transfer request is complete */ + udc->ep0state = WAIT_FOR_SETUP; + done(ep0, req, 0); + return 1; +} + +/* OUT endpoint 0 transfer */ +static int udc_ep0_out_req(struct lpc32xx_udc *udc) +{ + struct lpc32xx_request *req; + struct lpc32xx_ep *ep0 = &udc->ep[0]; + u32 tr, bufferspace; + + if (list_empty(&ep0->queue)) + return 0; + else + req = list_entry(ep0->queue.next, struct lpc32xx_request, + queue); + + if (req) { + if (req->req.length == 0) { + /* Just dequeue request */ + done(ep0, req, 0); + udc->ep0state = WAIT_FOR_SETUP; + return 1; + } + + /* Get data from FIFO */ + bufferspace = req->req.length - req->req.actual; + if (bufferspace > ep0->ep.maxpacket) + bufferspace = ep0->ep.maxpacket; + + /* Copy data to buffer */ + prefetchw(req->req.buf + req->req.actual); + tr = udc_read_hwep(udc, EP_OUT, req->req.buf + req->req.actual, + bufferspace); + req->req.actual += bufferspace; + + if (tr < ep0->ep.maxpacket) { + /* This is the last packet */ + done(ep0, req, 0); + udc->ep0state = WAIT_FOR_SETUP; + return 1; + } + } + + return 0; +} + +/* Must be called with lock */ +static void stop_activity(struct lpc32xx_udc *udc) +{ + struct usb_gadget_driver *driver = udc->driver; + int i; + + if (udc->gadget.speed == USB_SPEED_UNKNOWN) + driver = NULL; + + udc->gadget.speed = USB_SPEED_UNKNOWN; + udc->suspended = 0; + + for (i = 0; i < NUM_ENDPOINTS; i++) { + struct lpc32xx_ep *ep = &udc->ep[i]; + nuke(ep, -ESHUTDOWN); + } + if (driver) { + spin_unlock(&udc->lock); + driver->disconnect(&udc->gadget); + spin_lock(&udc->lock); + } + + isp1301_pullup_enable(udc, 0, 0); + udc_disable(udc); + udc_reinit(udc); +} + +/* + * Activate or kill host pullup + * Can be called with or without lock + */ +static void pullup(struct lpc32xx_udc *udc, int is_on) +{ + if (!udc->clocked) + return; + + if (!udc->enabled || !udc->vbus) + is_on = 0; + + if (is_on != udc->pullup) + isp1301_pullup_enable(udc, is_on, 0); +} + +/* Must be called without lock */ +static int lpc32xx_ep_disable(struct usb_ep *_ep) +{ + struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep); + struct lpc32xx_udc *udc = ep->udc; + unsigned long flags; + + if ((ep->hwep_num_base == 0) || (ep->hwep_num == 0)) + return -EINVAL; + spin_lock_irqsave(&udc->lock, flags); + + nuke(ep, -ESHUTDOWN); + + /* restore the endpoint's pristine config */ + ep->desc = NULL; + + /* Clear all DMA statuses for this EP */ + udc_ep_dma_disable(udc, ep->hwep_num); + writel(1 << ep->hwep_num, USBD_EOTINTCLR(udc->udp_baseaddr)); + writel(1 << ep->hwep_num, USBD_NDDRTINTCLR(udc->udp_baseaddr)); + writel(1 << ep->hwep_num, USBD_SYSERRTINTCLR(udc->udp_baseaddr)); + writel(1 << ep->hwep_num, USBD_DMARCLR(udc->udp_baseaddr)); + + /* Remove the DD pointer in the UDCA */ + udc->udca_v_base[ep->hwep_num] = 0; + + /* Disable and reset endpoint and interrupt */ + uda_clear_hwepint(udc, ep->hwep_num); + udc_unrealize_hwep(udc, ep->hwep_num); + + ep->hwep_num = 0; + + spin_unlock_irqrestore(&udc->lock, flags); + + atomic_dec(&udc->enabled_ep_cnt); + wake_up(&udc->ep_disable_wait_queue); + + return 0; +} + +/* Must be called without lock */ +static int lpc32xx_ep_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc) +{ + struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep); + struct lpc32xx_udc *udc = ep->udc; + u16 maxpacket; + u32 tmp; + unsigned long flags; + + /* Verify EP data */ + if ((!_ep) || (!ep) || (!desc) || (ep->desc) || + (desc->bDescriptorType != USB_DT_ENDPOINT)) { + dev_dbg(udc->dev, "bad ep or descriptor\n"); + return -EINVAL; + } + maxpacket = usb_endpoint_maxp(desc); + if ((maxpacket == 0) || (maxpacket > ep->maxpacket)) { + dev_dbg(udc->dev, "bad ep descriptor's packet size\n"); + return -EINVAL; + } + + /* Don't touch EP0 */ + if (ep->hwep_num_base == 0) { + dev_dbg(udc->dev, "Can't re-enable EP0!!!\n"); + return -EINVAL; + } + + /* Is driver ready? */ + if ((!udc->driver) || (udc->gadget.speed == USB_SPEED_UNKNOWN)) { + dev_dbg(udc->dev, "bogus device state\n"); + return -ESHUTDOWN; + } + + tmp = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + switch (tmp) { + case USB_ENDPOINT_XFER_CONTROL: + return -EINVAL; + + case USB_ENDPOINT_XFER_INT: + if (maxpacket > ep->maxpacket) { + dev_dbg(udc->dev, + "Bad INT endpoint maxpacket %d\n", maxpacket); + return -EINVAL; + } + break; + + case USB_ENDPOINT_XFER_BULK: + switch (maxpacket) { + case 8: + case 16: + case 32: + case 64: + break; + + default: + dev_dbg(udc->dev, + "Bad BULK endpoint maxpacket %d\n", maxpacket); + return -EINVAL; + } + break; + + case USB_ENDPOINT_XFER_ISOC: + break; + } + spin_lock_irqsave(&udc->lock, flags); + + /* Initialize endpoint to match the selected descriptor */ + ep->is_in = (desc->bEndpointAddress & USB_DIR_IN) != 0; + ep->desc = desc; + ep->ep.maxpacket = maxpacket; + + /* Map hardware endpoint from base and direction */ + if (ep->is_in) + /* IN endpoints are offset 1 from the OUT endpoint */ + ep->hwep_num = ep->hwep_num_base + EP_IN; + else + ep->hwep_num = ep->hwep_num_base; + + ep_dbg(ep, "EP enabled: %s, HW:%d, MP:%d IN:%d\n", ep->ep.name, + ep->hwep_num, maxpacket, (ep->is_in == 1)); + + /* Realize the endpoint, interrupt is enabled later when + * buffers are queued, IN EPs will NAK until buffers are ready */ + udc_realize_hwep(udc, ep->hwep_num, ep->ep.maxpacket); + udc_clr_buffer_hwep(udc, ep->hwep_num); + uda_disable_hwepint(udc, ep->hwep_num); + udc_clrstall_hwep(udc, ep->hwep_num); + + /* Clear all DMA statuses for this EP */ + udc_ep_dma_disable(udc, ep->hwep_num); + writel(1 << ep->hwep_num, USBD_EOTINTCLR(udc->udp_baseaddr)); + writel(1 << ep->hwep_num, USBD_NDDRTINTCLR(udc->udp_baseaddr)); + writel(1 << ep->hwep_num, USBD_SYSERRTINTCLR(udc->udp_baseaddr)); + writel(1 << ep->hwep_num, USBD_DMARCLR(udc->udp_baseaddr)); + + spin_unlock_irqrestore(&udc->lock, flags); + + atomic_inc(&udc->enabled_ep_cnt); + return 0; +} + +/* + * Allocate a USB request list + * Can be called with or without lock + */ +static struct usb_request *lpc32xx_ep_alloc_request(struct usb_ep *_ep, + gfp_t gfp_flags) +{ + struct lpc32xx_request *req; + + req = kzalloc(sizeof(struct lpc32xx_request), gfp_flags); + if (!req) + return NULL; + + INIT_LIST_HEAD(&req->queue); + return &req->req; +} + +/* + * De-allocate a USB request list + * Can be called with or without lock + */ +static void lpc32xx_ep_free_request(struct usb_ep *_ep, + struct usb_request *_req) +{ + struct lpc32xx_request *req; + + req = container_of(_req, struct lpc32xx_request, req); + BUG_ON(!list_empty(&req->queue)); + kfree(req); +} + +/* Must be called without lock */ +static int lpc32xx_ep_queue(struct usb_ep *_ep, + struct usb_request *_req, gfp_t gfp_flags) +{ + struct lpc32xx_request *req; + struct lpc32xx_ep *ep; + struct lpc32xx_udc *udc; + unsigned long flags; + int status = 0; + + req = container_of(_req, struct lpc32xx_request, req); + ep = container_of(_ep, struct lpc32xx_ep, ep); + + if (!_req || !_req->complete || !_req->buf || + !list_empty(&req->queue)) + return -EINVAL; + + udc = ep->udc; + + if (!_ep || (!ep->desc && ep->hwep_num_base != 0)) { + dev_dbg(udc->dev, "invalid ep\n"); + return -EINVAL; + } + + + if ((!udc) || (!udc->driver) || + (udc->gadget.speed == USB_SPEED_UNKNOWN)) { + dev_dbg(udc->dev, "invalid device\n"); + return -EINVAL; + } + + if (ep->lep) { + enum dma_data_direction direction; + struct lpc32xx_usbd_dd_gad *dd; + + /* Map DMA pointer */ + if (ep->is_in) + direction = DMA_TO_DEVICE; + else + direction = DMA_FROM_DEVICE; + + if (req->req.dma == 0) { + req->req.dma = dma_map_single( + ep->udc->gadget.dev.parent, + req->req.buf, req->req.length, direction); + req->mapped = 1; + } else { + dma_sync_single_for_device( + ep->udc->gadget.dev.parent, req->req.dma, + req->req.length, direction); + req->mapped = 0; + } + + /* For the request, build a list of DDs */ + dd = udc_dd_alloc(udc); + if (!dd) { + /* Error allocating DD */ + return -ENOMEM; + } + req->dd_desc_ptr = dd; + + /* Setup the DMA descriptor */ + dd->dd_next_phy = dd->dd_next_v = 0; + dd->dd_buffer_addr = req->req.dma; + dd->dd_status = 0; + + /* Special handling for ISO EPs */ + if (ep->eptype == EP_ISO_TYPE) { + dd->dd_setup = DD_SETUP_ISO_EP | + DD_SETUP_PACKETLEN(0) | + DD_SETUP_DMALENBYTES(1); + dd->dd_iso_ps_mem_addr = dd->this_dma + 24; + if (ep->is_in) + dd->iso_status[0] = req->req.length; + else + dd->iso_status[0] = 0; + } else + dd->dd_setup = DD_SETUP_PACKETLEN(ep->ep.maxpacket) | + DD_SETUP_DMALENBYTES(req->req.length); + } + + ep_dbg(ep, "%s queue req %p len %d buf %p (in=%d) z=%d\n", _ep->name, + _req, _req->length, _req->buf, ep->is_in, _req->zero); + + spin_lock_irqsave(&udc->lock, flags); + + _req->status = -EINPROGRESS; + _req->actual = 0; + req->send_zlp = _req->zero; + + /* Kickstart empty queues */ + if (list_empty(&ep->queue)) { + list_add_tail(&req->queue, &ep->queue); + + if (ep->hwep_num_base == 0) { + /* Handle expected data direction */ + if (ep->is_in) { + /* IN packet to host */ + udc->ep0state = DATA_IN; + status = udc_ep0_in_req(udc); + } else { + /* OUT packet from host */ + udc->ep0state = DATA_OUT; + status = udc_ep0_out_req(udc); + } + } else if (ep->is_in) { + /* IN packet to host and kick off transfer */ + if (!ep->req_pending) + udc_ep_in_req_dma(udc, ep); + } else + /* OUT packet from host and kick off list */ + if (!ep->req_pending) + udc_ep_out_req_dma(udc, ep); + } else + list_add_tail(&req->queue, &ep->queue); + + spin_unlock_irqrestore(&udc->lock, flags); + + return (status < 0) ? status : 0; +} + +/* Must be called without lock */ +static int lpc32xx_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct lpc32xx_ep *ep; + struct lpc32xx_request *req; + unsigned long flags; + + ep = container_of(_ep, struct lpc32xx_ep, ep); + if (!_ep || ep->hwep_num_base == 0) + return -EINVAL; + + spin_lock_irqsave(&ep->udc->lock, flags); + + /* make sure it's actually queued on this endpoint */ + list_for_each_entry(req, &ep->queue, queue) { + if (&req->req == _req) + break; + } + if (&req->req != _req) { + spin_unlock_irqrestore(&ep->udc->lock, flags); + return -EINVAL; + } + + done(ep, req, -ECONNRESET); + + spin_unlock_irqrestore(&ep->udc->lock, flags); + + return 0; +} + +/* Must be called without lock */ +static int lpc32xx_ep_set_halt(struct usb_ep *_ep, int value) +{ + struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep); + struct lpc32xx_udc *udc = ep->udc; + unsigned long flags; + + if ((!ep) || (ep->desc == NULL) || (ep->hwep_num <= 1)) + return -EINVAL; + + /* Don't halt an IN EP */ + if (ep->is_in) + return -EAGAIN; + + spin_lock_irqsave(&udc->lock, flags); + + if (value == 1) { + /* stall */ + udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(ep->hwep_num), + DAT_WR_BYTE(EP_STAT_ST)); + } else { + /* End stall */ + ep->wedge = 0; + udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(ep->hwep_num), + DAT_WR_BYTE(0)); + } + + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +/* set the halt feature and ignores clear requests */ +static int lpc32xx_ep_set_wedge(struct usb_ep *_ep) +{ + struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep); + + if (!_ep || !ep->udc) + return -EINVAL; + + ep->wedge = 1; + + return usb_ep_set_halt(_ep); +} + +static const struct usb_ep_ops lpc32xx_ep_ops = { + .enable = lpc32xx_ep_enable, + .disable = lpc32xx_ep_disable, + .alloc_request = lpc32xx_ep_alloc_request, + .free_request = lpc32xx_ep_free_request, + .queue = lpc32xx_ep_queue, + .dequeue = lpc32xx_ep_dequeue, + .set_halt = lpc32xx_ep_set_halt, + .set_wedge = lpc32xx_ep_set_wedge, +}; + +/* Send a ZLP on a non-0 IN EP */ +void udc_send_in_zlp(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep) +{ + /* Clear EP status */ + udc_clearep_getsts(udc, ep->hwep_num); + + /* Send ZLP via FIFO mechanism */ + udc_write_hwep(udc, ep->hwep_num, NULL, 0); +} + +/* + * Handle EP completion for ZLP + * This function will only be called when a delayed ZLP needs to be sent out + * after a DMA transfer has filled both buffers. + */ +void udc_handle_eps(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep) +{ + u32 epstatus; + struct lpc32xx_request *req; + + if (ep->hwep_num <= 0) + return; + + uda_clear_hwepint(udc, ep->hwep_num); + + /* If this interrupt isn't enabled, return now */ + if (!(udc->enabled_hwepints & (1 << ep->hwep_num))) + return; + + /* Get endpoint status */ + epstatus = udc_clearep_getsts(udc, ep->hwep_num); + + /* + * This should never happen, but protect against writing to the + * buffer when full. + */ + if (epstatus & EP_SEL_F) + return; + + if (ep->is_in) { + udc_send_in_zlp(udc, ep); + uda_disable_hwepint(udc, ep->hwep_num); + } else + return; + + /* If there isn't a request waiting, something went wrong */ + req = list_entry(ep->queue.next, struct lpc32xx_request, queue); + if (req) { + done(ep, req, 0); + + /* Start another request if ready */ + if (!list_empty(&ep->queue)) { + if (ep->is_in) + udc_ep_in_req_dma(udc, ep); + else + udc_ep_out_req_dma(udc, ep); + } else + ep->req_pending = 0; + } +} + + +/* DMA end of transfer completion */ +static void udc_handle_dma_ep(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep) +{ + u32 status, epstatus; + struct lpc32xx_request *req; + struct lpc32xx_usbd_dd_gad *dd; + +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + ep->totalints++; +#endif + + req = list_entry(ep->queue.next, struct lpc32xx_request, queue); + if (!req) { + ep_err(ep, "DMA interrupt on no req!\n"); + return; + } + dd = req->dd_desc_ptr; + + /* DMA descriptor should always be retired for this call */ + if (!(dd->dd_status & DD_STATUS_DD_RETIRED)) + ep_warn(ep, "DMA descriptor did not retire\n"); + + /* Disable DMA */ + udc_ep_dma_disable(udc, ep->hwep_num); + writel((1 << ep->hwep_num), USBD_EOTINTCLR(udc->udp_baseaddr)); + writel((1 << ep->hwep_num), USBD_NDDRTINTCLR(udc->udp_baseaddr)); + + /* System error? */ + if (readl(USBD_SYSERRTINTST(udc->udp_baseaddr)) & + (1 << ep->hwep_num)) { + writel((1 << ep->hwep_num), + USBD_SYSERRTINTCLR(udc->udp_baseaddr)); + ep_err(ep, "AHB critical error!\n"); + ep->req_pending = 0; + + /* The error could have occurred on a packet of a multipacket + * transfer, so recovering the transfer is not possible. Close + * the request with an error */ + done(ep, req, -ECONNABORTED); + return; + } + + /* Handle the current DD's status */ + status = dd->dd_status; + switch (status & DD_STATUS_STS_MASK) { + case DD_STATUS_STS_NS: + /* DD not serviced? This shouldn't happen! */ + ep->req_pending = 0; + ep_err(ep, "DMA critical EP error: DD not serviced (0x%x)!\n", + status); + + done(ep, req, -ECONNABORTED); + return; + + case DD_STATUS_STS_BS: + /* Interrupt only fires on EOT - This shouldn't happen! */ + ep->req_pending = 0; + ep_err(ep, "DMA critical EP error: EOT prior to service completion (0x%x)!\n", + status); + done(ep, req, -ECONNABORTED); + return; + + case DD_STATUS_STS_NC: + case DD_STATUS_STS_DUR: + /* Really just a short packet, not an underrun */ + /* This is a good status and what we expect */ + break; + + default: + /* Data overrun, system error, or unknown */ + ep->req_pending = 0; + ep_err(ep, "DMA critical EP error: System error (0x%x)!\n", + status); + done(ep, req, -ECONNABORTED); + return; + } + + /* ISO endpoints are handled differently */ + if (ep->eptype == EP_ISO_TYPE) { + if (ep->is_in) + req->req.actual = req->req.length; + else + req->req.actual = dd->iso_status[0] & 0xFFFF; + } else + req->req.actual += DD_STATUS_CURDMACNT(status); + + /* Send a ZLP if necessary. This will be done for non-int + * packets which have a size that is a divisor of MAXP */ + if (req->send_zlp) { + /* + * If at least 1 buffer is available, send the ZLP now. + * Otherwise, the ZLP send needs to be deferred until a + * buffer is available. + */ + if (udc_clearep_getsts(udc, ep->hwep_num) & EP_SEL_F) { + udc_clearep_getsts(udc, ep->hwep_num); + uda_enable_hwepint(udc, ep->hwep_num); + epstatus = udc_clearep_getsts(udc, ep->hwep_num); + + /* Let the EP interrupt handle the ZLP */ + return; + } else + udc_send_in_zlp(udc, ep); + } + + /* Transfer request is complete */ + done(ep, req, 0); + + /* Start another request if ready */ + udc_clearep_getsts(udc, ep->hwep_num); + if (!list_empty((&ep->queue))) { + if (ep->is_in) + udc_ep_in_req_dma(udc, ep); + else + udc_ep_out_req_dma(udc, ep); + } else + ep->req_pending = 0; + +} + +/* + * + * Endpoint 0 functions + * + */ +static void udc_handle_dev(struct lpc32xx_udc *udc) +{ + u32 tmp; + + udc_protocol_cmd_w(udc, CMD_GET_DEV_STAT); + tmp = udc_protocol_cmd_r(udc, DAT_GET_DEV_STAT); + + if (tmp & DEV_RST) + uda_usb_reset(udc); + else if (tmp & DEV_CON_CH) + uda_power_event(udc, (tmp & DEV_CON)); + else if (tmp & DEV_SUS_CH) { + if (tmp & DEV_SUS) { + if (udc->vbus == 0) + stop_activity(udc); + else if ((udc->gadget.speed != USB_SPEED_UNKNOWN) && + udc->driver) { + /* Power down transceiver */ + udc->poweron = 0; + schedule_work(&udc->pullup_job); + uda_resm_susp_event(udc, 1); + } + } else if ((udc->gadget.speed != USB_SPEED_UNKNOWN) && + udc->driver && udc->vbus) { + uda_resm_susp_event(udc, 0); + /* Power up transceiver */ + udc->poweron = 1; + schedule_work(&udc->pullup_job); + } + } +} + +static int udc_get_status(struct lpc32xx_udc *udc, u16 reqtype, u16 wIndex) +{ + struct lpc32xx_ep *ep; + u32 ep0buff = 0, tmp; + + switch (reqtype & USB_RECIP_MASK) { + case USB_RECIP_INTERFACE: + break; /* Not supported */ + + case USB_RECIP_DEVICE: + ep0buff = (udc->selfpowered << USB_DEVICE_SELF_POWERED); + if (udc->dev_status & (1 << USB_DEVICE_REMOTE_WAKEUP)) + ep0buff |= (1 << USB_DEVICE_REMOTE_WAKEUP); + break; + + case USB_RECIP_ENDPOINT: + tmp = wIndex & USB_ENDPOINT_NUMBER_MASK; + ep = &udc->ep[tmp]; + if ((tmp == 0) || (tmp >= NUM_ENDPOINTS) || (tmp && !ep->desc)) + return -EOPNOTSUPP; + + if (wIndex & USB_DIR_IN) { + if (!ep->is_in) + return -EOPNOTSUPP; /* Something's wrong */ + } else if (ep->is_in) + return -EOPNOTSUPP; /* Not an IN endpoint */ + + /* Get status of the endpoint */ + udc_protocol_cmd_w(udc, CMD_SEL_EP(ep->hwep_num)); + tmp = udc_protocol_cmd_r(udc, DAT_SEL_EP(ep->hwep_num)); + + if (tmp & EP_SEL_ST) + ep0buff = (1 << USB_ENDPOINT_HALT); + else + ep0buff = 0; + break; + + default: + break; + } + + /* Return data */ + udc_write_hwep(udc, EP_IN, &ep0buff, 2); + + return 0; +} + +static void udc_handle_ep0_setup(struct lpc32xx_udc *udc) +{ + struct lpc32xx_ep *ep, *ep0 = &udc->ep[0]; + struct usb_ctrlrequest ctrlpkt; + int i, bytes; + u16 wIndex, wValue, wLength, reqtype, req, tmp; + + /* Nuke previous transfers */ + nuke(ep0, -EPROTO); + + /* Get setup packet */ + bytes = udc_read_hwep(udc, EP_OUT, (u32 *) &ctrlpkt, 8); + if (bytes != 8) { + ep_warn(ep0, "Incorrectly sized setup packet (s/b 8, is %d)!\n", + bytes); + return; + } + + /* Native endianness */ + wIndex = le16_to_cpu(ctrlpkt.wIndex); + wValue = le16_to_cpu(ctrlpkt.wValue); + wLength = le16_to_cpu(ctrlpkt.wLength); + reqtype = le16_to_cpu(ctrlpkt.bRequestType); + + /* Set direction of EP0 */ + if (likely(reqtype & USB_DIR_IN)) + ep0->is_in = 1; + else + ep0->is_in = 0; + + /* Handle SETUP packet */ + req = le16_to_cpu(ctrlpkt.bRequest); + switch (req) { + case USB_REQ_CLEAR_FEATURE: + case USB_REQ_SET_FEATURE: + switch (reqtype) { + case (USB_TYPE_STANDARD | USB_RECIP_DEVICE): + if (wValue != USB_DEVICE_REMOTE_WAKEUP) + goto stall; /* Nothing else handled */ + + /* Tell board about event */ + if (req == USB_REQ_CLEAR_FEATURE) + udc->dev_status &= + ~(1 << USB_DEVICE_REMOTE_WAKEUP); + else + udc->dev_status |= + (1 << USB_DEVICE_REMOTE_WAKEUP); + uda_remwkp_cgh(udc); + goto zlp_send; + + case (USB_TYPE_STANDARD | USB_RECIP_ENDPOINT): + tmp = wIndex & USB_ENDPOINT_NUMBER_MASK; + if ((wValue != USB_ENDPOINT_HALT) || + (tmp >= NUM_ENDPOINTS)) + break; + + /* Find hardware endpoint from logical endpoint */ + ep = &udc->ep[tmp]; + tmp = ep->hwep_num; + if (tmp == 0) + break; + + if (req == USB_REQ_SET_FEATURE) + udc_stall_hwep(udc, tmp); + else if (!ep->wedge) + udc_clrstall_hwep(udc, tmp); + + goto zlp_send; + + default: + break; + } + + + case USB_REQ_SET_ADDRESS: + if (reqtype == (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) { + udc_set_address(udc, wValue); + goto zlp_send; + } + break; + + case USB_REQ_GET_STATUS: + udc_get_status(udc, reqtype, wIndex); + return; + + default: + break; /* Let GadgetFS handle the descriptor instead */ + } + + if (likely(udc->driver)) { + /* device-2-host (IN) or no data setup command, process + * immediately */ + spin_unlock(&udc->lock); + i = udc->driver->setup(&udc->gadget, &ctrlpkt); + + spin_lock(&udc->lock); + if (req == USB_REQ_SET_CONFIGURATION) { + /* Configuration is set after endpoints are realized */ + if (wValue) { + /* Set configuration */ + udc_set_device_configured(udc); + + udc_protocol_cmd_data_w(udc, CMD_SET_MODE, + DAT_WR_BYTE(AP_CLK | + INAK_BI | INAK_II)); + } else { + /* Clear configuration */ + udc_set_device_unconfigured(udc); + + /* Disable NAK interrupts */ + udc_protocol_cmd_data_w(udc, CMD_SET_MODE, + DAT_WR_BYTE(AP_CLK)); + } + } + + if (i < 0) { + /* setup processing failed, force stall */ + dev_err(udc->dev, + "req %02x.%02x protocol STALL; stat %d\n", + reqtype, req, i); + udc->ep0state = WAIT_FOR_SETUP; + goto stall; + } + } + + if (!ep0->is_in) + udc_ep0_send_zlp(udc); /* ZLP IN packet on data phase */ + + return; + +stall: + udc_stall_hwep(udc, EP_IN); + return; + +zlp_send: + udc_ep0_send_zlp(udc); + return; +} + +/* IN endpoint 0 transfer */ +static void udc_handle_ep0_in(struct lpc32xx_udc *udc) +{ + struct lpc32xx_ep *ep0 = &udc->ep[0]; + u32 epstatus; + + /* Clear EP interrupt */ + epstatus = udc_clearep_getsts(udc, EP_IN); + +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + ep0->totalints++; +#endif + + /* Stalled? Clear stall and reset buffers */ + if (epstatus & EP_SEL_ST) { + udc_clrstall_hwep(udc, EP_IN); + nuke(ep0, -ECONNABORTED); + udc->ep0state = WAIT_FOR_SETUP; + return; + } + + /* Is a buffer available? */ + if (!(epstatus & EP_SEL_F)) { + /* Handle based on current state */ + if (udc->ep0state == DATA_IN) + udc_ep0_in_req(udc); + else { + /* Unknown state for EP0 oe end of DATA IN phase */ + nuke(ep0, -ECONNABORTED); + udc->ep0state = WAIT_FOR_SETUP; + } + } +} + +/* OUT endpoint 0 transfer */ +static void udc_handle_ep0_out(struct lpc32xx_udc *udc) +{ + struct lpc32xx_ep *ep0 = &udc->ep[0]; + u32 epstatus; + + /* Clear EP interrupt */ + epstatus = udc_clearep_getsts(udc, EP_OUT); + + +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + ep0->totalints++; +#endif + + /* Stalled? */ + if (epstatus & EP_SEL_ST) { + udc_clrstall_hwep(udc, EP_OUT); + nuke(ep0, -ECONNABORTED); + udc->ep0state = WAIT_FOR_SETUP; + return; + } + + /* A NAK may occur if a packet couldn't be received yet */ + if (epstatus & EP_SEL_EPN) + return; + /* Setup packet incoming? */ + if (epstatus & EP_SEL_STP) { + nuke(ep0, 0); + udc->ep0state = WAIT_FOR_SETUP; + } + + /* Data available? */ + if (epstatus & EP_SEL_F) + /* Handle based on current state */ + switch (udc->ep0state) { + case WAIT_FOR_SETUP: + udc_handle_ep0_setup(udc); + break; + + case DATA_OUT: + udc_ep0_out_req(udc); + break; + + default: + /* Unknown state for EP0 */ + nuke(ep0, -ECONNABORTED); + udc->ep0state = WAIT_FOR_SETUP; + } +} + +/* Must be called without lock */ +static int lpc32xx_get_frame(struct usb_gadget *gadget) +{ + int frame; + unsigned long flags; + struct lpc32xx_udc *udc = to_udc(gadget); + + if (!udc->clocked) + return -EINVAL; + + spin_lock_irqsave(&udc->lock, flags); + + frame = (int) udc_get_current_frame(udc); + + spin_unlock_irqrestore(&udc->lock, flags); + + return frame; +} + +static int lpc32xx_wakeup(struct usb_gadget *gadget) +{ + return -ENOTSUPP; +} + +static int lpc32xx_set_selfpowered(struct usb_gadget *gadget, int is_on) +{ + struct lpc32xx_udc *udc = to_udc(gadget); + + /* Always self-powered */ + udc->selfpowered = (is_on != 0); + + return 0; +} + +/* + * vbus is here! turn everything on that's ready + * Must be called without lock + */ +static int lpc32xx_vbus_session(struct usb_gadget *gadget, int is_active) +{ + unsigned long flags; + struct lpc32xx_udc *udc = to_udc(gadget); + + spin_lock_irqsave(&udc->lock, flags); + + /* Doesn't need lock */ + if (udc->driver) { + udc_clk_set(udc, 1); + udc_enable(udc); + pullup(udc, is_active); + } else { + stop_activity(udc); + pullup(udc, 0); + + spin_unlock_irqrestore(&udc->lock, flags); + /* + * Wait for all the endpoints to disable, + * before disabling clocks. Don't wait if + * endpoints are not enabled. + */ + if (atomic_read(&udc->enabled_ep_cnt)) + wait_event_interruptible(udc->ep_disable_wait_queue, + (atomic_read(&udc->enabled_ep_cnt) == 0)); + + spin_lock_irqsave(&udc->lock, flags); + + udc_clk_set(udc, 0); + } + + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +/* Can be called with or without lock */ +static int lpc32xx_pullup(struct usb_gadget *gadget, int is_on) +{ + struct lpc32xx_udc *udc = to_udc(gadget); + + /* Doesn't need lock */ + pullup(udc, is_on); + + return 0; +} + +static int lpc32xx_start(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)); +static int lpc32xx_stop(struct usb_gadget_driver *driver); + +static const struct usb_gadget_ops lpc32xx_udc_ops = { + .get_frame = lpc32xx_get_frame, + .wakeup = lpc32xx_wakeup, + .set_selfpowered = lpc32xx_set_selfpowered, + .vbus_session = lpc32xx_vbus_session, + .pullup = lpc32xx_pullup, + .start = lpc32xx_start, + .stop = lpc32xx_stop, +}; + +static void nop_release(struct device *dev) +{ + /* nothing to free */ +} + +static struct lpc32xx_udc controller = { + .gadget = { + .ops = &lpc32xx_udc_ops, + .ep0 = &controller.ep[0].ep, + .name = driver_name, + .dev = { + .init_name = "gadget", + .release = nop_release, + } + }, + .ep[0] = { + .ep = { + .name = "ep0", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 64, + .hwep_num_base = 0, + .hwep_num = 0, /* Can be 0 or 1, has special handling */ + .lep = 0, + .eptype = EP_CTL_TYPE, + }, + .ep[1] = { + .ep = { + .name = "ep1-int", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 64, + .hwep_num_base = 2, + .hwep_num = 0, /* 2 or 3, will be set later */ + .lep = 1, + .eptype = EP_INT_TYPE, + }, + .ep[2] = { + .ep = { + .name = "ep2-bulk", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 64, + .hwep_num_base = 4, + .hwep_num = 0, /* 4 or 5, will be set later */ + .lep = 2, + .eptype = EP_BLK_TYPE, + }, + .ep[3] = { + .ep = { + .name = "ep3-iso", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 1023, + .hwep_num_base = 6, + .hwep_num = 0, /* 6 or 7, will be set later */ + .lep = 3, + .eptype = EP_ISO_TYPE, + }, + .ep[4] = { + .ep = { + .name = "ep4-int", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 64, + .hwep_num_base = 8, + .hwep_num = 0, /* 8 or 9, will be set later */ + .lep = 4, + .eptype = EP_INT_TYPE, + }, + .ep[5] = { + .ep = { + .name = "ep5-bulk", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 64, + .hwep_num_base = 10, + .hwep_num = 0, /* 10 or 11, will be set later */ + .lep = 5, + .eptype = EP_BLK_TYPE, + }, + .ep[6] = { + .ep = { + .name = "ep6-iso", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 1023, + .hwep_num_base = 12, + .hwep_num = 0, /* 12 or 13, will be set later */ + .lep = 6, + .eptype = EP_ISO_TYPE, + }, + .ep[7] = { + .ep = { + .name = "ep7-int", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 64, + .hwep_num_base = 14, + .hwep_num = 0, + .lep = 7, + .eptype = EP_INT_TYPE, + }, + .ep[8] = { + .ep = { + .name = "ep8-bulk", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 64, + .hwep_num_base = 16, + .hwep_num = 0, + .lep = 8, + .eptype = EP_BLK_TYPE, + }, + .ep[9] = { + .ep = { + .name = "ep9-iso", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 1023, + .hwep_num_base = 18, + .hwep_num = 0, + .lep = 9, + .eptype = EP_ISO_TYPE, + }, + .ep[10] = { + .ep = { + .name = "ep10-int", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 64, + .hwep_num_base = 20, + .hwep_num = 0, + .lep = 10, + .eptype = EP_INT_TYPE, + }, + .ep[11] = { + .ep = { + .name = "ep11-bulk", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 64, + .hwep_num_base = 22, + .hwep_num = 0, + .lep = 11, + .eptype = EP_BLK_TYPE, + }, + .ep[12] = { + .ep = { + .name = "ep12-iso", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 1023, + .hwep_num_base = 24, + .hwep_num = 0, + .lep = 12, + .eptype = EP_ISO_TYPE, + }, + .ep[13] = { + .ep = { + .name = "ep13-int", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 64, + .hwep_num_base = 26, + .hwep_num = 0, + .lep = 13, + .eptype = EP_INT_TYPE, + }, + .ep[14] = { + .ep = { + .name = "ep14-bulk", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 64, + .hwep_num_base = 28, + .hwep_num = 0, + .lep = 14, + .eptype = EP_BLK_TYPE, + }, + .ep[15] = { + .ep = { + .name = "ep15-bulk", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 1023, + .hwep_num_base = 30, + .hwep_num = 0, + .lep = 15, + .eptype = EP_BLK_TYPE, + }, +}; + +/* ISO and status interrupts */ +static irqreturn_t lpc32xx_usb_lp_irq(int irq, void *_udc) +{ + u32 tmp, devstat; + struct lpc32xx_udc *udc = _udc; + + spin_lock(&udc->lock); + + /* Read the device status register */ + devstat = readl(USBD_DEVINTST(udc->udp_baseaddr)); + + devstat &= ~USBD_EP_FAST; + writel(devstat, USBD_DEVINTCLR(udc->udp_baseaddr)); + devstat = devstat & udc->enabled_devints; + + /* Device specific handling needed? */ + if (devstat & USBD_DEV_STAT) + udc_handle_dev(udc); + + /* Start of frame? (devstat & FRAME_INT): + * The frame interrupt isn't really needed for ISO support, + * as the driver will queue the necessary packets */ + + /* Error? */ + if (devstat & ERR_INT) { + /* All types of errors, from cable removal during transfer to + * misc protocol and bit errors. These are mostly for just info, + * as the USB hardware will work around these. If these errors + * happen alot, something is wrong. */ + udc_protocol_cmd_w(udc, CMD_RD_ERR_STAT); + tmp = udc_protocol_cmd_r(udc, DAT_RD_ERR_STAT); + dev_dbg(udc->dev, "Device error (0x%x)!\n", tmp); + } + + spin_unlock(&udc->lock); + + return IRQ_HANDLED; +} + +/* EP interrupts */ +static irqreturn_t lpc32xx_usb_hp_irq(int irq, void *_udc) +{ + u32 tmp; + struct lpc32xx_udc *udc = _udc; + + spin_lock(&udc->lock); + + /* Read the device status register */ + writel(USBD_EP_FAST, USBD_DEVINTCLR(udc->udp_baseaddr)); + + /* Endpoints */ + tmp = readl(USBD_EPINTST(udc->udp_baseaddr)); + + /* Special handling for EP0 */ + if (tmp & (EP_MASK_SEL(0, EP_OUT) | EP_MASK_SEL(0, EP_IN))) { + /* Handle EP0 IN */ + if (tmp & (EP_MASK_SEL(0, EP_IN))) + udc_handle_ep0_in(udc); + + /* Handle EP0 OUT */ + if (tmp & (EP_MASK_SEL(0, EP_OUT))) + udc_handle_ep0_out(udc); + } + + /* All other EPs */ + if (tmp & ~(EP_MASK_SEL(0, EP_OUT) | EP_MASK_SEL(0, EP_IN))) { + int i; + + /* Handle other EP interrupts */ + for (i = 1; i < NUM_ENDPOINTS; i++) { + if (tmp & (1 << udc->ep[i].hwep_num)) + udc_handle_eps(udc, &udc->ep[i]); + } + } + + spin_unlock(&udc->lock); + + return IRQ_HANDLED; +} + +static irqreturn_t lpc32xx_usb_devdma_irq(int irq, void *_udc) +{ + struct lpc32xx_udc *udc = _udc; + + int i; + u32 tmp; + + spin_lock(&udc->lock); + + /* Handle EP DMA EOT interrupts */ + tmp = readl(USBD_EOTINTST(udc->udp_baseaddr)) | + (readl(USBD_EPDMAST(udc->udp_baseaddr)) & + readl(USBD_NDDRTINTST(udc->udp_baseaddr))) | + readl(USBD_SYSERRTINTST(udc->udp_baseaddr)); + for (i = 1; i < NUM_ENDPOINTS; i++) { + if (tmp & (1 << udc->ep[i].hwep_num)) + udc_handle_dma_ep(udc, &udc->ep[i]); + } + + spin_unlock(&udc->lock); + + return IRQ_HANDLED; +} + +/* + * + * VBUS detection, pullup handler, and Gadget cable state notification + * + */ +static void vbus_work(struct work_struct *work) +{ + u8 value; + struct lpc32xx_udc *udc = container_of(work, struct lpc32xx_udc, + vbus_job); + + if (udc->enabled != 0) { + /* Discharge VBUS real quick */ + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DISCHRG); + + /* Give VBUS some time (100mS) to discharge */ + msleep(100); + + /* Disable VBUS discharge resistor */ + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR, + OTG1_VBUS_DISCHRG); + + /* Clear interrupt */ + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_INTERRUPT_LATCH | + ISP1301_I2C_REG_CLEAR_ADDR, ~0); + + /* Get the VBUS status from the transceiver */ + value = i2c_smbus_read_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_OTG_CONTROL_2); + + /* VBUS on or off? */ + if (value & OTG_B_SESS_VLD) + udc->vbus = 1; + else + udc->vbus = 0; + + /* VBUS changed? */ + if (udc->last_vbus != udc->vbus) { + udc->last_vbus = udc->vbus; + lpc32xx_vbus_session(&udc->gadget, udc->vbus); + } + } + + /* Re-enable after completion */ + enable_irq(udc->udp_irq[IRQ_USB_ATX]); +} + +static irqreturn_t lpc32xx_usb_vbus_irq(int irq, void *_udc) +{ + struct lpc32xx_udc *udc = _udc; + + /* Defer handling of VBUS IRQ to work queue */ + disable_irq_nosync(udc->udp_irq[IRQ_USB_ATX]); + schedule_work(&udc->vbus_job); + + return IRQ_HANDLED; +} + +static int lpc32xx_start(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) +{ + struct lpc32xx_udc *udc = &controller; + int retval, i; + + if (!driver || driver->max_speed < USB_SPEED_FULL || + !bind || !driver->setup) { + dev_err(udc->dev, "bad parameter.\n"); + return -EINVAL; + } + + if (udc->driver) { + dev_err(udc->dev, "UDC already has a gadget driver\n"); + return -EBUSY; + } + + udc->driver = driver; + udc->gadget.dev.driver = &driver->driver; + udc->enabled = 1; + udc->selfpowered = 1; + udc->vbus = 0; + + retval = bind(&udc->gadget); + if (retval) { + dev_err(udc->dev, "bind() returned %d\n", retval); + udc->enabled = 0; + udc->selfpowered = 0; + udc->driver = NULL; + udc->gadget.dev.driver = NULL; + return retval; + } + + dev_dbg(udc->dev, "bound to %s\n", driver->driver.name); + + /* Force VBUS process once to check for cable insertion */ + udc->last_vbus = udc->vbus = 0; + schedule_work(&udc->vbus_job); + + /* Do not re-enable ATX IRQ (3) */ + for (i = IRQ_USB_LP; i < IRQ_USB_ATX; i++) + enable_irq(udc->udp_irq[i]); + + return 0; +} + +static int lpc32xx_stop(struct usb_gadget_driver *driver) +{ + int i; + struct lpc32xx_udc *udc = &controller; + + if (!driver || driver != udc->driver || !driver->unbind) + return -EINVAL; + + /* Disable USB pullup */ + isp1301_pullup_enable(udc, 0, 1); + + for (i = IRQ_USB_LP; i <= IRQ_USB_ATX; i++) + disable_irq(udc->udp_irq[i]); + + if (udc->clocked) { + + spin_lock(&udc->lock); + stop_activity(udc); + spin_unlock(&udc->lock); + + /* + * Wait for all the endpoints to disable, + * before disabling clocks. Don't wait if + * endpoints are not enabled. + */ + if (atomic_read(&udc->enabled_ep_cnt)) + wait_event_interruptible(udc->ep_disable_wait_queue, + (atomic_read(&udc->enabled_ep_cnt) == 0)); + + spin_lock(&udc->lock); + udc_clk_set(udc, 0); + spin_unlock(&udc->lock); + } + + udc->enabled = 0; + pullup(udc, 0); + + driver->unbind(&udc->gadget); + udc->gadget.dev.driver = NULL; + udc->driver = NULL; + + dev_dbg(udc->dev, "unbound from %s\n", driver->driver.name); + return 0; +} + +static void lpc32xx_udc_shutdown(struct platform_device *dev) +{ + /* Force disconnect on reboot */ + struct lpc32xx_udc *udc = &controller; + + pullup(udc, 0); +} + +/* + * Callbacks to be overridden by options passed via OF (TODO) + */ + +static void lpc32xx_usbd_conn_chg(int conn) +{ + /* Do nothing, it might be nice to enable an LED + * based on conn state being !0 */ +} + +static void lpc32xx_usbd_susp_chg(int susp) +{ + /* Device suspend if susp != 0 */ +} + +static void lpc32xx_rmwkup_chg(int remote_wakup_enable) +{ + /* Enable or disable USB remote wakeup */ +} + +struct lpc32xx_usbd_cfg lpc32xx_usbddata = { + .vbus_drv_pol = 0, + .conn_chgb = &lpc32xx_usbd_conn_chg, + .susp_chgb = &lpc32xx_usbd_susp_chg, + .rmwk_chgb = &lpc32xx_rmwkup_chg, +}; + + +static u64 lpc32xx_usbd_dmamask = ~(u32) 0x7F; + +static int __init lpc32xx_udc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct lpc32xx_udc *udc = &controller; + int retval, i; + struct resource *res; + dma_addr_t dma_handle; + struct device_node *isp1301_node; + + /* init software state */ + udc->gadget.dev.parent = dev; + udc->pdev = pdev; + udc->dev = &pdev->dev; + udc->enabled = 0; + + if (pdev->dev.of_node) { + isp1301_node = of_parse_phandle(pdev->dev.of_node, + "transceiver", 0); + } else { + isp1301_node = NULL; + } + + udc->isp1301_i2c_client = isp1301_get_client(isp1301_node); + if (!udc->isp1301_i2c_client) + return -EPROBE_DEFER; + + dev_info(udc->dev, "ISP1301 I2C device at address 0x%x\n", + udc->isp1301_i2c_client->addr); + + pdev->dev.dma_mask = &lpc32xx_usbd_dmamask; + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + + udc->board = &lpc32xx_usbddata; + + /* + * Resources are mapped as follows: + * IORESOURCE_MEM, base address and size of USB space + * IORESOURCE_IRQ, USB device low priority interrupt number + * IORESOURCE_IRQ, USB device high priority interrupt number + * IORESOURCE_IRQ, USB device interrupt number + * IORESOURCE_IRQ, USB transceiver interrupt number + */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENXIO; + + spin_lock_init(&udc->lock); + + /* Get IRQs */ + for (i = 0; i < 4; i++) { + udc->udp_irq[i] = platform_get_irq(pdev, i); + if (udc->udp_irq[i] < 0) { + dev_err(udc->dev, + "irq resource %d not available!\n", i); + return udc->udp_irq[i]; + } + } + + udc->io_p_start = res->start; + udc->io_p_size = resource_size(res); + if (!request_mem_region(udc->io_p_start, udc->io_p_size, driver_name)) { + dev_err(udc->dev, "someone's using UDC memory\n"); + return -EBUSY; + } + + udc->udp_baseaddr = ioremap(udc->io_p_start, udc->io_p_size); + if (!udc->udp_baseaddr) { + retval = -ENOMEM; + dev_err(udc->dev, "IO map failure\n"); + goto io_map_fail; + } + + /* Enable AHB slave USB clock, needed for further USB clock control */ + writel(USB_SLAVE_HCLK_EN | (1 << 19), USB_CTRL); + + /* Get required clocks */ + udc->usb_pll_clk = clk_get(&pdev->dev, "ck_pll5"); + if (IS_ERR(udc->usb_pll_clk)) { + dev_err(udc->dev, "failed to acquire USB PLL\n"); + retval = PTR_ERR(udc->usb_pll_clk); + goto pll_get_fail; + } + udc->usb_slv_clk = clk_get(&pdev->dev, "ck_usbd"); + if (IS_ERR(udc->usb_slv_clk)) { + dev_err(udc->dev, "failed to acquire USB device clock\n"); + retval = PTR_ERR(udc->usb_slv_clk); + goto usb_clk_get_fail; + } + + /* Setup PLL clock to 48MHz */ + retval = clk_enable(udc->usb_pll_clk); + if (retval < 0) { + dev_err(udc->dev, "failed to start USB PLL\n"); + goto pll_enable_fail; + } + + retval = clk_set_rate(udc->usb_pll_clk, 48000); + if (retval < 0) { + dev_err(udc->dev, "failed to set USB clock rate\n"); + goto pll_set_fail; + } + + writel(readl(USB_CTRL) | USB_DEV_NEED_CLK_EN, USB_CTRL); + + /* Enable USB device clock */ + retval = clk_enable(udc->usb_slv_clk); + if (retval < 0) { + dev_err(udc->dev, "failed to start USB device clock\n"); + goto usb_clk_enable_fail; + } + + /* Set to enable all needed USB OTG clocks */ + writel(USB_CLOCK_MASK, USB_OTG_CLK_CTRL(udc)); + + i = 1000; + while (((readl(USB_OTG_CLK_STAT(udc)) & USB_CLOCK_MASK) != + USB_CLOCK_MASK) && (i > 0)) + i--; + if (!i) + dev_dbg(udc->dev, "USB OTG clocks not correctly enabled\n"); + + /* Setup deferred workqueue data */ + udc->poweron = udc->pullup = 0; + INIT_WORK(&udc->pullup_job, pullup_work); + INIT_WORK(&udc->vbus_job, vbus_work); +#ifdef CONFIG_PM + INIT_WORK(&udc->power_job, power_work); +#endif + + /* All clocks are now on */ + udc->clocked = 1; + + isp1301_udc_configure(udc); + /* Allocate memory for the UDCA */ + udc->udca_v_base = dma_alloc_coherent(&pdev->dev, UDCA_BUFF_SIZE, + &dma_handle, + (GFP_KERNEL | GFP_DMA)); + if (!udc->udca_v_base) { + dev_err(udc->dev, "error getting UDCA region\n"); + retval = -ENOMEM; + goto i2c_fail; + } + udc->udca_p_base = dma_handle; + dev_dbg(udc->dev, "DMA buffer(0x%x bytes), P:0x%08x, V:0x%p\n", + UDCA_BUFF_SIZE, udc->udca_p_base, udc->udca_v_base); + + /* Setup the DD DMA memory pool */ + udc->dd_cache = dma_pool_create("udc_dd", udc->dev, + sizeof(struct lpc32xx_usbd_dd_gad), + sizeof(u32), 0); + if (!udc->dd_cache) { + dev_err(udc->dev, "error getting DD DMA region\n"); + retval = -ENOMEM; + goto dma_alloc_fail; + } + + /* Clear USB peripheral and initialize gadget endpoints */ + udc_disable(udc); + udc_reinit(udc); + + retval = device_register(&udc->gadget.dev); + if (retval < 0) { + dev_err(udc->dev, "Device registration failure\n"); + goto dev_register_fail; + } + + /* Request IRQs - low and high priority USB device IRQs are routed to + * the same handler, while the DMA interrupt is routed elsewhere */ + retval = request_irq(udc->udp_irq[IRQ_USB_LP], lpc32xx_usb_lp_irq, + 0, "udc_lp", udc); + if (retval < 0) { + dev_err(udc->dev, "LP request irq %d failed\n", + udc->udp_irq[IRQ_USB_LP]); + goto irq_lp_fail; + } + retval = request_irq(udc->udp_irq[IRQ_USB_HP], lpc32xx_usb_hp_irq, + 0, "udc_hp", udc); + if (retval < 0) { + dev_err(udc->dev, "HP request irq %d failed\n", + udc->udp_irq[IRQ_USB_HP]); + goto irq_hp_fail; + } + + retval = request_irq(udc->udp_irq[IRQ_USB_DEVDMA], + lpc32xx_usb_devdma_irq, 0, "udc_dma", udc); + if (retval < 0) { + dev_err(udc->dev, "DEV request irq %d failed\n", + udc->udp_irq[IRQ_USB_DEVDMA]); + goto irq_dev_fail; + } + + /* The transceiver interrupt is used for VBUS detection and will + kick off the VBUS handler function */ + retval = request_irq(udc->udp_irq[IRQ_USB_ATX], lpc32xx_usb_vbus_irq, + 0, "udc_otg", udc); + if (retval < 0) { + dev_err(udc->dev, "VBUS request irq %d failed\n", + udc->udp_irq[IRQ_USB_ATX]); + goto irq_xcvr_fail; + } + + /* Initialize wait queue */ + init_waitqueue_head(&udc->ep_disable_wait_queue); + atomic_set(&udc->enabled_ep_cnt, 0); + + /* Keep all IRQs disabled until GadgetFS starts up */ + for (i = IRQ_USB_LP; i <= IRQ_USB_ATX; i++) + disable_irq(udc->udp_irq[i]); + + retval = usb_add_gadget_udc(dev, &udc->gadget); + if (retval < 0) + goto add_gadget_fail; + + dev_set_drvdata(dev, udc); + device_init_wakeup(dev, 1); + create_debug_file(udc); + + /* Disable clocks for now */ + udc_clk_set(udc, 0); + + dev_info(udc->dev, "%s version %s\n", driver_name, DRIVER_VERSION); + return 0; + +add_gadget_fail: + free_irq(udc->udp_irq[IRQ_USB_ATX], udc); +irq_xcvr_fail: + free_irq(udc->udp_irq[IRQ_USB_DEVDMA], udc); +irq_dev_fail: + free_irq(udc->udp_irq[IRQ_USB_HP], udc); +irq_hp_fail: + free_irq(udc->udp_irq[IRQ_USB_LP], udc); +irq_lp_fail: + device_unregister(&udc->gadget.dev); +dev_register_fail: + dma_pool_destroy(udc->dd_cache); +dma_alloc_fail: + dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE, + udc->udca_v_base, udc->udca_p_base); +i2c_fail: + clk_disable(udc->usb_slv_clk); +usb_clk_enable_fail: +pll_set_fail: + clk_disable(udc->usb_pll_clk); +pll_enable_fail: + clk_put(udc->usb_slv_clk); +usb_clk_get_fail: + clk_put(udc->usb_pll_clk); +pll_get_fail: + iounmap(udc->udp_baseaddr); +io_map_fail: + release_mem_region(udc->io_p_start, udc->io_p_size); + dev_err(udc->dev, "%s probe failed, %d\n", driver_name, retval); + + return retval; +} + +static int __devexit lpc32xx_udc_remove(struct platform_device *pdev) +{ + struct lpc32xx_udc *udc = platform_get_drvdata(pdev); + + usb_del_gadget_udc(&udc->gadget); + if (udc->driver) + return -EBUSY; + + udc_clk_set(udc, 1); + udc_disable(udc); + pullup(udc, 0); + + free_irq(udc->udp_irq[IRQ_USB_ATX], udc); + + device_init_wakeup(&pdev->dev, 0); + remove_debug_file(udc); + + dma_pool_destroy(udc->dd_cache); + dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE, + udc->udca_v_base, udc->udca_p_base); + free_irq(udc->udp_irq[IRQ_USB_DEVDMA], udc); + free_irq(udc->udp_irq[IRQ_USB_HP], udc); + free_irq(udc->udp_irq[IRQ_USB_LP], udc); + + device_unregister(&udc->gadget.dev); + + clk_disable(udc->usb_slv_clk); + clk_put(udc->usb_slv_clk); + clk_disable(udc->usb_pll_clk); + clk_put(udc->usb_pll_clk); + iounmap(udc->udp_baseaddr); + release_mem_region(udc->io_p_start, udc->io_p_size); + + return 0; +} + +#ifdef CONFIG_PM +static int lpc32xx_udc_suspend(struct platform_device *pdev, pm_message_t mesg) +{ + int to = 1000; + struct lpc32xx_udc *udc = platform_get_drvdata(pdev); + + if (udc->clocked) { + /* Power down ISP */ + udc->poweron = 0; + isp1301_set_powerstate(udc, 0); + + /* Disable clocking */ + udc_clk_set(udc, 0); + + /* Keep clock flag on, so we know to re-enable clocks + on resume */ + udc->clocked = 1; + + /* Kill OTG and I2C clocks */ + writel(0, USB_OTG_CLK_CTRL(udc)); + while (((readl(USB_OTG_CLK_STAT(udc)) & OTGOFF_CLK_MASK) != + OTGOFF_CLK_MASK) && (to > 0)) + to--; + if (!to) + dev_dbg(udc->dev, + "USB OTG clocks not correctly enabled\n"); + + /* Kill global USB clock */ + clk_disable(udc->usb_slv_clk); + } + + return 0; +} + +static int lpc32xx_udc_resume(struct platform_device *pdev) +{ + struct lpc32xx_udc *udc = platform_get_drvdata(pdev); + + if (udc->clocked) { + /* Enable global USB clock */ + clk_enable(udc->usb_slv_clk); + + /* Enable clocking */ + udc_clk_set(udc, 1); + + /* ISP back to normal power mode */ + udc->poweron = 1; + isp1301_set_powerstate(udc, 1); + } + + return 0; +} +#else +#define lpc32xx_udc_suspend NULL +#define lpc32xx_udc_resume NULL +#endif + +#ifdef CONFIG_OF +static struct of_device_id lpc32xx_udc_of_match[] = { + { .compatible = "nxp,lpc3220-udc", }, + { }, +}; +MODULE_DEVICE_TABLE(of, lpc32xx_udc_of_match); +#endif + +static struct platform_driver lpc32xx_udc_driver = { + .remove = __devexit_p(lpc32xx_udc_remove), + .shutdown = lpc32xx_udc_shutdown, + .suspend = lpc32xx_udc_suspend, + .resume = lpc32xx_udc_resume, + .driver = { + .name = (char *) driver_name, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(lpc32xx_udc_of_match), + }, +}; + +static int __init udc_init_module(void) +{ + return platform_driver_probe(&lpc32xx_udc_driver, lpc32xx_udc_probe); +} +module_init(udc_init_module); + +static void __exit udc_exit_module(void) +{ + platform_driver_unregister(&lpc32xx_udc_driver); +} +module_exit(udc_exit_module); + +MODULE_DESCRIPTION("LPC32XX udc driver"); +MODULE_AUTHOR("Kevin Wells "); +MODULE_AUTHOR("Roland Stigge "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:lpc32xx_udc"); diff --git a/trunk/drivers/usb/gadget/m66592-udc.c b/trunk/drivers/usb/gadget/m66592-udc.c index 3608b3bd5732..8981fbb5748c 100644 --- a/trunk/drivers/usb/gadget/m66592-udc.c +++ b/trunk/drivers/usb/gadget/m66592-udc.c @@ -390,7 +390,7 @@ static int alloc_pipe_config(struct m66592_ep *ep, int *counter; int ret; - ep->desc = desc; + ep->ep.desc = desc; BUG_ON(ep->pipenum); @@ -558,7 +558,7 @@ static void start_packet_read(struct m66592_ep *ep, struct m66592_request *req) static void start_packet(struct m66592_ep *ep, struct m66592_request *req) { - if (ep->desc->bEndpointAddress & USB_DIR_IN) + if (ep->ep.desc->bEndpointAddress & USB_DIR_IN) start_packet_write(ep, req); else start_packet_read(ep, req); @@ -734,7 +734,7 @@ __acquires(m66592->lock) if (restart) { req = list_entry(ep->queue.next, struct m66592_request, queue); - if (ep->desc) + if (ep->ep.desc) start_packet(ep, req); } } @@ -917,7 +917,7 @@ static void irq_pipe_ready(struct m66592 *m66592, u16 status, u16 enb) ep = m66592->pipenum2ep[pipenum]; req = list_entry(ep->queue.next, struct m66592_request, queue); - if (ep->desc->bEndpointAddress & USB_DIR_IN) + if (ep->ep.desc->bEndpointAddress & USB_DIR_IN) irq_packet_write(ep, req); else irq_packet_read(ep, req); @@ -1377,7 +1377,7 @@ static int m66592_queue(struct usb_ep *_ep, struct usb_request *_req, req->req.actual = 0; req->req.status = -EINPROGRESS; - if (ep->desc == NULL) /* control */ + if (ep->ep.desc == NULL) /* control */ start_ep0(ep, req); else { if (request && !ep->busy) diff --git a/trunk/drivers/usb/gadget/m66592-udc.h b/trunk/drivers/usb/gadget/m66592-udc.h index 9d9f7e39f037..88c85b4116a2 100644 --- a/trunk/drivers/usb/gadget/m66592-udc.h +++ b/trunk/drivers/usb/gadget/m66592-udc.h @@ -456,7 +456,7 @@ struct m66592_ep { unsigned use_dma:1; u16 pipenum; u16 type; - const struct usb_endpoint_descriptor *desc; + /* register address */ unsigned long fifoaddr; unsigned long fifosel; diff --git a/trunk/drivers/usb/gadget/mv_udc.h b/trunk/drivers/usb/gadget/mv_udc.h index e2be9519abbe..9073436d8b24 100644 --- a/trunk/drivers/usb/gadget/mv_udc.h +++ b/trunk/drivers/usb/gadget/mv_udc.h @@ -232,7 +232,6 @@ struct mv_ep { struct mv_udc *udc; struct list_head queue; struct mv_dqh *dqh; - const struct usb_endpoint_descriptor *desc; u32 direction; char name[14]; unsigned stopped:1, diff --git a/trunk/drivers/usb/gadget/mv_udc_core.c b/trunk/drivers/usb/gadget/mv_udc_core.c index a73cf406e2a4..dbcd1329495e 100644 --- a/trunk/drivers/usb/gadget/mv_udc_core.c +++ b/trunk/drivers/usb/gadget/mv_udc_core.c @@ -464,7 +464,7 @@ static int mv_ep_enable(struct usb_ep *_ep, ep = container_of(_ep, struct mv_ep, ep); udc = ep->udc; - if (!_ep || !desc || ep->desc + if (!_ep || !desc || ep->ep.desc || desc->bDescriptorType != USB_DT_ENDPOINT) return -EINVAL; @@ -528,7 +528,7 @@ static int mv_ep_enable(struct usb_ep *_ep, dqh->size_ioc_int_sts = 0; ep->ep.maxpacket = max; - ep->desc = desc; + ep->ep.desc = desc; ep->stopped = 0; /* Enable the endpoint for Rx or Tx and set the endpoint type */ @@ -580,7 +580,7 @@ static int mv_ep_disable(struct usb_ep *_ep) unsigned long flags; ep = container_of(_ep, struct mv_ep, ep); - if ((_ep == NULL) || !ep->desc) + if ((_ep == NULL) || !ep->ep.desc) return -EINVAL; udc = ep->udc; @@ -606,7 +606,6 @@ static int mv_ep_disable(struct usb_ep *_ep) /* nuke all pending requests (does flush) */ nuke(ep, -ESHUTDOWN); - ep->desc = NULL; ep->ep.desc = NULL; ep->stopped = 1; @@ -651,7 +650,7 @@ static void mv_ep_fifo_flush(struct usb_ep *_ep) return; ep = container_of(_ep, struct mv_ep, ep); - if (!ep->desc) + if (!ep->ep.desc) return; udc = ep->udc; @@ -715,11 +714,11 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) dev_err(&udc->dev->dev, "%s, bad params", __func__); return -EINVAL; } - if (unlikely(!_ep || !ep->desc)) { + if (unlikely(!_ep || !ep->ep.desc)) { dev_err(&udc->dev->dev, "%s, bad ep", __func__); return -EINVAL; } - if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { + if (ep->ep.desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { if (req->req.length > ep->ep.maxpacket) return -EMSGSIZE; } @@ -925,12 +924,12 @@ static int mv_ep_set_halt_wedge(struct usb_ep *_ep, int halt, int wedge) ep = container_of(_ep, struct mv_ep, ep); udc = ep->udc; - if (!_ep || !ep->desc) { + if (!_ep || !ep->ep.desc) { status = -EINVAL; goto out; } - if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { + if (ep->ep.desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { status = -EOPNOTSUPP; goto out; } @@ -1279,7 +1278,7 @@ static int eps_init(struct mv_udc *udc) ep->stopped = 0; ep->ep.maxpacket = EP0_MAX_PKT_SIZE; ep->ep_num = 0; - ep->desc = &mv_ep0_desc; + ep->ep.desc = &mv_ep0_desc; INIT_LIST_HEAD(&ep->queue); ep->ep_type = USB_ENDPOINT_XFER_CONTROL; diff --git a/trunk/drivers/usb/gadget/ndis.h b/trunk/drivers/usb/gadget/ndis.h index b0e52fc277b4..a19f72dec0cd 100644 --- a/trunk/drivers/usb/gadget/ndis.h +++ b/trunk/drivers/usb/gadget/ndis.h @@ -15,11 +15,6 @@ #ifndef _LINUX_NDIS_H #define _LINUX_NDIS_H - -#define NDIS_STATUS_MULTICAST_FULL 0xC0010009 -#define NDIS_STATUS_MULTICAST_EXISTS 0xC001000A -#define NDIS_STATUS_MULTICAST_NOT_FOUND 0xC001000B - enum NDIS_DEVICE_POWER_STATE { NdisDeviceStateUnspecified = 0, NdisDeviceStateD0, @@ -35,11 +30,6 @@ struct NDIS_PM_WAKE_UP_CAPABILITIES { enum NDIS_DEVICE_POWER_STATE MinLinkChangeWakeUp; }; -/* NDIS_PNP_CAPABILITIES.Flags constants */ -#define NDIS_DEVICE_WAKE_UP_ENABLE 0x00000001 -#define NDIS_DEVICE_WAKE_ON_PATTERN_MATCH_ENABLE 0x00000002 -#define NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE 0x00000004 - struct NDIS_PNP_CAPABILITIES { __le32 Flags; struct NDIS_PM_WAKE_UP_CAPABILITIES WakeUpCapabilities; @@ -54,158 +44,4 @@ struct NDIS_PM_PACKET_PATTERN { __le32 PatternFlags; }; - -/* Required Object IDs (OIDs) */ -#define OID_GEN_SUPPORTED_LIST 0x00010101 -#define OID_GEN_HARDWARE_STATUS 0x00010102 -#define OID_GEN_MEDIA_SUPPORTED 0x00010103 -#define OID_GEN_MEDIA_IN_USE 0x00010104 -#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105 -#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106 -#define OID_GEN_LINK_SPEED 0x00010107 -#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108 -#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109 -#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A -#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B -#define OID_GEN_VENDOR_ID 0x0001010C -#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D -#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E -#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F -#define OID_GEN_DRIVER_VERSION 0x00010110 -#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111 -#define OID_GEN_PROTOCOL_OPTIONS 0x00010112 -#define OID_GEN_MAC_OPTIONS 0x00010113 -#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114 -#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115 -#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116 -#define OID_GEN_SUPPORTED_GUIDS 0x00010117 -#define OID_GEN_NETWORK_LAYER_ADDRESSES 0x00010118 -#define OID_GEN_TRANSPORT_HEADER_OFFSET 0x00010119 -#define OID_GEN_MACHINE_NAME 0x0001021A -#define OID_GEN_RNDIS_CONFIG_PARAMETER 0x0001021B -#define OID_GEN_VLAN_ID 0x0001021C - -/* Optional OIDs */ -#define OID_GEN_MEDIA_CAPABILITIES 0x00010201 -#define OID_GEN_PHYSICAL_MEDIUM 0x00010202 - -/* Required statistics OIDs */ -#define OID_GEN_XMIT_OK 0x00020101 -#define OID_GEN_RCV_OK 0x00020102 -#define OID_GEN_XMIT_ERROR 0x00020103 -#define OID_GEN_RCV_ERROR 0x00020104 -#define OID_GEN_RCV_NO_BUFFER 0x00020105 - -/* Optional statistics OIDs */ -#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201 -#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202 -#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203 -#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204 -#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205 -#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206 -#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207 -#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208 -#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209 -#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A -#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B -#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C -#define OID_GEN_RCV_CRC_ERROR 0x0002020D -#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E -#define OID_GEN_GET_TIME_CAPS 0x0002020F -#define OID_GEN_GET_NETCARD_TIME 0x00020210 -#define OID_GEN_NETCARD_LOAD 0x00020211 -#define OID_GEN_DEVICE_PROFILE 0x00020212 -#define OID_GEN_INIT_TIME_MS 0x00020213 -#define OID_GEN_RESET_COUNTS 0x00020214 -#define OID_GEN_MEDIA_SENSE_COUNTS 0x00020215 -#define OID_GEN_FRIENDLY_NAME 0x00020216 -#define OID_GEN_MINIPORT_INFO 0x00020217 -#define OID_GEN_RESET_VERIFY_PARAMETERS 0x00020218 - -/* IEEE 802.3 (Ethernet) OIDs */ -#define NDIS_802_3_MAC_OPTION_PRIORITY 0x00000001 - -#define OID_802_3_PERMANENT_ADDRESS 0x01010101 -#define OID_802_3_CURRENT_ADDRESS 0x01010102 -#define OID_802_3_MULTICAST_LIST 0x01010103 -#define OID_802_3_MAXIMUM_LIST_SIZE 0x01010104 -#define OID_802_3_MAC_OPTIONS 0x01010105 -#define OID_802_3_RCV_ERROR_ALIGNMENT 0x01020101 -#define OID_802_3_XMIT_ONE_COLLISION 0x01020102 -#define OID_802_3_XMIT_MORE_COLLISIONS 0x01020103 -#define OID_802_3_XMIT_DEFERRED 0x01020201 -#define OID_802_3_XMIT_MAX_COLLISIONS 0x01020202 -#define OID_802_3_RCV_OVERRUN 0x01020203 -#define OID_802_3_XMIT_UNDERRUN 0x01020204 -#define OID_802_3_XMIT_HEARTBEAT_FAILURE 0x01020205 -#define OID_802_3_XMIT_TIMES_CRS_LOST 0x01020206 -#define OID_802_3_XMIT_LATE_COLLISIONS 0x01020207 - -/* OID_GEN_MINIPORT_INFO constants */ -#define NDIS_MINIPORT_BUS_MASTER 0x00000001 -#define NDIS_MINIPORT_WDM_DRIVER 0x00000002 -#define NDIS_MINIPORT_SG_LIST 0x00000004 -#define NDIS_MINIPORT_SUPPORTS_MEDIA_QUERY 0x00000008 -#define NDIS_MINIPORT_INDICATES_PACKETS 0x00000010 -#define NDIS_MINIPORT_IGNORE_PACKET_QUEUE 0x00000020 -#define NDIS_MINIPORT_IGNORE_REQUEST_QUEUE 0x00000040 -#define NDIS_MINIPORT_IGNORE_TOKEN_RING_ERRORS 0x00000080 -#define NDIS_MINIPORT_INTERMEDIATE_DRIVER 0x00000100 -#define NDIS_MINIPORT_IS_NDIS_5 0x00000200 -#define NDIS_MINIPORT_IS_CO 0x00000400 -#define NDIS_MINIPORT_DESERIALIZE 0x00000800 -#define NDIS_MINIPORT_REQUIRES_MEDIA_POLLING 0x00001000 -#define NDIS_MINIPORT_SUPPORTS_MEDIA_SENSE 0x00002000 -#define NDIS_MINIPORT_NETBOOT_CARD 0x00004000 -#define NDIS_MINIPORT_PM_SUPPORTED 0x00008000 -#define NDIS_MINIPORT_SUPPORTS_MAC_ADDRESS_OVERWRITE 0x00010000 -#define NDIS_MINIPORT_USES_SAFE_BUFFER_APIS 0x00020000 -#define NDIS_MINIPORT_HIDDEN 0x00040000 -#define NDIS_MINIPORT_SWENUM 0x00080000 -#define NDIS_MINIPORT_SURPRISE_REMOVE_OK 0x00100000 -#define NDIS_MINIPORT_NO_HALT_ON_SUSPEND 0x00200000 -#define NDIS_MINIPORT_HARDWARE_DEVICE 0x00400000 -#define NDIS_MINIPORT_SUPPORTS_CANCEL_SEND_PACKETS 0x00800000 -#define NDIS_MINIPORT_64BITS_DMA 0x01000000 - -#define NDIS_MEDIUM_802_3 0x00000000 -#define NDIS_MEDIUM_802_5 0x00000001 -#define NDIS_MEDIUM_FDDI 0x00000002 -#define NDIS_MEDIUM_WAN 0x00000003 -#define NDIS_MEDIUM_LOCAL_TALK 0x00000004 -#define NDIS_MEDIUM_DIX 0x00000005 -#define NDIS_MEDIUM_ARCENT_RAW 0x00000006 -#define NDIS_MEDIUM_ARCENT_878_2 0x00000007 -#define NDIS_MEDIUM_ATM 0x00000008 -#define NDIS_MEDIUM_WIRELESS_LAN 0x00000009 -#define NDIS_MEDIUM_IRDA 0x0000000A -#define NDIS_MEDIUM_BPC 0x0000000B -#define NDIS_MEDIUM_CO_WAN 0x0000000C -#define NDIS_MEDIUM_1394 0x0000000D - -#define NDIS_PACKET_TYPE_DIRECTED 0x00000001 -#define NDIS_PACKET_TYPE_MULTICAST 0x00000002 -#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004 -#define NDIS_PACKET_TYPE_BROADCAST 0x00000008 -#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010 -#define NDIS_PACKET_TYPE_PROMISCUOUS 0x00000020 -#define NDIS_PACKET_TYPE_SMT 0x00000040 -#define NDIS_PACKET_TYPE_ALL_LOCAL 0x00000080 -#define NDIS_PACKET_TYPE_GROUP 0x00000100 -#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x00000200 -#define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400 -#define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800 - -#define NDIS_MEDIA_STATE_CONNECTED 0x00000000 -#define NDIS_MEDIA_STATE_DISCONNECTED 0x00000001 - -#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA 0x00000001 -#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED 0x00000002 -#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND 0x00000004 -#define NDIS_MAC_OPTION_NO_LOOPBACK 0x00000008 -#define NDIS_MAC_OPTION_FULL_DUPLEX 0x00000010 -#define NDIS_MAC_OPTION_EOTX_INDICATION 0x00000020 -#define NDIS_MAC_OPTION_8021P_PRIORITY 0x00000040 -#define NDIS_MAC_OPTION_RESERVED 0x80000000 - #endif /* _LINUX_NDIS_H */ diff --git a/trunk/drivers/usb/gadget/omap_udc.c b/trunk/drivers/usb/gadget/omap_udc.c index 3b4b6dd0f95a..7ba32469c5bd 100644 --- a/trunk/drivers/usb/gadget/omap_udc.c +++ b/trunk/drivers/usb/gadget/omap_udc.c @@ -153,7 +153,7 @@ static int omap_ep_enable(struct usb_ep *_ep, u16 maxp; /* catch various bogus parameters */ - if (!_ep || !desc || ep->desc + if (!_ep || !desc || ep->ep.desc || desc->bDescriptorType != USB_DT_ENDPOINT || ep->bEndpointAddress != desc->bEndpointAddress || ep->maxpacket < usb_endpoint_maxp(desc)) { @@ -200,7 +200,7 @@ static int omap_ep_enable(struct usb_ep *_ep, spin_lock_irqsave(&udc->lock, flags); - ep->desc = desc; + ep->ep.desc = desc; ep->irqs = 0; ep->stopped = 0; ep->ep.maxpacket = maxp; @@ -242,14 +242,13 @@ static int omap_ep_disable(struct usb_ep *_ep) struct omap_ep *ep = container_of(_ep, struct omap_ep, ep); unsigned long flags; - if (!_ep || !ep->desc) { + if (!_ep || !ep->ep.desc) { DBG("%s, %s not enabled\n", __func__, _ep ? ep->ep.name : NULL); return -EINVAL; } spin_lock_irqsave(&ep->udc->lock, flags); - ep->desc = NULL; ep->ep.desc = NULL; nuke (ep, -ESHUTDOWN); ep->ep.maxpacket = ep->maxpacket; @@ -917,7 +916,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) DBG("%s, bad params\n", __func__); return -EINVAL; } - if (!_ep || (!ep->desc && ep->bEndpointAddress)) { + if (!_ep || (!ep->ep.desc && ep->bEndpointAddress)) { DBG("%s, bad ep\n", __func__); return -EINVAL; } @@ -1121,7 +1120,7 @@ static int omap_ep_set_halt(struct usb_ep *_ep, int value) status = 0; /* otherwise, all active non-ISO endpoints can halt */ - } else if (ep->bmAttributes != USB_ENDPOINT_XFER_ISOC && ep->desc) { + } else if (ep->bmAttributes != USB_ENDPOINT_XFER_ISOC && ep->ep.desc) { /* IN endpoints must already be idle */ if ((ep->bEndpointAddress & USB_DIR_IN) @@ -1625,7 +1624,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) if (w_index & USB_DIR_IN) ep += 16; if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC - || !ep->desc) + || !ep->ep.desc) goto do_stall; use_ep(ep, 0); omap_writew(udc->clr_halt, UDC_CTRL); @@ -1653,7 +1652,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) if (w_index & USB_DIR_IN) ep += 16; if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC - || ep == ep0 || !ep->desc) + || ep == ep0 || !ep->ep.desc) goto do_stall; if (use_dma && ep->has_dma) { /* this has rude side-effects (aborts) and @@ -1688,7 +1687,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) ep = &udc->ep[w_index & 0xf]; if (w_index & USB_DIR_IN) ep += 16; - if (!ep->desc) + if (!ep->ep.desc) goto do_stall; /* iso never stalls */ @@ -2509,7 +2508,7 @@ static int proc_udc_show(struct seq_file *s, void *_) if (tmp & UDC_ADD) { list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) { - if (ep->desc) + if (ep->ep.desc) proc_ep_show(s, ep); } } diff --git a/trunk/drivers/usb/gadget/omap_udc.h b/trunk/drivers/usb/gadget/omap_udc.h index 59d3b2213cb1..cfadeb5fc5de 100644 --- a/trunk/drivers/usb/gadget/omap_udc.h +++ b/trunk/drivers/usb/gadget/omap_udc.h @@ -140,7 +140,6 @@ struct omap_ep { struct list_head queue; unsigned long irqs; struct list_head iso; - const struct usb_endpoint_descriptor *desc; char name[14]; u16 maxpacket; u8 bEndpointAddress; diff --git a/trunk/drivers/usb/gadget/pch_udc.c b/trunk/drivers/usb/gadget/pch_udc.c index 65307064a6fd..1cfcc9ecbfbc 100644 --- a/trunk/drivers/usb/gadget/pch_udc.c +++ b/trunk/drivers/usb/gadget/pch_udc.c @@ -295,7 +295,6 @@ struct pch_udc_ep { struct pch_udc_data_dma_desc *td_data; struct pch_udc_dev *dev; unsigned long offset_addr; - const struct usb_endpoint_descriptor *desc; struct list_head queue; unsigned num:5, in:1, @@ -1705,7 +1704,7 @@ static int pch_udc_pcd_ep_enable(struct usb_ep *usbep, if (!dev->driver || (dev->gadget.speed == USB_SPEED_UNKNOWN)) return -ESHUTDOWN; spin_lock_irqsave(&dev->lock, iflags); - ep->desc = desc; + ep->ep.desc = desc; ep->halted = 0; pch_udc_ep_enable(ep, &ep->dev->cfg_data, desc); ep->ep.maxpacket = usb_endpoint_maxp(desc); @@ -1734,7 +1733,7 @@ static int pch_udc_pcd_ep_disable(struct usb_ep *usbep) ep = container_of(usbep, struct pch_udc_ep, ep); dev = ep->dev; - if ((usbep->name == ep0_string) || !ep->desc) + if ((usbep->name == ep0_string) || !ep->ep.desc) return -EINVAL; spin_lock_irqsave(&ep->dev->lock, iflags); @@ -1742,7 +1741,6 @@ static int pch_udc_pcd_ep_disable(struct usb_ep *usbep) ep->halted = 1; pch_udc_ep_disable(ep); pch_udc_disable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num)); - ep->desc = NULL; ep->ep.desc = NULL; INIT_LIST_HEAD(&ep->queue); spin_unlock_irqrestore(&ep->dev->lock, iflags); @@ -1849,7 +1847,7 @@ static int pch_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq, return -EINVAL; ep = container_of(usbep, struct pch_udc_ep, ep); dev = ep->dev; - if (!ep->desc && ep->num) + if (!ep->ep.desc && ep->num) return -EINVAL; req = container_of(usbreq, struct pch_udc_request, req); if (!list_empty(&req->queue)) @@ -1949,7 +1947,7 @@ static int pch_udc_pcd_dequeue(struct usb_ep *usbep, ep = container_of(usbep, struct pch_udc_ep, ep); dev = ep->dev; - if (!usbep || !usbreq || (!ep->desc && ep->num)) + if (!usbep || !usbreq || (!ep->ep.desc && ep->num)) return ret; req = container_of(usbreq, struct pch_udc_request, req); spin_lock_irqsave(&ep->dev->lock, flags); @@ -1988,7 +1986,7 @@ static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt) return -EINVAL; ep = container_of(usbep, struct pch_udc_ep, ep); dev = ep->dev; - if (!ep->desc && !ep->num) + if (!ep->ep.desc && !ep->num) return -EINVAL; if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN)) return -ESHUTDOWN; @@ -2033,7 +2031,7 @@ static int pch_udc_pcd_set_wedge(struct usb_ep *usbep) return -EINVAL; ep = container_of(usbep, struct pch_udc_ep, ep); dev = ep->dev; - if (!ep->desc && !ep->num) + if (!ep->ep.desc && !ep->num) return -EINVAL; if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN)) return -ESHUTDOWN; @@ -2065,7 +2063,7 @@ static void pch_udc_pcd_fifo_flush(struct usb_ep *usbep) return; ep = container_of(usbep, struct pch_udc_ep, ep); - if (ep->desc || !ep->num) + if (ep->ep.desc || !ep->num) pch_udc_ep_fifo_flush(ep, ep->in); } @@ -3282,7 +3280,6 @@ static DEFINE_PCI_DEVICE_TABLE(pch_udc_pcidev_id) = { MODULE_DEVICE_TABLE(pci, pch_udc_pcidev_id); - static struct pci_driver pch_udc_driver = { .name = KBUILD_MODNAME, .id_table = pch_udc_pcidev_id, @@ -3293,17 +3290,7 @@ static struct pci_driver pch_udc_driver = { .shutdown = pch_udc_shutdown, }; -static int __init pch_udc_pci_init(void) -{ - return pci_register_driver(&pch_udc_driver); -} -module_init(pch_udc_pci_init); - -static void __exit pch_udc_pci_exit(void) -{ - pci_unregister_driver(&pch_udc_driver); -} -module_exit(pch_udc_pci_exit); +module_pci_driver(pch_udc_driver); MODULE_DESCRIPTION("Intel EG20T USB Device Controller"); MODULE_AUTHOR("LAPIS Semiconductor, "); diff --git a/trunk/drivers/usb/gadget/printer.c b/trunk/drivers/usb/gadget/printer.c index 4e4dc1f5f388..f1f9290a2f47 100644 --- a/trunk/drivers/usb/gadget/printer.c +++ b/trunk/drivers/usb/gadget/printer.c @@ -51,6 +51,7 @@ * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ +#include "composite.c" #include "usbstring.c" #include "config.c" #include "epautoconf.c" @@ -75,8 +76,6 @@ struct printer_dev { /* lock buffer lists during read/write calls */ struct mutex lock_printer_io; struct usb_gadget *gadget; - struct usb_request *req; /* for control responses */ - u8 config; s8 interface; struct usb_ep *in_ep, *out_ep; @@ -100,6 +99,7 @@ struct printer_dev { struct device *pdev; u8 printer_cdev_open; wait_queue_head_t wait; + struct usb_function function; }; static struct printer_dev usb_printer_gadget; @@ -120,26 +120,6 @@ static struct printer_dev usb_printer_gadget; * parameters are in UTF-8 (superset of ASCII's 7 bit characters). */ -static ushort idVendor; -module_param(idVendor, ushort, S_IRUGO); -MODULE_PARM_DESC(idVendor, "USB Vendor ID"); - -static ushort idProduct; -module_param(idProduct, ushort, S_IRUGO); -MODULE_PARM_DESC(idProduct, "USB Product ID"); - -static ushort bcdDevice; -module_param(bcdDevice, ushort, S_IRUGO); -MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)"); - -static char *iManufacturer; -module_param(iManufacturer, charp, S_IRUGO); -MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string"); - -static char *iProduct; -module_param(iProduct, charp, S_IRUGO); -MODULE_PARM_DESC(iProduct, "USB Product string"); - static char *iSerialNum; module_param(iSerialNum, charp, S_IRUGO); MODULE_PARM_DESC(iSerialNum, "1"); @@ -154,47 +134,8 @@ module_param(qlen, uint, S_IRUGO|S_IWUSR); #define QLEN qlen -#ifdef CONFIG_USB_GADGET_DUALSPEED -#define DEVSPEED USB_SPEED_HIGH -#else /* full speed (low speed doesn't do bulk) */ -#define DEVSPEED USB_SPEED_FULL -#endif - /*-------------------------------------------------------------------------*/ -#define xprintk(d, level, fmt, args...) \ - printk(level "%s: " fmt, DRIVER_DESC, ## args) - -#ifdef DEBUG -#define DBG(dev, fmt, args...) \ - xprintk(dev, KERN_DEBUG, fmt, ## args) -#else -#define DBG(dev, fmt, args...) \ - do { } while (0) -#endif /* DEBUG */ - -#ifdef VERBOSE -#define VDBG(dev, fmt, args...) \ - xprintk(dev, KERN_DEBUG, fmt, ## args) -#else -#define VDBG(dev, fmt, args...) \ - do { } while (0) -#endif /* VERBOSE */ - -#define ERROR(dev, fmt, args...) \ - xprintk(dev, KERN_ERR, fmt, ## args) -#define WARNING(dev, fmt, args...) \ - xprintk(dev, KERN_WARNING, fmt, ## args) -#define INFO(dev, fmt, args...) \ - xprintk(dev, KERN_INFO, fmt, ## args) - -/*-------------------------------------------------------------------------*/ - -/* USB DRIVER HOOKUP (to the hardware driver, below us), mostly - * ep0 implementation: descriptors, config management, setup(). - * also optional class-specific notification interrupt transfer. - */ - /* * DESCRIPTORS ... most are static, but strings and (full) configuration * descriptors are built on demand. @@ -227,24 +168,6 @@ static struct usb_device_descriptor device_desc = { .bNumConfigurations = 1 }; -static struct usb_otg_descriptor otg_desc = { - .bLength = sizeof otg_desc, - .bDescriptorType = USB_DT_OTG, - .bmAttributes = USB_OTG_SRP -}; - -static struct usb_config_descriptor config_desc = { - .bLength = sizeof config_desc, - .bDescriptorType = USB_DT_CONFIG, - - /* compute wTotalLength on the fly */ - .bNumInterfaces = 1, - .bConfigurationValue = DEV_CONFIG_VALUE, - .iConfiguration = 0, - .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, - .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2, -}; - static struct usb_interface_descriptor intf_desc = { .bLength = sizeof intf_desc, .bDescriptorType = USB_DT_INTERFACE, @@ -270,16 +193,13 @@ static struct usb_endpoint_descriptor fs_ep_out_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK }; -static const struct usb_descriptor_header *fs_printer_function [11] = { - (struct usb_descriptor_header *) &otg_desc, +static struct usb_descriptor_header *fs_printer_function[] = { (struct usb_descriptor_header *) &intf_desc, (struct usb_descriptor_header *) &fs_ep_in_desc, (struct usb_descriptor_header *) &fs_ep_out_desc, NULL }; -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* * usb 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. @@ -307,23 +227,26 @@ static struct usb_qualifier_descriptor dev_qualifier = { .bNumConfigurations = 1 }; -static const struct usb_descriptor_header *hs_printer_function [11] = { - (struct usb_descriptor_header *) &otg_desc, +static struct usb_descriptor_header *hs_printer_function[] = { (struct usb_descriptor_header *) &intf_desc, (struct usb_descriptor_header *) &hs_ep_in_desc, (struct usb_descriptor_header *) &hs_ep_out_desc, NULL }; -/* maxpacket and other transfer characteristics vary by speed. */ -#define ep_desc(g, hs, fs) (((g)->speed == USB_SPEED_HIGH)?(hs):(fs)) - -#else +static struct usb_otg_descriptor otg_descriptor = { + .bLength = sizeof otg_descriptor, + .bDescriptorType = USB_DT_OTG, + .bmAttributes = USB_OTG_SRP, +}; -/* if there's no high speed support, maxpacket doesn't change. */ -#define ep_desc(g, hs, fs) (((void)(g)), (fs)) +static const struct usb_descriptor_header *otg_desc[] = { + (struct usb_descriptor_header *) &otg_descriptor, + NULL, +}; -#endif /* !CONFIG_USB_GADGET_DUALSPEED */ +/* maxpacket and other transfer characteristics vary by speed. */ +#define ep_desc(g, hs, fs) (((g)->speed == USB_SPEED_HIGH)?(hs):(fs)) /*-------------------------------------------------------------------------*/ @@ -343,11 +266,16 @@ static struct usb_string strings [] = { { } /* end of list */ }; -static struct usb_gadget_strings stringtab = { +static struct usb_gadget_strings stringtab_dev = { .language = 0x0409, /* en-us */ .strings = strings, }; +static struct usb_gadget_strings *dev_strings[] = { + &stringtab_dev, + NULL, +}; + /*-------------------------------------------------------------------------*/ static struct usb_request * @@ -937,82 +865,8 @@ static void printer_reset_interface(struct printer_dev *dev) dev->interface = -1; } -/* change our operational config. must agree with the code - * that returns config descriptors, and altsetting code. - */ -static int -printer_set_config(struct printer_dev *dev, unsigned number) -{ - int result = 0; - struct usb_gadget *gadget = dev->gadget; - - switch (number) { - case DEV_CONFIG_VALUE: - result = 0; - break; - default: - result = -EINVAL; - /* FALL THROUGH */ - case 0: - break; - } - - if (result) { - usb_gadget_vbus_draw(dev->gadget, - dev->gadget->is_otg ? 8 : 100); - } else { - unsigned power; - - power = 2 * config_desc.bMaxPower; - usb_gadget_vbus_draw(dev->gadget, power); - - dev->config = number; - INFO(dev, "%s config #%d: %d mA, %s\n", - usb_speed_string(gadget->speed), - number, power, driver_desc); - } - return result; -} - -static int -config_buf(enum usb_device_speed speed, u8 *buf, u8 type, unsigned index, - int is_otg) -{ - int len; - const struct usb_descriptor_header **function; -#ifdef CONFIG_USB_GADGET_DUALSPEED - int hs = (speed == USB_SPEED_HIGH); - - if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; - - if (hs) { - function = hs_printer_function; - } else { - function = fs_printer_function; - } -#else - function = fs_printer_function; -#endif - - if (index >= device_desc.bNumConfigurations) - return -EINVAL; - - /* for now, don't advertise srp-only devices */ - if (!is_otg) - function++; - - len = usb_gadget_config_buf(&config_desc, buf, USB_DESC_BUFSIZE, - function); - if (len < 0) - return len; - ((struct usb_config_descriptor *) buf)->bDescriptorType = type; - return len; -} - /* Change our operational Interface. */ -static int -set_interface(struct printer_dev *dev, unsigned number) +static int set_interface(struct printer_dev *dev, unsigned number) { int result = 0; @@ -1043,14 +897,6 @@ set_interface(struct printer_dev *dev, unsigned number) return result; } -static void printer_setup_complete(struct usb_ep *ep, struct usb_request *req) -{ - if (req->status || req->actual != req->length) - DBG((struct printer_dev *) ep->driver_data, - "setup complete --> %d, %d/%d\n", - req->status, req->actual, req->length); -} - static void printer_soft_reset(struct printer_dev *dev) { struct usb_request *req; @@ -1107,11 +953,12 @@ static void printer_soft_reset(struct printer_dev *dev) * The setup() callback implements all the ep0 functionality that's not * handled lower down. */ -static int -printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) +static int printer_func_setup(struct usb_function *f, + const struct usb_ctrlrequest *ctrl) { - struct printer_dev *dev = get_gadget_data(gadget); - struct usb_request *req = dev->req; + struct printer_dev *dev = container_of(f, struct printer_dev, function); + struct usb_composite_dev *cdev = f->config->cdev; + struct usb_request *req = cdev->req; int value = -EOPNOTSUPP; u16 wIndex = le16_to_cpu(ctrl->wIndex); u16 wValue = le16_to_cpu(ctrl->wValue); @@ -1120,102 +967,7 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) DBG(dev, "ctrl req%02x.%02x v%04x i%04x l%d\n", ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength); - req->complete = printer_setup_complete; - switch (ctrl->bRequestType&USB_TYPE_MASK) { - - case USB_TYPE_STANDARD: - switch (ctrl->bRequest) { - - case USB_REQ_GET_DESCRIPTOR: - if (ctrl->bRequestType != USB_DIR_IN) - break; - switch (wValue >> 8) { - - case USB_DT_DEVICE: - device_desc.bMaxPacketSize0 = - gadget->ep0->maxpacket; - value = min(wLength, (u16) sizeof device_desc); - memcpy(req->buf, &device_desc, value); - break; -#ifdef CONFIG_USB_GADGET_DUALSPEED - case USB_DT_DEVICE_QUALIFIER: - if (!gadget_is_dualspeed(gadget)) - break; - /* - * assumes ep0 uses the same value for both - * speeds - */ - dev_qualifier.bMaxPacketSize0 = - gadget->ep0->maxpacket; - value = min(wLength, - (u16) sizeof dev_qualifier); - memcpy(req->buf, &dev_qualifier, value); - break; - - case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget_is_dualspeed(gadget)) - break; - /* FALLTHROUGH */ -#endif /* CONFIG_USB_GADGET_DUALSPEED */ - case USB_DT_CONFIG: - value = config_buf(gadget->speed, req->buf, - wValue >> 8, - wValue & 0xff, - gadget->is_otg); - if (value >= 0) - value = min(wLength, (u16) value); - break; - - case USB_DT_STRING: - value = usb_gadget_get_string(&stringtab, - wValue & 0xff, req->buf); - if (value >= 0) - value = min(wLength, (u16) value); - break; - } - break; - - case USB_REQ_SET_CONFIGURATION: - if (ctrl->bRequestType != 0) - break; - if (gadget->a_hnp_support) - DBG(dev, "HNP available\n"); - else if (gadget->a_alt_hnp_support) - DBG(dev, "HNP needs a different root port\n"); - value = printer_set_config(dev, wValue); - if (!value) - value = set_interface(dev, PRINTER_INTERFACE); - break; - case USB_REQ_GET_CONFIGURATION: - if (ctrl->bRequestType != USB_DIR_IN) - break; - *(u8 *)req->buf = dev->config; - value = min(wLength, (u16) 1); - break; - - case USB_REQ_SET_INTERFACE: - if (ctrl->bRequestType != USB_RECIP_INTERFACE || - !dev->config) - break; - - value = set_interface(dev, PRINTER_INTERFACE); - break; - case USB_REQ_GET_INTERFACE: - if (ctrl->bRequestType != - (USB_DIR_IN|USB_RECIP_INTERFACE) - || !dev->config) - break; - - *(u8 *)req->buf = dev->interface; - value = min(wLength, (u16) 1); - break; - - default: - goto unknown; - } - break; - case USB_TYPE_CLASS: switch (ctrl->bRequest) { case 0: /* Get the IEEE-1284 PNP String */ @@ -1261,44 +1013,50 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) wValue, wIndex, wLength); break; } - - /* respond with data transfer before status phase? */ - if (value >= 0) { - req->length = value; - req->zero = value < wLength; - value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); - if (value < 0) { - DBG(dev, "ep_queue --> %d\n", value); - req->status = 0; - printer_setup_complete(gadget->ep0, req); - } - } - /* host either stalls (value < 0) or reports success */ return value; } -static void -printer_disconnect(struct usb_gadget *gadget) +static int __init printer_func_bind(struct usb_configuration *c, + struct usb_function *f) { - struct printer_dev *dev = get_gadget_data(gadget); + return 0; +} + +static void printer_func_unbind(struct usb_configuration *c, + struct usb_function *f) +{ +} + +static int printer_func_set_alt(struct usb_function *f, + unsigned intf, unsigned alt) +{ + struct printer_dev *dev = container_of(f, struct printer_dev, function); + int ret = -ENOTSUPP; + + if (!alt) + ret = set_interface(dev, PRINTER_INTERFACE); + return ret; +} + +static void printer_func_disable(struct usb_function *f) +{ + struct printer_dev *dev = container_of(f, struct printer_dev, function); unsigned long flags; DBG(dev, "%s\n", __func__); spin_lock_irqsave(&dev->lock, flags); - printer_reset_interface(dev); - spin_unlock_irqrestore(&dev->lock, flags); } -static void -printer_unbind(struct usb_gadget *gadget) +static void printer_cfg_unbind(struct usb_configuration *c) { - struct printer_dev *dev = get_gadget_data(gadget); + struct printer_dev *dev; struct usb_request *req; + dev = &usb_printer_gadget; DBG(dev, "%s\n", __func__); @@ -1336,18 +1094,18 @@ printer_unbind(struct usb_gadget *gadget) list_del(&req->list); printer_req_free(dev->out_ep, req); } - - if (dev->req) { - printer_req_free(gadget->ep0, dev->req); - dev->req = NULL; - } - - set_gadget_data(gadget, NULL); } -static int __init -printer_bind(struct usb_gadget *gadget) +static struct usb_configuration printer_cfg_driver = { + .label = "printer", + .unbind = printer_cfg_unbind, + .bConfigurationValue = 1, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, +}; + +static int __init printer_bind_config(struct usb_configuration *c) { + struct usb_gadget *gadget = c->cdev->gadget; struct printer_dev *dev; struct usb_ep *in_ep, *out_ep; int status = -ENOMEM; @@ -1358,6 +1116,14 @@ printer_bind(struct usb_gadget *gadget) dev = &usb_printer_gadget; + dev->function.name = shortname; + dev->function.descriptors = fs_printer_function; + dev->function.hs_descriptors = hs_printer_function; + dev->function.bind = printer_func_bind; + dev->function.setup = printer_func_setup; + dev->function.unbind = printer_func_unbind; + dev->function.set_alt = printer_func_set_alt; + dev->function.disable = printer_func_disable; /* Setup the sysfs files for the printer gadget. */ dev->pdev = device_create(usb_gadget_class, NULL, g_printer_devno, @@ -1393,29 +1159,6 @@ printer_bind(struct usb_gadget *gadget) init_utsname()->sysname, init_utsname()->release, gadget->name); - device_desc.idVendor = - cpu_to_le16(PRINTER_VENDOR_NUM); - device_desc.idProduct = - cpu_to_le16(PRINTER_PRODUCT_NUM); - - /* support optional vendor/distro customization */ - if (idVendor) { - if (!idProduct) { - dev_err(&gadget->dev, "idVendor needs idProduct!\n"); - return -ENODEV; - } - device_desc.idVendor = cpu_to_le16(idVendor); - device_desc.idProduct = cpu_to_le16(idProduct); - if (bcdDevice) - device_desc.bcdDevice = cpu_to_le16(bcdDevice); - } - - if (iManufacturer) - strlcpy(manufacturer, iManufacturer, sizeof manufacturer); - - if (iProduct) - strlcpy(product_desc, iProduct, sizeof product_desc); - if (iSerialNum) strlcpy(serial_num, iSerialNum, sizeof serial_num); @@ -1442,17 +1185,16 @@ printer_bind(struct usb_gadget *gadget) goto autoconf_fail; out_ep->driver_data = out_ep; /* claim */ -#ifdef CONFIG_USB_GADGET_DUALSPEED /* assumes that all endpoints are dual-speed */ hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress; hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress; -#endif /* DUALSPEED */ usb_gadget_set_selfpowered(gadget); if (gadget->is_otg) { - otg_desc.bmAttributes |= USB_OTG_HNP, - config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + otg_descriptor.bmAttributes |= USB_OTG_HNP; + printer_cfg_driver.descriptors = otg_desc; + printer_cfg_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; } spin_lock_init(&dev->lock); @@ -1466,7 +1208,6 @@ printer_bind(struct usb_gadget *gadget) init_waitqueue_head(&dev->tx_wait); init_waitqueue_head(&dev->tx_flush_wait); - dev->config = 0; dev->interface = -1; dev->printer_cdev_open = 0; dev->printer_status = PRINTER_NOT_ERROR; @@ -1477,14 +1218,6 @@ printer_bind(struct usb_gadget *gadget) dev->in_ep = in_ep; dev->out_ep = out_ep; - /* preallocate control message data and buffer */ - dev->req = printer_req_alloc(gadget->ep0, USB_DESC_BUFSIZE, - GFP_KERNEL); - if (!dev->req) { - status = -ENOMEM; - goto fail; - } - for (i = 0; i < QLEN; i++) { req = printer_req_alloc(dev->in_ep, USB_BUFSIZE, GFP_KERNEL); if (!req) { @@ -1513,45 +1246,37 @@ printer_bind(struct usb_gadget *gadget) list_add(&req->list, &dev->rx_reqs); } - dev->req->complete = printer_setup_complete; - /* finish hookup to lower layer ... */ dev->gadget = gadget; - set_gadget_data(gadget, dev); - gadget->ep0->driver_data = dev; INFO(dev, "%s, version: " DRIVER_VERSION "\n", driver_desc); INFO(dev, "using %s, OUT %s IN %s\n", gadget->name, out_ep->name, in_ep->name); - return 0; fail: - printer_unbind(gadget); + printer_cfg_unbind(c); return status; } -/*-------------------------------------------------------------------------*/ +static int printer_unbind(struct usb_composite_dev *cdev) +{ + return 0; +} -static struct usb_gadget_driver printer_driver = { - .max_speed = DEVSPEED, +static int __init printer_bind(struct usb_composite_dev *cdev) +{ + return usb_add_config(cdev, &printer_cfg_driver, printer_bind_config); +} - .function = (char *) driver_desc, +static struct usb_composite_driver printer_driver = { + .name = shortname, + .dev = &device_desc, + .strings = dev_strings, + .max_speed = USB_SPEED_HIGH, .unbind = printer_unbind, - - .setup = printer_setup, - .disconnect = printer_disconnect, - - .driver = { - .name = (char *) shortname, - .owner = THIS_MODULE, - }, }; -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("Craig Nadler"); -MODULE_LICENSE("GPL"); - static int __init init(void) { @@ -1560,23 +1285,23 @@ init(void) usb_gadget_class = class_create(THIS_MODULE, "usb_printer_gadget"); if (IS_ERR(usb_gadget_class)) { status = PTR_ERR(usb_gadget_class); - ERROR(dev, "unable to create usb_gadget class %d\n", status); + pr_err("unable to create usb_gadget class %d\n", status); return status; } status = alloc_chrdev_region(&g_printer_devno, 0, 1, "USB printer gadget"); if (status) { - ERROR(dev, "alloc_chrdev_region %d\n", status); + pr_err("alloc_chrdev_region %d\n", status); class_destroy(usb_gadget_class); return status; } - status = usb_gadget_probe_driver(&printer_driver, printer_bind); + status = usb_composite_probe(&printer_driver, printer_bind); if (status) { class_destroy(usb_gadget_class); unregister_chrdev_region(g_printer_devno, 1); - DBG(dev, "usb_gadget_probe_driver %x\n", status); + pr_err("usb_gadget_probe_driver %x\n", status); } return status; @@ -1586,15 +1311,14 @@ module_init(init); static void __exit cleanup(void) { - int status; - mutex_lock(&usb_printer_gadget.lock_printer_io); - status = usb_gadget_unregister_driver(&printer_driver); - if (status) - ERROR(dev, "usb_gadget_unregister_driver %x\n", status); - + usb_composite_unregister(&printer_driver); unregister_chrdev_region(g_printer_devno, 1); class_destroy(usb_gadget_class); mutex_unlock(&usb_printer_gadget.lock_printer_io); } module_exit(cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Craig Nadler"); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/usb/gadget/pxa25x_udc.c b/trunk/drivers/usb/gadget/pxa25x_udc.c index 41ed69c96d8c..d7c8cb3bf759 100644 --- a/trunk/drivers/usb/gadget/pxa25x_udc.c +++ b/trunk/drivers/usb/gadget/pxa25x_udc.c @@ -218,7 +218,7 @@ static int pxa25x_ep_enable (struct usb_ep *_ep, struct pxa25x_udc *dev; ep = container_of (_ep, struct pxa25x_ep, ep); - if (!_ep || !desc || ep->desc || _ep->name == ep0name + if (!_ep || !desc || ep->ep.desc || _ep->name == ep0name || desc->bDescriptorType != USB_DT_ENDPOINT || ep->bEndpointAddress != desc->bEndpointAddress || ep->fifo_size < usb_endpoint_maxp (desc)) { @@ -249,7 +249,7 @@ static int pxa25x_ep_enable (struct usb_ep *_ep, return -ESHUTDOWN; } - ep->desc = desc; + ep->ep.desc = desc; ep->stopped = 0; ep->pio_irqs = 0; ep->ep.maxpacket = usb_endpoint_maxp (desc); @@ -269,7 +269,7 @@ static int pxa25x_ep_disable (struct usb_ep *_ep) unsigned long flags; ep = container_of (_ep, struct pxa25x_ep, ep); - if (!_ep || !ep->desc) { + if (!_ep || !ep->ep.desc) { DMSG("%s, %s not enabled\n", __func__, _ep ? ep->ep.name : NULL); return -EINVAL; @@ -281,7 +281,6 @@ static int pxa25x_ep_disable (struct usb_ep *_ep) /* flush fifo (mostly for IN buffers) */ pxa25x_ep_fifo_flush (_ep); - ep->desc = NULL; ep->ep.desc = NULL; ep->stopped = 1; @@ -390,7 +389,7 @@ write_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req) { unsigned max; - max = usb_endpoint_maxp(ep->desc); + max = usb_endpoint_maxp(ep->ep.desc); do { unsigned count; int is_last, is_short; @@ -644,7 +643,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) } ep = container_of(_ep, struct pxa25x_ep, ep); - if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) { + if (unlikely(!_ep || (!ep->ep.desc && ep->ep.name != ep0name))) { DMSG("%s, bad ep\n", __func__); return -EINVAL; } @@ -660,7 +659,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) * we can report per-packet status. that also helps with dma. */ if (unlikely (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC - && req->req.length > usb_endpoint_maxp (ep->desc))) + && req->req.length > usb_endpoint_maxp(ep->ep.desc))) return -EMSGSIZE; DBG(DBG_NOISY, "%s queue req %p, len %d buf %p\n", @@ -673,7 +672,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) /* kickstart this i/o queue? */ if (list_empty(&ep->queue) && !ep->stopped) { - if (ep->desc == NULL/* ep0 */) { + if (ep->ep.desc == NULL/* ep0 */) { unsigned length = _req->length; switch (dev->ep0state) { @@ -722,7 +721,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) req = NULL; } - if (likely (req && ep->desc)) + if (likely(req && ep->ep.desc)) pio_irq_enable(ep->bEndpointAddress); } @@ -749,7 +748,7 @@ static void nuke(struct pxa25x_ep *ep, int status) queue); done(ep, req, status); } - if (ep->desc) + if (ep->ep.desc) pio_irq_disable (ep->bEndpointAddress); } @@ -792,7 +791,7 @@ static int pxa25x_ep_set_halt(struct usb_ep *_ep, int value) ep = container_of(_ep, struct pxa25x_ep, ep); if (unlikely (!_ep - || (!ep->desc && ep->ep.name != ep0name)) + || (!ep->ep.desc && ep->ep.name != ep0name)) || ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) { DMSG("%s, bad ep\n", __func__); return -EINVAL; @@ -820,7 +819,7 @@ static int pxa25x_ep_set_halt(struct usb_ep *_ep, int value) *ep->reg_udccs = UDCCS_BI_FST|UDCCS_BI_FTF; /* ep0 needs special care */ - if (!ep->desc) { + if (!ep->ep.desc) { start_watchdog(ep->dev); ep->dev->req_pending = 0; ep->dev->ep0state = EP0_STALL; @@ -1087,7 +1086,7 @@ udc_seq_show(struct seq_file *m, void *_d) if (i != 0) { const struct usb_endpoint_descriptor *desc; - desc = ep->desc; + desc = ep->ep.desc; if (!desc) continue; tmp = *dev->ep [i].reg_udccs; @@ -1191,7 +1190,6 @@ static void udc_reinit(struct pxa25x_udc *dev) if (i != 0) list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list); - ep->desc = NULL; ep->ep.desc = NULL; ep->stopped = 0; INIT_LIST_HEAD (&ep->queue); diff --git a/trunk/drivers/usb/gadget/pxa25x_udc.h b/trunk/drivers/usb/gadget/pxa25x_udc.h index 893e917f048e..861f4df6ea22 100644 --- a/trunk/drivers/usb/gadget/pxa25x_udc.h +++ b/trunk/drivers/usb/gadget/pxa25x_udc.h @@ -41,7 +41,6 @@ struct pxa25x_ep { struct usb_ep ep; struct pxa25x_udc *dev; - const struct usb_endpoint_descriptor *desc; struct list_head queue; unsigned long pio_irqs; diff --git a/trunk/drivers/usb/gadget/r8a66597-udc.c b/trunk/drivers/usb/gadget/r8a66597-udc.c index c4401e7dd3a6..f3ac2a20c27c 100644 --- a/trunk/drivers/usb/gadget/r8a66597-udc.c +++ b/trunk/drivers/usb/gadget/r8a66597-udc.c @@ -459,7 +459,7 @@ static int alloc_pipe_config(struct r8a66597_ep *ep, unsigned char *counter; int ret; - ep->desc = desc; + ep->ep.desc = desc; if (ep->pipenum) /* already allocated pipe */ return 0; @@ -648,7 +648,7 @@ static int sudmac_alloc_channel(struct r8a66597 *r8a66597, /* set SUDMAC parameters */ dma = &r8a66597->dma; dma->used = 1; - if (ep->desc->bEndpointAddress & USB_DIR_IN) { + if (ep->ep.desc->bEndpointAddress & USB_DIR_IN) { dma->dir = 1; } else { dma->dir = 0; @@ -770,7 +770,7 @@ static void start_packet_read(struct r8a66597_ep *ep, static void start_packet(struct r8a66597_ep *ep, struct r8a66597_request *req) { - if (ep->desc->bEndpointAddress & USB_DIR_IN) + if (ep->ep.desc->bEndpointAddress & USB_DIR_IN) start_packet_write(ep, req); else start_packet_read(ep, req); @@ -930,7 +930,7 @@ __acquires(r8a66597->lock) if (restart) { req = get_request_from_ep(ep); - if (ep->desc) + if (ep->ep.desc) start_packet(ep, req); } } @@ -1116,7 +1116,7 @@ static void irq_pipe_ready(struct r8a66597 *r8a66597, u16 status, u16 enb) r8a66597_write(r8a66597, ~check, BRDYSTS); ep = r8a66597->pipenum2ep[pipenum]; req = get_request_from_ep(ep); - if (ep->desc->bEndpointAddress & USB_DIR_IN) + if (ep->ep.desc->bEndpointAddress & USB_DIR_IN) irq_packet_write(ep, req); else irq_packet_read(ep, req); @@ -1170,7 +1170,7 @@ __acquires(r8a66597->lock) switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_DEVICE: - status = 1 << USB_DEVICE_SELF_POWERED; + status = r8a66597->device_status; break; case USB_RECIP_INTERFACE: status = 0; @@ -1627,7 +1627,7 @@ static int r8a66597_queue(struct usb_ep *_ep, struct usb_request *_req, req->req.actual = 0; req->req.status = -EINPROGRESS; - if (ep->desc == NULL) /* control */ + if (ep->ep.desc == NULL) /* control */ start_ep0(ep, req); else { if (request && !ep->busy) @@ -1692,7 +1692,7 @@ static int r8a66597_set_wedge(struct usb_ep *_ep) ep = container_of(_ep, struct r8a66597_ep, ep); - if (!ep || !ep->desc) + if (!ep || !ep->ep.desc) return -EINVAL; spin_lock_irqsave(&ep->r8a66597->lock, flags); @@ -1800,11 +1800,24 @@ static int r8a66597_pullup(struct usb_gadget *gadget, int is_on) return 0; } +static int r8a66597_set_selfpowered(struct usb_gadget *gadget, int is_self) +{ + struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget); + + if (is_self) + r8a66597->device_status |= 1 << USB_DEVICE_SELF_POWERED; + else + r8a66597->device_status &= ~(1 << USB_DEVICE_SELF_POWERED); + + return 0; +} + static struct usb_gadget_ops r8a66597_gadget_ops = { .get_frame = r8a66597_get_frame, .udc_start = r8a66597_start, .udc_stop = r8a66597_stop, .pullup = r8a66597_pullup, + .set_selfpowered = r8a66597_set_selfpowered, }; static int __exit r8a66597_remove(struct platform_device *pdev) diff --git a/trunk/drivers/usb/gadget/r8a66597-udc.h b/trunk/drivers/usb/gadget/r8a66597-udc.h index 8e3de61cd4b8..99908c76ccd1 100644 --- a/trunk/drivers/usb/gadget/r8a66597-udc.h +++ b/trunk/drivers/usb/gadget/r8a66597-udc.h @@ -72,7 +72,7 @@ struct r8a66597_ep { unsigned use_dma:1; u16 pipenum; u16 type; - const struct usb_endpoint_descriptor *desc; + /* register address */ unsigned char fifoaddr; unsigned char fifosel; @@ -111,6 +111,7 @@ struct r8a66597 { u16 old_vbus; u16 scount; u16 old_dvsq; + u16 device_status; /* for GET_STATUS */ /* pipe config */ unsigned char bulk; diff --git a/trunk/drivers/usb/gadget/rndis.c b/trunk/drivers/usb/gadget/rndis.c index 73a934a170d1..b35babed6fcb 100644 --- a/trunk/drivers/usb/gadget/rndis.c +++ b/trunk/drivers/usb/gadget/rndis.c @@ -73,65 +73,65 @@ static rndis_resp_t *rndis_add_response(int configNr, u32 length); static const u32 oid_supported_list[] = { /* the general stuff */ - OID_GEN_SUPPORTED_LIST, - OID_GEN_HARDWARE_STATUS, - OID_GEN_MEDIA_SUPPORTED, - OID_GEN_MEDIA_IN_USE, - OID_GEN_MAXIMUM_FRAME_SIZE, - OID_GEN_LINK_SPEED, - OID_GEN_TRANSMIT_BLOCK_SIZE, - OID_GEN_RECEIVE_BLOCK_SIZE, - OID_GEN_VENDOR_ID, - OID_GEN_VENDOR_DESCRIPTION, - OID_GEN_VENDOR_DRIVER_VERSION, - OID_GEN_CURRENT_PACKET_FILTER, - OID_GEN_MAXIMUM_TOTAL_SIZE, - OID_GEN_MEDIA_CONNECT_STATUS, - OID_GEN_PHYSICAL_MEDIUM, + RNDIS_OID_GEN_SUPPORTED_LIST, + RNDIS_OID_GEN_HARDWARE_STATUS, + RNDIS_OID_GEN_MEDIA_SUPPORTED, + RNDIS_OID_GEN_MEDIA_IN_USE, + RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE, + RNDIS_OID_GEN_LINK_SPEED, + RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE, + RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE, + RNDIS_OID_GEN_VENDOR_ID, + RNDIS_OID_GEN_VENDOR_DESCRIPTION, + RNDIS_OID_GEN_VENDOR_DRIVER_VERSION, + RNDIS_OID_GEN_CURRENT_PACKET_FILTER, + RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE, + RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, + RNDIS_OID_GEN_PHYSICAL_MEDIUM, /* the statistical stuff */ - OID_GEN_XMIT_OK, - OID_GEN_RCV_OK, - OID_GEN_XMIT_ERROR, - OID_GEN_RCV_ERROR, - OID_GEN_RCV_NO_BUFFER, + RNDIS_OID_GEN_XMIT_OK, + RNDIS_OID_GEN_RCV_OK, + RNDIS_OID_GEN_XMIT_ERROR, + RNDIS_OID_GEN_RCV_ERROR, + RNDIS_OID_GEN_RCV_NO_BUFFER, #ifdef RNDIS_OPTIONAL_STATS - OID_GEN_DIRECTED_BYTES_XMIT, - OID_GEN_DIRECTED_FRAMES_XMIT, - OID_GEN_MULTICAST_BYTES_XMIT, - OID_GEN_MULTICAST_FRAMES_XMIT, - OID_GEN_BROADCAST_BYTES_XMIT, - OID_GEN_BROADCAST_FRAMES_XMIT, - OID_GEN_DIRECTED_BYTES_RCV, - OID_GEN_DIRECTED_FRAMES_RCV, - OID_GEN_MULTICAST_BYTES_RCV, - OID_GEN_MULTICAST_FRAMES_RCV, - OID_GEN_BROADCAST_BYTES_RCV, - OID_GEN_BROADCAST_FRAMES_RCV, - OID_GEN_RCV_CRC_ERROR, - OID_GEN_TRANSMIT_QUEUE_LENGTH, + RNDIS_OID_GEN_DIRECTED_BYTES_XMIT, + RNDIS_OID_GEN_DIRECTED_FRAMES_XMIT, + RNDIS_OID_GEN_MULTICAST_BYTES_XMIT, + RNDIS_OID_GEN_MULTICAST_FRAMES_XMIT, + RNDIS_OID_GEN_BROADCAST_BYTES_XMIT, + RNDIS_OID_GEN_BROADCAST_FRAMES_XMIT, + RNDIS_OID_GEN_DIRECTED_BYTES_RCV, + RNDIS_OID_GEN_DIRECTED_FRAMES_RCV, + RNDIS_OID_GEN_MULTICAST_BYTES_RCV, + RNDIS_OID_GEN_MULTICAST_FRAMES_RCV, + RNDIS_OID_GEN_BROADCAST_BYTES_RCV, + RNDIS_OID_GEN_BROADCAST_FRAMES_RCV, + RNDIS_OID_GEN_RCV_CRC_ERROR, + RNDIS_OID_GEN_TRANSMIT_QUEUE_LENGTH, #endif /* RNDIS_OPTIONAL_STATS */ /* mandatory 802.3 */ /* the general stuff */ - OID_802_3_PERMANENT_ADDRESS, - OID_802_3_CURRENT_ADDRESS, - OID_802_3_MULTICAST_LIST, - OID_802_3_MAC_OPTIONS, - OID_802_3_MAXIMUM_LIST_SIZE, + RNDIS_OID_802_3_PERMANENT_ADDRESS, + RNDIS_OID_802_3_CURRENT_ADDRESS, + RNDIS_OID_802_3_MULTICAST_LIST, + RNDIS_OID_802_3_MAC_OPTIONS, + RNDIS_OID_802_3_MAXIMUM_LIST_SIZE, /* the statistical stuff */ - OID_802_3_RCV_ERROR_ALIGNMENT, - OID_802_3_XMIT_ONE_COLLISION, - OID_802_3_XMIT_MORE_COLLISIONS, + RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT, + RNDIS_OID_802_3_XMIT_ONE_COLLISION, + RNDIS_OID_802_3_XMIT_MORE_COLLISIONS, #ifdef RNDIS_OPTIONAL_STATS - OID_802_3_XMIT_DEFERRED, - OID_802_3_XMIT_MAX_COLLISIONS, - OID_802_3_RCV_OVERRUN, - OID_802_3_XMIT_UNDERRUN, - OID_802_3_XMIT_HEARTBEAT_FAILURE, - OID_802_3_XMIT_TIMES_CRS_LOST, - OID_802_3_XMIT_LATE_COLLISIONS, + RNDIS_OID_802_3_XMIT_DEFERRED, + RNDIS_OID_802_3_XMIT_MAX_COLLISIONS, + RNDIS_OID_802_3_RCV_OVERRUN, + RNDIS_OID_802_3_XMIT_UNDERRUN, + RNDIS_OID_802_3_XMIT_HEARTBEAT_FAILURE, + RNDIS_OID_802_3_XMIT_TIMES_CRS_LOST, + RNDIS_OID_802_3_XMIT_LATE_COLLISIONS, #endif /* RNDIS_OPTIONAL_STATS */ #ifdef RNDIS_PM @@ -200,8 +200,8 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, /* general oids (table 4-1) */ /* mandatory */ - case OID_GEN_SUPPORTED_LIST: - pr_debug("%s: OID_GEN_SUPPORTED_LIST\n", __func__); + case RNDIS_OID_GEN_SUPPORTED_LIST: + pr_debug("%s: RNDIS_OID_GEN_SUPPORTED_LIST\n", __func__); length = sizeof(oid_supported_list); count = length / sizeof(u32); for (i = 0; i < count; i++) @@ -210,8 +210,8 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, break; /* mandatory */ - case OID_GEN_HARDWARE_STATUS: - pr_debug("%s: OID_GEN_HARDWARE_STATUS\n", __func__); + case RNDIS_OID_GEN_HARDWARE_STATUS: + pr_debug("%s: RNDIS_OID_GEN_HARDWARE_STATUS\n", __func__); /* Bogus question! * Hardware must be ready to receive high level protocols. * BTW: @@ -223,23 +223,23 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, break; /* mandatory */ - case OID_GEN_MEDIA_SUPPORTED: - pr_debug("%s: OID_GEN_MEDIA_SUPPORTED\n", __func__); + case RNDIS_OID_GEN_MEDIA_SUPPORTED: + pr_debug("%s: RNDIS_OID_GEN_MEDIA_SUPPORTED\n", __func__); *outbuf = cpu_to_le32(rndis_per_dev_params[configNr].medium); retval = 0; break; /* mandatory */ - case OID_GEN_MEDIA_IN_USE: - pr_debug("%s: OID_GEN_MEDIA_IN_USE\n", __func__); + case RNDIS_OID_GEN_MEDIA_IN_USE: + pr_debug("%s: RNDIS_OID_GEN_MEDIA_IN_USE\n", __func__); /* one medium, one transport... (maybe you do it better) */ *outbuf = cpu_to_le32(rndis_per_dev_params[configNr].medium); retval = 0; break; /* mandatory */ - case OID_GEN_MAXIMUM_FRAME_SIZE: - pr_debug("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __func__); + case RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE: + pr_debug("%s: RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE\n", __func__); if (rndis_per_dev_params[configNr].dev) { *outbuf = cpu_to_le32( rndis_per_dev_params[configNr].dev->mtu); @@ -248,11 +248,11 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, break; /* mandatory */ - case OID_GEN_LINK_SPEED: + case RNDIS_OID_GEN_LINK_SPEED: if (rndis_debug > 1) - pr_debug("%s: OID_GEN_LINK_SPEED\n", __func__); + pr_debug("%s: RNDIS_OID_GEN_LINK_SPEED\n", __func__); if (rndis_per_dev_params[configNr].media_state - == NDIS_MEDIA_STATE_DISCONNECTED) + == RNDIS_MEDIA_STATE_DISCONNECTED) *outbuf = cpu_to_le32(0); else *outbuf = cpu_to_le32( @@ -261,8 +261,8 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, break; /* mandatory */ - case OID_GEN_TRANSMIT_BLOCK_SIZE: - pr_debug("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __func__); + case RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE: + pr_debug("%s: RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE\n", __func__); if (rndis_per_dev_params[configNr].dev) { *outbuf = cpu_to_le32( rndis_per_dev_params[configNr].dev->mtu); @@ -271,8 +271,8 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, break; /* mandatory */ - case OID_GEN_RECEIVE_BLOCK_SIZE: - pr_debug("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __func__); + case RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE: + pr_debug("%s: RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE\n", __func__); if (rndis_per_dev_params[configNr].dev) { *outbuf = cpu_to_le32( rndis_per_dev_params[configNr].dev->mtu); @@ -281,16 +281,16 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, break; /* mandatory */ - case OID_GEN_VENDOR_ID: - pr_debug("%s: OID_GEN_VENDOR_ID\n", __func__); + case RNDIS_OID_GEN_VENDOR_ID: + pr_debug("%s: RNDIS_OID_GEN_VENDOR_ID\n", __func__); *outbuf = cpu_to_le32( rndis_per_dev_params[configNr].vendorID); retval = 0; break; /* mandatory */ - case OID_GEN_VENDOR_DESCRIPTION: - pr_debug("%s: OID_GEN_VENDOR_DESCRIPTION\n", __func__); + case RNDIS_OID_GEN_VENDOR_DESCRIPTION: + pr_debug("%s: RNDIS_OID_GEN_VENDOR_DESCRIPTION\n", __func__); if (rndis_per_dev_params[configNr].vendorDescr) { length = strlen(rndis_per_dev_params[configNr]. vendorDescr); @@ -303,38 +303,38 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, retval = 0; break; - case OID_GEN_VENDOR_DRIVER_VERSION: - pr_debug("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __func__); + case RNDIS_OID_GEN_VENDOR_DRIVER_VERSION: + pr_debug("%s: RNDIS_OID_GEN_VENDOR_DRIVER_VERSION\n", __func__); /* Created as LE */ *outbuf = rndis_driver_version; retval = 0; break; /* mandatory */ - case OID_GEN_CURRENT_PACKET_FILTER: - pr_debug("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __func__); + case RNDIS_OID_GEN_CURRENT_PACKET_FILTER: + pr_debug("%s: RNDIS_OID_GEN_CURRENT_PACKET_FILTER\n", __func__); *outbuf = cpu_to_le32(*rndis_per_dev_params[configNr].filter); retval = 0; break; /* mandatory */ - case OID_GEN_MAXIMUM_TOTAL_SIZE: - pr_debug("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __func__); + case RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE: + pr_debug("%s: RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE\n", __func__); *outbuf = cpu_to_le32(RNDIS_MAX_TOTAL_SIZE); retval = 0; break; /* mandatory */ - case OID_GEN_MEDIA_CONNECT_STATUS: + case RNDIS_OID_GEN_MEDIA_CONNECT_STATUS: if (rndis_debug > 1) - pr_debug("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __func__); + pr_debug("%s: RNDIS_OID_GEN_MEDIA_CONNECT_STATUS\n", __func__); *outbuf = cpu_to_le32(rndis_per_dev_params[configNr] .media_state); retval = 0; break; - case OID_GEN_PHYSICAL_MEDIUM: - pr_debug("%s: OID_GEN_PHYSICAL_MEDIUM\n", __func__); + case RNDIS_OID_GEN_PHYSICAL_MEDIUM: + pr_debug("%s: RNDIS_OID_GEN_PHYSICAL_MEDIUM\n", __func__); *outbuf = cpu_to_le32(0); retval = 0; break; @@ -343,20 +343,20 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, * of MS-Windows expect OIDs that aren't specified there. Other * versions emit undefined RNDIS messages. DOCUMENT ALL THESE! */ - case OID_GEN_MAC_OPTIONS: /* from WinME */ - pr_debug("%s: OID_GEN_MAC_OPTIONS\n", __func__); + case RNDIS_OID_GEN_MAC_OPTIONS: /* from WinME */ + pr_debug("%s: RNDIS_OID_GEN_MAC_OPTIONS\n", __func__); *outbuf = cpu_to_le32( - NDIS_MAC_OPTION_RECEIVE_SERIALIZED - | NDIS_MAC_OPTION_FULL_DUPLEX); + RNDIS_MAC_OPTION_RECEIVE_SERIALIZED + | RNDIS_MAC_OPTION_FULL_DUPLEX); retval = 0; break; /* statistics OIDs (table 4-2) */ /* mandatory */ - case OID_GEN_XMIT_OK: + case RNDIS_OID_GEN_XMIT_OK: if (rndis_debug > 1) - pr_debug("%s: OID_GEN_XMIT_OK\n", __func__); + pr_debug("%s: RNDIS_OID_GEN_XMIT_OK\n", __func__); if (stats) { *outbuf = cpu_to_le32(stats->tx_packets - stats->tx_errors - stats->tx_dropped); @@ -365,9 +365,9 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, break; /* mandatory */ - case OID_GEN_RCV_OK: + case RNDIS_OID_GEN_RCV_OK: if (rndis_debug > 1) - pr_debug("%s: OID_GEN_RCV_OK\n", __func__); + pr_debug("%s: RNDIS_OID_GEN_RCV_OK\n", __func__); if (stats) { *outbuf = cpu_to_le32(stats->rx_packets - stats->rx_errors - stats->rx_dropped); @@ -376,9 +376,9 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, break; /* mandatory */ - case OID_GEN_XMIT_ERROR: + case RNDIS_OID_GEN_XMIT_ERROR: if (rndis_debug > 1) - pr_debug("%s: OID_GEN_XMIT_ERROR\n", __func__); + pr_debug("%s: RNDIS_OID_GEN_XMIT_ERROR\n", __func__); if (stats) { *outbuf = cpu_to_le32(stats->tx_errors); retval = 0; @@ -386,9 +386,9 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, break; /* mandatory */ - case OID_GEN_RCV_ERROR: + case RNDIS_OID_GEN_RCV_ERROR: if (rndis_debug > 1) - pr_debug("%s: OID_GEN_RCV_ERROR\n", __func__); + pr_debug("%s: RNDIS_OID_GEN_RCV_ERROR\n", __func__); if (stats) { *outbuf = cpu_to_le32(stats->rx_errors); retval = 0; @@ -396,8 +396,8 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, break; /* mandatory */ - case OID_GEN_RCV_NO_BUFFER: - pr_debug("%s: OID_GEN_RCV_NO_BUFFER\n", __func__); + case RNDIS_OID_GEN_RCV_NO_BUFFER: + pr_debug("%s: RNDIS_OID_GEN_RCV_NO_BUFFER\n", __func__); if (stats) { *outbuf = cpu_to_le32(stats->rx_dropped); retval = 0; @@ -407,8 +407,8 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, /* ieee802.3 OIDs (table 4-3) */ /* mandatory */ - case OID_802_3_PERMANENT_ADDRESS: - pr_debug("%s: OID_802_3_PERMANENT_ADDRESS\n", __func__); + case RNDIS_OID_802_3_PERMANENT_ADDRESS: + pr_debug("%s: RNDIS_OID_802_3_PERMANENT_ADDRESS\n", __func__); if (rndis_per_dev_params[configNr].dev) { length = ETH_ALEN; memcpy(outbuf, @@ -419,8 +419,8 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, break; /* mandatory */ - case OID_802_3_CURRENT_ADDRESS: - pr_debug("%s: OID_802_3_CURRENT_ADDRESS\n", __func__); + case RNDIS_OID_802_3_CURRENT_ADDRESS: + pr_debug("%s: RNDIS_OID_802_3_CURRENT_ADDRESS\n", __func__); if (rndis_per_dev_params[configNr].dev) { length = ETH_ALEN; memcpy(outbuf, @@ -431,23 +431,23 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, break; /* mandatory */ - case OID_802_3_MULTICAST_LIST: - pr_debug("%s: OID_802_3_MULTICAST_LIST\n", __func__); + case RNDIS_OID_802_3_MULTICAST_LIST: + pr_debug("%s: RNDIS_OID_802_3_MULTICAST_LIST\n", __func__); /* Multicast base address only */ *outbuf = cpu_to_le32(0xE0000000); retval = 0; break; /* mandatory */ - case OID_802_3_MAXIMUM_LIST_SIZE: - pr_debug("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __func__); + case RNDIS_OID_802_3_MAXIMUM_LIST_SIZE: + pr_debug("%s: RNDIS_OID_802_3_MAXIMUM_LIST_SIZE\n", __func__); /* Multicast base address only */ *outbuf = cpu_to_le32(1); retval = 0; break; - case OID_802_3_MAC_OPTIONS: - pr_debug("%s: OID_802_3_MAC_OPTIONS\n", __func__); + case RNDIS_OID_802_3_MAC_OPTIONS: + pr_debug("%s: RNDIS_OID_802_3_MAC_OPTIONS\n", __func__); *outbuf = cpu_to_le32(0); retval = 0; break; @@ -455,8 +455,8 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, /* ieee802.3 statistics OIDs (table 4-4) */ /* mandatory */ - case OID_802_3_RCV_ERROR_ALIGNMENT: - pr_debug("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __func__); + case RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT: + pr_debug("%s: RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT\n", __func__); if (stats) { *outbuf = cpu_to_le32(stats->rx_frame_errors); retval = 0; @@ -464,15 +464,15 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, break; /* mandatory */ - case OID_802_3_XMIT_ONE_COLLISION: - pr_debug("%s: OID_802_3_XMIT_ONE_COLLISION\n", __func__); + case RNDIS_OID_802_3_XMIT_ONE_COLLISION: + pr_debug("%s: RNDIS_OID_802_3_XMIT_ONE_COLLISION\n", __func__); *outbuf = cpu_to_le32(0); retval = 0; break; /* mandatory */ - case OID_802_3_XMIT_MORE_COLLISIONS: - pr_debug("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __func__); + case RNDIS_OID_802_3_XMIT_MORE_COLLISIONS: + pr_debug("%s: RNDIS_OID_802_3_XMIT_MORE_COLLISIONS\n", __func__); *outbuf = cpu_to_le32(0); retval = 0; break; @@ -516,7 +516,7 @@ static int gen_ndis_set_resp(u8 configNr, u32 OID, u8 *buf, u32 buf_len, params = &rndis_per_dev_params[configNr]; switch (OID) { - case OID_GEN_CURRENT_PACKET_FILTER: + case RNDIS_OID_GEN_CURRENT_PACKET_FILTER: /* these NDIS_PACKET_TYPE_* bitflags are shared with * cdc_filter; it's not RNDIS-specific @@ -525,7 +525,7 @@ static int gen_ndis_set_resp(u8 configNr, u32 OID, u8 *buf, u32 buf_len, * MULTICAST, ALL_MULTICAST, BROADCAST */ *params->filter = (u16)get_unaligned_le32(buf); - pr_debug("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n", + pr_debug("%s: RNDIS_OID_GEN_CURRENT_PACKET_FILTER %08x\n", __func__, *params->filter); /* this call has a significant side effect: it's @@ -545,9 +545,9 @@ static int gen_ndis_set_resp(u8 configNr, u32 OID, u8 *buf, u32 buf_len, } break; - case OID_802_3_MULTICAST_LIST: + case RNDIS_OID_802_3_MULTICAST_LIST: /* I think we can ignore this */ - pr_debug("%s: OID_802_3_MULTICAST_LIST\n", __func__); + pr_debug("%s: RNDIS_OID_802_3_MULTICAST_LIST\n", __func__); retval = 0; break; @@ -577,7 +577,7 @@ static int rndis_init_response(int configNr, rndis_init_msg_type *buf) return -ENOMEM; resp = (rndis_init_cmplt_type *)r->buf; - resp->MessageType = cpu_to_le32(REMOTE_NDIS_INITIALIZE_CMPLT); + resp->MessageType = cpu_to_le32(RNDIS_MSG_INIT_C); resp->MessageLength = cpu_to_le32(52); resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS); @@ -621,7 +621,7 @@ static int rndis_query_response(int configNr, rndis_query_msg_type *buf) return -ENOMEM; resp = (rndis_query_cmplt_type *)r->buf; - resp->MessageType = cpu_to_le32(REMOTE_NDIS_QUERY_CMPLT); + resp->MessageType = cpu_to_le32(RNDIS_MSG_QUERY_C); resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ if (gen_ndis_query_resp(configNr, le32_to_cpu(buf->OID), @@ -668,7 +668,7 @@ static int rndis_set_response(int configNr, rndis_set_msg_type *buf) pr_debug("\n"); #endif - resp->MessageType = cpu_to_le32(REMOTE_NDIS_SET_CMPLT); + resp->MessageType = cpu_to_le32(RNDIS_MSG_SET_C); resp->MessageLength = cpu_to_le32(16); resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ if (gen_ndis_set_resp(configNr, le32_to_cpu(buf->OID), @@ -692,7 +692,7 @@ static int rndis_reset_response(int configNr, rndis_reset_msg_type *buf) return -ENOMEM; resp = (rndis_reset_cmplt_type *)r->buf; - resp->MessageType = cpu_to_le32(REMOTE_NDIS_RESET_CMPLT); + resp->MessageType = cpu_to_le32(RNDIS_MSG_RESET_C); resp->MessageLength = cpu_to_le32(16); resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS); /* resent information */ @@ -716,8 +716,7 @@ static int rndis_keepalive_response(int configNr, return -ENOMEM; resp = (rndis_keepalive_cmplt_type *)r->buf; - resp->MessageType = cpu_to_le32( - REMOTE_NDIS_KEEPALIVE_CMPLT); + resp->MessageType = cpu_to_le32(RNDIS_MSG_KEEPALIVE_C); resp->MessageLength = cpu_to_le32(16); resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS); @@ -745,7 +744,7 @@ static int rndis_indicate_status_msg(int configNr, u32 status) return -ENOMEM; resp = (rndis_indicate_status_msg_type *)r->buf; - resp->MessageType = cpu_to_le32(REMOTE_NDIS_INDICATE_STATUS_MSG); + resp->MessageType = cpu_to_le32(RNDIS_MSG_INDICATE); resp->MessageLength = cpu_to_le32(20); resp->Status = cpu_to_le32(status); resp->StatusBufferLength = cpu_to_le32(0); @@ -758,7 +757,7 @@ static int rndis_indicate_status_msg(int configNr, u32 status) int rndis_signal_connect(int configNr) { rndis_per_dev_params[configNr].media_state - = NDIS_MEDIA_STATE_CONNECTED; + = RNDIS_MEDIA_STATE_CONNECTED; return rndis_indicate_status_msg(configNr, RNDIS_STATUS_MEDIA_CONNECT); } @@ -766,7 +765,7 @@ int rndis_signal_connect(int configNr) int rndis_signal_disconnect(int configNr) { rndis_per_dev_params[configNr].media_state - = NDIS_MEDIA_STATE_DISCONNECTED; + = RNDIS_MEDIA_STATE_DISCONNECTED; return rndis_indicate_status_msg(configNr, RNDIS_STATUS_MEDIA_DISCONNECT); } @@ -817,15 +816,15 @@ int rndis_msg_parser(u8 configNr, u8 *buf) /* For USB: responses may take up to 10 seconds */ switch (MsgType) { - case REMOTE_NDIS_INITIALIZE_MSG: - pr_debug("%s: REMOTE_NDIS_INITIALIZE_MSG\n", + case RNDIS_MSG_INIT: + pr_debug("%s: RNDIS_MSG_INIT\n", __func__); params->state = RNDIS_INITIALIZED; return rndis_init_response(configNr, (rndis_init_msg_type *)buf); - case REMOTE_NDIS_HALT_MSG: - pr_debug("%s: REMOTE_NDIS_HALT_MSG\n", + case RNDIS_MSG_HALT: + pr_debug("%s: RNDIS_MSG_HALT\n", __func__); params->state = RNDIS_UNINITIALIZED; if (params->dev) { @@ -834,24 +833,24 @@ int rndis_msg_parser(u8 configNr, u8 *buf) } return 0; - case REMOTE_NDIS_QUERY_MSG: + case RNDIS_MSG_QUERY: return rndis_query_response(configNr, (rndis_query_msg_type *)buf); - case REMOTE_NDIS_SET_MSG: + case RNDIS_MSG_SET: return rndis_set_response(configNr, (rndis_set_msg_type *)buf); - case REMOTE_NDIS_RESET_MSG: - pr_debug("%s: REMOTE_NDIS_RESET_MSG\n", + case RNDIS_MSG_RESET: + pr_debug("%s: RNDIS_MSG_RESET\n", __func__); return rndis_reset_response(configNr, (rndis_reset_msg_type *)buf); - case REMOTE_NDIS_KEEPALIVE_MSG: + case RNDIS_MSG_KEEPALIVE: /* For USB: host does this every 5 seconds */ if (rndis_debug > 1) - pr_debug("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", + pr_debug("%s: RNDIS_MSG_KEEPALIVE\n", __func__); return rndis_keepalive_response(configNr, (rndis_keepalive_msg_type *) @@ -963,7 +962,7 @@ void rndis_add_hdr(struct sk_buff *skb) return; header = (void *)skb_push(skb, sizeof(*header)); memset(header, 0, sizeof *header); - header->MessageType = cpu_to_le32(REMOTE_NDIS_PACKET_MSG); + header->MessageType = cpu_to_le32(RNDIS_MSG_PACKET); header->MessageLength = cpu_to_le32(skb->len); header->DataOffset = cpu_to_le32(36); header->DataLength = cpu_to_le32(skb->len - sizeof(*header)); @@ -1031,7 +1030,7 @@ int rndis_rm_hdr(struct gether *port, __le32 *tmp = (void *)skb->data; /* MessageType, MessageLength */ - if (cpu_to_le32(REMOTE_NDIS_PACKET_MSG) + if (cpu_to_le32(RNDIS_MSG_PACKET) != get_unaligned(tmp++)) { dev_kfree_skb_any(skb); return -EINVAL; @@ -1173,7 +1172,7 @@ int rndis_init(void) rndis_per_dev_params[i].used = 0; rndis_per_dev_params[i].state = RNDIS_UNINITIALIZED; rndis_per_dev_params[i].media_state - = NDIS_MEDIA_STATE_DISCONNECTED; + = RNDIS_MEDIA_STATE_DISCONNECTED; INIT_LIST_HEAD(&(rndis_per_dev_params[i].resp_queue)); } diff --git a/trunk/drivers/usb/gadget/rndis.h b/trunk/drivers/usb/gadget/rndis.h index 907c33008118..0647f2f34e89 100644 --- a/trunk/drivers/usb/gadget/rndis.h +++ b/trunk/drivers/usb/gadget/rndis.h @@ -15,58 +15,12 @@ #ifndef _LINUX_RNDIS_H #define _LINUX_RNDIS_H +#include #include "ndis.h" #define RNDIS_MAXIMUM_FRAME_SIZE 1518 #define RNDIS_MAX_TOTAL_SIZE 1558 -/* Remote NDIS Versions */ -#define RNDIS_MAJOR_VERSION 1 -#define RNDIS_MINOR_VERSION 0 - -/* Status Values */ -#define RNDIS_STATUS_SUCCESS 0x00000000U /* Success */ -#define RNDIS_STATUS_FAILURE 0xC0000001U /* Unspecified error */ -#define RNDIS_STATUS_INVALID_DATA 0xC0010015U /* Invalid data */ -#define RNDIS_STATUS_NOT_SUPPORTED 0xC00000BBU /* Unsupported request */ -#define RNDIS_STATUS_MEDIA_CONNECT 0x4001000BU /* Device connected */ -#define RNDIS_STATUS_MEDIA_DISCONNECT 0x4001000CU /* Device disconnected */ -/* For all not specified status messages: - * RNDIS_STATUS_Xxx -> NDIS_STATUS_Xxx - */ - -/* Message Set for Connectionless (802.3) Devices */ -#define REMOTE_NDIS_PACKET_MSG 0x00000001U -#define REMOTE_NDIS_INITIALIZE_MSG 0x00000002U /* Initialize device */ -#define REMOTE_NDIS_HALT_MSG 0x00000003U -#define REMOTE_NDIS_QUERY_MSG 0x00000004U -#define REMOTE_NDIS_SET_MSG 0x00000005U -#define REMOTE_NDIS_RESET_MSG 0x00000006U -#define REMOTE_NDIS_INDICATE_STATUS_MSG 0x00000007U -#define REMOTE_NDIS_KEEPALIVE_MSG 0x00000008U - -/* Message completion */ -#define REMOTE_NDIS_INITIALIZE_CMPLT 0x80000002U -#define REMOTE_NDIS_QUERY_CMPLT 0x80000004U -#define REMOTE_NDIS_SET_CMPLT 0x80000005U -#define REMOTE_NDIS_RESET_CMPLT 0x80000006U -#define REMOTE_NDIS_KEEPALIVE_CMPLT 0x80000008U - -/* Device Flags */ -#define RNDIS_DF_CONNECTIONLESS 0x00000001U -#define RNDIS_DF_CONNECTION_ORIENTED 0x00000002U - -#define RNDIS_MEDIUM_802_3 0x00000000U - -/* from drivers/net/sk98lin/h/skgepnmi.h */ -#define OID_PNP_CAPABILITIES 0xFD010100 -#define OID_PNP_SET_POWER 0xFD010101 -#define OID_PNP_QUERY_POWER 0xFD010102 -#define OID_PNP_ADD_WAKE_UP_PATTERN 0xFD010103 -#define OID_PNP_REMOVE_WAKE_UP_PATTERN 0xFD010104 -#define OID_PNP_ENABLE_WAKE_UP 0xFD010106 - - typedef struct rndis_init_msg_type { __le32 MessageType; diff --git a/trunk/drivers/usb/gadget/s3c-hsotg.c b/trunk/drivers/usb/gadget/s3c-hsotg.c index 105b206cd844..f4abb0ed9872 100644 --- a/trunk/drivers/usb/gadget/s3c-hsotg.c +++ b/trunk/drivers/usb/gadget/s3c-hsotg.c @@ -1,4 +1,5 @@ -/* linux/drivers/usb/gadget/s3c-hsotg.c +/** + * linux/drivers/usb/gadget/s3c-hsotg.c * * Copyright (c) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com @@ -13,7 +14,7 @@ * 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 @@ -27,21 +28,25 @@ #include #include #include +#include #include #include +#include #include -#include -#include -#include -#include -#include +#include "s3c-hsotg.h" #define DMA_ADDR_INVALID (~((dma_addr_t)0)) -/* EP0_MPS_LIMIT +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 @@ -125,8 +130,6 @@ struct s3c_hsotg_ep { char name[10]; }; -#define S3C_HSOTG_EPS (8+1) /* limit to 9 for the moment */ - /** * struct s3c_hsotg - driver state. * @dev: The parent device supplied to the probe function @@ -135,7 +138,9 @@ struct s3c_hsotg_ep { * @regs: The memory area mapped for accessing registers. * @regs_res: The resource that was allocated when claiming register space. * @irq: The IRQ number we are using + * @supplies: Definition of USB power supplies * @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. @@ -143,6 +148,8 @@ struct s3c_hsotg_ep { * @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 { @@ -155,7 +162,10 @@ struct s3c_hsotg { int irq; struct clk *clk; + struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsotg_supply_names)]; + unsigned int dedicated_fifos:1; + unsigned char num_of_eps; struct dentry *debug_root; struct dentry *debug_file; @@ -167,7 +177,9 @@ struct s3c_hsotg { u8 ctrl_buff[8]; struct usb_gadget gadget; - struct s3c_hsotg_ep eps[]; + unsigned int setup; + unsigned long last_rst; + struct s3c_hsotg_ep *eps; }; /** @@ -244,14 +256,14 @@ static inline bool using_dma(struct s3c_hsotg *hsotg) */ static void s3c_hsotg_en_gsint(struct s3c_hsotg *hsotg, u32 ints) { - u32 gsintmsk = readl(hsotg->regs + S3C_GINTMSK); + u32 gsintmsk = readl(hsotg->regs + GINTMSK); u32 new_gsintmsk; new_gsintmsk = gsintmsk | ints; if (new_gsintmsk != gsintmsk) { dev_dbg(hsotg->dev, "gsintmsk now 0x%08x\n", new_gsintmsk); - writel(new_gsintmsk, hsotg->regs + S3C_GINTMSK); + writel(new_gsintmsk, hsotg->regs + GINTMSK); } } @@ -262,13 +274,13 @@ static void s3c_hsotg_en_gsint(struct s3c_hsotg *hsotg, u32 ints) */ static void s3c_hsotg_disable_gsint(struct s3c_hsotg *hsotg, u32 ints) { - u32 gsintmsk = readl(hsotg->regs + S3C_GINTMSK); + u32 gsintmsk = readl(hsotg->regs + GINTMSK); u32 new_gsintmsk; new_gsintmsk = gsintmsk & ~ints; if (new_gsintmsk != gsintmsk) - writel(new_gsintmsk, hsotg->regs + S3C_GINTMSK); + writel(new_gsintmsk, hsotg->regs + GINTMSK); } /** @@ -293,12 +305,12 @@ static void s3c_hsotg_ctrl_epint(struct s3c_hsotg *hsotg, bit <<= 16; local_irq_save(flags); - daint = readl(hsotg->regs + S3C_DAINTMSK); + daint = readl(hsotg->regs + DAINTMSK); if (en) daint |= bit; else daint &= ~bit; - writel(daint, hsotg->regs + S3C_DAINTMSK); + writel(daint, hsotg->regs + DAINTMSK); local_irq_restore(flags); } @@ -314,52 +326,51 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg) int timeout; u32 val; - /* the ryu 2.6.24 release ahs - writel(0x1C0, hsotg->regs + S3C_GRXFSIZ); - writel(S3C_GNPTXFSIZ_NPTxFStAddr(0x200) | - S3C_GNPTXFSIZ_NPTxFDep(0x1C0), - hsotg->regs + S3C_GNPTXFSIZ); - */ - /* set FIFO sizes to 2048/1024 */ - writel(2048, hsotg->regs + S3C_GRXFSIZ); - writel(S3C_GNPTXFSIZ_NPTxFStAddr(2048) | - S3C_GNPTXFSIZ_NPTxFDep(1024), - hsotg->regs + S3C_GNPTXFSIZ); + writel(2048, hsotg->regs + GRXFSIZ); + writel(GNPTXFSIZ_NPTxFStAddr(2048) | + GNPTXFSIZ_NPTxFDep(1024), + hsotg->regs + GNPTXFSIZ); - /* arange all the rest of the TX FIFOs, as some versions of this + /* + * arange all the rest of the TX FIFOs, as some versions of this * block have overlapping default addresses. This also ensures * that if the settings have been changed, then they are set to - * known values. */ + * known values. + */ /* start at the end of the GNPTXFSIZ, rounded up */ addr = 2048 + 1024; size = 768; - /* currently we allocate TX FIFOs for all possible endpoints, - * and assume that they are all the same size. */ + /* + * currently we allocate TX FIFOs for all possible endpoints, + * and assume that they are all the same size. + */ for (ep = 1; ep <= 15; ep++) { val = addr; - val |= size << S3C_DPTXFSIZn_DPTxFSize_SHIFT; + val |= size << DPTXFSIZn_DPTxFSize_SHIFT; addr += size; - writel(val, hsotg->regs + S3C_DPTXFSIZn(ep)); + writel(val, hsotg->regs + DPTXFSIZn(ep)); } - /* according to p428 of the design guide, we need to ensure that - * all fifos are flushed before continuing */ + /* + * according to p428 of the design guide, we need to ensure that + * all fifos are flushed before continuing + */ - writel(S3C_GRSTCTL_TxFNum(0x10) | S3C_GRSTCTL_TxFFlsh | - S3C_GRSTCTL_RxFFlsh, hsotg->regs + S3C_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 + S3C_GRSTCTL); + val = readl(hsotg->regs + GRSTCTL); - if ((val & (S3C_GRSTCTL_TxFFlsh | S3C_GRSTCTL_RxFFlsh)) == 0) + if ((val & (GRSTCTL_TxFFlsh | GRSTCTL_RxFFlsh)) == 0) break; if (--timeout == 0) { @@ -415,7 +426,7 @@ static inline int is_ep_periodic(struct s3c_hsotg_ep *hs_ep) * * This is the reverse of s3c_hsotg_map_dma(), called for the completion * of a request to ensure the buffer is ready for access by the caller. -*/ + */ static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg, struct s3c_hsotg_ep *hs_ep, struct s3c_hsotg_req *hs_req) @@ -456,13 +467,13 @@ static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg, * otherwise -ENOSPC is returned if the FIFO space was used up. * * This routine is only needed for PIO -*/ + */ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, struct s3c_hsotg_ep *hs_ep, struct s3c_hsotg_req *hs_req) { bool periodic = is_ep_periodic(hs_ep); - u32 gnptxsts = readl(hsotg->regs + S3C_GNPTXSTS); + u32 gnptxsts = readl(hsotg->regs + GNPTXSTS); int buf_pos = hs_req->req.actual; int to_write = hs_ep->size_loaded; void *data; @@ -476,20 +487,23 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, return 0; if (periodic && !hsotg->dedicated_fifos) { - u32 epsize = readl(hsotg->regs + S3C_DIEPTSIZ(hs_ep->index)); + u32 epsize = readl(hsotg->regs + DIEPTSIZ(hs_ep->index)); int size_left; int size_done; - /* work out how much data was loaded so we can calculate - * how much data is left in the fifo. */ + /* + * work out how much data was loaded so we can calculate + * how much data is left in the fifo. + */ - size_left = S3C_DxEPTSIZ_XferSize_GET(epsize); + size_left = DxEPTSIZ_XferSize_GET(epsize); - /* if shared fifo, we cannot write anything until the + /* + * 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, S3C_GINTSTS_PTxFEmp); + s3c_hsotg_en_gsint(hsotg, GINTSTS_PTxFEmp); return -ENOSPC; } @@ -510,47 +524,50 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, __func__, can_write); if (can_write <= 0) { - s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_PTxFEmp); + s3c_hsotg_en_gsint(hsotg, GINTSTS_PTxFEmp); return -ENOSPC; } } else if (hsotg->dedicated_fifos && hs_ep->index != 0) { - can_write = readl(hsotg->regs + S3C_DTXFSTS(hs_ep->index)); + can_write = readl(hsotg->regs + DTXFSTS(hs_ep->index)); can_write &= 0xffff; can_write *= 4; } else { - if (S3C_GNPTXSTS_NPTxQSpcAvail_GET(gnptxsts) == 0) { + if (GNPTXSTS_NPTxQSpcAvail_GET(gnptxsts) == 0) { dev_dbg(hsotg->dev, "%s: no queue slots available (0x%08x)\n", __func__, gnptxsts); - s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_NPTxFEmp); + s3c_hsotg_en_gsint(hsotg, GINTSTS_NPTxFEmp); return -ENOSPC; } - can_write = S3C_GNPTXSTS_NPTxFSpcAvail_GET(gnptxsts); + can_write = GNPTXSTS_NPTxFSpcAvail_GET(gnptxsts); can_write *= 4; /* fifo size is in 32bit quantities. */ } dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, mps %d\n", __func__, gnptxsts, can_write, to_write, hs_ep->ep.maxpacket); - /* limit to 512 bytes of data, it seems at least on the non-periodic + /* + * limit to 512 bytes of data, it seems at least on the non-periodic * FIFO, requests of >512 cause the endpoint to get stuck with a * fragment of the end of the transfer in it. */ if (can_write > 512) can_write = 512; - /* limit the write to one max-packet size worth of data, but allow + /* + * limit the write to one max-packet size worth of data, but allow * the transfer to return that it did not run out of fifo space - * doing it. */ + * doing it. + */ if (to_write > hs_ep->ep.maxpacket) { to_write = hs_ep->ep.maxpacket; s3c_hsotg_en_gsint(hsotg, - periodic ? S3C_GINTSTS_PTxFEmp : - S3C_GINTSTS_NPTxFEmp); + periodic ? GINTSTS_PTxFEmp : + GINTSTS_NPTxFEmp); } /* see if we can write data */ @@ -559,8 +576,8 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, to_write = can_write; pkt_round = to_write % hs_ep->ep.maxpacket; - /* Not sure, but we probably shouldn't be writing partial - * packets into the FIFO, so round the write down to an + /* + * Round the write down to an * exact number of packets. * * Note, we do not currently check to see if we can ever @@ -570,12 +587,14 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, if (pkt_round) to_write -= pkt_round; - /* enable correct FIFO interrupt to alert us when there - * is more room left. */ + /* + * enable correct FIFO interrupt to alert us when there + * is more room left. + */ s3c_hsotg_en_gsint(hsotg, - periodic ? S3C_GINTSTS_PTxFEmp : - S3C_GINTSTS_NPTxFEmp); + periodic ? GINTSTS_PTxFEmp : + GINTSTS_NPTxFEmp); } dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n", @@ -593,7 +612,7 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, to_write = DIV_ROUND_UP(to_write, 4); data = hs_req->req.buf + buf_pos; - writesl(hsotg->regs + S3C_EPFIFO(hs_ep->index), data, to_write); + writesl(hsotg->regs + EPFIFO(hs_ep->index), data, to_write); return (to_write >= can_write) ? -ENOSPC : 0; } @@ -612,12 +631,12 @@ static unsigned get_ep_limit(struct s3c_hsotg_ep *hs_ep) unsigned maxpkt; if (index != 0) { - maxsize = S3C_DxEPTSIZ_XferSize_LIMIT + 1; - maxpkt = S3C_DxEPTSIZ_PktCnt_LIMIT + 1; + maxsize = DxEPTSIZ_XferSize_LIMIT + 1; + maxpkt = DxEPTSIZ_PktCnt_LIMIT + 1; } else { maxsize = 64+64; if (hs_ep->dir_in) - maxpkt = S3C_DIEPTSIZ0_PktCnt_LIMIT + 1; + maxpkt = DIEPTSIZ0_PktCnt_LIMIT + 1; else maxpkt = 2; } @@ -626,8 +645,10 @@ static unsigned get_ep_limit(struct s3c_hsotg_ep *hs_ep) maxpkt--; maxsize--; - /* constrain by packet count if maxpkts*pktsize is greater - * than the length register size. */ + /* + * constrain by packet count if maxpkts*pktsize is greater + * than the length register size. + */ if ((maxpkt * hs_ep->ep.maxpacket) < maxsize) maxsize = maxpkt * hs_ep->ep.maxpacket; @@ -674,8 +695,8 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, } } - epctrl_reg = dir_in ? S3C_DIEPCTL(index) : S3C_DOEPCTL(index); - epsize_reg = dir_in ? S3C_DIEPTSIZ(index) : S3C_DOEPTSIZ(index); + epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); + epsize_reg = dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index); dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x, ep %d, dir %s\n", __func__, readl(hsotg->regs + epctrl_reg), index, @@ -684,13 +705,14 @@ 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 & S3C_DxEPCTL_Stall) { + if (ctrl & DxEPCTL_Stall) { dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index); return; } length = ureq->length - ureq->actual; - + dev_dbg(hsotg->dev, "ureq->length:%d ureq->actual:%d\n", + ureq->length, ureq->actual); if (0) dev_dbg(hsotg->dev, "REQ buf %p len %d dma 0x%08x noi=%d zp=%d snok=%d\n", @@ -717,20 +739,22 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, packets = 1; /* send one packet if length is zero. */ if (dir_in && index != 0) - epsize = S3C_DxEPTSIZ_MC(1); + epsize = DxEPTSIZ_MC(1); else epsize = 0; if (index != 0 && ureq->zero) { - /* test for the packets being exactly right for the - * transfer */ + /* + * test for the packets being exactly right for the + * transfer + */ if (length == (packets * hs_ep->ep.maxpacket)) packets++; } - epsize |= S3C_DxEPTSIZ_PktCnt(packets); - epsize |= S3C_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); @@ -744,26 +768,38 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, if (using_dma(hsotg) && !continuing) { unsigned int dma_reg; - /* write DMA address to control register, buffer already - * synced by s3c_hsotg_ep_queue(). */ + /* + * write DMA address to control register, buffer already + * synced by s3c_hsotg_ep_queue(). + */ - dma_reg = dir_in ? S3C_DIEPDMA(index) : S3C_DOEPDMA(index); + dma_reg = dir_in ? DIEPDMA(index) : DOEPDMA(index); writel(ureq->dma, hsotg->regs + dma_reg); dev_dbg(hsotg->dev, "%s: 0x%08x => 0x%08x\n", __func__, ureq->dma, dma_reg); } - ctrl |= S3C_DxEPCTL_EPEna; /* ensure ep enabled */ - ctrl |= S3C_DxEPCTL_USBActEp; - ctrl |= S3C_DxEPCTL_CNAK; /* clear NAK set by core */ + ctrl |= DxEPCTL_EPEna; /* ensure ep enabled */ + ctrl |= DxEPCTL_USBActEp; + + dev_dbg(hsotg->dev, "setup req:%d\n", hsotg->setup); + + /* For Setup request do not clear NAK */ + if (hsotg->setup && index == 0) + hsotg->setup = 0; + else + ctrl |= DxEPCTL_CNAK; /* clear NAK set by core */ + dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); writel(ctrl, hsotg->regs + epctrl_reg); - /* set these, it seems that DMA support increments past the end + /* + * set these, it seems that DMA support increments past the end * of the packet buffer so we need to calculate the length from - * this information. */ + * this information. + */ hs_ep->size_loaded = length; hs_ep->last_load = ureq->actual; @@ -774,17 +810,21 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, s3c_hsotg_write_fifo(hsotg, hs_ep, hs_req); } - /* clear the INTknTXFEmpMsk when we start request, more as a aide - * to debugging to see what is going on. */ + /* + * clear the INTknTXFEmpMsk when we start request, more as a aide + * to debugging to see what is going on. + */ if (dir_in) - writel(S3C_DIEPMSK_INTknTXFEmpMsk, - hsotg->regs + S3C_DIEPINT(index)); + writel(DIEPMSK_INTknTXFEmpMsk, + hsotg->regs + DIEPINT(index)); - /* Note, trying to clear the NAK here causes problems with transmit - * on the S3C6400 ending up with the TXFIFO becoming full. */ + /* + * Note, trying to clear the NAK here causes problems with transmit + * on the S3C6400 ending up with the TXFIFO becoming full. + */ /* check ep is enabled */ - if (!(readl(hsotg->regs + epctrl_reg) & S3C_DxEPCTL_EPEna)) + if (!(readl(hsotg->regs + epctrl_reg) & DxEPCTL_EPEna)) dev_warn(hsotg->dev, "ep%d: failed to become enabled (DxEPCTL=0x%08x)?\n", index, readl(hsotg->regs + epctrl_reg)); @@ -804,7 +844,7 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, * then ensure the buffer has been synced to memory. If our buffer has no * DMA memory, then we map the memory and mark our request to allow us to * cleanup on completion. -*/ + */ static int s3c_hsotg_map_dma(struct s3c_hsotg *hsotg, struct s3c_hsotg_ep *hs_ep, struct usb_request *req) @@ -922,7 +962,7 @@ static void s3c_hsotg_complete_oursetup(struct usb_ep *ep, * * Convert the given wIndex into a pointer to an driver endpoint * structure, or return NULL if it is not a valid endpoint. -*/ + */ static struct s3c_hsotg_ep *ep_from_windex(struct s3c_hsotg *hsotg, u32 windex) { @@ -933,7 +973,7 @@ static struct s3c_hsotg_ep *ep_from_windex(struct s3c_hsotg *hsotg, if (windex >= 0x100) return NULL; - if (idx > S3C_HSOTG_EPS) + if (idx > hsotg->num_of_eps) return NULL; if (idx && ep->dir_in != dir) @@ -1151,24 +1191,28 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg, ctrl->bRequest, ctrl->bRequestType, ctrl->wValue, ctrl->wLength); - /* record the direction of the request, for later use when enquing - * packets onto EP0. */ + /* + * record the direction of the request, for later use when enquing + * packets onto EP0. + */ ep0->dir_in = (ctrl->bRequestType & USB_DIR_IN) ? 1 : 0; dev_dbg(hsotg->dev, "ctrl: dir_in=%d\n", ep0->dir_in); - /* if we've no data with this request, then the last part of the - * transaction is going to implicitly be IN. */ + /* + * if we've no data with this request, then the last part of the + * transaction is going to implicitly be IN. + */ if (ctrl->wLength == 0) ep0->dir_in = 1; if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { switch (ctrl->bRequest) { case USB_REQ_SET_ADDRESS: - dcfg = readl(hsotg->regs + S3C_DCFG); - dcfg &= ~S3C_DCFG_DevAddr_MASK; - dcfg |= ctrl->wValue << S3C_DCFG_DevAddr_SHIFT; - writel(dcfg, hsotg->regs + S3C_DCFG); + dcfg = readl(hsotg->regs + DCFG); + dcfg &= ~DCFG_DevAddr_MASK; + dcfg |= ctrl->wValue << DCFG_DevAddr_SHIFT; + writel(dcfg, hsotg->regs + DCFG); dev_info(hsotg->dev, "new address %d\n", ctrl->wValue); @@ -1194,7 +1238,8 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg, dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret); } - /* the request is either unhandlable, or is not formatted correctly + /* + * the request is either unhandlable, or is not formatted correctly * so respond with a STALL for the status stage to indicate failure. */ @@ -1203,22 +1248,26 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg, u32 ctrl; dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in); - reg = (ep0->dir_in) ? S3C_DIEPCTL0 : S3C_DOEPCTL0; + reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0; - /* S3C_DxEPCTL_Stall will be cleared by EP once it has - * taken effect, so no need to clear later. */ + /* + * DxEPCTL_Stall will be cleared by EP once it has + * taken effect, so no need to clear later. + */ ctrl = readl(hsotg->regs + reg); - ctrl |= S3C_DxEPCTL_Stall; - ctrl |= S3C_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", ctrl, reg, readl(hsotg->regs + reg)); - /* don't believe we need to anything more to get the EP - * to reply with a STALL packet */ + /* + * don't believe we need to anything more to get the EP + * to reply with a STALL packet + */ } } @@ -1279,8 +1328,10 @@ static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg) ret = s3c_hsotg_ep_queue(&hsotg->eps[0].ep, req, GFP_ATOMIC); if (ret < 0) { dev_err(hsotg->dev, "%s: failed queue (%d)\n", __func__, ret); - /* Don't think there's much we can do other than watch the - * driver fail. */ + /* + * Don't think there's much we can do other than watch the + * driver fail. + */ } } @@ -1296,7 +1347,7 @@ static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg) * on the endpoint. * * Note, expects the ep to already be locked as appropriate. -*/ + */ static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg, struct s3c_hsotg_ep *hs_ep, struct s3c_hsotg_req *hs_req, @@ -1312,8 +1363,10 @@ static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg, dev_dbg(hsotg->dev, "complete: ep %p %s, req %p, %d => %p\n", hs_ep, hs_ep->ep.name, hs_req, result, hs_req->req.complete); - /* only replace the status if we've not already set an error - * from a previous transaction */ + /* + * only replace the status if we've not already set an error + * from a previous transaction + */ if (hs_req->req.status == -EINPROGRESS) hs_req->req.status = result; @@ -1324,8 +1377,10 @@ static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg, if (using_dma(hsotg)) s3c_hsotg_unmap_dma(hsotg, hs_ep, hs_req); - /* call the complete request with the locks off, just in case the - * request tries to queue more work for this endpoint. */ + /* + * call the complete request with the locks off, just in case the + * request tries to queue more work for this endpoint. + */ if (hs_req->req.complete) { spin_unlock(&hs_ep->lock); @@ -1333,9 +1388,11 @@ static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg, spin_lock(&hs_ep->lock); } - /* Look to see if there is anything else to do. Note, the completion + /* + * Look to see if there is anything else to do. Note, the completion * of the previous request may have caused a new request to be started - * so be careful when doing this. */ + * so be careful when doing this. + */ if (!hs_ep->req && result >= 0) { restart = !list_empty(&hs_ep->queue); @@ -1355,7 +1412,7 @@ static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg, * * See s3c_hsotg_complete_request(), but called with the endpoint's * lock held. -*/ + */ static void s3c_hsotg_complete_request_lock(struct s3c_hsotg *hsotg, struct s3c_hsotg_ep *hs_ep, struct s3c_hsotg_req *hs_req, @@ -1382,13 +1439,13 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size) { struct s3c_hsotg_ep *hs_ep = &hsotg->eps[ep_idx]; struct s3c_hsotg_req *hs_req = hs_ep->req; - void __iomem *fifo = hsotg->regs + S3C_EPFIFO(ep_idx); + void __iomem *fifo = hsotg->regs + EPFIFO(ep_idx); int to_read; int max_req; int read_ptr; if (!hs_req) { - u32 epctl = readl(hsotg->regs + S3C_DOEPCTL(ep_idx)); + u32 epctl = readl(hsotg->regs + DOEPCTL(ep_idx)); int ptr; dev_warn(hsotg->dev, @@ -1412,7 +1469,8 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size) __func__, to_read, max_req, read_ptr, hs_req->req.length); if (to_read > max_req) { - /* more data appeared than we where willing + /* + * more data appeared than we where willing * to deal with in this request. */ @@ -1424,8 +1482,10 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size) hs_req->req.actual += to_read; to_read = DIV_ROUND_UP(to_read, 4); - /* note, we might over-write the buffer end by 3 bytes depending on - * alignment of the data. */ + /* + * note, we might over-write the buffer end by 3 bytes depending on + * alignment of the data. + */ readsl(fifo, hs_req->req.buf + read_ptr, to_read); spin_unlock(&hs_ep->lock); @@ -1465,14 +1525,14 @@ 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(S3C_DxEPTSIZ_MC(1) | S3C_DxEPTSIZ_PktCnt(1) | - S3C_DxEPTSIZ_XferSize(0), hsotg->regs + S3C_DIEPTSIZ(0)); + writel(DxEPTSIZ_MC(1) | DxEPTSIZ_PktCnt(1) | + DxEPTSIZ_XferSize(0), hsotg->regs + DIEPTSIZ(0)); - ctrl = readl(hsotg->regs + S3C_DIEPCTL0); - ctrl |= S3C_DxEPCTL_CNAK; /* clear NAK set by core */ - ctrl |= S3C_DxEPCTL_EPEna; /* ensure ep enabled */ - ctrl |= S3C_DxEPCTL_USBActEp; - writel(ctrl, hsotg->regs + S3C_DIEPCTL0); + ctrl = readl(hsotg->regs + DIEPCTL0); + ctrl |= DxEPCTL_CNAK; /* clear NAK set by core */ + ctrl |= DxEPCTL_EPEna; /* ensure ep enabled */ + ctrl |= DxEPCTL_USBActEp; + writel(ctrl, hsotg->regs + DIEPCTL0); } /** @@ -1484,15 +1544,15 @@ static void s3c_hsotg_send_zlp(struct s3c_hsotg *hsotg, * The RXFIFO has delivered an OutDone event, which means that the data * transfer for an OUT endpoint has been completed, either by a short * packet or by the finish of a transfer. -*/ + */ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg, int epnum, bool was_setup) { - u32 epsize = readl(hsotg->regs + S3C_DOEPTSIZ(epnum)); + u32 epsize = readl(hsotg->regs + DOEPTSIZ(epnum)); 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 = S3C_DxEPTSIZ_XferSize_GET(epsize); + unsigned size_left = DxEPTSIZ_XferSize_GET(epsize); int result = 0; if (!hs_req) { @@ -1503,7 +1563,8 @@ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg, if (using_dma(hsotg)) { unsigned size_done; - /* Calculate the size of the transfer by checking how much + /* + * Calculate the size of the transfer by checking how much * is left in the endpoint size register and then working it * out from the amount we loaded for the transfer. * @@ -1521,17 +1582,29 @@ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg, if (req->actual < req->length && size_left == 0) { s3c_hsotg_start_req(hsotg, hs_ep, hs_req, true); return; + } else if (epnum == 0) { + /* + * After was_setup = 1 => + * set CNAK for non Setup requests + */ + hsotg->setup = was_setup ? 0 : 1; } if (req->actual < req->length && req->short_not_ok) { dev_dbg(hsotg->dev, "%s: got %d/%d (short not ok) => error\n", __func__, req->actual, req->length); - /* todo - what should we return here? there's no one else - * even bothering to check the status. */ + /* + * todo - what should we return here? there's no one else + * even bothering to check the status. + */ } if (epnum == 0) { + /* + * Condition req->complete != s3c_hsotg_complete_setup says: + * send ZLP when we have an asynchronous request from gadget + */ if (!was_setup && req->complete != s3c_hsotg_complete_setup) s3c_hsotg_send_zlp(hsotg, hs_req); } @@ -1544,14 +1617,14 @@ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg, * @hsotg: The device instance * * Return the current frame number -*/ + */ static u32 s3c_hsotg_read_frameno(struct s3c_hsotg *hsotg) { u32 dsts; - dsts = readl(hsotg->regs + S3C_DSTS); - dsts &= S3C_DSTS_SOFFN_MASK; - dsts >>= S3C_DSTS_SOFFN_SHIFT; + dsts = readl(hsotg->regs + DSTS); + dsts &= DSTS_SOFFN_MASK; + dsts >>= DSTS_SOFFN_SHIFT; return dsts; } @@ -1574,29 +1647,29 @@ static u32 s3c_hsotg_read_frameno(struct s3c_hsotg *hsotg) */ static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg) { - u32 grxstsr = readl(hsotg->regs + S3C_GRXSTSP); + u32 grxstsr = readl(hsotg->regs + GRXSTSP); u32 epnum, status, size; WARN_ON(using_dma(hsotg)); - epnum = grxstsr & S3C_GRXSTS_EPNum_MASK; - status = grxstsr & S3C_GRXSTS_PktSts_MASK; + epnum = grxstsr & GRXSTS_EPNum_MASK; + status = grxstsr & GRXSTS_PktSts_MASK; - size = grxstsr & S3C_GRXSTS_ByteCnt_MASK; - size >>= S3C_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) >> S3C_GRXSTS_PktSts_SHIFT) +#define __status(x) ((x) >> GRXSTS_PktSts_SHIFT) - switch (status >> S3C_GRXSTS_PktSts_SHIFT) { - case __status(S3C_GRXSTS_PktSts_GlobalOutNAK): + switch (status >> GRXSTS_PktSts_SHIFT) { + case __status(GRXSTS_PktSts_GlobalOutNAK): dev_dbg(hsotg->dev, "GlobalOutNAK\n"); break; - case __status(S3C_GRXSTS_PktSts_OutDone): + case __status(GRXSTS_PktSts_OutDone): dev_dbg(hsotg->dev, "OutDone (Frame=0x%08x)\n", s3c_hsotg_read_frameno(hsotg)); @@ -1604,24 +1677,24 @@ static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg) s3c_hsotg_handle_outdone(hsotg, epnum, false); break; - case __status(S3C_GRXSTS_PktSts_SetupDone): + case __status(GRXSTS_PktSts_SetupDone): dev_dbg(hsotg->dev, "SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n", s3c_hsotg_read_frameno(hsotg), - readl(hsotg->regs + S3C_DOEPCTL(0))); + readl(hsotg->regs + DOEPCTL(0))); s3c_hsotg_handle_outdone(hsotg, epnum, true); break; - case __status(S3C_GRXSTS_PktSts_OutRX): + case __status(GRXSTS_PktSts_OutRX): s3c_hsotg_rx_data(hsotg, epnum, size); break; - case __status(S3C_GRXSTS_PktSts_SetupRX): + case __status(GRXSTS_PktSts_SetupRX): dev_dbg(hsotg->dev, "SetupRX (Frame=0x%08x, DOPEPCTL=0x%08x)\n", s3c_hsotg_read_frameno(hsotg), - readl(hsotg->regs + S3C_DOEPCTL(0))); + readl(hsotg->regs + DOEPCTL(0))); s3c_hsotg_rx_data(hsotg, epnum, size); break; @@ -1638,18 +1711,18 @@ static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg) /** * s3c_hsotg_ep0_mps - turn max packet size into register setting * @mps: The maximum packet size in bytes. -*/ + */ static u32 s3c_hsotg_ep0_mps(unsigned int mps) { switch (mps) { case 64: - return S3C_D0EPCTL_MPS_64; + return D0EPCTL_MPS_64; case 32: - return S3C_D0EPCTL_MPS_32; + return D0EPCTL_MPS_32; case 16: - return S3C_D0EPCTL_MPS_16; + return D0EPCTL_MPS_16; case 8: - return S3C_D0EPCTL_MPS_8; + return D0EPCTL_MPS_8; } /* bad max packet size, warn and return invalid result */ @@ -1680,7 +1753,7 @@ static void s3c_hsotg_set_ep_maxpacket(struct s3c_hsotg *hsotg, if (mpsval > 3) goto bad_mps; } else { - if (mps >= S3C_DxEPCTL_MPS_LIMIT+1) + if (mps >= DxEPCTL_MPS_LIMIT+1) goto bad_mps; mpsval = mps; @@ -1688,19 +1761,21 @@ static void s3c_hsotg_set_ep_maxpacket(struct s3c_hsotg *hsotg, hs_ep->ep.maxpacket = mps; - /* update both the in and out endpoint controldir_ registers, even - * if one of the directions may not be in use. */ + /* + * update both the in and out endpoint controldir_ registers, even + * if one of the directions may not be in use. + */ - reg = readl(regs + S3C_DIEPCTL(ep)); - reg &= ~S3C_DxEPCTL_MPS_MASK; + reg = readl(regs + DIEPCTL(ep)); + reg &= ~DxEPCTL_MPS_MASK; reg |= mpsval; - writel(reg, regs + S3C_DIEPCTL(ep)); + writel(reg, regs + DIEPCTL(ep)); if (ep) { - reg = readl(regs + S3C_DOEPCTL(ep)); - reg &= ~S3C_DxEPCTL_MPS_MASK; + reg = readl(regs + DOEPCTL(ep)); + reg &= ~DxEPCTL_MPS_MASK; reg |= mpsval; - writel(reg, regs + S3C_DOEPCTL(ep)); + writel(reg, regs + DOEPCTL(ep)); } return; @@ -1719,16 +1794,16 @@ static void s3c_hsotg_txfifo_flush(struct s3c_hsotg *hsotg, unsigned int idx) int timeout; int val; - writel(S3C_GRSTCTL_TxFNum(idx) | S3C_GRSTCTL_TxFFlsh, - hsotg->regs + S3C_GRSTCTL); + writel(GRSTCTL_TxFNum(idx) | GRSTCTL_TxFFlsh, + hsotg->regs + GRSTCTL); /* wait until the fifo is flushed */ timeout = 100; while (1) { - val = readl(hsotg->regs + S3C_GRSTCTL); + val = readl(hsotg->regs + GRSTCTL); - if ((val & (S3C_GRSTCTL_TxFFlsh)) == 0) + if ((val & (GRSTCTL_TxFFlsh)) == 0) break; if (--timeout == 0) { @@ -1778,7 +1853,7 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg, struct s3c_hsotg_ep *hs_ep) { struct s3c_hsotg_req *hs_req = hs_ep->req; - u32 epsize = readl(hsotg->regs + S3C_DIEPTSIZ(hs_ep->index)); + u32 epsize = readl(hsotg->regs + DIEPTSIZ(hs_ep->index)); int size_left, size_done; if (!hs_req) { @@ -1786,7 +1861,15 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg, return; } - /* Calculate the size of the transfer by checking how much is left + /* Finish ZLP handling for IN EP0 transactions */ + if (hsotg->eps[0].sent_zlp) { + dev_dbg(hsotg->dev, "zlp packet received\n"); + s3c_hsotg_complete_request_lock(hsotg, hs_ep, hs_req, 0); + return; + } + + /* + * Calculate the size of the transfer by checking how much is left * in the endpoint size register and then working it out from * the amount we loaded for the transfer. * @@ -1795,7 +1878,7 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg, * aligned). */ - size_left = S3C_DxEPTSIZ_XferSize_GET(epsize); + size_left = DxEPTSIZ_XferSize_GET(epsize); size_done = hs_ep->size_loaded - size_left; size_done += hs_ep->last_load; @@ -1805,9 +1888,28 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg, __func__, hs_req->req.actual, size_done); hs_req->req.actual = size_done; + dev_dbg(hsotg->dev, "req->length:%d req->actual:%d req->zero:%d\n", + hs_req->req.length, hs_req->req.actual, hs_req->req.zero); + + /* + * Check if dealing with Maximum Packet Size(MPS) IN transfer at EP0 + * When sent data is a multiple MPS size (e.g. 64B ,128B ,192B + * ,256B ... ), after last MPS sized packet send IN ZLP packet to + * inform the host that no more data is available. + * The state of req.zero member is checked to be sure that the value to + * send is smaller than wValue expected from host. + * Check req.length to NOT send another ZLP when the current one is + * under completion (the one for which this completion has been called). + */ + if (hs_req->req.length && hs_ep->index == 0 && hs_req->req.zero && + hs_req->req.length == hs_req->req.actual && + !(hs_req->req.length % hs_ep->ep.maxpacket)) { - /* if we did all of the transfer, and there is more data left - * around, then try restarting the rest of the request */ + dev_dbg(hsotg->dev, "ep0 zlp IN packet sent\n"); + s3c_hsotg_send_zlp(hsotg, hs_req); + + return; + } if (!size_left && hs_req->req.actual < hs_req->req.length) { dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__); @@ -1823,14 +1925,14 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg, * @dir_in: Set if this is an IN endpoint * * Process and clear any interrupt pending for an individual endpoint -*/ + */ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, int dir_in) { struct s3c_hsotg_ep *hs_ep = &hsotg->eps[idx]; - u32 epint_reg = dir_in ? S3C_DIEPINT(idx) : S3C_DOEPINT(idx); - u32 epctl_reg = dir_in ? S3C_DIEPCTL(idx) : S3C_DOEPCTL(idx); - u32 epsiz_reg = dir_in ? S3C_DIEPTSIZ(idx) : S3C_DOEPTSIZ(idx); + u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx); + u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx); + u32 epsiz_reg = dir_in ? DIEPTSIZ(idx) : DOEPTSIZ(idx); u32 ints; ints = readl(hsotg->regs + epint_reg); @@ -1841,28 +1943,32 @@ 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 & S3C_DxEPINT_XferCompl) { + if (ints & DxEPINT_XferCompl) { dev_dbg(hsotg->dev, "%s: XferCompl: DxEPCTL=0x%08x, DxEPTSIZ=%08x\n", __func__, readl(hsotg->regs + epctl_reg), readl(hsotg->regs + epsiz_reg)); - /* we get OutDone from the FIFO, so we only need to look - * at completing IN requests here */ + /* + * we get OutDone from the FIFO, so we only need to look + * at completing IN requests here + */ if (dir_in) { s3c_hsotg_complete_in(hsotg, hs_ep); if (idx == 0 && !hs_ep->req) s3c_hsotg_enqueue_setup(hsotg); } else if (using_dma(hsotg)) { - /* We're using DMA, we need to fire an OutDone here - * as we ignore the RXFIFO. */ + /* + * We're using DMA, we need to fire an OutDone here + * as we ignore the RXFIFO. + */ s3c_hsotg_handle_outdone(hsotg, idx, false); } } - if (ints & S3C_DxEPINT_EPDisbld) { + if (ints & DxEPINT_EPDisbld) { dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__); if (dir_in) { @@ -1870,27 +1976,29 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, s3c_hsotg_txfifo_flush(hsotg, idx); - if ((epctl & S3C_DxEPCTL_Stall) && - (epctl & S3C_DxEPCTL_EPType_Bulk)) { - int dctl = readl(hsotg->regs + S3C_DCTL); + if ((epctl & DxEPCTL_Stall) && + (epctl & DxEPCTL_EPType_Bulk)) { + int dctl = readl(hsotg->regs + DCTL); - dctl |= S3C_DCTL_CGNPInNAK; - writel(dctl, hsotg->regs + S3C_DCTL); + dctl |= DCTL_CGNPInNAK; + writel(dctl, hsotg->regs + DCTL); } } } - if (ints & S3C_DxEPINT_AHBErr) + if (ints & DxEPINT_AHBErr) dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__); - if (ints & S3C_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) { - /* this is the notification we've received a + /* + * this is the notification we've received a * setup packet. In non-DMA mode we'd get this * from the RXFIFO, instead we need to process - * the setup here. */ + * the setup here. + */ if (dir_in) WARN_ON_ONCE(1); @@ -1899,26 +2007,25 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, } } - if (ints & S3C_DxEPINT_Back2BackSetup) + if (ints & DxEPINT_Back2BackSetup) dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__); if (dir_in) { - /* not sure if this is important, but we'll clear it anyway - */ - if (ints & S3C_DIEPMSK_INTknTXFEmpMsk) { + /* not sure if this is important, but we'll clear it anyway */ + if (ints & DIEPMSK_INTknTXFEmpMsk) { dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n", __func__, idx); } /* this probably means something bad is happening */ - if (ints & S3C_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 & S3C_DIEPMSK_TxFIFOEmpty) { + ints & DIEPMSK_TxFIFOEmpty) { dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n", __func__, idx); if (!using_dma(hsotg)) @@ -1933,40 +2040,45 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, * * Handle updating the device settings after the enumeration phase has * been completed. -*/ + */ static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg) { - u32 dsts = readl(hsotg->regs + S3C_DSTS); + u32 dsts = readl(hsotg->regs + DSTS); int ep0_mps = 0, ep_mps; - /* This should signal the finish of the enumeration phase + /* + * This should signal the finish of the enumeration phase * of the USB handshaking, so we should now know what rate - * we connected at. */ + * we connected at. + */ dev_dbg(hsotg->dev, "EnumDone (DSTS=0x%08x)\n", dsts); - /* note, since we're limited by the size of transfer on EP0, and + /* + * note, since we're limited by the size of transfer on EP0, and * it seems IN transfers must be a even number of packets we do - * not advertise a 64byte MPS on EP0. */ + * not advertise a 64byte MPS on EP0. + */ /* catch both EnumSpd_FS and EnumSpd_FS48 */ - switch (dsts & S3C_DSTS_EnumSpd_MASK) { - case S3C_DSTS_EnumSpd_FS: - case S3C_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 = 64; break; - case S3C_DSTS_EnumSpd_HS: + case DSTS_EnumSpd_HS: hsotg->gadget.speed = USB_SPEED_HIGH; ep0_mps = EP0_MPS_LIMIT; ep_mps = 512; break; - case S3C_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 + /* + * note, we don't actually support LS in this driver at the * moment, and the documentation seems to imply that it isn't * supported by the PHYs on some of the devices. */ @@ -1975,13 +2087,15 @@ static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg) dev_info(hsotg->dev, "new device is %s\n", usb_speed_string(hsotg->gadget.speed)); - /* we should now know the maximum packet size for an - * endpoint, so set the endpoints to a default value. */ + /* + * we should now know the maximum packet size for an + * endpoint, so set the endpoints to a default value. + */ if (ep0_mps) { int i; s3c_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps); - for (i = 1; i < S3C_HSOTG_EPS; i++) + for (i = 1; i < hsotg->num_of_eps; i++) s3c_hsotg_set_ep_maxpacket(hsotg, i, ep_mps); } @@ -1990,8 +2104,8 @@ static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg) s3c_hsotg_enqueue_setup(hsotg); dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", - readl(hsotg->regs + S3C_DIEPCTL0), - readl(hsotg->regs + S3C_DOEPCTL0)); + readl(hsotg->regs + DIEPCTL0), + readl(hsotg->regs + DOEPCTL0)); } /** @@ -2014,8 +2128,10 @@ static void kill_all_requests(struct s3c_hsotg *hsotg, spin_lock_irqsave(&ep->lock, flags); list_for_each_entry_safe(req, treq, &ep->queue, queue) { - /* currently, we can't do much about an already - * running request on an in endpoint */ + /* + * currently, we can't do much about an already + * running request on an in endpoint + */ if (ep->req == req && ep->dir_in && !force) continue; @@ -2033,18 +2149,18 @@ static void kill_all_requests(struct s3c_hsotg *hsotg, (_hs)->driver->_entry(&(_hs)->gadget); /** - * s3c_hsotg_disconnect_irq - disconnect irq service + * s3c_hsotg_disconnect - disconnect service * @hsotg: The device state. * - * A disconnect IRQ has been received, meaning that the host has - * lost contact with the bus. Remove all current transactions - * and signal the gadget driver that this has happened. -*/ -static void s3c_hsotg_disconnect_irq(struct s3c_hsotg *hsotg) + * The device has been disconnected. Remove all current + * transactions and signal the gadget driver that this + * has happened. + */ +static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg) { unsigned ep; - for (ep = 0; ep < S3C_HSOTG_EPS; ep++) + for (ep = 0; ep < hsotg->num_of_eps; ep++) kill_all_requests(hsotg, &hsotg->eps[ep], -ESHUTDOWN, true); call_gadget(hsotg, disconnect); @@ -2062,7 +2178,7 @@ static void s3c_hsotg_irq_fifoempty(struct s3c_hsotg *hsotg, bool periodic) /* look through for any more data to transmit */ - for (epno = 0; epno < S3C_HSOTG_EPS; epno++) { + for (epno = 0; epno < hsotg->num_of_eps; epno++) { ep = &hsotg->eps[epno]; if (!ep->dir_in) @@ -2078,12 +2194,187 @@ static void s3c_hsotg_irq_fifoempty(struct s3c_hsotg *hsotg, bool periodic) } } -static struct s3c_hsotg *our_hsotg; - /* IRQ flags which will trigger a retry around the IRQ loop */ -#define IRQ_RETRY_MASK (S3C_GINTSTS_NPTxFEmp | \ - S3C_GINTSTS_PTxFEmp | \ - S3C_GINTSTS_RxFLvl) +#define IRQ_RETRY_MASK (GINTSTS_NPTxFEmp | \ + GINTSTS_PTxFEmp | \ + GINTSTS_RxFLvl) + +/** + * s3c_hsotg_corereset - issue softreset to the core + * @hsotg: The device state + * + * Issue a soft reset to the core, and await the core finishing it. + */ +static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg) +{ + int timeout; + u32 grstctl; + + dev_dbg(hsotg->dev, "resetting core\n"); + + /* issue soft reset */ + writel(GRSTCTL_CSftRst, hsotg->regs + GRSTCTL); + + timeout = 1000; + do { + grstctl = readl(hsotg->regs + GRSTCTL); + } while ((grstctl & GRSTCTL_CSftRst) && timeout-- > 0); + + if (grstctl & GRSTCTL_CSftRst) { + dev_err(hsotg->dev, "Failed to get CSftRst asserted\n"); + return -EINVAL; + } + + timeout = 1000; + + while (1) { + u32 grstctl = readl(hsotg->regs + GRSTCTL); + + if (timeout-- < 0) { + dev_info(hsotg->dev, + "%s: reset failed, GRSTCTL=%08x\n", + __func__, grstctl); + return -ETIMEDOUT; + } + + if (!(grstctl & GRSTCTL_AHBIdle)) + continue; + + break; /* reset done */ + } + + dev_dbg(hsotg->dev, "reset successful\n"); + return 0; +} + +/** + * s3c_hsotg_core_init - issue softreset to the core + * @hsotg: The device state + * + * Issue a soft reset to the core, and await the core finishing it. + */ +static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg) +{ + s3c_hsotg_corereset(hsotg); + + /* + * we must now enable ep0 ready for host detection and then + * set configuration. + */ + + /* set the PLL on, remove the HNP/SRP and set the PHY */ + writel(GUSBCFG_PHYIf16 | GUSBCFG_TOutCal(7) | + (0x5 << 10), hsotg->regs + GUSBCFG); + + s3c_hsotg_init_fifo(hsotg); + + __orr32(hsotg->regs + DCTL, DCTL_SftDiscon); + + writel(1 << 18 | DCFG_DevSpd_HS, hsotg->regs + DCFG); + + /* Clear any pending OTG interrupts */ + writel(0xffffffff, hsotg->regs + GOTGINT); + + /* 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); + + if (using_dma(hsotg)) + writel(GAHBCFG_GlblIntrEn | GAHBCFG_DMAEn | + GAHBCFG_HBstLen_Incr4, + hsotg->regs + GAHBCFG); + else + writel(GAHBCFG_GlblIntrEn, hsotg->regs + GAHBCFG); + + /* + * Enabling INTknTXFEmpMsk here seems to be a big mistake, we end + * up being flooded with interrupts if the host is polling the + * endpoint to try and read data. + */ + + writel(((hsotg->dedicated_fifos) ? DIEPMSK_TxFIFOEmpty : 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(0, hsotg->regs + DAINTMSK); + + dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", + readl(hsotg->regs + DIEPCTL0), + readl(hsotg->regs + DOEPCTL0)); + + /* enable in and out endpoint interrupts */ + s3c_hsotg_en_gsint(hsotg, GINTSTS_OEPInt | GINTSTS_IEPInt); + + /* + * Enable the RXFIFO when in slave mode, as this is how we collect + * the data. In DMA mode, we get events from the FIFO but also + * things we cannot process, so do not use it. + */ + if (!using_dma(hsotg)) + 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); + udelay(10); /* see openiboot */ + __bic32(hsotg->regs + DCTL, DCTL_PWROnPrgDone); + + dev_dbg(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + DCTL)); + + /* + * DxEPCTL_USBActEp says RO in manual, but seems to be set by + * writing to the EPCTL register.. + */ + + /* set to read 1 8byte packet */ + 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, + hsotg->regs + DOEPCTL0); + + /* enable, but don't activate EP0in */ + writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) | + DxEPCTL_USBActEp, hsotg->regs + DIEPCTL0); + + s3c_hsotg_enqueue_setup(hsotg); + + dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", + readl(hsotg->regs + DIEPCTL0), + readl(hsotg->regs + DOEPCTL0)); + + /* clear global NAKs */ + 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); +} /** * s3c_hsotg_irq - handle device interrupt @@ -2098,52 +2389,45 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw) u32 gintmsk; irq_retry: - gintsts = readl(hsotg->regs + S3C_GINTSTS); - gintmsk = readl(hsotg->regs + S3C_GINTMSK); + gintsts = readl(hsotg->regs + GINTSTS); + gintmsk = readl(hsotg->regs + GINTMSK); dev_dbg(hsotg->dev, "%s: %08x %08x (%08x) retry %d\n", __func__, gintsts, gintsts & gintmsk, gintmsk, retry_count); gintsts &= gintmsk; - if (gintsts & S3C_GINTSTS_OTGInt) { - u32 otgint = readl(hsotg->regs + S3C_GOTGINT); + if (gintsts & GINTSTS_OTGInt) { + u32 otgint = readl(hsotg->regs + GOTGINT); dev_info(hsotg->dev, "OTGInt: %08x\n", otgint); - writel(otgint, hsotg->regs + S3C_GOTGINT); - } - - if (gintsts & S3C_GINTSTS_DisconnInt) { - dev_dbg(hsotg->dev, "%s: DisconnInt\n", __func__); - writel(S3C_GINTSTS_DisconnInt, hsotg->regs + S3C_GINTSTS); - - s3c_hsotg_disconnect_irq(hsotg); + writel(otgint, hsotg->regs + GOTGINT); } - if (gintsts & S3C_GINTSTS_SessReqInt) { + if (gintsts & GINTSTS_SessReqInt) { dev_dbg(hsotg->dev, "%s: SessReqInt\n", __func__); - writel(S3C_GINTSTS_SessReqInt, hsotg->regs + S3C_GINTSTS); + writel(GINTSTS_SessReqInt, hsotg->regs + GINTSTS); } - if (gintsts & S3C_GINTSTS_EnumDone) { - writel(S3C_GINTSTS_EnumDone, hsotg->regs + S3C_GINTSTS); + if (gintsts & GINTSTS_EnumDone) { + writel(GINTSTS_EnumDone, hsotg->regs + GINTSTS); s3c_hsotg_irq_enumdone(hsotg); } - if (gintsts & S3C_GINTSTS_ConIDStsChng) { + if (gintsts & GINTSTS_ConIDStsChng) { dev_dbg(hsotg->dev, "ConIDStsChg (DSTS=0x%08x, GOTCTL=%08x)\n", - readl(hsotg->regs + S3C_DSTS), - readl(hsotg->regs + S3C_GOTGCTL)); + readl(hsotg->regs + DSTS), + readl(hsotg->regs + GOTGCTL)); - writel(S3C_GINTSTS_ConIDStsChng, hsotg->regs + S3C_GINTSTS); + writel(GINTSTS_ConIDStsChng, hsotg->regs + GINTSTS); } - if (gintsts & (S3C_GINTSTS_OEPInt | S3C_GINTSTS_IEPInt)) { - u32 daint = readl(hsotg->regs + S3C_DAINT); - u32 daint_out = daint >> S3C_DAINT_OutEP_SHIFT; - u32 daint_in = daint & ~(daint_out << S3C_DAINT_OutEP_SHIFT); + if (gintsts & (GINTSTS_OEPInt | GINTSTS_IEPInt)) { + u32 daint = readl(hsotg->regs + DAINT); + u32 daint_out = daint >> DAINT_OutEP_SHIFT; + u32 daint_in = daint & ~(daint_out << DAINT_OutEP_SHIFT); int ep; dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint); @@ -2159,102 +2443,116 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw) } } - if (gintsts & S3C_GINTSTS_USBRst) { + if (gintsts & GINTSTS_USBRst) { + + u32 usb_status = readl(hsotg->regs + GOTGCTL); + dev_info(hsotg->dev, "%s: USBRst\n", __func__); dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n", - readl(hsotg->regs + S3C_GNPTXSTS)); + readl(hsotg->regs + GNPTXSTS)); - writel(S3C_GINTSTS_USBRst, hsotg->regs + S3C_GINTSTS); + writel(GINTSTS_USBRst, hsotg->regs + GINTSTS); - kill_all_requests(hsotg, &hsotg->eps[0], -ECONNRESET, true); + if (usb_status & GOTGCTL_BSESVLD) { + if (time_after(jiffies, hsotg->last_rst + + msecs_to_jiffies(200))) { - /* it seems after a reset we can end up with a situation - * where the TXFIFO still has data in it... the docs - * suggest resetting all the fifos, so use the init_fifo - * code to relayout and flush the fifos. - */ + kill_all_requests(hsotg, &hsotg->eps[0], + -ECONNRESET, true); - s3c_hsotg_init_fifo(hsotg); - - s3c_hsotg_enqueue_setup(hsotg); + s3c_hsotg_core_init(hsotg); + hsotg->last_rst = jiffies; + } + } } /* check both FIFOs */ - if (gintsts & S3C_GINTSTS_NPTxFEmp) { + if (gintsts & GINTSTS_NPTxFEmp) { dev_dbg(hsotg->dev, "NPTxFEmp\n"); - /* Disable the interrupt to stop it happening again + /* + * Disable the interrupt to stop it happening again * unless one of these endpoint routines decides that - * it needs re-enabling */ + * it needs re-enabling + */ - s3c_hsotg_disable_gsint(hsotg, S3C_GINTSTS_NPTxFEmp); + s3c_hsotg_disable_gsint(hsotg, GINTSTS_NPTxFEmp); s3c_hsotg_irq_fifoempty(hsotg, false); } - if (gintsts & S3C_GINTSTS_PTxFEmp) { + if (gintsts & GINTSTS_PTxFEmp) { dev_dbg(hsotg->dev, "PTxFEmp\n"); - /* See note in S3C_GINTSTS_NPTxFEmp */ + /* See note in GINTSTS_NPTxFEmp */ - s3c_hsotg_disable_gsint(hsotg, S3C_GINTSTS_PTxFEmp); + s3c_hsotg_disable_gsint(hsotg, GINTSTS_PTxFEmp); s3c_hsotg_irq_fifoempty(hsotg, true); } - if (gintsts & S3C_GINTSTS_RxFLvl) { - /* note, since GINTSTS_RxFLvl doubles as FIFO-not-empty, + 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 - * set. */ + * set. + */ s3c_hsotg_handle_rx(hsotg); } - if (gintsts & S3C_GINTSTS_ModeMis) { + if (gintsts & GINTSTS_ModeMis) { dev_warn(hsotg->dev, "warning, mode mismatch triggered\n"); - writel(S3C_GINTSTS_ModeMis, hsotg->regs + S3C_GINTSTS); + writel(GINTSTS_ModeMis, hsotg->regs + GINTSTS); } - if (gintsts & S3C_GINTSTS_USBSusp) { - dev_info(hsotg->dev, "S3C_GINTSTS_USBSusp\n"); - writel(S3C_GINTSTS_USBSusp, hsotg->regs + S3C_GINTSTS); + if (gintsts & GINTSTS_USBSusp) { + dev_info(hsotg->dev, "GINTSTS_USBSusp\n"); + writel(GINTSTS_USBSusp, hsotg->regs + GINTSTS); call_gadget(hsotg, suspend); + s3c_hsotg_disconnect(hsotg); } - if (gintsts & S3C_GINTSTS_WkUpInt) { - dev_info(hsotg->dev, "S3C_GINTSTS_WkUpIn\n"); - writel(S3C_GINTSTS_WkUpInt, hsotg->regs + S3C_GINTSTS); + if (gintsts & GINTSTS_WkUpInt) { + dev_info(hsotg->dev, "GINTSTS_WkUpIn\n"); + writel(GINTSTS_WkUpInt, hsotg->regs + GINTSTS); call_gadget(hsotg, resume); } - if (gintsts & S3C_GINTSTS_ErlySusp) { - dev_dbg(hsotg->dev, "S3C_GINTSTS_ErlySusp\n"); - writel(S3C_GINTSTS_ErlySusp, hsotg->regs + S3C_GINTSTS); + if (gintsts & GINTSTS_ErlySusp) { + dev_dbg(hsotg->dev, "GINTSTS_ErlySusp\n"); + writel(GINTSTS_ErlySusp, hsotg->regs + GINTSTS); + + s3c_hsotg_disconnect(hsotg); } - /* these next two seem to crop-up occasionally causing the core + /* + * these next two seem to crop-up occasionally causing the core * to shutdown the USB transfer, so try clearing them and logging - * the occurrence. */ + * the occurrence. + */ - if (gintsts & S3C_GINTSTS_GOUTNakEff) { + if (gintsts & GINTSTS_GOUTNakEff) { dev_info(hsotg->dev, "GOUTNakEff triggered\n"); - writel(S3C_DCTL_CGOUTNak, hsotg->regs + S3C_DCTL); + writel(DCTL_CGOUTNak, hsotg->regs + DCTL); s3c_hsotg_dump(hsotg); } - if (gintsts & S3C_GINTSTS_GINNakEff) { + if (gintsts & GINTSTS_GINNakEff) { dev_info(hsotg->dev, "GINNakEff triggered\n"); - writel(S3C_DCTL_CGNPInNAK, hsotg->regs + S3C_DCTL); + writel(DCTL_CGNPInNAK, hsotg->regs + DCTL); s3c_hsotg_dump(hsotg); } - /* if we've had fifo events, we should try and go around the - * loop again to see if there's any point in returning yet. */ + /* + * if we've had fifo events, we should try and go around the + * loop again to see if there's any point in returning yet. + */ if (gintsts & IRQ_RETRY_MASK && --retry_count > 0) goto irq_retry; @@ -2268,7 +2566,7 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw) * @desc: The USB endpoint descriptor to configure with. * * This is called from the USB gadget code's usb_ep_enable(). -*/ + */ static int s3c_hsotg_ep_enable(struct usb_ep *ep, const struct usb_endpoint_descriptor *desc) { @@ -2300,7 +2598,7 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep, /* note, we handle this here instead of s3c_hsotg_set_ep_maxpacket */ - epctrl_reg = dir_in ? S3C_DIEPCTL(index) : S3C_DOEPCTL(index); + epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); epctrl = readl(hsotg->regs + epctrl_reg); dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n", @@ -2308,20 +2606,23 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep, spin_lock_irqsave(&hs_ep->lock, flags); - epctrl &= ~(S3C_DxEPCTL_EPType_MASK | S3C_DxEPCTL_MPS_MASK); - epctrl |= S3C_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 |= S3C_DxEPCTL_USBActEp; + /* + * mark the endpoint as active, otherwise the core may ignore + * transactions entirely for this endpoint + */ + epctrl |= DxEPCTL_USBActEp; - /* set the NAK status on the endpoint, otherwise we might try and + /* + * set the NAK status on the endpoint, otherwise we might try and * do something with data that we've yet got a request to process * since the RXFIFO will take data for an endpoint even if the * size register hasn't been set. */ - epctrl |= S3C_DxEPCTL_SNAK; + epctrl |= DxEPCTL_SNAK; /* update the endpoint state */ hs_ep->ep.maxpacket = mps; @@ -2336,37 +2637,40 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep, goto out; case USB_ENDPOINT_XFER_BULK: - epctrl |= S3C_DxEPCTL_EPType_Bulk; + epctrl |= DxEPCTL_EPType_Bulk; break; case USB_ENDPOINT_XFER_INT: if (dir_in) { - /* Allocate our TxFNum by simply using the index + /* + * Allocate our TxFNum by simply using the index * of the endpoint for the moment. We could do * something better if the host indicates how - * many FIFOs we are expecting to use. */ + * many FIFOs we are expecting to use. + */ hs_ep->periodic = 1; - epctrl |= S3C_DxEPCTL_TxFNum(index); + epctrl |= DxEPCTL_TxFNum(index); } - epctrl |= S3C_DxEPCTL_EPType_Intterupt; + epctrl |= DxEPCTL_EPType_Intterupt; break; case USB_ENDPOINT_XFER_CONTROL: - epctrl |= S3C_DxEPCTL_EPType_Control; + epctrl |= DxEPCTL_EPType_Control; break; } - /* if the hardware has dedicated fifos, we must give each IN EP + /* + * if the hardware has dedicated fifos, we must give each IN EP * a unique tx-fifo even if it is non-periodic. */ if (dir_in && hsotg->dedicated_fifos) - epctrl |= S3C_DxEPCTL_TxFNum(index); + epctrl |= DxEPCTL_TxFNum(index); /* for non control endpoints, set PID to D0 */ if (index) - epctrl |= S3C_DxEPCTL_SetD0PID; + epctrl |= DxEPCTL_SetD0PID; dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n", __func__, epctrl); @@ -2383,6 +2687,10 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep, return ret; } +/** + * s3c_hsotg_ep_disable - disable given endpoint + * @ep: The endpoint to disable. + */ static int s3c_hsotg_ep_disable(struct usb_ep *ep) { struct s3c_hsotg_ep *hs_ep = our_ep(ep); @@ -2400,7 +2708,7 @@ static int s3c_hsotg_ep_disable(struct usb_ep *ep) return -EINVAL; } - epctrl_reg = dir_in ? S3C_DIEPCTL(index) : S3C_DOEPCTL(index); + epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); /* terminate all requests with shutdown */ kill_all_requests(hsotg, hs_ep, -ESHUTDOWN, false); @@ -2408,9 +2716,9 @@ static int s3c_hsotg_ep_disable(struct usb_ep *ep) spin_lock_irqsave(&hs_ep->lock, flags); ctrl = readl(hsotg->regs + epctrl_reg); - ctrl &= ~S3C_DxEPCTL_EPEna; - ctrl &= ~S3C_DxEPCTL_USBActEp; - ctrl |= S3C_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); @@ -2426,7 +2734,7 @@ static int s3c_hsotg_ep_disable(struct usb_ep *ep) * on_list - check request is on the given endpoint * @ep: The endpoint to check. * @test: The request to test if it is on the endpoint. -*/ + */ static bool on_list(struct s3c_hsotg_ep *ep, struct s3c_hsotg_req *test) { struct s3c_hsotg_req *req, *treq; @@ -2439,6 +2747,11 @@ static bool on_list(struct s3c_hsotg_ep *ep, struct s3c_hsotg_req *test) return false; } +/** + * s3c_hsotg_ep_dequeue - dequeue given endpoint + * @ep: The endpoint to dequeue. + * @req: The request to be removed from a queue. + */ static int s3c_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) { struct s3c_hsotg_req *hs_req = our_req(req); @@ -2461,6 +2774,11 @@ static int s3c_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) return 0; } +/** + * s3c_hsotg_ep_sethalt - set halt on a given endpoint + * @ep: The endpoint to set halt. + * @value: Set or unset the halt. + */ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value) { struct s3c_hsotg_ep *hs_ep = our_ep(ep); @@ -2477,34 +2795,34 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value) /* write both IN and OUT control registers */ - epreg = S3C_DIEPCTL(index); + epreg = DIEPCTL(index); epctl = readl(hs->regs + epreg); if (value) { - epctl |= S3C_DxEPCTL_Stall + S3C_DxEPCTL_SNAK; - if (epctl & S3C_DxEPCTL_EPEna) - epctl |= S3C_DxEPCTL_EPDis; + epctl |= DxEPCTL_Stall + DxEPCTL_SNAK; + if (epctl & DxEPCTL_EPEna) + epctl |= DxEPCTL_EPDis; } else { - epctl &= ~S3C_DxEPCTL_Stall; - xfertype = epctl & S3C_DxEPCTL_EPType_MASK; - if (xfertype == S3C_DxEPCTL_EPType_Bulk || - xfertype == S3C_DxEPCTL_EPType_Intterupt) - epctl |= S3C_DxEPCTL_SetD0PID; + epctl &= ~DxEPCTL_Stall; + xfertype = epctl & DxEPCTL_EPType_MASK; + if (xfertype == DxEPCTL_EPType_Bulk || + xfertype == DxEPCTL_EPType_Intterupt) + epctl |= DxEPCTL_SetD0PID; } writel(epctl, hs->regs + epreg); - epreg = S3C_DOEPCTL(index); + epreg = DOEPCTL(index); epctl = readl(hs->regs + epreg); if (value) - epctl |= S3C_DxEPCTL_Stall; + epctl |= DxEPCTL_Stall; else { - epctl &= ~S3C_DxEPCTL_Stall; - xfertype = epctl & S3C_DxEPCTL_EPType_MASK; - if (xfertype == S3C_DxEPCTL_EPType_Bulk || - xfertype == S3C_DxEPCTL_EPType_Intterupt) - epctl |= S3C_DxEPCTL_SetD0PID; + epctl &= ~DxEPCTL_Stall; + xfertype = epctl & DxEPCTL_EPType_MASK; + if (xfertype == DxEPCTL_EPType_Bulk || + xfertype == DxEPCTL_EPType_Intterupt) + epctl |= DxEPCTL_SetD0PID; } writel(epctl, hs->regs + epreg); @@ -2526,57 +2844,91 @@ static struct usb_ep_ops s3c_hsotg_ep_ops = { }; /** - * s3c_hsotg_corereset - issue softreset to the core - * @hsotg: The device state + * s3c_hsotg_phy_enable - enable platform phy dev + * @hsotg: The driver state * - * Issue a soft reset to the core, and await the core finishing it. -*/ -static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg) + * A wrapper for platform code responsible for controlling + * low-level USB code + */ +static void s3c_hsotg_phy_enable(struct s3c_hsotg *hsotg) { - int timeout; - u32 grstctl; + struct platform_device *pdev = to_platform_device(hsotg->dev); - dev_dbg(hsotg->dev, "resetting core\n"); + dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev); + if (hsotg->plat->phy_init) + hsotg->plat->phy_init(pdev, hsotg->plat->phy_type); +} - /* issue soft reset */ - writel(S3C_GRSTCTL_CSftRst, hsotg->regs + S3C_GRSTCTL); +/** + * s3c_hsotg_phy_disable - disable platform phy dev + * @hsotg: The driver state + * + * A wrapper for platform code responsible for controlling + * low-level USB code + */ +static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg) +{ + struct platform_device *pdev = to_platform_device(hsotg->dev); - timeout = 1000; - do { - grstctl = readl(hsotg->regs + S3C_GRSTCTL); - } while ((grstctl & S3C_GRSTCTL_CSftRst) && timeout-- > 0); + if (hsotg->plat->phy_exit) + hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type); +} - if (grstctl & S3C_GRSTCTL_CSftRst) { - dev_err(hsotg->dev, "Failed to get CSftRst asserted\n"); - return -EINVAL; - } +/** + * s3c_hsotg_init - initalize the usb core + * @hsotg: The driver state + */ +static void s3c_hsotg_init(struct s3c_hsotg *hsotg) +{ + /* unmask subset of endpoint interrupts */ - timeout = 1000; + writel(DIEPMSK_TimeOUTMsk | DIEPMSK_AHBErrMsk | + DIEPMSK_EPDisbldMsk | DIEPMSK_XferComplMsk, + hsotg->regs + DIEPMSK); - while (1) { - u32 grstctl = readl(hsotg->regs + S3C_GRSTCTL); + writel(DOEPMSK_SetupMsk | DOEPMSK_AHBErrMsk | + DOEPMSK_EPDisbldMsk | DOEPMSK_XferComplMsk, + hsotg->regs + DOEPMSK); - if (timeout-- < 0) { - dev_info(hsotg->dev, - "%s: reset failed, GRSTCTL=%08x\n", - __func__, grstctl); - return -ETIMEDOUT; - } + writel(0, hsotg->regs + DAINTMSK); - if (!(grstctl & S3C_GRSTCTL_AHBIdle)) - continue; + /* Be in disconnected state until gadget is registered */ + __orr32(hsotg->regs + DCTL, DCTL_SftDiscon); - break; /* reset done */ + if (0) { + /* post global nak until we're ready */ + writel(DCTL_SGNPInNAK | DCTL_SGOUTNak, + hsotg->regs + DCTL); } - dev_dbg(hsotg->dev, "reset successful\n"); - return 0; + /* setup fifos */ + + dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", + readl(hsotg->regs + GRXFSIZ), + readl(hsotg->regs + GNPTXFSIZ)); + + 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), + hsotg->regs + GUSBCFG); + + writel(using_dma(hsotg) ? GAHBCFG_DMAEn : 0x0, + hsotg->regs + GAHBCFG); } -static int s3c_hsotg_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) +/** + * s3c_hsotg_udc_start - prepare the udc for work + * @gadget: The usb gadget state + * @driver: The usb gadget driver + * + * Perform initialization to prepare udc device and driver + * to work. + */ +static int s3c_hsotg_udc_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { - struct s3c_hsotg *hsotg = our_hsotg; + struct s3c_hsotg *hsotg = to_hsotg(gadget); int ret; if (!hsotg) { @@ -2592,7 +2944,7 @@ static int s3c_hsotg_start(struct usb_gadget_driver *driver, if (driver->max_speed < USB_SPEED_FULL) dev_err(hsotg->dev, "%s: bad speed\n", __func__); - if (!bind || !driver->setup) { + if (!driver->setup) { dev_err(hsotg->dev, "%s: missing entry points\n", __func__); return -EINVAL; } @@ -2605,135 +2957,17 @@ static int s3c_hsotg_start(struct usb_gadget_driver *driver, hsotg->gadget.dev.dma_mask = hsotg->dev->dma_mask; hsotg->gadget.speed = USB_SPEED_UNKNOWN; - ret = device_add(&hsotg->gadget.dev); + ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies), + hsotg->supplies); if (ret) { - dev_err(hsotg->dev, "failed to register gadget device\n"); + dev_err(hsotg->dev, "failed to enable supplies: %d\n", ret); goto err; } - ret = bind(&hsotg->gadget); - if (ret) { - dev_err(hsotg->dev, "failed bind %s\n", driver->driver.name); - - hsotg->gadget.dev.driver = NULL; - hsotg->driver = NULL; - goto err; - } - - /* we must now enable ep0 ready for host detection and then - * set configuration. */ - - s3c_hsotg_corereset(hsotg); - - /* set the PLL on, remove the HNP/SRP and set the PHY */ - writel(S3C_GUSBCFG_PHYIf16 | S3C_GUSBCFG_TOutCal(7) | - (0x5 << 10), hsotg->regs + S3C_GUSBCFG); - - /* looks like soft-reset changes state of FIFOs */ - s3c_hsotg_init_fifo(hsotg); - - __orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon); - - writel(1 << 18 | S3C_DCFG_DevSpd_HS, hsotg->regs + S3C_DCFG); - - /* Clear any pending OTG interrupts */ - writel(0xffffffff, hsotg->regs + S3C_GOTGINT); - - /* Clear any pending interrupts */ - writel(0xffffffff, hsotg->regs + S3C_GINTSTS); - - writel(S3C_GINTSTS_DisconnInt | S3C_GINTSTS_SessReqInt | - S3C_GINTSTS_ConIDStsChng | S3C_GINTSTS_USBRst | - S3C_GINTSTS_EnumDone | S3C_GINTSTS_OTGInt | - S3C_GINTSTS_USBSusp | S3C_GINTSTS_WkUpInt | - S3C_GINTSTS_GOUTNakEff | S3C_GINTSTS_GINNakEff | - S3C_GINTSTS_ErlySusp, - hsotg->regs + S3C_GINTMSK); - - if (using_dma(hsotg)) - writel(S3C_GAHBCFG_GlblIntrEn | S3C_GAHBCFG_DMAEn | - S3C_GAHBCFG_HBstLen_Incr4, - hsotg->regs + S3C_GAHBCFG); - else - writel(S3C_GAHBCFG_GlblIntrEn, hsotg->regs + S3C_GAHBCFG); - - /* Enabling INTknTXFEmpMsk here seems to be a big mistake, we end - * up being flooded with interrupts if the host is polling the - * endpoint to try and read data. */ - - writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk | - S3C_DIEPMSK_INTknEPMisMsk | - S3C_DIEPMSK_EPDisbldMsk | S3C_DIEPMSK_XferComplMsk | - ((hsotg->dedicated_fifos) ? S3C_DIEPMSK_TxFIFOEmpty : 0), - hsotg->regs + S3C_DIEPMSK); - - /* don't need XferCompl, we get that from RXFIFO in slave mode. In - * DMA mode we may need this. */ - writel(S3C_DOEPMSK_SetupMsk | S3C_DOEPMSK_AHBErrMsk | - S3C_DOEPMSK_EPDisbldMsk | - (using_dma(hsotg) ? (S3C_DIEPMSK_XferComplMsk | - S3C_DIEPMSK_TimeOUTMsk) : 0), - hsotg->regs + S3C_DOEPMSK); - - writel(0, hsotg->regs + S3C_DAINTMSK); - - dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", - readl(hsotg->regs + S3C_DIEPCTL0), - readl(hsotg->regs + S3C_DOEPCTL0)); - - /* enable in and out endpoint interrupts */ - s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_OEPInt | S3C_GINTSTS_IEPInt); - - /* Enable the RXFIFO when in slave mode, as this is how we collect - * the data. In DMA mode, we get events from the FIFO but also - * things we cannot process, so do not use it. */ - if (!using_dma(hsotg)) - s3c_hsotg_en_gsint(hsotg, S3C_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 + S3C_DCTL, S3C_DCTL_PWROnPrgDone); - udelay(10); /* see openiboot */ - __bic32(hsotg->regs + S3C_DCTL, S3C_DCTL_PWROnPrgDone); - - dev_dbg(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + S3C_DCTL)); - - /* S3C_DxEPCTL_USBActEp says RO in manual, but seems to be set by - writing to the EPCTL register.. */ - - /* set to read 1 8byte packet */ - writel(S3C_DxEPTSIZ_MC(1) | S3C_DxEPTSIZ_PktCnt(1) | - S3C_DxEPTSIZ_XferSize(8), hsotg->regs + DOEPTSIZ0); - - writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) | - S3C_DxEPCTL_CNAK | S3C_DxEPCTL_EPEna | - S3C_DxEPCTL_USBActEp, - hsotg->regs + S3C_DOEPCTL0); - - /* enable, but don't activate EP0in */ - writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) | - S3C_DxEPCTL_USBActEp, hsotg->regs + S3C_DIEPCTL0); - - s3c_hsotg_enqueue_setup(hsotg); - - dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", - readl(hsotg->regs + S3C_DIEPCTL0), - readl(hsotg->regs + S3C_DOEPCTL0)); - - /* clear global NAKs */ - writel(S3C_DCTL_CGOUTNak | S3C_DCTL_CGNPInNAK, - hsotg->regs + S3C_DCTL); - - /* must be at-least 3ms to allow bus to see disconnect */ - msleep(3); - - /* remove the soft-disconnect and let's go */ - __bic32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon); - - /* report to the user, and return */ + s3c_hsotg_phy_enable(hsotg); + s3c_hsotg_core_init(hsotg); + hsotg->last_rst = jiffies; dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); return 0; @@ -2743,9 +2977,17 @@ static int s3c_hsotg_start(struct usb_gadget_driver *driver, return ret; } -static int s3c_hsotg_stop(struct usb_gadget_driver *driver) +/** + * s3c_hsotg_udc_stop - stop the udc + * @gadget: The usb gadget state + * @driver: The usb gadget driver + * + * Stop udc hw block and stay tunned for future transmissions + */ +static int s3c_hsotg_udc_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { - struct s3c_hsotg *hsotg = our_hsotg; + struct s3c_hsotg *hsotg = to_hsotg(gadget); int ep; if (!hsotg) @@ -2755,16 +2997,15 @@ static int s3c_hsotg_stop(struct usb_gadget_driver *driver) return -EINVAL; /* all endpoints should be shutdown */ - for (ep = 0; ep < S3C_HSOTG_EPS; ep++) + for (ep = 0; ep < hsotg->num_of_eps; ep++) s3c_hsotg_ep_disable(&hsotg->eps[ep].ep); - call_gadget(hsotg, disconnect); + s3c_hsotg_phy_disable(hsotg); + regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); - driver->unbind(&hsotg->gadget); hsotg->driver = NULL; hsotg->gadget.speed = USB_SPEED_UNKNOWN; - - device_del(&hsotg->gadget.dev); + hsotg->gadget.dev.driver = NULL; dev_info(hsotg->dev, "unregistered gadget driver '%s'\n", driver->driver.name); @@ -2772,6 +3013,12 @@ static int s3c_hsotg_stop(struct usb_gadget_driver *driver) return 0; } +/** + * s3c_hsotg_gadget_getframe - read the frame number + * @gadget: The usb gadget state + * + * Read the {micro} frame number + */ static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget) { return s3c_hsotg_read_frameno(to_hsotg(gadget)); @@ -2779,8 +3026,8 @@ static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget) static struct usb_gadget_ops s3c_hsotg_gadget_ops = { .get_frame = s3c_hsotg_gadget_getframe, - .start = s3c_hsotg_start, - .stop = s3c_hsotg_stop, + .udc_start = s3c_hsotg_udc_start, + .udc_stop = s3c_hsotg_udc_stop, }; /** @@ -2827,111 +3074,42 @@ static void __devinit s3c_hsotg_initep(struct s3c_hsotg *hsotg, hs_ep->ep.maxpacket = epnum ? 512 : EP0_MPS_LIMIT; hs_ep->ep.ops = &s3c_hsotg_ep_ops; - /* Read the FIFO size for the Periodic TX FIFO, even if we're + /* + * Read the FIFO size for the Periodic TX FIFO, even if we're * an OUT endpoint, we may as well do this if in future the * code is changed to make each endpoint's direction changeable. */ - ptxfifo = readl(hsotg->regs + S3C_DPTXFSIZn(epnum)); - hs_ep->fifo_size = S3C_DPTXFSIZn_DPTxFSize_GET(ptxfifo) * 4; + ptxfifo = readl(hsotg->regs + DPTXFSIZn(epnum)); + hs_ep->fifo_size = DPTXFSIZn_DPTxFSize_GET(ptxfifo) * 4; - /* if we're using dma, we need to set the next-endpoint pointer + /* + * if we're using dma, we need to set the next-endpoint pointer * to be something valid. */ if (using_dma(hsotg)) { - u32 next = S3C_DxEPCTL_NextEp((epnum + 1) % 15); - writel(next, hsotg->regs + S3C_DIEPCTL(epnum)); - writel(next, hsotg->regs + S3C_DOEPCTL(epnum)); + u32 next = DxEPCTL_NextEp((epnum + 1) % 15); + writel(next, hsotg->regs + DIEPCTL(epnum)); + writel(next, hsotg->regs + DOEPCTL(epnum)); } } /** - * s3c_hsotg_otgreset - reset the OtG phy block - * @hsotg: The host state. + * s3c_hsotg_hw_cfg - read HW configuration registers + * @param: The device state * - * Power up the phy, set the basic configuration and start the PHY. + * Read the USB core HW configuration registers */ -static void s3c_hsotg_otgreset(struct s3c_hsotg *hsotg) -{ - struct clk *xusbxti; - u32 pwr, osc; - - pwr = readl(S3C_PHYPWR); - pwr &= ~0x19; - writel(pwr, S3C_PHYPWR); - mdelay(1); - - osc = hsotg->plat->is_osc ? S3C_PHYCLK_EXT_OSC : 0; - - xusbxti = clk_get(hsotg->dev, "xusbxti"); - if (xusbxti && !IS_ERR(xusbxti)) { - switch (clk_get_rate(xusbxti)) { - case 12*MHZ: - osc |= S3C_PHYCLK_CLKSEL_12M; - break; - case 24*MHZ: - osc |= S3C_PHYCLK_CLKSEL_24M; - break; - default: - case 48*MHZ: - /* default reference clock */ - break; - } - clk_put(xusbxti); - } - - writel(osc | 0x10, S3C_PHYCLK); - - /* issue a full set of resets to the otg and core */ - - writel(S3C_RSTCON_PHY, S3C_RSTCON); - udelay(20); /* at-least 10uS */ - writel(0, S3C_RSTCON); -} - - -static void s3c_hsotg_init(struct s3c_hsotg *hsotg) +static void s3c_hsotg_hw_cfg(struct s3c_hsotg *hsotg) { - u32 cfg4; - - /* unmask subset of endpoint interrupts */ - - writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk | - S3C_DIEPMSK_EPDisbldMsk | S3C_DIEPMSK_XferComplMsk, - hsotg->regs + S3C_DIEPMSK); - - writel(S3C_DOEPMSK_SetupMsk | S3C_DOEPMSK_AHBErrMsk | - S3C_DOEPMSK_EPDisbldMsk | S3C_DOEPMSK_XferComplMsk, - hsotg->regs + S3C_DOEPMSK); - - writel(0, hsotg->regs + S3C_DAINTMSK); - - /* Be in disconnected state until gadget is registered */ - __orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon); - - if (0) { - /* post global nak until we're ready */ - writel(S3C_DCTL_SGNPInNAK | S3C_DCTL_SGOUTNak, - hsotg->regs + S3C_DCTL); - } - - /* setup fifos */ - - dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", - readl(hsotg->regs + S3C_GRXFSIZ), - readl(hsotg->regs + S3C_GNPTXFSIZ)); - - s3c_hsotg_init_fifo(hsotg); - - /* set the PLL on, remove the HNP/SRP and set the PHY */ - writel(S3C_GUSBCFG_PHYIf16 | S3C_GUSBCFG_TOutCal(7) | (0x5 << 10), - hsotg->regs + S3C_GUSBCFG); + u32 cfg2, cfg4; + /* check hardware configuration */ - writel(using_dma(hsotg) ? S3C_GAHBCFG_DMAEn : 0x0, - hsotg->regs + S3C_GAHBCFG); + cfg2 = readl(hsotg->regs + 0x48); + hsotg->num_of_eps = (cfg2 >> 10) & 0xF; - /* check hardware configuration */ + dev_info(hsotg->dev, "EPs:%d\n", hsotg->num_of_eps); cfg4 = readl(hsotg->regs + 0x50); hsotg->dedicated_fifos = (cfg4 >> 25) & 1; @@ -2940,6 +3118,10 @@ static void s3c_hsotg_init(struct s3c_hsotg *hsotg) hsotg->dedicated_fifos ? "dedicated" : "shared"); } +/** + * s3c_hsotg_dump - dump state of the udc + * @param: The device state + */ static void s3c_hsotg_dump(struct s3c_hsotg *hsotg) { #ifdef DEBUG @@ -2949,46 +3131,45 @@ static void s3c_hsotg_dump(struct s3c_hsotg *hsotg) int idx; dev_info(dev, "DCFG=0x%08x, DCTL=0x%08x, DIEPMSK=%08x\n", - readl(regs + S3C_DCFG), readl(regs + S3C_DCTL), - readl(regs + S3C_DIEPMSK)); + readl(regs + DCFG), readl(regs + DCTL), + readl(regs + DIEPMSK)); dev_info(dev, "GAHBCFG=0x%08x, 0x44=0x%08x\n", - readl(regs + S3C_GAHBCFG), readl(regs + 0x44)); + readl(regs + GAHBCFG), readl(regs + 0x44)); dev_info(dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", - readl(regs + S3C_GRXFSIZ), readl(regs + S3C_GNPTXFSIZ)); + readl(regs + GRXFSIZ), readl(regs + GNPTXFSIZ)); /* show periodic fifo settings */ for (idx = 1; idx <= 15; idx++) { - val = readl(regs + S3C_DPTXFSIZn(idx)); + val = readl(regs + DPTXFSIZn(idx)); dev_info(dev, "DPTx[%d] FSize=%d, StAddr=0x%08x\n", idx, - val >> S3C_DPTXFSIZn_DPTxFSize_SHIFT, - val & S3C_DPTXFSIZn_DPTxFStAddr_MASK); + val >> DPTXFSIZn_DPTxFSize_SHIFT, + val & DPTXFSIZn_DPTxFStAddr_MASK); } for (idx = 0; idx < 15; idx++) { dev_info(dev, "ep%d-in: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", idx, - readl(regs + S3C_DIEPCTL(idx)), - readl(regs + S3C_DIEPTSIZ(idx)), - readl(regs + S3C_DIEPDMA(idx))); + readl(regs + DIEPCTL(idx)), + readl(regs + DIEPTSIZ(idx)), + readl(regs + DIEPDMA(idx))); - val = readl(regs + S3C_DOEPCTL(idx)); + val = readl(regs + DOEPCTL(idx)); dev_info(dev, "ep%d-out: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", - idx, readl(regs + S3C_DOEPCTL(idx)), - readl(regs + S3C_DOEPTSIZ(idx)), - readl(regs + S3C_DOEPDMA(idx))); + idx, readl(regs + DOEPCTL(idx)), + readl(regs + DOEPTSIZ(idx)), + readl(regs + DOEPDMA(idx))); } dev_info(dev, "DVBUSDIS=0x%08x, DVBUSPULSE=%08x\n", - readl(regs + S3C_DVBUSDIS), readl(regs + S3C_DVBUSPULSE)); + readl(regs + DVBUSDIS), readl(regs + DVBUSPULSE)); #endif } - /** * state_show - debugfs: show overall driver and device state. * @seq: The seq file to write to. @@ -3005,38 +3186,38 @@ static int state_show(struct seq_file *seq, void *v) int idx; seq_printf(seq, "DCFG=0x%08x, DCTL=0x%08x, DSTS=0x%08x\n", - readl(regs + S3C_DCFG), - readl(regs + S3C_DCTL), - readl(regs + S3C_DSTS)); + readl(regs + DCFG), + readl(regs + DCTL), + readl(regs + DSTS)); seq_printf(seq, "DIEPMSK=0x%08x, DOEPMASK=0x%08x\n", - readl(regs + S3C_DIEPMSK), readl(regs + S3C_DOEPMSK)); + readl(regs + DIEPMSK), readl(regs + DOEPMSK)); seq_printf(seq, "GINTMSK=0x%08x, GINTSTS=0x%08x\n", - readl(regs + S3C_GINTMSK), - readl(regs + S3C_GINTSTS)); + readl(regs + GINTMSK), + readl(regs + GINTSTS)); seq_printf(seq, "DAINTMSK=0x%08x, DAINT=0x%08x\n", - readl(regs + S3C_DAINTMSK), - readl(regs + S3C_DAINT)); + readl(regs + DAINTMSK), + readl(regs + DAINT)); seq_printf(seq, "GNPTXSTS=0x%08x, GRXSTSR=%08x\n", - readl(regs + S3C_GNPTXSTS), - readl(regs + S3C_GRXSTSR)); + readl(regs + GNPTXSTS), + readl(regs + GRXSTSR)); seq_printf(seq, "\nEndpoint status:\n"); for (idx = 0; idx < 15; idx++) { u32 in, out; - in = readl(regs + S3C_DIEPCTL(idx)); - out = readl(regs + S3C_DOEPCTL(idx)); + in = readl(regs + DIEPCTL(idx)); + out = readl(regs + DOEPCTL(idx)); seq_printf(seq, "ep%d: DIEPCTL=0x%08x, DOEPCTL=0x%08x", idx, in, out); - in = readl(regs + S3C_DIEPTSIZ(idx)); - out = readl(regs + S3C_DOEPTSIZ(idx)); + in = readl(regs + DIEPTSIZ(idx)); + out = readl(regs + DOEPTSIZ(idx)); seq_printf(seq, ", DIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x", in, out); @@ -3067,7 +3248,7 @@ static const struct file_operations state_fops = { * * Show the FIFO information for the overall fifo and all the * periodic transmission FIFOs. -*/ + */ static int fifo_show(struct seq_file *seq, void *v) { struct s3c_hsotg *hsotg = seq->private; @@ -3076,21 +3257,21 @@ static int fifo_show(struct seq_file *seq, void *v) int idx; seq_printf(seq, "Non-periodic FIFOs:\n"); - seq_printf(seq, "RXFIFO: Size %d\n", readl(regs + S3C_GRXFSIZ)); + seq_printf(seq, "RXFIFO: Size %d\n", readl(regs + GRXFSIZ)); - val = readl(regs + S3C_GNPTXFSIZ); + val = readl(regs + GNPTXFSIZ); seq_printf(seq, "NPTXFIFO: Size %d, Start 0x%08x\n", - val >> S3C_GNPTXFSIZ_NPTxFDep_SHIFT, - val & S3C_GNPTXFSIZ_NPTxFStAddr_MASK); + val >> GNPTXFSIZ_NPTxFDep_SHIFT, + val & GNPTXFSIZ_NPTxFStAddr_MASK); seq_printf(seq, "\nPeriodic TXFIFOs:\n"); for (idx = 1; idx <= 15; idx++) { - val = readl(regs + S3C_DPTXFSIZn(idx)); + val = readl(regs + DPTXFSIZn(idx)); seq_printf(seq, "\tDPTXFIFO%2d: Size %d, Start 0x%08x\n", idx, - val >> S3C_DPTXFSIZn_DPTxFSize_SHIFT, - val & S3C_DPTXFSIZn_DPTxFStAddr_MASK); + val >> DPTXFSIZn_DPTxFSize_SHIFT, + val & DPTXFSIZn_DPTxFStAddr_MASK); } return 0; @@ -3122,7 +3303,7 @@ static const char *decode_direction(int is_in) * * This debugfs entry shows the state of the given endpoint (one is * registered for each available). -*/ + */ static int ep_show(struct seq_file *seq, void *v) { struct s3c_hsotg_ep *ep = seq->private; @@ -3139,20 +3320,20 @@ static int ep_show(struct seq_file *seq, void *v) /* first show the register state */ seq_printf(seq, "\tDIEPCTL=0x%08x, DOEPCTL=0x%08x\n", - readl(regs + S3C_DIEPCTL(index)), - readl(regs + S3C_DOEPCTL(index))); + readl(regs + DIEPCTL(index)), + readl(regs + DOEPCTL(index))); seq_printf(seq, "\tDIEPDMA=0x%08x, DOEPDMA=0x%08x\n", - readl(regs + S3C_DIEPDMA(index)), - readl(regs + S3C_DOEPDMA(index))); + readl(regs + DIEPDMA(index)), + readl(regs + DOEPDMA(index))); seq_printf(seq, "\tDIEPINT=0x%08x, DOEPINT=0x%08x\n", - readl(regs + S3C_DIEPINT(index)), - readl(regs + S3C_DOEPINT(index))); + readl(regs + DIEPINT(index)), + readl(regs + DOEPINT(index))); seq_printf(seq, "\tDIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x\n", - readl(regs + S3C_DIEPTSIZ(index)), - readl(regs + S3C_DOEPTSIZ(index))); + readl(regs + DIEPTSIZ(index)), + readl(regs + DOEPTSIZ(index))); seq_printf(seq, "\n"); seq_printf(seq, "mps %d\n", ep->ep.maxpacket); @@ -3202,7 +3383,7 @@ static const struct file_operations ep_fops = { * about the state of the system. The directory name is created * with the same name as the device itself, in case we end up * with multiple blocks in future systems. -*/ + */ static void __devinit s3c_hsotg_create_debug(struct s3c_hsotg *hsotg) { struct dentry *root; @@ -3231,7 +3412,7 @@ static void __devinit s3c_hsotg_create_debug(struct s3c_hsotg *hsotg) /* create one file for each endpoint */ - for (epidx = 0; epidx < S3C_HSOTG_EPS; epidx++) { + for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) { struct s3c_hsotg_ep *ep = &hsotg->eps[epidx]; ep->debugfs = debugfs_create_file(ep->name, 0444, @@ -3248,12 +3429,12 @@ static void __devinit s3c_hsotg_create_debug(struct s3c_hsotg *hsotg) * @hsotg: The driver state * * Cleanup (remove) the debugfs files for use on module exit. -*/ + */ static void __devexit s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg) { unsigned epidx; - for (epidx = 0; epidx < S3C_HSOTG_EPS; epidx++) { + for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) { struct s3c_hsotg_ep *ep = &hsotg->eps[epidx]; debugfs_remove(ep->debugfs); } @@ -3264,48 +3445,39 @@ static void __devexit s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg) } /** - * s3c_hsotg_gate - set the hardware gate for the block - * @pdev: The device we bound to - * @on: On or off. - * - * Set the hardware gate setting into the block. If we end up on - * something other than an S3C64XX, then we might need to change this - * to using a platform data callback, or some other mechanism. + * s3c_hsotg_release - release callback for hsotg device + * @dev: Device to for which release is called */ -static void s3c_hsotg_gate(struct platform_device *pdev, bool on) +static void s3c_hsotg_release(struct device *dev) { - unsigned long flags; - u32 others; - - local_irq_save(flags); - - others = __raw_readl(S3C64XX_OTHERS); - if (on) - others |= S3C64XX_OTHERS_USBMASK; - else - others &= ~S3C64XX_OTHERS_USBMASK; - __raw_writel(others, S3C64XX_OTHERS); + struct s3c_hsotg *hsotg = dev_get_drvdata(dev); - local_irq_restore(flags); + kfree(hsotg); } -static struct s3c_hsotg_plat s3c_hsotg_default_pdata; +/** + * s3c_hsotg_probe - probe function for hsotg driver + * @pdev: The platform information for the driver + */ static int __devinit s3c_hsotg_probe(struct platform_device *pdev) { struct s3c_hsotg_plat *plat = pdev->dev.platform_data; struct device *dev = &pdev->dev; + struct s3c_hsotg_ep *eps; struct s3c_hsotg *hsotg; struct resource *res; int epnum; int ret; + int i; - if (!plat) - plat = &s3c_hsotg_default_pdata; + plat = pdev->dev.platform_data; + if (!plat) { + dev_err(&pdev->dev, "no platform data defined\n"); + return -EINVAL; + } - hsotg = kzalloc(sizeof(struct s3c_hsotg) + - sizeof(struct s3c_hsotg_ep) * S3C_HSOTG_EPS, - GFP_KERNEL); + hsotg = kzalloc(sizeof(struct s3c_hsotg), GFP_KERNEL); if (!hsotg) { dev_err(dev, "cannot get memory\n"); return -ENOMEM; @@ -3371,6 +3543,54 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev) hsotg->gadget.dev.parent = dev; hsotg->gadget.dev.dma_mask = dev->dma_mask; + hsotg->gadget.dev.release = s3c_hsotg_release; + + /* reset the system */ + + clk_prepare_enable(hsotg->clk); + + /* regulators */ + + for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++) + hsotg->supplies[i].supply = s3c_hsotg_supply_names[i]; + + ret = regulator_bulk_get(dev, ARRAY_SIZE(hsotg->supplies), + hsotg->supplies); + if (ret) { + dev_err(dev, "failed to request supplies: %d\n", ret); + goto err_irq; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies), + hsotg->supplies); + + if (ret) { + dev_err(hsotg->dev, "failed to enable supplies: %d\n", ret); + goto err_supplies; + } + + /* usb phy enable */ + s3c_hsotg_phy_enable(hsotg); + + s3c_hsotg_corereset(hsotg); + s3c_hsotg_init(hsotg); + s3c_hsotg_hw_cfg(hsotg); + + /* hsotg->num_of_eps holds number of EPs other than ep0 */ + + if (hsotg->num_of_eps == 0) { + dev_err(dev, "wrong number of EPs (zero)\n"); + goto err_supplies; + } + + eps = kcalloc(hsotg->num_of_eps + 1, sizeof(struct s3c_hsotg_ep), + GFP_KERNEL); + if (!eps) { + dev_err(dev, "cannot get memory\n"); + goto err_supplies; + } + + hsotg->eps = eps; /* setup endpoint information */ @@ -3383,39 +3603,47 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev) GFP_KERNEL); if (!hsotg->ctrl_req) { dev_err(dev, "failed to allocate ctrl req\n"); - goto err_regs; + goto err_ep_mem; } - /* reset the system */ + /* initialise the endpoints now the core has been initialised */ + for (epnum = 0; epnum < hsotg->num_of_eps; epnum++) + s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum); - clk_enable(hsotg->clk); + /* disable power and clock */ - s3c_hsotg_gate(pdev, true); + ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), + hsotg->supplies); + if (ret) { + dev_err(hsotg->dev, "failed to disable supplies: %d\n", ret); + goto err_ep_mem; + } - s3c_hsotg_otgreset(hsotg); - s3c_hsotg_corereset(hsotg); - s3c_hsotg_init(hsotg); + s3c_hsotg_phy_disable(hsotg); - /* initialise the endpoints now the core has been initialised */ - for (epnum = 0; epnum < S3C_HSOTG_EPS; epnum++) - s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum); + ret = device_add(&hsotg->gadget.dev); + if (ret) { + put_device(&hsotg->gadget.dev); + goto err_ep_mem; + } ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget); if (ret) - goto err_add_udc; + goto err_ep_mem; s3c_hsotg_create_debug(hsotg); s3c_hsotg_dump(hsotg); - our_hsotg = hsotg; return 0; -err_add_udc: - s3c_hsotg_gate(pdev, false); - clk_disable(hsotg->clk); - clk_put(hsotg->clk); - +err_ep_mem: + kfree(eps); +err_supplies: + s3c_hsotg_phy_disable(hsotg); + regulator_bulk_free(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); +err_irq: + free_irq(hsotg->irq, hsotg); err_regs: iounmap(hsotg->regs); @@ -3423,12 +3651,17 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev) release_resource(hsotg->regs_res); kfree(hsotg->regs_res); err_clk: + clk_disable_unprepare(hsotg->clk); clk_put(hsotg->clk); err_mem: kfree(hsotg); return ret; } +/** + * s3c_hsotg_remove - remove function for hsotg driver + * @pdev: The platform information for the driver + */ static int __devexit s3c_hsotg_remove(struct platform_device *pdev) { struct s3c_hsotg *hsotg = platform_get_drvdata(pdev); @@ -3437,7 +3670,10 @@ static int __devexit s3c_hsotg_remove(struct platform_device *pdev) s3c_hsotg_delete_debug(hsotg); - usb_gadget_unregister_driver(hsotg->driver); + if (hsotg->driver) { + /* should have been done already by driver model core */ + usb_gadget_unregister_driver(hsotg->driver); + } free_irq(hsotg->irq, hsotg); iounmap(hsotg->regs); @@ -3445,12 +3681,13 @@ static int __devexit s3c_hsotg_remove(struct platform_device *pdev) release_resource(hsotg->regs_res); kfree(hsotg->regs_res); - s3c_hsotg_gate(pdev, false); + s3c_hsotg_phy_disable(hsotg); + regulator_bulk_free(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); - clk_disable(hsotg->clk); + clk_disable_unprepare(hsotg->clk); clk_put(hsotg->clk); - kfree(hsotg); + device_unregister(&hsotg->gadget.dev); return 0; } diff --git a/trunk/drivers/usb/gadget/s3c-hsotg.h b/trunk/drivers/usb/gadget/s3c-hsotg.h new file mode 100644 index 000000000000..d650b1295831 --- /dev/null +++ b/trunk/drivers/usb/gadget/s3c-hsotg.h @@ -0,0 +1,377 @@ +/* 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_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/trunk/drivers/usb/gadget/s3c-hsudc.c b/trunk/drivers/usb/gadget/s3c-hsudc.c index cef9b82ff911..36c6836eeb0f 100644 --- a/trunk/drivers/usb/gadget/s3c-hsudc.c +++ b/trunk/drivers/usb/gadget/s3c-hsudc.c @@ -110,7 +110,6 @@ struct s3c_hsudc_ep { struct usb_ep ep; char name[20]; struct s3c_hsudc *dev; - const struct usb_endpoint_descriptor *desc; struct list_head queue; u8 stopped; u8 wedge; @@ -761,7 +760,7 @@ static int s3c_hsudc_ep_enable(struct usb_ep *_ep, u32 ecr = 0; hsep = our_ep(_ep); - if (!_ep || !desc || hsep->desc || _ep->name == ep0name + if (!_ep || !desc || hsep->ep.desc || _ep->name == ep0name || desc->bDescriptorType != USB_DT_ENDPOINT || hsep->bEndpointAddress != desc->bEndpointAddress || ep_maxpacket(hsep) < usb_endpoint_maxp(desc)) @@ -783,7 +782,7 @@ static int s3c_hsudc_ep_enable(struct usb_ep *_ep, writel(ecr, hsudc->regs + S3C_ECR); hsep->stopped = hsep->wedge = 0; - hsep->desc = desc; + hsep->ep.desc = desc; hsep->ep.maxpacket = usb_endpoint_maxp(desc); s3c_hsudc_set_halt(_ep, 0); @@ -806,7 +805,7 @@ static int s3c_hsudc_ep_disable(struct usb_ep *_ep) struct s3c_hsudc *hsudc = hsep->dev; unsigned long flags; - if (!_ep || !hsep->desc) + if (!_ep || !hsep->ep.desc) return -EINVAL; spin_lock_irqsave(&hsudc->lock, flags); @@ -816,7 +815,6 @@ static int s3c_hsudc_ep_disable(struct usb_ep *_ep) s3c_hsudc_nuke_ep(hsep, -ESHUTDOWN); - hsep->desc = 0; hsep->ep.desc = NULL; hsep->stopped = 1; @@ -1006,7 +1004,6 @@ static void s3c_hsudc_initep(struct s3c_hsudc *hsudc, hsep->ep.maxpacket = epnum ? 512 : 64; hsep->ep.ops = &s3c_hsudc_ep_ops; hsep->fifo = hsudc->regs + S3C_BR(epnum); - hsep->desc = 0; hsep->ep.desc = NULL; hsep->stopped = 0; hsep->wedge = 0; diff --git a/trunk/drivers/usb/gadget/s3c2410_udc.c b/trunk/drivers/usb/gadget/s3c2410_udc.c index 195524cde6c3..3de71d37d75e 100644 --- a/trunk/drivers/usb/gadget/s3c2410_udc.c +++ b/trunk/drivers/usb/gadget/s3c2410_udc.c @@ -1062,7 +1062,7 @@ static int s3c2410_udc_ep_enable(struct usb_ep *_ep, ep = to_s3c2410_ep(_ep); - if (!_ep || !desc || ep->desc + if (!_ep || !desc || ep->ep.desc || _ep->name == ep0name || desc->bDescriptorType != USB_DT_ENDPOINT) return -EINVAL; @@ -1075,7 +1075,7 @@ static int s3c2410_udc_ep_enable(struct usb_ep *_ep, local_irq_save (flags); _ep->maxpacket = max & 0x7ff; - ep->desc = desc; + ep->ep.desc = desc; ep->halted = 0; ep->bEndpointAddress = desc->bEndpointAddress; @@ -1136,7 +1136,7 @@ static int s3c2410_udc_ep_disable(struct usb_ep *_ep) unsigned long flags; u32 int_en_reg; - if (!_ep || !ep->desc) { + if (!_ep || !ep->ep.desc) { dprintk(DEBUG_NORMAL, "%s not enabled\n", _ep ? ep->ep.name : NULL); return -EINVAL; @@ -1146,7 +1146,6 @@ static int s3c2410_udc_ep_disable(struct usb_ep *_ep) dprintk(DEBUG_NORMAL, "ep_disable: %s\n", _ep->name); - ep->desc = NULL; ep->ep.desc = NULL; ep->halted = 1; @@ -1195,7 +1194,7 @@ s3c2410_udc_free_request(struct usb_ep *_ep, struct usb_request *_req) dprintk(DEBUG_VERBOSE, "%s(%p,%p)\n", __func__, _ep, _req); - if (!ep || !_req || (!ep->desc && _ep->name != ep0name)) + if (!ep || !_req || (!ep->ep.desc && _ep->name != ep0name)) return; WARN_ON (!list_empty (&req->queue)); @@ -1215,7 +1214,7 @@ static int s3c2410_udc_queue(struct usb_ep *_ep, struct usb_request *_req, int fifo_count = 0; unsigned long flags; - if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) { + if (unlikely(!_ep || (!ep->ep.desc && ep->ep.name != ep0name))) { dprintk(DEBUG_NORMAL, "%s: invalid args\n", __func__); return -EINVAL; } @@ -1363,7 +1362,7 @@ static int s3c2410_udc_set_halt(struct usb_ep *_ep, int value) unsigned long flags; u32 idx; - if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) { + if (unlikely(!_ep || (!ep->ep.desc && ep->ep.name != ep0name))) { dprintk(DEBUG_NORMAL, "%s: inval 2\n", __func__); return -EINVAL; } @@ -1629,7 +1628,6 @@ static void s3c2410_udc_reinit(struct s3c2410_udc *dev) list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list); ep->dev = dev; - ep->desc = NULL; ep->ep.desc = NULL; ep->halted = 0; INIT_LIST_HEAD (&ep->queue); diff --git a/trunk/drivers/usb/gadget/s3c2410_udc.h b/trunk/drivers/usb/gadget/s3c2410_udc.h index 1653bae08b80..3e80fd5c820f 100644 --- a/trunk/drivers/usb/gadget/s3c2410_udc.h +++ b/trunk/drivers/usb/gadget/s3c2410_udc.h @@ -19,7 +19,6 @@ struct s3c2410_ep { unsigned long last_io; /* jiffies timestamp */ struct usb_gadget *gadget; struct s3c2410_udc *dev; - const struct usb_endpoint_descriptor *desc; struct usb_ep ep; u8 num; diff --git a/trunk/drivers/usb/gadget/tcm_usb_gadget.c b/trunk/drivers/usb/gadget/tcm_usb_gadget.c new file mode 100644 index 000000000000..c46439c8dd74 --- /dev/null +++ b/trunk/drivers/usb/gadget/tcm_usb_gadget.c @@ -0,0 +1,2480 @@ +/* Target based USB-Gadget + * + * UAS protocol handling, target callbacks, configfs handling, + * BBB (USB Mass Storage Class Bulk-Only (BBB) and Transport protocol handling. + * + * Author: Sebastian Andrzej Siewior + * License: GPLv2 as published by FSF. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "usbstring.c" +#include "epautoconf.c" +#include "config.c" +#include "composite.c" + +#include "tcm_usb_gadget.h" + +static struct target_fabric_configfs *usbg_fabric_configfs; + +static inline struct f_uas *to_f_uas(struct usb_function *f) +{ + return container_of(f, struct f_uas, function); +} + +static void usbg_cmd_release(struct kref *); + +static inline void usbg_cleanup_cmd(struct usbg_cmd *cmd) +{ + kref_put(&cmd->ref, usbg_cmd_release); +} + +/* Start bot.c code */ + +static int bot_enqueue_cmd_cbw(struct f_uas *fu) +{ + int ret; + + if (fu->flags & USBG_BOT_CMD_PEND) + return 0; + + ret = usb_ep_queue(fu->ep_out, fu->cmd.req, GFP_ATOMIC); + if (!ret) + fu->flags |= USBG_BOT_CMD_PEND; + return ret; +} + +static void bot_status_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct usbg_cmd *cmd = req->context; + struct f_uas *fu = cmd->fu; + + usbg_cleanup_cmd(cmd); + if (req->status < 0) { + pr_err("ERR %s(%d)\n", __func__, __LINE__); + return; + } + + /* CSW completed, wait for next CBW */ + bot_enqueue_cmd_cbw(fu); +} + +static void bot_enqueue_sense_code(struct f_uas *fu, struct usbg_cmd *cmd) +{ + struct bulk_cs_wrap *csw = &fu->bot_status.csw; + int ret; + u8 *sense; + unsigned int csw_stat; + + csw_stat = cmd->csw_code; + + /* + * We can't send SENSE as a response. So we take ASC & ASCQ from our + * sense buffer and queue it and hope the host sends a REQUEST_SENSE + * command where it learns why we failed. + */ + sense = cmd->sense_iu.sense; + + csw->Tag = cmd->bot_tag; + csw->Status = csw_stat; + fu->bot_status.req->context = cmd; + ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_ATOMIC); + if (ret) + pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret); +} + +static void bot_err_compl(struct usb_ep *ep, struct usb_request *req) +{ + struct usbg_cmd *cmd = req->context; + struct f_uas *fu = cmd->fu; + + if (req->status < 0) + pr_err("ERR %s(%d)\n", __func__, __LINE__); + + if (cmd->data_len) { + if (cmd->data_len > ep->maxpacket) { + req->length = ep->maxpacket; + cmd->data_len -= ep->maxpacket; + } else { + req->length = cmd->data_len; + cmd->data_len = 0; + } + + usb_ep_queue(ep, req, GFP_ATOMIC); + return ; + } + bot_enqueue_sense_code(fu, cmd); +} + +static void bot_send_bad_status(struct usbg_cmd *cmd) +{ + struct f_uas *fu = cmd->fu; + struct bulk_cs_wrap *csw = &fu->bot_status.csw; + struct usb_request *req; + struct usb_ep *ep; + + csw->Residue = cpu_to_le32(cmd->data_len); + + if (cmd->data_len) { + if (cmd->is_read) { + ep = fu->ep_in; + req = fu->bot_req_in; + } else { + ep = fu->ep_out; + req = fu->bot_req_out; + } + + if (cmd->data_len > fu->ep_in->maxpacket) { + req->length = ep->maxpacket; + cmd->data_len -= ep->maxpacket; + } else { + req->length = cmd->data_len; + cmd->data_len = 0; + } + req->complete = bot_err_compl; + req->context = cmd; + req->buf = fu->cmd.buf; + usb_ep_queue(ep, req, GFP_KERNEL); + } else { + bot_enqueue_sense_code(fu, cmd); + } +} + +static int bot_send_status(struct usbg_cmd *cmd, bool moved_data) +{ + struct f_uas *fu = cmd->fu; + struct bulk_cs_wrap *csw = &fu->bot_status.csw; + int ret; + + if (cmd->se_cmd.scsi_status == SAM_STAT_GOOD) { + if (!moved_data && cmd->data_len) { + /* + * the host wants to move data, we don't. Fill / empty + * the pipe and then send the csw with reside set. + */ + cmd->csw_code = US_BULK_STAT_OK; + bot_send_bad_status(cmd); + return 0; + } + + csw->Tag = cmd->bot_tag; + csw->Residue = cpu_to_le32(0); + csw->Status = US_BULK_STAT_OK; + fu->bot_status.req->context = cmd; + + ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_KERNEL); + if (ret) + pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret); + } else { + cmd->csw_code = US_BULK_STAT_FAIL; + bot_send_bad_status(cmd); + } + return 0; +} + +/* + * Called after command (no data transfer) or after the write (to device) + * operation is completed + */ +static int bot_send_status_response(struct usbg_cmd *cmd) +{ + bool moved_data = false; + + if (!cmd->is_read) + moved_data = true; + return bot_send_status(cmd, moved_data); +} + +/* Read request completed, now we have to send the CSW */ +static void bot_read_compl(struct usb_ep *ep, struct usb_request *req) +{ + struct usbg_cmd *cmd = req->context; + + if (req->status < 0) + pr_err("ERR %s(%d)\n", __func__, __LINE__); + + bot_send_status(cmd, true); +} + +static int bot_send_read_response(struct usbg_cmd *cmd) +{ + struct f_uas *fu = cmd->fu; + struct se_cmd *se_cmd = &cmd->se_cmd; + struct usb_gadget *gadget = fuas_to_gadget(fu); + int ret; + + if (!cmd->data_len) { + cmd->csw_code = US_BULK_STAT_PHASE; + bot_send_bad_status(cmd); + return 0; + } + + if (!gadget->sg_supported) { + cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC); + if (!cmd->data_buf) + return -ENOMEM; + + sg_copy_to_buffer(se_cmd->t_data_sg, + se_cmd->t_data_nents, + cmd->data_buf, + se_cmd->data_length); + + fu->bot_req_in->buf = cmd->data_buf; + } else { + fu->bot_req_in->buf = NULL; + fu->bot_req_in->num_sgs = se_cmd->t_data_nents; + fu->bot_req_in->sg = se_cmd->t_data_sg; + } + + fu->bot_req_in->complete = bot_read_compl; + fu->bot_req_in->length = se_cmd->data_length; + fu->bot_req_in->context = cmd; + ret = usb_ep_queue(fu->ep_in, fu->bot_req_in, GFP_ATOMIC); + if (ret) + pr_err("%s(%d)\n", __func__, __LINE__); + return 0; +} + +static void usbg_data_write_cmpl(struct usb_ep *, struct usb_request *); +static int usbg_prepare_w_request(struct usbg_cmd *, struct usb_request *); + +static int bot_send_write_request(struct usbg_cmd *cmd) +{ + struct f_uas *fu = cmd->fu; + struct se_cmd *se_cmd = &cmd->se_cmd; + struct usb_gadget *gadget = fuas_to_gadget(fu); + int ret; + + init_completion(&cmd->write_complete); + cmd->fu = fu; + + if (!cmd->data_len) { + cmd->csw_code = US_BULK_STAT_PHASE; + return -EINVAL; + } + + if (!gadget->sg_supported) { + cmd->data_buf = kmalloc(se_cmd->data_length, GFP_KERNEL); + if (!cmd->data_buf) + return -ENOMEM; + + fu->bot_req_out->buf = cmd->data_buf; + } else { + fu->bot_req_out->buf = NULL; + fu->bot_req_out->num_sgs = se_cmd->t_data_nents; + fu->bot_req_out->sg = se_cmd->t_data_sg; + } + + fu->bot_req_out->complete = usbg_data_write_cmpl; + fu->bot_req_out->length = se_cmd->data_length; + fu->bot_req_out->context = cmd; + + ret = usbg_prepare_w_request(cmd, fu->bot_req_out); + if (ret) + goto cleanup; + ret = usb_ep_queue(fu->ep_out, fu->bot_req_out, GFP_KERNEL); + if (ret) + pr_err("%s(%d)\n", __func__, __LINE__); + + wait_for_completion(&cmd->write_complete); + transport_generic_process_write(se_cmd); +cleanup: + return ret; +} + +static int bot_submit_command(struct f_uas *, void *, unsigned int); + +static void bot_cmd_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct f_uas *fu = req->context; + int ret; + + fu->flags &= ~USBG_BOT_CMD_PEND; + + if (req->status < 0) + return; + + ret = bot_submit_command(fu, req->buf, req->actual); + if (ret) + pr_err("%s(%d): %d\n", __func__, __LINE__, ret); +} + +static int bot_prepare_reqs(struct f_uas *fu) +{ + int ret; + + fu->bot_req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL); + if (!fu->bot_req_in) + goto err; + + fu->bot_req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL); + if (!fu->bot_req_out) + goto err_out; + + fu->cmd.req = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL); + if (!fu->cmd.req) + goto err_cmd; + + fu->bot_status.req = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL); + if (!fu->bot_status.req) + goto err_sts; + + fu->bot_status.req->buf = &fu->bot_status.csw; + fu->bot_status.req->length = US_BULK_CS_WRAP_LEN; + fu->bot_status.req->complete = bot_status_complete; + fu->bot_status.csw.Signature = cpu_to_le32(US_BULK_CS_SIGN); + + fu->cmd.buf = kmalloc(fu->ep_out->maxpacket, GFP_KERNEL); + if (!fu->cmd.buf) + goto err_buf; + + fu->cmd.req->complete = bot_cmd_complete; + fu->cmd.req->buf = fu->cmd.buf; + fu->cmd.req->length = fu->ep_out->maxpacket; + fu->cmd.req->context = fu; + + ret = bot_enqueue_cmd_cbw(fu); + if (ret) + goto err_queue; + return 0; +err_queue: + kfree(fu->cmd.buf); + fu->cmd.buf = NULL; +err_buf: + usb_ep_free_request(fu->ep_in, fu->bot_status.req); +err_sts: + usb_ep_free_request(fu->ep_out, fu->cmd.req); + fu->cmd.req = NULL; +err_cmd: + usb_ep_free_request(fu->ep_out, fu->bot_req_out); + fu->bot_req_out = NULL; +err_out: + usb_ep_free_request(fu->ep_in, fu->bot_req_in); + fu->bot_req_in = NULL; +err: + pr_err("BOT: endpoint setup failed\n"); + return -ENOMEM; +} + +void bot_cleanup_old_alt(struct f_uas *fu) +{ + if (!(fu->flags & USBG_ENABLED)) + return; + + usb_ep_disable(fu->ep_in); + usb_ep_disable(fu->ep_out); + + if (!fu->bot_req_in) + return; + + usb_ep_free_request(fu->ep_in, fu->bot_req_in); + usb_ep_free_request(fu->ep_out, fu->bot_req_out); + usb_ep_free_request(fu->ep_out, fu->cmd.req); + usb_ep_free_request(fu->ep_out, fu->bot_status.req); + + kfree(fu->cmd.buf); + + fu->bot_req_in = NULL; + fu->bot_req_out = NULL; + fu->cmd.req = NULL; + fu->bot_status.req = NULL; + fu->cmd.buf = NULL; +} + +static void bot_set_alt(struct f_uas *fu) +{ + struct usb_function *f = &fu->function; + struct usb_gadget *gadget = f->config->cdev->gadget; + int ret; + + fu->flags = USBG_IS_BOT; + + config_ep_by_speed(gadget, f, fu->ep_in); + ret = usb_ep_enable(fu->ep_in); + if (ret) + goto err_b_in; + + config_ep_by_speed(gadget, f, fu->ep_out); + ret = usb_ep_enable(fu->ep_out); + if (ret) + goto err_b_out; + + ret = bot_prepare_reqs(fu); + if (ret) + goto err_wq; + fu->flags |= USBG_ENABLED; + pr_info("Using the BOT protocol\n"); + return; +err_wq: + usb_ep_disable(fu->ep_out); +err_b_out: + usb_ep_disable(fu->ep_in); +err_b_in: + fu->flags = USBG_IS_BOT; +} + +static int usbg_bot_setup(struct usb_function *f, + const struct usb_ctrlrequest *ctrl) +{ + struct f_uas *fu = to_f_uas(f); + struct usb_composite_dev *cdev = f->config->cdev; + u16 w_value = le16_to_cpu(ctrl->wValue); + u16 w_length = le16_to_cpu(ctrl->wLength); + int luns; + u8 *ret_lun; + + switch (ctrl->bRequest) { + case US_BULK_GET_MAX_LUN: + if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_CLASS | + USB_RECIP_INTERFACE)) + return -ENOTSUPP; + + if (w_length < 1) + return -EINVAL; + if (w_value != 0) + return -EINVAL; + luns = atomic_read(&fu->tpg->tpg_port_count); + if (!luns) { + pr_err("No LUNs configured?\n"); + return -EINVAL; + } + /* + * If 4 LUNs are present we return 3 i.e. LUN 0..3 can be + * accessed. The upper limit is 0xf + */ + luns--; + if (luns > 0xf) { + pr_info_once("Limiting the number of luns to 16\n"); + luns = 0xf; + } + ret_lun = cdev->req->buf; + *ret_lun = luns; + cdev->req->length = 1; + return usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC); + break; + + case US_BULK_RESET_REQUEST: + /* XXX maybe we should remove previous requests for IN + OUT */ + bot_enqueue_cmd_cbw(fu); + return 0; + break; + }; + return -ENOTSUPP; +} + +/* Start uas.c code */ + +static void uasp_cleanup_one_stream(struct f_uas *fu, struct uas_stream *stream) +{ + /* We have either all three allocated or none */ + if (!stream->req_in) + return; + + usb_ep_free_request(fu->ep_in, stream->req_in); + usb_ep_free_request(fu->ep_out, stream->req_out); + usb_ep_free_request(fu->ep_status, stream->req_status); + + stream->req_in = NULL; + stream->req_out = NULL; + stream->req_status = NULL; +} + +static void uasp_free_cmdreq(struct f_uas *fu) +{ + usb_ep_free_request(fu->ep_cmd, fu->cmd.req); + kfree(fu->cmd.buf); + fu->cmd.req = NULL; + fu->cmd.buf = NULL; +} + +static void uasp_cleanup_old_alt(struct f_uas *fu) +{ + int i; + + if (!(fu->flags & USBG_ENABLED)) + return; + + usb_ep_disable(fu->ep_in); + usb_ep_disable(fu->ep_out); + usb_ep_disable(fu->ep_status); + usb_ep_disable(fu->ep_cmd); + + for (i = 0; i < UASP_SS_EP_COMP_NUM_STREAMS; i++) + uasp_cleanup_one_stream(fu, &fu->stream[i]); + uasp_free_cmdreq(fu); +} + +static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req); + +static int uasp_prepare_r_request(struct usbg_cmd *cmd) +{ + struct se_cmd *se_cmd = &cmd->se_cmd; + struct f_uas *fu = cmd->fu; + struct usb_gadget *gadget = fuas_to_gadget(fu); + struct uas_stream *stream = cmd->stream; + + if (!gadget->sg_supported) { + cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC); + if (!cmd->data_buf) + return -ENOMEM; + + sg_copy_to_buffer(se_cmd->t_data_sg, + se_cmd->t_data_nents, + cmd->data_buf, + se_cmd->data_length); + + stream->req_in->buf = cmd->data_buf; + } else { + stream->req_in->buf = NULL; + stream->req_in->num_sgs = se_cmd->t_data_nents; + stream->req_in->sg = se_cmd->t_data_sg; + } + + stream->req_in->complete = uasp_status_data_cmpl; + stream->req_in->length = se_cmd->data_length; + stream->req_in->context = cmd; + + cmd->state = UASP_SEND_STATUS; + return 0; +} + +static void uasp_prepare_status(struct usbg_cmd *cmd) +{ + struct se_cmd *se_cmd = &cmd->se_cmd; + struct sense_iu *iu = &cmd->sense_iu; + struct uas_stream *stream = cmd->stream; + + cmd->state = UASP_QUEUE_COMMAND; + iu->iu_id = IU_ID_STATUS; + iu->tag = cpu_to_be16(cmd->tag); + + /* + * iu->status_qual = cpu_to_be16(STATUS QUALIFIER SAM-4. Where R U?); + */ + iu->len = cpu_to_be16(se_cmd->scsi_sense_length); + iu->status = se_cmd->scsi_status; + stream->req_status->context = cmd; + stream->req_status->length = se_cmd->scsi_sense_length + 16; + stream->req_status->buf = iu; + stream->req_status->complete = uasp_status_data_cmpl; +} + +static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req) +{ + struct usbg_cmd *cmd = req->context; + struct uas_stream *stream = cmd->stream; + struct f_uas *fu = cmd->fu; + int ret; + + if (req->status < 0) + goto cleanup; + + switch (cmd->state) { + case UASP_SEND_DATA: + ret = uasp_prepare_r_request(cmd); + if (ret) + goto cleanup; + ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC); + if (ret) + pr_err("%s(%d) => %d\n", __func__, __LINE__, ret); + break; + + case UASP_RECEIVE_DATA: + ret = usbg_prepare_w_request(cmd, stream->req_out); + if (ret) + goto cleanup; + ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC); + if (ret) + pr_err("%s(%d) => %d\n", __func__, __LINE__, ret); + break; + + case UASP_SEND_STATUS: + uasp_prepare_status(cmd); + ret = usb_ep_queue(fu->ep_status, stream->req_status, + GFP_ATOMIC); + if (ret) + pr_err("%s(%d) => %d\n", __func__, __LINE__, ret); + break; + + case UASP_QUEUE_COMMAND: + usbg_cleanup_cmd(cmd); + usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC); + break; + + default: + BUG(); + }; + return; + +cleanup: + usbg_cleanup_cmd(cmd); +} + +static int uasp_send_status_response(struct usbg_cmd *cmd) +{ + struct f_uas *fu = cmd->fu; + struct uas_stream *stream = cmd->stream; + struct sense_iu *iu = &cmd->sense_iu; + + iu->tag = cpu_to_be16(cmd->tag); + stream->req_status->complete = uasp_status_data_cmpl; + stream->req_status->context = cmd; + cmd->fu = fu; + uasp_prepare_status(cmd); + return usb_ep_queue(fu->ep_status, stream->req_status, GFP_ATOMIC); +} + +static int uasp_send_read_response(struct usbg_cmd *cmd) +{ + struct f_uas *fu = cmd->fu; + struct uas_stream *stream = cmd->stream; + struct sense_iu *iu = &cmd->sense_iu; + int ret; + + cmd->fu = fu; + + iu->tag = cpu_to_be16(cmd->tag); + if (fu->flags & USBG_USE_STREAMS) { + + ret = uasp_prepare_r_request(cmd); + if (ret) + goto out; + ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC); + if (ret) { + pr_err("%s(%d) => %d\n", __func__, __LINE__, ret); + kfree(cmd->data_buf); + cmd->data_buf = NULL; + } + + } else { + + iu->iu_id = IU_ID_READ_READY; + iu->tag = cpu_to_be16(cmd->tag); + + stream->req_status->complete = uasp_status_data_cmpl; + stream->req_status->context = cmd; + + cmd->state = UASP_SEND_DATA; + stream->req_status->buf = iu; + stream->req_status->length = sizeof(struct iu); + + ret = usb_ep_queue(fu->ep_status, stream->req_status, + GFP_ATOMIC); + if (ret) + pr_err("%s(%d) => %d\n", __func__, __LINE__, ret); + } +out: + return ret; +} + +static int uasp_send_write_request(struct usbg_cmd *cmd) +{ + struct f_uas *fu = cmd->fu; + struct se_cmd *se_cmd = &cmd->se_cmd; + struct uas_stream *stream = cmd->stream; + struct sense_iu *iu = &cmd->sense_iu; + int ret; + + init_completion(&cmd->write_complete); + cmd->fu = fu; + + iu->tag = cpu_to_be16(cmd->tag); + + if (fu->flags & USBG_USE_STREAMS) { + + ret = usbg_prepare_w_request(cmd, stream->req_out); + if (ret) + goto cleanup; + ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC); + if (ret) + pr_err("%s(%d)\n", __func__, __LINE__); + + } else { + + iu->iu_id = IU_ID_WRITE_READY; + iu->tag = cpu_to_be16(cmd->tag); + + stream->req_status->complete = uasp_status_data_cmpl; + stream->req_status->context = cmd; + + cmd->state = UASP_RECEIVE_DATA; + stream->req_status->buf = iu; + stream->req_status->length = sizeof(struct iu); + + ret = usb_ep_queue(fu->ep_status, stream->req_status, + GFP_ATOMIC); + if (ret) + pr_err("%s(%d)\n", __func__, __LINE__); + } + + wait_for_completion(&cmd->write_complete); + transport_generic_process_write(se_cmd); +cleanup: + return ret; +} + +static int usbg_submit_command(struct f_uas *, void *, unsigned int); + +static void uasp_cmd_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct f_uas *fu = req->context; + int ret; + + if (req->status < 0) + return; + + ret = usbg_submit_command(fu, req->buf, req->actual); + /* + * Once we tune for performance enqueue the command req here again so + * we can receive a second command while we processing this one. Pay + * attention to properly sync STAUS endpoint with DATA IN + OUT so you + * don't break HS. + */ + if (!ret) + return; + usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC); +} + +static int uasp_alloc_stream_res(struct f_uas *fu, struct uas_stream *stream) +{ + stream->req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL); + if (!stream->req_in) + goto out; + + stream->req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL); + if (!stream->req_out) + goto err_out; + + stream->req_status = usb_ep_alloc_request(fu->ep_status, GFP_KERNEL); + if (!stream->req_status) + goto err_sts; + + return 0; +err_sts: + usb_ep_free_request(fu->ep_status, stream->req_status); + stream->req_status = NULL; +err_out: + usb_ep_free_request(fu->ep_out, stream->req_out); + stream->req_out = NULL; +out: + return -ENOMEM; +} + +static int uasp_alloc_cmd(struct f_uas *fu) +{ + fu->cmd.req = usb_ep_alloc_request(fu->ep_cmd, GFP_KERNEL); + if (!fu->cmd.req) + goto err; + + fu->cmd.buf = kmalloc(fu->ep_cmd->maxpacket, GFP_KERNEL); + if (!fu->cmd.buf) + goto err_buf; + + fu->cmd.req->complete = uasp_cmd_complete; + fu->cmd.req->buf = fu->cmd.buf; + fu->cmd.req->length = fu->ep_cmd->maxpacket; + fu->cmd.req->context = fu; + return 0; + +err_buf: + usb_ep_free_request(fu->ep_cmd, fu->cmd.req); +err: + return -ENOMEM; +} + +static void uasp_setup_stream_res(struct f_uas *fu, int max_streams) +{ + int i; + + for (i = 0; i < max_streams; i++) { + struct uas_stream *s = &fu->stream[i]; + + s->req_in->stream_id = i + 1; + s->req_out->stream_id = i + 1; + s->req_status->stream_id = i + 1; + } +} + +static int uasp_prepare_reqs(struct f_uas *fu) +{ + int ret; + int i; + int max_streams; + + if (fu->flags & USBG_USE_STREAMS) + max_streams = UASP_SS_EP_COMP_NUM_STREAMS; + else + max_streams = 1; + + for (i = 0; i < max_streams; i++) { + ret = uasp_alloc_stream_res(fu, &fu->stream[i]); + if (ret) + goto err_cleanup; + } + + ret = uasp_alloc_cmd(fu); + if (ret) + goto err_free_stream; + uasp_setup_stream_res(fu, max_streams); + + ret = usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC); + if (ret) + goto err_free_stream; + + return 0; + +err_free_stream: + uasp_free_cmdreq(fu); + +err_cleanup: + if (i) { + do { + uasp_cleanup_one_stream(fu, &fu->stream[i - 1]); + i--; + } while (i); + } + pr_err("UASP: endpoint setup failed\n"); + return ret; +} + +static void uasp_set_alt(struct f_uas *fu) +{ + struct usb_function *f = &fu->function; + struct usb_gadget *gadget = f->config->cdev->gadget; + int ret; + + fu->flags = USBG_IS_UAS; + + if (gadget->speed == USB_SPEED_SUPER) + fu->flags |= USBG_USE_STREAMS; + + config_ep_by_speed(gadget, f, fu->ep_in); + ret = usb_ep_enable(fu->ep_in); + if (ret) + goto err_b_in; + + config_ep_by_speed(gadget, f, fu->ep_out); + ret = usb_ep_enable(fu->ep_out); + if (ret) + goto err_b_out; + + config_ep_by_speed(gadget, f, fu->ep_cmd); + ret = usb_ep_enable(fu->ep_cmd); + if (ret) + goto err_cmd; + config_ep_by_speed(gadget, f, fu->ep_status); + ret = usb_ep_enable(fu->ep_status); + if (ret) + goto err_status; + + ret = uasp_prepare_reqs(fu); + if (ret) + goto err_wq; + fu->flags |= USBG_ENABLED; + + pr_info("Using the UAS protocol\n"); + return; +err_wq: + usb_ep_disable(fu->ep_status); +err_status: + usb_ep_disable(fu->ep_cmd); +err_cmd: + usb_ep_disable(fu->ep_out); +err_b_out: + usb_ep_disable(fu->ep_in); +err_b_in: + fu->flags = 0; +} + +static int get_cmd_dir(const unsigned char *cdb) +{ + int ret; + + switch (cdb[0]) { + case READ_6: + case READ_10: + case READ_12: + case READ_16: + case INQUIRY: + case MODE_SENSE: + case MODE_SENSE_10: + case SERVICE_ACTION_IN: + case MAINTENANCE_IN: + case PERSISTENT_RESERVE_IN: + case SECURITY_PROTOCOL_IN: + case ACCESS_CONTROL_IN: + case REPORT_LUNS: + case READ_BLOCK_LIMITS: + case READ_POSITION: + case READ_CAPACITY: + case READ_TOC: + case READ_FORMAT_CAPACITIES: + case REQUEST_SENSE: + ret = DMA_FROM_DEVICE; + break; + + case WRITE_6: + case WRITE_10: + case WRITE_12: + case WRITE_16: + case MODE_SELECT: + case MODE_SELECT_10: + case WRITE_VERIFY: + case WRITE_VERIFY_12: + case PERSISTENT_RESERVE_OUT: + case MAINTENANCE_OUT: + case SECURITY_PROTOCOL_OUT: + case ACCESS_CONTROL_OUT: + ret = DMA_TO_DEVICE; + break; + case ALLOW_MEDIUM_REMOVAL: + case TEST_UNIT_READY: + case SYNCHRONIZE_CACHE: + case START_STOP: + case ERASE: + case REZERO_UNIT: + case SEEK_10: + case SPACE: + case VERIFY: + case WRITE_FILEMARKS: + ret = DMA_NONE; + break; + default: + pr_warn("target: Unknown data direction for SCSI Opcode " + "0x%02x\n", cdb[0]); + ret = -EINVAL; + } + return ret; +} + +static void usbg_data_write_cmpl(struct usb_ep *ep, struct usb_request *req) +{ + struct usbg_cmd *cmd = req->context; + struct se_cmd *se_cmd = &cmd->se_cmd; + + if (req->status < 0) { + pr_err("%s() state %d transfer failed\n", __func__, cmd->state); + goto cleanup; + } + + if (req->num_sgs == 0) { + sg_copy_from_buffer(se_cmd->t_data_sg, + se_cmd->t_data_nents, + cmd->data_buf, + se_cmd->data_length); + } + + complete(&cmd->write_complete); + return; + +cleanup: + usbg_cleanup_cmd(cmd); +} + +static int usbg_prepare_w_request(struct usbg_cmd *cmd, struct usb_request *req) +{ + struct se_cmd *se_cmd = &cmd->se_cmd; + struct f_uas *fu = cmd->fu; + struct usb_gadget *gadget = fuas_to_gadget(fu); + + if (!gadget->sg_supported) { + cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC); + if (!cmd->data_buf) + return -ENOMEM; + + req->buf = cmd->data_buf; + } else { + req->buf = NULL; + req->num_sgs = se_cmd->t_data_nents; + req->sg = se_cmd->t_data_sg; + } + + req->complete = usbg_data_write_cmpl; + req->length = se_cmd->data_length; + req->context = cmd; + return 0; +} + +static int usbg_send_status_response(struct se_cmd *se_cmd) +{ + struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd, + se_cmd); + struct f_uas *fu = cmd->fu; + + if (fu->flags & USBG_IS_BOT) + return bot_send_status_response(cmd); + else + return uasp_send_status_response(cmd); +} + +static int usbg_send_write_request(struct se_cmd *se_cmd) +{ + struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd, + se_cmd); + struct f_uas *fu = cmd->fu; + + if (fu->flags & USBG_IS_BOT) + return bot_send_write_request(cmd); + else + return uasp_send_write_request(cmd); +} + +static int usbg_send_read_response(struct se_cmd *se_cmd) +{ + struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd, + se_cmd); + struct f_uas *fu = cmd->fu; + + if (fu->flags & USBG_IS_BOT) + return bot_send_read_response(cmd); + else + return uasp_send_read_response(cmd); +} + +static void usbg_cmd_work(struct work_struct *work) +{ + struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work); + struct se_cmd *se_cmd; + struct tcm_usbg_nexus *tv_nexus; + struct usbg_tpg *tpg; + int dir; + + se_cmd = &cmd->se_cmd; + tpg = cmd->fu->tpg; + tv_nexus = tpg->tpg_nexus; + dir = get_cmd_dir(cmd->cmd_buf); + if (dir < 0) { + transport_init_se_cmd(se_cmd, + tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo, + tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE, + cmd->prio_attr, cmd->sense_iu.sense); + + transport_send_check_condition_and_sense(se_cmd, + TCM_UNSUPPORTED_SCSI_OPCODE, 1); + usbg_cleanup_cmd(cmd); + return; + } + + target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, + cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun, + 0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE); +} + +static int usbg_submit_command(struct f_uas *fu, + void *cmdbuf, unsigned int len) +{ + struct command_iu *cmd_iu = cmdbuf; + struct usbg_cmd *cmd; + struct usbg_tpg *tpg; + struct se_cmd *se_cmd; + struct tcm_usbg_nexus *tv_nexus; + u32 cmd_len; + int ret; + + if (cmd_iu->iu_id != IU_ID_COMMAND) { + pr_err("Unsupported type %d\n", cmd_iu->iu_id); + return -EINVAL; + } + + cmd = kzalloc(sizeof *cmd, GFP_ATOMIC); + if (!cmd) + return -ENOMEM; + + cmd->fu = fu; + + /* XXX until I figure out why I can't free in on complete */ + kref_init(&cmd->ref); + kref_get(&cmd->ref); + + tpg = fu->tpg; + cmd_len = (cmd_iu->len & ~0x3) + 16; + if (cmd_len > USBG_MAX_CMD) + goto err; + + memcpy(cmd->cmd_buf, cmd_iu->cdb, cmd_len); + + cmd->tag = be16_to_cpup(&cmd_iu->tag); + if (fu->flags & USBG_USE_STREAMS) { + if (cmd->tag > UASP_SS_EP_COMP_NUM_STREAMS) + goto err; + if (!cmd->tag) + cmd->stream = &fu->stream[0]; + else + cmd->stream = &fu->stream[cmd->tag - 1]; + } else { + cmd->stream = &fu->stream[0]; + } + + tv_nexus = tpg->tpg_nexus; + if (!tv_nexus) { + pr_err("Missing nexus, ignoring command\n"); + goto err; + } + + switch (cmd_iu->prio_attr & 0x7) { + case UAS_HEAD_TAG: + cmd->prio_attr = MSG_HEAD_TAG; + break; + case UAS_ORDERED_TAG: + cmd->prio_attr = MSG_ORDERED_TAG; + break; + case UAS_ACA: + cmd->prio_attr = MSG_ACA_TAG; + break; + default: + pr_debug_once("Unsupported prio_attr: %02x.\n", + cmd_iu->prio_attr); + case UAS_SIMPLE_TAG: + cmd->prio_attr = MSG_SIMPLE_TAG; + break; + } + + se_cmd = &cmd->se_cmd; + cmd->unpacked_lun = scsilun_to_int(&cmd_iu->lun); + + INIT_WORK(&cmd->work, usbg_cmd_work); + ret = queue_work(tpg->workqueue, &cmd->work); + if (ret < 0) + goto err; + + return 0; +err: + kfree(cmd); + return -EINVAL; +} + +static void bot_cmd_work(struct work_struct *work) +{ + struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work); + struct se_cmd *se_cmd; + struct tcm_usbg_nexus *tv_nexus; + struct usbg_tpg *tpg; + int dir; + + se_cmd = &cmd->se_cmd; + tpg = cmd->fu->tpg; + tv_nexus = tpg->tpg_nexus; + dir = get_cmd_dir(cmd->cmd_buf); + if (dir < 0) { + transport_init_se_cmd(se_cmd, + tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo, + tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE, + cmd->prio_attr, cmd->sense_iu.sense); + + transport_send_check_condition_and_sense(se_cmd, + TCM_UNSUPPORTED_SCSI_OPCODE, 1); + usbg_cleanup_cmd(cmd); + return; + } + + target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, + cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun, + cmd->data_len, cmd->prio_attr, dir, 0); +} + +static int bot_submit_command(struct f_uas *fu, + void *cmdbuf, unsigned int len) +{ + struct bulk_cb_wrap *cbw = cmdbuf; + struct usbg_cmd *cmd; + struct usbg_tpg *tpg; + struct se_cmd *se_cmd; + struct tcm_usbg_nexus *tv_nexus; + u32 cmd_len; + int ret; + + if (cbw->Signature != cpu_to_le32(US_BULK_CB_SIGN)) { + pr_err("Wrong signature on CBW\n"); + return -EINVAL; + } + if (len != 31) { + pr_err("Wrong length for CBW\n"); + return -EINVAL; + } + + cmd_len = cbw->Length; + if (cmd_len < 1 || cmd_len > 16) + return -EINVAL; + + cmd = kzalloc(sizeof *cmd, GFP_ATOMIC); + if (!cmd) + return -ENOMEM; + + cmd->fu = fu; + + /* XXX until I figure out why I can't free in on complete */ + kref_init(&cmd->ref); + kref_get(&cmd->ref); + + tpg = fu->tpg; + + memcpy(cmd->cmd_buf, cbw->CDB, cmd_len); + + cmd->bot_tag = cbw->Tag; + + tv_nexus = tpg->tpg_nexus; + if (!tv_nexus) { + pr_err("Missing nexus, ignoring command\n"); + goto err; + } + + cmd->prio_attr = MSG_SIMPLE_TAG; + se_cmd = &cmd->se_cmd; + cmd->unpacked_lun = cbw->Lun; + cmd->is_read = cbw->Flags & US_BULK_FLAG_IN ? 1 : 0; + cmd->data_len = le32_to_cpu(cbw->DataTransferLength); + + INIT_WORK(&cmd->work, bot_cmd_work); + ret = queue_work(tpg->workqueue, &cmd->work); + if (ret < 0) + goto err; + + return 0; +err: + kfree(cmd); + return -EINVAL; +} + +/* Start fabric.c code */ + +static int usbg_check_true(struct se_portal_group *se_tpg) +{ + return 1; +} + +static int usbg_check_false(struct se_portal_group *se_tpg) +{ + return 0; +} + +static char *usbg_get_fabric_name(void) +{ + return "usb_gadget"; +} + +static u8 usbg_get_fabric_proto_ident(struct se_portal_group *se_tpg) +{ + struct usbg_tpg *tpg = container_of(se_tpg, + struct usbg_tpg, se_tpg); + struct usbg_tport *tport = tpg->tport; + u8 proto_id; + + switch (tport->tport_proto_id) { + case SCSI_PROTOCOL_SAS: + default: + proto_id = sas_get_fabric_proto_ident(se_tpg); + break; + } + + return proto_id; +} + +static char *usbg_get_fabric_wwn(struct se_portal_group *se_tpg) +{ + struct usbg_tpg *tpg = container_of(se_tpg, + struct usbg_tpg, se_tpg); + struct usbg_tport *tport = tpg->tport; + + return &tport->tport_name[0]; +} + +static u16 usbg_get_tag(struct se_portal_group *se_tpg) +{ + struct usbg_tpg *tpg = container_of(se_tpg, + struct usbg_tpg, se_tpg); + return tpg->tport_tpgt; +} + +static u32 usbg_get_default_depth(struct se_portal_group *se_tpg) +{ + return 1; +} + +static u32 usbg_get_pr_transport_id( + struct se_portal_group *se_tpg, + struct se_node_acl *se_nacl, + struct t10_pr_registration *pr_reg, + int *format_code, + unsigned char *buf) +{ + struct usbg_tpg *tpg = container_of(se_tpg, + struct usbg_tpg, se_tpg); + struct usbg_tport *tport = tpg->tport; + int ret = 0; + + switch (tport->tport_proto_id) { + case SCSI_PROTOCOL_SAS: + default: + ret = sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg, + format_code, buf); + break; + } + + return ret; +} + +static u32 usbg_get_pr_transport_id_len( + struct se_portal_group *se_tpg, + struct se_node_acl *se_nacl, + struct t10_pr_registration *pr_reg, + int *format_code) +{ + struct usbg_tpg *tpg = container_of(se_tpg, + struct usbg_tpg, se_tpg); + struct usbg_tport *tport = tpg->tport; + int ret = 0; + + switch (tport->tport_proto_id) { + case SCSI_PROTOCOL_SAS: + default: + ret = sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, + format_code); + break; + } + + return ret; +} + +static char *usbg_parse_pr_out_transport_id( + struct se_portal_group *se_tpg, + const char *buf, + u32 *out_tid_len, + char **port_nexus_ptr) +{ + struct usbg_tpg *tpg = container_of(se_tpg, + struct usbg_tpg, se_tpg); + struct usbg_tport *tport = tpg->tport; + char *tid = NULL; + + switch (tport->tport_proto_id) { + case SCSI_PROTOCOL_SAS: + default: + tid = sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, + port_nexus_ptr); + } + + return tid; +} + +static struct se_node_acl *usbg_alloc_fabric_acl(struct se_portal_group *se_tpg) +{ + struct usbg_nacl *nacl; + + nacl = kzalloc(sizeof(struct usbg_nacl), GFP_KERNEL); + if (!nacl) { + printk(KERN_ERR "Unable to alocate struct usbg_nacl\n"); + return NULL; + } + + return &nacl->se_node_acl; +} + +static void usbg_release_fabric_acl( + struct se_portal_group *se_tpg, + struct se_node_acl *se_nacl) +{ + struct usbg_nacl *nacl = container_of(se_nacl, + struct usbg_nacl, se_node_acl); + kfree(nacl); +} + +static u32 usbg_tpg_get_inst_index(struct se_portal_group *se_tpg) +{ + return 1; +} + +static int usbg_new_cmd(struct se_cmd *se_cmd) +{ + struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd, + se_cmd); + int ret; + + ret = target_setup_cmd_from_cdb(se_cmd, cmd->cmd_buf); + if (ret) + return ret; + + return transport_generic_map_mem_to_cmd(se_cmd, NULL, 0, NULL, 0); +} + +static void usbg_cmd_release(struct kref *ref) +{ + struct usbg_cmd *cmd = container_of(ref, struct usbg_cmd, + ref); + + transport_generic_free_cmd(&cmd->se_cmd, 0); +} + +static void usbg_release_cmd(struct se_cmd *se_cmd) +{ + struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd, + se_cmd); + kfree(cmd->data_buf); + kfree(cmd); + return; +} + +static int usbg_shutdown_session(struct se_session *se_sess) +{ + return 0; +} + +static void usbg_close_session(struct se_session *se_sess) +{ + return; +} + +static u32 usbg_sess_get_index(struct se_session *se_sess) +{ + return 0; +} + +/* + * XXX Error recovery: return != 0 if we expect writes. Dunno when that could be + */ +static int usbg_write_pending_status(struct se_cmd *se_cmd) +{ + return 0; +} + +static void usbg_set_default_node_attrs(struct se_node_acl *nacl) +{ + return; +} + +static u32 usbg_get_task_tag(struct se_cmd *se_cmd) +{ + struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd, + se_cmd); + struct f_uas *fu = cmd->fu; + + if (fu->flags & USBG_IS_BOT) + return le32_to_cpu(cmd->bot_tag); + else + return cmd->tag; +} + +static int usbg_get_cmd_state(struct se_cmd *se_cmd) +{ + return 0; +} + +static int usbg_queue_tm_rsp(struct se_cmd *se_cmd) +{ + return 0; +} + +static u16 usbg_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length) +{ + return 0; +} + +static u16 usbg_get_fabric_sense_len(void) +{ + return 0; +} + +static const char *usbg_check_wwn(const char *name) +{ + const char *n; + unsigned int len; + + n = strstr(name, "naa."); + if (!n) + return NULL; + n += 4; + len = strlen(n); + if (len == 0 || len > USBG_NAMELEN - 1) + return NULL; + return n; +} + +static struct se_node_acl *usbg_make_nodeacl( + struct se_portal_group *se_tpg, + struct config_group *group, + const char *name) +{ + struct se_node_acl *se_nacl, *se_nacl_new; + struct usbg_nacl *nacl; + u64 wwpn = 0; + u32 nexus_depth; + const char *wnn_name; + + wnn_name = usbg_check_wwn(name); + if (!wnn_name) + return ERR_PTR(-EINVAL); + se_nacl_new = usbg_alloc_fabric_acl(se_tpg); + if (!(se_nacl_new)) + return ERR_PTR(-ENOMEM); + + nexus_depth = 1; + /* + * se_nacl_new may be released by core_tpg_add_initiator_node_acl() + * when converting a NodeACL from demo mode -> explict + */ + se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new, + name, nexus_depth); + if (IS_ERR(se_nacl)) { + usbg_release_fabric_acl(se_tpg, se_nacl_new); + return se_nacl; + } + /* + * Locate our struct usbg_nacl and set the FC Nport WWPN + */ + nacl = container_of(se_nacl, struct usbg_nacl, se_node_acl); + nacl->iport_wwpn = wwpn; + snprintf(nacl->iport_name, sizeof(nacl->iport_name), "%s", name); + return se_nacl; +} + +static void usbg_drop_nodeacl(struct se_node_acl *se_acl) +{ + struct usbg_nacl *nacl = container_of(se_acl, + struct usbg_nacl, se_node_acl); + core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1); + kfree(nacl); +} + +struct usbg_tpg *the_only_tpg_I_currently_have; + +static struct se_portal_group *usbg_make_tpg( + struct se_wwn *wwn, + struct config_group *group, + const char *name) +{ + struct usbg_tport *tport = container_of(wwn, struct usbg_tport, + tport_wwn); + struct usbg_tpg *tpg; + unsigned long tpgt; + int ret; + + if (strstr(name, "tpgt_") != name) + return ERR_PTR(-EINVAL); + if (kstrtoul(name + 5, 0, &tpgt) || tpgt > UINT_MAX) + return ERR_PTR(-EINVAL); + if (the_only_tpg_I_currently_have) { + pr_err("Until the gadget framework can't handle multiple\n"); + pr_err("gadgets, you can't do this here.\n"); + return ERR_PTR(-EBUSY); + } + + tpg = kzalloc(sizeof(struct usbg_tpg), GFP_KERNEL); + if (!tpg) { + printk(KERN_ERR "Unable to allocate struct usbg_tpg"); + return ERR_PTR(-ENOMEM); + } + mutex_init(&tpg->tpg_mutex); + atomic_set(&tpg->tpg_port_count, 0); + tpg->workqueue = alloc_workqueue("tcm_usb_gadget", 0, 1); + if (!tpg->workqueue) { + kfree(tpg); + return NULL; + } + + tpg->tport = tport; + tpg->tport_tpgt = tpgt; + + ret = core_tpg_register(&usbg_fabric_configfs->tf_ops, wwn, + &tpg->se_tpg, tpg, + TRANSPORT_TPG_TYPE_NORMAL); + if (ret < 0) { + destroy_workqueue(tpg->workqueue); + kfree(tpg); + return NULL; + } + the_only_tpg_I_currently_have = tpg; + return &tpg->se_tpg; +} + +static void usbg_drop_tpg(struct se_portal_group *se_tpg) +{ + struct usbg_tpg *tpg = container_of(se_tpg, + struct usbg_tpg, se_tpg); + + core_tpg_deregister(se_tpg); + destroy_workqueue(tpg->workqueue); + kfree(tpg); + the_only_tpg_I_currently_have = NULL; +} + +static struct se_wwn *usbg_make_tport( + struct target_fabric_configfs *tf, + struct config_group *group, + const char *name) +{ + struct usbg_tport *tport; + const char *wnn_name; + u64 wwpn = 0; + + wnn_name = usbg_check_wwn(name); + if (!wnn_name) + return ERR_PTR(-EINVAL); + + tport = kzalloc(sizeof(struct usbg_tport), GFP_KERNEL); + if (!(tport)) { + printk(KERN_ERR "Unable to allocate struct usbg_tport"); + return ERR_PTR(-ENOMEM); + } + tport->tport_wwpn = wwpn; + snprintf(tport->tport_name, sizeof(tport->tport_name), wnn_name); + return &tport->tport_wwn; +} + +static void usbg_drop_tport(struct se_wwn *wwn) +{ + struct usbg_tport *tport = container_of(wwn, + struct usbg_tport, tport_wwn); + kfree(tport); +} + +/* + * If somebody feels like dropping the version property, go ahead. + */ +static ssize_t usbg_wwn_show_attr_version( + struct target_fabric_configfs *tf, + char *page) +{ + return sprintf(page, "usb-gadget fabric module\n"); +} +TF_WWN_ATTR_RO(usbg, version); + +static struct configfs_attribute *usbg_wwn_attrs[] = { + &usbg_wwn_version.attr, + NULL, +}; + +static ssize_t tcm_usbg_tpg_show_enable( + struct se_portal_group *se_tpg, + char *page) +{ + struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg); + + return snprintf(page, PAGE_SIZE, "%u\n", tpg->gadget_connect); +} + +static int usbg_attach(struct usbg_tpg *); +static void usbg_detach(struct usbg_tpg *); + +static ssize_t tcm_usbg_tpg_store_enable( + struct se_portal_group *se_tpg, + const char *page, + size_t count) +{ + struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg); + unsigned long op; + ssize_t ret; + + ret = kstrtoul(page, 0, &op); + if (ret < 0) + return -EINVAL; + if (op > 1) + return -EINVAL; + + if (op && tpg->gadget_connect) + goto out; + if (!op && !tpg->gadget_connect) + goto out; + + if (op) { + ret = usbg_attach(tpg); + if (ret) + goto out; + } else { + usbg_detach(tpg); + } + tpg->gadget_connect = op; +out: + return count; +} +TF_TPG_BASE_ATTR(tcm_usbg, enable, S_IRUGO | S_IWUSR); + +static ssize_t tcm_usbg_tpg_show_nexus( + struct se_portal_group *se_tpg, + char *page) +{ + struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg); + struct tcm_usbg_nexus *tv_nexus; + ssize_t ret; + + mutex_lock(&tpg->tpg_mutex); + tv_nexus = tpg->tpg_nexus; + if (!tv_nexus) { + ret = -ENODEV; + goto out; + } + ret = snprintf(page, PAGE_SIZE, "%s\n", + tv_nexus->tvn_se_sess->se_node_acl->initiatorname); +out: + mutex_unlock(&tpg->tpg_mutex); + return ret; +} + +static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name) +{ + struct se_portal_group *se_tpg; + struct tcm_usbg_nexus *tv_nexus; + int ret; + + mutex_lock(&tpg->tpg_mutex); + if (tpg->tpg_nexus) { + ret = -EEXIST; + pr_debug("tpg->tpg_nexus already exists\n"); + goto err_unlock; + } + se_tpg = &tpg->se_tpg; + + ret = -ENOMEM; + tv_nexus = kzalloc(sizeof(*tv_nexus), GFP_KERNEL); + if (!tv_nexus) { + pr_err("Unable to allocate struct tcm_vhost_nexus\n"); + goto err_unlock; + } + tv_nexus->tvn_se_sess = transport_init_session(); + if (IS_ERR(tv_nexus->tvn_se_sess)) + goto err_free; + + /* + * Since we are running in 'demo mode' this call with generate a + * struct se_node_acl for the tcm_vhost struct se_portal_group with + * the SCSI Initiator port name of the passed configfs group 'name'. + */ + tv_nexus->tvn_se_sess->se_node_acl = core_tpg_check_initiator_node_acl( + se_tpg, name); + if (!tv_nexus->tvn_se_sess->se_node_acl) { + pr_debug("core_tpg_check_initiator_node_acl() failed" + " for %s\n", name); + goto err_session; + } + /* + * Now register the TCM vHost virtual I_T Nexus as active with the + * call to __transport_register_session() + */ + __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl, + tv_nexus->tvn_se_sess, tv_nexus); + tpg->tpg_nexus = tv_nexus; + mutex_unlock(&tpg->tpg_mutex); + return 0; + +err_session: + transport_free_session(tv_nexus->tvn_se_sess); +err_free: + kfree(tv_nexus); +err_unlock: + mutex_unlock(&tpg->tpg_mutex); + return ret; +} + +static int tcm_usbg_drop_nexus(struct usbg_tpg *tpg) +{ + struct se_session *se_sess; + struct tcm_usbg_nexus *tv_nexus; + int ret = -ENODEV; + + mutex_lock(&tpg->tpg_mutex); + tv_nexus = tpg->tpg_nexus; + if (!tv_nexus) + goto out; + + se_sess = tv_nexus->tvn_se_sess; + if (!se_sess) + goto out; + + if (atomic_read(&tpg->tpg_port_count)) { + ret = -EPERM; + pr_err("Unable to remove Host I_T Nexus with" + " active TPG port count: %d\n", + atomic_read(&tpg->tpg_port_count)); + goto out; + } + + pr_debug("Removing I_T Nexus to Initiator Port: %s\n", + tv_nexus->tvn_se_sess->se_node_acl->initiatorname); + /* + * Release the SCSI I_T Nexus to the emulated vHost Target Port + */ + transport_deregister_session(tv_nexus->tvn_se_sess); + tpg->tpg_nexus = NULL; + + kfree(tv_nexus); +out: + mutex_unlock(&tpg->tpg_mutex); + return 0; +} + +static ssize_t tcm_usbg_tpg_store_nexus( + struct se_portal_group *se_tpg, + const char *page, + size_t count) +{ + struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg); + unsigned char i_port[USBG_NAMELEN], *ptr; + int ret; + + if (!strncmp(page, "NULL", 4)) { + ret = tcm_usbg_drop_nexus(tpg); + return (!ret) ? count : ret; + } + if (strlen(page) > USBG_NAMELEN) { + pr_err("Emulated NAA Sas Address: %s, exceeds" + " max: %d\n", page, USBG_NAMELEN); + return -EINVAL; + } + snprintf(i_port, USBG_NAMELEN, "%s", page); + + ptr = strstr(i_port, "naa."); + if (!ptr) { + pr_err("Missing 'naa.' prefix\n"); + return -EINVAL; + } + + if (i_port[strlen(i_port) - 1] == '\n') + i_port[strlen(i_port) - 1] = '\0'; + + ret = tcm_usbg_make_nexus(tpg, &i_port[4]); + if (ret < 0) + return ret; + return count; +} +TF_TPG_BASE_ATTR(tcm_usbg, nexus, S_IRUGO | S_IWUSR); + +static struct configfs_attribute *usbg_base_attrs[] = { + &tcm_usbg_tpg_enable.attr, + &tcm_usbg_tpg_nexus.attr, + NULL, +}; + +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(); + return 0; +} + +static void usbg_port_unlink(struct se_portal_group *se_tpg, + struct se_lun *se_lun) +{ + struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg); + + atomic_dec(&tpg->tpg_port_count); + smp_mb__after_atomic_dec(); +} + +static int usbg_check_stop_free(struct se_cmd *se_cmd) +{ + struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd, + se_cmd); + + kref_put(&cmd->ref, usbg_cmd_release); + return 1; +} + +static struct target_core_fabric_ops usbg_ops = { + .get_fabric_name = usbg_get_fabric_name, + .get_fabric_proto_ident = usbg_get_fabric_proto_ident, + .tpg_get_wwn = usbg_get_fabric_wwn, + .tpg_get_tag = usbg_get_tag, + .tpg_get_default_depth = usbg_get_default_depth, + .tpg_get_pr_transport_id = usbg_get_pr_transport_id, + .tpg_get_pr_transport_id_len = usbg_get_pr_transport_id_len, + .tpg_parse_pr_out_transport_id = usbg_parse_pr_out_transport_id, + .tpg_check_demo_mode = usbg_check_true, + .tpg_check_demo_mode_cache = usbg_check_false, + .tpg_check_demo_mode_write_protect = usbg_check_false, + .tpg_check_prod_mode_write_protect = usbg_check_false, + .tpg_alloc_fabric_acl = usbg_alloc_fabric_acl, + .tpg_release_fabric_acl = usbg_release_fabric_acl, + .tpg_get_inst_index = usbg_tpg_get_inst_index, + .new_cmd_map = usbg_new_cmd, + .release_cmd = usbg_release_cmd, + .shutdown_session = usbg_shutdown_session, + .close_session = usbg_close_session, + .sess_get_index = usbg_sess_get_index, + .sess_get_initiator_sid = NULL, + .write_pending = usbg_send_write_request, + .write_pending_status = usbg_write_pending_status, + .set_default_node_attributes = usbg_set_default_node_attrs, + .get_task_tag = usbg_get_task_tag, + .get_cmd_state = usbg_get_cmd_state, + .queue_data_in = usbg_send_read_response, + .queue_status = usbg_send_status_response, + .queue_tm_rsp = usbg_queue_tm_rsp, + .get_fabric_sense_len = usbg_get_fabric_sense_len, + .set_fabric_sense_len = usbg_set_fabric_sense_len, + .check_stop_free = usbg_check_stop_free, + + .fabric_make_wwn = usbg_make_tport, + .fabric_drop_wwn = usbg_drop_tport, + .fabric_make_tpg = usbg_make_tpg, + .fabric_drop_tpg = usbg_drop_tpg, + .fabric_post_link = usbg_port_link, + .fabric_pre_unlink = usbg_port_unlink, + .fabric_make_np = NULL, + .fabric_drop_np = NULL, + .fabric_make_nodeacl = usbg_make_nodeacl, + .fabric_drop_nodeacl = usbg_drop_nodeacl, +}; + +static int usbg_register_configfs(void) +{ + struct target_fabric_configfs *fabric; + int ret; + + fabric = target_fabric_configfs_init(THIS_MODULE, "usb_gadget"); + if (IS_ERR(fabric)) { + printk(KERN_ERR "target_fabric_configfs_init() failed\n"); + return PTR_ERR(fabric); + } + + fabric->tf_ops = usbg_ops; + TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = usbg_wwn_attrs; + TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = usbg_base_attrs; + TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL; + TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL; + TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL; + TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL; + TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; + TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL; + TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL; + ret = target_fabric_configfs_register(fabric); + if (ret < 0) { + printk(KERN_ERR "target_fabric_configfs_register() failed" + " for usb-gadget\n"); + return ret; + } + usbg_fabric_configfs = fabric; + return 0; +}; + +static void usbg_deregister_configfs(void) +{ + if (!(usbg_fabric_configfs)) + return; + + target_fabric_configfs_deregister(usbg_fabric_configfs); + usbg_fabric_configfs = NULL; +}; + +/* Start gadget.c code */ + +static struct usb_interface_descriptor bot_intf_desc = { + .bLength = sizeof(bot_intf_desc), + .bDescriptorType = USB_DT_INTERFACE, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bAlternateSetting = USB_G_ALT_INT_BBB, + .bInterfaceClass = USB_CLASS_MASS_STORAGE, + .bInterfaceSubClass = USB_SC_SCSI, + .bInterfaceProtocol = USB_PR_BULK, + .iInterface = USB_G_STR_INT_UAS, +}; + +static struct usb_interface_descriptor uasp_intf_desc = { + .bLength = sizeof(uasp_intf_desc), + .bDescriptorType = USB_DT_INTERFACE, + .bNumEndpoints = 4, + .bAlternateSetting = USB_G_ALT_INT_UAS, + .bInterfaceClass = USB_CLASS_MASS_STORAGE, + .bInterfaceSubClass = USB_SC_SCSI, + .bInterfaceProtocol = USB_PR_UAS, + .iInterface = USB_G_STR_INT_BBB, +}; + +static struct usb_endpoint_descriptor uasp_bi_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(512), +}; + +static struct usb_endpoint_descriptor uasp_fs_bi_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, +}; + +static struct usb_pipe_usage_descriptor uasp_bi_pipe_desc = { + .bLength = sizeof(uasp_bi_pipe_desc), + .bDescriptorType = USB_DT_PIPE_USAGE, + .bPipeID = DATA_IN_PIPE_ID, +}; + +static struct usb_endpoint_descriptor uasp_ss_bi_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor uasp_bi_ep_comp_desc = { + .bLength = sizeof(uasp_bi_ep_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bMaxBurst = 0, + .bmAttributes = UASP_SS_EP_COMP_LOG_STREAMS, + .wBytesPerInterval = 0, +}; + +static struct usb_ss_ep_comp_descriptor bot_bi_ep_comp_desc = { + .bLength = sizeof(bot_bi_ep_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bMaxBurst = 0, +}; + +static struct usb_endpoint_descriptor uasp_bo_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(512), +}; + +static struct usb_endpoint_descriptor uasp_fs_bo_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, +}; + +static struct usb_pipe_usage_descriptor uasp_bo_pipe_desc = { + .bLength = sizeof(uasp_bo_pipe_desc), + .bDescriptorType = USB_DT_PIPE_USAGE, + .bPipeID = DATA_OUT_PIPE_ID, +}; + +static struct usb_endpoint_descriptor uasp_ss_bo_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(0x400), +}; + +static struct usb_ss_ep_comp_descriptor uasp_bo_ep_comp_desc = { + .bLength = sizeof(uasp_bo_ep_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bmAttributes = UASP_SS_EP_COMP_LOG_STREAMS, +}; + +static struct usb_ss_ep_comp_descriptor bot_bo_ep_comp_desc = { + .bLength = sizeof(bot_bo_ep_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, +}; + +static struct usb_endpoint_descriptor uasp_status_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(512), +}; + +static struct usb_endpoint_descriptor uasp_fs_status_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, +}; + +static struct usb_pipe_usage_descriptor uasp_status_pipe_desc = { + .bLength = sizeof(uasp_status_pipe_desc), + .bDescriptorType = USB_DT_PIPE_USAGE, + .bPipeID = STATUS_PIPE_ID, +}; + +static struct usb_endpoint_descriptor uasp_ss_status_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor uasp_status_in_ep_comp_desc = { + .bLength = sizeof(uasp_status_in_ep_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bmAttributes = UASP_SS_EP_COMP_LOG_STREAMS, +}; + +static struct usb_endpoint_descriptor uasp_cmd_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(512), +}; + +static struct usb_endpoint_descriptor uasp_fs_cmd_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, +}; + +static struct usb_pipe_usage_descriptor uasp_cmd_pipe_desc = { + .bLength = sizeof(uasp_cmd_pipe_desc), + .bDescriptorType = USB_DT_PIPE_USAGE, + .bPipeID = CMD_PIPE_ID, +}; + +static struct usb_endpoint_descriptor uasp_ss_cmd_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor uasp_cmd_comp_desc = { + .bLength = sizeof(uasp_cmd_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, +}; + +static struct usb_descriptor_header *uasp_fs_function_desc[] = { + (struct usb_descriptor_header *) &bot_intf_desc, + (struct usb_descriptor_header *) &uasp_fs_bi_desc, + (struct usb_descriptor_header *) &uasp_fs_bo_desc, + + (struct usb_descriptor_header *) &uasp_intf_desc, + (struct usb_descriptor_header *) &uasp_fs_bi_desc, + (struct usb_descriptor_header *) &uasp_bi_pipe_desc, + (struct usb_descriptor_header *) &uasp_fs_bo_desc, + (struct usb_descriptor_header *) &uasp_bo_pipe_desc, + (struct usb_descriptor_header *) &uasp_fs_status_desc, + (struct usb_descriptor_header *) &uasp_status_pipe_desc, + (struct usb_descriptor_header *) &uasp_fs_cmd_desc, + (struct usb_descriptor_header *) &uasp_cmd_pipe_desc, +}; + +static struct usb_descriptor_header *uasp_hs_function_desc[] = { + (struct usb_descriptor_header *) &bot_intf_desc, + (struct usb_descriptor_header *) &uasp_bi_desc, + (struct usb_descriptor_header *) &uasp_bo_desc, + + (struct usb_descriptor_header *) &uasp_intf_desc, + (struct usb_descriptor_header *) &uasp_bi_desc, + (struct usb_descriptor_header *) &uasp_bi_pipe_desc, + (struct usb_descriptor_header *) &uasp_bo_desc, + (struct usb_descriptor_header *) &uasp_bo_pipe_desc, + (struct usb_descriptor_header *) &uasp_status_desc, + (struct usb_descriptor_header *) &uasp_status_pipe_desc, + (struct usb_descriptor_header *) &uasp_cmd_desc, + (struct usb_descriptor_header *) &uasp_cmd_pipe_desc, + NULL, +}; + +static struct usb_descriptor_header *uasp_ss_function_desc[] = { + (struct usb_descriptor_header *) &bot_intf_desc, + (struct usb_descriptor_header *) &uasp_ss_bi_desc, + (struct usb_descriptor_header *) &bot_bi_ep_comp_desc, + (struct usb_descriptor_header *) &uasp_ss_bo_desc, + (struct usb_descriptor_header *) &bot_bo_ep_comp_desc, + + (struct usb_descriptor_header *) &uasp_intf_desc, + (struct usb_descriptor_header *) &uasp_ss_bi_desc, + (struct usb_descriptor_header *) &uasp_bi_ep_comp_desc, + (struct usb_descriptor_header *) &uasp_bi_pipe_desc, + (struct usb_descriptor_header *) &uasp_ss_bo_desc, + (struct usb_descriptor_header *) &uasp_bo_ep_comp_desc, + (struct usb_descriptor_header *) &uasp_bo_pipe_desc, + (struct usb_descriptor_header *) &uasp_ss_status_desc, + (struct usb_descriptor_header *) &uasp_status_in_ep_comp_desc, + (struct usb_descriptor_header *) &uasp_status_pipe_desc, + (struct usb_descriptor_header *) &uasp_ss_cmd_desc, + (struct usb_descriptor_header *) &uasp_cmd_comp_desc, + (struct usb_descriptor_header *) &uasp_cmd_pipe_desc, + NULL, +}; + +#define UAS_VENDOR_ID 0x0525 /* NetChip */ +#define UAS_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */ + +static struct usb_device_descriptor usbg_device_desc = { + .bLength = sizeof(usbg_device_desc), + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = cpu_to_le16(0x0200), + .bDeviceClass = USB_CLASS_PER_INTERFACE, + .idVendor = cpu_to_le16(UAS_VENDOR_ID), + .idProduct = cpu_to_le16(UAS_PRODUCT_ID), + .iManufacturer = USB_G_STR_MANUFACTOR, + .iProduct = USB_G_STR_PRODUCT, + .iSerialNumber = USB_G_STR_SERIAL, + + .bNumConfigurations = 1, +}; + +static struct usb_string usbg_us_strings[] = { + { USB_G_STR_MANUFACTOR, "Target Manufactor"}, + { USB_G_STR_PRODUCT, "Target Product"}, + { USB_G_STR_SERIAL, "000000000001"}, + { USB_G_STR_CONFIG, "default config"}, + { USB_G_STR_INT_UAS, "USB Attached SCSI"}, + { USB_G_STR_INT_BBB, "Bulk Only Transport"}, + { }, +}; + +static struct usb_gadget_strings usbg_stringtab = { + .language = 0x0409, + .strings = usbg_us_strings, +}; + +static struct usb_gadget_strings *usbg_strings[] = { + &usbg_stringtab, + NULL, +}; + +static int guas_unbind(struct usb_composite_dev *cdev) +{ + return 0; +} + +static struct usb_configuration usbg_config_driver = { + .label = "Linux Target", + .bConfigurationValue = 1, + .iConfiguration = USB_G_STR_CONFIG, + .bmAttributes = USB_CONFIG_ATT_SELFPOWER, +}; + +static void give_back_ep(struct usb_ep **pep) +{ + struct usb_ep *ep = *pep; + if (!ep) + return; + ep->driver_data = NULL; +} + +static int usbg_bind(struct usb_configuration *c, struct usb_function *f) +{ + struct f_uas *fu = to_f_uas(f); + struct usb_gadget *gadget = c->cdev->gadget; + struct usb_ep *ep; + int iface; + + iface = usb_interface_id(c, f); + if (iface < 0) + return iface; + + bot_intf_desc.bInterfaceNumber = iface; + uasp_intf_desc.bInterfaceNumber = iface; + fu->iface = iface; + ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bi_desc, + &uasp_bi_ep_comp_desc); + if (!ep) + goto ep_fail; + + ep->driver_data = fu; + fu->ep_in = ep; + + ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bo_desc, + &uasp_bo_ep_comp_desc); + if (!ep) + goto ep_fail; + ep->driver_data = fu; + fu->ep_out = ep; + + ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_status_desc, + &uasp_status_in_ep_comp_desc); + if (!ep) + goto ep_fail; + ep->driver_data = fu; + fu->ep_status = ep; + + ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_cmd_desc, + &uasp_cmd_comp_desc); + if (!ep) + goto ep_fail; + ep->driver_data = fu; + fu->ep_cmd = ep; + + /* Assume endpoint addresses are the same for both speeds */ + uasp_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress; + uasp_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress; + uasp_status_desc.bEndpointAddress = + uasp_ss_status_desc.bEndpointAddress; + uasp_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress; + + uasp_fs_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress; + uasp_fs_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress; + uasp_fs_status_desc.bEndpointAddress = + uasp_ss_status_desc.bEndpointAddress; + uasp_fs_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress; + + return 0; +ep_fail: + pr_err("Can't claim all required eps\n"); + + give_back_ep(&fu->ep_in); + give_back_ep(&fu->ep_out); + give_back_ep(&fu->ep_status); + give_back_ep(&fu->ep_cmd); + return -ENOTSUPP; +} + +static void usbg_unbind(struct usb_configuration *c, struct usb_function *f) +{ + struct f_uas *fu = to_f_uas(f); + + kfree(fu); +} + +struct guas_setup_wq { + struct work_struct work; + struct f_uas *fu; + unsigned int alt; +}; + +static void usbg_delayed_set_alt(struct work_struct *wq) +{ + struct guas_setup_wq *work = container_of(wq, struct guas_setup_wq, + work); + struct f_uas *fu = work->fu; + int alt = work->alt; + + kfree(work); + + if (fu->flags & USBG_IS_BOT) + bot_cleanup_old_alt(fu); + if (fu->flags & USBG_IS_UAS) + uasp_cleanup_old_alt(fu); + + if (alt == USB_G_ALT_INT_BBB) + bot_set_alt(fu); + else if (alt == USB_G_ALT_INT_UAS) + uasp_set_alt(fu); + usb_composite_setup_continue(fu->function.config->cdev); +} + +static int usbg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) +{ + struct f_uas *fu = to_f_uas(f); + + if ((alt == USB_G_ALT_INT_BBB) || (alt == USB_G_ALT_INT_UAS)) { + struct guas_setup_wq *work; + + work = kmalloc(sizeof(*work), GFP_ATOMIC); + if (!work) + return -ENOMEM; + INIT_WORK(&work->work, usbg_delayed_set_alt); + work->fu = fu; + work->alt = alt; + schedule_work(&work->work); + return USB_GADGET_DELAYED_STATUS; + } + return -EOPNOTSUPP; +} + +static void usbg_disable(struct usb_function *f) +{ + struct f_uas *fu = to_f_uas(f); + + if (fu->flags & USBG_IS_UAS) + uasp_cleanup_old_alt(fu); + else if (fu->flags & USBG_IS_BOT) + bot_cleanup_old_alt(fu); + fu->flags = 0; +} + +static int usbg_setup(struct usb_function *f, + const struct usb_ctrlrequest *ctrl) +{ + struct f_uas *fu = to_f_uas(f); + + if (!(fu->flags & USBG_IS_BOT)) + return -EOPNOTSUPP; + + return usbg_bot_setup(f, ctrl); +} + +static int usbg_cfg_bind(struct usb_configuration *c) +{ + struct f_uas *fu; + int ret; + + fu = kzalloc(sizeof(*fu), GFP_KERNEL); + if (!fu) + return -ENOMEM; + fu->function.name = "Target Function"; + fu->function.descriptors = uasp_fs_function_desc; + fu->function.hs_descriptors = uasp_hs_function_desc; + fu->function.ss_descriptors = uasp_ss_function_desc; + fu->function.bind = usbg_bind; + fu->function.unbind = usbg_unbind; + fu->function.set_alt = usbg_set_alt; + fu->function.setup = usbg_setup; + fu->function.disable = usbg_disable; + fu->tpg = the_only_tpg_I_currently_have; + + ret = usb_add_function(c, &fu->function); + if (ret) + goto err; + + return 0; +err: + kfree(fu); + return ret; +} + +static int usb_target_bind(struct usb_composite_dev *cdev) +{ + int ret; + + ret = usb_add_config(cdev, &usbg_config_driver, + usbg_cfg_bind); + return 0; +} + +static struct usb_composite_driver usbg_driver = { + .name = "g_target", + .dev = &usbg_device_desc, + .strings = usbg_strings, + .max_speed = USB_SPEED_SUPER, + .unbind = guas_unbind, +}; + +static int usbg_attach(struct usbg_tpg *tpg) +{ + return usb_composite_probe(&usbg_driver, usb_target_bind); +} + +static void usbg_detach(struct usbg_tpg *tpg) +{ + usb_composite_unregister(&usbg_driver); +} + +static int __init usb_target_gadget_init(void) +{ + int ret; + + ret = usbg_register_configfs(); + return ret; +} +module_init(usb_target_gadget_init); + +static void __exit usb_target_gadget_exit(void) +{ + usbg_deregister_configfs(); +} +module_exit(usb_target_gadget_exit); + +MODULE_AUTHOR("Sebastian Andrzej Siewior "); +MODULE_DESCRIPTION("usb-gadget fabric"); +MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/usb/gadget/tcm_usb_gadget.h b/trunk/drivers/usb/gadget/tcm_usb_gadget.h new file mode 100644 index 000000000000..bb18999a9a8d --- /dev/null +++ b/trunk/drivers/usb/gadget/tcm_usb_gadget.h @@ -0,0 +1,146 @@ +#ifndef __TARGET_USB_GADGET_H__ +#define __TARGET_USB_GADGET_H__ + +#include +/* #include */ +#include +#include +#include +#include +#include +#include + +#define USBG_NAMELEN 32 + +#define fuas_to_gadget(f) (f->function.config->cdev->gadget) +#define UASP_SS_EP_COMP_LOG_STREAMS 4 +#define UASP_SS_EP_COMP_NUM_STREAMS (1 << UASP_SS_EP_COMP_LOG_STREAMS) + +#define USB_G_STR_MANUFACTOR 1 +#define USB_G_STR_PRODUCT 2 +#define USB_G_STR_SERIAL 3 +#define USB_G_STR_CONFIG 4 +#define USB_G_STR_INT_UAS 5 +#define USB_G_STR_INT_BBB 6 + +#define USB_G_ALT_INT_BBB 0 +#define USB_G_ALT_INT_UAS 1 + +struct usbg_nacl { + /* Binary World Wide unique Port Name for SAS Initiator port */ + u64 iport_wwpn; + /* ASCII formatted WWPN for Sas Initiator port */ + char iport_name[USBG_NAMELEN]; + /* Returned by usbg_make_nodeacl() */ + struct se_node_acl se_node_acl; +}; + +struct tcm_usbg_nexus { + struct se_session *tvn_se_sess; +}; + +struct usbg_tpg { + struct mutex tpg_mutex; + /* SAS port target portal group tag for TCM */ + u16 tport_tpgt; + /* Pointer back to usbg_tport */ + struct usbg_tport *tport; + struct workqueue_struct *workqueue; + /* Returned by usbg_make_tpg() */ + struct se_portal_group se_tpg; + u32 gadget_connect; + struct tcm_usbg_nexus *tpg_nexus; + atomic_t tpg_port_count; +}; + +struct usbg_tport { + /* SCSI protocol the tport is providing */ + u8 tport_proto_id; + /* Binary World Wide unique Port Name for SAS Target port */ + u64 tport_wwpn; + /* ASCII formatted WWPN for SAS Target port */ + char tport_name[USBG_NAMELEN]; + /* Returned by usbg_make_tport() */ + struct se_wwn tport_wwn; +}; + +enum uas_state { + UASP_SEND_DATA, + UASP_RECEIVE_DATA, + UASP_SEND_STATUS, + UASP_QUEUE_COMMAND, +}; + +#define USBG_MAX_CMD 64 +struct usbg_cmd { + /* common */ + u8 cmd_buf[USBG_MAX_CMD]; + u32 data_len; + struct work_struct work; + int unpacked_lun; + struct se_cmd se_cmd; + void *data_buf; /* used if no sg support available */ + struct f_uas *fu; + struct completion write_complete; + struct kref ref; + + /* UAS only */ + u16 tag; + u16 prio_attr; + struct sense_iu sense_iu; + enum uas_state state; + struct uas_stream *stream; + + /* BOT only */ + __le32 bot_tag; + unsigned int csw_code; + unsigned is_read:1; + +}; + +struct uas_stream { + struct usb_request *req_in; + struct usb_request *req_out; + struct usb_request *req_status; +}; + +struct usbg_cdb { + struct usb_request *req; + void *buf; +}; + +struct bot_status { + struct usb_request *req; + struct bulk_cs_wrap csw; +}; + +struct f_uas { + struct usbg_tpg *tpg; + struct usb_function function; + u16 iface; + + u32 flags; +#define USBG_ENABLED (1 << 0) +#define USBG_IS_UAS (1 << 1) +#define USBG_USE_STREAMS (1 << 2) +#define USBG_IS_BOT (1 << 3) +#define USBG_BOT_CMD_PEND (1 << 4) + + struct usbg_cdb cmd; + struct usb_ep *ep_in; + struct usb_ep *ep_out; + + /* UAS */ + struct usb_ep *ep_status; + struct usb_ep *ep_cmd; + struct uas_stream stream[UASP_SS_EP_COMP_NUM_STREAMS]; + + /* BOT */ + struct bot_status bot_status; + struct usb_request *bot_req_in; + struct usb_request *bot_req_out; +}; + +extern struct usbg_tpg *the_only_tpg_I_currently_have; + +#endif diff --git a/trunk/drivers/usb/gadget/u_ether.c b/trunk/drivers/usb/gadget/u_ether.c index 29c854bbca44..47cf48b51c9d 100644 --- a/trunk/drivers/usb/gadget/u_ether.c +++ b/trunk/drivers/usb/gadget/u_ether.c @@ -744,10 +744,11 @@ static struct device_type gadget_type = { }; /** - * gether_setup - initialize one ethernet-over-usb link + * gether_setup_name - initialize one ethernet-over-usb link * @g: gadget to associated with these links * @ethaddr: NULL, or a buffer in which the ethernet address of the * host side of the link is recorded + * @netname: name for network device (for example, "usb") * Context: may sleep * * This sets up the single network link that may be exported by a @@ -756,7 +757,8 @@ static struct device_type gadget_type = { * * Returns negative errno, or zero on success */ -int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]) +int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN], + const char *netname) { struct eth_dev *dev; struct net_device *net; @@ -780,7 +782,7 @@ int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]) /* network device setup */ dev->net = net; - strcpy(net->name, "usb%d"); + snprintf(net->name, sizeof(net->name), "%s%%d", netname); if (get_ether_addr(dev_addr, net->dev_addr)) dev_warn(&g->dev, diff --git a/trunk/drivers/usb/gadget/u_ether.h b/trunk/drivers/usb/gadget/u_ether.h index 8012357e98aa..6f4a1623d854 100644 --- a/trunk/drivers/usb/gadget/u_ether.h +++ b/trunk/drivers/usb/gadget/u_ether.h @@ -69,9 +69,28 @@ struct gether { |USB_CDC_PACKET_TYPE_PROMISCUOUS \ |USB_CDC_PACKET_TYPE_DIRECTED) +/* variant of gether_setup that allows customizing network device name */ +int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN], + const char *netname); /* netdev setup/teardown as directed by the gadget driver */ -int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]); +/* gether_setup - initialize one ethernet-over-usb link + * @g: gadget to associated with these links + * @ethaddr: NULL, or a buffer in which the ethernet address of the + * host side of the link is recorded + * Context: may sleep + * + * This sets up the single network link that may be exported by a + * gadget driver using this framework. The link layer addresses are + * set up using module parameters. + * + * Returns negative errno, or zero on success + */ +static inline int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]) +{ + return gether_setup_name(g, ethaddr, "usb"); +} + void gether_cleanup(void); /* connect/disconnect is handled by individual functions */ @@ -99,16 +118,37 @@ int eem_bind_config(struct usb_configuration *c); #ifdef USB_ETH_RNDIS -int rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]); +int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], + u32 vendorID, const char *manufacturer); #else static inline int -rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) +rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], + u32 vendorID, const char *manufacturer) { return 0; } #endif +/** + * rndis_bind_config - add RNDIS network link to a configuration + * @c: the configuration to support the network link + * @ethaddr: a buffer in which the ethernet address of the host side + * side of the link was recorded + * Context: single threaded during gadget setup + * + * Returns zero on success, else negative errno. + * + * Caller must have called @gether_setup(). Caller is also responsible + * for calling @gether_cleanup() before module unload. + */ +static inline int rndis_bind_config(struct usb_configuration *c, + u8 ethaddr[ETH_ALEN]) +{ + return rndis_bind_config_vendor(c, ethaddr, 0, NULL); +} + + #endif /* __U_ETHER_H */ diff --git a/trunk/drivers/usb/gadget/u_serial.c b/trunk/drivers/usb/gadget/u_serial.c index 6c23938d2711..5b3f5fffea92 100644 --- a/trunk/drivers/usb/gadget/u_serial.c +++ b/trunk/drivers/usb/gadget/u_serial.c @@ -94,17 +94,14 @@ struct gs_buf { * (and thus for each /dev/ node). */ struct gs_port { + struct tty_port port; spinlock_t port_lock; /* guard port_* access */ struct gserial *port_usb; - struct tty_struct *port_tty; - unsigned open_count; bool openclose; /* open/close in progress */ u8 port_num; - wait_queue_head_t close_wait; /* wait for last close */ - struct list_head read_pool; int read_started; int read_allocated; @@ -412,8 +409,8 @@ __acquires(&port->port_lock) break; } - if (do_tty_wake && port->port_tty) - tty_wakeup(port->port_tty); + if (do_tty_wake && port->port.tty) + tty_wakeup(port->port.tty); return status; } @@ -435,7 +432,7 @@ __acquires(&port->port_lock) struct tty_struct *tty; /* no more rx if closed */ - tty = port->port_tty; + tty = port->port.tty; if (!tty) break; @@ -488,7 +485,7 @@ static void gs_rx_push(unsigned long _port) /* hand any queued data to the tty */ spin_lock_irq(&port->port_lock); - tty = port->port_tty; + tty = port->port.tty; while (!list_empty(queue)) { struct usb_request *req; @@ -699,7 +696,7 @@ static int gs_start_io(struct gs_port *port) /* unblock any pending writes into our circular buffer */ if (started) { - tty_wakeup(port->port_tty); + tty_wakeup(port->port.tty); } else { gs_free_requests(ep, head, &port->read_allocated); gs_free_requests(port->port_usb->in, &port->write_pool, @@ -734,9 +731,9 @@ static int gs_open(struct tty_struct *tty, struct file *file) spin_lock_irq(&port->port_lock); /* already open? Great. */ - if (port->open_count) { + if (port->port.count) { status = 0; - port->open_count++; + port->port.count++; /* currently opening/closing? wait ... */ } else if (port->openclose) { @@ -793,9 +790,9 @@ static int gs_open(struct tty_struct *tty, struct file *file) /* REVISIT maybe wait for "carrier detect" */ tty->driver_data = port; - port->port_tty = tty; + port->port.tty = tty; - port->open_count = 1; + port->port.count = 1; port->openclose = false; /* if connected, start the I/O stream */ @@ -837,11 +834,11 @@ static void gs_close(struct tty_struct *tty, struct file *file) spin_lock_irq(&port->port_lock); - if (port->open_count != 1) { - if (port->open_count == 0) + if (port->port.count != 1) { + if (port->port.count == 0) WARN_ON(1); else - --port->open_count; + --port->port.count; goto exit; } @@ -851,7 +848,7 @@ static void gs_close(struct tty_struct *tty, struct file *file) * and sleep if necessary */ port->openclose = true; - port->open_count = 0; + port->port.count = 0; gser = port->port_usb; if (gser && gser->disconnect) @@ -879,14 +876,14 @@ static void gs_close(struct tty_struct *tty, struct file *file) gs_buf_clear(&port->port_write_buf); tty->driver_data = NULL; - port->port_tty = NULL; + port->port.tty = NULL; port->openclose = false; pr_debug("gs_close: ttyGS%d (%p,%p) done!\n", port->port_num, tty, file); - wake_up_interruptible(&port->close_wait); + wake_up_interruptible(&port->port.close_wait); exit: spin_unlock_irq(&port->port_lock); } @@ -917,7 +914,7 @@ static int gs_put_char(struct tty_struct *tty, unsigned char ch) unsigned long flags; int status; - pr_vdebug("gs_put_char: (%d,%p) char=0x%x, called from %p\n", + pr_vdebug("gs_put_char: (%d,%p) char=0x%x, called from %pf\n", port->port_num, tty, ch, __builtin_return_address(0)); spin_lock_irqsave(&port->port_lock, flags); @@ -1025,7 +1022,7 @@ static const struct tty_operations gs_tty_ops = { static struct tty_driver *gs_tty_driver; -static int __init +static int gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding) { struct gs_port *port; @@ -1034,8 +1031,8 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding) if (port == NULL) return -ENOMEM; + tty_port_init(&port->port); spin_lock_init(&port->port_lock); - init_waitqueue_head(&port->close_wait); init_waitqueue_head(&port->drain_wait); tasklet_init(&port->push, gs_rx_push, (unsigned long) port); @@ -1071,7 +1068,7 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding) * * Returns negative errno or zero. */ -int __init gserial_setup(struct usb_gadget *g, unsigned count) +int gserial_setup(struct usb_gadget *g, unsigned count) { unsigned i; struct usb_cdc_line_coding coding; @@ -1155,7 +1152,7 @@ static int gs_closed(struct gs_port *port) int cond; spin_lock_irq(&port->port_lock); - cond = (port->open_count == 0) && !port->openclose; + cond = (port->port.count == 0) && !port->openclose; spin_unlock_irq(&port->port_lock); return cond; } @@ -1194,7 +1191,7 @@ void gserial_cleanup(void) tasklet_kill(&port->push); /* wait for old opens to finish */ - wait_event(port->close_wait, gs_closed(port)); + wait_event(port->port.close_wait, gs_closed(port)); WARN_ON(port->port_usb != NULL); @@ -1268,7 +1265,7 @@ int gserial_connect(struct gserial *gser, u8 port_num) /* if it's already open, start I/O ... and notify the serial * protocol about open/close status (connect/disconnect). */ - if (port->open_count) { + if (port->port.count) { pr_debug("gserial_connect: start ttyGS%d\n", port->port_num); gs_start_io(port); if (gser->connect) @@ -1315,10 +1312,10 @@ void gserial_disconnect(struct gserial *gser) port->port_usb = NULL; gser->ioport = NULL; - if (port->open_count > 0 || port->openclose) { + if (port->port.count > 0 || port->openclose) { wake_up_interruptible(&port->drain_wait); - if (port->port_tty) - tty_hangup(port->port_tty); + if (port->port.tty) + tty_hangup(port->port.tty); } spin_unlock_irqrestore(&port->port_lock, flags); @@ -1331,7 +1328,7 @@ void gserial_disconnect(struct gserial *gser) /* finally, free any unused/unusable I/O buffers */ spin_lock_irqsave(&port->port_lock, flags); - if (port->open_count == 0 && !port->openclose) + if (port->port.count == 0 && !port->openclose) gs_buf_free(&port->port_write_buf); gs_free_requests(gser->out, &port->read_pool, NULL); gs_free_requests(gser->out, &port->read_queue, NULL); diff --git a/trunk/drivers/usb/gadget/zero.c b/trunk/drivers/usb/gadget/zero.c index 31d34832907e..12ad516ada77 100644 --- a/trunk/drivers/usb/gadget/zero.c +++ b/trunk/drivers/usb/gadget/zero.c @@ -72,7 +72,7 @@ static const char longname[] = "Gadget Zero"; -unsigned buflen = 4096; +unsigned buflen = 4096; /* only used for bulk endpoints */ module_param(buflen, uint, 0); /* @@ -170,14 +170,17 @@ static struct usb_gadget_strings *dev_strings[] = { /*-------------------------------------------------------------------------*/ -struct usb_request *alloc_ep_req(struct usb_ep *ep) +struct usb_request *alloc_ep_req(struct usb_ep *ep, int len) { struct usb_request *req; req = usb_ep_alloc_request(ep, GFP_ATOMIC); if (req) { - req->length = buflen; - req->buf = kmalloc(buflen, GFP_ATOMIC); + if (len) + req->length = len; + else + req->length = buflen; + req->buf = kmalloc(req->length, GFP_ATOMIC); if (!req->buf) { usb_ep_free_request(ep, req); req = NULL; @@ -206,10 +209,15 @@ static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep) } void disable_endpoints(struct usb_composite_dev *cdev, - struct usb_ep *in, struct usb_ep *out) + struct usb_ep *in, struct usb_ep *out, + struct usb_ep *iso_in, struct usb_ep *iso_out) { disable_ep(cdev, in); disable_ep(cdev, out); + if (iso_in) + disable_ep(cdev, iso_in); + if (iso_out) + disable_ep(cdev, iso_out); } /*-------------------------------------------------------------------------*/ @@ -311,7 +319,6 @@ static int __init zero_bind(struct usb_composite_dev *cdev) device_desc.bcdDevice = cpu_to_le16(0x9999); } - INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname); snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", diff --git a/trunk/drivers/usb/host/Kconfig b/trunk/drivers/usb/host/Kconfig index f788eb86707c..83e58df29fe3 100644 --- a/trunk/drivers/usb/host/Kconfig +++ b/trunk/drivers/usb/host/Kconfig @@ -65,7 +65,7 @@ config USB_EHCI_HCD config USB_EHCI_ROOT_HUB_TT bool "Root Hub Transaction Translators" - depends on USB_EHCI_HCD + depends on USB_EHCI_HCD || USB_CHIPIDEA_HOST ---help--- Some EHCI chips have vendor-specific extensions to integrate transaction translators, so that no OHCI or UHCI companion @@ -77,7 +77,7 @@ config USB_EHCI_ROOT_HUB_TT config USB_EHCI_TT_NEWSCHED bool "Improved Transaction Translator scheduling" - depends on USB_EHCI_HCD + depends on USB_EHCI_HCD || USB_CHIPIDEA_HOST default y ---help--- This changes the periodic scheduling code to fill more of the low @@ -110,13 +110,14 @@ config USB_EHCI_BIG_ENDIAN_MMIO depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || \ ARCH_IXP4XX || XPS_USB_HCD_XILINX || \ PPC_MPC512x || CPU_CAVIUM_OCTEON || \ - PMC_MSP || SPARC_LEON) + PMC_MSP || SPARC_LEON || MIPS_SEAD3) default y config USB_EHCI_BIG_ENDIAN_DESC bool depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX || \ - PPC_MPC512x || PMC_MSP || SPARC_LEON) + PPC_MPC512x || PMC_MSP || SPARC_LEON || \ + MIPS_SEAD3) default y config XPS_USB_HCD_XILINX @@ -152,7 +153,7 @@ config USB_EHCI_HCD_OMAP bool "EHCI support for OMAP3 and later chips" depends on USB_EHCI_HCD && ARCH_OMAP default y - --- help --- + ---help--- Enables support for the on-chip EHCI controller on OMAP3 and later chips. @@ -291,6 +292,7 @@ config USB_OHCI_HCD depends on USB && USB_ARCH_HAS_OHCI select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 select USB_OTG_UTILS if ARCH_OMAP + select USB_ISP1301 if ARCH_LPC32XX || ARCH_PNX4008 ---help--- The Open Host Controller Interface (OHCI) is a standard for accessing USB 1.1 host controller hardware. It does more in hardware than Intel's @@ -373,10 +375,15 @@ config USB_OHCI_HCD_PCI If unsure, say Y. config USB_OHCI_HCD_SSB - bool "OHCI support for Broadcom SSB OHCI core" + bool "OHCI support for Broadcom SSB OHCI core (DEPRECATED)" depends on USB_OHCI_HCD && (SSB = y || SSB = USB_OHCI_HCD) && EXPERIMENTAL + select USB_HCD_SSB + select USB_OHCI_HCD_PLATFORM default n ---help--- + This option is deprecated now and the driver was removed, use + USB_HCD_SSB and USB_OHCI_HCD_PLATFORM instead. + Support for the Sonics Silicon Backplane (SSB) attached Broadcom USB OHCI core. @@ -638,3 +645,27 @@ config USB_OCTEON_OHCI config USB_OCTEON2_COMMON bool default y if USB_OCTEON_EHCI || USB_OCTEON_OHCI + +config USB_HCD_BCMA + tristate "BCMA usb host driver" + depends on BCMA && EXPERIMENTAL + select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD + select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD + help + Enbale support for the EHCI and OCHI host controller on an bcma bus. + It converts the bcma driver into two platform device drivers + for ehci and ohci. + + If unsure, say N. + +config USB_HCD_SSB + tristate "SSB usb host driver" + depends on SSB && EXPERIMENTAL + select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD + select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD + help + Enbale support for the EHCI and OCHI host controller on an bcma bus. + It converts the bcma driver into two platform device drivers + for ehci and ohci. + + If unsure, say N. diff --git a/trunk/drivers/usb/host/Makefile b/trunk/drivers/usb/host/Makefile index 0982bcc140bd..9e0a89ced15c 100644 --- a/trunk/drivers/usb/host/Makefile +++ b/trunk/drivers/usb/host/Makefile @@ -41,3 +41,5 @@ obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o obj-$(CONFIG_MIPS_ALCHEMY) += alchemy-common.o +obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o +obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o diff --git a/trunk/drivers/usb/host/bcma-hcd.c b/trunk/drivers/usb/host/bcma-hcd.c new file mode 100644 index 000000000000..443da21d73ca --- /dev/null +++ b/trunk/drivers/usb/host/bcma-hcd.c @@ -0,0 +1,335 @@ +/* + * Broadcom specific Advanced Microcontroller Bus + * Broadcom USB-core driver (BCMA bus glue) + * + * Copyright 2011-2012 Hauke Mehrtens + * + * Based on ssb-ohci driver + * Copyright 2007 Michael Buesch + * + * Derived from the OHCI-PCI driver + * Copyright 1999 Roman Weissgaerber + * Copyright 2000-2002 David Brownell + * Copyright 1999 Linus Torvalds + * Copyright 1999 Gregory P. Smith + * + * Derived from the USBcore related parts of Broadcom-SB + * Copyright 2005-2011 Broadcom Corporation + * + * Licensed under the GNU/GPL. See COPYING for details. + */ +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Hauke Mehrtens"); +MODULE_DESCRIPTION("Common USB driver for BCMA Bus"); +MODULE_LICENSE("GPL"); + +struct bcma_hcd_device { + struct platform_device *ehci_dev; + struct platform_device *ohci_dev; +}; + +/* Wait for bitmask in a register to get set or cleared. + * timeout is in units of ten-microseconds. + */ +static int bcma_wait_bits(struct bcma_device *dev, u16 reg, u32 bitmask, + int timeout) +{ + int i; + u32 val; + + for (i = 0; i < timeout; i++) { + val = bcma_read32(dev, reg); + if ((val & bitmask) == bitmask) + return 0; + udelay(10); + } + + return -ETIMEDOUT; +} + +static void __devinit bcma_hcd_4716wa(struct bcma_device *dev) +{ +#ifdef CONFIG_BCMA_DRIVER_MIPS + /* Work around for 4716 failures. */ + if (dev->bus->chipinfo.id == 0x4716) { + u32 tmp; + + tmp = bcma_cpu_clock(&dev->bus->drv_mips); + if (tmp >= 480000000) + tmp = 0x1846b; /* set CDR to 0x11(fast) */ + else if (tmp == 453000000) + tmp = 0x1046b; /* set CDR to 0x10(slow) */ + else + tmp = 0; + + /* Change Shim mdio control reg to fix host not acking at + * high frequencies + */ + if (tmp) { + bcma_write32(dev, 0x524, 0x1); /* write sel to enable */ + udelay(500); + + bcma_write32(dev, 0x524, tmp); + udelay(500); + bcma_write32(dev, 0x524, 0x4ab); + udelay(500); + bcma_read32(dev, 0x528); + bcma_write32(dev, 0x528, 0x80000000); + } + } +#endif /* CONFIG_BCMA_DRIVER_MIPS */ +} + +/* based on arch/mips/brcm-boards/bcm947xx/pcibios.c */ +static void __devinit bcma_hcd_init_chip(struct bcma_device *dev) +{ + u32 tmp; + + /* + * USB 2.0 special considerations: + * + * 1. Since the core supports both OHCI and EHCI functions, it must + * only be reset once. + * + * 2. In addition to the standard SI reset sequence, the Host Control + * Register must be programmed to bring the USB core and various + * phy components out of reset. + */ + if (!bcma_core_is_enabled(dev)) { + bcma_core_enable(dev, 0); + mdelay(10); + if (dev->id.rev >= 5) { + /* Enable Misc PLL */ + tmp = bcma_read32(dev, 0x1e0); + tmp |= 0x100; + bcma_write32(dev, 0x1e0, tmp); + if (bcma_wait_bits(dev, 0x1e0, 1 << 24, 100)) + printk(KERN_EMERG "Failed to enable misc PPL!\n"); + + /* Take out of resets */ + bcma_write32(dev, 0x200, 0x4ff); + udelay(25); + bcma_write32(dev, 0x200, 0x6ff); + udelay(25); + + /* Make sure digital and AFE are locked in USB PHY */ + bcma_write32(dev, 0x524, 0x6b); + udelay(50); + tmp = bcma_read32(dev, 0x524); + udelay(50); + bcma_write32(dev, 0x524, 0xab); + udelay(50); + tmp = bcma_read32(dev, 0x524); + udelay(50); + bcma_write32(dev, 0x524, 0x2b); + udelay(50); + tmp = bcma_read32(dev, 0x524); + udelay(50); + bcma_write32(dev, 0x524, 0x10ab); + udelay(50); + tmp = bcma_read32(dev, 0x524); + + if (bcma_wait_bits(dev, 0x528, 0xc000, 10000)) { + tmp = bcma_read32(dev, 0x528); + printk(KERN_EMERG + "USB20H mdio_rddata 0x%08x\n", tmp); + } + bcma_write32(dev, 0x528, 0x80000000); + tmp = bcma_read32(dev, 0x314); + udelay(265); + bcma_write32(dev, 0x200, 0x7ff); + udelay(10); + + /* Take USB and HSIC out of non-driving modes */ + bcma_write32(dev, 0x510, 0); + } else { + bcma_write32(dev, 0x200, 0x7ff); + + udelay(1); + } + + bcma_hcd_4716wa(dev); + } +} + +static const struct usb_ehci_pdata ehci_pdata = { +}; + +static const struct usb_ohci_pdata ohci_pdata = { +}; + +static struct platform_device * __devinit +bcma_hcd_create_pdev(struct bcma_device *dev, bool ohci, u32 addr) +{ + struct platform_device *hci_dev; + struct resource hci_res[2]; + int ret = -ENOMEM; + + memset(hci_res, 0, sizeof(hci_res)); + + hci_res[0].start = addr; + hci_res[0].end = hci_res[0].start + 0x1000 - 1; + hci_res[0].flags = IORESOURCE_MEM; + + hci_res[1].start = dev->irq; + hci_res[1].flags = IORESOURCE_IRQ; + + hci_dev = platform_device_alloc(ohci ? "ohci-platform" : + "ehci-platform" , 0); + if (!hci_dev) + return NULL; + + hci_dev->dev.parent = &dev->dev; + hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask; + + ret = platform_device_add_resources(hci_dev, hci_res, + ARRAY_SIZE(hci_res)); + if (ret) + goto err_alloc; + if (ohci) + ret = platform_device_add_data(hci_dev, &ohci_pdata, + sizeof(ohci_pdata)); + else + ret = platform_device_add_data(hci_dev, &ehci_pdata, + sizeof(ehci_pdata)); + if (ret) + goto err_alloc; + ret = platform_device_add(hci_dev); + if (ret) + goto err_alloc; + + return hci_dev; + +err_alloc: + platform_device_put(hci_dev); + return ERR_PTR(ret); +} + +static int __devinit bcma_hcd_probe(struct bcma_device *dev) +{ + int err; + u16 chipid_top; + u32 ohci_addr; + struct bcma_hcd_device *usb_dev; + struct bcma_chipinfo *chipinfo; + + chipinfo = &dev->bus->chipinfo; + /* USBcores are only connected on embedded devices. */ + chipid_top = (chipinfo->id & 0xFF00); + if (chipid_top != 0x4700 && chipid_top != 0x5300) + return -ENODEV; + + /* TODO: Probably need checks here; is the core connected? */ + + if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) || + dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32))) + return -EOPNOTSUPP; + + usb_dev = kzalloc(sizeof(struct bcma_hcd_device), GFP_KERNEL); + if (!usb_dev) + return -ENOMEM; + + bcma_hcd_init_chip(dev); + + /* In AI chips EHCI is addrspace 0, OHCI is 1 */ + ohci_addr = dev->addr1; + if ((chipinfo->id == 0x5357 || chipinfo->id == 0x4749) + && chipinfo->rev == 0) + ohci_addr = 0x18009000; + + usb_dev->ohci_dev = bcma_hcd_create_pdev(dev, true, ohci_addr); + if (IS_ERR(usb_dev->ohci_dev)) { + err = PTR_ERR(usb_dev->ohci_dev); + goto err_free_usb_dev; + } + + usb_dev->ehci_dev = bcma_hcd_create_pdev(dev, false, dev->addr); + if (IS_ERR(usb_dev->ehci_dev)) { + err = PTR_ERR(usb_dev->ehci_dev); + goto err_unregister_ohci_dev; + } + + bcma_set_drvdata(dev, usb_dev); + return 0; + +err_unregister_ohci_dev: + platform_device_unregister(usb_dev->ohci_dev); +err_free_usb_dev: + kfree(usb_dev); + return err; +} + +static void __devexit bcma_hcd_remove(struct bcma_device *dev) +{ + struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev); + struct platform_device *ohci_dev = usb_dev->ohci_dev; + struct platform_device *ehci_dev = usb_dev->ehci_dev; + + if (ohci_dev) + platform_device_unregister(ohci_dev); + if (ehci_dev) + platform_device_unregister(ehci_dev); + + bcma_core_disable(dev, 0); +} + +static void bcma_hcd_shutdown(struct bcma_device *dev) +{ + bcma_core_disable(dev, 0); +} + +#ifdef CONFIG_PM + +static int bcma_hcd_suspend(struct bcma_device *dev) +{ + bcma_core_disable(dev, 0); + + return 0; +} + +static int bcma_hcd_resume(struct bcma_device *dev) +{ + bcma_core_enable(dev, 0); + + return 0; +} + +#else /* !CONFIG_PM */ +#define bcma_hcd_suspend NULL +#define bcma_hcd_resume NULL +#endif /* CONFIG_PM */ + +static const struct bcma_device_id bcma_hcd_table[] __devinitconst = { + BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_USB20_HOST, BCMA_ANY_REV, BCMA_ANY_CLASS), + BCMA_CORETABLE_END +}; +MODULE_DEVICE_TABLE(bcma, bcma_hcd_table); + +static struct bcma_driver bcma_hcd_driver = { + .name = KBUILD_MODNAME, + .id_table = bcma_hcd_table, + .probe = bcma_hcd_probe, + .remove = __devexit_p(bcma_hcd_remove), + .shutdown = bcma_hcd_shutdown, + .suspend = bcma_hcd_suspend, + .resume = bcma_hcd_resume, +}; + +static int __init bcma_hcd_init(void) +{ + return bcma_driver_register(&bcma_hcd_driver); +} +module_init(bcma_hcd_init); + +static void __exit bcma_hcd_exit(void) +{ + bcma_driver_unregister(&bcma_hcd_driver); +} +module_exit(bcma_hcd_exit); diff --git a/trunk/drivers/usb/host/ehci-dbg.c b/trunk/drivers/usb/host/ehci-dbg.c index 680e1a31fb87..7561966fbdc4 100644 --- a/trunk/drivers/usb/host/ehci-dbg.c +++ b/trunk/drivers/usb/host/ehci-dbg.c @@ -1025,10 +1025,8 @@ static ssize_t debug_lpm_write(struct file *file, const char __user *user_buf, if (strict_strtoul(buf + 5, 16, &hird)) return -EINVAL; printk(KERN_INFO "setting hird %s %lu\n", buf + 6, hird); - temp = ehci_readl(ehci, &ehci->regs->command); - temp &= ~CMD_HIRD; - temp |= hird << 24; - ehci_writel(ehci, temp, &ehci->regs->command); + ehci->command = (ehci->command & ~CMD_HIRD) | (hird << 24); + ehci_writel(ehci, ehci->command, &ehci->regs->command); } else if (strncmp(buf, "disable", 7) == 0) { if (strict_strtoul(buf + 8, 10, &port)) return -EINVAL; diff --git a/trunk/drivers/usb/host/ehci-fsl.c b/trunk/drivers/usb/host/ehci-fsl.c index d0a84bd3f3eb..43362577b54a 100644 --- a/trunk/drivers/usb/host/ehci-fsl.c +++ b/trunk/drivers/usb/host/ehci-fsl.c @@ -1,6 +1,6 @@ /* * Copyright 2005-2009 MontaVista Software, Inc. - * Copyright 2008 Freescale Semiconductor, Inc. + * Copyright 2008,2012 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 @@ -150,8 +150,7 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver, retval = otg_set_host(ehci->transceiver->otg, &ehci_to_hcd(ehci)->self); if (retval) { - if (ehci->transceiver) - put_device(ehci->transceiver->dev); + usb_put_transceiver(ehci->transceiver); goto err4; } } else { @@ -195,7 +194,7 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd, if (ehci->transceiver) { otg_set_host(ehci->transceiver->otg, NULL); - put_device(ehci->transceiver->dev); + usb_put_transceiver(ehci->transceiver); } usb_remove_hcd(hcd); @@ -211,22 +210,32 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd, usb_put_hcd(hcd); } -static void ehci_fsl_setup_phy(struct ehci_hcd *ehci, +static void ehci_fsl_setup_phy(struct usb_hcd *hcd, enum fsl_usb2_phy_modes phy_mode, unsigned int port_offset) { - u32 portsc; - struct usb_hcd *hcd = ehci_to_hcd(ehci); + u32 portsc, temp; + struct ehci_hcd *ehci = hcd_to_ehci(hcd); void __iomem *non_ehci = hcd->regs; - struct fsl_usb2_platform_data *pdata; + struct device *dev = hcd->self.controller; + struct fsl_usb2_platform_data *pdata = dev->platform_data; - pdata = hcd->self.controller->platform_data; + if (pdata->controller_ver < 0) { + dev_warn(hcd->self.controller, "Could not get controller version\n"); + return; + } portsc = ehci_readl(ehci, &ehci->regs->port_status[port_offset]); portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW); switch (phy_mode) { case FSL_USB2_PHY_ULPI: + if (pdata->controller_ver) { + /* controller version 1.6 or above */ + temp = in_be32(non_ehci + FSL_SOC_USB_CTRL); + out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | + USB_CTRL_USB_EN | ULPI_PHY_CLK_SEL); + } portsc |= PORT_PTS_ULPI; break; case FSL_USB2_PHY_SERIAL: @@ -236,6 +245,14 @@ static void ehci_fsl_setup_phy(struct ehci_hcd *ehci, portsc |= PORT_PTS_PTW; /* fall through */ case FSL_USB2_PHY_UTMI: + if (pdata->controller_ver) { + /* controller version 1.6 or above */ + temp = in_be32(non_ehci + FSL_SOC_USB_CTRL); + out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | + UTMI_PHY_EN | USB_CTRL_USB_EN); + mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI PHY CLK to + become stable - 10ms*/ + } /* enable UTMI PHY */ if (pdata->have_sysif_regs) setbits32(non_ehci + FSL_SOC_USB_CTRL, @@ -276,7 +293,7 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci) if ((pdata->operating_mode == FSL_USB2_DR_HOST) || (pdata->operating_mode == FSL_USB2_DR_OTG)) - ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0); + ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0); if (pdata->operating_mode == FSL_USB2_MPH_HOST) { unsigned int chip, rev, svr; @@ -290,9 +307,9 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci) ehci->has_fsl_port_bug = 1; if (pdata->port_enables & FSL_USB2_PORT0_ENABLED) - ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0); + ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0); if (pdata->port_enables & FSL_USB2_PORT1_ENABLED) - ehci_fsl_setup_phy(ehci, pdata->phy_mode, 1); + ehci_fsl_setup_phy(hcd, pdata->phy_mode, 1); } if (pdata->have_sysif_regs) { diff --git a/trunk/drivers/usb/host/ehci-fsl.h b/trunk/drivers/usb/host/ehci-fsl.h index 863fb0c080d7..88403684d10b 100644 --- a/trunk/drivers/usb/host/ehci-fsl.h +++ b/trunk/drivers/usb/host/ehci-fsl.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2005-2010 Freescale Semiconductor, Inc. +/* Copyright (C) 2005-2010,2012 Freescale Semiconductor, Inc. * Copyright (c) 2005 MontaVista Software * * This program is free software; you can redistribute it and/or modify it @@ -50,4 +50,15 @@ #define CTRL_UTMI_PHY_EN (1<<9) #define CTRL_PHY_CLK_VALID (1 << 17) #define SNOOP_SIZE_2GB 0x1e + +/* control Register Bit Masks */ +#define ULPI_INT_EN (1<<0) +#define WU_INT_EN (1<<1) +#define USB_CTRL_USB_EN (1<<2) +#define LINE_STATE_FILTER__EN (1<<3) +#define KEEP_OTG_ON (1<<4) +#define OTG_PORT (1<<5) +#define PLL_RESET (1<<8) +#define UTMI_PHY_EN (1<<9) +#define ULPI_PHY_CLK_SEL (1<<10) #endif /* _EHCI_FSL_H */ diff --git a/trunk/drivers/usb/host/ehci-hcd.c b/trunk/drivers/usb/host/ehci-hcd.c index 4a3bc5b7a06f..b100f5f9f4b6 100644 --- a/trunk/drivers/usb/host/ehci-hcd.c +++ b/trunk/drivers/usb/host/ehci-hcd.c @@ -226,8 +226,13 @@ static int ehci_halt (struct ehci_hcd *ehci) if ((temp & STS_HALT) != 0) return 0; + /* + * This routine gets called during probe before ehci->command + * has been initialized, so we can't rely on its value. + */ + ehci->command &= ~CMD_RUN; temp = ehci_readl(ehci, &ehci->regs->command); - temp &= ~CMD_RUN; + temp &= ~(CMD_RUN | CMD_IAAD); ehci_writel(ehci, temp, &ehci->regs->command); return handshake (ehci, &ehci->regs->status, STS_HALT, STS_HALT, 16 * 125); @@ -363,16 +368,14 @@ static void ehci_quiesce (struct ehci_hcd *ehci) #endif /* wait for any schedule enables/disables to take effect */ - temp = ehci_readl(ehci, &ehci->regs->command) << 10; - temp &= STS_ASS | STS_PSS; + temp = (ehci->command << 10) & (STS_ASS | STS_PSS); if (handshake_on_error_set_halt(ehci, &ehci->regs->status, STS_ASS | STS_PSS, temp, 16 * 125)) return; /* then disable anything that's still active */ - temp = ehci_readl(ehci, &ehci->regs->command); - temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE); - ehci_writel(ehci, temp, &ehci->regs->command); + ehci->command &= ~(CMD_ASE | CMD_PSE); + ehci_writel(ehci, ehci->command, &ehci->regs->command); /* hardware can take 16 microframes to turn off ... */ handshake_on_error_set_halt(ehci, &ehci->regs->status, @@ -417,9 +420,6 @@ static void ehci_iaa_watchdog(unsigned long param) * CMD_IAAD when it sets STS_IAA.) */ cmd = ehci_readl(ehci, &ehci->regs->command); - if (cmd & CMD_IAAD) - ehci_writel(ehci, cmd & ~CMD_IAAD, - &ehci->regs->command); /* If IAA is set here it either legitimately triggered * before we cleared IAAD above (but _way_ late, so we'll @@ -894,11 +894,8 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) /* complete the unlinking of some qh [4.15.2.3] */ if (status & STS_IAA) { /* guard against (alleged) silicon errata */ - if (cmd & CMD_IAAD) { - ehci_writel(ehci, cmd & ~CMD_IAAD, - &ehci->regs->command); + if (cmd & CMD_IAAD) ehci_dbg(ehci, "IAA with IAAD still set?\n"); - } if (ehci->reclaim) { COUNT(ehci->stats.reclaim); end_unlink_async(ehci); @@ -1248,6 +1245,13 @@ static int ehci_get_frame (struct usb_hcd *hcd) } /*-------------------------------------------------------------------------*/ +/* + * The EHCI in ChipIdea HDRC cannot be a separate module or device, + * because its registers (and irq) are shared between host/gadget/otg + * functions and in order to facilitate role switching we cannot + * give the ehci driver exclusive access to those. + */ +#ifndef CHIPIDEA_EHCI MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR (DRIVER_AUTHOR); @@ -1378,6 +1382,11 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_ls1x_driver #endif +#ifdef CONFIG_MIPS_SEAD3 +#include "ehci-sead3.c" +#define PLATFORM_DRIVER ehci_hcd_sead3_driver +#endif + #ifdef CONFIG_USB_EHCI_HCD_PLATFORM #include "ehci-platform.c" #define PLATFORM_DRIVER ehci_platform_driver @@ -1501,3 +1510,4 @@ static void __exit ehci_hcd_cleanup(void) } module_exit(ehci_hcd_cleanup); +#endif /* CHIPIDEA_EHCI */ diff --git a/trunk/drivers/usb/host/ehci-hub.c b/trunk/drivers/usb/host/ehci-hub.c index 38fe07623152..fc9e7cc6ac9b 100644 --- a/trunk/drivers/usb/host/ehci-hub.c +++ b/trunk/drivers/usb/host/ehci-hub.c @@ -233,7 +233,6 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) /* stop schedules, clean any completed work */ if (ehci->rh_state == EHCI_RH_RUNNING) ehci_quiesce (ehci); - ehci->command = ehci_readl(ehci, &ehci->regs->command); ehci_work(ehci); /* Unlike other USB host controller types, EHCI doesn't have @@ -374,6 +373,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd) ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next); /* restore CMD_RUN, framelist size, and irq threshold */ + ehci->command |= CMD_RUN; ehci_writel(ehci, ehci->command, &ehci->regs->command); ehci->rh_state = EHCI_RH_RUNNING; @@ -531,7 +531,8 @@ static int check_reset_complete ( if (ehci->has_amcc_usb23) set_ohci_hcfs(ehci, 1); } else { - ehci_dbg (ehci, "port %d high speed\n", index + 1); + ehci_dbg(ehci, "port %d reset complete, port enabled\n", + index + 1); /* ensure 440EPx ohci controller state is suspended */ if (ehci->has_amcc_usb23) set_ohci_hcfs(ehci, 0); @@ -699,6 +700,7 @@ static int ehci_hub_control ( goto error; wIndex--; temp = ehci_readl(ehci, status_reg); + temp &= ~PORT_RWC_BITS; /* * Even if OWNER is set, so the port is owned by the @@ -712,8 +714,7 @@ static int ehci_hub_control ( ehci_writel(ehci, temp & ~PORT_PE, status_reg); break; case USB_PORT_FEAT_C_ENABLE: - ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_PEC, - status_reg); + ehci_writel(ehci, temp | PORT_PEC, status_reg); break; case USB_PORT_FEAT_SUSPEND: if (temp & PORT_RESET) @@ -742,7 +743,7 @@ static int ehci_hub_control ( spin_lock_irqsave(&ehci->lock, flags); } /* resume signaling for 20 msec */ - temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); + temp &= ~PORT_WAKE_BITS; ehci_writel(ehci, temp | PORT_RESUME, status_reg); ehci->reset_done[wIndex] = jiffies + msecs_to_jiffies(20); @@ -752,9 +753,8 @@ static int ehci_hub_control ( break; case USB_PORT_FEAT_POWER: if (HCS_PPC (ehci->hcs_params)) - ehci_writel(ehci, - temp & ~(PORT_RWC_BITS | PORT_POWER), - status_reg); + ehci_writel(ehci, temp & ~PORT_POWER, + status_reg); break; case USB_PORT_FEAT_C_CONNECTION: if (ehci->has_lpm) { @@ -762,12 +762,10 @@ static int ehci_hub_control ( temp &= ~PORT_LPM; temp &= ~PORT_DEV_ADDR; } - ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC, - status_reg); + ehci_writel(ehci, temp | PORT_CSC, status_reg); break; case USB_PORT_FEAT_C_OVER_CURRENT: - ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_OCC, - status_reg); + ehci_writel(ehci, temp | PORT_OCC, status_reg); break; case USB_PORT_FEAT_C_RESET: /* GetPortStatus clears reset */ diff --git a/trunk/drivers/usb/host/ehci-omap.c b/trunk/drivers/usb/host/ehci-omap.c index 5c78f9e71466..a44294d13494 100644 --- a/trunk/drivers/usb/host/ehci-omap.c +++ b/trunk/drivers/usb/host/ehci-omap.c @@ -242,15 +242,6 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) ehci_reset(omap_ehci); - ret = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (ret) { - dev_err(dev, "failed to add hcd with err %d\n", ret); - goto err_add_hcd; - } - - /* root ports should always stay powered */ - ehci_port_power(omap_ehci, 1); - if (pdata->phy_reset) { /* Hold the PHY in RESET for enough time till * PHY is settled and ready @@ -258,12 +249,21 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) udelay(10); if (gpio_is_valid(pdata->reset_gpio_port[0])) - gpio_set_value(pdata->reset_gpio_port[0], 1); + gpio_set_value_cansleep(pdata->reset_gpio_port[0], 1); if (gpio_is_valid(pdata->reset_gpio_port[1])) - gpio_set_value(pdata->reset_gpio_port[1], 1); + gpio_set_value_cansleep(pdata->reset_gpio_port[1], 1); } + ret = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (ret) { + dev_err(dev, "failed to add hcd with err %d\n", ret); + goto err_add_hcd; + } + + /* root ports should always stay powered */ + ehci_port_power(omap_ehci, 1); + return 0; err_add_hcd: diff --git a/trunk/drivers/usb/host/ehci-pci.c b/trunk/drivers/usb/host/ehci-pci.c index fe8dc069164e..bc94d7bf072d 100644 --- a/trunk/drivers/usb/host/ehci-pci.c +++ b/trunk/drivers/usb/host/ehci-pci.c @@ -368,7 +368,9 @@ static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev) { return pdev->class == PCI_CLASS_SERIAL_USB_EHCI && pdev->vendor == PCI_VENDOR_ID_INTEL && - pdev->device == 0x1E26; + (pdev->device == 0x1E26 || + pdev->device == 0x8C2D || + pdev->device == 0x8C26); } static void ehci_enable_xhci_companion(void) diff --git a/trunk/drivers/usb/host/ehci-platform.c b/trunk/drivers/usb/host/ehci-platform.c index d238b4e24bb6..dfe881a34ae2 100644 --- a/trunk/drivers/usb/host/ehci-platform.c +++ b/trunk/drivers/usb/host/ehci-platform.c @@ -75,8 +75,6 @@ static const struct hc_driver ehci_platform_hc_driver = { .relinquish_port = ehci_relinquish_port, .port_handed_over = ehci_port_handed_over, - .update_device = ehci_update_device, - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, }; @@ -94,12 +92,12 @@ static int __devinit ehci_platform_probe(struct platform_device *dev) irq = platform_get_irq(dev, 0); if (irq < 0) { - pr_err("no irq provieded"); + pr_err("no irq provided"); return irq; } res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0); if (!res_mem) { - pr_err("no memory recourse provieded"); + pr_err("no memory recourse provided"); return -ENXIO; } diff --git a/trunk/drivers/usb/host/ehci-q.c b/trunk/drivers/usb/host/ehci-q.c index 36ca5077cdf7..4378bf72bbac 100644 --- a/trunk/drivers/usb/host/ehci-q.c +++ b/trunk/drivers/usb/host/ehci-q.c @@ -943,7 +943,8 @@ qh_make ( } break; default: - dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed); + ehci_dbg(ehci, "bogus dev %p speed %d\n", urb->dev, + urb->dev->speed); done: qh_put (qh); return NULL; @@ -981,14 +982,12 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) head = ehci->async; timer_action_done (ehci, TIMER_ASYNC_OFF); if (!head->qh_next.qh) { - u32 cmd = ehci_readl(ehci, &ehci->regs->command); - - if (!(cmd & CMD_ASE)) { + if (!(ehci->command & CMD_ASE)) { /* in case a clear of CMD_ASE didn't take yet */ (void)handshake(ehci, &ehci->regs->status, STS_ASS, 0, 150); - cmd |= CMD_ASE; - ehci_writel(ehci, cmd, &ehci->regs->command); + ehci->command |= CMD_ASE; + ehci_writel(ehci, ehci->command, &ehci->regs->command); /* posted write need not be known to HC yet ... */ } } @@ -1204,7 +1203,6 @@ static void end_unlink_async (struct ehci_hcd *ehci) static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) { - int cmd = ehci_readl(ehci, &ehci->regs->command); struct ehci_qh *prev; #ifdef DEBUG @@ -1222,8 +1220,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) if (ehci->rh_state != EHCI_RH_HALTED && !ehci->reclaim) { /* ... and CMD_IAAD clear */ - ehci_writel(ehci, cmd & ~CMD_ASE, - &ehci->regs->command); + ehci->command &= ~CMD_ASE; + ehci_writel(ehci, ehci->command, &ehci->regs->command); wmb (); // handshake later, if we need to timer_action_done (ehci, TIMER_ASYNC_OFF); @@ -1253,8 +1251,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) return; } - cmd |= CMD_IAAD; - ehci_writel(ehci, cmd, &ehci->regs->command); + ehci_writel(ehci, ehci->command | CMD_IAAD, &ehci->regs->command); (void)ehci_readl(ehci, &ehci->regs->command); iaa_watchdog_start(ehci); } diff --git a/trunk/drivers/usb/host/ehci-s5p.c b/trunk/drivers/usb/host/ehci-s5p.c index f098e2a291a0..c474cec064e4 100644 --- a/trunk/drivers/usb/host/ehci-s5p.c +++ b/trunk/drivers/usb/host/ehci-s5p.c @@ -232,6 +232,8 @@ static int s5p_ehci_suspend(struct device *dev) if (pdata && pdata->phy_exit) pdata->phy_exit(pdev, S5P_USB_PHY_HOST); + clk_disable(s5p_ehci->clk); + return rc; } @@ -243,6 +245,8 @@ static int s5p_ehci_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; + clk_enable(s5p_ehci->clk); + if (pdata && pdata->phy_init) pdata->phy_init(pdev, S5P_USB_PHY_HOST); diff --git a/trunk/drivers/usb/host/ehci-sched.c b/trunk/drivers/usb/host/ehci-sched.c index a60679cbbf85..33182c6d1ff9 100644 --- a/trunk/drivers/usb/host/ehci-sched.c +++ b/trunk/drivers/usb/host/ehci-sched.c @@ -481,7 +481,6 @@ static int tt_no_collision ( static int enable_periodic (struct ehci_hcd *ehci) { - u32 cmd; int status; if (ehci->periodic_sched++) @@ -497,8 +496,8 @@ static int enable_periodic (struct ehci_hcd *ehci) return status; } - cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE; - ehci_writel(ehci, cmd, &ehci->regs->command); + ehci->command |= CMD_PSE; + ehci_writel(ehci, ehci->command, &ehci->regs->command); /* posted write ... PSS happens later */ /* make sure ehci_work scans these */ @@ -511,7 +510,6 @@ static int enable_periodic (struct ehci_hcd *ehci) static int disable_periodic (struct ehci_hcd *ehci) { - u32 cmd; int status; if (--ehci->periodic_sched) @@ -537,8 +535,8 @@ static int disable_periodic (struct ehci_hcd *ehci) return status; } - cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE; - ehci_writel(ehci, cmd, &ehci->regs->command); + ehci->command &= ~CMD_PSE; + ehci_writel(ehci, ehci->command, &ehci->regs->command); /* posted write ... */ free_cached_lists(ehci); @@ -1333,34 +1331,36 @@ sitd_slot_ok ( if (mask & ~0xffff) return 0; + /* check bandwidth */ + uframe %= period_uframes; + frame = uframe >> 3; + +#ifdef CONFIG_USB_EHCI_TT_NEWSCHED + /* The tt's fullspeed bus bandwidth must be available. + * tt_available scheduling guarantees 10+% for control/bulk. + */ + uf = uframe & 7; + if (!tt_available(ehci, period_uframes >> 3, + stream->udev, frame, uf, stream->tt_usecs)) + return 0; +#else + /* tt must be idle for start(s), any gap, and csplit. + * assume scheduling slop leaves 10+% for control/bulk. + */ + if (!tt_no_collision(ehci, period_uframes >> 3, + stream->udev, frame, mask)) + return 0; +#endif + /* this multi-pass logic is simple, but performance may * suffer when the schedule data isn't cached. */ - - /* check bandwidth */ - uframe %= period_uframes; do { u32 max_used; frame = uframe >> 3; uf = uframe & 7; -#ifdef CONFIG_USB_EHCI_TT_NEWSCHED - /* The tt's fullspeed bus bandwidth must be available. - * tt_available scheduling guarantees 10+% for control/bulk. - */ - if (!tt_available (ehci, period_uframes << 3, - stream->udev, frame, uf, stream->tt_usecs)) - return 0; -#else - /* tt must be idle for start(s), any gap, and csplit. - * assume scheduling slop leaves 10+% for control/bulk. - */ - if (!tt_no_collision (ehci, period_uframes << 3, - stream->udev, frame, mask)) - return 0; -#endif - /* check starts (OUT uses more than one) */ max_used = ehci->uframe_periodic_max - stream->usecs; for (tmp = stream->raw_mask & 0xff; tmp; tmp >>= 1, uf++) { @@ -2358,7 +2358,8 @@ scan_periodic (struct ehci_hcd *ehci) * in the previous frame for completions. */ if (q.fstn->hw_prev != EHCI_LIST_END(ehci)) { - dbg ("ignoring completions from FSTNs"); + ehci_dbg(ehci, + "ignoring completions from FSTNs\n"); } type = Q_NEXT_TYPE(ehci, q.fstn->hw_next); q = q.fstn->fstn_next; @@ -2441,7 +2442,7 @@ scan_periodic (struct ehci_hcd *ehci) q = *q_p; break; default: - dbg ("corrupt type %d frame %d shadow %p", + ehci_dbg(ehci, "corrupt type %d frame %d shadow %p\n", type, frame, q.ptr); // BUG (); q.ptr = NULL; diff --git a/trunk/drivers/usb/host/ehci-sead3.c b/trunk/drivers/usb/host/ehci-sead3.c new file mode 100644 index 000000000000..cc199e87a7a9 --- /dev/null +++ b/trunk/drivers/usb/host/ehci-sead3.c @@ -0,0 +1,266 @@ +/* + * MIPS CI13320A EHCI Host Controller driver + * Based on "ehci-au1xxx.c" by K.Boge + * + * Copyright (C) 2012 MIPS Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +static int ehci_sead3_setup(struct usb_hcd *hcd) +{ + int ret; + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + + ehci->caps = hcd->regs + 0x100; + +#ifdef __BIG_ENDIAN + ehci->big_endian_mmio = 1; + ehci->big_endian_desc = 1; +#endif + + ret = ehci_setup(hcd); + if (ret) + return ret; + + ehci->need_io_watchdog = 0; + + /* Set burst length to 16 words. */ + ehci_writel(ehci, 0x1010, &ehci->regs->reserved[1]); + + return ret; +} + +const struct hc_driver ehci_sead3_hc_driver = { + .description = hcd_name, + .product_desc = "SEAD-3 EHCI", + .hcd_priv_size = sizeof(struct ehci_hcd), + + /* + * generic hardware linkage + */ + .irq = ehci_irq, + .flags = HCD_MEMORY | HCD_USB2, + + /* + * basic lifecycle operations + * + */ + .reset = ehci_sead3_setup, + .start = ehci_run, + .stop = ehci_stop, + .shutdown = ehci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + .endpoint_reset = ehci_endpoint_reset, + + /* + * scheduling support + */ + .get_frame_number = ehci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, + .relinquish_port = ehci_relinquish_port, + .port_handed_over = ehci_port_handed_over, + + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, +}; + +static int ehci_hcd_sead3_drv_probe(struct platform_device *pdev) +{ + struct usb_hcd *hcd; + struct resource *res; + int ret; + + if (usb_disabled()) + return -ENODEV; + + if (pdev->resource[1].flags != IORESOURCE_IRQ) { + pr_debug("resource[1] is not IORESOURCE_IRQ"); + return -ENOMEM; + } + hcd = usb_create_hcd(&ehci_sead3_hc_driver, &pdev->dev, "SEAD-3"); + if (!hcd) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { + pr_debug("request_mem_region failed"); + ret = -EBUSY; + goto err1; + } + + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) { + pr_debug("ioremap failed"); + ret = -ENOMEM; + goto err2; + } + + /* Root hub has integrated TT. */ + hcd->has_tt = 1; + + ret = usb_add_hcd(hcd, pdev->resource[1].start, + IRQF_SHARED); + if (ret == 0) { + platform_set_drvdata(pdev, hcd); + return ret; + } + + iounmap(hcd->regs); +err2: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); +err1: + usb_put_hcd(hcd); + return ret; +} + +static int ehci_hcd_sead3_drv_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + usb_remove_hcd(hcd); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +#ifdef CONFIG_PM +static int ehci_hcd_sead3_drv_suspend(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + unsigned long flags; + int rc = 0; + + if (time_before(jiffies, ehci->next_statechange)) + msleep(20); + + /* Root hub was already suspended. Disable irq emission and + * mark HW unaccessible. The PM and USB cores make sure that + * the root hub is either suspended or stopped. + */ + ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev)); + spin_lock_irqsave(&ehci->lock, flags); + ehci_writel(ehci, 0, &ehci->regs->intr_enable); + (void)ehci_readl(ehci, &ehci->regs->intr_enable); + + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + spin_unlock_irqrestore(&ehci->lock, flags); + + /* could save FLADJ in case of Vaux power loss + * ... we'd only use it to handle clock skew + */ + + return rc; +} + +static int ehci_hcd_sead3_drv_resume(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + + /* maybe restore FLADJ. */ + + if (time_before(jiffies, ehci->next_statechange)) + msleep(100); + + /* Mark hardware accessible again as we are out of D3 state by now */ + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + + /* If CF is still set, we maintained PCI Vaux power. + * Just undo the effect of ehci_pci_suspend(). + */ + if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) { + int mask = INTR_MASK; + + ehci_prepare_ports_for_controller_resume(ehci); + if (!hcd->self.root_hub->do_remote_wakeup) + mask &= ~STS_PCD; + ehci_writel(ehci, mask, &ehci->regs->intr_enable); + ehci_readl(ehci, &ehci->regs->intr_enable); + return 0; + } + + ehci_dbg(ehci, "lost power, restarting\n"); + usb_root_hub_lost_power(hcd->self.root_hub); + + /* Else reset, to cope with power loss or flush-to-storage + * style "resume" having let BIOS kick in during reboot. + */ + (void) ehci_halt(ehci); + (void) ehci_reset(ehci); + + /* emptying the schedule aborts any urbs */ + spin_lock_irq(&ehci->lock); + if (ehci->reclaim) + end_unlink_async(ehci); + ehci_work(ehci); + spin_unlock_irq(&ehci->lock); + + ehci_writel(ehci, ehci->command, &ehci->regs->command); + ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); + ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ + + /* here we "know" root ports should always stay powered */ + ehci_port_power(ehci, 1); + + ehci->rh_state = EHCI_RH_SUSPENDED; + + return 0; +} + +static const struct dev_pm_ops sead3_ehci_pmops = { + .suspend = ehci_hcd_sead3_drv_suspend, + .resume = ehci_hcd_sead3_drv_resume, +}; + +#define SEAD3_EHCI_PMOPS (&sead3_ehci_pmops) + +#else +#define SEAD3_EHCI_PMOPS NULL +#endif + +static struct platform_driver ehci_hcd_sead3_driver = { + .probe = ehci_hcd_sead3_drv_probe, + .remove = ehci_hcd_sead3_drv_remove, + .shutdown = usb_hcd_platform_shutdown, + .driver = { + .name = "sead3-ehci", + .owner = THIS_MODULE, + .pm = SEAD3_EHCI_PMOPS, + } +}; + +MODULE_ALIAS("platform:sead3-ehci"); diff --git a/trunk/drivers/usb/host/ehci-sh.c b/trunk/drivers/usb/host/ehci-sh.c index 9d9cf47d80da..ca819cdd0c5e 100644 --- a/trunk/drivers/usb/host/ehci-sh.c +++ b/trunk/drivers/usb/host/ehci-sh.c @@ -11,6 +11,7 @@ */ #include #include +#include struct ehci_sh_priv { struct clk *iclk, *fclk; @@ -100,6 +101,7 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev) const struct hc_driver *driver = &ehci_sh_hc_driver; struct resource *res; struct ehci_sh_priv *priv; + struct ehci_sh_platdata *pdata; struct usb_hcd *hcd; int irq, ret; @@ -124,6 +126,9 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev) goto fail_create_hcd; } + if (pdev->dev.platform_data != NULL) + pdata = pdev->dev.platform_data; + /* initialize hcd */ hcd = usb_create_hcd(&ehci_sh_hc_driver, &pdev->dev, dev_name(&pdev->dev)); @@ -168,6 +173,9 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev) clk_enable(priv->fclk); clk_enable(priv->iclk); + if (pdata && pdata->phy_init) + pdata->phy_init(); + ret = usb_add_hcd(hcd, irq, IRQF_SHARED); if (ret != 0) { dev_err(&pdev->dev, "Failed to add hcd"); diff --git a/trunk/drivers/usb/host/ehci-spear.c b/trunk/drivers/usb/host/ehci-spear.c index 6e928559169c..37ba8c8d2fd0 100644 --- a/trunk/drivers/usb/host/ehci-spear.c +++ b/trunk/drivers/usb/host/ehci-spear.c @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -25,12 +26,12 @@ struct spear_ehci { static void spear_start_ehci(struct spear_ehci *ehci) { - clk_enable(ehci->clk); + clk_prepare_enable(ehci->clk); } static void spear_stop_ehci(struct spear_ehci *ehci) { - clk_disable(ehci->clk); + clk_disable_unprepare(ehci->clk); } static int ehci_spear_setup(struct usb_hcd *hcd) @@ -168,6 +169,8 @@ static int ehci_spear_drv_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(ehci_spear_pm_ops, ehci_spear_drv_suspend, ehci_spear_drv_resume); +static u64 spear_ehci_dma_mask = DMA_BIT_MASK(32); + static int spear_ehci_hcd_drv_probe(struct platform_device *pdev) { struct usb_hcd *hcd ; @@ -175,12 +178,9 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev) struct resource *res; struct clk *usbh_clk; const struct hc_driver *driver = &ehci_spear_hc_driver; - int *pdata = pdev->dev.platform_data; int irq, retval; char clk_name[20] = "usbh_clk"; - - if (pdata == NULL) - return -EFAULT; + static int instance = -1; if (usb_disabled()) return -ENODEV; @@ -191,8 +191,22 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev) goto fail_irq_get; } - if (*pdata >= 0) - sprintf(clk_name, "usbh.%01d_clk", *pdata); + /* + * Right now device-tree probed devices don't get dma_mask set. + * Since shared usb code relies on it, set it here for now. + * Once we have dma capability bindings this can go away. + */ + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &spear_ehci_dma_mask; + + /* + * Increment the device instance, when probing via device-tree + */ + if (pdev->id < 0) + instance++; + else + instance = pdev->id; + sprintf(clk_name, "usbh.%01d_clk", instance); usbh_clk = clk_get(NULL, clk_name); if (IS_ERR(usbh_clk)) { @@ -277,6 +291,11 @@ static int spear_ehci_hcd_drv_remove(struct platform_device *pdev) return 0; } +static struct of_device_id spear_ehci_id_table[] __devinitdata = { + { .compatible = "st,spear600-ehci", }, + { }, +}; + static struct platform_driver spear_ehci_hcd_driver = { .probe = spear_ehci_hcd_drv_probe, .remove = spear_ehci_hcd_drv_remove, @@ -285,6 +304,7 @@ static struct platform_driver spear_ehci_hcd_driver = { .name = "spear-ehci", .bus = &platform_bus_type, .pm = &ehci_spear_pm_ops, + .of_match_table = of_match_ptr(spear_ehci_id_table), } }; diff --git a/trunk/drivers/usb/host/ehci-tegra.c b/trunk/drivers/usb/host/ehci-tegra.c index f214a80cdee2..4a44bf833611 100644 --- a/trunk/drivers/usb/host/ehci-tegra.c +++ b/trunk/drivers/usb/host/ehci-tegra.c @@ -147,18 +147,7 @@ static int tegra_ehci_hub_control( spin_lock_irqsave(&ehci->lock, flags); - /* - * In ehci_hub_control() for USB_PORT_FEAT_ENABLE clears the other bits - * that are write on clear, by writing back the register read value, so - * USB_PORT_FEAT_ENABLE is handled by masking the set on clear bits - */ - if (typeReq == ClearPortFeature && wValue == USB_PORT_FEAT_ENABLE) { - temp = ehci_readl(ehci, status_reg) & ~PORT_RWC_BITS; - ehci_writel(ehci, temp & ~PORT_PE, status_reg); - goto done; - } - - else if (typeReq == GetPortStatus) { + if (typeReq == GetPortStatus) { temp = ehci_readl(ehci, status_reg); if (tegra->port_resuming && !(temp & PORT_SUSPEND)) { /* Resume completed, re-enable disconnect detection */ @@ -174,7 +163,7 @@ static int tegra_ehci_hub_control( goto done; } - temp &= ~PORT_WKCONN_E; + temp &= ~(PORT_RWC_BITS | PORT_WKCONN_E); temp |= PORT_WKDISC_E | PORT_WKOC_E; ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); @@ -319,26 +308,23 @@ static int tegra_ehci_setup(struct usb_hcd *hcd) return retval; } -struct temp_buffer { +struct dma_aligned_buffer { void *kmalloc_ptr; void *old_xfer_buffer; u8 data[0]; }; -static void free_temp_buffer(struct urb *urb) +static void free_dma_aligned_buffer(struct urb *urb) { - enum dma_data_direction dir; - struct temp_buffer *temp; + struct dma_aligned_buffer *temp; if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER)) return; - dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - - temp = container_of(urb->transfer_buffer, struct temp_buffer, - data); + temp = container_of(urb->transfer_buffer, + struct dma_aligned_buffer, data); - if (dir == DMA_FROM_DEVICE) + if (usb_urb_dir_in(urb)) memcpy(temp->old_xfer_buffer, temp->data, urb->transfer_buffer_length); urb->transfer_buffer = temp->old_xfer_buffer; @@ -347,10 +333,9 @@ static void free_temp_buffer(struct urb *urb) urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER; } -static int alloc_temp_buffer(struct urb *urb, gfp_t mem_flags) +static int alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags) { - enum dma_data_direction dir; - struct temp_buffer *temp, *kmalloc_ptr; + struct dma_aligned_buffer *temp, *kmalloc_ptr; size_t kmalloc_size; if (urb->num_sgs || urb->sg || @@ -358,22 +343,19 @@ static int alloc_temp_buffer(struct urb *urb, gfp_t mem_flags) !((uintptr_t)urb->transfer_buffer & (TEGRA_USB_DMA_ALIGN - 1))) return 0; - dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - /* Allocate a buffer with enough padding for alignment */ kmalloc_size = urb->transfer_buffer_length + - sizeof(struct temp_buffer) + TEGRA_USB_DMA_ALIGN - 1; + sizeof(struct dma_aligned_buffer) + TEGRA_USB_DMA_ALIGN - 1; kmalloc_ptr = kmalloc(kmalloc_size, mem_flags); if (!kmalloc_ptr) return -ENOMEM; - /* Position our struct temp_buffer such that data is aligned */ + /* Position our struct dma_aligned_buffer such that data is aligned */ temp = PTR_ALIGN(kmalloc_ptr + 1, TEGRA_USB_DMA_ALIGN) - 1; - temp->kmalloc_ptr = kmalloc_ptr; temp->old_xfer_buffer = urb->transfer_buffer; - if (dir == DMA_TO_DEVICE) + if (usb_urb_dir_out(urb)) memcpy(temp->data, urb->transfer_buffer, urb->transfer_buffer_length); urb->transfer_buffer = temp->data; @@ -388,13 +370,13 @@ static int tegra_ehci_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, { int ret; - ret = alloc_temp_buffer(urb, mem_flags); + ret = alloc_dma_aligned_buffer(urb, mem_flags); if (ret) return ret; ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags); if (ret) - free_temp_buffer(urb); + free_dma_aligned_buffer(urb); return ret; } @@ -402,49 +384,51 @@ static int tegra_ehci_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) { usb_hcd_unmap_urb_for_dma(hcd, urb); - free_temp_buffer(urb); + free_dma_aligned_buffer(urb); } static const struct hc_driver tegra_ehci_hc_driver = { .description = hcd_name, .product_desc = "Tegra EHCI Host Controller", .hcd_priv_size = sizeof(struct ehci_hcd), - .flags = HCD_USB2 | HCD_MEMORY, - .reset = tegra_ehci_setup, + /* standard ehci functions */ .irq = ehci_irq, - .start = ehci_run, .stop = ehci_stop, - .shutdown = tegra_ehci_shutdown, .urb_enqueue = ehci_urb_enqueue, .urb_dequeue = ehci_urb_dequeue, - .map_urb_for_dma = tegra_ehci_map_urb_for_dma, - .unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma, .endpoint_disable = ehci_endpoint_disable, .endpoint_reset = ehci_endpoint_reset, .get_frame_number = ehci_get_frame, .hub_status_data = ehci_hub_status_data, - .hub_control = tegra_ehci_hub_control, .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, + .relinquish_port = ehci_relinquish_port, + .port_handed_over = ehci_port_handed_over, + + /* modified ehci functions for tegra */ + .reset = tegra_ehci_setup, + .shutdown = tegra_ehci_shutdown, + .map_urb_for_dma = tegra_ehci_map_urb_for_dma, + .unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma, + .hub_control = tegra_ehci_hub_control, #ifdef CONFIG_PM .bus_suspend = ehci_bus_suspend, .bus_resume = ehci_bus_resume, #endif - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, }; -static int setup_vbus_gpio(struct platform_device *pdev) +static int setup_vbus_gpio(struct platform_device *pdev, + struct tegra_ehci_platform_data *pdata) { int err = 0; int gpio; - if (!pdev->dev.of_node) - return 0; - - gpio = of_get_named_gpio(pdev->dev.of_node, "nvidia,vbus-gpio", 0); + gpio = pdata->vbus_gpio; + if (!gpio_is_valid(gpio)) + gpio = of_get_named_gpio(pdev->dev.of_node, + "nvidia,vbus-gpio", 0); if (!gpio_is_valid(gpio)) return 0; @@ -664,7 +648,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) if (!pdev->dev.dma_mask) pdev->dev.dma_mask = &tegra_ehci_dma_mask; - setup_vbus_gpio(pdev); + setup_vbus_gpio(pdev, pdata); tegra = kzalloc(sizeof(struct tegra_ehci_hcd), GFP_KERNEL); if (!tegra) diff --git a/trunk/drivers/usb/host/fhci-tds.c b/trunk/drivers/usb/host/fhci-tds.c index 0ea577bfca2a..c5ed88199292 100644 --- a/trunk/drivers/usb/host/fhci-tds.c +++ b/trunk/drivers/usb/host/fhci-tds.c @@ -155,7 +155,7 @@ u32 fhci_create_ep(struct fhci_usb *usb, enum fhci_mem_alloc data_mem, struct endpoint *ep; struct usb_td __iomem *td; unsigned long ep_offset; - char *err_for = "enpoint PRAM"; + char *err_for = "endpoint PRAM"; int ep_mem_size; u32 i; diff --git a/trunk/drivers/usb/host/fsl-mph-dr-of.c b/trunk/drivers/usb/host/fsl-mph-dr-of.c index ab333ac6071d..22ff6b3a676f 100644 --- a/trunk/drivers/usb/host/fsl-mph-dr-of.c +++ b/trunk/drivers/usb/host/fsl-mph-dr-of.c @@ -119,6 +119,39 @@ struct platform_device * __devinit fsl_usb2_device_register( static const struct of_device_id fsl_usb2_mph_dr_of_match[]; +static int usb_get_ver_info(struct device_node *np) +{ + int ver = -1; + + /* + * returns 1 for usb controller version 1.6 + * returns 2 for usb controller version 2.2 + * returns 0 otherwise + */ + if (of_device_is_compatible(np, "fsl-usb2-dr")) { + if (of_device_is_compatible(np, "fsl-usb2-dr-v1.6")) + ver = FSL_USB_VER_1_6; + else if (of_device_is_compatible(np, "fsl-usb2-dr-v2.2")) + ver = FSL_USB_VER_2_2; + else /* for previous controller versions */ + ver = FSL_USB_VER_OLD; + + if (ver > -1) + return ver; + } + + if (of_device_is_compatible(np, "fsl-usb2-mph")) { + if (of_device_is_compatible(np, "fsl-usb2-mph-v1.6")) + ver = FSL_USB_VER_1_6; + else if (of_device_is_compatible(np, "fsl-usb2-mph-v2.2")) + ver = FSL_USB_VER_2_2; + else /* for previous controller versions */ + ver = FSL_USB_VER_OLD; + } + + return ver; +} + static int __devinit fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) { struct device_node *np = ofdev->dev.of_node; @@ -166,6 +199,14 @@ static int __devinit fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) prop = of_get_property(np, "phy_type", NULL); pdata->phy_mode = determine_usb_phy(prop); + pdata->controller_ver = usb_get_ver_info(np); + + if (pdata->have_sysif_regs) { + if (pdata->controller_ver < 0) { + dev_warn(&ofdev->dev, "Could not get controller version\n"); + return -ENODEV; + } + } for (i = 0; i < ARRAY_SIZE(dev_data->drivers); i++) { if (!dev_data->drivers[i]) diff --git a/trunk/drivers/usb/host/isp1760-hcd.c b/trunk/drivers/usb/host/isp1760-hcd.c index fc72d44bf787..a35bbddf8968 100644 --- a/trunk/drivers/usb/host/isp1760-hcd.c +++ b/trunk/drivers/usb/host/isp1760-hcd.c @@ -1562,11 +1562,14 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { retval = -ESHUTDOWN; + qtd_list_free(&new_qtds); goto out; } retval = usb_hcd_link_urb_to_ep(hcd, urb); - if (retval) + if (retval) { + qtd_list_free(&new_qtds); goto out; + } qh = urb->ep->hcpriv; if (qh) { @@ -1584,6 +1587,7 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, if (!qh) { retval = -ENOMEM; usb_hcd_unlink_urb_from_ep(hcd, urb); + qtd_list_free(&new_qtds); goto out; } list_add_tail(&qh->qh_list, ep_queue); @@ -1683,6 +1687,7 @@ static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, list_for_each_entry(qtd, &qh->qtd_list, qtd_list) if (qtd->urb == urb) { dequeue_urb_from_qtd(hcd, qh, qtd); + list_move(&qtd->qtd_list, &qh->qtd_list); break; } @@ -2176,7 +2181,7 @@ static const struct hc_driver isp1760_hc_driver = { int __init init_kmem_once(void) { - urb_listitem_cachep = kmem_cache_create("isp1760 urb_listitem", + urb_listitem_cachep = kmem_cache_create("isp1760_urb_listitem", sizeof(struct urb_listitem), 0, SLAB_TEMPORARY | SLAB_MEM_SPREAD, NULL); diff --git a/trunk/drivers/usb/host/isp1760-if.c b/trunk/drivers/usb/host/isp1760-if.c index 4592dc17a9f9..fff114fd5461 100644 --- a/trunk/drivers/usb/host/isp1760-if.c +++ b/trunk/drivers/usb/host/isp1760-if.c @@ -398,6 +398,9 @@ static int __devinit isp1760_plat_probe(struct platform_device *pdev) hcd = isp1760_register(mem_res->start, mem_size, irq_res->start, irqflags, -ENOENT, &pdev->dev, dev_name(&pdev->dev), devflags); + + dev_set_drvdata(&pdev->dev, hcd); + if (IS_ERR(hcd)) { pr_warning("isp1760: Failed to register the HCD device\n"); ret = -ENODEV; @@ -417,11 +420,16 @@ static int __devexit isp1760_plat_remove(struct platform_device *pdev) { struct resource *mem_res; resource_size_t mem_size; + struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev); + + usb_remove_hcd(hcd); mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); mem_size = resource_size(mem_res); release_mem_region(mem_res->start, mem_size); + usb_put_hcd(hcd); + return 0; } diff --git a/trunk/drivers/usb/host/ohci-at91.c b/trunk/drivers/usb/host/ohci-at91.c index 13ebeca8e73e..a665b3eaa746 100644 --- a/trunk/drivers/usb/host/ohci-at91.c +++ b/trunk/drivers/usb/host/ohci-at91.c @@ -129,7 +129,7 @@ static int __devinit usb_hcd_at91_probe(const struct hc_driver *driver, if (!hcd) return -ENOMEM; hcd->rsrc_start = pdev->resource[0].start; - hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; + hcd->rsrc_len = resource_size(&pdev->resource[0]); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { pr_debug("request_mem_region failed\n"); @@ -223,7 +223,7 @@ static void __devexit usb_hcd_at91_remove(struct usb_hcd *hcd, /*-------------------------------------------------------------------------*/ static int __devinit -ohci_at91_start (struct usb_hcd *hcd) +ohci_at91_reset (struct usb_hcd *hcd) { struct at91_usbh_data *board = hcd->self.controller->platform_data; struct ohci_hcd *ohci = hcd_to_ohci (hcd); @@ -233,9 +233,18 @@ ohci_at91_start (struct usb_hcd *hcd) return ret; ohci->num_ports = board->ports; + return 0; +} + +static int __devinit +ohci_at91_start (struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int ret; if ((ret = ohci_run(ohci)) < 0) { - err("can't start %s", hcd->self.bus_name); + dev_err(hcd->self.controller, "can't start %s\n", + hcd->self.bus_name); ohci_stop(hcd); return ret; } @@ -418,6 +427,7 @@ static const struct hc_driver ohci_at91_hc_driver = { /* * basic lifecycle operations */ + .reset = ohci_at91_reset, .start = ohci_at91_start, .stop = ohci_stop, .shutdown = ohci_shutdown, diff --git a/trunk/drivers/usb/host/ohci-au1xxx.c b/trunk/drivers/usb/host/ohci-au1xxx.c index 4ea63b2cac42..c611699b4aa6 100644 --- a/trunk/drivers/usb/host/ohci-au1xxx.c +++ b/trunk/drivers/usb/host/ohci-au1xxx.c @@ -37,7 +37,8 @@ static int __devinit ohci_au1xxx_start(struct usb_hcd *hcd) return ret; if ((ret = ohci_run(ohci)) < 0) { - err ("can't start %s", hcd->self.bus_name); + dev_err(hcd->self.controller, "can't start %s", + hcd->self.bus_name); ohci_stop(hcd); return ret; } diff --git a/trunk/drivers/usb/host/ohci-cns3xxx.c b/trunk/drivers/usb/host/ohci-cns3xxx.c index 5a00a1e1c6ca..2c9f233047be 100644 --- a/trunk/drivers/usb/host/ohci-cns3xxx.c +++ b/trunk/drivers/usb/host/ohci-cns3xxx.c @@ -41,7 +41,8 @@ cns3xxx_ohci_start(struct usb_hcd *hcd) ret = ohci_run(ohci); if (ret < 0) { - err("can't start %s", hcd->self.bus_name); + dev_err(hcd->self.controller, "can't start %s\n", + hcd->self.bus_name); ohci_stop(hcd); return ret; } diff --git a/trunk/drivers/usb/host/ohci-da8xx.c b/trunk/drivers/usb/host/ohci-da8xx.c index 843509778a33..269b1e0f7691 100644 --- a/trunk/drivers/usb/host/ohci-da8xx.c +++ b/trunk/drivers/usb/host/ohci-da8xx.c @@ -454,3 +454,5 @@ static struct platform_driver ohci_hcd_da8xx_driver = { .name = "ohci", }, }; + +MODULE_ALIAS("platform:ohci"); diff --git a/trunk/drivers/usb/host/ohci-dbg.c b/trunk/drivers/usb/host/ohci-dbg.c index e4bcb62b930a..31b81f9eacdc 100644 --- a/trunk/drivers/usb/host/ohci-dbg.c +++ b/trunk/drivers/usb/host/ohci-dbg.c @@ -29,14 +29,14 @@ urb_print(struct urb * urb, char * str, int small, int status) unsigned int pipe= urb->pipe; if (!urb->dev || !urb->dev->bus) { - dbg("%s URB: no dev", str); + printk(KERN_DEBUG "%s URB: no dev\n", str); return; } #ifndef OHCI_VERBOSE_DEBUG if (status != 0) #endif - dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d", + printk(KERN_DEBUG "%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d\n", str, urb, usb_pipedevice (pipe), diff --git a/trunk/drivers/usb/host/ohci-ep93xx.c b/trunk/drivers/usb/host/ohci-ep93xx.c index 3d63574d2c7e..dbfbd1dfd2e2 100644 --- a/trunk/drivers/usb/host/ohci-ep93xx.c +++ b/trunk/drivers/usb/host/ohci-ep93xx.c @@ -47,7 +47,7 @@ static int usb_hcd_ep93xx_probe(const struct hc_driver *driver, struct usb_hcd *hcd; if (pdev->resource[1].flags != IORESOURCE_IRQ) { - dbg("resource[1] is not IORESOURCE_IRQ"); + dev_dbg(&pdev->dev, "resource[1] is not IORESOURCE_IRQ\n"); return -ENOMEM; } @@ -65,14 +65,14 @@ static int usb_hcd_ep93xx_probe(const struct hc_driver *driver, hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); if (hcd->regs == NULL) { - dbg("ioremap failed"); + dev_dbg(&pdev->dev, "ioremap failed\n"); retval = -ENOMEM; goto err2; } usb_host_clock = clk_get(&pdev->dev, NULL); if (IS_ERR(usb_host_clock)) { - dbg("clk_get failed"); + dev_dbg(&pdev->dev, "clk_get failed\n"); retval = PTR_ERR(usb_host_clock); goto err3; } @@ -116,7 +116,8 @@ static int __devinit ohci_ep93xx_start(struct usb_hcd *hcd) return ret; if ((ret = ohci_run(ohci)) < 0) { - err("can't start %s", hcd->self.bus_name); + dev_err(hcd->self.controller, "can't start %s\n", + hcd->self.bus_name); ohci_stop(hcd); return ret; } diff --git a/trunk/drivers/usb/host/ohci-exynos.c b/trunk/drivers/usb/host/ohci-exynos.c index 37bb20ebb6fc..2909621ea196 100644 --- a/trunk/drivers/usb/host/ohci-exynos.c +++ b/trunk/drivers/usb/host/ohci-exynos.c @@ -35,7 +35,8 @@ static int ohci_exynos_start(struct usb_hcd *hcd) ret = ohci_run(ohci); if (ret < 0) { - err("can't start %s", hcd->self.bus_name); + dev_err(hcd->self.controller, "can't start %s\n", + hcd->self.bus_name); ohci_stop(hcd); return ret; } diff --git a/trunk/drivers/usb/host/ohci-hcd.c b/trunk/drivers/usb/host/ohci-hcd.c index 235171f29460..e0adf5c0cf55 100644 --- a/trunk/drivers/usb/host/ohci-hcd.c +++ b/trunk/drivers/usb/host/ohci-hcd.c @@ -1080,11 +1080,6 @@ MODULE_LICENSE ("GPL"); #define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver #endif -#ifdef CONFIG_USB_OHCI_HCD_SSB -#include "ohci-ssb.c" -#define SSB_OHCI_DRIVER ssb_ohci_driver -#endif - #ifdef CONFIG_MFD_SM501 #include "ohci-sm501.c" #define SM501_OHCI_DRIVER ohci_hcd_sm501_driver @@ -1128,8 +1123,7 @@ MODULE_LICENSE ("GPL"); !defined(SA1111_DRIVER) && \ !defined(PS3_SYSTEM_BUS_DRIVER) && \ !defined(SM501_OHCI_DRIVER) && \ - !defined(TMIO_OHCI_DRIVER) && \ - !defined(SSB_OHCI_DRIVER) + !defined(TMIO_OHCI_DRIVER) #error "missing bus glue for ohci-hcd" #endif @@ -1195,12 +1189,6 @@ static int __init ohci_hcd_mod_init(void) goto error_pci; #endif -#ifdef SSB_OHCI_DRIVER - retval = ssb_driver_register(&SSB_OHCI_DRIVER); - if (retval) - goto error_ssb; -#endif - #ifdef SM501_OHCI_DRIVER retval = platform_driver_register(&SM501_OHCI_DRIVER); if (retval < 0) @@ -1224,10 +1212,6 @@ static int __init ohci_hcd_mod_init(void) platform_driver_unregister(&SM501_OHCI_DRIVER); error_sm501: #endif -#ifdef SSB_OHCI_DRIVER - ssb_driver_unregister(&SSB_OHCI_DRIVER); - error_ssb: -#endif #ifdef PCI_DRIVER pci_unregister_driver(&PCI_DRIVER); error_pci: @@ -1275,9 +1259,6 @@ static void __exit ohci_hcd_mod_exit(void) #ifdef SM501_OHCI_DRIVER platform_driver_unregister(&SM501_OHCI_DRIVER); #endif -#ifdef SSB_OHCI_DRIVER - ssb_driver_unregister(&SSB_OHCI_DRIVER); -#endif #ifdef PCI_DRIVER pci_unregister_driver(&PCI_DRIVER); #endif diff --git a/trunk/drivers/usb/host/ohci-nxp.c b/trunk/drivers/usb/host/ohci-nxp.c index 6618de1d881d..1e364ec962fb 100644 --- a/trunk/drivers/usb/host/ohci-nxp.c +++ b/trunk/drivers/usb/host/ohci-nxp.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include @@ -29,7 +31,6 @@ #include #include -#include #define USB_CONFIG_BASE 0x31020000 #define PWRMAN_BASE 0x40004000 @@ -38,7 +39,9 @@ /* USB_CTRL bit defines */ #define USB_SLAVE_HCLK_EN (1 << 24) +#define USB_DEV_NEED_CLK_EN (1 << 22) #define USB_HOST_NEED_CLK_EN (1 << 21) +#define PAD_CONTROL_LAST_DRIVEN (1 << 19) #define USB_OTG_CLK_CTRL IO_ADDRESS(USB_CONFIG_BASE + 0xFF4) #define USB_OTG_CLK_STAT IO_ADDRESS(USB_CONFIG_BASE + 0xFF8) @@ -56,54 +59,6 @@ #define TRANSPARENT_I2C_EN (1 << 7) #define HOST_EN (1 << 0) -/* ISP1301 USB transceiver I2C registers */ -#define ISP1301_MODE_CONTROL_1 0x04 /* u8 read, set, +1 clear */ - -#define MC1_SPEED_REG (1 << 0) -#define MC1_SUSPEND_REG (1 << 1) -#define MC1_DAT_SE0 (1 << 2) -#define MC1_TRANSPARENT (1 << 3) -#define MC1_BDIS_ACON_EN (1 << 4) -#define MC1_OE_INT_EN (1 << 5) -#define MC1_UART_EN (1 << 6) -#define MC1_MASK 0x7f - -#define ISP1301_MODE_CONTROL_2 0x12 /* u8 read, set, +1 clear */ - -#define MC2_GLOBAL_PWR_DN (1 << 0) -#define MC2_SPD_SUSP_CTRL (1 << 1) -#define MC2_BI_DI (1 << 2) -#define MC2_TRANSP_BDIR0 (1 << 3) -#define MC2_TRANSP_BDIR1 (1 << 4) -#define MC2_AUDIO_EN (1 << 5) -#define MC2_PSW_EN (1 << 6) -#define MC2_EN2V7 (1 << 7) - -#define ISP1301_OTG_CONTROL_1 0x06 /* u8 read, set, +1 clear */ -# define OTG1_DP_PULLUP (1 << 0) -# define OTG1_DM_PULLUP (1 << 1) -# define OTG1_DP_PULLDOWN (1 << 2) -# define OTG1_DM_PULLDOWN (1 << 3) -# define OTG1_ID_PULLDOWN (1 << 4) -# define OTG1_VBUS_DRV (1 << 5) -# define OTG1_VBUS_DISCHRG (1 << 6) -# define OTG1_VBUS_CHRG (1 << 7) -#define ISP1301_OTG_STATUS 0x10 /* u8 readonly */ -# define OTG_B_SESS_END (1 << 6) -# define OTG_B_SESS_VLD (1 << 7) - -#define ISP1301_I2C_ADDR 0x2C - -#define ISP1301_I2C_MODE_CONTROL_1 0x4 -#define ISP1301_I2C_MODE_CONTROL_2 0x12 -#define ISP1301_I2C_OTG_CONTROL_1 0x6 -#define ISP1301_I2C_OTG_CONTROL_2 0x10 -#define ISP1301_I2C_INTERRUPT_SOURCE 0x8 -#define ISP1301_I2C_INTERRUPT_LATCH 0xA -#define ISP1301_I2C_INTERRUPT_FALLING 0xC -#define ISP1301_I2C_INTERRUPT_RISING 0xE -#define ISP1301_I2C_REG_CLEAR_ADDR 1 - /* On LPC32xx, those are undefined */ #ifndef start_int_set_falling_edge #define start_int_set_falling_edge(irq) @@ -113,42 +68,12 @@ #define start_int_umask(irq) #endif -static struct i2c_driver isp1301_driver; static struct i2c_client *isp1301_i2c_client; extern int usb_disabled(void); -extern int ocpi_enable(void); static struct clk *usb_clk; -static const unsigned short normal_i2c[] = - { ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END }; - -static int isp1301_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - return 0; -} - -static int isp1301_remove(struct i2c_client *client) -{ - return 0; -} - -static const struct i2c_device_id isp1301_id[] = { - { "isp1301_nxp", 0 }, - { } -}; - -static struct i2c_driver isp1301_driver = { - .driver = { - .name = "isp1301_nxp", - }, - .probe = isp1301_probe, - .remove = isp1301_remove, - .id_table = isp1301_id, -}; - static void isp1301_configure_pnx4008(void) { /* PNX4008 only supports DAT_SE0 USB mode */ @@ -220,7 +145,7 @@ static void isp1301_configure_lpc32xx(void) ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR, ~0); /* Enable usb_need_clk clock after transceiver is initialized */ - __raw_writel((__raw_readl(USB_CTRL) | (1 << 22)), USB_CTRL); + __raw_writel(__raw_readl(USB_CTRL) | USB_HOST_NEED_CLK_EN, USB_CTRL); printk(KERN_INFO "ISP1301 Vendor ID : 0x%04x\n", i2c_smbus_read_word_data(isp1301_i2c_client, 0x00)); @@ -372,65 +297,55 @@ static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev) struct usb_hcd *hcd = 0; struct ohci_hcd *ohci; const struct hc_driver *driver = &ohci_nxp_hc_driver; - struct i2c_adapter *i2c_adap; - struct i2c_board_info i2c_info; - + struct resource *res; int ret = 0, irq; + struct device_node *isp1301_node; - dev_dbg(&pdev->dev, "%s: " DRIVER_DESC " (nxp)\n", hcd_name); - if (usb_disabled()) { - err("USB is disabled"); - ret = -ENODEV; - goto out; + if (pdev->dev.of_node) { + isp1301_node = of_parse_phandle(pdev->dev.of_node, + "transceiver", 0); + } else { + isp1301_node = NULL; } - if (pdev->num_resources != 2 - || pdev->resource[0].flags != IORESOURCE_MEM - || pdev->resource[1].flags != IORESOURCE_IRQ) { - err("Invalid resource configuration"); - ret = -ENODEV; + isp1301_i2c_client = isp1301_get_client(isp1301_node); + if (!isp1301_i2c_client) { + ret = -EPROBE_DEFER; goto out; } - /* Enable AHB slave USB clock, needed for further USB clock control */ - __raw_writel(USB_SLAVE_HCLK_EN | (1 << 19), USB_CTRL); + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; - ret = i2c_add_driver(&isp1301_driver); - if (ret < 0) { - err("failed to add ISP1301 driver"); - goto out; - } - i2c_adap = i2c_get_adapter(2); - memset(&i2c_info, 0, sizeof(struct i2c_board_info)); - strlcpy(i2c_info.type, "isp1301_nxp", I2C_NAME_SIZE); - isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info, - normal_i2c, NULL); - i2c_put_adapter(i2c_adap); - if (!isp1301_i2c_client) { - err("failed to connect I2C to ISP1301 USB Transceiver"); + dev_dbg(&pdev->dev, "%s: " DRIVER_DESC " (nxp)\n", hcd_name); + if (usb_disabled()) { + dev_err(&pdev->dev, "USB is disabled\n"); ret = -ENODEV; - goto out_i2c_driver; + goto out; } + /* Enable AHB slave USB clock, needed for further USB clock control */ + __raw_writel(USB_SLAVE_HCLK_EN | PAD_CONTROL_LAST_DRIVEN, USB_CTRL); + isp1301_configure(); /* Enable USB PLL */ usb_clk = clk_get(&pdev->dev, "ck_pll5"); if (IS_ERR(usb_clk)) { - err("failed to acquire USB PLL"); + dev_err(&pdev->dev, "failed to acquire USB PLL\n"); ret = PTR_ERR(usb_clk); goto out1; } ret = clk_enable(usb_clk); if (ret < 0) { - err("failed to start USB PLL"); + dev_err(&pdev->dev, "failed to start USB PLL\n"); goto out2; } ret = clk_set_rate(usb_clk, 48000); if (ret < 0) { - err("failed to set USB clock rate"); + dev_err(&pdev->dev, "failed to set USB clock rate\n"); goto out3; } @@ -442,9 +357,9 @@ static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev) while ((__raw_readl(USB_OTG_CLK_STAT) & USB_CLOCK_MASK) != USB_CLOCK_MASK) ; - hcd = usb_create_hcd (driver, &pdev->dev, dev_name(&pdev->dev)); + hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) { - err("Failed to allocate HC buffer"); + dev_err(&pdev->dev, "Failed to allocate HC buffer\n"); ret = -ENOMEM; goto out3; } @@ -452,14 +367,21 @@ static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev) /* Set all USB bits in the Start Enable register */ nxp_set_usb_bits(); - hcd->rsrc_start = pdev->resource[0].start; - hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - dev_dbg(&pdev->dev, "request_mem_region failed\n"); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Failed to get MEM resource\n"); + ret = -ENOMEM; + goto out4; + } + + hcd->regs = devm_request_and_ioremap(&pdev->dev, res); + if (!hcd->regs) { + dev_err(&pdev->dev, "Failed to devm_request_and_ioremap\n"); ret = -ENOMEM; goto out4; } - hcd->regs = (void __iomem *)pdev->resource[0].start; + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -486,10 +408,7 @@ static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev) out2: clk_put(usb_clk); out1: - i2c_unregister_device(isp1301_i2c_client); isp1301_i2c_client = NULL; -out_i2c_driver: - i2c_del_driver(&isp1301_driver); out: return ret; } @@ -507,7 +426,6 @@ static int usb_hcd_nxp_remove(struct platform_device *pdev) clk_put(usb_clk); i2c_unregister_device(isp1301_i2c_client); isp1301_i2c_client = NULL; - i2c_del_driver(&isp1301_driver); platform_set_drvdata(pdev, NULL); @@ -517,10 +435,19 @@ static int usb_hcd_nxp_remove(struct platform_device *pdev) /* work with hotplug and coldplug */ MODULE_ALIAS("platform:usb-ohci"); +#ifdef CONFIG_OF +static const struct of_device_id usb_hcd_nxp_match[] = { + { .compatible = "nxp,ohci-nxp" }, + {}, +}; +MODULE_DEVICE_TABLE(of, usb_hcd_nxp_match); +#endif + static struct platform_driver usb_hcd_nxp_driver = { .driver = { .name = "usb-ohci", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(usb_hcd_nxp_match), }, .probe = usb_hcd_nxp_probe, .remove = usb_hcd_nxp_remove, diff --git a/trunk/drivers/usb/host/ohci-omap.c b/trunk/drivers/usb/host/ohci-omap.c index 96451e41ee8a..9ce35d0d9d5d 100644 --- a/trunk/drivers/usb/host/ohci-omap.c +++ b/trunk/drivers/usb/host/ohci-omap.c @@ -205,8 +205,9 @@ static int ohci_omap_init(struct usb_hcd *hcd) need_transceiver = need_transceiver || machine_is_omap_h2() || machine_is_omap_h3(); - if (cpu_is_omap16xx()) - ocpi_enable(); + /* XXX OMAP16xx only */ + if (config->ocpi_enable) + config->ocpi_enable(); #ifdef CONFIG_USB_OTG if (need_transceiver) { @@ -217,8 +218,7 @@ static int ohci_omap_init(struct usb_hcd *hcd) dev_dbg(hcd->self.controller, "init %s transceiver, status %d\n", ohci->transceiver->label, status); if (status) { - if (ohci->transceiver) - put_device(ohci->transceiver->dev); + usb_put_transceiver(ohci->transceiver); return status; } } else { @@ -405,7 +405,7 @@ usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev) usb_remove_hcd(hcd); if (ohci->transceiver) { (void) otg_set_host(ohci->transceiver->otg, 0); - put_device(ohci->transceiver->dev); + usb_put_transceiver(ohci->transceiver); } if (machine_is_omap_osk()) gpio_free(9); diff --git a/trunk/drivers/usb/host/ohci-platform.c b/trunk/drivers/usb/host/ohci-platform.c index ec5c6791c8b4..670c7059c9ae 100644 --- a/trunk/drivers/usb/host/ohci-platform.c +++ b/trunk/drivers/usb/host/ohci-platform.c @@ -93,13 +93,13 @@ static int __devinit ohci_platform_probe(struct platform_device *dev) irq = platform_get_irq(dev, 0); if (irq < 0) { - pr_err("no irq provieded"); + pr_err("no irq provided"); return irq; } res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0); if (!res_mem) { - pr_err("no memory recourse provieded"); + pr_err("no memory recourse provided"); return -ENXIO; } diff --git a/trunk/drivers/usb/host/ohci-pnx8550.c b/trunk/drivers/usb/host/ohci-pnx8550.c index f13d08f94d6b..148d27d6a67c 100644 --- a/trunk/drivers/usb/host/ohci-pnx8550.c +++ b/trunk/drivers/usb/host/ohci-pnx8550.c @@ -157,7 +157,8 @@ ohci_pnx8550_start (struct usb_hcd *hcd) return ret; if ((ret = ohci_run (ohci)) < 0) { - err ("can't start %s", hcd->self.bus_name); + dev_err(hcd->self.controller, "can't start %s", + hcd->self.bus_name); ohci_stop (hcd); return ret; } diff --git a/trunk/drivers/usb/host/ohci-ppc-of.c b/trunk/drivers/usb/host/ohci-ppc-of.c index d24cc89de16f..e27d5ae2b9eb 100644 --- a/trunk/drivers/usb/host/ohci-ppc-of.c +++ b/trunk/drivers/usb/host/ohci-ppc-of.c @@ -29,7 +29,8 @@ ohci_ppc_of_start(struct usb_hcd *hcd) return ret; if ((ret = ohci_run(ohci)) < 0) { - err("can't start %s", ohci_to_hcd(ohci)->self.bus_name); + dev_err(hcd->self.controller, "can't start %s\n", + hcd->self.bus_name); ohci_stop(hcd); return ret; } @@ -236,7 +237,7 @@ MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match); #if !defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \ !defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE) -#error "No endianess selected for ppc-of-ohci" +#error "No endianness selected for ppc-of-ohci" #endif diff --git a/trunk/drivers/usb/host/ohci-ppc-soc.c b/trunk/drivers/usb/host/ohci-ppc-soc.c index 1514b7067470..185c39ed81b7 100644 --- a/trunk/drivers/usb/host/ohci-ppc-soc.c +++ b/trunk/drivers/usb/host/ohci-ppc-soc.c @@ -130,7 +130,8 @@ ohci_ppc_soc_start(struct usb_hcd *hcd) return ret; if ((ret = ohci_run(ohci)) < 0) { - err("can't start %s", ohci_to_hcd(ohci)->self.bus_name); + dev_err(hcd->self.controller, "can't start %s\n", + hcd->self.bus_name); ohci_stop(hcd); return ret; } diff --git a/trunk/drivers/usb/host/ohci-ps3.c b/trunk/drivers/usb/host/ohci-ps3.c index 6fd4fa1f19bb..2ee1d8d713d2 100644 --- a/trunk/drivers/usb/host/ohci-ps3.c +++ b/trunk/drivers/usb/host/ohci-ps3.c @@ -45,7 +45,8 @@ static int __devinit ps3_ohci_hc_start(struct usb_hcd *hcd) result = ohci_run(ohci); if (result < 0) { - err("can't start %s", hcd->self.bus_name); + dev_err(hcd->self.controller, "can't start %s\n", + hcd->self.bus_name); ohci_stop(hcd); } diff --git a/trunk/drivers/usb/host/ohci-pxa27x.c b/trunk/drivers/usb/host/ohci-pxa27x.c index c31b2815be1c..e1a3cc6d28dc 100644 --- a/trunk/drivers/usb/host/ohci-pxa27x.c +++ b/trunk/drivers/usb/host/ohci-pxa27x.c @@ -419,7 +419,8 @@ ohci_pxa27x_start (struct usb_hcd *hcd) return ret; if ((ret = ohci_run (ohci)) < 0) { - err ("can't start %s", hcd->self.bus_name); + dev_err(hcd->self.controller, "can't start %s", + hcd->self.bus_name); ohci_stop (hcd); return ret; } diff --git a/trunk/drivers/usb/host/ohci-s3c2410.c b/trunk/drivers/usb/host/ohci-s3c2410.c index 56dcf069246d..664c869eb096 100644 --- a/trunk/drivers/usb/host/ohci-s3c2410.c +++ b/trunk/drivers/usb/host/ohci-s3c2410.c @@ -420,7 +420,8 @@ ohci_s3c2410_start(struct usb_hcd *hcd) ret = ohci_run(ohci); if (ret < 0) { - err("can't start %s", hcd->self.bus_name); + dev_err(hcd->self.controller, "can't start %s\n", + hcd->self.bus_name); ohci_stop(hcd); return ret; } diff --git a/trunk/drivers/usb/host/ohci-sa1111.c b/trunk/drivers/usb/host/ohci-sa1111.c index e1004fb37bd9..b6cc92520924 100644 --- a/trunk/drivers/usb/host/ohci-sa1111.c +++ b/trunk/drivers/usb/host/ohci-sa1111.c @@ -46,7 +46,7 @@ static void dump_hci_status(struct usb_hcd *hcd, const char *label) { unsigned long status = sa1111_readl(hcd->regs + USB_STATUS); - dbg("%s USB_STATUS = { %s%s%s%s%s}", label, + printk(KERN_DEBUG "%s USB_STATUS = { %s%s%s%s%s}\n", label, ((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""), ((status & USB_STATUS_IRQHCIBUFFACC) ? "IRQHCIBUFFACC " : ""), ((status & USB_STATUS_NIRQHCIM) ? "" : "IRQHCIM "), @@ -193,7 +193,7 @@ static int ohci_hcd_sa1111_probe(struct sa1111_dev *dev) hcd->rsrc_len = resource_size(&dev->res); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - dbg("request_mem_region failed"); + dev_dbg(&dev->dev, "request_mem_region failed\n"); ret = -EBUSY; goto err1; } diff --git a/trunk/drivers/usb/host/ohci-sh.c b/trunk/drivers/usb/host/ohci-sh.c index 84686d90805b..76a20c278362 100644 --- a/trunk/drivers/usb/host/ohci-sh.c +++ b/trunk/drivers/usb/host/ohci-sh.c @@ -88,20 +88,20 @@ static int ohci_hcd_sh_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { - err("platform_get_resource error."); + dev_err(&pdev->dev, "platform_get_resource error.\n"); return -ENODEV; } irq = platform_get_irq(pdev, 0); if (irq < 0) { - err("platform_get_irq error."); + dev_err(&pdev->dev, "platform_get_irq error.\n"); return -ENODEV; } /* initialize hcd */ hcd = usb_create_hcd(&ohci_sh_hc_driver, &pdev->dev, (char *)hcd_name); if (!hcd) { - err("Failed to create hcd"); + dev_err(&pdev->dev, "Failed to create hcd\n"); return -ENOMEM; } @@ -110,7 +110,7 @@ static int ohci_hcd_sh_probe(struct platform_device *pdev) hcd->rsrc_len = resource_size(res); ret = usb_add_hcd(hcd, irq, IRQF_SHARED); if (ret != 0) { - err("Failed to add hcd"); + dev_err(&pdev->dev, "Failed to add hcd\n"); usb_put_hcd(hcd); return ret; } diff --git a/trunk/drivers/usb/host/ohci-spear.c b/trunk/drivers/usb/host/ohci-spear.c index 95c16489e883..fc7305ee3c9c 100644 --- a/trunk/drivers/usb/host/ohci-spear.c +++ b/trunk/drivers/usb/host/ohci-spear.c @@ -14,6 +14,7 @@ #include #include #include +#include struct spear_ohci { struct ohci_hcd ohci; @@ -24,12 +25,12 @@ struct spear_ohci { static void spear_start_ohci(struct spear_ohci *ohci) { - clk_enable(ohci->clk); + clk_prepare_enable(ohci->clk); } static void spear_stop_ohci(struct spear_ohci *ohci) { - clk_disable(ohci->clk); + clk_disable_unprepare(ohci->clk); } static int __devinit ohci_spear_start(struct usb_hcd *hcd) @@ -90,6 +91,8 @@ static const struct hc_driver ohci_spear_hc_driver = { .start_port_reset = ohci_start_port_reset, }; +static u64 spear_ohci_dma_mask = DMA_BIT_MASK(32); + static int spear_ohci_hcd_drv_probe(struct platform_device *pdev) { const struct hc_driver *driver = &ohci_spear_hc_driver; @@ -98,11 +101,8 @@ static int spear_ohci_hcd_drv_probe(struct platform_device *pdev) struct spear_ohci *ohci_p; struct resource *res; int retval, irq; - int *pdata = pdev->dev.platform_data; char clk_name[20] = "usbh_clk"; - - if (pdata == NULL) - return -EFAULT; + static int instance = -1; irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -110,8 +110,22 @@ static int spear_ohci_hcd_drv_probe(struct platform_device *pdev) goto fail_irq_get; } - if (*pdata >= 0) - sprintf(clk_name, "usbh.%01d_clk", *pdata); + /* + * Right now device-tree probed devices don't get dma_mask set. + * Since shared usb code relies on it, set it here for now. + * Once we have dma capability bindings this can go away. + */ + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &spear_ohci_dma_mask; + + /* + * Increment the device instance, when probing via device-tree + */ + if (pdev->id < 0) + instance++; + else + instance = pdev->id; + sprintf(clk_name, "usbh.%01d_clk", instance); usbh_clk = clk_get(NULL, clk_name); if (IS_ERR(usbh_clk)) { @@ -222,6 +236,11 @@ static int spear_ohci_hcd_drv_resume(struct platform_device *dev) } #endif +static struct of_device_id spear_ohci_id_table[] __devinitdata = { + { .compatible = "st,spear600-ohci", }, + { }, +}; + /* Driver definition to register with the platform bus */ static struct platform_driver spear_ohci_hcd_driver = { .probe = spear_ohci_hcd_drv_probe, @@ -233,6 +252,7 @@ static struct platform_driver spear_ohci_hcd_driver = { .driver = { .owner = THIS_MODULE, .name = "spear-ohci", + .of_match_table = of_match_ptr(spear_ohci_id_table), }, }; diff --git a/trunk/drivers/usb/host/ohci-ssb.c b/trunk/drivers/usb/host/ohci-ssb.c deleted file mode 100644 index 5ba18595d6f7..000000000000 --- a/trunk/drivers/usb/host/ohci-ssb.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Sonics Silicon Backplane - * Broadcom USB-core OHCI driver - * - * Copyright 2007 Michael Buesch - * - * Derived from the OHCI-PCI driver - * Copyright 1999 Roman Weissgaerber - * Copyright 2000-2002 David Brownell - * Copyright 1999 Linus Torvalds - * Copyright 1999 Gregory P. Smith - * - * Derived from the USBcore related parts of Broadcom-SB - * Copyright 2005 Broadcom Corporation - * - * Licensed under the GNU/GPL. See COPYING for details. - */ -#include - - -#define SSB_OHCI_TMSLOW_HOSTMODE (1 << 29) - -struct ssb_ohci_device { - struct ohci_hcd ohci; /* _must_ be at the beginning. */ - - u32 enable_flags; -}; - -static inline -struct ssb_ohci_device *hcd_to_ssb_ohci(struct usb_hcd *hcd) -{ - return (struct ssb_ohci_device *)(hcd->hcd_priv); -} - - -static int ssb_ohci_reset(struct usb_hcd *hcd) -{ - struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); - struct ohci_hcd *ohci = &ohcidev->ohci; - int err; - - ohci_hcd_init(ohci); - err = ohci_init(ohci); - - return err; -} - -static int ssb_ohci_start(struct usb_hcd *hcd) -{ - struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); - struct ohci_hcd *ohci = &ohcidev->ohci; - int err; - - err = ohci_run(ohci); - if (err < 0) { - ohci_err(ohci, "can't start\n"); - ohci_stop(hcd); - } - - return err; -} - -static const struct hc_driver ssb_ohci_hc_driver = { - .description = "ssb-usb-ohci", - .product_desc = "SSB OHCI Controller", - .hcd_priv_size = sizeof(struct ssb_ohci_device), - - .irq = ohci_irq, - .flags = HCD_MEMORY | HCD_USB11, - - .reset = ssb_ohci_reset, - .start = ssb_ohci_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - .get_frame_number = ohci_get_frame, - - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - - .start_port_reset = ohci_start_port_reset, -}; - -static void ssb_ohci_detach(struct ssb_device *dev) -{ - struct usb_hcd *hcd = ssb_get_drvdata(dev); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - ssb_device_disable(dev, 0); -} - -static int ssb_ohci_attach(struct ssb_device *dev) -{ - struct ssb_ohci_device *ohcidev; - struct usb_hcd *hcd; - int err = -ENOMEM; - u32 tmp, flags = 0; - - if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) || - dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32))) - return -EOPNOTSUPP; - - if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) { - /* Put the device into host-mode. */ - flags |= SSB_OHCI_TMSLOW_HOSTMODE; - ssb_device_enable(dev, flags); - } else if (dev->id.coreid == SSB_DEV_USB20_HOST) { - /* - * USB 2.0 special considerations: - * - * In addition to the standard SSB reset sequence, the Host - * Control Register must be programmed to bring the USB core - * and various phy components out of reset. - */ - ssb_device_enable(dev, 0); - ssb_write32(dev, 0x200, 0x7ff); - - /* Change Flush control reg */ - tmp = ssb_read32(dev, 0x400); - tmp &= ~8; - ssb_write32(dev, 0x400, tmp); - tmp = ssb_read32(dev, 0x400); - - /* Change Shim control reg */ - tmp = ssb_read32(dev, 0x304); - tmp &= ~0x100; - ssb_write32(dev, 0x304, tmp); - tmp = ssb_read32(dev, 0x304); - - udelay(1); - - /* Work around for 5354 failures */ - if (dev->id.revision == 2 && dev->bus->chip_id == 0x5354) { - /* Change syn01 reg */ - tmp = 0x00fe00fe; - ssb_write32(dev, 0x894, tmp); - - /* Change syn03 reg */ - tmp = ssb_read32(dev, 0x89c); - tmp |= 0x1; - ssb_write32(dev, 0x89c, tmp); - } - } else - ssb_device_enable(dev, 0); - - hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev, - dev_name(dev->dev)); - if (!hcd) - goto err_dev_disable; - ohcidev = hcd_to_ssb_ohci(hcd); - ohcidev->enable_flags = flags; - - tmp = ssb_read32(dev, SSB_ADMATCH0); - hcd->rsrc_start = ssb_admatch_base(tmp); - hcd->rsrc_len = ssb_admatch_size(tmp); - hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) - goto err_put_hcd; - err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED); - if (err) - goto err_iounmap; - - ssb_set_drvdata(dev, hcd); - - return err; - -err_iounmap: - iounmap(hcd->regs); -err_put_hcd: - usb_put_hcd(hcd); -err_dev_disable: - ssb_device_disable(dev, flags); - return err; -} - -static int ssb_ohci_probe(struct ssb_device *dev, - const struct ssb_device_id *id) -{ - int err; - u16 chipid_top; - - /* USBcores are only connected on embedded devices. */ - chipid_top = (dev->bus->chip_id & 0xFF00); - if (chipid_top != 0x4700 && chipid_top != 0x5300) - return -ENODEV; - - /* TODO: Probably need checks here; is the core connected? */ - - if (usb_disabled()) - return -ENODEV; - - /* We currently always attach SSB_DEV_USB11_HOSTDEV - * as HOST OHCI. If we want to attach it as Client device, - * we must branch here and call into the (yet to - * be written) Client mode driver. Same for remove(). */ - - err = ssb_ohci_attach(dev); - - return err; -} - -static void ssb_ohci_remove(struct ssb_device *dev) -{ - ssb_ohci_detach(dev); -} - -#ifdef CONFIG_PM - -static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state) -{ - ssb_device_disable(dev, 0); - - return 0; -} - -static int ssb_ohci_resume(struct ssb_device *dev) -{ - struct usb_hcd *hcd = ssb_get_drvdata(dev); - struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); - - ssb_device_enable(dev, ohcidev->enable_flags); - - ohci_finish_controller_resume(hcd); - return 0; -} - -#else /* !CONFIG_PM */ -#define ssb_ohci_suspend NULL -#define ssb_ohci_resume NULL -#endif /* CONFIG_PM */ - -static const struct ssb_device_id ssb_ohci_table[] = { - SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV), - SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV), - SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV), - SSB_DEVTABLE_END -}; -MODULE_DEVICE_TABLE(ssb, ssb_ohci_table); - -static struct ssb_driver ssb_ohci_driver = { - .name = KBUILD_MODNAME, - .id_table = ssb_ohci_table, - .probe = ssb_ohci_probe, - .remove = ssb_ohci_remove, - .suspend = ssb_ohci_suspend, - .resume = ssb_ohci_resume, -}; diff --git a/trunk/drivers/usb/host/ohci-tmio.c b/trunk/drivers/usb/host/ohci-tmio.c index 120bfe6ede38..60c2b0722f2e 100644 --- a/trunk/drivers/usb/host/ohci-tmio.c +++ b/trunk/drivers/usb/host/ohci-tmio.c @@ -140,7 +140,8 @@ static int ohci_tmio_start(struct usb_hcd *hcd) return ret; if ((ret = ohci_run(ohci)) < 0) { - err("can't start %s", hcd->self.bus_name); + dev_err(hcd->self.controller, "can't start %s\n", + hcd->self.bus_name); ohci_stop(hcd); return ret; } diff --git a/trunk/drivers/usb/host/ohci-xls.c b/trunk/drivers/usb/host/ohci-xls.c index a2247867af86..41e378f17c66 100644 --- a/trunk/drivers/usb/host/ohci-xls.c +++ b/trunk/drivers/usb/host/ohci-xls.c @@ -88,7 +88,8 @@ static int __devinit ohci_xls_start(struct usb_hcd *hcd) ohci = hcd_to_ohci(hcd); ret = ohci_run(ohci); if (ret < 0) { - err("can't start %s", hcd->self.bus_name); + dev_err(hcd->self.controller, "can't start %s\n", + hcd->self.bus_name); ohci_stop(hcd); return ret; } diff --git a/trunk/drivers/usb/host/oxu210hp-hcd.c b/trunk/drivers/usb/host/oxu210hp-hcd.c index 3b38030b02a8..4f0f0339532f 100644 --- a/trunk/drivers/usb/host/oxu210hp-hcd.c +++ b/trunk/drivers/usb/host/oxu210hp-hcd.c @@ -1399,8 +1399,8 @@ static struct ehci_qh *qh_make(struct oxu_hcd *oxu, * But interval 1 scheduling is simpler, and * includes high bandwidth. */ - dbg("intr period %d uframes, NYET!", - urb->interval); + oxu_dbg(oxu, "intr period %d uframes, NYET!\n", + urb->interval); goto done; } } else { @@ -1471,7 +1471,7 @@ static struct ehci_qh *qh_make(struct oxu_hcd *oxu, } break; default: - dbg("bogus dev %p speed %d", urb->dev, urb->dev->speed); + oxu_dbg(oxu, "bogus dev %p speed %d\n", urb->dev, urb->dev->speed); done: qh_put(qh); return NULL; @@ -2307,7 +2307,7 @@ static void scan_periodic(struct oxu_hcd *oxu) qh_put(temp.qh); break; default: - dbg("corrupt type %d frame %d shadow %p", + oxu_dbg(oxu, "corrupt type %d frame %d shadow %p\n", type, frame, q.ptr); q.ptr = NULL; } @@ -2991,8 +2991,9 @@ static int oxu_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) /* shouldn't happen often, but ... * FIXME kill those tds' urbs */ - err("can't reschedule qh %p, err %d", - qh, status); + dev_err(hcd->self.controller, + "can't reschedule qh %p, err %d\n", qh, + status); } return status; } diff --git a/trunk/drivers/usb/host/pci-quirks.c b/trunk/drivers/usb/host/pci-quirks.c index 32dada8c8b4f..df0828cb2aa3 100644 --- a/trunk/drivers/usb/host/pci-quirks.c +++ b/trunk/drivers/usb/host/pci-quirks.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -712,12 +713,28 @@ static int handshake(void __iomem *ptr, u32 mask, u32 done, return -ETIMEDOUT; } -bool usb_is_intel_switchable_xhci(struct pci_dev *pdev) +#define PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI 0x8C31 + +bool usb_is_intel_ppt_switchable_xhci(struct pci_dev *pdev) { return pdev->class == PCI_CLASS_SERIAL_USB_XHCI && pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI; } + +/* The Intel Lynx Point chipset also has switchable ports. */ +bool usb_is_intel_lpt_switchable_xhci(struct pci_dev *pdev) +{ + return pdev->class == PCI_CLASS_SERIAL_USB_XHCI && + pdev->vendor == PCI_VENDOR_ID_INTEL && + pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI; +} + +bool usb_is_intel_switchable_xhci(struct pci_dev *pdev) +{ + return usb_is_intel_ppt_switchable_xhci(pdev) || + usb_is_intel_lpt_switchable_xhci(pdev); +} EXPORT_SYMBOL_GPL(usb_is_intel_switchable_xhci); /* @@ -742,6 +759,19 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev) { u32 ports_available; + /* Don't switchover the ports if the user hasn't compiled the xHCI + * driver. Otherwise they will see "dead" USB ports that don't power + * the devices. + */ + if (!IS_ENABLED(CONFIG_USB_XHCI_HCD)) { + dev_warn(&xhci_pdev->dev, + "CONFIG_USB_XHCI_HCD is turned off, " + "defaulting to EHCI.\n"); + dev_warn(&xhci_pdev->dev, + "USB 3.0 devices will work at USB 2.0 speeds.\n"); + return; + } + ports_available = 0xffffffff; /* Write USB3_PSSEN, the USB 3.0 Port SuperSpeed Enable * Register, to turn on SuperSpeed terminations for all diff --git a/trunk/drivers/usb/host/r8a66597-hcd.c b/trunk/drivers/usb/host/r8a66597-hcd.c index 2bf1320dc9c3..c868be65e763 100644 --- a/trunk/drivers/usb/host/r8a66597-hcd.c +++ b/trunk/drivers/usb/host/r8a66597-hcd.c @@ -401,7 +401,7 @@ static u8 alloc_usb_address(struct r8a66597 *r8a66597, struct urb *urb) if (r8a66597->address_map & (1 << addr)) continue; - dbg("alloc_address: r8a66597_addr=%d", addr); + dev_dbg(&urb->dev->dev, "alloc_address: r8a66597_addr=%d\n", addr); r8a66597->address_map |= 1 << addr; if (make_r8a66597_device(r8a66597, urb, addr) < 0) @@ -426,7 +426,7 @@ static void free_usb_address(struct r8a66597 *r8a66597, if (!dev) return; - dbg("free_addr: addr=%d", dev->address); + dev_dbg(&dev->udev->dev, "free_addr: addr=%d\n", dev->address); dev->state = USB_STATE_DEFAULT; r8a66597->address_map &= ~(1 << dev->address); @@ -819,7 +819,7 @@ static void enable_r8a66597_pipe(struct r8a66597 *r8a66597, struct urb *urb, struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb); struct r8a66597_pipe *pipe = hep->hcpriv; - dbg("enable_pipe:"); + dev_dbg(&dev->udev->dev, "enable_pipe:\n"); pipe->info = *info; set_pipe_reg_addr(pipe, R8A66597_PIPE_NO_DMA); @@ -898,7 +898,7 @@ static void disable_r8a66597_pipe_all(struct r8a66597 *r8a66597, force_dequeue(r8a66597, pipenum, dev->address); } - dbg("disable_pipe"); + dev_dbg(&dev->udev->dev, "disable_pipe\n"); r8a66597->dma_map &= ~(dev->dma_map); dev->dma_map = 0; @@ -2264,7 +2264,7 @@ static int r8a66597_bus_suspend(struct usb_hcd *hcd) struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); int port; - dbg("%s", __func__); + dev_dbg(&r8a66597->device0.udev->dev, "%s\n", __func__); for (port = 0; port < r8a66597->max_root_hub; port++) { struct r8a66597_root_hub *rh = &r8a66597->root_hub[port]; @@ -2273,7 +2273,7 @@ static int r8a66597_bus_suspend(struct usb_hcd *hcd) if (!(rh->port & USB_PORT_STAT_ENABLE)) continue; - dbg("suspend port = %d", port); + dev_dbg(&rh->dev->udev->dev, "suspend port = %d\n", port); r8a66597_bclr(r8a66597, UACT, dvstctr_reg); /* suspend */ rh->port |= USB_PORT_STAT_SUSPEND; @@ -2295,7 +2295,7 @@ static int r8a66597_bus_resume(struct usb_hcd *hcd) struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); int port; - dbg("%s", __func__); + dev_dbg(&r8a66597->device0.udev->dev, "%s\n", __func__); for (port = 0; port < r8a66597->max_root_hub; port++) { struct r8a66597_root_hub *rh = &r8a66597->root_hub[port]; @@ -2304,7 +2304,7 @@ static int r8a66597_bus_resume(struct usb_hcd *hcd) if (!(rh->port & USB_PORT_STAT_SUSPEND)) continue; - dbg("resume port = %d", port); + dev_dbg(&rh->dev->udev->dev, "resume port = %d\n", port); rh->port &= ~USB_PORT_STAT_SUSPEND; rh->port |= USB_PORT_STAT_C_SUSPEND << 16; r8a66597_mdfy(r8a66597, RESUME, RESUME | UACT, dvstctr_reg); @@ -2360,7 +2360,7 @@ static int r8a66597_suspend(struct device *dev) struct r8a66597 *r8a66597 = dev_get_drvdata(dev); int port; - dbg("%s", __func__); + dev_dbg(dev, "%s\n", __func__); disable_controller(r8a66597); @@ -2378,7 +2378,7 @@ static int r8a66597_resume(struct device *dev) struct r8a66597 *r8a66597 = dev_get_drvdata(dev); struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597); - dbg("%s", __func__); + dev_dbg(dev, "%s\n", __func__); enable_controller(r8a66597); usb_root_hub_lost_power(hcd->self.root_hub); diff --git a/trunk/drivers/usb/host/ssb-hcd.c b/trunk/drivers/usb/host/ssb-hcd.c new file mode 100644 index 000000000000..c2a29faba076 --- /dev/null +++ b/trunk/drivers/usb/host/ssb-hcd.c @@ -0,0 +1,280 @@ +/* + * Sonics Silicon Backplane + * Broadcom USB-core driver (SSB bus glue) + * + * Copyright 2011-2012 Hauke Mehrtens + * + * Based on ssb-ohci driver + * Copyright 2007 Michael Buesch + * + * Derived from the OHCI-PCI driver + * Copyright 1999 Roman Weissgaerber + * Copyright 2000-2002 David Brownell + * Copyright 1999 Linus Torvalds + * Copyright 1999 Gregory P. Smith + * + * Derived from the USBcore related parts of Broadcom-SB + * Copyright 2005-2011 Broadcom Corporation + * + * Licensed under the GNU/GPL. See COPYING for details. + */ +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Hauke Mehrtens"); +MODULE_DESCRIPTION("Common USB driver for SSB Bus"); +MODULE_LICENSE("GPL"); + +#define SSB_HCD_TMSLOW_HOSTMODE (1 << 29) + +struct ssb_hcd_device { + struct platform_device *ehci_dev; + struct platform_device *ohci_dev; + + u32 enable_flags; +}; + +static void __devinit ssb_hcd_5354wa(struct ssb_device *dev) +{ +#ifdef CONFIG_SSB_DRIVER_MIPS + /* Work around for 5354 failures */ + if (dev->id.revision == 2 && dev->bus->chip_id == 0x5354) { + /* Change syn01 reg */ + ssb_write32(dev, 0x894, 0x00fe00fe); + + /* Change syn03 reg */ + ssb_write32(dev, 0x89c, ssb_read32(dev, 0x89c) | 0x1); + } +#endif +} + +static void __devinit ssb_hcd_usb20wa(struct ssb_device *dev) +{ + if (dev->id.coreid == SSB_DEV_USB20_HOST) { + /* + * USB 2.0 special considerations: + * + * In addition to the standard SSB reset sequence, the Host + * Control Register must be programmed to bring the USB core + * and various phy components out of reset. + */ + ssb_write32(dev, 0x200, 0x7ff); + + /* Change Flush control reg */ + ssb_write32(dev, 0x400, ssb_read32(dev, 0x400) & ~8); + ssb_read32(dev, 0x400); + + /* Change Shim control reg */ + ssb_write32(dev, 0x304, ssb_read32(dev, 0x304) & ~0x100); + ssb_read32(dev, 0x304); + + udelay(1); + + ssb_hcd_5354wa(dev); + } +} + +/* based on arch/mips/brcm-boards/bcm947xx/pcibios.c */ +static u32 __devinit ssb_hcd_init_chip(struct ssb_device *dev) +{ + u32 flags = 0; + + if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) + /* Put the device into host-mode. */ + flags |= SSB_HCD_TMSLOW_HOSTMODE; + + ssb_device_enable(dev, flags); + + ssb_hcd_usb20wa(dev); + + return flags; +} + +static const struct usb_ehci_pdata ehci_pdata = { +}; + +static const struct usb_ohci_pdata ohci_pdata = { +}; + +static struct platform_device * __devinit +ssb_hcd_create_pdev(struct ssb_device *dev, bool ohci, u32 addr, u32 len) +{ + struct platform_device *hci_dev; + struct resource hci_res[2]; + int ret = -ENOMEM; + + memset(hci_res, 0, sizeof(hci_res)); + + hci_res[0].start = addr; + hci_res[0].end = hci_res[0].start + len - 1; + hci_res[0].flags = IORESOURCE_MEM; + + hci_res[1].start = dev->irq; + hci_res[1].flags = IORESOURCE_IRQ; + + hci_dev = platform_device_alloc(ohci ? "ohci-platform" : + "ehci-platform" , 0); + if (!hci_dev) + return NULL; + + hci_dev->dev.parent = dev->dev; + hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask; + + ret = platform_device_add_resources(hci_dev, hci_res, + ARRAY_SIZE(hci_res)); + if (ret) + goto err_alloc; + if (ohci) + ret = platform_device_add_data(hci_dev, &ohci_pdata, + sizeof(ohci_pdata)); + else + ret = platform_device_add_data(hci_dev, &ehci_pdata, + sizeof(ehci_pdata)); + if (ret) + goto err_alloc; + ret = platform_device_add(hci_dev); + if (ret) + goto err_alloc; + + return hci_dev; + +err_alloc: + platform_device_put(hci_dev); + return ERR_PTR(ret); +} + +static int __devinit ssb_hcd_probe(struct ssb_device *dev, + const struct ssb_device_id *id) +{ + int err, tmp; + int start, len; + u16 chipid_top; + u16 coreid = dev->id.coreid; + struct ssb_hcd_device *usb_dev; + + /* USBcores are only connected on embedded devices. */ + chipid_top = (dev->bus->chip_id & 0xFF00); + if (chipid_top != 0x4700 && chipid_top != 0x5300) + return -ENODEV; + + /* TODO: Probably need checks here; is the core connected? */ + + if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) || + dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32))) + return -EOPNOTSUPP; + + usb_dev = kzalloc(sizeof(struct ssb_hcd_device), GFP_KERNEL); + if (!usb_dev) + return -ENOMEM; + + /* We currently always attach SSB_DEV_USB11_HOSTDEV + * as HOST OHCI. If we want to attach it as Client device, + * we must branch here and call into the (yet to + * be written) Client mode driver. Same for remove(). */ + usb_dev->enable_flags = ssb_hcd_init_chip(dev); + + tmp = ssb_read32(dev, SSB_ADMATCH0); + + start = ssb_admatch_base(tmp); + len = (coreid == SSB_DEV_USB20_HOST) ? 0x800 : ssb_admatch_size(tmp); + usb_dev->ohci_dev = ssb_hcd_create_pdev(dev, true, start, len); + if (IS_ERR(usb_dev->ohci_dev)) { + err = PTR_ERR(usb_dev->ohci_dev); + goto err_free_usb_dev; + } + + if (coreid == SSB_DEV_USB20_HOST) { + start = ssb_admatch_base(tmp) + 0x800; /* ehci core offset */ + usb_dev->ehci_dev = ssb_hcd_create_pdev(dev, false, start, len); + if (IS_ERR(usb_dev->ehci_dev)) { + err = PTR_ERR(usb_dev->ehci_dev); + goto err_unregister_ohci_dev; + } + } + + ssb_set_drvdata(dev, usb_dev); + return 0; + +err_unregister_ohci_dev: + platform_device_unregister(usb_dev->ohci_dev); +err_free_usb_dev: + kfree(usb_dev); + return err; +} + +static void __devexit ssb_hcd_remove(struct ssb_device *dev) +{ + struct ssb_hcd_device *usb_dev = ssb_get_drvdata(dev); + struct platform_device *ohci_dev = usb_dev->ohci_dev; + struct platform_device *ehci_dev = usb_dev->ehci_dev; + + if (ohci_dev) + platform_device_unregister(ohci_dev); + if (ehci_dev) + platform_device_unregister(ehci_dev); + + ssb_device_disable(dev, 0); +} + +static void __devexit ssb_hcd_shutdown(struct ssb_device *dev) +{ + ssb_device_disable(dev, 0); +} + +#ifdef CONFIG_PM + +static int ssb_hcd_suspend(struct ssb_device *dev, pm_message_t state) +{ + ssb_device_disable(dev, 0); + + return 0; +} + +static int ssb_hcd_resume(struct ssb_device *dev) +{ + struct ssb_hcd_device *usb_dev = ssb_get_drvdata(dev); + + ssb_device_enable(dev, usb_dev->enable_flags); + + return 0; +} + +#else /* !CONFIG_PM */ +#define ssb_hcd_suspend NULL +#define ssb_hcd_resume NULL +#endif /* CONFIG_PM */ + +static const struct ssb_device_id ssb_hcd_table[] __devinitconst = { + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV), + SSB_DEVTABLE_END +}; +MODULE_DEVICE_TABLE(ssb, ssb_hcd_table); + +static struct ssb_driver ssb_hcd_driver = { + .name = KBUILD_MODNAME, + .id_table = ssb_hcd_table, + .probe = ssb_hcd_probe, + .remove = __devexit_p(ssb_hcd_remove), + .shutdown = ssb_hcd_shutdown, + .suspend = ssb_hcd_suspend, + .resume = ssb_hcd_resume, +}; + +static int __init ssb_hcd_init(void) +{ + return ssb_driver_register(&ssb_hcd_driver); +} +module_init(ssb_hcd_init); + +static void __exit ssb_hcd_exit(void) +{ + ssb_driver_unregister(&ssb_hcd_driver); +} +module_exit(ssb_hcd_exit); diff --git a/trunk/drivers/usb/host/xhci-hub.c b/trunk/drivers/usb/host/xhci-hub.c index 673ad120c43e..2732ef660c5c 100644 --- a/trunk/drivers/usb/host/xhci-hub.c +++ b/trunk/drivers/usb/host/xhci-hub.c @@ -475,6 +475,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, struct xhci_bus_state *bus_state; u16 link_state = 0; u16 wake_mask = 0; + u16 timeout = 0; max_ports = xhci_get_ports(hcd, &port_array); bus_state = &xhci->bus_state[hcd_index(hcd)]; @@ -558,6 +559,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, xhci_dbg(xhci, "Resume USB2 port %d\n", wIndex + 1); bus_state->resume_done[wIndex] = 0; + clear_bit(wIndex, &bus_state->resuming_ports); xhci_set_link_state(xhci, port_array, wIndex, XDEV_U0); xhci_dbg(xhci, "set port %d resume\n", @@ -622,6 +624,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, link_state = (wIndex & 0xff00) >> 3; if (wValue == USB_PORT_FEAT_REMOTE_WAKE_MASK) wake_mask = wIndex & 0xff00; + /* The MSB of wIndex is the U1/U2 timeout */ + timeout = (wIndex & 0xff00) >> 8; wIndex &= 0xff; if (!wIndex || wIndex > max_ports) goto error; @@ -746,6 +750,22 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, temp = xhci_readl(xhci, port_array[wIndex]); break; + case USB_PORT_FEAT_U1_TIMEOUT: + if (hcd->speed != HCD_USB3) + goto error; + temp = xhci_readl(xhci, port_array[wIndex] + 1); + temp &= ~PORT_U1_TIMEOUT_MASK; + temp |= PORT_U1_TIMEOUT(timeout); + xhci_writel(xhci, temp, port_array[wIndex] + 1); + break; + case USB_PORT_FEAT_U2_TIMEOUT: + if (hcd->speed != HCD_USB3) + goto error; + temp = xhci_readl(xhci, port_array[wIndex] + 1); + temp &= ~PORT_U2_TIMEOUT_MASK; + temp |= PORT_U2_TIMEOUT(timeout); + xhci_writel(xhci, temp, port_array[wIndex] + 1); + break; default: goto error; } @@ -845,7 +865,12 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) /* Initial status is no changes */ retval = (max_ports + 8) / 8; memset(buf, 0, retval); - status = 0; + + /* + * Inform the usbcore about resume-in-progress by returning + * a non-zero value even if there are no status changes. + */ + status = bus_state->resuming_ports; mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC; @@ -885,15 +910,11 @@ int xhci_bus_suspend(struct usb_hcd *hcd) spin_lock_irqsave(&xhci->lock, flags); if (hcd->self.root_hub->do_remote_wakeup) { - port_index = max_ports; - while (port_index--) { - if (bus_state->resume_done[port_index] != 0) { - spin_unlock_irqrestore(&xhci->lock, flags); - xhci_dbg(xhci, "suspend failed because " - "port %d is resuming\n", - port_index + 1); - return -EBUSY; - } + if (bus_state->resuming_ports) { + spin_unlock_irqrestore(&xhci->lock, flags); + xhci_dbg(xhci, "suspend failed because " + "a port is resuming\n"); + return -EBUSY; } } diff --git a/trunk/drivers/usb/host/xhci-mem.c b/trunk/drivers/usb/host/xhci-mem.c index 68eaa908ac8e..ec4338eec826 100644 --- a/trunk/drivers/usb/host/xhci-mem.c +++ b/trunk/drivers/usb/host/xhci-mem.c @@ -1791,6 +1791,14 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) { struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); struct dev_info *dev_info, *next; + struct list_head *tt_list_head; + struct list_head *tt; + struct list_head *endpoints; + struct list_head *ep, *q; + struct xhci_tt_bw_info *tt_info; + struct xhci_interval_bw_table *bwt; + struct xhci_virt_ep *virt_ep; + unsigned long flags; int size; int i; @@ -1807,6 +1815,9 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci->event_ring = NULL; xhci_dbg(xhci, "Freed event ring\n"); + if (xhci->lpm_command) + xhci_free_command(xhci, xhci->lpm_command); + xhci->cmd_ring_reserved_trbs = 0; if (xhci->cmd_ring) xhci_ring_free(xhci, xhci->cmd_ring); xhci->cmd_ring = NULL; @@ -1849,8 +1860,26 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) } spin_unlock_irqrestore(&xhci->lock, flags); + bwt = &xhci->rh_bw->bw_table; + for (i = 0; i < XHCI_MAX_INTERVAL; i++) { + endpoints = &bwt->interval_bw[i].endpoints; + list_for_each_safe(ep, q, endpoints) { + virt_ep = list_entry(ep, struct xhci_virt_ep, bw_endpoint_list); + list_del(&virt_ep->bw_endpoint_list); + kfree(virt_ep); + } + } + + tt_list_head = &xhci->rh_bw->tts; + list_for_each_safe(tt, q, tt_list_head) { + tt_info = list_entry(tt, struct xhci_tt_bw_info, tt_list); + list_del(tt); + kfree(tt_info); + } + xhci->num_usb2_ports = 0; xhci->num_usb3_ports = 0; + xhci->num_active_eps = 0; kfree(xhci->usb2_ports); kfree(xhci->usb3_ports); kfree(xhci->port_array); @@ -2350,6 +2379,16 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring); xhci_dbg_cmd_ptrs(xhci); + xhci->lpm_command = xhci_alloc_command(xhci, true, true, flags); + if (!xhci->lpm_command) + goto fail; + + /* Reserve one command ring TRB for disabling LPM. + * Since the USB core grabs the shared usb_bus bandwidth mutex before + * disabling LPM, we only need to reserve one TRB for all devices. + */ + xhci->cmd_ring_reserved_trbs++; + val = xhci_readl(xhci, &xhci->cap_regs->db_off); val &= DBOFF_MASK; xhci_dbg(xhci, "// Doorbell array is located at offset 0x%x" diff --git a/trunk/drivers/usb/host/xhci-pci.c b/trunk/drivers/usb/host/xhci-pci.c index 7a856a767e77..18b231b0c5d3 100644 --- a/trunk/drivers/usb/host/xhci-pci.c +++ b/trunk/drivers/usb/host/xhci-pci.c @@ -72,6 +72,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) xhci_dbg(xhci, "QUIRK: Fresco Logic revision %u " "has broken MSI implementation\n", pdev->revision); + xhci->quirks |= XHCI_TRUST_TX_LENGTH; } if (pdev->vendor == PCI_VENDOR_ID_NEC) @@ -83,6 +84,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) /* AMD PLL quirk */ if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info()) xhci->quirks |= XHCI_AMD_PLL_FIX; + if (pdev->vendor == PCI_VENDOR_ID_INTEL) { + xhci->quirks |= XHCI_LPM_SUPPORT; + xhci->quirks |= XHCI_INTEL_HOST; + } if (pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI) { xhci->quirks |= XHCI_SPURIOUS_SUCCESS; @@ -169,6 +174,13 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) if (retval) goto put_usb3_hcd; /* Roothub already marked as USB 3.0 speed */ + + /* We know the LPM timeout algorithms for this host, let the USB core + * enable and disable LPM for devices under the USB 3.0 roothub. + */ + if (xhci->quirks & XHCI_LPM_SUPPORT) + hcd_to_bus(xhci->shared_hcd)->root_hub->lpm_capable = 1; + return 0; put_usb3_hcd: @@ -292,6 +304,8 @@ static const struct hc_driver xhci_pci_hc_driver = { */ .update_device = xhci_update_device, .set_usb2_hw_lpm = xhci_set_usb2_hardware_lpm, + .enable_usb3_lpm_timeout = xhci_enable_usb3_lpm_timeout, + .disable_usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout, }; /*-------------------------------------------------------------------------*/ diff --git a/trunk/drivers/usb/host/xhci-ring.c b/trunk/drivers/usb/host/xhci-ring.c index 3d9422f16a20..23b4aefd1036 100644 --- a/trunk/drivers/usb/host/xhci-ring.c +++ b/trunk/drivers/usb/host/xhci-ring.c @@ -1377,6 +1377,7 @@ static void handle_port_status(struct xhci_hcd *xhci, xhci_dbg(xhci, "resume HS port %d\n", port_id); bus_state->resume_done[faked_port_index] = jiffies + msecs_to_jiffies(20); + set_bit(faked_port_index, &bus_state->resuming_ports); mod_timer(&hcd->rh_timer, bus_state->resume_done[faked_port_index]); /* Do the rest in GetPortStatus */ @@ -1786,8 +1787,12 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, /* handle completion code */ switch (trb_comp_code) { case COMP_SUCCESS: - frame->status = 0; - break; + if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) { + frame->status = 0; + break; + } + if ((xhci->quirks & XHCI_TRUST_TX_LENGTH)) + trb_comp_code = COMP_SHORT_TX; case COMP_SHORT_TX: frame->status = td->urb->transfer_flags & URB_SHORT_NOT_OK ? -EREMOTEIO : 0; @@ -1803,6 +1808,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, break; case COMP_DEV_ERR: case COMP_STALL: + case COMP_TX_ERR: frame->status = -EPROTO; skip_td = true; break; @@ -1883,13 +1889,16 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, switch (trb_comp_code) { case COMP_SUCCESS: /* Double check that the HW transferred everything. */ - if (event_trb != td->last_trb) { + if (event_trb != td->last_trb || + TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { xhci_warn(xhci, "WARN Successful completion " "on short TX\n"); if (td->urb->transfer_flags & URB_SHORT_NOT_OK) *status = -EREMOTEIO; else *status = 0; + if ((xhci->quirks & XHCI_TRUST_TX_LENGTH)) + trb_comp_code = COMP_SHORT_TX; } else { *status = 0; } @@ -2048,6 +2057,13 @@ static int handle_tx_event(struct xhci_hcd *xhci, * transfer type */ case COMP_SUCCESS: + if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) + break; + if (xhci->quirks & XHCI_TRUST_TX_LENGTH) + trb_comp_code = COMP_SHORT_TX; + else + xhci_warn(xhci, "WARN Successful completion on short TX: " + "needs XHCI_TRUST_TX_LENGTH quirk?\n"); case COMP_SHORT_TX: break; case COMP_STOP: @@ -2270,7 +2286,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, (status != 0 && !usb_endpoint_xfer_isoc(&urb->ep->desc))) xhci_dbg(xhci, "Giveback URB %p, len = %d, " - "expected = %x, status = %d\n", + "expected = %d, status = %d\n", urb, urb->actual_length, urb->transfer_buffer_length, status); @@ -3593,12 +3609,12 @@ int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, /* Queue an evaluate context command TRB */ int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, - u32 slot_id) + u32 slot_id, bool command_must_succeed) { return queue_command(xhci, lower_32_bits(in_ctx_ptr), upper_32_bits(in_ctx_ptr), 0, TRB_TYPE(TRB_EVAL_CONTEXT) | SLOT_ID_FOR_TRB(slot_id), - false); + command_must_succeed); } /* diff --git a/trunk/drivers/usb/host/xhci.c b/trunk/drivers/usb/host/xhci.c index 36641a7f2371..afdc73ee84a6 100644 --- a/trunk/drivers/usb/host/xhci.c +++ b/trunk/drivers/usb/host/xhci.c @@ -152,7 +152,7 @@ int xhci_reset(struct xhci_hcd *xhci) { u32 command; u32 state; - int ret; + int ret, i; state = xhci_readl(xhci, &xhci->op_regs->status); if ((state & STS_HALT) == 0) { @@ -175,7 +175,15 @@ int xhci_reset(struct xhci_hcd *xhci) * xHCI cannot write to any doorbells or operational registers other * than status until the "Controller Not Ready" flag is cleared. */ - return handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000); + ret = handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000); + + for (i = 0; i < 2; ++i) { + xhci->bus_state[i].port_c_suspend = 0; + xhci->bus_state[i].suspended_ports = 0; + xhci->bus_state[i].resuming_ports = 0; + } + + return ret; } #ifdef CONFIG_PCI @@ -2438,7 +2446,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, udev->slot_id, must_succeed); else ret = xhci_queue_evaluate_context(xhci, in_ctx->dma, - udev->slot_id); + udev->slot_id, must_succeed); if (ret < 0) { if (command) list_del(&command->cmd_list); @@ -3863,6 +3871,474 @@ int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev) #endif /* CONFIG_USB_SUSPEND */ +/*---------------------- USB 3.0 Link PM functions ------------------------*/ + +#ifdef CONFIG_PM +/* Service interval in nanoseconds = 2^(bInterval - 1) * 125us * 1000ns / 1us */ +static unsigned long long xhci_service_interval_to_ns( + struct usb_endpoint_descriptor *desc) +{ + return (1 << (desc->bInterval - 1)) * 125 * 1000; +} + +static u16 xhci_get_timeout_no_hub_lpm(struct usb_device *udev, + enum usb3_link_state state) +{ + unsigned long long sel; + unsigned long long pel; + unsigned int max_sel_pel; + char *state_name; + + switch (state) { + case USB3_LPM_U1: + /* Convert SEL and PEL stored in nanoseconds to microseconds */ + sel = DIV_ROUND_UP(udev->u1_params.sel, 1000); + pel = DIV_ROUND_UP(udev->u1_params.pel, 1000); + max_sel_pel = USB3_LPM_MAX_U1_SEL_PEL; + state_name = "U1"; + break; + case USB3_LPM_U2: + sel = DIV_ROUND_UP(udev->u2_params.sel, 1000); + pel = DIV_ROUND_UP(udev->u2_params.pel, 1000); + max_sel_pel = USB3_LPM_MAX_U2_SEL_PEL; + state_name = "U2"; + break; + default: + dev_warn(&udev->dev, "%s: Can't get timeout for non-U1 or U2 state.\n", + __func__); + return -EINVAL; + } + + if (sel <= max_sel_pel && pel <= max_sel_pel) + return USB3_LPM_DEVICE_INITIATED; + + if (sel > max_sel_pel) + dev_dbg(&udev->dev, "Device-initiated %s disabled " + "due to long SEL %llu ms\n", + state_name, sel); + else + dev_dbg(&udev->dev, "Device-initiated %s disabled " + "due to long PEL %llu\n ms", + state_name, pel); + return USB3_LPM_DISABLED; +} + +/* Returns the hub-encoded U1 timeout value. + * The U1 timeout should be the maximum of the following values: + * - For control endpoints, U1 system exit latency (SEL) * 3 + * - For bulk endpoints, U1 SEL * 5 + * - For interrupt endpoints: + * - Notification EPs, U1 SEL * 3 + * - Periodic EPs, max(105% of bInterval, U1 SEL * 2) + * - For isochronous endpoints, max(105% of bInterval, U1 SEL * 2) + */ +static u16 xhci_calculate_intel_u1_timeout(struct usb_device *udev, + struct usb_endpoint_descriptor *desc) +{ + unsigned long long timeout_ns; + int ep_type; + int intr_type; + + ep_type = usb_endpoint_type(desc); + switch (ep_type) { + case USB_ENDPOINT_XFER_CONTROL: + timeout_ns = udev->u1_params.sel * 3; + break; + case USB_ENDPOINT_XFER_BULK: + timeout_ns = udev->u1_params.sel * 5; + break; + case USB_ENDPOINT_XFER_INT: + intr_type = usb_endpoint_interrupt_type(desc); + if (intr_type == USB_ENDPOINT_INTR_NOTIFICATION) { + timeout_ns = udev->u1_params.sel * 3; + break; + } + /* Otherwise the calculation is the same as isoc eps */ + case USB_ENDPOINT_XFER_ISOC: + timeout_ns = xhci_service_interval_to_ns(desc); + timeout_ns = DIV_ROUND_UP_ULL(timeout_ns * 105, 100); + if (timeout_ns < udev->u1_params.sel * 2) + timeout_ns = udev->u1_params.sel * 2; + break; + default: + return 0; + } + + /* The U1 timeout is encoded in 1us intervals. */ + timeout_ns = DIV_ROUND_UP_ULL(timeout_ns, 1000); + /* Don't return a timeout of zero, because that's USB3_LPM_DISABLED. */ + if (timeout_ns == USB3_LPM_DISABLED) + timeout_ns++; + + /* If the necessary timeout value is bigger than what we can set in the + * USB 3.0 hub, we have to disable hub-initiated U1. + */ + if (timeout_ns <= USB3_LPM_U1_MAX_TIMEOUT) + return timeout_ns; + dev_dbg(&udev->dev, "Hub-initiated U1 disabled " + "due to long timeout %llu ms\n", timeout_ns); + return xhci_get_timeout_no_hub_lpm(udev, USB3_LPM_U1); +} + +/* Returns the hub-encoded U2 timeout value. + * The U2 timeout should be the maximum of: + * - 10 ms (to avoid the bandwidth impact on the scheduler) + * - largest bInterval of any active periodic endpoint (to avoid going + * into lower power link states between intervals). + * - the U2 Exit Latency of the device + */ +static u16 xhci_calculate_intel_u2_timeout(struct usb_device *udev, + struct usb_endpoint_descriptor *desc) +{ + unsigned long long timeout_ns; + unsigned long long u2_del_ns; + + timeout_ns = 10 * 1000 * 1000; + + if ((usb_endpoint_xfer_int(desc) || usb_endpoint_xfer_isoc(desc)) && + (xhci_service_interval_to_ns(desc) > timeout_ns)) + timeout_ns = xhci_service_interval_to_ns(desc); + + u2_del_ns = udev->bos->ss_cap->bU2DevExitLat * 1000; + if (u2_del_ns > timeout_ns) + timeout_ns = u2_del_ns; + + /* The U2 timeout is encoded in 256us intervals */ + timeout_ns = DIV_ROUND_UP_ULL(timeout_ns, 256 * 1000); + /* If the necessary timeout value is bigger than what we can set in the + * USB 3.0 hub, we have to disable hub-initiated U2. + */ + if (timeout_ns <= USB3_LPM_U2_MAX_TIMEOUT) + return timeout_ns; + dev_dbg(&udev->dev, "Hub-initiated U2 disabled " + "due to long timeout %llu ms\n", timeout_ns); + return xhci_get_timeout_no_hub_lpm(udev, USB3_LPM_U2); +} + +static u16 xhci_call_host_update_timeout_for_endpoint(struct xhci_hcd *xhci, + struct usb_device *udev, + struct usb_endpoint_descriptor *desc, + enum usb3_link_state state, + u16 *timeout) +{ + if (state == USB3_LPM_U1) { + if (xhci->quirks & XHCI_INTEL_HOST) + return xhci_calculate_intel_u1_timeout(udev, desc); + } else { + if (xhci->quirks & XHCI_INTEL_HOST) + return xhci_calculate_intel_u2_timeout(udev, desc); + } + + return USB3_LPM_DISABLED; +} + +static int xhci_update_timeout_for_endpoint(struct xhci_hcd *xhci, + struct usb_device *udev, + struct usb_endpoint_descriptor *desc, + enum usb3_link_state state, + u16 *timeout) +{ + u16 alt_timeout; + + alt_timeout = xhci_call_host_update_timeout_for_endpoint(xhci, udev, + desc, state, timeout); + + /* If we found we can't enable hub-initiated LPM, or + * the U1 or U2 exit latency was too high to allow + * device-initiated LPM as well, just stop searching. + */ + if (alt_timeout == USB3_LPM_DISABLED || + alt_timeout == USB3_LPM_DEVICE_INITIATED) { + *timeout = alt_timeout; + return -E2BIG; + } + if (alt_timeout > *timeout) + *timeout = alt_timeout; + return 0; +} + +static int xhci_update_timeout_for_interface(struct xhci_hcd *xhci, + struct usb_device *udev, + struct usb_host_interface *alt, + enum usb3_link_state state, + u16 *timeout) +{ + int j; + + for (j = 0; j < alt->desc.bNumEndpoints; j++) { + if (xhci_update_timeout_for_endpoint(xhci, udev, + &alt->endpoint[j].desc, state, timeout)) + return -E2BIG; + continue; + } + return 0; +} + +static int xhci_check_intel_tier_policy(struct usb_device *udev, + enum usb3_link_state state) +{ + struct usb_device *parent; + unsigned int num_hubs; + + if (state == USB3_LPM_U2) + return 0; + + /* Don't enable U1 if the device is on a 2nd tier hub or lower. */ + for (parent = udev->parent, num_hubs = 0; parent->parent; + parent = parent->parent) + num_hubs++; + + if (num_hubs < 2) + return 0; + + dev_dbg(&udev->dev, "Disabling U1 link state for device" + " below second-tier hub.\n"); + dev_dbg(&udev->dev, "Plug device into first-tier hub " + "to decrease power consumption.\n"); + return -E2BIG; +} + +static int xhci_check_tier_policy(struct xhci_hcd *xhci, + struct usb_device *udev, + enum usb3_link_state state) +{ + if (xhci->quirks & XHCI_INTEL_HOST) + return xhci_check_intel_tier_policy(udev, state); + return -EINVAL; +} + +/* Returns the U1 or U2 timeout that should be enabled. + * If the tier check or timeout setting functions return with a non-zero exit + * code, that means the timeout value has been finalized and we shouldn't look + * at any more endpoints. + */ +static u16 xhci_calculate_lpm_timeout(struct usb_hcd *hcd, + struct usb_device *udev, enum usb3_link_state state) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct usb_host_config *config; + char *state_name; + int i; + u16 timeout = USB3_LPM_DISABLED; + + if (state == USB3_LPM_U1) + state_name = "U1"; + else if (state == USB3_LPM_U2) + state_name = "U2"; + else { + dev_warn(&udev->dev, "Can't enable unknown link state %i\n", + state); + return timeout; + } + + if (xhci_check_tier_policy(xhci, udev, state) < 0) + return timeout; + + /* Gather some information about the currently installed configuration + * and alternate interface settings. + */ + if (xhci_update_timeout_for_endpoint(xhci, udev, &udev->ep0.desc, + state, &timeout)) + return timeout; + + config = udev->actconfig; + if (!config) + return timeout; + + for (i = 0; i < USB_MAXINTERFACES; i++) { + struct usb_driver *driver; + struct usb_interface *intf = config->interface[i]; + + if (!intf) + continue; + + /* Check if any currently bound drivers want hub-initiated LPM + * disabled. + */ + if (intf->dev.driver) { + driver = to_usb_driver(intf->dev.driver); + if (driver && driver->disable_hub_initiated_lpm) { + dev_dbg(&udev->dev, "Hub-initiated %s disabled " + "at request of driver %s\n", + state_name, driver->name); + return xhci_get_timeout_no_hub_lpm(udev, state); + } + } + + /* Not sure how this could happen... */ + if (!intf->cur_altsetting) + continue; + + if (xhci_update_timeout_for_interface(xhci, udev, + intf->cur_altsetting, + state, &timeout)) + return timeout; + } + return timeout; +} + +/* + * Issue an Evaluate Context command to change the Maximum Exit Latency in the + * slot context. If that succeeds, store the new MEL in the xhci_virt_device. + */ +static int xhci_change_max_exit_latency(struct xhci_hcd *xhci, + struct usb_device *udev, u16 max_exit_latency) +{ + struct xhci_virt_device *virt_dev; + struct xhci_command *command; + struct xhci_input_control_ctx *ctrl_ctx; + struct xhci_slot_ctx *slot_ctx; + unsigned long flags; + int ret; + + spin_lock_irqsave(&xhci->lock, flags); + if (max_exit_latency == xhci->devs[udev->slot_id]->current_mel) { + spin_unlock_irqrestore(&xhci->lock, flags); + return 0; + } + + /* Attempt to issue an Evaluate Context command to change the MEL. */ + virt_dev = xhci->devs[udev->slot_id]; + command = xhci->lpm_command; + xhci_slot_copy(xhci, command->in_ctx, virt_dev->out_ctx); + spin_unlock_irqrestore(&xhci->lock, flags); + + ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx); + ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG); + slot_ctx = xhci_get_slot_ctx(xhci, command->in_ctx); + slot_ctx->dev_info2 &= cpu_to_le32(~((u32) MAX_EXIT)); + slot_ctx->dev_info2 |= cpu_to_le32(max_exit_latency); + + xhci_dbg(xhci, "Set up evaluate context for LPM MEL change.\n"); + xhci_dbg(xhci, "Slot %u Input Context:\n", udev->slot_id); + xhci_dbg_ctx(xhci, command->in_ctx, 0); + + /* Issue and wait for the evaluate context command. */ + ret = xhci_configure_endpoint(xhci, udev, command, + true, true); + xhci_dbg(xhci, "Slot %u Output Context:\n", udev->slot_id); + xhci_dbg_ctx(xhci, virt_dev->out_ctx, 0); + + if (!ret) { + spin_lock_irqsave(&xhci->lock, flags); + virt_dev->current_mel = max_exit_latency; + spin_unlock_irqrestore(&xhci->lock, flags); + } + return ret; +} + +static int calculate_max_exit_latency(struct usb_device *udev, + enum usb3_link_state state_changed, + u16 hub_encoded_timeout) +{ + unsigned long long u1_mel_us = 0; + unsigned long long u2_mel_us = 0; + unsigned long long mel_us = 0; + bool disabling_u1; + bool disabling_u2; + bool enabling_u1; + bool enabling_u2; + + disabling_u1 = (state_changed == USB3_LPM_U1 && + hub_encoded_timeout == USB3_LPM_DISABLED); + disabling_u2 = (state_changed == USB3_LPM_U2 && + hub_encoded_timeout == USB3_LPM_DISABLED); + + enabling_u1 = (state_changed == USB3_LPM_U1 && + hub_encoded_timeout != USB3_LPM_DISABLED); + enabling_u2 = (state_changed == USB3_LPM_U2 && + hub_encoded_timeout != USB3_LPM_DISABLED); + + /* If U1 was already enabled and we're not disabling it, + * or we're going to enable U1, account for the U1 max exit latency. + */ + if ((udev->u1_params.timeout != USB3_LPM_DISABLED && !disabling_u1) || + enabling_u1) + u1_mel_us = DIV_ROUND_UP(udev->u1_params.mel, 1000); + if ((udev->u2_params.timeout != USB3_LPM_DISABLED && !disabling_u2) || + enabling_u2) + u2_mel_us = DIV_ROUND_UP(udev->u2_params.mel, 1000); + + if (u1_mel_us > u2_mel_us) + mel_us = u1_mel_us; + else + mel_us = u2_mel_us; + /* xHCI host controller max exit latency field is only 16 bits wide. */ + if (mel_us > MAX_EXIT) { + dev_warn(&udev->dev, "Link PM max exit latency of %lluus " + "is too big.\n", mel_us); + return -E2BIG; + } + return mel_us; +} + +/* Returns the USB3 hub-encoded value for the U1/U2 timeout. */ +int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd, + struct usb_device *udev, enum usb3_link_state state) +{ + struct xhci_hcd *xhci; + u16 hub_encoded_timeout; + int mel; + int ret; + + xhci = hcd_to_xhci(hcd); + /* The LPM timeout values are pretty host-controller specific, so don't + * enable hub-initiated timeouts unless the vendor has provided + * information about their timeout algorithm. + */ + if (!xhci || !(xhci->quirks & XHCI_LPM_SUPPORT) || + !xhci->devs[udev->slot_id]) + return USB3_LPM_DISABLED; + + hub_encoded_timeout = xhci_calculate_lpm_timeout(hcd, udev, state); + mel = calculate_max_exit_latency(udev, state, hub_encoded_timeout); + if (mel < 0) { + /* Max Exit Latency is too big, disable LPM. */ + hub_encoded_timeout = USB3_LPM_DISABLED; + mel = 0; + } + + ret = xhci_change_max_exit_latency(xhci, udev, mel); + if (ret) + return ret; + return hub_encoded_timeout; +} + +int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd, + struct usb_device *udev, enum usb3_link_state state) +{ + struct xhci_hcd *xhci; + u16 mel; + int ret; + + xhci = hcd_to_xhci(hcd); + if (!xhci || !(xhci->quirks & XHCI_LPM_SUPPORT) || + !xhci->devs[udev->slot_id]) + return 0; + + mel = calculate_max_exit_latency(udev, state, USB3_LPM_DISABLED); + ret = xhci_change_max_exit_latency(xhci, udev, mel); + if (ret) + return ret; + return 0; +} +#else /* CONFIG_PM */ + +int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd, + struct usb_device *udev, enum usb3_link_state state) +{ + return USB3_LPM_DISABLED; +} + +int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd, + struct usb_device *udev, enum usb3_link_state state) +{ + return 0; +} +#endif /* CONFIG_PM */ + +/*-------------------------------------------------------------------------*/ + /* Once a hub descriptor is fetched for a device, we need to update the xHC's * internal data structures for the device. */ @@ -4090,7 +4566,6 @@ static int __init xhci_hcd_init(void) BUILD_BUG_ON(sizeof(struct xhci_intr_reg) != 8*32/8); /* xhci_run_regs has eight fields and embeds 128 xhci_intr_regs */ BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8); - BUILD_BUG_ON(sizeof(struct xhci_doorbell_array) != 256*32/8); return 0; unreg_pci: xhci_unregister_pci(); diff --git a/trunk/drivers/usb/host/xhci.h b/trunk/drivers/usb/host/xhci.h index 3d69c4b2b542..de3d6e3e57be 100644 --- a/trunk/drivers/usb/host/xhci.h +++ b/trunk/drivers/usb/host/xhci.h @@ -362,8 +362,10 @@ struct xhci_op_regs { * Timeout can be up to 127us. 0xFF means an infinite timeout. */ #define PORT_U1_TIMEOUT(p) ((p) & 0xff) +#define PORT_U1_TIMEOUT_MASK 0xff /* Inactivity timer value for transitions into U2 */ #define PORT_U2_TIMEOUT(p) (((p) & 0xff) << 8) +#define PORT_U2_TIMEOUT_MASK (0xff << 8) /* Bits 24:31 for port testing */ /* USB2 Protocol PORTSPMSC */ @@ -914,6 +916,8 @@ struct xhci_virt_device { u8 real_port; struct xhci_interval_bw_table *bw_table; struct xhci_tt_bw_info *tt_info; + /* The current max exit latency for the enabled USB3 link states. */ + u16 current_mel; }; /* @@ -1362,6 +1366,8 @@ struct xhci_bus_state { u32 suspended_ports; u32 port_remote_wakeup; unsigned long resume_done[USB_MAXCHILDREN]; + /* which ports have started to resume */ + unsigned long resuming_ports; }; static inline unsigned int hcd_index(struct usb_hcd *hcd) @@ -1422,6 +1428,8 @@ struct xhci_hcd { /* slot enabling and address device helpers */ struct completion addr_dev; int slot_id; + /* For USB 3.0 LPM enable/disable. */ + struct xhci_command *lpm_command; /* Internal mirror of the HW's dcbaa */ struct xhci_virt_device *devs[MAX_HC_SLOTS]; /* For keeping track of bandwidth domains per roothub. */ @@ -1479,6 +1487,9 @@ struct xhci_hcd { #define XHCI_RESET_ON_RESUME (1 << 7) #define XHCI_SW_BW_CHECKING (1 << 8) #define XHCI_AMD_0x96_HOST (1 << 9) +#define XHCI_TRUST_TX_LENGTH (1 << 10) +#define XHCI_LPM_SUPPORT (1 << 11) +#define XHCI_INTEL_HOST (1 << 12) unsigned int num_active_eps; unsigned int limit_active_eps; /* There are two roothubs to keep track of bus suspend info for */ @@ -1752,7 +1763,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, u32 slot_id, bool command_must_succeed); int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, - u32 slot_id); + u32 slot_id, bool command_must_succeed); int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id, unsigned int ep_index); int xhci_queue_reset_device(struct xhci_hcd *xhci, u32 slot_id); @@ -1776,6 +1787,10 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id, /* xHCI roothub code */ void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array, int port_id, u32 link_state); +int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd, + struct usb_device *udev, enum usb3_link_state state); +int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd, + struct usb_device *udev, enum usb3_link_state state); void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array, int port_id, u32 port_bit); int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, diff --git a/trunk/drivers/usb/image/mdc800.c b/trunk/drivers/usb/image/mdc800.c index 575b56c79e97..7121b50098d3 100644 --- a/trunk/drivers/usb/image/mdc800.c +++ b/trunk/drivers/usb/image/mdc800.c @@ -284,18 +284,16 @@ static void mdc800_usb_irq (struct urb *urb) int data_received=0, wake_up; unsigned char* b=urb->transfer_buffer; struct mdc800_data* mdc800=urb->context; + struct device *dev = &mdc800->dev->dev; int status = urb->status; if (status >= 0) { - - //dbg ("%i %i %i %i %i %i %i %i \n",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]); - if (mdc800_isBusy (b)) { if (!mdc800->camera_busy) { mdc800->camera_busy=1; - dbg ("gets busy"); + dev_dbg(dev, "gets busy\n"); } } else @@ -303,13 +301,13 @@ static void mdc800_usb_irq (struct urb *urb) if (mdc800->camera_busy && mdc800_isReady (b)) { mdc800->camera_busy=0; - dbg ("gets ready"); + dev_dbg(dev, "gets ready\n"); } } if (!(mdc800_isBusy (b) || mdc800_isReady (b))) { /* Store Data in camera_answer field */ - dbg ("%i %i %i %i %i %i %i %i ",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]); + dev_dbg(dev, "%i %i %i %i %i %i %i %i \n",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]); memcpy (mdc800->camera_response,b,8); data_received=1; @@ -441,7 +439,7 @@ static int mdc800_usb_probe (struct usb_interface *intf, int irq_interval=0; int retval; - dbg ("(mdc800_usb_probe) called."); + dev_dbg(&intf->dev, "(%s) called.\n", __func__); if (mdc800->dev != NULL) @@ -554,7 +552,7 @@ static void mdc800_usb_disconnect (struct usb_interface *intf) { struct mdc800_data* mdc800 = usb_get_intfdata(intf); - dbg ("(mdc800_usb_disconnect) called"); + dev_dbg(&intf->dev, "(%s) called\n", __func__); if (mdc800) { if (mdc800->state == NOT_CONNECTED) @@ -656,7 +654,7 @@ static int mdc800_device_open (struct inode* inode, struct file *file) } mdc800->open=1; - dbg ("Mustek MDC800 device opened."); + dev_dbg(&mdc800->dev->dev, "Mustek MDC800 device opened.\n"); error_out: mutex_unlock(&mdc800->io_lock); @@ -670,7 +668,6 @@ static int mdc800_device_open (struct inode* inode, struct file *file) static int mdc800_device_release (struct inode* inode, struct file *file) { int retval=0; - dbg ("Mustek MDC800 device closed."); mutex_lock(&mdc800->io_lock); if (mdc800->open && (mdc800->state != NOT_CONNECTED)) @@ -927,7 +924,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s { mdc800->pic_len=(int) 65536*(unsigned char) mdc800->camera_response[0]+256*(unsigned char) mdc800->camera_response[1]+(unsigned char) mdc800->camera_response[2]; - dbg ("cached imagesize = %i",mdc800->pic_len); + dev_dbg(&mdc800->dev->dev, "cached imagesize = %i\n", mdc800->pic_len); } } diff --git a/trunk/drivers/usb/misc/appledisplay.c b/trunk/drivers/usb/misc/appledisplay.c index ac0d75a9005a..0fc6e5fc745f 100644 --- a/trunk/drivers/usb/misc/appledisplay.c +++ b/trunk/drivers/usb/misc/appledisplay.c @@ -88,6 +88,7 @@ static struct workqueue_struct *wq; static void appledisplay_complete(struct urb *urb) { struct appledisplay *pdata = urb->context; + struct device *dev = &pdata->udev->dev; unsigned long flags; int status = urb->status; int retval; @@ -97,18 +98,18 @@ static void appledisplay_complete(struct urb *urb) /* success */ break; case -EOVERFLOW: - printk(KERN_ERR "appletouch: OVERFLOW with data " - "length %d, actual length is %d\n", + dev_err(dev, + "OVERFLOW with data length %d, actual length is %d\n", ACD_URB_BUFFER_LEN, pdata->urb->actual_length); case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: /* This urb is terminated, clean up */ - dbg("%s - urb shuttingdown with status: %d", + dev_dbg(dev, "%s - urb shuttingdown with status: %d\n", __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", + dev_dbg(dev, "%s - nonzero urb status received: %d/n", __func__, status); goto exit; } @@ -132,8 +133,7 @@ static void appledisplay_complete(struct urb *urb) exit: retval = usb_submit_urb(pdata->urb, GFP_ATOMIC); if (retval) { - dev_err(&pdata->udev->dev, - "%s - usb_submit_urb failed with result %d\n", + dev_err(dev, "%s - usb_submit_urb failed with result %d\n", __func__, retval); } } diff --git a/trunk/drivers/usb/misc/emi26.c b/trunk/drivers/usb/misc/emi26.c index da97dcec1f32..d65984dee751 100644 --- a/trunk/drivers/usb/misc/emi26.c +++ b/trunk/drivers/usb/misc/emi26.c @@ -78,18 +78,14 @@ static int emi26_load_firmware (struct usb_device *dev) const struct firmware *bitstream_fw = NULL; const struct firmware *firmware_fw = NULL; const struct ihex_binrec *rec; - int err; + int err = -ENOMEM; int i; __u32 addr; /* Address to write */ __u8 *buf; buf = kmalloc(FW_LOAD_SIZE, GFP_KERNEL); - if (!buf) { - dev_err(&dev->dev, "%s - error loading firmware: error = %d\n", - __func__, -ENOMEM); - err = -ENOMEM; + if (!buf) goto wraperr; - } err = request_ihex_firmware(&loader_fw, "emi26/loader.fw", &dev->dev); if (err) @@ -111,11 +107,8 @@ static int emi26_load_firmware (struct usb_device *dev) /* Assert reset (stop the CPU in the EMI) */ err = emi26_set_reset(dev,1); - if (err < 0) { - dev_err(&dev->dev,"%s - error loading firmware: error = %d\n", - __func__, err); + if (err < 0) goto wraperr; - } rec = (const struct ihex_binrec *)loader_fw->data; /* 1. We need to put the loader for the FPGA into the EZ-USB */ @@ -123,19 +116,15 @@ static int emi26_load_firmware (struct usb_device *dev) err = emi26_writememory(dev, be32_to_cpu(rec->addr), rec->data, be16_to_cpu(rec->len), ANCHOR_LOAD_INTERNAL); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } rec = ihex_next_binrec(rec); } /* De-assert reset (let the CPU run) */ err = emi26_set_reset(dev,0); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } msleep(250); /* let device settle */ /* 2. We upload the FPGA firmware into the EMI @@ -153,18 +142,14 @@ static int emi26_load_firmware (struct usb_device *dev) rec = ihex_next_binrec(rec); } err = emi26_writememory(dev, addr, buf, i, ANCHOR_LOAD_FPGA); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } } while (rec); /* Assert reset (stop the CPU in the EMI) */ err = emi26_set_reset(dev,1); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } /* 3. We need to put the loader for the firmware into the EZ-USB (again...) */ for (rec = (const struct ihex_binrec *)loader_fw->data; @@ -172,19 +157,15 @@ static int emi26_load_firmware (struct usb_device *dev) err = emi26_writememory(dev, be32_to_cpu(rec->addr), rec->data, be16_to_cpu(rec->len), ANCHOR_LOAD_INTERNAL); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } } msleep(250); /* let device settle */ /* De-assert reset (let the CPU run) */ err = emi26_set_reset(dev,0); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } /* 4. We put the part of the firmware that lies in the external RAM into the EZ-USB */ @@ -194,19 +175,15 @@ static int emi26_load_firmware (struct usb_device *dev) err = emi26_writememory(dev, be32_to_cpu(rec->addr), rec->data, be16_to_cpu(rec->len), ANCHOR_LOAD_EXTERNAL); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } } } - + /* Assert reset (stop the CPU in the EMI) */ err = emi26_set_reset(dev,1); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } for (rec = (const struct ihex_binrec *)firmware_fw->data; rec; rec = ihex_next_binrec(rec)) { @@ -214,19 +191,15 @@ static int emi26_load_firmware (struct usb_device *dev) err = emi26_writememory(dev, be32_to_cpu(rec->addr), rec->data, be16_to_cpu(rec->len), ANCHOR_LOAD_INTERNAL); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } } } /* De-assert reset (let the CPU run) */ err = emi26_set_reset(dev,0); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } msleep(250); /* let device settle */ /* return 1 to fail the driver inialization @@ -234,6 +207,10 @@ static int emi26_load_firmware (struct usb_device *dev) err = 1; wraperr: + if (err < 0) + dev_err(&dev->dev,"%s - error loading firmware: error = %d\n", + __func__, err); + release_firmware(loader_fw); release_firmware(bitstream_fw); release_firmware(firmware_fw); diff --git a/trunk/drivers/usb/misc/emi62.c b/trunk/drivers/usb/misc/emi62.c index 4e0f167a6c4e..ff08015b230c 100644 --- a/trunk/drivers/usb/misc/emi62.c +++ b/trunk/drivers/usb/misc/emi62.c @@ -56,7 +56,7 @@ static int emi62_writememory(struct usb_device *dev, int address, unsigned char *buffer = kmemdup(data, length, GFP_KERNEL); if (!buffer) { - err("emi62: kmalloc(%d) failed.", length); + dev_err(&dev->dev, "kmalloc(%d) failed.\n", length); return -ENOMEM; } /* Note: usb_control_msg returns negative value on error or length of the @@ -73,9 +73,8 @@ static int emi62_set_reset (struct usb_device *dev, unsigned char reset_bit) dev_info(&dev->dev, "%s - %d\n", __func__, reset_bit); response = emi62_writememory (dev, CPUCS_REG, &reset_bit, 1, 0xa0); - if (response < 0) { - err("emi62: set_reset (%d) failed", reset_bit); - } + if (response < 0) + dev_err(&dev->dev, "set_reset (%d) failed\n", reset_bit); return response; } @@ -87,18 +86,15 @@ static int emi62_load_firmware (struct usb_device *dev) const struct firmware *bitstream_fw = NULL; const struct firmware *firmware_fw = NULL; const struct ihex_binrec *rec; - int err; + int err = -ENOMEM; int i; __u32 addr; /* Address to write */ __u8 *buf; dev_dbg(&dev->dev, "load_firmware\n"); buf = kmalloc(FW_LOAD_SIZE, GFP_KERNEL); - if (!buf) { - err( "%s - error loading firmware: error = %d", __func__, -ENOMEM); - err = -ENOMEM; + if (!buf) goto wraperr; - } err = request_ihex_firmware(&loader_fw, "emi62/loader.fw", &dev->dev); if (err) @@ -112,16 +108,13 @@ static int emi62_load_firmware (struct usb_device *dev) err = request_ihex_firmware(&firmware_fw, FIRMWARE_FW, &dev->dev); if (err) { nofw: - err( "%s - request_firmware() failed", __func__); goto wraperr; } /* Assert reset (stop the CPU in the EMI) */ err = emi62_set_reset(dev,1); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } rec = (const struct ihex_binrec *)loader_fw->data; @@ -130,19 +123,15 @@ static int emi62_load_firmware (struct usb_device *dev) err = emi62_writememory(dev, be32_to_cpu(rec->addr), rec->data, be16_to_cpu(rec->len), ANCHOR_LOAD_INTERNAL); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } rec = ihex_next_binrec(rec); } /* De-assert reset (let the CPU run) */ err = emi62_set_reset(dev,0); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } msleep(250); /* let device settle */ /* 2. We upload the FPGA firmware into the EMI @@ -160,18 +149,14 @@ static int emi62_load_firmware (struct usb_device *dev) rec = ihex_next_binrec(rec); } err = emi62_writememory(dev, addr, buf, i, ANCHOR_LOAD_FPGA); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } } while (rec); /* Assert reset (stop the CPU in the EMI) */ err = emi62_set_reset(dev,1); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } /* 3. We need to put the loader for the firmware into the EZ-USB (again...) */ for (rec = (const struct ihex_binrec *)loader_fw->data; @@ -179,18 +164,14 @@ static int emi62_load_firmware (struct usb_device *dev) err = emi62_writememory(dev, be32_to_cpu(rec->addr), rec->data, be16_to_cpu(rec->len), ANCHOR_LOAD_INTERNAL); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } } /* De-assert reset (let the CPU run) */ err = emi62_set_reset(dev,0); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } msleep(250); /* let device settle */ /* 4. We put the part of the firmware that lies in the external RAM into the EZ-USB */ @@ -201,19 +182,15 @@ static int emi62_load_firmware (struct usb_device *dev) err = emi62_writememory(dev, be32_to_cpu(rec->addr), rec->data, be16_to_cpu(rec->len), ANCHOR_LOAD_EXTERNAL); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } } } /* Assert reset (stop the CPU in the EMI) */ err = emi62_set_reset(dev,1); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } for (rec = (const struct ihex_binrec *)firmware_fw->data; rec; rec = ihex_next_binrec(rec)) { @@ -221,19 +198,15 @@ static int emi62_load_firmware (struct usb_device *dev) err = emi62_writememory(dev, be32_to_cpu(rec->addr), rec->data, be16_to_cpu(rec->len), ANCHOR_LOAD_EXTERNAL); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } } } /* De-assert reset (let the CPU run) */ err = emi62_set_reset(dev,0); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } msleep(250); /* let device settle */ release_firmware(loader_fw); @@ -247,6 +220,9 @@ static int emi62_load_firmware (struct usb_device *dev) return 1; wraperr: + if (err < 0) + dev_err(&dev->dev,"%s - error loading firmware: error = %d\n", + __func__, err); release_firmware(loader_fw); release_firmware(bitstream_fw); release_firmware(firmware_fw); diff --git a/trunk/drivers/usb/misc/idmouse.c b/trunk/drivers/usb/misc/idmouse.c index 0dee24698504..ce978384fda1 100644 --- a/trunk/drivers/usb/misc/idmouse.c +++ b/trunk/drivers/usb/misc/idmouse.c @@ -200,7 +200,8 @@ static int idmouse_create_image(struct usb_idmouse *dev) return -EAGAIN; /* should be IMGSIZE == 65040 */ - dbg("read %d bytes fingerprint data", bytes_read); + dev_dbg(&dev->interface->dev, "read %d bytes fingerprint data\n", + bytes_read); return result; } @@ -366,14 +367,14 @@ static int idmouse_probe(struct usb_interface *interface, kmalloc(IMGSIZE + dev->bulk_in_size, GFP_KERNEL); if (!dev->bulk_in_buffer) { - err("Unable to allocate input buffer."); + dev_err(&interface->dev, "Unable to allocate input buffer.\n"); idmouse_delete(dev); return -ENOMEM; } } if (!(dev->bulk_in_endpointAddr)) { - err("Unable to find bulk-in endpoint."); + dev_err(&interface->dev, "Unable to find bulk-in endpoint.\n"); idmouse_delete(dev); return -ENODEV; } @@ -385,7 +386,7 @@ static int idmouse_probe(struct usb_interface *interface, result = usb_register_dev(interface, &idmouse_class); if (result) { /* something prevented us from registering this device */ - err("Unble to allocate minor number."); + dev_err(&interface->dev, "Unble to allocate minor number.\n"); usb_set_intfdata(interface, NULL); idmouse_delete(dev); return result; diff --git a/trunk/drivers/usb/misc/iowarrior.c b/trunk/drivers/usb/misc/iowarrior.c index 4fd0dc835ae5..db46143c67a6 100644 --- a/trunk/drivers/usb/misc/iowarrior.c +++ b/trunk/drivers/usb/misc/iowarrior.c @@ -610,8 +610,8 @@ static int iowarrior_open(struct inode *inode, struct file *file) interface = usb_find_interface(&iowarrior_driver, subminor); if (!interface) { mutex_unlock(&iowarrior_mutex); - err("%s - error, can't find device for minor %d", __func__, - subminor); + printk(KERN_ERR "%s - error, can't find device for minor %d\n", + __func__, subminor); return -ENODEV; } diff --git a/trunk/drivers/usb/misc/ldusb.c b/trunk/drivers/usb/misc/ldusb.c index 5db4ab52061e..ac762299eaa8 100644 --- a/trunk/drivers/usb/misc/ldusb.c +++ b/trunk/drivers/usb/misc/ldusb.c @@ -334,8 +334,8 @@ static int ld_usb_open(struct inode *inode, struct file *file) interface = usb_find_interface(&ld_usb_driver, subminor); if (!interface) { - err("%s - error, can't find device for minor %d\n", - __func__, subminor); + printk(KERN_ERR "%s - error, can't find device for minor %d\n", + __func__, subminor); return -ENODEV; } @@ -485,7 +485,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count, /* verify that the device wasn't unplugged */ if (dev->intf == NULL) { retval = -ENODEV; - err("No device or device unplugged %d\n", retval); + printk(KERN_ERR "ldusb: No device or device unplugged %d\n", retval); goto unlock_exit; } @@ -565,7 +565,7 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer, /* verify that the device wasn't unplugged */ if (dev->intf == NULL) { retval = -ENODEV; - err("No device or device unplugged %d\n", retval); + printk(KERN_ERR "ldusb: No device or device unplugged %d\n", retval); goto unlock_exit; } @@ -603,7 +603,9 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer, bytes_to_write, USB_CTRL_SET_TIMEOUT * HZ); if (retval < 0) - err("Couldn't submit HID_REQ_SET_REPORT %d\n", retval); + dev_err(&dev->intf->dev, + "Couldn't submit HID_REQ_SET_REPORT %d\n", + retval); goto unlock_exit; } @@ -624,7 +626,8 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer, retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL); if (retval) { dev->interrupt_out_busy = 0; - err("Couldn't submit interrupt_out_urb %d\n", retval); + dev_err(&dev->intf->dev, + "Couldn't submit interrupt_out_urb %d\n", retval); goto unlock_exit; } retval = bytes_to_write; diff --git a/trunk/drivers/usb/misc/legousbtower.c b/trunk/drivers/usb/misc/legousbtower.c index 575222042767..a2702cbfe804 100644 --- a/trunk/drivers/usb/misc/legousbtower.c +++ b/trunk/drivers/usb/misc/legousbtower.c @@ -354,8 +354,8 @@ static int tower_open (struct inode *inode, struct file *file) interface = usb_find_interface (&tower_driver, subminor); if (!interface) { - err ("%s - error, can't find device for minor %d", - __func__, subminor); + printk(KERN_ERR "%s - error, can't find device for minor %d\n", + __func__, subminor); retval = -ENODEV; goto exit; } @@ -397,7 +397,8 @@ static int tower_open (struct inode *inode, struct file *file) sizeof(reset_reply), 1000); if (result < 0) { - err("LEGO USB Tower reset control request failed"); + dev_err(&dev->udev->dev, + "LEGO USB Tower reset control request failed\n"); retval = result; goto unlock_exit; } @@ -420,7 +421,8 @@ static int tower_open (struct inode *inode, struct file *file) retval = usb_submit_urb (dev->interrupt_in_urb, GFP_KERNEL); if (retval) { - err("Couldn't submit interrupt_in_urb %d", retval); + dev_err(&dev->udev->dev, + "Couldn't submit interrupt_in_urb %d\n", retval); dev->interrupt_in_running = 0; dev->open_count = 0; goto unlock_exit; @@ -608,7 +610,7 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count, /* verify that the device wasn't unplugged */ if (dev->udev == NULL) { retval = -ENODEV; - err("No device or device unplugged %d", retval); + printk(KERN_ERR "legousbtower: No device or device unplugged %d\n", retval); goto unlock_exit; } @@ -697,7 +699,7 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t /* verify that the device wasn't unplugged */ if (dev->udev == NULL) { retval = -ENODEV; - err("No device or device unplugged %d", retval); + printk(KERN_ERR "legousbtower: No device or device unplugged %d\n", retval); goto unlock_exit; } @@ -744,7 +746,8 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t retval = usb_submit_urb (dev->interrupt_out_urb, GFP_KERNEL); if (retval) { dev->interrupt_out_busy = 0; - err("Couldn't submit interrupt_out_urb %d", retval); + dev_err(&dev->udev->dev, + "Couldn't submit interrupt_out_urb %d\n", retval); goto unlock_exit; } retval = bytes_to_write; @@ -803,9 +806,10 @@ static void tower_interrupt_in_callback (struct urb *urb) /* resubmit if we're still running */ if (dev->interrupt_in_running && dev->udev) { retval = usb_submit_urb (dev->interrupt_in_urb, GFP_ATOMIC); - if (retval) { - err("%s: usb_submit_urb failed (%d)", __func__, retval); - } + if (retval) + dev_err(&dev->udev->dev, + "%s: usb_submit_urb failed (%d)\n", + __func__, retval); } exit: @@ -852,6 +856,7 @@ static void tower_interrupt_out_callback (struct urb *urb) */ static int tower_probe (struct usb_interface *interface, const struct usb_device_id *id) { + struct device *idev = &interface->dev; struct usb_device *udev = interface_to_usbdev(interface); struct lego_usb_tower *dev = NULL; struct usb_host_interface *iface_desc; @@ -871,7 +876,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device dev = kmalloc (sizeof(struct lego_usb_tower), GFP_KERNEL); if (dev == NULL) { - err ("Out of memory"); + dev_err(idev, "Out of memory\n"); goto exit; } @@ -915,37 +920,37 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device } } if(dev->interrupt_in_endpoint == NULL) { - err("interrupt in endpoint not found"); + dev_err(idev, "interrupt in endpoint not found\n"); goto error; } if (dev->interrupt_out_endpoint == NULL) { - err("interrupt out endpoint not found"); + dev_err(idev, "interrupt out endpoint not found\n"); goto error; } dev->read_buffer = kmalloc (read_buffer_size, GFP_KERNEL); if (!dev->read_buffer) { - err("Couldn't allocate read_buffer"); + dev_err(idev, "Couldn't allocate read_buffer\n"); goto error; } dev->interrupt_in_buffer = kmalloc (usb_endpoint_maxp(dev->interrupt_in_endpoint), GFP_KERNEL); if (!dev->interrupt_in_buffer) { - err("Couldn't allocate interrupt_in_buffer"); + dev_err(idev, "Couldn't allocate interrupt_in_buffer\n"); goto error; } dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->interrupt_in_urb) { - err("Couldn't allocate interrupt_in_urb"); + dev_err(idev, "Couldn't allocate interrupt_in_urb\n"); goto error; } dev->interrupt_out_buffer = kmalloc (write_buffer_size, GFP_KERNEL); if (!dev->interrupt_out_buffer) { - err("Couldn't allocate interrupt_out_buffer"); + dev_err(idev, "Couldn't allocate interrupt_out_buffer\n"); goto error; } dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->interrupt_out_urb) { - err("Couldn't allocate interrupt_out_urb"); + dev_err(idev, "Couldn't allocate interrupt_out_urb\n"); goto error; } dev->interrupt_in_interval = interrupt_in_interval ? interrupt_in_interval : dev->interrupt_in_endpoint->bInterval; @@ -958,7 +963,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device if (retval) { /* something prevented us from registering this driver */ - err ("Not able to get a minor for this device."); + dev_err(idev, "Not able to get a minor for this device.\n"); usb_set_intfdata (interface, NULL); goto error; } @@ -980,7 +985,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device sizeof(get_version_reply), 1000); if (result < 0) { - err("LEGO USB Tower get version control request failed"); + dev_err(idev, "LEGO USB Tower get version control request failed\n"); retval = result; goto error; } diff --git a/trunk/drivers/usb/misc/rio500.c b/trunk/drivers/usb/misc/rio500.c index 487a8ce0775e..1084124c4a44 100644 --- a/trunk/drivers/usb/misc/rio500.c +++ b/trunk/drivers/usb/misc/rio500.c @@ -153,10 +153,10 @@ static long ioctl_rio(struct file *file, unsigned int cmd, unsigned long arg) requesttype = rio_cmd.requesttype | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE; - dbg - ("sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x", - requesttype, rio_cmd.request, rio_cmd.value, - rio_cmd.index, rio_cmd.length); + dev_dbg(&rio->rio_dev->dev, + "sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n", + requesttype, rio_cmd.request, rio_cmd.value, + rio_cmd.index, rio_cmd.length); /* Send rio control message */ retries = 3; while (retries) { @@ -171,11 +171,14 @@ static long ioctl_rio(struct file *file, unsigned int cmd, unsigned long arg) if (result == -ETIMEDOUT) retries--; else if (result < 0) { - err("Error executing ioctrl. code = %d", result); + dev_err(&rio->rio_dev->dev, + "Error executing ioctrl. code = %d\n", + result); retries = 0; } else { - dbg("Executed ioctl. Result = %d (data=%02x)", - result, buffer[0]); + dev_dbg(&rio->rio_dev->dev, + "Executed ioctl. Result = %d (data=%02x)\n", + result, buffer[0]); if (copy_to_user(rio_cmd.buffer, buffer, rio_cmd.length)) { free_page((unsigned long) buffer); @@ -221,9 +224,10 @@ static long ioctl_rio(struct file *file, unsigned int cmd, unsigned long arg) requesttype = rio_cmd.requesttype | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; - dbg("sending command: reqtype=%0x req=%0x value=%0x index=%0x len=%0x", - requesttype, rio_cmd.request, rio_cmd.value, - rio_cmd.index, rio_cmd.length); + dev_dbg(&rio->rio_dev->dev, + "sending command: reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n", + requesttype, rio_cmd.request, rio_cmd.value, + rio_cmd.index, rio_cmd.length); /* Send rio control message */ retries = 3; while (retries) { @@ -238,10 +242,13 @@ static long ioctl_rio(struct file *file, unsigned int cmd, unsigned long arg) if (result == -ETIMEDOUT) retries--; else if (result < 0) { - err("Error executing ioctrl. code = %d", result); + dev_err(&rio->rio_dev->dev, + "Error executing ioctrl. code = %d\n", + result); retries = 0; } else { - dbg("Executed ioctl. Result = %d", result); + dev_dbg(&rio->rio_dev->dev, + "Executed ioctl. Result = %d\n", result); retries = 0; } @@ -313,8 +320,9 @@ write_rio(struct file *file, const char __user *buffer, usb_sndbulkpipe(rio->rio_dev, 2), obuf, thistime, &partial, 5000); - dbg("write stats: result:%d thistime:%lu partial:%u", - result, thistime, partial); + dev_dbg(&rio->rio_dev->dev, + "write stats: result:%d thistime:%lu partial:%u\n", + result, thistime, partial); if (result == -ETIMEDOUT) { /* NAK - so hold for a while */ if (!maxretry--) { @@ -332,7 +340,8 @@ write_rio(struct file *file, const char __user *buffer, break; }; if (result) { - err("Write Whoops - %x", result); + dev_err(&rio->rio_dev->dev, "Write Whoops - %x\n", + result); errn = -EIO; goto error; } @@ -393,15 +402,17 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos) ibuf, this_read, &partial, 8000); - dbg("read stats: result:%d this_read:%u partial:%u", - result, this_read, partial); + dev_dbg(&rio->rio_dev->dev, + "read stats: result:%d this_read:%u partial:%u\n", + result, this_read, partial); if (partial) { count = this_read = partial; } else if (result == -ETIMEDOUT || result == 15) { /* FIXME: 15 ??? */ if (!maxretry--) { mutex_unlock(&(rio->lock)); - err("read_rio: maxretry timeout"); + dev_err(&rio->rio_dev->dev, + "read_rio: maxretry timeout\n"); return -ETIME; } prepare_to_wait(&rio->wait_q, &wait, TASK_INTERRUPTIBLE); @@ -410,8 +421,9 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos) continue; } else if (result != -EREMOTEIO) { mutex_unlock(&(rio->lock)); - err("Read Whoops - result:%u partial:%u this_read:%u", - result, partial, this_read); + dev_err(&rio->rio_dev->dev, + "Read Whoops - result:%u partial:%u this_read:%u\n", + result, partial, this_read); return -EIO; } else { mutex_unlock(&(rio->lock)); @@ -459,26 +471,29 @@ static int probe_rio(struct usb_interface *intf, retval = usb_register_dev(intf, &usb_rio_class); if (retval) { - err("Not able to get a minor for this device."); + dev_err(&dev->dev, + "Not able to get a minor for this device.\n"); return -ENOMEM; } rio->rio_dev = dev; if (!(rio->obuf = kmalloc(OBUF_SIZE, GFP_KERNEL))) { - err("probe_rio: Not enough memory for the output buffer"); + dev_err(&dev->dev, + "probe_rio: Not enough memory for the output buffer\n"); usb_deregister_dev(intf, &usb_rio_class); return -ENOMEM; } - dbg("probe_rio: obuf address:%p", rio->obuf); + dev_dbg(&intf->dev, "obuf address:%p\n", rio->obuf); if (!(rio->ibuf = kmalloc(IBUF_SIZE, GFP_KERNEL))) { - err("probe_rio: Not enough memory for the input buffer"); + dev_err(&dev->dev, + "probe_rio: Not enough memory for the input buffer\n"); usb_deregister_dev(intf, &usb_rio_class); kfree(rio->obuf); return -ENOMEM; } - dbg("probe_rio: ibuf address:%p", rio->ibuf); + dev_dbg(&intf->dev, "ibuf address:%p\n", rio->ibuf); mutex_init(&(rio->lock)); diff --git a/trunk/drivers/usb/misc/usblcd.c b/trunk/drivers/usb/misc/usblcd.c index e2b4bd31c2b6..89927bcff974 100644 --- a/trunk/drivers/usb/misc/usblcd.c +++ b/trunk/drivers/usb/misc/usblcd.c @@ -87,8 +87,8 @@ static int lcd_open(struct inode *inode, struct file *file) interface = usb_find_interface(&lcd_driver, subminor); if (!interface) { mutex_unlock(&lcd_mutex); - err("USBLCD: %s - error, can't find device for minor %d", - __func__, subminor); + printk(KERN_ERR "USBLCD: %s - error, can't find device for minor %d\n", + __func__, subminor); return -ENODEV; } @@ -209,8 +209,8 @@ static void lcd_write_bulk_callback(struct urb *urb) !(status == -ENOENT || status == -ECONNRESET || status == -ESHUTDOWN)) { - dbg("USBLCD: %s - nonzero write bulk status received: %d", - __func__, status); + dev_dbg(&dev->interface->dev, + "nonzero write bulk status received: %d\n", status); } /* free up our allocated buffer */ @@ -268,8 +268,9 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, /* send the data out the bulk port */ retval = usb_submit_urb(urb, GFP_KERNEL); if (retval) { - err("USBLCD: %s - failed submitting write urb, error %d", - __func__, retval); + dev_err(&dev->udev->dev, + "%s - failed submitting write urb, error %d\n", + __func__, retval); goto error_unanchor; } @@ -322,7 +323,7 @@ static int lcd_probe(struct usb_interface *interface, /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { - err("Out of memory"); + dev_err(&interface->dev, "Out of memory\n"); goto error; } kref_init(&dev->kref); @@ -352,7 +353,8 @@ static int lcd_probe(struct usb_interface *interface, dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); if (!dev->bulk_in_buffer) { - err("Could not allocate bulk_in_buffer"); + dev_err(&interface->dev, + "Could not allocate bulk_in_buffer\n"); goto error; } } @@ -364,7 +366,8 @@ static int lcd_probe(struct usb_interface *interface, } } if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) { - err("Could not find both bulk-in and bulk-out endpoints"); + dev_err(&interface->dev, + "Could not find both bulk-in and bulk-out endpoints\n"); goto error; } @@ -375,7 +378,8 @@ static int lcd_probe(struct usb_interface *interface, retval = usb_register_dev(interface, &lcd_class); if (retval) { /* something prevented us from registering this driver */ - err("Not able to get a minor for this device."); + dev_err(&interface->dev, + "Not able to get a minor for this device.\n"); usb_set_intfdata(interface, NULL); goto error; } diff --git a/trunk/drivers/usb/misc/usbtest.c b/trunk/drivers/usb/misc/usbtest.c index 9dcb68f04f03..055b84adedac 100644 --- a/trunk/drivers/usb/misc/usbtest.c +++ b/trunk/drivers/usb/misc/usbtest.c @@ -1028,7 +1028,10 @@ test_ctrl_queue(struct usbtest_dev *dev, struct usbtest_param *param) case 13: /* short read, resembling case 10 */ req.wValue = cpu_to_le16((USB_DT_CONFIG << 8) | 0); /* last data packet "should" be DATA1, not DATA0 */ - len = 1024 - udev->descriptor.bMaxPacketSize0; + if (udev->speed == USB_SPEED_SUPER) + len = 1024 - 512; + else + len = 1024 - udev->descriptor.bMaxPacketSize0; expected = -EREMOTEIO; break; case 14: /* short read; try to fill the last packet */ @@ -1387,11 +1390,15 @@ static int test_halt(struct usbtest_dev *tdev, int ep, struct urb *urb) static int halt_simple(struct usbtest_dev *dev) { - int ep; - int retval = 0; - struct urb *urb; + int ep; + int retval = 0; + struct urb *urb; + struct usb_device *udev = testdev_to_usbdev(dev); - urb = simple_alloc_urb(testdev_to_usbdev(dev), 0, 512); + if (udev->speed == USB_SPEED_SUPER) + urb = simple_alloc_urb(udev, 0, 1024); + else + urb = simple_alloc_urb(udev, 0, 512); if (urb == NULL) return -ENOMEM; diff --git a/trunk/drivers/usb/misc/uss720.c b/trunk/drivers/usb/misc/uss720.c index 8b1d94a76914..29cad9e0a7a9 100644 --- a/trunk/drivers/usb/misc/uss720.c +++ b/trunk/drivers/usb/misc/uss720.c @@ -85,9 +85,9 @@ static void destroy_priv(struct kref *kref) { struct parport_uss720_private *priv = container_of(kref, struct parport_uss720_private, ref_count); + dev_dbg(&priv->usbdev->dev, "destroying priv datastructure\n"); usb_put_dev(priv->usbdev); kfree(priv); - dbg("destroying priv datastructure"); } static void destroy_async(struct kref *kref) @@ -118,14 +118,17 @@ static void async_complete(struct urb *urb) priv = rq->priv; pp = priv->pp; if (status) { - err("async_complete: urb error %d", status); + dev_err(&urb->dev->dev, "async_complete: urb error %d\n", + status); } else if (rq->dr.bRequest == 3) { memcpy(priv->reg, rq->reg, sizeof(priv->reg)); #if 0 - dbg("async_complete regs %02x %02x %02x %02x %02x %02x %02x", - (unsigned int)priv->reg[0], (unsigned int)priv->reg[1], (unsigned int)priv->reg[2], - (unsigned int)priv->reg[3], (unsigned int)priv->reg[4], (unsigned int)priv->reg[5], - (unsigned int)priv->reg[6]); + dev_dbg(&priv->usbdev->dev, + "async_complete regs %02x %02x %02x %02x %02x %02x %02x\n", + (unsigned int)priv->reg[0], (unsigned int)priv->reg[1], + (unsigned int)priv->reg[2], (unsigned int)priv->reg[3], + (unsigned int)priv->reg[4], (unsigned int)priv->reg[5], + (unsigned int)priv->reg[6]); #endif /* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */ if (rq->reg[2] & rq->reg[1] & 0x10 && pp) @@ -151,7 +154,7 @@ static struct uss720_async_request *submit_async_request(struct parport_uss720_p return NULL; rq = kmalloc(sizeof(struct uss720_async_request), mem_flags); if (!rq) { - err("submit_async_request out of memory"); + dev_err(&usbdev->dev, "submit_async_request out of memory\n"); return NULL; } kref_init(&rq->ref_count); @@ -162,7 +165,7 @@ static struct uss720_async_request *submit_async_request(struct parport_uss720_p rq->urb = usb_alloc_urb(0, mem_flags); if (!rq->urb) { kref_put(&rq->ref_count, destroy_async); - err("submit_async_request out of memory"); + dev_err(&usbdev->dev, "submit_async_request out of memory\n"); return NULL; } rq->dr.bRequestType = requesttype; @@ -182,7 +185,7 @@ static struct uss720_async_request *submit_async_request(struct parport_uss720_p if (!ret) return rq; destroy_async(&rq->ref_count); - err("submit_async_request submit_urb failed with %d", ret); + dev_err(&usbdev->dev, "submit_async_request submit_urb failed with %d\n", ret); return NULL; } @@ -217,7 +220,8 @@ static int get_1284_register(struct parport *pp, unsigned char reg, unsigned cha priv = pp->private_data; rq = submit_async_request(priv, 3, 0xc0, ((unsigned int)reg) << 8, 0, mem_flags); if (!rq) { - err("get_1284_register(%u) failed", (unsigned int)reg); + dev_err(&priv->usbdev->dev, "get_1284_register(%u) failed", + (unsigned int)reg); return -EIO; } if (!val) { @@ -248,7 +252,8 @@ static int set_1284_register(struct parport *pp, unsigned char reg, unsigned cha priv = pp->private_data; rq = submit_async_request(priv, 4, 0x40, (((unsigned int)reg) << 8) | val, 0, mem_flags); if (!rq) { - err("set_1284_register(%u,%u) failed", (unsigned int)reg, (unsigned int)val); + dev_err(&priv->usbdev->dev, "set_1284_register(%u,%u) failed", + (unsigned int)reg, (unsigned int)val); return -EIO; } kref_put(&rq->ref_count, destroy_async); @@ -690,9 +695,9 @@ static int uss720_probe(struct usb_interface *intf, unsigned char reg; int i; - dbg("probe: vendor id 0x%x, device id 0x%x\n", - le16_to_cpu(usbdev->descriptor.idVendor), - le16_to_cpu(usbdev->descriptor.idProduct)); + dev_dbg(&intf->dev, "probe: vendor id 0x%x, device id 0x%x\n", + le16_to_cpu(usbdev->descriptor.idVendor), + le16_to_cpu(usbdev->descriptor.idProduct)); /* our known interfaces have 3 alternate settings */ if (intf->num_altsetting != 3) { @@ -700,7 +705,7 @@ static int uss720_probe(struct usb_interface *intf, return -ENODEV; } i = usb_set_interface(usbdev, intf->altsetting->desc.bInterfaceNumber, 2); - dbg("set inteface result %d", i); + dev_dbg(&intf->dev, "set inteface result %d\n", i); interface = intf->cur_altsetting; @@ -731,11 +736,13 @@ static int uss720_probe(struct usb_interface *intf, set_1284_register(pp, 2, 0x0c, GFP_KERNEL); /* debugging */ get_1284_register(pp, 0, ®, GFP_KERNEL); - dbg("reg: %02x %02x %02x %02x %02x %02x %02x", - priv->reg[0], priv->reg[1], priv->reg[2], priv->reg[3], priv->reg[4], priv->reg[5], priv->reg[6]); + dev_dbg(&intf->dev, "reg: %02x %02x %02x %02x %02x %02x %02x\n", + priv->reg[0], priv->reg[1], priv->reg[2], priv->reg[3], + priv->reg[4], priv->reg[5], priv->reg[6]); endpoint = &interface->endpoint[2]; - dbg("epaddr %d interval %d", endpoint->desc.bEndpointAddress, endpoint->desc.bInterval); + dev_dbg(&intf->dev, "epaddr %d interval %d\n", + endpoint->desc.bEndpointAddress, endpoint->desc.bInterval); parport_announce_port(pp); usb_set_intfdata(intf, pp); @@ -753,20 +760,20 @@ static void uss720_disconnect(struct usb_interface *intf) struct parport_uss720_private *priv; struct usb_device *usbdev; - dbg("disconnect"); + dev_dbg(&intf->dev, "disconnect\n"); usb_set_intfdata(intf, NULL); if (pp) { priv = pp->private_data; usbdev = priv->usbdev; priv->usbdev = NULL; priv->pp = NULL; - dbg("parport_remove_port"); + dev_dbg(&intf->dev, "parport_remove_port\n"); parport_remove_port(pp); parport_put_port(pp); kill_all_async_requests_priv(priv); kref_put(&priv->ref_count, destroy_priv); } - dbg("disconnect done"); + dev_dbg(&intf->dev, "disconnect done\n"); } /* table of cables that work through this driver */ diff --git a/trunk/drivers/usb/misc/yurex.c b/trunk/drivers/usb/misc/yurex.c index 70201462e19c..42ad2e6d86c4 100644 --- a/trunk/drivers/usb/misc/yurex.c +++ b/trunk/drivers/usb/misc/yurex.c @@ -83,7 +83,8 @@ static void yurex_control_callback(struct urb *urb) int status = urb->status; if (status) { - err("%s - control failed: %d\n", __func__, status); + dev_err(&urb->dev->dev, "%s - control failed: %d\n", + __func__, status); wake_up_interruptible(&dev->waitq); return; } @@ -94,7 +95,7 @@ static void yurex_delete(struct kref *kref) { struct usb_yurex *dev = to_yurex_dev(kref); - dbg("yurex_delete"); + dev_dbg(&dev->interface->dev, "%s\n", __func__); usb_put_dev(dev->udev); if (dev->cntl_urb) { @@ -137,8 +138,9 @@ static void yurex_interrupt(struct urb *urb) case 0: /*success*/ break; case -EOVERFLOW: - err("%s - overflow with length %d, actual length is %d", - __func__, YUREX_BUF_SIZE, dev->urb->actual_length); + dev_err(&dev->interface->dev, + "%s - overflow with length %d, actual length is %d\n", + __func__, YUREX_BUF_SIZE, dev->urb->actual_length); case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: @@ -146,7 +148,8 @@ static void yurex_interrupt(struct urb *urb) /* The device is terminated, clean up */ return; default: - err("%s - unknown status received: %d", __func__, status); + dev_err(&dev->interface->dev, + "%s - unknown status received: %d\n", __func__, status); goto exit; } @@ -162,16 +165,19 @@ static void yurex_interrupt(struct urb *urb) if (i != 5) dev->bbu <<= 8; } - dbg("%s count: %lld", __func__, dev->bbu); + dev_dbg(&dev->interface->dev, "%s count: %lld\n", + __func__, dev->bbu); spin_unlock_irqrestore(&dev->lock, flags); kill_fasync(&dev->async_queue, SIGIO, POLL_IN); } else - dbg("data format error - no EOF"); + dev_dbg(&dev->interface->dev, + "data format error - no EOF\n"); break; case CMD_ACK: - dbg("%s ack: %c", __func__, buf[1]); + dev_dbg(&dev->interface->dev, "%s ack: %c\n", + __func__, buf[1]); wake_up_interruptible(&dev->waitq); break; } @@ -179,7 +185,7 @@ static void yurex_interrupt(struct urb *urb) exit: retval = usb_submit_urb(dev->urb, GFP_ATOMIC); if (retval) { - err("%s - usb_submit_urb failed: %d", + dev_err(&dev->interface->dev, "%s - usb_submit_urb failed: %d\n", __func__, retval); } } @@ -196,7 +202,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_ /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { - err("Out of memory"); + dev_err(&interface->dev, "Out of memory\n"); goto error; } kref_init(&dev->kref); @@ -219,7 +225,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_ } if (!dev->int_in_endpointAddr) { retval = -ENODEV; - err("Could not find endpoints"); + dev_err(&interface->dev, "Could not find endpoints\n"); goto error; } @@ -227,14 +233,14 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_ /* allocate control URB */ dev->cntl_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->cntl_urb) { - err("Could not allocate control URB"); + dev_err(&interface->dev, "Could not allocate control URB\n"); goto error; } /* allocate buffer for control req */ dev->cntl_req = kmalloc(YUREX_BUF_SIZE, GFP_KERNEL); if (!dev->cntl_req) { - err("Could not allocate cntl_req"); + dev_err(&interface->dev, "Could not allocate cntl_req\n"); goto error; } @@ -243,7 +249,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_ GFP_KERNEL, &dev->cntl_urb->transfer_dma); if (!dev->cntl_buffer) { - err("Could not allocate cntl_buffer"); + dev_err(&interface->dev, "Could not allocate cntl_buffer\n"); goto error; } @@ -265,7 +271,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_ /* allocate interrupt URB */ dev->urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->urb) { - err("Could not allocate URB"); + dev_err(&interface->dev, "Could not allocate URB\n"); goto error; } @@ -273,7 +279,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_ dev->int_buffer = usb_alloc_coherent(dev->udev, YUREX_BUF_SIZE, GFP_KERNEL, &dev->urb->transfer_dma); if (!dev->int_buffer) { - err("Could not allocate int_buffer"); + dev_err(&interface->dev, "Could not allocate int_buffer\n"); goto error; } @@ -285,7 +291,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_ dev->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; if (usb_submit_urb(dev->urb, GFP_KERNEL)) { retval = -EIO; - err("Could not submitting URB"); + dev_err(&interface->dev, "Could not submitting URB\n"); goto error; } @@ -295,7 +301,8 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_ /* we can register the device now, as it is ready */ retval = usb_register_dev(interface, &yurex_class); if (retval) { - err("Not able to get a minor for this device."); + dev_err(&interface->dev, + "Not able to get a minor for this device.\n"); usb_set_intfdata(interface, NULL); goto error; } @@ -368,8 +375,8 @@ static int yurex_open(struct inode *inode, struct file *file) interface = usb_find_interface(&yurex_driver, subminor); if (!interface) { - err("%s - error, can't find device for minor %d", - __func__, subminor); + printk(KERN_ERR "%s - error, can't find device for minor %d", + __func__, subminor); retval = -ENODEV; goto exit; } @@ -505,7 +512,8 @@ static ssize_t yurex_write(struct file *file, const char *user_buffer, size_t co /* send the data as the control msg */ prepare_to_wait(&dev->waitq, &wait, TASK_INTERRUPTIBLE); - dbg("%s - submit %c", __func__, dev->cntl_buffer[0]); + dev_dbg(&dev->interface->dev, "%s - submit %c\n", __func__, + dev->cntl_buffer[0]); retval = usb_submit_urb(dev->cntl_urb, GFP_KERNEL); if (retval >= 0) timeout = schedule_timeout(YUREX_WRITE_TIMEOUT); @@ -514,7 +522,9 @@ static ssize_t yurex_write(struct file *file, const char *user_buffer, size_t co mutex_unlock(&dev->io_mutex); if (retval < 0) { - err("%s - failed to send bulk msg, error %d", __func__, retval); + dev_err(&dev->interface->dev, + "%s - failed to send bulk msg, error %d\n", + __func__, retval); goto error; } if (set && timeout) diff --git a/trunk/drivers/usb/musb/Kconfig b/trunk/drivers/usb/musb/Kconfig index f70cab3beeec..ef0c3f9f0947 100644 --- a/trunk/drivers/usb/musb/Kconfig +++ b/trunk/drivers/usb/musb/Kconfig @@ -8,6 +8,7 @@ config USB_MUSB_HDRC tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)' depends on USB && USB_GADGET select NOP_USB_XCEIV if (ARCH_DAVINCI || MACH_OMAP3EVM || BLACKFIN) + select NOP_USB_XCEIV if (SOC_OMAPTI81XX || SOC_OMAPAM33XX) select TWL4030_USB if MACH_OMAP_3430SDP select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA select USB_OTG_UTILS @@ -54,6 +55,10 @@ config USB_MUSB_AM35X tristate "AM35x" depends on ARCH_OMAP +config USB_MUSB_DSPS + tristate "TI DSPS platforms" + depends on SOC_OMAPTI81XX || SOC_OMAPAM33XX + config USB_MUSB_BLACKFIN tristate "Blackfin" depends on (BF54x && !BF544) || (BF52x && ! BF522 && !BF523) @@ -70,7 +75,8 @@ choice default USB_INVENTRA_DMA if USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN default USB_TI_CPPI_DMA if USB_MUSB_DAVINCI default USB_TUSB_OMAP_DMA if USB_MUSB_TUSB6010 - default MUSB_PIO_ONLY if USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X + default MUSB_PIO_ONLY if USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X \ + || USB_MUSB_DSPS help Unfortunately, only one option can be enabled here. Ideally one should be able to build all these drivers into one kernel to diff --git a/trunk/drivers/usb/musb/Makefile b/trunk/drivers/usb/musb/Makefile index 88bfb9dee4bf..3b858715b5ea 100644 --- a/trunk/drivers/usb/musb/Makefile +++ b/trunk/drivers/usb/musb/Makefile @@ -13,6 +13,7 @@ musb_hdrc-$(CONFIG_DEBUG_FS) += musb_debugfs.o # Hardware Glue Layer obj-$(CONFIG_USB_MUSB_OMAP2PLUS) += omap2430.o obj-$(CONFIG_USB_MUSB_AM35X) += am35x.o +obj-$(CONFIG_USB_MUSB_DSPS) += musb_dsps.o obj-$(CONFIG_USB_MUSB_TUSB6010) += tusb6010.o obj-$(CONFIG_USB_MUSB_DAVINCI) += davinci.o obj-$(CONFIG_USB_MUSB_DA8XX) += da8xx.o diff --git a/trunk/drivers/usb/musb/cppi_dma.c b/trunk/drivers/usb/musb/cppi_dma.c index 66bc376005d2..8637c1f69fc3 100644 --- a/trunk/drivers/usb/musb/cppi_dma.c +++ b/trunk/drivers/usb/musb/cppi_dma.c @@ -6,6 +6,7 @@ * The TUSB6020, using VLYNQ, has CPPI that looks much like DaVinci. */ +#include #include #include #include diff --git a/trunk/drivers/usb/musb/musb_core.c b/trunk/drivers/usb/musb/musb_core.c index 66aaccf04490..db3dff854b71 100644 --- a/trunk/drivers/usb/musb/musb_core.c +++ b/trunk/drivers/usb/musb/musb_core.c @@ -1034,7 +1034,9 @@ static void musb_shutdown(struct platform_device *pdev) || defined(CONFIG_USB_MUSB_OMAP2PLUS) \ || defined(CONFIG_USB_MUSB_OMAP2PLUS_MODULE) \ || defined(CONFIG_USB_MUSB_AM35X) \ - || defined(CONFIG_USB_MUSB_AM35X_MODULE) + || defined(CONFIG_USB_MUSB_AM35X_MODULE) \ + || defined(CONFIG_USB_MUSB_DSPS) \ + || defined(CONFIG_USB_MUSB_DSPS_MODULE) static ushort __devinitdata fifo_mode = 4; #elif defined(CONFIG_USB_MUSB_UX500) \ || defined(CONFIG_USB_MUSB_UX500_MODULE) diff --git a/trunk/drivers/usb/musb/musb_dsps.c b/trunk/drivers/usb/musb/musb_dsps.c new file mode 100644 index 000000000000..23db42db761a --- /dev/null +++ b/trunk/drivers/usb/musb/musb_dsps.c @@ -0,0 +1,711 @@ +/* + * Texas Instruments DSPS platforms "glue layer" + * + * Copyright (C) 2012, by Texas Instruments + * + * Based on the am35x "glue layer" code. + * + * This file is part of the Inventra Controller Driver for Linux. + * + * The Inventra Controller Driver for Linux 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. + * + * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not, + * write to the Free Software Foundation, Inc., 59 Temple Place, + * Suite 330, Boston, MA 02111-1307 USA + * + * musb_dsps.c will be a common file for all the TI DSPS platforms + * such as dm64x, dm36x, dm35x, da8x, am35x and ti81x. + * For now only ti81x is using this and in future davinci.c, am35x.c + * da8xx.c would be merged to this file after testing. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "musb_core.h" + +/** + * avoid using musb_readx()/musb_writex() as glue layer should not be + * dependent on musb core layer symbols. + */ +static inline u8 dsps_readb(const void __iomem *addr, unsigned offset) + { return __raw_readb(addr + offset); } + +static inline u32 dsps_readl(const void __iomem *addr, unsigned offset) + { return __raw_readl(addr + offset); } + +static inline void dsps_writeb(void __iomem *addr, unsigned offset, u8 data) + { __raw_writeb(data, addr + offset); } + +static inline void dsps_writel(void __iomem *addr, unsigned offset, u32 data) + { __raw_writel(data, addr + offset); } + +/** + * DSPS musb wrapper register offset. + * FIXME: This should be expanded to have all the wrapper registers from TI DSPS + * musb ips. + */ +struct dsps_musb_wrapper { + u16 revision; + u16 control; + u16 status; + u16 eoi; + u16 epintr_set; + u16 epintr_clear; + u16 epintr_status; + u16 coreintr_set; + u16 coreintr_clear; + u16 coreintr_status; + u16 phy_utmi; + u16 mode; + + /* bit positions for control */ + unsigned reset:5; + + /* bit positions for interrupt */ + unsigned usb_shift:5; + u32 usb_mask; + u32 usb_bitmap; + unsigned drvvbus:5; + + unsigned txep_shift:5; + u32 txep_mask; + u32 txep_bitmap; + + unsigned rxep_shift:5; + u32 rxep_mask; + u32 rxep_bitmap; + + /* bit positions for phy_utmi */ + unsigned otg_disable:5; + + /* bit positions for mode */ + unsigned iddig:5; + /* miscellaneous stuff */ + u32 musb_core_offset; + u8 poll_seconds; +}; + +/** + * DSPS glue structure. + */ +struct dsps_glue { + struct device *dev; + struct platform_device *musb; /* child musb pdev */ + const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ + struct timer_list timer; /* otg_workaround timer */ +}; + +/** + * dsps_musb_enable - enable interrupts + */ +static void dsps_musb_enable(struct musb *musb) +{ + struct device *dev = musb->controller; + struct platform_device *pdev = to_platform_device(dev->parent); + struct dsps_glue *glue = platform_get_drvdata(pdev); + const struct dsps_musb_wrapper *wrp = glue->wrp; + void __iomem *reg_base = musb->ctrl_base; + u32 epmask, coremask; + + /* Workaround: setup IRQs through both register sets. */ + epmask = ((musb->epmask & wrp->txep_mask) << wrp->txep_shift) | + ((musb->epmask & wrp->rxep_mask) << wrp->rxep_shift); + coremask = (wrp->usb_bitmap & ~MUSB_INTR_SOF); + + dsps_writel(reg_base, wrp->epintr_set, epmask); + dsps_writel(reg_base, wrp->coreintr_set, coremask); + /* Force the DRVVBUS IRQ so we can start polling for ID change. */ + if (is_otg_enabled(musb)) + dsps_writel(reg_base, wrp->coreintr_set, + (1 << wrp->drvvbus) << wrp->usb_shift); +} + +/** + * dsps_musb_disable - disable HDRC and flush interrupts + */ +static void dsps_musb_disable(struct musb *musb) +{ + struct device *dev = musb->controller; + struct platform_device *pdev = to_platform_device(dev->parent); + struct dsps_glue *glue = platform_get_drvdata(pdev); + const struct dsps_musb_wrapper *wrp = glue->wrp; + void __iomem *reg_base = musb->ctrl_base; + + dsps_writel(reg_base, wrp->coreintr_clear, wrp->usb_bitmap); + dsps_writel(reg_base, wrp->epintr_clear, + wrp->txep_bitmap | wrp->rxep_bitmap); + dsps_writeb(musb->mregs, MUSB_DEVCTL, 0); + dsps_writel(reg_base, wrp->eoi, 0); +} + +static void otg_timer(unsigned long _musb) +{ + struct musb *musb = (void *)_musb; + void __iomem *mregs = musb->mregs; + struct device *dev = musb->controller; + struct platform_device *pdev = to_platform_device(dev->parent); + struct dsps_glue *glue = platform_get_drvdata(pdev); + const struct dsps_musb_wrapper *wrp = glue->wrp; + u8 devctl; + unsigned long flags; + + /* + * We poll because DSPS IP's won't expose several OTG-critical + * status change events (from the transceiver) otherwise. + */ + devctl = dsps_readb(mregs, MUSB_DEVCTL); + dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl, + otg_state_string(musb->xceiv->state)); + + spin_lock_irqsave(&musb->lock, flags); + switch (musb->xceiv->state) { + case OTG_STATE_A_WAIT_BCON: + devctl &= ~MUSB_DEVCTL_SESSION; + dsps_writeb(musb->mregs, MUSB_DEVCTL, devctl); + + devctl = dsps_readb(musb->mregs, MUSB_DEVCTL); + if (devctl & MUSB_DEVCTL_BDEVICE) { + musb->xceiv->state = OTG_STATE_B_IDLE; + MUSB_DEV_MODE(musb); + } else { + musb->xceiv->state = OTG_STATE_A_IDLE; + MUSB_HST_MODE(musb); + } + break; + case OTG_STATE_A_WAIT_VFALL: + musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; + dsps_writel(musb->ctrl_base, wrp->coreintr_set, + MUSB_INTR_VBUSERROR << wrp->usb_shift); + break; + case OTG_STATE_B_IDLE: + if (!is_peripheral_enabled(musb)) + break; + + devctl = dsps_readb(mregs, MUSB_DEVCTL); + if (devctl & MUSB_DEVCTL_BDEVICE) + mod_timer(&glue->timer, + jiffies + wrp->poll_seconds * HZ); + else + musb->xceiv->state = OTG_STATE_A_IDLE; + break; + default: + break; + } + spin_unlock_irqrestore(&musb->lock, flags); +} + +static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) +{ + struct device *dev = musb->controller; + struct platform_device *pdev = to_platform_device(dev->parent); + struct dsps_glue *glue = platform_get_drvdata(pdev); + static unsigned long last_timer; + + if (!is_otg_enabled(musb)) + return; + + if (timeout == 0) + timeout = jiffies + msecs_to_jiffies(3); + + /* Never idle if active, or when VBUS timeout is not set as host */ + if (musb->is_active || (musb->a_wait_bcon == 0 && + musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { + dev_dbg(musb->controller, "%s active, deleting timer\n", + otg_state_string(musb->xceiv->state)); + del_timer(&glue->timer); + last_timer = jiffies; + return; + } + + if (time_after(last_timer, timeout) && timer_pending(&glue->timer)) { + dev_dbg(musb->controller, + "Longer idle timer already pending, ignoring...\n"); + return; + } + last_timer = timeout; + + dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", + otg_state_string(musb->xceiv->state), + jiffies_to_msecs(timeout - jiffies)); + mod_timer(&glue->timer, timeout); +} + +static irqreturn_t dsps_interrupt(int irq, void *hci) +{ + struct musb *musb = hci; + void __iomem *reg_base = musb->ctrl_base; + struct device *dev = musb->controller; + struct platform_device *pdev = to_platform_device(dev->parent); + struct dsps_glue *glue = platform_get_drvdata(pdev); + const struct dsps_musb_wrapper *wrp = glue->wrp; + unsigned long flags; + irqreturn_t ret = IRQ_NONE; + u32 epintr, usbintr; + + spin_lock_irqsave(&musb->lock, flags); + + /* Get endpoint interrupts */ + epintr = dsps_readl(reg_base, wrp->epintr_status); + musb->int_rx = (epintr & wrp->rxep_bitmap) >> wrp->rxep_shift; + musb->int_tx = (epintr & wrp->txep_bitmap) >> wrp->txep_shift; + + if (epintr) + dsps_writel(reg_base, wrp->epintr_status, epintr); + + /* Get usb core interrupts */ + usbintr = dsps_readl(reg_base, wrp->coreintr_status); + if (!usbintr && !epintr) + goto eoi; + + musb->int_usb = (usbintr & wrp->usb_bitmap) >> wrp->usb_shift; + if (usbintr) + dsps_writel(reg_base, wrp->coreintr_status, usbintr); + + dev_dbg(musb->controller, "usbintr (%x) epintr(%x)\n", + usbintr, epintr); + /* + * DRVVBUS IRQs are the only proxy we have (a very poor one!) for + * DSPS IP's missing ID change IRQ. We need an ID change IRQ to + * switch appropriately between halves of the OTG state machine. + * Managing DEVCTL.SESSION per Mentor docs requires that we know its + * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set. + * Also, DRVVBUS pulses for SRP (but not at 5V) ... + */ + if ((usbintr & MUSB_INTR_BABBLE) && is_host_enabled(musb)) + pr_info("CAUTION: musb: Babble Interrupt Occured\n"); + + if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) { + int drvvbus = dsps_readl(reg_base, wrp->status); + void __iomem *mregs = musb->mregs; + u8 devctl = dsps_readb(mregs, MUSB_DEVCTL); + int err; + + err = is_host_enabled(musb) && (musb->int_usb & + MUSB_INTR_VBUSERROR); + if (err) { + /* + * The Mentor core doesn't debounce VBUS as needed + * to cope with device connect current spikes. This + * means it's not uncommon for bus-powered devices + * to get VBUS errors during enumeration. + * + * This is a workaround, but newer RTL from Mentor + * seems to allow a better one: "re"-starting sessions + * without waiting for VBUS to stop registering in + * devctl. + */ + musb->int_usb &= ~MUSB_INTR_VBUSERROR; + musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; + mod_timer(&glue->timer, + jiffies + wrp->poll_seconds * HZ); + WARNING("VBUS error workaround (delay coming)\n"); + } else if (is_host_enabled(musb) && drvvbus) { + musb->is_active = 1; + MUSB_HST_MODE(musb); + musb->xceiv->otg->default_a = 1; + musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; + del_timer(&glue->timer); + } else { + musb->is_active = 0; + MUSB_DEV_MODE(musb); + musb->xceiv->otg->default_a = 0; + musb->xceiv->state = OTG_STATE_B_IDLE; + } + + /* NOTE: this must complete power-on within 100 ms. */ + dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n", + drvvbus ? "on" : "off", + otg_state_string(musb->xceiv->state), + err ? " ERROR" : "", + devctl); + ret = IRQ_HANDLED; + } + + if (musb->int_tx || musb->int_rx || musb->int_usb) + ret |= musb_interrupt(musb); + + eoi: + /* EOI needs to be written for the IRQ to be re-asserted. */ + if (ret == IRQ_HANDLED || epintr || usbintr) + dsps_writel(reg_base, wrp->eoi, 1); + + /* Poll for ID change */ + if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE) + mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ); + + spin_unlock_irqrestore(&musb->lock, flags); + + return ret; +} + +static int dsps_musb_init(struct musb *musb) +{ + struct device *dev = musb->controller; + struct musb_hdrc_platform_data *plat = dev->platform_data; + struct platform_device *pdev = to_platform_device(dev->parent); + struct dsps_glue *glue = platform_get_drvdata(pdev); + const struct dsps_musb_wrapper *wrp = glue->wrp; + struct omap_musb_board_data *data = plat->board_data; + void __iomem *reg_base = musb->ctrl_base; + u32 rev, val; + int status; + + /* mentor core register starts at offset of 0x400 from musb base */ + musb->mregs += wrp->musb_core_offset; + + /* NOP driver needs change if supporting dual instance */ + usb_nop_xceiv_register(); + musb->xceiv = usb_get_transceiver(); + if (!musb->xceiv) + return -ENODEV; + + /* Returns zero if e.g. not clocked */ + rev = dsps_readl(reg_base, wrp->revision); + if (!rev) { + status = -ENODEV; + goto err0; + } + + if (is_host_enabled(musb)) + setup_timer(&glue->timer, otg_timer, (unsigned long) musb); + + /* Reset the musb */ + dsps_writel(reg_base, wrp->control, (1 << wrp->reset)); + + /* Start the on-chip PHY and its PLL. */ + if (data->set_phy_power) + data->set_phy_power(1); + + musb->isr = dsps_interrupt; + + /* reset the otgdisable bit, needed for host mode to work */ + val = dsps_readl(reg_base, wrp->phy_utmi); + val &= ~(1 << wrp->otg_disable); + dsps_writel(musb->ctrl_base, wrp->phy_utmi, val); + + /* clear level interrupt */ + dsps_writel(reg_base, wrp->eoi, 0); + + return 0; +err0: + usb_put_transceiver(musb->xceiv); + usb_nop_xceiv_unregister(); + return status; +} + +static int dsps_musb_exit(struct musb *musb) +{ + struct device *dev = musb->controller; + struct musb_hdrc_platform_data *plat = dev->platform_data; + struct omap_musb_board_data *data = plat->board_data; + struct platform_device *pdev = to_platform_device(dev->parent); + struct dsps_glue *glue = platform_get_drvdata(pdev); + + if (is_host_enabled(musb)) + del_timer_sync(&glue->timer); + + /* Shutdown the on-chip PHY and its PLL. */ + if (data->set_phy_power) + data->set_phy_power(0); + + /* NOP driver needs change if supporting dual instance */ + usb_put_transceiver(musb->xceiv); + usb_nop_xceiv_unregister(); + + return 0; +} + +static struct musb_platform_ops dsps_ops = { + .init = dsps_musb_init, + .exit = dsps_musb_exit, + + .enable = dsps_musb_enable, + .disable = dsps_musb_disable, + + .try_idle = dsps_musb_try_idle, +}; + +static u64 musb_dmamask = DMA_BIT_MASK(32); + +static int __devinit dsps_create_musb_pdev(struct dsps_glue *glue, u8 id) +{ + struct device *dev = glue->dev; + struct platform_device *pdev = to_platform_device(dev); + struct musb_hdrc_platform_data *pdata = dev->platform_data; + struct platform_device *musb; + struct resource *res; + struct resource resources[2]; + char res_name[10]; + int ret; + + /* get memory resource */ + sprintf(res_name, "musb%d", id); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name); + if (!res) { + dev_err(dev, "%s get mem resource failed\n", res_name); + ret = -ENODEV; + goto err0; + } + res->parent = NULL; + resources[0] = *res; + + /* get irq resource */ + sprintf(res_name, "musb%d-irq", id); + res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name); + if (!res) { + dev_err(dev, "%s get irq resource failed\n", res_name); + ret = -ENODEV; + goto err0; + } + strcpy((u8 *)res->name, "mc"); + res->parent = NULL; + resources[1] = *res; + + /* allocate the child platform device */ + musb = platform_device_alloc("musb-hdrc", -1); + if (!musb) { + dev_err(dev, "failed to allocate musb device\n"); + ret = -ENOMEM; + goto err0; + } + + musb->dev.parent = dev; + musb->dev.dma_mask = &musb_dmamask; + musb->dev.coherent_dma_mask = musb_dmamask; + + glue->musb = musb; + + pdata->platform_ops = &dsps_ops; + + ret = platform_device_add_resources(musb, resources, 2); + if (ret) { + dev_err(dev, "failed to add resources\n"); + goto err1; + } + + ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); + if (ret) { + dev_err(dev, "failed to add platform_data\n"); + goto err1; + } + + ret = platform_device_add(musb); + if (ret) { + dev_err(dev, "failed to register musb device\n"); + goto err1; + } + + return 0; + +err1: + platform_device_put(musb); +err0: + return ret; +} + +static void __devexit dsps_delete_musb_pdev(struct dsps_glue *glue) +{ + platform_device_del(glue->musb); + platform_device_put(glue->musb); +} + +static int __devinit dsps_probe(struct platform_device *pdev) +{ + const struct platform_device_id *id = platform_get_device_id(pdev); + const struct dsps_musb_wrapper *wrp = + (struct dsps_musb_wrapper *)id->driver_data; + struct dsps_glue *glue; + struct resource *iomem; + int ret; + + /* allocate glue */ + glue = kzalloc(sizeof(*glue), GFP_KERNEL); + if (!glue) { + dev_err(&pdev->dev, "unable to allocate glue memory\n"); + ret = -ENOMEM; + goto err0; + } + + /* get memory resource */ + iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!iomem) { + dev_err(&pdev->dev, "failed to get usbss mem resourse\n"); + ret = -ENODEV; + goto err1; + } + + glue->dev = &pdev->dev; + + glue->wrp = kmemdup(wrp, sizeof(*wrp), GFP_KERNEL); + if (!glue->wrp) { + dev_err(&pdev->dev, "failed to duplicate wrapper struct memory\n"); + ret = -ENOMEM; + goto err1; + } + platform_set_drvdata(pdev, glue); + + /* create the child platform device for first instances of musb */ + ret = dsps_create_musb_pdev(glue, 0); + if (ret != 0) { + dev_err(&pdev->dev, "failed to create child pdev\n"); + goto err2; + } + + /* enable the usbss clocks */ + pm_runtime_enable(&pdev->dev); + + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "pm_runtime_get_sync FAILED"); + goto err3; + } + + return 0; + +err3: + pm_runtime_disable(&pdev->dev); +err2: + kfree(glue->wrp); +err1: + kfree(glue); +err0: + return ret; +} +static int __devexit dsps_remove(struct platform_device *pdev) +{ + struct dsps_glue *glue = platform_get_drvdata(pdev); + + /* delete the child platform device */ + dsps_delete_musb_pdev(glue); + + /* disable usbss clocks */ + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); + kfree(glue->wrp); + kfree(glue); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int dsps_suspend(struct device *dev) +{ + struct musb_hdrc_platform_data *plat = dev->platform_data; + struct omap_musb_board_data *data = plat->board_data; + + /* Shutdown the on-chip PHY and its PLL. */ + if (data->set_phy_power) + data->set_phy_power(0); + + return 0; +} + +static int dsps_resume(struct device *dev) +{ + struct musb_hdrc_platform_data *plat = dev->platform_data; + struct omap_musb_board_data *data = plat->board_data; + + /* Start the on-chip PHY and its PLL. */ + if (data->set_phy_power) + data->set_phy_power(1); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume); + +static const struct dsps_musb_wrapper ti81xx_driver_data __devinitconst = { + .revision = 0x00, + .control = 0x14, + .status = 0x18, + .eoi = 0x24, + .epintr_set = 0x38, + .epintr_clear = 0x40, + .epintr_status = 0x30, + .coreintr_set = 0x3c, + .coreintr_clear = 0x44, + .coreintr_status = 0x34, + .phy_utmi = 0xe0, + .mode = 0xe8, + .reset = 0, + .otg_disable = 21, + .iddig = 8, + .usb_shift = 0, + .usb_mask = 0x1ff, + .usb_bitmap = (0x1ff << 0), + .drvvbus = 8, + .txep_shift = 0, + .txep_mask = 0xffff, + .txep_bitmap = (0xffff << 0), + .rxep_shift = 16, + .rxep_mask = 0xfffe, + .rxep_bitmap = (0xfffe << 16), + .musb_core_offset = 0x400, + .poll_seconds = 2, +}; + +static const struct platform_device_id musb_dsps_id_table[] __devinitconst = { + { + .name = "musb-ti81xx", + .driver_data = (kernel_ulong_t) &ti81xx_driver_data, + }, + { }, /* Terminating Entry */ +}; +MODULE_DEVICE_TABLE(platform, musb_dsps_id_table); + +static const struct of_device_id musb_dsps_of_match[] __devinitconst = { + { .compatible = "musb-ti81xx", }, + { .compatible = "ti,ti81xx-musb", }, + { .compatible = "ti,am335x-musb", }, + { }, +}; +MODULE_DEVICE_TABLE(of, musb_dsps_of_match); + +static struct platform_driver dsps_usbss_driver = { + .probe = dsps_probe, + .remove = __devexit_p(dsps_remove), + .driver = { + .name = "musb-dsps", + .pm = &dsps_pm_ops, + .of_match_table = musb_dsps_of_match, + }, + .id_table = musb_dsps_id_table, +}; + +MODULE_DESCRIPTION("TI DSPS MUSB Glue Layer"); +MODULE_AUTHOR("Ravi B "); +MODULE_AUTHOR("Ajay Kumar Gupta "); +MODULE_LICENSE("GPL v2"); + +static int __init dsps_init(void) +{ + return platform_driver_register(&dsps_usbss_driver); +} +subsys_initcall(dsps_init); + +static void __exit dsps_exit(void) +{ + platform_driver_unregister(&dsps_usbss_driver); +} +module_exit(dsps_exit); diff --git a/trunk/drivers/usb/musb/musb_io.h b/trunk/drivers/usb/musb/musb_io.h index 1d5eda26fbd1..f7c1c8e2dc3f 100644 --- a/trunk/drivers/usb/musb/musb_io.h +++ b/trunk/drivers/usb/musb/musb_io.h @@ -40,7 +40,7 @@ #if !defined(CONFIG_ARM) && !defined(CONFIG_SUPERH) \ && !defined(CONFIG_AVR32) && !defined(CONFIG_PPC32) \ && !defined(CONFIG_PPC64) && !defined(CONFIG_BLACKFIN) \ - && !defined(CONFIG_MIPS) + && !defined(CONFIG_MIPS) && !defined(CONFIG_M68K) static inline void readsl(const void __iomem *addr, void *buf, int len) { insl((unsigned long)addr, buf, len); } static inline void readsw(const void __iomem *addr, void *buf, int len) diff --git a/trunk/drivers/usb/otg/gpio_vbus.c b/trunk/drivers/usb/otg/gpio_vbus.c index a0a2178974fe..bde6298a9693 100644 --- a/trunk/drivers/usb/otg/gpio_vbus.c +++ b/trunk/drivers/usb/otg/gpio_vbus.c @@ -37,7 +37,9 @@ struct gpio_vbus_data { struct regulator *vbus_draw; int vbus_draw_enabled; unsigned mA; - struct work_struct work; + struct delayed_work work; + int vbus; + int irq; }; @@ -51,8 +53,7 @@ struct gpio_vbus_data { * edges might be workable. */ #define VBUS_IRQ_FLAGS \ - ( IRQF_SAMPLE_RANDOM | IRQF_SHARED \ - | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING ) + (IRQF_SHARED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING) /* interface to regulator framework */ @@ -94,20 +95,26 @@ static int is_vbus_powered(struct gpio_vbus_mach_info *pdata) static void gpio_vbus_work(struct work_struct *work) { struct gpio_vbus_data *gpio_vbus = - container_of(work, struct gpio_vbus_data, work); + container_of(work, struct gpio_vbus_data, work.work); struct gpio_vbus_mach_info *pdata = gpio_vbus->dev->platform_data; - int gpio, status; + int gpio, status, vbus; if (!gpio_vbus->phy.otg->gadget) return; + vbus = is_vbus_powered(pdata); + if ((vbus ^ gpio_vbus->vbus) == 0) + return; + gpio_vbus->vbus = vbus; + /* Peripheral controllers which manage the pullup themselves won't have * gpio_pullup configured here. If it's configured here, we'll do what * isp1301_omap::b_peripheral() does and enable the pullup here... although * that may complicate usb_gadget_{,dis}connect() support. */ gpio = pdata->gpio_pullup; - if (is_vbus_powered(pdata)) { + + if (vbus) { status = USB_EVENT_VBUS; gpio_vbus->phy.state = OTG_STATE_B_PERIPHERAL; gpio_vbus->phy.last_event = status; @@ -152,7 +159,7 @@ static irqreturn_t gpio_vbus_irq(int irq, void *data) otg->gadget ? otg->gadget->name : "none"); if (otg->gadget) - schedule_work(&gpio_vbus->work); + schedule_delayed_work(&gpio_vbus->work, msecs_to_jiffies(100)); return IRQ_HANDLED; } @@ -166,12 +173,11 @@ static int gpio_vbus_set_peripheral(struct usb_otg *otg, struct gpio_vbus_data *gpio_vbus; struct gpio_vbus_mach_info *pdata; struct platform_device *pdev; - int gpio, irq; + int gpio; gpio_vbus = container_of(otg->phy, struct gpio_vbus_data, phy); pdev = to_platform_device(gpio_vbus->dev); pdata = gpio_vbus->dev->platform_data; - irq = gpio_to_irq(pdata->gpio_vbus); gpio = pdata->gpio_pullup; if (!gadget) { @@ -195,7 +201,8 @@ static int gpio_vbus_set_peripheral(struct usb_otg *otg, dev_dbg(&pdev->dev, "registered gadget '%s'\n", gadget->name); /* initialize connection state */ - gpio_vbus_irq(irq, pdev); + gpio_vbus->vbus = 0; /* start with disconnected */ + gpio_vbus_irq(gpio_vbus->irq, pdev); return 0; } @@ -235,6 +242,7 @@ static int __init gpio_vbus_probe(struct platform_device *pdev) struct gpio_vbus_data *gpio_vbus; struct resource *res; int err, gpio, irq; + unsigned long irqflags; if (!pdata || !gpio_is_valid(pdata->gpio_vbus)) return -EINVAL; @@ -271,10 +279,13 @@ static int __init gpio_vbus_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (res) { irq = res->start; - res->flags &= IRQF_TRIGGER_MASK; - res->flags |= IRQF_SAMPLE_RANDOM | IRQF_SHARED; - } else + irqflags = (res->flags & IRQF_TRIGGER_MASK) | IRQF_SHARED; + } else { irq = gpio_to_irq(gpio); + irqflags = VBUS_IRQ_FLAGS; + } + + gpio_vbus->irq = irq; /* if data line pullup is in use, initialize it to "not pulling up" */ gpio = pdata->gpio_pullup; @@ -290,8 +301,7 @@ static int __init gpio_vbus_probe(struct platform_device *pdev) gpio_direction_output(gpio, pdata->gpio_pullup_inverted); } - err = request_irq(irq, gpio_vbus_irq, VBUS_IRQ_FLAGS, - "vbus_detect", pdev); + err = request_irq(irq, gpio_vbus_irq, irqflags, "vbus_detect", pdev); if (err) { dev_err(&pdev->dev, "can't request irq %i, err: %d\n", irq, err); @@ -300,7 +310,7 @@ static int __init gpio_vbus_probe(struct platform_device *pdev) ATOMIC_INIT_NOTIFIER_HEAD(&gpio_vbus->phy.notifier); - INIT_WORK(&gpio_vbus->work, gpio_vbus_work); + INIT_DELAYED_WORK(&gpio_vbus->work, gpio_vbus_work); gpio_vbus->vbus_draw = regulator_get(&pdev->dev, "vbus_draw"); if (IS_ERR(gpio_vbus->vbus_draw)) { @@ -317,9 +327,12 @@ static int __init gpio_vbus_probe(struct platform_device *pdev) goto err_otg; } + device_init_wakeup(&pdev->dev, pdata->wakeup); + return 0; err_otg: - free_irq(irq, &pdev->dev); + regulator_put(gpio_vbus->vbus_draw); + free_irq(irq, pdev); err_irq: if (gpio_is_valid(pdata->gpio_pullup)) gpio_free(pdata->gpio_pullup); @@ -337,11 +350,13 @@ static int __exit gpio_vbus_remove(struct platform_device *pdev) struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data; int gpio = pdata->gpio_vbus; + device_init_wakeup(&pdev->dev, 0); + cancel_delayed_work_sync(&gpio_vbus->work); regulator_put(gpio_vbus->vbus_draw); usb_set_transceiver(NULL); - free_irq(gpio_to_irq(gpio), &pdev->dev); + free_irq(gpio_vbus->irq, pdev); if (gpio_is_valid(pdata->gpio_pullup)) gpio_free(pdata->gpio_pullup); gpio_free(gpio); @@ -352,6 +367,33 @@ static int __exit gpio_vbus_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int gpio_vbus_pm_suspend(struct device *dev) +{ + struct gpio_vbus_data *gpio_vbus = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(gpio_vbus->irq); + + return 0; +} + +static int gpio_vbus_pm_resume(struct device *dev) +{ + struct gpio_vbus_data *gpio_vbus = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(gpio_vbus->irq); + + return 0; +} + +static const struct dev_pm_ops gpio_vbus_dev_pm_ops = { + .suspend = gpio_vbus_pm_suspend, + .resume = gpio_vbus_pm_resume, +}; +#endif + /* NOTE: the gpio-vbus device may *NOT* be hotplugged */ MODULE_ALIAS("platform:gpio-vbus"); @@ -360,6 +402,9 @@ static struct platform_driver gpio_vbus_driver = { .driver = { .name = "gpio-vbus", .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &gpio_vbus_dev_pm_ops, +#endif }, .remove = __exit_p(gpio_vbus_remove), }; diff --git a/trunk/drivers/usb/otg/twl6030-usb.c b/trunk/drivers/usb/otg/twl6030-usb.c index e3fa387ca81e..d2a9a8e691b9 100644 --- a/trunk/drivers/usb/otg/twl6030-usb.c +++ b/trunk/drivers/usb/otg/twl6030-usb.c @@ -455,7 +455,7 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev) twl->irq_enabled = true; status = request_threaded_irq(twl->irq1, NULL, twl6030_usbotg_irq, - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, "twl6030_usb", twl); if (status < 0) { dev_err(&pdev->dev, "can't get IRQ %d, err %d\n", @@ -467,7 +467,7 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev) } status = request_threaded_irq(twl->irq2, NULL, twl6030_usb_irq, - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, "twl6030_usb", twl); if (status < 0) { dev_err(&pdev->dev, "can't get IRQ %d, err %d\n", diff --git a/trunk/drivers/usb/phy/Kconfig b/trunk/drivers/usb/phy/Kconfig new file mode 100644 index 000000000000..3cfabcba7447 --- /dev/null +++ b/trunk/drivers/usb/phy/Kconfig @@ -0,0 +1,17 @@ +# +# Physical Layer USB driver configuration +# +comment "USB Physical Layer drivers" + depends on USB + +config USB_ISP1301 + tristate "NXP ISP1301 USB transceiver support" + depends on USB + depends on I2C + help + Say Y here to add support for the NXP ISP1301 USB transceiver driver. + This chip is typically used as USB transceiver for USB host, gadget + and OTG drivers (to be selected separately). + + To compile this driver as a module, choose M here: the + module will be called isp1301. diff --git a/trunk/drivers/usb/phy/Makefile b/trunk/drivers/usb/phy/Makefile new file mode 100644 index 000000000000..eca095b1a890 --- /dev/null +++ b/trunk/drivers/usb/phy/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for physical layer USB drivers +# + +ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG + +obj-$(CONFIG_USB_ISP1301) += isp1301.o diff --git a/trunk/drivers/usb/phy/isp1301.c b/trunk/drivers/usb/phy/isp1301.c new file mode 100644 index 000000000000..b19f4932a037 --- /dev/null +++ b/trunk/drivers/usb/phy/isp1301.c @@ -0,0 +1,77 @@ +/* + * NXP ISP1301 USB transceiver driver + * + * Copyright (C) 2012 Roland Stigge + * + * Author: Roland Stigge + * + * 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 + +#define DRV_NAME "isp1301" + +#define ISP1301_I2C_ADDR 0x2C + +static const unsigned short normal_i2c[] = { + ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END +}; + +static const struct i2c_device_id isp1301_id[] = { + { "isp1301", 0 }, + { } +}; + +static struct i2c_client *isp1301_i2c_client; + +static int isp1301_probe(struct i2c_client *client, + const struct i2c_device_id *i2c_id) +{ + isp1301_i2c_client = client; + return 0; +} + +static int isp1301_remove(struct i2c_client *client) +{ + return 0; +} + +static struct i2c_driver isp1301_driver = { + .driver = { + .name = DRV_NAME, + }, + .probe = isp1301_probe, + .remove = isp1301_remove, + .id_table = isp1301_id, +}; + +module_i2c_driver(isp1301_driver); + +static int match(struct device *dev, void *data) +{ + struct device_node *node = (struct device_node *)data; + return (dev->of_node == node) && + (dev->driver == &isp1301_driver.driver); +} + +struct i2c_client *isp1301_get_client(struct device_node *node) +{ + if (node) { /* reference of ISP1301 I2C node via DT */ + struct device *dev = bus_find_device(&i2c_bus_type, NULL, + node, match); + if (!dev) + return NULL; + return to_i2c_client(dev); + } else { /* non-DT: only one ISP1301 chip supported */ + return isp1301_i2c_client; + } +} +EXPORT_SYMBOL_GPL(isp1301_get_client); + +MODULE_AUTHOR("Roland Stigge "); +MODULE_DESCRIPTION("NXP ISP1301 USB transceiver driver"); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/usb/renesas_usbhs/mod_gadget.c b/trunk/drivers/usb/renesas_usbhs/mod_gadget.c index 00bd2a5e0362..28478ce26c34 100644 --- a/trunk/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/trunk/drivers/usb/renesas_usbhs/mod_gadget.c @@ -55,6 +55,7 @@ struct usbhsg_gpriv { #define USBHSG_STATUS_STARTED (1 << 0) #define USBHSG_STATUS_REGISTERD (1 << 1) #define USBHSG_STATUS_WEDGE (1 << 2) +#define USBHSG_STATUS_SELF_POWERED (1 << 3) }; struct usbhsg_recip_handle { @@ -333,7 +334,10 @@ static int usbhsg_recip_handler_std_get_device(struct usbhs_priv *priv, struct usb_ctrlrequest *ctrl) { struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); - unsigned short status = 1 << USB_DEVICE_SELF_POWERED; + unsigned short status = 0; + + if (usbhsg_status_has(gpriv, USBHSG_STATUS_SELF_POWERED)) + status = 1 << USB_DEVICE_SELF_POWERED; __usbhsg_recip_send_status(gpriv, status); @@ -879,8 +883,21 @@ static int usbhsg_get_frame(struct usb_gadget *gadget) return usbhs_frame_get_num(priv); } +static int usbhsg_set_selfpowered(struct usb_gadget *gadget, int is_self) +{ + struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); + + if (is_self) + usbhsg_status_set(gpriv, USBHSG_STATUS_SELF_POWERED); + else + usbhsg_status_clr(gpriv, USBHSG_STATUS_SELF_POWERED); + + return 0; +} + static struct usb_gadget_ops usbhsg_gadget_ops = { .get_frame = usbhsg_get_frame, + .set_selfpowered = usbhsg_set_selfpowered, .udc_start = usbhsg_gadget_start, .udc_stop = usbhsg_gadget_stop, }; diff --git a/trunk/drivers/usb/serial/Kconfig b/trunk/drivers/usb/serial/Kconfig index 7141d6599060..325d2910f9f9 100644 --- a/trunk/drivers/usb/serial/Kconfig +++ b/trunk/drivers/usb/serial/Kconfig @@ -669,6 +669,15 @@ config USB_SERIAL_SSU100 To compile this driver as a module, choose M here: the module will be called ssu100. +config USB_SERIAL_QT2 + tristate "USB Quatech Serial Driver for USB 2 devices" + help + Say Y here if you want to use the Quatech USB 2 + serial adapters. + + To compile this driver as a module, choose M here: the + module will be called quatech-serial. + config USB_SERIAL_DEBUG tristate "USB Debugging Device" help diff --git a/trunk/drivers/usb/serial/Makefile b/trunk/drivers/usb/serial/Makefile index 07f198ee0486..1dc483a8bfc7 100644 --- a/trunk/drivers/usb/serial/Makefile +++ b/trunk/drivers/usb/serial/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_USB_SERIAL_OTI6858) += oti6858.o obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o obj-$(CONFIG_USB_SERIAL_QCAUX) += qcaux.o obj-$(CONFIG_USB_SERIAL_QUALCOMM) += qcserial.o +obj-$(CONFIG_USB_SERIAL_QT2) += quatech2.o obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o obj-$(CONFIG_USB_SERIAL_SIEMENS_MPI) += siemens_mpi.o obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o diff --git a/trunk/drivers/usb/serial/aircable.c b/trunk/drivers/usb/serial/aircable.c index eec4fb9a35c1..d634e6635632 100644 --- a/trunk/drivers/usb/serial/aircable.c +++ b/trunk/drivers/usb/serial/aircable.c @@ -111,13 +111,14 @@ static int aircable_probe(struct usb_serial *serial, for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { endpoint = &iface_desc->endpoint[i].desc; if (usb_endpoint_is_bulk_out(endpoint)) { - dbg("found bulk out on endpoint %d", i); + dev_dbg(&serial->dev->dev, + "found bulk out on endpoint %d\n", i); ++num_bulk_out; } } if (num_bulk_out == 0) { - dbg("Invalid interface, discarding"); + dev_dbg(&serial->dev->dev, "Invalid interface, discarding\n"); return -ENODEV; } @@ -133,7 +134,7 @@ static int aircable_process_packet(struct tty_struct *tty, packet += HCI_HEADER_LENGTH; } if (len <= 0) { - dbg("%s - malformed packet", __func__); + dev_dbg(&port->dev, "%s - malformed packet\n", __func__); return 0; } @@ -170,13 +171,6 @@ static void aircable_process_read_urb(struct urb *urb) tty_kref_put(tty); } -static struct usb_driver aircable_driver = { - .name = "aircable", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver aircable_device = { .driver = { .owner = THIS_MODULE, @@ -196,7 +190,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &aircable_device, NULL }; -module_usb_serial_driver(aircable_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/trunk/drivers/usb/serial/ark3116.c b/trunk/drivers/usb/serial/ark3116.c index f99f47100dd8..f8ce97d8b0ad 100644 --- a/trunk/drivers/usb/serial/ark3116.c +++ b/trunk/drivers/usb/serial/ark3116.c @@ -265,7 +265,7 @@ static void ark3116_set_termios(struct tty_struct *tty, hcr = (cflag & CRTSCTS) ? 0x03 : 0x00; /* calc baudrate */ - dbg("%s - setting bps to %d", __func__, bps); + dev_dbg(&port->dev, "%s - setting bps to %d\n", __func__, bps); eval = 0; switch (bps) { case 0: @@ -292,8 +292,8 @@ static void ark3116_set_termios(struct tty_struct *tty, /* keep old LCR_SBC bit */ lcr |= (priv->lcr & UART_LCR_SBC); - dbg("%s - setting hcr:0x%02x,lcr:0x%02x,quot:%d", - __func__, hcr, lcr, quot); + dev_dbg(&port->dev, "%s - setting hcr:0x%02x,lcr:0x%02x,quot:%d\n", + __func__, hcr, lcr, quot); /* handshake control */ if (priv->hcr != hcr) { @@ -375,8 +375,9 @@ static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port) result = usb_serial_generic_open(tty, port); if (result) { - dbg("%s - usb_serial_generic_open failed: %d", - __func__, result); + dev_dbg(&port->dev, + "%s - usb_serial_generic_open failed: %d\n", + __func__, result); goto err_out; } @@ -622,24 +623,26 @@ static void ark3116_read_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", - __func__, status); + dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", + __func__, status); break; case 0: /* success */ /* discovered this by trail and error... */ if ((urb->actual_length == 4) && (data[0] == 0xe8)) { const __u8 id = data[1]&UART_IIR_ID; - dbg("%s: iir=%02x", __func__, data[1]); + dev_dbg(&port->dev, "%s: iir=%02x\n", __func__, data[1]); if (id == UART_IIR_MSI) { - dbg("%s: msr=%02x", __func__, data[3]); + dev_dbg(&port->dev, "%s: msr=%02x\n", + __func__, data[3]); ark3116_update_msr(port, data[3]); break; } else if (id == UART_IIR_RLSI) { - dbg("%s: lsr=%02x", __func__, data[2]); + dev_dbg(&port->dev, "%s: lsr=%02x\n", + __func__, data[2]); ark3116_update_lsr(port, data[2]); break; } @@ -714,13 +717,6 @@ static void ark3116_process_read_urb(struct urb *urb) tty_kref_put(tty); } -static struct usb_driver ark3116_driver = { - .name = "ark3116", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver ark3116_device = { .driver = { .owner = THIS_MODULE, @@ -747,7 +743,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &ark3116_device, NULL }; -module_usb_serial_driver(ark3116_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/usb/serial/belkin_sa.c b/trunk/drivers/usb/serial/belkin_sa.c index a52e0d2cec31..6b7365632951 100644 --- a/trunk/drivers/usb/serial/belkin_sa.c +++ b/trunk/drivers/usb/serial/belkin_sa.c @@ -2,17 +2,17 @@ * Belkin USB Serial Adapter Driver * * Copyright (C) 2000 William Greathouse (wgreathouse@smva.com) - * Copyright (C) 2000-2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2000-2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com) * * This program is largely derived from work by the linux-usb group * and associated source files. Please see the usb/serial files for * individual credits and copyrights. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * * See Documentation/usb/usb-serial.txt for more information on using this * driver @@ -62,7 +62,7 @@ static int belkin_sa_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); -static const struct usb_device_id id_table_combined[] = { +static const struct usb_device_id id_table[] = { { USB_DEVICE(BELKIN_SA_VID, BELKIN_SA_PID) }, { USB_DEVICE(BELKIN_OLD_VID, BELKIN_OLD_PID) }, { USB_DEVICE(PERACOM_VID, PERACOM_PID) }, @@ -71,14 +71,7 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(BELKIN_DOCKSTATION_VID, BELKIN_DOCKSTATION_PID) }, { } /* Terminating entry */ }; -MODULE_DEVICE_TABLE(usb, id_table_combined); - -static struct usb_driver belkin_driver = { - .name = "belkin", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; +MODULE_DEVICE_TABLE(usb, id_table); /* All of the device info needed for the serial converters */ static struct usb_serial_driver belkin_device = { @@ -87,7 +80,7 @@ static struct usb_serial_driver belkin_device = { .name = "belkin", }, .description = "Belkin / Peracom / GoHubs USB Serial Adapter", - .id_table = id_table_combined, + .id_table = id_table, .num_ports = 1, .open = belkin_sa_open, .close = belkin_sa_close, @@ -159,8 +152,6 @@ static void belkin_sa_release(struct usb_serial *serial) { int i; - dbg("%s", __func__); - for (i = 0; i < serial->num_ports; ++i) kfree(usb_get_serial_port_data(serial->port[i])); } @@ -170,8 +161,6 @@ static int belkin_sa_open(struct tty_struct *tty, { int retval; - dbg("%s port %d", __func__, port->number); - retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (retval) { dev_err(&port->dev, "usb_submit_urb(read int) failed\n"); @@ -187,8 +176,6 @@ static int belkin_sa_open(struct tty_struct *tty, static void belkin_sa_close(struct usb_serial_port *port) { - dbg("%s port %d", __func__, port->number); - usb_serial_generic_close(port); usb_kill_urb(port->interrupt_in_urb); } @@ -210,12 +197,12 @@ static void belkin_sa_read_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", - __func__, status); + dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", + __func__, status); goto exit; } @@ -403,7 +390,9 @@ static void belkin_sa_set_termios(struct tty_struct *tty, case CS8: urb_value = BELKIN_SA_DATA_BITS(8); break; - default: dbg("CSIZE was not CS5-CS8, using default of 8"); + default: + dev_dbg(&port->dev, + "CSIZE was not CS5-CS8, using default of 8\n"); urb_value = BELKIN_SA_DATA_BITS(8); break; } @@ -463,8 +452,6 @@ static int belkin_sa_tiocmget(struct tty_struct *tty) unsigned long control_state; unsigned long flags; - dbg("%s", __func__); - spin_lock_irqsave(&priv->lock, flags); control_state = priv->control_state; spin_unlock_irqrestore(&priv->lock, flags); @@ -484,8 +471,6 @@ static int belkin_sa_tiocmset(struct tty_struct *tty, int rts = 0; int dtr = 0; - dbg("%s", __func__); - spin_lock_irqsave(&priv->lock, flags); control_state = priv->control_state; @@ -524,7 +509,7 @@ static int belkin_sa_tiocmset(struct tty_struct *tty, return retval; } -module_usb_serial_driver(belkin_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/trunk/drivers/usb/serial/bus.c b/trunk/drivers/usb/serial/bus.c index ed8adb052ca7..f398d1e34474 100644 --- a/trunk/drivers/usb/serial/bus.c +++ b/trunk/drivers/usb/serial/bus.c @@ -124,8 +124,15 @@ static ssize_t store_new_id(struct device_driver *driver, return retval; } +static ssize_t show_dynids(struct device_driver *driver, char *buf) +{ + struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver); + + return usb_show_dynids(&usb_drv->dynids, buf); +} + static struct driver_attribute drv_attrs[] = { - __ATTR(new_id, S_IWUSR, NULL, store_new_id), + __ATTR(new_id, S_IRUGO | S_IWUSR, show_dynids, store_new_id), __ATTR_NULL, }; diff --git a/trunk/drivers/usb/serial/ch341.c b/trunk/drivers/usb/serial/ch341.c index aaab32db31d0..cabd1b15ddce 100644 --- a/trunk/drivers/usb/serial/ch341.c +++ b/trunk/drivers/usb/serial/ch341.c @@ -125,8 +125,6 @@ static int ch341_set_baudrate(struct usb_device *dev, unsigned long factor; short divisor; - dbg("ch341_set_baudrate(%d)", priv->baud_rate); - if (!priv->baud_rate) return -EINVAL; factor = (CH341_BAUDBASE_FACTOR / priv->baud_rate); @@ -153,7 +151,6 @@ static int ch341_set_baudrate(struct usb_device *dev, static int ch341_set_handshake(struct usb_device *dev, u8 control) { - dbg("ch341_set_handshake(0x%02x)", control); return ch341_control_out(dev, 0xa4, ~control, 0); } @@ -164,8 +161,6 @@ static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv) const unsigned size = 8; unsigned long flags; - dbg("ch341_get_status()"); - buffer = kmalloc(size, GFP_KERNEL); if (!buffer) return -ENOMEM; @@ -196,8 +191,6 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv) int r; const unsigned size = 8; - dbg("ch341_configure()"); - buffer = kmalloc(size, GFP_KERNEL); if (!buffer) return -ENOMEM; @@ -254,8 +247,6 @@ static int ch341_attach(struct usb_serial *serial) struct ch341_private *priv; int r; - dbg("ch341_attach()"); - /* private data */ priv = kzalloc(sizeof(struct ch341_private), GFP_KERNEL); if (!priv) @@ -290,7 +281,6 @@ static void ch341_dtr_rts(struct usb_serial_port *port, int on) struct ch341_private *priv = usb_get_serial_port_data(port); unsigned long flags; - dbg("%s - port %d", __func__, port->number); /* drop DTR and RTS */ spin_lock_irqsave(&priv->lock, flags); if (on) @@ -304,8 +294,6 @@ static void ch341_dtr_rts(struct usb_serial_port *port, int on) static void ch341_close(struct usb_serial_port *port) { - dbg("%s - port %d", __func__, port->number); - usb_serial_generic_close(port); usb_kill_urb(port->interrupt_in_urb); } @@ -318,8 +306,6 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port) struct ch341_private *priv = usb_get_serial_port_data(serial->port[0]); int r; - dbg("ch341_open()"); - priv->baud_rate = DEFAULT_BAUD_RATE; r = ch341_configure(serial->dev, priv); @@ -358,8 +344,6 @@ static void ch341_set_termios(struct tty_struct *tty, unsigned baud_rate; unsigned long flags; - dbg("ch341_set_termios()"); - baud_rate = tty_get_baud_rate(tty); priv->baud_rate = baud_rate; @@ -393,8 +377,6 @@ static void ch341_break_ctl(struct tty_struct *tty, int break_state) uint16_t reg_contents; uint8_t *break_reg; - dbg("%s()", __func__); - break_reg = kmalloc(2, GFP_KERNEL); if (!break_reg) { dev_err(&port->dev, "%s - kmalloc failed\n", __func__); @@ -461,8 +443,6 @@ static void ch341_read_int_callback(struct urb *urb) unsigned int actual_length = urb->actual_length; int status; - dbg("%s (%d)", __func__, port->number); - switch (urb->status) { case 0: /* success */ @@ -580,8 +560,6 @@ static int ch341_tiocmget(struct tty_struct *tty) u8 status; unsigned int result; - dbg("%s (%d)", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); mcr = priv->line_control; status = priv->line_status; @@ -599,35 +577,18 @@ static int ch341_tiocmget(struct tty_struct *tty) return result; } - -static int ch341_reset_resume(struct usb_interface *intf) +static int ch341_reset_resume(struct usb_serial *serial) { - struct usb_device *dev = interface_to_usbdev(intf); - struct usb_serial *serial = NULL; struct ch341_private *priv; - serial = usb_get_intfdata(intf); priv = usb_get_serial_port_data(serial->port[0]); - /*reconfigure ch341 serial port after bus-reset*/ - ch341_configure(dev, priv); - - usb_serial_resume(intf); + /* reconfigure ch341 serial port after bus-reset */ + ch341_configure(serial->dev, priv); return 0; } -static struct usb_driver ch341_driver = { - .name = "ch341", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .reset_resume = ch341_reset_resume, - .id_table = id_table, - .supports_autosuspend = 1, -}; - static struct usb_serial_driver ch341_device = { .driver = { .owner = THIS_MODULE, @@ -646,13 +607,14 @@ static struct usb_serial_driver ch341_device = { .tiocmset = ch341_tiocmset, .read_int_callback = ch341_read_int_callback, .attach = ch341_attach, + .reset_resume = ch341_reset_resume, }; static struct usb_serial_driver * const serial_drivers[] = { &ch341_device, NULL }; -module_usb_serial_driver(ch341_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/usb/serial/console.c b/trunk/drivers/usb/serial/console.c index 1ee6b2ab0f89..b9cca6dcde07 100644 --- a/trunk/drivers/usb/serial/console.c +++ b/trunk/drivers/usb/serial/console.c @@ -113,7 +113,8 @@ static int usb_console_setup(struct console *co, char *options) serial = usb_serial_get_by_index(co->index); if (serial == NULL) { /* no device is connected yet, sorry :( */ - err("No USB device connected to ttyUSB%i", co->index); + printk(KERN_ERR "No USB device connected to ttyUSB%i\n", + co->index); return -ENODEV; } @@ -137,7 +138,7 @@ static int usb_console_setup(struct console *co, char *options) tty = kzalloc(sizeof(*tty), GFP_KERNEL); if (!tty) { retval = -ENOMEM; - err("no more memory"); + dev_err(&port->dev, "no more memory\n"); goto reset_open_count; } kref_init(&tty->kref); @@ -146,7 +147,7 @@ static int usb_console_setup(struct console *co, char *options) tty->index = co->index; if (tty_init_termios(tty)) { retval = -ENOMEM; - err("no more memory"); + dev_err(&port->dev, "no more memory\n"); goto free_tty; } } @@ -159,7 +160,7 @@ static int usb_console_setup(struct console *co, char *options) retval = usb_serial_generic_open(NULL, port); if (retval) { - err("could not open USB console port"); + dev_err(&port->dev, "could not open USB console port\n"); goto fail; } diff --git a/trunk/drivers/usb/serial/cp210x.c b/trunk/drivers/usb/serial/cp210x.c index ec30f95ef399..1b1926200ba7 100644 --- a/trunk/drivers/usb/serial/cp210x.c +++ b/trunk/drivers/usb/serial/cp210x.c @@ -156,13 +156,6 @@ struct cp210x_port_private { __u8 bInterfaceNumber; }; -static struct usb_driver cp210x_driver = { - .name = "cp210x", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver cp210x_device = { .driver = { .owner = THIS_MODULE, @@ -188,8 +181,10 @@ static struct usb_serial_driver * const serial_drivers[] = { }; /* Config request types */ -#define REQTYPE_HOST_TO_DEVICE 0x41 -#define REQTYPE_DEVICE_TO_HOST 0xc1 +#define REQTYPE_HOST_TO_INTERFACE 0x41 +#define REQTYPE_INTERFACE_TO_HOST 0xc1 +#define REQTYPE_HOST_TO_DEVICE 0x40 +#define REQTYPE_DEVICE_TO_HOST 0xc0 /* Config request codes */ #define CP210X_IFC_ENABLE 0x00 @@ -286,7 +281,7 @@ static int cp210x_get_config(struct usb_serial_port *port, u8 request, /* Issue the request, attempting to read 'size' bytes */ result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - request, REQTYPE_DEVICE_TO_HOST, 0x0000, + request, REQTYPE_INTERFACE_TO_HOST, 0x0000, port_priv->bInterfaceNumber, buf, size, USB_CTRL_GET_TIMEOUT); @@ -340,13 +335,13 @@ static int cp210x_set_config(struct usb_serial_port *port, u8 request, if (size > 2) { result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - request, REQTYPE_HOST_TO_DEVICE, 0x0000, + request, REQTYPE_HOST_TO_INTERFACE, 0x0000, port_priv->bInterfaceNumber, buf, size, USB_CTRL_SET_TIMEOUT); } else { result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - request, REQTYPE_HOST_TO_DEVICE, data[0], + request, REQTYPE_HOST_TO_INTERFACE, data[0], port_priv->bInterfaceNumber, NULL, 0, USB_CTRL_SET_TIMEOUT); } @@ -422,8 +417,6 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port) { int result; - dbg("%s - port %d", __func__, port->number); - result = cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_ENABLE); if (result) { @@ -443,8 +436,6 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port) static void cp210x_close(struct usb_serial_port *port) { - dbg("%s - port %d", __func__, port->number); - usb_serial_generic_close(port); mutex_lock(&port->serial->disc_mutex); @@ -488,8 +479,6 @@ static void cp210x_get_termios_port(struct usb_serial_port *port, unsigned int baud; unsigned int bits; - dbg("%s - port %d", __func__, port->number); - cp210x_get_config(port, CP210X_GET_BAUDRATE, &baud, 4); dbg("%s - baud rate = %d", __func__, baud); @@ -787,8 +776,6 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port, { unsigned int control = 0; - dbg("%s - port %d", __func__, port->number); - if (set & TIOCM_RTS) { control |= CONTROL_RTS; control |= CONTROL_WRITE_RTS; @@ -825,8 +812,6 @@ static int cp210x_tiocmget (struct tty_struct *tty) unsigned int control; int result; - dbg("%s - port %d", __func__, port->number); - cp210x_get_config(port, CP210X_GET_MDMSTS, &control, 1); result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0) @@ -846,7 +831,6 @@ static void cp210x_break_ctl (struct tty_struct *tty, int break_state) struct usb_serial_port *port = tty->driver_data; unsigned int state; - dbg("%s - port %d", __func__, port->number); if (break_state == 0) state = BREAK_OFF; else @@ -891,7 +875,7 @@ static void cp210x_release(struct usb_serial *serial) } } -module_usb_serial_driver(cp210x_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_VERSION(DRIVER_VERSION); diff --git a/trunk/drivers/usb/serial/cyberjack.c b/trunk/drivers/usb/serial/cyberjack.c index d39b9418f2fb..3aa0b530f68e 100644 --- a/trunk/drivers/usb/serial/cyberjack.c +++ b/trunk/drivers/usb/serial/cyberjack.c @@ -77,13 +77,6 @@ static const struct usb_device_id id_table[] = { MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver cyberjack_driver = { - .name = "cyberjack", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver cyberjack_device = { .driver = { .owner = THIS_MODULE, @@ -122,8 +115,6 @@ static int cyberjack_startup(struct usb_serial *serial) struct cyberjack_private *priv; int i; - dbg("%s", __func__); - /* allocate the private data structure */ priv = kmalloc(sizeof(struct cyberjack_private), GFP_KERNEL); if (!priv) @@ -155,8 +146,6 @@ static void cyberjack_disconnect(struct usb_serial *serial) { int i; - dbg("%s", __func__); - for (i = 0; i < serial->num_ports; ++i) usb_kill_urb(serial->port[i]->interrupt_in_urb); } @@ -165,8 +154,6 @@ static void cyberjack_release(struct usb_serial *serial) { int i; - dbg("%s", __func__); - for (i = 0; i < serial->num_ports; ++i) { /* My special items, the standard routines free my urbs */ kfree(usb_get_serial_port_data(serial->port[i])); @@ -180,8 +167,6 @@ static int cyberjack_open(struct tty_struct *tty, unsigned long flags; int result = 0; - dbg("%s - port %d", __func__, port->number); - dbg("%s - usb_clear_halt", __func__); usb_clear_halt(port->serial->dev, port->write_urb->pipe); @@ -197,8 +182,6 @@ static int cyberjack_open(struct tty_struct *tty, static void cyberjack_close(struct usb_serial_port *port) { - dbg("%s - port %d", __func__, port->number); - if (port->serial->dev) { /* shutdown any bulk reads that might be going on */ usb_kill_urb(port->write_urb); @@ -214,8 +197,6 @@ static int cyberjack_write(struct tty_struct *tty, int result; int wrexpected; - dbg("%s - port %d", __func__, port->number); - if (count == 0) { dbg("%s - write request of 0 bytes", __func__); return 0; @@ -307,8 +288,6 @@ static void cyberjack_read_int_callback(struct urb *urb) int status = urb->status; int result; - dbg("%s - port %d", __func__, port->number); - /* the urb might have been killed. */ if (status) return; @@ -367,8 +346,6 @@ static void cyberjack_read_bulk_callback(struct urb *urb) int result; int status = urb->status; - dbg("%s - port %d", __func__, port->number); - usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data); if (status) { @@ -417,8 +394,6 @@ static void cyberjack_write_bulk_callback(struct urb *urb) struct cyberjack_private *priv = usb_get_serial_port_data(port); int status = urb->status; - dbg("%s - port %d", __func__, port->number); - set_bit(0, &port->write_urbs_free); if (status) { dbg("%s - nonzero write bulk status received: %d", @@ -475,7 +450,7 @@ static void cyberjack_write_bulk_callback(struct urb *urb) usb_serial_port_softint(port); } -module_usb_serial_driver(cyberjack_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/trunk/drivers/usb/serial/cypress_m8.c b/trunk/drivers/usb/serial/cypress_m8.c index afc886c75d2f..b78c34eb5d3f 100644 --- a/trunk/drivers/usb/serial/cypress_m8.c +++ b/trunk/drivers/usb/serial/cypress_m8.c @@ -89,13 +89,6 @@ static const struct usb_device_id id_table_combined[] = { MODULE_DEVICE_TABLE(usb, id_table_combined); -static struct usb_driver cypress_driver = { - .name = "cypress", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; - enum packet_format { packet_format_1, /* b0:status, b1:payload count */ packet_format_2 /* b0[7:3]:status, b0[2:0]:payload count */ @@ -305,8 +298,6 @@ static int cypress_serial_control(struct tty_struct *tty, const unsigned int feature_len = 5; unsigned long flags; - dbg("%s", __func__); - priv = usb_get_serial_port_data(port); if (!priv->comm_is_ok) @@ -451,8 +442,6 @@ static int generic_startup(struct usb_serial *serial) struct cypress_private *priv; struct usb_serial_port *port = serial->port[0]; - dbg("%s - port %d", __func__, port->number); - priv = kzalloc(sizeof(struct cypress_private), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -505,8 +494,6 @@ static int cypress_earthmate_startup(struct usb_serial *serial) struct cypress_private *priv; struct usb_serial_port *port = serial->port[0]; - dbg("%s", __func__); - if (generic_startup(serial)) { dbg("%s - Failed setting up port %d", __func__, port->number); @@ -537,8 +524,6 @@ static int cypress_hidcom_startup(struct usb_serial *serial) { struct cypress_private *priv; - dbg("%s", __func__); - if (generic_startup(serial)) { dbg("%s - Failed setting up port %d", __func__, serial->port[0]->number); @@ -556,8 +541,6 @@ static int cypress_ca42v2_startup(struct usb_serial *serial) { struct cypress_private *priv; - dbg("%s", __func__); - if (generic_startup(serial)) { dbg("%s - Failed setting up port %d", __func__, serial->port[0]->number); @@ -575,10 +558,7 @@ static void cypress_release(struct usb_serial *serial) { struct cypress_private *priv; - dbg("%s - port %d", __func__, serial->port[0]->number); - /* all open ports are closed at this point */ - priv = usb_get_serial_port_data(serial->port[0]); if (priv) { @@ -595,8 +575,6 @@ static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port) unsigned long flags; int result = 0; - dbg("%s - port %d", __func__, port->number); - if (!priv->comm_is_ok) return -EIO; @@ -661,8 +639,6 @@ static void cypress_close(struct usb_serial_port *port) struct cypress_private *priv = usb_get_serial_port_data(port); unsigned long flags; - dbg("%s - port %d", __func__, port->number); - /* writing is potentially harmful, lock must be taken */ mutex_lock(&port->serial->disc_mutex); if (port->serial->disconnected) { @@ -720,7 +696,6 @@ static void cypress_send(struct usb_serial_port *port) if (!priv->comm_is_ok) return; - dbg("%s - port %d", __func__, port->number); dbg("%s - interrupt out size is %d", __func__, port->interrupt_out_size); @@ -828,8 +803,6 @@ static int cypress_write_room(struct tty_struct *tty) int room = 0; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); room = kfifo_avail(&priv->write_fifo); spin_unlock_irqrestore(&priv->lock, flags); @@ -847,8 +820,6 @@ static int cypress_tiocmget(struct tty_struct *tty) unsigned int result = 0; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); control = priv->line_control; status = priv->current_status; @@ -874,8 +845,6 @@ static int cypress_tiocmset(struct tty_struct *tty, struct cypress_private *priv = usb_get_serial_port_data(port); unsigned long flags; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); if (set & TIOCM_RTS) priv->line_control |= CONTROL_RTS; @@ -948,8 +917,6 @@ static void cypress_set_termios(struct tty_struct *tty, __u8 oldlines; int linechange = 0; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); /* We can't clean this one up as we don't know the device type early enough */ @@ -1096,8 +1063,6 @@ static int cypress_chars_in_buffer(struct tty_struct *tty) int chars = 0; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); chars = kfifo_len(&priv->write_fifo); spin_unlock_irqrestore(&priv->lock, flags); @@ -1112,8 +1077,6 @@ static void cypress_throttle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; struct cypress_private *priv = usb_get_serial_port_data(port); - dbg("%s - port %d", __func__, port->number); - spin_lock_irq(&priv->lock); priv->rx_flags = THROTTLED; spin_unlock_irq(&priv->lock); @@ -1126,8 +1089,6 @@ static void cypress_unthrottle(struct tty_struct *tty) struct cypress_private *priv = usb_get_serial_port_data(port); int actually_throttled, result; - dbg("%s - port %d", __func__, port->number); - spin_lock_irq(&priv->lock); actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED; priv->rx_flags = 0; @@ -1161,8 +1122,6 @@ static void cypress_read_int_callback(struct urb *urb) int i = 0; int status = urb->status; - dbg("%s - port %d", __func__, port->number); - switch (status) { case 0: /* success */ break; @@ -1303,8 +1262,6 @@ static void cypress_write_int_callback(struct urb *urb) int result; int status = urb->status; - dbg("%s - port %d", __func__, port->number); - switch (status) { case 0: /* success */ @@ -1346,7 +1303,7 @@ static void cypress_write_int_callback(struct urb *urb) cypress_send(port); } -module_usb_serial_driver(cypress_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/trunk/drivers/usb/serial/digi_acceleport.c b/trunk/drivers/usb/serial/digi_acceleport.c index 999f91bf70de..b5cd838093ef 100644 --- a/trunk/drivers/usb/serial/digi_acceleport.c +++ b/trunk/drivers/usb/serial/digi_acceleport.c @@ -271,14 +271,6 @@ static const struct usb_device_id id_table_4[] = { MODULE_DEVICE_TABLE(usb, id_table_combined); -static struct usb_driver digi_driver = { - .name = "digi_acceleport", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; - - /* device info needed for the Digi serial converter */ static struct usb_serial_driver digi_acceleport_2_device = { @@ -657,9 +649,6 @@ static void digi_rx_throttle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; struct digi_port *priv = usb_get_serial_port_data(port); - - dbg("digi_rx_throttle: TOP: port=%d", priv->dp_port_num); - /* stop receiving characters by not resubmitting the read urb */ spin_lock_irqsave(&priv->dp_port_lock, flags); priv->dp_throttled = 1; @@ -675,8 +664,6 @@ static void digi_rx_unthrottle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; struct digi_port *priv = usb_get_serial_port_data(port); - dbg("digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num); - spin_lock_irqsave(&priv->dp_port_lock, flags); /* restart read chain */ @@ -904,8 +891,6 @@ static int digi_tiocmget(struct tty_struct *tty) unsigned int val; unsigned long flags; - dbg("%s: TOP: port=%d", __func__, priv->dp_port_num); - spin_lock_irqsave(&priv->dp_port_lock, flags); val = priv->dp_modem_signals; spin_unlock_irqrestore(&priv->dp_port_lock, flags); @@ -921,8 +906,6 @@ static int digi_tiocmset(struct tty_struct *tty, unsigned int val; unsigned long flags; - dbg("%s: TOP: port=%d", __func__, priv->dp_port_num); - spin_lock_irqsave(&priv->dp_port_lock, flags); val = (priv->dp_modem_signals & ~clear) | set; spin_unlock_irqrestore(&priv->dp_port_lock, flags); @@ -1013,8 +996,6 @@ static void digi_write_bulk_callback(struct urb *urb) int ret = 0; int status = urb->status; - dbg("digi_write_bulk_callback: TOP, status=%d", status); - /* port and serial sanity check */ if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) { pr_err("%s: port or port->private is NULL, status=%d\n", @@ -1121,8 +1102,6 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port) struct digi_port *priv = usb_get_serial_port_data(port); struct ktermios not_termios; - dbg("digi_open: TOP: port=%d", priv->dp_port_num); - /* be sure the device is started up */ if (digi_startup_device(port->serial) != 0) return -ENXIO; @@ -1160,8 +1139,6 @@ static void digi_close(struct usb_serial_port *port) unsigned char buf[32]; struct digi_port *priv = usb_get_serial_port_data(port); - dbg("digi_close: TOP: port=%d", priv->dp_port_num); - mutex_lock(&port->serial->disc_mutex); /* if disconnected, just clear flags */ if (port->serial->disconnected) @@ -1220,7 +1197,6 @@ static void digi_close(struct usb_serial_port *port) wake_up_interruptible(&priv->dp_close_wait); spin_unlock_irq(&priv->dp_port_lock); mutex_unlock(&port->serial->disc_mutex); - dbg("digi_close: done"); } @@ -1269,8 +1245,6 @@ static int digi_startup(struct usb_serial *serial) struct digi_port *priv; struct digi_serial *serial_priv; - dbg("digi_startup: TOP"); - /* allocate the private data structures for all ports */ /* number of regular ports + 1 for the out-of-band port */ for (i = 0; i < serial->type->num_ports + 1; i++) { @@ -1325,7 +1299,6 @@ static int digi_startup(struct usb_serial *serial) static void digi_disconnect(struct usb_serial *serial) { int i; - dbg("digi_disconnect: TOP, in_interrupt()=%ld", in_interrupt()); /* stop reads and writes on all ports */ for (i = 0; i < serial->type->num_ports + 1; i++) { @@ -1338,7 +1311,6 @@ static void digi_disconnect(struct usb_serial *serial) static void digi_release(struct usb_serial *serial) { int i; - dbg("digi_release: TOP, in_interrupt()=%ld", in_interrupt()); /* free the private data structures for all ports */ /* number of regular ports + 1 for the out-of-band port */ @@ -1356,8 +1328,6 @@ static void digi_read_bulk_callback(struct urb *urb) int ret; int status = urb->status; - dbg("digi_read_bulk_callback: TOP"); - /* port sanity check, do not resubmit if port is not valid */ if (port == NULL) return; @@ -1507,9 +1477,6 @@ static int digi_read_oob_callback(struct urb *urb) int i; unsigned int rts; - dbg("digi_read_oob_callback: port=%d, len=%d", - priv->dp_port_num, urb->actual_length); - /* handle each oob command */ for (i = 0; i < urb->actual_length - 3;) { opcode = ((unsigned char *)urb->transfer_buffer)[i++]; @@ -1580,7 +1547,7 @@ static int digi_read_oob_callback(struct urb *urb) } -module_usb_serial_driver(digi_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/trunk/drivers/usb/serial/empeg.c b/trunk/drivers/usb/serial/empeg.c index 5b99fc09e327..cdf61dd07318 100644 --- a/trunk/drivers/usb/serial/empeg.c +++ b/trunk/drivers/usb/serial/empeg.c @@ -51,13 +51,6 @@ static const struct usb_device_id id_table[] = { MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver empeg_driver = { - .name = "empeg", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver empeg_device = { .driver = { .owner = THIS_MODULE, @@ -80,14 +73,12 @@ static int empeg_startup(struct usb_serial *serial) { int r; - dbg("%s", __func__); - if (serial->dev->actconfig->desc.bConfigurationValue != 1) { dev_err(&serial->dev->dev, "active config #%d != 1 ??\n", serial->dev->actconfig->desc.bConfigurationValue); return -ENODEV; } - dbg("%s - reset config", __func__); + r = usb_reset_configuration(serial->dev); /* continue on with initialization */ @@ -138,7 +129,7 @@ static void empeg_init_termios(struct tty_struct *tty) tty_encode_baud_rate(tty, 115200, 115200); } -module_usb_serial_driver(empeg_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/trunk/drivers/usb/serial/ezusb.c b/trunk/drivers/usb/serial/ezusb.c index 3cfc762f5056..800e8eb60003 100644 --- a/trunk/drivers/usb/serial/ezusb.c +++ b/trunk/drivers/usb/serial/ezusb.c @@ -26,7 +26,6 @@ int ezusb_writememory(struct usb_serial *serial, int address, int result; unsigned char *transfer_buffer; - /* dbg("ezusb_writememory %x, %d", address, length); */ if (!serial->dev) { printk(KERN_ERR "ezusb: %s - no physical device present, " "failing.\n", __func__); @@ -50,7 +49,6 @@ int ezusb_set_reset(struct usb_serial *serial, unsigned char reset_bit) { int response; - /* dbg("%s - %d", __func__, reset_bit); */ response = ezusb_writememory(serial, CPUCS_REG, &reset_bit, 1, 0xa0); if (response < 0) dev_err(&serial->dev->dev, "%s- %d failed\n", diff --git a/trunk/drivers/usb/serial/f81232.c b/trunk/drivers/usb/serial/f81232.c index 88c0b1963920..499b15fd82f1 100644 --- a/trunk/drivers/usb/serial/f81232.c +++ b/trunk/drivers/usb/serial/f81232.c @@ -68,8 +68,6 @@ static void f81232_read_int_callback(struct urb *urb) int status = urb->status; int retval; - dbg("%s (%d)", __func__, port->number); - switch (status) { case 0: /* success */ @@ -78,12 +76,12 @@ static void f81232_read_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, - status); + dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", __func__, - status); + dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", + __func__, status); goto exit; } @@ -133,7 +131,7 @@ static void f81232_process_read_urb(struct urb *urb) tty_flag = TTY_PARITY; else if (line_status & UART_FRAME_ERROR) tty_flag = TTY_FRAME; - dbg("%s - tty_flag = %d", __func__, tty_flag); + dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag); /* overrun is special, not associated with a char */ if (line_status & UART_OVERRUN_ERROR) @@ -203,7 +201,6 @@ static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port) if (tty) f81232_set_termios(tty, port, &tmp_termios); - dbg("%s - submitting interrupt urb", __func__); result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) { dev_err(&port->dev, "%s - failed submitting interrupt urb," @@ -293,7 +290,9 @@ static int f81232_ioctl(struct tty_struct *tty, { struct serial_struct ser; struct usb_serial_port *port = tty->driver_data; - dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd); + + dev_dbg(&port->dev, "%s (%d) cmd = 0x%04x\n", __func__, + port->number, cmd); switch (cmd) { case TIOCGSERIAL: @@ -309,10 +308,12 @@ static int f81232_ioctl(struct tty_struct *tty, return 0; case TIOCMIWAIT: - dbg("%s (%d) TIOCMIWAIT", __func__, port->number); + dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__, + port->number); return wait_modem_info(port, arg); default: - dbg("%s not supported = 0x%04x", __func__, cmd); + dev_dbg(&port->dev, "%s not supported = 0x%04x\n", + __func__, cmd); break; } return -ENOIOCTLCMD; @@ -353,24 +354,12 @@ static void f81232_release(struct usb_serial *serial) } } -static struct usb_driver f81232_driver = { - .name = "f81232", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .no_dynamic_id = 1, - .supports_autosuspend = 1, -}; - static struct usb_serial_driver f81232_device = { .driver = { .owner = THIS_MODULE, .name = "f81232", }, .id_table = id_table, - .usb_driver = &f81232_driver, .num_ports = 1, .bulk_in_size = 256, .bulk_out_size = 256, @@ -394,7 +383,7 @@ static struct usb_serial_driver * const serial_drivers[] = { NULL, }; -module_usb_serial_driver(f81232_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION("Fintek F81232 USB to serial adaptor driver"); MODULE_AUTHOR("Greg Kroah-Hartman chip_type != SIO) { @@ -1619,8 +1609,6 @@ static void remove_sysfs_attrs(struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); - dbg("%s", __func__); - /* XXX see create_sysfs_attrs */ if (priv->chip_type != SIO) { device_remove_file(&port->dev, &dev_attr_event_char); @@ -1667,8 +1655,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial); - dbg("%s", __func__); - priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL); if (!priv) { dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", __func__, @@ -1704,8 +1690,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) /* Called from usbserial:serial_probe */ static void ftdi_USB_UIRT_setup(struct ftdi_private *priv) { - dbg("%s", __func__); - priv->flags |= ASYNC_SPD_CUST; priv->custom_divisor = 77; priv->force_baud = 38400; @@ -1716,8 +1700,6 @@ static void ftdi_USB_UIRT_setup(struct ftdi_private *priv) static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv) { - dbg("%s", __func__); - priv->flags |= ASYNC_SPD_CUST; priv->custom_divisor = 240; priv->force_baud = 38400; @@ -1767,8 +1749,6 @@ static int ftdi_jtag_probe(struct usb_serial *serial) struct usb_device *udev = serial->dev; struct usb_interface *interface = serial->interface; - dbg("%s", __func__); - if (interface == udev->actconfig->interface[0]) { dev_info(&udev->dev, "Ignoring serial port reserved for JTAG\n"); @@ -1782,8 +1762,6 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial) { struct usb_device *udev = serial->dev; - dbg("%s", __func__); - if ((udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems")) || (udev->product && !strcmp(udev->product, "BeagleBone/XDS100"))) return ftdi_jtag_probe(serial); @@ -1800,8 +1778,6 @@ static int ftdi_stmclite_probe(struct usb_serial *serial) struct usb_device *udev = serial->dev; struct usb_interface *interface = serial->interface; - dbg("%s", __func__); - if (interface == udev->actconfig->interface[2]) return 0; @@ -1839,8 +1815,6 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); - dbg("%s", __func__); - priv->dev_gone = true; wake_up_interruptible_all(&priv->delta_msr_wait); @@ -1858,8 +1832,6 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) struct ftdi_private *priv = usb_get_serial_port_data(port); int result; - dbg("%s", __func__); - /* No error checking for this (will get errors later anyway) */ /* See ftdi_sio.h for description of what is reset */ usb_control_msg(dev, usb_sndctrlpipe(dev, 0), @@ -1918,8 +1890,6 @@ static void ftdi_close(struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); - dbg("%s", __func__); - usb_serial_generic_close(port); kref_put(&priv->kref, ftdi_sio_priv_release); } @@ -1976,8 +1946,6 @@ static int ftdi_process_packet(struct tty_struct *tty, char flag; char *ch; - dbg("%s - port %d", __func__, port->number); - if (len < 2) { dbg("malformed packet"); return 0; @@ -2121,8 +2089,6 @@ static void ftdi_set_termios(struct tty_struct *tty, unsigned char vstop; unsigned char vstart; - dbg("%s", __func__); - /* Force baud rate if this device requires it, unless it is set to B0. */ if (priv->force_baud && ((termios->c_cflag & CBAUD) != B0)) { @@ -2295,8 +2261,6 @@ static int ftdi_tiocmget(struct tty_struct *tty) int len; int ret; - dbg("%s TIOCMGET", __func__); - buf = kmalloc(2, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -2346,7 +2310,7 @@ static int ftdi_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; - dbg("%s TIOCMSET", __func__); + return update_mctrl(port, set, clear); } @@ -2435,7 +2399,6 @@ static int __init ftdi_init(void) { int retval; - dbg("%s", __func__); if (vendor > 0 && product > 0) { /* Add user specified VID/PID to reserved element of table. */ int i; @@ -2445,7 +2408,7 @@ static int __init ftdi_init(void) id_table_combined[i].idVendor = vendor; id_table_combined[i].idProduct = product; } - retval = usb_serial_register_drivers(&ftdi_driver, serial_drivers); + retval = usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, id_table_combined); if (retval == 0) printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" DRIVER_DESC "\n"); @@ -2454,9 +2417,7 @@ static int __init ftdi_init(void) static void __exit ftdi_exit(void) { - dbg("%s", __func__); - - usb_serial_deregister_drivers(&ftdi_driver, serial_drivers); + usb_serial_deregister_drivers(serial_drivers); } diff --git a/trunk/drivers/usb/serial/ftdi_sio_ids.h b/trunk/drivers/usb/serial/ftdi_sio_ids.h index 0838baf892f3..f3c7c78ede33 100644 --- a/trunk/drivers/usb/serial/ftdi_sio_ids.h +++ b/trunk/drivers/usb/serial/ftdi_sio_ids.h @@ -785,6 +785,14 @@ #define RTSYSTEMS_SERIAL_VX7_PID 0x9e52 /* Serial converter for VX-7 Radios using FT232RL */ #define RTSYSTEMS_CT29B_PID 0x9e54 /* CT29B Radio Cable */ + +/* + * Physik Instrumente + * http://www.physikinstrumente.com/en/products/ + */ +#define PI_VID 0x1a72 /* Vendor ID */ +#define PI_E861_PID 0x1008 /* E-861 piezo controller USB connection */ + /* * Bayer Ascensia Contour blood glucose meter USB-converter cable. * http://winglucofacts.com/cables/ diff --git a/trunk/drivers/usb/serial/funsoft.c b/trunk/drivers/usb/serial/funsoft.c index 4577b3607922..235707961ca3 100644 --- a/trunk/drivers/usb/serial/funsoft.c +++ b/trunk/drivers/usb/serial/funsoft.c @@ -24,13 +24,6 @@ static const struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver funsoft_driver = { - .name = "funsoft", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver funsoft_device = { .driver = { .owner = THIS_MODULE, @@ -44,7 +37,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &funsoft_device, NULL }; -module_usb_serial_driver(funsoft_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/usb/serial/garmin_gps.c b/trunk/drivers/usb/serial/garmin_gps.c index e8eb6347bf3a..346c15a51066 100644 --- a/trunk/drivers/usb/serial/garmin_gps.c +++ b/trunk/drivers/usb/serial/garmin_gps.c @@ -216,16 +216,8 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(GARMIN_VENDOR_ID, 3) }, { } /* Terminating entry */ }; - MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver garmin_driver = { - .name = "garmin_gps", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static inline int getLayerId(const __u8 *usbPacket) { @@ -345,8 +337,6 @@ static void pkt_clear(struct garmin_data *garmin_data_p) unsigned long flags; struct garmin_packet *result = NULL; - dbg("%s", __func__); - spin_lock_irqsave(&garmin_data_p->lock, flags); while (!list_empty(&garmin_data_p->pktlist)) { result = (struct garmin_packet *)garmin_data_p->pktlist.next; @@ -939,8 +929,6 @@ static int garmin_open(struct tty_struct *tty, struct usb_serial_port *port) int status = 0; struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&garmin_data_p->lock, flags); garmin_data_p->mode = initial_mode; garmin_data_p->count = 0; @@ -996,8 +984,6 @@ static void garmin_write_bulk_callback(struct urb *urb) struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - dbg("%s - port %d", __func__, port->number); - if (GARMIN_LAYERID_APPL == getLayerId(urb->transfer_buffer)) { if (garmin_data_p->mode == MODE_GARMIN_SERIAL) { @@ -1027,9 +1013,6 @@ static int garmin_write_bulk(struct usb_serial_port *port, unsigned char *buffer; int status; - dbg("%s - port %d, state %d", __func__, port->number, - garmin_data_p->state); - spin_lock_irqsave(&garmin_data_p->lock, flags); garmin_data_p->flags &= ~FLAGS_DROP_DATA; spin_unlock_irqrestore(&garmin_data_p->lock, flags); @@ -1224,8 +1207,6 @@ static void garmin_read_bulk_callback(struct urb *urb) int status = urb->status; int retval; - dbg("%s - port %d", __func__, port->number); - if (!serial) { dbg("%s - bad serial pointer, exiting", __func__); return; @@ -1384,7 +1365,6 @@ static void garmin_throttle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - dbg("%s - port %d", __func__, port->number); /* set flag, data received will be put into a queue for later processing */ spin_lock_irq(&garmin_data_p->lock); @@ -1399,7 +1379,6 @@ static void garmin_unthrottle(struct tty_struct *tty) struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); int status; - dbg("%s - port %d", __func__, port->number); spin_lock_irq(&garmin_data_p->lock); garmin_data_p->flags &= ~FLAGS_THROTTLED; spin_unlock_irq(&garmin_data_p->lock); @@ -1441,8 +1420,6 @@ static int garmin_attach(struct usb_serial *serial) struct usb_serial_port *port = serial->port[0]; struct garmin_data *garmin_data_p = NULL; - dbg("%s", __func__); - garmin_data_p = kzalloc(sizeof(struct garmin_data), GFP_KERNEL); if (garmin_data_p == NULL) { dev_err(&port->dev, "%s - Out of memory\n", __func__); @@ -1471,8 +1448,6 @@ static void garmin_disconnect(struct usb_serial *serial) struct usb_serial_port *port = serial->port[0]; struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - dbg("%s", __func__); - usb_kill_urb(port->interrupt_in_urb); del_timer_sync(&garmin_data_p->timer); } @@ -1483,8 +1458,6 @@ static void garmin_release(struct usb_serial *serial) struct usb_serial_port *port = serial->port[0]; struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - dbg("%s", __func__); - kfree(garmin_data_p); } @@ -1516,7 +1489,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &garmin_device, NULL }; -module_usb_serial_driver(garmin_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/trunk/drivers/usb/serial/generic.c b/trunk/drivers/usb/serial/generic.c index 664deb63807c..105a6d898ca4 100644 --- a/trunk/drivers/usb/serial/generic.c +++ b/trunk/drivers/usb/serial/generic.c @@ -28,9 +28,6 @@ static int debug; #ifdef CONFIG_USB_SERIAL_GENERIC -static int generic_probe(struct usb_interface *interface, - const struct usb_device_id *id); - static __u16 vendor = 0x05f9; static __u16 product = 0xffff; @@ -49,13 +46,6 @@ static const struct usb_device_id generic_serial_ids[] = { {} }; -static struct usb_driver generic_driver = { - .name = "usbserial_generic", - .probe = generic_probe, - .disconnect = usb_serial_disconnect, - .id_table = generic_serial_ids, -}; - /* All of the device info needed for the Generic Serial Converter */ struct usb_serial_driver usb_serial_generic_device = { .driver = { @@ -75,16 +65,6 @@ static struct usb_serial_driver * const serial_drivers[] = { &usb_serial_generic_device, NULL }; -static int generic_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - const struct usb_device_id *id_pattern; - - id_pattern = usb_match_id(interface, generic_device_ids); - if (id_pattern != NULL) - return usb_serial_probe(interface, id); - return -ENODEV; -} #endif int usb_serial_generic_register(int _debug) @@ -99,7 +79,7 @@ int usb_serial_generic_register(int _debug) USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT; /* register our generic driver with ourselves */ - retval = usb_serial_register_drivers(&generic_driver, serial_drivers); + retval = usb_serial_register_drivers(serial_drivers, "usbserial_generic", generic_serial_ids); #endif return retval; } @@ -108,7 +88,7 @@ void usb_serial_generic_deregister(void) { #ifdef CONFIG_USB_SERIAL_GENERIC /* remove our generic driver */ - usb_serial_deregister_drivers(&generic_driver, serial_drivers); + usb_serial_deregister_drivers(serial_drivers); #endif } @@ -117,8 +97,6 @@ int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port int result = 0; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - /* clear the throttle flags */ spin_lock_irqsave(&port->lock, flags); port->throttled = 0; @@ -139,12 +117,9 @@ static void generic_cleanup(struct usb_serial_port *port) unsigned long flags; int i; - dbg("%s - port %d", __func__, port->number); - if (serial->dev) { /* shutdown any bulk transfers that might be going on */ if (port->bulk_out_size) { - usb_kill_urb(port->write_urb); for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) usb_kill_urb(port->write_urbs[i]); @@ -161,7 +136,6 @@ static void generic_cleanup(struct usb_serial_port *port) void usb_serial_generic_close(struct usb_serial_port *port) { - dbg("%s - port %d", __func__, port->number); generic_cleanup(port); } EXPORT_SYMBOL_GPL(usb_serial_generic_close); @@ -249,8 +223,6 @@ int usb_serial_generic_write(struct tty_struct *tty, { int result; - dbg("%s - port %d", __func__, port->number); - /* only do something if we have a bulk out endpoint */ if (!port->bulk_out_size) return -ENODEV; @@ -273,8 +245,6 @@ int usb_serial_generic_write_room(struct tty_struct *tty) unsigned long flags; int room; - dbg("%s - port %d", __func__, port->number); - if (!port->bulk_out_size) return 0; @@ -282,7 +252,7 @@ int usb_serial_generic_write_room(struct tty_struct *tty) room = kfifo_avail(&port->write_fifo); spin_unlock_irqrestore(&port->lock, flags); - dbg("%s - returns %d", __func__, room); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, room); return room; } @@ -292,8 +262,6 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty) unsigned long flags; int chars; - dbg("%s - port %d", __func__, port->number); - if (!port->bulk_out_size) return 0; @@ -301,7 +269,7 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty) chars = kfifo_len(&port->write_fifo) + port->tx_bytes; spin_unlock_irqrestore(&port->lock, flags); - dbg("%s - returns %d", __func__, chars); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars); return chars; } @@ -313,7 +281,8 @@ static int usb_serial_generic_submit_read_urb(struct usb_serial_port *port, if (!test_and_clear_bit(index, &port->read_urbs_free)) return 0; - dbg("%s - port %d, urb %d\n", __func__, port->number, index); + dev_dbg(&port->dev, "%s - port %d, urb %d\n", __func__, + port->number, index); res = usb_submit_urb(port->read_urbs[index], mem_flags); if (res) { @@ -335,8 +304,6 @@ int usb_serial_generic_submit_read_urbs(struct usb_serial_port *port, int res; int i; - dbg("%s - port %d", __func__, port->number); - for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) { res = usb_serial_generic_submit_read_urb(port, i, mem_flags); if (res) @@ -395,10 +362,12 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb) } set_bit(i, &port->read_urbs_free); - dbg("%s - port %d, urb %d, len %d\n", __func__, port->number, i, - urb->actual_length); + dev_dbg(&port->dev, "%s - port %d, urb %d, len %d\n", + __func__, port->number, i, urb->actual_length); + if (urb->status) { - dbg("%s - non-zero urb status: %d\n", __func__, urb->status); + dev_dbg(&port->dev, "%s - non-zero urb status: %d\n", + __func__, urb->status); return; } @@ -424,8 +393,6 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb) int status = urb->status; int i; - dbg("%s - port %d", __func__, port->number); - for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) if (port->write_urbs[i] == urb) break; @@ -436,7 +403,8 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb) spin_unlock_irqrestore(&port->lock, flags); if (status) { - dbg("%s - non-zero urb status: %d", __func__, status); + dev_dbg(&port->dev, "%s - non-zero urb status: %d\n", + __func__, status); spin_lock_irqsave(&port->lock, flags); kfifo_reset_out(&port->write_fifo); @@ -454,8 +422,6 @@ void usb_serial_generic_throttle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - /* Set the throttle request flag. It will be picked up * by usb_serial_generic_read_bulk_callback(). */ spin_lock_irqsave(&port->lock, flags); @@ -469,8 +435,6 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; int was_throttled; - dbg("%s - port %d", __func__, port->number); - /* Clear the throttle flags */ spin_lock_irq(&port->lock); was_throttled = port->throttled; @@ -525,7 +489,8 @@ void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port, { struct tty_port *port = &usb_port->port; - dbg("%s - port %d, status %d", __func__, usb_port->number, status); + dev_dbg(&usb_port->dev, "%s - port %d, status %d\n", __func__, + usb_port->number, status); if (status) wake_up_interruptible(&port->open_wait); @@ -566,8 +531,6 @@ void usb_serial_generic_disconnect(struct usb_serial *serial) { int i; - dbg("%s", __func__); - /* stop reads and writes on all ports */ for (i = 0; i < serial->num_ports; ++i) generic_cleanup(serial->port[i]); @@ -576,5 +539,4 @@ EXPORT_SYMBOL_GPL(usb_serial_generic_disconnect); void usb_serial_generic_release(struct usb_serial *serial) { - dbg("%s", __func__); } diff --git a/trunk/drivers/usb/serial/hp4x.c b/trunk/drivers/usb/serial/hp4x.c index 2563e788c9b3..0bbaf21a9d1e 100644 --- a/trunk/drivers/usb/serial/hp4x.c +++ b/trunk/drivers/usb/serial/hp4x.c @@ -36,13 +36,6 @@ static const struct usb_device_id id_table[] = { MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver hp49gp_driver = { - .name = "hp4X", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver hp49gp_device = { .driver = { .owner = THIS_MODULE, @@ -56,7 +49,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &hp49gp_device, NULL }; -module_usb_serial_driver(hp49gp_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_VERSION(DRIVER_VERSION); diff --git a/trunk/drivers/usb/serial/io_edgeport.c b/trunk/drivers/usb/serial/io_edgeport.c index 323e87235711..e1f5ccd1e8f8 100644 --- a/trunk/drivers/usb/serial/io_edgeport.c +++ b/trunk/drivers/usb/serial/io_edgeport.c @@ -3181,7 +3181,7 @@ static void edge_release(struct usb_serial *serial) kfree(edge_serial); } -module_usb_serial_driver(io_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/trunk/drivers/usb/serial/io_tables.h b/trunk/drivers/usb/serial/io_tables.h index d0e7c9affb6f..350afddb55ba 100644 --- a/trunk/drivers/usb/serial/io_tables.h +++ b/trunk/drivers/usb/serial/io_tables.h @@ -95,13 +95,6 @@ static const struct usb_device_id id_table_combined[] = { MODULE_DEVICE_TABLE(usb, id_table_combined); -static struct usb_driver io_driver = { - .name = "io_edgeport", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; - static struct usb_serial_driver edgeport_2port_device = { .driver = { .owner = THIS_MODULE, diff --git a/trunk/drivers/usb/serial/io_ti.c b/trunk/drivers/usb/serial/io_ti.c index 40a95a7fe383..3936904c6419 100644 --- a/trunk/drivers/usb/serial/io_ti.c +++ b/trunk/drivers/usb/serial/io_ti.c @@ -197,14 +197,6 @@ static const struct usb_device_id id_table_combined[] = { MODULE_DEVICE_TABLE(usb, id_table_combined); -static struct usb_driver io_driver = { - .name = "io_ti", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; - - static unsigned char OperationalMajorVersion; static unsigned char OperationalMinorVersion; static unsigned short OperationalBuildNumber; @@ -547,6 +539,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout, { int baud_rate; struct tty_struct *tty = tty_port_tty_get(&port->port->port); + struct usb_serial *serial = port->port->serial; wait_queue_t wait; unsigned long flags; @@ -561,7 +554,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout, set_current_state(TASK_INTERRUPTIBLE); if (kfifo_len(&port->write_fifo) == 0 || timeout == 0 || signal_pending(current) - || !usb_get_intfdata(port->port->serial->interface)) + || serial->disconnected) /* disconnect */ break; spin_unlock_irqrestore(&port->ep_lock, flags); @@ -578,7 +571,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout, /* wait for data to drain from the device */ timeout += jiffies; while ((long)(jiffies - timeout) < 0 && !signal_pending(current) - && usb_get_intfdata(port->port->serial->interface)) { + && !serial->disconnected) { /* not disconnected */ if (!tx_active(port)) break; @@ -586,7 +579,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout, } /* disconnected */ - if (!usb_get_intfdata(port->port->serial->interface)) + if (serial->disconnected) return; /* wait one more character time, based on baud rate */ @@ -2003,8 +1996,8 @@ static void edge_close(struct usb_serial_port *port) { struct edgeport_serial *edge_serial; struct edgeport_port *edge_port; + struct usb_serial *serial = port->serial; int port_number; - int status; dbg("%s - port %d", __func__, port->number); @@ -2028,12 +2021,18 @@ static void edge_close(struct usb_serial_port *port) * send a close port command to it */ dbg("%s - send umpc_close_port", __func__); port_number = port->number - port->serial->minor; - status = send_cmd(port->serial->dev, + + mutex_lock(&serial->disc_mutex); + if (!serial->disconnected) { + send_cmd(serial->dev, UMPC_CLOSE_PORT, (__u8)(UMPM_UART1_PORT + port_number), 0, NULL, 0); + } + mutex_unlock(&serial->disc_mutex); + mutex_lock(&edge_serial->es_lock); --edge_port->edge_serial->num_ports_open; if (edge_port->edge_serial->num_ports_open <= 0) { @@ -2783,7 +2782,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &edgeport_1port_device, &edgeport_2port_device, NULL }; -module_usb_serial_driver(io_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/trunk/drivers/usb/serial/ipaq.c b/trunk/drivers/usb/serial/ipaq.c index 10c02b8b5664..c85a7eb87d4e 100644 --- a/trunk/drivers/usb/serial/ipaq.c +++ b/trunk/drivers/usb/serial/ipaq.c @@ -33,7 +33,6 @@ #define DRIVER_AUTHOR "Ganesh Varadarajan " #define DRIVER_DESC "USB PocketPC PDA driver" -static __u16 product, vendor; static bool debug; static int connect_retries = KP_RETRIES; static int initial_wait; @@ -45,8 +44,6 @@ static int ipaq_calc_num_ports(struct usb_serial *serial); static int ipaq_startup(struct usb_serial *serial); static struct usb_device_id ipaq_id_table [] = { - /* The first entry is a placeholder for the insmod-specified device */ - { USB_DEVICE(0x049F, 0x0003) }, { USB_DEVICE(0x0104, 0x00BE) }, /* Socket USB Sync */ { USB_DEVICE(0x03F0, 0x1016) }, /* HP USB Sync */ { USB_DEVICE(0x03F0, 0x1116) }, /* HP USB Sync 1611 */ @@ -505,13 +502,6 @@ static struct usb_device_id ipaq_id_table [] = { MODULE_DEVICE_TABLE(usb, ipaq_id_table); -static struct usb_driver ipaq_driver = { - .name = "ipaq", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = ipaq_id_table, -}; - /* All of the device info needed for the Compaq iPAQ */ static struct usb_serial_driver ipaq_device = { @@ -539,8 +529,6 @@ static int ipaq_open(struct tty_struct *tty, int result = 0; int retries = connect_retries; - dbg("%s - port %d", __func__, port->number); - msleep(1000*initial_wait); /* @@ -577,7 +565,7 @@ static int ipaq_calc_num_ports(struct usb_serial *serial) */ int ipaq_num_ports = 1; - dbg("%s - numberofendpoints: %d", __FUNCTION__, + dev_dbg(&serial->dev->dev, "%s - numberofendpoints: %d\n", __func__, (int)serial->interface->cur_altsetting->desc.bNumEndpoints); /* @@ -596,8 +584,6 @@ static int ipaq_calc_num_ports(struct usb_serial *serial) static int ipaq_startup(struct usb_serial *serial) { - dbg("%s", __func__); - /* Some of the devices in ipaq_id_table[] are composite, and we * shouldn't bind to all the interfaces. This test will rule out * some obviously invalid possibilities. @@ -617,36 +603,14 @@ static int ipaq_startup(struct usb_serial *serial) return -ENODEV; } - dbg("%s - iPAQ module configured for %d ports", - __FUNCTION__, serial->num_ports); + dev_dbg(&serial->dev->dev, + "%s - iPAQ module configured for %d ports\n", __func__, + serial->num_ports); return usb_reset_configuration(serial->dev); } -static int __init ipaq_init(void) -{ - int retval; - - if (vendor) { - ipaq_id_table[0].idVendor = vendor; - ipaq_id_table[0].idProduct = product; - } - - retval = usb_serial_register_drivers(&ipaq_driver, serial_drivers); - if (retval == 0) - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - return retval; -} - -static void __exit ipaq_exit(void) -{ - usb_serial_deregister_drivers(&ipaq_driver, serial_drivers); -} - - -module_init(ipaq_init); -module_exit(ipaq_exit); +module_usb_serial_driver(serial_drivers, ipaq_id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); @@ -655,12 +619,6 @@ MODULE_LICENSE("GPL"); module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); -module_param(vendor, ushort, 0); -MODULE_PARM_DESC(vendor, "User specified USB idVendor"); - -module_param(product, ushort, 0); -MODULE_PARM_DESC(product, "User specified USB idProduct"); - module_param(connect_retries, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(connect_retries, "Maximum number of connect retries (one second each)"); diff --git a/trunk/drivers/usb/serial/ipw.c b/trunk/drivers/usb/serial/ipw.c index 76a06406e26a..5811d34b6c6b 100644 --- a/trunk/drivers/usb/serial/ipw.c +++ b/trunk/drivers/usb/serial/ipw.c @@ -132,19 +132,11 @@ enum { #define IPW_WANTS_TO_SEND 0x30 -static const struct usb_device_id usb_ipw_ids[] = { +static const struct usb_device_id id_table[] = { { USB_DEVICE(IPW_VID, IPW_PID) }, { }, }; - -MODULE_DEVICE_TABLE(usb, usb_ipw_ids); - -static struct usb_driver usb_ipw_driver = { - .name = "ipwtty", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = usb_ipw_ids, -}; +MODULE_DEVICE_TABLE(usb, id_table); static bool debug; @@ -155,8 +147,6 @@ static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port) u8 *buf_flow_init; int result; - dbg("%s", __func__); - buf_flow_init = kmemdup(buf_flow_static, 16, GFP_KERNEL); if (!buf_flow_init) return -ENOMEM; @@ -317,7 +307,7 @@ static struct usb_serial_driver ipw_device = { .name = "ipw", }, .description = "IPWireless converter", - .id_table = usb_ipw_ids, + .id_table = id_table, .num_ports = 1, .disconnect = usb_wwan_disconnect, .open = ipw_open, @@ -333,7 +323,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &ipw_device, NULL }; -module_usb_serial_driver(usb_ipw_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); /* Module information */ MODULE_AUTHOR(DRIVER_AUTHOR); diff --git a/trunk/drivers/usb/serial/ir-usb.c b/trunk/drivers/usb/serial/ir-usb.c index 84965cd65c76..fc09414c960f 100644 --- a/trunk/drivers/usb/serial/ir-usb.c +++ b/trunk/drivers/usb/serial/ir-usb.c @@ -77,13 +77,6 @@ static const struct usb_device_id ir_id_table[] = { MODULE_DEVICE_TABLE(usb, ir_id_table); -static struct usb_driver ir_driver = { - .name = "ir-usb", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = ir_id_table, -}; - static struct usb_serial_driver ir_device = { .driver = { .owner = THIS_MODULE, @@ -103,18 +96,21 @@ static struct usb_serial_driver * const serial_drivers[] = { &ir_device, NULL }; -static inline void irda_usb_dump_class_desc(struct usb_irda_cs_descriptor *desc) +static inline void irda_usb_dump_class_desc(struct usb_serial *serial, + struct usb_irda_cs_descriptor *desc) { - dbg("bLength=%x", desc->bLength); - dbg("bDescriptorType=%x", desc->bDescriptorType); - dbg("bcdSpecRevision=%x", __le16_to_cpu(desc->bcdSpecRevision)); - dbg("bmDataSize=%x", desc->bmDataSize); - dbg("bmWindowSize=%x", desc->bmWindowSize); - dbg("bmMinTurnaroundTime=%d", desc->bmMinTurnaroundTime); - dbg("wBaudRate=%x", __le16_to_cpu(desc->wBaudRate)); - dbg("bmAdditionalBOFs=%x", desc->bmAdditionalBOFs); - dbg("bIrdaRateSniff=%x", desc->bIrdaRateSniff); - dbg("bMaxUnicastList=%x", desc->bMaxUnicastList); + struct device *dev = &serial->dev->dev; + + dev_dbg(dev, "bLength=%x\n", desc->bLength); + dev_dbg(dev, "bDescriptorType=%x\n", desc->bDescriptorType); + dev_dbg(dev, "bcdSpecRevision=%x\n", __le16_to_cpu(desc->bcdSpecRevision)); + dev_dbg(dev, "bmDataSize=%x\n", desc->bmDataSize); + dev_dbg(dev, "bmWindowSize=%x\n", desc->bmWindowSize); + dev_dbg(dev, "bmMinTurnaroundTime=%d\n", desc->bmMinTurnaroundTime); + dev_dbg(dev, "wBaudRate=%x\n", __le16_to_cpu(desc->wBaudRate)); + dev_dbg(dev, "bmAdditionalBOFs=%x\n", desc->bmAdditionalBOFs); + dev_dbg(dev, "bIrdaRateSniff=%x\n", desc->bIrdaRateSniff); + dev_dbg(dev, "bMaxUnicastList=%x\n", desc->bMaxUnicastList); } /*------------------------------------------------------------------*/ @@ -130,8 +126,9 @@ static inline void irda_usb_dump_class_desc(struct usb_irda_cs_descriptor *desc) * Based on the same function in drivers/net/irda/irda-usb.c */ static struct usb_irda_cs_descriptor * -irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum) +irda_usb_find_class_desc(struct usb_serial *serial, unsigned int ifnum) { + struct usb_device *dev = serial->dev; struct usb_irda_cs_descriptor *desc; int ret; @@ -144,20 +141,20 @@ irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum) USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, ifnum, desc, sizeof(*desc), 1000); - dbg("%s - ret=%d", __func__, ret); + dev_dbg(&serial->dev->dev, "%s - ret=%d\n", __func__, ret); if (ret < sizeof(*desc)) { - dbg("%s - class descriptor read %s (%d)", - __func__, - (ret < 0) ? "failed" : "too short", - ret); + dev_dbg(&serial->dev->dev, + "%s - class descriptor read %s (%d)\n", __func__, + (ret < 0) ? "failed" : "too short", ret); goto error; } if (desc->bDescriptorType != USB_DT_CS_IRDA) { - dbg("%s - bad class descriptor type", __func__); + dev_dbg(&serial->dev->dev, "%s - bad class descriptor type\n", + __func__); goto error; } - irda_usb_dump_class_desc(desc); + irda_usb_dump_class_desc(serial, desc); return desc; error: @@ -207,14 +204,15 @@ static int ir_startup(struct usb_serial *serial) { struct usb_irda_cs_descriptor *irda_desc; - irda_desc = irda_usb_find_class_desc(serial->dev, 0); + irda_desc = irda_usb_find_class_desc(serial, 0); if (!irda_desc) { dev_err(&serial->dev->dev, "IRDA class descriptor not found, device not bound\n"); return -ENODEV; } - dbg("%s - Baud rates supported:%s%s%s%s%s%s%s%s%s", + dev_dbg(&serial->dev->dev, + "%s - Baud rates supported:%s%s%s%s%s%s%s%s%s\n", __func__, (irda_desc->wBaudRate & USB_IRDA_BR_2400) ? " 2400" : "", (irda_desc->wBaudRate & USB_IRDA_BR_9600) ? " 9600" : "", @@ -264,8 +262,6 @@ static int ir_open(struct tty_struct *tty, struct usb_serial_port *port) { int i; - dbg("%s - port %d", __func__, port->number); - for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) port->write_urbs[i]->transfer_flags = URB_ZERO_PACKET; @@ -322,15 +318,11 @@ static void ir_process_read_urb(struct urb *urb) static void ir_set_termios_callback(struct urb *urb) { - struct usb_serial_port *port = urb->context; - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - kfree(urb->transfer_buffer); - if (status) - dbg("%s - non-zero urb status: %d", __func__, status); + if (urb->status) + dev_dbg(&urb->dev->dev, "%s - non-zero urb status: %d\n", + __func__, urb->status); } static void ir_set_termios(struct tty_struct *tty, @@ -342,8 +334,6 @@ static void ir_set_termios(struct tty_struct *tty, speed_t baud; int ir_baud; - dbg("%s - port %d", __func__, port->number); - baud = tty_get_baud_rate(tty); /* @@ -447,7 +437,7 @@ static int __init ir_init(void) ir_device.bulk_out_size = buffer_size; } - retval = usb_serial_register_drivers(&ir_driver, serial_drivers); + retval = usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, ir_id_table); if (retval == 0) printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" DRIVER_DESC "\n"); @@ -456,7 +446,7 @@ static int __init ir_init(void) static void __exit ir_exit(void) { - usb_serial_deregister_drivers(&ir_driver, serial_drivers); + usb_serial_deregister_drivers(serial_drivers); } diff --git a/trunk/drivers/usb/serial/iuu_phoenix.c b/trunk/drivers/usb/serial/iuu_phoenix.c index f2192d527db0..22b1eb5040b7 100644 --- a/trunk/drivers/usb/serial/iuu_phoenix.c +++ b/trunk/drivers/usb/serial/iuu_phoenix.c @@ -51,13 +51,6 @@ static const struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver iuu_driver = { - .name = "iuu_phoenix", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - /* turbo parameter */ static int boost = 100; static int clockmode = 1; @@ -135,8 +128,6 @@ static void iuu_release(struct usb_serial *serial) if (!port) return; - dbg("%s", __func__); - if (priv) { iuu_free_buf(priv); dbg("%s - I will free all", __func__); @@ -198,8 +189,6 @@ static void iuu_rxcmd(struct urb *urb) int result; int status = urb->status; - dbg("%s - enter", __func__); - if (status) { dbg("%s - status = %d", __func__, status); /* error stop all */ @@ -221,7 +210,6 @@ static int iuu_reset(struct usb_serial_port *port, u8 wt) struct iuu_private *priv = usb_get_serial_port_data(port); int result; char *buf_ptr = port->write_urb->transfer_buffer; - dbg("%s - enter", __func__); /* Prepare the reset sequence */ @@ -255,8 +243,6 @@ static void iuu_update_status_callback(struct urb *urb) u8 *st; int status = urb->status; - dbg("%s - enter", __func__); - if (status) { dbg("%s - status = %d", __func__, status); /* error stop all */ @@ -299,8 +285,6 @@ static int iuu_status(struct usb_serial_port *port) { int result; - dbg("%s - enter", __func__); - memset(port->write_urb->transfer_buffer, IUU_GET_STATE_REGISTER, 1); usb_fill_bulk_urb(port->write_urb, port->serial->dev, usb_sndbulkpipe(port->serial->dev, @@ -318,8 +302,6 @@ static int bulk_immediate(struct usb_serial_port *port, u8 *buf, u8 count) struct usb_serial *serial = port->serial; int actual = 0; - dbg("%s - enter", __func__); - /* send the data out the bulk port */ status = @@ -341,10 +323,7 @@ static int read_immediate(struct usb_serial_port *port, u8 *buf, u8 count) struct usb_serial *serial = port->serial; int actual = 0; - dbg("%s - enter", __func__); - /* send the data out the bulk port */ - status = usb_bulk_msg(serial->dev, usb_rcvbulkpipe(serial->dev, @@ -367,8 +346,6 @@ static int iuu_led(struct usb_serial_port *port, unsigned int R, if (!buf) return -ENOMEM; - dbg("%s - enter", __func__); - buf[0] = IUU_SET_LED; buf[1] = R & 0xFF; buf[2] = (R >> 8) & 0xFF; @@ -460,8 +437,6 @@ static int iuu_clk(struct usb_serial_port *port, int dwFrq) unsigned int P2 = 0; int frq = (int)dwFrq; - dbg("%s - enter", __func__); - if (frq == 0) { priv->buf[Count++] = IUU_UART_WRITE_I2C; priv->buf[Count++] = FrqGenAdr << 1; @@ -590,8 +565,6 @@ static int iuu_uart_flush(struct usb_serial_port *port) u8 rxcmd = IUU_UART_RX; struct iuu_private *priv = usb_get_serial_port_data(port); - dbg("%s - enter", __func__); - if (iuu_led(port, 0xF000, 0, 0, 0xFF) < 0) return -EIO; @@ -630,8 +603,6 @@ static void read_buf_callback(struct urb *urb) struct tty_struct *tty; int status = urb->status; - dbg("%s - status = %d", __func__, status); - if (status) { if (status == -EPROTO) { /* reschedule needed */ @@ -659,7 +630,6 @@ static int iuu_bulk_write(struct usb_serial_port *port) int i; int buf_len; char *buf_ptr = port->write_urb->transfer_buffer; - dbg("%s - enter", __func__); spin_lock_irqsave(&priv->lock, flags); *buf_ptr++ = IUU_UART_ESC; @@ -691,7 +661,6 @@ static int iuu_bulk_write(struct usb_serial_port *port) static int iuu_read_buf(struct usb_serial_port *port, int len) { int result; - dbg("%s - enter", __func__); usb_fill_bulk_urb(port->read_urb, port->serial->dev, usb_rcvbulkpipe(port->serial->dev, @@ -713,8 +682,6 @@ static void iuu_uart_read_callback(struct urb *urb) unsigned char *data = urb->transfer_buffer; priv->poll++; - dbg("%s - enter", __func__); - if (status) { dbg("%s - status = %d", __func__, status); /* error stop all */ @@ -771,7 +738,6 @@ static int iuu_uart_write(struct tty_struct *tty, struct usb_serial_port *port, { struct iuu_private *priv = usb_get_serial_port_data(port); unsigned long flags; - dbg("%s - enter", __func__); if (count > 256) return -ENOMEM; @@ -792,8 +758,6 @@ static void read_rxcmd_callback(struct urb *urb) int result; int status = urb->status; - dbg("%s - status = %d", __func__, status); - if (status) { /* error stop all */ return; @@ -1015,8 +979,6 @@ static void iuu_close(struct usb_serial_port *port) if (!serial) return; - dbg("%s - port %d", __func__, port->number); - iuu_uart_off(port); if (serial->dev) { /* free writebuf */ @@ -1031,7 +993,6 @@ static void iuu_close(struct usb_serial_port *port) static void iuu_init_termios(struct tty_struct *tty) { - dbg("%s - enter", __func__); *(tty->termios) = tty_std_termios; tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600 | TIOCM_CTS | CSTOPB | PARENB; @@ -1188,8 +1149,6 @@ static int iuu_vcc_set(struct usb_serial_port *port, unsigned int vcc) if (!buf) return -ENOMEM; - dbg("%s - enter", __func__); - buf[0] = IUU_SET_VCC; buf[1] = vcc & 0xFF; buf[2] = (vcc >> 8) & 0xFF; @@ -1250,15 +1209,11 @@ static DEVICE_ATTR(vcc_mode, S_IRUSR | S_IWUSR, show_vcc_mode, static int iuu_create_sysfs_attrs(struct usb_serial_port *port) { - dbg("%s", __func__); - return device_create_file(&port->dev, &dev_attr_vcc_mode); } static int iuu_remove_sysfs_attrs(struct usb_serial_port *port) { - dbg("%s", __func__); - device_remove_file(&port->dev, &dev_attr_vcc_mode); return 0; } @@ -1294,7 +1249,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &iuu_device, NULL }; -module_usb_serial_driver(iuu_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR("Alain Degreffe eczema@ecze.com"); diff --git a/trunk/drivers/usb/serial/keyspan.c b/trunk/drivers/usb/serial/keyspan.c index a39ddd1b0dca..a1b99243dac9 100644 --- a/trunk/drivers/usb/serial/keyspan.c +++ b/trunk/drivers/usb/serial/keyspan.c @@ -130,15 +130,13 @@ struct keyspan_port_private { #include "keyspan_usa67msg.h" -module_usb_serial_driver(keyspan_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, keyspan_ids_combined); static void keyspan_break_ctl(struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; struct keyspan_port_private *p_priv; - dbg("%s", __func__); - p_priv = usb_get_serial_port_data(port); if (break_state == -1) @@ -158,8 +156,6 @@ static void keyspan_set_termios(struct tty_struct *tty, const struct keyspan_device_details *d_details; unsigned int cflag; - dbg("%s", __func__); - p_priv = usb_get_serial_port_data(port); d_details = p_priv->device_details; cflag = tty->termios->c_cflag; @@ -306,8 +302,6 @@ static void usa26_indat_callback(struct urb *urb) unsigned char *data = urb->transfer_buffer; int status = urb->status; - dbg("%s", __func__); - endpoint = usb_pipeendpoint(urb->pipe); if (status) { @@ -369,8 +363,6 @@ static void usa2x_outdat_callback(struct urb *urb) static void usa26_inack_callback(struct urb *urb) { - dbg("%s", __func__); - } static void usa26_outcont_callback(struct urb *urb) @@ -452,7 +444,6 @@ exit: ; static void usa26_glocont_callback(struct urb *urb) { - dbg("%s", __func__); } @@ -465,8 +456,6 @@ static void usa28_indat_callback(struct urb *urb) struct keyspan_port_private *p_priv; int status = urb->status; - dbg("%s", __func__); - port = urb->context; p_priv = usb_get_serial_port_data(port); data = urb->transfer_buffer; @@ -505,7 +494,6 @@ static void usa28_indat_callback(struct urb *urb) static void usa28_inack_callback(struct urb *urb) { - dbg("%s", __func__); } static void usa28_outcont_callback(struct urb *urb) @@ -585,7 +573,6 @@ exit: ; static void usa28_glocont_callback(struct urb *urb) { - dbg("%s", __func__); } @@ -596,8 +583,6 @@ static void usa49_glocont_callback(struct urb *urb) struct keyspan_port_private *p_priv; int i; - dbg("%s", __func__); - serial = urb->context; for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; @@ -625,8 +610,6 @@ static void usa49_instat_callback(struct urb *urb) int old_dcd_state; int status = urb->status; - dbg("%s", __func__); - serial = urb->context; if (status) { @@ -679,7 +662,6 @@ exit: ; static void usa49_inack_callback(struct urb *urb) { - dbg("%s", __func__); } static void usa49_indat_callback(struct urb *urb) @@ -691,8 +673,6 @@ static void usa49_indat_callback(struct urb *urb) unsigned char *data = urb->transfer_buffer; int status = urb->status; - dbg("%s", __func__); - endpoint = usb_pipeendpoint(urb->pipe); if (status) { @@ -742,8 +722,6 @@ static void usa49wg_indat_callback(struct urb *urb) unsigned char *data = urb->transfer_buffer; int status = urb->status; - dbg("%s", __func__); - serial = urb->context; if (status) { @@ -806,7 +784,6 @@ static void usa49wg_indat_callback(struct urb *urb) /* not used, usa-49 doesn't have per-port control endpoints */ static void usa49_outcont_callback(struct urb *urb) { - dbg("%s", __func__); } static void usa90_indat_callback(struct urb *urb) @@ -819,8 +796,6 @@ static void usa90_indat_callback(struct urb *urb) unsigned char *data = urb->transfer_buffer; int status = urb->status; - dbg("%s", __func__); - endpoint = usb_pipeendpoint(urb->pipe); if (status) { @@ -957,8 +932,6 @@ static void usa67_instat_callback(struct urb *urb) int old_dcd_state; int status = urb->status; - dbg("%s", __func__); - serial = urb->context; if (status) { @@ -1010,8 +983,6 @@ static void usa67_glocont_callback(struct urb *urb) struct keyspan_port_private *p_priv; int i; - dbg("%s", __func__); - serial = urb->context; for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; @@ -1035,7 +1006,6 @@ static int keyspan_write_room(struct tty_struct *tty) int data_len; struct urb *this_urb; - dbg("%s", __func__); p_priv = usb_get_serial_port_data(port); d_details = p_priv->device_details; @@ -1078,8 +1048,6 @@ static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port) p_priv = usb_get_serial_port_data(port); d_details = p_priv->device_details; - dbg("%s - port%d.", __func__, port->number); - /* Set some sane defaults */ p_priv->rts_state = 1; p_priv->dtr_state = 1; @@ -1165,7 +1133,6 @@ static void keyspan_close(struct usb_serial_port *port) struct keyspan_serial_private *s_priv; struct keyspan_port_private *p_priv; - dbg("%s", __func__); s_priv = usb_get_serial_data(serial); p_priv = usb_get_serial_port_data(port); @@ -1438,8 +1405,6 @@ static void keyspan_setup_urbs(struct usb_serial *serial) struct callbacks *cback; int endp; - dbg("%s", __func__); - s_priv = usb_get_serial_data(serial); d_details = s_priv->device_details; @@ -1853,8 +1818,6 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial, struct urb *this_urb; int device_port, err; - dbg("%s", __func__); - s_priv = usb_get_serial_data(serial); p_priv = usb_get_serial_port_data(port); d_details = s_priv->device_details; @@ -1980,8 +1943,6 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial, struct urb *this_urb; int err, device_port; - dbg("%s", __func__); - s_priv = usb_get_serial_data(serial); p_priv = usb_get_serial_port_data(port); d_details = s_priv->device_details; @@ -2168,8 +2129,6 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial, int err; u8 prescaler; - dbg("%s", __func__); - s_priv = usb_get_serial_data(serial); p_priv = usb_get_serial_port_data(port); d_details = s_priv->device_details; @@ -2300,8 +2259,6 @@ static int keyspan_usa67_send_setup(struct usb_serial *serial, struct urb *this_urb; int err, device_port; - dbg("%s", __func__); - s_priv = usb_get_serial_data(serial); p_priv = usb_get_serial_port_data(port); d_details = s_priv->device_details; @@ -2442,8 +2399,6 @@ static void keyspan_send_setup(struct usb_serial_port *port, int reset_port) struct keyspan_serial_private *s_priv; const struct keyspan_device_details *d_details; - dbg("%s", __func__); - s_priv = usb_get_serial_data(serial); d_details = s_priv->device_details; @@ -2477,8 +2432,6 @@ static int keyspan_startup(struct usb_serial *serial) struct keyspan_port_private *p_priv; const struct keyspan_device_details *d_details; - dbg("%s", __func__); - for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i) if (d_details->product_id == le16_to_cpu(serial->dev->descriptor.idProduct)) @@ -2538,8 +2491,6 @@ static void keyspan_disconnect(struct usb_serial *serial) struct keyspan_serial_private *s_priv; struct keyspan_port_private *p_priv; - dbg("%s", __func__); - s_priv = usb_get_serial_data(serial); /* Stop reading/writing urbs */ @@ -2579,8 +2530,6 @@ static void keyspan_release(struct usb_serial *serial) struct usb_serial_port *port; struct keyspan_serial_private *s_priv; - dbg("%s", __func__); - s_priv = usb_get_serial_data(serial); /* dbg("Freeing serial->private."); */ diff --git a/trunk/drivers/usb/serial/keyspan.h b/trunk/drivers/usb/serial/keyspan.h index 622853c9e384..fe1c5d91692c 100644 --- a/trunk/drivers/usb/serial/keyspan.h +++ b/trunk/drivers/usb/serial/keyspan.h @@ -487,13 +487,6 @@ static const struct usb_device_id keyspan_ids_combined[] = { MODULE_DEVICE_TABLE(usb, keyspan_ids_combined); -static struct usb_driver keyspan_driver = { - .name = "keyspan", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = keyspan_ids_combined, -}; - /* usb_device_id table for the pre-firmware download keyspan devices */ static const struct usb_device_id keyspan_pre_ids[] = { { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) }, diff --git a/trunk/drivers/usb/serial/keyspan_pda.c b/trunk/drivers/usb/serial/keyspan_pda.c index 693bcdfcb3d5..a4ac3cfeffc4 100644 --- a/trunk/drivers/usb/serial/keyspan_pda.c +++ b/trunk/drivers/usb/serial/keyspan_pda.c @@ -86,13 +86,6 @@ static const struct usb_device_id id_table_combined[] = { MODULE_DEVICE_TABLE(usb, id_table_combined); -static struct usb_driver keyspan_pda_driver = { - .name = "keyspan_pda", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; - static const struct usb_device_id id_table_std[] = { { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_ID) }, { } /* Terminating entry */ @@ -131,7 +124,6 @@ static void keyspan_pda_request_unthrottle(struct work_struct *work) struct usb_serial *serial = priv->serial; int result; - dbg(" request_unthrottle"); /* ask the device to tell us when the tx buffer becomes sufficiently empty */ result = usb_control_msg(serial->dev, @@ -226,7 +218,7 @@ static void keyspan_pda_rx_throttle(struct tty_struct *tty) send an XOFF, although it might make sense to foist that off upon the device too. */ struct usb_serial_port *port = tty->driver_data; - dbg("keyspan_pda_rx_throttle port %d", port->number); + usb_kill_urb(port->interrupt_in_urb); } @@ -235,7 +227,7 @@ static void keyspan_pda_rx_unthrottle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; /* just restart the receive interrupt URB */ - dbg("keyspan_pda_rx_unthrottle port %d", port->number); + if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL)) dbg(" usb_submit_urb(read urb) failed"); } @@ -466,7 +458,6 @@ static int keyspan_pda_write(struct tty_struct *tty, select() or poll() too) until we receive that unthrottle interrupt. Block if we can't write anything at all, otherwise write as much as we can. */ - dbg("keyspan_pda_write(%d)", count); if (count == 0) { dbg(" write request of 0 bytes"); return 0; @@ -766,8 +757,6 @@ static int keyspan_pda_startup(struct usb_serial *serial) static void keyspan_pda_release(struct usb_serial *serial) { - dbg("%s", __func__); - kfree(usb_get_serial_port_data(serial->port[0])); } @@ -834,7 +823,7 @@ static struct usb_serial_driver * const serial_drivers[] = { NULL }; -module_usb_serial_driver(keyspan_pda_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/trunk/drivers/usb/serial/kl5kusb105.c b/trunk/drivers/usb/serial/kl5kusb105.c index 10f05407e535..5bed59cd5776 100644 --- a/trunk/drivers/usb/serial/kl5kusb105.c +++ b/trunk/drivers/usb/serial/kl5kusb105.c @@ -86,13 +86,6 @@ static const struct usb_device_id id_table[] = { MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver kl5kusb105d_driver = { - .name = "kl5kusb105d", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver kl5kusb105d_device = { .driver = { .owner = THIS_MODULE, @@ -282,8 +275,6 @@ static void klsi_105_release(struct usb_serial *serial) { int i; - dbg("%s", __func__); - for (i = 0; i < serial->num_ports; ++i) kfree(usb_get_serial_port_data(serial->port[i])); } @@ -298,8 +289,6 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) struct klsi_105_port_settings *cfg; unsigned long flags; - dbg("%s port %d", __func__, port->number); - /* Do a defined restart: * Set up sane default baud rate and send the 'READ_ON' * vendor command. @@ -376,8 +365,6 @@ static void klsi_105_close(struct usb_serial_port *port) { int rc; - dbg("%s port %d", __func__, port->number); - mutex_lock(&port->serial->disc_mutex); if (!port->serial->disconnected) { /* send READ_OFF */ @@ -646,7 +633,6 @@ static int klsi_105_tiocmget(struct tty_struct *tty) unsigned long flags; int rc; unsigned long line_state; - dbg("%s - request, just guessing", __func__); rc = klsi_105_get_line_state(port, &line_state); if (rc < 0) { @@ -668,8 +654,6 @@ static int klsi_105_tiocmset(struct tty_struct *tty, { int retval = -EINVAL; - dbg("%s", __func__); - /* if this ever gets implemented, it should be done something like this: struct usb_serial *serial = port->serial; struct klsi_105_private *priv = usb_get_serial_port_data(port); @@ -692,7 +676,7 @@ static int klsi_105_tiocmset(struct tty_struct *tty, return retval; } -module_usb_serial_driver(kl5kusb105d_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/trunk/drivers/usb/serial/kobil_sct.c b/trunk/drivers/usb/serial/kobil_sct.c index 4a9a75eb9b95..fafeabb64c55 100644 --- a/trunk/drivers/usb/serial/kobil_sct.c +++ b/trunk/drivers/usb/serial/kobil_sct.c @@ -81,18 +81,8 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_KAAN_SIM_PRODUCT_ID) }, { } /* Terminating entry */ }; - - MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver kobil_driver = { - .name = "kobil", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - - static struct usb_serial_driver kobil_device = { .driver = { .owner = THIS_MODULE, @@ -193,7 +183,6 @@ static int kobil_startup(struct usb_serial *serial) static void kobil_release(struct usb_serial *serial) { int i; - dbg("%s - port %d", __func__, serial->port[0]->number); for (i = 0; i < serial->num_ports; ++i) kfree(usb_get_serial_port_data(serial->port[i])); @@ -217,7 +206,6 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) int transfer_buffer_length = 8; int write_urb_transfer_buffer_length = 8; - dbg("%s - port %d", __func__, port->number); priv = usb_get_serial_port_data(port); /* allocate memory for transfer buffer */ @@ -327,8 +315,6 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) static void kobil_close(struct usb_serial_port *port) { - dbg("%s - port %d", __func__, port->number); - /* FIXME: Add rts/dtr methods */ if (port->write_urb) { usb_poison_urb(port->write_urb); @@ -349,8 +335,6 @@ static void kobil_read_int_callback(struct urb *urb) int status = urb->status; /* char *dbg_data; */ - dbg("%s - port %d", __func__, port->number); - if (status) { dbg("%s - port %d Read int status not zero: %d", __func__, port->number, status); @@ -474,7 +458,6 @@ static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port, static int kobil_write_room(struct tty_struct *tty) { - /* dbg("%s - port %d", __func__, port->number); */ /* FIXME */ return 8; } @@ -683,7 +666,7 @@ static int kobil_ioctl(struct tty_struct *tty, } } -module_usb_serial_driver(kobil_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/trunk/drivers/usb/serial/mct_u232.c b/trunk/drivers/usb/serial/mct_u232.c index 6edd26130e25..d0ec1aa52719 100644 --- a/trunk/drivers/usb/serial/mct_u232.c +++ b/trunk/drivers/usb/serial/mct_u232.c @@ -73,22 +73,14 @@ static void mct_u232_unthrottle(struct tty_struct *tty); /* * All of the device info needed for the MCT USB-RS232 converter. */ -static const struct usb_device_id id_table_combined[] = { +static const struct usb_device_id id_table[] = { { USB_DEVICE(MCT_U232_VID, MCT_U232_PID) }, { USB_DEVICE(MCT_U232_VID, MCT_U232_SITECOM_PID) }, { USB_DEVICE(MCT_U232_VID, MCT_U232_DU_H3SP_PID) }, { USB_DEVICE(MCT_U232_BELKIN_F5U109_VID, MCT_U232_BELKIN_F5U109_PID) }, { } /* Terminating entry */ }; - -MODULE_DEVICE_TABLE(usb, id_table_combined); - -static struct usb_driver mct_u232_driver = { - .name = "mct_u232", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; +MODULE_DEVICE_TABLE(usb, id_table); static struct usb_serial_driver mct_u232_device = { .driver = { @@ -96,7 +88,7 @@ static struct usb_serial_driver mct_u232_device = { .name = "mct_u232", }, .description = "MCT U232", - .id_table = id_table_combined, + .id_table = id_table, .num_ports = 1, .open = mct_u232_open, .close = mct_u232_close, @@ -427,8 +419,6 @@ static void mct_u232_release(struct usb_serial *serial) struct mct_u232_private *priv; int i; - dbg("%s", __func__); - for (i = 0; i < serial->num_ports; ++i) { /* My special items, the standard routines free my urbs */ priv = usb_get_serial_port_data(serial->port[i]); @@ -446,8 +436,6 @@ static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port) unsigned char last_lcr; unsigned char last_msr; - dbg("%s port %d", __func__, port->number); - /* Compensate for a hardware bug: although the Sitecom U232-P25 * device reports a maximum output packet size of 32 bytes, * it seems to be able to accept only 16 bytes (and that's what @@ -528,8 +516,6 @@ static void mct_u232_dtr_rts(struct usb_serial_port *port, int on) static void mct_u232_close(struct usb_serial_port *port) { - dbg("%s port %d", __func__, port->number); - if (port->serial->dev) { /* shutdown our urbs */ usb_kill_urb(port->write_urb); @@ -572,7 +558,6 @@ static void mct_u232_read_int_callback(struct urb *urb) return; } - dbg("%s - port %d", __func__, port->number); usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data); @@ -733,8 +718,6 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state) unsigned char lcr; unsigned long flags; - dbg("%sstate=%d", __func__, break_state); - spin_lock_irqsave(&priv->lock, flags); lcr = priv->last_lcr; @@ -753,8 +736,6 @@ static int mct_u232_tiocmget(struct tty_struct *tty) unsigned int control_state; unsigned long flags; - dbg("%s", __func__); - spin_lock_irqsave(&priv->lock, flags); control_state = priv->control_state; spin_unlock_irqrestore(&priv->lock, flags); @@ -771,8 +752,6 @@ static int mct_u232_tiocmset(struct tty_struct *tty, unsigned int control_state; unsigned long flags; - dbg("%s", __func__); - spin_lock_irqsave(&priv->lock, flags); control_state = priv->control_state; @@ -796,8 +775,6 @@ static void mct_u232_throttle(struct tty_struct *tty) struct mct_u232_private *priv = usb_get_serial_port_data(port); unsigned int control_state; - dbg("%s - port %d", __func__, port->number); - spin_lock_irq(&priv->lock); priv->rx_flags |= THROTTLED; if (C_CRTSCTS(tty)) { @@ -816,8 +793,6 @@ static void mct_u232_unthrottle(struct tty_struct *tty) struct mct_u232_private *priv = usb_get_serial_port_data(port); unsigned int control_state; - dbg("%s - port %d", __func__, port->number); - spin_lock_irq(&priv->lock); if ((priv->rx_flags & THROTTLED) && C_CRTSCTS(tty)) { priv->rx_flags &= ~THROTTLED; @@ -906,7 +881,7 @@ static int mct_u232_get_icount(struct tty_struct *tty, return 0; } -module_usb_serial_driver(mct_u232_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/trunk/drivers/usb/serial/metro-usb.c b/trunk/drivers/usb/serial/metro-usb.c index 08d16e8c002d..81423f7361db 100644 --- a/trunk/drivers/usb/serial/metro-usb.c +++ b/trunk/drivers/usb/serial/metro-usb.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include @@ -56,6 +55,47 @@ MODULE_DEVICE_TABLE(usb, id_table); /* Input parameter constants. */ static bool debug; +/* UNI-Directional mode commands for device configure */ +#define UNI_CMD_OPEN 0x80 +#define UNI_CMD_CLOSE 0xFF + +inline int metrousb_is_unidirectional_mode(struct usb_serial_port *port) +{ + __u16 product_id = le16_to_cpu( + port->serial->dev->descriptor.idProduct); + + return product_id == FOCUS_PRODUCT_ID_UNI; +} + +static int metrousb_send_unidirectional_cmd(u8 cmd, struct usb_serial_port *port) +{ + int ret; + int actual_len; + u8 *buffer_cmd = NULL; + + if (!metrousb_is_unidirectional_mode(port)) + return 0; + + buffer_cmd = kzalloc(sizeof(cmd), GFP_KERNEL); + if (!buffer_cmd) + return -ENOMEM; + + *buffer_cmd = cmd; + + ret = usb_interrupt_msg(port->serial->dev, + usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress), + buffer_cmd, sizeof(cmd), + &actual_len, USB_CTRL_SET_TIMEOUT); + + kfree(buffer_cmd); + + if (ret < 0) + return ret; + else if (actual_len != sizeof(cmd)) + return -EIO; + return 0; +} + static void metrousb_read_int_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; @@ -78,12 +118,12 @@ static void metrousb_read_int_callback(struct urb *urb) /* urb has been terminated. */ dev_dbg(&port->dev, "%s - urb shutting down, error code=%d\n", - __func__, result); + __func__, urb->status); return; default: dev_dbg(&port->dev, "%s - non-zero urb received, error code=%d\n", - __func__, result); + __func__, urb->status); goto exit; } @@ -91,7 +131,7 @@ static void metrousb_read_int_callback(struct urb *urb) /* Set the data read from the usb port into the serial port buffer. */ tty = tty_port_tty_get(&port->port); if (!tty) { - dev_dbg(&port->dev, "%s - bad tty pointer - exiting\n", + dev_err(&port->dev, "%s - bad tty pointer - exiting\n", __func__); return; } @@ -121,7 +161,7 @@ static void metrousb_read_int_callback(struct urb *urb) result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); if (result) - dev_dbg(&port->dev, + dev_err(&port->dev, "%s - failed submitting interrupt in urb, error code=%d\n", __func__, result); } @@ -131,11 +171,19 @@ static void metrousb_read_int_callback(struct urb *urb) /* Try to resubmit the urb. */ result = usb_submit_urb(urb, GFP_ATOMIC); if (result) - dev_dbg(&port->dev, + dev_err(&port->dev, "%s - failed submitting interrupt in urb, error code=%d\n", __func__, result); } +static void metrousb_write_int_callback(struct urb *urb) +{ + struct usb_serial_port *port = urb->context; + + dev_warn(&port->dev, "%s not implemented yet.\n", + __func__); +} + static void metrousb_cleanup(struct usb_serial_port *port) { dev_dbg(&port->dev, "%s\n", __func__); @@ -146,6 +194,9 @@ static void metrousb_cleanup(struct usb_serial_port *port) usb_unlink_urb(port->interrupt_in_urb); usb_kill_urb(port->interrupt_in_urb); } + + /* Send deactivate cmd to device */ + metrousb_send_unidirectional_cmd(UNI_CMD_CLOSE, port); } } @@ -160,7 +211,7 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port) /* Make sure the urb is initialized. */ if (!port->interrupt_in_urb) { - dev_dbg(&port->dev, "%s - interrupt urb not initialized\n", + dev_err(&port->dev, "%s - interrupt urb not initialized\n", __func__); return -ENODEV; } @@ -191,12 +242,21 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port) result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) { - dev_dbg(&port->dev, + dev_err(&port->dev, "%s - failed submitting interrupt in urb, error code=%d\n", __func__, result); goto exit; } + /* Send activate cmd to device */ + result = metrousb_send_unidirectional_cmd(UNI_CMD_OPEN, port); + if (result) { + dev_err(&port->dev, + "%s - failed to configure device for port number=%d, error code=%d\n", + __func__, port->number, result); + goto exit; + } + dev_dbg(&port->dev, "%s - port open\n", __func__); exit: return result; @@ -221,7 +281,7 @@ static int metrousb_set_modem_ctrl(struct usb_serial *serial, unsigned int contr METROUSB_SET_REQUEST_TYPE, METROUSB_SET_MODEM_CTRL_REQUEST, control_state, 0, NULL, 0, WDR_TIMEOUT); if (retval < 0) - dev_dbg(&serial->dev->dev, + dev_err(&serial->dev->dev, "%s - set modem ctrl=0x%x failed, error code=%d\n", __func__, mcr, retval); @@ -354,29 +414,23 @@ static void metrousb_unthrottle(struct tty_struct *tty) port->interrupt_in_urb->dev = port->serial->dev; result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); if (result) - dev_dbg(tty->dev, + dev_err(tty->dev, "failed submitting interrupt in urb error code=%d\n", result); } -static struct usb_driver metrousb_driver = { - .name = "metro-usb", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table -}; - static struct usb_serial_driver metrousb_device = { .driver = { .owner = THIS_MODULE, .name = "metro-usb", }, - .description = "Metrologic USB to serial converter.", + .description = "Metrologic USB to Serial", .id_table = id_table, .num_ports = 1, .open = metrousb_open, .close = metrousb_cleanup, .read_int_callback = metrousb_read_int_callback, + .write_int_callback = metrousb_write_int_callback, .attach = metrousb_startup, .release = metrousb_shutdown, .throttle = metrousb_throttle, @@ -390,7 +444,7 @@ static struct usb_serial_driver * const serial_drivers[] = { NULL, }; -module_usb_serial_driver(metrousb_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Philip Nicastro"); diff --git a/trunk/drivers/usb/serial/mos7720.c b/trunk/drivers/usb/serial/mos7720.c index bdce82034122..a07dd3c8cfef 100644 --- a/trunk/drivers/usb/serial/mos7720.c +++ b/trunk/drivers/usb/serial/mos7720.c @@ -79,12 +79,12 @@ static struct usb_serial_driver moschip7720_2port_driver; #define MOSCHIP_DEVICE_ID_7720 0x7720 #define MOSCHIP_DEVICE_ID_7715 0x7715 -static const struct usb_device_id moschip_port_id_table[] = { +static const struct usb_device_id id_table[] = { { USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7720) }, { USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7715) }, { } /* terminating entry */ }; -MODULE_DEVICE_TABLE(usb, moschip_port_id_table); +MODULE_DEVICE_TABLE(usb, id_table); #ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT @@ -257,7 +257,6 @@ static void destroy_mos_parport(struct kref *kref) struct mos7715_parport *mos_parport = container_of(kref, struct mos7715_parport, ref_count); - dbg("%s called", __func__); kfree(mos_parport); } @@ -266,7 +265,7 @@ static void destroy_urbtracker(struct kref *kref) struct urbtracker *urbtrack = container_of(kref, struct urbtracker, ref_count); struct mos7715_parport *mos_parport = urbtrack->mos_parport; - dbg("%s called", __func__); + usb_free_urb(urbtrack->urb); kfree(urbtrack); kref_put(&mos_parport->ref_count, destroy_mos_parport); @@ -285,8 +284,6 @@ static void send_deferred_urbs(unsigned long _mos_parport) struct urbtracker *urbtrack; struct list_head *cursor, *next; - dbg("%s called", __func__); - /* if release function ran, game over */ if (unlikely(mos_parport->serial == NULL)) return; @@ -335,7 +332,7 @@ static void async_complete(struct urb *urb) { struct urbtracker *urbtrack = urb->context; int status = urb->status; - dbg("%s called", __func__); + if (unlikely(status)) dbg("%s - nonzero urb status received: %d", __func__, status); @@ -355,7 +352,6 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport, struct usb_ctrlrequest setup; struct usb_serial *serial = mos_parport->serial; struct usb_device *usbdev = serial->dev; - dbg("%s called", __func__); /* create and initialize the control urb and containing urbtracker */ urbtrack = kmalloc(sizeof(struct urbtracker), GFP_ATOMIC); @@ -476,7 +472,7 @@ static inline void parport_epilogue(struct parport *pp) static void parport_mos7715_write_data(struct parport *pp, unsigned char d) { struct mos7715_parport *mos_parport = pp->private_data; - dbg("%s called: %2.2x", __func__, d); + if (parport_prologue(pp) < 0) return; mos7715_change_mode(mos_parport, SPP); @@ -488,7 +484,7 @@ static unsigned char parport_mos7715_read_data(struct parport *pp) { struct mos7715_parport *mos_parport = pp->private_data; unsigned char d; - dbg("%s called", __func__); + if (parport_prologue(pp) < 0) return 0; read_mos_reg(mos_parport->serial, dummy, DPR, &d); @@ -500,7 +496,7 @@ static void parport_mos7715_write_control(struct parport *pp, unsigned char d) { struct mos7715_parport *mos_parport = pp->private_data; __u8 data; - dbg("%s called: %2.2x", __func__, d); + if (parport_prologue(pp) < 0) return; data = ((__u8)d & 0x0f) | (mos_parport->shadowDCR & 0xf0); @@ -513,7 +509,7 @@ static unsigned char parport_mos7715_read_control(struct parport *pp) { struct mos7715_parport *mos_parport = pp->private_data; __u8 dcr; - dbg("%s called", __func__); + spin_lock(&release_lock); mos_parport = pp->private_data; if (unlikely(mos_parport == NULL)) { @@ -531,7 +527,7 @@ static unsigned char parport_mos7715_frob_control(struct parport *pp, { struct mos7715_parport *mos_parport = pp->private_data; __u8 dcr; - dbg("%s called", __func__); + mask &= 0x0f; val &= 0x0f; if (parport_prologue(pp) < 0) @@ -547,7 +543,7 @@ static unsigned char parport_mos7715_read_status(struct parport *pp) { unsigned char status; struct mos7715_parport *mos_parport = pp->private_data; - dbg("%s called", __func__); + spin_lock(&release_lock); mos_parport = pp->private_data; if (unlikely(mos_parport == NULL)) { /* release called */ @@ -561,17 +557,16 @@ static unsigned char parport_mos7715_read_status(struct parport *pp) static void parport_mos7715_enable_irq(struct parport *pp) { - dbg("%s called", __func__); } + static void parport_mos7715_disable_irq(struct parport *pp) { - dbg("%s called", __func__); } static void parport_mos7715_data_forward(struct parport *pp) { struct mos7715_parport *mos_parport = pp->private_data; - dbg("%s called", __func__); + if (parport_prologue(pp) < 0) return; mos7715_change_mode(mos_parport, PS2); @@ -583,7 +578,7 @@ static void parport_mos7715_data_forward(struct parport *pp) static void parport_mos7715_data_reverse(struct parport *pp) { struct mos7715_parport *mos_parport = pp->private_data; - dbg("%s called", __func__); + if (parport_prologue(pp) < 0) return; mos7715_change_mode(mos_parport, PS2); @@ -595,7 +590,6 @@ static void parport_mos7715_data_reverse(struct parport *pp) static void parport_mos7715_init_state(struct pardevice *dev, struct parport_state *s) { - dbg("%s called", __func__); s->u.pc.ctr = DCR_INIT_VAL; s->u.pc.ecr = ECR_INIT_VAL; } @@ -605,7 +599,7 @@ static void parport_mos7715_save_state(struct parport *pp, struct parport_state *s) { struct mos7715_parport *mos_parport; - dbg("%s called", __func__); + spin_lock(&release_lock); mos_parport = pp->private_data; if (unlikely(mos_parport == NULL)) { /* release called */ @@ -622,7 +616,7 @@ static void parport_mos7715_restore_state(struct parport *pp, struct parport_state *s) { struct mos7715_parport *mos_parport; - dbg("%s called", __func__); + spin_lock(&release_lock); mos_parport = pp->private_data; if (unlikely(mos_parport == NULL)) { /* release called */ @@ -641,7 +635,7 @@ static size_t parport_mos7715_write_compat(struct parport *pp, int retval; struct mos7715_parport *mos_parport = pp->private_data; int actual_len; - dbg("%s called: %u chars", __func__, (unsigned int)len); + if (parport_prologue(pp) < 0) return 0; mos7715_change_mode(mos_parport, PPF); @@ -2164,20 +2158,13 @@ static void mos7720_release(struct usb_serial *serial) kfree(usb_get_serial_port_data(serial->port[i])); } -static struct usb_driver usb_driver = { - .name = "moschip7720", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = moschip_port_id_table, -}; - static struct usb_serial_driver moschip7720_2port_driver = { .driver = { .owner = THIS_MODULE, .name = "moschip7720", }, .description = "Moschip 2 port adapter", - .id_table = moschip_port_id_table, + .id_table = id_table, .calc_num_ports = mos77xx_calc_num_ports, .open = mos7720_open, .close = mos7720_close, @@ -2203,7 +2190,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &moschip7720_2port_driver, NULL }; -module_usb_serial_driver(usb_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/trunk/drivers/usb/serial/mos7840.c b/trunk/drivers/usb/serial/mos7840.c index c526550694a0..29160f8b5101 100644 --- a/trunk/drivers/usb/serial/mos7840.c +++ b/trunk/drivers/usb/serial/mos7840.c @@ -114,10 +114,10 @@ #define USB_VENDOR_ID_MOSCHIP 0x9710 #define MOSCHIP_DEVICE_ID_7840 0x7840 #define MOSCHIP_DEVICE_ID_7820 0x7820 +#define MOSCHIP_DEVICE_ID_7810 0x7810 /* The native component can have its vendor/device id's overridden * in vendor-specific implementations. Such devices can be handled - * by making a change here, in moschip_port_id_table, and in - * moschip_id_table_combined + * by making a change here, in id_table. */ #define USB_VENDOR_ID_BANDB 0x0856 #define BANDB_DEVICE_ID_USO9ML2_2 0xAC22 @@ -184,31 +184,16 @@ #define NUM_URBS 16 /* URB Count */ #define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */ +/* LED on/off milliseconds*/ +#define LED_ON_MS 500 +#define LED_OFF_MS 500 -static const struct usb_device_id moschip_port_id_table[] = { - {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, - {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4P)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_2)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_2)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2P)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4P)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)}, - {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)}, - {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)}, - {} /* terminating entry */ -}; +static int device_type; -static const struct usb_device_id moschip_id_table_combined[] __devinitconst = { +static const struct usb_device_id id_table[] __devinitconst = { {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, + {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7810)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)}, @@ -226,8 +211,7 @@ static const struct usb_device_id moschip_id_table_combined[] __devinitconst = { {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)}, {} /* terminating entry */ }; - -MODULE_DEVICE_TABLE(usb, moschip_id_table_combined); +MODULE_DEVICE_TABLE(usb, id_table); /* This structure holds all of the local port information */ @@ -261,8 +245,13 @@ struct moschip_port { struct urb *write_urb_pool[NUM_URBS]; char busy[NUM_URBS]; bool read_urb_busy; -}; + /* For device(s) with LED indicator */ + bool has_led; + bool led_flag; + struct timer_list led_timer1; /* Timer for LED on */ + struct timer_list led_timer2; /* Timer for LED off */ +}; static bool debug; @@ -572,6 +561,69 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, return ret; } +static void mos7840_set_led_callback(struct urb *urb) +{ + switch (urb->status) { + case 0: + /* Success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* This urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", __func__, + urb->status); + break; + default: + dbg("%s - nonzero urb status received: %d", __func__, + urb->status); + } +} + +static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval, + __u16 reg) +{ + struct usb_device *dev = mcs->port->serial->dev; + struct usb_ctrlrequest *dr = mcs->dr; + + dr->bRequestType = MCS_WR_RTYPE; + dr->bRequest = MCS_WRREQ; + dr->wValue = cpu_to_le16(wval); + dr->wIndex = cpu_to_le16(reg); + dr->wLength = cpu_to_le16(0); + + usb_fill_control_urb(mcs->control_urb, dev, usb_sndctrlpipe(dev, 0), + (unsigned char *)dr, NULL, 0, mos7840_set_led_callback, NULL); + + usb_submit_urb(mcs->control_urb, GFP_ATOMIC); +} + +static void mos7840_set_led_sync(struct usb_serial_port *port, __u16 reg, + __u16 val) +{ + struct usb_device *dev = port->serial->dev; + + usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ, MCS_WR_RTYPE, + val, reg, NULL, 0, MOS_WDR_TIMEOUT); +} + +static void mos7840_led_off(unsigned long arg) +{ + struct moschip_port *mcs = (struct moschip_port *) arg; + + /* Turn off LED */ + mos7840_set_led_async(mcs, 0x0300, MODEM_CONTROL_REGISTER); + mod_timer(&mcs->led_timer2, + jiffies + msecs_to_jiffies(LED_OFF_MS)); +} + +static void mos7840_led_flag_off(unsigned long arg) +{ + struct moschip_port *mcs = (struct moschip_port *) arg; + + mcs->led_flag = false; +} + /***************************************************************************** * mos7840_interrupt_callback * this is the callback function for when we have received data on the @@ -591,8 +643,6 @@ static void mos7840_interrupt_callback(struct urb *urb) __u16 wval, wreg = 0; int status = urb->status; - dbg("%s", " : Entering"); - switch (status) { case 0: /* success */ @@ -766,12 +816,8 @@ static void mos7840_bulk_in_callback(struct urb *urb) return; } - dbg("%s", "Entering... "); - data = urb->transfer_buffer; - dbg("%s", "Entering ..........."); - if (urb->actual_length) { tty = tty_port_tty_get(&mos7840_port->port->port); if (tty) { @@ -792,6 +838,14 @@ static void mos7840_bulk_in_callback(struct urb *urb) return; } + /* Turn on LED */ + if (mos7840_port->has_led && !mos7840_port->led_flag) { + mos7840_port->led_flag = true; + mos7840_set_led_async(mos7840_port, 0x0301, + MODEM_CONTROL_REGISTER); + mod_timer(&mos7840_port->led_timer1, + jiffies + msecs_to_jiffies(LED_ON_MS)); + } mos7840_port->read_urb_busy = true; retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC); @@ -835,8 +889,6 @@ static void mos7840_bulk_out_data_callback(struct urb *urb) return; } - dbg("%s", "Entering ........."); - tty = tty_port_tty_get(&mos7840_port->port->port); if (tty && mos7840_port->open) tty_wakeup(tty); @@ -878,8 +930,6 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) struct moschip_port *mos7840_port; struct moschip_port *port0; - dbg ("%s enter", __func__); - if (mos7840_port_paranoia_check(port, __func__)) { dbg("%s", "Port Paranoia failed"); return -ENODEV; @@ -1151,10 +1201,7 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) dbg("usb_serial serial:%p mos7840_port:%p\n usb_serial_port port:%p", serial, mos7840_port, port); - dbg ("%s leave", __func__); - return 0; - } /***************************************************************************** @@ -1175,18 +1222,14 @@ static int mos7840_chars_in_buffer(struct tty_struct *tty) unsigned long flags; struct moschip_port *mos7840_port; - dbg("%s", " mos7840_chars_in_buffer:entering ..........."); - if (mos7840_port_paranoia_check(port, __func__)) { dbg("%s", "Invalid port"); return 0; } mos7840_port = mos7840_get_port_private(port); - if (mos7840_port == NULL) { - dbg("%s", "mos7840_break:leaving ..........."); + if (mos7840_port == NULL) return 0; - } spin_lock_irqsave(&mos7840_port->pool_lock, flags); for (i = 0; i < NUM_URBS; ++i) @@ -1211,8 +1254,6 @@ static void mos7840_close(struct usb_serial_port *port) int j; __u16 Data; - dbg("%s", "mos7840_close:entering..."); - if (mos7840_port_paranoia_check(port, __func__)) { dbg("%s", "Port Paranoia failed"); return; @@ -1287,8 +1328,6 @@ static void mos7840_close(struct usb_serial_port *port) mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data); mos7840_port->open = 0; - - dbg("%s", "Leaving ............"); } /************************************************************************ @@ -1343,9 +1382,6 @@ static void mos7840_break(struct tty_struct *tty, int break_state) struct usb_serial *serial; struct moschip_port *mos7840_port; - dbg("%s", "Entering ..........."); - dbg("mos7840_break: Start"); - if (mos7840_port_paranoia_check(port, __func__)) { dbg("%s", "Port Paranoia failed"); return; @@ -1395,8 +1431,6 @@ static int mos7840_write_room(struct tty_struct *tty) unsigned long flags; struct moschip_port *mos7840_port; - dbg("%s", " mos7840_write_room:entering ..........."); - if (mos7840_port_paranoia_check(port, __func__)) { dbg("%s", "Invalid port"); dbg("%s", " mos7840_write_room:leaving ..........."); @@ -1445,9 +1479,6 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, /* __u16 Data; */ const unsigned char *current_position = data; unsigned char *data1; - dbg("%s", "entering ..........."); - /* dbg("mos7840_write: mos7840_port->shadowLCR is %x", - mos7840_port->shadowLCR); */ #ifdef NOTMOS7840 Data = 0x00; @@ -1554,6 +1585,14 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, data1 = urb->transfer_buffer; dbg("bulkout endpoint is %d", port->bulk_out_endpointAddress); + /* Turn on LED */ + if (mos7840_port->has_led && !mos7840_port->led_flag) { + mos7840_port->led_flag = true; + mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0301); + mod_timer(&mos7840_port->led_timer1, + jiffies + msecs_to_jiffies(LED_ON_MS)); + } + /* send it down the pipe */ status = usb_submit_urb(urb, GFP_ATOMIC); @@ -1602,8 +1641,6 @@ static void mos7840_throttle(struct tty_struct *tty) return; } - dbg("%s", "Entering .........."); - /* if we are implementing XON/XOFF, send the stop character */ if (I_IXOFF(tty)) { unsigned char stop_char = STOP_CHAR(tty); @@ -1646,8 +1683,6 @@ static void mos7840_unthrottle(struct tty_struct *tty) return; } - dbg("%s", "Entering .........."); - /* if we are implementing XON/XOFF, send the start character */ if (I_IXOFF(tty)) { unsigned char start_char = START_CHAR(tty); @@ -1676,8 +1711,6 @@ static int mos7840_tiocmget(struct tty_struct *tty) int status; mos7840_port = mos7840_get_port_private(port); - dbg("%s - port %d", __func__, port->number); - if (mos7840_port == NULL) return -ENODEV; @@ -1704,8 +1737,6 @@ static int mos7840_tiocmset(struct tty_struct *tty, unsigned int mcr; int status; - dbg("%s - port %d", __func__, port->number); - mos7840_port = mos7840_get_port_private(port); if (mos7840_port == NULL) @@ -1746,7 +1777,6 @@ static int mos7840_tiocmset(struct tty_struct *tty, static int mos7840_calc_baud_rate_divisor(int baudRate, int *divisor, __u16 *clk_sel_val) { - dbg("%s - %d", __func__, baudRate); if (baudRate <= 115200) { @@ -1839,8 +1869,6 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, return -1; } - dbg("%s", "Entering .........."); - number = mos7840_port->port->number - mos7840_port->port->serial->minor; dbg("%s - port = %d, baud = %d", __func__, @@ -1966,8 +1994,6 @@ static void mos7840_change_port_settings(struct tty_struct *tty, return; } - dbg("%s", "Entering .........."); - lData = LCR_BITS_8; lStop = LCR_STOP_1; lParity = LCR_PAR_NONE; @@ -2108,7 +2134,7 @@ static void mos7840_set_termios(struct tty_struct *tty, unsigned int cflag; struct usb_serial *serial; struct moschip_port *mos7840_port; - dbg("mos7840_set_termios: START"); + if (mos7840_port_paranoia_check(port, __func__)) { dbg("%s", "Invalid port"); return; @@ -2327,28 +2353,74 @@ static int mos7840_ioctl(struct tty_struct *tty, return -ENOIOCTLCMD; } +static int mos7810_check(struct usb_serial *serial) +{ + int i, pass_count = 0; + __u16 data = 0, mcr_data = 0; + __u16 test_pattern = 0x55AA; + + /* Store MCR setting */ + usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + MCS_RDREQ, MCS_RD_RTYPE, 0x0300, MODEM_CONTROL_REGISTER, + &mcr_data, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); + + for (i = 0; i < 16; i++) { + /* Send the 1-bit test pattern out to MCS7810 test pin */ + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + MCS_WRREQ, MCS_WR_RTYPE, + (0x0300 | (((test_pattern >> i) & 0x0001) << 1)), + MODEM_CONTROL_REGISTER, NULL, 0, MOS_WDR_TIMEOUT); + + /* Read the test pattern back */ + usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &data, + VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); + + /* If this is a MCS7810 device, both test patterns must match */ + if (((test_pattern >> i) ^ (~data >> 1)) & 0x0001) + break; + + pass_count++; + } + + /* Restore MCR setting */ + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), MCS_WRREQ, + MCS_WR_RTYPE, 0x0300 | mcr_data, MODEM_CONTROL_REGISTER, NULL, + 0, MOS_WDR_TIMEOUT); + + if (pass_count == 16) + return 1; + + return 0; +} + static int mos7840_calc_num_ports(struct usb_serial *serial) { - __u16 Data = 0x00; - int ret = 0; + __u16 data = 0x00; int mos7840_num_ports; - ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &Data, + usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &data, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); - if ((Data & 0x01) == 0) { - mos7840_num_ports = 2; - serial->num_bulk_in = 2; - serial->num_bulk_out = 2; - serial->num_ports = 2; + if (serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7810 || + serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7820) { + device_type = serial->dev->descriptor.idProduct; } else { - mos7840_num_ports = 4; - serial->num_bulk_in = 4; - serial->num_bulk_out = 4; - serial->num_ports = 4; + /* For a MCS7840 device GPIO0 must be set to 1 */ + if ((data & 0x01) == 1) + device_type = MOSCHIP_DEVICE_ID_7840; + else if (mos7810_check(serial)) + device_type = MOSCHIP_DEVICE_ID_7810; + else + device_type = MOSCHIP_DEVICE_ID_7820; } + mos7840_num_ports = (device_type >> 4) & 0x000F; + serial->num_bulk_in = mos7840_num_ports; + serial->num_bulk_out = mos7840_num_ports; + serial->num_ports = mos7840_num_ports; + return mos7840_num_ports; } @@ -2361,9 +2433,7 @@ static int mos7840_startup(struct usb_serial *serial) struct moschip_port *mos7840_port; struct usb_device *dev; int i, status; - __u16 Data; - dbg("%s", "mos7840_startup :Entering.........."); if (!serial) { dbg("%s", "Invalid Handler"); @@ -2372,9 +2442,6 @@ static int mos7840_startup(struct usb_serial *serial) dev = serial->dev; - dbg("%s", "Entering..."); - dbg ("mos7840_startup: serial = %p", serial); - /* we set up the pointers to the endpoints in the mos7840_open * * function, as the structures aren't created yet. */ @@ -2563,6 +2630,34 @@ static int mos7840_startup(struct usb_serial *serial) status = -ENOMEM; goto error; } + + mos7840_port->has_led = false; + + /* Initialize LED timers */ + if (device_type == MOSCHIP_DEVICE_ID_7810) { + mos7840_port->has_led = true; + + init_timer(&mos7840_port->led_timer1); + mos7840_port->led_timer1.function = mos7840_led_off; + mos7840_port->led_timer1.expires = + jiffies + msecs_to_jiffies(LED_ON_MS); + mos7840_port->led_timer1.data = + (unsigned long)mos7840_port; + + init_timer(&mos7840_port->led_timer2); + mos7840_port->led_timer2.function = + mos7840_led_flag_off; + mos7840_port->led_timer2.expires = + jiffies + msecs_to_jiffies(LED_OFF_MS); + mos7840_port->led_timer2.data = + (unsigned long)mos7840_port; + + mos7840_port->led_flag = false; + + /* Turn off LED */ + mos7840_set_led_sync(serial->port[i], + MODEM_CONTROL_REGISTER, 0x0300); + } } dbg ("mos7840_startup: all ports configured..........."); @@ -2602,7 +2697,6 @@ static void mos7840_disconnect(struct usb_serial *serial) int i; unsigned long flags; struct moschip_port *mos7840_port; - dbg("%s", " disconnect :entering.........."); if (!serial) { dbg("%s", "Invalid Handler"); @@ -2624,9 +2718,6 @@ static void mos7840_disconnect(struct usb_serial *serial) usb_kill_urb(mos7840_port->control_urb); } } - - dbg("%s", "Thank u :: "); - } /**************************************************************************** @@ -2638,7 +2729,6 @@ static void mos7840_release(struct usb_serial *serial) { int i; struct moschip_port *mos7840_port; - dbg("%s", " release :entering.........."); if (!serial) { dbg("%s", "Invalid Handler"); @@ -2654,30 +2744,28 @@ static void mos7840_release(struct usb_serial *serial) mos7840_port = mos7840_get_port_private(serial->port[i]); dbg("mos7840_port %d = %p", i, mos7840_port); if (mos7840_port) { + if (mos7840_port->has_led) { + /* Turn off LED */ + mos7840_set_led_sync(mos7840_port->port, + MODEM_CONTROL_REGISTER, 0x0300); + + del_timer_sync(&mos7840_port->led_timer1); + del_timer_sync(&mos7840_port->led_timer2); + } kfree(mos7840_port->ctrl_buf); kfree(mos7840_port->dr); kfree(mos7840_port); } } - - dbg("%s", "Thank u :: "); - } -static struct usb_driver io_driver = { - .name = "mos7840", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = moschip_id_table_combined, -}; - static struct usb_serial_driver moschip7840_4port_device = { .driver = { .owner = THIS_MODULE, .name = "mos7840", }, .description = DRIVER_DESC, - .id_table = moschip_port_id_table, + .id_table = id_table, .num_ports = 4, .open = mos7840_open, .close = mos7840_close, @@ -2707,7 +2795,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &moschip7840_4port_device, NULL }; -module_usb_serial_driver(io_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/usb/serial/moto_modem.c b/trunk/drivers/usb/serial/moto_modem.c index 3ab6214b4bbf..c5ff6c7795a6 100644 --- a/trunk/drivers/usb/serial/moto_modem.c +++ b/trunk/drivers/usb/serial/moto_modem.c @@ -31,13 +31,6 @@ static const struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver moto_driver = { - .name = "moto-modem", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver moto_device = { .driver = { .owner = THIS_MODULE, @@ -51,5 +44,5 @@ static struct usb_serial_driver * const serial_drivers[] = { &moto_device, NULL }; -module_usb_serial_driver(moto_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/usb/serial/navman.c b/trunk/drivers/usb/serial/navman.c index 29ab6eb5b536..d95452cc076d 100644 --- a/trunk/drivers/usb/serial/navman.c +++ b/trunk/drivers/usb/serial/navman.c @@ -30,13 +30,6 @@ static const struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver navman_driver = { - .name = "navman", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static void navman_read_int_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; @@ -53,12 +46,12 @@ static void navman_read_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", - __func__, status); + dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", + __func__, status); goto exit; } @@ -84,10 +77,9 @@ static int navman_open(struct tty_struct *tty, struct usb_serial_port *port) { int result = 0; - dbg("%s - port %d", __func__, port->number); - if (port->interrupt_in_urb) { - dbg("%s - adding interrupt input for treo", __func__); + dev_dbg(&port->dev, "%s - adding interrupt input for treo\n", + __func__); result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) dev_err(&port->dev, @@ -99,16 +91,12 @@ static int navman_open(struct tty_struct *tty, struct usb_serial_port *port) static void navman_close(struct usb_serial_port *port) { - dbg("%s - port %d", __func__, port->number); - usb_kill_urb(port->interrupt_in_urb); } static int navman_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count) { - dbg("%s - port %d", __func__, port->number); - /* * This device can't write any data, only read from the device */ @@ -132,7 +120,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &navman_device, NULL }; -module_usb_serial_driver(navman_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/usb/serial/omninet.c b/trunk/drivers/usb/serial/omninet.c index 88dc785bb298..6f3d7051c7f4 100644 --- a/trunk/drivers/usb/serial/omninet.c +++ b/trunk/drivers/usb/serial/omninet.c @@ -54,17 +54,8 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(ZYXEL_VENDOR_ID, BT_IGNITIONPRO_ID) }, { } /* Terminating entry */ }; - MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver omninet_driver = { - .name = "omninet", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - - static struct usb_serial_driver zyxel_omninet_device = { .driver = { .owner = THIS_MODULE, @@ -144,8 +135,6 @@ static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port) struct usb_serial_port *wport; int result = 0; - dbg("%s - port %d", __func__, port->number); - wport = serial->port[1]; tty_port_tty_set(&wport->port, tty); @@ -160,7 +149,6 @@ static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port) static void omninet_close(struct usb_serial_port *port) { - dbg("%s - port %d", __func__, port->number); usb_kill_urb(port->read_urb); } @@ -178,8 +166,6 @@ static void omninet_read_bulk_callback(struct urb *urb) int result; int i; - dbg("%s - port %d", __func__, port->number); - if (status) { dbg("%s - nonzero read bulk status received: %d", __func__, status); @@ -225,8 +211,6 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, int result; - dbg("%s - port %d", __func__, port->number); - if (count == 0) { dbg("%s - write request of 0 bytes", __func__); return 0; @@ -289,8 +273,6 @@ static void omninet_write_bulk_callback(struct urb *urb) struct usb_serial_port *port = urb->context; int status = urb->status; - dbg("%s - port %0x", __func__, port->number); - set_bit(0, &port->write_urbs_free); if (status) { dbg("%s - nonzero write bulk status received: %d", @@ -306,8 +288,6 @@ static void omninet_disconnect(struct usb_serial *serial) { struct usb_serial_port *wport = serial->port[1]; - dbg("%s", __func__); - usb_kill_urb(wport->write_urb); } @@ -316,12 +296,10 @@ static void omninet_release(struct usb_serial *serial) { struct usb_serial_port *port = serial->port[0]; - dbg("%s", __func__); - kfree(usb_get_serial_port_data(port)); } -module_usb_serial_driver(omninet_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/trunk/drivers/usb/serial/opticon.c b/trunk/drivers/usb/serial/opticon.c index 82cc9d202b83..02cb1b7f6559 100644 --- a/trunk/drivers/usb/serial/opticon.c +++ b/trunk/drivers/usb/serial/opticon.c @@ -70,8 +70,6 @@ static void opticon_read_bulk_callback(struct urb *urb) int data_length; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - switch (status) { case 0: /* success */ @@ -179,8 +177,6 @@ static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port) unsigned long flags; int result = 0; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); priv->throttled = false; priv->actually_throttled = false; @@ -216,8 +212,6 @@ static void opticon_close(struct usb_serial_port *port) { struct opticon_private *priv = usb_get_serial_data(port->serial); - dbg("%s - port %d", __func__, port->number); - /* shutdown our urbs */ usb_kill_urb(priv->bulk_read_urb); } @@ -256,8 +250,6 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port, int status; struct usb_ctrlrequest *dr; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); if (priv->outstanding_urbs > URB_UPPER_LIMIT) { spin_unlock_irqrestore(&priv->lock, flags); @@ -338,8 +330,6 @@ static int opticon_write_room(struct tty_struct *tty) struct opticon_private *priv = usb_get_serial_data(port->serial); unsigned long flags; - dbg("%s - port %d", __func__, port->number); - /* * We really can take almost anything the user throws at us * but let's pick a nice big number to tell the tty @@ -362,7 +352,6 @@ static void opticon_throttle(struct tty_struct *tty) struct opticon_private *priv = usb_get_serial_data(port->serial); unsigned long flags; - dbg("%s - port %d", __func__, port->number); spin_lock_irqsave(&priv->lock, flags); priv->throttled = true; spin_unlock_irqrestore(&priv->lock, flags); @@ -376,8 +365,6 @@ static void opticon_unthrottle(struct tty_struct *tty) unsigned long flags; int result, was_throttled; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); priv->throttled = false; was_throttled = priv->actually_throttled; @@ -400,10 +387,6 @@ static int opticon_tiocmget(struct tty_struct *tty) unsigned long flags; int result = 0; - dbg("%s - port %d", __func__, port->number); - if (!usb_get_intfdata(port->serial->interface)) - return -ENODEV; - spin_lock_irqsave(&priv->lock, flags); if (priv->rts) result |= TIOCM_RTS; @@ -419,13 +402,13 @@ static int opticon_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; + struct usb_serial *serial = port->serial; struct opticon_private *priv = usb_get_serial_data(port->serial); unsigned long flags; bool rts; bool changed = false; + int ret; - if (!usb_get_intfdata(port->serial->interface)) - return -ENODEV; /* We only support RTS so we only handle that */ spin_lock_irqsave(&priv->lock, flags); @@ -441,7 +424,14 @@ static int opticon_tiocmset(struct tty_struct *tty, return 0; /* Send the new RTS state to the connected device */ - return send_control_msg(port, CONTROL_RTS, !rts); + mutex_lock(&serial->disc_mutex); + if (!serial->disconnected) + ret = send_control_msg(port, CONTROL_RTS, !rts); + else + ret = -ENODEV; + mutex_unlock(&serial->disc_mutex); + + return ret; } static int get_serial_info(struct opticon_private *priv, @@ -555,8 +545,6 @@ static void opticon_disconnect(struct usb_serial *serial) { struct opticon_private *priv = usb_get_serial_data(serial); - dbg("%s", __func__); - usb_kill_urb(priv->bulk_read_urb); usb_free_urb(priv->bulk_read_urb); } @@ -565,24 +553,20 @@ static void opticon_release(struct usb_serial *serial) { struct opticon_private *priv = usb_get_serial_data(serial); - dbg("%s", __func__); - kfree(priv->bulk_in_buffer); kfree(priv); } -static int opticon_suspend(struct usb_interface *intf, pm_message_t message) +static int opticon_suspend(struct usb_serial *serial, pm_message_t message) { - struct usb_serial *serial = usb_get_intfdata(intf); struct opticon_private *priv = usb_get_serial_data(serial); usb_kill_urb(priv->bulk_read_urb); return 0; } -static int opticon_resume(struct usb_interface *intf) +static int opticon_resume(struct usb_serial *serial) { - struct usb_serial *serial = usb_get_intfdata(intf); struct opticon_private *priv = usb_get_serial_data(serial); struct usb_serial_port *port = serial->port[0]; int result; @@ -597,15 +581,6 @@ static int opticon_resume(struct usb_interface *intf) return result; } -static struct usb_driver opticon_driver = { - .name = "opticon", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .suspend = opticon_suspend, - .resume = opticon_resume, - .id_table = id_table, -}; - static struct usb_serial_driver opticon_device = { .driver = { .owner = THIS_MODULE, @@ -625,13 +600,15 @@ static struct usb_serial_driver opticon_device = { .ioctl = opticon_ioctl, .tiocmget = opticon_tiocmget, .tiocmset = opticon_tiocmset, + .suspend = opticon_suspend, + .resume = opticon_resume, }; static struct usb_serial_driver * const serial_drivers[] = { &opticon_device, NULL }; -module_usb_serial_driver(opticon_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/usb/serial/option.c b/trunk/drivers/usb/serial/option.c index f4465ccddc35..1aae9028cd0b 100644 --- a/trunk/drivers/usb/serial/option.c +++ b/trunk/drivers/usb/serial/option.c @@ -1220,18 +1220,6 @@ static const struct usb_device_id option_ids[] = { }; MODULE_DEVICE_TABLE(usb, option_ids); -static struct usb_driver option_driver = { - .name = "option", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, -#ifdef CONFIG_PM - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .supports_autosuspend = 1, -#endif - .id_table = option_ids, -}; - /* The card has three separate interfaces, which the serial driver * recognizes separately, thus num_port=1. */ @@ -1300,7 +1288,7 @@ struct option_port_private { unsigned long tx_start_time[N_OUT_URB]; }; -module_usb_serial_driver(option_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, option_ids); static bool is_blacklisted(const u8 ifnum, enum option_blacklist_reason reason, const struct option_blacklist_info *blacklist) @@ -1375,7 +1363,6 @@ static void option_instat_callback(struct urb *urb) struct usb_serial_port *port = urb->context; struct option_port_private *portdata = usb_get_serial_port_data(port); - dbg("%s", __func__); dbg("%s: urb %p port %p has data %p", __func__, urb, port, portdata); if (status == 0) { @@ -1413,7 +1400,7 @@ static void option_instat_callback(struct urb *urb) req_pkt->bRequestType, req_pkt->bRequest); } } else - err("%s: error %d", __func__, status); + dev_err(&port->dev, "%s: error %d\n", __func__, status); /* Resubmit urb so we continue receiving IRQ data */ if (status != -ESHUTDOWN && status != -ENOENT) { @@ -1437,7 +1424,6 @@ static int option_send_setup(struct usb_serial_port *port) struct option_port_private *portdata; int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber; int val = 0; - dbg("%s", __func__); if (is_blacklisted(ifNum, OPTION_BLACKLIST_SENDSETUP, (struct option_blacklist_info *) intfdata->private)) { diff --git a/trunk/drivers/usb/serial/oti6858.c b/trunk/drivers/usb/serial/oti6858.c index 5fdc33c6a3c0..5976b65ab6ee 100644 --- a/trunk/drivers/usb/serial/oti6858.c +++ b/trunk/drivers/usb/serial/oti6858.c @@ -66,13 +66,6 @@ static const struct usb_device_id id_table[] = { MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver oti6858_driver = { - .name = "oti6858", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static bool debug; /* requests */ @@ -211,8 +204,6 @@ static void setup_line(struct work_struct *work) unsigned long flags; int result; - dbg("%s(port = %d)", __func__, port->number); - new_setup = kmalloc(OTI6858_CTRL_PKT_SIZE, GFP_KERNEL); if (new_setup == NULL) { dev_err(&port->dev, "%s(): out of memory!\n", __func__); @@ -282,8 +273,6 @@ static void send_data(struct work_struct *work) unsigned long flags; u8 *allow; - dbg("%s(port = %d)", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); if (priv->flags.write_urb_in_use) { spin_unlock_irqrestore(&priv->lock, flags); @@ -379,8 +368,6 @@ static int oti6858_startup(struct usb_serial *serial) static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count) { - dbg("%s(port = %d, count = %d)", __func__, port->number, count); - if (!count) return count; @@ -395,8 +382,6 @@ static int oti6858_write_room(struct tty_struct *tty) int room = 0; unsigned long flags; - dbg("%s(port = %d)", __func__, port->number); - spin_lock_irqsave(&port->lock, flags); room = kfifo_avail(&port->write_fifo); spin_unlock_irqrestore(&port->lock, flags); @@ -410,8 +395,6 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty) int chars = 0; unsigned long flags; - dbg("%s(port = %d)", __func__, port->number); - spin_lock_irqsave(&port->lock, flags); chars = kfifo_len(&port->write_fifo); spin_unlock_irqrestore(&port->lock, flags); @@ -437,8 +420,6 @@ static void oti6858_set_termios(struct tty_struct *tty, __le16 divisor; int br; - dbg("%s(port = %d)", __func__, port->number); - if (!tty) { dbg("%s(): no tty structures", __func__); return; @@ -545,8 +526,6 @@ static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port) unsigned long flags; int result; - dbg("%s(port = %d)", __func__, port->number); - usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); @@ -602,8 +581,6 @@ static void oti6858_close(struct usb_serial_port *port) struct oti6858_private *priv = usb_get_serial_port_data(port); unsigned long flags; - dbg("%s(port = %d)", __func__, port->number); - spin_lock_irqsave(&port->lock, flags); /* clear out any remaining data in the buffer */ kfifo_reset_out(&port->write_fifo); @@ -633,9 +610,6 @@ static int oti6858_tiocmset(struct tty_struct *tty, dbg("%s(port = %d, set = 0x%08x, clear = 0x%08x)", __func__, port->number, set, clear); - if (!usb_get_intfdata(port->serial->interface)) - return -ENODEV; - /* FIXME: check if this is correct (active high/low) */ spin_lock_irqsave(&priv->lock, flags); control = priv->pending_setup.control; @@ -663,11 +637,6 @@ static int oti6858_tiocmget(struct tty_struct *tty) unsigned pin_state; unsigned result = 0; - dbg("%s(port = %d)", __func__, port->number); - - if (!usb_get_intfdata(port->serial->interface)) - return -ENODEV; - spin_lock_irqsave(&priv->lock, flags); pin_state = priv->status.pin_state & PIN_MASK; spin_unlock_irqrestore(&priv->lock, flags); @@ -750,8 +719,6 @@ static void oti6858_release(struct usb_serial *serial) { int i; - dbg("%s()", __func__); - for (i = 0; i < serial->num_ports; ++i) kfree(usb_get_serial_port_data(serial->port[i])); } @@ -763,9 +730,6 @@ static void oti6858_read_int_callback(struct urb *urb) int transient = 0, can_recv = 0, resubmit = 1; int status = urb->status; - dbg("%s(port = %d, status = %d)", - __func__, port->number, status); - switch (status) { case 0: /* success */ @@ -882,9 +846,6 @@ static void oti6858_read_bulk_callback(struct urb *urb) int status = urb->status; int result; - dbg("%s(port = %d, status = %d)", - __func__, port->number, status); - spin_lock_irqsave(&priv->lock, flags); priv->flags.read_urb_in_use = 0; spin_unlock_irqrestore(&priv->lock, flags); @@ -916,9 +877,6 @@ static void oti6858_write_bulk_callback(struct urb *urb) int status = urb->status; int result; - dbg("%s(port = %d, status = %d)", - __func__, port->number, status); - switch (status) { case 0: /* success */ @@ -958,7 +916,7 @@ static void oti6858_write_bulk_callback(struct urb *urb) } } -module_usb_serial_driver(oti6858_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(OTI6858_DESCRIPTION); MODULE_AUTHOR(OTI6858_AUTHOR); diff --git a/trunk/drivers/usb/serial/pl2303.c b/trunk/drivers/usb/serial/pl2303.c index a1a9062954c4..13b8dd6481f5 100644 --- a/trunk/drivers/usb/serial/pl2303.c +++ b/trunk/drivers/usb/serial/pl2303.c @@ -38,8 +38,6 @@ static bool debug; -#define PL2303_CLOSING_WAIT (30*HZ) - static const struct usb_device_id id_table[] = { { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) }, @@ -97,16 +95,6 @@ static const struct usb_device_id id_table[] = { MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver pl2303_driver = { - .name = "pl2303", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .supports_autosuspend = 1, -}; - #define SET_LINE_REQUEST_TYPE 0x21 #define SET_LINE_REQUEST 0x20 @@ -161,8 +149,9 @@ static int pl2303_vendor_read(__u16 value, __u16 index, int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE, value, index, buf, 1, 100); - dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE, - VENDOR_READ_REQUEST, value, index, res, buf[0]); + dev_dbg(&serial->dev->dev, "0x%x:0x%x:0x%x:0x%x %d - %x\n", + VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, value, index, + res, buf[0]); return res; } @@ -172,8 +161,9 @@ static int pl2303_vendor_write(__u16 value, __u16 index, int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE, value, index, NULL, 0, 100); - dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE, - VENDOR_WRITE_REQUEST, value, index, res); + dev_dbg(&serial->dev->dev, "0x%x:0x%x:0x%x:0x%x %d\n", + VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, value, index, + res); return res; } @@ -196,7 +186,7 @@ static int pl2303_startup(struct usb_serial *serial) type = type_1; else if (serial->dev->descriptor.bDeviceClass == 0xFF) type = type_1; - dbg("device type: %d", type); + dev_dbg(&serial->interface->dev, "device type: %d\n", type); for (i = 0; i < serial->num_ports; ++i) { priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL); @@ -243,7 +233,8 @@ static int set_control_lines(struct usb_device *dev, u8 value) retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE, value, 0, NULL, 0, 100); - dbg("%s - value = %d, retval = %d", __func__, value, retval); + dev_dbg(&dev->dev, "%s - value = %d, retval = %d\n", __func__, + value, retval); return retval; } @@ -265,8 +256,6 @@ static void pl2303_set_termios(struct tty_struct *tty, int baud_floor, baud_ceil; int k; - dbg("%s - port %d", __func__, port->number); - /* The PL2303 is reported to lose bytes if you change serial settings even to the same values as before. Thus we actually need to filter in this specific case */ @@ -287,7 +276,7 @@ static void pl2303_set_termios(struct tty_struct *tty, i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, 0, 0, buf, 7, 100); - dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i, + dev_dbg(&port->dev, "0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x\n", i, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); if (cflag & CSIZE) { @@ -306,7 +295,7 @@ static void pl2303_set_termios(struct tty_struct *tty, buf[6] = 8; break; } - dbg("%s - data bits = %d", __func__, buf[6]); + dev_dbg(&port->dev, "data bits = %d\n", buf[6]); } /* For reference buf[0]:buf[3] baud rate value */ @@ -315,7 +304,7 @@ static void pl2303_set_termios(struct tty_struct *tty, * 9600 baud (at least my PL2303X always does) */ baud = tty_get_baud_rate(tty); - dbg("%s - baud requested = %d", __func__, baud); + dev_dbg(&port->dev, "baud requested = %d\n", baud); if (baud) { /* Set baudrate to nearest supported value */ for (k=0; k 6000000) baud = 6000000; } - dbg("%s - baud set = %d", __func__, baud); + dev_dbg(&port->dev, "baud set = %d\n", baud); if (baud <= 115200) { buf[0] = baud & 0xff; buf[1] = (baud >> 8) & 0xff; @@ -372,14 +361,14 @@ static void pl2303_set_termios(struct tty_struct *tty, */ if ((cflag & CSIZE) == CS5) { buf[4] = 1; - dbg("%s - stop bits = 1.5", __func__); + dev_dbg(&port->dev, "stop bits = 1.5\n"); } else { buf[4] = 2; - dbg("%s - stop bits = 2", __func__); + dev_dbg(&port->dev, "stop bits = 2\n"); } } else { buf[4] = 0; - dbg("%s - stop bits = 1", __func__); + dev_dbg(&port->dev, "stop bits = 1\n"); } if (cflag & PARENB) { @@ -391,29 +380,29 @@ static void pl2303_set_termios(struct tty_struct *tty, if (cflag & PARODD) { if (cflag & CMSPAR) { buf[5] = 3; - dbg("%s - parity = mark", __func__); + dev_dbg(&port->dev, "parity = mark\n"); } else { buf[5] = 1; - dbg("%s - parity = odd", __func__); + dev_dbg(&port->dev, "parity = odd\n"); } } else { if (cflag & CMSPAR) { buf[5] = 4; - dbg("%s - parity = space", __func__); + dev_dbg(&port->dev, "parity = space\n"); } else { buf[5] = 2; - dbg("%s - parity = even", __func__); + dev_dbg(&port->dev, "parity = even\n"); } } } else { buf[5] = 0; - dbg("%s - parity = none", __func__); + dev_dbg(&port->dev, "parity = none\n"); } i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, 0, 0, buf, 7, 100); - dbg("0x21:0x20:0:0 %d", i); + dev_dbg(&port->dev, "0x21:0x20:0:0 %d\n", i); /* change control lines if we are switching to or from B0 */ spin_lock_irqsave(&priv->lock, flags); @@ -435,7 +424,7 @@ static void pl2303_set_termios(struct tty_struct *tty, i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, 0, 0, buf, 7, 100); - dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i, + dev_dbg(&port->dev, "0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x\n", i, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); if (cflag & CRTSCTS) { @@ -473,8 +462,6 @@ static void pl2303_dtr_rts(struct usb_serial_port *port, int on) static void pl2303_close(struct usb_serial_port *port) { - dbg("%s - port %d", __func__, port->number); - usb_serial_generic_close(port); usb_kill_urb(port->interrupt_in_urb); } @@ -486,8 +473,6 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port) struct pl2303_private *priv = usb_get_serial_port_data(port); int result; - dbg("%s - port %d", __func__, port->number); - if (priv->type != HX) { usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); @@ -501,7 +486,6 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port) if (tty) pl2303_set_termios(tty, port, &tmp_termios); - dbg("%s - submitting interrupt urb", __func__); result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) { dev_err(&port->dev, "%s - failed submitting interrupt urb," @@ -523,12 +507,11 @@ static int pl2303_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; + struct usb_serial *serial = port->serial; struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned long flags; u8 control; - - if (!usb_get_intfdata(port->serial->interface)) - return -ENODEV; + int ret; spin_lock_irqsave(&priv->lock, flags); if (set & TIOCM_RTS) @@ -542,7 +525,14 @@ static int pl2303_tiocmset(struct tty_struct *tty, control = priv->line_control; spin_unlock_irqrestore(&priv->lock, flags); - return set_control_lines(port->serial->dev, control); + mutex_lock(&serial->disc_mutex); + if (!serial->disconnected) + ret = set_control_lines(serial->dev, control); + else + ret = -ENODEV; + mutex_unlock(&serial->disc_mutex); + + return ret; } static int pl2303_tiocmget(struct tty_struct *tty) @@ -554,11 +544,6 @@ static int pl2303_tiocmget(struct tty_struct *tty) unsigned int status; unsigned int result; - dbg("%s (%d)", __func__, port->number); - - if (!usb_get_intfdata(port->serial->interface)) - return -ENODEV; - spin_lock_irqsave(&priv->lock, flags); mcr = priv->line_control; status = priv->line_status; @@ -571,7 +556,7 @@ static int pl2303_tiocmget(struct tty_struct *tty) | ((status & UART_RING) ? TIOCM_RI : 0) | ((status & UART_DCD) ? TIOCM_CD : 0); - dbg("%s - result = %x", __func__, result); + dev_dbg(&port->dev, "%s - result = %x\n", __func__, result); return result; } @@ -625,7 +610,8 @@ static int pl2303_ioctl(struct tty_struct *tty, { struct serial_struct ser; struct usb_serial_port *port = tty->driver_data; - dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd); + + dev_dbg(&port->dev, "%s cmd = 0x%04x\n", __func__, cmd); switch (cmd) { case TIOCGSERIAL: @@ -641,10 +627,10 @@ static int pl2303_ioctl(struct tty_struct *tty, return 0; case TIOCMIWAIT: - dbg("%s (%d) TIOCMIWAIT", __func__, port->number); + dev_dbg(&port->dev, "%s TIOCMIWAIT\n", __func__); return wait_modem_info(port, arg); default: - dbg("%s not supported = 0x%04x", __func__, cmd); + dev_dbg(&port->dev, "%s not supported = 0x%04x\n", __func__, cmd); break; } return -ENOIOCTLCMD; @@ -657,20 +643,18 @@ static void pl2303_break_ctl(struct tty_struct *tty, int break_state) u16 state; int result; - dbg("%s - port %d", __func__, port->number); - if (break_state == 0) state = BREAK_OFF; else state = BREAK_ON; - dbg("%s - turning break %s", __func__, + dev_dbg(&port->dev, "%s - turning break %s\n", __func__, state == BREAK_OFF ? "off" : "on"); result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), BREAK_REQUEST, BREAK_REQUEST_TYPE, state, 0, NULL, 0, 100); if (result) - dbg("%s - error sending break = %d", __func__, result); + dev_err(&port->dev, "error sending break = %d\n", result); } static void pl2303_release(struct usb_serial *serial) @@ -678,8 +662,6 @@ static void pl2303_release(struct usb_serial *serial) int i; struct pl2303_private *priv; - dbg("%s", __func__); - for (i = 0; i < serial->num_ports; ++i) { priv = usb_get_serial_port_data(serial->port[i]); kfree(priv); @@ -742,8 +724,6 @@ static void pl2303_read_int_callback(struct urb *urb) int status = urb->status; int retval; - dbg("%s (%d)", __func__, port->number); - switch (status) { case 0: /* success */ @@ -752,12 +732,12 @@ static void pl2303_read_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, - status); + dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", __func__, - status); + dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", + __func__, status); goto exit; } @@ -769,7 +749,7 @@ static void pl2303_read_int_callback(struct urb *urb) exit: retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval) - dev_err(&urb->dev->dev, + dev_err(&port->dev, "%s - usb_submit_urb failed with result %d\n", __func__, retval); } @@ -807,7 +787,7 @@ static void pl2303_process_read_urb(struct urb *urb) tty_flag = TTY_PARITY; else if (line_status & UART_FRAME_ERROR) tty_flag = TTY_FRAME; - dbg("%s - tty_flag = %d", __func__, tty_flag); + dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag); /* overrun is special, not associated with a char */ if (line_status & UART_OVERRUN_ERROR) @@ -855,7 +835,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &pl2303_device, NULL }; -module_usb_serial_driver(pl2303_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/usb/serial/qcaux.c b/trunk/drivers/usb/serial/qcaux.c index 966245680f55..a4edc7ee9c8a 100644 --- a/trunk/drivers/usb/serial/qcaux.c +++ b/trunk/drivers/usb/serial/qcaux.c @@ -77,13 +77,6 @@ static struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver qcaux_driver = { - .name = "qcaux", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver qcaux_device = { .driver = { .owner = THIS_MODULE, @@ -97,5 +90,5 @@ static struct usb_serial_driver * const serial_drivers[] = { &qcaux_device, NULL }; -module_usb_serial_driver(qcaux_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/usb/serial/qcserial.c b/trunk/drivers/usb/serial/qcserial.c index 0206b10c9e6e..0d5fe59ebb9e 100644 --- a/trunk/drivers/usb/serial/qcserial.c +++ b/trunk/drivers/usb/serial/qcserial.c @@ -112,32 +112,22 @@ static const struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver qcdriver = { - .name = "qcserial", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .supports_autosuspend = true, -}; - static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) { struct usb_wwan_intf_private *data; struct usb_host_interface *intf = serial->interface->cur_altsetting; + struct device *dev = &serial->dev->dev; int retval = -ENODEV; __u8 nintf; __u8 ifnum; bool is_gobi1k = id->driver_info ? true : false; - dbg("%s", __func__); - dbg("Is Gobi 1000 = %d", is_gobi1k); + dev_dbg(dev, "Is Gobi 1000 = %d\n", is_gobi1k); nintf = serial->dev->actconfig->desc.bNumInterfaces; - dbg("Num Interfaces = %d", nintf); + dev_dbg(dev, "Num Interfaces = %d\n", nintf); ifnum = intf->desc.bInterfaceNumber; - dbg("This Interface = %d", ifnum); + dev_dbg(dev, "This Interface = %d\n", ifnum); data = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL); @@ -158,7 +148,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) if (intf->desc.bNumEndpoints == 2 && usb_endpoint_is_bulk_in(&intf->endpoint[0].desc) && usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) { - dbg("QDL port found"); + dev_dbg(dev, "QDL port found\n"); if (serial->interface->num_altsetting == 1) { retval = 0; /* Success */ @@ -167,7 +157,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) retval = usb_set_interface(serial->dev, ifnum, 1); if (retval < 0) { - dev_err(&serial->dev->dev, + dev_err(dev, "Could not set interface, error %d\n", retval); retval = -ENODEV; @@ -196,20 +186,20 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) */ if (ifnum == 1 && !is_gobi1k) { - dbg("Gobi 2K+ DM/DIAG interface found"); + dev_dbg(dev, "Gobi 2K+ DM/DIAG interface found\n"); retval = usb_set_interface(serial->dev, ifnum, 0); if (retval < 0) { - dev_err(&serial->dev->dev, + dev_err(dev, "Could not set interface, error %d\n", retval); retval = -ENODEV; kfree(data); } } else if (ifnum == 2) { - dbg("Modem port found"); + dev_dbg(dev, "Modem port found\n"); retval = usb_set_interface(serial->dev, ifnum, 0); if (retval < 0) { - dev_err(&serial->dev->dev, + dev_err(dev, "Could not set interface, error %d\n", retval); retval = -ENODEV; @@ -221,10 +211,10 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) * # echo "\$GPS_START" > /dev/ttyUSBx * # echo "\$GPS_STOP" > /dev/ttyUSBx */ - dbg("Gobi 2K+ NMEA GPS interface found"); + dev_dbg(dev, "Gobi 2K+ NMEA GPS interface found\n"); retval = usb_set_interface(serial->dev, ifnum, 0); if (retval < 0) { - dev_err(&serial->dev->dev, + dev_err(dev, "Could not set interface, error %d\n", retval); retval = -ENODEV; @@ -234,8 +224,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) break; default: - dev_err(&serial->dev->dev, - "unknown number of interfaces: %d\n", nintf); + dev_err(dev, "unknown number of interfaces: %d\n", nintf); kfree(data); retval = -ENODEV; } @@ -250,8 +239,6 @@ static void qc_release(struct usb_serial *serial) { struct usb_wwan_intf_private *priv = usb_get_serial_data(serial); - dbg("%s", __func__); - /* Call usb_wwan release & free the private data allocated in qcprobe */ usb_wwan_release(serial); usb_set_serial_data(serial, NULL); @@ -285,7 +272,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &qcdevice, NULL }; -module_usb_serial_driver(qcdriver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/trunk/drivers/usb/serial/quatech2.c b/trunk/drivers/usb/serial/quatech2.c new file mode 100644 index 000000000000..8dd88ebe9863 --- /dev/null +++ b/trunk/drivers/usb/serial/quatech2.c @@ -0,0 +1,1155 @@ +/* + * usb-serial driver for Quatech USB 2 devices + * + * Copyright (C) 2012 Bill Pemberton (wfp5p@virginia.edu) + * + * 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. + * + * + * These devices all have only 1 bulk in and 1 bulk out that is shared + * for all serial ports. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static bool debug; + +/* default urb timeout for usb operations */ +#define QT2_USB_TIMEOUT USB_CTRL_SET_TIMEOUT + +#define QT_OPEN_CLOSE_CHANNEL 0xca +#define QT_SET_GET_DEVICE 0xc2 +#define QT_SET_GET_REGISTER 0xc0 +#define QT_GET_SET_PREBUF_TRIG_LVL 0xcc +#define QT_SET_ATF 0xcd +#define QT_TRANSFER_IN 0xc0 +#define QT_HW_FLOW_CONTROL_MASK 0xc5 +#define QT_SW_FLOW_CONTROL_MASK 0xc6 +#define QT2_BREAK_CONTROL 0xc8 +#define QT2_GET_SET_UART 0xc1 +#define QT2_FLUSH_DEVICE 0xc4 +#define QT2_GET_SET_QMCR 0xe1 +#define QT2_QMCR_RS232 0x40 +#define QT2_QMCR_RS422 0x10 + +#define SERIAL_CRTSCTS ((UART_MCR_RTS << 8) | UART_MSR_CTS) + +#define SERIAL_EVEN_PARITY (UART_LCR_PARITY | UART_LCR_EPAR) + +/* status bytes for the device */ +#define QT2_CONTROL_BYTE 0x1b +#define QT2_LINE_STATUS 0x00 /* following 1 byte is line status */ +#define QT2_MODEM_STATUS 0x01 /* following 1 byte is modem status */ +#define QT2_XMIT_HOLD 0x02 /* following 2 bytes are ?? */ +#define QT2_CHANGE_PORT 0x03 /* following 1 byte is port to change to */ +#define QT2_REC_FLUSH 0x04 /* no following info */ +#define QT2_XMIT_FLUSH 0x05 /* no following info */ +#define QT2_CONTROL_ESCAPE 0xff /* pass through previous 2 control bytes */ + +#define MAX_BAUD_RATE 921600 +#define DEFAULT_BAUD_RATE 9600 + +#define QT2_WRITE_BUFFER_SIZE 512 /* size of write buffer */ +#define QT2_WRITE_CONTROL_SIZE 5 /* control bytes used for a write */ + +/* Version Information */ +#define DRIVER_VERSION "v0.1" +#define DRIVER_DESC "Quatech 2nd gen USB to Serial Driver" + +#define USB_VENDOR_ID_QUATECH 0x061d +#define QUATECH_SSU2_100 0xC120 /* RS232 single port */ +#define QUATECH_DSU2_100 0xC140 /* RS232 dual port */ +#define QUATECH_DSU2_400 0xC150 /* RS232/422/485 dual port */ +#define QUATECH_QSU2_100 0xC160 /* RS232 four port */ +#define QUATECH_QSU2_400 0xC170 /* RS232/422/485 four port */ +#define QUATECH_ESU2_100 0xC1A0 /* RS232 eight port */ +#define QUATECH_ESU2_400 0xC180 /* RS232/422/485 eight port */ + +struct qt2_device_detail { + int product_id; + int num_ports; +}; + +#define QT_DETAILS(prod, ports) \ + .product_id = (prod), \ + .num_ports = (ports) + +static const struct qt2_device_detail qt2_device_details[] = { + {QT_DETAILS(QUATECH_SSU2_100, 1)}, + {QT_DETAILS(QUATECH_DSU2_400, 2)}, + {QT_DETAILS(QUATECH_DSU2_100, 2)}, + {QT_DETAILS(QUATECH_QSU2_400, 4)}, + {QT_DETAILS(QUATECH_QSU2_100, 4)}, + {QT_DETAILS(QUATECH_ESU2_400, 8)}, + {QT_DETAILS(QUATECH_ESU2_100, 8)}, + {QT_DETAILS(0, 0)} /* Terminating entry */ +}; + +static const struct usb_device_id id_table[] = { + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU2_100)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_100)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_400)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_100)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_400)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_100)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_400)}, + {} /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, id_table); + +struct qt2_serial_private { + unsigned char current_port; /* current port for incoming data */ + + struct urb *read_urb; /* shared among all ports */ + char read_buffer[512]; +}; + +struct qt2_port_private { + bool is_open; + u8 device_port; + + spinlock_t urb_lock; + bool urb_in_use; + struct urb *write_urb; + char write_buffer[QT2_WRITE_BUFFER_SIZE]; + + spinlock_t lock; + u8 shadowLSR; + u8 shadowMSR; + + wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ + struct async_icount icount; + + struct usb_serial_port *port; +}; + +static void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch); +static void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch); +static void qt2_write_bulk_callback(struct urb *urb); +static void qt2_read_bulk_callback(struct urb *urb); + +static void qt2_release(struct usb_serial *serial) +{ + int i; + + kfree(usb_get_serial_data(serial)); + + for (i = 0; i < serial->num_ports; i++) + kfree(usb_get_serial_port_data(serial->port[i])); +} + +static inline int calc_baud_divisor(int baudrate) +{ + int divisor, rem; + + divisor = MAX_BAUD_RATE / baudrate; + rem = MAX_BAUD_RATE % baudrate; + /* Round to nearest divisor */ + if (((rem * 2) >= baudrate) && (baudrate != 110)) + divisor++; + + return divisor; +} + +static inline int qt2_set_port_config(struct usb_device *dev, + unsigned char port_number, + u16 baudrate, u16 lcr) +{ + int divisor = calc_baud_divisor(baudrate); + u16 index = ((u16) (lcr << 8) | (u16) (port_number)); + + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + QT2_GET_SET_UART, 0x40, + divisor, index, NULL, 0, QT2_USB_TIMEOUT); +} + +static inline int qt2_control_msg(struct usb_device *dev, + u8 request, u16 data, u16 index) +{ + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + request, 0x40, data, index, + NULL, 0, QT2_USB_TIMEOUT); +} + +static inline int qt2_setdevice(struct usb_device *dev, u8 *data) +{ + u16 x = ((u16) (data[1] << 8) | (u16) (data[0])); + + return qt2_control_msg(dev, QT_SET_GET_DEVICE, x, 0); +} + + +static inline int qt2_getdevice(struct usb_device *dev, u8 *data) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + QT_SET_GET_DEVICE, 0xc0, 0, 0, + data, 3, QT2_USB_TIMEOUT); +} + +static inline int qt2_getregister(struct usb_device *dev, + u8 uart, + u8 reg, + u8 *data) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + QT_SET_GET_REGISTER, 0xc0, reg, + uart, data, sizeof(*data), QT2_USB_TIMEOUT); + +} + +static inline int qt2_setregister(struct usb_device *dev, + u8 uart, u8 reg, u16 data) +{ + u16 value = (data << 8) | reg; + + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + QT_SET_GET_REGISTER, 0x40, value, uart, + NULL, 0, QT2_USB_TIMEOUT); +} + +static inline int update_mctrl(struct qt2_port_private *port_priv, + unsigned int set, unsigned int clear) +{ + struct usb_serial_port *port = port_priv->port; + struct usb_device *dev = port->serial->dev; + unsigned urb_value; + int status; + + if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) { + dev_dbg(&port->dev, + "update_mctrl - DTR|RTS not being set|cleared\n"); + return 0; /* no change */ + } + + clear &= ~set; /* 'set' takes precedence over 'clear' */ + urb_value = 0; + if (set & TIOCM_DTR) + urb_value |= UART_MCR_DTR; + if (set & TIOCM_RTS) + urb_value |= UART_MCR_RTS; + + status = qt2_setregister(dev, port_priv->device_port, UART_MCR, + urb_value); + if (status < 0) + dev_err(&port->dev, + "update_mctrl - Error from MODEM_CTRL urb: %i\n", + status); + return status; +} + +static int qt2_calc_num_ports(struct usb_serial *serial) +{ + struct qt2_device_detail d; + int i; + + for (i = 0; d = qt2_device_details[i], d.product_id != 0; i++) { + if (d.product_id == le16_to_cpu(serial->dev->descriptor.idProduct)) + return d.num_ports; + } + + /* we didn't recognize the device */ + dev_err(&serial->dev->dev, + "don't know the number of ports, assuming 1\n"); + + return 1; +} + +static void qt2_set_termios(struct tty_struct *tty, + struct usb_serial_port *port, + struct ktermios *old_termios) +{ + struct usb_device *dev = port->serial->dev; + struct qt2_port_private *port_priv; + struct ktermios *termios = tty->termios; + u16 baud; + unsigned int cflag = termios->c_cflag; + u16 new_lcr = 0; + int status; + + port_priv = usb_get_serial_port_data(port); + + if (cflag & PARENB) { + if (cflag & PARODD) + new_lcr |= UART_LCR_PARITY; + else + new_lcr |= SERIAL_EVEN_PARITY; + } + + switch (cflag & CSIZE) { + case CS5: + new_lcr |= UART_LCR_WLEN5; + break; + case CS6: + new_lcr |= UART_LCR_WLEN6; + break; + case CS7: + new_lcr |= UART_LCR_WLEN7; + break; + default: + case CS8: + new_lcr |= UART_LCR_WLEN8; + break; + } + + baud = tty_get_baud_rate(tty); + if (!baud) + baud = 9600; + + status = qt2_set_port_config(dev, port_priv->device_port, baud, + new_lcr); + if (status < 0) + dev_err(&port->dev, "%s - qt2_set_port_config failed: %i\n", + __func__, status); + + if (cflag & CRTSCTS) + status = qt2_control_msg(dev, QT_HW_FLOW_CONTROL_MASK, + SERIAL_CRTSCTS, + port_priv->device_port); + else + status = qt2_control_msg(dev, QT_HW_FLOW_CONTROL_MASK, + 0, port_priv->device_port); + if (status < 0) + dev_err(&port->dev, "%s - set HW flow control failed: %i\n", + __func__, status); + + if (I_IXOFF(tty) || I_IXON(tty)) { + u16 x = ((u16) (START_CHAR(tty) << 8) | (u16) (STOP_CHAR(tty))); + + status = qt2_control_msg(dev, QT_SW_FLOW_CONTROL_MASK, + x, port_priv->device_port); + } else + status = qt2_control_msg(dev, QT_SW_FLOW_CONTROL_MASK, + 0, port_priv->device_port); + + if (status < 0) + dev_err(&port->dev, "%s - set SW flow control failed: %i\n", + __func__, status); + +} + +static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port) +{ + struct usb_serial *serial; + struct qt2_serial_private *serial_priv; + struct qt2_port_private *port_priv; + u8 *data; + u16 device_port; + int status; + unsigned long flags; + + device_port = (u16) (port->number - port->serial->minor); + + serial = port->serial; + + port_priv = usb_get_serial_port_data(port); + serial_priv = usb_get_serial_data(serial); + + /* set the port to RS232 mode */ + status = qt2_control_msg(serial->dev, QT2_GET_SET_QMCR, + QT2_QMCR_RS232, device_port); + if (status < 0) { + dev_err(&port->dev, + "%s failed to set RS232 mode for port %i error %i\n", + __func__, device_port, status); + return status; + } + + data = kzalloc(2, GFP_KERNEL); + if (!data) + return -ENOMEM; + + /* open the port */ + status = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + QT_OPEN_CLOSE_CHANNEL, + 0xc0, 0, + device_port, data, 2, QT2_USB_TIMEOUT); + + if (status < 0) { + dev_err(&port->dev, "%s - open port failed %i", __func__, + status); + kfree(data); + return status; + } + + spin_lock_irqsave(&port_priv->lock, flags); + port_priv->shadowLSR = data[0]; + port_priv->shadowMSR = data[1]; + spin_unlock_irqrestore(&port_priv->lock, flags); + + kfree(data); + + /* set to default speed and 8bit word size */ + status = qt2_set_port_config(serial->dev, device_port, + DEFAULT_BAUD_RATE, UART_LCR_WLEN8); + if (status < 0) { + dev_err(&port->dev, + "%s - initial setup failed for port %i (%i)\n", + __func__, port->number, device_port); + return status; + } + + port_priv->is_open = true; + port_priv->device_port = (u8) device_port; + + if (tty) + qt2_set_termios(tty, port, tty->termios); + + return 0; + +} + +static void qt2_close(struct usb_serial_port *port) +{ + struct usb_serial *serial; + struct qt2_serial_private *serial_priv; + struct qt2_port_private *port_priv; + unsigned long flags; + int i; + + serial = port->serial; + serial_priv = usb_get_serial_data(serial); + port_priv = usb_get_serial_port_data(port); + + port_priv->is_open = false; + + spin_lock_irqsave(&port_priv->urb_lock, flags); + if (port_priv->write_urb->status == -EINPROGRESS) + usb_kill_urb(port_priv->write_urb); + port_priv->urb_in_use = false; + spin_unlock_irqrestore(&port_priv->urb_lock, flags); + + /* flush the port transmit buffer */ + i = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + QT2_FLUSH_DEVICE, 0x40, 1, + port_priv->device_port, NULL, 0, QT2_USB_TIMEOUT); + + if (i < 0) + dev_err(&port->dev, "%s - transmit buffer flush failed: %i\n", + __func__, i); + + /* flush the port receive buffer */ + i = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + QT2_FLUSH_DEVICE, 0x40, 0, + port_priv->device_port, NULL, 0, QT2_USB_TIMEOUT); + + if (i < 0) + dev_err(&port->dev, "%s - receive buffer flush failed: %i\n", + __func__, i); + + /* close the port */ + i = usb_control_msg(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + QT_OPEN_CLOSE_CHANNEL, + 0x40, 0, + port_priv->device_port, NULL, 0, QT2_USB_TIMEOUT); + + if (i < 0) + dev_err(&port->dev, "%s - close port failed %i\n", + __func__, i); + +} + +static void qt2_disconnect(struct usb_serial *serial) +{ + struct qt2_serial_private *serial_priv = usb_get_serial_data(serial); + struct qt2_port_private *port_priv; + int i; + + if (serial_priv->read_urb->status == -EINPROGRESS) + usb_kill_urb(serial_priv->read_urb); + + usb_free_urb(serial_priv->read_urb); + + for (i = 0; i < serial->num_ports; i++) { + port_priv = usb_get_serial_port_data(serial->port[i]); + + if (port_priv->write_urb->status == -EINPROGRESS) + usb_kill_urb(port_priv->write_urb); + usb_free_urb(port_priv->write_urb); + } +} + +static int get_serial_info(struct usb_serial_port *port, + struct serial_struct __user *retinfo) +{ + struct serial_struct tmp; + + if (!retinfo) + return -EFAULT; + + memset(&tmp, 0, sizeof(tmp)); + tmp.line = port->serial->minor; + tmp.port = 0; + tmp.irq = 0; + tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; + tmp.xmit_fifo_size = port->bulk_out_size; + tmp.baud_base = 9600; + tmp.close_delay = 5*HZ; + tmp.closing_wait = 30*HZ; + + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + return -EFAULT; + return 0; +} + +static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) +{ + struct qt2_port_private *priv = usb_get_serial_port_data(port); + struct async_icount prev, cur; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + prev = priv->icount; + spin_unlock_irqrestore(&priv->lock, flags); + + while (1) { + wait_event_interruptible(priv->delta_msr_wait, + ((priv->icount.rng != prev.rng) || + (priv->icount.dsr != prev.dsr) || + (priv->icount.dcd != prev.dcd) || + (priv->icount.cts != prev.cts))); + + if (signal_pending(current)) + return -ERESTARTSYS; + + spin_lock_irqsave(&priv->lock, flags); + cur = priv->icount; + spin_unlock_irqrestore(&priv->lock, flags); + + if ((prev.rng == cur.rng) && + (prev.dsr == cur.dsr) && + (prev.dcd == cur.dcd) && + (prev.cts == cur.cts)) + return -EIO; + + if ((arg & TIOCM_RNG && (prev.rng != cur.rng)) || + (arg & TIOCM_DSR && (prev.dsr != cur.dsr)) || + (arg & TIOCM_CD && (prev.dcd != cur.dcd)) || + (arg & TIOCM_CTS && (prev.cts != cur.cts))) + return 0; + } + return 0; +} + +static int qt2_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount) +{ + struct usb_serial_port *port = tty->driver_data; + struct qt2_port_private *priv = usb_get_serial_port_data(port); + struct async_icount cnow = priv->icount; + + icount->cts = cnow.cts; + icount->dsr = cnow.dsr; + icount->rng = cnow.rng; + icount->dcd = cnow.dcd; + icount->rx = cnow.rx; + icount->tx = cnow.tx; + icount->frame = cnow.frame; + icount->overrun = cnow.overrun; + icount->parity = cnow.parity; + icount->brk = cnow.brk; + icount->buf_overrun = cnow.buf_overrun; + + return 0; +} + +static int qt2_ioctl(struct tty_struct *tty, + unsigned int cmd, unsigned long arg) +{ + struct usb_serial_port *port = tty->driver_data; + + switch (cmd) { + case TIOCGSERIAL: + return get_serial_info(port, + (struct serial_struct __user *)arg); + + case TIOCMIWAIT: + return wait_modem_info(port, arg); + + default: + break; + } + + return -ENOIOCTLCMD; +} + +static void qt2_process_status(struct usb_serial_port *port, unsigned char *ch) +{ + switch (*ch) { + case QT2_LINE_STATUS: + qt2_update_lsr(port, ch + 1); + break; + case QT2_MODEM_STATUS: + qt2_update_msr(port, ch + 1); + break; + } +} + +/* not needed, kept to document functionality */ +static void qt2_process_xmit_empty(struct usb_serial_port *port, + unsigned char *ch) +{ + int bytes_written; + + bytes_written = (int)(*ch) + (int)(*(ch + 1) << 4); +} + +/* not needed, kept to document functionality */ +static void qt2_process_flush(struct usb_serial_port *port, unsigned char *ch) +{ + return; +} + +void qt2_process_read_urb(struct urb *urb) +{ + struct usb_serial *serial; + struct qt2_serial_private *serial_priv; + struct usb_serial_port *port; + struct qt2_port_private *port_priv; + struct tty_struct *tty; + bool escapeflag; + unsigned char *ch; + int i; + unsigned char newport; + int len = urb->actual_length; + + if (!len) + return; + + ch = urb->transfer_buffer; + tty = NULL; + serial = urb->context; + serial_priv = usb_get_serial_data(serial); + port = serial->port[serial_priv->current_port]; + port_priv = usb_get_serial_port_data(port); + + if (port_priv->is_open) + tty = tty_port_tty_get(&port->port); + + for (i = 0; i < urb->actual_length; i++) { + ch = (unsigned char *)urb->transfer_buffer + i; + if ((i <= (len - 3)) && + (*ch == QT2_CONTROL_BYTE) && + (*(ch + 1) == QT2_CONTROL_BYTE)) { + escapeflag = false; + switch (*(ch + 2)) { + case QT2_LINE_STATUS: + case QT2_MODEM_STATUS: + if (i > (len - 4)) { + dev_warn(&port->dev, + "%s - status message too short\n", + __func__); + break; + } + qt2_process_status(port, ch + 2); + i += 3; + escapeflag = true; + break; + case QT2_XMIT_HOLD: + if (i > (len - 5)) { + dev_warn(&port->dev, + "%s - xmit_empty message too short\n", + __func__); + break; + } + qt2_process_xmit_empty(port, ch + 3); + i += 4; + escapeflag = true; + break; + case QT2_CHANGE_PORT: + if (i > (len - 4)) { + dev_warn(&port->dev, + "%s - change_port message too short\n", + __func__); + break; + } + if (tty) { + tty_flip_buffer_push(tty); + tty_kref_put(tty); + } + + newport = *(ch + 3); + + if (newport > serial->num_ports) { + dev_err(&port->dev, + "%s - port change to invalid port: %i\n", + __func__, newport); + break; + } + + serial_priv->current_port = newport; + port = serial->port[serial_priv->current_port]; + port_priv = usb_get_serial_port_data(port); + if (port_priv->is_open) + tty = tty_port_tty_get(&port->port); + else + tty = NULL; + i += 3; + escapeflag = true; + break; + case QT2_REC_FLUSH: + case QT2_XMIT_FLUSH: + qt2_process_flush(port, ch + 2); + i += 2; + escapeflag = true; + break; + case QT2_CONTROL_ESCAPE: + tty_buffer_request_room(tty, 2); + tty_insert_flip_string(tty, ch, 2); + i += 2; + escapeflag = true; + break; + default: + dev_warn(&port->dev, + "%s - unsupported command %i\n", + __func__, *(ch + 2)); + break; + } + if (escapeflag) + continue; + } + + if (tty) { + tty_buffer_request_room(tty, 1); + tty_insert_flip_string(tty, ch, 1); + } + } + + if (tty) { + tty_flip_buffer_push(tty); + tty_kref_put(tty); + } +} + +static void qt2_write_bulk_callback(struct urb *urb) +{ + struct usb_serial_port *port; + struct qt2_port_private *port_priv; + + port = urb->context; + port_priv = usb_get_serial_port_data(port); + + spin_lock(&port_priv->urb_lock); + + port_priv->urb_in_use = false; + usb_serial_port_softint(port); + + spin_unlock(&port_priv->urb_lock); + +} + +static void qt2_read_bulk_callback(struct urb *urb) +{ + struct usb_serial *serial = urb->context; + int status; + + if (urb->status) { + dev_warn(&serial->dev->dev, + "%s - non-zero urb status: %i\n", __func__, + urb->status); + return; + } + + qt2_process_read_urb(urb); + + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status != 0) + dev_err(&serial->dev->dev, + "%s - resubmit read urb failed: %i\n", + __func__, status); +} + +static int qt2_setup_urbs(struct usb_serial *serial) +{ + struct usb_serial_port *port; + struct usb_serial_port *port0; + struct qt2_serial_private *serial_priv; + struct qt2_port_private *port_priv; + int pcount, status; + + port0 = serial->port[0]; + + serial_priv = usb_get_serial_data(serial); + serial_priv->read_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!serial_priv->read_urb) { + dev_err(&serial->dev->dev, "No free urbs available\n"); + return -ENOMEM; + } + + usb_fill_bulk_urb(serial_priv->read_urb, serial->dev, + usb_rcvbulkpipe(serial->dev, + port0->bulk_in_endpointAddress), + serial_priv->read_buffer, + sizeof(serial_priv->read_buffer), + qt2_read_bulk_callback, serial); + + /* setup write_urb for each port */ + for (pcount = 0; pcount < serial->num_ports; pcount++) { + + port = serial->port[pcount]; + port_priv = usb_get_serial_port_data(port); + + port_priv->write_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!port_priv->write_urb) { + dev_err(&serial->dev->dev, + "failed to alloc write_urb for port %i\n", + pcount); + return -ENOMEM; + } + + usb_fill_bulk_urb(port_priv->write_urb, + serial->dev, + usb_sndbulkpipe(serial->dev, + port0-> + bulk_out_endpointAddress), + port_priv->write_buffer, + sizeof(port_priv->write_buffer), + qt2_write_bulk_callback, port); + } + + status = usb_submit_urb(serial_priv->read_urb, GFP_KERNEL); + if (status != 0) { + dev_err(&serial->dev->dev, + "%s - submit read urb failed %i\n", __func__, status); + return status; + } + + return 0; + +} + +static int qt2_attach(struct usb_serial *serial) +{ + struct qt2_serial_private *serial_priv; + struct qt2_port_private *port_priv; + int status, pcount; + + /* power on unit */ + status = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + 0xc2, 0x40, 0x8000, 0, NULL, 0, + QT2_USB_TIMEOUT); + if (status < 0) { + dev_err(&serial->dev->dev, + "%s - failed to power on unit: %i\n", __func__, status); + return status; + } + + serial_priv = kzalloc(sizeof(*serial_priv), GFP_KERNEL); + if (!serial_priv) { + dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__); + return -ENOMEM; + } + + usb_set_serial_data(serial, serial_priv); + + for (pcount = 0; pcount < serial->num_ports; pcount++) { + port_priv = kzalloc(sizeof(*port_priv), GFP_KERNEL); + if (!port_priv) { + dev_err(&serial->dev->dev, + "%s- kmalloc(%Zd) failed.\n", __func__, + sizeof(*port_priv)); + pcount--; + status = -ENOMEM; + goto attach_failed; + } + + spin_lock_init(&port_priv->lock); + spin_lock_init(&port_priv->urb_lock); + init_waitqueue_head(&port_priv->delta_msr_wait); + + port_priv->port = serial->port[pcount]; + + usb_set_serial_port_data(serial->port[pcount], port_priv); + } + + status = qt2_setup_urbs(serial); + if (status != 0) + goto attach_failed; + + return 0; + +attach_failed: + for (/* empty */; pcount >= 0; pcount--) { + port_priv = usb_get_serial_port_data(serial->port[pcount]); + kfree(port_priv); + } + kfree(serial_priv); + return status; +} + +static int qt2_tiocmget(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + struct usb_device *dev = port->serial->dev; + struct qt2_port_private *port_priv = usb_get_serial_port_data(port); + u8 *d; + int r; + + d = kzalloc(2, GFP_KERNEL); + if (!d) + return -ENOMEM; + + r = qt2_getregister(dev, port_priv->device_port, UART_MCR, d); + if (r < 0) + goto mget_out; + + r = qt2_getregister(dev, port_priv->device_port, UART_MSR, d + 1); + if (r < 0) + goto mget_out; + + r = (d[0] & UART_MCR_DTR ? TIOCM_DTR : 0) | + (d[0] & UART_MCR_RTS ? TIOCM_RTS : 0) | + (d[1] & UART_MSR_CTS ? TIOCM_CTS : 0) | + (d[1] & UART_MSR_DCD ? TIOCM_CAR : 0) | + (d[1] & UART_MSR_RI ? TIOCM_RI : 0) | + (d[1] & UART_MSR_DSR ? TIOCM_DSR : 0); + +mget_out: + kfree(d); + return r; +} + +static int qt2_tiocmset(struct tty_struct *tty, + unsigned int set, unsigned int clear) +{ + struct qt2_port_private *port_priv; + + port_priv = usb_get_serial_port_data(tty->driver_data); + return update_mctrl(port_priv, set, clear); +} + +static void qt2_break_ctl(struct tty_struct *tty, int break_state) +{ + struct usb_serial_port *port = tty->driver_data; + struct qt2_port_private *port_priv; + int status; + u16 val; + + port_priv = usb_get_serial_port_data(port); + + if (!port_priv->is_open) { + dev_err(&port->dev, + "%s - port is not open\n", __func__); + return; + } + + val = (break_state == -1) ? 1 : 0; + + status = qt2_control_msg(port->serial->dev, QT2_BREAK_CONTROL, + val, port_priv->device_port); + if (status < 0) + dev_warn(&port->dev, + "%s - failed to send control message: %i\n", __func__, + status); +} + + + +static void qt2_dtr_rts(struct usb_serial_port *port, int on) +{ + struct usb_device *dev = port->serial->dev; + struct qt2_port_private *port_priv = usb_get_serial_port_data(port); + + mutex_lock(&port->serial->disc_mutex); + if (!port->serial->disconnected) { + /* Disable flow control */ + if (!on && qt2_setregister(dev, port_priv->device_port, + UART_MCR, 0) < 0) + dev_warn(&port->dev, "error from flowcontrol urb\n"); + /* drop RTS and DTR */ + if (on) + update_mctrl(port_priv, TIOCM_DTR | TIOCM_RTS, 0); + else + update_mctrl(port_priv, 0, TIOCM_DTR | TIOCM_RTS); + } + mutex_unlock(&port->serial->disc_mutex); +} + +static void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch) +{ + struct qt2_port_private *port_priv; + u8 newMSR = (u8) *ch; + unsigned long flags; + + port_priv = usb_get_serial_port_data(port); + + spin_lock_irqsave(&port_priv->lock, flags); + port_priv->shadowMSR = newMSR; + spin_unlock_irqrestore(&port_priv->lock, flags); + + if (newMSR & UART_MSR_ANY_DELTA) { + /* update input line counters */ + if (newMSR & UART_MSR_DCTS) + port_priv->icount.cts++; + + if (newMSR & UART_MSR_DDSR) + port_priv->icount.dsr++; + + if (newMSR & UART_MSR_DDCD) + port_priv->icount.dcd++; + + if (newMSR & UART_MSR_TERI) + port_priv->icount.rng++; + + wake_up_interruptible(&port_priv->delta_msr_wait); + } +} + +static void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch) +{ + struct qt2_port_private *port_priv; + struct async_icount *icount; + unsigned long flags; + u8 newLSR = (u8) *ch; + + port_priv = usb_get_serial_port_data(port); + + if (newLSR & UART_LSR_BI) + newLSR &= (u8) (UART_LSR_OE | UART_LSR_BI); + + spin_lock_irqsave(&port_priv->lock, flags); + port_priv->shadowLSR = newLSR; + spin_unlock_irqrestore(&port_priv->lock, flags); + + icount = &port_priv->icount; + + if (newLSR & UART_LSR_BRK_ERROR_BITS) { + + if (newLSR & UART_LSR_BI) + icount->brk++; + + if (newLSR & UART_LSR_OE) + icount->overrun++; + + if (newLSR & UART_LSR_PE) + icount->parity++; + + if (newLSR & UART_LSR_FE) + icount->frame++; + } + +} + +static int qt2_write_room(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + struct qt2_port_private *port_priv; + unsigned long flags = 0; + int r; + + port_priv = usb_get_serial_port_data(port); + + spin_lock_irqsave(&port_priv->urb_lock, flags); + + if (port_priv->urb_in_use) + r = 0; + else + r = QT2_WRITE_BUFFER_SIZE - QT2_WRITE_CONTROL_SIZE; + + spin_unlock_irqrestore(&port_priv->urb_lock, flags); + + return r; +} + +static int qt2_write(struct tty_struct *tty, + struct usb_serial_port *port, + const unsigned char *buf, int count) +{ + struct qt2_port_private *port_priv; + struct urb *write_urb; + unsigned char *data; + unsigned long flags; + int status; + int bytes_out = 0; + + port_priv = usb_get_serial_port_data(port); + + if (port_priv->write_urb == NULL) { + dev_err(&port->dev, "%s - no output urb\n", __func__); + return 0; + } + write_urb = port_priv->write_urb; + + count = min(count, QT2_WRITE_BUFFER_SIZE - QT2_WRITE_CONTROL_SIZE); + + data = write_urb->transfer_buffer; + spin_lock_irqsave(&port_priv->urb_lock, flags); + if (port_priv->urb_in_use == true) { + printk(KERN_INFO "qt2_write - urb is in use\n"); + goto write_out; + } + + *data++ = QT2_CONTROL_BYTE; + *data++ = QT2_CONTROL_BYTE; + *data++ = port_priv->device_port; + put_unaligned_le16(count, data); + data += 2; + memcpy(data, buf, count); + + write_urb->transfer_buffer_length = count + QT2_WRITE_CONTROL_SIZE; + + status = usb_submit_urb(write_urb, GFP_ATOMIC); + if (status == 0) { + port_priv->urb_in_use = true; + bytes_out += count; + } + +write_out: + spin_unlock_irqrestore(&port_priv->urb_lock, flags); + return bytes_out; +} + + +static struct usb_serial_driver qt2_device = { + .driver = { + .owner = THIS_MODULE, + .name = "quatech-serial", + }, + .description = DRIVER_DESC, + .id_table = id_table, + .open = qt2_open, + .close = qt2_close, + .write = qt2_write, + .write_room = qt2_write_room, + .calc_num_ports = qt2_calc_num_ports, + .attach = qt2_attach, + .release = qt2_release, + .disconnect = qt2_disconnect, + .dtr_rts = qt2_dtr_rts, + .break_ctl = qt2_break_ctl, + .tiocmget = qt2_tiocmget, + .tiocmset = qt2_tiocmset, + .get_icount = qt2_get_icount, + .ioctl = qt2_ioctl, + .set_termios = qt2_set_termios, +}; + +static struct usb_serial_driver *const serial_drivers[] = { + &qt2_device, NULL +}; + +module_usb_serial_driver(serial_drivers, id_table); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/trunk/drivers/usb/serial/safe_serial.c b/trunk/drivers/usb/serial/safe_serial.c index ae4ee30c7411..36e9d9fc0618 100644 --- a/trunk/drivers/usb/serial/safe_serial.c +++ b/trunk/drivers/usb/serial/safe_serial.c @@ -151,13 +151,6 @@ static struct usb_device_id id_table[] = { MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver safe_driver = { - .name = "safe_serial", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static const __u16 crc10_table[256] = { 0x000, 0x233, 0x255, 0x066, 0x299, 0x0aa, 0x0cc, 0x2ff, 0x301, 0x132, 0x154, 0x367, 0x198, 0x3ab, 0x3cd, 0x1fe, @@ -339,12 +332,12 @@ static int __init safe_init(void) } } - return usb_serial_register_drivers(&safe_driver, serial_drivers); + return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, id_table); } static void __exit safe_exit(void) { - usb_serial_deregister_drivers(&safe_driver, serial_drivers); + usb_serial_deregister_drivers(serial_drivers); } module_init(safe_init); diff --git a/trunk/drivers/usb/serial/siemens_mpi.c b/trunk/drivers/usb/serial/siemens_mpi.c index 46c0430fd38b..e4a1787cdbac 100644 --- a/trunk/drivers/usb/serial/siemens_mpi.c +++ b/trunk/drivers/usb/serial/siemens_mpi.c @@ -29,13 +29,6 @@ static const struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver siemens_usb_mpi_driver = { - .name = "siemens_mpi", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver siemens_usb_mpi_device = { .driver = { .owner = THIS_MODULE, @@ -49,7 +42,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &siemens_usb_mpi_device, NULL }; -module_usb_serial_driver(siemens_usb_mpi_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/trunk/drivers/usb/serial/sierra.c b/trunk/drivers/usb/serial/sierra.c index 8c8bf806f6fa..ba54a0a8235c 100644 --- a/trunk/drivers/usb/serial/sierra.c +++ b/trunk/drivers/usb/serial/sierra.c @@ -63,9 +63,7 @@ struct sierra_intf_private { static int sierra_set_power_state(struct usb_device *udev, __u16 swiState) { - int result; - dev_dbg(&udev->dev, "%s\n", __func__); - result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), SWIMS_USB_REQUEST_SetPower, /* __u8 request */ USB_TYPE_VENDOR, /* __u8 request type */ swiState, /* __u16 value */ @@ -73,14 +71,11 @@ static int sierra_set_power_state(struct usb_device *udev, __u16 swiState) NULL, /* void *data */ 0, /* __u16 size */ USB_CTRL_SET_TIMEOUT); /* int timeout */ - return result; } static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable) { - int result; - dev_dbg(&udev->dev, "%s\n", __func__); - result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), SWIMS_USB_REQUEST_SetNmea, /* __u8 request */ USB_TYPE_VENDOR, /* __u8 request type */ enable, /* __u16 value */ @@ -88,7 +83,6 @@ static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable) NULL, /* void *data */ 0, /* __u16 size */ USB_CTRL_SET_TIMEOUT); /* int timeout */ - return result; } static int sierra_calc_num_ports(struct usb_serial *serial) @@ -96,8 +90,6 @@ static int sierra_calc_num_ports(struct usb_serial *serial) int num_ports = 0; u8 ifnum, numendpoints; - dev_dbg(&serial->dev->dev, "%s\n", __func__); - ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber; numendpoints = serial->interface->cur_altsetting->desc.bNumEndpoints; @@ -150,7 +142,6 @@ static int sierra_calc_interface(struct usb_serial *serial) int interface; struct usb_interface *p_interface; struct usb_host_interface *p_host_interface; - dev_dbg(&serial->dev->dev, "%s\n", __func__); /* Get the interface structure pointer from the serial struct */ p_interface = serial->interface; @@ -175,9 +166,8 @@ static int sierra_probe(struct usb_serial *serial, u8 ifnum; udev = serial->dev; - dev_dbg(&udev->dev, "%s\n", __func__); - ifnum = sierra_calc_interface(serial); + /* * If this interface supports more than 1 alternate * select the 2nd one @@ -344,8 +334,6 @@ static int sierra_send_setup(struct usb_serial_port *port) int do_send = 0; int retval; - dev_dbg(&port->dev, "%s\n", __func__); - portdata = usb_get_serial_port_data(port); if (portdata->dtr_state) @@ -393,7 +381,6 @@ static int sierra_send_setup(struct usb_serial_port *port) static void sierra_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { - dev_dbg(&port->dev, "%s\n", __func__); tty_termios_copy_hw(tty->termios, old_termios); sierra_send_setup(port); } @@ -404,7 +391,6 @@ static int sierra_tiocmget(struct tty_struct *tty) unsigned int value; struct sierra_port_private *portdata; - dev_dbg(&port->dev, "%s\n", __func__); portdata = usb_get_serial_port_data(port); value = ((portdata->rts_state) ? TIOCM_RTS : 0) | @@ -441,8 +427,7 @@ static void sierra_release_urb(struct urb *urb) { struct usb_serial_port *port; if (urb) { - port = urb->context; - dev_dbg(&port->dev, "%s: %p\n", __func__, urb); + port = urb->context; kfree(urb->transfer_buffer); usb_free_urb(urb); } @@ -455,7 +440,6 @@ static void sierra_outdat_callback(struct urb *urb) struct sierra_intf_private *intfdata; int status = urb->status; - dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number); intfdata = port->serial->private; /* free up the transfer buffer, as usb_free_urb() does not do this */ @@ -598,8 +582,6 @@ static void sierra_indat_callback(struct urb *urb) endpoint = usb_pipeendpoint(urb->pipe); port = urb->context; - dev_dbg(&port->dev, "%s: %p\n", __func__, urb); - if (status) { dev_dbg(&port->dev, "%s: nonzero status: %d on" " endpoint %02x\n", __func__, status, endpoint); @@ -697,8 +679,6 @@ static int sierra_write_room(struct tty_struct *tty) struct sierra_port_private *portdata = usb_get_serial_port_data(port); unsigned long flags; - dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number); - /* try to give a good number back based on if we have any free urbs at * this point in time */ spin_lock_irqsave(&portdata->lock, flags); @@ -805,8 +785,6 @@ static void sierra_close(struct usb_serial_port *port) struct sierra_port_private *portdata; struct sierra_intf_private *intfdata = port->serial->private; - - dev_dbg(&port->dev, "%s\n", __func__); portdata = usb_get_serial_port_data(port); portdata->rts_state = 0; @@ -851,8 +829,6 @@ static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port) portdata = usb_get_serial_port_data(port); - dev_dbg(&port->dev, "%s\n", __func__); - /* Set some sane defaults */ portdata->rts_state = 1; portdata->dtr_state = 1; @@ -915,8 +891,6 @@ static int sierra_startup(struct usb_serial *serial) int i; u8 ifnum; - dev_dbg(&serial->dev->dev, "%s\n", __func__); - /* Set Device mode to D0 */ sierra_set_power_state(serial->dev, 0x0000); @@ -977,8 +951,6 @@ static void sierra_release(struct usb_serial *serial) struct usb_serial_port *port; struct sierra_port_private *portdata; - dev_dbg(&serial->dev->dev, "%s\n", __func__); - for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; if (!port) @@ -1067,29 +1039,11 @@ static int sierra_resume(struct usb_serial *serial) return ec ? -EIO : 0; } -static int sierra_reset_resume(struct usb_interface *intf) -{ - struct usb_serial *serial = usb_get_intfdata(intf); - dev_err(&serial->dev->dev, "%s\n", __func__); - return usb_serial_resume(intf); -} #else #define sierra_suspend NULL #define sierra_resume NULL -#define sierra_reset_resume NULL #endif -static struct usb_driver sierra_driver = { - .name = "sierra", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .reset_resume = sierra_reset_resume, - .id_table = id_table, - .supports_autosuspend = 1, -}; - static struct usb_serial_driver sierra_device = { .driver = { .owner = THIS_MODULE, @@ -1118,7 +1072,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &sierra_device, NULL }; -module_usb_serial_driver(sierra_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/trunk/drivers/usb/serial/spcp8x5.c b/trunk/drivers/usb/serial/spcp8x5.c index f06c9a8f3d37..cad608984710 100644 --- a/trunk/drivers/usb/serial/spcp8x5.c +++ b/trunk/drivers/usb/serial/spcp8x5.c @@ -151,14 +151,6 @@ enum spcp8x5_type { SPCP835_TYPE, }; -static struct usb_driver spcp8x5_driver = { - .name = "spcp8x5", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - - struct spcp8x5_private { spinlock_t lock; enum spcp8x5_type type; @@ -433,7 +425,7 @@ static void spcp8x5_set_termios(struct tty_struct *tty, if (i < 0) dev_err(&port->dev, "Set UART format %#x failed (error = %d)\n", uartdata, i); - dbg("0x21:0x40:0:0 %d", i); + dev_dbg(&port->dev, "0x21:0x40:0:0 %d\n", i); if (cflag & CRTSCTS) { /* enable hardware flow control */ @@ -454,8 +446,6 @@ static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port) u8 status = 0x30; /* status 0x30 means DSR and CTS = 1 other CDC RI and delta = 0 */ - dbg("%s - port %d", __func__, port->number); - usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); @@ -579,15 +569,19 @@ static int spcp8x5_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; - dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd); + + dev_dbg(&port->dev, "%s (%d) cmd = 0x%04x\n", __func__, + port->number, cmd); switch (cmd) { case TIOCMIWAIT: - dbg("%s (%d) TIOCMIWAIT", __func__, port->number); + dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__, + port->number); return spcp8x5_wait_modem_info(port, arg); default: - dbg("%s not supported = 0x%04x", __func__, cmd); + dev_dbg(&port->dev, "%s not supported = 0x%04x", __func__, + cmd); break; } @@ -666,7 +660,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &spcp8x5_device, NULL }; -module_usb_serial_driver(spcp8x5_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_VERSION(DRIVER_VERSION); diff --git a/trunk/drivers/usb/serial/ssu100.c b/trunk/drivers/usb/serial/ssu100.c index 3cdc8a52de44..3fee23bf0c14 100644 --- a/trunk/drivers/usb/serial/ssu100.c +++ b/trunk/drivers/usb/serial/ssu100.c @@ -59,20 +59,8 @@ static const struct usb_device_id id_table[] = { {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU100)}, {} /* Terminating entry */ }; - MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver ssu100_driver = { - .name = "ssu100", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .supports_autosuspend = 1, -}; - struct ssu100_port_private { spinlock_t status_lock; u8 shadowLSR; @@ -85,7 +73,6 @@ static void ssu100_release(struct usb_serial *serial) { struct ssu100_port_private *priv = usb_get_serial_port_data(*serial->port); - dbg("%s", __func__); kfree(priv); } @@ -171,8 +158,6 @@ static int ssu100_initdevice(struct usb_device *dev) u8 *data; int result = 0; - dbg("%s", __func__); - data = kzalloc(3, GFP_KERNEL); if (!data) return -ENOMEM; @@ -237,8 +222,6 @@ static void ssu100_set_termios(struct tty_struct *tty, u16 urb_value = 0; /* will hold the new flags */ int result; - dbg("%s", __func__); - if (cflag & PARENB) { if (cflag & PARODD) urb_value |= UART_LCR_PARITY; @@ -312,8 +295,6 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) int result; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - data = kzalloc(2, GFP_KERNEL); if (!data) return -ENOMEM; @@ -348,7 +329,6 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) static void ssu100_close(struct usb_serial_port *port) { - dbg("%s", __func__); usb_serial_generic_close(port); } @@ -467,8 +447,6 @@ static int ssu100_attach(struct usb_serial *serial) struct ssu100_port_private *priv; struct usb_serial_port *port = *serial->port; - dbg("%s", __func__); - priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) { dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", __func__, @@ -490,8 +468,6 @@ static int ssu100_tiocmget(struct tty_struct *tty) u8 *d; int r; - dbg("%s\n", __func__); - d = kzalloc(2, GFP_KERNEL); if (!d) return -ENOMEM; @@ -522,7 +498,6 @@ static int ssu100_tiocmset(struct tty_struct *tty, struct usb_serial_port *port = tty->driver_data; struct usb_device *dev = port->serial->dev; - dbg("%s\n", __func__); return update_mctrl(dev, set, clear); } @@ -530,8 +505,6 @@ static void ssu100_dtr_rts(struct usb_serial_port *port, int on) { struct usb_device *dev = port->serial->dev; - dbg("%s\n", __func__); - mutex_lock(&port->serial->disc_mutex); if (!port->serial->disconnected) { /* Disable flow control */ @@ -618,8 +591,6 @@ static int ssu100_process_packet(struct urb *urb, int i; char *ch; - dbg("%s - port %d", __func__, port->number); - if ((len >= 4) && (packet[0] == 0x1b) && (packet[1] == 0x1b) && ((packet[2] == 0x00) || (packet[2] == 0x01))) { @@ -656,8 +627,6 @@ static void ssu100_process_read_urb(struct urb *urb) struct tty_struct *tty; int count; - dbg("%s", __func__); - tty = tty_port_tty_get(&port->port); if (!tty) return; @@ -695,7 +664,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &ssu100_device, NULL }; -module_usb_serial_driver(ssu100_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/usb/serial/symbolserial.c b/trunk/drivers/usb/serial/symbolserial.c index 1a5be136e6cf..e53d2aac35c5 100644 --- a/trunk/drivers/usb/serial/symbolserial.c +++ b/trunk/drivers/usb/serial/symbolserial.c @@ -54,8 +54,6 @@ static void symbol_int_callback(struct urb *urb) int result; int data_length; - dbg("%s - port %d", __func__, port->number); - switch (status) { case 0: /* success */ @@ -64,12 +62,12 @@ static void symbol_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", - __func__, status); + dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", + __func__, status); goto exit; } @@ -125,8 +123,6 @@ static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port) unsigned long flags; int result = 0; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); priv->throttled = false; priv->actually_throttled = false; @@ -150,8 +146,6 @@ static void symbol_close(struct usb_serial_port *port) { struct symbol_private *priv = usb_get_serial_data(port->serial); - dbg("%s - port %d", __func__, port->number); - /* shutdown our urbs */ usb_kill_urb(priv->int_urb); } @@ -161,7 +155,6 @@ static void symbol_throttle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; struct symbol_private *priv = usb_get_serial_data(port->serial); - dbg("%s - port %d", __func__, port->number); spin_lock_irq(&priv->lock); priv->throttled = true; spin_unlock_irq(&priv->lock); @@ -174,8 +167,6 @@ static void symbol_unthrottle(struct tty_struct *tty) int result; bool was_throttled; - dbg("%s - port %d", __func__, port->number); - spin_lock_irq(&priv->lock); priv->throttled = false; was_throttled = priv->actually_throttled; @@ -266,8 +257,6 @@ static void symbol_disconnect(struct usb_serial *serial) { struct symbol_private *priv = usb_get_serial_data(serial); - dbg("%s", __func__); - usb_kill_urb(priv->int_urb); usb_free_urb(priv->int_urb); } @@ -276,19 +265,10 @@ static void symbol_release(struct usb_serial *serial) { struct symbol_private *priv = usb_get_serial_data(serial); - dbg("%s", __func__); - kfree(priv->int_buffer); kfree(priv); } -static struct usb_driver symbol_driver = { - .name = "symbol", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver symbol_device = { .driver = { .owner = THIS_MODULE, @@ -309,7 +289,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &symbol_device, NULL }; -module_usb_serial_driver(symbol_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/usb/serial/ti_usb_3410_5052.c b/trunk/drivers/usb/serial/ti_usb_3410_5052.c index ab74123d658e..a4404f5ad68e 100644 --- a/trunk/drivers/usb/serial/ti_usb_3410_5052.c +++ b/trunk/drivers/usb/serial/ti_usb_3410_5052.c @@ -165,7 +165,7 @@ static unsigned int product_5052_count; /* the array dimension is the number of default entries plus */ /* TI_EXTRA_VID_PID_COUNT user defined entries plus 1 terminating */ /* null entry */ -static struct usb_device_id ti_id_table_3410[14+TI_EXTRA_VID_PID_COUNT+1] = { +static struct usb_device_id ti_id_table_3410[15+TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, @@ -180,6 +180,7 @@ static struct usb_device_id ti_id_table_3410[14+TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) }, { USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) }, { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) }, + { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) }, }; static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = { @@ -189,7 +190,7 @@ static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) }, }; -static struct usb_device_id ti_id_table_combined[18+2*TI_EXTRA_VID_PID_COUNT+1] = { +static struct usb_device_id ti_id_table_combined[19+2*TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, @@ -208,16 +209,10 @@ static struct usb_device_id ti_id_table_combined[18+2*TI_EXTRA_VID_PID_COUNT+1] { USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) }, { USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) }, { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) }, + { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) }, { } }; -static struct usb_driver ti_usb_driver = { - .name = "ti_usb_3410_5052", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = ti_id_table_combined, -}; - static struct usb_serial_driver ti_1port_device = { .driver = { .owner = THIS_MODULE, @@ -344,20 +339,18 @@ static int __init ti_init(void) ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE; } - ret = usb_serial_register_drivers(&ti_usb_driver, serial_drivers); + ret = usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, ti_id_table_combined); if (ret == 0) printk(KERN_INFO KBUILD_MODNAME ": " TI_DRIVER_VERSION ":" TI_DRIVER_DESC "\n"); return ret; } - static void __exit ti_exit(void) { - usb_serial_deregister_drivers(&ti_usb_driver, serial_drivers); + usb_serial_deregister_drivers(serial_drivers); } - module_init(ti_init); module_exit(ti_exit); @@ -394,7 +387,9 @@ static int ti_startup(struct usb_serial *serial) /* if we have only 1 configuration, download firmware */ if (dev->descriptor.bNumConfigurations == 1) { - if ((status = ti_download_firmware(tdev)) != 0) + status = ti_download_firmware(tdev); + + if (status != 0) goto free_tdev; /* 3410 must be reset, 5052 resets itself */ @@ -463,8 +458,6 @@ static void ti_release(struct usb_serial *serial) struct ti_device *tdev = usb_get_serial_data(serial); struct ti_port *tport; - dbg("%s", __func__); - for (i = 0; i < serial->num_ports; ++i) { tport = usb_get_serial_port_data(serial->port[i]); if (tport) { @@ -489,8 +482,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) TI_PIPE_TIMEOUT_ENABLE | (TI_TRANSFER_TIMEOUT << 2)); - dbg("%s - port %d", __func__, port->number); - if (tport == NULL) return -ENODEV; @@ -631,8 +622,6 @@ static void ti_close(struct usb_serial_port *port) int status; int do_unlock; - dbg("%s - port %d", __func__, port->number); - tdev = usb_get_serial_data(port->serial); tport = usb_get_serial_port_data(port); if (tdev == NULL || tport == NULL) @@ -666,8 +655,6 @@ static void ti_close(struct usb_serial_port *port) } if (do_unlock) mutex_unlock(&tdev->td_open_close_lock); - - dbg("%s - exit", __func__); } @@ -676,8 +663,6 @@ static int ti_write(struct tty_struct *tty, struct usb_serial_port *port, { struct ti_port *tport = usb_get_serial_port_data(port); - dbg("%s - port %d", __func__, port->number); - if (count == 0) { dbg("%s - write request of 0 bytes", __func__); return 0; @@ -701,8 +686,6 @@ static int ti_write_room(struct tty_struct *tty) int room = 0; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - if (tport == NULL) return 0; @@ -722,8 +705,6 @@ static int ti_chars_in_buffer(struct tty_struct *tty) int chars = 0; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - if (tport == NULL) return 0; @@ -741,8 +722,6 @@ static void ti_throttle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; struct ti_port *tport = usb_get_serial_port_data(port); - dbg("%s - port %d", __func__, port->number); - if (tport == NULL) return; @@ -758,8 +737,6 @@ static void ti_unthrottle(struct tty_struct *tty) struct ti_port *tport = usb_get_serial_port_data(port); int status; - dbg("%s - port %d", __func__, port->number); - if (tport == NULL) return; @@ -854,8 +831,6 @@ static void ti_set_termios(struct tty_struct *tty, int port_number = port->number - port->serial->minor; unsigned int mcr; - dbg("%s - port %d", __func__, port->number); - cflag = tty->termios->c_cflag; iflag = tty->termios->c_iflag; @@ -988,8 +963,6 @@ static int ti_tiocmget(struct tty_struct *tty) unsigned int mcr; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - if (tport == NULL) return -ENODEV; @@ -1020,8 +993,6 @@ static int ti_tiocmset(struct tty_struct *tty, unsigned int mcr; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - if (tport == NULL) return -ENODEV; @@ -1084,8 +1055,6 @@ static void ti_interrupt_callback(struct urb *urb) int retval; __u8 msr; - dbg("%s", __func__); - switch (status) { case 0: break; @@ -1165,8 +1134,6 @@ static void ti_bulk_in_callback(struct urb *urb) int retval = 0; struct tty_struct *tty; - dbg("%s", __func__); - switch (status) { case 0: break; @@ -1233,8 +1200,6 @@ static void ti_bulk_out_callback(struct urb *urb) struct usb_serial_port *port = tport->tp_port; int status = urb->status; - dbg("%s - port %d", __func__, port->number); - tport->tp_write_urb_in_use = 0; switch (status) { @@ -1287,9 +1252,6 @@ static void ti_send(struct ti_port *tport) struct tty_struct *tty = tty_port_tty_get(&port->port); /* FIXME */ unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&tport->tp_lock, flags); if (tport->tp_write_urb_in_use) @@ -1366,8 +1328,6 @@ static int ti_get_lsr(struct ti_port *tport) int port_number = port->number - port->serial->minor; struct ti_port_status *data; - dbg("%s - port %d", __func__, port->number); - size = sizeof(struct ti_port_status); data = kmalloc(size, GFP_KERNEL); if (!data) { @@ -1480,8 +1440,6 @@ static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush) struct usb_serial_port *port = tport->tp_port; wait_queue_t wait; - dbg("%s - port %d", __func__, port->number); - spin_lock_irq(&tport->tp_lock); /* wait for data to drain from the buffer */ @@ -1679,11 +1637,12 @@ static int ti_download_firmware(struct ti_device *tdev) const struct firmware *fw_p; char buf[32]; - dbg("%s\n", __func__); /* try ID specific firmware first, then try generic firmware */ sprintf(buf, "ti_usb-v%04x-p%04x.fw", dev->descriptor.idVendor, dev->descriptor.idProduct); - if ((status = request_firmware(&fw_p, buf, &dev->dev)) != 0) { + status = request_firmware(&fw_p, buf, &dev->dev); + + if (status != 0) { buf[0] = '\0'; if (dev->descriptor.idVendor == MTS_VENDOR_ID) { switch (dev->descriptor.idProduct) { diff --git a/trunk/drivers/usb/serial/ti_usb_3410_5052.h b/trunk/drivers/usb/serial/ti_usb_3410_5052.h index f140f1b9d5c0..b353e7e3d480 100644 --- a/trunk/drivers/usb/serial/ti_usb_3410_5052.h +++ b/trunk/drivers/usb/serial/ti_usb_3410_5052.h @@ -37,6 +37,7 @@ #define TI_5152_BOOT_PRODUCT_ID 0x5152 /* no EEPROM, no firmware */ #define TI_5052_EEPROM_PRODUCT_ID 0x505A /* EEPROM, no firmware */ #define TI_5052_FIRMWARE_PRODUCT_ID 0x505F /* firmware is running */ +#define FRI2_PRODUCT_ID 0x5053 /* Fish River Island II */ /* Multi-Tech vendor and product ids */ #define MTS_VENDOR_ID 0x06E0 diff --git a/trunk/drivers/usb/serial/usb-serial.c b/trunk/drivers/usb/serial/usb-serial.c index 97355a15bbea..6a1b609a0d94 100644 --- a/trunk/drivers/usb/serial/usb-serial.c +++ b/trunk/drivers/usb/serial/usb-serial.c @@ -1,7 +1,7 @@ /* * USB Serial Converter driver * - * Copyright (C) 1999 - 2005 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 1999 - 2012 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2000 Peter Berger (pberger@brimson.com) * Copyright (C) 2000 Al Borchers (borchers@steinerpoint.com) * @@ -43,17 +43,6 @@ #define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/" #define DRIVER_DESC "USB Serial Driver core" -/* Driver structure we register with the USB core */ -static struct usb_driver usb_serial_driver = { - .name = "usbserial", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .no_dynamic_id = 1, - .supports_autosuspend = 1, -}; - /* There is no MODULE_DEVICE_TABLE for usbserial.c. Instead the MODULE_DEVICE_TABLE declarations in each serial driver cause the "hotplug" program to pull in whatever module is necessary @@ -710,7 +699,7 @@ static const struct tty_port_operations serial_port_ops = { .shutdown = serial_down, }; -int usb_serial_probe(struct usb_interface *interface, +static int usb_serial_probe(struct usb_interface *interface, const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev(interface); @@ -856,6 +845,8 @@ int usb_serial_probe(struct usb_interface *interface, module_put(type->driver.owner); return -EIO; } + dev_info(&interface->dev, "The \"generic\" usb-serial driver is only for testing and one-off prototypes.\n"); + dev_info(&interface->dev, "Tell linux-usb@vger.kernel.org to add your device to a proper driver.\n"); } #endif if (!num_ports) { @@ -1043,6 +1034,8 @@ int usb_serial_probe(struct usb_interface *interface, dbg("the device claims to support interrupt out transfers, but write_int_callback is not defined"); } + usb_set_intfdata(interface, serial); + /* if this device type has an attach function, call it */ if (type->attach) { retval = type->attach(serial); @@ -1087,10 +1080,7 @@ int usb_serial_probe(struct usb_interface *interface, serial->disconnected = 0; usb_serial_console_init(debug, minor); - exit: - /* success */ - usb_set_intfdata(interface, serial); module_put(type->driver.owner); return 0; @@ -1099,9 +1089,8 @@ int usb_serial_probe(struct usb_interface *interface, module_put(type->driver.owner); return -EIO; } -EXPORT_SYMBOL_GPL(usb_serial_probe); -void usb_serial_disconnect(struct usb_interface *interface) +static void usb_serial_disconnect(struct usb_interface *interface) { int i; struct usb_serial *serial = usb_get_intfdata(interface); @@ -1112,7 +1101,6 @@ void usb_serial_disconnect(struct usb_interface *interface) dbg("%s", __func__); mutex_lock(&serial->disc_mutex); - usb_set_intfdata(interface, NULL); /* must set a flag, to signal subdrivers */ serial->disconnected = 1; mutex_unlock(&serial->disc_mutex); @@ -1137,7 +1125,6 @@ void usb_serial_disconnect(struct usb_interface *interface) usb_serial_put(serial); dev_info(dev, "device disconnected\n"); } -EXPORT_SYMBOL_GPL(usb_serial_disconnect); int usb_serial_suspend(struct usb_interface *intf, pm_message_t message) { @@ -1181,6 +1168,22 @@ int usb_serial_resume(struct usb_interface *intf) } EXPORT_SYMBOL(usb_serial_resume); +static int usb_serial_reset_resume(struct usb_interface *intf) +{ + struct usb_serial *serial = usb_get_intfdata(intf); + int rv; + + serial->suspending = 0; + if (serial->type->reset_resume) + rv = serial->type->reset_resume(serial); + else { + rv = -EOPNOTSUPP; + intf->needs_binding = 1; + } + + return rv; +} + static const struct tty_operations serial_ops = { .open = serial_open, .close = serial_close, @@ -1204,6 +1207,17 @@ static const struct tty_operations serial_ops = { struct tty_driver *usb_serial_tty_driver; +/* Driver structure we register with the USB core */ +static struct usb_driver usb_serial_driver = { + .name = "usbserial", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .suspend = usb_serial_suspend, + .resume = usb_serial_resume, + .no_dynamic_id = 1, + .supports_autosuspend = 1, +}; + static int __init usb_serial_init(void) { int i; @@ -1338,7 +1352,6 @@ static int usb_serial_register(struct usb_serial_driver *driver) driver->description); return -EINVAL; } - driver->usb_driver->supports_autosuspend = 1; /* Add this device to our list of devices */ mutex_lock(&table_lock); @@ -1369,18 +1382,19 @@ static void usb_serial_deregister(struct usb_serial_driver *device) /** * usb_serial_register_drivers - register drivers for a usb-serial module - * @udriver: usb_driver used for matching devices/interfaces * @serial_drivers: NULL-terminated array of pointers to drivers to be registered + * @name: name of the usb_driver for this set of @serial_drivers + * @id_table: list of all devices this @serial_drivers set binds to * - * Registers @udriver and all the drivers in the @serial_drivers array. - * Automatically fills in the .no_dynamic_id field in @udriver and - * the .usb_driver field in each serial driver. + * Registers all the drivers in the @serial_drivers array, and dynamically + * creates a struct usb_driver with the name @name and id_table of @id_table. */ -int usb_serial_register_drivers(struct usb_driver *udriver, - struct usb_serial_driver * const serial_drivers[]) +int usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers[], + const char *name, + const struct usb_device_id *id_table) { int rc; - const struct usb_device_id *saved_id_table; + struct usb_driver *udriver; struct usb_serial_driver * const *sd; /* @@ -1391,12 +1405,30 @@ int usb_serial_register_drivers(struct usb_driver *udriver, * Performance hack: We don't want udriver to be probed until * the serial drivers are registered, because the probe would * simply fail for lack of a matching serial driver. - * Therefore save off udriver's id_table until we are all set. + * So we leave udriver's id_table set to NULL until we are all set. + * + * Suspend/resume support is implemented in the usb-serial core, + * so fill in the PM-related fields in udriver. */ - saved_id_table = udriver->id_table; - udriver->id_table = NULL; + udriver = kzalloc(sizeof(*udriver), GFP_KERNEL); + if (!udriver) + return -ENOMEM; + udriver->name = name; udriver->no_dynamic_id = 1; + udriver->supports_autosuspend = 1; + udriver->suspend = usb_serial_suspend; + udriver->resume = usb_serial_resume; + udriver->probe = usb_serial_probe; + udriver->disconnect = usb_serial_disconnect; + + /* we only set the reset_resume field if the serial_driver has one */ + for (sd = serial_drivers; *sd; ++sd) { + if ((*sd)->reset_resume) + udriver->reset_resume = usb_serial_reset_resume; + break; + } + rc = usb_register(udriver); if (rc) return rc; @@ -1408,8 +1440,8 @@ int usb_serial_register_drivers(struct usb_driver *udriver, goto failed; } - /* Now restore udriver's id_table and look for matches */ - udriver->id_table = saved_id_table; + /* Now set udriver's id_table and look for matches */ + udriver->id_table = id_table; rc = driver_attach(&udriver->drvwrap.driver); return 0; @@ -1423,17 +1455,20 @@ EXPORT_SYMBOL_GPL(usb_serial_register_drivers); /** * usb_serial_deregister_drivers - deregister drivers for a usb-serial module - * @udriver: usb_driver to unregister * @serial_drivers: NULL-terminated array of pointers to drivers to be deregistered * - * Deregisters @udriver and all the drivers in the @serial_drivers array. + * Deregisters all the drivers in the @serial_drivers array and deregisters and + * frees the struct usb_driver that was created by the call to + * usb_serial_register_drivers(). */ -void usb_serial_deregister_drivers(struct usb_driver *udriver, - struct usb_serial_driver * const serial_drivers[]) +void usb_serial_deregister_drivers(struct usb_serial_driver *const serial_drivers[]) { + struct usb_driver *udriver = (*serial_drivers)->usb_driver; + for (; *serial_drivers; ++serial_drivers) usb_serial_deregister(*serial_drivers); usb_deregister(udriver); + kfree(udriver); } EXPORT_SYMBOL_GPL(usb_serial_deregister_drivers); diff --git a/trunk/drivers/usb/serial/usb_debug.c b/trunk/drivers/usb/serial/usb_debug.c index e3e8995a4739..5760f97ee508 100644 --- a/trunk/drivers/usb/serial/usb_debug.c +++ b/trunk/drivers/usb/serial/usb_debug.c @@ -35,13 +35,6 @@ static const struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver debug_driver = { - .name = "debug", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - /* This HW really does not support a serial break, so one will be * emulated when ever the break state is set to true. */ @@ -83,5 +76,5 @@ static struct usb_serial_driver * const serial_drivers[] = { &debug_device, NULL }; -module_usb_serial_driver(debug_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/usb/serial/usb_wwan.c b/trunk/drivers/usb/serial/usb_wwan.c index c88657dd31c8..f35971dff4a5 100644 --- a/trunk/drivers/usb/serial/usb_wwan.c +++ b/trunk/drivers/usb/serial/usb_wwan.c @@ -43,11 +43,8 @@ void usb_wwan_dtr_rts(struct usb_serial_port *port, int on) { struct usb_serial *serial = port->serial; struct usb_wwan_port_private *portdata; - struct usb_wwan_intf_private *intfdata; - dbg("%s", __func__); - intfdata = port->serial->private; if (!intfdata->send_setup) @@ -69,8 +66,6 @@ void usb_wwan_set_termios(struct tty_struct *tty, { struct usb_wwan_intf_private *intfdata = port->serial->private; - dbg("%s", __func__); - /* Doesn't support option setting */ tty_termios_copy_hw(tty->termios, old_termios); @@ -286,8 +281,6 @@ static void usb_wwan_indat_callback(struct urb *urb) unsigned char *data = urb->transfer_buffer; int status = urb->status; - dbg("%s: %p", __func__, urb); - endpoint = usb_pipeendpoint(urb->pipe); port = urb->context; @@ -307,20 +300,17 @@ static void usb_wwan_indat_callback(struct urb *urb) } /* Resubmit urb so we continue receiving */ - if (status != -ESHUTDOWN) { - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) { - if (err != -EPERM) { - printk(KERN_ERR "%s: resubmit read urb failed. " - "(%d)", __func__, err); - /* busy also in error unless we are killed */ - usb_mark_last_busy(port->serial->dev); - } - } else { + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) { + if (err != -EPERM) { + printk(KERN_ERR "%s: resubmit read urb failed. " + "(%d)", __func__, err); + /* busy also in error unless we are killed */ usb_mark_last_busy(port->serial->dev); } + } else { + usb_mark_last_busy(port->serial->dev); } - } } @@ -331,8 +321,6 @@ static void usb_wwan_outdat_callback(struct urb *urb) struct usb_wwan_intf_private *intfdata; int i; - dbg("%s", __func__); - port = urb->context; intfdata = port->serial->private; @@ -406,8 +394,6 @@ int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port) portdata = usb_get_serial_port_data(port); intfdata = serial->private; - dbg("%s", __func__); - /* Start reading from the IN endpoint */ for (i = 0; i < N_IN_URB; i++) { urb = portdata->in_urbs[i]; @@ -441,7 +427,6 @@ void usb_wwan_close(struct usb_serial_port *port) struct usb_wwan_port_private *portdata; struct usb_wwan_intf_private *intfdata = port->serial->private; - dbg("%s", __func__); portdata = usb_get_serial_port_data(port); if (serial->dev) { @@ -492,8 +477,6 @@ static void usb_wwan_setup_urbs(struct usb_serial *serial) struct usb_serial_port *port; struct usb_wwan_port_private *portdata; - dbg("%s", __func__); - for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; portdata = usb_get_serial_port_data(port); @@ -534,8 +517,6 @@ int usb_wwan_startup(struct usb_serial *serial) struct usb_wwan_port_private *portdata; u8 *buffer; - dbg("%s", __func__); - /* Now setup per port private data */ for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; @@ -603,8 +584,6 @@ static void stop_read_write_urbs(struct usb_serial *serial) void usb_wwan_disconnect(struct usb_serial *serial) { - dbg("%s", __func__); - stop_read_write_urbs(serial); } EXPORT_SYMBOL(usb_wwan_disconnect); @@ -615,8 +594,6 @@ void usb_wwan_release(struct usb_serial *serial) struct usb_serial_port *port; struct usb_wwan_port_private *portdata; - dbg("%s", __func__); - /* Now free them */ for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; @@ -649,8 +626,6 @@ int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message) struct usb_wwan_intf_private *intfdata = serial->private; int b; - dbg("%s entered", __func__); - if (PMSG_IS_AUTO(message)) { spin_lock_irq(&intfdata->susp_lock); b = intfdata->in_flight; @@ -714,7 +689,6 @@ int usb_wwan_resume(struct usb_serial *serial) struct urb *urb; int err = 0; - dbg("%s entered", __func__); /* get the interrupt URBs resubmitted unconditionally */ for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; @@ -725,8 +699,8 @@ int usb_wwan_resume(struct usb_serial *serial) err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO); dbg("Submitted interrupt URB for port %d (result %d)", i, err); if (err < 0) { - err("%s: Error %d for interrupt URB of port%d", - __func__, err, i); + dev_err(&port->dev, "%s: Error %d for interrupt URB\n", + __func__, err); goto err_out; } } @@ -747,8 +721,8 @@ int usb_wwan_resume(struct usb_serial *serial) urb = portdata->in_urbs[j]; err = usb_submit_urb(urb, GFP_ATOMIC); if (err < 0) { - err("%s: Error %d for bulk URB %d", - __func__, err, i); + dev_err(&port->dev, "%s: Error %d for bulk URB %d\n", + __func__, err, i); spin_unlock_irq(&intfdata->susp_lock); goto err_out; } diff --git a/trunk/drivers/usb/serial/visor.c b/trunk/drivers/usb/serial/visor.c index 71d696474f24..f253c91383da 100644 --- a/trunk/drivers/usb/serial/visor.c +++ b/trunk/drivers/usb/serial/visor.c @@ -53,8 +53,6 @@ static int palm_os_4_probe(struct usb_serial *serial, /* Parameters that may be passed into the module. */ static bool debug; -static __u16 vendor; -static __u16 product; static struct usb_device_id id_table [] = { { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID), @@ -115,14 +113,12 @@ static struct usb_device_id id_table [] = { .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(FOSSIL_VENDOR_ID, FOSSIL_ABACUS_ID), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { }, /* optional parameter entry */ { } /* Terminating entry */ }; static struct usb_device_id clie_id_5_table [] = { { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_UX50_ID), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { }, /* optional parameter entry */ { } /* Terminating entry */ }; @@ -162,19 +158,11 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID) }, { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_7135_ID) }, { USB_DEVICE(FOSSIL_VENDOR_ID, FOSSIL_ABACUS_ID) }, - { }, /* optional parameter entry */ { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, id_table_combined); -static struct usb_driver visor_driver = { - .name = "visor", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; - /* All of the device info needed for the Handspring Visor, and Palm 4.0 devices */ static struct usb_serial_driver handspring_device = { @@ -244,8 +232,6 @@ static int visor_open(struct tty_struct *tty, struct usb_serial_port *port) { int result = 0; - dbg("%s - port %d", __func__, port->number); - if (!port->read_urb) { /* this is needed for some brain dead Sony devices */ dev_err(&port->dev, "Device lied about number of ports, please use a lower one.\n"); @@ -258,7 +244,7 @@ static int visor_open(struct tty_struct *tty, struct usb_serial_port *port) goto exit; if (port->interrupt_in_urb) { - dbg("%s - adding interrupt input for treo", __func__); + dev_dbg(&port->dev, "adding interrupt input for treo\n"); result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) dev_err(&port->dev, @@ -274,8 +260,6 @@ static void visor_close(struct usb_serial_port *port) { unsigned char *transfer_buffer; - dbg("%s - port %d", __func__, port->number); - /* shutdown our urbs */ usb_serial_generic_close(port); usb_kill_urb(port->interrupt_in_urb); @@ -310,12 +294,12 @@ static void visor_read_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", - __func__, status); + dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", + __func__, status); goto exit; } @@ -348,8 +332,6 @@ static int palm_os_3_probe(struct usb_serial *serial, int i; int num_ports = 0; - dbg("%s", __func__); - transfer_buffer = kmalloc(sizeof(*connection_info), GFP_KERNEL); if (!transfer_buffer) { dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __func__, @@ -445,8 +427,6 @@ static int palm_os_4_probe(struct usb_serial *serial, unsigned char *transfer_buffer; int retval; - dbg("%s", __func__); - transfer_buffer = kmalloc(sizeof(*connection_info), GFP_KERNEL); if (!transfer_buffer) { dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __func__, @@ -478,8 +458,6 @@ static int visor_probe(struct usb_serial *serial, int (*startup)(struct usb_serial *serial, const struct usb_device_id *id); - dbg("%s", __func__); - /* * some Samsung Android phones in modem mode have the same ID * as SPH-I500, but they are ACM devices, so dont bind to them @@ -521,8 +499,6 @@ static int clie_3_5_startup(struct usb_serial *serial) int result; u8 *data; - dbg("%s", __func__); - data = kmalloc(1, GFP_KERNEL); if (!data) return -ENOMEM; @@ -585,8 +561,6 @@ static int treo_attach(struct usb_serial *serial) (serial->num_interrupt_in == 0)) return 0; - dbg("%s", __func__); - /* * It appears that Treos and Kyoceras want to use the * 1st bulk in endpoint to communicate with the 2nd bulk out endpoint, @@ -622,8 +596,6 @@ static int clie_5_attach(struct usb_serial *serial) unsigned int pipe; int j; - dbg("%s", __func__); - /* TH55 registers 2 ports. Communication in from the UX50/TH55 uses bulk_in_endpointAddress from port 0. Communication out to the UX50/TH55 uses @@ -648,59 +620,7 @@ static int clie_5_attach(struct usb_serial *serial) return 0; } -static int __init visor_init(void) -{ - int i, retval; - /* Only if parameters were passed to us */ - if (vendor > 0 && product > 0) { - struct usb_device_id usb_dev_temp[] = { - { - USB_DEVICE(vendor, product), - .driver_info = - (kernel_ulong_t) &palm_os_4_probe - } - }; - - /* Find the last entry in id_table */ - for (i = 0;; i++) { - if (id_table[i].idVendor == 0) { - id_table[i] = usb_dev_temp[0]; - break; - } - } - /* Find the last entry in id_table_combined */ - for (i = 0;; i++) { - if (id_table_combined[i].idVendor == 0) { - id_table_combined[i] = usb_dev_temp[0]; - break; - } - } - printk(KERN_INFO KBUILD_MODNAME - ": Untested USB device specified at time of module insertion\n"); - printk(KERN_INFO KBUILD_MODNAME - ": Warning: This is not guaranteed to work\n"); - printk(KERN_INFO KBUILD_MODNAME - ": Using a newer kernel is preferred to this method\n"); - printk(KERN_INFO KBUILD_MODNAME - ": Adding Palm OS protocol 4.x support for unknown device: 0x%x/0x%x\n", - vendor, product); - } - - retval = usb_serial_register_drivers(&visor_driver, serial_drivers); - if (retval == 0) - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n"); - return retval; -} - - -static void __exit visor_exit (void) -{ - usb_serial_deregister_drivers(&visor_driver, serial_drivers); -} - - -module_init(visor_init); -module_exit(visor_exit); +module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); @@ -708,9 +628,3 @@ MODULE_LICENSE("GPL"); module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); - -module_param(vendor, ushort, 0); -MODULE_PARM_DESC(vendor, "User specified vendor ID"); -module_param(product, ushort, 0); -MODULE_PARM_DESC(product, "User specified product ID"); - diff --git a/trunk/drivers/usb/serial/vivopay-serial.c b/trunk/drivers/usb/serial/vivopay-serial.c index 078f338b5feb..0c0aa876c209 100644 --- a/trunk/drivers/usb/serial/vivopay-serial.c +++ b/trunk/drivers/usb/serial/vivopay-serial.c @@ -25,13 +25,6 @@ static struct usb_device_id id_table [] = { MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver vivopay_serial_driver = { - .name = "vivopay-serial", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver vivopay_serial_device = { .driver = { .owner = THIS_MODULE, @@ -45,7 +38,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &vivopay_serial_device, NULL }; -module_usb_serial_driver(vivopay_serial_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR("Forest Bond "); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/trunk/drivers/usb/serial/whiteheat.c b/trunk/drivers/usb/serial/whiteheat.c index 407e23c87946..473635e7f5db 100644 --- a/trunk/drivers/usb/serial/whiteheat.c +++ b/trunk/drivers/usb/serial/whiteheat.c @@ -45,7 +45,6 @@ static bool debug; /* * Version Information */ -#define DRIVER_VERSION "v2.0" #define DRIVER_AUTHOR "Greg Kroah-Hartman , Stuart MacDonald " #define DRIVER_DESC "USB ConnectTech WhiteHEAT driver" @@ -78,12 +77,6 @@ static const struct usb_device_id id_table_combined[] = { MODULE_DEVICE_TABLE(usb, id_table_combined); -static struct usb_driver whiteheat_driver = { - .name = "whiteheat", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; /* function prototypes for the Connect Tech WhiteHEAT prerenumeration device */ static int whiteheat_firmware_download(struct usb_serial *serial, @@ -96,10 +89,6 @@ static void whiteheat_release(struct usb_serial *serial); static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port); static void whiteheat_close(struct usb_serial_port *port); -static int whiteheat_write(struct tty_struct *tty, - struct usb_serial_port *port, - const unsigned char *buf, int count); -static int whiteheat_write_room(struct tty_struct *tty); static int whiteheat_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); static void whiteheat_set_termios(struct tty_struct *tty, @@ -108,11 +97,6 @@ static int whiteheat_tiocmget(struct tty_struct *tty); static int whiteheat_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); static void whiteheat_break_ctl(struct tty_struct *tty, int break_state); -static int whiteheat_chars_in_buffer(struct tty_struct *tty); -static void whiteheat_throttle(struct tty_struct *tty); -static void whiteheat_unthrottle(struct tty_struct *tty); -static void whiteheat_read_callback(struct urb *urb); -static void whiteheat_write_callback(struct urb *urb); static struct usb_serial_driver whiteheat_fake_device = { .driver = { @@ -138,18 +122,13 @@ static struct usb_serial_driver whiteheat_device = { .release = whiteheat_release, .open = whiteheat_open, .close = whiteheat_close, - .write = whiteheat_write, - .write_room = whiteheat_write_room, .ioctl = whiteheat_ioctl, .set_termios = whiteheat_set_termios, .break_ctl = whiteheat_break_ctl, .tiocmget = whiteheat_tiocmget, .tiocmset = whiteheat_tiocmset, - .chars_in_buffer = whiteheat_chars_in_buffer, - .throttle = whiteheat_throttle, - .unthrottle = whiteheat_unthrottle, - .read_bulk_callback = whiteheat_read_callback, - .write_bulk_callback = whiteheat_write_callback, + .throttle = usb_serial_generic_throttle, + .unthrottle = usb_serial_generic_unthrottle, }; static struct usb_serial_driver * const serial_drivers[] = { @@ -166,29 +145,8 @@ struct whiteheat_command_private { __u8 result_buffer[64]; }; - -#define THROTTLED 0x01 -#define ACTUALLY_THROTTLED 0x02 - -static int urb_pool_size = 8; - -struct whiteheat_urb_wrap { - struct list_head list; - struct urb *urb; -}; - struct whiteheat_private { - spinlock_t lock; - __u8 flags; __u8 mcr; /* FIXME: no locking on mcr */ - struct list_head rx_urbs_free; - struct list_head rx_urbs_submitted; - struct list_head rx_urb_q; - struct work_struct rx_work; - struct usb_serial_port *port; - struct list_head tx_urbs_free; - struct list_head tx_urbs_submitted; - struct mutex deathwarrant; }; @@ -198,12 +156,6 @@ static void stop_command_port(struct usb_serial *serial); static void command_port_write_callback(struct urb *urb); static void command_port_read_callback(struct urb *urb); -static int start_port_read(struct usb_serial_port *port); -static struct whiteheat_urb_wrap *urb_to_wrap(struct urb *urb, - struct list_head *head); -static struct list_head *list_first(struct list_head *head); -static void rx_data_softint(struct work_struct *work); - static int firm_send_command(struct usb_serial_port *port, __u8 command, __u8 *data, __u8 datasize); static int firm_open(struct usb_serial_port *port); @@ -247,8 +199,6 @@ static int whiteheat_firmware_download(struct usb_serial *serial, const struct firmware *loader_fw = NULL, *firmware_fw = NULL; const struct ihex_binrec *record; - dbg("%s", __func__); - if (request_ihex_firmware(&firmware_fw, "whiteheat.fw", &serial->dev->dev)) { dev_err(&serial->dev->dev, @@ -349,11 +299,6 @@ static int whiteheat_attach(struct usb_serial *serial) __u8 *command; __u8 *result; int i; - int j; - struct urb *urb; - int buf_size; - struct whiteheat_urb_wrap *wrap; - struct list_head *tmp; command_port = serial->port[COMMAND_PORT]; @@ -408,8 +353,8 @@ static int whiteheat_attach(struct usb_serial *serial) hw_info = (struct whiteheat_hw_info *)&result[1]; - dev_info(&serial->dev->dev, "%s: Driver %s: Firmware v%d.%02d\n", - serial->type->description, DRIVER_VERSION, + dev_info(&serial->dev->dev, "%s: Firmware v%d.%02d\n", + serial->type->description, hw_info->sw_major_rev, hw_info->sw_minor_rev); for (i = 0; i < serial->num_ports; i++) { @@ -423,72 +368,7 @@ static int whiteheat_attach(struct usb_serial *serial) goto no_private; } - spin_lock_init(&info->lock); - mutex_init(&info->deathwarrant); - info->flags = 0; info->mcr = 0; - INIT_WORK(&info->rx_work, rx_data_softint); - info->port = port; - - INIT_LIST_HEAD(&info->rx_urbs_free); - INIT_LIST_HEAD(&info->rx_urbs_submitted); - INIT_LIST_HEAD(&info->rx_urb_q); - INIT_LIST_HEAD(&info->tx_urbs_free); - INIT_LIST_HEAD(&info->tx_urbs_submitted); - - for (j = 0; j < urb_pool_size; j++) { - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - dev_err(&port->dev, "No free urbs available\n"); - goto no_rx_urb; - } - buf_size = port->read_urb->transfer_buffer_length; - urb->transfer_buffer = kmalloc(buf_size, GFP_KERNEL); - if (!urb->transfer_buffer) { - dev_err(&port->dev, - "Couldn't allocate urb buffer\n"); - goto no_rx_buf; - } - wrap = kmalloc(sizeof(*wrap), GFP_KERNEL); - if (!wrap) { - dev_err(&port->dev, - "Couldn't allocate urb wrapper\n"); - goto no_rx_wrap; - } - usb_fill_bulk_urb(urb, serial->dev, - usb_rcvbulkpipe(serial->dev, - port->bulk_in_endpointAddress), - urb->transfer_buffer, buf_size, - whiteheat_read_callback, port); - wrap->urb = urb; - list_add(&wrap->list, &info->rx_urbs_free); - - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - dev_err(&port->dev, "No free urbs available\n"); - goto no_tx_urb; - } - buf_size = port->write_urb->transfer_buffer_length; - urb->transfer_buffer = kmalloc(buf_size, GFP_KERNEL); - if (!urb->transfer_buffer) { - dev_err(&port->dev, - "Couldn't allocate urb buffer\n"); - goto no_tx_buf; - } - wrap = kmalloc(sizeof(*wrap), GFP_KERNEL); - if (!wrap) { - dev_err(&port->dev, - "Couldn't allocate urb wrapper\n"); - goto no_tx_wrap; - } - usb_fill_bulk_urb(urb, serial->dev, - usb_sndbulkpipe(serial->dev, - port->bulk_out_endpointAddress), - urb->transfer_buffer, buf_size, - whiteheat_write_callback, port); - wrap->urb = urb; - list_add(&wrap->list, &info->tx_urbs_free); - } usb_set_serial_port_data(port, info); } @@ -531,29 +411,6 @@ static int whiteheat_attach(struct usb_serial *serial) for (i = serial->num_ports - 1; i >= 0; i--) { port = serial->port[i]; info = usb_get_serial_port_data(port); - for (j = urb_pool_size - 1; j >= 0; j--) { - tmp = list_first(&info->tx_urbs_free); - list_del(tmp); - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - kfree(wrap); -no_tx_wrap: - kfree(urb->transfer_buffer); -no_tx_buf: - usb_free_urb(urb); -no_tx_urb: - tmp = list_first(&info->rx_urbs_free); - list_del(tmp); - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - kfree(wrap); -no_rx_wrap: - kfree(urb->transfer_buffer); -no_rx_buf: - usb_free_urb(urb); -no_rx_urb: - ; - } kfree(info); no_private: ; @@ -569,56 +426,27 @@ static int whiteheat_attach(struct usb_serial *serial) static void whiteheat_release(struct usb_serial *serial) { struct usb_serial_port *command_port; - struct usb_serial_port *port; struct whiteheat_private *info; - struct whiteheat_urb_wrap *wrap; - struct urb *urb; - struct list_head *tmp; - struct list_head *tmp2; int i; - dbg("%s", __func__); - /* free up our private data for our command port */ command_port = serial->port[COMMAND_PORT]; kfree(usb_get_serial_port_data(command_port)); for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - info = usb_get_serial_port_data(port); - list_for_each_safe(tmp, tmp2, &info->rx_urbs_free) { - list_del(tmp); - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - kfree(wrap); - kfree(urb->transfer_buffer); - usb_free_urb(urb); - } - list_for_each_safe(tmp, tmp2, &info->tx_urbs_free) { - list_del(tmp); - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - kfree(wrap); - kfree(urb->transfer_buffer); - usb_free_urb(urb); - } + info = usb_get_serial_port_data(serial->port[i]); kfree(info); } } static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port) { - int retval = 0; - - dbg("%s - port %d", __func__, port->number); + int retval; retval = start_command_port(port->serial); if (retval) goto exit; - if (tty) - tty->low_latency = 1; - /* send an open port command */ retval = firm_open(port); if (retval) { @@ -640,144 +468,25 @@ static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port) usb_clear_halt(port->serial->dev, port->read_urb->pipe); usb_clear_halt(port->serial->dev, port->write_urb->pipe); - /* Start reading from the device */ - retval = start_port_read(port); + retval = usb_serial_generic_open(tty, port); if (retval) { - dev_err(&port->dev, - "%s - failed submitting read urb, error %d\n", - __func__, retval); firm_close(port); stop_command_port(port->serial); goto exit; } - exit: - dbg("%s - exit, retval = %d", __func__, retval); return retval; } static void whiteheat_close(struct usb_serial_port *port) { - struct whiteheat_private *info = usb_get_serial_port_data(port); - struct whiteheat_urb_wrap *wrap; - struct urb *urb; - struct list_head *tmp; - struct list_head *tmp2; - - dbg("%s - port %d", __func__, port->number); - firm_report_tx_done(port); firm_close(port); - /* shutdown our bulk reads and writes */ - mutex_lock(&info->deathwarrant); - spin_lock_irq(&info->lock); - list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) { - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - list_del(tmp); - spin_unlock_irq(&info->lock); - usb_kill_urb(urb); - spin_lock_irq(&info->lock); - list_add(tmp, &info->rx_urbs_free); - } - list_for_each_safe(tmp, tmp2, &info->rx_urb_q) - list_move(tmp, &info->rx_urbs_free); - list_for_each_safe(tmp, tmp2, &info->tx_urbs_submitted) { - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - list_del(tmp); - spin_unlock_irq(&info->lock); - usb_kill_urb(urb); - spin_lock_irq(&info->lock); - list_add(tmp, &info->tx_urbs_free); - } - spin_unlock_irq(&info->lock); - mutex_unlock(&info->deathwarrant); - stop_command_port(port->serial); -} - - -static int whiteheat_write(struct tty_struct *tty, - struct usb_serial_port *port, const unsigned char *buf, int count) -{ - struct whiteheat_private *info = usb_get_serial_port_data(port); - struct whiteheat_urb_wrap *wrap; - struct urb *urb; - int result; - int bytes; - int sent = 0; - unsigned long flags; - struct list_head *tmp; - - dbg("%s - port %d", __func__, port->number); - - if (count == 0) { - dbg("%s - write request of 0 bytes", __func__); - return (0); - } - - while (count) { - spin_lock_irqsave(&info->lock, flags); - if (list_empty(&info->tx_urbs_free)) { - spin_unlock_irqrestore(&info->lock, flags); - break; - } - tmp = list_first(&info->tx_urbs_free); - list_del(tmp); - spin_unlock_irqrestore(&info->lock, flags); - - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - bytes = (count > port->bulk_out_size) ? - port->bulk_out_size : count; - memcpy(urb->transfer_buffer, buf + sent, bytes); - - usb_serial_debug_data(debug, &port->dev, - __func__, bytes, urb->transfer_buffer); - - urb->transfer_buffer_length = bytes; - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) { - dev_err_console(port, - "%s - failed submitting write urb, error %d\n", - __func__, result); - sent = result; - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->tx_urbs_free); - spin_unlock_irqrestore(&info->lock, flags); - break; - } else { - sent += bytes; - count -= bytes; - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->tx_urbs_submitted); - spin_unlock_irqrestore(&info->lock, flags); - } - } - - return sent; -} - -static int whiteheat_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct whiteheat_private *info = usb_get_serial_port_data(port); - struct list_head *tmp; - int room = 0; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); + usb_serial_generic_close(port); - spin_lock_irqsave(&info->lock, flags); - list_for_each(tmp, &info->tx_urbs_free) - room++; - spin_unlock_irqrestore(&info->lock, flags); - room *= port->bulk_out_size; - - dbg("%s - returns %d", __func__, room); - return (room); + stop_command_port(port->serial); } static int whiteheat_tiocmget(struct tty_struct *tty) @@ -786,8 +495,6 @@ static int whiteheat_tiocmget(struct tty_struct *tty) struct whiteheat_private *info = usb_get_serial_port_data(port); unsigned int modem_signals = 0; - dbg("%s - port %d", __func__, port->number); - firm_get_dtr_rts(port); if (info->mcr & UART_MCR_DTR) modem_signals |= TIOCM_DTR; @@ -803,8 +510,6 @@ static int whiteheat_tiocmset(struct tty_struct *tty, struct usb_serial_port *port = tty->driver_data; struct whiteheat_private *info = usb_get_serial_port_data(port); - dbg("%s - port %d", __func__, port->number); - if (set & TIOCM_RTS) info->mcr |= UART_MCR_RTS; if (set & TIOCM_DTR) @@ -837,7 +542,7 @@ static int whiteheat_ioctl(struct tty_struct *tty, serstruct.line = port->serial->minor; serstruct.port = port->number; serstruct.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; - serstruct.xmit_fifo_size = port->bulk_out_size; + serstruct.xmit_fifo_size = kfifo_size(&port->write_fifo); serstruct.custom_divisor = 0; serstruct.baud_base = 460800; serstruct.close_delay = CLOSING_DELAY; @@ -867,60 +572,6 @@ static void whiteheat_break_ctl(struct tty_struct *tty, int break_state) } -static int whiteheat_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct whiteheat_private *info = usb_get_serial_port_data(port); - struct list_head *tmp; - struct whiteheat_urb_wrap *wrap; - int chars = 0; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&info->lock, flags); - list_for_each(tmp, &info->tx_urbs_submitted) { - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - chars += wrap->urb->transfer_buffer_length; - } - spin_unlock_irqrestore(&info->lock, flags); - - dbg("%s - returns %d", __func__, chars); - return chars; -} - - -static void whiteheat_throttle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct whiteheat_private *info = usb_get_serial_port_data(port); - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irq(&info->lock); - info->flags |= THROTTLED; - spin_unlock_irq(&info->lock); -} - - -static void whiteheat_unthrottle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct whiteheat_private *info = usb_get_serial_port_data(port); - int actually_throttled; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irq(&info->lock); - actually_throttled = info->flags & ACTUALLY_THROTTLED; - info->flags &= ~(THROTTLED | ACTUALLY_THROTTLED); - spin_unlock_irq(&info->lock); - - if (actually_throttled) - rx_data_softint(&info->rx_work); -} - - /***************************************************************************** * Connect Tech's White Heat callback routines *****************************************************************************/ @@ -928,8 +579,6 @@ static void command_port_write_callback(struct urb *urb) { int status = urb->status; - dbg("%s", __func__); - if (status) { dbg("nonzero urb status: %d", status); return; @@ -945,8 +594,6 @@ static void command_port_read_callback(struct urb *urb) unsigned char *data = urb->transfer_buffer; int result; - dbg("%s", __func__); - command_info = usb_get_serial_port_data(command_port); if (!command_info) { dbg("%s - command_info is NULL, exiting.", __func__); @@ -989,80 +636,6 @@ static void command_port_read_callback(struct urb *urb) } -static void whiteheat_read_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct whiteheat_urb_wrap *wrap; - unsigned char *data = urb->transfer_buffer; - struct whiteheat_private *info = usb_get_serial_port_data(port); - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - - spin_lock(&info->lock); - wrap = urb_to_wrap(urb, &info->rx_urbs_submitted); - if (!wrap) { - spin_unlock(&info->lock); - dev_err(&port->dev, "%s - Not my urb!\n", __func__); - return; - } - list_del(&wrap->list); - spin_unlock(&info->lock); - - if (status) { - dbg("%s - nonzero read bulk status received: %d", - __func__, status); - spin_lock(&info->lock); - list_add(&wrap->list, &info->rx_urbs_free); - spin_unlock(&info->lock); - return; - } - - usb_serial_debug_data(debug, &port->dev, - __func__, urb->actual_length, data); - - spin_lock(&info->lock); - list_add_tail(&wrap->list, &info->rx_urb_q); - if (info->flags & THROTTLED) { - info->flags |= ACTUALLY_THROTTLED; - spin_unlock(&info->lock); - return; - } - spin_unlock(&info->lock); - - schedule_work(&info->rx_work); -} - - -static void whiteheat_write_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct whiteheat_private *info = usb_get_serial_port_data(port); - struct whiteheat_urb_wrap *wrap; - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - - spin_lock(&info->lock); - wrap = urb_to_wrap(urb, &info->tx_urbs_submitted); - if (!wrap) { - spin_unlock(&info->lock); - dev_err(&port->dev, "%s - Not my urb!\n", __func__); - return; - } - list_move(&wrap->list, &info->tx_urbs_free); - spin_unlock(&info->lock); - - if (status) { - dbg("%s - nonzero write bulk status received: %d", - __func__, status); - return; - } - - usb_serial_port_softint(port); -} - - /***************************************************************************** * Connect Tech's White Heat firmware interface *****************************************************************************/ @@ -1337,124 +910,7 @@ static void stop_command_port(struct usb_serial *serial) mutex_unlock(&command_info->mutex); } - -static int start_port_read(struct usb_serial_port *port) -{ - struct whiteheat_private *info = usb_get_serial_port_data(port); - struct whiteheat_urb_wrap *wrap; - struct urb *urb; - int retval = 0; - unsigned long flags; - struct list_head *tmp; - struct list_head *tmp2; - - spin_lock_irqsave(&info->lock, flags); - - list_for_each_safe(tmp, tmp2, &info->rx_urbs_free) { - list_del(tmp); - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - spin_unlock_irqrestore(&info->lock, flags); - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->rx_urbs_free); - list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) { - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - list_del(tmp); - spin_unlock_irqrestore(&info->lock, flags); - usb_kill_urb(urb); - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->rx_urbs_free); - } - break; - } - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->rx_urbs_submitted); - } - - spin_unlock_irqrestore(&info->lock, flags); - - return retval; -} - - -static struct whiteheat_urb_wrap *urb_to_wrap(struct urb *urb, - struct list_head *head) -{ - struct whiteheat_urb_wrap *wrap; - struct list_head *tmp; - - list_for_each(tmp, head) { - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - if (wrap->urb == urb) - return wrap; - } - - return NULL; -} - - -static struct list_head *list_first(struct list_head *head) -{ - return head->next; -} - - -static void rx_data_softint(struct work_struct *work) -{ - struct whiteheat_private *info = - container_of(work, struct whiteheat_private, rx_work); - struct usb_serial_port *port = info->port; - struct tty_struct *tty = tty_port_tty_get(&port->port); - struct whiteheat_urb_wrap *wrap; - struct urb *urb; - unsigned long flags; - struct list_head *tmp; - struct list_head *tmp2; - int result; - int sent = 0; - - spin_lock_irqsave(&info->lock, flags); - if (info->flags & THROTTLED) { - spin_unlock_irqrestore(&info->lock, flags); - goto out; - } - - list_for_each_safe(tmp, tmp2, &info->rx_urb_q) { - list_del(tmp); - spin_unlock_irqrestore(&info->lock, flags); - - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - - if (tty && urb->actual_length) - sent += tty_insert_flip_string(tty, - urb->transfer_buffer, urb->actual_length); - - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) { - dev_err(&port->dev, - "%s - failed resubmitting read urb, error %d\n", - __func__, result); - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->rx_urbs_free); - continue; - } - - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->rx_urbs_submitted); - } - spin_unlock_irqrestore(&info->lock, flags); - - if (sent) - tty_flip_buffer_push(tty); -out: - tty_kref_put(tty); -} - -module_usb_serial_driver(whiteheat_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); @@ -1463,8 +919,5 @@ MODULE_LICENSE("GPL"); MODULE_FIRMWARE("whiteheat.fw"); MODULE_FIRMWARE("whiteheat_loader.fw"); -module_param(urb_pool_size, int, 0); -MODULE_PARM_DESC(urb_pool_size, "Number of urbs to use for buffering"); - module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/trunk/drivers/usb/serial/zio.c b/trunk/drivers/usb/serial/zio.c index 9d0bb3752cd4..c043aa84a0ba 100644 --- a/trunk/drivers/usb/serial/zio.c +++ b/trunk/drivers/usb/serial/zio.c @@ -22,13 +22,6 @@ static const struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver zio_driver = { - .name = "zio", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver zio_device = { .driver = { .owner = THIS_MODULE, @@ -42,5 +35,5 @@ static struct usb_serial_driver * const serial_drivers[] = { &zio_device, NULL }; -module_usb_serial_driver(zio_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/usb/storage/ene_ub6250.c b/trunk/drivers/usb/storage/ene_ub6250.c index e7e678109500..b28f2ad127d4 100644 --- a/trunk/drivers/usb/storage/ene_ub6250.c +++ b/trunk/drivers/usb/storage/ene_ub6250.c @@ -1933,11 +1933,7 @@ static int ene_load_bincode(struct us_data *us, unsigned char flag) kfree(buf); nofw: - if (sd_fw != NULL) { - release_firmware(sd_fw); - sd_fw = NULL; - } - + release_firmware(sd_fw); return result; } diff --git a/trunk/drivers/usb/storage/unusual_devs.h b/trunk/drivers/usb/storage/unusual_devs.h index 856ad92c40de..1719886bb9be 100644 --- a/trunk/drivers/usb/storage/unusual_devs.h +++ b/trunk/drivers/usb/storage/unusual_devs.h @@ -110,7 +110,7 @@ UNUSUAL_DEV( 0x040d, 0x6205, 0x0003, 0x0003, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), -/* Deduced by Jonathan Woithe +/* Deduced by Jonathan Woithe * Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message * always fails and confuses drive. */ @@ -1885,6 +1885,13 @@ UNUSUAL_DEV( 0x1652, 0x6600, 0x0201, 0x0201, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* Reported by Jesse Feddema */ +UNUSUAL_DEV( 0x177f, 0x0400, 0x0000, 0x0000, + "Yarvik", + "PMP400", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_BULK_IGNORE_TAG | US_FL_MAX_SECTORS_64 ), + /* Reported by Hans de Goede * These Appotech controllers are found in Picture Frames, they provide a * (buggy) emulation of a cdrom drive which contains the windows software diff --git a/trunk/drivers/usb/storage/usb.c b/trunk/drivers/usb/storage/usb.c index 2653e73db623..e23c30ab66da 100644 --- a/trunk/drivers/usb/storage/usb.c +++ b/trunk/drivers/usb/storage/usb.c @@ -121,7 +121,7 @@ MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks"); } static struct us_unusual_dev us_unusual_dev_list[] = { -# include "unusual_devs.h" +# include "unusual_devs.h" { } /* Terminating entry */ }; @@ -261,17 +261,17 @@ EXPORT_SYMBOL_GPL(usb_stor_post_reset); void fill_inquiry_response(struct us_data *us, unsigned char *data, unsigned int data_len) { - if (data_len<36) // You lose. + if (data_len < 36) /* You lose. */ return; memset(data+8, ' ', 28); - if(data[0]&0x20) { /* USB device currently not connected. Return + if (data[0]&0x20) { /* USB device currently not connected. Return peripheral qualifier 001b ("...however, the physical device is not currently connected to this logical unit") and leave vendor and product identification empty. ("If the target does store some of the INQUIRY data on the - device, it may return zeros or ASCII spaces + device, it may return zeros or ASCII spaces (20h) in those fields until the data is available from the device."). */ } else { @@ -298,7 +298,7 @@ static int usb_stor_control_thread(void * __us) struct us_data *us = (struct us_data *)__us; struct Scsi_Host *host = us_to_host(us); - for(;;) { + for (;;) { US_DEBUGP("*** thread sleeping.\n"); if (wait_for_completion_interruptible(&us->cmnd_ready)) break; @@ -327,7 +327,7 @@ static int usb_stor_control_thread(void * __us) scsi_unlock(host); - /* reject the command if the direction indicator + /* reject the command if the direction indicator * is UNKNOWN */ if (us->srb->sc_data_direction == DMA_BIDIRECTIONAL) { @@ -338,7 +338,7 @@ static int usb_stor_control_thread(void * __us) /* reject if target != 0 or if LUN is higher than * the maximum known LUN */ - else if (us->srb->device->id && + else if (us->srb->device->id && !(us->fflags & US_FL_SCM_MULT_TARG)) { US_DEBUGP("Bad target number (%d:%d)\n", us->srb->device->id, us->srb->device->lun); @@ -351,7 +351,7 @@ static int usb_stor_control_thread(void * __us) us->srb->result = DID_BAD_TARGET << 16; } - /* Handle those devices which need us to fake + /* Handle those devices which need us to fake * their inquiry data */ else if ((us->srb->cmnd[0] == INQUIRY) && (us->fflags & US_FL_FIX_INQUIRY)) { @@ -376,7 +376,7 @@ static int usb_stor_control_thread(void * __us) /* indicate that the command is done */ if (us->srb->result != DID_ABORT << 16) { - US_DEBUGP("scsi cmd done, result=0x%x\n", + US_DEBUGP("scsi cmd done, result=0x%x\n", us->srb->result); us->srb->scsi_done(us->srb); } else { @@ -414,7 +414,7 @@ static int usb_stor_control_thread(void * __us) } __set_current_state(TASK_RUNNING); return 0; -} +} /*********************************************************************** * Device probing and disconnecting @@ -732,7 +732,7 @@ static int get_pipes(struct us_data *us) us->recv_ctrl_pipe = usb_rcvctrlpipe(us->pusb_dev, 0); us->send_bulk_pipe = usb_sndbulkpipe(us->pusb_dev, usb_endpoint_num(ep_out)); - us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev, + us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev, usb_endpoint_num(ep_in)); if (ep_int) { us->recv_intr_pipe = usb_rcvintpipe(us->pusb_dev, diff --git a/trunk/drivers/usb/usb-skeleton.c b/trunk/drivers/usb/usb-skeleton.c index b4a71679c933..0616f235bd6b 100644 --- a/trunk/drivers/usb/usb-skeleton.c +++ b/trunk/drivers/usb/usb-skeleton.c @@ -93,8 +93,8 @@ static int skel_open(struct inode *inode, struct file *file) interface = usb_find_interface(&skel_driver, subminor); if (!interface) { - err("%s - error, can't find device for minor %d", - __func__, subminor); + pr_err("%s - error, can't find device for minor %d\n", + __func__, subminor); retval = -ENODEV; goto exit; } @@ -179,8 +179,9 @@ static void skel_read_bulk_callback(struct urb *urb) if (!(urb->status == -ENOENT || urb->status == -ECONNRESET || urb->status == -ESHUTDOWN)) - err("%s - nonzero write bulk status received: %d", - __func__, urb->status); + dev_err(&dev->interface->dev, + "%s - nonzero write bulk status received: %d\n", + __func__, urb->status); dev->errors = urb->status; } else { @@ -213,7 +214,8 @@ static int skel_do_read_io(struct usb_skel *dev, size_t count) /* do it */ rv = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL); if (rv < 0) { - err("%s - failed submitting read urb, error %d", + dev_err(&dev->interface->dev, + "%s - failed submitting read urb, error %d\n", __func__, rv); dev->bulk_in_filled = 0; rv = (rv == -ENOMEM) ? rv : -EIO; @@ -364,8 +366,9 @@ static void skel_write_bulk_callback(struct urb *urb) if (!(urb->status == -ENOENT || urb->status == -ECONNRESET || urb->status == -ESHUTDOWN)) - err("%s - nonzero write bulk status received: %d", - __func__, urb->status); + dev_err(&dev->interface->dev, + "%s - nonzero write bulk status received: %d\n", + __func__, urb->status); spin_lock(&dev->err_lock); dev->errors = urb->status; @@ -459,8 +462,9 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, retval = usb_submit_urb(urb, GFP_KERNEL); mutex_unlock(&dev->io_mutex); if (retval) { - err("%s - failed submitting write urb, error %d", __func__, - retval); + dev_err(&dev->interface->dev, + "%s - failed submitting write urb, error %d\n", + __func__, retval); goto error_unanchor; } @@ -519,7 +523,7 @@ static int skel_probe(struct usb_interface *interface, /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { - err("Out of memory"); + dev_err(&interface->dev, "Out of memory\n"); goto error; } kref_init(&dev->kref); @@ -546,12 +550,14 @@ static int skel_probe(struct usb_interface *interface, dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); if (!dev->bulk_in_buffer) { - err("Could not allocate bulk_in_buffer"); + dev_err(&interface->dev, + "Could not allocate bulk_in_buffer\n"); goto error; } dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->bulk_in_urb) { - err("Could not allocate bulk_in_urb"); + dev_err(&interface->dev, + "Could not allocate bulk_in_urb\n"); goto error; } } @@ -563,7 +569,8 @@ static int skel_probe(struct usb_interface *interface, } } if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) { - err("Could not find both bulk-in and bulk-out endpoints"); + dev_err(&interface->dev, + "Could not find both bulk-in and bulk-out endpoints\n"); goto error; } @@ -574,7 +581,8 @@ static int skel_probe(struct usb_interface *interface, retval = usb_register_dev(interface, &skel_class); if (retval) { /* something prevented us from registering this driver */ - err("Not able to get a minor for this device."); + dev_err(&interface->dev, + "Not able to get a minor for this device.\n"); usb_set_intfdata(interface, NULL); goto error; } diff --git a/trunk/drivers/vhost/net.c b/trunk/drivers/vhost/net.c index 5c170100de9c..f82a7394756e 100644 --- a/trunk/drivers/vhost/net.c +++ b/trunk/drivers/vhost/net.c @@ -167,7 +167,7 @@ static void handle_tx(struct vhost_net *net) if (wmem < sock->sk->sk_sndbuf / 2) tx_poll_stop(net); hdr_size = vq->vhost_hlen; - zcopy = vhost_sock_zcopy(sock); + zcopy = vq->ubufs; for (;;) { /* Release DMAs done buffers first */ @@ -258,7 +258,8 @@ static void handle_tx(struct vhost_net *net) UIO_MAXIOV; } vhost_discard_vq_desc(vq, 1); - tx_poll_start(net, sock); + if (err == -EAGAIN || err == -ENOBUFS) + tx_poll_start(net, sock); break; } if (err != len) @@ -266,6 +267,8 @@ static void handle_tx(struct vhost_net *net) " len %d != %zd\n", err, len); if (!zcopy) vhost_add_used_and_signal(&net->dev, vq, head, 0); + else + vhost_zerocopy_signal_used(vq); total_len += len; if (unlikely(total_len >= VHOST_NET_WEIGHT)) { vhost_poll_queue(&vq->poll); diff --git a/trunk/drivers/vhost/vhost.c b/trunk/drivers/vhost/vhost.c index 51e4c1eeec4f..94dbd25caa30 100644 --- a/trunk/drivers/vhost/vhost.c +++ b/trunk/drivers/vhost/vhost.c @@ -1603,6 +1603,7 @@ void vhost_zerocopy_callback(struct ubuf_info *ubuf) struct vhost_ubuf_ref *ubufs = ubuf->ctx; struct vhost_virtqueue *vq = ubufs->vq; + vhost_poll_queue(&vq->poll); /* set len = 1 to mark this desc buffers done DMA */ vq->heads[ubuf->desc].len = VHOST_DMA_DONE_LEN; kref_put(&ubufs->kref, vhost_zerocopy_done_signal); diff --git a/trunk/drivers/video/au1100fb.c b/trunk/drivers/video/au1100fb.c index ffbce4525468..fe3b6ec87122 100644 --- a/trunk/drivers/video/au1100fb.c +++ b/trunk/drivers/video/au1100fb.c @@ -536,7 +536,7 @@ static int __devinit au1100fb_drv_probe(struct platform_device *dev) for (page = (unsigned long)fbdev->fb_mem; page < PAGE_ALIGN((unsigned long)fbdev->fb_mem + fbdev->fb_len); page += PAGE_SIZE) { -#if CONFIG_DMA_NONCOHERENT +#ifdef CONFIG_DMA_NONCOHERENT SetPageReserved(virt_to_page(CAC_ADDR((void *)page))); #else SetPageReserved(virt_to_page(page)); diff --git a/trunk/drivers/video/clps711xfb.c b/trunk/drivers/video/clps711xfb.c index 99b354b8e257..f994c8b8f10a 100644 --- a/trunk/drivers/video/clps711xfb.c +++ b/trunk/drivers/video/clps711xfb.c @@ -33,7 +33,6 @@ #include #include -#include #include struct fb_info *cfb; diff --git a/trunk/drivers/video/mxsfb.c b/trunk/drivers/video/mxsfb.c index 4a89f889852d..6c6bc578d0fc 100644 --- a/trunk/drivers/video/mxsfb.c +++ b/trunk/drivers/video/mxsfb.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #define REG_SET 4 @@ -756,6 +757,7 @@ static int __devinit mxsfb_probe(struct platform_device *pdev) struct mxsfb_info *host; struct fb_info *fb_info; struct fb_modelist *modelist; + struct pinctrl *pinctrl; int i, ret; if (!pdata) { @@ -793,6 +795,12 @@ static int __devinit mxsfb_probe(struct platform_device *pdev) host->devdata = &mxsfb_devdata[pdev->id_entry->driver_data]; + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(pinctrl)) { + ret = PTR_ERR(pinctrl); + goto error_getpin; + } + host->clk = clk_get(&host->pdev->dev, NULL); if (IS_ERR(host->clk)) { ret = PTR_ERR(host->clk); @@ -848,6 +856,7 @@ static int __devinit mxsfb_probe(struct platform_device *pdev) error_pseudo_pallette: clk_put(host->clk); error_getclock: +error_getpin: iounmap(host->base); error_ioremap: framebuffer_release(fb_info); diff --git a/trunk/drivers/video/omap2/displays/Kconfig b/trunk/drivers/video/omap2/displays/Kconfig index 408a9927be92..c3853c92279b 100644 --- a/trunk/drivers/video/omap2/displays/Kconfig +++ b/trunk/drivers/video/omap2/displays/Kconfig @@ -10,12 +10,12 @@ config PANEL_GENERIC_DPI Supports LCD Panel used in TI SDP3430 and EVM boards, OMAP3517 EVM boards and CM-T35. -config PANEL_DVI - tristate "DVI output" +config PANEL_TFP410 + tristate "TFP410 DPI-to-DVI chip" depends on OMAP2_DSS_DPI && I2C help - Driver for external monitors, connected via DVI. The driver uses i2c - to read EDID information from the monitor. + Driver for TFP410 DPI-to-DVI chip. The driver uses i2c to read EDID + information from the monitor. config PANEL_LGPHILIPS_LB035Q02 tristate "LG.Philips LB035Q02 LCD Panel" diff --git a/trunk/drivers/video/omap2/displays/Makefile b/trunk/drivers/video/omap2/displays/Makefile index fbfafc6eebb4..58a5176b07b0 100644 --- a/trunk/drivers/video/omap2/displays/Makefile +++ b/trunk/drivers/video/omap2/displays/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_PANEL_GENERIC_DPI) += panel-generic-dpi.o -obj-$(CONFIG_PANEL_DVI) += panel-dvi.o +obj-$(CONFIG_PANEL_TFP410) += panel-tfp410.o obj-$(CONFIG_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o obj-$(CONFIG_PANEL_NEC_NL8048HL11_01B) += panel-nec-nl8048hl11-01b.o diff --git a/trunk/drivers/video/omap2/displays/panel-dvi.c b/trunk/drivers/video/omap2/displays/panel-dvi.c deleted file mode 100644 index 03eb14af33e0..000000000000 --- a/trunk/drivers/video/omap2/displays/panel-dvi.c +++ /dev/null @@ -1,363 +0,0 @@ -/* - * DVI output support - * - * Copyright (C) 2011 Texas Instruments Inc - * Author: Tomi Valkeinen - * - * 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